summaryrefslogtreecommitdiffstats
path: root/sc/source/ui
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/ui')
-rw-r--r--sc/source/ui/Accessibility/AccessibilityHints.cxx62
-rw-r--r--sc/source/ui/Accessibility/AccessibleCell.cxx614
-rw-r--r--sc/source/ui/Accessibility/AccessibleCellBase.cxx590
-rw-r--r--sc/source/ui/Accessibility/AccessibleContextBase.cxx507
-rw-r--r--sc/source/ui/Accessibility/AccessibleCsvControl.cxx1460
-rw-r--r--sc/source/ui/Accessibility/AccessibleDocument.cxx2224
-rw-r--r--sc/source/ui/Accessibility/AccessibleDocumentBase.cxx36
-rw-r--r--sc/source/ui/Accessibility/AccessibleDocumentPagePreview.cxx1567
-rw-r--r--sc/source/ui/Accessibility/AccessibleEditObject.cxx604
-rw-r--r--sc/source/ui/Accessibility/AccessiblePageHeader.cxx371
-rw-r--r--sc/source/ui/Accessibility/AccessiblePageHeaderArea.cxx279
-rw-r--r--sc/source/ui/Accessibility/AccessiblePreviewCell.cxx277
-rw-r--r--sc/source/ui/Accessibility/AccessiblePreviewHeaderCell.cxx404
-rw-r--r--sc/source/ui/Accessibility/AccessiblePreviewTable.cxx641
-rw-r--r--sc/source/ui/Accessibility/AccessibleSpreadsheet.cxx1667
-rw-r--r--sc/source/ui/Accessibility/AccessibleTableBase.cxx470
-rw-r--r--sc/source/ui/Accessibility/AccessibleText.cxx1385
-rw-r--r--sc/source/ui/Accessibility/DrawModelBroadcaster.cxx107
-rw-r--r--sc/source/ui/StatisticsDialogs/AnalysisOfVarianceDialog.cxx559
-rw-r--r--sc/source/ui/StatisticsDialogs/ChiSquareTestDialog.cxx91
-rw-r--r--sc/source/ui/StatisticsDialogs/CorrelationDialog.cxx39
-rw-r--r--sc/source/ui/StatisticsDialogs/CovarianceDialog.cxx44
-rw-r--r--sc/source/ui/StatisticsDialogs/DescriptiveStatisticsDialog.cxx141
-rw-r--r--sc/source/ui/StatisticsDialogs/ExponentialSmoothingDialog.cxx120
-rw-r--r--sc/source/ui/StatisticsDialogs/FTestDialog.cxx171
-rw-r--r--sc/source/ui/StatisticsDialogs/FourierAnalysisDialog.cxx231
-rw-r--r--sc/source/ui/StatisticsDialogs/MatrixComparisonGenerator.cxx113
-rw-r--r--sc/source/ui/StatisticsDialogs/MovingAverageDialog.cxx116
-rw-r--r--sc/source/ui/StatisticsDialogs/RandomNumberGeneratorDialog.cxx482
-rw-r--r--sc/source/ui/StatisticsDialogs/RegressionDialog.cxx696
-rw-r--r--sc/source/ui/StatisticsDialogs/SamplingDialog.cxx563
-rw-r--r--sc/source/ui/StatisticsDialogs/StatisticsInputOutputDialog.cxx305
-rw-r--r--sc/source/ui/StatisticsDialogs/StatisticsTwoVariableDialog.cxx347
-rw-r--r--sc/source/ui/StatisticsDialogs/TTestDialog.cxx183
-rw-r--r--sc/source/ui/StatisticsDialogs/TableFillingAndNavigationTools.cxx386
-rw-r--r--sc/source/ui/StatisticsDialogs/ZTestDialog.cxx167
-rw-r--r--sc/source/ui/app/client.cxx232
-rw-r--r--sc/source/ui/app/drwtrans.cxx738
-rw-r--r--sc/source/ui/app/inputhdl.cxx4635
-rw-r--r--sc/source/ui/app/inputwin.cxx2703
-rw-r--r--sc/source/ui/app/lnktrans.cxx76
-rw-r--r--sc/source/ui/app/msgpool.cxx93
-rw-r--r--sc/source/ui/app/rfindlst.cxx90
-rw-r--r--sc/source/ui/app/scdll.cxx257
-rw-r--r--sc/source/ui/app/scmod.cxx2325
-rw-r--r--sc/source/ui/app/seltrans.cxx429
-rw-r--r--sc/source/ui/app/transobj.cxx921
-rw-r--r--sc/source/ui/app/typemap.cxx140
-rw-r--r--sc/source/ui/app/uiitems.cxx438
-rw-r--r--sc/source/ui/attrdlg/attrdlg.cxx88
-rw-r--r--sc/source/ui/attrdlg/scabstdlg.cxx55
-rw-r--r--sc/source/ui/attrdlg/scdlgfact.cxx1370
-rw-r--r--sc/source/ui/attrdlg/scdlgfact.hxx806
-rw-r--r--sc/source/ui/attrdlg/scuiexp.cxx33
-rw-r--r--sc/source/ui/attrdlg/tabpages.cxx220
-rw-r--r--sc/source/ui/cctrl/cbnumberformat.cxx88
-rw-r--r--sc/source/ui/cctrl/cbuttonw.cxx139
-rw-r--r--sc/source/ui/cctrl/checklistmenu.cxx1737
-rw-r--r--sc/source/ui/cctrl/dpcontrol.cxx220
-rw-r--r--sc/source/ui/cctrl/editfield.cxx63
-rw-r--r--sc/source/ui/cctrl/tbzoomsliderctrl.cxx457
-rw-r--r--sc/source/ui/condformat/colorformat.cxx303
-rw-r--r--sc/source/ui/condformat/condformatdlg.cxx709
-rw-r--r--sc/source/ui/condformat/condformatdlgentry.cxx1530
-rw-r--r--sc/source/ui/condformat/condformatdlgitem.cxx66
-rw-r--r--sc/source/ui/condformat/condformathelper.cxx229
-rw-r--r--sc/source/ui/condformat/condformatmgr.cxx180
-rw-r--r--sc/source/ui/dataprovider/csvdataprovider.cxx176
-rw-r--r--sc/source/ui/dataprovider/dataprovider.cxx313
-rw-r--r--sc/source/ui/dataprovider/datatransformation.cxx1275
-rw-r--r--sc/source/ui/dataprovider/htmldataprovider.cxx280
-rw-r--r--sc/source/ui/dataprovider/htmldataprovider.hxx38
-rw-r--r--sc/source/ui/dataprovider/sqldataprovider.cxx169
-rw-r--r--sc/source/ui/dataprovider/sqldataprovider.hxx38
-rw-r--r--sc/source/ui/dataprovider/xmldataprovider.cxx126
-rw-r--r--sc/source/ui/dataprovider/xmldataprovider.hxx37
-rw-r--r--sc/source/ui/dbgui/PivotLayoutDialog.cxx719
-rw-r--r--sc/source/ui/dbgui/PivotLayoutTreeList.cxx132
-rw-r--r--sc/source/ui/dbgui/PivotLayoutTreeListBase.cxx122
-rw-r--r--sc/source/ui/dbgui/PivotLayoutTreeListData.cxx287
-rw-r--r--sc/source/ui/dbgui/PivotLayoutTreeListLabel.cxx85
-rw-r--r--sc/source/ui/dbgui/asciiopt.cxx296
-rw-r--r--sc/source/ui/dbgui/consdlg.cxx535
-rw-r--r--sc/source/ui/dbgui/csvcontrol.cxx284
-rw-r--r--sc/source/ui/dbgui/csvgrid.cxx1418
-rw-r--r--sc/source/ui/dbgui/csvruler.cxx666
-rw-r--r--sc/source/ui/dbgui/csvsplits.cxx102
-rw-r--r--sc/source/ui/dbgui/csvtablebox.cxx369
-rw-r--r--sc/source/ui/dbgui/dapidata.cxx169
-rw-r--r--sc/source/ui/dbgui/dapitype.cxx153
-rw-r--r--sc/source/ui/dbgui/dbnamdlg.cxx645
-rw-r--r--sc/source/ui/dbgui/dpgroupdlg.cxx353
-rw-r--r--sc/source/ui/dbgui/filtdlg.cxx1571
-rw-r--r--sc/source/ui/dbgui/foptmgr.cxx260
-rw-r--r--sc/source/ui/dbgui/imoptdlg.cxx135
-rw-r--r--sc/source/ui/dbgui/pfiltdlg.cxx507
-rw-r--r--sc/source/ui/dbgui/pvfundlg.cxx973
-rw-r--r--sc/source/ui/dbgui/scendlg.cxx163
-rw-r--r--sc/source/ui/dbgui/scuiasciiopt.cxx943
-rw-r--r--sc/source/ui/dbgui/scuiimoptdlg.cxx340
-rw-r--r--sc/source/ui/dbgui/sfiltdlg.cxx435
-rw-r--r--sc/source/ui/dbgui/sortdlg.cxx65
-rw-r--r--sc/source/ui/dbgui/sortkeydlg.cxx77
-rw-r--r--sc/source/ui/dbgui/subtdlg.cxx46
-rw-r--r--sc/source/ui/dbgui/textimportoptions.cxx96
-rw-r--r--sc/source/ui/dbgui/tpsort.cxx855
-rw-r--r--sc/source/ui/dbgui/tpsubt.cxx621
-rw-r--r--sc/source/ui/dbgui/validate.cxx927
-rw-r--r--sc/source/ui/dialogs/SparklineDataRangeDialog.cxx202
-rw-r--r--sc/source/ui/dialogs/SparklineDialog.cxx552
-rw-r--r--sc/source/ui/dialogs/searchresults.cxx278
-rw-r--r--sc/source/ui/docshell/arealink.cxx498
-rw-r--r--sc/source/ui/docshell/autostyl.cxx191
-rw-r--r--sc/source/ui/docshell/datastream.cxx549
-rw-r--r--sc/source/ui/docshell/dbdocfun.cxx1790
-rw-r--r--sc/source/ui/docshell/dbdocimp.cxx628
-rw-r--r--sc/source/ui/docshell/docfunc.cxx5922
-rw-r--r--sc/source/ui/docshell/docfuncutil.cxx116
-rw-r--r--sc/source/ui/docshell/docsh.cxx3482
-rw-r--r--sc/source/ui/docshell/docsh2.cxx187
-rw-r--r--sc/source/ui/docshell/docsh3.cxx1331
-rw-r--r--sc/source/ui/docshell/docsh4.cxx2788
-rw-r--r--sc/source/ui/docshell/docsh5.cxx1037
-rw-r--r--sc/source/ui/docshell/docsh6.cxx517
-rw-r--r--sc/source/ui/docshell/docsh8.cxx1082
-rw-r--r--sc/source/ui/docshell/docshimp.hxx38
-rw-r--r--sc/source/ui/docshell/documentlinkmgr.cxx274
-rw-r--r--sc/source/ui/docshell/editable.cxx162
-rw-r--r--sc/source/ui/docshell/externalrefmgr.cxx3319
-rw-r--r--sc/source/ui/docshell/impex.cxx2887
-rw-r--r--sc/source/ui/docshell/macromgr.cxx201
-rw-r--r--sc/source/ui/docshell/olinefun.cxx792
-rw-r--r--sc/source/ui/docshell/pagedata.cxx100
-rw-r--r--sc/source/ui/docshell/pntlock.cxx43
-rw-r--r--sc/source/ui/docshell/servobj.cxx258
-rw-r--r--sc/source/ui/docshell/sizedev.cxx63
-rw-r--r--sc/source/ui/docshell/tablink.cxx594
-rw-r--r--sc/source/ui/docshell/tpstat.cxx70
-rw-r--r--sc/source/ui/drawfunc/chartsh.cxx155
-rw-r--r--sc/source/ui/drawfunc/drawsh.cxx626
-rw-r--r--sc/source/ui/drawfunc/drawsh2.cxx564
-rw-r--r--sc/source/ui/drawfunc/drawsh4.cxx65
-rw-r--r--sc/source/ui/drawfunc/drawsh5.cxx721
-rw-r--r--sc/source/ui/drawfunc/drformsh.cxx55
-rw-r--r--sc/source/ui/drawfunc/drtxtob.cxx1238
-rw-r--r--sc/source/ui/drawfunc/drtxtob1.cxx124
-rw-r--r--sc/source/ui/drawfunc/drtxtob2.cxx229
-rw-r--r--sc/source/ui/drawfunc/fuconarc.cxx154
-rw-r--r--sc/source/ui/drawfunc/fuconcustomshape.cxx199
-rw-r--r--sc/source/ui/drawfunc/fuconpol.cxx288
-rw-r--r--sc/source/ui/drawfunc/fuconrec.cxx449
-rw-r--r--sc/source/ui/drawfunc/fuconstr.cxx252
-rw-r--r--sc/source/ui/drawfunc/fuconuno.cxx122
-rw-r--r--sc/source/ui/drawfunc/fudraw.cxx766
-rw-r--r--sc/source/ui/drawfunc/fuins1.cxx450
-rw-r--r--sc/source/ui/drawfunc/fuins2.cxx689
-rw-r--r--sc/source/ui/drawfunc/fupoor.cxx280
-rw-r--r--sc/source/ui/drawfunc/fusel.cxx546
-rw-r--r--sc/source/ui/drawfunc/fusel2.cxx159
-rw-r--r--sc/source/ui/drawfunc/futext.cxx687
-rw-r--r--sc/source/ui/drawfunc/futext2.cxx46
-rw-r--r--sc/source/ui/drawfunc/futext3.cxx182
-rw-r--r--sc/source/ui/drawfunc/graphsh.cxx380
-rw-r--r--sc/source/ui/drawfunc/mediash.cxx65
-rw-r--r--sc/source/ui/drawfunc/oleobjsh.cxx51
-rw-r--r--sc/source/ui/formdlg/dwfunctr.cxx410
-rw-r--r--sc/source/ui/formdlg/formdata.cxx33
-rw-r--r--sc/source/ui/formdlg/formula.cxx691
-rw-r--r--sc/source/ui/inc/AccessibilityHints.hxx57
-rw-r--r--sc/source/ui/inc/AccessibleCell.hxx167
-rw-r--r--sc/source/ui/inc/AccessibleCellBase.hxx137
-rw-r--r--sc/source/ui/inc/AccessibleContextBase.hxx286
-rw-r--r--sc/source/ui/inc/AccessibleCsvControl.hxx511
-rw-r--r--sc/source/ui/inc/AccessibleDocument.hxx263
-rw-r--r--sc/source/ui/inc/AccessibleDocumentBase.hxx34
-rw-r--r--sc/source/ui/inc/AccessibleDocumentPagePreview.hxx132
-rw-r--r--sc/source/ui/inc/AccessibleEditObject.hxx231
-rw-r--r--sc/source/ui/inc/AccessiblePageHeader.hxx90
-rw-r--r--sc/source/ui/inc/AccessiblePageHeaderArea.hxx113
-rw-r--r--sc/source/ui/inc/AccessiblePreviewCell.hxx99
-rw-r--r--sc/source/ui/inc/AccessiblePreviewHeaderCell.hxx130
-rw-r--r--sc/source/ui/inc/AccessiblePreviewTable.hxx134
-rw-r--r--sc/source/ui/inc/AccessibleSpreadsheet.hxx273
-rw-r--r--sc/source/ui/inc/AccessibleTableBase.hxx234
-rw-r--r--sc/source/ui/inc/AccessibleText.hxx290
-rw-r--r--sc/source/ui/inc/AnalysisOfVarianceDialog.hxx61
-rw-r--r--sc/source/ui/inc/ChartRangeSelectionListener.hxx64
-rw-r--r--sc/source/ui/inc/ChiSquareTestDialog.hxx31
-rw-r--r--sc/source/ui/inc/ChildWindowWrapper.hxx81
-rw-r--r--sc/source/ui/inc/CorrelationDialog.hxx29
-rw-r--r--sc/source/ui/inc/CovarianceDialog.hxx30
-rw-r--r--sc/source/ui/inc/DescriptiveStatisticsDialog.hxx31
-rw-r--r--sc/source/ui/inc/DrawModelBroadcaster.hxx55
-rw-r--r--sc/source/ui/inc/ExponentialSmoothingDialog.hxx37
-rw-r--r--sc/source/ui/inc/FTestDialog.hxx31
-rw-r--r--sc/source/ui/inc/FilterListBox.hxx81
-rw-r--r--sc/source/ui/inc/FourierAnalysisDialog.hxx56
-rw-r--r--sc/source/ui/inc/IAnyRefDialog.hxx48
-rw-r--r--sc/source/ui/inc/MatrixComparisonGenerator.hxx36
-rw-r--r--sc/source/ui/inc/MovingAverageDialog.hxx38
-rw-r--r--sc/source/ui/inc/PivotLayoutDialog.hxx140
-rw-r--r--sc/source/ui/inc/PivotLayoutTreeList.hxx41
-rw-r--r--sc/source/ui/inc/PivotLayoutTreeListBase.hxx70
-rw-r--r--sc/source/ui/inc/PivotLayoutTreeListData.hxx42
-rw-r--r--sc/source/ui/inc/PivotLayoutTreeListLabel.hxx34
-rw-r--r--sc/source/ui/inc/RandomNumberGeneratorDialog.hxx85
-rw-r--r--sc/source/ui/inc/RegressionDialog.hxx82
-rw-r--r--sc/source/ui/inc/SamplingDialog.hxx91
-rw-r--r--sc/source/ui/inc/SparklineDataRangeDialog.hxx67
-rw-r--r--sc/source/ui/inc/SparklineDialog.hxx113
-rw-r--r--sc/source/ui/inc/SparklineRenderer.hxx576
-rw-r--r--sc/source/ui/inc/SparklineShell.hxx41
-rw-r--r--sc/source/ui/inc/StatisticsInputOutputDialog.hxx90
-rw-r--r--sc/source/ui/inc/StatisticsTwoVariableDialog.hxx91
-rw-r--r--sc/source/ui/inc/TTestDialog.hxx31
-rw-r--r--sc/source/ui/inc/TableFillingAndNavigationTools.hxx159
-rw-r--r--sc/source/ui/inc/ZTestDialog.hxx31
-rw-r--r--sc/source/ui/inc/acredlin.hxx163
-rw-r--r--sc/source/ui/inc/anyrefdg.hxx165
-rw-r--r--sc/source/ui/inc/areasave.hxx70
-rw-r--r--sc/source/ui/inc/areasdlg.hxx88
-rw-r--r--sc/source/ui/inc/asciiopt.hxx108
-rw-r--r--sc/source/ui/inc/attrdlg.hxx40
-rw-r--r--sc/source/ui/inc/auditsh.hxx49
-rw-r--r--sc/source/ui/inc/autofmt.hxx91
-rw-r--r--sc/source/ui/inc/autostyl.hxx81
-rw-r--r--sc/source/ui/inc/cbnumberformat.hxx42
-rw-r--r--sc/source/ui/inc/cbutton.hxx56
-rw-r--r--sc/source/ui/inc/cellmergeoption.hxx34
-rw-r--r--sc/source/ui/inc/cellsh.hxx109
-rw-r--r--sc/source/ui/inc/chartsh.hxx48
-rw-r--r--sc/source/ui/inc/checklistmenu.hxx381
-rw-r--r--sc/source/ui/inc/client.hxx44
-rw-r--r--sc/source/ui/inc/cliputil.hxx31
-rw-r--r--sc/source/ui/inc/colorformat.hxx64
-rw-r--r--sc/source/ui/inc/colrowba.hxx90
-rw-r--r--sc/source/ui/inc/condformatdlg.hxx129
-rw-r--r--sc/source/ui/inc/condformatdlgentry.hxx331
-rw-r--r--sc/source/ui/inc/condformatdlgitem.hxx62
-rw-r--r--sc/source/ui/inc/condformathelper.hxx36
-rw-r--r--sc/source/ui/inc/condformatmgr.hxx66
-rw-r--r--sc/source/ui/inc/condformatuno.hxx366
-rw-r--r--sc/source/ui/inc/conflictsdlg.hxx148
-rw-r--r--sc/source/ui/inc/consdlg.hxx99
-rw-r--r--sc/source/ui/inc/content.hxx161
-rw-r--r--sc/source/ui/inc/corodlg.hxx45
-rw-r--r--sc/source/ui/inc/crdlg.hxx39
-rw-r--r--sc/source/ui/inc/crnrdlg.hxx94
-rw-r--r--sc/source/ui/inc/csvcontrol.hxx373
-rw-r--r--sc/source/ui/inc/csvgrid.hxx315
-rw-r--r--sc/source/ui/inc/csvruler.hxx181
-rw-r--r--sc/source/ui/inc/csvsplits.hxx81
-rw-r--r--sc/source/ui/inc/csvtablebox.hxx132
-rw-r--r--sc/source/ui/inc/dapidata.hxx44
-rw-r--r--sc/source/ui/inc/dapitype.hxx69
-rw-r--r--sc/source/ui/inc/datafdlg.hxx70
-rw-r--r--sc/source/ui/inc/dataprovider.hxx149
-rw-r--r--sc/source/ui/inc/dataproviderdlg.hxx100
-rw-r--r--sc/source/ui/inc/datastream.hxx127
-rw-r--r--sc/source/ui/inc/datastreamdlg.hxx62
-rw-r--r--sc/source/ui/inc/datatableview.hxx109
-rw-r--r--sc/source/ui/inc/datatransformation.hxx229
-rw-r--r--sc/source/ui/inc/dbdocfun.hxx101
-rw-r--r--sc/source/ui/inc/dbfunc.hxx118
-rw-r--r--sc/source/ui/inc/dbnamdlg.hxx101
-rw-r--r--sc/source/ui/inc/delcldlg.hxx41
-rw-r--r--sc/source/ui/inc/delcodlg.hxx54
-rw-r--r--sc/source/ui/inc/docfunc.hxx264
-rw-r--r--sc/source/ui/inc/docfuncutil.hxx42
-rw-r--r--sc/source/ui/inc/docsh.hxx504
-rw-r--r--sc/source/ui/inc/dpcontrol.hxx71
-rw-r--r--sc/source/ui/inc/dpgroupdlg.hxx138
-rw-r--r--sc/source/ui/inc/drawsh.hxx96
-rw-r--r--sc/source/ui/inc/drawutil.hxx38
-rw-r--r--sc/source/ui/inc/drawview.hxx179
-rw-r--r--sc/source/ui/inc/drformsh.hxx43
-rw-r--r--sc/source/ui/inc/drtxtob.hxx80
-rw-r--r--sc/source/ui/inc/drwtrans.hxx99
-rw-r--r--sc/source/ui/inc/dwfunctr.hxx76
-rw-r--r--sc/source/ui/inc/editable.hxx89
-rw-r--r--sc/source/ui/inc/editfield.hxx43
-rw-r--r--sc/source/ui/inc/editsh.hxx90
-rw-r--r--sc/source/ui/inc/filldlg.hxx101
-rw-r--r--sc/source/ui/inc/filtdlg.hxx244
-rw-r--r--sc/source/ui/inc/foptmgr.hxx83
-rw-r--r--sc/source/ui/inc/formatsh.hxx75
-rw-r--r--sc/source/ui/inc/formdata.hxx48
-rw-r--r--sc/source/ui/inc/formula.hxx104
-rw-r--r--sc/source/ui/inc/fuconarc.hxx43
-rw-r--r--sc/source/ui/inc/fuconcustomshape.hxx49
-rw-r--r--sc/source/ui/inc/fuconpol.hxx44
-rw-r--r--sc/source/ui/inc/fuconrec.hxx44
-rw-r--r--sc/source/ui/inc/fuconstr.hxx43
-rw-r--r--sc/source/ui/inc/fuconuno.hxx50
-rw-r--r--sc/source/ui/inc/fudraw.hxx54
-rw-r--r--sc/source/ui/inc/fuinsert.hxx59
-rw-r--r--sc/source/ui/inc/fupoor.hxx107
-rw-r--r--sc/source/ui/inc/fusel.hxx48
-rw-r--r--sc/source/ui/inc/futext.hxx56
-rw-r--r--sc/source/ui/inc/gototabdlg.hxx43
-rw-r--r--sc/source/ui/inc/graphsh.hxx70
-rw-r--r--sc/source/ui/inc/gridmerg.hxx52
-rw-r--r--sc/source/ui/inc/gridwin.hxx527
-rw-r--r--sc/source/ui/inc/groupdlg.hxx36
-rw-r--r--sc/source/ui/inc/hdrcont.hxx133
-rw-r--r--sc/source/ui/inc/hfedtdlg.hxx152
-rw-r--r--sc/source/ui/inc/highred.hxx73
-rw-r--r--sc/source/ui/inc/hiranges.hxx34
-rw-r--r--sc/source/ui/inc/imoptdlg.hxx60
-rw-r--r--sc/source/ui/inc/impex.hxx241
-rw-r--r--sc/source/ui/inc/inputhdl.hxx334
-rw-r--r--sc/source/ui/inc/inputwin.hxx366
-rw-r--r--sc/source/ui/inc/inscldlg.hxx42
-rw-r--r--sc/source/ui/inc/inscodlg.hxx102
-rw-r--r--sc/source/ui/inc/instbdlg.hxx94
-rw-r--r--sc/source/ui/inc/invmerge.hxx44
-rw-r--r--sc/source/ui/inc/lbseldlg.hxx38
-rw-r--r--sc/source/ui/inc/linkarea.hxx72
-rw-r--r--sc/source/ui/inc/lnktrans.hxx42
-rw-r--r--sc/source/ui/inc/mediash.hxx45
-rw-r--r--sc/source/ui/inc/mergecellsdialog.hxx35
-rw-r--r--sc/source/ui/inc/msgpool.hxx57
-rw-r--r--sc/source/ui/inc/mtrindlg.hxx49
-rw-r--r--sc/source/ui/inc/mvtabdlg.hxx84
-rw-r--r--sc/source/ui/inc/namecrea.hxx38
-rw-r--r--sc/source/ui/inc/namedefdlg.hxx89
-rw-r--r--sc/source/ui/inc/namedlg.hxx124
-rw-r--r--sc/source/ui/inc/namemgrtable.hxx91
-rw-r--r--sc/source/ui/inc/namepast.hxx53
-rw-r--r--sc/source/ui/inc/navcitem.hxx40
-rw-r--r--sc/source/ui/inc/navipi.hxx194
-rw-r--r--sc/source/ui/inc/navsett.hxx49
-rw-r--r--sc/source/ui/inc/notemark.hxx69
-rw-r--r--sc/source/ui/inc/oleobjsh.hxx43
-rw-r--r--sc/source/ui/inc/olinefun.hxx52
-rw-r--r--sc/source/ui/inc/olinewin.hxx225
-rw-r--r--sc/source/ui/inc/opredlin.hxx41
-rw-r--r--sc/source/ui/inc/optsolver.hxx246
-rw-r--r--sc/source/ui/inc/output.hxx388
-rw-r--r--sc/source/ui/inc/overlayobject.hxx65
-rw-r--r--sc/source/ui/inc/pagedata.hxx81
-rw-r--r--sc/source/ui/inc/pfiltdlg.hxx93
-rw-r--r--sc/source/ui/inc/pfuncache.hxx111
-rw-r--r--sc/source/ui/inc/pgbrksh.hxx43
-rw-r--r--sc/source/ui/inc/pivotsh.hxx52
-rw-r--r--sc/source/ui/inc/pntlock.hxx56
-rw-r--r--sc/source/ui/inc/preview.hxx163
-rw-r--r--sc/source/ui/inc/prevloc.hxx152
-rw-r--r--sc/source/ui/inc/prevwsh.hxx118
-rw-r--r--sc/source/ui/inc/printfun.hxx399
-rw-r--r--sc/source/ui/inc/protectiondlg.hxx70
-rw-r--r--sc/source/ui/inc/pvfundlg.hxx216
-rw-r--r--sc/source/ui/inc/redcom.hxx57
-rw-r--r--sc/source/ui/inc/reffact.hxx217
-rw-r--r--sc/source/ui/inc/refundo.hxx55
-rw-r--r--sc/source/ui/inc/retypepassdlg.hxx128
-rw-r--r--sc/source/ui/inc/rfindlst.hxx64
-rw-r--r--sc/source/ui/inc/scendlg.hxx58
-rw-r--r--sc/source/ui/inc/scui_def.hxx69
-rw-r--r--sc/source/ui/inc/scuiasciiopt.hxx136
-rw-r--r--sc/source/ui/inc/scuiautofmt.hxx78
-rw-r--r--sc/source/ui/inc/scuiimoptdlg.hxx75
-rw-r--r--sc/source/ui/inc/scuitphfedit.hxx158
-rw-r--r--sc/source/ui/inc/searchresults.hxx57
-rw-r--r--sc/source/ui/inc/select.hxx108
-rw-r--r--sc/source/ui/inc/selectionstate.hxx55
-rw-r--r--sc/source/ui/inc/seltrans.hxx72
-rw-r--r--sc/source/ui/inc/servobj.hxx64
-rw-r--r--sc/source/ui/inc/sharedocdlg.hxx52
-rw-r--r--sc/source/ui/inc/shtabdlg.hxx47
-rw-r--r--sc/source/ui/inc/simpref.hxx78
-rw-r--r--sc/source/ui/inc/sizedev.hxx46
-rw-r--r--sc/source/ui/inc/solveroptions.hxx125
-rw-r--r--sc/source/ui/inc/solverutil.hxx39
-rw-r--r--sc/source/ui/inc/solvrdlg.hxx90
-rw-r--r--sc/source/ui/inc/sortdlg.hxx43
-rw-r--r--sc/source/ui/inc/sortkeydlg.hxx52
-rw-r--r--sc/source/ui/inc/spelldialog.hxx90
-rw-r--r--sc/source/ui/inc/spelleng.hxx151
-rw-r--r--sc/source/ui/inc/spellparam.hxx71
-rw-r--r--sc/source/ui/inc/strindlg.hxx43
-rw-r--r--sc/source/ui/inc/styledlg.hxx41
-rw-r--r--sc/source/ui/inc/subtdlg.hxx35
-rw-r--r--sc/source/ui/inc/tabbgcolordlg.hxx68
-rw-r--r--sc/source/ui/inc/tabcont.hxx78
-rw-r--r--sc/source/ui/inc/tabopdlg.hxx93
-rw-r--r--sc/source/ui/inc/tabpages.hxx68
-rw-r--r--sc/source/ui/inc/tabsplit.hxx44
-rw-r--r--sc/source/ui/inc/tabview.hxx612
-rw-r--r--sc/source/ui/inc/tabvwsh.hxx425
-rw-r--r--sc/source/ui/inc/target.hxx39
-rw-r--r--sc/source/ui/inc/tbzoomsliderctrl.hxx86
-rw-r--r--sc/source/ui/inc/textdlgs.hxx47
-rw-r--r--sc/source/ui/inc/textimportoptions.hxx52
-rw-r--r--sc/source/ui/inc/tpcalc.hxx73
-rw-r--r--sc/source/ui/inc/tpcompatibility.hxx29
-rw-r--r--sc/source/ui/inc/tpdefaults.hxx43
-rw-r--r--sc/source/ui/inc/tpformula.hxx85
-rw-r--r--sc/source/ui/inc/tphf.hxx70
-rw-r--r--sc/source/ui/inc/tphfedit.hxx86
-rw-r--r--sc/source/ui/inc/tpprint.hxx40
-rw-r--r--sc/source/ui/inc/tpsort.hxx152
-rw-r--r--sc/source/ui/inc/tpstat.hxx43
-rw-r--r--sc/source/ui/inc/tpsubt.hxx147
-rw-r--r--sc/source/ui/inc/tptable.hxx80
-rw-r--r--sc/source/ui/inc/tpusrlst.hxx88
-rw-r--r--sc/source/ui/inc/tpview.hxx115
-rw-r--r--sc/source/ui/inc/transobj.hxx112
-rw-r--r--sc/source/ui/inc/uiitems.hxx277
-rw-r--r--sc/source/ui/inc/uiobject.hxx47
-rw-r--r--sc/source/ui/inc/undo/UndoDeleteSparkline.hxx43
-rw-r--r--sc/source/ui/inc/undo/UndoDeleteSparklineGroup.hxx45
-rw-r--r--sc/source/ui/inc/undo/UndoEditSparkline.hxx47
-rw-r--r--sc/source/ui/inc/undo/UndoEditSparklineGroup.hxx44
-rw-r--r--sc/source/ui/inc/undo/UndoGroupSparklines.hxx56
-rw-r--r--sc/source/ui/inc/undo/UndoInsertSparkline.hxx45
-rw-r--r--sc/source/ui/inc/undo/UndoUngroupSparklines.hxx54
-rw-r--r--sc/source/ui/inc/undobase.hxx178
-rw-r--r--sc/source/ui/inc/undoblk.hxx983
-rw-r--r--sc/source/ui/inc/undocell.hxx369
-rw-r--r--sc/source/ui/inc/undoconvert.hxx33
-rw-r--r--sc/source/ui/inc/undodat.hxx446
-rw-r--r--sc/source/ui/inc/undodraw.hxx52
-rw-r--r--sc/source/ui/inc/undoolk.hxx32
-rw-r--r--sc/source/ui/inc/undosort.hxx34
-rw-r--r--sc/source/ui/inc/undostyl.hxx102
-rw-r--r--sc/source/ui/inc/undotab.hxx471
-rw-r--r--sc/source/ui/inc/undoutil.hxx50
-rw-r--r--sc/source/ui/inc/validate.hxx275
-rw-r--r--sc/source/ui/inc/viewdata.hxx734
-rw-r--r--sc/source/ui/inc/viewfunc.hxx384
-rw-r--r--sc/source/ui/inc/viewutil.hxx88
-rw-r--r--sc/source/ui/inc/warnbox.hxx39
-rw-r--r--sc/source/ui/inc/xmlsourcedlg.hxx106
-rw-r--r--sc/source/ui/miscdlgs/acredlin.cxx1792
-rw-r--r--sc/source/ui/miscdlgs/anyrefdg.cxx784
-rw-r--r--sc/source/ui/miscdlgs/autofmt.cxx531
-rw-r--r--sc/source/ui/miscdlgs/conflictsdlg.cxx643
-rw-r--r--sc/source/ui/miscdlgs/crdlg.cxx45
-rw-r--r--sc/source/ui/miscdlgs/crnrdlg.cxx800
-rw-r--r--sc/source/ui/miscdlgs/datafdlg.cxx355
-rw-r--r--sc/source/ui/miscdlgs/dataproviderdlg.cxx1125
-rw-r--r--sc/source/ui/miscdlgs/datastreamdlg.cxx178
-rw-r--r--sc/source/ui/miscdlgs/datatableview.cxx320
-rw-r--r--sc/source/ui/miscdlgs/delcldlg.cxx101
-rw-r--r--sc/source/ui/miscdlgs/delcodlg.cxx125
-rw-r--r--sc/source/ui/miscdlgs/filldlg.cxx290
-rw-r--r--sc/source/ui/miscdlgs/gototabdlg.cxx81
-rw-r--r--sc/source/ui/miscdlgs/groupdlg.cxx52
-rw-r--r--sc/source/ui/miscdlgs/highred.cxx221
-rw-r--r--sc/source/ui/miscdlgs/inscldlg.cxx110
-rw-r--r--sc/source/ui/miscdlgs/inscodlg.cxx367
-rw-r--r--sc/source/ui/miscdlgs/instbdlg.cxx356
-rw-r--r--sc/source/ui/miscdlgs/lbseldlg.cxx54
-rw-r--r--sc/source/ui/miscdlgs/linkarea.cxx336
-rw-r--r--sc/source/ui/miscdlgs/mergecellsdialog.cxx36
-rw-r--r--sc/source/ui/miscdlgs/mtrindlg.cxx104
-rw-r--r--sc/source/ui/miscdlgs/mvtabdlg.cxx319
-rw-r--r--sc/source/ui/miscdlgs/namecrea.cxx55
-rw-r--r--sc/source/ui/miscdlgs/optsolver.cxx1075
-rw-r--r--sc/source/ui/miscdlgs/protectiondlg.cxx154
-rw-r--r--sc/source/ui/miscdlgs/redcom.cxx167
-rw-r--r--sc/source/ui/miscdlgs/retypepassdlg.cxx366
-rw-r--r--sc/source/ui/miscdlgs/scuiautofmt.cxx385
-rw-r--r--sc/source/ui/miscdlgs/sharedocdlg.cxx213
-rw-r--r--sc/source/ui/miscdlgs/shtabdlg.cxx66
-rw-r--r--sc/source/ui/miscdlgs/simpref.cxx190
-rw-r--r--sc/source/ui/miscdlgs/solveroptions.cxx415
-rw-r--r--sc/source/ui/miscdlgs/solverutil.cxx175
-rw-r--r--sc/source/ui/miscdlgs/solvrdlg.cxx282
-rw-r--r--sc/source/ui/miscdlgs/strindlg.cxx42
-rw-r--r--sc/source/ui/miscdlgs/tabbgcolordlg.cxx141
-rw-r--r--sc/source/ui/miscdlgs/tabopdlg.cxx345
-rw-r--r--sc/source/ui/miscdlgs/textdlgs.cxx94
-rw-r--r--sc/source/ui/miscdlgs/warnbox.cxx52
-rw-r--r--sc/source/ui/namedlg/namedefdlg.cxx323
-rw-r--r--sc/source/ui/namedlg/namedlg.cxx505
-rw-r--r--sc/source/ui/namedlg/namemgrtable.cxx177
-rw-r--r--sc/source/ui/namedlg/namepast.cxx99
-rw-r--r--sc/source/ui/navipi/content.cxx1637
-rw-r--r--sc/source/ui/navipi/navcitem.cxx99
-rw-r--r--sc/source/ui/navipi/navipi.cxx965
-rw-r--r--sc/source/ui/navipi/scenwnd.cxx242
-rw-r--r--sc/source/ui/optdlg/calcoptionsdlg.cxx135
-rw-r--r--sc/source/ui/optdlg/calcoptionsdlg.hxx43
-rw-r--r--sc/source/ui/optdlg/opredlin.cxx105
-rw-r--r--sc/source/ui/optdlg/tpcalc.cxx277
-rw-r--r--sc/source/ui/optdlg/tpcompatibility.cxx74
-rw-r--r--sc/source/ui/optdlg/tpdefaults.cxx134
-rw-r--r--sc/source/ui/optdlg/tpformula.cxx411
-rw-r--r--sc/source/ui/optdlg/tpprint.cxx111
-rw-r--r--sc/source/ui/optdlg/tpusrlst.cxx738
-rw-r--r--sc/source/ui/optdlg/tpview.cxx619
-rw-r--r--sc/source/ui/pagedlg/areasdlg.cxx786
-rw-r--r--sc/source/ui/pagedlg/hfedtdlg.cxx263
-rw-r--r--sc/source/ui/pagedlg/scuitphfedit.cxx855
-rw-r--r--sc/source/ui/pagedlg/tphf.cxx262
-rw-r--r--sc/source/ui/pagedlg/tphfedit.cxx258
-rw-r--r--sc/source/ui/pagedlg/tptable.cxx522
-rw-r--r--sc/source/ui/sidebar/AlignmentPropertyPanel.cxx339
-rw-r--r--sc/source/ui/sidebar/AlignmentPropertyPanel.hxx112
-rw-r--r--sc/source/ui/sidebar/CellAppearancePropertyPanel.cxx506
-rw-r--r--sc/source/ui/sidebar/CellAppearancePropertyPanel.hxx147
-rw-r--r--sc/source/ui/sidebar/CellBorderStyleControl.cxx281
-rw-r--r--sc/source/ui/sidebar/CellBorderStyleControl.hxx52
-rw-r--r--sc/source/ui/sidebar/CellLineStyleControl.cxx243
-rw-r--r--sc/source/ui/sidebar/CellLineStyleControl.hxx54
-rw-r--r--sc/source/ui/sidebar/CellLineStyleValueSet.cxx187
-rw-r--r--sc/source/ui/sidebar/CellLineStyleValueSet.hxx48
-rw-r--r--sc/source/ui/sidebar/NumberFormatControl.cxx77
-rw-r--r--sc/source/ui/sidebar/NumberFormatPropertyPanel.cxx290
-rw-r--r--sc/source/ui/sidebar/NumberFormatPropertyPanel.hxx94
-rw-r--r--sc/source/ui/sidebar/ScPanelFactory.cxx143
-rw-r--r--sc/source/ui/sidebar/ScPanelFactory.hxx55
-rw-r--r--sc/source/ui/sparklines/SparklineAttributes.cxx277
-rw-r--r--sc/source/ui/sparklines/SparklineData.cxx30
-rw-r--r--sc/source/ui/sparklines/SparklineGroup.cxx34
-rw-r--r--sc/source/ui/sparklines/SparklineList.cxx103
-rw-r--r--sc/source/ui/styleui/styledlg.cxx139
-rw-r--r--sc/source/ui/styleui/template.curbin0 -> 326 bytes
-rw-r--r--sc/source/ui/uitest/uiobject.cxx410
-rw-r--r--sc/source/ui/undo/UndoDeleteSparkline.cxx76
-rw-r--r--sc/source/ui/undo/UndoDeleteSparklineGroup.cxx82
-rw-r--r--sc/source/ui/undo/UndoEditSparkline.cxx63
-rw-r--r--sc/source/ui/undo/UndoEditSparklineGroup.cxx65
-rw-r--r--sc/source/ui/undo/UndoGroupSparklines.cxx91
-rw-r--r--sc/source/ui/undo/UndoInsertSparkline.cxx78
-rw-r--r--sc/source/ui/undo/UndoUngroupSparklines.cxx89
-rw-r--r--sc/source/ui/undo/areasave.cxx192
-rw-r--r--sc/source/ui/undo/refundo.cxx176
-rw-r--r--sc/source/ui/undo/target.cxx24
-rw-r--r--sc/source/ui/undo/undobase.cxx616
-rw-r--r--sc/source/ui/undo/undoblk.cxx2437
-rw-r--r--sc/source/ui/undo/undoblk2.cxx186
-rw-r--r--sc/source/ui/undo/undoblk3.cxx1743
-rw-r--r--sc/source/ui/undo/undocell.cxx1048
-rw-r--r--sc/source/ui/undo/undocell2.cxx71
-rw-r--r--sc/source/ui/undo/undoconvert.cxx52
-rw-r--r--sc/source/ui/undo/undodat.cxx1925
-rw-r--r--sc/source/ui/undo/undodraw.cxx107
-rw-r--r--sc/source/ui/undo/undoolk.cxx75
-rw-r--r--sc/source/ui/undo/undorangename.cxx136
-rw-r--r--sc/source/ui/undo/undosort.cxx87
-rw-r--r--sc/source/ui/undo/undostyl.cxx280
-rw-r--r--sc/source/ui/undo/undotab.cxx1570
-rw-r--r--sc/source/ui/undo/undoutil.cxx114
-rw-r--r--sc/source/ui/unoobj/ChartRangeSelectionListener.cxx71
-rw-r--r--sc/source/ui/unoobj/ChartTools.cxx174
-rw-r--r--sc/source/ui/unoobj/PivotTableDataProvider.cxx904
-rw-r--r--sc/source/ui/unoobj/PivotTableDataSequence.cxx280
-rw-r--r--sc/source/ui/unoobj/PivotTableDataSource.cxx49
-rw-r--r--sc/source/ui/unoobj/TablePivotChart.cxx103
-rw-r--r--sc/source/ui/unoobj/TablePivotCharts.cxx279
-rw-r--r--sc/source/ui/unoobj/addruno.cxx300
-rw-r--r--sc/source/ui/unoobj/afmtuno.cxx724
-rw-r--r--sc/source/ui/unoobj/appluno.cxx621
-rw-r--r--sc/source/ui/unoobj/celllistsource.cxx433
-rw-r--r--sc/source/ui/unoobj/celllistsource.hxx155
-rw-r--r--sc/source/ui/unoobj/cellsuno.cxx9302
-rw-r--r--sc/source/ui/unoobj/cellvaluebinding.cxx576
-rw-r--r--sc/source/ui/unoobj/cellvaluebinding.hxx146
-rw-r--r--sc/source/ui/unoobj/chart2uno.cxx3490
-rw-r--r--sc/source/ui/unoobj/chartuno.cxx738
-rw-r--r--sc/source/ui/unoobj/condformatuno.cxx1904
-rw-r--r--sc/source/ui/unoobj/confuno.cxx657
-rw-r--r--sc/source/ui/unoobj/convuno.cxx46
-rw-r--r--sc/source/ui/unoobj/cursuno.cxx450
-rw-r--r--sc/source/ui/unoobj/dapiuno.cxx3356
-rw-r--r--sc/source/ui/unoobj/datauno.cxx2390
-rw-r--r--sc/source/ui/unoobj/defltuno.cxx335
-rw-r--r--sc/source/ui/unoobj/dispuno.cxx369
-rw-r--r--sc/source/ui/unoobj/docuno.cxx4866
-rw-r--r--sc/source/ui/unoobj/drdefuno.cxx79
-rw-r--r--sc/source/ui/unoobj/editsrc.cxx272
-rw-r--r--sc/source/ui/unoobj/eventuno.cxx174
-rw-r--r--sc/source/ui/unoobj/exceldetect.cxx198
-rw-r--r--sc/source/ui/unoobj/exceldetect.hxx34
-rw-r--r--sc/source/ui/unoobj/fielduno.cxx1302
-rw-r--r--sc/source/ui/unoobj/filtuno.cxx363
-rw-r--r--sc/source/ui/unoobj/fmtuno.cxx921
-rw-r--r--sc/source/ui/unoobj/forbiuno.cxx81
-rw-r--r--sc/source/ui/unoobj/funcuno.cxx653
-rw-r--r--sc/source/ui/unoobj/linkuno.cxx1691
-rw-r--r--sc/source/ui/unoobj/listenercalls.cxx69
-rw-r--r--sc/source/ui/unoobj/miscuno.cxx284
-rw-r--r--sc/source/ui/unoobj/nameuno.cxx1158
-rw-r--r--sc/source/ui/unoobj/notesuno.cxx232
-rw-r--r--sc/source/ui/unoobj/optuno.cxx222
-rw-r--r--sc/source/ui/unoobj/pageuno.cxx60
-rw-r--r--sc/source/ui/unoobj/scdetect.cxx353
-rw-r--r--sc/source/ui/unoobj/scdetect.hxx49
-rw-r--r--sc/source/ui/unoobj/servuno.cxx620
-rw-r--r--sc/source/ui/unoobj/shapeuno.cxx1443
-rw-r--r--sc/source/ui/unoobj/srchuno.cxx197
-rw-r--r--sc/source/ui/unoobj/styleuno.cxx1936
-rw-r--r--sc/source/ui/unoobj/targuno.cxx293
-rw-r--r--sc/source/ui/unoobj/textuno.cxx886
-rw-r--r--sc/source/ui/unoobj/tokenuno.cxx521
-rw-r--r--sc/source/ui/unoobj/unodoc.cxx45
-rw-r--r--sc/source/ui/unoobj/unoreflist.cxx54
-rw-r--r--sc/source/ui/unoobj/viewuno.cxx2204
-rw-r--r--sc/source/ui/unoobj/warnpassword.cxx62
-rw-r--r--sc/source/ui/vba/excelvbahelper.cxx399
-rw-r--r--sc/source/ui/vba/excelvbahelper.hxx97
-rw-r--r--sc/source/ui/vba/helperdecl.hxx47
-rw-r--r--sc/source/ui/vba/vbaapplication.cxx1566
-rw-r--r--sc/source/ui/vba/vbaapplication.hxx168
-rw-r--r--sc/source/ui/vba/vbaassistant.cxx116
-rw-r--r--sc/source/ui/vba/vbaassistant.hxx57
-rw-r--r--sc/source/ui/vba/vbaaxes.cxx211
-rw-r--r--sc/source/ui/vba/vbaaxes.hxx47
-rw-r--r--sc/source/ui/vba/vbaaxis.cxx656
-rw-r--r--sc/source/ui/vba/vbaaxis.hxx90
-rw-r--r--sc/source/ui/vba/vbaaxistitle.cxx44
-rw-r--r--sc/source/ui/vba/vbaaxistitle.hxx36
-rw-r--r--sc/source/ui/vba/vbaborders.cxx591
-rw-r--r--sc/source/ui/vba/vbaborders.hxx67
-rw-r--r--sc/source/ui/vba/vbacharacters.cxx134
-rw-r--r--sc/source/ui/vba/vbacharacters.hxx61
-rw-r--r--sc/source/ui/vba/vbachart.cxx1056
-rw-r--r--sc/source/ui/vba/vbachart.hxx103
-rw-r--r--sc/source/ui/vba/vbachartobject.cxx147
-rw-r--r--sc/source/ui/vba/vbachartobject.hxx61
-rw-r--r--sc/source/ui/vba/vbachartobjects.cxx206
-rw-r--r--sc/source/ui/vba/vbachartobjects.hxx60
-rw-r--r--sc/source/ui/vba/vbacharttitle.cxx44
-rw-r--r--sc/source/ui/vba/vbacharttitle.hxx35
-rw-r--r--sc/source/ui/vba/vbacomment.cxx234
-rw-r--r--sc/source/ui/vba/vbacomment.hxx72
-rw-r--r--sc/source/ui/vba/vbacomments.cxx113
-rw-r--r--sc/source/ui/vba/vbacomments.hxx49
-rw-r--r--sc/source/ui/vba/vbacondition.cxx143
-rw-r--r--sc/source/ui/vba/vbacondition.hxx48
-rw-r--r--sc/source/ui/vba/vbadialog.cxx85
-rw-r--r--sc/source/ui/vba/vbadialog.hxx40
-rw-r--r--sc/source/ui/vba/vbadialogs.cxx51
-rw-r--r--sc/source/ui/vba/vbadialogs.hxx43
-rw-r--r--sc/source/ui/vba/vbaeventshelper.cxx898
-rw-r--r--sc/source/ui/vba/vbaeventshelper.hxx84
-rw-r--r--sc/source/ui/vba/vbafiledialog.cxx174
-rw-r--r--sc/source/ui/vba/vbafiledialog.hxx58
-rw-r--r--sc/source/ui/vba/vbafiledialogitems.cxx123
-rw-r--r--sc/source/ui/vba/vbafiledialogitems.hxx43
-rw-r--r--sc/source/ui/vba/vbafont.cxx329
-rw-r--r--sc/source/ui/vba/vbafont.hxx76
-rw-r--r--sc/source/ui/vba/vbaformat.cxx814
-rw-r--r--sc/source/ui/vba/vbaformat.hxx154
-rw-r--r--sc/source/ui/vba/vbaformatcondition.cxx157
-rw-r--r--sc/source/ui/vba/vbaformatcondition.hxx67
-rw-r--r--sc/source/ui/vba/vbaformatconditions.cxx289
-rw-r--r--sc/source/ui/vba/vbaformatconditions.hxx66
-rw-r--r--sc/source/ui/vba/vbaglobals.cxx265
-rw-r--r--sc/source/ui/vba/vbaglobals.hxx82
-rw-r--r--sc/source/ui/vba/vbahyperlink.cxx236
-rw-r--r--sc/source/ui/vba/vbahyperlink.hxx86
-rw-r--r--sc/source/ui/vba/vbahyperlinks.cxx277
-rw-r--r--sc/source/ui/vba/vbahyperlinks.hxx136
-rw-r--r--sc/source/ui/vba/vbainterior.cxx413
-rw-r--r--sc/source/ui/vba/vbainterior.hxx83
-rw-r--r--sc/source/ui/vba/vbalineshape.cxx34
-rw-r--r--sc/source/ui/vba/vbalineshape.hxx34
-rw-r--r--sc/source/ui/vba/vbamenu.cxx67
-rw-r--r--sc/source/ui/vba/vbamenu.hxx37
-rw-r--r--sc/source/ui/vba/vbamenubar.cxx48
-rw-r--r--sc/source/ui/vba/vbamenubar.hxx33
-rw-r--r--sc/source/ui/vba/vbamenubars.cxx118
-rw-r--r--sc/source/ui/vba/vbamenubars.hxx40
-rw-r--r--sc/source/ui/vba/vbamenuitem.cxx64
-rw-r--r--sc/source/ui/vba/vbamenuitem.hxx38
-rw-r--r--sc/source/ui/vba/vbamenuitems.cxx138
-rw-r--r--sc/source/ui/vba/vbamenuitems.hxx42
-rw-r--r--sc/source/ui/vba/vbamenus.cxx124
-rw-r--r--sc/source/ui/vba/vbamenus.hxx42
-rw-r--r--sc/source/ui/vba/vbaname.cxx216
-rw-r--r--sc/source/ui/vba/vbaname.hxx69
-rw-r--r--sc/source/ui/vba/vbanames.cxx260
-rw-r--r--sc/source/ui/vba/vbanames.hxx69
-rw-r--r--sc/source/ui/vba/vbaoleobject.cxx150
-rw-r--r--sc/source/ui/vba/vbaoleobject.hxx57
-rw-r--r--sc/source/ui/vba/vbaoleobjects.cxx184
-rw-r--r--sc/source/ui/vba/vbaoleobjects.hxx47
-rw-r--r--sc/source/ui/vba/vbaoutline.cxx58
-rw-r--r--sc/source/ui/vba/vbaoutline.hxx43
-rw-r--r--sc/source/ui/vba/vbaovalshape.cxx34
-rw-r--r--sc/source/ui/vba/vbaovalshape.hxx34
-rw-r--r--sc/source/ui/vba/vbapagebreak.cxx142
-rw-r--r--sc/source/ui/vba/vbapagebreak.hxx87
-rw-r--r--sc/source/ui/vba/vbapagebreaks.cxx322
-rw-r--r--sc/source/ui/vba/vbapagebreaks.hxx83
-rw-r--r--sc/source/ui/vba/vbapagesetup.cxx631
-rw-r--r--sc/source/ui/vba/vbapagesetup.hxx90
-rw-r--r--sc/source/ui/vba/vbapalette.cxx115
-rw-r--r--sc/source/ui/vba/vbapalette.hxx44
-rw-r--r--sc/source/ui/vba/vbapane.cxx196
-rw-r--r--sc/source/ui/vba/vbapane.hxx55
-rw-r--r--sc/source/ui/vba/vbapivotcache.cxx50
-rw-r--r--sc/source/ui/vba/vbapivotcache.hxx40
-rw-r--r--sc/source/ui/vba/vbapivottable.cxx53
-rw-r--r--sc/source/ui/vba/vbapivottable.hxx40
-rw-r--r--sc/source/ui/vba/vbapivottables.cxx89
-rw-r--r--sc/source/ui/vba/vbapivottables.hxx49
-rw-r--r--sc/source/ui/vba/vbarange.cxx5720
-rw-r--r--sc/source/ui/vba/vbarange.hxx327
-rw-r--r--sc/source/ui/vba/vbasheetobject.cxx540
-rw-r--r--sc/source/ui/vba/vbasheetobject.hxx209
-rw-r--r--sc/source/ui/vba/vbasheetobjects.cxx555
-rw-r--r--sc/source/ui/vba/vbasheetobjects.hxx102
-rw-r--r--sc/source/ui/vba/vbastyle.cxx183
-rw-r--r--sc/source/ui/vba/vbastyle.hxx62
-rw-r--r--sc/source/ui/vba/vbastyles.cxx199
-rw-r--r--sc/source/ui/vba/vbastyles.hxx50
-rw-r--r--sc/source/ui/vba/vbatextboxshape.cxx60
-rw-r--r--sc/source/ui/vba/vbatextboxshape.hxx39
-rw-r--r--sc/source/ui/vba/vbatextframe.cxx67
-rw-r--r--sc/source/ui/vba/vbatextframe.hxx40
-rw-r--r--sc/source/ui/vba/vbatitle.hxx141
-rw-r--r--sc/source/ui/vba/vbavalidation.cxx382
-rw-r--r--sc/source/ui/vba/vbavalidation.hxx64
-rw-r--r--sc/source/ui/vba/vbawindow.cxx868
-rw-r--r--sc/source/ui/vba/vbawindow.hxx126
-rw-r--r--sc/source/ui/vba/vbawindows.cxx249
-rw-r--r--sc/source/ui/vba/vbawindows.hxx48
-rw-r--r--sc/source/ui/vba/vbaworkbook.cxx420
-rw-r--r--sc/source/ui/vba/vbaworkbook.hxx73
-rw-r--r--sc/source/ui/vba/vbaworkbooks.cxx291
-rw-r--r--sc/source/ui/vba/vbaworkbooks.hxx56
-rw-r--r--sc/source/ui/vba/vbaworksheet.cxx1052
-rw-r--r--sc/source/ui/vba/vbaworksheet.hxx167
-rw-r--r--sc/source/ui/vba/vbaworksheets.cxx535
-rw-r--r--sc/source/ui/vba/vbaworksheets.hxx68
-rw-r--r--sc/source/ui/vba/vbawsfunction.cxx298
-rw-r--r--sc/source/ui/vba/vbawsfunction.hxx45
-rw-r--r--sc/source/ui/view/SparklineShell.cxx54
-rw-r--r--sc/source/ui/view/auditsh.cxx123
-rw-r--r--sc/source/ui/view/cellmergeoption.cxx49
-rw-r--r--sc/source/ui/view/cellsh.cxx1322
-rw-r--r--sc/source/ui/view/cellsh1.cxx3454
-rw-r--r--sc/source/ui/view/cellsh2.cxx1263
-rw-r--r--sc/source/ui/view/cellsh3.cxx1067
-rw-r--r--sc/source/ui/view/cellsh4.cxx518
-rw-r--r--sc/source/ui/view/cliputil.cxx169
-rw-r--r--sc/source/ui/view/colrowba.cxx383
-rw-r--r--sc/source/ui/view/dbfunc.cxx447
-rw-r--r--sc/source/ui/view/dbfunc2.cxx41
-rw-r--r--sc/source/ui/view/dbfunc3.cxx2314
-rw-r--r--sc/source/ui/view/dbfunc4.cxx73
-rw-r--r--sc/source/ui/view/drawutil.cxx89
-rw-r--r--sc/source/ui/view/drawvie3.cxx259
-rw-r--r--sc/source/ui/view/drawvie4.cxx579
-rw-r--r--sc/source/ui/view/drawview.cxx1264
-rw-r--r--sc/source/ui/view/editsh.cxx1367
-rw-r--r--sc/source/ui/view/formatsh.cxx2868
-rw-r--r--sc/source/ui/view/gridmerg.cxx227
-rw-r--r--sc/source/ui/view/gridwin.cxx7094
-rw-r--r--sc/source/ui/view/gridwin2.cxx1090
-rw-r--r--sc/source/ui/view/gridwin3.cxx399
-rw-r--r--sc/source/ui/view/gridwin4.cxx2608
-rw-r--r--sc/source/ui/view/gridwin5.cxx392
-rw-r--r--sc/source/ui/view/gridwin_dbgutil.cxx171
-rw-r--r--sc/source/ui/view/hdrcont.cxx1123
-rw-r--r--sc/source/ui/view/hintwin.cxx181
-rw-r--r--sc/source/ui/view/imapwrap.cxx48
-rw-r--r--sc/source/ui/view/imapwrap.hxx40
-rw-r--r--sc/source/ui/view/invmerge.cxx162
-rw-r--r--sc/source/ui/view/notemark.cxx203
-rw-r--r--sc/source/ui/view/olinewin.cxx1040
-rw-r--r--sc/source/ui/view/output.cxx2698
-rw-r--r--sc/source/ui/view/output2.cxx5123
-rw-r--r--sc/source/ui/view/output3.cxx215
-rw-r--r--sc/source/ui/view/overlayobject.cxx85
-rw-r--r--sc/source/ui/view/pfuncache.cxx190
-rw-r--r--sc/source/ui/view/pgbrksh.cxx53
-rw-r--r--sc/source/ui/view/pivotsh.cxx167
-rw-r--r--sc/source/ui/view/preview.cxx1575
-rw-r--r--sc/source/ui/view/prevloc.cxx718
-rw-r--r--sc/source/ui/view/prevwsh.cxx1189
-rw-r--r--sc/source/ui/view/prevwsh2.cxx68
-rw-r--r--sc/source/ui/view/printfun.cxx3229
-rw-r--r--sc/source/ui/view/reffact.cxx298
-rw-r--r--sc/source/ui/view/scextopt.cxx218
-rw-r--r--sc/source/ui/view/select.cxx983
-rw-r--r--sc/source/ui/view/selectionstate.cxx54
-rw-r--r--sc/source/ui/view/spellcheckcontext.cxx387
-rw-r--r--sc/source/ui/view/spelldialog.cxx281
-rw-r--r--sc/source/ui/view/spelleng.cxx447
-rw-r--r--sc/source/ui/view/tabcont.cxx669
-rw-r--r--sc/source/ui/view/tabsplit.cxx127
-rw-r--r--sc/source/ui/view/tabview.cxx3016
-rw-r--r--sc/source/ui/view/tabview2.cxx1510
-rw-r--r--sc/source/ui/view/tabview3.cxx3112
-rw-r--r--sc/source/ui/view/tabview4.cxx532
-rw-r--r--sc/source/ui/view/tabview5.cxx708
-rw-r--r--sc/source/ui/view/tabvwsh.cxx120
-rw-r--r--sc/source/ui/view/tabvwsh2.cxx472
-rw-r--r--sc/source/ui/view/tabvwsh3.cxx1352
-rw-r--r--sc/source/ui/view/tabvwsh4.cxx1942
-rw-r--r--sc/source/ui/view/tabvwsh5.cxx390
-rw-r--r--sc/source/ui/view/tabvwsh8.cxx76
-rw-r--r--sc/source/ui/view/tabvwsh9.cxx203
-rw-r--r--sc/source/ui/view/tabvwsha.cxx896
-rw-r--r--sc/source/ui/view/tabvwshb.cxx831
-rw-r--r--sc/source/ui/view/tabvwshc.cxx745
-rw-r--r--sc/source/ui/view/tabvwshd.cxx67
-rw-r--r--sc/source/ui/view/tabvwshe.cxx342
-rw-r--r--sc/source/ui/view/tabvwshf.cxx1055
-rw-r--r--sc/source/ui/view/tabvwshg.cxx120
-rw-r--r--sc/source/ui/view/tabvwshh.cxx261
-rw-r--r--sc/source/ui/view/viewdata.cxx4366
-rw-r--r--sc/source/ui/view/viewfun2.cxx3464
-rw-r--r--sc/source/ui/view/viewfun3.cxx2027
-rw-r--r--sc/source/ui/view/viewfun4.cxx789
-rw-r--r--sc/source/ui/view/viewfun5.cxx818
-rw-r--r--sc/source/ui/view/viewfun6.cxx546
-rw-r--r--sc/source/ui/view/viewfun7.cxx456
-rw-r--r--sc/source/ui/view/viewfunc.cxx3073
-rw-r--r--sc/source/ui/view/viewutil.cxx426
-rw-r--r--sc/source/ui/view/waitoff.cxx51
-rw-r--r--sc/source/ui/xmlsource/xmlsourcedlg.cxx622
818 files changed, 329722 insertions, 0 deletions
diff --git a/sc/source/ui/Accessibility/AccessibilityHints.cxx b/sc/source/ui/Accessibility/AccessibilityHints.cxx
new file mode 100644
index 000000000..733311f72
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibilityHints.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 <AccessibilityHints.hxx>
+
+using namespace ::com::sun::star;
+
+// ScAccWinFocusLostHint - the current window lost its focus (to another application, view or document)
+
+ScAccWinFocusLostHint::~ScAccWinFocusLostHint()
+{
+}
+
+// ScAccWinFocusGotHint - the window got the focus (from another application, view or document)
+
+ScAccWinFocusGotHint::~ScAccWinFocusGotHint()
+{
+}
+
+// ScAccGridWinFocusLostHint - the current grid window lost its focus (to another application, view or document)
+
+ScAccGridWinFocusLostHint::ScAccGridWinFocusLostHint(ScSplitPos eOld )
+ :
+ ScAccWinFocusLostHint(),
+ eOldGridWin(eOld)
+{
+}
+
+ScAccGridWinFocusLostHint::~ScAccGridWinFocusLostHint()
+{
+}
+
+// ScAccGridWinFocusGotHint - the grid window got the focus (from another application, view or document)
+
+ScAccGridWinFocusGotHint::ScAccGridWinFocusGotHint(ScSplitPos eNew )
+ :
+ ScAccWinFocusGotHint(),
+ eNewGridWin(eNew)
+{
+}
+
+ScAccGridWinFocusGotHint::~ScAccGridWinFocusGotHint()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessibleCell.cxx b/sc/source/ui/Accessibility/AccessibleCell.cxx
new file mode 100644
index 000000000..392eb4b9a
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleCell.cxx
@@ -0,0 +1,614 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <sal/config.h>
+
+#include <AccessibleCell.hxx>
+#include <scitems.hxx>
+#include <AccessibleText.hxx>
+#include <AccessibleDocument.hxx>
+#include <tabvwsh.hxx>
+#include <comphelper/sequence.hxx>
+#include <document.hxx>
+#include <attrib.hxx>
+#include <editsrc.hxx>
+#include <dociter.hxx>
+#include <markdata.hxx>
+#include <cellvalue.hxx>
+#include <formulaiter.hxx>
+#include <validat.hxx>
+
+#include <unotools/accessiblestatesethelper.hxx>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+#include <editeng/brushitem.hxx>
+#include <vcl/svapp.hxx>
+
+#include <AccessibleSpreadsheet.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+rtl::Reference<ScAccessibleCell> ScAccessibleCell::create(
+ const uno::Reference<XAccessible>& rxParent,
+ ScTabViewShell* pViewShell,
+ const ScAddress& rCellAddress,
+ sal_Int32 nIndex,
+ ScSplitPos eSplitPos,
+ ScAccessibleDocument* pAccDoc)
+{
+ rtl::Reference<ScAccessibleCell> x(new ScAccessibleCell(
+ rxParent, pViewShell, rCellAddress, nIndex, eSplitPos, pAccDoc));
+ x->Init();
+ return x;
+}
+
+ScAccessibleCell::ScAccessibleCell(
+ const uno::Reference<XAccessible>& rxParent,
+ ScTabViewShell* pViewShell,
+ const ScAddress& rCellAddress,
+ sal_Int32 nIndex,
+ ScSplitPos eSplitPos,
+ ScAccessibleDocument* pAccDoc)
+ :
+ ScAccessibleCellBase(rxParent, GetDocument(pViewShell), rCellAddress, nIndex),
+ ::accessibility::AccessibleStaticTextBase(CreateEditSource(pViewShell, rCellAddress, eSplitPos)),
+ mpViewShell(pViewShell),
+ mpAccDoc(pAccDoc),
+ meSplitPos(eSplitPos)
+{
+ if (pViewShell)
+ pViewShell->AddAccessibilityObject(*this);
+}
+
+ScAccessibleCell::~ScAccessibleCell()
+{
+ if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
+ {
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+ // call dispose to inform object which have a weak reference to this object
+ dispose();
+ }
+}
+
+void ScAccessibleCell::Init()
+{
+ ScAccessibleCellBase::Init();
+
+ SetEventSource(this);
+}
+
+void SAL_CALL ScAccessibleCell::disposing()
+{
+ SolarMutexGuard aGuard;
+ // dispose in AccessibleStaticTextBase
+ Dispose();
+
+ if (mpViewShell)
+ {
+ mpViewShell->RemoveAccessibilityObject(*this);
+ mpViewShell = nullptr;
+ }
+ mpAccDoc = nullptr;
+
+ ScAccessibleCellBase::disposing();
+}
+
+ //===== XInterface =====================================================
+
+IMPLEMENT_FORWARD_XINTERFACE3( ScAccessibleCell, ScAccessibleCellBase, AccessibleStaticTextBase, ScAccessibleCellAttributeImpl )
+
+ //===== XTypeProvider ===================================================
+
+css::uno::Sequence< css::uno::Type > SAL_CALL ScAccessibleCell::getTypes()
+{
+ return ::comphelper::concatSequences(
+ ScAccessibleCellBase::getTypes(),
+ AccessibleStaticTextBase::getTypes(),
+ ScAccessibleCellAttributeImpl::getTypes()
+ );
+}
+IMPLEMENT_GET_IMPLEMENTATION_ID( ScAccessibleCell )
+
+ //===== XAccessibleComponent ============================================
+
+uno::Reference< XAccessible > SAL_CALL ScAccessibleCell::getAccessibleAtPoint(
+ const awt::Point& rPoint )
+{
+ return AccessibleStaticTextBase::getAccessibleAtPoint(rPoint);
+}
+
+void SAL_CALL ScAccessibleCell::grabFocus( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (getAccessibleParent().is() && mpViewShell)
+ {
+ uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
+ if (xAccessibleComponent.is())
+ {
+ xAccessibleComponent->grabFocus();
+ mpViewShell->SetCursor(maCellAddress.Col(), maCellAddress.Row());
+ }
+ }
+}
+
+tools::Rectangle ScAccessibleCell::GetBoundingBoxOnScreen() const
+{
+ tools::Rectangle aCellRect(GetBoundingBox());
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
+ if (pWindow)
+ {
+ tools::Rectangle aRect = pWindow->GetWindowExtentsRelative(nullptr);
+ aCellRect.Move(aRect.Left(), aRect.Top());
+ }
+ }
+ return aCellRect;
+}
+
+tools::Rectangle ScAccessibleCell::GetBoundingBox() const
+{
+ tools::Rectangle aCellRect;
+ if (mpViewShell)
+ {
+ tools::Long nSizeX, nSizeY;
+ mpViewShell->GetViewData().GetMergeSizePixel(
+ maCellAddress.Col(), maCellAddress.Row(), nSizeX, nSizeY);
+ aCellRect.SetSize(Size(nSizeX, nSizeY));
+ aCellRect.SetPos(mpViewShell->GetViewData().GetScrPos(maCellAddress.Col(), maCellAddress.Row(), meSplitPos, true));
+
+ vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
+ if (pWindow)
+ {
+ tools::Rectangle aRect(pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow()));
+ aRect.Move(-aRect.Left(), -aRect.Top());
+ aCellRect = aRect.Intersection(aCellRect);
+ }
+
+ /* #i19430# Gnopernicus reads text partly if it sticks out of the cell
+ boundaries. This leads to wrong results in cases where the cell
+ text is rotated, because rotation is not taken into account when
+ calculating the visible part of the text. In these cases we will
+ simply expand the cell size to the width of the unrotated text. */
+ if (mpDoc)
+ {
+ const ScRotateValueItem* pItem = mpDoc->GetAttr( maCellAddress, ATTR_ROTATE_VALUE );
+ if( pItem && (pItem->GetValue() != 0_deg100) )
+ {
+ tools::Rectangle aParaRect = GetParagraphBoundingBox();
+ if( !aParaRect.IsEmpty() && (aCellRect.GetWidth() < aParaRect.GetWidth()) )
+ aCellRect.SetSize( Size( aParaRect.GetWidth(), aCellRect.GetHeight() ) );
+ }
+ }
+ }
+ if (aCellRect.IsEmpty())
+ aCellRect.SetPos(Point(-1, -1));
+ return aCellRect;
+}
+
+ //===== XAccessibleContext ==============================================
+
+sal_Int32 SAL_CALL
+ ScAccessibleCell::getAccessibleChildCount()
+{
+ return AccessibleStaticTextBase::getAccessibleChildCount();
+}
+
+uno::Reference< XAccessible > SAL_CALL
+ ScAccessibleCell::getAccessibleChild(sal_Int32 nIndex)
+{
+ return AccessibleStaticTextBase::getAccessibleChild(nIndex);
+}
+
+uno::Reference<XAccessibleStateSet> SAL_CALL
+ ScAccessibleCell::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<XAccessibleStateSet> xParentStates;
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
+ xParentStates = xParentContext->getAccessibleStateSet();
+ }
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSet = new utl::AccessibleStateSetHelper();
+ if (IsDefunc(xParentStates))
+ pStateSet->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ if (IsFocused())
+ pStateSet->AddState(AccessibleStateType::FOCUSED);
+
+ if (IsFormulaMode())
+ {
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::MULTI_LINE);
+ pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE);
+ if (IsOpaque())
+ pStateSet->AddState(AccessibleStateType::OPAQUE);
+ pStateSet->AddState(AccessibleStateType::SELECTABLE);
+ if (IsSelected())
+ pStateSet->AddState(AccessibleStateType::SELECTED);
+ if (isShowing())
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ pStateSet->AddState(AccessibleStateType::TRANSIENT);
+ if (isVisible())
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ return pStateSet;
+ }
+ if (IsEditable(xParentStates))
+ {
+ pStateSet->AddState(AccessibleStateType::EDITABLE);
+ pStateSet->AddState(AccessibleStateType::RESIZABLE);
+ }
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::MULTI_LINE);
+ pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE);
+ pStateSet->AddState(AccessibleStateType::FOCUSABLE);
+ if (IsOpaque())
+ pStateSet->AddState(AccessibleStateType::OPAQUE);
+ pStateSet->AddState(AccessibleStateType::SELECTABLE);
+ if (IsSelected())
+ pStateSet->AddState(AccessibleStateType::SELECTED);
+ if (isShowing())
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ pStateSet->AddState(AccessibleStateType::TRANSIENT);
+ if (isVisible())
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ }
+ return pStateSet;
+}
+
+uno::Reference<XAccessibleRelationSet> SAL_CALL
+ ScAccessibleCell::getAccessibleRelationSet()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSet;
+ if (mpAccDoc)
+ pRelationSet = mpAccDoc->GetRelationSet(&maCellAddress);
+ if (!pRelationSet)
+ pRelationSet = new utl::AccessibleRelationSetHelper();
+ FillDependents(pRelationSet.get());
+ FillPrecedents(pRelationSet.get());
+ return pRelationSet;
+}
+
+ //===== XServiceInfo ====================================================
+
+OUString SAL_CALL ScAccessibleCell::getImplementationName()
+{
+ return "ScAccessibleCell";
+}
+
+uno::Sequence< OUString> SAL_CALL
+ ScAccessibleCell::getSupportedServiceNames()
+{
+ const css::uno::Sequence<OUString> vals { "com.sun.star.sheet.AccessibleCell" };
+ return comphelper::concatSequences(ScAccessibleContextBase::getSupportedServiceNames(), vals);
+}
+
+ //==== internal =========================================================
+
+bool ScAccessibleCell::IsDefunc(
+ const uno::Reference<XAccessibleStateSet>& rxParentStates)
+{
+ return ScAccessibleContextBase::IsDefunc() || (mpDoc == nullptr) || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
+ (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
+}
+
+bool ScAccessibleCell::IsEditable(
+ const uno::Reference<XAccessibleStateSet>& rxParentStates)
+{
+ bool bEditable(true);
+ if (rxParentStates.is() && !rxParentStates->contains(AccessibleStateType::EDITABLE) &&
+ mpDoc)
+ {
+ // here I have to test whether the protection of the table should influence this cell.
+ const ScProtectionAttr* pItem = mpDoc->GetAttr(maCellAddress, ATTR_PROTECTION);
+ if (pItem)
+ bEditable = !pItem->GetProtection();
+ }
+ return bEditable;
+}
+
+bool ScAccessibleCell::IsOpaque() const
+{
+ // test whether there is a background color
+ bool bOpaque(true);
+ if (mpDoc)
+ {
+ const SvxBrushItem* pItem = mpDoc->GetAttr(maCellAddress, ATTR_BACKGROUND);
+ if (pItem)
+ bOpaque = pItem->GetColor() != COL_TRANSPARENT;
+ }
+ return bOpaque;
+}
+
+bool ScAccessibleCell::IsFocused() const
+{
+ if (mpViewShell && mpViewShell->GetViewData().GetCurPos() == maCellAddress)
+ return mpViewShell->GetActiveWin()->HasFocus();
+
+ return false;
+}
+
+bool ScAccessibleCell::IsSelected()
+{
+ if (IsFormulaMode())
+ {
+ const ScAccessibleSpreadsheet *pSheet =static_cast<const ScAccessibleSpreadsheet*>(mxParent.get());
+ if (pSheet)
+ {
+ return pSheet->IsScAddrFormulaSel(maCellAddress);
+ }
+ return false;
+ }
+
+ bool bResult(false);
+ if (mpViewShell)
+ {
+ const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
+ bResult = rMarkdata.IsCellMarked(maCellAddress.Col(), maCellAddress.Row());
+ }
+ return bResult;
+}
+
+ScDocument* ScAccessibleCell::GetDocument(ScTabViewShell* pViewShell)
+{
+ ScDocument* pDoc = nullptr;
+ if (pViewShell)
+ pDoc = &pViewShell->GetViewData().GetDocument();
+ return pDoc;
+}
+
+::std::unique_ptr< SvxEditSource > ScAccessibleCell::CreateEditSource(ScTabViewShell* pViewShell, ScAddress aCell, ScSplitPos eSplitPos)
+{
+ if (IsFormulaMode())
+ {
+ return ::std::unique_ptr< SvxEditSource >();
+ }
+ ::std::unique_ptr< SvxEditSource > pEditSource (new ScAccessibilityEditSource(std::make_unique<ScAccessibleCellTextData>(pViewShell, aCell, eSplitPos, this)));
+
+ return pEditSource;
+}
+
+void ScAccessibleCell::FillDependents(utl::AccessibleRelationSetHelper* pRelationSet)
+{
+ if (!mpDoc)
+ return;
+
+ ScRange aRange(0, 0, maCellAddress.Tab(), mpDoc->MaxCol(), mpDoc->MaxRow(), maCellAddress.Tab());
+ ScCellIterator aCellIter(*mpDoc, aRange);
+
+ for (bool bHasCell = aCellIter.first(); bHasCell; bHasCell = aCellIter.next())
+ {
+ if (aCellIter.getType() == CELLTYPE_FORMULA)
+ {
+ bool bFound = false;
+ ScDetectiveRefIter aIter(*mpDoc, aCellIter.getFormulaCell());
+ ScRange aRef;
+ while ( !bFound && aIter.GetNextRef( aRef ) )
+ {
+ if (aRef.Contains(maCellAddress))
+ bFound = true;
+ }
+ if (bFound)
+ AddRelation(aCellIter.GetPos(), AccessibleRelationType::CONTROLLER_FOR, pRelationSet);
+ }
+ }
+}
+
+void ScAccessibleCell::FillPrecedents(utl::AccessibleRelationSetHelper* pRelationSet)
+{
+ if (!mpDoc)
+ return;
+
+ ScRefCellValue aCell(*mpDoc, maCellAddress);
+ if (aCell.meType == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pCell = aCell.mpFormula;
+ ScDetectiveRefIter aIter(*mpDoc, pCell);
+ ScRange aRef;
+ while ( aIter.GetNextRef( aRef ) )
+ {
+ AddRelation( aRef, AccessibleRelationType::CONTROLLED_BY, pRelationSet);
+ }
+ }
+}
+
+void ScAccessibleCell::AddRelation(const ScAddress& rCell,
+ const sal_uInt16 aRelationType,
+ utl::AccessibleRelationSetHelper* pRelationSet)
+{
+ AddRelation(ScRange(rCell, rCell), aRelationType, pRelationSet);
+}
+
+void ScAccessibleCell::AddRelation(const ScRange& rRange,
+ const sal_uInt16 aRelationType,
+ utl::AccessibleRelationSetHelper* pRelationSet)
+{
+ uno::Reference < XAccessibleTable > xTable ( getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY );
+ if (!xTable.is())
+ return;
+
+ const sal_uInt32 nCount(static_cast<sal_uInt32>(rRange.aEnd.Col() -
+ rRange.aStart.Col() + 1) * (rRange.aEnd.Row() -
+ rRange.aStart.Row() + 1));
+ uno::Sequence < uno::Reference < uno::XInterface > > aTargetSet( nCount );
+ uno::Reference < uno::XInterface >* pTargetSet = aTargetSet.getArray();
+ sal_uInt32 nPos(0);
+ for (sal_uInt32 nRow = rRange.aStart.Row(); nRow <= sal::static_int_cast<sal_uInt32>(rRange.aEnd.Row()); ++nRow)
+ {
+ for (sal_uInt32 nCol = rRange.aStart.Col(); nCol <= sal::static_int_cast<sal_uInt32>(rRange.aEnd.Col()); ++nCol)
+ {
+ pTargetSet[nPos] = xTable->getAccessibleCellAt(nRow, nCol);
+ ++nPos;
+ }
+ }
+ OSL_ENSURE(nCount == nPos, "something went wrong");
+ AccessibleRelation aRelation;
+ aRelation.RelationType = aRelationType;
+ aRelation.TargetSet = aTargetSet;
+ pRelationSet->AddRelation(aRelation);
+}
+
+static OUString ReplaceOneChar(const OUString& oldOUString, std::u16string_view replacedChar, std::u16string_view replaceStr)
+{
+ int iReplace = oldOUString.lastIndexOf(replacedChar);
+ OUString aRet = oldOUString;
+ while(iReplace > -1)
+ {
+ aRet = aRet.replaceAt(iReplace, 1, replaceStr);
+ iReplace = aRet.lastIndexOf(replacedChar, iReplace);
+ }
+ return aRet;
+}
+
+static OUString ReplaceFourChar(const OUString& oldOUString)
+{
+ OUString aRet = ReplaceOneChar(oldOUString, u"\\", u"\\\\");
+ aRet = ReplaceOneChar(aRet, u";", u"\\;");
+ aRet = ReplaceOneChar(aRet, u"=", u"\\=");
+ aRet = ReplaceOneChar(aRet, u",", u"\\,");
+ aRet = ReplaceOneChar(aRet, u":", u"\\:");
+ return aRet;
+}
+
+uno::Any SAL_CALL ScAccessibleCell::getExtendedAttributes()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any strRet;
+ if (mpViewShell)
+ {
+ OUString strFor = mpViewShell->GetFormula(maCellAddress) ;
+ if (!strFor.isEmpty())
+ {
+ strFor = strFor.copy(1);
+ strFor = ReplaceFourChar(strFor);
+ }
+ strFor = "Formula:" + strFor +
+ ";Note:" +
+ ReplaceFourChar(GetAllDisplayNote()) + ";" +
+ getShadowAttrs() + //the string returned contains the spliter ";"
+ getBorderAttrs();//the string returned contains the spliter ";"
+ //end of cell attributes
+ if( mpDoc )
+ {
+ strFor += "isdropdown:";
+ if( IsDropdown() )
+ strFor += "true";
+ else
+ strFor += "false";
+ strFor += ";";
+ }
+ strRet <<= strFor ;
+ }
+ return strRet;
+}
+
+// cell has its own ParaIndent property, so when calling character attributes on cell, the ParaIndent should replace the ParaLeftMargin if its value is not zero.
+uno::Sequence< beans::PropertyValue > SAL_CALL ScAccessibleCell::getCharacterAttributes( sal_Int32 nIndex, const css::uno::Sequence< OUString >& aRequestedAttributes )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Sequence< beans::PropertyValue > aAttribs = AccessibleStaticTextBase::getCharacterAttributes( nIndex, aRequestedAttributes );
+
+ sal_uInt16 nParaIndent = mpDoc->GetAttr( maCellAddress, ATTR_INDENT )->GetValue();
+ if (nParaIndent > 0)
+ {
+ auto [begin, end] = asNonConstRange(aAttribs);
+ auto pAttrib = std::find_if(begin, end,
+ [](const beans::PropertyValue& rAttrib) { return "ParaLeftMargin" == rAttrib.Name; });
+ if (pAttrib != end)
+ pAttrib->Value <<= nParaIndent;
+ }
+ return aAttribs;
+}
+
+bool ScAccessibleCell::IsFormulaMode()
+{
+ ScAccessibleSpreadsheet* pSheet = static_cast<ScAccessibleSpreadsheet*>(mxParent.get());
+ if (pSheet)
+ {
+ return pSheet->IsFormulaMode();
+ }
+ return false;
+}
+
+bool ScAccessibleCell::IsDropdown() const
+{
+ sal_uInt16 nPosX = maCellAddress.Col();
+ sal_uInt16 nPosY = sal_uInt16(maCellAddress.Row());
+ sal_uInt16 nTab = maCellAddress.Tab();
+ sal_uInt32 nValidation = mpDoc->GetAttr( nPosX, nPosY, nTab, ATTR_VALIDDATA )->GetValue();
+ if( nValidation )
+ {
+ const ScValidationData* pData = mpDoc->GetValidationEntry( nValidation );
+ if( pData && pData->HasSelectionList() )
+ return true;
+ }
+ const ScMergeFlagAttr* pAttr = mpDoc->GetAttr( nPosX, nPosY, nTab, ATTR_MERGE_FLAG );
+ if( pAttr->HasAutoFilter() )
+ {
+ return true;
+ }
+ else
+ {
+ sal_uInt16 nTabCount = mpDoc->GetTableCount();
+ if ( nTab+1<nTabCount && mpDoc->IsScenario(nTab+1) && !mpDoc->IsScenario(nTab) )
+ {
+ SCTAB i;
+ ScMarkData aMarks(mpDoc->GetSheetLimits());
+ for (i=nTab+1; i<nTabCount && mpDoc->IsScenario(i); i++)
+ mpDoc->MarkScenario( i, nTab, aMarks, false, ScScenarioFlags::ShowFrame );
+ ScRangeList aRanges;
+ aMarks.FillRangeListWithMarks( &aRanges, false );
+ bool bHasScenario;
+ SCTAB nRangeCount = aRanges.size();
+ for (i=0; i<nRangeCount; i++)
+ {
+ ScRange aRange = aRanges[i];
+ mpDoc->ExtendTotalMerge( aRange );
+ bool bTextBelow = ( aRange.aStart.Row() == 0 );
+ // MT IA2: Not used: sal_Bool bIsInScen = sal_False;
+ if ( bTextBelow )
+ {
+ bHasScenario = (aRange.aStart.Col() == nPosX && aRange.aEnd.Row() == nPosY-1);
+ }
+ else
+ {
+ bHasScenario = (aRange.aStart.Col() == nPosX && aRange.aStart.Row() == nPosY+1);
+ }
+ if( bHasScenario ) return true;
+ }
+ }
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessibleCellBase.cxx b/sc/source/ui/Accessibility/AccessibleCellBase.cxx
new file mode 100644
index 000000000..03ecf65af
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleCellBase.cxx
@@ -0,0 +1,590 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleCellBase.hxx>
+#include <document.hxx>
+#include <docfunc.hxx>
+#include <docsh.hxx>
+#include <strings.hxx>
+#include <unonames.hxx>
+#include <detfunc.hxx>
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSheetAnnotationAnchor.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/table/BorderLine.hpp>
+#include <com/sun/star/table/ShadowFormat.hpp>
+#include <comphelper/sequence.hxx>
+#include <sfx2/objsh.hxx>
+#include <vcl/svapp.hxx>
+
+#include <float.h>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+#define DEFAULT_LINE_WIDTH 2
+
+//===== internal ============================================================
+
+ScAccessibleCellBase::ScAccessibleCellBase(
+ const uno::Reference<XAccessible>& rxParent,
+ ScDocument* pDoc,
+ const ScAddress& rCellAddress,
+ sal_Int32 nIndex)
+ :
+ ScAccessibleContextBase(rxParent, AccessibleRole::TABLE_CELL),
+ maCellAddress(rCellAddress),
+ mpDoc(pDoc),
+ mnIndex(nIndex)
+{
+}
+
+ScAccessibleCellBase::~ScAccessibleCellBase()
+{
+}
+
+ //===== XAccessibleComponent ============================================
+
+bool ScAccessibleCellBase::isVisible()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ // test whether the cell is hidden (column/row - hidden/filtered)
+ bool bVisible(true);
+ if (mpDoc)
+ {
+ bool bColHidden = mpDoc->ColHidden(maCellAddress.Col(), maCellAddress.Tab());
+ bool bRowHidden = mpDoc->RowHidden(maCellAddress.Row(), maCellAddress.Tab());
+ bool bColFiltered = mpDoc->ColFiltered(maCellAddress.Col(), maCellAddress.Tab());
+ bool bRowFiltered = mpDoc->RowFiltered(maCellAddress.Row(), maCellAddress.Tab());
+
+ if (bColHidden || bColFiltered || bRowHidden || bRowFiltered)
+ bVisible = false;
+ }
+ return bVisible;
+}
+
+sal_Int32 SAL_CALL ScAccessibleCellBase::getForeground()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ sal_Int32 nColor(0);
+ if (mpDoc)
+ {
+ SfxObjectShell* pObjSh = mpDoc->GetDocumentShell();
+ if ( pObjSh )
+ {
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( pObjSh->GetModel(), uno::UNO_QUERY );
+ if ( xSpreadDoc.is() )
+ {
+ uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets();
+ uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
+ if ( xIndex.is() )
+ {
+ uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab());
+ uno::Reference<sheet::XSpreadsheet> xTable;
+ if (aTable>>=xTable)
+ {
+ uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row());
+ if (xCell.is())
+ {
+ uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
+ if (xCellProps.is())
+ {
+ uno::Any aAny = xCellProps->getPropertyValue(SC_UNONAME_CCOLOR);
+ aAny >>= nColor;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return nColor;
+}
+
+sal_Int32 SAL_CALL ScAccessibleCellBase::getBackground()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ sal_Int32 nColor(0);
+
+ if (mpDoc)
+ {
+ SfxObjectShell* pObjSh = mpDoc->GetDocumentShell();
+ if ( pObjSh )
+ {
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( pObjSh->GetModel(), uno::UNO_QUERY );
+ if ( xSpreadDoc.is() )
+ {
+ uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets();
+ uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
+ if ( xIndex.is() )
+ {
+ uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab());
+ uno::Reference<sheet::XSpreadsheet> xTable;
+ if (aTable>>=xTable)
+ {
+ uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row());
+ if (xCell.is())
+ {
+ uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
+ if (xCellProps.is())
+ {
+ uno::Any aAny = xCellProps->getPropertyValue(SC_UNONAME_CELLBACK);
+ aAny >>= nColor;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return nColor;
+}
+
+ //===== XInterface =====================================================
+
+uno::Any SAL_CALL ScAccessibleCellBase::queryInterface( uno::Type const & rType )
+{
+ uno::Any aAny (ScAccessibleCellBaseImpl::queryInterface(rType));
+ return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType);
+}
+
+void SAL_CALL ScAccessibleCellBase::acquire()
+ noexcept
+{
+ ScAccessibleContextBase::acquire();
+}
+
+void SAL_CALL ScAccessibleCellBase::release()
+ noexcept
+{
+ ScAccessibleContextBase::release();
+}
+
+ //===== XAccessibleContext ==============================================
+
+sal_Int32
+ ScAccessibleCellBase::getAccessibleIndexInParent()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ return mnIndex;
+}
+
+OUString
+ ScAccessibleCellBase::createAccessibleDescription()
+{
+ return STR_ACC_CELL_DESCR;
+}
+
+OUString
+ ScAccessibleCellBase::createAccessibleName()
+{
+ // Document not needed, because only the cell address, but not the tablename is needed
+ // always us OOO notation
+ return maCellAddress.Format(ScRefFlags::VALID);
+}
+
+ //===== XAccessibleValue ================================================
+
+uno::Any SAL_CALL
+ ScAccessibleCellBase::getCurrentValue()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ uno::Any aAny;
+ if (mpDoc)
+ {
+ aAny <<= mpDoc->GetValue(maCellAddress);
+ }
+ return aAny;
+}
+
+sal_Bool SAL_CALL
+ ScAccessibleCellBase::setCurrentValue( const uno::Any& aNumber )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ double fValue = 0;
+ bool bResult = false;
+ if((aNumber >>= fValue) && mpDoc && mpDoc->GetDocumentShell())
+ {
+ uno::Reference<XAccessibleStateSet> xParentStates;
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
+ xParentStates = xParentContext->getAccessibleStateSet();
+ }
+ if (IsEditable(xParentStates))
+ {
+ ScDocShell* pDocShell = static_cast<ScDocShell*>(mpDoc->GetDocumentShell());
+ bResult = pDocShell->GetDocFunc().SetValueCell(maCellAddress, fValue, false);
+ }
+ }
+ return bResult;
+}
+
+uno::Any SAL_CALL
+ ScAccessibleCellBase::getMaximumValue( )
+{
+ return uno::Any(DBL_MAX);
+}
+
+uno::Any SAL_CALL
+ ScAccessibleCellBase::getMinimumValue( )
+{
+ return uno::Any(-DBL_MAX);
+}
+
+uno::Any SAL_CALL
+ ScAccessibleCellBase::getMinimumIncrement( )
+{
+ return uno::Any();
+}
+
+ //===== XServiceInfo ====================================================
+
+OUString SAL_CALL ScAccessibleCellBase::getImplementationName()
+{
+ return "ScAccessibleCellBase";
+}
+
+ //===== XTypeProvider ===================================================
+
+uno::Sequence< uno::Type > SAL_CALL ScAccessibleCellBase::getTypes()
+{
+ return comphelper::concatSequences(ScAccessibleCellBaseImpl::getTypes(), ScAccessibleContextBase::getTypes());
+}
+
+uno::Sequence<sal_Int8> SAL_CALL
+ ScAccessibleCellBase::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+bool ScAccessibleCellBase::IsEditable(
+ const uno::Reference<XAccessibleStateSet>& rxParentStates)
+{
+ bool bEditable(false);
+ if (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::EDITABLE))
+ bEditable = true;
+ return bEditable;
+}
+
+OUString ScAccessibleCellBase::GetNote() const
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ OUString sNote;
+ if (mpDoc)
+ {
+ SfxObjectShell* pObjSh = mpDoc->GetDocumentShell();
+ if ( pObjSh )
+ {
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( pObjSh->GetModel(), uno::UNO_QUERY );
+ if ( xSpreadDoc.is() )
+ {
+ uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets();
+ uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
+ if ( xIndex.is() )
+ {
+ uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab());
+ uno::Reference<sheet::XSpreadsheet> xTable;
+ if (aTable>>=xTable)
+ {
+ uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row());
+ if (xCell.is())
+ {
+ uno::Reference <sheet::XSheetAnnotationAnchor> xAnnotationAnchor ( xCell, uno::UNO_QUERY);
+ if(xAnnotationAnchor.is())
+ {
+ uno::Reference <sheet::XSheetAnnotation> xSheetAnnotation = xAnnotationAnchor->getAnnotation();
+ if (xSheetAnnotation.is())
+ {
+ uno::Reference <text::XSimpleText> xText (xSheetAnnotation, uno::UNO_QUERY);
+ if (xText.is())
+ {
+ sNote = xText->getString();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return sNote;
+}
+
+OUString ScAccessibleCellBase::getShadowAttrs() const
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ table::ShadowFormat aShadowFmt;
+ if (mpDoc)
+ {
+ SfxObjectShell* pObjSh = mpDoc->GetDocumentShell();
+ if ( pObjSh )
+ {
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( pObjSh->GetModel(), uno::UNO_QUERY );
+ if ( xSpreadDoc.is() )
+ {
+ uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets();
+ uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
+ if ( xIndex.is() )
+ {
+ uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab());
+ uno::Reference<sheet::XSpreadsheet> xTable;
+ if (aTable>>=xTable)
+ {
+ uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row());
+ if (xCell.is())
+ {
+ uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
+ if (xCellProps.is())
+ {
+ uno::Any aAny = xCellProps->getPropertyValue(SC_UNONAME_SHADOW);
+ aAny >>= aShadowFmt;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ //construct shadow attributes string
+ OUString sShadowAttrs("Shadow:");
+ OUString sInnerSplit(",");
+ OUString sOuterSplit(";");
+ sal_Int32 nLocationVal = 0;
+ switch( aShadowFmt.Location )
+ {
+ case table::ShadowLocation_TOP_LEFT:
+ nLocationVal = 1;
+ break;
+ case table::ShadowLocation_TOP_RIGHT:
+ nLocationVal = 2;
+ break;
+ case table::ShadowLocation_BOTTOM_LEFT:
+ nLocationVal = 3;
+ break;
+ case table::ShadowLocation_BOTTOM_RIGHT:
+ nLocationVal = 4;
+ break;
+ default:
+ break;
+ }
+ //if there is no shadow property for the cell
+ if ( nLocationVal == 0 )
+ {
+ sShadowAttrs += sOuterSplit;
+ return sShadowAttrs;
+ }
+ //else return all the shadow properties
+ sShadowAttrs += "Location=" +
+ OUString::number( nLocationVal ) +
+ sInnerSplit +
+ "ShadowWidth=" +
+ OUString::number( static_cast<sal_Int32>(aShadowFmt.ShadowWidth) ) +
+ sInnerSplit +
+ "IsTransparent=" +
+ OUString::number( static_cast<int>(aShadowFmt.IsTransparent) ) +
+ sInnerSplit +
+ "Color=" +
+ OUString::number( aShadowFmt.Color ) +
+ sOuterSplit;
+ return sShadowAttrs;
+}
+
+OUString ScAccessibleCellBase::getBorderAttrs()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ table::BorderLine aTopBorder;
+ table::BorderLine aBottomBorder;
+ table::BorderLine aLeftBorder;
+ table::BorderLine aRightBorder;
+ if (mpDoc)
+ {
+ SfxObjectShell* pObjSh = mpDoc->GetDocumentShell();
+ if ( pObjSh )
+ {
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( pObjSh->GetModel(), uno::UNO_QUERY );
+ if ( xSpreadDoc.is() )
+ {
+ uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets();
+ uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
+ if ( xIndex.is() )
+ {
+ uno::Any aTable = xIndex->getByIndex(maCellAddress.Tab());
+ uno::Reference<sheet::XSpreadsheet> xTable;
+ if (aTable>>=xTable)
+ {
+ uno::Reference<table::XCell> xCell = xTable->getCellByPosition(maCellAddress.Col(), maCellAddress.Row());
+ if (xCell.is())
+ {
+ uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
+ if (xCellProps.is())
+ {
+ uno::Any aAny = xCellProps->getPropertyValue(SC_UNONAME_TOPBORDER);
+ aAny >>= aTopBorder;
+ aAny = xCellProps->getPropertyValue(SC_UNONAME_BOTTBORDER);
+ aAny >>= aBottomBorder;
+ aAny = xCellProps->getPropertyValue(SC_UNONAME_LEFTBORDER);
+ aAny >>= aLeftBorder;
+ aAny = xCellProps->getPropertyValue(SC_UNONAME_RIGHTBORDER);
+ aAny >>= aRightBorder;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Color aColor;
+ bool bIn = mpDoc && mpDoc->IsCellInChangeTrack(maCellAddress,&aColor);
+ if (bIn)
+ {
+ aTopBorder.Color = sal_Int32(aColor);
+ aBottomBorder.Color = sal_Int32(aColor);
+ aLeftBorder.Color = sal_Int32(aColor);
+ aRightBorder.Color = sal_Int32(aColor);
+ aTopBorder.OuterLineWidth = DEFAULT_LINE_WIDTH;
+ aBottomBorder.OuterLineWidth = DEFAULT_LINE_WIDTH;
+ aLeftBorder.OuterLineWidth = DEFAULT_LINE_WIDTH;
+ aRightBorder.OuterLineWidth = DEFAULT_LINE_WIDTH;
+ }
+
+ //construct border attributes string
+ OUString sBorderAttrs;
+ OUString sInnerSplit(",");
+ OUString sOuterSplit(";");
+ //top border
+ //if top of the cell has no border
+ if ( aTopBorder.InnerLineWidth == 0 && aTopBorder.OuterLineWidth == 0 )
+ {
+ sBorderAttrs += "TopBorder:;";
+ }
+ else//add all the border properties to the return string.
+ {
+ sBorderAttrs += "TopBorder:Color=" +
+ OUString::number( aTopBorder.Color ) +
+ sInnerSplit +
+ "InnerLineWidth=" +
+ OUString::number( static_cast<sal_Int32>(aTopBorder.InnerLineWidth) ) +
+ sInnerSplit +
+ "OuterLineWidth=" +
+ OUString::number( static_cast<sal_Int32>(aTopBorder.OuterLineWidth) ) +
+ sInnerSplit +
+ "LineDistance=" +
+ OUString::number( static_cast<sal_Int32>(aTopBorder.LineDistance) ) +
+ sOuterSplit;
+ }
+ //bottom border
+ if ( aBottomBorder.InnerLineWidth == 0 && aBottomBorder.OuterLineWidth == 0 )
+ {
+ sBorderAttrs += "BottomBorder:;";
+ }
+ else
+ {
+ sBorderAttrs += "BottomBorder:Color=" +
+ OUString::number( aBottomBorder.Color ) +
+ sInnerSplit +
+ "InnerLineWidth=" +
+ OUString::number( static_cast<sal_Int32>(aBottomBorder.InnerLineWidth) ) +
+ sInnerSplit +
+ "OuterLineWidth=" +
+ OUString::number( static_cast<sal_Int32>(aBottomBorder.OuterLineWidth) ) +
+ sInnerSplit +
+ "LineDistance=" +
+ OUString::number( static_cast<sal_Int32>(aBottomBorder.LineDistance) ) +
+ sOuterSplit;
+ }
+ //left border
+ if ( aLeftBorder.InnerLineWidth == 0 && aLeftBorder.OuterLineWidth == 0 )
+ {
+ sBorderAttrs += "LeftBorder:;";
+ }
+ else
+ {
+ sBorderAttrs += "LeftBorder:Color=" +
+ OUString::number( aLeftBorder.Color ) +
+ sInnerSplit +
+ "InnerLineWidth=" +
+ OUString::number( static_cast<sal_Int32>(aLeftBorder.InnerLineWidth) ) +
+ sInnerSplit +
+ "OuterLineWidth=" +
+ OUString::number( static_cast<sal_Int32>(aLeftBorder.OuterLineWidth) ) +
+ sInnerSplit +
+ "LineDistance=" +
+ OUString::number( static_cast<sal_Int32>(aLeftBorder.LineDistance) ) +
+ sOuterSplit;
+ }
+ //right border
+ if ( aRightBorder.InnerLineWidth == 0 && aRightBorder.OuterLineWidth == 0 )
+ {
+ sBorderAttrs += "RightBorder:;";
+ }
+ else
+ {
+ sBorderAttrs += "RightBorder:Color=" +
+ OUString::number( aRightBorder.Color ) +
+ sInnerSplit +
+ "InnerLineWidth=" +
+ OUString::number( static_cast<sal_Int32>(aRightBorder.InnerLineWidth) ) +
+ sInnerSplit +
+ "OuterLineWidth=" +
+ OUString::number( static_cast<sal_Int32>(aRightBorder.OuterLineWidth) ) +
+ sInnerSplit +
+ "LineDistance=" +
+ OUString::number( static_cast<sal_Int32>(aRightBorder.LineDistance) ) +
+ sOuterSplit;
+ }
+ return sBorderAttrs;
+}
+//end of cell attributes
+
+OUString ScAccessibleCellBase::GetAllDisplayNote() const
+{
+ OUString strNote;
+ OUString strTrackText;
+ if (mpDoc)
+ {
+ bool bLeftedge = false;
+ mpDoc->GetCellChangeTrackNote(maCellAddress,strTrackText,bLeftedge);
+ }
+ if (!strTrackText.isEmpty())
+ {
+ ScDetectiveFunc::AppendChangTrackNoteSeparator(strTrackText);
+ strNote = strTrackText;
+ }
+ strNote += GetNote();
+ return strNote;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessibleContextBase.cxx b/sc/source/ui/Accessibility/AccessibleContextBase.cxx
new file mode 100644
index 000000000..cdbb5ea71
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleContextBase.cxx
@@ -0,0 +1,507 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleContextBase.hxx>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/IllegalAccessibleComponentStateException.hpp>
+#include <tools/gen.hxx>
+#include <tools/color.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <svl/hint.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <vcl/unohelp.hxx>
+#include <comphelper/accessibleeventnotifier.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+ScAccessibleContextBase::ScAccessibleContextBase(
+ const uno::Reference<XAccessible>& rxParent,
+ const sal_Int16 aRole)
+ :
+ ScAccessibleContextBaseWeakImpl(m_aMutex),
+ mxParent(rxParent),
+ mnClientId(0),
+ maRole(aRole)
+{
+}
+
+ScAccessibleContextBase::~ScAccessibleContextBase()
+{
+ if (!IsDefunc() && !rBHelper.bInDispose)
+ {
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+ // call dispose to inform object which have a weak reference to this object
+ dispose();
+ }
+}
+
+void ScAccessibleContextBase::Init()
+{
+ // hold reference to make sure that the destructor is not called
+ uno::Reference< XAccessibleContext > xKeepAlive(this);
+
+ if (mxParent.is())
+ {
+ uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->addAccessibleEventListener(this);
+ }
+ msName = createAccessibleName();
+ msDescription = createAccessibleDescription();
+}
+
+void SAL_CALL ScAccessibleContextBase::disposing()
+{
+ SolarMutexGuard aGuard;
+// CommitDefunc(); not necessary and should not be send, because it cost a lot of time
+
+ // hold reference to make sure that the destructor is not called
+ uno::Reference< XAccessibleContext > xKeepAlive(this);
+
+ if ( mnClientId )
+ {
+ sal_Int32 nTemClientId(mnClientId);
+ mnClientId = 0;
+ comphelper::AccessibleEventNotifier::revokeClientNotifyDisposing( nTemClientId, *this );
+ }
+
+ if (mxParent.is())
+ {
+ uno::Reference< XAccessibleEventBroadcaster > xBroadcaster (mxParent->getAccessibleContext(), uno::UNO_QUERY);
+ if (xBroadcaster.is())
+ xBroadcaster->removeAccessibleEventListener(this);
+ mxParent = nullptr;
+ }
+
+ ScAccessibleContextBaseWeakImpl::disposing();
+}
+
+//===== XInterface =====================================================
+
+uno::Any SAL_CALL ScAccessibleContextBase::queryInterface( uno::Type const & rType )
+{
+ uno::Any aAny (ScAccessibleContextBaseWeakImpl::queryInterface(rType));
+ return aAny.hasValue() ? aAny : ScAccessibleContextBaseImplEvent::queryInterface(rType);
+}
+
+void SAL_CALL ScAccessibleContextBase::acquire()
+ noexcept
+{
+ ScAccessibleContextBaseWeakImpl::acquire();
+}
+
+void SAL_CALL ScAccessibleContextBase::release()
+ noexcept
+{
+ ScAccessibleContextBaseWeakImpl::release();
+}
+
+//===== SfxListener =====================================================
+
+void ScAccessibleContextBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ // it seems the Broadcaster is dying, since the view is dying
+ dispose();
+ }
+}
+
+//===== XAccessible =========================================================
+
+uno::Reference< XAccessibleContext> SAL_CALL
+ ScAccessibleContextBase::getAccessibleContext()
+{
+ return this;
+}
+
+//===== XAccessibleComponent ================================================
+
+sal_Bool SAL_CALL ScAccessibleContextBase::containsPoint(const awt::Point& rPoint )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ return tools::Rectangle (Point(), GetBoundingBox().GetSize()).Contains(VCLPoint(rPoint));
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessibleContextBase::getAccessibleAtPoint(
+ const awt::Point& /* rPoint */ )
+{
+ OSL_FAIL("not implemented");
+ return uno::Reference<XAccessible>();
+}
+
+awt::Rectangle SAL_CALL ScAccessibleContextBase::getBounds( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ return AWTRectangle(GetBoundingBox());
+}
+
+awt::Point SAL_CALL ScAccessibleContextBase::getLocation( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ return AWTPoint(GetBoundingBox().TopLeft());
+}
+
+awt::Point SAL_CALL ScAccessibleContextBase::getLocationOnScreen( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ return AWTPoint(GetBoundingBoxOnScreen().TopLeft());
+}
+
+awt::Size SAL_CALL ScAccessibleContextBase::getSize( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ return AWTSize(GetBoundingBox().GetSize());
+}
+
+bool ScAccessibleContextBase::isShowing( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ bool bShowing(false);
+ if (mxParent.is())
+ {
+ uno::Reference<XAccessibleComponent> xParentComponent (mxParent->getAccessibleContext(), uno::UNO_QUERY);
+ if (xParentComponent.is())
+ {
+ tools::Rectangle aParentBounds(VCLRectangle(xParentComponent->getBounds()));
+ tools::Rectangle aBounds(VCLRectangle(getBounds()));
+ bShowing = aBounds.Overlaps(aParentBounds);
+ }
+ }
+ return bShowing;
+}
+
+bool ScAccessibleContextBase::isVisible()
+{
+ return true;
+}
+
+void SAL_CALL ScAccessibleContextBase::grabFocus( )
+{
+ OSL_FAIL("not implemented");
+}
+
+sal_Int32 SAL_CALL ScAccessibleContextBase::getForeground( )
+{
+ return sal_Int32(COL_BLACK);
+}
+
+sal_Int32 SAL_CALL ScAccessibleContextBase::getBackground( )
+{
+ return sal_Int32(COL_WHITE);
+}
+
+//===== XAccessibleContext ==================================================
+
+sal_Int32 SAL_CALL ScAccessibleContextBase::getAccessibleChildCount()
+{
+ OSL_FAIL("should be implemented in the abrevated class");
+ return 0;
+}
+
+uno::Reference<XAccessible> SAL_CALL
+ ScAccessibleContextBase::getAccessibleChild(sal_Int32 /* nIndex */)
+{
+ OSL_FAIL("should be implemented in the abrevated class");
+ return uno::Reference<XAccessible>();
+}
+
+uno::Reference<XAccessible> SAL_CALL
+ ScAccessibleContextBase::getAccessibleParent()
+{
+ return mxParent;
+}
+
+sal_Int32 SAL_CALL
+ ScAccessibleContextBase::getAccessibleIndexInParent()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ // Use a simple but slow solution for now. Optimize later.
+ // Return -1 to indicate that this object's parent does not know about the
+ // object.
+ sal_Int32 nIndex(-1);
+
+ // Iterate over all the parent's children and search for this object.
+ if (mxParent.is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext (
+ mxParent->getAccessibleContext());
+ if (xParentContext.is())
+ {
+ sal_Int32 nChildCount = xParentContext->getAccessibleChildCount();
+ for (sal_Int32 i=0; i<nChildCount; ++i)
+ {
+ uno::Reference<XAccessible> xChild (xParentContext->getAccessibleChild (i));
+ if (xChild.is() && xChild.get() == this)
+ nIndex = i;
+ }
+ }
+ }
+
+ return nIndex;
+}
+
+sal_Int16 SAL_CALL
+ ScAccessibleContextBase::getAccessibleRole()
+{
+ return maRole;
+}
+
+OUString SAL_CALL
+ ScAccessibleContextBase::getAccessibleDescription()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (msDescription.isEmpty())
+ {
+ OUString sDescription(createAccessibleDescription());
+
+ if (msDescription != sDescription)
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::DESCRIPTION_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ aEvent.OldValue <<= msDescription;
+ aEvent.NewValue <<= sDescription;
+
+ msDescription = sDescription;
+
+ CommitChange(aEvent);
+ }
+ }
+ return msDescription;
+}
+
+OUString SAL_CALL
+ ScAccessibleContextBase::getAccessibleName()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (msName.isEmpty())
+ {
+ OUString sName(createAccessibleName());
+ OSL_ENSURE(!sName.isEmpty(), "We should give always a name.");
+
+ if (msName != sName)
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::NAME_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ aEvent.OldValue <<= msName;
+ aEvent.NewValue <<= sName;
+
+ msName = sName;
+
+ CommitChange(aEvent);
+ }
+ }
+ return msName;
+}
+
+uno::Reference<XAccessibleRelationSet> SAL_CALL
+ ScAccessibleContextBase::getAccessibleRelationSet()
+{
+ return new utl::AccessibleRelationSetHelper();
+}
+
+uno::Reference<XAccessibleStateSet> SAL_CALL
+ ScAccessibleContextBase::getAccessibleStateSet()
+{
+ return uno::Reference<XAccessibleStateSet>();
+}
+
+lang::Locale SAL_CALL
+ ScAccessibleContextBase::getLocale()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (mxParent.is())
+ {
+ uno::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
+ ScAccessibleContextBase::addAccessibleEventListener(
+ const uno::Reference<XAccessibleEventListener>& xListener)
+{
+ if (xListener.is())
+ {
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (!IsDefunc())
+ {
+ if (!mnClientId)
+ mnClientId = comphelper::AccessibleEventNotifier::registerClient( );
+ comphelper::AccessibleEventNotifier::addEventListener( mnClientId, xListener );
+ }
+ }
+}
+
+void SAL_CALL
+ ScAccessibleContextBase::removeAccessibleEventListener(
+ const uno::Reference<XAccessibleEventListener>& xListener)
+{
+ if (!xListener.is())
+ return;
+
+ SolarMutexGuard aGuard;
+ if (IsDefunc() || !mnClientId)
+ return;
+
+ sal_Int32 nListenerCount = comphelper::AccessibleEventNotifier::removeEventListener( mnClientId, xListener );
+ if ( !nListenerCount )
+ {
+ // no listeners anymore
+ // -> revoke ourself. This may lead to the notifier thread dying (if we were the last client),
+ // and at least to us not firing any events anymore, in case somebody calls
+ // NotifyAccessibleEvent, again
+ comphelper::AccessibleEventNotifier::revokeClient( mnClientId );
+ mnClientId = 0;
+ }
+}
+
+ //===== XAccessibleEventListener ========================================
+
+void SAL_CALL ScAccessibleContextBase::disposing(
+ const lang::EventObject& rSource )
+{
+ SolarMutexGuard aGuard;
+ if (rSource.Source == mxParent)
+ dispose();
+}
+
+void SAL_CALL ScAccessibleContextBase::notifyEvent(
+ const AccessibleEventObject& /* aEvent */ )
+{
+}
+
+// XServiceInfo
+OUString SAL_CALL ScAccessibleContextBase::getImplementationName()
+{
+ return "ScAccessibleContextBase";
+}
+
+sal_Bool SAL_CALL ScAccessibleContextBase::supportsService(const OUString& sServiceName)
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+uno::Sequence< OUString> SAL_CALL
+ ScAccessibleContextBase::getSupportedServiceNames()
+{
+ return {"com.sun.star.accessibility.Accessible",
+ "com.sun.star.accessibility.AccessibleContext"};
+}
+
+//===== XTypeProvider =======================================================
+
+uno::Sequence< uno::Type > SAL_CALL ScAccessibleContextBase::getTypes()
+{
+ return comphelper::concatSequences(ScAccessibleContextBaseWeakImpl::getTypes(), ScAccessibleContextBaseImplEvent::getTypes());
+}
+
+uno::Sequence<sal_Int8> SAL_CALL
+ ScAccessibleContextBase::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+//===== internal ============================================================
+
+OUString
+ ScAccessibleContextBase::createAccessibleDescription()
+{
+ OSL_FAIL("should be implemented in the abrevated class");
+ return OUString();
+}
+
+OUString ScAccessibleContextBase::createAccessibleName()
+{
+ OSL_FAIL("should be implemented in the abrevated class");
+ return OUString();
+}
+
+void ScAccessibleContextBase::CommitChange(const AccessibleEventObject& rEvent) const
+{
+ if (mnClientId)
+ comphelper::AccessibleEventNotifier::addEvent( mnClientId, rEvent );
+}
+
+void ScAccessibleContextBase::CommitFocusGained() const
+{
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::STATE_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
+ aEvent.NewValue <<= AccessibleStateType::FOCUSED;
+
+ CommitChange(aEvent);
+}
+
+void ScAccessibleContextBase::CommitFocusLost() const
+{
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::STATE_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(const_cast<ScAccessibleContextBase*>(this));
+ aEvent.OldValue <<= AccessibleStateType::FOCUSED;
+
+ CommitChange(aEvent);
+}
+
+tools::Rectangle ScAccessibleContextBase::GetBoundingBoxOnScreen() const
+{
+ OSL_FAIL("not implemented");
+ return tools::Rectangle();
+}
+
+tools::Rectangle ScAccessibleContextBase::GetBoundingBox() const
+{
+ OSL_FAIL("not implemented");
+ return tools::Rectangle();
+}
+
+void ScAccessibleContextBase::IsObjectValid() const
+{
+ if (rBHelper.bDisposed || rBHelper.bInDispose)
+ throw lang::DisposedException();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessibleCsvControl.cxx b/sc/source/ui/Accessibility/AccessibleCsvControl.cxx
new file mode 100644
index 000000000..e9a4a1dee
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleCsvControl.cxx
@@ -0,0 +1,1460 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <AccessibleCsvControl.hxx>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleTextType.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <comphelper/sequence.hxx>
+#include <scitems.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/langitem.hxx>
+#include <csvtablebox.hxx>
+#include <csvcontrol.hxx>
+#include <csvruler.hxx>
+#include <csvgrid.hxx>
+#include <AccessibleText.hxx>
+#include <editsrc.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <scmod.hxx>
+#include <svtools/colorcfg.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+
+using ::utl::AccessibleRelationSetHelper;
+using ::utl::AccessibleStateSetHelper;
+using ::accessibility::AccessibleStaticTextBase;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::XInterface;
+using ::com::sun::star::lang::IndexOutOfBoundsException;
+using ::com::sun::star::beans::PropertyValue;
+using namespace ::com::sun::star::accessibility;
+
+const sal_Unicode cRulerDot = '.';
+const sal_Unicode cRulerLine = '|';
+
+const sal_Int32 CSV_LINE_HEADER = CSV_POS_INVALID;
+const sal_uInt32 CSV_COLUMN_HEADER = CSV_COLUMN_INVALID;
+
+ScAccessibleCsvControl::ScAccessibleCsvControl(ScCsvControl& rControl)
+ : mpControl(&rControl)
+{
+}
+
+ScAccessibleCsvControl::~ScAccessibleCsvControl()
+{
+ ensureDisposed();
+}
+
+void SAL_CALL ScAccessibleCsvControl::disposing()
+{
+ SolarMutexGuard aGuard;
+ mpControl = nullptr;
+ comphelper::OAccessibleComponentHelper::disposing();
+}
+
+// XAccessibleComponent -------------------------------------------------------
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvControl::getAccessibleAtPoint( const css::awt::Point& /* rPoint */ )
+{
+ ensureAlive();
+ return nullptr;
+}
+
+void SAL_CALL ScAccessibleCsvControl::grabFocus()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ implGetControl().GrabFocus();
+}
+
+// events ---------------------------------------------------------------------
+
+void ScAccessibleCsvControl::SendFocusEvent( bool bFocused )
+{
+ Any aOldAny, aNewAny;
+ if (bFocused)
+ aNewAny <<= AccessibleStateType::FOCUSED;
+ else
+ aOldAny <<= AccessibleStateType::FOCUSED;
+ NotifyAccessibleEvent(AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny);
+}
+
+void ScAccessibleCsvControl::SendCaretEvent()
+{
+ OSL_FAIL( "ScAccessibleCsvControl::SendCaretEvent - Illegal call" );
+}
+
+void ScAccessibleCsvControl::SendVisibleEvent()
+{
+ NotifyAccessibleEvent(AccessibleEventId::VISIBLE_DATA_CHANGED, Any(), Any());
+}
+
+void ScAccessibleCsvControl::SendSelectionEvent()
+{
+ NotifyAccessibleEvent(AccessibleEventId::SELECTION_CHANGED, Any(), Any());
+}
+
+void ScAccessibleCsvControl::SendTableUpdateEvent( sal_uInt32 /* nFirstColumn */, sal_uInt32 /* nLastColumn */, bool /* bAllRows */ )
+{
+ OSL_FAIL( "ScAccessibleCsvControl::SendTableUpdateEvent - Illegal call" );
+}
+
+void ScAccessibleCsvControl::SendInsertColumnEvent( sal_uInt32 /* nFirstColumn */, sal_uInt32 /* nLastColumn */ )
+{
+ OSL_FAIL( "ScAccessibleCsvControl::SendInsertColumnEvent - Illegal call" );
+}
+
+void ScAccessibleCsvControl::SendRemoveColumnEvent( sal_uInt32 /* nFirstColumn */, sal_uInt32 /* nLastColumn */ )
+{
+ OSL_FAIL( "ScAccessibleCsvControl::SendRemoveColumnEvent - Illegal call" );
+}
+
+// helpers --------------------------------------------------------------------
+
+css::awt::Rectangle ScAccessibleCsvControl::implGetBounds()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ Size aOutSize(implGetControl().GetOutputSizePixel());
+ return css::awt::Rectangle(0, 0, aOutSize.Width(), aOutSize.Height());
+}
+
+ScCsvControl& ScAccessibleCsvControl::implGetControl() const
+{
+ assert(mpControl && "ScAccessibleCsvControl::implGetControl - missing control");
+ return *mpControl;
+}
+
+rtl::Reference<AccessibleStateSetHelper> ScAccessibleCsvControl::implCreateStateSet()
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<AccessibleStateSetHelper> pStateSet = new AccessibleStateSetHelper();
+ if (isAlive())
+ {
+ const ScCsvControl& rCtrl = implGetControl();
+ pStateSet->AddState( AccessibleStateType::OPAQUE );
+ if( rCtrl.IsEnabled() )
+ pStateSet->AddState( AccessibleStateType::ENABLED );
+ if( rCtrl.IsReallyVisible() )
+ pStateSet->AddState( AccessibleStateType::SHOWING );
+ if( rCtrl.IsVisible() )
+ pStateSet->AddState( AccessibleStateType::VISIBLE );
+ }
+ else
+ pStateSet->AddState( AccessibleStateType::DEFUNC );
+ return pStateSet;
+}
+
+// Ruler ======================================================================
+
+/** Converts a ruler cursor position to API text index. */
+static sal_Int32 lcl_GetApiPos( sal_Int32 nRulerPos )
+{
+ sal_Int32 nApiPos = nRulerPos;
+ sal_Int32 nStart = (nRulerPos - 1) / 10;
+ sal_Int32 nExp = 1;
+ while( nStart >= nExp )
+ {
+ nApiPos += nStart - nExp + 1;
+ nExp *= 10;
+ }
+ return ::std::max( nApiPos, static_cast<sal_Int32>(0) );
+}
+
+/** Converts an API text index to a ruler cursor position. */
+static sal_Int32 lcl_GetRulerPos( sal_Int32 nApiPos )
+{
+ sal_Int32 nDiv = 10;
+ sal_Int32 nExp = 10;
+ sal_Int32 nRulerPos = 0;
+ sal_Int32 nApiBase = 0;
+ sal_Int32 nApiLimit = 10;
+ while( nApiPos >= nApiLimit )
+ {
+ ++nDiv;
+ nRulerPos = nExp;
+ nExp *= 10;
+ nApiBase = nApiLimit;
+ nApiLimit = lcl_GetApiPos( nExp );
+ }
+ sal_Int32 nRelPos = nApiPos - nApiBase;
+ return nRulerPos + nRelPos / nDiv * 10 + ::std::max<sal_Int32>( nRelPos % nDiv - nDiv + 10, 0 );
+}
+
+/** Expands the sequence's size and returns the base index of the new inserted elements. */
+static sal_Int32 lcl_ExpandSequence( Sequence< PropertyValue >& rSeq, sal_Int32 nExp )
+{
+ OSL_ENSURE( nExp > 0, "lcl_ExpandSequence - invalid value" );
+ rSeq.realloc( rSeq.getLength() + nExp );
+ return rSeq.getLength() - nExp;
+}
+
+/** Fills the property value rVal with the specified name and value from the item. */
+static void lcl_FillProperty( PropertyValue& rVal, const OUString& rPropName, const SfxPoolItem& rItem, sal_uInt8 nMID )
+{
+ rVal.Name = rPropName;
+ rItem.QueryValue( rVal.Value, nMID );
+}
+
+/** Fills the sequence with all font attributes of rFont. */
+static void lcl_FillFontAttributes( Sequence< PropertyValue >& rSeq, const vcl::Font& rFont )
+{
+ SvxFontItem aFontItem( rFont.GetFamilyType(), rFont.GetFamilyName(), rFont.GetStyleName(), rFont.GetPitch(), rFont.GetCharSet(), ATTR_FONT );
+ SvxFontHeightItem aHeightItem( rFont.GetFontSize().Height(), 100, ATTR_FONT_HEIGHT );
+ SvxLanguageItem aLangItem( rFont.GetLanguage(), ATTR_FONT_LANGUAGE );
+
+ sal_Int32 nIndex = lcl_ExpandSequence( rSeq, 7 );
+ auto pSeq = rSeq.getArray();
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharFontName", aFontItem, MID_FONT_FAMILY_NAME );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharFontFamily", aFontItem, MID_FONT_FAMILY );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharFontStyleName", aFontItem, MID_FONT_STYLE_NAME );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharFontCharSet", aFontItem, MID_FONT_PITCH );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharFontPitch", aFontItem, MID_FONT_CHAR_SET );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharHeight", aHeightItem, MID_FONTHEIGHT );
+ lcl_FillProperty( pSeq[ nIndex++ ], "CharLocale", aLangItem, MID_LANG_LOCALE );
+}
+
+ScAccessibleCsvRuler::ScAccessibleCsvRuler(ScCsvRuler& rRuler)
+ : ScAccessibleCsvControl(rRuler)
+{
+ constructStringBuffer();
+}
+
+ScAccessibleCsvRuler::~ScAccessibleCsvRuler()
+{
+ ensureDisposed();
+}
+
+// XAccessibleComponent -----------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getForeground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(Application::GetSettings().GetStyleSettings().GetLabelTextColor());
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getBackground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(Application::GetSettings().GetStyleSettings().GetFaceColor());
+}
+
+// XAccessibleContext ---------------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getAccessibleChildCount()
+{
+ ensureAlive();
+ return 0;
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvRuler::getAccessibleChild( sal_Int32 /* nIndex */ )
+{
+ ensureAlive();
+ throw IndexOutOfBoundsException();
+}
+
+Reference< XAccessibleRelationSet > SAL_CALL ScAccessibleCsvRuler::getAccessibleRelationSet()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ rtl::Reference<AccessibleRelationSetHelper> pRelationSet = new AccessibleRelationSetHelper();
+
+ ScCsvRuler& rRuler = implGetRuler();
+ ScCsvTableBox* pTableBox = rRuler.GetTableBox();
+ ScCsvGrid& rGrid = pTableBox->GetGrid();
+
+ css::uno::Reference<css::accessibility::XAccessible> xAccObj(static_cast<ScAccessibleCsvGrid*>(rGrid.GetAccessible()));
+ if( xAccObj.is() )
+ {
+ Sequence< Reference< XInterface > > aSeq{ xAccObj };
+ pRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::CONTROLLER_FOR, aSeq ) );
+ }
+
+ return pRelationSet;
+}
+
+Reference< XAccessibleStateSet > SAL_CALL ScAccessibleCsvRuler::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<AccessibleStateSetHelper> pStateSet = implCreateStateSet();
+ if( isAlive() )
+ {
+ pStateSet->AddState( AccessibleStateType::FOCUSABLE );
+ pStateSet->AddState( AccessibleStateType::SINGLE_LINE );
+ if( implGetRuler().HasFocus() )
+ pStateSet->AddState( AccessibleStateType::FOCUSED );
+ }
+ return pStateSet;
+}
+
+// XAccessibleText ------------------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getCaretPosition()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return lcl_GetApiPos( implGetRuler().GetRulerCursorPos() );
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvRuler::setCaretPosition( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nIndex );
+ ScCsvRuler& rRuler = implGetRuler();
+ sal_Int32 nOldCursor = rRuler.GetRulerCursorPos();
+ rRuler.Execute( CSVCMD_MOVERULERCURSOR, lcl_GetRulerPos( nIndex ) );
+ return rRuler.GetRulerCursorPos() != nOldCursor;
+}
+
+sal_Unicode SAL_CALL ScAccessibleCsvRuler::getCharacter( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nIndex );
+ return maBuffer[nIndex];
+}
+
+Sequence< PropertyValue > SAL_CALL ScAccessibleCsvRuler::getCharacterAttributes( sal_Int32 nIndex,
+ const css::uno::Sequence< OUString >& /* aRequestedAttributes */ )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndexWithEnd( nIndex );
+ Sequence< PropertyValue > aSeq;
+ lcl_FillFontAttributes( aSeq, implGetRuler().GetDrawingArea()->get_ref_device().GetFont() );
+ return aSeq;
+}
+
+css::awt::Rectangle SAL_CALL ScAccessibleCsvRuler::getCharacterBounds( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndexWithEnd( nIndex );
+ ScCsvRuler& rRuler = implGetRuler();
+ Point aPos( rRuler.GetX( lcl_GetRulerPos( nIndex ) ) - rRuler.GetCharWidth() / 2, 0 );
+ css::awt::Rectangle aRect( aPos.X(), aPos.Y(), rRuler.GetCharWidth(), rRuler.GetOutputSizePixel().Height() );
+ // do not return rectangle out of window
+ sal_Int32 nWidth = rRuler.GetOutputSizePixel().Width();
+ if( aRect.X >= nWidth )
+ throw IndexOutOfBoundsException();
+ if( aRect.X + aRect.Width > nWidth )
+ aRect.Width = nWidth - aRect.X;
+ return aRect;
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getCharacterCount()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return implGetTextLength();
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getIndexAtPoint( const css::awt::Point& rPoint )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ScCsvRuler& rRuler = implGetRuler();
+ // use object's coordinate system, convert to API position
+ return lcl_GetApiPos( ::std::clamp( rRuler.GetPosFromX( rPoint.X ), sal_Int32(0), rRuler.GetPosCount() ) );
+}
+
+OUString SAL_CALL ScAccessibleCsvRuler::getSelectedText()
+{
+ ensureAlive();
+ return OUString();
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getSelectionStart()
+{
+ ensureAlive();
+ return -1;
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvRuler::getSelectionEnd()
+{
+ ensureAlive();
+ return -1;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvRuler::setSelection( sal_Int32 /* nStartIndex */, sal_Int32 /* nEndIndex */ )
+{
+ ensureAlive();
+ return false;
+}
+
+OUString SAL_CALL ScAccessibleCsvRuler::getText()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return OUString( maBuffer.getStr(), implGetTextLength() );
+}
+
+OUString SAL_CALL ScAccessibleCsvRuler::getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidRange( nStartIndex, nEndIndex );
+ return OUString( maBuffer.getStr() + nStartIndex, nEndIndex - nStartIndex );
+}
+
+TextSegment SAL_CALL ScAccessibleCsvRuler::getTextAtIndex( sal_Int32 nIndex, sal_Int16 nTextType )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+
+ TextSegment aResult;
+ aResult.SegmentStart = -1;
+ aResult.SegmentEnd = -1;
+
+ if( (nIndex == implGetTextLength()) && (nTextType != AccessibleTextType::LINE) )
+ return aResult;
+
+ ensureValidIndex( nIndex );
+
+ OUStringBuffer aResultText; // will be assigned to aResult.SegmentText below
+ sal_Int32 nRulerPos = lcl_GetRulerPos( nIndex );
+
+ switch( nTextType )
+ {
+ // single character
+ case AccessibleTextType::CHARACTER:
+ {
+ aResult.SegmentStart = nIndex;
+ aResultText.append(maBuffer[nIndex]);
+ }
+ break;
+
+ // entire number or single dot/line
+ case AccessibleTextType::WORD:
+ case AccessibleTextType::GLYPH:
+ aResult.SegmentStart = nIndex;
+ if( nRulerPos % 10 )
+ aResultText.append(maBuffer[nIndex]);
+ else
+ aResultText.append( nRulerPos ); // string representation of sal_Int32!!!
+ break;
+
+ // entire text
+ case AccessibleTextType::SENTENCE:
+ case AccessibleTextType::PARAGRAPH:
+ case AccessibleTextType::LINE:
+ aResult.SegmentStart = 0;
+ aResultText.append( maBuffer.getStr(), implGetTextLength() );
+ break;
+
+ // equal-formatted text
+ case AccessibleTextType::ATTRIBUTE_RUN:
+ {
+ sal_Int32 nFirstIndex = implGetFirstEqualFormatted( nIndex );
+ sal_Int32 nLastIndex = implGetLastEqualFormatted( nIndex );
+ aResult.SegmentStart = nFirstIndex;
+ aResultText.append( maBuffer.getStr() + nFirstIndex, nLastIndex - nFirstIndex + 1 );
+ }
+ break;
+
+ default:
+ throw RuntimeException();
+ }
+
+ aResult.SegmentText = aResultText.makeStringAndClear();
+ aResult.SegmentEnd = aResult.SegmentStart + aResult.SegmentText.getLength();
+ return aResult;
+}
+
+TextSegment SAL_CALL ScAccessibleCsvRuler::getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 nTextType )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndexWithEnd( nIndex );
+
+ TextSegment aResult;
+ aResult.SegmentStart = -1;
+ aResult.SegmentEnd = -1;
+
+ sal_Int32 nRulerPos = lcl_GetRulerPos( nIndex );
+
+ switch( nTextType )
+ {
+ // single character
+ case AccessibleTextType::CHARACTER:
+ if( nIndex > 0 )
+ aResult = getTextAtIndex( nIndex - 1, nTextType );
+ // else empty
+ break;
+
+ // entire number or single dot/line
+ case AccessibleTextType::WORD:
+ case AccessibleTextType::GLYPH:
+ if( nRulerPos > 0 )
+ aResult = getTextAtIndex( lcl_GetApiPos( nRulerPos - 1 ), nTextType );
+ // else empty
+ break;
+
+ // entire text
+ case AccessibleTextType::SENTENCE:
+ case AccessibleTextType::PARAGRAPH:
+ case AccessibleTextType::LINE:
+ // empty
+ break;
+
+ // equal-formatted text
+ case AccessibleTextType::ATTRIBUTE_RUN:
+ {
+ sal_Int32 nFirstIndex = implGetFirstEqualFormatted( nIndex );
+ if( nFirstIndex > 0 )
+ aResult = getTextAtIndex( nFirstIndex - 1, nTextType );
+ // else empty
+ }
+ break;
+
+ default:
+ throw RuntimeException();
+ }
+ return aResult;
+}
+
+TextSegment SAL_CALL ScAccessibleCsvRuler::getTextBehindIndex( sal_Int32 nIndex, sal_Int16 nTextType )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndexWithEnd( nIndex );
+
+ TextSegment aResult;
+ aResult.SegmentStart = -1;
+ aResult.SegmentEnd = -1;
+
+ sal_Int32 nRulerPos = lcl_GetRulerPos( nIndex );
+ sal_Int32 nLastValid = implGetTextLength();
+
+ switch( nTextType )
+ {
+ // single character
+ case AccessibleTextType::CHARACTER:
+ if( nIndex < nLastValid )
+ aResult = getTextAtIndex( nIndex + 1, nTextType );
+ // else empty
+ break;
+
+ // entire number or single dot/line
+ case AccessibleTextType::WORD:
+ case AccessibleTextType::GLYPH:
+ if( nRulerPos < implGetRuler().GetPosCount() )
+ aResult = getTextAtIndex( lcl_GetApiPos( nRulerPos + 1 ), nTextType );
+ // else empty
+ break;
+
+ // entire text
+ case AccessibleTextType::SENTENCE:
+ case AccessibleTextType::PARAGRAPH:
+ case AccessibleTextType::LINE:
+ // empty
+ break;
+
+ // equal-formatted text
+ case AccessibleTextType::ATTRIBUTE_RUN:
+ {
+ sal_Int32 nLastIndex = implGetLastEqualFormatted( nIndex );
+ if( nLastIndex < nLastValid )
+ aResult = getTextAtIndex( nLastIndex + 1, nTextType );
+ // else empty
+ }
+ break;
+
+ default:
+ throw RuntimeException();
+ }
+ return aResult;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvRuler::copyText( sal_Int32 /* nStartIndex */, sal_Int32 /* nEndIndex */ )
+{
+ ensureAlive();
+ return false;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvRuler::scrollSubstringTo( sal_Int32 /* nStartIndex */, sal_Int32/* nEndIndex */, AccessibleScrollType /* aScrollType */ )
+{
+ return false;
+}
+
+// XInterface -----------------------------------------------------------------
+
+Any SAL_CALL ScAccessibleCsvRuler::queryInterface( const css::uno::Type& rType )
+{
+ Any aAny( ScAccessibleCsvRulerImpl::queryInterface( rType ) );
+ return aAny.hasValue() ? aAny : ScAccessibleCsvControl::queryInterface( rType );
+}
+
+void SAL_CALL ScAccessibleCsvRuler::acquire() noexcept
+{
+ ScAccessibleCsvControl::acquire();
+}
+
+void SAL_CALL ScAccessibleCsvRuler::release() noexcept
+{
+ ScAccessibleCsvControl::release();
+}
+
+// XTypeProvider --------------------------------------------------------------
+
+Sequence< css::uno::Type > SAL_CALL ScAccessibleCsvRuler::getTypes()
+{
+ return ::comphelper::concatSequences( ScAccessibleCsvControl::getTypes(),
+ Sequence { cppu::UnoType<XAccessibleText>::get() });
+}
+
+Sequence< sal_Int8 > SAL_CALL ScAccessibleCsvRuler::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// events ---------------------------------------------------------------------
+
+void ScAccessibleCsvRuler::SendCaretEvent()
+{
+ sal_Int32 nPos = implGetRuler().GetRulerCursorPos();
+ if (nPos != CSV_POS_INVALID)
+ {
+ Any aOldValue, aNewValue;
+ aNewValue <<= nPos;
+ NotifyAccessibleEvent( AccessibleEventId::CARET_CHANGED, aOldValue, aNewValue );
+ }
+}
+
+// helpers --------------------------------------------------------------------
+
+OUString SAL_CALL ScAccessibleCsvRuler::getAccessibleName()
+{
+ return ScResId( STR_ACC_CSVRULER_NAME );
+}
+
+OUString SAL_CALL ScAccessibleCsvRuler::getAccessibleDescription()
+{
+ return ScResId( STR_ACC_CSVRULER_DESCR );
+}
+
+void ScAccessibleCsvRuler::ensureValidIndex( sal_Int32 nIndex ) const
+{
+ if( (nIndex < 0) || (nIndex >= implGetTextLength()) )
+ throw IndexOutOfBoundsException();
+}
+
+void ScAccessibleCsvRuler::ensureValidIndexWithEnd( sal_Int32 nIndex ) const
+{
+ if( (nIndex < 0) || (nIndex > implGetTextLength()) )
+ throw IndexOutOfBoundsException();
+}
+
+void ScAccessibleCsvRuler::ensureValidRange( sal_Int32& rnStartIndex, sal_Int32& rnEndIndex ) const
+{
+ if( rnStartIndex > rnEndIndex )
+ ::std::swap( rnStartIndex, rnEndIndex );
+ if( (rnStartIndex < 0) || (rnEndIndex > implGetTextLength()) )
+ throw IndexOutOfBoundsException();
+}
+
+ScCsvRuler& ScAccessibleCsvRuler::implGetRuler() const
+{
+ return static_cast< ScCsvRuler& >( implGetControl() );
+}
+
+void ScAccessibleCsvRuler::constructStringBuffer()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ // extend existing string buffer to new ruler size
+ sal_Int32 nRulerCount = implGetRuler().GetPosCount();
+ sal_Int32 nRulerPos = lcl_GetRulerPos( maBuffer.getLength() );
+ for( ; nRulerPos <= nRulerCount; ++nRulerPos ) // include last position
+ {
+ switch( nRulerPos % 10 )
+ {
+ case 0: maBuffer.append( nRulerPos ); break;
+ case 5: maBuffer.append( cRulerLine ); break;
+ default: maBuffer.append( cRulerDot );
+ }
+ }
+}
+
+sal_Int32 ScAccessibleCsvRuler::implGetTextLength() const
+{
+ return lcl_GetApiPos( implGetRuler().GetPosCount() + 1 );
+}
+
+bool ScAccessibleCsvRuler::implHasSplit( sal_Int32 nApiPos )
+{
+ sal_Int32 nRulerPos = lcl_GetRulerPos( nApiPos );
+ return implGetRuler().HasSplit( nRulerPos ) && (nApiPos == lcl_GetApiPos( nRulerPos ));
+}
+
+sal_Int32 ScAccessibleCsvRuler::implGetFirstEqualFormatted( sal_Int32 nApiPos )
+{
+ bool bSplit = implHasSplit( nApiPos );
+ while( (nApiPos > 0) && (implHasSplit( nApiPos - 1 ) == bSplit) )
+ --nApiPos;
+ return nApiPos;
+}
+
+sal_Int32 ScAccessibleCsvRuler::implGetLastEqualFormatted( sal_Int32 nApiPos )
+{
+ bool bSplit = implHasSplit( nApiPos );
+ sal_Int32 nLength = implGetTextLength();
+ while( (nApiPos < nLength - 1) && (implHasSplit( nApiPos + 1 ) == bSplit) )
+ ++nApiPos;
+ return nApiPos;
+}
+
+css::uno::Reference<css::accessibility::XAccessible> SAL_CALL ScAccessibleCsvRuler::getAccessibleParent()
+{
+ return implGetControl().GetDrawingArea()->get_accessible_parent();
+}
+
+// Grid =======================================================================
+
+/** Converts a grid columnm index to an API column index. */
+static sal_Int32 lcl_GetApiColumn( sal_uInt32 nGridColumn )
+{
+ return (nGridColumn != CSV_COLUMN_HEADER) ? static_cast< sal_Int32 >( nGridColumn + 1 ) : 0;
+}
+
+/** Converts an API columnm index to a ScCsvGrid column index. */
+static sal_uInt32 lcl_GetGridColumn( sal_Int32 nApiColumn )
+{
+ return (nApiColumn > 0) ? static_cast< sal_uInt32 >( nApiColumn - 1 ) : CSV_COLUMN_HEADER;
+}
+
+ScAccessibleCsvGrid::ScAccessibleCsvGrid(ScCsvGrid& rGrid)
+ : ScAccessibleCsvControl(rGrid)
+{
+}
+
+ScAccessibleCsvGrid::~ScAccessibleCsvGrid()
+{
+ ensureDisposed();
+}
+
+void ScAccessibleCsvGrid::disposing()
+{
+ SolarMutexGuard aGuard;
+ for (auto& rEntry : maAccessibleChildren)
+ rEntry.second->dispose();
+ maAccessibleChildren.clear();
+ ScAccessibleCsvControl::disposing();
+}
+
+// XAccessibleComponent -------------------------------------------------------
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleAtPoint( const css::awt::Point& rPoint )
+{
+ Reference< XAccessible > xRet;
+ if( containsPoint( rPoint ) )
+ {
+ SolarMutexGuard aGuard;
+ ensureAlive();
+
+ const ScCsvGrid& rGrid = implGetGrid();
+ // #102679#; use <= instead of <, because the offset is the size and not the point
+ sal_Int32 nColumn = ((rGrid.GetFirstX() <= rPoint.X) && (rPoint.X <= rGrid.GetLastX())) ?
+ lcl_GetApiColumn( rGrid.GetColumnFromX( rPoint.X ) ) : 0;
+ sal_Int32 nRow = (rPoint.Y >= rGrid.GetHdrHeight()) ?
+ (rGrid.GetLineFromY( rPoint.Y ) - rGrid.GetFirstVisLine() + 1) : 0;
+ xRet = getAccessibleCell(nRow, nColumn);
+ }
+ return xRet;
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getForeground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(Application::GetSettings().GetStyleSettings().GetButtonTextColor());
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getBackground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor);
+}
+
+// XAccessibleContext ---------------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return implGetCellCount();
+}
+
+Reference<XAccessible> ScAccessibleCsvGrid::getAccessibleCell(sal_Int32 nRow, sal_Int32 nColumn)
+{
+ sal_Int32 nIndex = implGetIndex(nRow, nColumn);
+
+ XAccessibleSet::iterator aI = maAccessibleChildren.lower_bound(nIndex);
+ if (aI != maAccessibleChildren.end() && !(maAccessibleChildren.key_comp()(nIndex, aI->first)))
+ {
+ // key already exists
+ return aI->second;
+ }
+ // key does not exist
+ rtl::Reference<ScAccessibleCsvCell> xNew = implCreateCellObj(nRow, nColumn);
+ maAccessibleChildren.insert(aI, XAccessibleSet::value_type(nIndex, xNew));
+ return xNew;
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleChild( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nIndex );
+
+ return getAccessibleCell(implGetRow(nIndex), implGetColumn(nIndex));
+}
+
+Reference< XAccessibleRelationSet > SAL_CALL ScAccessibleCsvGrid::getAccessibleRelationSet()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ rtl::Reference<AccessibleRelationSetHelper> pRelationSet = new AccessibleRelationSetHelper();
+
+ ScCsvGrid& rGrid = implGetGrid();
+ ScCsvTableBox* pTableBox = rGrid.GetTableBox();
+ ScCsvRuler& rRuler = pTableBox->GetRuler();
+
+ if (rRuler.IsVisible())
+ {
+ css::uno::Reference<css::accessibility::XAccessible> xAccObj(static_cast<ScAccessibleCsvGrid*>(rRuler.GetAccessible()));
+ if( xAccObj.is() )
+ {
+ Sequence< Reference< XInterface > > aSeq{ xAccObj };
+ pRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::CONTROLLED_BY, aSeq ) );
+ }
+ }
+
+ return pRelationSet;
+}
+
+Reference< XAccessibleStateSet > SAL_CALL ScAccessibleCsvGrid::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<AccessibleStateSetHelper> pStateSet = implCreateStateSet();
+ if( isAlive() )
+ {
+ pStateSet->AddState( AccessibleStateType::FOCUSABLE );
+ pStateSet->AddState( AccessibleStateType::MULTI_SELECTABLE );
+ pStateSet->AddState( AccessibleStateType::MANAGES_DESCENDANTS );
+ if( implGetGrid().HasFocus() )
+ pStateSet->AddState( AccessibleStateType::FOCUSED );
+ }
+ else
+ pStateSet->AddState( AccessibleStateType::DEFUNC );
+ return pStateSet;
+}
+
+// XAccessibleTable -----------------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleRowCount()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return implGetRowCount();
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnCount()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return implGetColumnCount();
+}
+
+OUString SAL_CALL ScAccessibleCsvGrid::getAccessibleRowDescription( sal_Int32 nRow )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidPosition( nRow, 0 );
+ return implGetCellText( nRow, 0 );
+}
+
+OUString SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnDescription( sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidPosition( 0, nColumn );
+ return implGetCellText( 0, nColumn );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ ensureAlive();
+ ensureValidPosition( nRow, nColumn );
+ return 1;
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ ensureAlive();
+ ensureValidPosition( nRow, nColumn );
+ return 1;
+}
+
+Reference< XAccessibleTable > SAL_CALL ScAccessibleCsvGrid::getAccessibleRowHeaders()
+{
+ ensureAlive();
+ return nullptr;
+}
+
+Reference< XAccessibleTable > SAL_CALL ScAccessibleCsvGrid::getAccessibleColumnHeaders()
+{
+ ensureAlive();
+ return nullptr;
+}
+
+Sequence< sal_Int32 > SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleRows()
+{
+ ensureAlive();
+ return Sequence< sal_Int32 >();
+}
+
+Sequence< sal_Int32 > SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleColumns()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+
+ ScCsvGrid& rGrid = implGetGrid();
+ Sequence< sal_Int32 > aSeq( implGetColumnCount() );
+ auto pSeq = aSeq.getArray();
+
+ sal_Int32 nSeqIx = 0;
+ sal_uInt32 nColIx = rGrid.GetFirstSelected();
+ for( ; nColIx != CSV_COLUMN_INVALID; ++nSeqIx, nColIx = rGrid.GetNextSelected( nColIx ) )
+ pSeq[ nSeqIx ] = lcl_GetApiColumn( nColIx );
+
+ aSeq.realloc( nSeqIx );
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvGrid::isAccessibleRowSelected( sal_Int32 /* nRow */ )
+{
+ ensureAlive();
+ return false;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvGrid::isAccessibleColumnSelected( sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nColumn );
+ return implIsColumnSelected( nColumn );
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidPosition( nRow, nColumn );
+ return getAccessibleCell(nRow, nColumn);
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleCaption()
+{
+ ensureAlive();
+ return nullptr;
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getAccessibleSummary()
+{
+ ensureAlive();
+ return nullptr;
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvGrid::isAccessibleSelected( sal_Int32 /* nRow */, sal_Int32 nColumn )
+{
+ return isAccessibleColumnSelected( nColumn );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidPosition( nRow, nColumn );
+ return implGetIndex( nRow, nColumn );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleRow( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nChildIndex );
+ return implGetRow( nChildIndex );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getAccessibleColumn( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nChildIndex );
+ return implGetColumn( nChildIndex );
+}
+
+// XAccessibleSelection -------------------------------------------------------
+
+void SAL_CALL ScAccessibleCsvGrid::selectAccessibleChild( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nChildIndex );
+ sal_Int32 nColumn = implGetColumn( nChildIndex );
+ if( nChildIndex == 0 )
+ implGetGrid().SelectAll();
+ else
+ implSelectColumn( nColumn, true );
+}
+
+sal_Bool SAL_CALL ScAccessibleCsvGrid::isAccessibleChildSelected( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ensureValidIndex( nChildIndex );
+ sal_Int32 nColumn = implGetColumn( nChildIndex );
+ return implIsColumnSelected( nColumn );
+}
+
+void SAL_CALL ScAccessibleCsvGrid::clearAccessibleSelection()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ implGetGrid().SelectAll( false );
+}
+
+void SAL_CALL ScAccessibleCsvGrid::selectAllAccessibleChildren()
+{
+ selectAccessibleChild( 0 );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return implGetRowCount() * implGetSelColumnCount();
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvGrid::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ sal_Int32 nColumns = implGetSelColumnCount();
+ if( nColumns == 0 )
+ throw IndexOutOfBoundsException();
+
+ sal_Int32 nRow = nSelectedChildIndex / nColumns;
+ sal_Int32 nColumn = implGetSelColumn( nSelectedChildIndex % nColumns );
+ return getAccessibleCellAt( nRow, nColumn );
+}
+
+void SAL_CALL ScAccessibleCsvGrid::deselectAccessibleChild( sal_Int32 nSelectedChildIndex )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ sal_Int32 nColumns = implGetSelColumnCount();
+ if( nColumns == 0 )
+ throw IndexOutOfBoundsException();
+
+ sal_Int32 nColumn = implGetSelColumn( nSelectedChildIndex % nColumns );
+ ensureValidPosition( nSelectedChildIndex / nColumns, nColumn );
+ if( nColumn > 0 )
+ implSelectColumn( nColumn, false );
+}
+
+// XInterface -----------------------------------------------------------------
+
+Any SAL_CALL ScAccessibleCsvGrid::queryInterface( const css::uno::Type& rType )
+{
+ Any aAny( ScAccessibleCsvGridImpl::queryInterface( rType ) );
+ return aAny.hasValue() ? aAny : ScAccessibleCsvControl::queryInterface( rType );
+}
+
+void SAL_CALL ScAccessibleCsvGrid::acquire() noexcept
+{
+ ScAccessibleCsvControl::acquire();
+}
+
+void SAL_CALL ScAccessibleCsvGrid::release() noexcept
+{
+ ScAccessibleCsvControl::release();
+}
+
+// XTypeProvider --------------------------------------------------------------
+
+Sequence< css::uno::Type > SAL_CALL ScAccessibleCsvGrid::getTypes()
+{
+ return ::comphelper::concatSequences( ScAccessibleCsvControl::getTypes(),
+ Sequence {
+ cppu::UnoType<XAccessibleTable>::get(),
+ cppu::UnoType<XAccessibleSelection>::get() });
+}
+
+Sequence< sal_Int8 > SAL_CALL ScAccessibleCsvGrid::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// events ---------------------------------------------------------------------
+
+void ScAccessibleCsvGrid::SendFocusEvent( bool bFocused )
+{
+ ScAccessibleCsvControl::SendFocusEvent( bFocused );
+ Any aOldAny, aNewAny;
+ (bFocused ? aNewAny : aOldAny) <<=
+ getAccessibleCellAt( 0, lcl_GetApiColumn( implGetGrid().GetFocusColumn() ) );
+ NotifyAccessibleEvent(AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, aOldAny, aNewAny);
+}
+
+void ScAccessibleCsvGrid::SendTableUpdateEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn, bool bAllRows )
+{
+ if( nFirstColumn <= nLastColumn )
+ {
+ AccessibleTableModelChange aModelChange(
+ AccessibleTableModelChangeType::UPDATE, 0, bAllRows ? implGetRowCount() - 1 : 0,
+ lcl_GetApiColumn( nFirstColumn ), lcl_GetApiColumn( nLastColumn ) );
+ Any aOldAny, aNewAny;
+ aNewAny <<= aModelChange;
+ NotifyAccessibleEvent(AccessibleEventId::TABLE_MODEL_CHANGED, aOldAny, aNewAny);
+ }
+}
+
+void ScAccessibleCsvGrid::SendInsertColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn )
+{
+ if( nFirstColumn <= nLastColumn )
+ {
+ AccessibleTableModelChange aModelChange(
+ AccessibleTableModelChangeType::COLUMNS_INSERTED, -1, -1,
+ lcl_GetApiColumn( nFirstColumn ), lcl_GetApiColumn( nLastColumn ) );
+ Any aOldAny, aNewAny;
+ aNewAny <<= aModelChange;
+ NotifyAccessibleEvent(AccessibleEventId::TABLE_MODEL_CHANGED, aOldAny, aNewAny);
+ }
+}
+
+void ScAccessibleCsvGrid::SendRemoveColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn )
+{
+ if( nFirstColumn <= nLastColumn )
+ {
+ AccessibleTableModelChange aModelChange(
+ AccessibleTableModelChangeType::COLUMNS_REMOVED, -1, -1,
+ lcl_GetApiColumn( nFirstColumn ), lcl_GetApiColumn( nLastColumn ) );
+ Any aOldAny, aNewAny;
+ aNewAny <<= aModelChange;
+ NotifyAccessibleEvent(AccessibleEventId::TABLE_MODEL_CHANGED, aOldAny, aNewAny);
+ }
+}
+
+// helpers --------------------------------------------------------------------
+
+OUString SAL_CALL ScAccessibleCsvGrid::getAccessibleName()
+{
+ return ScResId( STR_ACC_CSVGRID_NAME );
+}
+
+OUString SAL_CALL ScAccessibleCsvGrid::getAccessibleDescription()
+{
+ return ScResId( STR_ACC_CSVGRID_DESCR );
+}
+
+void ScAccessibleCsvGrid::ensureValidIndex( sal_Int32 nIndex ) const
+{
+ if( (nIndex < 0) || (nIndex >= implGetCellCount()) )
+ throw IndexOutOfBoundsException();
+}
+
+void ScAccessibleCsvGrid::ensureValidPosition( sal_Int32 nRow, sal_Int32 nColumn ) const
+{
+ if( (nRow < 0) || (nRow >= implGetRowCount()) || (nColumn < 0) || (nColumn >= implGetColumnCount()) )
+ throw IndexOutOfBoundsException();
+}
+
+ScCsvGrid& ScAccessibleCsvGrid::implGetGrid() const
+{
+ return static_cast< ScCsvGrid& >( implGetControl() );
+}
+
+bool ScAccessibleCsvGrid::implIsColumnSelected( sal_Int32 nColumn ) const
+{
+ return (nColumn > 0) && implGetGrid().IsSelected( lcl_GetGridColumn( nColumn ) );
+}
+
+void ScAccessibleCsvGrid::implSelectColumn( sal_Int32 nColumn, bool bSelect )
+{
+ if( nColumn > 0 )
+ implGetGrid().Select( lcl_GetGridColumn( nColumn ), bSelect );
+}
+
+sal_Int32 ScAccessibleCsvGrid::implGetRowCount() const
+{
+ return static_cast< sal_Int32 >( implGetGrid().GetLastVisLine() - implGetGrid().GetFirstVisLine() + 2 );
+}
+
+sal_Int32 ScAccessibleCsvGrid::implGetColumnCount() const
+{
+ return static_cast< sal_Int32 >( implGetGrid().GetColumnCount() + 1 );
+}
+
+sal_Int32 ScAccessibleCsvGrid::implGetSelColumnCount() const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ sal_Int32 nCount = 0;
+ for( sal_uInt32 nColIx = rGrid.GetFirstSelected(); nColIx != CSV_COLUMN_INVALID; nColIx = rGrid.GetNextSelected( nColIx ) )
+ ++nCount;
+ return nCount;
+}
+
+sal_Int32 ScAccessibleCsvGrid::implGetSelColumn( sal_Int32 nSelColumn ) const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ sal_Int32 nColumn = 0;
+ for( sal_uInt32 nColIx = rGrid.GetFirstSelected(); nColIx != CSV_COLUMN_INVALID; nColIx = rGrid.GetNextSelected( nColIx ) )
+ {
+ if( nColumn == nSelColumn )
+ return static_cast< sal_Int32 >( nColIx + 1 );
+ ++nColumn;
+ }
+ return 0;
+}
+
+OUString ScAccessibleCsvGrid::implGetCellText( sal_Int32 nRow, sal_Int32 nColumn ) const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ sal_Int32 nLine = nRow + rGrid.GetFirstVisLine() - 1;
+ OUString aCellStr;
+ if( (nColumn > 0) && (nRow > 0) )
+ aCellStr = rGrid.GetCellText( lcl_GetGridColumn( nColumn ), nLine );
+ else if( nRow > 0 )
+ aCellStr = OUString::number( nLine + 1 );
+ else if( nColumn > 0 )
+ aCellStr = rGrid.GetColumnTypeName( lcl_GetGridColumn( nColumn ) );
+ return aCellStr;
+}
+
+rtl::Reference<ScAccessibleCsvCell> ScAccessibleCsvGrid::implCreateCellObj( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ return new ScAccessibleCsvCell(implGetGrid(), implGetCellText(nRow, nColumn), nRow, nColumn);
+}
+
+css::uno::Reference<css::accessibility::XAccessible> SAL_CALL ScAccessibleCsvGrid::getAccessibleParent()
+{
+ return implGetControl().GetDrawingArea()->get_accessible_parent();
+}
+
+ScAccessibleCsvCell::ScAccessibleCsvCell(
+ ScCsvGrid& rGrid,
+ const OUString& rCellText,
+ sal_Int32 nRow, sal_Int32 nColumn ) :
+ ScAccessibleCsvControl( rGrid ),
+ AccessibleStaticTextBase( SvxEditSourcePtr() ),
+ maCellText( rCellText ),
+ mnLine( nRow ? (nRow + rGrid.GetFirstVisLine() - 1) : CSV_LINE_HEADER ),
+ mnColumn( lcl_GetGridColumn( nColumn ) ),
+ mnIndex( nRow * (rGrid.GetColumnCount() + 1) + nColumn )
+{
+ SetEditSource( implCreateEditSource() );
+}
+
+ScAccessibleCsvCell::~ScAccessibleCsvCell()
+{
+}
+
+void SAL_CALL ScAccessibleCsvCell::disposing()
+{
+ SolarMutexGuard aGuard;
+ SetEditSource( SvxEditSourcePtr() );
+ ScAccessibleCsvControl::disposing();
+}
+
+// XAccessibleComponent -------------------------------------------------------
+
+void SAL_CALL ScAccessibleCsvCell::grabFocus()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ ScCsvGrid& rGrid = implGetGrid();
+ rGrid.Execute( CSVCMD_MOVEGRIDCURSOR, rGrid.GetColumnPos( mnColumn ) );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvCell::getForeground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(Application::GetSettings().GetStyleSettings().GetButtonTextColor());
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvCell::getBackground( )
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return sal_Int32(SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor);
+}
+
+// XAccessibleContext -----------------------------------------------------
+
+sal_Int32 SAL_CALL ScAccessibleCsvCell::getAccessibleChildCount()
+{
+ return AccessibleStaticTextBase::getAccessibleChildCount();
+}
+
+Reference< XAccessible > SAL_CALL ScAccessibleCsvCell::getAccessibleChild( sal_Int32 nIndex )
+{
+ return AccessibleStaticTextBase::getAccessibleChild( nIndex );
+}
+
+sal_Int32 SAL_CALL ScAccessibleCsvCell::getAccessibleIndexInParent()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return mnIndex;
+}
+
+Reference< XAccessibleRelationSet > SAL_CALL ScAccessibleCsvCell::getAccessibleRelationSet()
+{
+ SolarMutexGuard aGuard;
+ ensureAlive();
+ return new AccessibleRelationSetHelper();
+}
+
+Reference< XAccessibleStateSet > SAL_CALL ScAccessibleCsvCell::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<AccessibleStateSetHelper> pStateSet = implCreateStateSet();
+ if( isAlive() )
+ {
+ const ScCsvGrid& rGrid = implGetGrid();
+ pStateSet->AddState( AccessibleStateType::SINGLE_LINE );
+ if( mnColumn != CSV_COLUMN_HEADER )
+ pStateSet->AddState( AccessibleStateType::SELECTABLE );
+ if( rGrid.HasFocus() && (rGrid.GetFocusColumn() == mnColumn) && (mnLine == CSV_LINE_HEADER) )
+ pStateSet->AddState( AccessibleStateType::ACTIVE );
+ if( rGrid.IsSelected( mnColumn ) )
+ pStateSet->AddState( AccessibleStateType::SELECTED );
+ }
+ return pStateSet;
+}
+
+// XInterface -----------------------------------------------------------------
+
+IMPLEMENT_FORWARD_XINTERFACE2( ScAccessibleCsvCell, ScAccessibleCsvControl, AccessibleStaticTextBase )
+
+// XTypeProvider --------------------------------------------------------------
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( ScAccessibleCsvCell, ScAccessibleCsvControl, AccessibleStaticTextBase )
+
+// helpers --------------------------------------------------------------------
+
+OUString SAL_CALL ScAccessibleCsvCell::getAccessibleName()
+{
+ return maCellText;
+}
+
+OUString SAL_CALL ScAccessibleCsvCell::getAccessibleDescription()
+{
+ return OUString();
+}
+
+ScCsvGrid& ScAccessibleCsvCell::implGetGrid() const
+{
+ return static_cast< ScCsvGrid& >( implGetControl() );
+}
+
+Point ScAccessibleCsvCell::implGetRealPos() const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ return Point(
+ (mnColumn == CSV_COLUMN_HEADER) ? rGrid.GetHdrX() : rGrid.GetColumnX( mnColumn ),
+ (mnLine == CSV_LINE_HEADER) ? 0 : rGrid.GetY( mnLine ) );
+}
+
+sal_uInt32 ScAccessibleCsvCell::implCalcPixelWidth(sal_uInt32 nChars) const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ return rGrid.GetCharWidth() * nChars;
+}
+
+Size ScAccessibleCsvCell::implGetRealSize() const
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ return Size(
+ (mnColumn == CSV_COLUMN_HEADER) ? rGrid.GetHdrWidth() : implCalcPixelWidth( rGrid.GetColumnWidth( mnColumn ) ),
+ (mnLine == CSV_LINE_HEADER) ? rGrid.GetHdrHeight() : rGrid.GetLineHeight() );
+}
+
+css::awt::Rectangle ScAccessibleCsvCell::implGetBounds()
+{
+ ScCsvGrid& rGrid = implGetGrid();
+ tools::Rectangle aClipRect( Point( 0, 0 ), rGrid.GetOutputSizePixel() );
+ if( mnColumn != CSV_COLUMN_HEADER )
+ {
+ aClipRect.SetLeft( rGrid.GetFirstX() );
+ aClipRect.SetRight( rGrid.GetLastX() );
+ }
+ if( mnLine != CSV_LINE_HEADER )
+ aClipRect.SetTop( rGrid.GetHdrHeight() );
+
+ tools::Rectangle aRect( implGetRealPos(), implGetRealSize() );
+ aRect.Intersection( aClipRect );
+ if( aRect.IsEmpty() )
+ aRect.SetSize( Size( -1, -1 ) );
+
+ return css::awt::Rectangle(aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight());
+}
+
+::std::unique_ptr< SvxEditSource > ScAccessibleCsvCell::implCreateEditSource()
+{
+ ScCsvGrid& rGrid = implGetGrid();
+
+ ::std::unique_ptr< SvxEditSource > pEditSource( new ScAccessibilityEditSource( std::make_unique<ScAccessibleCsvTextData>(&rGrid.GetDrawingArea()->get_ref_device(), rGrid.GetEditEngine(), maCellText, implGetRealSize()) ) );
+ return pEditSource;
+}
+
+css::uno::Reference<css::accessibility::XAccessible> SAL_CALL ScAccessibleCsvCell::getAccessibleParent()
+{
+ ScCsvGrid& rGrid = implGetGrid();
+
+ ScAccessibleCsvGrid* pAcc = static_cast<ScAccessibleCsvGrid*>(rGrid.GetAccessible());
+
+ return pAcc;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessibleDocument.cxx b/sc/source/ui/Accessibility/AccessibleDocument.cxx
new file mode 100644
index 000000000..52b5a6c53
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleDocument.cxx
@@ -0,0 +1,2224 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleDocument.hxx>
+#include <AccessibleSpreadsheet.hxx>
+#include <tabvwsh.hxx>
+#include <AccessibilityHints.hxx>
+#include <document.hxx>
+#include <drwlayer.hxx>
+#include <DrawModelBroadcaster.hxx>
+#include <drawview.hxx>
+#include <gridwin.hxx>
+#include <AccessibleEditObject.hxx>
+#include <userdat.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <markdata.hxx>
+
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/drawing/ShapeCollection.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <o3tl/safeint.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <tools/gen.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/ShapeTypeHandler.hxx>
+#include <svx/AccessibleShape.hxx>
+#include <svx/AccessibleShapeTreeInfo.hxx>
+#include <svx/AccessibleShapeInfo.hxx>
+#include <svx/IAccessibleParent.hxx>
+#include <comphelper/sequence.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/docfile.hxx>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <vcl/svapp.hxx>
+
+#include <svx/AccessibleControlShape.hxx>
+#include <svx/SvxShapeTypes.hxx>
+#include <sfx2/objsh.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editeng.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <algorithm>
+
+#include <scmod.hxx>
+
+#ifdef indices
+#undef indices
+#endif
+
+#ifdef extents
+#undef extents
+#endif
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+ //===== internal ========================================================
+
+namespace {
+
+struct ScAccessibleShapeData
+{
+ ScAccessibleShapeData(css::uno::Reference< css::drawing::XShape > xShape_);
+ ~ScAccessibleShapeData();
+ mutable rtl::Reference< ::accessibility::AccessibleShape > pAccShape;
+ mutable std::optional<ScAddress> xRelationCell; // if it is NULL this shape is anchored on the table
+ css::uno::Reference< css::drawing::XShape > xShape;
+ mutable bool bSelected;
+ bool bSelectable;
+ // cache these to make the sorting cheaper
+ std::optional<sal_Int16> mxLayerID;
+ std::optional<sal_Int32> mxZOrder;
+};
+
+}
+
+ScAccessibleShapeData::ScAccessibleShapeData(css::uno::Reference< css::drawing::XShape > xShape_)
+ : xShape(xShape_),
+ bSelected(false), bSelectable(true)
+{
+ static constexpr OUStringLiteral gsLayerId = u"LayerID";
+ static constexpr OUStringLiteral gsZOrder = u"ZOrder";
+ uno::Reference< beans::XPropertySet> xProps(xShape, uno::UNO_QUERY);
+ if (xProps.is())
+ {
+ uno::Any aAny = xProps->getPropertyValue(gsLayerId);
+ sal_Int16 nLayerID;
+ if (aAny >>= nLayerID)
+ mxLayerID = nLayerID;
+ sal_Int32 nZOrder;
+ aAny = xProps->getPropertyValue(gsZOrder);
+ if (aAny >>= nZOrder)
+ mxZOrder = nZOrder;
+ }
+}
+
+ScAccessibleShapeData::~ScAccessibleShapeData()
+{
+ if (pAccShape.is())
+ {
+ pAccShape->dispose();
+ }
+}
+
+namespace {
+
+struct ScShapeDataLess
+{
+ static void ConvertLayerId(sal_Int16& rLayerID) // changes the number of the LayerId so it the accessibility order
+ {
+ // note: MSVC 2017 ICE's if this is written as "switch" so use "if"
+ if (SC_LAYER_FRONT.get() == rLayerID)
+ {
+ rLayerID = 1;
+ }
+ else if (SC_LAYER_BACK.get() == rLayerID)
+ {
+ rLayerID = 0;
+ }
+ else if (SC_LAYER_INTERN.get() == rLayerID)
+ {
+ rLayerID = 2;
+ }
+ else if (SC_LAYER_CONTROLS.get() == rLayerID)
+ {
+ rLayerID = 3;
+ }
+ }
+ static bool LessThanSheet(const ScAccessibleShapeData* pData)
+ {
+ bool bResult(false);
+ if (pData->mxLayerID)
+ {
+ if (SdrLayerID(*pData->mxLayerID) == SC_LAYER_BACK)
+ bResult = true;
+ }
+ return bResult;
+ }
+ bool operator()(const ScAccessibleShapeData* pData1, const ScAccessibleShapeData* pData2) const
+ {
+ bool bResult(false);
+ if (pData1 && pData2)
+ {
+ if( pData1->mxLayerID && pData2->mxLayerID )
+ {
+ sal_Int16 nLayerID1 = *pData1->mxLayerID;
+ sal_Int16 nLayerID2 = *pData2->mxLayerID;
+ if (nLayerID1 == nLayerID2)
+ {
+ if ( pData1->mxZOrder && pData2->mxZOrder )
+ bResult = (*pData1->mxZOrder < *pData2->mxZOrder);
+ }
+ else
+ {
+ ConvertLayerId(nLayerID1);
+ ConvertLayerId(nLayerID2);
+ bResult = (nLayerID1 < nLayerID2);
+ }
+ }
+ }
+ else if (pData1 && !pData2)
+ bResult = LessThanSheet(pData1);
+ else if (!pData1 && pData2)
+ bResult = !LessThanSheet(pData2);
+ else
+ bResult = false;
+ return bResult;
+ }
+};
+
+}
+
+class ScChildrenShapes : public SfxListener,
+ public ::accessibility::IAccessibleParent
+{
+public:
+ ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos);
+ virtual ~ScChildrenShapes() override;
+
+ ///===== SfxListener =====================================================
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ ///===== IAccessibleParent ===============================================
+
+ virtual bool ReplaceChild (
+ ::accessibility::AccessibleShape* pCurrentChild,
+ const css::uno::Reference< css::drawing::XShape >& _rxShape,
+ const tools::Long _nIndex,
+ const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo
+ ) override;
+
+ virtual ::accessibility::AccessibleControlShape* GetAccControlShapeFromModel
+ (css::beans::XPropertySet* pSet) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible>
+ GetAccessibleCaption (const css::uno::Reference<css::drawing::XShape>& xShape) override;
+ ///===== Internal ========================================================
+ void SetDrawBroadcaster();
+
+ sal_Int32 GetCount() const;
+ uno::Reference< XAccessible > Get(const ScAccessibleShapeData* pData) const;
+ uno::Reference< XAccessible > Get(sal_Int32 nIndex) const;
+ uno::Reference< XAccessible > GetAt(const awt::Point& rPoint) const;
+
+ // gets the index of the shape starting on 0 (without the index of the table)
+ // returns the selected shape
+ bool IsSelected(sal_Int32 nIndex,
+ css::uno::Reference<css::drawing::XShape>& rShape) const;
+
+ bool SelectionChanged();
+
+ void Select(sal_Int32 nIndex);
+ void DeselectAll(); // deselect also the table
+ void SelectAll();
+ sal_Int32 GetSelectedCount() const;
+ uno::Reference< XAccessible > GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const;
+ void Deselect(sal_Int32 nChildIndex);
+
+ SdrPage* GetDrawPage() const;
+
+ rtl::Reference<utl::AccessibleRelationSetHelper> GetRelationSet(const ScAddress* pAddress) const;
+
+ void VisAreaChanged() const;
+private:
+ typedef std::vector<ScAccessibleShapeData*> SortedShapes;
+ typedef std::unordered_map<css::uno::Reference< css::drawing::XShape >, ScAccessibleShapeData*> ShapesMap;
+
+ mutable SortedShapes maZOrderedShapes; // a null pointer represents the sheet in the correct order
+ mutable ShapesMap maShapesMap;
+ mutable bool mbShapesNeedSorting; // set if maZOrderedShapes needs sorting
+
+ mutable ::accessibility::AccessibleShapeTreeInfo maShapeTreeInfo;
+ mutable css::uno::Reference<css::view::XSelectionSupplier> xSelectionSupplier;
+ mutable sal_uInt32 mnShapesSelected;
+ ScTabViewShell* mpViewShell;
+ ScAccessibleDocument* mpAccessibleDocument;
+ ScSplitPos meSplitPos;
+
+ void FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const;
+ bool FindSelectedShapesChanges(const css::uno::Reference<css::drawing::XShapes>& xShapes) const;
+
+ std::optional<ScAddress> GetAnchor(const uno::Reference<drawing::XShape>& xShape) const;
+ uno::Reference<XAccessibleRelationSet> GetRelationSet(const ScAccessibleShapeData* pData) const;
+ void SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const;
+ void AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const;
+ void RemoveShape(const uno::Reference<drawing::XShape>& xShape) const;
+
+ bool FindShape(const uno::Reference<drawing::XShape>& xShape, SortedShapes::iterator& rItr) const;
+
+ static sal_Int8 Compare(const ScAccessibleShapeData* pData1,
+ const ScAccessibleShapeData* pData2);
+};
+
+ScChildrenShapes::ScChildrenShapes(ScAccessibleDocument* pAccessibleDocument, ScTabViewShell* pViewShell, ScSplitPos eSplitPos)
+ :
+ mbShapesNeedSorting(false),
+ mnShapesSelected(0),
+ mpViewShell(pViewShell),
+ mpAccessibleDocument(pAccessibleDocument),
+ meSplitPos(eSplitPos)
+{
+ if (mpViewShell)
+ {
+ SfxViewFrame* pViewFrame = mpViewShell->GetViewFrame();
+ if (pViewFrame)
+ {
+ xSelectionSupplier = uno::Reference<view::XSelectionSupplier>(pViewFrame->GetFrame().GetController(), uno::UNO_QUERY);
+ if (xSelectionSupplier.is())
+ {
+ xSelectionSupplier->addSelectionChangeListener(mpAccessibleDocument);
+ uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
+ if (xShapes.is())
+ mnShapesSelected = xShapes->getCount();
+ }
+ }
+ }
+
+ maZOrderedShapes.push_back(nullptr); // add an element which represents the table
+
+ GetCount(); // fill list with filtered shapes (no internal shapes)
+
+ if (mnShapesSelected)
+ {
+ //set flag on every selected shape
+ if (!xSelectionSupplier.is())
+ throw uno::RuntimeException();
+
+ uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
+ if (xShapes.is())
+ FindSelectedShapesChanges(xShapes);
+ }
+ if (!pViewShell)
+ return;
+
+ ScViewData& rViewData = pViewShell->GetViewData();
+ SfxBroadcaster* pDrawBC = rViewData.GetDocument().GetDrawBroadcaster();
+ if (pDrawBC)
+ {
+ StartListening(*pDrawBC);
+
+ maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument().GetDrawLayer()) );
+ maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView());
+ maShapeTreeInfo.SetController(nullptr);
+ maShapeTreeInfo.SetWindow(pViewShell->GetWindowByPos(meSplitPos));
+ maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument);
+ }
+}
+
+ScChildrenShapes::~ScChildrenShapes()
+{
+ for (ScAccessibleShapeData* pShapeData : maZOrderedShapes)
+ delete pShapeData;
+ if (mpViewShell)
+ {
+ SfxBroadcaster* pDrawBC = mpViewShell->GetViewData().GetDocument().GetDrawBroadcaster();
+ if (pDrawBC)
+ EndListening(*pDrawBC);
+ }
+ if (mpAccessibleDocument && xSelectionSupplier.is())
+ xSelectionSupplier->removeSelectionChangeListener(mpAccessibleDocument);
+}
+
+void ScChildrenShapes::SetDrawBroadcaster()
+{
+ if (!mpViewShell)
+ return;
+
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ SfxBroadcaster* pDrawBC = rViewData.GetDocument().GetDrawBroadcaster();
+ if (pDrawBC)
+ {
+ StartListening(*pDrawBC, DuplicateHandling::Prevent);
+
+ maShapeTreeInfo.SetModelBroadcaster( new ScDrawModelBroadcaster(rViewData.GetDocument().GetDrawLayer()) );
+ maShapeTreeInfo.SetSdrView(rViewData.GetScDrawView());
+ maShapeTreeInfo.SetController(nullptr);
+ maShapeTreeInfo.SetWindow(mpViewShell->GetWindowByPos(meSplitPos));
+ maShapeTreeInfo.SetViewForwarder(mpAccessibleDocument);
+ }
+}
+
+void ScChildrenShapes::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+
+ SdrObject* pObj = const_cast<SdrObject*>(pSdrHint->GetObject());
+ if (!(pObj && /*(pObj->GetLayer() != SC_LAYER_INTERN) && */(pObj->getSdrPageFromSdrObject() == GetDrawPage()) &&
+ (pObj->getSdrPageFromSdrObject() == pObj->getParentSdrObjListFromSdrObject())) ) //only do something if the object lies direct on the page
+ return;
+
+ switch (pSdrHint->GetKind())
+ {
+ case SdrHintKind::ObjectChange : // object changed
+ {
+ uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
+ if (xShape.is())
+ {
+ mbShapesNeedSorting = true; // sort, because the z index or layer could be changed
+ auto it = maShapesMap.find(xShape);
+ if (it != maShapesMap.end())
+ SetAnchor(xShape, it->second);
+ }
+ }
+ break;
+ case SdrHintKind::ObjectInserted : // new drawing object inserted
+ {
+ uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
+ if (xShape.is())
+ AddShape(xShape, true);
+ }
+ break;
+ case SdrHintKind::ObjectRemoved : // Removed drawing object from list
+ {
+ uno::Reference<drawing::XShape> xShape (pObj->getUnoShape(), uno::UNO_QUERY);
+ if (xShape.is())
+ RemoveShape(xShape);
+ }
+ break;
+ default :
+ {
+ // other events are not interesting
+ }
+ break;
+ }
+}
+
+bool ScChildrenShapes::ReplaceChild (::accessibility::AccessibleShape* pCurrentChild,
+ const css::uno::Reference< css::drawing::XShape >& _rxShape,
+ const tools::Long /*_nIndex*/, const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo)
+{
+ // create the new child
+ rtl::Reference< ::accessibility::AccessibleShape > pReplacement(::accessibility::ShapeTypeHandler::Instance().CreateAccessibleObject (
+ ::accessibility::AccessibleShapeInfo ( _rxShape, pCurrentChild->getAccessibleParent(), this ),
+ _rShapeTreeInfo
+ ));
+
+ bool bResult(false);
+ if (pReplacement.is())
+ {
+ OSL_ENSURE(pCurrentChild->GetXShape().get() == pReplacement->GetXShape().get(), "XShape changes and should be inserted sorted");
+ auto it = maShapesMap.find(pCurrentChild->GetXShape());
+ if (it != maShapesMap.end() && it->second->pAccShape.is())
+ {
+ OSL_ENSURE(it->second->pAccShape == pCurrentChild, "wrong child found");
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
+ aEvent.OldValue <<= uno::Reference<XAccessible>(pCurrentChild);
+
+ mpAccessibleDocument->CommitChange(aEvent); // child is gone - event
+
+ pCurrentChild->dispose();
+ }
+
+ // Init after above possible pCurrentChild->dispose so we don't trigger the assert
+ // ScDrawModelBroadcaster::addShapeEventListener of duplicate listeners
+ pReplacement->Init();
+
+ if (it != maShapesMap.end())
+ {
+ it->second->pAccShape = pReplacement;
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
+ aEvent.NewValue <<= uno::Reference<XAccessible>(pReplacement);
+
+ mpAccessibleDocument->CommitChange(aEvent); // child is new - event
+ bResult = true;
+ }
+ }
+ return bResult;
+}
+
+::accessibility::AccessibleControlShape * ScChildrenShapes::GetAccControlShapeFromModel(css::beans::XPropertySet* pSet)
+{
+ GetCount(); // populate
+ for (ScAccessibleShapeData* pShape : maZOrderedShapes)
+ {
+ if (pShape)
+ {
+ rtl::Reference< ::accessibility::AccessibleShape > pAccShape(pShape->pAccShape);
+ if (pAccShape.is() && ::accessibility::ShapeTypeHandler::Instance().GetTypeId (pAccShape->GetXShape()) == ::accessibility::DRAWING_CONTROL)
+ {
+ ::accessibility::AccessibleControlShape *pCtlAccShape = static_cast < ::accessibility::AccessibleControlShape* >(pAccShape.get());
+ if (pCtlAccShape && pCtlAccShape->GetControlModel() == pSet)
+ return pCtlAccShape;
+ }
+ }
+ }
+ return nullptr;
+}
+
+css::uno::Reference < css::accessibility::XAccessible >
+ScChildrenShapes::GetAccessibleCaption (const css::uno::Reference < css::drawing::XShape>& xShape)
+{
+ GetCount(); // populate
+ auto it = maShapesMap.find(xShape);
+ if (it == maShapesMap.end())
+ return nullptr;
+ ScAccessibleShapeData* pShape = it->second;
+ css::uno::Reference< css::accessibility::XAccessible > xNewChild( pShape->pAccShape );
+ if(xNewChild)
+ return xNewChild;
+ return nullptr;
+}
+
+sal_Int32 ScChildrenShapes::GetCount() const
+{
+ SdrPage* pDrawPage = GetDrawPage();
+ if (pDrawPage && (maZOrderedShapes.size() == 1)) // the table is always in
+ {
+ size_t nSdrObjCount = pDrawPage->GetObjCount();
+ maZOrderedShapes.reserve(nSdrObjCount + 1); // the table is always in
+ for (size_t i = 0; i < nSdrObjCount; ++i)
+ {
+ SdrObject* pObj = pDrawPage->GetObj(i);
+ if (pObj/* && (pObj->GetLayer() != SC_LAYER_INTERN)*/)
+ {
+ uno::Reference< drawing::XShape > xShape (pObj->getUnoShape(), uno::UNO_QUERY);
+ AddShape(xShape, false); //inserts in the correct order
+ }
+ }
+ }
+ return maZOrderedShapes.size();
+}
+
+uno::Reference< XAccessible > ScChildrenShapes::Get(const ScAccessibleShapeData* pData) const
+{
+ if (!pData)
+ return nullptr;
+
+ if (!pData->pAccShape.is())
+ {
+ ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance();
+ ::accessibility::AccessibleShapeInfo aShapeInfo(pData->xShape, mpAccessibleDocument, const_cast<ScChildrenShapes*>(this));
+ pData->pAccShape = rShapeHandler.CreateAccessibleObject(
+ aShapeInfo, maShapeTreeInfo);
+ if (pData->pAccShape.is())
+ {
+ pData->pAccShape->Init();
+ if (pData->bSelected)
+ pData->pAccShape->SetState(AccessibleStateType::SELECTED);
+ if (!pData->bSelectable)
+ pData->pAccShape->ResetState(AccessibleStateType::SELECTABLE);
+ pData->pAccShape->SetRelationSet(GetRelationSet(pData));
+ }
+ }
+ return pData->pAccShape;
+ }
+
+uno::Reference< XAccessible > ScChildrenShapes::Get(sal_Int32 nIndex) const
+{
+ if (maZOrderedShapes.size() <= 1)
+ GetCount(); // fill list with filtered shapes (no internal shapes)
+
+ if (mbShapesNeedSorting)
+ {
+ std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
+ mbShapesNeedSorting = false;
+ }
+
+ if (o3tl::make_unsigned(nIndex) >= maZOrderedShapes.size())
+ return nullptr;
+
+ return Get(maZOrderedShapes[nIndex]);
+}
+
+uno::Reference< XAccessible > ScChildrenShapes::GetAt(const awt::Point& rPoint) const
+{
+ uno::Reference<XAccessible> xAccessible;
+ if(mpViewShell)
+ {
+ if (mbShapesNeedSorting)
+ {
+ std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
+ mbShapesNeedSorting = false;
+ }
+
+ sal_Int32 i(maZOrderedShapes.size() - 1);
+ bool bFound(false);
+ while (!bFound && i >= 0)
+ {
+ ScAccessibleShapeData* pShape = maZOrderedShapes[i];
+ if (pShape)
+ {
+ if (!pShape->pAccShape.is())
+ Get(pShape);
+
+ if (pShape->pAccShape.is())
+ {
+ Point aPoint(VCLPoint(rPoint));
+ aPoint -= VCLRectangle(pShape->pAccShape->getBounds()).TopLeft();
+ if (pShape->pAccShape->containsPoint(AWTPoint(aPoint)))
+ {
+ xAccessible = pShape->pAccShape.get();
+ bFound = true;
+ }
+ }
+ else
+ {
+ OSL_FAIL("I should have an accessible shape now!");
+ }
+ }
+ else
+ bFound = true; // this is the sheet and it lies before the rest of the shapes which are background shapes
+
+ --i;
+ }
+ }
+ return xAccessible;
+}
+
+bool ScChildrenShapes::IsSelected(sal_Int32 nIndex,
+ uno::Reference<drawing::XShape>& rShape) const
+{
+ bool bResult (false);
+ if (maZOrderedShapes.size() <= 1)
+ GetCount(); // fill list with filtered shapes (no internal shapes)
+
+ if (!xSelectionSupplier.is())
+ throw uno::RuntimeException();
+
+ if (mbShapesNeedSorting)
+ {
+ std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
+ mbShapesNeedSorting = false;
+ }
+
+ if (!maZOrderedShapes[nIndex])
+ return false;
+
+ bResult = maZOrderedShapes[nIndex]->bSelected;
+ rShape = maZOrderedShapes[nIndex]->xShape;
+
+#if OSL_DEBUG_LEVEL > 0 // test whether it is truly selected by a slower method
+ uno::Reference< drawing::XShape > xReturnShape;
+ bool bDebugResult(false);
+ uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
+
+ if (xShapes.is())
+ {
+ sal_Int32 nCount(xShapes->getCount());
+ if (nCount)
+ {
+ uno::Reference< drawing::XShape > xShape;
+ uno::Reference< drawing::XShape > xIndexShape = maZOrderedShapes[nIndex]->xShape;
+ sal_Int32 i(0);
+ while (!bDebugResult && (i < nCount))
+ {
+ xShapes->getByIndex(i) >>= xShape;
+ if (xShape.is() && (xIndexShape.get() == xShape.get()))
+ {
+ bDebugResult = true;
+ xReturnShape = xShape;
+ }
+ else
+ ++i;
+ }
+ }
+ }
+ OSL_ENSURE((bResult == bDebugResult) && ((bResult && (rShape.get() == xReturnShape.get())) || !bResult), "found the wrong shape or result");
+#endif
+
+ return bResult;
+}
+
+bool ScChildrenShapes::SelectionChanged()
+{
+ bool bResult(false);
+ if (!xSelectionSupplier.is())
+ throw uno::RuntimeException();
+
+ uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
+
+ bResult = FindSelectedShapesChanges(xShapes);
+
+ return bResult;
+}
+
+void ScChildrenShapes::Select(sal_Int32 nIndex)
+{
+ if (maZOrderedShapes.size() <= 1)
+ GetCount(); // fill list with filtered shapes (no internal shapes)
+
+ if (!xSelectionSupplier.is())
+ throw uno::RuntimeException();
+
+ if (mbShapesNeedSorting)
+ {
+ std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
+ mbShapesNeedSorting = false;
+ }
+
+ if (!maZOrderedShapes[nIndex])
+ return;
+
+ uno::Reference<drawing::XShape> xShape;
+ if (IsSelected(nIndex, xShape) || !maZOrderedShapes[nIndex]->bSelectable)
+ return;
+
+ uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
+
+ if (!xShapes.is())
+ xShapes = drawing::ShapeCollection::create(
+ comphelper::getProcessComponentContext());
+
+ xShapes->add(maZOrderedShapes[nIndex]->xShape);
+
+ try
+ {
+ xSelectionSupplier->select(uno::Any(xShapes));
+ maZOrderedShapes[nIndex]->bSelected = true;
+ if (maZOrderedShapes[nIndex]->pAccShape.is())
+ maZOrderedShapes[nIndex]->pAccShape->SetState(AccessibleStateType::SELECTED);
+ }
+ catch (lang::IllegalArgumentException&)
+ {
+ }
+}
+
+void ScChildrenShapes::DeselectAll()
+{
+ if (!xSelectionSupplier.is())
+ throw uno::RuntimeException();
+
+ bool bSomethingSelected(true);
+ try
+ {
+ xSelectionSupplier->select(uno::Any()); //deselects all
+ }
+ catch (lang::IllegalArgumentException&)
+ {
+ OSL_FAIL("nothing selected before");
+ bSomethingSelected = false;
+ }
+
+ if (bSomethingSelected)
+ for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
+ if (pAccShapeData)
+ {
+ pAccShapeData->bSelected = false;
+ if (pAccShapeData->pAccShape.is())
+ pAccShapeData->pAccShape->ResetState(AccessibleStateType::SELECTED);
+ }
+};
+
+
+void ScChildrenShapes::SelectAll()
+{
+ if (!xSelectionSupplier.is())
+ throw uno::RuntimeException();
+
+ if (maZOrderedShapes.size() <= 1)
+ GetCount(); // fill list with filtered shapes (no internal shapes)
+
+ if (maZOrderedShapes.size() <= 1)
+ return;
+
+ uno::Reference<drawing::XShapes> xShapes = drawing::ShapeCollection::create(
+ comphelper::getProcessComponentContext());
+
+ try
+ {
+ for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
+ {
+ if (pAccShapeData && pAccShapeData->bSelectable)
+ {
+ pAccShapeData->bSelected = true;
+ if (pAccShapeData->pAccShape.is())
+ pAccShapeData->pAccShape->SetState(AccessibleStateType::SELECTED);
+ if (xShapes.is())
+ xShapes->add(pAccShapeData->xShape);
+ }
+ }
+ xSelectionSupplier->select(uno::Any(xShapes));
+ }
+ catch (lang::IllegalArgumentException&)
+ {
+ SelectionChanged(); // find all selected shapes and set the flags
+ }
+}
+
+void ScChildrenShapes::FillShapes(std::vector < uno::Reference < drawing::XShape > >& rShapes) const
+{
+ uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
+ if (xShapes.is())
+ {
+ sal_uInt32 nCount(xShapes->getCount());
+ for (sal_uInt32 i = 0; i < nCount; ++i)
+ {
+ uno::Reference<drawing::XShape> xShape;
+ xShapes->getByIndex(i) >>= xShape;
+ if (xShape.is())
+ rShapes.push_back(xShape);
+ }
+ }
+}
+
+sal_Int32 ScChildrenShapes::GetSelectedCount() const
+{
+ if (!xSelectionSupplier.is())
+ throw uno::RuntimeException();
+
+ std::vector < uno::Reference < drawing::XShape > > aShapes;
+ FillShapes(aShapes);
+
+ return aShapes.size();
+}
+
+uno::Reference< XAccessible > ScChildrenShapes::GetSelected(sal_Int32 nSelectedChildIndex, bool bTabSelected) const
+{
+ uno::Reference< XAccessible > xAccessible;
+
+ if (maZOrderedShapes.size() <= 1)
+ GetCount(); // fill list with shapes
+
+ if (!bTabSelected)
+ {
+ std::vector < uno::Reference < drawing::XShape > > aShapes;
+ FillShapes(aShapes);
+
+ if (nSelectedChildIndex < 0 || o3tl::make_unsigned(nSelectedChildIndex) >= aShapes.size())
+ return xAccessible;
+
+ SortedShapes::iterator aItr;
+ if (FindShape(aShapes[nSelectedChildIndex], aItr))
+ xAccessible = Get(*aItr);
+ }
+ else
+ {
+ if (mbShapesNeedSorting)
+ {
+ std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
+ mbShapesNeedSorting = false;
+ }
+ for(const auto& rpShape : maZOrderedShapes)
+ {
+ if (!rpShape || rpShape->bSelected)
+ {
+ if (nSelectedChildIndex == 0)
+ {
+ if (rpShape)
+ xAccessible = rpShape->pAccShape.get();
+ break;
+ }
+ else
+ --nSelectedChildIndex;
+ }
+ }
+ }
+
+ return xAccessible;
+}
+
+void ScChildrenShapes::Deselect(sal_Int32 nChildIndex)
+{
+ uno::Reference<drawing::XShape> xShape;
+ if (!IsSelected(nChildIndex, xShape)) // returns false if it is the sheet
+ return;
+
+ if (!xShape.is())
+ return;
+
+ uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
+ if (xShapes.is())
+ xShapes->remove(xShape);
+
+ try
+ {
+ xSelectionSupplier->select(uno::Any(xShapes));
+ }
+ catch (lang::IllegalArgumentException&)
+ {
+ OSL_FAIL("something not selectable");
+ }
+
+ maZOrderedShapes[nChildIndex]->bSelected = false;
+ if (maZOrderedShapes[nChildIndex]->pAccShape.is())
+ maZOrderedShapes[nChildIndex]->pAccShape->ResetState(AccessibleStateType::SELECTED);
+}
+
+SdrPage* ScChildrenShapes::GetDrawPage() const
+{
+ SCTAB nTab(mpAccessibleDocument->getVisibleTable());
+ SdrPage* pDrawPage = nullptr;
+ if (mpViewShell)
+ {
+ ScDocument& rDoc = mpViewShell->GetViewData().GetDocument();
+ if (ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer())
+ {
+ if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab))
+ pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab)));
+ }
+ }
+ return pDrawPage;
+}
+
+rtl::Reference<utl::AccessibleRelationSetHelper> ScChildrenShapes::GetRelationSet(const ScAddress* pAddress) const
+{
+ rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSet;
+ for (const ScAccessibleShapeData* pAccShapeData : maZOrderedShapes)
+ {
+ if (pAccShapeData &&
+ ((!pAccShapeData->xRelationCell && !pAddress) ||
+ (pAccShapeData->xRelationCell && pAddress && (*(pAccShapeData->xRelationCell) == *pAddress))))
+ {
+ if (!pRelationSet)
+ pRelationSet = new utl::AccessibleRelationSetHelper();
+
+ AccessibleRelation aRelation;
+ aRelation.TargetSet = { Get(pAccShapeData) };
+ aRelation.RelationType = AccessibleRelationType::CONTROLLER_FOR;
+
+ pRelationSet->AddRelation(aRelation);
+ }
+ }
+ return pRelationSet;
+}
+
+bool ScChildrenShapes::FindSelectedShapesChanges(const uno::Reference<drawing::XShapes>& xShapes) const
+{
+ bool bResult(false);
+ SortedShapes aShapesList;
+ if (xShapes.is())
+ {
+ mnShapesSelected = xShapes->getCount();
+ for (sal_uInt32 i = 0; i < mnShapesSelected; ++i)
+ {
+ uno::Reference< drawing::XShape > xShape;
+ xShapes->getByIndex(i) >>= xShape;
+ if (xShape.is())
+ {
+ ScAccessibleShapeData* pShapeData = new ScAccessibleShapeData(xShape);
+ aShapesList.push_back(pShapeData);
+ }
+ }
+ }
+ else
+ mnShapesSelected = 0;
+ SdrObject *pFocusedObj = nullptr;
+ if( mnShapesSelected == 1 && aShapesList.size() == 1)
+ {
+ pFocusedObj = SdrObject::getSdrObjectFromXShape(aShapesList[0]->xShape);
+ }
+ std::sort(aShapesList.begin(), aShapesList.end(), ScShapeDataLess());
+ SortedShapes vecSelectedShapeAdd;
+ SortedShapes vecSelectedShapeRemove;
+ bool bHasSelect=false;
+ SortedShapes::iterator aXShapesItr(aShapesList.begin());
+ SortedShapes::const_iterator aXShapesEndItr(aShapesList.end());
+ SortedShapes::iterator aDataItr(maZOrderedShapes.begin());
+ SortedShapes::const_iterator aDataEndItr(maZOrderedShapes.end());
+ SortedShapes::const_iterator aFocusedItr = aDataEndItr;
+ while(aDataItr != aDataEndItr)
+ {
+ if (*aDataItr) // is it really a shape or only the sheet
+ {
+ sal_Int8 nComp(0);
+ if (aXShapesItr == aXShapesEndItr)
+ nComp = -1; // simulate that the Shape is lower, so the selection state will be removed
+ else
+ nComp = Compare(*aDataItr, *aXShapesItr);
+ if (nComp == 0)
+ {
+ if (!(*aDataItr)->bSelected)
+ {
+ (*aDataItr)->bSelected = true;
+ if ((*aDataItr)->pAccShape.is())
+ {
+ (*aDataItr)->pAccShape->SetState(AccessibleStateType::SELECTED);
+ (*aDataItr)->pAccShape->SetState(AccessibleStateType::FOCUSED);
+ bResult = true;
+ vecSelectedShapeAdd.push_back(*aDataItr);
+ }
+ aFocusedItr = aDataItr;
+ }
+ else
+ {
+ bHasSelect = true;
+ }
+ ++aDataItr;
+ ++aXShapesItr;
+ }
+ else if (nComp < 0)
+ {
+ if ((*aDataItr)->bSelected)
+ {
+ (*aDataItr)->bSelected = false;
+ if ((*aDataItr)->pAccShape.is())
+ {
+ (*aDataItr)->pAccShape->ResetState(AccessibleStateType::SELECTED);
+ (*aDataItr)->pAccShape->ResetState(AccessibleStateType::FOCUSED);
+ bResult = true;
+ vecSelectedShapeRemove.push_back(*aDataItr);
+ }
+ }
+ ++aDataItr;
+ }
+ else
+ {
+ OSL_FAIL("here is a selected shape which is not in the childlist");
+ ++aXShapesItr;
+ --mnShapesSelected;
+ }
+ }
+ else
+ ++aDataItr;
+ }
+ bool bWinFocus=false;
+ if (mpViewShell)
+ {
+ ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
+ if (pWin)
+ {
+ bWinFocus = pWin->HasFocus();
+ }
+ }
+ const SdrMarkList* pMarkList = nullptr;
+ SdrObject* pMarkedObj = nullptr;
+ bool bIsFocuseMarked = true;
+ if( mpViewShell && mnShapesSelected == 1 && bWinFocus)
+ {
+ ScDrawView* pScDrawView = mpViewShell->GetViewData().GetScDrawView();
+ if( pScDrawView )
+ {
+ if( pScDrawView->GetMarkedObjectList().GetMarkCount() == 1 )
+ {
+ pMarkList = &(pScDrawView->GetMarkedObjectList());
+ pMarkedObj = pMarkList->GetMark(0)->GetMarkedSdrObj();
+ uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY);
+ if( aFocusedItr != aDataEndItr &&
+ (*aFocusedItr)->xShape.is() &&
+ xMarkedXShape.is() &&
+ (*aFocusedItr)->xShape != xMarkedXShape )
+ bIsFocuseMarked = false;
+ }
+ }
+ }
+ //if ((aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1))
+ if ( bIsFocuseMarked && (aFocusedItr != aDataEndItr) && (*aFocusedItr)->pAccShape.is() && (mnShapesSelected == 1) && bWinFocus)
+ {
+ (*aFocusedItr)->pAccShape->SetState(AccessibleStateType::FOCUSED);
+ }
+ else if( pFocusedObj && bWinFocus && pMarkList && pMarkList->GetMarkCount() == 1 && mnShapesSelected == 1 )
+ {
+ if( pMarkedObj )
+ {
+ uno::Reference< drawing::XShape > xMarkedXShape (pMarkedObj->getUnoShape(), uno::UNO_QUERY);
+ SdrObject* pUpObj = pMarkedObj->getParentSdrObjectFromSdrObject();
+
+ if( pMarkedObj == pFocusedObj && pUpObj )
+ {
+ uno::Reference< drawing::XShape > xUpGroupXShape (pUpObj->getUnoShape(), uno::UNO_QUERY);
+ uno::Reference < XAccessible > xAccGroupShape =
+ const_cast<ScChildrenShapes*>(this)->GetAccessibleCaption( xUpGroupXShape );
+ if( xAccGroupShape.is() )
+ {
+ ::accessibility::AccessibleShape* pAccGroupShape =
+ static_cast< ::accessibility::AccessibleShape* >(xAccGroupShape.get());
+ if( pAccGroupShape )
+ {
+ sal_Int32 nCount = pAccGroupShape->getAccessibleChildCount();
+ for( sal_Int32 i = 0; i < nCount; i++ )
+ {
+ uno::Reference<XAccessible> xAccShape = pAccGroupShape->getAccessibleChild(i);
+ if (xAccShape.is())
+ {
+ ::accessibility::AccessibleShape* pChildAccShape = static_cast< ::accessibility::AccessibleShape* >(xAccShape.get());
+ uno::Reference< drawing::XShape > xChildShape = pChildAccShape->GetXShape();
+ if (xChildShape == xMarkedXShape)
+ {
+ pChildAccShape->SetState(AccessibleStateType::FOCUSED);
+ }
+ else
+ {
+ pChildAccShape->ResetState(AccessibleStateType::FOCUSED);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (vecSelectedShapeAdd.size() >= 10 )
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
+ aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
+ mpAccessibleDocument->CommitChange(aEvent);
+ }
+ else
+ {
+ for (const auto& rpShape : vecSelectedShapeAdd)
+ {
+ AccessibleEventObject aEvent;
+ if (bHasSelect)
+ {
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD;
+ }
+ else
+ {
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
+ }
+ aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
+ uno::Reference< XAccessible > xChild( rpShape->pAccShape );
+ aEvent.NewValue <<= xChild;
+ mpAccessibleDocument->CommitChange(aEvent);
+ }
+ }
+ for (const auto& rpShape : vecSelectedShapeRemove)
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
+ aEvent.Source = uno::Reference< XAccessible >(mpAccessibleDocument);
+ uno::Reference< XAccessible > xChild( rpShape->pAccShape );
+ aEvent.NewValue <<= xChild;
+ mpAccessibleDocument->CommitChange(aEvent);
+ }
+ for(ScAccessibleShapeData*& pShapeData : aShapesList)
+ {
+ delete pShapeData;
+ pShapeData = nullptr;
+ }
+ return bResult;
+}
+
+std::optional<ScAddress> ScChildrenShapes::GetAnchor(const uno::Reference<drawing::XShape>& xShape) const
+{
+ if (mpViewShell)
+ {
+ SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape(xShape);
+ uno::Reference<beans::XPropertySet> xShapeProp(xShape, uno::UNO_QUERY);
+ if (pSdrObj && xShapeProp.is())
+ {
+ if (ScDrawObjData *pAnchor = ScDrawLayer::GetObjData(pSdrObj))
+ return std::optional<ScAddress>(pAnchor->maStart);
+ }
+ }
+
+ return std::optional<ScAddress>();
+}
+
+uno::Reference<XAccessibleRelationSet> ScChildrenShapes::GetRelationSet(const ScAccessibleShapeData* pData) const
+{
+ rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSet = new utl::AccessibleRelationSetHelper();
+
+ if (pData && mpAccessibleDocument)
+ {
+ uno::Reference<XAccessible> xAccessible = mpAccessibleDocument->GetAccessibleSpreadsheet(); // should be the current table
+ if (pData->xRelationCell && xAccessible.is())
+ {
+ sal_Int32 nRow = pData->xRelationCell->Row();
+ sal_Int32 nColumn = pData->xRelationCell->Col();
+ bool bPositionUnset = nRow == -1 && nColumn == -1;
+ if (!bPositionUnset)
+ {
+ uno::Reference<XAccessibleTable> xAccTable(xAccessible->getAccessibleContext(), uno::UNO_QUERY);
+ if (xAccTable.is())
+ xAccessible = xAccTable->getAccessibleCellAt(nRow, nColumn);
+ }
+ }
+ AccessibleRelation aRelation;
+ aRelation.TargetSet = { xAccessible };
+ aRelation.RelationType = AccessibleRelationType::CONTROLLED_BY;
+ pRelationSet->AddRelation(aRelation);
+ }
+
+ return pRelationSet;
+}
+
+void ScChildrenShapes::SetAnchor(const uno::Reference<drawing::XShape>& xShape, ScAccessibleShapeData* pData) const
+{
+ if (pData)
+ {
+ std::optional<ScAddress> xAddress = GetAnchor(xShape);
+ if ((xAddress && pData->xRelationCell && (*xAddress != *(pData->xRelationCell))) ||
+ (!xAddress && pData->xRelationCell) || (xAddress && !pData->xRelationCell))
+ {
+ pData->xRelationCell = xAddress;
+ if (pData->pAccShape.is())
+ pData->pAccShape->SetRelationSet(GetRelationSet(pData));
+ }
+ }
+}
+
+void ScChildrenShapes::AddShape(const uno::Reference<drawing::XShape>& xShape, bool bCommitChange) const
+{
+ assert( maShapesMap.find(xShape) == maShapesMap.end());
+
+ ScAccessibleShapeData* pShape = new ScAccessibleShapeData(xShape);
+ maZOrderedShapes.push_back(pShape);
+ mbShapesNeedSorting = true;
+ maShapesMap[xShape] = pShape;
+ SetAnchor(xShape, pShape);
+
+ uno::Reference< beans::XPropertySet > xShapeProp(xShape, uno::UNO_QUERY);
+ if (xShapeProp.is())
+ {
+ uno::Any aPropAny = xShapeProp->getPropertyValue("LayerID");
+ sal_Int16 nLayerID = 0;
+ if( aPropAny >>= nLayerID )
+ {
+ if( (SdrLayerID(nLayerID) == SC_LAYER_INTERN) || (SdrLayerID(nLayerID) == SC_LAYER_HIDDEN) )
+ pShape->bSelectable = false;
+ else
+ pShape->bSelectable = true;
+ }
+ }
+
+ if (!xSelectionSupplier.is())
+ throw uno::RuntimeException();
+
+ uno::Reference<drawing::XShapes> xShapes(mpViewShell->getSelectedXShapes());
+ uno::Reference<container::XEnumerationAccess> xEnumAcc(xShapes, uno::UNO_QUERY);
+ if (xEnumAcc.is())
+ {
+ uno::Reference<container::XEnumeration> xEnum = xEnumAcc->createEnumeration();
+ if (xEnum.is())
+ {
+ uno::Reference<drawing::XShape> xSelectedShape;
+ bool bFound(false);
+ while (!bFound && xEnum->hasMoreElements())
+ {
+ xEnum->nextElement() >>= xSelectedShape;
+ if (xShape.is() && (xShape.get() == xSelectedShape.get()))
+ {
+ pShape->bSelected = true;
+ bFound = true;
+ }
+ }
+ }
+ }
+ if (mpAccessibleDocument && bCommitChange)
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
+ aEvent.NewValue <<= Get(pShape);
+
+ mpAccessibleDocument->CommitChange(aEvent); // new child - event
+ }
+}
+
+void ScChildrenShapes::RemoveShape(const uno::Reference<drawing::XShape>& xShape) const
+{
+ if (mbShapesNeedSorting)
+ {
+ std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
+ mbShapesNeedSorting = false;
+ }
+ SortedShapes::iterator aItr;
+ if (FindShape(xShape, aItr))
+ {
+ if (mpAccessibleDocument)
+ {
+ uno::Reference<XAccessible> xOldAccessible (Get(*aItr));
+
+ delete *aItr;
+ maShapesMap.erase((*aItr)->xShape);
+ maZOrderedShapes.erase(aItr);
+
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.Source = uno::Reference< XAccessibleContext >(mpAccessibleDocument);
+ aEvent.OldValue <<= xOldAccessible;
+
+ mpAccessibleDocument->CommitChange(aEvent); // child is gone - event
+ }
+ else
+ {
+ delete *aItr;
+ maShapesMap.erase((*aItr)->xShape);
+ maZOrderedShapes.erase(aItr);
+ }
+ }
+ else
+ {
+ OSL_FAIL("shape was not in internal list");
+ }
+}
+
+bool ScChildrenShapes::FindShape(const uno::Reference<drawing::XShape>& xShape, ScChildrenShapes::SortedShapes::iterator& rItr) const
+{
+ if (mbShapesNeedSorting)
+ {
+ std::sort(maZOrderedShapes.begin(), maZOrderedShapes.end(), ScShapeDataLess());
+ mbShapesNeedSorting = false;
+ }
+ bool bResult(false);
+ ScAccessibleShapeData aShape(xShape);
+ rItr = std::lower_bound(maZOrderedShapes.begin(), maZOrderedShapes.end(), &aShape, ScShapeDataLess());
+ if ((rItr != maZOrderedShapes.end()) && (*rItr != nullptr) && ((*rItr)->xShape.get() == xShape.get()))
+ bResult = true; // if the shape is found
+
+#if OSL_DEBUG_LEVEL > 0 // test whether it finds truly the correct shape (perhaps it is not really sorted)
+ SortedShapes::iterator aDebugItr = std::find_if(maZOrderedShapes.begin(), maZOrderedShapes.end(),
+ [&xShape](const ScAccessibleShapeData* pShape) { return pShape && (pShape->xShape.get() == xShape.get()); });
+ bool bResult2 = (aDebugItr != maZOrderedShapes.end());
+ OSL_ENSURE((bResult == bResult2) && ((bResult && (rItr == aDebugItr)) || !bResult), "wrong Shape found");
+#endif
+ return bResult;
+}
+
+sal_Int8 ScChildrenShapes::Compare(const ScAccessibleShapeData* pData1,
+ const ScAccessibleShapeData* pData2)
+{
+ ScShapeDataLess aLess;
+
+ bool bResult1(aLess(pData1, pData2));
+ bool bResult2(aLess(pData2, pData1));
+
+ sal_Int8 nResult(0);
+ if (!bResult1 && bResult2)
+ nResult = 1;
+ else if (bResult1 && !bResult2)
+ nResult = -1;
+
+ return nResult;
+}
+
+void ScChildrenShapes::VisAreaChanged() const
+{
+ for (const ScAccessibleShapeData* pAccShapeData: maZOrderedShapes)
+ if (pAccShapeData && pAccShapeData->pAccShape.is())
+ pAccShapeData->pAccShape->ViewForwarderChanged();
+}
+
+ScAccessibleDocument::ScAccessibleDocument(
+ const uno::Reference<XAccessible>& rxParent,
+ ScTabViewShell* pViewShell,
+ ScSplitPos eSplitPos)
+ : ScAccessibleDocumentBase(rxParent),
+ mpViewShell(pViewShell),
+ meSplitPos(eSplitPos),
+ mbCompleteSheetSelected(false)
+{
+ maVisArea = GetVisibleArea_Impl();
+}
+
+void ScAccessibleDocument::PreInit()
+{
+ if (!mpViewShell)
+ return;
+
+ mpViewShell->AddAccessibilityObject(*this);
+ vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos);
+ if( pWin )
+ {
+ pWin->AddChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener ));
+ sal_uInt16 nCount = pWin->GetChildCount();
+ for( sal_uInt16 i=0; i < nCount; ++i )
+ {
+ vcl::Window *pChildWin = pWin->GetChild( i );
+ if( pChildWin &&
+ AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
+ AddChild( pChildWin->GetAccessible(), false );
+ }
+ }
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ if (rViewData.HasEditView(meSplitPos))
+ {
+ uno::Reference<XAccessible> xAcc = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos),
+ mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(), GetCurrentCellDescription(),
+ ScAccessibleEditObject::CellInEditMode);
+ AddChild(xAcc, false);
+ }
+}
+
+void ScAccessibleDocument::Init()
+{
+ if(!mpChildrenShapes)
+ mpChildrenShapes.reset( new ScChildrenShapes(this, mpViewShell, meSplitPos) );
+}
+
+ScAccessibleDocument::~ScAccessibleDocument()
+{
+ if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
+ {
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+}
+
+void SAL_CALL ScAccessibleDocument::disposing()
+{
+ SolarMutexGuard aGuard;
+ FreeAccessibleSpreadsheet();
+ if (mpViewShell)
+ {
+ vcl::Window *pWin = mpViewShell->GetWindowByPos(meSplitPos);
+ if( pWin )
+ pWin->RemoveChildEventListener( LINK( this, ScAccessibleDocument, WindowChildEventListener ));
+
+ mpViewShell->RemoveAccessibilityObject(*this);
+ mpViewShell = nullptr;
+ }
+ mpChildrenShapes.reset();
+
+ ScAccessibleDocumentBase::disposing();
+}
+
+void SAL_CALL ScAccessibleDocument::disposing( const lang::EventObject& /* Source */ )
+{
+ disposing();
+}
+
+ //===== SfxListener =====================================================
+
+IMPL_LINK( ScAccessibleDocument, WindowChildEventListener, VclWindowEvent&, rEvent, void )
+{
+ OSL_ENSURE( rEvent.GetWindow(), "Window???" );
+ switch ( rEvent.GetId() )
+ {
+ case VclEventId::WindowShow: // send create on show for direct accessible children
+ {
+ vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() );
+ if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
+ {
+ AddChild( pChildWin->GetAccessible(), true );
+ }
+ }
+ break;
+ case VclEventId::WindowHide: // send destroy on hide for direct accessible children
+ {
+ vcl::Window* pChildWin = static_cast < vcl::Window * >( rEvent.GetData() );
+ if( pChildWin && AccessibleRole::EMBEDDED_OBJECT == pChildWin->GetAccessibleRole() )
+ {
+ RemoveChild( pChildWin->GetAccessible(), true );
+ }
+ }
+ break;
+ default: break;
+ }
+}
+
+void ScAccessibleDocument::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if (auto pFocusLostHint = dynamic_cast<const ScAccGridWinFocusLostHint*>(&rHint) )
+ {
+ if (pFocusLostHint->GetOldGridWin() == meSplitPos)
+ {
+ if (mxTempAcc.is() && mpTempAccEdit)
+ mpTempAccEdit->LostFocus();
+ else if (mpAccessibleSpreadsheet.is())
+ mpAccessibleSpreadsheet->LostFocus();
+ else
+ CommitFocusLost();
+ }
+ }
+ else if (auto pFocusGotHint = dynamic_cast<const ScAccGridWinFocusGotHint*>(&rHint) )
+ {
+ if (pFocusGotHint->GetNewGridWin() == meSplitPos)
+ {
+ uno::Reference<XAccessible> xAccessible;
+ if (mpChildrenShapes)
+ {
+ bool bTabMarked(IsTableSelected());
+ xAccessible = mpChildrenShapes->GetSelected(0, bTabMarked);
+ }
+ if( xAccessible.is() )
+ {
+ uno::Any aNewValue;
+ aNewValue<<=AccessibleStateType::FOCUSED;
+ static_cast< ::accessibility::AccessibleShape* >(xAccessible.get())->
+ CommitChange(AccessibleEventId::STATE_CHANGED,
+ aNewValue,
+ uno::Any() );
+ }
+ else
+ {
+ if (mxTempAcc.is() && mpTempAccEdit)
+ mpTempAccEdit->GotFocus();
+ else if (mpAccessibleSpreadsheet.is())
+ mpAccessibleSpreadsheet->GotFocus();
+ else
+ CommitFocusGained();
+ }
+ }
+ }
+ else
+ {
+ // only notify if child exist, otherwise it is not necessary
+ if ((rHint.GetId() == SfxHintId::ScAccTableChanged) &&
+ mpAccessibleSpreadsheet.is())
+ {
+ FreeAccessibleSpreadsheet();
+
+ // Shapes / form controls after reload not accessible, rebuild the
+ // mpChildrenShapes variable.
+ mpChildrenShapes.reset( new ScChildrenShapes( this, mpViewShell, meSplitPos ) );
+
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::INVALIDATE_ALL_CHILDREN;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ CommitChange(aEvent); // all children changed
+
+ if (mpAccessibleSpreadsheet.is())
+ mpAccessibleSpreadsheet->FireFirstCellFocus();
+ }
+ else if (rHint.GetId() == SfxHintId::ScAccMakeDrawLayer)
+ {
+ if (mpChildrenShapes)
+ mpChildrenShapes->SetDrawBroadcaster();
+ }
+ else if (rHint.GetId() == SfxHintId::ScAccEnterEditMode) // this event comes only on creating edit field of a cell
+ {
+ if (mpViewShell->GetViewData().GetEditActivePart() == meSplitPos)
+ {
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ const EditEngine* pEditEng = rViewData.GetEditView(meSplitPos)->GetEditEngine();
+ if (pEditEng && pEditEng->IsUpdateLayout())
+ {
+ mpTempAccEdit = new ScAccessibleEditObject(this, rViewData.GetEditView(meSplitPos),
+ mpViewShell->GetWindowByPos(meSplitPos), GetCurrentCellName(),
+ ScResId(STR_ACC_EDITLINE_DESCR), ScAccessibleEditObject::CellInEditMode);
+ uno::Reference<XAccessible> xAcc = mpTempAccEdit;
+
+ AddChild(xAcc, true);
+
+ if (mpAccessibleSpreadsheet.is())
+ mpAccessibleSpreadsheet->LostFocus();
+ else
+ CommitFocusLost();
+
+ mpTempAccEdit->GotFocus();
+ }
+ }
+ }
+ else if (rHint.GetId() == SfxHintId::ScAccLeaveEditMode)
+ {
+ if (mxTempAcc.is())
+ {
+ if (mpTempAccEdit)
+ {
+ mpTempAccEdit->LostFocus();
+ }
+ RemoveChild(mxTempAcc, true);
+ if (mpTempAccEdit)
+ {
+ // tdf#125982 a11y use-after-free of editengine by
+ // ScAccessibleEditObjectTextData living past the
+ // the editengine of the editview passed in above
+ // in ScAccEnterEditMode
+ mpTempAccEdit->dispose();
+ mpTempAccEdit = nullptr;
+ }
+ if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive())
+ mpAccessibleSpreadsheet->GotFocus();
+ else if( mpViewShell && mpViewShell->IsActive())
+ CommitFocusGained();
+ }
+ }
+ else if ((rHint.GetId() == SfxHintId::ScAccVisAreaChanged) || (rHint.GetId() == SfxHintId::ScAccWindowResized))
+ {
+ tools::Rectangle aOldVisArea(maVisArea);
+ maVisArea = GetVisibleArea_Impl();
+
+ if (maVisArea != aOldVisArea)
+ {
+ if (maVisArea.GetSize() != aOldVisArea.GetSize())
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+
+ CommitChange(aEvent);
+
+ if (mpAccessibleSpreadsheet.is())
+ mpAccessibleSpreadsheet->BoundingBoxChanged();
+ if (mpAccessibleSpreadsheet.is() && mpViewShell && mpViewShell->IsActive())
+ mpAccessibleSpreadsheet->FireFirstCellFocus();
+ }
+ else if (mpAccessibleSpreadsheet.is())
+ {
+ mpAccessibleSpreadsheet->VisAreaChanged();
+ }
+ if (mpChildrenShapes)
+ mpChildrenShapes->VisAreaChanged();
+ }
+ }
+ }
+
+ ScAccessibleDocumentBase::Notify(rBC, rHint);
+}
+
+void SAL_CALL ScAccessibleDocument::selectionChanged( const lang::EventObject& /* aEvent */ )
+{
+ bool bSelectionChanged(false);
+ if (mpAccessibleSpreadsheet.is())
+ {
+ bool bOldSelected(mbCompleteSheetSelected);
+ mbCompleteSheetSelected = IsTableSelected();
+ if (bOldSelected != mbCompleteSheetSelected)
+ {
+ mpAccessibleSpreadsheet->CompleteSelectionChanged(mbCompleteSheetSelected);
+ bSelectionChanged = true;
+ }
+ }
+
+ if (mpChildrenShapes && mpChildrenShapes->SelectionChanged())
+ bSelectionChanged = true;
+
+ if (bSelectionChanged)
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+
+ CommitChange(aEvent);
+ }
+}
+
+ //===== XInterface =====================================================
+
+uno::Any SAL_CALL ScAccessibleDocument::queryInterface( uno::Type const & rType )
+{
+ uno::Any aAny (ScAccessibleDocumentImpl::queryInterface(rType));
+ return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType);
+}
+
+void SAL_CALL ScAccessibleDocument::acquire()
+ noexcept
+{
+ ScAccessibleContextBase::acquire();
+}
+
+void SAL_CALL ScAccessibleDocument::release()
+ noexcept
+{
+ ScAccessibleContextBase::release();
+}
+
+ //===== XAccessibleComponent ============================================
+
+uno::Reference< XAccessible > SAL_CALL ScAccessibleDocument::getAccessibleAtPoint(
+ const awt::Point& rPoint )
+{
+ uno::Reference<XAccessible> xAccessible;
+ if (containsPoint(rPoint))
+ {
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (mpChildrenShapes)
+ xAccessible = mpChildrenShapes->GetAt(rPoint);
+ if(!xAccessible.is())
+ {
+ if (mxTempAcc.is())
+ {
+ uno::Reference< XAccessibleContext > xCont(mxTempAcc->getAccessibleContext());
+ uno::Reference< XAccessibleComponent > xComp(xCont, uno::UNO_QUERY);
+ if (xComp.is())
+ {
+ tools::Rectangle aBound(VCLRectangle(xComp->getBounds()));
+ if (aBound.Contains(VCLPoint(rPoint)))
+ xAccessible = mxTempAcc;
+ }
+ }
+ if (!xAccessible.is())
+ xAccessible = GetAccessibleSpreadsheet();
+ }
+ }
+ return xAccessible;
+}
+
+void SAL_CALL ScAccessibleDocument::grabFocus( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (!getAccessibleParent().is())
+ return;
+
+ uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
+ if (xAccessibleComponent.is())
+ {
+ xAccessibleComponent->grabFocus();
+ // grab only focus if it does not have the focus and it is not hidden
+ if (mpViewShell &&
+ (mpViewShell->GetViewData().GetActivePart() != meSplitPos) &&
+ mpViewShell->GetWindowByPos(meSplitPos)->IsVisible())
+ {
+ mpViewShell->ActivatePart(meSplitPos);
+ }
+ }
+}
+
+ //===== XAccessibleContext ==============================================
+
+ /// Return the number of currently visible children.
+sal_Int32 SAL_CALL
+ ScAccessibleDocument::getAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ sal_Int32 nCount(1);
+ if (mpChildrenShapes)
+ nCount = mpChildrenShapes->GetCount(); // returns the count of the shapes inclusive the table
+
+ if (mxTempAcc.is())
+ ++nCount;
+
+ return nCount;
+}
+
+ /// Return the specified child or NULL if index is invalid.
+uno::Reference<XAccessible> SAL_CALL
+ ScAccessibleDocument::getAccessibleChild(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ uno::Reference<XAccessible> xAccessible;
+ if (nIndex >= 0)
+ {
+ sal_Int32 nCount(1);
+ if (mpChildrenShapes)
+ {
+ xAccessible = mpChildrenShapes->Get(nIndex); // returns NULL if it is the table or out of range
+ nCount = mpChildrenShapes->GetCount(); //there is always a table
+ }
+ if (!xAccessible.is())
+ {
+ if (nIndex < nCount)
+ xAccessible = GetAccessibleSpreadsheet();
+ else if (nIndex == nCount && mxTempAcc.is())
+ xAccessible = mxTempAcc;
+ }
+ }
+
+ if (!xAccessible.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return xAccessible;
+}
+
+ /// Return the set of current states.
+uno::Reference<XAccessibleStateSet> SAL_CALL
+ ScAccessibleDocument::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<XAccessibleStateSet> xParentStates;
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
+ xParentStates = xParentContext->getAccessibleStateSet();
+ }
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSet = new utl::AccessibleStateSetHelper();
+ if (IsDefunc(xParentStates))
+ pStateSet->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ pStateSet->AddState(AccessibleStateType::EDITABLE);
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::OPAQUE);
+ if (isShowing())
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ if (isVisible())
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ }
+ return pStateSet;
+}
+
+OUString SAL_CALL
+ ScAccessibleDocument::getAccessibleName()
+{
+ SolarMutexGuard g;
+
+ OUString aName = ScResId(STR_ACC_DOC_SPREADSHEET);
+ ScDocument* pScDoc = GetDocument();
+ if (!pScDoc)
+ return aName;
+
+ SfxObjectShell* pObjSh = pScDoc->GetDocumentShell();
+ if (!pObjSh)
+ return aName;
+
+ OUString aFileName;
+ SfxMedium* pMed = pObjSh->GetMedium();
+ if (pMed)
+ aFileName = pMed->GetName();
+
+ if (aFileName.isEmpty())
+ aFileName = pObjSh->GetTitle(SFX_TITLE_APINAME);
+
+ if (!aFileName.isEmpty())
+ {
+ OUString aReadOnly;
+ if (pObjSh->IsReadOnly())
+ aReadOnly = ScResId(STR_ACC_DOC_SPREADSHEET_READONLY);
+
+ aName = aFileName + aReadOnly + " - " + aName;
+ }
+ return aName;
+}
+
+///===== XAccessibleSelection ===========================================
+
+void SAL_CALL
+ ScAccessibleDocument::selectAccessibleChild( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if (!(mpChildrenShapes && mpViewShell))
+ return;
+
+ sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
+ if (mxTempAcc.is())
+ ++nCount;
+ if (nChildIndex < 0 || nChildIndex >= nCount)
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
+ if (xAccessible.is())
+ {
+ bool bWasTableSelected(IsTableSelected());
+ mpChildrenShapes->Select(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high
+ if (bWasTableSelected)
+ mpViewShell->SelectAll();
+ }
+ else
+ {
+ mpViewShell->SelectAll();
+ }
+}
+
+sal_Bool SAL_CALL
+ ScAccessibleDocument::isAccessibleChildSelected( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ bool bResult(false);
+
+ if (mpChildrenShapes)
+ {
+ sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
+ if (mxTempAcc.is())
+ ++nCount;
+ if (nChildIndex < 0 || nChildIndex >= nCount)
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
+ if (xAccessible.is())
+ {
+ uno::Reference<drawing::XShape> xShape;
+ bResult = mpChildrenShapes->IsSelected(nChildIndex, xShape); // throws no lang::IndexOutOfBoundsException if Index is too high
+ }
+ else
+ {
+ if (mxTempAcc.is() && nChildIndex == nCount)
+ bResult = true;
+ else
+ bResult = IsTableSelected();
+ }
+ }
+ return bResult;
+}
+
+void SAL_CALL
+ ScAccessibleDocument::clearAccessibleSelection( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if (mpChildrenShapes)
+ mpChildrenShapes->DeselectAll(); //deselects all (also the table)
+}
+
+void SAL_CALL
+ ScAccessibleDocument::selectAllAccessibleChildren( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if (mpChildrenShapes)
+ mpChildrenShapes->SelectAll();
+
+ // select table after shapes, because while selecting shapes the table will be deselected
+ if (mpViewShell)
+ {
+ mpViewShell->SelectAll();
+ }
+}
+
+sal_Int32 SAL_CALL
+ ScAccessibleDocument::getSelectedAccessibleChildCount( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ sal_Int32 nCount(0);
+
+ if (mpChildrenShapes)
+ nCount = mpChildrenShapes->GetSelectedCount();
+
+ if (IsTableSelected())
+ ++nCount;
+
+ if (mxTempAcc.is())
+ ++nCount;
+
+ return nCount;
+}
+
+uno::Reference<XAccessible > SAL_CALL
+ ScAccessibleDocument::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ uno::Reference<XAccessible> xAccessible;
+ if (mpChildrenShapes)
+ {
+ sal_Int32 nCount(getSelectedAccessibleChildCount()); //all shapes and the table
+ if (nSelectedChildIndex < 0 || nSelectedChildIndex >= nCount)
+ throw lang::IndexOutOfBoundsException();
+
+ bool bTabMarked(IsTableSelected());
+
+ if (mpChildrenShapes)
+ xAccessible = mpChildrenShapes->GetSelected(nSelectedChildIndex, bTabMarked); // throws no lang::IndexOutOfBoundsException if Index is too high
+ if (mxTempAcc.is() && nSelectedChildIndex == nCount - 1)
+ xAccessible = mxTempAcc;
+ else if (bTabMarked)
+ xAccessible = GetAccessibleSpreadsheet();
+ }
+
+ OSL_ENSURE(xAccessible.is(), "here should always be an accessible object or an exception thrown");
+
+ return xAccessible;
+}
+
+void SAL_CALL
+ ScAccessibleDocument::deselectAccessibleChild( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if (!(mpChildrenShapes && mpViewShell))
+ return;
+
+ sal_Int32 nCount(mpChildrenShapes->GetCount()); // all shapes and the table
+ if (mxTempAcc.is())
+ ++nCount;
+ if (nChildIndex < 0 || nChildIndex >= nCount)
+ throw lang::IndexOutOfBoundsException();
+
+ bool bTabMarked(IsTableSelected());
+
+ uno::Reference < XAccessible > xAccessible = mpChildrenShapes->Get(nChildIndex);
+ if (xAccessible.is())
+ {
+ mpChildrenShapes->Deselect(nChildIndex); // throws no lang::IndexOutOfBoundsException if Index is too high
+ if (bTabMarked)
+ mpViewShell->SelectAll(); // select the table again
+ }
+ else if (bTabMarked)
+ mpViewShell->Unmark();
+}
+
+ //===== XServiceInfo ====================================================
+
+OUString SAL_CALL
+ ScAccessibleDocument::getImplementationName()
+{
+ return "ScAccessibleDocument";
+}
+
+uno::Sequence< OUString> SAL_CALL
+ ScAccessibleDocument::getSupportedServiceNames()
+{
+ const css::uno::Sequence<OUString> vals { "com.sun.star.AccessibleSpreadsheetDocumentView" };
+ return comphelper::concatSequences(ScAccessibleContextBase::getSupportedServiceNames(), vals);
+}
+
+//===== XTypeProvider =======================================================
+
+uno::Sequence< uno::Type > SAL_CALL ScAccessibleDocument::getTypes()
+{
+ return comphelper::concatSequences(ScAccessibleDocumentImpl::getTypes(), ScAccessibleContextBase::getTypes());
+}
+
+uno::Sequence<sal_Int8> SAL_CALL
+ ScAccessibleDocument::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+///===== IAccessibleViewForwarder ========================================
+
+tools::Rectangle ScAccessibleDocument::GetVisibleArea_Impl() const
+{
+ tools::Rectangle aVisRect(GetBoundingBox());
+
+ if (mpViewShell)
+ {
+ Point aPoint(mpViewShell->GetViewData().GetPixPos(meSplitPos)); // returns a negative Point
+ aPoint.setX(-aPoint.getX());
+ aPoint.setY(-aPoint.getY());
+ aVisRect.SetPos(aPoint);
+
+ ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
+ if (pWin)
+ aVisRect = pWin->PixelToLogic(aVisRect, pWin->GetDrawMapMode());
+ }
+
+ return aVisRect;
+}
+
+tools::Rectangle ScAccessibleDocument::GetVisibleArea() const
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ return maVisArea;
+}
+
+Point ScAccessibleDocument::LogicToPixel (const Point& rPoint) const
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ Point aPoint;
+ ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
+ if (pWin)
+ {
+ aPoint = pWin->LogicToPixel(rPoint, pWin->GetDrawMapMode());
+ aPoint += pWin->GetWindowExtentsRelative(nullptr).TopLeft();
+ }
+ return aPoint;
+}
+
+Size ScAccessibleDocument::LogicToPixel (const Size& rSize) const
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ Size aSize;
+ ScGridWindow* pWin = static_cast<ScGridWindow*>(mpViewShell->GetWindowByPos(meSplitPos));
+ if (pWin)
+ aSize = pWin->LogicToPixel(rSize, pWin->GetDrawMapMode());
+ return aSize;
+}
+
+ //===== internal ========================================================
+
+rtl::Reference<utl::AccessibleRelationSetHelper> ScAccessibleDocument::GetRelationSet(const ScAddress* pAddress) const
+{
+ rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSet;
+ if (mpChildrenShapes)
+ pRelationSet = mpChildrenShapes->GetRelationSet(pAddress);
+ return pRelationSet;
+}
+
+OUString
+ ScAccessibleDocument::createAccessibleDescription()
+{
+ return STR_ACC_DOC_DESCR;
+}
+
+OUString
+ ScAccessibleDocument::createAccessibleName()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ OUString sName = ScResId(STR_ACC_DOC_NAME);
+ sal_Int32 nNumber(sal_Int32(meSplitPos) + 1);
+ sName += OUString::number(nNumber);
+ return sName;
+}
+
+tools::Rectangle ScAccessibleDocument::GetBoundingBoxOnScreen() const
+{
+ tools::Rectangle aRect;
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
+ if (pWindow)
+ aRect = pWindow->GetWindowExtentsRelative(nullptr);
+ }
+ return aRect;
+}
+
+tools::Rectangle ScAccessibleDocument::GetBoundingBox() const
+{
+ tools::Rectangle aRect;
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
+ if (pWindow)
+ aRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow());
+ }
+ return aRect;
+}
+
+SCTAB ScAccessibleDocument::getVisibleTable() const
+{
+ SCTAB nVisibleTable(0);
+ if (mpViewShell)
+ nVisibleTable = mpViewShell->GetViewData().GetTabNo();
+ return nVisibleTable;
+}
+
+uno::Reference < XAccessible >
+ ScAccessibleDocument::GetAccessibleSpreadsheet()
+{
+ if (!mpAccessibleSpreadsheet.is() && mpViewShell)
+ {
+ mpAccessibleSpreadsheet = new ScAccessibleSpreadsheet(this, mpViewShell, getVisibleTable(), meSplitPos);
+ mpAccessibleSpreadsheet->Init();
+ mbCompleteSheetSelected = IsTableSelected();
+ }
+ return mpAccessibleSpreadsheet;
+}
+
+void ScAccessibleDocument::FreeAccessibleSpreadsheet()
+{
+ if (mpAccessibleSpreadsheet.is())
+ {
+ mpAccessibleSpreadsheet->dispose();
+ mpAccessibleSpreadsheet.clear();
+ }
+}
+
+bool ScAccessibleDocument::IsTableSelected() const
+{
+ bool bResult (false);
+ if(mpViewShell)
+ {
+ SCTAB nTab(getVisibleTable());
+ //#103800#; use a copy of MarkData
+ ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData());
+ ScDocument* pDoc = GetDocument();
+ if (aMarkData.IsAllMarked( ScRange( 0, 0, nTab, pDoc->MaxCol(), pDoc->MaxRow(), nTab)))
+ bResult = true;
+ }
+ return bResult;
+}
+
+bool ScAccessibleDocument::IsDefunc(
+ const uno::Reference<XAccessibleStateSet>& rxParentStates)
+{
+ return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
+ (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
+}
+
+void ScAccessibleDocument::AddChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent)
+{
+ OSL_ENSURE(!mxTempAcc.is(), "this object should be removed before");
+ if (xAcc.is())
+ {
+ mxTempAcc = xAcc;
+ if( bFireEvent )
+ {
+ AccessibleEventObject aEvent;
+ aEvent.Source = uno::Reference<XAccessibleContext>(this);
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.NewValue <<= mxTempAcc;
+ CommitChange( aEvent );
+ }
+ }
+}
+
+void ScAccessibleDocument::RemoveChild(const uno::Reference<XAccessible>& xAcc, bool bFireEvent)
+{
+ OSL_ENSURE(mxTempAcc.is(), "this object should be added before");
+ if (!xAcc.is())
+ return;
+
+ OSL_ENSURE(xAcc.get() == mxTempAcc.get(), "only the same object should be removed");
+ if( bFireEvent )
+ {
+ AccessibleEventObject aEvent;
+ aEvent.Source = uno::Reference<XAccessibleContext>(this);
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.OldValue <<= mxTempAcc;
+ CommitChange( aEvent );
+ }
+ mxTempAcc = nullptr;
+}
+
+OUString ScAccessibleDocument::GetCurrentCellName() const
+{
+ OUString sName(ScResId(STR_ACC_CELL_NAME));
+ if (mpViewShell)
+ {
+ // Document not needed, because only the cell address, but not the tablename is needed
+ OUString sAddress(mpViewShell->GetViewData().GetCurPos().Format(ScRefFlags::VALID));
+ sName = sName.replaceFirst("%1", sAddress);
+ }
+ return sName;
+}
+
+OUString ScAccessibleDocument::GetCurrentCellDescription()
+{
+ return OUString();
+}
+
+ScDocument *ScAccessibleDocument::GetDocument() const
+{
+ return mpViewShell ? &mpViewShell->GetViewData().GetDocument() : nullptr;
+}
+
+ScAddress ScAccessibleDocument::GetCurCellAddress() const
+{
+ return mpViewShell ? mpViewShell->GetViewData().GetCurPos() : ScAddress();
+}
+
+uno::Any SAL_CALL ScAccessibleDocument::getExtendedAttributes()
+{
+ SolarMutexGuard g;
+
+ uno::Any anyAttribute;
+
+ sal_uInt16 sheetIndex;
+ OUString sSheetName;
+ sheetIndex = getVisibleTable();
+ if(GetDocument()==nullptr)
+ return anyAttribute;
+ GetDocument()->GetName(sheetIndex,sSheetName);
+ OUString sValue = "page-name:" + sSheetName +
+ ";page-number:" + OUString::number(sheetIndex+1) +
+ ";total-pages:" + OUString::number(GetDocument()->GetTableCount()) + ";";
+ anyAttribute <<= sValue;
+ return anyAttribute;
+}
+
+sal_Int32 SAL_CALL ScAccessibleDocument::getForeground( )
+{
+ return sal_Int32(COL_BLACK);
+}
+
+sal_Int32 SAL_CALL ScAccessibleDocument::getBackground( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ return sal_Int32(SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessibleDocumentBase.cxx b/sc/source/ui/Accessibility/AccessibleDocumentBase.cxx
new file mode 100644
index 000000000..78da26006
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleDocumentBase.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 <AccessibleDocumentBase.hxx>
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+//===== internal ========================================================
+
+ScAccessibleDocumentBase::ScAccessibleDocumentBase(const uno::Reference<XAccessible>& rxParent)
+ : ScAccessibleContextBase(rxParent, AccessibleRole::DOCUMENT_SPREADSHEET)
+{
+}
+
+ScAccessibleDocumentBase::~ScAccessibleDocumentBase() {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessibleDocumentPagePreview.cxx b/sc/source/ui/Accessibility/AccessibleDocumentPagePreview.cxx
new file mode 100644
index 000000000..9656b82af
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleDocumentPagePreview.cxx
@@ -0,0 +1,1567 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleDocumentPagePreview.hxx>
+#include <AccessiblePreviewTable.hxx>
+#include <AccessiblePageHeader.hxx>
+#include <AccessibilityHints.hxx>
+#include <AccessibleText.hxx>
+#include <document.hxx>
+#include <prevwsh.hxx>
+#include <prevloc.hxx>
+#include <drwlayer.hxx>
+#include <editsrc.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <preview.hxx>
+#include <postit.hxx>
+
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/sequence.hxx>
+
+#include <unotools/accessiblestatesethelper.hxx>
+#include <tools/gen.hxx>
+#include <svx/fmview.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/AccessibleTextHelper.hxx>
+#include <svx/AccessibleShape.hxx>
+#include <svx/AccessibleShapeInfo.hxx>
+#include <svx/IAccessibleParent.hxx>
+#include <svx/IAccessibleViewForwarder.hxx>
+#include <svx/ShapeTypeHandler.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/docfile.hxx>
+
+#include <vector>
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+typedef std::vector< uno::Reference< XAccessible > > ScXAccVector;
+
+namespace {
+
+struct ScAccNote
+{
+ OUString maNoteText;
+ tools::Rectangle maRect;
+ ScAddress maNoteCell;
+ ::accessibility::AccessibleTextHelper* mpTextHelper;
+ sal_Int32 mnParaCount;
+ bool mbMarkNote;
+
+ ScAccNote()
+ : mpTextHelper(nullptr)
+ , mnParaCount(0)
+ , mbMarkNote(false)
+ {
+ }
+};
+
+}
+
+class ScNotesChildren
+{
+public:
+ ScNotesChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc);
+ ~ScNotesChildren();
+ void Init(const tools::Rectangle& rVisRect, sal_Int32 nOffset);
+
+ sal_Int32 GetChildrenCount() const { return mnParagraphs;}
+ uno::Reference<XAccessible> GetChild(sal_Int32 nIndex) const;
+ uno::Reference<XAccessible> GetAt(const awt::Point& rPoint) const;
+
+ void DataChanged(const tools::Rectangle& rVisRect);
+
+private:
+ ScPreviewShell* mpViewShell;
+ ScAccessibleDocumentPagePreview* mpAccDoc;
+ typedef std::vector<ScAccNote> ScAccNotes;
+ mutable ScAccNotes maNotes;
+ mutable ScAccNotes maMarks;
+ sal_Int32 mnParagraphs;
+ sal_Int32 mnOffset;
+
+ ::accessibility::AccessibleTextHelper* CreateTextHelper(const OUString& rString, const tools::Rectangle& rVisRect, const ScAddress& aCellPos, bool bMarkNote, sal_Int32 nChildOffset) const;
+ sal_Int32 AddNotes(const ScPreviewLocationData& rData, const tools::Rectangle& rVisRect, bool bMark, ScAccNotes& rNotes);
+
+ static sal_Int8 CompareCell(const ScAddress& aCell1, const ScAddress& aCell2);
+ static void CollectChildren(const ScAccNote& rNote, ScXAccVector& rVector);
+ sal_Int32 CheckChanges(const ScPreviewLocationData& rData, const tools::Rectangle& rVisRect,
+ bool bMark, ScAccNotes& rOldNotes, ScAccNotes& rNewNotes,
+ ScXAccVector& rOldParas, ScXAccVector& rNewParas);
+
+ inline ScDocument* GetDocument() const;
+};
+
+ScNotesChildren::ScNotesChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc)
+ : mpViewShell(pViewShell),
+ mpAccDoc(pAccDoc),
+ mnParagraphs(0),
+ mnOffset(0)
+{
+}
+
+ScNotesChildren::~ScNotesChildren()
+{
+ for (auto & i : maNotes)
+ if (i.mpTextHelper)
+ {
+ delete i.mpTextHelper;
+ i.mpTextHelper = nullptr;
+ }
+ for (auto & i : maMarks)
+ if (i.mpTextHelper)
+ {
+ delete i.mpTextHelper;
+ i.mpTextHelper = nullptr;
+ }
+}
+
+::accessibility::AccessibleTextHelper* ScNotesChildren::CreateTextHelper(const OUString& rString, const tools::Rectangle& rVisRect, const ScAddress& aCellPos, bool bMarkNote, sal_Int32 nChildOffset) const
+{
+ ::accessibility::AccessibleTextHelper* pTextHelper = new ::accessibility::AccessibleTextHelper(std::make_unique<ScAccessibilityEditSource>(std::make_unique<ScAccessibleNoteTextData>(mpViewShell, rString, aCellPos, bMarkNote)));
+ pTextHelper->SetEventSource(mpAccDoc);
+ pTextHelper->SetStartIndex(nChildOffset);
+ pTextHelper->SetOffset(rVisRect.TopLeft());
+
+ return pTextHelper;
+}
+
+sal_Int32 ScNotesChildren::AddNotes(const ScPreviewLocationData& rData, const tools::Rectangle& rVisRect, bool bMark, ScAccNotes& rNotes)
+{
+ sal_Int32 nCount = rData.GetNoteCountInRange(rVisRect, bMark);
+
+ rNotes.reserve(nCount);
+
+ sal_Int32 nParagraphs(0);
+ ScDocument* pDoc = GetDocument();
+ if (pDoc)
+ {
+ ScAccNote aNote;
+ aNote.mbMarkNote = bMark;
+ if (bMark)
+ aNote.mnParaCount = 1;
+ for (sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex)
+ {
+ if (rData.GetNoteInRange(rVisRect, nIndex, bMark, aNote.maNoteCell, aNote.maRect))
+ {
+ if (bMark)
+ {
+ // Document not needed, because only the cell address, but not the tablename is needed
+ aNote.maNoteText = aNote.maNoteCell.Format(ScRefFlags::VALID);
+ }
+ else
+ {
+ if( ScPostIt* pNote = pDoc->GetNote( aNote.maNoteCell ) )
+ aNote.maNoteText = pNote->GetText();
+ aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset);
+ if (aNote.mpTextHelper)
+ aNote.mnParaCount = aNote.mpTextHelper->GetChildCount();
+ }
+ nParagraphs += aNote.mnParaCount;
+ rNotes.push_back(aNote);
+ }
+ }
+ }
+ return nParagraphs;
+}
+
+void ScNotesChildren::Init(const tools::Rectangle& rVisRect, sal_Int32 nOffset)
+{
+ if (mpViewShell && !mnParagraphs)
+ {
+ mnOffset = nOffset;
+ const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
+
+ mnParagraphs = AddNotes(rData, rVisRect, false, maMarks);
+ mnParagraphs += AddNotes(rData, rVisRect, true, maNotes);
+ }
+}
+
+namespace {
+
+struct ScParaFound
+{
+ sal_Int32 mnIndex;
+ explicit ScParaFound(sal_Int32 nIndex) : mnIndex(nIndex) {}
+ bool operator() (const ScAccNote& rNote)
+ {
+ bool bResult(false);
+ if (rNote.mnParaCount > mnIndex)
+ bResult = true;
+ else
+ mnIndex -= rNote.mnParaCount;
+ return bResult;
+ }
+};
+
+}
+
+uno::Reference<XAccessible> ScNotesChildren::GetChild(sal_Int32 nIndex) const
+{
+ uno::Reference<XAccessible> xAccessible;
+
+ if (nIndex < mnParagraphs)
+ {
+ if (nIndex < static_cast<sal_Int32>(maMarks.size()))
+ {
+ ScAccNotes::iterator aEndItr = maMarks.end();
+ ScParaFound aParaFound(nIndex);
+ ScAccNotes::iterator aItr = std::find_if(maMarks.begin(), aEndItr, aParaFound);
+ if (aItr != aEndItr)
+ {
+ OSL_ENSURE((aItr->maNoteCell == maMarks[nIndex].maNoteCell) && (aItr->mbMarkNote == maMarks[nIndex].mbMarkNote), "wrong note found");
+ if (!aItr->mpTextHelper)
+ aItr->mpTextHelper = CreateTextHelper(maMarks[nIndex].maNoteText, maMarks[nIndex].maRect, maMarks[nIndex].maNoteCell, maMarks[nIndex].mbMarkNote, nIndex + mnOffset); // the marks are the first and every mark has only one paragraph
+ xAccessible = aItr->mpTextHelper->GetChild(aParaFound.mnIndex + aItr->mpTextHelper->GetStartIndex());
+ }
+ else
+ {
+ OSL_FAIL("wrong note found");
+ }
+ }
+ else
+ {
+ nIndex -= maMarks.size();
+ ScAccNotes::iterator aEndItr = maNotes.end();
+ ScParaFound aParaFound(nIndex);
+ ScAccNotes::iterator aItr = std::find_if(maNotes.begin(), aEndItr, aParaFound);
+ if (aEndItr != aItr)
+ {
+ if (!aItr->mpTextHelper)
+ aItr->mpTextHelper = CreateTextHelper(aItr->maNoteText, aItr->maRect, aItr->maNoteCell, aItr->mbMarkNote, (nIndex - aParaFound.mnIndex) + mnOffset + maMarks.size());
+ xAccessible = aItr->mpTextHelper->GetChild(aParaFound.mnIndex + aItr->mpTextHelper->GetStartIndex());
+ }
+ }
+ }
+
+ return xAccessible;
+}
+
+namespace {
+
+struct ScPointFound
+{
+ tools::Rectangle maPoint;
+ sal_Int32 mnParagraphs;
+ explicit ScPointFound(const Point& rPoint) : maPoint(rPoint, Size(0, 0)), mnParagraphs(0) {}
+ bool operator() (const ScAccNote& rNote)
+ {
+ bool bResult(false);
+ if (maPoint.Contains(rNote.maRect))
+ bResult = true;
+ else
+ mnParagraphs += rNote.mnParaCount;
+ return bResult;
+ }
+};
+
+}
+
+uno::Reference<XAccessible> ScNotesChildren::GetAt(const awt::Point& rPoint) const
+{
+ uno::Reference<XAccessible> xAccessible;
+
+ ScPointFound aPointFound(Point(rPoint.X, rPoint.Y));
+
+ ScAccNotes::iterator aEndItr = maMarks.end();
+ ScAccNotes::iterator aItr = std::find_if(maMarks.begin(), aEndItr, aPointFound);
+ if (aEndItr == aItr)
+ {
+ aEndItr = maNotes.end();
+ aItr = std::find_if(maNotes.begin(), aEndItr, aPointFound);
+ }
+ if (aEndItr != aItr)
+ {
+ if (!aItr->mpTextHelper)
+ aItr->mpTextHelper = CreateTextHelper(aItr->maNoteText, aItr->maRect, aItr->maNoteCell, aItr->mbMarkNote, aPointFound.mnParagraphs + mnOffset);
+ xAccessible = aItr->mpTextHelper->GetAt(rPoint);
+ }
+
+ return xAccessible;
+}
+
+sal_Int8 ScNotesChildren::CompareCell(const ScAddress& aCell1, const ScAddress& aCell2)
+{
+ OSL_ENSURE(aCell1.Tab() == aCell2.Tab(), "the notes should be on the same table");
+ sal_Int8 nResult(0);
+ if (aCell1 != aCell2)
+ {
+ if (aCell1.Row() == aCell2.Row())
+ nResult = (aCell1.Col() < aCell2.Col()) ? -1 : 1;
+ else
+ nResult = (aCell1.Row() < aCell2.Row()) ? -1 : 1;
+ }
+ return nResult;
+}
+
+void ScNotesChildren::CollectChildren(const ScAccNote& rNote, ScXAccVector& rVector)
+{
+ if (rNote.mpTextHelper)
+ for (sal_Int32 i = 0; i < rNote.mnParaCount; ++i)
+ rVector.push_back(rNote.mpTextHelper->GetChild(i + rNote.mpTextHelper->GetStartIndex()));
+}
+
+sal_Int32 ScNotesChildren::CheckChanges(const ScPreviewLocationData& rData,
+ const tools::Rectangle& rVisRect, bool bMark, ScAccNotes& rOldNotes,
+ ScAccNotes& rNewNotes, ScXAccVector& rOldParas, ScXAccVector& rNewParas)
+{
+ sal_Int32 nCount = rData.GetNoteCountInRange(rVisRect, bMark);
+
+ rNewNotes.reserve(nCount);
+
+ sal_Int32 nParagraphs(0);
+ ScDocument* pDoc = GetDocument();
+ if (pDoc)
+ {
+ ScAccNote aNote;
+ aNote.mbMarkNote = bMark;
+ if (bMark)
+ aNote.mnParaCount = 1;
+ ScAccNotes::iterator aItr = rOldNotes.begin();
+ ScAccNotes::iterator aEndItr = rOldNotes.end();
+ bool bAddNote(false);
+ for (sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex)
+ {
+ if (rData.GetNoteInRange(rVisRect, nIndex, bMark, aNote.maNoteCell, aNote.maRect))
+ {
+ if (bMark)
+ {
+ // Document not needed, because only the cell address, but not the tablename is needed
+ aNote.maNoteText = aNote.maNoteCell.Format(ScRefFlags::VALID);
+ }
+ else
+ {
+ if( ScPostIt* pNote = pDoc->GetNote( aNote.maNoteCell ) )
+ aNote.maNoteText = pNote->GetText();
+ }
+
+ sal_Int8 nCompare(-1); // if there are no more old children it is always a new one
+ if (aItr != aEndItr)
+ nCompare = CompareCell(aNote.maNoteCell, aItr->maNoteCell);
+ if (nCompare == 0)
+ {
+ if (aNote.maNoteText == aItr->maNoteText)
+ {
+ aNote.mpTextHelper = aItr->mpTextHelper;
+ if (aNote.maRect != aItr->maRect) // set new VisArea
+ {
+ aNote.mpTextHelper->SetOffset(aNote.maRect.TopLeft());
+ aNote.mpTextHelper->UpdateChildren();
+ //OSL_ENSURE(aItr->maRect.GetSize() == aNote.maRect.GetSize(), "size should be the same, because the text is not changed");
+ // could be changed, because only a part of the note is visible
+ }
+ }
+ else
+ {
+ aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset);
+ if (aNote.mpTextHelper)
+ aNote.mnParaCount = aNote.mpTextHelper->GetChildCount();
+ // collect removed children
+ CollectChildren(*aItr, rOldParas);
+ delete aItr->mpTextHelper;
+ aItr->mpTextHelper = nullptr;;
+ // collect new children
+ CollectChildren(aNote, rNewParas);
+ }
+ bAddNote = true;
+ // not necessary, because this branch should not be reached if it is the end
+ //if (aItr != aEndItr)
+ ++aItr;
+ }
+ else if (nCompare < 0)
+ {
+ aNote.mpTextHelper = CreateTextHelper(aNote.maNoteText, aNote.maRect, aNote.maNoteCell, aNote.mbMarkNote, nParagraphs + mnOffset);
+ if (aNote.mpTextHelper)
+ aNote.mnParaCount = aNote.mpTextHelper->GetChildCount();
+ // collect new children
+ CollectChildren(aNote, rNewParas);
+ bAddNote = true;
+ }
+ else
+ {
+ // collect removed children
+ CollectChildren(*aItr, rOldParas);
+ delete aItr->mpTextHelper;
+ aItr->mpTextHelper = nullptr;
+
+ // no note to add
+ // not necessary, because this branch should not be reached if it is the end
+ //if (aItr != aEndItr)
+ ++aItr;
+ }
+ if (bAddNote)
+ {
+ nParagraphs += aNote.mnParaCount;
+ rNewNotes.push_back(aNote);
+ bAddNote = false;
+ }
+ }
+ }
+ }
+ return nParagraphs;
+}
+
+namespace {
+
+struct ScChildGone
+{
+ ScAccessibleDocumentPagePreview* mpAccDoc;
+ explicit ScChildGone(ScAccessibleDocumentPagePreview* pAccDoc) : mpAccDoc(pAccDoc) {}
+ void operator() (const uno::Reference<XAccessible>& xAccessible) const
+ {
+ if (mpAccDoc)
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.Source = uno::Reference< XAccessibleContext >(mpAccDoc);
+ aEvent.OldValue <<= xAccessible;
+
+ mpAccDoc->CommitChange(aEvent); // gone child - event
+ }
+ }
+};
+
+struct ScChildNew
+{
+ ScAccessibleDocumentPagePreview* mpAccDoc;
+ explicit ScChildNew(ScAccessibleDocumentPagePreview* pAccDoc) : mpAccDoc(pAccDoc) {}
+ void operator() (const uno::Reference<XAccessible>& xAccessible) const
+ {
+ if (mpAccDoc)
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.Source = uno::Reference< XAccessibleContext >(mpAccDoc);
+ aEvent.NewValue <<= xAccessible;
+
+ mpAccDoc->CommitChange(aEvent); // new child - event
+ }
+ }
+};
+
+}
+
+void ScNotesChildren::DataChanged(const tools::Rectangle& rVisRect)
+{
+ if (!(mpViewShell && mpAccDoc))
+ return;
+
+ ScXAccVector aNewParas;
+ ScXAccVector aOldParas;
+ ScAccNotes aNewMarks;
+ mnParagraphs = CheckChanges(mpViewShell->GetLocationData(), rVisRect, true, maMarks, aNewMarks, aOldParas, aNewParas);
+ maMarks = aNewMarks;
+ ScAccNotes aNewNotes;
+ mnParagraphs += CheckChanges(mpViewShell->GetLocationData(), rVisRect, false, maNotes, aNewNotes, aOldParas, aNewParas);
+ maNotes = aNewNotes;
+
+ std::for_each(aOldParas.begin(), aOldParas.end(), ScChildGone(mpAccDoc));
+ std::for_each(aNewParas.begin(), aNewParas.end(), ScChildNew(mpAccDoc));
+}
+
+inline ScDocument* ScNotesChildren::GetDocument() const
+{
+ ScDocument* pDoc = nullptr;
+ if (mpViewShell)
+ pDoc = &mpViewShell->GetDocument();
+ return pDoc;
+}
+
+namespace {
+
+class ScIAccessibleViewForwarder : public ::accessibility::IAccessibleViewForwarder
+{
+public:
+ ScIAccessibleViewForwarder();
+ ScIAccessibleViewForwarder(ScPreviewShell* pViewShell,
+ ScAccessibleDocumentPagePreview* pAccDoc,
+ const MapMode& aMapMode);
+
+ ///===== IAccessibleViewForwarder ========================================
+
+ virtual tools::Rectangle GetVisibleArea() const override;
+ virtual Point LogicToPixel (const Point& rPoint) const override;
+ virtual Size LogicToPixel (const Size& rSize) const override;
+
+private:
+ ScPreviewShell* mpViewShell;
+ ScAccessibleDocumentPagePreview* mpAccDoc;
+ MapMode maMapMode;
+};
+
+}
+
+ScIAccessibleViewForwarder::ScIAccessibleViewForwarder()
+ : mpViewShell(nullptr), mpAccDoc(nullptr)
+{
+}
+
+ScIAccessibleViewForwarder::ScIAccessibleViewForwarder(ScPreviewShell* pViewShell,
+ ScAccessibleDocumentPagePreview* pAccDoc,
+ const MapMode& aMapMode)
+ : mpViewShell(pViewShell),
+ mpAccDoc(pAccDoc),
+ maMapMode(aMapMode)
+{
+}
+
+///===== IAccessibleViewForwarder ========================================
+
+tools::Rectangle ScIAccessibleViewForwarder::GetVisibleArea() const
+{
+ SolarMutexGuard aGuard;
+ tools::Rectangle aVisRect;
+ vcl::Window* pWin = mpViewShell->GetWindow();
+ if (pWin)
+ {
+ aVisRect.SetSize(pWin->GetOutputSizePixel());
+ aVisRect.SetPos(Point(0, 0));
+
+ aVisRect = pWin->PixelToLogic(aVisRect, maMapMode);
+ }
+
+ return aVisRect;
+}
+
+Point ScIAccessibleViewForwarder::LogicToPixel (const Point& rPoint) const
+{
+ SolarMutexGuard aGuard;
+ Point aPoint;
+ vcl::Window* pWin = mpViewShell->GetWindow();
+ if (pWin && mpAccDoc)
+ {
+ tools::Rectangle aRect(mpAccDoc->GetBoundingBoxOnScreen());
+ aPoint = pWin->LogicToPixel(rPoint, maMapMode) + aRect.TopLeft();
+ }
+
+ return aPoint;
+}
+
+Size ScIAccessibleViewForwarder::LogicToPixel (const Size& rSize) const
+{
+ SolarMutexGuard aGuard;
+ Size aSize;
+ vcl::Window* pWin = mpViewShell->GetWindow();
+ if (pWin)
+ aSize = pWin->LogicToPixel(rSize, maMapMode);
+ return aSize;
+}
+
+namespace {
+
+struct ScShapeChild
+{
+ ScShapeChild()
+ : mnRangeId(0)
+ {
+ }
+ ScShapeChild(ScShapeChild const &) = delete;
+ ScShapeChild(ScShapeChild &&) = default;
+ ~ScShapeChild();
+ ScShapeChild & operator =(ScShapeChild const &) = delete;
+ ScShapeChild & operator =(ScShapeChild && other) {
+ std::swap(mpAccShape, other.mpAccShape);
+ mxShape = std::move(other.mxShape);
+ mnRangeId = other.mnRangeId;
+ return *this;
+ }
+
+ mutable rtl::Reference< ::accessibility::AccessibleShape > mpAccShape;
+ css::uno::Reference< css::drawing::XShape > mxShape;
+ sal_Int32 mnRangeId;
+};
+
+}
+
+ScShapeChild::~ScShapeChild()
+{
+ if (mpAccShape.is())
+ {
+ mpAccShape->dispose();
+ }
+}
+
+namespace {
+
+struct ScShapeChildLess
+{
+ bool operator()(const ScShapeChild& rChild1, const ScShapeChild& rChild2) const
+ {
+ bool bResult(false);
+ if (rChild1.mxShape.is() && rChild2.mxShape.is())
+ bResult = (rChild1.mxShape.get() < rChild2.mxShape.get());
+ return bResult;
+ }
+};
+
+}
+
+typedef std::vector<ScShapeChild> ScShapeChildVec;
+
+namespace {
+
+struct ScShapeRange
+{
+ ScShapeRange() = default;
+ ScShapeRange(ScShapeRange const &) = delete;
+ ScShapeRange(ScShapeRange &&) = default;
+ ScShapeRange & operator =(ScShapeRange const &) = delete;
+ ScShapeRange & operator =(ScShapeRange &&) = default;
+
+ ScShapeChildVec maBackShapes;
+ ScShapeChildVec maForeShapes; // inclusive internal shapes
+ ScShapeChildVec maControls;
+ ScIAccessibleViewForwarder maViewForwarder;
+};
+
+}
+
+typedef std::vector<ScShapeRange> ScShapeRangeVec;
+
+class ScShapeChildren : public ::accessibility::IAccessibleParent
+{
+public:
+ ScShapeChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc);
+
+ ///===== IAccessibleParent ==============================================
+
+ virtual bool ReplaceChild (
+ ::accessibility::AccessibleShape* pCurrentChild,
+ const css::uno::Reference< css::drawing::XShape >& _rxShape,
+ const tools::Long _nIndex,
+ const ::accessibility::AccessibleShapeTreeInfo& _rShapeTreeInfo
+ ) override;
+
+ ///===== Internal ========================================================
+
+ void Init();
+
+ sal_Int32 GetBackShapeCount() const;
+ uno::Reference<XAccessible> GetBackShape(sal_Int32 nIndex) const;
+ sal_Int32 GetForeShapeCount() const;
+ uno::Reference<XAccessible> GetForeShape(sal_Int32 nIndex) const;
+ sal_Int32 GetControlCount() const;
+ uno::Reference<XAccessible> GetControl(sal_Int32 nIndex) const;
+ uno::Reference<XAccessible> GetForegroundShapeAt(const awt::Point& rPoint) const; // inclusive controls
+ uno::Reference<XAccessible> GetBackgroundShapeAt(const awt::Point& rPoint) const;
+
+ void DataChanged();
+ void VisAreaChanged() const;
+
+private:
+ ScAccessibleDocumentPagePreview* mpAccDoc;
+ ScPreviewShell* mpViewShell;
+ ScShapeRangeVec maShapeRanges;
+
+ void FindChanged(ScShapeChildVec& aOld, ScShapeChildVec& aNew) const;
+ void FindChanged(ScShapeRange& aOld, ScShapeRange& aNew) const;
+ ::accessibility::AccessibleShape* GetAccShape(const ScShapeChild& rShape) const;
+ ::accessibility::AccessibleShape* GetAccShape(const ScShapeChildVec& rShapes, sal_Int32 nIndex) const;
+ void FillShapes(const tools::Rectangle& aPixelPaintRect, const MapMode& aMapMode, sal_uInt8 nRangeId);
+
+// void AddShape(const uno::Reference<drawing::XShape>& xShape, SdrLayerID aLayerID);
+// void RemoveShape(const uno::Reference<drawing::XShape>& xShape, SdrLayerID aLayerID);
+ SdrPage* GetDrawPage() const;
+};
+
+ScShapeChildren::ScShapeChildren(ScPreviewShell* pViewShell, ScAccessibleDocumentPagePreview* pAccDoc)
+ :
+ mpAccDoc(pAccDoc),
+ mpViewShell(pViewShell),
+ maShapeRanges(SC_PREVIEW_MAXRANGES)
+{
+}
+
+void ScShapeChildren::FindChanged(ScShapeChildVec& rOld, ScShapeChildVec& rNew) const
+{
+ ScShapeChildVec::iterator aOldItr = rOld.begin();
+ ScShapeChildVec::iterator aOldEnd = rOld.end();
+ ScShapeChildVec::const_iterator aNewItr = rNew.begin();
+ ScShapeChildVec::const_iterator aNewEnd = rNew.end();
+ uno::Reference<XAccessible> xAcc;
+ while ((aNewItr != aNewEnd) && (aOldItr != aOldEnd))
+ {
+ if (aNewItr->mxShape.get() == aOldItr->mxShape.get())
+ {
+ ++aOldItr;
+ ++aNewItr;
+ }
+ else if (aNewItr->mxShape.get() < aOldItr->mxShape.get())
+ {
+ xAcc = GetAccShape(*aNewItr);
+ AccessibleEventObject aEvent;
+ aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc);
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.NewValue <<= xAcc;
+ mpAccDoc->CommitChange(aEvent);
+ ++aNewItr;
+ }
+ else
+ {
+ xAcc = GetAccShape(*aOldItr);
+ AccessibleEventObject aEvent;
+ aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc);
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.OldValue <<= xAcc;
+ mpAccDoc->CommitChange(aEvent);
+ ++aOldItr;
+ }
+ }
+ while (aOldItr != aOldEnd)
+ {
+ xAcc = GetAccShape(*aOldItr);
+ AccessibleEventObject aEvent;
+ aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc);
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.OldValue <<= xAcc;
+ mpAccDoc->CommitChange(aEvent);
+ ++aOldItr;
+ }
+ while (aNewItr != aNewEnd)
+ {
+ xAcc = GetAccShape(*aNewItr);
+ AccessibleEventObject aEvent;
+ aEvent.Source = uno::Reference<XAccessibleContext> (mpAccDoc);
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.NewValue <<= xAcc;
+ mpAccDoc->CommitChange(aEvent);
+ ++aNewItr;
+ }
+}
+
+void ScShapeChildren::FindChanged(ScShapeRange& rOld, ScShapeRange& rNew) const
+{
+ FindChanged(rOld.maBackShapes, rNew.maBackShapes);
+ FindChanged(rOld.maForeShapes, rNew.maForeShapes);
+ FindChanged(rOld.maControls, rNew.maControls);
+}
+
+void ScShapeChildren::DataChanged()
+{
+ ScShapeRangeVec aOldShapeRanges(std::move(maShapeRanges));
+ maShapeRanges.clear();
+ maShapeRanges.resize(SC_PREVIEW_MAXRANGES);
+ Init();
+ for (sal_Int32 i = 0; i < SC_PREVIEW_MAXRANGES; ++i)
+ {
+ FindChanged(aOldShapeRanges[i], maShapeRanges[i]);
+ }
+}
+
+namespace
+{
+ struct ScVisAreaChanged
+ {
+ void operator() (const ScShapeChild& rAccShapeData) const
+ {
+ if (rAccShapeData.mpAccShape.is())
+ {
+ rAccShapeData.mpAccShape->ViewForwarderChanged();
+ }
+ }
+ };
+}
+
+void ScShapeChildren::VisAreaChanged() const
+{
+ for (auto const& shape : maShapeRanges)
+ {
+ ScVisAreaChanged aVisAreaChanged;
+ std::for_each(shape.maBackShapes.begin(), shape.maBackShapes.end(), aVisAreaChanged);
+ std::for_each(shape.maControls.begin(), shape.maControls.end(), aVisAreaChanged);
+ std::for_each(shape.maForeShapes.begin(), shape.maForeShapes.end(), aVisAreaChanged);
+ }
+}
+
+ ///===== IAccessibleParent ==============================================
+
+bool ScShapeChildren::ReplaceChild (::accessibility::AccessibleShape* /* pCurrentChild */,
+ const css::uno::Reference< css::drawing::XShape >& /* _rxShape */,
+ const tools::Long /* _nIndex */, const ::accessibility::AccessibleShapeTreeInfo& /* _rShapeTreeInfo */)
+{
+ OSL_FAIL("should not be called in the page preview");
+ return false;
+}
+
+ ///===== Internal ========================================================
+
+void ScShapeChildren::Init()
+{
+ if(!mpViewShell)
+ return;
+
+ const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
+ MapMode aMapMode;
+ tools::Rectangle aPixelPaintRect;
+ sal_uInt8 nRangeId;
+ sal_uInt16 nCount(rData.GetDrawRanges());
+ for (sal_uInt16 i = 0; i < nCount; ++i)
+ {
+ rData.GetDrawRange(i, aPixelPaintRect, aMapMode, nRangeId);
+ FillShapes(aPixelPaintRect, aMapMode, nRangeId);
+ }
+}
+
+sal_Int32 ScShapeChildren::GetBackShapeCount() const
+{
+ sal_Int32 nCount(0);
+ for (auto const& shape : maShapeRanges)
+ nCount += shape.maBackShapes.size();
+ return nCount;
+}
+
+uno::Reference<XAccessible> ScShapeChildren::GetBackShape(sal_Int32 nIndex) const
+{
+ uno::Reference<XAccessible> xAccessible;
+ for (const auto& rShapeRange : maShapeRanges)
+ {
+ sal_Int32 nCount(rShapeRange.maBackShapes.size());
+ if(nIndex < nCount)
+ xAccessible = GetAccShape(rShapeRange.maBackShapes, nIndex);
+ nIndex -= nCount;
+ if (xAccessible.is())
+ break;
+ }
+
+ if (nIndex >= 0)
+ throw lang::IndexOutOfBoundsException();
+
+ return xAccessible;
+}
+
+sal_Int32 ScShapeChildren::GetForeShapeCount() const
+{
+ sal_Int32 nCount(0);
+ for (auto const& shape : maShapeRanges)
+ nCount += shape.maForeShapes.size();
+ return nCount;
+}
+
+uno::Reference<XAccessible> ScShapeChildren::GetForeShape(sal_Int32 nIndex) const
+{
+ uno::Reference<XAccessible> xAccessible;
+ for (const auto& rShapeRange : maShapeRanges)
+ {
+ sal_Int32 nCount(rShapeRange.maForeShapes.size());
+ if(nIndex < nCount)
+ xAccessible = GetAccShape(rShapeRange.maForeShapes, nIndex);
+ nIndex -= nCount;
+ if (xAccessible.is())
+ break;
+ }
+
+ if (nIndex >= 0)
+ throw lang::IndexOutOfBoundsException();
+
+ return xAccessible;
+}
+
+sal_Int32 ScShapeChildren::GetControlCount() const
+{
+ sal_Int32 nCount(0);
+ for (auto const& shape : maShapeRanges)
+ nCount += shape.maControls.size();
+ return nCount;
+}
+
+uno::Reference<XAccessible> ScShapeChildren::GetControl(sal_Int32 nIndex) const
+{
+ uno::Reference<XAccessible> xAccessible;
+ for (const auto& rShapeRange : maShapeRanges)
+ {
+ sal_Int32 nCount(rShapeRange.maControls.size());
+ if(nIndex < nCount)
+ xAccessible = GetAccShape(rShapeRange.maControls, nIndex);
+ nIndex -= nCount;
+ if (xAccessible.is())
+ break;
+ }
+
+ if (nIndex >= 0)
+ throw lang::IndexOutOfBoundsException();
+
+ return xAccessible;
+}
+
+namespace {
+
+struct ScShapePointFound
+{
+ Point maPoint;
+ explicit ScShapePointFound(const awt::Point& rPoint) : maPoint(VCLPoint(rPoint)) {}
+ bool operator() (const ScShapeChild& rShape)
+ {
+ bool bResult(false);
+ if (VCLRectangle(rShape.mpAccShape->getBounds()).Contains(maPoint))
+ bResult = true;
+ return bResult;
+ }
+};
+
+}
+
+uno::Reference<XAccessible> ScShapeChildren::GetForegroundShapeAt(const awt::Point& rPoint) const //inclusive Controls
+{
+ uno::Reference<XAccessible> xAcc;
+
+ for(const auto& rShapeRange : maShapeRanges)
+ {
+ ScShapeChildVec::const_iterator aFindItr = std::find_if(rShapeRange.maForeShapes.begin(), rShapeRange.maForeShapes.end(), ScShapePointFound(rPoint));
+ if (aFindItr != rShapeRange.maForeShapes.end())
+ xAcc = GetAccShape(*aFindItr);
+ else
+ {
+ ScShapeChildVec::const_iterator aCtrlItr = std::find_if(rShapeRange.maControls.begin(), rShapeRange.maControls.end(), ScShapePointFound(rPoint));
+ if (aCtrlItr != rShapeRange.maControls.end())
+ xAcc = GetAccShape(*aCtrlItr);
+ }
+
+ if (xAcc.is())
+ break;
+ }
+
+ return xAcc;
+}
+
+uno::Reference<XAccessible> ScShapeChildren::GetBackgroundShapeAt(const awt::Point& rPoint) const
+{
+ uno::Reference<XAccessible> xAcc;
+
+ for(const auto& rShapeRange : maShapeRanges)
+ {
+ ScShapeChildVec::const_iterator aFindItr = std::find_if(rShapeRange.maBackShapes.begin(), rShapeRange.maBackShapes.end(), ScShapePointFound(rPoint));
+ if (aFindItr != rShapeRange.maBackShapes.end())
+ xAcc = GetAccShape(*aFindItr);
+ if (xAcc.is())
+ break;
+ }
+
+ return xAcc;
+}
+
+::accessibility::AccessibleShape* ScShapeChildren::GetAccShape(const ScShapeChild& rShape) const
+{
+ if (!rShape.mpAccShape.is())
+ {
+ ::accessibility::ShapeTypeHandler& rShapeHandler = ::accessibility::ShapeTypeHandler::Instance();
+ ::accessibility::AccessibleShapeInfo aShapeInfo(rShape.mxShape, mpAccDoc);
+
+ if (mpViewShell)
+ {
+ ::accessibility::AccessibleShapeTreeInfo aShapeTreeInfo;
+ aShapeTreeInfo.SetSdrView(mpViewShell->GetPreview()->GetDrawView());
+ aShapeTreeInfo.SetController(nullptr);
+ aShapeTreeInfo.SetWindow(mpViewShell->GetWindow());
+ aShapeTreeInfo.SetViewForwarder(&(maShapeRanges[rShape.mnRangeId].maViewForwarder));
+ rShape.mpAccShape = rShapeHandler.CreateAccessibleObject(aShapeInfo, aShapeTreeInfo);
+ if (rShape.mpAccShape.is())
+ {
+ rShape.mpAccShape->Init();
+ }
+ }
+ }
+ return rShape.mpAccShape.get();
+}
+
+::accessibility::AccessibleShape* ScShapeChildren::GetAccShape(const ScShapeChildVec& rShapes, sal_Int32 nIndex) const
+{
+ return GetAccShape(rShapes[nIndex]);
+}
+
+void ScShapeChildren::FillShapes(const tools::Rectangle& aPixelPaintRect, const MapMode& aMapMode, sal_uInt8 nRangeId)
+{
+ OSL_ENSURE(nRangeId < maShapeRanges.size(), "this is not a valid range for draw objects");
+ SdrPage* pPage = GetDrawPage();
+ vcl::Window* pWin = mpViewShell->GetWindow();
+ if (!(pPage && pWin))
+ return;
+
+ bool bForeAdded(false);
+ bool bBackAdded(false);
+ bool bControlAdded(false);
+ tools::Rectangle aClippedPixelPaintRect(aPixelPaintRect);
+ if (mpAccDoc)
+ {
+ tools::Rectangle aRect2(Point(0,0), mpAccDoc->GetBoundingBoxOnScreen().GetSize());
+ aClippedPixelPaintRect = aPixelPaintRect.GetIntersection(aRect2);
+ }
+ ScIAccessibleViewForwarder aViewForwarder(mpViewShell, mpAccDoc, aMapMode);
+ maShapeRanges[nRangeId].maViewForwarder = aViewForwarder;
+ const size_t nCount(pPage->GetObjCount());
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ SdrObject* pObj = pPage->GetObj(i);
+ if (pObj)
+ {
+ uno::Reference< drawing::XShape > xShape(pObj->getUnoShape(), uno::UNO_QUERY);
+ if (xShape.is())
+ {
+ tools::Rectangle aRect(pWin->LogicToPixel(VCLPoint(xShape->getPosition()), aMapMode), pWin->LogicToPixel(VCLSize(xShape->getSize()), aMapMode));
+ if(!aClippedPixelPaintRect.GetIntersection(aRect).IsEmpty())
+ {
+ ScShapeChild aShape;
+ aShape.mxShape = xShape;
+ aShape.mnRangeId = nRangeId;
+ if (pObj->GetLayer().anyOf(SC_LAYER_INTERN, SC_LAYER_FRONT))
+ {
+ maShapeRanges[nRangeId].maForeShapes.push_back(std::move(aShape));
+ bForeAdded = true;
+ }
+ else if (pObj->GetLayer() == SC_LAYER_BACK)
+ {
+ maShapeRanges[nRangeId].maBackShapes.push_back(std::move(aShape));
+ bBackAdded = true;
+ }
+ else if (pObj->GetLayer() == SC_LAYER_CONTROLS)
+ {
+ maShapeRanges[nRangeId].maControls.push_back(std::move(aShape));
+ bControlAdded = true;
+ }
+ else
+ {
+ OSL_FAIL("I don't know this layer.");
+ }
+ }
+ }
+ }
+ }
+ if (bForeAdded)
+ std::sort(maShapeRanges[nRangeId].maForeShapes.begin(), maShapeRanges[nRangeId].maForeShapes.end(),ScShapeChildLess());
+ if (bBackAdded)
+ std::sort(maShapeRanges[nRangeId].maBackShapes.begin(), maShapeRanges[nRangeId].maBackShapes.end(),ScShapeChildLess());
+ if (bControlAdded)
+ std::sort(maShapeRanges[nRangeId].maControls.begin(), maShapeRanges[nRangeId].maControls.end(),ScShapeChildLess());
+}
+
+SdrPage* ScShapeChildren::GetDrawPage() const
+{
+ SCTAB nTab( mpViewShell->GetLocationData().GetPrintTab() );
+ SdrPage* pDrawPage = nullptr;
+ ScDocument& rDoc = mpViewShell->GetDocument();
+ if (rDoc.GetDrawLayer())
+ {
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab))
+ pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab)));
+ }
+ return pDrawPage;
+}
+
+namespace {
+
+struct ScPagePreviewCountData
+{
+ // order is background shapes, header, table or notes, footer, foreground shapes, controls
+
+ tools::Rectangle aVisRect;
+ tools::Long nBackShapes;
+ tools::Long nHeaders;
+ tools::Long nTables;
+ tools::Long nNoteParagraphs;
+ tools::Long nFooters;
+ tools::Long nForeShapes;
+ tools::Long nControls;
+
+ ScPagePreviewCountData( const ScPreviewLocationData& rData, const vcl::Window* pSizeWindow,
+ const ScNotesChildren* pNotesChildren, const ScShapeChildren* pShapeChildren );
+
+ tools::Long GetTotal() const
+ {
+ return nBackShapes + nHeaders + nTables + nNoteParagraphs + nFooters + nForeShapes + nControls;
+ }
+};
+
+}
+
+ScPagePreviewCountData::ScPagePreviewCountData( const ScPreviewLocationData& rData,
+ const vcl::Window* pSizeWindow, const ScNotesChildren* pNotesChildren,
+ const ScShapeChildren* pShapeChildren) :
+ nBackShapes( 0 ),
+ nHeaders( 0 ),
+ nTables( 0 ),
+ nNoteParagraphs( 0 ),
+ nFooters( 0 ),
+ nForeShapes( 0 ),
+ nControls( 0 )
+{
+ Size aOutputSize;
+ if ( pSizeWindow )
+ aOutputSize = pSizeWindow->GetOutputSizePixel();
+ aVisRect = tools::Rectangle( Point(), aOutputSize );
+
+ tools::Rectangle aObjRect;
+
+ if ( rData.GetHeaderPosition( aObjRect ) && aObjRect.Overlaps( aVisRect ) )
+ nHeaders = 1;
+
+ if ( rData.GetFooterPosition( aObjRect ) && aObjRect.Overlaps( aVisRect ) )
+ nFooters = 1;
+
+ if ( rData.HasCellsInRange( aVisRect ) )
+ nTables = 1;
+
+ //! shapes...
+ nBackShapes = pShapeChildren->GetBackShapeCount();
+ nForeShapes = pShapeChildren->GetForeShapeCount();
+ nControls = pShapeChildren->GetControlCount();
+
+ // there are only notes if there is no table
+ if (nTables == 0)
+ nNoteParagraphs = pNotesChildren->GetChildrenCount();
+}
+
+//===== internal ========================================================
+
+ScAccessibleDocumentPagePreview::ScAccessibleDocumentPagePreview(
+ const uno::Reference<XAccessible>& rxParent, ScPreviewShell* pViewShell ) :
+ ScAccessibleDocumentBase(rxParent),
+ mpViewShell(pViewShell)
+{
+ if (pViewShell)
+ pViewShell->AddAccessibilityObject(*this);
+
+}
+
+ScAccessibleDocumentPagePreview::~ScAccessibleDocumentPagePreview()
+{
+ if (!ScAccessibleDocumentBase::IsDefunc() && !rBHelper.bInDispose)
+ {
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+ // call dispose to inform object which have a weak reference to this object
+ dispose();
+ }
+}
+
+void SAL_CALL ScAccessibleDocumentPagePreview::disposing()
+{
+ SolarMutexGuard aGuard;
+ mpTable.clear();
+ mpHeader.clear();
+ mpFooter.clear();
+
+ if (mpViewShell)
+ {
+ mpViewShell->RemoveAccessibilityObject(*this);
+ mpViewShell = nullptr;
+ }
+
+ // no need to Dispose the AccessibleTextHelper,
+ // as long as mpNotesChildren are destructed here
+ mpNotesChildren.reset();
+
+ mpShapeChildren.reset();
+
+ ScAccessibleDocumentBase::disposing();
+}
+
+//===== SfxListener =====================================================
+
+void ScAccessibleDocumentPagePreview::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScAccWinFocusLostHint*>(&rHint) )
+ {
+ CommitFocusLost();
+ }
+ else if ( dynamic_cast<const ScAccWinFocusGotHint*>(&rHint) )
+ {
+ CommitFocusGained();
+ }
+ else
+ {
+ // only notify if child exist, otherwise it is not necessary
+ if (rHint.GetId() == SfxHintId::ScDataChanged)
+ {
+ if (mpTable.is()) // if there is no table there is nothing to notify, because no one recognizes the change
+ {
+ {
+ uno::Reference<XAccessible> xAcc = mpTable;
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ aEvent.OldValue <<= xAcc;
+ CommitChange(aEvent);
+ }
+
+ mpTable->dispose();
+ mpTable.clear();
+ }
+
+ Size aOutputSize;
+ vcl::Window* pSizeWindow = mpViewShell->GetWindow();
+ if ( pSizeWindow )
+ aOutputSize = pSizeWindow->GetOutputSizePixel();
+ tools::Rectangle aVisRect( Point(), aOutputSize );
+ GetNotesChildren()->DataChanged(aVisRect);
+
+ GetShapeChildren()->DataChanged();
+
+ const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
+ ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
+
+ if (aCount.nTables > 0)
+ {
+ //! order is background shapes, header, table or notes, footer, foreground shapes, controls
+ sal_Int32 nIndex (aCount.nBackShapes + aCount.nHeaders);
+
+ mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex );
+ mpTable->Init();
+
+ {
+ uno::Reference<XAccessible> xAcc = mpTable;
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ aEvent.NewValue <<= xAcc;
+ CommitChange(aEvent);
+ }
+ }
+ }
+ else if (rHint.GetId() == SfxHintId::ScAccVisAreaChanged)
+ {
+ Size aOutputSize;
+ vcl::Window* pSizeWindow = mpViewShell->GetWindow();
+ if ( pSizeWindow )
+ aOutputSize = pSizeWindow->GetOutputSizePixel();
+ tools::Rectangle aVisRect( Point(), aOutputSize );
+ GetNotesChildren()->DataChanged(aVisRect);
+
+ GetShapeChildren()->VisAreaChanged();
+
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ CommitChange(aEvent);
+ }
+ }
+ ScAccessibleDocumentBase::Notify(rBC, rHint);
+}
+
+//===== XAccessibleComponent ============================================
+
+uno::Reference< XAccessible > SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleAtPoint( const awt::Point& rPoint )
+{
+ uno::Reference<XAccessible> xAccessible;
+ if (containsPoint(rPoint))
+ {
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if ( mpViewShell )
+ {
+ xAccessible = GetShapeChildren()->GetForegroundShapeAt(rPoint);
+ if (!xAccessible.is())
+ {
+ const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
+ ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
+
+ if ( !mpTable.is() && (aCount.nTables > 0) )
+ {
+ //! order is background shapes, header, table or notes, footer, foreground shapes, controls
+ sal_Int32 nIndex (aCount.nBackShapes + aCount.nHeaders);
+
+ mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex );
+ mpTable->Init();
+ }
+ if (mpTable.is() && VCLRectangle(mpTable->getBounds()).Contains(VCLPoint(rPoint)))
+ xAccessible = mpTable.get();
+ }
+ if (!xAccessible.is())
+ xAccessible = GetNotesChildren()->GetAt(rPoint);
+ if (!xAccessible.is())
+ {
+ if (!mpHeader.is() || !mpFooter.is())
+ {
+ const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
+ ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
+
+ if (!mpHeader.is())
+ {
+ mpHeader = new ScAccessiblePageHeader( this, mpViewShell, true, aCount.nBackShapes + aCount.nHeaders - 1);
+ }
+ if (!mpFooter.is())
+ {
+ mpFooter = new ScAccessiblePageHeader( this, mpViewShell, false, aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters - 1 );
+ }
+ }
+
+ Point aPoint(VCLPoint(rPoint));
+
+ if (VCLRectangle(mpHeader->getBounds()).Contains(aPoint))
+ xAccessible = mpHeader.get();
+ else if (VCLRectangle(mpFooter->getBounds()).Contains(aPoint))
+ xAccessible = mpFooter.get();
+ }
+ if (!xAccessible.is())
+ xAccessible = GetShapeChildren()->GetBackgroundShapeAt(rPoint);
+ }
+ }
+
+ return xAccessible;
+}
+
+void SAL_CALL ScAccessibleDocumentPagePreview::grabFocus()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
+ if (xAccessibleComponent.is())
+ {
+ // just grab the focus for the window
+ xAccessibleComponent->grabFocus();
+ }
+ }
+}
+
+//===== XAccessibleContext ==============================================
+
+sal_Int32 SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ tools::Long nRet = 0;
+ if ( mpViewShell )
+ {
+ ScPagePreviewCountData aCount( mpViewShell->GetLocationData(), mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
+ nRet = aCount.GetTotal();
+ }
+
+ return nRet;
+}
+
+uno::Reference<XAccessible> SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleChild(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ uno::Reference<XAccessible> xAccessible;
+
+ if ( mpViewShell )
+ {
+ const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
+ ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
+
+ if ( nIndex < aCount.nBackShapes )
+ {
+ xAccessible = GetShapeChildren()->GetBackShape(nIndex);
+ }
+ else if ( nIndex < aCount.nBackShapes + aCount.nHeaders )
+ {
+ if ( !mpHeader.is() )
+ {
+ mpHeader = new ScAccessiblePageHeader( this, mpViewShell, true, nIndex );
+ }
+
+ xAccessible = mpHeader.get();
+ }
+ else if ( nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nTables )
+ {
+ if ( !mpTable.is() )
+ {
+ mpTable = new ScAccessiblePreviewTable( this, mpViewShell, nIndex );
+ mpTable->Init();
+ }
+ xAccessible = mpTable.get();
+ }
+ else if ( nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nNoteParagraphs )
+ {
+ xAccessible = GetNotesChildren()->GetChild(nIndex - aCount.nBackShapes - aCount.nHeaders);
+ }
+ else if ( nIndex < aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters )
+ {
+ if ( !mpFooter.is() )
+ {
+ mpFooter = new ScAccessiblePageHeader( this, mpViewShell, false, nIndex );
+ }
+ xAccessible = mpFooter.get();
+ }
+ else
+ {
+ sal_Int32 nIdx(nIndex - (aCount.nBackShapes + aCount.nHeaders + aCount.nTables + aCount.nNoteParagraphs + aCount.nFooters));
+ if (nIdx < aCount.nForeShapes)
+ xAccessible = GetShapeChildren()->GetForeShape(nIdx);
+ else
+ xAccessible = GetShapeChildren()->GetControl(nIdx - aCount.nForeShapes);
+ }
+ }
+
+ if ( !xAccessible.is() )
+ throw lang::IndexOutOfBoundsException();
+
+ return xAccessible;
+}
+
+ /// Return the set of current states.
+uno::Reference<XAccessibleStateSet> SAL_CALL ScAccessibleDocumentPagePreview::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<XAccessibleStateSet> xParentStates;
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
+ xParentStates = xParentContext->getAccessibleStateSet();
+ }
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSet = new utl::AccessibleStateSetHelper();
+ if (IsDefunc(xParentStates))
+ pStateSet->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ // never editable
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::OPAQUE);
+ if (isShowing())
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ if (isVisible())
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ }
+ return pStateSet;
+}
+
+ //===== XServiceInfo ====================================================
+
+OUString SAL_CALL ScAccessibleDocumentPagePreview::getImplementationName()
+{
+ return "ScAccessibleDocumentPagePreview";
+}
+
+uno::Sequence< OUString> SAL_CALL ScAccessibleDocumentPagePreview::getSupportedServiceNames()
+{
+ const css::uno::Sequence<OUString> vals { "com.sun.star.AccessibleSpreadsheetPageView" };
+ return comphelper::concatSequences(ScAccessibleContextBase::getSupportedServiceNames(), vals);
+}
+
+//===== XTypeProvider =======================================================
+
+uno::Sequence<sal_Int8> SAL_CALL
+ ScAccessibleDocumentPagePreview::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+//===== internal ========================================================
+
+OUString ScAccessibleDocumentPagePreview::createAccessibleDescription()
+{
+ return STR_ACC_PREVIEWDOC_DESCR;
+}
+
+OUString ScAccessibleDocumentPagePreview::createAccessibleName()
+{
+ OUString sName = ScResId(STR_ACC_PREVIEWDOC_NAME);
+ return sName;
+}
+
+tools::Rectangle ScAccessibleDocumentPagePreview::GetBoundingBoxOnScreen() const
+{
+ tools::Rectangle aRect;
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if (pWindow)
+ aRect = pWindow->GetWindowExtentsRelative(nullptr);
+ }
+ return aRect;
+}
+
+tools::Rectangle ScAccessibleDocumentPagePreview::GetBoundingBox() const
+{
+ tools::Rectangle aRect;
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if (pWindow)
+ aRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow());
+ }
+ return aRect;
+}
+
+bool ScAccessibleDocumentPagePreview::IsDefunc(
+ const uno::Reference<XAccessibleStateSet>& rxParentStates)
+{
+ return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() ||
+ (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
+}
+
+ScNotesChildren* ScAccessibleDocumentPagePreview::GetNotesChildren()
+{
+ if (!mpNotesChildren && mpViewShell)
+ {
+ mpNotesChildren.reset( new ScNotesChildren(mpViewShell, this) );
+
+ const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
+ ScPagePreviewCountData aCount( rData, mpViewShell->GetWindow(), GetNotesChildren(), GetShapeChildren() );
+
+ //! order is background shapes, header, table or notes, footer, foreground shapes, controls
+ mpNotesChildren->Init(aCount.aVisRect, aCount.nBackShapes + aCount.nHeaders);
+ }
+ return mpNotesChildren.get();
+}
+
+ScShapeChildren* ScAccessibleDocumentPagePreview::GetShapeChildren()
+{
+ if (!mpShapeChildren && mpViewShell)
+ {
+ mpShapeChildren.reset( new ScShapeChildren(mpViewShell, this) );
+ mpShapeChildren->Init();
+ }
+
+ return mpShapeChildren.get();
+}
+
+OUString ScAccessibleDocumentPagePreview::getAccessibleName()
+{
+ SolarMutexGuard g;
+
+ OUString aName = ScResId(STR_ACC_DOC_SPREADSHEET);
+ ScDocument& rScDoc = mpViewShell->GetDocument();
+
+ SfxObjectShell* pObjSh = rScDoc.GetDocumentShell();
+ if (!pObjSh)
+ return aName;
+
+ OUString aFileName;
+ SfxMedium* pMed = pObjSh->GetMedium();
+ if (pMed)
+ aFileName = pMed->GetName();
+
+ if (aFileName.isEmpty())
+ aFileName = pObjSh->GetTitle(SFX_TITLE_APINAME);
+
+ if (!aFileName.isEmpty())
+ {
+ aName = aFileName + " - " + aName + ScResId(STR_ACC_DOC_PREVIEW_SUFFIX);
+
+ }
+
+ return aName;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessibleEditObject.cxx b/sc/source/ui/Accessibility/AccessibleEditObject.cxx
new file mode 100644
index 000000000..8412b313c
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleEditObject.cxx
@@ -0,0 +1,604 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <AccessibleEditObject.hxx>
+#include <AccessibleText.hxx>
+#include <editsrc.hxx>
+#include <scmod.hxx>
+#include <inputhdl.hxx>
+#include <inputwin.hxx>
+
+#include <unotools/accessiblestatesethelper.hxx>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <svx/AccessibleTextHelper.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editeng.hxx>
+#include <svx/svdmodel.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <sfx2/objsh.hxx>
+#include <cppuhelper/queryinterface.hxx>
+
+#include <unonames.hxx>
+#include <document.hxx>
+#include <AccessibleDocument.hxx>
+#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+
+using ::com::sun::star::lang::IndexOutOfBoundsException;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+//===== internal ============================================================
+
+ScAccessibleEditObject::ScAccessibleEditObject(
+ const uno::Reference<XAccessible>& rxParent,
+ EditView* pEditView, vcl::Window* pWin, const OUString& rName,
+ const OUString& rDescription, EditObjectType eObjectType)
+ : ScAccessibleContextBase(rxParent, AccessibleRole::TEXT_FRAME)
+ , mpEditView(pEditView)
+ , mpWindow(pWin)
+ , mpTextWnd(nullptr)
+ , meObjectType(eObjectType)
+ , mbHasFocus(false)
+ , m_pScDoc(nullptr)
+{
+ InitAcc(rxParent, pEditView, rName, rDescription);
+}
+
+ScAccessibleEditObject::ScAccessibleEditObject(EditObjectType eObjectType)
+ : ScAccessibleContextBase(nullptr, AccessibleRole::TEXT_FRAME)
+ , mpEditView(nullptr)
+ , mpWindow(nullptr)
+ , mpTextWnd(nullptr)
+ , meObjectType(eObjectType)
+ , mbHasFocus(false)
+ , m_pScDoc(nullptr)
+{
+}
+
+void ScAccessibleEditObject::InitAcc(
+ const uno::Reference<XAccessible>& rxParent,
+ EditView* pEditView,
+ const OUString& rName,
+ const OUString& rDescription)
+{
+ SetParent(rxParent);
+ mpEditView = pEditView;
+
+ CreateTextHelper();
+ SetName(rName);
+ SetDescription(rDescription);
+ if( meObjectType == CellInEditMode)
+ {
+ const ScAccessibleDocument *pAccDoc = static_cast<ScAccessibleDocument*>(rxParent.get());
+ if (pAccDoc)
+ {
+ m_pScDoc = pAccDoc->GetDocument();
+ m_curCellAddress =pAccDoc->GetCurCellAddress();
+ }
+ }
+}
+
+ScAccessibleEditObject::~ScAccessibleEditObject()
+{
+ if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
+ {
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+ // call dispose to inform object which have a weak reference to this object
+ dispose();
+ }
+}
+
+void SAL_CALL ScAccessibleEditObject::disposing()
+{
+ SolarMutexGuard aGuard;
+ mpTextHelper.reset();
+
+ ScAccessibleContextBase::disposing();
+}
+
+void ScAccessibleEditObject::LostFocus()
+{
+ mbHasFocus = false;
+ if (mpTextHelper)
+ mpTextHelper->SetFocus(false);
+ CommitFocusLost();
+}
+
+void ScAccessibleEditObject::GotFocus()
+{
+ mbHasFocus = true;
+ CommitFocusGained();
+ if (mpTextHelper)
+ mpTextHelper->SetFocus();
+}
+
+//===== XInterface ==========================================================
+
+css::uno::Any SAL_CALL
+ ScAccessibleEditObject::queryInterface (const css::uno::Type & rType)
+{
+ css::uno::Any aReturn = ScAccessibleContextBase::queryInterface (rType);
+ if ( ! aReturn.hasValue())
+ aReturn = ::cppu::queryInterface (rType,
+ static_cast< css::accessibility::XAccessibleSelection* >(this)
+ );
+ return aReturn;
+}
+void SAL_CALL
+ ScAccessibleEditObject::acquire()
+ noexcept
+{
+ ScAccessibleContextBase::acquire ();
+}
+void SAL_CALL
+ ScAccessibleEditObject::release()
+ noexcept
+{
+ ScAccessibleContextBase::release ();
+}
+ //===== XAccessibleComponent ============================================
+
+uno::Reference< XAccessible > SAL_CALL ScAccessibleEditObject::getAccessibleAtPoint(
+ const awt::Point& rPoint )
+{
+ uno::Reference<XAccessible> xRet;
+ if (containsPoint(rPoint))
+ {
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ CreateTextHelper();
+
+ xRet = mpTextHelper->GetAt(rPoint);
+ }
+
+ return xRet;
+}
+
+tools::Rectangle ScAccessibleEditObject::GetBoundingBoxOnScreen() const
+{
+ tools::Rectangle aScreenBounds;
+
+ if ( mpWindow )
+ {
+ if ( meObjectType == CellInEditMode )
+ {
+ if ( mpEditView && mpEditView->GetEditEngine() )
+ {
+ MapMode aMapMode( mpEditView->GetEditEngine()->GetRefMapMode() );
+ aScreenBounds = mpWindow->LogicToPixel( mpEditView->GetOutputArea(), aMapMode );
+ Point aCellLoc = aScreenBounds.TopLeft();
+ tools::Rectangle aWindowRect = mpWindow->GetWindowExtentsRelative( nullptr );
+ Point aWindowLoc = aWindowRect.TopLeft();
+ Point aPos( aCellLoc.getX() + aWindowLoc.getX(), aCellLoc.getY() + aWindowLoc.getY() );
+ aScreenBounds.SetPos( aPos );
+ }
+ }
+ else
+ {
+ aScreenBounds = mpWindow->GetWindowExtentsRelative( nullptr );
+ }
+ }
+
+ return aScreenBounds;
+}
+
+tools::Rectangle ScAccessibleEditObject::GetBoundingBox() const
+{
+ tools::Rectangle aBounds( GetBoundingBoxOnScreen() );
+
+ if ( mpWindow )
+ {
+ uno::Reference< XAccessible > xThis( mpWindow->GetAccessible() );
+ if ( xThis.is() )
+ {
+ uno::Reference< XAccessibleContext > xContext( xThis->getAccessibleContext() );
+ if ( xContext.is() )
+ {
+ uno::Reference< XAccessible > xParent( xContext->getAccessibleParent() );
+ if ( xParent.is() )
+ {
+ uno::Reference< XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), uno::UNO_QUERY );
+ if ( xParentComponent.is() )
+ {
+ Point aScreenLoc = aBounds.TopLeft();
+ awt::Point aParentScreenLoc = xParentComponent->getLocationOnScreen();
+ Point aPos( aScreenLoc.getX() - aParentScreenLoc.X, aScreenLoc.getY() - aParentScreenLoc.Y );
+ aBounds.SetPos( aPos );
+ }
+ }
+ }
+ }
+ }
+
+ return aBounds;
+}
+
+ //===== XAccessibleContext ==============================================
+
+sal_Int32 SAL_CALL
+ ScAccessibleEditObject::getAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ CreateTextHelper();
+ return mpTextHelper->GetChildCount();
+}
+
+uno::Reference< XAccessible > SAL_CALL
+ ScAccessibleEditObject::getAccessibleChild(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ CreateTextHelper();
+ return mpTextHelper->GetChild(nIndex);
+}
+
+uno::Reference<XAccessibleStateSet> SAL_CALL
+ ScAccessibleEditObject::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<XAccessibleStateSet> xParentStates;
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
+ xParentStates = xParentContext->getAccessibleStateSet();
+ }
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSet = new utl::AccessibleStateSetHelper();
+ if (IsDefunc(xParentStates))
+ pStateSet->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ // all states are const, because this object exists only in one state
+ pStateSet->AddState(AccessibleStateType::EDITABLE);
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::SENSITIVE);
+ pStateSet->AddState(AccessibleStateType::MULTI_LINE);
+ pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE);
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ }
+ return pStateSet;
+}
+
+OUString
+ ScAccessibleEditObject::createAccessibleDescription()
+{
+// OSL_FAIL("Should never be called, because is set in the constructor.")
+ return OUString();
+}
+
+OUString
+ ScAccessibleEditObject::createAccessibleName()
+{
+ OSL_FAIL("Should never be called, because is set in the constructor.");
+ return OUString();
+}
+
+ ///===== XAccessibleEventBroadcaster =====================================
+
+void SAL_CALL
+ ScAccessibleEditObject::addAccessibleEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
+{
+ CreateTextHelper();
+
+ mpTextHelper->AddEventListener(xListener);
+
+ ScAccessibleContextBase::addAccessibleEventListener(xListener);
+}
+
+void SAL_CALL
+ ScAccessibleEditObject::removeAccessibleEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
+{
+ CreateTextHelper();
+
+ mpTextHelper->RemoveEventListener(xListener);
+
+ ScAccessibleContextBase::removeAccessibleEventListener(xListener);
+}
+
+ //===== XServiceInfo ====================================================
+
+OUString SAL_CALL ScAccessibleEditObject::getImplementationName()
+{
+ return "ScAccessibleEditObject";
+}
+
+//===== XTypeProvider =======================================================
+
+uno::Sequence<sal_Int8> SAL_CALL
+ ScAccessibleEditObject::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+ //==== internal =========================================================
+
+bool ScAccessibleEditObject::IsDefunc(
+ const uno::Reference<XAccessibleStateSet>& rxParentStates)
+{
+ return ScAccessibleContextBase::IsDefunc() || !getAccessibleParent().is() ||
+ (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
+}
+
+OutputDevice* ScAccessibleEditObject::GetOutputDeviceForView()
+{
+ return mpWindow->GetOutDev();
+}
+
+void ScAccessibleEditObject::CreateTextHelper()
+{
+ if (mpTextHelper)
+ return;
+
+ ::std::unique_ptr < ScAccessibleTextData > pAccessibleTextData;
+ if (meObjectType == CellInEditMode || meObjectType == EditControl)
+ {
+ pAccessibleTextData.reset
+ (new ScAccessibleEditObjectTextData(mpEditView, GetOutputDeviceForView()));
+ }
+ else
+ {
+ pAccessibleTextData.reset
+ (new ScAccessibleEditLineTextData(nullptr, GetOutputDeviceForView(), mpTextWnd));
+ }
+
+ std::unique_ptr<ScAccessibilityEditSource> pEditSrc =
+ std::make_unique<ScAccessibilityEditSource>(std::move(pAccessibleTextData));
+
+ mpTextHelper = std::make_unique<::accessibility::AccessibleTextHelper>(std::move(pEditSrc));
+ mpTextHelper->SetEventSource(this);
+
+ const ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
+ if ( pInputHdl && pInputHdl->IsEditMode() )
+ {
+ mpTextHelper->SetFocus();
+ }
+ else
+ {
+ mpTextHelper->SetFocus(mbHasFocus);
+ }
+
+ // #i54814# activate cell in edit mode
+ if( meObjectType == CellInEditMode )
+ {
+ // do not activate cell object, if top edit line is active
+ if( pInputHdl && !pInputHdl->IsTopMode() )
+ {
+ SdrHint aHint( SdrHintKind::BeginEdit );
+ mpTextHelper->GetEditSource().GetBroadcaster().Broadcast( aHint );
+ }
+ }
+}
+
+sal_Int32 SAL_CALL ScAccessibleEditObject::getForeground( )
+{
+ return GetFgBgColor(SC_UNONAME_CCOLOR);
+}
+
+sal_Int32 SAL_CALL ScAccessibleEditObject::getBackground( )
+{
+ return GetFgBgColor(SC_UNONAME_CELLBACK);
+}
+
+sal_Int32 ScAccessibleEditObject::GetFgBgColor( const OUString &strPropColor)
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nColor(0);
+ if (m_pScDoc)
+ {
+ SfxObjectShell* pObjSh = m_pScDoc->GetDocumentShell();
+ if ( pObjSh )
+ {
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( pObjSh->GetModel(), uno::UNO_QUERY );
+ if ( xSpreadDoc.is() )
+ {
+ uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets();
+ uno::Reference<container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
+ if ( xIndex.is() )
+ {
+ uno::Any aTable = xIndex->getByIndex(m_curCellAddress.Tab());
+ uno::Reference<sheet::XSpreadsheet> xTable;
+ if (aTable>>=xTable)
+ {
+ uno::Reference<table::XCell> xCell = xTable->getCellByPosition(m_curCellAddress.Col(), m_curCellAddress.Row());
+ if (xCell.is())
+ {
+ uno::Reference<beans::XPropertySet> xCellProps(xCell, uno::UNO_QUERY);
+ if (xCellProps.is())
+ {
+ uno::Any aAny = xCellProps->getPropertyValue(strPropColor);
+ aAny >>= nColor;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return nColor;
+}
+//===== XAccessibleSelection ============================================
+
+void SAL_CALL ScAccessibleEditObject::selectAccessibleChild( sal_Int32 )
+{
+}
+
+sal_Bool SAL_CALL ScAccessibleEditObject::isAccessibleChildSelected( sal_Int32 nChildIndex )
+{
+ uno::Reference<XAccessible> xAcc = getAccessibleChild( nChildIndex );
+ uno::Reference<XAccessibleContext> xContext;
+ if( xAcc.is() )
+ xContext = xAcc->getAccessibleContext();
+ if( xContext.is() )
+ {
+ if( xContext->getAccessibleRole() == AccessibleRole::PARAGRAPH )
+ {
+ uno::Reference< css::accessibility::XAccessibleText >
+ xText(xAcc, uno::UNO_QUERY);
+ if( xText.is() )
+ {
+ if( xText->getSelectionStart() >= 0 ) return true;
+ }
+ }
+ }
+ return false;
+}
+
+void SAL_CALL ScAccessibleEditObject::clearAccessibleSelection( )
+{
+}
+
+void SAL_CALL ScAccessibleEditObject::selectAllAccessibleChildren( )
+{
+}
+
+sal_Int32 SAL_CALL ScAccessibleEditObject::getSelectedAccessibleChildCount()
+{
+ sal_Int32 nCount = 0;
+ sal_Int32 TotalCount = getAccessibleChildCount();
+ for( sal_Int32 i = 0; i < TotalCount; i++ )
+ if( isAccessibleChildSelected(i) ) nCount++;
+ return nCount;
+}
+
+uno::Reference<XAccessible> SAL_CALL ScAccessibleEditObject::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
+{
+ if ( nSelectedChildIndex > getSelectedAccessibleChildCount() )
+ throw IndexOutOfBoundsException();
+ sal_Int32 i1, i2;
+ for( i1 = 0, i2 = 0; i1 < getAccessibleChildCount(); i1++ )
+ if( isAccessibleChildSelected(i1) )
+ {
+ if( i2 == nSelectedChildIndex )
+ return getAccessibleChild( i1 );
+ i2++;
+ }
+ return uno::Reference<XAccessible>();
+}
+
+void SAL_CALL ScAccessibleEditObject::deselectAccessibleChild(
+ sal_Int32 )
+{
+}
+
+uno::Reference< XAccessibleRelationSet > ScAccessibleEditObject::getAccessibleRelationSet( )
+{
+ SolarMutexGuard aGuard;
+ vcl::Window* pWindow = mpWindow;
+ rtl::Reference<utl::AccessibleRelationSetHelper> rRelationSet = new utl::AccessibleRelationSetHelper;
+ if ( pWindow )
+ {
+ vcl::Window *pLabeledBy = pWindow->GetAccessibleRelationLabeledBy();
+ if ( pLabeledBy && pLabeledBy != pWindow )
+ {
+ uno::Sequence< uno::Reference< uno::XInterface > > aSequence { pLabeledBy->GetAccessible() };
+ rRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::LABELED_BY, aSequence ) );
+ }
+ vcl::Window* pMemberOf = pWindow->GetAccessibleRelationMemberOf();
+ if ( pMemberOf && pMemberOf != pWindow )
+ {
+ uno::Sequence< uno::Reference< uno::XInterface > > aSequence { pMemberOf->GetAccessible() };
+ rRelationSet->AddRelation( AccessibleRelation( AccessibleRelationType::MEMBER_OF, aSequence ) );
+ }
+ return rRelationSet;
+ }
+ return uno::Reference< XAccessibleRelationSet >();
+}
+
+tools::Rectangle ScAccessibleEditControlObject::GetBoundingBoxOnScreen() const
+{
+ tools::Rectangle aScreenBounds;
+
+ if (m_pController && m_pController->GetDrawingArea())
+ {
+ aScreenBounds = tools::Rectangle(m_pController->GetDrawingArea()->get_accessible_location_on_screen(),
+ m_pController->GetOutputSizePixel());
+ }
+
+ return aScreenBounds;
+}
+
+tools::Rectangle ScAccessibleEditControlObject::GetBoundingBox() const
+{
+ tools::Rectangle aBounds( GetBoundingBoxOnScreen() );
+
+ uno::Reference< XAccessibleContext > xContext(const_cast<ScAccessibleEditControlObject*>(this)->getAccessibleContext());
+ if ( xContext.is() )
+ {
+ uno::Reference< XAccessible > xParent( xContext->getAccessibleParent() );
+ if ( xParent.is() )
+ {
+ uno::Reference< XAccessibleComponent > xParentComponent( xParent->getAccessibleContext(), uno::UNO_QUERY );
+ if ( xParentComponent.is() )
+ {
+ Point aScreenLoc = aBounds.TopLeft();
+ awt::Point aParentScreenLoc = xParentComponent->getLocationOnScreen();
+ Point aPos( aScreenLoc.getX() - aParentScreenLoc.X, aScreenLoc.getY() - aParentScreenLoc.Y );
+ aBounds.SetPos( aPos );
+ }
+ }
+ }
+
+ return aBounds;
+}
+
+void SAL_CALL ScAccessibleEditControlObject::disposing()
+{
+ ScAccessibleEditObject::disposing();
+ m_pController = nullptr;
+}
+
+uno::Reference< XAccessibleRelationSet > ScAccessibleEditControlObject::getAccessibleRelationSet()
+{
+ SolarMutexGuard aGuard;
+ if (!m_pController || !m_pController->GetDrawingArea())
+ return uno::Reference< XAccessibleRelationSet >();
+ return m_pController->GetDrawingArea()->get_accessible_relation_set();
+}
+
+OutputDevice* ScAccessibleEditControlObject::GetOutputDeviceForView()
+{
+ if (!m_pController || !m_pController->GetDrawingArea())
+ return nullptr;
+ return &m_pController->GetDrawingArea()->get_ref_device();
+}
+
+ScAccessibleEditLineObject::ScAccessibleEditLineObject(ScTextWnd* pTextWnd)
+ : ScAccessibleEditControlObject(pTextWnd, ScAccessibleEditObject::EditLine)
+{
+ // tdf#141769 set this early so its always available, even before the on-demand
+ // editview is created
+ mpTextWnd = pTextWnd;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessiblePageHeader.cxx b/sc/source/ui/Accessibility/AccessiblePageHeader.cxx
new file mode 100644
index 000000000..a95093203
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessiblePageHeader.cxx
@@ -0,0 +1,371 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessiblePageHeader.hxx>
+#include <AccessiblePageHeaderArea.hxx>
+#include <prevwsh.hxx>
+#include <prevloc.hxx>
+#include <document.hxx>
+#include <stlpool.hxx>
+#include <scitems.hxx>
+#include <attrib.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/sequence.hxx>
+
+#include <vcl/window.hxx>
+#include <svl/hint.hxx>
+#include <svl/itemset.hxx>
+#include <vcl/svapp.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <svl/style.hxx>
+#include <editeng/editobj.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+const sal_uInt8 MAX_AREAS = 3;
+
+ScAccessiblePageHeader::ScAccessiblePageHeader( const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScPreviewShell* pViewShell, bool bHeader, sal_Int32 nIndex ) :
+ScAccessibleContextBase( rxParent, bHeader ? AccessibleRole::HEADER : AccessibleRole::FOOTER ),
+ mpViewShell( pViewShell ),
+ mnIndex( nIndex ),
+ mbHeader( bHeader ),
+ maAreas(MAX_AREAS, rtl::Reference<ScAccessiblePageHeaderArea>()),
+ mnChildCount(-1)
+{
+ if (mpViewShell)
+ mpViewShell->AddAccessibilityObject(*this);
+}
+
+ScAccessiblePageHeader::~ScAccessiblePageHeader()
+{
+ if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
+ {
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+}
+
+void SAL_CALL ScAccessiblePageHeader::disposing()
+{
+ SolarMutexGuard aGuard;
+ if (mpViewShell)
+ {
+ mpViewShell->RemoveAccessibilityObject(*this);
+ mpViewShell = nullptr;
+ }
+ for (auto & i : maAreas)
+ {
+ if (i.is())
+ {
+ i->dispose();
+ i.clear();
+ }
+ }
+
+ ScAccessibleContextBase::disposing();
+}
+
+//===== SfxListener =====================================================
+
+void ScAccessiblePageHeader::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ // only notify if child exist, otherwise it is not necessary
+ if (rHint.GetId() == SfxHintId::ScDataChanged)
+ {
+ std::vector<rtl::Reference<ScAccessiblePageHeaderArea>> aOldAreas(maAreas);
+ mnChildCount = -1;
+ getAccessibleChildCount();
+ for (sal_uInt8 i = 0; i < MAX_AREAS; ++i)
+ {
+ if ((aOldAreas[i].is() && maAreas[i].is() && !ScGlobal::EETextObjEqual(aOldAreas[i]->GetEditTextObject(), maAreas[i]->GetEditTextObject())) ||
+ (aOldAreas[i].is() && !maAreas[i].is()) || (!aOldAreas[i].is() && maAreas[i].is()))
+ {
+ if (aOldAreas[i].is() && aOldAreas[i]->GetEditTextObject())
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ aEvent.OldValue <<= uno::Reference<XAccessible>(aOldAreas[i]);
+
+ CommitChange(aEvent); // child gone - event
+ aOldAreas[i]->dispose();
+ }
+ if (maAreas[i].is() && maAreas[i]->GetEditTextObject())
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::CHILD;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ aEvent.NewValue <<= uno::Reference<XAccessible>(maAreas[i]);
+
+ CommitChange(aEvent); // new child - event
+ }
+ }
+ }
+ }
+ else if (rHint.GetId() == SfxHintId::ScAccVisAreaChanged)
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ CommitChange(aEvent);
+ }
+
+ ScAccessibleContextBase::Notify(rBC, rHint);
+}
+
+//===== XAccessibleComponent ============================================
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePageHeader::getAccessibleAtPoint( const awt::Point& aPoint )
+{
+ uno::Reference<XAccessible> xRet;
+
+ if (containsPoint(aPoint))
+ {
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ sal_Int32 nCount(getAccessibleChildCount()); // fill the areas
+
+ if (nCount)
+ {
+ // return the first with content, because they have all the same Bounding Box
+ sal_uInt8 i(0);
+ while(!xRet.is() && i < MAX_AREAS)
+ {
+ if (maAreas[i].is())
+ xRet = maAreas[i].get();
+ else
+ ++i;
+ }
+ }
+ }
+
+ return xRet;
+}
+
+void SAL_CALL ScAccessiblePageHeader::grabFocus()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
+ if (xAccessibleComponent.is())
+ xAccessibleComponent->grabFocus();
+ }
+}
+
+//===== XAccessibleContext ==============================================
+
+sal_Int32 SAL_CALL ScAccessiblePageHeader::getAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if((mnChildCount < 0) && mpViewShell)
+ {
+ mnChildCount = 0;
+ ScDocument& rDoc = mpViewShell->GetDocument();
+ // find out how many regions (left,center, right) are with content
+
+ SfxStyleSheetBase* pStyle = rDoc.GetStyleSheetPool()->Find(rDoc.GetPageStyle(mpViewShell->GetLocationData().GetPrintTab()), SfxStyleFamily::Page);
+ if (pStyle)
+ {
+ sal_uInt16 nPageWhichId(0);
+ if (mbHeader)
+ nPageWhichId = mpViewShell->GetLocationData().IsHeaderLeft() ? ATTR_PAGE_HEADERLEFT : ATTR_PAGE_HEADERRIGHT;
+ else
+ nPageWhichId = mpViewShell->GetLocationData().IsFooterLeft() ? ATTR_PAGE_FOOTERLEFT : ATTR_PAGE_FOOTERRIGHT;
+
+ const ScPageHFItem& rPageItem = static_cast<const ScPageHFItem&>(pStyle->GetItemSet().Get(nPageWhichId));
+ AddChild(rPageItem.GetLeftArea(), 0, SvxAdjust::Left);
+ AddChild(rPageItem.GetCenterArea(), 1, SvxAdjust::Center);
+ AddChild(rPageItem.GetRightArea(), 2, SvxAdjust::Right);
+ }
+ }
+
+ return mnChildCount;
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePageHeader::getAccessibleChild( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ uno::Reference<XAccessible> xRet;
+
+ if(mnChildCount < 0)
+ getAccessibleChildCount();
+
+ if (nIndex >= 0)
+ for (const auto& rxArea : maAreas)
+ {
+ if (rxArea.is())
+ {
+ if (nIndex == 0)
+ {
+ xRet = rxArea.get();
+ break;
+ }
+ else
+ --nIndex;
+ }
+ }
+
+ if ( !xRet.is() )
+ throw lang::IndexOutOfBoundsException();
+
+ return xRet;
+}
+
+sal_Int32 SAL_CALL ScAccessiblePageHeader::getAccessibleIndexInParent()
+{
+ return mnIndex;
+}
+
+uno::Reference< XAccessibleStateSet > SAL_CALL ScAccessiblePageHeader::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<XAccessibleStateSet> xParentStates;
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
+ xParentStates = xParentContext->getAccessibleStateSet();
+ }
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSet = new utl::AccessibleStateSetHelper();
+ if (IsDefunc(xParentStates))
+ pStateSet->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::OPAQUE);
+ if (isShowing())
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ if (isVisible())
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ }
+ return pStateSet;
+}
+
+//===== XServiceInfo ====================================================
+
+OUString SAL_CALL ScAccessiblePageHeader::getImplementationName()
+{
+ return "ScAccessiblePageHeader";
+}
+
+uno::Sequence<OUString> SAL_CALL ScAccessiblePageHeader::getSupportedServiceNames()
+{
+ const css::uno::Sequence<OUString> vals { "com.sun.star.text.AccessibleHeaderFooterView" };
+ return comphelper::concatSequences(ScAccessibleContextBase::getSupportedServiceNames(), vals);
+}
+
+//==== internal =========================================================
+
+OUString ScAccessiblePageHeader::createAccessibleDescription()
+{
+ OUString sDesc(mbHeader ? OUString(STR_ACC_HEADER_DESCR) : OUString(STR_ACC_FOOTER_DESCR));
+ return sDesc.replaceFirst("%1", ScResId(SCSTR_UNKNOWN));
+}
+
+OUString ScAccessiblePageHeader::createAccessibleName()
+{
+ OUString sName(ScResId(mbHeader ? STR_ACC_HEADER_NAME : STR_ACC_FOOTER_NAME));
+ return sName.replaceFirst("%1", ScResId(SCSTR_UNKNOWN));
+}
+
+tools::Rectangle ScAccessiblePageHeader::GetBoundingBoxOnScreen() const
+{
+ tools::Rectangle aCellRect(GetBoundingBox());
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if (pWindow)
+ {
+ tools::Rectangle aRect = pWindow->GetWindowExtentsRelative(nullptr);
+ aCellRect.Move(aRect.Left(), aRect.Top());
+ }
+ }
+ return aCellRect;
+}
+
+tools::Rectangle ScAccessiblePageHeader::GetBoundingBox() const
+{
+ tools::Rectangle aRect;
+ if (mpViewShell)
+ {
+ const ScPreviewLocationData& rData = mpViewShell->GetLocationData();
+ if ( mbHeader )
+ rData.GetHeaderPosition( aRect );
+ else
+ rData.GetFooterPosition( aRect );
+
+ // the Rectangle could contain negative coordinates so it should be clipped
+ tools::Rectangle aClipRect(Point(0, 0), aRect.GetSize());
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if (pWindow)
+ aClipRect = pWindow->GetWindowExtentsRelative(pWindow->GetAccessibleParentWindow());
+ aRect = aClipRect.GetIntersection(aRect);
+ }
+ if (aRect.IsEmpty())
+ aRect.SetSize(Size(-1, -1));
+
+ return aRect;
+}
+
+bool ScAccessiblePageHeader::IsDefunc( const uno::Reference<XAccessibleStateSet>& rxParentStates )
+{
+ return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
+ (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
+}
+
+void ScAccessiblePageHeader::AddChild(const EditTextObject* pArea, sal_uInt32 nIndex, SvxAdjust eAdjust)
+{
+ if (pArea && (!pArea->GetText(0).isEmpty() || (pArea->GetParagraphCount() > 1)))
+ {
+ if (maAreas[nIndex].is())
+ {
+ if (!ScGlobal::EETextObjEqual(maAreas[nIndex]->GetEditTextObject(), pArea))
+ {
+ maAreas[nIndex] = new ScAccessiblePageHeaderArea(this, mpViewShell, pArea, eAdjust);
+ }
+ }
+ else
+ {
+ maAreas[nIndex] = new ScAccessiblePageHeaderArea(this, mpViewShell, pArea, eAdjust);
+ }
+ ++mnChildCount;
+ }
+ else
+ {
+ maAreas[nIndex].clear();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessiblePageHeaderArea.cxx b/sc/source/ui/Accessibility/AccessiblePageHeaderArea.cxx
new file mode 100644
index 000000000..9ea60780b
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessiblePageHeaderArea.cxx
@@ -0,0 +1,279 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <tools/gen.hxx>
+#include <AccessiblePageHeaderArea.hxx>
+#include <AccessibleText.hxx>
+#include <editsrc.hxx>
+#include <prevwsh.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <comphelper/sequence.hxx>
+#include <editeng/editobj.hxx>
+#include <svx/AccessibleTextHelper.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+ //===== internal ========================================================
+
+ScAccessiblePageHeaderArea::ScAccessiblePageHeaderArea(
+ const uno::Reference<XAccessible>& rxParent,
+ ScPreviewShell* pViewShell,
+ const EditTextObject* pEditObj,
+ SvxAdjust eAdjust)
+ : ScAccessibleContextBase(rxParent, AccessibleRole::TEXT),
+ mpEditObj(pEditObj->Clone()),
+ mpViewShell(pViewShell),
+ meAdjust(eAdjust)
+{
+ if (mpViewShell)
+ mpViewShell->AddAccessibilityObject(*this);
+}
+
+ScAccessiblePageHeaderArea::~ScAccessiblePageHeaderArea()
+{
+ if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
+ {
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+}
+
+void SAL_CALL ScAccessiblePageHeaderArea::disposing()
+{
+ SolarMutexGuard aGuard;
+ if (mpViewShell)
+ {
+ mpViewShell->RemoveAccessibilityObject(*this);
+ mpViewShell = nullptr;
+ }
+ mpTextHelper.reset();
+ mpEditObj.reset();
+ ScAccessibleContextBase::disposing();
+}
+
+//===== SfxListener =====================================================
+
+void ScAccessiblePageHeaderArea::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ // only notify if child exist, otherwise it is not necessary
+ if (rHint.GetId() == SfxHintId::ScAccVisAreaChanged)
+ {
+ if (mpTextHelper)
+ mpTextHelper->UpdateChildren();
+
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ CommitChange(aEvent);
+ }
+ ScAccessibleContextBase::Notify(rBC, rHint);
+}
+ //===== XAccessibleComponent ============================================
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePageHeaderArea::getAccessibleAtPoint(
+ const awt::Point& rPoint )
+{
+ uno::Reference<XAccessible> xRet;
+ if (containsPoint(rPoint))
+ {
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if(!mpTextHelper)
+ CreateTextHelper();
+
+ xRet = mpTextHelper->GetAt(rPoint);
+ }
+
+ return xRet;
+}
+
+ //===== XAccessibleContext ==============================================
+
+sal_Int32 SAL_CALL
+ ScAccessiblePageHeaderArea::getAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (!mpTextHelper)
+ CreateTextHelper();
+ return mpTextHelper->GetChildCount();
+}
+
+uno::Reference< XAccessible > SAL_CALL
+ ScAccessiblePageHeaderArea::getAccessibleChild(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (!mpTextHelper)
+ CreateTextHelper();
+ return mpTextHelper->GetChild(nIndex);
+}
+
+uno::Reference<XAccessibleStateSet> SAL_CALL
+ ScAccessiblePageHeaderArea::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<XAccessibleStateSet> xParentStates;
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
+ xParentStates = xParentContext->getAccessibleStateSet();
+ }
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSet = new utl::AccessibleStateSetHelper();
+ if (IsDefunc())
+ pStateSet->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::MULTI_LINE);
+ if (isShowing())
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ if (isVisible())
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ }
+ return pStateSet;
+}
+
+// XServiceInfo
+
+OUString SAL_CALL
+ ScAccessiblePageHeaderArea::getImplementationName()
+{
+ return "ScAccessiblePageHeaderArea";
+}
+
+uno::Sequence< OUString> SAL_CALL
+ ScAccessiblePageHeaderArea::getSupportedServiceNames()
+{
+ const css::uno::Sequence<OUString> vals { "com.sun.star.sheet.AccessiblePageHeaderFooterAreasView" };
+ return comphelper::concatSequences(ScAccessibleContextBase::getSupportedServiceNames(), vals);
+}
+
+//===== XTypeProvider =======================================================
+
+uno::Sequence<sal_Int8> SAL_CALL
+ ScAccessiblePageHeaderArea::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+//===== internal ==============================================================
+OUString ScAccessiblePageHeaderArea::createAccessibleDescription()
+{
+ OUString sDesc;
+ switch (meAdjust)
+ {
+ case SvxAdjust::Left :
+ sDesc = STR_ACC_LEFTAREA_DESCR;
+ break;
+ case SvxAdjust::Right:
+ sDesc = STR_ACC_RIGHTAREA_DESCR;
+ break;
+ case SvxAdjust::Center:
+ sDesc = STR_ACC_CENTERAREA_DESCR;
+ break;
+ default:
+ OSL_FAIL("wrong adjustment found");
+ }
+
+ return sDesc;
+}
+
+OUString ScAccessiblePageHeaderArea::createAccessibleName()
+{
+ OUString sName;
+ switch (meAdjust)
+ {
+ case SvxAdjust::Left :
+ sName = ScResId(STR_ACC_LEFTAREA_NAME);
+ break;
+ case SvxAdjust::Right:
+ sName = ScResId(STR_ACC_RIGHTAREA_NAME);
+ break;
+ case SvxAdjust::Center:
+ sName = ScResId(STR_ACC_CENTERAREA_NAME);
+ break;
+ default:
+ OSL_FAIL("wrong adjustment found");
+ }
+
+ return sName;
+}
+
+tools::Rectangle ScAccessiblePageHeaderArea::GetBoundingBoxOnScreen() const
+{
+ tools::Rectangle aRect;
+ if (mxParent.is())
+ {
+ uno::Reference<XAccessibleContext> xContext = mxParent->getAccessibleContext();
+ uno::Reference<XAccessibleComponent> xComp(xContext, uno::UNO_QUERY);
+ if (xComp.is())
+ {
+ // has the same size and position on screen like the parent
+ aRect = tools::Rectangle(VCLPoint(xComp->getLocationOnScreen()), VCLRectangle(xComp->getBounds()).GetSize());
+ }
+ }
+ return aRect;
+}
+
+tools::Rectangle ScAccessiblePageHeaderArea::GetBoundingBox() const
+{
+ tools::Rectangle aRect;
+ if (mxParent.is())
+ {
+ uno::Reference<XAccessibleContext> xContext = mxParent->getAccessibleContext();
+ uno::Reference<XAccessibleComponent> xComp(xContext, uno::UNO_QUERY);
+ if (xComp.is())
+ {
+ // has the same size and position on screen like the parent and so the pos is (0, 0)
+ tools::Rectangle aNewRect(Point(0, 0), VCLRectangle(xComp->getBounds()).GetSize());
+ aRect = aNewRect;
+ }
+ }
+
+ return aRect;
+}
+
+void ScAccessiblePageHeaderArea::CreateTextHelper()
+{
+ if (!mpTextHelper)
+ {
+ mpTextHelper.reset( new ::accessibility::AccessibleTextHelper(
+ std::make_unique<ScAccessibilityEditSource>(
+ std::make_unique<ScAccessibleHeaderTextData>(
+ mpViewShell, mpEditObj.get(), meAdjust))) );
+ mpTextHelper->SetEventSource(this);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessiblePreviewCell.cxx b/sc/source/ui/Accessibility/AccessiblePreviewCell.cxx
new file mode 100644
index 000000000..f3bc3e717
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessiblePreviewCell.cxx
@@ -0,0 +1,277 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <scitems.hxx>
+#include <tools/gen.hxx>
+#include <AccessibleText.hxx>
+#include <editsrc.hxx>
+#include <AccessiblePreviewCell.hxx>
+#include <prevwsh.hxx>
+#include <prevloc.hxx>
+#include <document.hxx>
+#include <svx/AccessibleTextHelper.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <editeng/brushitem.hxx>
+#include <vcl/window.hxx>
+#include <vcl/svapp.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <comphelper/sequence.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+//===== internal ============================================================
+
+ScAccessiblePreviewCell::ScAccessiblePreviewCell( const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScPreviewShell* pViewShell,
+ const ScAddress& rCellAddress,
+ sal_Int32 nIndex ) :
+ ScAccessibleCellBase( rxParent, ( pViewShell ? &pViewShell->GetDocument() : nullptr ), rCellAddress, nIndex ),
+ mpViewShell( pViewShell )
+{
+ if (mpViewShell)
+ mpViewShell->AddAccessibilityObject(*this);
+}
+
+ScAccessiblePreviewCell::~ScAccessiblePreviewCell()
+{
+ if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
+ {
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+ // call dispose to inform object which have a weak reference to this object
+ dispose();
+ }
+}
+
+void SAL_CALL ScAccessiblePreviewCell::disposing()
+{
+ SolarMutexGuard aGuard;
+ if (mpViewShell)
+ {
+ mpViewShell->RemoveAccessibilityObject(*this);
+ mpViewShell = nullptr;
+ }
+
+ mpTextHelper.reset();
+
+ ScAccessibleCellBase::disposing();
+}
+
+void ScAccessiblePreviewCell::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if (rHint.GetId() == SfxHintId::ScAccVisAreaChanged)
+ {
+ if (mpTextHelper)
+ mpTextHelper->UpdateChildren();
+ }
+
+ ScAccessibleContextBase::Notify(rBC, rHint);
+}
+
+//===== XAccessibleComponent ============================================
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewCell::getAccessibleAtPoint( const awt::Point& rPoint )
+{
+ uno::Reference<XAccessible> xRet;
+ if (containsPoint(rPoint))
+ {
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if(!mpTextHelper)
+ CreateTextHelper();
+
+ xRet = mpTextHelper->GetAt(rPoint);
+ }
+
+ return xRet;
+}
+
+void SAL_CALL ScAccessiblePreviewCell::grabFocus()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
+ if (xAccessibleComponent.is())
+ xAccessibleComponent->grabFocus();
+ }
+}
+
+//===== XAccessibleContext ==============================================
+
+sal_Int32 SAL_CALL ScAccessiblePreviewCell::getAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (!mpTextHelper)
+ CreateTextHelper();
+ return mpTextHelper->GetChildCount();
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewCell::getAccessibleChild(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (!mpTextHelper)
+ CreateTextHelper();
+ return mpTextHelper->GetChild(nIndex);
+}
+
+uno::Reference<XAccessibleStateSet> SAL_CALL ScAccessiblePreviewCell::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<XAccessibleStateSet> xParentStates;
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
+ xParentStates = xParentContext->getAccessibleStateSet();
+ }
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSet = new utl::AccessibleStateSetHelper();
+ if (IsDefunc(xParentStates))
+ pStateSet->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::MULTI_LINE);
+ if (IsOpaque())
+ pStateSet->AddState(AccessibleStateType::OPAQUE);
+ if (isShowing())
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ pStateSet->AddState(AccessibleStateType::TRANSIENT);
+ if (isVisible())
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ // MANAGES_DESCENDANTS (for paragraphs)
+ pStateSet->AddState(AccessibleStateType::MANAGES_DESCENDANTS);
+ }
+ return pStateSet;
+}
+
+//===== XServiceInfo ====================================================
+
+OUString SAL_CALL ScAccessiblePreviewCell::getImplementationName()
+{
+ return "ScAccessiblePreviewCell";
+}
+
+uno::Sequence<OUString> SAL_CALL ScAccessiblePreviewCell::getSupportedServiceNames()
+{
+ const css::uno::Sequence<OUString> vals { "com.sun.star.table.AccessibleCellView" };
+ return comphelper::concatSequences(ScAccessibleContextBase::getSupportedServiceNames(), vals);
+}
+
+//===== XTypeProvider =======================================================
+
+uno::Sequence<sal_Int8> SAL_CALL
+ ScAccessiblePreviewCell::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+//==== internal =========================================================
+
+tools::Rectangle ScAccessiblePreviewCell::GetBoundingBoxOnScreen() const
+{
+ tools::Rectangle aCellRect;
+ if (mpViewShell)
+ {
+ mpViewShell->GetLocationData().GetCellPosition( maCellAddress, aCellRect );
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if (pWindow)
+ {
+ tools::Rectangle aRect = pWindow->GetWindowExtentsRelative(nullptr);
+ aCellRect.Move(aRect.Left(), aRect.Top());
+ }
+ }
+ return aCellRect;
+}
+
+tools::Rectangle ScAccessiblePreviewCell::GetBoundingBox() const
+{
+ tools::Rectangle aCellRect;
+ if (mpViewShell)
+ {
+ mpViewShell->GetLocationData().GetCellPosition( maCellAddress, aCellRect );
+ uno::Reference<XAccessible> xAccParent = const_cast<ScAccessiblePreviewCell*>(this)->getAccessibleParent();
+ if (xAccParent.is())
+ {
+ uno::Reference<XAccessibleContext> xAccParentContext = xAccParent->getAccessibleContext();
+ uno::Reference<XAccessibleComponent> xAccParentComp (xAccParentContext, uno::UNO_QUERY);
+ if (xAccParentComp.is())
+ {
+ tools::Rectangle aParentRect (VCLRectangle(xAccParentComp->getBounds()));
+ aCellRect.Move(-aParentRect.Left(), -aParentRect.Top());
+ }
+ }
+ }
+ return aCellRect;
+}
+
+bool ScAccessiblePreviewCell::IsDefunc(
+ const uno::Reference<XAccessibleStateSet>& rxParentStates)
+{
+ return ScAccessibleContextBase::IsDefunc() || (mpDoc == nullptr) || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
+ (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
+}
+
+bool ScAccessiblePreviewCell::IsEditable(
+ const uno::Reference<XAccessibleStateSet>& /* rxParentStates */)
+{
+ return false;
+}
+
+bool ScAccessiblePreviewCell::IsOpaque() const
+{
+ // test whether there is a background color
+ //! could be moved to ScAccessibleCellBase
+
+ bool bOpaque(true);
+ if (mpDoc)
+ {
+ const SvxBrushItem* pItem = mpDoc->GetAttr(maCellAddress, ATTR_BACKGROUND);
+ if (pItem)
+ bOpaque = pItem->GetColor() != COL_TRANSPARENT;
+ }
+ return bOpaque;
+}
+
+void ScAccessiblePreviewCell::CreateTextHelper()
+{
+ if (mpTextHelper)
+ return;
+
+ mpTextHelper.reset( new ::accessibility::AccessibleTextHelper(
+ std::make_unique<ScAccessibilityEditSource>(
+ std::make_unique<ScAccessiblePreviewCellTextData>(
+ mpViewShell, maCellAddress))) );
+ mpTextHelper->SetEventSource( this );
+
+ // paragraphs in preview are transient
+ ::accessibility::AccessibleTextHelper::VectorOfStates aChildStates;
+ aChildStates.push_back( AccessibleStateType::TRANSIENT );
+ mpTextHelper->SetAdditionalChildStates( std::move(aChildStates) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessiblePreviewHeaderCell.cxx b/sc/source/ui/Accessibility/AccessiblePreviewHeaderCell.cxx
new file mode 100644
index 000000000..1bda4744a
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessiblePreviewHeaderCell.cxx
@@ -0,0 +1,404 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <tools/gen.hxx>
+#include <AccessibleText.hxx>
+#include <editsrc.hxx>
+#include <svx/AccessibleTextHelper.hxx>
+#include <AccessiblePreviewHeaderCell.hxx>
+#include <prevwsh.hxx>
+#include <prevloc.hxx>
+#include <strings.hxx>
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <comphelper/sequence.hxx>
+
+#include <vcl/window.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/hint.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <toolkit/helper/convert.hxx>
+
+#ifdef indices
+#undef indices
+#endif
+
+#ifdef extents
+#undef extents
+#endif
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+//===== internal ============================================================
+
+ScAccessiblePreviewHeaderCell::ScAccessiblePreviewHeaderCell( const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScPreviewShell* pViewShell,
+ const ScAddress& rCellPos, bool bIsColHdr, bool bIsRowHdr,
+ sal_Int32 nIndex ) :
+ ScAccessibleContextBase( rxParent, AccessibleRole::TABLE_CELL ),
+ mpViewShell( pViewShell ),
+ mnIndex( nIndex ),
+ maCellPos( rCellPos ),
+ mbColumnHeader( bIsColHdr ),
+ mbRowHeader( bIsRowHdr )
+{
+ if (mpViewShell)
+ mpViewShell->AddAccessibilityObject(*this);
+}
+
+ScAccessiblePreviewHeaderCell::~ScAccessiblePreviewHeaderCell()
+{
+ if (mpViewShell)
+ mpViewShell->RemoveAccessibilityObject(*this);
+}
+
+void SAL_CALL ScAccessiblePreviewHeaderCell::disposing()
+{
+ SolarMutexGuard aGuard;
+ if (mpViewShell)
+ {
+ mpViewShell->RemoveAccessibilityObject(*this);
+ mpViewShell = nullptr;
+ }
+
+ mpTableInfo.reset();
+
+ ScAccessibleContextBase::disposing();
+}
+
+//===== SfxListener =====================================================
+
+void ScAccessiblePreviewHeaderCell::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ const SfxHintId nId = rHint.GetId();
+ if (nId == SfxHintId::ScAccVisAreaChanged)
+ {
+ if (mxTextHelper)
+ mxTextHelper->UpdateChildren();
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ // column / row layout may change with any document change,
+ // so it must be invalidated
+ mpTableInfo.reset();
+ }
+
+ ScAccessibleContextBase::Notify(rBC, rHint);
+}
+
+//===== XInterface =====================================================
+
+uno::Any SAL_CALL ScAccessiblePreviewHeaderCell::queryInterface( uno::Type const & rType )
+{
+ uno::Any aAny (ScAccessiblePreviewHeaderCellImpl::queryInterface(rType));
+ return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType);
+}
+
+void SAL_CALL ScAccessiblePreviewHeaderCell::acquire()
+ noexcept
+{
+ ScAccessibleContextBase::acquire();
+}
+
+void SAL_CALL ScAccessiblePreviewHeaderCell::release()
+ noexcept
+{
+ ScAccessibleContextBase::release();
+}
+
+//===== XAccessibleValue ================================================
+
+uno::Any SAL_CALL ScAccessiblePreviewHeaderCell::getCurrentValue()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ double fValue(0.0);
+ if (mbColumnHeader)
+ fValue = maCellPos.Col();
+ else
+ fValue = maCellPos.Row();
+
+ return uno::Any(fValue);
+}
+
+sal_Bool SAL_CALL ScAccessiblePreviewHeaderCell::setCurrentValue( const uno::Any& /* aNumber */ )
+{
+ // it is not possible to set a value
+ return false;
+}
+
+uno::Any SAL_CALL ScAccessiblePreviewHeaderCell::getMaximumValue()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ double fValue(0.0);
+ ScDocument& rDoc = mpViewShell->GetDocument();
+ if (mbColumnHeader)
+ fValue = rDoc.MaxCol();
+ else
+ fValue = rDoc.MaxRow();
+ return uno::Any(fValue);
+}
+
+uno::Any SAL_CALL ScAccessiblePreviewHeaderCell::getMinimumValue()
+{
+ return uno::Any(0.0);
+}
+
+uno::Any SAL_CALL ScAccessiblePreviewHeaderCell::getMinimumIncrement()
+{
+ // value can't be changed, s. 'setCurrentValue'
+ return uno::Any();
+}
+
+//===== XAccessibleComponent ============================================
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewHeaderCell::getAccessibleAtPoint( const awt::Point& rPoint )
+{
+ uno::Reference<XAccessible> xRet;
+ if (containsPoint(rPoint))
+ {
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if(!mxTextHelper)
+ CreateTextHelper();
+
+ xRet = mxTextHelper->GetAt(rPoint);
+ }
+
+ return xRet;
+}
+
+void SAL_CALL ScAccessiblePreviewHeaderCell::grabFocus()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
+ if (xAccessibleComponent.is())
+ xAccessibleComponent->grabFocus();
+ }
+}
+
+//===== XAccessibleContext ==============================================
+
+sal_Int32 SAL_CALL ScAccessiblePreviewHeaderCell::getAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (!mxTextHelper)
+ CreateTextHelper();
+ return mxTextHelper->GetChildCount();
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewHeaderCell::getAccessibleChild(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (!mxTextHelper)
+ CreateTextHelper();
+ return mxTextHelper->GetChild(nIndex);
+}
+
+sal_Int32 SAL_CALL ScAccessiblePreviewHeaderCell::getAccessibleIndexInParent()
+{
+ return mnIndex;
+}
+
+uno::Reference<XAccessibleStateSet> SAL_CALL ScAccessiblePreviewHeaderCell::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<XAccessibleStateSet> xParentStates;
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
+ xParentStates = xParentContext->getAccessibleStateSet();
+ }
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSet = new utl::AccessibleStateSetHelper();
+ if (IsDefunc(xParentStates))
+ pStateSet->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::MULTI_LINE);
+ if (isShowing())
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ pStateSet->AddState(AccessibleStateType::TRANSIENT);
+ if (isVisible())
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ }
+ return pStateSet;
+}
+
+//===== XServiceInfo ====================================================
+
+OUString SAL_CALL ScAccessiblePreviewHeaderCell::getImplementationName()
+{
+ return "ScAccessiblePreviewHeaderCell";
+}
+
+uno::Sequence<OUString> SAL_CALL ScAccessiblePreviewHeaderCell::getSupportedServiceNames()
+{
+ const css::uno::Sequence<OUString> vals { "com.sun.star.table.AccessibleCellView" };
+ return comphelper::concatSequences(ScAccessibleContextBase::getSupportedServiceNames(), vals);
+}
+
+//===== XTypeProvider =======================================================
+
+uno::Sequence< uno::Type > SAL_CALL ScAccessiblePreviewHeaderCell::getTypes()
+{
+ return comphelper::concatSequences(ScAccessiblePreviewHeaderCellImpl::getTypes(), ScAccessibleContextBase::getTypes());
+}
+
+uno::Sequence<sal_Int8> SAL_CALL
+ ScAccessiblePreviewHeaderCell::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+//==== internal =========================================================
+
+tools::Rectangle ScAccessiblePreviewHeaderCell::GetBoundingBoxOnScreen() const
+{
+ tools::Rectangle aCellRect;
+
+ FillTableInfo();
+
+ if (mpTableInfo)
+ {
+ const ScPreviewColRowInfo& rColInfo = mpTableInfo->GetColInfo()[maCellPos.Col()];
+ const ScPreviewColRowInfo& rRowInfo = mpTableInfo->GetRowInfo()[maCellPos.Row()];
+
+ aCellRect = tools::Rectangle( rColInfo.nPixelStart, rRowInfo.nPixelStart, rColInfo.nPixelEnd, rRowInfo.nPixelEnd );
+ }
+
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if (pWindow)
+ {
+ tools::Rectangle aRect = pWindow->GetWindowExtentsRelative(nullptr);
+ aCellRect.Move(aRect.Left(), aRect.Top());
+ }
+ }
+ return aCellRect;
+}
+
+tools::Rectangle ScAccessiblePreviewHeaderCell::GetBoundingBox() const
+{
+ FillTableInfo();
+
+ if (mpTableInfo)
+ {
+ const ScPreviewColRowInfo& rColInfo = mpTableInfo->GetColInfo()[maCellPos.Col()];
+ const ScPreviewColRowInfo& rRowInfo = mpTableInfo->GetRowInfo()[maCellPos.Row()];
+
+ tools::Rectangle aCellRect( rColInfo.nPixelStart, rRowInfo.nPixelStart, rColInfo.nPixelEnd, rRowInfo.nPixelEnd );
+ uno::Reference<XAccessible> xAccParent = const_cast<ScAccessiblePreviewHeaderCell*>(this)->getAccessibleParent();
+ if (xAccParent.is())
+ {
+ uno::Reference<XAccessibleContext> xAccParentContext = xAccParent->getAccessibleContext();
+ uno::Reference<XAccessibleComponent> xAccParentComp (xAccParentContext, uno::UNO_QUERY);
+ if (xAccParentComp.is())
+ {
+ tools::Rectangle aParentRect (VCLRectangle(xAccParentComp->getBounds()));
+ aCellRect.Move(-aParentRect.Left(), -aParentRect.Top());
+ }
+ }
+ return aCellRect;
+ }
+ return tools::Rectangle();
+}
+
+OUString ScAccessiblePreviewHeaderCell::createAccessibleDescription()
+{
+ return STR_ACC_HEADERCELL_DESCR;
+}
+
+OUString ScAccessiblePreviewHeaderCell::createAccessibleName()
+{
+ OUString sName = STR_ACC_HEADERCELL_NAME;
+
+ if ( mbColumnHeader )
+ {
+ if ( mbRowHeader )
+ {
+ //! name for corner cell?
+
+// sName = "Column/Row Header";
+ }
+ else
+ {
+ // name of column header
+ sName += ScColToAlpha( maCellPos.Col() );
+ }
+ }
+ else
+ {
+ // name of row header
+ sName += OUString::number( maCellPos.Row() + 1 );
+ }
+
+ return sName;
+}
+
+bool ScAccessiblePreviewHeaderCell::IsDefunc( const uno::Reference<XAccessibleStateSet>& rxParentStates )
+{
+ return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
+ (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
+}
+
+void ScAccessiblePreviewHeaderCell::CreateTextHelper()
+{
+ if (!mxTextHelper)
+ {
+ mxTextHelper.reset( new ::accessibility::AccessibleTextHelper(
+ std::make_unique<ScAccessibilityEditSource>(
+ std::make_unique<ScAccessiblePreviewHeaderCellTextData>(
+ mpViewShell, getAccessibleName(), maCellPos,
+ mbColumnHeader, mbRowHeader))) );
+ mxTextHelper->SetEventSource(this);
+ }
+}
+
+void ScAccessiblePreviewHeaderCell::FillTableInfo() const
+{
+ if ( mpViewShell && !mpTableInfo )
+ {
+ Size aOutputSize;
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if ( pWindow )
+ aOutputSize = pWindow->GetOutputSizePixel();
+ tools::Rectangle aVisRect( Point(), aOutputSize );
+
+ mpTableInfo.reset( new ScPreviewTableInfo );
+ mpViewShell->GetLocationData().GetTableInfo( aVisRect, *mpTableInfo );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessiblePreviewTable.cxx b/sc/source/ui/Accessibility/AccessiblePreviewTable.cxx
new file mode 100644
index 000000000..2f2cb48f6
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessiblePreviewTable.cxx
@@ -0,0 +1,641 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <AccessiblePreviewTable.hxx>
+#include <AccessiblePreviewCell.hxx>
+#include <AccessiblePreviewHeaderCell.hxx>
+#include <prevwsh.hxx>
+#include <prevloc.hxx>
+#include <attrib.hxx>
+#include <document.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include <vcl/window.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/hint.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <comphelper/sequence.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+//===== internal ============================================================
+
+ScAccessiblePreviewTable::ScAccessiblePreviewTable( const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScPreviewShell* pViewShell, sal_Int32 nIndex ) :
+ ScAccessibleContextBase( rxParent, AccessibleRole::TABLE ),
+ mpViewShell( pViewShell ),
+ mnIndex( nIndex )
+{
+ if (mpViewShell)
+ mpViewShell->AddAccessibilityObject(*this);
+}
+
+ScAccessiblePreviewTable::~ScAccessiblePreviewTable()
+{
+ if (!ScAccessibleContextBase::IsDefunc() && !rBHelper.bInDispose)
+ {
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+}
+
+void SAL_CALL ScAccessiblePreviewTable::disposing()
+{
+ SolarMutexGuard aGuard;
+ if (mpViewShell)
+ {
+ mpViewShell->RemoveAccessibilityObject(*this);
+ mpViewShell = nullptr;
+ }
+
+ mpTableInfo.reset();
+
+ ScAccessibleContextBase::disposing();
+}
+
+//===== SfxListener =====================================================
+
+void ScAccessiblePreviewTable::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ const SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::DataChanged )
+ {
+ // column / row layout may change with any document change,
+ // so it must be invalidated
+ mpTableInfo.reset();
+ }
+ else if (nId == SfxHintId::ScAccVisAreaChanged)
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ CommitChange(aEvent);
+ }
+
+ ScAccessibleContextBase::Notify(rBC, rHint);
+}
+
+//===== XInterface =====================================================
+
+uno::Any SAL_CALL ScAccessiblePreviewTable::queryInterface( uno::Type const & rType )
+{
+ uno::Any aAny (ScAccessiblePreviewTableImpl::queryInterface(rType));
+ return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType);
+}
+
+void SAL_CALL ScAccessiblePreviewTable::acquire()
+ noexcept
+{
+ ScAccessibleContextBase::acquire();
+}
+
+void SAL_CALL ScAccessiblePreviewTable::release()
+ noexcept
+{
+ ScAccessibleContextBase::release();
+}
+
+//===== XAccessibleTable ================================================
+
+sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleRowCount()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ sal_Int32 nRet = 0;
+ if ( mpTableInfo )
+ nRet = mpTableInfo->GetRows();
+ return nRet;
+}
+
+sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleColumnCount()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ sal_Int32 nRet = 0;
+ if ( mpTableInfo )
+ nRet = mpTableInfo->GetCols();
+ return nRet;
+}
+
+OUString SAL_CALL ScAccessiblePreviewTable::getAccessibleRowDescription( sal_Int32 nRow )
+{
+ SolarMutexGuard aGuard;
+ FillTableInfo();
+ if ( nRow < 0 || (mpTableInfo && nRow >= mpTableInfo->GetRows()) )
+ throw lang::IndexOutOfBoundsException();
+
+ return OUString();
+}
+
+OUString SAL_CALL ScAccessiblePreviewTable::getAccessibleColumnDescription( sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ FillTableInfo();
+ if ( nColumn < 0 || (mpTableInfo && nColumn >= mpTableInfo->GetCols()) )
+ throw lang::IndexOutOfBoundsException();
+
+ return OUString();
+}
+
+sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ sal_Int32 nRows = 1;
+ if ( !mpViewShell || !mpTableInfo || nColumn < 0 || nRow < 0 ||
+ nColumn >= mpTableInfo->GetCols() || nRow >= mpTableInfo->GetRows() )
+ throw lang::IndexOutOfBoundsException();
+
+ const ScPreviewColRowInfo& rColInfo = mpTableInfo->GetColInfo()[nColumn];
+ const ScPreviewColRowInfo& rRowInfo = mpTableInfo->GetRowInfo()[nRow];
+
+ if ( rColInfo.bIsHeader || rRowInfo.bIsHeader )
+ {
+ // header cells only span a single cell
+ }
+ else
+ {
+ ScDocument& rDoc = mpViewShell->GetDocument();
+ const ScMergeAttr* pItem = rDoc.GetAttr(
+ static_cast<SCCOL>(rColInfo.nDocIndex), static_cast<SCROW>(rRowInfo.nDocIndex), mpTableInfo->GetTab(), ATTR_MERGE );
+ if ( pItem && pItem->GetRowMerge() > 0 )
+ nRows = pItem->GetRowMerge();
+ }
+
+ return nRows;
+}
+
+sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ sal_Int32 nColumns = 1;
+ if ( !mpViewShell || !mpTableInfo || nColumn < 0 || nRow < 0 ||
+ nColumn >= mpTableInfo->GetCols() || nRow >= mpTableInfo->GetRows() )
+ throw lang::IndexOutOfBoundsException();
+
+ const ScPreviewColRowInfo& rColInfo = mpTableInfo->GetColInfo()[nColumn];
+ const ScPreviewColRowInfo& rRowInfo = mpTableInfo->GetRowInfo()[nRow];
+
+ if ( rColInfo.bIsHeader || rRowInfo.bIsHeader )
+ {
+ // header cells only span a single cell
+ }
+ else
+ {
+ ScDocument& rDoc = mpViewShell->GetDocument();
+ const ScMergeAttr* pItem = rDoc.GetAttr(
+ static_cast<SCCOL>(rColInfo.nDocIndex), static_cast<SCROW>(rRowInfo.nDocIndex), mpTableInfo->GetTab(), ATTR_MERGE );
+ if ( pItem && pItem->GetColMerge() > 0 )
+ nColumns = pItem->GetColMerge();
+ }
+
+ return nColumns;
+}
+
+uno::Reference< XAccessibleTable > SAL_CALL ScAccessiblePreviewTable::getAccessibleRowHeaders()
+{
+ //! missing
+ return nullptr;
+}
+
+uno::Reference< XAccessibleTable > SAL_CALL ScAccessiblePreviewTable::getAccessibleColumnHeaders()
+{
+ //! missing
+ return nullptr;
+}
+
+uno::Sequence< sal_Int32 > SAL_CALL ScAccessiblePreviewTable::getSelectedAccessibleRows()
+{
+ // in the page preview, there is no selection
+ return {};
+}
+
+uno::Sequence< sal_Int32 > SAL_CALL ScAccessiblePreviewTable::getSelectedAccessibleColumns()
+{
+ // in the page preview, there is no selection
+ return {};
+}
+
+sal_Bool SAL_CALL ScAccessiblePreviewTable::isAccessibleRowSelected( sal_Int32 nRow )
+{
+ // in the page preview, there is no selection
+
+ SolarMutexGuard aGuard;
+ FillTableInfo();
+ if ( nRow < 0 || (mpTableInfo && nRow >= mpTableInfo->GetRows()) )
+ throw lang::IndexOutOfBoundsException();
+
+ return false;
+}
+
+sal_Bool SAL_CALL ScAccessiblePreviewTable::isAccessibleColumnSelected( sal_Int32 nColumn )
+{
+ // in the page preview, there is no selection
+
+ SolarMutexGuard aGuard;
+ FillTableInfo();
+ if ( nColumn < 0 || (mpTableInfo && nColumn >= mpTableInfo->GetCols()) )
+ throw lang::IndexOutOfBoundsException();
+
+ return false;
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ uno::Reference<XAccessible> xRet;
+ if ( mpTableInfo && nColumn >= 0 && nRow >= 0 && nColumn < mpTableInfo->GetCols() && nRow < mpTableInfo->GetRows() )
+ {
+ // index iterates horizontally
+ tools::Long nNewIndex = nRow * mpTableInfo->GetCols() + nColumn;
+
+ const ScPreviewColRowInfo& rColInfo = mpTableInfo->GetColInfo()[nColumn];
+ const ScPreviewColRowInfo& rRowInfo = mpTableInfo->GetRowInfo()[nRow];
+
+ ScAddress aCellPos( static_cast<SCCOL>(rColInfo.nDocIndex), static_cast<SCROW>(rRowInfo.nDocIndex), mpTableInfo->GetTab() );
+ if ( rColInfo.bIsHeader || rRowInfo.bIsHeader )
+ {
+ const bool bRotatedColHeader = rRowInfo.bIsHeader;
+ const bool bRotatedRowHeader = rColInfo.bIsHeader;
+ rtl::Reference<ScAccessiblePreviewHeaderCell> pHeaderCell(new ScAccessiblePreviewHeaderCell(this, mpViewShell, aCellPos,
+ bRotatedColHeader, bRotatedRowHeader, nNewIndex));
+ xRet = pHeaderCell.get();
+ pHeaderCell->Init();
+ }
+ else
+ {
+ rtl::Reference<ScAccessiblePreviewCell> pCell(new ScAccessiblePreviewCell( this, mpViewShell, aCellPos, nNewIndex ));
+ xRet = pCell.get();
+ pCell->Init();
+ }
+ }
+
+ if ( !xRet.is() )
+ throw lang::IndexOutOfBoundsException();
+
+ return xRet;
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleCaption()
+{
+ //! missing
+ return nullptr;
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleSummary()
+{
+ //! missing
+ return nullptr;
+}
+
+sal_Bool SAL_CALL ScAccessiblePreviewTable::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ // in the page preview, there is no selection
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ if ( !mpTableInfo || nColumn < 0 || nRow < 0 || nColumn >= mpTableInfo->GetCols() || nRow >= mpTableInfo->GetRows() )
+ throw lang::IndexOutOfBoundsException();
+
+ // index iterates horizontally
+ return false;
+}
+
+sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ if ( !mpTableInfo || nColumn < 0 || nRow < 0 || nColumn >= mpTableInfo->GetCols() || nRow >= mpTableInfo->GetRows() )
+ throw lang::IndexOutOfBoundsException();
+
+ // index iterates horizontally
+ sal_Int32 nRet = nRow * mpTableInfo->GetCols() + nColumn;
+ return nRet;
+}
+
+sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleRow( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ if ( !mpTableInfo || nChildIndex < 0 || nChildIndex >= static_cast<sal_Int32>(mpTableInfo->GetRows()) * mpTableInfo->GetCols() )
+ throw lang::IndexOutOfBoundsException();
+
+ sal_Int32 nRow = nChildIndex / mpTableInfo->GetCols();
+ return nRow;
+}
+
+sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleColumn( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ if ( !mpTableInfo || nChildIndex < 0 || nChildIndex >= static_cast<sal_Int32>(mpTableInfo->GetRows()) * mpTableInfo->GetCols() )
+ throw lang::IndexOutOfBoundsException();
+
+ sal_Int32 nCol = nChildIndex % static_cast<sal_Int32>(mpTableInfo->GetCols());
+ return nCol;
+}
+
+//===== XAccessibleComponent ============================================
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleAtPoint( const awt::Point& aPoint )
+{
+ uno::Reference<XAccessible> xRet;
+ if (containsPoint(aPoint))
+ {
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ if ( mpTableInfo )
+ {
+ SCCOL nCols = mpTableInfo->GetCols();
+ SCROW nRows = mpTableInfo->GetRows();
+ const ScPreviewColRowInfo* pColInfo = mpTableInfo->GetColInfo();
+ const ScPreviewColRowInfo* pRowInfo = mpTableInfo->GetRowInfo();
+
+ tools::Rectangle aScreenRect(GetBoundingBox());
+
+ awt::Point aMovedPoint = aPoint;
+ aMovedPoint.X += aScreenRect.Left();
+ aMovedPoint.Y += aScreenRect.Top();
+
+ if ( nCols > 0 && nRows > 0 && aMovedPoint.X >= pColInfo[0].nPixelStart && aMovedPoint.Y >= pRowInfo[0].nPixelStart )
+ {
+ SCCOL nColIndex = 0;
+ while ( nColIndex < nCols && aMovedPoint.X > pColInfo[nColIndex].nPixelEnd )
+ ++nColIndex;
+ SCROW nRowIndex = 0;
+ while ( nRowIndex < nRows && aMovedPoint.Y > pRowInfo[nRowIndex].nPixelEnd )
+ ++nRowIndex;
+ if ( nColIndex < nCols && nRowIndex < nRows )
+ {
+ try
+ {
+ xRet = getAccessibleCellAt( nRowIndex, nColIndex );
+ }
+ catch (uno::Exception&)
+ {
+ }
+ }
+ }
+ }
+ }
+
+ return xRet;
+}
+
+void SAL_CALL ScAccessiblePreviewTable::grabFocus()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
+ if (xAccessibleComponent.is())
+ xAccessibleComponent->grabFocus();
+ }
+}
+
+//===== XAccessibleContext ==============================================
+
+sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ tools::Long nRet = 0;
+ if ( mpTableInfo )
+ nRet = static_cast<sal_Int32>(mpTableInfo->GetCols()) * mpTableInfo->GetRows();
+ return nRet;
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessiblePreviewTable::getAccessibleChild( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ FillTableInfo();
+
+ uno::Reference<XAccessible> xRet;
+ if ( mpTableInfo )
+ {
+ sal_Int32 nColumns = mpTableInfo->GetCols();
+ if ( nColumns > 0 )
+ {
+ // nCol, nRow are within the visible table, not the document
+ sal_Int32 nCol = nIndex % nColumns;
+ sal_Int32 nRow = nIndex / nColumns;
+
+ xRet = getAccessibleCellAt( nRow, nCol );
+ }
+ }
+
+ if ( !xRet.is() )
+ throw lang::IndexOutOfBoundsException();
+
+ return xRet;
+}
+
+sal_Int32 SAL_CALL ScAccessiblePreviewTable::getAccessibleIndexInParent()
+{
+ return mnIndex;
+}
+
+uno::Reference< XAccessibleStateSet > SAL_CALL ScAccessiblePreviewTable::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<XAccessibleStateSet> xParentStates;
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
+ xParentStates = xParentContext->getAccessibleStateSet();
+ }
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSet = new utl::AccessibleStateSetHelper();
+ if (IsDefunc(xParentStates))
+ pStateSet->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ pStateSet->AddState(AccessibleStateType::MANAGES_DESCENDANTS);
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::OPAQUE);
+ if (isShowing())
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ if (isVisible())
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ }
+ return pStateSet;
+}
+
+//===== XServiceInfo ====================================================
+
+OUString SAL_CALL ScAccessiblePreviewTable::getImplementationName()
+{
+ return "ScAccessiblePreviewTable";
+}
+
+uno::Sequence<OUString> SAL_CALL ScAccessiblePreviewTable::getSupportedServiceNames()
+{
+ uno::Sequence< OUString > aSequence = ScAccessibleContextBase::getSupportedServiceNames();
+ sal_Int32 nOldSize(aSequence.getLength());
+ aSequence.realloc(nOldSize + 1);
+
+ aSequence.getArray()[nOldSize] = "com.sun.star.table.AccessibleTableView";
+
+ return aSequence;
+}
+
+//===== XTypeProvider ===================================================
+
+uno::Sequence< uno::Type > SAL_CALL ScAccessiblePreviewTable::getTypes()
+{
+ return comphelper::concatSequences(ScAccessiblePreviewTableImpl::getTypes(), ScAccessibleContextBase::getTypes());
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScAccessiblePreviewTable::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+//==== internal =========================================================
+
+OUString ScAccessiblePreviewTable::createAccessibleDescription()
+{
+ return STR_ACC_TABLE_DESCR;
+}
+
+OUString ScAccessiblePreviewTable::createAccessibleName()
+{
+ OUString sName(ScResId(STR_ACC_TABLE_NAME));
+
+ if (mpViewShell)
+ {
+ FillTableInfo();
+
+ if ( mpTableInfo )
+ {
+ OUString sCoreName;
+ if (mpViewShell->GetDocument().GetName( mpTableInfo->GetTab(), sCoreName ))
+ sName = sName.replaceFirst("%1", sCoreName);
+ }
+ }
+
+ return sName;
+}
+
+tools::Rectangle ScAccessiblePreviewTable::GetBoundingBoxOnScreen() const
+{
+ tools::Rectangle aCellRect(GetBoundingBox());
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if (pWindow)
+ {
+ tools::Rectangle aRect = pWindow->GetWindowExtentsRelative(nullptr);
+ aCellRect.Move(aRect.Left(), aRect.Top());
+ }
+ }
+ return aCellRect;
+}
+
+tools::Rectangle ScAccessiblePreviewTable::GetBoundingBox() const
+{
+ FillTableInfo();
+
+ tools::Rectangle aRect;
+ if ( mpTableInfo )
+ {
+ SCCOL nColumns = mpTableInfo->GetCols();
+ SCROW nRows = mpTableInfo->GetRows();
+ if ( nColumns > 0 && nRows > 0 )
+ {
+ const ScPreviewColRowInfo* pColInfo = mpTableInfo->GetColInfo();
+ const ScPreviewColRowInfo* pRowInfo = mpTableInfo->GetRowInfo();
+
+ aRect = tools::Rectangle( pColInfo[0].nPixelStart,
+ pRowInfo[0].nPixelStart,
+ pColInfo[nColumns-1].nPixelEnd,
+ pRowInfo[nRows-1].nPixelEnd );
+ }
+ }
+ return aRect;
+}
+
+bool ScAccessiblePreviewTable::IsDefunc( const uno::Reference<XAccessibleStateSet>& rxParentStates )
+{
+ return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
+ (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
+}
+
+void ScAccessiblePreviewTable::FillTableInfo() const
+{
+ if ( mpViewShell && !mpTableInfo )
+ {
+ Size aOutputSize;
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if ( pWindow )
+ aOutputSize = pWindow->GetOutputSizePixel();
+ tools::Rectangle aVisRect( Point(), aOutputSize );
+
+ mpTableInfo.reset( new ScPreviewTableInfo );
+ mpViewShell->GetLocationData().GetTableInfo( aVisRect, *mpTableInfo );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessibleSpreadsheet.cxx b/sc/source/ui/Accessibility/AccessibleSpreadsheet.cxx
new file mode 100644
index 000000000..e435c37e7
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleSpreadsheet.cxx
@@ -0,0 +1,1667 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleSpreadsheet.hxx>
+#include <AccessibleCell.hxx>
+#include <AccessibleDocument.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <hints.hxx>
+#include <scmod.hxx>
+#include <markdata.hxx>
+#include <gridwin.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <unotools/accessiblestatesethelper.hxx>
+#include <unotools/accessiblerelationsethelper.hxx>
+#include <com/sun/star/accessibility/AccessibleStateType.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChangeType.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <sal/log.hxx>
+#include <tools/gen.hxx>
+#include <svtools/colorcfg.hxx>
+#include <vcl/svapp.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+#include <algorithm>
+#include <cstdlib>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+static bool CompMinCol(const std::pair<sal_uInt16,sal_uInt16> & pc1,const std::pair<sal_uInt16,sal_uInt16> &pc2)
+{
+ return pc1.first < pc2.first;
+}
+
+ScMyAddress ScAccessibleSpreadsheet::CalcScAddressFromRangeList(ScRangeList *pMarkedRanges,sal_Int32 nSelectedChildIndex)
+{
+ if (pMarkedRanges->size() <= 1)
+ {
+ ScRange const & rRange = pMarkedRanges->front();
+ // MT IA2: Not used.
+ // const int nRowNum = rRange.aEnd.Row() - rRange.aStart.Row() + 1;
+ const int nColNum = rRange.aEnd.Col() - rRange.aStart.Col() + 1;
+ const int nCurCol = nSelectedChildIndex % nColNum;
+ const int nCurRow = (nSelectedChildIndex - nCurCol)/nColNum;
+ return ScMyAddress(static_cast<SCCOL>(rRange.aStart.Col() + nCurCol), rRange.aStart.Row() + nCurRow, maActiveCell.Tab());
+ }
+ else
+ {
+ ScDocument* pDoc= GetDocument(mpViewShell);
+ sal_Int32 nMinRow = pDoc->MaxRow();
+ sal_Int32 nMaxRow = 0;
+ std::vector<ScRange> aRanges;
+ size_t nSize = pMarkedRanges->size();
+ for (size_t i = 0; i < nSize; ++i)
+ {
+ ScRange const & rRange = (*pMarkedRanges)[i];
+ if (rRange.aStart.Tab() != rRange.aEnd.Tab())
+ {
+ if ((maActiveCell.Tab() >= rRange.aStart.Tab()) ||
+ maActiveCell.Tab() <= rRange.aEnd.Tab())
+ {
+ aRanges.push_back(rRange);
+ nMinRow = std::min(rRange.aStart.Row(),nMinRow);
+ nMaxRow = std::max(rRange.aEnd.Row(),nMaxRow);
+ }
+ else
+ SAL_WARN("sc", "Range of wrong table");
+ }
+ else if(rRange.aStart.Tab() == maActiveCell.Tab())
+ {
+ aRanges.push_back(rRange);
+ nMinRow = std::min(rRange.aStart.Row(),nMinRow);
+ nMaxRow = std::max(rRange.aEnd.Row(),nMaxRow);
+ }
+ else
+ SAL_WARN("sc", "Range of wrong table");
+ }
+ int nCurrentIndex = 0 ;
+ for(sal_Int32 row = nMinRow ; row <= nMaxRow ; ++row)
+ {
+ std::vector<std::pair<SCCOL, SCCOL>> aVecCol;
+ for (ScRange const & r : aRanges)
+ {
+ if ( row >= r.aStart.Row() && row <= r.aEnd.Row())
+ {
+ aVecCol.emplace_back(r.aStart.Col(), r.aEnd.Col());
+ }
+ }
+ std::sort(aVecCol.begin(), aVecCol.end(), CompMinCol);
+ for (const std::pair<SCCOL, SCCOL> &pairCol : aVecCol)
+ {
+ SCCOL nCol = pairCol.second - pairCol.first + 1;
+ if (nCol + nCurrentIndex > nSelectedChildIndex)
+ {
+ return ScMyAddress(static_cast<SCCOL>(pairCol.first + nSelectedChildIndex - nCurrentIndex), row, maActiveCell.Tab());
+ }
+ nCurrentIndex += nCol;
+ }
+ }
+ }
+ return ScMyAddress(0,0,maActiveCell.Tab());
+}
+
+bool ScAccessibleSpreadsheet::CalcScRangeDifferenceMax(const ScRange & rSrc, const ScRange & rDest, int nMax,
+ std::vector<ScMyAddress> &vecRet, int &nSize)
+{
+ //Src Must be :Src > Dest
+ if (rDest.Contains(rSrc))
+ {//Here is Src In Dest,Src <= Dest
+ return false;
+ }
+ if (!rDest.Intersects(rSrc))
+ {
+ int nCellCount = sal_uInt32(rDest.aEnd.Col() - rDest.aStart.Col() + 1)
+ * sal_uInt32(rDest.aEnd.Row() - rDest.aStart.Row() + 1)
+ * sal_uInt32(rDest.aEnd.Tab() - rDest.aStart.Tab() + 1);
+ if (nCellCount + nSize > nMax)
+ {
+ return true;
+ }
+ else if(nCellCount > 0)
+ {
+ for (sal_Int32 row = rDest.aStart.Row(); row <= rDest.aEnd.Row();++row)
+ {
+ for (sal_uInt16 col = rDest.aStart.Col(); col <= rDest.aEnd.Col();++col)
+ {
+ vecRet.emplace_back(col,row,rDest.aStart.Tab());
+ }
+ }
+ }
+ return false;
+ }
+ sal_Int32 nMinRow = rSrc.aStart.Row();
+ sal_Int32 nMaxRow = rSrc.aEnd.Row();
+ for (; nMinRow <= nMaxRow ; ++nMinRow,--nMaxRow)
+ {
+ for (sal_uInt16 col = rSrc.aStart.Col(); col <= rSrc.aEnd.Col();++col)
+ {
+ if (nSize > nMax)
+ {
+ return true;
+ }
+ ScMyAddress cell(col,nMinRow,rSrc.aStart.Tab());
+ if(!rDest.Contains(cell))
+ {//In Src ,Not In Dest
+ vecRet.push_back(cell);
+ ++nSize;
+ }
+ }
+ if (nMinRow != nMaxRow)
+ {
+ for (sal_uInt16 col = rSrc.aStart.Col(); col <= rSrc.aEnd.Col();++col)
+ {
+ if (nSize > nMax)
+ {
+ return true;
+ }
+ ScMyAddress cell(col,nMaxRow,rSrc.aStart.Tab());
+ if(!rDest.Contains(cell))
+ {//In Src ,Not In Dest
+ vecRet.push_back(cell);
+ ++nSize;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+//In Src , Not in Dest
+bool ScAccessibleSpreadsheet::CalcScRangeListDifferenceMax(ScRangeList *pSrc, ScRangeList *pDest,
+ int nMax, std::vector<ScMyAddress> &vecRet)
+{
+ if (pSrc == nullptr || pDest == nullptr)
+ {
+ return false;
+ }
+ int nSize =0;
+ if (pDest->GetCellCount() == 0)//if the Dest Rang List is empty
+ {
+ if (pSrc->GetCellCount() > o3tl::make_unsigned(nMax))//if the Src Cell count is greater than nMax
+ {
+ return true;
+ }
+ //now the cell count is less than nMax
+ vecRet.reserve(10);
+ size_t nSrcSize = pSrc->size();
+ for (size_t i = 0; i < nSrcSize; ++i)
+ {
+ ScRange const & rRange = (*pSrc)[i];
+ for (sal_Int32 row = rRange.aStart.Row(); row <= rRange.aEnd.Row();++row)
+ {
+ for (sal_uInt16 col = rRange.aStart.Col(); col <= rRange.aEnd.Col();++col)
+ {
+ vecRet.emplace_back(col,row, rRange.aStart.Tab());
+ }
+ }
+ }
+ return false;
+ }
+ //the Dest Rang List is not empty
+ vecRet.reserve(10);
+ size_t nSizeSrc = pSrc->size();
+ for (size_t i = 0; i < nSizeSrc; ++i)
+ {
+ ScRange const & rRange = (*pSrc)[i];
+ size_t nSizeDest = pDest->size();
+ for (size_t j = 0; j < nSizeDest; ++j)
+ {
+ ScRange const & rRangeDest = (*pDest)[j];
+ if (CalcScRangeDifferenceMax(rRange,rRangeDest,nMax,vecRet,nSize))
+ {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+//===== internal ============================================================
+
+// FIXME: really unclear why we have an ScAccessibleTableBase with
+// only this single sub-class
+ScAccessibleSpreadsheet::ScAccessibleSpreadsheet(
+ ScAccessibleDocument* pAccDoc,
+ ScTabViewShell* pViewShell,
+ SCTAB nTab,
+ ScSplitPos eSplitPos)
+ :
+ ScAccessibleTableBase( pAccDoc, GetDocument(pViewShell), ScRange( 0, 0, nTab, GetDocument(pViewShell)->MaxCol(), GetDocument(pViewShell)->MaxRow(), nTab)),
+ mbIsSpreadsheet( true ),
+ m_bFormulaMode( false ),
+ m_bFormulaLastMode( false ),
+ m_nMinX(0),m_nMaxX(0),m_nMinY(0),m_nMaxY(0)
+{
+ ConstructScAccessibleSpreadsheet( pAccDoc, pViewShell, nTab, eSplitPos );
+}
+
+ScAccessibleSpreadsheet::ScAccessibleSpreadsheet(
+ ScAccessibleSpreadsheet& rParent, const ScRange& rRange ) :
+ ScAccessibleTableBase( rParent.mpAccDoc, rParent.mpDoc, rRange),
+ mbIsSpreadsheet( false ),
+ m_bFormulaMode( false ),
+ m_bFormulaLastMode( false ),
+ m_nMinX(0),m_nMaxX(0),m_nMinY(0),m_nMaxY(0)
+{
+ ConstructScAccessibleSpreadsheet( rParent.mpAccDoc, rParent.mpViewShell, rParent.mnTab, rParent.meSplitPos );
+}
+
+ScAccessibleSpreadsheet::~ScAccessibleSpreadsheet()
+{
+ mpMarkedRanges.reset();
+ if (mpViewShell)
+ mpViewShell->RemoveAccessibilityObject(*this);
+}
+
+void ScAccessibleSpreadsheet::ConstructScAccessibleSpreadsheet(
+ ScAccessibleDocument* pAccDoc,
+ ScTabViewShell* pViewShell,
+ SCTAB nTab,
+ ScSplitPos eSplitPos)
+{
+ mpViewShell = pViewShell;
+ mpMarkedRanges = nullptr;
+ mpAccDoc = pAccDoc;
+ mpAccCell.clear();
+ meSplitPos = eSplitPos;
+ mnTab = nTab;
+ mbDelIns = false;
+ mbIsFocusSend = false;
+ if (!mpViewShell)
+ return;
+
+ mpViewShell->AddAccessibilityObject(*this);
+
+ const ScViewData& rViewData = mpViewShell->GetViewData();
+ maActiveCell = rViewData.GetCurPos();
+ mpAccCell = GetAccessibleCellAt(maActiveCell.Row(), maActiveCell.Col());
+ ScDocument* pScDoc= GetDocument(mpViewShell);
+ if (pScDoc)
+ {
+ pScDoc->GetName( maActiveCell.Tab(), m_strOldTabName );
+ }
+}
+
+void SAL_CALL ScAccessibleSpreadsheet::disposing()
+{
+ SolarMutexGuard aGuard;
+ if (mpViewShell)
+ {
+ mpViewShell->RemoveAccessibilityObject(*this);
+ mpViewShell = nullptr;
+ }
+ mpAccCell.clear();
+
+ ScAccessibleTableBase::disposing();
+}
+
+void ScAccessibleSpreadsheet::CompleteSelectionChanged(bool bNewState)
+{
+ if (IsFormulaMode())
+ {
+ return ;
+ }
+ mpMarkedRanges.reset();
+
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::STATE_CHANGED;
+ if (bNewState)
+ aEvent.NewValue <<= AccessibleStateType::SELECTED;
+ else
+ aEvent.OldValue <<= AccessibleStateType::SELECTED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+
+ CommitChange(aEvent);
+}
+
+void ScAccessibleSpreadsheet::LostFocus()
+{
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ aEvent.OldValue <<= uno::Reference<XAccessible>(mpAccCell);
+
+ CommitChange(aEvent);
+
+ CommitFocusLost();
+}
+
+void ScAccessibleSpreadsheet::GotFocus()
+{
+ CommitFocusGained();
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ uno::Reference< XAccessible > xNew;
+ if (IsFormulaMode())
+ {
+ if (!m_pAccFormulaCell.is() || !m_bFormulaLastMode)
+ {
+ ScAddress aFormulaAddr;
+ if(!GetFormulaCurrentFocusCell(aFormulaAddr))
+ {
+ return;
+ }
+ m_pAccFormulaCell = GetAccessibleCellAt(aFormulaAddr.Row(),aFormulaAddr.Col());
+ }
+ xNew = m_pAccFormulaCell.get();
+ }
+ else
+ {
+ if(mpAccCell->GetCellAddress() == maActiveCell)
+ {
+ xNew = mpAccCell.get();
+ }
+ else
+ {
+ CommitFocusCell(maActiveCell);
+ return ;
+ }
+ }
+ aEvent.NewValue <<= xNew;
+
+ CommitChange(aEvent);
+}
+
+void ScAccessibleSpreadsheet::BoundingBoxChanged()
+{
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::BOUNDRECT_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+
+ CommitChange(aEvent);
+}
+
+void ScAccessibleSpreadsheet::VisAreaChanged()
+{
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::VISIBLE_DATA_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+
+ CommitChange(aEvent);
+}
+
+ //===== SfxListener =====================================================
+
+void ScAccessibleSpreadsheet::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if ( auto pRefHint = dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ if (pRefHint->GetMode() == URM_INSDEL && pRefHint->GetDz() == 0) //test whether table is inserted or deleted
+ {
+ if (((pRefHint->GetRange().aStart.Col() == maRange.aStart.Col()) &&
+ (pRefHint->GetRange().aEnd.Col() == maRange.aEnd.Col())) ||
+ ((pRefHint->GetRange().aStart.Row() == maRange.aStart.Row()) &&
+ (pRefHint->GetRange().aEnd.Row() == maRange.aEnd.Row())))
+ {
+ // ignore next SfxHintId::ScDataChanged notification
+ mbDelIns = true;
+
+ SCROW nFirstRow = -1;
+ SCROW nLastRow = -1;
+ SCCOL nFirstCol = -1;
+ SCCOL nLastCol = -1;
+
+ sal_Int16 nId(0);
+ SCCOL nX(pRefHint->GetDx());
+ SCROW nY(pRefHint->GetDy());
+ ScRange aRange(pRefHint->GetRange());
+ if ((nX < 0) || (nY < 0))
+ {
+ assert(!((nX < 0) && (nY < 0)) && "should not be possible to remove row and column at the same time");
+
+ // Range in the update hint is the range after the removed rows/columns;
+ // calculate indices for the removed ones from that
+ if (nX < 0)
+ {
+ nId = AccessibleTableModelChangeType::COLUMNS_REMOVED;
+ nFirstCol = aRange.aStart.Col() + nX;
+ nLastCol = aRange.aStart.Col() - 1;
+ }
+ else
+ {
+ nId = AccessibleTableModelChangeType::ROWS_REMOVED;
+ nFirstRow = aRange.aStart.Row() + nY;
+ nLastRow = aRange.aStart.Row() - 1;
+ }
+ }
+ else if ((nX > 0) || (nY > 0))
+ {
+ assert(!((nX > 0) && (nY > 0)) && "should not be possible to add row and column at the same time");
+
+ // Range in the update hint is from first inserted row/column to last one in spreadsheet;
+ // calculate indices for the inserted ones from that
+ if (nX > 0)
+ {
+ nId = AccessibleTableModelChangeType::COLUMNS_INSERTED;
+ nFirstCol = aRange.aStart.Col();
+ nLastCol = aRange.aStart.Col() + nX - 1;
+ }
+ else
+ {
+ nId = AccessibleTableModelChangeType::ROWS_INSERTED;
+ nFirstRow = aRange.aStart.Row();
+ nLastRow = aRange.aStart.Row() + nY -1;
+ }
+ }
+ else
+ {
+ assert(false && "is it a deletion or an insertion?");
+ }
+
+ CommitTableModelChange(nFirstRow, nFirstCol, nLastRow, nLastCol, nId);
+
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ aEvent.NewValue <<= uno::Reference<XAccessible>(mpAccCell);
+
+ CommitChange(aEvent);
+ }
+ }
+ }
+ else
+ {
+ if (rHint.GetId() == SfxHintId::ScAccCursorChanged)
+ {
+ if (mpViewShell)
+ {
+ ScViewData& rViewData = mpViewShell->GetViewData();
+
+ m_bFormulaMode = rViewData.IsRefMode() || SC_MOD()->IsFormulaMode();
+ if ( m_bFormulaMode )
+ {
+ NotifyRefMode();
+ m_bFormulaLastMode = true;
+ return;
+ }
+ if (m_bFormulaLastMode)
+ {//Last Notify Mode Is Formula Mode.
+ m_vecFormulaLastMyAddr.clear();
+ RemoveFormulaSelection(true);
+ m_pAccFormulaCell.clear();
+ //Remove All Selection
+ }
+ m_bFormulaLastMode = m_bFormulaMode;
+
+ AccessibleEventObject aEvent;
+ aEvent.Source = uno::Reference< XAccessible >(this);
+ ScAddress aNewCell = rViewData.GetCurPos();
+ if(aNewCell.Tab() != maActiveCell.Tab())
+ {
+ aEvent.EventId = AccessibleEventId::PAGE_CHANGED;
+ auto pAccParent = getAccessibleParent();
+ ScAccessibleDocument *pAccDoc =
+ static_cast<ScAccessibleDocument*>(pAccParent.get());
+ if(pAccDoc)
+ {
+ pAccDoc->CommitChange(aEvent);
+ }
+ }
+ bool bNewPosCell = (aNewCell != maActiveCell) || mpViewShell->GetForceFocusOnCurCell(); // #i123629#
+ bool bNewPosCellFocus=false;
+ if ( bNewPosCell && IsFocused() && aNewCell.Tab() == maActiveCell.Tab() )
+ {//single Focus
+ bNewPosCellFocus=true;
+ }
+ ScMarkData &refScMarkData = rViewData.GetMarkData();
+ // MT IA2: Not used
+ // int nSelCount = refScMarkData.GetSelectCount();
+ bool bIsMark =refScMarkData.IsMarked();
+ bool bIsMultMark = refScMarkData.IsMultiMarked();
+ bool bNewMarked = refScMarkData.GetTableSelect(aNewCell.Tab()) && ( bIsMark || bIsMultMark );
+// sal_Bool bNewCellSelected = isAccessibleSelected(aNewCell.Row(), aNewCell.Col());
+ sal_uInt16 nTab = rViewData.GetTabNo();
+ const ScRange& aMarkRange = refScMarkData.GetMarkArea();
+ aEvent.OldValue.clear();
+ ScDocument* pDoc= GetDocument(mpViewShell);
+ //Mark All
+ if ( !bNewPosCellFocus &&
+ (bNewMarked || bIsMark || bIsMultMark ) &&
+ aMarkRange == ScRange( 0,0,nTab, pDoc->MaxCol(),pDoc->MaxRow(),nTab ) )
+ {
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
+ aEvent.NewValue.clear();
+ CommitChange(aEvent);
+ return ;
+ }
+ if (!mpMarkedRanges)
+ {
+ mpMarkedRanges.reset(new ScRangeList());
+ }
+ refScMarkData.FillRangeListWithMarks(mpMarkedRanges.get(), true);
+
+ //For Whole Col Row
+ bool bWholeRow = std::abs(aMarkRange.aStart.Row() - aMarkRange.aEnd.Row()) == pDoc->MaxRow() ;
+ bool bWholeCol = ::abs(aMarkRange.aStart.Col() - aMarkRange.aEnd.Col()) == pDoc->MaxCol() ;
+ if ((bNewMarked || bIsMark || bIsMultMark ) && (bWholeCol || bWholeRow))
+ {
+ if ( aMarkRange != m_aLastWithInMarkRange )
+ {
+ RemoveSelection(refScMarkData);
+ if(bNewPosCell)
+ {
+ CommitFocusCell(aNewCell);
+ }
+ bool bLastIsWholeColRow =
+ (std::abs(m_aLastWithInMarkRange.aStart.Row() - m_aLastWithInMarkRange.aEnd.Row()) == pDoc->MaxRow() && bWholeRow) ||
+ (::abs(m_aLastWithInMarkRange.aStart.Col() - m_aLastWithInMarkRange.aEnd.Col()) == pDoc->MaxCol() && bWholeCol);
+ bool bSelSmaller=
+ bLastIsWholeColRow &&
+ !aMarkRange.Contains(m_aLastWithInMarkRange) &&
+ aMarkRange.Intersects(m_aLastWithInMarkRange);
+ if( !bSelSmaller )
+ {
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
+ aEvent.NewValue.clear();
+ CommitChange(aEvent);
+ }
+ m_aLastWithInMarkRange = aMarkRange;
+ }
+ return ;
+ }
+ m_aLastWithInMarkRange = aMarkRange;
+ int nNewMarkCount = mpMarkedRanges->GetCellCount();
+ bool bSendSingle= (0 == nNewMarkCount) && bNewPosCell;
+ if (bSendSingle)
+ {
+ RemoveSelection(refScMarkData);
+ if(bNewPosCellFocus)
+ {
+ CommitFocusCell(aNewCell);
+ }
+ uno::Reference< XAccessible > xChild ;
+ if (bNewPosCellFocus)
+ {
+ xChild = mpAccCell.get();
+ }
+ else
+ {
+ mpAccCell = GetAccessibleCellAt(aNewCell.Row(),aNewCell.Col());
+ xChild = mpAccCell.get();
+
+ maActiveCell = aNewCell;
+ aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS;
+ aEvent.NewValue <<= xChild;
+ aEvent.OldValue <<= uno::Reference< XAccessible >();
+ CommitChange(aEvent);
+ }
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
+ aEvent.NewValue <<= xChild;
+ CommitChange(aEvent);
+ OSL_ASSERT(m_mapSelectionSend.count(aNewCell) == 0 );
+ m_mapSelectionSend.emplace(aNewCell,xChild);
+
+ }
+ else
+ {
+ ScRange aDelRange;
+ bool bIsDel = rViewData.GetDelMark( aDelRange );
+ if ( (!bIsDel || aMarkRange != aDelRange) &&
+ bNewMarked &&
+ nNewMarkCount > 0 &&
+ m_LastMarkedRanges != *mpMarkedRanges )
+ {
+ RemoveSelection(refScMarkData);
+ if(bNewPosCellFocus)
+ {
+ CommitFocusCell(aNewCell);
+ }
+ std::vector<ScMyAddress> vecNew;
+ if(CalcScRangeListDifferenceMax(mpMarkedRanges.get(), &m_LastMarkedRanges,10,vecNew))
+ {
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
+ aEvent.NewValue.clear();
+ CommitChange(aEvent);
+ }
+ else
+ {
+ for(const auto& rAddr : vecNew)
+ {
+ uno::Reference< XAccessible > xChild = getAccessibleCellAt(rAddr.Row(),rAddr.Col());
+ if (!(bNewPosCellFocus && rAddr == aNewCell) )
+ {
+ aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS;
+ aEvent.NewValue <<= xChild;
+ CommitChange(aEvent);
+ }
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD;
+ aEvent.NewValue <<= xChild;
+ CommitChange(aEvent);
+ m_mapSelectionSend.emplace(rAddr,xChild);
+ }
+ }
+ }
+ }
+ if (bNewPosCellFocus && maActiveCell != aNewCell)
+ {
+ CommitFocusCell(aNewCell);
+ }
+ m_LastMarkedRanges = *mpMarkedRanges;
+ }
+ }
+ else if (rHint.GetId() == SfxHintId::ScDataChanged)
+ {
+ if (!mbDelIns)
+ CommitTableModelChange(maRange.aStart.Row(), maRange.aStart.Col(), maRange.aEnd.Row(), maRange.aEnd.Col(), AccessibleTableModelChangeType::UPDATE);
+ else
+ mbDelIns = false;
+ if (mpViewShell)
+ {
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ ScAddress aNewCell = rViewData.GetCurPos();
+ if( maActiveCell == aNewCell)
+ {
+ ScDocument* pScDoc= GetDocument(mpViewShell);
+ if (pScDoc)
+ {
+ OUString valStr(pScDoc->GetString(aNewCell.Col(),aNewCell.Row(),aNewCell.Tab()));
+ if(m_strCurCellValue != valStr)
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::VALUE_CHANGED;
+ mpAccCell->CommitChange(aEvent);
+ m_strCurCellValue=valStr;
+ }
+ OUString tabName;
+ pScDoc->GetName( maActiveCell.Tab(), tabName );
+ if( m_strOldTabName != tabName )
+ {
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::NAME_CHANGED;
+ OUString sOldName(ScResId(STR_ACC_TABLE_NAME));
+ sOldName = sOldName.replaceFirst("%1", m_strOldTabName);
+ aEvent.OldValue <<= sOldName;
+ OUString sNewName(ScResId(STR_ACC_TABLE_NAME));
+ sNewName = sNewName.replaceFirst("%1", tabName);
+ aEvent.NewValue <<= sNewName;
+ CommitChange( aEvent );
+ m_strOldTabName = tabName;
+ }
+ }
+ }
+ }
+ }
+ // commented out, because to use a ModelChangeEvent is not the right way
+ // at the moment there is no way, but the Java/Gnome Api should be extended sometime
+/* if (mpViewShell)
+ {
+ Rectangle aNewVisCells(GetVisCells(GetVisArea(mpViewShell, meSplitPos)));
+
+ Rectangle aNewPos(aNewVisCells);
+
+ if (aNewVisCells.Overlaps(maVisCells))
+ aNewPos.Union(maVisCells);
+ else
+ CommitTableModelChange(maVisCells.Top(), maVisCells.Left(), maVisCells.Bottom(), maVisCells.Right(), AccessibleTableModelChangeType::UPDATE);
+
+ maVisCells = aNewVisCells;
+
+ CommitTableModelChange(aNewPos.Top(), aNewPos.Left(), aNewPos.Bottom(), aNewPos.Right(), AccessibleTableModelChangeType::UPDATE);
+ }
+ }*/
+ }
+
+ ScAccessibleTableBase::Notify(rBC, rHint);
+}
+
+void ScAccessibleSpreadsheet::RemoveSelection(const ScMarkData &refScMarkData)
+{
+ AccessibleEventObject aEvent;
+ aEvent.Source = uno::Reference< XAccessible >(this);
+ MAP_ADDR_XACC::iterator miRemove = m_mapSelectionSend.begin();
+ while (miRemove != m_mapSelectionSend.end())
+ {
+ if (refScMarkData.IsCellMarked(miRemove->first.Col(),miRemove->first.Row(),true) ||
+ refScMarkData.IsCellMarked(miRemove->first.Col(),miRemove->first.Row()) )
+ {
+ ++miRemove;
+ continue;
+ }
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
+ aEvent.NewValue <<= miRemove->second;
+ CommitChange(aEvent);
+ miRemove = m_mapSelectionSend.erase(miRemove);
+ }
+}
+void ScAccessibleSpreadsheet::CommitFocusCell(const ScAddress &aNewCell)
+{
+ OSL_ASSERT(!IsFormulaMode());
+ if(IsFormulaMode())
+ {
+ return ;
+ }
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED;
+ aEvent.Source = uno::Reference< XAccessible >(this);
+ aEvent.OldValue <<= uno::Reference<XAccessible>(mpAccCell);
+ mpAccCell.clear();
+ mpAccCell = GetAccessibleCellAt(aNewCell.Row(), aNewCell.Col());
+ aEvent.NewValue <<= uno::Reference<XAccessible>(mpAccCell);
+ maActiveCell = aNewCell;
+ ScDocument* pScDoc= GetDocument(mpViewShell);
+ if (pScDoc)
+ {
+ m_strCurCellValue = pScDoc->GetString(maActiveCell.Col(),maActiveCell.Row(),maActiveCell.Tab());
+ }
+ CommitChange(aEvent);
+}
+
+//===== XAccessibleTable ================================================
+
+uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleSpreadsheet::getAccessibleRowHeaders( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ uno::Reference< XAccessibleTable > xAccessibleTable;
+ if( mpDoc && mbIsSpreadsheet )
+ {
+ if( std::optional<ScRange> oRowRange = mpDoc->GetRepeatRowRange( mnTab ) )
+ {
+ SCROW nStart = oRowRange->aStart.Row();
+ SCROW nEnd = oRowRange->aEnd.Row();
+ ScDocument* pDoc = GetDocument(mpViewShell);
+ if( (0 <= nStart) && (nStart <= nEnd) && (nEnd <= pDoc->MaxRow()) )
+ xAccessibleTable.set( new ScAccessibleSpreadsheet( *this, ScRange( 0, nStart, mnTab, pDoc->MaxCol(), nEnd, mnTab ) ) );
+ }
+ }
+ return xAccessibleTable;
+}
+
+uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleSpreadsheet::getAccessibleColumnHeaders( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ uno::Reference< XAccessibleTable > xAccessibleTable;
+ if( mpDoc && mbIsSpreadsheet )
+ {
+ if( std::optional<ScRange> oColRange = mpDoc->GetRepeatColRange( mnTab ) )
+ {
+ SCCOL nStart = oColRange->aStart.Col();
+ SCCOL nEnd = oColRange->aEnd.Col();
+ ScDocument* pDoc = GetDocument(mpViewShell);
+ if( (0 <= nStart) && (nStart <= nEnd) && (nEnd <= pDoc->MaxCol()) )
+ xAccessibleTable.set( new ScAccessibleSpreadsheet( *this, ScRange( nStart, 0, mnTab, nEnd, pDoc->MaxRow(), mnTab ) ) );
+ }
+ }
+ return xAccessibleTable;
+}
+
+uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleSpreadsheet::getSelectedAccessibleRows( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ uno::Sequence<sal_Int32> aSequence;
+ if (IsFormulaMode())
+ {
+ return aSequence;
+ }
+ if (mpViewShell)
+ {
+ aSequence.realloc(maRange.aEnd.Row() - maRange.aStart.Row() + 1);
+ const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
+ sal_Int32* pSequence = aSequence.getArray();
+ sal_Int32 nCount(0);
+ for (SCROW i = maRange.aStart.Row(); i <= maRange.aEnd.Row(); ++i)
+ {
+ if (rMarkdata.IsRowMarked(i))
+ {
+ pSequence[nCount] = i;
+ ++nCount;
+ }
+ }
+ aSequence.realloc(nCount);
+ }
+ else
+ aSequence.realloc(0);
+ return aSequence;
+}
+
+uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleSpreadsheet::getSelectedAccessibleColumns( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ uno::Sequence<sal_Int32> aSequence;
+ if (IsFormulaMode() || !mpViewShell)
+ return aSequence;
+
+ aSequence.realloc(maRange.aEnd.Col() - maRange.aStart.Col() + 1);
+ sal_Int32* pSequence = aSequence.getArray();
+ sal_Int32 nCount(0);
+ const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
+ for (SCCOL i = maRange.aStart.Col(); i <= maRange.aEnd.Col(); ++i)
+ {
+ if (rMarkdata.IsColumnMarked(i))
+ {
+ pSequence[nCount] = i;
+ ++nCount;
+ }
+ }
+ aSequence.realloc(nCount);
+ return aSequence;
+}
+
+sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleRowSelected( sal_Int32 nRow )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (IsFormulaMode())
+ {
+ return false;
+ }
+
+ if ((nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0))
+ throw lang::IndexOutOfBoundsException();
+
+ bool bResult(false);
+ if (mpViewShell)
+ {
+ const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
+ bResult = rMarkdata.IsRowMarked(static_cast<SCROW>(nRow));
+ }
+ return bResult;
+}
+
+sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleColumnSelected( sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if (IsFormulaMode())
+ {
+ return false;
+ }
+ if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0))
+ throw lang::IndexOutOfBoundsException();
+
+ bool bResult(false);
+ if (mpViewShell)
+ {
+ const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
+ bResult = rMarkdata.IsColumnMarked(static_cast<SCCOL>(nColumn));
+ }
+ return bResult;
+}
+
+rtl::Reference<ScAccessibleCell> ScAccessibleSpreadsheet::GetAccessibleCellAt(sal_Int32 nRow, sal_Int32 nColumn)
+{
+ if (IsFormulaMode())
+ {
+ ScAddress aCellAddress(static_cast<SCCOL>(nColumn), nRow, mpViewShell->GetViewData().GetTabNo());
+ if ((aCellAddress == m_aFormulaActiveCell) && m_pAccFormulaCell.is())
+ {
+ return m_pAccFormulaCell;
+ }
+ else
+ return ScAccessibleCell::create(this, mpViewShell, aCellAddress, GetAccessibleIndexFormula(nRow, nColumn), meSplitPos, mpAccDoc);
+ }
+ else
+ {
+ ScAddress aCellAddress(static_cast<SCCOL>(maRange.aStart.Col() + nColumn),
+ static_cast<SCROW>(maRange.aStart.Row() + nRow), maRange.aStart.Tab());
+ if ((aCellAddress == maActiveCell) && mpAccCell.is())
+ {
+ return mpAccCell;
+ }
+ else
+ return ScAccessibleCell::create(this, mpViewShell, aCellAddress, getAccessibleIndex(nRow, nColumn), meSplitPos, mpAccDoc);
+ }
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessibleSpreadsheet::getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (!IsFormulaMode())
+ {
+ if (nRow > (maRange.aEnd.Row() - maRange.aStart.Row()) ||
+ nRow < 0 ||
+ nColumn > (maRange.aEnd.Col() - maRange.aStart.Col()) ||
+ nColumn < 0)
+ throw lang::IndexOutOfBoundsException();
+ }
+ rtl::Reference<ScAccessibleCell> pAccessibleCell = GetAccessibleCellAt(nRow, nColumn);
+ return pAccessibleCell;
+}
+
+sal_Bool SAL_CALL ScAccessibleSpreadsheet::isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if (IsFormulaMode())
+ {
+ ScAddress addr(static_cast<SCCOL>(nColumn), nRow, 0);
+ return IsScAddrFormulaSel(addr);
+ }
+ if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0) ||
+ (nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0))
+ throw lang::IndexOutOfBoundsException();
+
+ bool bResult(false);
+ if (mpViewShell)
+ {
+ const ScMarkData& rMarkdata = mpViewShell->GetViewData().GetMarkData();
+ bResult = rMarkdata.IsCellMarked(static_cast<SCCOL>(nColumn), static_cast<SCROW>(nRow));
+ }
+ return bResult;
+}
+
+ //===== XAccessibleComponent ============================================
+
+uno::Reference< XAccessible > SAL_CALL ScAccessibleSpreadsheet::getAccessibleAtPoint(const awt::Point& rPoint)
+{
+ uno::Reference< XAccessible > xAccessible;
+ if (containsPoint(rPoint))
+ {
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (mpViewShell)
+ {
+ SCCOL nX;
+ SCROW nY;
+ mpViewShell->GetViewData().GetPosFromPixel( rPoint.X, rPoint.Y, meSplitPos, nX, nY);
+ try {
+ xAccessible = getAccessibleCellAt(nY, nX);
+ }
+ catch(const css::lang::IndexOutOfBoundsException &)
+ {
+ return nullptr;
+ }
+ }
+ }
+ return xAccessible;
+}
+
+void SAL_CALL ScAccessibleSpreadsheet::grabFocus( )
+{
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleComponent> xAccessibleComponent(getAccessibleParent()->getAccessibleContext(), uno::UNO_QUERY);
+ if (xAccessibleComponent.is())
+ xAccessibleComponent->grabFocus();
+ }
+}
+
+sal_Int32 SAL_CALL ScAccessibleSpreadsheet::getForeground( )
+{
+ return sal_Int32(COL_BLACK);
+}
+
+sal_Int32 SAL_CALL ScAccessibleSpreadsheet::getBackground( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ return sal_Int32(SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor);
+}
+
+ //===== XAccessibleContext ==============================================
+
+uno::Reference<XAccessibleRelationSet> SAL_CALL ScAccessibleSpreadsheet::getAccessibleRelationSet()
+{
+ rtl::Reference<utl::AccessibleRelationSetHelper> pRelationSet;
+ if(mpAccDoc)
+ pRelationSet = mpAccDoc->GetRelationSet(nullptr);
+ if (pRelationSet)
+ return pRelationSet;
+ return new utl::AccessibleRelationSetHelper();
+}
+
+uno::Reference<XAccessibleStateSet> SAL_CALL
+ ScAccessibleSpreadsheet::getAccessibleStateSet()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<XAccessibleStateSet> xParentStates;
+ if (getAccessibleParent().is())
+ {
+ uno::Reference<XAccessibleContext> xParentContext = getAccessibleParent()->getAccessibleContext();
+ xParentStates = xParentContext->getAccessibleStateSet();
+ }
+ rtl::Reference<utl::AccessibleStateSetHelper> pStateSet = new utl::AccessibleStateSetHelper();
+ if (IsDefunc(xParentStates))
+ pStateSet->AddState(AccessibleStateType::DEFUNC);
+ else
+ {
+ pStateSet->AddState(AccessibleStateType::MANAGES_DESCENDANTS);
+ if (IsEditable())
+ pStateSet->AddState(AccessibleStateType::EDITABLE);
+ pStateSet->AddState(AccessibleStateType::ENABLED);
+ pStateSet->AddState(AccessibleStateType::FOCUSABLE);
+ if (IsFocused())
+ pStateSet->AddState(AccessibleStateType::FOCUSED);
+ pStateSet->AddState(AccessibleStateType::MULTI_SELECTABLE);
+ pStateSet->AddState(AccessibleStateType::OPAQUE);
+ pStateSet->AddState(AccessibleStateType::SELECTABLE);
+ if (IsCompleteSheetSelected())
+ pStateSet->AddState(AccessibleStateType::SELECTED);
+ if (isShowing())
+ pStateSet->AddState(AccessibleStateType::SHOWING);
+ if (isVisible())
+ pStateSet->AddState(AccessibleStateType::VISIBLE);
+ }
+ return pStateSet;
+}
+
+ ///===== XAccessibleSelection ===========================================
+
+void SAL_CALL ScAccessibleSpreadsheet::selectAccessibleChild( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
+ throw lang::IndexOutOfBoundsException();
+
+ if (mpViewShell)
+ {
+ sal_Int32 nCol(getAccessibleColumn(nChildIndex));
+ sal_Int32 nRow(getAccessibleRow(nChildIndex));
+
+ SelectCell(nRow, nCol, false);
+ }
+}
+
+void SAL_CALL
+ ScAccessibleSpreadsheet::clearAccessibleSelection( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (mpViewShell && !IsFormulaMode())
+ mpViewShell->Unmark();
+}
+
+void SAL_CALL ScAccessibleSpreadsheet::selectAllAccessibleChildren( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ if (!mpViewShell)
+ return;
+
+ if (IsFormulaMode())
+ {
+ ScDocument* pDoc = GetDocument(mpViewShell);
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ mpViewShell->InitRefMode( 0, 0, rViewData.GetTabNo(), SC_REFTYPE_REF );
+ rViewData.SetRefStart(0, 0, rViewData.GetTabNo());
+ rViewData.SetRefEnd(pDoc->MaxCol(), pDoc->MaxRow(), rViewData.GetTabNo());
+ mpViewShell->UpdateRef(pDoc->MaxCol(), pDoc->MaxRow(), rViewData.GetTabNo());
+ }
+ else
+ mpViewShell->SelectAll();
+}
+
+sal_Int32 SAL_CALL
+ ScAccessibleSpreadsheet::getSelectedAccessibleChildCount( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ sal_Int32 nResult(0);
+ if (mpViewShell)
+ {
+ if (IsFormulaMode())
+ {
+ nResult = GetRowAll() * GetColAll() ;
+ }
+ else
+ {
+ if (!mpMarkedRanges)
+ {
+ mpMarkedRanges.reset(new ScRangeList());
+ ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData());
+ aMarkData.FillRangeListWithMarks(mpMarkedRanges.get(), false);
+ }
+ // is possible, because there shouldn't be overlapped ranges in it
+ if (mpMarkedRanges)
+ nResult = mpMarkedRanges->GetCellCount();
+ }
+ }
+ return nResult;
+}
+
+uno::Reference<XAccessible > SAL_CALL
+ ScAccessibleSpreadsheet::getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ uno::Reference < XAccessible > xAccessible;
+ if (IsFormulaMode())
+ {
+ if(CheckChildIndex(nSelectedChildIndex))
+ {
+ ScAddress addr = GetChildIndexAddress(nSelectedChildIndex);
+ xAccessible = getAccessibleCellAt(addr.Row(), addr.Col());
+ }
+ return xAccessible;
+ }
+ if (mpViewShell)
+ {
+ if (!mpMarkedRanges)
+ {
+ mpMarkedRanges.reset(new ScRangeList());
+ mpViewShell->GetViewData().GetMarkData().FillRangeListWithMarks(mpMarkedRanges.get(), false);
+ }
+ if (mpMarkedRanges)
+ {
+ if ((nSelectedChildIndex < 0) ||
+ (mpMarkedRanges->GetCellCount() <= o3tl::make_unsigned(nSelectedChildIndex)))
+ {
+ throw lang::IndexOutOfBoundsException();
+ }
+ ScMyAddress addr = CalcScAddressFromRangeList(mpMarkedRanges.get(),nSelectedChildIndex);
+ if( m_mapSelectionSend.find(addr) != m_mapSelectionSend.end() )
+ xAccessible = m_mapSelectionSend[addr];
+ else
+ xAccessible = getAccessibleCellAt(addr.Row(), addr.Col());
+ }
+ }
+ return xAccessible;
+}
+
+void SAL_CALL ScAccessibleSpreadsheet::deselectAccessibleChild( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
+ throw lang::IndexOutOfBoundsException();
+
+ if (!mpViewShell)
+ return;
+
+ sal_Int32 nCol(getAccessibleColumn(nChildIndex));
+ sal_Int32 nRow(getAccessibleRow(nChildIndex));
+
+ if (IsFormulaMode())
+ {
+ if(IsScAddrFormulaSel(
+ ScAddress(static_cast<SCCOL>(nCol), nRow,mpViewShell->GetViewData().GetTabNo()))
+ )
+ {
+ SelectCell(nRow, nCol, true);
+ }
+ return ;
+ }
+ if (mpViewShell->GetViewData().GetMarkData().IsCellMarked(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow)))
+ SelectCell(nRow, nCol, true);
+}
+
+void ScAccessibleSpreadsheet::SelectCell(sal_Int32 nRow, sal_Int32 nCol, bool bDeselect)
+{
+ if (IsFormulaMode())
+ {
+ if (bDeselect)
+ {//??
+ return;
+ }
+ else
+ {
+ ScViewData& rViewData = mpViewShell->GetViewData();
+
+ mpViewShell->InitRefMode( static_cast<SCCOL>(nCol), nRow, rViewData.GetTabNo(), SC_REFTYPE_REF );
+ mpViewShell->UpdateRef(static_cast<SCCOL>(nCol), nRow, rViewData.GetTabNo());
+ }
+ return ;
+ }
+ mpViewShell->SetTabNo( maRange.aStart.Tab() );
+
+ mpViewShell->DoneBlockMode( true ); // continue selecting
+ mpViewShell->InitBlockMode( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), maRange.aStart.Tab(), bDeselect );
+
+ mpViewShell->SelectionChanged();
+}
+
+/*
+void ScAccessibleSpreadsheet::CreateSortedMarkedCells()
+{
+ mpSortedMarkedCells = new std::vector<ScMyAddress>();
+ mpSortedMarkedCells->reserve(mpMarkedRanges->GetCellCount());
+ for ( size_t i = 0, ListSize = mpMarkedRanges->size(); i < ListSize; ++i )
+ {
+ ScRange* pRange = (*mpMarkedRanges)[i];
+ if (pRange->aStart.Tab() != pRange->aEnd.Tab())
+ {
+ if ((maActiveCell.Tab() >= pRange->aStart.Tab()) ||
+ maActiveCell.Tab() <= pRange->aEnd.Tab())
+ {
+ ScRange aRange(*pRange);
+ aRange.aStart.SetTab(maActiveCell.Tab());
+ aRange.aEnd.SetTab(maActiveCell.Tab());
+ AddMarkedRange(aRange);
+ }
+ else
+ {
+ OSL_FAIL("Range of wrong table");
+ }
+ }
+ else if(pRange->aStart.Tab() == maActiveCell.Tab())
+ AddMarkedRange(*pRange);
+ else
+ {
+ OSL_FAIL("Range of wrong table");
+ }
+ }
+ std::sort(mpSortedMarkedCells->begin(), mpSortedMarkedCells->end());
+}
+
+void ScAccessibleSpreadsheet::AddMarkedRange(const ScRange& rRange)
+{
+ for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
+ {
+ for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
+ {
+ ScMyAddress aCell(nCol, nRow, maActiveCell.Tab());
+ mpSortedMarkedCells->push_back(aCell);
+ }
+ }
+}*/
+
+ //===== XServiceInfo ====================================================
+
+OUString SAL_CALL ScAccessibleSpreadsheet::getImplementationName()
+{
+ return "ScAccessibleSpreadsheet";
+}
+
+uno::Sequence< OUString> SAL_CALL
+ ScAccessibleSpreadsheet::getSupportedServiceNames()
+{
+ const css::uno::Sequence<OUString> vals { "com.sun.star.AccessibleSpreadsheet" };
+ return comphelper::concatSequences(ScAccessibleContextBase::getSupportedServiceNames(), vals);
+}
+
+//===== XTypeProvider =======================================================
+
+uno::Sequence<sal_Int8> SAL_CALL
+ ScAccessibleSpreadsheet::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+///===== XAccessibleEventBroadcaster =====================================
+
+void SAL_CALL ScAccessibleSpreadsheet::addAccessibleEventListener(const uno::Reference<XAccessibleEventListener>& xListener)
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ ScAccessibleTableBase::addAccessibleEventListener(xListener);
+
+}
+
+//==== internal =========================================================
+
+tools::Rectangle ScAccessibleSpreadsheet::GetBoundingBoxOnScreen() const
+{
+ tools::Rectangle aRect;
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
+ if (pWindow)
+ aRect = pWindow->GetWindowExtentsRelative(nullptr);
+ }
+ return aRect;
+}
+
+tools::Rectangle ScAccessibleSpreadsheet::GetBoundingBox() const
+{
+ tools::Rectangle aRect;
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
+ if (pWindow)
+ //#101986#; extends to the same window, because the parent is the document and it has the same window
+ aRect = pWindow->GetWindowExtentsRelative(pWindow);
+ }
+ return aRect;
+}
+
+bool ScAccessibleSpreadsheet::IsDefunc(
+ const uno::Reference<XAccessibleStateSet>& rxParentStates)
+{
+ return ScAccessibleContextBase::IsDefunc() || (mpViewShell == nullptr) || !getAccessibleParent().is() ||
+ (rxParentStates.is() && rxParentStates->contains(AccessibleStateType::DEFUNC));
+}
+
+bool ScAccessibleSpreadsheet::IsEditable()
+{
+ if (IsFormulaMode())
+ {
+ return false;
+ }
+ bool bProtected(false);
+ if (mpDoc && mpDoc->IsTabProtected(maRange.aStart.Tab()))
+ bProtected = true;
+ return !bProtected;
+}
+
+bool ScAccessibleSpreadsheet::IsFocused()
+{
+ bool bFocused(false);
+ if (mpViewShell)
+ {
+ if (mpViewShell->GetViewData().GetActivePart() == meSplitPos)
+ bFocused = mpViewShell->GetActiveWin()->HasFocus();
+ }
+ return bFocused;
+}
+
+bool ScAccessibleSpreadsheet::IsCompleteSheetSelected()
+{
+ if (IsFormulaMode())
+ {
+ return false;
+ }
+
+ bool bResult(false);
+ if(mpViewShell)
+ {
+ //#103800#; use a copy of MarkData
+ ScMarkData aMarkData(mpViewShell->GetViewData().GetMarkData());
+ if (aMarkData.IsAllMarked(maRange))
+ bResult = true;
+ }
+ return bResult;
+}
+
+ScDocument* ScAccessibleSpreadsheet::GetDocument(ScTabViewShell* pViewShell)
+{
+ ScDocument* pDoc = nullptr;
+ if (pViewShell)
+ pDoc = &pViewShell->GetViewData().GetDocument();
+ return pDoc;
+}
+
+sal_Bool SAL_CALL ScAccessibleSpreadsheet::selectRow( sal_Int32 row )
+{
+ SolarMutexGuard g;
+
+ if (IsFormulaMode())
+ {
+ return false;
+ }
+
+ ScDocument* pDoc = GetDocument(mpViewShell);
+ mpViewShell->SetTabNo( maRange.aStart.Tab() );
+ mpViewShell->DoneBlockMode( true ); // continue selecting
+ mpViewShell->InitBlockMode( 0, row, maRange.aStart.Tab(), false, false, true );
+ mpViewShell->MarkCursor( pDoc->MaxCol(), row, maRange.aStart.Tab(), false, true );
+ mpViewShell->SelectionChanged();
+ return true;
+}
+
+sal_Bool SAL_CALL ScAccessibleSpreadsheet::selectColumn( sal_Int32 column )
+{
+ SolarMutexGuard g;
+
+ if (IsFormulaMode())
+ {
+ return false;
+ }
+
+ ScDocument* pDoc = GetDocument(mpViewShell);
+ mpViewShell->SetTabNo( maRange.aStart.Tab() );
+ mpViewShell->DoneBlockMode( true ); // continue selecting
+ mpViewShell->InitBlockMode( static_cast<SCCOL>(column), 0, maRange.aStart.Tab(), false, true );
+ mpViewShell->MarkCursor( static_cast<SCCOL>(column), pDoc->MaxRow(), maRange.aStart.Tab(), true );
+ mpViewShell->SelectionChanged();
+ return true;
+}
+
+sal_Bool SAL_CALL ScAccessibleSpreadsheet::unselectRow( sal_Int32 row )
+{
+ SolarMutexGuard g;
+
+ if (IsFormulaMode())
+ {
+ return false;
+ }
+
+ ScDocument* pDoc = GetDocument(mpViewShell);
+ mpViewShell->SetTabNo( maRange.aStart.Tab() );
+ mpViewShell->DoneBlockMode( true ); // continue selecting
+ mpViewShell->InitBlockMode( 0, row, maRange.aStart.Tab(), false, false, true, true );
+ mpViewShell->MarkCursor( pDoc->MaxCol(), row, maRange.aStart.Tab(), false, true );
+ mpViewShell->SelectionChanged();
+ mpViewShell->DoneBlockMode( true );
+ return true;
+}
+
+sal_Bool SAL_CALL ScAccessibleSpreadsheet::unselectColumn( sal_Int32 column )
+{
+ SolarMutexGuard g;
+
+ if (IsFormulaMode())
+ {
+ return false;
+ }
+
+ ScDocument* pDoc = GetDocument(mpViewShell);
+ mpViewShell->SetTabNo( maRange.aStart.Tab() );
+ mpViewShell->DoneBlockMode( true ); // continue selecting
+ mpViewShell->InitBlockMode( static_cast<SCCOL>(column), 0, maRange.aStart.Tab(), false, true, false, true );
+ mpViewShell->MarkCursor( static_cast<SCCOL>(column), pDoc->MaxRow(), maRange.aStart.Tab(), true );
+ mpViewShell->SelectionChanged();
+ mpViewShell->DoneBlockMode( true );
+ return true;
+}
+
+void ScAccessibleSpreadsheet::FireFirstCellFocus()
+{
+ if (IsFormulaMode())
+ {
+ return ;
+ }
+ if (mbIsFocusSend)
+ {
+ return ;
+ }
+ mbIsFocusSend = true;
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED;
+ aEvent.Source = uno::Reference< XAccessible >(this);
+ aEvent.NewValue <<= getAccessibleCellAt(maActiveCell.Row(), maActiveCell.Col());
+ CommitChange(aEvent);
+}
+
+void ScAccessibleSpreadsheet::NotifyRefMode()
+{
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ if (!rViewData.IsRefMode())
+ // Not in reference mode. Bail out.
+ return;
+
+ sal_uInt16 nRefStartX = rViewData.GetRefStartX();
+ sal_Int32 nRefStartY = rViewData.GetRefStartY();
+ sal_uInt16 nRefEndX = rViewData.GetRefEndX();
+ sal_Int32 nRefEndY = rViewData.GetRefEndY();
+ ScAddress aFormulaAddr;
+ if(!GetFormulaCurrentFocusCell(aFormulaAddr))
+ {
+ return ;
+ }
+ if (m_aFormulaActiveCell != aFormulaAddr)
+ {//New Focus
+ m_nMinX =std::min(nRefStartX,nRefEndX);
+ m_nMaxX =std::max(nRefStartX,nRefEndX);
+ m_nMinY = std::min(nRefStartY,nRefEndY);
+ m_nMaxY = std::max(nRefStartY,nRefEndY);
+ RemoveFormulaSelection();
+ AccessibleEventObject aEvent;
+ aEvent.Source = uno::Reference< XAccessible >(this);
+ aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED;
+ aEvent.OldValue <<= uno::Reference<XAccessible>(m_pAccFormulaCell);
+ m_pAccFormulaCell = GetAccessibleCellAt(aFormulaAddr.Row(), aFormulaAddr.Col());
+ uno::Reference< XAccessible > xNew = m_pAccFormulaCell;
+ aEvent.NewValue <<= xNew;
+ CommitChange(aEvent);
+ if (nRefStartX == nRefEndX && nRefStartY == nRefEndY)
+ {//Selection Single
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED;
+ aEvent.NewValue <<= xNew;
+ CommitChange(aEvent);
+ m_mapFormulaSelectionSend.emplace(aFormulaAddr,xNew);
+ m_vecFormulaLastMyAddr.clear();
+ m_vecFormulaLastMyAddr.emplace_back(aFormulaAddr);
+ }
+ else
+ {
+ std::vector<ScMyAddress> vecCurSel;
+ int nCurSize = (m_nMaxX - m_nMinX +1)*(m_nMaxY - m_nMinY +1) ;
+ vecCurSel.reserve(nCurSize);
+ for (sal_uInt16 x = m_nMinX ; x <= m_nMaxX ; ++x)
+ {
+ for (sal_Int32 y = m_nMinY ; y <= m_nMaxY ; ++y)
+ {
+ ScMyAddress aAddr(x,y,0);
+ vecCurSel.push_back(aAddr);
+ }
+ }
+ std::sort(vecCurSel.begin(), vecCurSel.end());
+ std::vector<ScMyAddress> vecNew;
+ std::set_difference(vecCurSel.begin(),vecCurSel.end(),
+ m_vecFormulaLastMyAddr.begin(),m_vecFormulaLastMyAddr.end(),
+ std::back_insert_iterator(vecNew));
+ int nNewSize = vecNew.size();
+ if ( nNewSize > 10 )
+ {
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_WITHIN;
+ aEvent.NewValue.clear();
+ CommitChange(aEvent);
+ }
+ else
+ {
+ for(const auto& rAddr : vecNew)
+ {
+ uno::Reference< XAccessible > xChild;
+ if (rAddr == aFormulaAddr)
+ {
+ xChild = m_pAccFormulaCell.get();
+ }
+ else
+ {
+ xChild = getAccessibleCellAt(rAddr.Row(),rAddr.Col());
+ aEvent.EventId = AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS;
+ aEvent.NewValue <<= xChild;
+ CommitChange(aEvent);
+ }
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_ADD;
+ aEvent.NewValue <<= xChild;
+ CommitChange(aEvent);
+ m_mapFormulaSelectionSend.emplace(rAddr,xChild);
+ }
+ }
+ m_vecFormulaLastMyAddr.swap(vecCurSel);
+ }
+ }
+ m_aFormulaActiveCell = aFormulaAddr;
+}
+
+void ScAccessibleSpreadsheet::RemoveFormulaSelection(bool bRemoveAll )
+{
+ AccessibleEventObject aEvent;
+ aEvent.Source = uno::Reference< XAccessible >(this);
+ MAP_ADDR_XACC::iterator miRemove = m_mapFormulaSelectionSend.begin();
+ while (miRemove != m_mapFormulaSelectionSend.end())
+ {
+ if( !bRemoveAll && IsScAddrFormulaSel(miRemove->first) )
+ {
+ ++miRemove;
+ continue;
+ }
+ aEvent.EventId = AccessibleEventId::SELECTION_CHANGED_REMOVE;
+ aEvent.NewValue <<= miRemove->second;
+ CommitChange(aEvent);
+ miRemove = m_mapFormulaSelectionSend.erase(miRemove);
+ }
+}
+
+bool ScAccessibleSpreadsheet::IsScAddrFormulaSel(const ScAddress &addr) const
+{
+ return addr.Col() >= m_nMinX && addr.Col() <= m_nMaxX &&
+ addr.Row() >= m_nMinY && addr.Row() <= m_nMaxY &&
+ addr.Tab() == mpViewShell->GetViewData().GetTabNo();
+}
+
+bool ScAccessibleSpreadsheet::CheckChildIndex(sal_Int32 nIndex) const
+{
+ sal_Int32 nMaxIndex = (m_nMaxX - m_nMinX +1)*(m_nMaxY - m_nMinY +1) -1 ;
+ return nIndex <= nMaxIndex && nIndex >= 0 ;
+}
+
+ScAddress ScAccessibleSpreadsheet::GetChildIndexAddress(sal_Int32 nIndex) const
+{
+ sal_Int32 nRowAll = GetRowAll();
+ sal_uInt16 nColAll = GetColAll();
+ if (nIndex < 0 || nIndex >= nRowAll * nColAll )
+ {
+ return ScAddress();
+ }
+ return ScAddress(
+ static_cast<SCCOL>((nIndex - nIndex % nRowAll) / nRowAll + + m_nMinX),
+ nIndex % nRowAll + m_nMinY,
+ mpViewShell->GetViewData().GetTabNo()
+ );
+}
+
+sal_Int32 ScAccessibleSpreadsheet::GetAccessibleIndexFormula( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ sal_uInt16 nColRelative = sal_uInt16(nColumn) - GetColAll();
+ sal_Int32 nRowRelative = nRow - GetRowAll();
+ if (nRow < 0 || nColumn < 0 || nRowRelative >= GetRowAll() || nColRelative >= GetColAll() )
+ {
+ return -1;
+ }
+ return GetRowAll() * nRowRelative + nColRelative;
+}
+
+bool ScAccessibleSpreadsheet::IsFormulaMode()
+{
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ m_bFormulaMode = rViewData.IsRefMode() || SC_MOD()->IsFormulaMode();
+ return m_bFormulaMode ;
+}
+
+bool ScAccessibleSpreadsheet::GetFormulaCurrentFocusCell(ScAddress &addr)
+{
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ sal_uInt16 nRefX=0;
+ sal_Int32 nRefY=0;
+ if(m_bFormulaLastMode)
+ {
+ nRefX=rViewData.GetRefEndX();
+ nRefY=rViewData.GetRefEndY();
+ }
+ else
+ {
+ nRefX=rViewData.GetRefStartX();
+ nRefY=rViewData.GetRefStartY();
+ }
+ ScDocument* pDoc = GetDocument(mpViewShell);
+ if( /* Always true: nRefX >= 0 && */ nRefX <= pDoc->MaxCol() && nRefY >= 0 && nRefY <= pDoc->MaxRow())
+ {
+ addr = ScAddress(nRefX,nRefY,rViewData.GetTabNo());
+ return true;
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessibleTableBase.cxx b/sc/source/ui/Accessibility/AccessibleTableBase.cxx
new file mode 100644
index 000000000..5877c1e36
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleTableBase.cxx
@@ -0,0 +1,470 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <AccessibleTableBase.hxx>
+#include <document.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <table.hxx>
+
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleTableModelChange.hpp>
+#include <com/sun/star/accessibility/AccessibleEventId.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/sequence.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::accessibility;
+
+//===== internal ============================================================
+
+ScAccessibleTableBase::ScAccessibleTableBase(
+ const uno::Reference<XAccessible>& rxParent,
+ ScDocument* pDoc,
+ const ScRange& rRange)
+ :
+ ScAccessibleContextBase (rxParent, AccessibleRole::TABLE),
+ maRange(rRange),
+ mpDoc(pDoc)
+{
+}
+
+ScAccessibleTableBase::~ScAccessibleTableBase()
+{
+}
+
+void SAL_CALL ScAccessibleTableBase::disposing()
+{
+ SolarMutexGuard aGuard;
+ mpDoc = nullptr;
+
+ ScAccessibleContextBase::disposing();
+}
+
+ //===== XInterface =====================================================
+
+uno::Any SAL_CALL ScAccessibleTableBase::queryInterface( uno::Type const & rType )
+{
+ if ( rType == cppu::UnoType<XAccessibleTableSelection>::get())
+ {
+ return uno::Any(uno::Reference<XAccessibleTableSelection>(this));
+ }
+ else
+ {
+ uno::Any aAny (ScAccessibleTableBaseImpl::queryInterface(rType));
+ return aAny.hasValue() ? aAny : ScAccessibleContextBase::queryInterface(rType);
+ }
+}
+
+void SAL_CALL ScAccessibleTableBase::acquire()
+ noexcept
+{
+ ScAccessibleContextBase::acquire();
+}
+
+void SAL_CALL ScAccessibleTableBase::release()
+ noexcept
+{
+ ScAccessibleContextBase::release();
+}
+
+ //===== XAccessibleTable ================================================
+
+sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleRowCount( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ return maRange.aEnd.Row() - maRange.aStart.Row() + 1;
+}
+
+sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleColumnCount( )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+ return maRange.aEnd.Col() - maRange.aStart.Col() + 1;
+}
+
+OUString SAL_CALL ScAccessibleTableBase::getAccessibleRowDescription( sal_Int32 nRow )
+{
+ OSL_FAIL("Here should be an implementation to fill the description");
+
+ if ((nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0))
+ throw lang::IndexOutOfBoundsException();
+
+ //setAccessibleRowDescription(nRow, xAccessible); // to remember the created Description
+ return OUString();
+}
+
+OUString SAL_CALL ScAccessibleTableBase::getAccessibleColumnDescription( sal_Int32 nColumn )
+{
+ OSL_FAIL("Here should be an implementation to fill the description");
+
+ if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0))
+ throw lang::IndexOutOfBoundsException();
+
+ //setAccessibleColumnDescription(nColumn, xAccessible); // to remember the created Description
+ return OUString();
+}
+
+sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0) ||
+ (nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0))
+ throw lang::IndexOutOfBoundsException();
+
+ sal_Int32 nCount(1); // the same cell
+ nRow += maRange.aStart.Row();
+ nColumn += maRange.aStart.Col();
+
+ if (mpDoc)
+ {
+ ScTable* pTab = mpDoc->FetchTable(maRange.aStart.Tab());
+ if (pTab)
+ {
+ SCROW nStartRow = static_cast<SCROW>(nRow);
+ SCROW nEndRow = nStartRow;
+ SCCOL nStartCol = static_cast<SCCOL>(nColumn);
+ SCCOL nEndCol = nStartCol;
+ if (pTab->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, false))
+ {
+ if (nEndRow > nStartRow)
+ nCount = nEndRow - nStartRow + 1;
+ }
+ }
+ }
+
+ return nCount;
+}
+
+sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if ((nColumn > (maRange.aEnd.Col() - maRange.aStart.Col())) || (nColumn < 0) ||
+ (nRow > (maRange.aEnd.Row() - maRange.aStart.Row())) || (nRow < 0))
+ throw lang::IndexOutOfBoundsException();
+
+ sal_Int32 nCount(1); // the same cell
+ nRow += maRange.aStart.Row();
+ nColumn += maRange.aStart.Col();
+
+ if (mpDoc)
+ {
+ ScTable* pTab = mpDoc->FetchTable(maRange.aStart.Tab());
+ if (pTab)
+ {
+ SCROW nStartRow = static_cast<SCROW>(nRow);
+ SCROW nEndRow = nStartRow;
+ SCCOL nStartCol = static_cast<SCCOL>(nColumn);
+ SCCOL nEndCol = nStartCol;
+ if (pTab->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, false))
+ {
+ if (nEndCol > nStartCol)
+ nCount = nEndCol - nStartCol + 1;
+ }
+ }
+ }
+
+ return nCount;
+}
+
+uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleTableBase::getAccessibleRowHeaders( )
+{
+ uno::Reference< XAccessibleTable > xAccessibleTable;
+ OSL_FAIL("Here should be an implementation to fill the row headers");
+
+ //CommitChange
+ return xAccessibleTable;
+}
+
+uno::Reference< XAccessibleTable > SAL_CALL ScAccessibleTableBase::getAccessibleColumnHeaders( )
+{
+ uno::Reference< XAccessibleTable > xAccessibleTable;
+ OSL_FAIL("Here should be an implementation to fill the column headers");
+
+ //CommitChange
+ return xAccessibleTable;
+}
+
+uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleTableBase::getSelectedAccessibleRows( )
+{
+ OSL_FAIL("not implemented yet");
+ uno::Sequence< sal_Int32 > aSequence;
+ return aSequence;
+}
+
+uno::Sequence< sal_Int32 > SAL_CALL ScAccessibleTableBase::getSelectedAccessibleColumns( )
+{
+ OSL_FAIL("not implemented yet");
+ uno::Sequence< sal_Int32 > aSequence;
+ return aSequence;
+}
+
+sal_Bool SAL_CALL ScAccessibleTableBase::isAccessibleRowSelected( sal_Int32 /* nRow */ )
+{
+ OSL_FAIL("not implemented yet");
+ return false;
+}
+
+sal_Bool SAL_CALL ScAccessibleTableBase::isAccessibleColumnSelected( sal_Int32 /* nColumn */ )
+{
+ OSL_FAIL("not implemented yet");
+ return false;
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessibleTableBase::getAccessibleCellAt( sal_Int32 /* nRow */, sal_Int32 /* nColumn */ )
+{
+ OSL_FAIL("not implemented yet");
+ uno::Reference< XAccessible > xAccessible;
+ return xAccessible;
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessibleTableBase::getAccessibleCaption( )
+{
+ OSL_FAIL("not implemented yet");
+ uno::Reference< XAccessible > xAccessible;
+ return xAccessible;
+}
+
+uno::Reference< XAccessible > SAL_CALL ScAccessibleTableBase::getAccessibleSummary( )
+{
+ OSL_FAIL("not implemented yet");
+ uno::Reference< XAccessible > xAccessible;
+ return xAccessible;
+}
+
+sal_Bool SAL_CALL ScAccessibleTableBase::isAccessibleSelected( sal_Int32 /* nRow */, sal_Int32 /* nColumn */ )
+{
+ OSL_FAIL("not implemented yet");
+ return false;
+}
+
+// ===== XAccessibleExtendedTable ========================================
+
+sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if (nRow > (maRange.aEnd.Row() - maRange.aStart.Row()) ||
+ nRow < 0 ||
+ nColumn > (maRange.aEnd.Col() - maRange.aStart.Col()) ||
+ nColumn < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ nRow -= maRange.aStart.Row();
+ nColumn -= maRange.aStart.Col();
+ return (nRow * (maRange.aEnd.Col() + 1)) + nColumn;
+}
+
+sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleRow( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if (nChildIndex >= getAccessibleChildCount() || nChildIndex < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ return nChildIndex / (maRange.aEnd.Col() - maRange.aStart.Col() + 1);
+}
+
+sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleColumn( sal_Int32 nChildIndex )
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if (nChildIndex >= getAccessibleChildCount() || nChildIndex < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ return nChildIndex % static_cast<sal_Int32>(maRange.aEnd.Col() - maRange.aStart.Col() + 1);
+}
+
+// ===== XAccessibleContext ==============================================
+
+sal_Int32 SAL_CALL ScAccessibleTableBase::getAccessibleChildCount()
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ // FIXME: representing rows & columns this way is a plain and simple madness.
+ // this needs a radical re-think.
+ sal_Int64 nMax = static_cast<sal_Int64>(maRange.aEnd.Row() - maRange.aStart.Row() + 1) *
+ static_cast<sal_Int64>(maRange.aEnd.Col() - maRange.aStart.Col() + 1);
+ if (nMax > SAL_MAX_INT32)
+ nMax = SAL_MAX_INT32;
+ if (nMax < 0)
+ return 0;
+ return static_cast<sal_Int32>(nMax);
+}
+
+uno::Reference< XAccessible > SAL_CALL
+ ScAccessibleTableBase::getAccessibleChild(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ IsObjectValid();
+
+ if (nIndex >= getAccessibleChildCount() || nIndex < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ // FIXME: representing rows & columns this way is a plain and simple madness.
+ // this needs a radical re-think.
+
+ sal_Int32 nRow(0);
+ sal_Int32 nColumn(0);
+ sal_Int32 nTemp(maRange.aEnd.Col() - maRange.aStart.Col() + 1);
+ nRow = nIndex / nTemp;
+ nColumn = nIndex % nTemp;
+ return getAccessibleCellAt(nRow, nColumn);
+}
+
+OUString
+ ScAccessibleTableBase::createAccessibleDescription()
+{
+ return STR_ACC_TABLE_DESCR;
+}
+
+OUString ScAccessibleTableBase::createAccessibleName()
+{
+ OUString sName(ScResId(STR_ACC_TABLE_NAME));
+ OUString sCoreName;
+ if (mpDoc && mpDoc->GetName( maRange.aStart.Tab(), sCoreName ))
+ sName = sName.replaceFirst("%1", sCoreName);
+ return sName;
+}
+
+uno::Reference<XAccessibleRelationSet> SAL_CALL
+ ScAccessibleTableBase::getAccessibleRelationSet()
+{
+ OSL_FAIL("should be implemented in the abrevated class");
+ return uno::Reference<XAccessibleRelationSet>();
+}
+
+uno::Reference<XAccessibleStateSet> SAL_CALL
+ ScAccessibleTableBase::getAccessibleStateSet()
+{
+ OSL_FAIL("should be implemented in the abrevated class");
+ uno::Reference< XAccessibleStateSet > xAccessibleStateSet;
+ return xAccessibleStateSet;
+}
+
+ ///===== XAccessibleSelection ===========================================
+
+void SAL_CALL ScAccessibleTableBase::selectAccessibleChild( sal_Int32 /* nChildIndex */ )
+{
+}
+
+sal_Bool SAL_CALL
+ ScAccessibleTableBase::isAccessibleChildSelected( sal_Int32 nChildIndex )
+{
+ // I don't need to guard, because the called functions have a guard
+ if (nChildIndex < 0 || nChildIndex >= getAccessibleChildCount())
+ throw lang::IndexOutOfBoundsException();
+ return isAccessibleSelected(getAccessibleRow(nChildIndex), getAccessibleColumn(nChildIndex));
+}
+
+void SAL_CALL
+ ScAccessibleTableBase::clearAccessibleSelection( )
+{
+}
+
+void SAL_CALL ScAccessibleTableBase::selectAllAccessibleChildren()
+{
+}
+
+sal_Int32 SAL_CALL
+ ScAccessibleTableBase::getSelectedAccessibleChildCount( )
+{
+ return 0;
+}
+
+uno::Reference<XAccessible > SAL_CALL
+ ScAccessibleTableBase::getSelectedAccessibleChild( sal_Int32 /* nSelectedChildIndex */ )
+{
+ uno::Reference < XAccessible > xAccessible;
+ return xAccessible;
+}
+
+void SAL_CALL ScAccessibleTableBase::deselectAccessibleChild( sal_Int32 /* nSelectedChildIndex */ )
+{
+}
+
+ //===== XServiceInfo ====================================================
+
+OUString SAL_CALL ScAccessibleTableBase::getImplementationName()
+{
+ return "ScAccessibleTableBase";
+}
+
+ //===== XTypeProvider ===================================================
+
+uno::Sequence< uno::Type > SAL_CALL ScAccessibleTableBase::getTypes()
+{
+ return comphelper::concatSequences(ScAccessibleTableBaseImpl::getTypes(), ScAccessibleContextBase::getTypes());
+}
+
+uno::Sequence<sal_Int8> SAL_CALL
+ ScAccessibleTableBase::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void ScAccessibleTableBase::CommitTableModelChange(sal_Int32 nStartRow, sal_Int32 nStartCol, sal_Int32 nEndRow, sal_Int32 nEndCol, sal_uInt16 nId)
+{
+ AccessibleTableModelChange aModelChange;
+ aModelChange.FirstRow = nStartRow;
+ aModelChange.FirstColumn = nStartCol;
+ aModelChange.LastRow = nEndRow;
+ aModelChange.LastColumn = nEndCol;
+ aModelChange.Type = nId;
+
+ AccessibleEventObject aEvent;
+ aEvent.EventId = AccessibleEventId::TABLE_MODEL_CHANGED;
+ aEvent.Source = uno::Reference< XAccessibleContext >(this);
+ aEvent.NewValue <<= aModelChange;
+
+ CommitChange(aEvent);
+}
+
+sal_Bool SAL_CALL ScAccessibleTableBase::selectRow( sal_Int32 )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ScAccessibleTableBase::selectColumn( sal_Int32 )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ScAccessibleTableBase::unselectRow( sal_Int32 )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ScAccessibleTableBase::unselectColumn( sal_Int32 )
+{
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/AccessibleText.cxx b/sc/source/ui/Accessibility/AccessibleText.cxx
new file mode 100644
index 000000000..13c67f737
--- /dev/null
+++ b/sc/source/ui/Accessibility/AccessibleText.cxx
@@ -0,0 +1,1385 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <memory>
+#include <AccessibleText.hxx>
+#include <AccessibleCell.hxx>
+#include <attrib.hxx>
+#include <tabvwsh.hxx>
+#include <editutil.hxx>
+#include <document.hxx>
+#include <scmod.hxx>
+#include <prevwsh.hxx>
+#include <docsh.hxx>
+#include <prevloc.hxx>
+#include <patattr.hxx>
+#include <inputwin.hxx>
+#include <editeng/unofored.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/unoedhlp.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/algitem.hxx>
+#include <vcl/svapp.hxx>
+
+class ScViewForwarder : public SvxViewForwarder
+{
+ ScTabViewShell* mpViewShell;
+ ScSplitPos meSplitPos;
+public:
+ ScViewForwarder(ScTabViewShell* pViewShell, ScSplitPos eSplitPos);
+
+ 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;
+
+ void SetInvalid();
+};
+
+ScViewForwarder::ScViewForwarder(ScTabViewShell* pViewShell, ScSplitPos eSplitPos)
+ :
+ mpViewShell(pViewShell),
+ meSplitPos(eSplitPos)
+{
+}
+
+bool ScViewForwarder::IsValid() const
+{
+ return mpViewShell != nullptr;
+}
+
+Point ScViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
+ if (pWindow)
+ return pWindow->LogicToPixel( rPoint, rMapMode );
+ }
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return Point();
+}
+
+Point ScViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindowByPos(meSplitPos);
+ if (pWindow)
+ return pWindow->PixelToLogic( rPoint, rMapMode );
+ }
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return Point();
+}
+
+void ScViewForwarder::SetInvalid()
+{
+ mpViewShell = nullptr;
+}
+
+class ScEditObjectViewForwarder : public SvxViewForwarder
+{
+ VclPtr<OutputDevice> mpWindow;
+ // #i49561# EditView needed for access to its visible area.
+ const EditView* mpEditView;
+public:
+ ScEditObjectViewForwarder( OutputDevice* pWindow,
+ const EditView* _pEditView);
+
+ 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;
+
+ void SetInvalid();
+};
+
+ScEditObjectViewForwarder::ScEditObjectViewForwarder( OutputDevice* pWindow,
+ const EditView* _pEditView )
+ : mpWindow(pWindow)
+ , mpEditView( _pEditView )
+{
+}
+
+bool ScEditObjectViewForwarder::IsValid() const
+{
+ return (mpWindow != nullptr);
+}
+
+Point ScEditObjectViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ if (mpWindow)
+ {
+ // #i49561# - consider offset of the visible area
+ // of the EditView before converting point to pixel.
+ Point aPoint( rPoint );
+ if ( mpEditView )
+ {
+ tools::Rectangle aEditViewVisArea( mpEditView->GetVisArea() );
+ aPoint += aEditViewVisArea.TopLeft();
+ }
+ return mpWindow->LogicToPixel( aPoint, rMapMode );
+ }
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return Point();
+}
+
+Point ScEditObjectViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ if (mpWindow)
+ {
+ // #i49561# - consider offset of the visible area
+ // of the EditView after converting point to logic.
+ Point aPoint( mpWindow->PixelToLogic( rPoint, rMapMode ) );
+ if ( mpEditView )
+ {
+ tools::Rectangle aEditViewVisArea( mpEditView->GetVisArea() );
+ aPoint -= aEditViewVisArea.TopLeft();
+ }
+ return aPoint;
+ }
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return Point();
+}
+
+void ScEditObjectViewForwarder::SetInvalid()
+{
+ mpWindow = nullptr;
+}
+
+class ScPreviewViewForwarder : public SvxViewForwarder
+{
+protected:
+ ScPreviewShell* mpViewShell;
+public:
+ explicit ScPreviewViewForwarder(ScPreviewShell* pViewShell);
+
+ 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;
+
+ void SetInvalid();
+};
+
+ScPreviewViewForwarder::ScPreviewViewForwarder(ScPreviewShell* pViewShell)
+ : mpViewShell(pViewShell)
+{
+}
+
+bool ScPreviewViewForwarder::IsValid() const
+{
+ return mpViewShell != nullptr;
+}
+
+Point ScPreviewViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if (pWindow)
+ {
+ MapMode aMapMode(pWindow->GetMapMode().GetMapUnit());
+ Point aPoint2( OutputDevice::LogicToLogic( rPoint, rMapMode, aMapMode) );
+ return pWindow->LogicToPixel(aPoint2);
+ }
+ }
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return Point();
+}
+
+Point ScPreviewViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ if (mpViewShell)
+ {
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if (pWindow)
+ {
+ MapMode aMapMode(pWindow->GetMapMode());
+ aMapMode.SetOrigin(Point());
+ Point aPoint1( pWindow->PixelToLogic( rPoint ) );
+ Point aPoint2( OutputDevice::LogicToLogic( aPoint1,
+ MapMode(aMapMode.GetMapUnit()),
+ rMapMode ) );
+ return aPoint2;
+ }
+ }
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return Point();
+}
+
+void ScPreviewViewForwarder::SetInvalid()
+{
+ mpViewShell = nullptr;
+}
+
+namespace {
+
+class ScPreviewHeaderFooterViewForwarder : public ScPreviewViewForwarder
+{
+public:
+ ScPreviewHeaderFooterViewForwarder(ScPreviewShell* pViewShell);
+};
+
+}
+
+ScPreviewHeaderFooterViewForwarder::ScPreviewHeaderFooterViewForwarder(ScPreviewShell* pViewShell)
+ :
+ ScPreviewViewForwarder(pViewShell)
+{
+}
+
+namespace {
+
+class ScPreviewCellViewForwarder : public ScPreviewViewForwarder
+{
+public:
+ ScPreviewCellViewForwarder(ScPreviewShell* pViewShell);
+};
+
+}
+
+ScPreviewCellViewForwarder::ScPreviewCellViewForwarder(ScPreviewShell* pViewShell)
+ :
+ ScPreviewViewForwarder(pViewShell)
+{
+}
+
+namespace {
+
+class ScPreviewHeaderCellViewForwarder : public ScPreviewViewForwarder
+{
+public:
+ ScPreviewHeaderCellViewForwarder(ScPreviewShell* pViewShell);
+};
+
+}
+
+ScPreviewHeaderCellViewForwarder::ScPreviewHeaderCellViewForwarder(ScPreviewShell* pViewShell)
+ :
+ ScPreviewViewForwarder(pViewShell)
+{
+}
+
+namespace {
+
+class ScPreviewNoteViewForwarder : public ScPreviewViewForwarder
+{
+public:
+ ScPreviewNoteViewForwarder(ScPreviewShell* pViewShell);
+};
+
+}
+
+ScPreviewNoteViewForwarder::ScPreviewNoteViewForwarder(ScPreviewShell* pViewShell)
+ :
+ ScPreviewViewForwarder(pViewShell)
+{
+}
+
+class ScEditViewForwarder : public SvxEditViewForwarder
+{
+ EditView* mpEditView;
+ VclPtr<OutputDevice> mpWindow;
+public:
+ ScEditViewForwarder(EditView* pEditView, OutputDevice* pWin);
+
+ virtual bool IsValid() const override;
+ virtual Point LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const override;
+ virtual Point PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const override;
+ virtual bool GetSelection( ESelection& rSelection ) const override;
+ virtual bool SetSelection( const ESelection& rSelection ) override;
+ virtual bool Copy() override;
+ virtual bool Cut() override;
+ virtual bool Paste() override;
+
+ void SetInvalid();
+};
+
+ScEditViewForwarder::ScEditViewForwarder(EditView* pEditView, OutputDevice* pWin)
+ : mpEditView(pEditView)
+ , mpWindow(pWin)
+{
+}
+
+bool ScEditViewForwarder::IsValid() const
+{
+ return mpWindow && mpEditView;
+}
+
+Point ScEditViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ if (mpWindow)
+ return mpWindow->LogicToPixel( rPoint, rMapMode );
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return Point();
+}
+
+Point ScEditViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ if (mpWindow)
+ return mpWindow->PixelToLogic( rPoint, rMapMode );
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return Point();
+}
+
+bool ScEditViewForwarder::GetSelection( ESelection& rSelection ) const
+{
+ bool bResult(false);
+ if (IsValid())
+ {
+ rSelection = mpEditView->GetSelection();
+ bResult = true;
+ }
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return bResult;
+}
+
+bool ScEditViewForwarder::SetSelection( const ESelection& rSelection )
+{
+ bool bResult(false);
+ if (IsValid())
+ {
+ mpEditView->SetSelection(rSelection);
+ bResult = true;
+ }
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return bResult;
+}
+
+bool ScEditViewForwarder::Copy()
+{
+ bool bResult(false);
+ if (IsValid())
+ {
+ mpEditView->Copy();
+ bResult = true;
+ }
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return bResult;
+}
+
+bool ScEditViewForwarder::Cut()
+{
+ bool bResult(false);
+ if (IsValid())
+ {
+ mpEditView->Cut();
+ bResult = true;
+ }
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return bResult;
+}
+
+bool ScEditViewForwarder::Paste()
+{
+ bool bResult(false);
+ if (IsValid())
+ {
+ mpEditView->Paste();
+ bResult = true;
+ }
+ else
+ {
+ OSL_FAIL("this ViewForwarder is not valid");
+ }
+ return bResult;
+}
+
+void ScEditViewForwarder::SetInvalid()
+{
+ mpWindow = nullptr;
+ mpEditView = nullptr;
+}
+
+// ScAccessibleCellTextData: shared data between sub objects of an accessible cell text object
+
+ScAccessibleCellTextData::ScAccessibleCellTextData(ScTabViewShell* pViewShell,
+ const ScAddress& rP, ScSplitPos eSplitPos, ScAccessibleCell* pAccCell)
+ : ScAccessibleCellBaseTextData(GetDocShell(pViewShell), rP),
+ mpViewShell(pViewShell),
+ meSplitPos(eSplitPos),
+ mpAccessibleCell( pAccCell )
+{
+}
+
+ScAccessibleCellTextData::~ScAccessibleCellTextData()
+{
+ if (pEditEngine)
+ pEditEngine->SetNotifyHdl(Link<EENotify&,void>());
+ mpViewForwarder.reset();
+}
+
+void ScAccessibleCellTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ mpViewShell = nullptr; // invalid now
+ if (mpViewForwarder)
+ mpViewForwarder->SetInvalid();
+ }
+ ScAccessibleCellBaseTextData::Notify(rBC, rHint);
+}
+
+ScAccessibleTextData* ScAccessibleCellTextData::Clone() const
+{
+ return new ScAccessibleCellTextData( mpViewShell, aCellPos, meSplitPos, mpAccessibleCell );
+}
+
+SvxTextForwarder* ScAccessibleCellTextData::GetTextForwarder()
+{
+ ScCellTextData::GetTextForwarder(); // creates Forwarder and EditEngine
+
+ if ( pDocShell && pEditEngine && mpViewShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ tools::Long nSizeX, nSizeY;
+ mpViewShell->GetViewData().GetMergeSizePixel(
+ aCellPos.Col(), aCellPos.Row(), nSizeX, nSizeY);
+
+ Size aSize(nSizeX, nSizeY);
+
+ // #i92143# text getRangeExtents reports incorrect 'x' values for spreadsheet cells
+ tools::Long nIndent = 0;
+ const SvxHorJustifyItem* pHorJustifyItem = rDoc.GetAttr( aCellPos, ATTR_HOR_JUSTIFY );
+ SvxCellHorJustify eHorJust = pHorJustifyItem ? pHorJustifyItem->GetValue() : SvxCellHorJustify::Standard;
+ if ( eHorJust == SvxCellHorJustify::Left )
+ {
+ const ScIndentItem* pIndentItem = rDoc.GetAttr( aCellPos, ATTR_INDENT );
+ if ( pIndentItem )
+ {
+ nIndent = static_cast< tools::Long >( pIndentItem->GetValue() );
+ }
+ }
+
+ const SvxMarginItem* pMarginItem = rDoc.GetAttr( aCellPos, ATTR_MARGIN );
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ double nPPTX = rViewData.GetPPTX();
+ double nPPTY = rViewData.GetPPTY();
+ tools::Long nLeftM = ( pMarginItem ? static_cast< tools::Long >( ( pMarginItem->GetLeftMargin() + nIndent ) * nPPTX ) : 0 );
+ tools::Long nTopM = ( pMarginItem ? static_cast< tools::Long >( pMarginItem->GetTopMargin() * nPPTY ) : 0 );
+ tools::Long nRightM = ( pMarginItem ? static_cast< tools::Long >( pMarginItem->GetRightMargin() * nPPTX ) : 0 );
+ tools::Long nBottomM = ( pMarginItem ? static_cast< tools::Long >( pMarginItem->GetBottomMargin() * nPPTY ) : 0 );
+ tools::Long nWidth = aSize.getWidth() - nLeftM - nRightM;
+ aSize.setWidth( nWidth );
+ aSize.setHeight( aSize.getHeight() - nTopM - nBottomM );
+
+ vcl::Window* pWin = mpViewShell->GetWindowByPos( meSplitPos );
+ if ( pWin )
+ {
+ aSize = pWin->PixelToLogic( aSize, pEditEngine->GetRefMapMode() );
+ }
+
+ /* #i19430# Gnopernicus reads text partly if it sticks out of the cell
+ boundaries. This leads to wrong results in cases where the cell text
+ is rotated, because rotation is not taken into account when calcu-
+ lating the visible part of the text. In these cases we will expand
+ the cell size passed as paper size to the edit engine. The function
+ accessibility::AccessibleStaticTextBase::GetParagraphBoundingBox()
+ (see svx/source/accessibility/AccessibleStaticTextBase.cxx) will
+ return the size of the complete text then, which is used to expand
+ the cell bounding box in ScAccessibleCell::GetBoundingBox()
+ (see sc/source/ui/Accessibility/AccessibleCell.cxx). */
+ const ScRotateValueItem* pItem = rDoc.GetAttr( aCellPos, ATTR_ROTATE_VALUE );
+ if( pItem && (pItem->GetValue() != 0_deg100) )
+ {
+ pEditEngine->SetPaperSize( Size( LONG_MAX, aSize.getHeight() ) );
+ tools::Long nTxtWidth = static_cast< tools::Long >( pEditEngine->CalcTextWidth() );
+ aSize.setWidth( std::max( aSize.getWidth(), nTxtWidth + 2 ) );
+ }
+ else
+ {
+ // #i92143# text getRangeExtents reports incorrect 'x' values for spreadsheet cells
+ const ScLineBreakCell* pLineBreakItem = rDoc.GetAttr( aCellPos, ATTR_LINEBREAK );
+ bool bLineBreak = ( pLineBreakItem && pLineBreakItem->GetValue() );
+ if ( !bLineBreak )
+ {
+ tools::Long nTxtWidth = static_cast< tools::Long >( pEditEngine->CalcTextWidth() );
+ aSize.setWidth( ::std::max( aSize.getWidth(), nTxtWidth ) );
+ }
+ }
+
+ pEditEngine->SetPaperSize( aSize );
+
+ // #i92143# text getRangeExtents reports incorrect 'x' values for spreadsheet cells
+ if ( eHorJust == SvxCellHorJustify::Standard && rDoc.HasValueData( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab() ) )
+ {
+ pEditEngine->SetDefaultItem( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
+ }
+
+ Size aTextSize;
+ if ( pWin )
+ {
+ aTextSize = pWin->LogicToPixel( Size( pEditEngine->CalcTextWidth(), pEditEngine->GetTextHeight() ), pEditEngine->GetRefMapMode() );
+ }
+ tools::Long nTextWidth = aTextSize.Width();
+ tools::Long nTextHeight = aTextSize.Height();
+
+ tools::Long nOffsetX = nLeftM;
+ tools::Long nDiffX = nTextWidth - nWidth;
+ if ( nDiffX > 0 )
+ {
+ switch ( eHorJust )
+ {
+ case SvxCellHorJustify::Right:
+ {
+ nOffsetX -= nDiffX;
+ }
+ break;
+ case SvxCellHorJustify::Center:
+ {
+ nOffsetX -= nDiffX / 2;
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+ }
+
+ tools::Long nOffsetY = 0;
+ const SvxVerJustifyItem* pVerJustifyItem = rDoc.GetAttr( aCellPos, ATTR_VER_JUSTIFY );
+ SvxCellVerJustify eVerJust = ( pVerJustifyItem ? pVerJustifyItem->GetValue() : SvxCellVerJustify::Standard );
+ switch ( eVerJust )
+ {
+ case SvxCellVerJustify::Standard:
+ case SvxCellVerJustify::Bottom:
+ {
+ nOffsetY = nSizeY - nBottomM - nTextHeight;
+ }
+ break;
+ case SvxCellVerJustify::Center:
+ {
+ nOffsetY = ( nSizeY - nTopM - nBottomM - nTextHeight ) / 2 + nTopM;
+ }
+ break;
+ default:
+ {
+ nOffsetY = nTopM;
+ }
+ break;
+ }
+
+ if ( mpAccessibleCell )
+ {
+ mpAccessibleCell->SetOffset( Point( nOffsetX, nOffsetY ) );
+ }
+
+ pEditEngine->SetNotifyHdl( LINK(this, ScAccessibleCellTextData, NotifyHdl) );
+ }
+
+ return pForwarder.get();
+}
+
+SvxViewForwarder* ScAccessibleCellTextData::GetViewForwarder()
+{
+ if (!mpViewForwarder)
+ mpViewForwarder.reset(new ScViewForwarder(mpViewShell, meSplitPos));
+ return mpViewForwarder.get();
+}
+
+SvxEditViewForwarder* ScAccessibleCellTextData::GetEditViewForwarder( bool /* bCreate */ )
+{
+ //#102219#; there should no EditViewForwarder be, because the cell is now readonly in this interface
+ return nullptr;
+}
+
+IMPL_LINK(ScAccessibleTextData, NotifyHdl, EENotify&, aNotify, void)
+{
+ ::std::unique_ptr< SfxHint > aHint = SvxEditSourceHelper::EENotification2Hint( &aNotify );
+
+ if (aHint)
+ GetBroadcaster().Broadcast(*aHint);
+}
+
+ScDocShell* ScAccessibleCellTextData::GetDocShell(ScTabViewShell* pViewShell)
+{
+ ScDocShell* pDocSh = nullptr;
+ if (pViewShell)
+ pDocSh = pViewShell->GetViewData().GetDocShell();
+ return pDocSh;
+}
+
+ScAccessibleEditObjectTextData::ScAccessibleEditObjectTextData(EditView* pEditView, OutputDevice* pWin, bool isClone)
+ :
+ mpEditView(pEditView),
+ mpEditEngine(pEditView ? pEditView->GetEditEngine() : nullptr),
+ mpWindow(pWin)
+{
+ // If the object is cloned, do NOT add notify hdl.
+ mbIsCloned = isClone;
+ if (mpEditEngine && !mbIsCloned)
+ mpEditEngine->SetNotifyHdl( LINK(this, ScAccessibleEditObjectTextData, NotifyHdl) );
+}
+
+ScAccessibleEditObjectTextData::~ScAccessibleEditObjectTextData()
+{
+ // If the object is cloned, do NOT set notify hdl.
+ if (mpEditEngine && !mbIsCloned)
+ mpEditEngine->SetNotifyHdl(Link<EENotify&,void>());
+ mpViewForwarder.reset();
+ mpEditViewForwarder.reset();
+ mpForwarder.reset();
+}
+
+void ScAccessibleEditObjectTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ mpWindow = nullptr;
+ mpEditView = nullptr;
+ mpEditEngine = nullptr;
+ mpForwarder.reset();
+ if (mpViewForwarder)
+ mpViewForwarder->SetInvalid();
+ if (mpEditViewForwarder)
+ mpEditViewForwarder->SetInvalid();
+ }
+ ScAccessibleTextData::Notify(rBC, rHint);
+}
+
+ScAccessibleTextData* ScAccessibleEditObjectTextData::Clone() const
+{
+ // Add para to indicate the object is cloned
+ return new ScAccessibleEditObjectTextData(mpEditView, mpWindow, true);
+}
+
+SvxTextForwarder* ScAccessibleEditObjectTextData::GetTextForwarder()
+{
+ if ((!mpForwarder && mpEditView) || (mpEditEngine && !mpEditEngine->GetNotifyHdl().IsSet()))
+ {
+ if (!mpEditEngine)
+ mpEditEngine = mpEditView->GetEditEngine();
+ // If the object is cloned, do NOT add notify hdl.
+ if (mpEditEngine && !mpEditEngine->GetNotifyHdl().IsSet()&&!mbIsCloned)
+ mpEditEngine->SetNotifyHdl( LINK(this, ScAccessibleEditObjectTextData, NotifyHdl) );
+ if(!mpForwarder)
+ mpForwarder.reset(new SvxEditEngineForwarder(*mpEditEngine));
+ }
+ return mpForwarder.get();
+}
+
+SvxViewForwarder* ScAccessibleEditObjectTextData::GetViewForwarder()
+{
+ if (!mpViewForwarder)
+ {
+ // i#49561 Get right-aligned cell content to be read by screenreader.
+ mpViewForwarder.reset(new ScEditObjectViewForwarder( mpWindow, mpEditView ));
+ }
+ return mpViewForwarder.get();
+}
+
+SvxEditViewForwarder* ScAccessibleEditObjectTextData::GetEditViewForwarder( bool bCreate )
+{
+ if (!mpEditViewForwarder && mpEditView)
+ mpEditViewForwarder.reset(new ScEditViewForwarder(mpEditView, mpWindow));
+ if (bCreate)
+ {
+ if (!mpEditView && mpEditViewForwarder)
+ {
+ mpEditViewForwarder.reset();
+ }
+ }
+ return mpEditViewForwarder.get();
+}
+
+IMPL_LINK(ScAccessibleEditObjectTextData, NotifyHdl, EENotify&, rNotify, void)
+{
+ ::std::unique_ptr< SfxHint > aHint = SvxEditSourceHelper::EENotification2Hint( &rNotify );
+
+ if (aHint)
+ GetBroadcaster().Broadcast(*aHint);
+}
+
+ScAccessibleEditLineTextData::ScAccessibleEditLineTextData(EditView* pEditView,
+ OutputDevice* pWin,
+ ScTextWnd* pTxtWnd)
+ : ScAccessibleEditObjectTextData(pEditView, pWin)
+ , mpTxtWnd(pTxtWnd)
+ , mbEditEngineCreated(false)
+{
+ if (mpTxtWnd)
+ mpTxtWnd->InsertAccessibleTextData( *this );
+}
+
+ScAccessibleEditLineTextData::~ScAccessibleEditLineTextData()
+{
+ if (mpTxtWnd)
+ mpTxtWnd->RemoveAccessibleTextData( *this );
+
+ if (mbEditEngineCreated && mpEditEngine)
+ {
+ delete mpEditEngine;
+ mpEditEngine = nullptr; // don't access in ScAccessibleEditObjectTextData dtor!
+ }
+ else if (mpTxtWnd && mpTxtWnd->HasEditView() && mpTxtWnd->GetEditView()->GetEditEngine())
+ {
+ // the NotifyHdl also has to be removed from the ScTextWnd's EditEngine
+ // (it's set in ScAccessibleEditLineTextData::GetTextForwarder, and mpEditEngine
+ // is reset there)
+ mpTxtWnd->GetEditView()->GetEditEngine()->SetNotifyHdl(Link<EENotify&,void>());
+ }
+}
+
+void ScAccessibleEditLineTextData::Dispose()
+{
+ if (mpTxtWnd)
+ mpTxtWnd->RemoveAccessibleTextData( *this );
+
+ ResetEditMode();
+ mpWindow = nullptr;
+ mpTxtWnd = nullptr;
+}
+
+ScAccessibleTextData* ScAccessibleEditLineTextData::Clone() const
+{
+ return new ScAccessibleEditLineTextData(mpEditView, mpWindow, mpTxtWnd);
+}
+
+SvxTextForwarder* ScAccessibleEditLineTextData::GetTextForwarder()
+{
+ if (mpTxtWnd)
+ {
+ if (mpTxtWnd->HasEditView())
+ {
+ mpEditView = mpTxtWnd->GetEditView();
+
+ if (mbEditEngineCreated && mpEditEngine)
+ ResetEditMode();
+ mbEditEngineCreated = false;
+
+ mpEditView = mpTxtWnd->GetEditView();
+ ScAccessibleEditObjectTextData::GetTextForwarder(); // fill the mpForwarder
+ mpEditEngine = nullptr;
+ }
+ else
+ {
+ mpEditView = nullptr;
+
+ if (mpEditEngine && !mbEditEngineCreated)
+ ResetEditMode();
+ if (!mpEditEngine)
+ {
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->FreezeIdRanges();
+ mpEditEngine = new ScFieldEditEngine(nullptr, pEnginePool.get(), nullptr, true);
+ mbEditEngineCreated = true;
+ mpEditEngine->EnableUndo( false );
+ mpEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
+ mpForwarder.reset(new SvxEditEngineForwarder(*mpEditEngine));
+
+ mpEditEngine->SetText(mpTxtWnd->GetTextString());
+
+#if 0
+ Size aSize(pTxtWnd->GetSizePixel());
+ aSize = pTxtWnd->PixelToLogic(aSize, mpEditEngine->GetRefMapMode());
+ mpEditEngine->SetPaperSize(aSize);
+#else
+ OutputDevice& rDevice = mpTxtWnd->GetDrawingArea()->get_ref_device();
+ Size aSize(rDevice.GetOutputSizePixel());
+ aSize = rDevice.PixelToLogic(aSize, mpEditEngine->GetRefMapMode());
+ mpEditEngine->SetPaperSize(aSize);
+#endif
+
+ mpEditEngine->SetNotifyHdl( LINK(this, ScAccessibleEditObjectTextData, NotifyHdl) );
+ }
+ }
+ }
+ return mpForwarder.get();
+}
+
+SvxEditViewForwarder* ScAccessibleEditLineTextData::GetEditViewForwarder( bool bCreate )
+{
+ if (mpTxtWnd)
+ {
+ if (!mpTxtWnd->HasEditView() && bCreate)
+ {
+ if ( !mpTxtWnd->IsInputActive() )
+ {
+ mpTxtWnd->StartEditEngine();
+ mpTxtWnd->GrabFocus();
+
+ mpEditView = mpTxtWnd->GetEditView();
+ }
+ }
+ }
+
+ return ScAccessibleEditObjectTextData::GetEditViewForwarder(bCreate);
+}
+
+void ScAccessibleEditLineTextData::ResetEditMode()
+{
+ if (mbEditEngineCreated && mpEditEngine)
+ delete mpEditEngine;
+ else if (mpTxtWnd && mpTxtWnd->HasEditView() && mpTxtWnd->GetEditView()->GetEditEngine())
+ mpTxtWnd->GetEditView()->GetEditEngine()->SetNotifyHdl(Link<EENotify&,void>());
+ mpEditEngine = nullptr;
+
+ mpForwarder.reset();
+ mpEditViewForwarder.reset();
+ mpViewForwarder.reset();
+ mbEditEngineCreated = false;
+}
+
+void ScAccessibleEditLineTextData::TextChanged()
+{
+ if (mbEditEngineCreated && mpEditEngine)
+ {
+ if (mpTxtWnd)
+ mpEditEngine->SetText(mpTxtWnd->GetTextString());
+ }
+}
+
+void ScAccessibleEditLineTextData::StartEdit()
+{
+ ResetEditMode();
+ mpEditView = nullptr;
+
+ // send SdrHintKind::BeginEdit
+ SdrHint aHint(SdrHintKind::BeginEdit);
+ GetBroadcaster().Broadcast( aHint );
+}
+
+void ScAccessibleEditLineTextData::EndEdit()
+{
+ // send SdrHintKind::EndEdit
+ SdrHint aHint(SdrHintKind::EndEdit);
+ GetBroadcaster().Broadcast( aHint );
+
+ ResetEditMode();
+ mpEditView = nullptr;
+}
+
+// ScAccessiblePreviewCellTextData: shared data between sub objects of an accessible cell text object
+
+ScAccessiblePreviewCellTextData::ScAccessiblePreviewCellTextData(ScPreviewShell* pViewShell,
+ const ScAddress& rP)
+ : ScAccessibleCellBaseTextData(GetDocShell(pViewShell), rP),
+ mpViewShell(pViewShell)
+{
+}
+
+ScAccessiblePreviewCellTextData::~ScAccessiblePreviewCellTextData()
+{
+ if (pEditEngine)
+ pEditEngine->SetNotifyHdl(Link<EENotify&,void>());
+ mpViewForwarder.reset();
+}
+
+void ScAccessiblePreviewCellTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ mpViewShell = nullptr; // invalid now
+ if (mpViewForwarder)
+ mpViewForwarder->SetInvalid();
+ }
+ ScAccessibleCellBaseTextData::Notify(rBC, rHint);
+}
+
+ScAccessibleTextData* ScAccessiblePreviewCellTextData::Clone() const
+{
+ return new ScAccessiblePreviewCellTextData(mpViewShell, aCellPos);
+}
+
+SvxTextForwarder* ScAccessiblePreviewCellTextData::GetTextForwarder()
+{
+ bool bEditEngineBefore(pEditEngine != nullptr);
+
+ ScCellTextData::GetTextForwarder(); // creates Forwarder and EditEngine
+
+ if (!bEditEngineBefore && pEditEngine)
+ {
+ Size aSize(mpViewShell->GetLocationData().GetCellOutputRect(aCellPos).GetSize());
+ vcl::Window* pWin = mpViewShell->GetWindow();
+ if (pWin)
+ aSize = pWin->PixelToLogic(aSize, pEditEngine->GetRefMapMode());
+ pEditEngine->SetPaperSize(aSize);
+ }
+
+ if (pEditEngine)
+ pEditEngine->SetNotifyHdl( LINK(this, ScAccessiblePreviewCellTextData, NotifyHdl) );
+
+ return pForwarder.get();
+}
+
+SvxViewForwarder* ScAccessiblePreviewCellTextData::GetViewForwarder()
+{
+ if (!mpViewForwarder)
+ mpViewForwarder.reset(new ScPreviewCellViewForwarder(mpViewShell));
+ return mpViewForwarder.get();
+}
+
+ScDocShell* ScAccessiblePreviewCellTextData::GetDocShell(ScPreviewShell* pViewShell)
+{
+ ScDocShell* pDocSh = nullptr;
+ if (pViewShell)
+ pDocSh = static_cast<ScDocShell*>( pViewShell->GetDocument().GetDocumentShell());
+ return pDocSh;
+}
+
+// ScAccessiblePreviewHeaderCellTextData: shared data between sub objects of an accessible cell text object
+
+ScAccessiblePreviewHeaderCellTextData::ScAccessiblePreviewHeaderCellTextData(ScPreviewShell* pViewShell,
+ const OUString& rText, const ScAddress& rP, bool bColHeader, bool bRowHeader)
+ : ScAccessibleCellBaseTextData(GetDocShell(pViewShell), rP),
+ mpViewShell(pViewShell),
+ maText(rText),
+ mbColHeader(bColHeader),
+ mbRowHeader(bRowHeader)
+{
+}
+
+ScAccessiblePreviewHeaderCellTextData::~ScAccessiblePreviewHeaderCellTextData()
+{
+ if (pEditEngine)
+ pEditEngine->SetNotifyHdl(Link<EENotify&,void>());
+ mpViewForwarder.reset();
+}
+
+void ScAccessiblePreviewHeaderCellTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ mpViewShell = nullptr; // invalid now
+ if (mpViewForwarder)
+ mpViewForwarder->SetInvalid();
+ }
+ ScAccessibleCellBaseTextData::Notify(rBC, rHint);
+}
+
+ScAccessibleTextData* ScAccessiblePreviewHeaderCellTextData::Clone() const
+{
+ return new ScAccessiblePreviewHeaderCellTextData(mpViewShell, maText, aCellPos, mbColHeader, mbRowHeader);
+}
+
+SvxTextForwarder* ScAccessiblePreviewHeaderCellTextData::GetTextForwarder()
+{
+ if (!pEditEngine)
+ {
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pEditEngine = rDoc.CreateFieldEditEngine();
+ }
+ else
+ {
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->FreezeIdRanges();
+ pEditEngine.reset( new ScFieldEditEngine(nullptr, pEnginePool.get(), nullptr, true) );
+ }
+ pEditEngine->EnableUndo( false );
+ if (pDocShell)
+ pEditEngine->SetRefDevice(pDocShell->GetRefDevice());
+ else
+ pEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
+ pForwarder.reset( new SvxEditEngineForwarder(*pEditEngine) );
+ }
+
+ if (bDataValid)
+ return pForwarder.get();
+
+ if (!maText.isEmpty())
+ {
+ if ( mpViewShell )
+ {
+ Size aOutputSize;
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if ( pWindow )
+ aOutputSize = pWindow->GetOutputSizePixel();
+ tools::Rectangle aVisRect( Point(), aOutputSize );
+ Size aSize(mpViewShell->GetLocationData().GetHeaderCellOutputRect(aVisRect, aCellPos, mbColHeader).GetSize());
+ if (pWindow)
+ aSize = pWindow->PixelToLogic(aSize, pEditEngine->GetRefMapMode());
+ pEditEngine->SetPaperSize(aSize);
+ }
+ pEditEngine->SetTextCurrentDefaults( maText );
+ }
+
+ bDataValid = true;
+
+ pEditEngine->SetNotifyHdl( LINK(this, ScAccessiblePreviewHeaderCellTextData, NotifyHdl) );
+
+ return pForwarder.get();
+}
+
+SvxViewForwarder* ScAccessiblePreviewHeaderCellTextData::GetViewForwarder()
+{
+ if (!mpViewForwarder)
+ mpViewForwarder.reset(new ScPreviewHeaderCellViewForwarder(mpViewShell));
+ return mpViewForwarder.get();
+}
+
+ScDocShell* ScAccessiblePreviewHeaderCellTextData::GetDocShell(ScPreviewShell* pViewShell)
+{
+ ScDocShell* pDocSh = nullptr;
+ if (pViewShell)
+ pDocSh = static_cast<ScDocShell*>(pViewShell->GetDocument().GetDocumentShell());
+ return pDocSh;
+}
+
+ScAccessibleHeaderTextData::ScAccessibleHeaderTextData(ScPreviewShell* pViewShell,
+ const EditTextObject* pEditObj, SvxAdjust eAdjust)
+ :
+ mpViewShell(pViewShell),
+ mpDocSh(nullptr),
+ mpEditObj(pEditObj),
+ mbDataValid(false),
+ meAdjust(eAdjust)
+{
+ if (pViewShell)
+ mpDocSh = static_cast<ScDocShell*>(pViewShell->GetDocument().GetDocumentShell());
+ if (mpDocSh)
+ mpDocSh->GetDocument().AddUnoObject(*this);
+}
+
+ScAccessibleHeaderTextData::~ScAccessibleHeaderTextData()
+{
+ SolarMutexGuard aGuard; // needed for EditEngine dtor
+
+ if (mpDocSh)
+ mpDocSh->GetDocument().RemoveUnoObject(*this);
+ if (mpEditEngine)
+ mpEditEngine->SetNotifyHdl(Link<EENotify&,void>());
+ mpEditEngine.reset();
+ mpForwarder.reset();
+}
+
+ScAccessibleTextData* ScAccessibleHeaderTextData::Clone() const
+{
+ return new ScAccessibleHeaderTextData(mpViewShell, mpEditObj, meAdjust);
+}
+
+void ScAccessibleHeaderTextData::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ mpViewShell = nullptr;// invalid now
+ mpDocSh = nullptr;
+ if (mxViewForwarder)
+ mxViewForwarder->SetInvalid();
+ }
+}
+
+SvxTextForwarder* ScAccessibleHeaderTextData::GetTextForwarder()
+{
+ if (!mpEditEngine)
+ {
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->FreezeIdRanges();
+ std::unique_ptr<ScHeaderEditEngine> pHdrEngine(new ScHeaderEditEngine( pEnginePool.get() ));
+
+ pHdrEngine->EnableUndo( false );
+ pHdrEngine->SetRefMapMode(MapMode(MapUnit::MapTwip));
+
+ // default font must be set, independently of document
+ // -> use global pool from module
+
+ SfxItemSet aDefaults( pHdrEngine->GetEmptyItemSet() );
+ const ScPatternAttr& rPattern = SC_MOD()->GetPool().GetDefaultItem(ATTR_PATTERN);
+ rPattern.FillEditItemSet( &aDefaults );
+ // FillEditItemSet adjusts font height to 1/100th mm,
+ // but for header/footer twips is needed, as in the PatternAttr:
+ aDefaults.Put( rPattern.GetItem(ATTR_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT) );
+ aDefaults.Put( rPattern.GetItem(ATTR_CJK_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CJK) );
+ aDefaults.Put( rPattern.GetItem(ATTR_CTL_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CTL) );
+ aDefaults.Put( SvxAdjustItem( meAdjust, EE_PARA_JUST ) );
+ pHdrEngine->SetDefaults( aDefaults );
+
+ ScHeaderFieldData aData;
+ if (mpViewShell)
+ mpViewShell->FillFieldData(aData);
+ else
+ ScHeaderFooterTextObj::FillDummyFieldData( aData );
+ pHdrEngine->SetData( aData );
+
+ mpEditEngine = std::move(pHdrEngine);
+ mpForwarder.reset(new SvxEditEngineForwarder(*mpEditEngine));
+ }
+
+ if (mbDataValid)
+ return mpForwarder.get();
+
+ if ( mpViewShell )
+ {
+ tools::Rectangle aVisRect;
+ mpViewShell->GetLocationData().GetHeaderPosition(aVisRect);
+ Size aSize(aVisRect.GetSize());
+ vcl::Window* pWin = mpViewShell->GetWindow();
+ if (pWin)
+ aSize = pWin->PixelToLogic(aSize, mpEditEngine->GetRefMapMode());
+ mpEditEngine->SetPaperSize(aSize);
+ }
+ if (mpEditObj)
+ mpEditEngine->SetTextCurrentDefaults(*mpEditObj);
+
+ mbDataValid = true;
+ return mpForwarder.get();
+}
+
+SvxViewForwarder* ScAccessibleHeaderTextData::GetViewForwarder()
+{
+ if (!mxViewForwarder)
+ mxViewForwarder = std::make_unique<ScPreviewHeaderFooterViewForwarder>(mpViewShell);
+ return mxViewForwarder.get();
+}
+
+ScAccessibleNoteTextData::ScAccessibleNoteTextData(ScPreviewShell* pViewShell,
+ const OUString& sText, const ScAddress& aCellPos, bool bMarkNote)
+ :
+ mpViewShell(pViewShell),
+ mpDocSh(nullptr),
+ msText(sText),
+ maCellPos(aCellPos),
+ mbMarkNote(bMarkNote),
+ mbDataValid(false)
+{
+ if (pViewShell)
+ mpDocSh = static_cast<ScDocShell*>(pViewShell->GetDocument().GetDocumentShell());
+ if (mpDocSh)
+ mpDocSh->GetDocument().AddUnoObject(*this);
+}
+
+ScAccessibleNoteTextData::~ScAccessibleNoteTextData()
+{
+ SolarMutexGuard aGuard; // needed for EditEngine dtor
+
+ if (mpDocSh)
+ mpDocSh->GetDocument().RemoveUnoObject(*this);
+ if (mpEditEngine)
+ mpEditEngine->SetNotifyHdl(Link<EENotify&,void>());
+ mpEditEngine.reset();
+ mpForwarder.reset();
+}
+
+ScAccessibleTextData* ScAccessibleNoteTextData::Clone() const
+{
+ return new ScAccessibleNoteTextData(mpViewShell, msText, maCellPos, mbMarkNote);
+}
+
+void ScAccessibleNoteTextData::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ mpViewShell = nullptr;// invalid now
+ mpDocSh = nullptr;
+ if (mxViewForwarder)
+ mxViewForwarder->SetInvalid();
+ }
+}
+
+SvxTextForwarder* ScAccessibleNoteTextData::GetTextForwarder()
+{
+ if (!mpEditEngine)
+ {
+ if ( mpDocSh )
+ {
+ ScDocument& rDoc = mpDocSh->GetDocument();
+ mpEditEngine = rDoc.CreateFieldEditEngine();
+ }
+ else
+ {
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->FreezeIdRanges();
+ mpEditEngine.reset( new ScFieldEditEngine(nullptr, pEnginePool.get(), nullptr, true) );
+ }
+ mpEditEngine->EnableUndo( false );
+ if (mpDocSh)
+ mpEditEngine->SetRefDevice(mpDocSh->GetRefDevice());
+ else
+ mpEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
+ mpForwarder.reset( new SvxEditEngineForwarder(*mpEditEngine) );
+ }
+
+ if (mbDataValid)
+ return mpForwarder.get();
+
+ if (!msText.isEmpty())
+ {
+
+ if ( mpViewShell )
+ {
+ Size aOutputSize;
+ vcl::Window* pWindow = mpViewShell->GetWindow();
+ if ( pWindow )
+ aOutputSize = pWindow->GetOutputSizePixel();
+ tools::Rectangle aVisRect( Point(), aOutputSize );
+ Size aSize(mpViewShell->GetLocationData().GetNoteInRangeOutputRect(aVisRect, mbMarkNote, maCellPos).GetSize());
+ if (pWindow)
+ aSize = pWindow->PixelToLogic(aSize, mpEditEngine->GetRefMapMode());
+ mpEditEngine->SetPaperSize(aSize);
+ }
+ mpEditEngine->SetTextCurrentDefaults( msText );
+ }
+
+ mbDataValid = true;
+
+ mpEditEngine->SetNotifyHdl( LINK(this, ScAccessibleNoteTextData, NotifyHdl) );
+
+ return mpForwarder.get();
+}
+
+SvxViewForwarder* ScAccessibleNoteTextData::GetViewForwarder()
+{
+ if (!mxViewForwarder)
+ mxViewForwarder = std::make_unique<ScPreviewNoteViewForwarder>(mpViewShell);
+ return mxViewForwarder.get();
+}
+
+// CSV import =================================================================
+
+class ScCsvViewForwarder : public SvxViewForwarder
+{
+ VclPtr<OutputDevice> mpWindow;
+
+public:
+ explicit ScCsvViewForwarder( OutputDevice* pWindow );
+
+ 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;
+
+ void SetInvalid();
+};
+
+ScCsvViewForwarder::ScCsvViewForwarder( OutputDevice* pWindow ) :
+ mpWindow( pWindow )
+{
+}
+
+bool ScCsvViewForwarder::IsValid() const
+{
+ return mpWindow != nullptr;
+}
+
+Point ScCsvViewForwarder::LogicToPixel( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ if( !mpWindow ) return Point();
+ return mpWindow->LogicToPixel( rPoint, rMapMode );
+}
+
+Point ScCsvViewForwarder::PixelToLogic( const Point& rPoint, const MapMode& rMapMode ) const
+{
+ if( !mpWindow ) return Point();
+ return mpWindow->PixelToLogic( rPoint, rMapMode );
+}
+
+void ScCsvViewForwarder::SetInvalid()
+{
+ mpWindow = nullptr;
+}
+
+ScAccessibleCsvTextData::ScAccessibleCsvTextData(
+ OutputDevice* pWindow, EditEngine* pEditEngine,
+ const OUString& rCellText, const Size& rCellSize ) :
+ mpWindow( pWindow ),
+ mpEditEngine( pEditEngine ),
+ maCellText( rCellText ),
+ maCellSize( rCellSize )
+{
+}
+
+ScAccessibleCsvTextData::~ScAccessibleCsvTextData()
+{
+}
+
+void ScAccessibleCsvTextData::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ mpWindow = nullptr;
+ mpEditEngine = nullptr;
+ if (mpViewForwarder)
+ mpViewForwarder->SetInvalid();
+ }
+ ScAccessibleTextData::Notify( rBC, rHint );
+}
+
+ScAccessibleTextData* ScAccessibleCsvTextData::Clone() const
+{
+ return new ScAccessibleCsvTextData( mpWindow, mpEditEngine, maCellText, maCellSize );
+}
+
+SvxTextForwarder* ScAccessibleCsvTextData::GetTextForwarder()
+{
+ if( mpEditEngine )
+ {
+ mpEditEngine->SetPaperSize( maCellSize );
+ mpEditEngine->SetText( maCellText );
+ if( !mpTextForwarder )
+ mpTextForwarder.reset( new SvxEditEngineForwarder( *mpEditEngine ) );
+ }
+ else
+ mpTextForwarder.reset();
+ return mpTextForwarder.get();
+}
+
+SvxViewForwarder* ScAccessibleCsvTextData::GetViewForwarder()
+{
+ if( !mpViewForwarder )
+ mpViewForwarder.reset( new ScCsvViewForwarder( mpWindow ) );
+ return mpViewForwarder.get();
+}
+
+SvxEditViewForwarder* ScAccessibleCsvTextData::GetEditViewForwarder( bool /* bCreate */ )
+{
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx b/sc/source/ui/Accessibility/DrawModelBroadcaster.cxx
new file mode 100644
index 000000000..c181656fe
--- /dev/null
+++ b/sc/source/ui/Accessibility/DrawModelBroadcaster.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 <DrawModelBroadcaster.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/unomod.hxx>
+#include <svx/svdobj.hxx>
+
+using namespace ::com::sun::star;
+
+ScDrawModelBroadcaster::ScDrawModelBroadcaster( SdrModel *pDrawModel ) :
+ mpDrawModel( pDrawModel )
+{
+ if (mpDrawModel)
+ StartListening( *mpDrawModel );
+}
+
+ScDrawModelBroadcaster::~ScDrawModelBroadcaster()
+{
+ if (mpDrawModel)
+ EndListening( *mpDrawModel );
+}
+
+void SAL_CALL ScDrawModelBroadcaster::addEventListener( const uno::Reference< document::XEventListener >& xListener )
+{
+ std::unique_lock aGuard(maListenerMutex);
+ maEventListeners.addInterface( aGuard, xListener );
+}
+
+void SAL_CALL ScDrawModelBroadcaster::removeEventListener( const uno::Reference< document::XEventListener >& xListener )
+{
+ std::unique_lock aGuard(maListenerMutex);
+ maEventListeners.removeInterface( aGuard, xListener );
+}
+
+void SAL_CALL ScDrawModelBroadcaster::addShapeEventListener(
+ const css::uno::Reference< css::drawing::XShape >& xShape,
+ const uno::Reference< document::XShapeEventListener >& xListener )
+{
+ assert(xShape.is() && "no shape?");
+ std::scoped_lock aGuard(maListenerMutex);
+ auto rv = maShapeListeners.emplace(xShape, xListener);
+ assert(rv.second && "duplicate listener?");
+ (void)rv;
+}
+
+void SAL_CALL ScDrawModelBroadcaster::removeShapeEventListener(
+ const css::uno::Reference< css::drawing::XShape >& xShape,
+ const uno::Reference< document::XShapeEventListener >& xListener )
+{
+ std::scoped_lock aGuard(maListenerMutex);
+ auto it = maShapeListeners.find(xShape);
+ if (it != maShapeListeners.end())
+ {
+ assert(it->second == xListener && "removing wrong listener?");
+ (void)xListener;
+ maShapeListeners.erase(it);
+ }
+}
+
+void ScDrawModelBroadcaster::Notify( SfxBroadcaster&,
+ const SfxHint& rHint )
+{
+ if (rHint.GetId() != SfxHintId::ThisIsAnSdrHint)
+ return;
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+
+ document::EventObject aEvent;
+ if( !SvxUnoDrawMSFactory::createEvent( mpDrawModel, pSdrHint, aEvent ) )
+ return;
+
+ std::unique_lock aGuard(maListenerMutex);
+ maEventListeners.forEach(aGuard,
+ [&aEvent](const css::uno::Reference<document::XEventListener>& xListener)
+ {
+ xListener->notifyEvent(aEvent);
+ }
+ );
+
+ // right now, we're only handling the specific event necessary to fix this performance problem
+ if (pSdrHint->GetKind() == SdrHintKind::ObjectChange)
+ {
+ auto pSdrObject = const_cast<SdrObject*>(pSdrHint->GetObject());
+ uno::Reference<drawing::XShape> xShape(pSdrObject->getUnoShape(), uno::UNO_QUERY);
+ auto it = maShapeListeners.find(xShape);
+ if (it != maShapeListeners.end())
+ it->second->notifyShapeEvent(aEvent);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/AnalysisOfVarianceDialog.cxx b/sc/source/ui/StatisticsDialogs/AnalysisOfVarianceDialog.cxx
new file mode 100644
index 000000000..f6871ccff
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/AnalysisOfVarianceDialog.cxx
@@ -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/.
+ *
+ */
+
+#include <memory>
+#include <string_view>
+
+#include <rangelst.hxx>
+#include <reffact.hxx>
+#include <TableFillingAndNavigationTools.hxx>
+#include <AnalysisOfVarianceDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+namespace
+{
+
+struct StatisticCalculation {
+ TranslateId aLabelId;
+ const char* aFormula;
+ const char* aResultRangeName;
+};
+
+StatisticCalculation const lclBasicStatistics[] =
+{
+ { STR_ANOVA_LABEL_GROUPS, nullptr, nullptr },
+ { STRID_CALC_COUNT, "=COUNT(%RANGE%)", "COUNT_RANGE" },
+ { STRID_CALC_SUM, "=SUM(%RANGE%)", "SUM_RANGE" },
+ { STRID_CALC_MEAN, "=AVERAGE(%RANGE%)", "MEAN_RANGE" },
+ { STRID_CALC_VARIANCE, "=VAR(%RANGE%)", "VAR_RANGE" },
+ { {}, nullptr, nullptr }
+};
+
+const TranslateId lclAnovaLabels[] =
+{
+ STR_ANOVA_LABEL_SOURCE_OF_VARIATION,
+ STR_ANOVA_LABEL_SS,
+ STR_ANOVA_LABEL_DF,
+ STR_ANOVA_LABEL_MS,
+ STR_ANOVA_LABEL_F,
+ STR_ANOVA_LABEL_P_VALUE,
+ STR_ANOVA_LABEL_F_CRITICAL,
+ {}
+};
+
+constexpr OUStringLiteral strWildcardRange = u"%RANGE%";
+
+OUString lclCreateMultiParameterFormula(
+ ScRangeList& aRangeList, const OUString& aFormulaTemplate,
+ std::u16string_view aWildcard, const ScDocument& rDocument,
+ const ScAddress::Details& aAddressDetails)
+{
+ OUStringBuffer aResult;
+ for (size_t i = 0; i < aRangeList.size(); i++)
+ {
+ OUString aRangeString(aRangeList[i].Format(rDocument, ScRefFlags::RANGE_ABS_3D, aAddressDetails));
+ OUString aFormulaString = aFormulaTemplate.replaceAll(aWildcard, aRangeString);
+ aResult.append(aFormulaString);
+ if(i != aRangeList.size() - 1) // Not Last
+ aResult.append(";");
+ }
+ return aResult.makeStringAndClear();
+}
+
+void lclMakeSubRangesList(ScRangeList& rRangeList, const ScRange& rInputRange, ScStatisticsInputOutputDialog::GroupedBy aGroupedBy)
+{
+ std::unique_ptr<DataRangeIterator> pIterator;
+ if (aGroupedBy == ScStatisticsInputOutputDialog::BY_COLUMN)
+ pIterator.reset(new DataRangeByColumnIterator(rInputRange));
+ else
+ pIterator.reset(new DataRangeByRowIterator(rInputRange));
+
+ for( ; pIterator->hasNext(); pIterator->next() )
+ {
+ ScRange aRange = pIterator->get();
+ rRangeList.push_back(aRange);
+ }
+}
+
+}
+
+ScAnalysisOfVarianceDialog::ScAnalysisOfVarianceDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData )
+ : ScStatisticsInputOutputDialog(
+ pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/analysisofvariancedialog.ui",
+ "AnalysisOfVarianceDialog")
+ , meFactor(SINGLE_FACTOR)
+ , mxAlphaField(m_xBuilder->weld_spin_button("alpha-spin"))
+ , mxSingleFactorRadio(m_xBuilder->weld_radio_button("radio-single-factor"))
+ , mxTwoFactorRadio(m_xBuilder->weld_radio_button("radio-two-factor"))
+ , mxRowsPerSampleField(m_xBuilder->weld_spin_button("rows-per-sample-spin"))
+{
+ mxSingleFactorRadio->connect_toggled( LINK( this, ScAnalysisOfVarianceDialog, FactorChanged ) );
+ mxTwoFactorRadio->connect_toggled( LINK( this, ScAnalysisOfVarianceDialog, FactorChanged ) );
+
+ mxSingleFactorRadio->set_active(true);
+ mxTwoFactorRadio->set_active(false);
+
+ FactorChanged();
+}
+
+ScAnalysisOfVarianceDialog::~ScAnalysisOfVarianceDialog()
+{
+}
+
+void ScAnalysisOfVarianceDialog::Close()
+{
+ DoClose( ScAnalysisOfVarianceDialogWrapper::GetChildWindowId() );
+}
+
+TranslateId ScAnalysisOfVarianceDialog::GetUndoNameId()
+{
+ return STR_ANALYSIS_OF_VARIANCE_UNDO_NAME;
+}
+
+IMPL_LINK_NOARG( ScAnalysisOfVarianceDialog, FactorChanged, weld::Toggleable&, void )
+{
+ FactorChanged();
+}
+
+void ScAnalysisOfVarianceDialog::FactorChanged()
+{
+ if (mxSingleFactorRadio->get_active())
+ {
+ mxGroupByRowsRadio->set_sensitive(true);
+ mxGroupByColumnsRadio->set_sensitive(true);
+ mxRowsPerSampleField->set_sensitive(false);
+ meFactor = SINGLE_FACTOR;
+ }
+ else if (mxTwoFactorRadio->get_active())
+ {
+ mxGroupByRowsRadio->set_sensitive(false);
+ mxGroupByColumnsRadio->set_sensitive(false);
+ mxRowsPerSampleField->set_sensitive(false); // Rows per sample not yet implemented
+ meFactor = TWO_FACTOR;
+ }
+}
+
+void ScAnalysisOfVarianceDialog::RowColumn(ScRangeList& rRangeList, AddressWalkerWriter& aOutput, FormulaTemplate& aTemplate,
+ const OUString& sFormula, GroupedBy aGroupedBy, ScRange* pResultRange)
+{
+ if (pResultRange != nullptr)
+ pResultRange->aStart = aOutput.current();
+ if (!sFormula.isEmpty())
+ {
+ for (size_t i = 0; i < rRangeList.size(); i++)
+ {
+ ScRange const & rRange = rRangeList[i];
+ aTemplate.setTemplate(sFormula);
+ aTemplate.applyRange(strWildcardRange, rRange);
+ aOutput.writeFormula(aTemplate.getTemplate());
+ if (pResultRange != nullptr)
+ pResultRange->aEnd = aOutput.current();
+ aOutput.nextRow();
+ }
+ }
+ else
+ {
+ TranslateId pLabelId = (aGroupedBy == BY_COLUMN) ? STR_COLUMN_LABEL_TEMPLATE : STR_ROW_LABEL_TEMPLATE;
+ OUString aLabelTemplate(ScResId(pLabelId));
+
+ for (size_t i = 0; i < rRangeList.size(); i++)
+ {
+ aTemplate.setTemplate(aLabelTemplate);
+ aTemplate.applyNumber(u"%NUMBER%", i + 1);
+ aOutput.writeString(aTemplate.getTemplate());
+ if (pResultRange != nullptr)
+ pResultRange->aEnd = aOutput.current();
+ aOutput.nextRow();
+ }
+ }
+}
+
+void ScAnalysisOfVarianceDialog::AnovaSingleFactor(AddressWalkerWriter& output, FormulaTemplate& aTemplate)
+{
+ output.writeBoldString(ScResId(STR_ANOVA_SINGLE_FACTOR_LABEL));
+ output.newLine();
+
+ double aAlphaValue = mxAlphaField->get_value() / 100.0;
+ output.writeString(ScResId(STR_LABEL_ALPHA));
+ output.nextColumn();
+ output.writeValue(aAlphaValue);
+ aTemplate.autoReplaceAddress("%ALPHA%", output.current());
+ output.newLine();
+ output.newLine();
+
+ // Write labels
+ for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
+ {
+ output.writeString(ScResId(lclBasicStatistics[i].aLabelId));
+ output.nextColumn();
+ }
+ output.newLine();
+
+ // Collect aRangeList
+ ScRangeList aRangeList;
+ lclMakeSubRangesList(aRangeList, mInputRange, mGroupedBy);
+
+ output.push();
+
+ // Write values
+ for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
+ {
+ output.resetRow();
+ ScRange aResultRange;
+ OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
+ RowColumn(aRangeList, output, aTemplate, sFormula, mGroupedBy, &aResultRange);
+ output.nextColumn();
+ if (lclBasicStatistics[i].aResultRangeName != nullptr)
+ {
+ OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
+ aTemplate.autoReplaceRange("%" + sResultRangeName + "%", aResultRange);
+ }
+ }
+
+ output.nextRow(); // Blank row
+
+ // Write ANOVA labels
+ output.resetColumn();
+ for(sal_Int32 i = 0; lclAnovaLabels[i]; i++)
+ {
+ output.writeString(ScResId(lclAnovaLabels[i]));
+ output.nextColumn();
+ }
+ output.nextRow();
+
+ aTemplate.autoReplaceRange("%FIRST_COLUMN%", aRangeList[0]);
+
+ // Between Groups
+ {
+ // Label
+ output.resetColumn();
+ output.writeString(ScResId(STR_ANOVA_LABEL_BETWEEN_GROUPS));
+ output.nextColumn();
+
+ // Sum of Squares
+ aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE%;%MEAN_RANGE%)-SUM(%SUM_RANGE%)^2/SUM(%COUNT_RANGE%)");
+ aTemplate.autoReplaceAddress("%BETWEEN_SS%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // Degree of freedom
+ aTemplate.setTemplate("=COUNT(%SUM_RANGE%)-1");
+ aTemplate.autoReplaceAddress("%BETWEEN_DF%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // MS
+ aTemplate.setTemplate("=%BETWEEN_SS% / %BETWEEN_DF%");
+ aTemplate.autoReplaceAddress("%BETWEEN_MS%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // F
+ aTemplate.setTemplate("=%BETWEEN_MS% / %WITHIN_MS%");
+ aTemplate.applyAddress(u"%WITHIN_MS%", output.current(-1, 1));
+ aTemplate.autoReplaceAddress("%F_VAL%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // P-value
+ aTemplate.setTemplate("=FDIST(%F_VAL%; %BETWEEN_DF%; %WITHIN_DF%");
+ aTemplate.applyAddress(u"%WITHIN_DF%", output.current(-3, 1));
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // F critical
+ aTemplate.setTemplate("=FINV(%ALPHA%; %BETWEEN_DF%; %WITHIN_DF%");
+ aTemplate.applyAddress(u"%WITHIN_DF%", output.current(-4, 1));
+ output.writeFormula(aTemplate.getTemplate());
+ }
+ output.nextRow();
+
+ // Within Groups
+ {
+ // Label
+ output.resetColumn();
+ output.writeString(ScResId(STR_ANOVA_LABEL_WITHIN_GROUPS));
+ output.nextColumn();
+
+ // Sum of Squares
+ OUString aSSPart = lclCreateMultiParameterFormula(aRangeList, "DEVSQ(%RANGE%)", strWildcardRange, mDocument, mAddressDetails);
+ aTemplate.setTemplate("=SUM(%RANGE%)");
+ aTemplate.applyString(strWildcardRange, aSSPart);
+ aTemplate.autoReplaceAddress("%WITHIN_SS%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // Degree of freedom
+ aTemplate.setTemplate("=SUM(%COUNT_RANGE%)-COUNT(%COUNT_RANGE%)");
+ aTemplate.autoReplaceAddress("%WITHIN_DF%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // MS
+ aTemplate.setTemplate("=%WITHIN_SS% / %WITHIN_DF%");
+ output.writeFormula(aTemplate.getTemplate());
+ }
+ output.nextRow();
+
+ // Total
+ {
+ // Label
+ output.resetColumn();
+ output.writeString(ScResId(STR_ANOVA_LABEL_TOTAL));
+ output.nextColumn();
+
+ // Sum of Squares
+ aTemplate.setTemplate("=DEVSQ(%RANGE_LIST%)");
+ aTemplate.applyRangeList(u"%RANGE_LIST%", aRangeList, ';');
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // Degree of freedom
+ aTemplate.setTemplate("=SUM(%COUNT_RANGE%) - 1");
+ output.writeFormula(aTemplate.getTemplate());
+ }
+ output.nextRow();
+}
+
+void ScAnalysisOfVarianceDialog::AnovaTwoFactor(AddressWalkerWriter& output, FormulaTemplate& aTemplate)
+{
+ output.writeBoldString(ScResId(STR_ANOVA_TWO_FACTOR_LABEL));
+ output.newLine();
+
+ double aAlphaValue = mxAlphaField->get_value() / 100.0;
+ output.writeString("Alpha");
+ output.nextColumn();
+ output.writeValue(aAlphaValue);
+ aTemplate.autoReplaceAddress("%ALPHA%", output.current());
+ output.newLine();
+ output.newLine();
+
+ // Write labels
+ for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
+ {
+ output.writeString(ScResId(lclBasicStatistics[i].aLabelId));
+ output.nextColumn();
+ }
+ output.newLine();
+
+ ScRangeList aColumnRangeList;
+ ScRangeList aRowRangeList;
+
+ lclMakeSubRangesList(aColumnRangeList, mInputRange, BY_COLUMN);
+ lclMakeSubRangesList(aRowRangeList, mInputRange, BY_ROW);
+
+ // Write ColumnX values
+ output.push();
+ for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
+ {
+ output.resetRow();
+ ScRange aResultRange;
+ OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
+ RowColumn(aColumnRangeList, output, aTemplate, sFormula, BY_COLUMN, &aResultRange);
+ if (lclBasicStatistics[i].aResultRangeName != nullptr)
+ {
+ OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
+ aTemplate.autoReplaceRange("%" + sResultRangeName + "_COLUMN%", aResultRange);
+ }
+ output.nextColumn();
+ }
+ output.newLine();
+
+ // Write RowX values
+ output.push();
+ for(sal_Int32 i = 0; lclBasicStatistics[i].aLabelId; i++)
+ {
+ output.resetRow();
+ ScRange aResultRange;
+ OUString sFormula = OUString::createFromAscii(lclBasicStatistics[i].aFormula);
+ RowColumn(aRowRangeList, output, aTemplate, sFormula, BY_ROW, &aResultRange);
+
+ if (lclBasicStatistics[i].aResultRangeName != nullptr)
+ {
+ OUString sResultRangeName = OUString::createFromAscii(lclBasicStatistics[i].aResultRangeName);
+ aTemplate.autoReplaceRange("%" + sResultRangeName + "_ROW%", aResultRange);
+ }
+ output.nextColumn();
+ }
+ output.newLine();
+
+ // Write ANOVA labels
+ for(sal_Int32 i = 0; lclAnovaLabels[i]; i++)
+ {
+ output.writeString(ScResId(lclAnovaLabels[i]));
+ output.nextColumn();
+ }
+ output.nextRow();
+
+ // Setup auto-replace strings
+ aTemplate.autoReplaceRange(strWildcardRange, mInputRange);
+ aTemplate.autoReplaceRange("%FIRST_COLUMN%", aColumnRangeList[0]);
+ aTemplate.autoReplaceRange("%FIRST_ROW%", aRowRangeList[0]);
+
+ // Rows
+ {
+ // Label
+ output.resetColumn();
+ output.writeString("Rows");
+ output.nextColumn();
+
+ // Sum of Squares
+ aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE_ROW%;%MEAN_RANGE_ROW%) - SUM(%RANGE%)^2 / COUNT(%RANGE%)");
+ aTemplate.autoReplaceAddress("%ROW_SS%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // Degree of freedom
+ aTemplate.setTemplate("=MAX(%COUNT_RANGE_COLUMN%) - 1");
+ aTemplate.autoReplaceAddress("%ROW_DF%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // MS
+ aTemplate.setTemplate("=%ROW_SS% / %ROW_DF%");
+ aTemplate.autoReplaceAddress("%MS_ROW%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // F
+ aTemplate.setTemplate("=%MS_ROW% / %MS_ERROR%");
+ aTemplate.applyAddress(u"%MS_ERROR%", output.current(-1, 2));
+ aTemplate.autoReplaceAddress("%F_ROW%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // P-value
+ aTemplate.setTemplate("=FDIST(%F_ROW%; %ROW_DF%; %ERROR_DF%");
+ aTemplate.applyAddress(u"%ERROR_DF%", output.current(-3, 2));
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // F critical
+ aTemplate.setTemplate("=FINV(%ALPHA%; %ROW_DF%; %ERROR_DF%");
+ aTemplate.applyAddress(u"%ERROR_DF%", output.current(-4, 2));
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+ }
+ output.nextRow();
+
+ // Columns
+ {
+ // Label
+ output.resetColumn();
+ output.writeString("Columns");
+ output.nextColumn();
+
+ // Sum of Squares
+ aTemplate.setTemplate("=SUMPRODUCT(%SUM_RANGE_COLUMN%;%MEAN_RANGE_COLUMN%) - SUM(%RANGE%)^2 / COUNT(%RANGE%)");
+ aTemplate.autoReplaceAddress("%COLUMN_SS%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // Degree of freedom
+ aTemplate.setTemplate("=MAX(%COUNT_RANGE_ROW%) - 1");
+ aTemplate.autoReplaceAddress("%COLUMN_DF%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // MS
+ aTemplate.setTemplate("=%COLUMN_SS% / %COLUMN_DF%");
+ aTemplate.autoReplaceAddress("%MS_COLUMN%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // F
+ aTemplate.setTemplate("=%MS_COLUMN% / %MS_ERROR%");
+ aTemplate.applyAddress(u"%MS_ERROR%", output.current(-1, 1));
+ aTemplate.autoReplaceAddress("%F_COLUMN%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // P-value
+ aTemplate.setTemplate("=FDIST(%F_COLUMN%; %COLUMN_DF%; %ERROR_DF%");
+ aTemplate.applyAddress(u"%ERROR_DF%", output.current(-3, 1));
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // F critical
+ aTemplate.setTemplate("=FINV(%ALPHA%; %COLUMN_DF%; %ERROR_DF%");
+ aTemplate.applyAddress(u"%ERROR_DF%", output.current(-4, 1));
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+ }
+ output.nextRow();
+
+ // Error
+ {
+ // Label
+ output.resetColumn();
+ output.writeString("Error");
+ output.nextColumn();
+
+ // Sum of Squares
+ aTemplate.setTemplate("=SUMSQ(%RANGE%)+SUM(%RANGE%)^2/COUNT(%RANGE%) - (SUMPRODUCT(%SUM_RANGE_ROW%;%MEAN_RANGE_ROW%) + SUMPRODUCT(%SUM_RANGE_COLUMN%;%MEAN_RANGE_COLUMN%))");
+ aTemplate.autoReplaceAddress("%ERROR_SS%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // Degree of freedom
+ aTemplate.setTemplate("=%TOTAL_DF% - %ROW_DF% - %COLUMN_DF%");
+ aTemplate.applyAddress(u"%TOTAL_DF%", output.current(0,1));
+ aTemplate.autoReplaceAddress("%ERROR_DF%", output.current());
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // MS
+ aTemplate.setTemplate("=%ERROR_SS% / %ERROR_DF%");
+ output.writeFormula(aTemplate.getTemplate());
+ }
+ output.nextRow();
+
+ // Total
+ {
+ // Label
+ output.resetColumn();
+ output.writeString("Total");
+ output.nextColumn();
+
+ // Sum of Squares
+ aTemplate.setTemplate("=SUM(%ROW_SS%;%COLUMN_SS%;%ERROR_SS%)");
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+
+ // Degree of freedom
+ aTemplate.setTemplate("=COUNT(%RANGE%)-1");
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextColumn();
+ }
+}
+
+ScRange ScAnalysisOfVarianceDialog::ApplyOutput(ScDocShell* pDocShell)
+{
+ AddressWalkerWriter output(mOutputAddress, pDocShell, mDocument,
+ formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
+ FormulaTemplate aTemplate(&mDocument);
+
+ if (meFactor == SINGLE_FACTOR)
+ {
+ AnovaSingleFactor(output, aTemplate);
+ }
+ else if (meFactor == TWO_FACTOR)
+ {
+ AnovaTwoFactor(output, aTemplate);
+ }
+
+ return ScRange(output.mMinimumAddress, output.mMaximumAddress);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/ChiSquareTestDialog.cxx b/sc/source/ui/StatisticsDialogs/ChiSquareTestDialog.cxx
new file mode 100644
index 000000000..cfcf53699
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/ChiSquareTestDialog.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/.
+ *
+ */
+
+#include <reffact.hxx>
+#include <TableFillingAndNavigationTools.hxx>
+#include <ChiSquareTestDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+ScChiSquareTestDialog::ScChiSquareTestDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData ) :
+ ScStatisticsInputOutputDialog(
+ pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/chisquaretestdialog.ui", "ChiSquareTestDialog")
+{
+ m_xDialog->set_title(ScResId(STR_CHI_SQUARE_TEST));
+}
+
+ScChiSquareTestDialog::~ScChiSquareTestDialog()
+{}
+
+void ScChiSquareTestDialog::Close()
+{
+ DoClose(ScChiSquareTestDialogWrapper::GetChildWindowId());
+}
+
+TranslateId ScChiSquareTestDialog::GetUndoNameId()
+{
+ return STR_CHI_SQUARE_TEST;
+}
+
+ScRange ScChiSquareTestDialog::ApplyOutput(ScDocShell* pDocShell)
+{
+ AddressWalkerWriter aOutput(mOutputAddress, pDocShell, mDocument,
+ formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
+ FormulaTemplate aTemplate(&mDocument);
+
+ aTemplate.autoReplaceRange("%RANGE%", mInputRange);
+
+ aOutput.writeBoldString(ScResId(STR_CHI_SQUARE_TEST));
+ aOutput.newLine();
+
+ // Alpha
+ aOutput.writeString(ScResId(STR_LABEL_ALPHA));
+ aOutput.nextColumn();
+ aOutput.writeValue(0.05);
+ aTemplate.autoReplaceAddress("%ALPHA%", aOutput.current());
+ aOutput.newLine();
+
+ // DF
+ aOutput.writeString(ScResId(STR_DEGREES_OF_FREEDOM_LABEL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=(COLUMNS(%RANGE%) - 1) * (ROWS(%RANGE%) - 1)");
+ aTemplate.autoReplaceAddress("%DEGREES_OF_FREEDOM%", aOutput.current());
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // p Value
+ aOutput.writeString(ScResId(STR_P_VALUE_LABEL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=CHITEST(%RANGE%; MMULT(MMULT(%RANGE%;TRANSPOSE(IF(COLUMN(%RANGE%))));MMULT(TRANSPOSE(IF(ROW(%RANGE%)));%RANGE%)) / SUM(%RANGE%))");
+ aTemplate.autoReplaceAddress("%P_VALUE%", aOutput.current());
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // Test Statistic
+ aOutput.writeString(ScResId(STR_TEST_STATISTIC_LABEL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=CHIINV(%P_VALUE%; %DEGREES_OF_FREEDOM%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // Critical value
+ aOutput.writeString(ScResId(STR_CRITICAL_VALUE_LABEL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=CHIINV(%ALPHA%; %DEGREES_OF_FREEDOM%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ return ScRange(aOutput.mMinimumAddress, aOutput.mMaximumAddress);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/CorrelationDialog.cxx b/sc/source/ui/StatisticsDialogs/CorrelationDialog.cxx
new file mode 100644
index 000000000..7e9a23372
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/CorrelationDialog.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/.
+ *
+ */
+
+#include <reffact.hxx>
+#include <CorrelationDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+ScCorrelationDialog::ScCorrelationDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData ) :
+ ScMatrixComparisonGenerator(
+ pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/correlationdialog.ui", "CorrelationDialog")
+{}
+
+void ScCorrelationDialog::Close()
+{
+ DoClose(ScCorrelationDialogWrapper::GetChildWindowId());
+}
+
+OUString ScCorrelationDialog::getLabel()
+{
+ return ScResId(STR_CORRELATION_LABEL);
+}
+
+OUString ScCorrelationDialog::getTemplate()
+{
+ return "=CORREL(%VAR1%; %VAR2%)";
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/CovarianceDialog.cxx b/sc/source/ui/StatisticsDialogs/CovarianceDialog.cxx
new file mode 100644
index 000000000..b2849d316
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/CovarianceDialog.cxx
@@ -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/.
+ *
+ */
+
+#include <reffact.hxx>
+#include <CovarianceDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+ScCovarianceDialog::ScCovarianceDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData ) :
+ ScMatrixComparisonGenerator(
+ pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/covariancedialog.ui", "CovarianceDialog")
+{}
+
+TranslateId ScCovarianceDialog::GetUndoNameId()
+{
+ return STR_COVARIANCE_UNDO_NAME;
+}
+
+void ScCovarianceDialog::Close()
+{
+ DoClose( ScCovarianceDialogWrapper::GetChildWindowId() );
+}
+
+OUString ScCovarianceDialog::getLabel()
+{
+ return ScResId(STR_COVARIANCE_LABEL);
+}
+
+OUString ScCovarianceDialog::getTemplate()
+{
+ return "=COVAR(%VAR1%; %VAR2%)";
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/DescriptiveStatisticsDialog.cxx b/sc/source/ui/StatisticsDialogs/DescriptiveStatisticsDialog.cxx
new file mode 100644
index 000000000..0924278c5
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/DescriptiveStatisticsDialog.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/.
+ *
+ */
+
+#include <memory>
+
+#include <reffact.hxx>
+#include <TableFillingAndNavigationTools.hxx>
+#include <DescriptiveStatisticsDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+namespace
+{
+
+struct StatisticCalculation {
+ TranslateId aCalculationNameId;
+ const char* aFormula;
+};
+
+const StatisticCalculation lclCalcDefinitions[] =
+{
+ { STRID_CALC_MEAN, "=AVERAGE(%RANGE%)" },
+ { STRID_CALC_STD_ERROR, "=SQRT(VAR(%RANGE%)/COUNT(%RANGE%))"},
+ { STRID_CALC_MODE, "=MODE(%RANGE%)"},
+ { STRID_CALC_MEDIAN, "=MEDIAN(%RANGE%)"},
+ { STRID_CALC_FIRST_QUARTILE, "=QUARTILE(%RANGE%; 1)" },
+ { STRID_CALC_THIRD_QUARTILE, "=QUARTILE(%RANGE%; 3)" },
+ { STRID_CALC_VARIANCE, "=VAR(%RANGE%)"},
+ { STRID_CALC_STD_DEVIATION, "=STDEV(%RANGE%)"},
+ { STRID_CALC_KURTOSIS, "=KURT(%RANGE%)"},
+ { STRID_CALC_SKEWNESS, "=SKEW(%RANGE%)"},
+ { STRID_CALC_RANGE, "=MAX(%RANGE%)-MIN(%RANGE%)"},
+ { STRID_CALC_MIN, "=MIN(%RANGE%)"},
+ { STRID_CALC_MAX, "=MAX(%RANGE%)"},
+ { STRID_CALC_SUM, "=SUM(%RANGE%)"},
+ { STRID_CALC_COUNT, "=COUNT(%RANGE%)" },
+ { {}, nullptr }
+};
+
+}
+
+ScDescriptiveStatisticsDialog::ScDescriptiveStatisticsDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData ) :
+ ScStatisticsInputOutputDialog(
+ pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/descriptivestatisticsdialog.ui",
+ "DescriptiveStatisticsDialog")
+{}
+
+ScDescriptiveStatisticsDialog::~ScDescriptiveStatisticsDialog()
+{}
+
+void ScDescriptiveStatisticsDialog::Close()
+{
+ DoClose( ScDescriptiveStatisticsDialogWrapper::GetChildWindowId() );
+}
+
+TranslateId ScDescriptiveStatisticsDialog::GetUndoNameId()
+{
+ return STR_DESCRIPTIVE_STATISTICS_UNDO_NAME;
+}
+
+ScRange ScDescriptiveStatisticsDialog::ApplyOutput(ScDocShell* pDocShell)
+{
+ AddressWalkerWriter aOutput(mOutputAddress, pDocShell, mDocument,
+ formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
+ FormulaTemplate aTemplate(&mDocument);
+
+ std::unique_ptr<DataRangeIterator> pIterator;
+ if (mGroupedBy == BY_COLUMN)
+ pIterator.reset(new DataRangeByColumnIterator(mInputRange));
+ else
+ pIterator.reset(new DataRangeByRowIterator(mInputRange));
+
+ aOutput.nextColumn();
+
+ // Use explicit sheet name in case the input and output are on different sheets.
+ bool b3DAddress = mInputRange.aStart.Tab() != mOutputAddress.Tab();
+
+ // Write column/row labels
+ for( ; pIterator->hasNext(); pIterator->next() )
+ {
+ // tdf#128018 - add column/row labels to the output
+ OUString aColRowLabel = mDocument.GetString(pIterator->get().aStart);
+ if (aColRowLabel.isEmpty())
+ {
+ if (mGroupedBy == BY_COLUMN)
+ aTemplate.setTemplate(ScResId(STR_COLUMN_LABEL_TEMPLATE));
+ else
+ aTemplate.setTemplate(ScResId(STR_ROW_LABEL_TEMPLATE));
+
+ aTemplate.applyNumber(u"%NUMBER%", pIterator->index() + 1);
+ aOutput.writeBoldString(aTemplate.getTemplate());
+ }
+ else
+ {
+ aOutput.writeBoldString(aColRowLabel);
+ }
+ aOutput.nextColumn();
+ }
+ aOutput.nextRow();
+ aOutput.resetColumn();
+ aOutput.push();
+
+ // Write calculation labels
+ for(sal_Int32 i = 0; lclCalcDefinitions[i].aFormula != nullptr; i++)
+ {
+ OUString aLabel(ScResId(lclCalcDefinitions[i].aCalculationNameId));
+ aOutput.writeString(aLabel);
+ aOutput.nextRow();
+ }
+ aOutput.nextColumn();
+
+ pIterator->reset();
+
+ for( ; pIterator->hasNext(); pIterator->next() )
+ {
+ aOutput.resetRow();
+
+ for(sal_Int32 i = 0; lclCalcDefinitions[i].aFormula != nullptr; i++)
+ {
+ aTemplate.setTemplate(lclCalcDefinitions[i].aFormula);
+ aTemplate.applyRange(u"%RANGE%", pIterator->get(), b3DAddress);
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.nextRow();
+ }
+ aOutput.nextColumn();
+ }
+
+ return ScRange(aOutput.mMinimumAddress, aOutput.mMaximumAddress);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/ExponentialSmoothingDialog.cxx b/sc/source/ui/StatisticsDialogs/ExponentialSmoothingDialog.cxx
new file mode 100644
index 000000000..1a87f5beb
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/ExponentialSmoothingDialog.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/.
+ *
+ */
+
+#include <memory>
+
+#include <reffact.hxx>
+#include <TableFillingAndNavigationTools.hxx>
+#include <ExponentialSmoothingDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+ScExponentialSmoothingDialog::ScExponentialSmoothingDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData )
+ : ScStatisticsInputOutputDialog(
+ pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/exponentialsmoothingdialog.ui",
+ "ExponentialSmoothingDialog")
+ , mxSmoothingFactor(m_xBuilder->weld_spin_button("smoothing-factor-spin"))
+{
+}
+
+ScExponentialSmoothingDialog::~ScExponentialSmoothingDialog()
+{
+}
+
+void ScExponentialSmoothingDialog::Close()
+{
+ DoClose( ScExponentialSmoothingDialogWrapper::GetChildWindowId() );
+}
+
+TranslateId ScExponentialSmoothingDialog::GetUndoNameId()
+{
+ return STR_EXPONENTIAL_SMOOTHING_UNDO_NAME;
+}
+
+ScRange ScExponentialSmoothingDialog::ApplyOutput(ScDocShell* pDocShell)
+{
+ AddressWalkerWriter output(mOutputAddress, pDocShell, mDocument,
+ formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
+ FormulaTemplate aTemplate(&mDocument);
+
+ // Smoothing factor
+ double aSmoothingFactor = mxSmoothingFactor->get_value() / 100.0;
+
+ // Alpha
+ output.writeBoldString(ScResId(STR_LABEL_ALPHA));
+ output.nextRow();
+
+ // Alpha Value
+ ScAddress aSmoothingFactorAddress = output.current();
+ output.writeValue(aSmoothingFactor);
+ output.nextRow();
+
+ // Exponential Smoothing
+ output.push();
+
+ std::unique_ptr<DataRangeIterator> pIterator;
+ if (mGroupedBy == BY_COLUMN)
+ pIterator.reset(new DataRangeByColumnIterator(mInputRange));
+ else
+ pIterator.reset(new DataRangeByRowIterator(mInputRange));
+
+ for( ; pIterator->hasNext(); pIterator->next() )
+ {
+ output.resetRow();
+
+ ScRange aCurrentRange = pIterator->get();
+
+ // Write column label
+ if (mGroupedBy == BY_COLUMN)
+ aTemplate.setTemplate(ScResId(STR_COLUMN_LABEL_TEMPLATE));
+ else
+ aTemplate.setTemplate(ScResId(STR_ROW_LABEL_TEMPLATE));
+ aTemplate.applyNumber(u"%NUMBER%", pIterator->index() + 1);
+ output.writeBoldString(aTemplate.getTemplate());
+ output.nextRow();
+
+ // Initial value
+ if ((false))
+ {
+ aTemplate.setTemplate("=AVERAGE(%RANGE%)");
+ aTemplate.applyRange(u"%RANGE%", aCurrentRange);
+ output.writeFormula(aTemplate.getTemplate());
+ }
+ else
+ {
+ aTemplate.setTemplate("=%VAR%");
+ aTemplate.applyAddress(u"%VAR%", aCurrentRange.aStart);
+ output.writeFormula(aTemplate.getTemplate());
+ }
+
+ output.nextRow();
+
+ DataCellIterator aDataCellIterator = pIterator->iterateCells();
+
+ for (; aDataCellIterator.hasNext(); aDataCellIterator.next())
+ {
+ aTemplate.setTemplate("=%VALUE% * %PREVIOUS_INPUT% + (1 - %VALUE%) * %PREVIOUS_OUTPUT%");
+ aTemplate.applyAddress(u"%PREVIOUS_INPUT%", aDataCellIterator.get());
+ aTemplate.applyAddress(u"%PREVIOUS_OUTPUT%", output.current(0, -1));
+ aTemplate.applyAddress(u"%VALUE%", aSmoothingFactorAddress);
+
+ output.writeFormula(aTemplate.getTemplate());
+ output.nextRow();
+ }
+ output.nextColumn();
+ }
+
+ return ScRange (output.mMinimumAddress, output.mMaximumAddress);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/FTestDialog.cxx b/sc/source/ui/StatisticsDialogs/FTestDialog.cxx
new file mode 100644
index 000000000..76b2bade6
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/FTestDialog.cxx
@@ -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/.
+ *
+ */
+
+#include <memory>
+
+#include <reffact.hxx>
+#include <TableFillingAndNavigationTools.hxx>
+#include <FTestDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+ScFTestDialog::ScFTestDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData ) :
+ ScStatisticsTwoVariableDialog(
+ pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/ttestdialog.ui", "TTestDialog" )
+{
+ m_xDialog->set_title(ScResId(STR_FTEST));
+}
+
+ScFTestDialog::~ScFTestDialog()
+{}
+
+void ScFTestDialog::Close()
+{
+ DoClose( ScFTestDialogWrapper::GetChildWindowId() );
+}
+
+TranslateId ScFTestDialog::GetUndoNameId()
+{
+ return STR_FTEST_UNDO_NAME;
+}
+
+ScRange ScFTestDialog::ApplyOutput(ScDocShell* pDocShell)
+{
+ AddressWalkerWriter aOutput(mOutputAddress, pDocShell, mDocument,
+ formula::FormulaGrammar::mergeToGrammar(formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
+ FormulaTemplate aTemplate(&mDocument);
+
+ std::unique_ptr<DataRangeIterator> pVariable1Iterator;
+ if (mGroupedBy == BY_COLUMN)
+ pVariable1Iterator.reset(new DataRangeByColumnIterator(mVariable1Range));
+ else
+ pVariable1Iterator.reset(new DataRangeByRowIterator(mVariable1Range));
+
+ std::unique_ptr<DataRangeIterator> pVariable2Iterator;
+ if (mGroupedBy == BY_COLUMN)
+ pVariable2Iterator.reset(new DataRangeByColumnIterator(mVariable2Range));
+ else
+ pVariable2Iterator.reset(new DataRangeByRowIterator(mVariable2Range));
+
+ aTemplate.autoReplaceRange("%VARIABLE1_RANGE%", pVariable1Iterator->get());
+ aTemplate.autoReplaceRange("%VARIABLE2_RANGE%", pVariable2Iterator->get());
+
+ aOutput.writeBoldString(ScResId(STR_FTEST_UNDO_NAME));
+ aOutput.newLine();
+
+ // Alpha
+ aOutput.writeString(ScResId(STR_LABEL_ALPHA));
+ aOutput.nextColumn();
+ aOutput.writeValue(0.05);
+ aTemplate.autoReplaceAddress("%ALPHA%", aOutput.current());
+ aOutput.newLine();
+
+ aOutput.nextColumn();
+ aOutput.writeBoldString(ScResId(STR_VARIABLE_1_LABEL));
+ aOutput.nextColumn();
+ aOutput.writeBoldString(ScResId(STR_VARIABLE_2_LABEL));
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STRID_CALC_MEAN));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=AVERAGE(%VARIABLE1_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=AVERAGE(%VARIABLE2_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STRID_CALC_VARIANCE));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=VAR(%VARIABLE1_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%VARIABLE1_VARIANCE%", aOutput.current());
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=VAR(%VARIABLE2_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%VARIABLE2_VARIANCE%", aOutput.current());
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STR_OBSERVATIONS_LABEL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=COUNT(%VARIABLE1_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%VARIABLE1_OBSERVATIONS%", aOutput.current());
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=COUNT(%VARIABLE2_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%VARIABLE2_OBSERVATIONS%", aOutput.current());
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STR_ANOVA_LABEL_DF));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=%VARIABLE1_OBSERVATIONS% - 1");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%VARIABLE1_DEGREE_OF_FREEDOM%", aOutput.current());
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=%VARIABLE2_OBSERVATIONS% - 1");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%VARIABLE2_DEGREE_OF_FREEDOM%", aOutput.current());
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STR_ANOVA_LABEL_F));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=%VARIABLE1_VARIANCE% / %VARIABLE2_VARIANCE%");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%F_VALUE%", aOutput.current());
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STR_FTEST_P_RIGHT_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=FDIST(%F_VALUE%; %VARIABLE1_DEGREE_OF_FREEDOM%; %VARIABLE2_DEGREE_OF_FREEDOM%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%P_RIGHT_TAIL_VALUE%", aOutput.current());
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STR_FTEST_F_CRITICAL_RIGHT_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=FINV(%ALPHA%; %VARIABLE1_DEGREE_OF_FREEDOM%; %VARIABLE2_DEGREE_OF_FREEDOM%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STR_FTEST_P_LEFT_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=1 - %P_RIGHT_TAIL_VALUE%");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%P_LEFT_TAIL_VALUE%", aOutput.current());
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STR_FTEST_F_CRITICAL_LEFT_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=FINV(1-%ALPHA%; %VARIABLE1_DEGREE_OF_FREEDOM%; %VARIABLE2_DEGREE_OF_FREEDOM%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STR_FTEST_P_TWO_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=2*MIN(%P_RIGHT_TAIL_VALUE%; %P_LEFT_TAIL_VALUE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STR_FTEST_F_CRITICAL_TWO_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=FINV(1-(%ALPHA%/2); %VARIABLE1_DEGREE_OF_FREEDOM%; %VARIABLE2_DEGREE_OF_FREEDOM%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=FINV(%ALPHA%/2; %VARIABLE1_DEGREE_OF_FREEDOM%; %VARIABLE2_DEGREE_OF_FREEDOM%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+
+ return ScRange(aOutput.mMinimumAddress, aOutput.mMaximumAddress);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/FourierAnalysisDialog.cxx b/sc/source/ui/StatisticsDialogs/FourierAnalysisDialog.cxx
new file mode 100644
index 000000000..c6cff45e8
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/FourierAnalysisDialog.cxx
@@ -0,0 +1,231 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <docsh.hxx>
+#include <reffact.hxx>
+#include <TableFillingAndNavigationTools.hxx>
+#include <FourierAnalysisDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <o3tl/safeint.hxx>
+
+ScFourierAnalysisDialog::ScFourierAnalysisDialog(SfxBindings* pSfxBindings,
+ SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData)
+ : ScStatisticsInputOutputDialog(pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/fourieranalysisdialog.ui",
+ "FourierAnalysisDialog")
+ , maLabelAddr(ScAddress::INITIALIZE_INVALID)
+ , maActualInputRange(ScAddress::INITIALIZE_INVALID)
+ , mnLen(0)
+ , mfMinMag(0.0)
+ , mbUse3DAddresses(false)
+ , mbGroupedByColumn(true)
+ , mbWithLabels(false)
+ , mbInverse(false)
+ , mbPolar(false)
+ , mxWithLabelsCheckBox(m_xBuilder->weld_check_button("withlabels-check"))
+ , mxInverseCheckBox(m_xBuilder->weld_check_button("inverse-check"))
+ , mxPolarCheckBox(m_xBuilder->weld_check_button("polar-check"))
+ , mxMinMagnitudeField(m_xBuilder->weld_spin_button("minmagnitude-spin"))
+ , mxErrorMessage(m_xBuilder->weld_label("error-message"))
+{
+ m_xDialog->set_title(ScResId(STR_FOURIER_ANALYSIS));
+
+ mxWithLabelsCheckBox->connect_toggled(LINK(this, ScFourierAnalysisDialog, CheckBoxHdl));
+}
+
+ScFourierAnalysisDialog::~ScFourierAnalysisDialog() {}
+
+void ScFourierAnalysisDialog::Close()
+{
+ DoClose(ScFourierAnalysisDialogWrapper::GetChildWindowId());
+}
+
+TranslateId ScFourierAnalysisDialog::GetUndoNameId() { return STR_FOURIER_ANALYSIS_UNDO_NAME; }
+
+ScRange ScFourierAnalysisDialog::ApplyOutput(ScDocShell* pDocShell)
+{
+ getOptions();
+ AddressWalkerWriter aOutput(mOutputAddress, pDocShell, mDocument,
+ formula::FormulaGrammar::mergeToGrammar(
+ formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
+ FormulaTemplate aTemplate(&mDocument);
+ aTemplate.autoReplaceUses3D(mbUse3DAddresses);
+
+ aOutput.writeBoldString(mbInverse ? ScResId(STR_INVERSE_FOURIER_TRANSFORM)
+ : ScResId(STR_FOURIER_TRANSFORM));
+ aOutput.newLine();
+ OUString aLabel;
+ getDataLabel(aLabel);
+ if (aLabel.startsWith("="))
+ aOutput.writeFormula(aLabel);
+ else
+ aOutput.writeString(aLabel);
+
+ aOutput.newLine();
+ // Components header
+ if (!mbPolar)
+ {
+ aOutput.writeString(ScResId(STR_REAL_PART));
+ aOutput.nextColumn();
+ aOutput.writeString(ScResId(STR_IMAGINARY_PART));
+ }
+ else
+ {
+ aOutput.writeString(ScResId(STR_MAGNITUDE_PART));
+ aOutput.nextColumn();
+ aOutput.writeString(ScResId(STR_PHASE_PART));
+ }
+
+ aOutput.newLine();
+ aTemplate.autoReplaceRange("%INPUTRANGE%", maActualInputRange);
+
+ OUString aFormula;
+ genFormula(aFormula);
+
+ aTemplate.setTemplate(aFormula);
+ aOutput.writeMatrixFormula(aTemplate.getTemplate(), 2, mnLen);
+
+ return ScRange(aOutput.mMinimumAddress, aOutput.mMaximumAddress);
+}
+
+bool ScFourierAnalysisDialog::InputRangesValid()
+{
+ if (!mInputRange.IsValid())
+ {
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_INVALID_INPUT_RANGE));
+ return false;
+ }
+
+ if (!mOutputAddress.IsValid())
+ {
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_INVALID_OUTPUT_ADDR));
+ return false;
+ }
+
+ mInputRange.PutInOrder();
+
+ mbGroupedByColumn = mGroupedBy == BY_COLUMN;
+ mbWithLabels = mxWithLabelsCheckBox->get_active();
+
+ mbUse3DAddresses = mInputRange.aStart.Tab() != mOutputAddress.Tab();
+
+ SCSIZE nRows = mInputRange.aEnd.Row() - mInputRange.aStart.Row() + 1;
+ SCSIZE nCols = mInputRange.aEnd.Col() - mInputRange.aStart.Col() + 1;
+
+ SCSIZE nLen = mbGroupedByColumn ? nRows : nCols;
+ SCSIZE nComponents = mbGroupedByColumn ? nCols : nRows;
+
+ if (nComponents > 2)
+ {
+ OUString aMsg = mbGroupedByColumn ? ScResId(STR_MESSAGE_INVALID_NUMCOLS)
+ : ScResId(STR_MESSAGE_INVALID_NUMROWS);
+ mxErrorMessage->set_label(aMsg);
+ return false;
+ }
+
+ if (mbWithLabels && nLen < 2)
+ {
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_NODATA_IN_RANGE));
+ return false;
+ }
+
+ // Include space for writing the title, label and Real/Imaginary/Magnitude/Phase heading.
+ SCSIZE nLastOutputRow = mOutputAddress.Row() + nLen + 2;
+ if (mbWithLabels)
+ --nLastOutputRow;
+
+ if (nLastOutputRow > o3tl::make_unsigned(mDocument.MaxRow()))
+ {
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_OUTPUT_TOO_LONG));
+ return false;
+ }
+
+ ScAddress aActualStart(mInputRange.aStart);
+
+ if (mbWithLabels)
+ {
+ if (mbGroupedByColumn)
+ aActualStart.IncRow();
+ else
+ aActualStart.IncCol();
+
+ if (nComponents == 1)
+ maLabelAddr = mInputRange.aStart;
+ else
+ mbWithLabels = false;
+
+ mnLen = nLen - 1;
+ }
+ else
+ {
+ mnLen = nLen;
+ }
+
+ maActualInputRange = ScRange(aActualStart, mInputRange.aEnd);
+ mxErrorMessage->set_label("");
+
+ return true;
+}
+
+void ScFourierAnalysisDialog::getOptions()
+{
+ mbInverse = mxInverseCheckBox->get_active();
+ mbPolar = mxPolarCheckBox->get_active();
+
+ sal_Int32 nDeciBels = static_cast<sal_Int32>(mxMinMagnitudeField->get_value());
+ if (nDeciBels <= -150)
+ mfMinMag = 0.0;
+ else
+ mfMinMag = pow(10.0, static_cast<double>(nDeciBels) / 10.0);
+}
+
+void ScFourierAnalysisDialog::getDataLabel(OUString& rLabel)
+{
+ if (mbWithLabels)
+ {
+ rLabel = "="
+ + maLabelAddr.Format(mbUse3DAddresses ? ScRefFlags::ADDR_ABS_3D
+ : ScRefFlags::ADDR_ABS,
+ &mDocument, mAddressDetails);
+
+ return;
+ }
+
+ OUString aDataSrc(mInputRange.Format(
+ mDocument, mbUse3DAddresses ? ScRefFlags::RANGE_ABS_3D : ScRefFlags::RANGE_ABS,
+ mAddressDetails));
+
+ rLabel = ScResId(STR_INPUT_DATA_RANGE) + " : " + aDataSrc;
+ return;
+}
+
+void ScFourierAnalysisDialog::genFormula(OUString& rFormula)
+{
+ static constexpr OUStringLiteral aSep(u";");
+
+ if (!mbPolar)
+ {
+ rFormula = "FOURIER(%INPUTRANGE%;" + OUString::boolean(mbGroupedByColumn) + aSep
+ + OUString::boolean(mbInverse) + ")";
+ return;
+ }
+
+ rFormula = "FOURIER(%INPUTRANGE%;" + OUString::boolean(mbGroupedByColumn) + aSep
+ + OUString::boolean(mbInverse) + ";true;" + OUString::number(mfMinMag) + ")";
+}
+
+IMPL_LINK_NOARG(ScFourierAnalysisDialog, CheckBoxHdl, weld::Toggleable&, void)
+{
+ ValidateDialogInput();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/MatrixComparisonGenerator.cxx b/sc/source/ui/StatisticsDialogs/MatrixComparisonGenerator.cxx
new file mode 100644
index 000000000..4345b816b
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/MatrixComparisonGenerator.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/.
+ *
+ */
+
+#include <rangelst.hxx>
+#include <TableFillingAndNavigationTools.hxx>
+#include <MatrixComparisonGenerator.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+namespace
+{
+ void lclWriteCorrelationFormulas(
+ AddressWalkerWriter& aOutput, FormulaTemplate& aTemplate,
+ const ScRangeList& aRangeList, const OUString& aTemplateString)
+ {
+ for (size_t i = 0; i < aRangeList.size(); i++)
+ {
+ aOutput.resetRow();
+ for (size_t j = 0; j < aRangeList.size(); j++)
+ {
+ if (j >= i)
+ {
+ aTemplate.setTemplate(aTemplateString);
+ aTemplate.applyRange(u"%VAR1%", aRangeList[i]);
+ aTemplate.applyRange(u"%VAR2%", aRangeList[j]);
+ aOutput.writeFormula(aTemplate.getTemplate());
+ }
+ aOutput.nextRow();
+ }
+ aOutput.nextColumn();
+ }
+ }
+}
+
+ScMatrixComparisonGenerator::ScMatrixComparisonGenerator(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData,
+ const OUString& rUiXmlDescription,
+ const OString& rID)
+ : ScStatisticsInputOutputDialog(pSfxBindings, pChildWindow, pParent, rViewData, rUiXmlDescription, rID)
+{}
+
+ScMatrixComparisonGenerator::~ScMatrixComparisonGenerator()
+{}
+
+TranslateId ScMatrixComparisonGenerator::GetUndoNameId()
+{
+ return STR_CORRELATION_UNDO_NAME;
+}
+
+ScRange ScMatrixComparisonGenerator::ApplyOutput(ScDocShell* pDocShell)
+{
+ AddressWalkerWriter output(mOutputAddress, pDocShell, mDocument,
+ formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
+ FormulaTemplate aTemplate(&mDocument);
+
+ SCTAB inTab = mInputRange.aStart.Tab();
+
+ ScRangeList aRangeList = (mGroupedBy == BY_COLUMN) ?
+ MakeColumnRangeList(inTab, mInputRange.aStart, mInputRange.aEnd) :
+ MakeRowRangeList(inTab, mInputRange.aStart, mInputRange.aEnd);
+
+ // labels
+ output.writeString(getLabel());
+ output.nextColumn();
+
+ static const OUStringLiteral strWildcardNumber(u"%NUMBER%");
+
+ // write labels to columns
+ for (size_t i = 0; i < aRangeList.size(); i++)
+ {
+ if (mGroupedBy == BY_COLUMN)
+ aTemplate.setTemplate(ScResId(STR_COLUMN_LABEL_TEMPLATE));
+ else
+ aTemplate.setTemplate(ScResId(STR_ROW_LABEL_TEMPLATE));
+
+ aTemplate.applyNumber(strWildcardNumber, i + 1);
+ output.writeString(aTemplate.getTemplate());
+ output.nextColumn();
+ }
+
+ // write labels to rows
+ output.resetColumn();
+ output.nextRow();
+ for (size_t i = 0; i < aRangeList.size(); i++)
+ {
+ if (mGroupedBy == BY_COLUMN)
+ aTemplate.setTemplate(ScResId(STR_COLUMN_LABEL_TEMPLATE));
+ else
+ aTemplate.setTemplate(ScResId(STR_ROW_LABEL_TEMPLATE));
+
+ aTemplate.applyNumber(strWildcardNumber, i + 1);
+ output.writeString(aTemplate.getTemplate());
+ output.nextRow();
+ }
+
+ // write correlation formulas
+ output.reset();
+ output.push(1, 1);
+
+ lclWriteCorrelationFormulas(output, aTemplate, aRangeList, getTemplate());
+
+ return ScRange(output.mMinimumAddress, output.mMaximumAddress);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/MovingAverageDialog.cxx b/sc/source/ui/StatisticsDialogs/MovingAverageDialog.cxx
new file mode 100644
index 000000000..9d990ed5a
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/MovingAverageDialog.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/.
+ *
+ */
+
+#include <memory>
+
+#include <reffact.hxx>
+#include <TableFillingAndNavigationTools.hxx>
+#include <MovingAverageDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+ScMovingAverageDialog::ScMovingAverageDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData )
+ : ScStatisticsInputOutputDialog(
+ pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/movingaveragedialog.ui",
+ "MovingAverageDialog")
+ , mxTrimRangeCheck(m_xBuilder->weld_check_button("trimrange-check"))
+ , mxIntervalSpin(m_xBuilder->weld_spin_button("interval-spin"))
+{
+}
+
+ScMovingAverageDialog::~ScMovingAverageDialog()
+{
+}
+
+void ScMovingAverageDialog::Close()
+{
+ DoClose( ScMovingAverageDialogWrapper::GetChildWindowId() );
+}
+
+TranslateId ScMovingAverageDialog::GetUndoNameId()
+{
+ return STR_MOVING_AVERAGE_UNDO_NAME;
+}
+
+ScRange ScMovingAverageDialog::ApplyOutput(ScDocShell* pDocShell)
+{
+ AddressWalkerWriter output(mOutputAddress, pDocShell, mDocument,
+ formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
+ FormulaTemplate aTemplate(&mDocument);
+
+ if (mxTrimRangeCheck->get_active())
+ mDocument.GetDataAreaSubrange(mInputRange);
+
+ std::unique_ptr<DataRangeIterator> pIterator;
+ if (mGroupedBy == BY_COLUMN)
+ pIterator.reset(new DataRangeByColumnIterator(mInputRange));
+ else
+ pIterator.reset(new DataRangeByRowIterator(mInputRange));
+
+ sal_Int32 aIntervalSize = mxIntervalSpin->get_value();
+ const bool aCentral = true; //to-do add support to change this to the dialog
+
+ for( ; pIterator->hasNext(); pIterator->next() )
+ {
+ output.resetRow();
+
+ // Write label
+ if (mGroupedBy == BY_COLUMN)
+ aTemplate.setTemplate(ScResId(STR_COLUMN_LABEL_TEMPLATE));
+ else
+ aTemplate.setTemplate(ScResId(STR_ROW_LABEL_TEMPLATE));
+
+ aTemplate.applyNumber(u"%NUMBER%", pIterator->index() + 1);
+ output.writeBoldString(aTemplate.getTemplate());
+ output.nextRow();
+
+ DataCellIterator aDataCellIterator = pIterator->iterateCells();
+ std::vector<OUString> aFormulas;
+
+ for (; aDataCellIterator.hasNext(); aDataCellIterator.next())
+ {
+ ScAddress aIntervalStart;
+ ScAddress aIntervalEnd;
+
+ if (aCentral)
+ {
+ sal_Int32 aHalf = aIntervalSize / 2;
+ sal_Int32 aHalfRemainder = aIntervalSize % 2;
+ aIntervalStart = aDataCellIterator.getRelative(-aHalf);
+ aIntervalEnd = aDataCellIterator.getRelative(aHalf - 1 + aHalfRemainder);
+ }
+ else
+ {
+ aIntervalStart = aDataCellIterator.getRelative(-aIntervalSize);
+ aIntervalEnd = aDataCellIterator.getRelative(0);
+ }
+
+ if(aIntervalStart.IsValid() && aIntervalEnd.IsValid())
+ {
+ aTemplate.setTemplate("=AVERAGE(%RANGE%)");
+ aTemplate.applyRange(u"%RANGE%", ScRange(aIntervalStart, aIntervalEnd));
+ aFormulas.push_back(aTemplate.getTemplate());
+ }
+ else
+ {
+ aFormulas.push_back("=#N/A");
+ }
+ }
+
+ output.writeFormulas(aFormulas);
+ output.nextColumn();
+ }
+ return ScRange(output.mMinimumAddress, output.mMaximumAddress);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/RandomNumberGeneratorDialog.cxx b/sc/source/ui/StatisticsDialogs/RandomNumberGeneratorDialog.cxx
new file mode 100644
index 000000000..91b43cbe0
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/RandomNumberGeneratorDialog.cxx
@@ -0,0 +1,482 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <svl/undo.hxx>
+#include <rtl/math.hxx>
+#include <osl/time.h>
+
+#include <rangelst.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <reffact.hxx>
+#include <docfunc.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+#include <random>
+
+#include <RandomNumberGeneratorDialog.hxx>
+
+namespace
+{
+
+const sal_Int64 DIST_UNIFORM = 0;
+const sal_Int64 DIST_NORMAL = 1;
+const sal_Int64 DIST_CAUCHY = 2;
+const sal_Int64 DIST_BERNOULLI = 3;
+const sal_Int64 DIST_BINOMIAL = 4;
+const sal_Int64 DIST_CHI_SQUARED = 5;
+const sal_Int64 DIST_GEOMETRIC = 6;
+const sal_Int64 DIST_NEGATIVE_BINOMIAL = 7;
+const sal_Int64 DIST_UNIFORM_INTEGER = 8;
+
+const sal_Int64 PRECISION = 10000;
+const sal_Int64 DIGITS = 4;
+
+}
+
+ScRandomNumberGeneratorDialog::ScRandomNumberGeneratorDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData)
+ : ScAnyRefDlgController(pSfxBindings, pChildWindow, pParent,
+ "modules/scalc/ui/randomnumbergenerator.ui",
+ "RandomNumberGeneratorDialog")
+ , mrViewData(rViewData)
+ , mrDoc(rViewData.GetDocument())
+ , mbDialogLostFocus(false)
+ , mxInputRangeText(m_xBuilder->weld_label("cell-range-label"))
+ , mxInputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("cell-range-edit")))
+ , mxInputRangeButton(new formula::RefButton(m_xBuilder->weld_button("cell-range-button")))
+ , mxDistributionCombo(m_xBuilder->weld_combo_box("distribution-combo"))
+ , mxParameter1Text(m_xBuilder->weld_label("parameter1-label"))
+ , mxParameter1Value(m_xBuilder->weld_spin_button("parameter1-spin"))
+ , mxParameter2Text(m_xBuilder->weld_label("parameter2-label"))
+ , mxParameter2Value(m_xBuilder->weld_spin_button("parameter2-spin"))
+ , mxSeed(m_xBuilder->weld_spin_button("seed-spin"))
+ , mxEnableSeed(m_xBuilder->weld_check_button("enable-seed-check"))
+ , mxDecimalPlaces(m_xBuilder->weld_spin_button("decimal-places-spin"))
+ , mxEnableRounding(m_xBuilder->weld_check_button("enable-rounding-check"))
+ , mxButtonApply(m_xBuilder->weld_button("apply"))
+ , mxButtonOk(m_xBuilder->weld_button("ok"))
+ , mxButtonClose(m_xBuilder->weld_button("close"))
+{
+ mxInputRangeEdit->SetReferences(this, mxInputRangeText.get());
+ mxInputRangeButton->SetReferences(this, mxInputRangeEdit.get());
+
+ Init();
+ GetRangeFromSelection();
+}
+
+ScRandomNumberGeneratorDialog::~ScRandomNumberGeneratorDialog()
+{
+}
+
+void ScRandomNumberGeneratorDialog::Init()
+{
+ mxButtonOk->connect_clicked( LINK( this, ScRandomNumberGeneratorDialog, OkClicked ) );
+ mxButtonClose->connect_clicked( LINK( this, ScRandomNumberGeneratorDialog, CloseClicked ) );
+ mxButtonApply->connect_clicked( LINK( this, ScRandomNumberGeneratorDialog, ApplyClicked ) );
+
+ mxInputRangeEdit->SetGetFocusHdl(LINK( this, ScRandomNumberGeneratorDialog, GetEditFocusHandler ));
+ mxInputRangeButton->SetGetFocusHdl(LINK( this, ScRandomNumberGeneratorDialog, GetButtonFocusHandler ));
+
+ mxInputRangeEdit->SetLoseFocusHdl (LINK( this, ScRandomNumberGeneratorDialog, LoseEditFocusHandler ));
+ mxInputRangeButton->SetLoseFocusHdl (LINK( this, ScRandomNumberGeneratorDialog, LoseButtonFocusHandler ));
+
+ mxInputRangeEdit->SetModifyHdl( LINK( this, ScRandomNumberGeneratorDialog, InputRangeModified ));
+ mxParameter1Value->connect_value_changed( LINK( this, ScRandomNumberGeneratorDialog, Parameter1ValueModified ));
+ mxParameter2Value->connect_value_changed( LINK( this, ScRandomNumberGeneratorDialog, Parameter2ValueModified ));
+
+ mxDistributionCombo->connect_changed( LINK( this, ScRandomNumberGeneratorDialog, DistributionChanged ));
+
+ mxEnableSeed->connect_toggled( LINK( this, ScRandomNumberGeneratorDialog, CheckChanged ));
+ mxEnableRounding->connect_toggled( LINK( this, ScRandomNumberGeneratorDialog, CheckChanged ));
+
+ DistributionChanged(*mxDistributionCombo);
+ CheckChanged(*mxEnableSeed);
+}
+
+void ScRandomNumberGeneratorDialog::GetRangeFromSelection()
+{
+ mrViewData.GetSimpleArea(maInputRange);
+ OUString aCurrentString(maInputRange.Format(mrDoc, ScRefFlags::RANGE_ABS_3D, mrDoc.GetAddressConvention()));
+ mxInputRangeEdit->SetText( aCurrentString );
+}
+
+void ScRandomNumberGeneratorDialog::SetActive()
+{
+ if ( mbDialogLostFocus )
+ {
+ mbDialogLostFocus = false;
+ if( mxInputRangeEdit )
+ mxInputRangeEdit->GrabFocus();
+ }
+ else
+ {
+ m_xDialog->grab_focus();
+ }
+ RefInputDone();
+}
+
+void ScRandomNumberGeneratorDialog::Close()
+{
+ DoClose( ScRandomNumberGeneratorDialogWrapper::GetChildWindowId() );
+}
+
+void ScRandomNumberGeneratorDialog::SetReference( const ScRange& rReferenceRange, ScDocument& rDoc )
+{
+ if (!mxInputRangeEdit->GetWidget()->get_sensitive())
+ return;
+
+ if ( rReferenceRange.aStart != rReferenceRange.aEnd )
+ RefInputStart(mxInputRangeEdit.get());
+
+ maInputRange = rReferenceRange;
+
+ OUString aReferenceString(maInputRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()));
+ mxInputRangeEdit->SetRefString( aReferenceString );
+
+ mxButtonApply->set_sensitive(true);
+ mxButtonOk->set_sensitive(true);
+}
+
+void ScRandomNumberGeneratorDialog::SelectGeneratorAndGenerateNumbers()
+{
+ if (!maInputRange.IsValid())
+ return;
+
+ sal_Int64 aSelectedId = mxDistributionCombo->get_active_id().toInt64();
+
+ sal_uInt32 seedValue;
+
+ if( mxEnableSeed->get_active() )
+ {
+ seedValue = mxSeed->get_value();
+ }
+ else
+ {
+ TimeValue now;
+ osl_getSystemTime(&now);
+ seedValue = now.Nanosec;
+ }
+
+ std::mt19937 seed(seedValue);
+
+ sal_Int64 parameterInteger1 = mxParameter1Value->get_value();
+ sal_Int64 parameterInteger2 = mxParameter2Value->get_value();
+
+ double parameter1 = parameterInteger1 / static_cast<double>(PRECISION);
+ double parameter2 = parameterInteger2 / static_cast<double>(PRECISION);
+
+ std::optional<sal_Int8> aDecimalPlaces;
+ if (mxEnableRounding->get_active())
+ {
+ aDecimalPlaces = static_cast<sal_Int8>(mxDecimalPlaces->get_value());
+ }
+
+ switch(aSelectedId)
+ {
+ case DIST_UNIFORM:
+ {
+ std::uniform_real_distribution<> distribution(parameter1, parameter2);
+ auto rng = std::bind(distribution, seed);
+ GenerateNumbers(rng, STR_DISTRIBUTION_UNIFORM_REAL, aDecimalPlaces);
+ break;
+ }
+ case DIST_UNIFORM_INTEGER:
+ {
+ std::uniform_int_distribution<sal_Int64> distribution(parameterInteger1, parameterInteger2);
+ auto rng = std::bind(distribution, seed);
+ GenerateNumbers(rng, STR_DISTRIBUTION_UNIFORM_INTEGER, aDecimalPlaces);
+ break;
+ }
+ case DIST_NORMAL:
+ {
+ std::normal_distribution<> distribution(parameter1, parameter2);
+ auto rng = std::bind(distribution, seed);
+ GenerateNumbers(rng, STR_DISTRIBUTION_NORMAL, aDecimalPlaces);
+ break;
+ }
+ case DIST_CAUCHY:
+ {
+ std::cauchy_distribution<> distribution(parameter1);
+ auto rng = std::bind(distribution, seed);
+ GenerateNumbers(rng, STR_DISTRIBUTION_CAUCHY, aDecimalPlaces);
+ break;
+ }
+ case DIST_BERNOULLI:
+ {
+ std::bernoulli_distribution distribution(parameter1);
+ auto rng = std::bind(distribution, seed);
+ GenerateNumbers(rng, STR_DISTRIBUTION_BERNOULLI, aDecimalPlaces);
+ break;
+ }
+ case DIST_BINOMIAL:
+ {
+ std::binomial_distribution<> distribution(parameterInteger2, parameter1);
+ auto rng = std::bind(distribution, seed);
+ GenerateNumbers(rng, STR_DISTRIBUTION_BINOMIAL, aDecimalPlaces);
+ break;
+ }
+ case DIST_NEGATIVE_BINOMIAL:
+ {
+ std::negative_binomial_distribution<> distribution(parameterInteger2, parameter1);
+ auto rng = std::bind(distribution, seed);
+ GenerateNumbers(rng, STR_DISTRIBUTION_NEGATIVE_BINOMIAL, aDecimalPlaces);
+ break;
+ }
+ case DIST_CHI_SQUARED:
+ {
+ std::chi_squared_distribution<> distribution(parameter1);
+ auto rng = std::bind(distribution, seed);
+ GenerateNumbers(rng, STR_DISTRIBUTION_CHI_SQUARED, aDecimalPlaces);
+ break;
+ }
+ case DIST_GEOMETRIC:
+ {
+ std::geometric_distribution<> distribution(parameter1);
+ auto rng = std::bind(distribution, seed);
+ GenerateNumbers(rng, STR_DISTRIBUTION_GEOMETRIC, aDecimalPlaces);
+ break;
+ }
+ }
+}
+
+template<class RNG>
+void ScRandomNumberGeneratorDialog::GenerateNumbers(RNG& randomGenerator, TranslateId pDistributionStringId, std::optional<sal_Int8> aDecimalPlaces)
+{
+ OUString aUndo = ScResId(STR_UNDO_DISTRIBUTION_TEMPLATE);
+ OUString aDistributionName = ScResId(pDistributionStringId);
+ aUndo = aUndo.replaceAll("$(DISTRIBUTION)", aDistributionName);
+
+ ScDocShell* pDocShell = mrViewData.GetDocShell();
+ SfxUndoManager* pUndoManager = pDocShell->GetUndoManager();
+ pUndoManager->EnterListAction( aUndo, aUndo, 0, mrViewData.GetViewShell()->GetViewShellId() );
+
+ SCROW nRowStart = maInputRange.aStart.Row();
+ SCROW nRowEnd = maInputRange.aEnd.Row();
+ SCCOL nColStart = maInputRange.aStart.Col();
+ SCCOL nColEnd = maInputRange.aEnd.Col();
+ SCTAB nTabStart = maInputRange.aStart.Tab();
+ SCTAB nTabEnd = maInputRange.aEnd.Tab();
+
+ std::vector<double> aVals;
+ aVals.reserve(nRowEnd - nRowStart + 1);
+
+ for (SCROW nTab = nTabStart; nTab <= nTabEnd; ++nTab)
+ {
+ for (SCCOL nCol = nColStart; nCol <= nColEnd; ++nCol)
+ {
+ aVals.clear();
+
+ ScAddress aPos(nCol, nRowStart, nTab);
+ for (SCROW nRow = nRowStart; nRow <= nRowEnd; ++nRow)
+ {
+
+ if (aDecimalPlaces)
+ aVals.push_back(rtl::math::round(randomGenerator(), *aDecimalPlaces));
+ else
+ aVals.push_back(randomGenerator());
+ }
+
+ pDocShell->GetDocFunc().SetValueCells(aPos, aVals, true);
+ }
+ }
+
+ pUndoManager->LeaveListAction();
+
+ pDocShell->PostPaint( maInputRange, PaintPartFlags::Grid );
+}
+
+IMPL_LINK_NOARG( ScRandomNumberGeneratorDialog, OkClicked, weld::Button&, void )
+{
+ ApplyClicked(*mxButtonApply);
+ CloseClicked(*mxButtonClose);
+}
+
+IMPL_LINK_NOARG( ScRandomNumberGeneratorDialog, ApplyClicked, weld::Button&, void )
+{
+ SelectGeneratorAndGenerateNumbers();
+}
+
+IMPL_LINK_NOARG( ScRandomNumberGeneratorDialog, CloseClicked, weld::Button&, void )
+{
+ response(RET_CLOSE);
+}
+
+IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, GetEditFocusHandler, formula::RefEdit&, void)
+{
+ mxInputRangeEdit->SelectAll();
+}
+
+IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, GetButtonFocusHandler, formula::RefButton&, void)
+{
+ mxInputRangeEdit->SelectAll();
+}
+
+IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, LoseEditFocusHandler, formula::RefEdit&, void)
+{
+ mbDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, LoseButtonFocusHandler, formula::RefButton&, void)
+{
+ mbDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, InputRangeModified, formula::RefEdit&, void)
+{
+ ScRangeList aRangeList;
+ bool bValid = ParseWithNames( aRangeList, mxInputRangeEdit->GetText(), mrDoc);
+ const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
+ if (pRange)
+ {
+ maInputRange = *pRange;
+ mxButtonApply->set_sensitive(true);
+ mxButtonOk->set_sensitive(true);
+ // Highlight the resulting range.
+ mxInputRangeEdit->StartUpdateData();
+ }
+ else
+ {
+ maInputRange = ScRange( ScAddress::INITIALIZE_INVALID);
+ mxButtonApply->set_sensitive(false);
+ mxButtonOk->set_sensitive(false);
+ }
+}
+
+IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, Parameter1ValueModified, weld::SpinButton&, void)
+{
+ sal_Int64 aSelectedId = mxDistributionCombo->get_active_id().toInt64();
+ if (aSelectedId == DIST_UNIFORM ||
+ aSelectedId == DIST_UNIFORM_INTEGER)
+ {
+ sal_Int64 min = mxParameter1Value->get_value();
+ sal_Int64 max = mxParameter2Value->get_value();
+ if(min > max)
+ {
+ mxParameter2Value->set_value(min);
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, Parameter2ValueModified, weld::SpinButton&, void)
+{
+ sal_Int64 aSelectedId = mxDistributionCombo->get_active_id().toInt64();
+ if (aSelectedId == DIST_UNIFORM ||
+ aSelectedId == DIST_UNIFORM_INTEGER)
+ {
+ sal_Int64 min = mxParameter1Value->get_value();
+ sal_Int64 max = mxParameter2Value->get_value();
+ if(min > max)
+ {
+ mxParameter1Value->set_value(max);
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, CheckChanged, weld::Toggleable&, void)
+{
+ mxSeed->set_sensitive(mxEnableSeed->get_active());
+ mxDecimalPlaces->set_sensitive(mxEnableRounding->get_active());
+}
+
+IMPL_LINK_NOARG(ScRandomNumberGeneratorDialog, DistributionChanged, weld::ComboBox&, void)
+{
+ sal_Int64 aSelectedId = mxDistributionCombo->get_active_id().toInt64();
+
+ mxParameter1Value->set_range(SAL_MIN_INT32, SAL_MAX_INT32);
+ mxParameter2Value->set_range(SAL_MIN_INT32, SAL_MAX_INT32);
+
+ mxParameter1Value->set_digits(DIGITS);
+ mxParameter1Value->set_increments(PRECISION, PRECISION * 10);
+
+ mxParameter2Value->set_digits(DIGITS);
+ mxParameter2Value->set_increments(PRECISION, PRECISION * 10);
+
+ switch(aSelectedId)
+ {
+ case DIST_UNIFORM:
+ {
+ mxParameter1Text->set_label(ScResId(STR_RNG_PARAMETER_MINIMUM));
+ mxParameter2Text->set_label(ScResId(STR_RNG_PARAMETER_MAXIMUM));
+ mxParameter2Text->show();
+ mxParameter2Value->show();
+ break;
+ }
+ case DIST_UNIFORM_INTEGER:
+ {
+ mxParameter1Text->set_label(ScResId(STR_RNG_PARAMETER_MINIMUM));
+ mxParameter1Value->set_digits(0);
+ mxParameter1Value->set_increments(1, 10);
+
+ mxParameter2Text->set_label(ScResId(STR_RNG_PARAMETER_MAXIMUM));
+ mxParameter2Value->set_digits(0);
+ mxParameter2Value->set_increments(1, 10);
+
+ mxParameter2Text->show();
+ mxParameter2Value->show();
+ break;
+ }
+ case DIST_NORMAL:
+ {
+ mxParameter1Text->set_label(ScResId(STR_RNG_PARAMETER_MEAN));
+ mxParameter2Text->set_label(ScResId(STR_RNG_PARAMETER_STANDARD_DEVIATION));
+ mxParameter2Text->show();
+ mxParameter2Value->show();
+ break;
+ }
+ case DIST_CAUCHY:
+ {
+ mxParameter1Text->set_label(ScResId(STR_RNG_PARAMETER_STANDARD_MEDIAN));
+ mxParameter2Text->set_label(ScResId(STR_RNG_PARAMETER_STANDARD_SIGMA));
+ mxParameter2Text->show();
+ mxParameter2Value->show();
+ break;
+ }
+ case DIST_BERNOULLI:
+ case DIST_GEOMETRIC:
+ {
+ mxParameter1Text->set_label(ScResId(STR_RNG_PARAMETER_STANDARD_PROBABILITY));
+ mxParameter1Value->set_range(0, PRECISION);
+ mxParameter1Value->set_increments(1000, 10000);
+
+ mxParameter2Text->hide();
+ mxParameter2Value->hide();
+ break;
+ }
+ case DIST_BINOMIAL:
+ case DIST_NEGATIVE_BINOMIAL:
+ {
+ mxParameter1Text->set_label(ScResId(STR_RNG_PARAMETER_STANDARD_PROBABILITY));
+ mxParameter1Value->set_range(0, PRECISION);
+ mxParameter1Value->set_increments(1000, 10000);
+
+ mxParameter2Text->set_label(ScResId(STR_RNG_PARAMETER_STANDARD_NUMBER_OF_TRIALS));
+ mxParameter2Value->set_digits(0);
+ mxParameter2Value->set_increments(1, 10);
+ mxParameter2Value->set_min(0);
+
+ mxParameter2Text->show();
+ mxParameter2Value->show();
+ break;
+ }
+ case DIST_CHI_SQUARED:
+ {
+ mxParameter1Text->set_label(ScResId(STR_RNG_PARAMETER_STANDARD_NU_VALUE));
+
+ mxParameter2Text->hide();
+ mxParameter2Value->hide();
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/RegressionDialog.cxx b/sc/source/ui/StatisticsDialogs/RegressionDialog.cxx
new file mode 100644
index 000000000..ad4adb1fe
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/RegressionDialog.cxx
@@ -0,0 +1,696 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <document.hxx>
+#include <reffact.hxx>
+#include <TableFillingAndNavigationTools.hxx>
+#include <RegressionDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+/*
+ Some regression basics
+ ----------------------
+
+ 1. Linear regression fits using data, a linear function between the dependent variable and the independent variable(s).
+ The basic form of this function is :-
+
+ y = b + m_1*x_1 + m_2*x_2 + ... + m_k*x_k
+
+ where y is the dependent variable
+ x_1, x_2, ..., x_k are the k independent variables
+ b is the intercept
+ m_1, m_2, ..., m_k are the slopes corresponding to the variables x_1, x_2, ..., x_k respectively.
+
+
+ This equation for n observations can be compactly written using matrices as :-
+
+ y = X*A
+
+ where y is the n dimensional column vector containing dependent variable observations.
+ where X is matrix of shape n*(k+1) where a row looks like [ 1 x_1 x_2 ... x_k ]
+ A is the k+1 dimensional column vector [ b m_1 m_2 ... m_k ]
+
+ Calc formula LINEST(Y_array ; X_array) can be used to compute all entries in "A" along with many other statistics.
+
+
+ 2. Logarithmic regression is basically used to find a linear function between the dependent variable and
+ the natural logarithm of the independent variable(s).
+ So the basic form of this functions is :-
+
+ y = b + m_1*ln(x_1) + m_2*ln(x_2) + ... + m_k*ln(x_k)
+
+ This can be again written in a compact matrix form for n observations.
+
+ y = ln(X)*A
+
+ where y is the n dimensional column vector containing dependent variable observations.
+ where X is matrix of shape n*(k+1) where a row looks like [ e x_1 x_2 ... x_k ]
+ A is the k+1 dimensional column vector [ b m_1 m_2 ... m_k ]
+
+ To estimate A, we use the formula =LINEST(Y_array ; LN(X_array))
+
+
+ 3. Power regression is used to fit the following model :-
+
+ y = b * (x_1 ^ m_1) * (x_2 ^ m_2) * ... * (x_k ^ m_k)
+
+ To reduce this to a linear function(so that we can still use LINEST()), we take natural logarithm on both sides
+
+ ln(y) = c + m_1*ln(x_1) + m_2*ln(x_2) + ... + m_k*ln(x_k) ; where c = ln(b)
+
+
+ This again can be written compactly in matrix form as :-
+
+ ln(y) = ln(X)*A
+
+ where y is the n dimensional column vector containing dependent variable observations.
+ where X is matrix of shape n*(k+1) where a row looks like [ e x_1 x_2 ... x_k ]
+ A is the k+1 dimensional column vector [ c m_1 m_2 ... m_k ]
+
+ To estimate A, we use the formula =LINEST(LN(Y_array) ; LN(X_array))
+
+ Once we get A, to get back y from x's we use the formula :-
+
+ y = exp( ln(X)*A )
+
+
+
+ Some references for computing confidence interval for the regression coefficients :-
+
+ [1] https://en.wikipedia.org/wiki/Student%27s_t-test#Slope_of_a_regression_line
+ [2] https://en.wikipedia.org/wiki/Simple_linear_regression#Normality_assumption
+ [3] https://onlinecourses.science.psu.edu/stat414/node/280
+
+ */
+
+namespace
+{
+ enum class ScRegType {
+ LINEAR,
+ LOGARITHMIC,
+ POWER
+ };
+
+ const TranslateId constRegressionModel[] =
+ {
+ STR_LABEL_LINEAR,
+ STR_LABEL_LOGARITHMIC,
+ STR_LABEL_POWER
+ };
+
+ OUString constTemplateLINEST[] =
+ {
+ "=LINEST(%VARIABLE2_RANGE% ; %VARIABLE1_RANGE% ; %CALC_INTERCEPT% ; TRUE)",
+ "=LINEST(%VARIABLE2_RANGE% ; LN(%VARIABLE1_RANGE%) ; %CALC_INTERCEPT% ; TRUE)",
+ "=LINEST(LN(%VARIABLE2_RANGE%) ; LN(%VARIABLE1_RANGE%) ; %CALC_INTERCEPT% ; TRUE)"
+ };
+
+ OUString constRegressionFormula[] =
+ {
+ "=MMULT(%XDATAMATRIX_RANGE% ; %SLOPES_RANGE%) + %INTERCEPT_ADDR%",
+ "=MMULT(LN(%XDATAMATRIX_RANGE%) ; %SLOPES_RANGE%) + %INTERCEPT_ADDR%",
+ "=EXP(MMULT(LN(%XDATAMATRIX_RANGE%) ; %SLOPES_RANGE%) + %INTERCEPT_ADDR%)"
+ };
+
+} // end anonymous namespace
+
+static size_t lcl_GetNumRowsColsInRange(const ScRange& rRange, bool bRows)
+{
+ if (bRows)
+ return rRange.aEnd.Row() - rRange.aStart.Row() + 1;
+
+ return rRange.aEnd.Col() - rRange.aStart.Col() + 1;
+}
+
+ScRegressionDialog::ScRegressionDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData )
+ : ScStatisticsTwoVariableDialog(
+ pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/regressiondialog.ui", "RegressionDialog")
+ , mbUnivariate(true)
+ , mnNumIndependentVars(1)
+ , mnNumObservations(0)
+ , mbUse3DAddresses(false)
+ , mbCalcIntercept(true)
+ , mxWithLabelsCheckBox(m_xBuilder->weld_check_button("withlabels-check"))
+ , mxLinearRadioButton(m_xBuilder->weld_radio_button("linear-radio"))
+ , mxLogarithmicRadioButton(m_xBuilder->weld_radio_button("logarithmic-radio"))
+ , mxPowerRadioButton(m_xBuilder->weld_radio_button("power-radio"))
+ , mxErrorMessage(m_xBuilder->weld_label("error-message"))
+ , mxConfidenceLevelField(m_xBuilder->weld_spin_button("confidencelevel-spin"))
+ , mxCalcResidualsCheckBox(m_xBuilder->weld_check_button("calcresiduals-check"))
+ , mxNoInterceptCheckBox(m_xBuilder->weld_check_button("nointercept-check"))
+{
+ mxWithLabelsCheckBox->connect_toggled(LINK(this, ScRegressionDialog, CheckBoxHdl));
+ mxConfidenceLevelField->connect_value_changed(LINK(this, ScRegressionDialog, NumericFieldHdl));
+}
+
+ScRegressionDialog::~ScRegressionDialog()
+{
+}
+
+void ScRegressionDialog::Close()
+{
+ DoClose(ScRegressionDialogWrapper::GetChildWindowId());
+}
+
+TranslateId ScRegressionDialog::GetUndoNameId()
+{
+ return STR_REGRESSION_UNDO_NAME;
+}
+
+ScRange ScRegressionDialog::ApplyOutput(ScDocShell* pDocShell)
+{
+ AddressWalkerWriter aOutput(mOutputAddress, pDocShell, mDocument,
+ formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
+ FormulaTemplate aTemplate(&mDocument);
+ aTemplate.autoReplaceUses3D(mbUse3DAddresses);
+ mbCalcIntercept = !mxNoInterceptCheckBox->get_active();
+
+ // max col of our output should account for
+ // 1. constant term column,
+ // 2. mnNumIndependentVars columns
+ // 3. Actual Y column
+ // 4. Predicted Y column
+ // 5. Residual Column
+ SCCOL nOutputMaxCol = mOutputAddress.Col() + mnNumIndependentVars + 3;
+
+ ScRange aXDataRange(GetDataRange(mVariable1Range));
+ ScRange aYDataRange(GetDataRange(mVariable2Range));
+
+ aTemplate.autoReplaceRange("%VARIABLE1_RANGE%", aXDataRange);
+ aTemplate.autoReplaceRange("%VARIABLE2_RANGE%", aYDataRange);
+ size_t nRegressionIndex = GetRegressionTypeIndex();
+ ScRegType eRegType = static_cast<ScRegType>(nRegressionIndex);
+ bool bTakeLogX = eRegType == ScRegType::LOGARITHMIC || eRegType == ScRegType::POWER;
+
+ WriteRawRegressionResults(aOutput, aTemplate, nRegressionIndex);
+ WriteRegressionStatistics(aOutput, aTemplate);
+ WriteRegressionANOVAResults(aOutput, aTemplate);
+ WriteRegressionEstimatesWithCI(aOutput, aTemplate, bTakeLogX);
+ if (mxCalcResidualsCheckBox->get_active())
+ WritePredictionsWithResiduals(aOutput, aTemplate, nRegressionIndex);
+
+ ScAddress aMaxAddress(aOutput.mMaximumAddress);
+ aMaxAddress.SetCol(std::max(aMaxAddress.Col(), nOutputMaxCol));
+ return ScRange(aOutput.mMinimumAddress, aMaxAddress);
+}
+
+bool ScRegressionDialog::InputRangesValid()
+{
+ if (!mVariable1Range.IsValid())
+ {
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_XINVALID_RANGE));
+ return false;
+ }
+
+ if (!mVariable2Range.IsValid())
+ {
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_YINVALID_RANGE));
+ return false;
+ }
+
+ if (!mOutputAddress.IsValid())
+ {
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_INVALID_OUTPUT_ADDR));
+ return false;
+ }
+
+ {
+ double fConfidenceLevel = mxConfidenceLevelField->get_value();
+ if ( fConfidenceLevel <= 0.0 || fConfidenceLevel >= 100.0 )
+ {
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_INVALID_CONFIDENCE_LEVEL));
+ return false;
+ }
+ }
+
+ mVariable1Range.PutInOrder();
+ mVariable2Range.PutInOrder();
+
+ bool bGroupedByColumn = mGroupedBy == BY_COLUMN;
+
+ bool bYHasSingleDim = (
+ (bGroupedByColumn &&
+ mVariable2Range.aStart.Col() == mVariable2Range.aEnd.Col()) ||
+ (!bGroupedByColumn &&
+ mVariable2Range.aStart.Row() == mVariable2Range.aEnd.Row()));
+
+ if (!bYHasSingleDim)
+ {
+ if (bGroupedByColumn)
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_YVARIABLE_MULTI_COLUMN));
+ else
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_YVARIABLE_MULTI_ROW));
+ return false;
+ }
+
+ bool bWithLabels = mxWithLabelsCheckBox->get_active();
+
+ size_t nYObs = lcl_GetNumRowsColsInRange(mVariable2Range, bGroupedByColumn);
+ size_t nNumXVars = lcl_GetNumRowsColsInRange(mVariable1Range, !bGroupedByColumn);
+ mbUnivariate = nNumXVars == 1;
+ // Observation count mismatch check
+ if (lcl_GetNumRowsColsInRange(mVariable1Range, bGroupedByColumn) != nYObs)
+ {
+ if (mbUnivariate)
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_UNIVARIATE_NUMOBS_MISMATCH));
+ else
+ mxErrorMessage->set_label(ScResId(STR_MESSAGE_MULTIVARIATE_NUMOBS_MISMATCH));
+ return false;
+ }
+
+ mnNumIndependentVars = nNumXVars;
+ mnNumObservations = bWithLabels ? nYObs - 1 : nYObs;
+
+ mbUse3DAddresses = mVariable1Range.aStart.Tab() != mOutputAddress.Tab() ||
+ mVariable2Range.aStart.Tab() != mOutputAddress.Tab();
+
+ mxErrorMessage->set_label("");
+
+ return true;
+}
+
+size_t ScRegressionDialog::GetRegressionTypeIndex() const
+{
+ if (mxLinearRadioButton->get_active())
+ return 0;
+ if (mxLogarithmicRadioButton->get_active())
+ return 1;
+ return 2;
+}
+
+ScRange ScRegressionDialog::GetDataRange(const ScRange& rRange)
+{
+ if (!mxWithLabelsCheckBox->get_active())
+ return rRange;
+
+ ScRange aDataRange(rRange);
+ if (mGroupedBy == BY_COLUMN)
+ aDataRange.aStart.IncRow(1);
+ else
+ aDataRange.aStart.IncCol(1);
+
+ return aDataRange;
+}
+
+OUString ScRegressionDialog::GetVariableNameFormula(bool bXVar, size_t nIndex, bool bWithLog)
+{
+ if (bXVar && nIndex == 0)
+ return "=\"" + ScResId(STR_LABEL_INTERCEPT) + "\"";
+
+ if (mxWithLabelsCheckBox->get_active())
+ {
+ ScAddress aAddr(bXVar ? mVariable1Range.aStart : mVariable2Range.aStart);
+ if (mGroupedBy == BY_COLUMN)
+ aAddr.IncCol(nIndex - 1);
+ else
+ aAddr.IncRow(nIndex - 1);
+
+ ScRefFlags eAddrFlag = mbUse3DAddresses ? ScRefFlags::ADDR_ABS_3D : ScRefFlags::ADDR_ABS;
+ return bWithLog ? OUString("=CONCAT(\"LN(\";" +
+ aAddr.Format(eAddrFlag, &mDocument, mDocument.GetAddressConvention()) + ";\")\")") :
+ OUString("=" + aAddr.Format(eAddrFlag, &mDocument, mDocument.GetAddressConvention()));
+ }
+
+ OUString aDefaultVarName;
+
+ if (bXVar)
+ aDefaultVarName = "X" + OUString::number(nIndex);
+ else
+ aDefaultVarName = "Y";
+
+ return bWithLog ? OUString("=\"LN(" + aDefaultVarName + ")\"") :
+ OUString("=\"" + aDefaultVarName + "\"");
+}
+
+OUString ScRegressionDialog::GetXVariableNameFormula(size_t nIndex, bool bWithLog)
+{
+ assert(nIndex <= mnNumIndependentVars);
+ return GetVariableNameFormula(true, nIndex, bWithLog);
+}
+
+OUString ScRegressionDialog::GetYVariableNameFormula(bool bWithLog)
+{
+ return GetVariableNameFormula(false, 1, bWithLog);
+}
+
+void ScRegressionDialog::WriteRawRegressionResults(AddressWalkerWriter& rOutput, FormulaTemplate& rTemplate,
+ size_t nRegressionIndex)
+{
+ rOutput.writeBoldString(ScResId(STR_REGRESSION));
+ rOutput.newLine();
+ // REGRESSION MODEL
+ rOutput.writeString(ScResId(STR_LABEL_REGRESSION_MODEL));
+ rOutput.nextColumn();
+ rOutput.writeString(ScResId(constRegressionModel[nRegressionIndex]));
+ rOutput.newLine();
+ rOutput.newLine();
+
+ rOutput.writeString(ScResId(STR_LINEST_RAW_OUTPUT_TITLE));
+ rOutput.newLine();
+ rOutput.push();
+
+ rTemplate.setTemplate(constTemplateLINEST[nRegressionIndex].
+ replaceFirst("%CALC_INTERCEPT%",
+ mbCalcIntercept ? std::u16string_view(u"TRUE") : std::u16string_view(u"FALSE")));
+ rOutput.writeMatrixFormula(rTemplate.getTemplate(), 1 + mnNumIndependentVars, 5);
+ // Add LINEST result components to template
+ // 1. Add ranges for coefficients and standard errors for indep. vars and the intercept.
+ // Note that these two are in the reverse order(m_n, m_n-1, ..., m_1, b) w.r.t what we expect.
+ rTemplate.autoReplaceRange("%COEFFICIENTS_REV_RANGE%", ScRange(rOutput.current(), rOutput.current(mnNumIndependentVars)));
+ rTemplate.autoReplaceRange("%SERRORSX_REV_RANGE%", ScRange(rOutput.current(0, 1), rOutput.current(mnNumIndependentVars, 1)));
+
+ // 2. Add R-squared and standard error for y estimate.
+ rTemplate.autoReplaceAddress("%RSQUARED_ADDR%", rOutput.current(0, 2));
+ rTemplate.autoReplaceAddress("%SERRORY_ADDR%", rOutput.current(1, 2));
+
+ // 3. Add F statistic and degrees of freedom
+ rTemplate.autoReplaceAddress("%FSTATISTIC_ADDR%", rOutput.current(0, 3));
+ rTemplate.autoReplaceAddress("%DoFRESID_ADDR%", rOutput.current(1, 3));
+
+ // 4. Add regression sum of squares and residual sum of squares
+ rTemplate.autoReplaceAddress("%SSREG_ADDR%", rOutput.current(0, 4));
+ rTemplate.autoReplaceAddress("%SSRESID_ADDR%", rOutput.current(1, 4));
+
+ rOutput.push(0, 4);
+ rOutput.newLine();
+}
+
+void ScRegressionDialog::WriteRegressionStatistics(AddressWalkerWriter& rOutput, FormulaTemplate& rTemplate)
+{
+ rOutput.newLine();
+ rOutput.writeString(ScResId(STR_LABEL_REGRESSION_STATISTICS));
+ rOutput.newLine();
+
+ const TranslateId aMeasureNames[] =
+ {
+ STR_LABEL_RSQUARED,
+ STRID_CALC_STD_ERROR,
+ STR_LABEL_XVARIABLES_COUNT,
+ STR_OBSERVATIONS_LABEL,
+ STR_LABEL_ADJUSTED_RSQUARED
+ };
+
+ OUString aMeasureFormulas[] =
+ {
+ "=%RSQUARED_ADDR%",
+ "=%SERRORY_ADDR%",
+ "=" + OUString::number(mnNumIndependentVars),
+ "=" + OUString::number(mnNumObservations),
+ OUString::Concat(
+ "=1 - (1 - %RSQUARED_ADDR%)*(%NUMOBS_ADDR% - 1)/(%NUMOBS_ADDR% - %NUMXVARS_ADDR%") +
+ (mbCalcIntercept ? std::u16string_view(u" - 1)") : std::u16string_view(u")"))
+ };
+
+ rTemplate.autoReplaceAddress("%NUMXVARS_ADDR%", rOutput.current(1, 2));
+ rTemplate.autoReplaceAddress("%NUMOBS_ADDR%", rOutput.current(1, 3));
+
+ for (size_t nIdx = 0; nIdx < SAL_N_ELEMENTS(aMeasureNames); ++nIdx)
+ {
+ rOutput.writeString(ScResId(aMeasureNames[nIdx]));
+ rOutput.nextColumn();
+ rTemplate.setTemplate(aMeasureFormulas[nIdx]);
+ rOutput.writeFormula(rTemplate.getTemplate());
+ rOutput.newLine();
+ }
+}
+
+void ScRegressionDialog::WriteRegressionANOVAResults(AddressWalkerWriter& rOutput, FormulaTemplate& rTemplate)
+{
+ rOutput.newLine();
+ rOutput.writeString(ScResId(STR_LABEL_ANOVA));
+ rOutput.newLine();
+
+ const size_t nColsInTable = 6;
+ const size_t nRowsInTable = 4;
+ OUString aTable[nRowsInTable][nColsInTable] =
+ {
+ {
+ "",
+ ScResId(STR_ANOVA_LABEL_DF),
+ ScResId(STR_ANOVA_LABEL_SS),
+ ScResId(STR_ANOVA_LABEL_MS),
+ ScResId(STR_ANOVA_LABEL_F),
+ ScResId(STR_ANOVA_LABEL_SIGNIFICANCE_F)
+ },
+ {
+ ScResId(STR_REGRESSION),
+ "=%NUMXVARS_ADDR%",
+ "=%SSREG_ADDR%",
+ "=%SSREG_ADDR% / %DoFREG_ADDR%",
+ "=%FSTATISTIC_ADDR%",
+ "=FDIST(%FSTATISTIC_ADDR% ; %DoFREG_ADDR% ; %DoFRESID_ADDR%)"
+ },
+ {
+ ScResId(STR_LABEL_RESIDUAL),
+ "=%DoFRESID_ADDR%",
+ "=%SSRESID_ADDR%",
+ "=%SSRESID_ADDR% / %DoFRESID_ADDR%",
+ "",
+ ""
+ },
+ {
+ ScResId(STR_ANOVA_LABEL_TOTAL),
+ "=%DoFREG_ADDR% + %DoFRESID_ADDR%",
+ "=%SSREG_ADDR% + %SSRESID_ADDR%",
+ "",
+ "",
+ ""
+ }
+ };
+
+ rTemplate.autoReplaceAddress("%DoFREG_ADDR%", rOutput.current(1, 1));
+
+ // Cell getter lambda
+ std::function<CellValueGetter> aCellGetterFunc = [&aTable](size_t nRowIdx, size_t nColIdx) -> const OUString&
+ {
+ return aTable[nRowIdx][nColIdx];
+ };
+
+ // Cell writer lambda
+ std::function<CellWriter> aCellWriterFunc = [&rOutput, &rTemplate]
+ (const OUString& rContent, size_t /*nRowIdx*/, size_t /*nColIdx*/)
+ {
+ if (!rContent.isEmpty())
+ {
+ if (rContent.startsWith("="))
+ {
+ rTemplate.setTemplate(rContent);
+ rOutput.writeFormula(rTemplate.getTemplate());
+ }
+ else
+ rOutput.writeString(rContent);
+ }
+ };
+
+ WriteTable(aCellGetterFunc, nRowsInTable, nColsInTable, rOutput, aCellWriterFunc);
+
+ // User given confidence level
+ rOutput.newLine();
+ rOutput.writeString(ScResId(STR_LABEL_CONFIDENCE_LEVEL));
+ rOutput.nextColumn();
+ rOutput.writeValue(mxConfidenceLevelField->get_value() / 100.0);
+ rTemplate.autoReplaceAddress("%CONFIDENCE_LEVEL_ADDR%", rOutput.current());
+ rOutput.newLine();
+}
+
+// Write slopes, intercept, their standard errors, t-statistics, p-value, confidence intervals
+void ScRegressionDialog::WriteRegressionEstimatesWithCI(AddressWalkerWriter& rOutput, FormulaTemplate& rTemplate,
+ bool bTakeLogX)
+{
+ rOutput.newLine();
+ ScAddress aEnd( rOutput.current(0, 1 + mnNumIndependentVars));
+ ScRefFlags eAddrFlag = mbUse3DAddresses ? ScRefFlags::ADDR_ABS_3D : ScRefFlags::ADDR_ABS;
+ aEnd.IncCol();
+ const OUString aCoeffAddr( aEnd.Format( eAddrFlag, &mDocument, mDocument.GetAddressConvention()));
+ aEnd.IncCol();
+ const OUString aStErrAddr( aEnd.Format( eAddrFlag, &mDocument, mDocument.GetAddressConvention()));
+
+ // Coefficients & Std.Errors ranges (column vectors) in this table (yet to populate).
+ rTemplate.autoReplaceRange("%COEFFICIENTS_RANGE%",
+ ScRange(rOutput.current(1, 1),
+ rOutput.current(1, 1 + mnNumIndependentVars)));
+ rTemplate.autoReplaceRange("%SLOPES_RANGE%", // Excludes the intercept
+ ScRange(rOutput.current(1, 2),
+ rOutput.current(1, 1 + mnNumIndependentVars)));
+ rTemplate.autoReplaceAddress("%INTERCEPT_ADDR%", rOutput.current(1, 1));
+ rTemplate.autoReplaceRange("%SERRORSX_RANGE%",
+ ScRange(rOutput.current(2, 1),
+ rOutput.current(2, 1 + mnNumIndependentVars)));
+ // t-Statistics range in this table (yet to populate)
+ rTemplate.autoReplaceRange("%TSTAT_RANGE%",
+ ScRange(rOutput.current(3, 1),
+ rOutput.current(3, 1 + mnNumIndependentVars)));
+
+ const size_t nColsInTable = 7;
+ const size_t nRowsInTable = 2;
+ OUString aTable[nRowsInTable][nColsInTable] =
+ {
+ {
+ "",
+ ScResId(STR_LABEL_COEFFICIENTS),
+ ScResId(STRID_CALC_STD_ERROR),
+ ScResId(STR_LABEL_TSTATISTIC),
+ ScResId(STR_P_VALUE_LABEL),
+
+ "=CONCAT(\"" + ScResId(STR_LABEL_LOWER) +
+ " \" ; INT(%CONFIDENCE_LEVEL_ADDR% * 100) ; \"%\")",
+
+ "=CONCAT(\"" + ScResId(STR_LABEL_UPPER) +
+ " \" ; INT(%CONFIDENCE_LEVEL_ADDR% * 100) ; \"%\")",
+ },
+
+ // Following are matrix formulas of size numcols = 1, numrows = (mnNumIndependentVars + 1)
+ {
+ "",
+ // This puts the coefficients in the reverse order compared to that in LINEST output.
+ "=INDEX(%COEFFICIENTS_REV_RANGE%; 1 ; ROW(" + aCoeffAddr + ")+1 - ROW())",
+ // This puts the standard errors in the reverse order compared to that in LINEST output.
+ "=INDEX(%SERRORSX_REV_RANGE%; 1 ; ROW(" + aStErrAddr + ")+1 - ROW())",
+ // t-Statistic
+ "=%COEFFICIENTS_RANGE% / %SERRORSX_RANGE%",
+ // p-Value
+ "=TDIST(ABS(%TSTAT_RANGE%) ; %DoFRESID_ADDR% ; 2 )",
+ // Lower limit of confidence interval
+ "=%COEFFICIENTS_RANGE% - %SERRORSX_RANGE% * "
+ "TINV(1 - %CONFIDENCE_LEVEL_ADDR% ; %DoFRESID_ADDR%)",
+ // Upper limit of confidence interval
+ "=%COEFFICIENTS_RANGE% + %SERRORSX_RANGE% * "
+ "TINV(1 - %CONFIDENCE_LEVEL_ADDR% ; %DoFRESID_ADDR%)"
+ }
+ };
+
+ // Cell getter lambda
+ std::function<CellValueGetter> aCellGetterFunc = [&aTable](size_t nRowIdx, size_t nColIdx) -> const OUString&
+ {
+ return aTable[nRowIdx][nColIdx];
+ };
+
+ // Cell writer lambda
+ size_t nNumIndependentVars = mnNumIndependentVars;
+ std::function<CellWriter> aCellWriterFunc = [&rOutput, &rTemplate, nNumIndependentVars]
+ (const OUString& rContent, size_t nRowIdx, size_t /*nColIdx*/)
+ {
+ if (!rContent.isEmpty())
+ {
+ if (rContent.startsWith("="))
+ {
+ rTemplate.setTemplate(rContent);
+ if (nRowIdx == 0)
+ rOutput.writeFormula(rTemplate.getTemplate());
+ else
+ rOutput.writeMatrixFormula(rTemplate.getTemplate(), 1, 1 + nNumIndependentVars);
+ }
+ else
+ rOutput.writeString(rContent);
+ }
+ };
+
+ WriteTable(aCellGetterFunc, nRowsInTable, nColsInTable, rOutput, aCellWriterFunc);
+
+ // Go back to the second row and first column of the table to
+ // fill the names of variables + intercept
+ rOutput.push(0, -1);
+
+ for (size_t nXvarIdx = 0; nXvarIdx <= mnNumIndependentVars; ++nXvarIdx)
+ {
+ rOutput.writeFormula(GetXVariableNameFormula(nXvarIdx, bTakeLogX));
+ rOutput.newLine();
+ }
+
+}
+
+// Re-write all observations in group-by column mode with predictions and residuals
+void ScRegressionDialog::WritePredictionsWithResiduals(AddressWalkerWriter& rOutput, FormulaTemplate& rTemplate,
+ size_t nRegressionIndex)
+{
+ bool bGroupedByColumn = mGroupedBy == BY_COLUMN;
+ rOutput.newLine();
+ rOutput.push();
+
+ // Range of X variables with rows as observations and columns as variables.
+ ScRange aDataMatrixRange(rOutput.current(0, 1), rOutput.current(mnNumIndependentVars - 1, mnNumObservations));
+ rTemplate.autoReplaceRange("%XDATAMATRIX_RANGE%", aDataMatrixRange);
+
+ // Write X variable names
+ for (size_t nXvarIdx = 1; nXvarIdx <= mnNumIndependentVars; ++nXvarIdx)
+ {
+ // Here we write the X variables without any transformation(LN)
+ rOutput.writeFormula(GetXVariableNameFormula(nXvarIdx, false));
+ rOutput.nextColumn();
+ }
+ rOutput.reset();
+
+ // Write the X data matrix
+ rOutput.nextRow();
+ OUString aDataMatrixFormula = bGroupedByColumn ? OUString("=%VARIABLE1_RANGE%") : OUString("=TRANSPOSE(%VARIABLE1_RANGE%)");
+ rTemplate.setTemplate(aDataMatrixFormula);
+ rOutput.writeMatrixFormula(rTemplate.getTemplate(), mnNumIndependentVars, mnNumObservations);
+
+ // Write predicted values
+ rOutput.push(mnNumIndependentVars, -1);
+ rOutput.writeString(ScResId(STR_LABEL_PREDICTEDY));
+ rOutput.nextRow();
+ rTemplate.setTemplate(constRegressionFormula[nRegressionIndex]);
+ rOutput.writeMatrixFormula(rTemplate.getTemplate(), 1, mnNumObservations);
+ rTemplate.autoReplaceRange("%PREDICTEDY_RANGE%", ScRange(rOutput.current(), rOutput.current(0, mnNumObservations - 1)));
+
+ // Write actual Y
+ rOutput.push(1, -1);
+ rOutput.writeFormula(GetYVariableNameFormula(false));
+ rOutput.nextRow();
+ OUString aYVectorFormula = bGroupedByColumn ? OUString("=%VARIABLE2_RANGE%") : OUString("=TRANSPOSE(%VARIABLE2_RANGE%)");
+ rTemplate.setTemplate(aYVectorFormula);
+ rOutput.writeMatrixFormula(rTemplate.getTemplate(), 1, mnNumObservations);
+ rTemplate.autoReplaceRange("%ACTUALY_RANGE%", ScRange(rOutput.current(), rOutput.current(0, mnNumObservations - 1)));
+
+ // Write residual
+ rOutput.push(1, -1);
+ rOutput.writeString(ScResId(STR_LABEL_RESIDUAL));
+ rOutput.nextRow();
+ rTemplate.setTemplate("=%ACTUALY_RANGE% - %PREDICTEDY_RANGE%");
+ rOutput.writeMatrixFormula(rTemplate.getTemplate(), 1, mnNumObservations);
+}
+
+// Generic table writer
+void ScRegressionDialog::WriteTable(const std::function<CellValueGetter>& rCellGetter,
+ size_t nRowsInTable, size_t nColsInTable,
+ AddressWalkerWriter& rOutput,
+ const std::function<CellWriter>& rFunc)
+{
+ for (size_t nRowIdx = 0; nRowIdx < nRowsInTable; ++nRowIdx)
+ {
+ for (size_t nColIdx = 0; nColIdx < nColsInTable; ++nColIdx)
+ {
+ rFunc(rCellGetter(nRowIdx, nColIdx), nRowIdx, nColIdx);
+ rOutput.nextColumn();
+ }
+ rOutput.newLine();
+ }
+}
+
+IMPL_LINK_NOARG(ScRegressionDialog, CheckBoxHdl, weld::Toggleable&, void)
+{
+ ValidateDialogInput();
+}
+
+IMPL_LINK_NOARG(ScRegressionDialog, NumericFieldHdl, weld::SpinButton&, void)
+{
+ ValidateDialogInput();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/SamplingDialog.cxx b/sc/source/ui/StatisticsDialogs/SamplingDialog.cxx
new file mode 100644
index 000000000..fad4ac6d0
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/SamplingDialog.cxx
@@ -0,0 +1,563 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <svl/undo.hxx>
+#include <comphelper/random.hxx>
+#include <rangelst.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <reffact.hxx>
+#include <docfunc.hxx>
+#include <SamplingDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+ScSamplingDialog::ScSamplingDialog(SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData)
+ : ScAnyRefDlgController(pSfxBindings, pChildWindow, pParent,
+ "modules/scalc/ui/samplingdialog.ui", "SamplingDialog")
+ , mpActiveEdit(nullptr)
+ , mViewData(rViewData)
+ , mDocument(rViewData.GetDocument())
+ , mInputRange(ScAddress::INITIALIZE_INVALID)
+ , mAddressDetails(mDocument.GetAddressConvention(), 0, 0)
+ , mOutputAddress(ScAddress::INITIALIZE_INVALID)
+ , mCurrentAddress(rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo())
+ , mnLastSampleSizeValue(1)
+ , mnLastPeriodValue(1)
+ , mDialogLostFocus(false)
+ , mxInputRangeLabel(m_xBuilder->weld_label("input-range-label"))
+ , mxInputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("input-range-edit")))
+ , mxInputRangeButton(new formula::RefButton(m_xBuilder->weld_button("input-range-button")))
+ , mxOutputRangeLabel(m_xBuilder->weld_label("output-range-label"))
+ , mxOutputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("output-range-edit")))
+ , mxOutputRangeButton(new formula::RefButton(m_xBuilder->weld_button("output-range-button")))
+ , mxSampleSize(m_xBuilder->weld_spin_button("sample-size-spin"))
+ , mxPeriod(m_xBuilder->weld_spin_button("period-spin"))
+ , mxRandomMethodRadio(m_xBuilder->weld_radio_button("random-method-radio"))
+ , mxWithReplacement(m_xBuilder->weld_check_button("with-replacement"))
+ , mxKeepOrder(m_xBuilder->weld_check_button("keep-order"))
+ , mxPeriodicMethodRadio(m_xBuilder->weld_radio_button("periodic-method-radio"))
+ , mxButtonOk(m_xBuilder->weld_button("ok"))
+ , mxButtonCancel(m_xBuilder->weld_button("cancel"))
+{
+ mxInputRangeEdit->SetReferences(this, mxInputRangeLabel.get());
+ mxInputRangeButton->SetReferences(this, mxInputRangeEdit.get());
+
+ mxOutputRangeEdit->SetReferences(this, mxOutputRangeLabel.get());
+ mxOutputRangeButton->SetReferences(this, mxOutputRangeEdit.get());
+
+ Init();
+ GetRangeFromSelection();
+}
+
+ScSamplingDialog::~ScSamplingDialog()
+{
+}
+
+void ScSamplingDialog::Init()
+{
+ mxButtonCancel->connect_clicked( LINK( this, ScSamplingDialog, ButtonClicked ) );
+ mxButtonOk->connect_clicked( LINK( this, ScSamplingDialog, ButtonClicked ) );
+ mxButtonOk->set_sensitive(false);
+
+ Link<formula::RefEdit&,void> aEditLink = LINK( this, ScSamplingDialog, GetEditFocusHandler );
+ mxInputRangeEdit->SetGetFocusHdl( aEditLink );
+ mxOutputRangeEdit->SetGetFocusHdl( aEditLink );
+ Link<formula::RefButton&,void> aButtonLink = LINK( this, ScSamplingDialog, GetButtonFocusHandler );
+ mxInputRangeButton->SetGetFocusHdl( aButtonLink );
+ mxOutputRangeButton->SetGetFocusHdl( aButtonLink );
+
+ aEditLink = LINK( this, ScSamplingDialog, LoseEditFocusHandler );
+ mxInputRangeEdit->SetLoseFocusHdl( aEditLink );
+ mxOutputRangeEdit->SetLoseFocusHdl( aEditLink );
+ aButtonLink = LINK( this, ScSamplingDialog, LoseButtonFocusHandler );
+ mxInputRangeButton->SetLoseFocusHdl( aButtonLink );
+ mxOutputRangeButton->SetLoseFocusHdl( aButtonLink );
+
+ Link<formula::RefEdit&,void> aLink2 = LINK( this, ScSamplingDialog, RefInputModifyHandler);
+ mxInputRangeEdit->SetModifyHdl( aLink2);
+ mxOutputRangeEdit->SetModifyHdl( aLink2);
+
+ mxSampleSize->connect_value_changed( LINK( this, ScSamplingDialog, SamplingSizeValueModified ));
+ mxSampleSize->set_range(1, SAL_MAX_INT32);
+ mxPeriod->connect_value_changed( LINK( this, ScSamplingDialog, PeriodValueModified ));
+ mxPeriod->set_range(1, SAL_MAX_INT32);
+
+ mxPeriodicMethodRadio->connect_toggled( LINK( this, ScSamplingDialog, ToggleSamplingMethod ) );
+ mxRandomMethodRadio->connect_toggled( LINK( this, ScSamplingDialog, ToggleSamplingMethod ) );
+
+ mxWithReplacement->connect_toggled( LINK( this, ScSamplingDialog, CheckHdl));
+ mxKeepOrder->connect_toggled( LINK( this, ScSamplingDialog, CheckHdl));
+
+ mxOutputRangeEdit->GrabFocus();
+ mxPeriodicMethodRadio->set_active(true);
+
+ ToggleSamplingMethod();
+}
+
+void ScSamplingDialog::GetRangeFromSelection()
+{
+ mViewData.GetSimpleArea(mInputRange);
+ OUString aCurrentString(mInputRange.Format(mDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails));
+ mxInputRangeEdit->SetText(aCurrentString);
+}
+
+void ScSamplingDialog::SetActive()
+{
+ if ( mDialogLostFocus )
+ {
+ mDialogLostFocus = false;
+ if( mpActiveEdit )
+ mpActiveEdit->GrabFocus();
+ }
+ else
+ {
+ m_xDialog->grab_focus();
+ }
+ RefInputDone();
+}
+
+void ScSamplingDialog::Close()
+{
+ DoClose( ScSamplingDialogWrapper::GetChildWindowId() );
+}
+
+void ScSamplingDialog::SetReference( const ScRange& rReferenceRange, ScDocument& rDocument )
+{
+ if ( mpActiveEdit )
+ {
+ if ( rReferenceRange.aStart != rReferenceRange.aEnd )
+ RefInputStart( mpActiveEdit );
+
+ OUString aReferenceString;
+
+ if ( mpActiveEdit == mxInputRangeEdit.get() )
+ {
+ mInputRange = rReferenceRange;
+ aReferenceString = mInputRange.Format(rDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails);
+ mxInputRangeEdit->SetRefString( aReferenceString );
+
+ LimitSampleSizeAndPeriod();
+ }
+ else if ( mpActiveEdit == mxOutputRangeEdit.get() )
+ {
+ mOutputAddress = rReferenceRange.aStart;
+
+ ScRefFlags nFormat = ( mOutputAddress.Tab() == mCurrentAddress.Tab() ) ?
+ ScRefFlags::ADDR_ABS :
+ ScRefFlags::ADDR_ABS_3D;
+ aReferenceString = mOutputAddress.Format(nFormat, &rDocument, rDocument.GetAddressConvention());
+ mxOutputRangeEdit->SetRefString( aReferenceString );
+
+ // Change sampling size according to output range selection
+ sal_Int64 aSelectedSampleSize = rReferenceRange.aEnd.Row() - rReferenceRange.aStart.Row() + 1;
+ if (aSelectedSampleSize > 1)
+ mxSampleSize->set_value(aSelectedSampleSize);
+ SamplingSizeValueModified(*mxSampleSize);
+ }
+ }
+
+ // Enable OK if both, input range and output address are set.
+ // Disable if at least one is invalid.
+ mxButtonOk->set_sensitive(mInputRange.IsValid() && mOutputAddress.IsValid());
+}
+
+ScRange ScSamplingDialog::PerformPeriodicSampling(ScDocShell* pDocShell)
+{
+ ScAddress aStart = mInputRange.aStart;
+ ScAddress aEnd = mInputRange.aEnd;
+
+ SCTAB outTab = mOutputAddress.Tab();
+ SCROW outRow = mOutputAddress.Row();
+
+ sal_Int64 aPeriod = mxPeriod->get_value();
+
+ for (SCROW inTab = aStart.Tab(); inTab <= aEnd.Tab(); inTab++)
+ {
+ SCCOL outCol = mOutputAddress.Col();
+ for (SCCOL inCol = aStart.Col(); inCol <= aEnd.Col(); inCol++)
+ {
+ sal_Int64 i = 0;
+ outRow = mOutputAddress.Row();
+ for (SCROW inRow = aStart.Row(); inRow <= aEnd.Row(); inRow++)
+ {
+ assert(aPeriod && "div-by-zero");
+ if (i % aPeriod == aPeriod - 1 ) // Sample the last of period
+ {
+ double aValue = mDocument.GetValue(ScAddress(inCol, inRow, inTab));
+ pDocShell->GetDocFunc().SetValueCell(ScAddress(outCol, outRow, outTab), aValue, true);
+ outRow++;
+ }
+ i++;
+ }
+ outCol++;
+ }
+ outTab++;
+ }
+
+ return ScRange(mOutputAddress, ScAddress(outTab, outRow, outTab) );
+}
+
+ScRange ScSamplingDialog::PerformRandomSampling(ScDocShell* pDocShell)
+{
+ ScAddress aStart = mInputRange.aStart;
+ ScAddress aEnd = mInputRange.aEnd;
+
+ SCTAB outTab = mOutputAddress.Tab();
+ SCROW outRow = mOutputAddress.Row();
+
+ const sal_Int64 nSampleSize = mxSampleSize->get_value();
+
+ // This implementation groups by columns. Other options could be grouping
+ // by rows or area.
+ const sal_Int64 nPopulationSize = aEnd.Row() - aStart.Row() + 1;
+
+ const bool bWithReplacement = mxWithReplacement->get_sensitive() && mxWithReplacement->get_active();
+
+ // WOR (WithOutReplacement) can't draw more than population. Catch that in
+ // the caller.
+ assert( bWithReplacement || nSampleSize <= nPopulationSize);
+ if (!bWithReplacement && nSampleSize > nPopulationSize)
+ // Would enter an endless loop below, bail out.
+ return ScRange( mOutputAddress);
+
+ for (SCROW inTab = aStart.Tab(); inTab <= aEnd.Tab(); inTab++)
+ {
+ SCCOL outCol = mOutputAddress.Col();
+ for (SCCOL inCol = aStart.Col(); inCol <= aEnd.Col(); inCol++)
+ {
+ outRow = mOutputAddress.Row();
+ std::vector<bool> vUsed( nPopulationSize, false);
+
+ while ((outRow - mOutputAddress.Row()) < nSampleSize)
+ {
+ // [a,b] *both* inclusive
+ SCROW nRandom = comphelper::rng::uniform_int_distribution( aStart.Row(), aEnd.Row());
+
+ if (!bWithReplacement)
+ {
+ nRandom -= aStart.Row();
+ if (vUsed[nRandom])
+ {
+ // Find a nearest one, preferring forwards.
+ // Again: it's essential that the loop is entered only
+ // if nSampleSize<=nPopulationSize, which is checked
+ // above.
+ SCROW nBack = nRandom;
+ SCROW nForw = nRandom;
+ do
+ {
+ if (nForw < nPopulationSize - 1 && !vUsed[++nForw])
+ {
+ nRandom = nForw;
+ break;
+ }
+ if (nBack > 0 && !vUsed[--nBack])
+ {
+ nRandom = nBack;
+ break;
+ }
+ }
+ while (true);
+ }
+ vUsed[nRandom] = true;
+ nRandom += aStart.Row();
+ }
+
+ const double fValue = mDocument.GetValue( ScAddress(inCol, nRandom, inTab) );
+ pDocShell->GetDocFunc().SetValueCell(ScAddress(outCol, outRow, outTab), fValue, true);
+ outRow++;
+ }
+ outCol++;
+ }
+ outTab++;
+ }
+
+ return ScRange(mOutputAddress, ScAddress(outTab, outRow, outTab) );
+}
+
+ScRange ScSamplingDialog::PerformRandomSamplingKeepOrder(ScDocShell* pDocShell)
+{
+ ScAddress aStart = mInputRange.aStart;
+ ScAddress aEnd = mInputRange.aEnd;
+
+ SCTAB outTab = mOutputAddress.Tab();
+ SCROW outRow = mOutputAddress.Row();
+
+ SCROW inRow;
+
+ sal_Int64 aSampleSize = mxSampleSize->get_value();
+
+ for (SCROW inTab = aStart.Tab(); inTab <= aEnd.Tab(); inTab++)
+ {
+ SCCOL outCol = mOutputAddress.Col();
+ for (SCCOL inCol = aStart.Col(); inCol <= aEnd.Col(); inCol++)
+ {
+ SCROW aPopulationSize = (aEnd.Row() - aStart.Row()) + 1;
+
+ outRow = mOutputAddress.Row();
+ inRow = aStart.Row();
+
+ while ((outRow - mOutputAddress.Row()) < aSampleSize)
+ {
+ double aRandomValue = comphelper::rng::uniform_real_distribution();
+
+ if ( (aPopulationSize - (inRow - aStart.Row())) * aRandomValue >= aSampleSize - (outRow - mOutputAddress.Row()) )
+ {
+ inRow++;
+ }
+ else
+ {
+ double aValue = mDocument.GetValue( ScAddress(inCol, inRow, inTab) );
+ pDocShell->GetDocFunc().SetValueCell(ScAddress(outCol, outRow, outTab), aValue, true);
+ inRow++;
+ outRow++;
+ }
+ }
+ outCol++;
+ }
+ outTab++;
+ }
+
+ return ScRange(mOutputAddress, ScAddress(outTab, outRow, outTab) );
+}
+
+void ScSamplingDialog::PerformSampling()
+{
+ OUString aUndo(ScResId(STR_SAMPLING_UNDO_NAME));
+ ScDocShell* pDocShell = mViewData.GetDocShell();
+ SfxUndoManager* pUndoManager = pDocShell->GetUndoManager();
+
+ ScRange aModifiedRange;
+
+ pUndoManager->EnterListAction( aUndo, aUndo, 0, mViewData.GetViewShell()->GetViewShellId() );
+
+ if (mxRandomMethodRadio->get_active())
+ {
+ if (mxKeepOrder->get_sensitive() && mxKeepOrder->get_active())
+ aModifiedRange = PerformRandomSamplingKeepOrder(pDocShell);
+ else
+ aModifiedRange = PerformRandomSampling(pDocShell);
+ }
+ else if (mxPeriodicMethodRadio->get_active())
+ {
+ aModifiedRange = PerformPeriodicSampling(pDocShell);
+ }
+
+ pUndoManager->LeaveListAction();
+ pDocShell->PostPaint(aModifiedRange, PaintPartFlags::Grid);
+}
+
+sal_Int64 ScSamplingDialog::GetPopulationSize() const
+{
+ return mInputRange.IsValid() ? mInputRange.aEnd.Row() - mInputRange.aStart.Row() + 1 : 0;
+}
+
+void ScSamplingDialog::LimitSampleSizeAndPeriod()
+{
+ // Limit sample size (for WOR methods) and period if population is smaller
+ // than last known value. When enlargening the input population range the
+ // values will be adjusted up to the last known value again.
+ const sal_Int64 nPopulationSize = GetPopulationSize();
+ if (nPopulationSize <= mnLastSampleSizeValue && !mxWithReplacement->get_active())
+ mxSampleSize->set_value( nPopulationSize);
+ if (nPopulationSize <= mnLastPeriodValue)
+ mxPeriod->set_value( nPopulationSize);
+}
+
+IMPL_LINK_NOARG(ScSamplingDialog, SamplingSizeValueModified, weld::SpinButton&, void)
+{
+ if (!mxWithReplacement->get_active())
+ {
+ // For all WOR methods limit sample size to population size.
+ const sal_Int64 nPopulationSize = GetPopulationSize();
+ if (mxSampleSize->get_value() > nPopulationSize)
+ mxSampleSize->set_value(nPopulationSize);
+ }
+ mnLastSampleSizeValue = mxSampleSize->get_value();
+}
+
+IMPL_LINK_NOARG(ScSamplingDialog, PeriodValueModified, weld::SpinButton&, void)
+{
+ // Limit period to population size.
+ const sal_Int64 nPopulationSize = GetPopulationSize();
+ if (mxPeriod->get_value() > nPopulationSize)
+ mxPeriod->set_value(nPopulationSize);
+ mnLastPeriodValue = mxPeriod->get_value();
+}
+
+IMPL_LINK( ScSamplingDialog, GetEditFocusHandler, formula::RefEdit&, rCtrl, void )
+{
+ if (&rCtrl == mxInputRangeEdit.get())
+ mpActiveEdit = mxInputRangeEdit.get();
+ else if (&rCtrl == mxOutputRangeEdit.get())
+ mpActiveEdit = mxOutputRangeEdit.get();
+ else
+ mpActiveEdit = nullptr;
+
+ if (mpActiveEdit)
+ mpActiveEdit->SelectAll();
+}
+
+IMPL_LINK(ScSamplingDialog, GetButtonFocusHandler, formula::RefButton&, rCtrl, void)
+{
+ if (&rCtrl == mxInputRangeButton.get())
+ mpActiveEdit = mxInputRangeEdit.get();
+ else if (&rCtrl == mxOutputRangeButton.get())
+ mpActiveEdit = mxOutputRangeEdit.get();
+ else
+ mpActiveEdit = nullptr;
+
+ if (mpActiveEdit)
+ mpActiveEdit->SelectAll();
+}
+
+
+IMPL_LINK(ScSamplingDialog, ButtonClicked, weld::Button&, rButton, void)
+{
+ if (&rButton == mxButtonOk.get())
+ {
+ PerformSampling();
+ response(RET_OK);
+ }
+ else
+ response(RET_CANCEL);
+}
+
+IMPL_LINK_NOARG(ScSamplingDialog, LoseEditFocusHandler, formula::RefEdit&, void)
+{
+ mDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScSamplingDialog, LoseButtonFocusHandler, formula::RefButton&, void)
+{
+ mDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScSamplingDialog, ToggleSamplingMethod, weld::Toggleable&, void)
+{
+ ToggleSamplingMethod();
+}
+
+void ScSamplingDialog::ToggleSamplingMethod()
+{
+ if (mxRandomMethodRadio->get_active())
+ {
+ mxPeriod->set_sensitive(false);
+ mxSampleSize->set_sensitive(true);
+ mxWithReplacement->set_sensitive(true);
+ mxKeepOrder->set_sensitive(true);
+ }
+ else if (mxPeriodicMethodRadio->get_active())
+ {
+ // WOR keeping order.
+ mxPeriod->set_sensitive(true);
+ mxSampleSize->set_sensitive(false);
+ mxWithReplacement->set_active(false);
+ mxWithReplacement->set_sensitive(false);
+ mxKeepOrder->set_active(true);
+ mxKeepOrder->set_sensitive(false);
+ }
+}
+
+IMPL_LINK(ScSamplingDialog, CheckHdl, weld::Toggleable&, rBtn, void)
+{
+ // Keep both checkboxes enabled so user can easily switch between the three
+ // possible combinations (one or the other or none), just uncheck the other
+ // one if one is checked. Otherwise the other checkbox would had to be
+ // disabled until user unchecks the enabled one again, which would force
+ // user to two clicks to switch.
+ if (&rBtn == mxWithReplacement.get())
+ {
+ if (mxWithReplacement->get_active())
+ {
+ // For WR can't keep order.
+ mxKeepOrder->set_active(false);
+ }
+ else
+ {
+ // For WOR limit sample size to population size.
+ SamplingSizeValueModified(*mxSampleSize);
+ }
+ }
+ else if (&rBtn == mxKeepOrder.get())
+ {
+ if (mxKeepOrder->get_active())
+ {
+ // Keep order is always WOR.
+ mxWithReplacement->set_active(false);
+ SamplingSizeValueModified(*mxSampleSize);
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ScSamplingDialog, RefInputModifyHandler, formula::RefEdit&, void)
+{
+ if ( mpActiveEdit )
+ {
+ if ( mpActiveEdit == mxInputRangeEdit.get() )
+ {
+ ScRangeList aRangeList;
+ bool bValid = ParseWithNames( aRangeList, mxInputRangeEdit->GetText(), mDocument);
+ const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
+ if (pRange)
+ {
+ mInputRange = *pRange;
+ // Highlight the resulting range.
+ mxInputRangeEdit->StartUpdateData();
+
+ LimitSampleSizeAndPeriod();
+ }
+ else
+ {
+ mInputRange = ScRange( ScAddress::INITIALIZE_INVALID);
+ }
+ }
+ else if ( mpActiveEdit == mxOutputRangeEdit.get() )
+ {
+ ScRangeList aRangeList;
+ bool bValid = ParseWithNames( aRangeList, mxOutputRangeEdit->GetText(), mDocument);
+ const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
+ if (pRange)
+ {
+ mOutputAddress = pRange->aStart;
+
+ // Crop output range to top left address for Edit field.
+ if (pRange->aStart != pRange->aEnd)
+ {
+ ScRefFlags nFormat = ( mOutputAddress.Tab() == mCurrentAddress.Tab() ) ?
+ ScRefFlags::ADDR_ABS :
+ ScRefFlags::ADDR_ABS_3D;
+ OUString aReferenceString = mOutputAddress.Format(nFormat, &mDocument, mDocument.GetAddressConvention());
+ mxOutputRangeEdit->SetRefString( aReferenceString );
+ }
+
+ // Change sampling size according to output range selection
+ sal_Int64 aSelectedSampleSize = pRange->aEnd.Row() - pRange->aStart.Row() + 1;
+ if (aSelectedSampleSize > 1)
+ mxSampleSize->set_value(aSelectedSampleSize);
+ SamplingSizeValueModified(*mxSampleSize);
+
+ // Highlight the resulting range.
+ mxOutputRangeEdit->StartUpdateData();
+ }
+ else
+ {
+ mOutputAddress = ScAddress( ScAddress::INITIALIZE_INVALID);
+ }
+ }
+ }
+
+ // Enable OK if both, input range and output address are set.
+ mxButtonOk->set_sensitive(mInputRange.IsValid() && mOutputAddress.IsValid());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/StatisticsInputOutputDialog.cxx b/sc/source/ui/StatisticsDialogs/StatisticsInputOutputDialog.cxx
new file mode 100644
index 000000000..7447ebf9a
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/StatisticsInputOutputDialog.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/.
+ *
+ */
+
+#include <svl/undo.hxx>
+
+#include <rangelst.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <scresid.hxx>
+#include <tabvwsh.hxx>
+
+#include <StatisticsInputOutputDialog.hxx>
+
+ScRangeList ScStatisticsInputOutputDialog::MakeColumnRangeList(SCTAB aTab, ScAddress const & aStart, ScAddress const & aEnd)
+{
+ ScRangeList aRangeList;
+ for (SCCOL inCol = aStart.Col(); inCol <= aEnd.Col(); inCol++)
+ {
+ ScRange aColumnRange (
+ ScAddress(inCol, aStart.Row(), aTab),
+ ScAddress(inCol, aEnd.Row(), aTab) );
+
+ aRangeList.push_back(aColumnRange);
+ }
+ return aRangeList;
+}
+
+ScRangeList ScStatisticsInputOutputDialog::MakeRowRangeList(SCTAB aTab, ScAddress const & aStart, ScAddress const & aEnd)
+{
+ ScRangeList aRangeList;
+ for (SCROW inRow = aStart.Row(); inRow <= aEnd.Row(); inRow++)
+ {
+ ScRange aRowRange (
+ ScAddress(aStart.Col(), inRow, aTab),
+ ScAddress(aEnd.Col(), inRow, aTab) );
+
+ aRangeList.push_back(aRowRange);
+ }
+ return aRangeList;
+}
+
+ScStatisticsInputOutputDialog::ScStatisticsInputOutputDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData, const OUString& rUIXMLDescription, const OString& rID)
+ : ScAnyRefDlgController(pSfxBindings, pChildWindow, pParent, rUIXMLDescription, rID)
+ , mxInputRangeLabel(m_xBuilder->weld_label("input-range-label"))
+ , mxInputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("input-range-edit")))
+ , mxInputRangeButton(new formula::RefButton(m_xBuilder->weld_button("input-range-button")))
+ , mxOutputRangeLabel(m_xBuilder->weld_label("output-range-label"))
+ , mxOutputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("output-range-edit")))
+ , mxOutputRangeButton(new formula::RefButton(m_xBuilder->weld_button("output-range-button")))
+ , mxGroupByColumnsRadio(m_xBuilder->weld_radio_button("groupedby-columns-radio"))
+ , mxGroupByRowsRadio(m_xBuilder->weld_radio_button("groupedby-rows-radio"))
+ , mViewData(rViewData)
+ , mDocument(rViewData.GetDocument())
+ , mInputRange(ScAddress::INITIALIZE_INVALID)
+ , mAddressDetails(mDocument.GetAddressConvention(), 0, 0)
+ , mOutputAddress(ScAddress::INITIALIZE_INVALID)
+ , mGroupedBy(BY_COLUMN)
+ , mxButtonOk(m_xBuilder->weld_button("ok"))
+ , mxButtonCancel(m_xBuilder->weld_button("cancel"))
+ , mpActiveEdit(nullptr)
+ , mCurrentAddress(rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo())
+ , mDialogLostFocus(false)
+{
+ mxInputRangeEdit->SetReferences(this, mxInputRangeLabel.get());
+ mxInputRangeButton->SetReferences(this, mxInputRangeEdit.get());
+
+ mxOutputRangeEdit->SetReferences(this, mxOutputRangeLabel.get());
+ mxOutputRangeButton->SetReferences(this, mxOutputRangeEdit.get());
+
+ Init();
+ GetRangeFromSelection();
+}
+
+ScStatisticsInputOutputDialog::~ScStatisticsInputOutputDialog()
+{
+}
+
+void ScStatisticsInputOutputDialog::Init()
+{
+ mxButtonCancel->connect_clicked( LINK( this, ScStatisticsInputOutputDialog, ButtonClicked ) );
+ mxButtonOk->connect_clicked( LINK( this, ScStatisticsInputOutputDialog, ButtonClicked ) );
+ mxButtonOk->set_sensitive(false);
+
+ Link<formula::RefEdit&,void> aEditLink = LINK( this, ScStatisticsInputOutputDialog, GetEditFocusHandler );
+ mxInputRangeEdit->SetGetFocusHdl( aEditLink );
+ mxOutputRangeEdit->SetGetFocusHdl( aEditLink );
+ Link<formula::RefButton&,void> aButtonLink = LINK( this, ScStatisticsInputOutputDialog, GetButtonFocusHandler );
+ mxInputRangeButton->SetGetFocusHdl( aButtonLink );
+ mxOutputRangeButton->SetGetFocusHdl( aButtonLink );
+
+ aEditLink = LINK( this, ScStatisticsInputOutputDialog, LoseEditFocusHandler );
+ mxInputRangeEdit->SetLoseFocusHdl( aEditLink );
+ mxOutputRangeEdit->SetLoseFocusHdl( aEditLink );
+ aButtonLink = LINK( this, ScStatisticsInputOutputDialog, LoseButtonFocusHandler );
+ mxInputRangeButton->SetLoseFocusHdl( aButtonLink );
+ mxOutputRangeButton->SetLoseFocusHdl( aButtonLink );
+
+ Link<formula::RefEdit&,void> aLink2 = LINK( this, ScStatisticsInputOutputDialog, RefInputModifyHandler);
+ mxInputRangeEdit->SetModifyHdl( aLink2);
+ mxOutputRangeEdit->SetModifyHdl( aLink2);
+
+ mxOutputRangeEdit->GrabFocus();
+
+ mxGroupByColumnsRadio->connect_toggled( LINK( this, ScStatisticsInputOutputDialog, GroupByChanged ) );
+ mxGroupByRowsRadio->connect_toggled( LINK( this, ScStatisticsInputOutputDialog, GroupByChanged ) );
+
+ mxGroupByColumnsRadio->set_active(true);
+ mxGroupByRowsRadio->set_active(false);
+}
+
+void ScStatisticsInputOutputDialog::GetRangeFromSelection()
+{
+ mViewData.GetSimpleArea(mInputRange);
+ OUString aCurrentString(mInputRange.Format(mDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails));
+ mxInputRangeEdit->SetText(aCurrentString);
+}
+
+void ScStatisticsInputOutputDialog::SetActive()
+{
+ if ( mDialogLostFocus )
+ {
+ mDialogLostFocus = false;
+ if( mpActiveEdit )
+ mpActiveEdit->GrabFocus();
+ }
+ else
+ {
+ m_xDialog->grab_focus();
+ }
+ RefInputDone();
+}
+
+void ScStatisticsInputOutputDialog::SetReference( const ScRange& rReferenceRange, ScDocument& rDocument )
+{
+ if ( mpActiveEdit )
+ {
+ if ( rReferenceRange.aStart != rReferenceRange.aEnd )
+ RefInputStart( mpActiveEdit );
+
+ OUString aReferenceString;
+
+ if (mpActiveEdit == mxInputRangeEdit.get())
+ {
+ mInputRange = rReferenceRange;
+ aReferenceString = mInputRange.Format(rDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails);
+ mxInputRangeEdit->SetRefString( aReferenceString );
+ }
+ else if (mpActiveEdit == mxOutputRangeEdit.get())
+ {
+ mOutputAddress = rReferenceRange.aStart;
+
+ ScRefFlags nFormat = ( mOutputAddress.Tab() == mCurrentAddress.Tab() ) ?
+ ScRefFlags::ADDR_ABS :
+ ScRefFlags::ADDR_ABS_3D;
+ aReferenceString = mOutputAddress.Format(nFormat, &rDocument, rDocument.GetAddressConvention());
+ mxOutputRangeEdit->SetRefString( aReferenceString );
+ }
+ }
+
+ ValidateDialogInput();
+}
+
+IMPL_LINK( ScStatisticsInputOutputDialog, ButtonClicked, weld::Button&, rButton, void )
+{
+ if (&rButton == mxButtonOk.get())
+ {
+ CalculateInputAndWriteToOutput();
+ response(RET_OK);
+ }
+ else
+ response(RET_CANCEL);
+}
+
+IMPL_LINK(ScStatisticsInputOutputDialog, GetEditFocusHandler, formula::RefEdit&, rCtrl, void)
+{
+ mpActiveEdit = nullptr;
+
+ if (&rCtrl == mxInputRangeEdit.get())
+ mpActiveEdit = mxInputRangeEdit.get();
+ if (&rCtrl == mxOutputRangeEdit.get())
+ mpActiveEdit = mxOutputRangeEdit.get();
+
+ if (mpActiveEdit)
+ mpActiveEdit->SelectAll();
+}
+
+IMPL_LINK(ScStatisticsInputOutputDialog, GetButtonFocusHandler, formula::RefButton&, rCtrl, void)
+{
+ mpActiveEdit = nullptr;
+
+ if (&rCtrl == mxInputRangeButton.get())
+ mpActiveEdit = mxInputRangeEdit.get();
+ else if (&rCtrl == mxOutputRangeButton.get())
+ mpActiveEdit = mxOutputRangeEdit.get();
+
+ if (mpActiveEdit)
+ mpActiveEdit->SelectAll();
+}
+
+IMPL_LINK_NOARG(ScStatisticsInputOutputDialog, LoseEditFocusHandler, formula::RefEdit&, void)
+{
+ mDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScStatisticsInputOutputDialog, LoseButtonFocusHandler, formula::RefButton&, void)
+{
+ mDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG( ScStatisticsInputOutputDialog, GroupByChanged, weld::Toggleable&, void )
+{
+ if (mxGroupByColumnsRadio->get_active())
+ mGroupedBy = BY_COLUMN;
+ else if (mxGroupByRowsRadio->get_active())
+ mGroupedBy = BY_ROW;
+
+ ValidateDialogInput();
+}
+
+IMPL_LINK_NOARG( ScStatisticsInputOutputDialog, RefInputModifyHandler, formula::RefEdit&, void )
+{
+ if ( mpActiveEdit )
+ {
+ if (mpActiveEdit == mxInputRangeEdit.get())
+ {
+ ScRangeList aRangeList;
+ bool bValid = ParseWithNames( aRangeList, mxInputRangeEdit->GetText(), mDocument);
+ const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
+ if (pRange)
+ {
+ mInputRange = *pRange;
+ // Highlight the resulting range.
+ mxInputRangeEdit->StartUpdateData();
+ }
+ else
+ {
+ mInputRange = ScRange( ScAddress::INITIALIZE_INVALID);
+ }
+ }
+ else if (mpActiveEdit == mxOutputRangeEdit.get())
+ {
+ ScRangeList aRangeList;
+ bool bValid = ParseWithNames( aRangeList, mxOutputRangeEdit->GetText(), mDocument);
+ const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
+ if (pRange)
+ {
+ mOutputAddress = pRange->aStart;
+
+ // Crop output range to top left address for Edit field.
+ if (pRange->aStart != pRange->aEnd)
+ {
+ ScRefFlags nFormat = ( mOutputAddress.Tab() == mCurrentAddress.Tab() ) ?
+ ScRefFlags::ADDR_ABS :
+ ScRefFlags::ADDR_ABS_3D;
+ OUString aReferenceString = mOutputAddress.Format(nFormat, &mDocument, mDocument.GetAddressConvention());
+ mxOutputRangeEdit->SetRefString( aReferenceString );
+ }
+
+ // Highlight the resulting range.
+ mxOutputRangeEdit->StartUpdateData();
+ }
+ else
+ {
+ mOutputAddress = ScAddress( ScAddress::INITIALIZE_INVALID);
+ }
+ }
+ }
+
+ ValidateDialogInput();
+}
+
+void ScStatisticsInputOutputDialog::CalculateInputAndWriteToOutput()
+{
+ OUString aUndo(ScResId(GetUndoNameId()));
+ ScDocShell* pDocShell = mViewData.GetDocShell();
+ SfxUndoManager* pUndoManager = pDocShell->GetUndoManager();
+ pUndoManager->EnterListAction( aUndo, aUndo, 0, mViewData.GetViewShell()->GetViewShellId() );
+
+ ScRange aOutputRange = ApplyOutput(pDocShell);
+
+ pUndoManager->LeaveListAction();
+ pDocShell->PostPaint( aOutputRange, PaintPartFlags::Grid );
+}
+
+bool ScStatisticsInputOutputDialog::InputRangesValid()
+{
+ return mInputRange.IsValid() && mOutputAddress.IsValid();
+}
+
+void ScStatisticsInputOutputDialog::ValidateDialogInput()
+{
+ // Enable OK button if all inputs are ok.
+ mxButtonOk->set_sensitive(InputRangesValid());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/StatisticsTwoVariableDialog.cxx b/sc/source/ui/StatisticsDialogs/StatisticsTwoVariableDialog.cxx
new file mode 100644
index 000000000..3c0f7ce98
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/StatisticsTwoVariableDialog.cxx
@@ -0,0 +1,347 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <svl/undo.hxx>
+
+#include <rangelst.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <scresid.hxx>
+#include <tabvwsh.hxx>
+
+#include <StatisticsTwoVariableDialog.hxx>
+
+ScStatisticsTwoVariableDialog::ScStatisticsTwoVariableDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData, const OUString& rUIXMLDescription, const OString& rID)
+ : ScAnyRefDlgController(pSfxBindings, pChildWindow, pParent, rUIXMLDescription, rID)
+ , mxVariable1RangeLabel(m_xBuilder->weld_label("variable1-range-label"))
+ , mxVariable1RangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("variable1-range-edit")))
+ , mxVariable1RangeButton(new formula::RefButton(m_xBuilder->weld_button("variable1-range-button")))
+ , mxVariable2RangeLabel(m_xBuilder->weld_label("variable2-range-label"))
+ , mxVariable2RangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("variable2-range-edit")))
+ , mxVariable2RangeButton(new formula::RefButton(m_xBuilder->weld_button("variable2-range-button")))
+ , mxOutputRangeLabel(m_xBuilder->weld_label("output-range-label"))
+ , mxOutputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("output-range-edit")))
+ , mxOutputRangeButton(new formula::RefButton(m_xBuilder->weld_button("output-range-button")))
+ , mViewData(rViewData)
+ , mDocument(rViewData.GetDocument())
+ , mVariable1Range(ScAddress::INITIALIZE_INVALID)
+ , mVariable2Range(ScAddress::INITIALIZE_INVALID)
+ , mAddressDetails(mDocument.GetAddressConvention(), 0, 0 )
+ , mOutputAddress(ScAddress::INITIALIZE_INVALID)
+ , mGroupedBy(BY_COLUMN)
+ , mxButtonOk(m_xBuilder->weld_button("ok"))
+ , mxButtonCancel(m_xBuilder->weld_button("cancel"))
+ , mxGroupByColumnsRadio(m_xBuilder->weld_radio_button("groupedby-columns-radio"))
+ , mxGroupByRowsRadio(m_xBuilder->weld_radio_button("groupedby-rows-radio"))
+ , mpActiveEdit(nullptr)
+ , mCurrentAddress(rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() )
+ , mDialogLostFocus(false)
+{
+ mxVariable1RangeEdit->SetReferences(this, mxVariable1RangeLabel.get());
+ mxVariable1RangeButton->SetReferences(this, mxVariable1RangeEdit.get());
+
+ mxVariable2RangeEdit->SetReferences(this, mxVariable2RangeLabel.get());
+ mxVariable2RangeButton->SetReferences(this, mxVariable2RangeEdit.get());
+
+ mxOutputRangeEdit->SetReferences(this, mxOutputRangeLabel.get());
+ mxOutputRangeButton->SetReferences(this, mxOutputRangeEdit.get());
+
+ Init();
+ GetRangeFromSelection();
+}
+
+ScStatisticsTwoVariableDialog::~ScStatisticsTwoVariableDialog()
+{
+}
+
+void ScStatisticsTwoVariableDialog::Init()
+{
+ mxButtonCancel->connect_clicked( LINK( this, ScStatisticsTwoVariableDialog, ButtonClicked ) );
+ mxButtonOk->connect_clicked( LINK( this, ScStatisticsTwoVariableDialog, ButtonClicked ) );
+ mxButtonOk->set_sensitive(false);
+
+ Link<formula::RefEdit&,void> aEditLink = LINK( this, ScStatisticsTwoVariableDialog, GetEditFocusHandler );
+ mxVariable1RangeEdit->SetGetFocusHdl( aEditLink );
+ mxVariable2RangeEdit->SetGetFocusHdl( aEditLink );
+ mxOutputRangeEdit->SetGetFocusHdl( aEditLink );
+
+ Link<formula::RefButton&,void> aButtonLink = LINK( this, ScStatisticsTwoVariableDialog, GetButtonFocusHandler );
+ mxVariable1RangeButton->SetGetFocusHdl( aButtonLink );
+ mxVariable2RangeButton->SetGetFocusHdl( aButtonLink );
+ mxOutputRangeButton->SetGetFocusHdl( aButtonLink );
+
+ aEditLink = LINK( this, ScStatisticsTwoVariableDialog, LoseEditFocusHandler );
+ mxVariable1RangeEdit->SetLoseFocusHdl( aEditLink );
+ mxVariable2RangeEdit->SetLoseFocusHdl( aEditLink );
+ mxOutputRangeEdit->SetLoseFocusHdl( aEditLink );
+
+ aButtonLink = LINK( this, ScStatisticsTwoVariableDialog, LoseButtonFocusHandler );
+ mxVariable1RangeButton->SetLoseFocusHdl( aButtonLink );
+ mxVariable2RangeButton->SetLoseFocusHdl( aButtonLink );
+ mxOutputRangeButton->SetLoseFocusHdl( aButtonLink );
+
+ Link<formula::RefEdit&,void> aLink2 = LINK( this, ScStatisticsTwoVariableDialog, RefInputModifyHandler);
+ mxVariable1RangeEdit->SetModifyHdl( aLink2);
+ mxVariable2RangeEdit->SetModifyHdl( aLink2);
+ mxOutputRangeEdit->SetModifyHdl( aLink2);
+
+ mxOutputRangeEdit->GrabFocus();
+
+ mxGroupByColumnsRadio->connect_toggled( LINK( this, ScStatisticsTwoVariableDialog, GroupByChanged ) );
+ mxGroupByRowsRadio->connect_toggled( LINK( this, ScStatisticsTwoVariableDialog, GroupByChanged ) );
+
+ mxGroupByColumnsRadio->set_active(true);
+ mxGroupByRowsRadio->set_active(false);
+}
+
+void ScStatisticsTwoVariableDialog::GetRangeFromSelection()
+{
+ OUString aCurrentString;
+
+ ScRange aCurrentRange;
+ mViewData.GetSimpleArea(aCurrentRange);
+
+ if (aCurrentRange.aEnd.Col() - aCurrentRange.aStart.Col() == 1)
+ {
+ mVariable1Range = aCurrentRange;
+ mVariable1Range.aEnd.SetCol(mVariable1Range.aStart.Col());
+ aCurrentString = mVariable1Range.Format(mDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails);
+ mxVariable1RangeEdit->SetText(aCurrentString);
+
+ mVariable2Range = aCurrentRange;
+ mVariable2Range.aStart.SetCol(mVariable2Range.aEnd.Col());
+ aCurrentString = mVariable2Range.Format(mDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails);
+ mxVariable2RangeEdit->SetText(aCurrentString);
+ }
+ else
+ {
+ mVariable1Range = aCurrentRange;
+ aCurrentString = mVariable1Range.Format(mDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails);
+ mxVariable1RangeEdit->SetText(aCurrentString);
+ }
+}
+
+void ScStatisticsTwoVariableDialog::SetActive()
+{
+ if ( mDialogLostFocus )
+ {
+ mDialogLostFocus = false;
+ if( mpActiveEdit )
+ mpActiveEdit->GrabFocus();
+ }
+ else
+ {
+ m_xDialog->grab_focus();
+ }
+ RefInputDone();
+}
+
+void ScStatisticsTwoVariableDialog::SetReference( const ScRange& rReferenceRange, ScDocument& rDocument )
+{
+ if ( mpActiveEdit != nullptr )
+ {
+ if ( rReferenceRange.aStart != rReferenceRange.aEnd )
+ RefInputStart( mpActiveEdit );
+
+ OUString aReferenceString;
+
+ if ( mpActiveEdit == mxVariable1RangeEdit.get() )
+ {
+ mVariable1Range = rReferenceRange;
+ aReferenceString = mVariable1Range.Format(rDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails);
+ mxVariable1RangeEdit->SetRefString(aReferenceString);
+ }
+ else if ( mpActiveEdit == mxVariable2RangeEdit.get() )
+ {
+ mVariable2Range = rReferenceRange;
+ aReferenceString = mVariable2Range.Format(rDocument, ScRefFlags::RANGE_ABS_3D, mAddressDetails);
+ mxVariable2RangeEdit->SetRefString(aReferenceString);
+ }
+ else if ( mpActiveEdit == mxOutputRangeEdit.get() )
+ {
+ mOutputAddress = rReferenceRange.aStart;
+
+ ScRefFlags nFormat = ( mOutputAddress.Tab() == mCurrentAddress.Tab() ) ?
+ ScRefFlags::ADDR_ABS :
+ ScRefFlags::ADDR_ABS_3D;
+ aReferenceString = mOutputAddress.Format(nFormat, &rDocument, rDocument.GetAddressConvention());
+ mxOutputRangeEdit->SetRefString( aReferenceString );
+ }
+ }
+
+ ValidateDialogInput();
+}
+
+IMPL_LINK( ScStatisticsTwoVariableDialog, ButtonClicked, weld::Button&, rButton, void )
+{
+ if (&rButton == mxButtonOk.get())
+ {
+ CalculateInputAndWriteToOutput();
+ response(RET_OK);
+ }
+ else
+ response(RET_CANCEL);
+}
+
+IMPL_LINK(ScStatisticsTwoVariableDialog, GetEditFocusHandler, formula::RefEdit&, rCtrl, void)
+{
+ mpActiveEdit = nullptr;
+ if (&rCtrl == mxVariable1RangeEdit.get())
+ {
+ mpActiveEdit = mxVariable1RangeEdit.get();
+ }
+ else if (&rCtrl == mxVariable2RangeEdit.get())
+ {
+ mpActiveEdit = mxVariable2RangeEdit.get();
+ }
+ else if (&rCtrl == mxOutputRangeEdit.get())
+ {
+ mpActiveEdit = mxOutputRangeEdit.get();
+ }
+
+ if( mpActiveEdit )
+ mpActiveEdit->SelectAll();
+}
+
+IMPL_LINK( ScStatisticsTwoVariableDialog, GetButtonFocusHandler, formula::RefButton&, rCtrl, void )
+{
+ mpActiveEdit = nullptr;
+ if (&rCtrl == mxVariable1RangeButton.get())
+ {
+ mpActiveEdit = mxVariable1RangeEdit.get();
+ }
+ else if (&rCtrl == mxVariable2RangeButton.get())
+ {
+ mpActiveEdit = mxVariable2RangeEdit.get();
+ }
+ else if (&rCtrl == mxOutputRangeButton.get())
+ {
+ mpActiveEdit = mxOutputRangeEdit.get();
+ }
+
+ if( mpActiveEdit )
+ mpActiveEdit->SelectAll();
+}
+
+IMPL_LINK_NOARG( ScStatisticsTwoVariableDialog, LoseEditFocusHandler, formula::RefEdit&, void )
+{
+ mDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG( ScStatisticsTwoVariableDialog, LoseButtonFocusHandler, formula::RefButton&, void )
+{
+ mDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScStatisticsTwoVariableDialog, GroupByChanged, weld::Toggleable&, void)
+{
+ if (mxGroupByColumnsRadio->get_active())
+ mGroupedBy = BY_COLUMN;
+ else if (mxGroupByRowsRadio->get_active())
+ mGroupedBy = BY_ROW;
+
+ ValidateDialogInput();
+}
+
+IMPL_LINK_NOARG( ScStatisticsTwoVariableDialog, RefInputModifyHandler, formula::RefEdit&, void )
+{
+ if ( mpActiveEdit )
+ {
+ if (mpActiveEdit == mxVariable1RangeEdit.get())
+ {
+ ScRangeList aRangeList;
+ bool bValid = ParseWithNames( aRangeList, mxVariable1RangeEdit->GetText(), mDocument);
+ const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
+ if (pRange)
+ {
+ mVariable1Range = *pRange;
+ // Highlight the resulting range.
+ mxVariable1RangeEdit->StartUpdateData();
+ }
+ else
+ {
+ mVariable1Range = ScRange( ScAddress::INITIALIZE_INVALID);
+ }
+ }
+ else if ( mpActiveEdit == mxVariable2RangeEdit.get() )
+ {
+ ScRangeList aRangeList;
+ bool bValid = ParseWithNames( aRangeList, mxVariable2RangeEdit->GetText(), mDocument);
+ const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
+ if (pRange)
+ {
+ mVariable2Range = *pRange;
+ // Highlight the resulting range.
+ mxVariable2RangeEdit->StartUpdateData();
+ }
+ else
+ {
+ mVariable2Range = ScRange( ScAddress::INITIALIZE_INVALID);
+ }
+ }
+ else if ( mpActiveEdit == mxOutputRangeEdit.get() )
+ {
+ ScRangeList aRangeList;
+ bool bValid = ParseWithNames( aRangeList, mxOutputRangeEdit->GetText(), mDocument);
+ const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
+ if (pRange)
+ {
+ mOutputAddress = pRange->aStart;
+
+ // Crop output range to top left address for Edit field.
+ if (pRange->aStart != pRange->aEnd)
+ {
+ ScRefFlags nFormat = ( mOutputAddress.Tab() == mCurrentAddress.Tab() ) ?
+ ScRefFlags::ADDR_ABS :
+ ScRefFlags::ADDR_ABS_3D;
+ OUString aReferenceString = mOutputAddress.Format(nFormat, &mDocument, mDocument.GetAddressConvention());
+ mxOutputRangeEdit->SetRefString( aReferenceString );
+ }
+
+ // Highlight the resulting range.
+ mxOutputRangeEdit->StartUpdateData();
+ }
+ else
+ {
+ mOutputAddress = ScAddress( ScAddress::INITIALIZE_INVALID);
+ }
+ }
+ }
+
+ ValidateDialogInput();
+}
+
+void ScStatisticsTwoVariableDialog::CalculateInputAndWriteToOutput()
+{
+ OUString aUndo(ScResId(GetUndoNameId()));
+ ScDocShell* pDocShell = mViewData.GetDocShell();
+ SfxUndoManager* pUndoManager = pDocShell->GetUndoManager();
+ pUndoManager->EnterListAction( aUndo, aUndo, 0, mViewData.GetViewShell()->GetViewShellId() );
+
+ ScRange aOutputRange = ApplyOutput(pDocShell);
+
+ pUndoManager->LeaveListAction();
+ pDocShell->PostPaint( aOutputRange, PaintPartFlags::Grid );
+}
+
+bool ScStatisticsTwoVariableDialog::InputRangesValid()
+{
+ return mVariable1Range.IsValid() && mVariable2Range.IsValid() && mOutputAddress.IsValid();
+}
+
+void ScStatisticsTwoVariableDialog::ValidateDialogInput()
+{
+ // Enable OK button if all inputs are ok.
+ mxButtonOk->set_sensitive(InputRangesValid());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/TTestDialog.cxx b/sc/source/ui/StatisticsDialogs/TTestDialog.cxx
new file mode 100644
index 000000000..864d4ac4f
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/TTestDialog.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 <reffact.hxx>
+#include <TableFillingAndNavigationTools.hxx>
+#include <TTestDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+ScTTestDialog::ScTTestDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData ) :
+ ScStatisticsTwoVariableDialog(
+ pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/ttestdialog.ui", "TTestDialog")
+{
+ m_xDialog->set_title(ScResId(STR_TTEST));
+}
+
+ScTTestDialog::~ScTTestDialog()
+{}
+
+void ScTTestDialog::Close()
+{
+ DoClose( ScTTestDialogWrapper::GetChildWindowId() );
+}
+
+TranslateId ScTTestDialog::GetUndoNameId()
+{
+ return STR_TTEST_UNDO_NAME;
+}
+
+ScRange ScTTestDialog::ApplyOutput(ScDocShell* pDocShell)
+{
+ AddressWalkerWriter aOutput(mOutputAddress, pDocShell, mDocument,
+ formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
+ FormulaTemplate aTemplate(&mDocument);
+
+ std::unique_ptr<DataRangeIterator> pVariable1Iterator;
+ if (mGroupedBy == BY_COLUMN)
+ pVariable1Iterator.reset(new DataRangeByColumnIterator(mVariable1Range));
+ else
+ pVariable1Iterator.reset(new DataRangeByRowIterator(mVariable1Range));
+
+ std::unique_ptr<DataRangeIterator> pVariable2Iterator;
+ if (mGroupedBy == BY_COLUMN)
+ pVariable2Iterator.reset(new DataRangeByColumnIterator(mVariable2Range));
+ else
+ pVariable2Iterator.reset(new DataRangeByRowIterator(mVariable2Range));
+
+ aTemplate.autoReplaceRange("%VARIABLE1_RANGE%", pVariable1Iterator->get());
+ aTemplate.autoReplaceRange("%VARIABLE2_RANGE%", pVariable2Iterator->get());
+
+ aOutput.writeBoldString(ScResId(STR_TTEST_UNDO_NAME));
+ aOutput.newLine();
+
+ // Alpha
+ aOutput.writeString(ScResId(STR_LABEL_ALPHA));
+ aOutput.nextColumn();
+ aOutput.writeValue(0.05);
+ aTemplate.autoReplaceAddress("%ALPHA%", aOutput.current());
+ aOutput.newLine();
+
+ // Hypothesized mean difference
+ aOutput.writeString(ScResId(STR_HYPOTHESIZED_MEAN_DIFFERENCE_LABEL));
+ aOutput.nextColumn();
+ aOutput.writeValue(0);
+ aTemplate.autoReplaceAddress("%HYPOTHESIZED_MEAN_DIFFERENCE%", aOutput.current());
+ aOutput.newLine();
+
+ aOutput.nextColumn();
+ aOutput.writeBoldString(ScResId(STR_VARIABLE_1_LABEL));
+ aOutput.nextColumn();
+ aOutput.writeBoldString(ScResId(STR_VARIABLE_2_LABEL));
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STRID_CALC_MEAN));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=AVERAGE(%VARIABLE1_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=AVERAGE(%VARIABLE2_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ aOutput.writeString(ScResId(STRID_CALC_VARIANCE));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=VAR(%VARIABLE1_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=VAR(%VARIABLE2_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // Observations
+ aOutput.writeString(ScResId(STR_OBSERVATIONS_LABEL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=COUNT(%VARIABLE1_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=COUNT(%VARIABLE2_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // Pearson Correlation
+ aOutput.writeString(ScResId(STR_TTEST_PEARSON_CORRELATION));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=CORREL(%VARIABLE1_RANGE%;%VARIABLE2_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // Observed mean difference
+ aOutput.writeString(ScResId(STR_OBSERVED_MEAN_DIFFERENCE_LABEL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=AVERAGE(IF(ISODD(IF(ISNUMBER(%VARIABLE1_RANGE%); 1; 0) * IF(ISNUMBER(%VARIABLE2_RANGE%); 1; 0)); %VARIABLE1_RANGE% - %VARIABLE2_RANGE%; \"NA\"))");
+ aOutput.writeMatrixFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%OBSERVED_MEAN_DIFFERENCE%", aOutput.current());
+ aOutput.newLine();
+
+ // Variance of the Differences
+ aOutput.writeString(ScResId(STR_TTEST_VARIANCE_OF_THE_DIFFERENCES));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=VAR(IF(ISODD(IF(ISNUMBER(%VARIABLE1_RANGE%); 1; 0) * IF(ISNUMBER(%VARIABLE2_RANGE%); 1; 0)); %VARIABLE1_RANGE% - %VARIABLE2_RANGE%; \"NA\"))");
+ aOutput.writeMatrixFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%VARIANCE_OF_DIFFERENCES%", aOutput.current());
+ aOutput.newLine();
+
+ // df
+ aOutput.writeString(ScResId(STR_ANOVA_LABEL_DF));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=SUM(IF(ISNUMBER(%VARIABLE1_RANGE%); 1; 0) * IF(ISNUMBER(%VARIABLE2_RANGE%); 1; 0)) - 1");
+ aOutput.writeMatrixFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%DEGREE_OF_FREEDOM%", aOutput.current());
+ aOutput.newLine();
+
+ // t stat
+ aOutput.writeString(ScResId(STR_TTEST_T_STAT));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=(%OBSERVED_MEAN_DIFFERENCE% - %HYPOTHESIZED_MEAN_DIFFERENCE%) / (%VARIANCE_OF_DIFFERENCES% / ( %DEGREE_OF_FREEDOM% + 1)) ^ 0.5");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%T_STAT%", aOutput.current());
+ aOutput.newLine();
+
+ // P one-tail
+ aOutput.writeString(ScResId(STR_TTEST_P_ONE_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=TDIST(ABS(%T_STAT%); %DEGREE_OF_FREEDOM%; 1)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // T critical one-tail
+ aOutput.writeString(ScResId(STR_TTEST_T_CRITICAL_ONE_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=TINV(2*%ALPHA%; %DEGREE_OF_FREEDOM%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // P two-tail
+ aOutput.writeString(ScResId(STR_TTEST_P_TWO_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=TDIST(ABS(%T_STAT%); %DEGREE_OF_FREEDOM%; 2)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // T critical two-tail
+ aOutput.writeString(ScResId(STR_TTEST_T_CRITICAL_TWO_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=TINV(%ALPHA%; %DEGREE_OF_FREEDOM%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+
+ return ScRange(aOutput.mMinimumAddress, aOutput.mMaximumAddress);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/TableFillingAndNavigationTools.cxx b/sc/source/ui/StatisticsDialogs/TableFillingAndNavigationTools.cxx
new file mode 100644
index 000000000..be8431128
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/TableFillingAndNavigationTools.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/.
+ *
+ */
+
+#include <memory>
+
+#include <editeng/editobj.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <editutil.hxx>
+
+#include <TableFillingAndNavigationTools.hxx>
+#include <formulacell.hxx>
+#include <docfunc.hxx>
+#include <docsh.hxx>
+
+FormulaTemplate::FormulaTemplate(ScDocument* pDoc)
+ : mpDoc(pDoc)
+ , mbUse3D(true)
+{}
+
+void FormulaTemplate::setTemplate(const OUString& aTemplate)
+{
+ mTemplate = aTemplate;
+}
+
+void FormulaTemplate::setTemplate(const char* aTemplate)
+{
+ mTemplate = OUString::createFromAscii(aTemplate);
+}
+
+const OUString& FormulaTemplate::getTemplate()
+{
+ for (const auto& [rVariable, rRange] : mRangeReplacementMap)
+ {
+ applyRange(rVariable, rRange, mbUse3D);
+ }
+ for (const auto& [rVariable, rAddress] : mAddressReplacementMap)
+ {
+ applyAddress(rVariable, rAddress, mbUse3D);
+ }
+ return mTemplate;
+}
+
+void FormulaTemplate::autoReplaceRange(const OUString& aVariable, const ScRange& rRange)
+{
+ mRangeReplacementMap[aVariable] = rRange;
+}
+
+void FormulaTemplate::autoReplaceAddress(const OUString& aVariable, ScAddress const & aAddress)
+{
+
+ mAddressReplacementMap[aVariable] = aAddress;
+}
+
+void FormulaTemplate::applyRange(std::u16string_view aVariable, const ScRange& aRange, bool b3D)
+{
+ ScRefFlags nFlag = b3D ? ScRefFlags::RANGE_ABS_3D : ScRefFlags::RANGE_ABS;
+ OUString aString = aRange.Format(*mpDoc, nFlag, mpDoc->GetAddressConvention());
+ mTemplate = mTemplate.replaceAll(aVariable, aString);
+}
+
+void FormulaTemplate::applyRangeList(std::u16string_view aVariable, const ScRangeList& aRangeList, sal_Unicode cDelimiter)
+{
+ OUString aString;
+ aRangeList.Format(aString, ScRefFlags::RANGE_ABS_3D, *mpDoc, mpDoc->GetAddressConvention(), cDelimiter);
+ mTemplate = mTemplate.replaceAll(aVariable, aString);
+}
+
+void FormulaTemplate::applyAddress(std::u16string_view aVariable, const ScAddress& aAddress, bool b3D)
+{
+ ScRefFlags nFlag = b3D ? ScRefFlags::ADDR_ABS_3D : ScRefFlags::ADDR_ABS;
+ OUString aString = aAddress.Format(nFlag, mpDoc, mpDoc->GetAddressConvention());
+ mTemplate = mTemplate.replaceAll(aVariable, aString);
+}
+
+void FormulaTemplate::applyString(std::u16string_view aVariable, std::u16string_view aValue)
+{
+ mTemplate = mTemplate.replaceAll(aVariable, aValue);
+}
+
+void FormulaTemplate::applyNumber(std::u16string_view aVariable, sal_Int32 aValue)
+{
+ mTemplate = mTemplate.replaceAll(aVariable, OUString::number(aValue));
+}
+
+AddressWalker::AddressWalker(const ScAddress& aInitialAddress) :
+ mCurrentAddress(aInitialAddress),
+ mMinimumAddress(aInitialAddress),
+ mMaximumAddress(aInitialAddress)
+{
+ mAddressStack.push_back(mCurrentAddress);
+}
+
+void AddressWalker::resetColumn()
+{
+ mCurrentAddress.SetCol(mAddressStack.back().Col());
+}
+
+void AddressWalker::resetRow()
+{
+ mCurrentAddress.SetRow(mAddressStack.back().Row());
+}
+
+void AddressWalker::reset()
+{
+ mCurrentAddress = mAddressStack.back();
+}
+
+void AddressWalker::newLine()
+{
+ resetColumn();
+ nextRow();
+}
+
+ScAddress AddressWalker::current(SCCOL aRelCol, SCROW aRelRow, SCTAB aRelTab)
+{
+ return ScAddress(
+ mCurrentAddress.Col() + aRelCol,
+ mCurrentAddress.Row() + aRelRow,
+ mCurrentAddress.Tab() + aRelTab);
+}
+
+void AddressWalker::nextColumn()
+{
+ mCurrentAddress.IncCol();
+
+ if(mMaximumAddress.Col() < mCurrentAddress.Col())
+ mMaximumAddress.SetCol(mCurrentAddress.Col());
+}
+
+void AddressWalker::nextRow()
+{
+ mCurrentAddress.IncRow();
+ if(mMaximumAddress.Row() < mCurrentAddress.Row())
+ mMaximumAddress.SetRow(mCurrentAddress.Row());
+}
+
+void AddressWalker::push(SCCOL aRelativeCol, SCROW aRelativeRow, SCTAB aRelativeTab)
+{
+ mCurrentAddress = current(aRelativeCol, aRelativeRow, aRelativeTab);
+ mAddressStack.push_back(mCurrentAddress);
+}
+
+AddressWalkerWriter::AddressWalkerWriter(const ScAddress& aInitialAddress, ScDocShell* pDocShell, ScDocument& rDocument,
+ formula::FormulaGrammar::Grammar eGrammar ) :
+ AddressWalker(aInitialAddress),
+ mpDocShell(pDocShell),
+ mrDocument(rDocument),
+ meGrammar(eGrammar)
+{}
+
+void AddressWalkerWriter::writeFormula(const OUString& aFormula)
+{
+ mpDocShell->GetDocFunc().SetFormulaCell(mCurrentAddress,
+ new ScFormulaCell(mrDocument, mCurrentAddress, aFormula, meGrammar), true);
+}
+
+void AddressWalkerWriter::writeFormulas(const std::vector<OUString>& rFormulas)
+{
+ size_t nLength = rFormulas.size();
+ if (!nLength)
+ return;
+
+ const size_t nMaxLen = mpDocShell->GetDocument().MaxRow() - mCurrentAddress.Row() + 1;
+ // If not done already, trim the length to fit.
+ if (nLength > nMaxLen)
+ nLength = nMaxLen;
+
+ std::vector<ScFormulaCell*> aFormulaCells(nLength);
+ ScAddress aAddr(mCurrentAddress);
+ for (size_t nIdx = 0; nIdx < nLength; ++nIdx)
+ {
+ aFormulaCells[nIdx] = new ScFormulaCell(mrDocument, aAddr, rFormulas[nIdx], meGrammar);
+ aAddr.IncRow(1);
+ }
+
+ mpDocShell->GetDocFunc().SetFormulaCells(mCurrentAddress, aFormulaCells, true);
+}
+
+void AddressWalkerWriter::writeMatrixFormula(const OUString& aFormula, SCCOL nCols, SCROW nRows)
+{
+ ScRange aRange;
+ aRange.aStart = mCurrentAddress;
+ aRange.aEnd = mCurrentAddress;
+ if (nCols > 1)
+ aRange.aEnd.IncCol(nCols - 1);
+ if (nRows > 1)
+ aRange.aEnd.IncRow(nRows - 1);
+ mpDocShell->GetDocFunc().EnterMatrix(aRange, nullptr, nullptr, aFormula, false, false, OUString(), meGrammar );
+}
+
+void AddressWalkerWriter::writeString(const OUString& aString)
+{
+ mpDocShell->GetDocFunc().SetStringCell(mCurrentAddress, aString, true);
+}
+
+void AddressWalkerWriter::writeString(const char* aCharArray)
+{
+ writeString(OUString::createFromAscii(aCharArray));
+}
+
+void AddressWalkerWriter::writeBoldString(const OUString& aString)
+{
+ ScFieldEditEngine& rEngine = mrDocument.GetEditEngine();
+ rEngine.SetTextCurrentDefaults(aString);
+ SfxItemSet aItemSet = rEngine.GetEmptyItemSet();
+ SvxWeightItem aWeight(WEIGHT_BOLD, EE_CHAR_WEIGHT);
+ aItemSet.Put(aWeight);
+ rEngine.QuickSetAttribs(aItemSet, ESelection(0, 0, 0, aString.getLength()) );
+ std::unique_ptr<EditTextObject> pEditText(rEngine.CreateTextObject());
+ mpDocShell->GetDocFunc().SetEditCell(mCurrentAddress, *pEditText, true);
+}
+
+void AddressWalkerWriter::writeValue(double aValue)
+{
+ mpDocShell->GetDocFunc().SetValueCell(mCurrentAddress, aValue, true);
+}
+
+// DataCellIterator
+
+DataCellIterator::DataCellIterator(const ScRange& aInputRange, bool aByColumn)
+ : mInputRange(aInputRange)
+ , mByColumn(aByColumn)
+ , mCol(0)
+ , mRow(0)
+{
+ if(aByColumn)
+ mCol = aInputRange.aStart.Col();
+ else
+ mRow = aInputRange.aStart.Row();
+}
+
+bool DataCellIterator::hasNext() const
+{
+ if(mByColumn)
+ return mCol <= mInputRange.aEnd.Col();
+ else
+ return mRow <= mInputRange.aEnd.Row();
+}
+
+void DataCellIterator::next()
+{
+ if(mByColumn)
+ mCol++;
+ else
+ mRow++;
+}
+
+ScAddress DataCellIterator::get()
+{
+ return getRelative(0);
+}
+
+ScAddress DataCellIterator::getRelative(int aDelta)
+{
+ if(mByColumn)
+ {
+ SCCOL aNewColumn = mCol + aDelta;
+ if(aNewColumn < mInputRange.aStart.Col() || aNewColumn > mInputRange.aEnd.Col())
+ {
+ ScAddress aResult;
+ aResult.SetInvalid();
+ return aResult;
+ }
+ return ScAddress(aNewColumn, mInputRange.aStart.Row(), mInputRange.aStart.Tab());
+ }
+ else
+ {
+ SCROW aNewRow = mRow + aDelta;
+ if(aNewRow < mInputRange.aStart.Row() || aNewRow > mInputRange.aEnd.Row())
+ {
+ ScAddress aResult;
+ aResult.SetInvalid();
+ return aResult;
+ }
+ return ScAddress(mInputRange.aStart.Col(), aNewRow, mInputRange.aStart.Tab());
+ }
+}
+
+// DataRangeIterator
+
+DataRangeIterator::DataRangeIterator(const ScRange& aInputRange) :
+ mInputRange(aInputRange),
+ mIndex(0)
+{}
+
+DataRangeIterator::~DataRangeIterator()
+{}
+
+sal_Int32 DataRangeIterator::index()
+{
+ return mIndex;
+}
+
+// DataRangeByColumnIterator
+
+DataRangeByColumnIterator::DataRangeByColumnIterator(const ScRange& aInputRange)
+ : DataRangeIterator(aInputRange)
+ , mCol(aInputRange.aStart.Col())
+{}
+
+bool DataRangeByColumnIterator::hasNext()
+{
+ return mCol <= mInputRange.aEnd.Col();
+}
+
+void DataRangeByColumnIterator::next()
+{
+ mCol++;
+ mIndex++;
+}
+
+ScRange DataRangeByColumnIterator::get()
+{
+ return ScRange(
+ ScAddress(mCol, mInputRange.aStart.Row(), mInputRange.aStart.Tab()),
+ ScAddress(mCol, mInputRange.aEnd.Row(), mInputRange.aEnd.Tab())
+ );
+}
+
+size_t DataRangeByColumnIterator::size()
+{
+ return mInputRange.aEnd.Row() - mInputRange.aStart.Row() + 1;
+}
+
+void DataRangeByColumnIterator::reset()
+{
+ mCol = mInputRange.aStart.Col();
+}
+
+DataCellIterator DataRangeByColumnIterator::iterateCells()
+{
+ return DataCellIterator(get(), false);
+}
+
+// DataRangeByRowIterator
+
+DataRangeByRowIterator::DataRangeByRowIterator(const ScRange& aInputRange)
+ : DataRangeIterator(aInputRange)
+ , mRow(aInputRange.aStart.Row())
+{}
+
+bool DataRangeByRowIterator::hasNext()
+{
+ return mRow <= mInputRange.aEnd.Row();
+}
+
+void DataRangeByRowIterator::next()
+{
+ mRow++;
+ mIndex++;
+}
+
+ScRange DataRangeByRowIterator::get()
+{
+ return ScRange(
+ ScAddress(mInputRange.aStart.Col(), mRow, mInputRange.aStart.Tab()),
+ ScAddress(mInputRange.aEnd.Col(), mRow, mInputRange.aEnd.Tab())
+ );
+}
+
+size_t DataRangeByRowIterator::size()
+{
+ return mInputRange.aEnd.Col() - mInputRange.aStart.Col() + 1;
+}
+
+void DataRangeByRowIterator::reset()
+{
+ mRow = mInputRange.aStart.Row();
+}
+
+DataCellIterator DataRangeByRowIterator::iterateCells()
+{
+ return DataCellIterator(get(), true);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/StatisticsDialogs/ZTestDialog.cxx b/sc/source/ui/StatisticsDialogs/ZTestDialog.cxx
new file mode 100644
index 000000000..a1731fa8f
--- /dev/null
+++ b/sc/source/ui/StatisticsDialogs/ZTestDialog.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/.
+ *
+ */
+
+#include <memory>
+
+#include <reffact.hxx>
+#include <TableFillingAndNavigationTools.hxx>
+#include <ZTestDialog.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+ScZTestDialog::ScZTestDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData ) :
+ ScStatisticsTwoVariableDialog(
+ pSfxBindings, pChildWindow, pParent, rViewData,
+ "modules/scalc/ui/ztestdialog.ui", "ZTestDialog")
+{
+ m_xDialog->set_title(ScResId(STR_ZTEST));
+}
+
+ScZTestDialog::~ScZTestDialog()
+{}
+
+void ScZTestDialog::Close()
+{
+ DoClose( ScZTestDialogWrapper::GetChildWindowId() );
+}
+
+TranslateId ScZTestDialog::GetUndoNameId()
+{
+ return STR_ZTEST_UNDO_NAME;
+}
+
+ScRange ScZTestDialog::ApplyOutput(ScDocShell* pDocShell)
+{
+ AddressWalkerWriter aOutput(mOutputAddress, pDocShell, mDocument,
+ formula::FormulaGrammar::mergeToGrammar( formula::FormulaGrammar::GRAM_ENGLISH, mAddressDetails.eConv));
+ FormulaTemplate aTemplate(&mDocument);
+
+ std::unique_ptr<DataRangeIterator> pVariable1Iterator;
+ if (mGroupedBy == BY_COLUMN)
+ pVariable1Iterator.reset(new DataRangeByColumnIterator(mVariable1Range));
+ else
+ pVariable1Iterator.reset(new DataRangeByRowIterator(mVariable1Range));
+
+ std::unique_ptr<DataRangeIterator> pVariable2Iterator;
+ if (mGroupedBy == BY_COLUMN)
+ pVariable2Iterator.reset(new DataRangeByColumnIterator(mVariable2Range));
+ else
+ pVariable2Iterator.reset(new DataRangeByRowIterator(mVariable2Range));
+
+ aTemplate.autoReplaceRange("%VARIABLE1_RANGE%", pVariable1Iterator->get());
+ aTemplate.autoReplaceRange("%VARIABLE2_RANGE%", pVariable2Iterator->get());
+
+ aOutput.writeBoldString(ScResId(STR_ZTEST));
+ aOutput.newLine();
+
+ // Alpha
+ aOutput.writeString(ScResId(STR_LABEL_ALPHA));
+ aOutput.nextColumn();
+ aOutput.writeValue(0.05);
+ aTemplate.autoReplaceAddress("%ALPHA%", aOutput.current());
+ aOutput.newLine();
+
+ // Hypothesized mean difference
+ aOutput.writeString(ScResId(STR_HYPOTHESIZED_MEAN_DIFFERENCE_LABEL));
+ aOutput.nextColumn();
+ aOutput.writeValue(0);
+ aTemplate.autoReplaceAddress("%HYPOTHESIZED_MEAN_DIFFERENCE%", aOutput.current());
+ aOutput.newLine();
+
+ // Variable Label
+ aOutput.nextColumn();
+ aOutput.writeBoldString(ScResId(STR_VARIABLE_1_LABEL));
+ aOutput.nextColumn();
+ aOutput.writeBoldString(ScResId(STR_VARIABLE_2_LABEL));
+ aOutput.newLine();
+
+ // Known Variance
+ aOutput.writeString(ScResId(STR_ZTEST_KNOWN_VARIANCE));
+ aOutput.nextColumn();
+ aOutput.writeValue(0);
+ aTemplate.autoReplaceAddress("%KNOWN_VARIANCE_VARIABLE1%", aOutput.current());
+ aOutput.nextColumn();
+ aOutput.writeValue(0);
+ aTemplate.autoReplaceAddress("%KNOWN_VARIANCE_VARIABLE2%", aOutput.current());
+ aOutput.newLine();
+
+ // Mean
+ aOutput.writeString(ScResId(STRID_CALC_MEAN));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=AVERAGE(%VARIABLE1_RANGE%)");
+ aTemplate.autoReplaceAddress("%MEAN_VARIABLE1%", aOutput.current());
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=AVERAGE(%VARIABLE2_RANGE%)");
+ aTemplate.autoReplaceAddress("%MEAN_VARIABLE2%", aOutput.current());
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // Observations
+ aOutput.writeString(ScResId(STR_OBSERVATIONS_LABEL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=COUNT(%VARIABLE1_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%OBSERVATION_VARIABLE1%", aOutput.current());
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=COUNT(%VARIABLE2_RANGE%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%OBSERVATION_VARIABLE2%", aOutput.current());
+ aOutput.newLine();
+
+ // Observed mean difference
+ aOutput.writeString(ScResId(STR_OBSERVED_MEAN_DIFFERENCE_LABEL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=%MEAN_VARIABLE1% - %MEAN_VARIABLE2%");
+ aOutput.writeMatrixFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%OBSERVED_MEAN_DIFFERENCE%", aOutput.current());
+ aOutput.newLine();
+
+ // z
+ aOutput.writeString(ScResId(STR_ZTEST_Z_VALUE));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=(%OBSERVED_MEAN_DIFFERENCE% - %HYPOTHESIZED_MEAN_DIFFERENCE%) / SQRT( %KNOWN_VARIANCE_VARIABLE1% / %OBSERVATION_VARIABLE1% + %KNOWN_VARIANCE_VARIABLE2% / %OBSERVATION_VARIABLE2% )");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aTemplate.autoReplaceAddress("%Z_STAT%", aOutput.current());
+ aOutput.newLine();
+
+ // P one-tail
+ aOutput.writeString(ScResId(STR_ZTEST_P_ONE_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=1 - NORMSDIST(ABS(%Z_STAT%))");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // z critical one-tail
+ aOutput.writeString(ScResId(STR_ZTEST_Z_CRITICAL_ONE_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=-NORMSINV(%ALPHA%)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // P two-tail
+ aOutput.writeString(ScResId(STR_ZTEST_P_TWO_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=2 * NORMSDIST(-ABS(%Z_STAT%))");
+ aOutput.writeFormula(aTemplate.getTemplate());
+ aOutput.newLine();
+
+ // z critical two-tail
+ aOutput.writeString(ScResId(STR_ZTEST_Z_CRITICAL_TWO_TAIL));
+ aOutput.nextColumn();
+ aTemplate.setTemplate("=-NORMSINV(%ALPHA%/2)");
+ aOutput.writeFormula(aTemplate.getTemplate());
+
+ return ScRange(aOutput.mMinimumAddress, aOutput.mMaximumAddress);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/client.cxx b/sc/source/ui/app/client.cxx
new file mode 100644
index 000000000..0886fae89
--- /dev/null
+++ b/sc/source/ui/app/client.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 <com/sun/star/embed/XEmbeddedObject.hpp>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <sfx2/objsh.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdoole2.hxx>
+
+#include <client.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <gridwin.hxx>
+
+using namespace com::sun::star;
+
+ScClient::ScClient( ScTabViewShell* pViewShell, vcl::Window* pDraw, SdrModel* pSdrModel, const SdrOle2Obj* pObj ) :
+ SfxInPlaceClient( pViewShell, pDraw, pObj->GetAspect() ),
+ pModel( pSdrModel )
+{
+ SetObject( pObj->GetObjRef() );
+}
+
+ScClient::~ScClient()
+{
+}
+
+SdrOle2Obj* ScClient::GetDrawObj()
+{
+ uno::Reference < embed::XEmbeddedObject > xObj = GetObject();
+ SdrOle2Obj* pOle2Obj = nullptr;
+ OUString aName = GetViewShell()->GetObjectShell()->GetEmbeddedObjectContainer().GetEmbeddedObjectName( xObj );
+
+ sal_uInt16 nPages = pModel->GetPageCount();
+ for (sal_uInt16 nPNr=0; nPNr<nPages && !pOle2Obj; nPNr++)
+ {
+ SdrPage* pPage = pModel->GetPage(nPNr);
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !pOle2Obj)
+ {
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 )
+ {
+ // name from InfoObject is PersistName
+ if ( static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == aName )
+ pOle2Obj = static_cast<SdrOle2Obj*>(pObject);
+ }
+ pObject = aIter.Next();
+ }
+ }
+ return pOle2Obj;
+}
+
+void ScClient::RequestNewObjectArea( tools::Rectangle& aLogicRect )
+{
+ SfxViewShell* pSfxViewSh = GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( pSfxViewSh );
+ if (!pViewSh)
+ {
+ OSL_FAIL("Wrong ViewShell");
+ return;
+ }
+
+ tools::Rectangle aOldRect = GetObjArea();
+ SdrOle2Obj* pDrawObj = GetDrawObj();
+ if ( pDrawObj )
+ {
+ if ( pDrawObj->IsResizeProtect() )
+ aLogicRect.SetSize( aOldRect.GetSize() );
+
+ if ( pDrawObj->IsMoveProtect() )
+ aLogicRect.SetPos( aOldRect.TopLeft() );
+ }
+
+ sal_uInt16 nTab = pViewSh->GetViewData().GetTabNo();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(static_cast<sal_Int16>(nTab)));
+ if ( !(pPage && aLogicRect != aOldRect) )
+ return;
+
+ Point aPos;
+ Size aSize = pPage->GetSize();
+ if ( aSize.Width() < 0 )
+ {
+ aPos.setX( aSize.Width() + 1 ); // negative
+ aSize.setWidth( -aSize.Width() ); // positive
+ }
+ tools::Rectangle aPageRect( aPos, aSize );
+
+ if (aLogicRect.Right() > aPageRect.Right())
+ {
+ tools::Long nDiff = aLogicRect.Right() - aPageRect.Right();
+ aLogicRect.AdjustLeft( -nDiff );
+ aLogicRect.AdjustRight( -nDiff );
+ }
+ if (aLogicRect.Bottom() > aPageRect.Bottom())
+ {
+ tools::Long nDiff = aLogicRect.Bottom() - aPageRect.Bottom();
+ aLogicRect.AdjustTop( -nDiff );
+ aLogicRect.AdjustBottom( -nDiff );
+ }
+
+ if (aLogicRect.Left() < aPageRect.Left())
+ {
+ tools::Long nDiff = aLogicRect.Left() - aPageRect.Left();
+ aLogicRect.AdjustRight( -nDiff );
+ aLogicRect.AdjustLeft( -nDiff );
+ }
+ if (aLogicRect.Top() < aPageRect.Top())
+ {
+ tools::Long nDiff = aLogicRect.Top() - aPageRect.Top();
+ aLogicRect.AdjustBottom( -nDiff );
+ aLogicRect.AdjustTop( -nDiff );
+ }
+}
+
+void ScClient::ObjectAreaChanged()
+{
+ SfxViewShell* pSfxViewSh = GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( pSfxViewSh );
+ if (!pViewSh)
+ {
+ OSL_FAIL("Wrong ViewShell");
+ return;
+ }
+
+ // Take over position and size into document
+ SdrOle2Obj* pDrawObj = GetDrawObj();
+ if (!pDrawObj)
+ return;
+
+ tools::Rectangle aNewRectangle(GetScaledObjArea());
+
+ // #i118524# if sheared/rotated, center to non-rotated LogicRect
+ pDrawObj->setSuppressSetVisAreaSize(true);
+
+ if(pDrawObj->GetGeoStat().nRotationAngle || pDrawObj->GetGeoStat().nShearAngle)
+ {
+ pDrawObj->SetLogicRect( aNewRectangle );
+
+ const tools::Rectangle& rBoundRect = pDrawObj->GetCurrentBoundRect();
+ const Point aDelta(aNewRectangle.Center() - rBoundRect.Center());
+
+ aNewRectangle.Move(aDelta.X(), aDelta.Y());
+ }
+
+ pDrawObj->SetLogicRect( aNewRectangle );
+ pDrawObj->setSuppressSetVisAreaSize(false);
+
+ // set document modified (SdrModel::SetChanged is not used)
+ pViewSh->GetViewData().GetDocShell()->SetDrawModified();
+ pViewSh->ScrollToObject(pDrawObj);
+}
+
+void ScClient::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
+
+ return;
+ }
+
+ uno::Reference < embed::XEmbeddedObject > xObj = GetObject();
+
+ // TODO/LEAN: working with Visual Area can switch object to running state
+ awt::Size aSz;
+ try {
+ aSz = xObj->getVisualAreaSize( GetAspect() );
+ } catch (const uno::Exception&) {
+ TOOLS_WARN_EXCEPTION("sc", "The visual area size must be available!");
+ return; // leave it unchanged on failure
+ }
+
+ MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( GetAspect() ) );
+ Size aVisSize = OutputDevice::LogicToLogic(Size(aSz.Width, aSz.Height), MapMode(aMapUnit), MapMode(MapUnit::Map100thMM));
+
+ // Take over position and size into document
+ SdrOle2Obj* pDrawObj = GetDrawObj();
+ if (!pDrawObj)
+ return;
+
+ tools::Rectangle aLogicRect = pDrawObj->GetLogicRect();
+ Fraction aFractX = GetScaleWidth() * aVisSize.Width();
+ Fraction aFractY = GetScaleHeight() * aVisSize.Height();
+ aVisSize = Size( static_cast<tools::Long>(aFractX), static_cast<tools::Long>(aFractY) ); // Scaled for Draw model
+
+ // pClientData->SetObjArea before pDrawObj->SetLogicRect, so that we don't
+ // calculate wrong scalings:
+ //Rectangle aObjArea = aLogicRect;
+ //aObjArea.SetSize( aVisSize ); // Document size from the server
+ //SetObjArea( aObjArea );
+
+ SfxViewShell* pSfxViewSh = GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( pSfxViewSh );
+ if ( pViewSh )
+ {
+ vcl::Window* pWin = pViewSh->GetActiveWin();
+ if ( pWin->LogicToPixel( aVisSize ) != pWin->LogicToPixel( aLogicRect.GetSize() ) )
+ {
+ aLogicRect.SetSize( aVisSize );
+ pDrawObj->SetLogicRect( aLogicRect );
+
+ // set document modified (SdrModel::SetChanged is not used)
+ pViewSh->GetViewData().GetDocShell()->SetDrawModified();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/drwtrans.cxx b/sc/source/ui/app/drwtrans.cxx
new file mode 100644
index 000000000..8cd335b2e
--- /dev/null
+++ b/sc/source/ui/app/drwtrans.cxx
@@ -0,0 +1,738 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/XTransactedObject.hpp>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/uno/Exception.hpp>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <unotools/streamwrap.hxx>
+
+#include <svx/unomodel.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/servicehelper.hxx>
+
+#include <svtools/embedtransfer.hxx>
+#include <sot/storage.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdouno.hxx>
+#include <sfx2/docfile.hxx>
+#include <svl/itempool.hxx>
+#include <svl/urlbmk.hxx>
+#include <tools/urlobj.hxx>
+#include <osl/diagnose.h>
+
+#include <drwtrans.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <drawview.hxx>
+#include <viewdata.hxx>
+#include <scmod.hxx>
+#include <dragdata.hxx>
+
+#include <editeng/eeitem.hxx>
+
+#include <editeng/fhgtitem.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace com::sun::star;
+
+constexpr sal_uInt32 SCDRAWTRANS_TYPE_EMBOBJ = 1;
+constexpr sal_uInt32 SCDRAWTRANS_TYPE_DRAWMODEL = 2;
+constexpr sal_uInt32 SCDRAWTRANS_TYPE_DOCUMENT = 3;
+
+ScDrawTransferObj::ScDrawTransferObj( std::unique_ptr<SdrModel> pClipModel, ScDocShell* pContainerShell,
+ const TransferableObjectDescriptor& rDesc ) :
+ m_pModel( std::move(pClipModel) ),
+ m_aObjDesc( rDesc ),
+ m_bGraphic( false ),
+ m_bGrIsBit( false ),
+ m_bOleObj( false ),
+ m_nDragSourceFlags( ScDragSrc::Undefined ),
+ m_bDragWasInternal( false ),
+ maShellID(SfxObjectShell::CreateShellID(pContainerShell))
+{
+
+ // check what kind of objects are contained
+
+ SdrPage* pPage = m_pModel->GetPage(0);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::Flat );
+ SdrObject* pObject = aIter.Next();
+ if (pObject && !aIter.Next()) // exactly one object?
+ {
+
+ // OLE object
+
+ SdrObjKind nSdrObjKind = pObject->GetObjIdentifier();
+ if (nSdrObjKind == SdrObjKind::OLE2)
+ {
+ // if object has no persistence it must be copied as a part of document
+ try
+ {
+ uno::Reference< embed::XEmbedPersist > xPersObj( static_cast<SdrOle2Obj*>(pObject)->GetObjRef(), uno::UNO_QUERY );
+ if ( xPersObj.is() && xPersObj->hasEntry() )
+ m_bOleObj = true;
+ }
+ catch( uno::Exception& )
+ {}
+ // aOleData is initialized later
+ }
+
+ // Graphic object
+
+ if (nSdrObjKind == SdrObjKind::Graphic)
+ {
+ m_bGraphic = true;
+ if ( static_cast<SdrGrafObj*>(pObject)->GetGraphic().GetType() == GraphicType::Bitmap )
+ m_bGrIsBit = true;
+ }
+
+ // URL button
+
+ SdrUnoObj* pUnoCtrl = dynamic_cast<SdrUnoObj*>( pObject );
+ if (pUnoCtrl && SdrInventor::FmForm == pUnoCtrl->GetObjInventor())
+ {
+ const uno::Reference<awt::XControlModel>& xControlModel = pUnoCtrl->GetUnoControlModel();
+ OSL_ENSURE( xControlModel.is(), "uno control without model" );
+ if ( xControlModel.is() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySetInfo > xInfo = xPropSet->getPropertySetInfo();
+
+ OUString sPropButtonType( "ButtonType" );
+
+ if(xInfo->hasPropertyByName( sPropButtonType ))
+ {
+ uno::Any aAny = xPropSet->getPropertyValue( sPropButtonType );
+ form::FormButtonType eTmp;
+ if ( (aAny >>= eTmp) && eTmp == form::FormButtonType_URL )
+ {
+ // URL
+ OUString sPropTargetURL( "TargetURL" );
+ if(xInfo->hasPropertyByName( sPropTargetURL ))
+ {
+ aAny = xPropSet->getPropertyValue( sPropTargetURL );
+ OUString sTmp;
+ if ( (aAny >>= sTmp) && !sTmp.isEmpty() )
+ {
+ OUString aUrl = sTmp;
+ OUString aAbs = aUrl;
+ if (pContainerShell)
+ {
+ const SfxMedium* pMedium = pContainerShell->GetMedium();
+ if (pMedium)
+ {
+ bool bWasAbs = true;
+ aAbs = pMedium->GetURLObject().smartRel2Abs( aUrl, bWasAbs ).
+ GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ // full path as stored INetBookmark must be encoded
+ }
+ }
+
+ // Label
+ OUString aLabel;
+ OUString sPropLabel( "Label" );
+ if(xInfo->hasPropertyByName( sPropLabel ))
+ {
+ aAny = xPropSet->getPropertyValue( sPropLabel );
+ if ( (aAny >>= sTmp) && !sTmp.isEmpty() )
+ {
+ aLabel = sTmp;
+ }
+ }
+ m_pBookmark.reset( new INetBookmark( aAbs, aLabel ) );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // get size for object descriptor
+
+ // #i71538# use complete SdrViews
+ // SdrExchangeView aView(pModel);
+ SdrView aView(*m_pModel);
+ SdrPageView* pPv = aView.ShowSdrPage(aView.GetModel()->GetPage(0));
+ aView.MarkAllObj(pPv);
+ m_aSrcSize = aView.GetAllMarkedRect().GetSize();
+
+ if ( m_bOleObj ) // single OLE object
+ {
+ SdrOle2Obj* pObj = GetSingleObject();
+ if ( pObj && pObj->GetObjRef().is() )
+ SvEmbedTransferHelper::FillTransferableObjectDescriptor( m_aObjDesc, pObj->GetObjRef(), pObj->GetGraphic(), pObj->GetAspect() );
+ }
+
+ m_aObjDesc.maSize = m_aSrcSize;
+ PrepareOLE( m_aObjDesc );
+
+ // remember a unique ID of the source document
+
+ if ( pContainerShell )
+ {
+ ScDocument& rDoc = pContainerShell->GetDocument();
+ if ( pPage )
+ {
+ ScChartHelper::FillProtectedChartRangesVector( m_aProtectedChartRangesVector, rDoc, pPage );
+ }
+ }
+}
+
+ScDrawTransferObj::~ScDrawTransferObj()
+{
+ SolarMutexGuard aSolarGuard;
+
+ ScModule* pScMod = SC_MOD();
+ if (pScMod && pScMod->GetDragData().pDrawTransfer == this)
+ {
+ OSL_FAIL("ScDrawTransferObj wasn't released");
+ pScMod->ResetDragObject();
+ }
+
+ m_aOleData = TransferableDataHelper(); // clear before releasing the mutex
+ m_aDocShellRef.clear();
+
+ m_pModel.reset();
+ m_aDrawPersistRef.clear(); // after the model
+
+ m_pBookmark.reset();
+ m_pDragSourceView.reset();
+}
+
+ScDrawTransferObj* ScDrawTransferObj::GetOwnClipboard(const uno::Reference<datatransfer::XTransferable2>& xTransferable)
+{
+ return comphelper::getFromUnoTunnel<ScDrawTransferObj>(xTransferable);
+}
+
+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;
+}
+
+void ScDrawTransferObj::AddSupportedFormats()
+{
+ if ( m_bGrIsBit ) // single bitmap graphic
+ {
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SVXB );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ }
+ else if ( m_bGraphic ) // other graphic
+ {
+ // #i25616#
+ AddFormat( SotClipboardFormatId::DRAWING );
+
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SVXB );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ }
+ else if ( m_pBookmark ) // url button
+ {
+// AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SOLK );
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
+ AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
+ AddFormat( SotClipboardFormatId::DRAWING );
+ }
+ else if ( m_bOleObj ) // single OLE object
+ {
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+
+ CreateOLEData();
+
+ if ( m_aOleData.GetTransferable().is() )
+ {
+ // get format list from object snapshot
+ // (this must be after inserting the default formats!)
+
+ DataFlavorExVector aVector( m_aOleData.GetDataFlavorExVector() );
+
+ for( const auto& rItem : aVector )
+ AddFormat( rItem );
+ }
+ }
+ else // any drawing objects
+ {
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::DRAWING );
+
+ // leave out bitmap and metafile if there are only controls
+ if ( !lcl_HasOnlyControls( m_pModel.get() ) )
+ {
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ }
+ }
+
+// if( pImageMap )
+// AddFormat( SotClipboardFormatId::SVIM );
+}
+
+bool ScDrawTransferObj::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc )
+{
+ bool bOK = false;
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+
+ if ( m_bOleObj && nFormat != SotClipboardFormatId::GDIMETAFILE )
+ {
+ CreateOLEData();
+
+ if( m_aOleData.GetTransferable().is() && m_aOleData.HasFormat( rFlavor ) )
+ {
+ bOK = SetAny( m_aOleData.GetAny(rFlavor, rDestDoc) );
+
+ return bOK;
+ }
+ }
+
+ if( HasFormat( nFormat ) )
+ {
+ if ( nFormat == SotClipboardFormatId::LINKSRCDESCRIPTOR || nFormat == SotClipboardFormatId::OBJECTDESCRIPTOR )
+ {
+ bOK = SetTransferableObjectDescriptor( m_aObjDesc );
+ }
+ else if ( nFormat == SotClipboardFormatId::DRAWING )
+ {
+ bOK = SetObject( m_pModel.get(), SCDRAWTRANS_TYPE_DRAWMODEL, rFlavor );
+ }
+ else if ( nFormat == SotClipboardFormatId::BITMAP
+ || nFormat == SotClipboardFormatId::PNG
+ || nFormat == SotClipboardFormatId::GDIMETAFILE )
+ {
+ // #i71538# use complete SdrViews
+ // SdrExchangeView aView( pModel );
+ SdrView aView(*m_pModel);
+ SdrPageView* pPv = aView.ShowSdrPage(aView.GetModel()->GetPage(0));
+ OSL_ENSURE( pPv, "pPv not there..." );
+ aView.MarkAllObj( pPv );
+ if ( nFormat == SotClipboardFormatId::GDIMETAFILE )
+ bOK = SetGDIMetaFile( aView.GetMarkedObjMetaFile(true) );
+ else
+ bOK = SetBitmapEx( aView.GetMarkedObjBitmapEx(true), rFlavor );
+ }
+ else if ( nFormat == SotClipboardFormatId::SVXB )
+ {
+ // only enabled for single graphics object
+
+ SdrPage* pPage = m_pModel->GetPage(0);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::Flat );
+ SdrObject* pObject = aIter.Next();
+ if (pObject && pObject->GetObjIdentifier() == SdrObjKind::Graphic)
+ {
+ SdrGrafObj* pGraphObj = static_cast<SdrGrafObj*>(pObject);
+ bOK = SetGraphic( pGraphObj->GetGraphic() );
+ }
+ }
+ }
+ else if ( nFormat == SotClipboardFormatId::EMBED_SOURCE )
+ {
+ if ( m_bOleObj ) // single OLE object
+ {
+ SdrOle2Obj* pObj = GetSingleObject();
+ if ( pObj && pObj->GetObjRef().is() )
+ {
+ bOK = SetObject( pObj->GetObjRef().get(), SCDRAWTRANS_TYPE_EMBOBJ, rFlavor );
+ }
+ }
+ else // create object from contents
+ {
+ //TODO/LATER: needs new Format, because now single OLE and "this" are different
+ InitDocShell(); // set aDocShellRef
+
+ SfxObjectShell* pEmbObj = m_aDocShellRef.get();
+ bOK = SetObject( pEmbObj, SCDRAWTRANS_TYPE_DOCUMENT, rFlavor );
+ }
+ }
+ else if( m_pBookmark )
+ {
+ bOK = SetINetBookmark( *m_pBookmark, rFlavor );
+ }
+ }
+ return bOK;
+}
+
+bool ScDrawTransferObj::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId,
+ const css::datatransfer::DataFlavor& /* rFlavor */ )
+{
+ // called from SetObject, put data into stream
+
+ bool bRet = false;
+ switch (nUserObjectId)
+ {
+ case SCDRAWTRANS_TYPE_DRAWMODEL:
+ {
+ SdrModel* pDrawModel = static_cast<SdrModel*>(pUserObject);
+ rxOStm->SetBufferSize( 0xff00 );
+
+ // for the changed pool defaults from drawing layer pool set those
+ // attributes as hard attributes to preserve them for saving
+ const SfxItemPool& rItemPool = m_pModel->GetItemPool();
+ const SvxFontHeightItem& rDefaultFontHeight = rItemPool.GetDefaultItem(EE_CHAR_FONTHEIGHT);
+
+ // SW should have no MasterPages
+ OSL_ENSURE(0 == m_pModel->GetMasterPageCount(), "SW with MasterPages (!)");
+
+ for(sal_uInt16 a(0); a < m_pModel->GetPageCount(); a++)
+ {
+ const SdrPage* pPage(m_pModel->GetPage(a));
+ SdrObjListIter aIter(pPage, SdrIterMode::DeepNoGroups);
+
+ while(aIter.IsMore())
+ {
+ SdrObject* pObj = aIter.Next();
+ const SvxFontHeightItem& rItem = pObj->GetMergedItem(EE_CHAR_FONTHEIGHT);
+
+ if(rItem.GetHeight() == rDefaultFontHeight.GetHeight())
+ {
+ pObj->SetMergedItem(rDefaultFontHeight);
+ }
+ }
+ }
+
+ {
+ css::uno::Reference<css::io::XOutputStream> xDocOut( new utl::OOutputStreamWrapper( *rxOStm ) );
+ SvxDrawingLayerExport( pDrawModel, xDocOut );
+ }
+
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ break;
+
+ case SCDRAWTRANS_TYPE_EMBOBJ:
+ {
+ // impl. for "single OLE"
+ embed::XEmbeddedObject* pEmbObj = static_cast<embed::XEmbeddedObject*>(pUserObject);
+
+ ::utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ uno::Reference< embed::XStorage > xWorkStore =
+ ::comphelper::OStorageHelper::GetStorageFromURL( aTempFile.GetURL(), embed::ElementModes::READWRITE );
+
+ uno::Reference < embed::XEmbedPersist > xPers( static_cast<embed::XVisualObject*>(pEmbObj), uno::UNO_QUERY );
+ if ( xPers.is() )
+ {
+ try
+ {
+ uno::Sequence < beans::PropertyValue > aSeq;
+ OUString aDummyName("Dummy");
+ xPers->storeToEntry( xWorkStore, aDummyName, aSeq, aSeq );
+ if ( xWorkStore->isStreamElement( aDummyName ) )
+ {
+ uno::Reference < io::XOutputStream > xDocOut( new utl::OOutputStreamWrapper( *rxOStm ) );
+ uno::Reference < io::XStream > xNewStream = xWorkStore->openStreamElement( aDummyName, embed::ElementModes::READ );
+ ::comphelper::OStorageHelper::CopyInputToOutput( xNewStream->getInputStream(), xDocOut );
+ }
+ else
+ {
+ uno::Reference < io::XStream > xDocStr( new utl::OStreamWrapper( *rxOStm ) );
+ uno::Reference< embed::XStorage > xDocStg = ::comphelper::OStorageHelper::GetStorageFromStream( xDocStr );
+ uno::Reference < embed::XStorage > xNewStg = xWorkStore->openStorageElement( aDummyName, embed::ElementModes::READ );
+ xNewStg->copyToStorage( xDocStg );
+ uno::Reference < embed::XTransactedObject > xTrans( xDocStg, uno::UNO_QUERY );
+ if ( xTrans.is() )
+ xTrans->commit();
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+
+ break;
+ }
+ case SCDRAWTRANS_TYPE_DOCUMENT:
+ {
+ // impl. for "DocShell"
+ SfxObjectShell* pEmbObj = static_cast<SfxObjectShell*>(pUserObject);
+
+ try
+ {
+ ::utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ 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();
+ }
+
+ xWorkStore->dispose();
+ xWorkStore.clear();
+ }
+ catch ( uno::Exception& )
+ {}
+
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ break;
+
+ default:
+ OSL_FAIL("unknown object id");
+ }
+ return bRet;
+}
+
+void ScDrawTransferObj::DragFinished( sal_Int8 nDropAction )
+{
+ if ( nDropAction == DND_ACTION_MOVE && !m_bDragWasInternal && !(m_nDragSourceFlags & ScDragSrc::Navigator) )
+ {
+ // move: delete source objects
+
+ if ( m_pDragSourceView )
+ m_pDragSourceView->DeleteMarked();
+ }
+
+ ScModule* pScMod = SC_MOD();
+ if ( pScMod->GetDragData().pDrawTransfer == this )
+ pScMod->ResetDragObject();
+
+ m_pDragSourceView.reset();
+
+ TransferDataContainer::DragFinished( nDropAction );
+}
+
+void ScDrawTransferObj::SetDrawPersist( const SfxObjectShellRef& rRef )
+{
+ m_aDrawPersistRef = rRef;
+}
+
+static void lcl_InitMarks( SdrMarkView& rDest, const SdrMarkView& rSource, SCTAB nTab )
+{
+ rDest.ShowSdrPage(rDest.GetModel()->GetPage(nTab));
+ SdrPageView* pDestPV = rDest.GetSdrPageView();
+ OSL_ENSURE(pDestPV,"PageView ?");
+
+ const SdrMarkList& rMarkList = rSource.GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ SdrMark* pMark = rMarkList.GetMark(i);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ rDest.MarkObj(pObj, pDestPV);
+ }
+}
+
+void ScDrawTransferObj::SetDragSource( const ScDrawView* pView )
+{
+ m_pDragSourceView.reset(new SdrView(pView->getSdrModelFromSdrView())); // TTTT pView should be reference
+ lcl_InitMarks( *m_pDragSourceView, *pView, pView->GetTab() );
+
+ //! add as listener with document, delete pDragSourceView if document gone
+}
+
+void ScDrawTransferObj::SetDragSourceObj( SdrObject& rObj, SCTAB nTab )
+{
+ m_pDragSourceView.reset(new SdrView(rObj.getSdrModelFromSdrObject()));
+ m_pDragSourceView->ShowSdrPage(m_pDragSourceView->GetModel()->GetPage(nTab));
+ SdrPageView* pPV = m_pDragSourceView->GetSdrPageView();
+ m_pDragSourceView->MarkObj(&rObj, pPV); // TTTT MarkObj should take SdrObject&
+
+ //! add as listener with document, delete pDragSourceView if document gone
+}
+
+void ScDrawTransferObj::SetDragSourceFlags(ScDragSrc nFlags)
+{
+ m_nDragSourceFlags = nFlags;
+}
+
+void ScDrawTransferObj::SetDragWasInternal()
+{
+ m_bDragWasInternal = true;
+}
+
+const OUString& ScDrawTransferObj::GetShellID() const
+{
+ return maShellID;
+}
+
+SdrOle2Obj* ScDrawTransferObj::GetSingleObject()
+{
+ // if single OLE object was copied, get its object
+
+ SdrPage* pPage = m_pModel->GetPage(0);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::Flat );
+ SdrObject* pObject = aIter.Next();
+ if (pObject && pObject->GetObjIdentifier() == SdrObjKind::OLE2)
+ {
+ return static_cast<SdrOle2Obj*>(pObject);
+ }
+ }
+
+ return nullptr;
+}
+
+void ScDrawTransferObj::CreateOLEData()
+{
+ if (m_aOleData.GetTransferable().is())
+ // Already created.
+ return;
+
+ SdrOle2Obj* pObj = GetSingleObject();
+ if (!pObj || !pObj->GetObjRef().is())
+ // No OLE object present.
+ return;
+
+ rtl::Reference<SvEmbedTransferHelper> pEmbedTransfer =
+ new SvEmbedTransferHelper(
+ pObj->GetObjRef(), pObj->GetGraphic(), pObj->GetAspect());
+
+ pEmbedTransfer->SetParentShellID(maShellID);
+
+ m_aOleData = TransferableDataHelper(pEmbedTransfer);
+}
+
+// initialize aDocShellRef with a live document from the ClipDoc
+
+void ScDrawTransferObj::InitDocShell()
+{
+ if ( m_aDocShellRef.is() )
+ return;
+
+ ScDocShell* pDocSh = new ScDocShell;
+ m_aDocShellRef = pDocSh; // ref must be there before InitNew
+
+ pDocSh->DoInitNew();
+
+ ScDocument& rDestDoc = pDocSh->GetDocument();
+ rDestDoc.InitDrawLayer( pDocSh );
+
+ SdrModel* pDestModel = rDestDoc.GetDrawLayer();
+ // #i71538# use complete SdrViews
+ // SdrExchangeView aDestView( pDestModel );
+ SdrView aDestView(*pDestModel);
+ aDestView.ShowSdrPage(aDestView.GetModel()->GetPage(0));
+ aDestView.Paste(
+ *m_pModel,
+ Point(m_aSrcSize.Width()/2, m_aSrcSize.Height()/2),
+ nullptr, SdrInsertFlags::NONE);
+
+ // put objects to right layer (see ScViewFunc::PasteDataFormat for SotClipboardFormatId::DRAWING)
+
+ SdrPage* pPage = pDestModel->GetPage(0);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( dynamic_cast<const SdrUnoObj*>( pObject) != nullptr )
+ pObject->NbcSetLayer(SC_LAYER_CONTROLS);
+ else
+ pObject->NbcSetLayer(SC_LAYER_FRONT);
+ pObject = aIter.Next();
+ }
+ }
+
+ tools::Rectangle aDestArea( Point(), m_aSrcSize );
+ pDocSh->SetVisArea( aDestArea );
+
+ ScViewOptions aViewOpt( rDestDoc.GetViewOptions() );
+ aViewOpt.SetOption( VOPT_GRID, false );
+ rDestDoc.SetViewOptions( aViewOpt );
+
+ ScViewData aViewData( *pDocSh, nullptr );
+ aViewData.SetTabNo( 0 );
+ aViewData.SetScreen( aDestArea );
+ aViewData.SetCurX( 0 );
+ aViewData.SetCurY( 0 );
+ pDocSh->UpdateOle(aViewData, true);
+}
+
+const css::uno::Sequence< sal_Int8 >& ScDrawTransferObj::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theScDrawTransferObjUnoTunnelId;
+ return theScDrawTransferObjUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL ScDrawTransferObj::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(
+ rId, this, comphelper::FallbackToGetSomethingOf<TransferDataContainer>{});
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx
new file mode 100644
index 000000000..884e2e696
--- /dev/null
+++ b/sc/source/ui/app/inputhdl.cxx
@@ -0,0 +1,4635 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <iterator>
+#include <memory>
+#include <string_view>
+
+#include <inputhdl.hxx>
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <sfx2/app.hxx>
+#include <editeng/acorrcfg.hxx>
+#include <formula/errorcodes.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <svtools/colorcfg.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/svxacorr.hxx>
+#include <editeng/unolingu.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <editeng/misspellrange.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/printer.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/charclass.hxx>
+#include <vcl/help.hxx>
+#include <vcl/jsdialog/executor.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/urlobj.hxx>
+#include <formula/formulahelper.hxx>
+#include <formula/funcvarargs.h>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+
+#include <attrib.hxx>
+#include <inputwin.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <scmod.hxx>
+#include <formulaopt.hxx>
+#include <uiitems.hxx>
+#include <global.hxx>
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <patattr.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <docpool.hxx>
+#include <editutil.hxx>
+#include <appoptio.hxx>
+#include <docoptio.hxx>
+#include <validat.hxx>
+#include <rfindlst.hxx>
+#include <inputopt.hxx>
+#include <simpleformulacalc.hxx>
+#include <compiler.hxx>
+#include <editable.hxx>
+#include <funcdesc.hxx>
+#include <markdata.hxx>
+#include <tokenarray.hxx>
+#include <gridwin.hxx>
+#include <output.hxx>
+#include <fillinfo.hxx>
+
+// Maximum Ranges in RangeFinder
+#define RANGEFIND_MAX 128
+
+using namespace formula;
+
+namespace {
+
+ScTypedCaseStrSet::const_iterator findText(
+ const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator const & itPos,
+ const OUString& rStart, OUString& rResult, bool bBack)
+{
+ auto lIsMatch = [&rStart](const ScTypedStrData& rData) {
+ return (rData.GetStringType() != ScTypedStrData::Value) && ScGlobal::GetTransliteration().isMatch(rStart, rData.GetString()); };
+
+ if (bBack) // Backwards
+ {
+ ScTypedCaseStrSet::const_reverse_iterator it = rDataSet.rbegin(), itEnd = rDataSet.rend();
+ if (itPos != rDataSet.end())
+ {
+ size_t nPos = std::distance(rDataSet.begin(), itPos);
+ size_t nRPos = rDataSet.size() - 1 - nPos;
+ std::advance(it, nRPos);
+ ++it;
+ }
+
+ it = std::find_if(it, itEnd, lIsMatch);
+ if (it != itEnd)
+ {
+ rResult = it->GetString();
+ return (++it).base(); // convert the reverse iterator back to iterator.
+ }
+ }
+ else // Forwards
+ {
+ ScTypedCaseStrSet::const_iterator it = rDataSet.begin(), itEnd = rDataSet.end();
+ if (itPos != itEnd)
+ {
+ it = std::next(itPos);
+ }
+
+ it = std::find_if(it, itEnd, lIsMatch);
+ if (it != itEnd)
+ {
+ rResult = it->GetString();
+ return it;
+ }
+ }
+
+ return rDataSet.end(); // no matching text found
+}
+
+OUString getExactMatch(const ScTypedCaseStrSet& rDataSet, const OUString& rString)
+{
+ auto it = std::find_if(rDataSet.begin(), rDataSet.end(),
+ [&rString](const ScTypedStrData& rData) {
+ return (rData.GetStringType() != ScTypedStrData::Value)
+ && ScGlobal::GetTransliteration().isEqual(rData.GetString(), rString);
+ });
+ if (it != rDataSet.end())
+ return it->GetString();
+ return rString;
+}
+
+// This assumes that rResults is a sorted ring w.r.t ScTypedStrData::LessCaseInsensitive() or
+// in the reverse direction, whose origin is specified by nRingOrigin.
+sal_Int32 getLongestCommonPrefixLength(const std::vector<OUString>& rResults, const OUString& rUserEntry, sal_Int32 nRingOrigin)
+{
+ sal_Int32 nResults = rResults.size();
+ if (!nResults)
+ return 0;
+
+ if (nResults == 1)
+ return rResults[0].getLength();
+
+ sal_Int32 nMinLen = rUserEntry.getLength();
+ sal_Int32 nLastIdx = nRingOrigin ? nRingOrigin - 1 : nResults - 1;
+ const OUString& rFirst = rResults[nRingOrigin];
+ const OUString& rLast = rResults[nLastIdx];
+ const sal_Int32 nMaxLen = std::min(rFirst.getLength(), rLast.getLength());
+
+ for (sal_Int32 nLen = nMaxLen; nLen > nMinLen; --nLen)
+ {
+ if (ScGlobal::GetTransliteration().isMatch(rFirst.copy(0, nLen), rLast))
+ return nLen;
+ }
+
+ return nMinLen;
+}
+
+ScTypedCaseStrSet::const_iterator findTextAll(
+ const ScTypedCaseStrSet& rDataSet, ScTypedCaseStrSet::const_iterator const & itPos,
+ const OUString& rStart, ::std::vector< OUString > &rResultVec, bool bBack, sal_Int32* pLongestPrefixLen = nullptr)
+{
+ rResultVec.clear(); // clear contents
+
+ if (!rDataSet.size())
+ return rDataSet.end();
+
+ sal_Int32 nRingOrigin = 0;
+ size_t nCount = 0;
+ ScTypedCaseStrSet::const_iterator retit;
+ if ( bBack ) // Backwards
+ {
+ ScTypedCaseStrSet::const_reverse_iterator it, itEnd;
+ if ( itPos == rDataSet.end() )
+ {
+ it = rDataSet.rend();
+ --it;
+ itEnd = it;
+ }
+ else
+ {
+ it = rDataSet.rbegin();
+ size_t nPos = std::distance(rDataSet.begin(), itPos);
+ size_t nRPos = rDataSet.size() - 1 - nPos; // if itPos == rDataSet.end(), then nRPos = -1
+ std::advance(it, nRPos);
+ if ( it == rDataSet.rend() )
+ it = rDataSet.rbegin();
+ itEnd = it;
+ }
+ bool bFirstTime = true;
+
+ while ( it != itEnd || bFirstTime )
+ {
+ ++it;
+ if ( it == rDataSet.rend() ) // go to the first if reach the end
+ {
+ it = rDataSet.rbegin();
+ nRingOrigin = nCount;
+ }
+
+ if ( bFirstTime )
+ bFirstTime = false;
+ const ScTypedStrData& rData = *it;
+ if ( rData.GetStringType() == ScTypedStrData::Value )
+ // skip values
+ continue;
+
+ if ( !ScGlobal::GetTransliteration().isMatch(rStart, rData.GetString()) )
+ // not a match
+ continue;
+
+ rResultVec.push_back(rData.GetString()); // set the match data
+ if ( nCount == 0 ) // convert the reverse iterator back to iterator.
+ {
+ // actually we want to do "retit = it;".
+ retit = rDataSet.begin();
+ size_t nRPos = std::distance(rDataSet.rbegin(), it);
+ size_t nPos = rDataSet.size() - 1 - nRPos;
+ std::advance(retit, nPos);
+ }
+ ++nCount;
+ }
+ }
+ else // Forwards
+ {
+ ScTypedCaseStrSet::const_iterator it, itEnd;
+ it = itPos;
+ if ( it == rDataSet.end() )
+ it = --rDataSet.end();
+ itEnd = it;
+ bool bFirstTime = true;
+
+ while ( it != itEnd || bFirstTime )
+ {
+ ++it;
+ if ( it == rDataSet.end() ) // go to the first if reach the end
+ {
+ it = rDataSet.begin();
+ nRingOrigin = nCount;
+ }
+
+ if ( bFirstTime )
+ bFirstTime = false;
+ const ScTypedStrData& rData = *it;
+ if ( rData.GetStringType() == ScTypedStrData::Value )
+ // skip values
+ continue;
+
+ if ( !ScGlobal::GetTransliteration().isMatch(rStart, rData.GetString()) )
+ // not a match
+ continue;
+
+ rResultVec.push_back(rData.GetString()); // set the match data
+ if ( nCount == 0 )
+ retit = it; // remember first match iterator
+ ++nCount;
+ }
+ }
+
+ if (pLongestPrefixLen)
+ {
+ if (nRingOrigin >= static_cast<sal_Int32>(nCount))
+ {
+ // All matches were picked when rDataSet was read in one direction.
+ nRingOrigin = 0;
+ }
+ // rResultsVec is a sorted ring with nRingOrigin "origin".
+ // The direction of sorting is not important for getLongestCommonPrefixLength.
+ *pLongestPrefixLen = getLongestCommonPrefixLength(rResultVec, rStart, nRingOrigin);
+ }
+
+ if ( nCount > 0 ) // at least one function has matched
+ return retit;
+ return rDataSet.end(); // no matching text found
+}
+
+}
+
+void ScInputHandler::SendReferenceMarks( const SfxViewShell* pViewShell,
+ const std::vector<ReferenceMark>& rReferenceMarks )
+{
+ if ( !pViewShell )
+ return;
+
+ bool bSend = false;
+
+ std::stringstream ss;
+
+ ss << "{ \"marks\": [ ";
+
+ for ( size_t i = 0; i < rReferenceMarks.size(); i++ )
+ {
+ if ( rReferenceMarks[i].Is() )
+ {
+ if ( bSend )
+ ss << ", ";
+
+ ss << "{ \"rectangle\": \""
+ << rReferenceMarks[i].nX << ", "
+ << rReferenceMarks[i].nY << ", "
+ << rReferenceMarks[i].nWidth << ", "
+ << rReferenceMarks[i].nHeight << "\", "
+ "\"color\": \"" << rReferenceMarks[i].aColor.AsRGBHexString() << "\", "
+ "\"part\": \"" << rReferenceMarks[i].nTab << "\" } ";
+
+ bSend = true;
+ }
+ }
+
+ ss << " ] }";
+
+ OString aPayload = ss.str().c_str();
+ pViewShell->libreOfficeKitViewCallback(
+ LOK_CALLBACK_REFERENCE_MARKS, aPayload.getStr() );
+}
+
+void ScInputHandler::InitRangeFinder( const OUString& rFormula )
+{
+ DeleteRangeFinder();
+ if ( !pActiveViewSh || !SC_MOD()->GetInputOptions().GetRangeFinder() )
+ return;
+ ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const sal_Unicode cSheetSep = rDoc.GetSheetSeparator();
+
+ OUString aDelimiters = ScEditUtil::ModifyDelimiters(" !~\"");
+ // delimiters (in addition to ScEditUtil): only characters that are
+ // allowed in formulas next to references and the quotation mark (so
+ // string constants can be skipped)
+
+ sal_Int32 nColon = aDelimiters.indexOf( ':' );
+ if ( nColon != -1 )
+ aDelimiters = aDelimiters.replaceAt( nColon, 1, u""); // Delimiter without colon
+ sal_Int32 nDot = aDelimiters.indexOf(cSheetSep);
+ if ( nDot != -1 )
+ aDelimiters = aDelimiters.replaceAt( nDot, 1 , u""); // Delimiter without dot
+
+ const sal_Unicode* pChar = rFormula.getStr();
+ sal_Int32 nLen = rFormula.getLength();
+ sal_Int32 nPos = 0;
+ sal_Int32 nStart = 0;
+ sal_uInt16 nCount = 0;
+ ScRange aRange;
+ while ( nPos < nLen && nCount < RANGEFIND_MAX )
+ {
+ // Skip separator
+ while ( nPos<nLen && ScGlobal::UnicodeStrChr( aDelimiters.getStr(), pChar[nPos] ) )
+ {
+ if ( pChar[nPos] == '"' ) // String
+ {
+ ++nPos;
+ while (nPos<nLen && pChar[nPos] != '"') // Skip until end
+ ++nPos;
+ }
+ ++nPos; // Separator or closing quote
+ }
+
+ // text between separators
+ nStart = nPos;
+handle_r1c1:
+ {
+ bool bSingleQuoted = false;
+ while (nPos < nLen)
+ {
+ // tdf#114113: handle addresses with quoted sheet names like "'Sheet 1'.A1"
+ // Literal single quotes in sheet names are masked by another single quote
+ if (pChar[nPos] == '\'')
+ {
+ bSingleQuoted = !bSingleQuoted;
+ }
+ else if (!bSingleQuoted) // Get everything in single quotes, including separators
+ {
+ if (ScGlobal::UnicodeStrChr(aDelimiters.getStr(), pChar[nPos]))
+ break;
+ }
+ ++nPos;
+ }
+ }
+
+ // for R1C1 '-' in R[-]... or C[-]... are not delimiters
+ // Nothing heroic here to ensure that there are '[]' around a negative
+ // integer. we need to clean up this code.
+ if( nPos < nLen && nPos > 0 &&
+ '-' == pChar[nPos] && '[' == pChar[nPos-1] &&
+ formula::FormulaGrammar::CONV_XL_R1C1 == rDoc.GetAddressConvention() )
+ {
+ nPos++;
+ goto handle_r1c1;
+ }
+
+ if ( nPos > nStart )
+ {
+ OUString aTest = rFormula.copy( nStart, nPos-nStart );
+ const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
+ ScRefFlags nFlags = aRange.ParseAny( aTest, rDoc, aAddrDetails );
+ if ( nFlags & ScRefFlags::VALID )
+ {
+ // Set tables if not specified
+ if ( (nFlags & ScRefFlags::TAB_3D) == ScRefFlags::ZERO)
+ aRange.aStart.SetTab( pActiveViewSh->GetViewData().GetTabNo() );
+ if ( (nFlags & ScRefFlags::TAB2_3D) == ScRefFlags::ZERO)
+ aRange.aEnd.SetTab( aRange.aStart.Tab() );
+
+ if ( ( nFlags & (ScRefFlags::COL2_VALID|ScRefFlags::ROW2_VALID|ScRefFlags::TAB2_VALID) ) ==
+ ScRefFlags::ZERO )
+ {
+ // #i73766# if a single ref was parsed, set the same "abs" flags for ref2,
+ // so Format doesn't output a double ref because of different flags.
+ ScRefFlags nAbsFlags = nFlags & (ScRefFlags::COL_ABS|ScRefFlags::ROW_ABS|ScRefFlags::TAB_ABS);
+ applyStartToEndFlags(nFlags, nAbsFlags);
+ }
+
+ if (!nCount)
+ {
+ mpEditEngine->SetUpdateLayout( false );
+ pRangeFindList.reset(new ScRangeFindList( pDocSh->GetTitle() ));
+ }
+
+ Color nColor = pRangeFindList->Insert( ScRangeFindData( aRange, nFlags, nStart, nPos ) );
+
+ ESelection aSel( 0, nStart, 0, nPos );
+ SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
+ aSet.Put( SvxColorItem( nColor, EE_CHAR_COLOR ) );
+ mpEditEngine->QuickSetAttribs( aSet, aSel );
+ ++nCount;
+ }
+ }
+
+ // Do not skip last separator; could be a quote (?)
+ }
+
+ UpdateLokReferenceMarks();
+
+ if (nCount)
+ {
+ mpEditEngine->SetUpdateLayout( true );
+
+ pDocSh->Broadcast( SfxHint( SfxHintId::ScShowRangeFinder ) );
+ }
+}
+
+ReferenceMark ScInputHandler::GetReferenceMark( const ScViewData& rViewData, ScDocShell* pDocSh,
+ tools::Long nX1, tools::Long nX2, tools::Long nY1, tools::Long nY2,
+ tools::Long nTab, const Color& rColor )
+{
+ ScSplitPos eWhich = rViewData.GetActivePart();
+
+ // This method is LOK specific.
+ if (comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ {
+ SCCOL nCol1 = nX1, nCol2 = nX2;
+ SCROW nRow1 = nY1, nRow2 = nY2;
+ PutInOrder(nCol1, nCol2);
+ PutInOrder(nRow1, nRow2);
+ if (nCol1 == nCol2 && nRow1 == nRow2)
+ pDocSh->GetDocument().ExtendMerge(nCol1, nRow1, nCol2, nRow2, nTab);
+
+ Point aTopLeft = rViewData.GetPrintTwipsPos(nCol1, nRow1);
+ Point aBottomRight = rViewData.GetPrintTwipsPos(nCol2 + 1, nRow2 + 1);
+ tools::Long nSizeX = aBottomRight.X() - aTopLeft.X() - 1;
+ tools::Long nSizeY = aBottomRight.Y() - aTopLeft.Y() - 1;
+
+ return ReferenceMark(aTopLeft.X(), aTopLeft.Y(), nSizeX, nSizeY, nTab, rColor);
+ }
+
+ Point aScrPos = rViewData.GetScrPos( nX1, nY1, eWhich );
+ tools::Long nScrX = aScrPos.X();
+ tools::Long nScrY = aScrPos.Y();
+
+ double nPPTX = rViewData.GetPPTX();
+ double nPPTY = rViewData.GetPPTY();
+
+ Fraction aZoomX = rViewData.GetZoomX();
+ Fraction aZoomY = rViewData.GetZoomY();
+
+ ScTableInfo aTabInfo;
+ pDocSh->GetDocument().FillInfo( aTabInfo, nX1, nY1, nX2, nY2,
+ nTab, nPPTX, nPPTY, false, false );
+
+ ScOutputData aOutputData( nullptr, OUTTYPE_WINDOW, aTabInfo,
+ &( pDocSh->GetDocument() ), nTab,
+ nScrX, nScrY,
+ nX1, nY1, nX2, nY2,
+ nPPTX, nPPTY,
+ &aZoomX, &aZoomY );
+
+ return aOutputData.FillReferenceMark( nX1, nY1, nX2, nY2,
+ rColor );
+}
+
+void ScInputHandler::UpdateLokReferenceMarks()
+{
+ if ( !comphelper::LibreOfficeKit::isActive())
+ return;
+
+ ScTabViewShell* pShell = pActiveViewSh ? pActiveViewSh
+ : dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
+
+ if (!pShell)
+ return;
+
+ ScViewData& rViewData = pShell->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScRangeFindList* pRangeFinder = GetRangeFindList();
+
+ if ( !pRangeFinder && !rViewData.IsRefMode() )
+ return;
+
+ sal_uInt16 nAdditionalMarks = 0;
+ std::vector<ReferenceMark> aReferenceMarks( 1 );
+
+ if ( rViewData.IsRefMode() )
+ {
+ nAdditionalMarks = 1;
+
+ const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
+ Color aRefColor( rColorCfg.GetColorValue( svtools::CALCREFERENCE ).nColor );
+ tools::Long nX1 = rViewData.GetRefStartX();
+ tools::Long nX2 = rViewData.GetRefEndX();
+ tools::Long nY1 = rViewData.GetRefStartY();
+ tools::Long nY2 = rViewData.GetRefEndY();
+ tools::Long nTab = rViewData.GetRefStartZ();
+
+ if (rViewData.GetRefEndZ() == rViewData.GetTabNo())
+ nTab = rViewData.GetRefEndZ();
+
+ PutInOrder(nX1, nX2);
+ PutInOrder(nY1, nY2);
+
+ aReferenceMarks[0] = ScInputHandler::GetReferenceMark( rViewData, pDocSh,
+ nX1, nX2, nY1, nY2,
+ nTab, aRefColor );
+ }
+
+ sal_uInt16 nCount = pRangeFinder ?
+ ( static_cast<sal_uInt16>( pRangeFinder->Count() ) + nAdditionalMarks ) : nAdditionalMarks;
+ aReferenceMarks.resize( nCount );
+
+ if ( nCount && pRangeFinder && !pRangeFinder->IsHidden() &&
+ pRangeFinder->GetDocName() == pDocSh->GetTitle() )
+ {
+ for (sal_uInt16 i = 0; i < nCount - nAdditionalMarks; i++)
+ {
+ ScRangeFindData& rData = pRangeFinder->GetObject( i );
+ ScRange aRef = rData.aRef;
+ aRef.PutInOrder();
+
+ tools::Long nX1 = aRef.aStart.Col();
+ tools::Long nX2 = aRef.aEnd.Col();
+ tools::Long nY1 = aRef.aStart.Row();
+ tools::Long nY2 = aRef.aEnd.Row();
+ tools::Long nTab = aRef.aStart.Tab();
+
+ aReferenceMarks[i + nAdditionalMarks] = ScInputHandler::GetReferenceMark( rViewData, pDocSh,
+ nX1, nX2, nY1, nY2,
+ nTab, rData.nColor );
+
+ ScInputHandler::SendReferenceMarks( pShell, aReferenceMarks );
+ }
+ }
+ else if ( nCount )
+ {
+ ScInputHandler::SendReferenceMarks( pShell, aReferenceMarks );
+ }
+ else
+ {
+ // Clear
+ aReferenceMarks.clear();
+ ScInputHandler::SendReferenceMarks( pShell, aReferenceMarks );
+ }
+}
+
+void ScInputHandler::SetDocumentDisposing( bool b )
+{
+ mbDocumentDisposing = b;
+}
+
+static void lcl_Replace( EditView* pView, const OUString& rNewStr, const ESelection& rOldSel )
+{
+ if ( !pView )
+ return;
+
+ ESelection aOldSel = pView->GetSelection();
+ if (aOldSel.HasRange())
+ pView->SetSelection( ESelection( aOldSel.nEndPara, aOldSel.nEndPos,
+ aOldSel.nEndPara, aOldSel.nEndPos ) );
+
+ EditEngine* pEngine = pView->GetEditEngine();
+ pEngine->QuickInsertText( rNewStr, rOldSel );
+
+ // Dummy InsertText for Update and Paint
+ // To do that we need to cancel the selection from above (before QuickInsertText)
+ pView->InsertText( OUString() );
+
+ sal_Int32 nLen = pEngine->GetTextLen(0);
+ ESelection aSel( 0, nLen, 0, nLen );
+ pView->SetSelection( aSel ); // Set cursor to the end
+}
+
+void ScInputHandler::UpdateRange( sal_uInt16 nIndex, const ScRange& rNew )
+{
+ ScTabViewShell* pDocView = pRefViewSh ? pRefViewSh : pActiveViewSh;
+ if ( pDocView && pRangeFindList && nIndex < pRangeFindList->Count() )
+ {
+ ScRangeFindData& rData = pRangeFindList->GetObject( nIndex );
+ sal_Int32 nOldStart = rData.nSelStart;
+ sal_Int32 nOldEnd = rData.nSelEnd;
+ Color nNewColor = pRangeFindList->FindColor( rNew, nIndex );
+
+ ScRange aJustified = rNew;
+ aJustified.PutInOrder(); // Always display Ref in the Formula the right way
+ ScDocument& rDoc = pDocView->GetViewData().GetDocument();
+ const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
+ OUString aNewStr(aJustified.Format(rDoc, rData.nFlags, aAddrDetails));
+ ESelection aOldSel( 0, nOldStart, 0, nOldEnd );
+ SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
+
+ DataChanging();
+
+ lcl_Replace( pTopView, aNewStr, aOldSel );
+ lcl_Replace( pTableView, aNewStr, aOldSel );
+ aSet.Put( SvxColorItem( nNewColor, EE_CHAR_COLOR ) );
+ mpEditEngine->QuickSetAttribs( aSet, aOldSel );
+
+ bInRangeUpdate = true;
+ DataChanged();
+ bInRangeUpdate = false;
+
+ tools::Long nDiff = aNewStr.getLength() - static_cast<tools::Long>(nOldEnd-nOldStart);
+
+ rData.aRef = rNew;
+ rData.nSelEnd = rData.nSelEnd + nDiff;
+ rData.nColor = nNewColor;
+
+ sal_uInt16 nCount = static_cast<sal_uInt16>(pRangeFindList->Count());
+ for (sal_uInt16 i=nIndex+1; i<nCount; i++)
+ {
+ ScRangeFindData& rNext = pRangeFindList->GetObject( i );
+ rNext.nSelStart = rNext.nSelStart + nDiff;
+ rNext.nSelEnd = rNext.nSelEnd + nDiff;
+ }
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ pActiveView->ShowCursor( false );
+ }
+ else
+ {
+ OSL_FAIL("UpdateRange: we're missing something");
+ }
+}
+
+void ScInputHandler::DeleteRangeFinder()
+{
+ ScTabViewShell* pPaintView = pRefViewSh ? pRefViewSh : pActiveViewSh;
+ if ( pRangeFindList && pPaintView )
+ {
+ ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
+ pRangeFindList->SetHidden(true);
+ pDocSh->Broadcast( SfxHint( SfxHintId::ScShowRangeFinder ) ); // Steal
+ pRangeFindList.reset();
+ }
+}
+
+static OUString GetEditText(const EditEngine* pEng)
+{
+ return ScEditUtil::GetMultilineString(*pEng);
+}
+
+static void lcl_RemoveTabs(OUString& rStr)
+{
+ rStr = rStr.replace('\t', ' ');
+}
+
+static void lcl_RemoveLineEnd(OUString& rStr)
+{
+ rStr = convertLineEnd(rStr, LINEEND_LF);
+ rStr = rStr.replace('\n', ' ');
+}
+
+static sal_Int32 lcl_MatchParenthesis( const OUString& rStr, sal_Int32 nPos )
+{
+ int nDir;
+ sal_Unicode c1, c2 = 0;
+ c1 = rStr[nPos];
+ switch ( c1 )
+ {
+ case '(' :
+ c2 = ')';
+ nDir = 1;
+ break;
+ case ')' :
+ c2 = '(';
+ nDir = -1;
+ break;
+ case '<' :
+ c2 = '>';
+ nDir = 1;
+ break;
+ case '>' :
+ c2 = '<';
+ nDir = -1;
+ break;
+ case '{' :
+ c2 = '}';
+ nDir = 1;
+ break;
+ case '}' :
+ c2 = '{';
+ nDir = -1;
+ break;
+ case '[' :
+ c2 = ']';
+ nDir = 1;
+ break;
+ case ']' :
+ c2 = '[';
+ nDir = -1;
+ break;
+ default:
+ nDir = 0;
+ }
+ if ( !nDir )
+ return -1;
+ sal_Int32 nLen = rStr.getLength();
+ const sal_Unicode* p0 = rStr.getStr();
+ const sal_Unicode* p;
+ const sal_Unicode* p1;
+ sal_uInt16 nQuotes = 0;
+ if ( nPos < nLen / 2 )
+ {
+ p = p0;
+ p1 = p0 + nPos;
+ }
+ else
+ {
+ p = p0 + nPos;
+ p1 = p0 + nLen;
+ }
+ while ( p < p1 )
+ {
+ if ( *p++ == '\"' )
+ nQuotes++;
+ }
+ // Odd number of quotes that we find ourselves in a string
+ bool bLookInString = ((nQuotes % 2) != 0);
+ bool bInString = bLookInString;
+ p = p0 + nPos;
+ p1 = (nDir < 0 ? p0 : p0 + nLen) ;
+ sal_uInt16 nLevel = 1;
+ while ( p != p1 && nLevel )
+ {
+ p += nDir;
+ if ( *p == '\"' )
+ {
+ bInString = !bInString;
+ if ( bLookInString && !bInString )
+ p = p1; // That's it then
+ }
+ else if ( bInString == bLookInString )
+ {
+ if ( *p == c1 )
+ nLevel++;
+ else if ( *p == c2 )
+ nLevel--;
+ }
+ }
+ if ( nLevel )
+ return -1;
+ return static_cast<sal_Int32>(p - p0);
+}
+
+ScInputHandler::ScInputHandler()
+ : pInputWin( nullptr ),
+ pTableView( nullptr ),
+ pTopView( nullptr ),
+ pTipVisibleParent( nullptr ),
+ nTipVisible( nullptr ),
+ pTipVisibleSecParent( nullptr ),
+ nTipVisibleSec( nullptr ),
+ nFormSelStart( 0 ),
+ nFormSelEnd( 0 ),
+ nCellPercentFormatDecSep( 0 ),
+ nAutoPar( 0 ),
+ eMode( SC_INPUT_NONE ),
+ bUseTab( false ),
+ bTextValid( true ),
+ bModified( false ),
+ bSelIsRef( false ),
+ bFormulaMode( false ),
+ bInRangeUpdate( false ),
+ bParenthesisShown( false ),
+ bCreatingFuncView( false ),
+ bInEnterHandler( false ),
+ bCommandErrorShown( false ),
+ bInOwnChange( false ),
+ bProtected( false ),
+ bLastIsSymbol( false ),
+ mbDocumentDisposing(false),
+ mbPartialPrefix(false),
+ mbEditingExistingContent(false),
+ nValidation( 0 ),
+ eAttrAdjust( SvxCellHorJustify::Standard ),
+ aScaleX( 1,1 ),
+ aScaleY( 1,1 ),
+ pRefViewSh( nullptr ),
+ pLastPattern( nullptr )
+{
+ // The InputHandler is constructed with the view, so SfxViewShell::Current
+ // doesn't have the right view yet. pActiveViewSh is updated in NotifyChange.
+ pActiveViewSh = nullptr;
+
+ // Bindings (only still used for Invalidate) are retrieved if needed on demand
+
+ pDelayTimer.reset( new Timer( "ScInputHandlerDelay timer" ) );
+ pDelayTimer->SetTimeout( 500 ); // 500 ms delay
+ pDelayTimer->SetInvokeHandler( LINK( this, ScInputHandler, DelayTimer ) );
+}
+
+ScInputHandler::~ScInputHandler()
+{
+ // If this is the application InputHandler, the dtor is called after SfxApplication::Main,
+ // thus we can't rely on any Sfx functions
+ if (!mbDocumentDisposing) // inplace
+ EnterHandler(); // Finish input
+
+ if (SC_MOD()->GetRefInputHdl() == this)
+ SC_MOD()->SetRefInputHdl(nullptr);
+
+ if ( pInputWin && pInputWin->GetInputHandler() == this )
+ pInputWin->SetInputHandler( nullptr );
+}
+
+void ScInputHandler::SetRefScale( const Fraction& rX, const Fraction& rY )
+{
+ if ( rX != aScaleX || rY != aScaleY )
+ {
+ aScaleX = rX;
+ aScaleY = rY;
+ if (mpEditEngine)
+ {
+ MapMode aMode( MapUnit::Map100thMM, Point(), aScaleX, aScaleY );
+ mpEditEngine->SetRefMapMode( aMode );
+ }
+ }
+}
+
+void ScInputHandler::UpdateRefDevice()
+{
+ if (!mpEditEngine)
+ return;
+
+ bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg();
+ bool bInPlace = pActiveViewSh && pActiveViewSh->GetViewFrame()->GetFrame().IsInPlace();
+ EEControlBits nCtrl = mpEditEngine->GetControlWord();
+ if ( bTextWysiwyg || bInPlace )
+ nCtrl |= EEControlBits::FORMAT100; // EditEngine default: always format for 100%
+ else
+ nCtrl &= ~EEControlBits::FORMAT100; // when formatting for screen, use the actual MapMode
+ mpEditEngine->SetControlWord( nCtrl );
+ if ( bTextWysiwyg && pActiveViewSh )
+ mpEditEngine->SetRefDevice( pActiveViewSh->GetViewData().GetDocument().GetPrinter() );
+ else
+ mpEditEngine->SetRefDevice( nullptr );
+
+ MapMode aMode( MapUnit::Map100thMM, Point(), aScaleX, aScaleY );
+ mpEditEngine->SetRefMapMode( aMode );
+
+ // SetRefDevice(NULL) uses VirtualDevice, SetRefMapMode forces creation of a local VDev,
+ // so the DigitLanguage can be safely modified (might use an own VDev instead of NULL).
+ if ( !( bTextWysiwyg && pActiveViewSh ) )
+ {
+ mpEditEngine->GetRefDevice()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
+ }
+}
+
+void ScInputHandler::ImplCreateEditEngine()
+{
+ if ( mpEditEngine )
+ return;
+
+ if ( pActiveViewSh )
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+ mpEditEngine = std::make_unique<ScFieldEditEngine>(&rDoc, rDoc.GetEnginePool(), rDoc.GetEditPool());
+ }
+ else
+ mpEditEngine = std::make_unique<ScFieldEditEngine>(nullptr, EditEngine::CreatePool().get(), nullptr, true);
+
+ mpEditEngine->SetWordDelimiters( ScEditUtil::ModifyDelimiters( mpEditEngine->GetWordDelimiters() ) );
+ UpdateRefDevice(); // also sets MapMode
+ mpEditEngine->SetPaperSize( Size( 1000000, 1000000 ) );
+ pEditDefaults.reset( new SfxItemSet( mpEditEngine->GetEmptyItemSet() ) );
+
+ mpEditEngine->SetControlWord( mpEditEngine->GetControlWord() | EEControlBits::AUTOCORRECT );
+ mpEditEngine->SetReplaceLeadingSingleQuotationMark( false );
+ mpEditEngine->SetModifyHdl( LINK( this, ScInputHandler, ModifyHdl ) );
+}
+
+void ScInputHandler::UpdateAutoCorrFlag()
+{
+ EEControlBits nCntrl = mpEditEngine->GetControlWord();
+ EEControlBits nOld = nCntrl;
+
+ // Don't use pLastPattern here (may be invalid because of AutoStyle)
+ bool bDisable = bLastIsSymbol || bFormulaMode;
+ if ( bDisable )
+ nCntrl &= ~EEControlBits::AUTOCORRECT;
+ else
+ nCntrl |= EEControlBits::AUTOCORRECT;
+
+ if ( nCntrl != nOld )
+ mpEditEngine->SetControlWord(nCntrl);
+}
+
+void ScInputHandler::UpdateSpellSettings( bool bFromStartTab )
+{
+ if ( !pActiveViewSh )
+ return;
+
+ ScViewData& rViewData = pActiveViewSh->GetViewData();
+ bool bOnlineSpell = rViewData.GetDocument().GetDocOptions().IsAutoSpell();
+
+ // SetDefaultLanguage is independent of the language attributes,
+ // ScGlobal::GetEditDefaultLanguage is always used.
+ // It must be set every time in case the office language was changed.
+
+ mpEditEngine->SetDefaultLanguage( ScGlobal::GetEditDefaultLanguage() );
+
+ // if called for changed options, update flags only if already editing
+ // if called from StartTable, always update flags
+
+ if ( bFromStartTab || eMode != SC_INPUT_NONE )
+ {
+ EEControlBits nCntrl = mpEditEngine->GetControlWord();
+ EEControlBits nOld = nCntrl;
+ if( bOnlineSpell )
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+ // No AutoCorrect for Symbol Font (EditEngine does no evaluate Default)
+ if ( pLastPattern && pLastPattern->IsSymbolFont() )
+ nCntrl &= ~EEControlBits::AUTOCORRECT;
+ else
+ nCntrl |= EEControlBits::AUTOCORRECT;
+ if ( nCntrl != nOld )
+ mpEditEngine->SetControlWord(nCntrl);
+
+ ScDocument& rDoc = rViewData.GetDocument();
+ rDoc.ApplyAsianEditSettings( *mpEditEngine );
+ mpEditEngine->SetDefaultHorizontalTextDirection(
+ rDoc.GetEditTextDirection( rViewData.GetTabNo() ) );
+ mpEditEngine->SetFirstWordCapitalization( false );
+ }
+
+ // Language is set separately, so the speller is needed only if online spelling is active
+ if ( bOnlineSpell ) {
+ css::uno::Reference<css::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
+ mpEditEngine->SetSpeller( xXSpellChecker1 );
+ }
+
+ bool bHyphen = pLastPattern && pLastPattern->GetItem(ATTR_HYPHENATE).GetValue();
+ if ( bHyphen ) {
+ css::uno::Reference<css::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
+ mpEditEngine->SetHyphenator( xXHyphenator );
+ }
+}
+
+// Function/Range names etc. as Tip help
+
+// The other types are defined in ScDocument::GetFormulaEntries
+void ScInputHandler::GetFormulaData()
+{
+ if ( !pActiveViewSh )
+ return;
+
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+
+ if ( pFormulaData )
+ pFormulaData->clear();
+ else
+ {
+ pFormulaData.reset( new ScTypedCaseStrSet );
+ }
+
+ if( pFormulaDataPara )
+ pFormulaDataPara->clear();
+ else
+ pFormulaDataPara.reset( new ScTypedCaseStrSet );
+
+ const OUString aParenthesesReplacement( cParenthesesReplacement);
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ const sal_uInt32 nListCount = pFuncList->GetCount();
+ const InputHandlerFunctionNames& rFunctionNames = ScGlobal::GetInputHandlerFunctionNames();
+ *pFormulaData = rFunctionNames.maFunctionData;
+ *pFormulaDataPara = rFunctionNames.maFunctionDataPara;
+ maFormulaChar = rFunctionNames.maFunctionChar;
+
+ // Increase suggestion priority of MRU formulas
+ const ScAppOptions& rOpt = SC_MOD()->GetAppOptions();
+ const sal_uInt16 nMRUCount = rOpt.GetLRUFuncListCount();
+ const sal_uInt16* pMRUList = rOpt.GetLRUFuncList();
+ for (sal_uInt16 i = 0; i < nMRUCount; i++)
+ {
+ const sal_uInt16 nId = pMRUList[i];
+ for (sal_uInt32 j = 0; j < nListCount; j++)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(j);
+ if (pDesc->nFIndex == nId && pDesc->mxFuncName)
+ {
+ const OUString aEntry = *pDesc->mxFuncName + aParenthesesReplacement;;
+ const ScTypedStrData aData(aEntry, 0.0, 0.0, ScTypedStrData::Standard);
+ auto it = pFormulaData->find(aData);
+ if (it != pFormulaData->end())
+ pFormulaData->erase(it);
+ pFormulaData->insert(ScTypedStrData(aEntry, 0.0, 0.0, ScTypedStrData::MRU));
+ break; // Stop searching
+ }
+ }
+ }
+ miAutoPosFormula = pFormulaData->end();
+
+ // tdf#142031 - collect all the characters for the formula suggestion auto input
+ ScTypedCaseStrSet aStrSet;
+ rDoc.GetFormulaEntries( aStrSet );
+ for (auto iter = aStrSet.begin(); iter != aStrSet.end(); ++iter)
+ {
+ const OUString aFuncName = ScGlobal::getCharClass().uppercase((*iter).GetString());
+ // fdo#75264 fill maFormulaChar with all characters used in formula names
+ for (sal_Int32 j = 0; j < aFuncName.getLength(); j++)
+ maFormulaChar.insert(aFuncName[j]);
+ }
+ pFormulaData->insert(aStrSet.begin(), aStrSet.end());
+ pFormulaDataPara->insert(aStrSet.begin(), aStrSet.end());
+}
+
+IMPL_LINK( ScInputHandler, ShowHideTipVisibleParentListener, VclWindowEvent&, rEvent, void )
+{
+ if (rEvent.GetId() == VclEventId::ObjectDying || rEvent.GetId() == VclEventId::WindowHide
+ || rEvent.GetId() == VclEventId::WindowLoseFocus || rEvent.GetId() == VclEventId::ControlLoseFocus)
+ HideTip();
+}
+
+IMPL_LINK( ScInputHandler, ShowHideTipVisibleSecParentListener, VclWindowEvent&, rEvent, void )
+{
+ if (rEvent.GetId() == VclEventId::ObjectDying || rEvent.GetId() == VclEventId::WindowHide
+ || rEvent.GetId() == VclEventId::WindowLoseFocus || rEvent.GetId() == VclEventId::ControlLoseFocus)
+ HideTipBelow();
+}
+
+void ScInputHandler::HideTip()
+{
+ if ( nTipVisible )
+ {
+ pTipVisibleParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
+ Help::HidePopover(pTipVisibleParent, nTipVisible );
+ nTipVisible = nullptr;
+ pTipVisibleParent = nullptr;
+ }
+ aManualTip.clear();
+}
+void ScInputHandler::HideTipBelow()
+{
+ if ( nTipVisibleSec )
+ {
+ pTipVisibleSecParent->RemoveEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
+ Help::HidePopover(pTipVisibleSecParent, nTipVisibleSec);
+ nTipVisibleSec = nullptr;
+ pTipVisibleSecParent = nullptr;
+ }
+ aManualTip.clear();
+}
+
+namespace
+{
+
+bool lcl_hasSingleToken(std::u16string_view s, sal_Unicode c)
+{
+ return !s.empty() && s.find(c) == std::u16string_view::npos;
+}
+
+}
+
+void ScInputHandler::ShowArgumentsTip( OUString& rSelText )
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ return;
+ }
+
+ ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ const sal_Unicode cSheetSep = pDocSh->GetDocument().GetSheetSeparator();
+ FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());
+ bool bFound = false;
+ while( !bFound )
+ {
+ rSelText += ")";
+ sal_Int32 nLeftParentPos = lcl_MatchParenthesis( rSelText, rSelText.getLength()-1 );
+ if( nLeftParentPos != -1 )
+ {
+ sal_Int32 nNextFStart = aHelper.GetFunctionStart( rSelText, nLeftParentPos, true);
+ const IFunctionDescription* ppFDesc;
+ ::std::vector< OUString> aArgs;
+ if( aHelper.GetNextFunc( rSelText, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
+ {
+ if( !ppFDesc->getFunctionName().isEmpty() )
+ {
+ sal_Int32 nArgPos = aHelper.GetArgStart( rSelText, nNextFStart, 0 );
+ sal_uInt16 nArgs = static_cast<sal_uInt16>(ppFDesc->getParameterCount());
+ OUString aFuncName( ppFDesc->getFunctionName() + "(");
+ OUString aNew;
+ ScTypedCaseStrSet::const_iterator it =
+ findText(*pFormulaDataPara, pFormulaDataPara->end(), aFuncName, aNew, false);
+ if (it != pFormulaDataPara->end())
+ {
+ bool bFlag = false;
+ sal_uInt16 nActive = 0;
+ for( sal_uInt16 i=0; i < nArgs; i++ )
+ {
+ sal_Int32 nLength = aArgs[i].getLength();
+ if( nArgPos <= rSelText.getLength()-1 )
+ {
+ nActive = i+1;
+ bFlag = true;
+ }
+ nArgPos+=nLength+1;
+ }
+ if( bFlag )
+ {
+ sal_Int32 nStartPosition = 0;
+ sal_Int32 nEndPosition = 0;
+
+ if( lcl_hasSingleToken(aNew, cSep) )
+ {
+ for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
+ {
+ sal_Unicode cNext = aNew[i];
+ if( cNext == '(' )
+ {
+ nStartPosition = i+1;
+ }
+ }
+ }
+ else if( lcl_hasSingleToken(aNew, cSheetSep) )
+ {
+ sal_uInt16 nCount = 0;
+ for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
+ {
+ sal_Unicode cNext = aNew[i];
+ if( cNext == '(' )
+ {
+ nStartPosition = i+1;
+ }
+ else if( cNext == cSep )
+ {
+ nCount ++;
+ nEndPosition = i;
+ if( nCount == nActive )
+ {
+ break;
+ }
+ nStartPosition = nEndPosition+1;
+ }
+ }
+ }
+ else
+ {
+ sal_uInt16 nCount = 0;
+ for (sal_Int32 i = 0; i < aNew.getLength(); ++i)
+ {
+ sal_Unicode cNext = aNew[i];
+ if( cNext == '(' )
+ {
+ nStartPosition = i+1;
+ }
+ else if( cNext == cSep )
+ {
+ nCount ++;
+ nEndPosition = i;
+ if( nCount == nActive )
+ {
+ break;
+ }
+ nStartPosition = nEndPosition+1;
+ }
+ else if( cNext == cSheetSep )
+ {
+ continue;
+ }
+ }
+ }
+
+ if (nStartPosition > 0)
+ {
+ nArgs = ppFDesc->getParameterCount();
+ sal_Int16 nVarArgsSet = 0;
+ if ( nArgs >= PAIRED_VAR_ARGS )
+ {
+ nVarArgsSet = 2;
+ nArgs -= PAIRED_VAR_ARGS - nVarArgsSet;
+ }
+ else if ( nArgs >= VAR_ARGS )
+ {
+ nVarArgsSet = 1;
+ nArgs -= VAR_ARGS - nVarArgsSet;
+ }
+ if ( nVarArgsSet > 0 && nActive > nArgs )
+ nActive = nArgs - (nActive - nArgs) % nVarArgsSet;
+ aNew = OUString::Concat(aNew.subView(0, nStartPosition)) +
+ u"\x25BA" +
+ aNew.subView(nStartPosition) +
+ " : " +
+ ppFDesc->getParameterDescription(nActive-1);
+ if (eMode != SC_INPUT_TOP)
+ {
+ ShowTipBelow( aNew );
+ }
+ else
+ {
+ ShowTip(aNew);
+ }
+ bFound = true;
+ }
+ }
+ else
+ {
+ ShowTipBelow( aNew );
+ bFound = true;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+void ScInputHandler::ShowTipCursor()
+{
+ HideTip();
+ HideTipBelow();
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+
+ /* TODO: MLFORMULA: this should work also with multi-line formulas. */
+ if ( !(bFormulaMode && pActiveView && pFormulaDataPara && mpEditEngine->GetParagraphCount() == 1) )
+ return;
+
+ OUString aParagraph = mpEditEngine->GetText( 0 );
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+
+ if ( aParagraph.getLength() < aSel.nEndPos )
+ return;
+
+ if ( aSel.nEndPos > 0 )
+ {
+ OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
+
+ ShowArgumentsTip( aSelText );
+ }
+}
+
+void ScInputHandler::ShowTip( const OUString& rText )
+{
+ // aManualTip needs to be set afterwards from outside
+
+ HideTip();
+ HideTipBelow();
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (!pActiveView)
+ return;
+
+ Point aPos;
+ if (pInputWin && pInputWin->GetEditView() == pActiveView)
+ {
+ pTipVisibleParent = pInputWin->GetEditWindow();
+ aPos = pInputWin->GetCursorScreenPixelPos();
+ }
+ else
+ {
+ pTipVisibleParent = pActiveView->GetWindow();
+ if (vcl::Cursor* pCur = pActiveView->GetCursor())
+ aPos = pTipVisibleParent->LogicToPixel( pCur->GetPos() );
+ aPos = pTipVisibleParent->OutputToScreenPixel( aPos );
+ }
+
+ tools::Rectangle aRect( aPos, aPos );
+ QuickHelpFlags const nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
+ nTipVisible = Help::ShowPopover(pTipVisibleParent, aRect, rText, nAlign);
+ pTipVisibleParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleParentListener ) );
+}
+
+void ScInputHandler::ShowTipBelow( const OUString& rText )
+{
+ HideTipBelow();
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( !pActiveView )
+ return;
+
+ Point aPos;
+ if (pInputWin && pInputWin->GetEditView() == pActiveView)
+ {
+ pTipVisibleSecParent = pInputWin->GetEditWindow();
+ aPos = pInputWin->GetCursorScreenPixelPos(true);
+ }
+ else
+ {
+ pTipVisibleSecParent = pActiveView->GetWindow();
+ if (vcl::Cursor* pCur = pActiveView->GetCursor())
+ {
+ Point aLogicPos = pCur->GetPos();
+ aLogicPos.AdjustY(pCur->GetHeight() );
+ aPos = pTipVisibleSecParent->LogicToPixel( aLogicPos );
+ }
+ aPos = pTipVisibleSecParent->OutputToScreenPixel( aPos );
+ }
+
+ tools::Rectangle aRect( aPos, aPos );
+ QuickHelpFlags const nAlign = QuickHelpFlags::Left | QuickHelpFlags::Top | QuickHelpFlags::NoEvadePointer;
+ nTipVisibleSec = Help::ShowPopover(pTipVisibleSecParent, aRect, rText, nAlign);
+ pTipVisibleSecParent->AddEventListener( LINK( this, ScInputHandler, ShowHideTipVisibleSecParentListener ) );
+}
+
+bool ScInputHandler::GetFuncName( OUString& aStart, OUString& aResult )
+{
+ if ( aStart.isEmpty() )
+ return false;
+
+ aStart = ScGlobal::getCharClass().uppercase( aStart );
+ sal_Int32 nPos = aStart.getLength() - 1;
+ sal_Unicode c = aStart[ nPos ];
+ // fdo#75264 use maFormulaChar to check if characters are used in function names
+ ::std::set< sal_Unicode >::const_iterator p = maFormulaChar.find( c );
+ if ( p == maFormulaChar.end() )
+ return false; // last character is not part of any function name, quit
+
+ ::std::vector<sal_Unicode> aTemp { c };
+ for(sal_Int32 i = nPos - 1; i >= 0; --i)
+ {
+ c = aStart[ i ];
+ p = maFormulaChar.find( c );
+
+ if (p == maFormulaChar.end())
+ break;
+
+ aTemp.push_back( c );
+ }
+
+ ::std::vector<sal_Unicode>::reverse_iterator rIt = aTemp.rbegin();
+ aResult = OUString( *rIt++ );
+ while ( rIt != aTemp.rend() )
+ aResult += OUStringChar( *rIt++ );
+
+ return true;
+}
+
+namespace {
+ /// Rid ourselves of unwanted " quoted json characters.
+ OString escapeJSON(const OUString &aStr)
+ {
+ OUString aEscaped = aStr;
+ aEscaped = aEscaped.replaceAll("\n", " ");
+ aEscaped = aEscaped.replaceAll("\"", "'");
+ return OUStringToOString(aEscaped, RTL_TEXTENCODING_UTF8);
+ }
+}
+
+void ScInputHandler::ShowFuncList( const ::std::vector< OUString > & rFuncStrVec )
+{
+ const SfxViewShell* pViewShell = SfxViewShell::Current();
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (rFuncStrVec.size() && pViewShell && pViewShell->isLOKMobilePhone())
+ {
+ auto aPos = pFormulaData->begin();
+ sal_uInt32 nCurIndex = std::distance(aPos, miAutoPosFormula);
+ const sal_uInt32 nSize = pFormulaData->size();
+
+ OUString aFuncNameStr;
+ OUString aDescFuncNameStr;
+ OStringBuffer aPayload;
+ aPayload.append("[ ");
+ for (const OUString& rFunc : rFuncStrVec)
+ {
+ if ( rFunc[rFunc.getLength()-1] == cParenthesesReplacement )
+ {
+ aFuncNameStr = rFunc.copy(0, rFunc.getLength()-1);
+ }
+ else
+ {
+ aFuncNameStr = rFunc;
+ }
+
+ FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());
+ aDescFuncNameStr = aFuncNameStr + "()";
+ sal_Int32 nNextFStart = 0;
+ const IFunctionDescription* ppFDesc;
+ ::std::vector< OUString > aArgs;
+ OUString eqPlusFuncName = "=" + aDescFuncNameStr;
+ if ( aHelper.GetNextFunc( eqPlusFuncName, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
+ {
+ if ( !ppFDesc->getFunctionName().isEmpty() )
+ {
+ aPayload.append("{");
+ aPayload.append("\"index\": ");
+ aPayload.append(static_cast<sal_Int64>(nCurIndex));
+ aPayload.append(", ");
+ aPayload.append("\"signature\": \"");
+ aPayload.append(escapeJSON(ppFDesc->getSignature()));
+ aPayload.append("\", ");
+ aPayload.append("\"description\": \"");
+ aPayload.append(escapeJSON(ppFDesc->getDescription()));
+ aPayload.append("\"}, ");
+ }
+ }
+ ++nCurIndex;
+ if (nCurIndex == nSize)
+ nCurIndex = 0;
+ }
+ sal_Int32 nLen = aPayload.getLength();
+ aPayload[nLen - 2] = ' ';
+ aPayload[nLen - 1] = ']';
+
+ OString s = aPayload.makeStringAndClear();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CALC_FUNCTION_LIST, s.getStr());
+ }
+ // not tunnel tooltips in the lok case
+ return;
+ }
+
+ OUStringBuffer aTipStr;
+ OUString aFuncNameStr;
+ OUString aDescFuncNameStr;
+ ::std::vector<OUString>::const_iterator itStr = rFuncStrVec.begin();
+ sal_Int32 nMaxFindNumber = 3;
+ sal_Int32 nRemainFindNumber = nMaxFindNumber;
+ for ( ; itStr != rFuncStrVec.end(); ++itStr )
+ {
+ const OUString& rFunc = *itStr;
+ if ( rFunc[rFunc.getLength()-1] == cParenthesesReplacement )
+ {
+ aFuncNameStr = rFunc.copy(0, rFunc.getLength()-1);
+ }
+ else
+ {
+ aFuncNameStr = rFunc;
+ }
+ if ( itStr == rFuncStrVec.begin() )
+ {
+ aTipStr = "[";
+ aDescFuncNameStr = aFuncNameStr + "()";
+ }
+ else
+ {
+ aTipStr.append(", ");
+ }
+ aTipStr.append(aFuncNameStr);
+ if ( itStr == rFuncStrVec.begin() )
+ aTipStr.append("]");
+ if ( --nRemainFindNumber <= 0 )
+ break;
+ }
+ sal_Int32 nRemainNumber = rFuncStrVec.size() - nMaxFindNumber;
+ if ( nRemainFindNumber == 0 && nRemainNumber > 0 )
+ {
+ OUString aMessage( ScResId( STR_FUNCTIONS_FOUND ) );
+ aMessage = aMessage.replaceFirst("%2", OUString::number(nRemainNumber));
+ aMessage = aMessage.replaceFirst("%1", aTipStr);
+ aTipStr = aMessage;
+ }
+ FormulaHelper aHelper(ScGlobal::GetStarCalcFunctionMgr());
+ sal_Int32 nNextFStart = 0;
+ const IFunctionDescription* ppFDesc;
+ ::std::vector< OUString > aArgs;
+ OUString eqPlusFuncName = "=" + aDescFuncNameStr;
+ if ( aHelper.GetNextFunc( eqPlusFuncName, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
+ {
+ if ( !ppFDesc->getFunctionName().isEmpty() )
+ {
+ aTipStr.append(" : " + ppFDesc->getDescription());
+ }
+ }
+ ShowTip( aTipStr.makeStringAndClear() );
+}
+
+void ScInputHandler::UseFormulaData()
+{
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+
+ /* TODO: MLFORMULA: this should work also with multi-line formulas. */
+ if ( !(pActiveView && pFormulaData && mpEditEngine->GetParagraphCount() == 1) )
+ return;
+
+ OUString aParagraph = mpEditEngine->GetText( 0 );
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+
+ // Due to differences between table and input cell (e.g clipboard with line breaks),
+ // the selection may not be in line with the EditEngine anymore.
+ // Just return without any indication as to why.
+ if ( aSel.nEndPos > aParagraph.getLength() )
+ return;
+
+ if ( aParagraph.getLength() > aSel.nEndPos &&
+ ( ScGlobal::getCharClass().isLetterNumeric( aParagraph, aSel.nEndPos ) ||
+ aParagraph[ aSel.nEndPos ] == '_' ||
+ aParagraph[ aSel.nEndPos ] == '.' ||
+ aParagraph[ aSel.nEndPos ] == '$' ) )
+ return;
+
+ // Is the cursor at the end of a word?
+ if ( aSel.nEndPos <= 0 )
+ return;
+
+ OUString aSelText( aParagraph.copy( 0, aSel.nEndPos ));
+
+ OUString aText;
+ if ( GetFuncName( aSelText, aText ) )
+ {
+ // function name is incomplete:
+ // show matching functions name as tip above cell
+ ::std::vector<OUString> aNewVec;
+ miAutoPosFormula = pFormulaData->end();
+ miAutoPosFormula = findTextAll(*pFormulaData, miAutoPosFormula, aText, aNewVec, false);
+ if (miAutoPosFormula != pFormulaData->end())
+ {
+ // check if partial function name is not between quotes
+ sal_Unicode cBetweenQuotes = 0;
+ for ( int n = 0; n < aSelText.getLength(); n++ )
+ {
+ if (cBetweenQuotes)
+ {
+ if (aSelText[n] == cBetweenQuotes)
+ cBetweenQuotes = 0;
+ }
+ else if ( aSelText[ n ] == '"' )
+ cBetweenQuotes = '"';
+ else if ( aSelText[ n ] == '\'' )
+ cBetweenQuotes = '\'';
+ }
+ if ( cBetweenQuotes )
+ return; // we're between quotes
+
+ ShowFuncList(aNewVec);
+ aAutoSearch = aText;
+ }
+ return;
+ }
+
+ // function name is complete:
+ // show tip below the cell with function name and arguments of function
+ ShowArgumentsTip( aSelText );
+}
+
+void ScInputHandler::NextFormulaEntry( bool bBack )
+{
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( pActiveView && pFormulaData )
+ {
+ ::std::vector<OUString> aNewVec;
+ ScTypedCaseStrSet::const_iterator itNew = findTextAll(*pFormulaData, miAutoPosFormula, aAutoSearch, aNewVec, bBack);
+ if (itNew != pFormulaData->end())
+ {
+ miAutoPosFormula = itNew;
+ ShowFuncList( aNewVec );
+ }
+ }
+
+ // For Tab we always call HideCursor first
+ if (pActiveView)
+ pActiveView->ShowCursor();
+}
+
+namespace {
+
+void completeFunction( EditView* pView, const OUString& rInsert, bool& rParInserted )
+{
+ if (!pView)
+ return;
+
+ ESelection aSel = pView->GetSelection();
+
+ bool bNoInitialLetter = false;
+ OUString aOld = pView->GetEditEngine()->GetText(0);
+ // in case we want just insert a function and not completing
+ if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ ESelection aSelRange = aSel;
+ --aSelRange.nStartPos;
+ --aSelRange.nEndPos;
+ pView->SetSelection(aSelRange);
+ pView->SelectCurrentWord();
+
+ if ( aOld == "=" )
+ {
+ bNoInitialLetter = true;
+ aSelRange.nStartPos = 1;
+ aSelRange.nEndPos = 1;
+ pView->SetSelection(aSelRange);
+ }
+ else if ( pView->GetSelected().startsWith("()") )
+ {
+ bNoInitialLetter = true;
+ ++aSelRange.nStartPos;
+ ++aSelRange.nEndPos;
+ pView->SetSelection(aSelRange);
+ }
+ }
+
+ if(!bNoInitialLetter)
+ {
+ const sal_Int32 nMinLen = std::max(aSel.nEndPos - aSel.nStartPos, sal_Int32(1));
+ // Since transliteration service is used to test for match, the replaced string could be
+ // longer than rInsert, so in order to find longest match before the cursor, test whole
+ // string from start to current cursor position (don't limit to length of rInsert)
+ // Disclaimer: I really don't know if a match longer than rInsert is actually possible,
+ // so the above is based on assumptions how "transliteration" might possibly work. If
+ // it's in fact impossible, an optimization would be useful to limit aSel.nStartPos to
+ // std::max(sal_Int32(0), aSel.nEndPos - rInsert.getLength()).
+ aSel.nStartPos = 0;
+ pView->SetSelection(aSel);
+ const OUString aAll = pView->GetSelected();
+ OUString aMatch;
+ for (sal_Int32 n = aAll.getLength(); n >= nMinLen && aMatch.isEmpty(); --n)
+ {
+ const OUString aTest = aAll.copy(aAll.getLength() - n); // n trailing chars
+ if (ScGlobal::GetTransliteration().isMatch(aTest, rInsert))
+ aMatch = aTest; // Found => break the loop
+ }
+
+ aSel.nStartPos = aSel.nEndPos - aMatch.getLength();
+ pView->SetSelection(aSel);
+ }
+
+ OUString aInsStr = rInsert;
+ sal_Int32 nInsLen = aInsStr.getLength();
+ bool bDoParen = ( nInsLen > 1 && aInsStr[nInsLen-2] == '('
+ && aInsStr[nInsLen-1] == ')' );
+ if ( bDoParen )
+ {
+ // Do not insert parentheses after function names if there already are some
+ // (e.g. if the function name was edited).
+ ESelection aWordSel = pView->GetSelection();
+
+ // aWordSel.EndPos points one behind string if word at end
+ if (aWordSel.nEndPos < aOld.getLength())
+ {
+ sal_Unicode cNext = aOld[aWordSel.nEndPos];
+ if ( cNext == '(' )
+ {
+ bDoParen = false;
+ aInsStr = aInsStr.copy( 0, nInsLen - 2 ); // Skip parentheses
+ }
+ }
+ }
+
+ pView->InsertText( aInsStr );
+
+ if ( bDoParen ) // Put cursor between parentheses
+ {
+ aSel = pView->GetSelection();
+ --aSel.nStartPos;
+ --aSel.nEndPos;
+ pView->SetSelection(aSel);
+
+ rParInserted = true;
+ }
+}
+
+}
+
+void ScInputHandler::PasteFunctionData()
+{
+ if (pFormulaData && miAutoPosFormula != pFormulaData->end())
+ {
+ const ScTypedStrData& rData = *miAutoPosFormula;
+ OUString aInsert = rData.GetString();
+ if (aInsert[aInsert.getLength()-1] == cParenthesesReplacement)
+ aInsert = OUString::Concat(aInsert.subView( 0, aInsert.getLength()-1)) + "()";
+ bool bParInserted = false;
+
+ DataChanging(); // Cannot be new
+ completeFunction( pTopView, aInsert, bParInserted );
+ completeFunction( pTableView, aInsert, bParInserted );
+ DataChanged();
+ ShowTipCursor();
+
+ if (bParInserted)
+ AutoParAdded();
+ }
+
+ HideTip();
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (comphelper::LibreOfficeKit::isActive() && pTopView && pInputWin)
+ pInputWin->TextGrabFocus();
+ if (pActiveView)
+ pActiveView->ShowCursor();
+}
+
+void ScInputHandler::LOKPasteFunctionData(const OUString& rFunctionName)
+{
+ // in case we have no top view try to create it
+ if (!pTopView && pInputWin)
+ {
+ ScInputMode eCurMode = eMode;
+ SetMode(SC_INPUT_TOP);
+ if (!pTopView)
+ SetMode(eCurMode);
+ }
+
+ EditView* pEditView = pTopView ? pTopView : pTableView;
+
+ if (!pActiveViewSh || !pEditView)
+ return;
+
+ bool bEdit = false;
+ OUString aFormula;
+ const EditEngine* pEditEngine = pEditView->GetEditEngine();
+ if (pEditEngine)
+ {
+ aFormula = pEditEngine->GetText(0);
+ /* TODO: LOK: are you sure you want '+' and '-' let start formulas with
+ * function names? That was meant for "data typist" numeric keyboard
+ * input. */
+ bEdit = aFormula.getLength() > 1 && (aFormula[0] == '=' || aFormula[0] == '+' || aFormula[0] == '-');
+ }
+
+ if ( !bEdit )
+ {
+ OUString aNewFormula('=');
+ if ( aFormula.startsWith("=") )
+ aNewFormula = aFormula;
+
+ InputReplaceSelection( aNewFormula );
+ }
+
+ if (pFormulaData)
+ {
+ OUString aNew;
+ ScTypedCaseStrSet::const_iterator aPos = findText(*pFormulaData, pFormulaData->begin(), rFunctionName, aNew, /* backward = */false);
+
+ if (aPos != pFormulaData->end())
+ {
+ miAutoPosFormula = aPos;
+ PasteFunctionData();
+ }
+ }
+}
+
+void ScInputHandler::LOKSendFormulabarUpdate(const SfxViewShell* pActiveViewSh,
+ const OUString& rText,
+ const ESelection& rSelection)
+{
+ OUString aSelection =
+ OUString::number(rSelection.nStartPos) + ";" + OUString::number(rSelection.nEndPos);
+
+ std::unique_ptr<jsdialog::ActionDataMap> pData = std::make_unique<jsdialog::ActionDataMap>();
+ (*pData)["action_type"] = "setText";
+ (*pData)["text"] = rText;
+ (*pData)["selection"] = aSelection;
+
+ sal_uInt64 nCurrentShellId = reinterpret_cast<sal_uInt64>(pActiveViewSh);
+ std::string sWindowId = std::to_string(nCurrentShellId) + "formulabar";
+ jsdialog::SendAction(sWindowId, "sc_input_window", std::move(pData));
+}
+
+// Calculate selection and display as tip help
+static OUString lcl_Calculate( const OUString& rFormula, ScDocument& rDoc, const ScAddress &rPos )
+{
+ //TODO: Merge with ScFormulaDlg::CalcValue and move into Document!
+ // Quotation marks for Strings are only inserted here.
+
+ if(rFormula.isEmpty())
+ return OUString();
+
+ std::optional<ScSimpleFormulaCalculator> pCalc( std::in_place, rDoc, rPos, rFormula, false );
+
+ // FIXME: HACK! In order to not get a #REF! for ColRowNames, if a name is actually inserted as a Range
+ // into the whole Formula, but is interpreted as a single cell reference when displaying it on its own
+ bool bColRowName = pCalc->HasColRowName();
+ if ( bColRowName )
+ {
+ // ColRowName in RPN code?
+ if ( pCalc->GetCode()->GetCodeLen() <= 1 )
+ { // ==1: Single one is as a Parameter always a Range
+ // ==0: It might be one, if ...
+ OUString aBraced = "(" + rFormula + ")";
+ pCalc.emplace( rDoc, rPos, aBraced, false );
+ }
+ else
+ bColRowName = false;
+ }
+
+ FormulaError nErrCode = pCalc->GetErrCode();
+ if ( nErrCode != FormulaError::NONE )
+ return ScGlobal::GetErrorString(nErrCode);
+
+ SvNumberFormatter& aFormatter = *rDoc.GetFormatTable();
+ OUString aValue;
+ if ( pCalc->IsValue() )
+ {
+ double n = pCalc->GetValue();
+ sal_uInt32 nFormat = aFormatter.GetStandardFormat( n, 0,
+ pCalc->GetFormatType(), ScGlobal::eLnge );
+ aFormatter.GetInputLineString( n, nFormat, aValue );
+ //! display OutputString but insert InputLineString
+ }
+ else
+ {
+ OUString aStr = pCalc->GetString().getString();
+ sal_uInt32 nFormat = aFormatter.GetStandardFormat(
+ pCalc->GetFormatType(), ScGlobal::eLnge);
+ {
+ const Color* pColor;
+ aFormatter.GetOutputString( aStr, nFormat,
+ aValue, &pColor );
+ }
+
+ aValue = "\"" + aValue + "\"";
+ //! Escape quotation marks in String??
+ }
+
+ ScRange aTestRange;
+ if ( bColRowName || (aTestRange.Parse(rFormula, rDoc) & ScRefFlags::VALID) )
+ aValue += " ...";
+
+ return aValue;
+}
+
+void ScInputHandler::FormulaPreview()
+{
+ OUString aValue;
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( pActiveView && pActiveViewSh )
+ {
+ OUString aPart = pActiveView->GetSelected();
+ if (aPart.isEmpty())
+ aPart = mpEditEngine->GetText(0);
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+ aValue = lcl_Calculate( aPart, rDoc, aCursorPos );
+ }
+
+ if (!aValue.isEmpty())
+ {
+ ShowTip( aValue ); // Display as QuickHelp
+ aManualTip = aValue; // Set after ShowTip
+ if (pFormulaData)
+ miAutoPosFormula = pFormulaData->end();
+ if (pColumnData)
+ miAutoPosColumn = pColumnData->end();
+ }
+}
+
+void ScInputHandler::PasteManualTip()
+{
+ // Three dots at the end -> Range reference -> do not insert
+ // FIXME: Once we have matrix constants, we can change this
+ sal_Int32 nTipLen = aManualTip.getLength();
+ sal_uInt32 const nTipLen2(sal::static_int_cast<sal_uInt32>(nTipLen));
+ if ( nTipLen && ( nTipLen < 3 || aManualTip.subView( nTipLen2-3 ) != u"..." ) )
+ {
+ DataChanging(); // Cannot be new
+
+ OUString aInsert = aManualTip;
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (!pActiveView->HasSelection())
+ {
+ // Nothing selected -> select everything
+ sal_Int32 nOldLen = mpEditEngine->GetTextLen(0);
+ ESelection aAllSel( 0, 0, 0, nOldLen );
+ if ( pTopView )
+ pTopView->SetSelection( aAllSel );
+ if ( pTableView )
+ pTableView->SetSelection( aAllSel );
+ }
+
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+ OSL_ENSURE( !aSel.nStartPara && !aSel.nEndPara, "Too many paragraphs in Formula" );
+ if ( !aSel.nStartPos ) // Selection from the start?
+ {
+ if ( aSel.nEndPos == mpEditEngine->GetTextLen(0) )
+ {
+ // Everything selected -> skip quotation marks
+ if ( aInsert[0] == '"' )
+ aInsert = aInsert.copy(1);
+ sal_Int32 nInsLen = aInsert.getLength();
+ if ( aInsert.endsWith("\"") )
+ aInsert = aInsert.copy( 0, nInsLen-1 );
+ }
+ else if ( aSel.nEndPos )
+ {
+ // Not everything selected -> do not overwrite equality sign
+ //FIXME: Even double equality signs??
+ aSel.nStartPos = 1;
+ if ( pTopView )
+ pTopView->SetSelection( aSel );
+ if ( pTableView )
+ pTableView->SetSelection( aSel );
+ }
+ }
+ if ( pTopView )
+ pTopView->InsertText( aInsert, true );
+ if ( pTableView )
+ pTableView->InsertText( aInsert, true );
+
+ DataChanged();
+ }
+
+ HideTip();
+}
+
+void ScInputHandler::ResetAutoPar()
+{
+ nAutoPar = 0;
+}
+
+void ScInputHandler::AutoParAdded()
+{
+ ++nAutoPar; // Closing parenthesis can be overwritten
+}
+
+bool ScInputHandler::CursorAtClosingPar()
+{
+ // Test if the cursor is before a closing parenthesis
+ // Selection from SetReference has been removed before
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( pActiveView && !pActiveView->HasSelection() && bFormulaMode )
+ {
+ ESelection aSel = pActiveView->GetSelection();
+ sal_Int32 nPos = aSel.nStartPos;
+ OUString aFormula = mpEditEngine->GetText(0);
+ if ( nPos < aFormula.getLength() && aFormula[nPos] == ')' )
+ return true;
+ }
+ return false;
+}
+
+void ScInputHandler::SkipClosingPar()
+{
+ // this is called when a ')' is typed and the cursor is before a ')'
+ // that can be overwritten -> just set the cursor behind the ')'
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (pActiveView)
+ {
+ ESelection aSel = pActiveView->GetSelection();
+ ++aSel.nStartPos;
+ ++aSel.nEndPos;
+
+ // this is in a formula (only one paragraph), so the selection
+ // can be used directly for the TopView
+
+ if ( pTopView )
+ pTopView->SetSelection( aSel );
+ if ( pTableView )
+ pTableView->SetSelection( aSel );
+ }
+
+ OSL_ENSURE(nAutoPar, "SkipClosingPar: count is wrong");
+ --nAutoPar;
+}
+
+// Auto input
+
+void ScInputHandler::GetColData()
+{
+ if ( !pActiveViewSh )
+ return;
+
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+
+ if ( pColumnData )
+ pColumnData->clear();
+ else
+ pColumnData.reset( new ScTypedCaseStrSet );
+
+ std::vector<ScTypedStrData> aEntries;
+ rDoc.GetDataEntries(
+ aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(), aEntries);
+ if (!aEntries.empty())
+ pColumnData->insert(aEntries.begin(), aEntries.end());
+
+ miAutoPosColumn = pColumnData->end();
+}
+
+void ScInputHandler::UseColData() // When typing
+{
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( !(pActiveView && pColumnData) )
+ return;
+
+ // Only change when cursor is at the end
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+
+ sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
+ if ( aSel.nEndPara+1 != nParCnt )
+ return;
+
+ sal_Int32 nParLen = mpEditEngine->GetTextLen( aSel.nEndPara );
+ if ( aSel.nEndPos != nParLen )
+ return;
+
+ OUString aText = GetEditText(mpEditEngine.get());
+ if (aText.isEmpty())
+ return;
+
+ std::vector< OUString > aResultVec;
+ OUString aNew;
+ sal_Int32 nLongestPrefixLen = 0;
+ miAutoPosColumn = pColumnData->end();
+ mbPartialPrefix = false;
+ miAutoPosColumn = findTextAll(*pColumnData, miAutoPosColumn, aText, aResultVec, false, &nLongestPrefixLen);
+
+ if (nLongestPrefixLen <= 0 || aResultVec.empty())
+ return;
+
+ if (aResultVec.size() > 1)
+ {
+ mbPartialPrefix = true;
+ bUseTab = true; // Allow Ctrl (+ Shift + ) + TAB cycling.
+ miAutoPosColumn = pColumnData->end();
+
+ // Display the rest of longest common prefix as suggestion.
+ aNew = aResultVec[0].copy(0, nLongestPrefixLen);
+ }
+ else
+ {
+ aNew = aResultVec[0];
+ }
+
+ // Strings can contain line endings (e.g. due to dBase import),
+ // which would result in multiple paragraphs here, which is not desirable.
+ //! Then GetExactMatch doesn't work either
+ lcl_RemoveLineEnd( aNew );
+
+ // Keep paragraph, just append the rest
+ //! Exact replacement in EnterHandler !!!
+ // One Space between paragraphs:
+ sal_Int32 nEdLen = mpEditEngine->GetTextLen() + nParCnt - 1;
+ OUString aIns = aNew.copy(nEdLen);
+
+ // Selection must be "backwards", so the cursor stays behind the last
+ // typed character
+ ESelection aSelection( aSel.nEndPara, aSel.nEndPos + aIns.getLength(),
+ aSel.nEndPara, aSel.nEndPos );
+
+ // When editing in input line, apply to both edit views
+ if ( pTableView )
+ {
+ pTableView->InsertText( aIns );
+ pTableView->SetSelection( aSelection );
+ }
+ if ( pTopView )
+ {
+ pTopView->InsertText( aIns );
+ pTopView->SetSelection( aSelection );
+ }
+
+ aAutoSearch = aText; // To keep searching - nAutoPos is set
+}
+
+void ScInputHandler::NextAutoEntry( bool bBack )
+{
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if ( pActiveView && pColumnData )
+ {
+ if (!aAutoSearch.isEmpty())
+ {
+ // Is the selection still valid (could be changed via the mouse)?
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+ sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
+ if ( aSel.nEndPara+1 == nParCnt && aSel.nStartPara == aSel.nEndPara )
+ {
+ OUString aText = GetEditText(mpEditEngine.get());
+ sal_Int32 nSelLen = aSel.nEndPos - aSel.nStartPos;
+ sal_Int32 nParLen = mpEditEngine->GetTextLen( aSel.nEndPara );
+ if ( aSel.nEndPos == nParLen && aText.getLength() == aAutoSearch.getLength() + nSelLen )
+ {
+ OUString aNew;
+ ScTypedCaseStrSet::const_iterator itNew =
+ findText(*pColumnData, miAutoPosColumn, aAutoSearch, aNew, bBack);
+
+ if (itNew != pColumnData->end())
+ {
+ // match found!
+ miAutoPosColumn = itNew;
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+ mbPartialPrefix = false;
+
+ lcl_RemoveLineEnd( aNew );
+ OUString aIns = aNew.copy(aAutoSearch.getLength());
+
+ // when editing in input line, apply to both edit views
+ if ( pTableView )
+ {
+ pTableView->DeleteSelected();
+ pTableView->InsertText( aIns );
+ pTableView->SetSelection( ESelection(
+ aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
+ aSel.nEndPara, aSel.nStartPos ) );
+ }
+ if ( pTopView )
+ {
+ pTopView->DeleteSelected();
+ pTopView->InsertText( aIns );
+ pTopView->SetSelection( ESelection(
+ aSel.nEndPara, aSel.nStartPos + aIns.getLength(),
+ aSel.nEndPara, aSel.nStartPos ) );
+ }
+
+ bInOwnChange = false;
+ }
+ }
+ }
+ }
+ }
+
+ // For Tab, HideCursor was always called first
+ if (pActiveView)
+ pActiveView->ShowCursor();
+}
+
+// Highlight parentheses
+void ScInputHandler::UpdateParenthesis()
+{
+ // Find parentheses
+ //TODO: Can we disable parentheses highlighting per parentheses?
+ bool bFound = false;
+ if ( bFormulaMode && eMode != SC_INPUT_TOP )
+ {
+ if ( pTableView && !pTableView->HasSelection() ) // Selection is always at the bottom
+ {
+ ESelection aSel = pTableView->GetSelection();
+ if (aSel.nStartPos)
+ {
+ // Examine character left to the cursor
+ sal_Int32 nPos = aSel.nStartPos - 1;
+ OUString aFormula = mpEditEngine->GetText(aSel.nStartPara);
+ sal_Unicode c = aFormula[nPos];
+ if ( c == '(' || c == ')' )
+ {
+ // Note this matches only within one paragraph.
+ sal_Int32 nOther = lcl_MatchParenthesis( aFormula, nPos );
+ if ( nOther != -1 )
+ {
+ SfxItemSet aSet( mpEditEngine->GetEmptyItemSet() );
+ aSet.Put( SvxWeightItem( WEIGHT_BOLD, EE_CHAR_WEIGHT ) );
+
+ //! Distinguish if cell is already highlighted!!!!
+ if (bParenthesisShown)
+ {
+ // Remove old highlighting
+ sal_Int32 nCount = mpEditEngine->GetParagraphCount();
+ for (sal_Int32 i=0; i<nCount; i++)
+ mpEditEngine->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
+ }
+
+ ESelection aSelThis( aSel.nStartPara, nPos, aSel.nStartPara, nPos+1);
+ mpEditEngine->QuickSetAttribs( aSet, aSelThis );
+ ESelection aSelOther( aSel.nStartPara, nOther, aSel.nStartPara, nOther+1);
+ mpEditEngine->QuickSetAttribs( aSet, aSelOther );
+
+ // Dummy InsertText for Update and Paint (selection is empty)
+ pTableView->InsertText( OUString() );
+
+ bFound = true;
+ }
+ }
+ }
+
+ // mark parenthesis right of cursor if it will be overwritten (nAutoPar)
+ // with different color (COL_LIGHTBLUE) ??
+ }
+ }
+
+ // Remove old highlighting, if no new one is set
+ if ( bParenthesisShown && !bFound && pTableView )
+ {
+ sal_Int32 nCount = mpEditEngine->GetParagraphCount();
+ for (sal_Int32 i=0; i<nCount; i++)
+ pTableView->RemoveCharAttribs( i, EE_CHAR_WEIGHT );
+ }
+
+ bParenthesisShown = bFound;
+}
+
+void ScInputHandler::ViewShellGone(const ScTabViewShell* pViewSh) // Executed synchronously!
+{
+ if ( pViewSh == pActiveViewSh )
+ {
+ pLastState.reset();
+ pLastPattern = nullptr;
+ }
+
+ if ( pViewSh == pRefViewSh )
+ {
+ //! The input from the EnterHandler does not arrive anymore
+ // We end the EditMode anyways
+ EnterHandler();
+ bFormulaMode = false;
+ pRefViewSh = nullptr;
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+ SC_MOD()->SetRefInputHdl(nullptr);
+ if (pInputWin)
+ pInputWin->SetFormulaMode(false);
+ UpdateAutoCorrFlag();
+ }
+
+ pActiveViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+
+ if ( pActiveViewSh && pActiveViewSh == pViewSh )
+ {
+ OSL_FAIL("pActiveViewSh is gone");
+ pActiveViewSh = nullptr;
+ }
+
+ if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
+ UpdateRefDevice(); // Don't keep old document's printer as RefDevice
+}
+
+void ScInputHandler::UpdateActiveView()
+{
+ ImplCreateEditEngine();
+
+ // #i20588# Don't rely on focus to find the active edit view. Instead, the
+ // active pane at the start of editing is now stored (GetEditActivePart).
+ // GetActiveWin (the currently active pane) fails for ref input across the
+ // panes of a split view.
+
+ vcl::Window* pShellWin = pActiveViewSh ?
+ pActiveViewSh->GetWindowByPos( pActiveViewSh->GetViewData().GetEditActivePart() ) :
+ nullptr;
+
+ sal_uInt16 nCount = mpEditEngine->GetViewCount();
+ if (nCount > 0)
+ {
+ pTableView = mpEditEngine->GetView();
+ for (sal_uInt16 i=1; i<nCount; i++)
+ {
+ EditView* pThis = mpEditEngine->GetView(i);
+ vcl::Window* pWin = pThis->GetWindow();
+ if ( pWin==pShellWin )
+ pTableView = pThis;
+ }
+ }
+ else
+ pTableView = nullptr;
+
+ // setup the pTableView editeng for tiled rendering to get cursor and selections
+ if (pTableView && pActiveViewSh)
+ {
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ pTableView->RegisterViewShell(pActiveViewSh);
+ }
+ }
+
+ if (pInputWin && (eMode == SC_INPUT_TOP || eMode == SC_INPUT_TABLE))
+ {
+ // tdf#71409: Always create the edit engine instance for the input
+ // window, in order to properly manage accessibility events.
+ pTopView = pInputWin->GetEditView();
+ if (eMode != SC_INPUT_TOP)
+ pTopView = nullptr;
+ }
+ else
+ pTopView = nullptr;
+}
+
+void ScInputHandler::SetInputWindow( ScInputWindow* pNew )
+{
+ pInputWin = pNew;
+}
+
+void ScInputHandler::StopInputWinEngine( bool bAll )
+{
+ if (pInputWin && !pInputWin->isDisposed())
+ pInputWin->StopEditEngine( bAll );
+
+ pTopView = nullptr; // invalid now
+}
+
+EditView* ScInputHandler::GetActiveView()
+{
+ UpdateActiveView();
+ return pTopView ? pTopView : pTableView;
+}
+
+void ScInputHandler::ForgetLastPattern()
+{
+ pLastPattern = nullptr;
+ if ( !pLastState && pActiveViewSh )
+ pActiveViewSh->UpdateInputHandler( true ); // Get status again
+ else
+ NotifyChange( pLastState.get(), true );
+}
+
+void ScInputHandler::UpdateAdjust( sal_Unicode cTyped )
+{
+ SvxAdjust eSvxAdjust;
+ switch (eAttrAdjust)
+ {
+ case SvxCellHorJustify::Standard:
+ {
+ bool bNumber = false;
+ if (cTyped) // Restarted
+ bNumber = (cTyped>='0' && cTyped<='9'); // Only ciphers are numbers
+ else if ( pActiveViewSh )
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+ bNumber = ( rDoc.GetCellType( aCursorPos ) == CELLTYPE_VALUE );
+ }
+ eSvxAdjust = bNumber ? SvxAdjust::Right : SvxAdjust::Left;
+ }
+ break;
+ case SvxCellHorJustify::Block:
+ eSvxAdjust = SvxAdjust::Block;
+ break;
+ case SvxCellHorJustify::Center:
+ eSvxAdjust = SvxAdjust::Center;
+ break;
+ case SvxCellHorJustify::Right:
+ eSvxAdjust = SvxAdjust::Right;
+ break;
+ default: // SvxCellHorJustify::Left
+ eSvxAdjust = SvxAdjust::Left;
+ break;
+ }
+
+ bool bAsianVertical = pLastPattern &&
+ pLastPattern->GetItem( ATTR_STACKED ).GetValue() &&
+ pLastPattern->GetItem( ATTR_VERTICAL_ASIAN ).GetValue();
+ if ( bAsianVertical )
+ {
+ // Always edit at top of cell -> LEFT when editing vertically
+ eSvxAdjust = SvxAdjust::Left;
+ }
+
+ pEditDefaults->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
+ mpEditEngine->SetDefaults( *pEditDefaults );
+
+ if ( pActiveViewSh )
+ {
+ pActiveViewSh->GetViewData().SetEditAdjust( eSvxAdjust );
+ }
+ mpEditEngine->SetVertical( bAsianVertical );
+}
+
+void ScInputHandler::RemoveAdjust()
+{
+ // Delete hard alignment attributes
+ bool bUndo = mpEditEngine->IsUndoEnabled();
+ if ( bUndo )
+ mpEditEngine->EnableUndo( false );
+
+ // Non-default paragraph attributes (e.g. from clipboard)
+ // must be turned into character attributes
+ mpEditEngine->RemoveParaAttribs();
+
+ if ( bUndo )
+ mpEditEngine->EnableUndo( true );
+
+}
+
+void ScInputHandler::RemoveRangeFinder()
+{
+ // Delete pRangeFindList and colors
+ mpEditEngine->SetUpdateLayout(false);
+ sal_Int32 nCount = mpEditEngine->GetParagraphCount(); // Could just have been inserted
+ for (sal_Int32 i=0; i<nCount; i++)
+ mpEditEngine->RemoveCharAttribs( i, EE_CHAR_COLOR );
+ mpEditEngine->SetUpdateLayout(true);
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ pActiveView->ShowCursor( false );
+
+ DeleteRangeFinder(); // Deletes the list and the labels on the table
+}
+
+bool ScInputHandler::StartTable( sal_Unicode cTyped, bool bFromCommand, bool bInputActivated,
+ ScEditEngineDefaulter* pTopEngine )
+{
+ bool bNewTable = false;
+
+ if (bModified)
+ return false;
+
+ if (pActiveViewSh)
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocShell()->GetDocument();
+
+ if (!rDoc.ValidCol(aCursorPos.Col()))
+ return false;
+
+ ImplCreateEditEngine();
+ UpdateActiveView();
+ SyncViews();
+
+
+ const ScMarkData& rMark = pActiveViewSh->GetViewData().GetMarkData();
+ ScEditableTester aTester;
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ aTester.TestSelection( rDoc, rMark );
+ else
+ aTester.TestSelectedBlock(
+ rDoc, aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Col(), aCursorPos.Row(), rMark );
+
+ bool bStartInputMode = true;
+
+ if (!aTester.IsEditable())
+ {
+ bProtected = true;
+ // We allow read-only input mode activation regardless
+ // whether it's part of an array or not or whether explicit cell
+ // activation is requested (double-click or F2) or a click in input
+ // line.
+ bool bShowError = (!bInputActivated || !aTester.GetMessageId() || aTester.GetMessageId() != STR_PROTECTIONERR) &&
+ !pActiveViewSh->GetViewData().GetDocShell()->IsReadOnly();
+ if (bShowError)
+ {
+ eMode = SC_INPUT_NONE;
+ StopInputWinEngine( true );
+ UpdateFormulaMode();
+ if ( pActiveViewSh && ( !bFromCommand || !bCommandErrorShown ) )
+ {
+ // Prevent repeated error messages for the same cell from command events
+ // (for keyboard events, multiple messages are wanted).
+ // Set the flag before showing the error message because the command handler
+ // for the next IME command may be called when showing the dialog.
+ if ( bFromCommand )
+ bCommandErrorShown = true;
+
+ pActiveViewSh->GetActiveWin()->GrabFocus();
+ pActiveViewSh->ErrorMessage(aTester.GetMessageId());
+ }
+ bStartInputMode = false;
+ }
+ }
+
+ if (bStartInputMode)
+ {
+ // UpdateMode is enabled again in ScViewData::SetEditEngine (and not needed otherwise)
+ mpEditEngine->SetUpdateLayout( false );
+
+ // Take over attributes in EditEngine
+ const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(),
+ aCursorPos.Row(),
+ aCursorPos.Tab() );
+ if (pPattern != pLastPattern)
+ {
+ // Percent format?
+ const SfxItemSet& rAttrSet = pPattern->GetItemSet();
+
+ if ( const SfxUInt32Item* pItem = rAttrSet.GetItemIfSet( ATTR_VALUE_FORMAT ) )
+ {
+ sal_uInt32 nFormat = pItem->GetValue();
+ if (SvNumFormatType::PERCENT == rDoc.GetFormatTable()->GetType( nFormat ))
+ nCellPercentFormatDecSep = rDoc.GetFormatTable()->GetFormatDecimalSep( nFormat).toChar();
+ else
+ nCellPercentFormatDecSep = 0;
+ }
+ else
+ nCellPercentFormatDecSep = 0; // Default: no percent
+
+ // Validity specified?
+ if ( const SfxUInt32Item* pItem = rAttrSet.GetItemIfSet( ATTR_VALIDDATA ) )
+ nValidation = pItem->GetValue();
+ else
+ nValidation = 0;
+
+ // EditEngine Defaults
+ // In no case SetParaAttribs, because the EditEngine might already
+ // be filled (for Edit cells).
+ // SetParaAttribs would change the content.
+
+ //! The SetDefaults is now (since MUST/src602
+ //! EditEngine changes) implemented as a SetParaAttribs.
+ //! Any problems?
+
+ pPattern->FillEditItemSet( pEditDefaults.get() );
+ mpEditEngine->SetDefaults( *pEditDefaults );
+ pLastPattern = pPattern;
+ bLastIsSymbol = pPattern->IsSymbolFont();
+
+ // Background color must be known for automatic font color.
+ // For transparent cell background, the document background color must be used.
+
+ Color aBackCol = pPattern->GetItem( ATTR_BACKGROUND ).GetColor();
+ ScModule* pScMod = SC_MOD();
+ if ( aBackCol.IsTransparent() ||
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ aBackCol = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+ mpEditEngine->SetBackgroundColor( aBackCol );
+
+ // Adjustment
+ eAttrAdjust = pPattern->GetItem(ATTR_HOR_JUSTIFY).GetValue();
+ if ( eAttrAdjust == SvxCellHorJustify::Repeat &&
+ pPattern->GetItem(ATTR_LINEBREAK).GetValue() )
+ {
+ // #i31843# "repeat" with "line breaks" is treated as default alignment
+ eAttrAdjust = SvxCellHorJustify::Standard;
+ }
+ }
+
+ if (pTopEngine)
+ {
+ // Necessary to sync SvxAutoCorrect behavior. This has to be
+ // done before InitRangeFinder() below.
+ MergeLanguageAttributes( *pTopEngine);
+ }
+
+ // UpdateSpellSettings enables online spelling if needed
+ // -> also call if attributes are unchanged
+ UpdateSpellSettings( true ); // uses pLastPattern
+
+ // Fill EditEngine
+ OUString aStr;
+ if (bTextValid)
+ {
+ mpEditEngine->SetTextCurrentDefaults(aCurrentText);
+ aStr = aCurrentText;
+ bTextValid = false;
+ aCurrentText.clear();
+ }
+ else
+ aStr = GetEditText(mpEditEngine.get());
+
+ // cTyped!=0 is overtyping, not editing.
+ mbEditingExistingContent = !cTyped && !aStr.isEmpty();
+
+ if (aStr.startsWith("{=") && aStr.endsWith("}") ) // Matrix formula?
+ {
+ aStr = aStr.copy(1, aStr.getLength() -2);
+ mpEditEngine->SetTextCurrentDefaults(aStr);
+ if ( pInputWin )
+ pInputWin->SetTextString(aStr);
+ }
+
+ UpdateAdjust( cTyped );
+
+ if ( SC_MOD()->GetAppOptions().GetAutoComplete() )
+ GetColData();
+
+ if (!cTyped && !bCreatingFuncView && StartsLikeFormula(aStr))
+ InitRangeFinder(aStr); // Formula is being edited -> RangeFinder
+
+ bNewTable = true; // -> PostEditView Call
+ }
+ }
+
+ if (!bProtected && pInputWin)
+ pInputWin->SetOkCancelMode();
+
+ return bNewTable;
+}
+
+void ScInputHandler::MergeLanguageAttributes( ScEditEngineDefaulter& rDestEngine ) const
+{
+ const SfxItemSet& rSrcSet = mpEditEngine->GetDefaults();
+ rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE ));
+ rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE_CJK ));
+ rDestEngine.SetDefaultItem( rSrcSet.Get( EE_CHAR_LANGUAGE_CTL ));
+}
+
+static void lcl_SetTopSelection( EditView* pEditView, ESelection& rSel )
+{
+ OSL_ENSURE( rSel.nStartPara==0 && rSel.nEndPara==0, "SetTopSelection: Para != 0" );
+
+ EditEngine* pEngine = pEditView->GetEditEngine();
+ sal_Int32 nCount = pEngine->GetParagraphCount();
+ if (nCount > 1)
+ {
+ sal_Int32 nParLen = pEngine->GetTextLen(rSel.nStartPara);
+ while (rSel.nStartPos > nParLen && rSel.nStartPara+1 < nCount)
+ {
+ rSel.nStartPos -= nParLen + 1; // Including space from line break
+ nParLen = pEngine->GetTextLen(++rSel.nStartPara);
+ }
+
+ nParLen = pEngine->GetTextLen(rSel.nEndPara);
+ while (rSel.nEndPos > nParLen && rSel.nEndPara+1 < nCount)
+ {
+ rSel.nEndPos -= nParLen + 1; // Including space from line break
+ nParLen = pEngine->GetTextLen(++rSel.nEndPara);
+ }
+ }
+
+ ESelection aSel = pEditView->GetSelection();
+
+ if ( rSel.nStartPara != aSel.nStartPara || rSel.nEndPara != aSel.nEndPara
+ || rSel.nStartPos != aSel.nStartPos || rSel.nEndPos != aSel.nEndPos )
+ pEditView->SetSelection( rSel );
+}
+
+void ScInputHandler::SyncViews( const EditView* pSourceView )
+{
+ if (pSourceView)
+ {
+ bool bSelectionForTopView = false;
+ if (pTopView && pTopView != pSourceView)
+ bSelectionForTopView = true;
+ bool bSelectionForTableView = false;
+ if (pTableView && pTableView != pSourceView)
+ bSelectionForTableView = true;
+ if (bSelectionForTopView || bSelectionForTableView)
+ {
+ ESelection aSel(pSourceView->GetSelection());
+ if (bSelectionForTopView)
+ pTopView->SetSelection(aSel);
+ if (bSelectionForTableView)
+ lcl_SetTopSelection(pTableView, aSel);
+ }
+ }
+ // Only sync selection from topView if we are actually editing there
+ else if (pTopView && pTableView)
+ {
+ ESelection aSel(pTopView->GetSelection());
+ lcl_SetTopSelection( pTableView, aSel );
+ }
+}
+
+IMPL_LINK_NOARG(ScInputHandler, ModifyHdl, LinkParamNone*, void)
+{
+ if ( !bInOwnChange && ( eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE ) &&
+ mpEditEngine && mpEditEngine->IsUpdateLayout() && pInputWin )
+ {
+ // Update input line from ModifyHdl for changes that are not
+ // wrapped by DataChanging/DataChanged calls (like Drag&Drop)
+ OUString aText(ScEditUtil::GetMultilineString(*mpEditEngine));
+ lcl_RemoveTabs(aText);
+ pInputWin->SetTextString(aText);
+ }
+}
+
+/**
+ * @return true means new view created
+ */
+bool ScInputHandler::DataChanging( sal_Unicode cTyped, bool bFromCommand )
+{
+ if (pActiveViewSh)
+ pActiveViewSh->GetViewData().SetPasteMode( ScPasteFlags::NONE );
+ bInOwnChange = true; // disable ModifyHdl (reset in DataChanged)
+
+ if ( eMode == SC_INPUT_NONE )
+ return StartTable( cTyped, bFromCommand, false, nullptr );
+ else
+ return false;
+}
+
+void ScInputHandler::DataChanged( bool bFromTopNotify, bool bSetModified )
+{
+ ImplCreateEditEngine();
+
+ if (eMode==SC_INPUT_NONE)
+ eMode = SC_INPUT_TYPE;
+
+ if ( eMode == SC_INPUT_TOP && pTopView && !bFromTopNotify )
+ {
+ // table EditEngine is formatted below, input line needs formatting after paste
+ // #i20282# not when called from the input line's modify handler
+ pTopView->GetEditEngine()->QuickFormatDoc( true );
+
+ // #i23720# QuickFormatDoc hides the cursor, but can't show it again because it
+ // can't safely access the EditEngine's current view, so the cursor has to be
+ // shown again here.
+ pTopView->ShowCursor();
+ }
+
+ if (bSetModified)
+ bModified = true;
+ bSelIsRef = false;
+
+ if ( pRangeFindList && !bInRangeUpdate )
+ RemoveRangeFinder(); // Delete attributes and labels
+
+ UpdateParenthesis(); // Highlight parentheses anew
+
+ if (eMode==SC_INPUT_TYPE || eMode==SC_INPUT_TABLE)
+ {
+ OUString aText;
+ if (pInputWin)
+ aText = ScEditUtil::GetMultilineString(*mpEditEngine);
+ else
+ aText = GetEditText(mpEditEngine.get());
+ lcl_RemoveTabs(aText);
+
+ if ( pInputWin )
+ pInputWin->SetTextString( aText );
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (pActiveViewSh)
+ {
+ // TODO: deprecated?
+ pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_FORMULA, aText.toUtf8().getStr());
+ }
+ }
+ }
+
+ // If the cursor is before the end of a paragraph, parts are being pushed to
+ // the right (independently from the eMode) -> Adapt View!
+ // If the cursor is at the end, the StatusHandler of the ViewData is sufficient.
+ //
+ // First make sure the status handler is called now if the cursor
+ // is outside the visible area
+ mpEditEngine->QuickFormatDoc();
+
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ ESelection aSel;
+ if (pActiveView && pActiveViewSh)
+ {
+ ScViewData& rViewData = pActiveViewSh->GetViewData();
+
+ bool bNeedGrow = ( rViewData.GetEditAdjust() != SvxAdjust::Left ); // Always right-aligned
+ if (!bNeedGrow)
+ {
+ // Cursor before the end?
+ aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+ bNeedGrow = ( aSel.nEndPos != mpEditEngine->GetTextLen(aSel.nEndPara) );
+ }
+ if (!bNeedGrow)
+ {
+ bNeedGrow = rViewData.GetDocument().IsLayoutRTL( rViewData.GetTabNo() );
+ }
+ if (bNeedGrow)
+ {
+ // Adjust inplace view
+ rViewData.EditGrowY();
+ rViewData.EditGrowX();
+ }
+ }
+
+ if (comphelper::LibreOfficeKit::isActive() && pActiveViewSh && pInputWin)
+ {
+ ScInputHandler::LOKSendFormulabarUpdate(pActiveViewSh,
+ ScEditUtil::GetMultilineString(*mpEditEngine),
+ aSel);
+ }
+
+ UpdateFormulaMode();
+ bTextValid = false; // Changes only in the EditEngine
+ bInOwnChange = false;
+}
+
+bool ScInputHandler::StartsLikeFormula( std::u16string_view rStr ) const
+{
+ // For new input '+' and '-' may start the dreaded "lazy data typist"
+ // formula input, editing existing formula content can only start with '='.
+ return !rStr.empty() && (rStr[0] == '=' || (!mbEditingExistingContent && (rStr[0] == '+' || rStr[0] == '-')));
+}
+
+void ScInputHandler::UpdateFormulaMode()
+{
+ SfxApplication* pSfxApp = SfxGetpApp();
+
+ bool bIsFormula = !bProtected;
+ if (bIsFormula)
+ {
+ const OUString& rText = mpEditEngine->GetText(0);
+ bIsFormula = StartsLikeFormula(rText);
+ }
+
+ if ( bIsFormula )
+ {
+ if (!bFormulaMode)
+ {
+ bFormulaMode = true;
+ pRefViewSh = pActiveViewSh;
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+ ScModule* pMod = SC_MOD();
+ pMod->SetRefInputHdl(this);
+ if (pInputWin)
+ pInputWin->SetFormulaMode(true);
+
+ // in LOK, we always need to perform the GetFormulaData() call so
+ // that the formula insertion works
+ if (comphelper::LibreOfficeKit::isActive() || pMod->GetAppOptions().GetAutoComplete())
+ GetFormulaData();
+
+ UpdateParenthesis();
+ UpdateAutoCorrFlag();
+ }
+ }
+ else // Deactivate
+ {
+ if (bFormulaMode)
+ {
+ ShowRefFrame();
+ bFormulaMode = false;
+ pRefViewSh = nullptr;
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+ SC_MOD()->SetRefInputHdl(nullptr);
+ if (pInputWin)
+ pInputWin->SetFormulaMode(false);
+ UpdateAutoCorrFlag();
+ }
+ }
+}
+
+void ScInputHandler::ShowRefFrame()
+{
+ // Modifying pActiveViewSh here would interfere with the bInEnterHandler / bRepeat
+ // checks in NotifyChange, and lead to keeping the wrong value in pActiveViewSh.
+ // A local variable is used instead.
+ ScTabViewShell* pVisibleSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( !(pRefViewSh && pRefViewSh != pVisibleSh) )
+ return;
+
+ bool bFound = false;
+ SfxViewFrame* pRefFrame = pRefViewSh->GetViewFrame();
+ SfxViewFrame* pOneFrame = SfxViewFrame::GetFirst();
+ while ( pOneFrame && !bFound )
+ {
+ if ( pOneFrame == pRefFrame )
+ bFound = true;
+ pOneFrame = SfxViewFrame::GetNext( *pOneFrame );
+ }
+
+ if (bFound)
+ {
+ // We count on Activate working synchronously here
+ // (pActiveViewSh is set while doing so)
+ pRefViewSh->SetActive(); // Appear and SetViewFrame
+
+ // pLastState is set correctly in the NotifyChange from the Activate
+ }
+ else
+ {
+ OSL_FAIL("ViewFrame for reference input is not here anymore");
+ }
+}
+
+void ScInputHandler::RemoveSelection()
+{
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (!pActiveView)
+ return;
+
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.nStartPara = aSel.nEndPara;
+ aSel.nStartPos = aSel.nEndPos;
+ if (pTableView)
+ pTableView->SetSelection( aSel );
+ if (pTopView)
+ pTopView->SetSelection( aSel );
+}
+
+void ScInputHandler::InvalidateAttribs()
+{
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (!pViewFrm)
+ return;
+
+ SfxBindings& rBindings = pViewFrm->GetBindings();
+
+ rBindings.Invalidate( SID_ATTR_CHAR_FONT );
+ rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
+
+ rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
+ rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
+ rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
+ rBindings.Invalidate( SID_ATTR_CHAR_OVERLINE );
+ rBindings.Invalidate( SID_ULINE_VAL_NONE );
+ rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
+
+ rBindings.Invalidate( SID_HYPERLINK_GETLINK );
+
+ rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
+ rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
+ rBindings.Invalidate( SID_SET_SUB_SCRIPT );
+ rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
+ rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
+
+ rBindings.Invalidate( SID_SAVEDOC );
+ rBindings.Invalidate( SID_DOC_MODIFIED );
+}
+
+// --------------- public methods --------------------------------------------
+
+void ScInputHandler::SetMode( ScInputMode eNewMode, const OUString* pInitText, ScEditEngineDefaulter* pTopEngine )
+{
+ if ( eMode == eNewMode )
+ return;
+
+ ImplCreateEditEngine();
+
+ if (bProtected)
+ {
+ eMode = SC_INPUT_NONE;
+ StopInputWinEngine( true );
+ if (pActiveViewSh)
+ pActiveViewSh->GetActiveWin()->GrabFocus();
+ return;
+ }
+
+ if (eNewMode != SC_INPUT_NONE && pActiveViewSh)
+ // Disable paste mode when edit mode starts.
+ pActiveViewSh->GetViewData().SetPasteMode( ScPasteFlags::NONE );
+
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+
+ ScInputMode eOldMode = eMode;
+ eMode = eNewMode;
+ if (eOldMode == SC_INPUT_TOP && eNewMode != eOldMode)
+ StopInputWinEngine( false );
+
+ if (eMode==SC_INPUT_TOP || eMode==SC_INPUT_TABLE)
+ {
+ if (eOldMode == SC_INPUT_NONE) // not if switching between modes
+ {
+ if (StartTable(0, false, eMode == SC_INPUT_TABLE, pTopEngine))
+ {
+ if (pActiveViewSh)
+ pActiveViewSh->GetViewData().GetDocShell()->PostEditView( mpEditEngine.get(), aCursorPos );
+ }
+ }
+
+ if (pInitText)
+ {
+ mpEditEngine->SetTextCurrentDefaults(*pInitText);
+ bModified = true;
+ }
+
+ sal_Int32 nPara = mpEditEngine->GetParagraphCount()-1;
+ sal_Int32 nLen = mpEditEngine->GetText(nPara).getLength();
+ sal_uInt16 nCount = mpEditEngine->GetViewCount();
+
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ if ( eMode == SC_INPUT_TABLE && eOldMode == SC_INPUT_TOP )
+ {
+ // Keep Selection
+ }
+ else
+ {
+ mpEditEngine->GetView(i)->
+ SetSelection( ESelection( nPara, nLen, nPara, nLen ) );
+ }
+ mpEditEngine->GetView(i)->ShowCursor(false);
+ }
+ }
+
+ UpdateActiveView();
+ if (eMode==SC_INPUT_TABLE || eMode==SC_INPUT_TYPE)
+ {
+ if (pTableView)
+ pTableView->SetEditEngineUpdateLayout(true);
+ }
+ else
+ {
+ if (pTopView)
+ pTopView->SetEditEngineUpdateLayout(true);
+ }
+
+ if (eNewMode != eOldMode)
+ UpdateFormulaMode();
+
+ bInOwnChange = false;
+}
+
+/**
+ * @return true if rString only contains digits (no autocorrect then)
+ */
+static bool lcl_IsNumber(const OUString& rString)
+{
+ sal_Int32 nLen = rString.getLength();
+ for (sal_Int32 i=0; i<nLen; i++)
+ {
+ sal_Unicode c = rString[i];
+ if ( c < '0' || c > '9' )
+ return false;
+ }
+ return true;
+}
+
+static void lcl_SelectionToEnd( EditView* pView )
+{
+ if ( pView )
+ {
+ EditEngine* pEngine = pView->GetEditEngine();
+ sal_Int32 nParCnt = pEngine->GetParagraphCount();
+ if ( nParCnt == 0 )
+ nParCnt = 1;
+ ESelection aSel( nParCnt-1, pEngine->GetTextLen(nParCnt-1) ); // empty selection, cursor at the end
+ pView->SetSelection( aSel );
+ }
+}
+
+void ScInputHandler::EnterHandler( ScEnterMode nBlockMode, bool bBeforeSavingInLOK )
+{
+ if (!mbDocumentDisposing && comphelper::LibreOfficeKit::isActive()
+ && pActiveViewSh != SfxViewShell::Current())
+ return;
+
+ // Macro calls for validity can cause a lot of problems, so inhibit
+ // nested calls of EnterHandler().
+ if (bInEnterHandler) return;
+ bInEnterHandler = true;
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+ mbPartialPrefix = false;
+
+ ImplCreateEditEngine();
+
+ bool bMatrix = ( nBlockMode == ScEnterMode::MATRIX );
+
+ SfxApplication* pSfxApp = SfxGetpApp();
+ std::unique_ptr<EditTextObject> pObject;
+ std::unique_ptr<ScPatternAttr> pCellAttrs;
+ bool bForget = false; // Remove due to validity?
+
+ OUString aString = GetEditText(mpEditEngine.get());
+ OUString aPreAutoCorrectString(aString);
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ if (bModified && pActiveView && !aString.isEmpty() && !lcl_IsNumber(aString))
+ {
+ if (pColumnData && miAutoPosColumn != pColumnData->end())
+ {
+ // #i47125# If AutoInput appended something, do the final AutoCorrect
+ // with the cursor at the end of the input.
+ lcl_SelectionToEnd(pTopView);
+ lcl_SelectionToEnd(pTableView);
+ }
+
+ vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : nullptr;
+
+ if (pTopView)
+ pTopView->CompleteAutoCorrect(); // CompleteAutoCorrect for both Views
+ if (pTableView)
+ pTableView->CompleteAutoCorrect(pFrameWin);
+ aString = GetEditText(mpEditEngine.get());
+ }
+ lcl_RemoveTabs(aString);
+ lcl_RemoveTabs(aPreAutoCorrectString);
+
+ // Test if valid (always with simple string)
+ if (bModified && nValidation && pActiveViewSh)
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocument();
+ const ScValidationData* pData = rDoc.GetValidationEntry( nValidation );
+ if (pData && pData->HasErrMsg())
+ {
+ // #i67990# don't use pLastPattern in EnterHandler
+ const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
+
+ bool bOk;
+
+ if (pData->GetDataMode() == SC_VALID_CUSTOM)
+ {
+ bOk = pData->IsDataValidCustom( aString, *pPattern, aCursorPos, ScValidationData::CustomValidationPrivateAccess() );
+ }
+ else
+ {
+ bOk = pData->IsDataValid( aString, *pPattern, aCursorPos );
+ }
+
+ if (!bOk)
+ {
+ pActiveViewSh->StopMarking(); // (the InfoBox consumes the MouseButtonUp)
+
+ // tdf#125917 Release the grab that a current mouse-down event being handled
+ // by ScTabView has put on the mouse via its SelectionEngine.
+ // Otherwise the warning box cannot interact with the mouse
+ if (ScTabView* pView = pActiveViewSh->GetViewData().GetView())
+ {
+ if (ScViewSelectionEngine* pSelEngine = pView->GetSelEngine())
+ pSelEngine->ReleaseMouse();
+ }
+
+ if (bBeforeSavingInLOK)
+ {
+ // Invalid entry but not applied to the document model.
+ // Exit to complete the "save", leaving the edit view as it is
+ // for the user to continue after save.
+ bInOwnChange = false;
+ bInEnterHandler = false;
+ return;
+ }
+
+ if (pData->DoError(pActiveViewSh->GetFrameWeld(), aString, aCursorPos))
+ bForget = true; // Do not take over input
+ }
+ }
+ }
+
+ // Check for input into DataPilot table
+ if ( bModified && pActiveViewSh && !bForget )
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocument();
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
+ if ( pDPObj )
+ {
+ // Any input within the DataPilot table is either a valid renaming
+ // or an invalid action - normal cell input is always aborted
+ pActiveViewSh->DataPilotInput( aCursorPos, aString );
+ bForget = true;
+ }
+ }
+
+ std::vector<editeng::MisspellRanges> aMisspellRanges;
+ // UpdateLayout must be true during CompleteOnlineSpelling
+ const bool bUpdateLayout = mpEditEngine->SetUpdateLayout( true );
+ mpEditEngine->CompleteOnlineSpelling();
+ bool bSpellErrors = !bFormulaMode && mpEditEngine->HasOnlineSpellErrors();
+ if ( bSpellErrors )
+ {
+ // #i3820# If the spell checker flags numerical input as error,
+ // it still has to be treated as number, not EditEngine object.
+ if ( pActiveViewSh )
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocument();
+ // #i67990# don't use pLastPattern in EnterHandler
+ const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab() );
+ if (pPattern)
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ // without conditional format, as in ScColumn::SetString
+ sal_uInt32 nFormat = pPattern->GetNumberFormat( pFormatter );
+ double nVal;
+ if ( pFormatter->IsNumberFormat( aString, nFormat, nVal ) )
+ {
+ bSpellErrors = false; // ignore the spelling errors
+ }
+ }
+ }
+ }
+
+ // After RemoveAdjust, the EditView must not be repainted (has wrong font size etc).
+ // SetUpdateLayout must come after CompleteOnlineSpelling.
+ // The view is hidden in any case below (Broadcast).
+ mpEditEngine->SetUpdateLayout( false );
+
+ if ( bModified && !bForget ) // What is being entered (text/object)?
+ {
+ sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
+ if ( nParCnt == 0 )
+ nParCnt = 1;
+
+ bool bUniformAttribs = true;
+ SfxItemSet aPara1Attribs = mpEditEngine->GetAttribs(0, 0, mpEditEngine->GetTextLen(0));
+ for (sal_Int32 nPara = 1; nPara < nParCnt; ++nPara)
+ {
+ SfxItemSet aPara2Attribs = mpEditEngine->GetAttribs(nPara, 0, mpEditEngine->GetTextLen(nPara));
+ if (!(aPara1Attribs == aPara2Attribs))
+ {
+ // Paragraph format different from that of the 1st paragraph.
+ bUniformAttribs = false;
+ break;
+ }
+ }
+
+ ESelection aSel( 0, 0, nParCnt-1, mpEditEngine->GetTextLen(nParCnt-1) );
+ SfxItemSet aOldAttribs = mpEditEngine->GetAttribs( aSel );
+ const SfxPoolItem* pItem = nullptr;
+
+ // Find common (cell) attributes before RemoveAdjust
+ if ( pActiveViewSh && bUniformAttribs )
+ {
+ std::optional<SfxItemSet> pCommonAttrs;
+ for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END; nId++)
+ {
+ SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
+ if ( eState == SfxItemState::SET &&
+ nId != EE_CHAR_ESCAPEMENT && nId != EE_CHAR_PAIRKERNING &&
+ nId != EE_CHAR_KERNING && nId != EE_CHAR_XMLATTRIBS &&
+ *pItem != pEditDefaults->Get(nId) )
+ {
+ if ( !pCommonAttrs )
+ pCommonAttrs.emplace( mpEditEngine->GetEmptyItemSet() );
+ pCommonAttrs->Put( *pItem );
+ }
+ }
+
+ if ( pCommonAttrs )
+ {
+ ScDocument& rDoc = pActiveViewSh->GetViewData().GetDocument();
+ pCellAttrs = std::make_unique<ScPatternAttr>(rDoc.GetPool());
+ pCellAttrs->GetFromEditItemSet( &*pCommonAttrs );
+ }
+ }
+
+ // Clear ParaAttribs (including adjustment)
+ RemoveAdjust();
+
+ bool bAttrib = false; // Formatting present?
+
+ // check if EditObject is needed
+ if (nParCnt > 1)
+ bAttrib = true;
+ else
+ {
+ for (sal_uInt16 nId = EE_CHAR_START; nId <= EE_CHAR_END && !bAttrib; nId++)
+ {
+ SfxItemState eState = aOldAttribs.GetItemState( nId, false, &pItem );
+ if (eState == SfxItemState::DONTCARE)
+ bAttrib = true;
+ else if (eState == SfxItemState::SET)
+ {
+ // Keep same items in EditEngine as in ScEditAttrTester
+ if ( nId == EE_CHAR_ESCAPEMENT || nId == EE_CHAR_PAIRKERNING ||
+ nId == EE_CHAR_KERNING || nId == EE_CHAR_XMLATTRIBS )
+ {
+ if ( *pItem != pEditDefaults->Get(nId) )
+ bAttrib = true;
+ }
+ }
+ }
+
+ // Contains fields?
+ SfxItemState eFieldState = aOldAttribs.GetItemState( EE_FEATURE_FIELD, false );
+ if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
+ bAttrib = true;
+
+ // Not converted characters?
+ SfxItemState eConvState = aOldAttribs.GetItemState( EE_FEATURE_NOTCONV, false );
+ if ( eConvState == SfxItemState::DONTCARE || eConvState == SfxItemState::SET )
+ bAttrib = true;
+
+ // Always recognize formulas as formulas
+ // We still need the preceding test due to cell attributes
+ }
+
+ if (bSpellErrors)
+ mpEditEngine->GetAllMisspellRanges(aMisspellRanges);
+
+ if (bMatrix)
+ bAttrib = false;
+
+ if (bAttrib)
+ {
+ mpEditEngine->ClearSpellErrors();
+ pObject = mpEditEngine->CreateTextObject();
+ }
+ else if (SC_MOD()->GetAppOptions().GetAutoComplete()) // Adjust Upper/Lower case
+ {
+ // Perform case-matching only when the typed text is partial.
+ if (pColumnData && aAutoSearch.getLength() < aString.getLength())
+ aString = getExactMatch(*pColumnData, aString);
+ }
+ }
+
+ // Don't rely on ShowRefFrame switching the active view synchronously
+ // execute the function directly on the correct view's bindings instead
+ // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
+ ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
+
+ if (bFormulaMode)
+ {
+ ShowRefFrame();
+
+ if (pExecuteSh)
+ {
+ pExecuteSh->SetTabNo(aCursorPos.Tab());
+ pExecuteSh->ActiveGrabFocus();
+ }
+
+ bFormulaMode = false;
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+ SC_MOD()->SetRefInputHdl(nullptr);
+ if (pInputWin)
+ pInputWin->SetFormulaMode(false);
+ UpdateAutoCorrFlag();
+ }
+ pRefViewSh = nullptr; // Also without FormulaMode due to FunctionsAutoPilot
+ DeleteRangeFinder();
+ ResetAutoPar();
+
+ bool bOldMod = bModified;
+
+ bModified = false;
+ bSelIsRef = false;
+ eMode = SC_INPUT_NONE;
+ StopInputWinEngine(true);
+
+ // Text input (through number formats) or ApplySelectionPattern modify
+ // the cell's attributes, so pLastPattern is no longer valid
+ pLastPattern = nullptr;
+
+ if (bOldMod && !bProtected && !bForget)
+ {
+ bool bInsertPreCorrectedString = true;
+ // No typographic quotes in formulas
+ if (aString.startsWith("="))
+ {
+ SvxAutoCorrect* pAuto = SvxAutoCorrCfg::Get().GetAutoCorrect();
+ if ( pAuto )
+ {
+ bInsertPreCorrectedString = false;
+ OUString aReplace(pAuto->GetStartDoubleQuote());
+ if( aReplace.isEmpty() )
+ aReplace = ScGlobal::getLocaleData().getDoubleQuotationMarkStart();
+ if( aReplace != "\"" )
+ aString = aString.replaceAll( aReplace, "\"" );
+
+ aReplace = OUString(pAuto->GetEndDoubleQuote());
+ if( aReplace.isEmpty() )
+ aReplace = ScGlobal::getLocaleData().getDoubleQuotationMarkEnd();
+ if( aReplace != "\"" )
+ aString = aString.replaceAll( aReplace, "\"" );
+
+ aReplace = OUString(pAuto->GetStartSingleQuote());
+ if( aReplace.isEmpty() )
+ aReplace = ScGlobal::getLocaleData().getQuotationMarkStart();
+ if( aReplace != "'" )
+ aString = aString.replaceAll( aReplace, "'" );
+
+ aReplace = OUString(pAuto->GetEndSingleQuote());
+ if( aReplace.isEmpty() )
+ aReplace = ScGlobal::getLocaleData().getQuotationMarkEnd();
+ if( aReplace != "'" )
+ aString = aString.replaceAll( aReplace, "'");
+ }
+ }
+
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditViewNoPaint ) );
+
+ if ( pExecuteSh )
+ {
+ SfxBindings& rBindings = pExecuteSh->GetViewFrame()->GetBindings();
+
+ sal_uInt16 nId = FID_INPUTLINE_ENTER;
+ if ( nBlockMode == ScEnterMode::BLOCK )
+ nId = FID_INPUTLINE_BLOCK;
+ else if ( nBlockMode == ScEnterMode::MATRIX )
+ nId = FID_INPUTLINE_MATRIX;
+
+ const SfxPoolItem* aArgs[2];
+ aArgs[1] = nullptr;
+
+ if ( bInsertPreCorrectedString && aString != aPreAutoCorrectString )
+ {
+ ScInputStatusItem aItem(FID_INPUTLINE_STATUS,
+ aCursorPos, aCursorPos, aCursorPos,
+ aPreAutoCorrectString, pObject.get());
+ aArgs[0] = &aItem;
+ rBindings.Execute(nId, aArgs);
+ }
+
+ ScInputStatusItem aItemCorrected(FID_INPUTLINE_STATUS,
+ aCursorPos, aCursorPos, aCursorPos,
+ aString, pObject.get());
+ if ( !aMisspellRanges.empty() )
+ aItemCorrected.SetMisspellRanges(&aMisspellRanges);
+
+ aArgs[0] = &aItemCorrected;
+ rBindings.Execute(nId, aArgs);
+ }
+
+ pLastState.reset(); // pLastState still contains the old text
+ }
+ else
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
+
+ if ( bOldMod && pExecuteSh && pCellAttrs && !bForget )
+ {
+ // Combine with input?
+ pExecuteSh->ApplySelectionPattern( *pCellAttrs, true );
+ pExecuteSh->AdjustBlockHeight();
+ }
+
+ HideTip();
+ HideTipBelow();
+
+ nFormSelStart = nFormSelEnd = 0;
+ aFormText.clear();
+
+ mbEditingExistingContent = false;
+ bInOwnChange = false;
+ bInEnterHandler = false;
+ if (bUpdateLayout)
+ mpEditEngine->SetUpdateLayout( true );
+}
+
+void ScInputHandler::CancelHandler()
+{
+ bInOwnChange = true; // Also without FormulaMode due to FunctionsAutoPilot
+
+ ImplCreateEditEngine();
+
+ bModified = false;
+ mbPartialPrefix = false;
+ mbEditingExistingContent = false;
+
+ // Don't rely on ShowRefFrame switching the active view synchronously
+ // execute the function directly on the correct view's bindings instead
+ // pRefViewSh is reset in ShowRefFrame - get pointer before ShowRefFrame call
+ ScTabViewShell* pExecuteSh = pRefViewSh ? pRefViewSh : pActiveViewSh;
+
+ if (bFormulaMode)
+ {
+ ShowRefFrame();
+ if (pExecuteSh)
+ {
+ pExecuteSh->SetTabNo(aCursorPos.Tab());
+ pExecuteSh->ActiveGrabFocus();
+ }
+ bFormulaMode = false;
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+ SC_MOD()->SetRefInputHdl(nullptr);
+ if (pInputWin)
+ pInputWin->SetFormulaMode(false);
+ UpdateAutoCorrFlag();
+ }
+ pRefViewSh = nullptr; // Also without FormulaMode due to FunctionsAutoPilot
+ DeleteRangeFinder();
+ ResetAutoPar();
+
+ eMode = SC_INPUT_NONE;
+ StopInputWinEngine( true );
+ if (pExecuteSh)
+ pExecuteSh->StopEditShell();
+
+ aCursorPos.Set(pExecuteSh->GetViewData().GetDocument().MaxCol()+1,0,0); // Invalid flag
+ mpEditEngine->SetTextCurrentDefaults(OUString());
+
+ if ( !pLastState && pExecuteSh )
+ pExecuteSh->UpdateInputHandler( true ); // Update status again
+ else
+ NotifyChange( pLastState.get(), true );
+
+ nFormSelStart = nFormSelEnd = 0;
+ aFormText.clear();
+
+ bInOwnChange = false;
+
+ if ( comphelper::LibreOfficeKit::isActive() && pExecuteSh )
+ {
+ // Clear
+ std::vector<ReferenceMark> aReferenceMarks;
+ ScInputHandler::SendReferenceMarks( pActiveViewSh, aReferenceMarks );
+ }
+}
+
+bool ScInputHandler::IsModalMode( const SfxObjectShell* pDocSh )
+{
+ // References to unnamed document; that doesn't work
+ return bFormulaMode && pRefViewSh
+ && pRefViewSh->GetViewData().GetDocument().GetDocumentShell() != pDocSh
+ && !pDocSh->HasName();
+}
+
+void ScInputHandler::AddRefEntry()
+{
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ UpdateActiveView();
+ if (!pTableView && !pTopView)
+ return; // E.g. FillMode
+
+ DataChanging(); // Cannot be new
+
+ RemoveSelection();
+ OUString aText = GetEditText(mpEditEngine.get());
+ sal_Unicode cLastChar = 0;
+ sal_Int32 nPos = aText.getLength() - 1;
+ while (nPos >= 0) //checking space
+ {
+ cLastChar = aText[nPos];
+ if (cLastChar != ' ')
+ break;
+ --nPos;
+ }
+
+ bool bAppendSeparator = (cLastChar != '(' && cLastChar != cSep && cLastChar != '=');
+ if (bAppendSeparator)
+ {
+ if (pTableView)
+ pTableView->InsertText( OUString(cSep) );
+ if (pTopView)
+ pTopView->InsertText( OUString(cSep) );
+ }
+
+ DataChanged();
+}
+
+void ScInputHandler::SetReference( const ScRange& rRef, const ScDocument& rDoc )
+{
+ HideTip();
+
+ const ScDocument* pThisDoc = nullptr;
+ if (pRefViewSh)
+ pThisDoc = &pRefViewSh->GetViewData().GetDocument();
+ bool bOtherDoc = (pThisDoc != &rDoc);
+ if (bOtherDoc && !rDoc.GetDocumentShell()->HasName())
+ {
+ // References to unnamed document; that doesn't work
+ // SetReference should not be called, then
+ return;
+ }
+ if (!pThisDoc)
+ pThisDoc = &rDoc;
+
+ UpdateActiveView();
+ if (!pTableView && !pTopView)
+ return; // E.g. FillMode
+
+ // Never overwrite the "="!
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ ESelection aSel = pActiveView->GetSelection();
+ aSel.Adjust();
+ if ( aSel.nStartPara == 0 && aSel.nStartPos == 0 )
+ return;
+
+ DataChanging(); // Cannot be new
+
+ // Turn around selection if backwards.
+ if (pTableView)
+ {
+ ESelection aTabSel = pTableView->GetSelection();
+ if (aTabSel.nStartPos > aTabSel.nEndPos && aTabSel.nStartPara == aTabSel.nEndPara)
+ {
+ aTabSel.Adjust();
+ pTableView->SetSelection(aTabSel);
+ }
+ }
+ if (pTopView)
+ {
+ ESelection aTopSel = pTopView->GetSelection();
+ if (aTopSel.nStartPos > aTopSel.nEndPos && aTopSel.nStartPara == aTopSel.nEndPara)
+ {
+ aTopSel.Adjust();
+ pTopView->SetSelection(aTopSel);
+ }
+ }
+
+ // Create string from reference, in the syntax of the document being edited.
+ OUString aRefStr;
+ const ScAddress::Details aAddrDetails( *pThisDoc, aCursorPos );
+ if (bOtherDoc)
+ {
+ // Reference to other document
+ OSL_ENSURE(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab");
+
+ // Always 3D and absolute.
+ OUString aTmp(rRef.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D, aAddrDetails));
+
+ SfxObjectShell* pObjSh = rDoc.GetDocumentShell();
+ // #i75893# convert escaped URL of the document to something user friendly
+ OUString aFileName = pObjSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+
+ switch(aAddrDetails.eConv)
+ {
+ case formula::FormulaGrammar::CONV_XL_A1 :
+ case formula::FormulaGrammar::CONV_XL_OOX :
+ case formula::FormulaGrammar::CONV_XL_R1C1 :
+ aRefStr = "[\'" + aFileName + "']";
+ break;
+ case formula::FormulaGrammar::CONV_OOO :
+ default:
+ aRefStr = "\'" + aFileName + "'#";
+ break;
+ }
+ aRefStr += aTmp;
+ }
+ else
+ {
+ if ( rRef.aStart.Tab() != aCursorPos.Tab() ||
+ rRef.aStart.Tab() != rRef.aEnd.Tab() )
+ // pointer-selected => absolute sheet reference
+ aRefStr = rRef.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D, aAddrDetails);
+ else
+ aRefStr = rRef.Format(rDoc, ScRefFlags::VALID, aAddrDetails);
+ }
+ bool bLOKShowSelect = true;
+ if(comphelper::LibreOfficeKit::isActive() && pRefViewSh->GetViewData().GetRefTabNo() != pRefViewSh->GetViewData().GetTabNo())
+ bLOKShowSelect = false;
+
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ pTableView->InsertText( aRefStr, true, bLOKShowSelect );
+ if (pTopView)
+ pTopView->InsertText( aRefStr, true, bLOKShowSelect );
+
+ DataChanged();
+ }
+
+ bSelIsRef = true;
+}
+
+void ScInputHandler::InsertFunction( const OUString& rFuncName, bool bAddPar )
+{
+ if ( eMode == SC_INPUT_NONE )
+ {
+ OSL_FAIL("InsertFunction, not during input mode");
+ return;
+ }
+
+ UpdateActiveView();
+ if (!pTableView && !pTopView)
+ return; // E.g. FillMode
+
+ DataChanging(); // Cannot be new
+
+ OUString aText = rFuncName;
+ if (bAddPar)
+ aText += "()";
+
+ if (pTableView)
+ {
+ pTableView->InsertText( aText );
+ if (bAddPar)
+ {
+ ESelection aSel = pTableView->GetSelection();
+ --aSel.nStartPos;
+ --aSel.nEndPos;
+ pTableView->SetSelection(aSel);
+ }
+ }
+ if (pTopView)
+ {
+ pTopView->InsertText( aText );
+ if (bAddPar)
+ {
+ ESelection aSel = pTopView->GetSelection();
+ --aSel.nStartPos;
+ --aSel.nEndPos;
+ pTopView->SetSelection(aSel);
+ }
+ }
+
+ DataChanged();
+
+ if (bAddPar)
+ AutoParAdded();
+}
+
+void ScInputHandler::ClearText()
+{
+ if ( eMode == SC_INPUT_NONE )
+ {
+ OSL_FAIL("ClearText, not during input mode");
+ return;
+ }
+
+ UpdateActiveView();
+ if (!pTableView && !pTopView)
+ return; // E.g. FillMode
+
+ DataChanging(); // Cannot be new
+
+ if (pTableView)
+ {
+ pTableView->GetEditEngine()->SetText( "" );
+ pTableView->SetSelection( ESelection(0,0, 0,0) );
+ }
+ if (pTopView)
+ {
+ pTopView->GetEditEngine()->SetText( "" );
+ pTopView->SetSelection( ESelection(0,0, 0,0) );
+ }
+
+ DataChanged();
+}
+
+bool ScInputHandler::KeyInput( const KeyEvent& rKEvt, bool bStartEdit /* = false */ )
+{
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+ sal_uInt16 nModi = aCode.GetModifier();
+ bool bShift = aCode.IsShift();
+ bool bControl = aCode.IsMod1();
+ bool bAlt = aCode.IsMod2();
+ sal_uInt16 nCode = aCode.GetCode();
+ sal_Unicode nChar = rKEvt.GetCharCode();
+
+ if (bAlt && !bControl && nCode != KEY_RETURN)
+ // Alt-Return and Alt-Ctrl-* are accepted. Everything else with ALT are not.
+ return false;
+
+ // There is a partial autocomplete suggestion.
+ // Allow its completion with right arrow key (without modifiers).
+ if (mbPartialPrefix && nCode == KEY_RIGHT && !bControl && !bShift && !bAlt &&
+ (pTopView || pTableView))
+ {
+ if (pTopView)
+ pTopView->PostKeyEvent(KeyEvent(0, css::awt::Key::MOVE_TO_END_OF_PARAGRAPH));
+ if (pTableView)
+ pTableView->PostKeyEvent(KeyEvent(0, css::awt::Key::MOVE_TO_END_OF_PARAGRAPH));
+
+ mbPartialPrefix = false;
+
+ // Indicate that this event has been consumed and ScTabViewShell should not act on this.
+ return true;
+ }
+
+ if (!bControl && nCode == KEY_TAB)
+ {
+ // Normal TAB moves the cursor right.
+ EnterHandler();
+
+ if (pActiveViewSh)
+ pActiveViewSh->FindNextUnprot( bShift, true );
+ return true;
+ }
+
+ bool bInputLine = ( eMode==SC_INPUT_TOP );
+
+ bool bUsed = false;
+ bool bSkip = false;
+ bool bDoEnter = false;
+
+ switch ( nCode )
+ {
+ case KEY_RETURN:
+ // New line when in the input line and Shift/Ctrl-Enter is pressed,
+ // or when in a cell and Ctrl-Enter is pressed.
+ if ((pInputWin && bInputLine && bControl != bShift) || (!bInputLine && bControl && !bShift))
+ {
+ bDoEnter = true;
+ }
+ else if (nModi == 0 && nTipVisible && pFormulaData && miAutoPosFormula != pFormulaData->end())
+ {
+ PasteFunctionData();
+ bUsed = true;
+ }
+ else if ( nModi == 0 && nTipVisible && !aManualTip.isEmpty() )
+ {
+ PasteManualTip();
+ bUsed = true;
+ }
+ else
+ {
+ ScEnterMode nMode = ScEnterMode::NORMAL;
+ if ( bShift && bControl )
+ nMode = ScEnterMode::MATRIX;
+ else if ( bAlt )
+ nMode = ScEnterMode::BLOCK;
+ EnterHandler( nMode );
+
+ if (pActiveViewSh)
+ pActiveViewSh->MoveCursorEnter( bShift && !bControl );
+
+ bUsed = true;
+ }
+ break;
+ case KEY_TAB:
+ if (bControl && !bAlt)
+ {
+ if (pFormulaData && nTipVisible && miAutoPosFormula != pFormulaData->end())
+ {
+ // Iterate
+ NextFormulaEntry( bShift );
+ bUsed = true;
+ }
+ else if (pColumnData && bUseTab)
+ {
+ // Iterate through AutoInput entries
+ NextAutoEntry( bShift );
+ bUsed = true;
+ }
+ }
+ break;
+ case KEY_ESCAPE:
+ if ( nTipVisible )
+ {
+ HideTip();
+ bUsed = true;
+ }
+ else if( nTipVisibleSec )
+ {
+ HideTipBelow();
+ bUsed = true;
+ }
+ else if (eMode != SC_INPUT_NONE)
+ {
+ CancelHandler();
+ bUsed = true;
+ }
+ else
+ bSkip = true;
+ break;
+ case KEY_F2:
+ if ( !bShift && !bControl && !bAlt && eMode == SC_INPUT_TABLE )
+ {
+ eMode = SC_INPUT_TYPE;
+ bUsed = true;
+ }
+ break;
+ }
+
+ // Only execute cursor keys if already in EditMode
+ // E.g. due to Shift-Ctrl-PageDn (not defined as an accelerator)
+ bool bCursorKey = EditEngine::DoesKeyMoveCursor(rKEvt);
+ bool bInsKey = ( nCode == KEY_INSERT && !nModi ); // Treat Insert like Cursorkeys
+ if ( !bUsed && !bSkip && ( bDoEnter || EditEngine::DoesKeyChangeText(rKEvt) ||
+ ( eMode != SC_INPUT_NONE && ( bCursorKey || bInsKey ) ) ) )
+ {
+ HideTip();
+ HideTipBelow();
+
+ if (bSelIsRef)
+ {
+ RemoveSelection();
+ bSelIsRef = false;
+ }
+
+ UpdateActiveView();
+ bool bNewView = DataChanging( nChar );
+
+ if (bProtected) // Protected cell?
+ bUsed = true; // Don't forward KeyEvent
+ else // Changes allowed
+ {
+ if (bNewView ) // Create anew
+ {
+ if (pActiveViewSh)
+ pActiveViewSh->GetViewData().GetDocShell()->PostEditView( mpEditEngine.get(), aCursorPos );
+ UpdateActiveView();
+ if (eMode==SC_INPUT_NONE)
+ if (pTableView || pTopView)
+ {
+ OUString aStrLoP;
+
+ if (bStartEdit && nCellPercentFormatDecSep != 0 &&
+ ((nChar >= '0' && nChar <= '9') || nChar == '-' || nChar == nCellPercentFormatDecSep))
+ {
+ aStrLoP = "%";
+ }
+
+ if (pTableView)
+ {
+ pTableView->GetEditEngine()->SetText( aStrLoP );
+ if ( !aStrLoP.isEmpty() )
+ pTableView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
+
+ // Don't call SetSelection if the string is empty anyway,
+ // to avoid breaking the bInitial handling in ScViewData::EditGrowY
+ }
+ if (pTopView)
+ {
+ pTopView->GetEditEngine()->SetText( aStrLoP );
+ if ( !aStrLoP.isEmpty() )
+ pTopView->SetSelection( ESelection(0,0, 0,0) ); // before the '%'
+ }
+ }
+ SyncViews();
+ }
+
+ if (pTableView || pTopView)
+ {
+ if (bDoEnter)
+ {
+ if (pTableView)
+ if( pTableView->PostKeyEvent( KeyEvent( '\r', vcl::KeyCode(KEY_RETURN) ) ) )
+ bUsed = true;
+ if (pTopView)
+ if( pTopView->PostKeyEvent( KeyEvent( '\r', vcl::KeyCode(KEY_RETURN) ) ) )
+ bUsed = true;
+ }
+ else if ( nAutoPar && nChar == ')' && CursorAtClosingPar() )
+ {
+ SkipClosingPar();
+ bUsed = true;
+ }
+ else
+ {
+ if (pTableView)
+ {
+ if (pTopView)
+ pTableView->SetControlWord(pTableView->GetControlWord() | EVControlBits::SINGLELINEPASTE);
+
+ vcl::Window* pFrameWin = pActiveViewSh ? pActiveViewSh->GetFrameWin() : nullptr;
+ if ( pTableView->PostKeyEvent( rKEvt, pFrameWin ) )
+ bUsed = true;
+
+ pTableView->SetControlWord(pTableView->GetControlWord() & ~EVControlBits::SINGLELINEPASTE);
+ }
+ if (pTopView)
+ {
+ if ( bUsed && rKEvt.GetKeyCode().GetFunction() == KeyFuncType::CUT )
+ pTopView->DeleteSelected();
+ else if ( pTopView->PostKeyEvent( rKEvt ) )
+ bUsed = true;
+ }
+ }
+
+ // AutoInput:
+ if ( bUsed && SC_MOD()->GetAppOptions().GetAutoComplete() )
+ {
+ bUseTab = false;
+ if (pFormulaData)
+ miAutoPosFormula = pFormulaData->end(); // do not search further
+ if (pColumnData)
+ miAutoPosColumn = pColumnData->end();
+
+ KeyFuncType eFunc = rKEvt.GetKeyCode().GetFunction();
+ if ( nChar && nChar != 8 && nChar != 127 && // no 'backspace', no 'delete'
+ KeyFuncType::CUT != eFunc) // and no 'CTRL-X'
+ {
+ if (bFormulaMode)
+ UseFormulaData();
+ else
+ UseColData();
+ }
+ }
+
+ // When the selection is changed manually or an opening parenthesis
+ // is typed, stop overwriting parentheses
+ if ( bUsed && nChar == '(' )
+ ResetAutoPar();
+
+ if ( KEY_INSERT == nCode )
+ {
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
+ }
+ if( bUsed && bFormulaMode && ( bCursorKey || bInsKey || nCode == KEY_DELETE || nCode == KEY_BACKSPACE ) )
+ {
+ ShowTipCursor();
+ }
+ if( bUsed && bFormulaMode && nCode == KEY_BACKSPACE )
+ {
+ UseFormulaData();
+ }
+
+ }
+
+ // #i114511# don't count cursor keys as modification
+ bool bSetModified = !bCursorKey;
+ DataChanged(false, bSetModified); // also calls UpdateParenthesis()
+
+ // In the LOK case, we want to set the document modified state
+ // right away at the start of the edit, so that the content is
+ // saved even when the user leaves the document before hitting
+ // Enter
+ if (comphelper::LibreOfficeKit::isActive() && bSetModified && pActiveViewSh && !pActiveViewSh->GetViewData().GetDocShell()->IsModified())
+ pActiveViewSh->GetViewData().GetDocShell()->SetModified();
+
+ InvalidateAttribs(); //! in DataChanged?
+ }
+ }
+
+ if (pTopView && eMode != SC_INPUT_NONE)
+ SyncViews();
+
+ return bUsed;
+}
+
+OUString ScInputHandler::GetSurroundingText()
+{
+ if (eMode != SC_INPUT_NONE)
+ {
+ UpdateActiveView();
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ return pTableView->GetSurroundingText();
+ else if (pTopView) // call only once
+ return pTopView->GetSurroundingText();
+ }
+ }
+ return OUString();
+}
+
+Selection ScInputHandler::GetSurroundingTextSelection()
+{
+ if (eMode != SC_INPUT_NONE)
+ {
+ UpdateActiveView();
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ return pTableView->GetSurroundingTextSelection();
+ else if (pTopView) // call only once
+ return pTopView->GetSurroundingTextSelection();
+ }
+ }
+ return Selection(0, 0);
+}
+
+bool ScInputHandler::DeleteSurroundingText(const Selection& rSelection)
+{
+ if (eMode != SC_INPUT_NONE)
+ {
+ UpdateActiveView();
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ return pTableView->DeleteSurroundingText(rSelection);
+ else if (pTopView) // call only once
+ return pTopView->DeleteSurroundingText(rSelection);
+ }
+ }
+ return false;
+}
+
+void ScInputHandler::InputCommand( const CommandEvent& rCEvt )
+{
+ if ( rCEvt.GetCommand() == CommandEventId::CursorPos )
+ {
+ // For CommandEventId::CursorPos, do as little as possible, because
+ // with remote VCL, even a ShowCursor will generate another event.
+ if ( eMode != SC_INPUT_NONE )
+ {
+ UpdateActiveView();
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ pTableView->Command( rCEvt );
+ else if (pTopView) // call only once
+ pTopView->Command( rCEvt );
+ }
+ }
+ }
+ else if ( rCEvt.GetCommand() == CommandEventId::QueryCharPosition )
+ {
+ if ( eMode != SC_INPUT_NONE )
+ {
+ UpdateActiveView();
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ pTableView->Command( rCEvt );
+ else if (pTopView) // call only once
+ pTopView->Command( rCEvt );
+ }
+ }
+ }
+ else
+ {
+ HideTip();
+ HideTipBelow();
+
+ if ( bSelIsRef )
+ {
+ RemoveSelection();
+ bSelIsRef = false;
+ }
+
+ UpdateActiveView();
+ bool bNewView = DataChanging( 0, true );
+
+ if (!bProtected) // changes allowed
+ {
+ if (bNewView) // create new edit view
+ {
+ if (pActiveViewSh)
+ pActiveViewSh->GetViewData().GetDocShell()->PostEditView( mpEditEngine.get(), aCursorPos );
+ UpdateActiveView();
+ if (eMode==SC_INPUT_NONE)
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ {
+ pTableView->GetEditEngine()->SetText( "" );
+ pTableView->SetSelection( ESelection(0,0, 0,0) );
+ }
+ if (pTopView)
+ {
+ pTopView->GetEditEngine()->SetText( "" );
+ pTopView->SetSelection( ESelection(0,0, 0,0) );
+ }
+ }
+ SyncViews();
+ }
+
+ if (pTableView || pTopView)
+ {
+ if (pTableView)
+ pTableView->Command( rCEvt );
+ if (pTopView && !comphelper::LibreOfficeKit::isActive())
+ pTopView->Command( rCEvt );
+
+ if ( rCEvt.GetCommand() == CommandEventId::EndExtTextInput )
+ {
+ // AutoInput after ext text input
+
+ if (pFormulaData)
+ miAutoPosFormula = pFormulaData->end();
+ if (pColumnData)
+ miAutoPosColumn = pColumnData->end();
+
+ if (bFormulaMode)
+ UseFormulaData();
+ else
+ UseColData();
+ }
+ }
+
+ DataChanged(); // calls UpdateParenthesis()
+ InvalidateAttribs(); //! in DataChanged ?
+ }
+
+ if (pTopView && eMode != SC_INPUT_NONE)
+ SyncViews();
+ }
+}
+
+void ScInputHandler::NotifyChange( const ScInputHdlState* pState,
+ bool bForce, ScTabViewShell* pSourceSh,
+ bool bStopEditing)
+{
+ // If the call originates from a macro call in the EnterHandler,
+ // return immediately and don't mess up the status
+ if (bInEnterHandler)
+ return;
+
+ bool bRepeat = (pState == pLastState.get());
+ if (!bRepeat && pState && pLastState)
+ bRepeat = (*pState == *pLastState);
+ if (bRepeat && !bForce)
+ return;
+
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+
+ if ( pState && !pLastState ) // Enable again
+ bForce = true;
+
+ bool bHadObject = pLastState && pLastState->GetEditData();
+
+ //! Before EditEngine gets eventually created (so it gets the right pools)
+ if ( pSourceSh )
+ pActiveViewSh = pSourceSh;
+ else
+ pActiveViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+
+ ImplCreateEditEngine();
+
+ if ( pState != pLastState.get() )
+ {
+ pLastState.reset( pState ? new ScInputHdlState( *pState ) : nullptr);
+ }
+
+ if ( pState && pActiveViewSh )
+ {
+ ScModule* pScMod = SC_MOD();
+
+ ScTabViewShell* pScTabViewShell = dynamic_cast<ScTabViewShell*>(pScMod->GetViewShell());
+
+ // Also take foreign reference input into account here (e.g. FunctionsAutoPilot),
+ // FormEditData, if we're switching from Help to Calc:
+ if ( !bFormulaMode && !pScMod->IsFormulaMode() &&
+ ( !pScTabViewShell || !pScTabViewShell->GetFormEditData() ) )
+ {
+ bool bIgnore = false;
+ if ( bModified )
+ {
+ if (pState->GetPos() != aCursorPos)
+ {
+ if (!bProtected)
+ EnterHandler();
+ }
+ else
+ bIgnore = true;
+ }
+
+ if ( !bIgnore )
+ {
+ const ScAddress& rSPos = pState->GetStartPos();
+ const ScAddress& rEPos = pState->GetEndPos();
+ const EditTextObject* pData = pState->GetEditData();
+ OUString aString = pState->GetString();
+ bool bTxtMod = false;
+ ScDocShell* pDocSh = pActiveViewSh->GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ aCursorPos = pState->GetPos();
+
+ if ( pData )
+ bTxtMod = true;
+ else if ( bHadObject )
+ bTxtMod = true;
+ else if ( bTextValid )
+ bTxtMod = ( aString != aCurrentText );
+ else
+ bTxtMod = ( aString != GetEditText(mpEditEngine.get()) );
+
+ if ( bTxtMod || bForce )
+ {
+ if (pData)
+ {
+ mpEditEngine->SetTextCurrentDefaults( *pData );
+ if (pInputWin)
+ aString = ScEditUtil::GetMultilineString(*mpEditEngine);
+ else
+ aString = GetEditText(mpEditEngine.get());
+ lcl_RemoveTabs(aString);
+ bTextValid = false;
+ aCurrentText.clear();
+ }
+ else
+ {
+ aCurrentText = aString;
+ bTextValid = true; //! To begin with remember as a string
+ }
+
+ if ( pInputWin )
+ pInputWin->SetTextString(aString);
+
+ if (comphelper::LibreOfficeKit::isActive() && pActiveViewSh)
+ {
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ ESelection aSel = pActiveView ? pActiveView->GetSelection() : ESelection();
+ ScInputHandler::LOKSendFormulabarUpdate(pActiveViewSh, aString, aSel);
+ // TODO: deprecated?
+ pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_FORMULA, aString.toUtf8().getStr());
+ }
+ }
+
+ if ( pInputWin || comphelper::LibreOfficeKit::isActive()) // Named range input
+ {
+ OUString aPosStr;
+ bool bSheetLocal = false;
+ const ScAddress::Details aAddrDetails( rDoc, aCursorPos );
+
+ // Is the range a name?
+ //! Find by Timer?
+ if ( pActiveViewSh )
+ pActiveViewSh->GetViewData().GetDocument().
+ GetRangeAtBlock( ScRange( rSPos, rEPos ), aPosStr, &bSheetLocal);
+
+ if ( aPosStr.isEmpty() ) // Not a name -> format
+ {
+ ScRefFlags nFlags = ScRefFlags::ZERO;
+ if( aAddrDetails.eConv == formula::FormulaGrammar::CONV_XL_R1C1 )
+ nFlags |= ScRefFlags::COL_ABS | ScRefFlags::ROW_ABS;
+ if ( rSPos != rEPos )
+ {
+ ScRange r(rSPos, rEPos);
+ applyStartToEndFlags(nFlags);
+ aPosStr = r.Format(rDoc, ScRefFlags::VALID | nFlags, aAddrDetails);
+ }
+ else
+ aPosStr = aCursorPos.Format(ScRefFlags::VALID | nFlags, &rDoc, aAddrDetails);
+ }
+ else if (bSheetLocal)
+ {
+ OUString aName;
+ if (rDoc.GetName( rSPos.Tab(), aName))
+ aPosStr = ScPosWnd::createLocalRangeName( aPosStr, aName);
+ }
+
+ if (pInputWin)
+ {
+ // Disable the accessible VALUE_CHANGE event
+ bool bIsSuppressed = pInputWin->IsAccessibilityEventsSuppressed(false);
+ pInputWin->SetAccessibilityEventsSuppressed(true);
+ pInputWin->SetPosString(aPosStr);
+ pInputWin->SetAccessibilityEventsSuppressed(bIsSuppressed);
+ pInputWin->SetSumAssignMode();
+ }
+
+ if (comphelper::LibreOfficeKit::isActive() && pActiveViewSh)
+ pActiveViewSh->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_ADDRESS, aPosStr.toUtf8().getStr());
+ }
+
+ if (bStopEditing) {
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
+
+ // As long as the content is not edited, turn off online spelling.
+ // Online spelling is turned back on in StartTable, after setting
+ // the right language from cell attributes.
+
+ EEControlBits nCntrl = mpEditEngine->GetControlWord();
+ if ( nCntrl & EEControlBits::ONLINESPELLING )
+ mpEditEngine->SetControlWord( nCntrl & ~EEControlBits::ONLINESPELLING );
+ }
+
+ bModified = false;
+ bSelIsRef = false;
+ bProtected = false;
+ bCommandErrorShown = false;
+ }
+ }
+
+ if ( pInputWin)
+ {
+ // Do not enable if RefDialog is open
+ if(!pScMod->IsFormulaMode()&& !pScMod->IsRefDialogOpen())
+ {
+ if ( !pInputWin->IsEnabled())
+ {
+ pDelayTimer->Stop();
+ pInputWin->Enable();
+ }
+ }
+ else if(pScMod->IsRefDialogOpen())
+ { // Because every document has its own InputWin,
+ // we should start Timer again, because the input line may
+ // still be active
+ if ( !pDelayTimer->IsActive() )
+ pDelayTimer->Start();
+ }
+ }
+ }
+ else // !pState || !pActiveViewSh
+ {
+ if ( !pDelayTimer->IsActive() )
+ pDelayTimer->Start();
+ }
+
+ HideTip();
+ HideTipBelow();
+ bInOwnChange = false;
+}
+
+void ScInputHandler::UpdateCellAdjust( SvxCellHorJustify eJust )
+{
+ eAttrAdjust = eJust;
+ UpdateAdjust( 0 );
+}
+
+void ScInputHandler::ResetDelayTimer()
+{
+ if( pDelayTimer->IsActive() )
+ {
+ pDelayTimer->Stop();
+ if ( pInputWin )
+ pInputWin->Enable();
+ }
+}
+
+IMPL_LINK_NOARG( ScInputHandler, DelayTimer, Timer*, void )
+{
+ if ( !(nullptr == pLastState || SC_MOD()->IsFormulaMode() || SC_MOD()->IsRefDialogOpen()))
+ return;
+
+ //! New method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if ( pViewFrm && pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
+ {
+ if ( pInputWin)
+ {
+ pInputWin->EnableButtons( false );
+ pInputWin->Disable();
+ }
+ }
+ else if ( !bFormulaMode ) // Keep formula e.g. for help
+ {
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+
+ pActiveViewSh = nullptr;
+ mpEditEngine->SetTextCurrentDefaults( OUString() );
+ if ( pInputWin )
+ {
+ pInputWin->SetPosString( OUString() );
+ pInputWin->SetTextString( OUString() );
+ pInputWin->Disable();
+ }
+
+ bInOwnChange = false;
+ }
+}
+
+void ScInputHandler::InputSelection( const EditView* pView )
+{
+ SyncViews( pView );
+ ShowTipCursor();
+ UpdateParenthesis(); // Selection changed -> update parentheses highlighting
+
+ // When the selection is changed manually, stop overwriting parentheses
+ ResetAutoPar();
+
+ if (comphelper::LibreOfficeKit::isActive() && pActiveViewSh)
+ {
+ EditView* pActiveView = pTopView ? pTopView : pTableView;
+ ESelection aSel = pActiveView ? pActiveView->GetSelection() : ESelection();
+ ScInputHandler::LOKSendFormulabarUpdate(pActiveViewSh, GetEditString(), aSel);
+ }
+}
+
+void ScInputHandler::InputChanged( const EditView* pView, bool bFromNotify )
+{
+ if ( !pView )
+ return;
+
+ UpdateActiveView();
+
+ // #i20282# DataChanged needs to know if this is from the input line's modify handler
+ bool bFromTopNotify = ( bFromNotify && pView == pTopView );
+
+ bool bNewView = DataChanging(); //FIXME: Is this at all possible?
+ aCurrentText = pView->GetEditEngine()->GetText(); // Also remember the string
+ mpEditEngine->SetTextCurrentDefaults( aCurrentText );
+ DataChanged( bFromTopNotify );
+ bTextValid = true; // Is set to false in DataChanged
+
+ if ( pActiveViewSh )
+ {
+ ScViewData& rViewData = pActiveViewSh->GetViewData();
+ if ( bNewView )
+ rViewData.GetDocShell()->PostEditView( mpEditEngine.get(), aCursorPos );
+
+ rViewData.EditGrowY();
+ rViewData.EditGrowX();
+ }
+
+ SyncViews( pView );
+}
+
+const OUString& ScInputHandler::GetEditString()
+{
+ if (mpEditEngine)
+ {
+ aCurrentText = mpEditEngine->GetText(); // Always new from Engine
+ bTextValid = true;
+ }
+
+ return aCurrentText;
+}
+
+Size ScInputHandler::GetTextSize()
+{
+ Size aSize;
+ if ( mpEditEngine )
+ aSize = Size( mpEditEngine->CalcTextWidth(), mpEditEngine->GetTextHeight() );
+
+ return aSize;
+}
+
+bool ScInputHandler::GetTextAndFields( ScEditEngineDefaulter& rDestEngine )
+{
+ bool bRet = false;
+ if (mpEditEngine)
+ {
+ // Contains field?
+ sal_Int32 nParCnt = mpEditEngine->GetParagraphCount();
+ SfxItemSet aSet = mpEditEngine->GetAttribs( ESelection(0,0,nParCnt,0) );
+ SfxItemState eFieldState = aSet.GetItemState( EE_FEATURE_FIELD, false );
+ if ( eFieldState == SfxItemState::DONTCARE || eFieldState == SfxItemState::SET )
+ {
+ // Copy content
+ std::unique_ptr<EditTextObject> pObj = mpEditEngine->CreateTextObject();
+ rDestEngine.SetTextCurrentDefaults(*pObj);
+ pObj.reset();
+
+ // Delete attributes
+ for (sal_Int32 i=0; i<nParCnt; i++)
+ rDestEngine.RemoveCharAttribs( i );
+
+ // Combine paragraphs
+ while ( nParCnt > 1 )
+ {
+ sal_Int32 nLen = rDestEngine.GetTextLen( 0 );
+ ESelection aSel( 0,nLen, 1,0 );
+ rDestEngine.QuickInsertText( OUString(' '), aSel ); // Replace line break with space
+ --nParCnt;
+ }
+
+ bRet = true;
+ }
+ }
+ return bRet;
+}
+
+/**
+ * Methods for FunctionAutoPilot:
+ * InputGetSelection, InputSetSelection, InputReplaceSelection, InputGetFormulaStr
+ */
+void ScInputHandler::InputGetSelection( sal_Int32& rStart, sal_Int32& rEnd )
+{
+ rStart = nFormSelStart;
+ rEnd = nFormSelEnd;
+}
+
+EditView* ScInputHandler::GetFuncEditView()
+{
+ UpdateActiveView(); // Due to pTableView
+
+ EditView* pView = nullptr;
+ if ( pInputWin )
+ {
+ pInputWin->MakeDialogEditView();
+ pView = pInputWin->GetEditView();
+ }
+ else
+ {
+ if ( eMode != SC_INPUT_TABLE )
+ {
+ bCreatingFuncView = true; // Don't display RangeFinder
+ SetMode( SC_INPUT_TABLE );
+ bCreatingFuncView = false;
+ if ( pTableView )
+ pTableView->GetEditEngine()->SetText( OUString() );
+ }
+ pView = pTableView;
+ }
+
+ return pView;
+}
+
+void ScInputHandler::InputSetSelection( sal_Int32 nStart, sal_Int32 nEnd )
+{
+ if ( nStart <= nEnd )
+ {
+ nFormSelStart = nStart;
+ nFormSelEnd = nEnd;
+ }
+ else
+ {
+ nFormSelEnd = nStart;
+ nFormSelStart = nEnd;
+ }
+
+ EditView* pView = GetFuncEditView();
+ if (pView)
+ pView->SetSelection( ESelection(0,nStart, 0,nEnd) );
+
+ bModified = true;
+}
+
+void ScInputHandler::InputReplaceSelection( const OUString& rStr )
+{
+ if (!pRefViewSh)
+ pRefViewSh = pActiveViewSh;
+
+ OSL_ENSURE(nFormSelEnd>=nFormSelStart,"Selection broken...");
+
+ sal_Int32 nOldLen = nFormSelEnd - nFormSelStart;
+ sal_Int32 nNewLen = rStr.getLength();
+
+ OUStringBuffer aBuf(aFormText);
+ if (nOldLen)
+ aBuf.remove(nFormSelStart, nOldLen);
+ if (nNewLen)
+ aBuf.insert(nFormSelStart, rStr);
+
+ aFormText = aBuf.makeStringAndClear();
+
+ nFormSelEnd = nFormSelStart + nNewLen;
+
+ EditView* pView = GetFuncEditView();
+ if (pView)
+ {
+ pView->SetEditEngineUpdateLayout( false );
+ pView->GetEditEngine()->SetText( aFormText );
+ pView->SetSelection( ESelection(0,nFormSelStart, 0,nFormSelEnd) );
+ pView->SetEditEngineUpdateLayout( true );
+ }
+ bModified = true;
+}
+
+void ScInputHandler::InputTurnOffWinEngine()
+{
+ bInOwnChange = true; // disable ModifyHdl (reset below)
+
+ eMode = SC_INPUT_NONE;
+ /* TODO: it would be better if there was some way to reset the input bar
+ * engine instead of deleting and having it recreate through
+ * GetFuncEditView(), but first least invasively let this fix fdo#71667 and
+ * fdo#72278 without reintroducing fdo#69971. */
+ StopInputWinEngine(true);
+
+ bInOwnChange = false;
+}
+
+/**
+ * ScInputHdlState
+ */
+ScInputHdlState::ScInputHdlState( const ScAddress& rCurPos,
+ const ScAddress& rStartPos,
+ const ScAddress& rEndPos,
+ const OUString& rString,
+ const EditTextObject* pData )
+ : aCursorPos ( rCurPos ),
+ aStartPos ( rStartPos ),
+ aEndPos ( rEndPos ),
+ aString ( rString ),
+ pEditData ( pData ? pData->Clone() : nullptr )
+{
+}
+
+ScInputHdlState::ScInputHdlState( const ScInputHdlState& rCpy )
+{
+ *this = rCpy;
+}
+
+ScInputHdlState::~ScInputHdlState()
+{
+}
+
+bool ScInputHdlState::operator==( const ScInputHdlState& r ) const
+{
+ return ( (aStartPos == r.aStartPos)
+ && (aEndPos == r.aEndPos)
+ && (aCursorPos == r.aCursorPos)
+ && (aString == r.aString)
+ && ScGlobal::EETextObjEqual( pEditData.get(), r.pEditData.get() ) );
+}
+
+ScInputHdlState& ScInputHdlState::operator=( const ScInputHdlState& r )
+{
+ if (this != &r)
+ {
+ aCursorPos = r.aCursorPos;
+ aStartPos = r.aStartPos;
+ aEndPos = r.aEndPos;
+ aString = r.aString;
+ pEditData.reset();
+ if (r.pEditData)
+ pEditData = r.pEditData->Clone();
+ }
+ return *this;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/inputwin.cxx b/sc/source/ui/app/inputwin.cxx
new file mode 100644
index 000000000..0b31b8160
--- /dev/null
+++ b/sc/source/ui/app/inputwin.cxx
@@ -0,0 +1,2703 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <algorithm>
+#include <string_view>
+
+#include <editeng/eeitem.hxx>
+
+#include <sfx2/app.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/langitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/event.hxx>
+#include <editeng/scriptspaceitem.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/help.hxx>
+#include <vcl/settings.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weldutils.hxx>
+#include <unotools/charclass.hxx>
+
+#include <inputwin.hxx>
+#include <scmod.hxx>
+#include <global.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <globstr.hrc>
+#include <bitmaps.hlst>
+#include <reffact.hxx>
+#include <editutil.hxx>
+#include <inputhdl.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <appoptio.hxx>
+#include <rangenam.hxx>
+#include <rangeutl.hxx>
+#include <docfunc.hxx>
+#include <funcdesc.hxx>
+#include <editeng/fontitem.hxx>
+#include <AccessibleEditObject.hxx>
+#include <AccessibleText.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/string.hxx>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <helpids.h>
+#include <output.hxx>
+
+namespace com::sun::star::accessibility { class XAccessible; }
+
+const tools::Long THESIZE = 1000000; // Should be more than enough!
+const tools::Long INPUTLINE_INSET_MARGIN = 2; // Space between border and interior widgets of input line
+const tools::Long LEFT_OFFSET = 5; // Left offset of input line
+//TODO const long BUTTON_OFFSET = 2; // Space between input line and button to expand/collapse
+const tools::Long INPUTWIN_MULTILINES = 6; // Initial number of lines within multiline dropdown
+const tools::Long TOOLBOX_WINDOW_HEIGHT = 22; // Height of toolbox window in pixels - TODO: The same on all systems?
+const tools::Long POSITION_COMBOBOX_WIDTH = 18; // Width of position combobox in characters
+const int RESIZE_HOTSPOT_HEIGHT = 4;
+
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::UNO_QUERY;
+
+using com::sun::star::frame::XLayoutManager;
+using com::sun::star::beans::XPropertySet;
+
+namespace {
+
+constexpr ToolBoxItemId SID_INPUT_FUNCTION (SC_VIEW_START + 47);
+constexpr ToolBoxItemId SID_INPUT_SUM (SC_VIEW_START + 48);
+constexpr ToolBoxItemId SID_INPUT_EQUAL (SC_VIEW_START + 49);
+constexpr ToolBoxItemId SID_INPUT_CANCEL (SC_VIEW_START + 50);
+constexpr ToolBoxItemId SID_INPUT_OK (SC_VIEW_START + 51);
+
+enum ScNameInputType
+{
+ SC_NAME_INPUT_CELL,
+ SC_NAME_INPUT_RANGE,
+ SC_NAME_INPUT_NAMEDRANGE_LOCAL,
+ SC_NAME_INPUT_NAMEDRANGE_GLOBAL,
+ SC_NAME_INPUT_DATABASE,
+ SC_NAME_INPUT_ROW,
+ SC_NAME_INPUT_SHEET,
+ SC_NAME_INPUT_DEFINE,
+ SC_NAME_INPUT_BAD_NAME,
+ SC_NAME_INPUT_BAD_SELECTION,
+ SC_MANAGE_NAMES
+};
+
+}
+
+SFX_IMPL_CHILDWINDOW_WITHID(ScInputWindowWrapper,FID_INPUTLINE_STATUS)
+
+ScInputWindowWrapper::ScInputWindowWrapper( vcl::Window* pParentP,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* /* pInfo */ )
+ : SfxChildWindow( pParentP, nId )
+{
+ VclPtr<ScInputWindow> pWin = VclPtr<ScInputWindow>::Create( pParentP, pBindings );
+ SetWindow( pWin );
+
+ pWin->Show();
+
+ pWin->SetSizePixel( pWin->CalcWindowSizePixel() );
+
+ SetAlignment(SfxChildAlignment::LOWESTTOP);
+ pBindings->Invalidate( FID_TOGGLEINPUTLINE );
+}
+
+/**
+ * GetInfo is disposed of if there's a SFX_IMPL_TOOLBOX!
+ */
+SfxChildWinInfo ScInputWindowWrapper::GetInfo() const
+{
+ SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
+ return aInfo;
+}
+
+
+static VclPtr<ScInputBarGroup> lcl_chooseRuntimeImpl( vcl::Window* pParent, const SfxBindings* pBind )
+{
+ ScTabViewShell* pViewSh = nullptr;
+ SfxDispatcher* pDisp = pBind->GetDispatcher();
+ if ( pDisp )
+ {
+ SfxViewFrame* pViewFrm = pDisp->GetFrame();
+ if ( pViewFrm )
+ pViewSh = dynamic_cast<ScTabViewShell*>( pViewFrm->GetViewShell() );
+ }
+
+ return VclPtr<ScInputBarGroup>::Create( pParent, pViewSh );
+}
+
+ScInputWindow::ScInputWindow( vcl::Window* pParent, const SfxBindings* pBind ) :
+ // With WB_CLIPCHILDREN otherwise we get flickering
+ ToolBox ( pParent, WinBits(WB_CLIPCHILDREN | WB_BORDER | WB_NOSHADOW) ),
+ aWndPos ( !comphelper::LibreOfficeKit::isActive() ? VclPtr<ScPosWnd>::Create(this) : nullptr ),
+ mxTextWindow ( lcl_chooseRuntimeImpl( this, pBind ) ),
+ pInputHdl ( nullptr ),
+ mpViewShell ( nullptr ),
+ mnMaxY (0),
+ mnStandardItemHeight(0),
+ bIsOkCancelMode ( false ),
+ bInResize ( false )
+{
+ // #i73615# don't rely on SfxViewShell::Current while constructing the input line
+ // (also for GetInputHdl below)
+ ScTabViewShell* pViewSh = nullptr;
+ SfxDispatcher* pDisp = pBind->GetDispatcher();
+ if ( pDisp )
+ {
+ SfxViewFrame* pViewFrm = pDisp->GetFrame();
+ if ( pViewFrm )
+ pViewSh = dynamic_cast<ScTabViewShell*>( pViewFrm->GetViewShell() );
+ }
+ OSL_ENSURE( pViewSh, "no view shell for input window" );
+
+ mpViewShell = pViewSh;
+
+ // Position window, 3 buttons, input window
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ InsertWindow (ToolBoxItemId(1), aWndPos.get(), ToolBoxItemBits::NONE, 0);
+ InsertSeparator (1);
+ InsertItem (SID_INPUT_FUNCTION, Image(StockImage::Yes, RID_BMP_INPUT_FUNCTION), ToolBoxItemBits::NONE, 2);
+ }
+
+ const bool bIsLOKMobilePhone = mpViewShell && mpViewShell->isLOKMobilePhone();
+
+ // sigma and equal buttons
+ if (!bIsLOKMobilePhone)
+ {
+ InsertItem (SID_INPUT_SUM, Image(StockImage::Yes, RID_BMP_INPUT_SUM), ToolBoxItemBits::DROPDOWNONLY, 3);
+ InsertItem (SID_INPUT_EQUAL, Image(StockImage::Yes, RID_BMP_INPUT_EQUAL), ToolBoxItemBits::NONE, 4);
+ InsertItem (SID_INPUT_CANCEL, Image(StockImage::Yes, RID_BMP_INPUT_CANCEL), ToolBoxItemBits::NONE, 5);
+ InsertItem (SID_INPUT_OK, Image(StockImage::Yes, RID_BMP_INPUT_OK), ToolBoxItemBits::NONE, 6);
+ }
+
+ InsertWindow (ToolBoxItemId(7), mxTextWindow.get(), ToolBoxItemBits::NONE, 7);
+ SetDropdownClickHdl( LINK( this, ScInputWindow, DropdownClickHdl ));
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ aWndPos ->SetQuickHelpText(ScResId(SCSTR_QHELP_POSWND));
+ aWndPos ->SetHelpId (HID_INSWIN_POS);
+
+ mxTextWindow->SetQuickHelpText(ScResId(SCSTR_QHELP_INPUTWND));
+ mxTextWindow->SetHelpId (HID_INSWIN_INPUT);
+
+ // No SetHelpText: the helptexts come from the Help
+ SetItemText (SID_INPUT_FUNCTION, ScResId(SCSTR_QHELP_BTNCALC));
+ SetHelpId (SID_INPUT_FUNCTION, HID_INSWIN_CALC);
+ }
+
+ // sigma and equal buttons
+ if (!bIsLOKMobilePhone)
+ {
+ SetHelpId (SID_INPUT_SUM, HID_INSWIN_SUMME);
+ SetHelpId (SID_INPUT_EQUAL, HID_INSWIN_FUNC);
+ SetHelpId (SID_INPUT_CANCEL, HID_INSWIN_CANCEL);
+ SetHelpId (SID_INPUT_OK, HID_INSWIN_OK);
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ SetItemText ( SID_INPUT_SUM, ScResId( SCSTR_QHELP_BTNSUM ) );
+ SetItemText ( SID_INPUT_EQUAL, ScResId( SCSTR_QHELP_BTNEQUAL ) );
+ SetItemText ( SID_INPUT_CANCEL, ScResId( SCSTR_QHELP_BTNCANCEL ) );
+ SetItemText ( SID_INPUT_OK, ScResId( SCSTR_QHELP_BTNOK ) );
+ }
+
+ EnableItem( SID_INPUT_CANCEL, false );
+ EnableItem( SID_INPUT_OK, false );
+
+ HideItem( SID_INPUT_CANCEL );
+ HideItem( SID_INPUT_OK );
+
+ mnStandardItemHeight = GetItemRect(SID_INPUT_SUM).GetHeight();
+ }
+
+ SetHelpId( HID_SC_INPUTWIN ); // For the whole input row
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ aWndPos ->Show();
+ mxTextWindow->Show();
+
+ pInputHdl = SC_MOD()->GetInputHdl( pViewSh, false ); // use own handler even if ref-handler is set
+ if (pInputHdl)
+ pInputHdl->SetInputWindow( this );
+
+ if (pInputHdl && !pInputHdl->GetFormString().isEmpty())
+ {
+ // Switch over while the Function AutoPilot is active
+ // -> show content of the Function AutoPilot again
+ // Also show selection (remember at the InputHdl)
+ mxTextWindow->SetTextString( pInputHdl->GetFormString() );
+ }
+ else if (pInputHdl && pInputHdl->IsInputMode())
+ {
+ // If the input row was hidden while editing (e.g. when editing a formula
+ // and then switching to another document or the help), display the text
+ // we just edited from the InputHandler
+ mxTextWindow->SetTextString( pInputHdl->GetEditString() ); // Display text
+ if ( pInputHdl->IsTopMode() )
+ pInputHdl->SetMode( SC_INPUT_TABLE ); // Focus ends up at the bottom anyways
+ }
+ else if (pViewSh)
+ {
+ // Don't stop editing in LOK a remote user might be editing.
+ const bool bStopEditing = !comphelper::LibreOfficeKit::isActive();
+ pViewSh->UpdateInputHandler(true, bStopEditing); // Absolutely necessary update
+ }
+
+ SetToolbarLayoutMode( ToolBoxLayoutMode::Locked );
+
+ SetAccessibleName(ScResId(STR_ACC_TOOLBAR_FORMULA));
+}
+
+ScInputWindow::~ScInputWindow()
+{
+ disposeOnce();
+}
+
+void ScInputWindow::dispose()
+{
+ bool bDown = !ScGlobal::oSysLocale; // after Clear?
+
+ // if any view's input handler has a pointer to this input window, reset it
+ // (may be several ones, #74522#)
+ // member pInputHdl is not used here
+
+ if ( !bDown )
+ {
+ SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
+ while ( pSh )
+ {
+ ScInputHandler* pHdl = static_cast<ScTabViewShell*>(pSh)->GetInputHandler();
+ if ( pHdl && pHdl->GetInputWindow() == this )
+ {
+ pHdl->SetInputWindow( nullptr );
+ pHdl->StopInputWinEngine( false ); // reset pTopView pointer
+ }
+ pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
+ }
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (GetLOKNotifier())
+ ReleaseLOKNotifier();
+ }
+
+ mxTextWindow.disposeAndClear();
+ aWndPos.disposeAndClear();
+
+ ToolBox::dispose();
+}
+
+void ScInputWindow::SetInputHandler( ScInputHandler* pNew )
+{
+ // Is called in the Activate of the View ...
+ if ( pNew != pInputHdl )
+ {
+ // On Reload (last version) the pInputHdl is the InputHandler of the old, deleted
+ // ViewShell: so don't touch it here!
+ pInputHdl = pNew;
+ if (pInputHdl)
+ pInputHdl->SetInputWindow( this );
+ }
+}
+
+void ScInputWindow::Select()
+{
+ ScModule* pScMod = SC_MOD();
+ ToolBox::Select();
+
+ ToolBoxItemId curItemId = GetCurItemId();
+ if (curItemId == SID_INPUT_FUNCTION)
+ {
+ //! new method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if ( pViewFrm && ( comphelper::LibreOfficeKit::isActive() || !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) ) )
+ {
+ pViewFrm->GetDispatcher()->Execute( SID_OPENDLG_FUNCTION,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
+
+ // The Toolbox will be disabled anyways, so we don't need to switch here,
+ // regardless whether it succeeded or not!
+// SetOkCancelMode();
+ }
+ }
+ else if (curItemId == SID_INPUT_CANCEL)
+ {
+ pScMod->InputCancelHandler();
+ SetSumAssignMode();
+ }
+ else if (curItemId == SID_INPUT_OK)
+ {
+ pScMod->InputEnterHandler();
+ SetSumAssignMode();
+ mxTextWindow->Invalidate(); // Or else the Selection remains
+ }
+ else if (curItemId == SID_INPUT_EQUAL)
+ {
+ StartFormula();
+ }
+}
+
+void ScInputWindow::StartFormula()
+{
+ ScModule* pScMod = SC_MOD();
+ mxTextWindow->StartEditEngine();
+ if ( pScMod->IsEditMode() ) // Isn't if e.g. protected
+ {
+ mxTextWindow->StartEditEngine();
+
+ sal_Int32 nStartPos = 1;
+ sal_Int32 nEndPos = 1;
+
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( pViewSh )
+ {
+ const OUString& rString = mxTextWindow->GetTextString();
+ const sal_Int32 nLen = rString.getLength();
+
+ ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
+ CellType eCellType = rDoc.GetCellType( pViewSh->GetViewData().GetCurPos() );
+ switch ( eCellType )
+ {
+ case CELLTYPE_VALUE:
+ {
+ nEndPos = nLen + 1;
+ mxTextWindow->SetTextString("=" + rString);
+ break;
+ }
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ nStartPos = 0;
+ nEndPos = nLen;
+ break;
+ case CELLTYPE_FORMULA:
+ nEndPos = nLen;
+ break;
+ default:
+ mxTextWindow->SetTextString("=");
+ break;
+ }
+ }
+
+ EditView* pView = mxTextWindow->GetEditView();
+ if (pView)
+ {
+ if (comphelper::LibreOfficeKit::isActive())
+ TextGrabFocus();
+ pView->SetSelection( ESelection(0, nStartPos, 0, nEndPos) );
+ pScMod->InputChanged(pView);
+ SetOkCancelMode();
+ pView->SetEditEngineUpdateLayout(true);
+ }
+ }
+}
+
+void ScInputWindow::PixelInvalidate(const tools::Rectangle* pRectangle)
+{
+ if (comphelper::LibreOfficeKit::isDialogPainting() || !comphelper::LibreOfficeKit::isActive())
+ return;
+
+ if (pRectangle)
+ {
+ tools::Rectangle aRect(*pRectangle);
+ aRect.Move(-GetOutOffXPixel(), -GetOutOffYPixel());
+ Window::PixelInvalidate(&aRect);
+ }
+ else
+ {
+ Window::PixelInvalidate(nullptr);
+ }
+}
+
+void ScInputWindow::SetSizePixel( const Size& rNewSize )
+{
+ const vcl::ILibreOfficeKitNotifier* pNotifier = GetLOKNotifier();
+ if (pNotifier)
+ {
+ if (vcl::Window* pFrameWindowImpl = GetParent())
+ {
+ if (vcl::Window* pWorkWindow = pFrameWindowImpl->GetParent())
+ {
+ if (vcl::Window* pImplBorderWindow = pWorkWindow->GetParent())
+ {
+ Size aSize = pImplBorderWindow->GetSizePixel();
+ aSize.setWidth(rNewSize.getWidth());
+ pImplBorderWindow->SetSizePixel(aSize);
+ }
+ }
+ }
+ }
+
+ ToolBox::SetSizePixel(rNewSize);
+}
+
+void ScInputWindow::Resize()
+{
+ ToolBox::Resize();
+
+ Size aStartSize = GetSizePixel();
+ Size aSize = aStartSize;
+
+ auto nLines = mxTextWindow->GetNumLines();
+ //(-10) to allow margin between sidebar and formulabar
+ tools::Long margin = (comphelper::LibreOfficeKit::isActive()) ? 10 : 0;
+ Size aTextWindowSize(aSize.Width() - mxTextWindow->GetPosPixel().X() - LEFT_OFFSET - margin,
+ mxTextWindow->GetPixelHeightForLines(nLines));
+ mxTextWindow->SetSizePixel(aTextWindowSize);
+
+ int nTopOffset = 0;
+ if (nLines > 1)
+ {
+ // Initially there is 1 line and the edit is vertically centered in the toolbar
+ // Later, if expanded then the vertical position of the edit will remain at
+ // that initial position, so when calculating the overall size of the expanded
+ // toolbar we have to include that initial offset in order to not make
+ // the edit overlap the RESIZE_HOTSPOT_HEIGHT area so that dragging to resize
+ // is still possible.
+ int nNormalHeight = mxTextWindow->GetPixelHeightForLines(1);
+ int nInitialTopMargin = (mnStandardItemHeight - nNormalHeight) / 2;
+ if (nInitialTopMargin > 0)
+ nTopOffset = nInitialTopMargin;
+ }
+
+ // add empty space of RESIZE_HOTSPOT_HEIGHT so resize is possible when hovering there
+ aSize.setHeight(CalcWindowSizePixel().Height() + RESIZE_HOTSPOT_HEIGHT + nTopOffset);
+
+ if (aStartSize != aSize)
+ SetSizePixel(aSize);
+
+ Invalidate();
+}
+
+void ScInputWindow::NotifyLOKClient()
+{
+ if (comphelper::LibreOfficeKit::isActive() && !GetLOKNotifier() && mpViewShell)
+ SetLOKNotifier(mpViewShell);
+}
+
+void ScInputWindow::SetFuncString( const OUString& rString, bool bDoEdit )
+{
+ //! new method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
+ mxTextWindow->StartEditEngine();
+
+ ScModule* pScMod = SC_MOD();
+ if ( !pScMod->IsEditMode() )
+ return;
+
+ if ( bDoEdit )
+ mxTextWindow->TextGrabFocus();
+ mxTextWindow->SetTextString( rString );
+ EditView* pView = mxTextWindow->GetEditView();
+ if (!pView)
+ return;
+
+ sal_Int32 nLen = rString.getLength();
+
+ if ( nLen > 0 )
+ {
+ nLen--;
+ pView->SetSelection( ESelection( 0, nLen, 0, nLen ) );
+ }
+
+ pScMod->InputChanged(pView);
+ if ( bDoEdit )
+ SetOkCancelMode(); // Not the case if immediately followed by Enter/Cancel
+
+ pView->SetEditEngineUpdateLayout(true);
+}
+
+void ScInputWindow::SetPosString( const OUString& rStr )
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ aWndPos->SetPos( rStr );
+}
+
+void ScInputWindow::SetTextString( const OUString& rString )
+{
+ if (rString.getLength() <= 32767)
+ mxTextWindow->SetTextString(rString);
+ else
+ mxTextWindow->SetTextString(rString.copy(0, 32767));
+}
+
+void ScInputWindow::SetOkCancelMode()
+{
+ //! new method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
+
+ if (bIsOkCancelMode)
+ return;
+
+ EnableItem ( SID_INPUT_SUM, false );
+ EnableItem ( SID_INPUT_EQUAL, false );
+ HideItem ( SID_INPUT_SUM );
+ HideItem ( SID_INPUT_EQUAL );
+
+ ShowItem ( SID_INPUT_CANCEL, true );
+ ShowItem ( SID_INPUT_OK, true );
+ EnableItem ( SID_INPUT_CANCEL, true );
+ EnableItem ( SID_INPUT_OK, true );
+
+ bIsOkCancelMode = true;
+}
+
+void ScInputWindow::SetSumAssignMode()
+{
+ //! new method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ EnableButtons( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) );
+
+ if (!bIsOkCancelMode)
+ return;
+
+ EnableItem ( SID_INPUT_CANCEL, false );
+ EnableItem ( SID_INPUT_OK, false );
+ HideItem ( SID_INPUT_CANCEL );
+ HideItem ( SID_INPUT_OK );
+
+ ShowItem ( SID_INPUT_SUM, true );
+ ShowItem ( SID_INPUT_EQUAL, true );
+ EnableItem ( SID_INPUT_SUM, true );
+ EnableItem ( SID_INPUT_EQUAL, true );
+
+ bIsOkCancelMode = false;
+
+ SetFormulaMode(false); // No editing -> no formula
+}
+
+void ScInputWindow::SetFormulaMode( bool bSet )
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ aWndPos->SetFormulaMode(bSet);
+ mxTextWindow->SetFormulaMode(bSet);
+}
+
+bool ScInputWindow::IsInputActive()
+{
+ return mxTextWindow->IsInputActive();
+}
+
+EditView* ScInputWindow::GetEditView()
+{
+ return mxTextWindow->GetEditView();
+}
+
+vcl::Window* ScInputWindow::GetEditWindow()
+{
+ return mxTextWindow;
+}
+
+Point ScInputWindow::GetCursorScreenPixelPos(bool bBelow)
+{
+ return mxTextWindow->GetCursorScreenPixelPos(bBelow);
+}
+
+void ScInputWindow::MakeDialogEditView()
+{
+ mxTextWindow->MakeDialogEditView();
+}
+
+void ScInputWindow::StopEditEngine( bool bAll )
+{
+ mxTextWindow->StopEditEngine( bAll );
+}
+
+void ScInputWindow::TextGrabFocus()
+{
+ mxTextWindow->TextGrabFocus();
+}
+
+void ScInputWindow::TextInvalidate()
+{
+ mxTextWindow->Invalidate();
+}
+
+void ScInputWindow::SwitchToTextWin()
+{
+ // used for shift-ctrl-F2
+
+ mxTextWindow->StartEditEngine();
+ if ( SC_MOD()->IsEditMode() )
+ {
+ mxTextWindow->TextGrabFocus();
+ EditView* pView = mxTextWindow->GetEditView();
+ if (pView)
+ {
+ sal_Int32 nPara = pView->GetEditEngine()->GetParagraphCount() ? ( pView->GetEditEngine()->GetParagraphCount() - 1 ) : 0;
+ sal_Int32 nLen = pView->GetEditEngine()->GetTextLen( nPara );
+ ESelection aSel( nPara, nLen, nPara, nLen );
+ pView->SetSelection( aSel ); // set cursor to end of text
+ }
+ }
+}
+
+void ScInputWindow::PosGrabFocus()
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ aWndPos->GrabFocus();
+}
+
+void ScInputWindow::EnableButtons( bool bEnable )
+{
+ // when enabling buttons, always also enable the input window itself
+ if ( bEnable && !IsEnabled() )
+ Enable();
+
+ EnableItem( SID_INPUT_FUNCTION, bEnable );
+ EnableItem( bIsOkCancelMode ? SID_INPUT_CANCEL : SID_INPUT_SUM, bEnable );
+ EnableItem( bIsOkCancelMode ? SID_INPUT_OK : SID_INPUT_EQUAL, bEnable );
+// Invalidate();
+}
+
+void ScInputWindow::NumLinesChanged()
+{
+ mxTextWindow->NumLinesChanged();
+}
+
+void ScInputWindow::StateChanged( StateChangedType nType )
+{
+ ToolBox::StateChanged( nType );
+
+ if ( nType == StateChangedType::InitShow ) Resize();
+}
+
+void ScInputWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( rDCEvt.GetType() == DataChangedEventType::SETTINGS && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ // update item images
+ SetItemImage(SID_INPUT_FUNCTION, Image(StockImage::Yes, RID_BMP_INPUT_FUNCTION));
+ if ( bIsOkCancelMode )
+ {
+ SetItemImage(SID_INPUT_CANCEL, Image(StockImage::Yes, RID_BMP_INPUT_CANCEL));
+ SetItemImage(SID_INPUT_OK, Image(StockImage::Yes, RID_BMP_INPUT_OK));
+ }
+ else
+ {
+ SetItemImage(SID_INPUT_SUM, Image(StockImage::Yes, RID_BMP_INPUT_SUM));
+ SetItemImage(SID_INPUT_EQUAL, Image(StockImage::Yes, RID_BMP_INPUT_EQUAL));
+ }
+ }
+
+ ToolBox::DataChanged( rDCEvt );
+}
+
+bool ScInputWindow::IsPointerAtResizePos()
+{
+ return GetOutputSizePixel().Height() - GetPointerPosPixel().Y() <= RESIZE_HOTSPOT_HEIGHT;
+}
+
+void ScInputWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ Point aPosPixel = GetPointerPosPixel();
+
+ ScInputBarGroup* pGroupBar = mxTextWindow.get();
+
+ if (bInResize || IsPointerAtResizePos())
+ SetPointer(PointerStyle::WindowSSize);
+ else
+ SetPointer(PointerStyle::Arrow);
+
+ if (bInResize)
+ {
+ // detect direction
+ tools::Long nResizeThreshold = tools::Long(TOOLBOX_WINDOW_HEIGHT * 0.7);
+ bool bResetPointerPos = false;
+
+ // Detect attempt to expand toolbar too much
+ if (aPosPixel.Y() >= mnMaxY)
+ {
+ bResetPointerPos = true;
+ aPosPixel.setY( mnMaxY );
+ } // or expanding down
+ else if (GetOutputSizePixel().Height() - aPosPixel.Y() < -nResizeThreshold)
+ {
+ pGroupBar->IncrementVerticalSize();
+ bResetPointerPos = true;
+ } // or shrinking up
+ else if ((GetOutputSizePixel().Height() - aPosPixel.Y()) > nResizeThreshold)
+ {
+ bResetPointerPos = true;
+ pGroupBar->DecrementVerticalSize();
+ }
+
+ if (bResetPointerPos)
+ {
+ aPosPixel.setY( GetOutputSizePixel().Height() );
+ SetPointerPosPixel(aPosPixel);
+ }
+ }
+
+ ToolBox::MouseMove(rMEvt);
+}
+
+void ScInputWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if (rMEvt.IsLeft())
+ {
+ if (IsPointerAtResizePos())
+ {
+ // Don't leave the mouse pointer leave *this* window
+ CaptureMouse();
+ bInResize = true;
+
+ // find the height of the gridwin, we don't want to be
+ // able to expand the toolbar too far so we need to
+ // calculate an upper limit
+ // I'd prefer to leave at least a single column header and a
+ // row but I don't know how to get that value in pixels.
+ // Use TOOLBOX_WINDOW_HEIGHT for the moment
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ mnMaxY = GetOutputSizePixel().Height() + (pViewSh->GetGridHeight(SC_SPLIT_TOP)
+ + pViewSh->GetGridHeight(SC_SPLIT_BOTTOM)) - TOOLBOX_WINDOW_HEIGHT;
+ }
+ }
+
+ ToolBox::MouseButtonDown( rMEvt );
+}
+void ScInputWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ ReleaseMouse();
+ if ( rMEvt.IsLeft() )
+ {
+ bInResize = false;
+ mnMaxY = 0;
+ }
+
+ ToolBox::MouseButtonUp( rMEvt );
+}
+
+void ScInputWindow::AutoSum( bool& bRangeFinder, bool& bSubTotal, OpCode eCode )
+{
+ ScModule* pScMod = SC_MOD();
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( !pViewSh )
+ return;
+
+ const OUString aFormula = pViewSh->DoAutoSum(bRangeFinder, bSubTotal, eCode);
+ if ( aFormula.isEmpty() )
+ return;
+
+ SetFuncString( aFormula );
+ const sal_Int32 aOpen = aFormula.indexOf('(');
+ const sal_Int32 aLen = aFormula.getLength();
+ if (!(bRangeFinder && pScMod->IsEditMode()))
+ return;
+
+ ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
+ if ( !pHdl )
+ return;
+
+ pHdl->InitRangeFinder( aFormula );
+
+ //! SetSelection at the InputHandler?
+ //! Set bSelIsRef?
+ if ( aOpen != -1 && aLen > aOpen )
+ {
+ ESelection aSel( 0, aOpen + (bSubTotal ? 3 : 1), 0, aLen-1 );
+ EditView* pTableView = pHdl->GetTableView();
+ if ( pTableView )
+ pTableView->SetSelection( aSel );
+ EditView* pTopView = pHdl->GetTopView();
+ if ( pTopView )
+ pTopView->SetSelection( aSel );
+ }
+}
+
+ScInputBarGroup::ScInputBarGroup(vcl::Window* pParent, ScTabViewShell* pViewSh)
+ : InterimItemWindow(pParent, "modules/scalc/ui/inputbar.ui", "InputBar", true, reinterpret_cast<sal_uInt64>(pViewSh))
+ , mxBackground(m_xBuilder->weld_container("background"))
+ , mxTextWndGroup(new ScTextWndGroup(*this, pViewSh))
+ , mxButtonUp(m_xBuilder->weld_button("up"))
+ , mxButtonDown(m_xBuilder->weld_button("down"))
+{
+ InitControlBase(m_xContainer.get());
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ SetPaintTransparent(false);
+ SetBackground(rStyleSettings.GetFaceColor());
+
+ // match to bg used in ScTextWnd::SetDrawingArea to the margin area is drawn with the
+ // same desired bg
+ mxBackground->set_background(rStyleSettings.GetWindowColor());
+
+ mxButtonUp->connect_clicked(LINK(this, ScInputBarGroup, ClickHdl));
+ mxButtonDown->connect_clicked(LINK(this, ScInputBarGroup, ClickHdl));
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ mxButtonUp->set_tooltip_text(ScResId( SCSTR_QHELP_COLLAPSE_FORMULA));
+ mxButtonDown->set_tooltip_text(ScResId(SCSTR_QHELP_EXPAND_FORMULA));
+ }
+
+ int nHeight = mxTextWndGroup->GetPixelHeightForLines(1);
+ mxButtonUp->set_size_request(-1, nHeight);
+ mxButtonDown->set_size_request(-1, nHeight);
+
+ // disable the multiline toggle on the mobile phones
+ const SfxViewShell* pViewShell = SfxViewShell::Current();
+ if (!comphelper::LibreOfficeKit::isActive() || !(pViewShell && pViewShell->isLOKMobilePhone()))
+ mxButtonDown->show();
+
+ // tdf#154042 Use an initial height of one row so the Toolbar positions
+ // this in the same place regardless of how many rows it eventually shows
+ Size aSize(GetSizePixel().Width(), nHeight);
+ SetSizePixel(aSize);
+}
+
+Point ScInputBarGroup::GetCursorScreenPixelPos(bool bBelow)
+{
+ return mxTextWndGroup->GetCursorScreenPixelPos(bBelow);
+}
+
+ScInputBarGroup::~ScInputBarGroup()
+{
+ disposeOnce();
+}
+
+void ScInputBarGroup::dispose()
+{
+ mxTextWndGroup.reset();
+ mxButtonUp.reset();
+ mxButtonDown.reset();
+ mxBackground.reset();
+ InterimItemWindow::dispose();
+}
+
+void ScInputBarGroup::InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
+{
+ mxTextWndGroup->InsertAccessibleTextData(rTextData);
+}
+
+void ScInputBarGroup::RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
+{
+ mxTextWndGroup->RemoveAccessibleTextData(rTextData);
+}
+
+const OUString& ScInputBarGroup::GetTextString() const
+{
+ return mxTextWndGroup->GetTextString();
+}
+
+void ScInputBarGroup::SetTextString( const OUString& rString )
+{
+ mxTextWndGroup->SetTextString(rString);
+}
+
+void ScInputBarGroup::Resize()
+{
+ mxTextWndGroup->SetScrollPolicy();
+ InterimItemWindow::Resize();
+ TriggerToolboxLayout();
+}
+
+void ScInputBarGroup::StopEditEngine(bool bAll)
+{
+ mxTextWndGroup->StopEditEngine(bAll);
+}
+
+void ScInputBarGroup::StartEditEngine()
+{
+ mxTextWndGroup->StartEditEngine();
+}
+
+void ScInputBarGroup::MakeDialogEditView()
+{
+ mxTextWndGroup->MakeDialogEditView();
+}
+
+EditView* ScInputBarGroup::GetEditView() const
+{
+ return mxTextWndGroup->GetEditView();
+}
+
+bool ScInputBarGroup::HasEditView() const
+{
+ return mxTextWndGroup->HasEditView();
+}
+
+bool ScInputBarGroup::IsInputActive()
+{
+ return mxTextWndGroup->IsInputActive();
+}
+
+void ScInputBarGroup::SetFormulaMode(bool bSet)
+{
+ mxTextWndGroup->SetFormulaMode(bSet);
+}
+
+void ScInputBarGroup::IncrementVerticalSize()
+{
+ mxTextWndGroup->SetNumLines(mxTextWndGroup->GetNumLines() + 1);
+ TriggerToolboxLayout();
+}
+
+void ScInputBarGroup::DecrementVerticalSize()
+{
+ if (mxTextWndGroup->GetNumLines() > 1)
+ {
+ mxTextWndGroup->SetNumLines(mxTextWndGroup->GetNumLines() - 1);
+ TriggerToolboxLayout();
+ }
+}
+
+void ScInputWindow::MenuHdl(std::string_view command)
+{
+ if (command.empty())
+ return;
+
+ bool bSubTotal = false;
+ bool bRangeFinder = false;
+ OpCode eCode = ocSum;
+ if ( command == "sum" )
+ {
+ eCode = ocSum;
+ }
+ else if ( command == "average" )
+ {
+ eCode = ocAverage;
+ }
+ else if ( command == "max" )
+ {
+ eCode = ocMax;
+ }
+ else if ( command == "min" )
+ {
+ eCode = ocMin;
+ }
+ else if ( command == "count" )
+ {
+ eCode = ocCount;
+ }
+ else if ( command == "counta" )
+ {
+ eCode = ocCount2;
+ }
+ else if ( command == "product" )
+ {
+ eCode = ocProduct;
+ }
+ else if (command == "stdev")
+ {
+ eCode = ocStDev;
+ }
+ else if (command == "stdevp")
+ {
+ eCode = ocStDevP;
+ }
+ else if (command == "var")
+ {
+ eCode = ocVar;
+ }
+ else if (command == "varp")
+ {
+ eCode = ocVarP;
+ }
+
+ AutoSum( bRangeFinder, bSubTotal, eCode );
+}
+
+IMPL_LINK_NOARG(ScInputWindow, DropdownClickHdl, ToolBox *, void)
+{
+ ToolBoxItemId nCurID = GetCurItemId();
+ EndSelection();
+
+ if (nCurID == SID_INPUT_SUM)
+ {
+ tools::Rectangle aRect(GetItemRect(SID_INPUT_SUM));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "modules/scalc/ui/autosum.ui"));
+ std::unique_ptr<weld::Menu> xPopMenu(xBuilder->weld_menu("menu"));
+ MenuHdl(xPopMenu->popup_at_rect(pPopupParent, aRect));
+ }
+}
+
+IMPL_LINK_NOARG(ScInputBarGroup, ClickHdl, weld::Button&, void)
+{
+ if (mxTextWndGroup->GetNumLines() > 1)
+ mxTextWndGroup->SetNumLines(1);
+ else
+ mxTextWndGroup->SetNumLines(mxTextWndGroup->GetLastNumExpandedLines());
+
+ NumLinesChanged();
+}
+
+void ScInputBarGroup::NumLinesChanged()
+{
+ if (mxTextWndGroup->GetNumLines() > 1)
+ {
+ mxButtonDown->hide();
+ mxButtonUp->show();
+ mxTextWndGroup->SetLastNumExpandedLines(mxTextWndGroup->GetNumLines());
+ }
+ else
+ {
+ mxButtonUp->hide();
+ mxButtonDown->show();
+ }
+ TriggerToolboxLayout();
+
+ // Restore focus to input line(s) if necessary
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if ( pHdl && pHdl->IsTopMode() )
+ mxTextWndGroup->TextGrabFocus();
+}
+
+void ScInputBarGroup::TriggerToolboxLayout()
+{
+ vcl::Window *w=GetParent();
+ ScInputWindow &rParent = dynamic_cast<ScInputWindow&>(*w);
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+
+ if ( !pViewFrm )
+ return;
+
+ Reference< css::beans::XPropertySet > xPropSet( pViewFrm->GetFrame().GetFrameInterface(), UNO_QUERY );
+ Reference< css::frame::XLayoutManager > xLayoutManager;
+
+ if ( xPropSet.is() )
+ {
+ css::uno::Any aValue = xPropSet->getPropertyValue("LayoutManager");
+ aValue >>= xLayoutManager;
+ }
+
+ if ( !xLayoutManager.is() )
+ return;
+
+ xLayoutManager->lock();
+ DataChangedEvent aFakeUpdate( DataChangedEventType::SETTINGS, nullptr, AllSettingsFlags::STYLE );
+
+ // this basically will trigger the repositioning of the
+ // items in the toolbar from ImplFormat ( which is controlled by
+ // mnWinHeight ) which in turn is updated in ImplCalcItem which is
+ // controlled by mbCalc. Additionally the ImplFormat above is
+ // controlled via mbFormat. It seems the easiest way to get these
+ // booleans set is to send in the fake event below.
+ rParent.DataChanged( aFakeUpdate);
+
+ // highest item in toolbar will have been calculated via the
+ // event above. Call resize on InputBar to pick up the height
+ // change
+ rParent.Resize();
+
+ // unlock relayouts the toolbars in the 4 quadrants
+ xLayoutManager->unlock();
+}
+
+void ScInputBarGroup::TextGrabFocus()
+{
+ mxTextWndGroup->TextGrabFocus();
+}
+
+constexpr tools::Long gnBorderWidth = (INPUTLINE_INSET_MARGIN + 1) * 2;
+constexpr tools::Long gnBorderHeight = INPUTLINE_INSET_MARGIN + 1;
+
+ScTextWndGroup::ScTextWndGroup(ScInputBarGroup& rParent, ScTabViewShell* pViewSh)
+ : mxTextWnd(new ScTextWnd(*this, pViewSh))
+ , mxScrollWin(rParent.GetBuilder().weld_scrolled_window("scrolledwindow", true))
+ , mxTextWndWin(new weld::CustomWeld(rParent.GetBuilder(), "sc_input_window", *mxTextWnd))
+ , mrParent(rParent)
+{
+ mxScrollWin->connect_vadjustment_changed(LINK(this, ScTextWndGroup, Impl_ScrollHdl));
+ if (comphelper::LibreOfficeKit::isActive())
+ ScInputHandler::LOKSendFormulabarUpdate(SfxViewShell::Current(), "", ESelection());
+}
+
+Point ScTextWndGroup::GetCursorScreenPixelPos(bool bBelow)
+{
+ Point aPos;
+ if (!HasEditView())
+ return aPos;
+ EditView* pEditView = GetEditView();
+ vcl::Cursor* pCur = pEditView->GetCursor();
+ if (!pCur)
+ return aPos;
+ Point aLogicPos = pCur->GetPos();
+ if (bBelow)
+ aLogicPos.AdjustY(pCur->GetHeight());
+ aPos = GetEditViewDevice().LogicToPixel(aLogicPos);
+ bool bRTL = mrParent.IsRTLEnabled();
+ if (bRTL)
+ aPos.setX(mxTextWnd->GetOutputSizePixel().Width() - aPos.X() + gnBorderWidth);
+ else
+ aPos.AdjustX(gnBorderWidth + 1);
+
+ return mrParent.OutputToScreenPixel(aPos);
+}
+
+ScTextWndGroup::~ScTextWndGroup()
+{
+}
+
+void ScTextWndGroup::InsertAccessibleTextData(ScAccessibleEditLineTextData& rTextData)
+{
+ mxTextWnd->InsertAccessibleTextData(rTextData);
+}
+
+EditView* ScTextWndGroup::GetEditView() const
+{
+ return mxTextWnd->GetEditView();
+}
+
+const OutputDevice& ScTextWndGroup::GetEditViewDevice() const
+{
+ return mxTextWnd->GetEditViewDevice();
+}
+
+tools::Long ScTextWndGroup::GetLastNumExpandedLines() const
+{
+ return mxTextWnd->GetLastNumExpandedLines();
+}
+
+void ScTextWndGroup::SetLastNumExpandedLines(tools::Long nLastExpandedLines)
+{
+ mxTextWnd->SetLastNumExpandedLines(nLastExpandedLines);
+}
+
+tools::Long ScTextWndGroup::GetNumLines() const
+{
+ return mxTextWnd->GetNumLines();
+}
+
+int ScTextWndGroup::GetPixelHeightForLines(tools::Long nLines)
+{
+ return mxTextWnd->GetPixelHeightForLines(nLines) + 2 * gnBorderHeight;
+}
+
+weld::ScrolledWindow& ScTextWndGroup::GetScrollWin()
+{
+ return *mxScrollWin;
+}
+
+const OUString& ScTextWndGroup::GetTextString() const
+{
+ return mxTextWnd->GetTextString();
+}
+
+bool ScTextWndGroup::HasEditView() const
+{
+ return mxTextWnd->HasEditView();
+}
+
+bool ScTextWndGroup::IsInputActive()
+{
+ return mxTextWnd->IsInputActive();
+}
+
+void ScTextWndGroup::MakeDialogEditView()
+{
+ mxTextWnd->MakeDialogEditView();
+}
+
+void ScTextWndGroup::RemoveAccessibleTextData(ScAccessibleEditLineTextData& rTextData)
+{
+ mxTextWnd->RemoveAccessibleTextData(rTextData);
+}
+
+void ScTextWndGroup::SetScrollPolicy()
+{
+ if (mxTextWnd->GetNumLines() > 2)
+ mxScrollWin->set_vpolicy(VclPolicyType::ALWAYS);
+ else
+ mxScrollWin->set_vpolicy(VclPolicyType::NEVER);
+}
+
+void ScTextWndGroup::SetNumLines(tools::Long nLines)
+{
+ mxTextWnd->SetNumLines(nLines);
+}
+
+void ScTextWndGroup::SetFormulaMode(bool bSet)
+{
+ mxTextWnd->SetFormulaMode(bSet);
+}
+
+void ScTextWndGroup::SetTextString(const OUString& rString)
+{
+ mxTextWnd->SetTextString(rString);
+}
+
+void ScTextWndGroup::StartEditEngine()
+{
+ mxTextWnd->StartEditEngine();
+}
+
+void ScTextWndGroup::StopEditEngine(bool bAll)
+{
+ mxTextWnd->StopEditEngine( bAll );
+}
+
+void ScTextWndGroup::TextGrabFocus()
+{
+ mxTextWnd->TextGrabFocus();
+}
+
+IMPL_LINK_NOARG(ScTextWndGroup, Impl_ScrollHdl, weld::ScrolledWindow&, void)
+{
+ mxTextWnd->DoScroll();
+}
+
+void ScTextWnd::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect )
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Color aBgColor = rStyleSettings.GetWindowColor();
+ rRenderContext.SetBackground(aBgColor);
+
+ // tdf#137713 we rely on GetEditView creating it if it doesn't already exist so
+ // GetEditView() must be called unconditionally
+ if (EditView* pView = GetEditView())
+ {
+ if (mbInvalidate)
+ {
+ pView->Invalidate();
+ mbInvalidate = false;
+ }
+ }
+
+ if (comphelper::LibreOfficeKit::isActive() && m_xEditEngine)
+ {
+ // EditEngine/EditView works in twips logical coordinates, so set the device map-mode to twips before painting
+ // and use twips version of the painting area 'rRect'.
+ // Document zoom should not be included in this conversion.
+ tools::Rectangle aLogicRect = OutputDevice::LogicToLogic(rRect, MapMode(MapUnit::MapPixel), MapMode(MapUnit::MapTwip));
+ MapMode aOriginalMode = rRenderContext.GetMapMode();
+ rRenderContext.SetMapMode(MapMode(MapUnit::MapTwip));
+ WeldEditView::Paint(rRenderContext, aLogicRect);
+ rRenderContext.SetMapMode(aOriginalMode);
+ }
+ else
+ WeldEditView::Paint(rRenderContext, rRect);
+}
+
+EditView* ScTextWnd::GetEditView() const
+{
+ if ( !m_xEditView )
+ const_cast<ScTextWnd&>(*this).InitEditEngine();
+ return m_xEditView.get();
+}
+
+bool ScTextWnd::HasEditView() const { return m_xEditView != nullptr; }
+
+const OutputDevice& ScTextWnd::GetEditViewDevice() const
+{
+ return EditViewOutputDevice();
+}
+
+int ScTextWnd::GetPixelHeightForLines(tools::Long nLines)
+{
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ return rDevice.LogicToPixel(Size(0, nLines * rDevice.GetTextHeight())).Height() + 1;
+}
+
+tools::Long ScTextWnd::GetNumLines() const
+{
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ return rViewData.GetFormulaBarLines();
+}
+
+void ScTextWnd::SetNumLines(tools::Long nLines)
+{
+ ScViewData& rViewData = mpViewShell->GetViewData();
+ rViewData.SetFormulaBarLines(nLines);
+ if ( nLines > 1 )
+ {
+ // SetFormulaBarLines sanitizes the height, so get the sanitized value
+ mnLastExpandedLines = rViewData.GetFormulaBarLines();
+ Resize();
+ }
+}
+
+void ScTextWnd::Resize()
+{
+ if (m_xEditView)
+ {
+ Size aOutputSize = GetOutputSizePixel();
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ tools::Rectangle aOutputArea = rDevice.PixelToLogic( tools::Rectangle( Point(), aOutputSize ));
+ m_xEditView->SetOutputArea( aOutputArea );
+
+ // Don't leave an empty area at the bottom if we can move the text down.
+ tools::Long nMaxVisAreaTop = m_xEditEngine->GetTextHeight() - aOutputArea.GetHeight();
+ if (m_xEditView->GetVisArea().Top() > nMaxVisAreaTop)
+ {
+ m_xEditView->Scroll(0, m_xEditView->GetVisArea().Top() - nMaxVisAreaTop);
+ }
+
+ m_xEditEngine->SetPaperSize( rDevice.PixelToLogic( Size( aOutputSize.Width(), 10000 ) ) );
+ }
+
+ // skip WeldEditView's Resize();
+ weld::CustomWidgetController::Resize();
+
+ SetScrollBarRange();
+}
+
+int ScTextWnd::GetEditEngTxtHeight() const
+{
+ return m_xEditView ? m_xEditView->GetEditEngine()->GetTextHeight() : 0;
+}
+
+void ScTextWnd::SetScrollBarRange()
+{
+ if (!m_xEditView)
+ return;
+
+ OutputDevice& rDevice = GetDrawingArea()->get_ref_device();
+ Size aOutputSize = rDevice.GetOutputSize();
+
+ int nUpper = GetEditEngTxtHeight();
+ int nCurrentDocPos = m_xEditView->GetVisArea().Top();
+ int nStepIncrement = GetTextHeight();
+ int nPageIncrement = aOutputSize.Height();
+ int nPageSize = aOutputSize.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);
+
+ weld::ScrolledWindow& rVBar = mrGroupBar.GetScrollWin();
+ rVBar.vadjustment_configure(nCurrentDocPos, 0, nUpper,
+ nStepIncrement, nPageIncrement, nPageSize);
+}
+
+void ScTextWnd::DoScroll()
+{
+ if (m_xEditView)
+ {
+ weld::ScrolledWindow& rVBar = mrGroupBar.GetScrollWin();
+ auto currentDocPos = m_xEditView->GetVisArea().Top();
+ auto nDiff = currentDocPos - rVBar.vadjustment_get_value();
+ // we expect SetScrollBarRange callback to be triggered by Scroll
+ // to set where we ended up
+ m_xEditView->Scroll(0, nDiff);
+ }
+}
+
+void ScTextWnd::StartEditEngine()
+{
+ // Don't activate if we're a modal dialog ourselves (Doc-modal dialog)
+ SfxObjectShell* pObjSh = SfxObjectShell::Current();
+ if ( pObjSh && pObjSh->IsInModalMode() )
+ return;
+
+ if ( !m_xEditView || !m_xEditEngine )
+ {
+ InitEditEngine();
+ }
+
+ ScInputHandler* pHdl = mpViewShell->GetInputHandler();
+ if (pHdl)
+ pHdl->SetMode(SC_INPUT_TOP, nullptr, static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get()));
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
+}
+
+static void lcl_ExtendEditFontAttribs( SfxItemSet& rSet )
+{
+ const SfxPoolItem& rFontItem = rSet.Get( EE_CHAR_FONTINFO );
+ std::unique_ptr<SfxPoolItem> pNewItem(rFontItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_FONTINFO_CJK);
+ rSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_FONTINFO_CTL);
+ rSet.Put( *pNewItem );
+ const SfxPoolItem& rHeightItem = rSet.Get( EE_CHAR_FONTHEIGHT );
+ pNewItem.reset(rHeightItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_FONTHEIGHT_CJK);
+ rSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_FONTHEIGHT_CTL);
+ rSet.Put( *pNewItem );
+ const SfxPoolItem& rWeightItem = rSet.Get( EE_CHAR_WEIGHT );
+ pNewItem.reset(rWeightItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_WEIGHT_CJK);
+ rSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_WEIGHT_CTL);
+ rSet.Put( *pNewItem );
+ const SfxPoolItem& rItalicItem = rSet.Get( EE_CHAR_ITALIC );
+ pNewItem.reset(rItalicItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_ITALIC_CJK);
+ rSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_ITALIC_CTL);
+ rSet.Put( *pNewItem );
+ const SfxPoolItem& rLangItem = rSet.Get( EE_CHAR_LANGUAGE );
+ pNewItem.reset(rLangItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_LANGUAGE_CJK);
+ rSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_LANGUAGE_CTL);
+ rSet.Put( *pNewItem );
+}
+
+static void lcl_ModifyRTLDefaults( SfxItemSet& rSet )
+{
+ rSet.Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
+
+ // always using rtl writing direction would break formulas
+ //rSet.Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
+
+ // PaperSize width is limited to USHRT_MAX in RTL mode (because of EditEngine's
+ // sal_uInt16 values in EditLine), so the text may be wrapped and line spacing must be
+ // increased to not see the beginning of the next line.
+ SvxLineSpacingItem aItem( LINE_SPACE_DEFAULT_HEIGHT, EE_PARA_SBL );
+ aItem.SetPropLineSpace( 200 );
+ rSet.Put( aItem );
+}
+
+static void lcl_ModifyRTLVisArea( EditView* pEditView )
+{
+ tools::Rectangle aVisArea = pEditView->GetVisArea();
+ Size aPaper = pEditView->GetEditEngine()->GetPaperSize();
+ tools::Long nDiff = aPaper.Width() - aVisArea.Right();
+ aVisArea.AdjustLeft(nDiff );
+ aVisArea.AdjustRight(nDiff );
+ pEditView->SetVisArea(aVisArea);
+}
+
+void ScTextWnd::InitEditEngine()
+{
+ std::unique_ptr<ScFieldEditEngine> pNew;
+ ScDocShell* pDocSh = nullptr;
+ if ( mpViewShell )
+ {
+ pDocSh = mpViewShell->GetViewData().GetDocShell();
+ ScDocument& rDoc = mpViewShell->GetViewData().GetDocument();
+ pNew = std::make_unique<ScFieldEditEngine>(&rDoc, rDoc.GetEnginePool(), rDoc.GetEditPool());
+ }
+ else
+ pNew = std::make_unique<ScFieldEditEngine>(nullptr, EditEngine::CreatePool().get(), nullptr, true);
+ pNew->SetExecuteURL( false );
+ m_xEditEngine = std::move(pNew);
+
+ Size barSize = GetOutputSizePixel();
+ m_xEditEngine->SetUpdateLayout( false );
+ m_xEditEngine->SetPaperSize( GetDrawingArea()->get_ref_device().PixelToLogic(Size(barSize.Width(),10000)) );
+ m_xEditEngine->SetWordDelimiters(
+ ScEditUtil::ModifyDelimiters( m_xEditEngine->GetWordDelimiters() ) );
+ m_xEditEngine->SetReplaceLeadingSingleQuotationMark( false );
+
+ UpdateAutoCorrFlag();
+
+ {
+ auto pSet = std::make_unique<SfxItemSet>( m_xEditEngine->GetEmptyItemSet() );
+ EditEngine::SetFontInfoInItemSet( *pSet, aTextFont );
+ lcl_ExtendEditFontAttribs( *pSet );
+ // turn off script spacing to match DrawText output
+ pSet->Put( SvxScriptSpaceItem( false, EE_PARA_ASIANCJKSPACING ) );
+ if ( bIsRTL )
+ lcl_ModifyRTLDefaults( *pSet );
+ static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetDefaults( std::move(pSet) );
+ }
+
+ // If the Cell contains URLFields, they need to be taken over into the entry row,
+ // or else the position is not correct anymore
+ bool bFilled = false;
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if ( pHdl ) //! Test if it's the right InputHdl?
+ bFilled = pHdl->GetTextAndFields(static_cast<ScEditEngineDefaulter&>(*m_xEditEngine));
+
+ m_xEditEngine->SetUpdateLayout( true );
+
+ // aString is the truth ...
+ if (bFilled && m_xEditEngine->GetText() == aString)
+ Invalidate(); // Repaint for (filled) Field
+ else
+ static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetTextCurrentDefaults(aString); // At least the right text then
+
+ m_xEditView = std::make_unique<EditView>(m_xEditEngine.get(), nullptr);
+
+ // we get cursor, selection etc. messages from the VCL/window layer
+ // otherwise these are injected into the document causing confusion.
+ m_xEditView->SuppressLOKMessages(true);
+
+ m_xEditView->setEditViewCallbacks(this);
+ m_xEditView->SetInsertMode(bIsInsertMode);
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Color aBgColor = rStyleSettings.GetWindowColor();
+ m_xEditView->SetBackgroundColor(aBgColor);
+
+ if (pAcc)
+ {
+ pAcc->InitAcc(nullptr, m_xEditView.get(),
+ ScResId(STR_ACC_EDITLINE_NAME),
+ ScResId(STR_ACC_EDITLINE_DESCR));
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ m_xEditView->RegisterViewShell(mpViewShell);
+
+ // Text from Clipboard is taken over as ASCII in a single row
+ EVControlBits n = m_xEditView->GetControlWord();
+ m_xEditView->SetControlWord( n | EVControlBits::SINGLELINEPASTE );
+
+ m_xEditEngine->InsertView( m_xEditView.get(), EE_APPEND );
+
+ Resize();
+
+ if ( bIsRTL )
+ lcl_ModifyRTLVisArea( m_xEditView.get() );
+
+ m_xEditEngine->SetModifyHdl(LINK(this, ScTextWnd, ModifyHdl));
+ m_xEditEngine->SetStatusEventHdl(LINK(this, ScTextWnd, EditStatusHdl));
+
+ if (!maAccTextDatas.empty())
+ maAccTextDatas.back()->StartEdit();
+
+ // as long as EditEngine and DrawText sometimes differ for CTL text,
+ // repaint now to have the EditEngine's version visible
+ if (pDocSh)
+ {
+ ScDocument& rDoc = pDocSh->GetDocument(); // any document
+ SvtScriptType nScript = rDoc.GetStringScriptType( aString );
+ if ( nScript & SvtScriptType::COMPLEX )
+ Invalidate();
+ }
+}
+
+ScTextWnd::ScTextWnd(ScTextWndGroup& rParent, ScTabViewShell* pViewSh) :
+ bIsRTL(AllSettings::GetLayoutRTL()),
+ bIsInsertMode(true),
+ bFormulaMode (false),
+ bInputMode (false),
+ mpViewShell(pViewSh),
+ mrGroupBar(rParent),
+ mnLastExpandedLines(INPUTWIN_MULTILINES),
+ mbInvalidate(false)
+{
+}
+
+ScTextWnd::~ScTextWnd()
+{
+ while (!maAccTextDatas.empty()) {
+ maAccTextDatas.back()->Dispose();
+ }
+}
+
+bool ScTextWnd::MouseMove( const MouseEvent& rMEvt )
+{
+ return m_xEditView && m_xEditView->MouseMove(rMEvt);
+}
+
+bool ScTextWnd::CanFocus() const
+{
+ return SC_MOD()->IsEditMode();
+}
+
+bool ScTextWnd::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if (!HasFocus())
+ {
+ StartEditEngine();
+ if (CanFocus())
+ TextGrabFocus();
+ }
+
+ bool bClickOnSelection = false;
+ if (m_xEditView)
+ {
+ m_xEditView->SetEditEngineUpdateLayout( true );
+ bClickOnSelection = m_xEditView->IsSelectionAtPoint(rMEvt.GetPosPixel());
+ }
+ if (!bClickOnSelection)
+ {
+ rtl::Reference<TransferDataContainer> xTransferable(new TransferDataContainer);
+ GetDrawingArea()->enable_drag_source(xTransferable, DND_ACTION_NONE);
+ }
+ else
+ {
+ rtl::Reference<TransferDataContainer> xTransferable(m_xHelper);
+ GetDrawingArea()->enable_drag_source(xTransferable, DND_ACTION_COPY);
+ }
+ return WeldEditView::MouseButtonDown(rMEvt);
+}
+
+bool ScTextWnd::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ bool bRet = WeldEditView::MouseButtonUp(rMEvt);
+ if (bRet)
+ {
+ if ( rMEvt.IsMiddle() &&
+ Application::GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection )
+ {
+ // EditView may have pasted from selection
+ SC_MOD()->InputChanged( m_xEditView.get() );
+ }
+ else
+ SC_MOD()->InputSelection( m_xEditView.get() );
+ }
+ return bRet;
+}
+
+bool ScTextWnd::Command( const CommandEvent& rCEvt )
+{
+ bool bConsumed = false;
+
+ bInputMode = true;
+ CommandEventId nCommand = rCEvt.GetCommand();
+ if (m_xEditView)
+ {
+ ScModule* pScMod = SC_MOD();
+ ScTabViewShell* pStartViewSh = ScTabViewShell::GetActiveViewShell();
+
+ // don't modify the font defaults here - the right defaults are
+ // already set in StartEditEngine when the EditEngine is created
+
+ // Prevent that the EditView is lost when switching between Views
+ pScMod->SetInEditCommand( true );
+ m_xEditView->Command( rCEvt );
+ pScMod->SetInEditCommand( false );
+
+ // CommandEventId::StartDrag does not mean by far that the content was actually changed,
+ // so don't trigger an InputChanged.
+ //! Detect if dragged with Move or forbid Drag&Move somehow
+
+ if ( nCommand == CommandEventId::StartDrag )
+ {
+ // Is dragged onto another View?
+ ScTabViewShell* pEndViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pEndViewSh != pStartViewSh && pStartViewSh != nullptr )
+ {
+ ScViewData& rViewData = pStartViewSh->GetViewData();
+ ScInputHandler* pHdl = pScMod->GetInputHdl( pStartViewSh );
+ if ( pHdl && rViewData.HasEditView( rViewData.GetActivePart() ) )
+ {
+ pHdl->CancelHandler();
+ rViewData.GetView()->ShowCursor(); // Missing for KillEditView, due to being inactive
+ }
+ }
+ }
+ else if ( nCommand == CommandEventId::EndExtTextInput )
+ {
+ if (bFormulaMode)
+ {
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if (pHdl)
+ pHdl->InputCommand(rCEvt);
+ }
+ }
+ else if ( nCommand == CommandEventId::CursorPos )
+ {
+ // don't call InputChanged for CommandEventId::CursorPos
+ }
+ else if ( nCommand == CommandEventId::InputLanguageChange )
+ {
+ // #i55929# Font and font size state depends on input language if nothing is selected,
+ // so the slots have to be invalidated when the input language is changed.
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ {
+ SfxBindings& rBindings = pViewFrm->GetBindings();
+ rBindings.Invalidate( SID_ATTR_CHAR_FONT );
+ rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ }
+ }
+ else if ( nCommand == CommandEventId::ContextMenu )
+ {
+ bConsumed = true;
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ {
+ Point aPos = rCEvt.GetMousePosPixel();
+ if (!rCEvt.IsMouseEvent())
+ {
+ Size aSize = GetOutputSizePixel();
+ aPos = Point(aSize.Width() / 2, aSize.Height() / 2);
+ }
+ if (IsMouseCaptured())
+ ReleaseMouse();
+ pViewFrm->GetDispatcher()->ExecutePopup("formulabar", &mrGroupBar.GetVclParent(), &aPos);
+ }
+ }
+ else if ( nCommand == CommandEventId::Wheel )
+ {
+ //don't call InputChanged for CommandEventId::Wheel
+ }
+ else if ( nCommand == CommandEventId::Swipe )
+ {
+ //don't call InputChanged for CommandEventId::Swipe
+ }
+ else if ( nCommand == CommandEventId::LongPress )
+ {
+ //don't call InputChanged for CommandEventId::LongPress
+ }
+ else if ( nCommand == CommandEventId::ModKeyChange )
+ {
+ //pass alt press/release to parent impl
+ }
+ else
+ SC_MOD()->InputChanged( m_xEditView.get() );
+ }
+
+ if ( comphelper::LibreOfficeKit::isActive() && nCommand == CommandEventId::CursorPos )
+ {
+ // LOK uses this to setup caret position because drawingarea is replaced
+ // with text input field, it sends logical caret position (start, end) not pixels
+
+ StartEditEngine();
+ TextGrabFocus();
+
+ if (!m_xEditView)
+ return true;
+
+ Point aSelectionStartEnd = rCEvt.GetMousePosPixel();
+ m_xEditView->SetSelection(ESelection(0, aSelectionStartEnd.X(),
+ 0, aSelectionStartEnd.Y()));
+
+ SC_MOD()->InputSelection( m_xEditView.get() );
+
+ bConsumed = true;
+ }
+
+ bInputMode = false;
+
+ return bConsumed;
+}
+
+bool ScTextWnd::StartDrag()
+{
+ // tdf#145248 don't start a drag if actively selecting
+ if (m_xEditView && !m_xEditEngine->IsInSelectionMode())
+ {
+ OUString sSelection = m_xEditView->GetSelected();
+ m_xHelper->SetData(sSelection);
+ return sSelection.isEmpty();
+ }
+ return true;
+}
+
+bool ScTextWnd::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bUsed = true;
+ bInputMode = true;
+ if (!SC_MOD()->InputKeyEvent( rKEvt ))
+ {
+ bUsed = false;
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ bUsed = pViewSh->SfxKeyInput(rKEvt); // Only accelerators, no input
+ }
+ bInputMode = false;
+ return bUsed;
+}
+
+void ScTextWnd::GetFocus()
+{
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ pViewSh->SetFormShellAtTop( false ); // focus in input line -> FormShell no longer on top
+ WeldEditView::GetFocus();
+}
+
+void ScTextWnd::SetFormulaMode( bool bSet )
+{
+ if ( bSet != bFormulaMode )
+ {
+ bFormulaMode = bSet;
+ UpdateAutoCorrFlag();
+ }
+}
+
+void ScTextWnd::UpdateAutoCorrFlag()
+{
+ if (m_xEditEngine)
+ {
+ EEControlBits nControl = m_xEditEngine->GetControlWord();
+ EEControlBits nOld = nControl;
+ if ( bFormulaMode )
+ nControl &= ~EEControlBits::AUTOCORRECT; // No AutoCorrect in Formulas
+ else
+ nControl |= EEControlBits::AUTOCORRECT; // Else do enable it
+
+ if ( nControl != nOld )
+ m_xEditEngine->SetControlWord( nControl );
+ }
+}
+
+void ScTextWnd::EditViewScrollStateChange()
+{
+ // editengine height has changed or editview scroll pos has changed
+ SetScrollBarRange();
+}
+
+IMPL_LINK_NOARG(ScTextWnd, ModifyHdl, LinkParamNone*, void)
+{
+ if (m_xEditView && !bInputMode)
+ {
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+
+ // Use the InputHandler's InOwnChange flag to prevent calling InputChanged
+ // while an InputHandler method is modifying the EditEngine content
+
+ if ( pHdl && !pHdl->IsInOwnChange() )
+ pHdl->InputChanged( m_xEditView.get(), true ); // #i20282# InputChanged must know if called from modify handler
+ }
+}
+
+IMPL_LINK_NOARG(ScTextWnd, EditStatusHdl, EditStatus&, void)
+{
+ SetScrollBarRange();
+ DoScroll();
+ Invalidate();
+}
+
+void ScTextWnd::StopEditEngine( bool bAll )
+{
+ if (!m_xEditEngine)
+ return;
+
+ if (m_xEditView)
+ {
+ if (!maAccTextDatas.empty())
+ maAccTextDatas.back()->EndEdit();
+
+ ScModule* pScMod = SC_MOD();
+
+ if (!bAll)
+ pScMod->InputSelection( m_xEditView.get() );
+ aString = m_xEditEngine->GetText();
+ bIsInsertMode = m_xEditView->IsInsertMode();
+ bool bSelection = m_xEditView->HasSelection();
+ m_xEditEngine->SetStatusEventHdl(Link<EditStatus&, void>());
+ m_xEditEngine->SetModifyHdl(Link<LinkParamNone*,void>());
+ m_xEditView.reset();
+ m_xEditEngine.reset();
+
+ ScInputHandler* pHdl = mpViewShell->GetInputHandler();
+
+ if (pHdl && pHdl->IsEditMode() && !bAll)
+ pHdl->SetMode(SC_INPUT_TABLE);
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ pViewFrm->GetBindings().Invalidate( SID_ATTR_INSERT );
+
+ if (bSelection)
+ Invalidate(); // So that the Selection is not left there
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // Clear
+ std::vector<ReferenceMark> aReferenceMarks;
+ ScInputHandler::SendReferenceMarks( mpViewShell, aReferenceMarks );
+ }
+}
+
+static sal_Int32 findFirstNonMatchingChar(const OUString& rStr1, const OUString& rStr2)
+{
+ // Search the string for unmatching chars
+ const sal_Unicode* pStr1 = rStr1.getStr();
+ const sal_Unicode* pStr2 = rStr2.getStr();
+ sal_Int32 i = 0;
+ while ( i < rStr1.getLength() )
+ {
+ // Abort on the first unmatching char
+ if ( *pStr1 != *pStr2 )
+ return i;
+ ++pStr1;
+ ++pStr2;
+ ++i;
+ }
+
+ return i;
+}
+
+void ScTextWnd::SetTextString( const OUString& rNewString )
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ESelection aSel = m_xEditView ? m_xEditView->GetSelection() : ESelection();
+ ScInputHandler::LOKSendFormulabarUpdate(SfxViewShell::Current(), rNewString, aSel);
+ }
+
+ // Ideally it would be best to create on demand the EditEngine/EditView here, but... for
+ // the initialisation scenario where a cell is first clicked on we end up with the text in the
+ // inputbar window scrolled to the bottom if we do that here ( because the tableview and topview
+ // are synced I guess ).
+ // should fix that I suppose :-/ need to look a bit further into that
+ mbInvalidate = true; // ensure next Paint ( that uses editengine ) call will call Invalidate first
+
+ if ( rNewString != aString )
+ {
+ bInputMode = true;
+
+ // Find position of the change, only paint the rest
+ if (!m_xEditEngine)
+ {
+ bool bPaintAll = GetNumLines() > 1 || bIsRTL;
+ if (!bPaintAll)
+ {
+ // test if CTL script type is involved
+ SvtScriptType nOldScript = SvtScriptType::NONE;
+ SvtScriptType nNewScript = SvtScriptType::NONE;
+ SfxObjectShell* pObjSh = SfxObjectShell::Current();
+ if ( auto pDocShell = dynamic_cast<ScDocShell*>( pObjSh) )
+ {
+ // any document can be used (used only for its break iterator)
+ ScDocument& rDoc = pDocShell->GetDocument();
+ nOldScript = rDoc.GetStringScriptType( aString );
+ nNewScript = rDoc.GetStringScriptType( rNewString );
+ }
+ bPaintAll = ( nOldScript & SvtScriptType::COMPLEX ) || ( nNewScript & SvtScriptType::COMPLEX );
+ }
+
+ if ( bPaintAll )
+ {
+ // In multiline mode, or if CTL is involved, the whole text has to be redrawn
+ Invalidate();
+ }
+ else
+ {
+ tools::Long nTextSize = 0;
+ sal_Int32 nDifPos;
+ if (rNewString.getLength() > aString.getLength())
+ nDifPos = findFirstNonMatchingChar(rNewString, aString);
+ else
+ nDifPos = findFirstNonMatchingChar(aString, rNewString);
+
+ tools::Long nSize1 = GetTextWidth(aString);
+ tools::Long nSize2 = GetTextWidth(rNewString);
+ if ( nSize1>0 && nSize2>0 )
+ nTextSize = std::max( nSize1, nSize2 );
+ else
+ nTextSize = GetOutputSizePixel().Width(); // Overflow
+
+ Point aLogicStart = GetDrawingArea()->get_ref_device().PixelToLogic(Point(0,0));
+ tools::Long nStartPos = aLogicStart.X();
+ tools::Long nInvPos = nStartPos;
+ if (nDifPos)
+ nInvPos += GetTextWidth(aString.copy(0,nDifPos));
+
+ Invalidate(tools::Rectangle(nInvPos, 0, nStartPos+nTextSize, GetOutputSizePixel().Height() - 1));
+ }
+ }
+ else
+ {
+ static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetTextCurrentDefaults(rNewString);
+ }
+
+ aString = rNewString;
+
+ if (!maAccTextDatas.empty())
+ maAccTextDatas.back()->TextChanged();
+
+ bInputMode = false;
+ }
+
+ SetScrollBarRange();
+ DoScroll();
+}
+
+const OUString& ScTextWnd::GetTextString() const
+{
+ return aString;
+}
+
+bool ScTextWnd::IsInputActive()
+{
+ return HasFocus();
+}
+
+void ScTextWnd::MakeDialogEditView()
+{
+ if ( m_xEditView ) return;
+
+ std::unique_ptr<ScFieldEditEngine> pNew;
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ {
+ ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
+ pNew = std::make_unique<ScFieldEditEngine>(&rDoc, rDoc.GetEnginePool(), rDoc.GetEditPool());
+ }
+ else
+ pNew = std::make_unique<ScFieldEditEngine>(nullptr, EditEngine::CreatePool().get(), nullptr, true);
+ pNew->SetExecuteURL( false );
+ m_xEditEngine = std::move(pNew);
+
+ const bool bPrevUpdateLayout = m_xEditEngine->SetUpdateLayout( false );
+ m_xEditEngine->SetWordDelimiters( m_xEditEngine->GetWordDelimiters() + "=" );
+ m_xEditEngine->SetPaperSize( Size( bIsRTL ? USHRT_MAX : THESIZE, 300 ) );
+
+ auto pSet = std::make_unique<SfxItemSet>( m_xEditEngine->GetEmptyItemSet() );
+ EditEngine::SetFontInfoInItemSet( *pSet, aTextFont );
+ lcl_ExtendEditFontAttribs( *pSet );
+ if ( bIsRTL )
+ lcl_ModifyRTLDefaults( *pSet );
+ static_cast<ScEditEngineDefaulter*>(m_xEditEngine.get())->SetDefaults( std::move(pSet) );
+ m_xEditEngine->SetUpdateLayout( bPrevUpdateLayout );
+
+ m_xEditView = std::make_unique<EditView>(m_xEditEngine.get(), nullptr);
+ m_xEditView->setEditViewCallbacks(this);
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Color aBgColor = rStyleSettings.GetWindowColor();
+ m_xEditView->SetBackgroundColor(aBgColor);
+
+ if (pAcc)
+ {
+ pAcc->InitAcc(nullptr, m_xEditView.get(),
+ ScResId(STR_ACC_EDITLINE_NAME),
+ ScResId(STR_ACC_EDITLINE_DESCR));
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ m_xEditView->RegisterViewShell(mpViewShell);
+ m_xEditEngine->InsertView( m_xEditView.get(), EE_APPEND );
+
+ Resize();
+
+ if ( bIsRTL )
+ lcl_ModifyRTLVisArea( m_xEditView.get() );
+
+ if (!maAccTextDatas.empty())
+ maAccTextDatas.back()->StartEdit();
+}
+
+void ScTextWnd::ImplInitSettings()
+{
+ bIsRTL = AllSettings::GetLayoutRTL();
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ Color aBgColor= rStyleSettings.GetWindowColor();
+ Color aTxtColor= rStyleSettings.GetWindowTextColor();
+
+ aTextFont.SetFillColor ( aBgColor );
+ aTextFont.SetColor (aTxtColor);
+ Invalidate();
+}
+
+void ScTextWnd::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ // bypass WeldEditView::SetDrawingArea
+ weld::CustomWidgetController::SetDrawingArea(pDrawingArea);
+
+ // set cursor
+ pDrawingArea->set_cursor(PointerStyle::Text);
+
+ // initialize dnd, deliberately just a simple string so
+ // we don't transfer the happenstance formatting in
+ // the input line
+ m_xHelper.set(new svt::OStringTransferable(OUString()));
+ rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
+ SetDragDataTransferrable(xHelper, DND_ACTION_COPY);
+
+ OutputDevice& rDevice = pDrawingArea->get_ref_device();
+ pDrawingArea->set_margin_start(gnBorderWidth);
+ pDrawingArea->set_margin_end(gnBorderWidth);
+ // leave 1 for the width of the scrolledwindow border
+ pDrawingArea->set_margin_top(gnBorderHeight - 1);
+ pDrawingArea->set_margin_bottom(gnBorderHeight - 1);
+
+ // always use application font, so a font with cjk chars can be installed
+ vcl::Font aAppFont = Application::GetSettings().GetStyleSettings().GetAppFont();
+ weld::SetPointFont(rDevice, aAppFont);
+
+ aTextFont = rDevice.GetFont();
+ Size aFontSize = aTextFont.GetFontSize();
+ aTextFont.SetFontSize(rDevice.PixelToLogic(aFontSize, MapMode(MapUnit::MapTwip)));
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ Color aBgColor = rStyleSettings.GetWindowColor();
+ Color aTxtColor = rStyleSettings.GetWindowTextColor();
+
+ aTextFont.SetTransparent(true);
+ aTextFont.SetFillColor(aBgColor);
+ aTextFont.SetColor(aTxtColor);
+ aTextFont.SetWeight(WEIGHT_NORMAL);
+
+ Size aSize(1, GetPixelHeightForLines(1));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+
+ rDevice.SetBackground(aBgColor);
+ rDevice.SetLineColor(COL_BLACK);
+ rDevice.SetMapMode(MapMode(MapUnit::MapTwip));
+ rDevice.SetFont(aTextFont);
+
+ EnableRTL(false); // EditEngine can't be used with VCL EnableRTL
+}
+
+css::uno::Reference< css::accessibility::XAccessible > ScTextWnd::CreateAccessible()
+{
+ pAcc = new ScAccessibleEditLineObject(this);
+ return pAcc;
+}
+
+void ScTextWnd::InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
+{
+ OSL_ENSURE( ::std::find( maAccTextDatas.begin(), maAccTextDatas.end(), &rTextData ) == maAccTextDatas.end(),
+ "ScTextWnd::InsertAccessibleTextData - passed object already registered" );
+ maAccTextDatas.push_back( &rTextData );
+}
+
+void ScTextWnd::RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData )
+{
+ AccTextDataVector::iterator aEnd = maAccTextDatas.end();
+ AccTextDataVector::iterator aIt = ::std::find( maAccTextDatas.begin(), aEnd, &rTextData );
+ OSL_ENSURE( aIt != aEnd, "ScTextWnd::RemoveAccessibleTextData - passed object not registered" );
+ if( aIt != aEnd )
+ maAccTextDatas.erase( aIt );
+}
+
+void ScTextWnd::StyleUpdated()
+{
+ ImplInitSettings();
+ CustomWidgetController::Invalidate();
+}
+
+void ScTextWnd::TextGrabFocus()
+{
+ GrabFocus();
+}
+
+// Position window
+ScPosWnd::ScPosWnd(vcl::Window* pParent)
+ : InterimItemWindow(pParent, "modules/scalc/ui/posbox.ui", "PosBox")
+ , m_xWidget(m_xBuilder->weld_combo_box("pos_window"))
+ , m_nAsyncGetFocusId(nullptr)
+ , nTipVisible(nullptr)
+ , bFormulaMode(false)
+{
+ InitControlBase(m_xWidget.get());
+
+ // Use calculation according to tdf#132338 to align combobox width to width of fontname combobox within formatting toolbar;
+ // formatting toolbar is placed above formulabar when using multiple toolbars typically
+
+ m_xWidget->set_entry_width_chars(1);
+ Size aSize(LogicToPixel(Size(POSITION_COMBOBOX_WIDTH * 4, 0), MapMode(MapUnit::MapAppFont)));
+ m_xWidget->set_size_request(aSize.Width(), -1);
+ SetSizePixel(m_xContainer->get_preferred_size());
+
+ FillRangeNames();
+
+ StartListening( *SfxGetpApp() ); // For Navigator rangename updates
+
+ m_xWidget->connect_key_press(LINK(this, ScPosWnd, KeyInputHdl));
+ m_xWidget->connect_entry_activate(LINK(this, ScPosWnd, ActivateHdl));
+ m_xWidget->connect_changed(LINK(this, ScPosWnd, ModifyHdl));
+ m_xWidget->connect_focus_in(LINK(this, ScPosWnd, FocusInHdl));
+ m_xWidget->connect_focus_out(LINK(this, ScPosWnd, FocusOutHdl));
+}
+
+ScPosWnd::~ScPosWnd()
+{
+ disposeOnce();
+}
+
+void ScPosWnd::dispose()
+{
+ EndListening( *SfxGetpApp() );
+
+ HideTip();
+
+ if (m_nAsyncGetFocusId)
+ {
+ Application::RemoveUserEvent(m_nAsyncGetFocusId);
+ m_nAsyncGetFocusId = nullptr;
+ }
+ m_xWidget.reset();
+
+ InterimItemWindow::dispose();
+}
+
+void ScPosWnd::SetFormulaMode( bool bSet )
+{
+ if ( bSet != bFormulaMode )
+ {
+ bFormulaMode = bSet;
+
+ if ( bSet )
+ FillFunctions();
+ else
+ FillRangeNames();
+
+ HideTip();
+ }
+}
+
+void ScPosWnd::SetPos( const OUString& rPosStr )
+{
+ if ( aPosStr != rPosStr )
+ {
+ aPosStr = rPosStr;
+ m_xWidget->set_entry_text(aPosStr);
+ }
+}
+
+// static
+OUString ScPosWnd::createLocalRangeName(std::u16string_view rName, std::u16string_view rTableName)
+{
+ return OUString::Concat(rName) + " (" + rTableName + ")";
+}
+
+void ScPosWnd::FillRangeNames()
+{
+ m_xWidget->clear();
+ m_xWidget->freeze();
+
+ SfxObjectShell* pObjSh = SfxObjectShell::Current();
+ if ( auto pDocShell = dynamic_cast<ScDocShell*>( pObjSh) )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ m_xWidget->append_text(ScResId(STR_MANAGE_NAMES));
+ m_xWidget->append_separator("separator");
+
+ ScRange aDummy;
+ std::set<OUString> aSet;
+ ScRangeName* pRangeNames = rDoc.GetRangeName();
+ for (const auto& rEntry : *pRangeNames)
+ {
+ if (rEntry.second->IsValidReference(aDummy))
+ aSet.insert(rEntry.second->GetName());
+ }
+ for (SCTAB i = 0; i < rDoc.GetTableCount(); ++i)
+ {
+ ScRangeName* pLocalRangeName = rDoc.GetRangeName(i);
+ if (pLocalRangeName && !pLocalRangeName->empty())
+ {
+ OUString aTableName;
+ rDoc.GetName(i, aTableName);
+ for (const auto& rEntry : *pLocalRangeName)
+ {
+ if (rEntry.second->IsValidReference(aDummy))
+ aSet.insert(createLocalRangeName(rEntry.second->GetName(), aTableName));
+ }
+ }
+ }
+
+ for (const auto& rItem : aSet)
+ {
+ m_xWidget->append_text(rItem);
+ }
+ }
+ m_xWidget->thaw();
+ m_xWidget->set_entry_text(aPosStr);
+}
+
+void ScPosWnd::FillFunctions()
+{
+ m_xWidget->clear();
+ m_xWidget->freeze();
+
+ OUString aFirstName;
+ const ScAppOptions& rOpt = SC_MOD()->GetAppOptions();
+ sal_uInt16 nMRUCount = rOpt.GetLRUFuncListCount();
+ const sal_uInt16* pMRUList = rOpt.GetLRUFuncList();
+ if (pMRUList)
+ {
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ sal_uInt32 nListCount = pFuncList->GetCount();
+ for (sal_uInt16 i=0; i<nMRUCount; i++)
+ {
+ sal_uInt16 nId = pMRUList[i];
+ for (sal_uInt32 j=0; j<nListCount; j++)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction( j );
+ if ( pDesc->nFIndex == nId && pDesc->mxFuncName )
+ {
+ m_xWidget->append_text(*pDesc->mxFuncName);
+ if (aFirstName.isEmpty())
+ aFirstName = *pDesc->mxFuncName;
+ break; // Stop searching
+ }
+ }
+ }
+ }
+
+ //! Re-add entry "Other..." for Function AutoPilot if it can work with text that
+ // has been entered so far
+
+ // m_xWidget->append_text(ScResId(STR_FUNCTIONLIST_MORE));
+
+ m_xWidget->thaw();
+ m_xWidget->set_entry_text(aFirstName);
+}
+
+void ScPosWnd::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( bFormulaMode )
+ return;
+
+ // Does the list of range names need updating?
+ if ( auto pEventHint = dynamic_cast<const SfxEventHint*>(&rHint) )
+ {
+ SfxEventHintId nEventId = pEventHint->GetEventId();
+ if ( nEventId == SfxEventHintId::ActivateDoc )
+ FillRangeNames();
+ }
+ else
+ {
+ const SfxHintId nHintId = rHint.GetId();
+ if (nHintId == SfxHintId::ScAreasChanged || nHintId == SfxHintId::ScNavigatorUpdateAll)
+ FillRangeNames();
+ }
+}
+
+void ScPosWnd::HideTip()
+{
+ if (nTipVisible)
+ {
+ Help::HidePopover(this, nTipVisible);
+ nTipVisible = nullptr;
+ }
+}
+
+static ScNameInputType lcl_GetInputType( const OUString& rText )
+{
+ ScNameInputType eRet = SC_NAME_INPUT_BAD_NAME; // the more general error
+
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ ScAddress::Details aDetails( rDoc.GetAddressConvention());
+
+ // test in same order as in SID_CURRENTCELL execute
+
+ ScRange aRange;
+ ScAddress aAddress;
+ SCTAB nNameTab;
+ sal_Int32 nNumeric;
+
+ // From the context we know that when testing for a range name
+ // sheet-local scope names have " (sheetname)" appended and global
+ // names don't and can't contain ')', so we can force one or the other.
+ const RutlNameScope eNameScope =
+ ((!rText.isEmpty() && rText[rText.getLength()-1] == ')') ? RUTL_NAMES_LOCAL : RUTL_NAMES_GLOBAL);
+
+ if (rText == ScResId(STR_MANAGE_NAMES))
+ eRet = SC_MANAGE_NAMES;
+ else if ( aRange.Parse( rText, rDoc, aDetails ) & ScRefFlags::VALID )
+ eRet = SC_NAME_INPUT_RANGE;
+ else if ( aAddress.Parse( rText, rDoc, aDetails ) & ScRefFlags::VALID )
+ eRet = SC_NAME_INPUT_CELL;
+ else if ( ScRangeUtil::MakeRangeFromName( rText, rDoc, nTab, aRange, eNameScope, aDetails ) )
+ {
+ eRet = ((eNameScope == RUTL_NAMES_LOCAL) ? SC_NAME_INPUT_NAMEDRANGE_LOCAL :
+ SC_NAME_INPUT_NAMEDRANGE_GLOBAL);
+ }
+ else if ( ScRangeUtil::MakeRangeFromName( rText, rDoc, nTab, aRange, RUTL_DBASE, aDetails ) )
+ eRet = SC_NAME_INPUT_DATABASE;
+ else if ( comphelper::string::isdigitAsciiString( rText ) &&
+ ( nNumeric = rText.toInt32() ) > 0 && nNumeric <= rDoc.MaxRow()+1 )
+ eRet = SC_NAME_INPUT_ROW;
+ else if ( rDoc.GetTable( rText, nNameTab ) )
+ eRet = SC_NAME_INPUT_SHEET;
+ else if (ScRangeData::IsNameValid(rText, rDoc)
+ == ScRangeData::IsNameValidType::NAME_VALID) // nothing found, create new range?
+ {
+ if ( rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
+ eRet = SC_NAME_INPUT_DEFINE;
+ else
+ eRet = SC_NAME_INPUT_BAD_SELECTION;
+ }
+ else
+ eRet = SC_NAME_INPUT_BAD_NAME;
+ }
+
+ return eRet;
+}
+
+IMPL_LINK_NOARG(ScPosWnd, ModifyHdl, weld::ComboBox&, void)
+{
+ HideTip();
+
+ if (m_xWidget->changed_by_direct_pick())
+ {
+ DoEnter();
+ return;
+ }
+
+ if (bFormulaMode)
+ return;
+
+ // determine the action that would be taken for the current input
+
+ ScNameInputType eType = lcl_GetInputType(m_xWidget->get_active_text()); // uses current view
+ TranslateId pStrId;
+ switch ( eType )
+ {
+ case SC_NAME_INPUT_CELL:
+ pStrId = STR_NAME_INPUT_CELL;
+ break;
+ case SC_NAME_INPUT_RANGE:
+ case SC_NAME_INPUT_NAMEDRANGE_LOCAL:
+ case SC_NAME_INPUT_NAMEDRANGE_GLOBAL:
+ pStrId = STR_NAME_INPUT_RANGE; // named range or range reference
+ break;
+ case SC_NAME_INPUT_DATABASE:
+ pStrId = STR_NAME_INPUT_DBRANGE;
+ break;
+ case SC_NAME_INPUT_ROW:
+ pStrId = STR_NAME_INPUT_ROW;
+ break;
+ case SC_NAME_INPUT_SHEET:
+ pStrId = STR_NAME_INPUT_SHEET;
+ break;
+ case SC_NAME_INPUT_DEFINE:
+ pStrId = STR_NAME_INPUT_DEFINE;
+ break;
+ default:
+ // other cases (error): no tip help
+ break;
+ }
+
+ if (!pStrId)
+ return;
+
+ // show the help tip at the text cursor position
+ Point aPos;
+ vcl::Cursor* pCur = GetCursor();
+ if (pCur)
+ aPos = LogicToPixel( pCur->GetPos() );
+ aPos = OutputToScreenPixel( aPos );
+ tools::Rectangle aRect( aPos, aPos );
+
+ OUString aText = ScResId(pStrId);
+ QuickHelpFlags const nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
+ nTipVisible = Help::ShowPopover(this, aRect, aText, nAlign);
+}
+
+void ScPosWnd::DoEnter()
+{
+ OUString aText = m_xWidget->get_active_text();
+ if ( !aText.isEmpty() )
+ {
+ if ( bFormulaMode )
+ {
+ ScModule* pScMod = SC_MOD();
+ if ( aText == ScResId(STR_FUNCTIONLIST_MORE) )
+ {
+ // Function AutoPilot
+ //! Continue working with the text entered so far
+
+ //! new method at ScModule to query if function autopilot is open
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if ( pViewFrm && !pViewFrm->GetChildWindow( SID_OPENDLG_FUNCTION ) )
+ pViewFrm->GetDispatcher()->Execute( SID_OPENDLG_FUNCTION,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
+ }
+ else
+ {
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
+ if (pHdl)
+ pHdl->InsertFunction( aText );
+ }
+ }
+ else
+ {
+ // depending on the input, select something or create a new named range
+
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocShell* pDocShell = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScNameInputType eType = lcl_GetInputType( aText );
+ if ( eType == SC_NAME_INPUT_BAD_NAME || eType == SC_NAME_INPUT_BAD_SELECTION )
+ {
+ TranslateId pId = (eType == SC_NAME_INPUT_BAD_NAME) ? STR_NAME_ERROR_NAME : STR_NAME_ERROR_SELECTION;
+ pViewSh->ErrorMessage(pId);
+ }
+ else if ( eType == SC_NAME_INPUT_DEFINE )
+ {
+ ScRangeName* pNames = rDoc.GetRangeName();
+ ScRange aSelection;
+ if ( pNames && !pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aText)) &&
+ (rViewData.GetSimpleArea( aSelection ) == SC_MARK_SIMPLE) )
+ {
+ ScRangeName aNewRanges( *pNames );
+ ScAddress aCursor( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
+ OUString aContent(aSelection.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()));
+ ScRangeData* pNew = new ScRangeData( rDoc, aText, aContent, aCursor );
+ if ( aNewRanges.insert(pNew) )
+ {
+ pDocShell->GetDocFunc().ModifyRangeNames( aNewRanges );
+ pViewSh->UpdateInputHandler(true);
+ }
+ }
+ }
+ else if (eType == SC_MANAGE_NAMES)
+ {
+ sal_uInt16 nId = ScNameDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pViewSh->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ SC_MOD()->SetRefDialog( nId, pWnd == nullptr );
+ }
+ else
+ {
+ bool bForceGlobalName = false;
+ // for all selection types, execute the SID_CURRENTCELL slot.
+ if (eType == SC_NAME_INPUT_CELL || eType == SC_NAME_INPUT_RANGE)
+ {
+ // Note that SID_CURRENTCELL always expects address to
+ // be in Calc A1 format. Convert the text.
+ ScRange aRange(0,0, rViewData.GetTabNo());
+ aRange.ParseAny(aText, rDoc, rDoc.GetAddressConvention());
+ aText = aRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, ::formula::FormulaGrammar::CONV_OOO);
+ }
+ else if (eType == SC_NAME_INPUT_NAMEDRANGE_GLOBAL)
+ {
+ bForceGlobalName = true;
+ }
+
+ SfxStringItem aPosItem( SID_CURRENTCELL, aText );
+ SfxBoolItem aUnmarkItem( FN_PARAM_1, true ); // remove existing selection
+ // FN_PARAM_2 reserved for AlignToCursor
+ SfxBoolItem aForceGlobalName( FN_PARAM_3, bForceGlobalName );
+
+ pViewSh->GetViewData().GetDispatcher().ExecuteList( SID_CURRENTCELL,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aPosItem, &aUnmarkItem, &aForceGlobalName });
+ }
+ }
+ }
+ }
+ else
+ m_xWidget->set_entry_text(aPosStr);
+
+ ReleaseFocus_Impl();
+}
+
+IMPL_LINK_NOARG(ScPosWnd, ActivateHdl, weld::ComboBox&, bool)
+{
+ DoEnter();
+ return true;
+}
+
+IMPL_LINK(ScPosWnd, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = true;
+
+ switch (rKEvt.GetKeyCode().GetCode())
+ {
+ case KEY_RETURN:
+ bHandled = ActivateHdl(*m_xWidget);
+ break;
+ case KEY_ESCAPE:
+ if (nTipVisible)
+ {
+ // escape when the tip help is shown: only hide the tip
+ HideTip();
+ }
+ else
+ {
+ if (!bFormulaMode)
+ m_xWidget->set_entry_text(aPosStr);
+ ReleaseFocus_Impl();
+ }
+ break;
+ default:
+ bHandled = false;
+ break;
+ }
+
+ return bHandled || ChildKeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(ScPosWnd, OnAsyncGetFocus, void*, void)
+{
+ m_nAsyncGetFocusId = nullptr;
+ m_xWidget->select_entry_region(0, -1);
+}
+
+IMPL_LINK_NOARG(ScPosWnd, FocusInHdl, weld::Widget&, void)
+{
+ if (m_nAsyncGetFocusId)
+ return;
+ // do it async to defeat entry in combobox having its own ideas about the focus
+ m_nAsyncGetFocusId = Application::PostUserEvent(LINK(this, ScPosWnd, OnAsyncGetFocus));
+}
+
+IMPL_LINK_NOARG(ScPosWnd, FocusOutHdl, weld::Widget&, void)
+{
+ if (m_nAsyncGetFocusId)
+ {
+ Application::RemoveUserEvent(m_nAsyncGetFocusId);
+ m_nAsyncGetFocusId = nullptr;
+ }
+
+ HideTip();
+}
+
+void ScPosWnd::ReleaseFocus_Impl()
+{
+ HideTip();
+
+ SfxViewShell* pCurSh = SfxViewShell::Current();
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl( dynamic_cast<ScTabViewShell*>( pCurSh ) );
+ if ( pHdl && pHdl->IsTopMode() )
+ {
+ // Focus back in input row?
+ ScInputWindow* pInputWin = pHdl->GetInputWindow();
+ if (pInputWin)
+ {
+ pInputWin->TextGrabFocus();
+ return;
+ }
+ }
+
+ // Set focus to active View
+ if ( pCurSh )
+ {
+ vcl::Window* pShellWnd = pCurSh->GetWindow();
+
+ if ( pShellWnd )
+ pShellWnd->GrabFocus();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/lnktrans.cxx b/sc/source/ui/app/lnktrans.cxx
new file mode 100644
index 000000000..1ff48e7fe
--- /dev/null
+++ b/sc/source/ui/app/lnktrans.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 <svl/urlbmk.hxx>
+
+#include <lnktrans.hxx>
+#include <scmod.hxx>
+
+using namespace com::sun::star;
+
+ScLinkTransferObj::ScLinkTransferObj()
+{
+}
+
+ScLinkTransferObj::~ScLinkTransferObj()
+{
+}
+
+void ScLinkTransferObj::SetLinkURL( const OUString& rURL, const OUString& rText )
+{
+ aLinkURL = rURL;
+ aLinkText = rText;
+}
+
+void ScLinkTransferObj::AddSupportedFormats()
+{
+ if ( !aLinkURL.isEmpty() )
+ {
+ // TransferableHelper::SetINetBookmark formats
+
+ AddFormat( SotClipboardFormatId::SOLK );
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
+ AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
+ AddFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::FILECONTENT );
+ }
+}
+
+bool ScLinkTransferObj::GetData(
+ const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+{
+ bool bOK = false;
+ if ( !aLinkURL.isEmpty() )
+ {
+ INetBookmark aBmk( aLinkURL, aLinkText );
+ bOK = SetINetBookmark( aBmk, rFlavor );
+ }
+ return bOK;
+}
+
+void ScLinkTransferObj::DragFinished( sal_Int8 nDropAction )
+{
+ ScModule* pScMod = SC_MOD();
+ pScMod->ResetDragObject();
+
+ TransferDataContainer::DragFinished( nDropAction );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/msgpool.cxx b/sc/source/ui/app/msgpool.cxx
new file mode 100644
index 000000000..58daba682
--- /dev/null
+++ b/sc/source/ui/app/msgpool.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 <scitems.hxx>
+
+#include <sc.hrc>
+#include <docpool.hxx>
+#include <msgpool.hxx>
+
+SfxItemInfo const aMsgItemInfos[] =
+{
+ { 0, true }, // SCITEM_STRING
+ { 0, true }, // SCITEM_SEARCHDATA - stop using this!
+ { SID_SORT, true }, // SCITEM_SORTDATA
+ { SID_QUERY, true }, // SCITEM_QUERYDATA
+ { SID_SUBTOTALS, true }, // SCITEM_SUBTDATA
+ { SID_CONSOLIDATE, true }, // SCITEM_CONSOLIDATEDATA
+ { SID_PIVOT_TABLE, true }, // SCITEM_PIVOTDATA
+ { SID_SOLVE, true }, // SCITEM_SOLVEDATA
+ { SID_SCUSERLISTS, true }, // SCITEM_USERLIST
+ { 0, false } // SCITEM_CONDFORMATDLGDATA
+};
+
+ScMessagePool::ScMessagePool()
+ : SfxItemPool ( "ScMessagePool",
+ MSGPOOL_START, MSGPOOL_END,
+ aMsgItemInfos, nullptr ),
+
+ aGlobalStringItem ( SfxStringItem ( SCITEM_STRING, OUString() ) ),
+ aGlobalSearchItem ( SvxSearchItem ( SCITEM_SEARCHDATA ) ),
+ aGlobalSortItem ( ScSortItem ( SCITEM_SORTDATA, nullptr ) ),
+ aGlobalQueryItem ( ScQueryItem ( SCITEM_QUERYDATA, nullptr, nullptr ) ),
+ aGlobalSubTotalItem ( ScSubTotalItem ( SCITEM_SUBTDATA, nullptr, nullptr ) ),
+ aGlobalConsolidateItem ( ScConsolidateItem ( SCITEM_CONSOLIDATEDATA, nullptr ) ),
+ aGlobalPivotItem ( ScPivotItem ( SCITEM_PIVOTDATA, nullptr, nullptr, false ) ),
+ aGlobalSolveItem ( ScSolveItem ( SCITEM_SOLVEDATA, nullptr ) ),
+ aGlobalUserListItem ( ScUserListItem ( SCITEM_USERLIST ) ),
+ aCondFormatDlgItem ( ScCondFormatDlgItem ( nullptr, -1, false ) ),
+
+ mvPoolDefaults(MSGPOOL_END - MSGPOOL_START + 1),
+ pDocPool(new ScDocumentPool)
+{
+ mvPoolDefaults[SCITEM_STRING - MSGPOOL_START] = &aGlobalStringItem;
+ mvPoolDefaults[SCITEM_SEARCHDATA - MSGPOOL_START] = &aGlobalSearchItem;
+ mvPoolDefaults[SCITEM_SORTDATA - MSGPOOL_START] = &aGlobalSortItem;
+ mvPoolDefaults[SCITEM_QUERYDATA - MSGPOOL_START] = &aGlobalQueryItem;
+ mvPoolDefaults[SCITEM_SUBTDATA - MSGPOOL_START] = &aGlobalSubTotalItem;
+ mvPoolDefaults[SCITEM_CONSOLIDATEDATA - MSGPOOL_START] = &aGlobalConsolidateItem;
+ mvPoolDefaults[SCITEM_PIVOTDATA - MSGPOOL_START] = &aGlobalPivotItem;
+ mvPoolDefaults[SCITEM_SOLVEDATA - MSGPOOL_START] = &aGlobalSolveItem;
+ mvPoolDefaults[SCITEM_USERLIST - MSGPOOL_START] = &aGlobalUserListItem;
+ mvPoolDefaults[SCITEM_CONDFORMATDLGDATA - MSGPOOL_START] = &aCondFormatDlgItem;
+
+ SetDefaults( &mvPoolDefaults );
+
+ SetSecondaryPool( pDocPool.get() );
+}
+
+ScMessagePool::~ScMessagePool()
+{
+ Delete();
+ SetSecondaryPool( nullptr ); // before deleting defaults (accesses defaults)
+
+ for ( sal_uInt16 i=0; i <= MSGPOOL_END-MSGPOOL_START; i++ )
+ ClearRefCount( *mvPoolDefaults[i] );
+}
+
+MapUnit ScMessagePool::GetMetric( sal_uInt16 nWhich ) const
+{
+ // Own attributes: Twips, everything else 1/100 mm
+ if ( nWhich >= ATTR_STARTINDEX && nWhich <= ATTR_ENDINDEX )
+ return MapUnit::MapTwip;
+ else
+ return MapUnit::Map100thMM;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/rfindlst.cxx b/sc/source/ui/app/rfindlst.cxx
new file mode 100644
index 000000000..330b8479b
--- /dev/null
+++ b/sc/source/ui/app/rfindlst.cxx
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rfindlst.hxx>
+#include <tools/debug.hxx>
+
+#define SC_RANGECOLORS 8
+
+const Color aColNames[SC_RANGECOLORS] =
+ { COL_LIGHTBLUE, COL_LIGHTRED, COL_LIGHTMAGENTA, COL_GREEN,
+ COL_BLUE, COL_RED, COL_MAGENTA, COL_BROWN };
+
+ScRangeFindList::ScRangeFindList(const OUString& rName) :
+ aDocName( rName ),
+ bHidden( false ),
+ nIndexColor( 0 )
+{
+}
+
+Color ScRangeFindList::Insert( const ScRangeFindData &rNew )
+{
+ auto it = std::find_if(maEntries.begin(), maEntries.end(),
+ [&rNew](const ScRangeFindData& rEntry) { return rEntry.aRef == rNew.aRef; });
+ ScRangeFindData insertData(rNew);
+ insertData.nColor = ( it != maEntries.end() ? it->nColor :
+ ScRangeFindList::GetColorName( maEntries.size() ) );
+ maEntries.push_back(insertData);
+ nIndexColor = maEntries.size() - 1;
+ return insertData.nColor;
+}
+
+Color ScRangeFindList::GetColorName( const size_t nIndex )
+{
+ return aColNames[nIndex % SC_RANGECOLORS];
+}
+
+Color ScRangeFindList::FindColor( const ScRange& rRef, const size_t nIndex )
+{
+ sal_Int32 nOldCntr = 0;
+ sal_Int32 nNewCntr = 0;
+ Color nOldColor(0);
+ Color nNewColor(0);
+
+ DBG_ASSERT( (nIndex < maEntries.size()), "nIndex out of range!" );
+
+ nOldColor = maEntries[nIndex].nColor;
+ nNewColor = ScRangeFindList::GetColorName( nIndex );
+
+ std::vector<ScRangeFindData>::iterator it=maEntries.begin();
+ for( ;it!=maEntries.end(); ++it)
+ {
+ if(it->aRef == rRef)
+ break;
+
+ if (it->nColor == nOldColor )
+ nOldCntr++;
+
+ if (it->nColor == nNewColor )
+ nNewCntr++;
+ }
+
+ if ( it != maEntries.end() )
+ return it->nColor;
+
+ if ( nOldCntr == 1 )
+ return nOldColor;
+
+ if ( nNewCntr > 0 )
+ return ScRangeFindList::GetColorName( ++nIndexColor );
+
+ return nNewColor;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/scdll.cxx b/sc/source/ui/app/scdll.cxx
new file mode 100644
index 000000000..2256ee2e1
--- /dev/null
+++ b/sc/source/ui/app/scdll.cxx
@@ -0,0 +1,257 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <svx/fmobjfac.hxx>
+#include <svx/objfac3d.hxx>
+
+#include <comphelper/lok.hxx>
+#include <sfx2/sidebar/SidebarChildWindow.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/devtools/DevelopmentToolChildWindow.hxx>
+#include <avmedia/mediatoolbox.hxx>
+#include <NumberFormatControl.hxx>
+
+#include <unotools/resmgr.hxx>
+
+#include <scmod.hxx>
+#include <scresid.hxx>
+#include <sc.hrc>
+
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <prevwsh.hxx>
+#include <drawsh.hxx>
+#include <drformsh.hxx>
+#include <drtxtob.hxx>
+#include <editsh.hxx>
+#include <pivotsh.hxx>
+#include <auditsh.hxx>
+#include <cellsh.hxx>
+#include <oleobjsh.hxx>
+#include <chartsh.hxx>
+#include <graphsh.hxx>
+#include <mediash.hxx>
+#include <pgbrksh.hxx>
+#include <scdll.hxx>
+#include <SparklineShell.hxx>
+
+#include <appoptio.hxx>
+#include <searchresults.hxx>
+
+// Controls
+
+#include <svx/tbxctl.hxx>
+#include <svx/fillctrl.hxx>
+#include <svx/linectrl.hxx>
+//#include <svx/tbcontrl.hxx>
+#include <svx/selctrl.hxx>
+#include <svx/insctrl.hxx>
+#include <svx/zoomctrl.hxx>
+#include <svx/modctrl.hxx>
+#include <svx/pszctrl.hxx>
+#include <svx/grafctrl.hxx>
+#include <svx/clipboardctl.hxx>
+#include <svx/formatpaintbrushctrl.hxx>
+#include <tbzoomsliderctrl.hxx>
+#include <svx/zoomsliderctrl.hxx>
+
+#include <svx/xmlsecctrl.hxx>
+// Child windows
+#include <reffact.hxx>
+#include <navipi.hxx>
+#include <inputwin.hxx>
+#include <spelldialog.hxx>
+#include <svx/fontwork.hxx>
+#include <svx/srchdlg.hxx>
+#include <svx/hyperdlg.hxx>
+#include <svx/imapdlg.hxx>
+
+#include <filter.hxx>
+#include <scabstdlg.hxx>
+
+OUString ScResId(TranslateId aId)
+{
+ return Translate::get(aId, SC_MOD()->GetResLocale());
+}
+
+OUString ScResId(TranslateNId aContextSingularPlural, int nCardinality)
+{
+ return Translate::nget(aContextSingularPlural, nCardinality, SC_MOD()->GetResLocale());
+}
+
+void ScDLL::Init()
+{
+ if ( SfxApplication::GetModule(SfxToolsModule::Calc) ) // Module already active
+ return;
+
+ auto pUniqueModule = std::make_unique<ScModule>(&ScDocShell::Factory());
+ ScModule* pMod = pUniqueModule.get();
+ SfxApplication::SetModule(SfxToolsModule::Calc, std::move(pUniqueModule));
+
+ ScDocShell::Factory().SetDocumentServiceName( "com.sun.star.sheet.SpreadsheetDocument" );
+
+ // Not until the ResManager is initialized
+ // The AppOptions must be initialized not until after ScGlobal::Init
+ ScGlobal::Init();
+
+ // register your view-factories here
+ ScTabViewShell ::RegisterFactory(SFX_INTERFACE_SFXAPP);
+ ScPreviewShell ::RegisterFactory(SFX_INTERFACE_SFXDOCSH);
+
+ // register your shell-interfaces here
+ ScModule ::RegisterInterface(pMod);
+ ScDocShell ::RegisterInterface(pMod);
+ ScTabViewShell ::RegisterInterface(pMod);
+ ScPreviewShell ::RegisterInterface(pMod);
+ ScDrawShell ::RegisterInterface(pMod);
+ ScDrawFormShell ::RegisterInterface(pMod);
+ ScDrawTextObjectBar ::RegisterInterface(pMod);
+ ScEditShell ::RegisterInterface(pMod);
+ ScPivotShell ::RegisterInterface(pMod);
+ sc::SparklineShell ::RegisterInterface(pMod);
+ ScAuditingShell ::RegisterInterface(pMod);
+ ScFormatShell ::RegisterInterface(pMod);
+ ScCellShell ::RegisterInterface(pMod);
+ ScOleObjectShell ::RegisterInterface(pMod);
+ ScChartShell ::RegisterInterface(pMod);
+ ScGraphicShell ::RegisterInterface(pMod);
+ ScMediaShell ::RegisterInterface(pMod);
+ ScPageBreakShell ::RegisterInterface(pMod);
+
+ // Own Controller
+ ScZoomSliderControl ::RegisterControl(SID_PREVIEW_SCALINGFACTOR, pMod);
+
+ // SvxToolboxController
+ SvxTbxCtlDraw ::RegisterControl(SID_INSERT_DRAW, pMod);
+ SvxFillToolBoxControl ::RegisterControl(0, pMod);
+ SvxLineWidthToolBoxControl ::RegisterControl(0, pMod);
+ SvxClipBoardControl ::RegisterControl(SID_PASTE, pMod );
+ SvxClipBoardControl ::RegisterControl(SID_PASTE_UNFORMATTED, pMod );
+ svx::FormatPaintBrushToolBoxControl::RegisterControl(SID_FORMATPAINTBRUSH, pMod );
+ sc::ScNumberFormatControl ::RegisterControl(SID_NUMBER_TYPE_FORMAT, 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);
+
+ // Media Controller
+#if HAVE_FEATURE_AVMEDIA
+ ::avmedia::MediaToolBoxControl::RegisterControl( SID_AVMEDIA_TOOLBOX, pMod );
+#endif
+
+ // Common SFX Controller
+ sfx2::sidebar::SidebarChildWindow::RegisterChildWindow(false, pMod);
+ DevelopmentToolChildWindow::RegisterChildWindow(false, pMod);
+
+ // SvxStatusBar Controller
+ SvxInsertStatusBarControl ::RegisterControl(SID_ATTR_INSERT, pMod);
+ SvxSelectionModeControl ::RegisterControl(SID_STATUS_SELMODE, pMod);
+ SvxZoomStatusBarControl ::RegisterControl(SID_ATTR_ZOOM, pMod);
+ SvxZoomSliderControl ::RegisterControl(SID_ATTR_ZOOMSLIDER, pMod);
+ SvxModifyControl ::RegisterControl(SID_DOC_MODIFIED, pMod);
+ XmlSecStatusBarControl ::RegisterControl( SID_SIGNATURE, pMod );
+
+ SvxPosSizeStatusBarControl ::RegisterControl(SID_ATTR_SIZE, pMod);
+
+ // Child Windows
+
+ ScInputWindowWrapper ::RegisterChildWindow(true, pMod, SfxChildWindowFlags::TASK|SfxChildWindowFlags::FORCEDOCK);
+ ScSolverDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScOptSolverDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScXMLSourceDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScNameDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScNameDefDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScPivotLayoutWrapper ::RegisterChildWindow(false, pMod);
+ ScTabOpDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScFilterDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScSpecialFilterDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScDbNameDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScConsolidateDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScPrintAreasDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScColRowNameRangesDlgWrapper::RegisterChildWindow(false, pMod);
+ ScFormulaDlgWrapper ::RegisterChildWindow(false, pMod);
+
+ ScRandomNumberGeneratorDialogWrapper::RegisterChildWindow(false, pMod);
+ ScSamplingDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScDescriptiveStatisticsDialogWrapper::RegisterChildWindow(false, pMod);
+ ScAnalysisOfVarianceDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScCorrelationDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScCovarianceDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScExponentialSmoothingDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScMovingAverageDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScRegressionDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScTTestDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScFTestDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScZTestDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScChiSquareTestDialogWrapper ::RegisterChildWindow(false, pMod);
+ ScFourierAnalysisDialogWrapper ::RegisterChildWindow(false, pMod);
+ sc::SparklineDialogWrapper ::RegisterChildWindow(false, pMod);
+ sc::SparklineDataRangeDialogWrapper ::RegisterChildWindow(false, pMod);
+
+ // Redlining Window
+ ScAcceptChgDlgWrapper ::RegisterChildWindow(false, pMod);
+ ScSimpleRefDlgWrapper ::RegisterChildWindow(false, pMod, SfxChildWindowFlags::ALWAYSAVAILABLE|SfxChildWindowFlags::NEVERHIDE );
+ ScHighlightChgDlgWrapper ::RegisterChildWindow(false, pMod);
+
+ SvxSearchDialogWrapper ::RegisterChildWindow(false, pMod);
+ SvxHlinkDlgWrapper ::RegisterChildWindow(false, pMod);
+ SvxFontWorkChildWindow ::RegisterChildWindow(false, pMod);
+ SvxIMapDlgChildWindow ::RegisterChildWindow(false, pMod);
+ ScSpellDialogChildWindow::RegisterChildWindow(
+ false, pMod, comphelper::LibreOfficeKit::isActive() ? SfxChildWindowFlags::NEVERCLONE
+ : SfxChildWindowFlags::NONE);
+
+ ScValidityRefChildWin::RegisterChildWindow(false, pMod);
+ sc::SearchResultsDlgWrapper::RegisterChildWindow(false, pMod);
+ ScCondFormatDlgWrapper::RegisterChildWindow(false, pMod);
+
+ ScNavigatorWrapper::RegisterChildWindow(false, pMod, SfxChildWindowFlags::NEVERHIDE);
+
+ // Add 3DObject Factory
+ E3dObjFactory();
+
+ // Add css::form::component::FormObject Factory
+ FmFormObjFactory();
+
+ pMod->PutItem( SfxUInt16Item( SID_ATTR_METRIC, sal::static_int_cast<sal_uInt16>(pMod->GetAppOptions().GetAppMetric()) ) );
+
+ // StarOne Services are now handled in the registry
+}
+
+#ifndef DISABLE_DYNLOADING
+
+extern "C" SAL_DLLPUBLIC_EXPORT
+void lok_preload_hook()
+{
+ // scfilt
+ ScFormatFilter::Get();
+ // scui
+ ScAbstractDialogFactory::Create();
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/scmod.cxx b/sc/source/ui/app/scmod.cxx
new file mode 100644
index 000000000..1529f9920
--- /dev/null
+++ b/sc/source/ui/app/scmod.cxx
@@ -0,0 +1,2325 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/dialogs/XSLTFilterDialog.hpp>
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <scitems.hxx>
+#include <sfx2/app.hxx>
+
+#include <editeng/flditem.hxx>
+#include <editeng/outliner.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/objface.hxx>
+
+#include <IAnyRefDialog.hxx>
+
+#include <svtools/ehdl.hxx>
+#include <svtools/accessibilityoptions.hxx>
+#include <svl/ctloptions.hxx>
+#include <unotools/useroptions.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/printer.hxx>
+#include <editeng/langitem.hxx>
+#include <svtools/colorcfg.hxx>
+
+#include <svl/whiter.hxx>
+#include <svx/dialogs.hrc>
+#include <svl/inethist.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/svxerr.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <editeng/unolingu.hxx>
+#include <unotools/lingucfg.hxx>
+#include <i18nlangtag/mslangid.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/linguistic2/XThesaurus.hpp>
+#include <ooo/vba/XSinkCaller.hpp>
+
+#include <scmod.hxx>
+#include <global.hxx>
+#include <viewopti.hxx>
+#include <docoptio.hxx>
+#include <appoptio.hxx>
+#include <defaultsoptions.hxx>
+#include <formulaopt.hxx>
+#include <inputopt.hxx>
+#include <printopt.hxx>
+#include <navicfg.hxx>
+#include <addincfg.hxx>
+#include <tabvwsh.hxx>
+#include <prevwsh.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <uiitems.hxx>
+#include <sc.hrc>
+#include <scerrors.hrc>
+#include <scstyles.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <bitmaps.hlst>
+#include <inputhdl.hxx>
+#include <inputwin.hxx>
+#include <msgpool.hxx>
+#include <detfunc.hxx>
+#include <preview.hxx>
+#include <dragdata.hxx>
+#include <markdata.hxx>
+#include <transobj.hxx>
+#include <funcdesc.hxx>
+
+#define ShellClass_ScModule
+#include <scslots.hxx>
+
+#include <scabstdlg.hxx>
+#include <formula/errorcodes.hxx>
+#include <documentlinkmgr.hxx>
+
+#define SC_IDLE_MIN 150
+#define SC_IDLE_MAX 3000
+#define SC_IDLE_STEP 75
+#define SC_IDLE_COUNT 50
+
+static sal_uInt16 nIdleCount = 0;
+
+SFX_IMPL_INTERFACE(ScModule, SfxShell)
+
+void ScModule::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_APPLICATION,
+ SfxVisibilityFlags::Standard | SfxVisibilityFlags::Client | SfxVisibilityFlags::Viewer,
+ ToolbarId::Objectbar_App);
+
+ GetStaticInterface()->RegisterStatusBar(StatusBarId::CalcStatusBar);
+}
+
+ScModule::ScModule( SfxObjectFactory* pFact ) :
+ SfxModule("sc", {pFact}),
+ m_aIdleTimer("sc ScModule IdleTimer"),
+ m_pDragData(new ScDragData),
+ m_pSelTransfer( nullptr ),
+ m_pRefInputHandler( nullptr ),
+ m_nCurRefDlgId( 0 ),
+ m_bIsWaterCan( false ),
+ m_bIsInEditCommand( false ),
+ m_bIsInExecuteDrop( false ),
+ m_bIsInSharedDocLoading( false ),
+ m_bIsInSharedDocSaving( false )
+{
+ // The ResManager (DLL data) is not yet initialized in the ctor!
+ SetName("StarCalc"); // for Basic
+
+ ResetDragObject();
+
+ // InputHandler does not need to be created
+
+ // Create ErrorHandler - was in Init()
+ // Between OfficeApplication::Init and ScGlobal::Init
+ SvxErrorHandler::ensure();
+ m_pErrorHdl.reset( new SfxErrorHandler(RID_ERRHDLSC,
+ ErrCodeArea::Sc,
+ ErrCodeArea::Sc,
+ GetResLocale()) );
+
+ m_aIdleTimer.SetTimeout(SC_IDLE_MIN);
+ m_aIdleTimer.SetInvokeHandler( LINK( this, ScModule, IdleHandler ) );
+ m_aIdleTimer.Start();
+
+ m_pMessagePool = new ScMessagePool;
+ m_pMessagePool->FreezeIdRanges();
+ SetPool( m_pMessagePool.get() );
+ ScGlobal::InitTextHeight( m_pMessagePool.get() );
+
+ StartListening( *SfxGetpApp() ); // for SfxHintId::Deinitializing
+}
+
+ScModule::~ScModule()
+{
+ OSL_ENSURE( !m_pSelTransfer, "Selection Transfer object not deleted" );
+
+ // InputHandler does not need to be deleted (there's none in the App anymore)
+
+ m_pMessagePool.clear();
+
+ m_pDragData.reset();
+ m_pErrorHdl.reset();
+
+ ScGlobal::Clear(); // Also calls ScDocumentPool::DeleteVersionMaps();
+
+ DeleteCfg(); // Called from Exit()
+}
+
+void ScModule::ConfigurationChanged( utl::ConfigurationBroadcaster* p, ConfigurationHints )
+{
+ if ( p == m_pColorConfig.get() || p == m_pAccessOptions.get() )
+ {
+ // Test if detective objects have to be updated with new colors
+ // (if the detective colors haven't been used yet, there's nothing to update)
+ if ( ScDetectiveFunc::IsColorsInitialized() )
+ {
+ const svtools::ColorConfig& rColors = GetColorConfig();
+ bool bArrows =
+ ( ScDetectiveFunc::GetArrowColor() != rColors.GetColorValue(svtools::CALCDETECTIVE).nColor ||
+ ScDetectiveFunc::GetErrorColor() != rColors.GetColorValue(svtools::CALCDETECTIVEERROR).nColor );
+ bool bComments =
+ ( ScDetectiveFunc::GetCommentColor() != rColors.GetColorValue(svtools::CALCNOTESBACKGROUND).nColor );
+ if ( bArrows || bComments )
+ {
+ ScDetectiveFunc::InitializeColors(); // get the new colors
+
+ // update detective objects in all open documents
+ SfxObjectShell* pObjSh = SfxObjectShell::GetFirst();
+ while ( pObjSh )
+ {
+ if ( auto pDocSh = dynamic_cast<ScDocShell * >(pObjSh) )
+ {
+ if ( bArrows )
+ ScDetectiveFunc( pDocSh->GetDocument(), 0 ).UpdateAllArrowColors();
+ if ( bComments )
+ ScDetectiveFunc::UpdateAllComments( pDocSh->GetDocument() );
+ }
+ pObjSh = SfxObjectShell::GetNext( *pObjSh );
+ }
+ }
+ }
+
+ // force all views to repaint, using the new options
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while(pViewShell)
+ {
+ if (ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(pViewShell))
+ {
+ pViewSh->PaintGrid();
+ pViewSh->PaintTop();
+ pViewSh->PaintLeft();
+ pViewSh->PaintExtras();
+
+ ScInputHandler* pHdl = pViewSh->GetInputHandler();
+ if ( pHdl )
+ pHdl->ForgetLastPattern(); // EditEngine BackgroundColor may change
+ }
+ else if ( dynamic_cast<const ScPreviewShell*>( pViewShell) != nullptr )
+ {
+ vcl::Window* pWin = pViewShell->GetWindow();
+ if (pWin)
+ pWin->Invalidate();
+ }
+ pViewShell = SfxViewShell::GetNext( *pViewShell );
+ }
+ }
+ else if ( p == m_pCTLOptions.get() )
+ {
+ // for all documents: set digit language for printer, recalc output factor, update row heights
+ SfxObjectShell* pObjSh = SfxObjectShell::GetFirst();
+ while ( pObjSh )
+ {
+ if ( auto pDocSh = dynamic_cast<ScDocShell *>(pObjSh) )
+ {
+ OutputDevice* pPrinter = pDocSh->GetPrinter();
+ if ( pPrinter )
+ pPrinter->SetDigitLanguage( GetOptDigitLanguage() );
+
+ pDocSh->CalcOutputFactor();
+
+ SCTAB nTabCount = pDocSh->GetDocument().GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ pDocSh->AdjustRowHeight( 0, pDocSh->GetDocument().MaxRow(), nTab );
+ }
+ pObjSh = SfxObjectShell::GetNext( *pObjSh );
+ }
+
+ // for all views (table and preview): update digit language
+ SfxViewShell* pSh = SfxViewShell::GetFirst();
+ while ( pSh )
+ {
+ if (ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(pSh))
+ {
+ // set ref-device for EditEngine (re-evaluates digit settings)
+ ScInputHandler* pHdl = GetInputHdl(pViewSh);
+ if (pHdl)
+ pHdl->UpdateRefDevice();
+
+ pViewSh->DigitLanguageChanged();
+ pViewSh->PaintGrid();
+ }
+ else if (ScPreviewShell* pPreviewSh = dynamic_cast<ScPreviewShell*>(pSh))
+ {
+ ScPreview* pPreview = pPreviewSh->GetPreview();
+
+ pPreview->GetOutDev()->SetDigitLanguage( GetOptDigitLanguage() );
+ pPreview->Invalidate();
+ }
+
+ pSh = SfxViewShell::GetNext( *pSh );
+ }
+ }
+}
+
+void ScModule::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Deinitializing )
+ {
+ // ConfigItems must be removed before ConfigManager
+ DeleteCfg();
+ }
+}
+
+void ScModule::DeleteCfg()
+{
+ m_pViewCfg.reset(); // Saving happens automatically before Exit()
+ m_pDocCfg.reset();
+ m_pAppCfg.reset();
+ m_pDefaultsCfg.reset();
+ m_pFormulaCfg.reset();
+ m_pInputCfg.reset();
+ m_pPrintCfg.reset();
+ m_pNavipiCfg.reset();
+ m_pAddInCfg.reset();
+
+ if ( m_pColorConfig )
+ {
+ m_pColorConfig->RemoveListener(this);
+ m_pColorConfig.reset();
+ }
+ if ( m_pAccessOptions )
+ {
+ m_pAccessOptions->RemoveListener(this);
+ m_pAccessOptions.reset();
+ }
+ if ( m_pCTLOptions )
+ {
+ m_pCTLOptions->RemoveListener(this);
+ m_pCTLOptions.reset();
+ }
+ m_pUserOptions.reset();
+}
+
+// Moved here from the App
+
+void ScModule::Execute( SfxRequest& rReq )
+{
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ SfxBindings* pBindings = pViewFrm ? &pViewFrm->GetBindings() : nullptr;
+
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ switch ( nSlot )
+ {
+ case SID_CHOOSE_DESIGN:
+ SfxApplication::CallAppBasic( "Template.Samples.ShowStyles" );
+ break;
+ case SID_EURO_CONVERTER:
+ SfxApplication::CallAppBasic( "Euro.ConvertRun.Main" );
+ break;
+ case SID_AUTOSPELL_CHECK:
+ {
+ bool bSet;
+ const SfxPoolItem* pItem;
+ if (pReqArgs && SfxItemState::SET == pReqArgs->GetItemState( FN_PARAM_1, true, &pItem ))
+ bSet = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ else if ( pReqArgs && SfxItemState::SET == pReqArgs->GetItemState( nSlot, true, &pItem ) )
+ bSet = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ else
+ { // Toggle
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ if ( pDocSh )
+ bSet = !pDocSh->GetDocument().GetDocOptions().IsAutoSpell();
+ else
+ bSet = !GetDocOptions().IsAutoSpell();
+ }
+
+ SfxItemSetFixed<SID_AUTOSPELL_CHECK, SID_AUTOSPELL_CHECK> aSet( GetPool() );
+ aSet.Put( SfxBoolItem( SID_AUTOSPELL_CHECK, bSet ) );
+ ModifyOptions( aSet );
+ rReq.Done();
+ }
+ break;
+
+ case SID_ATTR_METRIC:
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && SfxItemState::SET == pReqArgs->GetItemState( nSlot, true, &pItem ) )
+ {
+ FieldUnit eUnit = static_cast<FieldUnit>(static_cast<const SfxUInt16Item*>(pItem)->GetValue());
+ switch( eUnit )
+ {
+ case FieldUnit::MM: // Just the units that are also in the dialog
+ case FieldUnit::CM:
+ case FieldUnit::INCH:
+ case FieldUnit::PICA:
+ case FieldUnit::POINT:
+ {
+ PutItem( *pItem );
+ ScAppOptions aNewOpts( GetAppOptions() );
+ aNewOpts.SetAppMetric( eUnit );
+ SetAppOptions( aNewOpts );
+ rReq.Done();
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ break;
+
+ case FID_AUTOCOMPLETE:
+ {
+ ScAppOptions aNewOpts( GetAppOptions() );
+ bool bNew = !aNewOpts.GetAutoComplete();
+ aNewOpts.SetAutoComplete( bNew );
+ SetAppOptions( aNewOpts );
+ if (pBindings)
+ pBindings->Invalidate( FID_AUTOCOMPLETE );
+ rReq.Done();
+ }
+ break;
+
+ case SID_DETECTIVE_AUTO:
+ {
+ ScAppOptions aNewOpts( GetAppOptions() );
+ bool bNew = !aNewOpts.GetDetectiveAuto();
+ const SfxBoolItem* pAuto = rReq.GetArg<SfxBoolItem>(SID_DETECTIVE_AUTO);
+ if ( pAuto )
+ bNew = pAuto->GetValue();
+
+ aNewOpts.SetDetectiveAuto( bNew );
+ SetAppOptions( aNewOpts );
+ if (pBindings)
+ pBindings->Invalidate( SID_DETECTIVE_AUTO );
+ rReq.AppendItem( SfxBoolItem( SID_DETECTIVE_AUTO, bNew ) );
+ rReq.Done();
+ }
+ break;
+
+ case SID_PSZ_FUNCTION:
+ if (pReqArgs)
+ {
+ auto const & p = pReqArgs->Get(SID_PSZ_FUNCTION);
+ assert(dynamic_cast<const SfxUInt32Item*>(&p) && "wrong Parameter");
+ const SfxUInt32Item& rItem = static_cast<const SfxUInt32Item&>(p);
+
+ ScAppOptions aNewOpts( GetAppOptions() );
+ aNewOpts.SetStatusFunc( rItem.GetValue() );
+ SetAppOptions( aNewOpts );
+
+ if (pBindings)
+ {
+ pBindings->Invalidate( SID_TABLE_CELL );
+ pBindings->Update( SID_TABLE_CELL ); // Immediately
+
+ pBindings->Invalidate( SID_PSZ_FUNCTION );
+ pBindings->Update( SID_PSZ_FUNCTION );
+ // If the menu is opened again immediately
+ }
+ }
+ break;
+
+ case SID_ATTR_LANGUAGE:
+ case SID_ATTR_CHAR_CJK_LANGUAGE:
+ case SID_ATTR_CHAR_CTL_LANGUAGE:
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && SfxItemState::SET == pReqArgs->GetItemState( GetPool().GetWhich(nSlot), true, &pItem ) )
+ {
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ LanguageType eNewLang = static_cast<const SvxLanguageItem*>(pItem)->GetLanguage();
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+ LanguageType eOld = ( nSlot == SID_ATTR_CHAR_CJK_LANGUAGE ) ? eCjk :
+ ( ( nSlot == SID_ATTR_CHAR_CTL_LANGUAGE ) ? eCtl : eLatin );
+ if ( eNewLang != eOld )
+ {
+ if ( nSlot == SID_ATTR_CHAR_CJK_LANGUAGE )
+ eCjk = eNewLang;
+ else if ( nSlot == SID_ATTR_CHAR_CTL_LANGUAGE )
+ eCtl = eNewLang;
+ else
+ eLatin = eNewLang;
+
+ rDoc.SetLanguage( eLatin, eCjk, eCtl );
+
+ ScInputHandler* pInputHandler = GetInputHdl();
+ if ( pInputHandler )
+ pInputHandler->UpdateSpellSettings(); // EditEngine flags
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( pViewSh )
+ pViewSh->UpdateDrawTextOutliner(); // EditEngine flags
+
+ pDocSh->SetDocumentModified();
+ }
+ }
+ }
+ }
+ break;
+
+ case FID_FOCUS_POSWND:
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ {
+ ScInputWindow* pWin = pHdl->GetInputWindow();
+ if (pWin)
+ pWin->PosGrabFocus();
+ }
+ rReq.Done();
+ }
+ 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("sc.ui");
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL( "ScApplication: Unknown Message." );
+ break;
+ }
+}
+
+void ScModule::GetState( SfxItemSet& rSet )
+{
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ bool bTabView = pDocSh && (pDocSh->GetBestViewShell() != nullptr);
+
+ SfxWhichIter aIter(rSet);
+ for (sal_uInt16 nWhich = aIter.FirstWhich(); nWhich; nWhich = aIter.NextWhich())
+ {
+ if (!bTabView)
+ {
+ // Not in the normal calc view shell (most likely in preview shell). Disable all actions.
+ rSet.DisableItem(nWhich);
+ continue;
+ }
+
+ switch ( nWhich )
+ {
+ case FID_AUTOCOMPLETE:
+ rSet.Put( SfxBoolItem( nWhich, GetAppOptions().GetAutoComplete() ) );
+ break;
+ case SID_DETECTIVE_AUTO:
+ rSet.Put( SfxBoolItem( nWhich, GetAppOptions().GetDetectiveAuto() ) );
+ break;
+ case SID_PSZ_FUNCTION:
+ rSet.Put( SfxUInt32Item( nWhich, GetAppOptions().GetStatusFunc() ) );
+ break;
+ case SID_ATTR_METRIC:
+ rSet.Put( SfxUInt16Item( nWhich, sal::static_int_cast<sal_uInt16>(GetAppOptions().GetAppMetric()) ) );
+ break;
+ case SID_AUTOSPELL_CHECK:
+ rSet.Put( SfxBoolItem( nWhich, pDocSh->GetDocument().GetDocOptions().IsAutoSpell()) );
+ break;
+ case SID_ATTR_LANGUAGE:
+ case ATTR_CJK_FONT_LANGUAGE: // WID for SID_ATTR_CHAR_CJK_LANGUAGE
+ case ATTR_CTL_FONT_LANGUAGE: // WID for SID_ATTR_CHAR_CTL_LANGUAGE
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ pDocSh->GetDocument().GetLanguage( eLatin, eCjk, eCtl );
+ LanguageType eLang = ( nWhich == ATTR_CJK_FONT_LANGUAGE ) ? eCjk :
+ ( ( nWhich == ATTR_CTL_FONT_LANGUAGE ) ? eCtl : eLatin );
+ rSet.Put( SvxLanguageItem( eLang, nWhich ) );
+ }
+ break;
+ }
+ }
+}
+
+void ScModule::HideDisabledSlots( SfxItemSet& rSet )
+{
+ if( SfxViewFrame* pViewFrm = SfxViewFrame::Current() )
+ {
+ SfxBindings& rBindings = pViewFrm->GetBindings();
+ SfxWhichIter aIter( rSet );
+ for( sal_uInt16 nWhich = aIter.FirstWhich(); nWhich != 0; nWhich = aIter.NextWhich() )
+ {
+ ScViewUtil::HideDisabledSlot( rSet, rBindings, nWhich );
+ // always disable the slots
+ rSet.DisableItem( nWhich );
+ }
+ }
+}
+
+void ScModule::ResetDragObject()
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->ResetDragObject();
+ }
+ else
+ {
+ m_pDragData->pCellTransfer = nullptr;
+ m_pDragData->pDrawTransfer = nullptr;
+ m_pDragData->pJumpLocalDoc = nullptr;
+ m_pDragData->aLinkDoc.clear();
+ m_pDragData->aLinkTable.clear();
+ m_pDragData->aLinkArea.clear();
+ m_pDragData->aJumpTarget.clear();
+ m_pDragData->aJumpText.clear();
+ }
+}
+
+const ScDragData& ScModule::GetDragData() const
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ assert(pViewShell);
+ return pViewShell->GetDragData();
+ }
+ else
+ return *m_pDragData;
+}
+
+void ScModule::SetDragObject( ScTransferObj* pCellObj, ScDrawTransferObj* pDrawObj )
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetDragObject(pCellObj, pDrawObj);
+ }
+ else
+ {
+ ResetDragObject();
+ m_pDragData->pCellTransfer = pCellObj;
+ m_pDragData->pDrawTransfer = pDrawObj;
+ }
+}
+
+void ScModule::SetDragLink(
+ const OUString& rDoc, const OUString& rTab, const OUString& rArea )
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetDragLink(rDoc, rTab, rArea);
+ }
+ else
+ {
+ ResetDragObject();
+ m_pDragData->aLinkDoc = rDoc;
+ m_pDragData->aLinkTable = rTab;
+ m_pDragData->aLinkArea = rArea;
+ }
+}
+
+void ScModule::SetDragJump(
+ ScDocument* pLocalDoc, const OUString& rTarget, const OUString& rText )
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetDragJump(pLocalDoc, rTarget, rText);
+ }
+ else
+ {
+ ResetDragObject();
+
+ m_pDragData->pJumpLocalDoc = pLocalDoc;
+ m_pDragData->aJumpTarget = rTarget;
+ m_pDragData->aJumpText = rText;
+ }
+}
+
+ScDocument* ScModule::GetClipDoc()
+{
+ // called from document
+ SfxViewFrame* pViewFrame = nullptr;
+ ScTabViewShell* pViewShell = nullptr;
+ css::uno::Reference<css::datatransfer::XTransferable2> xTransferable;
+
+ if ((pViewShell = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current())))
+ xTransferable.set(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin()));
+ else if ((pViewShell = dynamic_cast<ScTabViewShell*>(SfxViewShell::GetFirst())))
+ xTransferable.set(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin()));
+ else if ((pViewFrame = SfxViewFrame::GetFirst()))
+ {
+ css::uno::Reference<css::datatransfer::clipboard::XClipboard> xClipboard =
+ pViewFrame->GetWindow().GetClipboard();
+ xTransferable.set(xClipboard.is() ? xClipboard->getContents() : nullptr, css::uno::UNO_QUERY);
+ }
+
+ const ScTransferObj* pObj = ScTransferObj::GetOwnClipboard(xTransferable);
+ if (pObj)
+ {
+ ScDocument* pDoc = pObj->GetDocument();
+ assert((!pDoc || pDoc->IsClipboard()) && "Document is not clipboard, how can that be?");
+ return pDoc;
+ }
+
+ return nullptr;
+}
+
+void ScModule::SetSelectionTransfer( ScSelectionTransferObj* pNew )
+{
+ m_pSelTransfer = pNew;
+}
+
+void ScModule::SetViewOptions( const ScViewOptions& rOpt )
+{
+ if ( !m_pViewCfg )
+ m_pViewCfg.reset(new ScViewCfg);
+
+ m_pViewCfg->SetOptions( rOpt );
+}
+
+const ScViewOptions& ScModule::GetViewOptions()
+{
+ if ( !m_pViewCfg )
+ m_pViewCfg.reset( new ScViewCfg );
+
+ return *m_pViewCfg;
+}
+
+void ScModule::SetDocOptions( const ScDocOptions& rOpt )
+{
+ if ( !m_pDocCfg )
+ m_pDocCfg.reset( new ScDocCfg );
+
+ m_pDocCfg->SetOptions( rOpt );
+}
+
+const ScDocOptions& ScModule::GetDocOptions()
+{
+ if ( !m_pDocCfg )
+ m_pDocCfg.reset( new ScDocCfg );
+
+ return *m_pDocCfg;
+}
+
+void ScModule::InsertEntryToLRUList(sal_uInt16 nFIndex)
+{
+ if(nFIndex == 0)
+ return;
+
+ const ScAppOptions& rAppOpt = GetAppOptions();
+ sal_uInt16 nLRUFuncCount = std::min( rAppOpt.GetLRUFuncListCount(), sal_uInt16(LRU_MAX) );
+ sal_uInt16* pLRUListIds = rAppOpt.GetLRUFuncList();
+
+ sal_uInt16 aIdxList[LRU_MAX];
+ sal_uInt16 n = 0;
+ bool bFound = false;
+
+ while ((n < LRU_MAX) && n<nLRUFuncCount) // Iterate through old list
+ {
+ if (!bFound && (pLRUListIds[n]== nFIndex))
+ bFound = true; // First hit!
+ else if (bFound)
+ aIdxList[n ] = pLRUListIds[n]; // Copy after hit
+ else if ((n+1) < LRU_MAX)
+ aIdxList[n+1] = pLRUListIds[n]; // Move before hit
+ n++;
+ }
+ if (!bFound && (n < LRU_MAX)) // Entry not found?
+ n++; // One more
+ aIdxList[0] = nFIndex; // Current on Top
+
+ ScAppOptions aNewOpts(rAppOpt); // Let App know
+ aNewOpts.SetLRUFuncList(aIdxList, n);
+ SetAppOptions(aNewOpts);
+}
+
+void ScModule::SetAppOptions( const ScAppOptions& rOpt )
+{
+ if ( !m_pAppCfg )
+ m_pAppCfg.reset( new ScAppCfg );
+
+ m_pAppCfg->SetOptions( rOpt );
+}
+
+void global_InitAppOptions()
+{
+ SC_MOD()->GetAppOptions();
+}
+
+const ScAppOptions& ScModule::GetAppOptions()
+{
+ if ( !m_pAppCfg )
+ m_pAppCfg.reset( new ScAppCfg );
+
+ return m_pAppCfg->GetOptions();
+}
+
+void ScModule::SetDefaultsOptions( const ScDefaultsOptions& rOpt )
+{
+ if ( !m_pDefaultsCfg )
+ m_pDefaultsCfg.reset( new ScDefaultsCfg );
+
+ m_pDefaultsCfg->SetOptions( rOpt );
+}
+
+const ScDefaultsOptions& ScModule::GetDefaultsOptions()
+{
+ if ( !m_pDefaultsCfg )
+ m_pDefaultsCfg.reset( new ScDefaultsCfg );
+
+ return *m_pDefaultsCfg;
+}
+
+void ScModule::SetFormulaOptions( const ScFormulaOptions& rOpt )
+{
+ if ( !m_pFormulaCfg )
+ m_pFormulaCfg.reset( new ScFormulaCfg );
+
+ m_pFormulaCfg->SetOptions( rOpt );
+}
+
+const ScFormulaOptions& ScModule::GetFormulaOptions()
+{
+ if ( !m_pFormulaCfg )
+ m_pFormulaCfg.reset( new ScFormulaCfg );
+
+ return *m_pFormulaCfg;
+}
+
+void ScModule::SetInputOptions( const ScInputOptions& rOpt )
+{
+ if ( !m_pInputCfg )
+ m_pInputCfg.reset( new ScInputCfg );
+
+ m_pInputCfg->SetOptions( rOpt );
+}
+
+const ScInputOptions& ScModule::GetInputOptions()
+{
+ if ( !m_pInputCfg )
+ m_pInputCfg.reset( new ScInputCfg );
+
+ return m_pInputCfg->GetOptions();
+}
+
+void ScModule::SetPrintOptions( const ScPrintOptions& rOpt )
+{
+ if ( !m_pPrintCfg )
+ m_pPrintCfg.reset( new ScPrintCfg );
+
+ m_pPrintCfg->SetOptions( rOpt );
+}
+
+const ScPrintOptions& ScModule::GetPrintOptions()
+{
+ if ( !m_pPrintCfg )
+ m_pPrintCfg.reset( new ScPrintCfg );
+
+ return m_pPrintCfg->GetOptions();
+}
+
+ScNavipiCfg& ScModule::GetNavipiCfg()
+{
+ if ( !m_pNavipiCfg )
+ m_pNavipiCfg.reset( new ScNavipiCfg );
+
+ return *m_pNavipiCfg;
+}
+
+ScAddInCfg& ScModule::GetAddInCfg()
+{
+ if ( !m_pAddInCfg )
+ m_pAddInCfg.reset( new ScAddInCfg );
+
+ return *m_pAddInCfg;
+}
+
+svtools::ColorConfig& ScModule::GetColorConfig()
+{
+ if ( !m_pColorConfig )
+ {
+ m_pColorConfig.reset( new svtools::ColorConfig );
+ m_pColorConfig->AddListener(this);
+ }
+
+ return *m_pColorConfig;
+}
+
+SvtAccessibilityOptions& ScModule::GetAccessOptions()
+{
+ if ( !m_pAccessOptions )
+ {
+ m_pAccessOptions.reset( new SvtAccessibilityOptions );
+ m_pAccessOptions->AddListener(this);
+ }
+
+ return *m_pAccessOptions;
+}
+
+SvtCTLOptions& ScModule::GetCTLOptions()
+{
+ if ( !m_pCTLOptions )
+ {
+ m_pCTLOptions.reset( new SvtCTLOptions );
+ m_pCTLOptions->AddListener(this);
+ }
+
+ return *m_pCTLOptions;
+}
+
+SvtUserOptions& ScModule::GetUserOptions()
+{
+ if( !m_pUserOptions )
+ {
+ m_pUserOptions.reset( new SvtUserOptions );
+ }
+ return *m_pUserOptions;
+}
+
+LanguageType ScModule::GetOptDigitLanguage()
+{
+ SvtCTLOptions::TextNumerals eNumerals = GetCTLOptions().GetCTLTextNumerals();
+ return ( eNumerals == SvtCTLOptions::NUMERALS_ARABIC ) ? LANGUAGE_ENGLISH_US :
+ ( eNumerals == SvtCTLOptions::NUMERALS_HINDI) ? LANGUAGE_ARABIC_SAUDI_ARABIA :
+ LANGUAGE_SYSTEM;
+}
+
+/**
+ * Options
+ *
+ * Items from Calc options dialog and SID_AUTOSPELL_CHECK
+ */
+void ScModule::ModifyOptions( const SfxItemSet& rOptSet )
+{
+ LanguageType nOldSpellLang, nOldCjkLang, nOldCtlLang;
+ bool bOldAutoSpell;
+ GetSpellSettings( nOldSpellLang, nOldCjkLang, nOldCtlLang, bOldAutoSpell );
+
+ if (!m_pAppCfg)
+ GetAppOptions();
+ OSL_ENSURE( m_pAppCfg, "AppOptions not initialised :-(" );
+
+ if (!m_pInputCfg)
+ GetInputOptions();
+ OSL_ENSURE( m_pInputCfg, "InputOptions not initialised :-(" );
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ SfxBindings* pBindings = pViewFrm ? &pViewFrm->GetBindings() : nullptr;
+
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ ScDocument* pDoc = pDocSh ? &pDocSh->GetDocument() : nullptr;
+ bool bRepaint = false;
+ bool bUpdateMarks = false;
+ bool bUpdateRefDev = false;
+ bool bCalcAll = false;
+ bool bSaveAppOptions = false;
+ bool bSaveInputOptions = false;
+ bool bCompileErrorCells = false;
+
+ // SfxGetpApp()->SetOptions( rOptSet );
+
+ ScAppOptions aAppOptions = m_pAppCfg->GetOptions();
+
+ // No more linguistics
+ if (const SfxUInt16Item* pItem = rOptSet.GetItemIfSet(SID_ATTR_METRIC))
+ {
+ PutItem( *pItem );
+ aAppOptions.SetAppMetric( static_cast<FieldUnit>(pItem->GetValue()) );
+ bSaveAppOptions = true;
+ }
+
+ if (const ScUserListItem* pItem = rOptSet.GetItemIfSet(SCITEM_USERLIST))
+ {
+ ScGlobal::SetUserList( pItem->GetUserList() );
+ bSaveAppOptions = true;
+ }
+
+ if (const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_OPT_SYNCZOOM))
+ {
+ aAppOptions.SetSynchronizeZoom( pItem->GetValue() );
+ bSaveAppOptions = true;
+ }
+
+ if (const SfxUInt16Item* pItem = rOptSet.GetItemIfSet(SID_SC_OPT_KEY_BINDING_COMPAT))
+ {
+ sal_uInt16 nVal = pItem->GetValue();
+ ScOptionsUtil::KeyBindingType eOld = aAppOptions.GetKeyBindingType();
+ ScOptionsUtil::KeyBindingType eNew = static_cast<ScOptionsUtil::KeyBindingType>(nVal);
+ if (eOld != eNew)
+ {
+ aAppOptions.SetKeyBindingType(eNew);
+ bSaveAppOptions = true;
+ ScDocShell::ResetKeyBindings(eNew);
+ }
+ }
+
+ // DefaultsOptions
+ if (const ScTpDefaultsItem* pItem = rOptSet.GetItemIfSet(SID_SCDEFAULTSOPTIONS))
+ {
+ const ScDefaultsOptions& rOpt = pItem->GetDefaultsOptions();
+ SetDefaultsOptions( rOpt );
+ }
+
+ // FormulaOptions
+ if (const ScTpFormulaItem* pItem = rOptSet.GetItemIfSet(SID_SCFORMULAOPTIONS))
+ {
+ const ScFormulaOptions& rOpt = pItem->GetFormulaOptions();
+
+ if (!m_pFormulaCfg || (*m_pFormulaCfg != rOpt))
+ // Formula options have changed. Repaint the column headers.
+ bRepaint = true;
+
+ if (m_pFormulaCfg && m_pFormulaCfg->GetUseEnglishFuncName() != rOpt.GetUseEnglishFuncName())
+ {
+ // Re-compile formula cells with error as the error may have been
+ // caused by unresolved function names.
+ bCompileErrorCells = true;
+ }
+
+ // Recalc for interpreter options changes.
+ if (m_pFormulaCfg && m_pFormulaCfg->GetCalcConfig() != rOpt.GetCalcConfig())
+ bCalcAll = true;
+
+ if ( pDocSh )
+ {
+ pDocSh->SetFormulaOptions( rOpt );
+ pDocSh->SetDocumentModified();
+ }
+
+ // ScDocShell::SetFormulaOptions() may check for changed settings, so
+ // set the new options here after that has been called.
+ if (!bCalcAll || rOpt.GetWriteCalcConfig())
+ {
+ // CalcConfig is new, didn't change or is global, simply set all.
+ SetFormulaOptions( rOpt );
+ }
+ else
+ {
+ // If "only for current document" was checked, reset those affected
+ // by that setting to previous values.
+ ScFormulaOptions aNewOpt( rOpt);
+ aNewOpt.GetCalcConfig().MergeDocumentSpecific( m_pFormulaCfg->GetCalcConfig());
+ SetFormulaOptions( aNewOpt);
+ }
+ }
+
+ // ViewOptions
+ if (const ScTpViewItem* pItem = rOptSet.GetItemIfSet(SID_SCVIEWOPTIONS))
+ {
+ const ScViewOptions& rNewOpt = pItem->GetViewOptions();
+
+ if ( pViewSh )
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ const ScViewOptions& rOldOpt = rViewData.GetOptions();
+
+ bool bAnchorList = ( rOldOpt.GetOption( VOPT_ANCHOR ) !=
+ rNewOpt.GetOption( VOPT_ANCHOR ) );
+
+ if ( rOldOpt != rNewOpt )
+ {
+ rViewData.SetOptions( rNewOpt ); // Changes rOldOpt
+ rViewData.GetDocument().SetViewOptions( rNewOpt );
+ if (pDocSh)
+ pDocSh->SetDocumentModified();
+ bRepaint = true;
+ }
+ if ( bAnchorList )
+ pViewSh->UpdateAnchorHandles();
+ }
+ SetViewOptions( rNewOpt );
+ if (pBindings)
+ {
+ pBindings->Invalidate(SID_HELPLINES_MOVE);
+ }
+ }
+
+ // GridOptions
+ // Evaluate after ViewOptions, as GridOptions is a member of ViewOptions
+ if ( const SvxGridItem* pItem = rOptSet.GetItemIfSet(SID_ATTR_GRID_OPTIONS) )
+ {
+ ScGridOptions aNewGridOpt( *pItem );
+
+ if ( pViewSh )
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScViewOptions aNewViewOpt( rViewData.GetOptions() );
+ const ScGridOptions& rOldGridOpt = aNewViewOpt.GetGridOptions();
+
+ if ( rOldGridOpt != aNewGridOpt )
+ {
+ aNewViewOpt.SetGridOptions( aNewGridOpt );
+ rViewData.SetOptions( aNewViewOpt );
+ rViewData.GetDocument().SetViewOptions( aNewViewOpt );
+ if (pDocSh)
+ pDocSh->SetDocumentModified();
+ bRepaint = true;
+ }
+ }
+ ScViewOptions aNewViewOpt ( GetViewOptions() );
+ aNewViewOpt.SetGridOptions( aNewGridOpt );
+ SetViewOptions( aNewViewOpt );
+ if (pBindings)
+ {
+ pBindings->Invalidate(SID_GRID_VISIBLE);
+ pBindings->Invalidate(SID_GRID_USE);
+ }
+ }
+
+ // DocOptions
+ if ( const ScTpCalcItem* pItem = rOptSet.GetItemIfSet(SID_SCDOCOPTIONS) )
+ {
+ const ScDocOptions& rNewOpt = pItem->GetDocOptions();
+
+ if ( pDoc )
+ {
+ const ScDocOptions& rOldOpt = pDoc->GetDocOptions();
+
+ bRepaint = ( bRepaint || ( rOldOpt != rNewOpt ) );
+ bCalcAll = bRepaint &&
+ ( rOldOpt.IsIter() != rNewOpt.IsIter()
+ || rOldOpt.GetIterCount() != rNewOpt.GetIterCount()
+ || rOldOpt.GetIterEps() != rNewOpt.GetIterEps()
+ || rOldOpt.IsIgnoreCase() != rNewOpt.IsIgnoreCase()
+ || rOldOpt.IsCalcAsShown() != rNewOpt.IsCalcAsShown()
+ || (rNewOpt.IsCalcAsShown() &&
+ rOldOpt.GetStdPrecision() != rNewOpt.GetStdPrecision())
+ || rOldOpt.IsMatchWholeCell() != rNewOpt.IsMatchWholeCell()
+ || rOldOpt.GetYear2000() != rNewOpt.GetYear2000()
+ || rOldOpt.IsFormulaRegexEnabled() != rNewOpt.IsFormulaRegexEnabled()
+ || rOldOpt.IsFormulaWildcardsEnabled() != rNewOpt.IsFormulaWildcardsEnabled()
+ );
+ pDoc->SetDocOptions( rNewOpt );
+ pDocSh->SetDocumentModified();
+ }
+ SetDocOptions( rNewOpt );
+ }
+
+ // Set TabDistance after the actual DocOptions
+ if ( const SfxUInt16Item* pItem = rOptSet.GetItemIfSet(SID_ATTR_DEFTABSTOP) )
+ {
+ sal_uInt16 nTabDist = pItem->GetValue();
+ ScDocOptions aOpt(GetDocOptions());
+ aOpt.SetTabDistance(nTabDist);
+ SetDocOptions( aOpt );
+
+ if ( pDoc )
+ {
+ ScDocOptions aDocOpt(pDoc->GetDocOptions());
+ aDocOpt.SetTabDistance(nTabDist);
+ pDoc->SetDocOptions( aDocOpt );
+ pDocSh->SetDocumentModified();
+ if(pDoc->GetDrawLayer())
+ pDoc->GetDrawLayer()->SetDefaultTabulator(nTabDist);
+ }
+ }
+
+ // AutoSpell after the DocOptions (due to being a member)
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_AUTOSPELL_CHECK) ) // At DocOptions
+ {
+ bool bDoAutoSpell = pItem->GetValue();
+
+ if (pDoc)
+ {
+ ScDocOptions aNewOpt = pDoc->GetDocOptions();
+ if ( aNewOpt.IsAutoSpell() != bDoAutoSpell )
+ {
+ aNewOpt.SetAutoSpell( bDoAutoSpell );
+ pDoc->SetDocOptions( aNewOpt );
+
+ if (pViewSh)
+ pViewSh->EnableAutoSpell(bDoAutoSpell);
+
+ bRepaint = true; // Because HideAutoSpell might be invalid
+ //TODO: Paint all Views?
+ }
+ }
+
+ if ( bOldAutoSpell != bDoAutoSpell )
+ SetAutoSpellProperty( bDoAutoSpell );
+ if ( pDocSh )
+ pDocSh->PostPaintGridAll(); // Due to marks
+ ScInputHandler* pInputHandler = GetInputHdl();
+ if ( pInputHandler )
+ pInputHandler->UpdateSpellSettings(); // EditEngine flags
+ if ( pViewSh )
+ pViewSh->UpdateDrawTextOutliner(); // EditEngine flags
+
+ if (pBindings)
+ pBindings->Invalidate( SID_AUTOSPELL_CHECK );
+ }
+
+ // InputOptions
+ ScInputOptions aInputOptions = m_pInputCfg->GetOptions();
+ if ( const SfxUInt16Item* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_SELECTIONPOS) )
+ {
+ aInputOptions.SetMoveDir( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_SELECTION) )
+ {
+ aInputOptions.SetMoveSelection( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_EDITMODE) )
+ {
+ aInputOptions.SetEnterEdit( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_FMT_EXPAND) )
+ {
+ aInputOptions.SetExtendFormat( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_RANGEFINDER) )
+ {
+ aInputOptions.SetRangeFinder( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_REF_EXPAND) )
+ {
+ aInputOptions.SetExpandRefs( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+ if (const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_OPT_SORT_REF_UPDATE))
+ {
+ aInputOptions.SetSortRefUpdate( pItem->GetValue());
+ bSaveInputOptions = true;
+ }
+
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_MARK_HEADER) )
+ {
+ aInputOptions.SetMarkHeader( pItem->GetValue() );
+ bSaveInputOptions = true;
+ bUpdateMarks = true;
+ }
+ if ( const SfxBoolItem* pItem = rOptSet.GetItemIfSet(SID_SC_INPUT_TEXTWYSIWYG) )
+ {
+ bool bNew = pItem->GetValue();
+ if ( bNew != aInputOptions.GetTextWysiwyg() )
+ {
+ aInputOptions.SetTextWysiwyg( bNew );
+ bSaveInputOptions = true;
+ bUpdateRefDev = true;
+ }
+ }
+ if( const SfxBoolItem* pItem = rOptSet.GetItemIfSet( SID_SC_INPUT_REPLCELLSWARN ) )
+ {
+ aInputOptions.SetReplaceCellsWarn( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+
+ if( const SfxBoolItem* pItem = rOptSet.GetItemIfSet( SID_SC_INPUT_LEGACY_CELL_SELECTION ) )
+ {
+ aInputOptions.SetLegacyCellSelection( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+
+ if( const SfxBoolItem* pItem = rOptSet.GetItemIfSet( SID_SC_INPUT_ENTER_PASTE_MODE ) )
+ {
+ aInputOptions.SetEnterPasteMode( pItem->GetValue() );
+ bSaveInputOptions = true;
+ }
+
+ // PrintOptions
+ if ( const ScTpPrintItem* pItem = rOptSet.GetItemIfSet(SID_SCPRINTOPTIONS) )
+ {
+ const ScPrintOptions& rNewOpt = pItem->GetPrintOptions();
+ SetPrintOptions( rNewOpt );
+
+ // broadcast causes all previews to recalc page numbers
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScPrintOptions ) );
+ }
+
+ if ( bSaveAppOptions )
+ m_pAppCfg->SetOptions(aAppOptions);
+
+ if ( bSaveInputOptions )
+ m_pInputCfg->SetOptions(aInputOptions);
+
+ // Kick off recalculation?
+ if (pDoc && bCompileErrorCells)
+ {
+ // Re-compile cells with name error, and recalc if at least one cell
+ // has been re-compiled. In the future we may want to find a way to
+ // recalc only those that are affected.
+ if (pDoc->CompileErrorCells(FormulaError::NoName))
+ bCalcAll = true;
+ }
+
+ if ( pDoc && bCalcAll )
+ {
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+ pDoc->CalcAll();
+ if ( pViewSh )
+ pViewSh->UpdateCharts( true );
+ else
+ ScDBFunc::DoUpdateCharts( ScAddress(), *pDoc, true );
+ if (pBindings)
+ pBindings->Invalidate( SID_ATTR_SIZE ); //SvxPosSize StatusControl Update
+ }
+
+ if ( pViewSh && bUpdateMarks )
+ pViewSh->UpdateAutoFillMark();
+
+ // Repaint View?
+ if ( pViewSh && bRepaint )
+ {
+ pViewSh->UpdateFixPos();
+ pViewSh->PaintGrid();
+ pViewSh->PaintTop();
+ pViewSh->PaintLeft();
+ pViewSh->PaintExtras();
+ pViewSh->InvalidateBorder();
+ if (pBindings)
+ {
+ pBindings->Invalidate( FID_TOGGLEHEADERS ); // -> Checks in menu
+ pBindings->Invalidate( FID_TOGGLESYNTAX );
+ }
+ }
+
+ // update ref device (for all documents)
+ if ( !bUpdateRefDev )
+ return;
+
+ // for all documents: recalc output factor, update row heights
+ SfxObjectShell* pObjSh = SfxObjectShell::GetFirst();
+ while ( pObjSh )
+ {
+ if ( auto pOneDocSh = dynamic_cast<ScDocShell *>(pObjSh) )
+ {
+ pOneDocSh->CalcOutputFactor();
+ SCTAB nTabCount = pOneDocSh->GetDocument().GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ pOneDocSh->AdjustRowHeight( 0, pDocSh->GetDocument().MaxRow(), nTab );
+ }
+ pObjSh = SfxObjectShell::GetNext( *pObjSh );
+ }
+
+ // for all (tab-) views:
+ SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
+ while ( pSh )
+ {
+ ScTabViewShell* pOneViewSh = static_cast<ScTabViewShell*>(pSh);
+
+ // set ref-device for EditEngine
+ ScInputHandler* pHdl = GetInputHdl(pOneViewSh);
+ if (pHdl)
+ pHdl->UpdateRefDevice();
+
+ // update view scale
+ ScViewData& rViewData = pOneViewSh->GetViewData();
+ pOneViewSh->SetZoom( rViewData.GetZoomX(), rViewData.GetZoomY(), false );
+
+ // repaint
+ pOneViewSh->PaintGrid();
+ pOneViewSh->PaintTop();
+ pOneViewSh->PaintLeft();
+
+ pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
+ }
+}
+
+/**
+ * Input-Handler
+ */
+ScInputHandler* ScModule::GetInputHdl( ScTabViewShell* pViewSh, bool bUseRef )
+{
+ if ( !comphelper::LibreOfficeKit::isActive() && m_pRefInputHandler && bUseRef )
+ return m_pRefInputHandler;
+
+ ScInputHandler* pHdl = nullptr;
+ if ( !pViewSh )
+ {
+ // in case a UIActive embedded object has no ViewShell (UNO component)
+ // the own calc view shell will be set as current, but no handling should happen
+ ScTabViewShell* pCurViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( pCurViewSh && !pCurViewSh->GetUIActiveClient() )
+ pViewSh = pCurViewSh;
+ }
+
+ if ( pViewSh )
+ pHdl = pViewSh->GetInputHandler(); // Viewshell always has one, from now on
+
+ // If no ViewShell passed or active, we can get NULL
+ OSL_ENSURE( pHdl || !pViewSh, "GetInputHdl: no InputHandler found!" );
+ return pHdl;
+}
+
+void ScModule::ViewShellChanged(bool bStopEditing /*=true*/)
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ ScTabViewShell* pShell = ScTabViewShell::GetActiveViewShell();
+ if ( pShell && pHdl )
+ pShell->UpdateInputHandler(false, bStopEditing);
+}
+
+void ScModule::SetInputMode( ScInputMode eMode, const OUString* pInitText )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->SetMode(eMode, pInitText);
+}
+
+bool ScModule::IsEditMode()
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ return pHdl && pHdl->IsEditMode();
+}
+
+bool ScModule::IsInputMode()
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ return pHdl && pHdl->IsInputMode();
+}
+
+bool ScModule::InputKeyEvent( const KeyEvent& rKEvt, bool bStartEdit )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ return pHdl && pHdl->KeyInput( rKEvt, bStartEdit );
+}
+
+void ScModule::InputEnterHandler( ScEnterMode nBlockMode, bool bBeforeSavingInLOK )
+{
+ if ( !SfxGetpApp()->IsDowning() ) // Not when quitting the program
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->EnterHandler( nBlockMode, bBeforeSavingInLOK );
+ }
+}
+
+void ScModule::InputCancelHandler()
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->CancelHandler();
+}
+
+void ScModule::InputSelection( const EditView* pView )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputSelection( pView );
+}
+
+void ScModule::InputChanged( const EditView* pView )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputChanged( pView, false );
+}
+
+void ScModule::ViewShellGone( const ScTabViewShell* pViewSh )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->ViewShellGone( pViewSh );
+}
+
+void ScModule::SetRefInputHdl( ScInputHandler* pNew )
+{
+ m_pRefInputHandler = pNew;
+}
+
+void ScModule::InputGetSelection( sal_Int32& rStart, sal_Int32& rEnd )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputGetSelection( rStart, rEnd );
+}
+
+void ScModule::InputSetSelection( sal_Int32 nStart, sal_Int32 nEnd )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputSetSelection( nStart, nEnd );
+}
+
+void ScModule::InputReplaceSelection( const OUString& rStr )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputReplaceSelection( rStr );
+}
+
+void ScModule::InputTurnOffWinEngine()
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->InputTurnOffWinEngine();
+}
+
+void ScModule::ActivateInputWindow( const OUString* pStrFormula, bool bMatrix )
+{
+ ScInputHandler* pHdl = GetInputHdl();
+ if ( !pHdl )
+ return;
+
+ ScInputWindow* pWin = pHdl->GetInputWindow();
+ if ( pStrFormula )
+ {
+ // Take over formula
+ if ( pWin )
+ {
+ pWin->SetFuncString( *pStrFormula, false );
+ // SetSumAssignMode due to sal_False not necessary
+ }
+ ScEnterMode nMode = bMatrix ? ScEnterMode::MATRIX : ScEnterMode::NORMAL;
+ pHdl->EnterHandler( nMode );
+
+ // Without Invalidate the selection remains active, if the formula has not changed
+ if (pWin)
+ pWin->TextInvalidate();
+ }
+ else
+ {
+ // Cancel
+ if ( pWin )
+ {
+ pWin->SetFuncString( OUString(), false );
+ // SetSumAssignMode due to sal_False no necessary
+ }
+ pHdl->CancelHandler();
+ }
+}
+
+/**
+ * Reference dialogs
+ */
+void ScModule::SetRefDialog( sal_uInt16 nId, bool bVis, SfxViewFrame* pViewFrm )
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ if ( !(m_nCurRefDlgId == 0 || ( nId == m_nCurRefDlgId && !bVis )
+ || ( comphelper::LibreOfficeKit::isActive() )) )
+ return;
+
+ if ( !pViewFrm )
+ pViewFrm = SfxViewFrame::Current();
+
+ // bindings update causes problems with update of stylist if
+ // current style family has changed
+ //if ( pViewFrm )
+ // pViewFrm->GetBindings().Update(); // to avoid trouble in LockDispatcher
+
+ // before SetChildWindow
+ if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ if ( bVis )
+ m_nCurRefDlgId = nId;
+ }
+ else
+ {
+ m_nCurRefDlgId = bVis ? nId : 0;
+ }
+
+ if ( pViewFrm )
+ {
+ // store the dialog id also in the view shell
+ SfxViewShell* pViewSh = pViewFrm->GetViewShell();
+ if (ScTabViewShell* pTabViewSh = dynamic_cast<ScTabViewShell*>(pViewSh))
+ pTabViewSh->SetCurRefDlgId(m_nCurRefDlgId);
+ else
+ {
+ // no ScTabViewShell - possible for example from a Basic macro
+ bVis = false;
+ m_nCurRefDlgId = 0; // don't set nCurRefDlgId if no dialog is created
+ }
+
+ pViewFrm->SetChildWindow( nId, bVis );
+ }
+
+ SfxApplication* pSfxApp = SfxGetpApp();
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScRefModeChanged ) );
+}
+
+static SfxChildWindow* lcl_GetChildWinFromCurrentView( sal_uInt16 nId )
+{
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+
+ // #i46999# current view frame can be null (for example, when closing help)
+ return pViewFrm ? pViewFrm->GetChildWindow( nId ) : nullptr;
+}
+
+static SfxChildWindow* lcl_GetChildWinFromAnyView( sal_uInt16 nId )
+{
+ // First, try the current view
+ SfxChildWindow* pChildWnd = lcl_GetChildWinFromCurrentView( nId );
+ if ( pChildWnd )
+ return pChildWnd; // found in the current view
+
+ // if not found there, get the child window from any open view
+ // it can be open only in one view because nCurRefDlgId is global
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::GetFirst();
+ while ( pViewFrm )
+ {
+ pChildWnd = pViewFrm->GetChildWindow( nId );
+ if ( pChildWnd )
+ return pChildWnd; // found in any view
+
+ pViewFrm = SfxViewFrame::GetNext( *pViewFrm );
+ }
+
+ return nullptr; // none found
+}
+
+bool ScModule::IsModalMode(SfxObjectShell* pDocSh)
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ bool bIsModal = false;
+
+ if ( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = lcl_GetChildWinFromCurrentView( m_nCurRefDlgId );
+ if ( pChildWnd )
+ {
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ bIsModal = pChildWnd->IsVisible() && pRefDlg &&
+ !( pRefDlg->IsRefInputMode() && pRefDlg->IsDocAllowed(pDocSh) );
+ }
+ }
+ else if ( pDocSh && comphelper::LibreOfficeKit::isActive() )
+ {
+ // m_nCurRefDlgId is not deglobalized so it can be set by other view
+ // in LOK case when no ChildWindow for this view was detected -> fallback
+ ScInputHandler* pHdl = GetInputHdl();
+ if ( pHdl )
+ bIsModal = pHdl->IsModalMode(pDocSh);
+ }
+ }
+ else if (pDocSh)
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if ( pHdl )
+ bIsModal = pHdl->IsModalMode(pDocSh);
+ }
+
+ return bIsModal;
+}
+
+bool ScModule::IsTableLocked()
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ bool bLocked = false;
+
+ // Up until now just for ScAnyRefDlg
+ if ( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = lcl_GetChildWinFromAnyView( m_nCurRefDlgId );
+ if ( pChildWnd )
+ {
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ if (pRefDlg)
+ bLocked = pRefDlg->IsTableLocked();
+ }
+ }
+ else if (!comphelper::LibreOfficeKit::isActive())
+ bLocked = true; // for other views, see IsModalMode
+ }
+
+ // We can't stop LOK clients from switching part, and getting out of sync.
+ assert(!bLocked || !comphelper::LibreOfficeKit::isActive());
+
+ return bLocked;
+}
+
+bool ScModule::IsRefDialogOpen()
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ bool bIsOpen = false;
+
+ if ( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = lcl_GetChildWinFromCurrentView( m_nCurRefDlgId );
+ if ( pChildWnd )
+ bIsOpen = pChildWnd->IsVisible();
+ }
+
+ return bIsOpen;
+}
+
+bool ScModule::IsFormulaMode()
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ bool bIsFormula = false;
+
+ if ( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = nullptr;
+
+ if ( comphelper::LibreOfficeKit::isActive() )
+ pChildWnd = lcl_GetChildWinFromCurrentView( m_nCurRefDlgId );
+ else
+ pChildWnd = lcl_GetChildWinFromAnyView( m_nCurRefDlgId );
+
+ if ( pChildWnd )
+ {
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ bIsFormula = pChildWnd->IsVisible() && pRefDlg && pRefDlg->IsRefInputMode();
+ }
+ }
+ else if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ // m_nCurRefDlgId is not deglobalized so it can be set by other view
+ // in LOK case when no ChildWindow for this view was detected -> fallback
+ ScInputHandler* pHdl = GetInputHdl();
+ if ( pHdl )
+ bIsFormula = pHdl->IsFormulaMode();
+ }
+ }
+ else
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if ( pHdl )
+ bIsFormula = pHdl->IsFormulaMode();
+ }
+
+ if (m_bIsInEditCommand)
+ bIsFormula = true;
+
+ return bIsFormula;
+}
+
+static void lcl_MarkedTabs( const ScMarkData& rMark, SCTAB& rStartTab, SCTAB& rEndTab )
+{
+ if (rMark.GetSelectCount() > 1)
+ {
+ rEndTab = rMark.GetLastSelected();
+ rStartTab = rMark.GetFirstSelected();
+ }
+}
+
+void ScModule::SetReference( const ScRange& rRef, ScDocument& rDoc,
+ const ScMarkData* pMarkData )
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+
+ // In RefDialogs we also trigger the ZoomIn, if the Ref's Start and End are different
+ ScRange aNew = rRef;
+ aNew.PutInOrder(); // Always in the right direction
+
+ if( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = nullptr;
+
+ if ( comphelper::LibreOfficeKit::isActive() )
+ pChildWnd = lcl_GetChildWinFromCurrentView( m_nCurRefDlgId );
+ else
+ pChildWnd = lcl_GetChildWinFromAnyView( m_nCurRefDlgId );
+
+ OSL_ENSURE( pChildWnd, "NoChildWin" );
+ if ( pChildWnd )
+ {
+ if ( m_nCurRefDlgId == SID_OPENDLG_CONSOLIDATE && pMarkData )
+ {
+ SCTAB nStartTab = aNew.aStart.Tab();
+ SCTAB nEndTab = aNew.aEnd.Tab();
+ lcl_MarkedTabs( *pMarkData, nStartTab, nEndTab );
+ aNew.aStart.SetTab(nStartTab);
+ aNew.aEnd.SetTab(nEndTab);
+ }
+
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ if(pRefDlg)
+ {
+ // hide the (color) selection now instead of later from LoseFocus,
+ // don't abort the ref input that causes this call (bDoneRefMode = sal_False)
+ pRefDlg->HideReference( false );
+ pRefDlg->SetReference( aNew, rDoc );
+ }
+ }
+ }
+ else if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ // m_nCurRefDlgId is not deglobalized so it can be set by other view
+ // in LOK case when no ChildWindow for this view was detected -> fallback
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->SetReference( aNew, rDoc );
+ }
+ }
+ else
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->SetReference( aNew, rDoc );
+ else
+ {
+ OSL_FAIL("SetReference without receiver");
+ }
+ }
+}
+
+/**
+ * Multiple selection
+ */
+void ScModule::AddRefEntry()
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+ if ( m_nCurRefDlgId )
+ {
+ SfxChildWindow* pChildWnd = lcl_GetChildWinFromAnyView( m_nCurRefDlgId );
+ OSL_ENSURE( pChildWnd, "NoChildWin" );
+ if ( pChildWnd )
+ {
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ if (pRefDlg)
+ {
+ pRefDlg->AddRefEntry();
+ }
+ }
+ }
+ }
+ else
+ {
+ ScInputHandler* pHdl = GetInputHdl();
+ if (pHdl)
+ pHdl->AddRefEntry();
+ }
+}
+
+void ScModule::EndReference()
+{
+ //TODO: Move reference dialog handling to view
+ // Just keep function autopilot here for references to other documents
+
+ // We also annul the ZoomIn again in RefDialogs
+
+ //FIXME: ShowRefFrame at InputHdl, if the Function AutoPilot is open?
+ if ( !m_nCurRefDlgId )
+ return;
+
+ SfxChildWindow* pChildWnd = nullptr;
+
+ if ( comphelper::LibreOfficeKit::isActive() )
+ pChildWnd = lcl_GetChildWinFromCurrentView( m_nCurRefDlgId );
+ else
+ pChildWnd = lcl_GetChildWinFromAnyView( m_nCurRefDlgId );
+
+ OSL_ENSURE( pChildWnd, "NoChildWin" );
+ if ( pChildWnd )
+ {
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ assert(pRefDlg);
+ if(pRefDlg)
+ {
+ pRefDlg->SetActive();
+ }
+ }
+ }
+}
+
+/**
+ * Idle/OnlineSpelling
+ */
+void ScModule::AnythingChanged()
+{
+ sal_uInt64 nOldTime = m_aIdleTimer.GetTimeout();
+ if ( nOldTime != SC_IDLE_MIN )
+ m_aIdleTimer.SetTimeout( SC_IDLE_MIN );
+
+ nIdleCount = 0;
+}
+
+static void lcl_CheckNeedsRepaint( const ScDocShell* pDocShell )
+{
+ SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell );
+ while ( pFrame )
+ {
+ SfxViewShell* p = pFrame->GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p );
+ if ( pViewSh )
+ pViewSh->CheckNeedsRepaint();
+ pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell );
+ }
+}
+
+IMPL_LINK_NOARG(ScModule, IdleHandler, Timer *, void)
+{
+ if ( Application::AnyInput( VclInputFlags::MOUSE | VclInputFlags::KEYBOARD ) )
+ {
+ m_aIdleTimer.Start(); // Timeout unchanged
+ return;
+ }
+
+ bool bMore = false;
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>(SfxObjectShell::Current());
+
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ sc::DocumentLinkManager& rLinkMgr = rDoc.GetDocLinkManager();
+ bool bLinks = rLinkMgr.idleCheckLinks();
+ bool bWidth = rDoc.IdleCalcTextWidth();
+
+ bMore = bLinks || bWidth; // Still something at all?
+
+ // While calculating a Basic formula, a paint event may have occurred,
+ // so check the bNeedsRepaint flags for this document's views
+ if (bWidth)
+ lcl_CheckNeedsRepaint( pDocSh );
+ }
+
+
+ sal_uInt64 nOldTime = m_aIdleTimer.GetTimeout();
+ sal_uInt64 nNewTime = nOldTime;
+ if ( bMore )
+ {
+ nNewTime = SC_IDLE_MIN;
+ nIdleCount = 0;
+ }
+ else
+ {
+ // Set SC_IDLE_COUNT to initial Timeout - increase afterwards
+ if ( nIdleCount < SC_IDLE_COUNT )
+ ++nIdleCount;
+ else
+ {
+ nNewTime += SC_IDLE_STEP;
+ if ( nNewTime > SC_IDLE_MAX )
+ nNewTime = SC_IDLE_MAX;
+ }
+ }
+ if ( nNewTime != nOldTime )
+ m_aIdleTimer.SetTimeout( nNewTime );
+
+
+ m_aIdleTimer.Start();
+}
+
+/**
+ * Virtual methods for the OptionsDialog
+ */
+std::optional<SfxItemSet> ScModule::CreateItemSet( sal_uInt16 nId )
+{
+ std::optional<SfxItemSet> pRet;
+ if(SID_SC_EDITOPTIONS == nId)
+ {
+ pRet.emplace(
+ GetPool(),
+ svl::Items<
+ // TP_USERLISTS:
+ SCITEM_USERLIST, SCITEM_USERLIST,
+ // TP_GRID:
+ SID_ATTR_GRID_OPTIONS, SID_ATTR_GRID_OPTIONS,
+ SID_ATTR_METRIC, SID_ATTR_METRIC,
+ SID_ATTR_DEFTABSTOP, SID_ATTR_DEFTABSTOP,
+ // TP_INPUT:
+ SID_SC_INPUT_LEGACY_CELL_SELECTION, SID_SC_OPT_SORT_REF_UPDATE,
+ // TP_FORMULA, TP_DEFAULTS:
+ SID_SCFORMULAOPTIONS, SID_SCDEFAULTSOPTIONS,
+ // TP_VIEW, TP_CALC:
+ SID_SCVIEWOPTIONS, SID_SCDOCOPTIONS,
+ // TP_INPUT:
+ SID_SC_INPUT_ENTER_PASTE_MODE, SID_SC_INPUT_ENTER_PASTE_MODE,
+ // TP_PRINT:
+ SID_SCPRINTOPTIONS, SID_SCPRINTOPTIONS,
+ // TP_INPUT:
+ SID_SC_INPUT_SELECTION, SID_SC_INPUT_MARK_HEADER,
+ SID_SC_INPUT_TEXTWYSIWYG, SID_SC_INPUT_TEXTWYSIWYG,
+ SID_SC_INPUT_REPLCELLSWARN, SID_SC_INPUT_REPLCELLSWARN,
+ // TP_VIEW:
+ SID_SC_OPT_SYNCZOOM, SID_SC_OPT_KEY_BINDING_COMPAT>);
+
+ const ScAppOptions& rAppOpt = GetAppOptions();
+
+ ScDocShell* pDocSh = dynamic_cast< ScDocShell *>( SfxObjectShell::Current() );
+ ScDocOptions aCalcOpt = pDocSh
+ ? pDocSh->GetDocument().GetDocOptions()
+ : GetDocOptions();
+
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( SfxViewShell::Current() );
+ ScViewOptions aViewOpt = pViewSh
+ ? pViewSh->GetViewData().GetOptions()
+ : GetViewOptions();
+
+ ScUserListItem aULItem( SCITEM_USERLIST );
+ ScUserList* pUL = ScGlobal::GetUserList();
+
+ // SfxGetpApp()->GetOptions( aSet );
+
+ pRet->Put( SfxUInt16Item( SID_ATTR_METRIC,
+ sal::static_int_cast<sal_uInt16>(rAppOpt.GetAppMetric()) ) );
+
+ // TP_CALC
+ pRet->Put( SfxUInt16Item( SID_ATTR_DEFTABSTOP,
+ aCalcOpt.GetTabDistance()));
+ pRet->Put( ScTpCalcItem( SID_SCDOCOPTIONS, aCalcOpt ) );
+
+ // TP_VIEW
+ pRet->Put( ScTpViewItem( aViewOpt ) );
+ pRet->Put( SfxBoolItem( SID_SC_OPT_SYNCZOOM, rAppOpt.GetSynchronizeZoom() ) );
+
+ // TP_INPUT
+ const ScInputOptions& rInpOpt = GetInputOptions();
+ pRet->Put( SfxUInt16Item( SID_SC_INPUT_SELECTIONPOS,
+ rInpOpt.GetMoveDir() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_SELECTION,
+ rInpOpt.GetMoveSelection() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_EDITMODE,
+ rInpOpt.GetEnterEdit() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_FMT_EXPAND,
+ rInpOpt.GetExtendFormat() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_RANGEFINDER,
+ rInpOpt.GetRangeFinder() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_REF_EXPAND,
+ rInpOpt.GetExpandRefs() ) );
+ pRet->Put( SfxBoolItem(SID_SC_OPT_SORT_REF_UPDATE, rInpOpt.GetSortRefUpdate()));
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_MARK_HEADER,
+ rInpOpt.GetMarkHeader() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_TEXTWYSIWYG,
+ rInpOpt.GetTextWysiwyg() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_REPLCELLSWARN,
+ rInpOpt.GetReplaceCellsWarn() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_LEGACY_CELL_SELECTION,
+ rInpOpt.GetLegacyCellSelection() ) );
+ pRet->Put( SfxBoolItem( SID_SC_INPUT_ENTER_PASTE_MODE,
+ rInpOpt.GetEnterPasteMode() ) );
+
+ // RID_SC_TP_PRINT
+ pRet->Put( ScTpPrintItem( GetPrintOptions() ) );
+
+ // TP_GRID
+ pRet->Put( aViewOpt.CreateGridItem() );
+
+ // TP_USERLISTS
+ if ( pUL )
+ {
+ aULItem.SetUserList( *pUL );
+ pRet->Put(aULItem);
+ }
+
+ // TP_COMPATIBILITY
+ pRet->Put( SfxUInt16Item( SID_SC_OPT_KEY_BINDING_COMPAT,
+ rAppOpt.GetKeyBindingType() ) );
+
+ // TP_DEFAULTS
+ pRet->Put( ScTpDefaultsItem( GetDefaultsOptions() ) );
+
+ // TP_FORMULA
+ ScFormulaOptions aOptions = GetFormulaOptions();
+ if (pDocSh)
+ {
+ ScCalcConfig aConfig( aOptions.GetCalcConfig());
+ aConfig.MergeDocumentSpecific( pDocSh->GetDocument().GetCalcConfig());
+ aOptions.SetCalcConfig( aConfig);
+ }
+ pRet->Put( ScTpFormulaItem( aOptions ) );
+ }
+ return pRet;
+}
+
+void ScModule::ApplyItemSet( sal_uInt16 nId, const SfxItemSet& rSet )
+{
+ if(SID_SC_EDITOPTIONS == nId)
+ {
+ ModifyOptions( rSet );
+ }
+}
+
+std::unique_ptr<SfxTabPage> ScModule::CreateTabPage( sal_uInt16 nId, weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet )
+{
+ std::unique_ptr<SfxTabPage> xRet;
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ switch(nId)
+ {
+ case SID_SC_TP_LAYOUT:
+ {
+ ::CreateTabPage ScTpLayoutOptionsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_LAYOUT);
+ if (ScTpLayoutOptionsCreate)
+ xRet = (*ScTpLayoutOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_CONTENT:
+ {
+ ::CreateTabPage ScTpContentOptionsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_CONTENT);
+ if (ScTpContentOptionsCreate)
+ xRet = (*ScTpContentOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_GRID:
+ xRet = SvxGridTabPage::Create(pPage, pController, rSet);
+ break;
+ case SID_SC_TP_USERLISTS:
+ {
+ ::CreateTabPage ScTpUserListsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_USERLISTS);
+ if (ScTpUserListsCreate)
+ xRet = (*ScTpUserListsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_CALC:
+ {
+ ::CreateTabPage ScTpCalcOptionsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_CALC);
+ if (ScTpCalcOptionsCreate)
+ xRet = (*ScTpCalcOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_FORMULA:
+ {
+ ::CreateTabPage ScTpFormulaOptionsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_FORMULA);
+ if (ScTpFormulaOptionsCreate)
+ xRet = (*ScTpFormulaOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_COMPATIBILITY:
+ {
+ ::CreateTabPage ScTpCompatOptionsCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_COMPATIBILITY);
+ if (ScTpCompatOptionsCreate)
+ xRet = (*ScTpCompatOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case SID_SC_TP_CHANGES:
+ {
+ ::CreateTabPage ScRedlineOptionsTabPageCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_CHANGES);
+ if (ScRedlineOptionsTabPageCreate)
+ xRet =(*ScRedlineOptionsTabPageCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case RID_SC_TP_PRINT:
+ {
+ ::CreateTabPage ScTpPrintOptionsCreate = pFact->GetTabPageCreatorFunc(RID_SC_TP_PRINT);
+ if (ScTpPrintOptionsCreate)
+ xRet = (*ScTpPrintOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ case RID_SC_TP_DEFAULTS:
+ {
+ ::CreateTabPage ScTpDefaultsOptionsCreate = pFact->GetTabPageCreatorFunc(RID_SC_TP_DEFAULTS);
+ if (ScTpDefaultsOptionsCreate)
+ xRet = (*ScTpDefaultsOptionsCreate)(pPage, pController, &rSet);
+ break;
+ }
+ }
+
+ OSL_ENSURE( xRet, "ScModule::CreateTabPage(): no valid ID for TabPage!" );
+
+ return xRet;
+}
+
+IMPL_LINK( ScModule, CalcFieldValueHdl, EditFieldInfo*, pInfo, void )
+{
+ //TODO: Merge with ScFieldEditEngine!
+ if (!pInfo)
+ return;
+
+ const SvxFieldItem& rField = pInfo->GetField();
+ const SvxFieldData* pField = rField.GetField();
+
+ if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
+ {
+ // URLField
+ const OUString& aURL = pURLField->GetURL();
+
+ switch ( pURLField->GetFormat() )
+ {
+ case SvxURLFormat::AppDefault: //TODO: Settable in the App?
+ case SvxURLFormat::Repr:
+ {
+ pInfo->SetRepresentation( pURLField->GetRepresentation() );
+ }
+ break;
+
+ case SvxURLFormat::Url:
+ {
+ pInfo->SetRepresentation( aURL );
+ }
+ break;
+ }
+
+ svtools::ColorConfigEntry eEntry =
+ INetURLHistory::GetOrCreate()->QueryUrl( aURL ) ? svtools::LINKSVISITED : svtools::LINKS;
+ pInfo->SetTextColor( GetColorConfig().GetColorValue(eEntry).nColor );
+ }
+ else
+ {
+ OSL_FAIL("Unknown Field");
+ pInfo->SetRepresentation(OUString('?'));
+ }
+}
+
+void ScModule::RegisterRefController(sal_uInt16 nSlotId, std::shared_ptr<SfxDialogController>& rWnd, weld::Window* pWndAncestor)
+{
+ std::vector<std::pair<std::shared_ptr<SfxDialogController>, weld::Window*>> & rlRefWindow = m_mapRefController[nSlotId];
+
+ if (std::find_if(rlRefWindow.begin(), rlRefWindow.end(),
+ [rWnd](const std::pair<std::shared_ptr<SfxDialogController>, weld::Window*>& rCandidate)
+ {
+ return rCandidate.first.get() == rWnd.get();
+ }) == rlRefWindow.end())
+ {
+ rlRefWindow.emplace_back(rWnd, pWndAncestor);
+ }
+}
+
+void ScModule::UnregisterRefController(sal_uInt16 nSlotId, const std::shared_ptr<SfxDialogController>& rWnd)
+{
+ auto iSlot = m_mapRefController.find( nSlotId );
+
+ if( iSlot == m_mapRefController.end() )
+ return;
+
+ std::vector<std::pair<std::shared_ptr<SfxDialogController>, weld::Window*>> & rlRefWindow = iSlot->second;
+
+ auto i = std::find_if(rlRefWindow.begin(), rlRefWindow.end(),
+ [rWnd](const std::pair<std::shared_ptr<SfxDialogController>, weld::Window*>& rCandidate)
+ {
+ return rCandidate.first.get() == rWnd.get();
+ });
+
+ if( i == rlRefWindow.end() )
+ return;
+
+ rlRefWindow.erase( i );
+
+ if( rlRefWindow.empty() )
+ m_mapRefController.erase( nSlotId );
+}
+
+std::shared_ptr<SfxDialogController> ScModule::Find1RefWindow(sal_uInt16 nSlotId, const weld::Window *pWndAncestor)
+{
+ if (!pWndAncestor)
+ return nullptr;
+
+ auto iSlot = m_mapRefController.find( nSlotId );
+
+ if( iSlot == m_mapRefController.end() )
+ return nullptr;
+
+ std::vector<std::pair<std::shared_ptr<SfxDialogController>, weld::Window*>> & rlRefWindow = iSlot->second;
+
+ for (auto const& refWindow : rlRefWindow)
+ if ( refWindow.second == pWndAncestor )
+ return refWindow.first;
+
+ return nullptr;
+}
+
+using namespace com::sun::star;
+
+constexpr OUStringLiteral LINGUPROP_AUTOSPELL = u"IsSpellAuto";
+
+void ScModule::GetSpellSettings( LanguageType& rDefLang, LanguageType& rCjkLang, LanguageType& rCtlLang,
+ bool& rAutoSpell )
+{
+ // use SvtLinguConfig instead of service LinguProperties to avoid
+ // loading the linguistic component
+ SvtLinguConfig aConfig;
+
+ SvtLinguOptions aOptions;
+ aConfig.GetOptions( aOptions );
+
+ rDefLang = MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage, css::i18n::ScriptType::LATIN);
+ rCjkLang = MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage_CJK, css::i18n::ScriptType::ASIAN);
+ rCtlLang = MsLangId::resolveSystemLanguageByScriptType(aOptions.nDefaultLanguage_CTL, css::i18n::ScriptType::COMPLEX);
+ rAutoSpell = aOptions.bIsSpellAuto;
+}
+
+void ScModule::SetAutoSpellProperty( bool bSet )
+{
+ // use SvtLinguConfig instead of service LinguProperties to avoid
+ // loading the linguistic component
+ SvtLinguConfig aConfig;
+
+ aConfig.SetProperty( LINGUPROP_AUTOSPELL, uno::Any(bSet) );
+}
+
+bool ScModule::HasThesaurusLanguage( LanguageType nLang )
+{
+ if ( nLang == LANGUAGE_NONE )
+ return false;
+
+ bool bHasLang = false;
+ try
+ {
+ uno::Reference< linguistic2::XThesaurus > xThes(LinguMgr::GetThesaurus());
+ if ( xThes.is() )
+ bHasLang = xThes->hasLocale( LanguageTag::convertToLocale( nLang ) );
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL("Error in Thesaurus");
+ }
+
+ return bHasLang;
+}
+
+std::optional<SfxStyleFamilies> ScModule::CreateStyleFamilies()
+{
+ SfxStyleFamilies aStyleFamilies;
+
+ aStyleFamilies.emplace_back(SfxStyleFamilyItem(SfxStyleFamily::Para,
+ ScResId(STR_STYLE_FAMILY_CELL),
+ BMP_STYLES_FAMILY_CELL,
+ RID_CELLSTYLEFAMILY, SC_MOD()->GetResLocale()));
+
+ aStyleFamilies.emplace_back(SfxStyleFamilyItem(SfxStyleFamily::Page,
+ ScResId(STR_STYLE_FAMILY_PAGE),
+ BMP_STYLES_FAMILY_PAGE,
+ RID_PAGESTYLEFAMILY, SC_MOD()->GetResLocale()));
+
+ return aStyleFamilies;
+}
+
+void ScModule::RegisterAutomationApplicationEventsCaller(css::uno::Reference< ooo::vba::XSinkCaller > const& xCaller)
+{
+ mxAutomationApplicationEventsCaller = xCaller;
+}
+
+void ScModule::CallAutomationApplicationEventSinks(const OUString& Method, css::uno::Sequence< css::uno::Any >& Arguments)
+{
+ if (mxAutomationApplicationEventsCaller.is())
+ mxAutomationApplicationEventsCaller->CallSinks(Method, Arguments);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/seltrans.cxx b/sc/source/ui/app/seltrans.cxx
new file mode 100644
index 000000000..6ba63e4dc
--- /dev/null
+++ b/sc/source/ui/app/seltrans.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 <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/form/FormButtonType.hpp>
+
+#include <tools/urlobj.hxx>
+#include <sfx2/docfile.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdouno.hxx>
+#include <osl/diagnose.h>
+
+#include <seltrans.hxx>
+#include <transobj.hxx>
+#include <drwtrans.hxx>
+#include <scmod.hxx>
+#include <dbfunc.hxx>
+#include <docsh.hxx>
+#include <drawview.hxx>
+#include <drwlayer.hxx>
+#include <markdata.hxx>
+
+using namespace com::sun::star;
+
+static bool lcl_IsURLButton( SdrObject* pObject )
+{
+ bool bRet = false;
+
+ SdrUnoObj* pUnoCtrl = dynamic_cast<SdrUnoObj*>( pObject );
+ if (pUnoCtrl && SdrInventor::FmForm == pUnoCtrl->GetObjInventor())
+ {
+ const uno::Reference<awt::XControlModel>& xControlModel = pUnoCtrl->GetUnoControlModel();
+ OSL_ENSURE( xControlModel.is(), "uno control without model" );
+ if ( xControlModel.is() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySetInfo > xInfo = xPropSet->getPropertySetInfo();
+
+ OUString sPropButtonType( "ButtonType" );
+ if(xInfo->hasPropertyByName( sPropButtonType ))
+ {
+ uno::Any aAny = xPropSet->getPropertyValue( sPropButtonType );
+ form::FormButtonType eTmp;
+ if ( (aAny >>= eTmp) && eTmp == form::FormButtonType_URL )
+ bRet = true;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+rtl::Reference<ScSelectionTransferObj> ScSelectionTransferObj::CreateFromView( ScTabView* pView )
+{
+ rtl::Reference<ScSelectionTransferObj> pRet;
+
+ try
+ {
+ if ( pView )
+ {
+ ScSelectionTransferMode eMode = SC_SELTRANS_INVALID;
+
+ SdrView* pSdrView = pView->GetScDrawView();
+ if ( pSdrView )
+ {
+ // handle selection on drawing layer
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+ if ( nMarkCount )
+ {
+ if ( nMarkCount == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
+
+ if ( nSdrObjKind == SdrObjKind::Graphic )
+ {
+ if ( static_cast<SdrGrafObj*>(pObj)->GetGraphic().GetType() == GraphicType::Bitmap )
+ eMode = SC_SELTRANS_DRAW_BITMAP;
+ else
+ eMode = SC_SELTRANS_DRAW_GRAPHIC;
+ }
+ else if ( nSdrObjKind == SdrObjKind::OLE2 )
+ eMode = SC_SELTRANS_DRAW_OLE;
+ else if ( lcl_IsURLButton( pObj ) )
+ eMode = SC_SELTRANS_DRAW_BOOKMARK;
+ }
+
+ if ( eMode == SC_SELTRANS_INVALID )
+ eMode = SC_SELTRANS_DRAW_OTHER; // something selected but no special selection
+ }
+ }
+ if ( eMode == SC_SELTRANS_INVALID ) // no drawing object selected
+ {
+ ScViewData& rViewData = pView->GetViewData();
+ const ScMarkData& rMark = rViewData.GetMarkData();
+ // allow MultiMarked because GetSimpleArea may be able to merge into a simple range
+ // (GetSimpleArea modifies a local copy of MarkData)
+ // Also allow simple filtered area.
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ {
+ ScRange aRange;
+ ScMarkType eMarkType = rViewData.GetSimpleArea( aRange );
+ if (eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED)
+ {
+ // only for "real" selection, cursor alone isn't used
+ if ( aRange.aStart == aRange.aEnd )
+ eMode = SC_SELTRANS_CELL;
+ else
+ eMode = SC_SELTRANS_CELLS;
+ }
+ }
+ }
+
+ if ( eMode != SC_SELTRANS_INVALID )
+ pRet = new ScSelectionTransferObj( pView, eMode );
+ }
+ }
+ catch (...)
+ {
+ }
+
+ return pRet;
+}
+
+ScSelectionTransferObj::ScSelectionTransferObj( ScTabView* pSource, ScSelectionTransferMode eNewMode ) :
+ pView( pSource ),
+ eMode( eNewMode )
+{
+ //! store range for StillValid
+}
+
+ScSelectionTransferObj::~ScSelectionTransferObj()
+{
+ ScModule* pScMod = SC_MOD();
+ if (pScMod && pScMod->GetSelectionTransfer() == this)
+ {
+ // this is reached when the object wasn't really copied to the selection
+ // (CopyToSelection has no effect under Windows)
+
+ ForgetView();
+ pScMod->SetSelectionTransfer( nullptr );
+ }
+
+ OSL_ENSURE( !pView, "ScSelectionTransferObj dtor: ForgetView not called" );
+}
+
+void ScSelectionTransferObj::ForgetView()
+{
+ pView = nullptr;
+ eMode = SC_SELTRANS_INVALID;
+
+ mxCellData.clear();
+ mxDrawData.clear();
+}
+
+void ScSelectionTransferObj::AddSupportedFormats()
+{
+ // AddSupportedFormats must work without actually creating the
+ // "real" transfer object
+
+ switch (eMode)
+ {
+ case SC_SELTRANS_CELL:
+ case SC_SELTRANS_CELLS:
+ // same formats as in ScTransferObj::AddSupportedFormats
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::HTML );
+ AddFormat( SotClipboardFormatId::SYLK );
+ AddFormat( SotClipboardFormatId::LINK );
+ AddFormat( SotClipboardFormatId::DIF );
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::STRING_TSVC );
+ AddFormat( SotClipboardFormatId::RTF );
+ AddFormat( SotClipboardFormatId::RICHTEXT );
+ if ( eMode == SC_SELTRANS_CELL )
+ {
+ AddFormat( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT );
+ }
+ break;
+
+ // different graphic formats as in ScDrawTransferObj::AddSupportedFormats:
+
+ case SC_SELTRANS_DRAW_BITMAP:
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SVXB );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ break;
+
+ case SC_SELTRANS_DRAW_GRAPHIC:
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SVXB );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ break;
+
+ case SC_SELTRANS_DRAW_BOOKMARK:
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::SOLK );
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR );
+ AddFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK );
+ AddFormat( SotClipboardFormatId::DRAWING );
+ break;
+
+ case SC_SELTRANS_DRAW_OLE:
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ break;
+
+ case SC_SELTRANS_DRAW_OTHER:
+ // other drawing objects
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::DRAWING );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ break;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
+void ScSelectionTransferObj::CreateCellData()
+{
+ OSL_ENSURE( !mxCellData.is(), "CreateCellData twice" );
+ if ( pView )
+ {
+ ScViewData& rViewData = pView->GetViewData();
+ ScMarkData aNewMark( rViewData.GetMarkData() ); // use local copy for MarkToSimple
+ aNewMark.MarkToSimple();
+
+ // similar to ScViewFunctionSet::BeginDrag
+ if ( aNewMark.IsMarked() && !aNewMark.IsMultiMarked() )
+ {
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+
+ const ScRange& aSelRange = aNewMark.GetMarkArea();
+ ScDocShellRef aDragShellRef;
+ if ( pDocSh->GetDocument().HasOLEObjectsInArea( aSelRange, &aNewMark ) )
+ {
+ aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately
+ aDragShellRef->DoInitNew();
+ }
+ ScDrawLayer::SetGlobalDrawPersist( aDragShellRef.get() );
+
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+ // bApi = sal_True -> no error messages
+ // #i18364# bStopEdit = sal_False -> don't end edit mode
+ // (this may be called from pasting into the edit line)
+ bool bCopied = rViewData.GetView()->CopyToClip( pClipDoc.get(), false, true, true, false );
+
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+
+ if ( bCopied )
+ {
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScTransferObj ctor
+
+ rtl::Reference<ScTransferObj> pTransferObj = new ScTransferObj( std::move(pClipDoc), aObjDesc );
+
+ // SetDragHandlePos is not used - there is no mouse position
+ //? pTransferObj->SetVisibleTab( nTab );
+
+ SfxObjectShellRef aPersistRef( aDragShellRef.get() );
+ pTransferObj->SetDrawPersist( aPersistRef ); // keep persist for ole objects alive
+
+ pTransferObj->SetDragSource( pDocSh, aNewMark );
+
+ mxCellData = pTransferObj;
+ }
+ }
+ }
+ OSL_ENSURE( mxCellData.is(), "can't create CellData" );
+}
+
+void ScSelectionTransferObj::CreateDrawData()
+{
+ OSL_ENSURE( !mxDrawData.is(), "CreateDrawData twice" );
+ if ( pView )
+ {
+ // similar to ScDrawView::BeginDrag
+
+ ScDrawView* pDrawView = pView->GetScDrawView();
+ if ( pDrawView )
+ {
+ bool bAnyOle, bOneOle;
+ const SdrMarkList& rMarkList = pDrawView->GetMarkedObjectList();
+ ScDrawView::CheckOle( rMarkList, bAnyOle, bOneOle );
+
+ ScDocShellRef aDragShellRef;
+ if (bAnyOle)
+ {
+ aDragShellRef = new ScDocShell; // Without Ref the DocShell does not live
+ aDragShellRef->DoInitNew();
+ }
+
+ ScDrawLayer::SetGlobalDrawPersist( aDragShellRef.get() );
+ std::unique_ptr<SdrModel> pModel(pDrawView->CreateMarkedObjModel());
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+
+ ScViewData& rViewData = pView->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScDrawTransferObj ctor
+
+ rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pModel), pDocSh, aObjDesc );
+
+ SfxObjectShellRef aPersistRef( aDragShellRef.get() );
+ pTransferObj->SetDrawPersist( aPersistRef ); // keep persist for ole objects alive
+ pTransferObj->SetDragSource( pDrawView ); // copies selection
+
+ mxDrawData = pTransferObj;
+ }
+ }
+ OSL_ENSURE( mxDrawData.is(), "can't create DrawData" );
+}
+
+ScTransferObj* ScSelectionTransferObj::GetCellData()
+{
+ if ( !mxCellData.is() && ( eMode == SC_SELTRANS_CELL || eMode == SC_SELTRANS_CELLS ) )
+ CreateCellData();
+ return mxCellData.get();
+}
+
+ScDrawTransferObj* ScSelectionTransferObj::GetDrawData()
+{
+ if ( !mxDrawData.is() && ( eMode == SC_SELTRANS_DRAW_BITMAP || eMode == SC_SELTRANS_DRAW_GRAPHIC ||
+ eMode == SC_SELTRANS_DRAW_BOOKMARK || eMode == SC_SELTRANS_DRAW_OLE ||
+ eMode == SC_SELTRANS_DRAW_OTHER ) )
+ CreateDrawData();
+ return mxDrawData.get();
+}
+
+bool ScSelectionTransferObj::GetData(
+ const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc )
+{
+ bool bOK = false;
+
+ uno::Reference<datatransfer::XTransferable> xSource;
+ switch (eMode)
+ {
+ case SC_SELTRANS_CELL:
+ case SC_SELTRANS_CELLS:
+ xSource = GetCellData();
+ break;
+ case SC_SELTRANS_DRAW_BITMAP:
+ case SC_SELTRANS_DRAW_GRAPHIC:
+ case SC_SELTRANS_DRAW_BOOKMARK:
+ case SC_SELTRANS_DRAW_OLE:
+ case SC_SELTRANS_DRAW_OTHER:
+ xSource = GetDrawData();
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if ( xSource.is() )
+ {
+ TransferableDataHelper aHelper( xSource );
+ uno::Any aAny = aHelper.GetAny(rFlavor, rDestDoc);
+ bOK = SetAny( aAny );
+ }
+
+ return bOK;
+}
+
+void ScSelectionTransferObj::ObjectReleased()
+{
+ // called when another selection is set from outside
+
+ ForgetView();
+
+ ScModule* pScMod = SC_MOD();
+ if ( pScMod->GetSelectionTransfer() == this )
+ pScMod->SetSelectionTransfer( nullptr );
+
+ TransferableHelper::ObjectReleased();
+}
+
+sal_Bool SAL_CALL ScSelectionTransferObj::isComplex()
+{
+ switch (eMode)
+ {
+ case SC_SELTRANS_CELL:
+ case SC_SELTRANS_CELLS:
+ return false;
+ default:
+ return true;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/transobj.cxx b/sc/source/ui/app/transobj.cxx
new file mode 100644
index 000000000..d0be7e0ae
--- /dev/null
+++ b/sc/source/ui/app/transobj.cxx
@@ -0,0 +1,921 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/justifyitem.hxx>
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+
+#include <o3tl/unit_conversion.hxx>
+#include <osl/diagnose.h>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/lok.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <sot/storage.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/jobset.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <sfx2/docfile.hxx>
+
+#include <transobj.hxx>
+#include <patattr.hxx>
+#include <cellvalue.hxx>
+#include <cellform.hxx>
+#include <document.hxx>
+#include <viewopti.hxx>
+#include <editutil.hxx>
+#include <impex.hxx>
+#include <formulacell.hxx>
+#include <printfun.hxx>
+#include <docfunc.hxx>
+#include <scmod.hxx>
+#include <dragdata.hxx>
+#include <sortparam.hxx>
+#include <tabvwsh.hxx>
+
+#include <editeng/paperinf.hxx>
+#include <editeng/sizeitem.hxx>
+#include <formula/errorcodes.hxx>
+#include <docsh.hxx>
+#include <markdata.hxx>
+#include <stlpool.hxx>
+#include <viewdata.hxx>
+#include <dociter.hxx>
+#include <cellsuno.hxx>
+#include <stringutil.hxx>
+#include <formulaiter.hxx>
+
+using namespace com::sun::star;
+
+constexpr sal_uInt32 SCTRANS_TYPE_IMPEX = 1;
+constexpr sal_uInt32 SCTRANS_TYPE_EDIT_RTF = 2;
+constexpr sal_uInt32 SCTRANS_TYPE_EDIT_BIN = 3;
+constexpr sal_uInt32 SCTRANS_TYPE_EMBOBJ = 4;
+constexpr sal_uInt32 SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT = 5;
+
+void ScTransferObj::GetAreaSize( const ScDocument& rDoc, SCTAB nTab1, SCTAB nTab2, SCROW& nRow, SCCOL& nCol )
+{
+ SCCOL nMaxCol = 0;
+ SCROW nMaxRow = 0;
+ for( SCTAB nTab = nTab1; nTab <= nTab2; nTab++ )
+ {
+ SCCOL nLastCol = 0;
+ SCROW nLastRow = 0;
+ // GetPrintArea instead of GetCellArea - include drawing objects
+ if( rDoc.GetPrintArea( nTab, nLastCol, nLastRow ) )
+ {
+ if( nLastCol > nMaxCol )
+ nMaxCol = nLastCol;
+ if( nLastRow > nMaxRow )
+ nMaxRow = nLastRow;
+ }
+ }
+ nRow = nMaxRow;
+ nCol = nMaxCol;
+}
+
+void ScTransferObj::PaintToDev( OutputDevice* pDev, ScDocument& rDoc, double nPrintFactor,
+ const ScRange& rBlock )
+{
+ tools::Rectangle aBound( Point(), pDev->GetOutputSize() ); //! use size from clip area?
+
+ ScViewData aViewData(rDoc);
+
+ aViewData.SetTabNo( rBlock.aEnd.Tab() );
+ aViewData.SetScreen( rBlock.aStart.Col(), rBlock.aStart.Row(),
+ rBlock.aEnd.Col(), rBlock.aEnd.Row() );
+
+ ScPrintFunc::DrawToDev( rDoc, pDev, nPrintFactor, aBound, &aViewData, false/*bMetaFile*/ );
+}
+
+ScTransferObj::ScTransferObj( const std::shared_ptr<ScDocument>& pClipDoc, const TransferableObjectDescriptor& rDesc ) :
+ m_pDoc( pClipDoc ),
+ m_nNonFiltered(0),
+ m_aObjDesc( rDesc ),
+ m_nDragHandleX( 0 ),
+ m_nDragHandleY( 0 ),
+ m_nSourceCursorX( m_pDoc->MaxCol() + 1 ),
+ m_nSourceCursorY( m_pDoc->MaxRow() + 1 ),
+ m_nDragSourceFlags( ScDragSrc::Undefined ),
+ m_bDragWasInternal( false ),
+ m_bUsedForLink( false ),
+ m_bUseInApi( false )
+{
+ OSL_ENSURE(m_pDoc->IsClipboard(), "wrong document");
+
+ // get aBlock from clipboard doc
+
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ m_pDoc->GetClipStart( nCol1, nRow1 );
+ m_pDoc->GetClipArea( nCol2, nRow2, true ); // real source area - include filtered rows
+ nCol2 = sal::static_int_cast<SCCOL>( nCol2 + nCol1 );
+ nRow2 = sal::static_int_cast<SCROW>( nRow2 + nRow1 );
+
+ SCCOL nDummy;
+ m_pDoc->GetClipArea( nDummy, m_nNonFiltered, false );
+ m_bHasFiltered = (m_nNonFiltered < (nRow2 - nRow1));
+ ++m_nNonFiltered; // to get count instead of diff
+
+ SCTAB nTab1=0;
+ SCTAB nTab2=0;
+ bool bFirst = true;
+ for (SCTAB i=0; i< m_pDoc->GetTableCount(); i++)
+ if (m_pDoc->HasTable(i))
+ {
+ if (bFirst)
+ nTab1 = i;
+ nTab2 = i;
+ bFirst = false;
+ }
+ OSL_ENSURE(!bFirst, "no sheet selected");
+
+ // only limit to used cells if whole sheet was marked
+ // (so empty cell areas can be copied)
+ if ( nCol2>=m_pDoc->MaxCol() && nRow2>=m_pDoc->MaxRow() )
+ {
+ SCROW nMaxRow;
+ SCCOL nMaxCol;
+ GetAreaSize( *m_pDoc, nTab1, nTab2, nMaxRow, nMaxCol );
+ if( nMaxRow < nRow2 )
+ nRow2 = nMaxRow;
+ if( nMaxCol < nCol2 )
+ nCol2 = nMaxCol;
+ }
+
+ m_aBlock = ScRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ m_nVisibleTab = nTab1; // valid table as default
+
+ tools::Rectangle aMMRect = m_pDoc->GetMMRect( nCol1,nRow1, nCol2,nRow2, nTab1 );
+ m_aObjDesc.maSize = aMMRect.GetSize();
+ PrepareOLE( m_aObjDesc );
+}
+
+ScTransferObj::~ScTransferObj()
+{
+ SolarMutexGuard aSolarGuard;
+
+ bool bIsDisposing = comphelper::LibreOfficeKit::isActive() && !ScTabViewShell::GetActiveViewShell();
+ ScModule* pScMod = SC_MOD();
+ if (pScMod && !bIsDisposing && pScMod->GetDragData().pCellTransfer == this)
+ {
+ OSL_FAIL("ScTransferObj wasn't released");
+ pScMod->ResetDragObject();
+ }
+
+ m_pDoc.reset(); // ScTransferObj is owner of clipboard document
+
+ m_aDocShellRef.clear(); // before releasing the mutex
+
+ m_aDrawPersistRef.clear(); // after the model
+
+}
+
+ScTransferObj* ScTransferObj::GetOwnClipboard(const uno::Reference<datatransfer::XTransferable2>& xTransferable)
+{
+ return comphelper::getFromUnoTunnel<ScTransferObj>(xTransferable);
+}
+
+void ScTransferObj::AddSupportedFormats()
+{
+ // same formats as in ScSelectionTransferObj::AddSupportedFormats
+ AddFormat( SotClipboardFormatId::EMBED_SOURCE );
+ AddFormat( SotClipboardFormatId::OBJECTDESCRIPTOR );
+ AddFormat( SotClipboardFormatId::GDIMETAFILE );
+ AddFormat( SotClipboardFormatId::PNG );
+ AddFormat( SotClipboardFormatId::BITMAP );
+
+ // ScImportExport formats
+ AddFormat( SotClipboardFormatId::HTML );
+ AddFormat( SotClipboardFormatId::SYLK );
+ AddFormat( SotClipboardFormatId::LINK );
+ AddFormat( SotClipboardFormatId::DIF );
+ AddFormat( SotClipboardFormatId::STRING );
+ AddFormat( SotClipboardFormatId::STRING_TSVC );
+
+ AddFormat( SotClipboardFormatId::RTF );
+ AddFormat( SotClipboardFormatId::RICHTEXT );
+ if ( m_aBlock.aStart == m_aBlock.aEnd )
+ {
+ AddFormat( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT );
+ }
+}
+
+static ScRange lcl_reduceBlock(const ScDocument& rDoc, ScRange aReducedBlock, bool bIncludeVisual = false)
+{
+ if ((aReducedBlock.aEnd.Col() == rDoc.MaxCol() || aReducedBlock.aEnd.Row() == rDoc.MaxRow()) &&
+ aReducedBlock.aStart.Tab() == aReducedBlock.aEnd.Tab())
+ {
+ // Shrink the block here so we don't waste time creating huge
+ // output when whole columns or rows are selected.
+
+ SCCOL nPrintAreaEndCol = 0;
+ SCROW nPrintAreaEndRow = 0;
+ if (bIncludeVisual)
+ rDoc.GetPrintArea( aReducedBlock.aStart.Tab(), nPrintAreaEndCol, nPrintAreaEndRow, true );
+
+ // Shrink the area to allow pasting to external applications.
+ // Shrink to real data area for HTML, RTF and RICHTEXT, but include
+ // all objects and top-left area for BITMAP and PNG.
+ SCCOL nStartCol = aReducedBlock.aStart.Col();
+ SCROW nStartRow = aReducedBlock.aStart.Row();
+ SCCOL nEndCol = aReducedBlock.aEnd.Col();
+ SCROW nEndRow = aReducedBlock.aEnd.Row();
+
+ if (bIncludeVisual)
+ {
+ ScDataAreaExtras aDataAreaExtras;
+ aDataAreaExtras.mbCellNotes = true;
+ aDataAreaExtras.mbCellDrawObjects = true;
+ bool bShrunk = false;
+ rDoc.ShrinkToUsedDataArea( bShrunk, aReducedBlock.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow,
+ false, true /*bStickyTopRow*/, true /*bStickyLeftCol*/, &aDataAreaExtras);
+ aDataAreaExtras.GetOverallRange( nStartCol, nStartRow, nEndCol, nEndRow, ScDataAreaExtras::Clip::None);
+ }
+ else
+ {
+ bool bShrunk = false;
+ rDoc.ShrinkToUsedDataArea( bShrunk, aReducedBlock.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow,
+ false, false /*bStickyTopRow*/, false /*bStickyLeftCol*/);
+ }
+
+ if ( nPrintAreaEndRow > nEndRow )
+ nEndRow = nPrintAreaEndRow;
+
+ if ( nPrintAreaEndCol > nEndCol )
+ nEndCol = nPrintAreaEndCol;
+
+ aReducedBlock = ScRange(nStartCol, nStartRow, aReducedBlock.aStart.Tab(), nEndCol, nEndRow, aReducedBlock.aEnd.Tab());
+ }
+ return aReducedBlock;
+}
+
+bool ScTransferObj::GetData( const datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ )
+{
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+ bool bOK = false;
+
+ if( HasFormat( nFormat ) )
+ {
+ ScRange aReducedBlock = m_aBlock;
+
+ bool bReduceBlockFormat =
+ nFormat == SotClipboardFormatId::HTML
+ || nFormat == SotClipboardFormatId::RTF
+ || nFormat == SotClipboardFormatId::RICHTEXT
+ || nFormat == SotClipboardFormatId::BITMAP
+ || nFormat == SotClipboardFormatId::PNG;
+
+ const bool bIncludeVisual = (nFormat == SotClipboardFormatId::BITMAP ||
+ nFormat == SotClipboardFormatId::PNG);
+
+ if (bReduceBlockFormat)
+ aReducedBlock = lcl_reduceBlock(*m_pDoc, m_aBlock, bIncludeVisual);
+
+ if ( nFormat == SotClipboardFormatId::LINKSRCDESCRIPTOR || nFormat == SotClipboardFormatId::OBJECTDESCRIPTOR )
+ {
+ bOK = SetTransferableObjectDescriptor( m_aObjDesc );
+ }
+ else if ( ( nFormat == SotClipboardFormatId::RTF || nFormat == SotClipboardFormatId::RICHTEXT ||
+ nFormat == SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT ) && m_aBlock.aStart == m_aBlock.aEnd )
+ {
+ // RTF from a single cell is handled by EditEngine
+
+ SCCOL nCol = m_aBlock.aStart.Col();
+ SCROW nRow = m_aBlock.aStart.Row();
+ SCTAB nTab = m_aBlock.aStart.Tab();
+ ScAddress aPos(nCol, nRow, nTab);
+
+ const ScPatternAttr* pPattern = m_pDoc->GetPattern( nCol, nRow, nTab );
+ ScTabEditEngine aEngine( *pPattern, m_pDoc->GetEditPool(), m_pDoc.get() );
+ ScRefCellValue aCell(*m_pDoc, aPos);
+ if (aCell.meType == CELLTYPE_EDIT)
+ {
+ const EditTextObject* pObj = aCell.mpEditText;
+ aEngine.SetTextCurrentDefaults(*pObj);
+ }
+ else
+ {
+ SvNumberFormatter* pFormatter = m_pDoc->GetFormatTable();
+ sal_uInt32 nNumFmt = pPattern->GetNumberFormat(pFormatter);
+ const Color* pColor;
+ OUString aText = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, *m_pDoc);
+ if (!aText.isEmpty())
+ aEngine.SetTextCurrentDefaults(aText);
+ }
+
+ bOK = SetObject( &aEngine,
+ ((nFormat == SotClipboardFormatId::RTF) ? SCTRANS_TYPE_EDIT_RTF :
+ ((nFormat == SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT) ?
+ SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT : SCTRANS_TYPE_EDIT_BIN)),
+ rFlavor );
+ }
+ else if ( ScImportExport::IsFormatSupported( nFormat ) || nFormat == SotClipboardFormatId::RTF
+ || nFormat == SotClipboardFormatId::RICHTEXT )
+ {
+ // if this transfer object was used to create a DDE link, filtered rows
+ // have to be included for subsequent calls (to be consistent with link data)
+ if ( nFormat == SotClipboardFormatId::LINK )
+ m_bUsedForLink = true;
+
+ bool bIncludeFiltered = m_pDoc->IsCutMode() || m_bUsedForLink;
+
+ ScImportExport aObj( *m_pDoc, aReducedBlock );
+ // Plain text ("Unformatted text") may contain embedded tabs and
+ // line breaks but is not enclosed in quotes. Which makes it
+ // unsuitable for multiple cells, especially if one of them is
+ // multi-line, but otherwise is expected behavior for plain text.
+ // For multiple cells replace embedded line breaks (and tabs) with
+ // space character, otherwise pasting would yield odd results.
+ /* XXX: it's debatable whether this is actually expected, but
+ * there's no way to satisfy all possible requirements when
+ * copy/pasting unformatted text. */
+ const bool bPlainMulti = (nFormat == SotClipboardFormatId::STRING &&
+ aReducedBlock.aStart != aReducedBlock.aEnd);
+ // Add quotes only for STRING_TSVC.
+ /* TODO: a possible future STRING_TSV should not contain embedded
+ * line breaks nor tab (separator) characters and not be quoted.
+ * A possible STRING_CSV should. */
+ ScExportTextOptions aTextOptions( ScExportTextOptions::None, 0,
+ (nFormat == SotClipboardFormatId::STRING_TSVC));
+ if ( bPlainMulti || m_bUsedForLink )
+ {
+ // For a DDE link or plain text multiple cells, convert line
+ // breaks and separators to space.
+ aTextOptions.meNewlineConversion = ScExportTextOptions::ToSpace;
+ aTextOptions.mcSeparatorConvertTo = ' ';
+ aTextOptions.mbAddQuotes = false;
+ }
+ aObj.SetExportTextOptions(aTextOptions);
+ aObj.SetFormulas( m_pDoc->GetViewOptions().GetOption( VOPT_FORMULAS ) );
+ aObj.SetIncludeFiltered( bIncludeFiltered );
+
+ // DataType depends on format type:
+
+ if ( rFlavor.DataType.equals( ::cppu::UnoType<OUString>::get() ) )
+ {
+ OUString aString;
+ if ( aObj.ExportString( aString, nFormat ) )
+ bOK = SetString( aString );
+ }
+ else if ( rFlavor.DataType.equals( cppu::UnoType<uno::Sequence< sal_Int8 >>::get() ) )
+ {
+ // SetObject converts a stream into an Int8-Sequence
+ bOK = SetObject( &aObj, SCTRANS_TYPE_IMPEX, rFlavor );
+ }
+ else
+ {
+ OSL_FAIL("unknown DataType");
+ }
+ }
+ else if ( nFormat == SotClipboardFormatId::BITMAP || nFormat == SotClipboardFormatId::PNG )
+ {
+ tools::Rectangle aMMRect = m_pDoc->GetMMRect( aReducedBlock.aStart.Col(), aReducedBlock.aStart.Row(),
+ aReducedBlock.aEnd.Col(), aReducedBlock.aEnd.Row(),
+ aReducedBlock.aStart.Tab() );
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ pVirtDev->SetOutputSizePixel(pVirtDev->LogicToPixel(aMMRect.GetSize(), MapMode(MapUnit::Map100thMM)));
+
+ PaintToDev( pVirtDev, *m_pDoc, 1.0, aReducedBlock );
+
+ pVirtDev->SetMapMode( MapMode( MapUnit::MapPixel ) );
+ BitmapEx aBmp = pVirtDev->GetBitmapEx( Point(), pVirtDev->GetOutputSize() );
+ bOK = SetBitmapEx( aBmp, rFlavor );
+ }
+ else if ( nFormat == SotClipboardFormatId::GDIMETAFILE )
+ {
+ // #i123405# Do not limit visual size calculation for metafile creation.
+ // It seems unlikely that removing the limitation causes problems since
+ // metafile creation means that no real pixel device in the needed size is
+ // created.
+ InitDocShell(false);
+
+ SfxObjectShell* pEmbObj = m_aDocShellRef.get();
+
+ // like SvEmbeddedTransfer::GetData:
+ GDIMetaFile aMtf;
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ MapMode aMapMode( pEmbObj->GetMapUnit() );
+ tools::Rectangle aVisArea( pEmbObj->GetVisArea( ASPECT_CONTENT ) );
+
+ pVDev->EnableOutput( false );
+ pVDev->SetMapMode( aMapMode );
+ aMtf.SetPrefSize( aVisArea.GetSize() );
+ aMtf.SetPrefMapMode( aMapMode );
+ aMtf.Record( pVDev );
+
+ pEmbObj->DoDraw( pVDev, Point(), aVisArea.GetSize(), JobSetup() );
+
+ aMtf.Stop();
+ aMtf.WindStart();
+
+ bOK = SetGDIMetaFile( aMtf );
+ }
+ else if ( nFormat == SotClipboardFormatId::EMBED_SOURCE )
+ {
+ //TODO/LATER: differentiate between formats?!
+ // #i123405# Do limit visual size calculation to PageSize
+ InitDocShell(true); // set aDocShellRef
+
+ SfxObjectShell* pEmbObj = m_aDocShellRef.get();
+ bOK = SetObject( pEmbObj, SCTRANS_TYPE_EMBOBJ, rFlavor );
+ }
+ }
+ return bOK;
+}
+
+bool ScTransferObj::WriteObject( tools::SvRef<SotTempStream>& rxOStm, void* pUserObject, sal_uInt32 nUserObjectId,
+ const datatransfer::DataFlavor& rFlavor )
+{
+ // called from SetObject, put data into stream
+
+ bool bRet = false;
+ switch (nUserObjectId)
+ {
+ case SCTRANS_TYPE_IMPEX:
+ {
+ ScImportExport* pImpEx = static_cast<ScImportExport*>(pUserObject);
+
+ SotClipboardFormatId nFormat = SotExchange::GetFormat( rFlavor );
+ // mba: no BaseURL for data exchange
+ if ( pImpEx->ExportStream( *rxOStm, OUString(), nFormat ) )
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ break;
+
+ case SCTRANS_TYPE_EDIT_RTF:
+ case SCTRANS_TYPE_EDIT_BIN:
+ {
+ ScTabEditEngine* pEngine = static_cast<ScTabEditEngine*>(pUserObject);
+ if ( nUserObjectId == SCTRANS_TYPE_EDIT_RTF )
+ {
+ pEngine->Write( *rxOStm, EETextFormat::Rtf );
+ bRet = ( rxOStm->GetError() == ERRCODE_NONE );
+ }
+ else
+ {
+ // can't use Write for EditEngine format because that would
+ // write old format without support for unicode characters.
+ // Get the data from the EditEngine's transferable instead.
+
+ sal_Int32 nParCnt = pEngine->GetParagraphCount();
+ if ( nParCnt == 0 )
+ nParCnt = 1;
+ ESelection aSel( 0, 0, nParCnt-1, pEngine->GetTextLen(nParCnt-1) );
+
+ uno::Reference<datatransfer::XTransferable> xEditTrans = pEngine->CreateTransferable( aSel );
+ TransferableDataHelper aEditHelper( xEditTrans );
+
+ bRet = aEditHelper.GetSotStorageStream( rFlavor, rxOStm );
+ }
+ }
+ break;
+
+ case SCTRANS_TYPE_EDIT_ODF_TEXT_FLAT:
+ {
+ ScTabEditEngine* pEngine = static_cast<ScTabEditEngine*>(pUserObject);
+ pEngine->Write(*rxOStm, EETextFormat::Xml);
+ bRet = (rxOStm->GetError() == ERRCODE_NONE);
+ }
+ break;
+
+ case SCTRANS_TYPE_EMBOBJ:
+ {
+ // TODO/MBA: testing
+ SfxObjectShell* pEmbObj = static_cast<SfxObjectShell*>(pUserObject);
+ ::utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ 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;
+
+ xWorkStore->dispose();
+ xWorkStore.clear();
+ }
+ break;
+
+ default:
+ OSL_FAIL("unknown object id");
+ }
+ return bRet;
+}
+
+sal_Bool SAL_CALL ScTransferObj::isComplex()
+{
+ ScRange aReduced = lcl_reduceBlock(*m_pDoc, m_aBlock);
+ size_t nCells = (aReduced.aEnd.Col() - aReduced.aStart.Col() + 1) *
+ (aReduced.aEnd.Row() - aReduced.aStart.Row() + 1) *
+ (aReduced.aEnd.Tab() - aReduced.aStart.Tab() + 1);
+ return nCells > 1000;
+}
+
+void ScTransferObj::DragFinished( sal_Int8 nDropAction )
+{
+ if ( nDropAction == DND_ACTION_MOVE && !m_bDragWasInternal && !(m_nDragSourceFlags & ScDragSrc::Navigator) )
+ {
+ // move: delete source data
+ ScDocShell* pSourceSh = GetSourceDocShell();
+ if (pSourceSh)
+ {
+ ScMarkData aMarkData = GetSourceMarkData();
+ // external drag&drop doesn't copy objects, so they also aren't deleted:
+ // bApi=TRUE, don't show error messages from drag&drop
+ pSourceSh->GetDocFunc().DeleteContents( aMarkData, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS, true, true );
+ }
+ }
+
+ ScModule* pScMod = SC_MOD();
+ if ( pScMod->GetDragData().pCellTransfer == this )
+ pScMod->ResetDragObject();
+
+ m_xDragSourceRanges = nullptr; // don't keep source after dropping
+
+ TransferDataContainer::DragFinished( nDropAction );
+}
+
+void ScTransferObj::SetDragHandlePos( SCCOL nX, SCROW nY )
+{
+ m_nDragHandleX = nX;
+ m_nDragHandleY = nY;
+}
+
+void ScTransferObj::SetSourceCursorPos( SCCOL nX, SCROW nY )
+{
+ m_nSourceCursorX = nX;
+ m_nSourceCursorY = nY;
+}
+
+bool ScTransferObj::WasSourceCursorInSelection() const
+{
+ return
+ m_nSourceCursorX >= m_aBlock.aStart.Col() && m_nSourceCursorX <= m_aBlock.aEnd.Col() &&
+ m_nSourceCursorY >= m_aBlock.aStart.Row() && m_nSourceCursorY <= m_aBlock.aEnd.Row();
+}
+
+void ScTransferObj::SetVisibleTab( SCTAB nNew )
+{
+ m_nVisibleTab = nNew;
+}
+
+void ScTransferObj::SetDrawPersist( const SfxObjectShellRef& rRef )
+{
+ m_aDrawPersistRef = rRef;
+}
+
+void ScTransferObj::SetDragSource( ScDocShell* pSourceShell, const ScMarkData& rMark )
+{
+ ScRangeList aRanges;
+ rMark.FillRangeListWithMarks( &aRanges, false );
+ m_xDragSourceRanges = new ScCellRangesObj( pSourceShell, aRanges );
+}
+
+void ScTransferObj::SetDragSourceFlags(ScDragSrc nFlags)
+{
+ m_nDragSourceFlags = nFlags;
+}
+
+void ScTransferObj::SetDragWasInternal()
+{
+ m_bDragWasInternal = true;
+}
+
+void ScTransferObj::SetUseInApi( bool bSet )
+{
+ m_bUseInApi = bSet;
+}
+
+ScDocument* ScTransferObj::GetSourceDocument()
+{
+ ScDocShell* pSourceDocSh = GetSourceDocShell();
+ if (pSourceDocSh)
+ return &pSourceDocSh->GetDocument();
+ return nullptr;
+}
+
+ScDocShell* ScTransferObj::GetSourceDocShell()
+{
+ ScCellRangesBase* pRangesObj = comphelper::getFromUnoTunnel<ScCellRangesBase>( m_xDragSourceRanges );
+ if (pRangesObj)
+ return pRangesObj->GetDocShell();
+
+ return nullptr; // none set
+}
+
+ScMarkData ScTransferObj::GetSourceMarkData() const
+{
+ ScMarkData aMarkData(m_pDoc->GetSheetLimits());
+ ScCellRangesBase* pRangesObj = comphelper::getFromUnoTunnel<ScCellRangesBase>( m_xDragSourceRanges );
+ if (pRangesObj)
+ {
+ const ScRangeList& rRanges = pRangesObj->GetRangeList();
+ aMarkData.MarkFromRangeList( rRanges, false );
+ }
+ return aMarkData;
+}
+
+// initialize aDocShellRef with a live document from the ClipDoc
+
+// #i123405# added parameter to allow size calculation without limitation
+// to PageSize, e.g. used for Metafile creation for clipboard.
+
+void ScTransferObj::InitDocShell(bool bLimitToPageSize)
+{
+ if ( m_aDocShellRef.is() )
+ return;
+
+ ScDocShell* pDocSh = new ScDocShell;
+ m_aDocShellRef = pDocSh; // ref must be there before InitNew
+
+ pDocSh->DoInitNew();
+
+ ScDocument& rDestDoc = pDocSh->GetDocument();
+ ScMarkData aDestMark(rDestDoc.GetSheetLimits());
+ aDestMark.SelectTable( 0, true );
+
+ rDestDoc.SetDocOptions( m_pDoc->GetDocOptions() ); // #i42666#
+
+ OUString aTabName;
+ m_pDoc->GetName( m_aBlock.aStart.Tab(), aTabName );
+ rDestDoc.RenameTab( 0, aTabName );
+
+ rDestDoc.CopyStdStylesFrom(*m_pDoc);
+
+ SCCOL nStartX = m_aBlock.aStart.Col();
+ SCROW nStartY = m_aBlock.aStart.Row();
+ SCCOL nEndX = m_aBlock.aEnd.Col();
+ SCROW nEndY = m_aBlock.aEnd.Row();
+
+ // widths / heights
+ // (must be copied before CopyFromClip, for drawing objects)
+
+ SCCOL nCol;
+ SCTAB nSrcTab = m_aBlock.aStart.Tab();
+ rDestDoc.SetLayoutRTL(0, m_pDoc->IsLayoutRTL(nSrcTab));
+ for (nCol=nStartX; nCol<=nEndX; nCol++)
+ if ( m_pDoc->ColHidden(nCol, nSrcTab) )
+ rDestDoc.ShowCol( nCol, 0, false );
+ else
+ rDestDoc.SetColWidth( nCol, 0, m_pDoc->GetColWidth( nCol, nSrcTab ) );
+
+ if (nStartY > 0)
+ {
+ // Set manual height for all previous rows so we can ensure
+ // that visible area will not change due to autoheight
+ rDestDoc.SetManualHeight(0, nStartY - 1, 0, true);
+ }
+ for (SCROW nRow = nStartY; nRow <= nEndY; ++nRow)
+ {
+ if ( m_pDoc->RowHidden(nRow, nSrcTab) )
+ rDestDoc.ShowRow( nRow, 0, false );
+ else
+ {
+ rDestDoc.SetRowHeight( nRow, 0, m_pDoc->GetOriginalHeight( nRow, nSrcTab ) );
+
+ // if height was set manually, that flag has to be copied, too
+ bool bManual = m_pDoc->IsManualRowHeight(nRow, nSrcTab);
+ rDestDoc.SetManualHeight(nRow, nRow, 0, bManual);
+ }
+ }
+
+ if (m_pDoc->GetDrawLayer() || m_pDoc->HasNotes())
+ pDocSh->MakeDrawLayer();
+
+ // cell range is copied to the original position, but on the first sheet
+ // -> bCutMode must be set
+ // pDoc is always a Clipboard-document
+
+ ScRange aDestRange( nStartX,nStartY,0, nEndX,nEndY,0 );
+ bool bWasCut = m_pDoc->IsCutMode();
+ if (!bWasCut)
+ m_pDoc->SetClipArea( aDestRange, true ); // Cut
+ rDestDoc.CopyFromClip( aDestRange, aDestMark, InsertDeleteFlags::ALL, nullptr, m_pDoc.get(), false );
+ m_pDoc->SetClipArea( aDestRange, bWasCut );
+
+ StripRefs(*m_pDoc, nStartX,nStartY, nEndX,nEndY, rDestDoc);
+
+ ScRange aMergeRange = aDestRange;
+ rDestDoc.ExtendMerge( aMergeRange, true );
+
+ m_pDoc->CopyDdeLinks( rDestDoc ); // copy values of DDE Links
+
+ // page format (grid etc) and page size (maximum size for ole object)
+
+ Size aPaperSize = SvxPaperInfo::GetPaperSize( PAPER_A4 ); // Twips
+ ScStyleSheetPool* pStylePool = m_pDoc->GetStyleSheetPool();
+ OUString aStyleName = m_pDoc->GetPageStyle( m_aBlock.aStart.Tab() );
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Page );
+ if (pStyleSheet)
+ {
+ const SfxItemSet& rSourceSet = pStyleSheet->GetItemSet();
+ aPaperSize = rSourceSet.Get(ATTR_PAGE_SIZE).GetSize();
+
+ // CopyStyleFrom copies SetItems with correct pool
+ ScStyleSheetPool* pDestPool = rDestDoc.GetStyleSheetPool();
+ pDestPool->CopyStyleFrom( pStylePool, aStyleName, SfxStyleFamily::Page );
+ }
+
+ ScViewData aViewData( *pDocSh, nullptr );
+ aViewData.SetScreen( nStartX,nStartY, nEndX,nEndY );
+ aViewData.SetCurX( nStartX );
+ aViewData.SetCurY( nStartY );
+
+ rDestDoc.SetViewOptions( m_pDoc->GetViewOptions() );
+
+ // Size
+ //! get while copying sizes
+
+ tools::Long nPosX = 0;
+ tools::Long nPosY = 0;
+
+ for (nCol=0; nCol<nStartX; nCol++)
+ nPosX += rDestDoc.GetColWidth( nCol, 0 );
+ nPosY += rDestDoc.GetRowHeight( 0, nStartY-1, 0 );
+ nPosX = o3tl::convert(nPosX, o3tl::Length::twip, o3tl::Length::mm100);
+ nPosY = o3tl::convert(nPosY, o3tl::Length::twip, o3tl::Length::mm100);
+
+ aPaperSize.setWidth( aPaperSize.Width() * 2 ); // limit OLE object to double of page size
+ aPaperSize.setHeight( aPaperSize.Height() * 2 );
+
+ tools::Long nSizeX = 0;
+ tools::Long nSizeY = 0;
+ for (nCol=nStartX; nCol<=nEndX; nCol++)
+ {
+ tools::Long nAdd = rDestDoc.GetColWidth( nCol, 0 );
+ if ( bLimitToPageSize && nSizeX+nAdd > aPaperSize.Width() && nSizeX ) // above limit?
+ break;
+ nSizeX += nAdd;
+ }
+ for (SCROW nRow=nStartY; nRow<=nEndY; nRow++)
+ {
+ tools::Long nAdd = rDestDoc.GetRowHeight( nRow, 0 );
+ if ( bLimitToPageSize && nSizeY+nAdd > aPaperSize.Height() && nSizeY ) // above limit?
+ break;
+ nSizeY += nAdd;
+ }
+ nSizeX = o3tl::convert(nSizeX, o3tl::Length::twip, o3tl::Length::mm100);
+ nSizeY = o3tl::convert(nSizeY, o3tl::Length::twip, o3tl::Length::mm100);
+
+// pDocSh->SetVisAreaSize( Size(nSizeX,nSizeY) );
+
+ tools::Rectangle aNewArea( Point(nPosX,nPosY), Size(nSizeX,nSizeY) );
+ //TODO/LATER: why twice?!
+ //pDocSh->SvInPlaceObject::SetVisArea( aNewArea );
+ pDocSh->SetVisArea( aNewArea );
+
+ pDocSh->UpdateOle(aViewData, true);
+
+ //! SetDocumentModified?
+ if ( rDestDoc.IsChartListenerCollectionNeedsUpdate() )
+ rDestDoc.UpdateChartListenerCollection();
+}
+
+SfxObjectShell* ScTransferObj::SetDrawClipDoc( bool bAnyOle, const std::shared_ptr<ScDocument>& pDoc )
+{
+ // update ScGlobal::xDrawClipDocShellRef
+
+ ScGlobal::xDrawClipDocShellRef.clear();
+ if (bAnyOle)
+ {
+ ScGlobal::xDrawClipDocShellRef = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS, pDoc); // there must be a ref
+ ScGlobal::xDrawClipDocShellRef->DoInitNew();
+ }
+
+ return ScGlobal::xDrawClipDocShellRef.get();
+}
+
+void ScTransferObj::StripRefs( ScDocument& rDoc,
+ SCCOL nStartX, SCROW nStartY, SCCOL nEndX, SCROW nEndY,
+ ScDocument& rDestDoc )
+{
+ // In a clipboard doc the data don't have to be on the first sheet
+
+ SCTAB nSrcTab = 0;
+ while (nSrcTab < rDoc.GetTableCount() && !rDoc.HasTable(nSrcTab))
+ ++nSrcTab;
+ SCTAB nDestTab = 0;
+ while (nDestTab < rDestDoc.GetTableCount() && !rDestDoc.HasTable(nDestTab))
+ ++nDestTab;
+
+ if (!rDoc.HasTable(nSrcTab) || !rDestDoc.HasTable(nDestTab))
+ {
+ OSL_FAIL("Sheet not found in ScTransferObj::StripRefs");
+ return;
+ }
+
+ ScRange aRef;
+
+ ScCellIterator aIter( rDoc, ScRange(nStartX, nStartY, nSrcTab, nEndX, nEndY, nSrcTab) );
+ for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
+ {
+ if (aIter.getType() != CELLTYPE_FORMULA)
+ continue;
+
+ ScFormulaCell* pFCell = aIter.getFormulaCell();
+ bool bOut = false;
+ ScDetectiveRefIter aRefIter( rDoc, pFCell );
+ while ( !bOut && aRefIter.GetNextRef( aRef ) )
+ {
+ if ( aRef.aStart.Tab() != nSrcTab || aRef.aEnd.Tab() != nSrcTab ||
+ aRef.aStart.Col() < nStartX || aRef.aEnd.Col() > nEndX ||
+ aRef.aStart.Row() < nStartY || aRef.aEnd.Row() > nEndY )
+ bOut = true;
+ }
+ if (bOut)
+ {
+ SCCOL nCol = aIter.GetPos().Col();
+ SCROW nRow = aIter.GetPos().Row();
+
+ FormulaError nErrCode = pFCell->GetErrCode();
+ ScAddress aPos(nCol, nRow, nDestTab);
+ if (nErrCode != FormulaError::NONE)
+ {
+ if ( rDestDoc.GetAttr( nCol,nRow,nDestTab, ATTR_HOR_JUSTIFY)->GetValue() ==
+ SvxCellHorJustify::Standard )
+ rDestDoc.ApplyAttr( nCol,nRow,nDestTab,
+ SvxHorJustifyItem(SvxCellHorJustify::Right, ATTR_HOR_JUSTIFY) );
+
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDestDoc.SetString(aPos, ScGlobal::GetErrorString(nErrCode), &aParam);
+ }
+ else if (pFCell->IsValue())
+ {
+ rDestDoc.SetValue(aPos, pFCell->GetValue());
+ }
+ else
+ {
+ OUString aStr = pFCell->GetString().getString();
+ if ( pFCell->IsMultilineResult() )
+ {
+ ScFieldEditEngine& rEngine = rDestDoc.GetEditEngine();
+ rEngine.SetTextCurrentDefaults(aStr);
+ rDestDoc.SetEditText(ScAddress(nCol,nRow,nDestTab), rEngine.CreateTextObject());
+ }
+ else
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDestDoc.SetString(aPos, aStr, &aParam);
+ }
+ }
+ }
+ }
+}
+
+const css::uno::Sequence< sal_Int8 >& ScTransferObj::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theScTransferUnoTunnelId;
+ return theScTransferUnoTunnelId.getSeq();
+}
+
+sal_Int64 SAL_CALL ScTransferObj::getSomething( const css::uno::Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(
+ rId, this, comphelper::FallbackToGetSomethingOf<TransferDataContainer>{});
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/typemap.cxx b/sc/source/ui/app/typemap.cxx
new file mode 100644
index 000000000..ac98c6fc4
--- /dev/null
+++ b/sc/source/ui/app/typemap.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 <mid.h>
+#include <editeng/memberids.h>
+#include <svx/unomid.hxx>
+
+#include <sfx2/msg.hxx>
+#include <svl/slstitm.hxx>
+#include <editeng/fontitem.hxx>
+#include <svx/hlnkitem.hxx>
+#include <svl/srchitem.hxx>
+#include <svx/postattr.hxx>
+#include <editeng/postitem.hxx>
+#include <sfx2/tplpitem.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/lineitem.hxx>
+#include <svl/ptitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <svx/algitem.hxx>
+#include <svx/clipfmtitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflhtit.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlndsit.hxx>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xtextit0.hxx>
+#include <svx/xftadit.hxx>
+#include <svx/xftdiit.hxx>
+#include <svx/xftstit.hxx>
+#include <svx/xftmrit.hxx>
+#include <svx/xftouit.hxx>
+#include <svx/xftshit.hxx>
+#include <svx/xftshcit.hxx>
+#include <svx/xftshxy.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/kernitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <svx/drawitem.hxx>
+#include <svl/ilstitem.hxx>
+#include <svl/globalnameitem.hxx>
+#include <svx/chrtitem.hxx>
+#include <svx/zoomslideritem.hxx>
+#include <svx/xflftrit.hxx>
+#include <svx/xlncapit.hxx>
+#include <svx/xlinjoit.hxx>
+#include <svx/galleryitem.hxx>
+#include <svx/sdooitm.hxx>
+#include <avmedia/mediaitem.hxx>
+#include <sfx2/frame.hxx>
+#include <attrib.hxx>
+#include <svx/sdprcitm.hxx>
+#include <svx/sdmetitm.hxx>
+
+#define avmedia_MediaItem ::avmedia::MediaItem
+
+#ifdef DISABLE_DYNLOADING
+/* Avoid clash with the ones from svx/source/form/typemap.cxx */
+#define aSfxBoolItem_Impl sc_source_ui_appl_typemap_aSfxBoolItem_Impl
+#define aSfxInt32Item_Impl sc_source_ui_appl_typemap_aSfxInt32Item_Impl
+#define aSfxStringItem_Impl sc_source_ui_appl_typemap_aSfxStringItem_Impl
+#define aSfxUInt16Item_Impl sc_source_ui_appl_typemap_aSfxUInt16Item_Impl
+#define aSfxUInt32Item_Impl sc_source_ui_appl_typemap_aSfxUInt32Item_Impl
+#define aSfxVoidItem_Impl sc_source_ui_appl_typemap_aSfxVoidItem_Impl
+#define aSvxCharReliefItem_Impl sc_source_ui_appl_typemap_aSvxCharReliefItem_Impl
+#define aSvxClipboardFormatItem_Impl sc_source_ui_appl_typemap_aSvxClipboardFormatItem_Impl
+#define aSvxColorItem_Impl sc_source_ui_appl_typemap_aSvxColorItem_Impl
+#define aSvxContourItem_Impl sc_source_ui_appl_typemap_aSvxContourItem_Impl
+#define aSvxCrossedOutItem_Impl sc_source_ui_appl_typemap_aSvxCrossedOutItem_Impl
+#define aSvxFontHeightItem_Impl sc_source_ui_appl_typemap_aSvxFontHeightItem_Impl
+#define aSvxFontItem_Impl sc_source_ui_appl_typemap_aSvxFontItem_Impl
+#define aSvxLanguageItem_Impl sc_source_ui_appl_typemap_aSvxLanguageItem_Impl
+#define aSvxPostureItem_Impl sc_source_ui_appl_typemap_aSvxPostureItem_Impl
+#define aSvxShadowedItem_Impl sc_source_ui_appl_typemap_aSvxShadowedItem_Impl
+#define aSvxUnderlineItem_Impl sc_source_ui_appl_typemap_aSvxUnderlineItem_Impl
+#define aSvxOverlineItem_Impl sc_source_ui_appl_typemap_aSvxOverlineItem_Impl
+#define aSvxWeightItem_Impl sc_source_ui_appl_typemap_aSvxWeightItem_Impl
+#endif
+
+#define SFX_TYPEMAP
+#include <scslots.hxx>
+
+#ifdef DISABLE_DYNLOADING
+#undef aSfxBoolItem_Impl
+#undef aSfxInt32Item_Impl
+#undef aSfxStringItem_Impl
+#undef aSfxUInt16Item_Impl
+#undef aSfxUInt32Item_Impl
+#undef aSfxVoidItem_Impl
+#undef aSvxCharReliefItem_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/sc/source/ui/app/uiitems.cxx b/sc/source/ui/app/uiitems.cxx
new file mode 100644
index 000000000..91cb50b07
--- /dev/null
+++ b/sc/source/ui/app/uiitems.cxx
@@ -0,0 +1,438 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <uiitems.hxx>
+
+#include <userlist.hxx>
+#include <dpsave.hxx>
+#include <queryparam.hxx>
+
+#include <osl/diagnose.h>
+#include <editeng/editobj.hxx>
+
+/**
+ * Status update for entry field
+ */
+ScInputStatusItem::ScInputStatusItem(
+ sal_uInt16 nWhichP, const ScAddress& rCurPos, const ScAddress& rStartPos,
+ const ScAddress& rEndPos, const OUString& rString, const EditTextObject* pData ) :
+ SfxPoolItem ( nWhichP ),
+ aCursorPos ( rCurPos ),
+ aStartPos ( rStartPos ),
+ aEndPos ( rEndPos ),
+ aString ( rString ),
+ pEditData ( pData ? pData->Clone() : nullptr ),
+ mpMisspellRanges(nullptr)
+{
+}
+
+ScInputStatusItem::ScInputStatusItem( const ScInputStatusItem& rItem ) :
+ SfxPoolItem ( rItem ),
+ aCursorPos ( rItem.aCursorPos ),
+ aStartPos ( rItem.aStartPos ),
+ aEndPos ( rItem.aEndPos ),
+ aString ( rItem.aString ),
+ pEditData ( rItem.pEditData ? rItem.pEditData->Clone() : nullptr ),
+ mpMisspellRanges(rItem.mpMisspellRanges)
+{
+}
+
+ScInputStatusItem::~ScInputStatusItem()
+{
+}
+
+bool ScInputStatusItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ return (aStartPos == static_cast<const ScInputStatusItem&>(rItem).aStartPos)
+ && (aEndPos == static_cast<const ScInputStatusItem&>(rItem).aEndPos)
+ && (aCursorPos == static_cast<const ScInputStatusItem&>(rItem).aCursorPos)
+ && (aString == static_cast<const ScInputStatusItem&>(rItem).aString);
+ //TODO: Compare Edit data!
+}
+
+ScInputStatusItem* ScInputStatusItem::Clone( SfxItemPool * ) const
+{
+ return new ScInputStatusItem( *this );
+}
+
+void ScInputStatusItem::SetMisspellRanges( const std::vector<editeng::MisspellRanges>* pRanges )
+{
+ mpMisspellRanges = pRanges;
+}
+
+// ScPaintHint was moved to hints.cxx
+
+/**
+ * Adapt Views when inserting/deleting a table
+ */
+ScTablesHint::ScTablesHint(sal_uInt16 nNewId, SCTAB nTable1, SCTAB nTable2) :
+ nId( nNewId ),
+ nTab1( nTable1 ),
+ nTab2( nTable2 )
+{
+}
+
+ScTablesHint::~ScTablesHint()
+{
+}
+
+ScIndexHint::ScIndexHint(SfxHintId nNewId, sal_uInt16 nIdx) :
+ SfxHint( nNewId ),
+ nIndex( nIdx )
+{
+}
+
+ScIndexHint::~ScIndexHint()
+{
+}
+
+/**
+ * Create new EditView for Cursorposition
+ */
+ScEditViewHint::ScEditViewHint( ScEditEngineDefaulter* pEngine, const ScAddress& rCurPos ) :
+ pEditEngine( pEngine ),
+ aCursorPos( rCurPos )
+{
+}
+
+ScEditViewHint::~ScEditViewHint()
+{
+}
+
+/**
+ * Data for the sorting dialog
+ */
+ScSortItem::ScSortItem( sal_uInt16 nWhichP,
+ ScViewData* ptrViewData,
+ const ScSortParam* pSortData ) :
+ SfxPoolItem ( nWhichP ),
+ pViewData ( ptrViewData )
+{
+ if ( pSortData ) theSortData = *pSortData;
+}
+
+ScSortItem::ScSortItem( sal_uInt16 nWhichP,
+ const ScSortParam* pSortData ) :
+ SfxPoolItem ( nWhichP ),
+ pViewData ( nullptr )
+{
+ if ( pSortData ) theSortData = *pSortData;
+}
+
+bool ScSortItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScSortItem& rOther = static_cast<const ScSortItem&>(rItem);
+
+ return ( (pViewData == rOther.pViewData)
+ && (theSortData == rOther.theSortData) );
+}
+
+ScSortItem* ScSortItem::Clone( SfxItemPool * ) const
+{
+ return new ScSortItem( *this );
+}
+
+bool ScSortItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /* nMemberUd */ ) const
+{
+ // Return empty value as there is no useful conversion
+ rVal = css::uno::Any();
+ return true;
+}
+
+/**
+ * Data for the Filter dialog
+ */
+ScQueryItem::ScQueryItem( sal_uInt16 nWhichP,
+ ScViewData* ptrViewData,
+ const ScQueryParam* pQueryData ) :
+ SfxPoolItem ( nWhichP ),
+ pViewData ( ptrViewData ),
+ bIsAdvanced ( false )
+{
+ if (pQueryData)
+ mpQueryData.reset(new ScQueryParam(*pQueryData));
+ else
+ mpQueryData.reset(new ScQueryParam);
+}
+
+ScQueryItem::ScQueryItem( sal_uInt16 nWhichP,
+ const ScQueryParam* pQueryData ) :
+ SfxPoolItem ( nWhichP ),
+ pViewData ( nullptr ),
+ bIsAdvanced ( false )
+{
+ if (pQueryData)
+ mpQueryData.reset(new ScQueryParam(*pQueryData));
+ else
+ mpQueryData.reset(new ScQueryParam);
+}
+
+ScQueryItem::ScQueryItem( const ScQueryItem& rItem ) :
+ SfxPoolItem ( rItem ),
+ mpQueryData(new ScQueryParam(*rItem.mpQueryData)),
+ pViewData ( rItem.pViewData ),
+ aAdvSource ( rItem.aAdvSource ),
+ bIsAdvanced ( rItem.bIsAdvanced )
+{
+}
+
+ScQueryItem::~ScQueryItem()
+{
+}
+
+void ScQueryItem::SetAdvancedQuerySource(const ScRange* pSource)
+{
+ if (pSource)
+ {
+ aAdvSource = *pSource;
+ bIsAdvanced = true;
+ }
+ else
+ bIsAdvanced = false;
+}
+
+const ScQueryParam& ScQueryItem::GetQueryData() const
+{
+ return *mpQueryData;
+}
+
+bool ScQueryItem::GetAdvancedQuerySource(ScRange& rSource) const
+{
+ rSource = aAdvSource;
+ return bIsAdvanced;
+}
+
+bool ScQueryItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScQueryItem& rQueryItem = static_cast<const ScQueryItem&>(rItem);
+
+ return ( (pViewData == rQueryItem.pViewData)
+ && (bIsAdvanced == rQueryItem.bIsAdvanced)
+ && (aAdvSource == rQueryItem.aAdvSource)
+ && (*mpQueryData == *rQueryItem.mpQueryData) );
+}
+
+ScQueryItem* ScQueryItem::Clone( SfxItemPool * ) const
+{
+ return new ScQueryItem( *this );
+}
+
+/**
+ * Data for the SubTotal dialog
+ */
+ScSubTotalItem::ScSubTotalItem( sal_uInt16 nWhichP,
+ ScViewData* ptrViewData,
+ const ScSubTotalParam* pSubTotalData ) :
+ SfxPoolItem ( nWhichP ),
+ pViewData ( ptrViewData )
+{
+ if ( pSubTotalData ) theSubTotalData = *pSubTotalData;
+}
+
+bool ScSubTotalItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScSubTotalItem& rSTItem = static_cast<const ScSubTotalItem&>(rItem);
+
+ return ( (pViewData == rSTItem.pViewData)
+ && (theSubTotalData == rSTItem.theSubTotalData) );
+}
+
+ScSubTotalItem* ScSubTotalItem::Clone( SfxItemPool * ) const
+{
+ return new ScSubTotalItem( *this );
+}
+
+bool ScSubTotalItem::QueryValue( css::uno::Any& rVal, sal_uInt8 /* nMemberUd */ ) const
+{
+ // Return empty value as there is no useful conversion
+ rVal = css::uno::Any();
+ return true;
+}
+
+/**
+ * Transporter for the UserLIst dialog
+ */
+ScUserListItem::ScUserListItem( sal_uInt16 nWhichP )
+ : SfxPoolItem ( nWhichP )
+{
+}
+
+ScUserListItem::ScUserListItem( const ScUserListItem& rItem )
+ : SfxPoolItem ( rItem )
+{
+ if ( rItem.pUserList )
+ pUserList.reset( new ScUserList( *(rItem.pUserList) ) );
+}
+
+ScUserListItem::~ScUserListItem()
+{
+}
+
+bool ScUserListItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScUserListItem& r = static_cast<const ScUserListItem&>(rItem);
+ bool bEqual = false;
+
+ if ( !pUserList || !r.pUserList )
+ bEqual = ( !pUserList && !r.pUserList );
+ else
+ bEqual = ( *pUserList == *(r.pUserList) );
+
+ return bEqual;
+}
+
+ScUserListItem* ScUserListItem::Clone( SfxItemPool * ) const
+{
+ return new ScUserListItem( *this );
+}
+
+void ScUserListItem::SetUserList( const ScUserList& rUserList )
+{
+ pUserList.reset( new ScUserList( rUserList ) );
+}
+
+/**
+ * Data for the Consolidate dialog
+ */
+ScConsolidateItem::ScConsolidateItem(
+ sal_uInt16 nWhichP,
+ const ScConsolidateParam* pConsolidateData ) :
+ SfxPoolItem ( nWhichP )
+{
+ if ( pConsolidateData ) theConsData = *pConsolidateData;
+}
+
+bool ScConsolidateItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScConsolidateItem& rCItem = static_cast<const ScConsolidateItem&>(rItem);
+
+ return ( theConsData == rCItem.theConsData);
+}
+
+ScConsolidateItem* ScConsolidateItem::Clone( SfxItemPool * ) const
+{
+ return new ScConsolidateItem( *this );
+}
+
+/**
+ * Data for the Pivot dialog
+ */
+ScPivotItem::ScPivotItem( sal_uInt16 nWhichP, const ScDPSaveData* pData,
+ const ScRange* pRange, bool bNew ) :
+ SfxPoolItem ( nWhichP )
+{
+ // pSaveData must always exist
+ if ( pData )
+ pSaveData.reset( new ScDPSaveData(*pData) );
+ else
+ pSaveData.reset( new ScDPSaveData );
+ if ( pRange ) aDestRange = *pRange;
+ bNewSheet = bNew;
+}
+
+ScPivotItem::ScPivotItem( const ScPivotItem& rItem ) :
+ SfxPoolItem ( rItem ),
+ aDestRange ( rItem.aDestRange ),
+ bNewSheet ( rItem.bNewSheet )
+{
+ assert(rItem.pSaveData && "pSaveData");
+ pSaveData.reset( new ScDPSaveData(*rItem.pSaveData) );
+}
+
+ScPivotItem::~ScPivotItem()
+{
+}
+
+bool ScPivotItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScPivotItem& rPItem = static_cast<const ScPivotItem&>(rItem);
+ OSL_ENSURE( pSaveData && rPItem.pSaveData, "pSaveData" );
+ return ( *pSaveData == *rPItem.pSaveData &&
+ aDestRange == rPItem.aDestRange &&
+ bNewSheet == rPItem.bNewSheet );
+}
+
+ScPivotItem* ScPivotItem::Clone( SfxItemPool * ) const
+{
+ return new ScPivotItem( *this );
+}
+
+/**
+ * Data for the Solver dialog
+ */
+ScSolveItem::ScSolveItem( sal_uInt16 nWhichP,
+ const ScSolveParam* pSolveData )
+ : SfxPoolItem ( nWhichP )
+{
+ if ( pSolveData ) theSolveData = *pSolveData;
+}
+
+bool ScSolveItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScSolveItem& rPItem = static_cast<const ScSolveItem&>(rItem);
+
+ return ( theSolveData == rPItem.theSolveData );
+}
+
+ScSolveItem* ScSolveItem::Clone( SfxItemPool * ) const
+{
+ return new ScSolveItem( *this );
+}
+
+/**
+ * Data for the TabOp dialog
+ */
+ScTabOpItem::ScTabOpItem( sal_uInt16 nWhichP,
+ const ScTabOpParam* pTabOpData )
+ : SfxPoolItem ( nWhichP )
+{
+ if ( pTabOpData ) theTabOpData = *pTabOpData;
+}
+
+bool ScTabOpItem::operator==( const SfxPoolItem& rItem ) const
+{
+ assert(SfxPoolItem::operator==(rItem));
+
+ const ScTabOpItem& rPItem = static_cast<const ScTabOpItem&>(rItem);
+
+ return ( theTabOpData == rPItem.theTabOpData );
+}
+
+ScTabOpItem* ScTabOpItem::Clone( SfxItemPool * ) const
+{
+ return new ScTabOpItem( *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/attrdlg/attrdlg.cxx b/sc/source/ui/attrdlg/attrdlg.cxx
new file mode 100644
index 000000000..734ae94d6
--- /dev/null
+++ b/sc/source/ui/attrdlg/attrdlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <sfx2/objsh.hxx>
+#include <sfx2/tabdlg.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <svl/cjkoptions.hxx>
+
+#include <tabpages.hxx>
+#include <attrdlg.hxx>
+#include <svx/dialogs.hrc>
+#include <editeng/editids.hrc>
+#include <editeng/flstitem.hxx>
+#include <osl/diagnose.h>
+
+ScAttrDlg::ScAttrDlg(weld::Window* pParent, const SfxItemSet* pCellAttrs)
+ : SfxTabDialogController(pParent, "modules/scalc/ui/formatcellsdialog.ui",
+ "FormatCellsDialog", pCellAttrs)
+{
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+
+ OSL_ENSURE(pFact->GetTabPageCreatorFunc( RID_SVXPAGE_NUMBERFORMAT ), "GetTabPageCreatorFunc fail!");
+ AddTabPage( "numbers", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_NUMBERFORMAT ), nullptr );
+ OSL_ENSURE(pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_NAME ), "GetTabPageCreatorFunc fail!");
+ AddTabPage( "font", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_NAME ), nullptr );
+ OSL_ENSURE(pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_EFFECTS ), "GetTabPageCreatorFunc fail!");
+ AddTabPage( "fonteffects", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_EFFECTS ), nullptr );
+ OSL_ENSURE(pFact->GetTabPageCreatorFunc( RID_SVXPAGE_ALIGNMENT ), "GetTabPageCreatorFunc fail!");
+ AddTabPage( "alignment", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_ALIGNMENT ), nullptr );
+
+ if (SvtCJKOptions::IsAsianTypographyEnabled())
+ {
+ OSL_ENSURE(pFact->GetTabPageCreatorFunc(RID_SVXPAGE_PARA_ASIAN), "GetTabPageCreatorFunc fail!");
+ AddTabPage( "asiantypography", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_PARA_ASIAN), nullptr );
+ }
+ else
+ RemoveTabPage( "asiantypography" );
+ OSL_ENSURE(pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), "GetTabPageCreatorFunc fail!");
+ AddTabPage( "borders", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), nullptr );
+ OSL_ENSURE(pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BKG ), "GetTabPageCreatorFunc fail!");
+ AddTabPage( "background", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BKG ), nullptr );
+ AddTabPage( "cellprotection" , ScTabPageProtection::Create, nullptr );
+}
+
+ScAttrDlg::~ScAttrDlg()
+{
+}
+
+void ScAttrDlg::PageCreated(const OString& rPageId, SfxTabPage& rTabPage)
+{
+ SfxObjectShell* pDocSh = SfxObjectShell::Current();
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ if (rPageId == "numbers")
+ {
+ rTabPage.PageCreated(aSet);
+ }
+ else if (rPageId == "font" && pDocSh)
+ {
+ const SfxPoolItem* pInfoItem = pDocSh->GetItem( SID_ATTR_CHAR_FONTLIST );
+ assert(pInfoItem && "FontListItem not found :-(");
+ aSet.Put (SvxFontListItem(static_cast<const SvxFontListItem*>(pInfoItem)->GetFontList(), SID_ATTR_CHAR_FONTLIST ));
+ rTabPage.PageCreated(aSet);
+ }
+ else if (rPageId == "background")
+ {
+ rTabPage.PageCreated(aSet);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/attrdlg/scabstdlg.cxx b/sc/source/ui/attrdlg/scabstdlg.cxx
new file mode 100644
index 000000000..a8a457c5c
--- /dev/null
+++ b/sc/source/ui/attrdlg/scabstdlg.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 <scabstdlg.hxx>
+
+#include <osl/module.hxx>
+#include <tools/svlibrary.h>
+
+typedef ScAbstractDialogFactory* (*ScFuncPtrCreateDialogFactory)();
+
+#ifndef DISABLE_DYNLOADING
+
+extern "C" { static void thisModule() {} }
+
+#else
+
+extern "C" ScAbstractDialogFactory* ScCreateDialogFactory();
+
+#endif
+
+ScAbstractDialogFactory* ScAbstractDialogFactory::Create()
+{
+ ScFuncPtrCreateDialogFactory fp = nullptr;
+#ifndef DISABLE_DYNLOADING
+ static ::osl::Module aDialogLibrary;
+
+ if ( aDialogLibrary.is() || aDialogLibrary.loadRelative( &thisModule, SVLIBRARY("scui"),
+ SAL_LOADMODULE_GLOBAL | SAL_LOADMODULE_LAZY ) )
+ fp = reinterpret_cast<ScAbstractDialogFactory* (SAL_CALL*)()>(
+ aDialogLibrary.getFunctionSymbol( "ScCreateDialogFactory" ));
+#else
+ fp = ScCreateDialogFactory;
+#endif
+ if ( fp )
+ return fp();
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/attrdlg/scdlgfact.cxx b/sc/source/ui/attrdlg/scdlgfact.cxx
new file mode 100644
index 000000000..8b59e672c
--- /dev/null
+++ b/sc/source/ui/attrdlg/scdlgfact.cxx
@@ -0,0 +1,1370 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include "scdlgfact.hxx"
+
+#include <scuiasciiopt.hxx>
+#include <scuiautofmt.hxx>
+#include <corodlg.hxx>
+#include <dapidata.hxx>
+#include <dapitype.hxx>
+#include <delcldlg.hxx>
+#include <delcodlg.hxx>
+#include <filldlg.hxx>
+#include <groupdlg.hxx>
+#include <inscldlg.hxx>
+#include <inscodlg.hxx>
+#include <instbdlg.hxx>
+#include <lbseldlg.hxx>
+#include <linkarea.hxx>
+#include <mtrindlg.hxx>
+#include <mvtabdlg.hxx>
+#include <namecrea.hxx>
+#include <namepast.hxx>
+#include <pfiltdlg.hxx>
+#include <pvfundlg.hxx>
+#include <dpgroupdlg.hxx>
+#include <scendlg.hxx>
+#include <shtabdlg.hxx>
+#include <strindlg.hxx>
+#include <tabbgcolordlg.hxx>
+#include <scuiimoptdlg.hxx>
+#include <attrdlg.hxx>
+#include <hfedtdlg.hxx>
+#include <styledlg.hxx>
+#include <subtdlg.hxx>
+#include <textdlgs.hxx>
+#include <sortdlg.hxx>
+#include <textimportoptions.hxx>
+#include <opredlin.hxx>
+#include <tpcalc.hxx>
+#include <tpprint.hxx>
+#include <tpstat.hxx>
+#include <tpusrlst.hxx>
+#include <tpview.hxx>
+#include <tpformula.hxx>
+#include <datafdlg.hxx>
+#include <tpcompatibility.hxx>
+#include <tpdefaults.hxx>
+#include <condformatmgr.hxx>
+#include <scres.hrc>
+#include <svx/dialogs.hrc>
+#include <sfx2/sfxdlg.hxx>
+#include <conditio.hxx>
+
+#include <vcl/virdev.hxx>
+
+short AbstractScImportAsciiDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractScImportAsciiDlg_Impl::StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+short AbstractScAutoFormatDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScColRowLabelDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScCondFormatManagerDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractScCondFormatManagerDlg_Impl::StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+short AbstractScDataPilotDatabaseDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractScDataPilotDatabaseDlg_Impl::StartExecuteAsync(AsyncContext &rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+short AbstractScDataPilotSourceTypeDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractScDataPilotSourceTypeDlg_Impl::StartExecuteAsync(AsyncContext &rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+short AbstractScDataPilotServiceDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractScDataPilotServiceDlg_Impl::StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+short AbstractScDeleteCellDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+//for dataform
+short AbstractScDataFormDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+BitmapEx AbstractScDataFormDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScDataFormDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+short AbstractScDeleteContentsDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScFillSeriesDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScGroupDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScInsertCellDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScInsertContentsDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScInsertTableDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScSelEntryDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScMetricInputDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScMoveTableDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+BitmapEx AbstractScMoveTableDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScMoveTableDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+short AbstractScNameCreateDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScNamePasteDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScPivotFilterDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScDPFunctionDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractScDPFunctionDlg_Impl::StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+short AbstractScDPSubtotalDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractScDPSubtotalDlg_Impl::StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+short AbstractScDPNumGroupDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScDPDateGroupDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScDPShowDetailDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScNewScenarioDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScShowTabDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractScShowTabDlg_Impl::StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+short AbstractScGoToTabDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool AbstractScGoToTabDlg_Impl::StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+short AbstractScSortWarningDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScTabBgColorDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScImportOptionsDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+short AbstractScTextImportOptionsDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+AbstractScLinkedAreaDlg_Impl::~AbstractScLinkedAreaDlg_Impl()
+{
+}
+
+short AbstractScLinkedAreaDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+void AbstractScImportAsciiDlg_Impl::GetOptions( ScAsciiOptions& rOpt )
+{
+ m_xDlg->GetOptions( rOpt );
+}
+
+void AbstractScImportAsciiDlg_Impl::SaveParameters()
+{
+ m_xDlg->SaveParameters();
+}
+
+BitmapEx AbstractScImportAsciiDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScImportAsciiDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+sal_uInt16 AbstractScAutoFormatDlg_Impl::GetIndex() const
+{
+ return m_xDlg->GetIndex();
+}
+
+OUString AbstractScAutoFormatDlg_Impl::GetCurrFormatName()
+{
+ return m_xDlg->GetCurrFormatName();
+}
+
+bool AbstractScColRowLabelDlg_Impl::IsCol()
+{
+ return m_xDlg->IsCol();
+}
+
+bool AbstractScColRowLabelDlg_Impl::IsRow()
+{
+ return m_xDlg->IsRow();
+}
+
+BitmapEx AbstractScColRowLabelDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScColRowLabelDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractScDataPilotDatabaseDlg_Impl::GetValues( ScImportSourceDesc& rDesc )
+{
+ m_xDlg->GetValues(rDesc);
+}
+
+BitmapEx AbstractScDataPilotDatabaseDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScDataPilotDatabaseDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+bool AbstractScDataPilotSourceTypeDlg_Impl::IsDatabase() const
+{
+ return m_xDlg->IsDatabase();
+}
+
+bool AbstractScDataPilotSourceTypeDlg_Impl::IsExternal() const
+{
+ return m_xDlg->IsExternal();
+}
+
+bool AbstractScDataPilotSourceTypeDlg_Impl::IsNamedRange() const
+{
+ return m_xDlg->IsNamedRange();
+}
+
+OUString AbstractScDataPilotSourceTypeDlg_Impl::GetSelectedNamedRange() const
+{
+ return m_xDlg->GetSelectedNamedRange();
+}
+
+void AbstractScDataPilotSourceTypeDlg_Impl::AppendNamedRange(const OUString& rName)
+{
+ m_xDlg->AppendNamedRange(rName);
+}
+
+BitmapEx AbstractScDataPilotSourceTypeDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScDataPilotSourceTypeDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+OUString AbstractScDataPilotServiceDlg_Impl::GetServiceName() const
+{
+ return m_xDlg->GetServiceName();
+}
+
+OUString AbstractScDataPilotServiceDlg_Impl::GetParSource() const
+{
+ return m_xDlg->GetParSource();
+}
+
+OUString AbstractScDataPilotServiceDlg_Impl::GetParName() const
+{
+ return m_xDlg->GetParName();
+}
+
+OUString AbstractScDataPilotServiceDlg_Impl::GetParUser() const
+{
+ return m_xDlg->GetParUser();
+}
+
+OUString AbstractScDataPilotServiceDlg_Impl::GetParPass() const
+{
+ return m_xDlg->GetParPass();
+}
+
+DelCellCmd AbstractScDeleteCellDlg_Impl::GetDelCellCmd() const
+{
+ return m_xDlg->GetDelCellCmd();
+}
+
+BitmapEx AbstractScDeleteCellDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScDeleteCellDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractScDeleteContentsDlg_Impl::DisableObjects()
+{
+ m_xDlg->DisableObjects();
+}
+
+InsertDeleteFlags AbstractScDeleteContentsDlg_Impl::GetDelContentsCmdBits() const
+{
+ return m_xDlg->GetDelContentsCmdBits();
+}
+
+BitmapEx AbstractScDeleteContentsDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScDeleteContentsDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+FillDir AbstractScFillSeriesDlg_Impl::GetFillDir() const
+{
+ return m_xDlg->GetFillDir();
+}
+
+FillCmd AbstractScFillSeriesDlg_Impl::GetFillCmd() const
+{
+ return m_xDlg->GetFillCmd();
+}
+
+FillDateCmd AbstractScFillSeriesDlg_Impl::GetFillDateCmd() const
+{
+ return m_xDlg->GetFillDateCmd();
+}
+
+double AbstractScFillSeriesDlg_Impl::GetStart() const
+{
+ return m_xDlg->GetStart();
+}
+
+double AbstractScFillSeriesDlg_Impl::GetStep() const
+{
+ return m_xDlg->GetStep();
+}
+
+double AbstractScFillSeriesDlg_Impl::GetMax() const
+{
+ return m_xDlg->GetMax();
+}
+
+OUString AbstractScFillSeriesDlg_Impl::GetStartStr() const
+{
+ return m_xDlg->GetStartStr();
+}
+
+void AbstractScFillSeriesDlg_Impl::SetEdStartValEnabled(bool bFlag)
+{
+ m_xDlg->SetEdStartValEnabled(bFlag);
+}
+
+bool AbstractScGroupDlg_Impl::StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx)
+{
+ return weld::DialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+bool AbstractScGroupDlg_Impl::GetColsChecked() const
+{
+ return m_xDlg->GetColsChecked();
+}
+
+InsCellCmd AbstractScInsertCellDlg_Impl::GetInsCellCmd() const
+{
+ return m_xDlg->GetInsCellCmd();
+}
+
+InsertDeleteFlags AbstractScInsertContentsDlg_Impl::GetInsContentsCmdBits() const
+{
+ return m_xDlg->GetInsContentsCmdBits();
+}
+
+ScPasteFunc AbstractScInsertContentsDlg_Impl::GetFormulaCmdBits() const
+{
+ return m_xDlg->GetFormulaCmdBits();
+}
+
+bool AbstractScInsertContentsDlg_Impl::IsSkipEmptyCells() const
+{
+ return m_xDlg->IsSkipEmptyCells();
+}
+
+bool AbstractScInsertContentsDlg_Impl::IsLink() const
+{
+ return m_xDlg->IsLink();
+}
+
+void AbstractScInsertContentsDlg_Impl::SetFillMode( bool bSet )
+{
+ m_xDlg->SetFillMode( bSet );
+}
+
+void AbstractScInsertContentsDlg_Impl::SetOtherDoc( bool bSet )
+{
+ m_xDlg->SetOtherDoc( bSet );
+}
+
+bool AbstractScInsertContentsDlg_Impl::IsTranspose() const
+{
+ return m_xDlg->IsTranspose();
+}
+
+void AbstractScInsertContentsDlg_Impl::SetChangeTrack( bool bSet )
+{
+ m_xDlg->SetChangeTrack( bSet );
+}
+
+void AbstractScInsertContentsDlg_Impl::SetCellShiftDisabled( CellShiftDisabledFlags nDisable )
+{
+ m_xDlg->SetCellShiftDisabled( nDisable );
+}
+
+InsCellCmd AbstractScInsertContentsDlg_Impl::GetMoveMode()
+{
+ return m_xDlg->GetMoveMode();
+}
+
+BitmapEx AbstractScInsertContentsDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScInsertContentsDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+bool AbstractScInsertTableDlg_Impl::GetTablesFromFile()
+{
+ return m_xDlg->GetTablesFromFile();
+}
+
+bool AbstractScInsertTableDlg_Impl::GetTablesAsLink()
+{
+ return m_xDlg->GetTablesAsLink();
+}
+
+const OUString* AbstractScInsertTableDlg_Impl::GetFirstTable( sal_uInt16* pN )
+{
+ return m_xDlg->GetFirstTable( pN );
+}
+
+ScDocShell* AbstractScInsertTableDlg_Impl::GetDocShellTables()
+{
+ return m_xDlg->GetDocShellTables();
+}
+
+bool AbstractScInsertTableDlg_Impl::IsTableBefore()
+{
+ return m_xDlg->IsTableBefore();
+}
+
+sal_uInt16 AbstractScInsertTableDlg_Impl::GetTableCount()
+{
+ return m_xDlg->GetTableCount();
+}
+
+const OUString* AbstractScInsertTableDlg_Impl::GetNextTable( sal_uInt16* pN )
+{
+ return m_xDlg->GetNextTable( pN );
+}
+
+BitmapEx AbstractScInsertTableDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScInsertTableDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+OUString AbstractScSelEntryDlg_Impl::GetSelectedEntry() const
+{
+ return m_xDlg->GetSelectedEntry();
+}
+
+void AbstractScLinkedAreaDlg_Impl::InitFromOldLink( const OUString& rFile, const OUString& rFilter,
+ const OUString& rOptions, const OUString& rSource,
+ sal_Int32 nRefreshDelaySeconds )
+{
+ m_xDlg->InitFromOldLink( rFile, rFilter, rOptions, rSource, nRefreshDelaySeconds);
+}
+
+OUString AbstractScLinkedAreaDlg_Impl::GetURL()
+{
+ return m_xDlg->GetURL();
+}
+
+OUString AbstractScLinkedAreaDlg_Impl::GetFilter()
+{
+ return m_xDlg->GetFilter();
+}
+
+OUString AbstractScLinkedAreaDlg_Impl::GetOptions()
+{
+ return m_xDlg->GetOptions();
+}
+
+OUString AbstractScLinkedAreaDlg_Impl::GetSource()
+{
+ return m_xDlg->GetSource();
+}
+
+sal_Int32 AbstractScLinkedAreaDlg_Impl::GetRefreshDelaySeconds()
+{
+ return m_xDlg->GetRefreshDelaySeconds();
+}
+
+std::unique_ptr<ScConditionalFormatList> AbstractScCondFormatManagerDlg_Impl::GetConditionalFormatList()
+{
+ return m_xDlg->GetConditionalFormatList();
+}
+
+bool AbstractScCondFormatManagerDlg_Impl::CondFormatsChanged() const
+{
+ return m_xDlg->CondFormatsChanged();
+}
+
+void AbstractScCondFormatManagerDlg_Impl::SetModified()
+{
+ return m_xDlg->SetModified();
+}
+
+ScConditionalFormat* AbstractScCondFormatManagerDlg_Impl::GetCondFormatSelected()
+{
+ return m_xDlg->GetCondFormatSelected();
+}
+
+int AbstractScMetricInputDlg_Impl::GetInputValue() const
+{
+ return m_xDlg->GetInputValue();
+}
+
+sal_uInt16 AbstractScMoveTableDlg_Impl::GetSelectedDocument() const
+{
+ return m_xDlg->GetSelectedDocument();
+}
+
+sal_uInt16 AbstractScMoveTableDlg_Impl::GetSelectedTable() const
+{
+ return m_xDlg->GetSelectedTable();
+}
+
+bool AbstractScMoveTableDlg_Impl::GetCopyTable() const
+{
+ return m_xDlg->GetCopyTable();
+}
+
+bool AbstractScMoveTableDlg_Impl::GetRenameTable() const
+{
+ return m_xDlg->GetRenameTable();
+}
+
+void AbstractScMoveTableDlg_Impl::GetTabNameString( OUString& rString ) const
+{
+ m_xDlg->GetTabNameString( rString );
+}
+
+void AbstractScMoveTableDlg_Impl::SetForceCopyTable()
+{
+ return m_xDlg->SetForceCopyTable();
+}
+
+void AbstractScMoveTableDlg_Impl::EnableRenameTable(bool bFlag)
+{
+ return m_xDlg->EnableRenameTable( bFlag);
+}
+
+CreateNameFlags AbstractScNameCreateDlg_Impl::GetFlags() const
+{
+ return m_xDlg->GetFlags();
+}
+
+BitmapEx AbstractScNameCreateDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScNameCreateDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+std::vector<OUString> AbstractScNamePasteDlg_Impl::GetSelectedNames() const
+{
+ return m_xDlg->GetSelectedNames();
+}
+
+const ScQueryItem& AbstractScPivotFilterDlg_Impl::GetOutputItem()
+{
+ return m_xDlg->GetOutputItem();
+}
+
+PivotFunc AbstractScDPFunctionDlg_Impl::GetFuncMask() const
+{
+ return m_xDlg->GetFuncMask();
+}
+
+void AbstractScDPFunctionDlg_Impl::Response(int nResponse)
+{
+ m_xDlg->response(nResponse);
+}
+
+css::sheet::DataPilotFieldReference AbstractScDPFunctionDlg_Impl::GetFieldRef() const
+{
+ return m_xDlg->GetFieldRef();
+}
+
+PivotFunc AbstractScDPSubtotalDlg_Impl::GetFuncMask() const
+{
+ return m_xDlg->GetFuncMask();
+}
+
+void AbstractScDPSubtotalDlg_Impl::FillLabelData( ScDPLabelData& rLabelData ) const
+{
+ m_xDlg->FillLabelData( rLabelData );
+}
+
+void AbstractScDPSubtotalDlg_Impl::Response(int nResponse)
+{
+ m_xDlg->response(nResponse);
+}
+
+ScDPNumGroupInfo AbstractScDPNumGroupDlg_Impl::GetGroupInfo() const
+{
+ return m_xDlg->GetGroupInfo();
+}
+
+ScDPNumGroupInfo AbstractScDPDateGroupDlg_Impl::GetGroupInfo() const
+{
+ return m_xDlg->GetGroupInfo();
+}
+
+sal_Int32 AbstractScDPDateGroupDlg_Impl::GetDatePart() const
+{
+ return m_xDlg->GetDatePart();
+}
+
+OUString AbstractScDPShowDetailDlg_Impl::GetDimensionName() const
+{
+ return m_xDlg->GetDimensionName();
+}
+
+void AbstractScNewScenarioDlg_Impl::SetScenarioData(
+ const OUString& rName, const OUString& rComment, const Color& rColor, ScScenarioFlags nFlags )
+{
+ m_xDlg->SetScenarioData(rName, rComment, rColor, nFlags);
+}
+
+void AbstractScNewScenarioDlg_Impl::GetScenarioData(
+ OUString& rName, OUString& rComment, Color& rColor, ScScenarioFlags& rFlags ) const
+{
+ m_xDlg->GetScenarioData(rName, rComment, rColor, rFlags);
+}
+
+void AbstractScShowTabDlg_Impl::Insert( const OUString& rString, bool bSelected )
+{
+ m_xDlg->Insert(rString, bSelected);
+}
+
+void AbstractScShowTabDlg_Impl::SetDescription(
+ const OUString& rTitle, const OUString& rFixedText,
+ const OString& sDlgHelpId, const OString& sLbHelpId )
+{
+ m_xDlg->SetDescription( rTitle, rFixedText, sDlgHelpId, sLbHelpId );
+}
+
+std::vector<sal_Int32> AbstractScShowTabDlg_Impl::GetSelectedRows() const
+{
+ return m_xDlg->GetSelectedRows();
+}
+
+OUString AbstractScShowTabDlg_Impl::GetEntry(sal_Int32 nPos) const
+{
+ return m_xDlg->GetEntry(nPos);
+}
+
+void AbstractScGoToTabDlg_Impl::Insert( const OUString& rString, bool bSelected )
+{
+ m_xDlg->Insert(rString, bSelected);
+}
+
+void AbstractScGoToTabDlg_Impl::SetDescription(
+ const OUString& rTitle, const OUString& rEntryLabel, const OUString& rListLabel,
+ const OString& rDlgHelpId, const OString& rEnHelpId, const OString& rLbHelpId )
+{
+ m_xDlg->SetDescription( rTitle, rEntryLabel, rListLabel, rDlgHelpId, rEnHelpId, rLbHelpId );
+}
+
+OUString AbstractScGoToTabDlg_Impl::GetSelectedEntry() const
+{
+ return m_xDlg->GetSelectedEntry();
+}
+
+short AbstractScStringInputDlg_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+OUString AbstractScStringInputDlg_Impl::GetInputString() const
+{
+ return m_xDlg->GetInputString();
+}
+
+BitmapEx AbstractScStringInputDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScStringInputDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractScTabBgColorDlg_Impl::GetSelectedColor( Color& rColor ) const
+{
+ m_xDlg->GetSelectedColor( rColor );
+}
+
+BitmapEx AbstractScTabBgColorDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScTabBgColorDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+void AbstractScImportOptionsDlg_Impl::GetImportOptions( ScImportOptions& rOptions ) const
+{
+ m_xDlg->GetImportOptions(rOptions);
+}
+
+void AbstractScImportOptionsDlg_Impl::SaveImportOptions() const
+{
+ m_xDlg->SaveImportOptions();
+}
+
+LanguageType AbstractScTextImportOptionsDlg_Impl::GetLanguageType() const
+{
+ return m_xDlg->getLanguageType();
+}
+
+bool AbstractScTextImportOptionsDlg_Impl::IsDateConversionSet() const
+{
+ return m_xDlg->isDateConversionSet();
+}
+
+bool AbstractScTextImportOptionsDlg_Impl::IsKeepAskingSet() const
+{
+ return m_xDlg->isKeepAskingSet();
+}
+
+BitmapEx AbstractScTextImportOptionsDlg_Impl::createScreenshot() const
+{
+ VclPtr<VirtualDevice> xDialogSurface(m_xDlg->getDialog()->screenshot());
+ return xDialogSurface->GetBitmapEx(Point(), xDialogSurface->GetOutputSizePixel());
+}
+
+OString AbstractScTextImportOptionsDlg_Impl::GetScreenshotId() const
+{
+ return m_xDlg->get_help_id();
+}
+
+short ScAbstractTabController_Impl::Execute()
+{
+ return m_xDlg->run();
+}
+
+bool ScAbstractTabController_Impl::StartExecuteAsync(AsyncContext &rCtx)
+{
+ return SfxTabDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+void ScAbstractTabController_Impl::SetCurPageId( const OString &rName )
+{
+ m_xDlg->SetCurPageId( rName );
+}
+
+const SfxItemSet* ScAbstractTabController_Impl::GetOutputItemSet() const
+{
+ return m_xDlg->GetOutputItemSet();
+}
+
+WhichRangesContainer ScAbstractTabController_Impl::GetInputRanges(const SfxItemPool& pItem )
+{
+ return m_xDlg->GetInputRanges( pItem );
+}
+
+void ScAbstractTabController_Impl::SetInputSet( const SfxItemSet* pInSet )
+{
+ m_xDlg->SetInputSet( pInSet );
+}
+
+//From class Window.
+void ScAbstractTabController_Impl::SetText( const OUString& rStr )
+{
+ m_xDlg->set_title(rStr);
+}
+
+std::vector<OString> ScAbstractTabController_Impl::getAllPageUIXMLDescriptions() const
+{
+ return m_xDlg->getAllPageUIXMLDescriptions();
+}
+
+bool ScAbstractTabController_Impl::selectPageByUIXMLDescription(const OString& rUIXMLDescription)
+{
+ return m_xDlg->selectPageByUIXMLDescription(rUIXMLDescription);
+}
+
+BitmapEx ScAbstractTabController_Impl::createScreenshot() const
+{
+ return m_xDlg->createScreenshot();
+}
+
+OString ScAbstractTabController_Impl::GetScreenshotId() const
+{
+ return m_xDlg->GetScreenshotId();
+}
+
+bool ScAsyncTabController_Impl::StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx)
+{
+ return SfxTabDialogController::runAsync(m_xDlg, rCtx.maEndDialogFn);
+}
+
+void ScAsyncTabController_Impl::SetCurPageId( const OString &rName )
+{
+ m_xDlg->SetCurPageId( rName );
+}
+
+const SfxItemSet* ScAsyncTabController_Impl::GetOutputItemSet() const
+{
+ return m_xDlg->GetOutputItemSet();
+}
+
+// =========================Factories for createdialog ===================
+VclPtr<AbstractScImportAsciiDlg> ScAbstractDialogFactory_Impl::CreateScImportAsciiDlg(weld::Window* pParent,
+ const OUString& aDatName,
+ SvStream* pInStream, ScImportAsciiCall eCall)
+{
+ return VclPtr<AbstractScImportAsciiDlg_Impl>::Create(std::make_shared<ScImportAsciiDlg>(pParent, aDatName,pInStream, eCall));
+}
+
+VclPtr<AbstractScTextImportOptionsDlg> ScAbstractDialogFactory_Impl::CreateScTextImportOptionsDlg(weld::Window* pParent)
+{
+ return VclPtr<AbstractScTextImportOptionsDlg_Impl>::Create(std::make_unique<ScTextImportOptionsDlg>(pParent));
+}
+
+VclPtr<AbstractScAutoFormatDlg> ScAbstractDialogFactory_Impl::CreateScAutoFormatDlg(weld::Window* pParent,
+ ScAutoFormat* pAutoFormat,
+ const ScAutoFormatData* pSelFormatData,
+ ScViewData& rViewData)
+{
+ return VclPtr<AbstractScAutoFormatDlg_Impl>::Create(std::make_unique<ScAutoFormatDlg>(pParent, pAutoFormat, pSelFormatData, rViewData));
+}
+
+VclPtr<AbstractScColRowLabelDlg> ScAbstractDialogFactory_Impl::CreateScColRowLabelDlg(weld::Window* pParent,
+ bool bCol, bool bRow)
+{
+ return VclPtr<AbstractScColRowLabelDlg_Impl>::Create(std::make_unique<ScColRowLabelDlg>(pParent, bCol, bRow));
+}
+
+VclPtr<AbstractScSortWarningDlg> ScAbstractDialogFactory_Impl::CreateScSortWarningDlg(weld::Window* pParent, const OUString& rExtendText, const OUString& rCurrentText)
+{
+ return VclPtr<AbstractScSortWarningDlg_Impl>::Create(std::make_unique<ScSortWarningDlg>(pParent, rExtendText, rCurrentText));
+}
+
+VclPtr<AbstractScCondFormatManagerDlg> ScAbstractDialogFactory_Impl::CreateScCondFormatMgrDlg(weld::Window* pParent, ScDocument& rDoc, const ScConditionalFormatList* pFormatList )
+{
+ return VclPtr<AbstractScCondFormatManagerDlg_Impl>::Create(std::make_shared<ScCondFormatManagerDlg>(pParent, rDoc, pFormatList));
+}
+
+VclPtr<AbstractScDataPilotDatabaseDlg> ScAbstractDialogFactory_Impl::CreateScDataPilotDatabaseDlg(weld::Window* pParent)
+{
+ return VclPtr<AbstractScDataPilotDatabaseDlg_Impl>::Create(std::make_shared<ScDataPilotDatabaseDlg>(pParent));
+}
+
+VclPtr<AbstractScDataPilotSourceTypeDlg> ScAbstractDialogFactory_Impl::CreateScDataPilotSourceTypeDlg(
+ weld::Window* pParent, bool bEnableExternal)
+{
+ return VclPtr<AbstractScDataPilotSourceTypeDlg_Impl>::Create(std::make_shared<ScDataPilotSourceTypeDlg>(pParent, bEnableExternal));
+}
+
+VclPtr<AbstractScDataPilotServiceDlg> ScAbstractDialogFactory_Impl::CreateScDataPilotServiceDlg(weld::Window* pParent,
+ const std::vector<OUString>& rServices)
+{
+ return VclPtr<AbstractScDataPilotServiceDlg_Impl>::Create(std::make_shared<ScDataPilotServiceDlg>(pParent, rServices));
+}
+
+VclPtr<AbstractScDeleteCellDlg> ScAbstractDialogFactory_Impl::CreateScDeleteCellDlg(weld::Window* pParent,
+ bool bDisallowCellMove)
+{
+ return VclPtr<AbstractScDeleteCellDlg_Impl>::Create(std::make_unique<ScDeleteCellDlg>(pParent, bDisallowCellMove));
+}
+
+VclPtr<AbstractScDataFormDlg> ScAbstractDialogFactory_Impl::CreateScDataFormDlg(weld::Window* pParent,
+ ScTabViewShell* pTabViewShell)
+{
+ return VclPtr<AbstractScDataFormDlg_Impl>::Create(std::make_unique<ScDataFormDlg>(pParent, pTabViewShell));
+}
+
+VclPtr<AbstractScDeleteContentsDlg> ScAbstractDialogFactory_Impl::CreateScDeleteContentsDlg(weld::Window* pParent)
+{
+ return VclPtr<AbstractScDeleteContentsDlg_Impl>::Create(std::make_unique<ScDeleteContentsDlg>(pParent));
+}
+
+VclPtr<AbstractScFillSeriesDlg> ScAbstractDialogFactory_Impl::CreateScFillSeriesDlg(weld::Window* pParent,
+ ScDocument& rDocument,
+ FillDir eFillDir,
+ FillCmd eFillCmd,
+ FillDateCmd eFillDateCmd,
+ const OUString& aStartStr,
+ double fStep,
+ double fMax,
+ const SCSIZE nSelectHeight,
+ const SCSIZE nSelectWidth,
+ sal_uInt16 nPossDir)
+{
+ return VclPtr<AbstractScFillSeriesDlg_Impl>::Create(std::make_unique<ScFillSeriesDlg>(pParent, rDocument,eFillDir, eFillCmd,eFillDateCmd, aStartStr,fStep,fMax,nSelectHeight,nSelectWidth,nPossDir));
+}
+
+VclPtr<AbstractScGroupDlg> ScAbstractDialogFactory_Impl::CreateAbstractScGroupDlg(weld::Window* pParent, bool bUnGroup)
+{
+ return VclPtr<AbstractScGroupDlg_Impl>::Create(std::make_shared<ScGroupDlg>(pParent, bUnGroup, true/*bRows*/));
+}
+
+VclPtr<AbstractScInsertCellDlg> ScAbstractDialogFactory_Impl::CreateScInsertCellDlg(weld::Window* pParent,
+ bool bDisallowCellMove)
+{
+ return VclPtr<AbstractScInsertCellDlg_Impl>::Create(std::make_unique<ScInsertCellDlg>(pParent, bDisallowCellMove));
+}
+
+VclPtr<AbstractScInsertContentsDlg> ScAbstractDialogFactory_Impl::CreateScInsertContentsDlg(weld::Window* pParent,
+ const OUString* pStrTitle)
+{
+ return VclPtr<AbstractScInsertContentsDlg_Impl>::Create(std::make_unique<ScInsertContentsDlg>(pParent, pStrTitle));
+}
+
+VclPtr<AbstractScInsertTableDlg> ScAbstractDialogFactory_Impl::CreateScInsertTableDlg(weld::Window* pParent, ScViewData& rViewData,
+ SCTAB nTabCount, bool bFromFile)
+{
+ return VclPtr<AbstractScInsertTableDlg_Impl>::Create(std::make_unique<ScInsertTableDlg>(pParent, rViewData,nTabCount, bFromFile));
+}
+
+VclPtr<AbstractScSelEntryDlg> ScAbstractDialogFactory_Impl::CreateScSelEntryDlg(weld::Window* pParent,
+ const std::vector<OUString> &rEntryList)
+{
+ return VclPtr<AbstractScSelEntryDlg_Impl>::Create(std::make_unique<ScSelEntryDlg>(pParent, rEntryList));
+}
+
+VclPtr<AbstractScLinkedAreaDlg> ScAbstractDialogFactory_Impl::CreateScLinkedAreaDlg(weld::Widget* pParent)
+{
+ return VclPtr<AbstractScLinkedAreaDlg_Impl>::Create(std::make_unique<ScLinkedAreaDlg>(pParent));
+}
+
+VclPtr<AbstractScMetricInputDlg> ScAbstractDialogFactory_Impl::CreateScMetricInputDlg(weld::Window* pParent,
+ const OString& sDialogName,
+ tools::Long nCurrent,
+ tools::Long nDefault,
+ FieldUnit eFUnit,
+ sal_uInt16 nDecimals,
+ tools::Long nMaximum ,
+ tools::Long nMinimum )
+{
+ return VclPtr<AbstractScMetricInputDlg_Impl>::Create(std::make_unique<ScMetricInputDlg>(pParent, sDialogName, nCurrent ,nDefault, eFUnit,
+ nDecimals, nMaximum , nMinimum));
+}
+
+VclPtr<AbstractScMoveTableDlg> ScAbstractDialogFactory_Impl::CreateScMoveTableDlg(weld::Window* pParent,
+ const OUString& rDefault)
+{
+ return VclPtr<AbstractScMoveTableDlg_Impl>::Create(std::make_unique<ScMoveTableDlg>(pParent, rDefault));
+}
+
+VclPtr<AbstractScNameCreateDlg> ScAbstractDialogFactory_Impl::CreateScNameCreateDlg(weld::Window * pParent, CreateNameFlags nFlags)
+{
+ return VclPtr<AbstractScNameCreateDlg_Impl>::Create(std::make_unique<ScNameCreateDlg>(pParent, nFlags));
+}
+
+VclPtr<AbstractScNamePasteDlg> ScAbstractDialogFactory_Impl::CreateScNamePasteDlg(weld::Window * pParent, ScDocShell* pShell)
+{
+ return VclPtr<AbstractScNamePasteDlg_Impl>::Create(std::make_unique<ScNamePasteDlg>(pParent, pShell));
+}
+
+VclPtr<AbstractScPivotFilterDlg> ScAbstractDialogFactory_Impl::CreateScPivotFilterDlg(weld::Window* pParent,
+ const SfxItemSet& rArgSet, sal_uInt16 nSourceTab)
+{
+ return VclPtr<AbstractScPivotFilterDlg_Impl>::Create(std::make_unique<ScPivotFilterDlg>(pParent, rArgSet, nSourceTab));
+}
+
+VclPtr<AbstractScDPFunctionDlg> ScAbstractDialogFactory_Impl::CreateScDPFunctionDlg(weld::Widget* pParent,
+ const ScDPLabelDataVector& rLabelVec,
+ const ScDPLabelData& rLabelData,
+ const ScPivotFuncData& rFuncData)
+{
+ return VclPtr<AbstractScDPFunctionDlg_Impl>::Create(std::make_shared<ScDPFunctionDlg>(pParent, rLabelVec, rLabelData, rFuncData));
+}
+
+VclPtr<AbstractScDPSubtotalDlg> ScAbstractDialogFactory_Impl::CreateScDPSubtotalDlg(weld::Widget* pParent,
+ ScDPObject& rDPObj,
+ const ScDPLabelData& rLabelData,
+ const ScPivotFuncData& rFuncData,
+ const ScDPNameVec& rDataFields)
+{
+ return VclPtr<AbstractScDPSubtotalDlg_Impl>::Create(std::make_shared<ScDPSubtotalDlg>(pParent, rDPObj, rLabelData, rFuncData, rDataFields, true/*bEnableLayout*/));
+}
+
+VclPtr<AbstractScDPNumGroupDlg> ScAbstractDialogFactory_Impl::CreateScDPNumGroupDlg(weld::Window* pParent, const ScDPNumGroupInfo& rInfo)
+{
+ return VclPtr<AbstractScDPNumGroupDlg_Impl>::Create(std::make_unique<ScDPNumGroupDlg>(pParent, rInfo));
+}
+
+VclPtr<AbstractScDPDateGroupDlg> ScAbstractDialogFactory_Impl::CreateScDPDateGroupDlg(
+ weld::Window* pParent, const ScDPNumGroupInfo& rInfo, sal_Int32 nDatePart, const Date& rNullDate)
+{
+ return VclPtr<AbstractScDPDateGroupDlg_Impl>::Create(std::make_unique<ScDPDateGroupDlg>(pParent, rInfo, nDatePart, rNullDate));
+}
+
+VclPtr<AbstractScDPShowDetailDlg> ScAbstractDialogFactory_Impl::CreateScDPShowDetailDlg (
+ weld::Window* pParent, ScDPObject& rDPObj, css::sheet::DataPilotFieldOrientation nOrient )
+{
+ return VclPtr<AbstractScDPShowDetailDlg_Impl>::Create(std::make_unique<ScDPShowDetailDlg>(pParent, rDPObj, nOrient));
+}
+
+VclPtr<AbstractScNewScenarioDlg> ScAbstractDialogFactory_Impl::CreateScNewScenarioDlg(weld::Window* pParent, const OUString& rName,
+ bool bEdit, bool bSheetProtected)
+{
+ return VclPtr<AbstractScNewScenarioDlg_Impl>::Create(std::make_unique<ScNewScenarioDlg>(pParent, rName, bEdit, bSheetProtected));
+}
+
+VclPtr<AbstractScShowTabDlg> ScAbstractDialogFactory_Impl::CreateScShowTabDlg(weld::Window* pParent)
+{
+ return VclPtr<AbstractScShowTabDlg_Impl>::Create(std::make_shared<ScShowTabDlg>(pParent));
+}
+
+VclPtr<AbstractScGoToTabDlg> ScAbstractDialogFactory_Impl::CreateScGoToTabDlg(weld::Window* pParent)
+{
+ return VclPtr<AbstractScGoToTabDlg_Impl>::Create(std::make_shared<ScGoToTabDlg>(pParent));
+}
+
+VclPtr<AbstractScStringInputDlg> ScAbstractDialogFactory_Impl::CreateScStringInputDlg(weld::Window* pParent,
+ const OUString& rTitle, const OUString& rEditTitle, const OUString& rDefault, const OString& rHelpId,
+ const OString& rEditHelpId)
+{
+ return VclPtr<AbstractScStringInputDlg_Impl>::Create(std::make_unique<ScStringInputDlg>(pParent, rTitle, rEditTitle,
+ rDefault, rHelpId, rEditHelpId));
+}
+
+VclPtr<AbstractScTabBgColorDlg> ScAbstractDialogFactory_Impl::CreateScTabBgColorDlg(
+ weld::Window* pParent,
+ const OUString& rTitle,
+ const OUString& rTabBgColorNoColorText,
+ const Color& rDefaultColor)
+{
+ return VclPtr<AbstractScTabBgColorDlg_Impl>::Create(std::make_unique<ScTabBgColorDlg>(pParent, rTitle, rTabBgColorNoColorText, rDefaultColor));
+}
+
+VclPtr<AbstractScImportOptionsDlg> ScAbstractDialogFactory_Impl::CreateScImportOptionsDlg(weld::Window* pParent,
+ bool bAscii,
+ const ScImportOptions* pOptions,
+ const OUString* pStrTitle,
+ bool bOnlyDbtoolsEncodings,
+ bool bImport)
+{
+ return VclPtr<AbstractScImportOptionsDlg_Impl>::Create(std::make_unique<ScImportOptionsDlg>(pParent, bAscii, pOptions, pStrTitle, true/*bMultiByte*/, bOnlyDbtoolsEncodings, bImport));
+}
+
+VclPtr<SfxAbstractTabDialog> ScAbstractDialogFactory_Impl::CreateScAttrDlg(weld::Window* pParent, const SfxItemSet* pCellAttrs)
+{
+ return VclPtr<ScAbstractTabController_Impl>::Create(std::make_shared<ScAttrDlg>(pParent, pCellAttrs));
+}
+
+VclPtr<SfxAbstractTabDialog> ScAbstractDialogFactory_Impl::CreateScHFEditDlg( weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ const OUString& rPageStyle,
+ sal_uInt16 nResId )
+{
+ std::shared_ptr<SfxTabDialogController> xDlg;
+
+ switch (nResId)
+ {
+ case RID_SCDLG_HFED_HEADER:
+ case RID_SCDLG_HFEDIT_HEADER:
+ xDlg = std::make_shared<ScHFEditHeaderDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFED_FOOTER:
+ case RID_SCDLG_HFEDIT_FOOTER:
+ xDlg = std::make_shared<ScHFEditFooterDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFEDIT_SHAREDFIRSTHEADER:
+ xDlg = std::make_shared<ScHFEditSharedFirstHeaderDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFEDIT_SHAREDLEFTHEADER:
+ xDlg = std::make_shared<ScHFEditSharedLeftHeaderDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFEDIT_SHAREDFIRSTFOOTER:
+ xDlg = std::make_shared<ScHFEditSharedFirstFooterDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFEDIT_SHAREDLEFTFOOTER:
+ xDlg = std::make_shared<ScHFEditSharedLeftFooterDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFEDIT_LEFTHEADER:
+ xDlg = std::make_shared<ScHFEditLeftHeaderDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFEDIT_RIGHTHEADER:
+ xDlg = std::make_shared<ScHFEditRightHeaderDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFEDIT_LEFTFOOTER:
+ xDlg = std::make_shared<ScHFEditLeftFooterDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFEDIT_RIGHTFOOTER:
+ xDlg = std::make_shared<ScHFEditRightFooterDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFEDIT_SHDR:
+ xDlg = std::make_shared<ScHFEditSharedHeaderDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFEDIT_SFTR:
+ xDlg = std::make_shared<ScHFEditSharedFooterDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ case RID_SCDLG_HFEDIT_ALL:
+ xDlg = std::make_shared<ScHFEditAllDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ default:
+ case RID_SCDLG_HFEDIT:
+ xDlg = std::make_shared<ScHFEditActiveDlg>(pParent, rCoreSet, rPageStyle);
+ break;
+ }
+
+ return xDlg ? VclPtr<ScAbstractTabController_Impl>::Create(std::move(xDlg)) : nullptr;
+}
+
+VclPtr<SfxAbstractTabDialog> ScAbstractDialogFactory_Impl::CreateScStyleDlg(weld::Window* pParent,
+ SfxStyleSheetBase& rStyleBase,
+ bool bPage)
+{
+ return VclPtr<ScAbstractTabController_Impl>::Create(std::make_shared<ScStyleDlg>(pParent, rStyleBase, bPage));
+}
+
+VclPtr<SfxAbstractTabDialog> ScAbstractDialogFactory_Impl::CreateScSubTotalDlg(weld::Window* pParent, const SfxItemSet& rArgSet)
+{
+ return VclPtr<ScAbstractTabController_Impl>::Create(std::make_shared<ScSubTotalDlg>(pParent, rArgSet));
+}
+
+VclPtr<SfxAbstractTabDialog> ScAbstractDialogFactory_Impl::CreateScCharDlg(
+ weld::Window* pParent, const SfxItemSet* pAttr, const SfxObjectShell* pDocShell, bool bDrawText)
+{
+ return VclPtr<ScAbstractTabController_Impl>::Create(std::make_shared<ScCharDlg>(pParent, pAttr, pDocShell, bDrawText));
+}
+
+VclPtr<SfxAbstractTabDialog> ScAbstractDialogFactory_Impl::CreateScParagraphDlg(
+ weld::Window* pParent, const SfxItemSet* pAttr)
+{
+ return VclPtr<ScAbstractTabController_Impl>::Create(std::make_shared<ScParagraphDlg>(pParent, pAttr));
+}
+
+std::shared_ptr<ScAsyncTabController> ScAbstractDialogFactory_Impl::CreateScSortDlg(weld::Window* pParent, const SfxItemSet* pArgSet)
+{
+ return std::make_shared<ScAsyncTabController_Impl>(std::make_shared<ScSortDlg>(pParent, pArgSet));
+}
+
+//------------------ Factories for TabPages--------------------
+CreateTabPage ScAbstractDialogFactory_Impl::GetTabPageCreatorFunc( sal_uInt16 nId )
+{
+ switch (nId)
+ {
+ case SID_SC_TP_CHANGES:
+ return ScRedlineOptionsTabPage::Create;
+ case SID_SC_TP_CALC:
+ return ScTpCalcOptions::Create;
+ case SID_SC_TP_FORMULA:
+ return ScTpFormulaOptions::Create;
+ case SID_SC_TP_COMPATIBILITY:
+ return ScTpCompatOptions::Create;
+ case RID_SC_TP_DEFAULTS:
+ return ScTpDefaultsOptions::Create;
+ case RID_SC_TP_PRINT:
+ return ScTpPrintOptions::Create;
+ case SID_SC_TP_STAT:
+ return ScDocStatPage::Create;
+ case SID_SC_TP_USERLISTS:
+ return ScTpUserLists::Create;
+ case SID_SC_TP_CONTENT:
+ return ScTpContentOptions::Create;
+ case SID_SC_TP_LAYOUT:
+ return ScTpLayoutOptions::Create;
+ default:
+ break;
+ }
+
+ return nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/attrdlg/scdlgfact.hxx b/sc/source/ui/attrdlg/scdlgfact.hxx
new file mode 100644
index 000000000..b1703930c
--- /dev/null
+++ b/sc/source/ui/attrdlg/scdlgfact.hxx
@@ -0,0 +1,806 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <scabstdlg.hxx>
+#include <sfx2/sfxdlg.hxx>
+
+#include <corodlg.hxx>
+#include <condformatmgr.hxx>
+#include <dapitype.hxx>
+#include <dapidata.hxx>
+#include <datafdlg.hxx>
+#include <delcodlg.hxx>
+#include <delcldlg.hxx>
+#include <dpgroupdlg.hxx>
+#include <filldlg.hxx>
+#include <gototabdlg.hxx>
+#include <groupdlg.hxx>
+#include <linkarea.hxx>
+#include <lbseldlg.hxx>
+#include <inscldlg.hxx>
+#include <instbdlg.hxx>
+#include <inscodlg.hxx>
+#include <mtrindlg.hxx>
+#include <mvtabdlg.hxx>
+#include <namecrea.hxx>
+#include <namepast.hxx>
+#include <pfiltdlg.hxx>
+#include <pvfundlg.hxx>
+#include <shtabdlg.hxx>
+#include <scendlg.hxx>
+#include <scuiasciiopt.hxx>
+#include <scuiautofmt.hxx>
+#include <scuiimoptdlg.hxx>
+#include <sortdlg.hxx>
+#include <strindlg.hxx>
+#include <tabbgcolordlg.hxx>
+#include <textimportoptions.hxx>
+
+class AbstractScImportAsciiDlg_Impl : public AbstractScImportAsciiDlg
+{
+ std::shared_ptr<ScImportAsciiDlg> m_xDlg;
+public:
+ explicit AbstractScImportAsciiDlg_Impl(std::shared_ptr<ScImportAsciiDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx) override;
+ virtual void GetOptions( ScAsciiOptions& rOpt ) override;
+ virtual void SaveParameters() override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScAutoFormatDlg_Impl : public AbstractScAutoFormatDlg
+{
+ std::unique_ptr<ScAutoFormatDlg> m_xDlg;
+public:
+ explicit AbstractScAutoFormatDlg_Impl(std::unique_ptr<ScAutoFormatDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual sal_uInt16 GetIndex() const override;
+ virtual OUString GetCurrFormatName() override;
+};
+
+class AbstractScColRowLabelDlg_Impl : public AbstractScColRowLabelDlg
+{
+ std::unique_ptr<ScColRowLabelDlg> m_xDlg;
+public:
+ explicit AbstractScColRowLabelDlg_Impl(std::unique_ptr<ScColRowLabelDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool IsCol() override;
+ virtual bool IsRow() override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScCondFormatManagerDlg_Impl : public AbstractScCondFormatManagerDlg
+{
+ std::shared_ptr<ScCondFormatManagerDlg> m_xDlg;
+public:
+ explicit AbstractScCondFormatManagerDlg_Impl(std::shared_ptr<ScCondFormatManagerDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx) override;
+ virtual std::unique_ptr<ScConditionalFormatList> GetConditionalFormatList() override;
+ virtual bool CondFormatsChanged() const override;
+ virtual void SetModified() override;
+ virtual ScConditionalFormat* GetCondFormatSelected() override;
+};
+
+class AbstractScDataPilotDatabaseDlg_Impl :public AbstractScDataPilotDatabaseDlg
+{
+ std::shared_ptr<ScDataPilotDatabaseDlg> m_xDlg;
+public:
+ explicit AbstractScDataPilotDatabaseDlg_Impl(std::shared_ptr<ScDataPilotDatabaseDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(AsyncContext &) override;
+ virtual void GetValues( ScImportSourceDesc& rDesc ) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScDataPilotSourceTypeDlg_Impl :public AbstractScDataPilotSourceTypeDlg
+{
+ std::shared_ptr<ScDataPilotSourceTypeDlg> m_xDlg;
+public:
+ explicit AbstractScDataPilotSourceTypeDlg_Impl(std::shared_ptr<ScDataPilotSourceTypeDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(AsyncContext &) override;
+ virtual bool IsDatabase() const override;
+ virtual bool IsExternal() const override;
+ virtual bool IsNamedRange() const override;
+ virtual OUString GetSelectedNamedRange() const override;
+ virtual void AppendNamedRange(const OUString& rName) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScDataPilotServiceDlg_Impl : public AbstractScDataPilotServiceDlg
+{
+ std::shared_ptr<ScDataPilotServiceDlg> m_xDlg;
+public:
+ explicit AbstractScDataPilotServiceDlg_Impl(std::shared_ptr<ScDataPilotServiceDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(AsyncContext &) override;
+ virtual OUString GetServiceName() const override;
+ virtual OUString GetParSource() const override;
+ virtual OUString GetParName() const override;
+ virtual OUString GetParUser() const override;
+ virtual OUString GetParPass() const override;
+};
+
+class AbstractScDeleteCellDlg_Impl : public AbstractScDeleteCellDlg
+{
+ std::unique_ptr<ScDeleteCellDlg> m_xDlg;
+public:
+ explicit AbstractScDeleteCellDlg_Impl(std::unique_ptr<ScDeleteCellDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual DelCellCmd GetDelCellCmd() const override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+//for dataform
+class AbstractScDataFormDlg_Impl : public AbstractScDataFormDlg
+{
+ std::unique_ptr<ScDataFormDlg> m_xDlg;
+public:
+ explicit AbstractScDataFormDlg_Impl(std::unique_ptr<ScDataFormDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScDeleteContentsDlg_Impl : public AbstractScDeleteContentsDlg
+{
+ std::unique_ptr<ScDeleteContentsDlg> m_xDlg;
+public:
+ explicit AbstractScDeleteContentsDlg_Impl(std::unique_ptr<ScDeleteContentsDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual void DisableObjects() override;
+ virtual InsertDeleteFlags GetDelContentsCmdBits() const override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScFillSeriesDlg_Impl:public AbstractScFillSeriesDlg
+{
+ std::unique_ptr<ScFillSeriesDlg> m_xDlg;
+public:
+ explicit AbstractScFillSeriesDlg_Impl(std::unique_ptr<ScFillSeriesDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual FillDir GetFillDir() const override;
+ virtual FillCmd GetFillCmd() const override;
+ virtual FillDateCmd GetFillDateCmd() const override;
+ virtual double GetStart() const override;
+ virtual double GetStep() const override;
+ virtual double GetMax() const override;
+ virtual OUString GetStartStr() const override;
+ virtual void SetEdStartValEnabled(bool bFlag) override;
+};
+
+class AbstractScGroupDlg_Impl : public AbstractScGroupDlg
+{
+ std::shared_ptr<ScGroupDlg> m_xDlg;
+public:
+ explicit AbstractScGroupDlg_Impl(std::shared_ptr<ScGroupDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx) override;
+ virtual bool GetColsChecked() const override;
+};
+
+class AbstractScInsertCellDlg_Impl : public AbstractScInsertCellDlg
+{
+ std::unique_ptr<ScInsertCellDlg> m_xDlg;
+public:
+ explicit AbstractScInsertCellDlg_Impl(std::unique_ptr<ScInsertCellDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual InsCellCmd GetInsCellCmd() const override ;
+};
+
+class AbstractScInsertContentsDlg_Impl : public AbstractScInsertContentsDlg
+{
+ std::unique_ptr<ScInsertContentsDlg> m_xDlg;
+public:
+ explicit AbstractScInsertContentsDlg_Impl(std::unique_ptr<ScInsertContentsDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual InsertDeleteFlags GetInsContentsCmdBits() const override;
+ virtual ScPasteFunc GetFormulaCmdBits() const override;
+ virtual bool IsSkipEmptyCells() const override;
+ virtual bool IsLink() const override;
+ virtual void SetFillMode( bool bSet ) override;
+ virtual void SetOtherDoc( bool bSet ) override;
+ virtual bool IsTranspose() const override;
+ virtual void SetChangeTrack( bool bSet ) override;
+ virtual void SetCellShiftDisabled( CellShiftDisabledFlags nDisable ) override;
+ virtual InsCellCmd GetMoveMode() override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScInsertTableDlg_Impl : public AbstractScInsertTableDlg
+{
+ std::unique_ptr<ScInsertTableDlg> m_xDlg;
+public:
+ explicit AbstractScInsertTableDlg_Impl(std::unique_ptr<ScInsertTableDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool GetTablesFromFile() override;
+ virtual bool GetTablesAsLink() override;
+ virtual const OUString* GetFirstTable( sal_uInt16* pN = nullptr ) override;
+ virtual ScDocShell* GetDocShellTables() override;
+ virtual bool IsTableBefore() override;
+ virtual sal_uInt16 GetTableCount() override;
+ virtual const OUString* GetNextTable( sal_uInt16* pN ) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScSelEntryDlg_Impl : public AbstractScSelEntryDlg
+{
+ std::unique_ptr<ScSelEntryDlg> m_xDlg;
+public:
+ explicit AbstractScSelEntryDlg_Impl(std::unique_ptr<ScSelEntryDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual OUString GetSelectedEntry() const override;
+};
+
+class AbstractScLinkedAreaDlg_Impl : public AbstractScLinkedAreaDlg
+{
+ std::unique_ptr<ScLinkedAreaDlg> m_xDlg;
+public:
+ explicit AbstractScLinkedAreaDlg_Impl(std::unique_ptr<ScLinkedAreaDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual ~AbstractScLinkedAreaDlg_Impl() override;
+ virtual short Execute() override;
+ virtual void InitFromOldLink( const OUString& rFile, const OUString& rFilter,
+ const OUString& rOptions, const OUString& rSource,
+ sal_Int32 nRefreshDelaySeconds ) override;
+ virtual OUString GetURL() override;
+ virtual OUString GetFilter() override; // may be empty
+ virtual OUString GetOptions() override; // filter options
+ virtual OUString GetSource() override; // separated by ";"
+ virtual sal_Int32 GetRefreshDelaySeconds() override; // 0 if disabled
+};
+
+class AbstractScMetricInputDlg_Impl : public AbstractScMetricInputDlg
+{
+ std::unique_ptr<ScMetricInputDlg> m_xDlg;
+public:
+ explicit AbstractScMetricInputDlg_Impl(std::unique_ptr<ScMetricInputDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual int GetInputValue() const override;
+};
+
+class AbstractScMoveTableDlg_Impl : public AbstractScMoveTableDlg
+{
+ std::unique_ptr<ScMoveTableDlg> m_xDlg;
+public:
+ explicit AbstractScMoveTableDlg_Impl(std::unique_ptr<ScMoveTableDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual sal_uInt16 GetSelectedDocument () const override;
+ virtual sal_uInt16 GetSelectedTable () const override;
+ virtual bool GetCopyTable () const override;
+ virtual bool GetRenameTable () const override;
+ virtual void GetTabNameString( OUString& rString ) const override;
+ virtual void SetForceCopyTable () override;
+ virtual void EnableRenameTable (bool bFlag) override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScNameCreateDlg_Impl : public AbstractScNameCreateDlg
+{
+ std::unique_ptr<ScNameCreateDlg> m_xDlg;
+public:
+ explicit AbstractScNameCreateDlg_Impl(std::unique_ptr<ScNameCreateDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual CreateNameFlags GetFlags() const override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScNamePasteDlg_Impl : public AbstractScNamePasteDlg
+{
+ std::unique_ptr<ScNamePasteDlg> m_xDlg;
+public:
+ explicit AbstractScNamePasteDlg_Impl(std::unique_ptr<ScNamePasteDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual std::vector<OUString> GetSelectedNames() const override;
+};
+
+class AbstractScPivotFilterDlg_Impl : public AbstractScPivotFilterDlg
+{
+ std::unique_ptr<ScPivotFilterDlg> m_xDlg;
+public:
+ explicit AbstractScPivotFilterDlg_Impl(std::unique_ptr<ScPivotFilterDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual const ScQueryItem& GetOutputItem() override;
+};
+
+class AbstractScDPFunctionDlg_Impl : public AbstractScDPFunctionDlg
+{
+ std::shared_ptr<ScDPFunctionDlg> m_xDlg;
+public:
+ explicit AbstractScDPFunctionDlg_Impl(std::shared_ptr<ScDPFunctionDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx) override;
+ virtual PivotFunc GetFuncMask() const override;
+ virtual css::sheet::DataPilotFieldReference GetFieldRef() const override;
+ virtual void Response(int nResponse) override;
+};
+
+class AbstractScDPSubtotalDlg_Impl : public AbstractScDPSubtotalDlg
+{
+ std::shared_ptr<ScDPSubtotalDlg> m_xDlg;
+public:
+ explicit AbstractScDPSubtotalDlg_Impl(std::shared_ptr<ScDPSubtotalDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx) override;
+ virtual PivotFunc GetFuncMask() const override;
+ virtual void FillLabelData( ScDPLabelData& rLabelData ) const override;
+ virtual void Response(int nResponse) override;
+};
+
+class AbstractScDPNumGroupDlg_Impl : public AbstractScDPNumGroupDlg
+{
+ std::unique_ptr<ScDPNumGroupDlg> m_xDlg;
+public:
+ explicit AbstractScDPNumGroupDlg_Impl(std::unique_ptr<ScDPNumGroupDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual ScDPNumGroupInfo GetGroupInfo() const override;
+};
+
+class AbstractScDPDateGroupDlg_Impl : public AbstractScDPDateGroupDlg
+{
+ std::unique_ptr<ScDPDateGroupDlg> m_xDlg;
+public:
+ explicit AbstractScDPDateGroupDlg_Impl(std::unique_ptr<ScDPDateGroupDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual ScDPNumGroupInfo GetGroupInfo() const override;
+ virtual sal_Int32 GetDatePart() const override;
+};
+
+class AbstractScDPShowDetailDlg_Impl : public AbstractScDPShowDetailDlg
+{
+ std::unique_ptr<ScDPShowDetailDlg> m_xDlg;
+public:
+ explicit AbstractScDPShowDetailDlg_Impl(std::unique_ptr<ScDPShowDetailDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual OUString GetDimensionName() const override;
+};
+
+class AbstractScNewScenarioDlg_Impl : public AbstractScNewScenarioDlg
+{
+ std::unique_ptr<ScNewScenarioDlg> m_xDlg;
+public:
+ explicit AbstractScNewScenarioDlg_Impl(std::unique_ptr<ScNewScenarioDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+
+ virtual void SetScenarioData( const OUString& rName, const OUString& rComment,
+ const Color& rColor, ScScenarioFlags nFlags ) override;
+
+ virtual void GetScenarioData( OUString& rName, OUString& rComment,
+ Color& rColor, ScScenarioFlags& rFlags ) const override;
+};
+
+class AbstractScShowTabDlg_Impl : public AbstractScShowTabDlg
+{
+ std::shared_ptr<ScShowTabDlg> m_xDlg;
+public:
+ explicit AbstractScShowTabDlg_Impl(std::shared_ptr<ScShowTabDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx) override;
+ virtual void Insert( const OUString& rString, bool bSelected ) override;
+ virtual void SetDescription(const OUString& rTitle, const OUString& rFixedText, const OString& sDlgHelpId, const OString& sLbHelpId) override;
+ virtual OUString GetEntry(sal_Int32 nPos) const override;
+ virtual std::vector<sal_Int32> GetSelectedRows() const override;
+};
+
+class AbstractScGoToTabDlg_Impl : public AbstractScGoToTabDlg
+{
+ std::shared_ptr<ScGoToTabDlg> m_xDlg;
+public:
+ explicit AbstractScGoToTabDlg_Impl(std::shared_ptr<ScGoToTabDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual bool StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx) override;
+ virtual void Insert( const OUString& rString, bool bSelected ) override;
+ virtual void SetDescription(const OUString& rTitle, const OUString& rEntryLabel, const OUString& rListLabel,
+ const OString& rDlgHelpId, const OString& rEnHelpId, const OString& rLbHelpId) override;
+ virtual OUString GetSelectedEntry() const override;
+};
+
+class AbstractScSortWarningDlg_Impl : public AbstractScSortWarningDlg
+{
+ std::unique_ptr<ScSortWarningDlg> m_xDlg;
+public:
+ explicit AbstractScSortWarningDlg_Impl(std::unique_ptr<ScSortWarningDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+};
+
+class AbstractScStringInputDlg_Impl : public AbstractScStringInputDlg
+{
+ std::unique_ptr<ScStringInputDlg> m_xDlg;
+public:
+ explicit AbstractScStringInputDlg_Impl(std::unique_ptr<ScStringInputDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual OUString GetInputString() const override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScTabBgColorDlg_Impl : public AbstractScTabBgColorDlg
+{
+ std::unique_ptr<ScTabBgColorDlg> m_xDlg;
+public:
+ explicit AbstractScTabBgColorDlg_Impl(std::unique_ptr<ScTabBgColorDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual void GetSelectedColor( Color& rColor ) const override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class AbstractScImportOptionsDlg_Impl : public AbstractScImportOptionsDlg
+{
+ std::unique_ptr<ScImportOptionsDlg> m_xDlg;
+public:
+ explicit AbstractScImportOptionsDlg_Impl(std::unique_ptr<ScImportOptionsDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual void GetImportOptions( ScImportOptions& rOptions ) const override;
+ virtual void SaveImportOptions() const override;
+};
+
+class AbstractScTextImportOptionsDlg_Impl : public AbstractScTextImportOptionsDlg
+{
+ std::unique_ptr<ScTextImportOptionsDlg> m_xDlg;
+public:
+ explicit AbstractScTextImportOptionsDlg_Impl(std::unique_ptr<ScTextImportOptionsDlg> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual short Execute() override;
+ virtual LanguageType GetLanguageType() const override;
+ virtual bool IsDateConversionSet() const override;
+ virtual bool IsKeepAskingSet() const override;
+
+ // screenshotting
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class ScAbstractTabController_Impl : public SfxAbstractTabDialog
+{
+ std::shared_ptr<SfxTabDialogController> m_xDlg;
+public:
+ explicit ScAbstractTabController_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 std::vector<OString> getAllPageUIXMLDescriptions() const override;
+ virtual bool selectPageByUIXMLDescription(const OString& rUIXMLDescription) override;
+ virtual BitmapEx createScreenshot() const override;
+ virtual OString GetScreenshotId() const override;
+};
+
+class ScAsyncTabController_Impl : public ScAsyncTabController
+{
+ std::shared_ptr<SfxTabDialogController> m_xDlg;
+public:
+ explicit ScAsyncTabController_Impl(std::shared_ptr<SfxTabDialogController> p)
+ : m_xDlg(std::move(p))
+ {
+ }
+ virtual bool StartExecuteAsync(VclAbstractDialog::AsyncContext &rCtx) override;
+ virtual const SfxItemSet* GetOutputItemSet() const override;
+ virtual void SetCurPageId( const OString &rName ) override;
+};
+
+//AbstractDialogFactory_Impl implementations
+class ScAbstractDialogFactory_Impl : public ScAbstractDialogFactory
+{
+
+public:
+ virtual ~ScAbstractDialogFactory_Impl() {}
+
+ virtual VclPtr<AbstractScImportAsciiDlg> CreateScImportAsciiDlg(weld::Window* pParent,
+ const OUString& aDatName,
+ SvStream* pInStream,
+ ScImportAsciiCall eCall) override;
+
+ virtual VclPtr<AbstractScTextImportOptionsDlg> CreateScTextImportOptionsDlg(weld::Window* pParent) override;
+
+ virtual VclPtr<AbstractScAutoFormatDlg> CreateScAutoFormatDlg(weld::Window* pParent,
+ ScAutoFormat* pAutoFormat,
+ const ScAutoFormatData* pSelFormatData,
+ ScViewData& rViewData) override;
+ virtual VclPtr<AbstractScColRowLabelDlg> CreateScColRowLabelDlg (weld::Window* pParent,
+ bool bCol,
+ bool bRow) override;
+
+ virtual VclPtr<AbstractScSortWarningDlg> CreateScSortWarningDlg(weld::Window* pParent, const OUString& rExtendText, const OUString& rCurrentText ) override;
+
+ virtual VclPtr<AbstractScCondFormatManagerDlg> CreateScCondFormatMgrDlg(weld::Window* pParent, ScDocument& rDoc, const ScConditionalFormatList* pFormatList ) override;
+
+ virtual VclPtr<AbstractScDataPilotDatabaseDlg> CreateScDataPilotDatabaseDlg(weld::Window* pParent) override;
+
+ virtual VclPtr<AbstractScDataPilotSourceTypeDlg> CreateScDataPilotSourceTypeDlg(weld::Window* pParent,
+ bool bEnableExternal) override;
+
+ virtual VclPtr<AbstractScDataPilotServiceDlg> CreateScDataPilotServiceDlg(weld::Window* pParent,
+ const std::vector<OUString>& rServices) override;
+ virtual VclPtr<AbstractScDeleteCellDlg> CreateScDeleteCellDlg(weld::Window* pParent, bool bDisallowCellMove ) override;
+
+ //for dataform
+ virtual VclPtr<AbstractScDataFormDlg> CreateScDataFormDlg(weld::Window* pParent, ScTabViewShell* pTabViewShell) override;
+
+ virtual VclPtr<AbstractScDeleteContentsDlg> CreateScDeleteContentsDlg(weld::Window* pParent) override;
+
+ virtual VclPtr<AbstractScFillSeriesDlg> CreateScFillSeriesDlg(weld::Window* pParent,
+ ScDocument& rDocument,
+ FillDir eFillDir,
+ FillCmd eFillCmd,
+ FillDateCmd eFillDateCmd,
+ const OUString& aStartStr,
+ double fStep,
+ double fMax,
+ SCSIZE nSelectHeight,
+ SCSIZE nSelectWidth,
+ sal_uInt16 nPossDir) override;
+ virtual VclPtr<AbstractScGroupDlg> CreateAbstractScGroupDlg(weld::Window* pParent, bool bUnGroup = false) override;
+
+ virtual VclPtr<AbstractScInsertCellDlg> CreateScInsertCellDlg(weld::Window* pParent,
+ bool bDisallowCellMove) override;
+
+ virtual VclPtr<AbstractScInsertContentsDlg> CreateScInsertContentsDlg(weld::Window* pParent,
+ const OUString* pStrTitle = nullptr) override;
+
+ virtual VclPtr<AbstractScInsertTableDlg> CreateScInsertTableDlg(weld::Window* pParent, ScViewData& rViewData,
+ SCTAB nTabCount, bool bFromFile) override;
+
+ virtual VclPtr<AbstractScSelEntryDlg> CreateScSelEntryDlg(weld::Window* pParent, const std::vector<OUString> &rEntryList) override;
+
+ virtual VclPtr<AbstractScLinkedAreaDlg> CreateScLinkedAreaDlg(weld::Widget* pParent) override;
+
+ virtual VclPtr<AbstractScMetricInputDlg> CreateScMetricInputDlg(weld::Window* pParent,
+ const OString& sDialogName,
+ tools::Long nCurrent,
+ tools::Long nDefault,
+ FieldUnit eFUnit,
+ sal_uInt16 nDecimals,
+ tools::Long nMaximum,
+ tools::Long nMinimum = 0 ) override;
+
+ virtual VclPtr<AbstractScMoveTableDlg> CreateScMoveTableDlg(weld::Window * pParent,
+ const OUString& rDefault) override;
+
+ virtual VclPtr<AbstractScNameCreateDlg> CreateScNameCreateDlg(weld::Window * pParent,
+ CreateNameFlags nFlags) override;
+
+ virtual VclPtr<AbstractScNamePasteDlg> CreateScNamePasteDlg(weld::Window * pParent, ScDocShell* pShell) override;
+
+ virtual VclPtr<AbstractScPivotFilterDlg> CreateScPivotFilterDlg(weld::Window* pParent, const SfxItemSet& rArgSet,
+ sal_uInt16 nSourceTab) override;
+
+ virtual VclPtr<AbstractScDPFunctionDlg> CreateScDPFunctionDlg(weld::Widget* pParent,
+ const ScDPLabelDataVector& rLabelVec,
+ const ScDPLabelData& rLabelData,
+ const ScPivotFuncData& rFuncData ) override;
+
+ virtual VclPtr<AbstractScDPSubtotalDlg> CreateScDPSubtotalDlg(weld::Widget* pParent,
+ ScDPObject& rDPObj,
+ const ScDPLabelData& rLabelData,
+ const ScPivotFuncData& rFuncData,
+ const ScDPNameVec& rDataFields ) override;
+
+ virtual VclPtr<AbstractScDPNumGroupDlg> CreateScDPNumGroupDlg(weld::Window* pParent,
+ const ScDPNumGroupInfo& rInfo) override;
+
+ virtual VclPtr<AbstractScDPDateGroupDlg> CreateScDPDateGroupDlg(weld::Window* pParent,
+ const ScDPNumGroupInfo& rInfo,
+ sal_Int32 nDatePart,
+ const Date& rNullDate) override;
+
+ virtual VclPtr<AbstractScDPShowDetailDlg> CreateScDPShowDetailDlg(weld::Window* pParent,
+ ScDPObject& rDPObj,
+ css::sheet::DataPilotFieldOrientation nOrient) override;
+
+ virtual VclPtr<AbstractScNewScenarioDlg> CreateScNewScenarioDlg(weld::Window* pParent, const OUString& rName,
+ bool bEdit, bool bSheetProtected) override;
+ virtual VclPtr<AbstractScShowTabDlg> CreateScShowTabDlg(weld::Window* pParent) override;
+ virtual VclPtr<AbstractScGoToTabDlg> CreateScGoToTabDlg(weld::Window* pParent) override;
+
+ virtual VclPtr<AbstractScStringInputDlg> CreateScStringInputDlg(weld::Window* pParent,
+ const OUString& rTitle,
+ const OUString& rEditTitle,
+ const OUString& rDefault,
+ const OString& rHelpId,
+ const OString& rEditHelpId) override;
+
+ virtual VclPtr<AbstractScTabBgColorDlg> CreateScTabBgColorDlg(weld::Window* pParent,
+ const OUString& rTitle, //Dialog Title
+ const OUString& rTabBgColorNoColorText, //Label for no tab color
+ const Color& rDefaultColor) override; //Currently selected Color
+
+ virtual VclPtr<AbstractScImportOptionsDlg> CreateScImportOptionsDlg(weld::Window* pParent, bool bAscii,
+ const ScImportOptions* pOptions,
+ const OUString* pStrTitle,
+ bool bOnlyDbtoolsEncodings,
+ bool bImport = true) override;
+
+ virtual VclPtr<SfxAbstractTabDialog> CreateScAttrDlg(weld::Window* pParent,
+ const SfxItemSet* pCellAttrs) override;
+
+ virtual VclPtr<SfxAbstractTabDialog> CreateScHFEditDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ const OUString& rPageStyle,
+ sal_uInt16 nResId ) override;
+
+ virtual VclPtr<SfxAbstractTabDialog> CreateScStyleDlg(weld::Window* pParent,
+ SfxStyleSheetBase& rStyleBase,
+ bool bPage) override;
+
+ virtual VclPtr<SfxAbstractTabDialog> CreateScSubTotalDlg(weld::Window* pParent,
+ const SfxItemSet& rArgSet) override;
+ virtual VclPtr<SfxAbstractTabDialog> CreateScCharDlg(weld::Window* pParent,
+ const SfxItemSet* pAttr, const SfxObjectShell* pDocShell, bool bDrawText) override;
+
+ virtual VclPtr<SfxAbstractTabDialog> CreateScParagraphDlg(weld::Window* pParent,
+ const SfxItemSet* pAttr) override;
+
+ virtual std::shared_ptr<ScAsyncTabController> CreateScSortDlg(weld::Window* pParent, const SfxItemSet* pArgSet) override;
+
+ // For TabPage
+ virtual CreateTabPage GetTabPageCreatorFunc( sal_uInt16 nId ) override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/attrdlg/scuiexp.cxx b/sc/source/ui/attrdlg/scuiexp.cxx
new file mode 100644
index 000000000..4351539a9
--- /dev/null
+++ b/sc/source/ui/attrdlg/scuiexp.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include "scdlgfact.hxx"
+#include <sal/types.h>
+
+extern "C" {
+SAL_DLLPUBLIC_EXPORT ScAbstractDialogFactory* ScCreateDialogFactory()
+{
+ static ScAbstractDialogFactory_Impl aFactory;
+ return &aFactory;
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/attrdlg/tabpages.cxx b/sc/source/ui/attrdlg/tabpages.cxx
new file mode 100644
index 000000000..af0ed1d6a
--- /dev/null
+++ b/sc/source/ui/attrdlg/tabpages.cxx
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <attrib.hxx>
+#include <sc.hrc>
+
+#include <tabpages.hxx>
+#include <osl/diagnose.h>
+
+const WhichRangesContainer ScTabPageProtection::pProtectionRanges(
+ svl::Items<SID_SCATTR_PROTECTION, SID_SCATTR_PROTECTION>);
+
+// Zellschutz-Tabpage:
+
+ScTabPageProtection::ScTabPageProtection(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/cellprotectionpage.ui", "CellProtectionPage", &rCoreAttrs)
+ , m_xBtnHideCell(m_xBuilder->weld_check_button("checkHideAll"))
+ , m_xBtnProtect(m_xBuilder->weld_check_button("checkProtected"))
+ , m_xBtnHideFormula(m_xBuilder->weld_check_button("checkHideFormula"))
+ , m_xBtnHidePrint(m_xBuilder->weld_check_button("checkHidePrinting"))
+{
+ // This Page need ExchangeSupport
+ SetExchangeSupport();
+
+ // States will be set in Reset
+ bTriEnabled = bDontCare = bProtect = bHideForm = bHideCell = bHidePrint = false;
+
+ m_xBtnProtect->connect_toggled(LINK(this, ScTabPageProtection, ProtectClickHdl));
+ m_xBtnHideCell->connect_toggled(LINK(this, ScTabPageProtection, HideCellClickHdl));
+ m_xBtnHideFormula->connect_toggled(LINK(this, ScTabPageProtection, HideFormulaClickHdl));
+ m_xBtnHidePrint->connect_toggled(LINK(this, ScTabPageProtection, HidePrintClickHdl));
+}
+
+ScTabPageProtection::~ScTabPageProtection()
+{
+}
+
+std::unique_ptr<SfxTabPage> ScTabPageProtection::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet)
+{
+ return std::make_unique<ScTabPageProtection>(pPage, pController, *rAttrSet);
+}
+
+void ScTabPageProtection::Reset( const SfxItemSet* rCoreAttrs )
+{
+ // Initialize variables
+
+ sal_uInt16 nWhich = GetWhich( SID_SCATTR_PROTECTION );
+ const ScProtectionAttr* pProtAttr = nullptr;
+ SfxItemState eItemState = rCoreAttrs->GetItemState( nWhich, false,
+ reinterpret_cast<const SfxPoolItem**>(&pProtAttr) );
+
+ // Is this a Default-Item?
+ if ( eItemState == SfxItemState::DEFAULT )
+ pProtAttr = static_cast<const ScProtectionAttr*>(&(rCoreAttrs->Get(nWhich)));
+ // At SfxItemState::DONTCARE let to 0
+
+ bTriEnabled = ( pProtAttr == nullptr ); // TriState, when DontCare
+ bDontCare = bTriEnabled;
+ if (bTriEnabled)
+ {
+ // Defaults which appear when a TriState will be clicked away:
+ // (because everything combined is an attribute, and also only
+ // everything combined as DontCare can be available - #38543#)
+
+ bProtect = true;
+ bHideForm = bHideCell = bHidePrint = false;
+ }
+ else
+ {
+ bProtect = pProtAttr->GetProtection();
+ bHideCell = pProtAttr->GetHideCell();
+ bHideForm = pProtAttr->GetHideFormula();
+ bHidePrint = pProtAttr->GetHidePrint();
+ }
+
+ aHideCellState.bTriStateEnabled = bTriEnabled;
+ aProtectState.bTriStateEnabled = bTriEnabled;
+ aHideFormulaState.bTriStateEnabled = bTriEnabled;
+ aHidePrintState.bTriStateEnabled = bTriEnabled;
+
+ UpdateButtons();
+}
+
+bool ScTabPageProtection::FillItemSet( SfxItemSet* rCoreAttrs )
+{
+ bool bAttrsChanged = false;
+ sal_uInt16 nWhich = GetWhich( SID_SCATTR_PROTECTION );
+ const SfxPoolItem* pOldItem = GetOldItem( *rCoreAttrs, SID_SCATTR_PROTECTION );
+ const SfxItemSet& rOldSet = GetItemSet();
+ SfxItemState eItemState = rOldSet.GetItemState( nWhich, false );
+ ScProtectionAttr aProtAttr;
+
+ if ( !bDontCare )
+ {
+ aProtAttr.SetProtection( bProtect );
+ aProtAttr.SetHideCell( bHideCell );
+ aProtAttr.SetHideFormula( bHideForm );
+ aProtAttr.SetHidePrint( bHidePrint );
+
+ if ( bTriEnabled )
+ bAttrsChanged = true; // DontCare -> properly value
+ else
+ bAttrsChanged = !pOldItem || aProtAttr != *static_cast<const ScProtectionAttr*>(pOldItem);
+ }
+
+ if ( bAttrsChanged )
+ rCoreAttrs->Put( aProtAttr );
+ else if ( eItemState == SfxItemState::DEFAULT )
+ rCoreAttrs->ClearItem( nWhich );
+
+ return bAttrsChanged;
+}
+
+DeactivateRC ScTabPageProtection::DeactivatePage( SfxItemSet* pSetP )
+{
+ if ( pSetP )
+ FillItemSet( pSetP );
+
+ return DeactivateRC::LeavePage;
+}
+
+IMPL_LINK(ScTabPageProtection, ProtectClickHdl, weld::Toggleable&, rBox, void)
+{
+ aProtectState.ButtonToggled(rBox);
+ ButtonClick(rBox);
+}
+
+IMPL_LINK(ScTabPageProtection, HideCellClickHdl, weld::Toggleable&, rBox, void)
+{
+ aHideCellState.ButtonToggled(rBox);
+ ButtonClick(rBox);
+}
+
+IMPL_LINK(ScTabPageProtection, HideFormulaClickHdl, weld::Toggleable&, rBox, void)
+{
+ aHideFormulaState.ButtonToggled(rBox);
+ ButtonClick(rBox);
+}
+
+IMPL_LINK(ScTabPageProtection, HidePrintClickHdl, weld::Toggleable&, rBox, void)
+{
+ aHidePrintState.ButtonToggled(rBox);
+ ButtonClick(rBox);
+}
+
+void ScTabPageProtection::ButtonClick(const weld::Toggleable& rBox)
+{
+ TriState eState = rBox.get_state();
+ if (eState == TRISTATE_INDET)
+ bDontCare = true; // everything combined at DontCare
+ else
+ {
+ bDontCare = false; // DontCare from everywhere
+ bool bOn = eState == TRISTATE_TRUE; // from a selected value
+
+ if (&rBox == m_xBtnProtect.get())
+ bProtect = bOn;
+ else if (&rBox == m_xBtnHideCell.get())
+ bHideCell = bOn;
+ else if (&rBox == m_xBtnHideFormula.get())
+ bHideForm = bOn;
+ else if (&rBox == m_xBtnHidePrint.get())
+ bHidePrint = bOn;
+ else
+ {
+ OSL_FAIL("Wrong button");
+ }
+ }
+
+ UpdateButtons(); // TriState and Logic-Enable
+}
+
+void ScTabPageProtection::UpdateButtons()
+{
+ if (bDontCare)
+ {
+ m_xBtnProtect->set_state(TRISTATE_INDET);
+ m_xBtnHideCell->set_state(TRISTATE_INDET);
+ m_xBtnHideFormula->set_state(TRISTATE_INDET);
+ m_xBtnHidePrint->set_state(TRISTATE_INDET);
+ }
+ else
+ {
+ m_xBtnProtect->set_state(bProtect ? TRISTATE_TRUE : TRISTATE_FALSE);
+ m_xBtnHideCell->set_state(bHideCell ? TRISTATE_TRUE : TRISTATE_FALSE);
+ m_xBtnHideFormula->set_state(bHideForm ? TRISTATE_TRUE : TRISTATE_FALSE);
+ m_xBtnHidePrint->set_state(bHidePrint ? TRISTATE_TRUE : TRISTATE_FALSE);
+ }
+
+ aHideCellState.eState = m_xBtnHideCell->get_state();
+ aProtectState.eState = m_xBtnProtect->get_state();
+ aHideFormulaState.eState = m_xBtnHideFormula->get_state();
+ aHidePrintState.eState = m_xBtnHidePrint->get_state();
+
+ bool bEnable = (m_xBtnHideCell->get_state() != TRISTATE_TRUE);
+ {
+ m_xBtnProtect->set_sensitive(bEnable);
+ m_xBtnHideFormula->set_sensitive(bEnable);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/cctrl/cbnumberformat.cxx b/sc/source/ui/cctrl/cbnumberformat.cxx
new file mode 100644
index 000000000..29ab64e84
--- /dev/null
+++ b/sc/source/ui/cctrl/cbnumberformat.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 <cbnumberformat.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewsh.hxx>
+#include <svl/intitem.hxx>
+#include <sc.hrc>
+
+ScNumberFormat::ScNumberFormat(vcl::Window* pParent)
+ : InterimItemWindow(pParent, "modules/scalc/ui/numberbox.ui", "NumberBox", true,
+ reinterpret_cast<sal_uInt64>(SfxViewShell::Current()))
+ , m_xWidget(m_xBuilder->weld_combo_box("numbertype"))
+{
+ m_xWidget->append_text(ScResId(STR_GENERAL));
+ m_xWidget->append_text(ScResId(STR_NUMBER));
+ m_xWidget->append_text(ScResId(STR_PERCENT));
+ m_xWidget->append_text(ScResId(STR_CURRENCY));
+ m_xWidget->append_text(ScResId(STR_DATE));
+ m_xWidget->append_text(ScResId(STR_TIME));
+ m_xWidget->append_text(ScResId(STR_SCIENTIFIC));
+ m_xWidget->append_text(ScResId(STR_FRACTION));
+ m_xWidget->append_text(ScResId(STR_BOOLEAN_VALUE));
+ m_xWidget->append_text(ScResId(STR_TEXT));
+
+ m_xWidget->connect_changed(LINK(this, ScNumberFormat, NumFormatSelectHdl));
+ m_xWidget->connect_key_press(LINK(this, ScNumberFormat, KeyInputHdl));
+
+ SetSizePixel(m_xWidget->get_preferred_size());
+}
+
+void ScNumberFormat::dispose()
+{
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
+}
+
+ScNumberFormat::~ScNumberFormat() { disposeOnce(); }
+
+void ScNumberFormat::GetFocus()
+{
+ if (m_xWidget)
+ m_xWidget->grab_focus();
+ InterimItemWindow::GetFocus();
+}
+
+IMPL_STATIC_LINK(ScNumberFormat, NumFormatSelectHdl, weld::ComboBox&, rBox, void)
+{
+ auto* pCurSh = SfxViewFrame::Current();
+ if (!pCurSh)
+ return;
+
+ SfxDispatcher* pDisp = pCurSh->GetBindings().GetDispatcher();
+ if (pDisp)
+ {
+ const sal_Int32 nVal = rBox.get_active();
+ SfxUInt16Item aItem(SID_NUMBER_TYPE_FORMAT, nVal);
+ pDisp->ExecuteList(SID_NUMBER_TYPE_FORMAT, SfxCallMode::RECORD, { &aItem });
+
+ pCurSh->GetWindow().GrabFocus();
+ }
+}
+
+IMPL_LINK(ScNumberFormat, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ return ChildKeyInput(rKEvt);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/cctrl/cbuttonw.cxx b/sc/source/ui/cctrl/cbuttonw.cxx
new file mode 100644
index 000000000..b7f99f731
--- /dev/null
+++ b/sc/source/ui/cctrl/cbuttonw.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 <comphelper/lok.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <cbutton.hxx>
+
+
+ScDDComboBoxButton::ScDDComboBoxButton( OutputDevice* pOutputDevice )
+ : pOut( pOutputDevice )
+{
+ SetOptSizePixel();
+}
+
+ScDDComboBoxButton::~ScDDComboBoxButton()
+{
+}
+
+void ScDDComboBoxButton::SetOutputDevice( OutputDevice* pOutputDevice )
+{
+ pOut = pOutputDevice;
+}
+
+void ScDDComboBoxButton::SetOptSizePixel()
+{
+ aBtnSize = pOut->LogicToPixel(Size(8, 11), MapMode(MapUnit::MapAppFont));
+ aBtnSize.setWidth( std::max(aBtnSize.Width(), static_cast<tools::Long>(pOut->GetSettings().GetStyleSettings().GetScrollBarSize())) );
+}
+
+void ScDDComboBoxButton::Draw( const Point& rAt,
+ const Size& rSize )
+{
+ if ( rSize.IsEmpty() )
+ return;
+
+ // save old state
+ bool bHadFill = pOut->IsFillColor();
+ Color aOldFill = pOut->GetFillColor();
+ bool bHadLine = pOut->IsLineColor();
+ Color aOldLine = pOut->GetLineColor();
+ bool bOldEnable = pOut->IsMapModeEnabled();
+
+ tools::Rectangle aBtnRect( rAt, rSize );
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ pOut->EnableMapMode(false);
+
+ DecorationView aDecoView( pOut);
+
+ tools::Rectangle aInnerRect=aDecoView.DrawButton( aBtnRect, DrawButtonFlags::Default );
+
+ aInnerRect.AdjustLeft(1 );
+ aInnerRect.AdjustTop(1 );
+ aInnerRect.AdjustRight( -1 );
+ aInnerRect.AdjustBottom( -1 );
+
+ Size aInnerSize = aInnerRect.GetSize();
+ Point aInnerCenter = aInnerRect.Center();
+
+ aInnerRect.SetTop( aInnerCenter.Y() - (aInnerSize.Width()>>1) );
+ aInnerRect.SetBottom( aInnerCenter.Y() + (aInnerSize.Width()>>1) );
+
+ ImpDrawArrow( aInnerRect );
+
+ // restore old state
+ pOut->EnableMapMode( bOldEnable );
+ if (bHadLine)
+ pOut->SetLineColor(aOldLine);
+ else
+ pOut->SetLineColor();
+ if (bHadFill)
+ pOut->SetFillColor(aOldFill);
+ else
+ pOut->SetFillColor();
+}
+
+void ScDDComboBoxButton::ImpDrawArrow( const tools::Rectangle& rRect )
+{
+ // no need to save old line and fill color here (is restored after the call)
+
+ tools::Rectangle aPixRect = rRect;
+ Point aCenter = aPixRect.Center();
+ Size aSize = aPixRect.GetSize();
+
+ Size aSize3;
+ aSize3.setWidth( aSize.Width() >> 1 );
+ aSize3.setHeight( aSize.Height() >> 1 );
+
+ Size aSize4;
+ aSize4.setWidth( aSize.Width() >> 2 );
+ aSize4.setHeight( aSize.Height() >> 2 );
+
+ tools::Rectangle aTempRect = aPixRect;
+
+ const StyleSettings& rSett = Application::GetSettings().GetStyleSettings();
+ Color aColor( rSett.GetButtonTextColor() );
+ pOut->SetFillColor( aColor );
+ pOut->SetLineColor( aColor );
+
+ aTempRect.SetLeft( aCenter.X() - aSize4.Width() );
+ aTempRect.SetRight( aCenter.X() + aSize4.Width() );
+ aTempRect.SetTop( aCenter.Y() - aSize3.Height() );
+ aTempRect.SetBottom( aCenter.Y() - 1 );
+
+ pOut->DrawRect( aTempRect );
+
+ Point aPos1( aCenter.X()-aSize3.Width(), aCenter.Y() );
+ Point aPos2( aCenter.X()+aSize3.Width(), aCenter.Y() );
+ while( aPos1.X() <= aPos2.X() )
+ {
+ pOut->DrawLine( aPos1, aPos2 );
+ aPos1.AdjustX( 1 ); aPos2.AdjustX( -1 );
+ aPos1.AdjustY( 1 ); aPos2.AdjustY( 1 );
+ }
+
+ pOut->DrawLine( Point( aCenter.X() - aSize3.Width(), aPos1.Y()+1 ),
+ Point( aCenter.X() + aSize3.Width(), aPos1.Y()+1 ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/cctrl/checklistmenu.cxx b/sc/source/ui/cctrl/checklistmenu.cxx
new file mode 100644
index 000000000..82e7488c9
--- /dev/null
+++ b/sc/source/ui/cctrl/checklistmenu.cxx
@@ -0,0 +1,1737 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <checklistmenu.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <vcl/commandevent.hxx>
+#include <vcl/decoview.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <rtl/math.hxx>
+#include <unotools/charclass.hxx>
+#include <comphelper/lok.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <tools/json_writer.hxx>
+#include <svl/numformat.hxx>
+
+#include <document.hxx>
+#include <viewdata.hxx>
+
+using namespace com::sun::star;
+using ::com::sun::star::uno::Reference;
+
+ScCheckListMenuControl::MenuItemData::MenuItemData()
+ : mbEnabled(true)
+{
+}
+
+ScCheckListMenuControl::SubMenuItemData::SubMenuItemData(ScCheckListMenuControl* pParent)
+ : maTimer("sc SubMenuItemData maTimer")
+ , mpSubMenu(nullptr)
+ , mnMenuPos(MENU_NOT_SELECTED)
+ , mpParent(pParent)
+{
+ maTimer.SetInvokeHandler(LINK(this, ScCheckListMenuControl::SubMenuItemData, TimeoutHdl));
+ maTimer.SetTimeout(Application::GetSettings().GetMouseSettings().GetMenuDelay());
+}
+
+void ScCheckListMenuControl::SubMenuItemData::reset()
+{
+ mpSubMenu = nullptr;
+ mnMenuPos = MENU_NOT_SELECTED;
+ maTimer.Stop();
+}
+
+IMPL_LINK_NOARG(ScCheckListMenuControl::SubMenuItemData, TimeoutHdl, Timer *, void)
+{
+ mpParent->handleMenuTimeout(this);
+}
+
+IMPL_LINK_NOARG(ScCheckListMenuControl, RowActivatedHdl, weld::TreeView&, bool)
+{
+ executeMenuItem(mxMenu->get_selected_index());
+ return true;
+}
+
+IMPL_LINK(ScCheckListMenuControl, MenuKeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+
+ switch (rKeyCode.GetCode())
+ {
+ case KEY_RIGHT:
+ {
+ if (mnSelectedMenu >= maMenuItems.size() || mnSelectedMenu == MENU_NOT_SELECTED)
+ break;
+
+ const MenuItemData& rMenu = maMenuItems[mnSelectedMenu];
+ if (!rMenu.mxSubMenuWin)
+ break;
+
+ executeMenuItem(mnSelectedMenu);
+ }
+ }
+
+ return false;
+}
+
+IMPL_LINK_NOARG(ScCheckListMenuControl, SelectHdl, weld::TreeView&, void)
+{
+ sal_uInt32 nSelectedMenu = MENU_NOT_SELECTED;
+ if (!mxMenu->get_selected(mxScratchIter.get()))
+ {
+ // reselect current item if its submenu is up and the launching item
+ // became unselected by mouse moving out of the top level menu
+ if (mnSelectedMenu < maMenuItems.size() &&
+ maMenuItems[mnSelectedMenu].mxSubMenuWin &&
+ maMenuItems[mnSelectedMenu].mxSubMenuWin->IsVisible())
+ {
+ mxMenu->select(mnSelectedMenu);
+ return;
+ }
+ }
+ else
+ nSelectedMenu = mxMenu->get_iter_index_in_parent(*mxScratchIter);
+
+ setSelectedMenuItem(nSelectedMenu);
+}
+
+void ScCheckListMenuControl::addMenuItem(const OUString& rText, Action* pAction)
+{
+ MenuItemData aItem;
+ aItem.mbEnabled = true;
+ aItem.mxAction.reset(pAction);
+ maMenuItems.emplace_back(std::move(aItem));
+
+ mxMenu->show();
+ mxMenu->append_text(rText);
+ mxMenu->set_image(mxMenu->n_children() - 1, css::uno::Reference<css::graphic::XGraphic>(), 1);
+}
+
+void ScCheckListMenuControl::addSeparator()
+{
+ MenuItemData aItem;
+ maMenuItems.emplace_back(std::move(aItem));
+
+ mxMenu->append_separator("separator" + OUString::number(maMenuItems.size()));
+}
+
+IMPL_LINK(ScCheckListMenuControl, TreeSizeAllocHdl, const Size&, rSize, void)
+{
+ if (maAllocatedSize == rSize)
+ return;
+ maAllocatedSize = rSize;
+ SetDropdownPos();
+ if (!mnAsyncSetDropdownPosId && Application::GetToolkitName().startsWith("gtk"))
+ {
+ // for gtk retry again later in case it didn't work (wayland)
+ mnAsyncSetDropdownPosId = Application::PostUserEvent(LINK(this, ScCheckListMenuControl, SetDropdownPosHdl));
+ }
+}
+
+void ScCheckListMenuControl::SetDropdownPos()
+{
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(maAllocatedSize.Width() - (mxMenu->get_text_height() * 3) / 4 - 6)
+ };
+ mxMenu->set_column_fixed_widths(aWidths);
+}
+
+IMPL_LINK_NOARG(ScCheckListMenuControl, SetDropdownPosHdl, void*, void)
+{
+ mnAsyncSetDropdownPosId = nullptr;
+ SetDropdownPos();
+ mxMenu->queue_resize();
+}
+
+void ScCheckListMenuControl::CreateDropDown()
+{
+ int nWidth = (mxMenu->get_text_height() * 3) / 4;
+ mxDropDown->SetOutputSizePixel(Size(nWidth, nWidth));
+ DecorationView aDecoView(mxDropDown.get());
+ aDecoView.DrawSymbol(tools::Rectangle(Point(0, 0), Size(nWidth, nWidth)),
+ SymbolType::SPIN_RIGHT, mxDropDown->GetTextColor(),
+ DrawSymbolFlags::NONE);
+}
+
+ScListSubMenuControl* ScCheckListMenuControl::addSubMenuItem(const OUString& rText, bool bEnabled, bool bColorMenu)
+{
+ MenuItemData aItem;
+ aItem.mbEnabled = bEnabled;
+
+ aItem.mxSubMenuWin.reset(new ScListSubMenuControl(mxMenu.get(), *this, bColorMenu));
+ maMenuItems.emplace_back(std::move(aItem));
+
+ mxMenu->show();
+ mxMenu->append_text(rText);
+ mxMenu->set_image(mxMenu->n_children() - 1, *mxDropDown, 1);
+ return maMenuItems.back().mxSubMenuWin.get();
+}
+
+void ScCheckListMenuControl::executeMenuItem(size_t nPos)
+{
+ if (nPos >= maMenuItems.size())
+ return;
+
+ const MenuItemData& rMenu = maMenuItems[nPos];
+ if (rMenu.mxSubMenuWin)
+ {
+ if (rMenu.mbEnabled)
+ {
+ maOpenTimer.mnMenuPos = nPos;
+ maOpenTimer.mpSubMenu = rMenu.mxSubMenuWin.get();
+ launchSubMenu();
+ }
+ return;
+ }
+
+ if (!maMenuItems[nPos].mxAction)
+ // no action is defined.
+ return;
+
+ const bool bClosePopup = maMenuItems[nPos].mxAction->execute();
+ if (bClosePopup)
+ terminateAllPopupMenus();
+}
+
+void ScCheckListMenuControl::setSelectedMenuItem(size_t nPos)
+{
+ if (mnSelectedMenu == nPos)
+ // nothing to do.
+ return;
+
+ selectMenuItem(nPos, /*bSubMenuTimer*/true);
+}
+
+void ScCheckListMenuControl::handleMenuTimeout(const SubMenuItemData* pTimer)
+{
+ if (pTimer == &maOpenTimer)
+ {
+ // Close any open submenu immediately.
+ if (maCloseTimer.mpSubMenu)
+ {
+ maCloseTimer.mpSubMenu->EndPopupMode();
+ maCloseTimer.mpSubMenu = nullptr;
+ maCloseTimer.maTimer.Stop();
+ }
+
+ launchSubMenu();
+ }
+ else if (pTimer == &maCloseTimer)
+ {
+ // end submenu.
+ if (maCloseTimer.mpSubMenu)
+ {
+ maCloseTimer.mpSubMenu->EndPopupMode();
+ maCloseTimer.mpSubMenu = nullptr;
+
+ // EndPopup sends a user event, and we want this focus to be set after that has done its conflicting focus-setting work
+ if (!mnAsyncPostPopdownId)
+ mnAsyncPostPopdownId = Application::PostUserEvent(LINK(this, ScCheckListMenuControl, PostPopdownHdl));
+ }
+ }
+}
+
+void ScCheckListMenuControl::queueLaunchSubMenu(size_t nPos, ScListSubMenuControl* pMenu)
+{
+ if (!pMenu)
+ return;
+
+ // Set the submenu on launch queue.
+ if (maOpenTimer.mpSubMenu)
+ {
+ if (maOpenTimer.mpSubMenu != pMenu)
+ {
+ // new submenu is being requested.
+ queueCloseSubMenu();
+ }
+ else
+ {
+ if (pMenu == maCloseTimer.mpSubMenu)
+ maCloseTimer.reset();
+ }
+ }
+
+ maOpenTimer.mpSubMenu = pMenu;
+ maOpenTimer.mnMenuPos = nPos;
+ if (comphelper::LibreOfficeKit::isActive())
+ maOpenTimer.maTimer.Invoke();
+ else
+ maOpenTimer.maTimer.Start();
+}
+
+void ScCheckListMenuControl::queueCloseSubMenu()
+{
+ if (!maOpenTimer.mpSubMenu)
+ // There is no submenu to close.
+ return;
+
+ // Stop any submenu on queue for opening.
+ maOpenTimer.maTimer.Stop();
+
+ // Flush any pending close so it doesn't get skipped
+ if (maCloseTimer.mpSubMenu)
+ {
+ maCloseTimer.mpSubMenu->EndPopupMode();
+ }
+
+ maCloseTimer.mpSubMenu = maOpenTimer.mpSubMenu;
+ maCloseTimer.mnMenuPos = maOpenTimer.mnMenuPos;
+ maOpenTimer.mpSubMenu = nullptr;
+ maOpenTimer.mnMenuPos = MENU_NOT_SELECTED;
+
+ if (comphelper::LibreOfficeKit::isActive())
+ maCloseTimer.maTimer.Invoke();
+ else
+ maCloseTimer.maTimer.Start();
+}
+
+tools::Rectangle ScCheckListMenuControl::GetSubMenuParentRect()
+{
+ if (!mxMenu->get_selected(mxScratchIter.get()))
+ return tools::Rectangle();
+ return mxMenu->get_row_area(*mxScratchIter);
+}
+
+void ScCheckListMenuControl::launchSubMenu()
+{
+ ScListSubMenuControl* pSubMenu = maOpenTimer.mpSubMenu;
+ if (!pSubMenu)
+ return;
+
+ if (!mxMenu->get_selected(mxScratchIter.get()))
+ return;
+
+ tools::Rectangle aRect = GetSubMenuParentRect();
+ pSubMenu->StartPopupMode(mxMenu.get(), aRect);
+
+ mxMenu->select(*mxScratchIter);
+ pSubMenu->GrabFocus();
+}
+
+IMPL_LINK_NOARG(ScCheckListMenuControl, PostPopdownHdl, void*, void)
+{
+ mnAsyncPostPopdownId = nullptr;
+ mxMenu->grab_focus();
+}
+
+IMPL_LINK(ScCheckListMenuControl, MouseEnterHdl, const MouseEvent&, rMEvt, bool)
+{
+ if (!rMEvt.IsEnterWindow())
+ return false;
+ selectMenuItem(MENU_NOT_SELECTED, true);
+ return false;
+}
+
+void ScCheckListMenuControl::endSubMenu(ScListSubMenuControl& rSubMenu)
+{
+ rSubMenu.EndPopupMode();
+ maOpenTimer.reset();
+
+ // EndPopup sends a user event, and we want this focus to be set after that has done its conflicting focus-setting work
+ if (!mnAsyncPostPopdownId)
+ mnAsyncPostPopdownId = Application::PostUserEvent(LINK(this, ScCheckListMenuControl, PostPopdownHdl));
+
+ size_t nMenuPos = getSubMenuPos(&rSubMenu);
+ if (nMenuPos != MENU_NOT_SELECTED)
+ {
+ mnSelectedMenu = nMenuPos;
+ mxMenu->select(mnSelectedMenu);
+ }
+}
+
+void ScCheckListMenuControl::selectMenuItem(size_t nPos, bool bSubMenuTimer)
+{
+ mxMenu->select(nPos == MENU_NOT_SELECTED ? -1 : nPos);
+ mnSelectedMenu = nPos;
+
+ if (nPos >= maMenuItems.size() || nPos == MENU_NOT_SELECTED)
+ {
+ queueCloseSubMenu();
+ return;
+ }
+
+ if (!maMenuItems[nPos].mbEnabled)
+ {
+ queueCloseSubMenu();
+ return;
+ }
+
+ if (bSubMenuTimer)
+ {
+ if (maMenuItems[nPos].mxSubMenuWin && mxMenu->changed_by_hover())
+ {
+ ScListSubMenuControl* pSubMenu = maMenuItems[nPos].mxSubMenuWin.get();
+ queueLaunchSubMenu(nPos, pSubMenu);
+ }
+ else
+ queueCloseSubMenu();
+ }
+}
+
+void ScCheckListMenuControl::clearSelectedMenuItem()
+{
+ selectMenuItem(MENU_NOT_SELECTED, false);
+}
+
+size_t ScCheckListMenuControl::getSubMenuPos(const ScListSubMenuControl* pSubMenu)
+{
+ size_t n = maMenuItems.size();
+ for (size_t i = 0; i < n; ++i)
+ {
+ if (maMenuItems[i].mxSubMenuWin.get() == pSubMenu)
+ return i;
+ }
+ return MENU_NOT_SELECTED;
+}
+
+void ScCheckListMenuControl::setSubMenuFocused(const ScListSubMenuControl* pSubMenu)
+{
+ maCloseTimer.reset();
+ size_t nMenuPos = getSubMenuPos(pSubMenu);
+ if (mnSelectedMenu != nMenuPos)
+ {
+ mnSelectedMenu = nMenuPos;
+ mxMenu->select(mnSelectedMenu);
+ }
+}
+
+void ScCheckListMenuControl::EndPopupMode()
+{
+ if (!mbIsPoppedUp)
+ return;
+ mxPopover->connect_closed(Link<weld::Popover&, void>());
+ mxPopover->popdown();
+ PopupModeEndHdl(*mxPopover);
+ assert(mbIsPoppedUp == false);
+}
+
+void ScCheckListMenuControl::StartPopupMode(weld::Widget* pParent, const tools::Rectangle& rRect)
+{
+ mxPopover->connect_closed(LINK(this, ScCheckListMenuControl, PopupModeEndHdl));
+ mbIsPoppedUp = true;
+ mxPopover->popup_at_rect(pParent, rRect);
+ GrabFocus();
+}
+
+void ScCheckListMenuControl::terminateAllPopupMenus()
+{
+ EndPopupMode();
+}
+
+ScCheckListMenuControl::Config::Config() :
+ mbAllowEmptySet(true), mbRTL(false)
+{
+}
+
+ScCheckListMember::ScCheckListMember()
+ : mnValue(0.0)
+ , mbVisible(true)
+ , mbDate(false)
+ , mbLeaf(false)
+ , mbValue(false)
+ , meDatePartType(YEAR)
+{
+}
+
+// the value of border-width of FilterDropDown
+constexpr int nBorderWidth = 4;
+// number of rows visible in checklist
+constexpr int nCheckListVisibleRows = 9;
+// number of rows visible in colorlist
+constexpr int nColorListVisibleRows = 9;
+
+ScCheckListMenuControl::ScCheckListMenuControl(weld::Widget* pParent, ScViewData& rViewData,
+ bool bHasDates, int nWidth)
+ : mxBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/filterdropdown.ui"))
+ , mxPopover(mxBuilder->weld_popover("FilterDropDown"))
+ , mxContainer(mxBuilder->weld_container("container"))
+ , mxMenu(mxBuilder->weld_tree_view("menu"))
+ , mxScratchIter(mxMenu->make_iterator())
+ , mxNonMenu(mxBuilder->weld_widget("nonmenu"))
+ , mxEdSearch(mxBuilder->weld_entry("search_edit"))
+ , mxBox(mxBuilder->weld_widget("box"))
+ , mxListChecks(mxBuilder->weld_tree_view("check_list_box"))
+ , mxTreeChecks(mxBuilder->weld_tree_view("check_tree_box"))
+ , mxChkToggleAll(mxBuilder->weld_check_button("toggle_all"))
+ , mxBtnSelectSingle(mxBuilder->weld_button("select_current"))
+ , mxBtnUnselectSingle(mxBuilder->weld_button("unselect_current"))
+ , mxButtonBox(mxBuilder->weld_box("buttonbox"))
+ , mxBtnOk(mxBuilder->weld_button("ok"))
+ , mxBtnCancel(mxBuilder->weld_button("cancel"))
+ , mxContextMenu(mxBuilder->weld_menu("contextmenu"))
+ , mxDropDown(mxMenu->create_virtual_device())
+ , mnCheckWidthReq(-1)
+ , mnWndWidth(0)
+ , mnCheckListVisibleRows(nCheckListVisibleRows)
+ , mePrevToggleAllState(TRISTATE_INDET)
+ , mnSelectedMenu(MENU_NOT_SELECTED)
+ , mrViewData(rViewData)
+ , mnAsyncPostPopdownId(nullptr)
+ , mnAsyncSetDropdownPosId(nullptr)
+ , mbHasDates(bHasDates)
+ , mbIsPoppedUp(false)
+ , maOpenTimer(this)
+ , maCloseTimer(this)
+{
+ mxTreeChecks->set_clicks_to_toggle(1);
+ mxListChecks->set_clicks_to_toggle(1);
+
+ mxNonMenu->connect_mouse_move(LINK(this, ScCheckListMenuControl, MouseEnterHdl));
+ mxEdSearch->connect_mouse_move(LINK(this, ScCheckListMenuControl, MouseEnterHdl));
+ mxListChecks->connect_mouse_move(LINK(this, ScCheckListMenuControl, MouseEnterHdl));
+ mxTreeChecks->connect_mouse_move(LINK(this, ScCheckListMenuControl, MouseEnterHdl));
+ mxListChecks->connect_popup_menu(LINK(this, ScCheckListMenuControl, CommandHdl));
+ mxTreeChecks->connect_popup_menu(LINK(this, ScCheckListMenuControl, CommandHdl));
+ mxChkToggleAll->connect_mouse_move(LINK(this, ScCheckListMenuControl, MouseEnterHdl));
+ mxBtnSelectSingle->connect_mouse_move(LINK(this, ScCheckListMenuControl, MouseEnterHdl));
+ mxBtnUnselectSingle->connect_mouse_move(LINK(this, ScCheckListMenuControl, MouseEnterHdl));
+ mxBtnOk->connect_mouse_move(LINK(this, ScCheckListMenuControl, MouseEnterHdl));
+ mxBtnCancel->connect_mouse_move(LINK(this, ScCheckListMenuControl, MouseEnterHdl));
+
+ /*
+ tdf#136559 If we have no dates we don't need a tree
+ structure, just a list. GtkListStore can be then
+ used which is much faster than a GtkTreeStore, so
+ with no dates switch to the treeview which uses the
+ faster GtkListStore
+ */
+ if (mbHasDates)
+ mpChecks = mxTreeChecks.get();
+ else
+ {
+ mxTreeChecks->hide();
+ mxListChecks->show();
+ mpChecks = mxListChecks.get();
+ }
+
+ int nChecksHeight = mxTreeChecks->get_height_rows(mnCheckListVisibleRows);
+ if (nWidth != -1)
+ {
+ mnCheckWidthReq = nWidth - nBorderWidth * 2 - 4;
+ mxTreeChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+ mxListChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+ }
+
+ // sort ok/cancel into native order, if this was a dialog they would be auto-sorted, but this
+ // popup isn't a true dialog
+ mxButtonBox->sort_native_button_order();
+
+ mxTreeChecks->enable_toggle_buttons(weld::ColumnToggleType::Check);
+ mxListChecks->enable_toggle_buttons(weld::ColumnToggleType::Check);
+
+ mxBox->show();
+ mxEdSearch->show();
+ mxButtonBox->show();
+
+ mxMenu->connect_row_activated(LINK(this, ScCheckListMenuControl, RowActivatedHdl));
+ mxMenu->connect_changed(LINK(this, ScCheckListMenuControl, SelectHdl));
+ mxMenu->connect_key_press(LINK(this, ScCheckListMenuControl, MenuKeyInputHdl));
+
+ mxBtnOk->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
+ mxBtnCancel->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
+ mxEdSearch->connect_changed(LINK(this, ScCheckListMenuControl, EdModifyHdl));
+ mxEdSearch->connect_activate(LINK(this, ScCheckListMenuControl, EdActivateHdl));
+ mxTreeChecks->connect_toggled(LINK(this, ScCheckListMenuControl, CheckHdl));
+ mxTreeChecks->connect_key_press(LINK(this, ScCheckListMenuControl, KeyInputHdl));
+ mxListChecks->connect_toggled(LINK(this, ScCheckListMenuControl, CheckHdl));
+ mxListChecks->connect_key_press(LINK(this, ScCheckListMenuControl, KeyInputHdl));
+ mxChkToggleAll->connect_toggled(LINK(this, ScCheckListMenuControl, TriStateHdl));
+ mxBtnSelectSingle->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
+ mxBtnUnselectSingle->connect_clicked(LINK(this, ScCheckListMenuControl, ButtonHdl));
+
+ CreateDropDown();
+ mxMenu->connect_size_allocate(LINK(this, ScCheckListMenuControl, TreeSizeAllocHdl));
+
+ // determine what width the checklist will end up with
+ mnCheckWidthReq = mxContainer->get_preferred_size().Width();
+ // make that size fixed now, we can now use mnCheckWidthReq to speed up
+ // bulk_insert_for_each
+ mxTreeChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+ mxListChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+}
+
+void ScCheckListMenuControl::GrabFocus()
+{
+ if (mxEdSearch->get_visible())
+ mxEdSearch->grab_focus();
+ else
+ {
+ mxMenu->set_cursor(0);
+ mxMenu->grab_focus();
+ }
+}
+
+void ScCheckListMenuControl::DropPendingEvents()
+{
+ if (mnAsyncPostPopdownId)
+ {
+ Application::RemoveUserEvent(mnAsyncPostPopdownId);
+ mnAsyncPostPopdownId = nullptr;
+ }
+ if (mnAsyncSetDropdownPosId)
+ {
+ Application::RemoveUserEvent(mnAsyncSetDropdownPosId);
+ mnAsyncSetDropdownPosId = nullptr;
+ }
+}
+
+ScCheckListMenuControl::~ScCheckListMenuControl()
+{
+ EndPopupMode();
+ for (auto& rMenuItem : maMenuItems)
+ rMenuItem.mxSubMenuWin.reset();
+ DropPendingEvents();
+}
+
+void ScCheckListMenuControl::prepWindow()
+{
+ mxMenu->set_size_request(-1, mxMenu->get_preferred_size().Height() + 2);
+ mnSelectedMenu = MENU_NOT_SELECTED;
+ if (mxMenu->n_children())
+ {
+ mxMenu->set_cursor(0);
+ mxMenu->unselect_all();
+ }
+
+ mnWndWidth = mxContainer->get_preferred_size().Width() + nBorderWidth * 2 + 4;
+}
+
+void ScCheckListMenuControl::setAllMemberState(bool bSet)
+{
+ mpChecks->all_foreach([this, bSet](weld::TreeIter& rEntry){
+ mpChecks->set_toggle(rEntry, bSet ? TRISTATE_TRUE : TRISTATE_FALSE);
+ return false;
+ });
+
+ if (!maConfig.mbAllowEmptySet)
+ {
+ // We need to have at least one member selected.
+ mxBtnOk->set_sensitive(GetCheckedEntryCount() != 0);
+ }
+}
+
+void ScCheckListMenuControl::selectCurrentMemberOnly(bool bSet)
+{
+ setAllMemberState(!bSet);
+ std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator();
+ if (!mpChecks->get_cursor(xEntry.get()))
+ return;
+ mpChecks->set_toggle(*xEntry, bSet ? TRISTATE_TRUE : TRISTATE_FALSE);
+}
+
+IMPL_LINK(ScCheckListMenuControl, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ mxContextMenu->set_sensitive("less", mnCheckListVisibleRows > 4);
+ mxContextMenu->set_sensitive("more", mnCheckListVisibleRows < 42);
+
+ OString sCommand = mxContextMenu->popup_at_rect(mpChecks, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
+ if (sCommand.isEmpty())
+ return true;
+
+ if (sCommand == "more")
+ ++mnCheckListVisibleRows;
+ else if (sCommand == "less")
+ --mnCheckListVisibleRows;
+ ResizeToRequest();
+
+ return true;
+}
+
+void ScCheckListMenuControl::ResizeToRequest()
+{
+ int nChecksHeight = mxTreeChecks->get_height_rows(mnCheckListVisibleRows);
+ mxTreeChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+ mxListChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+ mxPopover->resize_to_request();
+}
+
+IMPL_LINK(ScCheckListMenuControl, ButtonHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == mxBtnOk.get())
+ close(true);
+ else if (&rBtn == mxBtnCancel.get())
+ close(false);
+ else if (&rBtn == mxBtnSelectSingle.get() || &rBtn == mxBtnUnselectSingle.get())
+ {
+ selectCurrentMemberOnly(&rBtn == mxBtnSelectSingle.get());
+ std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator();
+ if (!mpChecks->get_cursor(xEntry.get()))
+ xEntry.reset();
+ Check(xEntry.get());
+ }
+}
+
+IMPL_LINK_NOARG(ScCheckListMenuControl, TriStateHdl, weld::Toggleable&, void)
+{
+ switch (mePrevToggleAllState)
+ {
+ case TRISTATE_FALSE:
+ mxChkToggleAll->set_state(TRISTATE_TRUE);
+ setAllMemberState(true);
+ break;
+ case TRISTATE_TRUE:
+ mxChkToggleAll->set_state(TRISTATE_FALSE);
+ setAllMemberState(false);
+ break;
+ case TRISTATE_INDET:
+ default:
+ mxChkToggleAll->set_state(TRISTATE_TRUE);
+ setAllMemberState(true);
+ break;
+ }
+
+ mePrevToggleAllState = mxChkToggleAll->get_state();
+}
+
+namespace
+{
+ void insertMember(weld::TreeView& rView, const weld::TreeIter& rIter, const ScCheckListMember& rMember, bool bChecked)
+ {
+ OUString aLabel = rMember.maName;
+ if (aLabel.isEmpty())
+ aLabel = ScResId(STR_EMPTYDATA);
+ rView.set_toggle(rIter, bChecked ? TRISTATE_TRUE : TRISTATE_FALSE);
+ rView.set_text(rIter, aLabel, 0);
+ }
+}
+
+IMPL_LINK_NOARG(ScCheckListMenuControl, EdModifyHdl, weld::Entry&, void)
+{
+ OUString aSearchText = mxEdSearch->get_text();
+ aSearchText = ScGlobal::getCharClass().lowercase( aSearchText );
+ bool bSearchTextEmpty = aSearchText.isEmpty();
+ size_t n = maMembers.size();
+ size_t nSelCount = 0;
+
+ // This branch is the general case, the other is an optimized variant of
+ // this one where we can take advantage of knowing we have no hierarchy
+ if (mbHasDates)
+ {
+ mpChecks->freeze();
+
+ bool bSomeDateDeletes = false;
+
+ for (size_t i = 0; i < n; ++i)
+ {
+ bool bIsDate = maMembers[i].mbDate;
+ bool bPartialMatch = false;
+
+ OUString aLabelDisp = maMembers[i].maName;
+ if ( aLabelDisp.isEmpty() )
+ aLabelDisp = ScResId( STR_EMPTYDATA );
+
+ if ( !bSearchTextEmpty )
+ {
+ if ( !bIsDate )
+ bPartialMatch = ( ScGlobal::getCharClass().lowercase( aLabelDisp ).indexOf( aSearchText ) != -1 );
+ else if ( maMembers[i].meDatePartType == ScCheckListMember::DAY ) // Match with both numerical and text version of month
+ bPartialMatch = (ScGlobal::getCharClass().lowercase( OUString(
+ maMembers[i].maRealName + maMembers[i].maDateParts[1] )).indexOf( aSearchText ) != -1);
+ else
+ continue;
+ }
+ else if ( bIsDate && maMembers[i].meDatePartType != ScCheckListMember::DAY )
+ continue;
+
+ if ( bSearchTextEmpty )
+ {
+ auto xLeaf = ShowCheckEntry(aLabelDisp, maMembers[i], true, maMembers[i].mbVisible);
+ updateMemberParents(xLeaf.get(), i);
+ if ( maMembers[i].mbVisible )
+ ++nSelCount;
+ continue;
+ }
+
+ if ( bPartialMatch )
+ {
+ auto xLeaf = ShowCheckEntry(aLabelDisp, maMembers[i]);
+ updateMemberParents(xLeaf.get(), i);
+ ++nSelCount;
+ }
+ else
+ {
+ ShowCheckEntry(aLabelDisp, maMembers[i], false, false);
+ if( bIsDate )
+ bSomeDateDeletes = true;
+ }
+ }
+
+ if ( bSomeDateDeletes )
+ {
+ for (size_t i = 0; i < n; ++i)
+ {
+ if (!maMembers[i].mbDate)
+ continue;
+ if (maMembers[i].meDatePartType != ScCheckListMember::DAY)
+ continue;
+ updateMemberParents(nullptr, i);
+ }
+ }
+
+ mpChecks->thaw();
+ }
+ else
+ {
+ mpChecks->freeze();
+
+ // when there are a lot of rows, it is cheaper to simply clear the tree and either
+ // re-initialise or just insert the filtered lines
+ mpChecks->clear();
+
+ mpChecks->thaw();
+
+ if (bSearchTextEmpty)
+ nSelCount = initMembers();
+ else
+ {
+ std::vector<size_t> aShownIndexes;
+
+ for (size_t i = 0; i < n; ++i)
+ {
+ assert(!maMembers[i].mbDate);
+
+ OUString aLabelDisp = maMembers[i].maName;
+ if ( aLabelDisp.isEmpty() )
+ aLabelDisp = ScResId( STR_EMPTYDATA );
+
+ bool bPartialMatch = ScGlobal::getCharClass().lowercase( aLabelDisp ).indexOf( aSearchText ) != -1;
+
+ if (!bPartialMatch)
+ continue;
+
+ aShownIndexes.push_back(i);
+ }
+
+ std::vector<int> aFixedWidths { mnCheckWidthReq };
+ // tdf#122419 insert in the fastest order, this might be backwards.
+ mpChecks->bulk_insert_for_each(aShownIndexes.size(), [this, &aShownIndexes, &nSelCount](weld::TreeIter& rIter, int i) {
+ size_t nIndex = aShownIndexes[i];
+ insertMember(*mpChecks, rIter, maMembers[nIndex], true);
+ ++nSelCount;
+ }, nullptr, &aFixedWidths);
+ }
+ }
+
+ if ( nSelCount == n )
+ mxChkToggleAll->set_state( TRISTATE_TRUE );
+ else if ( nSelCount == 0 )
+ mxChkToggleAll->set_state( TRISTATE_FALSE );
+ else
+ mxChkToggleAll->set_state( TRISTATE_INDET );
+
+ if ( !maConfig.mbAllowEmptySet )
+ {
+ const bool bEmptySet( nSelCount == 0 );
+ mpChecks->set_sensitive(!bEmptySet);
+ mxChkToggleAll->set_sensitive(!bEmptySet);
+ mxBtnSelectSingle->set_sensitive(!bEmptySet);
+ mxBtnUnselectSingle->set_sensitive(!bEmptySet);
+ mxBtnOk->set_sensitive(!bEmptySet);
+ }
+}
+
+IMPL_LINK_NOARG(ScCheckListMenuControl, EdActivateHdl, weld::Entry&, bool)
+{
+ if (mxBtnOk->get_sensitive())
+ close(true);
+ return true;
+}
+
+IMPL_LINK( ScCheckListMenuControl, CheckHdl, const weld::TreeView::iter_col&, rRowCol, void )
+{
+ Check(&rRowCol.first);
+}
+
+void ScCheckListMenuControl::Check(const weld::TreeIter* pEntry)
+{
+ if (pEntry)
+ CheckEntry(*pEntry, mpChecks->get_toggle(*pEntry) == TRISTATE_TRUE);
+ size_t nNumChecked = GetCheckedEntryCount();
+ if (nNumChecked == maMembers.size())
+ // all members visible
+ mxChkToggleAll->set_state(TRISTATE_TRUE);
+ else if (nNumChecked == 0)
+ // no members visible
+ mxChkToggleAll->set_state(TRISTATE_FALSE);
+ else
+ mxChkToggleAll->set_state(TRISTATE_INDET);
+
+ if (!maConfig.mbAllowEmptySet)
+ // We need to have at least one member selected.
+ mxBtnOk->set_sensitive(nNumChecked != 0);
+
+ mePrevToggleAllState = mxChkToggleAll->get_state();
+}
+
+void ScCheckListMenuControl::updateMemberParents(const weld::TreeIter* pLeaf, size_t nIdx)
+{
+ if ( !maMembers[nIdx].mbDate || maMembers[nIdx].meDatePartType != ScCheckListMember::DAY )
+ return;
+
+ OUString aYearName = maMembers[nIdx].maDateParts[0];
+ OUString aMonthName = maMembers[nIdx].maDateParts[1];
+ auto aItr = maYearMonthMap.find(aYearName + aMonthName);
+
+ if ( pLeaf )
+ {
+ std::unique_ptr<weld::TreeIter> xYearEntry;
+ std::unique_ptr<weld::TreeIter> xMonthEntry = mpChecks->make_iterator(pLeaf);
+ if (!mpChecks->iter_parent(*xMonthEntry))
+ xMonthEntry.reset();
+ else
+ {
+ xYearEntry = mpChecks->make_iterator(xMonthEntry.get());
+ if (!mpChecks->iter_parent(*xYearEntry))
+ xYearEntry.reset();
+ }
+
+ maMembers[nIdx].mxParent = std::move(xMonthEntry);
+ if ( aItr != maYearMonthMap.end() )
+ {
+ size_t nMonthIdx = aItr->second;
+ maMembers[nMonthIdx].mxParent = std::move(xYearEntry);
+ }
+ }
+ else
+ {
+ std::unique_ptr<weld::TreeIter> xYearEntry = FindEntry(nullptr, aYearName);
+ if (aItr != maYearMonthMap.end() && !xYearEntry)
+ {
+ size_t nMonthIdx = aItr->second;
+ maMembers[nMonthIdx].mxParent.reset();
+ maMembers[nIdx].mxParent.reset();
+ }
+ else if (xYearEntry && !FindEntry(xYearEntry.get(), aMonthName))
+ maMembers[nIdx].mxParent.reset();
+ }
+}
+
+void ScCheckListMenuControl::setMemberSize(size_t n)
+{
+ maMembers.reserve(n);
+}
+
+void ScCheckListMenuControl::addDateMember(const OUString& rsName, double nVal, bool bVisible)
+{
+ SvNumberFormatter* pFormatter = mrViewData.GetDocument().GetFormatTable();
+
+ // Convert the numeric date value to a date object.
+ Date aDate = pFormatter->GetNullDate();
+ aDate.AddDays(rtl::math::approxFloor(nVal));
+
+ sal_Int16 nYear = aDate.GetYear();
+ sal_uInt16 nMonth = aDate.GetMonth();
+ sal_uInt16 nDay = aDate.GetDay();
+
+ // Get the localized month name list.
+ CalendarWrapper& rCalendar = ScGlobal::GetCalendar();
+ uno::Sequence<i18n::CalendarItem2> aMonths = rCalendar.getMonths();
+ if (aMonths.getLength() < nMonth)
+ return;
+
+ OUString aYearName = OUString::number(nYear);
+ OUString aMonthName = aMonths[nMonth-1].FullName;
+ OUString aDayName = OUString::number(nDay);
+
+ if ( aDayName.getLength() == 1 )
+ aDayName = "0" + aDayName;
+
+ mpChecks->freeze();
+
+ std::unique_ptr<weld::TreeIter> xYearEntry = FindEntry(nullptr, aYearName);
+ if (!xYearEntry)
+ {
+ xYearEntry = mpChecks->make_iterator();
+ mpChecks->insert(nullptr, -1, nullptr, nullptr, nullptr, nullptr, false, xYearEntry.get());
+ mpChecks->set_toggle(*xYearEntry, TRISTATE_FALSE);
+ mpChecks->set_text(*xYearEntry, aYearName, 0);
+ ScCheckListMember aMemYear;
+ aMemYear.maName = aYearName;
+ aMemYear.maRealName = rsName;
+ aMemYear.mbDate = true;
+ aMemYear.mbLeaf = false;
+ aMemYear.mbVisible = bVisible;
+ aMemYear.mxParent.reset();
+ aMemYear.meDatePartType = ScCheckListMember::YEAR;
+ maMembers.emplace_back(std::move(aMemYear));
+ }
+
+ std::unique_ptr<weld::TreeIter> xMonthEntry = FindEntry(xYearEntry.get(), aMonthName);
+ if (!xMonthEntry)
+ {
+ xMonthEntry = mpChecks->make_iterator();
+ mpChecks->insert(xYearEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xMonthEntry.get());
+ mpChecks->set_toggle(*xMonthEntry, TRISTATE_FALSE);
+ mpChecks->set_text(*xMonthEntry, aMonthName, 0);
+ ScCheckListMember aMemMonth;
+ aMemMonth.maName = aMonthName;
+ aMemMonth.maRealName = rsName;
+ aMemMonth.mbDate = true;
+ aMemMonth.mbLeaf = false;
+ aMemMonth.mbVisible = bVisible;
+ aMemMonth.mxParent = std::move(xYearEntry);
+ aMemMonth.meDatePartType = ScCheckListMember::MONTH;
+ maMembers.emplace_back(std::move(aMemMonth));
+ maYearMonthMap[aYearName + aMonthName] = maMembers.size() - 1;
+ }
+
+ std::unique_ptr<weld::TreeIter> xDayEntry = FindEntry(xMonthEntry.get(), aDayName);
+ if (!xDayEntry)
+ {
+ xDayEntry = mpChecks->make_iterator();
+ mpChecks->insert(xMonthEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xDayEntry.get());
+ mpChecks->set_toggle(*xDayEntry, TRISTATE_FALSE);
+ mpChecks->set_text(*xDayEntry, aDayName, 0);
+ ScCheckListMember aMemDay;
+ aMemDay.maName = aDayName;
+ aMemDay.maRealName = rsName;
+ aMemDay.maDateParts.resize(2);
+ aMemDay.maDateParts[0] = aYearName;
+ aMemDay.maDateParts[1] = aMonthName;
+ aMemDay.mbDate = true;
+ aMemDay.mbLeaf = true;
+ aMemDay.mbVisible = bVisible;
+ aMemDay.mxParent = std::move(xMonthEntry);
+ aMemDay.meDatePartType = ScCheckListMember::DAY;
+ maMembers.emplace_back(std::move(aMemDay));
+ }
+
+ mpChecks->thaw();
+}
+
+void ScCheckListMenuControl::addMember(const OUString& rName, const double nVal, bool bVisible, bool bValue)
+{
+ ScCheckListMember aMember;
+ // tdf#46062 - indicate hidden whitespaces using quotes
+ aMember.maName = o3tl::trim(rName) != rName ? "\"" + rName + "\"" : rName;
+ aMember.maRealName = rName;
+ aMember.mnValue = nVal;
+ aMember.mbDate = false;
+ aMember.mbLeaf = true;
+ aMember.mbValue = bValue;
+ aMember.mbVisible = bVisible;
+ aMember.mxParent.reset();
+ maMembers.emplace_back(std::move(aMember));
+}
+
+std::unique_ptr<weld::TreeIter> ScCheckListMenuControl::FindEntry(const weld::TreeIter* pParent, std::u16string_view sNode)
+{
+ std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator(pParent);
+ bool bEntry = pParent ? mpChecks->iter_children(*xEntry) : mpChecks->get_iter_first(*xEntry);
+ while (bEntry)
+ {
+ if (sNode == mpChecks->get_text(*xEntry, 0))
+ return xEntry;
+ bEntry = mpChecks->iter_next_sibling(*xEntry);
+ }
+ return nullptr;
+}
+
+void ScCheckListMenuControl::GetRecursiveChecked(const weld::TreeIter* pEntry, std::unordered_set<OUString>& vOut,
+ OUString& rLabel)
+{
+ if (mpChecks->get_toggle(*pEntry) != TRISTATE_TRUE)
+ return;
+
+ // We have to hash parents and children together.
+ // Per convention for easy access in getResult()
+ // "child;parent;grandparent" while descending.
+ if (rLabel.isEmpty())
+ rLabel = mpChecks->get_text(*pEntry, 0);
+ else
+ rLabel = mpChecks->get_text(*pEntry, 0) + ";" + rLabel;
+
+ // Prerequisite: the selection mechanism guarantees that if a child is
+ // selected then also the parent is selected, so we only have to
+ // inspect the children in case the parent is selected.
+ if (!mpChecks->iter_has_child(*pEntry))
+ return;
+
+ std::unique_ptr<weld::TreeIter> xChild(mpChecks->make_iterator(pEntry));
+ bool bChild = mpChecks->iter_children(*xChild);
+ while (bChild)
+ {
+ OUString aLabel = rLabel;
+ GetRecursiveChecked(xChild.get(), vOut, aLabel);
+ if (!aLabel.isEmpty() && aLabel != rLabel)
+ vOut.insert(aLabel);
+ bChild = mpChecks->iter_next_sibling(*xChild);
+ }
+ // Let the caller not add the parent alone.
+ rLabel.clear();
+}
+
+std::unordered_set<OUString> ScCheckListMenuControl::GetAllChecked()
+{
+ std::unordered_set<OUString> vResults(0);
+
+ std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator();
+ bool bEntry = mpChecks->get_iter_first(*xEntry);
+ while (bEntry)
+ {
+ OUString aLabel;
+ GetRecursiveChecked(xEntry.get(), vResults, aLabel);
+ if (!aLabel.isEmpty())
+ vResults.insert(aLabel);
+ bEntry = mpChecks->iter_next_sibling(*xEntry);
+ }
+
+ return vResults;
+}
+
+bool ScCheckListMenuControl::IsChecked(std::u16string_view sName, const weld::TreeIter* pParent)
+{
+ std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pParent, sName);
+ return xEntry && mpChecks->get_toggle(*xEntry) == TRISTATE_TRUE;
+}
+
+void ScCheckListMenuControl::CheckEntry(std::u16string_view sName, const weld::TreeIter* pParent, bool bCheck)
+{
+ std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pParent, sName);
+ if (xEntry)
+ CheckEntry(*xEntry, bCheck);
+}
+
+// Recursively check all children of rParent
+void ScCheckListMenuControl::CheckAllChildren(const weld::TreeIter& rParent, bool bCheck)
+{
+ mpChecks->set_toggle(rParent, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE);
+ std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator(&rParent);
+ bool bEntry = mpChecks->iter_children(*xEntry);
+ while (bEntry)
+ {
+ CheckAllChildren(*xEntry, bCheck);
+ bEntry = mpChecks->iter_next_sibling(*xEntry);
+ }
+}
+
+void ScCheckListMenuControl::CheckEntry(const weld::TreeIter& rParent, bool bCheck)
+{
+ // recursively check all items below rParent
+ CheckAllChildren(rParent, bCheck);
+ // checking rParent can affect ancestors, e.g. if ancestor is unchecked and rParent is
+ // now checked then the ancestor needs to be checked also
+ if (!mpChecks->get_iter_depth(rParent))
+ return;
+
+ std::unique_ptr<weld::TreeIter> xAncestor(mpChecks->make_iterator(&rParent));
+ bool bAncestor = mpChecks->iter_parent(*xAncestor);
+ while (bAncestor)
+ {
+ // if any first level children checked then ancestor
+ // needs to be checked, similarly if no first level children
+ // checked then ancestor needs to be unchecked
+ std::unique_ptr<weld::TreeIter> xChild(mpChecks->make_iterator(xAncestor.get()));
+ bool bChild = mpChecks->iter_children(*xChild);
+ bool bChildChecked = false;
+
+ while (bChild)
+ {
+ if (mpChecks->get_toggle(*xChild) == TRISTATE_TRUE)
+ {
+ bChildChecked = true;
+ break;
+ }
+ bChild = mpChecks->iter_next_sibling(*xChild);
+ }
+ mpChecks->set_toggle(*xAncestor, bChildChecked ? TRISTATE_TRUE : TRISTATE_FALSE);
+ bAncestor = mpChecks->iter_parent(*xAncestor);
+ }
+}
+
+std::unique_ptr<weld::TreeIter> ScCheckListMenuControl::ShowCheckEntry(const OUString& sName, ScCheckListMember& rMember, bool bShow, bool bCheck)
+{
+ std::unique_ptr<weld::TreeIter> xEntry;
+ if (!rMember.mbDate || rMember.mxParent)
+ xEntry = FindEntry(rMember.mxParent.get(), sName);
+
+ if ( bShow )
+ {
+ if (!xEntry)
+ {
+ if (rMember.mbDate)
+ {
+ if (rMember.maDateParts.empty())
+ return nullptr;
+
+ std::unique_ptr<weld::TreeIter> xYearEntry = FindEntry(nullptr, rMember.maDateParts[0]);
+ if (!xYearEntry)
+ {
+ xYearEntry = mpChecks->make_iterator();
+ mpChecks->insert(nullptr, -1, nullptr, nullptr, nullptr, nullptr, false, xYearEntry.get());
+ mpChecks->set_toggle(*xYearEntry, TRISTATE_FALSE);
+ mpChecks->set_text(*xYearEntry, rMember.maDateParts[0], 0);
+ }
+ std::unique_ptr<weld::TreeIter> xMonthEntry = FindEntry(xYearEntry.get(), rMember.maDateParts[1]);
+ if (!xMonthEntry)
+ {
+ xMonthEntry = mpChecks->make_iterator();
+ mpChecks->insert(xYearEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xMonthEntry.get());
+ mpChecks->set_toggle(*xMonthEntry, TRISTATE_FALSE);
+ mpChecks->set_text(*xMonthEntry, rMember.maDateParts[1], 0);
+ }
+ std::unique_ptr<weld::TreeIter> xDayEntry = FindEntry(xMonthEntry.get(), rMember.maName);
+ if (!xDayEntry)
+ {
+ xDayEntry = mpChecks->make_iterator();
+ mpChecks->insert(xMonthEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xDayEntry.get());
+ mpChecks->set_toggle(*xDayEntry, TRISTATE_FALSE);
+ mpChecks->set_text(*xDayEntry, rMember.maName, 0);
+ }
+ return xDayEntry; // Return leaf node
+ }
+
+ xEntry = mpChecks->make_iterator();
+ mpChecks->append(xEntry.get());
+ mpChecks->set_toggle(*xEntry, bCheck ? TRISTATE_TRUE : TRISTATE_FALSE);
+ mpChecks->set_text(*xEntry, sName, 0);
+ }
+ else
+ CheckEntry(*xEntry, bCheck);
+ }
+ else if (xEntry)
+ {
+ mpChecks->remove(*xEntry);
+ if (rMember.mxParent)
+ {
+ std::unique_ptr<weld::TreeIter> xParent(mpChecks->make_iterator(rMember.mxParent.get()));
+ while (xParent && !mpChecks->iter_has_child(*xParent))
+ {
+ std::unique_ptr<weld::TreeIter> xTmp(mpChecks->make_iterator(xParent.get()));
+ if (!mpChecks->iter_parent(*xParent))
+ xParent.reset();
+ mpChecks->remove(*xTmp);
+ }
+ }
+ }
+ return nullptr;
+}
+
+int ScCheckListMenuControl::GetCheckedEntryCount() const
+{
+ int nRet = 0;
+
+ mpChecks->all_foreach([this, &nRet](weld::TreeIter& rEntry){
+ if (mpChecks->get_toggle(rEntry) == TRISTATE_TRUE)
+ ++nRet;
+ return false;
+ });
+
+ return nRet;
+}
+
+IMPL_LINK(ScCheckListMenuControl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ const vcl::KeyCode& rKey = rKEvt.GetKeyCode();
+
+ if ( rKey.GetCode() == KEY_RETURN || rKey.GetCode() == KEY_SPACE )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator();
+ bool bEntry = mpChecks->get_cursor(xEntry.get());
+ if (bEntry)
+ {
+ bool bOldCheck = mpChecks->get_toggle(*xEntry) == TRISTATE_TRUE;
+ CheckEntry(*xEntry, !bOldCheck);
+ bool bNewCheck = mpChecks->get_toggle(*xEntry) == TRISTATE_TRUE;
+ if (bOldCheck != bNewCheck)
+ Check(xEntry.get());
+ }
+ return true;
+ }
+
+ return false;
+}
+
+size_t ScCheckListMenuControl::initMembers(int nMaxMemberWidth)
+{
+ size_t n = maMembers.size();
+ size_t nVisMemCount = 0;
+
+ if (nMaxMemberWidth == -1)
+ nMaxMemberWidth = mnCheckWidthReq;
+
+ if (!mpChecks->n_children() && !mbHasDates)
+ {
+ std::vector<int> aFixedWidths { nMaxMemberWidth };
+ // tdf#134038 insert in the fastest order, this might be backwards so only do it for
+ // the !mbHasDates case where no entry depends on another to exist before getting
+ // inserted. We cannot retain pre-existing treeview content, only clear and fill it.
+ mpChecks->bulk_insert_for_each(n, [this, &nVisMemCount](weld::TreeIter& rIter, int i) {
+ assert(!maMembers[i].mbDate);
+ insertMember(*mpChecks, rIter, maMembers[i], maMembers[i].mbVisible);
+ if (maMembers[i].mbVisible)
+ ++nVisMemCount;
+ }, nullptr, &aFixedWidths);
+ }
+ else
+ {
+ mpChecks->freeze();
+
+ std::unique_ptr<weld::TreeIter> xEntry = mpChecks->make_iterator();
+ std::vector<std::unique_ptr<weld::TreeIter>> aExpandRows;
+
+ for (size_t i = 0; i < n; ++i)
+ {
+ if (maMembers[i].mbDate)
+ {
+ CheckEntry(maMembers[i].maName, maMembers[i].mxParent.get(), maMembers[i].mbVisible);
+ // Expand first node of checked dates
+ if (!maMembers[i].mxParent && IsChecked(maMembers[i].maName, maMembers[i].mxParent.get()))
+ {
+ std::unique_ptr<weld::TreeIter> xDateEntry = FindEntry(nullptr, maMembers[i].maName);
+ if (xDateEntry)
+ aExpandRows.emplace_back(std::move(xDateEntry));
+ }
+ }
+ else
+ {
+ mpChecks->append(xEntry.get());
+ insertMember(*mpChecks, *xEntry, maMembers[i], maMembers[i].mbVisible);
+ }
+
+ if (maMembers[i].mbVisible)
+ ++nVisMemCount;
+ }
+
+ mpChecks->thaw();
+
+ for (const auto& rRow : aExpandRows)
+ mpChecks->expand_row(*rRow);
+ }
+
+ if (nVisMemCount == n)
+ {
+ // all members visible
+ mxChkToggleAll->set_state(TRISTATE_TRUE);
+ mePrevToggleAllState = TRISTATE_TRUE;
+ }
+ else if (nVisMemCount == 0)
+ {
+ // no members visible
+ mxChkToggleAll->set_state(TRISTATE_FALSE);
+ mePrevToggleAllState = TRISTATE_FALSE;
+ }
+ else
+ {
+ mxChkToggleAll->set_state(TRISTATE_INDET);
+ mePrevToggleAllState = TRISTATE_INDET;
+ }
+
+ if (nVisMemCount)
+ mpChecks->set_cursor(0);
+
+ return nVisMemCount;
+}
+
+void ScCheckListMenuControl::setConfig(const Config& rConfig)
+{
+ maConfig = rConfig;
+}
+
+bool ScCheckListMenuControl::isAllSelected() const
+{
+ return mxChkToggleAll->get_state() == TRISTATE_TRUE;
+}
+
+void ScCheckListMenuControl::getResult(ResultType& rResult)
+{
+ ResultType aResult;
+ std::unordered_set<OUString> vCheckeds = GetAllChecked();
+ size_t n = maMembers.size();
+ for (size_t i = 0; i < n; ++i)
+ {
+ if ( maMembers[i].mbLeaf )
+ {
+ OUStringBuffer aLabel(maMembers[i].maName);
+ if (aLabel.isEmpty())
+ aLabel = ScResId(STR_EMPTYDATA);
+
+ /* TODO: performance-wise this looks suspicious, concatenating to
+ * do the lookup for each leaf item seems wasteful. */
+ // Checked labels are in the form "child;parent;grandparent".
+ if (maMembers[i].mxParent)
+ {
+ std::unique_ptr<weld::TreeIter> xIter(mpChecks->make_iterator(maMembers[i].mxParent.get()));
+ do
+ {
+ aLabel.append(";" + mpChecks->get_text(*xIter));
+ }
+ while (mpChecks->iter_parent(*xIter));
+ }
+
+ bool bState = vCheckeds.find(aLabel.makeStringAndClear()) != vCheckeds.end();
+
+ ResultEntry aResultEntry;
+ aResultEntry.bValid = bState;
+ aResultEntry.aName = maMembers[i].maRealName;
+ aResultEntry.nValue = maMembers[i].mnValue;
+ aResultEntry.bDate = maMembers[i].mbDate;
+ aResultEntry.bValue = maMembers[i].mbValue;
+ aResult.insert(aResultEntry);
+ }
+ }
+ rResult.swap(aResult);
+}
+
+void ScCheckListMenuControl::launch(weld::Widget* pWidget, const tools::Rectangle& rRect)
+{
+ prepWindow();
+ if (!maConfig.mbAllowEmptySet)
+ // We need to have at least one member selected.
+ mxBtnOk->set_sensitive(GetCheckedEntryCount() != 0);
+
+ tools::Rectangle aRect(rRect);
+ if (maConfig.mbRTL)
+ {
+ // In RTL mode, the logical "left" is visual "right".
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ tools::Long nLeft = aRect.Left() - aRect.GetWidth();
+ aRect.SetLeft( nLeft );
+ }
+ else
+ {
+ // in LOK mode, rRect is in document pixel coordinates, so width has to be added
+ // to place the popup next to the (visual) left aligned button.
+ aRect.Move(aRect.GetWidth(), 0);
+ }
+ }
+ else if (mnWndWidth < aRect.GetWidth())
+ {
+ // Target rectangle (i.e. cell width) is wider than the window.
+ // Simulate right-aligned launch by modifying the target rectangle
+ // size.
+ tools::Long nDiff = aRect.GetWidth() - mnWndWidth;
+ aRect.AdjustLeft(nDiff );
+ }
+
+ StartPopupMode(pWidget, aRect);
+}
+
+void ScCheckListMenuControl::close(bool bOK)
+{
+ if (bOK && mxOKAction)
+ mxOKAction->execute();
+ EndPopupMode();
+}
+
+void ScCheckListMenuControl::setExtendedData(std::unique_ptr<ExtendedData> p)
+{
+ mxExtendedData = std::move(p);
+}
+
+ScCheckListMenuControl::ExtendedData* ScCheckListMenuControl::getExtendedData()
+{
+ return mxExtendedData.get();
+}
+
+void ScCheckListMenuControl::setOKAction(Action* p)
+{
+ mxOKAction.reset(p);
+}
+
+void ScCheckListMenuControl::setPopupEndAction(Action* p)
+{
+ mxPopupEndAction.reset(p);
+}
+
+IMPL_LINK_NOARG(ScCheckListMenuControl, PopupModeEndHdl, weld::Popover&, void)
+{
+ mbIsPoppedUp = false;
+ clearSelectedMenuItem();
+ if (mxPopupEndAction)
+ mxPopupEndAction->execute();
+
+ DropPendingEvents();
+}
+
+int ScCheckListMenuControl::GetTextWidth(const OUString& rsName) const
+{
+ return mxDropDown->GetTextWidth(rsName);
+}
+
+int ScCheckListMenuControl::IncreaseWindowWidthToFitText(int nMaxTextWidth)
+{
+ int nBorder = nBorderWidth * 2 + 4;
+ int nNewWidth = nMaxTextWidth - nBorder;
+ if (nNewWidth > mnCheckWidthReq)
+ {
+ mnCheckWidthReq = nNewWidth;
+ int nChecksHeight = mpChecks->get_height_rows(nCheckListVisibleRows);
+ mpChecks->set_size_request(mnCheckWidthReq, nChecksHeight);
+ }
+ return mnCheckWidthReq + nBorder;
+}
+
+ScListSubMenuControl::ScListSubMenuControl(weld::Widget* pParent, ScCheckListMenuControl& rParentControl, bool bColorMenu)
+ : mxBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/filtersubdropdown.ui"))
+ , mxPopover(mxBuilder->weld_popover("FilterSubDropDown"))
+ , mxContainer(mxBuilder->weld_container("container"))
+ , mxMenu(mxBuilder->weld_tree_view("menu"))
+ , mxBackColorMenu(mxBuilder->weld_tree_view("background"))
+ , mxTextColorMenu(mxBuilder->weld_tree_view("textcolor"))
+ , mxScratchIter(mxMenu->make_iterator())
+ , mrParentControl(rParentControl)
+ , mnBackColorMenuPrefHeight(-1)
+ , mnTextColorMenuPrefHeight(-1)
+ , mbColorMenu(bColorMenu)
+{
+ mxMenu->hide();
+ mxBackColorMenu->hide();
+ mxTextColorMenu->hide();
+
+ if (!bColorMenu)
+ {
+ SetupMenu(*mxMenu);
+ mxMenu->show();
+ }
+ else
+ {
+ mxBackColorMenu->set_clicks_to_toggle(1);
+ mxBackColorMenu->enable_toggle_buttons(weld::ColumnToggleType::Radio);
+ mxBackColorMenu->connect_changed(LINK(this, ScListSubMenuControl, ColorSelChangedHdl));
+ mxTextColorMenu->set_clicks_to_toggle(1);
+ mxTextColorMenu->enable_toggle_buttons(weld::ColumnToggleType::Radio);
+ mxTextColorMenu->connect_changed(LINK(this, ScListSubMenuControl, ColorSelChangedHdl));
+ SetupMenu(*mxBackColorMenu);
+ SetupMenu(*mxTextColorMenu);
+ }
+}
+
+void ScListSubMenuControl::SetupMenu(weld::TreeView& rMenu)
+{
+ rMenu.connect_row_activated(LINK(this, ScListSubMenuControl, RowActivatedHdl));
+ rMenu.connect_key_press(LINK(this, ScListSubMenuControl, MenuKeyInputHdl));
+}
+
+void ScListSubMenuControl::StartPopupMode(weld::Widget* pParent, const tools::Rectangle& rRect)
+{
+ if (mxPopupStartAction)
+ mxPopupStartAction->execute();
+
+ mxPopover->popup_at_rect(pParent, rRect, weld::Placement::End);
+
+ weld::TreeView& rFirstMenu = mbColorMenu ? *mxBackColorMenu : *mxMenu;
+ rFirstMenu.set_cursor(0);
+ rFirstMenu.select(0);
+
+ mrParentControl.setSubMenuFocused(this);
+}
+
+void ScListSubMenuControl::EndPopupMode()
+{
+ mxPopover->popdown();
+}
+
+void ScListSubMenuControl::GrabFocus()
+{
+ weld::TreeView& rFirstMenu = mbColorMenu ? *mxBackColorMenu : *mxMenu;
+ rFirstMenu.grab_focus();
+}
+
+bool ScListSubMenuControl::IsVisible() const
+{
+ return mxPopover->get_visible();
+}
+
+void ScListSubMenuControl::resizeToFitMenuItems()
+{
+ if (!mbColorMenu)
+ mxMenu->set_size_request(-1, mxMenu->get_preferred_size().Height());
+ else
+ {
+ int nBackColorMenuPrefHeight = mnBackColorMenuPrefHeight;
+ if (nBackColorMenuPrefHeight == -1)
+ nBackColorMenuPrefHeight = mxBackColorMenu->get_preferred_size().Height();
+ mxBackColorMenu->set_size_request(-1, nBackColorMenuPrefHeight);
+ int nTextColorMenuPrefHeight = mnTextColorMenuPrefHeight;
+ if (nTextColorMenuPrefHeight == -1)
+ nTextColorMenuPrefHeight = mxTextColorMenu->get_preferred_size().Height();
+ mxTextColorMenu->set_size_request(-1, nTextColorMenuPrefHeight);
+ }
+}
+
+void ScListSubMenuControl::addItem(ScCheckListMenuControl::Action* pAction)
+{
+ ScCheckListMenuControl::MenuItemData aItem;
+ aItem.mbEnabled = true;
+ aItem.mxAction.reset(pAction);
+ maMenuItems.emplace_back(std::move(aItem));
+}
+
+void ScListSubMenuControl::addMenuItem(const OUString& rText, ScCheckListMenuControl::Action* pAction)
+{
+ addItem(pAction);
+ mxMenu->append(weld::toId(pAction), rText);
+}
+
+void ScListSubMenuControl::addMenuColorItem(const OUString& rText, bool bActive, VirtualDevice& rImage,
+ int nMenu, ScCheckListMenuControl::Action* pAction)
+{
+ addItem(pAction);
+
+ weld::TreeView& rColorMenu = nMenu == 0 ? *mxBackColorMenu : *mxTextColorMenu;
+ rColorMenu.show();
+
+ OUString sId = weld::toId(pAction);
+ rColorMenu.insert(nullptr, -1, &rText, &sId, nullptr, nullptr, false, mxScratchIter.get());
+ rColorMenu.set_toggle(*mxScratchIter, bActive ? TRISTATE_TRUE : TRISTATE_FALSE);
+ rColorMenu.set_image(*mxScratchIter, rImage);
+
+ if (mnTextColorMenuPrefHeight == -1 &&
+ &rColorMenu == mxTextColorMenu.get() &&
+ mxTextColorMenu->n_children() == nColorListVisibleRows)
+ {
+ mnTextColorMenuPrefHeight = mxTextColorMenu->get_preferred_size().Height();
+ }
+
+ if (mnBackColorMenuPrefHeight == -1 &&
+ &rColorMenu == mxBackColorMenu.get() &&
+ mxBackColorMenu->n_children() == nColorListVisibleRows)
+ {
+ mnBackColorMenuPrefHeight = mxBackColorMenu->get_preferred_size().Height();
+ }
+}
+
+void ScListSubMenuControl::addSeparator()
+{
+ ScCheckListMenuControl::MenuItemData aItem;
+ maMenuItems.emplace_back(std::move(aItem));
+
+ mxMenu->append_separator("separator" + OUString::number(maMenuItems.size()));
+}
+
+void ScListSubMenuControl::clearMenuItems()
+{
+ maMenuItems.clear();
+ mxMenu->clear();
+ mxBackColorMenu->clear();
+ mnBackColorMenuPrefHeight = -1;
+ mxTextColorMenu->clear();
+ mnTextColorMenuPrefHeight = -1;
+}
+
+IMPL_LINK(ScListSubMenuControl, MenuKeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bConsumed = false;
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+
+ switch (rKeyCode.GetCode())
+ {
+ case KEY_ESCAPE:
+ case KEY_LEFT:
+ {
+ mrParentControl.endSubMenu(*this);
+ bConsumed = true;
+ break;
+ }
+ case KEY_SPACE:
+ case KEY_RETURN:
+ {
+ weld::TreeView& rMenu = !mbColorMenu ? *mxMenu :
+ (mxBackColorMenu->has_focus() ? *mxBackColorMenu : *mxTextColorMenu);
+ // don't toggle checkbutton, go straight to activating entry
+ bConsumed = RowActivatedHdl(rMenu);
+ break;
+ }
+ case KEY_DOWN:
+ {
+ if (mxTextColorMenu->get_visible() &&
+ mxBackColorMenu->has_focus() &&
+ mxBackColorMenu->get_selected_index() == mxBackColorMenu->n_children() - 1)
+ {
+ mxBackColorMenu->unselect_all();
+ mxTextColorMenu->select(0);
+ mxTextColorMenu->set_cursor(0);
+ mxTextColorMenu->grab_focus();
+ bConsumed = true;
+ }
+ break;
+ }
+ case KEY_UP:
+ {
+ if (mxBackColorMenu->get_visible() &&
+ mxTextColorMenu->has_focus() &&
+ mxTextColorMenu->get_selected_index() == 0)
+ {
+ mxTextColorMenu->unselect_all();
+ int nIndex = mxBackColorMenu->n_children() - 1;
+ mxBackColorMenu->select(nIndex);
+ mxBackColorMenu->set_cursor(nIndex);
+ mxBackColorMenu->grab_focus();
+ bConsumed = true;
+ }
+ break;
+ }
+ }
+
+ return bConsumed;
+}
+
+IMPL_LINK(ScListSubMenuControl, ColorSelChangedHdl, weld::TreeView&, rMenu, void)
+{
+ if (rMenu.get_selected_index() == -1)
+ return;
+ if (&rMenu != mxTextColorMenu.get())
+ mxTextColorMenu->unselect_all();
+ else
+ mxBackColorMenu->unselect_all();
+ rMenu.grab_focus();
+}
+
+IMPL_LINK(ScListSubMenuControl, RowActivatedHdl, weld::TreeView&, rMenu, bool)
+{
+ executeMenuItem(weld::fromId<ScCheckListMenuControl::Action*>(rMenu.get_selected_id()));
+ return true;
+}
+
+void ScListSubMenuControl::executeMenuItem(ScCheckListMenuControl::Action* pAction)
+{
+ // if no action is defined.
+ if (!pAction)
+ return;
+
+ const bool bClosePopup = pAction->execute();
+ if (bClosePopup)
+ terminateAllPopupMenus();
+}
+
+void ScListSubMenuControl::setPopupStartAction(ScCheckListMenuControl::Action* p)
+{
+ mxPopupStartAction.reset(p);
+}
+
+void ScListSubMenuControl::terminateAllPopupMenus()
+{
+ EndPopupMode();
+ mrParentControl.terminateAllPopupMenus();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/cctrl/dpcontrol.cxx b/sc/source/ui/cctrl/dpcontrol.cxx
new file mode 100644
index 000000000..4c9fbbc6a
--- /dev/null
+++ b/sc/source/ui/cctrl/dpcontrol.cxx
@@ -0,0 +1,220 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dpcontrol.hxx>
+
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+#include <comphelper/lok.hxx>
+#include <scitems.hxx>
+#include <document.hxx>
+#include <docpool.hxx>
+#include <patattr.hxx>
+
+ScDPFieldButton::ScDPFieldButton(OutputDevice* pOutDev, const StyleSettings* pStyle, const Fraction* pZoomY, ScDocument* pDoc) :
+ mpDoc(pDoc),
+ mpOutDev(pOutDev),
+ mpStyle(pStyle),
+ mbBaseButton(true),
+ mbPopupButton(false),
+ mbHasHiddenMember(false),
+ mbPopupPressed(false),
+ mbPopupLeft(false)
+{
+ if (pZoomY)
+ maZoomY = *pZoomY;
+ else
+ maZoomY = Fraction(1, 1);
+}
+
+ScDPFieldButton::~ScDPFieldButton()
+{
+}
+
+void ScDPFieldButton::setText(const OUString& rText)
+{
+ maText = rText;
+}
+
+void ScDPFieldButton::setBoundingBox(const Point& rPos, const Size& rSize, bool bLayoutRTL)
+{
+ maPos = rPos;
+ maSize = rSize;
+ if (bLayoutRTL)
+ {
+ // rPos is the logical-left position, adjust maPos to visual-left (inside the cell border)
+ maPos.AdjustX( -(maSize.Width() - 1) );
+ }
+}
+
+void ScDPFieldButton::setDrawBaseButton(bool b)
+{
+ mbBaseButton = b;
+}
+
+void ScDPFieldButton::setDrawPopupButton(bool b)
+{
+ mbPopupButton = b;
+}
+
+void ScDPFieldButton::setHasHiddenMember(bool b)
+{
+ mbHasHiddenMember = b;
+}
+
+void ScDPFieldButton::setPopupPressed(bool b)
+{
+ mbPopupPressed = b;
+}
+
+void ScDPFieldButton::setPopupLeft(bool b)
+{
+ mbPopupLeft = b;
+}
+
+void ScDPFieldButton::draw()
+{
+ bool bOldMapEnabled = mpOutDev->IsMapModeEnabled();
+
+ if (mpOutDev->GetMapMode().GetMapUnit() != MapUnit::MapPixel)
+ mpOutDev->EnableMapMode(false);
+
+ if (mbBaseButton)
+ {
+ // Background
+ tools::Rectangle aRect(maPos, maSize);
+ mpOutDev->SetLineColor(mpStyle->GetFaceColor());
+ mpOutDev->SetFillColor(mpStyle->GetFaceColor());
+ mpOutDev->DrawRect(aRect);
+
+ // Border lines
+ mpOutDev->SetLineColor(mpStyle->GetLightColor());
+ mpOutDev->DrawLine(maPos, Point(maPos.X(), maPos.Y()+maSize.Height()-1));
+ mpOutDev->DrawLine(maPos, Point(maPos.X()+maSize.Width()-1, maPos.Y()));
+
+ mpOutDev->SetLineColor(mpStyle->GetShadowColor());
+ mpOutDev->DrawLine(Point(maPos.X(), maPos.Y()+maSize.Height()-1),
+ Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1));
+ mpOutDev->DrawLine(Point(maPos.X()+maSize.Width()-1, maPos.Y()),
+ Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1));
+
+ // Field name.
+ // Get the font and size the same way as in scenario selection (lcl_DrawOneFrame in gridwin4.cxx)
+ vcl::Font aTextFont( mpStyle->GetAppFont() );
+ if ( mpDoc )
+ {
+ // use ScPatternAttr::GetFont only for font size
+ vcl::Font aAttrFont;
+ mpDoc->GetPool()->GetDefaultItem(ATTR_PATTERN).
+ GetFont( aAttrFont, SC_AUTOCOL_BLACK, mpOutDev, &maZoomY );
+ aTextFont.SetFontSize( aAttrFont.GetFontSize() );
+ }
+ mpOutDev->SetFont(aTextFont);
+ mpOutDev->SetTextColor(mpStyle->GetButtonTextColor());
+
+ Point aTextPos = maPos;
+ tools::Long nTHeight = mpOutDev->GetTextHeight();
+ aTextPos.setX(maPos.getX() + 2); // 2 = Margin
+ aTextPos.setY(maPos.getY() + (maSize.Height()-nTHeight)/2);
+
+ mpOutDev->Push(vcl::PushFlags::CLIPREGION);
+ mpOutDev->IntersectClipRegion(aRect);
+ mpOutDev->DrawText(aTextPos, maText);
+ mpOutDev->Pop();
+ }
+
+ if (mbPopupButton)
+ drawPopupButton();
+
+ mpOutDev->EnableMapMode(bOldMapEnabled);
+}
+
+void ScDPFieldButton::getPopupBoundingBox(Point& rPos, Size& rSize) const
+{
+ float fScaleFactor = mpOutDev->GetDPIScaleFactor();
+
+ tools::Long nMaxSize = 18 * fScaleFactor; // Button max size in either dimension
+
+ tools::Long nW = std::min(maSize.getWidth() / 2, nMaxSize);
+ tools::Long nH = std::min(maSize.getHeight(), nMaxSize);
+
+ double fZoom = static_cast<double>(maZoomY) > 1.0 ? static_cast<double>(maZoomY) : 1.0;
+ if (fZoom > 1.0)
+ {
+ nW = fZoom * (nW - 1);
+ nH = fZoom * (nH - 1);
+ }
+
+ // #i114944# AutoFilter button is left-aligned in RTL.
+ // DataPilot button is always right-aligned for now, so text output isn't affected.
+ if (mbPopupLeft)
+ rPos.setX(maPos.getX());
+ else
+ rPos.setX(maPos.getX() + maSize.getWidth() - nW);
+
+ rPos.setY(maPos.getY() + maSize.getHeight() - nH);
+ rSize.setWidth(nW);
+ rSize.setHeight(nH);
+}
+
+void ScDPFieldButton::drawPopupButton()
+{
+ Point aPos;
+ Size aSize;
+ getPopupBoundingBox(aPos, aSize);
+
+ float fScaleFactor = mpOutDev->GetDPIScaleFactor();
+
+ // Background & outer black border
+ mpOutDev->SetLineColor(COL_BLACK);
+ Color aBackgroundColor
+ = mbHasHiddenMember ? mpStyle->GetHighlightColor()
+ : mbPopupPressed ? mpStyle->GetShadowColor() : mpStyle->GetFaceColor();
+ mpOutDev->SetFillColor(aBackgroundColor);
+ mpOutDev->DrawRect(tools::Rectangle(aPos, aSize));
+
+ // the arrowhead
+ Color aArrowColor = mbHasHiddenMember ? mpStyle->GetHighlightTextColor() : mpStyle->GetButtonTextColor();
+ // FIXME: HACK: The following DrawPolygon draws twice in lok rtl mode for some reason.
+ // => one at the correct location with fill (possibly no outline)
+ // => and the other at an x offset with outline and without fill
+ // eg. Replacing this with a DrawRect() does not have any such problems.
+ comphelper::LibreOfficeKit::isActive() ? mpOutDev->SetLineColor() : mpOutDev->SetLineColor(aArrowColor);
+ mpOutDev->SetFillColor(aArrowColor);
+
+ Point aCenter(aPos.X() + (aSize.Width() / 2), aPos.Y() + (aSize.Height() / 2));
+
+ Size aArrowSize(4 * fScaleFactor, 2 * fScaleFactor);
+
+ tools::Polygon aPoly(3);
+ aPoly.SetPoint(Point(aCenter.X() - aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 0);
+ aPoly.SetPoint(Point(aCenter.X() + aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 1);
+ aPoly.SetPoint(Point(aCenter.X(), aCenter.Y() + aArrowSize.Height()), 2);
+ mpOutDev->DrawPolygon(aPoly);
+
+ if (mbHasHiddenMember)
+ {
+ // tiny little box to display in presence of hidden member(s).
+ Point aBoxPos(aPos.X() + aSize.Width() - 5 * fScaleFactor, aPos.Y() + aSize.Height() - 5 * fScaleFactor);
+ Size aBoxSize(3 * fScaleFactor, 3 * fScaleFactor);
+ mpOutDev->DrawRect(tools::Rectangle(aBoxPos, aBoxSize));
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/cctrl/editfield.cxx b/sc/source/ui/cctrl/editfield.cxx
new file mode 100644
index 000000000..fd9d1e6b0
--- /dev/null
+++ b/sc/source/ui/cctrl/editfield.cxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifdef SC_DLLIMPLEMENTATION
+#undef SC_DLLIMPLEMENTATION
+#endif
+#include <editfield.hxx>
+#include <comphelper/string.hxx>
+#include <rtl/math.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <global.hxx>
+
+namespace {
+
+sal_Unicode lclGetDecSep()
+{
+ return ScGlobal::getLocaleData().getNumDecimalSep()[0];
+}
+
+} // namespace
+
+ScDoubleField::ScDoubleField(std::unique_ptr<weld::Entry> xEntry)
+ : m_xEntry(std::move(xEntry))
+{
+}
+
+bool ScDoubleField::GetValue( double& rfValue ) const
+{
+ OUString aStr(comphelper::string::strip(m_xEntry->get_text(), ' '));
+ bool bOk = !aStr.isEmpty();
+ if( bOk )
+ {
+ rtl_math_ConversionStatus eStatus;
+ sal_Int32 nEnd;
+ rfValue = ScGlobal::getLocaleData().stringToDouble( aStr, true, &eStatus, &nEnd );
+ bOk = (eStatus == rtl_math_ConversionStatus_Ok) && (nEnd == aStr.getLength() );
+ }
+ return bOk;
+}
+
+void ScDoubleField::SetValue( double fValue, sal_Int32 nDecPlaces )
+{
+ m_xEntry->set_text( ::rtl::math::doubleToUString( fValue, rtl_math_StringFormat_G,
+ nDecPlaces, lclGetDecSep(), true/*bEraseTrailingDecZeros*/ ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/cctrl/tbzoomsliderctrl.cxx b/sc/source/ui/cctrl/tbzoomsliderctrl.cxx
new file mode 100644
index 000000000..7d3443bb0
--- /dev/null
+++ b/sc/source/ui/cctrl/tbzoomsliderctrl.cxx
@@ -0,0 +1,457 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include <tbzoomsliderctrl.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <vcl/event.hxx>
+#include <vcl/image.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/virdev.hxx>
+#include <svx/zoomslideritem.hxx>
+#include <iterator>
+#include <set>
+#include <bitmaps.hlst>
+
+#include <com/sun/star/frame/XFrame.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+
+// class ScZoomSliderControl ---------------------------------------
+
+SFX_IMPL_TOOLBOX_CONTROL( ScZoomSliderControl, SvxZoomSliderItem );
+
+ScZoomSliderControl::ScZoomSliderControl(
+ sal_uInt16 nSlotId,
+ ToolBoxItemId nId,
+ ToolBox& rTbx )
+ :SfxToolBoxControl( nSlotId, nId, rTbx )
+{
+ rTbx.Invalidate();
+}
+
+ScZoomSliderControl::~ScZoomSliderControl()
+{
+
+}
+
+void ScZoomSliderControl::StateChangedAtToolBoxControl( sal_uInt16 /*nSID*/, SfxItemState eState,
+ const SfxPoolItem* pState )
+{
+ ToolBoxItemId nId = GetId();
+ ToolBox& rTbx = GetToolBox();
+ ScZoomSliderWnd* pBox = static_cast<ScZoomSliderWnd*>(rTbx.GetItemWindow( nId ));
+ OSL_ENSURE( pBox ,"Control not found!" );
+
+ if ( SfxItemState::DEFAULT != eState || pState->IsVoidItem() )
+ {
+ SvxZoomSliderItem aZoomSliderItem( 100 );
+ pBox->Disable();
+ pBox->UpdateFromItem( &aZoomSliderItem );
+ }
+ else
+ {
+ pBox->Enable();
+ OSL_ENSURE( dynamic_cast<const SvxZoomSliderItem*>( pState) != nullptr, "invalid item type" );
+ const SvxZoomSliderItem* pZoomSliderItem = dynamic_cast< const SvxZoomSliderItem* >( pState );
+
+ OSL_ENSURE( pZoomSliderItem, "Sc::ScZoomSliderControl::StateChanged(), wrong item type!" );
+ if( pZoomSliderItem )
+ pBox->UpdateFromItem( pZoomSliderItem );
+ }
+}
+
+VclPtr<InterimItemWindow> ScZoomSliderControl::CreateItemWindow( vcl::Window *pParent )
+{
+ // #i98000# Don't try to get a value via SfxViewFrame::Current here.
+ // The view's value is always notified via StateChanged later.
+ VclPtrInstance<ScZoomSliderWnd> xSlider( pParent,
+ css::uno::Reference< css::frame::XDispatchProvider >( m_xFrame->getController(),
+ css::uno::UNO_QUERY ), 100 );
+ return xSlider;
+}
+
+constexpr sal_uInt16 gnSliderCenter(100);
+
+const tools::Long nButtonWidth = 10;
+const tools::Long nButtonHeight = 10;
+const tools::Long nIncDecWidth = 11;
+const tools::Long nIncDecHeight = 11;
+const tools::Long nSliderHeight = 2;
+const tools::Long nSliderWidth = 4;
+const tools::Long nSnappingHeight = 4;
+const tools::Long nSliderXOffset = 20;
+const tools::Long nSnappingEpsilon = 5; // snapping epsilon in pixels
+const tools::Long nSnappingPointsMinDist = nSnappingEpsilon; // minimum distance of two adjacent snapping points
+
+sal_uInt16 ScZoomSlider::Offset2Zoom( tools::Long nOffset ) const
+{
+ Size aSliderWindowSize = GetOutputSizePixel();
+ const tools::Long nControlWidth = aSliderWindowSize.Width();
+ sal_uInt16 nRet = 0;
+
+ if( nOffset < nSliderXOffset )
+ return mnMinZoom;
+ if( nOffset > nControlWidth - nSliderXOffset )
+ return mnMaxZoom;
+
+ // check for snapping points:
+ auto aSnappingPointIter = std::find_if(maSnappingPointOffsets.begin(), maSnappingPointOffsets.end(),
+ [nOffset](const tools::Long nCurrent) { return std::abs(nCurrent - nOffset) < nSnappingEpsilon; });
+ if (aSnappingPointIter != maSnappingPointOffsets.end())
+ {
+ nOffset = *aSnappingPointIter;
+ auto nCount = static_cast<sal_uInt16>(std::distance(maSnappingPointOffsets.begin(), aSnappingPointIter));
+ nRet = maSnappingPointZooms[ nCount ];
+ }
+
+ if( 0 == nRet )
+ {
+ if( nOffset < nControlWidth / 2 )
+ {
+ // first half of slider
+ const tools::Long nFirstHalfRange = gnSliderCenter - mnMinZoom;
+ const tools::Long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
+ const tools::Long nZoomPerSliderPixel = (1000 * nFirstHalfRange) / nHalfSliderWidth;
+ const tools::Long nOffsetToSliderLeft = nOffset - nSliderXOffset;
+ nRet = mnMinZoom + sal_uInt16( nOffsetToSliderLeft * nZoomPerSliderPixel / 1000 );
+ }
+ else
+ {
+ // second half of slider
+ const tools::Long nSecondHalfRange = mnMaxZoom - gnSliderCenter;
+ const tools::Long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
+ const tools::Long nZoomPerSliderPixel = 1000 * nSecondHalfRange / nHalfSliderWidth;
+ const tools::Long nOffsetToSliderCenter = nOffset - nControlWidth/2;
+ nRet = gnSliderCenter + sal_uInt16( nOffsetToSliderCenter * nZoomPerSliderPixel / 1000 );
+ }
+ }
+
+ if( nRet < mnMinZoom )
+ return mnMinZoom;
+
+ else if( nRet > mnMaxZoom )
+ return mnMaxZoom;
+
+ return nRet;
+}
+
+tools::Long ScZoomSlider::Zoom2Offset( sal_uInt16 nCurrentZoom ) const
+{
+ Size aSliderWindowSize = GetOutputSizePixel();
+ const tools::Long nControlWidth = aSliderWindowSize.Width();
+ tools::Long nRect = nSliderXOffset;
+
+ const tools::Long nHalfSliderWidth = nControlWidth/2 - nSliderXOffset;
+ if( nCurrentZoom <= gnSliderCenter )
+ {
+ nCurrentZoom = nCurrentZoom - mnMinZoom;
+ const tools::Long nFirstHalfRange = gnSliderCenter - mnMinZoom;
+ const tools::Long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth / nFirstHalfRange;
+ const tools::Long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
+ nRect += nOffset;
+ }
+ else
+ {
+ nCurrentZoom = nCurrentZoom - gnSliderCenter;
+ const tools::Long nSecondHalfRange = mnMaxZoom - gnSliderCenter;
+ const tools::Long nSliderPixelPerZoomPercent = 1000 * nHalfSliderWidth / nSecondHalfRange;
+ const tools::Long nOffset = (nSliderPixelPerZoomPercent * nCurrentZoom) / 1000;
+ nRect += nHalfSliderWidth + nOffset;
+ }
+ return nRect;
+}
+
+ScZoomSliderWnd::ScZoomSliderWnd( vcl::Window* pParent,
+ const css::uno::Reference< css::frame::XDispatchProvider >& rDispatchProvider,
+ sal_uInt16 nCurrentZoom ):
+ InterimItemWindow(pParent, "modules/scalc/ui/zoombox.ui", "ZoomBox"),
+ mxWidget(new ScZoomSlider(rDispatchProvider, nCurrentZoom)),
+ mxWeld(new weld::CustomWeld(*m_xBuilder, "zoom", *mxWidget))
+{
+ Size aLogicalSize( 115, 40 );
+ Size aSliderSize = LogicToPixel(aLogicalSize, MapMode(MapUnit::Map10thMM));
+ Size aPreferredSize(aSliderSize.Width() * nSliderWidth-1, aSliderSize.Height() + nSliderHeight);
+ mxWidget->GetDrawingArea()->set_size_request(aPreferredSize.Width(), aPreferredSize.Height());
+ mxWidget->SetOutputSizePixel(aPreferredSize);
+ SetSizePixel(aPreferredSize);
+}
+
+ScZoomSliderWnd::~ScZoomSliderWnd()
+{
+ disposeOnce();
+}
+
+void ScZoomSliderWnd::dispose()
+{
+ mxWeld.reset();
+ mxWidget.reset();
+ InterimItemWindow::dispose();
+}
+
+ScZoomSlider::ScZoomSlider(const css::uno::Reference< css::frame::XDispatchProvider>& rDispatchProvider,
+ sal_uInt16 nCurrentZoom)
+ : mnCurrentZoom( nCurrentZoom ),
+ mnMinZoom( 10 ),
+ mnMaxZoom( 400 ),
+ mbOmitPaint( false ),
+ m_xDispatchProvider(rDispatchProvider)
+{
+ maSliderButton = Image(StockImage::Yes, RID_SVXBMP_SLIDERBUTTON);
+ maIncreaseButton = Image(StockImage::Yes, RID_SVXBMP_SLIDERINCREASE);
+ maDecreaseButton = Image(StockImage::Yes, RID_SVXBMP_SLIDERDECREASE);
+}
+
+
+bool ScZoomSlider::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ Size aSliderWindowSize = GetOutputSizePixel();
+
+ const Point aPoint = rMEvt.GetPosPixel();
+
+ const tools::Long nButtonLeftOffset = ( nSliderXOffset - nIncDecWidth )/2;
+ const tools::Long nButtonRightOffset = ( nSliderXOffset + nIncDecWidth )/2;
+
+ const tools::Long nOldZoom = mnCurrentZoom;
+
+ // click to - button
+ if ( aPoint.X() >= nButtonLeftOffset && aPoint.X() <= nButtonRightOffset )
+ {
+ mnCurrentZoom = mnCurrentZoom - 5;
+ }
+ // click to + button
+ else if ( aPoint.X() >= aSliderWindowSize.Width() - nSliderXOffset + nButtonLeftOffset &&
+ aPoint.X() <= aSliderWindowSize.Width() - nSliderXOffset + nButtonRightOffset )
+ {
+ mnCurrentZoom = mnCurrentZoom + 5;
+ }
+ else if( aPoint.X() >= nSliderXOffset && aPoint.X() <= aSliderWindowSize.Width() - nSliderXOffset )
+ {
+ mnCurrentZoom = Offset2Zoom( aPoint.X() );
+ }
+
+ if( mnCurrentZoom < mnMinZoom )
+ mnCurrentZoom = mnMinZoom;
+ else if( mnCurrentZoom > mnMaxZoom )
+ mnCurrentZoom = mnMaxZoom;
+
+ if( nOldZoom == mnCurrentZoom )
+ return true;
+
+ tools::Rectangle aRect( Point( 0, 0 ), aSliderWindowSize );
+
+ Invalidate(aRect);
+ mbOmitPaint = true;
+
+ SvxZoomSliderItem aZoomSliderItem( mnCurrentZoom );
+
+ css::uno::Any a;
+ aZoomSliderItem.QueryValue( a );
+
+ css::uno::Sequence aArgs{ comphelper::makePropertyValue("ScalingFactor", a) };
+
+ SfxToolBoxControl::Dispatch( m_xDispatchProvider, ".uno:ScalingFactor", aArgs );
+
+ mbOmitPaint = false;
+
+ return true;
+}
+
+bool ScZoomSlider::MouseMove( const MouseEvent& rMEvt )
+{
+ Size aSliderWindowSize = GetOutputSizePixel();
+ const tools::Long nControlWidth = aSliderWindowSize.Width();
+ const short nButtons = rMEvt.GetButtons();
+
+ // check mouse move with button pressed
+ if ( 1 == nButtons )
+ {
+ const Point aPoint = rMEvt.GetPosPixel();
+
+ if ( aPoint.X() >= nSliderXOffset && aPoint.X() <= nControlWidth - nSliderXOffset )
+ {
+ mnCurrentZoom = Offset2Zoom( aPoint.X() );
+
+ tools::Rectangle aRect(Point(0, 0), aSliderWindowSize);
+ Invalidate(aRect);
+
+ mbOmitPaint = true; // optimization: paint before executing command,
+
+ // commit state change
+ SvxZoomSliderItem aZoomSliderItem( mnCurrentZoom );
+
+ css::uno::Any a;
+ aZoomSliderItem.QueryValue( a );
+
+ css::uno::Sequence aArgs{ comphelper::makePropertyValue("ScalingFactor", a) };
+
+ SfxToolBoxControl::Dispatch( m_xDispatchProvider, ".uno:ScalingFactor", aArgs );
+
+ mbOmitPaint = false;
+ }
+ }
+
+ return false;
+}
+
+void ScZoomSliderWnd::UpdateFromItem( const SvxZoomSliderItem* pZoomSliderItem )
+{
+ mxWidget->UpdateFromItem(pZoomSliderItem);
+}
+
+void ScZoomSlider::UpdateFromItem(const SvxZoomSliderItem* pZoomSliderItem)
+{
+ if( pZoomSliderItem )
+ {
+ mnCurrentZoom = pZoomSliderItem->GetValue();
+ mnMinZoom = pZoomSliderItem->GetMinZoom();
+ mnMaxZoom = pZoomSliderItem->GetMaxZoom();
+
+ OSL_ENSURE( mnMinZoom <= mnCurrentZoom &&
+ mnMinZoom < gnSliderCenter &&
+ mnMaxZoom >= mnCurrentZoom &&
+ mnMaxZoom > gnSliderCenter,
+ "Looks like the zoom slider item is corrupted" );
+ const css::uno::Sequence < sal_Int32 >& rSnappingPoints = pZoomSliderItem->GetSnappingPoints();
+ maSnappingPointOffsets.clear();
+ maSnappingPointZooms.clear();
+
+ // get all snapping points:
+ std::set< sal_uInt16 > aTmpSnappingPoints;
+ std::transform(rSnappingPoints.begin(), rSnappingPoints.end(), std::inserter(aTmpSnappingPoints, aTmpSnappingPoints.end()),
+ [](const sal_Int32 nSnappingPoint) -> sal_uInt16 { return static_cast<sal_uInt16>(nSnappingPoint); });
+
+ // remove snapping points that are too close to each other:
+ tools::Long nLastOffset = 0;
+
+ for ( const sal_uInt16 nCurrent : aTmpSnappingPoints )
+ {
+ const tools::Long nCurrentOffset = Zoom2Offset( nCurrent );
+
+ if ( nCurrentOffset - nLastOffset >= nSnappingPointsMinDist )
+ {
+ maSnappingPointOffsets.push_back( nCurrentOffset );
+ maSnappingPointZooms.push_back( nCurrent );
+ nLastOffset = nCurrentOffset;
+ }
+ }
+ }
+
+ Size aSliderWindowSize = GetOutputSizePixel();
+ tools::Rectangle aRect(Point(0, 0), aSliderWindowSize);
+
+ if ( !mbOmitPaint )
+ Invalidate(aRect);
+}
+
+void ScZoomSlider::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
+{
+ DoPaint(rRenderContext);
+}
+
+void ScZoomSlider::DoPaint(vcl::RenderContext& rRenderContext)
+{
+ if (mbOmitPaint)
+ return;
+
+ Size aSliderWindowSize(GetOutputSizePixel());
+ tools::Rectangle aRect(Point(0, 0), aSliderWindowSize);
+
+ ScopedVclPtrInstance< VirtualDevice > pVDev(rRenderContext);
+ pVDev->SetOutputSizePixel(aSliderWindowSize);
+
+ tools::Rectangle aSlider = aRect;
+
+ aSlider.AdjustTop((aSliderWindowSize.Height() - nSliderHeight) / 2 - 1 );
+ aSlider.SetBottom( aSlider.Top() + nSliderHeight );
+ aSlider.AdjustLeft(nSliderXOffset );
+ aSlider.AdjustRight( -nSliderXOffset );
+
+ tools::Rectangle aFirstLine(aSlider);
+ aFirstLine.SetBottom( aFirstLine.Top() );
+
+ tools::Rectangle aSecondLine(aSlider);
+ aSecondLine.SetTop( aSecondLine.Bottom() );
+
+ tools::Rectangle aLeft(aSlider);
+ aLeft.SetRight( aLeft.Left() );
+
+ tools::Rectangle aRight(aSlider);
+ aRight.SetLeft( aRight.Right() );
+
+ // draw VirtualDevice's background color
+ Color aStartColor = rRenderContext.GetSettings().GetStyleSettings().GetFaceColor();
+ Color aEndColor = rRenderContext.GetSettings().GetStyleSettings().GetFaceColor();
+
+ if (aEndColor.IsDark())
+ aStartColor = aEndColor;
+
+ Gradient aGradient;
+ aGradient.SetAngle(0_deg10);
+ aGradient.SetStyle(GradientStyle::Linear);
+
+ aGradient.SetStartColor(aStartColor);
+ aGradient.SetEndColor(aEndColor);
+ pVDev->DrawGradient(aRect, aGradient);
+
+ // draw slider
+ pVDev->SetLineColor(COL_WHITE);
+ pVDev->DrawRect(aSecondLine);
+ pVDev->DrawRect(aRight);
+
+ pVDev->SetLineColor(COL_GRAY);
+ pVDev->DrawRect(aFirstLine);
+ pVDev->DrawRect(aLeft);
+
+ // draw snapping points:
+ for (const auto& rSnappingPointOffset : maSnappingPointOffsets)
+ {
+ pVDev->SetLineColor(COL_GRAY);
+ tools::Rectangle aSnapping(aRect);
+ aSnapping.SetBottom( aSlider.Top() );
+ aSnapping.SetTop( aSnapping.Bottom() - nSnappingHeight );
+ aSnapping.AdjustLeft(rSnappingPointOffset );
+ aSnapping.SetRight( aSnapping.Left() );
+ pVDev->DrawRect(aSnapping);
+
+ aSnapping.AdjustTop(nSnappingHeight + nSliderHeight );
+ aSnapping.AdjustBottom(nSnappingHeight + nSliderHeight );
+ pVDev->DrawRect(aSnapping);
+ }
+
+ // draw slider button
+ Point aImagePoint = aRect.TopLeft();
+ aImagePoint.AdjustX(Zoom2Offset(mnCurrentZoom) );
+ aImagePoint.AdjustX( -(nButtonWidth / 2) );
+ aImagePoint.AdjustY( (aSliderWindowSize.Height() - nButtonHeight) / 2 );
+ pVDev->DrawImage(aImagePoint, maSliderButton);
+
+ // draw decrease button
+ aImagePoint = aRect.TopLeft();
+ aImagePoint.AdjustX((nSliderXOffset - nIncDecWidth) / 2 );
+ aImagePoint.AdjustY((aSliderWindowSize.Height() - nIncDecHeight) / 2 );
+ pVDev->DrawImage(aImagePoint, maDecreaseButton);
+
+ // draw increase button
+ aImagePoint.setX( aRect.Left() + aSliderWindowSize.Width() - nIncDecWidth - (nSliderXOffset - nIncDecWidth) / 2 );
+ pVDev->DrawImage(aImagePoint, maIncreaseButton);
+
+ rRenderContext.DrawOutDev(Point(0, 0), aSliderWindowSize, Point(0, 0), aSliderWindowSize, *pVDev);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/condformat/colorformat.cxx b/sc/source/ui/condformat/colorformat.cxx
new file mode 100644
index 000000000..920fee3c0
--- /dev/null
+++ b/sc/source/ui/condformat/colorformat.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/.
+ */
+
+#include <colorformat.hxx>
+#include <colorscale.hxx>
+
+#include <document.hxx>
+
+#include <svl/numformat.hxx>
+#include <svx/colorbox.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+namespace {
+
+void SetType(const ScColorScaleEntry* pEntry, weld::ComboBox& rLstBox)
+{
+ rLstBox.set_active(pEntry->GetType());
+}
+
+void GetType(const weld::ComboBox& rLstBox, const weld::Entry& rEd, ScColorScaleEntry* pEntry, SvNumberFormatter* pNumberFormatter,
+ ScDocument* pDoc, const ScAddress& rPos )
+{
+ double nVal = 0;
+ sal_uInt32 nIndex = 0;
+ pEntry->SetType(static_cast<ScColorScaleEntryType>(rLstBox.get_active()));
+ switch (rLstBox.get_active())
+ {
+ case COLORSCALE_AUTO:
+ case COLORSCALE_MIN:
+ case COLORSCALE_MAX:
+ break;
+ case COLORSCALE_PERCENTILE:
+ case COLORSCALE_VALUE:
+ case COLORSCALE_PERCENT:
+ (void)pNumberFormatter->IsNumberFormat( rEd.get_text(), nIndex, nVal );
+ pEntry->SetValue(nVal);
+ break;
+ case COLORSCALE_FORMULA:
+ pEntry->SetFormula(rEd.get_text(), *pDoc, rPos);
+ break;
+ }
+}
+
+OUString convertNumberToString(double nVal, const ScDocument* pDoc)
+{
+ SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable();
+ OUString aText;
+ pNumberFormatter->GetInputLineString(nVal, 0, aText);
+ return aText;
+}
+
+void SetValue( const ScDocument* pDoc, const ScColorScaleEntry* pEntry, weld::Entry& rEdit)
+{
+ if(pEntry->GetType() == COLORSCALE_FORMULA)
+ rEdit.set_text(pEntry->GetFormula(formula::FormulaGrammar::GRAM_DEFAULT));
+ else if(pEntry->GetType() != COLORSCALE_MIN && pEntry->GetType() != COLORSCALE_MAX)
+ rEdit.set_text(convertNumberToString(pEntry->GetValue(), pDoc));
+ else
+ rEdit.set_sensitive(false);
+}
+
+}
+
+ScDataBarSettingsDlg::ScDataBarSettingsDlg(weld::Window* pParent, const ScDataBarFormatData& rData, ScDocument* pDoc, const ScAddress& rPos)
+ : GenericDialogController(pParent, "modules/scalc/ui/databaroptions.ui", "DataBarOptions")
+ , mpNumberFormatter(pDoc->GetFormatTable())
+ , mpDoc(pDoc)
+ , maPos(rPos)
+ , mxBtnOk(m_xBuilder->weld_button("ok"))
+ , mxBtnCancel(m_xBuilder->weld_button("cancel"))
+ , mxLbPos(new ColorListBox(m_xBuilder->weld_menu_button("positive_colour"), [this]{ return m_xDialog.get(); }))
+ , mxLbNeg(new ColorListBox(m_xBuilder->weld_menu_button("negative_colour"), [this]{ return m_xDialog.get(); }))
+ , mxLbAxisCol(new ColorListBox(m_xBuilder->weld_menu_button("axis_colour"), [this]{ return m_xDialog.get(); }))
+ , mxLbFillType(m_xBuilder->weld_combo_box("fill_type"))
+ , mxLbTypeMin(m_xBuilder->weld_combo_box("min"))
+ , mxLbTypeMax(m_xBuilder->weld_combo_box("max"))
+ , mxLbAxisPos(m_xBuilder->weld_combo_box("axis_pos"))
+ , mxEdMin(m_xBuilder->weld_entry("min_value"))
+ , mxEdMax(m_xBuilder->weld_entry("max_value"))
+ , mxLenMin(m_xBuilder->weld_entry("min_length"))
+ , mxLenMax(m_xBuilder->weld_entry("max_length"))
+ , mxCbOnlyBar(m_xBuilder->weld_check_button("only_bar"))
+ , mxStrSameValueFT(m_xBuilder->weld_label("str_same_value"))
+{
+ maStrWarnSameValue = mxStrSameValueFT->get_label();
+
+ Init();
+
+ mxLbPos->SelectEntry(rData.maPositiveColor);
+ mxLbFillType->set_active( rData.mbGradient ? 1 : 0 );
+ if (rData.mxNegativeColor)
+ mxLbNeg->SelectEntry(*rData.mxNegativeColor);
+
+ switch (rData.meAxisPosition)
+ {
+ case databar::NONE:
+ mxLbAxisPos->set_active(2);
+ break;
+ case databar::AUTOMATIC:
+ mxLbAxisPos->set_active(0);
+ break;
+ case databar::MIDDLE:
+ mxLbAxisPos->set_active(1);
+ break;
+ }
+ ::SetType(rData.mpLowerLimit.get(), *mxLbTypeMin);
+ ::SetType(rData.mpUpperLimit.get(), *mxLbTypeMax);
+ SetValue(mpDoc, rData.mpLowerLimit.get(), *mxEdMin);
+ SetValue(mpDoc, rData.mpUpperLimit.get(), *mxEdMax);
+ mxLenMin->set_text(convertNumberToString(rData.mnMinLength, mpDoc));
+ mxLenMax->set_text(convertNumberToString(rData.mnMaxLength, mpDoc));
+ mxLbAxisCol->SelectEntry(rData.maAxisColor);
+ mxCbOnlyBar->set_active(rData.mbOnlyBar);
+
+ TypeSelectHdl(*mxLbTypeMin);
+ PosSelectHdl(*mxLbTypeMin);
+}
+
+ScDataBarSettingsDlg::~ScDataBarSettingsDlg()
+{
+}
+
+void ScDataBarSettingsDlg::Init()
+{
+ mxLbNeg->SelectEntry(COL_LIGHTRED);
+ mxLbAxisCol->SelectEntry(COL_BLACK);
+ mxLbPos->SelectEntry(0x2a6099);
+ mxBtnOk->connect_clicked( LINK( this, ScDataBarSettingsDlg, OkBtnHdl ) );
+
+ mxLbTypeMin->connect_changed( LINK( this, ScDataBarSettingsDlg, TypeSelectHdl ) );
+ mxLbTypeMax->connect_changed( LINK( this, ScDataBarSettingsDlg, TypeSelectHdl ) );
+ mxLbAxisPos->connect_changed( LINK( this, ScDataBarSettingsDlg, PosSelectHdl ) );
+
+}
+
+namespace {
+
+void GetAxesPosition(ScDataBarFormatData* pData, const weld::ComboBox& rLbox)
+{
+ switch (rLbox.get_active())
+ {
+ case 0:
+ pData->meAxisPosition = databar::AUTOMATIC;
+ break;
+ case 1:
+ pData->meAxisPosition = databar::MIDDLE;
+ break;
+ case 2:
+ pData->meAxisPosition = databar::NONE;
+ break;
+ }
+}
+
+void SetBarLength(ScDataBarFormatData* pData, const OUString& minStr, const OUString& maxStr, SvNumberFormatter* mpNumberFormatter)
+{
+ double nMinValue = 0;
+ sal_uInt32 nIndex = 0;
+ (void)mpNumberFormatter->IsNumberFormat(minStr, nIndex, nMinValue);
+ nIndex = 0;
+ double nMaxValue = 0;
+ (void)mpNumberFormatter->IsNumberFormat(maxStr, nIndex, nMaxValue);
+ pData->mnMinLength = nMinValue;
+ pData->mnMaxLength = nMaxValue;
+}
+
+}
+
+ScDataBarFormatData* ScDataBarSettingsDlg::GetData()
+{
+ ScDataBarFormatData* pData = new ScDataBarFormatData();
+ pData->maPositiveColor = mxLbPos->GetSelectEntryColor();
+ pData->mxNegativeColor = mxLbNeg->GetSelectEntryColor();
+ pData->mbGradient = ( mxLbFillType->get_active() == 1 );
+ pData->mpUpperLimit.reset(new ScColorScaleEntry());
+ pData->mpLowerLimit.reset(new ScColorScaleEntry());
+ pData->maAxisColor = mxLbAxisCol->GetSelectEntryColor();
+ pData->mbOnlyBar = mxCbOnlyBar->get_active();
+
+ ::GetType(*mxLbTypeMin, *mxEdMin, pData->mpLowerLimit.get(), mpNumberFormatter, mpDoc, maPos);
+ ::GetType(*mxLbTypeMax, *mxEdMax, pData->mpUpperLimit.get(), mpNumberFormatter, mpDoc, maPos);
+ GetAxesPosition(pData, *mxLbAxisPos);
+ SetBarLength(pData, mxLenMin->get_text(), mxLenMax->get_text(), mpNumberFormatter);
+
+ return pData;
+}
+
+IMPL_LINK_NOARG(ScDataBarSettingsDlg, OkBtnHdl, weld::Button&, void)
+{
+ //check that min < max
+ bool bWarn = false;
+ int nSelectMin = mxLbTypeMin->get_active();
+ if( nSelectMin == COLORSCALE_MAX )
+ bWarn = true;
+ int nSelectMax = mxLbTypeMax->get_active();
+ if( nSelectMax == COLORSCALE_MIN )
+ bWarn = true;
+ if(!bWarn) // databar length checks
+ {
+ OUString aMinString = mxLenMin->get_text();
+ OUString aMaxString = mxLenMax->get_text();
+ double nMinValue = 0;
+ sal_uInt32 nIndex = 0;
+ (void)mpNumberFormatter->IsNumberFormat(aMinString, nIndex, nMinValue);
+ nIndex = 0;
+ double nMaxValue = 0;
+ (void)mpNumberFormatter->IsNumberFormat(aMaxString, nIndex, nMaxValue);
+ if(rtl::math::approxEqual(nMinValue, nMaxValue) || nMinValue > nMaxValue || nMaxValue > 100 || nMinValue < 0)
+ bWarn = true;
+ }
+ if (!bWarn && mxLbTypeMin->get_active() == mxLbTypeMax->get_active())
+ {
+
+ if(nSelectMax != COLORSCALE_FORMULA && nSelectMax != COLORSCALE_AUTO)
+ {
+ OUString aMinString = mxEdMin->get_text();
+ OUString aMaxString = mxEdMax->get_text();
+ double nMinValue = 0;
+ sal_uInt32 nIndex = 0;
+ (void)mpNumberFormatter->IsNumberFormat(aMinString, nIndex, nMinValue);
+ nIndex = 0;
+ double nMaxValue = 0;
+ (void)mpNumberFormatter->IsNumberFormat(aMaxString, nIndex, nMaxValue);
+ if(rtl::math::approxEqual(nMinValue, nMaxValue) || nMinValue > nMaxValue)
+ bWarn = true;
+ }
+ }
+
+ if(bWarn)
+ {
+ //show warning message and don't close
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ maStrWarnSameValue));
+ xWarn->run();
+ }
+ else
+ {
+ m_xDialog->response(RET_OK);
+ }
+}
+
+IMPL_LINK_NOARG(ScDataBarSettingsDlg, TypeSelectHdl, weld::ComboBox&, void)
+{
+ int nSelectMin = mxLbTypeMin->get_active();
+ if( nSelectMin <= COLORSCALE_MAX)
+ mxEdMin->set_sensitive(false);
+ else
+ {
+ mxEdMin->set_sensitive(true);
+ if(mxEdMin->get_text().isEmpty())
+ {
+ if(nSelectMin == COLORSCALE_PERCENTILE || nSelectMin == COLORSCALE_PERCENT)
+ mxEdMin->set_text(OUString::number(50));
+ else
+ mxEdMin->set_text(OUString::number(0));
+ }
+ }
+
+ int nSelectMax = mxLbTypeMax->get_active();
+ if (nSelectMax <= COLORSCALE_MAX)
+ mxEdMax->set_sensitive(false);
+ else
+ {
+ mxEdMax->set_sensitive(true);
+ if (mxEdMax->get_text().isEmpty())
+ {
+ if(nSelectMax == COLORSCALE_PERCENTILE || nSelectMax == COLORSCALE_PERCENT)
+ mxEdMax->set_text(OUString::number(50));
+ else
+ mxEdMax->set_text(OUString::number(0));
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ScDataBarSettingsDlg, PosSelectHdl, weld::ComboBox&, void)
+{
+ int axisPos = mxLbAxisPos->get_active();
+ if(axisPos != 2 && axisPos != 1) // disable if axis vertical position is automatic
+ {
+ mxLenMin->set_sensitive(false);
+ mxLenMax->set_sensitive(false);
+ }
+ else
+ {
+ mxLenMin->set_sensitive(true);
+ mxLenMax->set_sensitive(true);
+ if(mxLenMin->get_text().isEmpty())
+ {
+ mxLenMin->set_text(OUString::number(0));
+ mxLenMax->set_text(OUString::number(100));
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/sc/source/ui/condformat/condformatdlg.cxx b/sc/source/ui/condformat/condformatdlg.cxx
new file mode 100644
index 000000000..b4759bb39
--- /dev/null
+++ b/sc/source/ui/condformat/condformatdlg.cxx
@@ -0,0 +1,709 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <condformatdlg.hxx>
+
+#include <sfx2/dispatch.hxx>
+#include <vcl/svapp.hxx>
+
+#include <anyrefdg.hxx>
+#include <document.hxx>
+#include <conditio.hxx>
+#include <tabvwsh.hxx>
+#include <colorscale.hxx>
+#include <reffact.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <condformatdlgentry.hxx>
+#include <condformatdlgitem.hxx>
+
+ScCondFormatList::ScCondFormatList(ScCondFormatDlg* pDialogParent,
+ std::unique_ptr<weld::ScrolledWindow> xWindow,
+ std::unique_ptr<weld::Container> xGrid)
+ : mxScrollWindow(std::move(xWindow))
+ , mxGrid(std::move(xGrid))
+ , mbFrozen(false)
+ , mbNewEntry(false)
+ , mpDoc(nullptr)
+ , mpDialogParent(pDialogParent)
+{
+ mxScrollWindow->set_size_request(mxScrollWindow->get_approximate_digit_width() * 85,
+ mxScrollWindow->get_text_height() * 23);
+ mxGrid->set_stack_background();
+}
+
+weld::Window* ScCondFormatList::GetFrameWeld()
+{
+ return mpDialogParent->getDialog();
+}
+
+ScCondFormatList::~ScCondFormatList()
+{
+ Freeze();
+}
+
+void ScCondFormatList::init(ScDocument& rDoc,
+ const ScConditionalFormat* pFormat, const ScRangeList& rRanges,
+ const ScAddress& rPos, condformat::dialog::ScCondFormatDialogType eType)
+{
+ mpDoc = &rDoc;
+ maPos = rPos;
+ maRanges = rRanges;
+
+ Freeze();
+
+ if(pFormat)
+ {
+ size_t nCount = pFormat->size();
+ for (size_t nIndex = 0; nIndex < nCount; ++nIndex)
+ {
+ const ScFormatEntry* pEntry = pFormat->GetEntry(nIndex);
+ switch(pEntry->GetType())
+ {
+ case ScFormatEntry::Type::Condition:
+ case ScFormatEntry::Type::ExtCondition:
+ {
+ const ScCondFormatEntry* pConditionEntry = static_cast<const ScCondFormatEntry*>( pEntry );
+ if(pConditionEntry->GetOperation() != ScConditionMode::Direct)
+ maEntries.emplace_back(new ScConditionFrmtEntry( this, mpDoc, mpDialogParent, maPos, pConditionEntry ) );
+ else
+ maEntries.emplace_back(new ScFormulaFrmtEntry( this, mpDoc, mpDialogParent, maPos, pConditionEntry ) );
+
+ }
+ break;
+ case ScFormatEntry::Type::Colorscale:
+ {
+ const ScColorScaleFormat* pColorScale = static_cast<const ScColorScaleFormat*>( pEntry );
+ if( pColorScale->size() == 2 )
+ maEntries.emplace_back(new ScColorScale2FrmtEntry( this, mpDoc, maPos, pColorScale ) );
+ else
+ maEntries.emplace_back(new ScColorScale3FrmtEntry( this, mpDoc, maPos, pColorScale ) );
+ }
+ break;
+ case ScFormatEntry::Type::Databar:
+ maEntries.emplace_back(new ScDataBarFrmtEntry( this, mpDoc, maPos, static_cast<const ScDataBarFormat*>( pEntry ) ) );
+ break;
+ case ScFormatEntry::Type::Iconset:
+ maEntries.emplace_back(new ScIconSetFrmtEntry( this, mpDoc, maPos, static_cast<const ScIconSetFormat*>( pEntry ) ) );
+ break;
+ case ScFormatEntry::Type::Date:
+ maEntries.emplace_back(new ScDateFrmtEntry( this, mpDoc, static_cast<const ScCondDateFormatEntry*>( pEntry ) ) );
+ break;
+ }
+ }
+ if(nCount)
+ EntrySelectHdl(*maEntries[0]);
+ }
+ else
+ {
+ switch(eType)
+ {
+ case condformat::dialog::CONDITION:
+ maEntries.emplace_back(new ScConditionFrmtEntry( this, mpDoc, mpDialogParent, maPos ));
+ break;
+ case condformat::dialog::COLORSCALE:
+ maEntries.emplace_back(new ScColorScale3FrmtEntry( this, mpDoc, maPos ));
+ break;
+ case condformat::dialog::DATABAR:
+ maEntries.emplace_back(new ScDataBarFrmtEntry( this, mpDoc, maPos ));
+ break;
+ case condformat::dialog::ICONSET:
+ maEntries.emplace_back(new ScIconSetFrmtEntry( this, mpDoc, maPos ));
+ break;
+ case condformat::dialog::DATE:
+ maEntries.emplace_back(new ScDateFrmtEntry( this, mpDoc ));
+ break;
+ case condformat::dialog::NONE:
+ break;
+ }
+ mbNewEntry = true;
+ }
+ Thaw();
+ RecalcAll();
+ if (!maEntries.empty())
+ {
+ (*maEntries.begin())->SetActive();
+ mpDialogParent->OnSelectionChange(0, maEntries.size());
+ }
+
+ RecalcAll();
+}
+
+void ScCondFormatList::SetRange(const ScRangeList& rRange)
+{
+ maRanges = rRange;
+}
+
+std::unique_ptr<ScConditionalFormat> ScCondFormatList::GetConditionalFormat() const
+{
+ if(maEntries.empty())
+ return nullptr;
+
+ std::unique_ptr<ScConditionalFormat> pFormat(new ScConditionalFormat(0, mpDoc));
+ pFormat->SetRange(maRanges);
+
+ for(auto & rEntry: maEntries)
+ {
+ // tdf#119178: Sometimes initial apply-to range (the one this dialog
+ // was opened with) is different from the final apply-to range
+ // (as edited by the user)
+
+ // If this format entry is new, take top-left corner of the final range
+ // and use it to create the initial entry (token array therein, if applicable)
+ if (mbNewEntry)
+ rEntry->SetPos(maRanges.GetTopLeftCorner());
+ // else do nothing: setting new position when editing recompiles formulas
+ // in entries and nobody wants that
+
+ ScFormatEntry* pEntry = rEntry->GetEntry();
+ if(pEntry)
+ pFormat->AddEntry(pEntry);
+ }
+
+ return pFormat;
+}
+
+void ScCondFormatList::RecalcAll()
+{
+ if (mbFrozen)
+ return;
+
+ int nWheelScroll = SAL_MAX_INT32;
+
+ sal_Int32 nIndex = 1;
+ for (const auto& item : maEntries)
+ {
+ if (!item)
+ continue;
+ item->SetIndex(nIndex);
+ item->set_grid_top_attach(nIndex - 1);
+ nWheelScroll = std::min(nWheelScroll, item->get_preferred_height());
+ ++nIndex;
+ }
+
+ if (nWheelScroll != SAL_MAX_INT32)
+ {
+ // tdf#118482 set a scroll step of the height of a collapsed entry
+ mxScrollWindow->vadjustment_set_step_increment(nWheelScroll);
+ }
+}
+
+IMPL_LINK(ScCondFormatList, ColFormatTypeHdl, weld::ComboBox&, rBox, void)
+{
+ Application::PostUserEvent(LINK(this, ScCondFormatList, AfterColFormatTypeHdl), &rBox);
+}
+
+IMPL_LINK(ScCondFormatList, AfterColFormatTypeHdl, void*, p, void)
+{
+ weld::ComboBox* pBox = static_cast<weld::ComboBox*>(p);
+ EntryContainer::iterator itr = std::find_if(maEntries.begin(), maEntries.end(),
+ [](const std::unique_ptr<ScCondFrmtEntry>& widget) { return widget->IsSelected(); });
+ if(itr == maEntries.end())
+ return;
+
+ sal_Int32 nPos = pBox->get_active();
+ switch(nPos)
+ {
+ case 0:
+ if((*itr)->GetType() == condformat::entry::COLORSCALE2)
+ return;
+
+ Freeze();
+ itr->reset(new ScColorScale2FrmtEntry(this, mpDoc, maPos));
+ break;
+ case 1:
+ if((*itr)->GetType() == condformat::entry::COLORSCALE3)
+ return;
+
+ Freeze();
+ itr->reset(new ScColorScale3FrmtEntry(this, mpDoc, maPos));
+ break;
+ case 2:
+ if((*itr)->GetType() == condformat::entry::DATABAR)
+ return;
+
+ Freeze();
+ itr->reset(new ScDataBarFrmtEntry(this, mpDoc, maPos));
+ break;
+ case 3:
+ if((*itr)->GetType() == condformat::entry::ICONSET)
+ return;
+
+ Freeze();
+ itr->reset(new ScIconSetFrmtEntry(this, mpDoc, maPos));
+ break;
+ default:
+ break;
+ }
+ mpDialogParent->InvalidateRefData();
+ (*itr)->SetActive();
+ Thaw();
+ RecalcAll();
+}
+
+IMPL_LINK(ScCondFormatList, TypeListHdl, weld::ComboBox&, rBox, void)
+{
+ //Resolves: fdo#79021 At this point we are still inside the ListBox Select.
+ //If we call maEntries.replace here then the pBox will be deleted before it
+ //has finished Select and will crash on accessing its deleted this. So Post
+ //to do the real work after the Select has completed
+ Application::PostUserEvent(LINK(this, ScCondFormatList, AfterTypeListHdl), &rBox);
+}
+
+IMPL_LINK(ScCondFormatList, AfterTypeListHdl, void*, p, void)
+{
+ weld::ComboBox* pBox = static_cast<weld::ComboBox*>(p);
+ EntryContainer::iterator itr = std::find_if(maEntries.begin(), maEntries.end(),
+ [](const std::unique_ptr<ScCondFrmtEntry>& widget) { return widget->IsSelected(); });
+ if(itr == maEntries.end())
+ return;
+
+ sal_Int32 nPos = pBox->get_active();
+ switch(nPos)
+ {
+ case 0:
+ switch((*itr)->GetType())
+ {
+ case condformat::entry::FORMULA:
+ case condformat::entry::CONDITION:
+ case condformat::entry::DATE:
+ break;
+ case condformat::entry::COLORSCALE2:
+ case condformat::entry::COLORSCALE3:
+ case condformat::entry::DATABAR:
+ case condformat::entry::ICONSET:
+ return;
+ }
+ Freeze();
+ itr->reset(new ScColorScale3FrmtEntry(this, mpDoc, maPos));
+ mpDialogParent->InvalidateRefData();
+ (*itr)->SetActive();
+ break;
+ case 1:
+ if((*itr)->GetType() == condformat::entry::CONDITION)
+ return;
+
+ Freeze();
+ itr->reset(new ScConditionFrmtEntry(this, mpDoc, mpDialogParent, maPos));
+ mpDialogParent->InvalidateRefData();
+ (*itr)->SetActive();
+ break;
+ case 2:
+ if((*itr)->GetType() == condformat::entry::FORMULA)
+ return;
+
+ Freeze();
+ itr->reset(new ScFormulaFrmtEntry(this, mpDoc, mpDialogParent, maPos));
+ mpDialogParent->InvalidateRefData();
+ (*itr)->SetActive();
+ break;
+ case 3:
+ if((*itr)->GetType() == condformat::entry::DATE)
+ return;
+
+ Freeze();
+ itr->reset(new ScDateFrmtEntry( this, mpDoc ));
+ mpDialogParent->InvalidateRefData();
+ (*itr)->SetActive();
+ break;
+
+ }
+ Thaw();
+ RecalcAll();
+}
+
+IMPL_LINK_NOARG( ScCondFormatList, AddBtnHdl, weld::Button&, void )
+{
+ Freeze();
+ maEntries.emplace_back(new ScConditionFrmtEntry(this, mpDoc, mpDialogParent, maPos));
+ for(auto& rxEntry : maEntries)
+ {
+ rxEntry->SetInactive();
+ }
+ mpDialogParent->InvalidateRefData();
+ maEntries.back()->SetActive();
+ mpDialogParent->OnSelectionChange(maEntries.size() - 1, maEntries.size());
+ Thaw();
+ RecalcAll();
+}
+
+IMPL_LINK_NOARG( ScCondFormatList, RemoveBtnHdl, weld::Button&, void )
+{
+ Freeze();
+ auto itr = std::find_if(maEntries.begin(), maEntries.end(),
+ [](const std::unique_ptr<ScCondFrmtEntry>& widget) { return widget->IsSelected(); });
+ if (itr != maEntries.end())
+ {
+ maEntries.erase(itr);
+ }
+ mpDialogParent->InvalidateRefData();
+ mpDialogParent->OnSelectionChange(0, maEntries.size(), false);
+ Thaw();
+ RecalcAll();
+}
+
+IMPL_LINK_NOARG(ScCondFormatList, UpBtnHdl, weld::Button&, void)
+{
+ Freeze();
+ size_t index = 0;
+ for (size_t i = 0; i < maEntries.size(); i++)
+ {
+ auto& widget = maEntries[i];
+ if (widget->IsSelected() && i > 0)
+ {
+ std::swap(maEntries[i], maEntries[i - 1]);
+ index = i - 1;
+ break;
+ }
+ }
+ mpDialogParent->InvalidateRefData();
+ mpDialogParent->OnSelectionChange(index, maEntries.size());
+ Thaw();
+ RecalcAll();
+}
+
+IMPL_LINK_NOARG(ScCondFormatList, DownBtnHdl, weld::Button&, void)
+{
+ Freeze();
+ size_t index = 0;
+ for (size_t i = 0; i < maEntries.size(); i++)
+ {
+ auto& widget = maEntries[i];
+ if (widget->IsSelected())
+ {
+ index = i;
+ if (i < maEntries.size()-1)
+ {
+ std::swap(maEntries[i], maEntries[i + 1]);
+ index = i + 1;
+ break;
+ }
+ }
+ }
+ mpDialogParent->InvalidateRefData();
+ mpDialogParent->OnSelectionChange(index, maEntries.size());
+ Thaw();
+ RecalcAll();
+}
+
+IMPL_LINK( ScCondFormatList, EntrySelectHdl, ScCondFrmtEntry&, rEntry, void )
+{
+ if(rEntry.IsSelected())
+ return;
+
+ Freeze();
+ size_t index = 0;
+ for(size_t i = 0; i < maEntries.size(); i++)
+ {
+ if (maEntries[i].get() == &rEntry)
+ {
+ index = i;
+ }
+ maEntries[i]->SetInactive();
+ }
+ mpDialogParent->InvalidateRefData();
+ mpDialogParent->OnSelectionChange(index, maEntries.size());
+ rEntry.SetActive();
+ Thaw();
+ RecalcAll();
+}
+
+ScCondFormatDlg::ScCondFormatDlg(SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData* pViewData,
+ const ScCondFormatDlgItem* pItem)
+ : ScAnyRefDlgController(pB, pCW, pParent,
+ (SfxViewShell::Current() && SfxViewShell::Current()->isLOKMobilePhone())?OUString("modules/scalc/ui/conditionalformatdialogmobile.ui"):OUString("modules/scalc/ui/conditionalformatdialog.ui"),
+ "ConditionalFormatDialog")
+ , mpViewData(pViewData)
+ , mpDlgItem(pItem->Clone())
+ , mpLastEdit(nullptr)
+ , mxBtnOk(m_xBuilder->weld_button("ok"))
+ , mxBtnAdd(m_xBuilder->weld_button("add"))
+ , mxBtnRemove(m_xBuilder->weld_button("delete"))
+ , mxBtnUp(m_xBuilder->weld_button("up"))
+ , mxBtnDown(m_xBuilder->weld_button("down"))
+ , mxBtnCancel(m_xBuilder->weld_button("cancel"))
+ , mxFtRange(m_xBuilder->weld_label("ftassign"))
+ , mxEdRange(new formula::RefEdit(m_xBuilder->weld_entry("edassign")))
+ , mxRbRange(new formula::RefButton(m_xBuilder->weld_button("rbassign")))
+ , mxCondFormList(new ScCondFormatList(this, m_xBuilder->weld_scrolled_window("listwindow"),
+ m_xBuilder->weld_container("list")))
+{
+ mxEdRange->SetReferences(this, mxFtRange.get());
+ mxRbRange->SetReferences(this, mxEdRange.get());
+
+ ScConditionalFormat* pFormat = nullptr;
+ mnKey = mpDlgItem->GetIndex();
+ if (mpDlgItem->IsManaged() && mpDlgItem->GetConditionalFormatList())
+ {
+ pFormat = mpDlgItem->GetConditionalFormatList()->GetFormat(mnKey);
+ }
+ else if (!mpDlgItem->IsManaged())
+ {
+ ScDocument& rDoc = mpViewData->GetDocument();
+ pFormat = rDoc.GetCondFormList(mpViewData->GetTabNo())->GetFormat ( mnKey );
+ }
+
+ ScRangeList aRange;
+ if (pFormat)
+ {
+ aRange = pFormat->GetRange();
+ }
+ else
+ {
+ // this is for adding a new entry
+ mpViewData->GetMarkData().FillRangeListWithMarks(&aRange, false);
+ if(aRange.empty())
+ {
+ ScAddress aPos(mpViewData->GetCurX(), mpViewData->GetCurY(), mpViewData->GetTabNo());
+ aRange.push_back(ScRange(aPos));
+ }
+ mnKey = 0;
+ }
+ maPos = aRange.GetTopLeftCorner();
+
+ mxCondFormList->init(mpViewData->GetDocument(), pFormat, aRange, maPos, mpDlgItem->GetDialogType());
+
+ mxBtnOk->connect_clicked(LINK(this, ScCondFormatDlg, BtnPressedHdl ) );
+ mxBtnAdd->connect_clicked( LINK( mxCondFormList.get(), ScCondFormatList, AddBtnHdl ) );
+ mxBtnRemove->connect_clicked( LINK( mxCondFormList.get(), ScCondFormatList, RemoveBtnHdl ) );
+ mxBtnUp->connect_clicked(LINK(mxCondFormList.get(), ScCondFormatList, UpBtnHdl));
+ mxBtnDown->connect_clicked(LINK(mxCondFormList.get(), ScCondFormatList, DownBtnHdl));
+ mxBtnCancel->connect_clicked( LINK(this, ScCondFormatDlg, BtnPressedHdl ) );
+ mxEdRange->SetModifyHdl( LINK( this, ScCondFormatDlg, EdRangeModifyHdl ) );
+ mxEdRange->SetGetFocusHdl( LINK( this, ScCondFormatDlg, RangeGetFocusHdl ) );
+
+ OUString aRangeString;
+ const ScDocument& rDoc = pViewData->GetDocument();
+ aRange.Format(aRangeString, ScRefFlags::VALID, rDoc, rDoc.GetAddressConvention());
+ mxEdRange->SetText(aRangeString);
+
+ msBaseTitle = m_xDialog->get_title();
+ updateTitle();
+}
+
+void ScCondFormatDlg::updateTitle()
+{
+ OUString aTitle = msBaseTitle + " " + mxEdRange->GetText();
+
+ m_xDialog->set_title(aTitle);
+}
+
+ScCondFormatDlg::~ScCondFormatDlg()
+{
+}
+
+void ScCondFormatDlg::SetActive()
+{
+ if(mpLastEdit)
+ mpLastEdit->GrabFocus();
+ else
+ mxEdRange->GrabFocus();
+
+ RefInputDone();
+}
+
+void ScCondFormatDlg::RefInputDone( bool bForced )
+{
+ ScAnyRefDlgController::RefInputDone(bForced);
+
+ // ScAnyRefModalDlg::RefInputDone resets the title back
+ // to its original state.
+ // I.e. if we open the dialog normally, and then click into the sheet
+ // to modify the selection, the title is updated such that the range
+ // is only a single cell (e.g. $A$1), after which the dialog switches
+ // into the RefInput mode. During the RefInput mode the title is updated
+ // as expected, however at the end RefInputDone overwrites the title
+ // with the initial (now incorrect) single cell range. Hence we correct
+ // it here.
+ updateTitle();
+}
+
+bool ScCondFormatDlg::IsTableLocked() const
+{
+ return !mpLastEdit || mpLastEdit == mxEdRange.get();
+}
+
+bool ScCondFormatDlg::IsRefInputMode() const
+{
+ return mxEdRange->GetWidget()->get_sensitive();
+}
+
+void ScCondFormatDlg::SetReference(const ScRange& rRef, ScDocument&)
+{
+ formula::RefEdit* pEdit = mpLastEdit;
+ if (!mpLastEdit)
+ pEdit = mxEdRange.get();
+
+ if (!pEdit->GetWidget()->get_sensitive())
+ return;
+
+ if(rRef.aStart != rRef.aEnd)
+ RefInputStart(pEdit);
+
+ ScRefFlags nFlags;
+ if (mpLastEdit && mpLastEdit != mxEdRange.get())
+ nFlags = ScRefFlags::RANGE_ABS_3D;
+ else
+ nFlags = ScRefFlags::RANGE_ABS;
+
+ const ScDocument& rDoc = mpViewData->GetDocument();
+ OUString aRefStr(rRef.Format(rDoc, nFlags,
+ ScAddress::Details(rDoc.GetAddressConvention(), 0, 0)));
+ if (pEdit != mxEdRange.get())
+ {
+ Selection sel = pEdit->GetSelection();
+ sel.Justify(); // in case of RTL selection
+ sel.Max() = sel.Min() + aRefStr.getLength();
+ pEdit->GetWidget()->replace_selection(aRefStr);
+ pEdit->SetSelection(sel); // to replace it again with next drag event
+ }
+ else
+ pEdit->SetRefString( aRefStr );
+ updateTitle();
+}
+
+std::unique_ptr<ScConditionalFormat> ScCondFormatDlg::GetConditionalFormat() const
+{
+ OUString aRangeStr = mxEdRange->GetText();
+ if(aRangeStr.isEmpty())
+ return nullptr;
+
+ ScRangeList aRange;
+ ScRefFlags nFlags = aRange.Parse(aRangeStr, mpViewData->GetDocument(),
+ mpViewData->GetDocument().GetAddressConvention(), maPos.Tab());
+ mxCondFormList->SetRange(aRange);
+ std::unique_ptr<ScConditionalFormat> pFormat = mxCondFormList->GetConditionalFormat();
+
+ if((nFlags & ScRefFlags::VALID) && !aRange.empty() && pFormat)
+ pFormat->SetRange(aRange);
+ else
+ pFormat.reset();
+
+ return pFormat;
+}
+
+void ScCondFormatDlg::InvalidateRefData()
+{
+ mpLastEdit = nullptr;
+}
+
+// Close the Conditional Format Dialog
+//
+void ScCondFormatDlg::Close()
+{
+ DoClose( ScCondFormatDlgWrapper::GetChildWindowId() );
+}
+
+// Occurs when the Conditional Format Dialog the OK button is pressed.
+//
+void ScCondFormatDlg::OkPressed()
+{
+ std::unique_ptr<ScConditionalFormat> pFormat = GetConditionalFormat();
+
+ if (!mpDlgItem->IsManaged())
+ {
+ if(pFormat)
+ {
+ auto& rRangeList = pFormat->GetRange();
+ mpViewData->GetDocShell()->GetDocFunc().ReplaceConditionalFormat(mnKey,
+ std::move(pFormat), maPos.Tab(), rRangeList);
+ }
+ else
+ mpViewData->GetDocShell()->GetDocFunc().ReplaceConditionalFormat(mnKey,
+ nullptr, maPos.Tab(), ScRangeList());
+ }
+ else
+ {
+ ScConditionalFormatList* pList = mpDlgItem->GetConditionalFormatList();
+ sal_uInt32 nKey = mnKey;
+ if (mnKey == 0)
+ {
+ nKey = pList->getMaxKey() + 1;
+ }
+
+ pList->erase(nKey);
+ if (pFormat)
+ {
+ pFormat->SetKey(nKey);
+ pList->InsertNew(std::move(pFormat));
+ }
+ mpViewData->GetViewShell()->GetPool().Put(*mpDlgItem);
+
+ SetDispatcherLock( false );
+ // Queue message to open Conditional Format Manager Dialog
+ GetBindings().GetDispatcher()->Execute( SID_OPENDLG_CONDFRMT_MANAGER,
+ SfxCallMode::ASYNCHRON );
+ }
+ m_xDialog->response(RET_OK);
+}
+
+// Occurs when the Conditional Format Dialog is cancelled.
+//
+void ScCondFormatDlg::CancelPressed()
+{
+ if ( mpDlgItem->IsManaged() )
+ {
+ mpViewData->GetViewShell()->GetPool().Put(*mpDlgItem);
+ SetDispatcherLock( false );
+ // Queue message to open Conditional Format Manager Dialog
+ GetBindings().GetDispatcher()->Execute( SID_OPENDLG_CONDFRMT_MANAGER,
+ SfxCallMode::ASYNCHRON );
+ }
+ m_xDialog->response(RET_CANCEL);
+}
+
+void ScCondFormatDlg::OnSelectionChange(size_t nIndex, size_t nSize, bool bSelected)
+{
+ if (nSize <= 1 || !bSelected)
+ {
+ mxBtnUp->set_sensitive(false);
+ mxBtnDown->set_sensitive(false);
+ }
+ else
+ {
+ mxBtnUp->set_sensitive(nIndex != 0);
+ mxBtnDown->set_sensitive(nIndex < nSize - 1);
+ }
+}
+
+IMPL_LINK(ScCondFormatDlg, EdRangeModifyHdl, formula::RefEdit&, rEdit, void)
+{
+ OUString aRangeStr = rEdit.GetText();
+ ScRangeList aRange;
+ ScRefFlags nFlags = aRange.Parse(aRangeStr, mpViewData->GetDocument(),
+ mpViewData->GetDocument().GetAddressConvention());
+ if(nFlags & ScRefFlags::VALID)
+ {
+ rEdit.GetWidget()->set_message_type(weld::EntryMessageType::Normal);
+ mxBtnOk->set_sensitive(true);
+ }
+ else
+ {
+ rEdit.GetWidget()->set_message_type(weld::EntryMessageType::Error);
+ mxBtnOk->set_sensitive(false);
+ }
+
+ updateTitle();
+}
+
+IMPL_LINK(ScCondFormatDlg, RangeGetFocusHdl, formula::RefEdit&, rControl, void)
+{
+ mpLastEdit = &rControl;
+}
+
+IMPL_LINK( ScCondFormatDlg, BtnPressedHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == mxBtnOk.get())
+ OkPressed();
+ else if (&rBtn == mxBtnCancel.get())
+ CancelPressed();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/condformat/condformatdlgentry.cxx b/sc/source/ui/condformat/condformatdlgentry.cxx
new file mode 100644
index 000000000..77175fa64
--- /dev/null
+++ b/sc/source/ui/condformat/condformatdlgentry.cxx
@@ -0,0 +1,1530 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <memory>
+#include <condformatdlg.hxx>
+#include <condformatdlgentry.hxx>
+#include <conditio.hxx>
+#include <compiler.hxx>
+#include <colorscale.hxx>
+#include <condformathelper.hxx>
+
+#include <document.hxx>
+
+#include <o3tl/string_view.hxx>
+#include <svl/style.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/frame.hxx>
+#include <svl/stritem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/numformat.hxx>
+#include <svx/colorbox.hxx>
+#include <vcl/svapp.hxx>
+#include <formula/token.hxx>
+#include <formula/errorcodes.hxx>
+#include <tokenarray.hxx>
+#include <stlpool.hxx>
+#include <tabvwsh.hxx>
+#include <unotools/charclass.hxx>
+
+#include <colorformat.hxx>
+#include <scresid.hxx>
+#include <globstr.hrc>
+#include <strings.hrc>
+
+#include <set>
+
+// set the widget width to something to override their auto-width calc and
+// force them to take a 1/3 of the available space
+#define CommonWidgetWidth 10
+
+ScCondFrmtEntry::ScCondFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos)
+ : mpParent(pParent)
+ , mxBuilder(Application::CreateBuilder(pParent->GetContainer(), (SfxViewShell::Current() && SfxViewShell::Current()->isLOKMobilePhone())?OUString("modules/scalc/ui/conditionalentrymobile.ui"):OUString("modules/scalc/ui/conditionalentry.ui")))
+ , mxBorder(mxBuilder->weld_widget("border"))
+ , mxGrid(mxBuilder->weld_container("grid"))
+ , mxFtCondNr(mxBuilder->weld_label("number"))
+ , mxFtCondition(mxBuilder->weld_label("condition"))
+ , mbActive(false)
+ , maStrCondition(ScResId(SCSTR_CONDITION))
+ , mxLbType(mxBuilder->weld_combo_box("type"))
+ , mpDoc(pDoc)
+ , maPos(rPos)
+{
+ mxLbType->set_size_request(CommonWidgetWidth, -1);
+ mxLbType->connect_changed(LINK(pParent, ScCondFormatList, TypeListHdl));
+ mxGrid->connect_mouse_press(LINK(this, ScCondFrmtEntry, EntrySelectHdl));
+ maClickHdl = LINK( pParent, ScCondFormatList, EntrySelectHdl );
+
+ Show();
+}
+
+ScCondFrmtEntry::~ScCondFrmtEntry()
+{
+ mpParent->GetContainer()->move(mxBorder.get(), nullptr);
+}
+
+IMPL_LINK_NOARG(ScCondFrmtEntry, EntrySelectHdl, const MouseEvent&, bool)
+{
+ maClickHdl.Call(*this);
+ return false;
+}
+
+void ScCondFrmtEntry::SetIndex(sal_Int32 nIndex)
+{
+ OUString sLabel = maStrCondition + OUString::number(nIndex);
+ mxFtCondNr->set_label(sLabel);
+
+ // tdf#124412: uitest
+ mxFtCondition->set_buildable_name(sLabel.toUtf8());
+}
+
+void ScCondFrmtEntry::Select()
+{
+ mxFtCondition->set_label(OUString());
+ mxFtCondition->hide();
+ mxLbType->show();
+ mbActive = true;
+}
+
+void ScCondFrmtEntry::Deselect()
+{
+ OUString aCondText = GetExpressionString();
+ mxFtCondition->set_label(aCondText);
+ mxFtCondition->show();
+ mxLbType->hide();
+ mbActive = false;
+}
+
+//condition
+
+namespace {
+
+void FillStyleListBox( const ScDocument* pDoc, weld::ComboBox& rLbStyle )
+{
+ std::set<OUString> aStyleNames;
+ SfxStyleSheetIterator aStyleIter( pDoc->GetStyleSheetPool(), SfxStyleFamily::Para );
+ for ( SfxStyleSheetBase* pStyle = aStyleIter.First(); pStyle; pStyle = aStyleIter.Next() )
+ {
+ aStyleNames.insert(pStyle->GetName());
+ }
+ for(const auto& rStyleName : aStyleNames)
+ {
+ rLbStyle.append_text(rStyleName);
+ }
+}
+
+}
+
+const ScConditionMode ScConditionFrmtEntry::mpEntryToCond[ScConditionFrmtEntry::NUM_COND_ENTRIES] = {
+ ScConditionMode::Equal,
+ ScConditionMode::Less,
+ ScConditionMode::Greater,
+ ScConditionMode::EqLess,
+ ScConditionMode::EqGreater,
+ ScConditionMode::NotEqual,
+ ScConditionMode::Between,
+ ScConditionMode::NotBetween,
+ ScConditionMode::Duplicate,
+ ScConditionMode::NotDuplicate,
+ ScConditionMode::Top10,
+ ScConditionMode::Bottom10,
+ ScConditionMode::TopPercent,
+ ScConditionMode::BottomPercent,
+ ScConditionMode::AboveAverage,
+ ScConditionMode::BelowAverage,
+ ScConditionMode::AboveEqualAverage,
+ ScConditionMode::BelowEqualAverage,
+ ScConditionMode::Error,
+ ScConditionMode::NoError,
+ ScConditionMode::BeginsWith,
+ ScConditionMode::EndsWith,
+ ScConditionMode::ContainsText,
+ ScConditionMode::NotContainsText
+};
+
+ScConditionFrmtEntry::ScConditionFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, ScCondFormatDlg* pDialogParent,
+ const ScAddress& rPos, const ScCondFormatEntry* pFormatEntry)
+ : ScCondFrmtEntry(pParent, pDoc, rPos)
+ , mxLbCondType(mxBuilder->weld_combo_box("typeis"))
+ , mxEdVal1(new formula::RefEdit(mxBuilder->weld_entry("val1")))
+ , mxEdVal2(new formula::RefEdit(mxBuilder->weld_entry("val2")))
+ , mxFtVal(mxBuilder->weld_label("valueft"))
+ , mxFtStyle(mxBuilder->weld_label("styleft"))
+ , mxLbStyle(mxBuilder->weld_combo_box("style"))
+ , mxWdPreviewWin(mxBuilder->weld_widget("previewwin"))
+ , mxWdPreview(new weld::CustomWeld(*mxBuilder, "preview", maWdPreview))
+ , mbIsInStyleCreate(false)
+{
+ mxLbCondType->set_size_request(CommonWidgetWidth, -1);
+ mxLbType->set_size_request(CommonWidgetWidth, -1);
+ mxWdPreview->set_size_request(-1, mxLbStyle->get_preferred_size().Height());
+
+ mxLbType->set_active(1);
+
+ Init(pDialogParent);
+
+ StartListening(*pDoc->GetStyleSheetPool(), DuplicateHandling::Prevent);
+
+ if(pFormatEntry)
+ {
+ mxLbStyle->set_active_text(pFormatEntry->GetStyle());
+ StyleSelectHdl(*mxLbStyle);
+ ScConditionMode eMode = pFormatEntry->GetOperation();
+
+ mxLbCondType->set_active(ConditionModeToEntryPos(eMode));
+
+ switch(GetNumberEditFields(eMode))
+ {
+ case 0:
+ mxEdVal1->GetWidget()->hide();
+ mxEdVal2->GetWidget()->hide();
+ break;
+ case 1:
+ mxEdVal1->GetWidget()->show();
+ mxEdVal1->SetText(pFormatEntry->GetExpression(maPos, 0));
+ mxEdVal2->GetWidget()->hide();
+ OnEdChanged(*mxEdVal1);
+ break;
+ case 2:
+ mxEdVal1->GetWidget()->show();
+ mxEdVal1->SetText(pFormatEntry->GetExpression(maPos, 0));
+ OnEdChanged(*mxEdVal1);
+ mxEdVal2->GetWidget()->show();
+ mxEdVal2->SetText(pFormatEntry->GetExpression(maPos, 1));
+ OnEdChanged(*mxEdVal2);
+ break;
+ }
+ }
+ else
+ {
+ mxLbCondType->set_active(0);
+ mxEdVal2->GetWidget()->hide();
+ mxLbStyle->set_active(1);
+ }
+}
+
+ScConditionFrmtEntry::~ScConditionFrmtEntry()
+{
+}
+
+void ScConditionFrmtEntry::Init(ScCondFormatDlg* pDialogParent)
+{
+ mxEdVal1->SetGetFocusHdl( LINK( pDialogParent, ScCondFormatDlg, RangeGetFocusHdl ) );
+ mxEdVal2->SetGetFocusHdl( LINK( pDialogParent, ScCondFormatDlg, RangeGetFocusHdl ) );
+
+ mxEdVal1->SetModifyHdl( LINK( this, ScConditionFrmtEntry, OnEdChanged ) );
+ mxEdVal2->SetModifyHdl( LINK( this, ScConditionFrmtEntry, OnEdChanged ) );
+
+ FillStyleListBox( mpDoc, *mxLbStyle );
+ mxLbStyle->connect_changed( LINK( this, ScConditionFrmtEntry, StyleSelectHdl ) );
+
+ mxLbCondType->connect_changed( LINK( this, ScConditionFrmtEntry, ConditionTypeSelectHdl ) );
+}
+
+ScFormatEntry* ScConditionFrmtEntry::createConditionEntry() const
+{
+ ScConditionMode eMode = EntryPosToConditionMode(mxLbCondType->get_active());
+ OUString aExpr1 = mxEdVal1->GetText();
+ OUString aExpr2;
+ if (GetNumberEditFields(eMode) == 2)
+ {
+ aExpr2 = mxEdVal2->GetText();
+ if (aExpr2.isEmpty())
+ {
+ return nullptr;
+ }
+ }
+
+ ScFormatEntry* pEntry = new ScCondFormatEntry(eMode, aExpr1, aExpr2, *mpDoc, maPos, mxLbStyle->get_active_text());
+ return pEntry;
+}
+
+IMPL_LINK(ScConditionFrmtEntry, OnEdChanged, formula::RefEdit&, rRefEdit, void)
+{
+ weld::Entry& rEdit = *rRefEdit.GetWidget();
+ OUString aFormula = rEdit.get_text();
+
+ if( aFormula.isEmpty() )
+ {
+ mxFtVal->set_label(ScResId(STR_ENTER_VALUE));
+ return;
+ }
+
+ ScCompiler aComp( *mpDoc, maPos, mpDoc->GetGrammar() );
+ std::unique_ptr<ScTokenArray> ta(aComp.CompileString(aFormula));
+
+ // Error, warn the user
+ if( ta->GetCodeError() != FormulaError::NONE || ( ta->GetLen() == 0 ) )
+ {
+ rEdit.set_message_type(weld::EntryMessageType::Error);
+ mxFtVal->set_label(ScResId(STR_VALID_DEFERROR));
+ return;
+ }
+
+ // Recognized col/row name or string token, warn the user
+ formula::FormulaToken* token = ta->FirstToken();
+ formula::StackVar t = token->GetType();
+ OpCode op = token->GetOpCode();
+ if( ( op == ocColRowName ) ||
+ ( ( op == ocBad ) && ( t == formula::svString ) )
+ )
+ {
+ rEdit.set_message_type(weld::EntryMessageType::Warning);
+ mxFtVal->set_label(ScResId(STR_UNQUOTED_STRING));
+ return;
+ }
+
+ rEdit.set_message_type(weld::EntryMessageType::Normal);
+ mxFtVal->set_label("");
+}
+
+void ScConditionFrmtEntry::Select()
+{
+ mxFtVal->show();
+ ScCondFrmtEntry::Select();
+}
+
+void ScConditionFrmtEntry::Deselect()
+{
+ mxFtVal->hide();
+ ScCondFrmtEntry::Deselect();
+}
+
+sal_Int32 ScConditionFrmtEntry::ConditionModeToEntryPos( ScConditionMode eMode )
+{
+ for ( sal_Int32 i = 0; i < NUM_COND_ENTRIES; ++i )
+ {
+ if (mpEntryToCond[i] == eMode)
+ {
+ return i;
+ }
+ }
+ assert(false); // should never get here
+ return 0;
+}
+
+ScConditionMode ScConditionFrmtEntry::EntryPosToConditionMode( sal_Int32 aEntryPos )
+{
+ assert( 0 <= aEntryPos && aEntryPos < NUM_COND_ENTRIES );
+ return mpEntryToCond[aEntryPos];
+}
+
+sal_Int32 ScConditionFrmtEntry::GetNumberEditFields( ScConditionMode eMode )
+{
+ switch(eMode)
+ {
+ case ScConditionMode::Equal:
+ case ScConditionMode::Less:
+ case ScConditionMode::Greater:
+ case ScConditionMode::EqLess:
+ case ScConditionMode::EqGreater:
+ case ScConditionMode::NotEqual:
+ case ScConditionMode::Top10:
+ case ScConditionMode::Bottom10:
+ case ScConditionMode::TopPercent:
+ case ScConditionMode::BottomPercent:
+ case ScConditionMode::BeginsWith:
+ case ScConditionMode::EndsWith:
+ case ScConditionMode::ContainsText:
+ case ScConditionMode::NotContainsText:
+ case ScConditionMode::Error:
+ case ScConditionMode::NoError:
+ return 1;
+ case ScConditionMode::AboveAverage:
+ case ScConditionMode::BelowAverage:
+ case ScConditionMode::AboveEqualAverage:
+ case ScConditionMode::BelowEqualAverage:
+ case ScConditionMode::Duplicate:
+ case ScConditionMode::NotDuplicate:
+ return 0;
+ case ScConditionMode::Between:
+ case ScConditionMode::NotBetween:
+ return 2;
+ default:
+ assert(false); // should never get here
+ return 0;
+ }
+}
+
+OUString ScConditionFrmtEntry::GetExpressionString()
+{
+ return ScCondFormatHelper::GetExpression(CONDITION, mxLbCondType->get_active(), mxEdVal1->GetText(), mxEdVal2->GetText());
+}
+
+ScFormatEntry* ScConditionFrmtEntry::GetEntry() const
+{
+ return createConditionEntry();
+}
+
+void ScConditionFrmtEntry::SetActive()
+{
+ ScConditionMode eMode = EntryPosToConditionMode(mxLbCondType->get_active());
+ mxLbCondType->show();
+ switch(GetNumberEditFields(eMode))
+ {
+ case 1:
+ mxEdVal1->GetWidget()->show();
+ break;
+ case 2:
+ mxEdVal1->GetWidget()->show();
+ mxEdVal2->GetWidget()->show();
+ break;
+ }
+ mxFtStyle->show();
+ mxLbStyle->show();
+ mxWdPreviewWin->show();
+
+ Select();
+}
+
+void ScConditionFrmtEntry::SetInactive()
+{
+ mxLbCondType->hide();
+ mxEdVal1->GetWidget()->hide();
+ mxEdVal2->GetWidget()->hide();
+ mxFtStyle->hide();
+ mxLbStyle->hide();
+ mxWdPreviewWin->hide();
+
+ Deselect();
+}
+
+namespace {
+
+void UpdateStyleList(weld::ComboBox& rLbStyle, const ScDocument* pDoc)
+{
+ OUString aSelectedStyle = rLbStyle.get_active_text();
+ for (sal_Int32 i = rLbStyle.get_count(); i > 1; --i)
+ rLbStyle.remove(i - 1);
+ FillStyleListBox(pDoc, rLbStyle);
+ rLbStyle.set_active_text(aSelectedStyle);
+}
+
+}
+
+void ScConditionFrmtEntry::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ if(rHint.GetId() == SfxHintId::StyleSheetModified)
+ {
+ if(!mbIsInStyleCreate)
+ UpdateStyleList(*mxLbStyle, mpDoc);
+ }
+}
+
+namespace {
+
+void StyleSelect(weld::Window* pDialogParent, weld::ComboBox& rLbStyle, const ScDocument* pDoc, SvxFontPrevWindow& rWdPreview)
+{
+ if (rLbStyle.get_active() == 0)
+ {
+ // call new style dialog
+ SfxUInt16Item aFamilyItem( SID_STYLE_FAMILY, sal_uInt16(SfxStyleFamily::Para) );
+ SfxStringItem aRefItem( SID_STYLE_REFERENCE, ScResId(STR_STYLENAME_STANDARD) );
+ css::uno::Any aAny(pDialogParent->GetXWindow());
+ SfxUnoAnyItem aDialogParent( SID_DIALOG_PARENT, aAny );
+
+ // unlock the dispatcher so SID_STYLE_NEW can be executed
+ // (SetDispatcherLock would affect all Calc documents)
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SfxDispatcher* pDisp = pViewShell->GetDispatcher();
+ bool bLocked = pDisp->IsLocked();
+ if (bLocked)
+ pDisp->Lock(false);
+
+ // Execute the "new style" slot, complete with undo and all necessary updates.
+ // The return value (SfxUInt16Item) is ignored, look for new styles instead.
+ pDisp->ExecuteList(SID_STYLE_NEW,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aFamilyItem, &aRefItem }, { &aDialogParent });
+
+ if (bLocked)
+ pDisp->Lock(true);
+
+ // Find the new style and add it into the style list boxes
+ SfxStyleSheetIterator aStyleIter( pDoc->GetStyleSheetPool(), SfxStyleFamily::Para );
+ bool bFound = false;
+ for ( SfxStyleSheetBase* pStyle = aStyleIter.First(); pStyle && !bFound; pStyle = aStyleIter.Next() )
+ {
+ const OUString& aName = pStyle->GetName();
+ if (rLbStyle.find_text(aName) == -1) // all lists contain the same entries
+ {
+ for( sal_Int32 i = 1, n = rLbStyle.get_count(); i <= n && !bFound; ++i)
+ {
+ OUString aStyleName = ScGlobal::getCharClass().uppercase(rLbStyle.get_text(i));
+ if( i == n )
+ {
+ rLbStyle.append_text(aName);
+ rLbStyle.set_active_text(aName);
+ bFound = true;
+ }
+ else if( aStyleName > ScGlobal::getCharClass().uppercase(aName) )
+ {
+ rLbStyle.insert_text(i, aName);
+ rLbStyle.set_active_text(aName);
+ bFound = true;
+ }
+ }
+ }
+ }
+ }
+
+ OUString aStyleName = rLbStyle.get_active_text();
+ SfxStyleSheetBase* pStyleSheet = pDoc->GetStyleSheetPool()->Find( aStyleName, SfxStyleFamily::Para );
+ if(pStyleSheet)
+ {
+ const SfxItemSet& rSet = pStyleSheet->GetItemSet();
+ rWdPreview.SetFromItemSet(rSet, false);
+ }
+}
+
+}
+
+IMPL_LINK_NOARG(ScConditionFrmtEntry, StyleSelectHdl, weld::ComboBox&, void)
+{
+ mbIsInStyleCreate = true;
+ StyleSelect(mpParent->GetFrameWeld(), *mxLbStyle, mpDoc, maWdPreview);
+ mbIsInStyleCreate = false;
+}
+
+// formula
+
+ScFormulaFrmtEntry::ScFormulaFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, ScCondFormatDlg* pDialogParent, const ScAddress& rPos, const ScCondFormatEntry* pFormat)
+ : ScCondFrmtEntry(pParent, pDoc, rPos)
+ , mxFtStyle(mxBuilder->weld_label("styleft"))
+ , mxLbStyle(mxBuilder->weld_combo_box("style"))
+ , mxWdPreviewWin(mxBuilder->weld_widget("previewwin"))
+ , mxWdPreview(new weld::CustomWeld(*mxBuilder, "preview", maWdPreview))
+ , mxEdFormula(new formula::RefEdit(mxBuilder->weld_entry("formula")))
+{
+ mxLbType->set_size_request(CommonWidgetWidth, -1);
+ mxWdPreview->set_size_request(-1, mxLbStyle->get_preferred_size().Height());
+
+ Init(pDialogParent);
+
+ mxLbType->set_active(2);
+
+ if(pFormat)
+ {
+ mxEdFormula->SetText(pFormat->GetExpression(rPos, 0, 0, pDoc->GetGrammar()));
+ mxLbStyle->set_active_text(pFormat->GetStyle());
+ }
+ else
+ {
+ mxLbStyle->set_active(1);
+ }
+
+ StyleSelectHdl(*mxLbStyle);
+}
+
+ScFormulaFrmtEntry::~ScFormulaFrmtEntry()
+{
+}
+
+void ScFormulaFrmtEntry::Init(ScCondFormatDlg* pDialogParent)
+{
+ mxEdFormula->SetGetFocusHdl( LINK( pDialogParent, ScCondFormatDlg, RangeGetFocusHdl ) );
+
+ FillStyleListBox( mpDoc, *mxLbStyle );
+ mxLbStyle->connect_changed( LINK( this, ScFormulaFrmtEntry, StyleSelectHdl ) );
+}
+
+IMPL_LINK_NOARG(ScFormulaFrmtEntry, StyleSelectHdl, weld::ComboBox&, void)
+{
+ StyleSelect(mpParent->GetFrameWeld(), *mxLbStyle, mpDoc, maWdPreview);
+}
+
+ScFormatEntry* ScFormulaFrmtEntry::createFormulaEntry() const
+{
+ OUString aFormula = mxEdFormula->GetText();
+ if(aFormula.isEmpty())
+ return nullptr;
+
+ ScFormatEntry* pEntry = new ScCondFormatEntry(ScConditionMode::Direct, aFormula, OUString(), *mpDoc, maPos, mxLbStyle->get_active_text());
+ return pEntry;
+}
+
+ScFormatEntry* ScFormulaFrmtEntry::GetEntry() const
+{
+ return createFormulaEntry();
+}
+
+OUString ScFormulaFrmtEntry::GetExpressionString()
+{
+ return ScCondFormatHelper::GetExpression(FORMULA, 0, mxEdFormula->GetText());
+}
+
+void ScFormulaFrmtEntry::SetActive()
+{
+ mxWdPreviewWin->show();
+ mxFtStyle->show();
+ mxLbStyle->show();
+ mxEdFormula->GetWidget()->show();
+
+ Select();
+}
+
+void ScFormulaFrmtEntry::SetInactive()
+{
+ mxWdPreviewWin->hide();
+ mxFtStyle->hide();
+ mxLbStyle->hide();
+ mxEdFormula->GetWidget()->hide();
+
+ Deselect();
+}
+
+//color scale
+
+namespace {
+
+OUString convertNumberToString(double nVal, const ScDocument* pDoc)
+{
+ SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable();
+ OUString aText;
+ pNumberFormatter->GetInputLineString(nVal, 0, aText);
+ return aText;
+}
+
+const struct
+{
+ ScColorScaleEntryType eType;
+ const char* sId;
+} TypeIdMap[] = {
+ { COLORSCALE_AUTO, "auto" },
+ { COLORSCALE_MIN, "min" },
+ { COLORSCALE_MAX, "max" },
+ { COLORSCALE_PERCENTILE, "percentil" },
+ { COLORSCALE_VALUE, "value" },
+ { COLORSCALE_PERCENT, "percent" },
+ { COLORSCALE_FORMULA, "formula" },
+};
+
+ScColorScaleEntryType getTypeForId(std::u16string_view sId)
+{
+ for (auto& r : TypeIdMap)
+ {
+ if (o3tl::equalsAscii(sId, r.sId))
+ return r.eType;
+ }
+ assert(false); // The id is not in TypeIdMap - something not in sync?
+ return COLORSCALE_AUTO; // invalid id - use default
+}
+
+// Item ids are imported from .ui into OUString* and are referenced by entry data.
+// See commit 83cefb5ceb4428d61a5b9fae80d1e673131e9bfe
+
+ScColorScaleEntryType getSelectedType(const weld::ComboBox& rListBox)
+{
+ return getTypeForId(rListBox.get_active_id());
+}
+
+sal_Int32 getEntryPos(const weld::ComboBox& rListBox, ScColorScaleEntryType eType)
+{
+ const sal_Int32 nSize = rListBox.get_count();
+ for (sal_Int32 i = 0; i < nSize; ++i)
+ {
+ if (getTypeForId(rListBox.get_id(i)) == eType)
+ return i;
+ }
+ return -1;
+}
+
+void selectType(weld::ComboBox& rListBox, ScColorScaleEntryType eType)
+{
+ const sal_Int32 nPos = getEntryPos(rListBox, eType);
+ if (nPos >= 0)
+ rListBox.set_active(nPos);
+}
+
+void removeType(weld::ComboBox& rListBox, ScColorScaleEntryType eType)
+{
+ const sal_Int32 nPos = getEntryPos(rListBox, eType);
+ if (nPos >= 0)
+ rListBox.remove(nPos);
+}
+
+void SetColorScaleEntryTypes( const ScColorScaleEntry& rEntry, weld::ComboBox& rLbType, weld::Entry& rEdit, ColorListBox& rLbCol, const ScDocument* pDoc )
+{
+ // entry Automatic is not available for color scales
+ assert(rEntry.GetType() > COLORSCALE_AUTO);
+ selectType(rLbType, rEntry.GetType());
+ switch(rEntry.GetType())
+ {
+ case COLORSCALE_MIN:
+ case COLORSCALE_MAX:
+ break;
+ case COLORSCALE_PERCENTILE:
+ case COLORSCALE_VALUE:
+ case COLORSCALE_PERCENT:
+ {
+ double nVal = rEntry.GetValue();
+ rEdit.set_text(convertNumberToString(nVal, pDoc));
+ }
+ break;
+ case COLORSCALE_FORMULA:
+ rEdit.set_text(rEntry.GetFormula(formula::FormulaGrammar::GRAM_DEFAULT));
+ break;
+ case COLORSCALE_AUTO:
+ abort();
+ break;
+ }
+ rLbCol.SelectEntry(rEntry.GetColor());
+}
+
+void SetColorScaleEntry(ScColorScaleEntry* pEntry, const weld::ComboBox& rType, const weld::Entry& rValue,
+ ScDocument* pDoc, const ScAddress& rPos)
+{
+ ScColorScaleEntryType eType = getSelectedType(rType);
+
+ pEntry->SetType(eType);
+ switch (eType)
+ {
+ case COLORSCALE_AUTO:
+ case COLORSCALE_MIN:
+ case COLORSCALE_MAX:
+ break;
+ case COLORSCALE_PERCENTILE:
+ case COLORSCALE_VALUE:
+ case COLORSCALE_PERCENT:
+ {
+ sal_uInt32 nIndex = 0;
+ double nVal = 0;
+ SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable();
+ (void)pNumberFormatter->IsNumberFormat(rValue.get_text(), nIndex, nVal);
+ pEntry->SetValue(nVal);
+ }
+ break;
+ case COLORSCALE_FORMULA:
+ pEntry->SetFormula(rValue.get_text(), *pDoc, rPos);
+ break;
+ default:
+ break;
+ }
+}
+
+ScColorScaleEntry* createColorScaleEntry( const weld::ComboBox& rType, const ColorListBox& rColor, const weld::Entry& rValue, ScDocument* pDoc, const ScAddress& rPos )
+{
+ ScColorScaleEntry* pEntry = new ScColorScaleEntry();
+
+ SetColorScaleEntry(pEntry, rType, rValue, pDoc, rPos);
+ Color aColor = rColor.GetSelectEntryColor();
+ pEntry->SetColor(aColor);
+ return pEntry;
+}
+
+}
+
+ScColorScale2FrmtEntry::ScColorScale2FrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScColorScaleFormat* pFormat)
+ : ScCondFrmtEntry(pParent, pDoc, rPos)
+ , mxLbColorFormat(mxBuilder->weld_combo_box("colorformat"))
+ , mxLbEntryTypeMin(mxBuilder->weld_combo_box("colscalemin"))
+ , mxLbEntryTypeMax(mxBuilder->weld_combo_box("colscalemax"))
+ , mxEdMin(mxBuilder->weld_entry("edcolscalemin"))
+ , mxEdMax(mxBuilder->weld_entry("edcolscalemax"))
+ , mxLbColMin(new ColorListBox(mxBuilder->weld_menu_button("lbcolmin"), [this]{ return mpParent->GetFrameWeld(); }))
+ , mxLbColMax(new ColorListBox(mxBuilder->weld_menu_button("lbcolmax"), [this]{ return mpParent->GetFrameWeld(); }))
+ , mxFtMin(mxBuilder->weld_label("Label_minimum"))
+ , mxFtMax(mxBuilder->weld_label("Label_maximum"))
+{
+ mxLbColorFormat->set_size_request(CommonWidgetWidth, -1);
+ mxLbEntryTypeMin->set_size_request(CommonWidgetWidth, -1);
+ mxLbEntryTypeMax->set_size_request(CommonWidgetWidth, -1);
+ mxLbColMin->get_widget().set_size_request(CommonWidgetWidth, -1);
+ mxLbColMax->get_widget().set_size_request(CommonWidgetWidth, -1);
+
+ mxFtMin->show();
+ mxFtMax->show();
+
+ // remove the automatic entry from color scales
+ removeType(*mxLbEntryTypeMin, COLORSCALE_AUTO);
+ removeType(*mxLbEntryTypeMax, COLORSCALE_AUTO);
+ // "min" selector doesn't need "max" entry, and vice versa
+ removeType(*mxLbEntryTypeMin, COLORSCALE_MAX);
+ removeType(*mxLbEntryTypeMax, COLORSCALE_MIN);
+
+ mxLbType->set_active(0);
+ mxLbColorFormat->set_active(0);
+ Init();
+ if(pFormat)
+ {
+ ScColorScaleEntries::const_iterator itr = pFormat->begin();
+ SetColorScaleEntryTypes(*itr[0], *mxLbEntryTypeMin, *mxEdMin, *mxLbColMin, pDoc);
+ ++itr;
+ SetColorScaleEntryTypes(*itr[0], *mxLbEntryTypeMax, *mxEdMax, *mxLbColMax, pDoc);
+ }
+ else
+ {
+ selectType(*mxLbEntryTypeMin, COLORSCALE_MIN);
+ selectType(*mxLbEntryTypeMax, COLORSCALE_MAX);
+ }
+
+ mxLbColorFormat->connect_changed( LINK( pParent, ScCondFormatList, ColFormatTypeHdl ) );
+
+ EntryTypeHdl(*mxLbEntryTypeMin);
+ EntryTypeHdl(*mxLbEntryTypeMax);
+}
+
+ScColorScale2FrmtEntry::~ScColorScale2FrmtEntry()
+{
+}
+
+void ScColorScale2FrmtEntry::Init()
+{
+ mxLbEntryTypeMin->connect_changed( LINK( this, ScColorScale2FrmtEntry, EntryTypeHdl ) );
+ mxLbEntryTypeMax->connect_changed( LINK( this, ScColorScale2FrmtEntry, EntryTypeHdl ) );
+ mxLbColMin->SelectEntry(Color(0xffff6d)); // Light Yellow 2
+ mxLbColMax->SelectEntry(Color(0x77bc65)); // Light Green 2
+}
+
+ScFormatEntry* ScColorScale2FrmtEntry::createColorscaleEntry() const
+{
+ ScColorScaleFormat* pColorScale = new ScColorScaleFormat(mpDoc);
+ pColorScale->AddEntry(createColorScaleEntry(*mxLbEntryTypeMin, *mxLbColMin, *mxEdMin, mpDoc, maPos));
+ pColorScale->AddEntry(createColorScaleEntry(*mxLbEntryTypeMax, *mxLbColMax, *mxEdMax, mpDoc, maPos));
+ return pColorScale;
+}
+
+OUString ScColorScale2FrmtEntry::GetExpressionString()
+{
+ return ScCondFormatHelper::GetExpression( COLORSCALE, 0 );
+}
+
+ScFormatEntry* ScColorScale2FrmtEntry::GetEntry() const
+{
+ return createColorscaleEntry();
+}
+
+void ScColorScale2FrmtEntry::SetActive()
+{
+ mxLbColorFormat->show();
+
+ mxLbEntryTypeMin->show();
+ mxLbEntryTypeMax->show();
+
+ mxEdMin->show();
+ mxEdMax->show();
+
+ mxLbColMin->show();
+ mxLbColMax->show();
+
+ Select();
+}
+
+void ScColorScale2FrmtEntry::SetInactive()
+{
+ mxLbColorFormat->hide();
+
+ mxLbEntryTypeMin->hide();
+ mxLbEntryTypeMax->hide();
+
+ mxEdMin->hide();
+ mxEdMax->hide();
+
+ mxLbColMin->hide();
+ mxLbColMax->hide();
+
+ Deselect();
+}
+
+IMPL_LINK( ScColorScale2FrmtEntry, EntryTypeHdl, weld::ComboBox&, rBox, void )
+{
+ weld::Entry* pEd = nullptr;
+ if (&rBox == mxLbEntryTypeMin.get())
+ pEd = mxEdMin.get();
+ else if (&rBox == mxLbEntryTypeMax.get())
+ pEd = mxEdMax.get();
+
+ if (!pEd)
+ return;
+
+ bool bEnableEdit = true;
+ if (getSelectedType(rBox) <= COLORSCALE_MAX)
+ {
+ bEnableEdit = false;
+ }
+
+ if (bEnableEdit)
+ pEd->set_sensitive(true);
+ else
+ pEd->set_sensitive(false);
+}
+
+ScColorScale3FrmtEntry::ScColorScale3FrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScColorScaleFormat* pFormat)
+ : ScCondFrmtEntry(pParent, pDoc, rPos)
+ , mxLbColorFormat(mxBuilder->weld_combo_box("colorformat"))
+ , mxLbEntryTypeMin(mxBuilder->weld_combo_box("colscalemin"))
+ , mxLbEntryTypeMiddle(mxBuilder->weld_combo_box("colscalemiddle"))
+ , mxLbEntryTypeMax(mxBuilder->weld_combo_box("colscalemax"))
+ , mxEdMin(mxBuilder->weld_entry("edcolscalemin"))
+ , mxEdMiddle(mxBuilder->weld_entry("edcolscalemiddle"))
+ , mxEdMax(mxBuilder->weld_entry("edcolscalemax"))
+ , mxLbColMin(new ColorListBox(mxBuilder->weld_menu_button("lbcolmin"), [this]{ return mpParent->GetFrameWeld(); }))
+ , mxLbColMiddle(new ColorListBox(mxBuilder->weld_menu_button("lbcolmiddle"), [this]{ return mpParent->GetFrameWeld(); }))
+ , mxLbColMax(new ColorListBox(mxBuilder->weld_menu_button("lbcolmax"), [this]{ return mpParent->GetFrameWeld(); }))
+ , mxFtMin(mxBuilder->weld_label("Label_minimum"))
+ , mxFtMax(mxBuilder->weld_label("Label_maximum"))
+{
+ mxLbColorFormat->set_size_request(CommonWidgetWidth, -1);
+ mxLbEntryTypeMin->set_size_request(CommonWidgetWidth, -1);
+ mxLbEntryTypeMiddle->set_size_request(CommonWidgetWidth, -1);
+ mxLbEntryTypeMax->set_size_request(CommonWidgetWidth, -1);
+ mxLbColMin->get_widget().set_size_request(CommonWidgetWidth, -1);
+ mxLbColMiddle->get_widget().set_size_request(CommonWidgetWidth, -1);
+ mxLbColMax->get_widget().set_size_request(CommonWidgetWidth, -1);
+ mxFtMin->show();
+ mxFtMax->show();
+
+ // remove the automatic entry from color scales
+ removeType(*mxLbEntryTypeMin, COLORSCALE_AUTO);
+ removeType(*mxLbEntryTypeMiddle, COLORSCALE_AUTO);
+ removeType(*mxLbEntryTypeMax, COLORSCALE_AUTO);
+ // "min" selector doesn't need "max" entry, and vice versa
+ removeType(*mxLbEntryTypeMin, COLORSCALE_MAX);
+ removeType(*mxLbEntryTypeMax, COLORSCALE_MIN);
+ mxLbColorFormat->set_active(1);
+
+ Init();
+ mxLbType->set_active(0);
+ if(pFormat)
+ {
+ ScColorScaleEntries::const_iterator itr = pFormat->begin();
+ SetColorScaleEntryTypes(*itr[0], *mxLbEntryTypeMin, *mxEdMin, *mxLbColMin, pDoc);
+ assert(pFormat->size() == 3);
+ ++itr;
+ SetColorScaleEntryTypes(*itr[0], *mxLbEntryTypeMiddle, *mxEdMiddle, *mxLbColMiddle, pDoc);
+ ++itr;
+ SetColorScaleEntryTypes(*itr[0], *mxLbEntryTypeMax, *mxEdMax, *mxLbColMax, pDoc);
+ }
+ else
+ {
+ mxLbColorFormat->set_active(1);
+ selectType(*mxLbEntryTypeMin, COLORSCALE_MIN);
+ selectType(*mxLbEntryTypeMiddle, COLORSCALE_PERCENTILE);
+ selectType(*mxLbEntryTypeMax, COLORSCALE_MAX);
+ mxEdMiddle->set_text(OUString::number(50));
+ }
+
+ mxLbColorFormat->connect_changed( LINK( pParent, ScCondFormatList, ColFormatTypeHdl ) );
+ EntryTypeHdl(*mxLbEntryTypeMin);
+ EntryTypeHdl(*mxLbEntryTypeMiddle);
+ EntryTypeHdl(*mxLbEntryTypeMax);
+}
+
+ScColorScale3FrmtEntry::~ScColorScale3FrmtEntry()
+{
+}
+
+void ScColorScale3FrmtEntry::Init()
+{
+ mxLbEntryTypeMin->connect_changed( LINK( this, ScColorScale3FrmtEntry, EntryTypeHdl ) );
+ mxLbEntryTypeMax->connect_changed( LINK( this, ScColorScale3FrmtEntry, EntryTypeHdl ) );
+ mxLbEntryTypeMiddle->connect_changed( LINK( this, ScColorScale3FrmtEntry, EntryTypeHdl ) );
+ mxLbColMin->SelectEntry(COL_LIGHTRED);
+ mxLbColMiddle->SelectEntry(COL_YELLOW);
+ mxLbColMax->SelectEntry(Color(0x00a933));
+}
+
+ScFormatEntry* ScColorScale3FrmtEntry::createColorscaleEntry() const
+{
+ ScColorScaleFormat* pColorScale = new ScColorScaleFormat(mpDoc);
+ pColorScale->AddEntry(createColorScaleEntry(*mxLbEntryTypeMin, *mxLbColMin, *mxEdMin, mpDoc, maPos));
+ if (mxLbColorFormat->get_active() == 1)
+ pColorScale->AddEntry(createColorScaleEntry(*mxLbEntryTypeMiddle, *mxLbColMiddle, *mxEdMiddle, mpDoc, maPos));
+ pColorScale->AddEntry(createColorScaleEntry(*mxLbEntryTypeMax, *mxLbColMax, *mxEdMax, mpDoc, maPos));
+ return pColorScale;
+}
+
+OUString ScColorScale3FrmtEntry::GetExpressionString()
+{
+ return ScCondFormatHelper::GetExpression( COLORSCALE, 0 );
+}
+
+ScFormatEntry* ScColorScale3FrmtEntry::GetEntry() const
+{
+ return createColorscaleEntry();
+}
+
+void ScColorScale3FrmtEntry::SetActive()
+{
+ mxLbColorFormat->show();
+ mxLbEntryTypeMin->show();
+ mxLbEntryTypeMiddle->show();
+ mxLbEntryTypeMax->show();
+
+ mxEdMin->show();
+ mxEdMiddle->show();
+ mxEdMax->show();
+
+ mxLbColMin->show();
+ mxLbColMiddle->show();
+ mxLbColMax->show();
+
+ Select();
+}
+
+void ScColorScale3FrmtEntry::SetInactive()
+{
+ mxLbColorFormat->hide();
+
+ mxLbEntryTypeMin->hide();
+ mxLbEntryTypeMiddle->hide();
+ mxLbEntryTypeMax->hide();
+
+ mxEdMin->hide();
+ mxEdMiddle->hide();
+ mxEdMax->hide();
+
+ mxLbColMin->hide();
+ mxLbColMiddle->hide();
+ mxLbColMax->hide();
+
+ Deselect();
+}
+
+IMPL_LINK( ScColorScale3FrmtEntry, EntryTypeHdl, weld::ComboBox&, rBox, void )
+{
+ weld::Entry* pEd = nullptr;
+ if(&rBox == mxLbEntryTypeMin.get())
+ pEd = mxEdMin.get();
+ else if(&rBox == mxLbEntryTypeMiddle.get())
+ pEd = mxEdMiddle.get();
+ else if(&rBox == mxLbEntryTypeMax.get())
+ pEd = mxEdMax.get();
+
+ if (!pEd)
+ return;
+
+ bool bEnableEdit = true;
+ if (getSelectedType(rBox) <= COLORSCALE_MAX)
+ {
+ bEnableEdit = false;
+ }
+
+ if(bEnableEdit)
+ pEd->set_sensitive(true);
+ else
+ pEd->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(ScConditionFrmtEntry, ConditionTypeSelectHdl, weld::ComboBox&, void)
+{
+ sal_Int32 nSelectPos = mxLbCondType->get_active();
+ ScConditionMode eMode = EntryPosToConditionMode(nSelectPos);
+ switch(GetNumberEditFields(eMode))
+ {
+ case 0:
+ mxEdVal1->GetWidget()->hide();
+ mxEdVal2->GetWidget()->hide();
+ mxFtVal->hide();
+ break;
+ case 1:
+ mxEdVal1->GetWidget()->show();
+ mxEdVal2->GetWidget()->hide();
+ mxFtVal->show();
+ break;
+ case 2:
+ mxEdVal1->GetWidget()->show();
+ mxEdVal2->GetWidget()->show();
+ mxFtVal->show();
+ break;
+ }
+}
+
+//databar
+
+namespace {
+
+void SetDataBarEntryTypes( const ScColorScaleEntry& rEntry, weld::ComboBox& rLbType, weld::Entry& rEdit, const ScDocument* pDoc )
+{
+ selectType(rLbType, rEntry.GetType());
+ switch(rEntry.GetType())
+ {
+ case COLORSCALE_AUTO:
+ case COLORSCALE_MIN:
+ case COLORSCALE_MAX:
+ break;
+ case COLORSCALE_VALUE:
+ case COLORSCALE_PERCENT:
+ case COLORSCALE_PERCENTILE:
+ {
+ double nVal = rEntry.GetValue();
+ SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable();
+ OUString aText;
+ pNumberFormatter->GetInputLineString(nVal, 0, aText);
+ rEdit.set_text(aText);
+ }
+ break;
+ case COLORSCALE_FORMULA:
+ rEdit.set_text(rEntry.GetFormula(formula::FormulaGrammar::GRAM_DEFAULT));
+ break;
+ }
+}
+
+}
+
+ScDataBarFrmtEntry::ScDataBarFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScDataBarFormat* pFormat)
+ : ScCondFrmtEntry(pParent, pDoc, rPos)
+ , mxLbColorFormat(mxBuilder->weld_combo_box("colorformat"))
+ , mxLbDataBarMinType(mxBuilder->weld_combo_box("colscalemin"))
+ , mxLbDataBarMaxType(mxBuilder->weld_combo_box("colscalemax"))
+ , mxEdDataBarMin(mxBuilder->weld_entry("edcolscalemin"))
+ , mxEdDataBarMax(mxBuilder->weld_entry("edcolscalemax"))
+ , mxBtOptions(mxBuilder->weld_button("options"))
+ , mxFtMin(mxBuilder->weld_label("Label_minimum"))
+ , mxFtMax(mxBuilder->weld_label("Label_maximum"))
+{
+ mxLbColorFormat->set_size_request(CommonWidgetWidth, -1);
+ mxLbDataBarMinType->set_size_request(CommonWidgetWidth, -1);
+ mxLbDataBarMaxType->set_size_request(CommonWidgetWidth, -1);
+
+ // "min" selector doesn't need "max" entry, and vice versa
+ removeType(*mxLbDataBarMinType, COLORSCALE_MAX);
+ removeType(*mxLbDataBarMaxType, COLORSCALE_MIN);
+
+ mxFtMin->show();
+ mxFtMax->show();
+
+ mxLbColorFormat->set_active(2);
+ mxLbType->set_active(0);
+ if(pFormat)
+ {
+ mpDataBarData.reset(new ScDataBarFormatData(*pFormat->GetDataBarData()));
+ SetDataBarEntryTypes(*mpDataBarData->mpLowerLimit, *mxLbDataBarMinType, *mxEdDataBarMin, pDoc);
+ SetDataBarEntryTypes(*mpDataBarData->mpUpperLimit, *mxLbDataBarMaxType, *mxEdDataBarMax, pDoc);
+ DataBarTypeSelectHdl(*mxLbDataBarMinType);
+ }
+ else
+ {
+ selectType(*mxLbDataBarMinType, COLORSCALE_AUTO);
+ selectType(*mxLbDataBarMaxType, COLORSCALE_AUTO);
+ DataBarTypeSelectHdl(*mxLbDataBarMinType);
+ }
+ Init();
+
+ mxLbColorFormat->connect_changed( LINK( pParent, ScCondFormatList, ColFormatTypeHdl ) );
+}
+
+ScDataBarFrmtEntry::~ScDataBarFrmtEntry()
+{
+}
+
+ScFormatEntry* ScDataBarFrmtEntry::GetEntry() const
+{
+ return createDatabarEntry();
+}
+
+void ScDataBarFrmtEntry::Init()
+{
+ mxLbDataBarMinType->connect_changed( LINK( this, ScDataBarFrmtEntry, DataBarTypeSelectHdl ) );
+ mxLbDataBarMaxType->connect_changed( LINK( this, ScDataBarFrmtEntry, DataBarTypeSelectHdl ) );
+
+ mxBtOptions->connect_clicked( LINK( this, ScDataBarFrmtEntry, OptionBtnHdl ) );
+
+ if(!mpDataBarData)
+ {
+ mpDataBarData.reset(new ScDataBarFormatData());
+ mpDataBarData->mpUpperLimit.reset(new ScColorScaleEntry());
+ mpDataBarData->mpLowerLimit.reset(new ScColorScaleEntry());
+ mpDataBarData->mpLowerLimit->SetType(COLORSCALE_AUTO);
+ mpDataBarData->mpUpperLimit->SetType(COLORSCALE_AUTO);
+ mpDataBarData->maPositiveColor = 0x2a6099;
+ }
+}
+
+ScFormatEntry* ScDataBarFrmtEntry::createDatabarEntry() const
+{
+ SetColorScaleEntry(mpDataBarData->mpLowerLimit.get(), *mxLbDataBarMinType,
+ *mxEdDataBarMin, mpDoc, maPos);
+ SetColorScaleEntry(mpDataBarData->mpUpperLimit.get(), *mxLbDataBarMaxType,
+ *mxEdDataBarMax, mpDoc, maPos);
+ ScDataBarFormat* pDataBar = new ScDataBarFormat(mpDoc);
+ pDataBar->SetDataBarData(new ScDataBarFormatData(*mpDataBarData));
+ return pDataBar;
+}
+
+OUString ScDataBarFrmtEntry::GetExpressionString()
+{
+ return ScCondFormatHelper::GetExpression( DATABAR, 0 );
+}
+
+void ScDataBarFrmtEntry::SetActive()
+{
+ mxLbColorFormat->show();
+
+ mxLbDataBarMinType->show();
+ mxLbDataBarMaxType->show();
+ mxEdDataBarMin->show();
+ mxEdDataBarMax->show();
+ mxBtOptions->show();
+
+ Select();
+}
+
+void ScDataBarFrmtEntry::SetInactive()
+{
+ mxLbColorFormat->hide();
+
+ mxLbDataBarMinType->hide();
+ mxLbDataBarMaxType->hide();
+ mxEdDataBarMin->hide();
+ mxEdDataBarMax->hide();
+ mxBtOptions->hide();
+
+ Deselect();
+}
+
+IMPL_LINK_NOARG( ScDataBarFrmtEntry, DataBarTypeSelectHdl, weld::ComboBox&, void )
+{
+ if (getSelectedType(*mxLbDataBarMinType) <= COLORSCALE_MAX)
+ mxEdDataBarMin->set_sensitive(false);
+ else
+ mxEdDataBarMin->set_sensitive(true);
+
+ if (getSelectedType(*mxLbDataBarMaxType) <= COLORSCALE_MAX)
+ mxEdDataBarMax->set_sensitive(false);
+ else
+ mxEdDataBarMax->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG( ScDataBarFrmtEntry, OptionBtnHdl, weld::Button&, void )
+{
+ SetColorScaleEntry(mpDataBarData->mpLowerLimit.get(), *mxLbDataBarMinType,
+ *mxEdDataBarMin, mpDoc, maPos);
+ SetColorScaleEntry(mpDataBarData->mpUpperLimit.get(), *mxLbDataBarMaxType,
+ *mxEdDataBarMax, mpDoc, maPos);
+ ScDataBarSettingsDlg aDlg(mpParent->GetFrameWeld(), *mpDataBarData, mpDoc, maPos);
+ if (aDlg.run() == RET_OK)
+ {
+ mpDataBarData.reset(aDlg.GetData());
+ SetDataBarEntryTypes(*mpDataBarData->mpLowerLimit, *mxLbDataBarMinType, *mxEdDataBarMin, mpDoc);
+ SetDataBarEntryTypes(*mpDataBarData->mpUpperLimit, *mxLbDataBarMaxType, *mxEdDataBarMax, mpDoc);
+ DataBarTypeSelectHdl(*mxLbDataBarMinType);
+ }
+}
+
+ScDateFrmtEntry::ScDateFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScCondDateFormatEntry* pFormat)
+ : ScCondFrmtEntry(pParent, pDoc, ScAddress())
+ , mxLbDateEntry(mxBuilder->weld_combo_box("datetype"))
+ , mxFtStyle(mxBuilder->weld_label("styleft"))
+ , mxLbStyle(mxBuilder->weld_combo_box("style"))
+ , mxWdPreviewWin(mxBuilder->weld_widget("previewwin"))
+ , mxWdPreview(new weld::CustomWeld(*mxBuilder, "preview", maWdPreview))
+ , mbIsInStyleCreate(false)
+{
+ mxLbDateEntry->set_size_request(CommonWidgetWidth, -1);
+ mxLbStyle->set_size_request(CommonWidgetWidth, -1);
+
+ mxWdPreview->set_size_request(mxLbStyle->get_preferred_size().Height(), -1);
+
+ Init();
+
+ StartListening(*pDoc->GetStyleSheetPool(), DuplicateHandling::Prevent);
+
+ if(pFormat)
+ {
+ sal_Int32 nPos = static_cast<sal_Int32>(pFormat->GetDateType());
+ mxLbDateEntry->set_active(nPos);
+
+ mxLbStyle->set_active_text(pFormat->GetStyleName());
+ }
+
+ StyleSelectHdl(*mxLbStyle);
+}
+
+ScDateFrmtEntry::~ScDateFrmtEntry()
+{
+}
+
+void ScDateFrmtEntry::Init()
+{
+ mxLbDateEntry->set_active(0);
+ mxLbType->set_active(3);
+
+ FillStyleListBox( mpDoc, *mxLbStyle );
+ mxLbStyle->connect_changed( LINK( this, ScDateFrmtEntry, StyleSelectHdl ) );
+ mxLbStyle->set_active(1);
+}
+
+void ScDateFrmtEntry::SetActive()
+{
+ mxLbDateEntry->show();
+ mxFtStyle->show();
+ mxWdPreviewWin->show();
+ mxLbStyle->show();
+
+ Select();
+}
+
+void ScDateFrmtEntry::SetInactive()
+{
+ mxLbDateEntry->hide();
+ mxFtStyle->hide();
+ mxWdPreviewWin->hide();
+ mxLbStyle->hide();
+
+ Deselect();
+}
+
+void ScDateFrmtEntry::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if(rHint.GetId() == SfxHintId::StyleSheetModified)
+ {
+ if(!mbIsInStyleCreate)
+ UpdateStyleList(*mxLbStyle, mpDoc);
+ }
+}
+
+ScFormatEntry* ScDateFrmtEntry::GetEntry() const
+{
+ ScCondDateFormatEntry* pNewEntry = new ScCondDateFormatEntry(mpDoc);
+ condformat::ScCondFormatDateType eType = static_cast<condformat::ScCondFormatDateType>(mxLbDateEntry->get_active());
+ pNewEntry->SetDateType(eType);
+ pNewEntry->SetStyleName(mxLbStyle->get_active_text());
+ return pNewEntry;
+}
+
+OUString ScDateFrmtEntry::GetExpressionString()
+{
+ // tdf#124412 - set actual condition for an inactive date entry
+ return ScCondFormatHelper::GetExpression(DATE, mxLbDateEntry->get_active());
+}
+
+IMPL_LINK_NOARG( ScDateFrmtEntry, StyleSelectHdl, weld::ComboBox&, void )
+{
+ mbIsInStyleCreate = true;
+ StyleSelect(mpParent->GetFrameWeld(), *mxLbStyle, mpDoc, maWdPreview);
+ mbIsInStyleCreate = false;
+}
+
+class ScIconSetFrmtDataEntry
+{
+protected:
+ std::unique_ptr<weld::Builder> mxBuilder;
+private:
+ std::unique_ptr<weld::Container> mxGrid;
+ std::unique_ptr<weld::Image> mxImgIcon;
+ std::unique_ptr<weld::Label> mxFtEntry;
+ std::unique_ptr<weld::Entry> mxEdEntry;
+ std::unique_ptr<weld::ComboBox> mxLbEntryType;
+ weld::Container* mpContainer;
+
+public:
+ ScIconSetFrmtDataEntry(weld::Container* pParent, ScIconSetType eType, const ScDocument* pDoc,
+ sal_Int32 i, const ScColorScaleEntry* pEntry = nullptr);
+ ~ScIconSetFrmtDataEntry();
+ void Show() { mxGrid->show(); }
+ void Hide() { mxGrid->hide(); }
+ void set_grid_top_attach(int nTop)
+ {
+ mxGrid->set_grid_left_attach(0);
+ mxGrid->set_grid_top_attach(nTop);
+ }
+
+ ScColorScaleEntry* CreateEntry(ScDocument& rDoc, const ScAddress& rPos) const;
+
+ void SetFirstEntry();
+};
+
+ScIconSetFrmtDataEntry::ScIconSetFrmtDataEntry(weld::Container* pParent, ScIconSetType eType, const ScDocument* pDoc, sal_Int32 i, const ScColorScaleEntry* pEntry)
+ : mxBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/conditionaliconset.ui"))
+ , mxGrid(mxBuilder->weld_container("ConditionalIconSet"))
+ , mxImgIcon(mxBuilder->weld_image("icon"))
+ , mxFtEntry(mxBuilder->weld_label("label"))
+ , mxEdEntry(mxBuilder->weld_entry("entry"))
+ , mxLbEntryType(mxBuilder->weld_combo_box("listbox"))
+ , mpContainer(pParent)
+{
+ mxImgIcon->set_from_icon_name(ScIconSetFormat::getIconName(eType, i));
+ if(pEntry)
+ {
+ switch(pEntry->GetType())
+ {
+ case COLORSCALE_VALUE:
+ mxLbEntryType->set_active(0);
+ mxEdEntry->set_text(convertNumberToString(pEntry->GetValue(), pDoc));
+ break;
+ case COLORSCALE_PERCENTILE:
+ mxLbEntryType->set_active(2);
+ mxEdEntry->set_text(convertNumberToString(pEntry->GetValue(), pDoc));
+ break;
+ case COLORSCALE_PERCENT:
+ mxLbEntryType->set_active(1);
+ mxEdEntry->set_text(convertNumberToString(pEntry->GetValue(), pDoc));
+ break;
+ case COLORSCALE_FORMULA:
+ mxLbEntryType->set_active(3);
+ mxEdEntry->set_text(pEntry->GetFormula(formula::FormulaGrammar::GRAM_DEFAULT));
+ break;
+ default:
+ assert(false);
+ }
+ }
+ else
+ {
+ mxLbEntryType->set_active(1);
+ }
+}
+
+ScIconSetFrmtDataEntry::~ScIconSetFrmtDataEntry()
+{
+ mpContainer->move(mxGrid.get(), nullptr);
+}
+
+ScColorScaleEntry* ScIconSetFrmtDataEntry::CreateEntry(ScDocument& rDoc, const ScAddress& rPos) const
+{
+ sal_Int32 nPos = mxLbEntryType->get_active();
+ OUString aText = mxEdEntry->get_text();
+ ScColorScaleEntry* pEntry = new ScColorScaleEntry();
+
+ sal_uInt32 nIndex = 0;
+ double nVal = 0;
+ SvNumberFormatter* pNumberFormatter = rDoc.GetFormatTable();
+ (void)pNumberFormatter->IsNumberFormat(aText, nIndex, nVal);
+ pEntry->SetValue(nVal);
+
+ switch(nPos)
+ {
+ case 0:
+ pEntry->SetType(COLORSCALE_VALUE);
+ break;
+ case 1:
+ pEntry->SetType(COLORSCALE_PERCENT);
+ break;
+ case 2:
+ pEntry->SetType(COLORSCALE_PERCENTILE);
+ break;
+ case 3:
+ pEntry->SetType(COLORSCALE_FORMULA);
+ pEntry->SetFormula(aText, rDoc, rPos, rDoc.GetGrammar());
+ break;
+ default:
+ assert(false);
+ }
+
+ return pEntry;
+}
+
+void ScIconSetFrmtDataEntry::SetFirstEntry()
+{
+ mxEdEntry->hide();
+ mxLbEntryType->hide();
+ mxFtEntry->hide();
+ mxEdEntry->set_text("0");
+ mxLbEntryType->set_active(1);
+}
+
+ScIconSetFrmtEntry::ScIconSetFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScIconSetFormat* pFormat)
+ : ScCondFrmtEntry(pParent, pDoc, rPos)
+ , mxLbColorFormat(mxBuilder->weld_combo_box("colorformat"))
+ , mxLbIconSetType(mxBuilder->weld_combo_box("iconsettype"))
+ , mxIconParent(mxBuilder->weld_container("iconparent"))
+{
+ mxLbColorFormat->set_size_request(CommonWidgetWidth, -1);
+ mxLbIconSetType->set_size_request(CommonWidgetWidth, -1);
+
+ Init();
+ mxLbColorFormat->connect_changed(LINK(pParent, ScCondFormatList, ColFormatTypeHdl));
+
+ if(pFormat)
+ {
+ const ScIconSetFormatData* pIconSetFormatData = pFormat->GetIconSetData();
+ ScIconSetType eType = pIconSetFormatData->eIconSetType;
+ sal_Int32 nType = static_cast<sal_Int32>(eType);
+ mxLbIconSetType->set_active(nType);
+
+ for (size_t i = 0, n = pIconSetFormatData->m_Entries.size();
+ i < n; ++i)
+ {
+ maEntries.emplace_back(new ScIconSetFrmtDataEntry(
+ mxIconParent.get(), eType, pDoc, i, pIconSetFormatData->m_Entries[i].get()));
+ maEntries[i]->set_grid_top_attach(i);
+ }
+ maEntries[0]->SetFirstEntry();
+ }
+ else
+ IconSetTypeHdl(*mxLbIconSetType);
+}
+
+ScIconSetFrmtEntry::~ScIconSetFrmtEntry()
+{
+}
+
+void ScIconSetFrmtEntry::Init()
+{
+ mxLbColorFormat->set_active(3);
+ mxLbType->set_active(0);
+ mxLbIconSetType->set_active(0);
+
+ mxLbIconSetType->connect_changed(LINK(this, ScIconSetFrmtEntry, IconSetTypeHdl));
+}
+
+IMPL_LINK_NOARG( ScIconSetFrmtEntry, IconSetTypeHdl, weld::ComboBox&, void )
+{
+ const ScIconSetMap* pMap = ScIconSetFormat::g_IconSetMap;
+
+ sal_Int32 nPos = mxLbIconSetType->get_active();
+ sal_uInt32 nElements = pMap[nPos].nElements;
+
+ maEntries.clear();
+
+ for(size_t i = 0; i < nElements; ++i)
+ {
+ maEntries.emplace_back(new ScIconSetFrmtDataEntry(mxIconParent.get(), static_cast<ScIconSetType>(nPos), mpDoc, i));
+ maEntries[i]->set_grid_top_attach(i);
+ maEntries[i]->Show();
+ }
+ maEntries[0]->SetFirstEntry();
+}
+
+OUString ScIconSetFrmtEntry::GetExpressionString()
+{
+ return ScCondFormatHelper::GetExpression(ICONSET, 0);
+}
+
+void ScIconSetFrmtEntry::SetActive()
+{
+ mxLbColorFormat->show();
+ mxLbIconSetType->show();
+ for(auto& rxEntry : maEntries)
+ {
+ rxEntry->Show();
+ }
+
+ Select();
+}
+
+void ScIconSetFrmtEntry::SetInactive()
+{
+ mxLbColorFormat->hide();
+ mxLbIconSetType->hide();
+ for(auto& rxEntry : maEntries)
+ {
+ rxEntry->Hide();
+ }
+
+ Deselect();
+}
+
+ScFormatEntry* ScIconSetFrmtEntry::GetEntry() const
+{
+ ScIconSetFormat* pFormat = new ScIconSetFormat(mpDoc);
+
+ ScIconSetFormatData* pData = new ScIconSetFormatData;
+ pData->eIconSetType = static_cast<ScIconSetType>(mxLbIconSetType->get_active());
+ for(const auto& rxEntry : maEntries)
+ {
+ pData->m_Entries.emplace_back(rxEntry->CreateEntry(*mpDoc, maPos));
+ }
+ pFormat->SetIconSetData(pData);
+
+ return pFormat;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/condformat/condformatdlgitem.cxx b/sc/source/ui/condformat/condformatdlgitem.cxx
new file mode 100644
index 000000000..b0bf511c3
--- /dev/null
+++ b/sc/source/ui/condformat/condformatdlgitem.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/.
+ */
+
+
+#include <utility>
+
+#include <scitems.hxx>
+#include <condformatdlgitem.hxx>
+
+ScCondFormatDlgItem::ScCondFormatDlgItem(std::shared_ptr<ScConditionalFormatList> pCondFormats,
+ sal_Int32 nItem, bool bManaged):
+ SfxPoolItem(SCITEM_CONDFORMATDLGDATA),
+ mpCondFormats(std::move(pCondFormats)),
+ mnItem(nItem),
+ meDialogType(condformat::dialog::CONDITION),
+ mbManaged(bManaged)
+{
+}
+
+ScCondFormatDlgItem::~ScCondFormatDlgItem()
+{
+}
+
+bool ScCondFormatDlgItem::operator==(const SfxPoolItem& rItem) const
+{
+ assert(SfxPoolItem::operator==(rItem)); (void)rItem;
+ return false;
+}
+
+ScCondFormatDlgItem* ScCondFormatDlgItem::Clone(SfxItemPool* /*pPool*/) const
+{
+ return new ScCondFormatDlgItem(*this);
+}
+
+bool ScCondFormatDlgItem::IsManaged() const
+{
+ return mbManaged;
+}
+
+condformat::dialog::ScCondFormatDialogType ScCondFormatDlgItem::GetDialogType() const
+{
+ return meDialogType;
+}
+
+sal_Int32 ScCondFormatDlgItem::GetIndex() const
+{
+ return mnItem;
+}
+
+ScConditionalFormatList* ScCondFormatDlgItem::GetConditionalFormatList()
+{
+ return mpCondFormats.get();
+}
+
+void ScCondFormatDlgItem::SetDialogType(condformat::dialog::ScCondFormatDialogType eType)
+{
+ meDialogType = eType;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/condformat/condformathelper.cxx b/sc/source/ui/condformat/condformathelper.cxx
new file mode 100644
index 000000000..00509b7e2
--- /dev/null
+++ b/sc/source/ui/condformat/condformathelper.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/.
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/safeint.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <condformathelper.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <conditio.hxx>
+
+namespace {
+
+OUString getTextForType(ScCondFormatEntryType eType)
+{
+ switch(eType)
+ {
+ case CONDITION:
+ return ScResId(STR_COND_CONDITION);
+ case COLORSCALE:
+ return ScResId(STR_COND_COLORSCALE);
+ case DATABAR:
+ return ScResId(STR_COND_DATABAR);
+ case FORMULA:
+ return ScResId(STR_COND_FORMULA);
+ case ICONSET:
+ return ScResId(STR_COND_ICONSET);
+ case DATE:
+ return ScResId(STR_COND_DATE);
+ default:
+ break;
+ }
+
+ return OUString();
+}
+
+OUString getExpression(sal_Int32 nIndex)
+{
+ switch(nIndex)
+ {
+ case 0:
+ return "=";
+ case 1:
+ return "<";
+ case 2:
+ return ">";
+ case 3:
+ return "<=";
+ case 4:
+ return ">=";
+ case 5:
+ return "!=";
+ case 6:
+ return ScResId(STR_COND_BETWEEN);
+ case 7:
+ return ScResId(STR_COND_NOTBETWEEN);
+ case 8:
+ return ScResId(STR_COND_DUPLICATE);
+ case 9:
+ return ScResId(STR_COND_UNIQUE);
+
+ case 11:
+ return ScResId(STR_COND_TOP10);
+ case 12:
+ return ScResId(STR_COND_BOTTOM10);
+ case 13:
+ return ScResId(STR_COND_TOP_PERCENT);
+ case 14:
+ return ScResId(STR_COND_BOTTOM_PERCENT);
+ case 15:
+ return ScResId(STR_COND_ABOVE_AVERAGE);
+ case 16:
+ return ScResId(STR_COND_BELOW_AVERAGE);
+ case 17:
+ return ScResId(STR_COND_ABOVE_EQUAL_AVERAGE);
+ case 18:
+ return ScResId(STR_COND_BELOW_EQUAL_AVERAGE);
+ case 19:
+ return ScResId(STR_COND_ERROR);
+ case 20:
+ return ScResId(STR_COND_NOERROR);
+ case 21:
+ return ScResId(STR_COND_BEGINS_WITH);
+ case 22:
+ return ScResId(STR_COND_ENDS_WITH);
+ case 23:
+ return ScResId(STR_COND_CONTAINS);
+ case 24:
+ return ScResId(STR_COND_NOT_CONTAINS);
+
+ case 10:
+ assert(false);
+ }
+ return OUString();
+}
+
+OUString getDateString(sal_Int32 nIndex)
+{
+ const TranslateId aCondStrs[] =
+ {
+ STR_COND_TODAY,
+ STR_COND_YESTERDAY,
+ STR_COND_TOMORROW,
+ STR_COND_LAST7DAYS,
+ STR_COND_THISWEEK,
+ STR_COND_LASTWEEK,
+ STR_COND_NEXTWEEK,
+ STR_COND_THISMONTH,
+ STR_COND_LASTMONTH,
+ STR_COND_NEXTMONTH,
+ STR_COND_THISYEAR,
+ STR_COND_LASTYEAR,
+ STR_COND_NEXTYEAR
+ };
+
+ if (nIndex >= 0 && o3tl::make_unsigned(nIndex) < SAL_N_ELEMENTS(aCondStrs))
+ return ScResId(aCondStrs[nIndex]);
+ assert(false);
+ return OUString();
+}
+
+}
+
+OUString ScCondFormatHelper::GetExpression(const ScConditionalFormat& rFormat, const ScAddress& rPos)
+{
+ OUStringBuffer aBuffer;
+ if(!rFormat.IsEmpty())
+ {
+ switch(rFormat.GetEntry(0)->GetType())
+ {
+ case ScFormatEntry::Type::Condition:
+ case ScFormatEntry::Type::ExtCondition:
+ {
+ const ScConditionEntry* pEntry = static_cast<const ScConditionEntry*>(rFormat.GetEntry(0));
+ ScConditionMode eMode = pEntry->GetOperation();
+ if(eMode == ScConditionMode::Direct)
+ {
+ aBuffer.append(getTextForType(FORMULA));
+ aBuffer.append(" ");
+ aBuffer.append(pEntry->GetExpression(rPos, 0));
+ }
+ else
+ {
+ aBuffer.append(getTextForType(CONDITION));
+ aBuffer.append(" ");
+ aBuffer.append(getExpression(static_cast<sal_Int32>(eMode)));
+ aBuffer.append(" ");
+ if(eMode == ScConditionMode::Between || eMode == ScConditionMode::NotBetween)
+ {
+ aBuffer.append(pEntry->GetExpression(rPos, 0));
+ aBuffer.append(" ");
+ aBuffer.append(ScResId(STR_COND_AND));
+ aBuffer.append(" ");
+ aBuffer.append(pEntry->GetExpression(rPos, 1));
+ }
+ else if(eMode <= ScConditionMode::NotEqual || eMode >= ScConditionMode::BeginsWith)
+ {
+ aBuffer.append(pEntry->GetExpression(rPos, 0));
+ }
+ }
+ }
+
+ break;
+ case ScFormatEntry::Type::Databar:
+ aBuffer.append(getTextForType(DATABAR));
+ break;
+ case ScFormatEntry::Type::Colorscale:
+ aBuffer.append(getTextForType(COLORSCALE));
+ break;
+ case ScFormatEntry::Type::Iconset:
+ aBuffer.append(getTextForType(ICONSET));
+ break;
+ case ScFormatEntry::Type::Date:
+ {
+ aBuffer.append(getTextForType(DATE));
+ aBuffer.append(" ");
+ sal_Int32 nDateEntry = static_cast<sal_Int32>(static_cast<const ScCondDateFormatEntry*>(rFormat.GetEntry(0))->GetDateType());
+ aBuffer.append(getDateString(nDateEntry));
+ }
+ break;
+ }
+ }
+ return aBuffer.makeStringAndClear();
+}
+
+OUString ScCondFormatHelper::GetExpression( ScCondFormatEntryType eType, sal_Int32 nIndex,
+ std::u16string_view aStr1, std::u16string_view aStr2 )
+{
+ OUStringBuffer aBuffer(getTextForType(eType));
+ aBuffer.append(" ");
+ if(eType == CONDITION)
+ {
+ // workaround missing FORMULA option in the conditions case
+ // FORMULA is handled later
+ if(nIndex > 9)
+ ++nIndex;
+ aBuffer.append(getExpression(nIndex));
+ if(nIndex <= 7 || nIndex >= 19)
+ {
+ aBuffer.append(OUString::Concat(" ") + aStr1);
+ if(nIndex == 6 || nIndex == 7)
+ {
+ aBuffer.append(" ");
+ aBuffer.append(ScResId(STR_COND_AND));
+ aBuffer.append(" ");
+ aBuffer.append(aStr2);
+ }
+ }
+ }
+ else if(eType == FORMULA)
+ {
+ aBuffer.append(OUString::Concat(" ") + aStr1);
+ }
+ else if(eType == DATE)
+ {
+ aBuffer.append(getDateString(nIndex));
+ }
+
+ return aBuffer.makeStringAndClear();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/condformat/condformatmgr.cxx b/sc/source/ui/condformat/condformatmgr.cxx
new file mode 100644
index 000000000..79f41bf5c
--- /dev/null
+++ b/sc/source/ui/condformat/condformatmgr.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/.
+ */
+
+#include <condformatmgr.hxx>
+#include <condformathelper.hxx>
+#include <condformatdlg.hxx>
+#include <document.hxx>
+#include <conditio.hxx>
+#include <o3tl/safeint.hxx>
+#include <unotools/viewoptions.hxx>
+
+ScCondFormatManagerWindow::ScCondFormatManagerWindow(weld::TreeView& rTreeView,
+ ScDocument& rDoc, ScConditionalFormatList* pFormatList)
+ : mrTreeView(rTreeView)
+ , mrDoc(rDoc)
+ , mpFormatList(pFormatList)
+{
+ mrTreeView.set_size_request(mrTreeView.get_approximate_digit_width() * 70,
+ mrTreeView.get_height_rows(20));
+ setColSizes();
+
+ Init();
+ mrTreeView.set_selection_mode(SelectionMode::Multiple);
+ mrTreeView.make_sorted();
+}
+
+void ScCondFormatManagerWindow::Init()
+{
+ mrTreeView.freeze();
+
+ if (mpFormatList)
+ {
+ int nRow = 0;
+ OUString sRangeStr;
+ for(const auto& rItem : *mpFormatList)
+ {
+ const ScRangeList& aRange = rItem->GetRange();
+ aRange.Format(sRangeStr, ScRefFlags::VALID, mrDoc, mrDoc.GetAddressConvention());
+ mrTreeView.append(OUString::number(rItem->GetKey()), sRangeStr);
+ mrTreeView.set_text(nRow, ScCondFormatHelper::GetExpression(*rItem, aRange.GetTopLeftCorner()), 1);
+ ++nRow;
+ }
+ }
+
+ mrTreeView.thaw();
+
+ if (mpFormatList && !mpFormatList->empty())
+ mrTreeView.select(0);
+}
+
+void ScCondFormatManagerWindow::DeleteSelection()
+{
+ auto aSelectedRows = mrTreeView.get_selected_rows();
+ std::sort(aSelectedRows.begin(), aSelectedRows.end());
+ for (auto it = aSelectedRows.rbegin(); it != aSelectedRows.rend(); ++it)
+ {
+ sal_Int32 nIndex = mrTreeView.get_id(*it).toInt32();
+ mpFormatList->erase(nIndex);
+ mrTreeView.remove(*it);
+ }
+}
+
+ScConditionalFormat* ScCondFormatManagerWindow::GetSelection()
+{
+ int nEntry = mrTreeView.get_selected_index();
+ if (nEntry == -1)
+ return nullptr;
+
+ sal_Int32 nIndex = mrTreeView.get_id(nEntry).toInt32();
+ return mpFormatList->GetFormat(nIndex);
+}
+
+void ScCondFormatManagerWindow::setColSizes()
+{
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(mrTreeView.get_size_request().Width() / 2)
+ };
+ mrTreeView.set_column_fixed_widths(aWidths);
+}
+
+ScCondFormatManagerDlg::ScCondFormatManagerDlg(weld::Window* pParent, ScDocument& rDoc, const ScConditionalFormatList* pFormatList)
+ : GenericDialogController(pParent, "modules/scalc/ui/condformatmanager.ui", "CondFormatManager")
+ , m_bModified(false)
+ , m_xFormatList( pFormatList ? new ScConditionalFormatList(*pFormatList) : nullptr)
+ , m_xBtnAdd(m_xBuilder->weld_button("add"))
+ , m_xBtnRemove(m_xBuilder->weld_button("remove"))
+ , m_xBtnEdit(m_xBuilder->weld_button("edit"))
+ , m_xTreeView(m_xBuilder->weld_tree_view("CONTAINER"))
+ , m_xCtrlManager(new ScCondFormatManagerWindow(*m_xTreeView, rDoc, m_xFormatList.get()))
+{
+ m_xBtnRemove->connect_clicked(LINK(this, ScCondFormatManagerDlg, RemoveBtnHdl));
+ m_xBtnEdit->connect_clicked(LINK(this, ScCondFormatManagerDlg, EditBtnClickHdl));
+ m_xBtnAdd->connect_clicked(LINK(this, ScCondFormatManagerDlg, AddBtnHdl));
+ m_xTreeView->connect_row_activated(LINK(this, ScCondFormatManagerDlg, EditBtnHdl));
+
+ SvtViewOptions aDlgOpt(EViewType::Dialog, "CondFormatDialog");
+ if (aDlgOpt.Exists())
+ m_xDialog->set_window_state(aDlgOpt.GetWindowState().toUtf8());
+
+ UpdateButtonSensitivity();
+}
+
+ScCondFormatManagerDlg::~ScCondFormatManagerDlg()
+{
+ // tdf#101285 - Remember position of dialog
+ SvtViewOptions aDlgOpt(EViewType::Dialog, "CondFormatDialog");
+ OString sWindowState
+ = m_xDialog->get_window_state(WindowStateMask::Pos);
+ aDlgOpt.SetWindowState(OUString::fromUtf8(sWindowState));
+}
+
+std::unique_ptr<ScConditionalFormatList> ScCondFormatManagerDlg::GetConditionalFormatList()
+{
+ return std::move(m_xFormatList);
+}
+
+void ScCondFormatManagerDlg::UpdateButtonSensitivity()
+{
+ bool bNewSensitivity = !m_xFormatList->empty();
+ m_xBtnRemove->set_sensitive(bNewSensitivity);
+ m_xBtnEdit->set_sensitive(bNewSensitivity);
+}
+
+// Get the current conditional format selected.
+//
+ScConditionalFormat* ScCondFormatManagerDlg::GetCondFormatSelected()
+{
+ return m_xCtrlManager->GetSelection();
+}
+
+IMPL_LINK_NOARG(ScCondFormatManagerDlg, RemoveBtnHdl, weld::Button&, void)
+{
+ m_xCtrlManager->DeleteSelection();
+ m_bModified = true;
+ UpdateButtonSensitivity();
+}
+
+IMPL_LINK_NOARG(ScCondFormatManagerDlg, EditBtnClickHdl, weld::Button&, void)
+{
+ EditBtnHdl(*m_xTreeView);
+}
+
+IMPL_LINK_NOARG(ScCondFormatManagerDlg, EditBtnHdl, weld::TreeView&, bool)
+{
+ ScConditionalFormat* pFormat = m_xCtrlManager->GetSelection();
+
+ if (!pFormat)
+ return true;
+
+ m_bModified = true;
+ m_xDialog->response( DLG_RET_EDIT );
+
+ return true;
+}
+
+IMPL_LINK_NOARG(ScCondFormatManagerDlg, AddBtnHdl, weld::Button&, void)
+{
+ m_bModified = true;
+ m_xDialog->response( DLG_RET_ADD );
+}
+
+void ScCondFormatManagerDlg::SetModified()
+{
+ m_bModified = true;
+ UpdateButtonSensitivity();
+}
+
+bool ScCondFormatManagerDlg::CondFormatsChanged() const
+{
+ return m_bModified;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dataprovider/csvdataprovider.cxx b/sc/source/ui/dataprovider/csvdataprovider.cxx
new file mode 100644
index 000000000..29391c378
--- /dev/null
+++ b/sc/source/ui/dataprovider/csvdataprovider.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/.
+ */
+
+#include <dataprovider.hxx>
+#include <datatransformation.hxx>
+#include <datamapper.hxx>
+#include <stringutil.hxx>
+
+#include <tools/stream.hxx>
+#include <vcl/svapp.hxx>
+#include <docsh.hxx>
+#include <orcus/csv_parser.hpp>
+#include <utility>
+
+namespace {
+
+class CSVHandler
+{
+ ScDocument* mpDoc;
+ SCCOL mnCol;
+ SCROW mnRow;
+
+public:
+ CSVHandler(ScDocument* pDoc) :
+ mpDoc(pDoc), mnCol(0), mnRow(0)
+ {
+ }
+
+ static void begin_parse() {}
+ static void end_parse() {}
+ static void begin_row() {}
+ void end_row()
+ {
+ ++mnRow;
+ mnCol = 0;
+ }
+
+ void cell(const char* p, size_t n, bool /*transient*/)
+ {
+ if (mnCol > mpDoc->MaxCol())
+ return;
+
+ double mfValue = 0.0;
+ if (ScStringUtil::parseSimpleNumber(p, n, '.', ',', mfValue))
+ {
+ mpDoc->SetValue(mnCol, mnRow, 0, mfValue);
+ }
+ else
+ {
+ OString aStr(p, n);
+ mpDoc->SetString(mnCol, mnRow, 0, OStringToOUString(aStr, RTL_TEXTENCODING_UTF8));
+ }
+
+ ++mnCol;
+ }
+};
+
+}
+
+namespace sc {
+CSVFetchThread::CSVFetchThread(
+ ScDocument& rDoc, const OUString& mrURL, std::function<void()> aImportFinishedHdl,
+ std::vector<std::shared_ptr<sc::DataTransformation>>&& rDataTransformations)
+ : Thread("CSV Fetch Thread")
+ , mrDocument(rDoc)
+ , maURL(mrURL)
+ , mbTerminate(false)
+ , maDataTransformations(std::move(rDataTransformations))
+ , maImportFinishedHdl(std::move(aImportFinishedHdl))
+{
+ maConfig.delimiters.push_back(',');
+ maConfig.text_qualifier = '"';
+}
+
+CSVFetchThread::~CSVFetchThread()
+{
+}
+
+bool CSVFetchThread::IsRequestedTerminate()
+{
+ osl::MutexGuard aGuard(maMtxTerminate);
+ return mbTerminate;
+}
+
+void CSVFetchThread::RequestTerminate()
+{
+ osl::MutexGuard aGuard(maMtxTerminate);
+ mbTerminate = true;
+}
+
+void CSVFetchThread::EndThread()
+{
+ RequestTerminate();
+}
+
+void CSVFetchThread::execute()
+{
+ OStringBuffer aBuffer(64000);
+ DataProvider::FetchStreamFromURL(maURL, aBuffer);
+ if (mbTerminate)
+ return;
+
+ CSVHandler aHdl(&mrDocument);
+ orcus::csv_parser<CSVHandler> parser(aBuffer.getStr(), aBuffer.getLength(), aHdl, maConfig);
+ parser.parse();
+
+ for (const auto& itr : maDataTransformations)
+ {
+ itr->Transform(mrDocument);
+ }
+
+ SolarMutexGuard aGuard;
+ maImportFinishedHdl();
+}
+
+CSVDataProvider::CSVDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource):
+ DataProvider(rDataSource),
+ mpDocument(pDoc)
+{
+}
+
+CSVDataProvider::~CSVDataProvider()
+{
+ if (mxCSVFetchThread.is())
+ {
+ SolarMutexReleaser aReleaser;
+ mxCSVFetchThread->join();
+ }
+}
+
+void CSVDataProvider::Import()
+{
+ // already importing data
+ if (mpDoc)
+ return;
+
+ mpDoc.reset(new ScDocument(SCDOCMODE_CLIP));
+ mpDoc->ResetClip(mpDocument, SCTAB(0));
+ mxCSVFetchThread = new CSVFetchThread(*mpDoc, mrDataSource.getURL(), std::bind(&CSVDataProvider::ImportFinished, this), std::vector(mrDataSource.getDataTransformation()));
+ mxCSVFetchThread->launch();
+
+ if (mbDeterministic)
+ {
+ SolarMutexReleaser aReleaser;
+ mxCSVFetchThread->join();
+ }
+}
+
+void CSVDataProvider::ImportFinished()
+{
+ mrDataSource.getDBManager()->WriteToDoc(*mpDoc);
+ mpDoc.reset();
+ Refresh();
+}
+
+void CSVDataProvider::Refresh()
+{
+ ScDocShell* pDocShell = static_cast<ScDocShell*>(mpDocument->GetDocumentShell());
+ if (pDocShell)
+ pDocShell->SetDocumentModified();
+}
+
+const OUString& CSVDataProvider::GetURL() const
+{
+ return mrDataSource.getURL();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dataprovider/dataprovider.cxx b/sc/source/ui/dataprovider/dataprovider.cxx
new file mode 100644
index 000000000..72f674a7b
--- /dev/null
+++ b/sc/source/ui/dataprovider/dataprovider.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/.
+ */
+
+#include <dataprovider.hxx>
+#include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <o3tl/string_view.hxx>
+#include <rtl/strbuf.hxx>
+#include <sal/log.hxx>
+#include <unotools/charclass.hxx>
+#include <tools/stream.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include "htmldataprovider.hxx"
+#include "xmldataprovider.hxx"
+#include "sqldataprovider.hxx"
+#include <datamapper.hxx>
+#include <dbdata.hxx>
+#include <docsh.hxx>
+
+using namespace com::sun::star;
+
+namespace sc {
+
+std::unique_ptr<SvStream> DataProvider::FetchStreamFromURL(const OUString& rURL, OStringBuffer& rBuffer)
+{
+ try
+ {
+ uno::Reference< ucb::XSimpleFileAccess3 > xFileAccess = ucb::SimpleFileAccess::create( comphelper::getProcessComponentContext() );
+
+ uno::Reference< io::XInputStream > xStream = xFileAccess->openFileRead( rURL );
+
+ const sal_Int32 BUF_LEN = 8000;
+ uno::Sequence< sal_Int8 > buffer( BUF_LEN );
+
+ sal_Int32 nRead = 0;
+ while ( ( nRead = xStream->readBytes( buffer, BUF_LEN ) ) == BUF_LEN )
+ {
+ rBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead );
+ }
+
+ if ( nRead > 0 )
+ {
+ rBuffer.append( reinterpret_cast< const char* >( buffer.getConstArray() ), nRead );
+ }
+
+ xStream->closeInput();
+
+ SvStream* pStream = new SvMemoryStream(const_cast<char*>(rBuffer.getStr()), rBuffer.getLength(), StreamMode::READ);
+ return std::unique_ptr<SvStream>(pStream);
+ }
+ catch(...)
+ {
+ rBuffer.setLength(0);
+ return nullptr;
+ }
+}
+
+ExternalDataSource::ExternalDataSource(const OUString& rURL,
+ const OUString& rProvider, ScDocument* pDoc)
+ : maURL(rURL)
+ , maProvider(rProvider)
+ , mpDoc(pDoc)
+{
+}
+
+void ExternalDataSource::setID(const OUString& rID)
+{
+ maID = rID;
+}
+
+void ExternalDataSource::setXMLImportParam(const ScOrcusImportXMLParam& rParam)
+{
+ maParam = rParam;
+}
+
+
+
+void ExternalDataSource::setURL(const OUString& rURL)
+{
+ maURL = rURL;
+}
+
+void ExternalDataSource::setProvider(const OUString& rProvider)
+{
+ maProvider = rProvider;
+ mpDataProvider.reset();
+}
+
+const OUString& ExternalDataSource::getURL() const
+{
+ return maURL;
+}
+
+const OUString& ExternalDataSource::getProvider() const
+{
+ return maProvider;
+}
+
+const OUString& ExternalDataSource::getID() const
+{
+ return maID;
+}
+
+const ScOrcusImportXMLParam& ExternalDataSource::getXMLImportParam() const
+{
+ return maParam;
+}
+
+OUString ExternalDataSource::getDBName() const
+{
+ if (mpDBDataManager)
+ {
+ ScDBData* pDBData = mpDBDataManager->getDBData();
+ if (pDBData)
+ return pDBData->GetName();
+ }
+ return OUString();
+}
+
+void ExternalDataSource::setDBData(const OUString& rDBName)
+{
+ if (!mpDBDataManager)
+ {
+ mpDBDataManager = std::make_shared<ScDBDataManager>(rDBName, mpDoc);
+ }
+ else
+ {
+ mpDBDataManager->SetDatabase(rDBName);
+ }
+}
+
+double ExternalDataSource::getUpdateFrequency()
+{
+ return 0;
+}
+
+ScDBDataManager* ExternalDataSource::getDBManager()
+{
+ return mpDBDataManager.get();
+}
+
+void ExternalDataSource::refresh(ScDocument* pDoc, bool bDeterministic)
+{
+ // no DB data available
+ if (!mpDBDataManager)
+ return;
+
+ // if no data provider exists, try to create one
+ if (!mpDataProvider)
+ mpDataProvider = DataProviderFactory::getDataProvider(pDoc, *this);
+
+ // if we still have not been able to create one, we can not refresh the data
+ if (!mpDataProvider)
+ return;
+
+ if (bDeterministic)
+ mpDataProvider->setDeterministic();
+
+ mpDataProvider->Import();
+}
+
+void ExternalDataSource::AddDataTransformation(
+ const std::shared_ptr<sc::DataTransformation>& mpDataTransformation)
+{
+ maDataTransformations.push_back(mpDataTransformation);
+}
+
+const std::vector<std::shared_ptr<sc::DataTransformation>>& ExternalDataSource::getDataTransformation() const
+{
+ return maDataTransformations;
+}
+
+ExternalDataMapper::ExternalDataMapper(ScDocument& /*rDoc*/)
+ //mrDoc(rDoc)
+{
+}
+
+ExternalDataMapper::~ExternalDataMapper()
+{
+}
+
+void ExternalDataMapper::insertDataSource(const sc::ExternalDataSource& rSource)
+{
+ maDataSources.push_back(rSource);
+}
+
+const std::vector<sc::ExternalDataSource>& ExternalDataMapper::getDataSources() const
+{
+ return maDataSources;
+}
+
+std::vector<sc::ExternalDataSource>& ExternalDataMapper::getDataSources()
+{
+ return maDataSources;
+}
+
+DataProvider::DataProvider(sc::ExternalDataSource& rDataSource):
+ mbDeterministic(false),
+ mrDataSource(rDataSource)
+{
+}
+
+void DataProvider::setDeterministic()
+{
+ mbDeterministic = true;
+}
+
+DataProvider::~DataProvider()
+{
+}
+
+void ScDBDataManager::WriteToDoc(ScDocument& rDoc)
+{
+ // first apply all data transformations
+
+ bool bShrunk = false;
+ SCCOL nStartCol = 0;
+ SCROW nStartRow = 0;
+ SCCOL nEndCol = rDoc.MaxCol();
+ SCROW nEndRow = rDoc.MaxRow();
+ rDoc.ShrinkToUsedDataArea(bShrunk, 0, nStartCol, nStartRow, nEndCol, nEndRow, false, true, true);
+ ScRange aClipRange(nStartCol, nStartRow, 0, nEndCol, nEndRow, 0);
+ rDoc.SetClipArea(aClipRange);
+
+ ScRange aDestRange;
+ getDBData()->GetArea(aDestRange);
+ SCCOL nColSize = std::min<SCCOL>(aDestRange.aEnd.Col() - aDestRange.aStart.Col(), nEndCol);
+ aDestRange.aEnd.SetCol(aDestRange.aStart.Col() + nColSize);
+
+ SCROW nRowSize = std::min<SCROW>(aDestRange.aEnd.Row() - aDestRange.aStart.Row(), nEndRow);
+ aDestRange.aEnd.SetRow(aDestRange.aStart.Row() + nRowSize);
+
+ ScMarkData aMark(mpDoc->GetSheetLimits());
+ aMark.SelectTable(0, true);
+ mpDoc->CopyFromClip(aDestRange, aMark, InsertDeleteFlags::CONTENTS, nullptr, &rDoc);
+ ScDocShell* pDocShell = static_cast<ScDocShell*>(mpDoc->GetDocumentShell());
+ if (pDocShell)
+ pDocShell->PostPaint(aDestRange, PaintPartFlags::All);
+}
+
+ScDBDataManager::ScDBDataManager(const OUString& rDBName, ScDocument* pDoc):
+ maDBName(rDBName),
+ mpDoc(pDoc)
+{
+}
+
+ScDBDataManager::~ScDBDataManager()
+{
+}
+
+void ScDBDataManager::SetDatabase(const OUString& rDBName)
+{
+ maDBName = rDBName;
+}
+
+ScDBData* ScDBDataManager::getDBData()
+{
+ ScDBData* pDBData = mpDoc->GetDBCollection()->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(maDBName));
+ return pDBData;
+}
+
+bool DataProviderFactory::isInternalDataProvider(std::u16string_view rProvider)
+{
+ return o3tl::starts_with(rProvider, u"org.libreoffice.calc");
+}
+
+std::shared_ptr<DataProvider> DataProviderFactory::getDataProvider(ScDocument* pDoc,
+ sc::ExternalDataSource& rDataSource)
+{
+ const OUString& rDataProvider = rDataSource.getProvider();
+ bool bInternal = DataProviderFactory::isInternalDataProvider(rDataProvider);
+ if (bInternal)
+ {
+ if (rDataProvider == "org.libreoffice.calc.csv")
+ return std::make_shared<CSVDataProvider>(pDoc, rDataSource);
+ else if (rDataProvider == "org.libreoffice.calc.html")
+ return std::make_shared<HTMLDataProvider>(pDoc, rDataSource);
+ else if (rDataProvider == "org.libreoffice.calc.xml")
+ return std::make_shared<XMLDataProvider>(pDoc, rDataSource);
+ else if (rDataProvider == "org.libreoffice.calc.sql")
+ return std::make_shared<SQLDataProvider>(pDoc, rDataSource);
+ }
+ else
+ {
+ SAL_WARN("sc", "no external data provider supported yet");
+ return std::shared_ptr<DataProvider>();
+ }
+
+ return std::shared_ptr<DataProvider>();
+}
+
+std::vector<OUString> DataProviderFactory::getDataProviders()
+{
+ std::vector<OUString> aDataProviders;
+ aDataProviders.emplace_back("org.libreoffice.calc.csv");
+ aDataProviders.emplace_back("org.libreoffice.calc.html");
+ aDataProviders.emplace_back("org.libreoffice.calc.xml");
+ aDataProviders.emplace_back("org.libreoffice.calc.sql");
+
+ return aDataProviders;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dataprovider/datatransformation.cxx b/sc/source/ui/dataprovider/datatransformation.cxx
new file mode 100644
index 000000000..62c82adb9
--- /dev/null
+++ b/sc/source/ui/dataprovider/datatransformation.cxx
@@ -0,0 +1,1275 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <datatransformation.hxx>
+#include <limits>
+#include <document.hxx>
+#include <rtl/math.hxx>
+#include <cmath>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <unotools/charclass.hxx>
+
+namespace {
+
+Date getDate(double nDateTime, const SvNumberFormatter* pFormatter)
+{
+ Date aDate = pFormatter->GetNullDate();
+ aDate.AddDays(static_cast<sal_Int32>(::rtl::math::approxFloor(nDateTime)));
+ return aDate;
+}
+}
+
+namespace sc {
+DataTransformation::~DataTransformation()
+{
+}
+
+SCROW DataTransformation::getLastRow(const ScDocument& rDoc, SCCOL nCol)
+{
+ SCROW nEndRow = rDoc.MaxRow();
+
+ return rDoc.GetLastDataRow(0, nCol, nCol, nEndRow);
+}
+
+ColumnRemoveTransformation::ColumnRemoveTransformation(std::set<SCCOL>&& rColumns):
+ maColumns(std::move(rColumns))
+{
+}
+
+ColumnRemoveTransformation::~ColumnRemoveTransformation()
+{
+}
+
+void ColumnRemoveTransformation::Transform(ScDocument& rDoc) const
+{
+ sal_Int32 nIncrementIndex = 0;
+ for (auto& rCol : maColumns)
+ {
+ rDoc.DeleteCol(0, 0, rDoc.MaxRow(), 0, rCol - nIncrementIndex, 1);
+ nIncrementIndex++;
+ }
+}
+
+TransformationType ColumnRemoveTransformation::getTransformationType() const
+{
+ return TransformationType::DELETE_TRANSFORMATION;
+}
+
+const std::set<SCCOL> & ColumnRemoveTransformation::getColumns() const
+{
+ return maColumns;
+}
+
+SplitColumnTransformation::SplitColumnTransformation(SCCOL nCol, sal_Unicode cSeparator):
+ mnCol(nCol),
+ mcSeparator(cSeparator)
+{
+}
+
+void SplitColumnTransformation::Transform(ScDocument& rDoc) const
+{
+ if (mnCol == -1)
+ return;
+
+ rDoc.InsertCol(0, 0, rDoc.MaxRow(), 0, mnCol + 1, 1);
+
+ SCROW nEndRow = getLastRow(rDoc, mnCol);
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(mnCol, nRow, 0);
+ if (eType == CELLTYPE_STRING)
+ {
+ OUString aStr = rDoc.GetString(mnCol, nRow, 0);
+ sal_Int32 nIndex = aStr.indexOf(mcSeparator);
+ if (nIndex != -1)
+ {
+ rDoc.SetString(mnCol + 1, nRow, 0, aStr.copy(nIndex + 1));
+ rDoc.SetString(mnCol, nRow, 0, aStr.copy(0, nIndex));
+ }
+ }
+ }
+}
+
+TransformationType SplitColumnTransformation::getTransformationType() const
+{
+ return TransformationType::SPLIT_TRANSFORMATION;
+}
+
+SCCOL SplitColumnTransformation::getColumn() const
+{
+ return mnCol;
+}
+
+sal_Unicode SplitColumnTransformation::getSeparator() const
+{
+ return mcSeparator;
+}
+
+MergeColumnTransformation::MergeColumnTransformation( std::set<SCCOL>&& rColumns, const OUString& rMergeString):
+ maColumns(std::move(rColumns)),
+ maMergeString(rMergeString)
+{
+}
+
+void MergeColumnTransformation::Transform(ScDocument& rDoc) const
+{
+ if (maColumns.empty())
+ return;
+
+ SCROW nMaxRow = 0;
+ for (auto& itr : maColumns)
+ {
+ nMaxRow = getLastRow(rDoc, itr);
+ }
+ assert(nMaxRow != -1);
+
+ SCCOL nTargetCol = *maColumns.begin();
+
+
+ for (SCROW nRow = 0; nRow <= nMaxRow; ++nRow)
+ {
+ OUStringBuffer aStr(rDoc.GetString(nTargetCol, nRow, 0));
+ for (auto& itr : maColumns)
+ {
+ if (itr != nTargetCol)
+ {
+ aStr.append(maMergeString + rDoc.GetString(itr, nRow, 0));
+ }
+ }
+ rDoc.SetString(nTargetCol, nRow, 0, aStr.makeStringAndClear());
+ }
+
+ for (auto& itr : maColumns)
+ {
+ if (itr == nTargetCol)
+ continue;
+
+ rDoc.DeleteCol(0, 0, rDoc.MaxRow(), 0, itr, 1);
+ }
+}
+
+TransformationType MergeColumnTransformation::getTransformationType() const
+{
+ return TransformationType::MERGE_TRANSFORMATION;
+}
+
+const OUString & MergeColumnTransformation::getMergeString() const
+{
+ return maMergeString;
+}
+
+const std::set<SCCOL> & MergeColumnTransformation::getColumns() const
+{
+ return maColumns;
+}
+
+SortTransformation::SortTransformation(const ScSortParam& rSortParam):
+ maSortParam(rSortParam)
+{
+}
+
+void SortTransformation::Transform(ScDocument& rDoc) const
+{
+ rDoc.Sort(0, maSortParam, false, false, nullptr, nullptr);
+}
+
+TransformationType SortTransformation::getTransformationType() const
+{
+ return TransformationType::SORT_TRANSFORMATION;
+}
+
+const ScSortParam & SortTransformation::getSortParam() const
+{
+ return maSortParam;
+}
+
+TextTransformation::TextTransformation( std::set<SCCOL>&& nCol, const TEXT_TRANSFORM_TYPE rType):
+ mnCol(std::move(nCol)),
+ maType(rType)
+{
+}
+
+void TextTransformation::Transform(ScDocument& rDoc) const
+{
+ SCROW nEndRow = 0;
+ for(auto& rCol : mnCol)
+ {
+ nEndRow = getLastRow(rDoc, rCol);
+ }
+ assert(nEndRow != -1);
+
+ for(auto& rCol : mnCol)
+ {
+ switch (maType)
+ {
+ case TEXT_TRANSFORM_TYPE::TO_LOWER:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_STRING)
+ {
+ OUString aStr = rDoc.GetString(rCol, nRow, 0);
+ rDoc.SetString(rCol, nRow, 0, ScGlobal::getCharClass().lowercase(aStr));
+ }
+ }
+ }
+ break;
+ case TEXT_TRANSFORM_TYPE::TO_UPPER:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_STRING)
+ {
+ OUString aStr = rDoc.GetString(rCol, nRow, 0);
+ rDoc.SetString(rCol, nRow, 0, ScGlobal::getCharClass().uppercase(aStr));
+ }
+ }
+ }
+ break;
+ case TEXT_TRANSFORM_TYPE::CAPITALIZE:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_STRING)
+ {
+ OUString aStr = rDoc.GetString(rCol, nRow, 0);
+
+ sal_Int32 length = aStr.getLength();
+
+ if(length != 0)
+ aStr = aStr.replaceAt(0, 1, ScGlobal::getCharClass().uppercase(OUString(aStr[0])));
+
+ for (sal_Int32 i = 1; i < length; i++){
+ if (aStr[i-1] == sal_Unicode(U' '))
+ {
+ aStr = aStr.replaceAt(i, 1, ScGlobal::getCharClass().uppercase(OUString(aStr[i])));
+ }
+ else
+ {
+ aStr = aStr.replaceAt(i, 1, ScGlobal::getCharClass().lowercase(OUString(aStr[i])));
+ }
+ }
+ rDoc.SetString(rCol, nRow, 0, aStr);
+ }
+ }
+ }
+ break;
+ case TEXT_TRANSFORM_TYPE::TRIM:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_STRING)
+ {
+ OUString aStr = rDoc.GetString(rCol, nRow, 0);
+ rDoc.SetString(rCol, nRow, 0, aStr.trim());
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+TransformationType TextTransformation::getTransformationType() const
+{
+ return TransformationType::TEXT_TRANSFORMATION;
+}
+
+TEXT_TRANSFORM_TYPE TextTransformation::getTextTransformationType() const
+{
+ return maType;
+}
+
+const std::set<SCCOL>& TextTransformation::getColumns() const
+{
+ return mnCol;
+}
+
+AggregateFunction::AggregateFunction(std::set<SCCOL>&& rColumns, const AGGREGATE_FUNCTION rType):
+ maColumns(std::move(rColumns)),
+ maType(rType)
+{
+}
+
+void AggregateFunction::Transform(ScDocument& rDoc) const
+{
+ SCROW nEndRow = 0;
+ for (auto& itr : maColumns)
+ {
+ nEndRow = getLastRow(rDoc, itr);
+ }
+ assert(nEndRow != -1);
+
+ for (auto& rCol : maColumns)
+ {
+ switch (maType)
+ {
+ case AGGREGATE_FUNCTION::SUM:
+ {
+ double nSum = 0;
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ nSum += nVal;
+ }
+ }
+ rDoc.SetValue(rCol, nEndRow + 1, 0, nSum);
+ }
+ break;
+ case AGGREGATE_FUNCTION::AVERAGE:
+ {
+ double nSum = 0;
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ nSum += nVal;
+ }
+ }
+
+ double nAvg = nSum / (nEndRow + 1);
+ rDoc.SetValue(rCol, nEndRow + 1, 0, nAvg);
+ }
+ break;
+ case AGGREGATE_FUNCTION::MIN:
+ {
+ double nMin = std::numeric_limits<double>::max();
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ if(nVal < nMin)
+ nMin = nVal;
+ }
+ }
+ rDoc.SetValue(rCol, nEndRow + 1, 0, nMin);
+ }
+ break;
+ case AGGREGATE_FUNCTION::MAX:
+ {
+ double nMax = std::numeric_limits<double>::lowest();
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ if(nMax < nVal)
+ nMax = nVal;
+ }
+ }
+ rDoc.SetValue(rCol, nEndRow + 1, 0, nMax);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+TransformationType AggregateFunction::getTransformationType() const
+{
+ return TransformationType::AGGREGATE_FUNCTION;
+}
+
+AGGREGATE_FUNCTION AggregateFunction::getAggregateType() const
+{
+ return maType;
+}
+
+const std::set<SCCOL>& AggregateFunction::getColumns() const
+{
+ return maColumns;
+}
+
+NumberTransformation::NumberTransformation(std::set<SCCOL>&& nCol,
+ const NUMBER_TRANSFORM_TYPE rType)
+ : mnCol(std::move(nCol))
+ , maType(rType)
+ , maPrecision(-1)
+{
+}
+
+NumberTransformation::NumberTransformation(std::set<SCCOL>&& nCol,
+ const NUMBER_TRANSFORM_TYPE rType, int nPrecision)
+ : mnCol(std::move(nCol))
+ , maType(rType)
+ , maPrecision(nPrecision)
+{
+}
+
+void NumberTransformation::Transform(ScDocument& rDoc) const
+{
+ SCROW nEndRow = 0;
+ for(auto& rCol : mnCol)
+ {
+ nEndRow = getLastRow(rDoc, rCol);
+ }
+ assert(nEndRow != -1);
+
+ for(auto& rCol : mnCol)
+ {
+ switch (maType)
+ {
+ case NUMBER_TRANSFORM_TYPE::ROUND:
+ {
+ if(maPrecision > -1)
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ rDoc.SetValue(rCol, nRow, 0, rtl::math::round(nVal, maPrecision));
+ }
+ }
+ }
+ }
+ break;
+ case NUMBER_TRANSFORM_TYPE::ROUND_UP:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ rDoc.SetValue(rCol, nRow, 0, rtl::math::approxCeil(nVal));
+ }
+ }
+ }
+ break;
+ case NUMBER_TRANSFORM_TYPE::ROUND_DOWN:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ rDoc.SetValue(rCol, nRow, 0, rtl::math::approxFloor(nVal));
+ }
+ }
+ }
+ break;
+ case NUMBER_TRANSFORM_TYPE::ABSOLUTE:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ if(std::signbit(nVal))
+ rDoc.SetValue(rCol, nRow, 0, -1 * nVal);
+ }
+ }
+ }
+ break;
+ case NUMBER_TRANSFORM_TYPE::LOG_E:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ if (nVal > 0)
+ {
+ rDoc.SetValue(rCol, nRow, 0, rtl::math::log1p(nVal-1));
+ }
+ else
+ {
+ rDoc.SetString(rCol, nRow, 0, OUString());
+ }
+ }
+ }
+ }
+ break;
+ case NUMBER_TRANSFORM_TYPE::LOG_10:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ if (nVal > 0)
+ {
+ rDoc.SetValue(rCol, nRow, 0, log10(nVal));
+ }
+ else
+ {
+ rDoc.SetString(rCol, nRow, 0, OUString());
+ }
+ }
+ }
+ }
+ break;
+ case NUMBER_TRANSFORM_TYPE::CUBE:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ rDoc.SetValue(rCol, nRow, 0, nVal * nVal * nVal);
+ }
+ }
+ }
+ break;
+ case NUMBER_TRANSFORM_TYPE::SQUARE:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ rDoc.SetValue(rCol, nRow, 0, nVal * nVal);
+ }
+ }
+ }
+ break;
+ case NUMBER_TRANSFORM_TYPE::SQUARE_ROOT:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ if (!std::signbit(nVal))
+ {
+ rDoc.SetValue(rCol, nRow, 0, sqrt(nVal));
+ }
+ else
+ {
+ rDoc.SetString(rCol, nRow, 0, OUString());
+ }
+ }
+ }
+ }
+ break;
+ case NUMBER_TRANSFORM_TYPE::IS_EVEN:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ if (fmod(nVal, 1) == 0 && fmod(nVal, 2) == 0)
+ rDoc.SetValue(rCol, nRow, 0, 1);
+ else
+ rDoc.SetValue(rCol, nRow, 0, 0);
+ }
+ }
+ }
+ break;
+ case NUMBER_TRANSFORM_TYPE::IS_ODD:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ if (fmod(nVal, 1) == 0 && fmod(nVal, 2) != 0)
+ rDoc.SetValue(rCol, nRow, 0, 1);
+ else
+ rDoc.SetValue(rCol, nRow, 0, 0);
+ }
+ }
+ }
+ break;
+ case NUMBER_TRANSFORM_TYPE::SIGN:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ if (nVal > 0)
+ rDoc.SetValue(rCol, nRow, 0, 1);
+ else if (nVal < 0)
+ rDoc.SetValue(rCol, nRow, 0, -1);
+ else
+ rDoc.SetValue(rCol, nRow, 0, 0);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+TransformationType NumberTransformation::getTransformationType() const
+{
+ return TransformationType::NUMBER_TRANSFORMATION;
+}
+
+NUMBER_TRANSFORM_TYPE NumberTransformation::getNumberTransformationType() const
+{
+ return maType;
+}
+
+int NumberTransformation::getPrecision() const
+{
+ return maPrecision;
+}
+
+const std::set<SCCOL>& NumberTransformation::getColumn() const
+{
+ return mnCol;
+}
+
+ReplaceNullTransformation::ReplaceNullTransformation(std::set<SCCOL>&& nCol,
+ const OUString& sReplaceWith)
+ : mnCol(std::move(nCol))
+ , msReplaceWith(sReplaceWith)
+{
+}
+
+void ReplaceNullTransformation::Transform(ScDocument& rDoc) const
+{
+ if (mnCol.empty())
+ return;
+
+ for(auto& rCol : mnCol)
+ {
+ SCROW nEndRow = getLastRow(rDoc, rCol);
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_NONE)
+ {
+ // OUString aStr = rDoc.GetString(rCol, nRow, 0);
+ // if (aStr == "" || aStr.isEmpty())
+ rDoc.SetString(rCol, nRow, 0, msReplaceWith);
+ }
+ }
+ }
+
+}
+
+const std::set<SCCOL>& ReplaceNullTransformation::getColumn() const
+{
+ return mnCol;
+}
+
+const OUString& ReplaceNullTransformation::getReplaceString() const
+{
+ return msReplaceWith;
+}
+
+TransformationType ReplaceNullTransformation::getTransformationType() const
+{
+ return TransformationType::REMOVE_NULL_TRANSFORMATION;
+}
+
+DateTimeTransformation::DateTimeTransformation(std::set<SCCOL>&& nCol,
+ const DATETIME_TRANSFORMATION_TYPE rType)
+ : mnCol(std::move(nCol))
+ , maType(rType)
+{
+}
+
+void DateTimeTransformation::Transform(ScDocument& rDoc) const
+{
+ SCROW nEndRow = 0;
+ for(auto& rCol : mnCol)
+ {
+ nEndRow = getLastRow(rDoc, rCol);
+ }
+ assert(nEndRow != -1);
+
+ for(auto& rCol : mnCol)
+ {
+ switch (maType)
+ {
+ case DATETIME_TRANSFORMATION_TYPE::DATE_STRING:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ LanguageType eLanguage = ScGlobal::eLnge;
+ sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage );
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ ScAddress aAddress(rCol, nRow, 0);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::YEAR:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+ rDoc.SetValue(rCol, nRow, 0, aDate.GetYear());
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::START_OF_YEAR:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ LanguageType eLanguage = ScGlobal::eLnge;
+ sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage );
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+ aDate.SetDay(1);
+ aDate.SetMonth(1);
+ nVal = aDate - pFormatter->GetNullDate();
+ ScAddress aAddress(rCol, nRow, 0);
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::END_OF_YEAR:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ LanguageType eLanguage = ScGlobal::eLnge;
+ sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage );
+
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+ aDate.SetMonth(12);
+ aDate.SetDay(31);
+ nVal = aDate - pFormatter->GetNullDate();
+ ScAddress aAddress(rCol, nRow, 0);
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::MONTH:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+ rDoc.SetValue(rCol, nRow, 0, aDate.GetMonth());
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::MONTH_NAME:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ LanguageType eLanguage = ScGlobal::eLnge;
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ const Color* pColor = nullptr;
+ OUString aResult;
+ pFormatter->GetPreviewStringGuess("MMMM", nVal, aResult, &pColor, eLanguage);
+ rDoc.SetString(rCol, nRow, 0, aResult);
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::START_OF_MONTH:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ LanguageType eLanguage = ScGlobal::eLnge;
+ sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage );
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ ScAddress aAddress(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+ aDate.SetDay(1);
+ nVal = aDate - pFormatter->GetNullDate();
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::END_OF_MONTH:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ LanguageType eLanguage = ScGlobal::eLnge;
+ sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage );
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ ScAddress aAddress(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+ aDate.SetDay(aDate.GetDaysInMonth());
+ nVal = aDate - pFormatter->GetNullDate();
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::DAY:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+ rDoc.SetValue(rCol, nRow, 0, aDate.GetDay());
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::DAY_OF_WEEK:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+ rDoc.SetValue(rCol, nRow, 0, aDate.GetDayOfWeek());
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::DAY_OF_YEAR:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+ rDoc.SetValue(rCol, nRow, 0, aDate.GetDayOfYear());
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::QUARTER:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+
+ int nMonth = aDate.GetMonth();
+
+ if(nMonth >= 1 && nMonth <=3)
+ rDoc.SetValue(rCol, nRow, 0, 1);
+
+ else if(nMonth >= 4 && nMonth <=6)
+ rDoc.SetValue(rCol, nRow, 0, 2);
+
+ else if(nMonth >= 7 && nMonth <=9)
+ rDoc.SetValue(rCol, nRow, 0, 3);
+
+ else if(nMonth >= 10 && nMonth <=12)
+ rDoc.SetValue(rCol, nRow, 0, 4);
+ else
+ rDoc.SetValue(rCol, nRow, 0, -1);
+
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::START_OF_QUARTER:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ LanguageType eLanguage = ScGlobal::eLnge;
+ sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage );
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ ScAddress aAddress(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+
+ int nMonth = aDate.GetMonth();
+
+ if(nMonth >= 1 && nMonth <=3)
+ {
+ aDate.SetDay(1);
+ aDate.SetMonth(1);
+ nVal = aDate - pFormatter->GetNullDate();
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+ else if(nMonth >= 4 && nMonth <=6)
+ {
+ aDate.SetDay(1);
+ aDate.SetMonth(4);
+ nVal = aDate - pFormatter->GetNullDate();
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+ else if(nMonth >= 7 && nMonth <=9)
+ {
+ aDate.SetDay(1);
+ aDate.SetMonth(7);
+ nVal = aDate - pFormatter->GetNullDate();
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+ else if(nMonth >= 10 && nMonth <=12)
+ {
+ aDate.SetDay(1);
+ aDate.SetMonth(10);
+ nVal = aDate - pFormatter->GetNullDate();
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+ else
+ rDoc.SetValue(rCol, nRow, 0, -1);
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::END_OF_QUARTER:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ LanguageType eLanguage = ScGlobal::eLnge;
+ sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::DATE, eLanguage );
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ ScAddress aAddress(rCol, nRow, 0);
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ Date aDate = getDate(nVal, pFormatter);
+ int nMonth = aDate.GetMonth();
+
+ if(nMonth >= 1 && nMonth <=3)
+ {
+ aDate.SetDay(31);
+ aDate.SetMonth(3);
+ nVal = aDate - pFormatter->GetNullDate();
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+
+ else if(nMonth >= 4 && nMonth <=6)
+ {
+ aDate.SetDay(30);
+ aDate.SetMonth(6);
+ nVal = aDate - pFormatter->GetNullDate();
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+
+ else if(nMonth >= 7 && nMonth <=9)
+ {
+ aDate.SetDay(30);
+ aDate.SetMonth(9);
+ nVal = aDate - pFormatter->GetNullDate();
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+
+ else if(nMonth >= 10 && nMonth <=12)
+ {
+ aDate.SetDay(31);
+ aDate.SetMonth(12);
+ nVal = aDate - pFormatter->GetNullDate();
+ rDoc.SetValue(rCol, nRow, 0, nVal);
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+ else
+ rDoc.SetValue(rCol, nRow, 0, -1);
+
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::TIME:
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ LanguageType eLanguage = ScGlobal::eLnge;
+ sal_uInt32 nFormat = pFormatter->GetStandardFormat(SvNumFormatType::TIME, eLanguage);
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ ScAddress aAddress(rCol, nRow, 0);
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ rDoc.SetNumberFormat(aAddress, nFormat);
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::HOUR:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ sal_uInt16 nHour, nMinute, nSecond;
+ double fFractionOfSecond;
+ tools::Time::GetClock( nVal, nHour, nMinute, nSecond, fFractionOfSecond, 0);
+ rDoc.SetValue(rCol, nRow, 0, nHour);
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::MINUTE:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ sal_uInt16 nHour, nMinute, nSecond;
+ double fFractionOfSecond;
+ tools::Time::GetClock( nVal, nHour, nMinute, nSecond, fFractionOfSecond, 0);
+ rDoc.SetValue(rCol, nRow, 0, nMinute);
+ }
+ }
+ }
+ break;
+ case DATETIME_TRANSFORMATION_TYPE::SECOND:
+ {
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(rCol, nRow, 0);
+ if (eType == CELLTYPE_VALUE)
+ {
+ double nVal = rDoc.GetValue(rCol, nRow, 0);
+ sal_uInt16 nHour, nMinute, nSecond;
+ double fFractionOfSecond;
+ tools::Time::GetClock( nVal, nHour, nMinute, nSecond, fFractionOfSecond, 0);
+ rDoc.SetValue(rCol, nRow, 0, nSecond);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+TransformationType DateTimeTransformation::getTransformationType() const
+{
+ return TransformationType::DATETIME_TRANSFORMATION;
+}
+
+DATETIME_TRANSFORMATION_TYPE DateTimeTransformation::getDateTimeTransformationType() const
+{
+ return maType;
+}
+
+const std::set<SCCOL>& DateTimeTransformation::getColumn() const
+{
+ return mnCol;
+}
+
+FindReplaceTransformation::FindReplaceTransformation(SCCOL nCol, const OUString& aFindString, const OUString& aReplaceString)
+ : mnCol(nCol)
+ , maFindString(aFindString)
+ , maReplaceString(aReplaceString)
+{
+}
+
+void FindReplaceTransformation::Transform(ScDocument& rDoc) const
+{
+ if (mnCol == -1)
+ return;
+
+ SCROW nEndRow = getLastRow(rDoc, mnCol);
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(mnCol, nRow, 0);
+ if (eType != CELLTYPE_NONE)
+ {
+ OUString aStr = rDoc.GetString(mnCol, nRow, 0);
+ if (aStr == maFindString)
+ rDoc.SetString(mnCol, nRow, 0, maReplaceString);
+ }
+ }
+}
+
+TransformationType FindReplaceTransformation::getTransformationType() const
+{
+ return TransformationType::FINDREPLACE_TRANSFORMATION;
+}
+
+SCCOL FindReplaceTransformation::getColumn() const
+{
+ return mnCol;
+}
+
+const OUString& FindReplaceTransformation::getFindString() const
+{
+ return maFindString;
+}
+
+const OUString& FindReplaceTransformation::getReplaceString() const
+{
+ return maReplaceString;
+}
+
+DeleteRowTransformation::DeleteRowTransformation(SCCOL nCol, const OUString& aFindString)
+ : mnCol(nCol)
+ , maFindString(aFindString)
+{
+}
+
+void DeleteRowTransformation::Transform(ScDocument& rDoc) const
+{
+ sal_Int32 nIncrementIndex = 0;
+ if (mnCol == -1)
+ return;
+
+ SCROW nEndRow = getLastRow(rDoc, mnCol);
+ for (SCROW nRow = 0; nRow <= nEndRow; ++nRow)
+ {
+ CellType eType = rDoc.GetCellType(mnCol, nRow - nIncrementIndex, 0);
+ if (eType != CELLTYPE_NONE)
+ {
+ OUString aStr = rDoc.GetString(mnCol, nRow - nIncrementIndex, 0);
+ if (aStr == maFindString)
+ {
+ rDoc.DeleteRow(0, 0, rDoc.MaxCol(), 0, nRow - nIncrementIndex, 1);
+ nIncrementIndex++;
+ }
+ }
+ }
+}
+
+TransformationType DeleteRowTransformation::getTransformationType() const
+{
+ return TransformationType::DELETEROW_TRANSFORMATION;
+}
+
+SCCOL DeleteRowTransformation::getColumn() const
+{
+ return mnCol;
+}
+
+const OUString& DeleteRowTransformation::getFindString() const
+{
+ return maFindString;
+}
+
+SwapRowsTransformation::SwapRowsTransformation(SCROW mRow, SCROW nRow)
+ : mxRow(mRow)
+ , nxRow(nRow)
+{
+}
+
+void SwapRowsTransformation::Transform(ScDocument& rDoc) const
+{
+ if (mxRow == -1 || nxRow == -1)
+ return;
+
+ for (SCCOL nCol = 0; nCol <= rDoc.MaxCol(); ++nCol)
+ {
+ CellType aType = rDoc.GetCellType(nCol, mxRow, 0);
+ if (aType == CELLTYPE_STRING)
+ {
+ OUString aStr = rDoc.GetString(nCol, mxRow, 0);
+ OUString bStr = rDoc.GetString(nCol, nxRow, 0);
+ rDoc.SetString(nCol, mxRow, 0, bStr);
+ rDoc.SetString(nCol, nxRow, 0, aStr);
+ }
+ else if (aType == CELLTYPE_VALUE)
+ {
+ double aVal = rDoc.GetValue(nCol, mxRow, 0);
+ double bVal = rDoc.GetValue(nCol, nxRow, 0);
+ rDoc.SetValue(nCol, mxRow, 0, bVal);
+ rDoc.SetValue(nCol, nxRow, 0, aVal);
+ }
+ }
+}
+
+TransformationType SwapRowsTransformation::getTransformationType() const
+{
+ return TransformationType::SWAPROWS_TRANSFORMATION;
+}
+
+SCROW SwapRowsTransformation::getFirstRow() const
+{
+ return mxRow;
+}
+
+SCROW SwapRowsTransformation::getSecondRow() const
+{
+ return nxRow;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dataprovider/htmldataprovider.cxx b/sc/source/ui/dataprovider/htmldataprovider.cxx
new file mode 100644
index 000000000..8b241ddfe
--- /dev/null
+++ b/sc/source/ui/dataprovider/htmldataprovider.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/.
+ */
+
+#include "htmldataprovider.hxx"
+#include <datamapper.hxx>
+#include <datatransformation.hxx>
+#include <salhelper/thread.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/stream.hxx>
+
+#include <libxml/HTMLparser.h>
+
+#include <libxml/xpath.h>
+
+#include <comphelper/string.hxx>
+#include <utility>
+
+namespace sc {
+
+class HTMLFetchThread : public salhelper::Thread
+{
+ ScDocument& mrDocument;
+ OUString maURL;
+ OUString maID;
+ const std::vector<std::shared_ptr<sc::DataTransformation>> maDataTransformations;
+ std::function<void()> maImportFinishedHdl;
+
+ void handleTable(xmlNodePtr pTable);
+ void handleRow(xmlNodePtr pRow, SCROW nRow);
+ void skipHeadBody(xmlNodePtr pSkip, SCROW& rRow);
+ void handleCell(xmlNodePtr pCell, SCROW nRow, SCCOL nCol);
+
+public:
+ HTMLFetchThread(ScDocument& rDoc, const OUString&, const OUString& rID, std::function<void()> aImportFinishedHdl,
+ std::vector<std::shared_ptr<sc::DataTransformation>>&& rTransformations);
+
+ virtual void execute() override;
+};
+
+HTMLFetchThread::HTMLFetchThread(
+ ScDocument& rDoc, const OUString& rURL, const OUString& rID,
+ std::function<void()> aImportFinishedHdl,
+ std::vector<std::shared_ptr<sc::DataTransformation>>&& rTransformations)
+ : salhelper::Thread("HTML Fetch Thread")
+ , mrDocument(rDoc)
+ , maURL(rURL)
+ , maID(rID)
+ , maDataTransformations(std::move(rTransformations))
+ , maImportFinishedHdl(std::move(aImportFinishedHdl))
+{
+}
+
+namespace {
+
+OString toString(const xmlChar* pStr)
+{
+ return OString(reinterpret_cast<const char*>(pStr), xmlStrlen(pStr));
+}
+
+OUString trim_string(const OUString& aStr)
+{
+ OUString aOldString;
+ OUString aString = aStr;
+ do
+ {
+ aOldString = aString;
+ aString = comphelper::string::strip(aString, ' ');
+ aString = comphelper::string::strip(aString, '\n');
+ aString = comphelper::string::strip(aString, '\r');
+ aString = comphelper::string::strip(aString, '\t');
+ }
+ while (aOldString != aString);
+
+ return aString;
+}
+
+OUString get_node_str(xmlNodePtr pNode)
+{
+ OUStringBuffer aStr;
+ for (xmlNodePtr cur_node = pNode->children; cur_node; cur_node = cur_node->next)
+ {
+ if (cur_node->type == XML_TEXT_NODE)
+ {
+ OUString aString = OStringToOUString(toString(cur_node->content), RTL_TEXTENCODING_UTF8);
+ aStr.append(trim_string(aString));
+ }
+ else if (cur_node->type == XML_ELEMENT_NODE)
+ {
+ aStr.append(get_node_str(cur_node));
+ }
+ }
+
+ return aStr.makeStringAndClear();
+}
+
+}
+
+void HTMLFetchThread::handleCell(xmlNodePtr pCellNode, SCROW nRow, SCCOL nCol)
+{
+ OUStringBuffer aStr;
+ for (xmlNodePtr cur_node = pCellNode->children; cur_node; cur_node = cur_node->next)
+ {
+ if (cur_node->type == XML_TEXT_NODE)
+ {
+ OUString aString = OStringToOUString(toString(cur_node->content), RTL_TEXTENCODING_UTF8);
+ aStr.append(trim_string(aString));
+ }
+ else if (cur_node->type == XML_ELEMENT_NODE)
+ {
+ aStr.append(get_node_str(cur_node));
+ }
+ }
+
+ if (!aStr.isEmpty())
+ {
+ OUString aCellStr = aStr.makeStringAndClear();
+ mrDocument.SetString(nCol, nRow, 0, aCellStr);
+ }
+}
+
+void HTMLFetchThread::handleRow(xmlNodePtr pRowNode, SCROW nRow)
+{
+ sal_Int32 nCol = 0;
+ for (xmlNodePtr cur_node = pRowNode->children; cur_node; cur_node = cur_node->next)
+ {
+ if (cur_node->type == XML_ELEMENT_NODE)
+ {
+ OString aNodeName = toString(cur_node->name);
+ if (aNodeName == "td" || aNodeName == "th")
+ {
+ handleCell(cur_node, nRow, nCol);
+ ++nCol;
+ }
+ }
+ }
+}
+
+void HTMLFetchThread::skipHeadBody(xmlNodePtr pSkipElement, SCROW& rRow)
+{
+ for (xmlNodePtr cur_node = pSkipElement->children; cur_node; cur_node = cur_node->next)
+ {
+ if (cur_node->type == XML_ELEMENT_NODE)
+ {
+ OString aNodeName = toString(cur_node->name);
+ if (aNodeName == "tr")
+ {
+ handleRow(cur_node, rRow);
+ ++rRow;
+ }
+
+ }
+ }
+}
+
+void HTMLFetchThread::handleTable(xmlNodePtr pTable)
+{
+ sal_Int32 nRow = 0;
+ for (xmlNodePtr cur_node = pTable->children; cur_node; cur_node = cur_node->next)
+ {
+ if (cur_node->type == XML_ELEMENT_NODE)
+ {
+ OString aNodeName = toString(cur_node->name);
+ if (aNodeName == "tr")
+ {
+ handleRow(cur_node, nRow);
+ ++nRow;
+ }
+ else if (aNodeName == "thead" || aNodeName == "tbody")
+ {
+ skipHeadBody(cur_node, nRow);
+ }
+ }
+ }
+}
+
+void HTMLFetchThread::execute()
+{
+ OStringBuffer aBuffer(64000);
+ DataProvider::FetchStreamFromURL(maURL, aBuffer);
+
+ if (aBuffer.isEmpty())
+ return;
+
+ htmlDocPtr pHtmlPtr = htmlParseDoc(reinterpret_cast<xmlChar*>(const_cast<char*>(aBuffer.getStr())), nullptr);
+
+ OString aID = OUStringToOString(maID, RTL_TEXTENCODING_UTF8);
+ xmlXPathContextPtr pXmlXpathCtx = xmlXPathNewContext(pHtmlPtr);
+ xmlXPathObjectPtr pXmlXpathObj = xmlXPathEvalExpression(BAD_CAST(aID.getStr()), pXmlXpathCtx);
+
+ if (!pXmlXpathObj)
+ {
+ xmlXPathFreeContext(pXmlXpathCtx);
+ return;
+ }
+ xmlNodeSetPtr pXmlNodes = pXmlXpathObj->nodesetval;
+
+ if (!pXmlNodes)
+ {
+ xmlXPathFreeNodeSetList(pXmlXpathObj);
+ xmlXPathFreeContext(pXmlXpathCtx);
+ return;
+ }
+
+ if (pXmlNodes->nodeNr == 0)
+ {
+ xmlXPathFreeNodeSet(pXmlNodes);
+ xmlXPathFreeNodeSetList(pXmlXpathObj);
+ xmlXPathFreeContext(pXmlXpathCtx);
+ return;
+ }
+
+ xmlNodePtr pNode = pXmlNodes->nodeTab[0];
+ handleTable(pNode);
+
+ xmlXPathFreeNodeSet(pXmlNodes);
+ xmlXPathFreeNodeSetList(pXmlXpathObj);
+ xmlXPathFreeContext(pXmlXpathCtx);
+
+ for (auto& itr : maDataTransformations)
+ {
+ itr->Transform(mrDocument);
+ }
+
+ SolarMutexGuard aGuard;
+ maImportFinishedHdl();
+}
+
+HTMLDataProvider::HTMLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource):
+ DataProvider(rDataSource),
+ mpDocument(pDoc)
+{
+}
+
+HTMLDataProvider::~HTMLDataProvider()
+{
+ if (mxHTMLFetchThread.is())
+ {
+ SolarMutexReleaser aReleaser;
+ mxHTMLFetchThread->join();
+ }
+}
+
+void HTMLDataProvider::Import()
+{
+ // already importing data
+ if (mpDoc)
+ return;
+
+ mpDoc.reset(new ScDocument(SCDOCMODE_CLIP));
+ mpDoc->ResetClip(mpDocument, SCTAB(0));
+ mxHTMLFetchThread = new HTMLFetchThread(*mpDoc, mrDataSource.getURL(), mrDataSource.getID(),
+ std::bind(&HTMLDataProvider::ImportFinished, this), std::vector(mrDataSource.getDataTransformation()));
+ mxHTMLFetchThread->launch();
+
+ if (mbDeterministic)
+ {
+ SolarMutexReleaser aReleaser;
+ mxHTMLFetchThread->join();
+ }
+}
+
+void HTMLDataProvider::ImportFinished()
+{
+ mrDataSource.getDBManager()->WriteToDoc(*mpDoc);
+}
+
+const OUString& HTMLDataProvider::GetURL() const
+{
+ return mrDataSource.getURL();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dataprovider/htmldataprovider.hxx b/sc/source/ui/dataprovider/htmldataprovider.hxx
new file mode 100644
index 000000000..f978ebdd1
--- /dev/null
+++ b/sc/source/ui/dataprovider/htmldataprovider.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 <dataprovider.hxx>
+
+namespace sc
+{
+class HTMLFetchThread;
+
+class HTMLDataProvider : public DataProvider
+{
+private:
+ ScDocument* mpDocument;
+ rtl::Reference<HTMLFetchThread> mxHTMLFetchThread;
+
+ ScDocumentUniquePtr mpDoc;
+
+public:
+ HTMLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource);
+ virtual ~HTMLDataProvider() override;
+
+ virtual void Import() override;
+
+ virtual const OUString& GetURL() const override;
+
+ void ImportFinished();
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dataprovider/sqldataprovider.cxx b/sc/source/ui/dataprovider/sqldataprovider.cxx
new file mode 100644
index 000000000..a7d27dfa9
--- /dev/null
+++ b/sc/source/ui/dataprovider/sqldataprovider.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/.
+ */
+
+#include "sqldataprovider.hxx"
+#include <datatransformation.hxx>
+#include <salhelper/thread.hxx>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <dbdocutl.hxx>
+#include <datamapper.hxx>
+#include <vcl/svapp.hxx>
+#include <comphelper/processfactory.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace css;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::uno;
+
+namespace sc
+{
+class SQLFetchThread : public salhelper::Thread
+{
+ ScDocument& mrDocument;
+ OUString maID;
+ const std::vector<std::shared_ptr<sc::DataTransformation>> maDataTransformations;
+ std::function<void()> maImportFinishedHdl;
+
+public:
+ SQLFetchThread(ScDocument& rDoc, const OUString& rID, std::function<void()> aImportFinishedHdl,
+ std::vector<std::shared_ptr<sc::DataTransformation>>&& rTransformations);
+
+ virtual void execute() override;
+};
+
+SQLFetchThread::SQLFetchThread(
+ ScDocument& rDoc, const OUString& rID, std::function<void()> aImportFinishedHdl,
+ std::vector<std::shared_ptr<sc::DataTransformation>>&& rTransformations)
+ : salhelper::Thread("SQL Fetch Thread")
+ , mrDocument(rDoc)
+ , maID(rID)
+ , maDataTransformations(std::move(rTransformations))
+ , maImportFinishedHdl(aImportFinishedHdl)
+{
+}
+
+void SQLFetchThread::execute()
+{
+ sal_Int32 nIndex = maID.indexOf("@");
+ if (nIndex == -1)
+ return;
+
+ OUString aTable = maID.copy(0, nIndex);
+ OUString aDatabase = maID.copy(nIndex + 1);
+
+ try
+ {
+ uno::Reference<sdb::XDatabaseContext> xContext
+ = sdb::DatabaseContext::create(comphelper::getProcessComponentContext());
+ uno::Any aSourceAny = xContext->getByName(aDatabase);
+
+ uno::Reference<sdb::XCompletedConnection> xSource(aSourceAny, uno::UNO_QUERY);
+ if (!xSource.is())
+ return;
+
+ uno::Reference<task::XInteractionHandler> xHandler(
+ task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(),
+ nullptr),
+ uno::UNO_QUERY_THROW);
+
+ uno::Reference<sdbc::XConnection> xConnection = xSource->connectWithCompletion(xHandler);
+
+ uno::Reference<sdbc::XStatement> xStatement = xConnection->createStatement();
+
+ uno::Reference<sdbc::XResultSet> xResult
+ = xStatement->executeQuery("SELECT * FROM " + aTable);
+
+ if (xResult.is())
+ {
+ Reference<sdbc::XResultSetMetaDataSupplier> xMetaDataSupplier(xResult, UNO_QUERY);
+
+ Reference<sdbc::XResultSetMetaData> xMetaData = xMetaDataSupplier->getMetaData();
+
+ Reference<XRow> xRow(xResult, UNO_QUERY);
+
+ SCCOL nColCount = static_cast<SCCOL>(xMetaData->getColumnCount());
+
+ while (xResult->next())
+ {
+ SCROW nRow = static_cast<SCROW>(xResult->getRow());
+
+ for (SCCOL nCol = 0; nCol < nColCount; nCol++)
+ {
+ ScDatabaseDocUtil::PutData(mrDocument, nCol, nRow - 1, 0, xRow, nCol + 1,
+ xMetaData->getColumnType(nCol + 1), false);
+ }
+ }
+ }
+ }
+ catch (uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("sc", "exception in database");
+ }
+
+ for (auto& itr : maDataTransformations)
+ {
+ itr->Transform(mrDocument);
+ }
+
+ SolarMutexGuard aGuard;
+ maImportFinishedHdl();
+}
+
+SQLDataProvider::SQLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource)
+ : DataProvider(rDataSource)
+ , mpDocument(pDoc)
+{
+}
+
+SQLDataProvider::~SQLDataProvider()
+{
+ if (mxSQLFetchThread.is())
+ {
+ SolarMutexReleaser aReleaser;
+ mxSQLFetchThread->join();
+ }
+}
+
+void SQLDataProvider::Import()
+{
+ // already importing data
+ if (mpDoc)
+ return;
+
+ mpDoc.reset(new ScDocument(SCDOCMODE_CLIP));
+ mpDoc->ResetClip(mpDocument, SCTAB(0));
+ mxSQLFetchThread = new SQLFetchThread(*mpDoc, mrDataSource.getID(),
+ std::bind(&SQLDataProvider::ImportFinished, this),
+ std::vector(mrDataSource.getDataTransformation()));
+ mxSQLFetchThread->launch();
+
+ if (mbDeterministic)
+ {
+ SolarMutexReleaser aReleaser;
+ mxSQLFetchThread->join();
+ }
+}
+
+void SQLDataProvider::ImportFinished()
+{
+ mrDataSource.getDBManager()->WriteToDoc(*mpDoc);
+ mxSQLFetchThread.clear();
+ mpDoc.reset();
+}
+
+const OUString& SQLDataProvider::GetURL() const { return mrDataSource.getURL(); }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dataprovider/sqldataprovider.hxx b/sc/source/ui/dataprovider/sqldataprovider.hxx
new file mode 100644
index 000000000..fbbca7601
--- /dev/null
+++ b/sc/source/ui/dataprovider/sqldataprovider.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 <dataprovider.hxx>
+
+namespace sc
+{
+class SQLFetchThread;
+
+class SQLDataProvider : public DataProvider
+{
+private:
+ ScDocument* mpDocument;
+ rtl::Reference<SQLFetchThread> mxSQLFetchThread;
+
+ ScDocumentUniquePtr mpDoc;
+
+public:
+ SQLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource);
+ virtual ~SQLDataProvider() override;
+
+ virtual void Import() override;
+
+ virtual const OUString& GetURL() const override;
+
+ void ImportFinished();
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dataprovider/xmldataprovider.cxx b/sc/source/ui/dataprovider/xmldataprovider.cxx
new file mode 100644
index 000000000..4ffa45bd1
--- /dev/null
+++ b/sc/source/ui/dataprovider/xmldataprovider.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/.
+ */
+
+#include "xmldataprovider.hxx"
+#include <datatransformation.hxx>
+#include <salhelper/thread.hxx>
+#include <filter.hxx>
+#include <document.hxx>
+#include <datamapper.hxx>
+#include <vcl/svapp.hxx>
+#include <orcusfilters.hxx>
+#include <utility>
+
+using namespace com::sun::star;
+
+namespace sc
+{
+class XMLFetchThread : public salhelper::Thread
+{
+ ScDocument& mrDocument;
+ OUString maURL;
+ OUString maID;
+ ScOrcusImportXMLParam maParam;
+ std::unique_ptr<ScOrcusXMLContext> mpXMLContext;
+ const std::vector<std::shared_ptr<sc::DataTransformation>> maDataTransformations;
+ std::function<void()> maImportFinishedHdl;
+
+public:
+ XMLFetchThread(ScDocument& rDoc, const OUString&, const ScOrcusImportXMLParam& rParam,
+ const OUString& rID, std::function<void()> aImportFinishedHdl,
+ std::vector<std::shared_ptr<sc::DataTransformation>>&& rTransformations);
+ virtual void execute() override;
+};
+
+XMLFetchThread::XMLFetchThread(
+ ScDocument& rDoc, const OUString& rURL, const ScOrcusImportXMLParam& rParam,
+ const OUString& rID, std::function<void()> aImportFinishedHdl,
+ std::vector<std::shared_ptr<sc::DataTransformation>>&& rTransformations)
+ : salhelper::Thread("XML Fetch Thread")
+ , mrDocument(rDoc)
+ , maURL(rURL)
+ , maID(rID)
+ , maParam(rParam)
+ , maDataTransformations(std::move(rTransformations))
+ , maImportFinishedHdl(std::move(aImportFinishedHdl))
+{
+}
+
+void XMLFetchThread::execute()
+{
+ ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
+ if (!pOrcus)
+ return;
+
+ mpXMLContext = pOrcus->createXMLContext(mrDocument, maURL);
+ if (!mpXMLContext)
+ return;
+
+ if (!maID.isEmpty())
+ {
+ ScOrcusImportXMLParam::RangeLink aRangeLink;
+ aRangeLink.maPos = ScAddress(0, 0, 0);
+ aRangeLink.maFieldPaths.push_back(OUStringToOString(maID, RTL_TEXTENCODING_UTF8));
+ maParam.maRangeLinks.clear();
+ maParam.maRangeLinks.push_back(aRangeLink);
+ }
+ // Do the import.
+ mpXMLContext->importXML(maParam);
+
+ for (auto& itr : maDataTransformations)
+ {
+ itr->Transform(mrDocument);
+ }
+
+ SolarMutexGuard aGuard;
+ maImportFinishedHdl();
+}
+
+XMLDataProvider::XMLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource)
+ : DataProvider(rDataSource)
+ , mpDocument(pDoc)
+{
+}
+
+XMLDataProvider::~XMLDataProvider()
+{
+ if (mxXMLFetchThread.is())
+ {
+ SolarMutexReleaser aReleaser;
+ mxXMLFetchThread->join();
+ }
+}
+
+void XMLDataProvider::Import()
+{
+ // already importing data
+ if (mpDoc)
+ return;
+
+ mpDoc.reset(new ScDocument(SCDOCMODE_CLIP));
+ mpDoc->ResetClip(mpDocument, SCTAB(0));
+ mxXMLFetchThread = new XMLFetchThread(*mpDoc, mrDataSource.getURL(),
+ mrDataSource.getXMLImportParam(), mrDataSource.getID(),
+ std::bind(&XMLDataProvider::ImportFinished, this),
+ std::vector(mrDataSource.getDataTransformation()));
+ mxXMLFetchThread->launch();
+
+ if (mbDeterministic)
+ {
+ SolarMutexReleaser aReleaser;
+ mxXMLFetchThread->join();
+ }
+}
+
+void XMLDataProvider::ImportFinished() { mrDataSource.getDBManager()->WriteToDoc(*mpDoc); }
+
+const OUString& XMLDataProvider::GetURL() const { return mrDataSource.getURL(); }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dataprovider/xmldataprovider.hxx b/sc/source/ui/dataprovider/xmldataprovider.hxx
new file mode 100644
index 000000000..7be3f95c3
--- /dev/null
+++ b/sc/source/ui/dataprovider/xmldataprovider.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 <dataprovider.hxx>
+
+namespace sc
+{
+class XMLFetchThread;
+
+class XMLDataProvider : public DataProvider
+{
+private:
+ ScDocument* mpDocument;
+ rtl::Reference<XMLFetchThread> mxXMLFetchThread;
+ ScDocumentUniquePtr mpDoc;
+
+public:
+ XMLDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource);
+ virtual ~XMLDataProvider() override;
+
+ virtual void Import() override;
+
+ virtual const OUString& GetURL() const override;
+
+ void ImportFinished();
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/PivotLayoutDialog.cxx b/sc/source/ui/dbgui/PivotLayoutDialog.cxx
new file mode 100644
index 000000000..9244a4d7e
--- /dev/null
+++ b/sc/source/ui/dbgui/PivotLayoutDialog.cxx
@@ -0,0 +1,719 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ */
+
+#include <PivotLayoutTreeList.hxx>
+#include <PivotLayoutDialog.hxx>
+#include <reffact.hxx>
+
+#include <rangeutl.hxx>
+#include <uiitems.hxx>
+#include <dputil.hxx>
+#include <dbdocfun.hxx>
+#include <dpsave.hxx>
+#include <dpshttab.hxx>
+#include <scmod.hxx>
+
+#include <memory>
+#include <vector>
+
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
+
+using namespace css::uno;
+using namespace css::sheet;
+
+ScItemValue::ScItemValue(OUString const & aName, SCCOL nColumn, PivotFunc nFunctionMask) :
+ maName(aName),
+ maFunctionData(nColumn, nFunctionMask),
+ mpOriginalItemValue(this)
+{}
+
+ScItemValue::ScItemValue(const ScItemValue* pInputItemValue) :
+ maName(pInputItemValue->maName),
+ maFunctionData(pInputItemValue->maFunctionData),
+ mpOriginalItemValue(this)
+{}
+
+ScItemValue::~ScItemValue()
+{}
+
+namespace
+{
+
+ScRange lclGetRangeForNamedRange(OUString const & aName, const ScDocument& rDocument)
+{
+ ScRange aInvalidRange(ScAddress::INITIALIZE_INVALID);
+ ScRangeName* pRangeName = rDocument.GetRangeName();
+ if (pRangeName == nullptr)
+ return aInvalidRange;
+
+ const ScRangeData* pData = pRangeName->findByUpperName(aName.toAsciiUpperCase());
+ if (pData == nullptr)
+ return aInvalidRange;
+
+ ScRange aRange;
+ if (pData->IsReference(aRange))
+ return aRange;
+
+ return aInvalidRange;
+}
+
+}
+
+ScPivotLayoutDialog::ScPivotLayoutDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow, weld::Window* pParent,
+ ScViewData* pViewData, const ScDPObject* pPivotTableObject, bool bNewPivotTable)
+ : ScAnyRefDlgController(pSfxBindings, pChildWindow, pParent, "modules/scalc/ui/pivottablelayoutdialog.ui", "PivotTableLayout")
+ , maPivotTableObject(*pPivotTableObject)
+ , mpPreviouslyFocusedListBox(nullptr)
+ , mpViewData(pViewData)
+ , mrDocument(pViewData->GetDocument())
+ , mbNewPivotTable(bNewPivotTable)
+ , maAddressDetails(mrDocument.GetAddressConvention(), 0, 0)
+ , mbDialogLostFocus(false)
+ , mpActiveEdit(nullptr)
+ , mxListBoxField(new ScPivotLayoutTreeListLabel(m_xBuilder->weld_tree_view("listbox-fields")))
+ , mxListBoxPage(new ScPivotLayoutTreeList(m_xBuilder->weld_tree_view("listbox-page")))
+ , mxListBoxColumn(new ScPivotLayoutTreeList(m_xBuilder->weld_tree_view("listbox-column")))
+ , mxListBoxRow(new ScPivotLayoutTreeList(m_xBuilder->weld_tree_view("listbox-row")))
+ , mxListBoxData(new ScPivotLayoutTreeListData(m_xBuilder->weld_tree_view("listbox-data")))
+ , mxCheckIgnoreEmptyRows(m_xBuilder->weld_check_button("check-ignore-empty-rows"))
+ , mxCheckTotalColumns(m_xBuilder->weld_check_button("check-total-columns"))
+ , mxCheckAddFilter(m_xBuilder->weld_check_button("check-add-filter"))
+ , mxCheckIdentifyCategories(m_xBuilder->weld_check_button("check-identify-categories"))
+ , mxCheckTotalRows(m_xBuilder->weld_check_button("check-total-rows"))
+ , mxCheckDrillToDetail(m_xBuilder->weld_check_button("check-drill-to-details"))
+ , mxSourceRadioNamedRange(m_xBuilder->weld_radio_button("source-radio-named-range"))
+ , mxSourceRadioSelection(m_xBuilder->weld_radio_button("source-radio-selection"))
+ , mxSourceListBox(m_xBuilder->weld_combo_box("source-list"))
+ , mxSourceEdit(new formula::RefEdit(m_xBuilder->weld_entry("source-edit")))
+ , mxSourceButton(new formula::RefButton(m_xBuilder->weld_button("source-button")))
+ , mxDestinationRadioNewSheet(m_xBuilder->weld_radio_button("destination-radio-new-sheet"))
+ , mxDestinationRadioNamedRange(m_xBuilder->weld_radio_button("destination-radio-named-range"))
+ , mxDestinationRadioSelection(m_xBuilder->weld_radio_button("destination-radio-selection"))
+ , mxDestinationListBox(m_xBuilder->weld_combo_box("destination-list"))
+ , mxDestinationEdit(new formula::RefEdit(m_xBuilder->weld_entry("destination-edit")))
+ , mxDestinationButton(new formula::RefButton(m_xBuilder->weld_button("destination-button")))
+ , mxBtnOK(m_xBuilder->weld_button("ok"))
+ , mxBtnCancel(m_xBuilder->weld_button("cancel"))
+ , mxSourceFrame(m_xBuilder->weld_frame("frame2"))
+ , mxSourceLabel(mxSourceFrame->weld_label_widget())
+ , mxDestFrame(m_xBuilder->weld_frame("frame1"))
+ , mxDestLabel(mxDestFrame->weld_label_widget())
+ , mxOptions(m_xBuilder->weld_expander("options"))
+ , mxMore(m_xBuilder->weld_expander("more"))
+{
+ // Source UI
+ Link<weld::Toggleable&,void> aLink2 = LINK(this, ScPivotLayoutDialog, ToggleSource);
+ mxSourceRadioNamedRange->connect_toggled(aLink2);
+ mxSourceRadioSelection->connect_toggled(aLink2);
+
+ mxSourceEdit->SetReferences(this, mxSourceLabel.get());
+ mxSourceButton->SetReferences(this, mxSourceEdit.get());
+
+ Link<formula::RefEdit&,void> aEditLink = LINK(this, ScPivotLayoutDialog, GetEditFocusHandler);
+ mxDestinationEdit->SetGetFocusHdl(aEditLink);
+ mxSourceEdit->SetGetFocusHdl(aEditLink);
+
+ aEditLink = LINK(this, ScPivotLayoutDialog, LoseEditFocusHandler);
+ mxDestinationEdit->SetLoseFocusHdl(aEditLink);
+ mxSourceEdit->SetLoseFocusHdl(aEditLink);
+
+ mxSourceEdit->SetModifyHdl(LINK(this, ScPivotLayoutDialog, SourceEditModified));
+ mxSourceListBox->connect_changed(LINK(this, ScPivotLayoutDialog, SourceListSelected));
+
+ // Destination UI
+ aLink2 = LINK(this, ScPivotLayoutDialog, ToggleDestination);
+ mxDestinationRadioNewSheet->connect_toggled(aLink2);
+ mxDestinationRadioNamedRange->connect_toggled(aLink2);
+ mxDestinationRadioSelection->connect_toggled(aLink2);
+
+ mxDestinationEdit->SetReferences(this, mxDestLabel.get());
+ mxDestinationButton->SetReferences(this, mxDestinationEdit.get());
+
+ Link<formula::RefButton&,void> aButtonLink = LINK(this, ScPivotLayoutDialog, GetButtonFocusHandler);
+ mxSourceButton->SetGetFocusHdl(aButtonLink);
+ mxDestinationButton->SetGetFocusHdl(aButtonLink);
+
+ aButtonLink = LINK(this, ScPivotLayoutDialog, LoseButtonFocusHandler);
+ mxSourceButton->SetLoseFocusHdl(aButtonLink);
+ mxDestinationButton->SetLoseFocusHdl(aButtonLink);
+
+ // Buttons
+ mxBtnCancel->connect_clicked(LINK(this, ScPivotLayoutDialog, CancelClicked));
+ mxBtnOK->connect_clicked(LINK(this, ScPivotLayoutDialog, OKClicked));
+
+ // Initialize Data
+ maPivotTableObject.FillOldParam(maPivotParameters);
+ maPivotTableObject.FillLabelData(maPivotParameters);
+
+ mxListBoxField->Setup (this);
+ mxListBoxPage->Setup (this, ScPivotLayoutTreeList::PAGE_LIST);
+ mxListBoxColumn->Setup(this, ScPivotLayoutTreeList::COLUMN_LIST);
+ mxListBoxRow->Setup (this, ScPivotLayoutTreeList::ROW_LIST);
+ mxListBoxData->Setup (this);
+
+ FillValuesToListBoxes();
+
+ // Initialize Options
+ const ScDPSaveData* pSaveData = maPivotTableObject.GetSaveData();
+ if (pSaveData == nullptr)
+ {
+ mxCheckAddFilter->set_active(false);
+ mxCheckDrillToDetail->set_active(false);
+ }
+ else
+ {
+ mxCheckAddFilter->set_active(pSaveData->GetFilterButton());
+ mxCheckDrillToDetail->set_active(pSaveData->GetDrillDown());
+ }
+
+ mxCheckIgnoreEmptyRows->set_active(maPivotParameters.bIgnoreEmptyRows);
+ mxCheckIdentifyCategories->set_active(maPivotParameters.bDetectCategories);
+ mxCheckTotalColumns->set_active(maPivotParameters.bMakeTotalCol);
+ mxCheckTotalRows->set_active(maPivotParameters.bMakeTotalRow);
+
+ SetupSource();
+ SetupDestination();
+}
+
+ScPivotLayoutDialog::~ScPivotLayoutDialog()
+{
+}
+
+void ScPivotLayoutDialog::SetupSource()
+{
+ mxSourceListBox->clear();
+
+ ScRange aSourceRange;
+ OUString sSourceNamedRangeName;
+
+ if (maPivotTableObject.GetSheetDesc())
+ {
+ const ScSheetSourceDesc* pSheetSourceDesc = maPivotTableObject.GetSheetDesc();
+ aSourceRange = pSheetSourceDesc->GetSourceRange();
+
+ if(!aSourceRange.IsValid())
+ {
+ // Source is probably a DB Range
+ mxSourceRadioNamedRange->set_sensitive(false);
+ mxSourceRadioSelection->set_sensitive(false);
+ ToggleSource();
+ return;
+ }
+ else
+ {
+ OUString aSourceRangeName = aSourceRange.Format(mrDocument, ScRefFlags::RANGE_ABS_3D, maAddressDetails);
+ mxSourceEdit->SetText(aSourceRangeName);
+ }
+ }
+ else
+ {
+ mxSourceRadioNamedRange->set_sensitive(false);
+ mxSourceRadioSelection->set_sensitive(false);
+ ToggleSource();
+ return;
+ }
+
+ // Setup Named Ranges
+ bool bIsNamedRange = false;
+
+ ScAreaNameIterator aIterator(mrDocument);
+ OUString aEachName;
+ ScRange aEachRange;
+
+ while (aIterator.Next(aEachName, aEachRange))
+ {
+ if (!aIterator.WasDBName())
+ {
+ mxSourceListBox->append_text(aEachName);
+ if (aEachRange == aSourceRange)
+ {
+ sSourceNamedRangeName = aEachName;
+ bIsNamedRange = true;
+ }
+ }
+ }
+
+ bool bSourceBoxHasEntries = mxSourceListBox->get_count() > 0;
+
+ if (bIsNamedRange)
+ {
+ mxSourceListBox->set_active_text(sSourceNamedRangeName);
+ mxSourceRadioNamedRange->set_active(true);
+ }
+ else
+ {
+ // If entries - select first entry
+ mxSourceListBox->set_active(bSourceBoxHasEntries ? 0 : -1);
+ mxSourceRadioSelection->set_active(true);
+ }
+
+ // If no entries disable the radio button.
+ if (!bSourceBoxHasEntries)
+ mxSourceRadioNamedRange->set_sensitive(false);
+
+ ToggleSource();
+}
+
+void ScPivotLayoutDialog::SetupDestination()
+{
+ mxDestinationListBox->clear();
+
+ // Fill up named ranges
+ ScAreaNameIterator aIterator(mrDocument);
+ OUString aName;
+ ScRange aRange;
+
+ while (aIterator.Next(aName, aRange))
+ {
+ if (!aIterator.WasDBName())
+ {
+ mxDestinationListBox->append_text(aName);
+ }
+ }
+
+ // If entries - select first entry, otherwise disable the radio button.
+ if (mxDestinationListBox->get_count() > 0)
+ mxDestinationListBox->set_active(0);
+ else
+ mxDestinationRadioNamedRange->set_sensitive(false);
+
+ //
+ if (mbNewPivotTable)
+ {
+ mxDestinationRadioNewSheet->set_active(true);
+ }
+ else
+ {
+ if (maPivotParameters.nTab != MAXTAB + 1)
+ {
+ ScAddress aAddress(maPivotParameters.nCol, maPivotParameters.nRow, maPivotParameters.nTab);
+ OUString aAddressString = aAddress.Format(ScRefFlags::ADDR_ABS_3D, &mrDocument, maAddressDetails);
+ mxDestinationEdit->SetText(aAddressString);
+ mxDestinationRadioSelection->set_active(true);
+ }
+ }
+
+ ToggleDestination();
+}
+
+void ScPivotLayoutDialog::FillValuesToListBoxes()
+{
+ mxListBoxField->FillLabelFields(maPivotParameters.maLabelArray);
+ mxListBoxData->FillDataField(maPivotParameters.maDataFields);
+ mxListBoxColumn->FillFields(maPivotParameters.maColFields);
+ mxListBoxRow->FillFields(maPivotParameters.maRowFields);
+ mxListBoxPage->FillFields(maPivotParameters.maPageFields);
+}
+
+void ScPivotLayoutDialog::SetActive()
+{
+ if (mbDialogLostFocus)
+ {
+ mbDialogLostFocus = false;
+ if(mpActiveEdit != nullptr)
+ {
+ mpActiveEdit->GrabFocus();
+ if (mpActiveEdit == mxSourceEdit.get())
+ UpdateSourceRange();
+ }
+ }
+ else
+ {
+ m_xDialog->grab_focus();
+ }
+
+ RefInputDone();
+}
+
+void ScPivotLayoutDialog::SetReference(const ScRange& rReferenceRange, ScDocument& rDocument)
+{
+ if (!mbDialogLostFocus)
+ return;
+
+ if (mpActiveEdit == nullptr)
+ return;
+
+ if (rReferenceRange.aStart != rReferenceRange.aEnd)
+ RefInputStart(mpActiveEdit);
+
+ OUString aReferenceString = rReferenceRange.Format(rDocument, ScRefFlags::RANGE_ABS_3D, maAddressDetails);
+
+ if (mpActiveEdit == mxSourceEdit.get())
+ {
+ mxSourceEdit->SetRefString(aReferenceString);
+ }
+ else if (mpActiveEdit == mxDestinationEdit.get())
+ {
+ mxDestinationEdit->SetRefString(aReferenceString);
+ }
+}
+
+bool ScPivotLayoutDialog::IsRefInputMode() const
+{
+ return mbDialogLostFocus;
+}
+
+void ScPivotLayoutDialog::ItemInserted(const ScItemValue* pItemValue, ScPivotLayoutTreeList::SvPivotTreeListType eType)
+{
+ if (pItemValue == nullptr)
+ return;
+
+ switch (eType)
+ {
+ case ScPivotLayoutTreeList::ROW_LIST:
+ case ScPivotLayoutTreeList::COLUMN_LIST:
+ case ScPivotLayoutTreeList::PAGE_LIST:
+ {
+ mxListBoxRow->RemoveEntryForItem(pItemValue);
+ mxListBoxColumn->RemoveEntryForItem(pItemValue);
+ mxListBoxPage->RemoveEntryForItem(pItemValue);
+ }
+ break;
+ case ScPivotLayoutTreeList::LABEL_LIST:
+ {
+ mxListBoxRow->RemoveEntryForItem(pItemValue);
+ mxListBoxColumn->RemoveEntryForItem(pItemValue);
+ mxListBoxPage->RemoveEntryForItem(pItemValue);
+ mxListBoxData->RemoveEntryForItem(pItemValue);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void ScPivotLayoutDialog::UpdateSourceRange()
+{
+ if (!maPivotTableObject.GetSheetDesc())
+ return;
+
+ ScSheetSourceDesc aSourceSheet = *maPivotTableObject.GetSheetDesc();
+
+ if (mxSourceRadioNamedRange->get_active())
+ {
+ OUString aEntryString = mxSourceListBox->get_active_text();
+ ScRange aSourceRange = lclGetRangeForNamedRange(aEntryString, mrDocument);
+ if (!aSourceRange.IsValid() || aSourceSheet.GetSourceRange() == aSourceRange)
+ return;
+ aSourceSheet.SetRangeName(aEntryString);
+ }
+ else if (mxSourceRadioSelection->get_active())
+ {
+ OUString aSourceString = mxSourceEdit->GetText();
+ ScRange aSourceRange;
+ ScRefFlags nResult = aSourceRange.Parse(aSourceString, mrDocument, maAddressDetails);
+
+ bool bIsValid = (nResult & ScRefFlags::VALID) == ScRefFlags::VALID; // aSourceString is valid
+
+ mxSourceEdit->SetRefValid(true);
+
+ if (bIsValid)
+ {
+ ScRefAddress aStart;
+ ScRefAddress aEnd;
+
+ ConvertDoubleRef(mrDocument, aSourceString, 1, aStart, aEnd, maAddressDetails);
+ aSourceRange.aStart = aStart.GetAddress();
+ aSourceRange.aEnd = aEnd.GetAddress();
+ }
+ else
+ {
+ aSourceRange = lclGetRangeForNamedRange(aSourceString, mrDocument);
+ }
+
+ if (!aSourceRange.IsValid())
+ {
+ mxSourceEdit->SetRefValid(false);
+ return;
+ }
+
+ if (aSourceSheet.GetSourceRange() == aSourceRange)
+ return;
+
+ aSourceSheet.SetSourceRange(aSourceRange);
+ if (aSourceSheet.CheckSourceRange())
+ {
+ mxSourceEdit->SetRefValid(false);
+ return;
+ }
+ }
+ else
+ {
+ return;
+ }
+
+ maPivotTableObject.SetSheetDesc(aSourceSheet);
+ maPivotTableObject.FillOldParam(maPivotParameters);
+ maPivotTableObject.FillLabelData(maPivotParameters);
+
+ FillValuesToListBoxes();
+}
+
+void ScPivotLayoutDialog::ApplyChanges()
+{
+ ScDPSaveData aSaveData;
+ ApplySaveData(aSaveData);
+ ApplyLabelData(aSaveData);
+
+ ScDPObject *pOldDPObj = mrDocument.GetDPAtCursor( maPivotParameters.nCol, maPivotParameters.nRow, maPivotParameters.nTab);
+ ScRange aDestinationRange;
+ bool bToNewSheet = false;
+
+ if (!GetDestination(aDestinationRange, bToNewSheet))
+ return;
+
+ SetDispatcherLock(false);
+ SwitchToDocument();
+
+ sal_uInt16 nWhichPivot = SC_MOD()->GetPool().GetWhich(SID_PIVOT_TABLE);
+ ScPivotItem aPivotItem(nWhichPivot, &aSaveData, &aDestinationRange, bToNewSheet);
+ mpViewData->GetViewShell()->SetDialogDPObject(std::make_unique<ScDPObject>(maPivotTableObject));
+
+
+ SfxDispatcher* pDispatcher = GetBindings().GetDispatcher();
+ SfxCallMode const nCallMode = SfxCallMode::SLOT | SfxCallMode::RECORD;
+ const SfxPoolItem* pResult = pDispatcher->ExecuteList(SID_PIVOT_TABLE,
+ nCallMode, { &aPivotItem });
+
+ if (pResult != nullptr)
+ {
+ // existing pivot table might have moved to a new range or a new sheet
+ if ( pOldDPObj != nullptr )
+ {
+ const ScRange& rOldRange = pOldDPObj->GetOutRange();
+
+ ScDPObject *pDPObj = nullptr;
+ // FIXME: if the new range overlaps with the old one, the table actually doesn't move
+ // and shouldn't therefore be deleted
+ if ( ( ( rOldRange != aDestinationRange ) && !rOldRange.Contains( aDestinationRange ) )
+ || bToNewSheet )
+ {
+ pDPObj = mrDocument.GetDPAtCursor( maPivotParameters.nCol, maPivotParameters.nRow, maPivotParameters.nTab);
+ }
+ if (pDPObj)
+ {
+ ScDBDocFunc aFunc( *(mpViewData->GetDocShell() ));
+ aFunc.RemovePivotTable( *pDPObj, true, false);
+ mpViewData->GetView()->CursorPosChanged();
+ }
+ }
+ return;
+ }
+
+ SetDispatcherLock(true);
+}
+
+void ScPivotLayoutDialog::ApplySaveData(ScDPSaveData& rSaveData)
+{
+ rSaveData.SetIgnoreEmptyRows(mxCheckIgnoreEmptyRows->get_active());
+ rSaveData.SetRepeatIfEmpty(mxCheckIdentifyCategories->get_active());
+ rSaveData.SetColumnGrand(mxCheckTotalColumns->get_active());
+ rSaveData.SetRowGrand(mxCheckTotalRows->get_active());
+ rSaveData.SetFilterButton(mxCheckAddFilter->get_active());
+ rSaveData.SetDrillDown(mxCheckDrillToDetail->get_active());
+
+ Reference<XDimensionsSupplier> xSource = maPivotTableObject.GetSource();
+
+ ScPivotFieldVector aPageFieldVector;
+ mxListBoxPage->PushEntriesToPivotFieldVector(aPageFieldVector);
+ ScDPObject::ConvertOrientation(rSaveData, aPageFieldVector, DataPilotFieldOrientation_PAGE,
+ xSource, maPivotParameters.maLabelArray);
+
+ ScPivotFieldVector aColFieldVector;
+ mxListBoxColumn->PushEntriesToPivotFieldVector(aColFieldVector);
+ ScDPObject::ConvertOrientation(rSaveData, aColFieldVector, DataPilotFieldOrientation_COLUMN,
+ xSource, maPivotParameters.maLabelArray);
+
+ ScPivotFieldVector aRowFieldVector;
+ mxListBoxRow->PushEntriesToPivotFieldVector(aRowFieldVector);
+ ScDPObject::ConvertOrientation(rSaveData, aRowFieldVector, DataPilotFieldOrientation_ROW,
+ xSource, maPivotParameters.maLabelArray);
+
+ ScPivotFieldVector aDataFieldVector;
+ mxListBoxData->PushEntriesToPivotFieldVector(aDataFieldVector);
+ ScDPObject::ConvertOrientation(rSaveData, aDataFieldVector, DataPilotFieldOrientation_DATA,
+ xSource, maPivotParameters.maLabelArray,
+ &aColFieldVector, &aRowFieldVector, &aPageFieldVector);
+}
+
+void ScPivotLayoutDialog::ApplyLabelData(const ScDPSaveData& rSaveData)
+{
+ ScDPLabelDataVector& rLabelDataVector = GetLabelDataVector();
+
+ for (std::unique_ptr<ScDPLabelData> const & pLabelData : rLabelDataVector)
+ {
+ OUString aUnoName = ScDPUtil::createDuplicateDimensionName(pLabelData->maName, pLabelData->mnDupCount);
+ ScDPSaveDimension* pSaveDimensions = rSaveData.GetExistingDimensionByName(aUnoName);
+
+ if (pSaveDimensions == nullptr)
+ continue;
+
+ pSaveDimensions->SetUsedHierarchy(pLabelData->mnUsedHier);
+ pSaveDimensions->SetShowEmpty(pLabelData->mbShowAll);
+ pSaveDimensions->SetRepeatItemLabels(pLabelData->mbRepeatItemLabels);
+ pSaveDimensions->SetSortInfo(&pLabelData->maSortInfo);
+ pSaveDimensions->SetLayoutInfo(&pLabelData->maLayoutInfo);
+ pSaveDimensions->SetAutoShowInfo(&pLabelData->maShowInfo);
+
+ bool bManualSort = (pLabelData->maSortInfo.Mode == DataPilotFieldSortMode::MANUAL);
+
+ for (ScDPLabelData::Member const & rLabelMember : pLabelData->maMembers)
+ {
+ ScDPSaveMember* pMember = pSaveDimensions->GetMemberByName(rLabelMember.maName);
+
+ if (bManualSort || !rLabelMember.mbVisible || !rLabelMember.mbShowDetails)
+ {
+ pMember->SetIsVisible(rLabelMember.mbVisible);
+ pMember->SetShowDetails(rLabelMember.mbShowDetails);
+ }
+ }
+ }
+}
+
+bool ScPivotLayoutDialog::GetDestination(ScRange& aDestinationRange, bool& bToNewSheet)
+{
+ bToNewSheet = false;
+
+ if (mxDestinationRadioNamedRange->get_active())
+ {
+ OUString aName = mxDestinationListBox->get_active_text();
+ aDestinationRange = lclGetRangeForNamedRange(aName, mrDocument);
+ if (!aDestinationRange.IsValid())
+ return false;
+ }
+ else if (mxDestinationRadioSelection->get_active())
+ {
+ ScAddress aAddress;
+ aAddress.Parse(mxDestinationEdit->GetText(), mrDocument, maAddressDetails);
+ aDestinationRange = ScRange(aAddress);
+ }
+ else
+ {
+ bToNewSheet = true;
+ aDestinationRange = ScRange(maPivotParameters.nCol, maPivotParameters.nRow, maPivotParameters.nTab);
+ }
+ return true;
+}
+
+ScItemValue* ScPivotLayoutDialog::GetItem(SCCOL nColumn)
+{
+ return mxListBoxField->GetItem(nColumn);
+}
+
+bool ScPivotLayoutDialog::IsDataElement(SCCOL nColumn)
+{
+ return mxListBoxField->IsDataElement(nColumn);
+}
+
+ScDPLabelData& ScPivotLayoutDialog::GetLabelData(SCCOL nColumn)
+{
+ return *maPivotParameters.maLabelArray[nColumn];
+}
+
+void ScPivotLayoutDialog::PushDataFieldNames(std::vector<ScDPName>& rDataFieldNames)
+{
+ mxListBoxData->PushDataFieldNames(rDataFieldNames);
+}
+
+void ScPivotLayoutDialog::Close()
+{
+ DoClose(ScPivotLayoutWrapper::GetChildWindowId());
+ SfxDialogController::Close();
+}
+
+IMPL_LINK_NOARG( ScPivotLayoutDialog, OKClicked, weld::Button&, void )
+{
+ /* tdf#137726 hide so it's not a candidate to be parent of any error
+ messages that may appear because this dialog is going to disappear on
+ response(RET_OK) and the error dialog is not run in its own event loop
+ but instead async */
+ m_xDialog->hide();
+
+ ApplyChanges();
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG( ScPivotLayoutDialog, CancelClicked, weld::Button&, void )
+{
+ m_xDialog->response(RET_CANCEL);
+}
+
+IMPL_LINK(ScPivotLayoutDialog, GetEditFocusHandler, formula::RefEdit&, rCtrl, void)
+{
+ mpActiveEdit = &rCtrl;
+ mpActiveEdit->SelectAll();
+}
+
+IMPL_LINK(ScPivotLayoutDialog, GetButtonFocusHandler, formula::RefButton&, rCtrl, void)
+{
+ mpActiveEdit = nullptr;
+
+ if (&rCtrl == mxSourceButton.get())
+ mpActiveEdit = mxSourceEdit.get();
+ else if (&rCtrl == mxDestinationButton.get())
+ mpActiveEdit = mxDestinationEdit.get();
+
+ if (mpActiveEdit)
+ mpActiveEdit->SelectAll();
+}
+
+IMPL_LINK_NOARG(ScPivotLayoutDialog, LoseEditFocusHandler, formula::RefEdit&, void)
+{
+ mbDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScPivotLayoutDialog, LoseButtonFocusHandler, formula::RefButton&, void)
+{
+ mbDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScPivotLayoutDialog, SourceListSelected, weld::ComboBox&, void)
+{
+ UpdateSourceRange();
+}
+
+IMPL_LINK_NOARG(ScPivotLayoutDialog, SourceEditModified, formula::RefEdit&, void)
+{
+ UpdateSourceRange();
+}
+
+IMPL_LINK_NOARG(ScPivotLayoutDialog, ToggleSource, weld::Toggleable&, void)
+{
+ ToggleSource();
+}
+
+void ScPivotLayoutDialog::ToggleSource()
+{
+ bool bNamedRange = mxSourceRadioNamedRange->get_active();
+ bool bSelection = mxSourceRadioSelection->get_active();
+ mxSourceListBox->set_sensitive(bNamedRange);
+ mxSourceButton->GetWidget()->set_sensitive(bSelection);
+ mxSourceEdit->GetWidget()->set_sensitive(bSelection);
+ UpdateSourceRange();
+}
+
+IMPL_LINK_NOARG(ScPivotLayoutDialog, ToggleDestination, weld::Toggleable&, void)
+{
+ ToggleDestination();
+}
+
+void ScPivotLayoutDialog::ToggleDestination()
+{
+ bool bNamedRange = mxDestinationRadioNamedRange->get_active();
+ bool bSelection = mxDestinationRadioSelection->get_active();
+ mxDestinationListBox->set_sensitive(bNamedRange);
+ mxDestinationButton->GetWidget()->set_sensitive(bSelection);
+ mxDestinationEdit->GetWidget()->set_sensitive(bSelection);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/PivotLayoutTreeList.cxx b/sc/source/ui/dbgui/PivotLayoutTreeList.cxx
new file mode 100644
index 000000000..c173d7ca7
--- /dev/null
+++ b/sc/source/ui/dbgui/PivotLayoutTreeList.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:
+ */
+
+#include <memory>
+#include <PivotLayoutTreeList.hxx>
+#include <PivotLayoutDialog.hxx>
+
+#include <vcl/event.hxx>
+#include <pivot.hxx>
+
+ScPivotLayoutTreeList::ScPivotLayoutTreeList(std::unique_ptr<weld::TreeView> xControl)
+ : ScPivotLayoutTreeListBase(std::move(xControl))
+{
+ mxControl->connect_key_press(LINK(this, ScPivotLayoutTreeList, KeyInputHdl));
+ mxControl->connect_row_activated(LINK(this, ScPivotLayoutTreeList, DoubleClickHdl));
+}
+
+ScPivotLayoutTreeList::~ScPivotLayoutTreeList()
+{
+ if (mpSubtotalDlg)
+ {
+ mpSubtotalDlg->Response(RET_CANCEL);
+ mpSubtotalDlg.clear();
+ }
+}
+
+void ScPivotLayoutTreeList::Setup(ScPivotLayoutDialog* pParent, SvPivotTreeListType eType)
+{
+ mpParent = pParent;
+ meType = eType;
+}
+
+IMPL_LINK_NOARG(ScPivotLayoutTreeList, DoubleClickHdl, weld::TreeView&, bool)
+{
+ int nEntry = mxControl->get_cursor_index();
+ if (nEntry == -1)
+ return true;
+
+ ScItemValue* pCurrentItemValue = weld::fromId<ScItemValue*>(mxControl->get_id(nEntry));
+ ScPivotFuncData& rCurrentFunctionData = pCurrentItemValue->maFunctionData;
+ SCCOL nCurrentColumn = rCurrentFunctionData.mnCol;
+
+ if (mpParent->IsDataElement(nCurrentColumn))
+ return true;
+
+ ScDPLabelData& rCurrentLabelData = mpParent->GetLabelData(nCurrentColumn);
+
+ ScAbstractDialogFactory* pFactory = ScAbstractDialogFactory::Create();
+
+ maDataFieldNames.clear();
+ mpParent->PushDataFieldNames(maDataFieldNames);
+
+ mpSubtotalDlg = pFactory->CreateScDPSubtotalDlg(mxControl.get(), mpParent->maPivotTableObject,
+ rCurrentLabelData, rCurrentFunctionData,
+ maDataFieldNames);
+
+ mpSubtotalDlg->StartExecuteAsync([this, pCurrentItemValue, nCurrentColumn](int nResult) {
+ if (nResult == RET_OK)
+ {
+ mpSubtotalDlg->FillLabelData(mpParent->GetLabelData(nCurrentColumn));
+ pCurrentItemValue->maFunctionData.mnFuncMask = mpSubtotalDlg->GetFuncMask();
+ }
+
+ mpSubtotalDlg.disposeAndClear();
+ });
+
+ return true;
+}
+
+void ScPivotLayoutTreeList::FillFields(ScPivotFieldVector& rFieldVector)
+{
+ mxControl->clear();
+ maItemValues.clear();
+
+ for (const ScPivotField& rField : rFieldVector)
+ {
+ OUString aLabel = mpParent->GetItem(rField.nCol)->maName;
+ ScItemValue* pItemValue = new ScItemValue(aLabel, rField.nCol, rField.nFuncMask);
+ maItemValues.push_back(std::unique_ptr<ScItemValue>(pItemValue));
+ OUString sId(weld::toId(pItemValue));
+ mxControl->append(sId, pItemValue->maName);
+ }
+}
+
+void ScPivotLayoutTreeList::InsertEntryForSourceTarget(weld::TreeView& rSource, int nTarget)
+{
+ ScItemValue* pItemValue = weld::fromId<ScItemValue*>(rSource.get_selected_id());
+ ScItemValue* pOriginalItemValue = pItemValue->mpOriginalItemValue;
+
+ // Don't allow to add "Data" element to page fields
+ if (meType == PAGE_LIST && mpParent->IsDataElement(pItemValue->maFunctionData.mnCol))
+ return;
+
+ mpParent->ItemInserted(pOriginalItemValue, meType);
+
+ InsertEntryForItem(pOriginalItemValue, nTarget);
+}
+
+void ScPivotLayoutTreeList::InsertEntryForItem(const ScItemValue* pItemValue, int nPosition)
+{
+ ScItemValue* pListItemValue = new ScItemValue(pItemValue);
+ maItemValues.push_back(std::unique_ptr<ScItemValue>(pListItemValue));
+ OUString sName = pListItemValue->maName;
+ OUString sId(weld::toId(pListItemValue));
+ mxControl->insert(nullptr, nPosition, &sName, &sId, nullptr, nullptr, false, nullptr);
+}
+
+IMPL_LINK(ScPivotLayoutTreeList, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
+{
+ vcl::KeyCode aCode = rKeyEvent.GetKeyCode();
+ sal_uInt16 nCode = aCode.GetCode();
+
+ if (nCode == KEY_DELETE)
+ {
+ const int nEntry = mxControl->get_cursor_index();
+ if (nEntry != -1)
+ mxControl->remove(nEntry);
+ return true;
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/PivotLayoutTreeListBase.cxx b/sc/source/ui/dbgui/PivotLayoutTreeListBase.cxx
new file mode 100644
index 000000000..45af29a4f
--- /dev/null
+++ b/sc/source/ui/dbgui/PivotLayoutTreeListBase.cxx
@@ -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:
+ */
+
+#include <PivotLayoutTreeListBase.hxx>
+#include <PivotLayoutDialog.hxx>
+
+ScPivotLayoutTreeListBase::ScPivotLayoutTreeListBase(std::unique_ptr<weld::TreeView> xControl, SvPivotTreeListType eType)
+ : mxControl(std::move(xControl))
+ , maDropTargetHelper(*this)
+ , meType(eType)
+ , mpParent(nullptr)
+{
+ mxControl->connect_focus_in(LINK(this, ScPivotLayoutTreeListBase, GetFocusHdl));
+ mxControl->connect_mnemonic_activate(LINK(this, ScPivotLayoutTreeListBase, MnemonicActivateHdl));
+ mxControl->connect_focus_out(LINK(this, ScPivotLayoutTreeListBase, LoseFocusHdl));
+}
+
+ScPivotLayoutTreeListBase::~ScPivotLayoutTreeListBase()
+{
+}
+
+void ScPivotLayoutTreeListBase::Setup(ScPivotLayoutDialog* pParent)
+{
+ mpParent = pParent;
+}
+
+ScPivotLayoutTreeDropTarget::ScPivotLayoutTreeDropTarget(ScPivotLayoutTreeListBase& rTreeView)
+ : DropTargetHelper(rTreeView.get_widget().get_drop_target())
+ , m_rTreeView(rTreeView)
+{
+}
+
+sal_Int8 ScPivotLayoutTreeDropTarget::AcceptDrop(const AcceptDropEvent& rEvt)
+{
+ // 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 DND_ACTION_MOVE;
+}
+
+sal_Int8 ScPivotLayoutTreeDropTarget::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ weld::TreeView& rWidget = m_rTreeView.get_widget();
+ weld::TreeView* pSource = rWidget.get_drag_source();
+ if (!pSource)
+ return DND_ACTION_NONE;
+
+ std::unique_ptr<weld::TreeIter> xTarget(rWidget.make_iterator());
+ int nTargetPos = -1;
+ if (rWidget.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
+ nTargetPos = rWidget.get_iter_index_in_parent(*xTarget);
+ m_rTreeView.InsertEntryForSourceTarget(*pSource, nTargetPos);
+ rWidget.unset_drag_dest_row();
+ return DND_ACTION_NONE;
+}
+
+void ScPivotLayoutTreeListBase::PushEntriesToPivotFieldVector(ScPivotFieldVector& rVector)
+{
+ std::unique_ptr<weld::TreeIter> xEachEntry(mxControl->make_iterator());
+ if (!mxControl->get_iter_first(*xEachEntry))
+ return;
+ do
+ {
+ ScItemValue* pItemValue = weld::fromId<ScItemValue*>(mxControl->get_id(*xEachEntry));
+ ScPivotFuncData& rFunctionData = pItemValue->maFunctionData;
+
+ ScPivotField aField;
+ aField.nCol = rFunctionData.mnCol;
+ aField.mnOriginalDim = rFunctionData.mnOriginalDim;
+ aField.nFuncMask = rFunctionData.mnFuncMask;
+ aField.mnDupCount = rFunctionData.mnDupCount;
+ aField.maFieldRef = rFunctionData.maFieldRef;
+ rVector.push_back(aField);
+ } while (mxControl->iter_next(*xEachEntry));
+}
+
+void ScPivotLayoutTreeListBase::InsertEntryForSourceTarget(weld::TreeView& /*pSource*/, int /*nTarget*/)
+{
+}
+
+void ScPivotLayoutTreeListBase::RemoveEntryForItem(const ScItemValue* pItemValue)
+{
+ OUString sId(weld::toId(pItemValue));
+ int nPos = mxControl->find_id(sId);
+ if (nPos == -1)
+ return;
+ mxControl->remove(nPos);
+}
+
+IMPL_LINK_NOARG(ScPivotLayoutTreeListBase, GetFocusHdl, weld::Widget&, void)
+{
+ if (!mpParent)
+ return;
+ mpParent->mpPreviouslyFocusedListBox = this;
+}
+
+IMPL_LINK_NOARG(ScPivotLayoutTreeListBase, MnemonicActivateHdl, weld::Widget&, bool)
+{
+ if (!mpParent || !mpParent->mpPreviouslyFocusedListBox)
+ return false;
+ weld::TreeView& rSource = mpParent->mpPreviouslyFocusedListBox->get_widget();
+ int nEntry = rSource.get_cursor_index();
+ if (nEntry != -1)
+ InsertEntryForSourceTarget(rSource, -1);
+ return true;
+}
+
+IMPL_LINK_NOARG(ScPivotLayoutTreeListBase, LoseFocusHdl, weld::Widget&, void)
+{
+ if (!mpParent)
+ return;
+ mpParent->mpPreviouslyFocusedListBox = nullptr;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/PivotLayoutTreeListData.cxx b/sc/source/ui/dbgui/PivotLayoutTreeListData.cxx
new file mode 100644
index 000000000..19992fc31
--- /dev/null
+++ b/sc/source/ui/dbgui/PivotLayoutTreeListData.cxx
@@ -0,0 +1,287 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ */
+
+#include <memory>
+#include <string_view>
+
+#include <PivotLayoutTreeListData.hxx>
+#include <PivotLayoutDialog.hxx>
+
+#include <vcl/event.hxx>
+#include <pivot.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+namespace
+{
+
+OUString lclGetFunctionMaskName(const PivotFunc nFunctionMask)
+{
+ TranslateId pStrId;
+ switch (nFunctionMask)
+ {
+ case PivotFunc::Sum: pStrId = STR_FUN_TEXT_SUM; break;
+ case PivotFunc::Count: pStrId = STR_FUN_TEXT_COUNT; break;
+ case PivotFunc::Average: pStrId = STR_FUN_TEXT_AVG; break;
+ case PivotFunc::Median: pStrId = STR_FUN_TEXT_MEDIAN; break;
+ case PivotFunc::Max: pStrId = STR_FUN_TEXT_MAX; break;
+ case PivotFunc::Min: pStrId = STR_FUN_TEXT_MIN; break;
+ case PivotFunc::Product: pStrId = STR_FUN_TEXT_PRODUCT; break;
+ case PivotFunc::CountNum: pStrId = STR_FUN_TEXT_COUNT; break;
+ case PivotFunc::StdDev: pStrId = STR_FUN_TEXT_STDDEV; break;
+ case PivotFunc::StdDevP: pStrId = STR_FUN_TEXT_STDDEV; break;
+ case PivotFunc::StdVar: pStrId = STR_FUN_TEXT_VAR; break;
+ case PivotFunc::StdVarP: pStrId = STR_FUN_TEXT_VAR; break;
+ default:
+ assert(false);
+ break;
+ }
+ if (pStrId)
+ return ScResId(pStrId);
+ else
+ return OUString();
+}
+
+OUString lclCreateDataItemName(const PivotFunc nFunctionMask, std::u16string_view rName, const sal_uInt8 nDuplicationCount)
+{
+ OUString aBuffer = lclGetFunctionMaskName(nFunctionMask) + " - " + rName;
+ if(nDuplicationCount > 0)
+ {
+ aBuffer += " " + OUString::number(nDuplicationCount);
+ }
+ return aBuffer;
+}
+
+} // anonymous namespace
+
+ScPivotLayoutTreeListData::ScPivotLayoutTreeListData(std::unique_ptr<weld::TreeView> xControl)
+ : ScPivotLayoutTreeListBase(std::move(xControl))
+{
+ mxControl->connect_key_press(LINK(this, ScPivotLayoutTreeListData, KeyInputHdl));
+ mxControl->connect_row_activated(LINK(this, ScPivotLayoutTreeListData, DoubleClickHdl));
+}
+
+ScPivotLayoutTreeListData::~ScPivotLayoutTreeListData()
+{
+ if (mpFunctionDlg)
+ {
+ mpFunctionDlg->Response(RET_CANCEL);
+ mpFunctionDlg.clear();
+ }
+}
+
+IMPL_LINK_NOARG(ScPivotLayoutTreeListData, DoubleClickHdl, weld::TreeView&, bool)
+{
+ int nEntry = mxControl->get_cursor_index();
+ if (nEntry == -1)
+ return true;
+
+ ScItemValue* pCurrentItemValue = weld::fromId<ScItemValue*>(mxControl->get_id(nEntry));
+ ScPivotFuncData& rCurrentFunctionData = pCurrentItemValue->maFunctionData;
+
+ SCCOL nCurrentColumn = rCurrentFunctionData.mnCol;
+ ScDPLabelData& rCurrentLabelData = mpParent->GetLabelData(nCurrentColumn);
+
+ ScAbstractDialogFactory* pFactory = ScAbstractDialogFactory::Create();
+
+ mpFunctionDlg = pFactory->CreateScDPFunctionDlg(mxControl.get(), mpParent->GetLabelDataVector(), rCurrentLabelData, rCurrentFunctionData);
+
+ mpFunctionDlg->StartExecuteAsync([this, pCurrentItemValue,
+ rCurrentLabelData, nEntry](int nResult) mutable {
+ if (nResult == RET_OK)
+ {
+ ScPivotFuncData& rFunctionData = pCurrentItemValue->maFunctionData;
+ rFunctionData.mnFuncMask = mpFunctionDlg->GetFuncMask();
+ rCurrentLabelData.mnFuncMask = mpFunctionDlg->GetFuncMask();
+
+ rFunctionData.maFieldRef = mpFunctionDlg->GetFieldRef();
+
+ ScDPLabelData& rDFData = mpParent->GetLabelData(rFunctionData.mnCol);
+
+ AdjustDuplicateCount(pCurrentItemValue);
+
+ OUString sDataItemName = lclCreateDataItemName(
+ rFunctionData.mnFuncMask,
+ rDFData.maName,
+ rFunctionData.mnDupCount);
+
+ mxControl->set_text(nEntry, sDataItemName);
+ }
+
+ mpFunctionDlg->disposeOnce();
+ });
+
+ return true;
+}
+
+void ScPivotLayoutTreeListData::FillDataField(ScPivotFieldVector& rDataFields)
+{
+ mxControl->clear();
+ maDataItemValues.clear();
+
+ for (const ScPivotField& rField : rDataFields)
+ {
+ if (rField.nCol == PIVOT_DATA_FIELD)
+ continue;
+
+ SCCOL nColumn;
+ if (rField.mnOriginalDim >= 0)
+ nColumn = rField.mnOriginalDim;
+ else
+ nColumn = rField.nCol;
+
+ ScItemValue* pOriginalItemValue = mpParent->GetItem(nColumn);
+ ScItemValue* pItemValue = new ScItemValue(pOriginalItemValue->maName, nColumn, rField.nFuncMask);
+
+ pItemValue->mpOriginalItemValue = pOriginalItemValue;
+ pItemValue->maFunctionData.mnOriginalDim = rField.mnOriginalDim;
+ pItemValue->maFunctionData.maFieldRef = rField.maFieldRef;
+
+ AdjustDuplicateCount(pItemValue);
+ OUString sDataItemName = lclCreateDataItemName(pItemValue->maFunctionData.mnFuncMask,
+ pItemValue->maName,
+ pItemValue->maFunctionData.mnDupCount);
+
+ maDataItemValues.push_back(std::unique_ptr<ScItemValue>(pItemValue));
+ OUString sId(weld::toId(pItemValue));
+ mxControl->append(sId, sDataItemName);
+ }
+}
+
+void ScPivotLayoutTreeListData::PushDataFieldNames(std::vector<ScDPName>& rDataFieldNames)
+{
+ std::unique_ptr<weld::TreeIter> xLoopEntry(mxControl->make_iterator());
+ if (!mxControl->get_iter_first(*xLoopEntry))
+ return;
+
+ do
+ {
+ ScItemValue* pEachItemValue = weld::fromId<ScItemValue*>(mxControl->get_id(*xLoopEntry));
+ SCCOL nColumn = pEachItemValue->maFunctionData.mnCol;
+
+ ScDPLabelData& rLabelData = mpParent->GetLabelData(nColumn);
+
+ if (rLabelData.maName.isEmpty())
+ continue;
+
+ OUString sLayoutName = rLabelData.maLayoutName;
+ if (sLayoutName.isEmpty())
+ {
+ sLayoutName = lclCreateDataItemName(
+ pEachItemValue->maFunctionData.mnFuncMask,
+ pEachItemValue->maName,
+ pEachItemValue->maFunctionData.mnDupCount);
+ }
+
+ rDataFieldNames.emplace_back(rLabelData.maName, sLayoutName, rLabelData.mnDupCount);
+ } while (mxControl->iter_next(*xLoopEntry));
+}
+
+void ScPivotLayoutTreeListData::InsertEntryForSourceTarget(weld::TreeView& rSource, int nTarget)
+{
+ if (rSource.count_selected_rows() <=0)
+ return;
+
+ ScItemValue* pItemValue = weld::fromId<ScItemValue*>(rSource.get_selected_id());
+
+ if (mpParent->IsDataElement(pItemValue->maFunctionData.mnCol))
+ return;
+
+ if (&rSource == mxControl.get())
+ {
+ OUString sText = mxControl->get_selected_text();
+ OUString sId(weld::toId(pItemValue));
+ mxControl->remove_id(sId);
+ mxControl->insert(nullptr, nTarget, &sText, &sId, nullptr, nullptr, false, nullptr);
+ }
+ else
+ {
+ InsertEntryForItem(pItemValue->mpOriginalItemValue, nTarget);
+ }
+}
+
+void ScPivotLayoutTreeListData::InsertEntryForItem(ScItemValue* pItemValue, int nPosition)
+{
+ ScItemValue* pDataItemValue = new ScItemValue(pItemValue);
+ pDataItemValue->mpOriginalItemValue = pItemValue;
+ maDataItemValues.push_back(std::unique_ptr<ScItemValue>(pDataItemValue));
+
+ ScPivotFuncData& rFunctionData = pDataItemValue->maFunctionData;
+
+ if (rFunctionData.mnFuncMask == PivotFunc::NONE ||
+ rFunctionData.mnFuncMask == PivotFunc::Auto)
+ {
+ rFunctionData.mnFuncMask = PivotFunc::Sum;
+ }
+
+ AdjustDuplicateCount(pDataItemValue);
+
+ OUString sDataName = lclCreateDataItemName(
+ rFunctionData.mnFuncMask,
+ pDataItemValue->maName,
+ rFunctionData.mnDupCount);
+
+ OUString sId(weld::toId(pDataItemValue));
+ mxControl->insert(nullptr, nPosition, &sDataName, &sId, nullptr, nullptr, false, nullptr);
+}
+
+void ScPivotLayoutTreeListData::AdjustDuplicateCount(ScItemValue* pInputItemValue)
+{
+ ScPivotFuncData& rInputFunctionData = pInputItemValue->maFunctionData;
+
+ bool bFoundDuplicate = false;
+
+ rInputFunctionData.mnDupCount = 0;
+ sal_uInt8 nMaxDuplicateCount = 0;
+
+ std::unique_ptr<weld::TreeIter> xEachEntry(mxControl->make_iterator());
+ if (!mxControl->get_iter_first(*xEachEntry))
+ return;
+ do
+ {
+ ScItemValue* pItemValue = weld::fromId<ScItemValue*>(mxControl->get_id(*xEachEntry));
+ if (pItemValue == pInputItemValue)
+ continue;
+
+ ScPivotFuncData& rFunctionData = pItemValue->maFunctionData;
+
+ if (rFunctionData.mnCol == rInputFunctionData.mnCol &&
+ rFunctionData.mnFuncMask == rInputFunctionData.mnFuncMask)
+ {
+ bFoundDuplicate = true;
+ if(rFunctionData.mnDupCount > nMaxDuplicateCount)
+ nMaxDuplicateCount = rFunctionData.mnDupCount;
+ }
+ } while (mxControl->iter_next(*xEachEntry));
+
+ if(bFoundDuplicate)
+ {
+ rInputFunctionData.mnDupCount = nMaxDuplicateCount + 1;
+ }
+}
+
+IMPL_LINK(ScPivotLayoutTreeListData, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
+{
+ vcl::KeyCode aCode = rKeyEvent.GetKeyCode();
+ sal_uInt16 nCode = aCode.GetCode();
+
+ if (nCode == KEY_DELETE)
+ {
+ int nEntry = mxControl->get_cursor_index();
+ if (nEntry != -1)
+ mxControl->remove(nEntry);
+ return true;
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/PivotLayoutTreeListLabel.cxx b/sc/source/ui/dbgui/PivotLayoutTreeListLabel.cxx
new file mode 100644
index 000000000..e4a2276da
--- /dev/null
+++ b/sc/source/ui/dbgui/PivotLayoutTreeListLabel.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:
+ */
+
+#include <memory>
+#include <PivotLayoutTreeListLabel.hxx>
+#include <PivotLayoutDialog.hxx>
+
+#include <vcl/event.hxx>
+#include <pivot.hxx>
+
+ScPivotLayoutTreeListLabel::ScPivotLayoutTreeListLabel(std::unique_ptr<weld::TreeView> xControl)
+ : ScPivotLayoutTreeListBase(std::move(xControl), LABEL_LIST)
+ , maDataItem(0)
+{
+ mxControl->connect_key_press(LINK(this, ScPivotLayoutTreeListLabel, KeyInputHdl));
+}
+
+ScPivotLayoutTreeListLabel::~ScPivotLayoutTreeListLabel()
+{}
+
+void ScPivotLayoutTreeListLabel::FillLabelFields(ScDPLabelDataVector& rLabelVector)
+{
+ mxControl->clear();
+ maItemValues.clear();
+
+ for (std::unique_ptr<ScDPLabelData> const & pLabelData : rLabelVector)
+ {
+ ScItemValue* pValue = new ScItemValue(pLabelData->maName, pLabelData->mnCol, pLabelData->mnFuncMask);
+ maItemValues.push_back(std::unique_ptr<ScItemValue>(pValue));
+ if (pLabelData->mbDataLayout)
+ {
+ maDataItem = maItemValues.size() - 1;
+ }
+
+ if (pLabelData->mnOriginalDim < 0 && !pLabelData->mbDataLayout)
+ {
+ mxControl->append(weld::toId(pValue), pLabelData->maName);
+ }
+ }
+}
+
+void ScPivotLayoutTreeListLabel::InsertEntryForSourceTarget(weld::TreeView& rSource, int /*nTarget*/)
+{
+ if (&rSource == mxControl.get())
+ return;
+ rSource.remove(rSource.get_selected_index());
+}
+
+bool ScPivotLayoutTreeListLabel::IsDataElement(SCCOL nColumn)
+{
+ return (nColumn == PIVOT_DATA_FIELD || nColumn == maDataItem);
+}
+
+ScItemValue* ScPivotLayoutTreeListLabel::GetItem(SCCOL nColumn)
+{
+ if (nColumn == PIVOT_DATA_FIELD)
+ return maItemValues[maDataItem].get();
+ return maItemValues[nColumn].get();
+}
+
+IMPL_LINK(ScPivotLayoutTreeListLabel, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
+{
+ vcl::KeyCode aCode = rKeyEvent.GetKeyCode();
+ sal_uInt16 nCode = aCode.GetCode();
+
+ if (nCode == KEY_DELETE)
+ {
+ int nEntry = mxControl->get_cursor_index();
+ if (nEntry != -1)
+ mxControl->remove(nEntry);
+ return true;
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/asciiopt.cxx b/sc/source/ui/dbgui/asciiopt.cxx
new file mode 100644
index 000000000..933491efb
--- /dev/null
+++ b/sc/source/ui/dbgui/asciiopt.cxx
@@ -0,0 +1,296 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <global.hxx>
+#include <asciiopt.hxx>
+#include <comphelper/string.hxx>
+#include <osl/thread.h>
+#include <o3tl/string_view.hxx>
+
+constexpr std::u16string_view pStrFix = u"FIX";
+constexpr std::u16string_view pStrMrg = u"MRG";
+
+ScAsciiOptions::ScAsciiOptions() :
+ bFixedLen ( false ),
+ aFieldSeps ( OUString(';') ),
+ bMergeFieldSeps ( false ),
+ bRemoveSpace ( false ),
+ bQuotedFieldAsText(false),
+ bDetectSpecialNumber(false),
+ bEvaluateFormulas(true),
+ bSkipEmptyCells(false),
+ bSaveAsShown(true),
+ bSaveFormulas(false),
+ cTextSep ( cDefaultTextSep ),
+ eCharSet ( osl_getThreadTextEncoding() ),
+ eLang ( LANGUAGE_SYSTEM ),
+ bCharSetSystem ( false ),
+ nStartRow ( 1 )
+{
+}
+
+void ScAsciiOptions::SetColumnInfo( const ScCsvExpDataVec& rDataVec )
+{
+ sal_uInt16 nInfoCount = static_cast< sal_uInt16 >( rDataVec.size() );
+ mvColStart.resize(nInfoCount);
+ mvColFormat.resize(nInfoCount);
+ for( sal_uInt16 nIx = 0; nIx < nInfoCount; ++nIx )
+ {
+ mvColStart[ nIx ] = rDataVec[ nIx ].mnIndex;
+ mvColFormat[ nIx ] = rDataVec[ nIx ].mnType;
+ }
+}
+
+static OUString lcl_decodeSepString( std::u16string_view rSepNums, bool & o_bMergeFieldSeps )
+{
+ if ( rSepNums.empty() )
+ return OUString();
+
+ OUStringBuffer aFieldSeps;
+ sal_Int32 nPos = 0;
+ do
+ {
+ const std::u16string_view aCode = o3tl::getToken(rSepNums, 0, '/', nPos );
+ if ( aCode == pStrMrg )
+ o_bMergeFieldSeps = true;
+ else
+ {
+ sal_Int32 nVal = o3tl::toInt32(aCode);
+ if ( nVal )
+ aFieldSeps.append(sal_Unicode(nVal));
+ }
+ }
+ while ( nPos >= 0 );
+
+ return aFieldSeps.makeStringAndClear();
+}
+
+// The options string must not contain semicolons (because of the pick list),
+// use comma as separator.
+
+void ScAsciiOptions::ReadFromString( std::u16string_view rString )
+{
+ sal_Int32 nPos = rString.empty() ? -1 : 0;
+
+ // Token 0: Field separator.
+ if ( nPos >= 0 )
+ {
+ bFixedLen = bMergeFieldSeps = false;
+
+ const std::u16string_view aToken = o3tl::getToken(rString, 0, ',', nPos);
+ if ( aToken == pStrFix )
+ bFixedLen = true;
+ aFieldSeps = lcl_decodeSepString( aToken, bMergeFieldSeps);
+ }
+
+ // Token 1: Text separator.
+ if ( nPos >= 0 )
+ {
+ const sal_Int32 nVal = o3tl::toInt32(o3tl::getToken(rString, 0, ',', nPos));
+ cTextSep = static_cast<sal_Unicode>(nVal);
+ }
+
+ // Token 2: Text encoding.
+ if ( nPos >= 0 )
+ {
+ eCharSet = ScGlobal::GetCharsetValue( o3tl::getToken(rString, 0, ',', nPos) );
+ }
+
+ // Token 3: Number of start row.
+ if ( nPos >= 0 )
+ {
+ nStartRow = o3tl::toInt32(o3tl::getToken(rString, 0, ',', nPos));
+ }
+
+ // Token 4: Column info.
+ if ( nPos >= 0 )
+ {
+ const std::u16string_view aToken = o3tl::getToken(rString, 0, ',', nPos);
+ const sal_Int32 nInfoCount = comphelper::string::getTokenCount(aToken, '/')/2;
+ mvColStart.resize(nInfoCount);
+ mvColFormat.resize(nInfoCount);
+ sal_Int32 nP = 0;
+ for (sal_Int32 nInfo=0; nInfo<nInfoCount; ++nInfo)
+ {
+ mvColStart[nInfo] = o3tl::toInt32(o3tl::getToken(aToken, 0, '/', nP));
+ mvColFormat[nInfo] = static_cast<sal_uInt8>(o3tl::toInt32(o3tl::getToken(aToken, 0, '/', nP)));
+ }
+ }
+
+ // Token 5: Language.
+ if (nPos >= 0)
+ {
+ eLang = static_cast<LanguageType>(o3tl::toInt32(o3tl::getToken(rString, 0, ',', nPos)));
+ }
+
+ // Token 6: Import quoted field as text.
+ if (nPos >= 0)
+ {
+ bQuotedFieldAsText = o3tl::getToken(rString, 0, ',', nPos) == u"true";
+ }
+
+ // Token 7: Detect special numbers.
+ if (nPos >= 0)
+ {
+ bDetectSpecialNumber = o3tl::getToken(rString, 0, ',', nPos) == u"true";
+ }
+ else
+ bDetectSpecialNumber = true; // default of versions that didn't add the parameter
+
+ // Token 8: used for "Save as shown" in export options
+ if ( nPos >= 0 )
+ {
+ bSaveAsShown = o3tl::getToken(rString, 0, ',', nPos) == u"true";
+ }
+ else
+ bSaveAsShown = true; // default value
+
+ // Token 9: used for "Save cell formulas" in export options
+ if ( nPos >= 0 )
+ {
+ bSaveFormulas = o3tl::getToken(rString, 0, ',', nPos) == u"true";
+ }
+ else
+ bSaveFormulas = false;
+
+ // Token 10: Boolean for Trim spaces.
+ if (nPos >= 0)
+ {
+ bRemoveSpace = o3tl::getToken(rString, 0, ',', nPos) == u"true";
+ }
+ else
+ bRemoveSpace = false;
+
+ // Token 11: sheet to export for --convert-to csv
+ // Does not need to be evaluated here but may be present.
+ if (nPos >= 0)
+ {
+ o3tl::getToken(rString, 0, ',', nPos);
+ }
+
+ // Token 12: evaluate formulas.
+ if (nPos >= 0)
+ {
+ // If present, defaults to "false".
+ bEvaluateFormulas = o3tl::getToken(rString, 0, ',', nPos) == u"true";
+ }
+ else
+ bEvaluateFormulas = true; // default of versions that didn't add the parameter
+}
+
+OUString ScAsciiOptions::WriteToString() const
+{
+ OUStringBuffer aOutStr;
+
+ // Token 0: Field separator.
+ if ( bFixedLen )
+ aOutStr.append(pStrFix);
+ else if ( aFieldSeps.isEmpty() )
+ aOutStr.append("0");
+ else
+ {
+ sal_Int32 nLen = aFieldSeps.getLength();
+ for (sal_Int32 i=0; i<nLen; i++)
+ {
+ if (i)
+ aOutStr.append("/");
+ aOutStr.append(OUString::number(aFieldSeps[i]));
+ }
+ if ( bMergeFieldSeps )
+ {
+ aOutStr.append("/");
+ aOutStr.append(pStrMrg);
+ }
+ }
+
+ // Token 1: Text Quote character.
+ aOutStr.append("," + OUString::number(cTextSep) + ",");
+
+ //Token 2: Text encoding.
+ if ( bCharSetSystem ) // force "SYSTEM"
+ aOutStr.append(ScGlobal::GetCharsetString( RTL_TEXTENCODING_DONTKNOW ));
+ else
+ aOutStr.append(ScGlobal::GetCharsetString( eCharSet ));
+
+ //Token 3: Number of start row.
+ aOutStr.append("," + OUString::number(nStartRow) + ",");
+
+ //Token 4: Column info.
+ for (size_t nInfo=0; nInfo<mvColStart.size(); nInfo++)
+ {
+ if (nInfo)
+ aOutStr.append("/");
+ aOutStr.append(OUString::number(mvColStart[nInfo]) +
+ "/" +
+ OUString::number(mvColFormat[nInfo]));
+ }
+
+ // #i112025# the options string is used in macros and linked sheets,
+ // so new options must be added at the end, to remain compatible
+ // Always keep in sync with ScImportOptions.
+
+ aOutStr.append("," +
+ // Token 5: Language
+ OUString::number(static_cast<sal_uInt16>(eLang)) + "," +
+ // Token 6: Import quoted field as text.
+ OUString::boolean( bQuotedFieldAsText ) + "," +
+ // Token 7: Detect special numbers.
+ OUString::boolean( bDetectSpecialNumber ) + "," +
+ // Token 8: used for "Save as shown" in export options
+ OUString::boolean( bSaveAsShown ) +"," +
+ // Token 9: used for "Save cell formulas" in export options
+ OUString::boolean( bSaveFormulas ) + "," +
+ // Token 10: Trim Space
+ OUString::boolean( bRemoveSpace ) +
+ // Token 11: sheet to export, always 0 for current sheet
+ ",0," +
+ // Token 12: evaluate formulas in import
+ OUString::boolean( bEvaluateFormulas )
+ );
+ return aOutStr.makeStringAndClear();
+}
+
+// static
+sal_Unicode ScAsciiOptions::GetWeightedFieldSep( const OUString & rFieldSeps, bool bDecodeNumbers )
+{
+ bool bMergeFieldSeps = false;
+ OUString aFieldSeps( bDecodeNumbers ? lcl_decodeSepString( rFieldSeps, bMergeFieldSeps) : rFieldSeps);
+ if (aFieldSeps.isEmpty())
+ {
+ return 0;
+ }
+ else if (aFieldSeps.getLength() == 1)
+ return aFieldSeps[0];
+ else
+ {
+ // There can be only one separator for output. See also fdo#53449
+ if (aFieldSeps.indexOf(',') != -1)
+ return ',';
+ else if (aFieldSeps.indexOf('\t') != -1)
+ return '\t';
+ else if (aFieldSeps.indexOf(';') != -1)
+ return ';';
+ else if (aFieldSeps.indexOf(' ') != -1)
+ return ' ';
+ else
+ return aFieldSeps[0];
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/consdlg.cxx b/sc/source/ui/dbgui/consdlg.cxx
new file mode 100644
index 000000000..1dde53c18
--- /dev/null
+++ b/sc/source/ui/dbgui/consdlg.cxx
@@ -0,0 +1,535 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tabvwsh.hxx>
+#include <uiitems.hxx>
+#include <dbdata.hxx>
+#include <rangenam.hxx>
+#include <rangeutl.hxx>
+#include <reffact.hxx>
+#include <document.hxx>
+#include <scresid.hxx>
+
+#include <globstr.hrc>
+#include <strings.hrc>
+
+#include <consdlg.hxx>
+#include <o3tl/safeint.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+namespace
+{
+ void INFOBOX(weld::Window* pWindow, TranslateId id)
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pWindow,
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(id)));
+ xInfoBox->run();
+ }
+}
+
+class ScAreaData
+{
+public:
+ ScAreaData()
+ {
+ }
+
+ void Set( const OUString& rName, const OUString& rArea )
+ {
+ aStrName = rName;
+ aStrArea = rArea;
+ }
+
+ OUString aStrName;
+ OUString aStrArea;
+};
+
+ScConsolidateDlg::ScConsolidateDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ const SfxItemSet& rArgSet)
+
+ : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/consolidatedialog.ui", "ConsolidateDialog")
+ , aStrUndefined ( ScResId( SCSTR_UNDEFINED ) )
+ , theConsData ( static_cast<const ScConsolidateItem&>(
+ rArgSet.Get( rArgSet.GetPool()->
+ GetWhich( SID_CONSOLIDATE ) )
+ ).GetData() )
+ , rViewData ( static_cast<ScTabViewShell*>(SfxViewShell::Current())->
+ GetViewData() )
+ , rDoc ( static_cast<ScTabViewShell*>(SfxViewShell::Current())->
+ GetViewData().GetDocument() )
+ , nAreaDataCount ( 0 )
+ , nWhichCons ( rArgSet.GetPool()->GetWhich( SID_CONSOLIDATE ) )
+ , bDlgLostFocus ( false )
+ , m_xLbFunc(m_xBuilder->weld_combo_box("func"))
+ , m_xLbConsAreas(m_xBuilder->weld_tree_view("consareas"))
+ , m_xLbDataArea(m_xBuilder->weld_combo_box("lbdataarea"))
+ , m_xEdDataArea(new formula::RefEdit(m_xBuilder->weld_entry("eddataarea")))
+ , m_xRbDataArea(new formula::RefButton(m_xBuilder->weld_button("rbdataarea")))
+ , m_xLbDestArea(m_xBuilder->weld_combo_box("lbdestarea"))
+ , m_xEdDestArea(new formula::RefEdit(m_xBuilder->weld_entry("eddestarea")))
+ , m_xRbDestArea(new formula::RefButton(m_xBuilder->weld_button("rbdestarea")))
+ , m_xExpander(m_xBuilder->weld_expander("more"))
+ , m_xBtnByRow(m_xBuilder->weld_check_button("byrow"))
+ , m_xBtnByCol(m_xBuilder->weld_check_button("bycol"))
+ , m_xBtnRefs(m_xBuilder->weld_check_button("refs"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_xBtnAdd(m_xBuilder->weld_button("add"))
+ , m_xBtnRemove(m_xBuilder->weld_button("delete"))
+ , m_xDataFT(m_xBuilder->weld_label("ftdataarea"))
+ , m_xDestFT(m_xBuilder->weld_label("ftdestarea"))
+{
+ m_pRefInputEdit = m_xEdDataArea.get();
+ Init();
+}
+
+ScConsolidateDlg::~ScConsolidateDlg()
+{
+}
+
+void ScConsolidateDlg::Init()
+{
+ OUString aStr;
+ sal_uInt16 i=0;
+
+ m_xRbDataArea->SetReferences(this, m_xEdDataArea.get());
+ m_xEdDataArea->SetReferences(this, m_xDataFT.get());
+ m_xRbDestArea->SetReferences(this, m_xEdDestArea.get());
+ m_xEdDestArea->SetReferences(this, m_xDestFT.get());
+
+ m_xEdDataArea->SetGetFocusHdl( LINK( this, ScConsolidateDlg, GetEditFocusHdl ) );
+ m_xEdDestArea->SetGetFocusHdl( LINK( this, ScConsolidateDlg, GetEditFocusHdl ) );
+ m_xLbDataArea->connect_focus_in( LINK( this, ScConsolidateDlg, GetFocusHdl ) );
+ m_xLbDestArea->connect_focus_in( LINK( this, ScConsolidateDlg, GetFocusHdl ) );
+ m_xEdDataArea->SetModifyHdl( LINK( this, ScConsolidateDlg, ModifyHdl ) );
+ m_xEdDestArea->SetModifyHdl( LINK( this, ScConsolidateDlg, ModifyHdl ) );
+ m_xLbConsAreas->connect_changed( LINK( this, ScConsolidateDlg, SelectTVHdl ) );
+ m_xLbDataArea->connect_changed( LINK( this, ScConsolidateDlg, SelectCBHdl ) );
+ m_xLbDestArea->connect_changed( LINK( this, ScConsolidateDlg, SelectCBHdl ) );
+ m_xBtnOk->connect_clicked( LINK( this, ScConsolidateDlg, OkHdl ) );
+ m_xBtnCancel->connect_clicked( LINK( this, ScConsolidateDlg, ClickHdl ) );
+ m_xBtnAdd->connect_clicked( LINK( this, ScConsolidateDlg, ClickHdl ) );
+ m_xBtnRemove->connect_clicked( LINK( this, ScConsolidateDlg, ClickHdl ) );
+
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(false);
+
+ m_xBtnByRow->set_active( theConsData.bByRow );
+ m_xBtnByCol->set_active( theConsData.bByCol );
+ m_xBtnRefs->set_active( theConsData.bReferenceData );
+
+ m_xLbFunc->set_active( FuncToLbPos( theConsData.eFunction ) );
+
+ m_xLbConsAreas->set_selection_mode(SelectionMode::Multiple);
+ m_xLbConsAreas->set_size_request(m_xLbConsAreas->get_approximate_digit_width() * 16,
+ m_xLbConsAreas->get_height_rows(5));
+
+ // read consolidation areas
+ m_xLbConsAreas->clear();
+ const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
+ for ( i=0; i<theConsData.nDataAreaCount; i++ )
+ {
+ const ScArea& rArea = theConsData.pDataAreas[i];
+ if ( rArea.nTab < rDoc.GetTableCount() )
+ {
+ aStr = ScRange( rArea.nColStart, rArea.nRowStart, rArea.nTab,
+ rArea.nColEnd, rArea.nRowEnd, rArea.nTab ).Format( rDoc,
+ ScRefFlags::RANGE_ABS_3D, eConv );
+ m_xLbConsAreas->append_text(aStr);
+ }
+ }
+
+ if ( theConsData.nTab < rDoc.GetTableCount() )
+ {
+ aStr = ScAddress( theConsData.nCol, theConsData.nRow, theConsData.nTab
+ ).Format( ScRefFlags::ADDR_ABS_3D, &rDoc, eConv );
+ m_xEdDestArea->SetText( aStr );
+ }
+ else
+ m_xEdDestArea->SetText(OUString());
+
+ // Use the ScAreaData helper class to save those range names from the
+ // RangeNames and database ranges that appear in the ListBoxes.
+
+ ScRangeName* pRangeNames = rDoc.GetRangeName();
+ ScDBCollection* pDbNames = rDoc.GetDBCollection();
+ size_t nRangeCount = pRangeNames ? pRangeNames->size() : 0;
+ size_t nDbCount = pDbNames ? pDbNames->getNamedDBs().size() : 0;
+
+ nAreaDataCount = nRangeCount+nDbCount;
+ pAreaData = nullptr;
+
+ if ( nAreaDataCount > 0 )
+ {
+ pAreaData.reset( new ScAreaData[nAreaDataCount] );
+
+ OUString aStrName;
+ sal_uInt16 nAt = 0;
+ ScRange aRange;
+ ScAreaNameIterator aIter( rDoc );
+ while ( aIter.Next( aStrName, aRange ) )
+ {
+ OUString aStrArea(aRange.Format(rDoc, ScRefFlags::ADDR_ABS_3D, eConv));
+ pAreaData[nAt++].Set( aStrName, aStrArea );
+ }
+ }
+
+ FillAreaLists();
+ ModifyHdl( *m_xEdDestArea );
+ m_xLbDataArea->set_active( 0 );
+ m_xEdDataArea->SetText(OUString());
+ m_xEdDataArea->GrabFocus();
+
+ //aFlSep.SetStyle( aFlSep.GetStyle() | WB_VERT );
+
+ //@BugID 54702 enable/disable only in base class
+ //SFX_APPWINDOW->set_sensitive(true);
+}
+
+void ScConsolidateDlg::FillAreaLists()
+{
+ m_xLbDataArea->clear();
+ m_xLbDestArea->clear();
+ m_xLbDataArea->append_text( aStrUndefined );
+ m_xLbDestArea->append_text( aStrUndefined );
+
+ if ( pAreaData && (nAreaDataCount > 0) )
+ {
+ for ( size_t i=0;
+ (i<nAreaDataCount) && (!pAreaData[i].aStrName.isEmpty());
+ i++ )
+ {
+ m_xLbDataArea->append_text(pAreaData[i].aStrName);
+ m_xLbDestArea->append_text(pAreaData[i].aStrName);
+ }
+ }
+}
+
+// Handover of a range within a table that has been selected by the mouse.
+// This range is then shown in the reference window as new selection.
+
+void ScConsolidateDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
+{
+ if ( !m_pRefInputEdit )
+ return;
+
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart( m_pRefInputEdit );
+
+ OUString aStr;
+ ScRefFlags nFmt = ScRefFlags::RANGE_ABS_3D; //!!! nCurTab is still missing
+ const formula::FormulaGrammar::AddressConvention eConv = rDocP.GetAddressConvention();
+
+ if ( rRef.aStart.Tab() != rRef.aEnd.Tab() )
+ nFmt |= ScRefFlags::TAB2_3D;
+
+ if ( m_pRefInputEdit == m_xEdDataArea.get())
+ aStr = rRef.Format(rDocP, nFmt, eConv);
+ else if ( m_pRefInputEdit == m_xEdDestArea.get() )
+ aStr = rRef.aStart.Format(nFmt, &rDocP, eConv);
+
+ m_pRefInputEdit->SetRefString( aStr );
+ ModifyHdl( *m_pRefInputEdit );
+}
+
+void ScConsolidateDlg::Close()
+{
+ DoClose( ScConsolidateDlgWrapper::GetChildWindowId() );
+}
+
+void ScConsolidateDlg::SetActive()
+{
+ if ( bDlgLostFocus )
+ {
+ bDlgLostFocus = false;
+
+ if ( m_pRefInputEdit )
+ {
+ m_pRefInputEdit->GrabFocus();
+ ModifyHdl( *m_pRefInputEdit );
+ }
+ }
+ else
+ m_xDialog->grab_focus();
+
+ RefInputDone();
+}
+
+void ScConsolidateDlg::Deactivate()
+{
+ bDlgLostFocus = true;
+}
+
+bool ScConsolidateDlg::VerifyEdit( formula::RefEdit* pEd )
+{
+ if (pEd != m_xEdDataArea.get() && pEd != m_xEdDestArea.get())
+ return false;
+
+ SCTAB nTab = rViewData.GetTabNo();
+ bool bEditOk = false;
+ OUString theCompleteStr;
+ const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
+
+ if ( pEd == m_xEdDataArea.get() )
+ {
+ bEditOk = ScRangeUtil::IsAbsArea( pEd->GetText(), rDoc,
+ nTab, &theCompleteStr, nullptr, nullptr, eConv );
+ }
+ else if ( pEd == m_xEdDestArea.get() )
+ {
+ OUString aPosStr;
+
+ ScRangeUtil::CutPosString( pEd->GetText(), aPosStr );
+ bEditOk = ScRangeUtil::IsAbsPos( aPosStr, rDoc,
+ nTab, &theCompleteStr, nullptr, eConv );
+ }
+
+ if ( bEditOk )
+ pEd->SetText( theCompleteStr );
+
+ return bEditOk;
+}
+
+// Handler:
+
+IMPL_LINK( ScConsolidateDlg, GetEditFocusHdl, formula::RefEdit&, rControl, void )
+{
+ m_pRefInputEdit = &rControl;
+}
+
+IMPL_LINK( ScConsolidateDlg, GetFocusHdl, weld::Widget&, rControl, void )
+{
+ if (&rControl == m_xLbDataArea.get())
+ m_pRefInputEdit = m_xEdDataArea.get();
+ else if (&rControl == m_xLbDestArea.get())
+ m_pRefInputEdit = m_xEdDestArea.get();
+}
+
+IMPL_LINK_NOARG(ScConsolidateDlg, OkHdl, weld::Button&, void)
+{
+ const sal_Int32 nDataAreaCount = m_xLbConsAreas->n_children();
+
+ if ( nDataAreaCount > 0 )
+ {
+ ScRefAddress aDestAddress;
+ SCTAB nTab = rViewData.GetTabNo();
+ OUString aDestPosStr( m_xEdDestArea->GetText() );
+ const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
+
+ if ( ScRangeUtil::IsAbsPos( aDestPosStr, rDoc, nTab, nullptr, &aDestAddress, eConv ) )
+ {
+ ScConsolidateParam theOutParam( theConsData );
+ std::unique_ptr<ScArea[]> pDataAreas(new ScArea[nDataAreaCount]);
+
+ for ( sal_Int32 i=0; i<nDataAreaCount; ++i )
+ {
+ ScRangeUtil::MakeArea(m_xLbConsAreas->get_text(i),
+ pDataAreas[i], rDoc, nTab, eConv);
+ }
+
+ theOutParam.nCol = aDestAddress.Col();
+ theOutParam.nRow = aDestAddress.Row();
+ theOutParam.nTab = aDestAddress.Tab();
+ theOutParam.eFunction = LbPosToFunc( m_xLbFunc->get_active() );
+ theOutParam.bByCol = m_xBtnByCol->get_active();
+ theOutParam.bByRow = m_xBtnByRow->get_active();
+ theOutParam.bReferenceData = m_xBtnRefs->get_active();
+ theOutParam.SetAreas( std::move(pDataAreas), nDataAreaCount );
+
+ ScConsolidateItem aOutItem( nWhichCons, &theOutParam );
+
+ SetDispatcherLock( false );
+ SwitchToDocument();
+ GetBindings().GetDispatcher()->ExecuteList(SID_CONSOLIDATE,
+ SfxCallMode::SLOT | SfxCallMode::RECORD,
+ { &aOutItem });
+ response(RET_OK);
+ }
+ else
+ {
+ INFOBOX(m_xDialog.get(), STR_INVALID_TABREF);
+ m_xEdDestArea->GrabFocus();
+ }
+ }
+ else
+ response(RET_CANCEL); // no area defined -> Cancel
+}
+
+IMPL_LINK( ScConsolidateDlg, ClickHdl, weld::Button&, rBtn, void )
+{
+ if ( &rBtn == m_xBtnCancel.get() )
+ response(RET_CANCEL);
+ else if ( &rBtn == m_xBtnAdd.get() )
+ {
+ if ( !m_xEdDataArea->GetText().isEmpty() )
+ {
+ OUString aNewEntry( m_xEdDataArea->GetText() );
+ std::unique_ptr<ScArea[]> ppAreas;
+ sal_uInt16 nAreaCount = 0;
+ const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
+
+ if ( ScRangeUtil::IsAbsTabArea( aNewEntry, &rDoc, &ppAreas, &nAreaCount, true, eConv ) )
+ {
+ // IsAbsTabArea() creates an array of ScArea pointers,
+ // which have been created dynamically as well.
+ // These objects need to be deleted here.
+
+ for ( sal_uInt16 i=0; i<nAreaCount; i++ )
+ {
+ const ScArea& rArea = ppAreas[i];
+ OUString aNewArea = ScRange( rArea.nColStart, rArea.nRowStart, rArea.nTab,
+ rArea.nColEnd, rArea.nRowEnd, rArea.nTab
+ ).Format(rDoc, ScRefFlags::RANGE_ABS_3D, eConv);
+
+ if (m_xLbConsAreas->find_text(aNewArea) == -1)
+ {
+ m_xLbConsAreas->append_text( aNewArea );
+ }
+ }
+ }
+ else if ( VerifyEdit( m_xEdDataArea.get() ) )
+ {
+ OUString aNewArea( m_xEdDataArea->GetText() );
+
+ if (m_xLbConsAreas->find_text(aNewArea) == -1)
+ m_xLbConsAreas->append_text(aNewArea);
+ else
+ INFOBOX(m_xDialog.get(), STR_AREA_ALREADY_INSERTED);
+ }
+ else
+ {
+ INFOBOX(m_xDialog.get(), STR_INVALID_TABREF);
+ m_xEdDataArea->GrabFocus();
+ }
+ }
+ }
+ else if ( &rBtn == m_xBtnRemove.get() )
+ {
+ std::vector<int> aSelectedRows(m_xLbConsAreas->get_selected_rows());
+ std::sort(aSelectedRows.begin(), aSelectedRows.end());
+ for (auto it = aSelectedRows.rbegin(); it != aSelectedRows.rend(); ++it)
+ m_xLbConsAreas->remove(*it);
+ m_xBtnRemove->set_sensitive(false);
+ }
+}
+
+IMPL_LINK( ScConsolidateDlg, SelectTVHdl, weld::TreeView&, rLb, void )
+{
+ if (rLb.get_selected_index() != -1)
+ m_xBtnRemove->set_sensitive(true);
+ else
+ m_xBtnRemove->set_sensitive(false);
+}
+
+IMPL_LINK( ScConsolidateDlg, SelectCBHdl, weld::ComboBox&, rLb, void )
+{
+ formula::RefEdit* pEd = (&rLb == m_xLbDataArea.get()) ? m_xEdDataArea.get() : m_xEdDestArea.get();
+ const sal_Int32 nSelPos = rLb.get_active();
+
+ if ( (nSelPos > 0)
+ && (nAreaDataCount > 0)
+ && (pAreaData != nullptr) )
+ {
+ if ( o3tl::make_unsigned(nSelPos) <= nAreaDataCount )
+ {
+ OUString aString( pAreaData[nSelPos-1].aStrArea );
+
+ if ( &rLb == m_xLbDestArea.get() )
+ ScRangeUtil::CutPosString( aString, aString );
+
+ pEd->SetText( aString );
+
+ if ( pEd == m_xEdDataArea.get() )
+ m_xBtnAdd->set_sensitive(true);
+ }
+ }
+ else
+ {
+ pEd->SetText( OUString() );
+ if ( pEd == m_xEdDataArea.get() )
+ m_xBtnAdd->set_sensitive(true);
+ }
+}
+
+IMPL_LINK( ScConsolidateDlg, ModifyHdl, formula::RefEdit&, rEd, void )
+{
+ if ( &rEd == m_xEdDataArea.get() )
+ {
+ OUString aAreaStr( rEd.GetText() );
+ if ( !aAreaStr.isEmpty() )
+ m_xBtnAdd->set_sensitive(true);
+ else
+ m_xBtnAdd->set_sensitive(false);
+ }
+ else if ( &rEd == m_xEdDestArea.get() )
+ {
+ m_xLbDestArea->set_active(0);
+ }
+}
+
+// TODO: generalize!
+// Resource of the ListBox and these two conversion methods are also in
+// tpsubt and everywhere, where StarCalc functions are selectable.
+
+ScSubTotalFunc ScConsolidateDlg::LbPosToFunc( sal_Int32 nPos )
+{
+ switch ( nPos )
+ {
+ case 2: return SUBTOTAL_FUNC_AVE;
+ case 6: return SUBTOTAL_FUNC_CNT;
+ case 1: return SUBTOTAL_FUNC_CNT2;
+ case 3: return SUBTOTAL_FUNC_MAX;
+ case 4: return SUBTOTAL_FUNC_MIN;
+ case 5: return SUBTOTAL_FUNC_PROD;
+ case 7: return SUBTOTAL_FUNC_STD;
+ case 8: return SUBTOTAL_FUNC_STDP;
+ case 9: return SUBTOTAL_FUNC_VAR;
+ case 10: return SUBTOTAL_FUNC_VARP;
+ case 0:
+ default:
+ return SUBTOTAL_FUNC_SUM;
+ }
+}
+
+sal_Int32 ScConsolidateDlg::FuncToLbPos( ScSubTotalFunc eFunc )
+{
+ switch ( eFunc )
+ {
+ case SUBTOTAL_FUNC_AVE: return 2;
+ case SUBTOTAL_FUNC_CNT: return 6;
+ case SUBTOTAL_FUNC_CNT2: return 1;
+ case SUBTOTAL_FUNC_MAX: return 3;
+ case SUBTOTAL_FUNC_MIN: return 4;
+ case SUBTOTAL_FUNC_PROD: return 5;
+ case SUBTOTAL_FUNC_STD: return 7;
+ case SUBTOTAL_FUNC_STDP: return 8;
+ case SUBTOTAL_FUNC_VAR: return 9;
+ case SUBTOTAL_FUNC_VARP: return 10;
+ case SUBTOTAL_FUNC_NONE:
+ case SUBTOTAL_FUNC_SUM:
+ default:
+ return 0;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/csvcontrol.cxx b/sc/source/ui/dbgui/csvcontrol.cxx
new file mode 100644
index 000000000..409e898b4
--- /dev/null
+++ b/sc/source/ui/dbgui/csvcontrol.cxx
@@ -0,0 +1,284 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <csvcontrol.hxx>
+#include <vcl/keycodes.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+
+ScCsvLayoutData::ScCsvLayoutData() :
+ mnPosCount( 1 ),
+ mnPosOffset( 0 ),
+ mnWinWidth( 1 ),
+ mnHdrWidth( 0 ),
+ mnCharWidth( 1 ),
+ mnLineCount( 1 ),
+ mnLineOffset( 0 ),
+ mnWinHeight( 1 ),
+ mnHdrHeight( 0 ),
+ mnLineHeight( 1 ),
+ mnPosCursor( CSV_POS_INVALID ),
+ mnColCursor( 0 ),
+ mnNoRepaint( 0 ),
+ mbAppRTL( AllSettings::GetLayoutRTL() )
+{
+}
+
+ScCsvDiff ScCsvLayoutData::GetDiff( const ScCsvLayoutData& rData ) const
+{
+ ScCsvDiff nRet = ScCsvDiff::Equal;
+ if( mnPosCount != rData.mnPosCount ) nRet |= ScCsvDiff::PosCount;
+ if( mnPosOffset != rData.mnPosOffset ) nRet |= ScCsvDiff::PosOffset;
+ if( mnHdrWidth != rData.mnHdrWidth ) nRet |= ScCsvDiff::HeaderWidth;
+ if( mnCharWidth != rData.mnCharWidth ) nRet |= ScCsvDiff::CharWidth;
+ if( mnLineCount != rData.mnLineCount ) nRet |= ScCsvDiff::LineCount;
+ if( mnLineOffset != rData.mnLineOffset ) nRet |= ScCsvDiff::LineOffset;
+ if( mnHdrHeight != rData.mnHdrHeight ) nRet |= ScCsvDiff::HeaderHeight;
+ if( mnLineHeight != rData.mnLineHeight ) nRet |= ScCsvDiff::LineHeight;
+ if( mnPosCursor != rData.mnPosCursor ) nRet |= ScCsvDiff::RulerCursor;
+ if( mnColCursor != rData.mnColCursor ) nRet |= ScCsvDiff::GridCursor;
+ return nRet;
+}
+
+ScCsvControl::ScCsvControl(const ScCsvLayoutData& rData)
+ : mrData(rData)
+ , mbValidGfx(false)
+{
+}
+
+ScCsvControl::~ScCsvControl()
+{
+ if( mxAccessible.is() )
+ mxAccessible->dispose();
+ mxAccessible = nullptr; // lp#1566050: prevent cyclic reference zombies
+}
+
+// event handling -------------------------------------------------------------
+
+void ScCsvControl::GetFocus()
+{
+ weld::CustomWidgetController::GetFocus();
+ AccSendFocusEvent( true );
+}
+
+void ScCsvControl::LoseFocus()
+{
+ weld::CustomWidgetController::LoseFocus();
+ AccSendFocusEvent( false );
+}
+
+void ScCsvControl::AccSendFocusEvent( bool bFocused )
+{
+ if( mxAccessible.is() )
+ mxAccessible->SendFocusEvent( bFocused );
+}
+
+void ScCsvControl::AccSendCaretEvent()
+{
+ if( mxAccessible.is() )
+ mxAccessible->SendCaretEvent();
+}
+
+void ScCsvControl::AccSendVisibleEvent()
+{
+ if( mxAccessible.is() )
+ mxAccessible->SendVisibleEvent();
+}
+
+void ScCsvControl::AccSendSelectionEvent()
+{
+ if( mxAccessible.is() )
+ mxAccessible->SendSelectionEvent();
+}
+
+void ScCsvControl::AccSendTableUpdateEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn, bool bAllRows )
+{
+ if( mxAccessible.is() )
+ mxAccessible->SendTableUpdateEvent( nFirstColumn, nLastColumn, bAllRows );
+}
+
+void ScCsvControl::AccSendInsertColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn )
+{
+ if( mxAccessible.is() )
+ mxAccessible->SendInsertColumnEvent( nFirstColumn, nLastColumn );
+}
+
+void ScCsvControl::AccSendRemoveColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn )
+{
+ if( mxAccessible.is() )
+ mxAccessible->SendRemoveColumnEvent( nFirstColumn, nLastColumn );
+}
+
+// repaint helpers ------------------------------------------------------------
+
+void ScCsvControl::Repaint( bool bInvalidate )
+{
+ if( bInvalidate )
+ InvalidateGfx();
+ if( !IsNoRepaint() )
+ Execute( CSVCMD_REPAINT );
+}
+
+void ScCsvControl::DisableRepaint()
+{
+ ++mrData.mnNoRepaint;
+}
+
+void ScCsvControl::EnableRepaint()
+{
+ OSL_ENSURE( IsNoRepaint(), "ScCsvControl::EnableRepaint - invalid call" );
+ --mrData.mnNoRepaint;
+ Repaint();
+}
+
+// command handling -----------------------------------------------------------
+
+void ScCsvControl::Execute( ScCsvCmdType eType, sal_Int32 nParam1, sal_Int32 nParam2 )
+{
+ maCmd.Set( eType, nParam1, nParam2 );
+ maCmdHdl.Call( *this );
+}
+
+// layout helpers -------------------------------------------------------------
+
+sal_Int32 ScCsvControl::GetVisPosCount() const
+{
+ return (mrData.mnWinWidth - GetHdrWidth()) / GetCharWidth();
+}
+
+sal_Int32 ScCsvControl::GetMaxPosOffset() const
+{
+ return std::max<sal_Int32>( GetPosCount() - GetVisPosCount() + 2, 0 );
+}
+
+bool ScCsvControl::IsValidSplitPos( sal_Int32 nPos ) const
+{
+ return (0 < nPos) && (nPos < GetPosCount() );
+}
+
+bool ScCsvControl::IsVisibleSplitPos( sal_Int32 nPos ) const
+{
+ return IsValidSplitPos( nPos ) && (GetFirstVisPos() <= nPos) && (nPos <= GetLastVisPos());
+}
+
+sal_Int32 ScCsvControl::GetHdrX() const
+{
+ return IsRTL() ? (mrData.mnWinWidth - GetHdrWidth()) : 0;
+}
+
+sal_Int32 ScCsvControl::GetFirstX() const
+{
+ return IsRTL() ? 0 : GetHdrWidth();
+}
+
+sal_Int32 ScCsvControl::GetLastX() const
+{
+ return mrData.mnWinWidth - (IsRTL() ? GetHdrWidth() : 0) - 1;
+}
+
+sal_Int32 ScCsvControl::GetX( sal_Int32 nPos ) const
+{
+ return GetFirstX() + (nPos - GetFirstVisPos()) * GetCharWidth();
+}
+
+sal_Int32 ScCsvControl::GetPosFromX( sal_Int32 nX ) const
+{
+ return (nX - GetFirstX() + GetCharWidth() / 2) / GetCharWidth() + GetFirstVisPos();
+}
+
+sal_Int32 ScCsvControl::GetVisLineCount() const
+{
+ return (mrData.mnWinHeight - GetHdrHeight() - 2) / GetLineHeight() + 1;
+}
+
+sal_Int32 ScCsvControl::GetLastVisLine() const
+{
+ return std::min( GetFirstVisLine() + GetVisLineCount(), GetLineCount() ) - 1;
+}
+
+sal_Int32 ScCsvControl::GetMaxLineOffset() const
+{
+ return std::max<sal_Int32>( GetLineCount() - GetVisLineCount() + 1, 0 );
+}
+
+bool ScCsvControl::IsValidLine( sal_Int32 nLine ) const
+{
+ return (0 <= nLine) && (nLine < GetLineCount());
+}
+
+bool ScCsvControl::IsVisibleLine( sal_Int32 nLine ) const
+{
+ return IsValidLine( nLine ) && (GetFirstVisLine() <= nLine) && (nLine <= GetLastVisLine());
+}
+
+sal_Int32 ScCsvControl::GetY( sal_Int32 nLine ) const
+{
+ return GetHdrHeight() + (nLine - GetFirstVisLine()) * GetLineHeight();
+}
+
+sal_Int32 ScCsvControl::GetLineFromY( sal_Int32 nY ) const
+{
+ return (nY - GetHdrHeight()) / GetLineHeight() + GetFirstVisLine();
+}
+
+// static helpers -------------------------------------------------------------
+
+void ScCsvControl::ImplInvertRect( OutputDevice& rOutDev, const tools::Rectangle& rRect )
+{
+ rOutDev.Push( vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR | vcl::PushFlags::RASTEROP );
+ rOutDev.SetLineColor( COL_BLACK );
+ rOutDev.SetFillColor( COL_BLACK );
+ rOutDev.SetRasterOp( RasterOp::Invert );
+ rOutDev.DrawRect( rRect );
+ rOutDev.Pop();
+}
+
+ScMoveMode ScCsvControl::GetHorzDirection( sal_uInt16 nCode, bool bHomeEnd )
+{
+ switch( nCode )
+ {
+ case KEY_LEFT: return MOVE_PREV;
+ case KEY_RIGHT: return MOVE_NEXT;
+ }
+ if( bHomeEnd ) switch( nCode )
+ {
+ case KEY_HOME: return MOVE_FIRST;
+ case KEY_END: return MOVE_LAST;
+ }
+ return MOVE_NONE;
+}
+
+ScMoveMode ScCsvControl::GetVertDirection( sal_uInt16 nCode, bool bHomeEnd )
+{
+ switch( nCode )
+ {
+ case KEY_UP: return MOVE_PREV;
+ case KEY_DOWN: return MOVE_NEXT;
+ case KEY_PAGEUP: return MOVE_PREVPAGE;
+ case KEY_PAGEDOWN: return MOVE_NEXTPAGE;
+ }
+ if( bHomeEnd ) switch( nCode )
+ {
+ case KEY_HOME: return MOVE_FIRST;
+ case KEY_END: return MOVE_LAST;
+ }
+ return MOVE_NONE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/csvgrid.cxx b/sc/source/ui/dbgui/csvgrid.cxx
new file mode 100644
index 000000000..6752fcb78
--- /dev/null
+++ b/sc/source/ui/dbgui/csvgrid.cxx
@@ -0,0 +1,1418 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <csvgrid.hxx>
+#include <csvtablebox.hxx>
+
+#include <algorithm>
+#include <memory>
+
+#include <svtools/colorcfg.hxx>
+#include <sal/macros.h>
+#include <tools/poly.hxx>
+#include <scmod.hxx>
+#include <asciiopt.hxx>
+#include <impex.hxx>
+#include <AccessibleCsvControl.hxx>
+
+// *** edit engine ***
+#include <editeng/eeitem.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weldutils.hxx>
+
+#include <editeng/colritem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/langitem.hxx>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <editutil.hxx>
+// *** edit engine ***
+
+namespace {
+
+struct Func_SetType
+{
+ sal_Int32 mnType;
+ explicit Func_SetType( sal_Int32 nType ) : mnType( nType ) {}
+ void operator()( ScCsvColState& rState ) const
+ { rState.mnType = mnType; }
+};
+
+struct Func_Select
+{
+ bool mbSelect;
+ explicit Func_Select( bool bSelect ) : mbSelect( bSelect ) {}
+ void operator()( ScCsvColState& rState ) const
+ { rState.Select( mbSelect ); }
+};
+
+}
+
+ScCsvGrid::ScCsvGrid(const ScCsvLayoutData& rData, std::unique_ptr<weld::Menu> xPopup, ScCsvTableBox* pTableBox)
+ : ScCsvControl(rData)
+ , mpTableBox(pTableBox)
+ , mpBackgrDev( VclPtr<VirtualDevice>::Create() )
+ , mpGridDev( VclPtr<VirtualDevice>::Create() )
+ , mxPopup(std::move(xPopup))
+ , mpColorConfig( nullptr )
+ , mpEditEngine( new ScEditEngineDefaulter( EditEngine::CreatePool().get(), true ) )
+ , maColStates( 1 )
+ , maTypeNames( 1 )
+ , mnFirstImpLine( 0 )
+ , mnRecentSelCol( CSV_COLUMN_INVALID )
+ , mnMTCurrCol( SAL_MAX_UINT32 )
+ , mbTracking( false )
+ , mbMTSelecting( false )
+{
+ mpEditEngine->SetRefDevice( mpBackgrDev.get() );
+ mpEditEngine->SetRefMapMode( MapMode( MapUnit::MapPixel ) );
+ maEdEngSize = mpEditEngine->GetPaperSize();
+}
+
+void ScCsvGrid::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ OutputDevice& rRefDevice = pDrawingArea->get_ref_device();
+ maHeaderFont = Application::GetSettings().GetStyleSettings().GetAppFont();
+
+ // expand the point size of the desired font to the equivalent pixel size
+ weld::SetPointFont(rRefDevice, maHeaderFont);
+ maHeaderFont = rRefDevice.GetFont();
+
+ // Because this is an always LeftToRight layout widget the initial size of
+ // this widget needs to be smaller than the size of the parent scrolling
+ // window (ScCsvTableBox ctor) because in RTL mode the alignment is against
+ // the right edge of the parent, and if larger than the scrolling window
+ // the left edge will be lost. If this widget is smaller than the scrolling
+ // window it is stretched to fit the parent and the problem doesn't arise.
+ Size aInitialSize(10, 10);
+ ScCsvControl::SetDrawingArea(pDrawingArea);
+ pDrawingArea->set_size_request(aInitialSize.Width(), aInitialSize.Height());
+ SetOutputSizePixel(aInitialSize);
+
+ EnableRTL( false ); // RTL
+
+ InitFonts();
+ ImplClearSplits();
+}
+
+ScCsvGrid::~ScCsvGrid()
+{
+ OSL_ENSURE(mpColorConfig, "the object hasn't been initialized properly");
+ if (mpColorConfig)
+ mpColorConfig->RemoveListener(this);
+ mpBackgrDev.disposeAndClear();
+ mpGridDev.disposeAndClear();
+}
+
+void
+ScCsvGrid::Init()
+{
+ OSL_PRECOND(!mpColorConfig, "the object has already been initialized");
+ mpColorConfig = &SC_MOD()->GetColorConfig();
+ InitColors();
+ mpColorConfig->AddListener(this);
+}
+
+// common grid handling -------------------------------------------------------
+
+void ScCsvGrid::UpdateLayoutData()
+{
+ DisableRepaint();
+ OutputDevice& rRefDevice = GetDrawingArea()->get_ref_device();
+ rRefDevice.SetFont(maMonoFont);
+ Execute(CSVCMD_SETCHARWIDTH, rRefDevice.GetTextWidth(OUString('X')));
+ Execute(CSVCMD_SETLINEHEIGHT, rRefDevice.GetTextHeight() + 1);
+ rRefDevice.SetFont(maHeaderFont);
+ Execute(CSVCMD_SETHDRHEIGHT, rRefDevice.GetTextHeight() + 1);
+ UpdateOffsetX();
+ EnableRepaint();
+}
+
+void ScCsvGrid::UpdateOffsetX()
+{
+ sal_Int32 nLastLine = GetLastVisLine() + 1;
+ sal_Int32 nDigits = 2;
+ for (;;)
+ {
+ nLastLine /= 10;
+ if (!nLastLine)
+ break;
+ ++nDigits;
+ }
+ nDigits = std::max( nDigits, sal_Int32( 3 ) );
+ Execute(CSVCMD_SETHDRWIDTH, GetDrawingArea()->get_approximate_digit_width() * nDigits);
+}
+
+void ScCsvGrid::ApplyLayout( const ScCsvLayoutData& rOldData )
+{
+ ScCsvDiff nDiff = GetLayoutData().GetDiff( rOldData );
+ if( nDiff == ScCsvDiff::Equal ) return;
+
+ DisableRepaint();
+
+ if( nDiff & ScCsvDiff::RulerCursor )
+ {
+ ImplInvertCursor( rOldData.mnPosCursor );
+ ImplInvertCursor( GetRulerCursorPos() );
+ }
+
+ if( nDiff & ScCsvDiff::PosCount )
+ {
+ if( GetPosCount() < rOldData.mnPosCount )
+ {
+ SelectAll( false );
+ maSplits.RemoveRange( GetPosCount(), rOldData.mnPosCount );
+ }
+ else
+ maSplits.Remove( rOldData.mnPosCount );
+ maSplits.Insert( GetPosCount() );
+ maColStates.resize( maSplits.Count() - 1 );
+ }
+
+ if( nDiff & ScCsvDiff::LineOffset )
+ {
+ Execute( CSVCMD_UPDATECELLTEXTS );
+ UpdateOffsetX();
+ }
+
+ ScCsvDiff nHVDiff = nDiff & (ScCsvDiff::HorizontalMask | ScCsvDiff::VerticalMask);
+ if( nHVDiff == ScCsvDiff::PosOffset )
+ ImplDrawHorzScrolled( rOldData.mnPosOffset );
+ else if( nHVDiff != ScCsvDiff::Equal )
+ InvalidateGfx();
+
+ EnableRepaint();
+
+ if( nDiff & (ScCsvDiff::PosOffset | ScCsvDiff::LineOffset) )
+ AccSendVisibleEvent();
+}
+
+void ScCsvGrid::SetFirstImportedLine( sal_Int32 nLine )
+{
+ ImplDrawFirstLineSep( false );
+ mnFirstImpLine = nLine;
+ ImplDrawFirstLineSep( true );
+ ImplDrawGridDev();
+ Repaint();
+}
+
+sal_Int32 ScCsvGrid::GetNoScrollCol( sal_Int32 nPos ) const
+{
+ sal_Int32 nNewPos = nPos;
+ if( nNewPos != CSV_POS_INVALID )
+ {
+ if( nNewPos < GetFirstVisPos() + CSV_SCROLL_DIST )
+ {
+ sal_Int32 nScroll = (GetFirstVisPos() > 0) ? CSV_SCROLL_DIST : 0;
+ nNewPos = GetFirstVisPos() + nScroll;
+ }
+ else if( nNewPos > GetLastVisPos() - CSV_SCROLL_DIST - 1 )
+ {
+ sal_Int32 nScroll = (GetFirstVisPos() < GetMaxPosOffset()) ? CSV_SCROLL_DIST : 0;
+ nNewPos = GetLastVisPos() - nScroll - 1;
+ }
+ }
+ return nNewPos;
+}
+
+void ScCsvGrid::InitColors()
+{
+ OSL_PRECOND(mpColorConfig, "the object hasn't been initialized properly");
+ if ( !mpColorConfig )
+ return;
+ maBackColor = mpColorConfig->GetColorValue( ::svtools::DOCCOLOR ).nColor;
+ maGridColor = mpColorConfig->GetColorValue( ::svtools::CALCGRID ).nColor;
+ maGridPBColor = mpColorConfig->GetColorValue( ::svtools::CALCPAGEBREAK ).nColor;
+ maAppBackColor = mpColorConfig->GetColorValue( ::svtools::APPBACKGROUND ).nColor;
+ maTextColor = mpColorConfig->GetColorValue( ::svtools::FONTCOLOR ).nColor;
+
+ const StyleSettings& rSett = Application::GetSettings().GetStyleSettings();
+ maHeaderBackColor = rSett.GetFaceColor();
+ maHeaderGridColor = rSett.GetDarkShadowColor();
+ maHeaderTextColor = rSett.GetButtonTextColor();
+ maSelectColor = rSett.GetActiveColor();
+
+ InvalidateGfx();
+}
+
+void ScCsvGrid::InitFonts()
+{
+ maMonoFont = OutputDevice::GetDefaultFont( DefaultFontType::FIXED, LANGUAGE_ENGLISH_US, GetDefaultFontFlags::NONE );
+ maMonoFont.SetFontSize( Size( maMonoFont.GetFontSize().Width(), maHeaderFont.GetFontSize().Height() ) );
+
+ /* *** Set edit engine defaults ***
+ maMonoFont for Latin script, smaller default font for Asian and Complex script. */
+
+ // get default fonts
+ SvxFontItem aLatinItem( EE_CHAR_FONTINFO );
+ SvxFontItem aAsianItem( EE_CHAR_FONTINFO_CJK );
+ SvxFontItem aComplexItem( EE_CHAR_FONTINFO_CTL );
+ ::GetDefaultFonts( aLatinItem, aAsianItem, aComplexItem );
+
+ // create item set for defaults
+ SfxItemSet aDefSet( mpEditEngine->GetEmptyItemSet() );
+ EditEngine::SetFontInfoInItemSet( aDefSet, maMonoFont );
+ aDefSet.Put( aAsianItem );
+ aDefSet.Put( aComplexItem );
+
+ // set Asian/Complex font size to height of character in Latin font
+ sal_uLong nFontHt = static_cast< sal_uLong >( maMonoFont.GetFontSize().Height() );
+ aDefSet.Put( SvxFontHeightItem( nFontHt, 100, EE_CHAR_FONTHEIGHT_CJK ) );
+ aDefSet.Put( SvxFontHeightItem( nFontHt, 100, EE_CHAR_FONTHEIGHT_CTL ) );
+
+ // copy other items from default font
+ const SfxPoolItem& rWeightItem = aDefSet.Get( EE_CHAR_WEIGHT );
+ std::unique_ptr<SfxPoolItem> pNewItem(rWeightItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_WEIGHT_CJK);
+ aDefSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_WEIGHT_CTL);
+ aDefSet.Put( *pNewItem );
+ const SfxPoolItem& rItalicItem = aDefSet.Get( EE_CHAR_ITALIC );
+ pNewItem.reset(rItalicItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_ITALIC_CJK);
+ aDefSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_ITALIC_CTL);
+ aDefSet.Put( *pNewItem );
+ const SfxPoolItem& rLangItem = aDefSet.Get( EE_CHAR_LANGUAGE );
+ pNewItem.reset(rLangItem.Clone());
+ pNewItem->SetWhich(EE_CHAR_LANGUAGE_CJK);
+ aDefSet.Put( *pNewItem );
+ pNewItem->SetWhich(EE_CHAR_LANGUAGE_CTL);
+ aDefSet.Put( *pNewItem );
+
+ mpEditEngine->SetDefaults( aDefSet );
+ InvalidateGfx();
+}
+
+void ScCsvGrid::InitSizeData()
+{
+ maWinSize = GetOutputSizePixel();
+ mpBackgrDev->SetOutputSizePixel( maWinSize );
+ mpGridDev->SetOutputSizePixel( maWinSize );
+ InvalidateGfx();
+}
+
+// split handling -------------------------------------------------------------
+
+void ScCsvGrid::InsertSplit( sal_Int32 nPos )
+{
+ if( ImplInsertSplit( nPos ) )
+ {
+ DisableRepaint();
+ Execute( CSVCMD_EXPORTCOLUMNTYPE );
+ Execute( CSVCMD_UPDATECELLTEXTS );
+ sal_uInt32 nColIx = GetColumnFromPos( nPos );
+ ImplDrawColumn( nColIx - 1 );
+ ImplDrawColumn( nColIx );
+ ValidateGfx(); // performance: do not redraw all columns
+ EnableRepaint();
+ }
+}
+
+void ScCsvGrid::RemoveSplit( sal_Int32 nPos )
+{
+ if( ImplRemoveSplit( nPos ) )
+ {
+ DisableRepaint();
+ Execute( CSVCMD_EXPORTCOLUMNTYPE );
+ Execute( CSVCMD_UPDATECELLTEXTS );
+ ImplDrawColumn( GetColumnFromPos( nPos ) );
+ ValidateGfx(); // performance: do not redraw all columns
+ EnableRepaint();
+ }
+}
+
+void ScCsvGrid::MoveSplit( sal_Int32 nPos, sal_Int32 nNewPos )
+{
+ sal_uInt32 nColIx = GetColumnFromPos( nPos );
+ if( nColIx == CSV_COLUMN_INVALID )
+ return;
+
+ DisableRepaint();
+ if( (GetColumnPos( nColIx - 1 ) < nNewPos) && (nNewPos < GetColumnPos( nColIx + 1 )) )
+ {
+ // move a split in the range between 2 others -> keep selection state of both columns
+ maSplits.Remove( nPos );
+ maSplits.Insert( nNewPos );
+ Execute( CSVCMD_UPDATECELLTEXTS );
+ ImplDrawColumn( nColIx - 1 );
+ ImplDrawColumn( nColIx );
+ ValidateGfx(); // performance: do not redraw all columns
+ AccSendTableUpdateEvent( nColIx - 1, nColIx );
+ }
+ else
+ {
+ ImplRemoveSplit( nPos );
+ ImplInsertSplit( nNewPos );
+ Execute( CSVCMD_EXPORTCOLUMNTYPE );
+ Execute( CSVCMD_UPDATECELLTEXTS );
+ }
+ EnableRepaint();
+}
+
+void ScCsvGrid::RemoveAllSplits()
+{
+ DisableRepaint();
+ ImplClearSplits();
+ Execute( CSVCMD_EXPORTCOLUMNTYPE );
+ Execute( CSVCMD_UPDATECELLTEXTS );
+ EnableRepaint();
+}
+
+void ScCsvGrid::SetSplits( const ScCsvSplits& rSplits )
+{
+ DisableRepaint();
+ ImplClearSplits();
+ sal_uInt32 nCount = rSplits.Count();
+ for( sal_uInt32 nIx = 0; nIx < nCount; ++nIx )
+ maSplits.Insert( rSplits[ nIx ] );
+ maColStates.clear();
+ maColStates.resize( maSplits.Count() - 1 );
+ Execute( CSVCMD_EXPORTCOLUMNTYPE );
+ Execute( CSVCMD_UPDATECELLTEXTS );
+ EnableRepaint();
+}
+
+bool ScCsvGrid::ImplInsertSplit( sal_Int32 nPos )
+{
+ sal_uInt32 nColIx = GetColumnFromPos( nPos );
+ bool bRet = (nColIx < GetColumnCount()) && maSplits.Insert( nPos );
+ if( bRet )
+ {
+ ScCsvColState aState( GetColumnType( nColIx ) );
+ aState.Select( IsSelected( nColIx ) && IsSelected( nColIx + 1 ) );
+ maColStates.insert( maColStates.begin() + nColIx + 1, aState );
+ AccSendInsertColumnEvent( nColIx + 1, nColIx + 1 );
+ AccSendTableUpdateEvent( nColIx, nColIx );
+ }
+ return bRet;
+}
+
+bool ScCsvGrid::ImplRemoveSplit( sal_Int32 nPos )
+{
+ bool bRet = maSplits.Remove( nPos );
+ if( bRet )
+ {
+ sal_uInt32 nColIx = GetColumnFromPos( nPos );
+ bool bSel = IsSelected( nColIx ) || IsSelected( nColIx + 1 );
+ maColStates.erase( maColStates.begin() + nColIx + 1 );
+ maColStates[ nColIx ].Select( bSel );
+ AccSendRemoveColumnEvent( nColIx + 1, nColIx + 1 );
+ AccSendTableUpdateEvent( nColIx, nColIx );
+ }
+ return bRet;
+}
+
+void ScCsvGrid::ImplClearSplits()
+{
+ sal_uInt32 nColumns = GetColumnCount();
+ maSplits.Clear();
+ maSplits.Insert( 0 );
+ maSplits.Insert( GetPosCount() );
+ maColStates.resize( 1 );
+ InvalidateGfx();
+ AccSendRemoveColumnEvent( 1, nColumns - 1 );
+}
+
+// columns/column types -------------------------------------------------------
+
+sal_uInt32 ScCsvGrid::GetFirstVisColumn() const
+{
+ return GetColumnFromPos( GetFirstVisPos() );
+}
+
+sal_uInt32 ScCsvGrid::GetLastVisColumn() const
+{
+ return GetColumnFromPos( std::min( GetLastVisPos(), GetPosCount() ) - 1 );
+}
+
+bool ScCsvGrid::IsValidColumn( sal_uInt32 nColIndex ) const
+{
+ return nColIndex < GetColumnCount();
+}
+
+bool ScCsvGrid::IsVisibleColumn( sal_uInt32 nColIndex ) const
+{
+ return IsValidColumn( nColIndex ) &&
+ (GetColumnPos( nColIndex ) < GetLastVisPos()) &&
+ (GetFirstVisPos() < GetColumnPos( nColIndex + 1 ));
+}
+
+sal_Int32 ScCsvGrid::GetColumnX( sal_uInt32 nColIndex ) const
+{
+ return GetX( GetColumnPos( nColIndex ) );
+}
+
+sal_uInt32 ScCsvGrid::GetColumnFromX( sal_Int32 nX ) const
+{
+ sal_Int32 nPos = (nX - GetFirstX()) / GetCharWidth() + GetFirstVisPos();
+ return ((GetFirstVisPos() <= nPos) && (nPos <= GetLastVisPos())) ?
+ GetColumnFromPos( nPos ) : CSV_COLUMN_INVALID;
+}
+
+sal_uInt32 ScCsvGrid::GetColumnFromPos( sal_Int32 nPos ) const
+{
+ return maSplits.UpperBound( nPos );
+}
+
+sal_Int32 ScCsvGrid::GetColumnWidth( sal_uInt32 nColIndex ) const
+{
+ return IsValidColumn( nColIndex ) ? (GetColumnPos( nColIndex + 1 ) - GetColumnPos( nColIndex )) : 0;
+}
+
+void ScCsvGrid::SetColumnStates( ScCsvColStateVec&& rStates )
+{
+ maColStates = std::move(rStates);
+ maColStates.resize( maSplits.Count() - 1 );
+ Execute( CSVCMD_EXPORTCOLUMNTYPE );
+ AccSendTableUpdateEvent( 0, GetColumnCount(), false );
+ AccSendSelectionEvent();
+}
+
+sal_Int32 ScCsvGrid::GetColumnType( sal_uInt32 nColIndex ) const
+{
+ return IsValidColumn( nColIndex ) ? maColStates[ nColIndex ].mnType : CSV_TYPE_NOSELECTION;
+}
+
+void ScCsvGrid::SetColumnType( sal_uInt32 nColIndex, sal_Int32 nColType )
+{
+ if( IsValidColumn( nColIndex ) )
+ {
+ maColStates[ nColIndex ].mnType = nColType;
+ AccSendTableUpdateEvent( nColIndex, nColIndex, false );
+ }
+}
+
+sal_Int32 ScCsvGrid::GetSelColumnType() const
+{
+ sal_uInt32 nColIx = GetFirstSelected();
+ if( nColIx == CSV_COLUMN_INVALID )
+ return CSV_TYPE_NOSELECTION;
+
+ sal_Int32 nType = GetColumnType( nColIx );
+ while( (nColIx != CSV_COLUMN_INVALID) && (nType != CSV_TYPE_MULTI) )
+ {
+ if( nType != GetColumnType( nColIx ) )
+ nType = CSV_TYPE_MULTI;
+ nColIx = GetNextSelected( nColIx );
+ }
+ return nType;
+}
+
+void ScCsvGrid::SetSelColumnType( sal_Int32 nType )
+{
+ if( (nType != CSV_TYPE_MULTI) && (nType != CSV_TYPE_NOSELECTION) )
+ {
+ for( sal_uInt32 nColIx = GetFirstSelected(); nColIx != CSV_COLUMN_INVALID; nColIx = GetNextSelected( nColIx ) )
+ SetColumnType( nColIx, nType );
+ Repaint( true );
+ Execute( CSVCMD_EXPORTCOLUMNTYPE );
+ }
+}
+
+void ScCsvGrid::SetTypeNames( std::vector<OUString>&& rTypeNames )
+{
+ OSL_ENSURE( !rTypeNames.empty(), "ScCsvGrid::SetTypeNames - vector is empty" );
+ maTypeNames = std::move(rTypeNames);
+ Repaint( true );
+
+ mxPopup->clear();
+ sal_uInt32 nCount = maTypeNames.size();
+ for (sal_uInt32 nIx = 0; nIx < nCount; ++nIx)
+ mxPopup->append(OUString::number(nIx), maTypeNames[nIx]);
+
+ ::std::for_each( maColStates.begin(), maColStates.end(), Func_SetType( CSV_TYPE_DEFAULT ) );
+}
+
+OUString ScCsvGrid::GetColumnTypeName( sal_uInt32 nColIndex ) const
+{
+ sal_uInt32 nTypeIx = static_cast< sal_uInt32 >( GetColumnType( nColIndex ) );
+ return (nTypeIx < maTypeNames.size()) ? maTypeNames[ nTypeIx ] : OUString();
+}
+
+static sal_uInt8 lcl_GetExtColumnType( sal_Int32 nIntType )
+{
+ static const sal_uInt8 pExtTypes[] =
+ { SC_COL_STANDARD, SC_COL_TEXT, SC_COL_DMY, SC_COL_MDY, SC_COL_YMD, SC_COL_ENGLISH, SC_COL_SKIP };
+ static const sal_Int32 nExtTypeCount = SAL_N_ELEMENTS(pExtTypes);
+ return pExtTypes[ ((0 <= nIntType) && (nIntType < nExtTypeCount)) ? nIntType : 0 ];
+}
+
+void ScCsvGrid::FillColumnDataSep( ScAsciiOptions& rOptions ) const
+{
+ sal_uInt32 nCount = GetColumnCount();
+ ScCsvExpDataVec aDataVec;
+
+ for( sal_uInt32 nColIx = 0; nColIx < nCount; ++nColIx )
+ {
+ if( GetColumnType( nColIx ) != CSV_TYPE_DEFAULT )
+ // 1-based column index
+ aDataVec.emplace_back(
+ static_cast< sal_Int32 >( nColIx + 1 ),
+ lcl_GetExtColumnType( GetColumnType( nColIx ) ) );
+ }
+ rOptions.SetColumnInfo( aDataVec );
+}
+
+void ScCsvGrid::FillColumnDataFix( ScAsciiOptions& rOptions ) const
+{
+ sal_uInt32 nCount = std::min( GetColumnCount(), static_cast<sal_uInt32>(MAXCOLCOUNT) );
+ ScCsvExpDataVec aDataVec( nCount + 1 );
+
+ for( sal_uInt32 nColIx = 0; nColIx < nCount; ++nColIx )
+ {
+ ScCsvExpData& rData = aDataVec[ nColIx ];
+ rData.mnIndex = GetColumnPos( nColIx );
+ rData.mnType = lcl_GetExtColumnType( GetColumnType( nColIx ) );
+ }
+ aDataVec[ nCount ].mnIndex = SAL_MAX_INT32;
+ aDataVec[ nCount ].mnType = SC_COL_SKIP;
+ rOptions.SetColumnInfo( aDataVec );
+}
+
+void ScCsvGrid::ScrollVertRel( ScMoveMode eDir )
+{
+ sal_Int32 nLine = GetFirstVisLine();
+ switch( eDir )
+ {
+ case MOVE_PREV: --nLine; break;
+ case MOVE_NEXT: ++nLine; break;
+ case MOVE_FIRST: nLine = 0; break;
+ case MOVE_LAST: nLine = GetMaxLineOffset(); break;
+ case MOVE_PREVPAGE: nLine -= GetVisLineCount() - 2; break;
+ case MOVE_NEXTPAGE: nLine += GetVisLineCount() - 2; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ Execute( CSVCMD_SETLINEOFFSET, nLine );
+}
+
+void ScCsvGrid::ExecutePopup( const Point& rPos )
+{
+ OString sItemId = mxPopup->popup_at_rect(GetDrawingArea(), tools::Rectangle(rPos, Size(1, 1)));
+ if (!sItemId.isEmpty()) // empty = cancelled
+ Execute(CSVCMD_SETCOLUMNTYPE, sItemId.toInt32());
+}
+
+// selection handling ---------------------------------------------------------
+
+bool ScCsvGrid::IsSelected( sal_uInt32 nColIndex ) const
+{
+ return IsValidColumn( nColIndex ) && maColStates[ nColIndex ].IsSelected();
+}
+
+sal_uInt32 ScCsvGrid::GetFirstSelected() const
+{
+ return IsSelected( 0 ) ? 0 : GetNextSelected( 0 );
+}
+
+sal_uInt32 ScCsvGrid::GetNextSelected( sal_uInt32 nFromIndex ) const
+{
+ sal_uInt32 nColCount = GetColumnCount();
+ for( sal_uInt32 nColIx = nFromIndex + 1; nColIx < nColCount; ++nColIx )
+ if( IsSelected( nColIx ) )
+ return nColIx;
+ return CSV_COLUMN_INVALID;
+}
+
+void ScCsvGrid::Select( sal_uInt32 nColIndex, bool bSelect )
+{
+ if( IsValidColumn( nColIndex ) )
+ {
+ maColStates[ nColIndex ].Select( bSelect );
+ ImplDrawColumnSelection( nColIndex );
+ Repaint();
+ Execute( CSVCMD_EXPORTCOLUMNTYPE );
+ if( bSelect )
+ mnRecentSelCol = nColIndex;
+ AccSendSelectionEvent();
+ }
+}
+
+void ScCsvGrid::ToggleSelect( sal_uInt32 nColIndex )
+{
+ Select( nColIndex, !IsSelected( nColIndex ) );
+}
+
+void ScCsvGrid::SelectRange( sal_uInt32 nColIndex1, sal_uInt32 nColIndex2, bool bSelect )
+{
+ if( nColIndex1 == CSV_COLUMN_INVALID )
+ Select( nColIndex2 );
+ else if( nColIndex2 == CSV_COLUMN_INVALID )
+ Select( nColIndex1 );
+ else if( nColIndex1 > nColIndex2 )
+ {
+ SelectRange( nColIndex2, nColIndex1, bSelect );
+ if( bSelect )
+ mnRecentSelCol = nColIndex1;
+ }
+ else if( IsValidColumn( nColIndex1 ) && IsValidColumn( nColIndex2 ) )
+ {
+ for( sal_uInt32 nColIx = nColIndex1; nColIx <= nColIndex2; ++nColIx )
+ {
+ maColStates[ nColIx ].Select( bSelect );
+ ImplDrawColumnSelection( nColIx );
+ }
+ Repaint();
+ Execute( CSVCMD_EXPORTCOLUMNTYPE );
+ if( bSelect )
+ mnRecentSelCol = nColIndex1;
+ AccSendSelectionEvent();
+ }
+}
+
+void ScCsvGrid::SelectAll( bool bSelect )
+{
+ SelectRange( 0, GetColumnCount() - 1, bSelect );
+}
+
+void ScCsvGrid::MoveCursor( sal_uInt32 nColIndex )
+{
+ DisableRepaint();
+ if( IsValidColumn( nColIndex ) )
+ {
+ sal_Int32 nPosBeg = GetColumnPos( nColIndex );
+ sal_Int32 nPosEnd = GetColumnPos( nColIndex + 1 );
+ sal_Int32 nMinPos = std::max( nPosBeg - CSV_SCROLL_DIST, sal_Int32( 0 ) );
+ sal_Int32 nMaxPos = std::min( nPosEnd - GetVisPosCount() + CSV_SCROLL_DIST + sal_Int32( 1 ), nMinPos );
+ if( nPosBeg - CSV_SCROLL_DIST + 1 <= GetFirstVisPos() )
+ Execute( CSVCMD_SETPOSOFFSET, nMinPos );
+ else if( nPosEnd + CSV_SCROLL_DIST >= GetLastVisPos() )
+ Execute( CSVCMD_SETPOSOFFSET, nMaxPos );
+ }
+ Execute( CSVCMD_MOVEGRIDCURSOR, GetColumnPos( nColIndex ) );
+ EnableRepaint();
+}
+
+void ScCsvGrid::MoveCursorRel( ScMoveMode eDir )
+{
+ if( GetFocusColumn() == CSV_COLUMN_INVALID )
+ return;
+
+ switch( eDir )
+ {
+ case MOVE_FIRST:
+ MoveCursor( 0 );
+ break;
+ case MOVE_LAST:
+ MoveCursor( GetColumnCount() - 1 );
+ break;
+ case MOVE_PREV:
+ if( GetFocusColumn() > 0 )
+ MoveCursor( GetFocusColumn() - 1 );
+ break;
+ case MOVE_NEXT:
+ if( GetFocusColumn() < GetColumnCount() - 1 )
+ MoveCursor( GetFocusColumn() + 1 );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
+void ScCsvGrid::ImplClearSelection()
+{
+ ::std::for_each( maColStates.begin(), maColStates.end(), Func_Select( false ) );
+ ImplDrawGridDev();
+}
+
+void ScCsvGrid::DoSelectAction( sal_uInt32 nColIndex, sal_uInt16 nModifier )
+{
+ if( !(nModifier & KEY_MOD1) )
+ ImplClearSelection();
+ if( nModifier & KEY_SHIFT ) // SHIFT always expands
+ SelectRange( mnRecentSelCol, nColIndex );
+ else if( !(nModifier & KEY_MOD1) ) // no SHIFT/CTRL always selects 1 column
+ Select( nColIndex );
+ else if( mbTracking ) // CTRL in tracking does not toggle
+ Select( nColIndex, mbMTSelecting );
+ else // CTRL only toggles
+ ToggleSelect( nColIndex );
+ Execute( CSVCMD_MOVEGRIDCURSOR, GetColumnPos( nColIndex ) );
+}
+
+// cell contents --------------------------------------------------------------
+
+void ScCsvGrid::ImplSetTextLineSep(
+ sal_Int32 nLine, const OUString& rTextLine,
+ const OUString& rSepChars, sal_Unicode cTextSep, bool bMergeSep, bool bRemoveSpace )
+{
+ if( nLine < GetFirstVisLine() ) return;
+
+ sal_uInt32 nLineIx = nLine - GetFirstVisLine();
+ while( maTexts.size() <= nLineIx )
+ maTexts.emplace_back( );
+ std::vector<OUString>& rStrVec = maTexts[ nLineIx ];
+ rStrVec.clear();
+
+ // scan for separators
+ OUString aCellText;
+ const sal_Unicode* pSepChars = rSepChars.getStr();
+ const sal_Unicode* pChar = rTextLine.getStr();
+ sal_uInt32 nColIx = 0;
+
+ while( *pChar && (nColIx < sal::static_int_cast<sal_uInt32>(CSV_MAXCOLCOUNT)) )
+ {
+ // scan for next cell text
+ bool bIsQuoted = false;
+ bool bOverflowCell = false;
+ pChar = ScImportExport::ScanNextFieldFromString( pChar, aCellText,
+ cTextSep, pSepChars, bMergeSep, bIsQuoted, bOverflowCell, bRemoveSpace );
+ /* TODO: signal overflow somewhere in UI */
+
+ // update column width
+ sal_Int32 nWidth = std::max( CSV_MINCOLWIDTH, ScImportExport::CountVisualWidth( aCellText ) + 1 );
+ if( IsValidColumn( nColIx ) )
+ {
+ // expand existing column
+ sal_Int32 nDiff = nWidth - GetColumnWidth( nColIx );
+ if( nDiff > 0 )
+ {
+ Execute( CSVCMD_SETPOSCOUNT, GetPosCount() + nDiff );
+ for( sal_uInt32 nSplitIx = GetColumnCount() - 1; nSplitIx > nColIx; --nSplitIx )
+ {
+ sal_Int32 nPos = maSplits[ nSplitIx ];
+ maSplits.Remove( nPos );
+ maSplits.Insert( nPos + nDiff );
+ }
+ }
+ }
+ else
+ {
+ // append new column
+ sal_Int32 nLastPos = GetPosCount();
+ Execute( CSVCMD_SETPOSCOUNT, nLastPos + nWidth );
+ ImplInsertSplit( nLastPos );
+ }
+
+ if( aCellText.getLength() <= CSV_MAXSTRLEN )
+ rStrVec.push_back( aCellText );
+ else
+ rStrVec.push_back( aCellText.copy( 0, CSV_MAXSTRLEN ) );
+ ++nColIx;
+ }
+ InvalidateGfx();
+}
+
+void ScCsvGrid::ImplSetTextLineFix( sal_Int32 nLine, const OUString& rTextLine )
+{
+ if( nLine < GetFirstVisLine() ) return;
+
+ sal_Int32 nWidth = ScImportExport::CountVisualWidth( rTextLine );
+ if( nWidth > GetPosCount() )
+ Execute( CSVCMD_SETPOSCOUNT, nWidth );
+
+ sal_uInt32 nLineIx = nLine - GetFirstVisLine();
+ while( maTexts.size() <= nLineIx )
+ maTexts.emplace_back( );
+
+ std::vector<OUString>& rStrVec = maTexts[ nLineIx ];
+ rStrVec.clear();
+ sal_uInt32 nColCount = GetColumnCount();
+ sal_Int32 nStrLen = rTextLine.getLength();
+ sal_Int32 nStrIx = 0;
+ for( sal_uInt32 nColIx = 0; (nColIx < nColCount) && (nStrIx < nStrLen); ++nColIx )
+ {
+ sal_Int32 nColWidth = GetColumnWidth( nColIx );
+ sal_Int32 nLastIx = nStrIx;
+ ScImportExport::CountVisualWidth( rTextLine, nLastIx, nColWidth );
+ sal_Int32 nLen = std::min( CSV_MAXSTRLEN, nLastIx - nStrIx );
+ rStrVec.push_back( rTextLine.copy( nStrIx, nLen ) );
+ nStrIx = nStrIx + nLen;
+ }
+ InvalidateGfx();
+}
+
+OUString ScCsvGrid::GetCellText( sal_uInt32 nColIndex, sal_Int32 nLine ) const
+{
+ if( nLine < GetFirstVisLine() ) return OUString();
+
+ sal_uInt32 nLineIx = nLine - GetFirstVisLine();
+ if( nLineIx >= maTexts.size() ) return OUString();
+
+ const std::vector<OUString>& rStrVec = maTexts[ nLineIx ];
+ if( nColIndex >= rStrVec.size() ) return OUString();
+
+ return rStrVec[ nColIndex ];
+}
+
+// event handling -------------------------------------------------------------
+
+void ScCsvGrid::Resize()
+{
+ mpTableBox->InitControls();
+
+ ScCsvControl::Resize();
+ InitSizeData();
+ Execute( CSVCMD_UPDATECELLTEXTS );
+}
+
+void ScCsvGrid::GetFocus()
+{
+ ScCsvControl::GetFocus();
+ Execute( CSVCMD_MOVEGRIDCURSOR, GetNoScrollCol( GetGridCursorPos() ) );
+ Repaint();
+}
+
+void ScCsvGrid::LoseFocus()
+{
+ ScCsvControl::LoseFocus();
+ Repaint();
+}
+
+bool ScCsvGrid::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ DisableRepaint();
+ if( !HasFocus() )
+ GrabFocus();
+
+ Point aPos( rMEvt.GetPosPixel() );
+ sal_uInt32 nColIx = GetColumnFromX( aPos.X() );
+
+ if( rMEvt.IsLeft() )
+ {
+ if( (GetFirstX() > aPos.X()) || (aPos.X() > GetLastX()) ) // in header column
+ {
+ if( aPos.Y() <= GetHdrHeight() )
+ SelectAll();
+ }
+ else if( IsValidColumn( nColIx ) )
+ {
+ DoSelectAction( nColIx, rMEvt.GetModifier() );
+ mnMTCurrCol = nColIx;
+ mbMTSelecting = IsSelected( nColIx );
+ mbTracking = true;
+ }
+ }
+ EnableRepaint();
+ return true;
+}
+
+bool ScCsvGrid::MouseButtonUp( const MouseEvent& )
+{
+ mbTracking = false;
+ return true;
+}
+
+bool ScCsvGrid::MouseMove( const MouseEvent& rMEvt )
+{
+ if (!mbTracking)
+ return true;
+
+ DisableRepaint();
+
+ sal_Int32 nPos = (rMEvt.GetPosPixel().X() - GetFirstX()) / GetCharWidth() + GetFirstVisPos();
+ // on mouse tracking: keep position valid
+ nPos = std::clamp( nPos, sal_Int32(0), GetPosCount() - 1 );
+ Execute( CSVCMD_MAKEPOSVISIBLE, nPos );
+
+ sal_uInt32 nColIx = GetColumnFromPos( nPos );
+ if( mnMTCurrCol != nColIx )
+ {
+ DoSelectAction( nColIx, rMEvt.GetModifier() );
+ mnMTCurrCol = nColIx;
+ }
+ EnableRepaint();
+
+ return true;
+}
+
+bool ScCsvGrid::KeyInput( const KeyEvent& rKEvt )
+{
+ const vcl::KeyCode& rKCode = rKEvt.GetKeyCode();
+ sal_uInt16 nCode = rKCode.GetCode();
+ bool bShift = rKCode.IsShift();
+ bool bMod1 = rKCode.IsMod1();
+
+ if( !rKCode.IsMod2() )
+ {
+ ScMoveMode eHDir = GetHorzDirection( nCode, !bMod1 );
+ ScMoveMode eVDir = GetVertDirection( nCode, bMod1 );
+
+ if( eHDir != MOVE_NONE )
+ {
+ DisableRepaint();
+ MoveCursorRel( eHDir );
+ if( !bMod1 )
+ ImplClearSelection();
+ if( bShift )
+ SelectRange( mnRecentSelCol, GetFocusColumn() );
+ else if( !bMod1 )
+ Select( GetFocusColumn() );
+ EnableRepaint();
+ }
+ else if( eVDir != MOVE_NONE )
+ ScrollVertRel( eVDir );
+ else if( nCode == KEY_SPACE )
+ {
+ if( !bMod1 )
+ ImplClearSelection();
+ if( bShift )
+ SelectRange( mnRecentSelCol, GetFocusColumn() );
+ else if( bMod1 )
+ ToggleSelect( GetFocusColumn() );
+ else
+ Select( GetFocusColumn() );
+ }
+ else if( !bShift && bMod1 )
+ {
+ if( nCode == KEY_A )
+ SelectAll();
+ else if( (KEY_1 <= nCode) && (nCode <= KEY_9) )
+ {
+ sal_uInt32 nType = nCode - KEY_1;
+ if( nType < maTypeNames.size() )
+ Execute( CSVCMD_SETCOLUMNTYPE, nType );
+ }
+ }
+ }
+
+ return rKCode.GetGroup() == KEYGROUP_CURSOR;
+}
+
+bool ScCsvGrid::Command( const CommandEvent& rCEvt )
+{
+ bool bConsumed = true;
+ switch( rCEvt.GetCommand() )
+ {
+ case CommandEventId::ContextMenu:
+ {
+ if( rCEvt.IsMouseEvent() )
+ {
+ Point aPos( rCEvt.GetMousePosPixel() );
+ sal_uInt32 nColIx = GetColumnFromX( aPos.X() );
+ if( IsValidColumn( nColIx ) && (GetFirstX() <= aPos.X()) && (aPos.X() <= GetLastX()) )
+ {
+ if( !IsSelected( nColIx ) )
+ DoSelectAction( nColIx, 0 ); // focus & select
+ ExecutePopup( aPos );
+ }
+ }
+ else
+ {
+ sal_uInt32 nColIx = GetFocusColumn();
+ if( !IsSelected( nColIx ) )
+ Select( nColIx );
+ sal_Int32 nX1 = std::max( GetColumnX( nColIx ), GetFirstX() );
+ sal_Int32 nX2 = std::min( GetColumnX( nColIx + 1 ), GetWidth() );
+ ExecutePopup( Point( (nX1 + nX2) / 2, GetHeight() / 2 ) );
+ }
+ break;
+ }
+ case CommandEventId::Wheel:
+ {
+ tools::Rectangle aRect( Point(), maWinSize );
+ if( aRect.Contains( rCEvt.GetMousePosPixel() ) )
+ {
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if( pData && (pData->GetMode() == CommandWheelMode::SCROLL) && !pData->IsHorz() )
+ Execute( CSVCMD_SETLINEOFFSET, GetFirstVisLine() - pData->GetNotchDelta() );
+ }
+ break;
+ }
+ default:
+ bConsumed = false;
+ break;
+ }
+ return bConsumed;
+}
+
+void ScCsvGrid::StyleUpdated()
+{
+ InitColors();
+ InitFonts();
+ UpdateLayoutData();
+ Execute( CSVCMD_UPDATECELLTEXTS );
+
+ ScCsvControl::StyleUpdated();
+}
+
+void ScCsvGrid::ConfigurationChanged( utl::ConfigurationBroadcaster*, ConfigurationHints )
+{
+ InitColors();
+ Repaint();
+}
+
+// painting -------------------------------------------------------------------
+
+void ScCsvGrid::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
+{
+ ImplRedraw(rRenderContext);
+}
+
+void ScCsvGrid::ImplRedraw(vcl::RenderContext& rRenderContext)
+{
+ if( IsVisible() )
+ {
+ if( !IsValidGfx() )
+ {
+ ValidateGfx();
+ ImplDrawBackgrDev();
+ ImplDrawGridDev();
+ }
+ rRenderContext.DrawOutDev( Point(), maWinSize, Point(), maWinSize, *mpGridDev );
+ }
+}
+
+EditEngine* ScCsvGrid::GetEditEngine()
+{
+ return mpEditEngine.get();
+}
+
+void ScCsvGrid::ImplSetColumnClipRegion( OutputDevice& rOutDev, sal_uInt32 nColIndex )
+{
+ rOutDev.SetClipRegion( vcl::Region( tools::Rectangle(
+ std::max( GetColumnX( nColIndex ), GetFirstX() ) + 1, 0,
+ std::min( GetColumnX( nColIndex + 1 ), GetLastX() ), GetHeight() - 1 ) ) );
+}
+
+void ScCsvGrid::ImplDrawColumnHeader( OutputDevice& rOutDev, sal_uInt32 nColIndex, Color aFillColor )
+{
+ sal_Int32 nX1 = GetColumnX( nColIndex ) + 1;
+ sal_Int32 nX2 = GetColumnX( nColIndex + 1 );
+ sal_Int32 nHdrHt = GetHdrHeight();
+
+ rOutDev.SetLineColor();
+ rOutDev.SetFillColor( aFillColor );
+ rOutDev.DrawRect( tools::Rectangle( nX1, 0, nX2, nHdrHt ) );
+
+ rOutDev.SetFont( maHeaderFont );
+ rOutDev.SetTextColor( maHeaderTextColor );
+ rOutDev.SetTextFillColor();
+ rOutDev.DrawText( Point( nX1 + 1, 0 ), GetColumnTypeName( nColIndex ) );
+
+ rOutDev.SetLineColor( maHeaderGridColor );
+ rOutDev.DrawLine( Point( nX1, nHdrHt ), Point( nX2, nHdrHt ) );
+ rOutDev.DrawLine( Point( nX2, 0 ), Point( nX2, nHdrHt ) );
+}
+
+void ScCsvGrid::ImplDrawCellText( const Point& rPos, const OUString& rText )
+{
+ OUString aPlainText = rText.replaceAll( "\t", " " );
+ aPlainText = aPlainText.replaceAll( "\n", " " );
+ mpEditEngine->SetPaperSize( maEdEngSize );
+
+ /* #i60296# If string contains mixed script types, the space character
+ U+0020 may be drawn with a wrong width (from non-fixed-width Asian or
+ Complex font). Now we draw every non-space portion separately. */
+ sal_Int32 nCharIxInt {aPlainText.isEmpty() ? -1 : 0};
+ while (nCharIxInt>=0)
+ {
+ sal_Int32 nBeginIx = nCharIxInt;
+ const OUString aToken = aPlainText.getToken( 0, ' ', nCharIxInt );
+ if( !aToken.isEmpty() )
+ {
+ sal_Int32 nX = rPos.X() + GetCharWidth() * nBeginIx;
+ mpEditEngine->SetTextCurrentDefaults( aToken );
+ mpEditEngine->Draw(*mpBackgrDev, Point(nX, rPos.Y()));
+ }
+ }
+
+ sal_Int32 nCharIx = 0;
+ while( (nCharIx = rText.indexOf( '\t', nCharIx )) != -1 )
+ {
+ sal_Int32 nX1 = rPos.X() + GetCharWidth() * nCharIx;
+ sal_Int32 nX2 = nX1 + GetCharWidth() - 2;
+ sal_Int32 nY = rPos.Y() + GetLineHeight() / 2;
+ Color aColor( maTextColor );
+ mpBackgrDev->SetLineColor( aColor );
+ mpBackgrDev->DrawLine( Point( nX1, nY ), Point( nX2, nY ) );
+ mpBackgrDev->DrawLine( Point( nX2 - 2, nY - 2 ), Point( nX2, nY ) );
+ mpBackgrDev->DrawLine( Point( nX2 - 2, nY + 2 ), Point( nX2, nY ) );
+ ++nCharIx;
+ }
+ nCharIx = 0;
+ while( (nCharIx = rText.indexOf( '\n', nCharIx )) != -1 )
+ {
+ sal_Int32 nX1 = rPos.X() + GetCharWidth() * nCharIx;
+ sal_Int32 nX2 = nX1 + GetCharWidth() - 2;
+ sal_Int32 nY = rPos.Y() + GetLineHeight() / 2;
+ Color aColor( maTextColor );
+ mpBackgrDev->SetLineColor( aColor );
+ mpBackgrDev->DrawLine( Point( nX1, nY ), Point( nX2, nY ) );
+ mpBackgrDev->DrawLine( Point( nX1 + 2, nY - 2 ), Point( nX1, nY ) );
+ mpBackgrDev->DrawLine( Point( nX1 + 2, nY + 2 ), Point( nX1, nY ) );
+ mpBackgrDev->DrawLine( Point( nX2, nY - 2 ), Point( nX2, nY ) );
+ ++nCharIx;
+ }
+}
+
+void ScCsvGrid::ImplDrawFirstLineSep( bool bSet )
+{
+ if( IsVisibleLine( mnFirstImpLine ) && (mnFirstImpLine != GetFirstVisLine() ) )
+ {
+ sal_Int32 nY = GetY( mnFirstImpLine );
+ sal_Int32 nX = std::min( GetColumnX( GetLastVisColumn() + 1 ), GetLastX() );
+ mpBackgrDev->SetLineColor( bSet ? maGridPBColor : maGridColor );
+ mpBackgrDev->DrawLine( Point( GetFirstX() + 1, nY ), Point( nX, nY ) );
+ }
+}
+
+void ScCsvGrid::ImplDrawColumnBackgr( sal_uInt32 nColIndex )
+{
+ if( !IsVisibleColumn( nColIndex ) )
+ return;
+
+ ImplSetColumnClipRegion( *mpBackgrDev, nColIndex );
+
+ // grid
+ mpBackgrDev->SetLineColor();
+ mpBackgrDev->SetFillColor( maBackColor );
+ sal_Int32 nX1 = GetColumnX( nColIndex ) + 1;
+ sal_Int32 nX2 = GetColumnX( nColIndex + 1 );
+ sal_Int32 nY2 = GetY( GetLastVisLine() + 1 );
+ sal_Int32 nHdrHt = GetHdrHeight();
+ tools::Rectangle aRect( nX1, nHdrHt, nX2, nY2 );
+ mpBackgrDev->DrawRect( aRect );
+ mpBackgrDev->SetLineColor( maGridColor );
+ mpBackgrDev->DrawGrid( aRect, Size( 1, GetLineHeight() ), DrawGridFlags::HorzLines );
+ mpBackgrDev->DrawLine( Point( nX2, nHdrHt ), Point( nX2, nY2 ) );
+ ImplDrawFirstLineSep( true );
+
+ // cell texts
+ mpEditEngine->SetDefaultItem( SvxColorItem( maTextColor, EE_CHAR_COLOR ) );
+ size_t nLineCount = ::std::min( static_cast< size_t >( GetLastVisLine() - GetFirstVisLine() + 1 ), maTexts.size() );
+ // #i67432# cut string to avoid edit engine performance problems with very large strings
+ sal_Int32 nFirstVisPos = ::std::max( GetColumnPos( nColIndex ), GetFirstVisPos() );
+ sal_Int32 nLastVisPos = ::std::min( GetColumnPos( nColIndex + 1 ), GetLastVisPos() );
+ sal_Int32 nStrPos = nFirstVisPos - GetColumnPos( nColIndex );
+ sal_Int32 nStrLen = nLastVisPos - nFirstVisPos + 1;
+ sal_Int32 nStrX = GetX( nFirstVisPos );
+ for( size_t nLine = 0; nLine < nLineCount; ++nLine )
+ {
+ std::vector<OUString>& rStrVec = maTexts[ nLine ];
+ if( (nColIndex < rStrVec.size()) && (rStrVec[ nColIndex ].getLength() > nStrPos) )
+ {
+ const OUString& rStr = rStrVec[ nColIndex ];
+ OUString aText = rStr.copy( nStrPos, ::std::min( nStrLen, rStr.getLength() - nStrPos) );
+ ImplDrawCellText( Point( nStrX, GetY( GetFirstVisLine() + nLine ) ), aText );
+ }
+ }
+
+ // header
+ ImplDrawColumnHeader( *mpBackgrDev, nColIndex, maHeaderBackColor );
+
+ mpBackgrDev->SetClipRegion();
+}
+
+void ScCsvGrid::ImplDrawRowHeaders()
+{
+ mpBackgrDev->SetLineColor();
+ mpBackgrDev->SetFillColor( maAppBackColor );
+ Point aPoint( GetHdrX(), 0 );
+ tools::Rectangle aRect( aPoint, Size( GetHdrWidth() + 1, GetHeight() ) );
+ mpBackgrDev->DrawRect( aRect );
+
+ mpBackgrDev->SetFillColor( maHeaderBackColor );
+ aRect.SetBottom( GetY( GetLastVisLine() + 1 ) );
+ mpBackgrDev->DrawRect( aRect );
+
+ // line numbers
+ mpBackgrDev->SetFont( maHeaderFont );
+ mpBackgrDev->SetTextColor( maHeaderTextColor );
+ mpBackgrDev->SetTextFillColor();
+ sal_Int32 nLastLine = GetLastVisLine();
+ for( sal_Int32 nLine = GetFirstVisLine(); nLine <= nLastLine; ++nLine )
+ {
+ OUString aText( OUString::number( nLine + 1 ) );
+ sal_Int32 nX = GetHdrX() + (GetHdrWidth() - mpBackgrDev->GetTextWidth( aText )) / 2;
+ mpBackgrDev->DrawText( Point( nX, GetY( nLine ) ), aText );
+ }
+
+ // grid
+ mpBackgrDev->SetLineColor( maHeaderGridColor );
+ if( IsRTL() )
+ {
+ mpBackgrDev->DrawLine( Point( 0, 0 ), Point( 0, GetHeight() - 1 ) );
+ mpBackgrDev->DrawLine( aRect.TopLeft(), aRect.BottomLeft() );
+ }
+ else
+ mpBackgrDev->DrawLine( aRect.TopRight(), aRect.BottomRight() );
+ aRect.SetTop( GetHdrHeight() );
+ mpBackgrDev->DrawGrid( aRect, Size( 1, GetLineHeight() ), DrawGridFlags::HorzLines );
+}
+
+void ScCsvGrid::ImplDrawBackgrDev()
+{
+ mpBackgrDev->SetLineColor();
+ mpBackgrDev->SetFillColor( maAppBackColor );
+ mpBackgrDev->DrawRect( tools::Rectangle(
+ Point( GetFirstX() + 1, 0 ), Size( GetWidth() - GetHdrWidth(), GetHeight() ) ) );
+
+ sal_uInt32 nLastCol = GetLastVisColumn();
+ if (nLastCol == CSV_COLUMN_INVALID)
+ return;
+ for( sal_uInt32 nColIx = GetFirstVisColumn(); nColIx <= nLastCol; ++nColIx )
+ ImplDrawColumnBackgr( nColIx );
+
+ ImplDrawRowHeaders();
+}
+
+void ScCsvGrid::ImplDrawColumnSelection( sal_uInt32 nColIndex )
+{
+ ImplInvertCursor( GetRulerCursorPos() );
+ ImplSetColumnClipRegion( *mpGridDev, nColIndex );
+ mpGridDev->DrawOutDev( Point(), maWinSize, Point(), maWinSize, *mpBackgrDev );
+
+ if( IsSelected( nColIndex ) )
+ {
+ sal_Int32 nX1 = GetColumnX( nColIndex ) + 1;
+ sal_Int32 nX2 = GetColumnX( nColIndex + 1 );
+
+ // header
+ tools::Rectangle aRect( nX1, 0, nX2, GetHdrHeight() );
+ mpGridDev->SetLineColor();
+ if( maHeaderBackColor.IsDark() )
+ // redraw with light gray background in dark mode
+ ImplDrawColumnHeader( *mpGridDev, nColIndex, COL_LIGHTGRAY );
+ else
+ {
+ // use transparent active color
+ mpGridDev->SetFillColor( maSelectColor );
+ mpGridDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aRect ) ), CSV_HDR_TRANSPARENCY );
+ }
+
+ // column selection
+ aRect = tools::Rectangle( nX1, GetHdrHeight() + 1, nX2, GetY( GetLastVisLine() + 1 ) - 1 );
+ ImplInvertRect( *mpGridDev, aRect );
+ }
+
+ mpGridDev->SetClipRegion();
+ ImplInvertCursor( GetRulerCursorPos() );
+}
+
+void ScCsvGrid::ImplDrawGridDev()
+{
+ mpGridDev->DrawOutDev( Point(), maWinSize, Point(), maWinSize, *mpBackgrDev );
+ sal_uInt32 nLastCol = GetLastVisColumn();
+ if (nLastCol == CSV_COLUMN_INVALID)
+ return;
+ for( sal_uInt32 nColIx = GetFirstVisColumn(); nColIx <= nLastCol; ++nColIx )
+ ImplDrawColumnSelection( nColIx );
+}
+
+void ScCsvGrid::ImplDrawColumn( sal_uInt32 nColIndex )
+{
+ ImplDrawColumnBackgr( nColIndex );
+ ImplDrawColumnSelection( nColIndex );
+}
+
+void ScCsvGrid::ImplDrawHorzScrolled( sal_Int32 nOldPos )
+{
+ sal_Int32 nPos = GetFirstVisPos();
+ if( !IsValidGfx() || (nPos == nOldPos) )
+ return;
+ if( std::abs( nPos - nOldPos ) > GetVisPosCount() / 2 )
+ {
+ ImplDrawBackgrDev();
+ ImplDrawGridDev();
+ return;
+ }
+
+ Point aSrc, aDest;
+ sal_uInt32 nFirstColIx, nLastColIx;
+ if( nPos < nOldPos )
+ {
+ aSrc = Point( GetFirstX() + 1, 0 );
+ aDest = Point( GetFirstX() + GetCharWidth() * (nOldPos - nPos) + 1, 0 );
+ nFirstColIx = GetColumnFromPos( nPos );
+ nLastColIx = GetColumnFromPos( nOldPos );
+ }
+ else
+ {
+ aSrc = Point( GetFirstX() + GetCharWidth() * (nPos - nOldPos) + 1, 0 );
+ aDest = Point( GetFirstX() + 1, 0 );
+ nFirstColIx = GetColumnFromPos( std::min( nOldPos + GetVisPosCount(), GetPosCount() ) - 1 );
+ nLastColIx = GetColumnFromPos( std::min( nPos + GetVisPosCount(), GetPosCount() ) - 1 );
+ }
+
+ ImplInvertCursor( GetRulerCursorPos() + (nPos - nOldPos) );
+ tools::Rectangle aRectangle( GetFirstX(), 0, GetLastX(), GetHeight() - 1 );
+ vcl::Region aClipReg( aRectangle );
+ mpBackgrDev->SetClipRegion( aClipReg );
+ mpBackgrDev->CopyArea( aDest, aSrc, maWinSize );
+ mpBackgrDev->SetClipRegion();
+ mpGridDev->SetClipRegion( aClipReg );
+ mpGridDev->CopyArea( aDest, aSrc, maWinSize );
+ mpGridDev->SetClipRegion();
+ ImplInvertCursor( GetRulerCursorPos() );
+
+ for( sal_uInt32 nColIx = nFirstColIx; nColIx <= nLastColIx; ++nColIx )
+ ImplDrawColumn( nColIx );
+
+ sal_Int32 nLastX = GetX( GetPosCount() ) + 1;
+ if( nLastX <= GetLastX() )
+ {
+ tools::Rectangle aRect( nLastX, 0, GetLastX(), GetHeight() - 1 );
+ mpBackgrDev->SetLineColor();
+ mpBackgrDev->SetFillColor( maAppBackColor );
+ mpBackgrDev->DrawRect( aRect );
+ mpGridDev->SetLineColor();
+ mpGridDev->SetFillColor( maAppBackColor );
+ mpGridDev->DrawRect( aRect );
+ }
+}
+
+void ScCsvGrid::ImplInvertCursor( sal_Int32 nPos )
+{
+ if( IsVisibleSplitPos( nPos ) )
+ {
+ sal_Int32 nX = GetX( nPos ) - 1;
+ tools::Rectangle aRect( Point( nX, 0 ), Size( 3, GetHdrHeight() ) );
+ ImplInvertRect( *mpGridDev, aRect );
+ aRect.SetTop( GetHdrHeight() + 1 );
+ aRect.SetBottom( GetY( GetLastVisLine() + 1 ) );
+ ImplInvertRect( *mpGridDev, aRect );
+ }
+}
+
+tools::Rectangle ScCsvGrid::GetFocusRect()
+{
+ auto nColIndex = GetFocusColumn();
+ if( HasFocus() && IsVisibleColumn( nColIndex ) )
+ {
+ sal_Int32 nX1 = std::max( GetColumnX( nColIndex ), GetFirstX() ) + 1;
+ sal_Int32 nX2 = std::min( GetColumnX( nColIndex + 1 ) - sal_Int32( 1 ), GetLastX() );
+ sal_Int32 nY2 = std::min( GetY( GetLastVisLine() + 1 ), GetHeight() ) - 1;
+ return tools::Rectangle( nX1, 0, nX2, nY2 );
+ }
+ return weld::CustomWidgetController::GetFocusRect();
+}
+
+// accessibility ==============================================================
+
+css::uno::Reference<css::accessibility::XAccessible> ScCsvGrid::CreateAccessible()
+{
+ rtl::Reference<ScAccessibleCsvGrid> xRef(new ScAccessibleCsvGrid(*this));
+ mxAccessible = xRef;
+ return xRef;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/csvruler.cxx b/sc/source/ui/dbgui/csvruler.cxx
new file mode 100644
index 000000000..3af7645e2
--- /dev/null
+++ b/sc/source/ui/dbgui/csvruler.cxx
@@ -0,0 +1,666 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <csvruler.hxx>
+#include <AccessibleCsvControl.hxx>
+
+#include <optutil.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/ptrstyle.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace com::sun::star::uno;
+
+constexpr OUStringLiteral SEP_PATH = u"Office.Calc/Dialogs/CSVImport";
+constexpr OUStringLiteral FIXED_WIDTH_LIST = u"FixedWidthList";
+
+static void load_FixedWidthList(ScCsvSplits &rSplits)
+{
+ Sequence<Any>aValues;
+ const Any *pProperties;
+ Sequence<OUString> aNames { FIXED_WIDTH_LIST };
+ ScLinkConfigItem aItem( SEP_PATH );
+
+ aValues = aItem.GetProperties( aNames );
+ pProperties = aValues.getConstArray();
+
+ if( !pProperties[0].hasValue() )
+ return;
+
+ rSplits.Clear();
+
+ OUString sFixedWidthLists;
+ pProperties[0] >>= sFixedWidthLists;
+
+ sal_Int32 nIdx {0};
+ for(;;)
+ {
+ const sal_Int32 n = o3tl::toInt32(o3tl::getToken(sFixedWidthLists, 0, ';', nIdx));
+ if (nIdx<0)
+ {
+ // String ends with a semi-colon so there
+ // is no useful 'int' after the last one.
+ // This also works in case of empty string
+ break;
+ }
+ rSplits.Insert(n);
+ }
+}
+static void save_FixedWidthList(const ScCsvSplits& rSplits)
+{
+ OUStringBuffer sSplits;
+ // Create a semi-colon separated string to save the splits
+ sal_uInt32 n = rSplits.Count();
+ for (sal_uInt32 i = 0; i < n; ++i)
+ {
+ sSplits.append(rSplits[i]);
+ sSplits.append(";");
+ }
+
+ OUString sFixedWidthLists = sSplits.makeStringAndClear();
+ Sequence<Any> aValues;
+ Any *pProperties;
+ Sequence<OUString> aNames { FIXED_WIDTH_LIST };
+ ScLinkConfigItem aItem( SEP_PATH );
+
+ aValues = aItem.GetProperties( aNames );
+ pProperties = aValues.getArray();
+ pProperties[0] <<= sFixedWidthLists;
+
+ aItem.PutProperties(aNames, aValues);
+}
+
+ScCsvRuler::ScCsvRuler(const ScCsvLayoutData& rData, ScCsvTableBox* pTableBox)
+ : ScCsvControl(rData)
+ , mpTableBox(pTableBox)
+ , mnPosCursorLast(1)
+ , mnPosMTStart(0)
+ , mnPosMTCurr(0)
+ , mbPosMTMoved(false)
+ , mnSplitSize(0)
+ , mbTracking(false)
+{
+}
+
+void ScCsvRuler::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ ScCsvControl::SetDrawingArea(pDrawingArea);
+
+ UpdateSplitSize();
+
+ Size aSize(1, GetTextHeight() + mnSplitSize + 2);
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+
+ EnableRTL( false ); // RTL
+ InitColors();
+ InitSizeData();
+
+ OutputDevice& rRefDevice = pDrawingArea->get_ref_device();
+ maBackgrDev->SetFont( rRefDevice.GetFont() );
+ maRulerDev->SetFont( rRefDevice.GetFont() );
+ load_FixedWidthList( maSplits );
+}
+
+ScCsvRuler::~ScCsvRuler()
+{
+ save_FixedWidthList( maSplits );
+}
+
+// common ruler handling ------------------------------------------------------
+
+void ScCsvRuler::ApplyLayout( const ScCsvLayoutData& rOldData )
+{
+ ScCsvDiff nDiff = GetLayoutData().GetDiff( rOldData ) & (ScCsvDiff::HorizontalMask | ScCsvDiff::RulerCursor);
+ if( nDiff == ScCsvDiff::Equal ) return;
+
+ DisableRepaint();
+ if( nDiff & ScCsvDiff::HorizontalMask )
+ {
+ InitSizeData();
+ if( GetRulerCursorPos() >= GetPosCount() )
+ MoveCursor( GetPosCount() - 1 );
+ }
+ if( nDiff & ScCsvDiff::RulerCursor )
+ {
+ ImplInvertCursor( rOldData.mnPosCursor );
+ ImplInvertCursor( GetRulerCursorPos() );
+ }
+ EnableRepaint();
+
+ if( nDiff & ScCsvDiff::PosOffset )
+ AccSendVisibleEvent();
+}
+
+void ScCsvRuler::InitColors()
+{
+ const StyleSettings& rSett = Application::GetSettings().GetStyleSettings();
+ maBackColor = rSett.GetFaceColor();
+ maActiveColor = rSett.GetWindowColor();
+ maTextColor = rSett.GetLabelTextColor();
+ maSplitColor = maBackColor.IsDark() ? maTextColor : COL_LIGHTRED;
+ InvalidateGfx();
+}
+
+void ScCsvRuler::UpdateSplitSize()
+{
+ mnSplitSize = (GetCharWidth() * 3 / 5) | 1; // make an odd number
+}
+
+void ScCsvRuler::InitSizeData()
+{
+ maWinSize = GetOutputSizePixel();
+
+ UpdateSplitSize();
+
+ sal_Int32 nActiveWidth = std::min( GetWidth() - GetHdrWidth(), GetPosCount() * GetCharWidth() );
+ sal_Int32 nActiveHeight = GetTextHeight();
+
+ maActiveRect.SetPos( Point( GetFirstX(), (GetHeight() - nActiveHeight - 1) / 2 ) );
+ maActiveRect.SetSize( Size( nActiveWidth, nActiveHeight ) );
+
+ maBackgrDev->SetOutputSizePixel( maWinSize );
+ maRulerDev->SetOutputSizePixel( maWinSize );
+
+ InvalidateGfx();
+}
+
+void ScCsvRuler::MoveCursor( sal_Int32 nPos, bool bScroll )
+{
+ DisableRepaint();
+ if( bScroll )
+ Execute( CSVCMD_MAKEPOSVISIBLE, nPos );
+ Execute( CSVCMD_MOVERULERCURSOR, IsVisibleSplitPos( nPos ) ? nPos : CSV_POS_INVALID );
+ EnableRepaint();
+ AccSendCaretEvent();
+}
+
+void ScCsvRuler::MoveCursorRel( ScMoveMode eDir )
+{
+ if( GetRulerCursorPos() == CSV_POS_INVALID )
+ return;
+
+ switch( eDir )
+ {
+ case MOVE_FIRST:
+ MoveCursor( 1 );
+ break;
+ case MOVE_LAST:
+ MoveCursor( GetPosCount() - 1 );
+ break;
+ case MOVE_PREV:
+ if( GetRulerCursorPos() > 1 )
+ MoveCursor( GetRulerCursorPos() - 1 );
+ break;
+ case MOVE_NEXT:
+ if( GetRulerCursorPos() < GetPosCount() - 1 )
+ MoveCursor( GetRulerCursorPos() + 1 );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
+void ScCsvRuler::MoveCursorToSplit( ScMoveMode eDir )
+{
+ if( GetRulerCursorPos() == CSV_POS_INVALID )
+ return;
+
+ sal_uInt32 nIndex = CSV_VEC_NOTFOUND;
+ switch( eDir )
+ {
+ case MOVE_FIRST: nIndex = maSplits.LowerBound( 0 ); break;
+ case MOVE_LAST: nIndex = maSplits.UpperBound( GetPosCount() ); break;
+ case MOVE_PREV: nIndex = maSplits.UpperBound( GetRulerCursorPos() - 1 ); break;
+ case MOVE_NEXT: nIndex = maSplits.LowerBound( GetRulerCursorPos() + 1 ); break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ sal_Int32 nPos = maSplits[ nIndex ];
+ if( nPos != CSV_POS_INVALID )
+ MoveCursor( nPos );
+}
+
+void ScCsvRuler::ScrollVertRel( ScMoveMode eDir )
+{
+ sal_Int32 nLine = GetFirstVisLine();
+ switch( eDir )
+ {
+ case MOVE_PREV: --nLine; break;
+ case MOVE_NEXT: ++nLine; break;
+ case MOVE_PREVPAGE: nLine -= GetVisLineCount() - 1; break;
+ case MOVE_NEXTPAGE: nLine += GetVisLineCount() - 1; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ Execute( CSVCMD_SETLINEOFFSET, nLine );
+}
+
+// split handling -------------------------------------------------------------
+
+sal_Int32 ScCsvRuler::GetNoScrollPos( sal_Int32 nPos ) const
+{
+ sal_Int32 nNewPos = nPos;
+ if( nNewPos != CSV_POS_INVALID )
+ {
+ if( nNewPos < GetFirstVisPos() + CSV_SCROLL_DIST )
+ {
+ sal_Int32 nScroll = (GetFirstVisPos() > 0) ? CSV_SCROLL_DIST : 0;
+ nNewPos = std::max( nPos, GetFirstVisPos() + nScroll );
+ }
+ else if( nNewPos > GetLastVisPos() - CSV_SCROLL_DIST - 1 )
+ {
+ sal_Int32 nScroll = (GetFirstVisPos() < GetMaxPosOffset()) ? CSV_SCROLL_DIST : 0;
+ nNewPos = std::min( nNewPos, GetLastVisPos() - nScroll - sal_Int32( 1 ) );
+ }
+ }
+ return nNewPos;
+}
+
+void ScCsvRuler::InsertSplit( sal_Int32 nPos )
+{
+ if( maSplits.Insert( nPos ) )
+ {
+ ImplDrawSplit( nPos );
+ Repaint();
+ }
+}
+
+void ScCsvRuler::RemoveSplit( sal_Int32 nPos )
+{
+ if( maSplits.Remove( nPos ) )
+ {
+ ImplEraseSplit( nPos );
+ Repaint();
+ }
+}
+
+void ScCsvRuler::MoveSplit( sal_Int32 nPos, sal_Int32 nNewPos )
+{
+ bool bRemove = maSplits.Remove( nPos );
+ bool bInsert = maSplits.Insert( nNewPos );
+ if( bRemove || bInsert )
+ {
+ ImplEraseSplit( nPos );
+ ImplDrawSplit( nNewPos );
+ Repaint();
+ }
+}
+
+void ScCsvRuler::RemoveAllSplits()
+{
+ maSplits.Clear();
+ Repaint( true );
+}
+
+sal_Int32 ScCsvRuler::FindEmptyPos( sal_Int32 nPos, ScMoveMode eDir ) const
+{
+ sal_Int32 nNewPos = nPos;
+ if( nNewPos != CSV_POS_INVALID )
+ {
+ switch( eDir )
+ {
+ case MOVE_FIRST:
+ nNewPos = std::min( nPos, FindEmptyPos( 0, MOVE_NEXT ) );
+ break;
+ case MOVE_LAST:
+ nNewPos = std::max( nPos, FindEmptyPos( GetPosCount(), MOVE_PREV ) );
+ break;
+ case MOVE_PREV:
+ while( HasSplit( --nNewPos ) ) ;
+ break;
+ case MOVE_NEXT:
+ while( HasSplit( ++nNewPos ) ) ;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ return IsValidSplitPos( nNewPos ) ? nNewPos : CSV_POS_INVALID;
+}
+
+void ScCsvRuler::MoveCurrSplit( sal_Int32 nNewPos )
+{
+ DisableRepaint();
+ Execute( CSVCMD_MOVESPLIT, GetRulerCursorPos(), nNewPos );
+ MoveCursor( nNewPos );
+ EnableRepaint();
+}
+
+void ScCsvRuler::MoveCurrSplitRel( ScMoveMode eDir )
+{
+ if( HasSplit( GetRulerCursorPos() ) )
+ {
+ sal_Int32 nNewPos = FindEmptyPos( GetRulerCursorPos(), eDir );
+ if( nNewPos != CSV_POS_INVALID )
+ MoveCurrSplit( nNewPos );
+ }
+}
+
+// event handling -------------------------------------------------------------
+
+void ScCsvRuler::Resize()
+{
+ ScCsvControl::Resize();
+ InitSizeData();
+ Repaint();
+}
+
+void ScCsvRuler::GetFocus()
+{
+ ScCsvControl::GetFocus();
+ DisableRepaint();
+ if( GetRulerCursorPos() == CSV_POS_INVALID )
+ MoveCursor( GetNoScrollPos( mnPosCursorLast ) );
+ EnableRepaint();
+}
+
+void ScCsvRuler::LoseFocus()
+{
+ ScCsvControl::LoseFocus();
+ mnPosCursorLast = GetRulerCursorPos();
+ MoveCursor( CSV_POS_INVALID );
+}
+
+void ScCsvRuler::StyleUpdated()
+{
+ InitColors();
+ Repaint();
+
+ ScCsvControl::StyleUpdated();
+}
+
+bool ScCsvRuler::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ DisableRepaint();
+ if( !HasFocus() )
+ GrabFocus();
+ if( rMEvt.IsLeft() )
+ {
+ sal_Int32 nPos = GetPosFromX( rMEvt.GetPosPixel().X() );
+ if( IsVisibleSplitPos( nPos ) )
+ StartMouseTracking( nPos );
+ ImplSetMousePointer( nPos );
+ }
+ EnableRepaint();
+ return true;
+}
+
+bool ScCsvRuler::MouseButtonUp( const MouseEvent& )
+{
+ if (mbTracking)
+ {
+ EndMouseTracking();
+ mbTracking = false;
+ }
+ return true;
+}
+
+bool ScCsvRuler::MouseMove( const MouseEvent& rMEvt )
+{
+ if( !rMEvt.IsModifierChanged() )
+ {
+ sal_Int32 nPos = GetPosFromX( rMEvt.GetPosPixel().X() );
+ if( mbTracking )
+ {
+ // on mouse tracking: keep position valid
+ nPos = std::clamp( nPos, sal_Int32(1), GetPosCount() - 1 );
+ MoveMouseTracking( nPos );
+ }
+ else
+ {
+ tools::Rectangle aRect( Point(), maWinSize );
+ if( !IsVisibleSplitPos( nPos ) || !aRect.Contains( rMEvt.GetPosPixel() ) )
+ // if focused, keep old cursor position for key input
+ nPos = HasFocus() ? GetRulerCursorPos() : CSV_POS_INVALID;
+ MoveCursor( nPos, false );
+ }
+ ImplSetMousePointer( nPos );
+ }
+ return true;
+}
+
+bool ScCsvRuler::KeyInput( const KeyEvent& rKEvt )
+{
+ const vcl::KeyCode& rKCode = rKEvt.GetKeyCode();
+ sal_uInt16 nCode = rKCode.GetCode();
+ bool bNoMod = !rKCode.GetModifier();
+ bool bShift = (rKCode.GetModifier() == KEY_SHIFT);
+ bool bJump = (rKCode.GetModifier() == KEY_MOD1);
+ bool bMove = (rKCode.GetModifier() == (KEY_MOD1 | KEY_SHIFT));
+
+ ScMoveMode eHDir = GetHorzDirection( nCode, true );
+ ScMoveMode eVDir = GetVertDirection( nCode, false );
+
+ if( bNoMod )
+ {
+ if( eHDir != MOVE_NONE )
+ MoveCursorRel( eHDir );
+ else if( eVDir != MOVE_NONE )
+ ScrollVertRel( eVDir );
+ else switch( nCode )
+ {
+ case KEY_SPACE: Execute( CSVCMD_TOGGLESPLIT, GetRulerCursorPos() ); break;
+ case KEY_INSERT: Execute( CSVCMD_INSERTSPLIT, GetRulerCursorPos() ); break;
+ case KEY_DELETE: Execute( CSVCMD_REMOVESPLIT, GetRulerCursorPos() ); break;
+ }
+ }
+ else if( bJump && (eHDir != MOVE_NONE) )
+ MoveCursorToSplit( eHDir );
+ else if( bMove && (eHDir != MOVE_NONE) )
+ MoveCurrSplitRel( eHDir );
+ else if( bShift && (nCode == KEY_DELETE) )
+ Execute( CSVCMD_REMOVEALLSPLITS );
+
+ return rKCode.GetGroup() == KEYGROUP_CURSOR;
+}
+
+void ScCsvRuler::StartMouseTracking( sal_Int32 nPos )
+{
+ mnPosMTStart = mnPosMTCurr = nPos;
+ mbPosMTMoved = false;
+ maOldSplits = maSplits;
+ Execute( CSVCMD_INSERTSPLIT, nPos );
+ if( HasSplit( nPos ) )
+ mbTracking = true;
+}
+
+void ScCsvRuler::MoveMouseTracking( sal_Int32 nPos )
+{
+ if( mnPosMTCurr != nPos )
+ {
+ DisableRepaint();
+ MoveCursor( nPos );
+ if( (mnPosMTCurr != mnPosMTStart) && maOldSplits.HasSplit( mnPosMTCurr ) )
+ Execute( CSVCMD_INSERTSPLIT, nPos );
+ else
+ Execute( CSVCMD_MOVESPLIT, mnPosMTCurr, nPos );
+ mnPosMTCurr = nPos;
+ mbPosMTMoved = true;
+ EnableRepaint();
+ }
+}
+
+void ScCsvRuler::EndMouseTracking()
+{
+ // remove on simple click on an existing split
+ if( (mnPosMTCurr == mnPosMTStart) && maOldSplits.HasSplit( mnPosMTCurr ) && !mbPosMTMoved )
+ Execute( CSVCMD_REMOVESPLIT, mnPosMTCurr );
+ mnPosMTStart = CSV_POS_INVALID;
+}
+
+// painting -------------------------------------------------------------------
+
+void ScCsvRuler::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& )
+{
+ ImplRedraw(rRenderContext);
+}
+
+void ScCsvRuler::ImplRedraw(vcl::RenderContext& rRenderContext)
+{
+ if( IsVisible() )
+ {
+ if( !IsValidGfx() )
+ {
+ ValidateGfx();
+ ImplDrawBackgrDev();
+ ImplDrawRulerDev();
+ }
+ rRenderContext.DrawOutDev( Point(), maWinSize, Point(), maWinSize, *maRulerDev );
+ }
+}
+
+tools::Rectangle ScCsvRuler::GetFocusRect()
+{
+ /* Draws directly tracking rectangle to the column with the specified index. */
+ if(HasFocus())
+ return tools::Rectangle(0, 0, GetWidth() - 1, GetHeight() - 2);
+ return weld::CustomWidgetController::GetFocusRect();
+}
+
+void ScCsvRuler::ImplDrawArea( sal_Int32 nPosX, sal_Int32 nWidth )
+{
+ maBackgrDev->SetLineColor();
+ tools::Rectangle aRect( Point( nPosX, 0 ), Size( nWidth, GetHeight() ) );
+ maBackgrDev->SetFillColor( maBackColor );
+ maBackgrDev->DrawRect( aRect );
+
+ aRect = maActiveRect;
+ aRect.SetLeft( std::max( GetFirstX(), nPosX ) );
+ aRect.SetRight( std::min( std::min( GetX( GetPosCount() ), GetLastX() ), nPosX + nWidth - sal_Int32( 1 ) ) );
+ if( aRect.Left() <= aRect.Right() )
+ {
+ maBackgrDev->SetFillColor( maActiveColor );
+ maBackgrDev->DrawRect( aRect );
+ }
+
+ maBackgrDev->SetLineColor( maTextColor );
+ sal_Int32 nY = GetHeight() - 1;
+ maBackgrDev->DrawLine( Point( nPosX, nY ), Point( nPosX + nWidth - 1, nY ) );
+}
+
+void ScCsvRuler::ImplDrawBackgrDev()
+{
+ ImplDrawArea( 0, GetWidth() );
+
+ // scale
+ maBackgrDev->SetLineColor( maTextColor );
+ maBackgrDev->SetFillColor();
+ sal_Int32 nPos;
+
+ sal_Int32 nFirstPos = std::max( GetPosFromX( 0 ) - 1, sal_Int32(0) );
+ sal_Int32 nLastPos = GetPosFromX( GetWidth() );
+ sal_Int32 nY = (maActiveRect.Top() + maActiveRect.Bottom()) / 2;
+ for( nPos = nFirstPos; nPos <= nLastPos; ++nPos )
+ {
+ sal_Int32 nX = GetX( nPos );
+ if( nPos % 5 )
+ maBackgrDev->DrawPixel( Point( nX, nY ) );
+ else
+ maBackgrDev->DrawLine( Point( nX, nY - 1 ), Point( nX, nY + 1 ) );
+ }
+
+ // texts
+ maBackgrDev->SetTextColor( maTextColor );
+ maBackgrDev->SetTextFillColor();
+ for( nPos = ((nFirstPos + 9) / 10) * 10; nPos <= nLastPos; nPos += 10 )
+ {
+ OUString aText( OUString::number( nPos ) );
+ sal_Int32 nTextWidth = maBackgrDev->GetTextWidth( aText );
+ sal_Int32 nTextX = GetX( nPos ) - nTextWidth / 2;
+ ImplDrawArea( nTextX - 1, nTextWidth + 2 );
+ maBackgrDev->DrawText( Point( nTextX, maActiveRect.Top() ), aText );
+ }
+}
+
+void ScCsvRuler::ImplDrawSplit( sal_Int32 nPos )
+{
+ if( IsVisibleSplitPos( nPos ) )
+ {
+ Point aPos( GetX( nPos ) - mnSplitSize / 2, GetHeight() - mnSplitSize - 2 );
+ Size aSize( mnSplitSize, mnSplitSize );
+ maRulerDev->SetLineColor( maTextColor );
+ maRulerDev->SetFillColor( maSplitColor );
+ maRulerDev->DrawEllipse( tools::Rectangle( aPos, aSize ) );
+ maRulerDev->DrawPixel( Point( GetX( nPos ), GetHeight() - 2 ) );
+ }
+}
+
+void ScCsvRuler::ImplEraseSplit( sal_Int32 nPos )
+{
+ if( IsVisibleSplitPos( nPos ) )
+ {
+ ImplInvertCursor( GetRulerCursorPos() );
+ Point aPos( GetX( nPos ) - mnSplitSize / 2, 0 );
+ Size aSize( mnSplitSize, GetHeight() );
+ maRulerDev->DrawOutDev( aPos, aSize, aPos, aSize, *maBackgrDev );
+ ImplInvertCursor( GetRulerCursorPos() );
+ }
+}
+
+void ScCsvRuler::ImplDrawRulerDev()
+{
+ maRulerDev->DrawOutDev( Point(), maWinSize, Point(), maWinSize, *maBackgrDev );
+ ImplInvertCursor( GetRulerCursorPos() );
+
+ sal_uInt32 nFirst = maSplits.LowerBound( GetFirstVisPos() );
+ sal_uInt32 nLast = maSplits.UpperBound( GetLastVisPos() );
+ if( (nFirst != CSV_VEC_NOTFOUND) && (nLast != CSV_VEC_NOTFOUND) )
+ for( sal_uInt32 nIndex = nFirst; nIndex <= nLast; ++nIndex )
+ ImplDrawSplit( GetSplitPos( nIndex ) );
+}
+
+void ScCsvRuler::ImplInvertCursor( sal_Int32 nPos )
+{
+ if( IsVisibleSplitPos( nPos ) )
+ {
+ ImplInvertRect( *maRulerDev, tools::Rectangle( Point( GetX( nPos ) - 1, 0 ), Size( 3, GetHeight() - 1 ) ) );
+ if( HasSplit( nPos ) )
+ ImplDrawSplit( nPos );
+ }
+}
+
+void ScCsvRuler::ImplSetMousePointer( sal_Int32 nPos )
+{
+ SetPointer( HasSplit( nPos ) ? PointerStyle::HSplit : PointerStyle::Arrow );
+}
+
+// accessibility ==============================================================
+
+css::uno::Reference<css::accessibility::XAccessible> ScCsvRuler::CreateAccessible()
+{
+ rtl::Reference<ScAccessibleCsvRuler> xRef(new ScAccessibleCsvRuler(*this));
+ mxAccessible = xRef;
+ return xRef;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/csvsplits.cxx b/sc/source/ui/dbgui/csvsplits.cxx
new file mode 100644
index 000000000..575bd53d0
--- /dev/null
+++ b/sc/source/ui/dbgui/csvsplits.cxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <csvsplits.hxx>
+
+#include <algorithm>
+
+#include <sal/log.hxx>
+
+bool ScCsvSplits::Insert( sal_Int32 nPos )
+{
+ if (nPos < 0)
+ return false;
+
+ const auto aIter = ::std::lower_bound( maVec.begin(), maVec.end(), nPos );
+
+ if (aIter != maVec.end() && *aIter == nPos)
+ return false;
+
+ SAL_WARN_IF(maVec.size()>=static_cast<std::size_t>(SAL_MAX_UINT32-1),
+ "sc.ui", "ScCsvSplits::Insert: too many elements in vector");
+
+ maVec.insert( aIter, nPos );
+ return true;
+}
+
+bool ScCsvSplits::Remove( sal_Int32 nPos )
+{
+ sal_uInt32 nIndex = GetIndex( nPos );
+ if (nIndex == CSV_VEC_NOTFOUND)
+ return false;
+
+ maVec.erase( maVec.begin() + nIndex );
+ return true;
+}
+
+void ScCsvSplits::RemoveRange( sal_Int32 nPosStart, sal_Int32 nPosEnd )
+{
+ sal_uInt32 nStartIx = LowerBound( nPosStart );
+ sal_uInt32 nEndIx = UpperBound( nPosEnd );
+ if( (nStartIx != CSV_VEC_NOTFOUND) && (nEndIx != CSV_VEC_NOTFOUND) && (nStartIx <= nEndIx) )
+ maVec.erase( maVec.begin() + nStartIx, maVec.begin() + nEndIx + 1 );
+}
+
+void ScCsvSplits::Clear()
+{
+ maVec.clear();
+}
+
+bool ScCsvSplits::HasSplit( sal_Int32 nPos ) const
+{
+ return GetIndex( nPos ) != CSV_VEC_NOTFOUND;
+}
+
+sal_uInt32 ScCsvSplits::GetIndex( sal_Int32 nPos ) const
+{
+ auto aIter = ::std::lower_bound( maVec.cbegin(), maVec.cend(), nPos );
+ return GetIterIndex( ((aIter != maVec.end()) && (*aIter == nPos)) ? aIter : maVec.end() );
+}
+
+sal_uInt32 ScCsvSplits::LowerBound( sal_Int32 nPos ) const
+{
+ return GetIterIndex( ::std::lower_bound( maVec.begin(), maVec.end(), nPos ) );
+}
+
+sal_uInt32 ScCsvSplits::UpperBound( sal_Int32 nPos ) const
+{
+ sal_uInt32 nIndex = LowerBound( nPos );
+ if( nIndex == CSV_VEC_NOTFOUND )
+ return Count() ? (Count() - 1) : CSV_VEC_NOTFOUND;
+ if( GetPos( nIndex ) == nPos )
+ return nIndex;
+ return nIndex ? (nIndex - 1) : CSV_VEC_NOTFOUND;
+}
+
+sal_Int32 ScCsvSplits::GetPos( sal_uInt32 nIndex ) const
+{
+ return (nIndex < Count()) ? maVec[ nIndex ] : CSV_POS_INVALID;
+}
+
+sal_uInt32 ScCsvSplits::GetIterIndex( const_iterator const & aIter ) const
+{
+ return (aIter == maVec.end()) ? CSV_VEC_NOTFOUND : (aIter - maVec.begin());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/csvtablebox.cxx b/sc/source/ui/dbgui/csvtablebox.cxx
new file mode 100644
index 000000000..10dba1b81
--- /dev/null
+++ b/sc/source/ui/dbgui/csvtablebox.cxx
@@ -0,0 +1,369 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <csvtablebox.hxx>
+#include <vcl/settings.hxx>
+
+ScCsvTableBox::ScCsvTableBox(weld::Builder& rBuilder)
+ : mxRuler(new ScCsvRuler(maData, this))
+ , mxGrid(new ScCsvGrid(maData, rBuilder.weld_menu("popup"), this))
+ , mxScroll(rBuilder.weld_scrolled_window("scrolledwindow", true))
+ , mxRulerWeld(new weld::CustomWeld(rBuilder, "csvruler", *mxRuler))
+ , mxGridWeld(new weld::CustomWeld(rBuilder, "csvgrid", *mxGrid))
+ , maEndScrollIdle("ScCsvTableBox maEndScrollIdle")
+{
+ Size aSize(mxScroll->get_approximate_digit_width() * 67,
+ mxScroll->get_text_height() * 10);
+ // this needs to be larger than the ScCsvGrid initial size to get it
+ // to stretch to fit, see ScCsvGrid::SetDrawingArea
+ mxScroll->set_size_request(aSize.Width(), aSize.Height());
+
+ mbFixedMode = false;
+ mnFixedWidth = 1;
+
+ Link<ScCsvControl&,void> aLink = LINK( this, ScCsvTableBox, CsvCmdHdl );
+ mxRuler->SetCmdHdl( aLink );
+ mxGrid->SetCmdHdl( aLink );
+
+ mxScroll->connect_hadjustment_changed(LINK(this, ScCsvTableBox, HScrollHdl));
+ mxScroll->connect_vadjustment_changed(LINK(this, ScCsvTableBox, VScrollHdl));
+
+ maEndScrollIdle.SetPriority(TaskPriority::LOWEST);
+ maEndScrollIdle.SetInvokeHandler(LINK(this,ScCsvTableBox,ScrollEndHdl));
+
+ InitControls();
+}
+
+ScCsvTableBox::~ScCsvTableBox()
+{
+}
+
+// common table box handling --------------------------------------------------
+
+void ScCsvTableBox::SetSeparatorsMode()
+{
+ if( !mbFixedMode )
+ return;
+
+ // rescue data for fixed width mode
+ mnFixedWidth = mxGrid->GetPosCount();
+ maFixColStates = mxGrid->GetColumnStates();
+ // switch to separators mode
+ mbFixedMode = false;
+ // reset and reinitialize controls
+ mxGrid->DisableRepaint();
+ mxGrid->Execute( CSVCMD_SETLINEOFFSET, 0 );
+ mxGrid->Execute( CSVCMD_SETPOSCOUNT, 1 );
+ mxGrid->Execute( CSVCMD_NEWCELLTEXTS );
+ mxGrid->SetColumnStates( std::vector(maSepColStates) );
+ InitControls();
+ mxGrid->EnableRepaint();
+}
+
+void ScCsvTableBox::SetFixedWidthMode()
+{
+ if( mbFixedMode )
+ return;
+
+ // rescue data for separators mode
+ maSepColStates = mxGrid->GetColumnStates();
+ // switch to fixed width mode
+ mbFixedMode = true;
+ // reset and reinitialize controls
+ mxGrid->DisableRepaint();
+ mxGrid->Execute( CSVCMD_SETLINEOFFSET, 0 );
+ mxGrid->Execute( CSVCMD_SETPOSCOUNT, mnFixedWidth );
+ mxGrid->SetSplits( mxRuler->GetSplits() );
+ mxGrid->SetColumnStates( std::vector(maFixColStates) );
+ InitControls();
+ mxGrid->EnableRepaint();
+}
+
+void ScCsvTableBox::Init()
+{
+ mxGrid->Init();
+}
+
+void ScCsvTableBox::InitControls()
+{
+ mxGrid->UpdateLayoutData();
+
+ mxGrid->Show();
+ if (mbFixedMode)
+ mxRuler->Show();
+ else
+ mxRuler->Hide();
+
+ Size aWinSize = mxGrid->GetOutputSizePixel();
+ maData.mnWinWidth = aWinSize.Width();
+ maData.mnWinHeight = aWinSize.Height();
+
+ // scrollbars always visible
+ InitHScrollBar();
+
+ // scrollbars always visible
+ InitVScrollBar();
+
+ // let the controls self-adjust to visible area
+ mxGrid->Execute( CSVCMD_SETPOSOFFSET, mxGrid->GetFirstVisPos() );
+ mxGrid->Execute( CSVCMD_SETLINEOFFSET, mxGrid->GetFirstVisLine() );
+}
+
+void ScCsvTableBox::InitHScrollBar()
+{
+ int nLower = 0;
+ int nValue = mxGrid->GetFirstVisPos();
+ int nUpper = mxGrid->GetPosCount() + 2;
+ int nPageSize = mxGrid->GetVisPosCount();
+
+ // Undo scrollbar RTL
+ if (AllSettings::GetLayoutRTL())
+ nValue = nUpper - (nValue - nLower + nPageSize);
+
+ mxScroll->hadjustment_configure(nValue, nLower, nUpper,
+ 1, mxGrid->GetVisPosCount() * 3 / 4,
+ nPageSize);
+}
+
+void ScCsvTableBox::InitVScrollBar()
+{
+ mxScroll->vadjustment_configure(mxGrid->GetFirstVisLine(), 0, mxGrid->GetLineCount() + 1,
+ 1, mxGrid->GetVisLineCount() - 2,
+ mxGrid->GetVisLineCount());
+}
+
+void ScCsvTableBox::MakePosVisible( sal_Int32 nPos )
+{
+ if( (0 <= nPos) && (nPos < mxGrid->GetPosCount()) )
+ {
+ if( nPos - CSV_SCROLL_DIST + 1 <= mxGrid->GetFirstVisPos() )
+ mxGrid->Execute( CSVCMD_SETPOSOFFSET, nPos - CSV_SCROLL_DIST );
+ else if( nPos + CSV_SCROLL_DIST >= mxGrid->GetLastVisPos() )
+ mxGrid->Execute( CSVCMD_SETPOSOFFSET, nPos - mxGrid->GetVisPosCount() + CSV_SCROLL_DIST );
+ }
+}
+
+// cell contents --------------------------------------------------------------
+
+void ScCsvTableBox::SetUniStrings(
+ const OUString* pTextLines, const OUString& rSepChars,
+ sal_Unicode cTextSep, bool bMergeSep, bool bRemoveSpace )
+{
+ // assuming that pTextLines is a string array with size CSV_PREVIEW_LINES
+ // -> will be dynamic sometime
+ mxGrid->DisableRepaint();
+ sal_Int32 nEndLine = mxGrid->GetFirstVisLine() + CSV_PREVIEW_LINES;
+ const OUString* pString = pTextLines;
+ for( sal_Int32 nLine = mxGrid->GetFirstVisLine(); nLine < nEndLine; ++nLine, ++pString )
+ {
+ if( mbFixedMode )
+ mxGrid->ImplSetTextLineFix( nLine, *pString );
+ else
+ mxGrid->ImplSetTextLineSep( nLine, *pString, rSepChars, cTextSep, bMergeSep, bRemoveSpace );
+ }
+ mxGrid->EnableRepaint();
+}
+
+// column settings ------------------------------------------------------------
+
+void ScCsvTableBox::InitTypes(const weld::ComboBox& rListBox)
+{
+ const sal_Int32 nTypeCount = rListBox.get_count();
+ std::vector<OUString> aTypeNames( nTypeCount );
+ for( sal_Int32 nIndex = 0; nIndex < nTypeCount; ++nIndex )
+ aTypeNames[ nIndex ] = rListBox.get_text( nIndex );
+ mxGrid->SetTypeNames( std::move(aTypeNames) );
+}
+
+void ScCsvTableBox::FillColumnData( ScAsciiOptions& rOptions ) const
+{
+ if( mbFixedMode )
+ mxGrid->FillColumnDataFix( rOptions );
+ else
+ mxGrid->FillColumnDataSep( rOptions );
+}
+
+// event handling -------------------------------------------------------------
+
+IMPL_LINK( ScCsvTableBox, CsvCmdHdl, ScCsvControl&, rCtrl, void )
+{
+ const ScCsvCmd& rCmd = rCtrl.GetCmd();
+ ScCsvCmdType eType = rCmd.GetType();
+ sal_Int32 nParam1 = rCmd.GetParam1();
+ sal_Int32 nParam2 = rCmd.GetParam2();
+
+ bool bFound = true;
+ switch( eType )
+ {
+ case CSVCMD_REPAINT:
+ if( !mxGrid->IsNoRepaint() )
+ {
+ mxGrid->Invalidate();
+ mxRuler->Invalidate();
+ InitHScrollBar();
+ InitVScrollBar();
+ }
+ break;
+ case CSVCMD_MAKEPOSVISIBLE:
+ MakePosVisible( nParam1 );
+ break;
+
+ case CSVCMD_NEWCELLTEXTS:
+ if( mbFixedMode )
+ mxGrid->Execute( CSVCMD_UPDATECELLTEXTS );
+ else
+ {
+ mxGrid->DisableRepaint();
+ ScCsvColStateVec aStates( mxGrid->GetColumnStates() );
+ sal_Int32 nPos = mxGrid->GetFirstVisPos();
+ mxGrid->Execute( CSVCMD_SETPOSCOUNT, 1 );
+ mxGrid->Execute( CSVCMD_UPDATECELLTEXTS );
+ mxGrid->Execute( CSVCMD_SETPOSOFFSET, nPos );
+ mxGrid->SetColumnStates( std::move(aStates) );
+ mxGrid->EnableRepaint();
+ }
+ break;
+ case CSVCMD_UPDATECELLTEXTS:
+ maUpdateTextHdl.Call( *this );
+ break;
+ case CSVCMD_SETCOLUMNTYPE:
+ mxGrid->SetSelColumnType( nParam1 );
+ break;
+ case CSVCMD_EXPORTCOLUMNTYPE:
+ maColTypeHdl.Call( *this );
+ break;
+ case CSVCMD_SETFIRSTIMPORTLINE:
+ mxGrid->SetFirstImportedLine( nParam1 );
+ break;
+
+ case CSVCMD_INSERTSPLIT:
+ OSL_ENSURE( mbFixedMode, "ScCsvTableBox::CsvCmdHdl::InsertSplit - invalid call" );
+ if( mxRuler->GetSplitCount() + 1 < sal::static_int_cast<sal_uInt32>(CSV_MAXCOLCOUNT) )
+ {
+ mxRuler->InsertSplit( nParam1 );
+ mxGrid->InsertSplit( nParam1 );
+ }
+ break;
+ case CSVCMD_REMOVESPLIT:
+ OSL_ENSURE( mbFixedMode, "ScCsvTableBox::CsvCmdHdl::RemoveSplit - invalid call" );
+ mxRuler->RemoveSplit( nParam1 );
+ mxGrid->RemoveSplit( nParam1 );
+ break;
+ case CSVCMD_TOGGLESPLIT:
+ mxGrid->Execute( mxRuler->HasSplit( nParam1 ) ? CSVCMD_REMOVESPLIT : CSVCMD_INSERTSPLIT, nParam1 );
+ break;
+ case CSVCMD_MOVESPLIT:
+ OSL_ENSURE( mbFixedMode, "ScCsvTableBox::CsvCmdHdl::MoveSplit - invalid call" );
+ mxRuler->MoveSplit( nParam1, nParam2 );
+ mxGrid->MoveSplit( nParam1, nParam2 );
+ break;
+ case CSVCMD_REMOVEALLSPLITS:
+ OSL_ENSURE( mbFixedMode, "ScCsvTableBox::CsvCmdHdl::RemoveAllSplits - invalid call" );
+ mxRuler->RemoveAllSplits();
+ mxGrid->RemoveAllSplits();
+ break;
+ default:
+ bFound = false;
+ }
+ if( bFound )
+ return;
+
+ const ScCsvLayoutData aOldData( maData );
+ switch( eType )
+ {
+ case CSVCMD_SETPOSCOUNT:
+ maData.mnPosCount = std::max( nParam1, sal_Int32( 1 ) );
+ ImplSetPosOffset( mxGrid->GetFirstVisPos() );
+ break;
+ case CSVCMD_SETPOSOFFSET:
+ ImplSetPosOffset( nParam1 );
+ break;
+ case CSVCMD_SETHDRWIDTH:
+ maData.mnHdrWidth = std::max( nParam1, sal_Int32( 0 ) );
+ ImplSetPosOffset( mxGrid->GetFirstVisPos() );
+ break;
+ case CSVCMD_SETCHARWIDTH:
+ maData.mnCharWidth = std::max( nParam1, sal_Int32( 1 ) );
+ ImplSetPosOffset( mxGrid->GetFirstVisPos() );
+ break;
+ case CSVCMD_SETLINECOUNT:
+ maData.mnLineCount = std::max( nParam1, sal_Int32( 1 ) );
+ ImplSetLineOffset( mxGrid->GetFirstVisLine() );
+ break;
+ case CSVCMD_SETLINEOFFSET:
+ ImplSetLineOffset( nParam1 );
+ break;
+ case CSVCMD_SETHDRHEIGHT:
+ maData.mnHdrHeight = std::max( nParam1, sal_Int32( 0 ) );
+ ImplSetLineOffset( mxGrid->GetFirstVisLine() );
+ break;
+ case CSVCMD_SETLINEHEIGHT:
+ maData.mnLineHeight = std::max( nParam1, sal_Int32( 1 ) );
+ ImplSetLineOffset( mxGrid->GetFirstVisLine() );
+ break;
+ case CSVCMD_MOVERULERCURSOR:
+ maData.mnPosCursor = mxGrid->IsVisibleSplitPos( nParam1 ) ? nParam1 : CSV_POS_INVALID;
+ break;
+ case CSVCMD_MOVEGRIDCURSOR:
+ maData.mnColCursor = ((0 <= nParam1) && (nParam1 < mxGrid->GetPosCount())) ? nParam1 : CSV_POS_INVALID;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if( maData != aOldData )
+ {
+ mxGrid->DisableRepaint();
+ mxRuler->ApplyLayout( aOldData );
+ mxGrid->ApplyLayout( aOldData );
+ mxGrid->EnableRepaint();
+ }
+}
+
+IMPL_LINK(ScCsvTableBox, HScrollHdl, weld::ScrolledWindow&, rScroll, void)
+{
+ int nLower = 0;
+ int nValue = rScroll.hadjustment_get_value();
+ int nUpper = mxGrid->GetPosCount() + 2;
+ int nPageSize = mxGrid->GetVisPosCount();
+
+ // Undo scrollbar RTL
+ if (AllSettings::GetLayoutRTL())
+ nValue = nUpper - (nValue - nLower + nPageSize);
+
+ mxGrid->Execute(CSVCMD_SETPOSOFFSET, nValue);
+ maEndScrollIdle.Start();
+}
+
+IMPL_LINK(ScCsvTableBox, VScrollHdl, weld::ScrolledWindow&, rScroll, void)
+{
+ mxGrid->Execute(CSVCMD_SETLINEOFFSET, rScroll.vadjustment_get_value());
+}
+
+IMPL_LINK_NOARG(ScCsvTableBox, ScrollEndHdl, Timer*, void)
+{
+ if( mxGrid->GetRulerCursorPos() != CSV_POS_INVALID )
+ mxGrid->Execute( CSVCMD_MOVERULERCURSOR, mxRuler->GetNoScrollPos( mxGrid->GetRulerCursorPos() ) );
+ if( mxGrid->GetGridCursorPos() != CSV_POS_INVALID )
+ mxGrid->Execute( CSVCMD_MOVEGRIDCURSOR, mxGrid->GetNoScrollCol( mxGrid->GetGridCursorPos() ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/dapidata.cxx b/sc/source/ui/dbgui/dapidata.cxx
new file mode 100644
index 000000000..198d82783
--- /dev/null
+++ b/sc/source/ui/dbgui/dapidata.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <comphelper/processfactory.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/sheet/DataImportMode.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+
+using namespace com::sun::star;
+
+#include <dapidata.hxx>
+#include <dpsdbtab.hxx>
+
+// entries in the "type" ListBox
+#define DP_TYPELIST_TABLE 0
+#define DP_TYPELIST_QUERY 1
+#define DP_TYPELIST_SQLNAT 3
+
+ScDataPilotDatabaseDlg::ScDataPilotDatabaseDlg(weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/selectdatasource.ui", "SelectDataSourceDialog")
+ , m_xLbDatabase(m_xBuilder->weld_combo_box("database"))
+ , m_xCbObject(m_xBuilder->weld_combo_box("datasource"))
+ , m_xLbType(m_xBuilder->weld_combo_box("type"))
+{
+ weld::WaitObject aWait(pParent); // initializing the database service the first time takes a while
+
+ try
+ {
+ // get database names
+
+ uno::Reference<sdb::XDatabaseContext> xContext = sdb::DatabaseContext::create(
+ comphelper::getProcessComponentContext() );
+ const uno::Sequence<OUString> aNames = xContext->getElementNames();
+ for( const OUString& aName : aNames )
+ {
+ m_xLbDatabase->append_text(aName);
+ }
+ }
+ catch(uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "exception in database");
+ }
+
+ m_xLbDatabase->set_active(0);
+ m_xLbType->set_active(0);
+
+ FillObjects();
+
+ m_xLbDatabase->connect_changed( LINK( this, ScDataPilotDatabaseDlg, SelectHdl ) );
+ m_xLbType->connect_changed( LINK( this, ScDataPilotDatabaseDlg, SelectHdl ) );
+}
+
+ScDataPilotDatabaseDlg::~ScDataPilotDatabaseDlg()
+{
+}
+
+void ScDataPilotDatabaseDlg::GetValues( ScImportSourceDesc& rDesc )
+{
+ const sal_Int32 nSelect = m_xLbType->get_active();
+
+ rDesc.aDBName = m_xLbDatabase->get_active_text();
+ rDesc.aObject = m_xCbObject->get_active_text();
+
+ if (rDesc.aDBName.isEmpty() || rDesc.aObject.isEmpty())
+ rDesc.nType = sheet::DataImportMode_NONE;
+ else if ( nSelect == DP_TYPELIST_TABLE )
+ rDesc.nType = sheet::DataImportMode_TABLE;
+ else if ( nSelect == DP_TYPELIST_QUERY )
+ rDesc.nType = sheet::DataImportMode_QUERY;
+ else
+ rDesc.nType = sheet::DataImportMode_SQL;
+
+ rDesc.bNative = ( nSelect == DP_TYPELIST_SQLNAT );
+}
+
+IMPL_LINK_NOARG(ScDataPilotDatabaseDlg, SelectHdl, weld::ComboBox&, void)
+{
+ FillObjects();
+}
+
+void ScDataPilotDatabaseDlg::FillObjects()
+{
+ m_xCbObject->clear();
+
+ OUString aDatabaseName = m_xLbDatabase->get_active_text();
+ if (aDatabaseName.isEmpty())
+ return;
+
+ const int nSelect = m_xLbType->get_active();
+ if ( nSelect > DP_TYPELIST_QUERY )
+ return; // only tables and queries
+
+ try
+ {
+ // open connection (for tables or queries)
+
+ uno::Reference<sdb::XDatabaseContext> xContext = sdb::DatabaseContext::create(
+ comphelper::getProcessComponentContext() );
+
+ uno::Any aSourceAny = xContext->getByName( aDatabaseName );
+ uno::Reference<sdb::XCompletedConnection> xSource(aSourceAny, uno::UNO_QUERY);
+ if ( !xSource.is() ) return;
+
+ uno::Reference<task::XInteractionHandler> xHandler(
+ task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), nullptr),
+ uno::UNO_QUERY_THROW);
+
+ uno::Reference<sdbc::XConnection> xConnection = xSource->connectWithCompletion( xHandler );
+
+ uno::Reference<container::XNameAccess> xItems;
+ if ( nSelect == DP_TYPELIST_TABLE )
+ {
+ // get all tables
+
+ uno::Reference<sdbcx::XTablesSupplier> xTablesSupp( xConnection, uno::UNO_QUERY );
+ if ( !xTablesSupp.is() ) return;
+
+ xItems = xTablesSupp->getTables();
+ }
+ else
+ {
+ // get all queries
+
+ uno::Reference<sdb::XQueriesSupplier> xQueriesSupp( xConnection, uno::UNO_QUERY );
+ if ( !xQueriesSupp.is() ) return;
+
+ xItems = xQueriesSupp->getQueries();
+ }
+
+ if ( !xItems.is() ) return;
+
+ // fill list
+ const uno::Sequence<OUString> aNames = xItems->getElementNames();
+ for( const OUString& aName : aNames )
+ {
+ m_xCbObject->append_text(aName);
+ }
+ }
+ catch(uno::Exception&)
+ {
+ // this may happen if an invalid database is selected -> no DBG_ERROR
+ TOOLS_WARN_EXCEPTION( "sc", "exception in database");
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/dapitype.cxx b/sc/source/ui/dbgui/dapitype.cxx
new file mode 100644
index 000000000..9843a2bb9
--- /dev/null
+++ b/sc/source/ui/dbgui/dapitype.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <dapitype.hxx>
+#include <comphelper/lok.hxx>
+
+using namespace com::sun::star;
+
+ScDataPilotSourceTypeDlg::ScDataPilotSourceTypeDlg(weld::Window* pParent, bool bEnableExternal)
+ : GenericDialogController(pParent, "modules/scalc/ui/selectsource.ui", "SelectSourceDialog")
+ , m_xBtnSelection(m_xBuilder->weld_radio_button("selection"))
+ , m_xBtnNamedRange(m_xBuilder->weld_radio_button("namedrange"))
+ , m_xBtnDatabase(m_xBuilder->weld_radio_button("database"))
+ , m_xBtnExternal(m_xBuilder->weld_radio_button("external"))
+ , m_xLbNamedRange(m_xBuilder->weld_combo_box("rangelb"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok")) // for LOK jsdialog
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel")) // for LOK jsdialog
+{
+ m_xBtnSelection->connect_toggled( LINK(this, ScDataPilotSourceTypeDlg, RadioClickHdl) );
+ m_xBtnNamedRange->connect_toggled( LINK(this, ScDataPilotSourceTypeDlg, RadioClickHdl) );
+ m_xBtnDatabase->connect_toggled( LINK(this, ScDataPilotSourceTypeDlg, RadioClickHdl) );
+ m_xBtnExternal->connect_toggled( LINK(this, ScDataPilotSourceTypeDlg, RadioClickHdl) );
+
+ m_xBtnOk->connect_clicked( LINK(this, ScDataPilotSourceTypeDlg, ResponseHdl ) );
+ m_xBtnCancel->connect_clicked( LINK(this, ScDataPilotSourceTypeDlg, ResponseHdl ) );
+
+ if (!bEnableExternal)
+ m_xBtnExternal->set_sensitive(false);
+
+ m_xBtnSelection->set_active(true);
+
+ // Disabled unless at least one named range exists.
+ m_xLbNamedRange->set_sensitive(false);
+ m_xBtnNamedRange->set_sensitive(false);
+
+ // Intentionally hide this button to see if anyone complains.
+ m_xBtnExternal->hide();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ m_xBtnDatabase->hide();
+}
+
+IMPL_LINK(ScDataPilotSourceTypeDlg, ResponseHdl, weld::Button&, rButton, void)
+{
+ if (&rButton == m_xBtnOk.get())
+ m_xDialog->response(RET_OK);
+ else
+ m_xDialog->response(RET_CANCEL);
+}
+
+ScDataPilotSourceTypeDlg::~ScDataPilotSourceTypeDlg()
+{
+}
+
+bool ScDataPilotSourceTypeDlg::IsDatabase() const
+{
+ return m_xBtnDatabase->get_active();
+}
+
+bool ScDataPilotSourceTypeDlg::IsExternal() const
+{
+ return m_xBtnExternal->get_active();
+}
+
+bool ScDataPilotSourceTypeDlg::IsNamedRange() const
+{
+ return m_xBtnNamedRange->get_active();
+}
+
+OUString ScDataPilotSourceTypeDlg::GetSelectedNamedRange() const
+{
+ return m_xLbNamedRange->get_active_text();
+}
+
+void ScDataPilotSourceTypeDlg::AppendNamedRange(const OUString& rName)
+{
+ m_xLbNamedRange->append_text(rName);
+ if (m_xLbNamedRange->get_count() == 1)
+ {
+ // Select position 0 only for the first time.
+ m_xLbNamedRange->set_active(0);
+ m_xBtnNamedRange->set_sensitive(true);
+ }
+}
+
+IMPL_LINK_NOARG(ScDataPilotSourceTypeDlg, RadioClickHdl, weld::Toggleable&, void)
+{
+ m_xLbNamedRange->set_sensitive(m_xBtnNamedRange->get_active());
+}
+
+ScDataPilotServiceDlg::ScDataPilotServiceDlg(weld::Window* pParent, const std::vector<OUString>& rServices)
+ : GenericDialogController(pParent, "modules/scalc/ui/dapiservicedialog.ui", "DapiserviceDialog")
+ , m_xLbService(m_xBuilder->weld_combo_box("service"))
+ , m_xEdSource(m_xBuilder->weld_entry("source"))
+ , m_xEdName(m_xBuilder->weld_entry("name"))
+ , m_xEdUser(m_xBuilder->weld_entry("user"))
+ , m_xEdPasswd(m_xBuilder->weld_entry("password"))
+{
+ for (const OUString& aName : rServices)
+ {
+ m_xLbService->append_text(aName);
+ }
+ m_xLbService->set_active(0);
+}
+
+ScDataPilotServiceDlg::~ScDataPilotServiceDlg()
+{
+}
+
+OUString ScDataPilotServiceDlg::GetServiceName() const
+{
+ return m_xLbService->get_active_text();
+}
+
+OUString ScDataPilotServiceDlg::GetParSource() const
+{
+ return m_xEdSource->get_text();
+}
+
+OUString ScDataPilotServiceDlg::GetParName() const
+{
+ return m_xEdName->get_text();
+}
+
+OUString ScDataPilotServiceDlg::GetParUser() const
+{
+ return m_xEdUser->get_text();
+}
+
+OUString ScDataPilotServiceDlg::GetParPass() const
+{
+ return m_xEdPasswd->get_text();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/dbnamdlg.cxx b/sc/source/ui/dbgui/dbnamdlg.cxx
new file mode 100644
index 000000000..a2ac72209
--- /dev/null
+++ b/sc/source/ui/dbgui/dbnamdlg.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 <memory>
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <comphelper/string.hxx>
+#include <unotools/charclass.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <reffact.hxx>
+#include <document.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <rangenam.hxx>
+#include <globalnames.hxx>
+#include <dbnamdlg.hxx>
+#include <dbdocfun.hxx>
+
+namespace {
+
+class DBSaveData;
+
+}
+
+static std::unique_ptr<DBSaveData> xSaveObj;
+
+namespace
+{
+ void ERRORBOX(weld::Window* pParent, const OUString& rString)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ rString));
+ xBox->run();
+ }
+
+
+class DBSaveData
+{
+public:
+ DBSaveData( formula::RefEdit& rEd, weld::CheckButton& rHdr, weld::CheckButton& rTot, weld::CheckButton& rSize, weld::CheckButton& rFmt,
+ weld::CheckButton& rStrip, ScRange& rArea )
+ : rEdAssign(rEd)
+ , rBtnHeader(rHdr)
+ , rBtnTotals(rTot)
+ , rBtnSize(rSize)
+ , rBtnFormat(rFmt)
+ , rBtnStrip(rStrip)
+ , rCurArea(rArea)
+ , bHeader(false)
+ , bTotals(false)
+ , bSize(false)
+ , bFormat(false)
+ , bStrip(false)
+ , bDirty(false)
+ {
+ }
+ void Save();
+ void Restore();
+
+private:
+ formula::RefEdit& rEdAssign;
+ weld::CheckButton& rBtnHeader;
+ weld::CheckButton& rBtnTotals;
+ weld::CheckButton& rBtnSize;
+ weld::CheckButton& rBtnFormat;
+ weld::CheckButton& rBtnStrip;
+ ScRange& rCurArea;
+ OUString aStr;
+ ScRange aArea;
+ bool bHeader:1;
+ bool bTotals:1;
+ bool bSize:1;
+ bool bFormat:1;
+ bool bStrip:1;
+ bool bDirty:1;
+};
+
+}
+
+void DBSaveData::Save()
+{
+ aArea = rCurArea;
+ aStr = rEdAssign.GetText();
+ bHeader = rBtnHeader.get_active();
+ bTotals = rBtnTotals.get_active();
+ bSize = rBtnSize.get_active();
+ bFormat = rBtnFormat.get_active();
+ bStrip = rBtnStrip.get_active();
+ bDirty = true;
+}
+
+void DBSaveData::Restore()
+{
+ if ( bDirty )
+ {
+ rCurArea = aArea;
+ rEdAssign.SetText( aStr );
+ rBtnHeader.set_active ( bHeader );
+ rBtnTotals.set_active ( bTotals );
+ rBtnSize.set_active ( bSize );
+ rBtnFormat.set_active ( bFormat );
+ rBtnStrip.set_active ( bStrip );
+ bDirty = false;
+ }
+}
+
+
+ScDbNameDlg::ScDbNameDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScViewData& rViewData)
+ : ScAnyRefDlgController(pB, pCW, pParent,
+ "modules/scalc/ui/definedatabaserangedialog.ui", "DefineDatabaseRangeDialog")
+ , m_rViewData(rViewData)
+ , rDoc(rViewData.GetDocument())
+ , bRefInputMode(false)
+ , aAddrDetails(rDoc.GetAddressConvention(), 0, 0)
+ , aLocalDbCol(*(rDoc.GetDBCollection()))
+ , m_xEdName(m_xBuilder->weld_entry_tree_view("entrygrid", "entry", "entry-list"))
+ , m_xAssignFrame(m_xBuilder->weld_frame("RangeFrame"))
+ , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry("assign")))
+ , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button("assignrb")))
+ , m_xOptions(m_xBuilder->weld_widget("Options"))
+ , m_xBtnHeader(m_xBuilder->weld_check_button("ContainsColumnLabels"))
+ , m_xBtnTotals(m_xBuilder->weld_check_button("ContainsTotalsRow"))
+ , m_xBtnDoSize(m_xBuilder->weld_check_button("InsertOrDeleteCells"))
+ , m_xBtnKeepFmt(m_xBuilder->weld_check_button("KeepFormatting"))
+ , m_xBtnStripData(m_xBuilder->weld_check_button("DontSaveImportedData"))
+ , m_xFTSource(m_xBuilder->weld_label("Source"))
+ , m_xFTOperations(m_xBuilder->weld_label("Operations"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_xBtnAdd(m_xBuilder->weld_button("add"))
+ , m_xBtnRemove(m_xBuilder->weld_button("delete"))
+ , m_xModifyPB(m_xBuilder->weld_button("modify"))
+ , m_xInvalidFT(m_xBuilder->weld_label("invalid"))
+ , m_xFrameLabel(m_xAssignFrame->weld_label_widget())
+ , m_xExpander(m_xBuilder->weld_expander("more"))
+{
+ m_xEdName->set_height_request_by_rows(4);
+ m_xEdAssign->SetReferences(this, m_xFrameLabel.get());
+ m_xRbAssign->SetReferences(this, m_xEdAssign.get());
+ aStrAdd = m_xBtnAdd->get_label();
+ aStrModify = m_xModifyPB->get_label();
+ aStrInvalid = m_xInvalidFT->get_label();
+
+ // so that the strings in the resource can stay with fixed texts:
+ aStrSource = m_xFTSource->get_label();
+ aStrOperations = m_xFTOperations->get_label();
+
+ xSaveObj.reset(new DBSaveData( *m_xEdAssign, *m_xBtnHeader, *m_xBtnTotals,
+ *m_xBtnDoSize, *m_xBtnKeepFmt, *m_xBtnStripData, theCurArea ));
+ Init();
+}
+
+ScDbNameDlg::~ScDbNameDlg()
+{
+ xSaveObj.reset();
+}
+
+void ScDbNameDlg::Init()
+{
+ m_xBtnHeader->set_active(true); // Default: with column headers
+ m_xBtnTotals->set_active( false ); // Default: without totals row
+ m_xBtnDoSize->set_active(true);
+ m_xBtnKeepFmt->set_active(true);
+
+ m_xBtnOk->connect_clicked ( LINK( this, ScDbNameDlg, OkBtnHdl ) );
+ m_xBtnCancel->connect_clicked ( LINK( this, ScDbNameDlg, CancelBtnHdl ) );
+ m_xBtnAdd->connect_clicked ( LINK( this, ScDbNameDlg, AddBtnHdl ) );
+ m_xBtnRemove->connect_clicked ( LINK( this, ScDbNameDlg, RemoveBtnHdl ) );
+ m_xEdName->connect_changed( LINK( this, ScDbNameDlg, NameModifyHdl ) );
+ m_xEdAssign->SetModifyHdl ( LINK( this, ScDbNameDlg, AssModifyHdl ) );
+ UpdateNames();
+
+ OUString theAreaStr;
+
+ SCCOL nStartCol = 0;
+ SCROW nStartRow = 0;
+ SCTAB nStartTab = 0;
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ SCTAB nEndTab = 0;
+
+ ScDBCollection* pDBColl = rDoc.GetDBCollection();
+
+ m_rViewData.GetSimpleArea( nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab );
+
+ theCurArea = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
+
+ theAreaStr = theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, aAddrDetails);
+
+ if ( pDBColl )
+ {
+ // determine if the defined DB area has been marked:
+ ScDBData* pDBData = pDBColl->GetDBAtCursor( nStartCol, nStartRow, nStartTab, ScDBDataPortion::TOP_LEFT );
+ if ( pDBData )
+ {
+ ScAddress& rStart = theCurArea.aStart;
+ ScAddress& rEnd = theCurArea.aEnd;
+ SCCOL nCol1;
+ SCCOL nCol2;
+ SCROW nRow1;
+ SCROW nRow2;
+ SCTAB nTab;
+
+ pDBData->GetArea( nTab, nCol1, nRow1, nCol2, nRow2 );
+
+ if ( (rStart.Tab() == nTab)
+ && (rStart.Col() == nCol1) && (rStart.Row() == nRow1)
+ && (rEnd.Col() == nCol2) && (rEnd.Row() == nRow2 ) )
+ {
+ OUString aDBName = pDBData->GetName();
+ if ( aDBName != STR_DB_LOCAL_NONAME )
+ m_xEdName->set_entry_text(aDBName);
+
+ m_xBtnHeader->set_active( pDBData->HasHeader() );
+ m_xBtnTotals->set_active( pDBData->HasTotals() );
+ m_xBtnDoSize->set_active( pDBData->IsDoSize() );
+ m_xBtnKeepFmt->set_active( pDBData->IsKeepFmt() );
+ m_xBtnStripData->set_active( pDBData->IsStripData() );
+ SetInfoStrings( pDBData );
+ }
+ }
+ }
+
+ m_xEdAssign->SetText( theAreaStr );
+ m_xEdName->grab_focus();
+ bSaved = true;
+ xSaveObj->Save();
+ NameModifyHdl( *m_xEdName );
+ bInvalid = false;
+}
+
+void ScDbNameDlg::SetInfoStrings( const ScDBData* pDBData )
+{
+ OUStringBuffer aBuf;
+ aBuf.append(aStrSource);
+ if (pDBData)
+ {
+ aBuf.append(' ');
+ aBuf.append(pDBData->GetSourceString());
+ }
+ m_xFTSource->set_label(aBuf.makeStringAndClear());
+
+ aBuf.append(aStrOperations);
+ if (pDBData)
+ {
+ aBuf.append(' ');
+ aBuf.append(pDBData->GetOperations());
+ }
+ m_xFTOperations->set_label(aBuf.makeStringAndClear());
+}
+
+// Transfer of a table area selected with the mouse, which is then displayed
+// as a new selection in the reference window.
+
+void ScDbNameDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
+{
+ if (!m_xEdAssign->GetWidget()->get_sensitive())
+ return;
+
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart(m_xEdAssign.get());
+
+ theCurArea = rRef;
+
+ OUString aRefStr(theCurArea.Format(rDocP, ScRefFlags::RANGE_ABS_3D, aAddrDetails));
+ m_xEdAssign->SetRefString( aRefStr );
+ m_xOptions->set_sensitive(true);
+ m_xBtnAdd->set_sensitive(true);
+ bSaved = true;
+ xSaveObj->Save();
+}
+
+void ScDbNameDlg::Close()
+{
+ DoClose( ScDbNameDlgWrapper::GetChildWindowId() );
+}
+
+void ScDbNameDlg::SetActive()
+{
+ m_xEdAssign->GrabFocus();
+
+ // No NameModifyHdl, because otherwise areas can not be changed
+ // (the old content would be displayed again after the reference selection is pulled)
+ // (the selected DB name has not changed either)
+
+ RefInputDone();
+}
+
+void ScDbNameDlg::UpdateNames()
+{
+ typedef ScDBCollection::NamedDBs DBsType;
+
+ const DBsType& rDBs = aLocalDbCol.getNamedDBs();
+
+ m_xEdName->freeze();
+
+ m_xEdName->clear();
+ m_xEdAssign->SetText( OUString() );
+
+ if (!rDBs.empty())
+ {
+ for (const auto& rxDB : rDBs)
+ m_xEdName->append_text(rxDB->GetName());
+ }
+ else
+ {
+ m_xBtnAdd->set_label( aStrAdd );
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(false);
+ }
+
+ m_xEdName->thaw();
+}
+
+void ScDbNameDlg::UpdateDBData( const OUString& rStrName )
+{
+
+ const ScDBData* pData = aLocalDbCol.getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rStrName));
+
+ if ( pData )
+ {
+ SCCOL nColStart = 0;
+ SCROW nRowStart = 0;
+ SCCOL nColEnd = 0;
+ SCROW nRowEnd = 0;
+ SCTAB nTab = 0;
+
+ pData->GetArea( nTab, nColStart, nRowStart, nColEnd, nRowEnd );
+ theCurArea = ScRange( ScAddress( nColStart, nRowStart, nTab ),
+ ScAddress( nColEnd, nRowEnd, nTab ) );
+ OUString theArea(theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, aAddrDetails));
+ m_xEdAssign->SetText( theArea );
+ m_xBtnAdd->set_label( aStrModify );
+ m_xBtnHeader->set_active( pData->HasHeader() );
+ m_xBtnTotals->set_active( pData->HasTotals() );
+ m_xBtnDoSize->set_active( pData->IsDoSize() );
+ m_xBtnKeepFmt->set_active( pData->IsKeepFmt() );
+ m_xBtnStripData->set_active( pData->IsStripData() );
+ SetInfoStrings( pData );
+ }
+
+ m_xBtnAdd->set_label( aStrModify );
+ m_xBtnAdd->set_sensitive(true);
+ m_xBtnRemove->set_sensitive(true);
+ m_xOptions->set_sensitive(true);
+}
+
+bool ScDbNameDlg::IsRefInputMode() const
+{
+ return bRefInputMode;
+}
+
+// Handler:
+
+IMPL_LINK_NOARG(ScDbNameDlg, OkBtnHdl, weld::Button&, void)
+{
+ bInvalid = false;
+ AddBtnHdl(*m_xBtnAdd);
+
+ // Pass the changes and the remove list to the view: both are
+ // transferred as a reference only, so that no dead memory can
+ // be created at this point:
+ if (!bInvalid)
+ {
+ ScDBDocFunc aFunc(*m_rViewData.GetDocShell());
+ aFunc.ModifyAllDBData(aLocalDbCol, aRemoveList);
+ response(RET_OK);
+ }
+}
+
+IMPL_LINK_NOARG(ScDbNameDlg, CancelBtnHdl, weld::Button&, void)
+{
+ response(RET_CANCEL);
+}
+
+IMPL_LINK_NOARG(ScDbNameDlg, AddBtnHdl, weld::Button&, void)
+{
+ OUString aNewName = comphelper::string::strip(m_xEdName->get_active_text(), ' ');
+ OUString aNewArea = m_xEdAssign->GetText();
+
+ if ( aNewName.isEmpty() || aNewArea.isEmpty() )
+ return;
+
+ if (ScRangeData::IsNameValid(aNewName, rDoc) == ScRangeData::IsNameValidType::NAME_VALID
+ && aNewName != STR_DB_LOCAL_NONAME)
+ {
+ // because editing can be done now, parsing is needed first
+ ScRange aTmpRange;
+ OUString aText = m_xEdAssign->GetText();
+ if ( aTmpRange.ParseAny( aText, rDoc, aAddrDetails ) & ScRefFlags::VALID )
+ {
+ theCurArea = aTmpRange;
+ ScAddress aStart = theCurArea.aStart;
+ ScAddress aEnd = theCurArea.aEnd;
+
+ ScDBData* pOldEntry = aLocalDbCol.getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(aNewName));
+ if (pOldEntry)
+ {
+ // modify area
+
+ pOldEntry->MoveTo( aStart.Tab(), aStart.Col(), aStart.Row(),
+ aEnd.Col(), aEnd.Row() );
+ pOldEntry->SetByRow( true );
+ pOldEntry->SetHeader( m_xBtnHeader->get_active() );
+ pOldEntry->SetTotals( m_xBtnTotals->get_active() );
+ pOldEntry->SetDoSize( m_xBtnDoSize->get_active() );
+ pOldEntry->SetKeepFmt( m_xBtnKeepFmt->get_active() );
+ pOldEntry->SetStripData( m_xBtnStripData->get_active() );
+ }
+ else
+ {
+ // insert new area
+
+ std::unique_ptr<ScDBData> pNewEntry(new ScDBData( aNewName, aStart.Tab(),
+ aStart.Col(), aStart.Row(),
+ aEnd.Col(), aEnd.Row(),
+ true, m_xBtnHeader->get_active(),
+ m_xBtnTotals->get_active() ));
+ pNewEntry->SetDoSize( m_xBtnDoSize->get_active() );
+ pNewEntry->SetKeepFmt( m_xBtnKeepFmt->get_active() );
+ pNewEntry->SetStripData( m_xBtnStripData->get_active() );
+
+ bool ins = aLocalDbCol.getNamedDBs().insert(std::move(pNewEntry));
+ assert(ins); (void)ins;
+ }
+
+ UpdateNames();
+
+ m_xEdName->set_entry_text( OUString() );
+ m_xEdName->grab_focus();
+ m_xBtnAdd->set_label( aStrAdd );
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(false);
+ m_xEdAssign->SetText( OUString() );
+ m_xBtnHeader->set_active(true); // Default: with column headers
+ m_xBtnTotals->set_active( false ); // Default: without totals row
+ m_xBtnDoSize->set_active( false );
+ m_xBtnKeepFmt->set_active( false );
+ m_xBtnStripData->set_active( false );
+ SetInfoStrings( nullptr ); // empty
+ theCurArea = ScRange();
+ bSaved = true;
+ xSaveObj->Save();
+ NameModifyHdl( *m_xEdName );
+ }
+ else
+ {
+ ERRORBOX(m_xDialog.get(), aStrInvalid);
+ m_xEdAssign->SelectAll();
+ m_xEdAssign->GrabFocus();
+ bInvalid = true;
+ }
+ }
+ else
+ {
+ ERRORBOX(m_xDialog.get(), ScResId(STR_INVALIDNAME));
+ m_xEdName->select_entry_region(0, -1);
+ m_xEdName->grab_focus();
+ bInvalid = true;
+ }
+}
+
+namespace {
+
+class FindByName
+{
+ const OUString& mrName;
+public:
+ explicit FindByName(const OUString& rName) : mrName(rName) {}
+ bool operator() (std::unique_ptr<ScDBData> const& p) const
+ {
+ return p->GetName() == mrName;
+ }
+};
+
+}
+
+IMPL_LINK_NOARG(ScDbNameDlg, RemoveBtnHdl, weld::Button&, void)
+{
+ OUString aStrEntry = m_xEdName->get_active_text();
+ ScDBCollection::NamedDBs& rDBs = aLocalDbCol.getNamedDBs();
+ ScDBCollection::NamedDBs::iterator itr =
+ ::std::find_if(rDBs.begin(), rDBs.end(), FindByName(aStrEntry));
+
+ if (itr == rDBs.end())
+ return;
+
+ OUString aStrDelMsg = ScResId( STR_QUERY_DELENTRY );
+ OUString sMsg{ o3tl::getToken(aStrDelMsg, 0, '#') + aStrEntry + o3tl::getToken(aStrDelMsg, 1, '#') };
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ sMsg));
+ xQueryBox->set_default_response(RET_YES);
+ if (RET_YES != xQueryBox->run())
+ return;
+
+ SCTAB nTab;
+ SCCOL nColStart, nColEnd;
+ SCROW nRowStart, nRowEnd;
+ (*itr)->GetArea( nTab, nColStart, nRowStart, nColEnd, nRowEnd );
+ aRemoveList.emplace_back( ScAddress( nColStart, nRowStart, nTab ),
+ ScAddress( nColEnd, nRowEnd, nTab ) );
+
+ rDBs.erase(itr);
+
+ UpdateNames();
+
+ m_xEdName->set_entry_text( OUString() );
+ m_xEdName->grab_focus();
+ m_xBtnAdd->set_label( aStrAdd );
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(false);
+ m_xEdAssign->SetText( OUString() );
+ theCurArea = ScRange();
+ m_xBtnHeader->set_active(true); // Default: with column headers
+ m_xBtnTotals->set_active( false ); // Default: without totals row
+ m_xBtnDoSize->set_active( false );
+ m_xBtnKeepFmt->set_active( false );
+ m_xBtnStripData->set_active( false );
+ SetInfoStrings( nullptr ); // empty
+ bSaved=false;
+ xSaveObj->Restore();
+ NameModifyHdl( *m_xEdName );
+}
+
+IMPL_LINK_NOARG(ScDbNameDlg, NameModifyHdl, weld::ComboBox&, void)
+{
+ OUString theName = m_xEdName->get_active_text();
+ bool bNameFound = m_xEdName->find_text(theName) != -1;
+
+ if ( theName.isEmpty() )
+ {
+ if (m_xBtnAdd->get_label() != aStrAdd)
+ m_xBtnAdd->set_label( aStrAdd );
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(false);
+ m_xAssignFrame->set_sensitive(false);
+ m_xOptions->set_sensitive(false);
+ //bSaved=sal_False;
+ //xSaveObj->Restore();
+ //@BugID 54702 enable/disable in the base class only
+ //SFX_APPWINDOW->Disable(sal_False); //! general method in ScAnyRefDlg
+ bRefInputMode = false;
+ }
+ else
+ {
+ if ( bNameFound )
+ {
+ if (m_xBtnAdd->get_label() != aStrModify)
+ m_xBtnAdd->set_label( aStrModify );
+
+ if(!bSaved)
+ {
+ bSaved = true;
+ xSaveObj->Save();
+ }
+ UpdateDBData( theName );
+ }
+ else
+ {
+ if (m_xBtnAdd->get_label() != aStrAdd)
+ m_xBtnAdd->set_label( aStrAdd );
+
+ bSaved=false;
+ xSaveObj->Restore();
+
+ if ( !m_xEdAssign->GetText().isEmpty() )
+ {
+ m_xBtnAdd->set_sensitive(true);
+ m_xOptions->set_sensitive(true);
+ }
+ else
+ {
+ m_xBtnAdd->set_sensitive(false);
+ m_xOptions->set_sensitive(false);
+ }
+ m_xBtnRemove->set_sensitive(false);
+ }
+
+ m_xAssignFrame->set_sensitive(true);
+
+ //@BugID 54702 enable/disable in the base class only
+ //SFX_APPWINDOW->set_sensitive(true);
+ bRefInputMode = true;
+ }
+}
+
+IMPL_LINK_NOARG(ScDbNameDlg, AssModifyHdl, formula::RefEdit&, void)
+{
+ // parse here for Save(), etc.
+
+ ScRange aTmpRange;
+ OUString aText = m_xEdAssign->GetText();
+ if ( aTmpRange.ParseAny( aText, rDoc, aAddrDetails ) & ScRefFlags::VALID )
+ theCurArea = aTmpRange;
+
+ if (!aText.isEmpty() && !m_xEdName->get_active_text().isEmpty())
+ {
+ m_xBtnAdd->set_sensitive(true);
+ m_xBtnHeader->set_sensitive(true);
+ m_xBtnTotals->set_sensitive(true);
+ m_xBtnDoSize->set_sensitive(true);
+ m_xBtnKeepFmt->set_sensitive(true);
+ m_xBtnStripData->set_sensitive(true);
+ m_xFTSource->set_sensitive(true);
+ m_xFTOperations->set_sensitive(true);
+ }
+ else
+ {
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnHeader->set_sensitive(false);
+ m_xBtnTotals->set_sensitive(false);
+ m_xBtnDoSize->set_sensitive(false);
+ m_xBtnKeepFmt->set_sensitive(false);
+ m_xBtnStripData->set_sensitive(false);
+ m_xFTSource->set_sensitive(false);
+ m_xFTOperations->set_sensitive(false);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/dpgroupdlg.cxx b/sc/source/ui/dbgui/dpgroupdlg.cxx
new file mode 100644
index 000000000..550695cc3
--- /dev/null
+++ b/sc/source/ui/dbgui/dpgroupdlg.cxx
@@ -0,0 +1,353 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifdef SC_DLLIMPLEMENTATION
+#undef SC_DLLIMPLEMENTATION
+#endif
+
+#include <dpgroupdlg.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <editfield.hxx>
+
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+#include <svtools/ctrlbox.hxx>
+
+namespace {
+
+/** Date part flags in order of the list box entries. */
+const sal_Int32 spnDateParts[] =
+{
+ css::sheet::DataPilotFieldGroupBy::SECONDS,
+ css::sheet::DataPilotFieldGroupBy::MINUTES,
+ css::sheet::DataPilotFieldGroupBy::HOURS,
+ css::sheet::DataPilotFieldGroupBy::DAYS,
+ css::sheet::DataPilotFieldGroupBy::MONTHS,
+ css::sheet::DataPilotFieldGroupBy::QUARTERS,
+ css::sheet::DataPilotFieldGroupBy::YEARS
+};
+
+const TranslateId aDatePartResIds[] =
+{
+ STR_DPFIELD_GROUP_BY_SECONDS,
+ STR_DPFIELD_GROUP_BY_MINUTES,
+ STR_DPFIELD_GROUP_BY_HOURS,
+ STR_DPFIELD_GROUP_BY_DAYS,
+ STR_DPFIELD_GROUP_BY_MONTHS,
+ STR_DPFIELD_GROUP_BY_QUARTERS,
+ STR_DPFIELD_GROUP_BY_YEARS
+};
+
+} // namespace
+
+ScDPGroupEditHelper::ScDPGroupEditHelper(weld::RadioButton& rRbAuto, weld::RadioButton& rRbMan, weld::Widget& rEdValue)
+ : mrRbAuto(rRbAuto)
+ , mrRbMan(rRbMan)
+ , mrEdValue(rEdValue)
+{
+ mrRbAuto.connect_toggled( LINK( this, ScDPGroupEditHelper, ToggleHdl ) );
+ mrRbMan.connect_toggled( LINK( this, ScDPGroupEditHelper, ToggleHdl ) );
+}
+
+bool ScDPGroupEditHelper::IsAuto() const
+{
+ return mrRbAuto.get_active();
+}
+
+double ScDPGroupEditHelper::GetValue() const
+{
+ double fValue;
+ if( !ImplGetValue( fValue ) )
+ fValue = 0.0;
+ return fValue;
+}
+
+void ScDPGroupEditHelper::SetValue( bool bAuto, double fValue )
+{
+ if( bAuto )
+ {
+ mrRbAuto.set_active(true);
+ ToggleHdl(mrRbAuto);
+ }
+ else
+ {
+ mrRbMan.set_active(true);
+ ToggleHdl(mrRbMan);
+ }
+ ImplSetValue( fValue );
+}
+
+IMPL_LINK(ScDPGroupEditHelper, ToggleHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+
+ if (mrRbAuto.get_active())
+ {
+ // disable edit field on clicking "automatic" radio button
+ mrEdValue.set_sensitive(false);
+ }
+ else if (mrRbMan.get_active())
+ {
+ // enable and set focus to edit field on clicking "manual" radio button
+ mrEdValue.set_sensitive(true);
+ mrEdValue.grab_focus();
+ }
+}
+
+ScDPNumGroupEditHelper::ScDPNumGroupEditHelper(weld::RadioButton& rRbAuto,
+ weld::RadioButton& rRbMan, ScDoubleField& rEdValue)
+ : ScDPGroupEditHelper(rRbAuto, rRbMan, rEdValue.get_widget())
+ , mrEdValue(rEdValue)
+{
+}
+
+bool ScDPNumGroupEditHelper::ImplGetValue( double& rfValue ) const
+{
+ return mrEdValue.GetValue(rfValue);
+}
+
+void ScDPNumGroupEditHelper::ImplSetValue( double fValue )
+{
+ mrEdValue.SetValue(fValue);
+}
+
+ScDPDateGroupEditHelper::ScDPDateGroupEditHelper(weld::RadioButton& rRbAuto, weld::RadioButton& rRbMan,
+ SvtCalendarBox& rEdValue, const Date& rNullDate)
+ : ScDPGroupEditHelper(rRbAuto, rRbMan, rEdValue.get_button())
+ , mrEdValue(rEdValue)
+ , maNullDate(rNullDate)
+{
+}
+
+bool ScDPDateGroupEditHelper::ImplGetValue( double& rfValue ) const
+{
+ rfValue = mrEdValue.get_date() - maNullDate;
+ return true;
+}
+
+void ScDPDateGroupEditHelper::ImplSetValue( double fValue )
+{
+ Date aDate( maNullDate );
+ aDate.AddDays( fValue );
+ mrEdValue.set_date( aDate );
+}
+
+ScDPNumGroupDlg::ScDPNumGroupDlg(weld::Window* pParent, const ScDPNumGroupInfo& rInfo)
+ : GenericDialogController(pParent, "modules/scalc/ui/groupbynumber.ui", "PivotTableGroupByNumber")
+ , mxRbAutoStart(m_xBuilder->weld_radio_button("auto_start"))
+ , mxRbManStart(m_xBuilder->weld_radio_button("manual_start"))
+ , mxEdStart(new ScDoubleField(m_xBuilder->weld_entry("edit_start")))
+ , mxRbAutoEnd(m_xBuilder->weld_radio_button("auto_end"))
+ , mxRbManEnd(m_xBuilder->weld_radio_button("manual_end"))
+ , mxEdEnd(new ScDoubleField(m_xBuilder->weld_entry("edit_end")))
+ , mxEdBy(new ScDoubleField(m_xBuilder->weld_entry("edit_by")))
+ , maStartHelper(*mxRbAutoStart, *mxRbManStart, *mxEdStart)
+ , maEndHelper(*mxRbAutoEnd, *mxRbManEnd, *mxEdEnd)
+{
+ maStartHelper.SetValue( rInfo.mbAutoStart, rInfo.mfStart );
+ maEndHelper.SetValue( rInfo.mbAutoEnd, rInfo.mfEnd );
+ mxEdBy->SetValue( (rInfo.mfStep <= 0.0) ? 1.0 : rInfo.mfStep );
+
+ /* Set the initial focus, currently it is somewhere after calling all the radio
+ button click handlers. Now the first enabled editable control is focused. */
+ if (mxEdStart->get_sensitive())
+ mxEdStart->grab_focus();
+ else if (mxEdEnd->get_sensitive())
+ mxEdEnd->grab_focus();
+ else
+ mxEdBy->grab_focus();
+}
+
+ScDPNumGroupDlg::~ScDPNumGroupDlg()
+{
+}
+
+ScDPNumGroupInfo ScDPNumGroupDlg::GetGroupInfo() const
+{
+ ScDPNumGroupInfo aInfo;
+ aInfo.mbEnable = true;
+ aInfo.mbDateValues = false;
+ aInfo.mbAutoStart = maStartHelper.IsAuto();
+ aInfo.mbAutoEnd = maEndHelper.IsAuto();
+
+ // get values and silently auto-correct them, if they are not valid
+ // TODO: error messages in OK event?
+ aInfo.mfStart = maStartHelper.GetValue();
+ aInfo.mfEnd = maEndHelper.GetValue();
+ if( !mxEdBy->GetValue( aInfo.mfStep ) || (aInfo.mfStep <= 0.0) )
+ aInfo.mfStep = 1.0;
+ if( aInfo.mfEnd <= aInfo.mfStart )
+ aInfo.mfEnd = aInfo.mfStart + aInfo.mfStep;
+
+ return aInfo;
+}
+
+ScDPDateGroupDlg::ScDPDateGroupDlg(weld::Window* pParent,
+ const ScDPNumGroupInfo& rInfo, sal_Int32 nDatePart, const Date& rNullDate)
+ : GenericDialogController(pParent, "modules/scalc/ui/groupbydate.ui", "PivotTableGroupByDate")
+ , mxRbAutoStart(m_xBuilder->weld_radio_button("auto_start"))
+ , mxRbManStart(m_xBuilder->weld_radio_button("manual_start"))
+ , mxEdStart(new SvtCalendarBox(m_xBuilder->weld_menu_button("start_date")))
+ , mxRbAutoEnd(m_xBuilder->weld_radio_button("auto_end"))
+ , mxRbManEnd(m_xBuilder->weld_radio_button("manual_end"))
+ , mxEdEnd(new SvtCalendarBox(m_xBuilder->weld_menu_button("end_date")))
+ , mxRbNumDays(m_xBuilder->weld_radio_button("days"))
+ , mxRbUnits(m_xBuilder->weld_radio_button("intervals"))
+ , mxEdNumDays(m_xBuilder->weld_spin_button("days_value"))
+ , mxLbUnits(m_xBuilder->weld_tree_view("interval_list"))
+ , mxBtnOk(m_xBuilder->weld_button("ok"))
+ , maStartHelper(*mxRbAutoStart, *mxRbManStart, *mxEdStart, rNullDate)
+ , maEndHelper(*mxRbAutoEnd, *mxRbManEnd, *mxEdEnd, rNullDate)
+{
+ maStartHelper.SetValue( rInfo.mbAutoStart, rInfo.mfStart );
+ maEndHelper.SetValue( rInfo.mbAutoEnd, rInfo.mfEnd );
+
+ mxLbUnits->enable_toggle_buttons(weld::ColumnToggleType::Check);
+
+ if( nDatePart == 0 )
+ nDatePart = css::sheet::DataPilotFieldGroupBy::MONTHS;
+ for (size_t nIdx = 0; nIdx < SAL_N_ELEMENTS(aDatePartResIds); ++nIdx)
+ {
+ mxLbUnits->append();
+ mxLbUnits->set_toggle(nIdx, (nDatePart & spnDateParts[ nIdx ]) ? TRISTATE_TRUE : TRISTATE_FALSE);
+ mxLbUnits->set_text(nIdx, ScResId(aDatePartResIds[nIdx]), 0);
+ }
+
+ if( rInfo.mbDateValues )
+ {
+ mxRbNumDays->set_active(true);
+ ToggleHdl(*mxRbNumDays );
+
+ double fNumDays = rInfo.mfStep;
+ if( fNumDays < 1.0 )
+ fNumDays = 1.0;
+ else if( fNumDays > 32767.0 )
+ fNumDays = 32767.0;
+ mxEdNumDays->set_value(fNumDays);
+ }
+ else
+ {
+ mxRbUnits->set_active(true);
+ ToggleHdl(*mxRbUnits);
+ }
+
+ /* Set the initial focus, currently it is somewhere after calling all the radio
+ button click handlers. Now the first enabled editable control is focused. */
+ if( mxEdStart->get_sensitive() )
+ mxEdStart->grab_focus();
+ else if( mxEdEnd->get_sensitive() )
+ mxEdEnd->grab_focus();
+ else if( mxEdNumDays->get_sensitive() )
+ mxEdNumDays->grab_focus();
+ else if( mxLbUnits->get_sensitive() )
+ mxLbUnits->grab_focus();
+
+ mxRbNumDays->connect_toggled( LINK( this, ScDPDateGroupDlg, ToggleHdl ) );
+ mxRbUnits->connect_toggled( LINK( this, ScDPDateGroupDlg, ToggleHdl ) );
+ mxLbUnits->connect_toggled( LINK( this, ScDPDateGroupDlg, CheckHdl ) );
+}
+
+ScDPDateGroupDlg::~ScDPDateGroupDlg()
+{
+}
+
+ScDPNumGroupInfo ScDPDateGroupDlg::GetGroupInfo() const
+{
+ ScDPNumGroupInfo aInfo;
+ aInfo.mbEnable = true;
+ aInfo.mbDateValues = mxRbNumDays->get_active();
+ aInfo.mbAutoStart = maStartHelper.IsAuto();
+ aInfo.mbAutoEnd = maEndHelper.IsAuto();
+
+ // get values and silently auto-correct them, if they are not valid
+ // TODO: error messages in OK event?
+ aInfo.mfStart = maStartHelper.GetValue();
+ aInfo.mfEnd = maEndHelper.GetValue();
+ sal_Int64 nNumDays = mxEdNumDays->get_value();
+ aInfo.mfStep = static_cast<double>( aInfo.mbDateValues ? nNumDays : 0L );
+ if( aInfo.mfEnd <= aInfo.mfStart )
+ aInfo.mfEnd = aInfo.mfStart + nNumDays;
+
+ return aInfo;
+}
+
+sal_Int32 ScDPDateGroupDlg::GetDatePart() const
+{
+ // return DAYS for special "number of days" mode
+ if( mxRbNumDays->get_active() )
+ return css::sheet::DataPilotFieldGroupBy::DAYS;
+
+ // return listbox contents for "units" mode
+ sal_Int32 nDatePart = 0;
+ for (int nIdx = 0, nCount = mxLbUnits->n_children(); nIdx < nCount; ++nIdx )
+ if (mxLbUnits->get_toggle(nIdx) == TRISTATE_TRUE)
+ nDatePart |= spnDateParts[ nIdx ];
+ return nDatePart;
+}
+
+IMPL_LINK(ScDPDateGroupDlg, ToggleHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+ if (mxRbNumDays->get_active())
+ {
+ mxLbUnits->set_sensitive(false);
+ // enable and set focus to edit field on clicking "num of days" radio button
+ mxEdNumDays->set_sensitive(true);
+ mxEdNumDays->grab_focus();
+ mxBtnOk->set_sensitive(true);
+ }
+ else if (mxRbUnits->get_active())
+ {
+ mxEdNumDays->set_sensitive(false);
+ // enable and set focus to listbox on clicking "units" radio button
+ mxLbUnits->set_sensitive(true);
+ mxLbUnits->grab_focus();
+ // disable OK button if no date part selected
+ Check();
+ }
+}
+
+namespace
+{
+ bool HasCheckedEntryCount(const weld::TreeView& rView)
+ {
+ for (int i = 0; i < rView.n_children(); ++i)
+ {
+ if (rView.get_toggle(i) == TRISTATE_TRUE)
+ return true;
+ }
+ return false;
+ }
+}
+
+IMPL_LINK_NOARG(ScDPDateGroupDlg, CheckHdl, const weld::TreeView::iter_col&, void)
+{
+ Check();
+}
+
+void ScDPDateGroupDlg::Check()
+{
+ // enable/disable OK button on modifying check list box
+ mxBtnOk->set_sensitive(HasCheckedEntryCount(*mxLbUnits));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/filtdlg.cxx b/sc/source/ui/dbgui/filtdlg.cxx
new file mode 100644
index 000000000..2af415670
--- /dev/null
+++ b/sc/source/ui/dbgui/filtdlg.cxx
@@ -0,0 +1,1571 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <sal/log.hxx>
+
+#include <uiitems.hxx>
+#include <reffact.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <scresid.hxx>
+#include <queryentry.hxx>
+
+#include <foptmgr.hxx>
+
+#include <globstr.hrc>
+#include <strings.hrc>
+
+#include <filtdlg.hxx>
+#include <svx/colorwindow.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+#include <svl/numformat.hxx>
+#include <svl/sharedstringpool.hxx>
+
+#include <limits>
+
+#define QUERY_ENTRY_COUNT 4
+#define INVALID_HEADER_POS std::numeric_limits<size_t>::max()
+
+ScFilterDlg::EntryList::EntryList() :
+ mnHeaderPos(INVALID_HEADER_POS) {}
+
+ScFilterDlg::ScFilterDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ const SfxItemSet& rArgSet)
+ : ScAnyRefDlgController(pB, pCW, pParent,
+ "modules/scalc/ui/standardfilterdialog.ui", "StandardFilterDialog")
+ , aStrUndefined(ScResId(SCSTR_UNDEFINED))
+ , aStrNone(ScResId(SCSTR_NONE))
+ , aStrEmpty(ScResId(SCSTR_FILTER_EMPTY))
+ , aStrNotEmpty(ScResId(SCSTR_FILTER_NOTEMPTY))
+ , aStrColumn(ScResId(SCSTR_COLUMN_LETTER))
+ , aStrTextColor(ScResId(SCSTR_FILTER_TEXT_COLOR_COND))
+ , aStrBackgroundColor(ScResId(SCSTR_FILTER_BACKGROUND_COLOR_COND))
+ , nWhichQuery(rArgSet.GetPool()->GetWhich(SID_QUERY))
+ , theQueryData(static_cast<const ScQueryItem&>(rArgSet.Get(nWhichQuery)).GetQueryData())
+ , pViewData(nullptr)
+ , pDoc(nullptr)
+ , nSrcTab(0)
+ , bRefInputMode(false)
+ , m_xLbConnect1(m_xBuilder->weld_combo_box("connect1"))
+ , m_xLbField1(m_xBuilder->weld_combo_box("field1"))
+ , m_xLbCond1(m_xBuilder->weld_combo_box("cond1"))
+ , m_xEdVal1(m_xBuilder->weld_combo_box("val1"))
+ , m_xLbColor1(m_xBuilder->weld_combo_box("color1"))
+ , m_xBtnRemove1(m_xBuilder->weld_button("remove1"))
+ , m_xLbConnect2(m_xBuilder->weld_combo_box("connect2"))
+ , m_xLbField2(m_xBuilder->weld_combo_box("field2"))
+ , m_xLbCond2(m_xBuilder->weld_combo_box("cond2"))
+ , m_xEdVal2(m_xBuilder->weld_combo_box("val2"))
+ , m_xLbColor2(m_xBuilder->weld_combo_box("color2"))
+ , m_xBtnRemove2(m_xBuilder->weld_button("remove2"))
+ , m_xLbConnect3(m_xBuilder->weld_combo_box("connect3"))
+ , m_xLbField3(m_xBuilder->weld_combo_box("field3"))
+ , m_xLbCond3(m_xBuilder->weld_combo_box("cond3"))
+ , m_xEdVal3(m_xBuilder->weld_combo_box("val3"))
+ , m_xLbColor3(m_xBuilder->weld_combo_box("color3"))
+ , m_xBtnRemove3(m_xBuilder->weld_button("remove3"))
+ , m_xLbConnect4(m_xBuilder->weld_combo_box("connect4"))
+ , m_xLbField4(m_xBuilder->weld_combo_box("field4"))
+ , m_xLbCond4(m_xBuilder->weld_combo_box("cond4"))
+ , m_xEdVal4(m_xBuilder->weld_combo_box("val4"))
+ , m_xLbColor4(m_xBuilder->weld_combo_box("color4"))
+ , m_xBtnRemove4(m_xBuilder->weld_button("remove4"))
+ , m_xContents(m_xBuilder->weld_widget("grid"))
+ , m_xScrollBar(m_xBuilder->weld_scrolled_window("scrollbar", true))
+ , m_xExpander(m_xBuilder->weld_expander("more"))
+ , m_xBtnClear(m_xBuilder->weld_button("clear"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_xBtnCase(m_xBuilder->weld_check_button("case"))
+ , m_xBtnRegExp(m_xBuilder->weld_check_button("regexp"))
+ , m_xBtnHeader(m_xBuilder->weld_check_button("header"))
+ , m_xBtnUnique(m_xBuilder->weld_check_button("unique"))
+ , m_xBtnCopyResult(m_xBuilder->weld_check_button("copyresult"))
+ , m_xLbCopyArea(m_xBuilder->weld_combo_box("lbcopyarea"))
+ , m_xEdCopyArea(new formula::RefEdit(m_xBuilder->weld_entry("edcopyarea")))
+ , m_xRbCopyArea(new formula::RefButton(m_xBuilder->weld_button("rbcopyarea")))
+ , m_xBtnDestPers(m_xBuilder->weld_check_button("destpers"))
+ , m_xFtDbAreaLabel(m_xBuilder->weld_label("dbarealabel"))
+ , m_xFtDbArea(m_xBuilder->weld_label("dbarea"))
+{
+ m_xExpander->connect_expanded(LINK(this, ScFilterDlg, MoreExpandedHdl));
+ m_xEdCopyArea->SetReferences(this, m_xFtDbAreaLabel.get());
+ m_xRbCopyArea->SetReferences(this, m_xEdCopyArea.get());
+
+ assert(m_xLbCond1->find_text(aStrTextColor) != -1);
+ assert(m_xLbCond1->find_text(aStrBackgroundColor) != -1);
+
+ Init( rArgSet );
+
+ // Hack: RefInput control
+ pTimer.reset( new Timer("ScFilterTimer") );
+ pTimer->SetTimeout( 50 ); // Wait 50ms
+ pTimer->SetInvokeHandler( LINK( this, ScFilterDlg, TimeOutHdl ) );
+}
+
+ScFilterDlg::~ScFilterDlg()
+{
+ pOptionsMgr.reset();
+ pOutItem.reset();
+
+ // Hack: RefInput control
+ pTimer->Stop();
+ pTimer.reset();
+}
+
+namespace {
+VirtualDevice* lcl_getColorImage(const Color &rColor)
+{
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Size aImageSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize());
+
+ VclPtrInstance<VirtualDevice> xDevice;
+ xDevice->SetOutputSize(aImageSize);
+ const tools::Rectangle aRect(Point(0, 0), aImageSize);
+ if (rColor == COL_NONE_COLOR)
+ {
+ const Color aW(COL_WHITE);
+ const Color aG(0xef, 0xef, 0xef);
+ xDevice->DrawCheckered(aRect.TopLeft(), aRect.GetSize(), 8, aW, aG);
+ xDevice->SetFillColor();
+ }
+ else
+ {
+ xDevice->SetFillColor(rColor);
+ }
+
+ xDevice->DrawRect(aRect);
+
+ return xDevice.get();
+}
+}
+
+void ScFilterDlg::Init( const SfxItemSet& rArgSet )
+{
+ const ScQueryItem& rQueryItem = static_cast<const ScQueryItem&>(
+ rArgSet.Get( nWhichQuery ));
+
+ m_xBtnClear->connect_clicked ( LINK( this, ScFilterDlg, BtnClearHdl ) );
+ m_xBtnOk->connect_clicked ( LINK( this, ScFilterDlg, EndDlgHdl ) );
+ m_xBtnCancel->connect_clicked ( LINK( this, ScFilterDlg, EndDlgHdl ) );
+ m_xBtnHeader->connect_toggled ( LINK( this, ScFilterDlg, CheckBoxHdl ) );
+ m_xBtnCase->connect_toggled ( LINK( this, ScFilterDlg, CheckBoxHdl ) );
+
+ m_xLbField1->connect_changed ( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbField2->connect_changed ( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbField3->connect_changed ( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbField4->connect_changed ( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbConnect1->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbConnect2->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbConnect3->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbConnect4->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+
+ m_xLbField1->append_text("0000000000");
+ m_xLbField1->set_active(0);
+ auto nPrefWidth = m_xLbField1->get_preferred_size().Width();
+ m_xLbField1->clear();
+
+ m_xLbField1->set_size_request(nPrefWidth, -1);
+ m_xLbField2->set_size_request(nPrefWidth, -1);
+ m_xLbField3->set_size_request(nPrefWidth, -1);
+ m_xLbField4->set_size_request(nPrefWidth, -1);
+
+ m_xLbCond1->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbCond2->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbCond3->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbCond4->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+
+ m_xLbColor1->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbColor2->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbColor3->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+ m_xLbColor4->connect_changed( LINK( this, ScFilterDlg, LbSelectHdl ) );
+
+ m_xBtnRemove1->connect_clicked( LINK( this, ScFilterDlg, BtnRemoveHdl ) );
+ m_xBtnRemove2->connect_clicked( LINK( this, ScFilterDlg, BtnRemoveHdl ) );
+ m_xBtnRemove3->connect_clicked( LINK( this, ScFilterDlg, BtnRemoveHdl ) );
+ m_xBtnRemove4->connect_clicked( LINK( this, ScFilterDlg, BtnRemoveHdl ) );
+
+ pViewData = rQueryItem.GetViewData();
+ pDoc = pViewData ? &pViewData->GetDocument() : nullptr;
+ nSrcTab = pViewData ? pViewData->GetTabNo() : static_cast<SCTAB>(0);
+
+ // for easier access:
+ maFieldLbArr.reserve(QUERY_ENTRY_COUNT);
+ maFieldLbArr.push_back(m_xLbField1.get());
+ maFieldLbArr.push_back(m_xLbField2.get());
+ maFieldLbArr.push_back(m_xLbField3.get());
+ maFieldLbArr.push_back(m_xLbField4.get());
+ maValueEdArr.reserve(QUERY_ENTRY_COUNT);
+ maValueEdArr.push_back(m_xEdVal1.get());
+ maValueEdArr.push_back(m_xEdVal2.get());
+ maValueEdArr.push_back(m_xEdVal3.get());
+ maValueEdArr.push_back(m_xEdVal4.get());
+ maCondLbArr.reserve(QUERY_ENTRY_COUNT);
+ maCondLbArr.push_back(m_xLbCond1.get());
+ maCondLbArr.push_back(m_xLbCond2.get());
+ maCondLbArr.push_back(m_xLbCond3.get());
+ maCondLbArr.push_back(m_xLbCond4.get());
+ maConnLbArr.reserve(QUERY_ENTRY_COUNT);
+ maConnLbArr.push_back(m_xLbConnect1.get());
+ maConnLbArr.push_back(m_xLbConnect2.get());
+ maConnLbArr.push_back(m_xLbConnect3.get());
+ maConnLbArr.push_back(m_xLbConnect4.get());
+ maColorLbArr.reserve(QUERY_ENTRY_COUNT);
+ maColorLbArr.push_back(m_xLbColor1.get());
+ maColorLbArr.push_back(m_xLbColor2.get());
+ maColorLbArr.push_back(m_xLbColor3.get());
+ maColorLbArr.push_back(m_xLbColor4.get());
+ maRemoveBtnArr.reserve(QUERY_ENTRY_COUNT);
+ maRemoveBtnArr.push_back(m_xBtnRemove1.get());
+ maRemoveBtnArr.push_back(m_xBtnRemove2.get());
+ maRemoveBtnArr.push_back(m_xBtnRemove3.get());
+ maRemoveBtnArr.push_back(m_xBtnRemove4.get());
+
+ // Option initialization:
+ pOptionsMgr.reset( new ScFilterOptionsMgr(
+ pViewData,
+ theQueryData,
+ m_xBtnCase.get(),
+ m_xBtnRegExp.get(),
+ m_xBtnHeader.get(),
+ m_xBtnUnique.get(),
+ m_xBtnCopyResult.get(),
+ m_xBtnDestPers.get(),
+ m_xLbCopyArea.get(),
+ m_xEdCopyArea.get(),
+ m_xRbCopyArea.get(),
+ m_xFtDbAreaLabel.get(),
+ m_xFtDbArea.get(),
+ aStrUndefined ) );
+ // Read in field lists and select entries
+
+ FillFieldLists();
+
+ for (size_t i = 0; i < QUERY_ENTRY_COUNT; ++i)
+ {
+ OUString aValStr;
+ size_t nCondPos = 0;
+ size_t nFieldSelPos = 0;
+
+ maColorLbArr[i]->set_visible(false);
+
+ ScQueryEntry& rEntry = theQueryData.GetEntry(i);
+ if ( rEntry.bDoQuery )
+ {
+ nCondPos = static_cast<size_t>(rEntry.eOp);
+ nFieldSelPos = GetFieldSelPos( static_cast<SCCOL>(rEntry.nField) );
+ if (rEntry.IsQueryByEmpty())
+ {
+ aValStr = aStrEmpty;
+ maCondLbArr[i]->set_sensitive(false);
+ }
+ else if (rEntry.IsQueryByNonEmpty())
+ {
+ aValStr = aStrNotEmpty;
+ maCondLbArr[i]->set_sensitive(false);
+ }
+ else if (rEntry.IsQueryByTextColor() || rEntry.IsQueryByBackgroundColor())
+ {
+ nCondPos = maCondLbArr[i]->find_text(
+ rEntry.IsQueryByTextColor() ? aStrTextColor : aStrBackgroundColor);
+ maValueEdArr[i]->set_visible(false);
+ maColorLbArr[i]->set_visible(true);
+ maColorLbArr[i]->set_sensitive(true);
+ }
+ else
+ {
+ const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
+ OUString aQueryStr = rItem.maString.getString();
+ SetValString(aQueryStr, rItem, aValStr);
+ }
+ }
+ else if ( i == 0 )
+ {
+ nFieldSelPos = pViewData ? GetFieldSelPos(pViewData->GetCurX()) : 0;
+ rEntry.nField = nFieldSelPos ? (theQueryData.nCol1 +
+ static_cast<SCCOL>(nFieldSelPos) - 1) : static_cast<SCCOL>(0);
+ rEntry.bDoQuery=true;
+ if (maRefreshExceptQuery.size() < i + 1)
+ maRefreshExceptQuery.resize(i + 1, false);
+ maRefreshExceptQuery[i] = true;
+
+ }
+ maFieldLbArr[i]->set_active( nFieldSelPos );
+ maCondLbArr [i]->set_active( nCondPos );
+ maValueEdArr[i]->set_entry_text( aValStr );
+ maValueEdArr[i]->set_entry_completion(false);
+ maValueEdArr[i]->connect_changed( LINK( this, ScFilterDlg, ValModifyHdl ) );
+ UpdateValueList(i+1);
+ UpdateColorList(i+1);
+ }
+
+ m_xScrollBar->connect_vadjustment_changed( LINK( this, ScFilterDlg, ScrollHdl ) );
+ m_xScrollBar->vadjustment_configure(0, 0, 8, 1, 3, 4);
+ Size aSize(m_xContents->get_preferred_size());
+ m_xContents->set_size_request(aSize.Width(), aSize.Height());
+
+ m_xLbConnect1->hide();
+ // Disable/Enable Logic:
+
+ (m_xLbField1->get_active() != 0)
+ && (m_xLbField2->get_active() != 0)
+ ? m_xLbConnect2->set_active( static_cast<sal_uInt16>(theQueryData.GetEntry(1).eConnect) )
+ : m_xLbConnect2->set_active(-1);
+
+ (m_xLbField2->get_active() != 0)
+ && (m_xLbField3->get_active() != 0)
+ ? m_xLbConnect3->set_active( static_cast<sal_uInt16>(theQueryData.GetEntry(2).eConnect) )
+ : m_xLbConnect3->set_active(-1);
+
+ (m_xLbField3->get_active() != 0)
+ && (m_xLbField4->get_active() != 0)
+ ? m_xLbConnect4->set_active( static_cast<sal_uInt16>(theQueryData.GetEntry(3).eConnect) )
+ : m_xLbConnect4->set_active(-1);
+ if ( m_xLbField1->get_active() == 0 )
+ {
+ m_xLbConnect2->set_sensitive(false);
+ m_xLbField2->set_sensitive(false);
+ m_xLbCond2->set_sensitive(false);
+ m_xEdVal2->set_sensitive(false);
+ m_xLbColor2->set_sensitive(false);
+ m_xBtnRemove2->set_sensitive(false);
+ }
+ else if ( m_xLbConnect2->get_active() == -1 )
+ {
+ m_xLbField2->set_sensitive(false);
+ m_xLbCond2->set_sensitive(false);
+ m_xEdVal2->set_sensitive(false);
+ m_xLbColor2->set_sensitive(false);
+ m_xBtnRemove2->set_sensitive(false);
+ }
+
+ if ( m_xLbField2->get_active() == 0 )
+ {
+ m_xLbConnect3->set_sensitive(false);
+ m_xLbField3->set_sensitive(false);
+ m_xLbCond3->set_sensitive(false);
+ m_xEdVal3->set_sensitive(false);
+ m_xLbColor3->set_sensitive(false);
+ m_xBtnRemove3->set_sensitive(false);
+ }
+ else if ( m_xLbConnect3->get_active() == -1 )
+ {
+ m_xLbField3->set_sensitive(false);
+ m_xLbCond3->set_sensitive(false);
+ m_xEdVal3->set_sensitive(false);
+ m_xLbColor3->set_sensitive(false);
+ m_xBtnRemove3->set_sensitive(false);
+ }
+ if ( m_xLbField3->get_active() == 0 )
+ {
+ m_xLbConnect4->set_sensitive(false);
+ m_xLbField4->set_sensitive(false);
+ m_xLbCond4->set_sensitive(false);
+ m_xEdVal4->set_sensitive(false);
+ m_xLbColor4->set_sensitive(false);
+ m_xBtnRemove4->set_sensitive(false);
+ }
+ else if ( m_xLbConnect4->get_active() == -1 )
+ {
+ m_xLbField4->set_sensitive(false);
+ m_xLbCond4->set_sensitive(false);
+ m_xEdVal4->set_sensitive(false);
+ m_xLbColor4->set_sensitive(false);
+ m_xBtnRemove4->set_sensitive(false);
+ }
+
+ m_xEdVal1->set_entry_width_chars(10);
+ m_xEdVal2->set_entry_width_chars(10);
+ m_xEdVal3->set_entry_width_chars(10);
+ m_xEdVal4->set_entry_width_chars(10);
+
+ if (pDoc != nullptr && pDoc->GetChangeTrack() != nullptr)
+ m_xBtnCopyResult->set_sensitive(false);
+}
+
+void ScFilterDlg::Close()
+{
+ if (pViewData)
+ pViewData->GetDocShell()->CancelAutoDBRange();
+
+ DoClose( ScFilterDlgWrapper::GetChildWindowId() );
+}
+
+// Mouse-selected cell area becomes the new selection and is shown in the
+// reference text box
+
+void ScFilterDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
+{
+ if ( bRefInputMode ) // Only possible if in reference edit mode
+ {
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart( m_xEdCopyArea.get() );
+ OUString aRefStr(rRef.aStart.Format(ScRefFlags::ADDR_ABS_3D, &rDocP, rDocP.GetAddressConvention()));
+ m_xEdCopyArea->SetRefString( aRefStr );
+ }
+}
+
+void ScFilterDlg::SetActive()
+{
+ if ( bRefInputMode )
+ {
+ m_xEdCopyArea->GrabFocus();
+ m_xEdCopyArea->GetModifyHdl().Call( *m_xEdCopyArea );
+ }
+ else
+ m_xDialog->grab_focus();
+
+ RefInputDone();
+}
+
+void ScFilterDlg::FillFieldLists()
+{
+ m_xLbField1->freeze();
+ m_xLbField2->freeze();
+ m_xLbField3->freeze();
+ m_xLbField4->freeze();
+
+ m_xLbField1->clear();
+ m_xLbField2->clear();
+ m_xLbField3->clear();
+ m_xLbField4->clear();
+ m_xLbField1->append_text( aStrNone );
+ m_xLbField2->append_text( aStrNone );
+ m_xLbField3->append_text( aStrNone );
+ m_xLbField4->append_text( aStrNone );
+
+ if ( pDoc )
+ {
+ OUString aFieldName;
+ SCTAB nTab = nSrcTab;
+ SCCOL nFirstCol = theQueryData.nCol1;
+ SCROW nFirstRow = theQueryData.nRow1;
+ SCCOL nMaxCol = theQueryData.nCol2;
+ SCCOL col = 0;
+
+ for ( col=nFirstCol; col<=nMaxCol; col++ )
+ {
+ aFieldName = pDoc->GetString(col, nFirstRow, nTab);
+ if (!m_xBtnHeader->get_active() || aFieldName.isEmpty())
+ {
+ aFieldName = ScGlobal::ReplaceOrAppend( aStrColumn, u"%1", ScColToAlpha( col ));
+ }
+ m_xLbField1->append_text( aFieldName );
+ m_xLbField2->append_text( aFieldName );
+ m_xLbField3->append_text( aFieldName );
+ m_xLbField4->append_text( aFieldName );
+ }
+ }
+
+ m_xLbField4->thaw();
+ m_xLbField3->thaw();
+ m_xLbField2->thaw();
+ m_xLbField1->thaw();
+}
+
+void ScFilterDlg::UpdateValueList( size_t nList )
+{
+ bool bCaseSens = m_xBtnCase->get_active();
+
+ if (pDoc && nList > 0 && nList <= QUERY_ENTRY_COUNT)
+ {
+ weld::ComboBox* pValList = maValueEdArr[nList-1];
+ const sal_Int32 nFieldSelPos = maFieldLbArr[nList-1]->get_active();
+ OUString aCurValue = pValList->get_active_text();
+
+ std::unique_ptr<weld::WaitObject> xWaiter;
+ std::vector<weld::ComboBoxEntry> aEntries;
+ aEntries.emplace_back(aStrNotEmpty);
+ aEntries.emplace_back(aStrEmpty);
+
+ if (nFieldSelPos)
+ {
+ xWaiter.reset(new weld::WaitObject(m_xDialog.get())); // even if only the list box has content
+ SCCOL nColumn = theQueryData.nCol1 + static_cast<SCCOL>(nFieldSelPos) - 1;
+ EntryList* pList = nullptr;
+ if (!m_EntryLists.count(nColumn))
+ {
+ size_t nOffset = GetSliderPos();
+ SCTAB nTab = nSrcTab;
+ SCROW nFirstRow = theQueryData.nRow1;
+ SCROW nLastRow = theQueryData.nRow2;
+ if (maHasDates.size() < nOffset+nList)
+ maHasDates.resize(nOffset+nList, false);
+ maHasDates[nOffset+nList-1] = false;
+
+ // first without the first line
+ std::pair<EntryListsMap::iterator, bool> r =
+ m_EntryLists.insert(std::make_pair(nColumn, std::make_unique<EntryList>()));
+ if (!r.second)
+ // insertion failed.
+ return;
+
+ pList = r.first->second.get();
+ pDoc->GetFilterEntriesArea(
+ nColumn, nFirstRow+1, nLastRow,
+ nTab, bCaseSens, pList->maFilterEntries);
+ maHasDates[nOffset+nList-1] = pList->maFilterEntries.mbHasDates;
+
+ // Entry for the first line
+ //! Entry (pHdrEntry) doesn't generate collection?
+
+ pList->mnHeaderPos = INVALID_HEADER_POS;
+ ScFilterEntries aHdrColl;
+ pDoc->GetFilterEntriesArea(
+ nColumn, nFirstRow, nFirstRow, nTab, true, aHdrColl );
+ if (!aHdrColl.empty())
+ {
+ // See if the header value is already in the list.
+ std::vector<ScTypedStrData>::iterator itBeg = pList->maFilterEntries.begin(), itEnd = pList->maFilterEntries.end();
+ if (std::none_of(itBeg, itEnd, FindTypedStrData(aHdrColl.front(), bCaseSens)))
+ {
+ // Not in the list. Insert it.
+ pList->maFilterEntries.push_back(aHdrColl.front());
+ if (bCaseSens)
+ std::sort(pList->maFilterEntries.begin(), pList->maFilterEntries.end(), ScTypedStrData::LessCaseSensitive());
+ else
+ std::sort(pList->maFilterEntries.begin(), pList->maFilterEntries.end(), ScTypedStrData::LessCaseInsensitive());
+
+ // Record its position.
+ itBeg = pList->maFilterEntries.begin();
+ itEnd = pList->maFilterEntries.end();
+ auto it = std::find_if(itBeg, itEnd, FindTypedStrData(aHdrColl.front(), bCaseSens));
+ pList->mnHeaderPos = std::distance(itBeg, it);
+ }
+ }
+ }
+ else
+ pList = m_EntryLists[nColumn].get();
+
+ assert(pList);
+
+ for (const auto& rEntry : pList->maFilterEntries)
+ aEntries.emplace_back(rEntry.GetString());
+ }
+ pValList->insert_vector(aEntries, false);
+ pValList->set_entry_text(aCurValue);
+ }
+
+ UpdateHdrInValueList( nList );
+}
+
+void ScFilterDlg::UpdateHdrInValueList( size_t nList )
+{
+ //! GetText / SetText ??
+
+ if (!pDoc)
+ return;
+
+ if (nList == 0 || nList > QUERY_ENTRY_COUNT)
+ return;
+
+ size_t nFieldSelPos = maFieldLbArr[nList-1]->get_active();
+ if (!nFieldSelPos)
+ return;
+
+ SCCOL nColumn = theQueryData.nCol1 + static_cast<SCCOL>(nFieldSelPos) - 1;
+ if (!m_EntryLists.count(nColumn))
+ {
+ OSL_FAIL("column not yet initialized");
+ return;
+ }
+
+ size_t const nPos = m_EntryLists[nColumn]->mnHeaderPos;
+ if (nPos == INVALID_HEADER_POS)
+ return;
+
+ weld::ComboBox* pValList = maValueEdArr[nList-1];
+ int nListPos = nPos + 2; // for "empty" and "non-empty"
+
+ const ScTypedStrData& rHdrEntry = m_EntryLists[nColumn]->maFilterEntries.maStrData[nPos];
+
+ const OUString& aHdrStr = rHdrEntry.GetString();
+ bool bWasThere = nListPos < pValList->get_count() && aHdrStr == pValList->get_text(nListPos);
+ bool bInclude = !m_xBtnHeader->get_active();
+
+ if (bInclude) // Include entry
+ {
+ if (!bWasThere)
+ pValList->insert_text(nListPos, aHdrStr);
+ }
+ else // Omit entry
+ {
+ if (bWasThere)
+ pValList->remove(nListPos);
+ }
+}
+
+void ScFilterDlg::ClearValueList( size_t nList )
+{
+ if (nList > 0 && nList <= QUERY_ENTRY_COUNT)
+ {
+ weld::ComboBox* pValList = maValueEdArr[nList-1];
+ pValList->clear();
+ pValList->append_text( aStrNotEmpty );
+ pValList->append_text( aStrEmpty );
+ pValList->set_entry_text( OUString() );
+ }
+}
+
+void ScFilterDlg::UpdateColorList(size_t nList)
+{
+ if (!pDoc || nList <= 0 || nList > QUERY_ENTRY_COUNT)
+ return;
+
+ size_t nPos = nList - 1;
+ ScQueryEntry& rEntry = theQueryData.GetEntry(nPos);
+ const sal_Int32 nFieldSelPos = maFieldLbArr[nPos]->get_active();
+ if (!nFieldSelPos)
+ return;
+
+ SCCOL nColumn = theQueryData.nCol1 + static_cast<SCCOL>(nFieldSelPos) - 1;
+ EntryList* pList = m_EntryLists[nColumn].get();
+ if (!pList)
+ return;
+
+ std::set<Color> aColors;
+ OUString sSelectedCondition = maCondLbArr[nPos]->get_active_text();
+ if (sSelectedCondition == aStrTextColor)
+ aColors = pList->maFilterEntries.getTextColors();
+ else if (sSelectedCondition == aStrBackgroundColor)
+ aColors = pList->maFilterEntries.getBackgroundColors();
+ else
+ return;
+
+ maColorLbArr[nPos]->clear();
+ for (const auto& rColor : aColors)
+ {
+ OUString sId = rColor.AsRGBHexString();
+ if (rColor == COL_AUTO)
+ {
+ OUString sText = sSelectedCondition == aStrTextColor
+ ? ScResId(SCSTR_FILTER_AUTOMATIC_COLOR)
+ : ScResId(SCSTR_FILTER_NO_FILL);
+ maColorLbArr[nPos]->append(sId, sText);
+ }
+ else
+ {
+ VirtualDevice* pDev = lcl_getColorImage(rColor);
+ maColorLbArr[nPos]->append(sId, OUString(), *pDev);
+ }
+
+ auto aItem = rEntry.GetQueryItem();
+ if (aItem.maColor == rColor
+ && ((sSelectedCondition == aStrTextColor && aItem.meType == ScQueryEntry::ByTextColor)
+ || (sSelectedCondition == aStrBackgroundColor
+ && aItem.meType == ScQueryEntry::ByBackgroundColor)))
+ {
+ maColorLbArr[nPos]->set_active_id(sId);
+ }
+ }
+}
+
+size_t ScFilterDlg::GetFieldSelPos( SCCOL nField )
+{
+ if ( nField >= theQueryData.nCol1 && nField <= theQueryData.nCol2 )
+ return static_cast<size_t>(nField - theQueryData.nCol1 + 1);
+ else
+ return 0;
+}
+
+ScQueryItem* ScFilterDlg::GetOutputItem()
+{
+ ScAddress theCopyPos;
+ ScQueryParam theParam( theQueryData );
+ bool bCopyPosOk = false;
+
+ if ( m_xBtnCopyResult->get_active() )
+ {
+ ScRefFlags nResult = theCopyPos.Parse(
+ m_xEdCopyArea->GetText(), *pDoc, pDoc->GetAddressConvention());
+ bCopyPosOk = (nResult & ScRefFlags::VALID) == ScRefFlags::VALID;
+ }
+
+ if ( m_xBtnCopyResult->get_active() && bCopyPosOk )
+ {
+ theParam.bInplace = false;
+ theParam.nDestTab = theCopyPos.Tab();
+ theParam.nDestCol = theCopyPos.Col();
+ theParam.nDestRow = theCopyPos.Row();
+ }
+ else
+ {
+ theParam.bInplace = true;
+ theParam.nDestTab = 0;
+ theParam.nDestCol = 0;
+ theParam.nDestRow = 0;
+ }
+
+ theParam.bHasHeader = m_xBtnHeader->get_active();
+ theParam.bByRow = true;
+ theParam.bDuplicate = !m_xBtnUnique->get_active();
+ theParam.bCaseSens = m_xBtnCase->get_active();
+ theParam.eSearchType = m_xBtnRegExp->get_active() ? utl::SearchParam::SearchType::Regexp : utl::SearchParam::SearchType::Normal;
+ theParam.bDestPers = m_xBtnDestPers->get_active();
+
+ // only set the three - reset everything else
+
+ pOutItem.reset( new ScQueryItem( nWhichQuery, &theParam ) );
+
+ return pOutItem.get();
+}
+
+bool ScFilterDlg::IsRefInputMode() const
+{
+ return bRefInputMode;
+}
+
+// Handler:
+
+IMPL_LINK( ScFilterDlg, BtnClearHdl, weld::Button&, rBtn, void )
+{
+ if ( &rBtn != m_xBtnClear.get() )
+ return;
+
+ // scroll to the top
+ m_xScrollBar->vadjustment_set_value(0);
+ size_t nOffset = 0;
+ RefreshEditRow( nOffset);
+
+ // clear all conditions
+ m_xLbConnect1->set_active(-1);
+ m_xLbConnect2->set_active(-1);
+ m_xLbConnect3->set_active(-1);
+ m_xLbConnect4->set_active(-1);
+ m_xLbField1->set_active(0);
+ m_xLbField2->set_active(0);
+ m_xLbField3->set_active(0);
+ m_xLbField4->set_active(0);
+ m_xLbCond1->set_active(0);
+ m_xLbCond2->set_active(0);
+ m_xLbCond3->set_active(0);
+ m_xLbCond4->set_active(0);
+ ClearValueList( 1 );
+ ClearValueList( 2 );
+ ClearValueList( 3 );
+ ClearValueList( 4 );
+
+ // disable fields for second row onward
+ m_xLbConnect2->set_sensitive(false);
+ m_xLbConnect3->set_sensitive(false);
+ m_xLbConnect4->set_sensitive(false);
+ m_xLbField2->set_sensitive(false);
+ m_xLbField3->set_sensitive(false);
+ m_xLbField4->set_sensitive(false);
+ m_xLbCond2->set_sensitive(false);
+ m_xLbCond3->set_sensitive(false);
+ m_xLbCond4->set_sensitive(false);
+ m_xEdVal2->set_sensitive(false);
+ m_xEdVal3->set_sensitive(false);
+ m_xEdVal4->set_sensitive(false);
+ m_xLbColor2->set_sensitive(false);
+ m_xLbColor3->set_sensitive(false);
+ m_xLbColor4->set_sensitive(false);
+ m_xBtnRemove2->set_sensitive(false);
+ m_xBtnRemove3->set_sensitive(false);
+ m_xBtnRemove4->set_sensitive(false);
+
+ // clear query data objects
+ SCSIZE nCount = theQueryData.GetEntryCount();
+ if (maRefreshExceptQuery.size() < nCount + 1)
+ maRefreshExceptQuery.resize(nCount + 1, false);
+ for (SCSIZE i = 0; i < nCount; ++i)
+ {
+ theQueryData.GetEntry(i).bDoQuery = false;
+ maRefreshExceptQuery[i] = false;
+ theQueryData.GetEntry(i).nField = static_cast<SCCOL>(0);
+ }
+ maRefreshExceptQuery[0] = true;
+}
+
+IMPL_LINK( ScFilterDlg, EndDlgHdl, weld::Button&, rBtn, void )
+{
+ if ( &rBtn == m_xBtnOk.get() )
+ {
+ bool bAreaInputOk = true;
+
+ if ( m_xBtnCopyResult->get_active() )
+ {
+ if ( !pOptionsMgr->VerifyPosStr( m_xEdCopyArea->GetText() ) )
+ {
+ if (!m_xExpander->get_expanded())
+ m_xExpander->set_expanded(true);
+
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(STR_INVALID_TABREF)));
+ xBox->run();
+ m_xEdCopyArea->GrabFocus();
+ bAreaInputOk = false;
+ }
+ }
+
+ if ( bAreaInputOk )
+ {
+ SetDispatcherLock( false );
+ SwitchToDocument();
+ GetBindings().GetDispatcher()->ExecuteList(FID_FILTER_OK,
+ SfxCallMode::SLOT | SfxCallMode::RECORD,
+ { GetOutputItem() });
+ response(RET_OK);
+ }
+ }
+ else if ( &rBtn == m_xBtnCancel.get() )
+ {
+ response(RET_CANCEL);
+ }
+}
+
+IMPL_LINK_NOARG(ScFilterDlg, MoreExpandedHdl, weld::Expander&, void)
+{
+ if ( m_xExpander->get_expanded() )
+ pTimer->Start();
+ else
+ {
+ pTimer->Stop();
+ bRefInputMode = false;
+ //@BugID 54702 Enable/disable only in Basic class
+ //SFX_APPWINDOW->Disable(FALSE); //! general method in ScAnyRefDlg
+ }
+}
+
+IMPL_LINK( ScFilterDlg, TimeOutHdl, Timer*, _pTimer, void )
+{
+ // Check if RefInputMode is still true every 50ms
+ if (_pTimer == pTimer.get() && m_xDialog->has_toplevel_focus())
+ bRefInputMode = (m_xEdCopyArea->GetWidget()->has_focus() || m_xRbCopyArea->GetWidget()->has_focus());
+
+ if ( m_xExpander->get_expanded() )
+ pTimer->Start();
+}
+
+IMPL_LINK(ScFilterDlg, LbSelectHdl, weld::ComboBox&, rLb, void)
+{
+ /*
+ * Handle enable/disable logic depending on which ListBox was selected
+ */
+ sal_uInt16 nOffset = GetSliderPos();
+
+ if ( &rLb == m_xLbConnect1.get() )
+ {
+ m_xLbField1->set_sensitive(true);
+ m_xLbCond1->set_sensitive(true);
+ m_xEdVal1->set_sensitive(true);
+ m_xBtnRemove1->set_sensitive(true);
+
+ const sal_Int32 nConnect1 = m_xLbConnect1->get_active();
+ size_t nQE = nOffset;
+ theQueryData.GetEntry(nQE).eConnect =static_cast<ScQueryConnect>(nConnect1);
+ if (maRefreshExceptQuery.size() < nQE + 1)
+ maRefreshExceptQuery.resize(nQE + 1, false);
+ maRefreshExceptQuery[nQE] = true;
+ }
+ else if ( &rLb == m_xLbConnect2.get() )
+ {
+ m_xLbField2->set_sensitive(true);
+ m_xLbCond2->set_sensitive(true);
+ m_xEdVal2->set_sensitive(true);
+ m_xBtnRemove2->set_sensitive(true);
+
+ const sal_Int32 nConnect2 = m_xLbConnect2->get_active();
+ size_t nQE = 1+nOffset;
+ theQueryData.GetEntry(nQE).eConnect =static_cast<ScQueryConnect>(nConnect2);
+ if (maRefreshExceptQuery.size() < nQE + 1)
+ maRefreshExceptQuery.resize(nQE + 1, false);
+ maRefreshExceptQuery[nQE]=true;
+ }
+ else if ( &rLb == m_xLbConnect3.get() )
+ {
+ m_xLbField3->set_sensitive(true);
+ m_xLbCond3->set_sensitive(true);
+ m_xEdVal3->set_sensitive(true);
+ m_xBtnRemove3->set_sensitive(true);
+
+ const sal_Int32 nConnect3 = m_xLbConnect3->get_active();
+ size_t nQE = 2 + nOffset;
+ theQueryData.GetEntry(nQE).eConnect = static_cast<ScQueryConnect>(nConnect3);
+ if (maRefreshExceptQuery.size() < nQE + 1)
+ maRefreshExceptQuery.resize(nQE + 1, false);
+ maRefreshExceptQuery[nQE] = true;
+
+ }
+ else if ( &rLb == m_xLbConnect4.get() )
+ {
+ m_xLbField4->set_sensitive(true);
+ m_xLbCond4->set_sensitive(true);
+ m_xEdVal4->set_sensitive(true);
+ m_xLbColor4->set_sensitive(true);
+ m_xBtnRemove4->set_sensitive(true);
+
+ const sal_Int32 nConnect4 = m_xLbConnect4->get_active();
+ size_t nQE = 3 + nOffset;
+ theQueryData.GetEntry(nQE).eConnect = static_cast<ScQueryConnect>(nConnect4);
+ if (maRefreshExceptQuery.size() < nQE + 1)
+ maRefreshExceptQuery.resize(nQE + 1, false);
+ maRefreshExceptQuery[nQE] = true;
+ }
+ else if ( &rLb == m_xLbField1.get() )
+ {
+ if ( m_xLbField1->get_active() == 0 )
+ {
+ m_xLbConnect2->set_active(-1);
+ m_xLbConnect3->set_active(-1);
+ m_xLbConnect4->set_active(-1);
+ m_xLbField2->set_active( 0 );
+ m_xLbField3->set_active( 0 );
+ m_xLbField4->set_active( 0 );
+ m_xLbCond2->set_active( 0 );
+ m_xLbCond3->set_active( 0 );
+ m_xLbCond4->set_active( 0 );
+ ClearValueList( 1 );
+ ClearValueList( 2 );
+ ClearValueList( 3 );
+ ClearValueList( 4 );
+
+ m_xLbConnect2->set_sensitive(false);
+ m_xLbConnect3->set_sensitive(false);
+ m_xLbConnect4->set_sensitive(false);
+ m_xLbField2->set_sensitive(false);
+ m_xLbField3->set_sensitive(false);
+ m_xLbField4->set_sensitive(false);
+ m_xLbCond2->set_sensitive(false);
+ m_xLbCond3->set_sensitive(false);
+ m_xLbCond4->set_sensitive(false);
+ m_xEdVal2->set_sensitive(false);
+ m_xEdVal3->set_sensitive(false);
+ m_xEdVal4->set_sensitive(false);
+ m_xLbColor2->set_sensitive(false);
+ m_xLbColor3->set_sensitive(false);
+ m_xLbColor4->set_sensitive(false);
+ m_xBtnRemove2->set_sensitive(false);
+ m_xBtnRemove3->set_sensitive(false);
+ m_xBtnRemove4->set_sensitive(false);
+ SCSIZE nCount = theQueryData.GetEntryCount();
+ if (maRefreshExceptQuery.size() < nCount + 1)
+ maRefreshExceptQuery.resize(nCount + 1, false);
+ for (SCSIZE i = nOffset; i < nCount; ++i)
+ {
+ theQueryData.GetEntry(i).bDoQuery = false;
+ maRefreshExceptQuery[i] = false;
+ theQueryData.GetEntry(i).nField = static_cast<SCCOL>(0);
+ }
+ maRefreshExceptQuery[nOffset] = true;
+ }
+ else
+ {
+ UpdateValueList( 1 );
+ UpdateColorList( 1 );
+ if ( !m_xLbConnect2->get_sensitive() )
+ {
+ m_xLbConnect2->set_sensitive(true);
+ }
+ theQueryData.GetEntry(nOffset).bDoQuery = true;
+ const sal_Int32 nField = rLb.get_active();
+ theQueryData.GetEntry(nOffset).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;
+ }
+ }
+ else if ( &rLb == m_xLbField2.get() )
+ {
+ if ( m_xLbField2->get_active() == 0 )
+ {
+ m_xLbConnect3->set_active(-1);
+ m_xLbConnect4->set_active(-1);
+ m_xLbField3->set_active( 0 );
+ m_xLbField4->set_active( 0 );
+ m_xLbCond3->set_active( 0 );
+ m_xLbCond4->set_active( 0 );
+ ClearValueList( 2 );
+ ClearValueList( 3 );
+ ClearValueList( 4 );
+
+ m_xLbConnect3->set_sensitive(false);
+ m_xLbConnect4->set_sensitive(false);
+ m_xLbField3->set_sensitive(false);
+ m_xLbField4->set_sensitive(false);
+ m_xLbCond3->set_sensitive(false);
+ m_xLbCond4->set_sensitive(false);
+ m_xEdVal3->set_sensitive(false);
+ m_xEdVal4->set_sensitive(false);
+ m_xLbColor3->set_sensitive(false);
+ m_xLbColor4->set_sensitive(false);
+ m_xBtnRemove3->set_sensitive(false);
+ m_xBtnRemove4->set_sensitive(false);
+
+ sal_uInt16 nTemp=nOffset+1;
+ SCSIZE nCount = theQueryData.GetEntryCount();
+ if (maRefreshExceptQuery.size() < nCount)
+ maRefreshExceptQuery.resize(nCount, false);
+ for (SCSIZE i= nTemp; i< nCount; i++)
+ {
+ theQueryData.GetEntry(i).bDoQuery = false;
+ maRefreshExceptQuery[i] = false;
+ theQueryData.GetEntry(i).nField = static_cast<SCCOL>(0);
+ }
+ maRefreshExceptQuery[nTemp] = true;
+ }
+ else
+ {
+ UpdateValueList( 2 );
+ UpdateColorList( 2 );
+ if ( !m_xLbConnect3->get_sensitive() )
+ {
+ m_xLbConnect3->set_sensitive(true);
+ }
+ const sal_Int32 nField = rLb.get_active();
+ sal_uInt16 nQ=1+nOffset;
+ theQueryData.GetEntry(nQ).bDoQuery = true;
+ theQueryData.GetEntry(nQ).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;
+ }
+ }
+ else if ( &rLb == m_xLbField3.get() )
+ {
+ if ( m_xLbField3->get_active() == 0 )
+ {
+ m_xLbConnect4->set_active(-1);
+ m_xLbField4->set_active( 0 );
+ m_xLbCond4->set_active( 0 );
+ ClearValueList( 3 );
+ ClearValueList( 4 );
+
+ m_xLbConnect4->set_sensitive(false);
+ m_xLbField4->set_sensitive(false);
+ m_xLbCond4->set_sensitive(false);
+ m_xEdVal4->set_sensitive(false);
+ m_xLbColor4->set_sensitive(false);
+ m_xBtnRemove4->set_sensitive(false);
+
+ sal_uInt16 nTemp=nOffset+2;
+ SCSIZE nCount = theQueryData.GetEntryCount();
+ if (maRefreshExceptQuery.size() < nCount)
+ maRefreshExceptQuery.resize(nCount, false);
+ for (SCSIZE i = nTemp; i < nCount; ++i)
+ {
+ theQueryData.GetEntry(i).bDoQuery = false;
+ maRefreshExceptQuery[i] = false;
+ theQueryData.GetEntry(i).nField = static_cast<SCCOL>(0);
+ }
+ maRefreshExceptQuery[nTemp] = true;
+ }
+ else
+ {
+ UpdateValueList( 3 );
+ UpdateColorList( 3 );
+ if ( !m_xLbConnect4->get_sensitive() )
+ {
+ m_xLbConnect4->set_sensitive(true);
+ }
+
+ const sal_Int32 nField = rLb.get_active();
+ sal_uInt16 nQ=2+nOffset;
+ theQueryData.GetEntry(nQ).bDoQuery = true;
+ theQueryData.GetEntry(nQ).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;
+
+ }
+ }
+ else if ( &rLb == m_xLbField4.get() )
+ {
+ if ( m_xLbField4->get_active() == 0 )
+ {
+ ClearValueList( 4 );
+ sal_uInt16 nTemp=nOffset+3;
+ SCSIZE nCount = theQueryData.GetEntryCount();
+ if (maRefreshExceptQuery.size() < nCount)
+ maRefreshExceptQuery.resize(nCount, false);
+ for (SCSIZE i = nTemp; i < nCount; ++i)
+ {
+ theQueryData.GetEntry(i).bDoQuery = false;
+ maRefreshExceptQuery[i] = false;
+ theQueryData.GetEntry(i).nField = static_cast<SCCOL>(0);
+ }
+ maRefreshExceptQuery[nTemp] = true;
+ }
+ else
+ {
+ UpdateValueList( 4 );
+ UpdateColorList( 4 );
+ const sal_Int32 nField = rLb.get_active();
+ sal_uInt16 nQ=3+nOffset;
+ theQueryData.GetEntry(nQ).bDoQuery = true;
+ theQueryData.GetEntry(nQ).nField = theQueryData.nCol1 + static_cast<SCCOL>(nField) - 1 ;
+ }
+
+ }
+ else if (&rLb == m_xLbCond1.get() || &rLb == m_xLbCond2.get() || &rLb == m_xLbCond3.get()
+ || &rLb == m_xLbCond4.get())
+ {
+ ScQueryOp op;
+ sal_uInt16 nQ = 0;
+ bool bEnableColorLb = false;
+ if (rLb.get_active_text() == aStrTextColor || rLb.get_active_text() == aStrBackgroundColor)
+ {
+ bEnableColorLb = true;
+ op = SC_EQUAL;
+ }
+ else
+ {
+ op = static_cast<ScQueryOp>(rLb.get_active());
+ }
+
+ if (&rLb == m_xLbCond1.get())
+ {
+ nQ = nOffset;
+ m_xLbColor1->set_visible(bEnableColorLb);
+ m_xLbColor1->set_sensitive(bEnableColorLb);
+ m_xEdVal1->set_visible(!bEnableColorLb);
+ UpdateColorList(1);
+ }
+ else if (&rLb == m_xLbCond2.get())
+ {
+ nQ = 1 + nOffset;
+ m_xLbColor2->set_visible(bEnableColorLb);
+ m_xLbColor2->set_sensitive(bEnableColorLb);
+ m_xEdVal2->set_visible(!bEnableColorLb);
+ UpdateColorList(2);
+ }
+ else if (&rLb == m_xLbCond3.get())
+ {
+ nQ = 2 + nOffset;
+ m_xLbColor3->set_visible(bEnableColorLb);
+ m_xLbColor3->set_sensitive(bEnableColorLb);
+ m_xEdVal3->set_visible(!bEnableColorLb);
+ UpdateColorList(3);
+ }
+ else if (&rLb == m_xLbCond4.get())
+ {
+ nQ = 3 + nOffset;
+ m_xLbColor4->set_visible(bEnableColorLb);
+ m_xLbColor4->set_sensitive(bEnableColorLb);
+ m_xEdVal4->set_visible(!bEnableColorLb);
+ UpdateColorList(4);
+ }
+
+ auto aEntry = theQueryData.GetEntry(nQ);
+ aEntry.eOp = op;
+ }
+ else if (&rLb == m_xLbColor1.get() || &rLb == m_xLbColor2.get() || &rLb == m_xLbColor3.get()
+ || &rLb == m_xLbColor4.get())
+ {
+ sal_uInt16 nQ = 0;
+ if (&rLb == m_xLbColor1.get())
+ {
+ nQ = nOffset;
+ }
+ else if (&rLb == m_xLbColor2.get())
+ {
+ nQ = 1 + nOffset;
+ }
+ else if (&rLb == m_xLbColor3.get())
+ {
+ nQ = 2 + nOffset;
+ }
+ else if (&rLb == m_xLbColor4.get())
+ {
+ nQ = 3 + nOffset;
+ }
+
+ ScQueryEntry& aEntry = theQueryData.GetEntry(nQ);
+ Color aColor = Color::STRtoRGB(maColorLbArr[nQ]->get_active_id());
+ if (maCondLbArr[nQ]->get_active_text() == aStrTextColor)
+ {
+ aEntry.SetQueryByTextColor(aColor);
+ }
+ else if (maCondLbArr[nQ]->get_active_text() == aStrBackgroundColor)
+ {
+ aEntry.SetQueryByBackgroundColor(aColor);
+ }
+ }
+}
+
+IMPL_LINK( ScFilterDlg, CheckBoxHdl, weld::Toggleable&, rBox, void )
+{
+ // Column headers:
+ // Field list: Columnxx <-> column header string
+ // Value list: Column header value not applicable.
+ // Upper/lower case:
+ // Value list: completely new
+
+ if ( &rBox == m_xBtnHeader.get() ) // Field list and value list
+ {
+ const sal_Int32 nCurSel1 = m_xLbField1->get_active();
+ const sal_Int32 nCurSel2 = m_xLbField2->get_active();
+ const sal_Int32 nCurSel3 = m_xLbField3->get_active();
+ const sal_Int32 nCurSel4 = m_xLbField4->get_active();
+ FillFieldLists();
+ m_xLbField1->set_active( nCurSel1 );
+ m_xLbField2->set_active( nCurSel2 );
+ m_xLbField3->set_active( nCurSel3 );
+ m_xLbField4->set_active( nCurSel4 );
+
+ UpdateHdrInValueList( 1 );
+ UpdateHdrInValueList( 2 );
+ UpdateHdrInValueList( 3 );
+ UpdateHdrInValueList( 4 );
+ }
+
+ if ( &rBox != m_xBtnCase.get() ) // Complete value list
+ return;
+
+ m_EntryLists.clear();
+ UpdateValueList( 1 ); // current text is recorded
+ UpdateValueList( 2 );
+ UpdateValueList( 3 );
+ UpdateValueList( 4 );
+
+ UpdateColorList( 1 );
+ UpdateColorList( 2 );
+ UpdateColorList( 3 );
+ UpdateColorList( 4 );
+}
+
+IMPL_LINK( ScFilterDlg, ValModifyHdl, weld::ComboBox&, rEd, void )
+{
+ size_t nOffset = GetSliderPos();
+ size_t i = 0;
+ size_t nQE = i + nOffset;
+ OUString aStrVal = rEd.get_active_text();
+ weld::ComboBox* pLbCond = m_xLbCond1.get();
+ weld::ComboBox* pLbField = m_xLbField1.get();
+ if ( &rEd == m_xEdVal2.get() )
+ {
+ pLbCond = m_xLbCond2.get();
+ pLbField = m_xLbField2.get();
+ i=1;
+ nQE=i+nOffset;
+ }
+ if ( &rEd == m_xEdVal3.get() )
+ {
+ pLbCond = m_xLbCond3.get();
+ pLbField = m_xLbField3.get();
+ i=2;
+ nQE=i+nOffset;
+ }
+ if ( &rEd == m_xEdVal4.get() )
+ {
+ pLbCond = m_xLbCond4.get();
+ pLbField = m_xLbField4.get();
+ i=3;
+ nQE=i+nOffset;
+ }
+
+ if ( aStrEmpty == aStrVal || aStrNotEmpty == aStrVal )
+ {
+ pLbCond->set_active_text(OUString('='));
+ pLbCond->set_sensitive(false);
+ }
+ else
+ pLbCond->set_sensitive(true);
+
+ if (maHasDates.size() < nQE + 1)
+ maHasDates.resize(nQE + 1, false);
+ if (maRefreshExceptQuery.size() < nQE + 1)
+ maRefreshExceptQuery.resize(nQE + 1, false);
+
+ ScQueryEntry& rEntry = theQueryData.GetEntry( nQE );
+ ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
+ bool bDoThis = (pLbField->get_active() != 0);
+ rEntry.bDoQuery = bDoThis;
+
+ if ( !(rEntry.bDoQuery || maRefreshExceptQuery[nQE]) )
+ return;
+
+ bool bByEmptyOrNotByEmpty = false;
+ if ( aStrEmpty == aStrVal )
+ {
+ bByEmptyOrNotByEmpty = true;
+ rEntry.SetQueryByEmpty();
+ }
+ else if ( aStrNotEmpty == aStrVal )
+ {
+ bByEmptyOrNotByEmpty = true;
+ rEntry.SetQueryByNonEmpty();
+ }
+ else
+ {
+ rItem.maString = pDoc->GetSharedStringPool().intern(aStrVal);
+ rItem.mfVal = 0.0;
+ rItem.meType = ScQueryEntry::ByString;
+ }
+
+ const sal_Int32 nField = pLbField->get_active();
+ rEntry.nField = nField ? (theQueryData.nCol1 +
+ static_cast<SCCOL>(nField) - 1) : static_cast<SCCOL>(0);
+
+ ScQueryOp eOp = static_cast<ScQueryOp>(pLbCond->get_active());
+ rEntry.eOp = eOp;
+ if (maHasDates[nQE] && !bByEmptyOrNotByEmpty)
+ rItem.meType = ScQueryEntry::ByDate;
+}
+
+IMPL_LINK( ScFilterDlg, BtnRemoveHdl, weld::Button&, rBtn, void )
+{
+ // Calculate the row to delete
+ sal_uInt16 nOffset = GetSliderPos();
+ int nButtonIndex = 0;
+ if ( &rBtn == m_xBtnRemove2.get() )
+ nButtonIndex = 1;
+ if ( &rBtn == m_xBtnRemove3.get() )
+ nButtonIndex = 2;
+ if ( &rBtn == m_xBtnRemove4.get() )
+ nButtonIndex = 3;
+ SCSIZE nRowToDelete = nOffset + nButtonIndex;
+
+ // Check that the index is sensible
+ SCSIZE nCount = theQueryData.GetEntryCount();
+ if (nRowToDelete >= nCount)
+ {
+ SAL_WARN( "sc", "ScFilterDlg::BtnRemoveHdl: could not delete row - invalid index.");
+ return;
+ }
+
+ // Resize maRefreshExceptQuery
+ if (maRefreshExceptQuery.size() < nCount + 1)
+ maRefreshExceptQuery.resize(nCount + 1, false);
+
+ // Move all the subsequent rows back one position;
+ // also find the last row, which we will delete
+ SCSIZE nRowToClear = nCount-1;
+ for (SCSIZE i = nRowToDelete; i < nCount-1; ++i)
+ {
+ if (theQueryData.GetEntry(i+1).bDoQuery)
+ {
+ theQueryData.GetEntry(i) = theQueryData.GetEntry(i+1);
+ }
+ else
+ {
+ nRowToClear = i;
+ break;
+ }
+ }
+
+ // If the next row is being edited, but not confirmed, move it back
+ // one position
+ if (nRowToClear < nCount-1 && maRefreshExceptQuery[nRowToClear+1])
+ {
+ theQueryData.GetEntry(nRowToClear) = theQueryData.GetEntry(nRowToClear+1);
+ maRefreshExceptQuery[nRowToClear] = true;
+ maRefreshExceptQuery[nRowToClear+1] = false;
+ }
+ else
+ {
+ // Remove the very last one, since everything has moved back
+ theQueryData.GetEntry(nRowToClear).bDoQuery = false;
+ theQueryData.GetEntry(nRowToClear).nField = static_cast<SCCOL>(0);
+ maRefreshExceptQuery[nRowToClear] = false;
+ }
+
+ // Always enable the very first row
+ if (!theQueryData.GetEntry(0).bDoQuery)
+ {
+ maRefreshExceptQuery[0] = true;
+ }
+
+ // Refresh the UI
+ RefreshEditRow( nOffset );
+
+ // Special handling if the very first row was cleared
+ if (!theQueryData.GetEntry(0).bDoQuery)
+ {
+ m_xLbConnect1->set_active(-1);
+ m_xLbField1->set_active(0);
+ m_xLbField1->set_sensitive(true);
+ m_xLbCond1->set_active(0);
+ m_xLbCond1->set_sensitive(true);
+ ClearValueList(1);
+ }
+}
+
+IMPL_LINK_NOARG(ScFilterDlg, ScrollHdl, weld::ScrolledWindow&, void)
+{
+ SliderMoved();
+}
+
+void ScFilterDlg::SliderMoved()
+{
+ size_t nOffset = GetSliderPos();
+ RefreshEditRow( nOffset);
+}
+
+size_t ScFilterDlg::GetSliderPos() const
+{
+ return static_cast<size_t>(m_xScrollBar->vadjustment_get_value());
+}
+
+void ScFilterDlg::RefreshEditRow( size_t nOffset )
+{
+ if (nOffset==0)
+ maConnLbArr[0]->hide();
+ else
+ maConnLbArr[0]->show();
+
+ for (size_t i = 0; i < QUERY_ENTRY_COUNT; ++i)
+ {
+ OUString aValStr;
+ size_t nCondPos = 0;
+ size_t nFieldSelPos = 0;
+ size_t nQE = i + nOffset;
+
+ maColorLbArr[i]->set_visible(false);
+
+ if (maRefreshExceptQuery.size() < nQE + 1)
+ maRefreshExceptQuery.resize(nQE + 1, false);
+
+ ScQueryEntry& rEntry = theQueryData.GetEntry( nQE);
+ if ( rEntry.bDoQuery || maRefreshExceptQuery[nQE] )
+ {
+ nCondPos = static_cast<size_t>(rEntry.eOp);
+ if(rEntry.bDoQuery)
+ nFieldSelPos = GetFieldSelPos( static_cast<SCCOL>(rEntry.nField) );
+
+ const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
+ OUString aQueryStr = rItem.maString.getString();
+ if (rEntry.IsQueryByEmpty())
+ {
+ aValStr = aStrEmpty;
+ maCondLbArr[i]->set_sensitive(false);
+ }
+ else if (rEntry.IsQueryByNonEmpty())
+ {
+ aValStr = aStrNotEmpty;
+ maCondLbArr[i]->set_sensitive(false);
+ }
+ else if (rEntry.IsQueryByTextColor() || rEntry.IsQueryByBackgroundColor())
+ {
+ nCondPos = maCondLbArr[i]->find_text(
+ rEntry.IsQueryByTextColor() ? aStrTextColor : aStrBackgroundColor);
+
+ maValueEdArr[i]->set_visible(false);
+ maColorLbArr[i]->set_visible(true);
+ maColorLbArr[i]->set_sensitive(true);
+ }
+ else
+ {
+ SetValString(aQueryStr, rItem, aValStr);
+ maCondLbArr[i]->set_sensitive(true);
+ }
+ maFieldLbArr[i]->set_sensitive(true);
+ maValueEdArr[i]->set_sensitive(true);
+ maRemoveBtnArr[i]->set_sensitive(true);
+
+ if (nOffset==0)
+ {
+ if (i<3)
+ {
+ if(rEntry.bDoQuery)
+ maConnLbArr[i+1]->set_sensitive(true);
+ else
+ maConnLbArr[i+1]->set_sensitive(false);
+ size_t nQENext = nQE + 1;
+ if (maRefreshExceptQuery.size() < nQENext + 1)
+ maRefreshExceptQuery.resize(nQENext + 1, false);
+ if (theQueryData.GetEntry(nQENext).bDoQuery || maRefreshExceptQuery[nQENext])
+ maConnLbArr[i+1]->set_active( static_cast<sal_uInt16>(theQueryData.GetEntry(nQENext).eConnect) );
+ else
+ maConnLbArr[i+1]->set_active(-1);
+ }
+ }
+ else
+ {
+ if(theQueryData.GetEntry( nQE-1).bDoQuery)
+ maConnLbArr[i]->set_sensitive(true);
+ else
+ maConnLbArr[i]->set_sensitive(false);
+
+ if (maRefreshExceptQuery.size() < nQE + 1)
+ maRefreshExceptQuery.resize(nQE + 1, false);
+ if(rEntry.bDoQuery || maRefreshExceptQuery[nQE])
+ maConnLbArr[i]->set_active( static_cast<sal_uInt16>(rEntry.eConnect) );
+ else
+ maConnLbArr[i]->set_active(-1);
+ }
+
+ }
+ else
+ {
+ if (nOffset==0)
+ {
+ if(i<3)
+ {
+ maConnLbArr[i+1]->set_active(-1);
+ maConnLbArr[i+1]->set_sensitive(false);
+ }
+ }
+ else
+ {
+ if(theQueryData.GetEntry( nQE-1).bDoQuery)
+ maConnLbArr[i]->set_sensitive(true);
+ else
+ maConnLbArr[i]->set_sensitive(false);
+ maConnLbArr[i]->set_active(-1);
+ }
+ maFieldLbArr[i]->set_sensitive(false);
+ maCondLbArr[i]->set_sensitive(false);
+ maValueEdArr[i]->set_sensitive(false);
+ maRemoveBtnArr[i]->set_sensitive(false);
+ }
+ maFieldLbArr[i]->set_active( nFieldSelPos );
+ maCondLbArr [i]->set_active( nCondPos );
+ maValueEdArr[i]->set_entry_text( aValStr );
+ UpdateValueList(i+1);
+ UpdateColorList(i+1);
+ }
+}
+
+void ScFilterDlg::SetValString( const OUString& rQueryStr, const ScQueryEntry::Item& rItem,
+ OUString& rValStr )
+{
+ if (rQueryStr.isEmpty())
+ {
+ pDoc = pViewData ? &pViewData->GetDocument() : nullptr;
+ if (rItem.meType == ScQueryEntry::ByValue)
+ {
+ if (pDoc)
+ {
+ pDoc->GetFormatTable()->GetInputLineString(rItem.mfVal, 0, rValStr);
+ }
+ }
+ else if (rItem.meType == ScQueryEntry::ByDate)
+ {
+ if (pDoc)
+ {
+ SvNumberFormatter* pFormatter = pDoc->GetFormatTable();
+ pFormatter->GetInputLineString(rItem.mfVal,
+ pFormatter->GetStandardFormat( SvNumFormatType::DATE), rValStr);
+ }
+ }
+ else
+ {
+ SAL_WARN( "sc", "ScFilterDlg::SetValString: empty query string, really?");
+ rValStr = rQueryStr;
+ }
+ }
+ else
+ {
+ // XXX NOTE: if not ByString we just assume this has been
+ // set to a proper string corresponding to the numeric
+ // value earlier!
+ rValStr = rQueryStr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/foptmgr.cxx b/sc/source/ui/dbgui/foptmgr.cxx
new file mode 100644
index 000000000..decaa622b
--- /dev/null
+++ b/sc/source/ui/dbgui/foptmgr.cxx
@@ -0,0 +1,260 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+
+#include <rangeutl.hxx>
+#include <dbdata.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <queryparam.hxx>
+#include <globalnames.hxx>
+
+#include <foptmgr.hxx>
+#include <formula/funcutl.hxx>
+
+// ScFilterOptionsMgr (.ui's option helper)
+
+ScFilterOptionsMgr::ScFilterOptionsMgr(
+ ScViewData* ptrViewData,
+ const ScQueryParam& refQueryData,
+ weld::CheckButton* refBtnCase,
+ weld::CheckButton* refBtnRegExp,
+ weld::CheckButton* refBtnHeader,
+ weld::CheckButton* refBtnUnique,
+ weld::CheckButton* refBtnCopyResult,
+ weld::CheckButton* refBtnDestPers,
+ weld::ComboBox* refLbCopyArea,
+ formula::RefEdit* refEdCopyArea,
+ formula::RefButton* refRbCopyArea,
+ weld::Label* refFtDbAreaLabel,
+ weld::Label* refFtDbArea,
+ const OUString& refStrUndefined )
+
+ : pViewData ( ptrViewData ),
+ pDoc ( ptrViewData ? &ptrViewData->GetDocument() : nullptr ),
+ pBtnCase ( refBtnCase ),
+ pBtnRegExp ( refBtnRegExp ),
+ pBtnHeader ( refBtnHeader ),
+ pBtnUnique ( refBtnUnique ),
+ pBtnCopyResult ( refBtnCopyResult ),
+ pBtnDestPers ( refBtnDestPers ),
+ pLbCopyArea ( refLbCopyArea ),
+ pEdCopyArea ( refEdCopyArea ),
+ pRbCopyArea ( refRbCopyArea ),
+ pFtDbAreaLabel ( refFtDbAreaLabel ),
+ pFtDbArea ( refFtDbArea ),
+ rStrUndefined ( refStrUndefined ),
+ rQueryData ( refQueryData )
+{
+ Init();
+}
+
+void ScFilterOptionsMgr::Init()
+{
+//moggi:TODO
+ OSL_ENSURE( pViewData && pDoc, "Init failed :-/" );
+
+ pLbCopyArea->connect_changed( LINK( this, ScFilterOptionsMgr, LbAreaSelHdl ) );
+ pEdCopyArea->SetModifyHdl ( LINK( this, ScFilterOptionsMgr, EdAreaModifyHdl ) );
+ pBtnCopyResult->connect_toggled( LINK( this, ScFilterOptionsMgr, BtnCopyResultHdl ) );
+
+ pBtnCase->set_active( rQueryData.bCaseSens );
+ pBtnHeader->set_active( rQueryData.bHasHeader );
+ pBtnRegExp->set_active( rQueryData.eSearchType == utl::SearchParam::SearchType::Regexp );
+ pBtnUnique->set_active( !rQueryData.bDuplicate );
+
+ if ( pViewData && pDoc )
+ {
+ OUString theAreaStr;
+ ScRange theCurArea ( ScAddress( rQueryData.nCol1,
+ rQueryData.nRow1,
+ pViewData->GetTabNo() ),
+ ScAddress( rQueryData.nCol2,
+ rQueryData.nRow2,
+ pViewData->GetTabNo() ) );
+ ScDBCollection* pDBColl = pDoc->GetDBCollection();
+ OUString theDbArea;
+ OUString theDbName(STR_DB_LOCAL_NONAME);
+ const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
+
+ theAreaStr = theCurArea.Format(*pDoc, ScRefFlags::RANGE_ABS_3D, eConv);
+
+ // fill the target area list
+
+ pLbCopyArea->clear();
+ pLbCopyArea->append_text(rStrUndefined);
+
+ ScAreaNameIterator aIter( *pDoc );
+ OUString aName;
+ ScRange aRange;
+ while ( aIter.Next( aName, aRange ) )
+ {
+ OUString aRefStr(aRange.aStart.Format(ScRefFlags::ADDR_ABS_3D, pDoc, eConv));
+ pLbCopyArea->append(aRefStr, aName);
+ }
+
+ pBtnDestPers->set_active(true); // always on when called
+ pLbCopyArea->set_active( 0 );
+ pEdCopyArea->SetText( OUString() );
+
+ /*
+ * Check whether the transferred area is a database area:
+ */
+
+ theDbArea = theAreaStr;
+
+ if ( pDBColl )
+ {
+ ScAddress& rStart = theCurArea.aStart;
+ ScAddress& rEnd = theCurArea.aEnd;
+ const ScDBData* pDBData = pDBColl->GetDBAtArea(
+ rStart.Tab(), rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row());
+
+ if ( pDBData )
+ {
+ pBtnHeader->set_active( pDBData->HasHeader() );
+ theDbName = pDBData->GetName();
+
+ pBtnHeader->set_sensitive(theDbName == STR_DB_LOCAL_NONAME);
+ }
+ }
+
+ if ( theDbName != STR_DB_LOCAL_NONAME )
+ {
+ theDbArea += " (" + theDbName + ")";
+
+ pFtDbArea->set_label( theDbArea );
+ }
+ else
+ {
+ pFtDbAreaLabel->set_label( OUString() );
+ pFtDbArea->set_label( OUString() );
+ }
+
+ // position to copy to:
+
+ if ( !rQueryData.bInplace )
+ {
+ OUString aString =
+ ScAddress( rQueryData.nDestCol,
+ rQueryData.nDestRow,
+ rQueryData.nDestTab
+ ).Format(ScRefFlags::ADDR_ABS_3D, pDoc, eConv);
+
+ pBtnCopyResult->set_active(true);
+ pEdCopyArea->SetText( aString );
+ EdAreaModifyHdl( *pEdCopyArea );
+ pLbCopyArea->set_sensitive(true);
+ pEdCopyArea->GetWidget()->set_sensitive(true);
+ pRbCopyArea->GetWidget()->set_sensitive(true);
+ pBtnDestPers->set_sensitive(true);
+ }
+ else
+ {
+ pBtnCopyResult->set_active( false );
+ pEdCopyArea->SetText( OUString() );
+ pLbCopyArea->set_sensitive(false);
+ pEdCopyArea->GetWidget()->set_sensitive(false);
+ pRbCopyArea->GetWidget()->set_sensitive(false);
+ pBtnDestPers->set_sensitive(false);
+ }
+ }
+ else
+ pEdCopyArea->SetText( OUString() );
+}
+
+bool ScFilterOptionsMgr::VerifyPosStr( const OUString& rPosStr ) const
+{
+ OUString aPosStr( rPosStr );
+ sal_Int32 nColonPos = aPosStr.indexOf( ':' );
+
+ if ( -1 != nColonPos )
+ aPosStr = aPosStr.copy( 0, nColonPos );
+
+ ScRefFlags nResult = ScAddress().Parse( aPosStr, *pDoc, pDoc->GetAddressConvention() );
+
+ return (nResult & ScRefFlags::VALID) == ScRefFlags::VALID;
+}
+
+// Handler:
+
+IMPL_LINK( ScFilterOptionsMgr, LbAreaSelHdl, weld::ComboBox&, rLb, void )
+{
+ if ( &rLb == pLbCopyArea )
+ {
+ OUString aString;
+ const sal_Int32 nSelPos = pLbCopyArea->get_active();
+
+ if ( nSelPos > 0 )
+ aString = pLbCopyArea->get_id(nSelPos);
+
+ pEdCopyArea->SetText( aString );
+ }
+}
+
+IMPL_LINK( ScFilterOptionsMgr, EdAreaModifyHdl, formula::RefEdit&, rEd, void )
+{
+ if ( &rEd != pEdCopyArea )
+ return;
+
+ OUString theCurPosStr = rEd.GetText();
+ ScRefFlags nResult = ScAddress().Parse( theCurPosStr, *pDoc, pDoc->GetAddressConvention() );
+
+ if ( (nResult & ScRefFlags::VALID) == ScRefFlags::VALID)
+ {
+ const sal_Int32 nCount = pLbCopyArea->get_count();
+
+ for ( sal_Int32 i=2; i<nCount; ++i )
+ {
+ OUString aStr = pLbCopyArea->get_id(i);
+ if (theCurPosStr == aStr)
+ {
+ pLbCopyArea->set_active( i );
+ return;
+ }
+ }
+
+ }
+ pLbCopyArea->set_active( 0 );
+}
+
+IMPL_LINK( ScFilterOptionsMgr, BtnCopyResultHdl, weld::Toggleable&, rBox, void )
+{
+ if ( &rBox != pBtnCopyResult )
+ return;
+
+ if ( rBox.get_active() )
+ {
+ pBtnDestPers->set_sensitive(true);
+ pLbCopyArea->set_sensitive(true);
+ pEdCopyArea->GetWidget()->set_sensitive(true);
+ pRbCopyArea->GetWidget()->set_sensitive(true);
+ pEdCopyArea->GrabFocus();
+ }
+ else
+ {
+ pBtnDestPers->set_sensitive(false);
+ pLbCopyArea->set_sensitive(false);
+ pEdCopyArea->GetWidget()->set_sensitive(false);
+ pRbCopyArea->GetWidget()->set_sensitive(false);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/imoptdlg.cxx b/sc/source/ui/dbgui/imoptdlg.cxx
new file mode 100644
index 000000000..b285c6ae9
--- /dev/null
+++ b/sc/source/ui/dbgui/imoptdlg.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 <imoptdlg.hxx>
+#include <asciiopt.hxx>
+#include <comphelper/string.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/thread.h>
+#include <o3tl/string_view.hxx>
+#include <global.hxx>
+
+const char pStrFix[] = "FIX";
+
+// The option string can no longer contain a semicolon (because of pick list),
+// therefore, starting with version 336 comma instead
+
+ScImportOptions::ScImportOptions( std::u16string_view rStr )
+{
+ // Use the same string format as ScAsciiOptions,
+ // because the import options string is passed here when a CSV file is loaded and saved again.
+ // The old format is still supported because it might be used in macros.
+
+ bFixedWidth = false;
+ nFieldSepCode = 0;
+ nTextSepCode = 0;
+ eCharSet = RTL_TEXTENCODING_DONTKNOW;
+ bSaveAsShown = true; // "true" if not in string (after CSV import)
+ bQuoteAllText = false;
+ bSaveNumberAsSuch = true;
+ bSaveFormulas = false;
+ bRemoveSpace = false;
+ nSheetToExport = 0;
+ bEvaluateFormulas = true; // true if not present at all, for compatibility
+ sal_Int32 nTokenCount = comphelper::string::getTokenCount(rStr, ',');
+ if ( nTokenCount < 3 )
+ return;
+
+ sal_Int32 nIdx{ 0 };
+ // first 3 tokens: common
+ OUString aToken( o3tl::getToken(rStr, 0, ',', nIdx ) );
+ if( aToken.equalsIgnoreAsciiCase( pStrFix ) )
+ bFixedWidth = true;
+ else
+ nFieldSepCode = ScAsciiOptions::GetWeightedFieldSep( aToken, true);
+ nTextSepCode = static_cast<sal_Unicode>(o3tl::toInt32(o3tl::getToken(rStr, 0, ',', nIdx)));
+ aStrFont = o3tl::getToken(rStr, 0, ',', nIdx);
+ eCharSet = ScGlobal::GetCharsetValue(aStrFont);
+
+ if ( nTokenCount == 4 )
+ {
+ // compatibility with old options string: "Save as shown" as 4th token, numeric
+ bSaveAsShown = o3tl::toInt32(o3tl::getToken(rStr, 0, ',', nIdx)) != 0;
+ bQuoteAllText = true; // use old default then
+ }
+ else
+ {
+ // look at the same positions as in ScAsciiOptions
+ if ( nTokenCount >= 7 )
+ bQuoteAllText = o3tl::getToken(rStr, 3, ',', nIdx) == u"true"; // 7th token
+ if ( nTokenCount >= 8 )
+ bSaveNumberAsSuch = o3tl::getToken(rStr, 0, ',', nIdx) == u"true";
+ if ( nTokenCount >= 9 )
+ bSaveAsShown = o3tl::getToken(rStr, 0, ',', nIdx) == u"true";
+ if ( nTokenCount >= 10 )
+ bSaveFormulas = o3tl::getToken(rStr, 0, ',', nIdx) == u"true";
+ if ( nTokenCount >= 11 )
+ bRemoveSpace = o3tl::getToken(rStr, 0, ',', nIdx) == u"true";
+ if ( nTokenCount >= 12 )
+ {
+ const OUString aTok(o3tl::getToken(rStr,0, ',', nIdx));
+ if (aTok == "-1")
+ nSheetToExport = -1; // all
+ else if (aTok.isEmpty() || CharClass::isAsciiNumeric(aTok))
+ nSheetToExport = aTok.toInt32();
+ else
+ nSheetToExport = -23; // invalid, force error
+ }
+ if ( nTokenCount >= 13 )
+ // If present, defaults to "false".
+ bEvaluateFormulas = o3tl::getToken(rStr, 0, ',', nIdx) == u"true";
+ }
+}
+
+OUString ScImportOptions::BuildString() const
+{
+ OUString aResult;
+
+ if( bFixedWidth )
+ aResult += pStrFix;
+ else
+ aResult += OUString::number(nFieldSepCode);
+ aResult += "," + OUString::number(nTextSepCode) + "," + aStrFont +
+ // use the same string format as ScAsciiOptions:
+ ",1,,0," + // first row, no column info, default language
+ OUString::boolean( bQuoteAllText ) + // same as "quoted field as text" in ScAsciiOptions
+ "," +
+ OUString::boolean( bSaveNumberAsSuch ) + // "save number as such": not in ScAsciiOptions
+ "," +
+ OUString::boolean( bSaveAsShown ) + // "save as shown": not in ScAsciiOptions
+ "," +
+ OUString::boolean( bSaveFormulas ) + // "save formulas": not in ScAsciiOptions
+ "," +
+ OUString::boolean( bRemoveSpace ) + // same as "Remove space" in ScAsciiOptions
+ "," +
+ OUString::number(nSheetToExport) + // Only available for command line --convert-to
+ "," +
+ OUString::boolean( bEvaluateFormulas ) ; // same as "Evaluate formulas" in ScAsciiOptions
+
+ return aResult;
+}
+
+void ScImportOptions::SetTextEncoding( rtl_TextEncoding nEnc )
+{
+ eCharSet = (nEnc == RTL_TEXTENCODING_DONTKNOW ?
+ osl_getThreadTextEncoding() : nEnc);
+ aStrFont = ScGlobal::GetCharsetString( nEnc );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/pfiltdlg.cxx b/sc/source/ui/dbgui/pfiltdlg.cxx
new file mode 100644
index 000000000..e87d676b5
--- /dev/null
+++ b/sc/source/ui/dbgui/pfiltdlg.cxx
@@ -0,0 +1,507 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <uiitems.hxx>
+#include <global.hxx>
+#include <globalnames.hxx>
+#include <dbdata.hxx>
+#include <scresid.hxx>
+#include <queryentry.hxx>
+#include <filterentries.hxx>
+
+#include <sc.hrc>
+#include <strings.hrc>
+
+#include <pfiltdlg.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <osl/diagnose.h>
+
+ScPivotFilterDlg::ScPivotFilterDlg(weld::Window* pParent, const SfxItemSet& rArgSet,
+ SCTAB nSourceTab )
+ : GenericDialogController(pParent, "modules/scalc/ui/pivotfilterdialog.ui", "PivotFilterDialog")
+ , aStrNone(ScResId(SCSTR_NONE))
+ , aStrEmpty(ScResId(SCSTR_FILTER_EMPTY))
+ , aStrNotEmpty(ScResId(SCSTR_FILTER_NOTEMPTY))
+ , aStrColumn(ScResId(SCSTR_COLUMN_LETTER))
+ , nWhichQuery(rArgSet.GetPool()->GetWhich(SID_QUERY))
+ , theQueryData(static_cast<const ScQueryItem&>(rArgSet.Get(nWhichQuery)).GetQueryData())
+ , pViewData(nullptr)
+ , pDoc(nullptr)
+ , nSrcTab(nSourceTab) // is not in QueryParam
+ , m_xLbField1(m_xBuilder->weld_combo_box("field1"))
+ , m_xLbCond1(m_xBuilder->weld_combo_box("cond1"))
+ , m_xEdVal1(m_xBuilder->weld_combo_box("val1"))
+ , m_xLbConnect1(m_xBuilder->weld_combo_box("connect1"))
+ , m_xLbField2(m_xBuilder->weld_combo_box("field2"))
+ , m_xLbCond2(m_xBuilder->weld_combo_box("cond2"))
+ , m_xEdVal2(m_xBuilder->weld_combo_box("val2"))
+ , m_xLbConnect2(m_xBuilder->weld_combo_box("connect2"))
+ , m_xLbField3(m_xBuilder->weld_combo_box("field3"))
+ , m_xLbCond3(m_xBuilder->weld_combo_box("cond3"))
+ , m_xEdVal3(m_xBuilder->weld_combo_box("val3"))
+ , m_xBtnCase(m_xBuilder->weld_check_button("case"))
+ , m_xBtnRegExp(m_xBuilder->weld_check_button("regexp"))
+ , m_xBtnUnique(m_xBuilder->weld_check_button("unique"))
+ , m_xFtDbArea(m_xBuilder->weld_label("dbarea"))
+{
+ Init( rArgSet );
+}
+
+ScPivotFilterDlg::~ScPivotFilterDlg()
+{
+}
+
+void ScPivotFilterDlg::Init( const SfxItemSet& rArgSet )
+{
+ const ScQueryItem& rQueryItem = static_cast<const ScQueryItem&>(
+ rArgSet.Get( nWhichQuery ));
+
+ m_xBtnCase->connect_toggled( LINK( this, ScPivotFilterDlg, CheckBoxHdl ) );
+
+ m_xLbField1->connect_changed ( LINK( this, ScPivotFilterDlg, LbSelectHdl ) );
+ m_xLbField2->connect_changed ( LINK( this, ScPivotFilterDlg, LbSelectHdl ) );
+ m_xLbField3->connect_changed ( LINK( this, ScPivotFilterDlg, LbSelectHdl ) );
+ m_xLbConnect1->connect_changed( LINK( this, ScPivotFilterDlg, LbSelectHdl ) );
+ m_xLbConnect2->connect_changed( LINK( this, ScPivotFilterDlg, LbSelectHdl ) );
+
+ m_xBtnCase->set_active( theQueryData.bCaseSens );
+ m_xBtnRegExp->set_active( theQueryData.eSearchType == utl::SearchParam::SearchType::Regexp );
+ m_xBtnUnique->set_active( !theQueryData.bDuplicate );
+
+ pViewData = rQueryItem.GetViewData();
+ pDoc = pViewData ? &pViewData->GetDocument() : nullptr;
+
+ // for easier access:
+ aFieldLbArr [0] = m_xLbField1.get();
+ aFieldLbArr [1] = m_xLbField2.get();
+ aFieldLbArr [2] = m_xLbField3.get();
+ aValueEdArr [0] = m_xEdVal1.get();
+ aValueEdArr [1] = m_xEdVal2.get();
+ aValueEdArr [2] = m_xEdVal3.get();
+ aCondLbArr [0] = m_xLbCond1.get();
+ aCondLbArr [1] = m_xLbCond2.get();
+ aCondLbArr [2] = m_xLbCond3.get();
+
+ if ( pViewData && pDoc )
+ {
+ ScRange theCurArea ( ScAddress( theQueryData.nCol1,
+ theQueryData.nRow1,
+ nSrcTab ),
+ ScAddress( theQueryData.nCol2,
+ theQueryData.nRow2,
+ nSrcTab ) );
+ ScDBCollection* pDBColl = pDoc->GetDBCollection();
+ OUString theDbName = STR_DB_LOCAL_NONAME;
+
+ // Check if the passed range is a database range
+
+ if ( pDBColl )
+ {
+ ScAddress& rStart = theCurArea.aStart;
+ ScAddress& rEnd = theCurArea.aEnd;
+ ScDBData* pDBData = pDBColl->GetDBAtArea( rStart.Tab(),
+ rStart.Col(), rStart.Row(),
+ rEnd.Col(), rEnd.Row() );
+ if ( pDBData )
+ theDbName = pDBData->GetName();
+ }
+
+ OUString sLabel = " (" + theDbName + ")";
+ m_xFtDbArea->set_label(sLabel);
+ }
+ else
+ {
+ m_xFtDbArea->set_label(OUString());
+ }
+
+ // Read the field lists and select the entries:
+
+ FillFieldLists();
+
+ for ( SCSIZE i=0; i<3; i++ )
+ {
+ if ( theQueryData.GetEntry(i).bDoQuery )
+ {
+ const ScQueryEntry& rEntry = theQueryData.GetEntry(i);
+ const ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
+ OUString aValStr = rItem.maString.getString();
+ if (rEntry.IsQueryByEmpty())
+ aValStr = aStrEmpty;
+ else if (rEntry.IsQueryByNonEmpty())
+ aValStr = aStrNotEmpty;
+ sal_uInt16 nCondPos = static_cast<sal_uInt16>(rEntry.eOp);
+ sal_uInt16 nFieldSelPos = GetFieldSelPos( static_cast<SCCOL>(rEntry.nField) );
+
+ aFieldLbArr[i]->set_active( nFieldSelPos );
+ aCondLbArr [i]->set_active( nCondPos );
+ UpdateValueList( static_cast<sal_uInt16>(i+1) );
+ aValueEdArr[i]->set_entry_text(aValStr);
+ if (aValStr == aStrEmpty || aValStr == aStrNotEmpty)
+ aCondLbArr[i]->set_sensitive(false);
+ }
+ else
+ {
+ aFieldLbArr[i]->set_active( 0 ); // "none" selected
+ aCondLbArr [i]->set_active( 0 ); // "=" selected
+ UpdateValueList( static_cast<sal_uInt16>(i) );
+ aValueEdArr[i]->set_entry_text(OUString());
+ }
+ aValueEdArr[i]->connect_changed( LINK( this, ScPivotFilterDlg, ValModifyHdl ) );
+ }
+
+ // disable/enable logic:
+
+ if (m_xLbField1->get_active() != 0 && m_xLbField2->get_active() != 0)
+ m_xLbConnect1->set_active( static_cast<sal_uInt16>(theQueryData.GetEntry(1).eConnect) );
+ else
+ m_xLbConnect1->set_active(-1);
+
+ if (m_xLbField2->get_active() != 0 && m_xLbField3->get_active() != 0)
+ m_xLbConnect2->set_active( static_cast<sal_uInt16>(theQueryData.GetEntry(2).eConnect) );
+ else
+ m_xLbConnect2->set_active(-1);
+
+ if (m_xLbField1->get_active() == 0)
+ {
+ m_xLbConnect1->set_sensitive(false);
+ m_xLbField2->set_sensitive(false);
+ m_xLbCond2->set_sensitive(false);
+ m_xEdVal2->set_sensitive(false);
+ }
+ else if (m_xLbConnect1->get_active() == -1)
+ {
+ m_xLbField2->set_sensitive(false);
+ m_xLbCond2->set_sensitive(false);
+ m_xEdVal2->set_sensitive(false);
+ }
+
+ if (m_xLbField2->get_active() == 0)
+ {
+ m_xLbConnect2->set_sensitive(false);
+ m_xLbField3->set_sensitive(false);
+ m_xLbCond3->set_sensitive(false);
+ m_xEdVal3->set_sensitive(false);
+ }
+ else if (m_xLbConnect2->get_active() == -1)
+ {
+ m_xLbField3->set_sensitive(false);
+ m_xLbCond3->set_sensitive(false);
+ m_xEdVal3->set_sensitive(false);
+ }
+}
+
+void ScPivotFilterDlg::FillFieldLists()
+{
+ m_xLbField1->clear();
+ m_xLbField2->clear();
+ m_xLbField3->clear();
+ m_xLbField1->append_text(aStrNone);
+ m_xLbField2->append_text(aStrNone);
+ m_xLbField3->append_text(aStrNone);
+
+ if ( !pDoc )
+ return;
+
+ OUString aFieldName;
+ SCTAB nTab = nSrcTab;
+ SCCOL nFirstCol = theQueryData.nCol1;
+ SCROW nFirstRow = theQueryData.nRow1;
+ SCCOL nMaxCol = theQueryData.nCol2;
+ SCCOL col = 0;
+
+ for ( col=nFirstCol; col<=nMaxCol; col++ )
+ {
+ aFieldName = pDoc->GetString(col, nFirstRow, nTab);
+ if ( aFieldName.isEmpty() )
+ {
+ aFieldName = ScGlobal::ReplaceOrAppend( aStrColumn, u"%1", ScColToAlpha( col ));
+ }
+ m_xLbField1->append_text(aFieldName);
+ m_xLbField2->append_text(aFieldName);
+ m_xLbField3->append_text(aFieldName);
+ }
+}
+
+void ScPivotFilterDlg::UpdateValueList( sal_uInt16 nList )
+{
+ if ( !(pDoc && nList>0 && nList<=3) )
+ return;
+
+ weld::ComboBox* pValList = aValueEdArr[nList-1];
+ sal_Int32 nFieldSelPos = aFieldLbArr[nList-1]->get_active();
+ OUString aCurValue = pValList->get_active_text();
+
+ pValList->clear();
+ pValList->append_text(aStrNotEmpty);
+ pValList->append_text(aStrEmpty);
+
+ if ( pDoc && nFieldSelPos )
+ {
+ SCCOL nColumn = theQueryData.nCol1 + static_cast<SCCOL>(nFieldSelPos) - 1;
+ if (!m_pEntryLists[nColumn])
+ {
+ weld::WaitObject aWaiter(m_xDialog.get());
+
+ SCTAB nTab = nSrcTab;
+ SCROW nFirstRow = theQueryData.nRow1;
+ SCROW nLastRow = theQueryData.nRow2;
+ nFirstRow++;
+ bool bCaseSens = m_xBtnCase->get_active();
+ m_pEntryLists[nColumn].reset( new ScFilterEntries);
+ pDoc->GetFilterEntriesArea(
+ nColumn, nFirstRow, nLastRow, nTab, bCaseSens, *m_pEntryLists[nColumn]);
+ }
+
+ const ScFilterEntries* pColl = m_pEntryLists[nColumn].get();
+ for (const auto& rEntry : *pColl)
+ {
+ pValList->append_text(rEntry.GetString());
+ }
+ }
+ pValList->set_entry_text(aCurValue);
+}
+
+void ScPivotFilterDlg::ClearValueList( sal_uInt16 nList )
+{
+ if ( nList>0 && nList<=3 )
+ {
+ weld::ComboBox* pValList = aValueEdArr[nList-1];
+ pValList->clear();
+ pValList->append_text(aStrNotEmpty);
+ pValList->append_text(aStrEmpty);
+ pValList->set_entry_text(OUString());
+ }
+}
+
+sal_uInt16 ScPivotFilterDlg::GetFieldSelPos( SCCOL nField )
+{
+ if ( nField >= theQueryData.nCol1 && nField <= theQueryData.nCol2 )
+ return static_cast<sal_uInt16>(nField - theQueryData.nCol1 + 1);
+ else
+ return 0;
+}
+
+const ScQueryItem& ScPivotFilterDlg::GetOutputItem()
+{
+ ScQueryParam theParam( theQueryData );
+ sal_Int32 nConnect1 = m_xLbConnect1->get_active();
+ sal_Int32 nConnect2 = m_xLbConnect2->get_active();
+
+ svl::SharedStringPool& rPool = pViewData->GetDocument().GetSharedStringPool();
+
+ for ( SCSIZE i=0; i<3; i++ )
+ {
+ const sal_Int32 nField = aFieldLbArr[i]->get_active();
+ ScQueryOp eOp = static_cast<ScQueryOp>(aCondLbArr[i]->get_active());
+
+ bool bDoThis = (aFieldLbArr[i]->get_active() != 0);
+ theParam.GetEntry(i).bDoQuery = bDoThis;
+
+ if ( bDoThis )
+ {
+ ScQueryEntry& rEntry = theParam.GetEntry(i);
+ ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
+
+ OUString aStrVal = aValueEdArr[i]->get_active_text();
+
+ /*
+ * The dialog returns the specific field values "empty"/"non empty"
+ * as constant in nVal in connection with the bQueryByString switch
+ * set to false
+ */
+ if ( aStrVal == aStrEmpty )
+ {
+ OSL_ASSERT(eOp == SC_EQUAL);
+ rEntry.SetQueryByEmpty();
+ }
+ else if ( aStrVal == aStrNotEmpty )
+ {
+ OSL_ASSERT(eOp == SC_EQUAL);
+ rEntry.SetQueryByNonEmpty();
+ }
+ else
+ {
+ rItem.maString = rPool.intern(aStrVal);
+ rItem.mfVal = 0.0;
+ rItem.meType = ScQueryEntry::ByString;
+ }
+
+ rEntry.nField = nField ? (theQueryData.nCol1 +
+ static_cast<SCCOL>(nField) - 1) : static_cast<SCCOL>(0);
+ rEntry.eOp = eOp;
+ }
+ }
+
+ theParam.GetEntry(1).eConnect = (nConnect1 != -1)
+ ? static_cast<ScQueryConnect>(nConnect1)
+ : SC_AND;
+ theParam.GetEntry(2).eConnect = (nConnect2 != -1)
+ ? static_cast<ScQueryConnect>(nConnect2)
+ : SC_AND;
+
+ theParam.bInplace = false;
+ theParam.nDestTab = 0; // Where do those values come from?
+ theParam.nDestCol = 0;
+ theParam.nDestRow = 0;
+
+ theParam.bDuplicate = !m_xBtnUnique->get_active();
+ theParam.bCaseSens = m_xBtnCase->get_active();
+ theParam.eSearchType = m_xBtnRegExp->get_active() ? utl::SearchParam::SearchType::Regexp : utl::SearchParam::SearchType::Normal;
+
+ pOutItem.reset( new ScQueryItem( nWhichQuery, &theParam ) );
+
+ return *pOutItem;
+}
+
+// Handler:
+
+IMPL_LINK( ScPivotFilterDlg, LbSelectHdl, weld::ComboBox&, rLb, void )
+{
+ /*
+ * Handling the enable/disable logic based on which ListBox was touched:
+ */
+ if (&rLb == m_xLbConnect1.get())
+ {
+ if ( !m_xLbField2->get_sensitive() )
+ {
+ m_xLbField2->set_sensitive(true);
+ m_xLbCond2->set_sensitive(true);
+ m_xEdVal2->set_sensitive(true);
+ }
+ }
+ else if (&rLb == m_xLbConnect2.get())
+ {
+ if ( !m_xLbField3->get_sensitive() )
+ {
+ m_xLbField3->set_sensitive(true);
+ m_xLbCond3->set_sensitive(true);
+ m_xEdVal3->set_sensitive(true);
+ }
+ }
+ else if (&rLb == m_xLbField1.get())
+ {
+ if ( m_xLbField1->get_active() == 0 )
+ {
+ m_xLbConnect1->set_active(-1);
+ m_xLbConnect2->set_active(-1);
+ m_xLbField2->set_active( 0 );
+ m_xLbField3->set_active( 0 );
+ m_xLbCond2->set_active( 0 );
+ m_xLbCond3->set_active( 0 );
+ ClearValueList( 1 );
+ ClearValueList( 2 );
+ ClearValueList( 3 );
+
+ m_xLbConnect1->set_sensitive(false);
+ m_xLbConnect2->set_sensitive(false);
+ m_xLbField2->set_sensitive(false);
+ m_xLbField3->set_sensitive(false);
+ m_xLbCond2->set_sensitive(false);
+ m_xLbCond3->set_sensitive(false);
+ m_xEdVal2->set_sensitive(false);
+ m_xEdVal3->set_sensitive(false);
+ }
+ else
+ {
+ UpdateValueList( 1 );
+ if ( !m_xLbConnect1->get_sensitive() )
+ {
+ m_xLbConnect1->set_sensitive(true);
+ }
+ }
+ }
+ else if (&rLb == m_xLbField2.get())
+ {
+ if ( m_xLbField2->get_active() == 0 )
+ {
+ m_xLbConnect2->set_active(-1);
+ m_xLbField3->set_active( 0 );
+ m_xLbCond3->set_active( 0 );
+ ClearValueList( 2 );
+ ClearValueList( 3 );
+
+ m_xLbConnect2->set_sensitive(false);
+ m_xLbField3->set_sensitive(false);
+ m_xLbCond3->set_sensitive(false);
+ m_xEdVal3->set_sensitive(false);
+ }
+ else
+ {
+ UpdateValueList( 2 );
+ if (!m_xLbConnect2->get_sensitive())
+ {
+ m_xLbConnect2->set_sensitive(true);
+ }
+ }
+ }
+ else if (&rLb == m_xLbField3.get())
+ {
+ if (m_xLbField3->get_active() == 0)
+ ClearValueList(3);
+ else
+ UpdateValueList(3);
+ }
+}
+
+IMPL_LINK(ScPivotFilterDlg, CheckBoxHdl, weld::Toggleable&, rBox, void)
+{
+ // update the value lists when dealing with uppercase/lowercase
+
+ if (&rBox != m_xBtnCase.get()) // value lists
+ return;
+
+ for (auto& a : m_pEntryLists)
+ a.reset();
+
+ OUString aCurVal1 = m_xEdVal1->get_active_text();
+ OUString aCurVal2 = m_xEdVal2->get_active_text();
+ OUString aCurVal3 = m_xEdVal3->get_active_text();
+ UpdateValueList( 1 );
+ UpdateValueList( 2 );
+ UpdateValueList( 3 );
+ m_xEdVal1->set_entry_text(aCurVal1);
+ m_xEdVal2->set_entry_text(aCurVal2);
+ m_xEdVal3->set_entry_text(aCurVal3);
+}
+
+IMPL_LINK( ScPivotFilterDlg, ValModifyHdl, weld::ComboBox&, rEd, void )
+{
+ OUString aStrVal = rEd.get_active_text();
+ weld::ComboBox* pLb = m_xLbCond1.get();
+
+ if ( &rEd == m_xEdVal2.get() ) pLb = m_xLbCond2.get();
+ else if ( &rEd == m_xEdVal3.get() ) pLb = m_xLbCond3.get();
+
+ // if cond of the special values "empty"/"non-empty" was chosen only the
+ // =-operand makes sense:
+
+ if ( aStrEmpty == aStrVal || aStrNotEmpty == aStrVal )
+ {
+ pLb->set_active_text(OUString('='));
+ pLb->set_sensitive(false);
+ }
+ else
+ pLb->set_sensitive(true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/pvfundlg.cxx b/sc/source/ui/dbgui/pvfundlg.cxx
new file mode 100644
index 000000000..90a13e920
--- /dev/null
+++ b/sc/source/ui/dbgui/pvfundlg.cxx
@@ -0,0 +1,973 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <pvfundlg.hxx>
+
+#include <com/sun/star/sheet/DataPilotFieldReferenceType.hpp>
+#include <com/sun/star/sheet/DataPilotFieldReferenceItemType.hpp>
+#include <com/sun/star/sheet/DataPilotFieldLayoutMode.hpp>
+#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
+#include <com/sun/star/sheet/DataPilotFieldShowItemsMode.hpp>
+
+#include <osl/diagnose.h>
+
+#include <scresid.hxx>
+#include <dpobject.hxx>
+#include <dpsave.hxx>
+#include <pvfundlg.hrc>
+#include <globstr.hrc>
+#include <dputil.hxx>
+
+#include <vector>
+
+using namespace ::com::sun::star::sheet;
+
+using ::com::sun::star::uno::Sequence;
+using ::std::vector;
+
+namespace {
+
+/** Appends all strings from the Sequence to the list box.
+
+ Empty strings are replaced by a localized "(empty)" entry and inserted at
+ the specified position.
+
+ @return true = The passed string list contains an empty string entry.
+ */
+
+bool lclFillListBox(weld::ComboBox& rLBox, const Sequence< OUString >& rStrings)
+{
+ bool bEmpty = false;
+ for (const OUString& str : rStrings)
+ {
+ if (!str.isEmpty())
+ rLBox.append_text(str);
+ else
+ {
+ rLBox.append_text(ScResId(STR_EMPTYDATA));
+ bEmpty = true;
+ }
+ }
+ return bEmpty;
+}
+
+bool lclFillListBox(weld::ComboBox& rLBox, const vector<ScDPLabelData::Member>& rMembers, int nEmptyPos)
+{
+ bool bEmpty = false;
+ vector<ScDPLabelData::Member>::const_iterator itr = rMembers.begin(), itrEnd = rMembers.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ OUString aName = itr->getDisplayName();
+ if (!aName.isEmpty())
+ rLBox.append_text(aName);
+ else
+ {
+ rLBox.insert_text(nEmptyPos, ScResId(STR_EMPTYDATA));
+ bEmpty = true;
+ }
+ }
+ return bEmpty;
+}
+
+bool lclFillListBox(weld::TreeView& rLBox, const vector<ScDPLabelData::Member>& rMembers)
+{
+ bool bEmpty = false;
+ for (const auto& rMember : rMembers)
+ {
+ rLBox.append();
+ int pos = rLBox.n_children() - 1;
+ rLBox.set_toggle(pos, TRISTATE_FALSE);
+ OUString aName = rMember.getDisplayName();
+ if (!aName.isEmpty())
+ rLBox.set_text(pos, aName, 0);
+ else
+ {
+ rLBox.set_text(pos, ScResId(STR_EMPTYDATA), 0);
+ bEmpty = true;
+ }
+ }
+ return bEmpty;
+}
+
+/** This table represents the order of the strings in the resource string array. */
+const PivotFunc spnFunctions[] =
+{
+ PivotFunc::Sum,
+ PivotFunc::Count,
+ PivotFunc::Average,
+ PivotFunc::Median,
+ PivotFunc::Max,
+ PivotFunc::Min,
+ PivotFunc::Product,
+ PivotFunc::CountNum,
+ PivotFunc::StdDev,
+ PivotFunc::StdDevP,
+ PivotFunc::StdVar,
+ PivotFunc::StdVarP
+};
+
+const sal_uInt16 SC_BASEITEM_PREV_POS = 0;
+const sal_uInt16 SC_BASEITEM_NEXT_POS = 1;
+const sal_uInt16 SC_BASEITEM_USER_POS = 2;
+
+const sal_uInt16 SC_SORTNAME_POS = 0;
+const sal_uInt16 SC_SORTDATA_POS = 1;
+
+const tools::Long SC_SHOW_DEFAULT = 10;
+
+} // namespace
+
+ScDPFunctionListBox::ScDPFunctionListBox(std::unique_ptr<weld::TreeView> xControl)
+ : m_xControl(std::move(xControl))
+{
+ FillFunctionNames();
+}
+
+void ScDPFunctionListBox::SetSelection( PivotFunc nFuncMask )
+{
+ if( (nFuncMask == PivotFunc::NONE) || (nFuncMask == PivotFunc::Auto) )
+ m_xControl->unselect_all();
+ else
+ {
+ for( sal_Int32 nEntry = 0, nCount = m_xControl->n_children(); nEntry < nCount; ++nEntry )
+ {
+ if (bool(nFuncMask & spnFunctions[ nEntry ]))
+ m_xControl->select(nEntry);
+ else
+ m_xControl->unselect(nEntry);
+ }
+ }
+}
+
+PivotFunc ScDPFunctionListBox::GetSelection() const
+{
+ PivotFunc nFuncMask = PivotFunc::NONE;
+ std::vector<int> aRows = m_xControl->get_selected_rows();
+ for (int nSel : aRows)
+ nFuncMask |= spnFunctions[nSel];
+ return nFuncMask;
+}
+
+void ScDPFunctionListBox::FillFunctionNames()
+{
+ OSL_ENSURE( !m_xControl->n_children(), "ScDPMultiFuncListBox::FillFunctionNames - do not add texts to resource" );
+ m_xControl->clear();
+ m_xControl->freeze();
+ for (size_t nIndex = 0; nIndex < SAL_N_ELEMENTS(SCSTR_DPFUNCLISTBOX); ++nIndex)
+ m_xControl->append_text(ScResId(SCSTR_DPFUNCLISTBOX[nIndex]));
+ m_xControl->thaw();
+ assert(m_xControl->n_children() == SAL_N_ELEMENTS(spnFunctions));
+}
+
+namespace
+{
+ int FromDataPilotFieldReferenceType(int eMode)
+ {
+ switch (eMode)
+ {
+ case DataPilotFieldReferenceType::NONE:
+ return 0;
+ case DataPilotFieldReferenceType::ITEM_DIFFERENCE:
+ return 1;
+ case DataPilotFieldReferenceType::ITEM_PERCENTAGE:
+ return 2;
+ case DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
+ return 3;
+ case DataPilotFieldReferenceType::RUNNING_TOTAL:
+ return 4;
+ case DataPilotFieldReferenceType::ROW_PERCENTAGE:
+ return 5;
+ case DataPilotFieldReferenceType::COLUMN_PERCENTAGE:
+ return 6;
+ case DataPilotFieldReferenceType::TOTAL_PERCENTAGE:
+ return 7;
+ case DataPilotFieldReferenceType::INDEX:
+ return 8;
+ }
+ return -1;
+ }
+
+ int ToDataPilotFieldReferenceType(int nPos)
+ {
+ switch (nPos)
+ {
+ case 0:
+ return DataPilotFieldReferenceType::NONE;
+ case 1:
+ return DataPilotFieldReferenceType::ITEM_DIFFERENCE;
+ case 2:
+ return DataPilotFieldReferenceType::ITEM_PERCENTAGE;
+ case 3:
+ return DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE;
+ case 4:
+ return DataPilotFieldReferenceType::RUNNING_TOTAL;
+ case 5:
+ return DataPilotFieldReferenceType::ROW_PERCENTAGE;
+ case 6:
+ return DataPilotFieldReferenceType::COLUMN_PERCENTAGE;
+ case 7:
+ return DataPilotFieldReferenceType::TOTAL_PERCENTAGE;
+ case 8:
+ return DataPilotFieldReferenceType::INDEX;
+ }
+ return DataPilotFieldReferenceType::NONE;
+
+ }
+}
+
+ScDPFunctionDlg::ScDPFunctionDlg(
+ weld::Widget* pParent, const ScDPLabelDataVector& rLabelVec,
+ const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData)
+ : GenericDialogController(pParent, "modules/scalc/ui/datafielddialog.ui", "DataFieldDialog")
+ , mxLbFunc(new ScDPFunctionListBox(m_xBuilder->weld_tree_view("functions")))
+ , mxFtName(m_xBuilder->weld_label("name"))
+ , mxLbType(m_xBuilder->weld_combo_box("type"))
+ , mxFtBaseField(m_xBuilder->weld_label("basefieldft"))
+ , mxLbBaseField(m_xBuilder->weld_combo_box("basefield"))
+ , mxFtBaseItem(m_xBuilder->weld_label("baseitemft"))
+ , mxLbBaseItem(m_xBuilder->weld_combo_box("baseitem"))
+ , mxBtnOk(m_xBuilder->weld_button("ok"))
+ , mxBtnCancel(m_xBuilder->weld_button("cancel"))
+ , mxExpander(m_xBuilder->weld_expander("expander"))
+ , mrLabelVec(rLabelVec)
+ , mbEmptyItem(false)
+{
+ mxLbFunc->set_size_request(-1, mxLbFunc->get_height_rows(8));
+
+ Init(rLabelData, rFuncData);
+}
+
+ScDPFunctionDlg::~ScDPFunctionDlg()
+{
+}
+
+PivotFunc ScDPFunctionDlg::GetFuncMask() const
+{
+ return mxLbFunc->GetSelection();
+}
+
+DataPilotFieldReference ScDPFunctionDlg::GetFieldRef() const
+{
+ DataPilotFieldReference aRef;
+
+ aRef.ReferenceType = ToDataPilotFieldReferenceType(mxLbType->get_active());
+ aRef.ReferenceField = GetBaseFieldName(mxLbBaseField->get_active_text());
+
+ sal_Int32 nBaseItemPos = mxLbBaseItem->get_active();
+ switch( nBaseItemPos )
+ {
+ case SC_BASEITEM_PREV_POS:
+ aRef.ReferenceItemType = DataPilotFieldReferenceItemType::PREVIOUS;
+ break;
+ case SC_BASEITEM_NEXT_POS:
+ aRef.ReferenceItemType = DataPilotFieldReferenceItemType::NEXT;
+ break;
+ default:
+ {
+ aRef.ReferenceItemType = DataPilotFieldReferenceItemType::NAMED;
+ if( !mbEmptyItem || (nBaseItemPos > SC_BASEITEM_USER_POS) )
+ aRef.ReferenceItemName = GetBaseItemName(mxLbBaseItem->get_active_text());
+ }
+ }
+
+ return aRef;
+}
+
+void ScDPFunctionDlg::Init( const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData )
+{
+ mxBtnOk->connect_clicked( LINK( this, ScDPFunctionDlg, ButtonClicked ) );
+ mxBtnCancel->connect_clicked( LINK( this, ScDPFunctionDlg, ButtonClicked ) );
+
+ // list box
+ PivotFunc nFuncMask = (rFuncData.mnFuncMask == PivotFunc::NONE) ? PivotFunc::Sum : rFuncData.mnFuncMask;
+ mxLbFunc->SetSelection( nFuncMask );
+
+ // field name
+ mxFtName->set_label(rLabelData.getDisplayName());
+
+ // handlers
+ mxLbFunc->connect_row_activated( LINK( this, ScDPFunctionDlg, DblClickHdl ) );
+ mxLbType->connect_changed( LINK( this, ScDPFunctionDlg, SelectHdl ) );
+ mxLbBaseField->connect_changed( LINK( this, ScDPFunctionDlg, SelectHdl ) );
+
+ // base field list box
+ OUString aSelectedEntry;
+ for( const auto& rxLabel : mrLabelVec )
+ {
+ mxLbBaseField->append_text(rxLabel->getDisplayName());
+ maBaseFieldNameMap.emplace(rxLabel->getDisplayName(), rxLabel->maName);
+ if (rxLabel->maName == rFuncData.maFieldRef.ReferenceField)
+ aSelectedEntry = rxLabel->getDisplayName();
+ }
+
+ // select field reference type
+ mxLbType->set_active(FromDataPilotFieldReferenceType(rFuncData.maFieldRef.ReferenceType));
+ SelectHdl( *mxLbType ); // enables base field/item list boxes
+
+ // select base field
+ mxLbBaseField->set_active_text(aSelectedEntry);
+ if (mxLbBaseField->get_active() == -1)
+ mxLbBaseField->set_active(0);
+ SelectHdl( *mxLbBaseField ); // fills base item list, selects base item
+
+ // select base item
+ switch( rFuncData.maFieldRef.ReferenceItemType )
+ {
+ case DataPilotFieldReferenceItemType::PREVIOUS:
+ mxLbBaseItem->set_active( SC_BASEITEM_PREV_POS );
+ break;
+ case DataPilotFieldReferenceItemType::NEXT:
+ mxLbBaseItem->set_active( SC_BASEITEM_NEXT_POS );
+ break;
+ default:
+ {
+ if( mbEmptyItem && rFuncData.maFieldRef.ReferenceItemName.isEmpty() )
+ {
+ // select special "(empty)" entry added before other items
+ mxLbBaseItem->set_active( SC_BASEITEM_USER_POS );
+ }
+ else
+ {
+ sal_Int32 nStartPos = mbEmptyItem ? (SC_BASEITEM_USER_POS + 1) : SC_BASEITEM_USER_POS;
+ sal_Int32 nPos = FindBaseItemPos( rFuncData.maFieldRef.ReferenceItemName, nStartPos );
+ if( nPos == -1)
+ nPos = (mxLbBaseItem->get_count() > SC_BASEITEM_USER_POS) ? SC_BASEITEM_USER_POS : SC_BASEITEM_PREV_POS;
+ mxLbBaseItem->set_active( nPos );
+ }
+ }
+ }
+}
+
+const OUString& ScDPFunctionDlg::GetBaseFieldName(const OUString& rLayoutName) const
+{
+ NameMapType::const_iterator itr = maBaseFieldNameMap.find(rLayoutName);
+ return itr == maBaseFieldNameMap.end() ? rLayoutName : itr->second;
+}
+
+const OUString& ScDPFunctionDlg::GetBaseItemName(const OUString& rLayoutName) const
+{
+ NameMapType::const_iterator itr = maBaseItemNameMap.find(rLayoutName);
+ return itr == maBaseItemNameMap.end() ? rLayoutName : itr->second;
+}
+
+sal_Int32 ScDPFunctionDlg::FindBaseItemPos( std::u16string_view rEntry, sal_Int32 nStartPos ) const
+{
+ sal_Int32 nPos = nStartPos;
+ bool bFound = false;
+ while (nPos < mxLbBaseItem->get_count())
+ {
+ // translate the displayed field name back to its original field name.
+ const OUString& rInName = mxLbBaseItem->get_text(nPos);
+ const OUString& rName = GetBaseItemName(rInName);
+ if (rName == rEntry)
+ {
+ bFound = true;
+ break;
+ }
+ ++nPos;
+ }
+ return bFound ? nPos : -1;
+}
+
+IMPL_LINK( ScDPFunctionDlg, SelectHdl, weld::ComboBox&, rLBox, void )
+{
+ if (&rLBox == mxLbType.get())
+ {
+ bool bEnableField, bEnableItem;
+ switch (ToDataPilotFieldReferenceType(mxLbType->get_active()))
+ {
+ case DataPilotFieldReferenceType::ITEM_DIFFERENCE:
+ case DataPilotFieldReferenceType::ITEM_PERCENTAGE:
+ case DataPilotFieldReferenceType::ITEM_PERCENTAGE_DIFFERENCE:
+ bEnableField = bEnableItem = true;
+ break;
+
+ case DataPilotFieldReferenceType::RUNNING_TOTAL:
+ bEnableField = true;
+ bEnableItem = false;
+ break;
+
+ default:
+ bEnableField = bEnableItem = false;
+ }
+
+ bEnableField &= (mxLbBaseField->get_count() > 0);
+ mxFtBaseField->set_sensitive( bEnableField );
+ mxLbBaseField->set_sensitive( bEnableField );
+
+ bEnableItem &= bEnableField;
+ mxFtBaseItem->set_sensitive( bEnableItem );
+ mxLbBaseItem->set_sensitive( bEnableItem );
+ }
+ else if (&rLBox == mxLbBaseField.get())
+ {
+ // keep "previous" and "next" entries
+ while (mxLbBaseItem->get_count() > SC_BASEITEM_USER_POS)
+ mxLbBaseItem->remove(SC_BASEITEM_USER_POS);
+
+ // update item list for current base field
+ mbEmptyItem = false;
+ size_t nBasePos = mxLbBaseField->get_active();
+ if (nBasePos < mrLabelVec.size())
+ {
+ const vector<ScDPLabelData::Member>& rMembers = mrLabelVec[nBasePos]->maMembers;
+ mbEmptyItem = lclFillListBox(*mxLbBaseItem, rMembers, SC_BASEITEM_USER_POS);
+ // build cache for base names.
+ NameMapType aMap;
+ for (const auto& rMember : rMembers)
+ aMap.emplace(rMember.getDisplayName(), rMember.maName);
+ maBaseItemNameMap.swap(aMap);
+ }
+
+ // select base item
+ sal_uInt16 nItemPos = (mxLbBaseItem->get_count() > SC_BASEITEM_USER_POS) ? SC_BASEITEM_USER_POS : SC_BASEITEM_PREV_POS;
+ mxLbBaseItem->set_active( nItemPos );
+ }
+}
+
+IMPL_LINK(ScDPFunctionDlg, ButtonClicked, weld::Button&, rButton, void)
+{
+ if (&rButton == mxBtnOk.get())
+ response(RET_OK);
+ else
+ response(RET_CANCEL);
+}
+
+IMPL_LINK_NOARG(ScDPFunctionDlg, DblClickHdl, weld::TreeView&, bool)
+{
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+ScDPSubtotalDlg::ScDPSubtotalDlg(weld::Widget* pParent, ScDPObject& rDPObj,
+ const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData,
+ const ScDPNameVec& rDataFields, bool bEnableLayout)
+ : GenericDialogController(pParent, "modules/scalc/ui/pivotfielddialog.ui", "PivotFieldDialog")
+ , mrDPObj(rDPObj)
+ , mrDataFields(rDataFields)
+ , maLabelData(rLabelData)
+ , mbEnableLayout(bEnableLayout)
+ , mxRbNone(m_xBuilder->weld_radio_button("none"))
+ , mxRbAuto(m_xBuilder->weld_radio_button("auto"))
+ , mxRbUser(m_xBuilder->weld_radio_button("user"))
+ , mxLbFunc(new ScDPFunctionListBox(m_xBuilder->weld_tree_view("functions")))
+ , mxFtName(m_xBuilder->weld_label("name"))
+ , mxCbShowAll(m_xBuilder->weld_check_button("showall"))
+ , mxBtnOk(m_xBuilder->weld_button("ok"))
+ , mxBtnCancel(m_xBuilder->weld_button("cancel"))
+ , mxBtnOptions(m_xBuilder->weld_button("options"))
+{
+ mxLbFunc->set_selection_mode(SelectionMode::Multiple);
+ mxLbFunc->set_size_request(-1, mxLbFunc->get_height_rows(8));
+ Init(rLabelData, rFuncData);
+}
+
+ScDPSubtotalDlg::~ScDPSubtotalDlg()
+{
+ CloseSubdialog();
+}
+
+void ScDPSubtotalDlg::CloseSubdialog()
+{
+ if (mxOptionsDlg && mxOptionsDlg->getDialog())
+ {
+ mxOptionsDlg->getDialog()->response(RET_CANCEL);
+ mxOptionsDlg = nullptr;
+ }
+}
+
+PivotFunc ScDPSubtotalDlg::GetFuncMask() const
+{
+ PivotFunc nFuncMask = PivotFunc::NONE;
+
+ if (mxRbAuto->get_active())
+ nFuncMask = PivotFunc::Auto;
+ else if (mxRbUser->get_active())
+ nFuncMask = mxLbFunc->GetSelection();
+
+ return nFuncMask;
+}
+
+void ScDPSubtotalDlg::FillLabelData( ScDPLabelData& rLabelData ) const
+{
+ rLabelData.mnFuncMask = GetFuncMask();
+ rLabelData.mnUsedHier = maLabelData.mnUsedHier;
+ rLabelData.mbShowAll = mxCbShowAll->get_active();
+ rLabelData.maMembers = maLabelData.maMembers;
+ rLabelData.maSortInfo = maLabelData.maSortInfo;
+ rLabelData.maLayoutInfo = maLabelData.maLayoutInfo;
+ rLabelData.maShowInfo = maLabelData.maShowInfo;
+ rLabelData.mbRepeatItemLabels = maLabelData.mbRepeatItemLabels;
+}
+
+void ScDPSubtotalDlg::Init( const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData )
+{
+ mxBtnOk->connect_clicked( LINK( this, ScDPSubtotalDlg, ButtonClicked ) );
+ mxBtnCancel->connect_clicked( LINK( this, ScDPSubtotalDlg, ButtonClicked ) );
+
+ // field name
+ mxFtName->set_label(rLabelData.getDisplayName());
+
+ // radio buttons
+ mxRbNone->connect_toggled( LINK( this, ScDPSubtotalDlg, RadioClickHdl ) );
+ mxRbAuto->connect_toggled( LINK( this, ScDPSubtotalDlg, RadioClickHdl ) );
+ mxRbUser->connect_toggled( LINK( this, ScDPSubtotalDlg, RadioClickHdl ) );
+
+ weld::RadioButton* pRBtn = nullptr;
+ switch( rFuncData.mnFuncMask )
+ {
+ case PivotFunc::NONE: pRBtn = mxRbNone.get(); break;
+ case PivotFunc::Auto: pRBtn = mxRbAuto.get(); break;
+ default: pRBtn = mxRbUser.get();
+ }
+ pRBtn->set_active(true);
+ RadioClickHdl(*pRBtn);
+
+ // list box
+ mxLbFunc->SetSelection( rFuncData.mnFuncMask );
+ mxLbFunc->connect_row_activated( LINK( this, ScDPSubtotalDlg, DblClickHdl ) );
+
+ // show all
+ mxCbShowAll->set_active( rLabelData.mbShowAll );
+
+ // options
+ mxBtnOptions->connect_clicked( LINK( this, ScDPSubtotalDlg, ClickHdl ) );
+}
+
+IMPL_LINK(ScDPSubtotalDlg, ButtonClicked, weld::Button&, rButton, void)
+{
+ CloseSubdialog();
+
+ if (&rButton == mxBtnOk.get())
+ response(RET_OK);
+ else
+ response(RET_CANCEL);
+}
+
+IMPL_LINK(ScDPSubtotalDlg, RadioClickHdl, weld::Toggleable&, rBtn, void)
+{
+ if (!rBtn.get_active())
+ return;
+ mxLbFunc->set_sensitive(mxRbUser->get_active());
+}
+
+IMPL_LINK_NOARG(ScDPSubtotalDlg, DblClickHdl, weld::TreeView&, bool)
+{
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+IMPL_LINK(ScDPSubtotalDlg, ClickHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == mxBtnOptions.get())
+ {
+ mxOptionsDlg = std::make_shared<ScDPSubtotalOptDlg>(m_xDialog.get(), mrDPObj, maLabelData, mrDataFields, mbEnableLayout);
+
+ weld::DialogController::runAsync(mxOptionsDlg, [this](int nResult) {
+ if (nResult == RET_OK)
+ mxOptionsDlg->FillLabelData(maLabelData);
+ mxOptionsDlg = nullptr;
+ });
+ }
+}
+
+namespace
+{
+ int FromDataPilotFieldLayoutMode(int eMode)
+ {
+ switch (eMode)
+ {
+ case DataPilotFieldLayoutMode::TABULAR_LAYOUT:
+ return 0;
+ case DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_TOP:
+ return 1;
+ case DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_BOTTOM:
+ return 2;
+ }
+ return -1;
+ }
+
+ int ToDataPilotFieldLayoutMode(int nPos)
+ {
+ switch (nPos)
+ {
+ case 0:
+ return DataPilotFieldLayoutMode::TABULAR_LAYOUT;
+ case 1:
+ return DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_TOP;
+ case 2:
+ return DataPilotFieldLayoutMode::OUTLINE_SUBTOTALS_BOTTOM;
+ }
+ return DataPilotFieldLayoutMode::TABULAR_LAYOUT;
+ }
+
+ int FromDataPilotFieldShowItemsMode(int eMode)
+ {
+ switch (eMode)
+ {
+ case DataPilotFieldShowItemsMode::FROM_TOP:
+ return 0;
+ case DataPilotFieldShowItemsMode::FROM_BOTTOM:
+ return 1;
+ }
+ return -1;
+ }
+
+ int ToDataPilotFieldShowItemsMode(int nPos)
+ {
+ switch (nPos)
+ {
+ case 0:
+ return DataPilotFieldShowItemsMode::FROM_TOP;
+ case 1:
+ return DataPilotFieldShowItemsMode::FROM_BOTTOM;
+ }
+ return DataPilotFieldShowItemsMode::FROM_TOP;
+ }
+}
+
+ScDPSubtotalOptDlg::ScDPSubtotalOptDlg(weld::Window* pParent, ScDPObject& rDPObj,
+ const ScDPLabelData& rLabelData, const ScDPNameVec& rDataFields,
+ bool bEnableLayout )
+ : GenericDialogController(pParent, "modules/scalc/ui/datafieldoptionsdialog.ui",
+ "DataFieldOptionsDialog")
+ , m_xLbSortBy(m_xBuilder->weld_combo_box("sortby"))
+ , m_xRbSortAsc(m_xBuilder->weld_radio_button("ascending"))
+ , m_xRbSortDesc(m_xBuilder->weld_radio_button("descending"))
+ , m_xRbSortMan(m_xBuilder->weld_radio_button("manual"))
+ , m_xLayoutFrame(m_xBuilder->weld_widget("layoutframe"))
+ , m_xLbLayout(m_xBuilder->weld_combo_box("layout"))
+ , m_xCbLayoutEmpty(m_xBuilder->weld_check_button("emptyline"))
+ , m_xCbRepeatItemLabels(m_xBuilder->weld_check_button("repeatitemlabels"))
+ , m_xCbShow(m_xBuilder->weld_check_button("show"))
+ , m_xNfShow(m_xBuilder->weld_spin_button("items"))
+ , m_xFtShow(m_xBuilder->weld_label("showft"))
+ , m_xFtShowFrom(m_xBuilder->weld_label("showfromft"))
+ , m_xLbShowFrom(m_xBuilder->weld_combo_box("from"))
+ , m_xFtShowUsing(m_xBuilder->weld_label("usingft"))
+ , m_xLbShowUsing(m_xBuilder->weld_combo_box("using"))
+ , m_xHideFrame(m_xBuilder->weld_widget("hideframe"))
+ , m_xLbHide(m_xBuilder->weld_tree_view("hideitems"))
+ , m_xFtHierarchy(m_xBuilder->weld_label("hierarchyft"))
+ , m_xLbHierarchy(m_xBuilder->weld_combo_box("hierarchy"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , mrDPObj(rDPObj)
+ , maLabelData(rLabelData)
+{
+ m_xLbHide->enable_toggle_buttons(weld::ColumnToggleType::Check);
+
+ m_xLbSortBy->set_size_request(m_xLbSortBy->get_approximate_digit_width() * 18, -1);
+ m_xLbHide->set_size_request(-1, m_xLbHide->get_height_rows(5));
+ Init(rDataFields, bEnableLayout);
+}
+
+ScDPSubtotalOptDlg::~ScDPSubtotalOptDlg()
+{
+}
+
+void ScDPSubtotalOptDlg::FillLabelData( ScDPLabelData& rLabelData ) const
+{
+ // *** SORTING ***
+
+ if (m_xRbSortMan->get_active())
+ rLabelData.maSortInfo.Mode = DataPilotFieldSortMode::MANUAL;
+ else if (m_xLbSortBy->get_active() == SC_SORTNAME_POS)
+ rLabelData.maSortInfo.Mode = DataPilotFieldSortMode::NAME;
+ else
+ rLabelData.maSortInfo.Mode = DataPilotFieldSortMode::DATA;
+
+ ScDPName aFieldName = GetFieldName(m_xLbSortBy->get_active_text());
+ if (!aFieldName.maName.isEmpty())
+ {
+ rLabelData.maSortInfo.Field =
+ ScDPUtil::createDuplicateDimensionName(aFieldName.maName, aFieldName.mnDupCount);
+ rLabelData.maSortInfo.IsAscending = m_xRbSortAsc->get_active();
+ }
+
+ // *** LAYOUT MODE ***
+
+ rLabelData.maLayoutInfo.LayoutMode = ToDataPilotFieldLayoutMode(m_xLbLayout->get_active());
+ rLabelData.maLayoutInfo.AddEmptyLines = m_xCbLayoutEmpty->get_active();
+ rLabelData.mbRepeatItemLabels = m_xCbRepeatItemLabels->get_active();
+
+ // *** AUTO SHOW ***
+
+ aFieldName = GetFieldName(m_xLbShowUsing->get_active_text());
+ if (!aFieldName.maName.isEmpty())
+ {
+ rLabelData.maShowInfo.IsEnabled = m_xCbShow->get_active();
+ rLabelData.maShowInfo.ShowItemsMode = ToDataPilotFieldShowItemsMode(m_xLbShowFrom->get_active());
+ rLabelData.maShowInfo.ItemCount = sal::static_int_cast<sal_Int32>( m_xNfShow->get_value() );
+ rLabelData.maShowInfo.DataField =
+ ScDPUtil::createDuplicateDimensionName(aFieldName.maName, aFieldName.mnDupCount);
+ }
+
+ // *** HIDDEN ITEMS ***
+
+ rLabelData.maMembers = maLabelData.maMembers;
+ int nVisCount = m_xLbHide->n_children();
+ for (int nPos = 0; nPos < nVisCount; ++nPos)
+ rLabelData.maMembers[nPos].mbVisible = m_xLbHide->get_toggle(nPos) == TRISTATE_FALSE;
+
+ // *** HIERARCHY ***
+
+ rLabelData.mnUsedHier = m_xLbHierarchy->get_active() != -1 ? m_xLbHierarchy->get_active() : 0;
+}
+
+void ScDPSubtotalOptDlg::Init( const ScDPNameVec& rDataFields, bool bEnableLayout )
+{
+ m_xBtnOk->connect_clicked(LINK(this, ScDPSubtotalOptDlg, ButtonClicked));
+ m_xBtnCancel->connect_clicked(LINK(this, ScDPSubtotalOptDlg, ButtonClicked));
+
+ // *** SORTING ***
+
+ sal_Int32 nSortMode = maLabelData.maSortInfo.Mode;
+
+ // sort fields list box
+ m_xLbSortBy->append_text(maLabelData.getDisplayName());
+
+ for( const auto& rDataField : rDataFields )
+ {
+ // Cache names for later lookup.
+ maDataFieldNameMap.emplace(rDataField.maLayoutName, rDataField);
+
+ m_xLbSortBy->append_text(rDataField.maLayoutName);
+ m_xLbShowUsing->append_text(rDataField.maLayoutName); // for AutoShow
+ }
+
+ sal_Int32 nSortPos = SC_SORTNAME_POS;
+ if( nSortMode == DataPilotFieldSortMode::DATA )
+ {
+ nSortPos = FindListBoxEntry( *m_xLbSortBy, maLabelData.maSortInfo.Field, SC_SORTDATA_POS );
+ if( nSortPos == -1 )
+ {
+ nSortPos = SC_SORTNAME_POS;
+ nSortMode = DataPilotFieldSortMode::MANUAL;
+ }
+ }
+ m_xLbSortBy->set_active(nSortPos);
+
+ // sorting mode
+ m_xRbSortAsc->connect_toggled( LINK( this, ScDPSubtotalOptDlg, RadioClickHdl ) );
+ m_xRbSortDesc->connect_toggled( LINK( this, ScDPSubtotalOptDlg, RadioClickHdl ) );
+ m_xRbSortMan->connect_toggled( LINK( this, ScDPSubtotalOptDlg, RadioClickHdl ) );
+
+ weld::RadioButton* pRBtn = nullptr;
+ switch( nSortMode )
+ {
+ case DataPilotFieldSortMode::NONE:
+ case DataPilotFieldSortMode::MANUAL:
+ pRBtn = m_xRbSortMan.get();
+ break;
+ default:
+ pRBtn = maLabelData.maSortInfo.IsAscending ? m_xRbSortAsc.get() : m_xRbSortDesc.get();
+ }
+ pRBtn->set_active(true);
+ RadioClickHdl(*pRBtn);
+
+ // *** LAYOUT MODE ***
+
+ m_xLayoutFrame->set_sensitive(bEnableLayout);
+
+ m_xLbLayout->set_active(FromDataPilotFieldLayoutMode(maLabelData.maLayoutInfo.LayoutMode));
+ m_xCbLayoutEmpty->set_active( maLabelData.maLayoutInfo.AddEmptyLines );
+ m_xCbRepeatItemLabels->set_active( maLabelData.mbRepeatItemLabels );
+
+ // *** AUTO SHOW ***
+
+ m_xCbShow->set_active( maLabelData.maShowInfo.IsEnabled );
+ m_xCbShow->connect_toggled( LINK( this, ScDPSubtotalOptDlg, CheckHdl ) );
+
+ m_xLbShowFrom->set_active(FromDataPilotFieldShowItemsMode(maLabelData.maShowInfo.ShowItemsMode));
+ tools::Long nCount = static_cast< tools::Long >( maLabelData.maShowInfo.ItemCount );
+ if( nCount < 1 )
+ nCount = SC_SHOW_DEFAULT;
+ m_xNfShow->set_value( nCount );
+
+ // m_xLbShowUsing already filled above
+ m_xLbShowUsing->set_active_text(maLabelData.maShowInfo.DataField);
+ if (m_xLbShowUsing->get_active() == -1)
+ m_xLbShowUsing->set_active(0);
+
+ CheckHdl(*m_xCbShow); // enable/disable dependent controls
+
+ // *** HIDDEN ITEMS ***
+
+ InitHideListBox();
+
+ // *** HIERARCHY ***
+
+ if( maLabelData.maHiers.getLength() > 1 )
+ {
+ lclFillListBox(*m_xLbHierarchy, maLabelData.maHiers);
+ sal_Int32 nHier = maLabelData.mnUsedHier;
+ if( (nHier < 0) || (nHier >= maLabelData.maHiers.getLength()) ) nHier = 0;
+ m_xLbHierarchy->set_active( nHier );
+ m_xLbHierarchy->connect_changed( LINK( this, ScDPSubtotalOptDlg, SelectHdl ) );
+ }
+ else
+ {
+ m_xFtHierarchy->set_sensitive(false);
+ m_xLbHierarchy->set_sensitive(false);
+ }
+}
+
+void ScDPSubtotalOptDlg::InitHideListBox()
+{
+ m_xLbHide->clear();
+ lclFillListBox(*m_xLbHide, maLabelData.maMembers);
+ size_t n = maLabelData.maMembers.size();
+ for (size_t i = 0; i < n; ++i)
+ m_xLbHide->set_toggle(i, maLabelData.maMembers[i].mbVisible ? TRISTATE_FALSE : TRISTATE_TRUE);
+ bool bEnable = m_xLbHide->n_children() > 0;
+ m_xHideFrame->set_sensitive(bEnable);
+}
+
+ScDPName ScDPSubtotalOptDlg::GetFieldName(const OUString& rLayoutName) const
+{
+ NameMapType::const_iterator itr = maDataFieldNameMap.find(rLayoutName);
+ return itr == maDataFieldNameMap.end() ? ScDPName() : itr->second;
+}
+
+sal_Int32 ScDPSubtotalOptDlg::FindListBoxEntry(
+ const weld::ComboBox& rLBox, std::u16string_view rEntry, sal_Int32 nStartPos ) const
+{
+ sal_Int32 nPos = nStartPos;
+ bool bFound = false;
+ while (nPos < rLBox.get_count())
+ {
+ // translate the displayed field name back to its original field name.
+ ScDPName aName = GetFieldName(rLBox.get_text(nPos));
+ OUString aUnoName = ScDPUtil::createDuplicateDimensionName(aName.maName, aName.mnDupCount);
+ if (aUnoName == rEntry)
+ {
+ bFound = true;
+ break;
+ }
+ ++nPos;
+ }
+ return bFound ? nPos : -1;
+}
+
+IMPL_LINK(ScDPSubtotalOptDlg, ButtonClicked, weld::Button&, rButton, void)
+{
+ if (&rButton == m_xBtnOk.get())
+ response(RET_OK);
+ else
+ response(RET_CANCEL);
+}
+
+IMPL_LINK(ScDPSubtotalOptDlg, RadioClickHdl, weld::Toggleable&, rBtn, void)
+{
+ if (!rBtn.get_active())
+ return;
+
+ m_xLbSortBy->set_sensitive(m_xRbSortMan->get_active());
+}
+
+IMPL_LINK(ScDPSubtotalOptDlg, CheckHdl, weld::Toggleable&, rCBox, void)
+{
+ if (&rCBox == m_xCbShow.get())
+ {
+ bool bEnable = m_xCbShow->get_active();
+ m_xNfShow->set_sensitive( bEnable );
+ m_xFtShow->set_sensitive( bEnable );
+ m_xFtShowFrom->set_sensitive( bEnable );
+ m_xLbShowFrom->set_sensitive( bEnable );
+
+ bool bEnableUsing = bEnable && (m_xLbShowUsing->get_count() > 0);
+ m_xFtShowUsing->set_sensitive(bEnableUsing);
+ m_xLbShowUsing->set_sensitive(bEnableUsing);
+ }
+}
+
+IMPL_LINK_NOARG(ScDPSubtotalOptDlg, SelectHdl, weld::ComboBox&, void)
+{
+ mrDPObj.GetMembers(maLabelData.mnCol, m_xLbHierarchy->get_active(), maLabelData.maMembers);
+ InitHideListBox();
+}
+
+ScDPShowDetailDlg::ScDPShowDetailDlg(weld::Window* pParent, ScDPObject& rDPObj, css::sheet::DataPilotFieldOrientation nOrient)
+ : GenericDialogController(pParent, "modules/scalc/ui/showdetaildialog.ui", "ShowDetail")
+ , mrDPObj(rDPObj)
+ , mxLbDims(m_xBuilder->weld_tree_view("dimsTreeview"))
+{
+ ScDPSaveData* pSaveData = rDPObj.GetSaveData();
+ tools::Long nDimCount = rDPObj.GetDimCount();
+ for (tools::Long nDim=0; nDim<nDimCount; nDim++)
+ {
+ bool bIsDataLayout;
+ sal_Int32 nDimFlags = 0;
+ OUString aName = rDPObj.GetDimName( nDim, bIsDataLayout, &nDimFlags );
+ if ( !bIsDataLayout && !rDPObj.IsDuplicated( nDim ) && ScDPObject::IsOrientationAllowed( nOrient, nDimFlags ) )
+ {
+ const ScDPSaveDimension* pDimension = pSaveData ? pSaveData->GetExistingDimensionByName(aName) : nullptr;
+ if ( !pDimension || (pDimension->GetOrientation() != nOrient) )
+ {
+ if (pDimension)
+ {
+ const std::optional<OUString> & pLayoutName = pDimension->GetLayoutName();
+ if (pLayoutName)
+ aName = *pLayoutName;
+ }
+ mxLbDims->append_text(aName);
+ maNameIndexMap.emplace(aName, nDim);
+ }
+ }
+ }
+ if (mxLbDims->n_children())
+ mxLbDims->select(0);
+
+ mxLbDims->connect_row_activated(LINK(this, ScDPShowDetailDlg, DblClickHdl));
+}
+
+ScDPShowDetailDlg::~ScDPShowDetailDlg()
+{
+}
+
+short ScDPShowDetailDlg::run()
+{
+ return mxLbDims->n_children() ? GenericDialogController::run() : static_cast<short>(RET_CANCEL);
+}
+
+OUString ScDPShowDetailDlg::GetDimensionName() const
+{
+ // Look up the internal dimension name which may be different from the
+ // displayed field name.
+ OUString aSelectedName = mxLbDims->get_selected_text();
+ DimNameIndexMap::const_iterator itr = maNameIndexMap.find(aSelectedName);
+ if (itr == maNameIndexMap.end())
+ // This should never happen!
+ return aSelectedName;
+
+ tools::Long nDim = itr->second;
+ bool bIsDataLayout = false;
+ return mrDPObj.GetDimName(nDim, bIsDataLayout);
+}
+
+IMPL_LINK_NOARG(ScDPShowDetailDlg, DblClickHdl, weld::TreeView&, bool)
+{
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/scendlg.cxx b/sc/source/ui/dbgui/scendlg.cxx
new file mode 100644
index 000000000..543914e14
--- /dev/null
+++ b/sc/source/ui/dbgui/scendlg.cxx
@@ -0,0 +1,163 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <comphelper/string.hxx>
+#include <svx/colorbox.hxx>
+#include <unotools/useroptions.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <unotools/localedatawrapper.hxx>
+
+#include <global.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <tabvwsh.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <scendlg.hxx>
+
+ScNewScenarioDlg::ScNewScenarioDlg(weld::Window* pParent, const OUString& rName, bool bEdit, bool bSheetProtected)
+ : GenericDialogController(pParent, "modules/scalc/ui/scenariodialog.ui", "ScenarioDialog")
+ , aDefScenarioName(rName)
+ , bIsEdit(bEdit)
+ , m_xEdName(m_xBuilder->weld_entry("name"))
+ , m_xEdComment(m_xBuilder->weld_text_view("comment"))
+ , m_xCbShowFrame(m_xBuilder->weld_check_button("showframe"))
+ , m_xLbColor(new ColorListBox(m_xBuilder->weld_menu_button("bordercolor"), [this] { return m_xDialog.get(); }))
+ , m_xCbTwoWay(m_xBuilder->weld_check_button("copyback"))
+ , m_xCbCopyAll(m_xBuilder->weld_check_button("copysheet"))
+ , m_xCbProtect(m_xBuilder->weld_check_button("preventchanges"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xAltTitle(m_xBuilder->weld_label("alttitle"))
+ , m_xCreatedFt(m_xBuilder->weld_label("createdft"))
+ , m_xOnFt(m_xBuilder->weld_label("onft"))
+{
+ m_xEdComment->set_size_request(m_xEdComment->get_approximate_digit_width() * 60,
+ m_xEdComment->get_height_rows(6));
+
+ if (bIsEdit)
+ m_xDialog->set_title(m_xAltTitle->get_label());
+
+ SvtUserOptions aUserOpt;
+
+ OUString sCreatedBy(m_xCreatedFt->get_label());
+ OUString sOn(m_xOnFt->get_label());
+
+ OUString aComment(sCreatedBy + " " + aUserOpt.GetFirstName() + " " +aUserOpt.GetLastName()
+ + ", " + sOn + " " + ScGlobal::getLocaleData().getDate(Date(Date::SYSTEM))
+ + ", " + ScGlobal::getLocaleData().getTime(tools::Time(tools::Time::SYSTEM)));
+
+ m_xEdComment->set_text(aComment);
+ m_xEdName->set_text(rName);
+ m_xBtnOk->connect_clicked(LINK(this, ScNewScenarioDlg, OkHdl));
+ m_xCbShowFrame->connect_toggled(LINK(this, ScNewScenarioDlg, EnableHdl));
+
+ m_xLbColor->SelectEntry( COL_LIGHTGRAY );
+ m_xCbShowFrame->set_active(true);
+ m_xCbTwoWay->set_active(true);
+ m_xCbCopyAll->set_active(false);
+ m_xCbProtect->set_active(true);
+
+ if (bIsEdit)
+ m_xCbCopyAll->set_active(false);
+ // If the Sheet is protected then we disable the Scenario Protect input
+ // and default it to true above. Note we are in 'Add' mode here as: if
+ // Sheet && scenario protection are true, then we cannot edit this dialog.
+ if (bSheetProtected)
+ m_xCbProtect->set_active(false);
+}
+
+ScNewScenarioDlg::~ScNewScenarioDlg()
+{
+}
+
+void ScNewScenarioDlg::GetScenarioData( OUString& rName, OUString& rComment,
+ Color& rColor, ScScenarioFlags& rFlags ) const
+{
+ rComment = m_xEdComment->get_text();
+ rName = m_xEdName->get_text();
+
+ if (rName.isEmpty())
+ rName = aDefScenarioName;
+
+ rColor = m_xLbColor->GetSelectEntryColor();
+ ScScenarioFlags nBits = ScScenarioFlags::NONE;
+ if (m_xCbShowFrame->get_active())
+ nBits |= ScScenarioFlags::ShowFrame;
+ if (m_xCbTwoWay->get_active())
+ nBits |= ScScenarioFlags::TwoWay;
+ if (m_xCbCopyAll->get_active())
+ nBits |= ScScenarioFlags::CopyAll;
+ if (m_xCbProtect->get_active())
+ nBits |= ScScenarioFlags::Protected;
+ rFlags = nBits;
+}
+
+void ScNewScenarioDlg::SetScenarioData(const OUString& rName, const OUString& rComment,
+ const Color& rColor, ScScenarioFlags nFlags)
+{
+ m_xEdComment->set_text(rComment);
+ m_xEdName->set_text(rName);
+ m_xLbColor->SelectEntry(rColor);
+
+ m_xCbShowFrame->set_active( (nFlags & ScScenarioFlags::ShowFrame) != ScScenarioFlags::NONE );
+ EnableHdl(*m_xCbShowFrame);
+ m_xCbTwoWay->set_active( (nFlags & ScScenarioFlags::TwoWay) != ScScenarioFlags::NONE );
+ // not CopyAll
+ m_xCbProtect->set_active( (nFlags & ScScenarioFlags::Protected) != ScScenarioFlags::NONE );
+}
+
+IMPL_LINK_NOARG(ScNewScenarioDlg, OkHdl, weld::Button&, void)
+{
+ OUString aName = comphelper::string::strip(m_xEdName->get_text(), ' ');
+ ScDocument& rDoc = static_cast<ScTabViewShell*>(SfxViewShell::Current())->GetViewData().GetDocument();
+
+ m_xEdName->set_text(aName);
+
+ if ( !ScDocument::ValidTabName( aName ) )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_INVALIDTABNAME)));
+ xInfoBox->run();
+ m_xEdName->grab_focus();
+ }
+ else if ( !bIsEdit && !rDoc.ValidNewTabName( aName ) )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_NEWTABNAMENOTUNIQUE)));
+ xInfoBox->run();
+ m_xEdName->grab_focus();
+ }
+ else
+ m_xDialog->response(RET_OK);
+
+ //! when editing, test whether another table has the name!
+}
+
+IMPL_LINK(ScNewScenarioDlg, EnableHdl, weld::Toggleable&, rBox, void)
+{
+ if (&rBox == m_xCbShowFrame.get())
+ m_xLbColor->set_sensitive(m_xCbShowFrame->get_active());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/scuiasciiopt.cxx b/sc/source/ui/dbgui/scuiasciiopt.cxx
new file mode 100644
index 000000000..126689d7b
--- /dev/null
+++ b/sc/source/ui/dbgui/scuiasciiopt.cxx
@@ -0,0 +1,943 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <svx/txencbox.hxx>
+
+#include <global.hxx>
+#include <scresid.hxx>
+#include <impex.hxx>
+#include <scuiasciiopt.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <csvtablebox.hxx>
+#include <osl/thread.h>
+#include <unotools/transliterationwrapper.hxx>
+
+#include <optutil.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <miscuno.hxx>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+#include <comphelper/lok.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <unicode/ucsdet.h>
+
+//! TODO make dynamic
+const SCSIZE ASCIIDLG_MAXROWS = MAXROWCOUNT;
+
+// Maximum number of source lines to concatenate while generating the preview
+// for one logical line. This may result in a wrong preview if the actual
+// number of embedded line feeds is greater, but a number too high would take
+// too much time (loop excessively if unlimited and large data) if none of the
+// selected separators are actually used in data but a field at start of line
+// is quoted.
+constexpr sal_uInt32 kMaxEmbeddedLinefeeds = 500;
+
+using namespace com::sun::star::uno;
+
+namespace {
+
+// Defines - CSV Import Preserve Options
+// For usage of index order see lcl_CreatePropertiesNames() below.
+enum CSVImportOptionsIndex
+{
+ CSVIO_MergeDelimiters = 0,
+ CSVIO_Separators,
+ CSVIO_TextSeparators,
+ CSVIO_FixedWidth,
+ CSVIO_RemoveSpace,
+ CSVIO_EvaluateFormulas,
+ // Settings for *all* dialog invocations above.
+ // Settings not for SC_TEXTTOCOLUMNS below.
+ CSVIO_FromRow,
+ CSVIO_Text2ColSkipEmptyCells = CSVIO_FromRow,
+ CSVIO_CharSet,
+ CSVIO_QuotedAsText,
+ CSVIO_DetectSpecialNum,
+ CSVIO_Language,
+ // Plus one not for SC_IMPORTFILE.
+ CSVIO_PasteSkipEmptyCells
+};
+
+}
+
+// Config items for all three paths are defined in
+// officecfg/registry/schema/org/openoffice/Office/Calc.xcs
+// If not, options are neither loaded nor saved.
+const ::std::vector<OUString> CSVImportOptionNames =
+{
+ "MergeDelimiters",
+ "Separators",
+ "TextSeparators",
+ "FixedWidth",
+ "RemoveSpace",
+ "EvaluateFormulas",
+ "FromRow",
+ "CharSet",
+ "QuotedFieldAsText",
+ "DetectSpecialNumbers",
+ "Language",
+ "SkipEmptyCells"
+};
+constexpr OUStringLiteral aSep_Path = u"Office.Calc/Dialogs/CSVImport";
+constexpr OUStringLiteral aSep_Path_Clpbrd = u"Office.Calc/Dialogs/ClipboardTextImport";
+constexpr OUStringLiteral aSep_Path_Text2Col = u"Office.Calc/Dialogs/TextToColumnsImport";
+
+namespace {
+CSVImportOptionsIndex getSkipEmptyCellsIndex( ScImportAsciiCall eCall )
+{
+ return eCall == SC_TEXTTOCOLUMNS ? CSVIO_Text2ColSkipEmptyCells : CSVIO_PasteSkipEmptyCells;
+}
+}
+
+static void lcl_FillCombo(weld::ComboBox& rCombo, std::u16string_view rList, sal_Unicode cSelect)
+{
+ OUString aStr;
+ if (!rList.empty())
+ {
+ sal_Int32 nIdx {0};
+ do
+ {
+ const OUString sEntry {o3tl::getToken(rList, 0, '\t', nIdx)};
+ rCombo.append_text(sEntry);
+ if (nIdx>0 && static_cast<sal_Unicode>(o3tl::toInt32(o3tl::getToken(rList, 0, '\t', nIdx))) == cSelect)
+ aStr = sEntry;
+ }
+ while (nIdx>0);
+ }
+
+ if ( cSelect )
+ {
+ if (aStr.isEmpty())
+ aStr = OUString(cSelect); // Ascii
+
+ rCombo.set_entry_text(aStr);
+ }
+}
+
+static sal_Unicode lcl_CharFromCombo(const weld::ComboBox& rCombo, std::u16string_view rList)
+{
+ sal_Unicode c = 0;
+ OUString aStr = rCombo.get_active_text();
+ if ( !aStr.isEmpty() && !rList.empty() )
+ {
+ sal_Int32 nIdx {0};
+ OUString sToken {o3tl::getToken(rList, 0, '\t', nIdx)};
+ while (nIdx>0)
+ {
+ if ( ScGlobal::GetTransliteration().isEqual( aStr, sToken ) )
+ {
+ sal_Int32 nTmpIdx {nIdx};
+ c = static_cast<sal_Unicode>(o3tl::toInt32(o3tl::getToken(rList, 0, '\t', nTmpIdx)));
+ }
+ // Skip to next token at even position
+ sToken = o3tl::getToken(rList, 1, '\t', nIdx);
+ }
+ if (!c)
+ {
+ sal_Unicode cFirst = aStr[0];
+ // #i24235# first try the first character of the string directly
+ if( (aStr.getLength() == 1) || (cFirst < '0') || (cFirst > '9') )
+ c = cFirst;
+ else // keep old behaviour for compatibility (i.e. "39" -> "'")
+ c = static_cast<sal_Unicode>(aStr.toInt32()); // Ascii
+ }
+ }
+ return c;
+}
+
+static void lcl_CreatePropertiesNames ( OUString& rSepPath, Sequence<OUString>& rNames, ScImportAsciiCall eCall )
+{
+ sal_Int32 nProperties = 0;
+
+ switch(eCall)
+ {
+ case SC_IMPORTFILE:
+ rSepPath = aSep_Path;
+ nProperties = 11;
+ break;
+ case SC_PASTETEXT:
+ rSepPath = aSep_Path_Clpbrd;
+ nProperties = 12;
+ break;
+ case SC_TEXTTOCOLUMNS:
+ default:
+ rSepPath = aSep_Path_Text2Col;
+ nProperties = 7;
+ break;
+ }
+ rNames.realloc( nProperties );
+ OUString* pNames = rNames.getArray();
+ pNames[ CSVIO_MergeDelimiters ] = CSVImportOptionNames[ CSVIO_MergeDelimiters ];
+ pNames[ CSVIO_Separators ] = CSVImportOptionNames[ CSVIO_Separators ];
+ pNames[ CSVIO_TextSeparators ] = CSVImportOptionNames[ CSVIO_TextSeparators ];
+ pNames[ CSVIO_FixedWidth ] = CSVImportOptionNames[ CSVIO_FixedWidth ];
+ pNames[ CSVIO_RemoveSpace ] = CSVImportOptionNames[ CSVIO_RemoveSpace ];
+ pNames[ CSVIO_EvaluateFormulas ] = CSVImportOptionNames[ CSVIO_EvaluateFormulas ];
+ if (eCall != SC_TEXTTOCOLUMNS)
+ {
+ pNames[ CSVIO_FromRow ] = CSVImportOptionNames[ CSVIO_FromRow ];
+ pNames[ CSVIO_CharSet ] = CSVImportOptionNames[ CSVIO_CharSet ];
+ pNames[ CSVIO_QuotedAsText ] = CSVImportOptionNames[ CSVIO_QuotedAsText ];
+ pNames[ CSVIO_DetectSpecialNum ] = CSVImportOptionNames[ CSVIO_DetectSpecialNum ];
+ pNames[ CSVIO_Language ] = CSVImportOptionNames[ CSVIO_Language ];
+ }
+ if (eCall != SC_IMPORTFILE)
+ {
+ const sal_Int32 nSkipEmptyCells = getSkipEmptyCellsIndex(eCall);
+ assert( nSkipEmptyCells < rNames.getLength());
+ pNames[ nSkipEmptyCells ] = CSVImportOptionNames[ CSVIO_PasteSkipEmptyCells ];
+ }
+}
+
+static void lcl_LoadSeparators( OUString& rFieldSeparators, OUString& rTextSeparators,
+ bool& rMergeDelimiters, bool& rQuotedAsText, bool& rDetectSpecialNum,
+ bool& rFixedWidth, sal_Int32& rFromRow, sal_Int32& rCharSet,
+ sal_Int32& rLanguage, bool& rSkipEmptyCells, bool& rRemoveSpace,
+ bool& rEvaluateFormulas, ScImportAsciiCall eCall )
+{
+ Sequence<Any>aValues;
+ const Any *pProperties;
+ Sequence<OUString> aNames;
+ OUString aSepPath;
+ lcl_CreatePropertiesNames ( aSepPath, aNames, eCall);
+ ScLinkConfigItem aItem( aSepPath );
+ aValues = aItem.GetProperties( aNames );
+ pProperties = aValues.getConstArray();
+
+ if( pProperties[ CSVIO_MergeDelimiters ].hasValue() )
+ rMergeDelimiters = ScUnoHelpFunctions::GetBoolFromAny( pProperties[ CSVIO_MergeDelimiters ] );
+
+ if( pProperties[ CSVIO_RemoveSpace ].hasValue() )
+ rRemoveSpace = ScUnoHelpFunctions::GetBoolFromAny( pProperties[ CSVIO_RemoveSpace ] );
+
+ if( pProperties[ CSVIO_Separators ].hasValue() )
+ pProperties[ CSVIO_Separators ] >>= rFieldSeparators;
+
+ if( pProperties[ CSVIO_TextSeparators ].hasValue() )
+ pProperties[ CSVIO_TextSeparators ] >>= rTextSeparators;
+
+ if( pProperties[ CSVIO_FixedWidth ].hasValue() )
+ rFixedWidth = ScUnoHelpFunctions::GetBoolFromAny( pProperties[ CSVIO_FixedWidth ] );
+
+ if( pProperties[ CSVIO_EvaluateFormulas ].hasValue() )
+ rEvaluateFormulas = ScUnoHelpFunctions::GetBoolFromAny( pProperties[ CSVIO_EvaluateFormulas ] );
+
+ if (eCall != SC_TEXTTOCOLUMNS)
+ {
+ if( pProperties[ CSVIO_FromRow ].hasValue() )
+ pProperties[ CSVIO_FromRow ] >>= rFromRow;
+
+ if( pProperties[ CSVIO_CharSet ].hasValue() )
+ pProperties[ CSVIO_CharSet ] >>= rCharSet;
+
+ if ( pProperties[ CSVIO_QuotedAsText ].hasValue() )
+ pProperties[ CSVIO_QuotedAsText ] >>= rQuotedAsText;
+
+ if ( pProperties[ CSVIO_DetectSpecialNum ].hasValue() )
+ pProperties[ CSVIO_DetectSpecialNum ] >>= rDetectSpecialNum;
+
+ if ( pProperties[ CSVIO_Language ].hasValue() )
+ pProperties[ CSVIO_Language ] >>= rLanguage;
+ }
+ if (eCall != SC_IMPORTFILE)
+ {
+ const sal_Int32 nSkipEmptyCells = getSkipEmptyCellsIndex(eCall);
+ assert( nSkipEmptyCells < aValues.getLength());
+ if ( pProperties[nSkipEmptyCells].hasValue() )
+ rSkipEmptyCells = ScUnoHelpFunctions::GetBoolFromAny( pProperties[nSkipEmptyCells] );
+ }
+}
+
+static void lcl_SaveSeparators(
+ const OUString& sFieldSeparators, const OUString& sTextSeparators, bool bMergeDelimiters, bool bQuotedAsText,
+ bool bDetectSpecialNum, bool bFixedWidth, sal_Int32 nFromRow,
+ sal_Int32 nCharSet, sal_Int32 nLanguage, bool bSkipEmptyCells, bool bRemoveSpace, bool bEvaluateFormulas,
+ ScImportAsciiCall eCall )
+{
+ Sequence<Any> aValues;
+ Any *pProperties;
+ Sequence<OUString> aNames;
+ OUString aSepPath;
+ lcl_CreatePropertiesNames ( aSepPath, aNames, eCall );
+ ScLinkConfigItem aItem( aSepPath );
+ aValues = aItem.GetProperties( aNames );
+ pProperties = aValues.getArray();
+
+ pProperties[ CSVIO_MergeDelimiters ] <<= bMergeDelimiters;
+ pProperties[ CSVIO_RemoveSpace ] <<= bRemoveSpace;
+ pProperties[ CSVIO_Separators ] <<= sFieldSeparators;
+ pProperties[ CSVIO_TextSeparators ] <<= sTextSeparators;
+ pProperties[ CSVIO_FixedWidth ] <<= bFixedWidth;
+ pProperties[ CSVIO_EvaluateFormulas ] <<= bEvaluateFormulas;
+ if (eCall != SC_TEXTTOCOLUMNS)
+ {
+ pProperties[ CSVIO_FromRow ] <<= nFromRow;
+ pProperties[ CSVIO_CharSet ] <<= nCharSet;
+ pProperties[ CSVIO_QuotedAsText ] <<= bQuotedAsText;
+ pProperties[ CSVIO_DetectSpecialNum ] <<= bDetectSpecialNum;
+ pProperties[ CSVIO_Language ] <<= nLanguage;
+ }
+ if (eCall != SC_IMPORTFILE)
+ {
+ const sal_Int32 nSkipEmptyCells = getSkipEmptyCellsIndex(eCall);
+ assert( nSkipEmptyCells < aValues.getLength());
+ pProperties[ nSkipEmptyCells ] <<= bSkipEmptyCells;
+ }
+
+ aItem.PutProperties(aNames, aValues);
+}
+
+ScImportAsciiDlg::ScImportAsciiDlg(weld::Window* pParent, const OUString& aDatName,
+ SvStream* pInStream, ScImportAsciiCall eCall)
+ : GenericDialogController(pParent, "modules/scalc/ui/textimportcsv.ui", "TextImportCsvDialog")
+ , mpDatStream(pInStream)
+ , mnStreamPos(pInStream ? pInStream->Tell() : 0)
+ , mnRowPosCount(0)
+ , mcTextSep(ScAsciiOptions::cDefaultTextSep)
+ , meCall(eCall)
+ , mbDetectSep(eCall != SC_TEXTTOCOLUMNS)
+ , mxFtCharSet(m_xBuilder->weld_label("textcharset"))
+ , mxLbCharSet(new SvxTextEncodingBox(m_xBuilder->weld_combo_box("charset")))
+ , mxFtCustomLang(m_xBuilder->weld_label("textlanguage"))
+ , mxLbCustomLang(new SvxLanguageBox(m_xBuilder->weld_combo_box("language")))
+ , mxFtRow(m_xBuilder->weld_label("textfromrow"))
+ , mxNfRow(m_xBuilder->weld_spin_button("fromrow"))
+ , mxRbFixed(m_xBuilder->weld_radio_button("tofixedwidth"))
+ , mxRbSeparated(m_xBuilder->weld_radio_button("toseparatedby"))
+ , mxCkbTab(m_xBuilder->weld_check_button("tab"))
+ , mxCkbSemicolon(m_xBuilder->weld_check_button("semicolon"))
+ , mxCkbComma(m_xBuilder->weld_check_button("comma"))
+ , mxCkbRemoveSpace(m_xBuilder->weld_check_button("removespace"))
+ , mxCkbSpace(m_xBuilder->weld_check_button("space"))
+ , mxCkbOther(m_xBuilder->weld_check_button("other"))
+ , mxEdOther(m_xBuilder->weld_entry("inputother"))
+ , mxCkbAsOnce(m_xBuilder->weld_check_button("mergedelimiters"))
+ , mxFtTextSep(m_xBuilder->weld_label("texttextdelimiter"))
+ , mxCbTextSep(m_xBuilder->weld_combo_box("textdelimiter"))
+ , mxCkbQuotedAsText(m_xBuilder->weld_check_button("quotedfieldastext"))
+ , mxCkbDetectNumber(m_xBuilder->weld_check_button("detectspecialnumbers"))
+ , mxCkbEvaluateFormulas(m_xBuilder->weld_check_button("evaluateformulas"))
+ , mxCkbSkipEmptyCells(m_xBuilder->weld_check_button("skipemptycells"))
+ , mxFtType(m_xBuilder->weld_label("textcolumntype"))
+ , mxLbType(m_xBuilder->weld_combo_box("columntype"))
+ , mxAltTitle(m_xBuilder->weld_label("textalttitle"))
+ , mxTableBox(new ScCsvTableBox(*m_xBuilder))
+{
+ OUString aName = m_xDialog->get_title();
+ switch (meCall)
+ {
+ case SC_TEXTTOCOLUMNS:
+ m_xDialog->set_title(mxAltTitle->get_label());
+ break;
+ case SC_IMPORTFILE:
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ aName += " - [" + aDatName + "]";
+ m_xDialog->set_title(aName);
+ }
+ break;
+ default:
+ break;
+ }
+
+ // To be able to prefill the correct values based on the file extension
+ bool bIsTSV = (aDatName.endsWithIgnoreAsciiCase(".tsv") || aDatName.endsWithIgnoreAsciiCase(".tab"));
+
+ // Default options are set in officecfg/registry/schema/org/openoffice/Office/Calc.xcs
+ OUString sFieldSeparators(",;\t");
+ OUString sTextSeparators(mcTextSep);
+ bool bMergeDelimiters = false;
+ bool bFixedWidth = false;
+ bool bQuotedFieldAsText = false;
+ bool bDetectSpecialNum = true;
+ bool bEvaluateFormulas = (meCall != SC_IMPORTFILE);
+ bool bSkipEmptyCells = true;
+ bool bRemoveSpace = false;
+ sal_Int32 nFromRow = 1;
+ sal_Int32 nCharSet = -1;
+ sal_Int32 nLanguage = 0;
+ lcl_LoadSeparators (sFieldSeparators, sTextSeparators, bMergeDelimiters,
+ bQuotedFieldAsText, bDetectSpecialNum, bFixedWidth, nFromRow,
+ nCharSet, nLanguage, bSkipEmptyCells, bRemoveSpace, bEvaluateFormulas, meCall);
+ // load from saved settings
+ maFieldSeparators = sFieldSeparators;
+
+ if( bMergeDelimiters && !bIsTSV )
+ mxCkbAsOnce->set_active(true);
+ if (bQuotedFieldAsText)
+ mxCkbQuotedAsText->set_active(true);
+ if (bRemoveSpace)
+ mxCkbRemoveSpace->set_active(true);
+ if (bDetectSpecialNum)
+ mxCkbDetectNumber->set_active(true);
+ if (bEvaluateFormulas)
+ mxCkbEvaluateFormulas->set_active(true);
+ if (bSkipEmptyCells)
+ mxCkbSkipEmptyCells->set_active(true);
+ if (bFixedWidth && !bIsTSV)
+ mxRbFixed->set_active(true);
+ if (nFromRow != 1)
+ mxNfRow->set_value(nFromRow);
+
+ // Clipboard is always Unicode, else detect.
+ rtl_TextEncoding ePreselectUnicode = (meCall == SC_IMPORTFILE ?
+ RTL_TEXTENCODING_DONTKNOW : RTL_TEXTENCODING_UNICODE);
+ // Sniff for Unicode / not
+ if( ePreselectUnicode == RTL_TEXTENCODING_DONTKNOW && mpDatStream )
+ {
+ mpDatStream->Seek( 0 );
+ constexpr size_t buffsize = 4096;
+ sal_Int8 bytes[buffsize] = { 0 };
+ sal_Int32 nRead = mpDatStream->ReadBytes( bytes, buffsize );
+ mpDatStream->Seek( 0 );
+
+ if ( nRead > 0 )
+ {
+ UErrorCode uerr = U_ZERO_ERROR;
+ UCharsetDetector* ucd = ucsdet_open( &uerr );
+ ucsdet_setText( ucd, reinterpret_cast<const char*>(bytes), nRead, &uerr );
+
+ if ( const UCharsetMatch* match = ucsdet_detect(ucd, &uerr) )
+ {
+ const char* pEncodingName = ucsdet_getName( match, &uerr );
+
+ if ( U_SUCCESS(uerr) && !strcmp("UTF-8", pEncodingName) )
+ {
+ ePreselectUnicode = RTL_TEXTENCODING_UTF8; // UTF-8
+ mpDatStream->StartReadingUnicodeText( RTL_TEXTENCODING_UTF8 );
+ }
+ else if ( U_SUCCESS(uerr) && !strcmp("UTF-16LE", pEncodingName) )
+ {
+ ePreselectUnicode = RTL_TEXTENCODING_UNICODE; // UTF-16LE
+ mpDatStream->SetEndian( SvStreamEndian::LITTLE );
+ mpDatStream->StartReadingUnicodeText( RTL_TEXTENCODING_UNICODE );
+ }
+ else if ( U_SUCCESS(uerr) && !strcmp("UTF-16BE", pEncodingName) )
+ {
+ ePreselectUnicode = RTL_TEXTENCODING_UNICODE; // UTF-16BE
+ mpDatStream->SetEndian( SvStreamEndian::BIG );
+ mpDatStream->StartReadingUnicodeText( RTL_TEXTENCODING_UNICODE );
+ }
+ else // other
+ mpDatStream->StartReadingUnicodeText( RTL_TEXTENCODING_DONTKNOW );
+ }
+
+ ucsdet_close( ucd );
+ }
+
+ mnStreamPos = mpDatStream->Tell();
+ }
+
+ if (bIsTSV)
+ SetSeparators('\t');
+ else
+ {
+ // Some MS-Excel convention is the first line containing the field
+ // separator as "sep=|" (without quotes and any field separator
+ // character). The second possibility seems to be it is present *with*
+ // quotes so it shows up as cell content *including* the separator and
+ // can be preserved during round trips. Check for an exact match of
+ // any such and set separator.
+ /* TODO: it is debatable whether the unquoted form should rather be
+ * treated special to actually include the separator in the field data.
+ * Currently it does not. */
+ sal_Unicode cSep = 0;
+ OUString aLine;
+ // Try to read one more character, if more than 7 it can't be an exact
+ // match of any.
+ mpDatStream->ReadUniOrByteStringLine( aLine, mpDatStream->GetStreamCharSet(), 8);
+ mpDatStream->Seek(mnStreamPos);
+ if (aLine.getLength() == 8)
+ ; // nothing
+ else if (aLine.getLength() == 5 && aLine.startsWithIgnoreAsciiCase("sep="))
+ cSep = aLine[4];
+ else if (aLine.getLength() == 7 && aLine[6] == '"' && aLine.startsWithIgnoreAsciiCase("\"sep="))
+ cSep = aLine[5];
+
+ // Set Separators in the dialog from maFieldSeparators (empty are not
+ // set) or an optionally defined by file content field separator.
+ SetSeparators(cSep);
+ }
+
+ // Get Separators from the dialog (empty are set from default)
+ maFieldSeparators = GetSeparators();
+
+ mxNfRow->connect_value_changed( LINK( this, ScImportAsciiDlg, FirstRowHdl ) );
+
+ // *** Separator characters ***
+ lcl_FillCombo( *mxCbTextSep, SCSTR_TEXTSEP, mcTextSep );
+ mxCbTextSep->set_entry_text(sTextSeparators);
+ // tdf#69207 - use selected text delimiter to parse the provided data
+ mcTextSep = lcl_CharFromCombo(*mxCbTextSep, SCSTR_TEXTSEP);
+
+ Link<weld::Toggleable&,void> aSeparatorClickHdl =LINK( this, ScImportAsciiDlg, SeparatorClickHdl );
+ mxCbTextSep->connect_changed( LINK( this, ScImportAsciiDlg, SeparatorComboBoxHdl ) );
+ mxCkbTab->connect_toggled( aSeparatorClickHdl );
+ mxCkbSemicolon->connect_toggled( aSeparatorClickHdl );
+ mxCkbComma->connect_toggled( aSeparatorClickHdl );
+ mxCkbAsOnce->connect_toggled( aSeparatorClickHdl );
+ mxCkbQuotedAsText->connect_toggled( aSeparatorClickHdl );
+ mxCkbDetectNumber->connect_toggled( aSeparatorClickHdl );
+ mxCkbEvaluateFormulas->connect_toggled( aSeparatorClickHdl );
+ mxCkbSkipEmptyCells->connect_toggled( aSeparatorClickHdl );
+ mxCkbSpace->connect_toggled( aSeparatorClickHdl );
+ mxCkbRemoveSpace->connect_toggled( aSeparatorClickHdl );
+ mxCkbOther->connect_toggled( aSeparatorClickHdl );
+ mxEdOther->connect_changed(LINK(this, ScImportAsciiDlg, SeparatorEditHdl));
+
+ // *** text encoding ListBox ***
+ // all encodings allowed, including Unicode, but subsets are excluded
+ mxLbCharSet->FillFromTextEncodingTable( true );
+ // Insert one "SYSTEM" entry for compatibility in AsciiOptions and system
+ // independent document linkage.
+ mxLbCharSet->InsertTextEncoding( RTL_TEXTENCODING_DONTKNOW, ScResId( SCSTR_CHARSET_USER ) );
+ if ( ePreselectUnicode == RTL_TEXTENCODING_DONTKNOW )
+ {
+ rtl_TextEncoding eSystemEncoding = osl_getThreadTextEncoding();
+ // Prefer UTF-8, as UTF-16 would have already been detected from the stream.
+ // This gives a better chance that the file is going to be opened correctly.
+ if ( ( eSystemEncoding == RTL_TEXTENCODING_UNICODE ) && mpDatStream )
+ eSystemEncoding = RTL_TEXTENCODING_UTF8;
+ mxLbCharSet->SelectTextEncoding( eSystemEncoding );
+ }
+ else
+ {
+ mxLbCharSet->SelectTextEncoding( ePreselectUnicode );
+ }
+
+ if (nCharSet >= 0 && ePreselectUnicode == RTL_TEXTENCODING_DONTKNOW)
+ mxLbCharSet->set_active(nCharSet);
+
+ SetSelectedCharSet();
+ mxLbCharSet->connect_changed( LINK( this, ScImportAsciiDlg, CharSetHdl ) );
+
+ mxLbCustomLang->SetLanguageList(
+ SvxLanguageListFlags::ALL | SvxLanguageListFlags::ONLY_KNOWN, false, false);
+ mxLbCustomLang->InsertLanguage(LANGUAGE_SYSTEM);
+ mxLbCustomLang->set_active_id(static_cast<LanguageType>(nLanguage));
+
+ // *** column type ListBox ***
+ OUString aColumnUser( ScResId( SCSTR_COLUMN_USER ) );
+ for (sal_Int32 nIdx {0}; nIdx>=0; )
+ {
+ mxLbType->append_text(aColumnUser.getToken(0, ';', nIdx));
+ }
+
+ mxLbType->connect_changed( LINK( this, ScImportAsciiDlg, LbColTypeHdl ) );
+ mxFtType->set_sensitive(false);
+ mxLbType->set_sensitive(false);
+
+ // *** table box preview ***
+ mxTableBox->Init();
+ mxTableBox->SetUpdateTextHdl( LINK( this, ScImportAsciiDlg, UpdateTextHdl ) );
+ mxTableBox->InitTypes( *mxLbType );
+ mxTableBox->SetColTypeHdl( LINK( this, ScImportAsciiDlg, ColTypeHdl ) );
+
+ mxRbSeparated->connect_toggled( LINK( this, ScImportAsciiDlg, RbSepFixHdl ) );
+ mxRbFixed->connect_toggled( LINK( this, ScImportAsciiDlg, RbSepFixHdl ) );
+
+ SetupSeparatorCtrls();
+ RbSepFix();
+
+ UpdateVertical();
+
+ mxTableBox->GetGrid().Execute( CSVCMD_NEWCELLTEXTS );
+
+ if (meCall == SC_TEXTTOCOLUMNS)
+ {
+ mxFtCharSet->set_sensitive(false);
+ mxLbCharSet->set_sensitive(false);
+ mxFtCustomLang->set_sensitive(false);
+ mxLbCustomLang->set_active_id(LANGUAGE_SYSTEM);
+ mxLbCustomLang->set_sensitive(false);
+ mxFtRow->set_sensitive(false);
+ mxNfRow->set_sensitive(false);
+
+ // Quoted field as text option is not used for text-to-columns mode.
+ mxCkbQuotedAsText->set_active(false);
+ mxCkbQuotedAsText->set_sensitive(false);
+
+ // Always detect special numbers for text-to-columns mode.
+ mxCkbDetectNumber->set_active(true);
+ mxCkbDetectNumber->set_sensitive(false);
+ }
+ if (meCall == SC_IMPORTFILE)
+ {
+ //Empty cells in imported file are empty
+ mxCkbSkipEmptyCells->set_active(false);
+ mxCkbSkipEmptyCells->hide();
+ }
+ m_xDialog->SetInstallLOKNotifierHdl(LINK(this, ScImportAsciiDlg, InstallLOKNotifierHdl));
+}
+
+IMPL_STATIC_LINK_NOARG(ScImportAsciiDlg, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*)
+{
+ return GetpApp();
+}
+
+ScImportAsciiDlg::~ScImportAsciiDlg()
+{
+}
+
+bool ScImportAsciiDlg::GetLine( sal_uLong nLine, OUString &rText, sal_Unicode& rcDetectSep )
+{
+ if (nLine >= ASCIIDLG_MAXROWS || !mpDatStream)
+ return false;
+
+ bool bRet = true;
+ bool bFixed = mxRbFixed->get_active();
+
+ if (!mpRowPosArray)
+ mpRowPosArray.reset( new sal_uLong[ASCIIDLG_MAXROWS + 2] );
+
+ if (!mnRowPosCount) // complete re-fresh
+ {
+ memset( mpRowPosArray.get(), 0, sizeof(mpRowPosArray[0]) * (ASCIIDLG_MAXROWS+2));
+
+ Seek(0);
+ mpDatStream->StartReadingUnicodeText( mpDatStream->GetStreamCharSet() );
+
+ mnStreamPos = mpDatStream->Tell();
+ mpRowPosArray[mnRowPosCount] = mnStreamPos;
+ }
+
+ if (nLine >= mnRowPosCount)
+ {
+ // need to work out some more line information
+ do
+ {
+ if (!Seek(mpRowPosArray[mnRowPosCount]) || !mpDatStream->good())
+ {
+ bRet = false;
+ break;
+ }
+ rText = ReadCsvLine(*mpDatStream, !bFixed, maFieldSeparators,
+ mcTextSep, rcDetectSep, kMaxEmbeddedLinefeeds);
+ mnStreamPos = mpDatStream->Tell();
+ mpRowPosArray[++mnRowPosCount] = mnStreamPos;
+ } while (nLine >= mnRowPosCount && mpDatStream->good());
+ if (mpDatStream->eof() &&
+ mnStreamPos == mpRowPosArray[mnRowPosCount-1])
+ {
+ // the very end, not even an empty line read
+ bRet = false;
+ --mnRowPosCount;
+ }
+ }
+ else
+ {
+ Seek( mpRowPosArray[nLine]);
+ rText = ReadCsvLine(*mpDatStream, !bFixed, maFieldSeparators, mcTextSep, rcDetectSep, kMaxEmbeddedLinefeeds);
+ mnStreamPos = mpDatStream->Tell();
+ }
+
+ // If the file content isn't unicode, ReadUniStringLine
+ // may try to seek beyond the file's end and cause a CANTSEEK error
+ // (depending on the stream type). The error code has to be cleared,
+ // or further read operations (including non-unicode) will fail.
+ if ( mpDatStream->GetError() == ERRCODE_IO_CANTSEEK )
+ mpDatStream->ResetError();
+
+ ScImportExport::EmbeddedNullTreatment( rText);
+
+ return bRet;
+}
+
+void ScImportAsciiDlg::GetOptions( ScAsciiOptions& rOpt )
+{
+ rOpt.SetCharSet( meCharSet );
+ rOpt.SetCharSetSystem( mbCharSetSystem );
+ rOpt.SetLanguage(mxLbCustomLang->get_active_id());
+ rOpt.SetFixedLen( mxRbFixed->get_active() );
+ rOpt.SetStartRow( mxNfRow->get_value() );
+ mxTableBox->FillColumnData( rOpt );
+ if( mxRbSeparated->get_active() )
+ {
+ rOpt.SetFieldSeps( GetSeparators() );
+ rOpt.SetMergeSeps( mxCkbAsOnce->get_active() );
+ rOpt.SetRemoveSpace( mxCkbRemoveSpace->get_active() );
+ rOpt.SetTextSep( lcl_CharFromCombo( *mxCbTextSep, SCSTR_TEXTSEP ) );
+ }
+
+ rOpt.SetQuotedAsText(mxCkbQuotedAsText->get_active());
+ rOpt.SetDetectSpecialNumber(mxCkbDetectNumber->get_active());
+ rOpt.SetEvaluateFormulas(mxCkbEvaluateFormulas->get_active());
+ rOpt.SetSkipEmptyCells(mxCkbSkipEmptyCells->get_active());
+}
+
+void ScImportAsciiDlg::SaveParameters()
+{
+ lcl_SaveSeparators( maFieldSeparators, mxCbTextSep->get_active_text(), mxCkbAsOnce->get_active(),
+ mxCkbQuotedAsText->get_active(), mxCkbDetectNumber->get_active(),
+ mxRbFixed->get_active(),
+ mxNfRow->get_value(),
+ mxLbCharSet->get_active(),
+ static_cast<sal_uInt16>(mxLbCustomLang->get_active_id()),
+ mxCkbSkipEmptyCells->get_active(), mxCkbRemoveSpace->get_active(),
+ mxCkbEvaluateFormulas->get_active(), meCall );
+}
+
+void ScImportAsciiDlg::SetSeparators( sal_Unicode cSep )
+{
+ if (cSep)
+ {
+ // Exclusively set a separator, maFieldSeparators needs not be
+ // modified, it's obtained by GetSeparators() after this call.
+ constexpr sal_Unicode aSeps[] = { '\t', ';', ',', ' ' };
+ for (const sal_Unicode c : aSeps)
+ {
+ const bool bSet = (c == cSep);
+ switch (c)
+ {
+ case '\t': mxCkbTab->set_active(bSet); break;
+ case ';': mxCkbSemicolon->set_active(bSet); break;
+ case ',': mxCkbComma->set_active(bSet); break;
+ case ' ': mxCkbSpace->set_active(bSet); break;
+ }
+ if (bSet)
+ cSep = 0;
+ }
+ if (cSep)
+ {
+ mxCkbOther->set_active(true);
+ mxEdOther->set_text(OUStringChar(cSep));
+ }
+ }
+ else
+ {
+ for (sal_Int32 i = 0; i < maFieldSeparators.getLength(); ++i)
+ {
+ switch (maFieldSeparators[i])
+ {
+ case '\t': mxCkbTab->set_active(true); break;
+ case ';': mxCkbSemicolon->set_active(true); break;
+ case ',': mxCkbComma->set_active(true); break;
+ case ' ': mxCkbSpace->set_active(true); break;
+ default:
+ mxCkbOther->set_active(true);
+ mxEdOther->set_text(mxEdOther->get_text() + OUStringChar(maFieldSeparators[i]));
+ }
+ }
+ }
+}
+
+void ScImportAsciiDlg::SetSelectedCharSet()
+{
+ meCharSet = mxLbCharSet->GetSelectTextEncoding();
+ mbCharSetSystem = (meCharSet == RTL_TEXTENCODING_DONTKNOW);
+ if( mbCharSetSystem )
+ meCharSet = osl_getThreadTextEncoding();
+}
+
+OUString ScImportAsciiDlg::GetSeparators() const
+{
+ OUString aSepChars;
+ if( mxCkbTab->get_active() )
+ aSepChars += "\t";
+ if( mxCkbSemicolon->get_active() )
+ aSepChars += ";";
+ if( mxCkbComma->get_active() )
+ aSepChars += ",";
+ if( mxCkbSpace->get_active() )
+ aSepChars += " ";
+ if( mxCkbOther->get_active() )
+ aSepChars += mxEdOther->get_text();
+ return aSepChars;
+}
+
+void ScImportAsciiDlg::SetupSeparatorCtrls()
+{
+ bool bEnable = mxRbSeparated->get_active();
+ mxCkbTab->set_sensitive( bEnable );
+ mxCkbSemicolon->set_sensitive( bEnable );
+ mxCkbComma->set_sensitive( bEnable );
+ mxCkbSpace->set_sensitive( bEnable );
+ mxCkbRemoveSpace->set_sensitive( bEnable );
+ mxCkbOther->set_sensitive( bEnable );
+ mxEdOther->set_sensitive( bEnable );
+ mxCkbAsOnce->set_sensitive( bEnable );
+ mxFtTextSep->set_sensitive( bEnable );
+ mxCbTextSep->set_sensitive( bEnable );
+}
+
+void ScImportAsciiDlg::UpdateVertical()
+{
+ mnRowPosCount = 0;
+ if (mpDatStream)
+ mpDatStream->SetStreamCharSet(meCharSet);
+}
+
+void ScImportAsciiDlg::RbSepFix()
+{
+ weld::WaitObject aWaitObj(m_xDialog.get());
+ if( mxRbFixed->get_active() )
+ mxTableBox->SetFixedWidthMode();
+ else
+ mxTableBox->SetSeparatorsMode();
+ SetupSeparatorCtrls();
+}
+
+IMPL_LINK(ScImportAsciiDlg, RbSepFixHdl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+ RbSepFix();
+}
+
+IMPL_LINK(ScImportAsciiDlg, SeparatorClickHdl, weld::Toggleable&, rCtrl, void)
+{
+ SeparatorHdl(&rCtrl);
+}
+
+IMPL_LINK( ScImportAsciiDlg, SeparatorComboBoxHdl, weld::ComboBox&, rCtrl, void )
+{
+ SeparatorHdl(&rCtrl);
+}
+
+IMPL_LINK( ScImportAsciiDlg, SeparatorEditHdl, weld::Entry&, rEdit, void )
+{
+ SeparatorHdl(&rEdit);
+}
+
+void ScImportAsciiDlg::SeparatorHdl(const weld::Widget* pCtrl)
+{
+ OSL_ENSURE( pCtrl, "ScImportAsciiDlg::SeparatorHdl - missing sender" );
+ OSL_ENSURE( !mxRbFixed->get_active(), "ScImportAsciiDlg::SeparatorHdl - not allowed in fixed width" );
+
+ /* #i41550# First update state of the controls. The GetSeparators()
+ function needs final state of the check boxes. */
+ if (pCtrl == mxCkbOther.get() && mxCkbOther->get_active())
+ mxEdOther->grab_focus();
+ else if (pCtrl == mxEdOther.get())
+ mxCkbOther->set_active(!mxEdOther->get_text().isEmpty());
+
+ OUString aOldFldSeps( maFieldSeparators);
+ maFieldSeparators = GetSeparators();
+ sal_Unicode cOldSep = mcTextSep;
+ mcTextSep = lcl_CharFromCombo( *mxCbTextSep, SCSTR_TEXTSEP );
+ // Any separator changed may result in completely different lines due to
+ // embedded line breaks.
+ if (cOldSep != mcTextSep || aOldFldSeps != maFieldSeparators)
+ UpdateVertical();
+
+ mxTableBox->GetGrid().Execute( CSVCMD_NEWCELLTEXTS );
+}
+
+IMPL_LINK_NOARG(ScImportAsciiDlg, CharSetHdl, weld::ComboBox&, void)
+{
+ if (mxLbCharSet->get_active() != -1)
+ {
+ weld::WaitObject aWaitObj(m_xDialog.get());
+ rtl_TextEncoding eOldCharSet = meCharSet;
+ SetSelectedCharSet();
+ // switching char-set invalidates 8bit -> String conversions
+ if (eOldCharSet != meCharSet)
+ UpdateVertical();
+
+ mxTableBox->GetGrid().Execute( CSVCMD_NEWCELLTEXTS );
+ }
+}
+
+IMPL_LINK(ScImportAsciiDlg, FirstRowHdl, weld::SpinButton&, rNumField, void)
+{
+ mxTableBox->GetGrid().Execute( CSVCMD_SETFIRSTIMPORTLINE, rNumField.get_value() - 1);
+}
+
+IMPL_LINK(ScImportAsciiDlg, LbColTypeHdl, weld::ComboBox&, rListBox, void)
+{
+ if (&rListBox == mxLbType.get())
+ mxTableBox->GetGrid().Execute(CSVCMD_SETCOLUMNTYPE, rListBox.get_active());
+}
+
+IMPL_LINK_NOARG(ScImportAsciiDlg, UpdateTextHdl, ScCsvTableBox&, void)
+{
+ // Checking the separator can only be done once for the very first time
+ // when the dialog wasn't already presented to the user.
+ // As a side effect this has the benefit that the check is only done on the
+ // first set of visible lines.
+ mbDetectSep = (mbDetectSep && !mxRbFixed->get_active()
+ && (!mxCkbTab->get_active() || !mxCkbSemicolon->get_active()
+ || !mxCkbComma->get_active() || !mxCkbSpace->get_active()));
+ sal_Unicode cDetectSep = (mbDetectSep ? 0 : 0xffff);
+
+ sal_Int32 nBaseLine = mxTableBox->GetGrid().GetFirstVisLine();
+ sal_Int32 nRead = mxTableBox->GetGrid().GetVisLineCount();
+ // If mnRowPosCount==0, this is an initializing call, read ahead for row
+ // count and resulting scroll bar size and position to be able to scroll at
+ // all. When adding lines, read only the amount of next lines to be
+ // displayed.
+ if (!mnRowPosCount || nRead > CSV_PREVIEW_LINES)
+ nRead = CSV_PREVIEW_LINES;
+
+ sal_Int32 i;
+ for (i = 0; i < nRead; i++)
+ {
+ if (!GetLine( nBaseLine + i, maPreviewLine[i], cDetectSep))
+ break;
+ }
+ for (; i < CSV_PREVIEW_LINES; i++)
+ maPreviewLine[i].clear();
+
+ if (mbDetectSep)
+ {
+ mbDetectSep = false;
+ if (cDetectSep)
+ {
+ // Expect separator to be appended by now so all subsequent
+ // GetLine()/ReadCsvLine() actually used it.
+ assert(maFieldSeparators.endsWith(OUStringChar(cDetectSep)));
+ // Preselect separator in UI.
+ switch (cDetectSep)
+ {
+ case '\t': mxCkbTab->set_active(true); break;
+ case ';': mxCkbSemicolon->set_active(true); break;
+ case ',': mxCkbComma->set_active(true); break;
+ case ' ': mxCkbSpace->set_active(true); break;
+ }
+ }
+ }
+
+ mxTableBox->GetGrid().Execute( CSVCMD_SETLINECOUNT, mnRowPosCount);
+ bool bMergeSep = mxCkbAsOnce->get_active();
+ bool bRemoveSpace = mxCkbRemoveSpace->get_active();
+ mxTableBox->SetUniStrings( maPreviewLine, maFieldSeparators, mcTextSep, bMergeSep, bRemoveSpace );
+}
+
+IMPL_LINK( ScImportAsciiDlg, ColTypeHdl, ScCsvTableBox&, rTableBox, void )
+{
+ sal_Int32 nType = rTableBox.GetSelColumnType();
+ sal_Int32 nTypeCount = mxLbType->get_count();
+ bool bEmpty = (nType == CSV_TYPE_MULTI);
+ bool bEnable = ((0 <= nType) && (nType < nTypeCount)) || bEmpty;
+
+ mxFtType->set_sensitive( bEnable );
+ mxLbType->set_sensitive( bEnable );
+
+ if (bEmpty)
+ mxLbType->set_active(-1);
+ else if (bEnable)
+ mxLbType->set_active(nType);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/scuiimoptdlg.cxx b/sc/source/ui/dbgui/scuiimoptdlg.cxx
new file mode 100644
index 000000000..e04f0b672
--- /dev/null
+++ b/sc/source/ui/dbgui/scuiimoptdlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <scuiimoptdlg.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <officecfg/Office/Calc.hxx>
+#include <osl/thread.h>
+#include <rtl/tencinfo.h>
+#include <imoptdlg.hxx>
+#include <svx/txencbox.hxx>
+#include <o3tl/string_view.hxx>
+
+// ScDelimiterTable
+
+class ScDelimiterTable
+{
+public:
+ explicit ScDelimiterTable( const OUString& rDelTab )
+ : theDelTab ( rDelTab ),
+ nDelIdx ( 0 )
+ {}
+
+ sal_uInt16 GetCode( std::u16string_view rDelimiter ) const;
+ OUString GetDelimiter( sal_Unicode nCode ) const;
+
+ OUString FirstDel() { nDelIdx = 0; return theDelTab.getToken( 0, cSep, nDelIdx ); }
+ OUString NextDel() { return theDelTab.getToken( 1, cSep, nDelIdx ); }
+
+private:
+ const OUString theDelTab;
+ static constexpr sal_Unicode cSep {'\t'};
+ sal_Int32 nDelIdx;
+};
+
+sal_uInt16 ScDelimiterTable::GetCode( std::u16string_view rDel ) const
+{
+ if (!theDelTab.isEmpty())
+ {
+ sal_Int32 nIdx {0};
+
+ // Check even tokens: start from 0 and then skip 1 token at each iteration
+ if (rDel != o3tl::getToken(theDelTab, 0, cSep, nIdx ))
+ while (nIdx>0 && rDel != o3tl::getToken(theDelTab, 1, cSep, nIdx ));
+
+ if (nIdx>0)
+ return static_cast<sal_Unicode>(o3tl::toInt32(o3tl::getToken(theDelTab, 0, cSep, nIdx )));
+ }
+
+ return 0;
+}
+
+OUString ScDelimiterTable::GetDelimiter( sal_Unicode nCode ) const
+{
+ if (!theDelTab.isEmpty())
+ {
+ sal_Int32 nIdx {0};
+ // Check odd tokens: start from 1 and then skip 1 token at each iteration
+ do
+ {
+ sal_Int32 nPrevIdx {nIdx};
+ if (nCode == static_cast<sal_Unicode>(o3tl::toInt32(o3tl::getToken(theDelTab, 1, cSep, nIdx ))))
+ return theDelTab.getToken( 0, cSep, nPrevIdx );
+ }
+ while (nIdx>0);
+ }
+
+ return OUString();
+}
+
+void ScImportOptionsDlg::FillFromTextEncodingTable(bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags)
+{
+ if (m_bIsAsciiImport)
+ m_xLbCharset->FillFromTextEncodingTable(bExcludeImportSubsets, nExcludeInfoFlags);
+ else
+ m_xTvCharset->FillFromTextEncodingTable(bExcludeImportSubsets, nExcludeInfoFlags);
+}
+
+void ScImportOptionsDlg::FillFromDbTextEncodingMap(bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags)
+{
+ if (m_bIsAsciiImport)
+ m_xLbCharset->FillFromDbTextEncodingMap(bExcludeImportSubsets, nExcludeInfoFlags);
+ else
+ m_xTvCharset->FillFromDbTextEncodingMap(bExcludeImportSubsets, nExcludeInfoFlags);
+}
+
+// ScImportOptionsDlg
+ScImportOptionsDlg::ScImportOptionsDlg(weld::Window* pParent, bool bAscii,
+ const ScImportOptions* pOptions,
+ const OUString* pStrTitle,
+ bool bMultiByte, bool bOnlyDbtoolsEncodings,
+ bool bImport)
+ : GenericDialogController(pParent, "modules/scalc/ui/imoptdialog.ui", "ImOptDialog")
+ , m_bIsAsciiImport(bAscii)
+ , m_xFieldFrame(m_xBuilder->weld_frame("fieldframe"))
+ , m_xFtCharset(m_xBuilder->weld_label("charsetft"))
+ , m_xEncGrid(m_xBuilder->weld_widget("grid2"))
+ , m_xFtFieldSep(m_xBuilder->weld_label("fieldft"))
+ , m_xEdFieldSep(m_xBuilder->weld_combo_box("field"))
+ , m_xFtTextSep(m_xBuilder->weld_label("textft"))
+ , m_xEdTextSep(m_xBuilder->weld_combo_box("text"))
+ , m_xCbShown(m_xBuilder->weld_check_button("asshown"))
+ , m_xCbFormulas(m_xBuilder->weld_check_button("formulas"))
+ , m_xCbQuoteAll(m_xBuilder->weld_check_button("quoteall"))
+ , m_xCbFixed(m_xBuilder->weld_check_button("fixedwidth"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xLbCharset(new SvxTextEncodingBox(m_xBuilder->weld_combo_box("charsetdropdown")))
+ , m_xTvCharset(new SvxTextEncodingTreeView(m_xBuilder->weld_tree_view("charsetlist")))
+{
+ if (bAscii)
+ {
+ m_xDialog->set_help_id(m_xDialog->get_help_id() + "?config=NonTextImport");
+ m_xLbCharset->show();
+ m_xTvCharset->hide();
+ }
+ else
+ {
+ m_xTvCharset->set_size_request(-1, m_xTvCharset->get_height_rows(6));
+ m_xEncGrid->set_vexpand(true);
+ m_xLbCharset->hide();
+ m_xTvCharset->show();
+ }
+
+ OUString sFieldSep(SCSTR_FIELDSEP);
+ sFieldSep = sFieldSep.replaceFirst( "%TAB", ScResId(SCSTR_FIELDSEP_TAB) );
+ sFieldSep = sFieldSep.replaceFirst( "%SPACE", ScResId(SCSTR_FIELDSEP_SPACE) );
+
+ // not possible in the Ctor initializer (MSC cannot do that):
+ pFieldSepTab.reset( new ScDelimiterTable(sFieldSep) );
+ pTextSepTab.reset( new ScDelimiterTable(SCSTR_TEXTSEP) );
+
+ OUString aStr = pFieldSepTab->FirstDel();
+
+ while (!aStr.isEmpty())
+ {
+ m_xEdFieldSep->append_text(aStr);
+ aStr = pFieldSepTab->NextDel();
+ }
+
+ aStr = pTextSepTab->FirstDel();
+
+ while (!aStr.isEmpty())
+ {
+ m_xEdTextSep->append_text(aStr);
+ aStr = pTextSepTab->NextDel();
+ }
+
+ m_xEdFieldSep->set_active(0);
+ m_xEdTextSep->set_active(0);
+
+ if ( bOnlyDbtoolsEncodings )
+ {
+ // Even dBase export allows multibyte now
+ if ( bMultiByte )
+ FillFromDbTextEncodingMap( bImport );
+ else
+ FillFromDbTextEncodingMap( bImport, RTL_TEXTENCODING_INFO_MULTIBYTE );
+ }
+ else if ( !bAscii )
+ { //!TODO: Unicode would need work in each filter
+ if ( bMultiByte )
+ FillFromTextEncodingTable( bImport, RTL_TEXTENCODING_INFO_UNICODE );
+ else
+ FillFromTextEncodingTable( bImport, RTL_TEXTENCODING_INFO_UNICODE |
+ RTL_TEXTENCODING_INFO_MULTIBYTE );
+ }
+ else
+ {
+ if ( pOptions )
+ {
+ sal_Unicode nCode = pOptions->nFieldSepCode;
+ aStr = pFieldSepTab->GetDelimiter( nCode );
+
+ if ( aStr.isEmpty() )
+ m_xEdFieldSep->set_entry_text(OUString(nCode));
+ else
+ m_xEdFieldSep->set_entry_text(aStr);
+
+ nCode = pOptions->nTextSepCode;
+ aStr = pTextSepTab->GetDelimiter( nCode );
+
+ if ( aStr.isEmpty() )
+ m_xEdTextSep->set_entry_text(OUString(nCode));
+ else
+ m_xEdTextSep->set_entry_text(aStr);
+ }
+ // all encodings allowed, even Unicode
+ FillFromTextEncodingTable( bImport );
+ }
+
+ if( bAscii )
+ {
+ sal_Int32 nCharSet = officecfg::Office::Calc::Dialogs::CSVExport::CharSet::get();
+ OUString strFieldSeparator = officecfg::Office::Calc::Dialogs::CSVExport::FieldSeparator::get();
+ OUString strTextSeparator = officecfg::Office::Calc::Dialogs::CSVExport::TextSeparator::get();
+ bool bSaveTrueCellContent = officecfg::Office::Calc::Dialogs::CSVExport::SaveTrueCellContent::get();
+ bool bSaveCellFormulas = officecfg::Office::Calc::Dialogs::CSVExport::SaveCellFormulas::get();
+ bool bQuoteAllTextCells = officecfg::Office::Calc::Dialogs::CSVExport::QuoteAllTextCells::get();
+ bool bFixedWidth = officecfg::Office::Calc::Dialogs::CSVExport::FixedWidth::get();
+
+ m_xCbFixed->show();
+ m_xCbFixed->connect_toggled(LINK(this, ScImportOptionsDlg, FixedWidthHdl));
+ m_xCbFixed->set_active( bFixedWidth );
+ FixedWidthHdl(*m_xCbFixed);
+ m_xCbShown->show();
+ m_xCbShown->set_active( bSaveTrueCellContent );
+ m_xCbQuoteAll->show();
+ m_xCbQuoteAll->set_active( bQuoteAllTextCells );
+ m_xCbFormulas->show();
+ // default option for "save formulas" no longer taken from view shell but from persisted dialog settings
+ m_xCbFormulas->set_active( bSaveCellFormulas );
+ // if no charset, text separator or field separator exist, keep the values from dialog initialization
+ if (strFieldSeparator.getLength() > 0)
+ m_xEdFieldSep->set_entry_text(strFieldSeparator);
+ if (strTextSeparator.getLength() > 0)
+ m_xEdTextSep->set_entry_text(strTextSeparator);
+ if (nCharSet < 0 || nCharSet == RTL_TEXTENCODING_DONTKNOW )
+ m_xLbCharset->SelectTextEncoding(pOptions ? pOptions->eCharSet : osl_getThreadTextEncoding());
+ else
+ m_xLbCharset->SelectTextEncoding(nCharSet);
+ }
+ else
+ {
+ m_xFieldFrame->set_label(m_xFtCharset->get_label());
+ m_xFtFieldSep->hide();
+ m_xFtTextSep->hide();
+ m_xFtCharset->hide();
+ m_xEdFieldSep->hide();
+ m_xEdTextSep->hide();
+ m_xCbFixed->hide();
+ m_xCbShown->hide();
+ m_xCbQuoteAll->hide();
+ m_xCbFormulas->hide();
+ m_xTvCharset->grab_focus();
+ m_xTvCharset->connect_row_activated(LINK(this, ScImportOptionsDlg, DoubleClickHdl));
+ m_xTvCharset->SelectTextEncoding(pOptions ? pOptions->eCharSet : osl_getThreadTextEncoding());
+ }
+
+ // optional title:
+ if (pStrTitle)
+ m_xDialog->set_title(*pStrTitle);
+}
+
+ScImportOptionsDlg::~ScImportOptionsDlg()
+{
+}
+
+void ScImportOptionsDlg::GetImportOptions( ScImportOptions& rOptions ) const
+{
+ auto nEncoding = m_bIsAsciiImport ? m_xLbCharset->GetSelectTextEncoding() : m_xTvCharset->GetSelectTextEncoding();
+ rOptions.SetTextEncoding(nEncoding);
+
+ if (m_xCbFixed->get_visible())
+ {
+ rOptions.nFieldSepCode = GetCodeFromCombo( *m_xEdFieldSep );
+ rOptions.nTextSepCode = GetCodeFromCombo( *m_xEdTextSep );
+ rOptions.bFixedWidth = m_xCbFixed->get_active();
+ rOptions.bSaveAsShown = m_xCbShown->get_active();
+ rOptions.bQuoteAllText = m_xCbQuoteAll->get_active();
+ rOptions.bSaveFormulas = m_xCbFormulas->get_active();
+ }
+}
+
+sal_uInt16 ScImportOptionsDlg::GetCodeFromCombo(const weld::ComboBox& rEd) const
+{
+ ScDelimiterTable* pTab;
+ OUString aStr( rEd.get_active_text() );
+ sal_uInt16 nCode;
+
+ if (&rEd == m_xEdTextSep.get())
+ pTab = pTextSepTab.get();
+ else
+ pTab = pFieldSepTab.get();
+
+ if ( aStr.isEmpty() )
+ {
+ nCode = 0; // no separator
+ }
+ else
+ {
+ nCode = pTab->GetCode( aStr );
+
+ if ( nCode == 0 )
+ nCode = static_cast<sal_uInt16>(aStr[0]);
+ }
+
+ return nCode;
+}
+
+IMPL_LINK_NOARG(ScImportOptionsDlg, FixedWidthHdl, weld::Toggleable&, void)
+{
+ bool bEnable = !m_xCbFixed->get_active();
+ m_xFtFieldSep->set_sensitive( bEnable );
+ m_xEdFieldSep->set_sensitive( bEnable );
+ m_xFtTextSep->set_sensitive( bEnable );
+ m_xEdTextSep->set_sensitive( bEnable );
+ m_xCbShown->set_sensitive( bEnable );
+ m_xCbQuoteAll->set_sensitive( bEnable );
+}
+
+IMPL_LINK_NOARG(ScImportOptionsDlg, DoubleClickHdl, weld::TreeView&, bool)
+{
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+void ScImportOptionsDlg::SaveImportOptions() const
+{
+ std::shared_ptr < comphelper::ConfigurationChanges > batch(comphelper::ConfigurationChanges::create());
+ auto nEncoding = m_bIsAsciiImport ? m_xLbCharset->GetSelectTextEncoding() : m_xTvCharset->GetSelectTextEncoding();
+ officecfg::Office::Calc::Dialogs::CSVExport::CharSet::set(nEncoding, batch);
+ officecfg::Office::Calc::Dialogs::CSVExport::FieldSeparator::set(m_xEdFieldSep->get_active_text(), batch);
+ officecfg::Office::Calc::Dialogs::CSVExport::TextSeparator::set(m_xEdTextSep->get_active_text(), batch);
+ officecfg::Office::Calc::Dialogs::CSVExport::FixedWidth::set(m_xCbFixed->get_active(), batch);
+ officecfg::Office::Calc::Dialogs::CSVExport::SaveCellFormulas::set(m_xCbFormulas->get_active(), batch);
+ officecfg::Office::Calc::Dialogs::CSVExport::SaveTrueCellContent::set(m_xCbShown->get_active(), batch);
+ officecfg::Office::Calc::Dialogs::CSVExport::QuoteAllTextCells::set(m_xCbQuoteAll->get_active(), batch);
+ batch->commit();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/sfiltdlg.cxx b/sc/source/ui/dbgui/sfiltdlg.cxx
new file mode 100644
index 000000000..3aeb31923
--- /dev/null
+++ b/sc/source/ui/dbgui/sfiltdlg.cxx
@@ -0,0 +1,435 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <uiitems.hxx>
+#include <rangenam.hxx>
+#include <reffact.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <scresid.hxx>
+
+#include <foptmgr.hxx>
+
+#include <globstr.hrc>
+#include <strings.hrc>
+
+#include <filtdlg.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+// DEFINE --------------------------------------------------------------------
+
+namespace
+{
+ void ERRORBOX(weld::Window* pParent, TranslateId rid)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(rid)));
+ xBox->run();
+ }
+}
+
+
+ScSpecialFilterDlg::ScSpecialFilterDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ const SfxItemSet& rArgSet )
+
+ : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/advancedfilterdialog.ui", "AdvancedFilterDialog")
+ , aStrUndefined ( ScResId(SCSTR_UNDEFINED) )
+ , nWhichQuery ( rArgSet.GetPool()->GetWhich( SID_QUERY ) )
+ , theQueryData ( static_cast<const ScQueryItem&>(
+ rArgSet.Get( nWhichQuery )).GetQueryData() )
+ , pViewData(nullptr)
+ , pDoc(nullptr)
+ , bRefInputMode(false)
+ , m_pRefInputEdit(nullptr)
+ , m_xLbFilterArea(m_xBuilder->weld_combo_box("lbfilterarea"))
+ , m_xEdFilterArea(new formula::RefEdit(m_xBuilder->weld_entry("edfilterarea")))
+ , m_xRbFilterArea(new formula::RefButton(m_xBuilder->weld_button("rbfilterarea")))
+ , m_xExpander(m_xBuilder->weld_expander("more"))
+ , m_xBtnCase(m_xBuilder->weld_check_button("case"))
+ , m_xBtnRegExp(m_xBuilder->weld_check_button("regexp"))
+ , m_xBtnHeader(m_xBuilder->weld_check_button("header"))
+ , m_xBtnUnique(m_xBuilder->weld_check_button("unique"))
+ , m_xBtnCopyResult(m_xBuilder->weld_check_button("copyresult"))
+ , m_xLbCopyArea(m_xBuilder->weld_combo_box("lbcopyarea"))
+ , m_xEdCopyArea(new formula::RefEdit(m_xBuilder->weld_entry("edcopyarea")))
+ , m_xRbCopyArea(new formula::RefButton(m_xBuilder->weld_button("rbcopyarea")))
+ , m_xBtnDestPers(m_xBuilder->weld_check_button("destpers"))
+ , m_xFtDbAreaLabel(m_xBuilder->weld_label("dbarealabel"))
+ , m_xFtDbArea(m_xBuilder->weld_label("dbarea"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_xFilterFrame(m_xBuilder->weld_frame("filterframe"))
+ , m_xFilterLabel(m_xFilterFrame->weld_label_widget())
+{
+ m_xEdFilterArea->SetReferences(this, m_xFilterLabel.get());
+ m_xRbFilterArea->SetReferences(this, m_xEdFilterArea.get());
+ m_xEdCopyArea->SetReferences(this, m_xFtDbAreaLabel.get());
+ m_xRbCopyArea->SetReferences(this, m_xEdCopyArea.get());
+
+ Init( rArgSet );
+
+ Link<formula::RefEdit&, void> aLinkEdit = LINK(this, ScSpecialFilterDlg, RefInputEditHdl);
+ Link<formula::RefButton&, void> aLinkButton = LINK(this, ScSpecialFilterDlg, RefInputButtonHdl);
+ m_xEdCopyArea->SetGetFocusHdl(aLinkEdit);
+ m_xRbCopyArea->SetGetFocusHdl(aLinkButton);
+ m_xEdFilterArea->SetGetFocusHdl(aLinkEdit);
+ m_xRbFilterArea->SetGetFocusHdl(aLinkButton);
+ m_xEdCopyArea->SetLoseFocusHdl(aLinkEdit);
+ m_xRbCopyArea->SetLoseFocusHdl(aLinkButton);
+ m_xEdFilterArea->SetLoseFocusHdl(aLinkEdit);
+ m_xRbFilterArea->SetLoseFocusHdl(aLinkButton);
+
+ m_xEdFilterArea->GrabFocus();
+}
+
+ScSpecialFilterDlg::~ScSpecialFilterDlg()
+{
+ pOptionsMgr.reset();
+
+ pOutItem.reset();
+}
+
+void ScSpecialFilterDlg::Init( const SfxItemSet& rArgSet )
+{
+ const ScQueryItem& rQueryItem = static_cast<const ScQueryItem&>(
+ rArgSet.Get( nWhichQuery ));
+
+ m_xBtnOk->connect_clicked( LINK( this, ScSpecialFilterDlg, EndDlgHdl ) );
+ m_xBtnCancel->connect_clicked( LINK( this, ScSpecialFilterDlg, EndDlgHdl ) );
+ m_xLbFilterArea->connect_changed( LINK( this, ScSpecialFilterDlg, FilterAreaSelHdl ) );
+ m_xEdFilterArea->SetModifyHdl ( LINK( this, ScSpecialFilterDlg, FilterAreaModHdl ) );
+
+ pViewData = rQueryItem.GetViewData();
+ pDoc = pViewData ? &pViewData->GetDocument() : nullptr;
+
+ m_xEdFilterArea->SetText( OUString() ); // may be overwritten below
+
+ if ( pViewData && pDoc )
+ {
+ if(pDoc->GetChangeTrack()!=nullptr) m_xBtnCopyResult->set_sensitive(false);
+
+ ScRangeName* pRangeNames = pDoc->GetRangeName();
+ m_xLbFilterArea->clear();
+ m_xLbFilterArea->append_text(aStrUndefined);
+
+ for (const auto& rEntry : *pRangeNames)
+ {
+ if (!rEntry.second->HasType(ScRangeData::Type::Criteria))
+ continue;
+
+ OUString aSymbol = rEntry.second->GetSymbol();
+ m_xLbFilterArea->append(aSymbol, rEntry.second->GetName());
+ }
+
+ // is there a stored source range?
+
+ ScRange aAdvSource;
+ if (rQueryItem.GetAdvancedQuerySource(aAdvSource))
+ {
+ OUString aRefStr(aAdvSource.Format(*pDoc, ScRefFlags::RANGE_ABS_3D, pDoc->GetAddressConvention()));
+ m_xEdFilterArea->SetRefString( aRefStr );
+ }
+ }
+
+ m_xLbFilterArea->set_active( 0 );
+
+ // let options be initialized:
+
+ pOptionsMgr.reset( new ScFilterOptionsMgr(
+ pViewData,
+ theQueryData,
+ m_xBtnCase.get(),
+ m_xBtnRegExp.get(),
+ m_xBtnHeader.get(),
+ m_xBtnUnique.get(),
+ m_xBtnCopyResult.get(),
+ m_xBtnDestPers.get(),
+ m_xLbCopyArea.get(),
+ m_xEdCopyArea.get(),
+ m_xRbCopyArea.get(),
+ m_xFtDbAreaLabel.get(),
+ m_xFtDbArea.get(),
+ aStrUndefined ) );
+
+ // special filter always needs column headers
+ m_xBtnHeader->set_active(true);
+ m_xBtnHeader->set_sensitive(false);
+
+ // turn on modal mode
+ // SetDispatcherLock( true );
+ //@BugID 54702 enable/disable in base class only
+ //SFX_APPWINDOW->Disable(false); //! general method in ScAnyRefDlg
+}
+
+void ScSpecialFilterDlg::Close()
+{
+ if (pViewData)
+ pViewData->GetDocShell()->CancelAutoDBRange();
+
+ DoClose( ScSpecialFilterDlgWrapper::GetChildWindowId() );
+}
+
+// Transfer of a table area selected with the mouse, which is then displayed
+// as a new selection in the reference edit.
+
+void ScSpecialFilterDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
+{
+ if ( !(bRefInputMode && m_pRefInputEdit) ) // only possible if in the reference edit mode
+ return;
+
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart( m_pRefInputEdit );
+
+ OUString aRefStr;
+ const formula::FormulaGrammar::AddressConvention eConv = rDocP.GetAddressConvention();
+
+ if (m_pRefInputEdit == m_xEdCopyArea.get())
+ aRefStr = rRef.aStart.Format(ScRefFlags::ADDR_ABS_3D, &rDocP, eConv);
+ else if (m_pRefInputEdit == m_xEdFilterArea.get())
+ aRefStr = rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D, eConv);
+
+ m_pRefInputEdit->SetRefString( aRefStr );
+}
+
+void ScSpecialFilterDlg::SetActive()
+{
+ if ( bRefInputMode )
+ {
+ if (m_pRefInputEdit == m_xEdCopyArea.get())
+ {
+ m_xEdCopyArea->GrabFocus();
+ m_xEdCopyArea->GetModifyHdl().Call( *m_xEdCopyArea );
+ }
+ else if (m_pRefInputEdit == m_xEdFilterArea.get())
+ {
+ m_xEdFilterArea->GrabFocus();
+ FilterAreaModHdl( *m_xEdFilterArea );
+ }
+ }
+ else
+ m_xDialog->grab_focus();
+
+ RefInputDone();
+}
+
+ScQueryItem* ScSpecialFilterDlg::GetOutputItem( const ScQueryParam& rParam,
+ const ScRange& rSource )
+{
+ pOutItem.reset(new ScQueryItem( nWhichQuery, &rParam ));
+ pOutItem->SetAdvancedQuerySource( &rSource );
+ return pOutItem.get();
+}
+
+bool ScSpecialFilterDlg::IsRefInputMode() const
+{
+ return bRefInputMode;
+}
+
+// Handler:
+
+IMPL_LINK(ScSpecialFilterDlg, EndDlgHdl, weld::Button&, rBtn, void)
+{
+ OSL_ENSURE( pDoc && pViewData, "Document or ViewData not found. :-/" );
+
+ if (&rBtn == m_xBtnOk.get() && pDoc && pViewData)
+ {
+ OUString theCopyStr( m_xEdCopyArea->GetText() );
+ OUString theAreaStr( m_xEdFilterArea->GetText() );
+ ScQueryParam theOutParam( theQueryData );
+ ScAddress theAdrCopy;
+ bool bEditInputOk = true;
+ bool bQueryOk = false;
+ ScRange theFilterArea;
+ const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
+
+ if ( m_xBtnCopyResult->get_active() )
+ {
+ sal_Int32 nColonPos = theCopyStr.indexOf( ':' );
+
+ if ( -1 != nColonPos )
+ theCopyStr = theCopyStr.copy( 0, nColonPos );
+
+ ScRefFlags nResult = theAdrCopy.Parse( theCopyStr, *pDoc, eConv );
+
+ if ( (nResult & ScRefFlags::VALID) == ScRefFlags::ZERO )
+ {
+ if (!m_xExpander->get_expanded())
+ m_xExpander->set_expanded(true);
+
+ ERRORBOX(m_xDialog.get(), STR_INVALID_TABREF);
+ m_xEdCopyArea->GrabFocus();
+ bEditInputOk = false;
+ }
+ }
+
+ if ( bEditInputOk )
+ {
+ ScRefFlags nResult = ScRange().Parse( theAreaStr, *pDoc, eConv );
+
+ if ( (nResult & ScRefFlags::VALID) == ScRefFlags::ZERO )
+ {
+ ERRORBOX(m_xDialog.get(), STR_INVALID_TABREF);
+ m_xEdFilterArea->GrabFocus();
+ bEditInputOk = false;
+ }
+ }
+
+ if ( bEditInputOk )
+ {
+ /*
+ * All edit fields contain valid areas. Now try to create
+ * a ScQueryParam from the filter area:
+ */
+
+ ScRefFlags nResult = theFilterArea.Parse( theAreaStr, *pDoc, eConv );
+
+ if ( (nResult & ScRefFlags::VALID) == ScRefFlags::VALID )
+ {
+ ScAddress& rStart = theFilterArea.aStart;
+ ScAddress& rEnd = theFilterArea.aEnd;
+
+ if ( m_xBtnCopyResult->get_active() )
+ {
+ theOutParam.bInplace = false;
+ theOutParam.nDestTab = theAdrCopy.Tab();
+ theOutParam.nDestCol = theAdrCopy.Col();
+ theOutParam.nDestRow = theAdrCopy.Row();
+ }
+ else
+ {
+ theOutParam.bInplace = true;
+ theOutParam.nDestTab = 0;
+ theOutParam.nDestCol = 0;
+ theOutParam.nDestRow = 0;
+ }
+
+ theOutParam.bHasHeader = m_xBtnHeader->get_active();
+ theOutParam.bByRow = true;
+ theOutParam.bCaseSens = m_xBtnCase->get_active();
+ theOutParam.eSearchType = m_xBtnRegExp->get_active() ? utl::SearchParam::SearchType::Regexp :
+ utl::SearchParam::SearchType::Normal;
+ theOutParam.bDuplicate = !m_xBtnUnique->get_active();
+ theOutParam.bDestPers = m_xBtnDestPers->get_active();
+
+ bQueryOk = pDoc->CreateQueryParam(ScRange(rStart,rEnd), theOutParam);
+ }
+ }
+
+ if ( bQueryOk )
+ {
+ SetDispatcherLock( false );
+ SwitchToDocument();
+ GetBindings().GetDispatcher()->ExecuteList(FID_FILTER_OK,
+ SfxCallMode::SLOT | SfxCallMode::RECORD,
+ { GetOutputItem(theOutParam, theFilterArea) });
+ response(RET_OK);
+ }
+ else
+ {
+ ERRORBOX(m_xDialog.get(), STR_INVALID_QUERYAREA);
+ m_xEdFilterArea->GrabFocus();
+ }
+ }
+ else if (&rBtn == m_xBtnCancel.get())
+ {
+ response(RET_CANCEL);
+ }
+}
+
+IMPL_LINK_NOARG(ScSpecialFilterDlg, RefInputEditHdl, formula::RefEdit&, void)
+{
+ RefInputHdl();
+}
+
+IMPL_LINK_NOARG(ScSpecialFilterDlg, RefInputButtonHdl, formula::RefButton&, void)
+{
+ RefInputHdl();
+}
+
+void ScSpecialFilterDlg::RefInputHdl()
+{
+ if (!m_xDialog->has_toplevel_focus())
+ return;
+
+ if( m_xEdCopyArea->GetWidget()->has_focus() || m_xRbCopyArea->GetWidget()->has_focus() )
+ {
+ m_pRefInputEdit = m_xEdCopyArea.get();
+ bRefInputMode = true;
+ }
+ else if( m_xEdFilterArea->GetWidget()->has_focus() || m_xRbFilterArea->GetWidget()->has_focus() )
+ {
+ m_pRefInputEdit = m_xEdFilterArea.get();
+ bRefInputMode = true;
+ }
+ else if( bRefInputMode )
+ {
+ m_pRefInputEdit = nullptr;
+ bRefInputMode = false;
+ }
+}
+
+IMPL_LINK(ScSpecialFilterDlg, FilterAreaSelHdl, weld::ComboBox&, rLb, void)
+{
+ if (&rLb == m_xLbFilterArea.get())
+ {
+ OUString aString;
+ const sal_Int32 nSelPos = m_xLbFilterArea->get_active();
+
+ if ( nSelPos > 0 )
+ aString = m_xLbFilterArea->get_id(nSelPos);
+
+ m_xEdFilterArea->SetText( aString );
+ }
+}
+
+IMPL_LINK( ScSpecialFilterDlg, FilterAreaModHdl, formula::RefEdit&, rEd, void )
+{
+ if (&rEd != m_xEdFilterArea.get())
+ return;
+
+ if ( pDoc && pViewData )
+ {
+ OUString theCurAreaStr = rEd.GetText();
+ ScRefFlags nResult = ScRange().Parse( theCurAreaStr, *pDoc );
+
+ if ( (nResult & ScRefFlags::VALID) == ScRefFlags::VALID )
+ {
+ const sal_Int32 nCount = m_xLbFilterArea->get_count();
+ for (sal_Int32 i = 1; i < nCount; ++i)
+ {
+ OUString aStr = m_xLbFilterArea->get_id(i);
+ if (theCurAreaStr == aStr)
+ {
+ m_xLbFilterArea->set_active( i );
+ return;
+ }
+ }
+ m_xLbFilterArea->set_active( 0 );
+ }
+ }
+ else
+ m_xLbFilterArea->set_active( 0 );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/sortdlg.cxx b/sc/source/ui/dbgui/sortdlg.cxx
new file mode 100644
index 000000000..22af2230b
--- /dev/null
+++ b/sc/source/ui/dbgui/sortdlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <scui_def.hxx>
+#include <tpsort.hxx>
+#include <sortdlg.hxx>
+
+ScSortDlg::ScSortDlg(weld::Window* pParent, const SfxItemSet* pArgSet)
+ : SfxTabDialogController(pParent, "modules/scalc/ui/sortdialog.ui", "SortDialog", pArgSet)
+{
+ AddTabPage("criteria", ScTabPageSortFields::Create, nullptr);
+ AddTabPage("options", ScTabPageSortOptions::Create, nullptr);
+}
+
+ScSortWarningDlg::ScSortWarningDlg(weld::Window* pParent,
+ std::u16string_view rExtendText, std::u16string_view rCurrentText)
+ : GenericDialogController(pParent, "modules/scalc/ui/sortwarning.ui", "SortWarning")
+ , m_xFtText(m_xBuilder->weld_label("sorttext"))
+ , m_xBtnExtSort(m_xBuilder->weld_button("extend"))
+ , m_xBtnCurSort(m_xBuilder->weld_button("current"))
+{
+ OUString sTextName = m_xFtText->get_label();
+ sTextName = sTextName.replaceFirst("%1", rExtendText);
+ sTextName = sTextName.replaceFirst("%2", rCurrentText);
+ m_xFtText->set_label(sTextName);
+
+ m_xBtnExtSort->connect_clicked( LINK( this, ScSortWarningDlg, BtnHdl ) );
+ m_xBtnCurSort->connect_clicked( LINK( this, ScSortWarningDlg, BtnHdl ) );
+}
+
+ScSortWarningDlg::~ScSortWarningDlg()
+{
+}
+
+IMPL_LINK(ScSortWarningDlg, BtnHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == m_xBtnExtSort.get())
+ {
+ m_xDialog->response(BTN_EXTEND_RANGE);
+ }
+ else if(&rBtn == m_xBtnCurSort.get())
+ {
+ m_xDialog->response(BTN_CURRENT_SELECTION);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/sortkeydlg.cxx b/sc/source/ui/dbgui/sortkeydlg.cxx
new file mode 100644
index 000000000..599280735
--- /dev/null
+++ b/sc/source/ui/dbgui/sortkeydlg.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/.
+ */
+
+#include <memory>
+#include <sortkeydlg.hxx>
+#include <vcl/svapp.hxx>
+
+#include <scresid.hxx>
+#include <strings.hrc>
+
+ScSortKeyItem::ScSortKeyItem(weld::Container* pParent)
+ : m_xBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/sortkey.ui"))
+ , m_xFrame(m_xBuilder->weld_frame("SortKeyFrame"))
+ , m_xLbSort(m_xBuilder->weld_combo_box("sortlb"))
+ , m_xBtnUp(m_xBuilder->weld_radio_button("up"))
+ , m_xBtnDown(m_xBuilder->weld_radio_button("down"))
+ , m_xLabel(m_xBuilder->weld_label("lbColRow"))
+ , m_pParent(pParent)
+{
+ // tdf#136155 let the other elements in the dialog determine the width of the
+ // combobox
+ m_xLbSort->set_size_request(m_xLbSort->get_approximate_digit_width() * 12, -1);
+ // keep the UI static when switching the labels
+ const sal_Int32 nChars = std::max( ScResId(SCSTR_COLUMN).getLength(), ScResId(SCSTR_ROW).getLength() ) + 2; // +2 to avoid cut-off labels on kf5/gen
+ m_xLabel->set_size_request( m_xLabel->get_approximate_digit_width() * nChars, -1);
+}
+
+ScSortKeyItem::~ScSortKeyItem()
+{
+ m_pParent->move(m_xFrame.get(), nullptr);
+}
+
+void ScSortKeyItem::DisableField()
+{
+ m_xFrame->set_sensitive(false);
+}
+
+void ScSortKeyItem::EnableField()
+{
+ m_xFrame->set_sensitive(true);
+}
+
+ScSortKeyWindow::ScSortKeyWindow(weld::Container* pBox)
+ : m_pBox(pBox)
+{
+}
+
+ScSortKeyWindow::~ScSortKeyWindow()
+{
+}
+
+void ScSortKeyWindow::AddSortKey( sal_uInt16 nItemNumber )
+{
+ ScSortKeyItem* pSortKeyItem = new ScSortKeyItem(m_pBox);
+
+ // Set Sort key number
+ OUString aLine = pSortKeyItem->m_xFrame->get_label() +
+ OUString::number( nItemNumber );
+ pSortKeyItem->m_xFrame->set_label(aLine);
+
+ // for ui-testing. Distinguish the sort keys
+ if ( m_aSortKeyItems.size() > 0 )
+ {
+ pSortKeyItem->m_xLbSort->set_buildable_name(
+ pSortKeyItem->m_xLbSort->get_buildable_name() + OString::number(m_aSortKeyItems.size() + 1));
+ }
+
+ m_aSortKeyItems.push_back(std::unique_ptr<ScSortKeyItem>(pSortKeyItem));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/subtdlg.cxx b/sc/source/ui/dbgui/subtdlg.cxx
new file mode 100644
index 000000000..924716a6f
--- /dev/null
+++ b/sc/source/ui/dbgui/subtdlg.cxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <tpsubt.hxx>
+#include <subtdlg.hxx>
+#include <scui_def.hxx>
+
+ScSubTotalDlg::ScSubTotalDlg(weld::Window* pParent, const SfxItemSet& rArgSet)
+ : SfxTabDialogController(pParent, "modules/scalc/ui/subtotaldialog.ui", "SubTotalDialog", &rArgSet)
+ , m_xBtnRemove(m_xBuilder->weld_button("remove"))
+{
+ AddTabPage("1stgroup", ScTpSubTotalGroup1::Create, nullptr);
+ AddTabPage("2ndgroup", ScTpSubTotalGroup2::Create, nullptr);
+ AddTabPage("3rdgroup", ScTpSubTotalGroup3::Create, nullptr);
+ AddTabPage("options", ScTpSubTotalOptions::Create, nullptr);
+ m_xBtnRemove->connect_clicked( LINK( this, ScSubTotalDlg, RemoveHdl ) );
+}
+
+ScSubTotalDlg::~ScSubTotalDlg()
+{
+}
+
+IMPL_LINK_NOARG(ScSubTotalDlg, RemoveHdl, weld::Button&, void)
+{
+ m_xDialog->response(SCRET_REMOVE);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/textimportoptions.cxx b/sc/source/ui/dbgui/textimportoptions.cxx
new file mode 100644
index 000000000..99ddc425d
--- /dev/null
+++ b/sc/source/ui/dbgui/textimportoptions.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <textimportoptions.hxx>
+#include <svx/langbox.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+ScTextImportOptionsDlg::ScTextImportOptionsDlg(weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/textimportoptions.ui", "TextImportOptionsDialog")
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xRbAutomatic(m_xBuilder->weld_radio_button("automatic"))
+ , m_xRbCustom(m_xBuilder->weld_radio_button("custom"))
+ , m_xBtnConvertDate(m_xBuilder->weld_check_button("convertdata"))
+ , m_xBtnKeepAsking(m_xBuilder->weld_check_button("keepasking"))
+ , m_xLbCustomLang(new SvxLanguageBox(m_xBuilder->weld_combo_box("lang")))
+{
+ init();
+}
+
+ScTextImportOptionsDlg::~ScTextImportOptionsDlg()
+{
+}
+
+LanguageType ScTextImportOptionsDlg::getLanguageType() const
+{
+ if (m_xRbAutomatic->get_active())
+ return LANGUAGE_SYSTEM;
+
+ return m_xLbCustomLang->get_active_id();
+}
+
+bool ScTextImportOptionsDlg::isDateConversionSet() const
+{
+ return m_xBtnConvertDate->get_active();
+}
+
+bool ScTextImportOptionsDlg::isKeepAskingSet() const
+{
+ return m_xBtnKeepAsking->get_active();
+}
+
+void ScTextImportOptionsDlg::init()
+{
+ m_xBtnOk->connect_clicked(LINK(this, ScTextImportOptionsDlg, OKHdl));
+ Link<weld::Toggleable&,void> aLink = LINK(this, ScTextImportOptionsDlg, RadioHdl);
+ m_xRbAutomatic->connect_toggled(aLink);
+ m_xRbCustom->connect_toggled(aLink);
+
+ m_xRbAutomatic->set_active(true);
+
+ m_xLbCustomLang->SetLanguageList(
+ SvxLanguageListFlags::ALL | SvxLanguageListFlags::ONLY_KNOWN, false);
+
+ LanguageType eLang = Application::GetSettings().GetLanguageTag().getLanguageType();
+ m_xLbCustomLang->set_active_id(eLang);
+ m_xLbCustomLang->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(ScTextImportOptionsDlg, OKHdl, weld::Button&, void)
+{
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK(ScTextImportOptionsDlg, RadioHdl, weld::Toggleable&, rBtn, void)
+{
+ if (&rBtn == m_xRbAutomatic.get())
+ {
+ m_xLbCustomLang->set_sensitive(false);
+ }
+ else if (&rBtn == m_xRbCustom.get())
+ {
+ m_xLbCustomLang->set_sensitive(true);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/tpsort.cxx b/sc/source/ui/dbgui/tpsort.cxx
new file mode 100644
index 000000000..35a24e633
--- /dev/null
+++ b/sc/source/ui/dbgui/tpsort.cxx
@@ -0,0 +1,855 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <svtools/collatorres.hxx>
+#include <unotools/collatorwrapper.hxx>
+#include <comphelper/processfactory.hxx>
+#include <osl/diagnose.h>
+
+#include <scitems.hxx>
+#include <uiitems.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <global.hxx>
+#include <dbdata.hxx>
+#include <userlist.hxx>
+#include <rangeutl.hxx>
+#include <scresid.hxx>
+#include <sc.hrc>
+#include <strings.hrc>
+#include <globstr.hrc>
+
+#include <sortkeydlg.hxx>
+
+#include <sortdlg.hxx>
+
+#include <tpsort.hxx>
+
+using namespace com::sun::star;
+
+/*
+ * Since the settings on the second Tab Page (Options) effects
+ * the first Tab Page, there must be a way for it to communicate with the
+ * other Page.
+ *
+ * At the moment this problem is solved through using two data members of the
+ * Tab Pages. If a page is enabled / disabled, it compares this data member
+ * with its own state (-> Activate() / Deactivate()).
+ *
+ * In the meantime the class SfxTabPage offers the following method:
+ *
+ * virtual sal_Bool HasExchangeSupport() const; -> return sal_True;
+ * virtual void ActivatePage(const SfxItemSet &);
+ * virtual int DeactivatePage(SfxItemSet * = 0);
+ *
+ * This still needs to be changed!
+ */
+
+// Sort Criteria Tab page
+
+ScTabPageSortFields::ScTabPageSortFields(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/sortcriteriapage.ui", "SortCriteriaPage", &rArgSet)
+ ,
+
+ m_aIdle("ScTabPageSortFields Scroll To End Idle"),
+ aStrUndefined ( ScResId( SCSTR_UNDEFINED ) ),
+ aStrColumn ( ScResId( SCSTR_COLUMN ) ),
+ aStrRow ( ScResId( SCSTR_ROW ) ),
+ aStrRowLabel ( ScResId( SCSTR_ROW_LABEL ) ),
+ aStrColLabel ( ScResId( SCSTR_COL_LABEL ) ),
+
+ nWhichSort ( rArgSet.GetPool()->GetWhich( SID_SORT ) ),
+ pViewData ( nullptr ),
+ aSortData ( rArgSet.Get( nWhichSort ).GetSortData() ),
+ nFieldCount ( 0 ),
+ // show actual size of the sorting keys without limiting them to the default size
+ nSortKeyCount(std::max(aSortData.GetSortKeyCount(), static_cast<sal_uInt16>(DEFSORT)))
+
+ , m_xTop(m_xBuilder->weld_container("TopWindow"))
+ , m_xBtnHeader(m_xBuilder->weld_check_button("cbHeader"))
+ , m_xBtnTopDown(m_xBuilder->weld_radio_button("rbTopDown"))
+ , m_xBtnLeftRight(m_xBuilder->weld_radio_button("rbLeftRight"))
+ , m_xScrolledWindow(m_xBuilder->weld_scrolled_window("SortCriteriaPage"))
+ , m_xBox(m_xBuilder->weld_container("SortKeyWindow"))
+ , m_aSortWin(m_xBox.get())
+{
+ // tdf#147722 set some nominal small default height so the height adapts
+ // to all the other contents and the natural height of this widget isn't
+ // an input into the overall size
+ m_xScrolledWindow->set_size_request(-1, 42);
+
+ Init();
+
+ m_aIdle.SetInvokeHandler(LINK(this, ScTabPageSortFields, ScrollToEndHdl));
+
+ SetExchangeSupport();
+}
+
+ScTabPageSortFields::~ScTabPageSortFields()
+{
+ m_aSortWin.m_aSortKeyItems.clear();
+ m_xBox.reset();
+ m_xScrolledWindow.reset();
+}
+
+void ScTabPageSortFields::Init()
+{
+ // Check whether the field that is passed on is a database field:
+ ScDocument* pDoc = pViewData ? &pViewData->GetDocument() : nullptr;
+ if ( pDoc )
+ {
+ ScDBCollection* pDBColl = pDoc->GetDBCollection();
+ const SCTAB nCurTab = pViewData->GetTabNo();
+ if ( pDBColl )
+ {
+ ScDBData* pDBData
+ = pDBColl->GetDBAtArea( nCurTab,
+ aSortData.nCol1, aSortData.nRow1,
+ aSortData.nCol2, aSortData.nRow2 );
+ if ( pDBData )
+ {
+ m_xBtnHeader->set_active(pDBData->HasHeader());
+ }
+ }
+ }
+ m_xBtnHeader->set_label(aStrColLabel);
+
+ Link<weld::Toggleable&,void> aLink = LINK(this, ScTabPageSortFields, SortDirHdl );
+ m_xBtnTopDown->connect_toggled( aLink );
+ m_xBtnLeftRight->connect_toggled( aLink );
+ m_xBtnHeader->connect_toggled( aLink );
+
+ const ScSortItem& rSortItem = GetItemSet().Get( nWhichSort );
+
+ pViewData = rSortItem.GetViewData();
+ OSL_ENSURE( pViewData, "ViewData not found!" );
+
+ nFieldArr.push_back( 0 );
+
+ // Create three sort key dialogs by default
+ for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
+ {
+ AddSortKey(i+1);
+ m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->connect_changed(LINK(this, ScTabPageSortFields, SelectHdl));
+ }
+}
+
+std::unique_ptr<SfxTabPage> ScTabPageSortFields::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pArgSet)
+{
+ return std::make_unique<ScTabPageSortFields>(pPage, pController, *pArgSet);
+}
+
+void ScTabPageSortFields::Reset( const SfxItemSet* /* rArgSet */ )
+{
+ m_xBtnHeader->set_active( aSortData.bHasHeader );
+ m_xBtnTopDown->set_active( aSortData.bByRow );
+ m_xBtnLeftRight->set_active( !aSortData.bByRow );
+
+ if (m_aSortWin.m_aSortKeyItems[0]->m_xLbSort->get_count() == 0)
+ FillFieldLists(0);
+
+ // ListBox selection:
+ if (!aSortData.maKeyState.empty() && aSortData.maKeyState[0].bDoSort)
+ {
+ // Make sure that the all sort keys are reset
+ for ( sal_uInt16 i=nSortKeyCount; i<aSortData.GetSortKeyCount(); i++ )
+ {
+ AddSortKey(i+1);
+ m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->connect_changed( LINK( this,
+ ScTabPageSortFields, SelectHdl ) );
+ }
+ nSortKeyCount = aSortData.GetSortKeyCount();
+ FillFieldLists(0);
+
+ for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
+ {
+ if (aSortData.maKeyState[i].bDoSort )
+ {
+ m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->set_active( GetFieldSelPos(
+ aSortData.maKeyState[i].nField ) );
+ (aSortData.maKeyState[i].bAscending)
+ ? m_aSortWin.m_aSortKeyItems[i]->m_xBtnUp->set_active(true)
+ : m_aSortWin.m_aSortKeyItems[i]->m_xBtnDown->set_active(true);
+ }
+ else
+ {
+ m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->set_active(0); // Select none
+ m_aSortWin.m_aSortKeyItems[i]->m_xBtnUp->set_active(true);
+ }
+ }
+
+ // Enable or disable field depending on preceding Listbox selection
+ m_aSortWin.m_aSortKeyItems[0]->EnableField();
+ for ( sal_uInt16 i=1; i<nSortKeyCount; i++ )
+ if ( m_aSortWin.m_aSortKeyItems[i - 1]->m_xLbSort->get_active() == 0 )
+ m_aSortWin.m_aSortKeyItems[i]->DisableField();
+ else
+ m_aSortWin.m_aSortKeyItems[i]->EnableField();
+ }
+ else
+ {
+ SCCOL nCol = pViewData->GetCurX();
+
+ if( nCol < aSortData.nCol1 )
+ nCol = aSortData.nCol1;
+ else if( nCol > aSortData.nCol2 )
+ nCol = aSortData.nCol2;
+
+ sal_uInt16 nSort1Pos = nCol - aSortData.nCol1+1;
+
+ m_aSortWin.m_aSortKeyItems[0]->m_xLbSort->set_active(nSort1Pos);
+ for ( sal_uInt16 i=1; i<nSortKeyCount; i++ )
+ m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->set_active(0);
+
+ for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
+ m_aSortWin.m_aSortKeyItems[i]->m_xBtnUp->set_active(true);
+
+ m_aSortWin.m_aSortKeyItems[0]->EnableField();
+ m_aSortWin.m_aSortKeyItems[1]->EnableField();
+ for ( sal_uInt16 i=2; i<nSortKeyCount; i++ )
+ m_aSortWin.m_aSortKeyItems[i]->DisableField();
+ }
+
+ // Make sure that there is always a last undefined sort key
+ if (m_aSortWin.m_aSortKeyItems[nSortKeyCount - 1]->m_xLbSort->get_active() > 0)
+ SetLastSortKey( nSortKeyCount );
+}
+
+bool ScTabPageSortFields::FillItemSet( SfxItemSet* rArgSet )
+{
+ ScSortParam aNewSortData = aSortData;
+
+ const SfxItemSet* pExample = GetDialogExampleSet();
+ if (pExample)
+ {
+ if (const ScSortItem* pItem = pExample->GetItemIfSet(nWhichSort))
+ {
+ ScSortParam aTempData = pItem->GetSortData();
+ aTempData.maKeyState = aNewSortData.maKeyState;
+ aNewSortData = aTempData;
+ }
+ }
+ aNewSortData.bByRow = m_xBtnTopDown->get_active();
+ aNewSortData.bHasHeader = m_xBtnHeader->get_active();
+
+ std::vector<sal_Int32> nSortPos;
+
+ for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
+ {
+ nSortPos.push_back(m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->get_active());
+ if (nSortPos[i] == -1) nSortPos[i] = 0;
+ }
+
+ if( nSortKeyCount >= aNewSortData.GetSortKeyCount() )
+ aNewSortData.maKeyState.resize(nSortKeyCount);
+
+ if ( nSortPos[0] > 0 )
+ {
+ for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
+ {
+ aNewSortData.maKeyState[i].bDoSort = (nSortPos[i] > 0);
+ aNewSortData.maKeyState[i].nField = nFieldArr[nSortPos[i]];
+ aNewSortData.maKeyState[i].bAscending = m_aSortWin.m_aSortKeyItems[i]->m_xBtnUp->get_active();
+ }
+ }
+ else
+ {
+ for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
+ aNewSortData.maKeyState[i].bDoSort = false;
+ }
+
+ rArgSet->Put( ScSortItem( SCITEM_SORTDATA, nullptr, &aNewSortData ) );
+
+ return true;
+}
+
+// for data exchange without dialogue detour:
+void ScTabPageSortFields::ActivatePage( const SfxItemSet& rSet )
+{
+ // Refresh local copy with shared data
+ aSortData = rSet.Get( SCITEM_SORTDATA ).GetSortData();
+
+ m_xBtnHeader->set_active( aSortData.bHasHeader );
+ m_xBtnTopDown->set_active( aSortData.bByRow );
+ m_xBtnLeftRight->set_active( !aSortData.bByRow );
+}
+
+DeactivateRC ScTabPageSortFields::DeactivatePage( SfxItemSet* pSetP )
+{
+ if ( pSetP )
+ FillItemSet( pSetP );
+
+ return DeactivateRC::LeavePage;
+}
+
+void ScTabPageSortFields::FillFieldLists( sal_uInt16 nStartField )
+{
+ if ( !pViewData )
+ return;
+
+ ScDocument& rDoc = pViewData->GetDocument();
+
+ for (sal_uInt16 j = nStartField; j < nSortKeyCount; ++j)
+ {
+ m_aSortWin.m_aSortKeyItems[j]->m_xLabel->set_label(aSortData.bByRow ? aStrColumn : aStrRow);
+ m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->clear();
+ m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->freeze();
+ m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->append_text(aStrUndefined);
+ }
+
+ SCCOL nFirstSortCol = aSortData.nCol1;
+ SCROW nFirstSortRow = aSortData.nRow1;
+ SCTAB nTab = pViewData->GetTabNo();
+ sal_uInt16 i = 1;
+ nFieldArr.clear();
+ nFieldArr.push_back(0);
+
+ if ( aSortData.bByRow )
+ {
+ OUString aFieldName;
+ SCCOL nMaxCol = rDoc.ClampToAllocatedColumns(nTab, aSortData.nCol2);
+ SCCOL col;
+
+ for ( col=nFirstSortCol; col<=nMaxCol && i<SC_MAXFIELDS(rDoc.GetSheetLimits()); col++ )
+ {
+ aFieldName = rDoc.GetString(col, nFirstSortRow, nTab);
+ if ( !aSortData.bHasHeader || aFieldName.isEmpty() )
+ aFieldName = ScColToAlpha( col );
+ nFieldArr.push_back( col );
+
+ for ( sal_uInt16 j=nStartField; j<nSortKeyCount; j++ )
+ m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->insert_text(i, aFieldName);
+
+ i++;
+ }
+ }
+ else
+ {
+ OUString aFieldName;
+ SCROW nMaxRow = aSortData.nRow2;
+ SCROW row;
+
+ for ( row=nFirstSortRow; row<=nMaxRow && i<SC_MAXFIELDS(rDoc.GetSheetLimits()); row++ )
+ {
+ aFieldName = rDoc.GetString(nFirstSortCol, row, nTab);
+ if ( !aSortData.bHasHeader || aFieldName.isEmpty() )
+ aFieldName = OUString::number( row+1);
+ nFieldArr.push_back( row );
+
+ for ( sal_uInt16 j=nStartField; j<nSortKeyCount; j++ )
+ m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->insert_text(i, aFieldName);
+
+ i++;
+ }
+ }
+
+ for (sal_uInt16 j=nStartField; j < nSortKeyCount; ++j)
+ {
+ m_aSortWin.m_aSortKeyItems[j]->m_xLbSort->thaw();
+ }
+
+ nFieldCount = i;
+}
+
+sal_uInt16 ScTabPageSortFields::GetFieldSelPos( SCCOLROW nField )
+{
+ sal_uInt16 nFieldPos = 0;
+ bool bFound = false;
+
+ for ( sal_uInt16 n=1; n<nFieldCount && !bFound; n++ )
+ {
+ if ( nFieldArr[n] == nField )
+ {
+ nFieldPos = n;
+ bFound = true;
+ }
+ }
+
+ return nFieldPos;
+}
+
+void ScTabPageSortFields::SetLastSortKey( sal_uInt16 nItem )
+{
+ // Extend local SortParam copy
+ const ScSortKeyState atempKeyState = { 0, false, true };
+ aSortData.maKeyState.push_back( atempKeyState );
+
+ // Add Sort Key Item
+ ++nSortKeyCount;
+ AddSortKey( nSortKeyCount );
+ m_aSortWin.m_aSortKeyItems[nItem]->m_xLbSort->connect_changed(
+ LINK( this, ScTabPageSortFields, SelectHdl ) );
+
+ FillFieldLists( nItem );
+
+ // Set Status
+ m_aSortWin.m_aSortKeyItems[nItem]->m_xBtnUp->set_active(true);
+ m_aSortWin.m_aSortKeyItems[nItem]->m_xLbSort->set_active(0);
+}
+
+// Handler:
+
+IMPL_LINK_NOARG(ScTabPageSortFields, SortDirHdl, weld::Toggleable&, void)
+{
+ if ( (m_xBtnTopDown->get_active() != aSortData.bByRow) || (m_xBtnHeader->get_active() != aSortData.bHasHeader))
+ {
+ if (m_xBtnTopDown->get_active())
+ m_xBtnHeader->set_label(aStrColLabel);
+ else
+ m_xBtnHeader->set_label(aStrRowLabel);
+
+ aSortData.bByRow = m_xBtnTopDown->get_active();
+ aSortData.bHasHeader = m_xBtnHeader->get_active();
+
+ // remember selection
+ std::vector<sal_uInt16> nCurSel;
+ for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
+ nCurSel.push_back( m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->get_active() );
+
+ FillFieldLists(0);
+
+ for ( sal_uInt16 i=0; i<nSortKeyCount; i++ )
+ m_aSortWin.m_aSortKeyItems[i]->m_xLbSort->set_active(nCurSel[i]);
+ }
+}
+
+IMPL_LINK( ScTabPageSortFields, SelectHdl, weld::ComboBox&, rLb, void )
+{
+ OUString aSelEntry = rLb.get_active_text();
+ ScSortKeyItems::iterator pIter;
+
+ // If last listbox is enabled add one item
+ if (m_aSortWin.m_aSortKeyItems.back()->m_xLbSort.get() == &rLb)
+ {
+ if ( aSelEntry != aStrUndefined )
+ {
+ SetLastSortKey( nSortKeyCount );
+ return;
+ }
+ }
+
+ // Find selected listbox
+ pIter = std::find_if(m_aSortWin.m_aSortKeyItems.begin(), m_aSortWin.m_aSortKeyItems.end(),
+ [&rLb](const ScSortKeyItems::value_type& rItem) { return rItem->m_xLbSort.get() == &rLb; });
+
+ if (pIter == m_aSortWin.m_aSortKeyItems.end())
+ return;
+
+ // If not selecting the last Listbox, modify the succeeding ones
+ ++pIter;
+ if ( std::distance(m_aSortWin.m_aSortKeyItems.begin(), pIter) >= nSortKeyCount )
+ return;
+
+ if ( aSelEntry == aStrUndefined )
+ {
+ for ( ; pIter != m_aSortWin.m_aSortKeyItems.end(); ++pIter )
+ {
+ (*pIter)->m_xLbSort->set_active(0);
+
+ (*pIter)->DisableField();
+ }
+ }
+ else
+ {
+ (*pIter)->EnableField();
+ }
+}
+
+IMPL_LINK_NOARG(ScTabPageSortFields, ScrollToEndHdl, Timer*, void)
+{
+ m_xScrolledWindow->vadjustment_set_value(m_xScrolledWindow->vadjustment_get_upper());
+}
+
+void ScTabPageSortFields::AddSortKey( sal_uInt16 nItem )
+{
+ m_aSortWin.AddSortKey(nItem);
+ m_aIdle.Start();
+}
+
+// Sort option Tab Page:
+
+ScTabPageSortOptions::ScTabPageSortOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/sortoptionspage.ui", "SortOptionsPage", &rArgSet)
+ , aStrUndefined(ScResId(SCSTR_UNDEFINED))
+ , nWhichSort(rArgSet.GetPool()->GetWhich(SID_SORT))
+ , aSortData(rArgSet.Get(nWhichSort).GetSortData())
+ , pViewData(nullptr)
+ , pDoc(nullptr)
+ , m_xBtnCase(m_xBuilder->weld_check_button("case"))
+ , m_xBtnFormats(m_xBuilder->weld_check_button("formats"))
+ , m_xBtnNaturalSort(m_xBuilder->weld_check_button("naturalsort"))
+ , m_xBtnCopyResult(m_xBuilder->weld_check_button("copyresult"))
+ , m_xLbOutPos(m_xBuilder->weld_combo_box("outarealb"))
+ , m_xEdOutPos(m_xBuilder->weld_entry("outareaed"))
+ , m_xBtnSortUser(m_xBuilder->weld_check_button("sortuser"))
+ , m_xLbSortUser(m_xBuilder->weld_combo_box("sortuserlb"))
+ , m_xLbLanguage(new SvxLanguageBox(m_xBuilder->weld_combo_box("language")))
+ , m_xFtAlgorithm(m_xBuilder->weld_label("algorithmft"))
+ , m_xLbAlgorithm(m_xBuilder->weld_combo_box("algorithmlb"))
+ , m_xBtnIncComments(m_xBuilder->weld_check_button("includenotes"))
+ , m_xBtnIncImages(m_xBuilder->weld_check_button("includeimages"))
+{
+ m_xLbSortUser->set_size_request(m_xLbSortUser->get_approximate_digit_width() * 50, -1);
+ m_xLbSortUser->set_accessible_description(ScResId(STR_A11Y_DESC_SORTUSER));
+ Init();
+ SetExchangeSupport();
+}
+
+void ScTabPageSortOptions::Init()
+{
+ // CollatorResource has user-visible names for sort algorithms
+ m_xColRes.reset(new CollatorResource);
+
+ //! use CollatorWrapper from document?
+ m_xColWrap.reset(new CollatorWrapper(comphelper::getProcessComponentContext()));
+
+ const ScSortItem& rSortItem = GetItemSet().Get( nWhichSort );
+
+ m_xLbOutPos->connect_changed( LINK( this, ScTabPageSortOptions, SelOutPosHdl ) );
+ m_xBtnCopyResult->connect_toggled( LINK( this, ScTabPageSortOptions, EnableHdl ) );
+ m_xBtnSortUser->connect_toggled( LINK( this, ScTabPageSortOptions, EnableHdl ) );
+ m_xLbLanguage->connect_changed( LINK( this, ScTabPageSortOptions, FillAlgorHdl ) );
+
+ pViewData = rSortItem.GetViewData();
+ pDoc = pViewData ? &pViewData->GetDocument() : nullptr;
+
+ OSL_ENSURE( pViewData, "ViewData not found! :-/" );
+
+ if ( pViewData && pDoc )
+ {
+ const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
+
+ m_xLbOutPos->clear();
+ m_xLbOutPos->append_text(aStrUndefined);
+ m_xLbOutPos->set_sensitive(false);
+
+ ScAreaNameIterator aIter( *pDoc );
+ OUString aName;
+ ScRange aRange;
+ while ( aIter.Next( aName, aRange ) )
+ {
+ OUString aRefStr(aRange.aStart.Format(ScRefFlags::ADDR_ABS_3D, pDoc, eConv));
+ m_xLbOutPos->append(aRefStr, aName);
+ }
+
+ m_xLbOutPos->set_active(0);
+ m_xEdOutPos->set_text(OUString());
+ }
+
+ FillUserSortListBox();
+
+ // get available languages
+
+ m_xLbLanguage->SetLanguageList( SvxLanguageListFlags::ALL | SvxLanguageListFlags::ONLY_KNOWN, false );
+ m_xLbLanguage->InsertLanguage( LANGUAGE_SYSTEM );
+}
+
+std::unique_ptr<SfxTabPage> ScTabPageSortOptions::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet)
+{
+ return std::make_unique<ScTabPageSortOptions>(pPage, pController, *rArgSet);
+}
+
+void ScTabPageSortOptions::Reset( const SfxItemSet* /* rArgSet */ )
+{
+ if ( aSortData.bUserDef )
+ {
+ m_xBtnSortUser->set_active(true);
+ m_xLbSortUser->set_sensitive(true);
+ m_xLbSortUser->set_active(aSortData.nUserIndex);
+ }
+ else
+ {
+ m_xBtnSortUser->set_active(false);
+ m_xLbSortUser->set_sensitive(false);
+ m_xLbSortUser->set_active(0);
+ }
+
+ m_xBtnCase->set_active( aSortData.bCaseSens );
+ m_xBtnFormats->set_active( aSortData.aDataAreaExtras.mbCellFormats );
+ m_xBtnNaturalSort->set_active( aSortData.bNaturalSort );
+ m_xBtnIncComments->set_active( aSortData.aDataAreaExtras.mbCellNotes );
+ m_xBtnIncImages->set_active( aSortData.aDataAreaExtras.mbCellDrawObjects );
+
+ LanguageType eLang = LanguageTag::convertToLanguageType( aSortData.aCollatorLocale, false);
+ if ( eLang == LANGUAGE_DONTKNOW )
+ eLang = LANGUAGE_SYSTEM;
+ m_xLbLanguage->set_active_id(eLang);
+ FillAlgor(); // get algorithms, select default
+ if ( !aSortData.aCollatorAlgorithm.isEmpty() )
+ m_xLbAlgorithm->set_active_text(m_xColRes->GetTranslation(aSortData.aCollatorAlgorithm));
+
+ if ( pDoc && !aSortData.bInplace )
+ {
+ ScRefFlags nFormat = (aSortData.nDestTab != pViewData->GetTabNo())
+ ? ScRefFlags::RANGE_ABS_3D
+ : ScRefFlags::RANGE_ABS;
+
+ theOutPos.Set( aSortData.nDestCol,
+ aSortData.nDestRow,
+ aSortData.nDestTab );
+
+ OUString aStr(theOutPos.Format(nFormat, pDoc, pDoc->GetAddressConvention()));
+ m_xBtnCopyResult->set_active(true);
+ m_xLbOutPos->set_sensitive(true);
+ m_xEdOutPos->set_sensitive(true);
+ m_xEdOutPos->set_text( aStr );
+ EdOutPosModHdl();
+ m_xEdOutPos->grab_focus();
+ m_xEdOutPos->select_region(0, -1);
+ }
+ else
+ {
+ m_xBtnCopyResult->set_active( false );
+ m_xLbOutPos->set_sensitive(false);
+ m_xEdOutPos->set_sensitive(false);
+ m_xEdOutPos->set_text( OUString() );
+ }
+}
+
+bool ScTabPageSortOptions::FillItemSet( SfxItemSet* rArgSet )
+{
+ // Create local copy of ScParam
+ ScSortParam aNewSortData = aSortData;
+
+ const SfxItemSet* pExample = GetDialogExampleSet();
+ if (pExample)
+ {
+ if (const ScSortItem* pSortItem = pExample->GetItemIfSet(nWhichSort))
+ aNewSortData = pSortItem->GetSortData();
+ }
+ aNewSortData.bCaseSens = m_xBtnCase->get_active();
+ aNewSortData.bNaturalSort = m_xBtnNaturalSort->get_active();
+ aNewSortData.aDataAreaExtras.mbCellNotes = m_xBtnIncComments->get_active();
+ aNewSortData.aDataAreaExtras.mbCellDrawObjects = m_xBtnIncImages->get_active();
+ aNewSortData.aDataAreaExtras.mbCellFormats = m_xBtnFormats->get_active();
+ aNewSortData.bInplace = !m_xBtnCopyResult->get_active();
+ aNewSortData.nDestCol = theOutPos.Col();
+ aNewSortData.nDestRow = theOutPos.Row();
+ aNewSortData.nDestTab = theOutPos.Tab();
+ aNewSortData.bUserDef = m_xBtnSortUser->get_active();
+ aNewSortData.nUserIndex = (m_xBtnSortUser->get_active())
+ ? m_xLbSortUser->get_active()
+ : 0;
+
+ // get locale
+ LanguageType eLang = m_xLbLanguage->get_active_id();
+ aNewSortData.aCollatorLocale = LanguageTag::convertToLocale( eLang, false);
+
+ // get algorithm
+ OUString sAlg;
+ if ( eLang != LANGUAGE_SYSTEM )
+ {
+ uno::Sequence<OUString> aAlgos = m_xColWrap->listCollatorAlgorithms(
+ aNewSortData.aCollatorLocale );
+ const int nSel = m_xLbAlgorithm->get_active();
+ if ( nSel < aAlgos.getLength() )
+ sAlg = aAlgos[nSel];
+ }
+ aNewSortData.aCollatorAlgorithm = sAlg;
+
+ rArgSet->Put( ScSortItem( SCITEM_SORTDATA, &aNewSortData ) );
+
+ return true;
+}
+
+// for data exchange without dialogue detour:
+void ScTabPageSortOptions::ActivatePage( const SfxItemSet& rSet )
+{
+ // Refresh local copy with shared data
+ aSortData = rSet.Get( SCITEM_SORTDATA ).GetSortData();
+ ScSortDlg* pDlg = static_cast<ScSortDlg*>(GetDialogController());
+ if (!pDlg)
+ return;
+}
+
+DeactivateRC ScTabPageSortOptions::DeactivatePage( SfxItemSet* pSetP )
+{
+ bool bPosInputOk = true;
+
+ if ( m_xBtnCopyResult->get_active() )
+ {
+ OUString thePosStr = m_xEdOutPos->get_text();
+ ScAddress thePos;
+ sal_Int32 nColonPos = thePosStr.indexOf( ':' );
+
+ if ( -1 != nColonPos )
+ thePosStr = thePosStr.copy( 0, nColonPos );
+
+ if ( pViewData )
+ {
+ // visible table is default for input without table
+ // must be changed to GetRefTabNo when sorting has RefInput!
+ thePos.SetTab( pViewData->GetTabNo() );
+ }
+
+ ScRefFlags nResult = thePos.Parse( thePosStr, *pDoc, pDoc->GetAddressConvention() );
+
+ bPosInputOk = (nResult & ScRefFlags::VALID) == ScRefFlags::VALID;
+
+ if ( !bPosInputOk )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(STR_INVALID_TABREF)));
+ xBox->run();
+ m_xEdOutPos->grab_focus();
+ m_xEdOutPos->select_region(0, -1);
+ theOutPos.Set(0,0,0);
+ }
+ else
+ {
+ m_xEdOutPos->set_text(thePosStr);
+ theOutPos = thePos;
+ }
+ }
+
+ if ( pSetP && bPosInputOk )
+ FillItemSet( pSetP );
+
+ return bPosInputOk ? DeactivateRC::LeavePage : DeactivateRC::KeepPage;
+}
+
+void ScTabPageSortOptions::FillUserSortListBox()
+{
+ ScUserList* pUserLists = ScGlobal::GetUserList();
+
+ m_xLbSortUser->clear();
+ if ( pUserLists )
+ {
+ size_t nCount = pUserLists->size();
+ for (size_t i=0; i<nCount; ++i)
+ m_xLbSortUser->append_text((*pUserLists)[i].GetString());
+ }
+}
+
+// Handler:
+
+IMPL_LINK( ScTabPageSortOptions, EnableHdl, weld::Toggleable&, rButton, void )
+{
+ if (&rButton == m_xBtnCopyResult.get())
+ {
+ if (rButton.get_active())
+ {
+ m_xLbOutPos->set_sensitive(true);
+ m_xEdOutPos->set_sensitive(true);
+ m_xEdOutPos->grab_focus();
+ }
+ else
+ {
+ m_xLbOutPos->set_sensitive(false);
+ m_xEdOutPos->set_sensitive(false);
+ }
+ }
+ else if (&rButton == m_xBtnSortUser.get())
+ {
+ if (rButton.get_active())
+ {
+ m_xLbSortUser->set_sensitive(true);
+ m_xLbSortUser->grab_focus();
+ }
+ else
+ m_xLbSortUser->set_sensitive(false);
+ }
+}
+
+IMPL_LINK(ScTabPageSortOptions, SelOutPosHdl, weld::ComboBox&, rLb, void)
+{
+ if (&rLb == m_xLbOutPos.get())
+ {
+ OUString aString;
+ const int nSelPos = m_xLbOutPos->get_active();
+
+ if (nSelPos > 0)
+ aString = m_xLbOutPos->get_id(nSelPos);
+
+ m_xEdOutPos->set_text(aString);
+ }
+}
+
+void ScTabPageSortOptions::EdOutPosModHdl()
+{
+ OUString theCurPosStr = m_xEdOutPos->get_text();
+ ScRefFlags nResult = ScAddress().Parse( theCurPosStr, *pDoc, pDoc->GetAddressConvention() );
+
+ if ( (nResult & ScRefFlags::VALID) != ScRefFlags::VALID )
+ return;
+
+ bool bFound = false;
+ sal_Int32 i = 0;
+ const int nCount = m_xLbOutPos->get_count();
+
+ for ( i=2; i<nCount && !bFound; i++ )
+ {
+ OUString aStr = m_xLbOutPos->get_id(i);
+ bFound = (theCurPosStr == aStr);
+ }
+
+ if ( bFound )
+ m_xLbOutPos->set_active(--i);
+ else
+ m_xLbOutPos->set_active(0);
+}
+
+void ScTabPageSortOptions::FillAlgor()
+{
+ tools::Long nCount = 0;
+
+ m_xLbAlgorithm->freeze();
+ m_xLbAlgorithm->clear();
+
+ LanguageType eLang = m_xLbLanguage->get_active_id();
+ if ( eLang == LANGUAGE_SYSTEM )
+ {
+ // for LANGUAGE_SYSTEM no algorithm can be selected because
+ // it wouldn't necessarily exist for other languages
+ // -> leave list box empty if LANGUAGE_SYSTEM is selected
+ m_xFtAlgorithm->set_sensitive( false ); // nothing to select
+ m_xLbAlgorithm->set_sensitive( false ); // nothing to select
+ }
+ else
+ {
+ lang::Locale aLocale( LanguageTag::convertToLocale( eLang ));
+ const uno::Sequence<OUString> aAlgos = m_xColWrap->listCollatorAlgorithms( aLocale );
+
+ nCount = aAlgos.getLength();
+ for (const OUString& sAlg : aAlgos)
+ {
+ OUString sUser = m_xColRes->GetTranslation( sAlg );
+ m_xLbAlgorithm->append_text(sUser);
+ }
+ }
+
+ m_xLbAlgorithm->thaw();
+
+ m_xLbAlgorithm->set_active(nCount ? 0 : -1); // first entry is default
+ m_xFtAlgorithm->set_sensitive(nCount > 1); // enable only if there is a choice
+ m_xLbAlgorithm->set_sensitive(nCount > 1); // enable only if there is a choice
+}
+
+IMPL_LINK_NOARG(ScTabPageSortOptions, FillAlgorHdl, weld::ComboBox&, void)
+{
+ FillAlgor();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/tpsubt.cxx b/sc/source/ui/dbgui/tpsubt.cxx
new file mode 100644
index 000000000..01431c815
--- /dev/null
+++ b/sc/source/ui/dbgui/tpsubt.cxx
@@ -0,0 +1,621 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <scitems.hxx>
+#include <uiitems.hxx>
+#include <global.hxx>
+#include <userlist.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <scresid.hxx>
+#include <sc.hrc>
+#include <strings.hrc>
+#include <subtotals.hrc>
+
+#include <tpsubt.hxx>
+#include <tpsort.hxx>
+#include <memory>
+
+#include <osl/diagnose.h>
+
+// Subtotals group tabpage:
+
+ScTpSubTotalGroup::ScTpSubTotalGroup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet, const sal_uInt16& rTabNumber)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/subtotalgrppage.ui", "SubTotalGrpPage", &rArgSet)
+ , aStrNone(ScResId(SCSTR_NONE))
+ , aStrColumn(ScResId(SCSTR_COLUMN_LETTER))
+ , pViewData(nullptr)
+ , pDoc(nullptr)
+ , nWhichSubTotals(rArgSet.GetPool()->GetWhich(SID_SUBTOTALS))
+ , rSubTotalData(rArgSet.Get(nWhichSubTotals).GetSubTotalData())
+ , nFieldCount(0)
+ , mxLbGroup(m_xBuilder->weld_combo_box("group_by"))
+ , mxLbColumns(m_xBuilder->weld_tree_view("columns"))
+ , mxLbFunctions(m_xBuilder->weld_tree_view("functions"))
+ , mxLbSelectAllColumns(m_xBuilder->weld_check_button("select_all_columns_button"))
+{
+ for (size_t i = 0; i < SAL_N_ELEMENTS(SCSTR_SUBTOTALS); ++i)
+ mxLbFunctions->append_text(ScResId(SCSTR_SUBTOTALS[i]));
+
+ auto nHeight = mxLbColumns->get_height_rows(14);
+ mxLbColumns->set_size_request(-1, nHeight);
+ mxLbFunctions->set_size_request(-1, nHeight);
+
+ mxLbColumns->enable_toggle_buttons(weld::ColumnToggleType::Check);
+
+ Init();
+
+ // UI tests
+ mxLbGroup->set_buildable_name(mxLbGroup->get_buildable_name() + OString::number(rTabNumber));
+ mxLbColumns->set_buildable_name(mxLbColumns->get_buildable_name() + OString::number(rTabNumber));
+}
+
+ScTpSubTotalGroup::~ScTpSubTotalGroup()
+{
+}
+
+void ScTpSubTotalGroup::Init()
+{
+ const ScSubTotalItem& rSubTotalItem = GetItemSet().Get( nWhichSubTotals );
+
+ pViewData = rSubTotalItem.GetViewData();
+ assert(pViewData && "CreateScSubTotalDlg aArgSet must contain a ScSubTotalItem with ViewData set");
+ pDoc = &pViewData->GetDocument();
+ assert(pDoc && "Document not found :-(");
+
+ mxLbGroup->connect_changed( LINK( this, ScTpSubTotalGroup, SelectListBoxHdl ) );
+ mxLbColumns->connect_changed( LINK( this, ScTpSubTotalGroup, SelectTreeListBoxHdl ) );
+ mxLbColumns->connect_toggled( LINK( this, ScTpSubTotalGroup, CheckHdl ) );
+ mxLbFunctions->connect_changed( LINK( this, ScTpSubTotalGroup, SelectTreeListBoxHdl) );
+ mxLbSelectAllColumns->connect_toggled( LINK( this, ScTpSubTotalGroup, CheckBoxHdl ) );
+
+ mnFieldArr.resize(SC_MAXFIELDS(pDoc->GetSheetLimits()));
+ mnFieldArr[0] = 0;
+ FillListBoxes();
+}
+
+namespace
+{
+ int GetCheckedEntryCount(weld::TreeView& rTreeView)
+ {
+ int nRet = 0;
+
+ rTreeView.all_foreach([&](const weld::TreeIter& rEntry) {
+ if ( rTreeView.get_toggle(rEntry) == TRISTATE_TRUE )
+ ++nRet;
+ return false;
+ });
+
+ return nRet;
+ }
+}
+
+bool ScTpSubTotalGroup::DoReset( sal_uInt16 nGroupNo,
+ const SfxItemSet& rArgSet )
+{
+ sal_uInt16 nGroupIdx = 0;
+
+ OSL_ENSURE( (nGroupNo<=3) && (nGroupNo>0), "Invalid group" );
+
+ if ( (nGroupNo > 3) || (nGroupNo == 0) )
+ return false;
+ else
+ nGroupIdx = nGroupNo-1;
+
+ // first we have to clear the listboxes...
+ for (int nLbEntry = 0, nCount = mxLbColumns->n_children(); nLbEntry < nCount; ++nLbEntry)
+ {
+ mxLbColumns->set_toggle(nLbEntry, TRISTATE_FALSE);
+ mxLbColumns->set_id(nLbEntry, "0");
+ }
+ mxLbFunctions->select(0);
+
+ const ScSubTotalParam & theSubTotalData( rArgSet.Get( nWhichSubTotals ).GetSubTotalData() );
+
+ if ( theSubTotalData.bGroupActive[nGroupIdx] )
+ {
+ SCCOL nField = theSubTotalData.nField[nGroupIdx];
+ SCCOL nSubTotals = theSubTotalData.nSubTotals[nGroupIdx];
+ SCCOL* pSubTotals = theSubTotalData.pSubTotals[nGroupIdx].get();
+ ScSubTotalFunc* pFunctions = theSubTotalData.pFunctions[nGroupIdx].get();
+
+ mxLbGroup->set_active( GetFieldSelPos( nField )+1 );
+
+ sal_uInt16 nFirstChecked = 0;
+ for ( sal_uInt16 i=0; i<nSubTotals; i++ )
+ {
+ sal_uInt16 nCheckPos = GetFieldSelPos( pSubTotals[i] );
+
+ mxLbColumns->set_toggle(nCheckPos, TRISTATE_TRUE);
+ mxLbColumns->set_id(nCheckPos, OUString::number(FuncToLbPos(pFunctions[i])));
+
+ if (i == 0 || nCheckPos < nFirstChecked)
+ nFirstChecked = nCheckPos;
+ }
+ // Select the first checked field from the top.
+ mxLbColumns->select(nFirstChecked);
+ }
+ else
+ {
+ mxLbGroup->set_active( (nGroupNo == 1) ? 1 : 0 );
+ mxLbColumns->select( 0 );
+ mxLbFunctions->select( 0 );
+ }
+
+ if ( mxLbColumns->n_children() == GetCheckedEntryCount(*mxLbColumns) )
+ mxLbSelectAllColumns->set_active( true );
+ else
+ mxLbSelectAllColumns->set_active( false );
+
+ return true;
+}
+
+bool ScTpSubTotalGroup::DoFillItemSet( sal_uInt16 nGroupNo,
+ SfxItemSet& rArgSet )
+{
+ sal_uInt16 nGroupIdx = 0;
+
+ OSL_ENSURE( (nGroupNo<=3) && (nGroupNo>0), "Invalid group" );
+ OSL_ENSURE( (mxLbGroup->get_count() > 0)
+ && (mxLbColumns->n_children() > 0)
+ && (mxLbFunctions->n_children() > 0),
+ "Non-initialized Lists" );
+
+ if ( (nGroupNo > 3) || (nGroupNo == 0)
+ || (mxLbGroup->get_count() == 0)
+ || (mxLbColumns->n_children() == 0)
+ || (mxLbFunctions->n_children() == 0)
+ )
+ return false;
+ else
+ nGroupIdx = nGroupNo-1;
+
+ ScSubTotalParam theSubTotalData; // read out, if already partly filled
+ const SfxItemSet* pExample = GetDialogExampleSet();
+ if (pExample)
+ {
+ if (const ScSubTotalItem* pItem = pExample->GetItemIfSet(nWhichSubTotals))
+ theSubTotalData = pItem->GetSubTotalData();
+ }
+
+ std::unique_ptr<ScSubTotalFunc[]> pFunctions;
+ std::unique_ptr<SCCOL[]> pSubTotals;
+ const sal_Int32 nGroup = mxLbGroup->get_active();
+ const sal_Int32 nEntryCount = mxLbColumns->n_children();
+ const sal_Int32 nCheckCount = GetCheckedEntryCount(*mxLbColumns);
+
+ theSubTotalData.nCol1 = rSubTotalData.nCol1;
+ theSubTotalData.nRow1 = rSubTotalData.nRow1;
+ theSubTotalData.nCol2 = rSubTotalData.nCol2;
+ theSubTotalData.nRow2 = rSubTotalData.nRow2;
+ theSubTotalData.bGroupActive[nGroupIdx] = (nGroup != 0);
+ theSubTotalData.nField[nGroupIdx] = (nGroup != 0)
+ ? mnFieldArr[nGroup-1]
+ : static_cast<SCCOL>(0);
+
+ if ( nEntryCount>0 && nCheckCount>0 && nGroup!=0 )
+ {
+ sal_uInt16 nFunction = 0;
+
+ pSubTotals.reset(new SCCOL [nCheckCount]);
+ pFunctions.reset(new ScSubTotalFunc [nCheckCount]);
+
+ for ( sal_Int32 i=0, nCheck=0; i<nEntryCount; i++ )
+ {
+ if (mxLbColumns->get_toggle(i) == TRISTATE_TRUE)
+ {
+ OSL_ENSURE( nCheck <= nCheckCount,
+ "Range error :-(" );
+ nFunction = mxLbColumns->get_id(i).toUInt32();
+ pSubTotals[nCheck] = mnFieldArr[i];
+ pFunctions[nCheck] = LbPosToFunc( nFunction );
+ nCheck++;
+ }
+ }
+ theSubTotalData.SetSubTotals( nGroupNo, // group number
+ pSubTotals.get(),
+ pFunctions.get(),
+ nCheckCount ); // number of array elements
+
+ }
+
+ rArgSet.Put( ScSubTotalItem( SCITEM_SUBTDATA, nullptr, &theSubTotalData ) );
+
+ return true;
+}
+
+void ScTpSubTotalGroup::FillListBoxes()
+{
+ assert(pViewData && pDoc && "CreateScSubTotalDlg aArgSet must contain a ScSubTotalItem with ViewData set");
+
+ SCCOL nFirstCol = rSubTotalData.nCol1;
+ SCROW nFirstRow = rSubTotalData.nRow1;
+ SCTAB nTab = pViewData->GetTabNo();
+ SCCOL nMaxCol = rSubTotalData.nCol2;
+ SCCOL col;
+ OUString aFieldName;
+
+ mxLbGroup->clear();
+ mxLbColumns->clear();
+ mxLbGroup->insert_text(0, aStrNone );
+
+ mxLbColumns->freeze();
+ sal_uInt16 i=0;
+ for ( col=nFirstCol; col<=nMaxCol && i<SC_MAXFIELDS(pDoc->GetSheetLimits()); col++ )
+ {
+ aFieldName = pDoc->GetString(col, nFirstRow, nTab);
+ if ( aFieldName.isEmpty() )
+ {
+ aFieldName = ScGlobal::ReplaceOrAppend( aStrColumn, u"%1", ScColToAlpha( col ));
+ }
+ mnFieldArr[i] = col;
+ mxLbGroup->insert_text(i+1, aFieldName);
+ mxLbColumns->insert(i);
+ mxLbColumns->set_toggle(i, TRISTATE_FALSE);
+ mxLbColumns->set_text(i, aFieldName, 0);
+ mxLbColumns->set_id(i, "0");
+ i++;
+ }
+ mxLbColumns->thaw();
+
+ // subsequent initialization of the constant:
+ nFieldCount = i;
+}
+
+sal_uInt16 ScTpSubTotalGroup::GetFieldSelPos( SCCOL nField )
+{
+ sal_uInt16 nFieldPos = 0;
+ bool bFound = false;
+
+ for ( sal_uInt16 n=0; n<nFieldCount && !bFound; n++ )
+ {
+ if ( mnFieldArr[n] == nField )
+ {
+ nFieldPos = n;
+ bFound = true;
+ }
+ }
+
+ return nFieldPos;
+}
+
+ScSubTotalFunc ScTpSubTotalGroup::LbPosToFunc( sal_uInt16 nPos )
+{
+ switch ( nPos )
+ {
+// case 0: return SUBTOTAL_FUNC_NONE;
+ case 2: return SUBTOTAL_FUNC_AVE;
+ case 6: return SUBTOTAL_FUNC_CNT;
+ case 1: return SUBTOTAL_FUNC_CNT2;
+ case 3: return SUBTOTAL_FUNC_MAX;
+ case 4: return SUBTOTAL_FUNC_MIN;
+ case 5: return SUBTOTAL_FUNC_PROD;
+ case 7: return SUBTOTAL_FUNC_STD;
+ case 8: return SUBTOTAL_FUNC_STDP;
+ case 0: return SUBTOTAL_FUNC_SUM;
+ case 9: return SUBTOTAL_FUNC_VAR;
+ case 10: return SUBTOTAL_FUNC_VARP;
+ default:
+ OSL_FAIL( "ScTpSubTotalGroup::LbPosToFunc" );
+ return SUBTOTAL_FUNC_NONE;
+ }
+}
+
+sal_uInt16 ScTpSubTotalGroup::FuncToLbPos( ScSubTotalFunc eFunc )
+{
+ switch ( eFunc )
+ {
+// case SUBTOTAL_FUNC_NONE: return 0;
+ case SUBTOTAL_FUNC_AVE: return 2;
+ case SUBTOTAL_FUNC_CNT: return 6;
+ case SUBTOTAL_FUNC_CNT2: return 1;
+ case SUBTOTAL_FUNC_MAX: return 3;
+ case SUBTOTAL_FUNC_MIN: return 4;
+ case SUBTOTAL_FUNC_PROD: return 5;
+ case SUBTOTAL_FUNC_STD: return 7;
+ case SUBTOTAL_FUNC_STDP: return 8;
+ case SUBTOTAL_FUNC_SUM: return 0;
+ case SUBTOTAL_FUNC_VAR: return 9;
+ case SUBTOTAL_FUNC_VARP: return 10;
+ default:
+ OSL_FAIL( "ScTpSubTotalGroup::FuncToLbPos" );
+ return 0;
+ }
+}
+
+// Handler:
+
+IMPL_LINK(ScTpSubTotalGroup, SelectTreeListBoxHdl, weld::TreeView&, rLb, void)
+{
+ SelectHdl(&rLb);
+
+ if ( mxLbColumns->n_children() == GetCheckedEntryCount(*mxLbColumns) )
+ mxLbSelectAllColumns->set_active( true );
+ else
+ mxLbSelectAllColumns->set_active( false );
+}
+
+IMPL_LINK(ScTpSubTotalGroup, SelectListBoxHdl, weld::ComboBox&, rLb, void)
+{
+ SelectHdl(&rLb);
+}
+
+void ScTpSubTotalGroup::SelectHdl(const weld::Widget *pLb)
+{
+ const sal_Int32 nColumn = mxLbColumns->get_selected_index();
+ if (nColumn == -1)
+ return;
+
+ const sal_Int32 nFunction = mxLbFunctions->get_selected_index();
+ sal_uInt16 nOldFunction = mxLbColumns->get_id(nColumn).toUInt32();
+
+ if ( pLb == mxLbColumns.get() )
+ {
+ mxLbFunctions->select(nOldFunction);
+ }
+ else if ( pLb == mxLbFunctions.get() )
+ {
+ mxLbColumns->set_id(nColumn, OUString::number(nFunction));
+ mxLbColumns->set_toggle(nColumn, TRISTATE_TRUE);
+ }
+}
+
+IMPL_LINK( ScTpSubTotalGroup, CheckHdl, const weld::TreeView::iter_col&, rRowCol, void )
+{
+ mxLbColumns->select(rRowCol.first);
+ SelectHdl(mxLbColumns.get());
+
+ if ( mxLbColumns->n_children() == GetCheckedEntryCount(*mxLbColumns) )
+ mxLbSelectAllColumns->set_active( true );
+ else
+ mxLbSelectAllColumns->set_active( false );
+}
+
+// Derived Group TabPages:
+
+std::unique_ptr<SfxTabPage> ScTpSubTotalGroup1::Create( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rArgSet )
+{
+ return std::make_unique<ScTpSubTotalGroup1>( pPage, pController, *rArgSet );
+}
+
+std::unique_ptr<SfxTabPage> ScTpSubTotalGroup2::Create( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rArgSet )
+{
+ return std::make_unique<ScTpSubTotalGroup2>( pPage, pController, *rArgSet );
+}
+
+std::unique_ptr<SfxTabPage> ScTpSubTotalGroup3::Create( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rArgSet )
+{
+ return std::make_unique<ScTpSubTotalGroup3>( pPage, pController, *rArgSet );
+}
+
+ScTpSubTotalGroup1::ScTpSubTotalGroup1( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet ) :
+ ScTpSubTotalGroup( pPage, pController, rArgSet, 1 )
+{}
+
+ScTpSubTotalGroup2::ScTpSubTotalGroup2( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet ) :
+ ScTpSubTotalGroup( pPage, pController, rArgSet, 2 )
+{}
+
+ScTpSubTotalGroup3::ScTpSubTotalGroup3( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet ) :
+ ScTpSubTotalGroup( pPage, pController, rArgSet, 3 )
+{}
+
+#define RESET(i) (ScTpSubTotalGroup::DoReset( (i), *rArgSet ))
+void ScTpSubTotalGroup1::Reset( const SfxItemSet* rArgSet ) { RESET(1); }
+void ScTpSubTotalGroup2::Reset( const SfxItemSet* rArgSet ) { RESET(2); }
+void ScTpSubTotalGroup3::Reset( const SfxItemSet* rArgSet ) { RESET(3); }
+#undef RESET
+
+#define FILLSET(i) (ScTpSubTotalGroup::DoFillItemSet( (i), *rArgSet ))
+bool ScTpSubTotalGroup1::FillItemSet( SfxItemSet* rArgSet ) { return FILLSET(1); }
+bool ScTpSubTotalGroup2::FillItemSet( SfxItemSet* rArgSet ) { return FILLSET(2); }
+bool ScTpSubTotalGroup3::FillItemSet( SfxItemSet* rArgSet ) { return FILLSET(3); }
+#undef FILL
+
+// options tab page:
+
+ScTpSubTotalOptions::ScTpSubTotalOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet)
+
+ : SfxTabPage ( pPage, pController,
+ "modules/scalc/ui/subtotaloptionspage.ui", "SubTotalOptionsPage",
+ &rArgSet ),
+ pViewData ( nullptr ),
+ pDoc ( nullptr ),
+ nWhichSubTotals ( rArgSet.GetPool()->GetWhich( SID_SUBTOTALS ) ),
+ rSubTotalData ( rArgSet.Get( nWhichSubTotals ).GetSubTotalData() )
+ , m_xBtnPagebreak(m_xBuilder->weld_check_button("pagebreak"))
+ , m_xBtnCase(m_xBuilder->weld_check_button("case"))
+ , m_xBtnSort(m_xBuilder->weld_check_button("sort"))
+ , m_xFlSort(m_xBuilder->weld_label("label2"))
+ , m_xBtnAscending(m_xBuilder->weld_radio_button("ascending"))
+ , m_xBtnDescending(m_xBuilder->weld_radio_button("descending"))
+ , m_xBtnFormats(m_xBuilder->weld_check_button("formats"))
+ , m_xBtnUserDef(m_xBuilder->weld_check_button("btnuserdef"))
+ , m_xLbUserDef(m_xBuilder->weld_combo_box("lbuserdef"))
+{
+ m_xLbUserDef->set_accessible_description(ScResId(STR_A11Y_DESC_USERDEF));
+ m_xBtnUserDef->set_accessible_description(ScResId(STR_A11Y_DESC_USERDEF));
+ Init();
+}
+
+ScTpSubTotalOptions::~ScTpSubTotalOptions()
+{
+}
+
+void ScTpSubTotalOptions::Init()
+{
+ const ScSubTotalItem& rSubTotalItem = GetItemSet().Get( nWhichSubTotals );
+
+ pViewData = rSubTotalItem.GetViewData();
+ assert(pViewData && "CreateScSubTotalDlg aArgSet must contain a ScSubTotalItem with ViewData set");
+ pDoc = &pViewData->GetDocument();
+ assert(pDoc && "Document not found!");
+
+ m_xBtnSort->connect_toggled( LINK( this, ScTpSubTotalOptions, CheckHdl ) );
+ m_xBtnUserDef->connect_toggled( LINK( this, ScTpSubTotalOptions, CheckHdl ) );
+
+ FillUserSortListBox();
+}
+
+std::unique_ptr<SfxTabPage> ScTpSubTotalOptions::Create(weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rArgSet)
+{
+ return std::make_unique<ScTpSubTotalOptions>(pPage, pController, *rArgSet);
+}
+
+void ScTpSubTotalOptions::Reset( const SfxItemSet* /* rArgSet */ )
+{
+ m_xBtnPagebreak->set_active( rSubTotalData.bPagebreak );
+ m_xBtnCase->set_active( rSubTotalData.bCaseSens );
+ m_xBtnFormats->set_active( rSubTotalData.bIncludePattern );
+ m_xBtnSort->set_active( rSubTotalData.bDoSort );
+ m_xBtnAscending->set_active( rSubTotalData.bAscending );
+ m_xBtnDescending->set_active( !rSubTotalData.bAscending );
+
+ if ( rSubTotalData.bUserDef )
+ {
+ m_xBtnUserDef->set_active(true);
+ m_xLbUserDef->set_sensitive(true);
+ m_xLbUserDef->set_active(rSubTotalData.nUserIndex);
+ }
+ else
+ {
+ m_xBtnUserDef->set_active( false );
+ m_xLbUserDef->set_sensitive(false);
+ m_xLbUserDef->set_active(0);
+ }
+
+ CheckHdl(*m_xBtnSort);
+}
+
+bool ScTpSubTotalOptions::FillItemSet( SfxItemSet* rArgSet )
+{
+ ScSubTotalParam theSubTotalData; // read out, if already partly filled
+ const SfxItemSet* pExample = GetDialogExampleSet();
+ if (pExample)
+ {
+ if (const ScSubTotalItem* pItem = pExample->GetItemIfSet(nWhichSubTotals))
+ theSubTotalData = pItem->GetSubTotalData();
+ }
+
+ theSubTotalData.bPagebreak = m_xBtnPagebreak->get_active();
+ theSubTotalData.bReplace = true;
+ theSubTotalData.bCaseSens = m_xBtnCase->get_active();
+ theSubTotalData.bIncludePattern = m_xBtnFormats->get_active();
+ theSubTotalData.bDoSort = m_xBtnSort->get_active();
+ theSubTotalData.bAscending = m_xBtnAscending->get_active();
+ theSubTotalData.bUserDef = m_xBtnUserDef->get_active();
+ theSubTotalData.nUserIndex = (m_xBtnUserDef->get_active())
+ ? m_xLbUserDef->get_active()
+ : 0;
+
+ rArgSet->Put( ScSubTotalItem( nWhichSubTotals, nullptr, &theSubTotalData ) );
+
+ return true;
+}
+
+void ScTpSubTotalOptions::FillUserSortListBox()
+{
+ ScUserList* pUserLists = ScGlobal::GetUserList();
+
+ m_xLbUserDef->freeze();
+ m_xLbUserDef->clear();
+ if ( pUserLists )
+ {
+ size_t nCount = pUserLists->size();
+ for ( size_t i=0; i<nCount; ++i )
+ m_xLbUserDef->append_text((*pUserLists)[i].GetString() );
+ }
+ m_xLbUserDef->thaw();
+}
+
+// Handler:
+
+IMPL_LINK(ScTpSubTotalOptions, CheckHdl, weld::Toggleable&, rBox, void)
+{
+ if (&rBox == m_xBtnSort.get())
+ {
+ if ( m_xBtnSort->get_active() )
+ {
+ m_xFlSort->set_sensitive(true);
+ m_xBtnFormats->set_sensitive(true);
+ m_xBtnUserDef->set_sensitive(true);
+ m_xBtnAscending->set_sensitive(true);
+ m_xBtnDescending->set_sensitive(true);
+
+ if ( m_xBtnUserDef->get_active() )
+ m_xLbUserDef->set_sensitive(true);
+ }
+ else
+ {
+ m_xFlSort->set_sensitive(false);
+ m_xBtnFormats->set_sensitive(false);
+ m_xBtnUserDef->set_sensitive(false);
+ m_xBtnAscending->set_sensitive(false);
+ m_xBtnDescending->set_sensitive(false);
+ m_xLbUserDef->set_sensitive(false);
+ }
+ }
+ else if (&rBox == m_xBtnUserDef.get())
+ {
+ if ( m_xBtnUserDef->get_active() )
+ {
+ m_xLbUserDef->set_sensitive(true);
+ m_xLbUserDef->grab_focus();
+ }
+ else
+ m_xLbUserDef->set_sensitive(false);
+ }
+}
+
+IMPL_LINK(ScTpSubTotalGroup, CheckBoxHdl, weld::Toggleable&, rBox, void)
+{
+ if (&rBox != mxLbSelectAllColumns.get())
+ return;
+
+ bool bChecked = mxLbSelectAllColumns->get_active();
+
+ mxLbColumns->all_foreach([&](const weld::TreeIter& rEntry) {
+ if ( bChecked )
+ mxLbColumns->set_toggle(rEntry, TRISTATE_TRUE);
+ else
+ mxLbColumns->set_toggle(rEntry, TRISTATE_FALSE);
+
+ return false;
+ });
+}
+
+ScTpSubTotalGroup1::~ScTpSubTotalGroup1()
+{
+}
+
+ScTpSubTotalGroup2::~ScTpSubTotalGroup2()
+{
+}
+
+ScTpSubTotalGroup3::~ScTpSubTotalGroup3()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dbgui/validate.cxx b/sc/source/ui/dbgui/validate.cxx
new file mode 100644
index 000000000..d194fdc10
--- /dev/null
+++ b/sc/source/ui/dbgui/validate.cxx
@@ -0,0 +1,927 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#ifdef SC_DLLIMPLEMENTATION
+#undef SC_DLLIMPLEMENTATION
+#endif
+
+#include <com/sun/star/sheet/TableValidationVisibility.hpp>
+#include <comphelper/string.hxx>
+#include <svl/stritem.hxx>
+#include <svl/eitem.hxx>
+#include <svl/intitem.hxx>
+#include <sfx2/app.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <scresid.hxx>
+#include <strings.hrc>
+
+#include <stringutil.hxx>
+#include <validat.hxx>
+#include <validate.hxx>
+#include <compiler.hxx>
+#include <formula/opcode.hxx>
+
+// cell range picker
+#include <tabvwsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/childwin.hxx>
+#include <reffact.hxx>
+#include <comphelper/lok.hxx>
+
+
+#define IS_MOBILE (comphelper::LibreOfficeKit::isActive() && SfxViewShell::Current() && SfxViewShell::Current()->isLOKMobilePhone())
+
+/* Position indexes for "Allow" list box.
+ They do not map directly to ScValidationMode and can safely be modified to
+ change the order of the list box entries. */
+#define SC_VALIDDLG_ALLOW_ANY 0
+#define SC_VALIDDLG_ALLOW_WHOLE 1
+#define SC_VALIDDLG_ALLOW_DECIMAL 2
+#define SC_VALIDDLG_ALLOW_DATE 3
+#define SC_VALIDDLG_ALLOW_TIME 4
+#define SC_VALIDDLG_ALLOW_RANGE 5
+#define SC_VALIDDLG_ALLOW_LIST 6
+#define SC_VALIDDLG_ALLOW_TEXTLEN 7
+#define SC_VALIDDLG_ALLOW_CUSTOM 8
+
+/* Position indexes for "Data" list box.
+ They do not map directly to ScConditionMode and can safely be modified to
+ change the order of the list box entries. */
+#define SC_VALIDDLG_DATA_EQUAL 0
+#define SC_VALIDDLG_DATA_LESS 1
+#define SC_VALIDDLG_DATA_GREATER 2
+#define SC_VALIDDLG_DATA_EQLESS 3
+#define SC_VALIDDLG_DATA_EQGREATER 4
+#define SC_VALIDDLG_DATA_NOTEQUAL 5
+#define SC_VALIDDLG_DATA_VALIDRANGE 6
+#define SC_VALIDDLG_DATA_INVALIDRANGE 7
+#define SC_VALIDDLG_DATA_DIRECT 8
+
+namespace ValidListType = css::sheet::TableValidationVisibility;
+
+const WhichRangesContainer ScTPValidationValue::pValueRanges(svl::Items<
+ FID_VALID_LISTTYPE, FID_VALID_LISTTYPE,
+ FID_VALID_MODE, FID_VALID_ERRTEXT
+>);
+
+ScValidationDlg::ScValidationDlg(weld::Window* pParent, const SfxItemSet* pArgSet,
+ ScTabViewShell *pTabViewSh)
+ : ScValidationDlgBase(pParent,
+ "modules/scalc/ui/validationdialog.ui", "ValidationDialog", pArgSet, nullptr)
+ , m_pTabVwSh(pTabViewSh)
+ , m_sValuePageId("criteria")
+ , m_bOwnRefHdlr(false)
+ , m_bRefInputting(false)
+ , m_xHBox(m_xBuilder->weld_container("refinputbox"))
+{
+ AddTabPage(m_sValuePageId, ScTPValidationValue::Create, nullptr);
+ AddTabPage("inputhelp", ScTPValidationHelp::Create, nullptr);
+ AddTabPage("erroralert", ScTPValidationError::Create, nullptr);
+
+ if (IS_MOBILE)
+ {
+ m_xBuilder->weld_button("cancel")->hide();
+ m_xBuilder->weld_button("help")->hide();
+ }
+}
+
+void ScValidationDlg::EndDialog(int nResponse)
+{
+ // tdf#137215 ensure original modality of true is restored before dialog loop ends
+ if (m_bOwnRefHdlr)
+ RemoveRefDlg(true);
+ ScValidationDlgBase::EndDialog(nResponse);
+}
+
+ScValidationDlg::~ScValidationDlg()
+{
+ if (m_bOwnRefHdlr)
+ RemoveRefDlg(false);
+}
+
+void ScTPValidationValue::SetReferenceHdl( const ScRange&rRange , const ScDocument& rDoc )
+{
+ if ( rRange.aStart != rRange.aEnd )
+ if ( ScValidationDlg *pValidationDlg = GetValidationDlg() )
+ if( m_pRefEdit )
+ pValidationDlg->RefInputStart( m_pRefEdit );
+
+ if ( m_pRefEdit )
+ {
+ OUString aStr(rRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()));
+ m_pRefEdit->SetRefString( aStr );
+ }
+}
+
+void ScTPValidationValue:: SetActiveHdl()
+{
+ if ( m_pRefEdit ) m_pRefEdit->GrabFocus();
+
+ if ( ScValidationDlg *pValidationDlg = GetValidationDlg() )
+ if( m_pRefEdit )
+ {
+ pValidationDlg->RefInputDone();
+ }
+}
+
+void ScTPValidationValue::RefInputStartPreHdl( formula::RefEdit* pEdit, const formula::RefButton* pButton )
+{
+ ScValidationDlg *pValidationDlg = GetValidationDlg();
+ if (!pValidationDlg)
+ return;
+
+ weld::Container* pNewParent = pValidationDlg->get_refinput_shrink_parent();
+ if (pEdit == m_pRefEdit && pNewParent != m_pRefEditParent)
+ {
+ m_xRefGrid->move(m_pRefEdit->GetWidget(), pNewParent);
+ m_pRefEditParent = pNewParent;
+ }
+
+ if (pNewParent != m_pBtnRefParent)
+ {
+ // if Edit SetParent but button not, the tab order will be
+ // incorrect, so move button anyway, and restore
+ // parent later in order to restore the tab order. But
+ // hide it if it's moved but unwanted.
+ m_xRefGrid->move(m_xBtnRef->GetWidget(), pNewParent);
+ m_xBtnRef->GetWidget()->set_visible(pButton == m_xBtnRef.get());
+ m_pBtnRefParent = pNewParent;
+ }
+
+ pNewParent->show();
+}
+
+void ScTPValidationValue::RefInputDonePostHdl()
+{
+ if (ScValidationDlg *pValidationDlg = GetValidationDlg())
+ {
+ weld::Container* pOldParent = pValidationDlg->get_refinput_shrink_parent();
+
+ if (m_pRefEdit && m_pRefEditParent != m_xRefGrid.get())
+ {
+ pOldParent->move(m_pRefEdit->GetWidget(), m_xRefGrid.get());
+ m_pRefEditParent = m_xRefGrid.get();
+ }
+
+ if (m_pBtnRefParent != m_xRefGrid.get())
+ {
+ pOldParent->move(m_xBtnRef->GetWidget(), m_xRefGrid.get());
+ m_xBtnRef->GetWidget()->show();
+ m_pBtnRefParent = m_xRefGrid.get();
+ }
+
+ pOldParent->hide();
+ ScViewData& rViewData = pValidationDlg->GetTabViewShell()->GetViewData();
+ SCTAB nCurTab = rViewData.GetTabNo();
+ SCTAB nRefTab = rViewData.GetRefTabNo();
+ // If RefInput switched to a different sheet from the data sheet,
+ // switch back: fdo#53920
+ if ( nCurTab != nRefTab )
+ {
+ rViewData.GetViewShell()->SetTabNo( nRefTab );
+ }
+ }
+
+ if (m_pRefEdit && !m_pRefEdit->GetWidget()->has_focus())
+ m_pRefEdit->GrabFocus();
+}
+
+namespace {
+
+/** Converts the passed ScValidationMode to the position in the list box. */
+sal_uInt16 lclGetPosFromValMode( ScValidationMode eValMode )
+{
+ sal_uInt16 nLbPos = SC_VALIDDLG_ALLOW_ANY;
+ switch( eValMode )
+ {
+ case SC_VALID_ANY: nLbPos = SC_VALIDDLG_ALLOW_ANY; break;
+ case SC_VALID_WHOLE: nLbPos = SC_VALIDDLG_ALLOW_WHOLE; break;
+ case SC_VALID_DECIMAL: nLbPos = SC_VALIDDLG_ALLOW_DECIMAL; break;
+ case SC_VALID_DATE: nLbPos = SC_VALIDDLG_ALLOW_DATE; break;
+ case SC_VALID_TIME: nLbPos = SC_VALIDDLG_ALLOW_TIME; break;
+ case SC_VALID_TEXTLEN: nLbPos = SC_VALIDDLG_ALLOW_TEXTLEN; break;
+ case SC_VALID_LIST: nLbPos = SC_VALIDDLG_ALLOW_RANGE; break;
+ case SC_VALID_CUSTOM: nLbPos = SC_VALIDDLG_ALLOW_CUSTOM; break;
+ default: OSL_FAIL( "lclGetPosFromValMode - unknown validity mode" );
+ }
+ return nLbPos;
+}
+
+/** Converts the passed list box position to an ScValidationMode. */
+ScValidationMode lclGetValModeFromPos( sal_uInt16 nLbPos )
+{
+ ScValidationMode eValMode = SC_VALID_ANY;
+ switch( nLbPos )
+ {
+ case SC_VALIDDLG_ALLOW_ANY: eValMode = SC_VALID_ANY; break;
+ case SC_VALIDDLG_ALLOW_WHOLE: eValMode = SC_VALID_WHOLE; break;
+ case SC_VALIDDLG_ALLOW_DECIMAL: eValMode = SC_VALID_DECIMAL; break;
+ case SC_VALIDDLG_ALLOW_DATE: eValMode = SC_VALID_DATE; break;
+ case SC_VALIDDLG_ALLOW_TIME: eValMode = SC_VALID_TIME; break;
+ case SC_VALIDDLG_ALLOW_RANGE: eValMode = SC_VALID_LIST; break;
+ case SC_VALIDDLG_ALLOW_LIST: eValMode = SC_VALID_LIST; break;
+ case SC_VALIDDLG_ALLOW_TEXTLEN: eValMode = SC_VALID_TEXTLEN; break;
+ case SC_VALIDDLG_ALLOW_CUSTOM: eValMode = SC_VALID_CUSTOM; break;
+ default: OSL_FAIL( "lclGetValModeFromPos - invalid list box position" );
+ }
+ return eValMode;
+}
+
+/** Converts the passed ScConditionMode to the position in the list box. */
+sal_uInt16 lclGetPosFromCondMode( ScConditionMode eCondMode )
+{
+ sal_uInt16 nLbPos = SC_VALIDDLG_DATA_EQUAL;
+ switch( eCondMode )
+ {
+ case ScConditionMode::NONE: // may occur in old XML files after Excel import
+ case ScConditionMode::Equal: nLbPos = SC_VALIDDLG_DATA_EQUAL; break;
+ case ScConditionMode::Less: nLbPos = SC_VALIDDLG_DATA_LESS; break;
+ case ScConditionMode::Greater: nLbPos = SC_VALIDDLG_DATA_GREATER; break;
+ case ScConditionMode::EqLess: nLbPos = SC_VALIDDLG_DATA_EQLESS; break;
+ case ScConditionMode::EqGreater: nLbPos = SC_VALIDDLG_DATA_EQGREATER; break;
+ case ScConditionMode::NotEqual: nLbPos = SC_VALIDDLG_DATA_NOTEQUAL; break;
+ case ScConditionMode::Between: nLbPos = SC_VALIDDLG_DATA_VALIDRANGE; break;
+ case ScConditionMode::NotBetween: nLbPos = SC_VALIDDLG_DATA_INVALIDRANGE; break;
+ case ScConditionMode::Direct: nLbPos = SC_VALIDDLG_DATA_DIRECT; break;
+ default: OSL_FAIL( "lclGetPosFromCondMode - unknown condition mode" );
+ }
+ return nLbPos;
+}
+
+/** Converts the passed list box position to an ScConditionMode. */
+ScConditionMode lclGetCondModeFromPos( sal_uInt16 nLbPos )
+{
+ ScConditionMode eCondMode = ScConditionMode::Equal;
+ switch( nLbPos )
+ {
+ case SC_VALIDDLG_DATA_EQUAL: eCondMode = ScConditionMode::Equal; break;
+ case SC_VALIDDLG_DATA_LESS: eCondMode = ScConditionMode::Less; break;
+ case SC_VALIDDLG_DATA_GREATER: eCondMode = ScConditionMode::Greater; break;
+ case SC_VALIDDLG_DATA_EQLESS: eCondMode = ScConditionMode::EqLess; break;
+ case SC_VALIDDLG_DATA_EQGREATER: eCondMode = ScConditionMode::EqGreater; break;
+ case SC_VALIDDLG_DATA_NOTEQUAL: eCondMode = ScConditionMode::NotEqual; break;
+ case SC_VALIDDLG_DATA_VALIDRANGE: eCondMode = ScConditionMode::Between; break;
+ case SC_VALIDDLG_DATA_INVALIDRANGE: eCondMode = ScConditionMode::NotBetween; break;
+ case SC_VALIDDLG_DATA_DIRECT: eCondMode = ScConditionMode::Direct; break;
+ default: OSL_FAIL( "lclGetCondModeFromPos - invalid list box position" );
+ }
+ return eCondMode;
+}
+
+/** Converts line feed separated string to a formula with strings separated by semicolons.
+ @descr Keeps all empty strings.
+ Example: abc\ndef\n\nghi -> "abc";"def";"";"ghi".
+ @param rFmlaStr (out-param) The converted formula string. */
+void lclGetFormulaFromStringList( OUString& rFmlaStr, std::u16string_view rStringList, sal_Unicode cFmlaSep )
+{
+ rFmlaStr.clear();
+ if (!rStringList.empty())
+ {
+ sal_Int32 nIdx {0};
+ do
+ {
+ OUString aToken {o3tl::getToken(rStringList, 0, '\n', nIdx )};
+ ScGlobal::AddQuotes( aToken, '"' );
+ rFmlaStr = ScGlobal::addToken(rFmlaStr, aToken, cFmlaSep);
+ }
+ while (nIdx>0);
+ }
+ if( rFmlaStr.isEmpty() )
+ rFmlaStr = "\"\"";
+}
+
+/** Converts formula with strings separated by semicolons to line feed separated string.
+ @descr Keeps all empty strings. Ignores all empty tokens (multiple semicolons).
+ Example: "abc";;;"def";"";"ghi" -> abc\ndef\n\nghi.
+ @param rStringList (out-param) The converted line feed separated string list.
+ @return true = Conversion successful. */
+bool lclGetStringListFromFormula( OUString& rStringList, const OUString& rFmlaStr, sal_Unicode cFmlaSep )
+{
+ static const OUStringLiteral aQuotes( u"\"\"" );
+
+ rStringList.clear();
+ bool bIsStringList = !rFmlaStr.isEmpty();
+ bool bTokenAdded = false;
+
+ for ( sal_Int32 nStringIx = 0; bIsStringList && nStringIx>=0; )
+ {
+ OUString aToken( ScStringUtil::GetQuotedToken(rFmlaStr, 0, aQuotes, cFmlaSep, nStringIx ) );
+ aToken = comphelper::string::strip(aToken, ' ');
+ if( !aToken.isEmpty() ) // ignore empty tokens, i.e. "a";;"b"
+ {
+ bIsStringList = ScGlobal::IsQuoted( aToken, '"' );
+ if( bIsStringList )
+ {
+ ScGlobal::EraseQuotes( aToken, '"' );
+ rStringList = ScGlobal::addToken(rStringList, aToken, '\n', 1, bTokenAdded);
+ bTokenAdded = true;
+ }
+ }
+ }
+
+ return bIsStringList;
+}
+
+} // namespace
+
+ScTPValidationValue::ScTPValidationValue(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/validationcriteriapage.ui",
+ "ValidationCriteriaPage", &rArgSet)
+ , maStrMin(ScResId(SCSTR_VALID_MINIMUM))
+ , maStrMax(ScResId(SCSTR_VALID_MAXIMUM))
+ , maStrValue(ScResId(SCSTR_VALID_VALUE))
+ , maStrFormula(ScResId(SCSTR_VALID_FORMULA))
+ , maStrRange(ScResId(SCSTR_VALID_RANGE))
+ , maStrList(ScResId(SCSTR_VALID_LIST))
+ , m_pRefEdit(nullptr)
+ , m_xLbAllow(m_xBuilder->weld_combo_box("allow"))
+ , m_xCbAllow(m_xBuilder->weld_check_button("allowempty"))
+ , m_xCbShow(m_xBuilder->weld_check_button("showlist"))
+ , m_xCbSort(m_xBuilder->weld_check_button("sortascend"))
+ , m_xFtValue(m_xBuilder->weld_label("valueft"))
+ , m_xLbValue(m_xBuilder->weld_combo_box("data"))
+ , m_xFtMin(m_xBuilder->weld_label("minft"))
+ , m_xMinGrid(m_xBuilder->weld_widget("mingrid"))
+ , m_xEdMin(new formula::RefEdit(m_xBuilder->weld_entry("min")))
+ , m_xEdList(m_xBuilder->weld_text_view("minlist"))
+ , m_xFtMax(m_xBuilder->weld_label("maxft"))
+ , m_xEdMax(new formula::RefEdit(m_xBuilder->weld_entry("max")))
+ , m_xFtHint(m_xBuilder->weld_label("hintft"))
+ , m_xBtnRef(new formula::RefButton(m_xBuilder->weld_button("validref")))
+ , m_xRefGrid(m_xBuilder->weld_container("refgrid"))
+ , m_pRefEditParent(m_xRefGrid.get())
+ , m_pBtnRefParent(m_xRefGrid.get())
+{
+ m_xEdMin->SetReferences(nullptr, m_xFtMin.get());
+
+ Size aSize(m_xEdList->get_approximate_digit_width() * 40,
+ m_xEdList->get_height_rows(10));
+ m_xEdList->set_size_request(aSize.Width(), aSize.Height());
+ m_xEdMax->SetReferences(nullptr, m_xFtMax.get());
+
+ m_xBtnRef->SetClickHdl(LINK(this, ScTPValidationValue, ClickHdl));
+
+ //lock in the max size initial config
+ aSize = m_xContainer->get_preferred_size();
+ m_xContainer->set_size_request(aSize.Width(), aSize.Height());
+
+ Init();
+
+ // list separator in formulas
+ OUString aListSep = ::ScCompiler::GetNativeSymbol( ocSep );
+ OSL_ENSURE( aListSep.getLength() == 1, "ScTPValidationValue::ScTPValidationValue - list separator error" );
+ mcFmlaSep = aListSep.getLength() ? aListSep[0] : ';';
+ m_xBtnRef->GetWidget()->hide(); // cell range picker
+}
+
+ScTPValidationValue::~ScTPValidationValue()
+{
+ m_xEdMin.reset();
+ m_xEdMax.reset();
+ m_xBtnRef.reset();
+}
+
+void ScTPValidationValue::Init()
+{
+ m_xLbAllow->connect_changed( LINK( this, ScTPValidationValue, SelectHdl ) );
+ m_xLbValue->connect_changed( LINK( this, ScTPValidationValue, SelectHdl ) );
+ m_xCbShow->connect_toggled( LINK( this, ScTPValidationValue, CheckHdl ) );
+
+ // cell range picker
+ m_xEdMin->SetGetFocusHdl( LINK( this, ScTPValidationValue, EditSetFocusHdl ) );
+ m_xEdMin->SetLoseFocusHdl( LINK( this, ScTPValidationValue, KillEditFocusHdl ) );
+ m_xEdMax->SetGetFocusHdl( LINK( this, ScTPValidationValue, EditSetFocusHdl ) );
+ m_xEdMax->SetLoseFocusHdl( LINK( this, ScTPValidationValue, KillEditFocusHdl ) );
+ m_xBtnRef->SetLoseFocusHdl( LINK( this, ScTPValidationValue, KillButtonFocusHdl ) );
+
+ m_xLbAllow->set_active( SC_VALIDDLG_ALLOW_ANY );
+ m_xLbValue->set_active( SC_VALIDDLG_DATA_EQUAL );
+
+ SelectHdl( *m_xLbAllow );
+ CheckHdl( *m_xCbShow );
+}
+
+std::unique_ptr<SfxTabPage> ScTPValidationValue::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet)
+{
+ return std::make_unique<ScTPValidationValue>(pPage, pController, *rArgSet);
+}
+
+void ScTPValidationValue::Reset( const SfxItemSet* rArgSet )
+{
+ sal_uInt16 nLbPos = SC_VALIDDLG_ALLOW_ANY;
+ if( const SfxUInt16Item* pItem = rArgSet->GetItemIfSet( FID_VALID_MODE ) )
+ nLbPos = lclGetPosFromValMode( static_cast< ScValidationMode >( pItem->GetValue() ) );
+ m_xLbAllow->set_active( nLbPos );
+
+ nLbPos = SC_VALIDDLG_DATA_EQUAL;
+ if( const SfxUInt16Item* pItem = rArgSet->GetItemIfSet( FID_VALID_CONDMODE ) )
+ nLbPos = lclGetPosFromCondMode( static_cast< ScConditionMode >( pItem->GetValue() ) );
+ m_xLbValue->set_active( nLbPos );
+
+ // *** check boxes ***
+ bool bCheck = true;
+ if( const SfxBoolItem* pItem = rArgSet->GetItemIfSet( FID_VALID_BLANK ) )
+ bCheck = pItem->GetValue();
+ m_xCbAllow->set_active( bCheck );
+
+ sal_Int32 nListType = ValidListType::UNSORTED;
+ if( const SfxInt16Item* pItem = rArgSet->GetItemIfSet( FID_VALID_LISTTYPE ) )
+ nListType = pItem->GetValue();
+ m_xCbShow->set_active( nListType != ValidListType::INVISIBLE );
+ m_xCbSort->set_active( nListType == ValidListType::SORTEDASCENDING );
+
+ // *** formulas ***
+ OUString aFmlaStr;
+ if ( const SfxStringItem* pItem = rArgSet->GetItemIfSet( FID_VALID_VALUE1 ) )
+ aFmlaStr = pItem->GetValue();
+ SetFirstFormula( aFmlaStr );
+
+ aFmlaStr.clear();
+ if ( const SfxStringItem* pItem = rArgSet->GetItemIfSet( FID_VALID_VALUE2 ) )
+ aFmlaStr = pItem->GetValue();
+ SetSecondFormula( aFmlaStr );
+
+ SelectHdl( *m_xLbAllow );
+ CheckHdl( *m_xCbShow );
+}
+
+bool ScTPValidationValue::FillItemSet( SfxItemSet* rArgSet )
+{
+ sal_Int16 nListType = m_xCbShow->get_active() ?
+ (m_xCbSort->get_active() ? ValidListType::SORTEDASCENDING : ValidListType::UNSORTED) :
+ ValidListType::INVISIBLE;
+
+ const sal_Int32 nLbPos = m_xLbAllow->get_active();
+ bool bCustom = (nLbPos == SC_VALIDDLG_ALLOW_CUSTOM);
+ ScConditionMode eCondMode = bCustom ?
+ ScConditionMode::Direct : lclGetCondModeFromPos( m_xLbValue->get_active() );
+
+ rArgSet->Put( SfxUInt16Item( FID_VALID_MODE, sal::static_int_cast<sal_uInt16>(
+ lclGetValModeFromPos( nLbPos ) ) ) );
+ rArgSet->Put( SfxUInt16Item( FID_VALID_CONDMODE, sal::static_int_cast<sal_uInt16>( eCondMode ) ) );
+ rArgSet->Put( SfxStringItem( FID_VALID_VALUE1, GetFirstFormula() ) );
+ rArgSet->Put( SfxStringItem( FID_VALID_VALUE2, GetSecondFormula() ) );
+ rArgSet->Put( SfxBoolItem( FID_VALID_BLANK, m_xCbAllow->get_active() ) );
+ rArgSet->Put( SfxInt16Item( FID_VALID_LISTTYPE, nListType ) );
+ return true;
+}
+
+OUString ScTPValidationValue::GetFirstFormula() const
+{
+ OUString aFmlaStr;
+ if( m_xLbAllow->get_active() == SC_VALIDDLG_ALLOW_LIST )
+ lclGetFormulaFromStringList( aFmlaStr, m_xEdList->get_text(), mcFmlaSep );
+ else
+ aFmlaStr = m_xEdMin->GetText();
+ return aFmlaStr;
+}
+
+OUString ScTPValidationValue::GetSecondFormula() const
+{
+ return m_xEdMax->GetText();
+}
+
+void ScTPValidationValue::SetFirstFormula( const OUString& rFmlaStr )
+{
+ // try if formula is a string list, validation mode must already be set
+ OUString aStringList;
+ if( (m_xLbAllow->get_active() == SC_VALIDDLG_ALLOW_RANGE) &&
+ lclGetStringListFromFormula( aStringList, rFmlaStr, mcFmlaSep ) )
+ {
+ m_xEdList->set_text( aStringList );
+ m_xEdMin->SetText( OUString() );
+ // change validation mode to string list
+ m_xLbAllow->set_active( SC_VALIDDLG_ALLOW_LIST );
+ }
+ else
+ {
+ m_xEdMin->SetText( rFmlaStr );
+ m_xEdList->set_text( OUString() );
+ }
+}
+
+void ScTPValidationValue::SetSecondFormula( const OUString& rFmlaStr )
+{
+ m_xEdMax->SetText( rFmlaStr );
+}
+
+ScValidationDlg * ScTPValidationValue::GetValidationDlg()
+{
+ return dynamic_cast<ScValidationDlg*>(GetDialogController());
+}
+
+void ScTPValidationValue::SetupRefDlg()
+{
+ ScValidationDlg *pValidationDlg = GetValidationDlg();
+ if( !pValidationDlg )
+ return;
+
+ if( !pValidationDlg->SetupRefDlg() )
+ return;
+
+ pValidationDlg->SetHandler( this );
+ pValidationDlg->SetSetRefHdl( static_cast<ScRefHandlerHelper::PFUNCSETREFHDLTYPE>( &ScTPValidationValue::SetReferenceHdl ) );
+ pValidationDlg->SetSetActHdl( static_cast<ScRefHandlerHelper::PCOMMONHDLTYPE>( &ScTPValidationValue::SetActiveHdl ) );
+ pValidationDlg->SetRefInputStartPreHdl( static_cast<ScRefHandlerHelper::PINPUTSTARTDLTYPE>( &ScTPValidationValue::RefInputStartPreHdl ) );
+ pValidationDlg->SetRefInputDonePostHdl( static_cast<ScRefHandlerHelper::PCOMMONHDLTYPE>( &ScTPValidationValue::RefInputDonePostHdl ) );
+
+ weld::Label* pLabel = nullptr;
+
+ if (m_xEdMax->GetWidget()->get_visible())
+ {
+ m_pRefEdit = m_xEdMax.get();
+ pLabel = m_xFtMax.get();
+ }
+ else if (m_xEdMin->GetWidget()->get_visible())
+ {
+ m_pRefEdit = m_xEdMin.get();
+ pLabel = m_xFtMin.get();
+ }
+
+ if (m_pRefEdit && !m_pRefEdit->GetWidget()->has_focus())
+ m_pRefEdit->GrabFocus();
+
+ if( m_pRefEdit )
+ m_pRefEdit->SetReferences( pValidationDlg, pLabel );
+
+ m_xBtnRef->SetReferences( pValidationDlg, m_pRefEdit );
+}
+
+void ScTPValidationValue::RemoveRefDlg(bool bRestoreModal)
+{
+ ScValidationDlg *pValidationDlg = GetValidationDlg();
+ if( !pValidationDlg )
+ return;
+
+ if( !pValidationDlg->RemoveRefDlg(bRestoreModal) )
+ return;
+
+ pValidationDlg->SetHandler( nullptr );
+ pValidationDlg->SetSetRefHdl( nullptr );
+ pValidationDlg->SetSetActHdl( nullptr );
+ pValidationDlg->SetRefInputStartPreHdl( nullptr );
+ pValidationDlg->SetRefInputDonePostHdl( nullptr );
+
+ if( m_pRefEdit )
+ m_pRefEdit->SetReferences( nullptr, nullptr );
+ m_pRefEdit = nullptr;
+
+ m_xBtnRef->SetReferences( nullptr, nullptr );
+}
+
+IMPL_LINK_NOARG(ScTPValidationValue, EditSetFocusHdl, formula::RefEdit&, void)
+{
+ const sal_Int32 nPos = m_xLbAllow->get_active();
+
+ if ( nPos == SC_VALIDDLG_ALLOW_RANGE )
+ {
+ SetupRefDlg();
+ }
+}
+
+IMPL_LINK( ScTPValidationValue, KillEditFocusHdl, formula::RefEdit&, rWnd, void )
+{
+ if (&rWnd != m_pRefEdit)
+ return;
+ if( ScValidationDlg *pValidationDlg = GetValidationDlg() )
+ {
+ if (pValidationDlg->IsChildFocus() && !pValidationDlg->IsRefInputting())
+ {
+ if( ( !m_pRefEdit || !m_pRefEdit->GetWidget()->has_focus()) && !m_xBtnRef->GetWidget()->has_focus() )
+ {
+ RemoveRefDlg(true);
+ }
+ }
+ }
+}
+
+IMPL_LINK( ScTPValidationValue, KillButtonFocusHdl, formula::RefButton&, rWnd, void )
+{
+ if( &rWnd != m_xBtnRef.get())
+ return;
+ if( ScValidationDlg *pValidationDlg = GetValidationDlg() )
+ if (pValidationDlg->IsChildFocus() && !pValidationDlg->IsRefInputting())
+ if( ( !m_pRefEdit || !m_pRefEdit->GetWidget()->has_focus()) && !m_xBtnRef->GetWidget()->has_focus() )
+ {
+ RemoveRefDlg(true);
+ }
+}
+
+IMPL_LINK_NOARG(ScTPValidationValue, SelectHdl, weld::ComboBox&, void)
+{
+ const sal_Int32 nLbPos = m_xLbAllow->get_active();
+ bool bEnable = (nLbPos != SC_VALIDDLG_ALLOW_ANY);
+ bool bRange = (nLbPos == SC_VALIDDLG_ALLOW_RANGE);
+ bool bList = (nLbPos == SC_VALIDDLG_ALLOW_LIST);
+ bool bCustom = (nLbPos == SC_VALIDDLG_ALLOW_CUSTOM);
+
+ m_xCbAllow->set_sensitive( bEnable ); // Empty cell
+ m_xFtValue->set_sensitive( bEnable );
+ m_xLbValue->set_sensitive( bEnable );
+ m_xFtMin->set_sensitive( bEnable );
+ m_xEdMin->GetWidget()->set_sensitive( bEnable );
+ m_xEdList->set_sensitive( bEnable );
+ m_xFtMax->set_sensitive( bEnable );
+ m_xEdMax->GetWidget()->set_sensitive( bEnable );
+
+ bool bShowMax = false;
+
+ if( bRange )
+ m_xFtMin->set_label( maStrRange );
+ else if( bList )
+ m_xFtMin->set_label( maStrList );
+ else if( bCustom )
+ m_xFtMin->set_label( maStrFormula );
+ else
+ {
+ switch( m_xLbValue->get_active() )
+ {
+ case SC_VALIDDLG_DATA_EQUAL:
+ case SC_VALIDDLG_DATA_NOTEQUAL: m_xFtMin->set_label( maStrValue ); break;
+
+ case SC_VALIDDLG_DATA_LESS:
+ case SC_VALIDDLG_DATA_EQLESS: m_xFtMin->set_label( maStrMax ); break;
+
+ case SC_VALIDDLG_DATA_VALIDRANGE:
+ case SC_VALIDDLG_DATA_INVALIDRANGE: bShowMax = true;
+ [[fallthrough]];
+ case SC_VALIDDLG_DATA_GREATER:
+ case SC_VALIDDLG_DATA_EQGREATER: m_xFtMin->set_label( maStrMin ); break;
+
+ default:
+ OSL_FAIL( "ScTPValidationValue::SelectHdl - unknown condition mode" );
+ }
+ }
+
+ m_xCbShow->set_visible( bRange || bList );
+ m_xCbSort->set_visible( bRange || bList );
+ m_xFtValue->set_visible( !bRange && !bList && !bCustom);
+ m_xLbValue->set_visible( !bRange && !bList && !bCustom );
+ m_xEdMin->GetWidget()->set_visible( !bList );
+ m_xEdList->set_visible( bList );
+ m_xMinGrid->set_vexpand( bList );
+ m_xFtMax->set_visible( bShowMax );
+ m_xEdMax->GetWidget()->set_visible( bShowMax );
+ m_xFtHint->set_visible( bRange );
+ m_xBtnRef->GetWidget()->set_visible( bRange ); // cell range picker
+}
+
+IMPL_LINK_NOARG(ScTPValidationValue, CheckHdl, weld::Toggleable&, void)
+{
+ m_xCbSort->set_sensitive( m_xCbShow->get_active() );
+}
+
+// Input Help Page
+
+ScTPValidationHelp::ScTPValidationHelp(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet)
+ : SfxTabPage(pPage, pController, IS_MOBILE ? OUString("modules/scalc/ui/validationhelptabpage-mobile.ui")
+ : OUString("modules/scalc/ui/validationhelptabpage.ui"), "ValidationHelpTabPage", &rArgSet)
+ , m_xTsbHelp(m_xBuilder->weld_check_button("tsbhelp"))
+ , m_xEdtTitle(m_xBuilder->weld_entry("title"))
+ , m_xEdInputHelp(m_xBuilder->weld_text_view("inputhelp"))
+{
+ m_xEdInputHelp->set_size_request(m_xEdInputHelp->get_approximate_digit_width() * 40, m_xEdInputHelp->get_height_rows(13));
+}
+
+ScTPValidationHelp::~ScTPValidationHelp()
+{
+}
+
+std::unique_ptr<SfxTabPage> ScTPValidationHelp::Create(weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rArgSet)
+{
+ return std::make_unique<ScTPValidationHelp>(pPage, pController, *rArgSet);
+}
+
+void ScTPValidationHelp::Reset( const SfxItemSet* rArgSet )
+{
+ if ( const SfxBoolItem* pItem = rArgSet->GetItemIfSet( FID_VALID_SHOWHELP ) )
+ m_xTsbHelp->set_state( pItem->GetValue() ? TRISTATE_TRUE : TRISTATE_FALSE );
+ else
+ m_xTsbHelp->set_state( TRISTATE_FALSE );
+
+ if ( const SfxStringItem* pItem = rArgSet->GetItemIfSet( FID_VALID_HELPTITLE ) )
+ m_xEdtTitle->set_text( pItem->GetValue() );
+ else
+ m_xEdtTitle->set_text( OUString() );
+
+ if ( const SfxStringItem* pItem = rArgSet->GetItemIfSet( FID_VALID_HELPTEXT ) )
+ m_xEdInputHelp->set_text( pItem->GetValue() );
+ else
+ m_xEdInputHelp->set_text( OUString() );
+}
+
+bool ScTPValidationHelp::FillItemSet( SfxItemSet* rArgSet )
+{
+ rArgSet->Put( SfxBoolItem( FID_VALID_SHOWHELP, m_xTsbHelp->get_state() == TRISTATE_TRUE ) );
+ rArgSet->Put( SfxStringItem( FID_VALID_HELPTITLE, m_xEdtTitle->get_text() ) );
+ rArgSet->Put( SfxStringItem( FID_VALID_HELPTEXT, m_xEdInputHelp->get_text() ) );
+
+ return true;
+}
+
+// Error Alert Page
+
+ScTPValidationError::ScTPValidationError(weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet& rArgSet)
+
+ : SfxTabPage ( pPage, pController,
+ IS_MOBILE ? OUString("modules/scalc/ui/erroralerttabpage-mobile.ui")
+ : OUString("modules/scalc/ui/erroralerttabpage.ui"), "ErrorAlertTabPage",
+ &rArgSet )
+ , m_xTsbShow(m_xBuilder->weld_check_button("tsbshow"))
+ , m_xLbAction(m_xBuilder->weld_combo_box("actionCB"))
+ , m_xBtnSearch(m_xBuilder->weld_button("browseBtn"))
+ , m_xEdtTitle(m_xBuilder->weld_entry("erroralert_title"))
+ , m_xFtError(m_xBuilder->weld_label("errormsg_label"))
+ , m_xEdError(m_xBuilder->weld_text_view("errorMsg"))
+{
+ m_xEdError->set_size_request(m_xEdError->get_approximate_digit_width() * 40, m_xEdError->get_height_rows(12));
+ Init();
+}
+
+ScTPValidationError::~ScTPValidationError()
+{
+}
+
+void ScTPValidationError::Init()
+{
+ m_xLbAction->connect_changed(LINK(this, ScTPValidationError, SelectActionHdl));
+ m_xBtnSearch->connect_clicked(LINK( this, ScTPValidationError, ClickSearchHdl));
+
+ m_xLbAction->set_active(0);
+
+ SelectActionHdl(*m_xLbAction);
+}
+
+std::unique_ptr<SfxTabPage> ScTPValidationError::Create(weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rArgSet)
+{
+ return std::make_unique<ScTPValidationError>(pPage, pController, *rArgSet);
+}
+
+void ScTPValidationError::Reset( const SfxItemSet* rArgSet )
+{
+ if ( const SfxBoolItem* pItem = rArgSet->GetItemIfSet( FID_VALID_SHOWERR ) )
+ m_xTsbShow->set_state( pItem->GetValue() ? TRISTATE_TRUE : TRISTATE_FALSE );
+ else
+ m_xTsbShow->set_state( TRISTATE_TRUE ); // check by default
+
+ if ( const SfxUInt16Item* pItem = rArgSet->GetItemIfSet( FID_VALID_ERRSTYLE ) )
+ m_xLbAction->set_active( pItem->GetValue() );
+ else
+ m_xLbAction->set_active( 0 );
+
+ if ( const SfxStringItem* pItem = rArgSet->GetItemIfSet( FID_VALID_ERRTITLE ) )
+ m_xEdtTitle->set_text( pItem->GetValue() );
+ else
+ m_xEdtTitle->set_text( OUString() );
+
+ if ( const SfxStringItem* pItem = rArgSet->GetItemIfSet( FID_VALID_ERRTEXT ) )
+ m_xEdError->set_text( pItem->GetValue() );
+ else
+ m_xEdError->set_text( OUString() );
+
+ SelectActionHdl(*m_xLbAction);
+}
+
+bool ScTPValidationError::FillItemSet( SfxItemSet* rArgSet )
+{
+ rArgSet->Put( SfxBoolItem( FID_VALID_SHOWERR, m_xTsbShow->get_state() == TRISTATE_TRUE ) );
+ rArgSet->Put( SfxUInt16Item( FID_VALID_ERRSTYLE, m_xLbAction->get_active() ) );
+ rArgSet->Put( SfxStringItem( FID_VALID_ERRTITLE, m_xEdtTitle->get_text() ) );
+ rArgSet->Put( SfxStringItem( FID_VALID_ERRTEXT, m_xEdError->get_text() ) );
+
+ return true;
+}
+
+IMPL_LINK_NOARG(ScTPValidationError, SelectActionHdl, weld::ComboBox&, void)
+{
+ ScValidErrorStyle eStyle = static_cast<ScValidErrorStyle>(m_xLbAction->get_active());
+ bool bMacro = ( eStyle == SC_VALERR_MACRO );
+
+ m_xBtnSearch->set_sensitive( bMacro );
+ m_xFtError->set_sensitive( !bMacro );
+ m_xEdError->set_sensitive( !bMacro );
+}
+
+IMPL_LINK_NOARG(ScTPValidationError, ClickSearchHdl, weld::Button&, void)
+{
+ // Use static SfxApplication method to bring up selector dialog for
+ // choosing a script
+ OUString aScriptURL = SfxApplication::ChooseScript(GetFrameWeld());
+
+ if ( !aScriptURL.isEmpty() )
+ {
+ m_xEdtTitle->set_text( aScriptURL );
+ }
+}
+
+bool ScValidationDlg::EnterRefStatus()
+{
+ ScTabViewShell *pTabViewShell = GetTabViewShell();
+
+ if( !pTabViewShell ) return false;
+
+ sal_uInt16 nId = SLOTID;
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ if (pWnd && pWnd->GetController().get() != this) pWnd = nullptr;
+
+ SC_MOD()->SetRefDialog( nId, pWnd == nullptr );
+
+ return true;
+}
+
+bool ScValidationDlg::LeaveRefStatus()
+{
+ ScTabViewShell *pTabViewShell = GetTabViewShell();
+
+ if( !pTabViewShell ) return false;
+
+ sal_uInt16 nId = SLOTID;
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ if ( pViewFrm->GetChildWindow( nId ) )
+ {
+ DoClose( nId );
+ }
+ return true;
+}
+
+bool ScValidationDlg::SetupRefDlg()
+{
+ if ( m_bOwnRefHdlr ) return false;
+ if( EnterRefMode() )
+ {
+ SetModal( false );
+ m_bOwnRefHdlr = true;
+ return EnterRefStatus();
+ }
+
+ return false;
+}
+
+bool ScValidationDlg::RemoveRefDlg( bool bRestoreModal /* = true */ )
+{
+ bool bVisLock = false;
+ bool bFreeWindowLock = false;
+
+ ScTabViewShell *pTabVwSh = GetTabViewShell();
+
+ if( !pTabVwSh ) return false;
+
+ if ( SfxChildWindow* pWnd = pTabVwSh->GetViewFrame()->GetChildWindow( SID_VALIDITY_REFERENCE ) )
+ {
+ bVisLock = static_cast<ScValidityRefChildWin*>(pWnd)->LockVisible( true );
+ bFreeWindowLock = static_cast<ScValidityRefChildWin*>(pWnd)->LockFreeWindow( true );
+ }
+
+ if ( !m_bOwnRefHdlr ) return false;
+ if( LeaveRefStatus() && LeaveRefMode() )
+ {
+ m_bOwnRefHdlr = false;
+
+ if( bRestoreModal )
+ {
+ SetModal( true );
+ }
+ }
+
+ if ( SfxChildWindow* pWnd = pTabVwSh->GetViewFrame()->GetChildWindow( SID_VALIDITY_REFERENCE ) )
+ {
+ static_cast<ScValidityRefChildWin*>(pWnd)->LockVisible( bVisLock );
+ static_cast<ScValidityRefChildWin*>(pWnd)->LockFreeWindow( bFreeWindowLock );
+ }
+
+ return true;
+}
+
+IMPL_LINK_NOARG(ScTPValidationValue, ClickHdl, formula::RefButton&, void)
+{
+ SetupRefDlg();
+}
+
+bool ScValidationDlg::IsChildFocus() const
+{
+ return m_xDialog->has_toplevel_focus();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dialogs/SparklineDataRangeDialog.cxx b/sc/source/ui/dialogs/SparklineDataRangeDialog.cxx
new file mode 100644
index 000000000..f085e737c
--- /dev/null
+++ b/sc/source/ui/dialogs/SparklineDataRangeDialog.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/.
+ */
+
+#include <SparklineDataRangeDialog.hxx>
+#include <Sparkline.hxx>
+#include <reffact.hxx>
+#include <docfunc.hxx>
+
+namespace sc
+{
+SparklineDataRangeDialog::SparklineDataRangeDialog(SfxBindings* pBindings,
+ SfxChildWindow* pChildWindow,
+ weld::Window* pWindow, ScViewData& rViewData)
+ : ScAnyRefDlgController(pBindings, pChildWindow, pWindow,
+ u"modules/scalc/ui/sparklinedatarangedialog.ui",
+ "SparklineDataRangeDialog")
+ , mrViewData(rViewData)
+ , mrDocument(rViewData.GetDocument())
+ , mpActiveEdit(nullptr)
+ , mbDialogLostFocus(false)
+ , mxButtonOk(m_xBuilder->weld_button("ok"))
+ , mxButtonCancel(m_xBuilder->weld_button("cancel"))
+ , mxDataRangeLabel(m_xBuilder->weld_label("cell-range-label"))
+ , mxDataRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("cell-range-edit")))
+ , mxDataRangeButton(new formula::RefButton(m_xBuilder->weld_button("cell-range-button")))
+
+{
+ mxDataRangeEdit->SetReferences(this, mxDataRangeLabel.get());
+ mxDataRangeButton->SetReferences(this, mxDataRangeEdit.get());
+
+ mxButtonCancel->connect_clicked(LINK(this, SparklineDataRangeDialog, ButtonClicked));
+ mxButtonOk->connect_clicked(LINK(this, SparklineDataRangeDialog, ButtonClicked));
+
+ mxButtonOk->set_sensitive(false);
+
+ Link<formula::RefEdit&, void> aEditLink
+ = LINK(this, SparklineDataRangeDialog, EditFocusHandler);
+ mxDataRangeEdit->SetGetFocusHdl(aEditLink);
+ aEditLink = LINK(this, SparklineDataRangeDialog, LoseEditFocusHandler);
+ mxDataRangeEdit->SetLoseFocusHdl(aEditLink);
+
+ Link<formula::RefButton&, void> aButtonLink
+ = LINK(this, SparklineDataRangeDialog, ButtonFocusHandler);
+ mxDataRangeButton->SetGetFocusHdl(aButtonLink);
+ aButtonLink = LINK(this, SparklineDataRangeDialog, LoseButtonFocusHandler);
+ mxDataRangeButton->SetLoseFocusHdl(aButtonLink);
+
+ Link<formula::RefEdit&, void> aModifyLink
+ = LINK(this, SparklineDataRangeDialog, RefInputModifyHandler);
+ mxDataRangeEdit->SetModifyHdl(aModifyLink);
+
+ setupValues();
+
+ mxDataRangeEdit->GrabFocus();
+}
+
+SparklineDataRangeDialog::~SparklineDataRangeDialog() = default;
+
+void SparklineDataRangeDialog::setupValues()
+{
+ ScAddress aCurrentAddress = mrViewData.GetCurPos();
+ mpSparkline = mrDocument.GetSparkline(aCurrentAddress);
+
+ if (mpSparkline)
+ {
+ ScRangeList aRangeList(mpSparkline->getInputRange());
+ if (!aRangeList.empty())
+ {
+ maDataRange = aRangeList[0];
+ OUString aString
+ = maDataRange.Format(mrDocument, ScRefFlags::VALID | ScRefFlags::TAB_3D,
+ mrDocument.GetAddressConvention());
+ mxDataRangeEdit->SetRefString(aString);
+ mxButtonOk->set_sensitive(true);
+ }
+ }
+}
+
+void SparklineDataRangeDialog::Close()
+{
+ DoClose(sc::SparklineDataRangeDialogWrapper::GetChildWindowId());
+}
+
+void SparklineDataRangeDialog::SetActive()
+{
+ if (mbDialogLostFocus)
+ {
+ mbDialogLostFocus = false;
+ if (mpActiveEdit)
+ mpActiveEdit->GrabFocus();
+ }
+ else
+ {
+ m_xDialog->grab_focus();
+ }
+ RefInputDone();
+}
+
+void SparklineDataRangeDialog::SetReference(const ScRange& rReferenceRange, ScDocument& rDocument)
+{
+ if (mpActiveEdit)
+ {
+ if (rReferenceRange.aStart != rReferenceRange.aEnd)
+ RefInputStart(mpActiveEdit);
+
+ OUString aString;
+ const ScRefFlags eFlags = ScRefFlags::VALID | ScRefFlags::TAB_3D;
+ auto eAddressConvention = rDocument.GetAddressConvention();
+
+ if (mpActiveEdit == mxDataRangeEdit.get())
+ {
+ maDataRange = rReferenceRange;
+ aString = maDataRange.Format(rDocument, eFlags, eAddressConvention);
+ mxDataRangeEdit->SetRefString(aString);
+ }
+ }
+}
+
+IMPL_LINK(SparklineDataRangeDialog, EditFocusHandler, formula::RefEdit&, rEdit, void)
+{
+ if (mxDataRangeEdit.get() == &rEdit)
+ mpActiveEdit = mxDataRangeEdit.get();
+ else
+ mpActiveEdit = nullptr;
+
+ if (mpActiveEdit)
+ mpActiveEdit->SelectAll();
+}
+
+IMPL_LINK(SparklineDataRangeDialog, ButtonFocusHandler, formula::RefButton&, rButton, void)
+{
+ if (mxDataRangeButton.get() == &rButton)
+ mpActiveEdit = mxDataRangeEdit.get();
+ else
+ mpActiveEdit = nullptr;
+
+ if (mpActiveEdit)
+ mpActiveEdit->SelectAll();
+}
+
+IMPL_LINK_NOARG(SparklineDataRangeDialog, LoseEditFocusHandler, formula::RefEdit&, void)
+{
+ mbDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(SparklineDataRangeDialog, LoseButtonFocusHandler, formula::RefButton&, void)
+{
+ mbDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(SparklineDataRangeDialog, RefInputModifyHandler, formula::RefEdit&, void)
+{
+ if (mpActiveEdit)
+ {
+ if (mpActiveEdit == mxDataRangeEdit.get())
+ {
+ ScRangeList aRangeList;
+ bool bValid = ParseWithNames(aRangeList, mxDataRangeEdit->GetText(), mrDocument);
+ const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
+ if (pRange)
+ {
+ maDataRange = *pRange;
+ mxDataRangeEdit->StartUpdateData();
+ }
+ else
+ {
+ maDataRange = ScRange(ScAddress::INITIALIZE_INVALID);
+ }
+ }
+ }
+}
+
+IMPL_LINK(SparklineDataRangeDialog, ButtonClicked, weld::Button&, rButton, void)
+{
+ if (mxButtonOk.get() == &rButton)
+ {
+ perform();
+ response(RET_OK);
+ }
+ else
+ {
+ response(RET_CANCEL);
+ }
+}
+
+void SparklineDataRangeDialog::perform()
+{
+ ScRangeList aList{ maDataRange };
+
+ auto& rDocFunc = mrViewData.GetDocShell()->GetDocFunc();
+ rDocFunc.ChangeSparkline(mpSparkline, mrViewData.GetTabNo(), aList);
+}
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dialogs/SparklineDialog.cxx b/sc/source/ui/dialogs/SparklineDialog.cxx
new file mode 100644
index 000000000..f27e0eb4a
--- /dev/null
+++ b/sc/source/ui/dialogs/SparklineDialog.cxx
@@ -0,0 +1,552 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <SparklineDialog.hxx>
+#include <SparklineData.hxx>
+#include <SparklineGroup.hxx>
+#include <Sparkline.hxx>
+#include <reffact.hxx>
+
+#include <docfunc.hxx>
+
+#include <svx/colorbox.hxx>
+#include <vcl/formatter.hxx>
+
+namespace sc
+{
+SparklineDialog::SparklineDialog(SfxBindings* pBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pWindow, ScViewData& rViewData)
+ : ScAnyRefDlgController(pBindings, pChildWindow, pWindow,
+ u"modules/scalc/ui/sparklinedialog.ui", "SparklineDialog")
+ , mrViewData(rViewData)
+ , mrDocument(rViewData.GetDocument())
+ , mpActiveEdit(nullptr)
+ , mbDialogLostFocus(false)
+ , mxButtonOk(m_xBuilder->weld_button("ok"))
+ , mxButtonCancel(m_xBuilder->weld_button("cancel"))
+ , mxFrameData(m_xBuilder->weld_frame("frmData"))
+ , mxInputRangeLabel(m_xBuilder->weld_label("lbInputRange"))
+ , mxInputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("edInputRange")))
+ , mxInputRangeButton(new formula::RefButton(m_xBuilder->weld_button("btnInputRange")))
+ , mxOutputRangeLabel(m_xBuilder->weld_label("lbOutputRange"))
+ , mxOutputRangeEdit(new formula::RefEdit(m_xBuilder->weld_entry("edOutputRange")))
+ , mxOutputRangeButton(new formula::RefButton(m_xBuilder->weld_button("btnOutputRange")))
+ , mxColorSeries(new ColorListBox(m_xBuilder->weld_menu_button("colSeries"),
+ [pWindow] { return pWindow; }))
+ , mxColorNegative(new ColorListBox(m_xBuilder->weld_menu_button("colNegative"),
+ [pWindow] { return pWindow; }))
+ , mxColorMarker(new ColorListBox(m_xBuilder->weld_menu_button("colMarker"),
+ [pWindow] { return pWindow; }))
+ , mxColorHigh(
+ new ColorListBox(m_xBuilder->weld_menu_button("colHigh"), [pWindow] { return pWindow; }))
+ , mxColorLow(
+ new ColorListBox(m_xBuilder->weld_menu_button("colLow"), [pWindow] { return pWindow; }))
+ , mxColorFirst(
+ new ColorListBox(m_xBuilder->weld_menu_button("colFirst"), [pWindow] { return pWindow; }))
+ , mxColorLast(
+ new ColorListBox(m_xBuilder->weld_menu_button("colLast"), [pWindow] { return pWindow; }))
+ , mxCheckButtonNegative(m_xBuilder->weld_check_button("cbNegative"))
+ , mxCheckButtonMarker(m_xBuilder->weld_check_button("cbMarker"))
+ , mxCheckButtonHigh(m_xBuilder->weld_check_button("cbHigh"))
+ , mxCheckButtonLow(m_xBuilder->weld_check_button("cbLow"))
+ , mxCheckButtonFirst(m_xBuilder->weld_check_button("cbFirst"))
+ , mxCheckButtonLast(m_xBuilder->weld_check_button("cbLast"))
+ , mxSpinLineWidth(m_xBuilder->weld_spin_button("seLineWidth"))
+ , mxType(m_xBuilder->weld_combo_box("cbType"))
+ , mxCheckDisplayXAxis(m_xBuilder->weld_check_button("cbDisplayXAxis"))
+ , mxCheckDisplayHidden(m_xBuilder->weld_check_button("cbHidden"))
+ , mxCheckRightToLeft(m_xBuilder->weld_check_button("cbRTL"))
+ , mxDisplayEmptyGap(m_xBuilder->weld_combo_box("cbEmptyCells"))
+ , mxComboMinAxisType(m_xBuilder->weld_combo_box("cbMinAxisType"))
+ , mxComboMaxAxisType(m_xBuilder->weld_combo_box("cbMaxAxisType"))
+ , mxSpinCustomMin(m_xBuilder->weld_formatted_spin_button("seMinAxis"))
+ , mxSpinCustomMax(m_xBuilder->weld_formatted_spin_button("seMaxAxis"))
+ , mbEditMode(false)
+{
+ mxInputRangeEdit->SetReferences(this, mxInputRangeLabel.get());
+ mxInputRangeButton->SetReferences(this, mxInputRangeEdit.get());
+
+ mxOutputRangeEdit->SetReferences(this, mxOutputRangeLabel.get());
+ mxOutputRangeButton->SetReferences(this, mxOutputRangeEdit.get());
+
+ mxButtonCancel->connect_clicked(LINK(this, SparklineDialog, ButtonClicked));
+ mxButtonOk->connect_clicked(LINK(this, SparklineDialog, ButtonClicked));
+ mxButtonOk->set_sensitive(false);
+
+ Link<formula::RefEdit&, void> aEditLink = LINK(this, SparklineDialog, EditFocusHandler);
+ mxInputRangeEdit->SetGetFocusHdl(aEditLink);
+ mxOutputRangeEdit->SetGetFocusHdl(aEditLink);
+ aEditLink = LINK(this, SparklineDialog, LoseEditFocusHandler);
+ mxInputRangeEdit->SetLoseFocusHdl(aEditLink);
+ mxOutputRangeEdit->SetLoseFocusHdl(aEditLink);
+
+ Link<formula::RefButton&, void> aButtonLink = LINK(this, SparklineDialog, ButtonFocusHandler);
+ mxInputRangeButton->SetGetFocusHdl(aButtonLink);
+ mxOutputRangeButton->SetGetFocusHdl(aButtonLink);
+ aButtonLink = LINK(this, SparklineDialog, LoseButtonFocusHandler);
+ mxInputRangeButton->SetLoseFocusHdl(aButtonLink);
+ mxOutputRangeButton->SetLoseFocusHdl(aButtonLink);
+
+ Link<formula::RefEdit&, void> aModifyLink = LINK(this, SparklineDialog, RefInputModifyHandler);
+ mxInputRangeEdit->SetModifyHdl(aModifyLink);
+ mxOutputRangeEdit->SetModifyHdl(aModifyLink);
+
+ mxType->connect_changed(LINK(this, SparklineDialog, SelectSparklineType));
+ mxDisplayEmptyGap->connect_changed(LINK(this, SparklineDialog, SelectSparklineType));
+
+ Link<weld::Toggleable&, void> aLink = LINK(this, SparklineDialog, ToggleHandler);
+ mxCheckButtonNegative->connect_toggled(aLink);
+ mxCheckButtonMarker->connect_toggled(aLink);
+ mxCheckButtonHigh->connect_toggled(aLink);
+ mxCheckButtonLow->connect_toggled(aLink);
+ mxCheckButtonFirst->connect_toggled(aLink);
+ mxCheckButtonLast->connect_toggled(aLink);
+ mxCheckDisplayXAxis->connect_toggled(aLink);
+ mxCheckDisplayHidden->connect_toggled(aLink);
+ mxCheckRightToLeft->connect_toggled(aLink);
+
+ mxSpinLineWidth->connect_value_changed(LINK(this, SparklineDialog, SpinLineWidthChanged));
+
+ mxComboMinAxisType->connect_changed(LINK(this, SparklineDialog, ComboValueChanged));
+ mxComboMaxAxisType->connect_changed(LINK(this, SparklineDialog, ComboValueChanged));
+
+ mxSpinCustomMin->connect_value_changed(LINK(this, SparklineDialog, SpinCustomChanged));
+ Formatter& rSpinCustomMinFormatter = mxSpinCustomMin->GetFormatter();
+ rSpinCustomMinFormatter.ClearMinValue();
+ rSpinCustomMinFormatter.ClearMaxValue();
+ rSpinCustomMinFormatter.UseInputStringForFormatting();
+
+ mxSpinCustomMax->connect_value_changed(LINK(this, SparklineDialog, SpinCustomChanged));
+ Formatter& rSpinCustomMaxFormatter = mxSpinCustomMax->GetFormatter();
+ rSpinCustomMaxFormatter.ClearMinValue();
+ rSpinCustomMaxFormatter.ClearMaxValue();
+ rSpinCustomMaxFormatter.UseInputStringForFormatting();
+
+ setupValues();
+
+ mxOutputRangeEdit->GrabFocus();
+ mxButtonOk->set_sensitive(checkValidInputOutput());
+}
+
+SparklineDialog::~SparklineDialog() = default;
+
+void SparklineDialog::setInputSelection()
+{
+ mrViewData.GetSimpleArea(maInputRange);
+ OUString aString = maInputRange.Format(mrDocument, ScRefFlags::VALID | ScRefFlags::TAB_3D,
+ mrDocument.GetAddressConvention());
+ mxInputRangeEdit->SetRefString(aString);
+}
+
+void SparklineDialog::setupValues()
+{
+ ScRange aSelectionRange;
+ mrViewData.GetSimpleArea(aSelectionRange);
+
+ if (mrDocument.HasOneSparklineGroup(aSelectionRange))
+ {
+ if (auto pSparkline = mrDocument.GetSparkline(aSelectionRange.aStart))
+ {
+ mpSparklineGroup = pSparkline->getSparklineGroup();
+ maAttributes = mpSparklineGroup->getAttributes();
+ mxFrameData->set_visible(false);
+ mbEditMode = true;
+ }
+ }
+ else
+ {
+ maInputRange = aSelectionRange;
+ }
+
+ setInputSelection();
+
+ switch (maAttributes.getType())
+ {
+ case sc::SparklineType::Line:
+ mxType->set_active(0);
+ break;
+ case sc::SparklineType::Column:
+ mxType->set_active(1);
+ break;
+ case sc::SparklineType::Stacked:
+ mxType->set_active(2);
+ break;
+ }
+
+ switch (maAttributes.getDisplayEmptyCellsAs())
+ {
+ case sc::DisplayEmptyCellsAs::Gap:
+ mxDisplayEmptyGap->set_active(0);
+ break;
+ case sc::DisplayEmptyCellsAs::Zero:
+ mxDisplayEmptyGap->set_active(1);
+ break;
+ case sc::DisplayEmptyCellsAs::Span:
+ mxDisplayEmptyGap->set_active(2);
+ break;
+ }
+
+ mxColorSeries->SelectEntry(maAttributes.getColorSeries());
+ mxColorNegative->SelectEntry(maAttributes.getColorNegative());
+ mxColorMarker->SelectEntry(maAttributes.getColorMarkers());
+ mxColorHigh->SelectEntry(maAttributes.getColorHigh());
+ mxColorLow->SelectEntry(maAttributes.getColorLow());
+ mxColorFirst->SelectEntry(maAttributes.getColorFirst());
+ mxColorLast->SelectEntry(maAttributes.getColorLast());
+
+ mxCheckButtonNegative->set_active(maAttributes.isNegative());
+ mxCheckButtonMarker->set_active(maAttributes.isMarkers());
+ mxCheckButtonHigh->set_active(maAttributes.isHigh());
+ mxCheckButtonLow->set_active(maAttributes.isLow());
+ mxCheckButtonFirst->set_active(maAttributes.isFirst());
+ mxCheckButtonLast->set_active(maAttributes.isLast());
+
+ mxSpinLineWidth->set_value(sal_Int64(maAttributes.getLineWeight() * 100.0));
+
+ mxCheckDisplayXAxis->set_active(maAttributes.shouldDisplayXAxis());
+ mxCheckDisplayHidden->set_active(maAttributes.shouldDisplayHidden());
+ mxCheckRightToLeft->set_active(maAttributes.isRightToLeft());
+
+ switch (maAttributes.getMinAxisType())
+ {
+ case sc::AxisType::Individual:
+ mxComboMinAxisType->set_active(0);
+ mxSpinCustomMin->GetFormatter().SetValue(0.0);
+ break;
+ case sc::AxisType::Group:
+ mxComboMinAxisType->set_active(1);
+ mxSpinCustomMin->GetFormatter().SetValue(0.0);
+ break;
+ case sc::AxisType::Custom:
+ mxComboMinAxisType->set_active(2);
+ if (maAttributes.getManualMin())
+ mxSpinCustomMin->GetFormatter().SetValue(*maAttributes.getManualMin());
+ break;
+ }
+ ComboValueChanged(*mxComboMinAxisType);
+
+ switch (maAttributes.getMaxAxisType())
+ {
+ case sc::AxisType::Individual:
+ mxComboMaxAxisType->set_active(0);
+ mxSpinCustomMax->GetFormatter().SetValue(0.0);
+ break;
+ case sc::AxisType::Group:
+ mxComboMaxAxisType->set_active(1);
+ mxSpinCustomMax->GetFormatter().SetValue(0.0);
+ break;
+ case sc::AxisType::Custom:
+ mxComboMaxAxisType->set_active(2);
+ if (maAttributes.getManualMax())
+ mxSpinCustomMax->GetFormatter().SetValue(*maAttributes.getManualMax());
+ break;
+ }
+ ComboValueChanged(*mxComboMaxAxisType);
+}
+
+void SparklineDialog::Close() { DoClose(sc::SparklineDialogWrapper::GetChildWindowId()); }
+
+void SparklineDialog::SetActive()
+{
+ if (mbDialogLostFocus)
+ {
+ mbDialogLostFocus = false;
+ if (mpActiveEdit)
+ mpActiveEdit->GrabFocus();
+ }
+ else
+ {
+ m_xDialog->grab_focus();
+ }
+ RefInputDone();
+}
+
+void SparklineDialog::SetReference(const ScRange& rReferenceRange, ScDocument& rDocument)
+{
+ if (mpActiveEdit)
+ {
+ if (rReferenceRange.aStart != rReferenceRange.aEnd)
+ RefInputStart(mpActiveEdit);
+
+ OUString aString;
+ const ScRefFlags eFlags = ScRefFlags::VALID | ScRefFlags::TAB_3D;
+ auto eAddressConvention = rDocument.GetAddressConvention();
+
+ if (mpActiveEdit == mxInputRangeEdit.get())
+ {
+ maInputRange = rReferenceRange;
+ aString = maInputRange.Format(rDocument, eFlags, eAddressConvention);
+ mxInputRangeEdit->SetRefString(aString);
+ }
+ else if (mpActiveEdit == mxOutputRangeEdit.get())
+ {
+ maOutputRange = rReferenceRange;
+ aString = maOutputRange.Format(rDocument, eFlags, eAddressConvention);
+ mxOutputRangeEdit->SetRefString(aString);
+ }
+ }
+
+ mxButtonOk->set_sensitive(checkValidInputOutput());
+}
+
+IMPL_LINK(SparklineDialog, EditFocusHandler, formula::RefEdit&, rEdit, void)
+{
+ auto* pEdit = &rEdit;
+
+ if (mxInputRangeEdit.get() == pEdit)
+ mpActiveEdit = mxInputRangeEdit.get();
+ else if (mxOutputRangeEdit.get() == pEdit)
+ mpActiveEdit = mxOutputRangeEdit.get();
+ else
+ mpActiveEdit = nullptr;
+
+ if (mpActiveEdit)
+ mpActiveEdit->SelectAll();
+}
+
+IMPL_LINK(SparklineDialog, ButtonFocusHandler, formula::RefButton&, rButton, void)
+{
+ auto* pButton = &rButton;
+
+ if (mxInputRangeButton.get() == pButton)
+ mpActiveEdit = mxInputRangeEdit.get();
+ else if (mxOutputRangeButton.get() == pButton)
+ mpActiveEdit = mxOutputRangeEdit.get();
+ else
+ mpActiveEdit = nullptr;
+
+ if (mpActiveEdit)
+ mpActiveEdit->SelectAll();
+}
+
+IMPL_LINK_NOARG(SparklineDialog, LoseEditFocusHandler, formula::RefEdit&, void)
+{
+ mbDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(SparklineDialog, LoseButtonFocusHandler, formula::RefButton&, void)
+{
+ mbDialogLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(SparklineDialog, RefInputModifyHandler, formula::RefEdit&, void)
+{
+ if (mpActiveEdit)
+ {
+ if (mpActiveEdit == mxInputRangeEdit.get())
+ {
+ ScRangeList aRangeList;
+ bool bValid = ParseWithNames(aRangeList, mxInputRangeEdit->GetText(), mrDocument);
+ const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
+ if (pRange)
+ {
+ maInputRange = *pRange;
+ mxInputRangeEdit->StartUpdateData();
+ }
+ else
+ {
+ maInputRange = ScRange(ScAddress::INITIALIZE_INVALID);
+ }
+ }
+ else if (mpActiveEdit == mxOutputRangeEdit.get())
+ {
+ ScRangeList aRangeList;
+ bool bValid = ParseWithNames(aRangeList, mxOutputRangeEdit->GetText(), mrDocument);
+ const ScRange* pRange = (bValid && aRangeList.size() == 1) ? &aRangeList[0] : nullptr;
+ if (pRange)
+ {
+ maOutputRange = *pRange;
+ mxOutputRangeEdit->StartUpdateData();
+ }
+ else
+ {
+ maOutputRange = ScRange(ScAddress::INITIALIZE_INVALID);
+ }
+ }
+ }
+
+ mxButtonOk->set_sensitive(checkValidInputOutput());
+}
+
+IMPL_LINK(SparklineDialog, ButtonClicked, weld::Button&, rButton, void)
+{
+ if (mxButtonOk.get() == &rButton)
+ {
+ perform();
+ response(RET_OK);
+ }
+ else
+ {
+ response(RET_CANCEL);
+ }
+}
+
+IMPL_LINK(SparklineDialog, ToggleHandler, weld::Toggleable&, rToggle, void)
+{
+ if (mxCheckButtonNegative.get() == &rToggle)
+ maAttributes.setNegative(mxCheckButtonNegative->get_active());
+ if (mxCheckButtonMarker.get() == &rToggle)
+ maAttributes.setMarkers(mxCheckButtonMarker->get_active());
+ if (mxCheckButtonHigh.get() == &rToggle)
+ maAttributes.setHigh(mxCheckButtonHigh->get_active());
+ if (mxCheckButtonLow.get() == &rToggle)
+ maAttributes.setLow(mxCheckButtonLow->get_active());
+ if (mxCheckButtonFirst.get() == &rToggle)
+ maAttributes.setFirst(mxCheckButtonFirst->get_active());
+ if (mxCheckButtonLast.get() == &rToggle)
+ maAttributes.setLast(mxCheckButtonLast->get_active());
+ if (mxCheckDisplayXAxis.get() == &rToggle)
+ maAttributes.setDisplayXAxis(mxCheckDisplayXAxis->get_active());
+ if (mxCheckDisplayHidden.get() == &rToggle)
+ maAttributes.setDisplayHidden(mxCheckDisplayHidden->get_active());
+ if (mxCheckRightToLeft.get() == &rToggle)
+ maAttributes.setRightToLeft(mxCheckRightToLeft->get_active());
+}
+
+IMPL_LINK_NOARG(SparklineDialog, SelectSparklineType, weld::ComboBox&, void)
+{
+ switch (mxType->get_active())
+ {
+ case 0:
+ maAttributes.setType(sc::SparklineType::Line);
+ break;
+ case 1:
+ maAttributes.setType(sc::SparklineType::Column);
+ break;
+ case 2:
+ maAttributes.setType(sc::SparklineType::Stacked);
+ break;
+ }
+ switch (mxDisplayEmptyGap->get_active())
+ {
+ case 1:
+ maAttributes.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Gap);
+ break;
+ case 2:
+ maAttributes.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Zero);
+ break;
+ case 3:
+ maAttributes.setDisplayEmptyCellsAs(sc::DisplayEmptyCellsAs::Span);
+ break;
+ }
+}
+
+IMPL_LINK_NOARG(SparklineDialog, SpinLineWidthChanged, weld::SpinButton&, void)
+{
+ double value = mxSpinLineWidth->get_value() / 100.0;
+ maAttributes.setLineWeight(value);
+}
+
+IMPL_LINK(SparklineDialog, SpinCustomChanged, weld::FormattedSpinButton&, rFormatted, void)
+{
+ if (mxSpinCustomMin.get() == &rFormatted)
+ {
+ maAttributes.setManualMin(rFormatted.GetFormatter().GetValue());
+ }
+ else if (mxSpinCustomMax.get() == &rFormatted)
+ {
+ maAttributes.setManualMax(rFormatted.GetFormatter().GetValue());
+ }
+}
+
+IMPL_LINK(SparklineDialog, ComboValueChanged, weld::ComboBox&, rComboBox, void)
+{
+ int nActive = rComboBox.get_active();
+
+ if (mxComboMinAxisType.get() == &rComboBox)
+ {
+ switch (nActive)
+ {
+ case 0:
+ maAttributes.setMinAxisType(sc::AxisType::Individual);
+ mxSpinCustomMin->set_sensitive(false);
+ break;
+ case 1:
+ maAttributes.setMinAxisType(sc::AxisType::Group);
+ mxSpinCustomMin->set_sensitive(false);
+ break;
+ case 2:
+ maAttributes.setMinAxisType(sc::AxisType::Custom);
+ mxSpinCustomMin->set_sensitive(true);
+ break;
+ default:
+ break;
+ }
+ }
+ else if (mxComboMaxAxisType.get() == &rComboBox)
+ {
+ switch (nActive)
+ {
+ case 0:
+ maAttributes.setMaxAxisType(sc::AxisType::Individual);
+ mxSpinCustomMax->set_sensitive(false);
+ break;
+ case 1:
+ maAttributes.setMaxAxisType(sc::AxisType::Group);
+ mxSpinCustomMax->set_sensitive(false);
+ break;
+ case 2:
+ maAttributes.setMaxAxisType(sc::AxisType::Custom);
+ mxSpinCustomMax->set_sensitive(true);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+bool SparklineDialog::checkValidInputOutput()
+{
+ if (mbEditMode)
+ return true;
+
+ if (!maInputRange.IsValid() || !maOutputRange.IsValid())
+ return false;
+
+ sc::RangeOrientation eInputOrientation = sc::RangeOrientation::Unknown;
+ if (maOutputRange.aStart.Col() == maOutputRange.aEnd.Col())
+ {
+ sal_Int32 nOutputRowSize = maOutputRange.aEnd.Row() - maOutputRange.aStart.Row();
+ eInputOrientation = sc::calculateOrientation(nOutputRowSize, maInputRange);
+ }
+ else if (maOutputRange.aStart.Row() == maOutputRange.aEnd.Row())
+ {
+ sal_Int32 nOutputColSize = maOutputRange.aEnd.Col() - maOutputRange.aStart.Col();
+ eInputOrientation = sc::calculateOrientation(nOutputColSize, maInputRange);
+ }
+
+ return eInputOrientation != sc::RangeOrientation::Unknown;
+}
+
+void SparklineDialog::perform()
+{
+ maAttributes.setColorSeries(mxColorSeries->GetSelectEntryColor());
+ maAttributes.setColorNegative(mxColorNegative->GetSelectEntryColor());
+ maAttributes.setColorMarkers(mxColorMarker->GetSelectEntryColor());
+ maAttributes.setColorHigh(mxColorHigh->GetSelectEntryColor());
+ maAttributes.setColorLow(mxColorLow->GetSelectEntryColor());
+ maAttributes.setColorFirst(mxColorFirst->GetSelectEntryColor());
+ maAttributes.setColorLast(mxColorLast->GetSelectEntryColor());
+
+ auto& rDocFunc = mrViewData.GetDocShell()->GetDocFunc();
+
+ if (mpSparklineGroup)
+ {
+ rDocFunc.ChangeSparklineGroupAttributes(mpSparklineGroup, maAttributes);
+ }
+ else
+ {
+ auto pNewSparklineGroup = std::make_shared<sc::SparklineGroup>(maAttributes);
+ rDocFunc.InsertSparklines(maInputRange, maOutputRange, pNewSparklineGroup);
+ }
+}
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/dialogs/searchresults.cxx b/sc/source/ui/dialogs/searchresults.cxx
new file mode 100644
index 000000000..ab0e57907
--- /dev/null
+++ b/sc/source/ui/dialogs/searchresults.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/.
+ */
+
+#include <o3tl/safeint.hxx>
+#include <searchresults.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/srchdlg.hxx>
+#include <dociter.hxx>
+#include <document.hxx>
+#include <tabvwsh.hxx>
+#include <strings.hrc>
+#include <sc.hrc>
+#include <scresid.hxx>
+
+namespace sc {
+
+SearchResultsDlg::SearchResultsDlg(SfxBindings* _pBindings, weld::Window* pParent)
+ : SfxDialogController(pParent, "modules/scalc/ui/searchresults.ui", "SearchResultsDialog")
+ , aSkipped(ScResId(SCSTR_SKIPPED))
+ , mpBindings(_pBindings)
+ , mpDoc(nullptr)
+ , mbSorted(false)
+ , mxList(m_xBuilder->weld_tree_view("results"))
+ , mxSearchResults(m_xBuilder->weld_label("lbSearchResults"))
+ , mxShowDialog(m_xBuilder->weld_check_button("cbShow"))
+{
+ mxList->set_size_request(mxList->get_approximate_digit_width() * 50, mxList->get_height_rows(15));
+ mxShowDialog->connect_toggled(LINK(this, SearchResultsDlg, OnShowToggled));
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(mxList->get_approximate_digit_width() * 10),
+ o3tl::narrowing<int>(mxList->get_approximate_digit_width() * 10)
+ };
+ mxList->set_column_fixed_widths(aWidths);
+ mxList->connect_changed(LINK(this, SearchResultsDlg, ListSelectHdl));
+ mxList->connect_column_clicked(LINK(this, SearchResultsDlg, HeaderBarClick));
+}
+
+SearchResultsDlg::~SearchResultsDlg()
+{
+ // tdf#133807 if the search dialog is shown then re-present that dialog
+ // when this results dialog is dismissed
+ SfxViewFrame* pViewFrame = mpBindings->GetDispatcher()->GetFrame();
+ if (!pViewFrame)
+ return;
+ SfxChildWindow* pChildWindow = pViewFrame->GetChildWindow(
+ SvxSearchDialogWrapper::GetChildWindowId());
+ if (!pChildWindow)
+ return;
+ SvxSearchDialog* pSearchDlg = static_cast<SvxSearchDialog*>(pChildWindow->GetController().get());
+ if (!pSearchDlg)
+ return;
+ pSearchDlg->Present();
+}
+
+namespace
+{
+ class ListWrapper {
+ weld::TreeView& mrList;
+ public:
+ size_t mnCount = 0;
+ static const size_t mnMaximum = 1000;
+ ListWrapper(weld::TreeView& rList)
+ : mrList(rList)
+ {
+ mrList.clear();
+ mrList.freeze();
+ }
+ ~ListWrapper()
+ {
+ mrList.thaw();
+ }
+ void Insert(const OUString &rTabName,
+ const ScAddress &rPos,
+ formula::FormulaGrammar::AddressConvention eConvention,
+ const OUString &rText)
+ {
+ if (mnCount++ < mnMaximum)
+ {
+ mrList.append_text(rTabName);
+ int nPos = mrList.n_children() - 1;
+ mrList.set_text(nPos, rPos.Format(ScRefFlags::ADDR_ABS,
+ nullptr, eConvention), 1);
+ mrList.set_text(nPos, rText, 2);
+ }
+ }
+ };
+}
+
+void SearchResultsDlg::FillResults( ScDocument& rDoc, const ScRangeList &rMatchedRanges, bool bCellNotes,
+ bool bEmptyCells )
+{
+ ListWrapper aList(*mxList);
+ std::vector<OUString> aTabNames = rDoc.GetAllTableNames();
+ SCTAB nTabCount = aTabNames.size();
+
+ // tdf#92160 - too many results blow the widget's mind
+ size_t nMatchMax = rMatchedRanges.size();
+ if (nMatchMax > ListWrapper::mnMaximum)
+ nMatchMax = ListWrapper::mnMaximum;
+
+ if (bCellNotes || bEmptyCells)
+ {
+ for (size_t i = 0, n = nMatchMax; i < n; ++i)
+ {
+ ScRange const & rRange( rMatchedRanges[i] );
+ // Bear in mind that mostly the range is one address position
+ // or a column or a row joined.
+ ScAddress aPos( rRange.aStart );
+ for ( ; aPos.Tab() <= rRange.aEnd.Tab(); aPos.IncTab())
+ {
+ if (aPos.Tab() >= nTabCount)
+ break; // can this even happen? we just searched on existing sheets ...
+ for (aPos.SetCol( rRange.aStart.Col()); aPos.Col() <= rRange.aEnd.Col(); aPos.IncCol())
+ {
+ for (aPos.SetRow( rRange.aStart.Row()); aPos.Row() <= rRange.aEnd.Row(); aPos.IncRow())
+ {
+ if (bCellNotes)
+ {
+ const ScPostIt* pNote = rDoc.GetNote( aPos);
+ if (pNote)
+ aList.Insert(aTabNames[aPos.Tab()], aPos,
+ rDoc.GetAddressConvention(),
+ pNote->GetText());
+ }
+ else // bEmptyCells
+ {
+ aList.Insert(aTabNames[aPos.Tab()], aPos,
+ rDoc.GetAddressConvention(),
+ rDoc.GetString(aPos));
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ for (size_t i = 0, n = nMatchMax; i < n; ++i)
+ {
+ ScCellIterator aIter(rDoc, rMatchedRanges[i]);
+ for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
+ {
+ const ScAddress& aPos = aIter.GetPos();
+ if (aPos.Tab() >= nTabCount)
+ // Out-of-bound sheet index.
+ continue;
+
+ aList.Insert(aTabNames[aPos.Tab()], aPos,
+ rDoc.GetAddressConvention(),
+ rDoc.GetString(aPos));
+ }
+ }
+ }
+
+ OUString aTotal(ScResId(SCSTR_TOTAL, aList.mnCount));
+ OUString aSearchResults = aTotal.replaceFirst("%1", OUString::number(aList.mnCount));
+ if (aList.mnCount > ListWrapper::mnMaximum)
+ aSearchResults += " " + ScGlobal::ReplaceOrAppend( aSkipped, u"%1", OUString::number( ListWrapper::mnMaximum ) );
+ mxSearchResults->set_label(aSearchResults);
+
+ mpDoc = &rDoc;
+}
+
+void SearchResultsDlg::Close()
+{
+ if (mpBindings)
+ {
+ // Remove this dialog from the view frame after the dialog gets
+ // dismissed, else it would keep popping up endlessly!
+ SfxDispatcher* pDispacher = mpBindings ->GetDispatcher();
+ SfxBoolItem aItem(SID_SEARCH_RESULTS_DIALOG, false);
+ if (pDispacher)
+ {
+ pDispacher->ExecuteList(SID_SEARCH_RESULTS_DIALOG,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD, { &aItem });
+ }
+ }
+
+ SfxDialogController::Close();
+}
+
+IMPL_LINK(SearchResultsDlg, HeaderBarClick, int, nColumn, void)
+{
+ if (!mbSorted)
+ {
+ mxList->make_sorted();
+ mbSorted = true;
+ }
+
+ bool bSortAtoZ = mxList->get_sort_order();
+
+ //set new arrow positions in headerbar
+ if (nColumn == mxList->get_sort_column())
+ {
+ bSortAtoZ = !bSortAtoZ;
+ mxList->set_sort_order(bSortAtoZ);
+ }
+ else
+ {
+ int nOldSortColumn = mxList->get_sort_column();
+ if (nOldSortColumn != -1)
+ mxList->set_sort_indicator(TRISTATE_INDET, nOldSortColumn);
+ mxList->set_sort_column(nColumn);
+ }
+
+ if (nColumn != -1)
+ {
+ //sort lists
+ mxList->set_sort_indicator(bSortAtoZ ? TRISTATE_TRUE : TRISTATE_FALSE, nColumn);
+ }
+}
+
+IMPL_LINK_NOARG( SearchResultsDlg, ListSelectHdl, weld::TreeView&, void )
+{
+ if (!mpDoc)
+ return;
+
+ int nEntry = mxList->get_selected_index();
+ OUString aTabStr = mxList->get_text(nEntry, 0);
+ OUString aPosStr = mxList->get_text(nEntry, 1);
+
+ SCTAB nTab = -1;
+ if (!mpDoc->GetTable(aTabStr, nTab))
+ // No sheet with specified name.
+ return;
+
+ ScAddress aPos;
+ ScRefFlags nRes = aPos.Parse(aPosStr, *mpDoc, mpDoc->GetAddressConvention());
+ if (!(nRes & ScRefFlags::VALID))
+ // Invalid address string.
+ return;
+
+ // Jump to the cell.
+ ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell();
+ pScViewShell->SetTabNo(nTab);
+ pScViewShell->SetCursor(aPos.Col(), aPos.Row());
+ pScViewShell->AlignToCursor(aPos.Col(), aPos.Row(), SC_FOLLOW_JUMP);
+}
+
+IMPL_STATIC_LINK( SearchResultsDlg, OnShowToggled, weld::Toggleable&, rButton, void )
+{
+ ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell();
+ ScViewOptions aViewOpt( pScViewShell->GetViewData().GetOptions() );
+ aViewOpt.SetOption( VOPT_SUMMARY, rButton.get_active() );
+ pScViewShell->GetViewData().SetOptions( aViewOpt );
+}
+
+SearchResultsDlgWrapper::SearchResultsDlgWrapper(
+ vcl::Window* _pParent, sal_uInt16 nId, SfxBindings* pBindings, SfxChildWinInfo* /*pInfo*/)
+ : SfxChildWindow(_pParent, nId)
+ , m_xDialog(std::make_shared<SearchResultsDlg>(pBindings, _pParent->GetFrameWeld()))
+{
+ SetController(m_xDialog);
+}
+
+SearchResultsDlgWrapper::~SearchResultsDlgWrapper() {}
+
+SfxChildWinInfo SearchResultsDlgWrapper::GetInfo() const
+{
+ SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
+ aInfo.bVisible = false;
+ return aInfo;
+}
+
+SFX_IMPL_CHILDWINDOW_WITHID(SearchResultsDlgWrapper, SID_SEARCH_RESULTS_DIALOG);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/arealink.cxx b/sc/source/ui/docshell/arealink.cxx
new file mode 100644
index 000000000..8d3a89a16
--- /dev/null
+++ b/sc/source/ui/docshell/arealink.cxx
@@ -0,0 +1,498 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/fcontnr.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/diagnose.h>
+
+#include <arealink.hxx>
+
+#include <tablink.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <rangenam.hxx>
+#include <dbdata.hxx>
+#include <undoblk.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <markdata.hxx>
+#include <hints.hxx>
+#include <filter.hxx>
+
+#include <attrib.hxx>
+#include <patattr.hxx>
+#include <docpool.hxx>
+
+#include <scabstdlg.hxx>
+#include <clipparam.hxx>
+
+
+ScAreaLink::ScAreaLink( SfxObjectShell* pShell, const OUString& rFile,
+ const OUString& rFilter, const OUString& rOpt,
+ const OUString& rArea, const ScRange& rDest,
+ sal_Int32 nRefreshDelaySeconds ) :
+ ::sfx2::SvBaseLink(SfxLinkUpdateMode::ONCALL,SotClipboardFormatId::SIMPLE_FILE),
+ ScRefreshTimer ( nRefreshDelaySeconds ),
+ m_pDocSh(static_cast<ScDocShell*>(pShell)),
+ aFileName (rFile),
+ aFilterName (rFilter),
+ aOptions (rOpt),
+ aSourceArea (rArea),
+ aDestArea (rDest),
+ bAddUndo (true),
+ bInCreate (false),
+ bDoInsert (true)
+{
+ OSL_ENSURE(dynamic_cast< const ScDocShell *>( pShell ) != nullptr, "ScAreaLink with wrong ObjectShell");
+ SetRefreshHandler( LINK( this, ScAreaLink, RefreshHdl ) );
+ SetRefreshControl( &m_pDocSh->GetDocument().GetRefreshTimerControlAddress() );
+}
+
+ScAreaLink::~ScAreaLink()
+{
+ StopRefreshTimer();
+}
+
+void ScAreaLink::Edit(weld::Window* pParent, const Link<SvBaseLink&,void>& /* rEndEditHdl */ )
+{
+ // use own dialog instead of SvBaseLink::Edit...
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScLinkedAreaDlg> pDlg(pFact->CreateScLinkedAreaDlg(pParent));
+ pDlg->InitFromOldLink( aFileName, aFilterName, aOptions, aSourceArea, GetRefreshDelaySeconds() );
+ if ( pDlg->Execute() == RET_OK )
+ {
+ aOptions = pDlg->GetOptions();
+ Refresh( pDlg->GetURL(), pDlg->GetFilter(),
+ pDlg->GetSource(), pDlg->GetRefreshDelaySeconds() );
+
+ // copy source data from members (set in Refresh) into link name for dialog
+ OUString aNewLinkName;
+ sfx2::MakeLnkName( aNewLinkName, nullptr, aFileName, aSourceArea, &aFilterName );
+ SetName( aNewLinkName );
+ }
+}
+
+::sfx2::SvBaseLink::UpdateResult ScAreaLink::DataChanged(
+ const OUString&, const css::uno::Any& )
+{
+ // Do not do anything at bInCreate so that update can be called to set
+ // the status in the LinkManager without changing the data in the document
+
+ if (bInCreate)
+ return SUCCESS;
+
+ sfx2::LinkManager* pLinkManager=m_pDocSh->GetDocument().GetLinkManager();
+ if (pLinkManager!=nullptr)
+ {
+ OUString aFile, aArea, aFilter;
+ sfx2::LinkManager::GetDisplayNames(this, nullptr, &aFile, &aArea, &aFilter);
+
+ // the file dialog returns the filter name with the application prefix
+ // -> remove prefix
+ ScDocumentLoader::RemoveAppPrefix( aFilter );
+
+ // dialog doesn't set area, so keep old one
+ if (aArea.isEmpty())
+ {
+ aArea = aSourceArea;
+
+ // adjust in dialog:
+ OUString aNewLinkName;
+ OUString aTmp = aFilter;
+ sfx2::MakeLnkName(aNewLinkName, nullptr, aFile, aArea, &aTmp);
+ aFilter = aTmp;
+ SetName( aNewLinkName );
+ }
+
+ tools::SvRef<sfx2::SvBaseLink> const xThis(this); // keep yourself alive
+ Refresh( aFile, aFilter, aArea, GetRefreshDelaySeconds() );
+ }
+
+ return SUCCESS;
+}
+
+void ScAreaLink::Closed()
+{
+ // delete link: Undo
+
+ ScDocument& rDoc = m_pDocSh->GetDocument();
+ bool bUndo (rDoc.IsUndoEnabled());
+ if (bAddUndo && bUndo)
+ {
+ m_pDocSh->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoRemoveAreaLink>( m_pDocSh,
+ aFileName, aFilterName, aOptions,
+ aSourceArea, aDestArea, GetRefreshDelaySeconds() ) );
+
+ bAddUndo = false; // only once
+ }
+
+ SCTAB nDestTab = aDestArea.aStart.Tab();
+ rDoc.SetStreamValid(nDestTab, false);
+
+ SvBaseLink::Closed();
+}
+
+void ScAreaLink::SetDestArea(const ScRange& rNew)
+{
+ aDestArea = rNew; // for Undo
+}
+
+void ScAreaLink::SetSource(const OUString& rDoc, const OUString& rFlt, const OUString& rOpt,
+ const OUString& rArea)
+{
+ aFileName = rDoc;
+ aFilterName = rFlt;
+ aOptions = rOpt;
+ aSourceArea = rArea;
+
+ // also update link name for dialog
+ OUString aNewLinkName;
+ sfx2::MakeLnkName( aNewLinkName, nullptr, aFileName, aSourceArea, &aFilterName );
+ SetName( aNewLinkName );
+}
+
+bool ScAreaLink::IsEqual( std::u16string_view rFile, std::u16string_view rFilter, std::u16string_view rOpt,
+ std::u16string_view rSource, const ScRange& rDest ) const
+{
+ return aFileName == rFile && aFilterName == rFilter && aOptions == rOpt &&
+ aSourceArea == rSource && aDestArea.aStart == rDest.aStart;
+}
+
+// find a range with name >rAreaName< in >rSrcDoc<, return it in >rRange<
+bool ScAreaLink::FindExtRange( ScRange& rRange, const ScDocument& rSrcDoc, const OUString& rAreaName )
+{
+ bool bFound = false;
+ OUString aUpperName = ScGlobal::getCharClass().uppercase(rAreaName);
+ ScRangeName* pNames = rSrcDoc.GetRangeName();
+ if (pNames) // named ranges
+ {
+ const ScRangeData* p = pNames->findByUpperName(aUpperName);
+ if (p && p->IsValidReference(rRange))
+ bFound = true;
+ }
+ if (!bFound) // database ranges
+ {
+ ScDBCollection* pDBColl = rSrcDoc.GetDBCollection();
+ if (pDBColl)
+ {
+ const ScDBData* pDB = pDBColl->getNamedDBs().findByUpperName(aUpperName);
+ if (pDB)
+ {
+ SCTAB nTab;
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ pDB->GetArea(nTab,nCol1,nRow1,nCol2,nRow2);
+ rRange = ScRange( nCol1,nRow1,nTab, nCol2,nRow2,nTab );
+ bFound = true;
+ }
+ }
+ }
+ if (!bFound) // direct reference (range or cell)
+ {
+ ScAddress::Details aDetails(rSrcDoc.GetAddressConvention(), 0, 0);
+ if ( rRange.ParseAny( rAreaName, rSrcDoc, aDetails ) & ScRefFlags::VALID )
+ bFound = true;
+ }
+ return bFound;
+}
+
+// execute:
+
+bool ScAreaLink::Refresh( const OUString& rNewFile, const OUString& rNewFilter,
+ const OUString& rNewArea, sal_Int32 nNewRefreshDelaySeconds )
+{
+ // load document - like TabLink
+
+ if (rNewFile.isEmpty() || rNewFilter.isEmpty())
+ return false;
+
+ if (!m_pDocSh->GetEmbeddedObjectContainer().getUserAllowsLinkUpdate())
+ return false;
+
+ OUString aNewUrl( ScGlobal::GetAbsDocName( rNewFile, m_pDocSh ) );
+ bool bNewUrlName = (aNewUrl != aFileName);
+
+ std::shared_ptr<const SfxFilter> pFilter = m_pDocSh->GetFactory().GetFilterContainer()->GetFilter4FilterName(rNewFilter);
+ if (!pFilter)
+ return false;
+
+ ScDocument& rDoc = m_pDocSh->GetDocument();
+
+ bool bUndo (rDoc.IsUndoEnabled());
+ rDoc.SetInLinkUpdate( true );
+
+ // if new filter was selected, forget options
+ if ( rNewFilter != aFilterName )
+ aOptions.clear();
+
+ SfxMedium* pMed = ScDocumentLoader::CreateMedium( aNewUrl, pFilter, aOptions);
+
+ // aRef->DoClose() will be closed explicitly, but it is still more safe to use SfxObjectShellLock here
+ ScDocShell* pSrcShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS);
+ SfxObjectShellLock aRef = pSrcShell;
+ pSrcShell->DoLoad(pMed);
+
+ ScDocument& rSrcDoc = pSrcShell->GetDocument();
+
+ // options could have been set
+ OUString aNewOpt = ScDocumentLoader::GetOptions(*pMed);
+ if (aNewOpt.isEmpty())
+ aNewOpt = aOptions;
+
+ // correct source range name list for web query import
+ OUString aTempArea;
+
+ if( rNewFilter == ScDocShell::GetWebQueryFilterName() )
+ aTempArea = ScFormatFilter::Get().GetHTMLRangeNameList( rSrcDoc, rNewArea );
+ else
+ aTempArea = rNewArea;
+
+ // find total size of source area
+ SCCOL nWidth = 0;
+ SCROW nHeight = 0;
+ ScRangeList aSourceRanges;
+
+ if (rNewFilter == SC_TEXT_CSV_FILTER_NAME && aTempArea == "CSV_all")
+ {
+ // The dummy All range. All data, including top/left empty
+ // rows/columns.
+ aTempArea.clear();
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ if (rSrcDoc.GetCellArea( 0, nEndCol, nEndRow))
+ {
+ aSourceRanges.push_back( ScRange( 0,0,0, nEndCol, nEndRow, 0));
+ nWidth = nEndCol + 1;
+ nHeight = nEndRow + 2;
+ }
+ }
+
+ if (!aTempArea.isEmpty())
+ {
+ sal_Int32 nIdx {0};
+ do
+ {
+ ScRange aTokenRange;
+ if( FindExtRange( aTokenRange, rSrcDoc, aTempArea.getToken( 0, ';', nIdx ) ) )
+ {
+ aSourceRanges.push_back( aTokenRange);
+ // columns: find maximum
+ nWidth = std::max( nWidth, static_cast<SCCOL>(aTokenRange.aEnd.Col() - aTokenRange.aStart.Col() + 1) );
+ // rows: add row range + 1 empty row
+ nHeight += aTokenRange.aEnd.Row() - aTokenRange.aStart.Row() + 2;
+ }
+ }
+ while (nIdx>0);
+ }
+ // remove the last empty row
+ if( nHeight > 0 )
+ nHeight--;
+
+ // delete old data / copy new
+
+ ScAddress aDestPos = aDestArea.aStart;
+ SCTAB nDestTab = aDestPos.Tab();
+ ScRange aOldRange = aDestArea;
+ ScRange aNewRange = aDestArea; // old range, if file not found or similar
+ if (nWidth > 0 && nHeight > 0)
+ {
+ aNewRange.aEnd.SetCol( aNewRange.aStart.Col() + nWidth - 1 );
+ aNewRange.aEnd.SetRow( aNewRange.aStart.Row() + nHeight - 1 );
+ }
+
+ //! check CanFitBlock only if bDoInsert is set?
+ bool bCanDo = rDoc.ValidColRow( aNewRange.aEnd.Col(), aNewRange.aEnd.Row() ) &&
+ rDoc.CanFitBlock( aOldRange, aNewRange );
+ if (bCanDo)
+ {
+ ScDocShellModificator aModificator( *m_pDocSh );
+
+ SCCOL nOldEndX = aOldRange.aEnd.Col();
+ SCROW nOldEndY = aOldRange.aEnd.Row();
+ SCCOL nNewEndX = aNewRange.aEnd.Col();
+ SCROW nNewEndY = aNewRange.aEnd.Row();
+ ScRange aMaxRange( aDestPos,
+ ScAddress(std::max(nOldEndX,nNewEndX), std::max(nOldEndY,nNewEndY), nDestTab) );
+
+ // initialise Undo
+
+ ScDocumentUniquePtr pUndoDoc;
+ if ( bAddUndo && bUndo )
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ if ( bDoInsert )
+ {
+ if ( nNewEndX != nOldEndX || nNewEndY != nOldEndY ) // range changed?
+ {
+ pUndoDoc->InitUndo( rDoc, 0, rDoc.GetTableCount()-1 );
+ rDoc.CopyToDocument(0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB,
+ InsertDeleteFlags::FORMULA, false, *pUndoDoc); // all formulas
+ }
+ else
+ pUndoDoc->InitUndo( rDoc, nDestTab, nDestTab ); // only destination table
+ rDoc.CopyToDocument(aOldRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, *pUndoDoc);
+ }
+ else // without insertion
+ {
+ pUndoDoc->InitUndo( rDoc, nDestTab, nDestTab ); // only destination table
+ rDoc.CopyToDocument(aMaxRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, *pUndoDoc);
+ }
+ }
+
+ // insert / delete cells
+ // DeleteAreaTab also deletes MERGE_FLAG attributes
+
+ if (bDoInsert)
+ rDoc.FitBlock( aOldRange, aNewRange ); // incl. deletion
+ else
+ rDoc.DeleteAreaTab( aMaxRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+
+ // copy data
+
+ if (nWidth > 0 && nHeight > 0)
+ {
+ ScDocument aClipDoc( SCDOCMODE_CLIP );
+ ScRange aNewTokenRange( aNewRange.aStart );
+ for (size_t nRange = 0; nRange < aSourceRanges.size(); ++nRange)
+ {
+ ScRange const & rTokenRange( aSourceRanges[nRange]);
+ SCTAB nSrcTab = rTokenRange.aStart.Tab();
+ ScMarkData aSourceMark(rSrcDoc.GetSheetLimits());
+ aSourceMark.SelectOneTable( nSrcTab ); // selecting for CopyToClip
+ aSourceMark.SetMarkArea( rTokenRange );
+
+ ScClipParam aClipParam(rTokenRange, false);
+ rSrcDoc.CopyToClip(aClipParam, &aClipDoc, &aSourceMark, false, false);
+
+ if ( aClipDoc.HasAttrib( 0,0,nSrcTab, rDoc.MaxCol(),rDoc.MaxRow(),nSrcTab,
+ HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
+ {
+ //! ResetAttrib at document !!!
+
+ ScPatternAttr aPattern( rSrcDoc.GetPool() );
+ aPattern.GetItemSet().Put( ScMergeAttr() ); // Defaults
+ aPattern.GetItemSet().Put( ScMergeFlagAttr() );
+ aClipDoc.ApplyPatternAreaTab( 0,0, rDoc.MaxCol(),rDoc.MaxRow(), nSrcTab, aPattern );
+ }
+
+ aNewTokenRange.aEnd.SetCol( aNewTokenRange.aStart.Col() + (rTokenRange.aEnd.Col() - rTokenRange.aStart.Col()) );
+ aNewTokenRange.aEnd.SetRow( aNewTokenRange.aStart.Row() + (rTokenRange.aEnd.Row() - rTokenRange.aStart.Row()) );
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ aDestMark.SelectOneTable( nDestTab );
+ aDestMark.SetMarkArea( aNewTokenRange );
+ rDoc.CopyFromClip( aNewTokenRange, aDestMark, InsertDeleteFlags::ALL, nullptr, &aClipDoc, false );
+ aNewTokenRange.aStart.SetRow( aNewTokenRange.aEnd.Row() + 2 );
+ }
+ }
+ else
+ {
+ OUString aErr = ScResId(STR_LINKERROR);
+ rDoc.SetString( aDestPos.Col(), aDestPos.Row(), aDestPos.Tab(), aErr );
+ }
+
+ // enter Undo
+
+ if ( bAddUndo && bUndo)
+ {
+ ScDocumentUniquePtr pRedoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pRedoDoc->InitUndo( rDoc, nDestTab, nDestTab );
+ rDoc.CopyToDocument(aNewRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, *pRedoDoc);
+
+ m_pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoUpdateAreaLink>( m_pDocSh,
+ aFileName, aFilterName, aOptions,
+ aSourceArea, aOldRange, GetRefreshDelaySeconds(),
+ aNewUrl, rNewFilter, aNewOpt,
+ rNewArea, aNewRange, nNewRefreshDelaySeconds,
+ std::move(pUndoDoc), std::move(pRedoDoc), bDoInsert ) );
+ }
+
+ // remember new settings
+
+ if ( bNewUrlName )
+ aFileName = aNewUrl;
+ if ( rNewFilter != aFilterName )
+ aFilterName = rNewFilter;
+ if ( rNewArea != aSourceArea )
+ aSourceArea = rNewArea;
+ if ( aNewOpt != aOptions )
+ aOptions = aNewOpt;
+
+ if ( aNewRange != aDestArea )
+ aDestArea = aNewRange;
+
+ if ( nNewRefreshDelaySeconds != GetRefreshDelaySeconds() )
+ SetRefreshDelay( nNewRefreshDelaySeconds );
+
+ SCCOL nPaintEndX = std::max( aOldRange.aEnd.Col(), aNewRange.aEnd.Col() );
+ SCROW nPaintEndY = std::max( aOldRange.aEnd.Row(), aNewRange.aEnd.Row() );
+
+ if ( aOldRange.aEnd.Col() != aNewRange.aEnd.Col() )
+ nPaintEndX = rDoc.MaxCol();
+ if ( aOldRange.aEnd.Row() != aNewRange.aEnd.Row() )
+ nPaintEndY = rDoc.MaxRow();
+
+ if ( !m_pDocSh->AdjustRowHeight( aDestPos.Row(), nPaintEndY, nDestTab ) )
+ m_pDocSh->PostPaint(
+ ScRange(aDestPos.Col(), aDestPos.Row(), nDestTab, nPaintEndX, nPaintEndY, nDestTab),
+ PaintPartFlags::Grid);
+ aModificator.SetDocumentModified();
+ }
+ else
+ {
+ // CanFitBlock sal_False -> Problems with summarized cells or table boundary reached!
+ //! cell protection ???
+
+ //! Link dialog must set default parent
+ // "cannot insert rows"
+ weld::Window* pWin = Application::GetFrameWeld(m_pDocSh->GetDialogParent());
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pWin,
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_MSSG_DOSUBTOTALS_2)));
+ xInfoBox->run();
+ }
+
+ // clean up
+
+ aRef->DoClose();
+
+ rDoc.SetInLinkUpdate( false );
+
+ if (bCanDo)
+ {
+ // notify Uno objects (for XRefreshListener)
+ //! also notify Uno objects if file name was changed!
+ ScLinkRefreshedHint aHint;
+ aHint.SetAreaLink( aDestPos );
+ rDoc.BroadcastUno( aHint );
+ }
+
+ return bCanDo;
+}
+
+IMPL_LINK_NOARG(ScAreaLink, RefreshHdl, Timer *, void)
+{
+ Refresh( aFileName, aFilterName, aSourceArea, GetRefreshDelaySeconds() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/autostyl.cxx b/sc/source/ui/docshell/autostyl.cxx
new file mode 100644
index 000000000..5b6eaa30c
--- /dev/null
+++ b/sc/source/ui/docshell/autostyl.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 <time.h>
+#include <osl/diagnose.h>
+
+#include <address.hxx>
+#include <autostyl.hxx>
+#include <docsh.hxx>
+
+static sal_uLong TimeNow() // seconds
+{
+ return static_cast<sal_uLong>(time(nullptr));
+}
+
+namespace {
+
+class FindByRange
+{
+ ScRange maRange;
+public:
+ explicit FindByRange(const ScRange& r) : maRange(r) {}
+ bool operator() (const ScAutoStyleData& rData) const { return rData.aRange == maRange; }
+};
+
+class FindByTimeout
+{
+ sal_uLong mnTimeout;
+public:
+ explicit FindByTimeout(sal_uLong n) : mnTimeout(n) {}
+ bool operator() (const ScAutoStyleData& rData) const { return rData.nTimeout >= mnTimeout; }
+};
+
+struct FindNonZeroTimeout
+{
+ bool operator() (const ScAutoStyleData& rData) const
+ {
+ return rData.nTimeout != 0;
+ }
+};
+
+}
+
+ScAutoStyleList::ScAutoStyleList(ScDocShell* pShell)
+ : pDocSh(pShell)
+ , aTimer("ScAutoStyleList Timer")
+ , aInitIdle("ScAutoStyleList InitIdle")
+ , nTimerStart(0)
+{
+ aTimer.SetInvokeHandler( LINK( this, ScAutoStyleList, TimerHdl ) );
+ aInitIdle.SetInvokeHandler( LINK( this, ScAutoStyleList, InitHdl ) );
+ aInitIdle.SetPriority( TaskPriority::HIGHEST );
+}
+
+ScAutoStyleList::~ScAutoStyleList()
+{
+}
+
+// initial short delay (asynchronous call)
+
+void ScAutoStyleList::AddInitial( const ScRange& rRange, const OUString& rStyle1,
+ sal_uLong nTimeout, const OUString& rStyle2 )
+{
+ aInitials.emplace_back( rRange, rStyle1, nTimeout, rStyle2 );
+ aInitIdle.Start();
+}
+
+IMPL_LINK_NOARG(ScAutoStyleList, InitHdl, Timer *, void)
+{
+ std::vector<ScAutoStyleInitData> aLocalInitials(std::move(aInitials));
+ for (const auto& rInitial : aLocalInitials)
+ {
+ // apply first style immediately
+ pDocSh->DoAutoStyle(rInitial.aRange, rInitial.aStyle1);
+
+ // add second style to list
+ if (rInitial.nTimeout)
+ AddEntry(rInitial.nTimeout, rInitial.aRange, rInitial.aStyle2 );
+ }
+}
+
+void ScAutoStyleList::AddEntry( sal_uLong nTimeout, const ScRange& rRange, const OUString& rStyle )
+{
+ aTimer.Stop();
+ sal_uLong nNow = TimeNow();
+
+ // Remove the first item with the same range.
+ std::vector<ScAutoStyleData>::iterator itr =
+ ::std::find_if(aEntries.begin(), aEntries.end(), FindByRange(rRange));
+
+ if (itr != aEntries.end())
+ aEntries.erase(itr);
+
+ // adjust timeouts of all entries
+
+ if (!aEntries.empty() && nNow != nTimerStart)
+ {
+ OSL_ENSURE(nNow>nTimerStart, "Time is running backwards?");
+ AdjustEntries((nNow-nTimerStart)*1000);
+ }
+
+ // find insert position
+ std::vector<ScAutoStyleData>::iterator iter =
+ ::std::find_if(aEntries.begin(), aEntries.end(), FindByTimeout(nTimeout));
+
+ aEntries.insert(iter, ScAutoStyleData(nTimeout,rRange,rStyle));
+
+ // execute expired, restart timer
+
+ ExecuteEntries();
+ StartTimer(nNow);
+}
+
+void ScAutoStyleList::AdjustEntries( sal_uLong nDiff ) // milliseconds
+{
+ for (auto& rEntry : aEntries)
+ {
+ if (rEntry.nTimeout <= nDiff)
+ rEntry.nTimeout = 0; // expired
+ else
+ rEntry.nTimeout -= nDiff; // continue counting
+ }
+}
+
+void ScAutoStyleList::ExecuteEntries()
+{
+ // Execute and remove all items with timeout == 0 from the begin position
+ // until the first item with non-zero timeout value.
+ std::vector<ScAutoStyleData>::iterator itr = aEntries.begin(), itrEnd = aEntries.end();
+ for (; itr != itrEnd; ++itr)
+ {
+ if (itr->nTimeout)
+ break;
+
+ pDocSh->DoAutoStyle(itr->aRange, itr->aStyle);
+ }
+ // At this point itr should be on the first item with non-zero timeout, or
+ // the end position in case all items have timeout == 0.
+ aEntries.erase(aEntries.begin(), itr);
+}
+
+void ScAutoStyleList::ExecuteAllNow()
+{
+ aTimer.Stop();
+
+ for (const auto& rEntry : aEntries)
+ pDocSh->DoAutoStyle(rEntry.aRange, rEntry.aStyle);
+
+ aEntries.clear();
+}
+
+void ScAutoStyleList::StartTimer( sal_uLong nNow ) // seconds
+{
+ // find first entry with Timeout != 0
+ std::vector<ScAutoStyleData>::iterator iter =
+ ::std::find_if(aEntries.begin(),aEntries.end(), FindNonZeroTimeout());
+
+ if (iter != aEntries.end())
+ {
+ aTimer.SetTimeout(iter->nTimeout);
+ aTimer.Start();
+ }
+
+ nTimerStart = nNow;
+}
+
+IMPL_LINK_NOARG(ScAutoStyleList, TimerHdl, Timer *, void)
+{
+ sal_uLong nNow = TimeNow();
+ AdjustEntries(aTimer.GetTimeout()); // the set waiting time
+ ExecuteEntries();
+ StartTimer(nNow);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/datastream.cxx b/sc/source/ui/docshell/datastream.cxx
new file mode 100644
index 000000000..4bcbbaf99
--- /dev/null
+++ b/sc/source/ui/docshell/datastream.cxx
@@ -0,0 +1,549 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <datastream.hxx>
+#include <datastreamgettime.hxx>
+
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <osl/conditn.hxx>
+#include <osl/time.h>
+#include <salhelper/thread.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <tools/stream.hxx>
+#include <vcl/svapp.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <viewdata.hxx>
+#include <stringutil.hxx>
+#include <documentlinkmgr.hxx>
+#include <o3tl/enumarray.hxx>
+
+#include <officecfg/Office/Calc.hxx>
+
+#include <orcus/csv_parser.hpp>
+
+#include <queue>
+
+namespace com::sun::star::ui { class XUIElement; }
+
+namespace sc {
+
+static o3tl::enumarray<DebugTime, double> fTimes { 0.0, 0.0, 0.0 };
+
+double datastream_get_time(DebugTime nIdx)
+{
+ return fTimes[ nIdx ];
+}
+
+namespace {
+
+double getNow()
+{
+ TimeValue now;
+ osl_getSystemTime(&now);
+ return static_cast<double>(now.Seconds) + static_cast<double>(now.Nanosec) / 1000000000.0;
+}
+
+class CSVHandler
+{
+ DataStream::Line& mrLine;
+ size_t mnColCount;
+ size_t mnCols;
+ const char* mpLineHead;
+
+public:
+ CSVHandler( DataStream::Line& rLine, size_t nColCount ) :
+ mrLine(rLine), mnColCount(nColCount), mnCols(0), mpLineHead(rLine.maLine.getStr()) {}
+
+ static void begin_parse() {}
+ static void end_parse() {}
+ static void begin_row() {}
+ static void end_row() {}
+
+ void cell(const char* p, size_t n, bool /*transient*/)
+ {
+ if (mnCols >= mnColCount)
+ return;
+
+ DataStream::Cell aCell;
+ if (ScStringUtil::parseSimpleNumber(p, n, '.', ',', aCell.mfValue))
+ {
+ aCell.mbValue = true;
+ }
+ else
+ {
+ aCell.mbValue = false;
+ aCell.maStr.Pos = std::distance(mpLineHead, p);
+ aCell.maStr.Size = n;
+ }
+ mrLine.maCells.push_back(aCell);
+
+ ++mnCols;
+ }
+};
+
+}
+
+namespace datastreams {
+
+class ReaderThread : public salhelper::Thread
+{
+ std::unique_ptr<SvStream> mpStream;
+ size_t mnColCount;
+ bool mbTerminate;
+ osl::Mutex maMtxTerminate;
+
+ std::queue<std::unique_ptr<DataStream::LinesType>> maPendingLines;
+ std::queue<std::unique_ptr<DataStream::LinesType>> maUsedLines;
+ osl::Mutex maMtxLines;
+
+ osl::Condition maCondReadStream;
+ osl::Condition maCondConsume;
+
+ orcus::csv::parser_config maConfig;
+
+public:
+
+ ReaderThread(std::unique_ptr<SvStream> pData, size_t nColCount):
+ Thread("ReaderThread"),
+ mpStream(std::move(pData)),
+ mnColCount(nColCount),
+ mbTerminate(false)
+ {
+ maConfig.delimiters.push_back(',');
+ maConfig.text_qualifier = '"';
+ }
+
+ bool isTerminateRequested()
+ {
+ osl::MutexGuard aGuard(maMtxTerminate);
+ return mbTerminate;
+ }
+
+ void requestTerminate()
+ {
+ osl::MutexGuard aGuard(maMtxTerminate);
+ mbTerminate = true;
+ }
+
+ void endThread()
+ {
+ requestTerminate();
+ maCondReadStream.set();
+ }
+
+ void waitForNewLines()
+ {
+ maCondConsume.wait();
+ maCondConsume.reset();
+ }
+
+ std::unique_ptr<DataStream::LinesType> popNewLines()
+ {
+ auto pLines = std::move(maPendingLines.front());
+ maPendingLines.pop();
+ return pLines;
+ }
+
+ void resumeReadStream()
+ {
+ if (maPendingLines.size() <= 4)
+ maCondReadStream.set(); // start producer again
+ }
+
+ bool hasNewLines() const
+ {
+ return !maPendingLines.empty();
+ }
+
+ void pushUsedLines( std::unique_ptr<DataStream::LinesType> pLines )
+ {
+ maUsedLines.push(std::move(pLines));
+ }
+
+ osl::Mutex& getLinesMutex()
+ {
+ return maMtxLines;
+ }
+
+private:
+ virtual void execute() override
+ {
+ while (!isTerminateRequested())
+ {
+ std::unique_ptr<DataStream::LinesType> pLines;
+ osl::ResettableMutexGuard aGuard(maMtxLines);
+
+ if (!maUsedLines.empty())
+ {
+ // Re-use lines from previous runs.
+ pLines = std::move(maUsedLines.front());
+ maUsedLines.pop();
+ aGuard.clear(); // unlock
+ }
+ else
+ {
+ aGuard.clear(); // unlock
+ pLines.reset(new DataStream::LinesType(10));
+ }
+
+ // Read & store new lines from stream.
+ for (DataStream::Line & rLine : *pLines)
+ {
+ rLine.maCells.clear();
+ mpStream->ReadLine(rLine.maLine);
+ CSVHandler aHdl(rLine, mnColCount);
+ orcus::csv_parser<CSVHandler> parser(rLine.maLine.getStr(), rLine.maLine.getLength(), aHdl, maConfig);
+ parser.parse();
+ }
+
+ aGuard.reset(); // lock
+ while (!isTerminateRequested() && maPendingLines.size() >= 8)
+ {
+ // pause reading for a bit
+ aGuard.clear(); // unlock
+ maCondReadStream.wait();
+ maCondReadStream.reset();
+ aGuard.reset(); // lock
+ }
+ maPendingLines.push(std::move(pLines));
+ maCondConsume.set();
+ if (!mpStream->good())
+ requestTerminate();
+ }
+ }
+};
+
+}
+
+DataStream::Cell::Cell() : mfValue(0.0), mbValue(true) {}
+
+DataStream::Cell::Cell( const Cell& r ) : mbValue(r.mbValue)
+{
+ if (r.mbValue)
+ mfValue = r.mfValue;
+ else
+ {
+ maStr.Pos = r.maStr.Pos;
+ maStr.Size = r.maStr.Size;
+ }
+}
+
+void DataStream::MakeToolbarVisible()
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ css::uno::Reference< css::frame::XFrame > xFrame =
+ pViewData->GetViewShell()->GetViewFrame()->GetFrame().GetFrameInterface();
+ if (!xFrame.is())
+ return;
+
+ css::uno::Reference< css::beans::XPropertySet > xPropSet(xFrame, css::uno::UNO_QUERY);
+ if (!xPropSet.is())
+ return;
+
+ css::uno::Reference< css::frame::XLayoutManager > xLayoutManager;
+ xPropSet->getPropertyValue("LayoutManager") >>= xLayoutManager;
+ if (!xLayoutManager.is())
+ return;
+
+ static const OUStringLiteral sResourceURL( u"private:resource/toolbar/datastreams" );
+ css::uno::Reference< css::ui::XUIElement > xUIElement = xLayoutManager->getElement(sResourceURL);
+ if (!xUIElement.is())
+ {
+ xLayoutManager->createElement( sResourceURL );
+ xLayoutManager->showElement( sResourceURL );
+ }
+}
+
+DataStream* DataStream::Set(
+ ScDocShell *pShell, const OUString& rURL, const ScRange& rRange,
+ sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings)
+{
+ DataStream* pLink = new DataStream(pShell, rURL, rRange, nLimit, eMove, nSettings);
+ sc::DocumentLinkManager& rMgr = pShell->GetDocument().GetDocLinkManager();
+ rMgr.setDataStream(pLink);
+ return pLink;
+}
+
+DataStream::DataStream(ScDocShell *pShell, const OUString& rURL, const ScRange& rRange,
+ sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings) :
+ mpDocShell(pShell),
+ maDocAccess(mpDocShell->GetDocument()),
+ meOrigMove(NO_MOVE),
+ meMove(NO_MOVE),
+ mbRunning(false),
+ mbValuesInLine(false),
+ mbRefreshOnEmptyLine(false),
+ mnLinesCount(0),
+ mnLinesSinceRefresh(0),
+ mfLastRefreshTime(0.0),
+ mnCurRow(0),
+ maImportTimer("sc DataStream maImportTimer"),
+ mbIsFirst(true),
+ mbIsUpdate(false)
+{
+ maImportTimer.SetTimeout(0);
+ maImportTimer.SetInvokeHandler( LINK(this, DataStream, ImportTimerHdl) );
+
+ Decode(rURL, rRange, nLimit, eMove, nSettings);
+}
+
+DataStream::~DataStream()
+{
+ if (mbRunning)
+ StopImport();
+
+ if (mxReaderThread.is())
+ {
+ mxReaderThread->endThread();
+ mxReaderThread->join();
+ }
+ mpLines.reset();
+}
+
+DataStream::Line DataStream::ConsumeLine()
+{
+ if (!mpLines || mnLinesCount >= mpLines->size())
+ {
+ mnLinesCount = 0;
+ if (mxReaderThread->isTerminateRequested())
+ return Line();
+
+ osl::ResettableMutexGuard aGuard(mxReaderThread->getLinesMutex());
+ if (mpLines)
+ mxReaderThread->pushUsedLines(std::move(mpLines));
+
+ while (!mxReaderThread->hasNewLines())
+ {
+ aGuard.clear(); // unlock
+ mxReaderThread->waitForNewLines();
+ aGuard.reset(); // lock
+ }
+
+ mpLines = mxReaderThread->popNewLines();
+ mxReaderThread->resumeReadStream();
+ }
+ return mpLines->at(mnLinesCount++);
+}
+
+ScRange DataStream::GetRange() const
+{
+ ScRange aRange = maStartRange;
+ aRange.aEnd = maEndRange.aEnd;
+ return aRange;
+}
+
+void DataStream::Decode(const OUString& rURL, const ScRange& rRange,
+ sal_Int32 nLimit, MoveType eMove, const sal_uInt32 nSettings)
+{
+ msURL = rURL;
+ meMove = eMove;
+ meOrigMove = eMove;
+ mnSettings = nSettings;
+
+ mbValuesInLine = true; // always true.
+
+ mnCurRow = rRange.aStart.Row();
+
+ ScRange aRange = rRange;
+ if (aRange.aStart.Row() != aRange.aEnd.Row())
+ // We only allow this range to be one row tall.
+ aRange.aEnd.SetRow(aRange.aStart.Row());
+
+ maStartRange = aRange;
+ maEndRange = aRange;
+ const auto & rDoc = mpDocShell->GetDocument();
+ if (nLimit == 0)
+ {
+ // Unlimited
+ maEndRange.aStart.SetRow(rDoc.MaxRow());
+ }
+ else if (nLimit > 0)
+ {
+ // Limited.
+ maEndRange.aStart.IncRow(nLimit-1);
+ if (maEndRange.aStart.Row() > rDoc.MaxRow())
+ maEndRange.aStart.SetRow(rDoc.MaxRow());
+ }
+
+ maEndRange.aEnd.SetRow(maEndRange.aStart.Row());
+}
+
+void DataStream::StartImport()
+{
+ if (mbRunning)
+ return;
+
+ if (!mxReaderThread.is())
+ {
+ std::unique_ptr<SvStream> pStream(new SvFileStream(msURL, StreamMode::READ));
+ mxReaderThread = new datastreams::ReaderThread(std::move(pStream), maStartRange.aEnd.Col() - maStartRange.aStart.Col() + 1);
+ mxReaderThread->launch();
+ }
+ mbRunning = true;
+ maDocAccess.reset();
+
+ maImportTimer.Start();
+}
+
+void DataStream::StopImport()
+{
+ if (!mbRunning)
+ return;
+
+ mbRunning = false;
+ Refresh();
+ maImportTimer.Stop();
+}
+
+void DataStream::SetRefreshOnEmptyLine( bool bVal )
+{
+ mbRefreshOnEmptyLine = bVal;
+}
+
+void DataStream::Refresh()
+{
+ Application::Yield();
+
+ double fStart = getNow();
+
+ // Hard recalc will repaint the grid area.
+ mpDocShell->DoHardRecalc();
+ mpDocShell->SetDocumentModified();
+
+ fTimes[ DebugTime::Recalc ] = getNow() - fStart;
+
+ mfLastRefreshTime = getNow();
+ mnLinesSinceRefresh = 0;
+}
+
+void DataStream::MoveData()
+{
+ switch (meMove)
+ {
+ case RANGE_DOWN:
+ {
+ if (mnCurRow == maEndRange.aStart.Row())
+ meMove = MOVE_UP;
+ }
+ break;
+ case MOVE_UP:
+ {
+ mbIsUpdate = true;
+ // Remove the top row and shift the remaining rows upward. Then
+ // insert a new row at the end row position.
+ ScRange aRange = maStartRange;
+ aRange.aEnd = maEndRange.aEnd;
+ maDocAccess.shiftRangeUp(aRange);
+ }
+ break;
+ case MOVE_DOWN:
+ {
+ mbIsUpdate = true;
+ // Remove the end row and shift the remaining rows downward by
+ // inserting a new row at the top row.
+ ScRange aRange = maStartRange;
+ aRange.aEnd = maEndRange.aEnd;
+ maDocAccess.shiftRangeDown(aRange);
+ }
+ break;
+ case NO_MOVE:
+ default:
+ ;
+ }
+ if(mbIsFirst && mbIsUpdate)
+ {
+ sal_Int32 nStreamTimeout = officecfg::Office::Calc::DataStream::UpdateTimeout::get();
+ maImportTimer.SetTimeout(nStreamTimeout);
+ mbIsFirst = false;
+ }
+}
+
+void DataStream::Text2Doc()
+{
+ Line aLine = ConsumeLine();
+ if (aLine.maCells.empty() && mbRefreshOnEmptyLine)
+ {
+ // Empty line detected. Trigger refresh and discard it.
+ Refresh();
+ return;
+ }
+
+ double fStart = getNow();
+
+ MoveData();
+ {
+ SCCOL nCol = maStartRange.aStart.Col();
+ const char* pLineHead = aLine.maLine.getStr();
+ for (const Cell& rCell : aLine.maCells)
+ {
+ if (rCell.mbValue)
+ {
+ maDocAccess.setNumericCell(
+ ScAddress(nCol, mnCurRow, maStartRange.aStart.Tab()), rCell.mfValue);
+ }
+ else
+ {
+ maDocAccess.setStringCell(
+ ScAddress(nCol, mnCurRow, maStartRange.aStart.Tab()),
+ OUString(pLineHead+rCell.maStr.Pos, rCell.maStr.Size, RTL_TEXTENCODING_UTF8));
+ }
+ ++nCol;
+ }
+ }
+
+ fTimes[ DebugTime::Import ] = getNow() - fStart;
+
+ if (meMove == NO_MOVE)
+ return;
+
+ if (meMove == RANGE_DOWN)
+ {
+ ++mnCurRow;
+// mpDocShell->GetViewData().GetView()->AlignToCursor(
+// maStartRange.aStart.Col(), mnCurRow, SC_FOLLOW_JUMP);
+ }
+
+ if (getNow() - mfLastRefreshTime > 0.1 && mnLinesSinceRefresh > 200)
+ // Refresh no more frequently than every 0.1 second, and wait until at
+ // least we have processed 200 lines.
+ Refresh();
+
+ ++mnLinesSinceRefresh;
+}
+
+bool DataStream::ImportData()
+{
+ if (!mbValuesInLine)
+ // We no longer support this mode. To be deleted later.
+ return false;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return false;
+
+ if (pViewData->GetViewShell()->NeedsRepaint())
+ return mbRunning;
+
+ Text2Doc();
+ return mbRunning;
+}
+
+IMPL_LINK_NOARG(DataStream, ImportTimerHdl, Timer *, void)
+{
+ if (ImportData())
+ maImportTimer.Start();
+}
+
+} // namespace sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/dbdocfun.cxx b/sc/source/ui/docshell/dbdocfun.cxx
new file mode 100644
index 000000000..ee59f3623
--- /dev/null
+++ b/sc/source/ui/docshell/dbdocfun.cxx
@@ -0,0 +1,1790 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/app.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdoole2.hxx>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <unotools/charclass.hxx>
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+
+#include <dbdocfun.hxx>
+#include <dbdata.hxx>
+#include <undodat.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <globalnames.hxx>
+#include <tabvwsh.hxx>
+#include <patattr.hxx>
+#include <rangenam.hxx>
+#include <olinetab.hxx>
+#include <dpobject.hxx>
+#include <dpsave.hxx>
+#include <dociter.hxx>
+#include <editable.hxx>
+#include <attrib.hxx>
+#include <drwlayer.hxx>
+#include <dpshttab.hxx>
+#include <hints.hxx>
+#include <queryentry.hxx>
+#include <markdata.hxx>
+#include <progress.hxx>
+#include <undosort.hxx>
+#include <inputopt.hxx>
+#include <scmod.hxx>
+
+#include <chartlis.hxx>
+#include <ChartTools.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+
+bool ScDBDocFunc::AddDBRange( const OUString& rName, const ScRange& rRange )
+{
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScDBCollection* pDocColl = rDoc.GetDBCollection();
+ bool bUndo (rDoc.IsUndoEnabled());
+
+ std::unique_ptr<ScDBCollection> pUndoColl;
+ if (bUndo)
+ pUndoColl.reset( new ScDBCollection( *pDocColl ) );
+
+ std::unique_ptr<ScDBData> pNew(new ScDBData( rName, rRange.aStart.Tab(),
+ rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row() ));
+
+ // #i55926# While loading XML, formula cells only have a single string token,
+ // so CompileDBFormula would never find any name (index) tokens, and would
+ // unnecessarily loop through all cells.
+ bool bCompile = !rDoc.IsImportingXML();
+ bool bOk;
+ if ( bCompile )
+ rDoc.PreprocessDBDataUpdate();
+ if ( rName == STR_DB_LOCAL_NONAME )
+ {
+ rDoc.SetAnonymousDBData(rRange.aStart.Tab(), std::move(pNew));
+ bOk = true;
+ }
+ else
+ {
+ bOk = pDocColl->getNamedDBs().insert(std::move(pNew));
+ }
+ if ( bCompile )
+ rDoc.CompileHybridFormula();
+
+ if (!bOk)
+ {
+ return false;
+ }
+
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDBData>( &rDocShell, std::move(pUndoColl),
+ std::make_unique<ScDBCollection>( *pDocColl ) ) );
+ }
+
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+ return true;
+}
+
+bool ScDBDocFunc::DeleteDBRange(const OUString& rName)
+{
+ bool bDone = false;
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScDBCollection* pDocColl = rDoc.GetDBCollection();
+ bool bUndo = rDoc.IsUndoEnabled();
+
+ ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
+ auto const iter = rDBs.findByUpperName2(ScGlobal::getCharClass().uppercase(rName));
+ if (iter != rDBs.end())
+ {
+ ScDocShellModificator aModificator( rDocShell );
+
+ std::unique_ptr<ScDBCollection> pUndoColl;
+ if (bUndo)
+ pUndoColl.reset( new ScDBCollection( *pDocColl ) );
+
+ rDoc.PreprocessDBDataUpdate();
+ rDBs.erase(iter);
+ rDoc.CompileHybridFormula();
+
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDBData>( &rDocShell, std::move(pUndoColl),
+ std::make_unique<ScDBCollection>( *pDocColl ) ) );
+ }
+
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+ bDone = true;
+ }
+
+ return bDone;
+}
+
+bool ScDBDocFunc::RenameDBRange( const OUString& rOld, const OUString& rNew )
+{
+ bool bDone = false;
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScDBCollection* pDocColl = rDoc.GetDBCollection();
+ bool bUndo = rDoc.IsUndoEnabled();
+ ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
+ auto const iterOld = rDBs.findByUpperName2(ScGlobal::getCharClass().uppercase(rOld));
+ const ScDBData* pNew = rDBs.findByUpperName(ScGlobal::getCharClass().uppercase(rNew));
+ if (iterOld != rDBs.end() && !pNew)
+ {
+ ScDocShellModificator aModificator( rDocShell );
+
+ std::unique_ptr<ScDBData> pNewData(new ScDBData(rNew, **iterOld));
+
+ std::unique_ptr<ScDBCollection> pUndoColl( new ScDBCollection( *pDocColl ) );
+
+ rDoc.PreprocessDBDataUpdate();
+ rDBs.erase(iterOld);
+ bool bInserted = rDBs.insert(std::move(pNewData));
+ if (!bInserted) // error -> restore old state
+ {
+ rDoc.SetDBCollection(std::move(pUndoColl)); // belongs to the document then
+ }
+
+ rDoc.CompileHybridFormula();
+
+ if (bInserted) // insertion worked
+ {
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDBData>( &rDocShell, std::move(pUndoColl),
+ std::make_unique<ScDBCollection>( *pDocColl ) ) );
+ }
+ else
+ pUndoColl.reset();
+
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+ bDone = true;
+ }
+ }
+
+ return bDone;
+}
+
+void ScDBDocFunc::ModifyDBData( const ScDBData& rNewData )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScDBCollection* pDocColl = rDoc.GetDBCollection();
+ bool bUndo = rDoc.IsUndoEnabled();
+
+ ScDBData* pData = nullptr;
+ if (rNewData.GetName() == STR_DB_LOCAL_NONAME)
+ {
+ ScRange aRange;
+ rNewData.GetArea(aRange);
+ SCTAB nTab = aRange.aStart.Tab();
+ pData = rDoc.GetAnonymousDBData(nTab);
+ }
+ else
+ pData = pDocColl->getNamedDBs().findByUpperName(rNewData.GetUpperName());
+
+ if (!pData)
+ return;
+
+ ScDocShellModificator aModificator( rDocShell );
+ ScRange aOldRange, aNewRange;
+ pData->GetArea(aOldRange);
+ rNewData.GetArea(aNewRange);
+ bool bAreaChanged = ( aOldRange != aNewRange ); // then a recompilation is needed
+
+ std::unique_ptr<ScDBCollection> pUndoColl;
+ if (bUndo)
+ pUndoColl.reset( new ScDBCollection( *pDocColl ) );
+
+ *pData = rNewData;
+ if (bAreaChanged)
+ rDoc.CompileDBFormula();
+
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDBData>( &rDocShell, std::move(pUndoColl),
+ std::make_unique<ScDBCollection>( *pDocColl ) ) );
+ }
+
+ aModificator.SetDocumentModified();
+}
+
+void ScDBDocFunc::ModifyAllDBData( const ScDBCollection& rNewColl, const std::vector<ScRange>& rDelAreaList )
+{
+ ScDocShellModificator aModificator(rDocShell);
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScDBCollection* pOldColl = rDoc.GetDBCollection();
+ std::unique_ptr<ScDBCollection> pUndoColl;
+ bool bRecord = rDoc.IsUndoEnabled();
+
+ for (const auto& rDelArea : rDelAreaList)
+ {
+ // unregistering target in SBA no longer necessary
+ const ScAddress& rStart = rDelArea.aStart;
+ const ScAddress& rEnd = rDelArea.aEnd;
+ rDocShell.DBAreaDeleted(
+ rStart.Tab(), rStart.Col(), rStart.Row(), rEnd.Col());
+ }
+
+ if (bRecord)
+ pUndoColl.reset( new ScDBCollection( *pOldColl ) );
+
+ // register target in SBA no longer necessary
+
+ rDoc.PreprocessDBDataUpdate();
+ rDoc.SetDBCollection( std::unique_ptr<ScDBCollection>(new ScDBCollection( rNewColl )) );
+ rDoc.CompileHybridFormula();
+ pOldColl = nullptr;
+ rDocShell.PostPaint(ScRange(0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB), PaintPartFlags::Grid);
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+
+ if (bRecord)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDBData>(&rDocShell, std::move(pUndoColl),
+ std::make_unique<ScDBCollection>(rNewColl)));
+ }
+}
+
+bool ScDBDocFunc::RepeatDB( const OUString& rDBName, bool bApi, bool bIsUnnamed, SCTAB aTab )
+{
+ //! use also for ScDBFunc::RepeatDB !
+
+ bool bDone = false;
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+ ScDBData* pDBData = nullptr;
+ if (bIsUnnamed)
+ {
+ pDBData = rDoc.GetAnonymousDBData( aTab );
+ }
+ else
+ {
+ ScDBCollection* pColl = rDoc.GetDBCollection();
+ if (pColl)
+ pDBData = pColl->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rDBName));
+ }
+
+ if ( pDBData )
+ {
+ ScQueryParam aQueryParam;
+ pDBData->GetQueryParam( aQueryParam );
+ bool bQuery = aQueryParam.GetEntry(0).bDoQuery;
+
+ ScSortParam aSortParam;
+ pDBData->GetSortParam( aSortParam );
+ bool bSort = aSortParam.maKeyState[0].bDoSort;
+
+ ScSubTotalParam aSubTotalParam;
+ pDBData->GetSubTotalParam( aSubTotalParam );
+ bool bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly;
+
+ if ( bQuery || bSort || bSubTotal )
+ {
+ bool bQuerySize = false;
+ ScRange aOldQuery;
+ ScRange aNewQuery;
+ if (bQuery && !aQueryParam.bInplace)
+ {
+ ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
+ aQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
+ if (pDest && pDest->IsDoSize())
+ {
+ pDest->GetArea( aOldQuery );
+ bQuerySize = true;
+ }
+ }
+
+ SCTAB nTab;
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ pDBData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
+
+ //! Undo needed data only ?
+
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScOutlineTable> pUndoTab;
+ std::unique_ptr<ScRangeName> pUndoRange;
+ std::unique_ptr<ScDBCollection> pUndoDB;
+
+ if (bRecord)
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+ if (pTable)
+ {
+ pUndoTab.reset(new ScOutlineTable( *pTable ));
+
+ // column/row state
+ SCCOLROW nOutStartCol, nOutEndCol;
+ SCCOLROW nOutStartRow, nOutEndRow;
+ pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
+ pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
+
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ rDoc.CopyToDocument(static_cast<SCCOL>(nOutStartCol), 0,
+ nTab, static_cast<SCCOL>(nOutEndCol), rDoc.MaxRow(), nTab,
+ InsertDeleteFlags::NONE, false, *pUndoDoc);
+ rDoc.CopyToDocument(0, static_cast<SCROW>(nOutStartRow),
+ nTab, rDoc.MaxCol(), static_cast<SCROW>(nOutEndRow), nTab,
+ InsertDeleteFlags::NONE, false, *pUndoDoc);
+ }
+ else
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
+
+ // secure data range - incl. filtering result
+ rDoc.CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::ALL, false, *pUndoDoc);
+
+ // all formulas because of references
+ rDoc.CopyToDocument(0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), nTabCount-1, InsertDeleteFlags::FORMULA, false, *pUndoDoc);
+
+ // ranges of DB and other
+ ScRangeName* pDocRange = rDoc.GetRangeName();
+ if (!pDocRange->empty())
+ pUndoRange.reset(new ScRangeName( *pDocRange ));
+ ScDBCollection* pDocDB = rDoc.GetDBCollection();
+ if (!pDocDB->empty())
+ pUndoDB.reset(new ScDBCollection( *pDocDB ));
+ }
+
+ if (bSort && bSubTotal)
+ {
+ // sort without SubTotals
+
+ aSubTotalParam.bRemoveOnly = true; // will be reset again further down
+ DoSubTotals( nTab, aSubTotalParam, false, bApi );
+ }
+
+ if (bSort)
+ {
+ pDBData->GetSortParam( aSortParam ); // range may have changed
+ (void)Sort( nTab, aSortParam, false, false, bApi );
+ }
+ if (bQuery)
+ {
+ pDBData->GetQueryParam( aQueryParam ); // range may have changed
+ ScRange aAdvSource;
+ if (pDBData->GetAdvancedQuerySource(aAdvSource))
+ Query( nTab, aQueryParam, &aAdvSource, false, bApi );
+ else
+ Query( nTab, aQueryParam, nullptr, false, bApi );
+
+ // at not-inplace the table may have been converted
+// if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
+// SetTabNo( nTab );
+ }
+ if (bSubTotal)
+ {
+ pDBData->GetSubTotalParam( aSubTotalParam ); // range may have changed
+ aSubTotalParam.bRemoveOnly = false;
+ DoSubTotals( nTab, aSubTotalParam, false, bApi );
+ }
+
+ if (bRecord)
+ {
+ SCTAB nDummyTab;
+ SCCOL nDummyCol;
+ SCROW nDummyRow;
+ SCROW nNewEndRow;
+ pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
+
+ const ScRange* pOld = nullptr;
+ const ScRange* pNew = nullptr;
+ if (bQuerySize)
+ {
+ ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
+ aQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
+ if (pDest)
+ {
+ pDest->GetArea( aNewQuery );
+ pOld = &aOldQuery;
+ pNew = &aNewQuery;
+ }
+ }
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRepeatDB>( &rDocShell, nTab,
+ nStartCol, nStartRow, nEndCol, nEndRow,
+ nNewEndRow,
+ //nCurX, nCurY,
+ nStartCol, nStartRow,
+ std::move(pUndoDoc), std::move(pUndoTab),
+ std::move(pUndoRange), std::move(pUndoDB),
+ pOld, pNew ) );
+ }
+
+ rDocShell.PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab),
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top | PaintPartFlags::Size);
+ bDone = true;
+ }
+ else if (!bApi) // "Don't execute any operations"
+ rDocShell.ErrorMessage(STR_MSSG_REPEATDB_0);
+ }
+
+ return bDone;
+}
+
+bool ScDBDocFunc::Sort( SCTAB nTab, const ScSortParam& rSortParam,
+ bool bRecord, bool bPaint, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1,
+ rSortParam.nCol2, rSortParam.nRow2 );
+ if (!pDBData)
+ {
+ OSL_FAIL( "Sort: no DBData" );
+ return false;
+ }
+
+ bool bCopy = !rSortParam.bInplace;
+ if ( bCopy && rSortParam.nDestCol == rSortParam.nCol1 &&
+ rSortParam.nDestRow == rSortParam.nRow1 && rSortParam.nDestTab == nTab )
+ bCopy = false;
+
+ ScSortParam aLocalParam( rSortParam );
+ if ( bCopy )
+ {
+ // Copy the data range to the destination then move the sort range to it.
+ ScRange aSrcRange(rSortParam.nCol1, rSortParam.nRow1, nTab, rSortParam.nCol2, rSortParam.nRow2, nTab);
+ ScAddress aDestPos(rSortParam.nDestCol,rSortParam.nDestRow,rSortParam.nDestTab);
+
+ ScDocFunc& rDocFunc = rDocShell.GetDocFunc();
+ bool bRet = rDocFunc.MoveBlock(aSrcRange, aDestPos, false, bRecord, bPaint, bApi);
+
+ if (!bRet)
+ return false;
+
+ aLocalParam.MoveToDest();
+ nTab = aLocalParam.nDestTab;
+ }
+
+ // tdf#119804: If there is a header row/column, it won't be affected by
+ // sorting; so we can exclude it from the test.
+ SCROW nStartingRowToEdit = aLocalParam.nRow1;
+ SCCOL nStartingColToEdit = aLocalParam.nCol1;
+ if ( aLocalParam.bHasHeader )
+ {
+ if ( aLocalParam.bByRow )
+ nStartingRowToEdit++;
+ else
+ nStartingColToEdit++;
+ }
+ ScEditableTester aTester( rDoc, nTab, nStartingColToEdit, nStartingRowToEdit,
+ aLocalParam.nCol2, aLocalParam.nRow2, true /*bNoMatrixAtAll*/ );
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ const ScInputOptions aInputOption = SC_MOD()->GetInputOptions();
+ const bool bUpdateRefs = aInputOption.GetSortRefUpdate();
+
+ // Adjust aLocalParam cols/rows to used data area. Keep sticky top row or
+ // column (depending on direction) in any case, not just if it has headers,
+ // so empty leading cells will be sorted to the end.
+ // aLocalParam.nCol/Row will encompass data content only, extras in
+ // aLocalParam.aDataAreaExtras.
+ bool bShrunk = false;
+ aLocalParam.aDataAreaExtras.resetArea();
+ rDoc.ShrinkToUsedDataArea(bShrunk, nTab, aLocalParam.nCol1, aLocalParam.nRow1,
+ aLocalParam.nCol2, aLocalParam.nRow2, false, aLocalParam.bByRow,
+ !aLocalParam.bByRow,
+ (aLocalParam.aDataAreaExtras.anyExtrasWanted() ?
+ &aLocalParam.aDataAreaExtras : nullptr));
+
+ SCROW nStartRow = aLocalParam.nRow1;
+ if (aLocalParam.bByRow && aLocalParam.bHasHeader && nStartRow < aLocalParam.nRow2)
+ ++nStartRow;
+
+ SCCOL nOverallCol1 = aLocalParam.nCol1;
+ SCROW nOverallRow1 = aLocalParam.nRow1;
+ SCCOL nOverallCol2 = aLocalParam.nCol2;
+ SCROW nOverallRow2 = aLocalParam.nRow2;
+ if (aLocalParam.aDataAreaExtras.anyExtrasWanted())
+ {
+ // Trailing empty excess columns/rows are excluded from being sorted,
+ // they stick at the end. Clip them.
+ const ScDataAreaExtras::Clip eClip = (aLocalParam.bByRow ?
+ ScDataAreaExtras::Clip::Row : ScDataAreaExtras::Clip::Col);
+ aLocalParam.aDataAreaExtras.GetOverallRange( nOverallCol1, nOverallRow1, nOverallCol2, nOverallRow2, eClip);
+ // Make it permanent.
+ aLocalParam.aDataAreaExtras.SetOverallRange( nOverallCol1, nOverallRow1, nOverallCol2, nOverallRow2);
+
+ if (bUpdateRefs)
+ {
+ // With update references the entire range needs to be handled as
+ // one entity for references pointing within to be moved along,
+ // even when there's no data content. For huge ranges we may be
+ // DOOMed then.
+ aLocalParam.nCol1 = nOverallCol1;
+ aLocalParam.nRow1 = nOverallRow1;
+ aLocalParam.nCol2 = nOverallCol2;
+ aLocalParam.nRow2 = nOverallRow2;
+ }
+ }
+
+ if (aLocalParam.aDataAreaExtras.mbCellFormats
+ && rDoc.HasAttrib( nOverallCol1, nStartRow, nTab, nOverallCol2, nOverallRow2, nTab,
+ HasAttrFlags::Merged | HasAttrFlags::Overlapped))
+ {
+ // Merge attributes would be mixed up during sorting.
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_SORT_ERR_MERGED);
+ return false;
+ }
+
+ // execute
+
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+
+ // Calculate the script types for all cells in the sort range beforehand.
+ // This will speed up the row height adjustment that takes place after the
+ // sort.
+ rDoc.UpdateScriptTypes(
+ ScAddress(aLocalParam.nCol1,nStartRow,nTab),
+ aLocalParam.nCol2-aLocalParam.nCol1+1,
+ aLocalParam.nRow2-nStartRow+1);
+
+ // No point adjusting row heights after the sort when all rows have the same height.
+ bool bUniformRowHeight = rDoc.HasUniformRowHeight(nTab, nStartRow, nOverallRow2);
+
+ bool bRepeatQuery = false; // repeat existing filter?
+ ScQueryParam aQueryParam;
+ pDBData->GetQueryParam( aQueryParam );
+ if ( aQueryParam.GetEntry(0).bDoQuery )
+ bRepeatQuery = true;
+
+ sc::ReorderParam aUndoParam;
+
+ // don't call ScDocument::Sort with an empty SortParam (may be empty here if bCopy is set)
+ if (aLocalParam.GetSortKeyCount() && aLocalParam.maKeyState[0].bDoSort)
+ {
+ ScProgress aProgress(&rDocShell, ScResId(STR_PROGRESS_SORTING), 0, true);
+ if (!bRepeatQuery)
+ bRepeatQuery = rDoc.HasHiddenRows(aLocalParam.nRow1, aLocalParam.nRow2, nTab);
+ rDoc.Sort(nTab, aLocalParam, bRepeatQuery, bUpdateRefs, &aProgress, &aUndoParam);
+ }
+
+ if (bRecord)
+ {
+ // Set up an undo object.
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<sc::UndoSort>(&rDocShell, aUndoParam));
+ }
+
+ pDBData->SetSortParam(rSortParam);
+ // Remember additional settings on anonymous database ranges.
+ if (pDBData == rDoc.GetAnonymousDBData( nTab) || rDoc.GetDBCollection()->getAnonDBs().has( pDBData))
+ pDBData->UpdateFromSortParam( rSortParam);
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ SfxViewShell* pSomeViewForThisDoc = rDocShell.GetBestViewShell(false);
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pTabViewShell && pTabViewShell->GetDocId() == pSomeViewForThisDoc->GetDocId())
+ {
+ if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKHeightHelper(nTab))
+ pPosHelper->invalidateByIndex(nStartRow);
+ }
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pSomeViewForThisDoc, false /* bColumns */, true /* bRows */, true /* bSizes*/,
+ true /* bHidden */, true /* bFiltered */, true /* bGroups */, nTab);
+ }
+
+ if (nStartRow <= aLocalParam.nRow2)
+ {
+ ScRange aDirtyRange(
+ aLocalParam.nCol1, nStartRow, nTab,
+ aLocalParam.nCol2, aLocalParam.nRow2, nTab);
+ rDoc.SetDirty( aDirtyRange, true );
+ }
+
+ if (bPaint)
+ {
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+ SCCOL nStartX = nOverallCol1;
+ SCROW nStartY = nOverallRow1;
+ SCCOL nEndX = nOverallCol2;
+ SCROW nEndY = nOverallRow2;
+ if ( bRepeatQuery )
+ {
+ nPaint |= PaintPartFlags::Left;
+ nStartX = 0;
+ nEndX = rDoc.MaxCol();
+ }
+ rDocShell.PostPaint(ScRange(nStartX, nStartY, nTab, nEndX, nEndY, nTab), nPaint);
+ }
+
+ if (!bUniformRowHeight && nStartRow <= nOverallRow2)
+ rDocShell.AdjustRowHeight(nStartRow, nOverallRow2, nTab);
+
+ aModificator.SetDocumentModified();
+
+ return true;
+}
+
+bool ScDBDocFunc::Query( SCTAB nTab, const ScQueryParam& rQueryParam,
+ const ScRange* pAdvSource, bool bRecord, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
+ if (pViewSh && ScTabViewShell::isAnyEditViewInRange(pViewSh, /*bColumns*/ false, rQueryParam.nRow1, rQueryParam.nRow2))
+ {
+ return false;
+ }
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rQueryParam.nCol1, rQueryParam.nRow1,
+ rQueryParam.nCol2, rQueryParam.nRow2 );
+ if (!pDBData)
+ {
+ OSL_FAIL( "Query: no DBData" );
+ return false;
+ }
+
+ // Change from Inplace to non-Inplace, only then cancel Inplace:
+ // (only if "Persistent" is selected in the dialog)
+
+ if ( !rQueryParam.bInplace && pDBData->HasQueryParam() && rQueryParam.bDestPers )
+ {
+ ScQueryParam aOldQuery;
+ pDBData->GetQueryParam(aOldQuery);
+ if (aOldQuery.bInplace)
+ {
+ // cancel old filtering
+
+ SCSIZE nEC = aOldQuery.GetEntryCount();
+ for (SCSIZE i=0; i<nEC; i++)
+ aOldQuery.GetEntry(i).bDoQuery = false;
+ aOldQuery.bDuplicate = true;
+ Query( nTab, aOldQuery, nullptr, bRecord, bApi );
+ }
+ }
+
+ ScQueryParam aLocalParam( rQueryParam ); // for Paint / destination range
+ bool bCopy = !rQueryParam.bInplace; // copied in Table::Query
+ ScDBData* pDestData = nullptr; // range to be copied to
+ bool bDoSize = false; // adjust destination size (insert/delete)
+ SCCOL nFormulaCols = 0; // only at bDoSize
+ bool bKeepFmt = false;
+ ScRange aOldDest;
+ ScRange aDestTotal;
+ if ( bCopy && rQueryParam.nDestCol == rQueryParam.nCol1 &&
+ rQueryParam.nDestRow == rQueryParam.nRow1 && rQueryParam.nDestTab == nTab )
+ bCopy = false;
+ SCTAB nDestTab = nTab;
+ if ( bCopy )
+ {
+ aLocalParam.MoveToDest();
+ nDestTab = rQueryParam.nDestTab;
+ if ( !rDoc.ValidColRow( aLocalParam.nCol2, aLocalParam.nRow2 ) )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PASTE_FULL);
+ return false;
+ }
+
+ ScEditableTester aTester( rDoc, nDestTab, aLocalParam.nCol1,aLocalParam.nRow1,
+ aLocalParam.nCol2,aLocalParam.nRow2);
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ pDestData = rDoc.GetDBAtCursor( rQueryParam.nDestCol, rQueryParam.nDestRow,
+ rQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
+ if (pDestData)
+ {
+ pDestData->GetArea( aOldDest );
+ aDestTotal=ScRange( rQueryParam.nDestCol,
+ rQueryParam.nDestRow,
+ nDestTab,
+ rQueryParam.nDestCol + rQueryParam.nCol2 - rQueryParam.nCol1,
+ rQueryParam.nDestRow + rQueryParam.nRow2 - rQueryParam.nRow1,
+ nDestTab );
+
+ bDoSize = pDestData->IsDoSize();
+ // test if formulas need to be filled in (nFormulaCols):
+ if ( bDoSize && aOldDest.aEnd.Col() == aDestTotal.aEnd.Col() )
+ {
+ SCCOL nTestCol = aOldDest.aEnd.Col() + 1; // next to the range
+ SCROW nTestRow = rQueryParam.nDestRow +
+ ( aLocalParam.bHasHeader ? 1 : 0 );
+ while ( nTestCol <= rDoc.MaxCol() &&
+ rDoc.GetCellType(ScAddress( nTestCol, nTestRow, nTab )) == CELLTYPE_FORMULA )
+ {
+ ++nTestCol;
+ ++nFormulaCols;
+ }
+ }
+
+ bKeepFmt = pDestData->IsKeepFmt();
+ if ( bDoSize && !rDoc.CanFitBlock( aOldDest, aDestTotal ) )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2); // cannot insert rows
+ return false;
+ }
+ }
+ }
+
+ // execute
+
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+
+ bool bKeepSub = false; // repeat existing partial results?
+ if (rQueryParam.GetEntry(0).bDoQuery) // not at cancellation
+ {
+ ScSubTotalParam aSubTotalParam;
+ pDBData->GetSubTotalParam( aSubTotalParam ); // partial results exist?
+
+ if ( aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly )
+ bKeepSub = true;
+ }
+
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScDBCollection> pUndoDB;
+ const ScRange* pOld = nullptr;
+
+ if ( bRecord )
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ if (bCopy)
+ {
+ pUndoDoc->InitUndo( rDoc, nDestTab, nDestTab, false, true );
+ rDoc.CopyToDocument(aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
+ aLocalParam.nCol2, aLocalParam.nRow2, nDestTab,
+ InsertDeleteFlags::ALL, false, *pUndoDoc);
+ // secure attributes in case they were copied along
+
+ if (pDestData)
+ {
+ rDoc.CopyToDocument(aOldDest, InsertDeleteFlags::ALL, false, *pUndoDoc);
+ pOld = &aOldDest;
+ }
+ }
+ else
+ {
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
+ rDoc.CopyToDocument(0, rQueryParam.nRow1, nTab, rDoc.MaxCol(), rQueryParam.nRow2, nTab,
+ InsertDeleteFlags::NONE, false, *pUndoDoc);
+ }
+
+ ScDBCollection* pDocDB = rDoc.GetDBCollection();
+ if (!pDocDB->empty())
+ pUndoDB.reset(new ScDBCollection( *pDocDB ));
+
+ rDoc.BeginDrawUndo();
+ }
+
+ std::unique_ptr<ScDocument> pAttribDoc;
+ ScRange aAttribRange;
+ if (pDestData) // delete destination range
+ {
+ if ( bKeepFmt )
+ {
+ // smaller of the end columns, header+1 row
+ aAttribRange = aOldDest;
+ if ( aAttribRange.aEnd.Col() > aDestTotal.aEnd.Col() )
+ aAttribRange.aEnd.SetCol( aDestTotal.aEnd.Col() );
+ aAttribRange.aEnd.SetRow( aAttribRange.aStart.Row() +
+ ( aLocalParam.bHasHeader ? 1 : 0 ) );
+
+ // also for filled-in formulas
+ aAttribRange.aEnd.SetCol( aAttribRange.aEnd.Col() + nFormulaCols );
+
+ pAttribDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pAttribDoc->InitUndo( rDoc, nDestTab, nDestTab, false, true );
+ rDoc.CopyToDocument(aAttribRange, InsertDeleteFlags::ATTRIB, false, *pAttribDoc);
+ }
+
+ if ( bDoSize )
+ rDoc.FitBlock( aOldDest, aDestTotal );
+ else
+ rDoc.DeleteAreaTab(aOldDest, InsertDeleteFlags::ALL); // simply delete
+ }
+
+ // execute filtering on the document
+ SCSIZE nCount = rDoc.Query( nTab, rQueryParam, bKeepSub );
+ pDBData->CalcSaveFilteredCount( nCount );
+ if (bCopy)
+ {
+ aLocalParam.nRow2 = aLocalParam.nRow1 + nCount;
+ if (!aLocalParam.bHasHeader && nCount > 0)
+ --aLocalParam.nRow2;
+
+ if ( bDoSize )
+ {
+ // adjust to the real result range
+ // (this here is always a reduction)
+
+ ScRange aNewDest( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
+ aLocalParam.nCol2, aLocalParam.nRow2, nDestTab );
+ rDoc.FitBlock( aDestTotal, aNewDest, false ); // sal_False - don't delete
+
+ if ( nFormulaCols > 0 )
+ {
+ // fill in formulas
+ //! Undo (Query and Repeat) !!!
+
+ ScRange aNewForm( aLocalParam.nCol2+1, aLocalParam.nRow1, nDestTab,
+ aLocalParam.nCol2+nFormulaCols, aLocalParam.nRow2, nDestTab );
+ ScRange aOldForm = aNewForm;
+ aOldForm.aEnd.SetRow( aOldDest.aEnd.Row() );
+ rDoc.FitBlock( aOldForm, aNewForm, false );
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SelectOneTable(nDestTab);
+ SCROW nFStartY = aLocalParam.nRow1 + ( aLocalParam.bHasHeader ? 1 : 0 );
+
+ sal_uLong nProgCount = nFormulaCols;
+ nProgCount *= aLocalParam.nRow2 - nFStartY;
+ ScProgress aProgress( rDoc.GetDocumentShell(),
+ ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true );
+
+ rDoc.Fill( aLocalParam.nCol2+1, nFStartY,
+ aLocalParam.nCol2+nFormulaCols, nFStartY, &aProgress, aMark,
+ aLocalParam.nRow2 - nFStartY,
+ FILL_TO_BOTTOM, FILL_SIMPLE );
+ }
+ }
+
+ if ( pAttribDoc ) // copy back the memorized attributes
+ {
+ // Header
+ if (aLocalParam.bHasHeader)
+ {
+ ScRange aHdrRange = aAttribRange;
+ aHdrRange.aEnd.SetRow( aHdrRange.aStart.Row() );
+ pAttribDoc->CopyToDocument(aHdrRange, InsertDeleteFlags::ATTRIB, false, rDoc);
+ }
+
+ // Data
+ SCCOL nAttrEndCol = aAttribRange.aEnd.Col();
+ SCROW nAttrRow = aAttribRange.aStart.Row() + ( aLocalParam.bHasHeader ? 1 : 0 );
+ for (SCCOL nCol = aAttribRange.aStart.Col(); nCol<=nAttrEndCol; nCol++)
+ {
+ const ScPatternAttr* pSrcPattern = pAttribDoc->GetPattern(
+ nCol, nAttrRow, nDestTab );
+ OSL_ENSURE(pSrcPattern,"Pattern is 0");
+ if (pSrcPattern)
+ {
+ rDoc.ApplyPatternAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
+ nDestTab, *pSrcPattern );
+ const ScStyleSheet* pStyle = pSrcPattern->GetStyleSheet();
+ if (pStyle)
+ rDoc.ApplyStyleAreaTab( nCol, nAttrRow, nCol, aLocalParam.nRow2,
+ nDestTab, *pStyle );
+ }
+ }
+ }
+ }
+
+ // saving: Inplace always, otherwise depending on setting
+ // old Inplace-Filter may have already been removed
+
+ bool bSave = rQueryParam.bInplace || rQueryParam.bDestPers;
+ if (bSave) // memorize
+ {
+ pDBData->SetQueryParam( rQueryParam );
+ pDBData->SetHeader( rQueryParam.bHasHeader ); //! ???
+ pDBData->SetAdvancedQuerySource( pAdvSource ); // after SetQueryParam
+ }
+
+ if (bCopy) // memorize new DB range
+ {
+ // Selection is done afterwards from outside (dbfunc).
+ // Currently through the DB area at the destination position,
+ // so a range must be created there in any case.
+
+ ScDBData* pNewData;
+ if (pDestData)
+ pNewData = pDestData; // range exists -> adjust (always!)
+ else // create range
+ pNewData = rDocShell.GetDBData(
+ ScRange( aLocalParam.nCol1, aLocalParam.nRow1, nDestTab,
+ aLocalParam.nCol2, aLocalParam.nRow2, nDestTab ),
+ SC_DB_MAKE, ScGetDBSelection::ForceMark );
+
+ if (pNewData)
+ {
+ pNewData->SetArea( nDestTab, aLocalParam.nCol1, aLocalParam.nRow1,
+ aLocalParam.nCol2, aLocalParam.nRow2 );
+
+ // query parameter is no longer set at the destination, only leads to confusion
+ // and mistakes with the query parameter at the source range (#37187#)
+ }
+ else
+ {
+ OSL_FAIL("Target are not available");
+ }
+ }
+
+ if (!bCopy)
+ {
+ rDoc.InvalidatePageBreaks(nTab);
+ rDoc.UpdatePageBreaks( nTab );
+ }
+
+ // #i23299# Subtotal functions depend on cell's filtered states.
+ ScRange aDirtyRange(0 , aLocalParam.nRow1, nDestTab, rDoc.MaxCol(), aLocalParam.nRow2, nDestTab);
+ rDoc.SetSubTotalCellsDirty(aDirtyRange);
+
+ if ( bRecord )
+ {
+ // create undo action after executing, because of drawing layer undo
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoQuery>( &rDocShell, nTab, rQueryParam, std::move(pUndoDoc), std::move(pUndoDB),
+ pOld, bDoSize, pAdvSource ) );
+ }
+
+ if ( pViewSh )
+ {
+ // could there be horizontal autofilter ?
+ // maybe it would be better to set bColumns to !rQueryParam.bByRow ?
+ // anyway at the beginning the value of bByRow is 'false'
+ // then after the first sort action it becomes 'true'
+ pViewSh->OnLOKShowHideColRow(/*bColumns*/ false, rQueryParam.nRow1 - 1);
+ }
+
+ if (bCopy)
+ {
+ SCCOL nEndX = aLocalParam.nCol2;
+ SCROW nEndY = aLocalParam.nRow2;
+ if (pDestData)
+ {
+ if ( aOldDest.aEnd.Col() > nEndX )
+ nEndX = aOldDest.aEnd.Col();
+ if ( aOldDest.aEnd.Row() > nEndY )
+ nEndY = aOldDest.aEnd.Row();
+ }
+ if (bDoSize)
+ nEndY = rDoc.MaxRow();
+
+ // remove AutoFilter button flags
+ rDocShell.DBAreaDeleted(nDestTab, aLocalParam.nCol1, aLocalParam.nRow1, aLocalParam.nCol2);
+
+ rDocShell.PostPaint(
+ ScRange(aLocalParam.nCol1, aLocalParam.nRow1, nDestTab, nEndX, nEndY, nDestTab),
+ PaintPartFlags::Grid);
+ }
+ else
+ rDocShell.PostPaint(
+ ScRange(0, rQueryParam.nRow1, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab),
+ PaintPartFlags::Grid | PaintPartFlags::Left);
+ aModificator.SetDocumentModified();
+
+ return true;
+}
+
+void ScDBDocFunc::DoSubTotals( SCTAB nTab, const ScSubTotalParam& rParam,
+ bool bRecord, bool bApi )
+{
+ //! use also for ScDBFunc::DoSubTotals !
+ // then stays outside:
+ // - mark new range (from DBData)
+ // - SelectionChanged (?)
+
+ bool bDo = !rParam.bRemoveOnly; // sal_False = only delete
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
+ rParam.nCol2, rParam.nRow2 );
+ if (!pDBData)
+ {
+ OSL_FAIL( "SubTotals: no DBData" );
+ return;
+ }
+
+ ScEditableTester aTester( rDoc, nTab, 0,rParam.nRow1+1, rDoc.MaxCol(),rDoc.MaxRow() );
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ if (rDoc.HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
+ rParam.nCol2, rParam.nRow2, nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0); // don't insert into merged
+ return;
+ }
+
+ bool bOk = true;
+ if (rParam.bReplace)
+ {
+ if (rDoc.TestRemoveSubTotals( nTab, rParam ))
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Question,
+ VclButtonsType::YesNo, ScResId(STR_MSSG_DOSUBTOTALS_1))); // "Delete Data?"
+ xBox->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0)); // "StarCalc"
+ bOk = xBox->run() == RET_YES;
+ }
+ }
+
+ if (!bOk)
+ return;
+
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScSubTotalParam aNewParam( rParam ); // end of range is being changed
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScOutlineTable> pUndoTab;
+ std::unique_ptr<ScRangeName> pUndoRange;
+ std::unique_ptr<ScDBCollection> pUndoDB;
+
+ if (bRecord) // secure old data
+ {
+ bool bOldFilter = bDo && rParam.bDoSort;
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+ if (pTable)
+ {
+ pUndoTab.reset(new ScOutlineTable( *pTable ));
+
+ // column/row state
+ SCCOLROW nOutStartCol, nOutEndCol;
+ SCCOLROW nOutStartRow, nOutEndRow;
+ pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
+ pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
+
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ rDoc.CopyToDocument(static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+ rDoc.CopyToDocument(0, nOutStartRow, nTab, rDoc.MaxCol(), nOutEndRow, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+ }
+ else
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, false, bOldFilter );
+
+ // secure data range - incl. filtering result
+ rDoc.CopyToDocument(0, rParam.nRow1+1,nTab, rDoc.MaxCol(),rParam.nRow2,nTab,
+ InsertDeleteFlags::ALL, false, *pUndoDoc);
+
+ // all formulas because of references
+ rDoc.CopyToDocument(0, 0, 0, rDoc.MaxCol(),rDoc.MaxRow(),nTabCount-1,
+ InsertDeleteFlags::FORMULA, false, *pUndoDoc);
+
+ // ranges of DB and other
+ ScRangeName* pDocRange = rDoc.GetRangeName();
+ if (!pDocRange->empty())
+ pUndoRange.reset(new ScRangeName( *pDocRange ));
+ ScDBCollection* pDocDB = rDoc.GetDBCollection();
+ if (!pDocDB->empty())
+ pUndoDB.reset(new ScDBCollection( *pDocDB ));
+ }
+
+// rDoc.SetOutlineTable( nTab, NULL );
+ ScOutlineTable* pOut = rDoc.GetOutlineTable( nTab );
+ if (pOut)
+ pOut->GetRowArray().RemoveAll(); // only delete row outlines
+
+ if (rParam.bReplace)
+ rDoc.RemoveSubTotals( nTab, aNewParam );
+ bool bSuccess = true;
+ if (bDo)
+ {
+ // sort
+ if ( rParam.bDoSort )
+ {
+ pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
+
+ // set partial result field to before the sorting
+ // (Duplicates are omitted, so can be called again)
+
+ ScSortParam aOldSort;
+ pDBData->GetSortParam( aOldSort );
+ ScSortParam aSortParam( aNewParam, aOldSort );
+ Sort( nTab, aSortParam, false, false, bApi );
+ }
+
+ bSuccess = rDoc.DoSubTotals( nTab, aNewParam );
+ rDoc.SetDrawPageSize(nTab);
+ }
+ ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
+ aNewParam.nCol2, aNewParam.nRow2, nTab );
+ rDoc.SetDirty( aDirtyRange, true );
+
+ if (bRecord)
+ {
+// ScDBData* pUndoDBData = pDBData ? new ScDBData( *pDBData ) : NULL;
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoSubTotals>( &rDocShell, nTab,
+ rParam, aNewParam.nRow2,
+ std::move(pUndoDoc), std::move(pUndoTab), // pUndoDBData,
+ std::move(pUndoRange), std::move(pUndoDB) ) );
+ }
+
+ if (!bSuccess)
+ {
+ // "Cannot insert rows"
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
+ }
+
+ // memorize
+ pDBData->SetSubTotalParam( aNewParam );
+ pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
+ rDoc.CompileDBFormula();
+
+ rDocShell.PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab),
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top | PaintPartFlags::Size);
+ aModificator.SetDocumentModified();
+}
+
+namespace {
+
+bool lcl_EmptyExcept( ScDocument& rDoc, const ScRange& rRange, const ScRange& rExcept )
+{
+ ScCellIterator aIter( rDoc, rRange );
+ for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
+ {
+ if (!aIter.isEmpty()) // real content?
+ {
+ if (!rExcept.Contains(aIter.GetPos()))
+ return false; // cell found
+ }
+ }
+
+ return true; // nothing found - empty
+}
+
+bool isEditable(ScDocShell& rDocShell, const ScRangeList& rRanges, bool bApi)
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (!rDocShell.IsEditable() || rDoc.GetChangeTrack())
+ {
+ // not recorded -> disallow
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PROTECTIONERR);
+
+ return false;
+ }
+
+ for (size_t i = 0, n = rRanges.size(); i < n; ++i)
+ {
+ const ScRange & r = rRanges[i];
+ ScEditableTester aTester(rDoc, r);
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void createUndoDoc(ScDocumentUniquePtr& pUndoDoc, ScDocument& rDoc, const ScRange& rRange)
+{
+ SCTAB nTab = rRange.aStart.Tab();
+ pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ pUndoDoc->InitUndo(rDoc, nTab, nTab);
+ rDoc.CopyToDocument(rRange, InsertDeleteFlags::ALL, false, *pUndoDoc);
+}
+
+bool checkNewOutputRange(ScDPObject& rDPObj, ScDocShell& rDocShell, ScRange& rNewOut, bool bApi)
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ bool bOverflow = false;
+ rNewOut = rDPObj.GetNewOutputRange(bOverflow);
+
+ // Test for overlap with source data range.
+ // TODO: Check with other pivot tables as well.
+ const ScSheetSourceDesc* pSheetDesc = rDPObj.GetSheetDesc();
+ if (pSheetDesc && pSheetDesc->GetSourceRange().Intersects(rNewOut))
+ {
+ // New output range intersteps with the source data. Move it up to
+ // where the old range is and see if that works.
+ ScRange aOldRange = rDPObj.GetOutRange();
+ SCROW nDiff = aOldRange.aStart.Row() - rNewOut.aStart.Row();
+ rNewOut.aStart.SetRow(aOldRange.aStart.Row());
+ rNewOut.aEnd.IncRow(nDiff);
+ if (!rDoc.ValidRow(rNewOut.aStart.Row()) || !rDoc.ValidRow(rNewOut.aEnd.Row()))
+ bOverflow = true;
+ }
+
+ if (bOverflow)
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PIVOT_ERROR);
+
+ return false;
+ }
+
+ ScEditableTester aTester(rDoc, rNewOut);
+ if (!aTester.IsEditable())
+ {
+ // destination area isn't editable
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+
+ return false;
+ }
+
+ return true;
+}
+
+}
+
+bool ScDBDocFunc::DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewObj,
+ bool bRecord, bool bApi, bool bAllowMove )
+{
+ if (!pOldObj)
+ {
+ if (!pNewObj)
+ return false;
+
+ return CreatePivotTable(*pNewObj, bRecord, bApi);
+ }
+
+ if (!pNewObj)
+ return RemovePivotTable(*pOldObj, bRecord, bApi);
+
+ if (pOldObj == pNewObj)
+ return UpdatePivotTable(*pOldObj, bRecord, bApi);
+
+ OSL_ASSERT(pOldObj && pNewObj && pOldObj != pNewObj);
+
+ ScDocShellModificator aModificator( rDocShell );
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+
+ ScRangeList aRanges;
+ aRanges.push_back(pOldObj->GetOutRange());
+ aRanges.push_back(pNewObj->GetOutRange().aStart); // at least one cell in the output position must be editable.
+ if (!isEditable(rDocShell, aRanges, bApi))
+ return false;
+
+ ScDocumentUniquePtr pOldUndoDoc;
+ ScDocumentUniquePtr pNewUndoDoc;
+
+ ScDPObject aUndoDPObj(*pOldObj); // for undo or revert on failure
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ if (bRecord)
+ createUndoDoc(pOldUndoDoc, rDoc, pOldObj->GetOutRange());
+
+ pNewObj->WriteSourceDataTo(*pOldObj); // copy source data
+
+ ScDPSaveData* pData = pNewObj->GetSaveData();
+ OSL_ENSURE( pData, "no SaveData from living DPObject" );
+ if (pData)
+ pOldObj->SetSaveData(*pData); // copy SaveData
+
+ pOldObj->SetAllowMove(bAllowMove);
+ pOldObj->ReloadGroupTableData();
+ pOldObj->SyncAllDimensionMembers();
+ pOldObj->InvalidateData(); // before getting the new output area
+
+ // make sure the table has a name (not set by dialog)
+ if (pOldObj->GetName().isEmpty())
+ pOldObj->SetName( rDoc.GetDPCollection()->CreateNewName() );
+
+ ScRange aNewOut;
+ if (!checkNewOutputRange(*pOldObj, rDocShell, aNewOut, bApi))
+ {
+ *pOldObj = aUndoDPObj;
+ return false;
+ }
+
+ // test if new output area is empty except for old area
+ if (!bApi)
+ {
+ // OutRange of pOldObj (pDestObj) is still old area
+ if (!lcl_EmptyExcept(rDoc, aNewOut, pOldObj->GetOutRange()))
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_PIVOT_NOTEMPTY)));
+ xQueryBox->set_default_response(RET_YES);
+ if (xQueryBox->run() == RET_NO)
+ {
+ //! like above (not editable)
+ *pOldObj = aUndoDPObj;
+ return false;
+ }
+ }
+ }
+
+ if (bRecord)
+ createUndoDoc(pNewUndoDoc, rDoc, aNewOut);
+
+ pOldObj->Output(aNewOut.aStart);
+ rDocShell.PostPaintGridAll(); //! only necessary parts
+
+ if (bRecord)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDataPilot>(
+ &rDocShell, std::move(pOldUndoDoc), std::move(pNewUndoDoc), &aUndoDPObj, pOldObj, bAllowMove));
+ }
+
+ // notify API objects
+ rDoc.BroadcastUno( ScDataPilotModifiedHint(pOldObj->GetName()) );
+ aModificator.SetDocumentModified();
+
+ return true;
+}
+
+bool ScDBDocFunc::RemovePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi)
+{
+ ScDocShellModificator aModificator(rDocShell);
+ weld::WaitObject aWait(ScDocShell::GetActiveDialogParent());
+
+ if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi))
+ return false;
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (!bApi)
+ {
+ // If we come from GUI - ask to delete the associated pivot charts too...
+ std::vector<SdrOle2Obj*> aListOfObjects =
+ sc::tools::getAllPivotChartsConnectedTo(rDPObj.GetName(), &rDocShell);
+
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+
+ if (pModel && !aListOfObjects.empty())
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_PIVOT_REMOVE_PIVOTCHART)));
+ xQueryBox->set_default_response(RET_YES);
+ if (xQueryBox->run() == RET_NO)
+ {
+ return false;
+ }
+ else
+ {
+ for (SdrOle2Obj* pChartObject : aListOfObjects)
+ {
+ rDoc.GetChartListenerCollection()->removeByName(pChartObject->GetName());
+ pModel->AddUndo(std::make_unique<SdrUndoDelObj>(*pChartObject));
+ pChartObject->getSdrPageFromSdrObject()->RemoveObject(pChartObject->GetOrdNum());
+ }
+ }
+ }
+ }
+
+ ScDocumentUniquePtr pOldUndoDoc;
+ std::unique_ptr<ScDPObject> pUndoDPObj;
+
+ if (bRecord)
+ pUndoDPObj.reset(new ScDPObject(rDPObj)); // copy old settings for undo
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ // delete table
+
+ ScRange aRange = rDPObj.GetOutRange();
+ SCTAB nTab = aRange.aStart.Tab();
+
+ if (bRecord)
+ createUndoDoc(pOldUndoDoc, rDoc, aRange);
+
+ rDoc.DeleteAreaTab( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(),
+ nTab, InsertDeleteFlags::ALL );
+ rDoc.RemoveFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(),
+ nTab, ScMF::Auto );
+
+ rDoc.GetDPCollection()->FreeTable(&rDPObj); // object is deleted here
+
+ rDocShell.PostPaintGridAll(); //! only necessary parts
+ rDocShell.PostPaint(aRange, PaintPartFlags::Grid);
+
+ if (bRecord)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDataPilot>(
+ &rDocShell, std::move(pOldUndoDoc), nullptr, pUndoDPObj.get(), nullptr, false));
+
+ // pUndoDPObj is copied
+ }
+
+ aModificator.SetDocumentModified();
+ return true;
+}
+
+bool ScDBDocFunc::CreatePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi)
+{
+ ScDocShellModificator aModificator(rDocShell);
+ weld::WaitObject aWait(ScDocShell::GetActiveDialogParent());
+
+ // At least one cell in the output range should be editable. Check in advance.
+ if (!isEditable(rDocShell, ScRange(rDPObj.GetOutRange().aStart), bApi))
+ return false;
+
+ ScDocumentUniquePtr pNewUndoDoc;
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ // output range must be set at pNewObj
+ std::unique_ptr<ScDPObject> pDestObj(new ScDPObject(rDPObj));
+
+ ScDPObject& rDestObj = *pDestObj;
+
+ // #i94570# When changing the output position in the dialog, a new table is created
+ // with the settings from the old table, including the name.
+ // So we have to check for duplicate names here (before inserting).
+ if (rDoc.GetDPCollection()->GetByName(rDestObj.GetName()))
+ rDestObj.SetName(OUString()); // ignore the invalid name, create a new name below
+
+ // Synchronize groups between linked tables
+ {
+ const ScDPDimensionSaveData* pGroups = nullptr;
+ bool bRefFound = rDoc.GetDPCollection()->GetReferenceGroups(rDestObj, &pGroups);
+ if (bRefFound)
+ {
+ ScDPSaveData* pSaveData = rDestObj.GetSaveData();
+ if (pSaveData)
+ pSaveData->SetDimensionData(pGroups);
+ }
+ }
+
+ rDoc.GetDPCollection()->InsertNewTable(std::move(pDestObj));
+
+ rDestObj.ReloadGroupTableData();
+ rDestObj.SyncAllDimensionMembers();
+ rDestObj.InvalidateData(); // before getting the new output area
+
+ // make sure the table has a name (not set by dialog)
+ if (rDestObj.GetName().isEmpty())
+ rDestObj.SetName(rDoc.GetDPCollection()->CreateNewName());
+
+ bool bOverflow = false;
+ ScRange aNewOut = rDestObj.GetNewOutputRange(bOverflow);
+
+ if (bOverflow)
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PIVOT_ERROR);
+
+ return false;
+ }
+
+ {
+ ScEditableTester aTester(rDoc, aNewOut);
+ if (!aTester.IsEditable())
+ {
+ // destination area isn't editable
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+
+ return false;
+ }
+ }
+
+ // test if new output area is empty except for old area
+ if (!bApi)
+ {
+ bool bEmpty = rDoc.IsBlockEmpty(
+ aNewOut.aStart.Col(), aNewOut.aStart.Row(),
+ aNewOut.aEnd.Col(), aNewOut.aEnd.Row(), aNewOut.aStart.Tab() );
+
+ if (!bEmpty)
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_PIVOT_NOTEMPTY)));
+ xQueryBox->set_default_response(RET_YES);
+ if (xQueryBox->run() == RET_NO)
+ {
+ //! like above (not editable)
+ return false;
+ }
+ }
+ }
+
+ if (bRecord)
+ createUndoDoc(pNewUndoDoc, rDoc, aNewOut);
+
+ rDestObj.Output(aNewOut.aStart);
+ rDocShell.PostPaintGridAll(); //! only necessary parts
+
+ if (bRecord)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDataPilot>(&rDocShell, nullptr, std::move(pNewUndoDoc), nullptr, &rDestObj, false));
+ }
+
+ // notify API objects
+ rDoc.BroadcastUno(ScDataPilotModifiedHint(rDestObj.GetName()));
+ aModificator.SetDocumentModified();
+
+ return true;
+}
+
+bool ScDBDocFunc::UpdatePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi)
+{
+ ScDocShellModificator aModificator( rDocShell );
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+
+ if (!isEditable(rDocShell, rDPObj.GetOutRange(), bApi))
+ return false;
+
+ ScDocumentUniquePtr pOldUndoDoc;
+ ScDocumentUniquePtr pNewUndoDoc;
+
+ ScDPObject aUndoDPObj(rDPObj); // For undo or revert on failure.
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ if (bRecord)
+ createUndoDoc(pOldUndoDoc, rDoc, rDPObj.GetOutRange());
+
+ rDPObj.SetAllowMove(false);
+ rDPObj.ReloadGroupTableData();
+ if (!rDPObj.SyncAllDimensionMembers())
+ return false;
+
+ rDPObj.InvalidateData(); // before getting the new output area
+
+ // make sure the table has a name (not set by dialog)
+ if (rDPObj.GetName().isEmpty())
+ rDPObj.SetName( rDoc.GetDPCollection()->CreateNewName() );
+
+ ScRange aNewOut;
+ if (!checkNewOutputRange(rDPObj, rDocShell, aNewOut, bApi))
+ {
+ rDPObj = aUndoDPObj;
+ return false;
+ }
+
+ // test if new output area is empty except for old area
+ if (!bApi)
+ {
+ if (!lcl_EmptyExcept(rDoc, aNewOut, rDPObj.GetOutRange()))
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_PIVOT_NOTEMPTY)));
+ xQueryBox->set_default_response(RET_YES);
+ if (xQueryBox->run() == RET_NO)
+ {
+ rDPObj = aUndoDPObj;
+ return false;
+ }
+ }
+ }
+
+ if (bRecord)
+ createUndoDoc(pNewUndoDoc, rDoc, aNewOut);
+
+ rDPObj.Output(aNewOut.aStart);
+ rDocShell.PostPaintGridAll(); //! only necessary parts
+
+ if (bRecord)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDataPilot>(
+ &rDocShell, std::move(pOldUndoDoc), std::move(pNewUndoDoc), &aUndoDPObj, &rDPObj, false));
+ }
+
+ // notify API objects
+ rDoc.BroadcastUno( ScDataPilotModifiedHint(rDPObj.GetName()) );
+ aModificator.SetDocumentModified();
+ return true;
+}
+
+void ScDBDocFunc::RefreshPivotTables(const ScDPObject* pDPObj, bool bApi)
+{
+ ScDPCollection* pDPs = rDocShell.GetDocument().GetDPCollection();
+ if (!pDPs)
+ return;
+
+ o3tl::sorted_vector<ScDPObject*> aRefs;
+ TranslateId pErrId = pDPs->ReloadCache(pDPObj, aRefs);
+ if (pErrId)
+ return;
+
+ for (ScDPObject* pObj : aRefs)
+ {
+ // This action is intentionally not undoable since it modifies cache.
+ UpdatePivotTable(*pObj, false, bApi);
+ }
+}
+
+void ScDBDocFunc::RefreshPivotTableGroups(ScDPObject* pDPObj)
+{
+ if (!pDPObj)
+ return;
+
+ ScDPCollection* pDPs = rDocShell.GetDocument().GetDPCollection();
+ if (!pDPs)
+ return;
+
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ if (!pSaveData)
+ return;
+
+ if (!pDPs->HasTable(pDPObj))
+ {
+ // This table is under construction so no need for a whole update (UpdatePivotTable()).
+ pDPObj->ReloadGroupTableData();
+ return;
+ }
+
+ // Update all linked tables, if this table is part of the cache (ScDPCollection)
+ o3tl::sorted_vector<ScDPObject*> aRefs;
+ if (!pDPs->ReloadGroupsInCache(pDPObj, aRefs))
+ return;
+
+ // We allow pDimData being NULL.
+ const ScDPDimensionSaveData* pDimData = pSaveData->GetExistingDimensionData();
+ for (ScDPObject* pObj : aRefs)
+ {
+ if (pObj != pDPObj)
+ {
+ pSaveData = pObj->GetSaveData();
+ if (pSaveData)
+ pSaveData->SetDimensionData(pDimData);
+ }
+
+ // This action is intentionally not undoable since it modifies cache.
+ UpdatePivotTable(*pObj, false, false);
+ }
+}
+
+// database import
+
+void ScDBDocFunc::UpdateImport( const OUString& rTarget, const svx::ODataAccessDescriptor& rDescriptor )
+{
+ // rTarget is the name of a database range
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScDBCollection& rDBColl = *rDoc.GetDBCollection();
+ const ScDBData* pData = rDBColl.getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rTarget));
+ if (!pData)
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_TARGETNOTFOUND)));
+ xInfoBox->run();
+ return;
+ }
+
+ SCTAB nTab;
+ SCCOL nDummyCol;
+ SCROW nDummyRow;
+ pData->GetArea( nTab, nDummyCol,nDummyRow,nDummyCol,nDummyRow );
+
+ ScImportParam aImportParam;
+ pData->GetImportParam( aImportParam );
+
+ OUString sDBName;
+ OUString sDBTable;
+ sal_Int32 nCommandType = 0;
+ sDBName = rDescriptor.getDataSource();
+ rDescriptor[svx::DataAccessDescriptorProperty::Command] >>= sDBTable;
+ rDescriptor[svx::DataAccessDescriptorProperty::CommandType] >>= nCommandType;
+
+ aImportParam.aDBName = sDBName;
+ aImportParam.bSql = ( nCommandType == sdb::CommandType::COMMAND );
+ aImportParam.aStatement = sDBTable;
+ aImportParam.bNative = false;
+ aImportParam.nType = static_cast<sal_uInt8>( ( nCommandType == sdb::CommandType::QUERY ) ? ScDbQuery : ScDbTable );
+ aImportParam.bImport = true;
+
+ bool bContinue = DoImport( nTab, aImportParam, &rDescriptor );
+
+ // repeat DB operations
+
+ ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
+ if (!pViewSh)
+ return;
+
+ ScRange aRange;
+ pData->GetArea(aRange);
+ pViewSh->MarkRange(aRange); // select
+
+ if ( bContinue ) // error at import -> abort
+ {
+ // internal operations, if some are saved
+
+ if ( pData->HasQueryParam() || pData->HasSortParam() || pData->HasSubTotalParam() )
+ pViewSh->RepeatDB();
+
+ // pivot tables which have the range as source data
+
+ rDocShell.RefreshPivotTables(aRange);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/dbdocimp.cxx b/sc/source/ui/docshell/dbdocimp.cxx
new file mode 100644
index 000000000..b7a0f95c9
--- /dev/null
+++ b/sc/source/ui/docshell/dbdocimp.cxx
@@ -0,0 +1,628 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/errinf.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/types.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/XCompletedExecution.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+
+#include <dbdocfun.hxx>
+#include <docsh.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <scerrors.hxx>
+#include <dbdata.hxx>
+#include <markdata.hxx>
+#include <undodat.hxx>
+#include <progress.hxx>
+#include <patattr.hxx>
+#include <docpool.hxx>
+#include <attrib.hxx>
+#include <dbdocutl.hxx>
+#include <editable.hxx>
+#include <hints.hxx>
+#include <miscuno.hxx>
+#include <chgtrack.hxx>
+#include <refupdatecontext.hxx>
+
+using namespace com::sun::star;
+
+constexpr OUStringLiteral SC_SERVICE_ROWSET = u"com.sun.star.sdb.RowSet";
+
+//! move to a header file?
+constexpr OUStringLiteral SC_DBPROP_DATASOURCENAME = u"DataSourceName";
+constexpr OUStringLiteral SC_DBPROP_COMMAND = u"Command";
+constexpr OUStringLiteral SC_DBPROP_COMMANDTYPE = u"CommandType";
+
+void ScDBDocFunc::ShowInBeamer( const ScImportParam& rParam, const SfxViewFrame* pFrame )
+{
+ // called after opening the database beamer
+
+ if ( !pFrame || !rParam.bImport )
+ return;
+
+ uno::Reference<frame::XFrame> xFrame = pFrame->GetFrame().GetFrameInterface();
+
+ uno::Reference<frame::XFrame> xBeamerFrame = xFrame->findFrame(
+ "_beamer",
+ frame::FrameSearchFlag::CHILDREN);
+ if (!xBeamerFrame.is())
+ return;
+
+ uno::Reference<frame::XController> xController = xBeamerFrame->getController();
+ uno::Reference<view::XSelectionSupplier> xControllerSelection(xController, uno::UNO_QUERY);
+ if (xControllerSelection.is())
+ {
+ sal_Int32 nType = rParam.bSql ? sdb::CommandType::COMMAND :
+ ( (rParam.nType == ScDbQuery) ? sdb::CommandType::QUERY :
+ sdb::CommandType::TABLE );
+
+ svx::ODataAccessDescriptor aSelection;
+ aSelection.setDataSource(rParam.aDBName);
+ aSelection[svx::DataAccessDescriptorProperty::Command] <<= rParam.aStatement;
+ aSelection[svx::DataAccessDescriptorProperty::CommandType] <<= nType;
+
+ xControllerSelection->select(uno::Any(aSelection.createPropertyValueSequence()));
+ }
+ else
+ {
+ OSL_FAIL("no selection supplier in the beamer!");
+ }
+}
+
+void ScDBDocFunc::DoImportUno( const ScAddress& rPos,
+ const uno::Sequence<beans::PropertyValue>& aArgs )
+{
+ svx::ODataAccessDescriptor aDesc( aArgs ); // includes selection and result set
+
+ // create database range
+ ScDBData* pDBData = rDocShell.GetDBData( ScRange(rPos), SC_DB_IMPORT, ScGetDBSelection::Keep );
+ DBG_ASSERT(pDBData, "can't create DB data");
+ OUString sTarget = pDBData->GetName();
+
+ UpdateImport( sTarget, aDesc );
+}
+
+bool ScDBDocFunc::DoImport( SCTAB nTab, const ScImportParam& rParam,
+ const svx::ODataAccessDescriptor* pDescriptor )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScChangeTrack *pChangeTrack = nullptr;
+ ScRange aChangedRange;
+
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
+ rParam.nCol2, rParam.nRow2 );
+ if (!pDBData)
+ {
+ OSL_FAIL( "DoImport: no DBData" );
+ return false;
+ }
+
+ std::unique_ptr<weld::WaitObject> xWaitWin(new weld::WaitObject(ScDocShell::GetActiveDialogParent()));
+ ScDocShellModificator aModificator( rDocShell );
+
+ bool bSuccess = false;
+ bool bTruncated = false; // for warning
+ TranslateId pErrStringId;
+ OUString aErrorMessage;
+
+ SCCOL nCol = rParam.nCol1;
+ SCROW nRow = rParam.nRow1;
+ SCCOL nEndCol = nCol; // end of resulting database area
+ SCROW nEndRow = nRow;
+
+ bool bDoSelection = false;
+ bool bRealSelection = false; // sal_True if not everything is selected
+ bool bBookmarkSelection = false;
+ sal_Int32 nListPos = 0;
+ sal_Int32 nRowsRead = 0;
+ sal_Int32 nListCount = 0;
+
+ uno::Sequence<uno::Any> aSelection;
+ if ( pDescriptor && pDescriptor->has(svx::DataAccessDescriptorProperty::Selection) )
+ {
+ (*pDescriptor)[svx::DataAccessDescriptorProperty::Selection] >>= aSelection;
+ nListCount = aSelection.getLength();
+ if ( nListCount > 0 )
+ {
+ bDoSelection = true;
+ if ( pDescriptor->has(svx::DataAccessDescriptorProperty::BookmarkSelection) )
+ bBookmarkSelection = ScUnoHelpFunctions::GetBoolFromAny( (*pDescriptor)[svx::DataAccessDescriptorProperty::BookmarkSelection] );
+ if ( bBookmarkSelection )
+ {
+ // From bookmarks, there's no way to detect if all records are selected.
+ // Rely on base to pass no selection in that case.
+ bRealSelection = true;
+ }
+ }
+ }
+
+ uno::Reference<sdbc::XResultSet> xResultSet;
+ if ( pDescriptor && pDescriptor->has(svx::DataAccessDescriptorProperty::Cursor) )
+ xResultSet.set((*pDescriptor)[svx::DataAccessDescriptorProperty::Cursor], uno::UNO_QUERY);
+
+ // ImportDoc - also used for Redo
+ ScDocumentUniquePtr pImportDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pImportDoc->InitUndo( rDoc, nTab, nTab );
+
+ // get data from database into import document
+
+ try
+ {
+ // progress bar
+ // only text (title is still needed, for the cancel button)
+ ScProgress aProgress( &rDocShell, ScResId(STR_UNDO_IMPORTDATA), 0, true );
+
+ uno::Reference<sdbc::XRowSet> xRowSet( xResultSet, uno::UNO_QUERY );
+ bool bDispose = false;
+ if ( !xRowSet.is() )
+ {
+ bDispose = true;
+ xRowSet.set(comphelper::getProcessServiceFactory()->createInstance(
+ SC_SERVICE_ROWSET ),
+ uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY );
+ OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
+ if ( xRowProp.is() )
+ {
+
+ // set source parameters
+
+ sal_Int32 nType = rParam.bSql ? sdb::CommandType::COMMAND :
+ ( (rParam.nType == ScDbQuery) ? sdb::CommandType::QUERY :
+ sdb::CommandType::TABLE );
+
+ xRowProp->setPropertyValue( SC_DBPROP_DATASOURCENAME, uno::Any(rParam.aDBName) );
+
+ xRowProp->setPropertyValue( SC_DBPROP_COMMAND, uno::Any(rParam.aStatement) );
+
+ xRowProp->setPropertyValue( SC_DBPROP_COMMANDTYPE, uno::Any(nType) );
+
+ uno::Reference<sdb::XCompletedExecution> xExecute( xRowSet, uno::UNO_QUERY );
+ if ( xExecute.is() )
+ {
+ uno::Reference<task::XInteractionHandler> xHandler(
+ task::InteractionHandler::createWithParent(comphelper::getProcessComponentContext(), nullptr),
+ uno::UNO_QUERY_THROW);
+ xExecute->executeWithCompletion( xHandler );
+ }
+ else
+ xRowSet->execute();
+ }
+ }
+ if ( xRowSet.is() )
+ {
+
+ // get column descriptions
+
+ sal_Int32 nColCount = 0;
+ uno::Reference<sdbc::XResultSetMetaData> xMeta;
+ uno::Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp( xRowSet, uno::UNO_QUERY );
+ if ( xMetaSupp.is() )
+ xMeta = xMetaSupp->getMetaData();
+ if ( xMeta.is() )
+ nColCount = xMeta->getColumnCount(); // this is the number of real columns
+
+ if ( rParam.nCol1 + nColCount - 1 > rDoc.MaxCol() )
+ {
+ nColCount = 0;
+ //! error message
+ }
+
+ uno::Reference<sdbcx::XRowLocate> xLocate;
+ if ( bBookmarkSelection )
+ {
+ xLocate.set( xRowSet, uno::UNO_QUERY );
+ if ( !xLocate.is() )
+ {
+ SAL_WARN( "sc.ui","can't get XRowLocate");
+ bDoSelection = bRealSelection = bBookmarkSelection = false;
+ }
+ }
+
+ uno::Reference<sdbc::XRow> xRow( xRowSet, uno::UNO_QUERY );
+ if ( nColCount > 0 && xRow.is() )
+ {
+ nEndCol = static_cast<SCCOL>( rParam.nCol1 + nColCount - 1 );
+
+ uno::Sequence<sal_Int32> aColTypes( nColCount ); // column types
+ uno::Sequence<sal_Bool> aColCurr( nColCount ); // currency flag is not in types
+ sal_Int32* pTypeArr = aColTypes.getArray();
+ sal_Bool* pCurrArr = aColCurr.getArray();
+ for (tools::Long i=0; i<nColCount; i++)
+ {
+ pTypeArr[i] = xMeta->getColumnType( i+1 );
+ pCurrArr[i] = xMeta->isCurrency( i+1 );
+ }
+
+ // read column names
+ nCol = rParam.nCol1;
+ for (tools::Long i=0; i<nColCount; i++)
+ {
+ pImportDoc->SetString( nCol, nRow, nTab,
+ xMeta->getColumnLabel( i+1 ) );
+ ++nCol;
+ }
+ ++nRow;
+
+ bool bEnd = false;
+ if ( !bDoSelection )
+ xRowSet->beforeFirst();
+ sal_uInt16 nInserted = 0;
+ while ( !bEnd )
+ {
+ // skip rows that are not selected
+ if ( !bDoSelection )
+ {
+ bEnd = !xRowSet->next();
+ if ( !bEnd )
+ ++nRowsRead;
+ }
+ else
+ {
+ if (nListPos < nListCount)
+ {
+ if ( bBookmarkSelection )
+ {
+ bEnd = !xLocate->moveToBookmark(aSelection[nListPos]);
+ }
+ else // use record numbers
+ {
+ sal_Int32 nNextRow = 0;
+ aSelection[nListPos] >>= nNextRow;
+ if ( nRowsRead+1 < nNextRow )
+ bRealSelection = true;
+ nRowsRead = nNextRow;
+ bEnd = !xRowSet->absolute(nRowsRead);
+ }
+ ++nListPos;
+ }
+ else
+ {
+ if ( !bBookmarkSelection && xRowSet->next() )
+ bRealSelection = true; // more data available but not used
+ bEnd = true;
+ }
+ }
+
+ if ( !bEnd )
+ {
+ if ( rDoc.ValidRow(nRow) )
+ {
+ nCol = rParam.nCol1;
+ for (tools::Long i=0; i<nColCount; i++)
+ {
+ ScDatabaseDocUtil::PutData( *pImportDoc, nCol, nRow, nTab,
+ xRow, i+1, pTypeArr[i], pCurrArr[i] );
+ ++nCol;
+ }
+ nEndRow = nRow;
+ ++nRow;
+
+ // progress bar
+
+ ++nInserted;
+ if (!(nInserted & 15))
+ {
+ aProgress.SetState( 0 );
+ }
+ }
+ else // past the end of the spreadsheet
+ {
+ bEnd = true; // don't continue
+ bTruncated = true; // warning flag
+ }
+ }
+ }
+
+ bSuccess = true;
+ }
+
+ if ( bDispose )
+ ::comphelper::disposeComponent( xRowSet );
+ }
+ }
+ catch ( const sdbc::SQLException& rError )
+ {
+ aErrorMessage = rError.Message;
+ }
+ catch ( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "Unexpected exception in database");
+ }
+
+ // test for cell protection
+
+ bool bKeepFormat = pDBData->IsKeepFmt();
+ bool bMoveCells = pDBData->IsDoSize();
+ SCCOL nFormulaCols = 0; // columns to be filled with formulas
+ if (bMoveCells && nEndCol == rParam.nCol2)
+ {
+ // if column count changes, formulas would become invalid anyway
+ // -> only set nFormulaCols for unchanged column count
+
+ SCCOL nTestCol = rParam.nCol2 + 1; // right of the data
+ SCROW nTestRow = rParam.nRow1 + 1; // below the title row
+ while ( nTestCol <= rDoc.MaxCol() &&
+ rDoc.GetCellType(ScAddress( nTestCol, nTestRow, nTab )) == CELLTYPE_FORMULA )
+ {
+ ++nTestCol;
+ ++nFormulaCols;
+ }
+ }
+
+ if (bSuccess)
+ {
+ // old and new range editable?
+ ScEditableTester aTester;
+ aTester.TestBlock( rDoc, nTab, rParam.nCol1,rParam.nRow1,rParam.nCol2,rParam.nRow2 );
+ aTester.TestBlock( rDoc, nTab, rParam.nCol1,rParam.nRow1,nEndCol,nEndRow );
+ if ( !aTester.IsEditable() )
+ {
+ pErrStringId = aTester.GetMessageId();
+ bSuccess = false;
+ }
+ else if ( (pChangeTrack = rDoc.GetChangeTrack()) != nullptr )
+ aChangedRange = ScRange(rParam.nCol1, rParam.nRow1, nTab,
+ nEndCol+nFormulaCols, nEndRow, nTab );
+ }
+
+ if ( bSuccess && bMoveCells )
+ {
+ ScRange aOld( rParam.nCol1, rParam.nRow1, nTab,
+ rParam.nCol2+nFormulaCols, rParam.nRow2, nTab );
+ ScRange aNew( rParam.nCol1, rParam.nRow1, nTab,
+ nEndCol+nFormulaCols, nEndRow, nTab );
+ if (!rDoc.CanFitBlock( aOld, aNew ))
+ {
+ pErrStringId = STR_MSSG_DOSUBTOTALS_2; // can't insert cells
+ bSuccess = false;
+ }
+ }
+
+ // copy data from import doc into real document
+
+ if ( bSuccess )
+ {
+ if (bKeepFormat)
+ {
+ // keep formatting of title and first data row from the document
+ // CopyToDocument also copies styles, Apply... needs separate calls
+
+ SCCOL nMinEndCol = std::min( rParam.nCol2, nEndCol ); // not too much
+ nMinEndCol = sal::static_int_cast<SCCOL>( nMinEndCol + nFormulaCols ); // only if column count unchanged
+ pImportDoc->DeleteAreaTab( 0,0, rDoc.MaxCol(),rDoc.MaxRow(), nTab, InsertDeleteFlags::ATTRIB );
+ rDoc.CopyToDocument(rParam.nCol1, rParam.nRow1, nTab,
+ nMinEndCol, rParam.nRow1, nTab,
+ InsertDeleteFlags::ATTRIB, false, *pImportDoc);
+
+ SCROW nDataStartRow = rParam.nRow1+1;
+ for (SCCOL nCopyCol=rParam.nCol1; nCopyCol<=nMinEndCol; nCopyCol++)
+ {
+ const ScPatternAttr* pSrcPattern = rDoc.GetPattern(
+ nCopyCol, nDataStartRow, nTab );
+ pImportDoc->ApplyPatternAreaTab( nCopyCol, nDataStartRow, nCopyCol, nEndRow,
+ nTab, *pSrcPattern );
+ const ScStyleSheet* pStyle = pSrcPattern->GetStyleSheet();
+ if (pStyle)
+ pImportDoc->ApplyStyleAreaTab( nCopyCol, nDataStartRow, nCopyCol, nEndRow,
+ nTab, *pStyle );
+ }
+ }
+
+ // don't set cell protection attribute if table is protected
+ if (rDoc.IsTabProtected(nTab))
+ {
+ ScPatternAttr aPattern(pImportDoc->GetPool());
+ aPattern.GetItemSet().Put( ScProtectionAttr( false,false,false,false ) );
+ pImportDoc->ApplyPatternAreaTab( 0,0,rDoc.MaxCol(),rDoc.MaxRow(), nTab, aPattern );
+ }
+
+ // copy old data for undo
+
+ SCCOL nUndoEndCol = std::max( nEndCol, rParam.nCol2 ); // rParam = old end
+ SCROW nUndoEndRow = std::max( nEndRow, rParam.nRow2 );
+
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScDBData> pUndoDBData;
+ if ( bRecord )
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+
+ pUndoDBData.reset(new ScDBData( *pDBData ));
+ }
+
+ ScMarkData aNewMark(rDoc.GetSheetLimits());
+ aNewMark.SelectOneTable( nTab );
+
+ if (bRecord)
+ {
+ // do not touch notes (ScUndoImportData does not support drawing undo)
+ InsertDeleteFlags nCopyFlags = InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE;
+
+ // nFormulaCols is set only if column count is unchanged
+ rDoc.CopyToDocument(rParam.nCol1, rParam.nRow1, nTab,
+ nEndCol+nFormulaCols, nEndRow, nTab,
+ nCopyFlags, false, *pUndoDoc);
+ if ( rParam.nCol2 > nEndCol )
+ rDoc.CopyToDocument(nEndCol+1, rParam.nRow1, nTab,
+ nUndoEndCol, nUndoEndRow, nTab,
+ nCopyFlags, false, *pUndoDoc);
+ if ( rParam.nRow2 > nEndRow )
+ rDoc.CopyToDocument(rParam.nCol1, nEndRow+1, nTab,
+ nUndoEndCol+nFormulaCols, nUndoEndRow, nTab,
+ nCopyFlags, false, *pUndoDoc);
+ }
+
+ // move new data
+
+ if (bMoveCells)
+ {
+ // clear only the range without the formulas,
+ // so the formula title and first row are preserved
+
+ ScRange aDelRange( rParam.nCol1, rParam.nRow1, nTab,
+ rParam.nCol2, rParam.nRow2, nTab );
+ rDoc.DeleteAreaTab( aDelRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE ); // without the formulas
+
+ ScRange aOld( rParam.nCol1, rParam.nRow1, nTab,
+ rParam.nCol2+nFormulaCols, rParam.nRow2, nTab );
+ ScRange aNew( rParam.nCol1, rParam.nRow1, nTab,
+ nEndCol+nFormulaCols, nEndRow, nTab );
+ rDoc.FitBlock( aOld, aNew, false ); // Do not delete formulas
+ }
+ else if ( nEndCol < rParam.nCol2 ) // DeleteArea calls PutInOrder
+ rDoc.DeleteArea( nEndCol+1, rParam.nRow1, rParam.nCol2, rParam.nRow2,
+ aNewMark, InsertDeleteFlags::CONTENTS & ~InsertDeleteFlags::NOTE );
+
+ // CopyToDocument doesn't remove contents
+ rDoc.DeleteAreaTab( rParam.nCol1, rParam.nRow1, nEndCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS & ~InsertDeleteFlags::NOTE );
+
+ // remove each column from ImportDoc after copying to reduce memory usage
+ bool bOldAutoCalc = rDoc.GetAutoCalc();
+ rDoc.SetAutoCalc( false ); // outside of the loop
+ for (SCCOL nCopyCol = rParam.nCol1; nCopyCol <= nEndCol; nCopyCol++)
+ {
+ pImportDoc->CopyToDocument(nCopyCol, rParam.nRow1, nTab, nCopyCol, nEndRow, nTab,
+ InsertDeleteFlags::ALL, false, rDoc);
+ pImportDoc->DeleteAreaTab( nCopyCol, rParam.nRow1, nCopyCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS );
+ }
+ rDoc.SetAutoCalc( bOldAutoCalc );
+
+ if (nFormulaCols > 0) // copy formulas
+ {
+ if (bKeepFormat) // formats for formulas
+ pImportDoc->CopyToDocument(nEndCol+1, rParam.nRow1, nTab,
+ nEndCol+nFormulaCols, nEndRow, nTab,
+ InsertDeleteFlags::ATTRIB, false, rDoc);
+ // fill formulas
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SelectOneTable(nTab);
+
+ sal_uLong nProgCount = nFormulaCols;
+ nProgCount *= nEndRow-rParam.nRow1-1;
+ ScProgress aProgress( rDoc.GetDocumentShell(),
+ ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true );
+
+ rDoc.Fill( nEndCol+1, rParam.nRow1+1, nEndCol+nFormulaCols, rParam.nRow1+1,
+ &aProgress, aMark, nEndRow-rParam.nRow1-1, FILL_TO_BOTTOM, FILL_SIMPLE );
+ }
+
+ // if new range is smaller, clear old contents
+
+ if (!bMoveCells) // move has happened above
+ {
+ if ( rParam.nCol2 > nEndCol )
+ rDoc.DeleteArea( nEndCol+1, rParam.nRow1, rParam.nCol2, rParam.nRow2,
+ aNewMark, InsertDeleteFlags::CONTENTS );
+ if ( rParam.nRow2 > nEndRow )
+ rDoc.DeleteArea( rParam.nCol1, nEndRow+1, rParam.nCol2, rParam.nRow2,
+ aNewMark, InsertDeleteFlags::CONTENTS );
+ }
+
+ // update database range
+ pDBData->SetImportParam( rParam );
+ pDBData->SetHeader( true );
+ pDBData->SetByRow( true );
+ pDBData->SetArea( nTab, rParam.nCol1,rParam.nRow1, nEndCol,nEndRow );
+ pDBData->SetImportSelection( bRealSelection );
+ rDoc.CompileDBFormula();
+
+ if (bRecord)
+ {
+ ScDocumentUniquePtr pRedoDoc = std::move(pImportDoc);
+
+ if (nFormulaCols > 0) // include filled formulas for redo
+ rDoc.CopyToDocument(rParam.nCol1, rParam.nRow1, nTab,
+ nEndCol+nFormulaCols, nEndRow, nTab,
+ InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, *pRedoDoc);
+
+ std::unique_ptr<ScDBData> pRedoDBData(new ScDBData(*pDBData));
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoImportData>( &rDocShell, nTab,
+ rParam, nUndoEndCol, nUndoEndRow,
+ nFormulaCols,
+ std::move(pUndoDoc), std::move(pRedoDoc),
+ std::move(pUndoDBData), std::move(pRedoDBData) ) );
+ }
+
+ sc::SetFormulaDirtyContext aCxt;
+ rDoc.SetAllFormulasDirty(aCxt);
+ rDocShell.PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab), PaintPartFlags::Grid);
+ aModificator.SetDocumentModified();
+
+ ScDBRangeRefreshedHint aHint( rParam );
+ rDoc.BroadcastUno( aHint );
+
+ xWaitWin.reset();
+
+ if ( bTruncated ) // show warning
+ ErrorHandler::HandleError(SCWARN_IMPORT_RANGE_OVERFLOW);
+ }
+ else
+ {
+ xWaitWin.reset();
+
+ if (aErrorMessage.isEmpty())
+ {
+ if (!pErrStringId)
+ pErrStringId = STR_MSSG_IMPORTDATA_0;
+ aErrorMessage = ScResId(pErrStringId);
+ }
+
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ aErrorMessage));
+ xInfoBox->run();
+ }
+
+ pImportDoc.reset();
+
+ if (bSuccess && pChangeTrack)
+ pChangeTrack->AppendInsert ( aChangedRange );
+
+ return bSuccess;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docfunc.cxx b/sc/source/ui/docshell/docfunc.cxx
new file mode 100644
index 000000000..752843797
--- /dev/null
+++ b/sc/source/ui/docshell/docfunc.cxx
@@ -0,0 +1,5922 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+
+#include <comphelper/lok.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <sfx2/app.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/justifyitem.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/bindings.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/svdocapt.hxx>
+#include <sal/log.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/script/ModuleType.hpp>
+#include <com/sun/star/script/XLibraryContainer.hpp>
+#include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
+
+#include <docfunc.hxx>
+
+#include <sc.hrc>
+#include <strings.hrc>
+
+#include <arealink.hxx>
+#include <attrib.hxx>
+#include <dociter.hxx>
+#include <autoform.hxx>
+#include <formulacell.hxx>
+#include <cellmergeoption.hxx>
+#include <detdata.hxx>
+#include <detfunc.hxx>
+#include <docpool.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <editutil.hxx>
+#include <globstr.hrc>
+#include <olinetab.hxx>
+#include <patattr.hxx>
+#include <rangenam.hxx>
+#include <refundo.hxx>
+#include <scresid.hxx>
+#include <stlpool.hxx>
+#include <stlsheet.hxx>
+#include <tablink.hxx>
+#include <tabvwsh.hxx>
+#include <uiitems.hxx>
+#include <undoblk.hxx>
+#include <undocell.hxx>
+#include <undodraw.hxx>
+#include <undotab.hxx>
+#include <sizedev.hxx>
+#include <scmod.hxx>
+#include <inputhdl.hxx>
+#include <editable.hxx>
+#include <compiler.hxx>
+#include <scui_def.hxx>
+#include <tabprotection.hxx>
+#include <clipparam.hxx>
+#include <externalrefmgr.hxx>
+#include <undorangename.hxx>
+#include <progress.hxx>
+#include <dpobject.hxx>
+#include <stringutil.hxx>
+#include <cellvalue.hxx>
+#include <tokenarray.hxx>
+#include <rowheightcontext.hxx>
+#include <cellvalues.hxx>
+#include <undoconvert.hxx>
+#include <docfuncutil.hxx>
+#include <sheetevents.hxx>
+#include <conditio.hxx>
+#include <columnspanset.hxx>
+#include <validat.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+#include <SparklineData.hxx>
+#include <undo/UndoInsertSparkline.hxx>
+#include <undo/UndoDeleteSparkline.hxx>
+#include <undo/UndoDeleteSparklineGroup.hxx>
+#include <undo/UndoEditSparklineGroup.hxx>
+#include <undo/UndoUngroupSparklines.hxx>
+#include <undo/UndoGroupSparklines.hxx>
+#include <undo/UndoEditSparkline.hxx>
+#include <config_features.h>
+
+#include <memory>
+#include <utility>
+#include <basic/basmgr.hxx>
+#include <set>
+#include <vector>
+#include <sfx2/viewfrm.hxx>
+
+using namespace com::sun::star;
+using ::std::vector;
+
+void ScDocFunc::NotifyDrawUndo( std::unique_ptr<SdrUndoAction> pUndoAction)
+{
+ // #i101118# if drawing layer collects the undo actions, add it there
+ ScDrawLayer* pDrawLayer = rDocShell.GetDocument().GetDrawLayer();
+ if( pDrawLayer && pDrawLayer->IsRecording() )
+ pDrawLayer->AddCalcUndo( std::move(pUndoAction) );
+ else
+ rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoDraw>( std::move(pUndoAction), &rDocShell ) );
+ rDocShell.SetDrawModified();
+
+ // the affected sheet isn't known, so all stream positions are invalidated
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ rDoc.SetStreamValid(nTab, false);
+}
+
+// paint row above the range (because of lines after AdjustRowHeight)
+
+static void lcl_PaintAbove( ScDocShell& rDocShell, const ScRange& rRange )
+{
+ SCROW nRow = rRange.aStart.Row();
+ if ( nRow > 0 )
+ {
+ SCTAB nTab = rRange.aStart.Tab(); //! all of them?
+ --nRow;
+ ScDocument& rDoc = rDocShell.GetDocument();
+ rDocShell.PostPaint( ScRange(0,nRow,nTab,rDoc.MaxCol(),nRow,nTab), PaintPartFlags::Grid );
+ }
+}
+
+bool ScDocFunc::AdjustRowHeight( const ScRange& rRange, bool bPaint, bool bApi )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SfxViewShell* pSomeViewForThisDoc = rDocShell.GetBestViewShell(false);
+ if ( rDoc.IsImportingXML() )
+ {
+ // for XML import, all row heights are updated together after importing
+ return false;
+ }
+ if ( rDoc.IsAdjustHeightLocked() )
+ {
+ return false;
+ }
+
+ SCTAB nTab = rRange.aStart.Tab();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCROW nEndRow = rRange.aEnd.Row();
+
+ ScSizeDeviceProvider aProv( &rDocShell );
+ Fraction aOne(1,1);
+
+ sc::RowHeightContext aCxt(rDoc.MaxRow(), aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, aProv.GetDevice());
+ bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartRow, nEndRow, nTab, bApi);
+ // tdf#76183: recalculate objects' positions
+ if (bChanged)
+ {
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pTabViewShell && pTabViewShell->GetDocId() == pSomeViewForThisDoc->GetDocId())
+ {
+ if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKHeightHelper(nTab))
+ pPosHelper->invalidateByIndex(nStartRow);
+ }
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+ }
+ rDoc.SetDrawPageSize(nTab);
+ }
+
+ if ( bPaint && bChanged )
+ rDocShell.PostPaint(ScRange(0, nStartRow, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab),
+ PaintPartFlags::Grid | PaintPartFlags::Left);
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pSomeViewForThisDoc, ROW_HEADER, nTab);
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pSomeViewForThisDoc, false /* bColumns */, true /* bRows */, true /* bSizes*/,
+ false /* bHidden */, false /* bFiltered */, false /* bGroups */, nTab);
+ }
+
+ return bChanged;
+}
+
+bool ScDocFunc::DetectiveAddPred(const ScAddress& rPos)
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ rDocShell.MakeDrawLayer();
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bUndo (rDoc.IsUndoEnabled());
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+
+ if (bUndo)
+ pModel->BeginCalcUndo(false);
+ bool bDone = ScDetectiveFunc(rDoc, nTab).ShowPred( nCol, nRow );
+ std::unique_ptr<SdrUndoGroup> pUndo;
+ if (bUndo)
+ pUndo = pModel->GetCalcUndo();
+ if (bDone)
+ {
+ ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDPRED );
+ rDoc.AddDetectiveOperation( aOperation );
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), &aOperation ) );
+ }
+ aModificator.SetDocumentModified();
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_DETECTIVE_REFRESH );
+ }
+
+ return bDone;
+}
+
+bool ScDocFunc::DetectiveDelPred(const ScAddress& rPos)
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ bool bUndo(rDoc.IsUndoEnabled());
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ if (!pModel)
+ return false;
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+
+ if (bUndo)
+ pModel->BeginCalcUndo(false);
+ bool bDone = ScDetectiveFunc(rDoc, nTab).DeletePred( nCol, nRow );
+ std::unique_ptr<SdrUndoGroup> pUndo;
+ if (bUndo)
+ pUndo = pModel->GetCalcUndo();
+ if (bDone)
+ {
+ ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELPRED );
+ rDoc.AddDetectiveOperation( aOperation );
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), &aOperation ) );
+ }
+ aModificator.SetDocumentModified();
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_DETECTIVE_REFRESH );
+ }
+
+ return bDone;
+}
+
+bool ScDocFunc::DetectiveAddSucc(const ScAddress& rPos)
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ rDocShell.MakeDrawLayer();
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ bool bUndo(rDoc.IsUndoEnabled());
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+
+ if (bUndo)
+ pModel->BeginCalcUndo(false);
+ bool bDone = ScDetectiveFunc(rDoc, nTab).ShowSucc( nCol, nRow );
+ std::unique_ptr<SdrUndoGroup> pUndo;
+ if (bUndo)
+ pUndo = pModel->GetCalcUndo();
+ if (bDone)
+ {
+ ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDSUCC );
+ rDoc.AddDetectiveOperation( aOperation );
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), &aOperation ) );
+ }
+ aModificator.SetDocumentModified();
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_DETECTIVE_REFRESH );
+ }
+
+ return bDone;
+}
+
+bool ScDocFunc::DetectiveDelSucc(const ScAddress& rPos)
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ bool bUndo (rDoc.IsUndoEnabled());
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ if (!pModel)
+ return false;
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+
+ if (bUndo)
+ pModel->BeginCalcUndo(false);
+ bool bDone = ScDetectiveFunc(rDoc, nTab).DeleteSucc( nCol, nRow );
+ std::unique_ptr<SdrUndoGroup> pUndo;
+ if (bUndo)
+ pUndo = pModel->GetCalcUndo();
+ if (bDone)
+ {
+ ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_DELSUCC );
+ rDoc.AddDetectiveOperation( aOperation );
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), &aOperation ) );
+ }
+ aModificator.SetDocumentModified();
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_DETECTIVE_REFRESH );
+ }
+
+ return bDone;
+}
+
+bool ScDocFunc::DetectiveAddError(const ScAddress& rPos)
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ rDocShell.MakeDrawLayer();
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ bool bUndo (rDoc.IsUndoEnabled());
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ SCCOL nCol = rPos.Col();
+ SCROW nRow = rPos.Row();
+ SCTAB nTab = rPos.Tab();
+
+ if (bUndo)
+ pModel->BeginCalcUndo(false);
+ bool bDone = ScDetectiveFunc(rDoc, nTab).ShowError( nCol, nRow );
+ std::unique_ptr<SdrUndoGroup> pUndo;
+ if (bUndo)
+ pUndo = pModel->GetCalcUndo();
+ if (bDone)
+ {
+ ScDetOpData aOperation( ScAddress(nCol,nRow,nTab), SCDETOP_ADDERROR );
+ rDoc.AddDetectiveOperation( aOperation );
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), &aOperation ) );
+ }
+ aModificator.SetDocumentModified();
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_DETECTIVE_REFRESH );
+ }
+
+ return bDone;
+}
+
+bool ScDocFunc::DetectiveMarkInvalid(SCTAB nTab)
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ rDocShell.MakeDrawLayer();
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ bool bUndo (rDoc.IsUndoEnabled());
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+
+ std::unique_ptr<weld::WaitObject> xWaitWin(new weld::WaitObject(ScDocShell::GetActiveDialogParent()));
+ if (bUndo)
+ pModel->BeginCalcUndo(false);
+ bool bOverflow;
+ bool bDone = ScDetectiveFunc(rDoc, nTab).MarkInvalid( bOverflow );
+ std::unique_ptr<SdrUndoGroup> pUndo;
+ if (bUndo)
+ pUndo = pModel->GetCalcUndo();
+ xWaitWin.reset();
+ if (bDone)
+ {
+ if (pUndo && bUndo)
+ {
+ pUndo->SetComment( ScResId( STR_UNDO_DETINVALID ) );
+ rDocShell.GetUndoManager()->AddUndoAction( std::move(pUndo) );
+ }
+ aModificator.SetDocumentModified();
+ if ( bOverflow )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_DETINVALID_OVERFLOW)));
+ xInfoBox->run();
+ }
+ }
+
+ return bDone;
+}
+
+bool ScDocFunc::DetectiveDelAll(SCTAB nTab)
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ bool bUndo (rDoc.IsUndoEnabled());
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ if (!pModel)
+ return false;
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ if (bUndo)
+ pModel->BeginCalcUndo(false);
+ bool bDone = ScDetectiveFunc(rDoc, nTab).DeleteAll( ScDetectiveDelete::Detective );
+ std::unique_ptr<SdrUndoGroup> pUndo;
+ if (bUndo)
+ pUndo = pModel->GetCalcUndo();
+ if (bDone)
+ {
+ ScDetOpList* pOldList = rDoc.GetDetOpList();
+ std::unique_ptr<ScDetOpList> pUndoList;
+ if (bUndo && pOldList)
+ pUndoList.reset(new ScDetOpList(*pOldList));
+
+ rDoc.ClearDetectiveOperations();
+
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDetective>( &rDocShell, std::move(pUndo), nullptr, std::move(pUndoList) ) );
+ }
+ aModificator.SetDocumentModified();
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_DETECTIVE_REFRESH );
+ }
+
+ return bDone;
+}
+
+bool ScDocFunc::DetectiveRefresh( bool bAutomatic )
+{
+ bool bDone = false;
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ ScDetOpList* pList = rDoc.GetDetOpList();
+ if ( pList && pList->Count() )
+ {
+ rDocShell.MakeDrawLayer();
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ const bool bUndo (rDoc.IsUndoEnabled());
+ if (bUndo)
+ pModel->BeginCalcUndo(false);
+
+ // Delete in all sheets
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ ScDetectiveFunc( rDoc,nTab ).DeleteAll( ScDetectiveDelete::Arrows ); // don't remove circles
+
+ // repeat
+
+ size_t nCount = pList->Count();
+ for (size_t i=0; i < nCount; ++i)
+ {
+ const ScDetOpData& rData = pList->GetObject(i);
+ const ScAddress& aPos = rData.GetPos();
+ ScDetectiveFunc aFunc( rDoc, aPos.Tab() );
+ SCCOL nCol = aPos.Col();
+ SCROW nRow = aPos.Row();
+ switch (rData.GetOperation())
+ {
+ case SCDETOP_ADDSUCC:
+ aFunc.ShowSucc( nCol, nRow );
+ break;
+ case SCDETOP_DELSUCC:
+ aFunc.DeleteSucc( nCol, nRow );
+ break;
+ case SCDETOP_ADDPRED:
+ aFunc.ShowPred( nCol, nRow );
+ break;
+ case SCDETOP_DELPRED:
+ aFunc.DeletePred( nCol, nRow );
+ break;
+ case SCDETOP_ADDERROR:
+ aFunc.ShowError( nCol, nRow );
+ break;
+ default:
+ OSL_FAIL("wrong operation in DetectiveRefresh");
+ }
+ }
+
+ if (bUndo)
+ {
+ std::unique_ptr<SdrUndoGroup> pUndo = pModel->GetCalcUndo();
+ if (pUndo)
+ {
+ pUndo->SetComment( ScResId( STR_UNDO_DETREFRESH ) );
+ // associate with the last action
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDraw>( std::move(pUndo), &rDocShell ),
+ bAutomatic );
+ }
+ }
+ rDocShell.SetDrawModified();
+ bDone = true;
+ }
+ return bDone;
+}
+
+static void lcl_collectAllPredOrSuccRanges(
+ const ScRangeList& rSrcRanges, vector<ScTokenRef>& rRefTokens, ScDocShell& rDocShell,
+ bool bPred)
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ vector<ScTokenRef> aRefTokens;
+ if (rSrcRanges.empty())
+ return;
+ ScRange const & rFrontRange = rSrcRanges.front();
+ ScDetectiveFunc aDetFunc(rDoc, rFrontRange.aStart.Tab());
+ for (size_t i = 0, n = rSrcRanges.size(); i < n; ++i)
+ {
+ ScRange const & r = rSrcRanges[i];
+ if (bPred)
+ {
+ aDetFunc.GetAllPreds(
+ r.aStart.Col(), r.aStart.Row(), r.aEnd.Col(), r.aEnd.Row(), aRefTokens);
+ }
+ else
+ {
+ aDetFunc.GetAllSuccs(
+ r.aStart.Col(), r.aStart.Row(), r.aEnd.Col(), r.aEnd.Row(), aRefTokens);
+ }
+ }
+ rRefTokens.swap(aRefTokens);
+}
+
+void ScDocFunc::DetectiveCollectAllPreds(const ScRangeList& rSrcRanges, vector<ScTokenRef>& rRefTokens)
+{
+ lcl_collectAllPredOrSuccRanges(rSrcRanges, rRefTokens, rDocShell, true);
+}
+
+void ScDocFunc::DetectiveCollectAllSuccs(const ScRangeList& rSrcRanges, vector<ScTokenRef>& rRefTokens)
+{
+ lcl_collectAllPredOrSuccRanges(rSrcRanges, rRefTokens, rDocShell, false);
+}
+
+bool ScDocFunc::DeleteContents(
+ const ScMarkData& rMark, InsertDeleteFlags nFlags, bool bRecord, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ OSL_FAIL("ScDocFunc::DeleteContents without markings");
+ return false;
+ }
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScEditableTester aTester( rDoc, rMark );
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ ScMarkData aMultiMark = rMark;
+ aMultiMark.SetMarking(false); // for MarkToMulti
+
+ ScDocumentUniquePtr pUndoDoc;
+ bool bMulti = aMultiMark.IsMultiMarked();
+ aMultiMark.MarkToMulti();
+ const ScRange& aMarkRange = aMultiMark.GetMultiMarkArea();
+ ScRange aExtendedRange(aMarkRange);
+ if ( rDoc.ExtendMerge( aExtendedRange, true ) )
+ bMulti = false;
+
+ // no objects on protected tabs
+ bool bObjects = (nFlags & InsertDeleteFlags::OBJECTS) && !sc::DocFuncUtil::hasProtectedTab(rDoc, rMark);
+
+ sal_uInt16 nExtFlags = 0; // extra flags are needed only if attributes are deleted
+ if ( nFlags & InsertDeleteFlags::ATTRIB )
+ rDocShell.UpdatePaintExt( nExtFlags, aMarkRange );
+
+ // order of operations:
+ // 1) BeginDrawUndo
+ // 2) Delete objects (DrawUndo will be filled)
+ // 3) Copy content for undo and set up undo actions
+ // 4) Delete content
+
+ bool bDrawUndo = bObjects || (nFlags & InsertDeleteFlags::NOTE);
+ if (bRecord && bDrawUndo)
+ rDoc.BeginDrawUndo();
+
+ if (bObjects)
+ {
+ if (bMulti)
+ rDoc.DeleteObjectsInSelection( aMultiMark );
+ else
+ rDoc.DeleteObjectsInArea( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
+ aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(),
+ aMultiMark );
+ }
+
+ // To keep track of all non-empty cells within the deleted area.
+ std::shared_ptr<ScSimpleUndo::DataSpansType> pDataSpans;
+
+ if ( bRecord )
+ {
+ pUndoDoc = sc::DocFuncUtil::createDeleteContentsUndoDoc(rDoc, aMultiMark, aMarkRange, nFlags, bMulti);
+ pDataSpans = sc::DocFuncUtil::getNonEmptyCellSpans(rDoc, aMultiMark, aMarkRange);
+ }
+
+ rDoc.DeleteSelection( nFlags, aMultiMark );
+
+ // add undo action after drawing undo is complete (objects and note captions)
+ if( bRecord )
+ {
+ sc::DocFuncUtil::addDeleteContentsUndo(
+ rDocShell.GetUndoManager(), &rDocShell, aMultiMark, aExtendedRange,
+ std::move(pUndoDoc), nFlags, pDataSpans, bMulti, bDrawUndo);
+ }
+
+ if (!AdjustRowHeight( aExtendedRange, true, bApi ))
+ rDocShell.PostPaint( aExtendedRange, PaintPartFlags::Grid, nExtFlags );
+ else if (nExtFlags & SC_PF_LINES)
+ lcl_PaintAbove( rDocShell, aExtendedRange ); // for lines above the range
+
+ aModificator.SetDocumentModified();
+
+ return true;
+}
+
+bool ScDocFunc::DeleteCell(
+ const ScAddress& rPos, const ScMarkData& rMark, InsertDeleteFlags nFlags, bool bRecord, bool bApi )
+{
+ ScDocShellModificator aModificator(rDocShell);
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScEditableTester aTester(rDoc, rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark);
+ if (!aTester.IsEditable())
+ {
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ // no objects on protected tabs
+ bool bObjects = (nFlags & InsertDeleteFlags::OBJECTS) && !sc::DocFuncUtil::hasProtectedTab(rDoc, rMark);
+
+ sal_uInt16 nExtFlags = 0; // extra flags are needed only if attributes are deleted
+ if (nFlags & InsertDeleteFlags::ATTRIB)
+ rDocShell.UpdatePaintExt(nExtFlags, rPos);
+
+ // order of operations:
+ // 1) BeginDrawUndo
+ // 2) delete objects (DrawUndo is filled)
+ // 3) copy contents for undo
+ // 4) delete contents
+ // 5) add undo-action
+
+ bool bDrawUndo = bObjects || (nFlags & InsertDeleteFlags::NOTE); // needed for shown notes
+ if (bDrawUndo && bRecord)
+ rDoc.BeginDrawUndo();
+
+ if (bObjects)
+ rDoc.DeleteObjectsInArea(rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark);
+
+ // To keep track of all non-empty cells within the deleted area.
+ std::shared_ptr<ScSimpleUndo::DataSpansType> pDataSpans;
+
+ ScDocumentUniquePtr pUndoDoc;
+ if (bRecord)
+ {
+ pUndoDoc = sc::DocFuncUtil::createDeleteContentsUndoDoc(rDoc, rMark, rPos, nFlags, false);
+ pDataSpans = sc::DocFuncUtil::getNonEmptyCellSpans(rDoc, rMark, rPos);
+ }
+
+ rDoc.DeleteArea(rPos.Col(), rPos.Row(), rPos.Col(), rPos.Row(), rMark, nFlags);
+
+ if (bRecord)
+ {
+ sc::DocFuncUtil::addDeleteContentsUndo(
+ rDocShell.GetUndoManager(), &rDocShell, rMark, rPos, std::move(pUndoDoc),
+ nFlags, pDataSpans, false, bDrawUndo);
+ }
+
+ if (!AdjustRowHeight(rPos, true, bApi))
+ rDocShell.PostPaint(
+ rPos.Col(), rPos.Row(), rPos.Tab(), rPos.Col(), rPos.Row(), rPos.Tab(),
+ PaintPartFlags::Grid, nExtFlags);
+
+ aModificator.SetDocumentModified();
+
+ return true;
+}
+
+bool ScDocFunc::TransliterateText( const ScMarkData& rMark, TransliterationFlags nType,
+ bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScEditableTester aTester( rDoc, rMark );
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ ScMarkData aMultiMark = rMark;
+ aMultiMark.SetMarking(false); // for MarkToMulti
+ aMultiMark.MarkToMulti();
+ const ScRange& aMarkRange = aMultiMark.GetMultiMarkArea();
+
+ if (bRecord)
+ {
+ SCTAB nStartTab = aMarkRange.aStart.Tab();
+ SCTAB nTabCount = rDoc.GetTableCount();
+
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab );
+ for (const auto& rTab : rMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (rTab != nStartTab)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ }
+
+ ScRange aCopyRange = aMarkRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument(aCopyRange, InsertDeleteFlags::CONTENTS, true, *pUndoDoc, &aMultiMark);
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoTransliterate>( &rDocShell, aMultiMark, std::move(pUndoDoc), nType ) );
+ }
+
+ rDoc.TransliterateText( aMultiMark, nType );
+
+ if (!AdjustRowHeight( aMarkRange, true, true ))
+ rDocShell.PostPaint( aMarkRange, PaintPartFlags::Grid );
+
+ aModificator.SetDocumentModified();
+
+ return true;
+}
+
+bool ScDocFunc::SetNormalString( bool& o_rbNumFmtSet, const ScAddress& rPos, const OUString& rText, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ bool bUndo(rDoc.IsUndoEnabled());
+ ScEditableTester aTester( rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() );
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ bool bEditDeleted = (rDoc.GetCellType(rPos) == CELLTYPE_EDIT);
+ ScUndoEnterData::ValuesType aOldValues;
+
+ if (bUndo)
+ {
+ ScUndoEnterData::Value aOldValue;
+
+ aOldValue.mnTab = rPos.Tab();
+ aOldValue.maCell.assign(rDoc, rPos);
+
+ const ScPatternAttr* pPattern = rDoc.GetPattern( rPos.Col(),rPos.Row(),rPos.Tab() );
+ if ( const SfxUInt32Item* pItem = pPattern->GetItemSet().GetItemIfSet(
+ ATTR_VALUE_FORMAT,false) )
+ {
+ aOldValue.mbHasFormat = true;
+ aOldValue.mnFormat = pItem->GetValue();
+ }
+ else
+ aOldValue.mbHasFormat = false;
+
+ aOldValues.push_back(aOldValue);
+ }
+
+ o_rbNumFmtSet = rDoc.SetString( rPos.Col(), rPos.Row(), rPos.Tab(), rText );
+
+ if (bUndo)
+ {
+ // because of ChangeTracking, UndoAction can be created only after SetString was called
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoEnterData>(&rDocShell, rPos, aOldValues, rText, nullptr));
+ }
+
+ if ( bEditDeleted || rDoc.HasAttrib( ScRange(rPos), HasAttrFlags::NeedHeight ) )
+ AdjustRowHeight( ScRange(rPos), true, bApi );
+
+ rDocShell.PostPaintCell( rPos );
+ aModificator.SetDocumentModified();
+
+ // notify input handler here the same way as in PutCell
+ if (bApi)
+ NotifyInputHandler( rPos );
+
+ const SfxUInt32Item* pItem = rDoc.GetAttr(rPos, ATTR_VALIDDATA);
+ const ScValidationData* pData = rDoc.GetValidationEntry(pItem->GetValue());
+ if (pData)
+ {
+ ScRefCellValue aCell(rDoc, rPos);
+ if (pData->IsDataValid(aCell, rPos))
+ ScDetectiveFunc(rDoc, rPos.Tab()).DeleteCirclesAt(rPos.Col(), rPos.Row());
+ }
+
+ return true;
+}
+
+bool ScDocFunc::SetValueCell( const ScAddress& rPos, double fVal, bool bInteraction )
+{
+ ScDocShellModificator aModificator( rDocShell );
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bUndo = rDoc.IsUndoEnabled();
+
+ bool bHeight = rDoc.HasAttrib(rPos, HasAttrFlags::NeedHeight);
+
+ ScCellValue aOldVal;
+ if (bUndo)
+ aOldVal.assign(rDoc, rPos);
+
+ rDoc.SetValue(rPos, fVal);
+
+ if (bUndo)
+ {
+ SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager();
+ ScCellValue aNewVal;
+ aNewVal.assign(rDoc, rPos);
+ pUndoMgr->AddUndoAction(std::make_unique<ScUndoSetCell>(&rDocShell, rPos, aOldVal, aNewVal));
+ }
+
+ if (bHeight)
+ AdjustRowHeight(rPos, true, !bInteraction);
+
+ rDocShell.PostPaintCell( rPos );
+ aModificator.SetDocumentModified();
+
+ // #103934#; notify editline and cell in edit mode
+ if (!bInteraction)
+ NotifyInputHandler( rPos );
+
+ return true;
+}
+
+void ScDocFunc::SetValueCells( const ScAddress& rPos, const std::vector<double>& aVals, bool bInteraction )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ // Check for invalid range.
+ SCROW nLastRow = rPos.Row() + aVals.size() - 1;
+ if (nLastRow > rDoc.MaxRow())
+ // out of bound.
+ return;
+
+ ScRange aRange(rPos);
+ aRange.aEnd.SetRow(nLastRow);
+
+ ScDocShellModificator aModificator(rDocShell);
+
+ if (rDoc.IsUndoEnabled())
+ {
+ std::unique_ptr<sc::UndoSetCells> pUndoObj(new sc::UndoSetCells(&rDocShell, rPos));
+ rDoc.TransferCellValuesTo(rPos, aVals.size(), pUndoObj->GetOldValues());
+ pUndoObj->SetNewValues(aVals);
+ SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager();
+ pUndoMgr->AddUndoAction(std::move(pUndoObj));
+ }
+
+ rDoc.SetValues(rPos, aVals);
+
+ rDocShell.PostPaint(aRange, PaintPartFlags::Grid);
+ aModificator.SetDocumentModified();
+
+ // #103934#; notify editline and cell in edit mode
+ if (!bInteraction)
+ NotifyInputHandler(rPos);
+}
+
+bool ScDocFunc::SetStringCell( const ScAddress& rPos, const OUString& rStr, bool bInteraction )
+{
+ ScDocShellModificator aModificator( rDocShell );
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bUndo = rDoc.IsUndoEnabled();
+
+ bool bHeight = rDoc.HasAttrib(rPos, HasAttrFlags::NeedHeight);
+
+ ScCellValue aOldVal;
+ if (bUndo)
+ aOldVal.assign(rDoc, rPos);
+
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(rPos, rStr, &aParam);
+
+ if (bUndo)
+ {
+ SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager();
+ ScCellValue aNewVal;
+ aNewVal.assign(rDoc, rPos);
+ pUndoMgr->AddUndoAction(std::make_unique<ScUndoSetCell>(&rDocShell, rPos, aOldVal, aNewVal));
+ }
+
+ if (bHeight)
+ AdjustRowHeight(rPos, true, !bInteraction);
+
+ rDocShell.PostPaintCell( rPos );
+ aModificator.SetDocumentModified();
+
+ // #103934#; notify editline and cell in edit mode
+ if (!bInteraction)
+ NotifyInputHandler( rPos );
+
+ return true;
+}
+
+bool ScDocFunc::SetEditCell( const ScAddress& rPos, const EditTextObject& rStr, bool bInteraction )
+{
+ ScDocShellModificator aModificator( rDocShell );
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bUndo = rDoc.IsUndoEnabled();
+
+ bool bHeight = rDoc.HasAttrib(rPos, HasAttrFlags::NeedHeight);
+
+ ScCellValue aOldVal;
+ if (bUndo)
+ aOldVal.assign(rDoc, rPos);
+
+ rDoc.SetEditText(rPos, rStr.Clone());
+
+ if (bUndo)
+ {
+ SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager();
+ ScCellValue aNewVal;
+ aNewVal.assign(rDoc, rPos);
+ pUndoMgr->AddUndoAction(std::make_unique<ScUndoSetCell>(&rDocShell, rPos, aOldVal, aNewVal));
+ }
+
+ if (bHeight)
+ AdjustRowHeight(rPos, true, !bInteraction);
+
+ rDocShell.PostPaintCell( rPos );
+ aModificator.SetDocumentModified();
+
+ // #103934#; notify editline and cell in edit mode
+ if (!bInteraction)
+ NotifyInputHandler( rPos );
+
+ return true;
+}
+
+bool ScDocFunc::SetStringOrEditCell( const ScAddress& rPos, const OUString& rStr, bool bInteraction )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (ScStringUtil::isMultiline(rStr))
+ {
+ ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
+ rEngine.SetTextCurrentDefaults(rStr);
+ std::unique_ptr<EditTextObject> pEditText(rEngine.CreateTextObject());
+ return SetEditCell(rPos, *pEditText, bInteraction);
+ }
+ else
+ return SetStringCell(rPos, rStr, bInteraction);
+}
+
+bool ScDocFunc::SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell, bool bInteraction )
+{
+ std::unique_ptr<ScFormulaCell> xCell(pCell);
+
+ ScDocShellModificator aModificator( rDocShell );
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bUndo = rDoc.IsUndoEnabled();
+
+ bool bHeight = rDoc.HasAttrib(rPos, HasAttrFlags::NeedHeight);
+
+ ScCellValue aOldVal;
+ if (bUndo)
+ aOldVal.assign(rDoc, rPos);
+
+ pCell = rDoc.SetFormulaCell(rPos, xCell.release());
+
+ // For performance reasons API calls may disable calculation while
+ // operating and recalculate once when done. If through user interaction
+ // and AutoCalc is disabled, calculate the formula (without its
+ // dependencies) once so the result matches the current document's content.
+ if (bInteraction && !rDoc.GetAutoCalc() && pCell)
+ {
+ // calculate just the cell once and set Dirty again
+ pCell->Interpret();
+ pCell->SetDirtyVar();
+ rDoc.PutInFormulaTree( pCell);
+ }
+
+ if (bUndo)
+ {
+ SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager();
+ ScCellValue aNewVal;
+ aNewVal.assign(rDoc, rPos);
+ pUndoMgr->AddUndoAction(std::make_unique<ScUndoSetCell>(&rDocShell, rPos, aOldVal, aNewVal));
+ }
+
+ if (bHeight)
+ AdjustRowHeight(rPos, true, !bInteraction);
+
+ rDocShell.PostPaintCell( rPos );
+ aModificator.SetDocumentModified();
+
+ // #103934#; notify editline and cell in edit mode
+ if (!bInteraction)
+ NotifyInputHandler( rPos );
+
+ return true;
+}
+
+bool ScDocFunc::SetFormulaCells( const ScAddress& rPos, std::vector<ScFormulaCell*>& rCells, bool bInteraction )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ const size_t nLength = rCells.size();
+ if (rPos.Row() + nLength - 1 > o3tl::make_unsigned(rDoc.MaxRow()))
+ // out of bound
+ return false;
+
+ ScRange aRange(rPos);
+ aRange.aEnd.IncRow(nLength - 1);
+
+ ScDocShellModificator aModificator( rDocShell );
+ bool bUndo = rDoc.IsUndoEnabled();
+
+ std::unique_ptr<sc::UndoSetCells> pUndoObj;
+ if (bUndo)
+ {
+ pUndoObj.reset(new sc::UndoSetCells(&rDocShell, rPos));
+ rDoc.TransferCellValuesTo(rPos, nLength, pUndoObj->GetOldValues());
+ }
+
+ rDoc.SetFormulaCells(rPos, rCells);
+
+ // For performance reasons API calls may disable calculation while
+ // operating and recalculate once when done. If through user interaction
+ // and AutoCalc is disabled, calculate the formula (without its
+ // dependencies) once so the result matches the current document's content.
+ if (bInteraction && !rDoc.GetAutoCalc())
+ {
+ for (auto* pCell : rCells)
+ {
+ // calculate just the cell once and set Dirty again
+ pCell->Interpret();
+ pCell->SetDirtyVar();
+ rDoc.PutInFormulaTree( pCell);
+ }
+ }
+
+ if (bUndo)
+ {
+ pUndoObj->SetNewValues(rCells);
+ SfxUndoManager* pUndoMgr = rDocShell.GetUndoManager();
+ pUndoMgr->AddUndoAction(std::move(pUndoObj));
+ }
+
+ rDocShell.PostPaint(aRange, PaintPartFlags::Grid);
+ aModificator.SetDocumentModified();
+
+ // #103934#; notify editline and cell in edit mode
+ if (!bInteraction)
+ NotifyInputHandler( rPos );
+
+ return true;
+}
+
+void ScDocFunc::NotifyInputHandler( const ScAddress& rPos )
+{
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( !(pViewSh && pViewSh->GetViewData().GetDocShell() == &rDocShell) )
+ return;
+
+ ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
+ if ( pInputHdl && pInputHdl->GetCursorPos() == rPos )
+ {
+ bool bIsEditMode(pInputHdl->IsEditMode());
+
+ // set modified if in editmode, because so the string is not set in the InputWindow like in the cell
+ // (the cell shows the same like the InputWindow)
+ if (bIsEditMode)
+ pInputHdl->SetModified();
+ pViewSh->UpdateInputHandler(false, !bIsEditMode);
+ }
+}
+
+namespace {
+
+ struct ScMyRememberItem
+ {
+ sal_Int32 nIndex;
+ SfxItemSet aItemSet;
+
+ ScMyRememberItem(const SfxItemSet& rItemSet, sal_Int32 nTempIndex) :
+ nIndex(nTempIndex), aItemSet(rItemSet) {}
+ };
+
+}
+
+void ScDocFunc::PutData( const ScAddress& rPos, ScEditEngineDefaulter& rEngine, bool bApi )
+{
+ // PutData calls PutCell or SetNormalString
+
+ bool bRet = false;
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScEditAttrTester aTester( &rEngine );
+ bool bEditCell = aTester.NeedsObject();
+ if ( bEditCell )
+ {
+ // #i61702# With bLoseContent set, the content of rEngine isn't restored
+ // (used in loading XML, where after the removeActionLock call the API object's
+ // EditEngine isn't accessed again.
+ bool bLoseContent = rDoc.IsImportingXML();
+
+ const bool bUpdateMode = rEngine.SetUpdateLayout(false);
+
+ std::vector<std::unique_ptr<ScMyRememberItem>> aRememberItems;
+
+ // All paragraph attributes must be removed before calling CreateTextObject,
+ // not only alignment, so the object doesn't contain the cell attributes as
+ // paragraph attributes. Before removing the attributes store them in a vector to
+ // set them back to the EditEngine.
+ sal_Int32 nCount = rEngine.GetParagraphCount();
+ for (sal_Int32 i=0; i<nCount; i++)
+ {
+ const SfxItemSet& rOld = rEngine.GetParaAttribs( i );
+ if ( rOld.Count() )
+ {
+ if ( !bLoseContent )
+ {
+ aRememberItems.push_back(std::make_unique<ScMyRememberItem>(rEngine.GetParaAttribs(i), i));
+ }
+ rEngine.SetParaAttribs( i, SfxItemSet( *rOld.GetPool(), rOld.GetRanges() ) );
+ }
+ }
+
+ // A copy of pNewData will be stored in the cell.
+ std::unique_ptr<EditTextObject> pNewData(rEngine.CreateTextObject());
+ bRet = SetEditCell(rPos, *pNewData, !bApi);
+
+ // Set the paragraph attributes back to the EditEngine.
+ for (const auto& rxItem : aRememberItems)
+ {
+ rEngine.SetParaAttribs(rxItem->nIndex, rxItem->aItemSet);
+ }
+
+ // #i61702# if the content isn't accessed, there's no need to set the UpdateMode again
+ if ( bUpdateMode && !bLoseContent )
+ rEngine.SetUpdateLayout(true);
+ }
+ else
+ {
+ OUString aText = rEngine.GetText();
+ if (aText.isEmpty())
+ {
+ bool bNumFmtSet = false;
+ bRet = SetNormalString( bNumFmtSet, rPos, aText, bApi );
+ }
+ else
+ bRet = SetStringCell(rPos, aText, !bApi);
+ }
+
+ if ( !(bRet && aTester.NeedsCellAttr()) )
+ return;
+
+ const SfxItemSet& rEditAttr = aTester.GetAttribs();
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetFromEditItemSet( &rEditAttr );
+ aPattern.DeleteUnchanged( rDoc.GetPattern( rPos.Col(), rPos.Row(), rPos.Tab() ) );
+ aPattern.GetItemSet().ClearItem( ATTR_HOR_JUSTIFY ); // wasn't removed above if no edit object
+ if ( aPattern.GetItemSet().Count() > 0 )
+ {
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SelectTable( rPos.Tab(), true );
+ aMark.SetMarkArea( ScRange( rPos ) );
+ ApplyAttributes( aMark, aPattern, bApi );
+ }
+}
+
+bool ScDocFunc::SetCellText(
+ const ScAddress& rPos, const OUString& rText, bool bInterpret, bool bEnglish, bool bApi,
+ const formula::FormulaGrammar::Grammar eGrammar )
+{
+ bool bSet = false;
+ if ( bInterpret )
+ {
+ if ( bEnglish )
+ {
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ ::std::optional<ScExternalRefManager::ApiGuard> pExtRefGuard;
+ if (bApi)
+ pExtRefGuard.emplace(rDoc);
+
+ ScInputStringType aRes =
+ ScStringUtil::parseInputString(*rDoc.GetFormatTable(), rText, LANGUAGE_ENGLISH_US);
+
+ switch (aRes.meType)
+ {
+ case ScInputStringType::Formula:
+ bSet = SetFormulaCell(rPos, new ScFormulaCell(rDoc, rPos, aRes.maText, eGrammar), !bApi);
+ break;
+ case ScInputStringType::Number:
+ bSet = SetValueCell(rPos, aRes.mfValue, !bApi);
+ break;
+ case ScInputStringType::Text:
+ bSet = SetStringOrEditCell(rPos, aRes.maText, !bApi);
+ break;
+ default:
+ ;
+ }
+ }
+ // otherwise keep Null -> SetString with local formulas/number formats
+ }
+ else if (!rText.isEmpty())
+ {
+ bSet = SetStringOrEditCell(rPos, rText, !bApi);
+ }
+
+ if (!bSet)
+ {
+ bool bNumFmtSet = false;
+ bSet = SetNormalString( bNumFmtSet, rPos, rText, bApi );
+ }
+ return bSet;
+}
+
+bool ScDocFunc::ShowNote( const ScAddress& rPos, bool bShow )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScPostIt* pNote = rDoc.GetNote( rPos );
+ if( !pNote || (bShow == pNote->IsCaptionShown()) ||
+ (comphelper::LibreOfficeKit::isActive() && !comphelper::LibreOfficeKit::isTiledAnnotations()) )
+ return false;
+
+ // move the caption to internal or hidden layer and create undo action
+ pNote->ShowCaption( rPos, bShow );
+ if( rDoc.IsUndoEnabled() )
+ rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideNote>( rDocShell, rPos, bShow ) );
+
+ rDoc.SetStreamValid(rPos.Tab(), false);
+
+ ScTabView::OnLOKNoteStateChanged(pNote);
+
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ {
+ if (ScDrawView* pDrawView = pViewData->GetScDrawView())
+ pDrawView->SyncForGrid( pNote->GetCaption());
+ }
+
+ rDocShell.SetDocumentModified();
+
+ return true;
+}
+
+void ScDocFunc::SetNoteText( const ScAddress& rPos, const OUString& rText, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScEditableTester aTester( rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() );
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ OUString aNewText = convertLineEnd(rText, GetSystemLineEnd()); //! is this necessary ???
+
+ if( ScPostIt* pNote = (!aNewText.isEmpty()) ? rDoc.GetOrCreateNote( rPos ) : rDoc.GetNote(rPos) )
+ pNote->SetText( rPos, aNewText );
+
+ //! Undo !!!
+
+ rDoc.SetStreamValid(rPos.Tab(), false);
+
+ rDocShell.PostPaintCell( rPos );
+ aModificator.SetDocumentModified();
+}
+
+void ScDocFunc::ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, const OUString* pAuthor, const OUString* pDate, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScEditableTester aTester( rDoc, rPos.Tab(), rPos.Col(),rPos.Row(), rPos.Col(),rPos.Row() );
+ if (aTester.IsEditable())
+ {
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ SfxUndoManager* pUndoMgr = (pDrawLayer && rDoc.IsUndoEnabled()) ? rDocShell.GetUndoManager() : nullptr;
+
+ ScNoteData aOldData;
+ std::unique_ptr<ScPostIt> pOldNote = rDoc.ReleaseNote( rPos );
+ sal_uInt32 nNoteId = 0;
+ if( pOldNote )
+ {
+ nNoteId = pOldNote->GetId();
+ // ensure existing caption object before draw undo tracking starts
+ pOldNote->GetOrCreateCaption( rPos );
+ // rescue note data for undo
+ aOldData = pOldNote->GetNoteData();
+ }
+
+ // collect drawing undo actions for deleting/inserting caption objects
+ if( pUndoMgr )
+ pDrawLayer->BeginCalcUndo(false);
+
+ // delete the note (creates drawing undo action for the caption object)
+ bool hadOldNote(pOldNote);
+ pOldNote.reset();
+
+ // create new note (creates drawing undo action for the new caption object)
+ ScNoteData aNewData;
+ ScPostIt* pNewNote = nullptr;
+ if( (pNewNote = ScNoteUtil::CreateNoteFromString( rDoc, rPos, rNoteText, false, true, nNoteId )) )
+ {
+ if( pAuthor ) pNewNote->SetAuthor( *pAuthor );
+ if( pDate ) pNewNote->SetDate( *pDate );
+
+ // rescue note data for undo
+ aNewData = pNewNote->GetNoteData();
+ }
+
+ // create the undo action
+ if( pUndoMgr && (aOldData.mxCaption || aNewData.mxCaption) )
+ pUndoMgr->AddUndoAction( std::make_unique<ScUndoReplaceNote>( rDocShell, rPos, aOldData, aNewData, pDrawLayer->GetCalcUndo() ) );
+
+ // repaint cell (to make note marker visible)
+ rDocShell.PostPaintCell( rPos );
+
+ rDoc.SetStreamValid(rPos.Tab(), false);
+
+ aModificator.SetDocumentModified();
+
+ // Let our LOK clients know about the new/modified note
+ if (pNewNote)
+ {
+ ScDocShell::LOKCommentNotify(hadOldNote ? LOKCommentNotificationType::Modify : LOKCommentNotificationType::Add,
+ &rDoc, rPos, pNewNote);
+ }
+ }
+ else if (!bApi)
+ {
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ }
+}
+
+ScPostIt* ScDocFunc::ImportNote( const ScAddress& rPos, const OUString& rNoteText )
+{
+ ScDocShellModificator aModificator( rDocShell );
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ std::unique_ptr<ScPostIt> pOldNote = rDoc.ReleaseNote( rPos );
+ SAL_WARN_IF(pOldNote, "sc.ui", "imported data has >1 notes on same cell? at pos " << rPos);
+
+ // create new note
+ ScPostIt* pNewNote = ScNoteUtil::CreateNoteFromString( rDoc, rPos, rNoteText, false, true, /*nNoteId*/0 );
+
+ rDoc.SetStreamValid(rPos.Tab(), false);
+
+ aModificator.SetDocumentModified();
+
+ return pNewNote;
+}
+
+bool ScDocFunc::ApplyAttributes( const ScMarkData& rMark, const ScPatternAttr& rPattern,
+ bool bApi )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bRecord = true;
+ if ( !rDoc.IsUndoEnabled() )
+ bRecord = false;
+
+ bool bImportingXML = rDoc.IsImportingXML();
+ // Cell formats can still be set if the range isn't editable only because of matrix formulas.
+ // #i62483# When loading XML, the check can be skipped altogether.
+ bool bOnlyNotBecauseOfMatrix;
+ if ( !bImportingXML && !rDoc.IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix )
+ && !bOnlyNotBecauseOfMatrix )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PROTECTIONERR);
+ return false;
+ }
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ //! Border
+
+ ScRange aMultiRange;
+ bool bMulti = rMark.IsMultiMarked();
+ if ( bMulti )
+ aMultiRange = rMark.GetMultiMarkArea();
+ else
+ aMultiRange = rMark.GetMarkArea();
+
+ if ( bRecord )
+ {
+ ScDocumentUniquePtr pUndoDoc( new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, aMultiRange.aStart.Tab(), aMultiRange.aEnd.Tab() );
+ rDoc.CopyToDocument(aMultiRange, InsertDeleteFlags::ATTRIB, bMulti, *pUndoDoc, &rMark);
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoSelectionAttr>(
+ &rDocShell, rMark,
+ aMultiRange.aStart.Col(), aMultiRange.aStart.Row(), aMultiRange.aStart.Tab(),
+ aMultiRange.aEnd.Col(), aMultiRange.aEnd.Row(), aMultiRange.aEnd.Tab(),
+ std::move(pUndoDoc), bMulti, &rPattern ) );
+ }
+
+ // While loading XML it is not necessary to ask HasAttrib. It needs too much time.
+ sal_uInt16 nExtFlags = 0;
+ if ( !bImportingXML )
+ rDocShell.UpdatePaintExt( nExtFlags, aMultiRange ); // content before the change
+
+ bool bChanged = false;
+ rDoc.ApplySelectionPattern( rPattern, rMark, nullptr, &bChanged );
+
+ if(bChanged)
+ {
+ if ( !bImportingXML )
+ rDocShell.UpdatePaintExt( nExtFlags, aMultiRange ); // content after the change
+
+ if (!AdjustRowHeight( aMultiRange, true, bApi ))
+ rDocShell.PostPaint( aMultiRange, PaintPartFlags::Grid, nExtFlags );
+ else if (nExtFlags & SC_PF_LINES)
+ lcl_PaintAbove( rDocShell, aMultiRange ); // because of lines above the range
+
+ aModificator.SetDocumentModified();
+ }
+
+ return true;
+}
+
+bool ScDocFunc::ApplyStyle( const ScMarkData& rMark, const OUString& rStyleName,
+ bool bApi )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bRecord = true;
+ if ( !rDoc.IsUndoEnabled() )
+ bRecord = false;
+
+ bool bImportingXML = rDoc.IsImportingXML();
+ // Cell formats can still be set if the range isn't editable only because of matrix formulas.
+ // #i62483# When loading XML, the check can be skipped altogether.
+ bool bOnlyNotBecauseOfMatrix;
+ if ( !bImportingXML && !rDoc.IsSelectionEditable( rMark, &bOnlyNotBecauseOfMatrix )
+ && !bOnlyNotBecauseOfMatrix )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PROTECTIONERR);
+ return false;
+ }
+
+ ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>( rDoc.GetStyleSheetPool()->Find(
+ rStyleName, SfxStyleFamily::Para ));
+ if (!pStyleSheet)
+ return false;
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScRange aMultiRange;
+ bool bMulti = rMark.IsMultiMarked();
+ if ( bMulti )
+ aMultiRange = rMark.GetMultiMarkArea();
+ else
+ aMultiRange = rMark.GetMarkArea();
+
+ if ( bRecord )
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ SCTAB nStartTab = aMultiRange.aStart.Tab();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab );
+ for (const auto& rTab : rMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (rTab != nStartTab)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ }
+
+ ScRange aCopyRange = aMultiRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, bMulti, *pUndoDoc, &rMark );
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoSelectionStyle>(
+ &rDocShell, rMark, aMultiRange, rStyleName, std::move(pUndoDoc) ) );
+
+ }
+
+ rDoc.ApplySelectionStyle( *pStyleSheet, rMark );
+
+ if (!AdjustRowHeight( aMultiRange, true, bApi ))
+ rDocShell.PostPaint( aMultiRange, PaintPartFlags::Grid );
+
+ aModificator.SetDocumentModified();
+
+ return true;
+}
+
+namespace {
+
+/**
+ * Check if this insertion attempt would end up cutting one or more pivot
+ * tables in half, which is not desirable.
+ *
+ * @return true if this insertion can be done safely without shearing any
+ * existing pivot tables, false otherwise.
+ */
+bool canInsertCellsByPivot(const ScRange& rRange, const ScMarkData& rMarkData, InsCellCmd eCmd, const ScDocument& rDoc)
+{
+ if (!rDoc.HasPivotTable())
+ // This document has no pivot tables.
+ return true;
+
+ const ScDPCollection* pDPs = rDoc.GetDPCollection();
+
+ ScRange aRange(rRange); // local copy
+ switch (eCmd)
+ {
+ case INS_INSROWS_BEFORE:
+ {
+ aRange.aStart.SetCol(0);
+ aRange.aEnd.SetCol(rDoc.MaxCol());
+ [[fallthrough]];
+ }
+ case INS_CELLSDOWN:
+ {
+ auto bIntersects = std::any_of(rMarkData.begin(), rMarkData.end(), [&pDPs, &aRange](const SCTAB& rTab) {
+ return pDPs->IntersectsTableByColumns(aRange.aStart.Col(), aRange.aEnd.Col(), aRange.aStart.Row(), rTab); });
+ if (bIntersects)
+ // This column range cuts through at least one pivot table. Not good.
+ return false;
+
+ // Start row must be either at the top or above any pivot tables.
+ if (aRange.aStart.Row() < 0)
+ // I don't know how to handle this case.
+ return false;
+
+ if (aRange.aStart.Row() == 0)
+ // First row is always allowed.
+ return true;
+
+ ScRange aTest(aRange);
+ aTest.aStart.IncRow(-1); // Test one row up.
+ aTest.aEnd.SetRow(aTest.aStart.Row());
+ for (const auto& rTab : rMarkData)
+ {
+ aTest.aStart.SetTab(rTab);
+ aTest.aEnd.SetTab(rTab);
+ if (pDPs->HasTable(aTest))
+ return false;
+ }
+ }
+ break;
+ case INS_INSCOLS_BEFORE:
+ {
+ aRange.aStart.SetRow(0);
+ aRange.aEnd.SetRow(rDoc.MaxRow());
+ [[fallthrough]];
+ }
+ case INS_CELLSRIGHT:
+ {
+ auto bIntersects = std::any_of(rMarkData.begin(), rMarkData.end(), [&pDPs, &aRange](const SCTAB& rTab) {
+ return pDPs->IntersectsTableByRows(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Row(), rTab); });
+ if (bIntersects)
+ // This column range cuts through at least one pivot table. Not good.
+ return false;
+
+ // Start row must be either at the top or above any pivot tables.
+ if (aRange.aStart.Col() < 0)
+ // I don't know how to handle this case.
+ return false;
+
+ if (aRange.aStart.Col() == 0)
+ // First row is always allowed.
+ return true;
+
+ ScRange aTest(aRange);
+ aTest.aStart.IncCol(-1); // Test one column to the left.
+ aTest.aEnd.SetCol(aTest.aStart.Col());
+ for (const auto& rTab : rMarkData)
+ {
+ aTest.aStart.SetTab(rTab);
+ aTest.aEnd.SetTab(rTab);
+ if (pDPs->HasTable(aTest))
+ return false;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ return true;
+}
+
+/**
+ * Check if this deletion attempt would end up cutting one or more pivot
+ * tables in half, which is not desirable.
+ *
+ * @return true if this deletion can be done safely without shearing any
+ * existing pivot tables, false otherwise.
+ */
+bool canDeleteCellsByPivot(const ScRange& rRange, const ScMarkData& rMarkData, DelCellCmd eCmd, const ScDocument& rDoc)
+{
+ if (!rDoc.HasPivotTable())
+ // This document has no pivot tables.
+ return true;
+
+ const ScDPCollection* pDPs = rDoc.GetDPCollection();
+
+ ScRange aRange(rRange); // local copy
+
+ switch (eCmd)
+ {
+ case DelCellCmd::Rows:
+ {
+ aRange.aStart.SetCol(0);
+ aRange.aEnd.SetCol(rDoc.MaxCol());
+ [[fallthrough]];
+ }
+ case DelCellCmd::CellsUp:
+ {
+ auto bIntersects = std::any_of(rMarkData.begin(), rMarkData.end(), [&pDPs, &aRange](const SCTAB& rTab) {
+ return pDPs->IntersectsTableByColumns(aRange.aStart.Col(), aRange.aEnd.Col(), aRange.aStart.Row(), rTab); });
+ if (bIntersects)
+ // This column range cuts through at least one pivot table. Not good.
+ return false;
+
+ ScRange aTest(aRange);
+ for (const auto& rTab : rMarkData)
+ {
+ aTest.aStart.SetTab(rTab);
+ aTest.aEnd.SetTab(rTab);
+ if (pDPs->HasTable(aTest))
+ return false;
+ }
+ }
+ break;
+ case DelCellCmd::Cols:
+ {
+ aRange.aStart.SetRow(0);
+ aRange.aEnd.SetRow(rDoc.MaxRow());
+ [[fallthrough]];
+ }
+ case DelCellCmd::CellsLeft:
+ {
+ auto bIntersects = std::any_of(rMarkData.begin(), rMarkData.end(), [&pDPs, &aRange](const SCTAB& rTab) {
+ return pDPs->IntersectsTableByRows(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Row(), rTab); });
+ if (bIntersects)
+ // This column range cuts through at least one pivot table. Not good.
+ return false;
+
+ ScRange aTest(aRange);
+ for (const auto& rTab : rMarkData)
+ {
+ aTest.aStart.SetTab(rTab);
+ aTest.aEnd.SetTab(rTab);
+ if (pDPs->HasTable(aTest))
+ return false;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ return true;
+}
+
+}
+
+bool ScDocFunc::InsertCells( const ScRange& rRange, const ScMarkData* pTabMark, InsCellCmd eCmd,
+ bool bRecord, bool bApi, bool bPartOfPaste )
+{
+ ScDocShellModificator aModificator( rDocShell );
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (rDocShell.GetDocument().GetChangeTrack() &&
+ ((eCmd == INS_CELLSDOWN && (rRange.aStart.Col() != 0 || rRange.aEnd.Col() != rDoc.MaxCol())) ||
+ (eCmd == INS_CELLSRIGHT && (rRange.aStart.Row() != 0 || rRange.aEnd.Row() != rDoc.MaxRow()))))
+ {
+ // We should not reach this via UI disabled slots.
+ assert(bApi);
+ SAL_WARN("sc.ui","ScDocFunc::InsertCells - no change-tracking of partial cell shift");
+ return false;
+ }
+
+ ScRange aTargetRange( rRange );
+
+ // If insertion is for full cols/rows and after the current
+ // selection, then shift the range accordingly
+ if ( eCmd == INS_INSROWS_AFTER )
+ {
+ ScRange aErrorRange( ScAddress::UNINITIALIZED );
+ if (!aTargetRange.Move(0, rRange.aEnd.Row() - rRange.aStart.Row() + 1, 0, aErrorRange, rDoc))
+ {
+ return false;
+ }
+ }
+ if ( eCmd == INS_INSCOLS_AFTER )
+ {
+ ScRange aErrorRange( ScAddress::UNINITIALIZED );
+ if (!aTargetRange.Move(rRange.aEnd.Col() - rRange.aStart.Col() + 1, 0, 0, aErrorRange, rDoc))
+ {
+ return false;
+ }
+ }
+
+ SCCOL nStartCol = aTargetRange.aStart.Col();
+ SCROW nStartRow = aTargetRange.aStart.Row();
+ SCTAB nStartTab = aTargetRange.aStart.Tab();
+ SCCOL nEndCol = aTargetRange.aEnd.Col();
+ SCROW nEndRow = aTargetRange.aEnd.Row();
+ SCTAB nEndTab = aTargetRange.aEnd.Tab();
+
+ if ( !rDoc.ValidRow(nStartRow) || !rDoc.ValidRow(nEndRow) )
+ {
+ OSL_FAIL("invalid row in InsertCells");
+ return false;
+ }
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCCOL nPaintStartCol = nStartCol;
+ SCROW nPaintStartRow = nStartRow;
+ SCCOL nPaintEndCol = nEndCol;
+ SCROW nPaintEndRow = nEndRow;
+ PaintPartFlags nPaintFlags = PaintPartFlags::Grid;
+ bool bSuccess;
+
+ ScTabViewShell* pViewSh = rDocShell.GetBestViewShell(); //preserve current cursor position
+ SCCOL nCursorCol = 0;
+ SCROW nCursorRow = 0;
+ if( pViewSh )
+ {
+ nCursorCol = pViewSh->GetViewData().GetCurX();
+ nCursorRow = pViewSh->GetViewData().GetCurY();
+ }
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ if (pTabMark)
+ aMark = *pTabMark;
+ else
+ {
+ SCTAB nCount = 0;
+ for( SCTAB i=0; i<nTabCount; i++ )
+ {
+ if( !rDoc.IsScenario(i) )
+ {
+ nCount++;
+ if( nCount == nEndTab+1 )
+ {
+ aMark.SelectTable( i, true );
+ break;
+ }
+ }
+ }
+ }
+
+ ScMarkData aFullMark( aMark ); // including scenario sheets
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ for( SCTAB j = rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ )
+ aFullMark.SelectTable( j, true );
+ }
+
+ SCTAB nSelCount = aMark.GetSelectCount();
+
+ // Adjust also related scenarios
+
+ SCCOL nMergeTestStartCol = nStartCol;
+ SCROW nMergeTestStartRow = nStartRow;
+ SCCOL nMergeTestEndCol = nEndCol;
+ SCROW nMergeTestEndRow = nEndRow;
+
+ ScRange aExtendMergeRange( aTargetRange );
+
+ if( aTargetRange.aStart == aTargetRange.aEnd && rDoc.HasAttrib(aTargetRange, HasAttrFlags::Merged) )
+ {
+ rDoc.ExtendMerge( aExtendMergeRange );
+ rDoc.ExtendOverlapped( aExtendMergeRange );
+ nMergeTestEndCol = aExtendMergeRange.aEnd.Col();
+ nMergeTestEndRow = aExtendMergeRange.aEnd.Row();
+ nPaintEndCol = nMergeTestEndCol;
+ nPaintEndRow = nMergeTestEndRow;
+ }
+
+ if ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER )
+ {
+ nMergeTestStartCol = 0;
+ nMergeTestEndCol = rDoc.MaxCol();
+ }
+ if ( eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER )
+ {
+ nMergeTestStartRow = 0;
+ nMergeTestEndRow = rDoc.MaxRow();
+ }
+ if ( eCmd == INS_CELLSDOWN )
+ nMergeTestEndRow = rDoc.MaxRow();
+ if ( eCmd == INS_CELLSRIGHT )
+ nMergeTestEndCol = rDoc.MaxCol();
+
+ bool bNeedRefresh = false;
+
+ SCCOL nEditTestEndCol = (eCmd==INS_INSCOLS_BEFORE || eCmd==INS_INSCOLS_AFTER) ? rDoc.MaxCol() : nMergeTestEndCol;
+ SCROW nEditTestEndRow = (eCmd==INS_INSROWS_BEFORE || eCmd==INS_INSROWS_AFTER) ? rDoc.MaxRow() : nMergeTestEndRow;
+
+ ScEditableTester aTester;
+
+ switch (eCmd)
+ {
+ case INS_INSCOLS_BEFORE:
+ aTester = ScEditableTester(
+ rDoc, sc::ColRowEditAction::InsertColumnsBefore, nMergeTestStartCol, nMergeTestEndCol, aMark);
+ break;
+ case INS_INSCOLS_AFTER:
+ aTester = ScEditableTester(
+ rDoc, sc::ColRowEditAction::InsertColumnsAfter, nMergeTestStartCol, nMergeTestEndCol, aMark);
+ break;
+ case INS_INSROWS_BEFORE:
+ aTester = ScEditableTester(
+ rDoc, sc::ColRowEditAction::InsertRowsBefore, nMergeTestStartRow, nMergeTestEndRow, aMark);
+ break;
+ case INS_INSROWS_AFTER:
+ aTester = ScEditableTester(
+ rDoc, sc::ColRowEditAction::InsertRowsAfter, nMergeTestStartRow, nMergeTestEndRow, aMark);
+ break;
+ default:
+ aTester = ScEditableTester(
+ rDoc, nMergeTestStartCol, nMergeTestStartRow, nEditTestEndCol, nEditTestEndRow, aMark);
+ }
+
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ // Check if this insertion is allowed with respect to pivot table.
+ if (!canInsertCellsByPivot(aTargetRange, aMark, eCmd, rDoc))
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_NO_INSERT_DELETE_OVER_PIVOT_TABLE);
+ return false;
+ }
+
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas at UpdateReference
+
+ ScDocumentUniquePtr pRefUndoDoc;
+ std::unique_ptr<ScRefUndoData> pUndoData;
+ if ( bRecord )
+ {
+ pRefUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pRefUndoDoc->InitUndo( rDoc, 0, nTabCount-1 );
+
+ // pRefUndoDoc is filled in InsertCol / InsertRow
+
+ pUndoData.reset(new ScRefUndoData( &rDoc ));
+
+ rDoc.BeginDrawUndo();
+ }
+
+ // #i8302 : we unmerge overwhelming ranges, before insertion all the actions are put in the same ListAction
+ // the patch comes from mloiseleur and maoyg
+ bool bInsertMerge = false;
+ std::vector<ScRange> qIncreaseRange;
+ OUString aUndo = ScResId( STR_UNDO_INSERTCELLS );
+ if (bRecord)
+ {
+ ViewShellId nViewShellId(-1);
+ if (pViewSh)
+ nViewShellId = pViewSh->GetViewShellId();
+ rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId );
+ }
+ std::unique_ptr<ScUndoRemoveMerge> pUndoRemoveMerge;
+
+ for (const SCTAB i : aMark)
+ {
+ if (i >= nTabCount)
+ break;
+
+ if( rDoc.HasAttrib( nMergeTestStartCol, nMergeTestStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i, HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
+ {
+ if (eCmd==INS_CELLSRIGHT)
+ bNeedRefresh = true;
+
+ SCCOL nMergeStartCol = nMergeTestStartCol;
+ SCROW nMergeStartRow = nMergeTestStartRow;
+ SCCOL nMergeEndCol = nMergeTestEndCol;
+ SCROW nMergeEndRow = nMergeTestEndRow;
+
+ rDoc.ExtendMerge( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i );
+ rDoc.ExtendOverlapped( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i );
+
+ if(( eCmd == INS_CELLSDOWN && ( nMergeStartCol != nMergeTestStartCol || nMergeEndCol != nMergeTestEndCol )) ||
+ (eCmd == INS_CELLSRIGHT && ( nMergeStartRow != nMergeTestStartRow || nMergeEndRow != nMergeTestEndRow )) )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0);
+ rDocShell.GetUndoManager()->LeaveListAction();
+ return false;
+ }
+
+ SCCOL nTestCol = -1;
+ SCROW nTestRow1 = -1;
+ SCROW nTestRow2 = -1;
+
+ ScDocAttrIterator aTestIter( rDoc, i, nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow );
+ ScRange aExtendRange( nMergeTestStartCol, nMergeTestStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i );
+ const ScPatternAttr* pPattern = nullptr;
+ while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != nullptr )
+ {
+ const ScMergeAttr& rMergeFlag = pPattern->GetItem(ATTR_MERGE);
+ const ScMergeFlagAttr& rMergeFlagAttr = pPattern->GetItem(ATTR_MERGE_FLAG);
+ ScMF nNewFlags = rMergeFlagAttr.GetValue() & (ScMF::Hor | ScMF::Ver);
+ if (rMergeFlag.IsMerged() || nNewFlags == ScMF::Hor || nNewFlags == ScMF::Ver)
+ {
+ ScRange aRange( nTestCol, nTestRow1, i );
+ rDoc.ExtendOverlapped(aRange);
+ rDoc.ExtendMerge(aRange, true);
+
+ if( nTestRow1 < nTestRow2 && nNewFlags == ScMF::Hor )
+ {
+ for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ )
+ {
+ ScRange aTestRange( nTestCol, nTestRow, i );
+ rDoc.ExtendOverlapped( aTestRange );
+ rDoc.ExtendMerge( aTestRange, true);
+ ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i );
+ if( !aExtendRange.Contains( aMergeRange ) )
+ {
+ qIncreaseRange.push_back( aTestRange );
+ bInsertMerge = true;
+ }
+ }
+ }
+ else
+ {
+ ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i );
+ if( !aExtendRange.Contains( aMergeRange ) )
+ {
+ qIncreaseRange.push_back( aRange );
+ }
+ bInsertMerge = true;
+ }
+ }
+ }
+
+ if( bInsertMerge )
+ {
+ if( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_CELLSDOWN )
+ {
+ nStartRow = aExtendMergeRange.aStart.Row();
+ nEndRow = aExtendMergeRange.aEnd.Row();
+
+ if( eCmd == INS_CELLSDOWN )
+ nEndCol = nMergeTestEndCol;
+ else
+ {
+ nStartCol = 0;
+ nEndCol = rDoc.MaxCol();
+ }
+ }
+ else if( eCmd == INS_CELLSRIGHT || eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER )
+ {
+
+ nStartCol = aExtendMergeRange.aStart.Col();
+ nEndCol = aExtendMergeRange.aEnd.Col();
+ if( eCmd == INS_CELLSRIGHT )
+ {
+ nEndRow = nMergeTestEndRow;
+ }
+ else
+ {
+ nStartRow = 0;
+ nEndRow = rDoc.MaxRow();
+ }
+ }
+
+ if( !qIncreaseRange.empty() )
+ {
+ if (bRecord && !pUndoRemoveMerge)
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, *aMark.begin(), *aMark.rbegin());
+ pUndoRemoveMerge.reset( new ScUndoRemoveMerge( &rDocShell, rRange, std::move(pUndoDoc) ));
+ }
+
+ for( const ScRange& aRange : qIncreaseRange )
+ {
+ if( rDoc.HasAttrib( aRange, HasAttrFlags::Overlapped | HasAttrFlags::Merged ) )
+ {
+ UnmergeCells( aRange, bRecord, pUndoRemoveMerge.get() );
+ }
+ }
+ }
+ }
+ else
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_MSSG_INSERTCELLS_0);
+ rDocShell.GetUndoManager()->LeaveListAction();
+ return false;
+ }
+ }
+ }
+
+ if (bRecord && pUndoRemoveMerge)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction( std::move(pUndoRemoveMerge));
+ }
+
+ switch (eCmd)
+ {
+ case INS_CELLSDOWN:
+ bSuccess = rDoc.InsertRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc.get(), &aFullMark );
+ nPaintEndRow = rDoc.MaxRow();
+ break;
+ case INS_INSROWS_BEFORE:
+ case INS_INSROWS_AFTER:
+ bSuccess = rDoc.InsertRow( 0, 0, rDoc.MaxCol(), MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc.get(), &aFullMark );
+ nPaintStartCol = 0;
+ nPaintEndCol = rDoc.MaxCol();
+ nPaintEndRow = rDoc.MaxRow();
+ nPaintFlags |= PaintPartFlags::Left;
+ break;
+ case INS_CELLSRIGHT:
+ bSuccess = rDoc.InsertCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc.get(), &aFullMark );
+ nPaintEndCol = rDoc.MaxCol();
+ break;
+ case INS_INSCOLS_BEFORE:
+ case INS_INSCOLS_AFTER:
+ bSuccess = rDoc.InsertCol( 0, 0, rDoc.MaxRow(), MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc.get(), &aFullMark );
+ nPaintStartRow = 0;
+ nPaintEndRow = rDoc.MaxRow();
+ nPaintEndCol = rDoc.MaxCol();
+ nPaintFlags |= PaintPartFlags::Top;
+ break;
+ default:
+ OSL_FAIL("Wrong code at inserting");
+ bSuccess = false;
+ break;
+ }
+
+ if ( bSuccess )
+ {
+ SCTAB nUndoPos = 0;
+
+ if ( bRecord )
+ {
+ std::unique_ptr<SCTAB[]> pTabs(new SCTAB[nSelCount]);
+ std::unique_ptr<SCTAB[]> pScenarios(new SCTAB[nSelCount]);
+ nUndoPos = 0;
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ SCTAB nCount = 0;
+ for( SCTAB j=rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ )
+ nCount ++;
+
+ pScenarios[nUndoPos] = nCount;
+ pTabs[nUndoPos] = rTab;
+ nUndoPos ++;
+ }
+
+ if( !bInsertMerge )
+ {
+ rDocShell.GetUndoManager()->LeaveListAction();
+ }
+
+ rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoInsertCells>(
+ &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ),
+ nUndoPos, std::move(pTabs), std::move(pScenarios), eCmd, std::move(pRefUndoDoc), std::move(pUndoData), bPartOfPaste ) );
+ }
+
+ // #i8302 : we remerge growing ranges, with the new part inserted
+
+ while( !qIncreaseRange.empty() )
+ {
+ ScRange aRange = qIncreaseRange.back();
+ if( !rDoc.HasAttrib( aRange, HasAttrFlags::Overlapped | HasAttrFlags::Merged ) )
+ {
+ switch (eCmd)
+ {
+ case INS_CELLSDOWN:
+ case INS_INSROWS_BEFORE:
+ case INS_INSROWS_AFTER:
+ aRange.aEnd.IncRow(static_cast<SCCOL>(nEndRow-nStartRow+1));
+ break;
+ case INS_CELLSRIGHT:
+ case INS_INSCOLS_BEFORE:
+ case INS_INSCOLS_AFTER:
+ aRange.aEnd.IncCol(static_cast<SCCOL>(nEndCol-nStartCol+1));
+ break;
+ default:
+ break;
+ }
+ ScCellMergeOption aMergeOption(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row() );
+ aMergeOption.maTabs.insert(aRange.aStart.Tab());
+ MergeCells(aMergeOption, false, true, true);
+ }
+ qIncreaseRange.pop_back();
+ }
+
+ if( bInsertMerge )
+ rDocShell.GetUndoManager()->LeaveListAction();
+
+ for (const SCTAB i : aMark)
+ {
+ if (i >= nTabCount)
+ break;
+
+ rDoc.SetDrawPageSize(i);
+
+ if (bNeedRefresh)
+ rDoc.ExtendMerge( nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow, i, true );
+ else
+ rDoc.RefreshAutoFilter( nMergeTestStartCol, nMergeTestStartRow, nMergeTestEndCol, nMergeTestEndRow, i );
+
+ if ( eCmd == INS_INSROWS_BEFORE ||eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSROWS_AFTER ||eCmd == INS_INSCOLS_AFTER )
+ rDoc.UpdatePageBreaks( i );
+
+ sal_uInt16 nExtFlags = 0;
+ rDocShell.UpdatePaintExt( nExtFlags, nPaintStartCol, nPaintStartRow, i, nPaintEndCol, nPaintEndRow, i );
+
+ SCTAB nScenarioCount = 0;
+
+ for( SCTAB j = i+1; j<nTabCount && rDoc.IsScenario(j); j++ )
+ nScenarioCount ++;
+
+ bool bAdjusted = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER ) ?
+ AdjustRowHeight(ScRange(0, nStartRow, i, rDoc.MaxCol(), nEndRow, i+nScenarioCount ), true, bApi) :
+ AdjustRowHeight(ScRange(0, nPaintStartRow, i, rDoc.MaxCol(), nPaintEndRow, i+nScenarioCount ), true, bApi);
+ if (bAdjusted)
+ {
+ // paint only what is not done by AdjustRowHeight
+ if (nPaintFlags & PaintPartFlags::Top)
+ rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, i, nPaintEndCol, nPaintEndRow, i+nScenarioCount, PaintPartFlags::Top );
+ }
+ else
+ rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, i, nPaintEndCol, nPaintEndRow, i+nScenarioCount, nPaintFlags, nExtFlags );
+ }
+ }
+ else
+ {
+ if( bInsertMerge )
+ {
+ while( !qIncreaseRange.empty() )
+ {
+ ScRange aRange = qIncreaseRange.back();
+ ScCellMergeOption aMergeOption(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row() );
+ MergeCells(aMergeOption, false, true, true);
+ qIncreaseRange.pop_back();
+ }
+
+ if( pViewSh )
+ {
+ pViewSh->MarkRange( aTargetRange, false );
+ pViewSh->SetCursor( nCursorCol, nCursorRow );
+ }
+ }
+
+ rDocShell.GetUndoManager()->LeaveListAction();
+ rDocShell.GetUndoManager()->RemoveLastUndoAction();
+
+ pRefUndoDoc.reset();
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_INSERT_FULL); // column/row full
+ }
+
+ // The cursor position needs to be modified earlier than updating
+ // any enabled edit view which is triggered by SetDocumentModified below.
+ if (bSuccess)
+ {
+ bool bInsertCols = ( eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER);
+ bool bInsertRows = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER );
+
+ if (bInsertCols)
+ {
+ pViewSh->OnLOKInsertDeleteColumn(rRange.aStart.Col(), 1);
+ }
+
+ if (bInsertRows)
+ {
+ pViewSh->OnLOKInsertDeleteRow(rRange.aStart.Row(), 1);
+ }
+ }
+
+ aModificator.SetDocumentModified();
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+ return bSuccess;
+}
+
+bool ScDocFunc::DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark, DelCellCmd eCmd,
+ bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (rDocShell.GetDocument().GetChangeTrack() &&
+ ((eCmd == DelCellCmd::CellsUp && (rRange.aStart.Col() != 0 || rRange.aEnd.Col() != rDoc.MaxCol())) ||
+ (eCmd == DelCellCmd::CellsLeft && (rRange.aStart.Row() != 0 || rRange.aEnd.Row() != rDoc.MaxRow()))))
+ {
+ // We should not reach this via UI disabled slots.
+ assert(bApi);
+ SAL_WARN("sc.ui","ScDocFunc::DeleteCells - no change-tracking of partial cell shift");
+ return false;
+ }
+
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+
+ if ( !rDoc.ValidRow(nStartRow) || !rDoc.ValidRow(nEndRow) )
+ {
+ OSL_FAIL("invalid row in DeleteCells");
+ return false;
+ }
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCCOL nPaintStartCol = nStartCol;
+ SCROW nPaintStartRow = nStartRow;
+ SCCOL nPaintEndCol = nEndCol;
+ SCROW nPaintEndRow = nEndRow;
+ PaintPartFlags nPaintFlags = PaintPartFlags::Grid;
+
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ if (pTabMark)
+ aMark = *pTabMark;
+ else
+ {
+ SCTAB nCount = 0;
+ for(SCTAB i=0; i<nTabCount; i++ )
+ {
+ if( !rDoc.IsScenario(i) )
+ {
+ nCount++;
+ if( nCount == nEndTab+1 )
+ {
+ aMark.SelectTable(i, true);
+ break;
+ }
+ }
+ }
+ }
+
+ ScMarkData aFullMark( aMark ); // including scenario sheets
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ for( SCTAB j = rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ )
+ aFullMark.SelectTable( j, true );
+ }
+
+ SCTAB nSelCount = aMark.GetSelectCount();
+
+ SCCOL nUndoStartCol = nStartCol;
+ SCROW nUndoStartRow = nStartRow;
+ SCCOL nUndoEndCol = nEndCol;
+ SCROW nUndoEndRow = nEndRow;
+
+ ScRange aExtendMergeRange( rRange );
+
+ if( rRange.aStart == rRange.aEnd && rDoc.HasAttrib(rRange, HasAttrFlags::Merged) )
+ {
+ rDoc.ExtendMerge( aExtendMergeRange );
+ rDoc.ExtendOverlapped( aExtendMergeRange );
+ nUndoEndCol = aExtendMergeRange.aEnd.Col();
+ nUndoEndRow = aExtendMergeRange.aEnd.Row();
+ nPaintEndCol = nUndoEndCol;
+ nPaintEndRow = nUndoEndRow;
+ }
+
+ if (eCmd==DelCellCmd::Rows)
+ {
+ nUndoStartCol = 0;
+ nUndoEndCol = rDoc.MaxCol();
+ }
+ if (eCmd==DelCellCmd::Cols)
+ {
+ nUndoStartRow = 0;
+ nUndoEndRow = rDoc.MaxRow();
+ }
+ // Test for cell protection
+
+ SCCOL nEditTestEndX = nUndoEndCol;
+ if ( eCmd==DelCellCmd::Cols || eCmd==DelCellCmd::CellsLeft )
+ nEditTestEndX = rDoc.MaxCol();
+ SCROW nEditTestEndY = nUndoEndRow;
+ if ( eCmd==DelCellCmd::Rows || eCmd==DelCellCmd::CellsUp )
+ nEditTestEndY = rDoc.MaxRow();
+
+ ScEditableTester aTester;
+
+ switch (eCmd)
+ {
+ case DelCellCmd::Cols:
+ aTester = ScEditableTester(
+ rDoc, sc::ColRowEditAction::DeleteColumns, nUndoStartCol, nUndoEndCol, aMark);
+ break;
+ case DelCellCmd::Rows:
+ aTester = ScEditableTester(
+ rDoc, sc::ColRowEditAction::DeleteRows, nUndoStartRow, nUndoEndRow, aMark);
+ break;
+ default:
+ aTester = ScEditableTester(
+ rDoc, nUndoStartCol, nUndoStartRow, nEditTestEndX, nEditTestEndY, aMark);
+ }
+
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ if (!canDeleteCellsByPivot(rRange, aMark, eCmd, rDoc))
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_NO_INSERT_DELETE_OVER_PIVOT_TABLE);
+ return false;
+ }
+ // Test for merged cells
+
+ SCCOL nMergeTestEndCol = (eCmd==DelCellCmd::CellsLeft) ? rDoc.MaxCol() : nUndoEndCol;
+ SCROW nMergeTestEndRow = (eCmd==DelCellCmd::CellsUp) ? rDoc.MaxRow() : nUndoEndRow;
+ SCCOL nExtendStartCol = nUndoStartCol;
+ SCROW nExtendStartRow = nUndoStartRow;
+ bool bNeedRefresh = false;
+
+ //Issue 8302 want to be able to insert into the middle of merged cells
+ //the patch comes from maoyg
+ ::std::vector<ScRange> qDecreaseRange;
+ bool bDeletingMerge = false;
+ OUString aUndo = ScResId( STR_UNDO_DELETECELLS );
+ if (bRecord)
+ {
+ ViewShellId nViewShellId(-1);
+ if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
+ nViewShellId = pViewSh->GetViewShellId();
+ rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId );
+ }
+ std::unique_ptr<ScUndoRemoveMerge> pUndoRemoveMerge;
+
+ for (const SCTAB i : aMark)
+ {
+ if (i >= nTabCount)
+ break;
+
+ if ( rDoc.HasAttrib( nUndoStartCol, nUndoStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i, HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
+ {
+ SCCOL nMergeStartCol = nUndoStartCol;
+ SCROW nMergeStartRow = nUndoStartRow;
+ SCCOL nMergeEndCol = nMergeTestEndCol;
+ SCROW nMergeEndRow = nMergeTestEndRow;
+
+ rDoc.ExtendMerge( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i );
+ rDoc.ExtendOverlapped( nMergeStartCol, nMergeStartRow, nMergeEndCol, nMergeEndRow, i );
+ if( ( eCmd == DelCellCmd::CellsUp && ( nMergeStartCol != nUndoStartCol || nMergeEndCol != nMergeTestEndCol))||
+ ( eCmd == DelCellCmd::CellsLeft && ( nMergeStartRow != nUndoStartRow || nMergeEndRow != nMergeTestEndRow)))
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0);
+ rDocShell.GetUndoManager()->LeaveListAction();
+ return false;
+ }
+
+ nExtendStartCol = nMergeStartCol;
+ nExtendStartRow = nMergeStartRow;
+ SCCOL nTestCol = -1;
+ SCROW nTestRow1 = -1;
+ SCROW nTestRow2 = -1;
+
+ ScDocAttrIterator aTestIter( rDoc, i, nUndoStartCol, nUndoStartRow, nMergeTestEndCol, nMergeTestEndRow );
+ ScRange aExtendRange( nUndoStartCol, nUndoStartRow, i, nMergeTestEndCol, nMergeTestEndRow, i );
+ const ScPatternAttr* pPattern = nullptr;
+ while ( ( pPattern = aTestIter.GetNext( nTestCol, nTestRow1, nTestRow2 ) ) != nullptr )
+ {
+ const ScMergeAttr& rMergeFlag = pPattern->GetItem(ATTR_MERGE);
+ const ScMergeFlagAttr& rMergeFlagAttr = pPattern->GetItem(ATTR_MERGE_FLAG);
+ ScMF nNewFlags = rMergeFlagAttr.GetValue() & (ScMF::Hor | ScMF::Ver);
+ if (rMergeFlag.IsMerged() || nNewFlags == ScMF::Hor || nNewFlags == ScMF::Ver)
+ {
+ ScRange aRange( nTestCol, nTestRow1, i );
+ rDoc.ExtendOverlapped( aRange );
+ rDoc.ExtendMerge( aRange, true );
+
+ if( nTestRow1 < nTestRow2 && nNewFlags == ScMF::Hor )
+ {
+ for( SCROW nTestRow = nTestRow1; nTestRow <= nTestRow2; nTestRow++ )
+ {
+ ScRange aTestRange( nTestCol, nTestRow, i );
+ rDoc.ExtendOverlapped( aTestRange );
+ rDoc.ExtendMerge( aTestRange, true );
+ ScRange aMergeRange( aTestRange.aStart.Col(),aTestRange.aStart.Row(), i );
+ if( !aExtendRange.Contains( aMergeRange ) )
+ {
+ qDecreaseRange.push_back( aTestRange );
+ bDeletingMerge = true;
+ }
+ }
+ }
+ else
+ {
+ ScRange aMergeRange( aRange.aStart.Col(),aRange.aStart.Row(), i );
+ if( !aExtendRange.Contains( aMergeRange ) )
+ {
+ qDecreaseRange.push_back( aRange );
+ }
+ bDeletingMerge = true;
+ }
+ }
+ }
+
+ if( bDeletingMerge )
+ {
+
+ if( eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::CellsUp )
+ {
+ nStartRow = aExtendMergeRange.aStart.Row();
+ nEndRow = aExtendMergeRange.aEnd.Row();
+ bNeedRefresh = true;
+
+ if( eCmd == DelCellCmd::CellsUp )
+ {
+ nEndCol = aExtendMergeRange.aEnd.Col();
+ }
+ else
+ {
+ nStartCol = 0;
+ nEndCol = rDoc.MaxCol();
+ }
+ }
+ else if( eCmd == DelCellCmd::CellsLeft || eCmd == DelCellCmd::Cols )
+ {
+
+ nStartCol = aExtendMergeRange.aStart.Col();
+ nEndCol = aExtendMergeRange.aEnd.Col();
+ if( eCmd == DelCellCmd::CellsLeft )
+ {
+ nEndRow = aExtendMergeRange.aEnd.Row();
+ bNeedRefresh = true;
+ }
+ else
+ {
+ nStartRow = 0;
+ nEndRow = rDoc.MaxRow();
+ }
+ }
+
+ if( !qDecreaseRange.empty() )
+ {
+ if (bRecord && !pUndoRemoveMerge)
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, *aMark.begin(), *aMark.rbegin());
+ pUndoRemoveMerge.reset( new ScUndoRemoveMerge( &rDocShell, rRange, std::move(pUndoDoc) ));
+ }
+
+ for( const ScRange& aRange : qDecreaseRange )
+ {
+ if( rDoc.HasAttrib( aRange, HasAttrFlags::Overlapped | HasAttrFlags::Merged ) )
+ {
+ UnmergeCells( aRange, bRecord, pUndoRemoveMerge.get() );
+ }
+ }
+ }
+ }
+ else
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_MSSG_DELETECELLS_0);
+ rDocShell.GetUndoManager()->LeaveListAction();
+ return false;
+ }
+ }
+ }
+
+ if (bRecord && pUndoRemoveMerge)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction( std::move(pUndoRemoveMerge));
+ }
+
+ // do it
+
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
+
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScDocument> pRefUndoDoc;
+ std::unique_ptr<ScRefUndoData> pUndoData;
+ if ( bRecord )
+ {
+ // With the fix for #101329#, UpdateRef always puts cells into pRefUndoDoc at their old position,
+ // so it's no longer necessary to copy more than the deleted range into pUndoDoc.
+
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, 0, nTabCount-1, (eCmd==DelCellCmd::Cols), (eCmd==DelCellCmd::Rows) );
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ SCTAB nScenarioCount = 0;
+
+ for( SCTAB j = rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ )
+ nScenarioCount ++;
+
+ rDoc.CopyToDocument( nUndoStartCol, nUndoStartRow, rTab, nUndoEndCol, nUndoEndRow, rTab+nScenarioCount,
+ InsertDeleteFlags::ALL | InsertDeleteFlags::NOCAPTIONS, false, *pUndoDoc );
+ }
+
+ pRefUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pRefUndoDoc->InitUndo( rDoc, 0, nTabCount-1 );
+
+ pUndoData.reset(new ScRefUndoData( &rDoc ));
+
+ rDoc.BeginDrawUndo();
+ }
+
+ sal_uInt16 nExtFlags = 0;
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ rDocShell.UpdatePaintExt( nExtFlags, nStartCol, nStartRow, rTab, nEndCol, nEndRow, rTab );
+ }
+
+ switch (eCmd)
+ {
+ case DelCellCmd::CellsUp:
+ case DelCellCmd::CellsLeft:
+ rDoc.DeleteObjectsInArea(nStartCol, nStartRow, nEndCol, nEndRow, aMark, true);
+ break;
+ case DelCellCmd::Rows:
+ rDoc.DeleteObjectsInArea(0, nStartRow, rDoc.MaxCol(), nEndRow, aMark, true);
+ break;
+ case DelCellCmd::Cols:
+ rDoc.DeleteObjectsInArea(nStartCol, 0, nEndCol, rDoc.MaxRow(), aMark, true);
+ break;
+ default:
+ break;
+ }
+
+
+ bool bUndoOutline = false;
+ switch (eCmd)
+ {
+ case DelCellCmd::CellsUp:
+ rDoc.DeleteRow( nStartCol, 0, nEndCol, MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc.get(), nullptr, &aFullMark );
+ nPaintEndRow = rDoc.MaxRow();
+ break;
+ case DelCellCmd::Rows:
+ rDoc.DeleteRow( 0, 0, rDoc.MaxCol(), MAXTAB, nStartRow, static_cast<SCSIZE>(nEndRow-nStartRow+1), pRefUndoDoc.get(), &bUndoOutline, &aFullMark );
+ nPaintStartCol = 0;
+ nPaintEndCol = rDoc.MaxCol();
+ nPaintEndRow = rDoc.MaxRow();
+ nPaintFlags |= PaintPartFlags::Left;
+ break;
+ case DelCellCmd::CellsLeft:
+ rDoc.DeleteCol( nStartRow, 0, nEndRow, MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc.get(), nullptr, &aFullMark );
+ nPaintEndCol = rDoc.MaxCol();
+ break;
+ case DelCellCmd::Cols:
+ rDoc.DeleteCol( 0, 0, rDoc.MaxRow(), MAXTAB, nStartCol, static_cast<SCSIZE>(nEndCol-nStartCol+1), pRefUndoDoc.get(), &bUndoOutline, &aFullMark );
+ nPaintStartRow = 0;
+ nPaintEndRow = rDoc.MaxRow();
+ nPaintEndCol = rDoc.MaxCol();
+ nPaintFlags |= PaintPartFlags::Top;
+ break;
+ default:
+ OSL_FAIL("Wrong code at deleting");
+ break;
+ }
+
+ //! Test if the size of outline has changed
+
+ if ( bRecord )
+ {
+ for (const auto& rTab : aFullMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ pRefUndoDoc->DeleteAreaTab(nUndoStartCol,nUndoStartRow,nUndoEndCol,nUndoEndRow, rTab, InsertDeleteFlags::ALL);
+ }
+
+ // for all sheets, so that formulas can be copied
+ pUndoDoc->AddUndoTab( 0, nTabCount-1 );
+
+ // copy with bColRowFlags=false (#54194#)
+ pRefUndoDoc->CopyToDocument(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB,InsertDeleteFlags::FORMULA,false,*pUndoDoc,nullptr,false);
+ pRefUndoDoc.reset();
+
+ std::unique_ptr<SCTAB[]> pTabs( new SCTAB[nSelCount]);
+ std::unique_ptr<SCTAB[]> pScenarios( new SCTAB[nSelCount]);
+ SCTAB nUndoPos = 0;
+
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ SCTAB nCount = 0;
+ for( SCTAB j=rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ )
+ nCount ++;
+
+ pScenarios[nUndoPos] = nCount;
+ pTabs[nUndoPos] = rTab;
+ nUndoPos ++;
+ }
+
+ if( !bDeletingMerge )
+ {
+ rDocShell.GetUndoManager()->LeaveListAction();
+ }
+
+ rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoDeleteCells>(
+ &rDocShell, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ),
+ nUndoPos, std::move(pTabs), std::move(pScenarios),
+ eCmd, std::move(pUndoDoc), std::move(pUndoData) ) );
+ }
+
+ // #i8302 want to be able to insert into the middle of merged cells
+ // the patch comes from maoyg
+
+ while( !qDecreaseRange.empty() )
+ {
+ ScRange aRange = qDecreaseRange.back();
+
+ sal_Int32 nDecreaseRowCount = 0;
+ sal_Int32 nDecreaseColCount = 0;
+ if( eCmd == DelCellCmd::CellsUp || eCmd == DelCellCmd::Rows )
+ {
+ if( nStartRow >= aRange.aStart.Row() && nStartRow <= aRange.aEnd.Row() && nEndRow>= aRange.aStart.Row() && nEndRow <= aRange.aEnd.Row() )
+ nDecreaseRowCount = nEndRow-nStartRow+1;
+ else if( nStartRow >= aRange.aStart.Row() && nStartRow <= aRange.aEnd.Row() && nEndRow >= aRange.aStart.Row() && nEndRow >= aRange.aEnd.Row() )
+ nDecreaseRowCount = aRange.aEnd.Row()-nStartRow+1;
+ else if( nStartRow >= aRange.aStart.Row() && nStartRow >= aRange.aEnd.Row() && nEndRow>= aRange.aStart.Row() && nEndRow <= aRange.aEnd.Row() )
+ nDecreaseRowCount = aRange.aEnd.Row()-nEndRow+1;
+ }
+ else if( eCmd == DelCellCmd::CellsLeft || eCmd == DelCellCmd::Cols )
+ {
+ if( nStartCol >= aRange.aStart.Col() && nStartCol <= aRange.aEnd.Col() && nEndCol>= aRange.aStart.Col() && nEndCol <= aRange.aEnd.Col() )
+ nDecreaseColCount = nEndCol-nStartCol+1;
+ else if( nStartCol >= aRange.aStart.Col() && nStartCol <= aRange.aEnd.Col() && nEndCol >= aRange.aStart.Col() && nEndCol >= aRange.aEnd.Col() )
+ nDecreaseColCount = aRange.aEnd.Col()-nStartCol+1;
+ else if( nStartCol >= aRange.aStart.Col() && nStartCol >= aRange.aEnd.Col() && nEndCol>= aRange.aStart.Col() && nEndCol <= aRange.aEnd.Col() )
+ nDecreaseColCount = aRange.aEnd.Col()-nEndCol+1;
+ }
+
+ switch (eCmd)
+ {
+ case DelCellCmd::CellsUp:
+ case DelCellCmd::Rows:
+ aRange.aEnd.SetRow(static_cast<SCCOL>( aRange.aEnd.Row()-nDecreaseRowCount));
+ break;
+ case DelCellCmd::CellsLeft:
+ case DelCellCmd::Cols:
+ aRange.aEnd.SetCol(static_cast<SCCOL>( aRange.aEnd.Col()-nDecreaseColCount));
+ break;
+ default:
+ break;
+ }
+
+ if( !rDoc.HasAttrib( aRange, HasAttrFlags::Overlapped | HasAttrFlags::Merged ) )
+ {
+ ScCellMergeOption aMergeOption(aRange);
+ MergeCells( aMergeOption, false, true, true );
+ }
+ qDecreaseRange.pop_back();
+ }
+
+ if( bDeletingMerge )
+ rDocShell.GetUndoManager()->LeaveListAction();
+
+ if ( eCmd==DelCellCmd::Cols || eCmd==DelCellCmd::CellsLeft )
+ nMergeTestEndCol = rDoc.MaxCol();
+ if ( eCmd==DelCellCmd::Rows || eCmd==DelCellCmd::CellsUp )
+ nMergeTestEndRow = rDoc.MaxRow();
+ if ( bNeedRefresh )
+ {
+ // #i51445# old merge flag attributes must be deleted also for single cells,
+ // not only for whole columns/rows
+
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( ScMergeFlagAttr() );
+
+ rDoc.ApplyPatternArea( nExtendStartCol, nExtendStartRow, nMergeTestEndCol, nMergeTestEndRow, aMark, aPattern );
+
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ SCTAB nScenarioCount = 0;
+
+ for( SCTAB j = rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ )
+ nScenarioCount ++;
+
+ ScRange aMergedRange( nExtendStartCol, nExtendStartRow, rTab, nMergeTestEndCol, nMergeTestEndRow, rTab+nScenarioCount );
+ rDoc.ExtendMerge( aMergedRange, true );
+ }
+ }
+
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ rDoc.RefreshAutoFilter( nExtendStartCol, nExtendStartRow, nMergeTestEndCol, nMergeTestEndRow, rTab );
+ }
+
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ rDoc.SetDrawPageSize(rTab);
+
+ if ( eCmd == DelCellCmd::Cols || eCmd == DelCellCmd::Rows )
+ rDoc.UpdatePageBreaks( rTab );
+
+ rDocShell.UpdatePaintExt( nExtFlags, nPaintStartCol, nPaintStartRow, rTab, nPaintEndCol, nPaintEndRow, rTab );
+
+ SCTAB nScenarioCount = 0;
+
+ for( SCTAB j = rTab+1; j<nTabCount && rDoc.IsScenario(j); j++ )
+ nScenarioCount ++;
+
+ // delete entire rows: do not adjust
+ if ( eCmd == DelCellCmd::Rows || !AdjustRowHeight(ScRange( 0, nPaintStartRow, rTab, rDoc.MaxCol(), nPaintEndRow, rTab+nScenarioCount ), true, bApi) )
+ rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, rTab, nPaintEndCol, nPaintEndRow, rTab+nScenarioCount, nPaintFlags, nExtFlags );
+ else
+ {
+ // paint only what is not done by AdjustRowHeight
+ if (nExtFlags & SC_PF_LINES)
+ lcl_PaintAbove( rDocShell, ScRange( nPaintStartCol, nPaintStartRow, rTab, nPaintEndCol, nPaintEndRow, rTab+nScenarioCount) );
+ if (nPaintFlags & PaintPartFlags::Top)
+ rDocShell.PostPaint( nPaintStartCol, nPaintStartRow, rTab, nPaintEndCol, nPaintEndRow, rTab+nScenarioCount, PaintPartFlags::Top );
+ }
+ }
+
+ // The cursor position needs to be modified earlier than updating
+ // any enabled edit view which is triggered by SetDocumentModified below.
+ ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
+ if (pViewSh)
+ {
+ if (eCmd == DelCellCmd::Cols)
+ {
+ pViewSh->OnLOKInsertDeleteColumn(rRange.aStart.Col(), -1);
+ }
+ if (eCmd == DelCellCmd::Rows)
+ {
+ pViewSh->OnLOKInsertDeleteRow(rRange.aStart.Row(), -1);
+ }
+ }
+
+ aModificator.SetDocumentModified();
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+
+ return true;
+}
+
+bool ScDocFunc::MoveBlock( const ScRange& rSource, const ScAddress& rDestPos,
+ bool bCut, bool bRecord, bool bPaint, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ SCCOL nStartCol = rSource.aStart.Col();
+ SCROW nStartRow = rSource.aStart.Row();
+ SCTAB nStartTab = rSource.aStart.Tab();
+ SCCOL nEndCol = rSource.aEnd.Col();
+ SCROW nEndRow = rSource.aEnd.Row();
+ SCTAB nEndTab = rSource.aEnd.Tab();
+ SCCOL nDestCol = rDestPos.Col();
+ SCROW nDestRow = rDestPos.Row();
+ SCTAB nDestTab = rDestPos.Tab();
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if ( !rDoc.ValidRow(nStartRow) || !rDoc.ValidRow(nEndRow) || !rDoc.ValidRow(nDestRow) )
+ {
+ OSL_FAIL("invalid row in MoveBlock");
+ return false;
+ }
+
+ // adjust related scenarios too - but only when moved within one sheet
+ bool bScenariosAdded = false;
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ if ( nDestTab == nStartTab && !rDoc.IsScenario(nEndTab) )
+ while ( nEndTab+1 < nTabCount && rDoc.IsScenario(nEndTab+1) )
+ {
+ ++nEndTab;
+ bScenariosAdded = true;
+ }
+
+ SCTAB nSrcTabCount = nEndTab-nStartTab+1;
+ SCTAB nDestEndTab = nDestTab+nSrcTabCount-1;
+ SCTAB nTab;
+
+ ScDocumentUniquePtr pClipDoc(new ScDocument(SCDOCMODE_CLIP));
+
+ ScMarkData aSourceMark(rDoc.GetSheetLimits());
+ for (nTab=nStartTab; nTab<=nEndTab; nTab++)
+ aSourceMark.SelectTable( nTab, true ); // select source
+ aSourceMark.SetMarkArea( rSource );
+
+ ScDocShellRef aDragShellRef;
+ if ( rDoc.HasOLEObjectsInArea( rSource ) )
+ {
+ aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately
+ aDragShellRef->DoInitNew();
+ }
+ ScDrawLayer::SetGlobalDrawPersist( aDragShellRef.get() );
+
+ ScClipParam aClipParam(ScRange(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nStartTab), bCut);
+ rDoc.CopyToClip(aClipParam, pClipDoc.get(), &aSourceMark, bScenariosAdded, true);
+
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+
+ SCCOL nOldEndCol = nEndCol;
+ SCROW nOldEndRow = nEndRow;
+ bool bClipOver = false;
+ for (nTab=nStartTab; nTab<=nEndTab; nTab++)
+ {
+ SCCOL nTmpEndCol = nOldEndCol;
+ SCROW nTmpEndRow = nOldEndRow;
+ if (rDoc.ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab ))
+ bClipOver = true;
+ if ( nTmpEndCol > nEndCol ) nEndCol = nTmpEndCol;
+ if ( nTmpEndRow > nEndRow ) nEndRow = nTmpEndRow;
+ }
+
+ SCCOL nDestEndCol = nDestCol + ( nOldEndCol-nStartCol );
+ SCROW nDestEndRow = nDestRow + ( nOldEndRow-nStartRow );
+
+ SCCOL nUndoEndCol = nDestCol + ( nEndCol-nStartCol ); // extended in destination block
+ SCROW nUndoEndRow = nDestRow + ( nEndRow-nStartRow );
+
+ bool bIncludeFiltered = bCut;
+ if ( !bIncludeFiltered )
+ {
+ // adjust sizes to include only non-filtered rows
+
+ SCCOL nClipX;
+ SCROW nClipY;
+ pClipDoc->GetClipArea( nClipX, nClipY, false );
+ SCROW nUndoAdd = nUndoEndRow - nDestEndRow;
+ nDestEndRow = nDestRow + nClipY;
+ nUndoEndRow = nDestEndRow + nUndoAdd;
+ }
+
+ if (!rDoc.ValidCol(nUndoEndCol) || !rDoc.ValidRow(nUndoEndRow))
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PASTE_FULL);
+ return false;
+ }
+
+ // Test for cell protection
+
+ ScEditableTester aTester;
+ for (nTab=nDestTab; nTab<=nDestEndTab; nTab++)
+ aTester.TestBlock( rDoc, nTab, nDestCol,nDestRow, nUndoEndCol,nUndoEndRow );
+ if (bCut)
+ for (nTab=nStartTab; nTab<=nEndTab; nTab++)
+ aTester.TestBlock( rDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow );
+
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ // Test for merged cells- when moving after delete
+
+ if (bClipOver && !bCut)
+ if (rDoc.HasAttrib( nDestCol,nDestRow,nDestTab, nUndoEndCol,nUndoEndRow,nDestEndTab,
+ HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
+ { // "Merge of already merged cells not possible"
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_MSSG_MOVEBLOCKTO_0);
+ return false;
+ }
+
+ // Are there borders in the cells? (for painting)
+
+ sal_uInt16 nSourceExt = 0;
+ rDocShell.UpdatePaintExt( nSourceExt, nStartCol,nStartRow,nStartTab, nEndCol,nEndRow,nEndTab );
+ sal_uInt16 nDestExt = 0;
+ rDocShell.UpdatePaintExt( nDestExt, nDestCol,nDestRow,nDestTab, nDestEndCol,nDestEndRow,nDestEndTab );
+
+ // do it
+
+ ScDocumentUniquePtr pUndoDoc;
+
+ if (bRecord)
+ {
+ bool bWholeCols = ( nStartRow == 0 && nEndRow == rDoc.MaxRow() );
+ bool bWholeRows = ( nStartCol == 0 && nEndCol == rDoc.MaxCol() );
+ InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
+
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab, bWholeCols, bWholeRows );
+
+ if (bCut)
+ {
+ rDoc.CopyToDocument( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
+ nUndoFlags, false, *pUndoDoc );
+ }
+
+ if ( nDestTab != nStartTab )
+ pUndoDoc->AddUndoTab( nDestTab, nDestEndTab, bWholeCols, bWholeRows );
+ rDoc.CopyToDocument( nDestCol, nDestRow, nDestTab,
+ nDestEndCol, nDestEndRow, nDestEndTab,
+ nUndoFlags, false, *pUndoDoc );
+ rDoc.BeginDrawUndo();
+ }
+
+ bool bSourceHeight = false; // adjust heights?
+ if (bCut)
+ {
+ ScMarkData aDelMark(rDoc.GetSheetLimits()); // only for tables
+ for (nTab=nStartTab; nTab<=nEndTab; nTab++)
+ {
+ rDoc.DeleteAreaTab( nStartCol,nStartRow, nOldEndCol,nOldEndRow, nTab, InsertDeleteFlags::ALL );
+ aDelMark.SelectTable( nTab, true );
+ }
+ rDoc.DeleteObjectsInArea( nStartCol,nStartRow, nOldEndCol,nOldEndRow, aDelMark );
+
+ // Test for merged cells
+
+ if (bClipOver)
+ if (rDoc.HasAttrib( nDestCol,nDestRow,nDestTab,
+ nUndoEndCol,nUndoEndRow,nDestEndTab,
+ HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
+ {
+ rDoc.CopyFromClip( rSource, aSourceMark, InsertDeleteFlags::ALL, nullptr, pClipDoc.get() );
+ for (nTab=nStartTab; nTab<=nEndTab; nTab++)
+ {
+ SCCOL nTmpEndCol = nEndCol;
+ SCROW nTmpEndRow = nEndRow;
+ rDoc.ExtendMerge( nStartCol, nStartRow, nTmpEndCol, nTmpEndRow, nTab, true );
+ }
+
+ // Report error only after restoring content
+ if (!bApi) // "Merge of already merged cells not possible"
+ rDocShell.ErrorMessage(STR_MSSG_MOVEBLOCKTO_0);
+
+ return false;
+ }
+
+ bSourceHeight = AdjustRowHeight( rSource, false, bApi );
+ }
+
+ ScRange aPasteDest( nDestCol, nDestRow, nDestTab, nDestEndCol, nDestEndRow, nDestEndTab );
+
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ for (nTab=nDestTab; nTab<=nDestEndTab; nTab++)
+ aDestMark.SelectTable( nTab, true ); // select destination
+ aDestMark.SetMarkArea( aPasteDest );
+
+ /* Do not copy drawing objects here. While pasting, the
+ function ScDocument::UpdateReference() is called which calls
+ ScDrawLayer::MoveCells() which may move away inserted objects to wrong
+ positions (e.g. if source and destination range overlaps).*/
+
+ rDoc.CopyFromClip(
+ aPasteDest, aDestMark, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS,
+ pUndoDoc.get(), pClipDoc.get(), true, false, bIncludeFiltered);
+
+ // skipped rows and merged cells don't mix
+ if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
+ UnmergeCells( aPasteDest, false, nullptr );
+
+ bool bDestHeight = AdjustRowHeight(
+ ScRange( 0,nDestRow,nDestTab, rDoc.MaxCol(),nDestEndRow,nDestEndTab ),
+ false, bApi );
+
+ /* Paste drawing objects after adjusting formula references
+ and row heights. There are no cell notes or drawing objects, if the
+ clipdoc does not contain a drawing layer.*/
+ if ( pClipDoc->GetDrawLayer() )
+ rDoc.CopyFromClip( aPasteDest, aDestMark, InsertDeleteFlags::OBJECTS,
+ nullptr, pClipDoc.get(), true, false, bIncludeFiltered );
+
+ if (bRecord)
+ {
+ ScRange aUndoRange(nStartCol, nStartRow, nStartTab, nOldEndCol, nOldEndRow, nEndTab);
+ ScAddress aDestPos(nDestCol, nDestRow, nDestTab);
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDragDrop>(
+ &rDocShell, aUndoRange, aDestPos, bCut, std::move(pUndoDoc), bScenariosAdded));
+ }
+
+ SCCOL nDestPaintEndCol = nDestEndCol;
+ SCROW nDestPaintEndRow = nDestEndRow;
+ for (nTab=nDestTab; nTab<=nDestEndTab; nTab++)
+ {
+ SCCOL nTmpEndCol = nDestEndCol;
+ SCROW nTmpEndRow = nDestEndRow;
+ rDoc.ExtendMerge( nDestCol, nDestRow, nTmpEndCol, nTmpEndRow, nTab, true );
+ if (nTmpEndCol > nDestPaintEndCol) nDestPaintEndCol = nTmpEndCol;
+ if (nTmpEndRow > nDestPaintEndRow) nDestPaintEndRow = nTmpEndRow;
+ }
+
+ if (bCut)
+ for (nTab=nStartTab; nTab<=nEndTab; nTab++)
+ rDoc.RefreshAutoFilter( nStartCol, nStartRow, nEndCol, nEndRow, nTab );
+
+ if (bPaint)
+ {
+ // destination range:
+
+ SCCOL nPaintStartX = nDestCol;
+ SCROW nPaintStartY = nDestRow;
+ SCCOL nPaintEndX = nDestPaintEndCol;
+ SCROW nPaintEndY = nDestPaintEndRow;
+ PaintPartFlags nFlags = PaintPartFlags::Grid;
+
+ if ( nStartRow==0 && nEndRow==rDoc.MaxRow() ) // copy widths too?
+ {
+ nPaintEndX = rDoc.MaxCol();
+ nPaintStartY = 0;
+ nPaintEndY = rDoc.MaxRow();
+ nFlags |= PaintPartFlags::Top;
+ }
+ if ( bDestHeight || ( nStartCol == 0 && nEndCol == rDoc.MaxCol() ) )
+ {
+ nPaintEndY = rDoc.MaxRow();
+ nPaintStartX = 0;
+ nPaintEndX = rDoc.MaxCol();
+ nFlags |= PaintPartFlags::Left;
+ }
+ if ( bScenariosAdded )
+ {
+ nPaintStartX = 0;
+ nPaintStartY = 0;
+ nPaintEndX = rDoc.MaxCol();
+ nPaintEndY = rDoc.MaxRow();
+ }
+
+ rDocShell.PostPaint( nPaintStartX,nPaintStartY,nDestTab,
+ nPaintEndX,nPaintEndY,nDestEndTab, nFlags, nSourceExt | nDestExt );
+
+ if ( bCut )
+ {
+ // source range:
+
+ nPaintStartX = nStartCol;
+ nPaintStartY = nStartRow;
+ nPaintEndX = nEndCol;
+ nPaintEndY = nEndRow;
+ nFlags = PaintPartFlags::Grid;
+
+ if ( bSourceHeight )
+ {
+ nPaintEndY = rDoc.MaxRow();
+ nPaintStartX = 0;
+ nPaintEndX = rDoc.MaxCol();
+ nFlags |= PaintPartFlags::Left;
+ }
+ if ( bScenariosAdded )
+ {
+ nPaintStartX = 0;
+ nPaintStartY = 0;
+ nPaintEndX = rDoc.MaxCol();
+ nPaintEndY = rDoc.MaxRow();
+ }
+
+ rDocShell.PostPaint( nPaintStartX,nPaintStartY,nStartTab,
+ nPaintEndX,nPaintEndY,nEndTab, nFlags, nSourceExt );
+ }
+ }
+
+ aModificator.SetDocumentModified();
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+
+ return true;
+}
+
+static uno::Reference< uno::XInterface > GetDocModuleObject( const SfxObjectShell& rDocSh, const OUString& sCodeName )
+{
+ uno::Reference< lang::XMultiServiceFactory> xSF(rDocSh.GetModel(), uno::UNO_QUERY);
+ uno::Reference< container::XNameAccess > xVBACodeNamedObjectAccess;
+ uno::Reference< uno::XInterface > xDocModuleApiObject;
+ if ( xSF.is() )
+ {
+ xVBACodeNamedObjectAccess.set( xSF->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), uno::UNO_QUERY );
+ xDocModuleApiObject.set( xVBACodeNamedObjectAccess->getByName( sCodeName ), uno::UNO_QUERY );
+ }
+ return xDocModuleApiObject;
+
+}
+
+static script::ModuleInfo lcl_InitModuleInfo( const SfxObjectShell& rDocSh, const OUString& sModule )
+{
+ script::ModuleInfo sModuleInfo;
+ sModuleInfo.ModuleType = script::ModuleType::DOCUMENT;
+ sModuleInfo.ModuleObject = GetDocModuleObject( rDocSh, sModule );
+ return sModuleInfo;
+}
+
+void VBA_InsertModule( ScDocument& rDoc, SCTAB nTab, const OUString& sSource )
+{
+ SfxObjectShell& rDocSh = *rDoc.GetDocumentShell();
+ uno::Reference< script::XLibraryContainer > xLibContainer = rDocSh.GetBasicContainer();
+ OSL_ENSURE( xLibContainer.is(), "No BasicContainer!" );
+
+ uno::Reference< container::XNameContainer > xLib;
+ if( xLibContainer.is() )
+ {
+ OUString aLibName( "Standard" );
+#if HAVE_FEATURE_SCRIPTING
+ if ( rDocSh.GetBasicManager() && !rDocSh.GetBasicManager()->GetName().isEmpty() )
+ {
+ aLibName = rDocSh.GetBasicManager()->GetName();
+ }
+#endif
+ uno::Any aLibAny = xLibContainer->getByName( aLibName );
+ aLibAny >>= xLib;
+ }
+ if( !xLib.is() )
+ return;
+
+ // if the Module with codename exists then find a new name
+ sal_Int32 nNum = 1;
+ OUString genModuleName = "Sheet1";
+ while( xLib->hasByName( genModuleName ) )
+ genModuleName = "Sheet" + OUString::number( ++nNum );
+
+ uno::Any aSourceAny;
+ OUString sTmpSource = sSource;
+ if ( sTmpSource.isEmpty() )
+ sTmpSource = "Rem Attribute VBA_ModuleType=VBADocumentModule\nOption VBASupport 1\n";
+ aSourceAny <<= sTmpSource;
+ uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY );
+ if ( xVBAModuleInfo.is() )
+ {
+ rDoc.SetCodeName( nTab, genModuleName );
+ script::ModuleInfo sModuleInfo = lcl_InitModuleInfo( rDocSh, genModuleName );
+ xVBAModuleInfo->insertModuleInfo( genModuleName, sModuleInfo );
+ xLib->insertByName( genModuleName, aSourceAny );
+ }
+}
+
+void VBA_DeleteModule( ScDocShell& rDocSh, const OUString& sModuleName )
+{
+ uno::Reference< script::XLibraryContainer > xLibContainer = rDocSh.GetBasicContainer();
+ OSL_ENSURE( xLibContainer.is(), "No BasicContainer!" );
+
+ uno::Reference< container::XNameContainer > xLib;
+ if( xLibContainer.is() )
+ {
+ OUString aLibName( "Standard" );
+#if HAVE_FEATURE_SCRIPTING
+ if ( rDocSh.GetBasicManager() && !rDocSh.GetBasicManager()->GetName().isEmpty() )
+ {
+ aLibName = rDocSh.GetBasicManager()->GetName();
+ }
+#endif
+ uno::Any aLibAny = xLibContainer->getByName( aLibName );
+ aLibAny >>= xLib;
+ }
+ if( xLib.is() )
+ {
+ uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY );
+ if( xLib->hasByName( sModuleName ) )
+ xLib->removeByName( sModuleName );
+ if ( xVBAModuleInfo.is() && xVBAModuleInfo->hasModuleInfo(sModuleName) )
+ xVBAModuleInfo->removeModuleInfo( sModuleName );
+
+ }
+}
+
+bool ScDocFunc::InsertTable( SCTAB nTab, const OUString& rName, bool bRecord, bool bApi )
+{
+ bool bSuccess = false;
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ // Strange loop, also basic is loaded too early ( InsertTable )
+ // is called via the xml import for sheets in described in ODF
+ bool bInsertDocModule = false;
+
+ if( !rDocShell.GetDocument().IsImportingXML() )
+ {
+ bInsertDocModule = rDoc.IsInVBAMode();
+ }
+ if ( bInsertDocModule || ( bRecord && !rDoc.IsUndoEnabled() ) )
+ bRecord = false;
+
+ if (bRecord)
+ rDoc.BeginDrawUndo(); // InsertTab generates SdrUndoNewPage
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ bool bAppend = ( nTab >= nTabCount );
+ if ( bAppend )
+ nTab = nTabCount; // important for Undo
+
+ if (rDoc.InsertTab( nTab, rName ))
+ {
+ if (bRecord)
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoInsertTab>( &rDocShell, nTab, bAppend, rName));
+ // Update views:
+ // Only insert vba modules if vba mode ( and not currently importing XML )
+ if( bInsertDocModule )
+ {
+ VBA_InsertModule( rDoc, nTab, OUString() );
+ }
+ rDocShell.Broadcast( ScTablesHint( SC_TAB_INSERTED, nTab ) );
+
+ rDocShell.PostPaintExtras();
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ bSuccess = true;
+ }
+ else if (!bApi)
+ rDocShell.ErrorMessage(STR_TABINSERT_ERROR);
+
+ return bSuccess;
+}
+
+bool ScDocFunc::DeleteTable( SCTAB nTab, bool bRecord )
+{
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ bool bSuccess = false;
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bVbaEnabled = rDoc.IsInVBAMode();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ if ( bVbaEnabled )
+ bRecord = false;
+ bool bWasLinked = rDoc.IsLinked(nTab);
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScRefUndoData> pUndoData;
+ if (bRecord)
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ SCTAB nCount = rDoc.GetTableCount();
+
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true ); // only nTab with Flags
+ pUndoDoc->AddUndoTab( 0, nCount-1 ); // all sheets for references
+
+ rDoc.CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::ALL,false, *pUndoDoc );
+ OUString aOldName;
+ rDoc.GetName( nTab, aOldName );
+ pUndoDoc->RenameTab( nTab, aOldName );
+ if (bWasLinked)
+ pUndoDoc->SetLink( nTab, rDoc.GetLinkMode(nTab), rDoc.GetLinkDoc(nTab),
+ rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab),
+ rDoc.GetLinkTab(nTab),
+ rDoc.GetLinkRefreshDelay(nTab) );
+
+ if ( rDoc.IsScenario(nTab) )
+ {
+ pUndoDoc->SetScenario( nTab, true );
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ rDoc.GetScenarioData( nTab, aComment, aColor, nScenFlags );
+ pUndoDoc->SetScenarioData( nTab, aComment, aColor, nScenFlags );
+ bool bActive = rDoc.IsActiveScenario( nTab );
+ pUndoDoc->SetActiveScenario( nTab, bActive );
+ }
+ pUndoDoc->SetVisible( nTab, rDoc.IsVisible( nTab ) );
+ pUndoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) );
+ auto pSheetEvents = rDoc.GetSheetEvents( nTab );
+ pUndoDoc->SetSheetEvents( nTab, std::unique_ptr<ScSheetEvents>(pSheetEvents ? new ScSheetEvents(*pSheetEvents) : nullptr) );
+
+ // Drawing-Layer has to take care of its own undo!!!
+ rDoc.BeginDrawUndo(); // DeleteTab generates SdrUndoDelPage
+
+ pUndoData.reset(new ScRefUndoData( &rDoc ));
+ }
+
+ if (rDoc.DeleteTab(nTab))
+ {
+ if (bRecord)
+ {
+ vector<SCTAB> theTabs;
+ theTabs.push_back(nTab);
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDeleteTab>( &rDocShell, theTabs, std::move(pUndoDoc), std::move(pUndoData) ));
+ }
+ // Update views:
+ if( bVbaEnabled )
+ {
+ OUString sCodeName;
+ if( rDoc.GetCodeName( nTab, sCodeName ) )
+ {
+ VBA_DeleteModule( rDocShell, sCodeName );
+ }
+ }
+ rDocShell.Broadcast( ScTablesHint( SC_TAB_DELETED, nTab ) );
+
+ if (bWasLinked)
+ {
+ rDocShell.UpdateLinks(); // update Link-Manager
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate(SID_LINKS);
+ }
+
+ rDocShell.PostPaintExtras();
+ aModificator.SetDocumentModified();
+
+ SfxApplication* pSfxApp = SfxGetpApp(); // Navigator
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+
+ bSuccess = true;
+ }
+ return bSuccess;
+}
+
+void ScDocFunc::SetTableVisible( SCTAB nTab, bool bVisible, bool bApi )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+ if ( rDoc.IsVisible( nTab ) == bVisible )
+ return; // nothing to do - ok
+
+ if ( !rDoc.IsDocEditable() )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ if ( !bVisible && !rDoc.IsImportingXML() ) // #i57869# allow hiding in any order for loading
+ {
+ // do not disable all sheets
+
+ sal_uInt16 nVisCount = 0;
+ SCTAB nCount = rDoc.GetTableCount();
+ for (SCTAB i=0; i<nCount && nVisCount<2; i++)
+ if (rDoc.IsVisible(i))
+ ++nVisCount;
+
+ if (nVisCount <= 1)
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PROTECTIONERR); //! separate error message?
+ return;
+ }
+ }
+
+ rDoc.SetVisible( nTab, bVisible );
+ if (bUndo)
+ {
+ std::vector<SCTAB> undoTabs { nTab };
+ rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideTab>( &rDocShell, std::move(undoTabs), bVisible ) );
+ }
+
+ // update views
+ if (!bVisible)
+ rDocShell.Broadcast( ScTablesHint( SC_TAB_HIDDEN, nTab ) );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ rDocShell.PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Extras);
+ aModificator.SetDocumentModified();
+}
+
+bool ScDocFunc::SetLayoutRTL( SCTAB nTab, bool bRTL )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+ if ( rDoc.IsLayoutRTL( nTab ) == bRTL )
+ return true; // nothing to do - ok
+
+ //! protection (sheet or document?)
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ rDoc.SetLayoutRTL( nTab, bRTL, ScObjectHandling::MirrorRTLMode);
+
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoLayoutRTL>( &rDocShell, nTab, bRTL ) );
+ }
+
+ rDocShell.PostPaint( 0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::All );
+ aModificator.SetDocumentModified();
+
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( FID_TAB_RTL );
+ pBindings->Invalidate( SID_ATTR_SIZE );
+ }
+
+ return true;
+}
+
+bool ScDocFunc::RenameTable( SCTAB nTab, const OUString& rName, bool bRecord, bool bApi )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ if ( !rDoc.IsDocEditable() )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PROTECTIONERR);
+ return false;
+ }
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ bool bSuccess = false;
+ OUString sOldName;
+ rDoc.GetName(nTab, sOldName);
+ if (rDoc.RenameTab( nTab, rName ))
+ {
+ if (bRecord)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRenameTab>( &rDocShell, nTab, sOldName, rName));
+ }
+ rDocShell.PostPaintExtras();
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+
+ bSuccess = true;
+ }
+ return bSuccess;
+}
+
+bool ScDocFunc::SetTabBgColor( SCTAB nTab, const Color& rColor, bool bRecord, bool bApi )
+{
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ if ( !rDoc.IsDocEditable() || rDoc.IsTabProtected(nTab) )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Check to see what this string is...
+ return false;
+ }
+
+ Color aOldTabBgColor = rDoc.GetTabBgColor(nTab);
+
+ bool bSuccess = false;
+ rDoc.SetTabBgColor(nTab, rColor);
+ if ( rDoc.GetTabBgColor(nTab) == rColor)
+ bSuccess = true;
+ if (bSuccess)
+ {
+ if (bRecord)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoTabColor>( &rDocShell, nTab, aOldTabBgColor, rColor));
+ }
+ rDocShell.PostPaintExtras();
+ ScDocShellModificator aModificator( rDocShell );
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+
+ bSuccess = true;
+ }
+ return bSuccess;
+}
+
+bool ScDocFunc::SetTabBgColor(
+ ScUndoTabColorInfo::List& rUndoTabColorList, bool bApi )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ if ( !rDoc.IsDocEditable() )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Get a better String Error...
+ return false;
+ }
+
+ sal_uInt16 nTab;
+ Color aNewTabBgColor;
+ bool bSuccess = true;
+ size_t nTabProtectCount = 0;
+ size_t nTabListCount = rUndoTabColorList.size();
+ for ( size_t i = 0; i < nTabListCount; ++i )
+ {
+ ScUndoTabColorInfo& rInfo = rUndoTabColorList[i];
+ nTab = rInfo.mnTabId;
+ if ( !rDoc.IsTabProtected(nTab) )
+ {
+ aNewTabBgColor = rInfo.maNewTabBgColor;
+ rInfo.maOldTabBgColor = rDoc.GetTabBgColor(nTab);
+ rDoc.SetTabBgColor(nTab, aNewTabBgColor);
+ if ( rDoc.GetTabBgColor(nTab) != aNewTabBgColor)
+ {
+ bSuccess = false;
+ break;
+ }
+ }
+ else
+ {
+ nTabProtectCount++;
+ }
+ }
+
+ if ( nTabProtectCount == nTabListCount )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PROTECTIONERR); //TODO Get a better String Error...
+ return false;
+ }
+
+ if (bSuccess)
+ {
+ if (bRecord)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoTabColor>( &rDocShell, std::vector(rUndoTabColorList)));
+ }
+ rDocShell.PostPaintExtras();
+ ScDocShellModificator aModificator( rDocShell );
+ aModificator.SetDocumentModified();
+ }
+ return bSuccess;
+}
+
+//! SetWidthOrHeight - duplicated in ViewFunc !!!!!!
+//! Problems:
+//! - Optimal height of text cells is different for a printer and a screen
+//! - Optimal width needs a selection in order to take only selected cells into account
+
+static sal_uInt16 lcl_GetOptimalColWidth( ScDocShell& rDocShell, SCCOL nCol, SCTAB nTab )
+{
+ ScSizeDeviceProvider aProv(&rDocShell);
+ OutputDevice* pDev = aProv.GetDevice(); // has pixel MapMode
+ double nPPTX = aProv.GetPPTX();
+ double nPPTY = aProv.GetPPTY();
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ Fraction aOne(1,1);
+ sal_uInt16 nTwips = rDoc.GetOptimalColWidth( nCol, nTab, pDev, nPPTX, nPPTY, aOne, aOne,
+ false/*bFormula*/ );
+
+ return nTwips;
+}
+
+bool ScDocFunc::SetWidthOrHeight(
+ bool bWidth, const std::vector<sc::ColRowSpan>& rRanges, SCTAB nTab,
+ ScSizeMode eMode, sal_uInt16 nSizeTwips, bool bRecord, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ if (rRanges.empty())
+ return true;
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if ( bRecord && !rDoc.IsUndoEnabled() )
+ bRecord = false;
+
+ // import into read-only document is possible
+ if ( !rDoc.IsChangeReadOnlyEnabled() && !rDocShell.IsEditable() )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_PROTECTIONERR); //! separate error message?
+ return false;
+ }
+
+ SCCOLROW nStart = rRanges[0].mnStart;
+ SCCOLROW nEnd = rRanges[0].mnEnd;
+
+ if ( eMode == SC_SIZE_OPTIMAL )
+ {
+ //! Option "Show formulas" - but where to get them from?
+ }
+
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScOutlineTable> pUndoTab;
+ std::vector<sc::ColRowSpan> aUndoRanges;
+
+ if ( bRecord )
+ {
+ rDoc.BeginDrawUndo(); // Drawing Updates
+
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ if (bWidth)
+ {
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true );
+ rDoc.CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab, static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
+ }
+ else
+ {
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
+ rDoc.CopyToDocument( 0, static_cast<SCROW>(nStart), nTab, rDoc.MaxCol(), static_cast<SCROW>(nEnd), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
+ }
+
+ aUndoRanges = rRanges;
+
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+ if (pTable)
+ pUndoTab.reset(new ScOutlineTable( *pTable ));
+ }
+
+ bool bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT;
+ bool bOutline = false;
+
+ for (const sc::ColRowSpan& rRange : rRanges)
+ {
+ SCCOLROW nStartNo = rRange.mnStart;
+ SCCOLROW nEndNo = rRange.mnEnd;
+
+ if ( !bWidth ) // deal with heights always in blocks
+ {
+ if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
+ {
+ bool bAll = ( eMode==SC_SIZE_OPTIMAL );
+ if (!bAll)
+ {
+ // delete for all that have CRFlags::ManualSize enabled
+ // then SetOptimalHeight with bShrink = FALSE
+ for (SCROW nRow=nStartNo; nRow<=nEndNo; nRow++)
+ {
+ CRFlags nOld = rDoc.GetRowFlags(nRow,nTab);
+ SCROW nLastRow = -1;
+ bool bHidden = rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow);
+ if ( !bHidden && ( nOld & CRFlags::ManualSize ) )
+ rDoc.SetRowFlags( nRow, nTab, nOld & ~CRFlags::ManualSize );
+ }
+ }
+
+ ScSizeDeviceProvider aProv( &rDocShell );
+ Fraction aOne(1,1);
+ sc::RowHeightContext aCxt(rDoc.MaxRow(), aProv.GetPPTX(), aProv.GetPPTY(), aOne, aOne, aProv.GetDevice());
+ aCxt.setForceAutoSize(bAll);
+ rDoc.SetOptimalHeight(aCxt, nStartNo, nEndNo, nTab, bApi);
+
+ if (bAll)
+ rDoc.ShowRows( nStartNo, nEndNo, nTab, true );
+
+ // Manual flag will be set already in SetOptimalHeight if bAll=true
+ // (it is on when Extra-Height, otherwise off).
+ }
+ else if ( eMode==SC_SIZE_DIRECT || eMode==SC_SIZE_ORIGINAL )
+ {
+ if (nSizeTwips)
+ {
+ rDoc.SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips );
+ rDoc.SetManualHeight( nStartNo, nEndNo, nTab, true ); // height was set manually
+ }
+ if ( eMode != SC_SIZE_ORIGINAL )
+ rDoc.ShowRows( nStartNo, nEndNo, nTab, nSizeTwips != 0 );
+ }
+ else if ( eMode==SC_SIZE_SHOW )
+ {
+ rDoc.ShowRows( nStartNo, nEndNo, nTab, true );
+ }
+ }
+ else // Column widths
+ {
+ for (SCCOL nCol=static_cast<SCCOL>(nStartNo); nCol<=static_cast<SCCOL>(nEndNo); nCol++)
+ {
+ if ( eMode != SC_SIZE_VISOPT || !rDoc.ColHidden(nCol, nTab) )
+ {
+ sal_uInt16 nThisSize = nSizeTwips;
+
+ if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
+ nThisSize = nSizeTwips +
+ lcl_GetOptimalColWidth( rDocShell, nCol, nTab );
+ if ( nThisSize )
+ rDoc.SetColWidth( nCol, nTab, nThisSize );
+
+ if ( eMode != SC_SIZE_ORIGINAL )
+ rDoc.ShowCol( nCol, nTab, bShow );
+ }
+ }
+ }
+
+ // adjust outlines
+
+ if ( eMode != SC_SIZE_ORIGINAL )
+ {
+ if (bWidth)
+ bOutline = bOutline || rDoc.UpdateOutlineCol(
+ static_cast<SCCOL>(nStartNo),
+ static_cast<SCCOL>(nEndNo), nTab, bShow );
+ else
+ bOutline = bOutline || rDoc.UpdateOutlineRow(
+ static_cast<SCROW>(nStartNo),
+ static_cast<SCROW>(nEndNo), nTab, bShow );
+ }
+ }
+ rDoc.SetDrawPageSize(nTab);
+
+ if (!bOutline)
+ pUndoTab.reset();
+
+ if (bRecord)
+ {
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SelectOneTable( nTab );
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoWidthOrHeight>(
+ &rDocShell, aMark, nStart, nTab, nEnd, nTab, std::move(pUndoDoc),
+ std::move(aUndoRanges), std::move(pUndoTab), eMode, nSizeTwips, bWidth));
+ }
+
+ rDoc.UpdatePageBreaks( nTab );
+
+ ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
+ if (pViewSh)
+ pViewSh->OnLOKSetWidthOrHeight(nStart, bWidth);
+
+ rDocShell.PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::All);
+ aModificator.SetDocumentModified();
+
+ return false;
+}
+
+bool ScDocFunc::InsertPageBreak( bool bColumn, const ScAddress& rPos,
+ bool bRecord, bool bSetModified )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ SCTAB nTab = rPos.Tab();
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+
+ SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(rPos.Col()) :
+ static_cast<SCCOLROW>(rPos.Row());
+ if (nPos == 0)
+ return false; // first column / row
+
+ ScBreakType nBreak = bColumn ?
+ rDoc.HasColBreak(static_cast<SCCOL>(nPos), nTab) :
+ rDoc.HasRowBreak(static_cast<SCROW>(nPos), nTab);
+ if (nBreak & ScBreakType::Manual)
+ return true;
+
+ if (bRecord)
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoPageBreak>( &rDocShell, rPos.Col(), rPos.Row(), nTab, bColumn, true ) );
+
+ if (bColumn)
+ rDoc.SetColBreak(static_cast<SCCOL>(nPos), nTab, false, true);
+ else
+ rDoc.SetRowBreak(static_cast<SCROW>(nPos), nTab, false, true);
+
+ rDoc.InvalidatePageBreaks(nTab);
+ rDoc.UpdatePageBreaks( nTab );
+
+ rDoc.SetStreamValid(nTab, false);
+
+ if (bColumn)
+ {
+ rDocShell.PostPaint( static_cast<SCCOL>(nPos)-1, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid );
+ if (pBindings)
+ {
+ pBindings->Invalidate( FID_INS_COLBRK );
+ pBindings->Invalidate( FID_DEL_COLBRK );
+ }
+ }
+ else
+ {
+ rDocShell.PostPaint( 0, static_cast<SCROW>(nPos)-1, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid );
+ if (pBindings)
+ {
+ pBindings->Invalidate( FID_INS_ROWBRK );
+ pBindings->Invalidate( FID_DEL_ROWBRK );
+ }
+ }
+ if (pBindings)
+ pBindings->Invalidate( FID_DEL_MANUALBREAKS );
+
+ if (bSetModified)
+ aModificator.SetDocumentModified();
+
+ return true;
+}
+
+bool ScDocFunc::RemovePageBreak( bool bColumn, const ScAddress& rPos,
+ bool bRecord, bool bSetModified )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ SCTAB nTab = rPos.Tab();
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+
+ SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(rPos.Col()) :
+ static_cast<SCCOLROW>(rPos.Row());
+
+ ScBreakType nBreak;
+ if (bColumn)
+ nBreak = rDoc.HasColBreak(static_cast<SCCOL>(nPos), nTab);
+ else
+ nBreak = rDoc.HasRowBreak(static_cast<SCROW>(nPos), nTab);
+ if (!(nBreak & ScBreakType::Manual))
+ // There is no manual break.
+ return false;
+
+ if (bRecord)
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoPageBreak>( &rDocShell, rPos.Col(), rPos.Row(), nTab, bColumn, false ) );
+
+ if (bColumn)
+ rDoc.RemoveColBreak(static_cast<SCCOL>(nPos), nTab, false, true);
+ else
+ rDoc.RemoveRowBreak(static_cast<SCROW>(nPos), nTab, false, true);
+
+ rDoc.UpdatePageBreaks( nTab );
+
+ rDoc.SetStreamValid(nTab, false);
+
+ if (bColumn)
+ {
+ rDocShell.PostPaint( static_cast<SCCOL>(nPos)-1, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid );
+ if (pBindings)
+ {
+ pBindings->Invalidate( FID_INS_COLBRK );
+ pBindings->Invalidate( FID_DEL_COLBRK );
+ }
+ }
+ else
+ {
+ rDocShell.PostPaint( 0, nPos-1, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid );
+ if (pBindings)
+ {
+ pBindings->Invalidate( FID_INS_ROWBRK );
+ pBindings->Invalidate( FID_DEL_ROWBRK );
+ }
+ }
+ if (pBindings)
+ pBindings->Invalidate( FID_DEL_MANUALBREAKS );
+
+ if (bSetModified)
+ aModificator.SetDocumentModified();
+
+ return true;
+}
+
+void ScDocFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ std::unique_ptr<ScTableProtection> p;
+ if (!rProtect.isProtected() && rDoc.IsUndoEnabled())
+ {
+ // In case of unprotecting, use a copy of passed ScTableProtection object for undo
+ p = std::make_unique<ScTableProtection>(rProtect);
+ }
+ rDoc.SetTabProtection(nTab, &rProtect);
+ if (rDoc.IsUndoEnabled())
+ {
+ if (!p)
+ {
+ // For protection case, use a copy of resulting ScTableProtection for undo
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ p = std::make_unique<ScTableProtection>(*pProtect);
+ }
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoTabProtect>(&rDocShell, nTab, std::move(p)));
+ // ownership of unique_ptr now transferred to ScUndoTabProtect.
+ }
+ for (SfxViewFrame* fr = SfxViewFrame::GetFirst(&rDocShell); fr;
+ fr = SfxViewFrame::GetNext(*fr, &rDocShell))
+ if (ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(fr->GetViewShell()))
+ pTabViewShell->SetTabProtectionSymbol(nTab, rProtect.isProtected());
+ rDocShell.PostPaintGridAll();
+ ScDocShellModificator aModificator(rDocShell);
+ aModificator.SetDocumentModified();
+}
+
+void ScDocFunc::ProtectDocument(const ScDocProtection& rProtect)
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ std::unique_ptr<ScDocProtection> p;
+ if (!rProtect.isProtected() && rDoc.IsUndoEnabled())
+ {
+ // In case of unprotecting, use a copy of passed ScTableProtection object for undo
+ p = std::make_unique<ScDocProtection>(rProtect);
+ }
+ rDoc.SetDocProtection(&rProtect);
+ if (rDoc.IsUndoEnabled())
+ {
+ if (!p)
+ {
+ // For protection case, use a copy of resulting ScTableProtection for undo
+ ScDocProtection* pProtect = rDoc.GetDocProtection();
+ p = std::make_unique<ScDocProtection>(*pProtect);
+ }
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDocProtect>(&rDocShell, std::move(p)));
+ // ownership of unique_ptr now transferred to ScUndoTabProtect.
+ }
+
+ rDocShell.PostPaintGridAll();
+ ScDocShellModificator aModificator(rDocShell);
+ aModificator.SetDocumentModified();
+}
+
+bool ScDocFunc::Protect( SCTAB nTab, const OUString& rPassword )
+{
+ if (nTab == TABLEID_DOC)
+ {
+ // document protection
+ ScDocProtection aProtection;
+ aProtection.setProtected(true);
+ aProtection.setPassword(rPassword);
+ ProtectDocument(aProtection);
+
+ }
+ else
+ {
+ // sheet protection
+
+ const ScTableProtection* pOldProtection = rDocShell.GetDocument().GetTabProtection(nTab);
+ ::std::unique_ptr<ScTableProtection> pNewProtection(pOldProtection ? new ScTableProtection(*pOldProtection) : new ScTableProtection());
+ pNewProtection->setProtected(true);
+ pNewProtection->setPassword(rPassword);
+ ProtectSheet(nTab, *pNewProtection);
+ }
+ return true;
+}
+
+bool ScDocFunc::Unprotect( SCTAB nTab, const OUString& rPassword, bool bApi )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (nTab == TABLEID_DOC)
+ {
+ // document protection
+
+ ScDocProtection* pDocProtect = rDoc.GetDocProtection();
+ if (!pDocProtect || !pDocProtect->isProtected())
+ // already unprotected (should not happen)!
+ return true;
+
+ if (!pDocProtect->verifyPassword(rPassword))
+ {
+ if (!bApi)
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(SCSTR_WRONGPASSWORD)));
+ xInfoBox->run();
+ }
+ return false;
+ }
+
+ ScDocProtection aNewProtection(*pDocProtect);
+ aNewProtection.setProtected(false);
+ ProtectDocument(aNewProtection);
+
+ }
+ else
+ {
+ // sheet protection
+
+ const ScTableProtection* pTabProtect = rDoc.GetTabProtection(nTab);
+ if (!pTabProtect || !pTabProtect->isProtected())
+ // already unprotected (should not happen)!
+ return true;
+ if (!pTabProtect->verifyPassword(rPassword))
+ {
+ if (!bApi)
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(SCSTR_WRONGPASSWORD)));
+ xInfoBox->run();
+ }
+ return false;
+ }
+
+ ScTableProtection aNewProtection(*pTabProtect);
+ aNewProtection.setProtected(false);
+ ProtectSheet(nTab, aNewProtection);
+ }
+
+ return true;
+}
+
+void ScDocFunc::ClearItems( const ScMarkData& rMark, const sal_uInt16* pWhich, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bUndo (rDoc.IsUndoEnabled());
+ ScEditableTester aTester( rDoc, rMark );
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ // #i12940# ClearItems is called (from setPropertyToDefault) directly with uno object's cached
+ // MarkData (GetMarkData), so rMark must be changed to multi selection for ClearSelectionItems
+ // here.
+
+ ScMarkData aMultiMark = rMark;
+ aMultiMark.SetMarking(false); // for MarkToMulti
+ aMultiMark.MarkToMulti();
+ const ScRange& aMarkRange = aMultiMark.GetMultiMarkArea();
+
+ if (bUndo)
+ {
+ SCTAB nStartTab = aMarkRange.aStart.Tab();
+ SCTAB nEndTab = aMarkRange.aEnd.Tab();
+
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab );
+ rDoc.CopyToDocument( aMarkRange, InsertDeleteFlags::ATTRIB, true, *pUndoDoc, &aMultiMark );
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoClearItems>( &rDocShell, aMultiMark, std::move(pUndoDoc), pWhich ) );
+ }
+
+ rDoc.ClearSelectionItems( pWhich, aMultiMark );
+
+ rDocShell.PostPaint( aMarkRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+ aModificator.SetDocumentModified();
+
+ //! Bindings-Invalidate etc.?
+}
+
+bool ScDocFunc::ChangeIndent( const ScMarkData& rMark, bool bIncrement, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+ ScEditableTester aTester( rDoc, rMark );
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ const ScRange& aMarkRange = rMark.GetMultiMarkArea();
+
+ if (bUndo)
+ {
+ SCTAB nStartTab = aMarkRange.aStart.Tab();
+ SCTAB nTabCount = rDoc.GetTableCount();
+
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab );
+ for (const auto& rTab : rMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (rTab != nStartTab)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ }
+
+ ScRange aCopyRange = aMarkRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, true, *pUndoDoc, &rMark );
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoIndent>( &rDocShell, rMark, std::move(pUndoDoc), bIncrement ) );
+ }
+
+ rDoc.ChangeSelectionIndent( bIncrement, rMark );
+
+ rDocShell.PostPaint( aMarkRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+ aModificator.SetDocumentModified();
+
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( SID_ALIGNLEFT ); // ChangeIndent aligns left
+ pBindings->Invalidate( SID_ALIGNRIGHT );
+ pBindings->Invalidate( SID_ALIGNBLOCK );
+ pBindings->Invalidate( SID_ALIGNCENTERHOR );
+ pBindings->Invalidate( SID_ATTR_LRSPACE );
+ pBindings->Invalidate( SID_ATTR_PARA_ADJUST_LEFT );
+ pBindings->Invalidate( SID_ATTR_PARA_ADJUST_RIGHT );
+ pBindings->Invalidate( SID_ATTR_PARA_ADJUST_BLOCK );
+ pBindings->Invalidate( SID_ATTR_PARA_ADJUST_CENTER);
+ // pseudo slots for Format menu
+ pBindings->Invalidate( SID_ALIGN_ANY_HDEFAULT );
+ pBindings->Invalidate( SID_ALIGN_ANY_LEFT );
+ pBindings->Invalidate( SID_ALIGN_ANY_HCENTER );
+ pBindings->Invalidate( SID_ALIGN_ANY_RIGHT );
+ pBindings->Invalidate( SID_ALIGN_ANY_JUSTIFIED );
+ }
+
+ return true;
+}
+
+bool ScDocFunc::AutoFormat( const ScRange& rRange, const ScMarkData* pTabMark,
+ sal_uInt16 nFormatNo, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ if (pTabMark)
+ aMark = *pTabMark;
+ else
+ {
+ for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
+ aMark.SelectTable( nTab, true );
+ }
+
+ ScAutoFormat* pAutoFormat = ScGlobal::GetOrCreateAutoFormat();
+ ScEditableTester aTester( rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
+ if ( nFormatNo < pAutoFormat->size() && aTester.IsEditable() )
+ {
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+
+ bool bSize = pAutoFormat->findByIndex(nFormatNo)->GetIncludeWidthHeight();
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ ScDocumentUniquePtr pUndoDoc;
+ if ( bRecord )
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab, bSize, bSize );
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (rTab != nStartTab)
+ pUndoDoc->AddUndoTab( rTab, rTab, bSize, bSize );
+ }
+
+ ScRange aCopyRange = rRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aStart.SetTab(nTabCount-1);
+ rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, false, *pUndoDoc, &aMark );
+ if (bSize)
+ {
+ rDoc.CopyToDocument( nStartCol,0,0, nEndCol,rDoc.MaxRow(),nTabCount-1,
+ InsertDeleteFlags::NONE, false, *pUndoDoc, &aMark );
+ rDoc.CopyToDocument( 0,nStartRow,0, rDoc.MaxCol(),nEndRow,nTabCount-1,
+ InsertDeleteFlags::NONE, false, *pUndoDoc, &aMark );
+ }
+ rDoc.BeginDrawUndo();
+ }
+
+ rDoc.AutoFormat( nStartCol, nStartRow, nEndCol, nEndRow, nFormatNo, aMark );
+
+ if (bSize)
+ {
+ std::vector<sc::ColRowSpan> aCols(1, sc::ColRowSpan(nStartCol,nEndCol));
+ std::vector<sc::ColRowSpan> aRows(1, sc::ColRowSpan(nStartRow,nEndRow));
+
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ SetWidthOrHeight(true, aCols, rTab, SC_SIZE_VISOPT, STD_EXTRA_WIDTH, false, true);
+ SetWidthOrHeight(false, aRows, rTab, SC_SIZE_VISOPT, 0, false, false);
+ rDocShell.PostPaint( 0,0,rTab, rDoc.MaxCol(),rDoc.MaxRow(),rTab,
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top );
+ }
+ }
+ else
+ {
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ bool bAdj = AdjustRowHeight( ScRange(nStartCol, nStartRow, rTab,
+ nEndCol, nEndRow, rTab), false, bApi );
+ if (bAdj)
+ rDocShell.PostPaint( 0,nStartRow,rTab, rDoc.MaxCol(),rDoc.MaxRow(),rTab,
+ PaintPartFlags::Grid | PaintPartFlags::Left );
+ else
+ rDocShell.PostPaint( nStartCol, nStartRow, rTab,
+ nEndCol, nEndRow, rTab, PaintPartFlags::Grid );
+ }
+ }
+
+ if ( bRecord ) // only now is Draw-Undo available
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAutoFormat>( &rDocShell, rRange, std::move(pUndoDoc), aMark, bSize, nFormatNo ) );
+ }
+
+ aModificator.SetDocumentModified();
+ }
+ else if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+
+ return false;
+}
+
+bool ScDocFunc::EnterMatrix( const ScRange& rRange, const ScMarkData* pTabMark,
+ const ScTokenArray* pTokenArray, const OUString& rString, bool bApi, bool bEnglish,
+ const OUString& rFormulaNmsp, const formula::FormulaGrammar::Grammar eGrammar )
+{
+ if (ScViewData::SelectionFillDOOM( rRange ))
+ return false;
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ bool bSuccess = false;
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ if (pTabMark)
+ aMark = *pTabMark;
+ else
+ {
+ for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
+ aMark.SelectTable( nTab, true );
+ }
+
+ ScEditableTester aTester( rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
+ if ( aTester.IsEditable() )
+ {
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+
+ ScDocumentUniquePtr pUndoDoc;
+
+ const bool bUndo(rDoc.IsUndoEnabled());
+ if (bUndo)
+ {
+ //! take selected sheets into account also when undoing
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab );
+ rDoc.CopyToDocument( rRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, *pUndoDoc );
+ }
+
+ // use TokenArray if given, string (and flags) otherwise
+ if ( pTokenArray )
+ {
+ rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
+ aMark, OUString(), pTokenArray, eGrammar);
+ }
+ else if ( rDoc.IsImportingXML() )
+ {
+ ScTokenArray aCode(rDoc);
+ aCode.AssignXMLString( rString,
+ ((eGrammar == formula::FormulaGrammar::GRAM_EXTERNAL) ? rFormulaNmsp : OUString()));
+ rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
+ aMark, OUString(), &aCode, eGrammar);
+ rDoc.IncXMLImportedFormulaCount( rString.getLength() );
+ }
+ else if (bEnglish)
+ {
+ ScCompiler aComp( rDoc, rRange.aStart, eGrammar);
+ std::unique_ptr<ScTokenArray> pCode = aComp.CompileString( rString );
+ rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
+ aMark, OUString(), pCode.get(), eGrammar);
+ }
+ else
+ rDoc.InsertMatrixFormula( nStartCol, nStartRow, nEndCol, nEndRow,
+ aMark, rString, nullptr, eGrammar);
+
+ if (bUndo)
+ {
+ //! take selected sheets into account also when undoing
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoEnterMatrix>( &rDocShell, rRange, std::move(pUndoDoc), rString ) );
+ }
+
+ // Err522 painting of DDE-Formulas will be intercepted during interpreting
+ rDocShell.PostPaint( nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab, PaintPartFlags::Grid );
+ aModificator.SetDocumentModified();
+
+ bSuccess = true;
+ }
+ else if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+
+ return bSuccess;
+}
+
+bool ScDocFunc::TabOp( const ScRange& rRange, const ScMarkData* pTabMark,
+ const ScTabOpParam& rParam, bool bRecord, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ bool bSuccess = false;
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ if (pTabMark)
+ aMark = *pTabMark;
+ else
+ {
+ for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
+ aMark.SelectTable( nTab, true );
+ }
+
+ ScEditableTester aTester( rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
+ if ( aTester.IsEditable() )
+ {
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+ rDoc.SetDirty( rRange, false );
+ if ( bRecord )
+ {
+ //! take selected sheets into account also when undoing
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab );
+ rDoc.CopyToDocument( rRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, *pUndoDoc );
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoTabOp>( &rDocShell,
+ nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab, std::move(pUndoDoc),
+ rParam.aRefFormulaCell,
+ rParam.aRefFormulaEnd,
+ rParam.aRefRowCell,
+ rParam.aRefColCell,
+ rParam.meMode) );
+ }
+ rDoc.InsertTableOp(rParam, nStartCol, nStartRow, nEndCol, nEndRow, aMark);
+ rDocShell.PostPaintGridAll();
+ aModificator.SetDocumentModified();
+ bSuccess = true;
+ }
+ else if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+
+ return bSuccess;
+}
+
+static ScDirection DirFromFillDir( FillDir eDir )
+{
+ if (eDir==FILL_TO_BOTTOM)
+ return DIR_BOTTOM;
+ else if (eDir==FILL_TO_RIGHT)
+ return DIR_RIGHT;
+ else if (eDir==FILL_TO_TOP)
+ return DIR_TOP;
+ else // if (eDir==FILL_TO_LEFT)
+ return DIR_LEFT;
+}
+
+namespace {
+
+/**
+ * Expand the fill range as necessary, to allow copying of adjacent cell(s)
+ * even when those cells are not in the original range.
+ */
+void adjustFillRangeForAdjacentCopy(const ScDocument &rDoc, ScRange& rRange, FillDir eDir)
+{
+ switch (eDir)
+ {
+ case FILL_TO_BOTTOM:
+ {
+ if (rRange.aStart.Row() == 0)
+ return;
+
+ if (rRange.aStart.Row() != rRange.aEnd.Row())
+ return;
+
+ // Include the above row.
+ ScAddress& s = rRange.aStart;
+ s.SetRow(s.Row()-1);
+ }
+ break;
+ case FILL_TO_TOP:
+ {
+ if (rRange.aStart.Row() == rDoc.MaxRow())
+ return;
+
+ if (rRange.aStart.Row() != rRange.aEnd.Row())
+ return;
+
+ // Include the row below.
+ ScAddress& e = rRange.aEnd;
+ e.SetRow(e.Row()+1);
+ }
+ break;
+ case FILL_TO_LEFT:
+ {
+ if (rRange.aStart.Col() == rDoc.MaxCol())
+ return;
+
+ if (rRange.aStart.Col() != rRange.aEnd.Col())
+ return;
+
+ // Include the column to the right.
+ ScAddress& e = rRange.aEnd;
+ e.SetCol(e.Col()+1);
+ }
+ break;
+ case FILL_TO_RIGHT:
+ {
+ if (rRange.aStart.Col() == 0)
+ return;
+
+ if (rRange.aStart.Col() != rRange.aEnd.Col())
+ return;
+
+ // Include the column to the left.
+ ScAddress& s = rRange.aStart;
+ s.SetCol(s.Col()-1);
+ }
+ break;
+ default:
+ ;
+ }
+}
+
+}
+
+bool ScDocFunc::FillSimple( const ScRange& rRange, const ScMarkData* pTabMark,
+ FillDir eDir, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ bool bSuccess = false;
+ ScRange aRange = rRange;
+ adjustFillRangeForAdjacentCopy(rDoc, aRange, eDir);
+
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCTAB nStartTab = aRange.aStart.Tab();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ SCTAB nEndTab = aRange.aEnd.Tab();
+
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ if (pTabMark)
+ aMark = *pTabMark;
+ else
+ {
+ for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
+ aMark.SelectTable( nTab, true );
+ }
+
+ ScEditableTester aTester( rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
+ if ( aTester.IsEditable() )
+ {
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+
+ ScRange aSourceArea = aRange;
+ ScRange aDestArea = aRange;
+
+ SCCOLROW nCount = 0;
+ switch (eDir)
+ {
+ case FILL_TO_BOTTOM:
+ nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row();
+ aSourceArea.aEnd.SetRow( aSourceArea.aStart.Row() );
+ break;
+ case FILL_TO_RIGHT:
+ nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col();
+ aSourceArea.aEnd.SetCol( aSourceArea.aStart.Col() );
+ break;
+ case FILL_TO_TOP:
+ nCount = aSourceArea.aEnd.Row()-aSourceArea.aStart.Row();
+ aSourceArea.aStart.SetRow( aSourceArea.aEnd.Row() );
+ break;
+ case FILL_TO_LEFT:
+ nCount = aSourceArea.aEnd.Col()-aSourceArea.aStart.Col();
+ aSourceArea.aStart.SetCol( aSourceArea.aEnd.Col() );
+ break;
+ }
+
+ ScDocumentUniquePtr pUndoDoc;
+ if ( bRecord )
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCTAB nDestStartTab = aDestArea.aStart.Tab();
+
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nDestStartTab, nDestStartTab );
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (rTab != nDestStartTab)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ }
+
+ ScRange aCopyRange = aDestArea;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::AUTOFILL, false, *pUndoDoc, &aMark );
+ }
+
+ sal_uLong nProgCount;
+ if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP)
+ nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1;
+ else
+ nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1;
+ nProgCount *= nCount;
+ ScProgress aProgress( rDoc.GetDocumentShell(),
+ ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true );
+
+ rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(),
+ aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress,
+ aMark, nCount, eDir, FILL_SIMPLE );
+ AdjustRowHeight(aRange, true, bApi);
+
+ if ( bRecord ) // only now is Draw-Undo available
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAutoFill>( &rDocShell, aDestArea, aSourceArea, std::move(pUndoDoc), aMark,
+ eDir, FILL_SIMPLE, FILL_DAY, MAXDOUBLE, 1.0, 1e307) );
+ }
+
+ rDocShell.PostPaintGridAll();
+ aModificator.SetDocumentModified();
+
+ bSuccess = true;
+ }
+ else if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+
+ return bSuccess;
+}
+
+bool ScDocFunc::FillSeries( const ScRange& rRange, const ScMarkData* pTabMark,
+ FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd,
+ double fStart, double fStep, double fMax,
+ bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ bool bSuccess = false;
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ if (pTabMark)
+ aMark = *pTabMark;
+ else
+ {
+ for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
+ aMark.SelectTable( nTab, true );
+ }
+
+ ScEditableTester aTester( rDoc, nStartCol,nStartRow, nEndCol,nEndRow, aMark );
+ if ( aTester.IsEditable() )
+ {
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+
+ ScRange aSourceArea = rRange;
+ ScRange aDestArea = rRange;
+
+ SCSIZE nCount = rDoc.GetEmptyLinesInBlock(
+ aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aStart.Tab(),
+ aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aSourceArea.aEnd.Tab(),
+ DirFromFillDir(eDir) );
+
+ // keep at least one row/column as source range
+ SCSIZE nTotLines = ( eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP ) ?
+ static_cast<SCSIZE>( aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1 ) :
+ static_cast<SCSIZE>( aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1 );
+ if ( nCount >= nTotLines )
+ nCount = nTotLines - 1;
+
+ switch (eDir)
+ {
+ case FILL_TO_BOTTOM:
+ aSourceArea.aEnd.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aEnd.Row() - nCount ) );
+ break;
+ case FILL_TO_RIGHT:
+ aSourceArea.aEnd.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aEnd.Col() - nCount ) );
+ break;
+ case FILL_TO_TOP:
+ aSourceArea.aStart.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aStart.Row() + nCount ) );
+ break;
+ case FILL_TO_LEFT:
+ aSourceArea.aStart.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aStart.Col() + nCount ) );
+ break;
+ }
+
+ ScDocumentUniquePtr pUndoDoc;
+ if ( bRecord )
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCTAB nDestStartTab = aDestArea.aStart.Tab();
+
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nDestStartTab, nDestStartTab );
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (rTab != nDestStartTab)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ }
+
+ rDoc.CopyToDocument(
+ aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0,
+ aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1,
+ InsertDeleteFlags::AUTOFILL, false, *pUndoDoc, &aMark );
+ }
+
+ if (aDestArea.aStart.Col() <= aDestArea.aEnd.Col() &&
+ aDestArea.aStart.Row() <= aDestArea.aEnd.Row())
+ {
+ if ( fStart != MAXDOUBLE )
+ {
+ SCCOL nValX = (eDir == FILL_TO_LEFT) ? aDestArea.aEnd.Col() : aDestArea.aStart.Col();
+ SCROW nValY = (eDir == FILL_TO_TOP ) ? aDestArea.aEnd.Row() : aDestArea.aStart.Row();
+ SCTAB nTab = aDestArea.aStart.Tab();
+ rDoc.SetValue( nValX, nValY, nTab, fStart );
+ }
+
+ sal_uLong nProgCount;
+ if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP)
+ nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1;
+ else
+ nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1;
+ nProgCount *= nCount;
+ ScProgress aProgress( rDoc.GetDocumentShell(),
+ ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true );
+
+ rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(),
+ aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress,
+ aMark, nCount, eDir, eCmd, eDateCmd, fStep, fMax );
+ AdjustRowHeight(rRange, true, bApi);
+
+ rDocShell.PostPaintGridAll();
+ aModificator.SetDocumentModified();
+ }
+
+ if ( bRecord ) // only now is Draw-Undo available
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAutoFill>( &rDocShell, aDestArea, aSourceArea, std::move(pUndoDoc), aMark,
+ eDir, eCmd, eDateCmd, fStart, fStep, fMax) );
+ }
+
+ bSuccess = true;
+ }
+ else if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+
+ return bSuccess;
+}
+
+bool ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark,
+ FillDir eDir, sal_uLong nCount, bool bApi )
+{
+ return FillAuto( rRange, pTabMark, eDir, FILL_AUTO, FILL_DAY, nCount, 1.0/*fStep*/, MAXDOUBLE/*fMax*/, true/*bRecord*/, bApi );
+}
+
+bool ScDocFunc::FillAuto( ScRange& rRange, const ScMarkData* pTabMark, FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, sal_uLong nCount, double fStep, double fMax, bool bRecord, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ if (pTabMark)
+ aMark = *pTabMark;
+ else
+ {
+ for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
+ aMark.SelectTable( nTab, true );
+ }
+
+ ScRange aSourceArea = rRange;
+ ScRange aDestArea = rRange;
+
+ switch (eDir)
+ {
+ case FILL_TO_BOTTOM:
+ aDestArea.aEnd.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aEnd.Row() + nCount ) );
+ break;
+ case FILL_TO_TOP:
+ if (nCount > sal::static_int_cast<sal_uLong>( aSourceArea.aStart.Row() ))
+ {
+ OSL_FAIL("FillAuto: Row < 0");
+ nCount = aSourceArea.aStart.Row();
+ }
+ aDestArea.aStart.SetRow( sal::static_int_cast<SCROW>( aSourceArea.aStart.Row() - nCount ) );
+ break;
+ case FILL_TO_RIGHT:
+ aDestArea.aEnd.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aEnd.Col() + nCount ) );
+ break;
+ case FILL_TO_LEFT:
+ if (nCount > sal::static_int_cast<sal_uLong>( aSourceArea.aStart.Col() ))
+ {
+ OSL_FAIL("FillAuto: Col < 0");
+ nCount = aSourceArea.aStart.Col();
+ }
+ aDestArea.aStart.SetCol( sal::static_int_cast<SCCOL>( aSourceArea.aStart.Col() - nCount ) );
+ break;
+ default:
+ OSL_FAIL("Wrong direction with FillAuto");
+ break;
+ }
+
+ // Test for cell protection
+ //! Source range can be protected !!!
+ //! but can't contain matrix fragments !!!
+
+ ScEditableTester aTester( rDoc, aDestArea );
+ if ( !aTester.IsEditable() )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ if ( rDoc.HasSelectedBlockMatrixFragment( nStartCol, nStartRow,
+ nEndCol, nEndRow, aMark ) )
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_MATRIXFRAGMENTERR);
+ return false;
+ }
+
+ // FID_FILL_... slots should already had been disabled, check here for API
+ // calls, no message.
+ if (ScViewData::SelectionFillDOOM( aDestArea))
+ return false;
+
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+
+ ScDocumentUniquePtr pUndoDoc;
+ if ( bRecord )
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCTAB nDestStartTab = aDestArea.aStart.Tab();
+
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nDestStartTab, nDestStartTab );
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (rTab != nDestStartTab)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ }
+
+ // do not clone note captions in undo document
+ rDoc.CopyToDocument(
+ aDestArea.aStart.Col(), aDestArea.aStart.Row(), 0,
+ aDestArea.aEnd.Col(), aDestArea.aEnd.Row(), nTabCount-1,
+ InsertDeleteFlags::AUTOFILL, false, *pUndoDoc, &aMark );
+ }
+
+ sal_uLong nProgCount;
+ if (eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP)
+ nProgCount = aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1;
+ else
+ nProgCount = aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1;
+ nProgCount *= nCount;
+ ScProgress aProgress( rDoc.GetDocumentShell(),
+ ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true );
+
+ rDoc.Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(),
+ aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), &aProgress,
+ aMark, nCount, eDir, eCmd, eDateCmd, fStep, fMax );
+
+ AdjustRowHeight(aDestArea, true, bApi);
+
+ if ( bRecord ) // only now is Draw-Undo available
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAutoFill>( &rDocShell, aDestArea, aSourceArea, std::move(pUndoDoc), aMark,
+ eDir, eCmd, eDateCmd, MAXDOUBLE, fStep, fMax) );
+ }
+
+ rDocShell.PostPaintGridAll();
+ aModificator.SetDocumentModified();
+
+ rRange = aDestArea; // return destination range (for marking)
+ return true;
+}
+
+bool ScDocFunc::MergeCells( const ScCellMergeOption& rOption, bool bContents, bool bRecord, bool bApi, bool bEmptyMergedCells /*=false*/ )
+{
+ using ::std::set;
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ SCCOL nStartCol = rOption.mnStartCol;
+ SCROW nStartRow = rOption.mnStartRow;
+ SCCOL nEndCol = rOption.mnEndCol;
+ SCROW nEndRow = rOption.mnEndRow;
+ if ((nStartCol == nEndCol && nStartRow == nEndRow) || rOption.maTabs.empty())
+ {
+ // Nothing to do. Bail out quickly
+ return true;
+ }
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SCTAB nTab1 = *rOption.maTabs.begin(), nTab2 = *rOption.maTabs.rbegin();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ for (const auto& rTab : rOption.maTabs)
+ {
+ ScEditableTester aTester( rDoc, rTab, nStartCol, nStartRow, nEndCol, nEndRow );
+ if (!aTester.IsEditable())
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ if ( rDoc.HasAttrib( nStartCol, nStartRow, rTab, nEndCol, nEndRow, rTab,
+ HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
+ {
+ // "Merge of already merged cells not possible"
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_MSSG_MERGECELLS_0);
+ return false;
+ }
+ }
+
+ ScDocumentUniquePtr pUndoDoc;
+ bool bNeedContentsUndo = false;
+ for (const SCTAB nTab : rOption.maTabs)
+ {
+ bool bIsBlockEmpty = ( nStartRow == nEndRow )
+ ? rDoc.IsEmptyData( nStartCol+1,nStartRow, nEndCol,nEndRow, nTab )
+ : rDoc.IsEmptyData( nStartCol,nStartRow+1, nStartCol,nEndRow, nTab ) &&
+ rDoc.IsEmptyData( nStartCol+1,nStartRow, nEndCol,nEndRow, nTab );
+ bool bNeedContents = bContents && !bIsBlockEmpty;
+ bool bNeedEmpty = bEmptyMergedCells && !bIsBlockEmpty && !bNeedContents; // if DoMergeContents then cells are emptied
+
+ if (bRecord)
+ {
+ // test if the range contains other notes which also implies that we need an undo document
+ bool bHasNotes = rDoc.HasNote(nTab, nStartCol, nStartRow, nEndCol, nEndRow);
+ if (!pUndoDoc)
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo(rDoc, nTab1, nTab2);
+ }
+ // note captions are collected by drawing undo
+ rDoc.CopyToDocument( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab,
+ InsertDeleteFlags::ALL|InsertDeleteFlags::NOCAPTIONS, false, *pUndoDoc );
+ if( bHasNotes )
+ rDoc.BeginDrawUndo();
+ }
+
+ if (bNeedContents)
+ rDoc.DoMergeContents( nStartCol,nStartRow, nEndCol,nEndRow, nTab );
+ else if ( bNeedEmpty )
+ rDoc.DoEmptyBlock( nStartCol,nStartRow, nEndCol,nEndRow, nTab );
+ rDoc.DoMerge( nStartCol,nStartRow, nEndCol,nEndRow, nTab );
+
+ if (rOption.mbCenter)
+ {
+ rDoc.ApplyAttr( nStartCol, nStartRow, nTab, SvxHorJustifyItem( SvxCellHorJustify::Center, ATTR_HOR_JUSTIFY ) );
+ rDoc.ApplyAttr( nStartCol, nStartRow, nTab, SvxVerJustifyItem( SvxCellVerJustify::Center, ATTR_VER_JUSTIFY ) );
+ }
+
+ if ( !AdjustRowHeight( ScRange( 0,nStartRow,nTab, rDoc.MaxCol(),nEndRow,nTab ), true, bApi ) )
+ rDocShell.PostPaint( nStartCol, nStartRow, nTab,
+ nEndCol, nEndRow, nTab, PaintPartFlags::Grid );
+ if (bNeedContents || rOption.mbCenter)
+ {
+ ScRange aRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab);
+ rDoc.SetDirty(aRange, true);
+ }
+
+ bool bDone = ScDetectiveFunc(rDoc, nTab).DeleteAll( ScDetectiveDelete::Circles );
+ if(bDone)
+ DetectiveMarkInvalid(nTab);
+
+ bNeedContentsUndo |= bNeedContents;
+ }
+
+ if (pUndoDoc)
+ {
+ std::unique_ptr<SdrUndoGroup> pDrawUndo = rDoc.GetDrawLayer() ? rDoc.GetDrawLayer()->GetCalcUndo() : nullptr;
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoMerge>(&rDocShell, rOption, bNeedContentsUndo, std::move(pUndoDoc), std::move(pDrawUndo)) );
+ }
+
+ aModificator.SetDocumentModified();
+
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( FID_MERGE_ON );
+ pBindings->Invalidate( FID_MERGE_OFF );
+ pBindings->Invalidate( FID_MERGE_TOGGLE );
+ }
+
+ return true;
+}
+
+bool ScDocFunc::UnmergeCells( const ScRange& rRange, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge )
+{
+ ScCellMergeOption aOption(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row());
+ SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
+ for (SCTAB i = nTab1; i <= nTab2; ++i)
+ aOption.maTabs.insert(i);
+
+ return UnmergeCells(aOption, bRecord, pUndoRemoveMerge);
+}
+
+bool ScDocFunc::UnmergeCells( const ScCellMergeOption& rOption, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge )
+{
+ using ::std::set;
+
+ if (rOption.maTabs.empty())
+ // Nothing to unmerge.
+ return true;
+
+ ScDocShellModificator aModificator( rDocShell );
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScDocument* pUndoDoc = (pUndoRemoveMerge ? pUndoRemoveMerge->GetUndoDoc() : nullptr);
+ assert( pUndoDoc || !pUndoRemoveMerge );
+ for (const SCTAB nTab : rOption.maTabs)
+ {
+ ScRange aRange = rOption.getSingleRange(nTab);
+ if ( !rDoc.HasAttrib(aRange, HasAttrFlags::Merged) )
+ continue;
+
+ ScRange aExtended = aRange;
+ rDoc.ExtendMerge(aExtended);
+ ScRange aRefresh = aExtended;
+ rDoc.ExtendOverlapped(aRefresh);
+
+ if (bRecord)
+ {
+ if (!pUndoDoc)
+ {
+ pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
+ pUndoDoc->InitUndo(rDoc, *rOption.maTabs.begin(), *rOption.maTabs.rbegin());
+ }
+ rDoc.CopyToDocument(aExtended, InsertDeleteFlags::ATTRIB, false, *pUndoDoc);
+ }
+
+ const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetDefaultItem( ATTR_MERGE );
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( rDefAttr );
+ rDoc.ApplyPatternAreaTab( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), nTab,
+ aPattern );
+
+ rDoc.RemoveFlagsTab( aExtended.aStart.Col(), aExtended.aStart.Row(),
+ aExtended.aEnd.Col(), aExtended.aEnd.Row(), nTab,
+ ScMF::Hor | ScMF::Ver );
+
+ rDoc.ExtendMerge( aRefresh, true );
+
+ if ( !AdjustRowHeight( aExtended, true, true ) )
+ rDocShell.PostPaint( aExtended, PaintPartFlags::Grid );
+
+ bool bDone = ScDetectiveFunc(rDoc, nTab).DeleteAll( ScDetectiveDelete::Circles );
+ if(bDone)
+ DetectiveMarkInvalid(nTab);
+ }
+
+ if (bRecord)
+ {
+ if (pUndoRemoveMerge)
+ {
+ // If pUndoRemoveMerge was passed, the caller is responsible for
+ // adding it to Undo. Just add the current option.
+ pUndoRemoveMerge->AddCellMergeOption( rOption);
+ }
+ else
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRemoveMerge>( &rDocShell, rOption, ScDocumentUniquePtr(pUndoDoc) ) );
+ }
+ }
+ aModificator.SetDocumentModified();
+
+ return true;
+}
+
+void ScDocFunc::ModifyRangeNames( const ScRangeName& rNewRanges, SCTAB nTab )
+{
+ SetNewRangeNames( std::unique_ptr<ScRangeName>(new ScRangeName(rNewRanges)), true, nTab );
+}
+
+void ScDocFunc::SetNewRangeNames( std::unique_ptr<ScRangeName> pNewRanges, bool bModifyDoc, SCTAB nTab ) // takes ownership of pNewRanges
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ OSL_ENSURE( pNewRanges, "pNewRanges is 0" );
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ if (bUndo)
+ {
+ ScRangeName* pOld;
+ if (nTab >=0)
+ {
+ pOld = rDoc.GetRangeName(nTab);
+ }
+ else
+ {
+ pOld = rDoc.GetRangeName();
+ }
+ std::unique_ptr<ScRangeName> pUndoRanges(new ScRangeName(*pOld));
+ std::unique_ptr<ScRangeName> pRedoRanges(new ScRangeName(*pNewRanges));
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRangeNames>( &rDocShell, std::move(pUndoRanges), std::move(pRedoRanges), nTab ) );
+ }
+
+ // #i55926# While loading XML, formula cells only have a single string token,
+ // so CompileNameFormula would never find any name (index) tokens, and would
+ // unnecessarily loop through all cells.
+ bool bCompile = ( !rDoc.IsImportingXML() && rDoc.GetNamedRangesLockCount() == 0 );
+
+ if ( bCompile )
+ rDoc.PreprocessRangeNameUpdate();
+ if (nTab >= 0)
+ rDoc.SetRangeName( nTab, std::move(pNewRanges) ); // takes ownership
+ else
+ rDoc.SetRangeName( std::move(pNewRanges) ); // takes ownership
+ if ( bCompile )
+ rDoc.CompileHybridFormula();
+
+ if (bModifyDoc)
+ {
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint(SfxHintId::ScAreasChanged) );
+ }
+}
+
+void ScDocFunc::ModifyAllRangeNames(const std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap)
+{
+ ScDocShellModificator aModificator(rDocShell);
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (rDoc.IsUndoEnabled())
+ {
+ std::map<OUString, ScRangeName*> aOldRangeMap;
+ rDoc.GetRangeNameMap(aOldRangeMap);
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAllRangeNames>(&rDocShell, aOldRangeMap, rRangeMap));
+ }
+
+ rDoc.PreprocessAllRangeNamesUpdate(rRangeMap);
+ rDoc.SetAllRangeNames(rRangeMap);
+ rDoc.CompileHybridFormula();
+
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScAreasChanged));
+}
+
+void ScDocFunc::CreateOneName( ScRangeName& rList,
+ SCCOL nPosX, SCROW nPosY, SCTAB nTab,
+ SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ bool& rCancel, bool bApi )
+{
+ if (rCancel)
+ return;
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (rDoc.HasValueData( nPosX, nPosY, nTab ))
+ return;
+
+ OUString aName = rDoc.GetString(nPosX, nPosY, nTab);
+ ScRangeData::MakeValidName(rDoc, aName);
+ if (aName.isEmpty())
+ return;
+
+ OUString aContent( ScRange( nX1, nY1, nTab, nX2, nY2, nTab ).Format(
+ rDoc, ScRefFlags::RANGE_ABS_3D, ScAddress::Details( rDoc.GetAddressConvention(), nPosY, nPosX)));
+
+ bool bInsert = false;
+ ScRangeData* pOld = rList.findByUpperName(ScGlobal::getCharClass().uppercase(aName));
+ if (pOld)
+ {
+ OUString aOldStr = pOld->GetSymbol();
+ if (aOldStr != aContent)
+ {
+ if (bApi)
+ bInsert = true; // don't check via API
+ else
+ {
+ OUString aTemplate = ScResId( STR_CREATENAME_REPLACE );
+ OUString aMessage = o3tl::getToken(aTemplate, 0, '#' ) + aName + o3tl::getToken(aTemplate, 1, '#' );
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ aMessage));
+ xQueryBox->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ xQueryBox->set_default_response(RET_YES);
+
+ short nResult = xQueryBox->run();
+ if ( nResult == RET_YES )
+ {
+ rList.erase(*pOld);
+ bInsert = true;
+ }
+ else if ( nResult == RET_CANCEL )
+ rCancel = true;
+ }
+ }
+ }
+ else
+ bInsert = true;
+
+ if (bInsert)
+ {
+ ScRangeData* pData = new ScRangeData( rDoc, aName, aContent,
+ ScAddress( nPosX, nPosY, nTab));
+ if (!rList.insert(pData))
+ {
+ OSL_FAIL("nanu?");
+ }
+ }
+}
+
+bool ScDocFunc::CreateNames( const ScRange& rRange, CreateNameFlags nFlags, bool bApi, SCTAB aTab )
+{
+ if (nFlags == CreateNameFlags::NONE)
+ return false; // was nothing
+
+ ScDocShellModificator aModificator( rDocShell );
+
+ bool bDone = false;
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nTab = rRange.aStart.Tab();
+ OSL_ENSURE(rRange.aEnd.Tab() == nTab, "CreateNames: multiple tables not possible");
+
+ bool bValid = true;
+ if ( nFlags & ( CreateNameFlags::Top | CreateNameFlags::Bottom ) )
+ if ( nStartRow == nEndRow )
+ bValid = false;
+ if ( nFlags & ( CreateNameFlags::Left | CreateNameFlags::Right ) )
+ if ( nStartCol == nEndCol )
+ bValid = false;
+
+ if (bValid)
+ {
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScRangeName* pNames;
+ if (aTab >=0)
+ pNames = rDoc.GetRangeName(nTab);
+ else
+ pNames = rDoc.GetRangeName();
+
+ if (!pNames)
+ return false; // shouldn't happen
+ ScRangeName aNewRanges( *pNames );
+
+ bool bTop ( nFlags & CreateNameFlags::Top );
+ bool bLeft ( nFlags & CreateNameFlags::Left );
+ bool bBottom( nFlags & CreateNameFlags::Bottom );
+ bool bRight ( nFlags & CreateNameFlags::Right );
+
+ SCCOL nContX1 = nStartCol;
+ SCROW nContY1 = nStartRow;
+ SCCOL nContX2 = nEndCol;
+ SCROW nContY2 = nEndRow;
+
+ if ( bTop )
+ ++nContY1;
+ if ( bLeft )
+ ++nContX1;
+ if ( bBottom )
+ --nContY2;
+ if ( bRight )
+ --nContX2;
+
+ bool bCancel = false;
+ SCCOL i;
+ SCROW j;
+
+ if ( bTop )
+ for (i=nContX1; i<=nContX2; i++)
+ CreateOneName( aNewRanges, i,nStartRow,nTab, i,nContY1,i,nContY2, bCancel, bApi );
+ if ( bLeft )
+ for (j=nContY1; j<=nContY2; j++)
+ CreateOneName( aNewRanges, nStartCol,j,nTab, nContX1,j,nContX2,j, bCancel, bApi );
+ if ( bBottom )
+ for (i=nContX1; i<=nContX2; i++)
+ CreateOneName( aNewRanges, i,nEndRow,nTab, i,nContY1,i,nContY2, bCancel, bApi );
+ if ( bRight )
+ for (j=nContY1; j<=nContY2; j++)
+ CreateOneName( aNewRanges, nEndCol,j,nTab, nContX1,j,nContX2,j, bCancel, bApi );
+
+ if ( bTop && bLeft )
+ CreateOneName( aNewRanges, nStartCol,nStartRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi );
+ if ( bTop && bRight )
+ CreateOneName( aNewRanges, nEndCol,nStartRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi );
+ if ( bBottom && bLeft )
+ CreateOneName( aNewRanges, nStartCol,nEndRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi );
+ if ( bBottom && bRight )
+ CreateOneName( aNewRanges, nEndCol,nEndRow,nTab, nContX1,nContY1,nContX2,nContY2, bCancel, bApi );
+
+ ModifyRangeNames( aNewRanges, aTab );
+ bDone = true;
+
+ }
+
+ return bDone;
+}
+
+bool ScDocFunc::InsertNameList( const ScAddress& rStartPos, bool bApi )
+{
+ ScDocShellModificator aModificator( rDocShell );
+
+ bool bDone = false;
+ ScDocument& rDoc = rDocShell.GetDocument();
+ const bool bRecord = rDoc.IsUndoEnabled();
+ SCTAB nTab = rStartPos.Tab();
+
+ //local names have higher priority than global names
+ ScRangeName* pLocalList = rDoc.GetRangeName(nTab);
+ sal_uInt16 nValidCount = 0;
+ for (const auto& rEntry : *pLocalList)
+ {
+ const ScRangeData& r = *rEntry.second;
+ if (!r.HasType(ScRangeData::Type::Database))
+ ++nValidCount;
+ }
+ ScRangeName* pList = rDoc.GetRangeName();
+ for (const auto& rEntry : *pList)
+ {
+ const ScRangeData& r = *rEntry.second;
+ if (!r.HasType(ScRangeData::Type::Database) && !pLocalList->findByUpperName(r.GetUpperName()))
+ ++nValidCount;
+ }
+
+ if (nValidCount)
+ {
+ SCCOL nStartCol = rStartPos.Col();
+ SCROW nStartRow = rStartPos.Row();
+ SCCOL nEndCol = nStartCol + 1;
+ SCROW nEndRow = nStartRow + static_cast<SCROW>(nValidCount) - 1;
+
+ ScEditableTester aTester( rDoc, nTab, nStartCol,nStartRow, nEndCol,nEndRow );
+ if (aTester.IsEditable())
+ {
+ ScDocumentUniquePtr pUndoDoc;
+
+ if (bRecord)
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ rDoc.CopyToDocument(nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab,
+ InsertDeleteFlags::ALL, false, *pUndoDoc);
+
+ rDoc.BeginDrawUndo(); // because of adjusting heights
+ }
+
+ std::unique_ptr<ScRangeData*[]> ppSortArray(new ScRangeData* [ nValidCount ]);
+ sal_uInt16 j = 0;
+ for (const auto& rEntry : *pLocalList)
+ {
+ ScRangeData& r = *rEntry.second;
+ if (!r.HasType(ScRangeData::Type::Database))
+ ppSortArray[j++] = &r;
+ }
+ for (const auto& [rName, rxData] : *pList)
+ {
+ ScRangeData& r = *rxData;
+ if (!r.HasType(ScRangeData::Type::Database) && !pLocalList->findByUpperName(rName))
+ ppSortArray[j++] = &r;
+ }
+ qsort( static_cast<void*>(ppSortArray.get()), nValidCount, sizeof(ScRangeData*),
+ &ScRangeData_QsortNameCompare );
+ OUString aName;
+ OUStringBuffer aContent;
+ OUString aFormula;
+ SCROW nOutRow = nStartRow;
+ for (j=0; j<nValidCount; j++)
+ {
+ ScRangeData* pData = ppSortArray[j];
+ pData->GetName(aName);
+ // adjust relative references to the left column in Excel-compliant way:
+ pData->UpdateSymbol(aContent, ScAddress( nStartCol, nOutRow, nTab ));
+ aFormula = "=" + aContent;
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(ScAddress(nStartCol,nOutRow,nTab), aName, &aParam);
+ rDoc.SetString(ScAddress(nEndCol,nOutRow,nTab), aFormula, &aParam);
+ ++nOutRow;
+ }
+
+ ppSortArray.reset();
+
+ if (bRecord)
+ {
+ ScDocumentUniquePtr pRedoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pRedoDoc->InitUndo( rDoc, nTab, nTab );
+ rDoc.CopyToDocument(nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab,
+ InsertDeleteFlags::ALL, false, *pRedoDoc);
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoListNames>( &rDocShell,
+ ScRange( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab ),
+ std::move(pUndoDoc), std::move(pRedoDoc) ) );
+ }
+
+ if (!AdjustRowHeight(ScRange(0,nStartRow,nTab,rDoc.MaxCol(),nEndRow,nTab), true, true))
+ rDocShell.PostPaint( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab, PaintPartFlags::Grid );
+
+ aModificator.SetDocumentModified();
+ bDone = true;
+ }
+ else if (!bApi)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ }
+ return bDone;
+}
+
+void ScDocFunc::ResizeMatrix( const ScRange& rOldRange, const ScAddress& rNewEnd )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SCCOL nStartCol = rOldRange.aStart.Col();
+ SCROW nStartRow = rOldRange.aStart.Row();
+ SCTAB nTab = rOldRange.aStart.Tab();
+
+ OUString aFormula = rDoc.GetFormula( nStartCol, nStartRow, nTab );
+ if ( !(aFormula.startsWith("{") && aFormula.endsWith("}")) )
+ return;
+
+ OUString aUndo = ScResId( STR_UNDO_RESIZEMATRIX );
+ bool bUndo(rDoc.IsUndoEnabled());
+ if (bUndo)
+ {
+ ViewShellId nViewShellId(1);
+ if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
+ nViewShellId = pViewSh->GetViewShellId();
+ rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId );
+ }
+
+ aFormula = aFormula.copy(1, aFormula.getLength()-2);
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SetMarkArea( rOldRange );
+ aMark.SelectTable( nTab, true );
+ ScRange aNewRange( rOldRange.aStart, rNewEnd );
+
+ if ( DeleteContents( aMark, InsertDeleteFlags::CONTENTS, true, false/*bApi*/ ) )
+ {
+ // GRAM_API for API compatibility.
+ if (!EnterMatrix( aNewRange, &aMark, nullptr, aFormula, false/*bApi*/, false, OUString(), formula::FormulaGrammar::GRAM_API ))
+ {
+ // try to restore the previous state
+ EnterMatrix( rOldRange, &aMark, nullptr, aFormula, false/*bApi*/, false, OUString(), formula::FormulaGrammar::GRAM_API );
+ }
+ }
+
+ if (bUndo)
+ rDocShell.GetUndoManager()->LeaveListAction();
+}
+
+void ScDocFunc::InsertAreaLink( const OUString& rFile, const OUString& rFilter,
+ const OUString& rOptions, const OUString& rSource,
+ const ScRange& rDestRange, sal_Int32 nRefreshDelaySeconds,
+ bool bFitBlock, bool bApi )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bUndo (rDoc.IsUndoEnabled());
+
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+
+ // #i52120# if other area links exist at the same start position,
+ // remove them first (file format specifies only one link definition
+ // for a cell)
+
+ sal_uInt16 nLinkCount = pLinkManager->GetLinks().size();
+ sal_uInt16 nRemoved = 0;
+ sal_uInt16 nLinkPos = 0;
+ while (nLinkPos<nLinkCount)
+ {
+ ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[nLinkPos].get();
+ ScAreaLink* pLink = dynamic_cast<ScAreaLink*>(pBase);
+ if (pLink && pLink->GetDestArea().aStart == rDestRange.aStart)
+ {
+ if ( bUndo )
+ {
+ if ( !nRemoved )
+ {
+ // group all remove and the insert action
+ OUString aUndo = ScResId( STR_UNDO_INSERTAREALINK );
+ ViewShellId nViewShellId(-1);
+ if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
+ nViewShellId = pViewSh->GetViewShellId();
+ rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId );
+ }
+
+ ScAreaLink* pOldArea = static_cast<ScAreaLink*>(pBase);
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRemoveAreaLink>( &rDocShell,
+ pOldArea->GetFile(), pOldArea->GetFilter(), pOldArea->GetOptions(),
+ pOldArea->GetSource(), pOldArea->GetDestArea(), pOldArea->GetRefreshDelaySeconds() ) );
+ }
+ pLinkManager->Remove( pBase );
+ nLinkCount = pLinkManager->GetLinks().size();
+ ++nRemoved;
+ }
+ else
+ ++nLinkPos;
+ }
+
+ OUString aFilterName = rFilter;
+ OUString aNewOptions = rOptions;
+ if (aFilterName.isEmpty())
+ ScDocumentLoader::GetFilterName( rFile, aFilterName, aNewOptions, true, !bApi );
+
+ // remove application prefix from filter name here, so the filter options
+ // aren't reset when the filter name is changed in ScAreaLink::DataChanged
+ ScDocumentLoader::RemoveAppPrefix( aFilterName );
+
+ ScAreaLink* pLink = new ScAreaLink( &rDocShell, rFile, aFilterName,
+ aNewOptions, rSource, rDestRange, nRefreshDelaySeconds );
+ OUString aTmp = aFilterName;
+ pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, rFile, &aTmp, &rSource );
+
+ // Undo for an empty link
+
+ if (bUndo)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction( std::make_unique<ScUndoInsertAreaLink>( &rDocShell,
+ rFile, aFilterName, aNewOptions,
+ rSource, rDestRange, nRefreshDelaySeconds ) );
+ if ( nRemoved )
+ rDocShell.GetUndoManager()->LeaveListAction(); // undo for link update is still separate
+ }
+
+ // Update has its own undo
+ if (rDoc.IsExecuteLinkEnabled())
+ {
+ pLink->SetDoInsert(bFitBlock); // if applicable, don't insert anything on first update
+ pLink->Update(); // no SetInCreate -> carry out update
+ }
+ pLink->SetDoInsert(true); // Default = true
+
+ SfxBindings* pBindings = rDocShell.GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_LINKS );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); // Navigator
+}
+
+void ScDocFunc::ReplaceConditionalFormat( sal_uLong nOldFormat, std::unique_ptr<ScConditionalFormat> pFormat, SCTAB nTab, const ScRangeList& rRanges )
+{
+ ScDocShellModificator aModificator(rDocShell);
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if(rDoc.IsTabProtected(nTab))
+ return;
+
+ bool bUndo = rDoc.IsUndoEnabled();
+ ScDocumentUniquePtr pUndoDoc;
+ ScRange aCombinedRange = rRanges.Combine();
+ ScRange aCompleteRange;
+ if(bUndo)
+ {
+ pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+
+ if(pFormat)
+ {
+ aCompleteRange = aCombinedRange;
+ }
+ if(nOldFormat)
+ {
+ ScConditionalFormat* pOldFormat = rDoc.GetCondFormList(nTab)->GetFormat(nOldFormat);
+ if(pOldFormat)
+ aCompleteRange.ExtendTo(pOldFormat->GetRange().Combine());
+ }
+
+ rDoc.CopyToDocument(aCompleteRange.aStart.Col(),aCompleteRange.aStart.Row(),nTab,
+ aCompleteRange.aEnd.Col(),aCompleteRange.aEnd.Row(),nTab,
+ InsertDeleteFlags::ALL, false, *pUndoDoc);
+ }
+
+ std::unique_ptr<ScRange> pRepaintRange;
+ if(nOldFormat)
+ {
+ ScConditionalFormat* pOldFormat = rDoc.GetCondFormList(nTab)->GetFormat(nOldFormat);
+ if(pOldFormat)
+ {
+ pRepaintRange.reset(new ScRange( pOldFormat->GetRange().Combine() ));
+ rDoc.RemoveCondFormatData(pOldFormat->GetRange(), nTab, pOldFormat->GetKey());
+ }
+
+ rDoc.DeleteConditionalFormat(nOldFormat, nTab);
+ rDoc.SetStreamValid(nTab, false);
+ }
+ if(pFormat)
+ {
+ if(pRepaintRange)
+ pRepaintRange->ExtendTo(aCombinedRange);
+ else
+ pRepaintRange.reset(new ScRange(aCombinedRange));
+
+ sal_uLong nIndex = rDoc.AddCondFormat(std::move(pFormat), nTab);
+
+ rDoc.AddCondFormatData(rRanges, nTab, nIndex);
+ rDoc.SetStreamValid(nTab, false);
+ }
+
+ if(bUndo)
+ {
+ ScDocumentUniquePtr pRedoDoc(new ScDocument(SCDOCMODE_UNDO));
+ pRedoDoc->InitUndo( rDoc, nTab, nTab );
+ rDoc.CopyToDocument(aCompleteRange.aStart.Col(),aCompleteRange.aStart.Row(),nTab,
+ aCompleteRange.aEnd.Col(),aCompleteRange.aEnd.Row(),nTab,
+ InsertDeleteFlags::ALL, false, *pRedoDoc);
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoConditionalFormat>(&rDocShell, std::move(pUndoDoc), std::move(pRedoDoc), aCompleteRange));
+ }
+
+ if(pRepaintRange)
+ rDocShell.PostPaint(*pRepaintRange, PaintPartFlags::Grid);
+
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScAreasChanged));
+}
+
+void ScDocFunc::SetConditionalFormatList( ScConditionalFormatList* pList, SCTAB nTab )
+{
+ ScDocShellModificator aModificator(rDocShell);
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if(rDoc.IsTabProtected(nTab))
+ return;
+
+ bool bUndo = rDoc.IsUndoEnabled();
+ ScDocumentUniquePtr pUndoDoc;
+ if (bUndo)
+ {
+ pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+
+ ScConditionalFormatList* pOld = rDoc.GetCondFormList(nTab);
+
+ if (pOld)
+ pUndoDoc->SetCondFormList(new ScConditionalFormatList(*pUndoDoc, *pOld), nTab);
+ else
+ pUndoDoc->SetCondFormList(nullptr, nTab);
+
+ }
+
+ // first remove all old entries
+ ScConditionalFormatList* pOldList = rDoc.GetCondFormList(nTab);
+ pOldList->RemoveFromDocument(rDoc);
+
+ // then set new entries
+ pList->AddToDocument(rDoc);
+
+ rDoc.SetCondFormList(pList, nTab);
+ rDocShell.PostPaintGridAll();
+
+ if(bUndo)
+ {
+ ScDocumentUniquePtr pRedoDoc(new ScDocument(SCDOCMODE_UNDO));
+ pRedoDoc->InitUndo( rDoc, nTab, nTab );
+ pRedoDoc->SetCondFormList(new ScConditionalFormatList(*pRedoDoc, *pList), nTab);
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoConditionalFormatList>(&rDocShell, std::move(pUndoDoc), std::move(pRedoDoc), nTab));
+ }
+
+ rDoc.SetStreamValid(nTab, false);
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScAreasChanged));
+}
+
+void ScDocFunc::ConvertFormulaToValue( const ScRange& rRange, bool bInteraction )
+{
+ ScDocShellModificator aModificator(rDocShell);
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScEditableTester aTester(rDoc, rRange);
+ if (!aTester.IsEditable())
+ {
+ if (bInteraction)
+ rDocShell.ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ sc::TableValues aUndoVals(rRange);
+ sc::TableValues* pUndoVals = bRecord ? &aUndoVals : nullptr;
+
+ rDoc.ConvertFormulaToValue(rRange, pUndoVals);
+
+ if (bRecord && pUndoVals)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<sc::UndoFormulaToValue>(&rDocShell, *pUndoVals));
+ }
+
+ rDocShell.PostPaint(rRange, PaintPartFlags::Grid);
+ rDocShell.PostDataChanged();
+ rDoc.BroadcastCells(rRange, SfxHintId::ScDataChanged);
+ aModificator.SetDocumentModified();
+}
+
+void ScDocFunc::EnterListAction(TranslateId pNameResId)
+{
+ OUString aUndo(ScResId(pNameResId));
+ ViewShellId nViewShellId(-1);
+ if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
+ nViewShellId = pViewSh->GetViewShellId();
+ rDocShell.GetUndoManager()->EnterListAction( aUndo, aUndo, 0, nViewShellId );
+}
+
+void ScDocFunc::EndListAction()
+{
+ rDocShell.GetUndoManager()->LeaveListAction();
+}
+
+bool ScDocFunc::InsertSparklines(ScRange const& rDataRange, ScRange const& rSparklineRange,
+ std::shared_ptr<sc::SparklineGroup> pSparklineGroup)
+{
+ std::vector<sc::SparklineData> aSparklineDataVector;
+
+ if (rSparklineRange.aStart.Col() == rSparklineRange.aEnd.Col())
+ {
+ sal_Int32 nOutputRowSize = rSparklineRange.aEnd.Row() - rSparklineRange.aStart.Row();
+
+ auto eInputOrientation = sc::calculateOrientation(nOutputRowSize, rDataRange);
+
+ if (eInputOrientation == sc::RangeOrientation::Unknown)
+ return false;
+
+ sal_Int32 nIndex = 0;
+
+ for (ScAddress aAddress = rSparklineRange.aStart; aAddress.Row() <= rSparklineRange.aEnd.Row();
+ aAddress.IncRow())
+ {
+ ScRange aInputRangeSlice = rDataRange;
+ if (eInputOrientation == sc::RangeOrientation::Row)
+ {
+ aInputRangeSlice.aStart.SetRow(rDataRange.aStart.Row() + nIndex);
+ aInputRangeSlice.aEnd.SetRow(rDataRange.aStart.Row() + nIndex);
+ }
+ else
+ {
+ aInputRangeSlice.aStart.SetCol(rDataRange.aStart.Col() + nIndex);
+ aInputRangeSlice.aEnd.SetCol(rDataRange.aStart.Col() + nIndex);
+ }
+
+ aSparklineDataVector.emplace_back(aAddress, aInputRangeSlice);
+
+ nIndex++;
+ }
+ }
+ else if (rSparklineRange.aStart.Row() == rSparklineRange.aEnd.Row())
+ {
+ sal_Int32 nOutputColSize = rSparklineRange.aEnd.Col() - rSparklineRange.aStart.Col();
+
+ auto eInputOrientation = sc::calculateOrientation(nOutputColSize, rDataRange);
+
+ if (eInputOrientation == sc::RangeOrientation::Unknown)
+ return false;
+
+ sal_Int32 nIndex = 0;
+
+ for (ScAddress aAddress = rSparklineRange.aStart; aAddress.Col() <= rSparklineRange.aEnd.Col();
+ aAddress.IncCol())
+ {
+ ScRange aInputRangeSlice = rDataRange;
+ if (eInputOrientation == sc::RangeOrientation::Row)
+ {
+ aInputRangeSlice.aStart.SetRow(rDataRange.aStart.Row() + nIndex);
+ aInputRangeSlice.aEnd.SetRow(rDataRange.aStart.Row() + nIndex);
+ }
+ else
+ {
+ aInputRangeSlice.aStart.SetCol(rDataRange.aStart.Col() + nIndex);
+ aInputRangeSlice.aEnd.SetCol(rDataRange.aStart.Col() + nIndex);
+ }
+
+ aSparklineDataVector.emplace_back(aAddress, aInputRangeSlice);
+
+ nIndex++;
+ }
+ }
+
+ if (aSparklineDataVector.empty())
+ return false;
+
+ auto pUndoInsertSparkline = std::make_unique<sc::UndoInsertSparkline>(rDocShell, aSparklineDataVector, pSparklineGroup);
+ // insert the sparkline by "redoing"
+ pUndoInsertSparkline->Redo();
+ rDocShell.GetUndoManager()->AddUndoAction(std::move(pUndoInsertSparkline));
+
+ return true;
+}
+
+bool ScDocFunc::DeleteSparkline(ScAddress const& rAddress)
+{
+ auto& rDocument = rDocShell.GetDocument();
+
+ if (!rDocument.HasSparkline(rAddress))
+ return false;
+
+ auto pUndoDeleteSparkline = std::make_unique<sc::UndoDeleteSparkline>(rDocShell, rAddress);
+ // delete sparkline by "redoing"
+ pUndoDeleteSparkline->Redo();
+ rDocShell.GetUndoManager()->AddUndoAction(std::move(pUndoDeleteSparkline));
+
+ return true;
+}
+
+bool ScDocFunc::DeleteSparklineGroup(std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup, SCTAB nTab)
+{
+ if (!pSparklineGroup)
+ return false;
+
+ auto& rDocument = rDocShell.GetDocument();
+
+ if (!rDocument.HasTable(nTab))
+ return false;
+
+ auto pUndo = std::make_unique<sc::UndoDeleteSparklineGroup>(rDocShell, pSparklineGroup, nTab);
+ // delete sparkline group by "redoing"
+ pUndo->Redo();
+ rDocShell.GetUndoManager()->AddUndoAction(std::move(pUndo));
+ return true;
+}
+
+bool ScDocFunc::ChangeSparklineGroupAttributes(std::shared_ptr<sc::SparklineGroup> const& pExistingSparklineGroup,
+ sc::SparklineAttributes const& rNewAttributes)
+{
+ auto pUndo = std::make_unique<sc::UndoEditSparklneGroup>(rDocShell, pExistingSparklineGroup, rNewAttributes);
+ // change sparkline group attributes by "redoing"
+ pUndo->Redo();
+ rDocShell.GetUndoManager()->AddUndoAction(std::move(pUndo));
+ return true;
+}
+
+bool ScDocFunc::GroupSparklines(ScRange const& rRange, std::shared_ptr<sc::SparklineGroup> const& rpGroup)
+{
+ auto pUndo = std::make_unique<sc::UndoGroupSparklines>(rDocShell, rRange, rpGroup);
+ // group sparklines by "redoing"
+ pUndo->Redo();
+ rDocShell.GetUndoManager()->AddUndoAction(std::move(pUndo));
+ return true;
+}
+
+bool ScDocFunc::UngroupSparklines(ScRange const& rRange)
+{
+ auto pUndo = std::make_unique<sc::UndoUngroupSparklines>(rDocShell, rRange);
+ // ungroup sparklines by "redoing"
+ pUndo->Redo();
+ rDocShell.GetUndoManager()->AddUndoAction(std::move(pUndo));
+ return true;
+}
+
+bool ScDocFunc::ChangeSparkline(std::shared_ptr<sc::Sparkline> const& rpSparkline, SCTAB nTab, ScRangeList const& rDataRange)
+{
+ auto pUndo = std::make_unique<sc::UndoEditSparkline>(rDocShell, rpSparkline, nTab, rDataRange);
+ // change sparkline by "redoing"
+ pUndo->Redo();
+ rDocShell.GetUndoManager()->AddUndoAction(std::move(pUndo));
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docfuncutil.cxx b/sc/source/ui/docshell/docfuncutil.cxx
new file mode 100644
index 000000000..ce1a25d61
--- /dev/null
+++ b/sc/source/ui/docshell/docfuncutil.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 <docfuncutil.hxx>
+#include <document.hxx>
+#include <undobase.hxx>
+#include <global.hxx>
+#include <undoblk.hxx>
+#include <columnspanset.hxx>
+
+#include <memory>
+#include <utility>
+
+namespace sc {
+
+bool DocFuncUtil::hasProtectedTab( const ScDocument& rDoc, const ScMarkData& rMark )
+{
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (const auto& rTab : rMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (rDoc.IsTabProtected(rTab))
+ return true;
+ }
+
+ return false;
+}
+
+ScDocumentUniquePtr DocFuncUtil::createDeleteContentsUndoDoc(
+ ScDocument& rDoc, const ScMarkData& rMark, const ScRange& rRange,
+ InsertDeleteFlags nFlags, bool bOnlyMarked )
+{
+ ScDocumentUniquePtr pUndoDoc(new ScDocument(SCDOCMODE_UNDO));
+ SCTAB nTab = rRange.aStart.Tab();
+ pUndoDoc->InitUndo(rDoc, nTab, nTab);
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (const auto& rTab : rMark)
+ if (rTab != nTab)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ ScRange aCopyRange = rRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+
+ // in case of "Format/Standard" copy all attributes, because CopyToDocument
+ // with InsertDeleteFlags::HARDATTR only is too time-consuming:
+ InsertDeleteFlags nUndoDocFlags = nFlags;
+ if (nFlags & InsertDeleteFlags::ATTRIB)
+ nUndoDocFlags |= InsertDeleteFlags::ATTRIB;
+ if (nFlags & InsertDeleteFlags::EDITATTR) // Edit-Engine-Attribute
+ nUndoDocFlags |= InsertDeleteFlags::STRING; // -> cells will be changed
+ if (nFlags & InsertDeleteFlags::NOTE)
+ nUndoDocFlags |= InsertDeleteFlags::CONTENTS; // copy all cells with their notes
+ // do not copy note captions to undo document
+ nUndoDocFlags |= InsertDeleteFlags::NOCAPTIONS;
+ rDoc.CopyToDocument(aCopyRange, nUndoDocFlags, bOnlyMarked, *pUndoDoc, &rMark);
+
+ return pUndoDoc;
+}
+
+void DocFuncUtil::addDeleteContentsUndo(
+ SfxUndoManager* pUndoMgr, ScDocShell* pDocSh, const ScMarkData& rMark,
+ const ScRange& rRange, ScDocumentUniquePtr&& pUndoDoc, InsertDeleteFlags nFlags,
+ const std::shared_ptr<ScSimpleUndo::DataSpansType>& pSpans,
+ bool bMulti, bool bDrawUndo )
+{
+ std::unique_ptr<ScUndoDeleteContents> pUndo(
+ new ScUndoDeleteContents(
+ pDocSh, rMark, rRange, std::move(pUndoDoc), bMulti, nFlags, bDrawUndo));
+ pUndo->SetDataSpans(pSpans);
+
+ pUndoMgr->AddUndoAction(std::move(pUndo));
+}
+
+std::shared_ptr<ScSimpleUndo::DataSpansType> DocFuncUtil::getNonEmptyCellSpans(
+ const ScDocument& rDoc, const ScMarkData& rMark, const ScRange& rRange )
+{
+ auto pDataSpans = std::make_shared<ScSimpleUndo::DataSpansType>();
+ for (const SCTAB nTab : rMark)
+ {
+ SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
+ SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
+
+ std::pair<ScSimpleUndo::DataSpansType::iterator,bool> r =
+ pDataSpans->insert(std::make_pair(nTab, std::make_unique<sc::ColumnSpanSet>()));
+
+ if (r.second)
+ {
+ sc::ColumnSpanSet *const pSet = r.first->second.get();
+ pSet->scan(rDoc, nTab, nCol1, nRow1, nCol2, nRow2, true);
+ }
+ }
+
+ return pDataSpans;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docsh.cxx b/sc/source/ui/docshell/docsh.cxx
new file mode 100644
index 000000000..219101f72
--- /dev/null
+++ b/sc/source/ui/docshell/docsh.cxx
@@ -0,0 +1,3482 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <docsh.hxx>
+
+#include <config_features.h>
+#include <scitems.hxx>
+#include <sc.hrc>
+#include <vcl/errinf.hxx>
+#include <editeng/justifyitem.hxx>
+#include <comphelper/fileformat.h>
+#include <comphelper/classids.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <formula/errorcodes.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/syswin.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+#include <rtl/bootstrap.hxx>
+#include <rtl/tencinfo.h>
+#include <sal/log.hxx>
+#include <svl/PasswordHelper.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dinfdlg.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/event.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/documentlockfile.hxx>
+#include <svl/fstathelper.hxx>
+#include <svl/sharecontrolfile.hxx>
+#include <svl/urihelper.hxx>
+#include <osl/file.hxx>
+#include <chgtrack.hxx>
+#include <chgviset.hxx>
+#include <com/sun/star/awt/Key.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/document/UpdateDocMode.hpp>
+#include <com/sun/star/script/vba/VBAEventId.hpp>
+#include <com/sun/star/script/vba/VBAScriptEventId.hpp>
+#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
+#include <com/sun/star/script/vba/XVBAScriptListener.hpp>
+#include <com/sun/star/script/vba/XVBACompatibility.hpp>
+#include <com/sun/star/sheet/XSpreadsheetView.hpp>
+#include <com/sun/star/task/XJob.hpp>
+#include <com/sun/star/ui/theModuleUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/ui/XAcceleratorConfiguration.hpp>
+#include <com/sun/star/util/VetoException.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <ooo/vba/excel/XWorkbook.hpp>
+#include <tools/diagnose_ex.h>
+
+#include <config_folders.h>
+
+#include <scabstdlg.hxx>
+#include <sot/formats.hxx>
+#include <svx/dialogs.hrc>
+
+#include <formulacell.hxx>
+#include <global.hxx>
+#include <filter.hxx>
+#include <scmod.hxx>
+#include <tabvwsh.hxx>
+#include <docfunc.hxx>
+#include <imoptdlg.hxx>
+#include <impex.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <globstr.hrc>
+#include <scerrors.hxx>
+#include <brdcst.hxx>
+#include <stlpool.hxx>
+#include <autostyl.hxx>
+#include <attrib.hxx>
+#include <asciiopt.hxx>
+#include <progress.hxx>
+#include <pntlock.hxx>
+#include <docuno.hxx>
+#include <appoptio.hxx>
+#include <formulaopt.hxx>
+#include <scdll.hxx>
+#include <detdata.hxx>
+#include <printfun.hxx>
+#include <dociter.hxx>
+#include <cellform.hxx>
+#include <chartlis.hxx>
+#include <hints.hxx>
+#include <xmlwrap.hxx>
+#include <drwlayer.hxx>
+#include <dbdata.hxx>
+#include <scextopt.hxx>
+#include <compiler.hxx>
+#include <warnpassword.hxx>
+#include <optsolver.hxx>
+#include <sheetdata.hxx>
+#include <tabprotection.hxx>
+#include <docparam.hxx>
+#include "docshimp.hxx"
+#include <sizedev.hxx>
+#include <refreshtimerprotector.hxx>
+
+#include <officecfg/Office/Calc.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/tempfile.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <uiitems.hxx>
+#include <dpobject.hxx>
+#include <markdata.hxx>
+#include <docoptio.hxx>
+#include <orcusfilters.hxx>
+#include <datastream.hxx>
+#include <documentlinkmgr.hxx>
+#include <refupdatecontext.hxx>
+
+#include <memory>
+#include <vector>
+
+#include <comphelper/lok.hxx>
+#include <svtools/sfxecode.hxx>
+#include <unotools/pathoptions.hxx>
+
+using namespace com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::lang::XMultiServiceFactory;
+using std::shared_ptr;
+using ::std::vector;
+
+// Filter names (like in sclib.cxx)
+
+constexpr OUStringLiteral pFilterSc50 = u"StarCalc 5.0";
+const char pFilterXML[] = "StarOffice XML (Calc)";
+constexpr OUStringLiteral pFilterLotus = u"Lotus";
+const char pFilterQPro6[] = "Quattro Pro 6.0";
+const char16_t pFilterExcel4[] = u"MS Excel 4.0";
+const char16_t pFilterEx4Temp[] = u"MS Excel 4.0 Vorlage/Template";
+const char pFilterExcel5[] = "MS Excel 5.0/95";
+const char pFilterEx5Temp[] = "MS Excel 5.0/95 Vorlage/Template";
+const char pFilterExcel95[] = "MS Excel 95";
+const char pFilterEx95Temp[] = "MS Excel 95 Vorlage/Template";
+const char pFilterExcel97[] = "MS Excel 97";
+const char pFilterEx97Temp[] = "MS Excel 97 Vorlage/Template";
+constexpr OUStringLiteral pFilterDBase = u"dBase";
+constexpr OUStringLiteral pFilterDif = u"DIF";
+const char16_t pFilterSylk[] = u"SYLK";
+constexpr OUStringLiteral pFilterHtml = u"HTML (StarCalc)";
+constexpr OUStringLiteral pFilterHtmlWebQ = u"calc_HTML_WebQuery";
+const char16_t pFilterRtf[] = u"Rich Text Format (StarCalc)";
+
+#define ShellClass_ScDocShell
+#include <scslots.hxx>
+
+SFX_IMPL_INTERFACE(ScDocShell,SfxObjectShell)
+
+void ScDocShell::InitInterface_Impl()
+{
+}
+
+// GlobalName of the current version:
+SFX_IMPL_OBJECTFACTORY( ScDocShell, SvGlobalName(SO3_SC_CLASSID), "scalc" )
+
+
+void ScDocShell::FillClass( SvGlobalName* pClassName,
+ SotClipboardFormatId* pFormat,
+ OUString* pFullTypeName,
+ sal_Int32 nFileFormat,
+ bool bTemplate /* = false */) const
+{
+ if ( nFileFormat == SOFFICE_FILEFORMAT_60 )
+ {
+ *pClassName = SvGlobalName( SO3_SC_CLASSID_60 );
+ *pFormat = SotClipboardFormatId::STARCALC_60;
+ *pFullTypeName = ScResId( SCSTR_LONG_SCDOC_NAME_60 );
+ }
+ else if ( nFileFormat == SOFFICE_FILEFORMAT_8 )
+ {
+ *pClassName = SvGlobalName( SO3_SC_CLASSID_60 );
+ *pFormat = bTemplate ? SotClipboardFormatId::STARCALC_8_TEMPLATE : SotClipboardFormatId::STARCALC_8;
+ *pFullTypeName = ScResId( SCSTR_LONG_SCDOC_NAME_80 );
+ }
+ else
+ {
+ OSL_FAIL("Which version?");
+ }
+}
+
+std::set<Color> ScDocShell::GetDocColors()
+{
+ return m_pDocument->GetDocColors();
+}
+
+void ScDocShell::DoEnterHandler()
+{
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if (pViewSh && pViewSh->GetViewData().GetDocShell() == this)
+ SC_MOD()->InputEnterHandler();
+}
+
+SCTAB ScDocShell::GetSaveTab()
+{
+ SCTAB nTab = 0;
+ ScTabViewShell* pSh = GetBestViewShell();
+ if (pSh)
+ {
+ const ScMarkData& rMark = pSh->GetViewData().GetMarkData();
+ nTab = rMark.GetFirstSelected();
+ }
+ return nTab;
+}
+
+HiddenInformation ScDocShell::GetHiddenInformationState( HiddenInformation nStates )
+{
+ // get global state like HiddenInformation::DOCUMENTVERSIONS
+ HiddenInformation nState = SfxObjectShell::GetHiddenInformationState( nStates );
+
+ if ( nStates & HiddenInformation::RECORDEDCHANGES )
+ {
+ if ( m_pDocument->GetChangeTrack() && m_pDocument->GetChangeTrack()->GetFirst() )
+ nState |= HiddenInformation::RECORDEDCHANGES;
+ }
+ if ( nStates & HiddenInformation::NOTES )
+ {
+ SCTAB nTableCount = m_pDocument->GetTableCount();
+ bool bFound = false;
+ for (SCTAB nTab = 0; nTab < nTableCount && !bFound; ++nTab)
+ {
+ if (m_pDocument->HasTabNotes(nTab)) //TODO:
+ bFound = true;
+ }
+
+ if (bFound)
+ nState |= HiddenInformation::NOTES;
+ }
+
+ return nState;
+}
+
+void ScDocShell::BeforeXMLLoading()
+{
+ m_pDocument->EnableIdle(false);
+
+ // prevent unnecessary broadcasts and updates
+ OSL_ENSURE(m_pModificator == nullptr, "The Modificator should not exist");
+ m_pModificator.reset( new ScDocShellModificator( *this ) );
+
+ m_pDocument->SetImportingXML( true );
+ m_pDocument->EnableExecuteLink( false ); // #i101304# to be safe, prevent nested loading from external references
+ m_pDocument->EnableUndo( false );
+ // prevent unnecessary broadcasts and "half way listeners"
+ m_pDocument->SetInsertingFromOtherDoc( true );
+}
+
+void ScDocShell::AfterXMLLoading(bool bRet)
+{
+ if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER)
+ {
+ UpdateLinks();
+ // don't prevent establishing of listeners anymore
+ m_pDocument->SetInsertingFromOtherDoc( false );
+ if ( bRet )
+ {
+ ScChartListenerCollection* pChartListener = m_pDocument->GetChartListenerCollection();
+ if (pChartListener)
+ pChartListener->UpdateDirtyCharts();
+
+ // #95582#; set the table names of linked tables to the new path
+ SCTAB nTabCount = m_pDocument->GetTableCount();
+ for (SCTAB i = 0; i < nTabCount; ++i)
+ {
+ if (m_pDocument->IsLinked( i ))
+ {
+ OUString aName;
+ m_pDocument->GetName(i, aName);
+ OUString aLinkTabName = m_pDocument->GetLinkTab(i);
+ sal_Int32 nLinkTabNameLength = aLinkTabName.getLength();
+ sal_Int32 nNameLength = aName.getLength();
+ if (nLinkTabNameLength < nNameLength)
+ {
+
+ // remove the quotes on begin and end of the docname and restore the escaped quotes
+ const sal_Unicode* pNameBuffer = aName.getStr();
+ if ( *pNameBuffer == '\'' && // all docnames have to have a ' character on the first pos
+ ScGlobal::UnicodeStrChr( pNameBuffer, SC_COMPILER_FILE_TAB_SEP ) )
+ {
+ OUStringBuffer aDocURLBuffer;
+ bool bQuote = true; // Document name is always quoted
+ ++pNameBuffer;
+ while ( bQuote && *pNameBuffer )
+ {
+ if ( *pNameBuffer == '\'' && *(pNameBuffer-1) != '\\' )
+ bQuote = false;
+ else if( *pNameBuffer != '\\' || *(pNameBuffer+1) != '\'' )
+ aDocURLBuffer.append(*pNameBuffer); // If escaped quote: only quote in the name
+ ++pNameBuffer;
+ }
+
+ if( *pNameBuffer == SC_COMPILER_FILE_TAB_SEP ) // after the last quote of the docname should be the # char
+ {
+ sal_Int32 nIndex = nNameLength - nLinkTabNameLength;
+ INetURLObject aINetURLObject(aDocURLBuffer);
+ if(aName.match( aLinkTabName, nIndex) &&
+ (aName[nIndex - 1] == '#') && // before the table name should be the # char
+ !aINetURLObject.HasError()) // the docname should be a valid URL
+ {
+ aName = ScGlobal::GetDocTabName( m_pDocument->GetLinkDoc( i ), m_pDocument->GetLinkTab( i ) );
+ m_pDocument->RenameTab(i, aName, true/*bExternalDocument*/);
+ }
+ // else; nothing has to happen, because it is a user given name
+ }
+ // else; nothing has to happen, because it is a user given name
+ }
+ // else; nothing has to happen, because it is a user given name
+ }
+ // else; nothing has to happen, because it is a user given name
+ }
+ }
+
+ // #i94570# DataPilot table names have to be unique, or the tables can't be accessed by API.
+ // If no name (or an invalid name, skipped in ScXMLDataPilotTableContext::EndElement) was set, create a new name.
+ ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
+ if ( pDPCollection )
+ {
+ size_t nDPCount = pDPCollection->GetCount();
+ for (size_t nDP=0; nDP<nDPCount; ++nDP)
+ {
+ ScDPObject& rDPObj = (*pDPCollection)[nDP];
+ if (rDPObj.GetName().isEmpty())
+ rDPObj.SetName( pDPCollection->CreateNewName() );
+ }
+ }
+ }
+ }
+ else
+ m_pDocument->SetInsertingFromOtherDoc( false );
+
+ m_pDocument->SetImportingXML( false );
+ m_pDocument->EnableExecuteLink( true );
+ m_pDocument->EnableUndo( true );
+ m_bIsEmpty = false;
+
+ if (m_pModificator)
+ {
+ ScDocument::HardRecalcState eRecalcState = m_pDocument->GetHardRecalcState();
+ // Temporarily set hard-recalc to prevent calling
+ // ScFormulaCell::Notify() during destruction of the Modificator which
+ // will set the cells dirty.
+ if (eRecalcState == ScDocument::HardRecalcState::OFF)
+ m_pDocument->SetHardRecalcState(ScDocument::HardRecalcState::TEMPORARY);
+ m_pModificator.reset();
+ m_pDocument->SetHardRecalcState(eRecalcState);
+ }
+ else
+ {
+ OSL_FAIL("The Modificator should exist");
+ }
+
+ m_pDocument->EnableIdle(true);
+}
+
+namespace {
+
+class LoadMediumGuard
+{
+public:
+ explicit LoadMediumGuard(ScDocument* pDoc) :
+ mpDoc(pDoc)
+ {
+ mpDoc->SetLoadingMedium(true);
+ }
+
+ ~LoadMediumGuard()
+ {
+ mpDoc->SetLoadingMedium(false);
+ }
+private:
+ ScDocument* mpDoc;
+};
+
+void processDataStream( ScDocShell& rShell, const sc::ImportPostProcessData& rData )
+{
+ if (!rData.mpDataStream)
+ return;
+
+ const sc::ImportPostProcessData::DataStream& r = *rData.mpDataStream;
+ if (!r.maRange.IsValid())
+ return;
+
+ // Break the streamed range into the top range and the height limit. A
+ // height limit of 0 means unlimited i.e. the streamed data will go all
+ // the way to the last row.
+
+ ScRange aTopRange = r.maRange;
+ aTopRange.aEnd.SetRow(aTopRange.aStart.Row());
+ sal_Int32 nLimit = r.maRange.aEnd.Row() - r.maRange.aStart.Row() + 1;
+ if (r.maRange.aEnd.Row() == rShell.GetDocument().MaxRow())
+ // Unlimited range.
+ nLimit = 0;
+
+ sc::DataStream::MoveType eMove =
+ r.meInsertPos == sc::ImportPostProcessData::DataStream::InsertTop ?
+ sc::DataStream::MOVE_DOWN : sc::DataStream::RANGE_DOWN;
+
+ sc::DataStream* pStrm = new sc::DataStream(&rShell, r.maURL, aTopRange, nLimit, eMove, 0);
+ pStrm->SetRefreshOnEmptyLine(r.mbRefreshOnEmpty);
+ sc::DocumentLinkManager& rMgr = rShell.GetDocument().GetDocLinkManager();
+ rMgr.setDataStream(pStrm);
+}
+
+class MessageWithCheck : public weld::MessageDialogController
+{
+private:
+ std::unique_ptr<weld::CheckButton> m_xWarningOnBox;
+public:
+ MessageWithCheck(weld::Window *pParent, const OUString& rUIFile, const OString& rDialogId)
+ : MessageDialogController(pParent, rUIFile, rDialogId, "ask")
+ , m_xWarningOnBox(m_xBuilder->weld_check_button("ask"))
+ {
+ }
+ bool get_active() const { return m_xWarningOnBox->get_active(); }
+ void hide_ask() const { m_xWarningOnBox->set_visible(false); };
+};
+
+#if HAVE_FEATURE_SCRIPTING
+class VBAScriptListener : public ::cppu::WeakImplHelper< css::script::vba::XVBAScriptListener >
+{
+private:
+ ScDocShell* m_pDocSh;
+public:
+ VBAScriptListener(ScDocShell* pDocSh) : m_pDocSh(pDocSh)
+ {
+ }
+
+ // XVBAScriptListener
+ virtual void SAL_CALL notifyVBAScriptEvent( const ::css::script::vba::VBAScriptEvent& aEvent ) override
+ {
+ if (aEvent.Identifier == script::vba::VBAScriptEventId::SCRIPT_STOPPED &&
+ m_pDocSh->GetClipData().is())
+ {
+ m_pDocSh->SetClipData(uno::Reference<datatransfer::XTransferable2>());
+ }
+ }
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const ::css::lang::EventObject& /*Source*/ ) override
+ {
+ }
+};
+#endif
+
+}
+
+bool ScDocShell::LoadXML( SfxMedium* pLoadMedium, const css::uno::Reference< css::embed::XStorage >& xStor )
+{
+ LoadMediumGuard aLoadGuard(m_pDocument.get());
+
+ // MacroCallMode is no longer needed, state is kept in SfxObjectShell now
+
+ // no Seek(0) here - always loading from storage, GetInStream must not be called
+
+ BeforeXMLLoading();
+
+ ScXMLImportWrapper aImport(*this, pLoadMedium, xStor);
+
+ bool bRet = false;
+ ErrCode nError = ERRCODE_NONE;
+ m_pDocument->LockAdjustHeight();
+ if (GetCreateMode() == SfxObjectCreateMode::ORGANIZER)
+ bRet = aImport.Import(ImportFlags::Styles, nError);
+ else
+ bRet = aImport.Import(ImportFlags::All, nError);
+
+ if ( nError )
+ pLoadMedium->SetError(nError);
+
+ processDataStream(*this, aImport.GetImportPostProcessData());
+
+ //if the document was not generated by LibreOffice, do hard recalc in case some other document
+ //generator saved cached formula results that differ from LibreOffice's calculated results or
+ //did not use cached formula results.
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
+
+ ScRecalcOptions nRecalcMode =
+ static_cast<ScRecalcOptions>(officecfg::Office::Calc::Formula::Load::ODFRecalcMode::get());
+
+ bool bHardRecalc = false;
+ if (nRecalcMode == RECALC_ASK)
+ {
+ OUString sProductName(utl::ConfigManager::getProductName());
+ if (m_pDocument->IsUserInteractionEnabled() && xDocProps->getGenerator().indexOf(sProductName) == -1)
+ {
+ // Generator is not LibreOffice. Ask if the user wants to perform
+ // full re-calculation.
+ MessageWithCheck aQueryBox(GetActiveDialogParent(),
+ "modules/scalc/ui/recalcquerydialog.ui", "RecalcQueryDialog");
+ aQueryBox.set_primary_text(ScResId(STR_QUERY_FORMULA_RECALC_ONLOAD_ODS));
+ aQueryBox.set_default_response(RET_YES);
+
+ if ( officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() )
+ aQueryBox.hide_ask();
+
+ bHardRecalc = aQueryBox.run() == RET_YES;
+
+ if (aQueryBox.get_active())
+ {
+ // Always perform selected action in the future.
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Calc::Formula::Load::ODFRecalcMode::set(sal_Int32(0), batch);
+ ScFormulaOptions aOpt = SC_MOD()->GetFormulaOptions();
+ aOpt.SetODFRecalcOptions(bHardRecalc ? RECALC_ALWAYS : RECALC_NEVER);
+ /* XXX is this really supposed to set the ScModule options?
+ * Not the ScDocShell options? */
+ SC_MOD()->SetFormulaOptions(aOpt);
+
+ batch->commit();
+ }
+ }
+ }
+ else if (nRecalcMode == RECALC_ALWAYS)
+ bHardRecalc = true;
+
+ if (bHardRecalc)
+ DoHardRecalc();
+ else
+ {
+ // still need to recalc volatile formula cells.
+ m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
+ }
+
+ AfterXMLLoading(bRet);
+
+ m_pDocument->UnlockAdjustHeight();
+ return bRet;
+}
+
+bool ScDocShell::SaveXML( SfxMedium* pSaveMedium, const css::uno::Reference< css::embed::XStorage >& xStor )
+{
+ m_pDocument->EnableIdle(false);
+
+ ScXMLImportWrapper aImport(*this, pSaveMedium, xStor);
+ bool bRet(false);
+ if (GetCreateMode() != SfxObjectCreateMode::ORGANIZER)
+ bRet = aImport.Export(false);
+ else
+ bRet = aImport.Export(true);
+
+ m_pDocument->EnableIdle(true);
+
+ return bRet;
+}
+
+bool ScDocShell::Load( SfxMedium& rMedium )
+{
+ LoadMediumGuard aLoadGuard(m_pDocument.get());
+ ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
+
+ // only the latin script language is loaded
+ // -> initialize the others from options (before loading)
+ InitOptions(true);
+
+ // 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))
+ {
+ if (m_pDocument->GetDrawLayer())
+ m_pDocument->GetDrawLayer()->SetAnchoredTextOverflowLegacy(true);
+ }
+
+ GetUndoManager()->Clear();
+
+ bool bRet = SfxObjectShell::Load(rMedium);
+ if (bRet)
+ {
+ SetInitialLinkUpdate(&rMedium);
+
+ {
+ // prepare a valid document for XML filter
+ // (for ConvertFrom, InitNew is called before)
+ m_pDocument->MakeTable(0);
+ m_pDocument->GetStyleSheetPool()->CreateStandardStyles();
+ m_pDocument->UpdStlShtPtrsFrmNms();
+
+ if (!m_bUcalcTest)
+ {
+ /* Create styles that are imported through Orcus */
+
+ OUString aURL("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/calc/styles.xml");
+ rtl::Bootstrap::expandMacros(aURL);
+
+ OUString aPath;
+ osl::FileBase::getSystemPathFromFileURL(aURL, aPath);
+
+ ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
+
+ if (pOrcus)
+ {
+ pOrcus->importODS_Styles(*m_pDocument, aPath);
+ m_pDocument->GetStyleSheetPool()->setAllParaStandard();
+ }
+ }
+
+ bRet = LoadXML( &rMedium, nullptr );
+ }
+ }
+
+ if (!bRet && !rMedium.GetError())
+ rMedium.SetError(SVSTREAM_FILEFORMAT_ERROR);
+
+ if (rMedium.GetError())
+ SetError(rMedium.GetError());
+
+ InitItems();
+ CalcOutputFactor();
+
+ // invalidate eventually temporary table areas
+ if ( bRet )
+ m_pDocument->InvalidateTableArea();
+
+ m_bIsEmpty = false;
+ FinishedLoading();
+ return bRet;
+}
+
+void ScDocShell::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const ScTablesHint* pScHint = dynamic_cast< const ScTablesHint* >( &rHint );
+ if (pScHint)
+ {
+ if (pScHint->GetTablesHintId() == SC_TAB_INSERTED)
+ {
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents = m_pDocument->GetVbaEventProcessor();
+ if ( xVbaEvents.is() ) try
+ {
+ uno::Sequence< uno::Any > aArgs{ uno::Any(pScHint->GetTab1()) };
+ xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_NEWSHEET, aArgs );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ }
+
+ if ( auto pStyleSheetHint = dynamic_cast<const SfxStyleSheetHint*>(&rHint) ) // Template changed
+ NotifyStyle( *pStyleSheetHint );
+ else if ( auto pStlHint = dynamic_cast<const ScAutoStyleHint*>(&rHint) )
+ {
+ //! direct call for AutoStyles
+
+ // this is called synchronously from ScInterpreter::ScStyle,
+ // modifying the document must be asynchronous
+ // (handled by AddInitial)
+
+ const ScRange& aRange = pStlHint->GetRange();
+ const OUString& aName1 = pStlHint->GetStyle1();
+ const OUString& aName2 = pStlHint->GetStyle2();
+ sal_uInt32 nTimeout = pStlHint->GetTimeout();
+
+ if (!m_pAutoStyleList)
+ m_pAutoStyleList.reset( new ScAutoStyleList(this) );
+ m_pAutoStyleList->AddInitial( aRange, aName1, nTimeout, aName2 );
+ }
+ else if ( auto pEventHint = dynamic_cast<const SfxEventHint*>(&rHint) )
+ {
+ SfxEventHintId nEventId = pEventHint->GetEventId();
+
+ switch ( nEventId )
+ {
+ case SfxEventHintId::LoadFinished:
+ {
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+ // the readonly documents should not be opened in shared mode
+ if ( HasSharedXMLFlagSet() && !SC_MOD()->IsInSharedDocLoading() && !IsReadOnly() )
+ {
+ if ( SwitchToShared( true, false ) )
+ {
+ ScViewData* pViewData = GetViewData();
+ ScTabView* pTabView = ( pViewData ? pViewData->GetView() : nullptr );
+ if ( pTabView )
+ {
+ pTabView->UpdateLayerLocks();
+ }
+ }
+ else
+ {
+ // switching to shared mode has failed, the document should be opened readonly
+ // TODO/LATER: And error message should be shown here probably
+ SetReadOnlyUI();
+ }
+ }
+#endif
+ }
+ break;
+ case SfxEventHintId::ViewCreated:
+ {
+ #if HAVE_FEATURE_SCRIPTING
+ uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY);
+ if ( !m_xVBAListener.is() && xVBACompat.is() )
+ {
+ m_xVBAListener.set(new VBAScriptListener(this));
+ xVBACompat->addVBAScriptListener(m_xVBAListener);
+ }
+#endif
+
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+ if ( IsDocShared() && !SC_MOD()->IsInSharedDocLoading() )
+ {
+ ScAppOptions aAppOptions = SC_MOD()->GetAppOptions();
+ if ( aAppOptions.GetShowSharedDocumentWarning() )
+ {
+ MessageWithCheck aWarningBox(ScDocShell::GetActiveDialogParent(),
+ "modules/scalc/ui/sharedwarningdialog.ui", "SharedWarningDialog");
+ aWarningBox.run();
+
+ bool bChecked = aWarningBox.get_active();
+ if (bChecked)
+ {
+ aAppOptions.SetShowSharedDocumentWarning(false);
+ SC_MOD()->SetAppOptions( aAppOptions );
+ }
+ }
+ }
+#endif
+ try
+ {
+ uno::Reference< uno::XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+ uno::Reference< lang::XMultiServiceFactory > xServiceManager(
+ xContext->getServiceManager(),
+ uno::UNO_QUERY_THROW );
+ uno::Reference< container::XContentEnumerationAccess > xEnumAccess( xServiceManager, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XEnumeration> xEnum = xEnumAccess->createContentEnumeration(
+ "com.sun.star.sheet.SpreadsheetDocumentJob" );
+ if ( xEnum.is() )
+ {
+ while ( xEnum->hasMoreElements() )
+ {
+ uno::Any aAny = xEnum->nextElement();
+ uno::Reference< lang::XSingleComponentFactory > xFactory;
+ aAny >>= xFactory;
+ if ( xFactory.is() )
+ {
+ uno::Reference< task::XJob > xJob( xFactory->createInstanceWithContext( xContext ), uno::UNO_QUERY_THROW );
+ ScViewData* pViewData = GetViewData();
+ SfxViewShell* pViewShell = ( pViewData ? pViewData->GetViewShell() : nullptr );
+ SfxViewFrame* pViewFrame = ( pViewShell ? pViewShell->GetViewFrame() : nullptr );
+ SfxFrame* pFrame = ( pViewFrame ? &pViewFrame->GetFrame() : nullptr );
+ uno::Reference< frame::XController > xController = ( pFrame ? pFrame->GetController() : nullptr );
+ uno::Reference< sheet::XSpreadsheetView > xSpreadsheetView( xController, uno::UNO_QUERY_THROW );
+ uno::Sequence< beans::NamedValue > aArgsForJob { { "SpreadsheetView", uno::Any( xSpreadsheetView ) } };
+ xJob->execute( aArgsForJob );
+ }
+ }
+ }
+ }
+ catch ( uno::Exception & )
+ {
+ }
+ }
+ break;
+ case SfxEventHintId::SaveDoc:
+ {
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+ if ( IsDocShared() && !SC_MOD()->IsInSharedDocSaving() )
+ {
+ bool bSuccess = false;
+ bool bRetry = true;
+ while ( bRetry )
+ {
+ bRetry = false;
+ uno::Reference< frame::XModel > xModel;
+ try
+ {
+ // load shared file
+ xModel.set( LoadSharedDocument(), uno::UNO_SET_THROW );
+ uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY_THROW );
+
+ // check if shared flag is set in shared file
+ bool bShared = false;
+ ScModelObj* pDocObj = comphelper::getFromUnoTunnel<ScModelObj>( xModel );
+ ScDocShell* pSharedDocShell = ( pDocObj ? dynamic_cast< ScDocShell* >( pDocObj->GetObjectShell() ) : nullptr );
+ if ( pSharedDocShell )
+ {
+ bShared = pSharedDocShell->HasSharedXMLFlagSet();
+ }
+
+ // #i87870# check if shared status was disabled and enabled again
+ bool bOwnEntry = false;
+ bool bEntriesNotAccessible = false;
+ try
+ {
+ ::svt::ShareControlFile aControlFile( GetSharedFileURL() );
+ bOwnEntry = aControlFile.HasOwnEntry();
+ }
+ catch ( uno::Exception& )
+ {
+ bEntriesNotAccessible = true;
+ }
+
+ if ( bShared && bOwnEntry )
+ {
+ uno::Reference< frame::XStorable > xStorable( xModel, uno::UNO_QUERY_THROW );
+
+ if ( xStorable->isReadonly() )
+ {
+ xCloseable->close( true );
+
+ OUString aUserName( ScResId( STR_UNKNOWN_USER ) );
+ bool bNoLockAccess = false;
+ try
+ {
+ ::svt::DocumentLockFile aLockFile( GetSharedFileURL() );
+ LockFileEntry aData = aLockFile.GetLockData();
+ if ( !aData[LockFileComponent::OOOUSERNAME].isEmpty() )
+ {
+ aUserName = aData[LockFileComponent::OOOUSERNAME];
+ }
+ else if ( !aData[LockFileComponent::SYSUSERNAME].isEmpty() )
+ {
+ aUserName = aData[LockFileComponent::SYSUSERNAME];
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ bNoLockAccess = true;
+ }
+
+ if ( bNoLockAccess )
+ {
+ // TODO/LATER: in future an error regarding impossibility to open file for writing could be shown
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ }
+ else
+ {
+ OUString aMessage( ScResId( STR_FILE_LOCKED_SAVE_LATER ) );
+ aMessage = aMessage.replaceFirst( "%1", aUserName );
+
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
+ VclMessageType::Warning, VclButtonsType::NONE,
+ aMessage));
+ xWarn->add_button(GetStandardText(StandardButtonType::Retry), RET_RETRY);
+ xWarn->add_button(GetStandardText(StandardButtonType::Cancel), RET_CANCEL);
+ xWarn->set_default_response(RET_RETRY);
+ if (xWarn->run() == RET_RETRY)
+ {
+ bRetry = true;
+ }
+ }
+ }
+ else
+ {
+ // merge changes from shared file into temp file
+ bool bSaveToShared = false;
+ if ( pSharedDocShell )
+ {
+ bSaveToShared = MergeSharedDocument( pSharedDocShell );
+ }
+
+ // close shared file
+ xCloseable->close( true );
+
+ // TODO: keep file lock on shared file
+
+ // store to shared file
+ if ( bSaveToShared )
+ {
+ bool bChangedViewSettings = false;
+ ScChangeViewSettings* pChangeViewSet = m_pDocument->GetChangeViewSettings();
+ if ( pChangeViewSet && pChangeViewSet->ShowChanges() )
+ {
+ pChangeViewSet->SetShowChanges( false );
+ pChangeViewSet->SetShowAccepted( false );
+ m_pDocument->SetChangeViewSettings( *pChangeViewSet );
+ bChangedViewSettings = true;
+ }
+
+ uno::Reference< frame::XStorable > xStor( GetModel(), uno::UNO_QUERY_THROW );
+ // TODO/LATER: More entries from the MediaDescriptor might be interesting for the merge
+ uno::Sequence< beans::PropertyValue > aValues{
+ comphelper::makePropertyValue(
+ "FilterName",
+ GetMedium()->GetFilter()->GetFilterName())
+ };
+
+ const SfxStringItem* pPasswordItem = SfxItemSet::GetItem<SfxStringItem>(GetMedium()->GetItemSet(), SID_PASSWORD, false);
+ if ( pPasswordItem && !pPasswordItem->GetValue().isEmpty() )
+ {
+ aValues.realloc( 2 );
+ auto pValues = aValues.getArray();
+ pValues[1].Name = "Password";
+ pValues[1].Value <<= pPasswordItem->GetValue();
+ }
+ const SfxUnoAnyItem* pEncryptionItem = SfxItemSet::GetItem<SfxUnoAnyItem>(GetMedium()->GetItemSet(), SID_ENCRYPTIONDATA, false);
+ if (pEncryptionItem)
+ {
+ aValues.realloc(aValues.getLength() + 1);
+ auto pValues = aValues.getArray();
+ pValues[aValues.getLength() - 1].Name = "EncryptionData";
+ pValues[aValues.getLength() - 1].Value = pEncryptionItem->GetValue();
+ }
+
+ SC_MOD()->SetInSharedDocSaving( true );
+ xStor->storeToURL( GetSharedFileURL(), aValues );
+ SC_MOD()->SetInSharedDocSaving( false );
+
+ if ( bChangedViewSettings )
+ {
+ pChangeViewSet->SetShowChanges( true );
+ pChangeViewSet->SetShowAccepted( true );
+ m_pDocument->SetChangeViewSettings( *pChangeViewSet );
+ }
+ }
+
+ bSuccess = true;
+ GetUndoManager()->Clear();
+ }
+ }
+ else
+ {
+ xCloseable->close( true );
+
+ if ( bEntriesNotAccessible )
+ {
+ // TODO/LATER: in future an error regarding impossibility to write to share control file could be shown
+ ErrorHandler::HandleError( ERRCODE_IO_GENERAL );
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(STR_DOC_NOLONGERSHARED)));
+ xWarn->run();
+
+ SfxBindings* pBindings = GetViewBindings();
+ if ( pBindings )
+ {
+ pBindings->ExecuteSynchron( SID_SAVEASDOC );
+ }
+ }
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "SfxEventHintId::SaveDoc" );
+ SC_MOD()->SetInSharedDocSaving( false );
+
+ try
+ {
+ uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW );
+ xClose->close( true );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ }
+
+ if ( !bSuccess )
+ SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
+ }
+#endif
+
+ if (m_pSheetSaveData)
+ m_pSheetSaveData->SetInSupportedSave(true);
+ }
+ break;
+ case SfxEventHintId::SaveAsDoc:
+ {
+ if ( GetDocument().GetExternalRefManager()->containsUnsavedReferences() )
+ {
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
+ VclMessageType::Warning, VclButtonsType::YesNo,
+ ScResId(STR_UNSAVED_EXT_REF)));
+ if (RET_NO == xWarn->run())
+ {
+ SetError(ERRCODE_IO_ABORT); // this error code will produce no error message, but will break the further saving process
+ }
+ }
+ [[fallthrough]];
+ }
+ case SfxEventHintId::SaveToDoc:
+ // #i108978# If no event is sent before saving, there will also be no "...DONE" event,
+ // and SAVE/SAVEAS can't be distinguished from SAVETO. So stream copying is only enabled
+ // if there is a SAVE/SAVEAS/SAVETO event first.
+ if (m_pSheetSaveData)
+ m_pSheetSaveData->SetInSupportedSave(true);
+ break;
+ case SfxEventHintId::SaveDocDone:
+ case SfxEventHintId::SaveAsDocDone:
+ {
+ // new positions are used after "save" and "save as", but not "save to"
+ UseSheetSaveEntries(); // use positions from saved file for next saving
+ [[fallthrough]];
+ }
+ case SfxEventHintId::SaveToDocDone:
+ // only reset the flag, don't use the new positions
+ if (m_pSheetSaveData)
+ m_pSheetSaveData->SetInSupportedSave(false);
+ break;
+ default:
+ {
+ }
+ break;
+ }
+ }
+ else if (rHint.GetId() == SfxHintId::TitleChanged) // Without parameter
+ {
+ m_pDocument->SetName( SfxShell::GetName() );
+ // RegisterNewTargetNames doesn't exist any longer
+ SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDocNameChanged )); // Navigator
+ }
+ else if (rHint.GetId() == SfxHintId::Deinitializing)
+ {
+
+#if HAVE_FEATURE_SCRIPTING
+ uno::Reference<script::vba::XVBACompatibility> xVBACompat(GetBasicContainer(), uno::UNO_QUERY);
+ if (m_xVBAListener.is() && xVBACompat.is())
+ {
+ xVBACompat->removeVBAScriptListener(m_xVBAListener);
+ }
+#endif
+
+ if (m_pDocument->IsClipboardSource())
+ {
+ // Notes copied to the clipboard have a raw SdrCaptionObj pointer
+ // copied from this document, forget it as it references this
+ // document's drawing layer pages and what not, which otherwise when
+ // pasting to another document after this document was destructed would
+ // attempt to access non-existing data. Preserve the text data though.
+ ScDocument* pClipDoc = ScModule::GetClipDoc();
+ if (pClipDoc)
+ pClipDoc->ClosingClipboardSource();
+ }
+ }
+
+ const SfxEventHint* pSfxEventHint = dynamic_cast<const SfxEventHint*>(&rHint);
+ if (!pSfxEventHint)
+ return;
+
+ switch( pSfxEventHint->GetEventId() )
+ {
+ case SfxEventHintId::CreateDoc:
+ {
+ uno::Any aWorkbook;
+ aWorkbook <<= mxAutomationWorkbookObject;
+ uno::Sequence< uno::Any > aArgs{ aWorkbook };
+ SC_MOD()->CallAutomationApplicationEventSinks( "NewWorkbook", aArgs );
+ }
+ break;
+ case SfxEventHintId::OpenDoc:
+ {
+ uno::Any aWorkbook;
+ aWorkbook <<= mxAutomationWorkbookObject;
+ uno::Sequence< uno::Any > aArgs{ aWorkbook };
+ SC_MOD()->CallAutomationApplicationEventSinks( "WorkbookOpen", aArgs );
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+// Load contents for organizer
+bool ScDocShell::LoadFrom( SfxMedium& rMedium )
+{
+ LoadMediumGuard aLoadGuard(m_pDocument.get());
+ ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
+
+ weld::WaitObject aWait( GetActiveDialogParent() );
+
+ bool bRet = false;
+
+ SetInitialLinkUpdate(&rMedium);
+
+ // until loading/saving only the styles in XML is implemented,
+ // load the whole file
+ bRet = LoadXML( &rMedium, nullptr );
+ InitItems();
+
+ SfxObjectShell::LoadFrom( rMedium );
+
+ return bRet;
+}
+
+static void lcl_parseHtmlFilterOption(const OUString& rOption, LanguageType& rLang, bool& rDateConvert)
+{
+ OUStringBuffer aBuf;
+ std::vector< OUString > aTokens;
+ sal_Int32 n = rOption.getLength();
+ const sal_Unicode* p = rOption.getStr();
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ const sal_Unicode c = p[i];
+ if (c == ' ')
+ {
+ if (!aBuf.isEmpty())
+ aTokens.push_back( aBuf.makeStringAndClear() );
+ }
+ else
+ aBuf.append(c);
+ }
+
+ if (!aBuf.isEmpty())
+ aTokens.push_back( aBuf.makeStringAndClear() );
+
+ rLang = LanguageType( 0 );
+ rDateConvert = false;
+
+ if (!aTokens.empty())
+ rLang = static_cast<LanguageType>(aTokens[0].toInt32());
+ if (aTokens.size() > 1)
+ rDateConvert = static_cast<bool>(aTokens[1].toInt32());
+}
+
+bool ScDocShell::ConvertFrom( SfxMedium& rMedium )
+{
+ LoadMediumGuard aLoadGuard(m_pDocument.get());
+
+ bool bRet = false; // sal_False means user quit!
+ // On error: Set error at stream
+
+ ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
+
+ GetUndoManager()->Clear();
+
+ // Set optimal col width after import?
+ bool bSetColWidths = false;
+ bool bSetSimpleTextColWidths = false;
+ std::map<SCCOL, ScColWidthParam> aColWidthParam;
+ ScRange aColWidthRange;
+ // Set optimal row height after import?
+ bool bSetRowHeights = false;
+
+ vector<ScDocRowHeightUpdater::TabRanges> aRecalcRowRangesArray;
+
+ // All filters need the complete file in one piece (not asynchronously)
+ // So make sure that we transfer the whole file with CreateFileStream
+ rMedium.GetPhysicalName(); //! Call CreateFileStream directly, if available
+
+ SetInitialLinkUpdate(&rMedium);
+
+ std::shared_ptr<const SfxFilter> pFilter = rMedium.GetFilter();
+ if (pFilter)
+ {
+ OUString aFltName = pFilter->GetFilterName();
+
+ bool bCalc3 = aFltName == "StarCalc 3.0";
+ bool bCalc4 = aFltName == "StarCalc 4.0";
+ if (!bCalc3 && !bCalc4)
+ m_pDocument->SetInsertingFromOtherDoc( true );
+
+ if (aFltName == pFilterXML)
+ bRet = LoadXML( &rMedium, nullptr );
+ else if (aFltName == pFilterLotus)
+ {
+ OUString sItStr;
+ SfxItemSet* pSet = rMedium.GetItemSet();
+ const SfxStringItem* pOptionsItem;
+ if ( pSet &&
+ (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS, true )) )
+ {
+ sItStr = pOptionsItem->GetValue();
+ }
+
+ if (sItStr.isEmpty())
+ {
+ // default for lotus import (from API without options):
+ // IBM_437 encoding
+ sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_437 );
+ }
+
+ ErrCode eError = ScFormatFilter::Get().ScImportLotus123( rMedium, *m_pDocument,
+ ScGlobal::GetCharsetValue(sItStr));
+ if (eError != ERRCODE_NONE)
+ {
+ if (!GetError())
+ SetError(eError);
+
+ if( eError.IsWarning() )
+ bRet = true;
+ }
+ else
+ bRet = true;
+ bSetColWidths = true;
+ bSetRowHeights = true;
+ }
+ else if ( aFltName == pFilterExcel4 || aFltName == pFilterExcel5 ||
+ aFltName == pFilterExcel95 || aFltName == pFilterExcel97 ||
+ aFltName == pFilterEx4Temp || aFltName == pFilterEx5Temp ||
+ aFltName == pFilterEx95Temp || aFltName == pFilterEx97Temp )
+ {
+ EXCIMPFORMAT eFormat = EIF_AUTO;
+ if ( aFltName == pFilterExcel4 || aFltName == pFilterEx4Temp )
+ eFormat = EIF_BIFF_LE4;
+ else if ( aFltName == pFilterExcel5 || aFltName == pFilterExcel95 ||
+ aFltName == pFilterEx5Temp || aFltName == pFilterEx95Temp )
+ eFormat = EIF_BIFF5;
+ else if ( aFltName == pFilterExcel97 || aFltName == pFilterEx97Temp )
+ eFormat = EIF_BIFF8;
+
+ MakeDrawLayer(); //! In the filter
+ CalcOutputFactor(); // prepare update of row height
+ ErrCode eError = ScFormatFilter::Get().ScImportExcel( rMedium, m_pDocument.get(), eFormat );
+ m_pDocument->UpdateFontCharSet();
+ if ( m_pDocument->IsChartListenerCollectionNeedsUpdate() )
+ m_pDocument->UpdateChartListenerCollection(); //! For all imports?
+
+ // all graphics objects must have names
+ m_pDocument->EnsureGraphicNames();
+
+ if (eError != ERRCODE_NONE)
+ {
+ if (!GetError())
+ SetError(eError);
+ if( eError.IsWarning() )
+ bRet = true;
+ }
+ else
+ bRet = true;
+ }
+ else if (aFltName == "Gnumeric Spreadsheet")
+ {
+ ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
+ if (!pOrcus)
+ return false;
+
+ bRet = pOrcus->importGnumeric(*m_pDocument, rMedium);
+ }
+ else if (aFltName == "MS Excel 2003 XML Orcus")
+ {
+ ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
+ if (!pOrcus)
+ return false;
+
+ bRet = pOrcus->importExcel2003XML(*m_pDocument, rMedium);
+ }
+ else if (aFltName == SC_TEXT_CSV_FILTER_NAME)
+ {
+ SfxItemSet* pSet = rMedium.GetItemSet();
+ const SfxStringItem* pOptionsItem;
+ ScAsciiOptions aOptions;
+ bool bOptInit = false;
+
+ if ( pSet &&
+ (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
+ {
+ aOptions.ReadFromString( pOptionsItem->GetValue() );
+ bOptInit = true;
+ }
+
+ if ( !bOptInit )
+ {
+ // default for ascii import (from API without options):
+ // ISO8859-1/MS_1252 encoding, comma, double quotes
+
+ aOptions.SetCharSet( RTL_TEXTENCODING_MS_1252 );
+ aOptions.SetFieldSeps( OUString(',') );
+ aOptions.SetTextSep( '"' );
+ }
+
+ ErrCode eError = ERRCODE_NONE;
+ bool bOverflowRow, bOverflowCol, bOverflowCell;
+ bOverflowRow = bOverflowCol = bOverflowCell = false;
+
+ if( ! rMedium.IsStorage() )
+ {
+ ScImportExport aImpEx( *m_pDocument );
+ aImpEx.SetExtOptions( aOptions );
+
+ SvStream* pInStream = rMedium.GetInStream();
+ if (pInStream)
+ {
+ pInStream->SetStreamCharSet( aOptions.GetCharSet() );
+ pInStream->Seek( 0 );
+ bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::STRING );
+ eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_CONNECT;
+ m_pDocument->StartAllListeners();
+ sc::SetFormulaDirtyContext aCxt;
+ m_pDocument->SetAllFormulasDirty(aCxt);
+
+ bool bIsMobile = comphelper::LibreOfficeKit::isActive() && SfxViewShell::Current()
+ && SfxViewShell::Current()->isLOKMobilePhone();
+ // for mobile case, we use a copy of the original document and give it a temporary name before editing
+ // Therefore, the sheet name becomes ugly, long and nonsensical.
+ if (!bIsMobile)
+ // The same resulting name has to be handled in
+ // ScExternalRefCache::initializeDoc() and related, hence
+ // pass 'true' for RenameTab()'s bExternalDocument for a
+ // composed name so ValidTabName() will not be checked,
+ // which could veto the rename in case it contained
+ // characters that Excel does not handle. If we wanted to
+ // change that then it needed to be handled in all
+ // corresponding places of the external references
+ // manager/cache. Likely then we'd also need a method to
+ // compose a name excluding such characters.
+ m_pDocument->RenameTab( 0, INetURLObject( rMedium.GetName()).GetBase(), true/*bExternalDocument*/);
+
+ bOverflowRow = aImpEx.IsOverflowRow();
+ bOverflowCol = aImpEx.IsOverflowCol();
+ bOverflowCell = aImpEx.IsOverflowCell();
+ }
+ else
+ {
+ OSL_FAIL( "No Stream" );
+ }
+ }
+
+ if (eError != ERRCODE_NONE)
+ {
+ if (!GetError())
+ SetError(eError);
+ if( eError.IsWarning() )
+ bRet = true;
+ }
+ else if (!GetError() && (bOverflowRow || bOverflowCol || bOverflowCell))
+ {
+ // precedence: row, column, cell
+ ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW :
+ (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW :
+ SCWARN_IMPORT_CELL_OVERFLOW));
+ SetError(nWarn);
+ }
+ bSetColWidths = true;
+ bSetSimpleTextColWidths = true;
+ }
+ else if (aFltName == pFilterDBase)
+ {
+ OUString sItStr;
+ SfxItemSet* pSet = rMedium.GetItemSet();
+ const SfxStringItem* pOptionsItem;
+ if ( pSet &&
+ (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
+ {
+ sItStr = pOptionsItem->GetValue();
+ }
+
+ if (sItStr.isEmpty())
+ {
+ // default for dBase import (from API without options):
+ // IBM_850 encoding
+
+ sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 );
+ }
+
+ ScDocRowHeightUpdater::TabRanges aRecalcRanges(0, m_pDocument->MaxRow());
+ ErrCode eError = DBaseImport( rMedium.GetPhysicalName(),
+ ScGlobal::GetCharsetValue(sItStr), aColWidthParam, aRecalcRanges.maRanges );
+ aRecalcRowRangesArray.push_back(aRecalcRanges);
+
+ if (eError != ERRCODE_NONE)
+ {
+ if (!GetError())
+ SetError(eError);
+ if( eError.IsWarning() )
+ bRet = true;
+ }
+ else
+ bRet = true;
+
+ aColWidthRange.aStart.SetRow( 1 ); // Except for the column header
+ bSetColWidths = true;
+ bSetSimpleTextColWidths = true;
+ }
+ else if (aFltName == pFilterDif)
+ {
+ SvStream* pStream = rMedium.GetInStream();
+ if (pStream)
+ {
+ ErrCode eError;
+ OUString sItStr;
+ SfxItemSet* pSet = rMedium.GetItemSet();
+ const SfxStringItem* pOptionsItem;
+ if ( pSet &&
+ (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
+ {
+ sItStr = pOptionsItem->GetValue();
+ }
+
+ if (sItStr.isEmpty())
+ {
+ // default for DIF import (from API without options):
+ // ISO8859-1/MS_1252 encoding
+
+ sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 );
+ }
+
+ eError = ScFormatFilter::Get().ScImportDif( *pStream, m_pDocument.get(), ScAddress(0,0,0),
+ ScGlobal::GetCharsetValue(sItStr));
+ if (eError != ERRCODE_NONE)
+ {
+ if (!GetError())
+ SetError(eError);
+
+ if( eError.IsWarning() )
+ bRet = true;
+ }
+ else
+ bRet = true;
+ }
+ bSetColWidths = true;
+ bSetSimpleTextColWidths = true;
+ bSetRowHeights = true;
+ }
+ else if (aFltName == pFilterSylk)
+ {
+ ErrCode eError = SCERR_IMPORT_UNKNOWN;
+ bool bOverflowRow, bOverflowCol, bOverflowCell;
+ bOverflowRow = bOverflowCol = bOverflowCell = false;
+ if( !rMedium.IsStorage() )
+ {
+ ScImportExport aImpEx( *m_pDocument );
+
+ SvStream* pInStream = rMedium.GetInStream();
+ if (pInStream)
+ {
+ pInStream->Seek( 0 );
+ bRet = aImpEx.ImportStream( *pInStream, rMedium.GetBaseURL(), SotClipboardFormatId::SYLK );
+ eError = bRet ? ERRCODE_NONE : SCERR_IMPORT_UNKNOWN;
+ m_pDocument->StartAllListeners();
+ sc::SetFormulaDirtyContext aCxt;
+ m_pDocument->SetAllFormulasDirty(aCxt);
+
+ bOverflowRow = aImpEx.IsOverflowRow();
+ bOverflowCol = aImpEx.IsOverflowCol();
+ bOverflowCell = aImpEx.IsOverflowCell();
+ }
+ else
+ {
+ OSL_FAIL( "No Stream" );
+ }
+ }
+
+ if (eError != ERRCODE_NONE)
+ {
+ if (!GetError())
+ SetError(eError);
+ if( eError.IsWarning() )
+ bRet = true;
+ }
+ else if (!GetError() && (bOverflowRow || bOverflowCol || bOverflowCell))
+ {
+ // precedence: row, column, cell
+ ErrCode nWarn = (bOverflowRow ? SCWARN_IMPORT_ROW_OVERFLOW :
+ (bOverflowCol ? SCWARN_IMPORT_COLUMN_OVERFLOW :
+ SCWARN_IMPORT_CELL_OVERFLOW));
+ SetError(nWarn);
+ }
+ bSetColWidths = true;
+ bSetSimpleTextColWidths = true;
+ bSetRowHeights = true;
+ }
+ else if (aFltName == pFilterQPro6)
+ {
+ ErrCode eError = ScFormatFilter::Get().ScImportQuattroPro(rMedium.GetInStream(), *m_pDocument);
+ if (eError != ERRCODE_NONE)
+ {
+ if (!GetError())
+ SetError(eError);
+ if( eError.IsWarning() )
+ bRet = true;
+ }
+ else
+ bRet = true;
+ // TODO: Filter should set column widths. Not doing it here, it may
+ // result in very narrow or wide columns, depending on content.
+ // Setting row heights makes cells with font size attribution or
+ // wrapping enabled look nicer...
+ bSetRowHeights = true;
+ }
+ else if (aFltName == pFilterRtf)
+ {
+ ErrCode eError = SCERR_IMPORT_UNKNOWN;
+ if( !rMedium.IsStorage() )
+ {
+ SvStream* pInStream = rMedium.GetInStream();
+ if (pInStream)
+ {
+ pInStream->Seek( 0 );
+ ScRange aRange;
+ eError = ScFormatFilter::Get().ScImportRTF( *pInStream, rMedium.GetBaseURL(), m_pDocument.get(), aRange );
+ if (eError != ERRCODE_NONE)
+ {
+ if (!GetError())
+ SetError(eError);
+
+ if( eError.IsWarning() )
+ bRet = true;
+ }
+ else
+ bRet = true;
+ m_pDocument->StartAllListeners();
+ sc::SetFormulaDirtyContext aCxt;
+ m_pDocument->SetAllFormulasDirty(aCxt);
+ bSetColWidths = true;
+ bSetRowHeights = true;
+ }
+ else
+ {
+ OSL_FAIL( "No Stream" );
+ }
+ }
+
+ if (eError != ERRCODE_NONE)
+ {
+ if (!GetError())
+ SetError(eError);
+ if( eError.IsWarning() )
+ bRet = true;
+ }
+ }
+ else if (aFltName == pFilterHtml || aFltName == pFilterHtmlWebQ)
+ {
+ ErrCode eError = SCERR_IMPORT_UNKNOWN;
+ bool bWebQuery = aFltName == pFilterHtmlWebQ;
+ if( !rMedium.IsStorage() )
+ {
+ SvStream* pInStream = rMedium.GetInStream();
+ if (pInStream)
+ {
+ LanguageType eLang = LANGUAGE_SYSTEM;
+ bool bDateConvert = false;
+ SfxItemSet* pSet = rMedium.GetItemSet();
+ const SfxStringItem* pOptionsItem;
+ if ( pSet &&
+ (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
+ {
+ OUString aFilterOption = pOptionsItem->GetValue();
+ lcl_parseHtmlFilterOption(aFilterOption, eLang, bDateConvert);
+ }
+
+ pInStream->Seek( 0 );
+ ScRange aRange;
+ // HTML does its own ColWidth/RowHeight
+ CalcOutputFactor();
+ SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eLang);
+ eError = ScFormatFilter::Get().ScImportHTML( *pInStream, rMedium.GetBaseURL(), m_pDocument.get(), aRange,
+ GetOutputFactor(), !bWebQuery, &aNumFormatter, bDateConvert );
+ if (eError != ERRCODE_NONE)
+ {
+ if (!GetError())
+ SetError(eError);
+
+ if( eError.IsWarning() )
+ bRet = true;
+ }
+ else
+ bRet = true;
+ m_pDocument->StartAllListeners();
+
+ sc::SetFormulaDirtyContext aCxt;
+ m_pDocument->SetAllFormulasDirty(aCxt);
+ }
+ else
+ {
+ OSL_FAIL( "No Stream" );
+ }
+ }
+
+ if (eError != ERRCODE_NONE)
+ {
+ if (!GetError())
+ SetError(eError);
+ if( eError.IsWarning() )
+ bRet = true;
+ }
+ }
+ else
+ {
+ if (!GetError())
+ {
+ SAL_WARN("sc.filter", "No match for filter '" << aFltName << "' in ConvertFrom");
+ SetError(SCERR_IMPORT_NI);
+ }
+ }
+
+ if (!bCalc3)
+ m_pDocument->SetInsertingFromOtherDoc( false );
+ }
+ else
+ {
+ OSL_FAIL("No Filter in ConvertFrom");
+ }
+
+ InitItems();
+ CalcOutputFactor();
+ if ( bRet && (bSetColWidths || bSetRowHeights) )
+ { // Adjust column width/row height; base 100% zoom
+ Fraction aZoom( 1, 1 );
+ double nPPTX = ScGlobal::nScreenPPTX * static_cast<double>(aZoom) / GetOutputFactor(); // Factor is printer display ratio
+ double nPPTY = ScGlobal::nScreenPPTY * static_cast<double>(aZoom);
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ // all sheets (for Excel import)
+ SCTAB nTabCount = m_pDocument->GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ {
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ m_pDocument->GetCellArea( nTab, nEndCol, nEndRow );
+ aColWidthRange.aEnd.SetCol( nEndCol );
+ aColWidthRange.aEnd.SetRow( nEndRow );
+ ScMarkData aMark(m_pDocument->GetSheetLimits());
+ aMark.SetMarkArea( aColWidthRange );
+ aMark.MarkToMulti();
+
+ // Order is important: First width, then height
+ if ( bSetColWidths )
+ {
+ for ( SCCOL nCol=0; nCol <= nEndCol; nCol++ )
+ {
+ if (!bSetSimpleTextColWidths)
+ aColWidthParam[nCol].mbSimpleText = false;
+
+ sal_uInt16 nWidth = m_pDocument->GetOptimalColWidth(
+ nCol, nTab, pVirtDev, nPPTX, nPPTY, aZoom, aZoom, false, &aMark,
+ &aColWidthParam[nCol] );
+ m_pDocument->SetColWidth( nCol, nTab,
+ nWidth + static_cast<sal_uInt16>(ScGlobal::nLastColWidthExtra) );
+ }
+ }
+ }
+
+ if (bSetRowHeights)
+ {
+ // Update all rows in all tables.
+ ScSizeDeviceProvider aProv(this);
+ ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), nullptr);
+ aUpdater.update();
+ }
+ else if (!aRecalcRowRangesArray.empty())
+ {
+ // Update only specified row ranges for better performance.
+ ScSizeDeviceProvider aProv(this);
+ ScDocRowHeightUpdater aUpdater(*m_pDocument, aProv.GetDevice(), aProv.GetPPTX(), aProv.GetPPTY(), &aRecalcRowRangesArray);
+ aUpdater.update();
+ }
+ }
+ FinishedLoading();
+
+ // invalidate eventually temporary table areas
+ if ( bRet )
+ m_pDocument->InvalidateTableArea();
+
+ m_bIsEmpty = false;
+
+ return bRet;
+}
+
+bool ScDocShell::LoadExternal( SfxMedium& rMed )
+{
+ std::shared_ptr<const SfxFilter> pFilter = rMed.GetFilter();
+ if (!pFilter)
+ return false;
+
+ if (pFilter->GetProviderName() == "orcus")
+ {
+ ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
+ if (!pOrcus)
+ return false;
+
+ const OUString& rFilterName = pFilter->GetName();
+ if (rFilterName == "gnumeric")
+ {
+ if (!pOrcus->importGnumeric(*m_pDocument, rMed))
+ return false;
+ }
+ else if (rFilterName == "csv")
+ {
+ if (!pOrcus->importCSV(*m_pDocument, rMed))
+ return false;
+ }
+ else if (rFilterName == "xlsx")
+ {
+ if (!pOrcus->importXLSX(*m_pDocument, rMed))
+ return false;
+ }
+ else if (rFilterName == "ods")
+ {
+ if (!pOrcus->importODS(*m_pDocument, rMed))
+ return false;
+ }
+
+ FinishedLoading();
+ return true;
+ }
+
+ return false;
+}
+
+ScDocShell::PrepareSaveGuard::PrepareSaveGuard( ScDocShell& rDocShell )
+ : mrDocShell( rDocShell)
+{
+ // DoEnterHandler not here (because of AutoSave), is in ExecuteSave.
+
+ ScChartListenerCollection* pCharts = mrDocShell.m_pDocument->GetChartListenerCollection();
+ if (pCharts)
+ pCharts->UpdateDirtyCharts(); // Charts to be updated.
+ mrDocShell.m_pDocument->StopTemporaryChartLock();
+ if (mrDocShell.m_pAutoStyleList)
+ mrDocShell.m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now.
+ if (mrDocShell.m_pDocument->HasExternalRefManager())
+ {
+ ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager();
+ if (pRefMgr && pRefMgr->hasExternalData())
+ {
+ pRefMgr->setAllCacheTableReferencedStati( false);
+ mrDocShell.m_pDocument->MarkUsedExternalReferences(); // Mark tables of external references to be written.
+ }
+ }
+ if (mrDocShell.GetCreateMode()== SfxObjectCreateMode::STANDARD)
+ mrDocShell.SfxObjectShell::SetVisArea( tools::Rectangle() ); // "Normally" worked on => no VisArea.
+}
+
+ScDocShell::PrepareSaveGuard::~PrepareSaveGuard() COVERITY_NOEXCEPT_FALSE
+{
+ if (mrDocShell.m_pDocument->HasExternalRefManager())
+ {
+ ScExternalRefManager* pRefMgr = mrDocShell.m_pDocument->GetExternalRefManager();
+ if (pRefMgr && pRefMgr->hasExternalData())
+ {
+ // Prevent accidental data loss due to lack of knowledge.
+ pRefMgr->setAllCacheTableReferencedStati( true);
+ }
+ }
+}
+
+bool ScDocShell::Save()
+{
+ ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
+
+ PrepareSaveGuard aPrepareGuard( *this);
+
+ if (const auto pFrame1 = SfxViewFrame::GetFirst(this))
+ {
+ if (auto pSysWin = pFrame1->GetWindow().GetSystemWindow())
+ {
+ pSysWin->SetAccessibleName(OUString());
+ }
+ }
+ // wait cursor is handled with progress bar
+ bool bRet = SfxObjectShell::Save();
+ if( bRet )
+ bRet = SaveXML( GetMedium(), nullptr );
+ return bRet;
+}
+
+namespace {
+
+/**
+ * Remove the file name from the full path, to keep only the directory path.
+ */
+void popFileName(OUString& rPath)
+{
+ if (!rPath.isEmpty())
+ {
+ INetURLObject aURLObj(rPath);
+ aURLObj.removeSegment();
+ rPath = aURLObj.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ }
+}
+
+}
+
+void ScDocShell::TerminateEditing()
+{
+ // Commit any cell changes before saving.
+ SC_MOD()->InputEnterHandler();
+}
+
+bool ScDocShell::SaveAs( SfxMedium& rMedium )
+{
+ OUString aCurPath; // empty for new document that hasn't been saved.
+ const SfxMedium* pCurMedium = GetMedium();
+ if (pCurMedium)
+ {
+ aCurPath = pCurMedium->GetName();
+ popFileName(aCurPath);
+ }
+
+ if (!aCurPath.isEmpty())
+ {
+ // current document has a path -> not a brand-new document.
+ OUString aNewPath = rMedium.GetName();
+ popFileName(aNewPath);
+ OUString aRel = URIHelper::simpleNormalizedMakeRelative(aCurPath, aNewPath);
+ if (!aRel.isEmpty())
+ {
+ // Directory path will change before and after the save.
+ m_pDocument->InvalidateStreamOnSave();
+ }
+ }
+
+ ScTabViewShell* pViewShell = GetBestViewShell();
+ bool bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA1);
+ if (bNeedsRehash)
+ // legacy xls hash double-hashed by SHA1 is also supported.
+ bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_XL, PASSHASH_SHA1);
+ if (bNeedsRehash)
+ { // SHA256 explicitly supported in ODF 1.2, implicitly in ODF 1.1
+ bNeedsRehash = ScPassHashHelper::needsPassHashRegen(*m_pDocument, PASSHASH_SHA256);
+ }
+
+ // skip saving recovery file instead of showing re-type password dialog window
+ if ( bNeedsRehash && rMedium.GetFilter()->GetFilterName() == "calc8" &&
+ // it seems, utl::MediaDescriptor::PROP_AUTOSAVEEVENT is true at Save As, too,
+ // so check the backup path
+ rMedium.GetName().startsWith( SvtPathOptions().GetBackupPath() ) )
+ {
+ SAL_WARN("sc.filter", "Should re-type password for own format, won't export recovery file");
+ rMedium.SetError(ERRCODE_SFX_WRONGPASSWORD);
+ return false;
+ }
+
+ if (pViewShell && bNeedsRehash)
+ {
+ if (!pViewShell->ExecuteRetypePassDlg(PASSHASH_SHA1))
+ // password re-type cancelled. Don't save the document.
+ return false;
+ }
+
+ ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
+
+ PrepareSaveGuard aPrepareGuard( *this);
+
+ // wait cursor is handled with progress bar
+ bool bRet = SfxObjectShell::SaveAs( rMedium );
+ if (bRet)
+ bRet = SaveXML( &rMedium, nullptr );
+
+ return bRet;
+}
+
+namespace {
+
+// Xcl-like column width measured in characters of standard font.
+sal_Int32 lcl_ScDocShell_GetColWidthInChars( sal_uInt16 nWidth )
+{
+ double f = nWidth;
+ f *= 1328.0 / 25.0;
+ f += 90.0;
+ f *= 1.0 / 23.0;
+ f /= 256.0;
+
+ return sal_Int32( f );
+}
+
+void lcl_ScDocShell_GetFixedWidthString( OUString& rStr, const ScDocument& rDoc,
+ SCTAB nTab, SCCOL nCol, bool bValue, SvxCellHorJustify eHorJust )
+{
+ OUString aString = rStr;
+ sal_Int32 nLen = lcl_ScDocShell_GetColWidthInChars(
+ rDoc.GetColWidth( nCol, nTab ) );
+ //If the text won't fit in the column
+ if ( nLen < aString.getLength() )
+ {
+ OUStringBuffer aReplacement;
+ if (bValue)
+ aReplacement.append("###");
+ else
+ aReplacement.append(aString);
+ //truncate to the number of characters that should fit, even in the
+ //bValue case nLen might be < len ###
+ aString = comphelper::string::truncateToLength(aReplacement, nLen).makeStringAndClear();
+ }
+ if ( nLen > aString.getLength() )
+ {
+ if ( bValue && eHorJust == SvxCellHorJustify::Standard )
+ eHorJust = SvxCellHorJustify::Right;
+ OUStringBuffer aTmp(nLen);
+ switch ( eHorJust )
+ {
+ case SvxCellHorJustify::Right:
+ comphelper::string::padToLength( aTmp, nLen - aString.getLength(), ' ' );
+ aString = aTmp.append(aString);
+ break;
+ case SvxCellHorJustify::Center:
+ comphelper::string::padToLength( aTmp, (nLen - aString.getLength()) / 2, ' ' );
+ [[fallthrough]];
+ default:
+ aTmp.append(aString);
+ comphelper::string::padToLength( aTmp, nLen, ' ' );
+ }
+ aString = aTmp.makeStringAndClear();
+ }
+ rStr = aString;
+}
+
+void lcl_ScDocShell_WriteEmptyFixedWidthString( SvStream& rStream,
+ const ScDocument& rDoc, SCTAB nTab, SCCOL nCol )
+{
+ OUString aString;
+ lcl_ScDocShell_GetFixedWidthString( aString, rDoc, nTab, nCol, false,
+ SvxCellHorJustify::Standard );
+ rStream.WriteUnicodeOrByteText( aString );
+}
+
+template<typename StrT, typename SepCharT>
+sal_Int32 getTextSepPos(
+ const StrT& rStr, const ScImportOptions& rAsciiOpt, const SepCharT& rTextSep, const SepCharT& rFieldSep, bool& rNeedQuotes)
+{
+ // #i116636# quotes are needed if text delimiter (quote), field delimiter,
+ // or LF or CR is in the cell text.
+ sal_Int32 nPos = rStr.indexOf(rTextSep);
+ rNeedQuotes = rAsciiOpt.bQuoteAllText || (nPos >= 0) ||
+ (rStr.indexOf(rFieldSep) >= 0) ||
+ (rStr.indexOf('\n') >= 0) ||
+ (rStr.indexOf('\r') >= 0);
+ return nPos;
+}
+
+template<typename StrT, typename StrBufT>
+void escapeTextSep(sal_Int32 nPos, const StrT& rStrDelim, StrT& rStr)
+{
+ while (nPos >= 0)
+ {
+ StrBufT aBuf(rStr);
+ aBuf.insert(nPos, rStrDelim);
+ rStr = aBuf.makeStringAndClear();
+ nPos = rStr.indexOf(rStrDelim, nPos+1+rStrDelim.getLength());
+ }
+}
+
+}
+
+void ScDocShell::AsciiSave( SvStream& rStream, const ScImportOptions& rAsciiOpt, SCTAB nTab )
+{
+ sal_Unicode cDelim = rAsciiOpt.nFieldSepCode;
+ sal_Unicode cStrDelim = rAsciiOpt.nTextSepCode;
+ rtl_TextEncoding eCharSet = rAsciiOpt.eCharSet;
+ bool bFixedWidth = rAsciiOpt.bFixedWidth;
+ bool bSaveNumberAsSuch = rAsciiOpt.bSaveNumberAsSuch;
+ bool bSaveAsShown = rAsciiOpt.bSaveAsShown;
+ bool bShowFormulas = rAsciiOpt.bSaveFormulas;
+
+ rtl_TextEncoding eOldCharSet = rStream.GetStreamCharSet();
+ rStream.SetStreamCharSet( eCharSet );
+ SvStreamEndian nOldNumberFormatInt = rStream.GetEndian();
+ OString aStrDelimEncoded; // only used if not Unicode
+ OUString aStrDelimDecoded; // only used if context encoding
+ OString aDelimEncoded;
+ OUString aDelimDecoded;
+ bool bContextOrNotAsciiEncoding;
+ if ( eCharSet == RTL_TEXTENCODING_UNICODE )
+ {
+ rStream.StartWritingUnicodeText();
+ bContextOrNotAsciiEncoding = false;
+ }
+ else
+ {
+ aStrDelimEncoded = OString(&cStrDelim, 1, eCharSet);
+ aDelimEncoded = OString(&cDelim, 1, eCharSet);
+ rtl_TextEncodingInfo aInfo;
+ aInfo.StructSize = sizeof(aInfo);
+ if ( rtl_getTextEncodingInfo( eCharSet, &aInfo ) )
+ {
+ bContextOrNotAsciiEncoding =
+ (((aInfo.Flags & RTL_TEXTENCODING_INFO_CONTEXT) != 0) ||
+ ((aInfo.Flags & RTL_TEXTENCODING_INFO_ASCII) == 0));
+ if ( bContextOrNotAsciiEncoding )
+ {
+ aStrDelimDecoded = OStringToOUString(aStrDelimEncoded, eCharSet);
+ aDelimDecoded = OStringToOUString(aDelimEncoded, eCharSet);
+ }
+ }
+ else
+ bContextOrNotAsciiEncoding = false;
+ }
+
+ SCCOL nStartCol = 0;
+ SCROW nStartRow = 0;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ m_pDocument->GetCellArea( nTab, nEndCol, nEndRow );
+
+ ScProgress aProgress( this, ScResId( STR_SAVE_DOC ), nEndRow, true );
+
+ OUString aString;
+
+ bool bTabProtect = m_pDocument->IsTabProtected( nTab );
+
+ SCCOL nCol;
+ SCROW nRow;
+
+ // Treat the top left cell separator "sep=" special.
+ // Here nStartRow == 0 && nStartCol == 0
+ if (!bFixedWidth && cDelim != 0)
+ {
+ // First row iterator.
+ ScHorizontalCellIterator aIter( *m_pDocument, nTab, nStartCol, nStartRow, nEndCol, nStartRow);
+ ScRefCellValue* pCell;
+ // Must be first column and all following cells on this row must be
+ // empty to fiddle with "sep=".
+ if ((pCell = aIter.GetNext( nCol, nRow)) != nullptr && nCol == nStartCol && !aIter.GetNext( nCol, nRow))
+ {
+ if (pCell->meType == CELLTYPE_STRING)
+ {
+ aString = pCell->mpString->getString();
+ if (aString.getLength() <= 5 && aString.startsWithIgnoreAsciiCase("sep="))
+ {
+ // Cell content is /^sep=.?$/ so write current separator.
+ // Force the quote character to '"' regardless what is set
+ // for export because that is the only one recognized on
+ // import.
+ aString = "sep=" + OUStringChar(cDelim);
+ if (cStrDelim != 0)
+ rStream.WriteUniOrByteChar( '"', eCharSet);
+ if (eCharSet == RTL_TEXTENCODING_UNICODE)
+ {
+ write_uInt16s_FromOUString( rStream, aString);
+ }
+ else
+ {
+ OString aStrEnc = OUStringToOString( aString, eCharSet);
+ // write byte encoded
+ rStream.WriteBytes( aStrEnc.getStr(), aStrEnc.getLength());
+ }
+ if (cStrDelim != 0)
+ rStream.WriteUniOrByteChar( '"', eCharSet);
+ endlub( rStream );
+ ++nStartRow;
+ }
+ }
+ }
+ }
+
+ SCCOL nNextCol = nStartCol;
+ SCROW nNextRow = nStartRow;
+ SCCOL nEmptyCol;
+ SCROW nEmptyRow;
+ SvNumberFormatter& rFormatter = *m_pDocument->GetFormatTable();
+
+ ScHorizontalCellIterator aIter( *m_pDocument, nTab, nStartCol, nStartRow,
+ nEndCol, nEndRow );
+ ScRefCellValue* pCell;
+ while ( ( pCell = aIter.GetNext( nCol, nRow ) ) != nullptr )
+ {
+ bool bProgress = false; // only upon line change
+ if ( nNextRow < nRow )
+ { // empty rows or/and empty columns up to end of row
+ bProgress = true;
+ for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ )
+ { // remaining columns of last row
+ if ( bFixedWidth )
+ lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
+ *m_pDocument, nTab, nEmptyCol );
+ else if ( cDelim != 0 )
+ rStream.WriteUniOrByteChar( cDelim );
+ }
+ endlub( rStream );
+ nNextRow++;
+ for ( nEmptyRow = nNextRow; nEmptyRow < nRow; nEmptyRow++ )
+ { // completely empty rows
+ for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ )
+ {
+ if ( bFixedWidth )
+ lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
+ *m_pDocument, nTab, nEmptyCol );
+ else if ( cDelim != 0 )
+ rStream.WriteUniOrByteChar( cDelim );
+ }
+ endlub( rStream );
+ }
+ for ( nEmptyCol = nStartCol; nEmptyCol < nCol; nEmptyCol++ )
+ { // empty columns at beginning of row
+ if ( bFixedWidth )
+ lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
+ *m_pDocument, nTab, nEmptyCol );
+ else if ( cDelim != 0 )
+ rStream.WriteUniOrByteChar( cDelim );
+ }
+ nNextRow = nRow;
+ }
+ else if ( nNextCol < nCol )
+ { // empty columns in same row
+ for ( nEmptyCol = nNextCol; nEmptyCol < nCol; nEmptyCol++ )
+ { // columns in between
+ if ( bFixedWidth )
+ lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
+ *m_pDocument, nTab, nEmptyCol );
+ else if ( cDelim != 0 )
+ rStream.WriteUniOrByteChar( cDelim );
+ }
+ }
+ if ( nCol == nEndCol )
+ {
+ bProgress = true;
+ nNextCol = nStartCol;
+ nNextRow = nRow + 1;
+ }
+ else
+ nNextCol = nCol + 1;
+
+ CellType eType = pCell->meType;
+ ScAddress aPos(nCol, nRow, nTab);
+ if ( bTabProtect )
+ {
+ const ScProtectionAttr* pProtAttr =
+ m_pDocument->GetAttr( nCol, nRow, nTab, ATTR_PROTECTION );
+ if ( pProtAttr->GetHideCell() ||
+ ( eType == CELLTYPE_FORMULA && bShowFormulas &&
+ pProtAttr->GetHideFormula() ) )
+ eType = CELLTYPE_NONE; // hide
+ }
+ bool bForceQuotes = false;
+ bool bString;
+ switch ( eType )
+ {
+ case CELLTYPE_NONE:
+ aString.clear();
+ bString = false;
+ break;
+ case CELLTYPE_FORMULA :
+ {
+ FormulaError nErrCode;
+ if ( bShowFormulas )
+ {
+ aString = pCell->mpFormula->GetFormula();
+ bString = true;
+ }
+ else if ((nErrCode = pCell->mpFormula->GetErrCode()) != FormulaError::NONE)
+ {
+ aString = ScGlobal::GetErrorString( nErrCode );
+ bString = true;
+ }
+ else if (pCell->mpFormula->IsValue())
+ {
+ sal_uInt32 nFormat = m_pDocument->GetNumberFormat(aPos);
+ if ( bFixedWidth || bSaveAsShown )
+ {
+ const Color* pDummy;
+ aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, rFormatter, *m_pDocument);
+ bString = bSaveAsShown && rFormatter.IsTextFormat( nFormat);
+ }
+ else
+ {
+ aString = ScCellFormat::GetInputString(*pCell, nFormat, rFormatter, *m_pDocument);
+ bString = bForceQuotes = !bSaveNumberAsSuch;
+ }
+ }
+ else
+ {
+ if ( bSaveAsShown )
+ {
+ sal_uInt32 nFormat = m_pDocument->GetNumberFormat(aPos);
+ const Color* pDummy;
+ aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, rFormatter, *m_pDocument);
+ }
+ else
+ aString = pCell->mpFormula->GetString().getString();
+ bString = true;
+ }
+ }
+ break;
+ case CELLTYPE_STRING :
+ if ( bSaveAsShown )
+ {
+ sal_uInt32 nFormat = m_pDocument->GetNumberFormat(aPos);
+ const Color* pDummy;
+ aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, rFormatter, *m_pDocument);
+ }
+ else
+ aString = pCell->mpString->getString();
+ bString = true;
+ break;
+ case CELLTYPE_EDIT :
+ {
+ const EditTextObject* pObj = pCell->mpEditText;
+ EditEngine& rEngine = m_pDocument->GetEditEngine();
+ rEngine.SetText( *pObj);
+ aString = rEngine.GetText(); // including LF
+ bString = true;
+ }
+ break;
+ case CELLTYPE_VALUE :
+ {
+ sal_uInt32 nFormat = m_pDocument->GetNumberFormat( nCol, nRow, nTab );
+ if ( bFixedWidth || bSaveAsShown )
+ {
+ const Color* pDummy;
+ aString = ScCellFormat::GetString(*pCell, nFormat, &pDummy, rFormatter, *m_pDocument);
+ bString = bSaveAsShown && rFormatter.IsTextFormat( nFormat);
+ }
+ else
+ {
+ aString = ScCellFormat::GetInputString(*pCell, nFormat, rFormatter, *m_pDocument);
+ bString = bForceQuotes = !bSaveNumberAsSuch;
+ }
+ }
+ break;
+ default:
+ OSL_FAIL( "ScDocShell::AsciiSave: unknown CellType" );
+ aString.clear();
+ bString = false;
+ }
+
+ if ( bFixedWidth )
+ {
+ SvxCellHorJustify eHorJust =
+ m_pDocument->GetAttr( nCol, nRow, nTab, ATTR_HOR_JUSTIFY )->GetValue();
+ lcl_ScDocShell_GetFixedWidthString( aString, *m_pDocument, nTab, nCol,
+ !bString, eHorJust );
+ rStream.WriteUnicodeOrByteText( aString );
+ }
+ else
+ {
+ OUString aUniString = aString;// TODO: remove that later
+ if (!bString && cStrDelim != 0 && !aUniString.isEmpty())
+ {
+ sal_Unicode c = aUniString[0];
+ bString = (c == cStrDelim || c == ' ' ||
+ aUniString.endsWith(" ") ||
+ aUniString.indexOf(cStrDelim) >= 0);
+ if (!bString && cDelim != 0)
+ bString = (aUniString.indexOf(cDelim) >= 0);
+ }
+ if ( bString )
+ {
+ if ( cStrDelim != 0 ) //@ BugId 55355
+ {
+ if ( eCharSet == RTL_TEXTENCODING_UNICODE )
+ {
+ bool bNeedQuotes = false;
+ sal_Int32 nPos = getTextSepPos(
+ aUniString, rAsciiOpt, cStrDelim, cDelim, bNeedQuotes);
+
+ escapeTextSep<OUString, OUStringBuffer>(
+ nPos, OUString(cStrDelim), aUniString);
+
+ if ( bNeedQuotes || bForceQuotes )
+ rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
+ write_uInt16s_FromOUString(rStream, aUniString);
+ if ( bNeedQuotes || bForceQuotes )
+ rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
+ }
+ else
+ {
+ // This is nasty. The Unicode to byte encoding
+ // may convert typographical quotation marks to ASCII
+ // quotation marks, which may interfere with the delimiter,
+ // so we have to escape delimiters after the string has
+ // been encoded. Since this may happen also with UTF-8
+ // encoded typographical quotation marks if such was
+ // specified as a delimiter we have to check for the full
+ // encoded delimiter string, not just one character.
+ // Now for RTL_TEXTENCODING_ISO_2022_... and similar brain
+ // dead encodings where one code point (and especially a
+ // low ASCII value) may represent different characters, we
+ // have to convert forth and back and forth again. Same for
+ // UTF-7 since it is a context sensitive encoding too.
+
+ if ( bContextOrNotAsciiEncoding )
+ {
+ // to byte encoding
+ OString aStrEnc = OUStringToOString(aUniString, eCharSet);
+ // back to Unicode
+ OUString aStrDec = OStringToOUString(aStrEnc, eCharSet);
+
+ // search on re-decoded string
+ bool bNeedQuotes = false;
+ sal_Int32 nPos = getTextSepPos(
+ aStrDec, rAsciiOpt, aStrDelimDecoded, aDelimDecoded, bNeedQuotes);
+
+ escapeTextSep<OUString, OUStringBuffer>(
+ nPos, aStrDelimDecoded, aStrDec);
+
+ // write byte re-encoded
+ if ( bNeedQuotes || bForceQuotes )
+ rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
+ rStream.WriteUnicodeOrByteText( aStrDec, eCharSet );
+ if ( bNeedQuotes || bForceQuotes )
+ rStream.WriteUniOrByteChar( cStrDelim, eCharSet );
+ }
+ else
+ {
+ OString aStrEnc = OUStringToOString(aUniString, eCharSet);
+
+ // search on encoded string
+ bool bNeedQuotes = false;
+ sal_Int32 nPos = getTextSepPos(
+ aStrEnc, rAsciiOpt, aStrDelimEncoded, aDelimEncoded, bNeedQuotes);
+
+ escapeTextSep<OString, OStringBuffer>(
+ nPos, aStrDelimEncoded, aStrEnc);
+
+ // write byte encoded
+ if ( bNeedQuotes || bForceQuotes )
+ rStream.WriteBytes(
+ aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength());
+ rStream.WriteBytes(aStrEnc.getStr(), aStrEnc.getLength());
+ if ( bNeedQuotes || bForceQuotes )
+ rStream.WriteBytes(
+ aStrDelimEncoded.getStr(), aStrDelimEncoded.getLength());
+ }
+ }
+ }
+ else
+ rStream.WriteUnicodeOrByteText( aUniString );
+ }
+ else
+ rStream.WriteUnicodeOrByteText( aUniString );
+ }
+
+ if( nCol < nEndCol )
+ {
+ if(cDelim!=0) //@ BugId 55355
+ rStream.WriteUniOrByteChar( cDelim );
+ }
+ else
+ endlub( rStream );
+
+ if ( bProgress )
+ aProgress.SetStateOnPercent( nRow );
+ }
+
+ // write out empty if requested
+ if ( nNextRow <= nEndRow )
+ {
+ for ( nEmptyCol = nNextCol; nEmptyCol < nEndCol; nEmptyCol++ )
+ { // remaining empty columns of last row
+ if ( bFixedWidth )
+ lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
+ *m_pDocument, nTab, nEmptyCol );
+ else if ( cDelim != 0 )
+ rStream.WriteUniOrByteChar( cDelim );
+ }
+ endlub( rStream );
+ nNextRow++;
+ }
+ for ( nEmptyRow = nNextRow; nEmptyRow <= nEndRow; nEmptyRow++ )
+ { // entire empty rows
+ for ( nEmptyCol = nStartCol; nEmptyCol < nEndCol; nEmptyCol++ )
+ {
+ if ( bFixedWidth )
+ lcl_ScDocShell_WriteEmptyFixedWidthString( rStream,
+ *m_pDocument, nTab, nEmptyCol );
+ else if ( cDelim != 0 )
+ rStream.WriteUniOrByteChar( cDelim );
+ }
+ endlub( rStream );
+ }
+
+ rStream.SetStreamCharSet( eOldCharSet );
+ rStream.SetEndian( nOldNumberFormatInt );
+}
+
+bool ScDocShell::ConvertTo( SfxMedium &rMed )
+{
+ ScRefreshTimerProtector aProt( m_pDocument->GetRefreshTimerControlAddress() );
+
+ // #i6500# don't call DoEnterHandler here (doesn't work with AutoSave),
+ // it's already in ExecuteSave (as for Save and SaveAs)
+
+ if (m_pAutoStyleList)
+ m_pAutoStyleList->ExecuteAllNow(); // Execute template timeouts now
+ if (GetCreateMode()== SfxObjectCreateMode::STANDARD)
+ SfxObjectShell::SetVisArea( tools::Rectangle() ); // Edited normally -> no VisArea
+
+ OSL_ENSURE( rMed.GetFilter(), "Filter == 0" );
+
+ bool bRet = false;
+ OUString aFltName = rMed.GetFilter()->GetFilterName();
+
+ if (aFltName == pFilterXML)
+ {
+ //TODO/LATER: this shouldn't happen!
+ OSL_FAIL("XML filter in ConvertFrom?!");
+ bRet = SaveXML( &rMed, nullptr );
+ }
+ else if (aFltName == pFilterExcel5 || aFltName == pFilterExcel95 ||
+ aFltName == pFilterExcel97 || aFltName == pFilterEx5Temp ||
+ aFltName == pFilterEx95Temp || aFltName == pFilterEx97Temp)
+ {
+ weld::WaitObject aWait( GetActiveDialogParent() );
+
+ bool bDoSave = true;
+ if( ScTabViewShell* pViewShell = GetBestViewShell() )
+ {
+ ScExtDocOptions* pExtDocOpt = m_pDocument->GetExtDocOptions();
+ if( !pExtDocOpt )
+ {
+ m_pDocument->SetExtDocOptions( std::make_unique<ScExtDocOptions>() );
+ pExtDocOpt = m_pDocument->GetExtDocOptions();
+ }
+ pViewShell->GetViewData().WriteExtOptions( *pExtDocOpt );
+
+ /* #i104990# If the imported document contains a medium
+ password, determine if we can save it, otherwise ask the users
+ whether they want to save without it. */
+ if( (rMed.GetFilter()->GetFilterFlags() & SfxFilterFlags::ENCRYPTION) == SfxFilterFlags::NONE )
+ {
+ SfxItemSet* pItemSet = rMed.GetItemSet();
+ if( pItemSet && pItemSet->GetItemState( SID_PASSWORD ) == SfxItemState::SET )
+ {
+ bDoSave = ScWarnPassword::WarningOnPassword( rMed );
+ // #i42858# remove password from medium (warn only one time)
+ if( bDoSave )
+ pItemSet->ClearItem( SID_PASSWORD );
+ }
+ }
+
+ if( bDoSave )
+ {
+ bool bNeedRetypePassDlg = ScPassHashHelper::needsPassHashRegen( *m_pDocument, PASSHASH_XL );
+ bDoSave = !bNeedRetypePassDlg || pViewShell->ExecuteRetypePassDlg( PASSHASH_XL );
+ }
+ }
+
+ if( bDoSave )
+ {
+ ExportFormatExcel eFormat = ExpBiff5;
+ if( aFltName == pFilterExcel97 || aFltName == pFilterEx97Temp )
+ eFormat = ExpBiff8;
+ ErrCode eError = ScFormatFilter::Get().ScExportExcel5( rMed, m_pDocument.get(), eFormat, RTL_TEXTENCODING_MS_1252 );
+
+ if( eError && !GetError() )
+ SetError(eError);
+
+ // don't return false for warnings
+ bRet = eError.IsWarning() || (eError == ERRCODE_NONE);
+ }
+ else
+ {
+ // export aborted, i.e. "Save without password" warning
+ SetError(ERRCODE_ABORT);
+ }
+ }
+ else if (aFltName == SC_TEXT_CSV_FILTER_NAME)
+ {
+ OUString sItStr;
+ SfxItemSet* pSet = rMed.GetItemSet();
+ const SfxStringItem* pOptionsItem;
+ if ( pSet &&
+ (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
+ {
+ sItStr = pOptionsItem->GetValue();
+ }
+
+ if ( sItStr.isEmpty() )
+ {
+ // default for ascii export (from API without options):
+ // ISO8859-1/MS_1252 encoding, comma, double quotes
+
+ ScImportOptions aDefOptions( ',', '"', RTL_TEXTENCODING_MS_1252 );
+ sItStr = aDefOptions.BuildString();
+ }
+
+ weld::WaitObject aWait( GetActiveDialogParent() );
+ ScImportOptions aOptions( sItStr );
+
+ if (aOptions.nSheetToExport)
+ {
+ // Only from command line --convert-to
+ bRet = true;
+
+ // Verbose only from command line, not UI (in case we actually
+ // implement that) nor macro filter options.
+ bool bVerbose = false;
+ const css::uno::Sequence<css::beans::PropertyValue> & rArgs = rMed.GetArgs();
+ const auto pProp = std::find_if( rArgs.begin(), rArgs.end(),
+ [](const css::beans::PropertyValue& rProp) { return rProp.Name == "ConversionRequestOrigin"; });
+ if (pProp != rArgs.end())
+ {
+ OUString aOrigin;
+ pProp->Value >>= aOrigin;
+ bVerbose = (aOrigin == "CommandLine");
+ }
+
+ SCTAB nStartTab;
+ SCTAB nCount = m_pDocument->GetTableCount();
+ if (aOptions.nSheetToExport == -1)
+ {
+ // All sheets.
+ nStartTab = 0;
+ }
+ else if (0 < aOptions.nSheetToExport && aOptions.nSheetToExport <= nCount)
+ {
+ // One sheet, 1-based.
+ nCount = aOptions.nSheetToExport;
+ nStartTab = nCount - 1;
+ }
+ else
+ {
+ // Usage error, no export but log.
+ if (bVerbose)
+ {
+ if (aOptions.nSheetToExport < 0)
+ std::cout << "Bad sheet number string given." << std::endl;
+ else
+ std::cout << "No sheet number " << aOptions.nSheetToExport
+ << ", number of sheets is " << nCount << std::endl;
+ }
+ nStartTab = 0;
+ nCount = 0;
+ SetError(SCERR_EXPORT_DATA);
+ bRet = false;
+ }
+
+ INetURLObject aURLObject(rMed.GetURLObject());
+ OUString sExt = aURLObject.CutExtension();
+ OUString sBaseName = aURLObject.GetLastName();
+ aURLObject.CutLastName();
+
+ for (SCTAB i = nStartTab; i < nCount; ++i)
+ {
+ OUString sTabName;
+ if (!m_pDocument->GetName(i, sTabName))
+ sTabName = OUString::number(i);
+ INetURLObject aSheetURLObject(aURLObject);
+ OUString sFileName = sBaseName + "-" + sTabName;
+ if (!sExt.isEmpty())
+ sFileName = sFileName + "." + sExt;
+ aSheetURLObject.Append(sFileName);
+
+ // log similar to DispatchWatcher::executeDispatchRequests
+ OUString aOutFile = aSheetURLObject.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ if (bVerbose)
+ {
+ OUString aDisplayedName;
+ if (osl::FileBase::E_None != osl::FileBase::getSystemPathFromFileURL(aOutFile, aDisplayedName))
+ aDisplayedName = aOutFile;
+ std::cout << "Writing sheet " << OUStringToOString(sTabName, osl_getThreadTextEncoding()) << " -> "
+ << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding())
+ << std::endl;
+
+ if (FStatHelper::IsDocument(aOutFile))
+ std::cout << "Overwriting: " << OUStringToOString(aDisplayedName, osl_getThreadTextEncoding())
+ << std::endl ;
+ }
+
+ std::unique_ptr<SvStream> xStm = ::utl::UcbStreamHelper::CreateStream(aOutFile, StreamMode::TRUNC | StreamMode::WRITE);
+ if (!xStm)
+ {
+ SetError(ERRCODE_IO_CANTCREATE);
+ bRet = false;
+ break;
+ }
+ AsciiSave(*xStm, aOptions, i);
+ }
+ }
+ else
+ {
+ SvStream* pStream = rMed.GetOutStream();
+ if (pStream)
+ {
+ AsciiSave(*pStream, aOptions, GetSaveTab());
+ bRet = true;
+
+ if (m_pDocument->GetTableCount() > 1)
+ if (!rMed.GetError())
+ rMed.SetError(SCWARN_EXPORT_ASCII);
+ }
+ }
+ }
+ else if (aFltName == pFilterDBase)
+ {
+ OUString sCharSet;
+ SfxItemSet* pSet = rMed.GetItemSet();
+ const SfxStringItem* pOptionsItem;
+ if ( pSet &&
+ (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
+ {
+ sCharSet = pOptionsItem->GetValue();
+ }
+
+ if (sCharSet.isEmpty())
+ {
+ // default for dBase export (from API without options):
+ // IBM_850 encoding
+
+ sCharSet = ScGlobal::GetCharsetString( RTL_TEXTENCODING_IBM_850 );
+ }
+
+ weld::WaitObject aWait( GetActiveDialogParent() );
+ // Hack so that Sba can overwrite the opened TempFile.
+ rMed.CloseOutStream();
+ bool bHasMemo = false;
+
+ ErrCode eError = DBaseExport(
+ rMed.GetPhysicalName(), ScGlobal::GetCharsetValue(sCharSet), bHasMemo);
+
+ INetURLObject aTmpFile( rMed.GetPhysicalName(), INetProtocol::File );
+ if ( bHasMemo )
+ aTmpFile.setExtension(u"dbt");
+ if ( eError != ERRCODE_NONE && !eError.IsWarning() )
+ {
+ if (!GetError())
+ SetError(eError);
+ if ( bHasMemo && IsDocument( aTmpFile ) )
+ KillFile( aTmpFile );
+ }
+ else
+ {
+ bRet = true;
+ if ( bHasMemo )
+ {
+ const SfxStringItem* pNameItem = rMed.GetItemSet()->GetItem<SfxStringItem>( SID_FILE_NAME );
+ INetURLObject aDbtFile( pNameItem->GetValue(), INetProtocol::File );
+ aDbtFile.setExtension(u"dbt");
+
+ // tdf#40713: don't lose dbt file
+ // if aDbtFile corresponds exactly to aTmpFile, we just have to return
+ if (aDbtFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ) ==
+ aTmpFile.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous ))
+ {
+ if (eError != ERRCODE_NONE && !GetError())
+ SetError(eError);
+ return bRet;
+ }
+
+ if ( IsDocument( aDbtFile ) && !KillFile( aDbtFile ) )
+ bRet = false;
+ if ( bRet && !MoveFile( aTmpFile, aDbtFile ) )
+ bRet = false;
+ if ( !bRet )
+ {
+ KillFile( aTmpFile );
+ if (eError == ERRCODE_NONE || eError.IsWarning())
+ eError = SCERR_EXPORT_DATA;
+ }
+ }
+ if (eError != ERRCODE_NONE && !GetError())
+ SetError(eError);
+ }
+ }
+ else if (aFltName == pFilterDif)
+ {
+ SvStream* pStream = rMed.GetOutStream();
+ if (pStream)
+ {
+ OUString sItStr;
+ SfxItemSet* pSet = rMed.GetItemSet();
+ const SfxStringItem* pOptionsItem;
+ if ( pSet &&
+ (pOptionsItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
+ {
+ sItStr = pOptionsItem->GetValue();
+ }
+
+ if (sItStr.isEmpty())
+ {
+ // default for DIF export (from API without options):
+ // ISO8859-1/MS_1252 encoding
+
+ sItStr = ScGlobal::GetCharsetString( RTL_TEXTENCODING_MS_1252 );
+ }
+
+ weld::WaitObject aWait( GetActiveDialogParent() );
+ ScFormatFilter::Get().ScExportDif( *pStream, m_pDocument.get(), ScAddress(0,0,0),
+ ScGlobal::GetCharsetValue(sItStr) );
+ bRet = true;
+
+ if (m_pDocument->GetTableCount() > 1)
+ if (!rMed.GetError())
+ rMed.SetError(SCWARN_EXPORT_ASCII);
+ }
+ }
+ else if (aFltName == pFilterSylk)
+ {
+ SvStream* pStream = rMed.GetOutStream();
+ if ( pStream )
+ {
+ weld::WaitObject aWait( GetActiveDialogParent() );
+
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ m_pDocument->GetCellArea( 0, nEndCol, nEndRow );
+ ScRange aRange( 0,0,0, nEndCol,nEndRow,0 );
+
+ ScImportExport aImExport( *m_pDocument, aRange );
+ aImExport.SetFormulas( true );
+ bRet = aImExport.ExportStream( *pStream, rMed.GetBaseURL( true ), SotClipboardFormatId::SYLK );
+ }
+ }
+ else if (aFltName == pFilterHtml)
+ {
+ SvStream* pStream = rMed.GetOutStream();
+ if ( pStream )
+ {
+ SfxItemSet* pSet = rMed.GetItemSet();
+ OUString sFilterOptions;
+
+ if (const SfxStringItem* pOptionsItem = pSet->GetItemIfSet(SID_FILE_FILTEROPTIONS))
+ sFilterOptions = pOptionsItem->GetValue();
+
+ weld::WaitObject aWait(GetActiveDialogParent());
+ ScImportExport aImExport(*m_pDocument);
+ aImExport.SetStreamPath(rMed.GetName());
+ aImExport.SetFilterOptions(sFilterOptions);
+ bRet = aImExport.ExportStream(*pStream, rMed.GetBaseURL(true), SotClipboardFormatId::HTML);
+ if (bRet && !aImExport.GetNonConvertibleChars().isEmpty())
+ {
+ SetError(*new StringErrorInfo(
+ SCWARN_EXPORT_NONCONVERTIBLE_CHARS,
+ aImExport.GetNonConvertibleChars(),
+ DialogMask::ButtonsOk | DialogMask::MessageInfo));
+ }
+ }
+ }
+ else
+ {
+ if (GetError())
+ SetError(SCERR_IMPORT_NI);
+ }
+ return bRet;
+}
+
+bool ScDocShell::DoSaveCompleted( SfxMedium * pNewStor, bool bRegisterRecent )
+{
+ bool bRet = SfxObjectShell::DoSaveCompleted( pNewStor, bRegisterRecent );
+
+ // SfxHintId::ScDocSaved for change ReadOnly -> Read/Write
+ Broadcast( SfxHint( SfxHintId::ScDocSaved ) );
+ return bRet;
+}
+
+bool ScDocShell::QuerySlotExecutable( sal_uInt16 nSlotId )
+{
+ // #i112634# ask VBA event handlers whether to save or print the document
+
+ using namespace ::com::sun::star::script::vba;
+
+ sal_Int32 nVbaEventId = VBAEventId::NO_EVENT;
+ uno::Sequence< uno::Any > aArgs;
+ switch( nSlotId )
+ {
+ case SID_SAVEDOC:
+ case SID_SAVEASDOC:
+ nVbaEventId = VBAEventId::WORKBOOK_BEFORESAVE;
+ aArgs = { uno::Any(nSlotId == SID_SAVEASDOC) };
+ break;
+ case SID_PRINTDOC:
+ case SID_PRINTDOCDIRECT:
+ nVbaEventId = VBAEventId::WORKBOOK_BEFOREPRINT;
+ break;
+ }
+
+ bool bSlotExecutable = true;
+ if( nVbaEventId != VBAEventId::NO_EVENT ) try
+ {
+ uno::Reference< XVBAEventProcessor > xEventProcessor( m_pDocument->GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ xEventProcessor->processVbaEvent( nVbaEventId, aArgs );
+ }
+ catch( util::VetoException& )
+ {
+ bSlotExecutable = false;
+ }
+ catch( uno::Exception& )
+ {
+ }
+ return bSlotExecutable;
+}
+
+bool ScDocShell::PrepareClose( bool bUI )
+{
+ if(SC_MOD()->GetCurRefDlgId()>0)
+ {
+ SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this );
+ if( pFrame )
+ {
+ SfxViewShell* p = pFrame->GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p );
+ if(pViewSh!=nullptr)
+ {
+ vcl::Window *pWin=pViewSh->GetWindow();
+ if(pWin!=nullptr) pWin->GrabFocus();
+ }
+ }
+
+ return false;
+ }
+ if ( m_pDocument->IsInLinkUpdate() || m_pDocument->IsInInterpreter() )
+ {
+ ErrorMessage(STR_CLOSE_ERROR_LINK);
+ return false;
+ }
+
+ DoEnterHandler();
+
+ // start 'Workbook_BeforeClose' VBA event handler for possible veto
+ if( !IsInPrepareClose() )
+ {
+ try
+ {
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( m_pDocument->GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ uno::Sequence< uno::Any > aArgs;
+ xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_BEFORECLOSE, aArgs );
+ }
+ catch( util::VetoException& )
+ {
+ // if event processor throws VetoException, macro has vetoed close
+ return false;
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ // end handler code
+
+ bool bRet = SfxObjectShell::PrepareClose( bUI );
+ if (bRet) // true == close
+ m_pDocument->EnableIdle(false); // Do not mess around with it anymore!
+
+ return bRet;
+}
+
+OUString ScDocShell::GetOwnFilterName()
+{
+ return pFilterSc50;
+}
+
+OUString ScDocShell::GetHtmlFilterName()
+{
+ return pFilterHtml;
+}
+
+OUString ScDocShell::GetWebQueryFilterName()
+{
+ return pFilterHtmlWebQ;
+}
+
+OUString ScDocShell::GetAsciiFilterName()
+{
+ return SC_TEXT_CSV_FILTER_NAME;
+}
+
+OUString ScDocShell::GetLotusFilterName()
+{
+ return pFilterLotus;
+}
+
+OUString ScDocShell::GetDBaseFilterName()
+{
+ return pFilterDBase;
+}
+
+OUString ScDocShell::GetDifFilterName()
+{
+ return pFilterDif;
+}
+
+bool ScDocShell::HasAutomaticTableName( std::u16string_view rFilter )
+{
+ // sal_True for those filters that keep the default table name
+ // (which is language specific)
+
+ return rFilter == SC_TEXT_CSV_FILTER_NAME
+ || rFilter == pFilterLotus
+ || rFilter == pFilterExcel4
+ || rFilter == pFilterEx4Temp
+ || rFilter == pFilterDBase
+ || rFilter == pFilterDif
+ || rFilter == pFilterSylk
+ || rFilter == pFilterHtml
+ || rFilter == pFilterRtf;
+}
+
+std::unique_ptr<ScDocFunc> ScDocShell::CreateDocFunc()
+{
+ return std::make_unique<ScDocFuncDirect>( *this );
+}
+
+ScDocShell::ScDocShell( const SfxModelFlags i_nSfxCreationFlags, const std::shared_ptr<ScDocument>& pDoc ) :
+ SfxObjectShell( i_nSfxCreationFlags ),
+ m_pDocument ( pDoc ? pDoc : std::make_shared<ScDocument>( SCDOCMODE_DOCUMENT, this )),
+ m_aDdeTextFmt(OUString("TEXT")),
+ m_nPrtToScreenFactor( 1.0 ),
+ m_pImpl ( new DocShell_Impl ),
+ m_bHeaderOn ( true ),
+ m_bFooterOn ( true ),
+ m_bIsEmpty ( true ),
+ m_bIsInUndo ( false ),
+ m_bDocumentModifiedPending( false ),
+ m_bUpdateEnabled ( true ),
+ m_bUcalcTest ( false ),
+ m_bAreasChangedNeedBroadcast( false ),
+ m_nDocumentLock ( 0 ),
+ m_nCanUpdate (css::document::UpdateDocMode::ACCORDING_TO_CONFIG)
+{
+ SetPool( &SC_MOD()->GetPool() );
+
+ m_bIsInplace = (GetCreateMode() == SfxObjectCreateMode::EMBEDDED);
+ // Will be reset if not in place
+
+ m_pDocFunc = CreateDocFunc();
+
+ // SetBaseModel needs exception handling
+ ScModelObj::CreateAndSet( this );
+
+ StartListening(*this);
+ SfxStyleSheetPool* pStlPool = m_pDocument->GetStyleSheetPool();
+ if (pStlPool)
+ StartListening(*pStlPool);
+
+ m_pDocument->GetDBCollection()->SetRefreshHandler(
+ LINK( this, ScDocShell, RefreshDBDataHdl ) );
+
+ // InitItems and CalcOutputFactor are called now in Load/ConvertFrom/InitNew
+}
+
+ScDocShell::~ScDocShell()
+{
+ ResetDrawObjectShell(); // If the Drawing Layer still tries to access it, access it
+
+ SfxStyleSheetPool* pStlPool = m_pDocument->GetStyleSheetPool();
+ if (pStlPool)
+ EndListening(*pStlPool);
+ EndListening(*this);
+
+ m_pAutoStyleList.reset();
+
+ SfxApplication *pSfxApp = SfxGetpApp();
+ if ( pSfxApp->GetDdeService() ) // Delete DDE for Document
+ pSfxApp->RemoveDdeTopic( this );
+
+ m_pDocFunc.reset();
+ delete m_pDocument->mpUndoManager;
+ m_pDocument->mpUndoManager = nullptr;
+ m_pImpl.reset();
+
+ m_pPaintLockData.reset();
+
+ m_pSolverSaveData.reset();
+ m_pSheetSaveData.reset();
+ m_pFormatSaveData.reset();
+ m_pOldAutoDBRange.reset();
+
+ if (m_pModificator)
+ {
+ OSL_FAIL("The Modificator should not exist");
+ m_pModificator.reset();
+ }
+}
+
+SfxUndoManager* ScDocShell::GetUndoManager()
+{
+ return m_pDocument->GetUndoManager();
+}
+
+void ScDocShell::SetModified( bool bModified )
+{
+ if ( SfxObjectShell::IsEnableSetModified() )
+ {
+ SfxObjectShell::SetModified( bModified );
+ Broadcast( SfxHint( SfxHintId::DocChanged ) );
+ }
+}
+
+void ScDocShell::SetDocumentModified()
+{
+ // BroadcastUno must also happen right away with pPaintLockData
+ // FIXME: Also for SetDrawModified, if Drawing is connected
+ // FIXME: Then own Hint?
+
+ if ( m_pPaintLockData )
+ {
+ // #i115009# broadcast BCA_BRDCST_ALWAYS, so a component can read recalculated results
+ // of RecalcModeAlways formulas (like OFFSET) after modifying cells
+ m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
+ m_pDocument->InvalidateTableArea(); // #i105279# needed here
+ m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
+
+ m_pPaintLockData->SetModified(); // Later on ...
+ return;
+ }
+
+ SetDrawModified();
+
+ if ( m_pDocument->IsAutoCalcShellDisabled() )
+ SetDocumentModifiedPending( true );
+ else
+ {
+ SetDocumentModifiedPending( false );
+ m_pDocument->InvalidateStyleSheetUsage();
+ m_pDocument->InvalidateTableArea();
+ m_pDocument->InvalidateLastTableOpParams();
+ m_pDocument->Broadcast(ScHint(SfxHintId::ScDataChanged, BCA_BRDCST_ALWAYS));
+ if ( m_pDocument->IsForcedFormulaPending() && m_pDocument->GetAutoCalc() )
+ m_pDocument->CalcFormulaTree( true );
+ m_pDocument->RefreshDirtyTableColumnNames();
+ PostDataChanged();
+
+ // Detective AutoUpdate:
+ // Update if formulas were modified (DetectiveDirty) or the list contains
+ // "Trace Error" entries (Trace Error can look completely different
+ // after changes to non-formula cells).
+
+ ScDetOpList* pList = m_pDocument->GetDetOpList();
+ if ( pList && ( m_pDocument->IsDetectiveDirty() || pList->HasAddError() ) &&
+ pList->Count() && !IsInUndo() && SC_MOD()->GetAppOptions().GetDetectiveAuto() )
+ {
+ GetDocFunc().DetectiveRefresh(true); // sal_True = caused by automatic update
+ }
+ m_pDocument->SetDetectiveDirty(false); // always reset, also if not refreshed
+ }
+
+ if (m_bAreasChangedNeedBroadcast)
+ {
+ m_bAreasChangedNeedBroadcast = false;
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged));
+ }
+
+ // notify UNO objects after BCA_BRDCST_ALWAYS etc.
+ m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
+}
+
+/**
+ * SetDrawModified - without Formula update
+ *
+ * Drawing also needs to be updated for the normal SetDocumentModified
+ * e.g.: when deleting tables etc.
+ */
+void ScDocShell::SetDrawModified()
+{
+ bool bUpdate = !IsModified();
+
+ SetModified();
+
+ SfxBindings* pBindings = GetViewBindings();
+ if (bUpdate && pBindings)
+ {
+ pBindings->Invalidate( SID_SAVEDOC );
+ pBindings->Invalidate( SID_DOC_MODIFIED );
+ }
+
+ if (pBindings)
+ {
+ // #i105960# Undo etc used to be volatile.
+ // They always have to be invalidated, including drawing layer or row height changes
+ // (but not while pPaintLockData is set).
+ pBindings->Invalidate( SID_UNDO );
+ pBindings->Invalidate( SID_REDO );
+ pBindings->Invalidate( SID_REPEAT );
+ }
+
+ if ( m_pDocument->IsChartListenerCollectionNeedsUpdate() )
+ {
+ m_pDocument->UpdateChartListenerCollection();
+ SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScDrawChanged )); // Navigator
+ }
+ SC_MOD()->AnythingChanged();
+}
+
+void ScDocShell::SetInUndo(bool bSet)
+{
+ m_bIsInUndo = bSet;
+}
+
+void ScDocShell::GetDocStat( ScDocStat& rDocStat )
+{
+ SfxPrinter* pPrinter = GetPrinter();
+
+ m_pDocument->GetDocStat( rDocStat );
+ rDocStat.nPageCount = 0;
+
+ if ( pPrinter )
+ for ( SCTAB i=0; i<rDocStat.nTableCount; i++ )
+ rDocStat.nPageCount = sal::static_int_cast<sal_uInt16>( rDocStat.nPageCount +
+ static_cast<sal_uInt16>(ScPrintFunc( this, pPrinter, i ).GetTotalPages()) );
+}
+
+std::shared_ptr<SfxDocumentInfoDialog> ScDocShell::CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet &rSet)
+{
+ std::shared_ptr<SfxDocumentInfoDialog> xDlg = std::make_shared<SfxDocumentInfoDialog>(pParent, rSet);
+ ScDocShell* pDocSh = dynamic_cast< ScDocShell *>( SfxObjectShell::Current() );
+
+ // Only for statistics, if this Doc is shown; not from the Doc Manager
+ if( pDocSh == this )
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ::CreateTabPage ScDocStatPageCreate = pFact->GetTabPageCreatorFunc(SID_SC_TP_STAT);
+ OSL_ENSURE(ScDocStatPageCreate, "Tabpage create fail!");
+ xDlg->AddFontTabPage();
+ xDlg->AddTabPage("calcstats", ScResId(STR_DOC_STAT), ScDocStatPageCreate);
+ }
+ return xDlg;
+}
+
+weld::Window* ScDocShell::GetActiveDialogParent()
+{
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ return pViewSh->GetDialogParent();
+ return Application::GetDefDialogParent();
+}
+
+void ScDocShell::SetSolverSaveData( std::unique_ptr<ScOptSolverSave> pData )
+{
+ m_pSolverSaveData = std::move(pData);
+}
+
+ScSheetSaveData* ScDocShell::GetSheetSaveData()
+{
+ if (!m_pSheetSaveData)
+ m_pSheetSaveData.reset( new ScSheetSaveData );
+
+ return m_pSheetSaveData.get();
+}
+
+ScFormatSaveData* ScDocShell::GetFormatSaveData()
+{
+ if (!m_pFormatSaveData)
+ m_pFormatSaveData.reset( new ScFormatSaveData );
+
+ return m_pFormatSaveData.get();
+}
+
+namespace {
+
+void removeKeysIfExists(const Reference<ui::XAcceleratorConfiguration>& xScAccel, const vector<const awt::KeyEvent*>& rKeys)
+{
+ for (const awt::KeyEvent* p : rKeys)
+ {
+ if (!p)
+ continue;
+
+ try
+ {
+ xScAccel->removeKeyEvent(*p);
+ }
+ catch (const container::NoSuchElementException&) {}
+ }
+}
+
+}
+
+void ScDocShell::ResetKeyBindings( ScOptionsUtil::KeyBindingType eType )
+{
+ using namespace ::com::sun::star::ui;
+
+ Reference<uno::XComponentContext> xContext = ::comphelper::getProcessComponentContext();
+ if (!xContext.is())
+ return;
+
+ Reference<XModuleUIConfigurationManagerSupplier> xModuleCfgSupplier(
+ theModuleUIConfigurationManagerSupplier::get(xContext) );
+
+ // Grab the Calc configuration.
+ Reference<XUIConfigurationManager> xConfigMgr =
+ xModuleCfgSupplier->getUIConfigurationManager(
+ "com.sun.star.sheet.SpreadsheetDocument");
+
+ if (!xConfigMgr.is())
+ return;
+
+ // shortcut manager
+ Reference<XAcceleratorConfiguration> xScAccel = xConfigMgr->getShortCutManager();
+
+ if (!xScAccel.is())
+ return;
+
+ vector<const awt::KeyEvent*> aKeys;
+ aKeys.reserve(9);
+
+ // Backspace key
+ awt::KeyEvent aBackspace;
+ aBackspace.KeyCode = awt::Key::BACKSPACE;
+ aBackspace.Modifiers = 0;
+ aKeys.push_back(&aBackspace);
+
+ // Delete key
+ awt::KeyEvent aDelete;
+ aDelete.KeyCode = awt::Key::DELETE;
+ aDelete.Modifiers = 0;
+ aKeys.push_back(&aDelete);
+
+ // Ctrl-D
+ awt::KeyEvent aCtrlD;
+ aCtrlD.KeyCode = awt::Key::D;
+ aCtrlD.Modifiers = awt::KeyModifier::MOD1;
+ aKeys.push_back(&aCtrlD);
+
+ // Alt-Down
+ awt::KeyEvent aAltDown;
+ aAltDown.KeyCode = awt::Key::DOWN;
+ aAltDown.Modifiers = awt::KeyModifier::MOD2;
+ aKeys.push_back(&aAltDown);
+
+ // Ctrl-Space
+ awt::KeyEvent aCtrlSpace;
+ aCtrlSpace.KeyCode = awt::Key::SPACE;
+ aCtrlSpace.Modifiers = awt::KeyModifier::MOD1;
+ aKeys.push_back(&aCtrlSpace);
+
+ // Ctrl-Shift-Space
+ awt::KeyEvent aCtrlShiftSpace;
+ aCtrlShiftSpace.KeyCode = awt::Key::SPACE;
+ aCtrlShiftSpace.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT;
+ aKeys.push_back(&aCtrlShiftSpace);
+
+ // F4
+ awt::KeyEvent aF4;
+ aF4.KeyCode = awt::Key::F4;
+ aF4.Modifiers = 0;
+ aKeys.push_back(&aF4);
+
+ // CTRL+SHIFT+F4
+ awt::KeyEvent aCtrlShiftF4;
+ aCtrlShiftF4.KeyCode = awt::Key::F4;
+ aCtrlShiftF4.Modifiers = awt::KeyModifier::MOD1 | awt::KeyModifier::SHIFT;
+ aKeys.push_back(&aCtrlShiftF4);
+
+ // SHIFT+F4
+ awt::KeyEvent aShiftF4;
+ aShiftF4.KeyCode = awt::Key::F4;
+ aShiftF4.Modifiers = awt::KeyModifier::SHIFT;
+ aKeys.push_back(&aShiftF4);
+
+ // Remove all involved keys first, because swapping commands don't work
+ // well without doing this.
+ removeKeysIfExists(xScAccel, aKeys);
+ xScAccel->store();
+
+ switch (eType)
+ {
+ case ScOptionsUtil::KEY_DEFAULT:
+ xScAccel->setKeyEvent(aDelete, ".uno:ClearContents");
+ xScAccel->setKeyEvent(aBackspace, ".uno:Delete");
+ xScAccel->setKeyEvent(aCtrlD, ".uno:FillDown");
+ xScAccel->setKeyEvent(aAltDown, ".uno:DataSelect");
+ xScAccel->setKeyEvent(aCtrlSpace, ".uno:SelectColumn");
+ xScAccel->setKeyEvent(aCtrlShiftSpace, ".uno:SelectAll");
+ xScAccel->setKeyEvent(aF4, ".uno:ToggleRelative");
+ xScAccel->setKeyEvent(aCtrlShiftF4, ".uno:ViewDataSourceBrowser");
+ break;
+ case ScOptionsUtil::KEY_OOO_LEGACY:
+ xScAccel->setKeyEvent(aDelete, ".uno:Delete");
+ xScAccel->setKeyEvent(aBackspace, ".uno:ClearContents");
+ xScAccel->setKeyEvent(aCtrlD, ".uno:DataSelect");
+ xScAccel->setKeyEvent(aCtrlShiftSpace, ".uno:SelectColumn");
+ xScAccel->setKeyEvent(aF4, ".uno:ViewDataSourceBrowser");
+ xScAccel->setKeyEvent(aShiftF4, ".uno:ToggleRelative");
+ break;
+ default:
+ ;
+ }
+
+ xScAccel->store();
+}
+
+void ScDocShell::UseSheetSaveEntries()
+{
+ if (!m_pSheetSaveData)
+ return;
+
+ m_pSheetSaveData->UseSaveEntries(); // use positions from saved file for next saving
+
+ bool bHasEntries = false;
+ SCTAB nTabCount = m_pDocument->GetTableCount();
+ SCTAB nTab;
+ for (nTab = 0; nTab < nTabCount; ++nTab)
+ if (m_pSheetSaveData->HasStreamPos(nTab))
+ bHasEntries = true;
+
+ if (!bHasEntries)
+ {
+ // if no positions were set (for example, export to other format),
+ // reset all "valid" flags
+ for (nTab = 0; nTab < nTabCount; ++nTab)
+ m_pDocument->SetStreamValid(nTab, false);
+ }
+}
+
+// --- ScDocShellModificator ------------------------------------------
+
+ScDocShellModificator::ScDocShellModificator( ScDocShell& rDS )
+ :
+ rDocShell( rDS ),
+ mpProtector(new ScRefreshTimerProtector(rDS.GetDocument().GetRefreshTimerControlAddress()))
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ bAutoCalcShellDisabled = rDoc.IsAutoCalcShellDisabled();
+ bIdleEnabled = rDoc.IsIdleEnabled();
+ rDoc.SetAutoCalcShellDisabled( true );
+ rDoc.EnableIdle(false);
+}
+
+ScDocShellModificator::~ScDocShellModificator() COVERITY_NOEXCEPT_FALSE
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
+ if ( !bAutoCalcShellDisabled && rDocShell.IsDocumentModifiedPending() )
+ rDocShell.SetDocumentModified(); // last one shuts off the lights
+ rDoc.EnableIdle(bIdleEnabled);
+}
+
+void ScDocShellModificator::SetDocumentModified()
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ rDoc.PrepareFormulaCalc();
+ if ( !rDoc.IsImportingXML() )
+ {
+ // temporarily restore AutoCalcShellDisabled
+ bool bDisabled = rDoc.IsAutoCalcShellDisabled();
+ rDoc.SetAutoCalcShellDisabled( bAutoCalcShellDisabled );
+ rDocShell.SetDocumentModified();
+ rDoc.SetAutoCalcShellDisabled( bDisabled );
+ }
+ else
+ {
+ // uno broadcast is necessary for api to work
+ // -> must also be done during xml import
+ rDoc.BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
+ }
+}
+
+bool ScDocShell::IsChangeRecording() const
+{
+ ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
+ return pChangeTrack != nullptr;
+}
+
+bool ScDocShell::HasChangeRecordProtection() const
+{
+ bool bRes = false;
+ ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
+ if (pChangeTrack)
+ bRes = pChangeTrack->IsProtected();
+ return bRes;
+}
+
+void ScDocShell::SetChangeRecording( bool bActivate, bool /*bLockAllViews*/ )
+{
+ bool bOldChangeRecording = IsChangeRecording();
+
+ if (bActivate)
+ {
+ m_pDocument->StartChangeTracking();
+ ScChangeViewSettings aChangeViewSet;
+ aChangeViewSet.SetShowChanges(true);
+ m_pDocument->SetChangeViewSettings(aChangeViewSet);
+ }
+ else
+ {
+ m_pDocument->EndChangeTracking();
+ PostPaintGridAll();
+ }
+
+ if (bOldChangeRecording != IsChangeRecording())
+ {
+ UpdateAcceptChangesDialog();
+ // invalidate slots
+ SfxBindings* pBindings = GetViewBindings();
+ if (pBindings)
+ pBindings->InvalidateAll(false);
+ }
+}
+
+void ScDocShell::SetProtectionPassword( const OUString &rNewPassword )
+{
+ ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
+ if (!pChangeTrack)
+ return;
+
+ bool bProtected = pChangeTrack->IsProtected();
+
+ if (!rNewPassword.isEmpty())
+ {
+ // when password protection is applied change tracking must always be active
+ SetChangeRecording( true );
+
+ css::uno::Sequence< sal_Int8 > aProtectionHash;
+ SvPasswordHelper::GetHashPassword( aProtectionHash, rNewPassword );
+ pChangeTrack->SetProtection( aProtectionHash );
+ }
+ else
+ {
+ pChangeTrack->SetProtection( css::uno::Sequence< sal_Int8 >() );
+ }
+
+ if ( bProtected != pChangeTrack->IsProtected() )
+ {
+ UpdateAcceptChangesDialog();
+ SetDocumentModified();
+ }
+}
+
+bool ScDocShell::GetProtectionHash( /*out*/ css::uno::Sequence< sal_Int8 > &rPasswordHash )
+{
+ bool bRes = false;
+ ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
+ if (pChangeTrack && pChangeTrack->IsProtected())
+ {
+ rPasswordHash = pChangeTrack->GetProtection();
+ bRes = true;
+ }
+ return bRes;
+}
+
+void ScDocShell::SetIsInUcalc()
+{
+ m_bUcalcTest = true;
+}
+
+void ScDocShell::RegisterAutomationWorkbookObject(css::uno::Reference< ooo::vba::excel::XWorkbook > const& xWorkbook)
+{
+ mxAutomationWorkbookObject = xWorkbook;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportSLK(SvStream &rStream)
+{
+ ScDLL::Init();
+ ScDocument aDocument;
+ ScDocOptions aDocOpt = aDocument.GetDocOptions();
+ aDocOpt.SetLookUpColRowNames(false);
+ aDocument.SetDocOptions(aDocOpt);
+ aDocument.MakeTable(0);
+ aDocument.EnableExecuteLink(false);
+ aDocument.SetInsertingFromOtherDoc(true);
+ aDocument.SetImportingXML(true);
+
+ ScImportExport aImpEx(aDocument);
+ return aImpEx.ImportStream(rStream, OUString(), SotClipboardFormatId::SYLK);
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportDBF(SvStream &rStream)
+{
+ ScDLL::Init();
+
+ // we need a real file for this filter
+
+ // put it in an empty dir
+ utl::TempFile aTmpDir(nullptr, true);
+ aTmpDir.EnableKillingFile();
+ OUString sTmpDir = aTmpDir.GetURL();
+
+ OUString sExtension(".dbf");
+ utl::TempFile aTempInput(u"", true, &sExtension, &sTmpDir);
+ aTempInput.EnableKillingFile();
+
+ SvStream* pInputStream = aTempInput.GetStream(StreamMode::WRITE);
+ sal_uInt8 aBuffer[8192];
+ while (auto nRead = rStream.ReadBytes(aBuffer, SAL_N_ELEMENTS(aBuffer)))
+ pInputStream->WriteBytes(aBuffer, nRead);
+ aTempInput.CloseStream();
+
+ SfxMedium aMedium(aTempInput.GetURL(), StreamMode::STD_READWRITE);
+
+ ScDocShellRef xDocShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT |
+ SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS |
+ SfxModelFlags::DISABLE_DOCUMENT_RECOVERY);
+
+ xDocShell->DoInitNew();
+
+ ScDocument& rDoc = xDocShell->GetDocument();
+
+ ScDocOptions aDocOpt = rDoc.GetDocOptions();
+ aDocOpt.SetLookUpColRowNames(false);
+ rDoc.SetDocOptions(aDocOpt);
+ rDoc.MakeTable(0);
+ rDoc.EnableExecuteLink(false);
+ rDoc.SetInsertingFromOtherDoc(true);
+
+ ScDocRowHeightUpdater::TabRanges aRecalcRanges(0, rDoc.MaxRow());
+ std::map<SCCOL, ScColWidthParam> aColWidthParam;
+ ErrCode eError = xDocShell->DBaseImport(aMedium.GetPhysicalName(), RTL_TEXTENCODING_IBM_850, aColWidthParam, aRecalcRanges.maRanges);
+
+ xDocShell->DoClose();
+ xDocShell.clear();
+
+ return eError == ERRCODE_NONE;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docsh2.cxx b/sc/source/ui/docshell/docsh2.cxx
new file mode 100644
index 000000000..04faa6e75
--- /dev/null
+++ b/sc/source/ui/docshell/docsh2.cxx
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rtl/bootstrap.hxx>
+#include <osl/file.hxx>
+#include <svx/drawitem.hxx>
+#include <svl/asiancfg.hxx>
+#include <editeng/forbiddencharacterstable.hxx>
+#include <orcusfilters.hxx>
+#include <config_folders.h>
+#include <unotools/configmgr.hxx>
+#include <comphelper/processfactory.hxx>
+#include <o3tl/unit_conversion.hxx>
+
+#include <drwlayer.hxx>
+#include <stlpool.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <svx/svxids.hrc>
+#include <filter.hxx>
+#include <functional>
+
+using namespace com::sun::star;
+
+bool ScDocShell::InitNew( const uno::Reference < embed::XStorage >& xStor )
+{
+ bool bRet = SfxObjectShell::InitNew( xStor );
+
+ m_pDocument->MakeTable(0);
+
+ // Additional tables are created by the first View, if bIsEmpty is still sal_True
+ if( bRet )
+ {
+ Size aSize(
+ o3tl::convert(STD_COL_WIDTH * OLE_STD_CELLS_X, o3tl::Length::twip, o3tl::Length::mm100),
+ o3tl::convert(ScGlobal::nStdRowHeight * OLE_STD_CELLS_Y, o3tl::Length::twip,
+ o3tl::Length::mm100));
+ // Also adjust start here
+ SetVisAreaOrSize( tools::Rectangle( Point(), aSize ) );
+ }
+
+ // InitOptions sets the document languages, must be called before CreateStandardStyles
+ InitOptions(false);
+
+ if (ScStyleSheetPool* pStyleSheetPool = m_pDocument->GetStyleSheetPool())
+ {
+ pStyleSheetPool->CreateStandardStyles();
+ m_pDocument->UpdStlShtPtrsFrmNms();
+
+ if (!m_bUcalcTest)
+ {
+ /* Create styles that are imported through Orcus */
+
+ OUString aURL("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER "/calc/styles.xml");
+ rtl::Bootstrap::expandMacros(aURL);
+
+ OUString aPath;
+ osl::FileBase::getSystemPathFromFileURL(aURL, aPath);
+
+ ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
+ if (pOrcus)
+ {
+ pOrcus->importODS_Styles(*m_pDocument, aPath);
+ pStyleSheetPool->setAllParaStandard();
+ }
+ }
+ }
+
+ // SetDocumentModified is not allowed anymore in Load/InitNew!
+ InitItems();
+ CalcOutputFactor();
+
+ return bRet;
+}
+
+void ScDocShell::SetEmpty(bool bSet)
+{
+ m_bIsEmpty = bSet;
+}
+
+void ScDocShell::InitItems()
+{
+ // Fill AllItemSet for Controller with needed Items:
+ // Printer Options are set in GetPrinter when printing
+ UpdateFontList();
+
+ ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ PutItem( SvxColorListItem ( pDrawLayer->GetColorList(), SID_COLOR_TABLE ) );
+ PutItem( SvxGradientListItem( pDrawLayer->GetGradientList(), SID_GRADIENT_LIST ) );
+ PutItem( SvxHatchListItem ( pDrawLayer->GetHatchList(), SID_HATCH_LIST ) );
+ PutItem( SvxBitmapListItem ( pDrawLayer->GetBitmapList(), SID_BITMAP_LIST ) );
+ PutItem( SvxPatternListItem ( pDrawLayer->GetPatternList(), SID_PATTERN_LIST ) );
+ PutItem( SvxDashListItem ( pDrawLayer->GetDashList(), SID_DASH_LIST ) );
+ PutItem( SvxLineEndListItem ( pDrawLayer->GetLineEndList(), SID_LINEEND_LIST ) );
+
+ // Other modifications after creation of the DrawLayer
+ pDrawLayer->SetNotifyUndoActionHdl( std::bind( &ScDocFunc::NotifyDrawUndo, m_pDocFunc.get(), std::placeholders::_1 ) );
+ }
+ else if (!utl::ConfigManager::IsFuzzing())
+ {
+ // always use global color table instead of local copy
+ PutItem( SvxColorListItem( XColorList::GetStdColorList(), SID_COLOR_TABLE ) );
+ }
+
+ if (utl::ConfigManager::IsFuzzing() ||
+ (m_pDocument->GetForbiddenCharacters() && m_pDocument->IsValidAsianCompression() && m_pDocument->IsValidAsianKerning()))
+ return;
+
+ // get settings from SvxAsianConfig
+ SvxAsianConfig aAsian;
+
+ if (!m_pDocument->GetForbiddenCharacters())
+ {
+ // set forbidden characters if necessary
+ const uno::Sequence<lang::Locale> aLocales = aAsian.GetStartEndCharLocales();
+ if (aLocales.hasElements())
+ {
+ std::shared_ptr<SvxForbiddenCharactersTable> xForbiddenTable(
+ SvxForbiddenCharactersTable::makeForbiddenCharactersTable(comphelper::getProcessComponentContext()));
+
+ for (const lang::Locale& rLocale : aLocales)
+ {
+ i18n::ForbiddenCharacters aForbidden;
+ aAsian.GetStartEndChars( rLocale, aForbidden.beginLine, aForbidden.endLine );
+ LanguageType eLang = LanguageTag::convertToLanguageType(rLocale);
+
+ xForbiddenTable->SetForbiddenCharacters( eLang, aForbidden );
+ }
+
+ m_pDocument->SetForbiddenCharacters( xForbiddenTable );
+ }
+ }
+
+ if ( !m_pDocument->IsValidAsianCompression() )
+ {
+ // set compression mode from configuration if not already set (e.g. XML import)
+ m_pDocument->SetAsianCompression( aAsian.GetCharDistanceCompression() );
+ }
+
+ if ( !m_pDocument->IsValidAsianKerning() )
+ {
+ // set asian punctuation kerning from configuration if not already set (e.g. XML import)
+ m_pDocument->SetAsianKerning( !aAsian.IsKerningWesternTextOnly() ); // reversed
+ }
+}
+
+void ScDocShell::ResetDrawObjectShell()
+{
+ ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ pDrawLayer->SetObjectShell( nullptr );
+}
+
+ScDrawLayer* ScDocShell::MakeDrawLayer()
+{
+ ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer();
+ if (!pDrawLayer)
+ {
+ m_pDocument->InitDrawLayer(this);
+ pDrawLayer = m_pDocument->GetDrawLayer();
+ InitItems(); // including Undo and Basic
+ Broadcast( SfxHint( SfxHintId::ScDrawLayerNew ) );
+ if (m_nDocumentLock)
+ pDrawLayer->setLock(true);
+ }
+ return pDrawLayer;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docsh3.cxx b/sc/source/ui/docshell/docsh3.cxx
new file mode 100644
index 000000000..edab7a530
--- /dev/null
+++ b/sc/source/ui/docshell/docsh3.cxx
@@ -0,0 +1,1331 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+
+#include <scitems.hxx>
+#include <rangelst.hxx>
+#include <editeng/flstitem.hxx>
+#include <editeng/paperinf.hxx>
+#include <editeng/sizeitem.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <sal/log.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/printer.hxx>
+#include <svl/numformat.hxx>
+#include <svx/pageitem.hxx>
+#include <svx/postattr.hxx>
+#include <svx/svxids.hrc>
+#include <unotools/configmgr.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+#include <osl/diagnose.h>
+
+#include <docsh.hxx>
+#include "docshimp.hxx"
+#include <scmod.hxx>
+#include <tabvwsh.hxx>
+#include <viewdata.hxx>
+#include <docpool.hxx>
+#include <stlpool.hxx>
+#include <patattr.hxx>
+#include <uiitems.hxx>
+#include <hints.hxx>
+#include <docoptio.hxx>
+#include <viewopti.hxx>
+#include <pntlock.hxx>
+#include <chgtrack.hxx>
+#include <docfunc.hxx>
+#include <formulacell.hxx>
+#include <chgviset.hxx>
+#include <progress.hxx>
+#include <redcom.hxx>
+#include <inputopt.hxx>
+#include <drwlayer.hxx>
+#include <inputhdl.hxx>
+#include <conflictsdlg.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <markdata.hxx>
+#include <memory>
+#include <formulaopt.hxx>
+
+#include <comphelper/lok.hxx>
+#include <sfx2/lokhelper.hxx>
+
+// Redraw - Notifications
+
+void ScDocShell::PostEditView( ScEditEngineDefaulter* pEditEngine, const ScAddress& rCursorPos )
+{
+// Broadcast( ScEditViewHint( pEditEngine, rCursorPos ) );
+
+ // Test: only active ViewShell
+
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if (pViewSh && pViewSh->GetViewData().GetDocShell() == this)
+ {
+ ScEditViewHint aHint( pEditEngine, rCursorPos );
+ pViewSh->Notify( *this, aHint );
+ }
+}
+
+void ScDocShell::PostDataChanged()
+{
+ Broadcast( SfxHint( SfxHintId::ScDataChanged ) );
+ SfxGetpApp()->Broadcast(SfxHint( SfxHintId::ScAnyDataChanged )); // Navigator
+ m_pDocument->PrepareFormulaCalc();
+ //! notify navigator directly!
+}
+
+void ScDocShell::PostPaint( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, PaintPartFlags nPart,
+ sal_uInt16 nExtFlags )
+{
+ ScRange aRange(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
+ PostPaint(aRange, nPart, nExtFlags);
+}
+
+void ScDocShell::PostPaint( const ScRangeList& rRanges, PaintPartFlags nPart, sal_uInt16 nExtFlags )
+{
+ ScRangeList aPaintRanges;
+ for (size_t i = 0, n = rRanges.size(); i < n; ++i)
+ {
+ const ScRange& rRange = rRanges[i];
+ SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
+ SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
+ SCTAB nTab1 = rRange.aStart.Tab(), nTab2 = rRange.aEnd.Tab();
+
+ if (!m_pDocument->ValidCol(nCol1)) nCol1 = m_pDocument->MaxCol();
+ if (!m_pDocument->ValidRow(nRow1)) nRow1 = m_pDocument->MaxRow();
+ if (!m_pDocument->ValidCol(nCol2)) nCol2 = m_pDocument->MaxCol();
+ if (!m_pDocument->ValidRow(nRow2)) nRow2 = m_pDocument->MaxRow();
+
+ if ( m_pPaintLockData )
+ {
+ // #i54081# PaintPartFlags::Extras still has to be broadcast because it changes the
+ // current sheet if it's invalid. All other flags added to pPaintLockData.
+ PaintPartFlags nLockPart = nPart & ~PaintPartFlags::Extras;
+ if ( nLockPart != PaintPartFlags::NONE )
+ {
+ //! nExtFlags ???
+ m_pPaintLockData->AddRange( ScRange( nCol1, nRow1, nTab1,
+ nCol2, nRow2, nTab2 ), nLockPart );
+ }
+
+ nPart &= PaintPartFlags::Extras; // for broadcasting
+ if (nPart == PaintPartFlags::NONE)
+ continue;
+ }
+
+ if (nExtFlags & SC_PF_LINES) // respect space for lines
+ {
+ //! check for hidden columns/rows!
+ if (nCol1>0) --nCol1;
+ if (nCol2<m_pDocument->MaxCol()) ++nCol2;
+ if (nRow1>0) --nRow1;
+ if (nRow2<m_pDocument->MaxRow()) ++nRow2;
+ }
+
+ // expand for the merged ones
+ if (nExtFlags & SC_PF_TESTMERGE)
+ m_pDocument->ExtendMerge( nCol1, nRow1, nCol2, nRow2, nTab1 );
+
+ if ( nCol1 != 0 || nCol2 != m_pDocument->MaxCol() )
+ {
+ // Extend to whole rows if SC_PF_WHOLEROWS is set, or rotated or non-left
+ // aligned cells are contained (see UpdatePaintExt).
+ // Special handling for RTL text (#i9731#) is unnecessary now with full
+ // support of right-aligned text.
+
+ if ( ( nExtFlags & SC_PF_WHOLEROWS ) ||
+ m_pDocument->HasAttrib( nCol1,nRow1,nTab1,
+ m_pDocument->MaxCol(),nRow2,nTab2, HasAttrFlags::Rotate | HasAttrFlags::RightOrCenter ) )
+ {
+ nCol1 = 0;
+ nCol2 = m_pDocument->MaxCol();
+ }
+ }
+ aPaintRanges.push_back(ScRange(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2));
+ }
+
+ Broadcast(ScPaintHint(aPaintRanges.Combine(), nPart));
+
+ // LOK: we are supposed to update the row / columns headers (and actually
+ // the document size too - cell size affects that, obviously)
+ if ((nPart & (PaintPartFlags::Top | PaintPartFlags::Left)) && comphelper::LibreOfficeKit::isActive())
+ {
+ ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>(this->GetModel());
+ SfxLokHelper::notifyDocumentSizeChangedAllViews(pModel);
+ }
+}
+
+void ScDocShell::PostPaintGridAll()
+{
+ PostPaint( 0,0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB, PaintPartFlags::Grid );
+}
+
+void ScDocShell::PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid, SC_PF_TESTMERGE );
+}
+
+void ScDocShell::PostPaintCell( const ScAddress& rPos )
+{
+ PostPaintCell( rPos.Col(), rPos.Row(), rPos.Tab() );
+}
+
+void ScDocShell::PostPaintExtras()
+{
+ PostPaint( 0,0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB, PaintPartFlags::Extras );
+}
+
+void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, const ScRange& rRange )
+{
+ if ( ( rExtFlags & SC_PF_LINES ) == 0 &&
+ m_pDocument->HasAttrib( rRange, HasAttrFlags::Lines | HasAttrFlags::Shadow | HasAttrFlags::Conditional ) )
+ {
+ // If the range contains lines, shadow or conditional formats,
+ // set SC_PF_LINES to include one extra cell in all directions.
+
+ rExtFlags |= SC_PF_LINES;
+ }
+
+ if ( ( rExtFlags & SC_PF_WHOLEROWS ) == 0 &&
+ ( rRange.aStart.Col() != 0 || rRange.aEnd.Col() != m_pDocument->MaxCol() ) &&
+ m_pDocument->HasAttrib( rRange, HasAttrFlags::Rotate | HasAttrFlags::RightOrCenter ) )
+ {
+ // If the range contains (logically) right- or center-aligned cells,
+ // or rotated cells, set SC_PF_WHOLEROWS to paint the whole rows.
+ // This test isn't needed after the cell changes, because it's also
+ // tested in PostPaint. UpdatePaintExt may later be changed to do this
+ // only if called before the changes.
+
+ rExtFlags |= SC_PF_WHOLEROWS;
+ }
+}
+
+void ScDocShell::UpdatePaintExt( sal_uInt16& rExtFlags, SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab )
+{
+ UpdatePaintExt( rExtFlags, ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab ) );
+}
+
+void ScDocShell::LockPaint_Impl(bool bDoc)
+{
+ if ( !m_pPaintLockData )
+ m_pPaintLockData.reset( new ScPaintLockData );
+ m_pPaintLockData->IncLevel(bDoc);
+}
+
+void ScDocShell::UnlockPaint_Impl(bool bDoc)
+{
+ if ( m_pPaintLockData )
+ {
+ if ( m_pPaintLockData->GetLevel(bDoc) )
+ m_pPaintLockData->DecLevel(bDoc);
+ if (!m_pPaintLockData->GetLevel(!bDoc) && !m_pPaintLockData->GetLevel(bDoc))
+ {
+ // Execute Paint now
+
+ // don't continue collecting
+ std::unique_ptr<ScPaintLockData> pPaint = std::move(m_pPaintLockData);
+
+ ScRangeListRef xRangeList = pPaint->GetRangeList();
+ if ( xRangeList.is() )
+ {
+ PaintPartFlags nParts = pPaint->GetParts();
+ for ( size_t i = 0, nCount = xRangeList->size(); i < nCount; i++ )
+ {
+ //! nExtFlags ???
+ ScRange const & rRange = (*xRangeList)[i];
+ PostPaint( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab(),
+ nParts );
+ }
+ }
+
+ if ( pPaint->GetModified() )
+ SetDocumentModified();
+ }
+ }
+ else
+ {
+ OSL_FAIL("UnlockPaint without LockPaint");
+ }
+}
+
+void ScDocShell::LockDocument_Impl(sal_uInt16 nNew)
+{
+ if (!m_nDocumentLock)
+ {
+ ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ pDrawLayer->setLock(true);
+ }
+ m_nDocumentLock = nNew;
+}
+
+void ScDocShell::UnlockDocument_Impl(sal_uInt16 nNew)
+{
+ m_nDocumentLock = nNew;
+ if (!m_nDocumentLock)
+ {
+ ScDrawLayer* pDrawLayer = m_pDocument->GetDrawLayer();
+ if (pDrawLayer)
+ pDrawLayer->setLock(false);
+ }
+}
+
+void ScDocShell::SetLockCount(sal_uInt16 nNew)
+{
+ if (nNew) // set
+ {
+ if ( !m_pPaintLockData )
+ m_pPaintLockData.reset( new ScPaintLockData );
+ m_pPaintLockData->SetDocLevel(nNew-1);
+ LockDocument_Impl(nNew);
+ }
+ else if (m_pPaintLockData) // delete
+ {
+ m_pPaintLockData->SetDocLevel(0); // at unlock, execute immediately
+ UnlockPaint_Impl(true); // now
+ UnlockDocument_Impl(0);
+ }
+}
+
+void ScDocShell::LockPaint()
+{
+ LockPaint_Impl(false);
+}
+
+void ScDocShell::UnlockPaint()
+{
+ UnlockPaint_Impl(false);
+}
+
+void ScDocShell::LockDocument()
+{
+ LockPaint_Impl(true);
+ LockDocument_Impl(m_nDocumentLock + 1);
+}
+
+void ScDocShell::UnlockDocument()
+{
+ if (m_nDocumentLock)
+ {
+ UnlockPaint_Impl(true);
+ UnlockDocument_Impl(m_nDocumentLock - 1);
+ }
+ else
+ {
+ OSL_FAIL("UnlockDocument without LockDocument");
+ }
+}
+
+void ScDocShell::SetInplace( bool bInplace )
+{
+ if (m_bIsInplace != bInplace)
+ {
+ m_bIsInplace = bInplace;
+ CalcOutputFactor();
+ }
+}
+
+void ScDocShell::CalcOutputFactor()
+{
+ if (m_bIsInplace)
+ {
+ m_nPrtToScreenFactor = 1.0; // otherwise it does not match the inactive display
+ return;
+ }
+
+ bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg();
+ if (bTextWysiwyg)
+ {
+ m_nPrtToScreenFactor = 1.0;
+ return;
+ }
+
+ OUString aTestString(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789");
+ tools::Long nPrinterWidth = 0;
+ const ScPatternAttr* pPattern = &m_pDocument->GetPool()->GetDefaultItem(ATTR_PATTERN);
+
+ vcl::Font aDefFont;
+ OutputDevice* pRefDev = GetRefDevice();
+ MapMode aOldMode = pRefDev->GetMapMode();
+ vcl::Font aOldFont = pRefDev->GetFont();
+
+ pRefDev->SetMapMode(MapMode(MapUnit::MapPixel));
+ pPattern->GetFont(aDefFont, SC_AUTOCOL_BLACK, pRefDev); // font color doesn't matter here
+ pRefDev->SetFont(aDefFont);
+ nPrinterWidth = pRefDev->PixelToLogic(Size(pRefDev->GetTextWidth(aTestString), 0), MapMode(MapUnit::Map100thMM)).Width();
+ pRefDev->SetFont(aOldFont);
+ pRefDev->SetMapMode(aOldMode);
+
+ ScopedVclPtrInstance< VirtualDevice > pVirtWindow( *Application::GetDefaultDevice() );
+ pVirtWindow->SetMapMode(MapMode(MapUnit::MapPixel));
+ pPattern->GetFont(aDefFont, SC_AUTOCOL_BLACK, pVirtWindow); // font color doesn't matter here
+ pVirtWindow->SetFont(aDefFont);
+ double nWindowWidth = pVirtWindow->GetTextWidth(aTestString) / ScGlobal::nScreenPPTX;
+ nWindowWidth = o3tl::convert(nWindowWidth, o3tl::Length::twip, o3tl::Length::mm100);
+
+ if (nPrinterWidth && nWindowWidth)
+ m_nPrtToScreenFactor = nPrinterWidth / nWindowWidth;
+ else
+ {
+ OSL_FAIL("GetTextSize returns 0 ??");
+ m_nPrtToScreenFactor = 1.0;
+ }
+}
+
+void ScDocShell::InitOptions(bool bForLoading) // called from InitNew and Load
+{
+ // Settings from the SpellCheckCfg get into Doc- and ViewOptions
+
+ LanguageType nDefLang, nCjkLang, nCtlLang;
+ bool bAutoSpell;
+ ScModule::GetSpellSettings( nDefLang, nCjkLang, nCtlLang, bAutoSpell );
+ ScModule* pScMod = SC_MOD();
+
+ ScDocOptions aDocOpt = pScMod->GetDocOptions();
+ ScFormulaOptions aFormulaOpt = pScMod->GetFormulaOptions();
+ ScViewOptions aViewOpt = pScMod->GetViewOptions();
+ aDocOpt.SetAutoSpell( bAutoSpell );
+
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ // two-digit year entry from Tools->Options->General
+ aDocOpt.SetYear2000(officecfg::Office::Common::DateFormat::TwoDigitYear::get());
+ }
+
+ if (bForLoading)
+ {
+ // #i112123# No style:decimal-places attribute means automatic decimals, not the configured default,
+ // so it must not be taken from the global options.
+ // Calculation settings are handled separately in ScXMLBodyContext::EndElement.
+ aDocOpt.SetStdPrecision( SvNumberFormatter::UNLIMITED_PRECISION );
+
+ // fdo#78294 The default null-date if
+ // <table:null-date table:date-value='...' />
+ // is absent is 1899-12-30 regardless what the configuration is set to.
+ // Import filters may override this value.
+ aDocOpt.SetDate( 30, 12, 1899);
+ }
+
+ m_pDocument->SetDocOptions( aDocOpt );
+ m_pDocument->SetViewOptions( aViewOpt );
+ SetFormulaOptions( aFormulaOpt, bForLoading );
+
+ // print options are now set directly before the printing
+
+ m_pDocument->SetLanguage( nDefLang, nCjkLang, nCtlLang );
+}
+
+Printer* ScDocShell::GetDocumentPrinter() // for OLE
+{
+ return m_pDocument->GetPrinter();
+}
+
+SfxPrinter* ScDocShell::GetPrinter(bool bCreateIfNotExist)
+{
+ return m_pDocument->GetPrinter(bCreateIfNotExist);
+}
+
+void ScDocShell::UpdateFontList()
+{
+ // pImpl->pFontList = new FontList( GetPrinter(), Application::GetDefaultDevice() );
+ m_pImpl->pFontList.reset(new FontList(GetRefDevice(), nullptr));
+ SvxFontListItem aFontListItem( m_pImpl->pFontList.get(), SID_ATTR_CHAR_FONTLIST );
+ PutItem( aFontListItem );
+
+ CalcOutputFactor();
+}
+
+OutputDevice* ScDocShell::GetRefDevice()
+{
+ return m_pDocument->GetRefDevice();
+}
+
+sal_uInt16 ScDocShell::SetPrinter( VclPtr<SfxPrinter> const & pNewPrinter, SfxPrinterChangeFlags nDiffFlags )
+{
+ SfxPrinter *pOld = m_pDocument->GetPrinter( false );
+ if ( pOld && pOld->IsPrinting() )
+ return SFX_PRINTERROR_BUSY;
+
+ if (nDiffFlags & SfxPrinterChangeFlags::PRINTER)
+ {
+ if ( m_pDocument->GetPrinter() != pNewPrinter )
+ {
+ m_pDocument->SetPrinter( pNewPrinter );
+ m_pDocument->SetPrintOptions();
+
+ // MT: Use UpdateFontList: Will use Printer fonts only if needed!
+ /*
+ delete pImpl->pFontList;
+ pImpl->pFontList = new FontList( pNewPrinter, Application::GetDefaultDevice() );
+ SvxFontListItem aFontListItem( pImpl->pFontList, SID_ATTR_CHAR_FONTLIST );
+ PutItem( aFontListItem );
+
+ CalcOutputFactor();
+ */
+ if ( SC_MOD()->GetInputOptions().GetTextWysiwyg() )
+ UpdateFontList();
+
+ ScModule* pScMod = SC_MOD();
+ SfxViewFrame *pFrame = SfxViewFrame::GetFirst( this );
+ while (pFrame)
+ {
+ SfxViewShell* pSh = pFrame->GetViewShell();
+ if (ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(pSh))
+ {
+ ScInputHandler* pInputHdl = pScMod->GetInputHdl(pViewSh);
+ if (pInputHdl)
+ pInputHdl->UpdateRefDevice();
+ }
+ pFrame = SfxViewFrame::GetNext( *pFrame, this );
+ }
+ }
+ }
+ else if (nDiffFlags & SfxPrinterChangeFlags::JOBSETUP)
+ {
+ SfxPrinter* pOldPrinter = m_pDocument->GetPrinter();
+ if (pOldPrinter)
+ {
+ pOldPrinter->SetJobSetup( pNewPrinter->GetJobSetup() );
+
+ // #i6706# Call SetPrinter with the old printer again, so the drawing layer
+ // RefDevice is set (calling ReformatAllTextObjects and rebuilding charts),
+ // because the JobSetup (printer device settings) may affect text layout.
+ m_pDocument->SetPrinter( pOldPrinter );
+ CalcOutputFactor(); // also with the new settings
+ }
+ }
+
+ if (nDiffFlags & SfxPrinterChangeFlags::OPTIONS)
+ {
+ m_pDocument->SetPrintOptions(); //! from new printer ???
+ }
+
+ if (nDiffFlags & (SfxPrinterChangeFlags::CHG_ORIENTATION | SfxPrinterChangeFlags::CHG_SIZE))
+ {
+ OUString aStyle = m_pDocument->GetPageStyle( GetCurTab() );
+ ScStyleSheetPool* pStPl = m_pDocument->GetStyleSheetPool();
+ SfxStyleSheet* pStyleSheet = static_cast<SfxStyleSheet*>(pStPl->Find(aStyle, SfxStyleFamily::Page));
+ if (pStyleSheet)
+ {
+ SfxItemSet& rSet = pStyleSheet->GetItemSet();
+
+ if (nDiffFlags & SfxPrinterChangeFlags::CHG_ORIENTATION)
+ {
+ const SvxPageItem& rOldItem = rSet.Get(ATTR_PAGE);
+ bool bWasLand = rOldItem.IsLandscape();
+ bool bNewLand = ( pNewPrinter->GetOrientation() == Orientation::Landscape );
+ if (bNewLand != bWasLand)
+ {
+ SvxPageItem aNewItem( rOldItem );
+ aNewItem.SetLandscape( bNewLand );
+ rSet.Put( aNewItem );
+
+ // flip size
+ Size aOldSize = rSet.Get(ATTR_PAGE_SIZE).GetSize();
+ // coverity[swapped_arguments : FALSE] - this is in the correct order
+ Size aNewSize(aOldSize.Height(),aOldSize.Width());
+ SvxSizeItem aNewSItem(ATTR_PAGE_SIZE,aNewSize);
+ rSet.Put( aNewSItem );
+ }
+ }
+ if (nDiffFlags & SfxPrinterChangeFlags::CHG_SIZE)
+ {
+ SvxSizeItem aPaperSizeItem( ATTR_PAGE_SIZE, SvxPaperInfo::GetPaperSize(pNewPrinter) );
+ rSet.Put( aPaperSizeItem );
+ }
+ }
+ }
+
+ PostPaint(0,0,0,m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB,PaintPartFlags::All);
+
+ return 0;
+}
+
+ScChangeAction* ScDocShell::GetChangeAction( const ScAddress& rPos )
+{
+ ScChangeTrack* pTrack = GetDocument().GetChangeTrack();
+ if (!pTrack)
+ return nullptr;
+
+ SCTAB nTab = rPos.Tab();
+
+ const ScChangeAction* pFound = nullptr;
+ const ScChangeAction* pAction = pTrack->GetFirst();
+ while (pAction)
+ {
+ ScChangeActionType eType = pAction->GetType();
+ //! ScViewUtil::IsActionShown( *pAction, *pSettings, *pDoc )...
+ if ( pAction->IsVisible() && eType != SC_CAT_DELETE_TABS )
+ {
+ const ScBigRange& rBig = pAction->GetBigRange();
+ if ( rBig.aStart.Tab() == nTab )
+ {
+ ScRange aRange = rBig.MakeRange( GetDocument() );
+
+ if ( eType == SC_CAT_DELETE_ROWS )
+ aRange.aEnd.SetRow( aRange.aStart.Row() );
+ else if ( eType == SC_CAT_DELETE_COLS )
+ aRange.aEnd.SetCol( aRange.aStart.Col() );
+
+ if ( aRange.Contains( rPos ) )
+ {
+ pFound = pAction; // the last one wins
+ }
+ }
+ if ( pAction->GetType() == SC_CAT_MOVE )
+ {
+ ScRange aRange =
+ static_cast<const ScChangeActionMove*>(pAction)->
+ GetFromRange().MakeRange( GetDocument() );
+ if ( aRange.Contains( rPos ) )
+ {
+ pFound = pAction;
+ }
+ }
+ }
+ pAction = pAction->GetNext();
+ }
+
+ return const_cast<ScChangeAction*>(pFound);
+}
+
+void ScDocShell::SetChangeComment( ScChangeAction* pAction, const OUString& rComment )
+{
+ if (!pAction)
+ return;
+
+ pAction->SetComment( rComment );
+ //! Undo ???
+ SetDocumentModified();
+
+ // Dialog-Notify
+ ScChangeTrack* pTrack = GetDocument().GetChangeTrack();
+ if (pTrack)
+ {
+ sal_uLong nNumber = pAction->GetActionNumber();
+ pTrack->NotifyModified( ScChangeTrackMsgType::Change, nNumber, nNumber );
+ }
+}
+
+void ScDocShell::ExecuteChangeCommentDialog( ScChangeAction* pAction, weld::Window* pParent, bool bPrevNext)
+{
+ if (!pAction) return; // without action is nothing...
+
+ OUString aComment = pAction->GetComment();
+ OUString aAuthor = pAction->GetUser();
+
+ DateTime aDT = pAction->GetDateTime();
+ OUString aDate = ScGlobal::getLocaleData().getDate( aDT ) + " " +
+ ScGlobal::getLocaleData().getTime( aDT, false );
+
+ SfxItemSetFixed<SID_ATTR_POSTIT_AUTHOR, SID_ATTR_POSTIT_TEXT> aSet( GetPool() );
+
+ aSet.Put( SvxPostItTextItem ( aComment, SID_ATTR_POSTIT_TEXT ) );
+ aSet.Put( SvxPostItAuthorItem( aAuthor, SID_ATTR_POSTIT_AUTHOR ) );
+ aSet.Put( SvxPostItDateItem ( aDate, SID_ATTR_POSTIT_DATE ) );
+
+ std::unique_ptr<ScRedComDialog> pDlg(new ScRedComDialog( pParent, aSet,this,pAction,bPrevNext));
+
+ pDlg->Execute();
+}
+
+void ScDocShell::CompareDocument( ScDocument& rOtherDoc )
+{
+ ScChangeTrack* pTrack = m_pDocument->GetChangeTrack();
+ if ( pTrack && pTrack->GetFirst() )
+ {
+ //! there are changes -> inquiry if needs to be deleted
+ }
+
+ m_pDocument->EndChangeTracking();
+ m_pDocument->StartChangeTracking();
+
+ OUString aOldUser;
+ pTrack = m_pDocument->GetChangeTrack();
+ if ( pTrack )
+ {
+ aOldUser = pTrack->GetUser();
+
+ // check if comparing to same document
+
+ OUString aThisFile;
+ const SfxMedium* pThisMed = GetMedium();
+ if (pThisMed)
+ aThisFile = pThisMed->GetName();
+ OUString aOtherFile;
+ SfxObjectShell* pOtherSh = rOtherDoc.GetDocumentShell();
+ if (pOtherSh)
+ {
+ const SfxMedium* pOtherMed = pOtherSh->GetMedium();
+ if (pOtherMed)
+ aOtherFile = pOtherMed->GetName();
+ }
+ bool bSameDoc = ( aThisFile == aOtherFile && !aThisFile.isEmpty() );
+ if ( !bSameDoc )
+ {
+ // create change actions from comparing with the name of the user
+ // who last saved the document
+ // (only if comparing different documents)
+
+ using namespace ::com::sun::star;
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
+ GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps(
+ xDPS->getDocumentProperties());
+ OSL_ENSURE(xDocProps.is(), "no DocumentProperties");
+ OUString aDocUser = xDocProps->getModifiedBy();
+
+ if ( !aDocUser.isEmpty() )
+ pTrack->SetUser( aDocUser );
+ }
+ }
+
+ m_pDocument->CompareDocument( rOtherDoc );
+
+ pTrack = m_pDocument->GetChangeTrack();
+ if ( pTrack )
+ pTrack->SetUser( aOldUser );
+
+ PostPaintGridAll();
+ SetDocumentModified();
+}
+
+// Merge (combine documents)
+
+static bool lcl_Equal( const ScChangeAction* pA, const ScChangeAction* pB, bool bIgnore100Sec )
+{
+ return pA && pB &&
+ pA->GetActionNumber() == pB->GetActionNumber() &&
+ pA->GetType() == pB->GetType() &&
+ pA->GetUser() == pB->GetUser() &&
+ (bIgnore100Sec ?
+ pA->GetDateTimeUTC().IsEqualIgnoreNanoSec( pB->GetDateTimeUTC() ) :
+ pA->GetDateTimeUTC() == pB->GetDateTimeUTC());
+ // don't compare state if an old change has been accepted
+}
+
+static bool lcl_FindAction( ScDocument& rDoc, const ScChangeAction* pAction, ScDocument& rSearchDoc, const ScChangeAction* pFirstSearchAction, const ScChangeAction* pLastSearchAction, bool bIgnore100Sec )
+{
+ if ( !pAction || !pFirstSearchAction || !pLastSearchAction )
+ {
+ return false;
+ }
+
+ sal_uLong nLastSearchAction = pLastSearchAction->GetActionNumber();
+ const ScChangeAction* pA = pFirstSearchAction;
+ while ( pA && pA->GetActionNumber() <= nLastSearchAction )
+ {
+ if ( pAction->GetType() == pA->GetType() &&
+ pAction->GetUser() == pA->GetUser() &&
+ (bIgnore100Sec ?
+ pAction->GetDateTimeUTC().IsEqualIgnoreNanoSec( pA->GetDateTimeUTC() ) :
+ pAction->GetDateTimeUTC() == pA->GetDateTimeUTC() ) &&
+ pAction->GetBigRange() == pA->GetBigRange() )
+ {
+ OUString aActionDesc = pAction->GetDescription(rDoc, true);
+ OUString aADesc = pA->GetDescription(rSearchDoc, true);
+ if (aActionDesc == aADesc)
+ {
+ OSL_FAIL( "lcl_FindAction(): found equal action!" );
+ return true;
+ }
+ }
+ pA = pA->GetNext();
+ }
+
+ return false;
+}
+
+void ScDocShell::MergeDocument( ScDocument& rOtherDoc, bool bShared, bool bCheckDuplicates, sal_uLong nOffset, ScChangeActionMergeMap* pMergeMap, bool bInverseMap )
+{
+ ScTabViewShell* pViewSh = GetBestViewShell( false ); //! functions to the DocShell
+ if (!pViewSh)
+ return;
+
+ ScChangeTrack* pSourceTrack = rOtherDoc.GetChangeTrack();
+ if (!pSourceTrack)
+ return; //! nothing to do - error notification?
+
+ ScChangeTrack* pThisTrack = m_pDocument->GetChangeTrack();
+ if ( !pThisTrack )
+ { // turn on
+ m_pDocument->StartChangeTracking();
+ pThisTrack = m_pDocument->GetChangeTrack();
+ OSL_ENSURE(pThisTrack,"ChangeTracking not enabled?");
+ if ( !bShared )
+ {
+ // turn on visual RedLining
+ ScChangeViewSettings aChangeViewSet;
+ aChangeViewSet.SetShowChanges(true);
+ m_pDocument->SetChangeViewSettings(aChangeViewSet);
+ }
+ }
+
+ // include Nano seconds in compare?
+ bool bIgnore100Sec = !pSourceTrack->IsTimeNanoSeconds() ||
+ !pThisTrack->IsTimeNanoSeconds();
+
+ // find common initial position
+ sal_uLong nFirstNewNumber = 0;
+ const ScChangeAction* pSourceAction = pSourceTrack->GetFirst();
+ const ScChangeAction* pThisAction = pThisTrack->GetFirst();
+ // skip identical actions
+ while ( lcl_Equal( pSourceAction, pThisAction, bIgnore100Sec ) )
+ {
+ nFirstNewNumber = pSourceAction->GetActionNumber() + 1;
+ pSourceAction = pSourceAction->GetNext();
+ pThisAction = pThisAction->GetNext();
+ }
+ // pSourceAction and pThisAction now point to the first "own" actions
+ // The common actions before don't interest at all
+
+ //! Inquiry if the documents where equal before the change tracking !!!
+
+ const ScChangeAction* pFirstMergeAction = pSourceAction;
+ const ScChangeAction* pFirstSearchAction = pThisAction;
+
+ // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
+ const ScChangeAction* pLastSearchAction = pThisTrack->GetLast();
+
+ // Create MergeChangeData from the following actions
+ sal_uLong nNewActionCount = 0;
+ const ScChangeAction* pCount = pSourceAction;
+ while ( pCount )
+ {
+ if ( bShared || !ScChangeTrack::MergeIgnore( *pCount, nFirstNewNumber ) )
+ ++nNewActionCount;
+ pCount = pCount->GetNext();
+ }
+ if (!nNewActionCount)
+ return; //! nothing to do - error notification?
+ // from here on no return
+
+ ScProgress aProgress( this, "...", nNewActionCount, true );
+
+ sal_uLong nLastMergeAction = pSourceTrack->GetLast()->GetActionNumber();
+ // UpdateReference-Undo, valid references for the last common state
+ pSourceTrack->MergePrepare( pFirstMergeAction, bShared );
+
+ // adjust MergeChangeData to all yet following actions in this document
+ // -> references valid for this document
+ while ( pThisAction )
+ {
+ // #i87049# [Collaboration] Conflict between delete row and insert content is not merged correctly
+ if ( !bShared || !ScChangeTrack::MergeIgnore( *pThisAction, nFirstNewNumber ) )
+ {
+ ScChangeActionType eType = pThisAction->GetType();
+ switch ( eType )
+ {
+ case SC_CAT_INSERT_COLS :
+ case SC_CAT_INSERT_ROWS :
+ case SC_CAT_INSERT_TABS :
+ pSourceTrack->AppendInsert( pThisAction->GetBigRange().MakeRange( GetDocument() ) );
+ break;
+ case SC_CAT_DELETE_COLS :
+ case SC_CAT_DELETE_ROWS :
+ case SC_CAT_DELETE_TABS :
+ {
+ const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pThisAction);
+ if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() )
+ { // deleted table contains deleted cols, which are not
+ sal_uLong nStart, nEnd;
+ pSourceTrack->AppendDeleteRange(
+ pDel->GetOverAllRange().MakeRange( GetDocument() ), nullptr, nStart, nEnd );
+ }
+ }
+ break;
+ case SC_CAT_MOVE :
+ {
+ const ScChangeActionMove* pMove = static_cast<const ScChangeActionMove*>(pThisAction);
+ pSourceTrack->AppendMove( pMove->GetFromRange().MakeRange( GetDocument() ),
+ pMove->GetBigRange().MakeRange( GetDocument() ), nullptr );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ pThisAction = pThisAction->GetNext();
+ }
+
+ LockPaint(); // #i73877# no repainting after each action
+
+ // take over MergeChangeData into the current document
+ bool bHasRejected = false;
+ OUString aOldUser = pThisTrack->GetUser();
+ pThisTrack->SetUseFixDateTime( true );
+ ScMarkData& rMarkData = pViewSh->GetViewData().GetMarkData();
+ ScMarkData aOldMarkData( rMarkData );
+ pSourceAction = pFirstMergeAction;
+ while ( pSourceAction && pSourceAction->GetActionNumber() <= nLastMergeAction )
+ {
+ bool bMergeAction = false;
+ if ( bShared )
+ {
+ if ( !bCheckDuplicates || !lcl_FindAction( rOtherDoc, pSourceAction, *m_pDocument, pFirstSearchAction, pLastSearchAction, bIgnore100Sec ) )
+ {
+ bMergeAction = true;
+ }
+ }
+ else
+ {
+ if ( !ScChangeTrack::MergeIgnore( *pSourceAction, nFirstNewNumber ) )
+ {
+ bMergeAction = true;
+ }
+ }
+
+ if ( bMergeAction )
+ {
+ ScChangeActionType eSourceType = pSourceAction->GetType();
+ if ( !bShared && pSourceAction->IsDeletedIn() )
+ {
+ //! does it need to be determined yet if really deleted in
+ //! _this_ document?
+
+ // lies in a range, which was deleted in this document
+ // -> is omitted
+ //! ??? revert deletion action ???
+ //! ??? save action somewhere else ???
+#if OSL_DEBUG_LEVEL > 0
+ OUString aValue;
+ if ( eSourceType == SC_CAT_CONTENT )
+ aValue = static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewString( m_pDocument.get() );
+ SAL_WARN( "sc", aValue << " omitted");
+#endif
+ }
+ else
+ {
+ //! Take over date/author/comment of the source action!
+
+ pThisTrack->SetUser( pSourceAction->GetUser() );
+ pThisTrack->SetFixDateTimeUTC( pSourceAction->GetDateTimeUTC() );
+ sal_uLong nOldActionMax = pThisTrack->GetActionMax();
+
+ bool bExecute = true;
+ sal_uLong nReject = pSourceAction->GetRejectAction();
+ if ( nReject )
+ {
+ if ( bShared )
+ {
+ if ( nReject >= nFirstNewNumber )
+ {
+ nReject += nOffset;
+ }
+ ScChangeAction* pOldAction = pThisTrack->GetAction( nReject );
+ if ( pOldAction && pOldAction->IsVirgin() )
+ {
+ pThisTrack->Reject( pOldAction );
+ bHasRejected = true;
+ bExecute = false;
+ }
+ }
+ else
+ {
+ // decline old action (of the common ones)
+ ScChangeAction* pOldAction = pThisTrack->GetAction( nReject );
+ if (pOldAction && pOldAction->GetState() == SC_CAS_VIRGIN)
+ {
+ //! what happens at actions, which were accepted in this document???
+ //! error notification or what???
+ //! or execute reject change normally
+
+ pThisTrack->Reject(pOldAction);
+ bHasRejected = true; // for Paint
+ }
+ bExecute = false;
+ }
+ }
+
+ if ( bExecute )
+ {
+ // execute normally
+ ScRange aSourceRange = pSourceAction->GetBigRange().MakeRange( GetDocument() );
+ rMarkData.SelectOneTable( aSourceRange.aStart.Tab() );
+ switch ( eSourceType )
+ {
+ case SC_CAT_CONTENT:
+ {
+ //! Test if it was at the very bottom in the document, then automatic
+ //! row insert ???
+
+ OSL_ENSURE( aSourceRange.aStart == aSourceRange.aEnd, "huch?" );
+ ScAddress aPos = aSourceRange.aStart;
+ OUString aValue = static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewString( m_pDocument.get() );
+ ScMatrixMode eMatrix = ScMatrixMode::NONE;
+ const ScCellValue& rCell = static_cast<const ScChangeActionContent*>(pSourceAction)->GetNewCell();
+ if (rCell.meType == CELLTYPE_FORMULA)
+ eMatrix = rCell.mpFormula->GetMatrixFlag();
+ switch ( eMatrix )
+ {
+ case ScMatrixMode::NONE :
+ pViewSh->EnterData( aPos.Col(), aPos.Row(), aPos.Tab(), aValue );
+ break;
+ case ScMatrixMode::Formula :
+ {
+ SCCOL nCols;
+ SCROW nRows;
+ rCell.mpFormula->GetMatColsRows(nCols, nRows);
+ aSourceRange.aEnd.SetCol( aPos.Col() + nCols - 1 );
+ aSourceRange.aEnd.SetRow( aPos.Row() + nRows - 1 );
+ aValue = aValue.copy(1, aValue.getLength()-2); // remove the 1st and last characters.
+ GetDocFunc().EnterMatrix( aSourceRange,
+ nullptr, nullptr, aValue, false, false,
+ OUString(), formula::FormulaGrammar::GRAM_DEFAULT );
+ }
+ break;
+ case ScMatrixMode::Reference : // do nothing
+ break;
+ }
+ }
+ break;
+ case SC_CAT_INSERT_TABS :
+ {
+ OUString aName;
+ m_pDocument->CreateValidTabName( aName );
+ (void)GetDocFunc().InsertTable( aSourceRange.aStart.Tab(), aName, true, false );
+ }
+ break;
+ case SC_CAT_INSERT_ROWS:
+ (void)GetDocFunc().InsertCells( aSourceRange, nullptr, INS_INSROWS_BEFORE, true, false );
+ break;
+ case SC_CAT_INSERT_COLS:
+ (void)GetDocFunc().InsertCells( aSourceRange, nullptr, INS_INSCOLS_BEFORE, true, false );
+ break;
+ case SC_CAT_DELETE_TABS :
+ (void)GetDocFunc().DeleteTable( aSourceRange.aStart.Tab(), true );
+ break;
+ case SC_CAT_DELETE_ROWS:
+ {
+ const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pSourceAction);
+ if ( pDel->IsTopDelete() )
+ {
+ aSourceRange = pDel->GetOverAllRange().MakeRange( GetDocument() );
+ (void)GetDocFunc().DeleteCells( aSourceRange, nullptr, DelCellCmd::Rows, false );
+
+ // #i101099# [Collaboration] Changes are not correctly shown
+ if ( bShared )
+ {
+ ScChangeAction* pAct = pThisTrack->GetLast();
+ if ( pAct && pAct->GetType() == eSourceType && pAct->IsDeletedIn() && !pSourceAction->IsDeletedIn() )
+ {
+ pAct->RemoveAllDeletedIn();
+ }
+ }
+ }
+ }
+ break;
+ case SC_CAT_DELETE_COLS:
+ {
+ const ScChangeActionDel* pDel = static_cast<const ScChangeActionDel*>(pSourceAction);
+ if ( pDel->IsTopDelete() && !pDel->IsTabDeleteCol() )
+ { // deleted table contains deleted cols, which are not
+ aSourceRange = pDel->GetOverAllRange().MakeRange( GetDocument() );
+ (void)GetDocFunc().DeleteCells( aSourceRange, nullptr, DelCellCmd::Cols, false );
+ }
+ }
+ break;
+ case SC_CAT_MOVE :
+ {
+ const ScChangeActionMove* pMove = static_cast<const ScChangeActionMove*>(pSourceAction);
+ ScRange aFromRange( pMove->GetFromRange().MakeRange( GetDocument() ) );
+ (void)GetDocFunc().MoveBlock( aFromRange,
+ aSourceRange.aStart, true, true, false, false );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ const OUString& rComment = pSourceAction->GetComment();
+ if ( !rComment.isEmpty() )
+ {
+ ScChangeAction* pAct = pThisTrack->GetLast();
+ if ( pAct && pAct->GetActionNumber() > nOldActionMax )
+ pAct->SetComment( rComment );
+ else
+ OSL_FAIL( "MergeDocument: what to do with the comment?!?" );
+ }
+
+ // adjust references
+ pSourceTrack->MergeOwn( const_cast<ScChangeAction*>(pSourceAction), nFirstNewNumber, bShared );
+
+ // merge action state
+ if ( bShared && !pSourceAction->IsRejected() )
+ {
+ ScChangeAction* pAct = pThisTrack->GetLast();
+ if ( pAct && pAct->GetActionNumber() > nOldActionMax )
+ {
+ ScChangeTrack::MergeActionState( pAct, pSourceAction );
+ }
+ }
+
+ // fill merge map
+ if ( bShared && pMergeMap )
+ {
+ ScChangeAction* pAct = pThisTrack->GetLast();
+ if ( pAct && pAct->GetActionNumber() > nOldActionMax )
+ {
+ sal_uLong nActionMax = pAct->GetActionNumber();
+ sal_uLong nActionCount = nActionMax - nOldActionMax;
+ sal_uLong nAction = nActionMax - nActionCount + 1;
+ sal_uLong nSourceAction = pSourceAction->GetActionNumber() - nActionCount + 1;
+ while ( nAction <= nActionMax )
+ {
+ if ( bInverseMap )
+ {
+ (*pMergeMap)[ nAction++ ] = nSourceAction++;
+ }
+ else
+ {
+ (*pMergeMap)[ nSourceAction++ ] = nAction++;
+ }
+ }
+ }
+ }
+ }
+ aProgress.SetStateCountDown( --nNewActionCount );
+ }
+ pSourceAction = pSourceAction->GetNext();
+ }
+
+ rMarkData = std::move(aOldMarkData);
+ pThisTrack->SetUser(aOldUser);
+ pThisTrack->SetUseFixDateTime( false );
+
+ pSourceTrack->Clear(); //! this one is bungled now
+
+ if (bHasRejected)
+ PostPaintGridAll(); // Reject() doesn't paint itself
+
+ UnlockPaint();
+}
+
+bool ScDocShell::MergeSharedDocument( ScDocShell* pSharedDocShell )
+{
+ if ( !pSharedDocShell )
+ {
+ return false;
+ }
+
+ ScChangeTrack* pThisTrack = m_pDocument->GetChangeTrack();
+ if ( !pThisTrack )
+ {
+ return false;
+ }
+
+ ScDocument& rSharedDoc = pSharedDocShell->GetDocument();
+ ScChangeTrack* pSharedTrack = rSharedDoc.GetChangeTrack();
+ if ( !pSharedTrack )
+ {
+ return false;
+ }
+
+ // reset show changes
+ ScChangeViewSettings aChangeViewSet;
+ aChangeViewSet.SetShowChanges( false );
+ m_pDocument->SetChangeViewSettings( aChangeViewSet );
+
+ // find first merge action in this document
+ bool bIgnore100Sec = !pThisTrack->IsTimeNanoSeconds() || !pSharedTrack->IsTimeNanoSeconds();
+ ScChangeAction* pThisAction = pThisTrack->GetFirst();
+ ScChangeAction* pSharedAction = pSharedTrack->GetFirst();
+ while ( lcl_Equal( pThisAction, pSharedAction, bIgnore100Sec ) )
+ {
+ pThisAction = pThisAction->GetNext();
+ pSharedAction = pSharedAction->GetNext();
+ }
+
+ if ( pSharedAction )
+ {
+ if ( pThisAction )
+ {
+ // merge own changes into shared document
+ sal_uLong nActStartShared = pSharedAction->GetActionNumber();
+ sal_uLong nActEndShared = pSharedTrack->GetActionMax();
+ std::optional<ScDocument> pTmpDoc(std::in_place);
+ for ( sal_Int32 nIndex = 0; nIndex < m_pDocument->GetTableCount(); ++nIndex )
+ {
+ OUString sTabName;
+ pTmpDoc->CreateValidTabName( sTabName );
+ pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName );
+ }
+ m_pDocument->GetChangeTrack()->Clone( &*pTmpDoc );
+ ScChangeActionMergeMap aOwnInverseMergeMap;
+ pSharedDocShell->MergeDocument( *pTmpDoc, true, true, 0, &aOwnInverseMergeMap, true );
+ pTmpDoc.reset();
+ sal_uLong nActStartOwn = nActEndShared + 1;
+ sal_uLong nActEndOwn = pSharedTrack->GetActionMax();
+
+ // find conflicts
+ ScConflictsList aConflictsList;
+ ScConflictsFinder aFinder( pSharedTrack, nActStartShared, nActEndShared, nActStartOwn, nActEndOwn, aConflictsList );
+ if ( aFinder.Find() )
+ {
+ ScConflictsListHelper::TransformConflictsList( aConflictsList, nullptr, &aOwnInverseMergeMap );
+ bool bLoop = true;
+ while ( bLoop )
+ {
+ bLoop = false;
+ weld::Window* pWin = GetActiveDialogParent();
+ ScConflictsDlg aDlg(pWin, GetViewData(), &rSharedDoc, aConflictsList);
+ if (aDlg.run() == RET_CANCEL)
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pWin,
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_DOC_WILLNOTBESAVED)));
+ xQueryBox->set_default_response(RET_YES);
+ if (xQueryBox->run() == RET_YES)
+ {
+ return false;
+ }
+ else
+ {
+ bLoop = true;
+ }
+ }
+ }
+ }
+
+ // undo own changes in shared document
+ pSharedTrack->Undo( nActStartOwn, nActEndOwn );
+
+ // clone change track for merging into own document
+ pTmpDoc.emplace();
+ for ( sal_Int32 nIndex = 0; nIndex < m_pDocument->GetTableCount(); ++nIndex )
+ {
+ OUString sTabName;
+ pTmpDoc->CreateValidTabName( sTabName );
+ pTmpDoc->InsertTab( SC_TAB_APPEND, sTabName );
+ }
+ pThisTrack->Clone( &*pTmpDoc );
+
+ // undo own changes since last save in own document
+ sal_uLong nStartShared = pThisAction->GetActionNumber();
+ ScChangeAction* pAction = pThisTrack->GetLast();
+ while ( pAction && pAction->GetActionNumber() >= nStartShared )
+ {
+ pThisTrack->Reject( pAction, true );
+ pAction = pAction->GetPrev();
+ }
+
+ // #i94841# [Collaboration] When deleting rows is rejected, the content is sometimes wrong
+ pThisTrack->Undo( nStartShared, pThisTrack->GetActionMax(), true );
+
+ // merge shared changes into own document
+ ScChangeActionMergeMap aSharedMergeMap;
+ MergeDocument( rSharedDoc, true, true, 0, &aSharedMergeMap );
+ sal_uLong nEndShared = pThisTrack->GetActionMax();
+
+ // resolve conflicts for shared non-content actions
+ if ( !aConflictsList.empty() )
+ {
+ ScConflictsListHelper::TransformConflictsList( aConflictsList, &aSharedMergeMap, nullptr );
+ ScConflictsResolver aResolver( pThisTrack, aConflictsList );
+ pAction = pThisTrack->GetAction( nEndShared );
+ while ( pAction && pAction->GetActionNumber() >= nStartShared )
+ {
+ aResolver.HandleAction( pAction, true /*bIsSharedAction*/,
+ false /*bHandleContentAction*/, true /*bHandleNonContentAction*/ );
+ pAction = pAction->GetPrev();
+ }
+ }
+ nEndShared = pThisTrack->GetActionMax();
+
+ // only show changes from shared document
+ aChangeViewSet.SetShowChanges( true );
+ aChangeViewSet.SetShowAccepted( true );
+ aChangeViewSet.SetHasActionRange();
+ aChangeViewSet.SetTheActionRange( nStartShared, nEndShared );
+ m_pDocument->SetChangeViewSettings( aChangeViewSet );
+
+ // merge own changes back into own document
+ sal_uLong nStartOwn = nEndShared + 1;
+ ScChangeActionMergeMap aOwnMergeMap;
+ MergeDocument( *pTmpDoc, true, true, nEndShared - nStartShared + 1, &aOwnMergeMap );
+ pTmpDoc.reset();
+ sal_uLong nEndOwn = pThisTrack->GetActionMax();
+
+ // resolve conflicts for shared content actions and own actions
+ if ( !aConflictsList.empty() )
+ {
+ ScConflictsListHelper::TransformConflictsList( aConflictsList, nullptr, &aOwnMergeMap );
+ ScConflictsResolver aResolver( pThisTrack, aConflictsList );
+ pAction = pThisTrack->GetAction( nEndShared );
+ while ( pAction && pAction->GetActionNumber() >= nStartShared )
+ {
+ aResolver.HandleAction( pAction, true /*bIsSharedAction*/,
+ true /*bHandleContentAction*/, false /*bHandleNonContentAction*/ );
+ pAction = pAction->GetPrev();
+ }
+
+ pAction = pThisTrack->GetAction( nEndOwn );
+ while ( pAction && pAction->GetActionNumber() >= nStartOwn )
+ {
+ aResolver.HandleAction( pAction, false /*bIsSharedAction*/,
+ true /*bHandleContentAction*/, true /*bHandleNonContentAction*/ );
+ pAction = pAction->GetPrev();
+ }
+ }
+ }
+ else
+ {
+ // merge shared changes into own document
+ sal_uLong nStartShared = pThisTrack->GetActionMax() + 1;
+ MergeDocument( rSharedDoc, true, true );
+ sal_uLong nEndShared = pThisTrack->GetActionMax();
+
+ // only show changes from shared document
+ aChangeViewSet.SetShowChanges( true );
+ aChangeViewSet.SetShowAccepted( true );
+ aChangeViewSet.SetHasActionRange();
+ aChangeViewSet.SetTheActionRange( nStartShared, nEndShared );
+ m_pDocument->SetChangeViewSettings( aChangeViewSet );
+ }
+
+ // update view
+ PostPaintExtras();
+ PostPaintGridAll();
+
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_DOC_UPDATED)));
+ xInfoBox->run();
+ }
+
+ return ( pThisAction != nullptr );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docsh4.cxx b/sc/source/ui/docshell/docsh4.cxx
new file mode 100644
index 000000000..f64ecaeaa
--- /dev/null
+++ b/sc/source/ui/docshell/docsh4.cxx
@@ -0,0 +1,2788 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <boost/property_tree/json_parser.hpp>
+
+#include <com/sun/star/frame/Desktop.hpp>
+
+using namespace ::com::sun::star;
+
+#include <scitems.hxx>
+#include <editeng/flstitem.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <sfx2/infobar.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <svtools/ehdl.hxx>
+#include <svtools/langtab.hxx>
+#include <basic/sbxcore.hxx>
+#include <basic/sberrors.hxx>
+#include <svtools/sfxecode.hxx>
+#include <svx/ofaitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/whiter.hxx>
+#include <vcl/stdtext.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <svx/drawitem.hxx>
+#include <svx/fmshell.hxx>
+#include <sfx2/passwd.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <svl/PasswordHelper.hxx>
+#include <svl/documentlockfile.hxx>
+#include <svl/sharecontrolfile.hxx>
+#include <unotools/securityoptions.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <sal/log.hxx>
+#include <unotools/charclass.hxx>
+#include <tools/diagnose_ex.h>
+#include <o3tl/string_view.hxx>
+
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <docuno.hxx>
+
+#include <docsh.hxx>
+#include "docshimp.hxx"
+#include <docfunc.hxx>
+#include <scres.hrc>
+#include <strings.hrc>
+#include <stlsheet.hxx>
+#include <stlpool.hxx>
+#include <appoptio.hxx>
+#include <globstr.hrc>
+#include <global.hxx>
+#include <dbdocfun.hxx>
+#include <printfun.hxx>
+#include <viewdata.hxx>
+#include <tabvwsh.hxx>
+#include <impex.hxx>
+#include <undodat.hxx>
+#include <undocell.hxx>
+#include <inputhdl.hxx>
+#include <dbdata.hxx>
+#include <servobj.hxx>
+#include <rangenam.hxx>
+#include <scmod.hxx>
+#include <chgviset.hxx>
+#include <reffact.hxx>
+#include <chartlis.hxx>
+#include <chartpos.hxx>
+#include <tablink.hxx>
+#include <drwlayer.hxx>
+#include <docoptio.hxx>
+#include <undostyl.hxx>
+#include <rangeseq.hxx>
+#include <chgtrack.hxx>
+#include <com/sun/star/document/UpdateDocMode.hpp>
+#include <scresid.hxx>
+#include <scabstdlg.hxx>
+#include <sharedocdlg.hxx>
+#include <conditio.hxx>
+#include <sheetevents.hxx>
+#include <formulacell.hxx>
+#include <documentlinkmgr.hxx>
+#include <memory>
+#include <sfx2/notebookbar/SfxNotebookBar.hxx>
+#include <helpids.h>
+#include <editeng/eeitem.hxx>
+#include <editeng/langitem.hxx>
+
+#include <svx/xdef.hxx>
+
+void ScDocShell::SetInitialLinkUpdate( const SfxMedium* pMed )
+{
+ if (pMed)
+ {
+ const SfxUInt16Item* pUpdateDocItem = SfxItemSet::GetItem<SfxUInt16Item>( pMed->GetItemSet(),
+ SID_UPDATEDOCMODE, false);
+ m_nCanUpdate = pUpdateDocItem ? pUpdateDocItem->GetValue() : css::document::UpdateDocMode::NO_UPDATE;
+ }
+
+ // GetLinkUpdateModeState() evaluates m_nCanUpdate so that must have
+ // been set first. Do not override an already forbidden LinkUpdate (the
+ // default is allow).
+ comphelper::EmbeddedObjectContainer& rEmbeddedObjectContainer = getEmbeddedObjectContainer();
+ if (rEmbeddedObjectContainer.getUserAllowsLinkUpdate())
+ {
+ // For anything else than LM_ALWAYS we need user confirmation.
+ rEmbeddedObjectContainer.setUserAllowsLinkUpdate( GetLinkUpdateModeState() == LM_ALWAYS);
+ }
+}
+
+ScLkUpdMode ScDocShell::GetLinkUpdateModeState() const
+{
+ ScLkUpdMode nSet;
+ if (m_nCanUpdate == css::document::UpdateDocMode::NO_UPDATE)
+ nSet = LM_NEVER;
+ else if (m_nCanUpdate == css::document::UpdateDocMode::FULL_UPDATE)
+ nSet = LM_ALWAYS;
+ else
+ {
+ nSet = GetDocument().GetLinkMode();
+ if (nSet == LM_UNKNOWN)
+ {
+ ScAppOptions aAppOptions = SC_MOD()->GetAppOptions();
+ nSet = aAppOptions.GetLinkMode();
+ }
+ }
+
+ if (nSet == LM_ALWAYS
+ && !(SvtSecurityOptions::isTrustedLocationUriForUpdatingLinks(
+ GetMedium() == nullptr ? OUString() : GetMedium()->GetName())
+ || (IsDocShared()
+ && SvtSecurityOptions::isTrustedLocationUriForUpdatingLinks(
+ GetSharedFileURL()))))
+ {
+ nSet = LM_ON_DEMAND;
+ }
+ if (m_nCanUpdate == css::document::UpdateDocMode::QUIET_UPDATE
+ && nSet == LM_ON_DEMAND)
+ {
+ nSet = LM_NEVER;
+ }
+
+ return nSet;
+}
+
+void ScDocShell::AllowLinkUpdate()
+{
+ m_pDocument->SetLinkFormulaNeedingCheck(false);
+ getEmbeddedObjectContainer().setUserAllowsLinkUpdate(true);
+}
+
+void ScDocShell::ReloadAllLinks()
+{
+ AllowLinkUpdate();
+
+ ReloadTabLinks();
+ weld::Window *pDialogParent = GetActiveDialogParent();
+ m_pDocument->UpdateExternalRefLinks(pDialogParent);
+
+ bool bAnyDde = m_pDocument->GetDocLinkManager().updateDdeOrOleOrWebServiceLinks(pDialogParent);
+
+ if (bAnyDde)
+ {
+ // calculate formulas and paint like in the TrackTimeHdl
+ m_pDocument->TrackFormulas();
+ Broadcast(SfxHint(SfxHintId::ScDataChanged));
+
+ // Should FID_DATACHANGED become asynchronous some time
+ // (e.g., with Invalidate at Window), an update needs to be forced here.
+ }
+
+ m_pDocument->UpdateAreaLinks();
+}
+
+IMPL_LINK_NOARG( ScDocShell, ReloadAllLinksHdl, weld::Button&, void )
+{
+ ReloadAllLinks();
+
+ ScTabViewShell* pViewSh = GetBestViewShell();
+ SfxViewFrame* pViewFrame = pViewSh ? pViewSh->GetFrame() : nullptr;
+ if (pViewFrame)
+ pViewFrame->RemoveInfoBar(u"enablecontent");
+ SAL_WARN_IF(!pViewFrame, "sc", "expected there to be a ViewFrame");
+}
+
+namespace
+{
+ class LinkHelp
+ {
+ public:
+ DECL_STATIC_LINK(LinkHelp, DispatchHelpLinksHdl, weld::Button&, void);
+ };
+}
+
+IMPL_STATIC_LINK(LinkHelp, DispatchHelpLinksHdl, weld::Button&, rBtn, void)
+{
+ if (Help* pHelp = Application::GetHelp())
+ pHelp->Start(HID_UPDATE_LINK_WARNING, &rBtn);
+}
+
+void ScDocShell::Execute( SfxRequest& rReq )
+{
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ SfxBindings* pBindings = GetViewBindings();
+ bool bUndo (m_pDocument->IsUndoEnabled());
+
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch ( nSlot )
+ {
+ case SID_SC_SETTEXT:
+ {
+ const SfxPoolItem* pColItem;
+ const SfxPoolItem* pRowItem;
+ const SfxPoolItem* pTabItem;
+ const SfxPoolItem* pTextItem;
+ if( pReqArgs && pReqArgs->HasItem( FN_PARAM_1, &pColItem ) &&
+ pReqArgs->HasItem( FN_PARAM_2, &pRowItem ) &&
+ pReqArgs->HasItem( FN_PARAM_3, &pTabItem ) &&
+ pReqArgs->HasItem( SID_SC_SETTEXT, &pTextItem ) )
+ {
+ // parameters are 1-based !!!
+ SCCOL nCol = static_cast<const SfxInt16Item*>(pColItem)->GetValue() - 1;
+ SCROW nRow = static_cast<const SfxInt32Item*>(pRowItem)->GetValue() - 1;
+ SCTAB nTab = static_cast<const SfxInt16Item*>(pTabItem)->GetValue() - 1;
+
+ SCTAB nTabCount = m_pDocument->GetTableCount();
+ if ( m_pDocument->ValidCol(nCol) && m_pDocument->ValidRow(nRow) && ValidTab(nTab,nTabCount) )
+ {
+ if ( m_pDocument->IsBlockEditable( nTab, nCol,nRow, nCol, nRow ) )
+ {
+ OUString aVal = static_cast<const SfxStringItem*>(pTextItem)->GetValue();
+ m_pDocument->SetString( nCol, nRow, nTab, aVal );
+
+ PostPaintCell( nCol, nRow, nTab );
+ SetDocumentModified();
+
+ rReq.Done();
+ break;
+ }
+ else // protected cell
+ {
+#if HAVE_FEATURE_SCRIPTING
+ SbxBase::SetError( ERRCODE_BASIC_BAD_PARAMETER ); //! which error ?
+#endif
+ break;
+ }
+ }
+ }
+#if HAVE_FEATURE_SCRIPTING
+ SbxBase::SetError( ERRCODE_BASIC_NO_OBJECT );
+#endif
+ }
+ break;
+
+ case SID_SBA_IMPORT:
+ {
+ if (pReqArgs)
+ {
+ const SfxPoolItem* pItem;
+ svx::ODataAccessDescriptor aDesc;
+ if ( pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
+ {
+ uno::Any aAny = static_cast<const SfxUnoAnyItem*>(pItem)->GetValue();
+ uno::Sequence<beans::PropertyValue> aProperties;
+ if ( aAny >>= aProperties )
+ aDesc.initializeFrom( aProperties );
+ }
+
+ OUString sTarget;
+ if ( pReqArgs->GetItemState( FN_PARAM_1, true, &pItem ) == SfxItemState::SET )
+ sTarget = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ bool bIsNewArea = true; // Default sal_True (no inquiry)
+ if ( pReqArgs->GetItemState( FN_PARAM_2, true, &pItem ) == SfxItemState::SET )
+ bIsNewArea = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ // if necessary, create new database area
+ bool bMakeArea = false;
+ if (bIsNewArea)
+ {
+ ScDBCollection* pDBColl = m_pDocument->GetDBCollection();
+ if ( !pDBColl || !pDBColl->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(sTarget)) )
+ {
+ ScAddress aPos;
+ if ( aPos.Parse( sTarget, *m_pDocument, m_pDocument->GetAddressConvention() ) & ScRefFlags::VALID )
+ {
+ bMakeArea = true;
+ if (bUndo)
+ {
+ OUString aStrImport = ScResId( STR_UNDO_IMPORTDATA );
+ ViewShellId nViewShellId(-1);
+ if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
+ nViewShellId = pViewSh->GetViewShellId();
+ GetUndoManager()->EnterListAction( aStrImport, aStrImport, 0, nViewShellId );
+ }
+
+ ScDBData* pDBData = GetDBData( ScRange(aPos), SC_DB_IMPORT, ScGetDBSelection::Keep );
+ OSL_ENSURE(pDBData, "Cannot create DB data");
+ sTarget = pDBData->GetName();
+ }
+ }
+ }
+
+ // inquire, before old DB range gets overwritten
+ bool bDo = true;
+ if (!bIsNewArea)
+ {
+ OUString aTemplate = ScResId( STR_IMPORT_REPLACE );
+ OUString aMessage = o3tl::getToken(aTemplate, 0, '#' )
+ + sTarget
+ + o3tl::getToken(aTemplate, 1, '#' );
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(nullptr,
+ VclMessageType::Question, VclButtonsType::YesNo,
+ aMessage));
+ xQueryBox->set_default_response(RET_YES);
+ bDo = xQueryBox->run() == RET_YES;
+ }
+
+ if (bDo)
+ {
+ ScDBDocFunc(*this).UpdateImport( sTarget, aDesc );
+ rReq.Done();
+
+ // UpdateImport also updates the internal operations
+ }
+ else
+ rReq.Ignore();
+
+ if ( bMakeArea && bUndo)
+ GetUndoManager()->LeaveListAction();
+ }
+ else
+ {
+ OSL_FAIL( "arguments expected" );
+ }
+ }
+ break;
+
+ case SID_CHART_SOURCE:
+ case SID_CHART_ADDSOURCE:
+ if (pReqArgs)
+ {
+ ScDocument& rDoc = GetDocument();
+ const SfxPoolItem* pItem;
+ OUString aChartName, aRangeName;
+
+ ScRange aSingleRange;
+ ScRangeListRef aRangeListRef;
+ bool bMultiRange = false;
+
+ bool bColHeaders = true;
+ bool bRowHeaders = true;
+ bool bColInit = false;
+ bool bRowInit = false;
+ bool bAddRange = (nSlot == SID_CHART_ADDSOURCE);
+
+ if( const SfxStringItem* pChartItem = pReqArgs->GetItemIfSet( SID_CHART_NAME ) )
+ aChartName = pChartItem->GetValue();
+
+ if( const SfxStringItem* pChartItem = pReqArgs->GetItemIfSet( SID_CHART_SOURCE ) )
+ aRangeName = pChartItem->GetValue();
+
+ if( pReqArgs->HasItem( FN_PARAM_1, &pItem ) )
+ {
+ bColHeaders = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ bColInit = true;
+ }
+ if( pReqArgs->HasItem( FN_PARAM_2, &pItem ) )
+ {
+ bRowHeaders = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ bRowInit = true;
+ }
+
+ ScAddress::Details aDetails(rDoc.GetAddressConvention(), 0, 0);
+ bool bValid = (aSingleRange.ParseAny(aRangeName, rDoc, aDetails) & ScRefFlags::VALID) != ScRefFlags::ZERO;
+ if (!bValid)
+ {
+ aRangeListRef = new ScRangeList;
+ aRangeListRef->Parse( aRangeName, rDoc, rDoc.GetAddressConvention());
+ if ( !aRangeListRef->empty() )
+ {
+ bMultiRange = true;
+ aSingleRange = aRangeListRef->front(); // for header
+ bValid = true;
+ }
+ else
+ aRangeListRef.clear();
+ }
+
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if (pViewSh && bValid && !aChartName.isEmpty() )
+ {
+ weld::Window* pParent = pViewSh->GetFrameWeld();
+
+ SCCOL nCol1 = aSingleRange.aStart.Col();
+ SCROW nRow1 = aSingleRange.aStart.Row();
+ SCCOL nCol2 = aSingleRange.aEnd.Col();
+ SCROW nRow2 = aSingleRange.aEnd.Row();
+ SCTAB nTab = aSingleRange.aStart.Tab();
+
+ //! limit always or not at all ???
+ if (!bMultiRange)
+ m_pDocument->LimitChartArea( nTab, nCol1,nRow1, nCol2,nRow2 );
+
+ // Dialog for column/row headers
+ bool bOk = true;
+ if ( !bAddRange && ( !bColInit || !bRowInit ) )
+ {
+ ScChartPositioner aChartPositioner( *m_pDocument, nTab, nCol1,nRow1, nCol2,nRow2 );
+ if (!bColInit)
+ bColHeaders = aChartPositioner.HasColHeaders();
+ if (!bRowInit)
+ bRowHeaders = aChartPositioner.HasRowHeaders();
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScColRowLabelDlg> pDlg(pFact->CreateScColRowLabelDlg(pParent, bRowHeaders, bColHeaders));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ bColHeaders = pDlg->IsRow();
+ bRowHeaders = pDlg->IsCol();
+
+ rReq.AppendItem(SfxBoolItem(FN_PARAM_1, bColHeaders));
+ rReq.AppendItem(SfxBoolItem(FN_PARAM_2, bRowHeaders));
+ }
+ else
+ bOk = false;
+ }
+
+ if (bOk) // execute
+ {
+ if (bMultiRange)
+ {
+ if (bUndo)
+ {
+ GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoChartData>( this, aChartName, aRangeListRef,
+ bColHeaders, bRowHeaders, bAddRange ) );
+ }
+ m_pDocument->UpdateChartArea( aChartName, aRangeListRef,
+ bColHeaders, bRowHeaders, bAddRange );
+ }
+ else
+ {
+ ScRange aNewRange( nCol1,nRow1,nTab, nCol2,nRow2,nTab );
+ if (bUndo)
+ {
+ GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoChartData>( this, aChartName, aNewRange,
+ bColHeaders, bRowHeaders, bAddRange ) );
+ }
+ m_pDocument->UpdateChartArea( aChartName, aNewRange,
+ bColHeaders, bRowHeaders, bAddRange );
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("UpdateChartArea: no ViewShell or wrong data");
+ }
+ rReq.Done();
+ }
+ else
+ {
+ OSL_FAIL("SID_CHART_SOURCE without arguments");
+ }
+ break;
+
+ case FID_AUTO_CALC:
+ {
+ bool bNewVal;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && SfxItemState::SET == pReqArgs->GetItemState( nSlot, true, &pItem ) )
+ bNewVal = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ else
+ bNewVal = !m_pDocument->GetAutoCalc(); // Toggle for menu
+ m_pDocument->SetAutoCalc( bNewVal );
+ SetDocumentModified();
+ if (pBindings)
+ {
+ pBindings->Invalidate( FID_AUTO_CALC );
+ }
+ rReq.AppendItem( SfxBoolItem( FID_AUTO_CALC, bNewVal ) );
+ rReq.Done();
+ }
+ break;
+ case FID_RECALC:
+ DoRecalc( rReq.IsAPI() );
+ rReq.Done();
+ break;
+ case FID_HARD_RECALC:
+ DoHardRecalc();
+ rReq.Done();
+ break;
+ case SID_UPDATETABLINKS:
+ {
+ ScLkUpdMode nSet = GetLinkUpdateModeState();
+
+ if (nSet == LM_ALWAYS)
+ {
+ ReloadAllLinks();
+ rReq.Done();
+ }
+ else if (nSet == LM_NEVER)
+ {
+ getEmbeddedObjectContainer().setUserAllowsLinkUpdate(false);
+ rReq.Ignore();
+ }
+ else if (nSet == LM_ON_DEMAND)
+ {
+ ScTabViewShell* pViewSh = GetBestViewShell();
+ SfxViewFrame* pViewFrame = pViewSh ? pViewSh->GetFrame() : nullptr;
+ if (pViewFrame)
+ {
+ pViewFrame->RemoveInfoBar(u"enablecontent");
+ auto pInfoBar = pViewFrame->AppendInfoBar("enablecontent", "", ScResId(STR_RELOAD_TABLES), InfobarType::WARNING);
+ if (pInfoBar)
+ {
+ weld::Button& rHelpBtn = pInfoBar->addButton();
+ rHelpBtn.set_label(GetStandardText(StandardButtonType::Help).replaceFirst("~", ""));
+ rHelpBtn.connect_clicked(LINK(nullptr, LinkHelp, DispatchHelpLinksHdl));
+ weld::Button& rBtn = pInfoBar->addButton();
+ rBtn.set_label(ScResId(STR_ENABLE_CONTENT));
+ rBtn.set_tooltip_text(ScResId(STR_ENABLE_CONTENT_TOOLTIP));
+ rBtn.connect_clicked(LINK(this, ScDocShell, ReloadAllLinksHdl));
+ }
+ }
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_REIMPORT_AFTER_LOAD:
+ {
+ // Is called after loading if there are DB areas with omitted data
+
+ bool bDone = false;
+ ScDBCollection* pDBColl = m_pDocument->GetDBCollection();
+
+ if ((m_nCanUpdate != css::document::UpdateDocMode::NO_UPDATE) &&
+ (m_nCanUpdate != css::document::UpdateDocMode::QUIET_UPDATE))
+ {
+ ScRange aRange;
+ ScTabViewShell* pViewSh = GetBestViewShell();
+ OSL_ENSURE(pViewSh,"SID_REIMPORT_AFTER_LOAD: no View");
+ if (pViewSh && pDBColl)
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetActiveDialogParent(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_REIMPORT_AFTER_LOAD)));
+ xQueryBox->set_default_response(RET_YES);
+ if (xQueryBox->run() == RET_YES)
+ {
+ ScDBCollection::NamedDBs& rDBs = pDBColl->getNamedDBs();
+ for (const auto& rxDB : rDBs)
+ {
+ ScDBData& rDBData = *rxDB;
+ if ( rDBData.IsStripData() &&
+ rDBData.HasImportParam() && !rDBData.HasImportSelection() )
+ {
+ rDBData.GetArea(aRange);
+ pViewSh->MarkRange(aRange);
+
+ // Import and internal operations like SID_REFRESH_DBAREA
+ // (inquiry for import not needed here)
+
+ ScImportParam aImportParam;
+ rDBData.GetImportParam( aImportParam );
+ bool bContinue = pViewSh->ImportData( aImportParam );
+ rDBData.SetImportParam( aImportParam );
+
+ // mark (size may have changed)
+ rDBData.GetArea(aRange);
+ pViewSh->MarkRange(aRange);
+
+ if ( bContinue ) // error at import -> abort
+ {
+ // internal operations, if some where saved
+
+ if ( rDBData.HasQueryParam() || rDBData.HasSortParam() ||
+ rDBData.HasSubTotalParam() )
+ pViewSh->RepeatDB();
+
+ // pivot tables, which have the range as source data
+
+ RefreshPivotTables(aRange);
+ }
+ }
+ }
+ bDone = true;
+ }
+ }
+ }
+
+ if ( !bDone && pDBColl )
+ {
+ // if not, but then update the dependent formulas
+ //! also for individual ranges, which cannot be updated
+
+ m_pDocument->CalcAll(); //! only for the dependent
+ PostDataChanged();
+ }
+
+ if (bDone)
+ rReq.Done();
+ else
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_AUTO_STYLE:
+ OSL_FAIL("use ScAutoStyleHint instead of SID_AUTO_STYLE");
+ 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 FID_CHG_RECORD:
+ {
+ ScDocument& rDoc = GetDocument();
+ // get argument (recorded macro)
+ const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(FID_CHG_RECORD);
+ bool bDo = true;
+
+ // desired state
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ bool bActivateTracking = (pChangeTrack == nullptr); // toggle
+ if ( pItem )
+ bActivateTracking = pItem->GetValue(); // from argument
+
+ if ( !bActivateTracking )
+ {
+ if ( !pItem )
+ {
+ // no dialog on playing the macro
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
+ VclMessageType::Warning, VclButtonsType::YesNo,
+ ScResId(STR_END_REDLINING)));
+ xWarn->set_default_response(RET_NO);
+ bDo = (xWarn->run() == RET_YES );
+ }
+
+ if ( bDo )
+ {
+ if (pChangeTrack)
+ {
+ if ( pChangeTrack->IsProtected() )
+ bDo = ExecuteChangeProtectionDialog();
+ }
+ if ( bDo )
+ {
+ rDoc.EndChangeTracking();
+ PostPaintGridAll();
+ }
+ }
+ }
+ else
+ {
+ rDoc.StartChangeTracking();
+ ScChangeViewSettings aChangeViewSet;
+ aChangeViewSet.SetShowChanges(true);
+ rDoc.SetChangeViewSettings(aChangeViewSet);
+ }
+
+ if ( bDo )
+ {
+ UpdateAcceptChangesDialog();
+
+ // invalidate slots
+ if (pBindings)
+ pBindings->InvalidateAll(false);
+ if ( !pItem )
+ rReq.AppendItem( SfxBoolItem( FID_CHG_RECORD, bActivateTracking ) );
+ rReq.Done();
+ }
+ else
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_CHG_PROTECT :
+ {
+ if ( ExecuteChangeProtectionDialog() )
+ {
+ rReq.Done();
+ SetDocumentModified();
+ }
+ else
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_DOCUMENT_MERGE:
+ case SID_DOCUMENT_COMPARE:
+ {
+ bool bDo = true;
+ ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
+ if ( pChangeTrack && !m_pImpl->bIgnoreLostRedliningWarning )
+ {
+ if ( nSlot == SID_DOCUMENT_COMPARE )
+ { //! old changes trace will be lost
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(GetActiveDialogParent(),
+ VclMessageType::Warning, VclButtonsType::YesNo,
+ ScResId(STR_END_REDLINING)));
+ xWarn->set_default_response(RET_NO);
+ if (xWarn->run() == RET_YES)
+ bDo = ExecuteChangeProtectionDialog( true );
+ else
+ bDo = false;
+ }
+ else // merge might reject some actions
+ bDo = ExecuteChangeProtectionDialog( true );
+ }
+ if ( !bDo )
+ {
+ rReq.Ignore();
+ break;
+ }
+ SfxApplication* pApp = SfxGetpApp();
+ const SfxPoolItem* pItem;
+ const SfxStringItem* pFileNameItem(nullptr);
+ SfxMedium* pMed = nullptr;
+ if (pReqArgs)
+ pFileNameItem = pReqArgs->GetItemIfSet(SID_FILE_NAME);
+ if (pFileNameItem)
+ {
+ OUString aFileName = pFileNameItem->GetValue();
+
+ OUString aFilterName;
+ if (const SfxStringItem* pFilterItem = pReqArgs->GetItemIfSet(SID_FILTER_NAME))
+ {
+ aFilterName = pFilterItem->GetValue();
+ }
+ OUString aOptions;
+ if (const SfxStringItem* pOptionsItem = pReqArgs->GetItemIfSet(SID_FILE_FILTEROPTIONS))
+ {
+ aOptions = pOptionsItem->GetValue();
+ }
+ short nVersion = 0;
+ const SfxInt16Item* pInt16Item(nullptr);
+ if (pReqArgs->GetItemState(SID_VERSION, true, &pItem) == SfxItemState::SET)
+ pInt16Item = dynamic_cast<const SfxInt16Item*>(pItem);
+ if (pInt16Item)
+ {
+ nVersion = pInt16Item->GetValue();
+ }
+
+ // no filter specified -> detection
+ if (aFilterName.isEmpty())
+ ScDocumentLoader::GetFilterName( aFileName, aFilterName, aOptions, true, false );
+
+ // filter name from dialog contains application prefix,
+ // GetFilter needs name without the prefix.
+ ScDocumentLoader::RemoveAppPrefix( aFilterName );
+
+ std::shared_ptr<const SfxFilter> pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName( aFilterName );
+ auto pSet = std::make_shared<SfxAllItemSet>( pApp->GetPool() );
+ if (!aOptions.isEmpty())
+ pSet->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, aOptions ) );
+ if ( nVersion != 0 )
+ pSet->Put( SfxInt16Item( SID_VERSION, nVersion ) );
+ pMed = new SfxMedium( aFileName, StreamMode::STD_READ, pFilter, std::move(pSet) );
+ }
+ else
+ {
+ const sfx2::DocumentInserter::Mode mode { nSlot==SID_DOCUMENT_COMPARE
+ ? sfx2::DocumentInserter::Mode::Compare
+ : sfx2::DocumentInserter::Mode::Merge};
+ // start file dialog asynchronous
+ m_pImpl->bIgnoreLostRedliningWarning = true;
+ m_pImpl->pRequest.reset(new SfxRequest( rReq ));
+ m_pImpl->pDocInserter.reset();
+
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ weld::Window* pParent = pViewSh ? pViewSh->GetFrameWeld() : nullptr;
+ m_pImpl->pDocInserter.reset( new ::sfx2::DocumentInserter(pParent,
+ ScDocShell::Factory().GetFactoryName(), mode ) );
+ m_pImpl->pDocInserter->StartExecuteModal( LINK( this, ScDocShell, DialogClosedHdl ) );
+ return ;
+ }
+
+ // now execute in earnest...
+ SfxErrorContext aEc( ERRCTX_SFX_OPENDOC, pMed->GetName() );
+
+ // pOtherDocSh->DoClose() will be called explicitly later, but it is still more safe to use SfxObjectShellLock here
+ ScDocShell* pOtherDocSh = new ScDocShell;
+ SfxObjectShellLock aDocShTablesRef = pOtherDocSh;
+ pOtherDocSh->DoLoad( pMed );
+ ErrCode nErr = pOtherDocSh->GetErrorCode();
+ if (nErr)
+ ErrorHandler::HandleError( nErr ); // also warnings
+
+ if ( !pOtherDocSh->GetError() ) // only errors
+ {
+ bool bHadTrack = ( m_pDocument->GetChangeTrack() != nullptr );
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+ sal_uLong nStart = 0;
+ if ( nSlot == SID_DOCUMENT_MERGE && pChangeTrack )
+ {
+ nStart = pChangeTrack->GetActionMax() + 1;
+ }
+#endif
+ if ( nSlot == SID_DOCUMENT_COMPARE )
+ CompareDocument( pOtherDocSh->GetDocument() );
+ else
+ MergeDocument( pOtherDocSh->GetDocument() );
+
+ // show "accept changes" dialog
+ //! get view for this document!
+ if ( !IsDocShared() )
+ {
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if ( pViewFrm )
+ {
+ pViewFrm->ShowChildWindow( ScAcceptChgDlgWrapper::GetChildWindowId() ); //@51669
+ }
+ if ( pBindings )
+ {
+ pBindings->Invalidate( FID_CHG_ACCEPT );
+ }
+ }
+
+ rReq.SetReturnValue( SfxInt32Item( nSlot, 0 ) ); //! ???????
+ rReq.Done();
+
+ if (!bHadTrack) // newly turned on -> show as well
+ {
+ ScChangeViewSettings* pOldSet = m_pDocument->GetChangeViewSettings();
+ if ( !pOldSet || !pOldSet->ShowChanges() )
+ {
+ ScChangeViewSettings aChangeViewSet;
+ aChangeViewSet.SetShowChanges(true);
+ m_pDocument->SetChangeViewSettings(aChangeViewSet);
+ }
+ }
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+ else if ( nSlot == SID_DOCUMENT_MERGE && IsDocShared() && pChangeTrack )
+ {
+ sal_uLong nEnd = pChangeTrack->GetActionMax();
+ if ( nEnd >= nStart )
+ {
+ // only show changes from merged document
+ ScChangeViewSettings aChangeViewSet;
+ aChangeViewSet.SetShowChanges( true );
+ aChangeViewSet.SetShowAccepted( true );
+ aChangeViewSet.SetHasActionRange();
+ aChangeViewSet.SetTheActionRange( nStart, nEnd );
+ m_pDocument->SetChangeViewSettings( aChangeViewSet );
+
+ // update view
+ PostPaintExtras();
+ PostPaintGridAll();
+ }
+ }
+#endif
+ }
+ pOtherDocSh->DoClose(); // delete happens with the Ref
+ }
+ break;
+
+ case SID_DELETE_SCENARIO:
+ if (pReqArgs)
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
+ {
+ if (const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>(pItem))
+ {
+ const OUString& aName = pStringItem->GetValue();
+ SCTAB nTab;
+ if (m_pDocument->GetTable( aName, nTab ))
+ {
+ // move DeleteTable from viewfunc to docfunc!
+
+ ScTabViewShell* pSh = GetBestViewShell();
+ if ( pSh )
+ {
+ //! omit SetTabNo in DeleteTable?
+ SCTAB nDispTab = pSh->GetViewData().GetTabNo();
+ pSh->DeleteTable( nTab );
+ pSh->SetTabNo(nDispTab);
+ rReq.Done();
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case SID_EDIT_SCENARIO:
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
+ {
+ if (const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>(pItem))
+ {
+ OUString aName = pStringItem->GetValue();
+ SCTAB nTab;
+ if (m_pDocument->GetTable( aName, nTab ))
+ {
+ if (m_pDocument->IsScenario(nTab))
+ {
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ m_pDocument->GetScenarioData( nTab, aComment, aColor, nFlags );
+
+ // Determine if the Sheet that the Scenario was created on
+ // is protected. But first we need to find that Sheet.
+ // Rewind back to the actual sheet.
+ SCTAB nActualTab = nTab;
+ do
+ {
+ nActualTab--;
+ }
+ while(m_pDocument->IsScenario(nActualTab));
+ bool bSheetProtected = m_pDocument->IsTabProtected(nActualTab);
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScNewScenarioDlg> pNewDlg(pFact->CreateScNewScenarioDlg(GetActiveDialogParent(), aName, true, bSheetProtected));
+ pNewDlg->SetScenarioData( aName, aComment, aColor, nFlags );
+ if ( pNewDlg->Execute() == RET_OK )
+ {
+ pNewDlg->GetScenarioData( aName, aComment, aColor, nFlags );
+ ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ rReq.Done();
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_YEAR2000 :
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
+ {
+ if (const SfxUInt16Item* pInt16Item = dynamic_cast<const SfxUInt16Item*>(pItem))
+ {
+ sal_uInt16 nY2k = pInt16Item->GetValue();
+ // set always to DocOptions, so that it is also saved for S050
+ // (and all inquiries run up until now on it as well).
+ // SetDocOptions propagates that to the NumberFormatter
+ ScDocOptions aDocOpt( m_pDocument->GetDocOptions() );
+ aDocOpt.SetYear2000( nY2k );
+ m_pDocument->SetDocOptions( aDocOpt );
+ // the FormShell shall notice it as well
+ ScTabViewShell* pSh = GetBestViewShell();
+ if ( pSh )
+ {
+ FmFormShell* pFSh = pSh->GetFormShell();
+ if ( pFSh )
+ pFSh->SetY2KState( nY2k );
+ }
+ }
+ }
+ }
+ break;
+
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+ case SID_SHARE_DOC:
+ {
+ ScViewData* pViewData = GetViewData();
+ if ( !pViewData )
+ {
+ rReq.Ignore();
+ break;
+ }
+
+ weld::Window* pWin = GetActiveDialogParent();
+ ScShareDocumentDlg aDlg(pWin, pViewData);
+ if (aDlg.run() == RET_OK)
+ {
+ bool bSetShared = aDlg.IsShareDocumentChecked();
+ if ( bSetShared != IsDocShared() )
+ {
+ if ( bSetShared )
+ {
+ bool bContinue = true;
+ if ( HasName() )
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pWin,
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_DOC_WILLBESAVED)));
+ xQueryBox->set_default_response(RET_YES);
+ if (xQueryBox->run() == RET_NO)
+ {
+ bContinue = false;
+ }
+ }
+ if ( bContinue )
+ {
+ EnableSharedSettings( true );
+
+ SC_MOD()->SetInSharedDocSaving( true );
+ if ( !SwitchToShared( true, true ) )
+ {
+ // TODO/LATER: what should be done in case the switch has failed?
+ // for example in case the user has cancelled the saveAs operation
+ }
+
+ SC_MOD()->SetInSharedDocSaving( false );
+
+ InvalidateName();
+ GetUndoManager()->Clear();
+
+ ScTabView* pTabView = pViewData->GetView();
+ if ( pTabView )
+ {
+ pTabView->UpdateLayerLocks();
+ }
+ }
+ }
+ else
+ {
+ uno::Reference< frame::XModel > xModel;
+ try
+ {
+ // load shared file
+ xModel.set( LoadSharedDocument(), uno::UNO_SET_THROW );
+ uno::Reference< util::XCloseable > xCloseable( xModel, uno::UNO_QUERY_THROW );
+
+ // check if shared flag is set in shared file
+ bool bShared = false;
+ ScModelObj* pDocObj = comphelper::getFromUnoTunnel<ScModelObj>( xModel );
+ if ( pDocObj )
+ {
+ ScDocShell* pDocShell = dynamic_cast< ScDocShell* >( pDocObj->GetEmbeddedObject() );
+ if ( pDocShell )
+ {
+ bShared = pDocShell->HasSharedXMLFlagSet();
+ }
+ }
+
+ // #i87870# check if shared status was disabled and enabled again
+ bool bOwnEntry = false;
+ try
+ {
+ ::svt::ShareControlFile aControlFile( GetSharedFileURL() );
+ bOwnEntry = aControlFile.HasOwnEntry();
+ }
+ catch ( uno::Exception& )
+ {
+ }
+
+ if ( bShared && bOwnEntry )
+ {
+ uno::Reference< frame::XStorable > xStorable( xModel, uno::UNO_QUERY_THROW );
+ if ( xStorable->isReadonly() )
+ {
+ xCloseable->close( true );
+
+ OUString aUserName( ScResId( STR_UNKNOWN_USER ) );
+ try
+ {
+ ::svt::DocumentLockFile aLockFile( GetSharedFileURL() );
+ LockFileEntry aData = aLockFile.GetLockData();
+ if ( !aData[LockFileComponent::OOOUSERNAME].isEmpty() )
+ {
+ aUserName = aData[LockFileComponent::OOOUSERNAME];
+ }
+ else if ( !aData[LockFileComponent::SYSUSERNAME].isEmpty() )
+ {
+ aUserName = aData[LockFileComponent::SYSUSERNAME];
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ OUString aMessage( ScResId( STR_FILE_LOCKED_TRY_LATER ) );
+ aMessage = aMessage.replaceFirst( "%1", aUserName );
+
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(pWin,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ aMessage));
+ xWarn->run();
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(pWin,
+ VclMessageType::Warning, VclButtonsType::YesNo,
+ ScResId(STR_DOC_DISABLESHARED)));
+ xWarn->set_default_response(RET_YES);
+
+ if (xWarn->run() == RET_YES)
+ {
+ xCloseable->close( true );
+
+ if ( !SwitchToShared( false, true ) )
+ {
+ // TODO/LATER: what should be done in case the switch has failed?
+ // for example in case the user has cancelled the saveAs operation
+ }
+
+ EnableSharedSettings( false );
+
+ // Do *not* use dispatch mechanism in this place - we don't want others (extensions etc.) to intercept this.
+ uno::Reference<frame::XStorable> xStorable2(
+ GetModel(), uno::UNO_QUERY_THROW);
+ xStorable2->store();
+
+ ScTabView* pTabView = pViewData->GetView();
+ if ( pTabView )
+ {
+ pTabView->UpdateLayerLocks();
+ }
+ }
+ else
+ {
+ xCloseable->close( true );
+ }
+ }
+ }
+ else
+ {
+ xCloseable->close( true );
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(pWin,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(STR_DOC_NOLONGERSHARED)));
+ xWarn->run();
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "SID_SHARE_DOC" );
+ SC_MOD()->SetInSharedDocSaving( false );
+
+ try
+ {
+ uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW );
+ xClose->close( true );
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ }
+ }
+ }
+ rReq.Done();
+ }
+ break;
+#endif
+ case SID_OPEN_CALC:
+ {
+ ScViewData* pViewData = GetViewData();
+ if (pViewData)
+ {
+ SfxStringItem aApp(SID_DOC_SERVICE, "com.sun.star.sheet.SpreadsheetDocument");
+ SfxStringItem aTarget(SID_TARGETNAME, "_blank");
+ pViewData->GetDispatcher().ExecuteList(
+ SID_OPENDOC, SfxCallMode::API|SfxCallMode::SYNCHRON,
+ { &aApp, &aTarget });
+ }
+ }
+ break;
+ case SID_NOTEBOOKBAR:
+ {
+ const SfxStringItem* pFile = rReq.GetArg<SfxStringItem>( SID_NOTEBOOKBAR );
+
+ if ( pBindings && sfx2::SfxNotebookBar::IsActive() )
+ sfx2::SfxNotebookBar::ExecMethod(*pBindings, pFile ? pFile->GetValue() : "");
+ else if ( pBindings )
+ sfx2::SfxNotebookBar::CloseMethod(*pBindings);
+ }
+ break;
+ case SID_LANGUAGE_STATUS:
+ {
+ OUString aLangText;
+ const SfxStringItem* pItem = rReq.GetArg<SfxStringItem>(nSlot);
+ if ( pItem )
+ aLangText = pItem->GetValue();
+
+ if ( !aLangText.isEmpty() )
+ {
+ LanguageType eLang, eLatin, eCjk, eCtl;
+ static const OUStringLiteral aSelectionLangPrefix(u"Current_");
+ static const OUStringLiteral aParagraphLangPrefix(u"Paragraph_");
+ static const OUStringLiteral aDocLangPrefix(u"Default_");
+
+ bool bSelection = false;
+ bool bParagraph = false;
+
+ ScDocument& rDoc = GetDocument();
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+
+ sal_Int32 nPos = 0;
+ if ( aLangText == "*" )
+ {
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ ScTabViewShell* pSh = GetBestViewShell();
+ ScopedVclPtr<VclAbstractDialog> pDlg(pFact->CreateVclDialog(pSh ? pSh->GetDialogParent() : nullptr, SID_LANGUAGE_OPTIONS));
+ pDlg->Execute();
+
+ rDoc.GetLanguage( eLang, eCjk, eCtl );
+ }
+ else if ( (nPos = aLangText.indexOf(aDocLangPrefix)) != -1 )
+ {
+ aLangText = aLangText.replaceAt(nPos, aDocLangPrefix.getLength(), u"");
+
+ if ( aLangText == "LANGUAGE_NONE" )
+ {
+ eLang = LANGUAGE_NONE;
+ rDoc.SetLanguage( eLang, eCjk, eCtl );
+ }
+ else if ( aLangText == "RESET_LANGUAGES" )
+ {
+ bool bAutoSpell;
+
+ ScModule::GetSpellSettings(eLang, eCjk, eCtl, bAutoSpell);
+ rDoc.SetLanguage(eLang, eCjk, eCtl);
+ }
+ else
+ {
+ eLang = SvtLanguageTable::GetLanguageType( aLangText );
+ if ( eLang != LANGUAGE_DONTKNOW && SvtLanguageOptions::GetScriptTypeOfLanguage(eLang) == SvtScriptType::LATIN )
+ {
+ rDoc.SetLanguage( eLang, eCjk, eCtl );
+ }
+ else
+ {
+ eLang = eLatin;
+ }
+ }
+ }
+ else if (-1 != (nPos = aLangText.indexOf( aSelectionLangPrefix )))
+ {
+ bSelection = true;
+ aLangText = aLangText.replaceAt( nPos, aSelectionLangPrefix.getLength(), u"" );
+ }
+ else if (-1 != (nPos = aLangText.indexOf( aParagraphLangPrefix )))
+ {
+ bParagraph = true;
+ aLangText = aLangText.replaceAt( nPos, aParagraphLangPrefix.getLength(), u"" );
+ }
+
+ if (bSelection || bParagraph)
+ {
+ ScViewData* pViewData = GetViewData();
+ if (!pViewData)
+ return;
+
+ EditView* pEditView = pViewData->GetEditView(pViewData->GetActivePart());
+ if (!pEditView)
+ return;
+
+ const LanguageType nLangToUse = SvtLanguageTable::GetLanguageType( aLangText );
+ SvtScriptType nScriptType = SvtLanguageOptions::GetScriptTypeOfLanguage( nLangToUse );
+
+ SfxItemSet aAttrs = pEditView->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 = pEditView->GetSelection();
+ aOldSel = aSel;
+ aSel.nStartPos = 0;
+ aSel.nEndPos = EE_TEXTPOS_ALL;
+ pEditView->SetSelection( aSel );
+ }
+
+ pEditView->SetAttribs( aAttrs );
+ if (bParagraph)
+ pEditView->SetSelection( aOldSel );
+ }
+ else if ( eLang != eLatin )
+ {
+ if ( ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell() )
+ {
+ ScInputHandler* pInputHandler = SC_MOD()->GetInputHdl(pViewSh);
+ if ( pInputHandler )
+ pInputHandler->UpdateSpellSettings();
+
+ pViewSh->UpdateDrawTextOutliner();
+ }
+
+ SetDocumentModified();
+ Broadcast(SfxHint(SfxHintId::LanguageChanged));
+ PostPaintGridAll();
+ }
+ }
+ }
+ break;
+ case SID_SPELLCHECK_IGNORE_ALL:
+ {
+ ScViewData* pViewData = GetViewData();
+ if (!pViewData)
+ return;
+
+ EditView* pEditView = pViewData->GetEditView(pViewData->GetActivePart());
+ if (!pEditView)
+ return;
+
+ OUString sIgnoreText;
+ const SfxStringItem* pItem2 = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pItem2)
+ sIgnoreText = pItem2->GetValue();
+
+ if(sIgnoreText == "Spelling")
+ {
+ ESelection aOldSel = pEditView->GetSelection();
+ pEditView->SpellIgnoreWord();
+ pEditView->SetSelection( aOldSel );
+ }
+ }
+ break;
+ case SID_SPELLCHECK_APPLY_SUGGESTION:
+ {
+ ScViewData* pViewData = GetViewData();
+ if (!pViewData)
+ return;
+
+ EditView* pEditView = pViewData->GetEditView(pViewData->GetActivePart());
+ if (!pEditView)
+ return;
+
+ 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"");
+ pEditView->InsertText( sApplyText );
+ }
+ }
+ break;
+ case SID_REFRESH_VIEW:
+ {
+ PostPaintGridAll();
+ }
+ break;
+ default:
+ {
+ // small (?) hack -> forwarding of the slots to TabViewShell
+ ScTabViewShell* pSh = GetBestViewShell();
+ if ( pSh )
+ pSh->Execute( rReq );
+#if HAVE_FEATURE_SCRIPTING
+ else
+ SbxBase::SetError( ERRCODE_BASIC_NO_ACTIVE_OBJECT );
+#endif
+ }
+ }
+}
+
+void UpdateAcceptChangesDialog()
+{
+ // update "accept changes" dialog
+ //! notify all views
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if ( pViewFrm && pViewFrm->HasChildWindow( FID_CHG_ACCEPT ) )
+ {
+ SfxChildWindow* pChild = pViewFrm->GetChildWindow( FID_CHG_ACCEPT );
+ if ( pChild )
+ static_cast<ScAcceptChgDlgWrapper*>(pChild)->ReInitDlg();
+ }
+}
+
+bool ScDocShell::ExecuteChangeProtectionDialog( bool bJustQueryIfProtected )
+{
+ bool bDone = false;
+ ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ bool bProtected = pChangeTrack->IsProtected();
+ if ( bJustQueryIfProtected && !bProtected )
+ return true;
+
+ OUString aTitle( ScResId( bProtected ? SCSTR_CHG_UNPROTECT : SCSTR_CHG_PROTECT ) );
+ OUString aText( ScResId( SCSTR_PASSWORD ) );
+ OUString aPassword;
+
+ weld::Window* pWin = ScDocShell::GetActiveDialogParent();
+ SfxPasswordDialog aDlg(pWin, &aText);
+ aDlg.set_title(aTitle);
+ aDlg.SetMinLen(1);
+ aDlg.set_help_id(GetStaticInterface()->GetSlot(SID_CHG_PROTECT)->GetCommand());
+ aDlg.SetEditHelpId( HID_CHG_PROTECT );
+ if ( !bProtected )
+ aDlg.ShowExtras(SfxShowExtras::CONFIRM);
+ if (aDlg.run() == RET_OK)
+ aPassword = aDlg.GetPassword();
+
+ if (!aPassword.isEmpty())
+ {
+ if ( bProtected )
+ {
+ if ( SvPasswordHelper::CompareHashPassword(pChangeTrack->GetProtection(), aPassword) )
+ {
+ if ( bJustQueryIfProtected )
+ bDone = true;
+ else
+ pChangeTrack->SetProtection( {} );
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pWin,
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(SCSTR_WRONGPASSWORD)));
+ xInfoBox->run();
+ }
+ }
+ else
+ {
+ css::uno::Sequence< sal_Int8 > aPass;
+ SvPasswordHelper::GetHashPassword( aPass, aPassword );
+ pChangeTrack->SetProtection( aPass );
+ }
+ if ( bProtected != pChangeTrack->IsProtected() )
+ {
+ UpdateAcceptChangesDialog();
+ bDone = true;
+ }
+ }
+ }
+ else if ( bJustQueryIfProtected )
+ bDone = true;
+ return bDone;
+}
+
+void ScDocShell::DoRecalc( bool bApi )
+{
+ if (m_pDocument->IsInDocShellRecalc())
+ {
+ SAL_WARN("sc","ScDocShell::DoRecalc tries re-entering while in Recalc; probably Forms->BASIC->Dispatcher.");
+ return;
+ }
+ ScDocShellRecalcGuard aGuard(*m_pDocument);
+ bool bDone = false;
+ ScTabViewShell* pSh = GetBestViewShell();
+ ScInputHandler* pHdl = ( pSh ? SC_MOD()->GetInputHdl( pSh ) : nullptr );
+ if ( pSh )
+ {
+ if ( pHdl && pHdl->IsInputMode() && pHdl->IsFormulaMode() && !bApi )
+ {
+ pHdl->FormulaPreview(); // partial result as QuickHelp
+ bDone = true;
+ }
+ else
+ {
+ ScTabView::UpdateInputLine(); // InputEnterHandler
+ pSh->UpdateInputHandler();
+ }
+ }
+ if (bDone) // otherwise re-calculate document
+ return;
+
+ weld::WaitObject aWaitObj( GetActiveDialogParent() );
+ if ( pHdl )
+ {
+ // tdf97897 set current cell to Dirty to force recalculation of cell
+ ScFormulaCell* pFC = m_pDocument->GetFormulaCell( pHdl->GetCursorPos());
+ if (pFC)
+ pFC->SetDirty();
+ }
+ m_pDocument->CalcFormulaTree();
+ if ( pSh )
+ pSh->UpdateCharts(true);
+
+ m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
+
+ // If there are charts, then paint everything, so that PostDataChanged
+ // and the charts do not come one after the other and parts are painted twice.
+
+ ScChartListenerCollection* pCharts = m_pDocument->GetChartListenerCollection();
+ if ( pCharts && pCharts->hasListeners() )
+ PostPaintGridAll();
+ else
+ PostDataChanged();
+}
+
+void ScDocShell::DoHardRecalc()
+{
+ if (m_pDocument->IsInDocShellRecalc())
+ {
+ SAL_WARN("sc","ScDocShell::DoHardRecalc tries re-entering while in Recalc; probably Forms->BASIC->Dispatcher.");
+ return;
+ }
+ auto start = std::chrono::steady_clock::now();
+ ScDocShellRecalcGuard aGuard(*m_pDocument);
+ weld::WaitObject aWaitObj( GetActiveDialogParent() );
+ ScTabViewShell* pSh = GetBestViewShell();
+ if ( pSh )
+ {
+ ScTabView::UpdateInputLine(); // InputEnterHandler
+ pSh->UpdateInputHandler();
+ }
+ m_pDocument->CalcAll();
+ GetDocFunc().DetectiveRefresh(); // creates own Undo
+ if ( pSh )
+ pSh->UpdateCharts(true);
+
+ // set notification flags for "calculate" event (used in SfxHintId::DataChanged broadcast)
+ // (might check for the presence of any formulas on each sheet)
+ SCTAB nTabCount = m_pDocument->GetTableCount();
+ if (m_pDocument->HasAnySheetEventScript( ScSheetEventId::CALCULATE, true )) // search also for VBA handler
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ m_pDocument->SetCalcNotification(nTab);
+
+ // CalcAll doesn't broadcast value changes, so SfxHintId::ScCalcAll is broadcasted globally
+ // in addition to SfxHintId::DataChanged.
+ m_pDocument->BroadcastUno( SfxHint( SfxHintId::ScCalcAll ) );
+ m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
+
+ // use hard recalc also to disable stream-copying of all sheets
+ // (somewhat consistent with charts)
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ m_pDocument->SetStreamValid(nTab, false);
+
+ PostPaintGridAll();
+ auto end = std::chrono::steady_clock::now();
+ SAL_INFO("sc.timing", "ScDocShell::DoHardRecalc(): took " << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms");
+}
+
+void ScDocShell::DoAutoStyle( const ScRange& rRange, const OUString& rStyle )
+{
+ ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
+ ScStyleSheet* pStyleSheet = pStylePool->FindAutoStyle(rStyle);
+ if (!pStyleSheet)
+ return;
+
+ OSL_ENSURE(rRange.aStart.Tab() == rRange.aEnd.Tab(),
+ "DoAutoStyle with several tables");
+ SCTAB nTab = rRange.aStart.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ m_pDocument->ApplyStyleAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, *pStyleSheet );
+ m_pDocument->ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab );
+ PostPaint( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab, PaintPartFlags::Grid );
+}
+
+void ScDocShell::NotifyStyle( const SfxStyleSheetHint& rHint )
+{
+ SfxHintId nId = rHint.GetId();
+ const SfxStyleSheetBase* pStyle = rHint.GetStyleSheet();
+ if (!pStyle)
+ return;
+
+ if ( pStyle->GetFamily() == SfxStyleFamily::Page )
+ {
+ if ( nId == SfxHintId::StyleSheetModified )
+ {
+ ScDocShellModificator aModificator( *this );
+
+ const OUString& aNewName = pStyle->GetName();
+ OUString aOldName = aNewName;
+ const SfxStyleSheetModifiedHint* pExtendedHint = dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint); // name changed?
+ if (pExtendedHint)
+ aOldName = pExtendedHint->GetOldName();
+
+ if ( aNewName != aOldName )
+ m_pDocument->RenamePageStyleInUse( aOldName, aNewName );
+
+ SCTAB nTabCount = m_pDocument->GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ if (m_pDocument->GetPageStyle(nTab) == aNewName) // already adjusted to new
+ {
+ m_pDocument->PageStyleModified( nTab, aNewName );
+ ScPrintFunc aPrintFunc( this, GetPrinter(), nTab );
+ aPrintFunc.UpdatePages();
+ }
+
+ aModificator.SetDocumentModified();
+
+ if (pExtendedHint)
+ {
+ SfxBindings* pBindings = GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( SID_STATUS_PAGESTYLE );
+ pBindings->Invalidate( SID_STYLE_FAMILY4 );
+ pBindings->Invalidate( FID_RESET_PRINTZOOM );
+ pBindings->Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ pBindings->Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT );
+ }
+ }
+ }
+ }
+ else if ( pStyle->GetFamily() == SfxStyleFamily::Para )
+ {
+ if ( nId == SfxHintId::StyleSheetModified)
+ {
+ const OUString& aNewName = pStyle->GetName();
+ OUString aOldName = aNewName;
+ const SfxStyleSheetModifiedHint* pExtendedHint = dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint);
+ if (pExtendedHint)
+ aOldName = pExtendedHint->GetOldName();
+ if ( aNewName != aOldName )
+ {
+ for(SCTAB i = 0; i < m_pDocument->GetTableCount(); ++i)
+ {
+ ScConditionalFormatList* pList = m_pDocument->GetCondFormList(i);
+ if (pList)
+ pList->RenameCellStyle( aOldName,aNewName );
+ }
+ }
+ }
+ }
+
+ // everything else goes via slots...
+}
+
+// like in printfun.cxx
+#define ZOOM_MIN 10
+
+void ScDocShell::SetPrintZoom( SCTAB nTab, sal_uInt16 nScale, sal_uInt16 nPages )
+{
+ OUString aStyleName = m_pDocument->GetPageStyle( nTab );
+ ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Page );
+ OSL_ENSURE( pStyleSheet, "PageStyle not found" );
+ if ( !pStyleSheet )
+ return;
+
+ ScDocShellModificator aModificator( *this );
+
+ SfxItemSet& rSet = pStyleSheet->GetItemSet();
+ const bool bUndo(m_pDocument->IsUndoEnabled());
+ if (bUndo)
+ {
+ sal_uInt16 nOldScale = rSet.Get(ATTR_PAGE_SCALE).GetValue();
+ sal_uInt16 nOldPages = rSet.Get(ATTR_PAGE_SCALETOPAGES).GetValue();
+ GetUndoManager()->AddUndoAction( std::make_unique<ScUndoPrintZoom>(
+ this, nTab, nOldScale, nOldPages, nScale, nPages ) );
+ }
+
+ rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALE, nScale ) );
+ rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, nPages ) );
+
+ ScPrintFunc aPrintFunc( this, GetPrinter(), nTab );
+ aPrintFunc.UpdatePages();
+ aModificator.SetDocumentModified();
+
+ SfxBindings* pBindings = GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( FID_RESET_PRINTZOOM );
+}
+
+bool ScDocShell::AdjustPrintZoom( const ScRange& rRange )
+{
+ bool bChange = false;
+ SCTAB nTab = rRange.aStart.Tab();
+
+ OUString aStyleName = m_pDocument->GetPageStyle( nTab );
+ ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Page );
+ OSL_ENSURE( pStyleSheet, "PageStyle not found" );
+ if ( pStyleSheet )
+ {
+ SfxItemSet& rSet = pStyleSheet->GetItemSet();
+ bool bHeaders = rSet.Get(ATTR_PAGE_HEADERS).GetValue();
+ sal_uInt16 nOldScale = rSet.Get(ATTR_PAGE_SCALE).GetValue();
+ sal_uInt16 nOldPages = rSet.Get(ATTR_PAGE_SCALETOPAGES).GetValue();
+ std::optional<ScRange> oRepeatCol = m_pDocument->GetRepeatColRange( nTab );
+ std::optional<ScRange> oRepeatRow = m_pDocument->GetRepeatRowRange( nTab );
+
+ // calculate needed scaling for selection
+
+ sal_uInt16 nNewScale = nOldScale;
+
+ tools::Long nBlkTwipsX = 0;
+ if (bHeaders)
+ nBlkTwipsX += PRINT_HEADER_WIDTH;
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ if ( oRepeatCol && nStartCol >= oRepeatCol->aStart.Col() )
+ {
+ for (SCCOL i=oRepeatCol->aStart.Col(); i<=oRepeatCol->aEnd.Col(); i++ )
+ nBlkTwipsX += m_pDocument->GetColWidth( i, nTab );
+ if ( nStartCol <= oRepeatCol->aEnd.Col() )
+ nStartCol = oRepeatCol->aEnd.Col() + 1;
+ }
+ // legacy compilers' own scope for i
+ {
+ for ( SCCOL i=nStartCol; i<=nEndCol; i++ )
+ nBlkTwipsX += m_pDocument->GetColWidth( i, nTab );
+ }
+
+ tools::Long nBlkTwipsY = 0;
+ if (bHeaders)
+ nBlkTwipsY += PRINT_HEADER_HEIGHT;
+ SCROW nStartRow = rRange.aStart.Row();
+ SCROW nEndRow = rRange.aEnd.Row();
+ if ( oRepeatRow && nStartRow >= oRepeatRow->aStart.Row() )
+ {
+ nBlkTwipsY += m_pDocument->GetRowHeight( oRepeatRow->aStart.Row(),
+ oRepeatRow->aEnd.Row(), nTab );
+ if ( nStartRow <= oRepeatRow->aEnd.Row() )
+ nStartRow = oRepeatRow->aEnd.Row() + 1;
+ }
+ nBlkTwipsY += m_pDocument->GetRowHeight( nStartRow, nEndRow, nTab );
+
+ Size aPhysPage;
+ tools::Long nHdr, nFtr;
+ ScPrintFunc aOldPrFunc( this, GetPrinter(), nTab );
+ aOldPrFunc.GetScaleData( aPhysPage, nHdr, nFtr );
+ nBlkTwipsY += nHdr + nFtr;
+
+ if ( nBlkTwipsX == 0 ) // hidden columns/rows may lead to 0
+ nBlkTwipsX = 1;
+ if ( nBlkTwipsY == 0 )
+ nBlkTwipsY = 1;
+
+ tools::Long nNeeded = std::min( aPhysPage.Width() * 100 / nBlkTwipsX,
+ aPhysPage.Height() * 100 / nBlkTwipsY );
+ if ( nNeeded < ZOOM_MIN )
+ nNeeded = ZOOM_MIN; // boundary
+ if ( nNeeded < static_cast<tools::Long>(nNewScale) )
+ nNewScale = static_cast<sal_uInt16>(nNeeded);
+
+ bChange = ( nNewScale != nOldScale || nOldPages != 0 );
+ if ( bChange )
+ SetPrintZoom( nTab, nNewScale, 0 );
+ }
+ return bChange;
+}
+
+void ScDocShell::PageStyleModified( std::u16string_view rStyleName, bool bApi )
+{
+ ScDocShellModificator aModificator( *this );
+
+ SCTAB nTabCount = m_pDocument->GetTableCount();
+ SCTAB nUseTab = MAXTAB+1;
+ for (SCTAB nTab=0; nTab<nTabCount && nUseTab>MAXTAB; nTab++)
+ if ( m_pDocument->GetPageStyle(nTab) == rStyleName &&
+ ( !bApi || m_pDocument->GetPageSize(nTab).Width() ) )
+ nUseTab = nTab;
+ // at bApi only if breaks already shown
+
+ if (ValidTab(nUseTab)) // not used -> nothing to do
+ {
+ bool bWarn = false;
+
+ ScPrintFunc aPrintFunc( this, GetPrinter(), nUseTab ); //! cope without CountPages
+ if (!aPrintFunc.UpdatePages()) // sets breaks on all tabs
+ bWarn = true;
+
+ if (bWarn && !bApi)
+ {
+ weld::Window* pWin = GetActiveDialogParent();
+ weld::WaitObject aWaitOff(pWin);
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pWin,
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_PRINT_INVALID_AREA)));
+ xInfoBox->run();
+ }
+ }
+
+ aModificator.SetDocumentModified();
+
+ SfxBindings* pBindings = GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( FID_RESET_PRINTZOOM );
+ pBindings->Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ pBindings->Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT );
+ }
+}
+
+void ScDocShell::ExecutePageStyle( const SfxViewShell& rCaller,
+ SfxRequest& rReq,
+ SCTAB nCurTab )
+{
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ switch ( rReq.GetSlot() )
+ {
+ case SID_STATUS_PAGESTYLE: // click on StatusBar control
+ case SID_FORMATPAGE:
+ {
+ if ( pReqArgs == nullptr )
+ {
+ OUString aOldName = m_pDocument->GetPageStyle( nCurTab );
+ ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet
+ = pStylePool->Find( aOldName, SfxStyleFamily::Page );
+
+ OSL_ENSURE( pStyleSheet, "PageStyle not found! :-/" );
+
+ if ( pStyleSheet )
+ {
+ ScStyleSaveData aOldData;
+ const bool bUndo(m_pDocument->IsUndoEnabled());
+ if (bUndo)
+ aOldData.InitFromStyle( pStyleSheet );
+
+ SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
+ rStyleSet.MergeRange( XATTR_FILL_FIRST, XATTR_FILL_LAST );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ VclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateScStyleDlg(GetActiveDialogParent(), *pStyleSheet, true));
+
+ auto pRequest = std::make_shared<SfxRequest>(rReq);
+ rReq.Ignore(); // the 'old' request is not relevant any more
+ pDlg->StartExecuteAsync([this, pDlg, pRequest, pStyleSheet, aOldData, aOldName, &rStyleSet, nCurTab, &rCaller, bUndo](sal_Int32 nResult){
+ if ( nResult == RET_OK )
+ {
+ const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
+
+ weld::WaitObject aWait( GetActiveDialogParent() );
+
+ OUString aNewName = pStyleSheet->GetName();
+ if ( aNewName != aOldName &&
+ m_pDocument->RenamePageStyleInUse( aOldName, aNewName ) )
+ {
+ SfxBindings* pBindings = GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( SID_STATUS_PAGESTYLE );
+ pBindings->Invalidate( FID_RESET_PRINTZOOM );
+ }
+ }
+
+ if ( pOutSet )
+ m_pDocument->ModifyStyleSheet( *pStyleSheet, *pOutSet );
+
+ // memorizing for GetState():
+ GetPageOnFromPageStyleSet( &rStyleSet, nCurTab, m_bHeaderOn, m_bFooterOn );
+ rCaller.GetViewFrame()->GetBindings().Invalidate( SID_HFEDIT );
+
+ ScStyleSaveData aNewData;
+ aNewData.InitFromStyle( pStyleSheet );
+ if (bUndo)
+ {
+ GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoModifyStyle>( this, SfxStyleFamily::Page,
+ aOldData, aNewData ) );
+ }
+
+ PageStyleModified( aNewName, false );
+ pRequest->Done();
+ }
+ pDlg->disposeOnce();
+ });
+ }
+ }
+ }
+ break;
+
+ case SID_HFEDIT:
+ {
+ if ( pReqArgs == nullptr )
+ {
+ OUString aStr( m_pDocument->GetPageStyle( nCurTab ) );
+
+ ScStyleSheetPool* pStylePool
+ = m_pDocument->GetStyleSheetPool();
+
+ SfxStyleSheetBase* pStyleSheet
+ = pStylePool->Find( aStr, SfxStyleFamily::Page );
+
+ OSL_ENSURE( pStyleSheet, "PageStyle not found! :-/" );
+
+ if ( pStyleSheet )
+ {
+ SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
+
+ SvxPageUsage eUsage = rStyleSet.Get( ATTR_PAGE ).GetPageUsage();
+ bool bShareHeader = rStyleSet
+ .Get(ATTR_PAGE_HEADERSET)
+ .GetItemSet()
+ .Get(ATTR_PAGE_SHARED)
+ .GetValue();
+ bool bShareFooter = rStyleSet
+ .Get(ATTR_PAGE_FOOTERSET)
+ .GetItemSet()
+ .Get(ATTR_PAGE_SHARED)
+ .GetValue();
+ sal_uInt16 nResId = 0;
+
+ switch ( eUsage )
+ {
+ case SvxPageUsage::Left:
+ case SvxPageUsage::Right:
+ {
+ if ( m_bHeaderOn && m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT;
+ else if ( SvxPageUsage::Right == eUsage )
+ {
+ if ( !m_bHeaderOn && m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_RIGHTFOOTER;
+ else if ( m_bHeaderOn && !m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_RIGHTHEADER;
+ }
+ else
+ {
+ // #69193a# respect "shared" setting
+ if ( !m_bHeaderOn && m_bFooterOn )
+ nResId = bShareFooter ?
+ RID_SCDLG_HFEDIT_RIGHTFOOTER :
+ RID_SCDLG_HFEDIT_LEFTFOOTER;
+ else if ( m_bHeaderOn && !m_bFooterOn )
+ nResId = bShareHeader ?
+ RID_SCDLG_HFEDIT_RIGHTHEADER :
+ RID_SCDLG_HFEDIT_LEFTHEADER;
+ }
+ }
+ break;
+
+ case SvxPageUsage::Mirror:
+ case SvxPageUsage::All:
+ default:
+ {
+ if ( !bShareHeader && !bShareFooter )
+ {
+ if ( m_bHeaderOn && m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_ALL;
+ else if ( !m_bHeaderOn && m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_FOOTER;
+ else if ( m_bHeaderOn && !m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_HEADER;
+ }
+ else if ( bShareHeader && bShareFooter )
+ {
+ if ( m_bHeaderOn && m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT;
+ else
+ {
+ if ( !m_bHeaderOn && m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_RIGHTFOOTER;
+ else if ( m_bHeaderOn && !m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_RIGHTHEADER;
+ }
+ }
+ else if ( !bShareHeader && bShareFooter )
+ {
+ if ( m_bHeaderOn && m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_SFTR;
+ else if ( !m_bHeaderOn && m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_RIGHTFOOTER;
+ else if ( m_bHeaderOn && !m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_HEADER;
+ }
+ else if ( bShareHeader && !bShareFooter )
+ {
+ if ( m_bHeaderOn && m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_SHDR;
+ else if ( !m_bHeaderOn && m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_FOOTER;
+ else if ( m_bHeaderOn && !m_bFooterOn )
+ nResId = RID_SCDLG_HFEDIT_RIGHTHEADER;
+ }
+ }
+ }
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ VclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateScHFEditDlg(
+ GetActiveDialogParent(),
+ rStyleSet,
+ aStr,
+ nResId));
+ auto xRequest = std::make_shared<SfxRequest>(rReq);
+ rReq.Ignore(); // the 'old' request is not relevant any more
+ pDlg->StartExecuteAsync([this, pDlg, pStyleSheet, xRequest](sal_Int32 nResult){
+ if ( nResult == RET_OK )
+ {
+ const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
+
+ if ( pOutSet )
+ m_pDocument->ModifyStyleSheet( *pStyleSheet, *pOutSet );
+
+ SetDocumentModified();
+ xRequest->Done();
+ }
+ pDlg->disposeOnce();
+ });
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void ScDocShell::GetStatePageStyle( SfxItemSet& rSet,
+ SCTAB nCurTab )
+{
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while ( nWhich )
+ {
+ switch (nWhich)
+ {
+ case SID_STATUS_PAGESTYLE:
+ rSet.Put( SfxStringItem( nWhich, m_pDocument->GetPageStyle( nCurTab ) ) );
+ break;
+
+ case SID_HFEDIT:
+ {
+ OUString aStr = m_pDocument->GetPageStyle( nCurTab );
+ ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStr, SfxStyleFamily::Page );
+
+ OSL_ENSURE( pStyleSheet, "PageStyle not found! :-/" );
+
+ if ( pStyleSheet )
+ {
+ SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
+ GetPageOnFromPageStyleSet( &rStyleSet, nCurTab, m_bHeaderOn, m_bFooterOn );
+
+ if ( !m_bHeaderOn && !m_bFooterOn )
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void ScDocShell::GetState( SfxItemSet &rSet )
+{
+ bool bTabView = GetBestViewShell() != nullptr;
+
+ SfxWhichIter aIter(rSet);
+ for (sal_uInt16 nWhich = aIter.FirstWhich(); nWhich; nWhich = aIter.NextWhich())
+ {
+ if (!bTabView)
+ {
+ rSet.DisableItem(nWhich);
+ continue;
+ }
+
+ switch (nWhich)
+ {
+ case FID_AUTO_CALC:
+ if ( m_pDocument->GetHardRecalcState() != ScDocument::HardRecalcState::OFF )
+ rSet.DisableItem( nWhich );
+ else
+ rSet.Put( SfxBoolItem( nWhich, m_pDocument->GetAutoCalc() ) );
+ break;
+
+ case FID_CHG_RECORD:
+ if ( IsDocShared() )
+ rSet.DisableItem( nWhich );
+ else
+ rSet.Put( SfxBoolItem( nWhich,
+ m_pDocument->GetChangeTrack() != nullptr ) );
+ break;
+
+ case SID_CHG_PROTECT:
+ {
+ ScChangeTrack* pChangeTrack = m_pDocument->GetChangeTrack();
+ if ( pChangeTrack && !IsDocShared() )
+ rSet.Put( SfxBoolItem( nWhich,
+ pChangeTrack->IsProtected() ) );
+ else
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_DOCUMENT_COMPARE:
+ {
+ if ( IsDocShared() )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ // When a formula is edited, FID_RECALC must be enabled in any case. Recalc for
+ // the doc was disabled once because of a bug if AutoCalc was on, but is now
+ // always enabled because of another bug.
+
+ case SID_TABLES_COUNT:
+ rSet.Put( SfxInt16Item( nWhich, m_pDocument->GetTableCount() ) );
+ break;
+
+ case SID_ATTR_YEAR2000 :
+ rSet.Put( SfxUInt16Item( nWhich,
+ m_pDocument->GetDocOptions().GetYear2000() ) );
+ break;
+
+ case SID_SHARE_DOC:
+ {
+ if ( IsReadOnly() || GetObjectShell()->isExportLocked() )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case SID_ATTR_CHAR_FONTLIST:
+ rSet.Put( SvxFontListItem( m_pImpl->pFontList.get(), nWhich ) );
+ break;
+
+ case SID_NOTEBOOKBAR:
+ {
+ if (GetViewBindings())
+ {
+ bool bVisible = sfx2::SfxNotebookBar::StateMethod(*GetViewBindings(),
+ u"modules/scalc/ui/");
+ rSet.Put( SfxBoolItem( SID_NOTEBOOKBAR, bVisible ) );
+ }
+ }
+ break;
+
+ case SID_LANGUAGE_STATUS:
+ {
+ LanguageType eLatin, eCjk, eCtl;
+
+ GetDocument().GetLanguage( eLatin, eCjk, eCtl );
+ OUString sLanguage = SvtLanguageTable::GetLanguageString(eLatin);
+ if (comphelper::LibreOfficeKit::isActive()) {
+ if (eLatin == LANGUAGE_NONE)
+ sLanguage += ";-";
+ else
+ sLanguage += ";" + LanguageTag(eLatin).getBcp47(false);
+ }
+ rSet.Put(SfxStringItem(nWhich, sLanguage));
+ }
+ break;
+
+ default:
+ {
+ }
+ break;
+ }
+ }
+}
+
+void ScDocShell::Draw( OutputDevice* pDev, const JobSetup & /* rSetup */, sal_uInt16 nAspect )
+{
+
+ SCTAB nVisTab = m_pDocument->GetVisibleTab();
+ if (!m_pDocument->HasTable(nVisTab))
+ return;
+
+ vcl::text::ComplexTextLayoutFlags nOldLayoutMode = pDev->GetLayoutMode();
+ pDev->SetLayoutMode( vcl::text::ComplexTextLayoutFlags::Default ); // even if it's the same, to get the metafile action
+
+ if ( nAspect == ASPECT_THUMBNAIL )
+ {
+ tools::Rectangle aBoundRect = GetVisArea( ASPECT_THUMBNAIL );
+ ScViewData aTmpData( *this, nullptr );
+ aTmpData.SetTabNo(nVisTab);
+ SnapVisArea( aBoundRect );
+ aTmpData.SetScreen( aBoundRect );
+ ScPrintFunc::DrawToDev( *m_pDocument, pDev, 1.0, aBoundRect, &aTmpData, true );
+ }
+ else
+ {
+ tools::Rectangle aOldArea = SfxObjectShell::GetVisArea();
+ tools::Rectangle aNewArea = aOldArea;
+ ScViewData aTmpData( *this, nullptr );
+ aTmpData.SetTabNo(nVisTab);
+ SnapVisArea( aNewArea );
+ if ( aNewArea != aOldArea && (m_pDocument->GetPosLeft() > 0 || m_pDocument->GetPosTop() > 0) )
+ SfxObjectShell::SetVisArea( aNewArea );
+ aTmpData.SetScreen( aNewArea );
+ ScPrintFunc::DrawToDev( *m_pDocument, pDev, 1.0, aNewArea, &aTmpData, true );
+ }
+
+ pDev->SetLayoutMode( nOldLayoutMode );
+}
+
+tools::Rectangle ScDocShell::GetVisArea( sal_uInt16 nAspect ) const
+{
+ SfxObjectCreateMode eShellMode = GetCreateMode();
+ if ( eShellMode == SfxObjectCreateMode::ORGANIZER )
+ {
+ // without contents we also don't know how large are the contents;
+ // return empty rectangle, it will then be calculated after the loading
+ return tools::Rectangle();
+ }
+
+ if( nAspect == ASPECT_THUMBNAIL )
+ {
+ SCTAB nVisTab = m_pDocument->GetVisibleTab();
+ if (!m_pDocument->HasTable(nVisTab))
+ {
+ nVisTab = 0;
+ const_cast<ScDocShell*>(this)->m_pDocument->SetVisibleTab(nVisTab);
+ }
+ Size aSize = m_pDocument->GetPageSize(nVisTab);
+ const tools::Long SC_PREVIEW_SIZE_X = 10000;
+ const tools::Long SC_PREVIEW_SIZE_Y = 12400;
+ tools::Rectangle aArea( 0,0, SC_PREVIEW_SIZE_X, SC_PREVIEW_SIZE_Y);
+ if (aSize.Width() > aSize.Height())
+ {
+ aArea.SetRight( SC_PREVIEW_SIZE_Y );
+ aArea.SetBottom( SC_PREVIEW_SIZE_X );
+ }
+
+ bool bNegativePage = m_pDocument->IsNegativePage( m_pDocument->GetVisibleTab() );
+ if ( bNegativePage )
+ ScDrawLayer::MirrorRectRTL( aArea );
+ SnapVisArea( aArea );
+ return aArea;
+ }
+ else if( nAspect == ASPECT_CONTENT && eShellMode != SfxObjectCreateMode::EMBEDDED )
+ {
+ // fetch visarea like after loading
+
+ SCTAB nVisTab = m_pDocument->GetVisibleTab();
+ if (!m_pDocument->HasTable(nVisTab))
+ {
+ nVisTab = 0;
+ const_cast<ScDocShell*>(this)->m_pDocument->SetVisibleTab(nVisTab);
+ }
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ m_pDocument->GetDataStart( nVisTab, nStartCol, nStartRow );
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ m_pDocument->GetPrintArea( nVisTab, nEndCol, nEndRow );
+ if (nStartCol>nEndCol)
+ nStartCol = nEndCol;
+ if (nStartRow>nEndRow)
+ nStartRow = nEndRow;
+ tools::Rectangle aNewArea = m_pDocument
+ ->GetMMRect( nStartCol,nStartRow, nEndCol,nEndRow, nVisTab );
+ return aNewArea;
+ }
+ else
+ return SfxObjectShell::GetVisArea( nAspect );
+}
+
+namespace {
+
+[[nodiscard]]
+tools::Long SnapHorizontal( const ScDocument& rDoc, SCTAB nTab, tools::Long nVal, SCCOL& rStartCol )
+{
+ SCCOL nCol = 0;
+ tools::Long nTwips = o3tl::convert(nVal, o3tl::Length::mm100, o3tl::Length::twip);
+ tools::Long nSnap = 0;
+ while ( nCol<rDoc.MaxCol() )
+ {
+ tools::Long nAdd = rDoc.GetColWidth(nCol, nTab);
+ if ( nSnap + nAdd/2 < nTwips || nCol < rStartCol )
+ {
+ nSnap += nAdd;
+ ++nCol;
+ }
+ else
+ break;
+ }
+ nVal = o3tl::convert(nSnap, o3tl::Length::twip, o3tl::Length::mm100);
+ rStartCol = nCol;
+ return nVal;
+}
+
+[[nodiscard]]
+tools::Long SnapVertical( const ScDocument& rDoc, SCTAB nTab, tools::Long nVal, SCROW& rStartRow )
+{
+ SCROW nRow = 0;
+ tools::Long nTwips = o3tl::convert(nVal, o3tl::Length::mm100, o3tl::Length::twip);
+ tools::Long nSnap = 0;
+
+ bool bFound = false;
+ for (SCROW i = nRow; i <= rDoc.MaxRow(); ++i)
+ {
+ SCROW nLastRow;
+ if (rDoc.RowHidden(i, nTab, nullptr, &nLastRow))
+ {
+ i = nLastRow;
+ continue;
+ }
+
+ nRow = i;
+ tools::Long nAdd = rDoc.GetRowHeight(i, nTab);
+ if ( nSnap + nAdd/2 < nTwips || nRow < rStartRow )
+ {
+ nSnap += nAdd;
+ ++nRow;
+ }
+ else
+ {
+ bFound = true;
+ break;
+ }
+ }
+ if (!bFound)
+ nRow = rDoc.MaxRow(); // all hidden down to the bottom
+
+ nVal = o3tl::convert(nSnap, o3tl::Length::twip, o3tl::Length::mm100);
+ rStartRow = nRow;
+ return nVal;
+}
+
+}
+
+void ScDocShell::SnapVisArea( tools::Rectangle& rRect ) const
+{
+ SCTAB nTab = m_pDocument->GetVisibleTab();
+ tools::Long nOrigTop = rRect.Top();
+ tools::Long nOrigLeft = rRect.Left();
+ bool bNegativePage = m_pDocument->IsNegativePage( nTab );
+ if ( bNegativePage )
+ ScDrawLayer::MirrorRectRTL( rRect ); // calculate with positive (LTR) values
+
+ SCCOL nCol = m_pDocument->GetPosLeft();
+ tools::Long nSetLeft = SnapHorizontal( *m_pDocument, nTab, rRect.Left(), nCol );
+ rRect.SetLeft( nSetLeft );
+ ++nCol; // at least one column
+ tools::Long nCorrectionLeft = (nOrigLeft == 0 && nCol > 0) ? nSetLeft : 0; // initial correction
+ rRect.SetRight( SnapHorizontal( *m_pDocument, nTab, rRect.Right() + nCorrectionLeft, nCol ));
+
+ SCROW nRow = m_pDocument->GetPosTop();
+ tools::Long nSetTop = SnapVertical( *m_pDocument, nTab, rRect.Top(), nRow );
+ rRect.SetTop( nSetTop );
+ ++nRow; // at least one row
+ tools::Long nCorrectionTop = (nOrigTop == 0 && nRow > 0) ? nSetTop : 0; // initial correction
+ rRect.SetBottom( SnapVertical( *m_pDocument, nTab, rRect.Bottom() + nCorrectionTop, nRow ));
+
+ if ( bNegativePage )
+ ScDrawLayer::MirrorRectRTL( rRect ); // back to real rectangle
+}
+
+void ScDocShell::GetPageOnFromPageStyleSet( const SfxItemSet* pStyleSet,
+ SCTAB nCurTab,
+ bool& rbHeader,
+ bool& rbFooter )
+{
+ if ( !pStyleSet )
+ {
+ ScStyleSheetPool* pStylePool = m_pDocument->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->
+ Find( m_pDocument->GetPageStyle( nCurTab ),
+ SfxStyleFamily::Page );
+
+ OSL_ENSURE( pStyleSheet, "PageStyle not found! :-/" );
+
+ if ( pStyleSheet )
+ pStyleSet = &pStyleSheet->GetItemSet();
+ else
+ rbHeader = rbFooter = false;
+ }
+
+ OSL_ENSURE( pStyleSet, "PageStyle-Set not found! :-(" );
+ if (!pStyleSet)
+ return;
+
+ const SvxSetItem* pSetItem = nullptr;
+ const SfxItemSet* pSet = nullptr;
+
+ pSetItem = &pStyleSet->Get( ATTR_PAGE_HEADERSET );
+ pSet = &pSetItem->GetItemSet();
+ rbHeader = pSet->Get(ATTR_PAGE_ON).GetValue();
+
+ pSetItem = &pStyleSet->Get( ATTR_PAGE_FOOTERSET );
+ pSet = &pSetItem->GetItemSet();
+ rbFooter = pSet->Get(ATTR_PAGE_ON).GetValue();
+}
+
+#if defined(_WIN32)
+bool ScDocShell::DdeGetData( const OUString& rItem,
+ const OUString& rMimeType,
+ css::uno::Any & rValue )
+{
+ SotClipboardFormatId eFormatId = SotExchange::GetFormatIdFromMimeType( rMimeType );
+ if (SotClipboardFormatId::STRING == eFormatId || SotClipboardFormatId::STRING_TSVC == eFormatId)
+ {
+ if( rItem.equalsIgnoreAsciiCase( "Format" ) )
+ {
+ OString aFmtByte(OUStringToOString(m_aDdeTextFmt,
+ osl_getThreadTextEncoding()));
+ rValue <<= css::uno::Sequence< sal_Int8 >(
+ reinterpret_cast<const sal_Int8*>(aFmtByte.getStr()),
+ aFmtByte.getLength() + 1 );
+ return true;
+ }
+ ScImportExport aObj( *m_pDocument, rItem );
+ if ( !aObj.IsRef() )
+ return false; // invalid range
+
+ if( m_aDdeTextFmt[0] == 'F' )
+ aObj.SetFormulas( true );
+ if( m_aDdeTextFmt == "SYLK" ||
+ m_aDdeTextFmt == "FSYLK" )
+ {
+ OString aData;
+ if( aObj.ExportByteString( aData, osl_getThreadTextEncoding(),
+ SotClipboardFormatId::SYLK ) )
+ {
+ rValue <<= css::uno::Sequence< sal_Int8 >(
+ reinterpret_cast<const sal_Int8*>(aData.getStr()),
+ aData.getLength() + 1 );
+ return true;
+ }
+ else
+ return false;
+ }
+ if( m_aDdeTextFmt == "CSV" ||
+ m_aDdeTextFmt == "FCSV" )
+ aObj.SetSeparator( ',' );
+ aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, 0, false ) );
+ return aObj.ExportData( rMimeType, rValue );
+ }
+
+ ScImportExport aObj( *m_pDocument, rItem );
+ aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, 0, false ) );
+ return aObj.IsRef() && aObj.ExportData( rMimeType, rValue );
+}
+
+bool ScDocShell::DdeSetData( const OUString& rItem,
+ const OUString& rMimeType,
+ const css::uno::Any & rValue )
+{
+ SotClipboardFormatId eFormatId = SotExchange::GetFormatIdFromMimeType( rMimeType );
+ if (SotClipboardFormatId::STRING == eFormatId || SotClipboardFormatId::STRING_TSVC == eFormatId)
+ {
+ if( rItem.equalsIgnoreAsciiCase( "Format" ) )
+ {
+ if ( ScByteSequenceToString::GetString( m_aDdeTextFmt, rValue, osl_getThreadTextEncoding() ) )
+ {
+ m_aDdeTextFmt = m_aDdeTextFmt.toAsciiUpperCase();
+ return true;
+ }
+ return false;
+ }
+ ScImportExport aObj( *m_pDocument, rItem );
+ if( m_aDdeTextFmt[0] == 'F' )
+ aObj.SetFormulas( true );
+ if( m_aDdeTextFmt == "SYLK" ||
+ m_aDdeTextFmt == "FSYLK" )
+ {
+ OUString aData;
+ if ( ScByteSequenceToString::GetString( aData, rValue, osl_getThreadTextEncoding() ) )
+ {
+ return aObj.ImportString( aData, SotClipboardFormatId::SYLK );
+ }
+ return false;
+ }
+ if( m_aDdeTextFmt == "CSV" ||
+ m_aDdeTextFmt == "FCSV" )
+ aObj.SetSeparator( ',' );
+ OSL_ENSURE( false, "Implementation is missing" );
+ return false;
+ }
+ /*ScImportExport aObj( aDocument, rItem );
+ return aObj.IsRef() && ScImportExport::ImportData( rMimeType, rValue );*/
+ OSL_ENSURE( false, "Implementation is missing" );
+ return false;
+}
+#endif
+
+::sfx2::SvLinkSource* ScDocShell::DdeCreateLinkSource( const OUString& rItem )
+{
+ // only check for valid item string - range is parsed again in ScServerObject ctor
+
+ // named range?
+ OUString aPos = rItem;
+ ScRangeName* pRange = m_pDocument->GetRangeName();
+ if( pRange )
+ {
+ const ScRangeData* pData = pRange->findByUpperName(ScGlobal::getCharClass().uppercase(aPos));
+ if (pData)
+ {
+ if( pData->HasType( ScRangeData::Type::RefArea )
+ || pData->HasType( ScRangeData::Type::AbsArea )
+ || pData->HasType( ScRangeData::Type::AbsPos ) )
+ aPos = pData->GetSymbol(); // continue with the name's contents
+ }
+ }
+
+ // Address in DDE function must be always parsed as CONV_OOO so that it
+ // would always work regardless of current address conversion. We do this
+ // because the address item in a DDE entry is *not* normalized when saved
+ // into ODF.
+ ScRange aRange;
+ bool bValid = ( (aRange.Parse(aPos, *m_pDocument, formula::FormulaGrammar::CONV_OOO ) & ScRefFlags::VALID) ||
+ (aRange.aStart.Parse(aPos, *m_pDocument, formula::FormulaGrammar::CONV_OOO) & ScRefFlags::VALID) );
+
+ ScServerObject* pObj = nullptr; // NULL = error
+ if ( bValid )
+ pObj = new ScServerObject( this, rItem );
+
+ // GetLinkManager()->InsertServer() is in the ScServerObject ctor
+
+ return pObj;
+}
+
+void ScDocShell::LOKCommentNotify(LOKCommentNotificationType nType, const ScDocument* pDocument, const ScAddress& rPos, const ScPostIt* pNote)
+{
+ if ( !pDocument->IsDocVisible() || // don't want callbacks until document load
+ !comphelper::LibreOfficeKit::isActive() ||
+ comphelper::LibreOfficeKit::isTiledAnnotations() )
+ return;
+
+ boost::property_tree::ptree aAnnotation;
+ aAnnotation.put("action", (nType == LOKCommentNotificationType::Add ? "Add" :
+ (nType == LOKCommentNotificationType::Remove ? "Remove" :
+ (nType == LOKCommentNotificationType::Modify ? "Modify" : "???"))));
+
+ assert(pNote);
+ aAnnotation.put("id", pNote->GetId());
+ aAnnotation.put("tab", rPos.Tab());
+
+ if (nType != LOKCommentNotificationType::Remove)
+ {
+ aAnnotation.put("author", pNote->GetAuthor());
+ aAnnotation.put("dateTime", pNote->GetDate());
+ aAnnotation.put("text", pNote->GetText());
+
+ // Calculating the cell cursor position
+ ScViewData* pViewData = GetViewData();
+ if (pViewData && pViewData->GetActiveWin())
+ {
+ bool bInPrintTwips = comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
+ OString aRectString;
+ if (bInPrintTwips)
+ {
+ Point aTopLeft = pViewData->GetPrintTwipsPos(rPos.Col(), rPos.Row());
+ tools::Long nSizeX, nSizeY;
+ pViewData->GetMergeSizePrintTwips(rPos.Col(), rPos.Row(), nSizeX, nSizeY);
+ aRectString = tools::Rectangle(aTopLeft, Size(nSizeX - 1, nSizeY - 1)).toString();
+ }
+ else
+ {
+ Point aTopLeft = pViewData->GetScrPos(rPos.Col(), rPos.Row(),
+ pViewData->GetActivePart(), true);
+ tools::Long nSizeXPix, nSizeYPix;
+ pViewData->GetMergeSizePixel(rPos.Col(), rPos.Row(), nSizeXPix, nSizeYPix);
+ const double fPPTX = pViewData->GetPPTX();
+ const double fPPTY = pViewData->GetPPTY();
+ aRectString = tools::Rectangle(Point(aTopLeft.getX() / fPPTX, aTopLeft.getY() / fPPTY),
+ Size(nSizeXPix / fPPTX, nSizeYPix / fPPTY)).toString();
+ }
+ aAnnotation.put("cellPos", aRectString);
+ }
+ }
+
+ boost::property_tree::ptree aTree;
+ aTree.add_child("comment", aAnnotation);
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, aTree);
+ std::string aPayload = aStream.str();
+
+ ScViewData* pViewData = GetViewData();
+ SfxViewShell* pThisViewShell = ( pViewData ? pViewData->GetViewShell() : nullptr );
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ if (pThisViewShell == nullptr || pViewShell->GetDocId() == pThisViewShell->GetDocId())
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_COMMENT, aPayload.c_str());
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
+ScViewData* ScDocShell::GetViewData()
+{
+ SfxViewShell* pCur = SfxViewShell::Current();
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( pCur );
+ return pViewSh ? &pViewSh->GetViewData() : nullptr;
+}
+
+SCTAB ScDocShell::GetCurTab()
+{
+ //! this must be made non-static and use a ViewShell from this document!
+
+ ScViewData* pViewData = GetViewData();
+
+ return pViewData ? pViewData->GetTabNo() : static_cast<SCTAB>(0);
+}
+
+ScTabViewShell* ScDocShell::GetBestViewShell( bool bOnlyVisible )
+{
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ // wrong Doc?
+ if( pViewSh && pViewSh->GetViewData().GetDocShell() != this )
+ pViewSh = nullptr;
+ if( !pViewSh )
+ {
+ // 1. find ViewShell
+ SfxViewFrame* pFrame = SfxViewFrame::GetFirst( this, bOnlyVisible );
+ if( pFrame )
+ {
+ SfxViewShell* p = pFrame->GetViewShell();
+ pViewSh = dynamic_cast< ScTabViewShell *>( p );
+ }
+ }
+ return pViewSh;
+}
+
+SfxBindings* ScDocShell::GetViewBindings()
+{
+ // used to invalidate slots after changes to this document
+
+ SfxViewShell* pViewSh = GetBestViewShell();
+ if (pViewSh)
+ return &pViewSh->GetViewFrame()->GetBindings();
+ else
+ return nullptr;
+}
+
+ScDocShell* ScDocShell::GetShellByNum( sal_uInt16 nDocNo ) // static
+{
+ ScDocShell* pFound = nullptr;
+ SfxObjectShell* pShell = SfxObjectShell::GetFirst();
+ sal_uInt16 nShellCnt = 0;
+
+ while ( pShell && !pFound )
+ {
+ if ( auto pDocSh = dynamic_cast<ScDocShell*>(pShell) )
+ {
+ if ( nShellCnt == nDocNo )
+ pFound = pDocSh;
+ else
+ ++nShellCnt;
+ }
+ pShell = SfxObjectShell::GetNext( *pShell );
+ }
+
+ return pFound;
+}
+
+IMPL_LINK( ScDocShell, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void )
+{
+ OSL_ENSURE( _pFileDlg, "ScDocShell::DialogClosedHdl(): no file dialog" );
+ OSL_ENSURE( m_pImpl->pDocInserter, "ScDocShell::DialogClosedHdl(): no document inserter" );
+
+ if ( ERRCODE_NONE == _pFileDlg->GetError() )
+ {
+ sal_uInt16 nSlot = m_pImpl->pRequest->GetSlot();
+ std::unique_ptr<SfxMedium> pMed = m_pImpl->pDocInserter->CreateMedium();
+ // #i87094# If a .odt was selected pMed is NULL.
+ if (pMed)
+ {
+ m_pImpl->pRequest->AppendItem( SfxStringItem( SID_FILE_NAME, pMed->GetName() ) );
+ if ( SID_DOCUMENT_COMPARE == nSlot )
+ {
+ if ( pMed->GetFilter() )
+ m_pImpl->pRequest->AppendItem(
+ SfxStringItem( SID_FILTER_NAME, pMed->GetFilter()->GetFilterName() ) );
+ OUString sOptions = ScDocumentLoader::GetOptions( *pMed );
+ if ( !sOptions.isEmpty() )
+ m_pImpl->pRequest->AppendItem( SfxStringItem( SID_FILE_FILTEROPTIONS, sOptions ) );
+ }
+ const SfxPoolItem* pItem = nullptr;
+ const SfxInt16Item* pInt16Item(nullptr);
+ SfxItemSet* pSet = pMed->GetItemSet();
+ if (pSet && pSet->GetItemState(SID_VERSION, true, &pItem) == SfxItemState::SET)
+ {
+ pInt16Item = dynamic_cast<const SfxInt16Item*>(pItem);
+ }
+ if (pInt16Item)
+ {
+ m_pImpl->pRequest->AppendItem( *pItem );
+ }
+
+ Execute( *(m_pImpl->pRequest) );
+ }
+ }
+
+ m_pImpl->bIgnoreLostRedliningWarning = false;
+}
+
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+
+void ScDocShell::EnableSharedSettings( bool bEnable )
+{
+ SetDocumentModified();
+
+ if ( bEnable )
+ {
+ m_pDocument->EndChangeTracking();
+ m_pDocument->StartChangeTracking();
+
+ // hide accept or reject changes dialog
+ sal_uInt16 nId = ScAcceptChgDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrame = SfxViewFrame::Current();
+ if ( pViewFrame && pViewFrame->HasChildWindow( nId ) )
+ {
+ pViewFrame->ToggleChildWindow( nId );
+ SfxBindings* pBindings = GetViewBindings();
+ if ( pBindings )
+ {
+ pBindings->Invalidate( FID_CHG_ACCEPT );
+ }
+ }
+ }
+ else
+ {
+ m_pDocument->EndChangeTracking();
+ }
+
+ ScChangeViewSettings aChangeViewSet;
+ aChangeViewSet.SetShowChanges( false );
+ m_pDocument->SetChangeViewSettings( aChangeViewSet );
+}
+
+uno::Reference< frame::XModel > ScDocShell::LoadSharedDocument()
+{
+ uno::Reference< frame::XModel > xModel;
+ try
+ {
+ SC_MOD()->SetInSharedDocLoading( true );
+ uno::Reference< frame::XDesktop2 > xLoader = frame::Desktop::create( ::comphelper::getProcessComponentContext() );
+ uno::Sequence aArgs{ comphelper::makePropertyValue("Hidden", true) };
+
+ if ( GetMedium() )
+ {
+ const SfxStringItem* pPasswordItem = SfxItemSet::GetItem<SfxStringItem>(GetMedium()->GetItemSet(), SID_PASSWORD, false);
+ if ( pPasswordItem && !pPasswordItem->GetValue().isEmpty() )
+ {
+ aArgs.realloc( 2 );
+ auto pArgs = aArgs.getArray();
+ pArgs[1].Name = "Password";
+ pArgs[1].Value <<= pPasswordItem->GetValue();
+ }
+ const SfxUnoAnyItem* pEncryptionItem = SfxItemSet::GetItem<SfxUnoAnyItem>(GetMedium()->GetItemSet(), SID_ENCRYPTIONDATA, false);
+ if (pEncryptionItem)
+ {
+ aArgs.realloc(aArgs.getLength() + 1);
+ auto pArgs = aArgs.getArray();
+ pArgs[aArgs.getLength() - 1].Name = "EncryptionData";
+ pArgs[aArgs.getLength() - 1].Value = pEncryptionItem->GetValue();
+ }
+ }
+
+ xModel.set(
+ xLoader->loadComponentFromURL( GetSharedFileURL(), "_blank", 0, aArgs ),
+ uno::UNO_QUERY_THROW );
+ SC_MOD()->SetInSharedDocLoading( false );
+ }
+ catch ( uno::Exception& )
+ {
+ OSL_FAIL( "ScDocShell::LoadSharedDocument(): caught exception" );
+ SC_MOD()->SetInSharedDocLoading( false );
+ try
+ {
+ uno::Reference< util::XCloseable > xClose( xModel, uno::UNO_QUERY_THROW );
+ xClose->close( true );
+ return uno::Reference< frame::XModel >();
+ }
+ catch ( uno::Exception& )
+ {
+ return uno::Reference< frame::XModel >();
+ }
+ }
+ return xModel;
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docsh5.cxx b/sc/source/ui/docshell/docsh5.cxx
new file mode 100644
index 000000000..d1749fee1
--- /dev/null
+++ b/sc/source/ui/docshell/docsh5.cxx
@@ -0,0 +1,1037 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <sal/config.h>
+
+#include <cassert>
+
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <unotools/charclass.hxx>
+
+#include <com/sun/star/script/vba/XVBACompatibility.hpp>
+
+#include <docsh.hxx>
+#include <global.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <globalnames.hxx>
+#include <undodat.hxx>
+#include <undotab.hxx>
+#include <undoblk.hxx>
+#include <dpobject.hxx>
+#include <dpshttab.hxx>
+#include <dbdocfun.hxx>
+#include <consoli.hxx>
+#include <dbdata.hxx>
+#include <progress.hxx>
+#include <olinetab.hxx>
+#include <patattr.hxx>
+#include <attrib.hxx>
+#include <docpool.hxx>
+#include <uiitems.hxx>
+#include <sc.hrc>
+#include <sizedev.hxx>
+#include <clipparam.hxx>
+#include <rowheightcontext.hxx>
+#include <refupdatecontext.hxx>
+
+using com::sun::star::script::XLibraryContainer;
+using com::sun::star::script::vba::XVBACompatibility;
+using com::sun::star::container::XNameContainer;
+using com::sun::star::uno::Reference;
+using com::sun::star::uno::UNO_QUERY;
+
+using ::std::unique_ptr;
+using ::std::vector;
+
+// former viewfunc/dbfunc methods
+
+void ScDocShell::ErrorMessage(TranslateId pGlobStrId)
+{
+ //! StopMarking at the (active) view?
+
+ weld::Window* pParent = GetActiveDialogParent();
+ weld::WaitObject aWaitOff( pParent );
+ bool bFocus = pParent && pParent->has_focus();
+
+ if (pGlobStrId && pGlobStrId == STR_PROTECTIONERR)
+ {
+ if (IsReadOnly())
+ {
+ pGlobStrId = STR_READONLYERR;
+ }
+ }
+
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(pGlobStrId)));
+ xInfoBox->run();
+
+ if (bFocus)
+ pParent->grab_focus();
+}
+
+bool ScDocShell::IsEditable() const
+{
+ // import into read-only document is possible - must be extended if other filters use api
+ // #i108547# MSOOXML filter uses "IsChangeReadOnlyEnabled" property
+
+ return !IsReadOnly() || m_pDocument->IsImportingXML() || m_pDocument->IsChangeReadOnlyEnabled();
+}
+
+void ScDocShell::DBAreaDeleted( SCTAB nTab, SCCOL nX1, SCROW nY1, SCCOL nX2 )
+{
+ ScDocShellModificator aModificator( *this );
+ // the auto-filter is in the first row of the area
+ m_pDocument->RemoveFlagsTab( nX1, nY1, nX2, nY1, nTab, ScMF::Auto );
+ PostPaint( nX1, nY1, nTab, nX2, nY1, nTab, PaintPartFlags::Grid );
+ // No SetDocumentModified, as the unnamed database range might have to be restored later.
+ // The UNO hint is broadcast directly instead, to keep UNO objects in valid state.
+ m_pDocument->BroadcastUno( SfxHint( SfxHintId::DataChanged ) );
+}
+
+ScDBData* ScDocShell::GetDBData( const ScRange& rMarked, ScGetDBMode eMode, ScGetDBSelection eSel )
+{
+ SCCOL nCol = rMarked.aStart.Col();
+ SCROW nRow = rMarked.aStart.Row();
+ SCTAB nTab = rMarked.aStart.Tab();
+
+ SCCOL nStartCol = nCol;
+ SCROW nStartRow = nRow;
+ SCTAB nStartTab = nTab;
+ SCCOL nEndCol = rMarked.aEnd.Col();
+ SCROW nEndRow = rMarked.aEnd.Row();
+ // Not simply GetDBAtCursor: The continuous data range for "unnamed" (GetDataArea) may be
+ // located next to the cursor; so a named DB range needs to be searched for there as well.
+ ScDBCollection* pColl = m_pDocument->GetDBCollection();
+ ScDBData* pData = m_pDocument->GetDBAtArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
+ if (!pData)
+ pData = pColl->GetDBNearCursor(nCol, nRow, nTab );
+
+ bool bSelected = ( eSel == ScGetDBSelection::ForceMark ||
+ (rMarked.aStart != rMarked.aEnd && eSel != ScGetDBSelection::RowDown) );
+ bool bOnlyDown = (!bSelected && eSel == ScGetDBSelection::RowDown && rMarked.aStart.Row() == rMarked.aEnd.Row());
+
+ bool bUseThis = false;
+ if (pData)
+ {
+ // take range, if nothing else is marked
+
+ SCTAB nDummy;
+ SCCOL nOldCol1;
+ SCROW nOldRow1;
+ SCCOL nOldCol2;
+ SCROW nOldRow2;
+ pData->GetArea( nDummy, nOldCol1,nOldRow1, nOldCol2,nOldRow2 );
+ bool bIsNoName = ( pData->GetName() == STR_DB_LOCAL_NONAME );
+
+ if (!bSelected)
+ {
+ bUseThis = true;
+ if ( bIsNoName && (eMode == SC_DB_MAKE || eMode == SC_DB_AUTOFILTER) )
+ {
+ // If nothing marked or only one row marked, adapt
+ // "unnamed" to contiguous area.
+ nStartCol = nCol;
+ nStartRow = nRow;
+ if (bOnlyDown)
+ {
+ nEndCol = rMarked.aEnd.Col();
+ nEndRow = rMarked.aEnd.Row();
+ }
+ else
+ {
+ nEndCol = nStartCol;
+ nEndRow = nStartRow;
+ }
+ m_pDocument->GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, bOnlyDown );
+ if ( nOldCol1 != nStartCol || nOldCol2 != nEndCol || nOldRow1 != nStartRow )
+ bUseThis = false; // doesn't fit at all
+ else if ( nOldRow2 != nEndRow )
+ {
+ // extend range to new end row
+ pData->SetArea( nTab, nOldCol1,nOldRow1, nOldCol2,nEndRow );
+ }
+ }
+ }
+ else
+ {
+ if ( nOldCol1 == nStartCol && nOldRow1 == nStartRow &&
+ nOldCol2 == nEndCol && nOldRow2 == nEndRow ) // marked precisely?
+ bUseThis = true;
+ else
+ bUseThis = false; // always take marking (Bug 11964)
+ }
+
+ // never take "unnamed" for import
+
+ if ( bUseThis && eMode == SC_DB_IMPORT && bIsNoName )
+ bUseThis = false;
+ }
+
+ if ( bUseThis )
+ {
+ pData->GetArea( nStartTab, nStartCol,nStartRow, nEndCol,nEndRow );
+ }
+ else if ( eMode == SC_DB_OLD )
+ {
+ pData = nullptr; // nothing found
+ }
+ else
+ {
+ if ( !bSelected )
+ { // continuous range
+ nStartCol = nCol;
+ nStartRow = nRow;
+ if (bOnlyDown)
+ {
+ nEndCol = rMarked.aEnd.Col();
+ nEndRow = rMarked.aEnd.Row();
+ }
+ else
+ {
+ nEndCol = nStartCol;
+ nEndRow = nStartRow;
+ }
+ m_pDocument->GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, bOnlyDown );
+ }
+
+ bool bHasHeader = m_pDocument->HasColHeader( nStartCol,nStartRow, nEndCol,nEndRow, nTab );
+
+ ScDBData* pNoNameData = m_pDocument->GetAnonymousDBData(nTab);
+ if ( eMode != SC_DB_IMPORT && pNoNameData)
+ {
+ // Do not reset AutoFilter range during temporary operations on
+ // other ranges, use the document global temporary anonymous range
+ // instead. But, if AutoFilter is to be toggled then do use the
+ // sheet-local DB range.
+ bool bSheetLocal = true;
+ if (eMode != SC_DB_AUTOFILTER && pNoNameData->HasAutoFilter())
+ {
+ bSheetLocal = false;
+ pNoNameData = m_pDocument->GetAnonymousDBData();
+ if (!pNoNameData)
+ {
+ m_pDocument->SetAnonymousDBData( std::unique_ptr<ScDBData>(new ScDBData( STR_DB_LOCAL_NONAME,
+ nTab, nStartCol, nStartRow, nEndCol, nEndRow, true, bHasHeader) ) );
+ pNoNameData = m_pDocument->GetAnonymousDBData();
+ }
+ // ScDocShell::CancelAutoDBRange() would restore the
+ // sheet-local anonymous DBData from pOldAutoDBRange, unset so
+ // that won't happen with data of a previous sheet-local
+ // DBData.
+ m_pOldAutoDBRange.reset();
+ }
+ else if (!m_pOldAutoDBRange)
+ {
+ // store the old unnamed database range with its settings for undo
+ // (store at the first change, get the state before all changes)
+ m_pOldAutoDBRange.reset( new ScDBData( *pNoNameData ) );
+ }
+ else if (m_pOldAutoDBRange->GetTab() != pNoNameData->GetTab())
+ {
+ // Different sheet-local unnamed DB range than the previous one.
+ *m_pOldAutoDBRange = *pNoNameData;
+ }
+
+ SCCOL nOldX1; // take old range away cleanly
+ SCROW nOldY1; //! (UNDO ???)
+ SCCOL nOldX2;
+ SCROW nOldY2;
+ SCTAB nOldTab;
+ pNoNameData->GetArea( nOldTab, nOldX1, nOldY1, nOldX2, nOldY2 );
+
+ // If previously bHasHeader was set and the new range starts on the
+ // same row and intersects the old column range, then don't reset
+ // bHasHeader but assume that the new range still has headers, just
+ // some are empty or numeric.
+ if (!bHasHeader && pNoNameData->HasHeader() && nTab == nOldTab && nStartRow == nOldY1 &&
+ nStartCol <= nOldY2 && nOldY1 <= nEndCol)
+ bHasHeader = true;
+
+ // Remove AutoFilter button flags only for sheet-local DB range,
+ // not if a temporary is used.
+ if (bSheetLocal)
+ DBAreaDeleted( nOldTab, nOldX1, nOldY1, nOldX2 );
+
+ pNoNameData->SetSortParam( ScSortParam() ); // reset parameter
+ pNoNameData->SetQueryParam( ScQueryParam() );
+ pNoNameData->SetSubTotalParam( ScSubTotalParam() );
+
+ pNoNameData->SetArea( nTab, nStartCol,nStartRow, nEndCol,nEndRow ); // set anew
+ pNoNameData->SetByRow( true );
+ pNoNameData->SetHeader( bHasHeader );
+ pNoNameData->SetAutoFilter( false );
+ }
+ else
+ {
+ std::unique_ptr<ScDBCollection> pUndoColl;
+
+ if (eMode==SC_DB_IMPORT)
+ {
+ m_pDocument->PreprocessDBDataUpdate();
+ pUndoColl.reset( new ScDBCollection( *pColl ) ); // Undo for import range
+
+ OUString aImport = ScResId( STR_DBNAME_IMPORT );
+ tools::Long nCount = 0;
+ const ScDBData* pDummy = nullptr;
+ ScDBCollection::NamedDBs& rDBs = pColl->getNamedDBs();
+ OUString aNewName;
+ do
+ {
+ ++nCount;
+ aNewName = aImport + OUString::number( nCount );
+ pDummy = rDBs.findByUpperName(ScGlobal::getCharClass().uppercase(aNewName));
+ }
+ while (pDummy);
+ pNoNameData = new ScDBData( aNewName, nTab,
+ nStartCol,nStartRow, nEndCol,nEndRow,
+ true, bHasHeader );
+ bool ins = rDBs.insert(std::unique_ptr<ScDBData>(pNoNameData));
+ assert(ins); (void)ins;
+ }
+ else
+ {
+ pNoNameData = new ScDBData(STR_DB_LOCAL_NONAME, nTab,
+ nStartCol,nStartRow, nEndCol,nEndRow,
+ true, bHasHeader );
+ m_pDocument->SetAnonymousDBData(nTab, std::unique_ptr<ScDBData>(pNoNameData));
+ }
+
+ if ( pUndoColl )
+ {
+ m_pDocument->CompileHybridFormula();
+
+ GetUndoManager()->AddUndoAction( std::make_unique<ScUndoDBData>( this,
+ std::move(pUndoColl),
+ std::make_unique<ScDBCollection>( *pColl ) ) );
+ }
+
+ // no longer needed to register new range at the Sba
+
+ // announce "Import1", etc., at the Navigator
+ if (eMode==SC_DB_IMPORT)
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+ }
+ pData = pNoNameData;
+ }
+
+ return pData;
+}
+
+ScDBData* ScDocShell::GetAnonymousDBData(const ScRange& rRange)
+{
+ ScDBCollection* pColl = m_pDocument->GetDBCollection();
+ if (!pColl)
+ return nullptr;
+
+ ScDBData* pData = pColl->getAnonDBs().getByRange(rRange);
+ if (!pData)
+ return nullptr;
+
+ if (!pData->HasHeader())
+ {
+ bool bHasHeader = m_pDocument->HasColHeader(
+ rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aStart.Tab());
+ pData->SetHeader(bHasHeader);
+ }
+
+ return pData;
+}
+
+std::unique_ptr<ScDBData> ScDocShell::GetOldAutoDBRange()
+{
+ return std::move(m_pOldAutoDBRange);
+}
+
+void ScDocShell::CancelAutoDBRange()
+{
+ // called when dialog is cancelled
+//moggi:TODO
+ if ( !m_pOldAutoDBRange )
+ return;
+
+ SCTAB nTab = GetCurTab();
+ ScDBData* pDBData = m_pDocument->GetAnonymousDBData(nTab);
+ if ( pDBData )
+ {
+ SCCOL nRangeX1;
+ SCROW nRangeY1;
+ SCCOL nRangeX2;
+ SCROW nRangeY2;
+ SCTAB nRangeTab;
+ pDBData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
+ DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2 );
+
+ *pDBData = *m_pOldAutoDBRange; // restore old settings
+
+ if ( m_pOldAutoDBRange->HasAutoFilter() )
+ {
+ // restore AutoFilter buttons
+ m_pOldAutoDBRange->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
+ m_pDocument->ApplyFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, ScMF::Auto );
+ PostPaint( nRangeX1, nRangeY1, nRangeTab, nRangeX2, nRangeY1, nRangeTab, PaintPartFlags::Grid );
+ }
+ }
+
+ m_pOldAutoDBRange.reset();
+}
+
+ // adjust height
+ //! merge with docfunc
+
+bool ScDocShell::AdjustRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab )
+{
+ ScSizeDeviceProvider aProv(this);
+ Fraction aZoom(1,1);
+ sc::RowHeightContext aCxt(m_pDocument->MaxRow(), aProv.GetPPTX(), aProv.GetPPTY(), aZoom, aZoom, aProv.GetDevice());
+ bool bChange = m_pDocument->SetOptimalHeight(aCxt, nStartRow,nEndRow, nTab, true);
+
+ if (bChange)
+ {
+ // tdf#76183: recalculate objects' positions
+ m_pDocument->SetDrawPageSize(nTab);
+
+ PostPaint( 0,nStartRow,nTab, m_pDocument->MaxCol(),m_pDocument->MaxRow(),nTab, PaintPartFlags::Grid|PaintPartFlags::Left );
+ }
+
+ return bChange;
+}
+
+void ScDocShell::UpdateAllRowHeights( const ScMarkData* pTabMark )
+{
+ // update automatic row heights
+
+ ScSizeDeviceProvider aProv(this);
+ Fraction aZoom(1,1);
+ sc::RowHeightContext aCxt(m_pDocument->MaxRow(), aProv.GetPPTX(), aProv.GetPPTY(), aZoom, aZoom, aProv.GetDevice());
+ m_pDocument->UpdateAllRowHeights(aCxt, pTabMark);
+}
+
+void ScDocShell::UpdatePendingRowHeights( SCTAB nUpdateTab, bool bBefore )
+{
+ bool bIsUndoEnabled = m_pDocument->IsUndoEnabled();
+ m_pDocument->EnableUndo( false );
+ m_pDocument->LockStreamValid( true ); // ignore draw page size (but not formula results)
+ if ( bBefore ) // check all sheets up to nUpdateTab
+ {
+ SCTAB nTabCount = m_pDocument->GetTableCount();
+ if ( nUpdateTab >= nTabCount )
+ nUpdateTab = nTabCount-1; // nUpdateTab is inclusive
+
+ ScMarkData aUpdateSheets(m_pDocument->GetSheetLimits());
+ SCTAB nTab;
+ for (nTab=0; nTab<=nUpdateTab; ++nTab)
+ if ( m_pDocument->IsPendingRowHeights( nTab ) )
+ aUpdateSheets.SelectTable( nTab, true );
+
+ if (aUpdateSheets.GetSelectCount())
+ UpdateAllRowHeights(&aUpdateSheets); // update with a single progress bar
+
+ for (nTab=0; nTab<=nUpdateTab; ++nTab)
+ if ( aUpdateSheets.GetTableSelect( nTab ) )
+ {
+ m_pDocument->UpdatePageBreaks( nTab );
+ m_pDocument->SetPendingRowHeights( nTab, false );
+ }
+ }
+ else // only nUpdateTab
+ {
+ if ( m_pDocument->IsPendingRowHeights( nUpdateTab ) )
+ {
+ AdjustRowHeight( 0, m_pDocument->MaxRow(), nUpdateTab );
+ m_pDocument->UpdatePageBreaks( nUpdateTab );
+ m_pDocument->SetPendingRowHeights( nUpdateTab, false );
+ }
+ }
+ m_pDocument->LockStreamValid( false );
+ m_pDocument->EnableUndo( bIsUndoEnabled );
+}
+
+void ScDocShell::RefreshPivotTables( const ScRange& rSource )
+{
+ ScDPCollection* pColl = m_pDocument->GetDPCollection();
+ if (!pColl)
+ return;
+
+ ScDBDocFunc aFunc(*this);
+ for (size_t i = 0, n = pColl->GetCount(); i < n; ++i)
+ {
+ ScDPObject& rOld = (*pColl)[i];
+
+ const ScSheetSourceDesc* pSheetDesc = rOld.GetSheetDesc();
+ if (pSheetDesc && pSheetDesc->GetSourceRange().Intersects(rSource))
+ aFunc.UpdatePivotTable(rOld, true, false);
+ }
+}
+
+static OUString lcl_GetAreaName( ScDocument* pDoc, const ScArea* pArea )
+{
+ ScDBData* pData = pDoc->GetDBAtArea( pArea->nTab, pArea->nColStart, pArea->nRowStart,
+ pArea->nColEnd, pArea->nRowEnd );
+ if (pData)
+ return pData->GetName();
+
+ OUString aName;
+ pDoc->GetName( pArea->nTab, aName );
+ return aName;
+}
+
+void ScDocShell::DoConsolidate( const ScConsolidateParam& rParam, bool bRecord )
+{
+ ScConsData aData;
+
+ sal_uInt16 nPos;
+ SCCOL nColSize = 0;
+ SCROW nRowSize = 0;
+ bool bErr = false;
+ for (nPos=0; nPos<rParam.nDataAreaCount; nPos++)
+ {
+ ScArea const & rArea = rParam.pDataAreas[nPos];
+ nColSize = std::max( nColSize, SCCOL( rArea.nColEnd - rArea.nColStart + 1 ) );
+ nRowSize = std::max( nRowSize, SCROW( rArea.nRowEnd - rArea.nRowStart + 1 ) );
+
+ // test if source data were moved
+ if (rParam.bReferenceData)
+ if (rArea.nTab == rParam.nTab && rArea.nRowEnd >= rParam.nRow)
+ bErr = true;
+ }
+
+ if (bErr)
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_CONSOLIDATE_ERR1)));
+ xInfoBox->run();
+ return;
+ }
+
+ // execute
+
+ weld::WaitObject aWait( GetActiveDialogParent() );
+ ScDocShellModificator aModificator( *this );
+
+ ScRange aOldDest;
+ ScDBData* pDestData = m_pDocument->GetDBAtCursor( rParam.nCol, rParam.nRow, rParam.nTab, ScDBDataPortion::TOP_LEFT );
+ if (pDestData)
+ pDestData->GetArea(aOldDest);
+
+ aData.SetSize( nColSize, nRowSize );
+ aData.SetFlags( rParam.eFunction, rParam.bByCol, rParam.bByRow, rParam.bReferenceData );
+ if ( rParam.bByCol || rParam.bByRow )
+ for (nPos=0; nPos<rParam.nDataAreaCount; nPos++)
+ {
+ ScArea const & rArea = rParam.pDataAreas[nPos];
+ aData.AddFields( m_pDocument.get(), rArea.nTab, rArea.nColStart, rArea.nRowStart,
+ rArea.nColEnd, rArea.nRowEnd );
+ }
+ aData.DoneFields();
+ for (nPos=0; nPos<rParam.nDataAreaCount; nPos++)
+ {
+ ScArea const & rArea = rParam.pDataAreas[nPos];
+ aData.AddData( m_pDocument.get(), rArea.nTab, rArea.nColStart, rArea.nRowStart,
+ rArea.nColEnd, rArea.nRowEnd );
+ aData.AddName( lcl_GetAreaName(m_pDocument.get(), &rArea) );
+ }
+
+ aData.GetSize( nColSize, nRowSize );
+ if (bRecord && nColSize > 0 && nRowSize > 0)
+ {
+ std::unique_ptr<ScDBData> pUndoData(pDestData ? new ScDBData(*pDestData) : nullptr);
+
+ SCTAB nDestTab = rParam.nTab;
+ ScArea aDestArea( rParam.nTab, rParam.nCol, rParam.nRow,
+ rParam.nCol+nColSize-1, rParam.nRow+nRowSize-1 );
+ if (rParam.bByCol) ++aDestArea.nColEnd;
+ if (rParam.bByRow) ++aDestArea.nRowEnd;
+
+ if (rParam.bReferenceData)
+ {
+ SCTAB nTabCount = m_pDocument->GetTableCount();
+ SCROW nInsertCount = aData.GetInsertCount();
+
+ // old outlines
+ ScOutlineTable* pTable = m_pDocument->GetOutlineTable( nDestTab );
+ std::unique_ptr<ScOutlineTable> pUndoTab(pTable ? new ScOutlineTable( *pTable ) : nullptr);
+
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( *m_pDocument, 0, nTabCount-1, false, true );
+
+ // row state
+ m_pDocument->CopyToDocument(0, 0, nDestTab, m_pDocument->MaxCol(), m_pDocument->MaxRow(), nDestTab,
+ InsertDeleteFlags::NONE, false, *pUndoDoc);
+
+ // all formulas
+ m_pDocument->CopyToDocument(0, 0, 0, m_pDocument->MaxCol(), m_pDocument->MaxRow(), nTabCount-1,
+ InsertDeleteFlags::FORMULA, false, *pUndoDoc);
+
+ // complete output rows
+ m_pDocument->CopyToDocument(0, aDestArea.nRowStart, nDestTab,
+ m_pDocument->MaxCol(),aDestArea.nRowEnd, nDestTab,
+ InsertDeleteFlags::ALL, false, *pUndoDoc);
+
+ // old output range
+ if (pDestData)
+ m_pDocument->CopyToDocument(aOldDest, InsertDeleteFlags::ALL, false, *pUndoDoc);
+
+ GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoConsolidate>( this, aDestArea, rParam, std::move(pUndoDoc),
+ true, nInsertCount, std::move(pUndoTab), std::move(pUndoData) ) );
+ }
+ else
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( *m_pDocument, aDestArea.nTab, aDestArea.nTab );
+
+ m_pDocument->CopyToDocument(aDestArea.nColStart, aDestArea.nRowStart, aDestArea.nTab,
+ aDestArea.nColEnd, aDestArea.nRowEnd, aDestArea.nTab,
+ InsertDeleteFlags::ALL, false, *pUndoDoc);
+
+ // old output range
+ if (pDestData)
+ m_pDocument->CopyToDocument(aOldDest, InsertDeleteFlags::ALL, false, *pUndoDoc);
+
+ GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoConsolidate>( this, aDestArea, rParam, std::move(pUndoDoc),
+ false, 0, nullptr, std::move(pUndoData) ) );
+ }
+ }
+
+ if (pDestData) // delete / adjust destination range
+ {
+ m_pDocument->DeleteAreaTab(aOldDest, InsertDeleteFlags::CONTENTS);
+ pDestData->SetArea( rParam.nTab, rParam.nCol, rParam.nRow,
+ rParam.nCol + nColSize - 1, rParam.nRow + nRowSize - 1 );
+ pDestData->SetHeader( rParam.bByRow );
+ }
+
+ aData.OutputToDocument( *m_pDocument, rParam.nCol, rParam.nRow, rParam.nTab );
+
+ SCCOL nPaintStartCol = rParam.nCol;
+ SCROW nPaintStartRow = rParam.nRow;
+ SCCOL nPaintEndCol = nPaintStartCol + nColSize - 1;
+ SCROW nPaintEndRow = nPaintStartRow + nRowSize - 1;
+ PaintPartFlags nPaintFlags = PaintPartFlags::Grid;
+ if (rParam.bByCol)
+ ++nPaintEndRow;
+ if (rParam.bByRow)
+ ++nPaintEndCol;
+ if (rParam.bReferenceData)
+ {
+ nPaintStartCol = 0;
+ nPaintEndCol = m_pDocument->MaxCol();
+ nPaintEndRow = m_pDocument->MaxRow();
+ nPaintFlags |= PaintPartFlags::Left | PaintPartFlags::Size;
+ }
+ if (pDestData)
+ {
+ if ( aOldDest.aEnd.Col() > nPaintEndCol )
+ nPaintEndCol = aOldDest.aEnd.Col();
+ if ( aOldDest.aEnd.Row() > nPaintEndRow )
+ nPaintEndRow = aOldDest.aEnd.Row();
+ }
+ PostPaint( nPaintStartCol, nPaintStartRow, rParam.nTab,
+ nPaintEndCol, nPaintEndRow, rParam.nTab, nPaintFlags );
+ aModificator.SetDocumentModified();
+}
+
+void ScDocShell::UseScenario( SCTAB nTab, const OUString& rName, bool bRecord )
+{
+ if (!m_pDocument->IsScenario(nTab))
+ {
+ SCTAB nTabCount = m_pDocument->GetTableCount();
+ SCTAB nSrcTab = SCTAB_MAX;
+ SCTAB nEndTab = nTab;
+ OUString aCompare;
+ while ( nEndTab+1 < nTabCount && m_pDocument->IsScenario(nEndTab+1) )
+ {
+ ++nEndTab;
+ if (nSrcTab > MAXTAB) // still searching for the scenario?
+ {
+ m_pDocument->GetName( nEndTab, aCompare );
+ if (aCompare == rName)
+ nSrcTab = nEndTab; // found
+ }
+ }
+ if (ValidTab(nSrcTab))
+ {
+ if ( m_pDocument->TestCopyScenario( nSrcTab, nTab ) ) // test cell protection
+ {
+ ScDocShellModificator aModificator( *this );
+ ScMarkData aScenMark(m_pDocument->GetSheetLimits());
+ m_pDocument->MarkScenario( nSrcTab, nTab, aScenMark );
+ const ScRange& aMultiRange = aScenMark.GetMultiMarkArea();
+ SCCOL nStartCol = aMultiRange.aStart.Col();
+ SCROW nStartRow = aMultiRange.aStart.Row();
+ SCCOL nEndCol = aMultiRange.aEnd.Col();
+ SCROW nEndRow = aMultiRange.aEnd.Row();
+
+ if (bRecord)
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( *m_pDocument, nTab,nEndTab ); // also all scenarios
+ // shown table:
+ m_pDocument->CopyToDocument(nStartCol, nStartRow, nTab,
+ nEndCol, nEndRow, nTab, InsertDeleteFlags::ALL,
+ true, *pUndoDoc, &aScenMark);
+ // scenarios
+ for (SCTAB i=nTab+1; i<=nEndTab; i++)
+ {
+ pUndoDoc->SetScenario( i, true );
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ m_pDocument->GetScenarioData( i, aComment, aColor, nScenFlags );
+ pUndoDoc->SetScenarioData( i, aComment, aColor, nScenFlags );
+ bool bActive = m_pDocument->IsActiveScenario( i );
+ pUndoDoc->SetActiveScenario( i, bActive );
+ // At copy-back scenarios also contents
+ if ( nScenFlags & ScScenarioFlags::TwoWay )
+ m_pDocument->CopyToDocument(0, 0, i, m_pDocument->MaxCol(), m_pDocument->MaxRow(), i,
+ InsertDeleteFlags::ALL, false, *pUndoDoc );
+ }
+
+ GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoUseScenario>( this, aScenMark,
+ ScArea( nTab,nStartCol,nStartRow,nEndCol,nEndRow ),
+ std::move(pUndoDoc), rName ) );
+ }
+
+ m_pDocument->CopyScenario( nSrcTab, nTab );
+
+ sc::SetFormulaDirtyContext aCxt;
+ m_pDocument->SetAllFormulasDirty(aCxt);
+
+ // paint all, because the active scenario may be modified in other ranges;
+ //! only if there are visible frames?
+ PostPaint( 0,0,nTab, m_pDocument->MaxCol(),m_pDocument->MaxRow(),nTab, PaintPartFlags::Grid );
+ aModificator.SetDocumentModified();
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_PROTECTIONERR)));
+ xInfoBox->run();
+ }
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetActiveDialogParent(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_SCENARIO_NOTFOUND)));
+ xInfoBox->run();
+ }
+ }
+ else
+ {
+ OSL_FAIL( "UseScenario on Scenario-Sheet" );
+ }
+}
+
+void ScDocShell::ModifyScenario( SCTAB nTab, const OUString& rName, const OUString& rComment,
+ const Color& rColor, ScScenarioFlags nFlags )
+{
+ // Undo
+ OUString aOldName;
+ m_pDocument->GetName( nTab, aOldName );
+ OUString aOldComment;
+ Color aOldColor;
+ ScScenarioFlags nOldFlags;
+ m_pDocument->GetScenarioData( nTab, aOldComment, aOldColor, nOldFlags );
+ GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoScenarioFlags>(this, nTab,
+ aOldName, rName, aOldComment, rComment,
+ aOldColor, rColor, nOldFlags, nFlags) );
+
+ // execute
+ ScDocShellModificator aModificator( *this );
+ m_pDocument->RenameTab( nTab, rName );
+ m_pDocument->SetScenarioData( nTab, rComment, rColor, nFlags );
+ PostPaintGridAll();
+ aModificator.SetDocumentModified();
+
+ if (aOldName != rName)
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+
+ SfxBindings* pBindings = GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_SELECT_SCENARIO );
+}
+
+SCTAB ScDocShell::MakeScenario( SCTAB nTab, const OUString& rName, const OUString& rComment,
+ const Color& rColor, ScScenarioFlags nFlags,
+ ScMarkData& rMark, bool bRecord )
+{
+ rMark.MarkToMulti();
+ if (rMark.IsMultiMarked())
+ {
+ SCTAB nNewTab = nTab + 1;
+ while (m_pDocument->IsScenario(nNewTab))
+ ++nNewTab;
+
+ bool bCopyAll = ( (nFlags & ScScenarioFlags::CopyAll) != ScScenarioFlags::NONE );
+ const ScMarkData* pCopyMark = nullptr;
+ if (!bCopyAll)
+ pCopyMark = &rMark;
+
+ ScDocShellModificator aModificator( *this );
+
+ if (bRecord)
+ m_pDocument->BeginDrawUndo(); // drawing layer must do its own undo actions
+
+ if (m_pDocument->CopyTab( nTab, nNewTab, pCopyMark ))
+ {
+ if (bRecord)
+ {
+ GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoMakeScenario>( this, nTab, nNewTab,
+ rName, rComment, rColor, nFlags, rMark ));
+ }
+
+ m_pDocument->RenameTab( nNewTab, rName);
+ m_pDocument->SetScenario( nNewTab, true );
+ m_pDocument->SetScenarioData( nNewTab, rComment, rColor, nFlags );
+
+ ScMarkData aDestMark = rMark;
+ aDestMark.SelectOneTable( nNewTab );
+
+ //! test for filter / buttons / merging
+
+ ScPatternAttr aProtPattern( m_pDocument->GetPool() );
+ aProtPattern.GetItemSet().Put( ScProtectionAttr( true ) );
+ m_pDocument->ApplyPatternAreaTab( 0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(), nNewTab, aProtPattern );
+
+ ScPatternAttr aPattern( m_pDocument->GetPool() );
+ aPattern.GetItemSet().Put( ScMergeFlagAttr( ScMF::Scenario ) );
+ aPattern.GetItemSet().Put( ScProtectionAttr( true ) );
+ m_pDocument->ApplySelectionPattern( aPattern, aDestMark );
+
+ if (!bCopyAll)
+ m_pDocument->SetVisible( nNewTab, false );
+
+ // this is the active scenario, then
+ m_pDocument->CopyScenario( nNewTab, nTab, true ); // sal_True - don't copy anything from scenario
+
+ if (nFlags & ScScenarioFlags::ShowFrame)
+ PostPaint( 0,0,nTab, m_pDocument->MaxCol(),m_pDocument->MaxRow(),nTab, PaintPartFlags::Grid ); // paint frames
+ PostPaintExtras(); // table tab
+ aModificator.SetDocumentModified();
+
+ // A scenario tab is like a hidden sheet, broadcasting also
+ // notifies ScTabViewShell to add an ScViewData::maTabData entry.
+ Broadcast( ScTablesHint( SC_TAB_INSERTED, nNewTab ));
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+
+ return nNewTab;
+ }
+ }
+ return nTab;
+}
+
+sal_uLong ScDocShell::TransferTab( ScDocShell& rSrcDocShell, SCTAB nSrcPos,
+ SCTAB nDestPos, bool bInsertNew,
+ bool bNotifyAndPaint )
+{
+ ScDocument& rSrcDoc = rSrcDocShell.GetDocument();
+
+ // set the transferred area to the copyparam to make adjusting formulas possible
+ ScClipParam aParam;
+ ScRange aRange(0, 0, nSrcPos, m_pDocument->MaxCol(), m_pDocument->MaxRow(), nSrcPos);
+ aParam.maRanges.push_back(aRange);
+ rSrcDoc.SetClipParam(aParam);
+
+ sal_uLong nErrVal = m_pDocument->TransferTab( rSrcDoc, nSrcPos, nDestPos,
+ bInsertNew ); // no insert
+
+ // TransferTab doesn't copy drawing objects with bInsertNew=FALSE
+ if ( nErrVal > 0 && !bInsertNew)
+ m_pDocument->TransferDrawPage( rSrcDoc, nSrcPos, nDestPos );
+
+ if(nErrVal>0 && rSrcDoc.IsScenario( nSrcPos ))
+ {
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+
+ rSrcDoc.GetScenarioData( nSrcPos, aComment,aColor, nFlags);
+ m_pDocument->SetScenario(nDestPos,true);
+ m_pDocument->SetScenarioData(nDestPos,aComment,aColor,nFlags);
+ bool bActive = rSrcDoc.IsActiveScenario(nSrcPos);
+ m_pDocument->SetActiveScenario(nDestPos, bActive );
+
+ bool bVisible = rSrcDoc.IsVisible(nSrcPos);
+ m_pDocument->SetVisible(nDestPos,bVisible );
+
+ }
+
+ if ( nErrVal > 0 && rSrcDoc.IsTabProtected( nSrcPos ) )
+ m_pDocument->SetTabProtection(nDestPos, rSrcDoc.GetTabProtection(nSrcPos));
+ if ( bNotifyAndPaint )
+ {
+ Broadcast( ScTablesHint( SC_TAB_INSERTED, nDestPos ) );
+ PostPaintExtras();
+ PostPaintGridAll();
+ }
+ return nErrVal;
+}
+
+bool ScDocShell::MoveTable( SCTAB nSrcTab, SCTAB nDestTab, bool bCopy, bool bRecord )
+{
+ ScDocShellModificator aModificator( *this );
+
+ // #i92477# be consistent with ScDocFunc::InsertTable: any index past the last sheet means "append"
+ // #i101139# nDestTab must be the target position, not APPEND (for CopyTabProtection etc.)
+ if ( nDestTab >= m_pDocument->GetTableCount() )
+ nDestTab = m_pDocument->GetTableCount();
+
+ if (bCopy)
+ {
+ if (bRecord)
+ m_pDocument->BeginDrawUndo(); // drawing layer must do its own undo actions
+
+ OUString sSrcCodeName;
+ m_pDocument->GetCodeName( nSrcTab, sSrcCodeName );
+ if (!m_pDocument->CopyTab( nSrcTab, nDestTab ))
+ {
+ //! EndDrawUndo?
+ return false;
+ }
+ else
+ {
+ SCTAB nAdjSource = nSrcTab;
+ if ( nDestTab <= nSrcTab )
+ ++nAdjSource; // new position of source table after CopyTab
+
+ if ( m_pDocument->IsTabProtected( nAdjSource ) )
+ m_pDocument->CopyTabProtection(nAdjSource, nDestTab);
+
+ if (bRecord)
+ {
+ unique_ptr< vector<SCTAB> > pSrcList(new vector<SCTAB>(1, nSrcTab));
+ unique_ptr< vector<SCTAB> > pDestList(new vector<SCTAB>(1, nDestTab));
+ GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoCopyTab>(this, std::move(pSrcList), std::move(pDestList)));
+ }
+
+ bool bVbaEnabled = m_pDocument->IsInVBAMode();
+ if ( bVbaEnabled )
+ {
+ OUString aLibName( "Standard" );
+ Reference< XLibraryContainer > xLibContainer = GetBasicContainer();
+ Reference< XVBACompatibility > xVBACompat( xLibContainer, UNO_QUERY );
+
+ if ( xVBACompat.is() )
+ {
+ aLibName = xVBACompat->getProjectName();
+ }
+
+ SCTAB nTabToUse = nDestTab;
+ if ( nDestTab == SC_TAB_APPEND )
+ nTabToUse = m_pDocument->GetMaxTableNumber() - 1;
+ OUString sSource;
+ try
+ {
+ Reference< XNameContainer > xLib;
+ if( xLibContainer.is() )
+ {
+ css::uno::Any aLibAny = xLibContainer->getByName( aLibName );
+ aLibAny >>= xLib;
+ }
+ if( xLib.is() )
+ {
+ xLib->getByName( sSrcCodeName ) >>= sSource;
+ }
+ }
+ catch ( const css::uno::Exception& )
+ {
+ }
+ VBA_InsertModule( *m_pDocument, nTabToUse, sSource );
+ }
+ }
+ Broadcast( ScTablesHint( SC_TAB_COPIED, nSrcTab, nDestTab ) );
+ }
+ else
+ {
+ if ( m_pDocument->GetChangeTrack() )
+ return false;
+
+ if ( nSrcTab<nDestTab && nDestTab!=SC_TAB_APPEND )
+ nDestTab--;
+
+ if ( nSrcTab == nDestTab )
+ {
+ //! allow only for api calls?
+ return true; // nothing to do, but valid
+ }
+
+ std::optional<ScProgress> pProgress(std::in_place, this, ScResId(STR_UNDO_MOVE_TAB),
+ m_pDocument->GetCodeCount(), true);
+ bool bDone = m_pDocument->MoveTab( nSrcTab, nDestTab, &*pProgress );
+ pProgress.reset();
+ if (!bDone)
+ {
+ return false;
+ }
+ else if (bRecord)
+ {
+ unique_ptr< vector<SCTAB> > pSrcList(new vector<SCTAB>(1, nSrcTab));
+ unique_ptr< vector<SCTAB> > pDestList(new vector<SCTAB>(1, nDestTab));
+ GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoMoveTab>(this, std::move(pSrcList), std::move(pDestList)));
+ }
+
+ Broadcast( ScTablesHint( SC_TAB_MOVED, nSrcTab, nDestTab ) );
+ }
+
+ PostPaintGridAll();
+ PostPaintExtras();
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+
+ return true;
+}
+
+IMPL_LINK( ScDocShell, RefreshDBDataHdl, Timer*, pRefreshTimer, void )
+{
+ ScDBDocFunc aFunc(*this);
+
+ ScDBData* pDBData = static_cast<ScDBData*>(pRefreshTimer);
+ ScImportParam aImportParam;
+ pDBData->GetImportParam( aImportParam );
+ if (aImportParam.bImport && !pDBData->HasImportSelection())
+ {
+ ScRange aRange;
+ pDBData->GetArea( aRange );
+ bool bContinue = aFunc.DoImport( aRange.aStart.Tab(), aImportParam, nullptr ); //! Api-Flag as parameter
+ // internal operations (sort, query, subtotal) only if no error
+ if (bContinue)
+ {
+ aFunc.RepeatDB( pDBData->GetName(), true, true );
+ RefreshPivotTables(aRange);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docsh6.cxx b/sc/source/ui/docshell/docsh6.cxx
new file mode 100644
index 000000000..caefdfc0f
--- /dev/null
+++ b/sc/source/ui/docshell/docsh6.cxx
@@ -0,0 +1,517 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+
+#include <svx/pageitem.hxx>
+#include <sfx2/linkmgr.hxx>
+
+#include <docsh.hxx>
+
+#include <stlpool.hxx>
+#include <global.hxx>
+#include <viewdata.hxx>
+#include <tabvwsh.hxx>
+#include <tablink.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <scmod.hxx>
+#include <compiler.hxx>
+#include <interpre.hxx>
+#include <formulaopt.hxx>
+
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <memory>
+#include <utility>
+
+namespace {
+
+struct ScStylePair
+{
+ SfxStyleSheetBase *pSource;
+ SfxStyleSheetBase *pDest;
+};
+
+}
+
+// Ole
+
+void ScDocShell::SetVisArea( const tools::Rectangle & rVisArea )
+{
+ // with the SnapVisArea call in SetVisAreaOrSize, it's safe to always
+ // use both the size and position of the VisArea
+ SetVisAreaOrSize( rVisArea );
+}
+
+static void lcl_SetTopRight( tools::Rectangle& rRect, const Point& rPos )
+{
+ Size aSize = rRect.GetSize();
+ rRect.SetRight( rPos.X() );
+ rRect.SetLeft( rPos.X() - aSize.Width() + 1 );
+ rRect.SetTop( rPos.Y() );
+ rRect.SetBottom( rPos.Y() + aSize.Height() - 1 );
+}
+
+void ScDocShell::SetVisAreaOrSize( const tools::Rectangle& rVisArea )
+{
+ bool bNegativePage = m_pDocument->IsNegativePage( m_pDocument->GetVisibleTab() );
+
+ tools::Rectangle aArea = rVisArea;
+ // when loading, don't check for negative values, because the sheet orientation
+ // might be set later
+ if ( !m_pDocument->IsImportingXML() )
+ {
+ if ( ( bNegativePage ? (aArea.Right() > 0) : (aArea.Left() < 0) ) || aArea.Top() < 0 )
+ {
+ // VisArea start position can't be negative.
+ // Move the VisArea, otherwise only the upper left position would
+ // be changed in SnapVisArea, and the size would be wrong.
+
+ Point aNewPos( 0, std::max( aArea.Top(), tools::Long(0) ) );
+ if ( bNegativePage )
+ {
+ aNewPos.setX( std::min( aArea.Right(), tools::Long(0) ) );
+ lcl_SetTopRight( aArea, aNewPos );
+ }
+ else
+ {
+ aNewPos.setX( std::max( aArea.Left(), tools::Long(0) ) );
+ aArea.SetPos( aNewPos );
+ }
+ }
+ }
+
+ // adjust position here!
+
+ // when loading an ole object, the VisArea is set from the document's
+ // view settings and must be used as-is (document content may not be complete yet).
+ if ( !m_pDocument->IsImportingXML() )
+ SnapVisArea( aArea );
+
+ //TODO/LATER: it's unclear which IPEnv is used here
+ /*
+ SvInPlaceEnvironment* pEnv = GetIPEnv();
+ if (pEnv)
+ {
+ vcl::Window* pWin = pEnv->GetEditWin();
+ pEnv->MakeScale( aArea.GetSize(), MapUnit::Map100thMM,
+ pWin->LogicToPixel( aArea.GetSize() ) );
+ } */
+
+ //TODO/LATER: formerly in SvInplaceObject
+ SfxObjectShell::SetVisArea( aArea );
+
+ if (m_bIsInplace) // adjust zoom in the InPlace View
+ {
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if (pViewSh)
+ {
+ if (pViewSh->GetViewData().GetDocShell() == this)
+ pViewSh->UpdateOleZoom();
+ }
+ }
+
+ if (!m_pDocument->IsEmbedded())
+ return;
+
+ ScRange aOld;
+ m_pDocument->GetEmbedded( aOld);
+ m_pDocument->SetEmbedded( m_pDocument->GetVisibleTab(), aArea );
+ ScRange aNew;
+ m_pDocument->GetEmbedded( aNew);
+ if (aOld != aNew)
+ PostPaint(0,0,0,m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB,PaintPartFlags::Grid);
+
+ //TODO/LATER: currently not implemented
+ //ViewChanged( ASPECT_CONTENT ); // show in the container as well
+}
+
+bool ScDocShell::IsOle() const
+{
+ return (GetCreateMode() == SfxObjectCreateMode::EMBEDDED);
+}
+
+void ScDocShell::UpdateOle(const ScViewData& rViewData, bool bSnapSize)
+{
+ // if it isn't Ole at all, one can be spared the calculations
+ // (VisArea will then be reset at the save)
+
+ if (GetCreateMode() == SfxObjectCreateMode::STANDARD)
+ return;
+
+ tools::Rectangle aOldArea = SfxObjectShell::GetVisArea();
+ tools::Rectangle aNewArea = aOldArea;
+
+ bool bEmbedded = m_pDocument->IsEmbedded();
+ if (bEmbedded)
+ aNewArea = m_pDocument->GetEmbeddedRect();
+ else
+ {
+ SCTAB nTab = rViewData.GetTabNo();
+ if ( nTab != m_pDocument->GetVisibleTab() )
+ m_pDocument->SetVisibleTab( nTab );
+
+ bool bNegativePage = m_pDocument->IsNegativePage( nTab );
+ SCCOL nX = rViewData.GetPosX(SC_SPLIT_LEFT);
+ if ( nX != m_pDocument->GetPosLeft() )
+ m_pDocument->SetPosLeft( nX );
+ SCROW nY = rViewData.GetPosY(SC_SPLIT_BOTTOM);
+ if ( nY != m_pDocument->GetPosTop() )
+ m_pDocument->SetPosTop( nY );
+ tools::Rectangle aMMRect = m_pDocument->GetMMRect( nX,nY, nX,nY, nTab );
+ if (bNegativePage)
+ lcl_SetTopRight( aNewArea, aMMRect.TopRight() );
+ else
+ aNewArea.SetPos( aMMRect.TopLeft() );
+ if (bSnapSize)
+ SnapVisArea(aNewArea); // uses the new VisibleTab
+ }
+
+ if (aNewArea != aOldArea)
+ SetVisAreaOrSize( aNewArea ); // the start must also be adjusted here
+}
+
+// Style stuff for Organizer, etc.
+
+SfxStyleSheetBasePool* ScDocShell::GetStyleSheetPool()
+{
+ return static_cast<SfxStyleSheetBasePool*>(m_pDocument->GetStyleSheetPool());
+}
+
+// After loading styles from another document (LoadStyles, Insert), the SetItems
+// (ATTR_PAGE_HEADERSET, ATTR_PAGE_FOOTERSET) must be converted to the correct pool
+// before the source pool is deleted.
+
+static void lcl_AdjustPool( SfxStyleSheetBasePool* pStylePool )
+{
+ SfxStyleSheetBase *pStyle = pStylePool->First(SfxStyleFamily::Page);
+ while ( pStyle )
+ {
+ SfxItemSet& rStyleSet = pStyle->GetItemSet();
+
+ if (const SvxSetItem* pItem = rStyleSet.GetItemIfSet(ATTR_PAGE_HEADERSET,false))
+ {
+ const SfxItemSet& rSrcSet = pItem->GetItemSet();
+ SfxItemSet aDestSet(*rStyleSet.GetPool(),rSrcSet.GetRanges());
+ aDestSet.Put(rSrcSet);
+ rStyleSet.Put(SvxSetItem(ATTR_PAGE_HEADERSET, std::move(aDestSet)));
+ }
+ if (const SvxSetItem* pItem = rStyleSet.GetItemIfSet(ATTR_PAGE_FOOTERSET,false))
+ {
+ const SfxItemSet& rSrcSet = pItem->GetItemSet();
+ SfxItemSet aDestSet(*rStyleSet.GetPool(),rSrcSet.GetRanges());
+ aDestSet.Put(rSrcSet);
+ rStyleSet.Put(SvxSetItem(ATTR_PAGE_FOOTERSET, std::move(aDestSet)));
+ }
+
+ pStyle = pStylePool->Next();
+ }
+}
+
+void ScDocShell::LoadStyles( SfxObjectShell &rSource )
+{
+ m_pDocument->StylesToNames();
+
+ SfxObjectShell::LoadStyles(rSource);
+ lcl_AdjustPool( GetStyleSheetPool() ); // adjust SetItems
+
+ m_pDocument->UpdStlShtPtrsFrmNms();
+
+ UpdateAllRowHeights();
+
+ // Paint
+
+ PostPaint( 0,0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB, PaintPartFlags::Grid | PaintPartFlags::Left );
+}
+
+void ScDocShell::LoadStylesArgs( ScDocShell& rSource, bool bReplace, bool bCellStyles, bool bPageStyles )
+{
+ // similar to LoadStyles, but with selectable behavior for XStyleLoader::loadStylesFromURL call
+
+ if ( !bCellStyles && !bPageStyles ) // nothing to do
+ return;
+
+ ScStyleSheetPool* pSourcePool = rSource.GetDocument().GetStyleSheetPool();
+ ScStyleSheetPool* pDestPool = m_pDocument->GetStyleSheetPool();
+
+ SfxStyleFamily eFamily = bCellStyles ?
+ ( bPageStyles ? SfxStyleFamily::All : SfxStyleFamily::Para ) :
+ SfxStyleFamily::Page;
+ SfxStyleSheetIterator aIter( pSourcePool, eFamily );
+ sal_uInt16 nSourceCount = aIter.Count();
+ if ( nSourceCount == 0 )
+ return; // no source styles
+
+ std::unique_ptr<ScStylePair[]> pStyles(new ScStylePair[ nSourceCount ]);
+ sal_uInt16 nFound = 0;
+
+ // first create all new styles
+
+ SfxStyleSheetBase* pSourceStyle = aIter.First();
+ while (pSourceStyle)
+ {
+ OUString aName = pSourceStyle->GetName();
+ SfxStyleSheetBase* pDestStyle = pDestPool->Find( pSourceStyle->GetName(), pSourceStyle->GetFamily() );
+ if ( pDestStyle )
+ {
+ // touch existing styles only if replace flag is set
+ if ( bReplace )
+ {
+ pStyles[nFound].pSource = pSourceStyle;
+ pStyles[nFound].pDest = pDestStyle;
+ ++nFound;
+ }
+ }
+ else
+ {
+ pStyles[nFound].pSource = pSourceStyle;
+ pStyles[nFound].pDest = &pDestPool->Make( aName, pSourceStyle->GetFamily(), pSourceStyle->GetMask() );
+ ++nFound;
+ }
+
+ pSourceStyle = aIter.Next();
+ }
+
+ // then copy contents (after inserting all styles, for parent etc.)
+
+ for ( sal_uInt16 i = 0; i < nFound; ++i )
+ {
+ pStyles[i].pDest->GetItemSet().PutExtended(
+ pStyles[i].pSource->GetItemSet(), SfxItemState::DONTCARE, SfxItemState::DEFAULT);
+ if(pStyles[i].pSource->HasParentSupport())
+ pStyles[i].pDest->SetParent(pStyles[i].pSource->GetParent());
+ // follow is never used
+ }
+
+ lcl_AdjustPool( GetStyleSheetPool() ); // adjust SetItems
+ UpdateAllRowHeights();
+ PostPaint( 0,0,0, m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB, PaintPartFlags::Grid | PaintPartFlags::Left ); // Paint
+}
+
+void ScDocShell::ReconnectDdeLink(SfxObjectShell& rServer)
+{
+ ::sfx2::LinkManager* pLinkManager = m_pDocument->GetLinkManager();
+ if (!pLinkManager)
+ return;
+
+ pLinkManager->ReconnectDdeLink(rServer);
+}
+
+void ScDocShell::UpdateLinks()
+{
+ typedef std::unordered_set<OUString> StrSetType;
+
+ sfx2::LinkManager* pLinkManager = m_pDocument->GetLinkManager();
+ StrSetType aNames;
+
+ // out with the no longer used links
+
+ size_t nCount = pLinkManager->GetLinks().size();
+ for (size_t k=nCount; k>0; )
+ {
+ --k;
+ ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[k].get();
+ if (ScTableLink* pTabLink = dynamic_cast<ScTableLink*>(pBase))
+ {
+ if (pTabLink->IsUsed())
+ aNames.insert(pTabLink->GetFileName());
+ else // no longer used -> delete
+ {
+ pTabLink->SetAddUndo(true);
+ pLinkManager->Remove(k);
+ }
+ }
+ }
+
+ // enter new links
+
+ SCTAB nTabCount = m_pDocument->GetTableCount();
+ for (SCTAB i = 0; i < nTabCount; ++i)
+ {
+ if (!m_pDocument->IsLinked(i))
+ continue;
+
+ OUString aDocName = m_pDocument->GetLinkDoc(i);
+ OUString aFltName = m_pDocument->GetLinkFlt(i);
+ OUString aOptions = m_pDocument->GetLinkOpt(i);
+ sal_uLong nRefresh = m_pDocument->GetLinkRefreshDelay(i);
+ bool bThere = false;
+ for (SCTAB j = 0; j < i && !bThere; ++j) // several times in the document?
+ {
+ if (m_pDocument->IsLinked(j)
+ && m_pDocument->GetLinkDoc(j) == aDocName
+ && m_pDocument->GetLinkFlt(j) == aFltName
+ && m_pDocument->GetLinkOpt(j) == aOptions)
+ // Ignore refresh delay in compare, it should be the
+ // same for identical links and we don't want dupes
+ // if it ain't.
+ bThere = true;
+ }
+
+ if (!bThere) // already entered as filter?
+ {
+ if (!aNames.insert(aDocName).second)
+ bThere = true;
+ }
+
+ if (!bThere)
+ {
+ ScTableLink* pLink = new ScTableLink( this, aDocName, aFltName, aOptions, nRefresh );
+ pLink->SetInCreate(true);
+ pLinkManager->InsertFileLink(*pLink, sfx2::SvBaseLinkObjectType::ClientFile, aDocName, &aFltName);
+ pLink->Update();
+ pLink->SetInCreate(false);
+ }
+ }
+}
+
+void ScDocShell::ReloadTabLinks()
+{
+ sfx2::LinkManager* pLinkManager = m_pDocument->GetLinkManager();
+
+ bool bAny = false;
+ size_t nCount = pLinkManager->GetLinks().size();
+ for (size_t i=0; i<nCount; i++ )
+ {
+ ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
+ if (ScTableLink* pTabLink = dynamic_cast<ScTableLink*>(pBase))
+ {
+// pTabLink->SetAddUndo(sal_False); //! merge Undos
+
+ // Painting only after Update() makes no sense:
+ // ScTableLink::Refresh() will post a Paint only is bDoPaint is true
+ // pTabLink->SetPaint(false); // Paint only once at the end
+ pTabLink->Update();
+ //pTabLink->SetPaint(true);
+// pTabLink->SetAddUndo(sal_True);
+ bAny = true;
+ }
+ }
+
+ if ( bAny )
+ {
+ // Paint only once
+ PostPaint( ScRange(0,0,0,m_pDocument->MaxCol(),m_pDocument->MaxRow(),MAXTAB),
+ PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left );
+
+ SetDocumentModified();
+ }
+}
+
+void ScDocShell::SetFormulaOptions( const ScFormulaOptions& rOpt, bool bForLoading )
+{
+ m_pDocument->SetGrammar( rOpt.GetFormulaSyntax() );
+
+ // This is nasty because it resets module globals from within a docshell!
+ // For actual damage caused see fdo#82183 where an unconditional
+ // ScGlobal::ResetFunctionList() (without checking GetUseEnglishFuncName())
+ // lead to a crash because the function list was still used by the Formula
+ // Wizard when loading the second document.
+ // Do the stupid stuff only when we're not called while loading a document.
+
+ /* TODO: bForLoading is a workaround, rather get rid of setting any
+ * globals from per document instances like ScDocShell. */
+
+ /* XXX this is utter crap, we rely on the options being set here at least
+ * once, for the very first document, empty or loaded. */
+ static bool bInitOnce = true;
+
+ if (!bForLoading || bInitOnce)
+ {
+ bool bForceInit = bInitOnce;
+ bInitOnce = false;
+ if (bForceInit || rOpt.GetUseEnglishFuncName() != SC_MOD()->GetFormulaOptions().GetUseEnglishFuncName())
+ {
+ // This needs to be called first since it may re-initialize the entire
+ // opcode map.
+ if (rOpt.GetUseEnglishFuncName())
+ {
+ // switch native symbols to English.
+ ScAddress aAddress;
+ ScCompiler aComp( *m_pDocument, aAddress);
+ ScCompiler::OpCodeMapPtr xMap = aComp.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH);
+ ScCompiler::SetNativeSymbols(xMap);
+ }
+ else
+ // re-initialize native symbols with localized function names.
+ ScCompiler::ResetNativeSymbols();
+
+ // Force re-population of function names for the function wizard, function tip etc.
+ ScGlobal::ResetFunctionList();
+ }
+
+ // Update the separators.
+ ScCompiler::UpdateSeparatorsNative(
+ rOpt.GetFormulaSepArg(), rOpt.GetFormulaSepArrayCol(), rOpt.GetFormulaSepArrayRow());
+
+ // Global interpreter settings.
+ ScInterpreter::SetGlobalConfig(rOpt.GetCalcConfig());
+ }
+
+ // Per document interpreter settings.
+ m_pDocument->SetCalcConfig( rOpt.GetCalcConfig() );
+}
+
+void ScDocShell::CheckConfigOptions()
+{
+ if (IsConfigOptionsChecked())
+ // no need to check repeatedly.
+ return;
+
+ OUString aDecSep = ScGlobal::getLocaleData().getNumDecimalSep();
+ OUString aDecSepAlt = ScGlobal::getLocaleData().getNumDecimalSepAlt();
+
+ ScModule* pScMod = SC_MOD();
+ const ScFormulaOptions& rOpt=pScMod->GetFormulaOptions();
+ const OUString& aSepArg = rOpt.GetFormulaSepArg();
+ const OUString& aSepArrRow = rOpt.GetFormulaSepArrayRow();
+ const OUString& aSepArrCol = rOpt.GetFormulaSepArrayCol();
+
+ if (aDecSep == aSepArg || aDecSep == aSepArrRow || aDecSep == aSepArrCol ||
+ aDecSepAlt == aSepArg || aDecSepAlt == aSepArrRow || aDecSepAlt == aSepArrCol)
+ {
+ // One of arg separators conflicts with the current decimal
+ // separator. Reset them to default.
+ ScFormulaOptions aNew = rOpt;
+ aNew.ResetFormulaSeparators();
+ SetFormulaOptions(aNew);
+ pScMod->SetFormulaOptions(aNew);
+
+ // Launch a nice warning dialog to let the users know of this change.
+ ScTabViewShell* pViewShell = GetBestViewShell();
+ if (pViewShell)
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pViewShell->GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_OPTIONS_WARN_SEPARATORS)));
+ xInfoBox->run();
+ }
+
+ // For now, this is the only option setting that could launch info
+ // dialog. But in the future we may want to implement a nicer
+ // dialog to display a list of warnings in case we have several
+ // pieces of information to display.
+ }
+
+ SetConfigOptionsChecked(true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docsh8.cxx b/sc/source/ui/docshell/docsh8.cxx
new file mode 100644
index 000000000..683ac2cbe
--- /dev/null
+++ b/sc/source/ui/docshell/docsh8.cxx
@@ -0,0 +1,1082 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <vcl/errinf.hxx>
+#include <tools/urlobj.hxx>
+#include <svl/converter.hxx>
+#include <svl/numformat.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/types.hxx>
+#include <ucbhelper/content.hxx>
+#include <svx/txenctab.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <unotools/charclass.hxx>
+#include <rtl/character.hxx>
+#include <rtl/tencinfo.h>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+#include <o3tl/string_view.hxx>
+
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDefinitionSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/ucb/NameClash.hpp>
+#include <com/sun/star/ucb/TransferInfo.hpp>
+#include <com/sun/star/ucb/XCommandInfo.hpp>
+
+#include <scerrors.hxx>
+#include <docsh.hxx>
+#include <progress.hxx>
+#include <editutil.hxx>
+#include <cellform.hxx>
+#include <dbdocutl.hxx>
+#include <dociter.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <svl/zformat.hxx>
+#include <svl/intitem.hxx>
+#include <patattr.hxx>
+#include <scitems.hxx>
+#include <docpool.hxx>
+#include <segmenttree.hxx>
+#include <docparam.hxx>
+#include <cellvalue.hxx>
+
+#include <unordered_set>
+#include <vector>
+
+using namespace com::sun::star;
+using ::std::vector;
+
+#if HAVE_FEATURE_DBCONNECTIVITY
+
+constexpr OUStringLiteral SC_SERVICE_ROWSET = u"com.sun.star.sdb.RowSet";
+
+//! move to a header file?
+constexpr OUStringLiteral SC_DBPROP_ACTIVECONNECTION = u"ActiveConnection";
+constexpr OUStringLiteral SC_DBPROP_COMMAND = u"Command";
+constexpr OUStringLiteral SC_DBPROP_COMMANDTYPE = u"CommandType";
+constexpr OUStringLiteral SC_DBPROP_PROPCHANGE_NOTIFY = u"PropertyChangeNotificationEnabled";
+
+constexpr OUStringLiteral SC_DBPROP_NAME = u"Name";
+constexpr OUStringLiteral SC_DBPROP_TYPE = u"Type";
+constexpr OUStringLiteral SC_DBPROP_PRECISION = u"Precision";
+constexpr OUStringLiteral SC_DBPROP_SCALE = u"Scale";
+
+constexpr OUStringLiteral SC_DBPROP_EXTENSION = u"Extension";
+constexpr OUStringLiteral SC_DBPROP_CHARSET = u"CharSet";
+
+namespace
+{
+ ErrCode lcl_getDBaseConnection(uno::Reference<sdbc::XDriverManager2>& _rDrvMgr, uno::Reference<sdbc::XConnection>& _rConnection, OUString& _rTabName, std::u16string_view rFullFileName, rtl_TextEncoding eCharSet)
+ {
+ INetURLObject aURL;
+ aURL.SetSmartProtocol( INetProtocol::File );
+ aURL.SetSmartURL( rFullFileName );
+ _rTabName = aURL.getBase( INetURLObject::LAST_SEGMENT, true,
+ INetURLObject::DecodeMechanism::Unambiguous );
+ OUString aExtension = aURL.getExtension();
+ aURL.removeSegment();
+ aURL.removeFinalSlash();
+ OUString aPath = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
+
+ _rDrvMgr.set( sdbc::DriverManager::create( xContext ) );
+
+ // get connection
+
+ const OUString aConnUrl{"sdbc:dbase:" + aPath};
+
+ // sdbc:dbase is based on the css.sdbc.FILEConnectionProperties UNOIDL service, so we can
+ // transport the raw rtl_TextEncoding value instead of having to translate it into an IANA
+ // character set name string (which might not exist for certain eCharSet values, like
+ // RTL_TEXTENCODING_MS_950):
+ uno::Sequence<beans::PropertyValue> aProps( comphelper::InitPropertySequence({
+ { SC_DBPROP_EXTENSION, uno::Any(aExtension) },
+ { SC_DBPROP_CHARSET, uno::Any(eCharSet) }
+ }));
+
+ _rConnection = _rDrvMgr->getConnectionWithInfo( aConnUrl, aProps );
+ return ERRCODE_NONE;
+ }
+}
+
+#endif // HAVE_FEATURE_DBCONNECTIVITY
+
+// MoveFile/KillFile/IsDocument: similar to SfxContentHelper
+
+bool ScDocShell::MoveFile( const INetURLObject& rSourceObj, const INetURLObject& rDestObj )
+{
+ bool bMoveData = true;
+ bool bRet = true, bKillSource = false;
+ if ( rSourceObj.GetProtocol() != rDestObj.GetProtocol() )
+ {
+ bMoveData = false;
+ bKillSource = true;
+ }
+ OUString aName = rDestObj.getName();
+ INetURLObject aDestPathObj = rDestObj;
+ aDestPathObj.removeSegment();
+ aDestPathObj.setFinalSlash();
+
+ try
+ {
+ ::ucbhelper::Content aDestPath( aDestPathObj.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ uno::Reference< css::ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext() );
+ uno::Reference< css::ucb::XCommandInfo > xInfo = aDestPath.getCommands();
+ OUString aTransferName = "transfer";
+ if ( xInfo->hasCommandByName( aTransferName ) )
+ {
+ aDestPath.executeCommand( aTransferName, uno::Any(
+ css::ucb::TransferInfo( bMoveData, rSourceObj.GetMainURL(INetURLObject::DecodeMechanism::NONE), aName,
+ css::ucb::NameClash::ERROR ) ) );
+ }
+ else
+ {
+ OSL_FAIL( "transfer command not available" );
+ }
+ }
+ catch( uno::Exception& )
+ {
+ // ucb may throw different exceptions on failure now
+ bRet = false;
+ }
+
+ if ( bKillSource )
+ KillFile( rSourceObj );
+
+ return bRet;
+}
+
+bool ScDocShell::KillFile( const INetURLObject& rURL )
+{
+ bool bRet = true;
+ try
+ {
+ ::ucbhelper::Content aCnt( rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ uno::Reference< css::ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext() );
+ aCnt.executeCommand( "delete", css::uno::Any( true ) );
+ }
+ catch( uno::Exception& )
+ {
+ // ucb may throw different exceptions on failure now
+ bRet = false;
+ }
+
+ return bRet;
+}
+
+bool ScDocShell::IsDocument( const INetURLObject& rURL )
+{
+ bool bRet = false;
+ try
+ {
+ ::ucbhelper::Content aCnt( rURL.GetMainURL(INetURLObject::DecodeMechanism::NONE),
+ uno::Reference< css::ucb::XCommandEnvironment >(),
+ comphelper::getProcessComponentContext() );
+ bRet = aCnt.isDocument();
+ }
+ catch( uno::Exception& )
+ {
+ // ucb may throw different exceptions on failure now - warning only
+ TOOLS_WARN_EXCEPTION( "sc", "Any other exception" );
+ }
+
+ return bRet;
+}
+
+#if HAVE_FEATURE_DBCONNECTIVITY
+
+static void lcl_setScalesToColumns(ScDocument& rDoc, const vector<tools::Long>& rScales)
+{
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ if (!pFormatter)
+ return;
+
+ SCCOL nColCount = static_cast<SCCOL>(rScales.size());
+ for (SCCOL i = 0; i < nColCount; ++i)
+ {
+ if (rScales[i] < 0)
+ continue;
+
+ sal_uInt32 nOldFormat = rDoc.GetNumberFormat(i, 0, 0);
+ const SvNumberformat* pOldEntry = pFormatter->GetEntry(nOldFormat);
+ if (!pOldEntry)
+ continue;
+
+ LanguageType eLang = pOldEntry->GetLanguage();
+ bool bThousand, bNegRed;
+ sal_uInt16 nPrecision, nLeading;
+ pOldEntry->GetFormatSpecialInfo(bThousand, bNegRed, nPrecision, nLeading);
+
+ nPrecision = static_cast<sal_uInt16>(rScales[i]);
+ OUString aNewPicture = pFormatter->GenerateFormat(nOldFormat, eLang,
+ bThousand, bNegRed, nPrecision, nLeading);
+
+ sal_uInt32 nNewFormat = pFormatter->GetEntryKey(aNewPicture, eLang);
+ if (nNewFormat == NUMBERFORMAT_ENTRY_NOT_FOUND)
+ {
+ sal_Int32 nErrPos = 0;
+ SvNumFormatType nNewType = SvNumFormatType::ALL;
+ bool bOk = pFormatter->PutEntry(
+ aNewPicture, nErrPos, nNewType, nNewFormat, eLang);
+
+ if (!bOk)
+ continue;
+ }
+
+ ScPatternAttr aNewAttrs( rDoc.GetPool() );
+ SfxItemSet& rSet = aNewAttrs.GetItemSet();
+ rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nNewFormat) );
+ rDoc.ApplyPatternAreaTab(i, 0, i, rDoc.MaxRow(), 0, aNewAttrs);
+ }
+}
+
+#endif // HAVE_FEATURE_DBCONNECTIVITY
+
+ErrCode ScDocShell::DBaseImport( const OUString& rFullFileName, rtl_TextEncoding eCharSet,
+ std::map<SCCOL, ScColWidthParam>& aColWidthParam, ScFlatBoolRowSegments& rRowHeightsRecalc )
+{
+#if !HAVE_FEATURE_DBCONNECTIVITY
+ (void) rFullFileName;
+ (void) eCharSet;
+ (void) aColWidthParam;
+ (void) rRowHeightsRecalc;
+
+ return ERRCODE_IO_GENERAL;
+#else
+
+ ErrCode nErr = ERRCODE_NONE;
+
+ try
+ {
+ tools::Long i;
+ sal_Int32 nColCount = 0;
+ OUString aTabName;
+ uno::Reference<sdbc::XDriverManager2> xDrvMan;
+ uno::Reference<sdbc::XConnection> xConnection;
+ ErrCode nRet = lcl_getDBaseConnection(xDrvMan,xConnection,aTabName,rFullFileName,eCharSet);
+ if ( !xConnection.is() || !xDrvMan.is() )
+ return nRet;
+ ::utl::DisposableComponent aConnectionHelper(xConnection);
+
+ ScProgress aProgress( this, ScResId( STR_LOAD_DOC ), 0, true );
+ uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory();
+ uno::Reference<sdbc::XRowSet> xRowSet( xFactory->createInstance(SC_SERVICE_ROWSET),
+ uno::UNO_QUERY);
+ ::utl::DisposableComponent aRowSetHelper(xRowSet);
+ uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY );
+ OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
+ if (!xRowProp.is()) return SCERR_IMPORT_CONNECT;
+
+ xRowProp->setPropertyValue( SC_DBPROP_ACTIVECONNECTION, uno::Any(xConnection) );
+
+ xRowProp->setPropertyValue( SC_DBPROP_COMMANDTYPE, uno::Any(sdb::CommandType::TABLE) );
+
+ xRowProp->setPropertyValue( SC_DBPROP_COMMAND, uno::Any(aTabName) );
+
+ xRowProp->setPropertyValue( SC_DBPROP_PROPCHANGE_NOTIFY, uno::Any(false) );
+
+ xRowSet->execute();
+
+ uno::Reference<sdbc::XResultSetMetaData> xMeta;
+ uno::Reference<sdbc::XResultSetMetaDataSupplier> xMetaSupp( xRowSet, uno::UNO_QUERY );
+ if ( xMetaSupp.is() )
+ xMeta = xMetaSupp->getMetaData();
+ if ( xMeta.is() )
+ nColCount = xMeta->getColumnCount(); // this is the number of real columns
+
+ if ( nColCount > m_pDocument->MaxCol()+1 )
+ {
+ nColCount = m_pDocument->MaxCol()+1;
+ nErr = SCWARN_IMPORT_COLUMN_OVERFLOW; // warning
+ }
+
+ uno::Reference<sdbc::XRow> xRow( xRowSet, uno::UNO_QUERY );
+ OSL_ENSURE( xRow.is(), "can't get Row" );
+ if (!xRow.is()) return SCERR_IMPORT_CONNECT;
+
+ // currency flag is not needed for dBase
+ uno::Sequence<sal_Int32> aColTypes( nColCount ); // column types
+ sal_Int32* pTypeArr = aColTypes.getArray();
+ for (i=0; i<nColCount; i++)
+ pTypeArr[i] = xMeta->getColumnType( i+1 );
+
+ // read column names
+ //! add type descriptions
+
+ aProgress.SetState( 0 );
+
+ vector<tools::Long> aScales(nColCount, -1);
+ for (i=0; i<nColCount; i++)
+ {
+ OUString aHeader = xMeta->getColumnLabel( i+1 );
+
+ switch ( pTypeArr[i] )
+ {
+ case sdbc::DataType::BIT:
+ aHeader += ",L";
+ break;
+ case sdbc::DataType::DATE:
+ aHeader += ",D";
+ break;
+ case sdbc::DataType::LONGVARCHAR:
+ aHeader += ",M";
+ break;
+ case sdbc::DataType::VARCHAR:
+ aHeader += ",C," + OUString::number( xMeta->getColumnDisplaySize( i+1 ) );
+ break;
+ case sdbc::DataType::DECIMAL:
+ {
+ tools::Long nPrec = xMeta->getPrecision( i+1 );
+ tools::Long nScale = xMeta->getScale( i+1 );
+ aHeader += ",N," +
+ OUString::number(
+ SvDbaseConverter::ConvertPrecisionToDbase(
+ nPrec, nScale ) ) +
+ "," +
+ OUString::number( nScale );
+ aScales[i] = nScale;
+ }
+ break;
+ }
+
+ m_pDocument->SetString( static_cast<SCCOL>(i), 0, 0, aHeader );
+ }
+
+ lcl_setScalesToColumns(*m_pDocument, aScales);
+
+ SCROW nRow = 1; // 0 is column titles
+ bool bEnd = false;
+ while ( !bEnd && xRowSet->next() )
+ {
+ if ( nRow <= m_pDocument->MaxRow() )
+ {
+ bool bSimpleRow = true;
+ SCCOL nCol = 0;
+ for (i=0; i<nColCount; i++)
+ {
+ ScDatabaseDocUtil::StrData aStrData;
+ ScDatabaseDocUtil::PutData( *m_pDocument, nCol, nRow, 0,
+ xRow, i+1, pTypeArr[i], false,
+ &aStrData );
+
+ if (aStrData.mnStrLength > aColWidthParam[nCol].mnMaxTextLen)
+ {
+ aColWidthParam[nCol].mnMaxTextLen = aStrData.mnStrLength;
+ aColWidthParam[nCol].mnMaxTextRow = nRow;
+ }
+
+ if (!aStrData.mbSimpleText)
+ {
+ bSimpleRow = false;
+ aColWidthParam[nCol].mbSimpleText = false;
+ }
+
+ ++nCol;
+ }
+ if (!bSimpleRow)
+ rRowHeightsRecalc.setTrue(nRow, nRow);
+ ++nRow;
+ }
+ else // past the end of the spreadsheet
+ {
+ bEnd = true; // don't continue
+ nErr = SCWARN_IMPORT_RANGE_OVERFLOW; // warning message
+ }
+ }
+ }
+ catch ( sdbc::SQLException& )
+ {
+ nErr = SCERR_IMPORT_CONNECT;
+ }
+ catch ( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "Unexpected exception in database");
+ nErr = ERRCODE_IO_GENERAL;
+ }
+
+ return nErr;
+#endif // HAVE_FEATURE_DBCONNECTIVITY
+}
+
+#if HAVE_FEATURE_DBCONNECTIVITY
+
+namespace {
+
+void lcl_GetColumnTypes(
+ ScDocShell& rDocShell, const ScRange& rDataRange, bool bHasFieldNames,
+ OUString* pColNames, sal_Int32* pColTypes, sal_Int32* pColLengths,
+ sal_Int32* pColScales, bool& bHasMemo, rtl_TextEncoding eCharSet )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SvNumberFormatter* pNumFmt = rDoc.GetFormatTable();
+
+ SCTAB nTab = rDataRange.aStart.Tab();
+ SCCOL nFirstCol = rDataRange.aStart.Col();
+ SCROW nFirstRow = rDataRange.aStart.Row();
+ SCCOL nLastCol = rDataRange.aEnd.Col();
+ SCROW nLastRow = rDataRange.aEnd.Row();
+
+ typedef std::unordered_set<OUString> StrSetType;
+ StrSetType aFieldNames;
+
+ tools::Long nField = 0;
+ SCROW nFirstDataRow = ( bHasFieldNames ? nFirstRow + 1 : nFirstRow );
+ for ( SCCOL nCol = nFirstCol; nCol <= nLastCol; nCol++ )
+ {
+ bool bTypeDefined = false;
+ bool bPrecDefined = false;
+ sal_Int32 nFieldLen = 0;
+ sal_Int32 nPrecision = 0;
+ sal_Int32 nDbType = sdbc::DataType::SQLNULL;
+ OUString aFieldName;
+
+ // Fieldname[,Type[,Width[,Prec]]]
+ // Type etc.: L; D; C[,W]; N[,W[,P]]
+ if ( bHasFieldNames )
+ {
+ OUString aString {rDoc.GetString(nCol, nFirstRow, nTab).toAsciiUpperCase()};
+ sal_Int32 nIdx {0};
+ aFieldName = aString.getToken( 0, ',', nIdx);
+ if ( nIdx>0 )
+ {
+ aString = aString.replaceAll(" ", "");
+ switch ( o3tl::getToken(aString, 0, ',', nIdx )[0] )
+ {
+ case 'L' :
+ nDbType = sdbc::DataType::BIT;
+ nFieldLen = 1;
+ bTypeDefined = true;
+ bPrecDefined = true;
+ break;
+ case 'D' :
+ nDbType = sdbc::DataType::DATE;
+ nFieldLen = 8;
+ bTypeDefined = true;
+ bPrecDefined = true;
+ break;
+ case 'M' :
+ nDbType = sdbc::DataType::LONGVARCHAR;
+ nFieldLen = 10;
+ bTypeDefined = true;
+ bPrecDefined = true;
+ bHasMemo = true;
+ break;
+ case 'C' :
+ nDbType = sdbc::DataType::VARCHAR;
+ bTypeDefined = true;
+ bPrecDefined = true;
+ break;
+ case 'N' :
+ nDbType = sdbc::DataType::DECIMAL;
+ bTypeDefined = true;
+ break;
+ }
+ if ( bTypeDefined && !nFieldLen && nIdx>0 )
+ {
+ nFieldLen = o3tl::toInt32(o3tl::getToken(aString, 0, ',', nIdx ));
+ if ( !bPrecDefined && nIdx>0 )
+ {
+ OUString aTmp( aString.getToken( 0, ',', nIdx ) );
+ if ( CharClass::isAsciiNumeric(aTmp) )
+ {
+ nPrecision = aTmp.toInt32();
+ if (nPrecision && nFieldLen < nPrecision+1)
+ nFieldLen = nPrecision + 1; // include decimal separator
+ bPrecDefined = true;
+ }
+ }
+ }
+ }
+
+ // Check field name and generate valid field name if necessary.
+ // First character has to be alphabetical, subsequent characters
+ // have to be alphanumerical or underscore.
+ // "_DBASELOCK" is reserved (obsolete because first character is
+ // not alphabetical).
+ // No duplicated names.
+ if ( !rtl::isAsciiAlpha(aFieldName[0]) )
+ aFieldName = "N" + aFieldName;
+ OUStringBuffer aTmpStr;
+ sal_Unicode c;
+ for ( const sal_Unicode* p = aFieldName.getStr(); ( c = *p ) != 0; p++ )
+ {
+ if ( rtl::isAsciiAlpha(c) || rtl::isAsciiDigit(c) || c == '_' )
+ aTmpStr.append(c);
+ else
+ aTmpStr.append("_");
+ }
+ aFieldName = aTmpStr.makeStringAndClear();
+ if ( aFieldName.getLength() > 10 )
+ aFieldName = aFieldName.copy(0, 10);
+
+ if (!aFieldNames.insert(aFieldName).second)
+ { // Duplicated field name, append numeric suffix.
+ sal_uInt16 nSub = 1;
+ OUString aFixPart( aFieldName );
+ do
+ {
+ ++nSub;
+ OUString aVarPart = OUString::number( nSub );
+ if ( aFixPart.getLength() + aVarPart.getLength() > 10 )
+ aFixPart = aFixPart.copy( 0, 10 - aVarPart.getLength() );
+ aFieldName = aFixPart + aVarPart;
+ } while (!aFieldNames.insert(aFieldName).second);
+ }
+ }
+ else
+ {
+ aFieldName = "N" + OUString::number(nCol+1);
+ }
+
+ if ( !bTypeDefined )
+ { // Field type.
+ ScRefCellValue aCell(rDoc, ScAddress(nCol, nFirstDataRow, nTab));
+ if (aCell.isEmpty() || aCell.hasString())
+ nDbType = sdbc::DataType::VARCHAR;
+ else
+ {
+ sal_uInt32 nFormat = rDoc.GetNumberFormat( nCol, nFirstDataRow, nTab );
+ switch ( pNumFmt->GetType( nFormat ) )
+ {
+ case SvNumFormatType::LOGICAL :
+ nDbType = sdbc::DataType::BIT;
+ nFieldLen = 1;
+ break;
+ case SvNumFormatType::DATE :
+ nDbType = sdbc::DataType::DATE;
+ nFieldLen = 8;
+ break;
+ case SvNumFormatType::TIME :
+ case SvNumFormatType::DATETIME :
+ nDbType = sdbc::DataType::VARCHAR;
+ break;
+ default:
+ nDbType = sdbc::DataType::DECIMAL;
+ }
+ }
+ }
+ // Field length.
+ if ( nDbType == sdbc::DataType::VARCHAR && !nFieldLen )
+ { // Determine maximum field width.
+ nFieldLen = rDoc.GetMaxStringLen( nTab, nCol, nFirstDataRow,
+ nLastRow, eCharSet );
+ if ( nFieldLen == 0 )
+ nFieldLen = 1;
+ }
+ else if ( nDbType == sdbc::DataType::DECIMAL )
+ { // Determine maximum field width and precision.
+ sal_Int32 nLen;
+ sal_uInt16 nPrec;
+ nLen = rDoc.GetMaxNumberStringLen( nPrec, nTab, nCol,
+ nFirstDataRow, nLastRow );
+ // dBaseIII precision limit: 15
+ if ( nPrecision > 15 )
+ nPrecision = 15;
+ if ( nPrec > 15 )
+ nPrec = 15;
+ if ( bPrecDefined && nPrecision != nPrec )
+ {
+ if (nPrecision < nPrec)
+ {
+ // This is a hairy case. User defined nPrecision but a
+ // number format has more precision. Modifying a dBase
+ // field may as well render the resulting file useless for
+ // an application that relies on its defined structure,
+ // especially if we are resaving an already existing file.
+ // So who's right, the user who (or the loaded file that)
+ // defined the field, or the user who applied the format?
+ // Commit f59e350d1733125055f1144f8b3b1b0a46f6d1ca gave the
+ // format a higher priority, which is debatable.
+ SAL_WARN( "sc", "lcl_GetColumnTypes: conflicting dBase field precision for "
+ << aFieldName << " (" << nPrecision << "<" << nPrec << ")");
+
+ // Adjust length to larger predefined integer part. There
+ // may be a reason that the field was prepared for larger
+ // numbers.
+ if (nFieldLen - nPrecision > nLen - nPrec)
+ nLen = nFieldLen - (nPrecision ? nPrecision+1 : 0) + 1 + nPrec;
+ // And override precision.
+ nPrecision = nPrec;
+ }
+ else
+ {
+#if 1
+ // Adjust length to predefined precision.
+ nLen = nLen + ( nPrecision - nPrec );
+#else
+ /* If the above override for (nPrecision < nPrec) was not in place then
+ * nPrecision could be 0 and this would be the code path to correctly
+ * calculate nLen. But as is, nPrecision is never 0 here, see CID#982304 */
+
+ // Adjust length to predefined precision.
+ if ( nPrecision )
+ nLen = nLen + ( nPrecision - nPrec );
+ else
+ nLen -= nPrec+1; // also remove the decimal separator
+#endif
+ }
+ }
+ if (nFieldLen < nLen)
+ {
+ if (!bTypeDefined)
+ nFieldLen = nLen;
+ else
+ {
+ // Again a hairy case and conflict. Furthermore, the
+ // larger overall length may be a result of only a higher
+ // precision obtained from formats.
+ SAL_WARN( "sc", "lcl_GetColumnTypes: conflicting dBase field length for "
+ << aFieldName << " (" << nFieldLen << "<" << nLen << ")");
+ nFieldLen = nLen;
+ }
+ }
+ if ( !bPrecDefined )
+ nPrecision = nPrec;
+ if ( nFieldLen == 0 )
+ nFieldLen = 1;
+ else if ( nFieldLen > 19 )
+ nFieldLen = 19; // dBaseIII numeric field length limit: 19
+ if ( nPrecision && nFieldLen < nPrecision + 2 )
+ nFieldLen = nPrecision + 2; // 0. must fit into
+ // 538 MUST: Sdb internal representation adds 2 to the field length!
+ // To give the user what he wants we must subtract it here.
+ //! CAVEAT! There is no way to define a numeric field with a length
+ //! of 1 and no decimals!
+ nFieldLen = SvDbaseConverter::ConvertPrecisionToOdbc( nFieldLen, nPrecision );
+ }
+ if ( nFieldLen > 254 )
+ {
+ if ( nDbType == sdbc::DataType::VARCHAR )
+ { // Too long for a normal text field => memo field.
+ nDbType = sdbc::DataType::LONGVARCHAR;
+ nFieldLen = 10;
+ bHasMemo = true;
+ }
+ else
+ nFieldLen = 254; // bad luck...
+ }
+
+ pColNames[nField] = aFieldName;
+ pColTypes[nField] = nDbType;
+ pColLengths[nField] = nFieldLen;
+ pColScales[nField] = nPrecision;
+
+ ++nField;
+ }
+}
+
+void lcl_getLongVarCharEditString( OUString& rString,
+ const ScRefCellValue& rCell, ScFieldEditEngine& rEditEngine )
+{
+ if (!rCell.mpEditText)
+ return;
+
+ rEditEngine.SetTextCurrentDefaults(*rCell.mpEditText);
+ rString = rEditEngine.GetText( LINEEND_CRLF );
+}
+
+void lcl_getLongVarCharString(
+ OUString& rString, ScDocument& rDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, SvNumberFormatter& rNumFmt )
+{
+ const Color* pColor;
+ ScAddress aPos(nCol, nRow, nTab);
+ sal_uInt32 nFormat = rDoc.GetNumberFormat(aPos);
+ rString = ScCellFormat::GetString(rDoc, aPos, nFormat, &pColor, rNumFmt);
+}
+
+}
+
+#endif // HAVE_FEATURE_DBCONNECTIVITY
+
+ErrCode ScDocShell::DBaseExport( const OUString& rFullFileName, rtl_TextEncoding eCharSet, bool& bHasMemo )
+{
+#if !HAVE_FEATURE_DBCONNECTIVITY
+ (void) rFullFileName;
+ (void) eCharSet;
+ (void) bHasMemo;
+
+ return ERRCODE_IO_GENERAL;
+#else
+ // remove the file so the dBase driver doesn't find an invalid file
+ INetURLObject aDeleteObj( rFullFileName, INetProtocol::File );
+ KillFile( aDeleteObj );
+
+ ErrCode nErr = ERRCODE_NONE;
+
+ SCCOL nFirstCol, nLastCol;
+ SCROW nFirstRow, nLastRow;
+ SCTAB nTab = GetSaveTab();
+ m_pDocument->GetDataStart( nTab, nFirstCol, nFirstRow );
+ m_pDocument->GetCellArea( nTab, nLastCol, nLastRow );
+ if ( nFirstCol > nLastCol )
+ nFirstCol = nLastCol;
+ if ( nFirstRow > nLastRow )
+ nFirstRow = nLastRow;
+ ScProgress aProgress( this, ScResId( STR_SAVE_DOC ),
+ nLastRow - nFirstRow, true );
+ SvNumberFormatter* pNumFmt = m_pDocument->GetFormatTable();
+
+ bool bHasFieldNames = true;
+ for ( SCCOL nDocCol = nFirstCol; nDocCol <= nLastCol && bHasFieldNames; nDocCol++ )
+ { // only Strings in first row => are field names
+ if ( !m_pDocument->HasStringData( nDocCol, nFirstRow, nTab ) )
+ bHasFieldNames = false;
+ }
+
+ sal_Int32 nColCount = nLastCol - nFirstCol + 1;
+ uno::Sequence<OUString> aColNames( nColCount );
+ uno::Sequence<sal_Int32> aColTypes( nColCount );
+ uno::Sequence<sal_Int32> aColLengths( nColCount );
+ uno::Sequence<sal_Int32> aColScales( nColCount );
+
+ ScRange aDataRange( nFirstCol, nFirstRow, nTab, nLastCol, nLastRow, nTab );
+ lcl_GetColumnTypes( *this, aDataRange, bHasFieldNames,
+ aColNames.getArray(), aColTypes.getArray(),
+ aColLengths.getArray(), aColScales.getArray(),
+ bHasMemo, eCharSet );
+ // also needed for exception catch
+ SCROW nDocRow = 0;
+ ScFieldEditEngine aEditEngine(m_pDocument.get(), m_pDocument->GetEditPool());
+ OUString aString;
+
+ try
+ {
+ uno::Reference<sdbc::XDriverManager2> xDrvMan;
+ uno::Reference<sdbc::XConnection> xConnection;
+ OUString aTabName;
+ ErrCode nRet = lcl_getDBaseConnection(xDrvMan,xConnection,aTabName,rFullFileName,eCharSet);
+ if ( !xConnection.is() || !xDrvMan.is() )
+ return nRet;
+ ::utl::DisposableComponent aConnectionHelper(xConnection);
+
+ // get dBase driver
+ uno::Reference< sdbcx::XDataDefinitionSupplier > xDDSup( xDrvMan->getDriverByURL( xConnection->getMetaData()->getURL() ), uno::UNO_QUERY );
+ if ( !xDDSup.is() )
+ return SCERR_EXPORT_CONNECT;
+
+ // create table
+ uno::Reference<sdbcx::XTablesSupplier> xTablesSupp =xDDSup->getDataDefinitionByConnection( xConnection );
+ OSL_ENSURE( xTablesSupp.is(), "can't get Data Definition" );
+ if (!xTablesSupp.is()) return SCERR_EXPORT_CONNECT;
+
+ uno::Reference<container::XNameAccess> xTables = xTablesSupp->getTables();
+ OSL_ENSURE( xTables.is(), "can't get Tables" );
+ if (!xTables.is()) return SCERR_EXPORT_CONNECT;
+
+ uno::Reference<sdbcx::XDataDescriptorFactory> xTablesFact( xTables, uno::UNO_QUERY );
+ OSL_ENSURE( xTablesFact.is(), "can't get tables factory" );
+ if (!xTablesFact.is()) return SCERR_EXPORT_CONNECT;
+
+ uno::Reference<sdbcx::XAppend> xTablesAppend( xTables, uno::UNO_QUERY );
+ OSL_ENSURE( xTablesAppend.is(), "can't get tables XAppend" );
+ if (!xTablesAppend.is()) return SCERR_EXPORT_CONNECT;
+
+ uno::Reference<beans::XPropertySet> xTableDesc = xTablesFact->createDataDescriptor();
+ OSL_ENSURE( xTableDesc.is(), "can't get table descriptor" );
+ if (!xTableDesc.is()) return SCERR_EXPORT_CONNECT;
+
+ xTableDesc->setPropertyValue( SC_DBPROP_NAME, uno::Any(aTabName) );
+
+ // create columns
+
+ uno::Reference<sdbcx::XColumnsSupplier> xColumnsSupp( xTableDesc, uno::UNO_QUERY );
+ OSL_ENSURE( xColumnsSupp.is(), "can't get columns supplier" );
+ if (!xColumnsSupp.is()) return SCERR_EXPORT_CONNECT;
+
+ uno::Reference<container::XNameAccess> xColumns = xColumnsSupp->getColumns();
+ OSL_ENSURE( xColumns.is(), "can't get columns" );
+ if (!xColumns.is()) return SCERR_EXPORT_CONNECT;
+
+ uno::Reference<sdbcx::XDataDescriptorFactory> xColumnsFact( xColumns, uno::UNO_QUERY );
+ OSL_ENSURE( xColumnsFact.is(), "can't get columns factory" );
+ if (!xColumnsFact.is()) return SCERR_EXPORT_CONNECT;
+
+ uno::Reference<sdbcx::XAppend> xColumnsAppend( xColumns, uno::UNO_QUERY );
+ OSL_ENSURE( xColumnsAppend.is(), "can't get columns XAppend" );
+ if (!xColumnsAppend.is()) return SCERR_EXPORT_CONNECT;
+
+ const OUString* pColNames = aColNames.getConstArray();
+ const sal_Int32* pColTypes = aColTypes.getConstArray();
+ const sal_Int32* pColLengths = aColLengths.getConstArray();
+ const sal_Int32* pColScales = aColScales.getConstArray();
+ sal_Int32 nCol;
+
+ for (nCol=0; nCol<nColCount; nCol++)
+ {
+ uno::Reference<beans::XPropertySet> xColumnDesc = xColumnsFact->createDataDescriptor();
+ OSL_ENSURE( xColumnDesc.is(), "can't get column descriptor" );
+ if (!xColumnDesc.is()) return SCERR_EXPORT_CONNECT;
+
+ xColumnDesc->setPropertyValue( SC_DBPROP_NAME, uno::Any(pColNames[nCol]) );
+
+ xColumnDesc->setPropertyValue( SC_DBPROP_TYPE, uno::Any(pColTypes[nCol]) );
+
+ xColumnDesc->setPropertyValue( SC_DBPROP_PRECISION, uno::Any(pColLengths[nCol]) );
+
+ xColumnDesc->setPropertyValue( SC_DBPROP_SCALE, uno::Any(pColScales[nCol]) );
+
+ xColumnsAppend->appendByDescriptor( xColumnDesc );
+ }
+
+ xTablesAppend->appendByDescriptor( xTableDesc );
+
+ // get row set for writing
+ uno::Reference<lang::XMultiServiceFactory> xFactory = comphelper::getProcessServiceFactory();
+ uno::Reference<sdbc::XRowSet> xRowSet( xFactory->createInstance(SC_SERVICE_ROWSET),
+ uno::UNO_QUERY);
+ ::utl::DisposableComponent aRowSetHelper(xRowSet);
+ uno::Reference<beans::XPropertySet> xRowProp( xRowSet, uno::UNO_QUERY );
+ OSL_ENSURE( xRowProp.is(), "can't get RowSet" );
+ if (!xRowProp.is()) return SCERR_EXPORT_CONNECT;
+
+ xRowProp->setPropertyValue( SC_DBPROP_ACTIVECONNECTION, uno::Any(xConnection) );
+
+ xRowProp->setPropertyValue( SC_DBPROP_COMMANDTYPE, uno::Any(sal_Int32(sdb::CommandType::TABLE)) );
+
+ xRowProp->setPropertyValue( SC_DBPROP_COMMAND, uno::Any(aTabName) );
+
+ xRowSet->execute();
+
+ // write data rows
+
+ uno::Reference<sdbc::XResultSetUpdate> xResultUpdate( xRowSet, uno::UNO_QUERY );
+ OSL_ENSURE( xResultUpdate.is(), "can't get XResultSetUpdate" );
+ if (!xResultUpdate.is()) return SCERR_EXPORT_CONNECT;
+
+ uno::Reference<sdbc::XRowUpdate> xRowUpdate( xRowSet, uno::UNO_QUERY );
+ OSL_ENSURE( xRowUpdate.is(), "can't get XRowUpdate" );
+ if (!xRowUpdate.is()) return SCERR_EXPORT_CONNECT;
+
+ SCROW nFirstDataRow = ( bHasFieldNames ? nFirstRow + 1 : nFirstRow );
+ double fVal;
+
+ for ( nDocRow = nFirstDataRow; nDocRow <= nLastRow; nDocRow++ )
+ {
+ xResultUpdate->moveToInsertRow();
+
+ for (nCol=0; nCol<nColCount; nCol++)
+ {
+ SCCOL nDocCol = sal::static_int_cast<SCCOL>( nFirstCol + nCol );
+
+ switch (pColTypes[nCol])
+ {
+ case sdbc::DataType::LONGVARCHAR:
+ {
+ ScRefCellValue aCell(*m_pDocument, ScAddress(nDocCol, nDocRow, nTab));
+ if (!aCell.isEmpty())
+ {
+ if (aCell.meType == CELLTYPE_EDIT)
+ { // preserve paragraphs
+ lcl_getLongVarCharEditString(aString, aCell, aEditEngine);
+ }
+ else
+ {
+ lcl_getLongVarCharString(
+ aString, *m_pDocument, nDocCol, nDocRow, nTab, *pNumFmt);
+ }
+ xRowUpdate->updateString( nCol+1, aString );
+ }
+ else
+ xRowUpdate->updateNull( nCol+1 );
+ }
+ break;
+
+ case sdbc::DataType::VARCHAR:
+ aString = m_pDocument->GetString(nDocCol, nDocRow, nTab);
+ xRowUpdate->updateString( nCol+1, aString );
+ if ( nErr == ERRCODE_NONE && pColLengths[nCol] < aString.getLength() )
+ nErr = SCWARN_EXPORT_DATALOST;
+ break;
+
+ case sdbc::DataType::DATE:
+ {
+ fVal = m_pDocument->GetValue( nDocCol, nDocRow, nTab );
+ // differentiate between 0 with value and 0 no-value
+ bool bIsNull = (fVal == 0.0);
+ if ( bIsNull )
+ bIsNull = !m_pDocument->HasValueData( nDocCol, nDocRow, nTab );
+ if ( bIsNull )
+ {
+ xRowUpdate->updateNull( nCol+1 );
+ if ( nErr == ERRCODE_NONE &&
+ m_pDocument->HasStringData( nDocCol, nDocRow, nTab ) )
+ nErr = SCWARN_EXPORT_DATALOST;
+ }
+ else
+ {
+ Date aDate = pNumFmt->GetNullDate(); // tools date
+ aDate.AddDays(fVal); //! approxfloor?
+ xRowUpdate->updateDate( nCol+1, aDate.GetUNODate() );
+ }
+ }
+ break;
+
+ case sdbc::DataType::DECIMAL:
+ case sdbc::DataType::BIT:
+ fVal = m_pDocument->GetValue( nDocCol, nDocRow, nTab );
+ if ( fVal == 0.0 && nErr == ERRCODE_NONE &&
+ m_pDocument->HasStringData( nDocCol, nDocRow, nTab ) )
+ nErr = SCWARN_EXPORT_DATALOST;
+ if ( pColTypes[nCol] == sdbc::DataType::BIT )
+ xRowUpdate->updateBoolean( nCol+1, ( fVal != 0.0 ) );
+ else
+ xRowUpdate->updateDouble( nCol+1, fVal );
+ break;
+
+ default:
+ OSL_FAIL( "ScDocShell::DBaseExport: unknown FieldType" );
+ if ( nErr == ERRCODE_NONE )
+ nErr = SCWARN_EXPORT_DATALOST;
+ fVal = m_pDocument->GetValue( nDocCol, nDocRow, nTab );
+ xRowUpdate->updateDouble( nCol+1, fVal );
+ }
+ }
+
+ xResultUpdate->insertRow();
+
+ //! error handling and recovery of old
+ //! ScDocShell::SbaSdbExport is still missing!
+
+ aProgress.SetStateOnPercent( nDocRow - nFirstRow );
+ }
+
+ comphelper::disposeComponent( xRowSet );
+ comphelper::disposeComponent( xConnection );
+ }
+ catch ( const sdbc::SQLException& aException )
+ {
+ sal_Int32 nError = aException.ErrorCode;
+ TOOLS_WARN_EXCEPTION("sc", "ScDocShell::DBaseExport");
+
+ if (nError == 22018 || nError == 22001)
+ {
+ // SQL error 22018: Character not in target encoding.
+ // SQL error 22001: String length exceeds field width (after encoding).
+ bool bEncErr = (nError == 22018);
+ bool bIsOctetTextEncoding = rtl_isOctetTextEncoding( eCharSet);
+ OSL_ENSURE( !bEncErr || bIsOctetTextEncoding, "ScDocShell::DBaseExport: encoding error and not an octet textencoding");
+ SCCOL nDocCol = nFirstCol;
+ const sal_Int32* pColTypes = aColTypes.getConstArray();
+ const sal_Int32* pColLengths = aColLengths.getConstArray();
+ ScHorizontalCellIterator aIter( *m_pDocument, nTab, nFirstCol,
+ nDocRow, nLastCol, nDocRow);
+ bool bTest = true;
+ while (bTest)
+ {
+ ScRefCellValue* pCell = aIter.GetNext( nDocCol, nDocRow);
+ if (!pCell)
+ break;
+ SCCOL nCol = nDocCol - nFirstCol;
+ switch (pColTypes[nCol])
+ {
+ case sdbc::DataType::LONGVARCHAR:
+ {
+ if (pCell->meType == CELLTYPE_EDIT)
+ lcl_getLongVarCharEditString(aString, *pCell, aEditEngine);
+ else
+ lcl_getLongVarCharString(
+ aString, *m_pDocument, nDocCol, nDocRow, nTab, *pNumFmt);
+ }
+ break;
+
+ case sdbc::DataType::VARCHAR:
+ aString = m_pDocument->GetString(nDocCol, nDocRow, nTab);
+ break;
+
+ // NOTE: length of DECIMAL fields doesn't need to be
+ // checked here, the database driver adjusts the field
+ // width accordingly.
+
+ default:
+ bTest = false;
+ }
+ if (bTest)
+ {
+ sal_Int32 nLen;
+ if (bIsOctetTextEncoding)
+ {
+ OString aOString;
+ if (!aString.convertToString( &aOString, eCharSet,
+ RTL_UNICODETOTEXT_FLAGS_UNDEFINED_ERROR |
+ RTL_UNICODETOTEXT_FLAGS_INVALID_ERROR))
+ {
+ bTest = false;
+ bEncErr = true;
+ }
+ nLen = aOString.getLength();
+ if (!bTest)
+ SAL_WARN("sc", "ScDocShell::DBaseExport encoding error, string with default replacements: ``" << aString << "''");
+ }
+ else
+ nLen = aString.getLength() * sizeof(sal_Unicode);
+ if (!bEncErr &&
+ pColTypes[nCol] != sdbc::DataType::LONGVARCHAR &&
+ pColLengths[nCol] < nLen)
+ {
+ bTest = false;
+ SAL_INFO("sc", "ScDocShell::DBaseExport: field width: " << pColLengths[nCol] << ", encoded length: " << nLen);
+ }
+ }
+ else
+ bTest = true;
+ }
+ OUString sPosition(ScAddress(nDocCol, nDocRow, nTab).GetColRowString());
+ OUString sEncoding(SvxTextEncodingTable::GetTextString(eCharSet));
+ nErr = *new TwoStringErrorInfo( (bEncErr ? SCERR_EXPORT_ENCODING :
+ SCERR_EXPORT_FIELDWIDTH), sPosition, sEncoding,
+ DialogMask::ButtonsOk | DialogMask::MessageError);
+ }
+ else if ( !aException.Message.isEmpty() )
+ nErr = *new StringErrorInfo( SCERR_EXPORT_SQLEXCEPTION, aException.Message, DialogMask::ButtonsOk | DialogMask::MessageError);
+ else
+ nErr = SCERR_EXPORT_DATA;
+ }
+ catch ( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "Unexpected exception in database");
+ nErr = ERRCODE_IO_GENERAL;
+ }
+
+ return nErr;
+#endif // HAVE_FEATURE_DBCONNECTIVITY
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/docshimp.hxx b/sc/source/ui/docshell/docshimp.hxx
new file mode 100644
index 000000000..58cfb23ac
--- /dev/null
+++ b/sc/source/ui/docshell/docshimp.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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in 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/ctrltool.hxx>
+#include <sfx2/docinsert.hxx>
+#include <sfx2/request.hxx>
+
+struct DocShell_Impl
+{
+ bool bIgnoreLostRedliningWarning;
+ std::unique_ptr<FontList> pFontList;
+ std::unique_ptr<sfx2::DocumentInserter> pDocInserter;
+ std::unique_ptr<SfxRequest> pRequest;
+
+ DocShell_Impl() :
+ bIgnoreLostRedliningWarning( false )
+ {}
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/documentlinkmgr.cxx b/sc/source/ui/docshell/documentlinkmgr.cxx
new file mode 100644
index 000000000..79a86d08b
--- /dev/null
+++ b/sc/source/ui/docshell/documentlinkmgr.cxx
@@ -0,0 +1,274 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/doublecheckedinit.hxx>
+#include <documentlinkmgr.hxx>
+#include <datastream.hxx>
+#include <ddelink.hxx>
+#include <webservicelink.hxx>
+#include <strings.hrc>
+#include <scresid.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/linksrc.hxx>
+#include <o3tl/deleter.hxx>
+#include <svx/svdoole2.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <memory>
+
+namespace sc {
+
+struct DocumentLinkManagerImpl
+{
+ SfxObjectShell* mpShell;
+ std::unique_ptr<DataStream, o3tl::default_delete<DataStream>> mpDataStream;
+ std::atomic<sfx2::LinkManager*> mpLinkManager;
+
+ DocumentLinkManagerImpl(const DocumentLinkManagerImpl&) = delete;
+ const DocumentLinkManagerImpl& operator=(const DocumentLinkManagerImpl&) = delete;
+
+ explicit DocumentLinkManagerImpl(SfxObjectShell* pShell)
+ : mpShell(pShell), mpLinkManager(nullptr) {}
+
+ ~DocumentLinkManagerImpl()
+ {
+ // Shared base links
+ sfx2::LinkManager* linkManager = mpLinkManager;
+ if (linkManager)
+ {
+ sfx2::SvLinkSources aTemp = linkManager->GetServers();
+ for (const auto& pLinkSource : aTemp)
+ pLinkSource->Closed();
+
+ if (!linkManager->GetLinks().empty())
+ linkManager->Remove(0, linkManager->GetLinks().size());
+ }
+ delete linkManager;
+ }
+};
+
+DocumentLinkManager::DocumentLinkManager( SfxObjectShell* pShell ) :
+ mpImpl(new DocumentLinkManagerImpl(pShell)) {}
+
+DocumentLinkManager::~DocumentLinkManager()
+{
+}
+
+void DocumentLinkManager::setDataStream( DataStream* p )
+{
+ mpImpl->mpDataStream.reset(p);
+}
+
+DataStream* DocumentLinkManager::getDataStream()
+{
+ return mpImpl->mpDataStream.get();
+}
+
+const DataStream* DocumentLinkManager::getDataStream() const
+{
+ return mpImpl->mpDataStream.get();
+}
+
+sfx2::LinkManager* DocumentLinkManager::getLinkManager( bool bCreate )
+{
+ if (bCreate && mpImpl->mpShell)
+ return comphelper::doubleCheckedInit( mpImpl->mpLinkManager,
+ [this]() { return new sfx2::LinkManager(mpImpl->mpShell); } );
+ return mpImpl->mpLinkManager;
+}
+
+const sfx2::LinkManager* DocumentLinkManager::getExistingLinkManager() const
+{
+ return mpImpl->mpLinkManager;
+}
+
+bool DocumentLinkManager::idleCheckLinks()
+{
+ sfx2::LinkManager* pMgr = mpImpl->mpLinkManager;
+ if (!pMgr)
+ return false;
+
+ bool bAnyLeft = false;
+ const sfx2::SvBaseLinks& rLinks = pMgr->GetLinks();
+ for (const auto & rLink : rLinks)
+ {
+ sfx2::SvBaseLink* pBase = rLink.get();
+ ScDdeLink* pDdeLink = dynamic_cast<ScDdeLink*>(pBase);
+ if (!pDdeLink || !pDdeLink->NeedsUpdate())
+ continue;
+
+ pDdeLink->TryUpdate();
+ if (pDdeLink->NeedsUpdate()) // Was not successful?
+ bAnyLeft = true;
+ }
+
+ return bAnyLeft;
+}
+
+bool DocumentLinkManager::hasDdeLinks() const
+{
+ return hasDdeOrOleOrWebServiceLinks(true, false, false);
+}
+
+bool DocumentLinkManager::hasDdeOrOleOrWebServiceLinks() const
+{
+ return hasDdeOrOleOrWebServiceLinks(true, true, true);
+}
+
+bool DocumentLinkManager::hasDdeOrOleOrWebServiceLinks(bool bDde, bool bOle, bool bWebService) const
+{
+ sfx2::LinkManager* pMgr = mpImpl->mpLinkManager;
+ if (!pMgr)
+ return false;
+
+ const sfx2::SvBaseLinks& rLinks = pMgr->GetLinks();
+ for (const auto & rLink : rLinks)
+ {
+ sfx2::SvBaseLink* pBase = rLink.get();
+ if (bDde && dynamic_cast<ScDdeLink*>(pBase))
+ return true;
+ if (bOle && (dynamic_cast<SdrEmbedObjectLink*>(pBase) || dynamic_cast<SdrIFrameLink*>(pBase)))
+ return true;
+ if (bWebService && dynamic_cast<ScWebServiceLink*>(pBase))
+ return true;
+ }
+
+ return false;
+}
+
+bool DocumentLinkManager::updateDdeOrOleOrWebServiceLinks(weld::Window* pWin)
+{
+ sfx2::LinkManager* pMgr = mpImpl->mpLinkManager;
+ if (!pMgr)
+ return false;
+
+ const sfx2::SvBaseLinks& rLinks = pMgr->GetLinks();
+
+ // If the update takes longer, reset all values so that nothing
+ // old (wrong) is left behind
+ bool bAny = false;
+ for (const auto & rLink : rLinks)
+ {
+ sfx2::SvBaseLink* pBase = rLink.get();
+
+ SdrEmbedObjectLink* pOleLink = dynamic_cast<SdrEmbedObjectLink*>(pBase);
+ if (pOleLink)
+ {
+ pOleLink->Update();
+ continue;
+ }
+
+ SdrIFrameLink* pIFrameLink = dynamic_cast<SdrIFrameLink*>(pBase);
+ if (pIFrameLink)
+ {
+ pIFrameLink->Update();
+ continue;
+ }
+
+ ScWebServiceLink* pWebserviceLink = dynamic_cast<ScWebServiceLink*>(pBase);
+ if (pWebserviceLink)
+ {
+ pWebserviceLink->Update();
+ continue;
+ }
+
+ ScDdeLink* pDdeLink = dynamic_cast<ScDdeLink*>(pBase);
+ if (!pDdeLink)
+ continue;
+
+ if (pDdeLink->Update())
+ bAny = true;
+ else
+ {
+ // Update failed. Notify the user.
+ const OUString& aFile = pDdeLink->GetTopic();
+ const OUString& aElem = pDdeLink->GetItem();
+ const OUString& aType = pDdeLink->GetAppl();
+
+ OUString sMessage =
+ ScResId(SCSTR_DDEDOC_NOT_LOADED) +
+ "\n\n"
+ "Source : " +
+ aFile +
+ "\nElement : " +
+ aElem +
+ "\nType : " +
+ aType;
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pWin,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ sMessage));
+ xBox->run();
+ }
+ }
+
+ pMgr->CloseCachedComps();
+
+ return bAny;
+}
+
+void DocumentLinkManager::updateDdeLink( std::u16string_view rAppl, std::u16string_view rTopic, std::u16string_view rItem )
+{
+ sfx2::LinkManager* pMgr = mpImpl->mpLinkManager;
+ if (!pMgr)
+ return;
+
+ const sfx2::SvBaseLinks& rLinks = pMgr->GetLinks();
+
+ for (const auto & rLink : rLinks)
+ {
+ ::sfx2::SvBaseLink* pBase = rLink.get();
+ ScDdeLink* pDdeLink = dynamic_cast<ScDdeLink*>(pBase);
+ if (!pDdeLink)
+ continue;
+
+ if ( pDdeLink->GetAppl() == rAppl &&
+ pDdeLink->GetTopic() == rTopic &&
+ pDdeLink->GetItem() == rItem )
+ {
+ pDdeLink->TryUpdate();
+ // Could be multiple (Mode), so continue searching
+ }
+ }
+}
+
+size_t DocumentLinkManager::getDdeLinkCount() const
+{
+ sfx2::LinkManager* pMgr = mpImpl->mpLinkManager;
+ if (!pMgr)
+ return 0;
+
+ size_t nDdeCount = 0;
+ const sfx2::SvBaseLinks& rLinks = pMgr->GetLinks();
+ for (const auto & rLink : rLinks)
+ {
+ ::sfx2::SvBaseLink* pBase = rLink.get();
+ ScDdeLink* pDdeLink = dynamic_cast<ScDdeLink*>(pBase);
+ if (!pDdeLink)
+ continue;
+
+ ++nDdeCount;
+ }
+
+ return nDdeCount;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/editable.cxx b/sc/source/ui/docshell/editable.cxx
new file mode 100644
index 000000000..86bbb9f2e
--- /dev/null
+++ b/sc/source/ui/docshell/editable.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 <editable.hxx>
+#include <document.hxx>
+#include <viewfunc.hxx>
+#include <globstr.hrc>
+
+ScEditableTester::ScEditableTester() :
+ mbIsEditable(true),
+ mbOnlyMatrix(true)
+{
+}
+
+ScEditableTester::ScEditableTester( const ScDocument& rDoc, SCTAB nTab,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bNoMatrixAtAll ) :
+ mbIsEditable(true),
+ mbOnlyMatrix(true)
+{
+ TestBlock( rDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow, bNoMatrixAtAll );
+}
+
+ScEditableTester::ScEditableTester( const ScDocument& rDoc,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark ) :
+ mbIsEditable(true),
+ mbOnlyMatrix(true)
+{
+ TestSelectedBlock( rDoc, nStartCol, nStartRow, nEndCol, nEndRow, rMark );
+}
+
+ScEditableTester::ScEditableTester( const ScDocument& rDoc, const ScRange& rRange ) :
+ mbIsEditable(true),
+ mbOnlyMatrix(true)
+{
+ TestRange( rDoc, rRange );
+}
+
+ScEditableTester::ScEditableTester( const ScDocument& rDoc, const ScMarkData& rMark ) :
+ mbIsEditable(true),
+ mbOnlyMatrix(true)
+{
+ TestSelection( rDoc, rMark );
+}
+
+ScEditableTester::ScEditableTester( ScViewFunc* pView ) :
+ mbIsEditable(true),
+ mbOnlyMatrix(true)
+{
+ bool bThisMatrix;
+ if ( !pView->SelectionEditable( &bThisMatrix ) )
+ {
+ mbIsEditable = false;
+ if ( !bThisMatrix )
+ mbOnlyMatrix = false;
+ }
+}
+
+ScEditableTester::ScEditableTester(
+ const ScDocument& rDoc, sc::ColRowEditAction eAction, SCCOLROW nStart, SCCOLROW nEnd, const ScMarkData& rMark ) :
+ ScEditableTester()
+{
+ TestBlockForAction(rDoc, eAction, nStart, nEnd, rMark);
+}
+
+void ScEditableTester::TestBlock( const ScDocument& rDoc, SCTAB nTab,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bNoMatrixAtAll )
+{
+ if (mbIsEditable || mbOnlyMatrix)
+ {
+ bool bThisMatrix;
+ if (!rDoc.IsBlockEditable( nTab, nStartCol, nStartRow, nEndCol, nEndRow, &bThisMatrix, bNoMatrixAtAll))
+ {
+ mbIsEditable = false;
+ if ( !bThisMatrix )
+ mbOnlyMatrix = false;
+ }
+ }
+}
+
+void ScEditableTester::TestSelectedBlock( const ScDocument& rDoc,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark )
+{
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (const auto& rTab : rMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ TestBlock( rDoc, rTab, nStartCol, nStartRow, nEndCol, nEndRow, false );
+ }
+}
+
+void ScEditableTester::TestRange( const ScDocument& rDoc, const ScRange& rRange )
+{
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCTAB nStartTab = rRange.aStart.Tab();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nEndTab = rRange.aEnd.Tab();
+ for (SCTAB nTab=nStartTab; nTab<=nEndTab; nTab++)
+ TestBlock( rDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow, false );
+}
+
+void ScEditableTester::TestSelection( const ScDocument& rDoc, const ScMarkData& rMark )
+{
+ if (mbIsEditable || mbOnlyMatrix)
+ {
+ bool bThisMatrix;
+ if ( !rDoc.IsSelectionEditable( rMark, &bThisMatrix ) )
+ {
+ mbIsEditable = false;
+ if ( !bThisMatrix )
+ mbOnlyMatrix = false;
+ }
+ }
+}
+
+void ScEditableTester::TestBlockForAction(
+ const ScDocument& rDoc, sc::ColRowEditAction eAction, SCCOLROW nStart, SCCOLROW nEnd,
+ const ScMarkData& rMark )
+{
+ mbOnlyMatrix = false;
+
+ for (const auto& rTab : rMark)
+ {
+ if (!mbIsEditable)
+ return;
+
+ mbIsEditable = rDoc.IsEditActionAllowed(eAction, rTab, nStart, nEnd);
+ }
+}
+
+TranslateId ScEditableTester::GetMessageId() const
+{
+ if (mbIsEditable)
+ return {};
+ else if (mbOnlyMatrix)
+ return STR_MATRIXFRAGMENTERR;
+ else
+ return STR_PROTECTIONERR;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/externalrefmgr.cxx b/sc/source/ui/docshell/externalrefmgr.cxx
new file mode 100644
index 000000000..fe731684a
--- /dev/null
+++ b/sc/source/ui/docshell/externalrefmgr.cxx
@@ -0,0 +1,3319 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <externalrefmgr.hxx>
+#include <document.hxx>
+#include <token.hxx>
+#include <tokenarray.hxx>
+#include <address.hxx>
+#include <tablink.hxx>
+#include <docsh.hxx>
+#include <scextopt.hxx>
+#include <rangenam.hxx>
+#include <formulacell.hxx>
+#include <viewdata.hxx>
+#include <tabvwsh.hxx>
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <cellvalue.hxx>
+#include <defaultsoptions.hxx>
+#include <scmod.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <osl/file.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/event.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/itemset.hxx>
+#include <svl/numformat.hxx>
+#include <svl/stritem.hxx>
+#include <svl/urihelper.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/charclass.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/ucbhelper.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <stringutil.hxx>
+#include <scmatrix.hxx>
+#include <columnspanset.hxx>
+#include <column.hxx>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/document/UpdateDocMode.hpp>
+#include <sal/log.hxx>
+
+#include <memory>
+#include <algorithm>
+
+using ::std::unique_ptr;
+using ::com::sun::star::uno::Any;
+using ::std::vector;
+using ::std::find_if;
+using ::std::for_each;
+using ::std::distance;
+using ::std::pair;
+using namespace formula;
+
+#define SRCDOC_LIFE_SPAN 30000 // 5 minutes (in 100th of a sec)
+#define SRCDOC_SCAN_INTERVAL 1000*30 // every 30 seconds (in msec)
+
+namespace {
+
+class TabNameSearchPredicate
+{
+public:
+ explicit TabNameSearchPredicate(const OUString& rSearchName) :
+ maSearchName(ScGlobal::getCharClass().uppercase(rSearchName))
+ {
+ }
+
+ bool operator()(const ScExternalRefCache::TableName& rTabNameSet) const
+ {
+ // Ok, I'm doing case insensitive search here.
+ return rTabNameSet.maUpperName == maSearchName;
+ }
+
+private:
+ OUString maSearchName;
+};
+
+class FindSrcFileByName
+{
+public:
+ explicit FindSrcFileByName(const OUString& rMatchName) :
+ mrMatchName(rMatchName)
+ {
+ }
+
+ bool operator()(const ScExternalRefManager::SrcFileData& rSrcData) const
+ {
+ return rSrcData.maFileName == mrMatchName;
+ }
+
+private:
+ const OUString& mrMatchName;
+};
+
+class NotifyLinkListener
+{
+public:
+ NotifyLinkListener(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType) :
+ mnFileId(nFileId), meType(eType) {}
+
+ void operator() (ScExternalRefManager::LinkListener* p) const
+ {
+ p->notify(mnFileId, meType);
+ }
+private:
+ sal_uInt16 mnFileId;
+ ScExternalRefManager::LinkUpdateType meType;
+};
+
+struct UpdateFormulaCell
+{
+ void operator() (ScFormulaCell* pCell) const
+ {
+ // Check to make sure the cell really contains svExternal*.
+ // External names, external cell and range references all have a
+ // token of svExternal*. Additionally check for INDIRECT() that can be
+ // called with any constructed URI string.
+ ScTokenArray* pCode = pCell->GetCode();
+ if (!pCode->HasExternalRef() && !pCode->HasOpCode(ocIndirect))
+ return;
+
+ if (pCode->GetCodeError() != FormulaError::NONE)
+ {
+ // Clear the error code, or a cell with error won't get re-compiled.
+ pCode->SetCodeError(FormulaError::NONE);
+ pCell->SetCompile(true);
+ pCell->CompileTokenArray();
+ }
+
+ pCell->SetDirty();
+ }
+};
+
+class RemoveFormulaCell
+{
+public:
+ explicit RemoveFormulaCell(ScFormulaCell* p) : mpCell(p) {}
+ void operator() (pair<const sal_uInt16, ScExternalRefManager::RefCellSet>& r) const
+ {
+ r.second.erase(mpCell);
+ }
+private:
+ ScFormulaCell* mpCell;
+};
+
+class ConvertFormulaToStatic
+{
+public:
+ explicit ConvertFormulaToStatic(ScDocument* pDoc) : mpDoc(pDoc) {}
+ void operator() (ScFormulaCell* pCell) const
+ {
+ ScAddress aPos = pCell->aPos;
+
+ // We don't check for empty cells because empty external cells are
+ // treated as having a value of 0.
+
+ if (pCell->IsValue())
+ {
+ // Turn this into value cell.
+ mpDoc->SetValue(aPos, pCell->GetValue());
+ }
+ else
+ {
+ // string cell otherwise.
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ mpDoc->SetString(aPos, pCell->GetString().getString(), &aParam);
+ }
+ }
+private:
+ ScDocument* mpDoc;
+};
+
+/**
+ * Check whether a named range contains an external reference to a
+ * particular document.
+ */
+bool hasRefsToSrcDoc(ScRangeData& rData, sal_uInt16 nFileId)
+{
+ ScTokenArray* pArray = rData.GetCode();
+ if (!pArray)
+ return false;
+
+ formula::FormulaTokenArrayPlainIterator aIter(*pArray);
+ formula::FormulaToken* p = aIter.GetNextReference();
+ for (; p; p = aIter.GetNextReference())
+ {
+ if (!p->IsExternalRef())
+ continue;
+
+ if (p->GetIndex() == nFileId)
+ return true;
+ }
+ return false;
+}
+
+class EraseRangeByIterator
+{
+ ScRangeName& mrRanges;
+public:
+ explicit EraseRangeByIterator(ScRangeName& rRanges) : mrRanges(rRanges) {}
+ void operator() (const ScRangeName::const_iterator& itr)
+ {
+ mrRanges.erase(itr);
+ }
+};
+
+/**
+ * Remove all named ranges that contain references to specified source
+ * document.
+ */
+void removeRangeNamesBySrcDoc(ScRangeName& rRanges, sal_uInt16 nFileId)
+{
+ ScRangeName::const_iterator itr = rRanges.begin(), itrEnd = rRanges.end();
+ vector<ScRangeName::const_iterator> v;
+ for (; itr != itrEnd; ++itr)
+ {
+ if (hasRefsToSrcDoc(*itr->second, nFileId))
+ v.push_back(itr);
+ }
+ for_each(v.begin(), v.end(), EraseRangeByIterator(rRanges));
+}
+
+}
+
+ScExternalRefCache::Table::Table()
+ : mbReferenced( true )
+ // Prevent accidental data loss due to lack of knowledge.
+{
+}
+
+ScExternalRefCache::Table::~Table()
+{
+}
+
+void ScExternalRefCache::Table::clear()
+{
+ maRows.clear();
+ maCachedRanges.RemoveAll();
+ mbReferenced = true;
+}
+
+void ScExternalRefCache::Table::setReferenced( bool bReferenced )
+{
+ mbReferenced = bReferenced;
+}
+
+bool ScExternalRefCache::Table::isReferenced() const
+{
+ return mbReferenced;
+}
+
+void ScExternalRefCache::Table::setCell(SCCOL nCol, SCROW nRow, TokenRef const & pToken, sal_uLong nFmtIndex, bool bSetCacheRange)
+{
+ using ::std::pair;
+ RowsDataType::iterator itrRow = maRows.find(nRow);
+ if (itrRow == maRows.end())
+ {
+ // This row does not exist yet.
+ pair<RowsDataType::iterator, bool> res = maRows.emplace(
+ nRow, RowDataType());
+
+ if (!res.second)
+ return;
+
+ itrRow = res.first;
+ }
+
+ // Insert this token into the specified column location. I don't need to
+ // check for existing data. Just overwrite it.
+ RowDataType& rRow = itrRow->second;
+ ScExternalRefCache::Cell aCell;
+ aCell.mxToken = pToken;
+ aCell.mnFmtIndex = nFmtIndex;
+ rRow.emplace(nCol, aCell);
+ if (bSetCacheRange)
+ setCachedCell(nCol, nRow);
+}
+
+ScExternalRefCache::TokenRef ScExternalRefCache::Table::getCell(SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex) const
+{
+ RowsDataType::const_iterator itrTable = maRows.find(nRow);
+ if (itrTable == maRows.end())
+ {
+ // this table doesn't have the specified row.
+ return getEmptyOrNullToken(nCol, nRow);
+ }
+
+ const RowDataType& rRowData = itrTable->second;
+ RowDataType::const_iterator itrRow = rRowData.find(nCol);
+ if (itrRow == rRowData.end())
+ {
+ // this row doesn't have the specified column.
+ return getEmptyOrNullToken(nCol, nRow);
+ }
+
+ const Cell& rCell = itrRow->second;
+ if (pnFmtIndex)
+ *pnFmtIndex = rCell.mnFmtIndex;
+
+ return rCell.mxToken;
+}
+
+bool ScExternalRefCache::Table::hasRow( SCROW nRow ) const
+{
+ RowsDataType::const_iterator itrRow = maRows.find(nRow);
+ return itrRow != maRows.end();
+}
+
+template< typename P >
+void ScExternalRefCache::Table::getAllRows(vector<SCROW>& rRows, P predicate) const
+{
+ vector<SCROW> aRows;
+ aRows.reserve(maRows.size());
+ for (const auto& rEntry : maRows)
+ if (predicate(rEntry))
+ aRows.push_back(rEntry.first);
+
+ // hash map is not ordered, so we need to explicitly sort it.
+ ::std::sort(aRows.begin(), aRows.end());
+ rRows.swap(aRows);
+}
+
+void ScExternalRefCache::Table::getAllRows(vector<SCROW>& rRows, SCROW nLow, SCROW nHigh) const
+{
+ getAllRows(rRows,
+ [nLow, nHigh](std::pair<SCROW, RowDataType> rEntry) { return (nLow <= rEntry.first && rEntry.first <= nHigh); });
+}
+
+void ScExternalRefCache::Table::getAllRows(vector<SCROW>& rRows) const
+{
+ getAllRows(rRows, [](std::pair<SCROW, RowDataType>) { return true; } );
+}
+
+::std::pair< SCROW, SCROW > ScExternalRefCache::Table::getRowRange() const
+{
+ ::std::pair< SCROW, SCROW > aRange( 0, 0 );
+ if( !maRows.empty() )
+ {
+ // iterate over entire container (hash map is not sorted by key)
+ auto itMinMax = std::minmax_element(maRows.begin(), maRows.end(),
+ [](const RowsDataType::value_type& a, const RowsDataType::value_type& b) { return a.first < b.first; });
+ aRange.first = itMinMax.first->first;
+ aRange.second = itMinMax.second->first + 1;
+ }
+ return aRange;
+}
+
+template< typename P >
+void ScExternalRefCache::Table::getAllCols(SCROW nRow, vector<SCCOL>& rCols, P predicate) const
+{
+ RowsDataType::const_iterator itrRow = maRows.find(nRow);
+ if (itrRow == maRows.end())
+ // this table doesn't have the specified row.
+ return;
+
+ const RowDataType& rRowData = itrRow->second;
+ vector<SCCOL> aCols;
+ aCols.reserve(rRowData.size());
+ for (const auto& rCol : rRowData)
+ if (predicate(rCol))
+ aCols.push_back(rCol.first);
+
+ // hash map is not ordered, so we need to explicitly sort it.
+ ::std::sort(aCols.begin(), aCols.end());
+ rCols.swap(aCols);
+}
+
+void ScExternalRefCache::Table::getAllCols(SCROW nRow, vector<SCCOL>& rCols, SCCOL nLow, SCCOL nHigh) const
+{
+ getAllCols(nRow, rCols,
+ [nLow, nHigh](std::pair<SCCOL, Cell> rCol) { return nLow <= rCol.first && rCol.first <= nHigh; } );
+}
+
+void ScExternalRefCache::Table::getAllCols(SCROW nRow, vector<SCCOL>& rCols) const
+{
+ getAllCols(nRow, rCols, [](std::pair<SCCOL, Cell>) { return true; } );
+}
+
+::std::pair< SCCOL, SCCOL > ScExternalRefCache::Table::getColRange( SCROW nRow ) const
+{
+ ::std::pair< SCCOL, SCCOL > aRange( 0, 0 );
+
+ RowsDataType::const_iterator itrRow = maRows.find( nRow );
+ if (itrRow == maRows.end())
+ // this table doesn't have the specified row.
+ return aRange;
+
+ const RowDataType& rRowData = itrRow->second;
+ if( !rRowData.empty() )
+ {
+ // iterate over entire container (hash map is not sorted by key)
+ auto itMinMax = std::minmax_element(rRowData.begin(), rRowData.end(),
+ [](const RowDataType::value_type& a, const RowDataType::value_type& b) { return a.first < b.first; });
+ aRange.first = itMinMax.first->first;
+ aRange.second = itMinMax.second->first + 1;
+ }
+ return aRange;
+}
+
+void ScExternalRefCache::Table::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
+{
+ for (const auto& rRow : maRows)
+ {
+ const RowDataType& rRowData = rRow.second;
+ for (const auto& rCol : rRowData)
+ {
+ const Cell& rCell = rCol.second;
+ rNumFmts.push_back(rCell.mnFmtIndex);
+ }
+ }
+}
+
+bool ScExternalRefCache::Table::isRangeCached(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2) const
+{
+ return maCachedRanges.Contains(ScRange(nCol1, nRow1, 0, nCol2, nRow2, 0));
+}
+
+void ScExternalRefCache::Table::setCachedCell(SCCOL nCol, SCROW nRow)
+{
+ setCachedCellRange(nCol, nRow, nCol, nRow);
+}
+
+void ScExternalRefCache::Table::setCachedCellRange(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
+{
+ ScRange aRange(nCol1, nRow1, 0, nCol2, nRow2, 0);
+ maCachedRanges.Join(aRange);
+}
+
+void ScExternalRefCache::Table::setWholeTableCached()
+{
+ setCachedCellRange(0, 0, MAXCOL, MAXROW);
+}
+
+bool ScExternalRefCache::Table::isInCachedRanges(SCCOL nCol, SCROW nRow) const
+{
+ return maCachedRanges.Contains(ScRange(nCol, nRow, 0, nCol, nRow, 0));
+}
+
+ScExternalRefCache::TokenRef ScExternalRefCache::Table::getEmptyOrNullToken(
+ SCCOL nCol, SCROW nRow) const
+{
+ if (isInCachedRanges(nCol, nRow))
+ {
+ TokenRef p(new ScEmptyCellToken(false, false));
+ return p;
+ }
+ return TokenRef();
+}
+
+ScExternalRefCache::TableName::TableName(const OUString& rUpper, const OUString& rReal) :
+ maUpperName(rUpper), maRealName(rReal)
+{
+}
+
+ScExternalRefCache::CellFormat::CellFormat() :
+ mbIsSet(false), mnType(SvNumFormatType::ALL), mnIndex(0)
+{
+}
+
+ScExternalRefCache::ScExternalRefCache(const ScDocument& rDoc)
+ : mrDoc(rDoc)
+{
+}
+
+ScExternalRefCache::~ScExternalRefCache() {}
+
+const OUString* ScExternalRefCache::getRealTableName(sal_uInt16 nFileId, const OUString& rTabName) const
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+
+ DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
+ if (itrDoc == maDocs.end())
+ {
+ // specified document is not cached.
+ return nullptr;
+ }
+
+ const DocItem& rDoc = itrDoc->second;
+ TableNameIndexMap::const_iterator itrTabId = rDoc.findTableNameIndex( rTabName);
+ if (itrTabId == rDoc.maTableNameIndex.end())
+ {
+ // the specified table is not in cache.
+ return nullptr;
+ }
+
+ return &rDoc.maTableNames[itrTabId->second].maRealName;
+}
+
+const OUString* ScExternalRefCache::getRealRangeName(sal_uInt16 nFileId, const OUString& rRangeName) const
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+
+ DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
+ if (itrDoc == maDocs.end())
+ {
+ // specified document is not cached.
+ return nullptr;
+ }
+
+ const DocItem& rDoc = itrDoc->second;
+ NamePairMap::const_iterator itr = rDoc.maRealRangeNameMap.find(
+ ScGlobal::getCharClass().uppercase(rRangeName));
+ if (itr == rDoc.maRealRangeNameMap.end())
+ // range name not found.
+ return nullptr;
+
+ return &itr->second;
+}
+
+ScExternalRefCache::TokenRef ScExternalRefCache::getCellData(
+ sal_uInt16 nFileId, const OUString& rTabName, SCCOL nCol, SCROW nRow, sal_uInt32* pnFmtIndex)
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+
+ DocDataType::const_iterator itrDoc = maDocs.find(nFileId);
+ if (itrDoc == maDocs.end())
+ {
+ // specified document is not cached.
+ return TokenRef();
+ }
+
+ const DocItem& rDoc = itrDoc->second;
+ TableNameIndexMap::const_iterator itrTabId = rDoc.findTableNameIndex( rTabName);
+ if (itrTabId == rDoc.maTableNameIndex.end())
+ {
+ // the specified table is not in cache.
+ return TokenRef();
+ }
+
+ const TableTypeRef& pTableData = rDoc.maTables[itrTabId->second];
+ if (!pTableData)
+ {
+ // the table data is not instantiated yet.
+ return TokenRef();
+ }
+
+ return pTableData->getCell(nCol, nRow, pnFmtIndex);
+}
+
+ScExternalRefCache::TokenArrayRef ScExternalRefCache::getCellRangeData(
+ sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange)
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+
+ DocDataType::iterator itrDoc = maDocs.find(nFileId);
+ if (itrDoc == maDocs.end())
+ // specified document is not cached.
+ return TokenArrayRef();
+
+ DocItem& rDoc = itrDoc->second;
+
+ TableNameIndexMap::const_iterator itrTabId = rDoc.findTableNameIndex( rTabName);
+ if (itrTabId == rDoc.maTableNameIndex.end())
+ // the specified table is not in cache.
+ return TokenArrayRef();
+
+ const ScAddress& s = rRange.aStart;
+ const ScAddress& e = rRange.aEnd;
+
+ const SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
+ const SCCOL nCol1 = s.Col(), nCol2 = e.Col();
+ const SCROW nRow1 = s.Row(), nRow2 = e.Row();
+
+ // Make sure I have all the tables cached.
+ size_t nTabFirstId = itrTabId->second;
+ size_t nTabLastId = nTabFirstId + nTab2 - nTab1;
+ if (nTabLastId >= rDoc.maTables.size())
+ // not all tables are cached.
+ return TokenArrayRef();
+
+ ScRange aCacheRange( nCol1, nRow1, static_cast<SCTAB>(nTabFirstId), nCol2, nRow2, static_cast<SCTAB>(nTabLastId));
+
+ RangeArrayMap::const_iterator itrRange = rDoc.maRangeArrays.find( aCacheRange);
+ if (itrRange != rDoc.maRangeArrays.end())
+ // Cache hit!
+ return itrRange->second;
+
+ std::unique_ptr<ScRange> pNewRange;
+ TokenArrayRef pArray;
+ bool bFirstTab = true;
+ for (size_t nTab = nTabFirstId; nTab <= nTabLastId; ++nTab)
+ {
+ TableTypeRef pTab = rDoc.maTables[nTab];
+ if (!pTab)
+ return TokenArrayRef();
+
+ SCCOL nDataCol1 = nCol1, nDataCol2 = nCol2;
+ SCROW nDataRow1 = nRow1, nDataRow2 = nRow2;
+
+ if (!pTab->isRangeCached(nDataCol1, nDataRow1, nDataCol2, nDataRow2))
+ {
+ // specified range is not entirely within cached ranges.
+ return TokenArrayRef();
+ }
+
+ SCSIZE nMatrixColumns = static_cast<SCSIZE>(nDataCol2-nDataCol1+1);
+ SCSIZE nMatrixRows = static_cast<SCSIZE>(nDataRow2-nDataRow1+1);
+ ScMatrixRef xMat = new ScMatrix( nMatrixColumns, nMatrixRows);
+
+ // Needed in shrink and fill.
+ vector<SCROW> aRows;
+ pTab->getAllRows(aRows, nDataRow1, nDataRow2);
+ bool bFill = true;
+
+ // Check if size could be allocated and if not skip the fill, there's
+ // one error element instead. But retry first with the actual data area
+ // if that is smaller than the original range, which works for most
+ // functions just not some that operate/compare with the original size
+ // and expect empty values in non-data areas.
+ // Restrict this though to ranges of entire columns or rows, other
+ // ranges might be on purpose. (Other special cases to handle?)
+ /* TODO: sparse matrix could help */
+ SCSIZE nMatCols, nMatRows;
+ xMat->GetDimensions( nMatCols, nMatRows);
+ if (nMatCols != nMatrixColumns || nMatRows != nMatrixRows)
+ {
+ bFill = false;
+ if (aRows.empty())
+ {
+ // There's no data at all. Set the one matrix element to empty
+ // for column-repeated and row-repeated access.
+ xMat->PutEmpty(0,0);
+ }
+ else if ((nCol1 == 0 && nCol2 == MAXCOL) || (nRow1 == 0 && nRow2 == MAXROW))
+ {
+ nDataRow1 = aRows.front();
+ nDataRow2 = aRows.back();
+ SCCOL nMinCol = std::numeric_limits<SCCOL>::max();
+ SCCOL nMaxCol = std::numeric_limits<SCCOL>::min();
+ for (const auto& rRow : aRows)
+ {
+ vector<SCCOL> aCols;
+ pTab->getAllCols(rRow, aCols, nDataCol1, nDataCol2);
+ if (!aCols.empty())
+ {
+ nMinCol = std::min( nMinCol, aCols.front());
+ nMaxCol = std::max( nMaxCol, aCols.back());
+ }
+ }
+
+ if (nMinCol <= nMaxCol && ((o3tl::make_unsigned(nMaxCol-nMinCol+1) < nMatrixColumns) ||
+ (o3tl::make_unsigned(nDataRow2-nDataRow1+1) < nMatrixRows)))
+ {
+ nMatrixColumns = static_cast<SCSIZE>(nMaxCol-nMinCol+1);
+ nMatrixRows = static_cast<SCSIZE>(nDataRow2-nDataRow1+1);
+ xMat = new ScMatrix( nMatrixColumns, nMatrixRows);
+ xMat->GetDimensions( nMatCols, nMatRows);
+ if (nMatCols == nMatrixColumns && nMatRows == nMatrixRows)
+ {
+ nDataCol1 = nMinCol;
+ nDataCol2 = nMaxCol;
+ bFill = true;
+ }
+ }
+ }
+ }
+
+ if (bFill)
+ {
+ // Only fill non-empty cells, for better performance.
+ for (SCROW nRow : aRows)
+ {
+ vector<SCCOL> aCols;
+ pTab->getAllCols(nRow, aCols, nDataCol1, nDataCol2);
+ for (SCCOL nCol : aCols)
+ {
+ TokenRef pToken = pTab->getCell(nCol, nRow);
+ if (!pToken)
+ // This should never happen!
+ return TokenArrayRef();
+
+ SCSIZE nC = nCol - nDataCol1, nR = nRow - nDataRow1;
+ switch (pToken->GetType())
+ {
+ case svDouble:
+ xMat->PutDouble(pToken->GetDouble(), nC, nR);
+ break;
+ case svString:
+ xMat->PutString(pToken->GetString(), nC, nR);
+ break;
+ default:
+ ;
+ }
+ }
+ }
+
+ if (!bFirstTab)
+ pArray->AddOpCode(ocSep);
+
+ ScMatrixToken aToken(xMat);
+ if (!pArray)
+ pArray = std::make_shared<ScTokenArray>(mrDoc);
+ pArray->AddToken(aToken);
+
+ bFirstTab = false;
+
+ if (!pNewRange)
+ pNewRange.reset(new ScRange(nDataCol1, nDataRow1, nTab, nDataCol2, nDataRow2, nTab));
+ else
+ pNewRange->ExtendTo(ScRange(nDataCol1, nDataRow1, nTab, nDataCol2, nDataRow2, nTab));
+ }
+ }
+
+ rDoc.maRangeArrays.emplace(aCacheRange, pArray);
+ if (pNewRange && *pNewRange != aCacheRange)
+ rDoc.maRangeArrays.emplace(*pNewRange, pArray);
+
+ return pArray;
+}
+
+ScExternalRefCache::TokenArrayRef ScExternalRefCache::getRangeNameTokens(sal_uInt16 nFileId, const OUString& rName)
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+
+ DocItem* pDoc = getDocItem(nFileId);
+ if (!pDoc)
+ return TokenArrayRef();
+
+ RangeNameMap& rMap = pDoc->maRangeNames;
+ RangeNameMap::const_iterator itr = rMap.find(
+ ScGlobal::getCharClass().uppercase(rName));
+ if (itr == rMap.end())
+ return TokenArrayRef();
+
+ return itr->second;
+}
+
+void ScExternalRefCache::setRangeNameTokens(sal_uInt16 nFileId, const OUString& rName, TokenArrayRef pArray)
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+
+ DocItem* pDoc = getDocItem(nFileId);
+ if (!pDoc)
+ return;
+
+ OUString aUpperName = ScGlobal::getCharClass().uppercase(rName);
+ RangeNameMap& rMap = pDoc->maRangeNames;
+ rMap.emplace(aUpperName, pArray);
+ pDoc->maRealRangeNameMap.emplace(aUpperName, rName);
+}
+
+bool ScExternalRefCache::isValidRangeName(sal_uInt16 nFileId, const OUString& rName) const
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+
+ DocItem* pDoc = getDocItem(nFileId);
+ if (!pDoc)
+ return false;
+
+ OUString aUpperName = ScGlobal::getCharClass().uppercase(rName);
+ const RangeNameMap& rMap = pDoc->maRangeNames;
+ return rMap.count(aUpperName) > 0;
+}
+
+void ScExternalRefCache::setRangeName(sal_uInt16 nFileId, const OUString& rName)
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+
+ DocItem* pDoc = getDocItem(nFileId);
+ if (!pDoc)
+ return;
+
+ OUString aUpperName = ScGlobal::getCharClass().uppercase(rName);
+ pDoc->maRealRangeNameMap.emplace(aUpperName, rName);
+}
+
+void ScExternalRefCache::setCellData(sal_uInt16 nFileId, const OUString& rTabName, SCCOL nCol, SCROW nRow,
+ TokenRef const & pToken, sal_uLong nFmtIndex)
+{
+ if (!isDocInitialized(nFileId))
+ return;
+
+ using ::std::pair;
+ DocItem* pDocItem = getDocItem(nFileId);
+ if (!pDocItem)
+ return;
+
+ DocItem& rDoc = *pDocItem;
+
+ // See if the table by this name already exists.
+ TableNameIndexMap::const_iterator itrTabName = rDoc.findTableNameIndex( rTabName);
+ if (itrTabName == rDoc.maTableNameIndex.end())
+ // Table not found. Maybe the table name or the file id is wrong ???
+ return;
+
+ TableTypeRef& pTableData = rDoc.maTables[itrTabName->second];
+ if (!pTableData)
+ pTableData = std::make_shared<Table>();
+
+ pTableData->setCell(nCol, nRow, pToken, nFmtIndex);
+ pTableData->setCachedCell(nCol, nRow);
+}
+
+void ScExternalRefCache::setCellRangeData(sal_uInt16 nFileId, const ScRange& rRange, const vector<SingleRangeData>& rData,
+ const TokenArrayRef& pArray)
+{
+ using ::std::pair;
+ if (rData.empty() || !isDocInitialized(nFileId))
+ // nothing to cache
+ return;
+
+ // First, get the document item for the given file ID.
+ DocItem* pDocItem = getDocItem(nFileId);
+ if (!pDocItem)
+ return;
+
+ DocItem& rDoc = *pDocItem;
+
+ // Now, find the table position of the first table to cache.
+ const OUString& rFirstTabName = rData.front().maTableName;
+ TableNameIndexMap::const_iterator itrTabName = rDoc.findTableNameIndex( rFirstTabName);
+ if (itrTabName == rDoc.maTableNameIndex.end())
+ {
+ // table index not found.
+ return;
+ }
+
+ size_t nTabFirstId = itrTabName->second;
+ SCROW nRow1 = rRange.aStart.Row(), nRow2 = rRange.aEnd.Row();
+ SCCOL nCol1 = rRange.aStart.Col(), nCol2 = rRange.aEnd.Col();
+ size_t i = nTabFirstId;
+ for (const auto& rItem : rData)
+ {
+ TableTypeRef& pTabData = rDoc.maTables[i];
+ if (!pTabData)
+ pTabData = std::make_shared<Table>();
+
+ const ScMatrixRef& pMat = rItem.mpRangeData;
+ SCSIZE nMatCols, nMatRows;
+ pMat->GetDimensions( nMatCols, nMatRows);
+ if (nMatCols > o3tl::make_unsigned(nCol2 - nCol1) && nMatRows > o3tl::make_unsigned(nRow2 - nRow1))
+ {
+ ScMatrix::DoubleOpFunction aDoubleFunc = [=](size_t row, size_t col, double val) -> void
+ {
+ pTabData->setCell(col + nCol1, row + nRow1, new formula::FormulaDoubleToken(val), 0, false);
+ };
+ ScMatrix::BoolOpFunction aBoolFunc = [=](size_t row, size_t col, bool val) -> void
+ {
+ pTabData->setCell(col + nCol1, row + nRow1, new formula::FormulaDoubleToken(val ? 1.0 : 0.0), 0, false);
+ };
+ ScMatrix::StringOpFunction aStringFunc = [=](size_t row, size_t col, svl::SharedString val) -> void
+ {
+ pTabData->setCell(col + nCol1, row + nRow1, new formula::FormulaStringToken(val), 0, false);
+ };
+ ScMatrix::EmptyOpFunction aEmptyFunc = [](size_t /*row*/, size_t /*col*/) -> void
+ {
+ // Nothing. Empty cell.
+ };
+ pMat->ExecuteOperation(std::pair<size_t, size_t>(0, 0),
+ std::pair<size_t, size_t>(nRow2-nRow1, nCol2-nCol1),
+ std::move(aDoubleFunc), std::move(aBoolFunc), std::move(aStringFunc), std::move(aEmptyFunc));
+ // Mark the whole range 'cached'.
+ pTabData->setCachedCellRange(nCol1, nRow1, nCol2, nRow2);
+ }
+ else
+ {
+ // This may happen due to a matrix not been allocated earlier, in
+ // which case it should have exactly one error element.
+ SAL_WARN("sc.ui","ScExternalRefCache::setCellRangeData - matrix size mismatch");
+ if (nMatCols != 1 || nMatRows != 1)
+ SAL_WARN("sc.ui","ScExternalRefCache::setCellRangeData - not a one element matrix");
+ else
+ {
+ FormulaError nErr = GetDoubleErrorValue( pMat->GetDouble(0,0));
+ SAL_WARN("sc.ui","ScExternalRefCache::setCellRangeData - matrix error value is " << static_cast<int>(nErr) <<
+ (nErr == FormulaError::MatrixSize ? ", ok" : ", not ok"));
+ }
+ }
+ ++i;
+ }
+
+ size_t nTabLastId = nTabFirstId + rRange.aEnd.Tab() - rRange.aStart.Tab();
+ ScRange aCacheRange( nCol1, nRow1, static_cast<SCTAB>(nTabFirstId), nCol2, nRow2, static_cast<SCTAB>(nTabLastId));
+
+ rDoc.maRangeArrays.emplace(aCacheRange, pArray);
+}
+
+bool ScExternalRefCache::isDocInitialized(sal_uInt16 nFileId)
+{
+ DocItem* pDoc = getDocItem(nFileId);
+ if (!pDoc)
+ return false;
+
+ return pDoc->mbInitFromSource;
+}
+
+static bool lcl_getStrictTableDataIndex(const ScExternalRefCache::TableNameIndexMap& rMap, const OUString& rName, size_t& rIndex)
+{
+ ScExternalRefCache::TableNameIndexMap::const_iterator itr = rMap.find(rName);
+ if (itr == rMap.end())
+ return false;
+
+ rIndex = itr->second;
+ return true;
+}
+
+bool ScExternalRefCache::DocItem::getTableDataIndex( const OUString& rTabName, size_t& rIndex ) const
+{
+ ScExternalRefCache::TableNameIndexMap::const_iterator itr = findTableNameIndex(rTabName);
+ if (itr == maTableNameIndex.end())
+ return false;
+
+ rIndex = itr->second;
+ return true;
+}
+
+namespace {
+OUString getFirstSheetName()
+{
+ // Get Custom prefix.
+ const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
+ // Form sheet name identical to the first generated sheet name when
+ // creating an internal document, e.g. 'Sheet1'.
+ return rOpt.GetInitTabPrefix() + "1";
+}
+}
+
+void ScExternalRefCache::initializeDoc(sal_uInt16 nFileId, const vector<OUString>& rTabNames,
+ const OUString& rBaseName)
+{
+ DocItem* pDoc = getDocItem(nFileId);
+ if (!pDoc)
+ return;
+
+ size_t n = rTabNames.size();
+
+ // table name list - the list must include all table names in the source
+ // document and only to be populated when loading the source document, not
+ // when loading cached data from, say, Excel XCT/CRN records.
+ vector<TableName> aNewTabNames;
+ aNewTabNames.reserve(n);
+ for (const auto& rTabName : rTabNames)
+ {
+ TableName aNameItem(ScGlobal::getCharClass().uppercase(rTabName), rTabName);
+ aNewTabNames.push_back(aNameItem);
+ }
+ pDoc->maTableNames.swap(aNewTabNames);
+
+ // data tables - preserve any existing data that may have been set during
+ // file import.
+ vector<TableTypeRef> aNewTables(n);
+ for (size_t i = 0; i < n; ++i)
+ {
+ size_t nIndex;
+ if (lcl_getStrictTableDataIndex(pDoc->maTableNameIndex, pDoc->maTableNames[i].maUpperName, nIndex))
+ {
+ aNewTables[i] = pDoc->maTables[nIndex];
+ }
+ }
+ pDoc->maTables.swap(aNewTables);
+
+ // name index map
+ TableNameIndexMap aNewNameIndex;
+ for (size_t i = 0; i < n; ++i)
+ aNewNameIndex.emplace(pDoc->maTableNames[i].maUpperName, i);
+ pDoc->maTableNameIndex.swap(aNewNameIndex);
+
+ // Setup name for Sheet1 vs base name to be able to load documents
+ // that store the base name as table name, or vice versa.
+ pDoc->maSingleTableNameAlias.clear();
+ if (!rBaseName.isEmpty() && pDoc->maTableNames.size() == 1)
+ {
+ OUString aSheetName = getFirstSheetName();
+ // If the one and only table name matches exactly, carry on the base
+ // file name for further alias use. If instead the table name matches
+ // the base name, carry on the sheet name as alias.
+ if (ScGlobal::GetTransliteration().isEqual( pDoc->maTableNames[0].maRealName, aSheetName))
+ pDoc->maSingleTableNameAlias = rBaseName;
+ else if (ScGlobal::GetTransliteration().isEqual( pDoc->maTableNames[0].maRealName, rBaseName))
+ pDoc->maSingleTableNameAlias = aSheetName;
+ }
+
+ pDoc->mbInitFromSource = true;
+}
+
+ScExternalRefCache::TableNameIndexMap::const_iterator ScExternalRefCache::DocItem::findTableNameIndex(
+ const OUString& rTabName ) const
+{
+ const OUString aTabNameUpper = ScGlobal::getCharClass().uppercase( rTabName);
+ TableNameIndexMap::const_iterator itrTabName = maTableNameIndex.find( aTabNameUpper);
+ if (itrTabName != maTableNameIndex.end())
+ return itrTabName;
+
+ // Since some time for external references to CSV files the base name is
+ // used as sheet name instead of Sheet1, check if we can resolve that.
+ // Also helps users that got accustomed to one or the other way.
+ if (maSingleTableNameAlias.isEmpty() || maTableNameIndex.size() != 1)
+ return itrTabName;
+
+ // maSingleTableNameAlias has been set up only if the original file loaded
+ // had exactly one sheet and internal sheet name was Sheet1 or localized or
+ // customized equivalent, or base name.
+ if (aTabNameUpper == ScGlobal::getCharClass().uppercase( maSingleTableNameAlias))
+ return maTableNameIndex.begin();
+
+ return itrTabName;
+}
+
+bool ScExternalRefCache::DocItem::getSingleTableNameAlternative( OUString& rTabName ) const
+{
+ if (maSingleTableNameAlias.isEmpty() || maTableNames.size() != 1)
+ return false;
+ if (ScGlobal::GetTransliteration().isEqual( rTabName, maTableNames[0].maRealName))
+ {
+ rTabName = maSingleTableNameAlias;
+ return true;
+ }
+ if (ScGlobal::GetTransliteration().isEqual( rTabName, maSingleTableNameAlias))
+ {
+ rTabName = maTableNames[0].maRealName;
+ return true;
+ }
+ return false;
+}
+
+bool ScExternalRefCache::getSrcDocTable( const ScDocument& rSrcDoc, const OUString& rTabName, SCTAB& rTab,
+ sal_uInt16 nFileId ) const
+{
+ bool bFound = rSrcDoc.GetTable( rTabName, rTab);
+ if (!bFound)
+ {
+ // Check the one table alias alternative.
+ const DocItem* pDoc = getDocItem( nFileId );
+ if (pDoc)
+ {
+ OUString aTabName( rTabName);
+ if (pDoc->getSingleTableNameAlternative( aTabName))
+ bFound = rSrcDoc.GetTable( aTabName, rTab);
+ }
+ }
+ return bFound;
+}
+
+OUString ScExternalRefCache::getTableName(sal_uInt16 nFileId, size_t nCacheId) const
+{
+ if( DocItem* pDoc = getDocItem( nFileId ) )
+ if( nCacheId < pDoc->maTableNames.size() )
+ return pDoc->maTableNames[ nCacheId ].maRealName;
+ return OUString();
+}
+
+void ScExternalRefCache::getAllTableNames(sal_uInt16 nFileId, vector<OUString>& rTabNames) const
+{
+ rTabNames.clear();
+ DocItem* pDoc = getDocItem(nFileId);
+ if (!pDoc)
+ return;
+
+ size_t n = pDoc->maTableNames.size();
+ rTabNames.reserve(n);
+ for (const auto& rTableName : pDoc->maTableNames)
+ rTabNames.push_back(rTableName.maRealName);
+}
+
+SCTAB ScExternalRefCache::getTabSpan( sal_uInt16 nFileId, const OUString& rStartTabName, const OUString& rEndTabName ) const
+{
+ DocItem* pDoc = getDocItem(nFileId);
+ if (!pDoc)
+ return -1;
+
+ vector<TableName>::const_iterator itrBeg = pDoc->maTableNames.begin();
+ vector<TableName>::const_iterator itrEnd = pDoc->maTableNames.end();
+
+ vector<TableName>::const_iterator itrStartTab = ::std::find_if( itrBeg, itrEnd,
+ TabNameSearchPredicate( rStartTabName));
+ if (itrStartTab == itrEnd)
+ return -1;
+
+ vector<TableName>::const_iterator itrEndTab = ::std::find_if( itrBeg, itrEnd,
+ TabNameSearchPredicate( rEndTabName));
+ if (itrEndTab == itrEnd)
+ return 0;
+
+ size_t nStartDist = ::std::distance( itrBeg, itrStartTab);
+ size_t nEndDist = ::std::distance( itrBeg, itrEndTab);
+ return nStartDist <= nEndDist ? static_cast<SCTAB>(nEndDist - nStartDist + 1) : -static_cast<SCTAB>(nStartDist - nEndDist + 1);
+}
+
+void ScExternalRefCache::getAllNumberFormats(vector<sal_uInt32>& rNumFmts) const
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+
+ using ::std::sort;
+ using ::std::unique;
+
+ vector<sal_uInt32> aNumFmts;
+ for (const auto& rEntry : maDocs)
+ {
+ const vector<TableTypeRef>& rTables = rEntry.second.maTables;
+ for (const TableTypeRef& pTab : rTables)
+ {
+ if (!pTab)
+ continue;
+
+ pTab->getAllNumberFormats(aNumFmts);
+ }
+ }
+
+ // remove duplicates.
+ sort(aNumFmts.begin(), aNumFmts.end());
+ aNumFmts.erase(unique(aNumFmts.begin(), aNumFmts.end()), aNumFmts.end());
+ rNumFmts.swap(aNumFmts);
+}
+
+bool ScExternalRefCache::setCacheDocReferenced( sal_uInt16 nFileId )
+{
+ DocItem* pDocItem = getDocItem(nFileId);
+ if (!pDocItem)
+ return areAllCacheTablesReferenced();
+
+ for (auto& rxTab : pDocItem->maTables)
+ {
+ if (rxTab)
+ rxTab->setReferenced(true);
+ }
+ addCacheDocToReferenced( nFileId);
+ return areAllCacheTablesReferenced();
+}
+
+bool ScExternalRefCache::setCacheTableReferenced( sal_uInt16 nFileId, const OUString& rTabName, size_t nSheets )
+{
+ DocItem* pDoc = getDocItem(nFileId);
+ if (pDoc)
+ {
+ size_t nIndex = 0;
+ if (pDoc->getTableDataIndex( rTabName, nIndex))
+ {
+ size_t nStop = ::std::min( nIndex + nSheets, pDoc->maTables.size());
+ for (size_t i = nIndex; i < nStop; ++i)
+ {
+ TableTypeRef pTab = pDoc->maTables[i];
+ if (pTab)
+ {
+ if (!pTab->isReferenced())
+ {
+ pTab->setReferenced(true);
+ addCacheTableToReferenced( nFileId, i);
+ }
+ }
+ }
+ }
+ }
+ return areAllCacheTablesReferenced();
+}
+
+void ScExternalRefCache::setAllCacheTableReferencedStati( bool bReferenced )
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+
+ if (bReferenced)
+ {
+ maReferenced.reset(0);
+ for (auto& rEntry : maDocs)
+ {
+ ScExternalRefCache::DocItem& rDocItem = rEntry.second;
+ for (auto& rxTab : rDocItem.maTables)
+ {
+ if (rxTab)
+ rxTab->setReferenced(true);
+ }
+ }
+ }
+ else
+ {
+ size_t nDocs = 0;
+ auto itrMax = std::max_element(maDocs.begin(), maDocs.end(),
+ [](const DocDataType::value_type& a, const DocDataType::value_type& b) { return a.first < b.first; });
+ if (itrMax != maDocs.end())
+ nDocs = itrMax->first + 1;
+ maReferenced.reset( nDocs);
+
+ for (auto& [nFileId, rDocItem] : maDocs)
+ {
+ size_t nTables = rDocItem.maTables.size();
+ ReferencedStatus::DocReferenced & rDocReferenced = maReferenced.maDocs[nFileId];
+ // All referenced => non-existing tables evaluate as completed.
+ rDocReferenced.maTables.resize( nTables, true);
+ for (size_t i=0; i < nTables; ++i)
+ {
+ TableTypeRef & xTab = rDocItem.maTables[i];
+ if (xTab)
+ {
+ xTab->setReferenced(false);
+ rDocReferenced.maTables[i] = false;
+ rDocReferenced.mbAllTablesReferenced = false;
+ // An addCacheTableToReferenced() actually may have
+ // resulted in mbAllReferenced been set. Clear it.
+ maReferenced.mbAllReferenced = false;
+ }
+ }
+ }
+ }
+}
+
+void ScExternalRefCache::addCacheTableToReferenced( sal_uInt16 nFileId, size_t nIndex )
+{
+ if (nFileId >= maReferenced.maDocs.size())
+ return;
+
+ ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables;
+ size_t nTables = rTables.size();
+ if (nIndex >= nTables)
+ return;
+
+ if (!rTables[nIndex])
+ {
+ rTables[nIndex] = true;
+ size_t i = 0;
+ while (i < nTables && rTables[i])
+ ++i;
+ if (i == nTables)
+ {
+ maReferenced.maDocs[nFileId].mbAllTablesReferenced = true;
+ maReferenced.checkAllDocs();
+ }
+ }
+}
+
+void ScExternalRefCache::addCacheDocToReferenced( sal_uInt16 nFileId )
+{
+ if (nFileId >= maReferenced.maDocs.size())
+ return;
+
+ if (!maReferenced.maDocs[nFileId].mbAllTablesReferenced)
+ {
+ ::std::vector<bool> & rTables = maReferenced.maDocs[nFileId].maTables;
+ size_t nSize = rTables.size();
+ for (size_t i=0; i < nSize; ++i)
+ rTables[i] = true;
+ maReferenced.maDocs[nFileId].mbAllTablesReferenced = true;
+ maReferenced.checkAllDocs();
+ }
+}
+
+void ScExternalRefCache::getAllCachedDataSpans( const ScDocument& rSrcDoc, sal_uInt16 nFileId, sc::ColumnSpanSet& rSet ) const
+{
+ const DocItem* pDocItem = getDocItem(nFileId);
+ if (!pDocItem)
+ // This document is not cached.
+ return;
+
+ const std::vector<TableTypeRef>& rTables = pDocItem->maTables;
+ for (size_t nTab = 0, nTabCount = rTables.size(); nTab < nTabCount; ++nTab)
+ {
+ TableTypeRef pTab = rTables[nTab];
+ if (!pTab)
+ continue;
+
+ std::vector<SCROW> aRows;
+ pTab->getAllRows(aRows);
+ for (SCROW nRow : aRows)
+ {
+ std::vector<SCCOL> aCols;
+ pTab->getAllCols(nRow, aCols);
+ for (SCCOL nCol : aCols)
+ {
+ rSet.set(rSrcDoc, nTab, nCol, nRow, true);
+ }
+ }
+ }
+}
+
+ScExternalRefCache::ReferencedStatus::ReferencedStatus() :
+ mbAllReferenced(false)
+{
+ reset(0);
+}
+
+void ScExternalRefCache::ReferencedStatus::reset( size_t nDocs )
+{
+ if (nDocs)
+ {
+ mbAllReferenced = false;
+ DocReferencedVec aRefs( nDocs);
+ maDocs.swap( aRefs);
+ }
+ else
+ {
+ mbAllReferenced = true;
+ DocReferencedVec aRefs;
+ maDocs.swap( aRefs);
+ }
+}
+
+void ScExternalRefCache::ReferencedStatus::checkAllDocs()
+{
+ if (std::all_of(maDocs.begin(), maDocs.end(), [](const DocReferenced& rDoc) { return rDoc.mbAllTablesReferenced; }))
+ mbAllReferenced = true;
+}
+
+ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
+{
+ DocItem* pDoc = getDocItem(nFileId);
+ if (!pDoc || nTabIndex >= pDoc->maTables.size())
+ return TableTypeRef();
+
+ return pDoc->maTables[nTabIndex];
+}
+
+ScExternalRefCache::TableTypeRef ScExternalRefCache::getCacheTable(sal_uInt16 nFileId, const OUString& rTabName,
+ bool bCreateNew, size_t* pnIndex, const OUString* pExtUrl)
+{
+ // In API, the index is transported as cached sheet ID of type sal_Int32 in
+ // sheet::SingleReference.Sheet or sheet::ComplexReference.Reference1.Sheet
+ // in a sheet::FormulaToken, choose a sensible value for N/A. Effectively
+ // being 0xffffffff
+ const size_t nNotAvailable = static_cast<size_t>( static_cast<sal_Int32>( -1));
+
+ DocItem* pDoc = getDocItem(nFileId);
+ if (!pDoc)
+ {
+ if (pnIndex) *pnIndex = nNotAvailable;
+ return TableTypeRef();
+ }
+
+ DocItem& rDoc = *pDoc;
+
+ size_t nIndex;
+ if (rDoc.getTableDataIndex(rTabName, nIndex))
+ {
+ // specified table found.
+ if( pnIndex ) *pnIndex = nIndex;
+ if (bCreateNew && !rDoc.maTables[nIndex])
+ rDoc.maTables[nIndex] = std::make_shared<Table>();
+
+ return rDoc.maTables[nIndex];
+ }
+
+ if (!bCreateNew)
+ {
+ if (pnIndex) *pnIndex = nNotAvailable;
+ return TableTypeRef();
+ }
+
+ // If this is the first table to be created propagate the base name or
+ // Sheet1 as an alias. For subsequent tables remove it again.
+ if (rDoc.maTableNames.empty())
+ {
+ if (pExtUrl)
+ {
+ const OUString aBaseName( INetURLObject( *pExtUrl).GetBase());
+ const OUString aSheetName( getFirstSheetName());
+ if (ScGlobal::GetTransliteration().isEqual( rTabName, aSheetName))
+ pDoc->maSingleTableNameAlias = aBaseName;
+ else if (ScGlobal::GetTransliteration().isEqual( rTabName, aBaseName))
+ pDoc->maSingleTableNameAlias = aSheetName;
+ }
+ }
+ else
+ {
+ rDoc.maSingleTableNameAlias.clear();
+ }
+
+ // Specified table doesn't exist yet. Create one.
+ OUString aTabNameUpper = ScGlobal::getCharClass().uppercase(rTabName);
+ nIndex = rDoc.maTables.size();
+ if( pnIndex ) *pnIndex = nIndex;
+ TableTypeRef pTab = std::make_shared<Table>();
+ rDoc.maTables.push_back(pTab);
+ rDoc.maTableNames.emplace_back(aTabNameUpper, rTabName);
+ rDoc.maTableNameIndex.emplace(aTabNameUpper, nIndex);
+ return pTab;
+}
+
+void ScExternalRefCache::clearCache(sal_uInt16 nFileId)
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+ maDocs.erase(nFileId);
+}
+
+void ScExternalRefCache::clearCacheTables(sal_uInt16 nFileId)
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+ DocItem* pDocItem = getDocItem(nFileId);
+ if (!pDocItem)
+ // This document is not cached at all.
+ return;
+
+ // Clear all cache table content, but keep the tables.
+ std::vector<TableTypeRef>& rTabs = pDocItem->maTables;
+ for (TableTypeRef & pTab : rTabs)
+ {
+ if (!pTab)
+ continue;
+
+ pTab->clear();
+ }
+
+ // Clear the external range name caches.
+ pDocItem->maRangeNames.clear();
+ pDocItem->maRangeArrays.clear();
+ pDocItem->maRealRangeNameMap.clear();
+}
+
+ScExternalRefCache::DocItem* ScExternalRefCache::getDocItem(sal_uInt16 nFileId) const
+{
+ osl::MutexGuard aGuard(&maMtxDocs);
+
+ using ::std::pair;
+ DocDataType::iterator itrDoc = maDocs.find(nFileId);
+ if (itrDoc == maDocs.end())
+ {
+ // specified document is not cached.
+ pair<DocDataType::iterator, bool> res = maDocs.emplace(
+ nFileId, DocItem());
+
+ if (!res.second)
+ // insertion failed.
+ return nullptr;
+
+ itrDoc = res.first;
+ }
+
+ return &itrDoc->second;
+}
+
+ScExternalRefLink::ScExternalRefLink(ScDocument& rDoc, sal_uInt16 nFileId) :
+ ::sfx2::SvBaseLink(::SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SIMPLE_FILE),
+ mnFileId(nFileId),
+ mrDoc(rDoc),
+ mbDoRefresh(true)
+{
+}
+
+ScExternalRefLink::~ScExternalRefLink()
+{
+}
+
+void ScExternalRefLink::Closed()
+{
+ ScExternalRefManager* pMgr = mrDoc.GetExternalRefManager();
+ pMgr->breakLink(mnFileId);
+}
+
+::sfx2::SvBaseLink::UpdateResult ScExternalRefLink::DataChanged(const OUString& /*rMimeType*/, const Any& /*rValue*/)
+{
+ if (!mbDoRefresh)
+ return SUCCESS;
+
+ OUString aFile, aFilter;
+ sfx2::LinkManager::GetDisplayNames(this, nullptr, &aFile, nullptr, &aFilter);
+ ScExternalRefManager* pMgr = mrDoc.GetExternalRefManager();
+
+ if (!pMgr->isFileLoadable(aFile))
+ return ERROR_GENERAL;
+
+ const OUString* pCurFile = pMgr->getExternalFileName(mnFileId);
+ if (!pCurFile)
+ return ERROR_GENERAL;
+
+ if (*pCurFile == aFile)
+ {
+ // Refresh the current source document.
+ if (!pMgr->refreshSrcDocument(mnFileId))
+ return ERROR_GENERAL;
+ }
+ else
+ {
+ // The source document has changed.
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return ERROR_GENERAL;
+
+ ScDocShell* pDocShell = pViewData->GetDocShell();
+ ScDocShellModificator aMod(*pDocShell);
+ pMgr->switchSrcFile(mnFileId, aFile, aFilter);
+ aMod.SetDocumentModified();
+ }
+
+ return SUCCESS;
+}
+
+void ScExternalRefLink::Edit(weld::Window* pParent, const Link<SvBaseLink&,void>& /*rEndEditHdl*/)
+{
+ SvBaseLink::Edit(pParent, Link<SvBaseLink&,void>());
+}
+
+void ScExternalRefLink::SetDoRefresh(bool b)
+{
+ mbDoRefresh = b;
+}
+
+static FormulaToken* convertToToken( ScDocument& rHostDoc, const ScDocument& rSrcDoc, ScRefCellValue& rCell )
+{
+ if (rCell.hasEmptyValue())
+ {
+ bool bInherited = (rCell.meType == CELLTYPE_FORMULA);
+ return new ScEmptyCellToken(bInherited, false);
+ }
+
+ switch (rCell.meType)
+ {
+ case CELLTYPE_EDIT:
+ case CELLTYPE_STRING:
+ {
+ OUString aStr = rCell.getString(&rSrcDoc);
+ svl::SharedString aSS = rHostDoc.GetSharedStringPool().intern(aStr);
+ return new formula::FormulaStringToken(aSS);
+ }
+ case CELLTYPE_VALUE:
+ return new formula::FormulaDoubleToken(rCell.mfValue);
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFCell = rCell.mpFormula;
+ FormulaError nError = pFCell->GetErrCode();
+ if (nError != FormulaError::NONE)
+ return new FormulaErrorToken( nError);
+ else if (pFCell->IsValue())
+ {
+ double fVal = pFCell->GetValue();
+ return new formula::FormulaDoubleToken(fVal);
+ }
+ else
+ {
+ svl::SharedString aSS = rHostDoc.GetSharedStringPool().intern( pFCell->GetString().getString());
+ return new formula::FormulaStringToken(aSS);
+ }
+ }
+ default:
+ OSL_FAIL("attempted to convert an unknown cell type.");
+ }
+
+ return nullptr;
+}
+
+static std::unique_ptr<ScTokenArray> convertToTokenArray(
+ ScDocument& rHostDoc, const ScDocument& rSrcDoc, ScRange& rRange, vector<ScExternalRefCache::SingleRangeData>& rCacheData )
+{
+ ScAddress& s = rRange.aStart;
+ ScAddress& e = rRange.aEnd;
+
+ const SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
+ const SCCOL nCol1 = s.Col(), nCol2 = e.Col();
+ const SCROW nRow1 = s.Row(), nRow2 = e.Row();
+
+ if (nTab2 != nTab1)
+ // For now, we don't support multi-sheet ranges intentionally because
+ // we don't have a way to express them in a single token. In the
+ // future we can introduce a new stack variable type svMatrixList with
+ // a new token type that can store a 3D matrix value and convert a 3D
+ // range to it.
+ return nullptr;
+
+ std::unique_ptr<ScRange> pUsedRange;
+
+ unique_ptr<ScTokenArray> pArray(new ScTokenArray(rSrcDoc));
+ bool bFirstTab = true;
+ vector<ScExternalRefCache::SingleRangeData>::iterator
+ itrCache = rCacheData.begin(), itrCacheEnd = rCacheData.end();
+
+ for (SCTAB nTab = nTab1; nTab <= nTab2 && itrCache != itrCacheEnd; ++nTab, ++itrCache)
+ {
+ // Only loop within the data area.
+ SCCOL nDataCol1 = nCol1, nDataCol2 = nCol2;
+ SCROW nDataRow1 = nRow1, nDataRow2 = nRow2;
+ bool bShrunk;
+ if (!rSrcDoc.ShrinkToUsedDataArea( bShrunk, nTab, nDataCol1, nDataRow1, nDataCol2, nDataRow2, false))
+ // no data within specified range.
+ continue;
+
+ if (pUsedRange)
+ // Make sure the used area only grows, not shrinks.
+ pUsedRange->ExtendTo(ScRange(nDataCol1, nDataRow1, 0, nDataCol2, nDataRow2, 0));
+ else
+ pUsedRange.reset(new ScRange(nDataCol1, nDataRow1, 0, nDataCol2, nDataRow2, 0));
+
+ SCSIZE nMatrixColumns = static_cast<SCSIZE>(nCol2-nCol1+1);
+ SCSIZE nMatrixRows = static_cast<SCSIZE>(nRow2-nRow1+1);
+ ScMatrixRef xMat = new ScMatrix( nMatrixColumns, nMatrixRows);
+
+ // Check if size could be allocated and if not skip the fill, there's
+ // one error element instead. But retry first with the actual data area
+ // if that is smaller than the original range, which works for most
+ // functions just not some that operate/compare with the original size
+ // and expect empty values in non-data areas.
+ // Restrict this though to ranges of entire columns or rows, other
+ // ranges might be on purpose. (Other special cases to handle?)
+ /* TODO: sparse matrix could help */
+ SCSIZE nMatCols, nMatRows;
+ xMat->GetDimensions( nMatCols, nMatRows);
+ if (nMatCols == nMatrixColumns && nMatRows == nMatrixRows)
+ {
+ rSrcDoc.FillMatrix(*xMat, nTab, nCol1, nRow1, nCol2, nRow2, &rHostDoc.GetSharedStringPool());
+ }
+ else if ((nCol1 == 0 && nCol2 == rSrcDoc.MaxCol()) || (nRow1 == 0 && nRow2 == rSrcDoc.MaxRow()))
+ {
+ if ((o3tl::make_unsigned(nDataCol2-nDataCol1+1) < nMatrixColumns) ||
+ (o3tl::make_unsigned(nDataRow2-nDataRow1+1) < nMatrixRows))
+ {
+ nMatrixColumns = static_cast<SCSIZE>(nDataCol2-nDataCol1+1);
+ nMatrixRows = static_cast<SCSIZE>(nDataRow2-nDataRow1+1);
+ xMat = new ScMatrix( nMatrixColumns, nMatrixRows);
+ xMat->GetDimensions( nMatCols, nMatRows);
+ if (nMatCols == nMatrixColumns && nMatRows == nMatrixRows)
+ rSrcDoc.FillMatrix(*xMat, nTab, nDataCol1, nDataRow1, nDataCol2, nDataRow2, &rHostDoc.GetSharedStringPool());
+ }
+ }
+
+ if (!bFirstTab)
+ pArray->AddOpCode(ocSep);
+
+ ScMatrixToken aToken(xMat);
+ pArray->AddToken(aToken);
+
+ itrCache->mpRangeData = xMat;
+
+ bFirstTab = false;
+ }
+
+ if (!pUsedRange)
+ return nullptr;
+
+ s.SetCol(pUsedRange->aStart.Col());
+ s.SetRow(pUsedRange->aStart.Row());
+ e.SetCol(pUsedRange->aEnd.Col());
+ e.SetRow(pUsedRange->aEnd.Row());
+
+ return pArray;
+}
+
+static std::unique_ptr<ScTokenArray> lcl_fillEmptyMatrix(const ScDocument& rDoc, const ScRange& rRange)
+{
+ SCSIZE nC = static_cast<SCSIZE>(rRange.aEnd.Col()-rRange.aStart.Col()+1);
+ SCSIZE nR = static_cast<SCSIZE>(rRange.aEnd.Row()-rRange.aStart.Row()+1);
+ ScMatrixRef xMat = new ScMatrix(nC, nR);
+
+ ScMatrixToken aToken(xMat);
+ unique_ptr<ScTokenArray> pArray(new ScTokenArray(rDoc));
+ pArray->AddToken(aToken);
+ return pArray;
+}
+
+namespace {
+bool isLinkUpdateAllowedInDoc(const ScDocument& rDoc)
+{
+ SfxObjectShell* pDocShell = rDoc.GetDocumentShell();
+ if (!pDocShell)
+ return rDoc.IsFunctionAccess();
+
+ return pDocShell->GetEmbeddedObjectContainer().getUserAllowsLinkUpdate();
+}
+}
+
+ScExternalRefManager::ScExternalRefManager(ScDocument& rDoc) :
+ mrDoc(rDoc),
+ maRefCache(rDoc),
+ mbInReferenceMarking(false),
+ mbUserInteractionEnabled(true),
+ mbDocTimerEnabled(true),
+ maSrcDocTimer( "sc::ScExternalRefManager maSrcDocTimer" )
+{
+ maSrcDocTimer.SetInvokeHandler( LINK(this, ScExternalRefManager, TimeOutHdl) );
+ maSrcDocTimer.SetTimeout(SRCDOC_SCAN_INTERVAL);
+}
+
+ScExternalRefManager::~ScExternalRefManager()
+{
+ clear();
+}
+
+OUString ScExternalRefManager::getCacheTableName(sal_uInt16 nFileId, size_t nTabIndex) const
+{
+ return maRefCache.getTableName(nFileId, nTabIndex);
+}
+
+ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(sal_uInt16 nFileId, size_t nTabIndex) const
+{
+ return maRefCache.getCacheTable(nFileId, nTabIndex);
+}
+
+ScExternalRefCache::TableTypeRef ScExternalRefManager::getCacheTable(
+ sal_uInt16 nFileId, const OUString& rTabName, bool bCreateNew, size_t* pnIndex, const OUString* pExtUrl)
+{
+ return maRefCache.getCacheTable(nFileId, rTabName, bCreateNew, pnIndex, pExtUrl);
+}
+
+ScExternalRefManager::LinkListener::LinkListener()
+{
+}
+
+ScExternalRefManager::LinkListener::~LinkListener()
+{
+}
+
+ScExternalRefManager::ApiGuard::ApiGuard(const ScDocument& rDoc) :
+ mpMgr(rDoc.GetExternalRefManager()),
+ mbOldInteractionEnabled(mpMgr->mbUserInteractionEnabled)
+{
+ // We don't want user interaction handled in the API.
+ mpMgr->mbUserInteractionEnabled = false;
+}
+
+ScExternalRefManager::ApiGuard::~ApiGuard()
+{
+ // Restore old value.
+ mpMgr->mbUserInteractionEnabled = mbOldInteractionEnabled;
+}
+
+void ScExternalRefManager::getAllCachedTableNames(sal_uInt16 nFileId, vector<OUString>& rTabNames) const
+{
+ maRefCache.getAllTableNames(nFileId, rTabNames);
+}
+
+SCTAB ScExternalRefManager::getCachedTabSpan( sal_uInt16 nFileId, const OUString& rStartTabName, const OUString& rEndTabName ) const
+{
+ return maRefCache.getTabSpan( nFileId, rStartTabName, rEndTabName);
+}
+
+void ScExternalRefManager::getAllCachedNumberFormats(vector<sal_uInt32>& rNumFmts) const
+{
+ maRefCache.getAllNumberFormats(rNumFmts);
+}
+
+sal_uInt16 ScExternalRefManager::getExternalFileCount() const
+{
+ return static_cast< sal_uInt16 >( maSrcFiles.size() );
+}
+
+void ScExternalRefManager::markUsedByLinkListeners()
+{
+ bool bAllMarked = false;
+ for (const auto& [rFileId, rLinkListeners] : maLinkListeners)
+ {
+ if (!rLinkListeners.empty())
+ bAllMarked = maRefCache.setCacheDocReferenced(rFileId);
+
+ if (bAllMarked)
+ break;
+ /* TODO: LinkListeners should remember the table they're listening to.
+ * As is, listening to one table will mark all tables of the document
+ * being referenced. */
+ }
+}
+
+void ScExternalRefManager::markUsedExternalRefCells()
+{
+ for (const auto& rEntry : maRefCells)
+ {
+ for (ScFormulaCell* pCell : rEntry.second)
+ {
+ bool bUsed = pCell->MarkUsedExternalReferences();
+ if (bUsed)
+ // Return true when at least one cell references external docs.
+ return;
+ }
+ }
+}
+
+bool ScExternalRefManager::setCacheTableReferenced( sal_uInt16 nFileId, const OUString& rTabName, size_t nSheets )
+{
+ return maRefCache.setCacheTableReferenced( nFileId, rTabName, nSheets);
+}
+
+void ScExternalRefManager::setAllCacheTableReferencedStati( bool bReferenced )
+{
+ mbInReferenceMarking = !bReferenced;
+ maRefCache.setAllCacheTableReferencedStati( bReferenced );
+}
+
+void ScExternalRefManager::storeRangeNameTokens(sal_uInt16 nFileId, const OUString& rName, const ScTokenArray& rArray)
+{
+ ScExternalRefCache::TokenArrayRef pNewArray;
+ if (!rArray.HasExternalRef())
+ {
+ // Parse all tokens in this external range data, and replace each absolute
+ // reference token with an external reference token, and cache them.
+ pNewArray = std::make_shared<ScTokenArray>(mrDoc);
+ FormulaTokenArrayPlainIterator aIter(rArray);
+ for (const FormulaToken* pToken = aIter.First(); pToken; pToken = aIter.Next())
+ {
+ bool bTokenAdded = false;
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ {
+ const ScSingleRefData& rRef = *pToken->GetSingleRef();
+ OUString aTabName;
+ if (SCTAB nCacheId = rRef.Tab(); nCacheId >= 0)
+ aTabName = maRefCache.getTableName(nFileId, nCacheId);
+ ScExternalSingleRefToken aNewToken(nFileId, svl::SharedString(aTabName), // string not interned
+ *pToken->GetSingleRef());
+ pNewArray->AddToken(aNewToken);
+ bTokenAdded = true;
+ }
+ break;
+ case svDoubleRef:
+ {
+ const ScSingleRefData& rRef = *pToken->GetSingleRef();
+ OUString aTabName;
+ if (SCTAB nCacheId = rRef.Tab(); nCacheId >= 0)
+ aTabName = maRefCache.getTableName(nFileId, nCacheId);
+ ScExternalDoubleRefToken aNewToken(nFileId, svl::SharedString(aTabName), // string not interned
+ *pToken->GetDoubleRef());
+ pNewArray->AddToken(aNewToken);
+ bTokenAdded = true;
+ }
+ break;
+ default:
+ ; // nothing
+ }
+
+ if (!bTokenAdded)
+ pNewArray->AddToken(*pToken);
+ }
+ }
+ else
+ pNewArray = rArray.Clone();
+
+ maRefCache.setRangeNameTokens(nFileId, rName, pNewArray);
+}
+
+namespace {
+
+/**
+ * Put a single cell data into internal cache table.
+ *
+ * @param pFmt optional cell format index that may need to be stored with
+ * the cell value.
+ */
+void putCellDataIntoCache(
+ ScExternalRefCache& rRefCache, const ScExternalRefCache::TokenRef& pToken,
+ sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rCell,
+ const ScExternalRefCache::CellFormat* pFmt)
+{
+ // Now, insert the token into cache table but don't cache empty cells.
+ if (pToken->GetType() != formula::svEmptyCell)
+ {
+ sal_uLong nFmtIndex = (pFmt && pFmt->mbIsSet) ? pFmt->mnIndex : 0;
+ rRefCache.setCellData(nFileId, rTabName, rCell.Col(), rCell.Row(), pToken, nFmtIndex);
+ }
+}
+
+/**
+ * Put the data into our internal cache table.
+ *
+ * @param rRefCache cache table set.
+ * @param pArray single range data to be returned.
+ * @param nFileId external file ID
+ * @param rTabName name of the table where the data should be cached.
+ * @param rCacheData range data to be cached.
+ * @param rCacheRange original cache range, including the empty region if
+ * any.
+ * @param rDataRange reduced cache range that includes only the non-empty
+ * data area.
+ */
+void putRangeDataIntoCache(
+ ScExternalRefCache& rRefCache, ScExternalRefCache::TokenArrayRef& pArray,
+ sal_uInt16 nFileId, const OUString& rTabName,
+ const vector<ScExternalRefCache::SingleRangeData>& rCacheData,
+ const ScRange& rCacheRange, const ScRange& rDataRange)
+{
+ if (pArray)
+ // Cache these values.
+ rRefCache.setCellRangeData(nFileId, rDataRange, rCacheData, pArray);
+ else
+ {
+ // Array is empty. Fill it with an empty matrix of the required size.
+ pArray = lcl_fillEmptyMatrix(rRefCache.getDoc(), rCacheRange);
+
+ // Make sure to set this range 'cached', to prevent unnecessarily
+ // accessing the src document time and time again.
+ ScExternalRefCache::TableTypeRef pCacheTab =
+ rRefCache.getCacheTable(nFileId, rTabName, true, nullptr, nullptr);
+ if (pCacheTab)
+ pCacheTab->setCachedCellRange(
+ rCacheRange.aStart.Col(), rCacheRange.aStart.Row(), rCacheRange.aEnd.Col(), rCacheRange.aEnd.Row());
+ }
+}
+
+/**
+ * When accessing an external document for the first time, we need to
+ * populate the cache with all its sheet names (whether they are referenced
+ * or not) in the correct order. Many client codes that use external
+ * references make this assumption.
+ *
+ * @param rRefCache cache table set.
+ * @param pSrcDoc source document instance.
+ * @param nFileId external file ID associated with the source document.
+ */
+void initDocInCache(ScExternalRefCache& rRefCache, const ScDocument* pSrcDoc, sal_uInt16 nFileId)
+{
+ if (!pSrcDoc)
+ return;
+
+ if (rRefCache.isDocInitialized(nFileId))
+ // Already initialized. No need to do this twice.
+ return;
+
+ SCTAB nTabCount = pSrcDoc->GetTableCount();
+ if (!nTabCount)
+ return;
+
+ // Populate the cache with all table names in the source document.
+ vector<OUString> aTabNames;
+ aTabNames.reserve(nTabCount);
+ for (SCTAB i = 0; i < nTabCount; ++i)
+ {
+ OUString aName;
+ pSrcDoc->GetName(i, aName);
+ aTabNames.push_back(aName);
+ }
+
+ // Obtain the base name, don't bother if there are more than one sheets.
+ OUString aBaseName;
+ if (nTabCount == 1)
+ {
+ const SfxObjectShell* pShell = pSrcDoc->GetDocumentShell();
+ if (pShell && pShell->GetMedium())
+ {
+ OUString aName = pShell->GetMedium()->GetName();
+ aBaseName = INetURLObject( aName).GetBase();
+ }
+ }
+
+ rRefCache.initializeDoc(nFileId, aTabNames, aBaseName);
+}
+
+}
+
+bool ScExternalRefManager::getSrcDocTable( const ScDocument& rSrcDoc, const OUString& rTabName, SCTAB& rTab,
+ sal_uInt16 nFileId ) const
+{
+ return maRefCache.getSrcDocTable( rSrcDoc, rTabName, rTab, nFileId);
+}
+
+ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefToken(
+ sal_uInt16 nFileId, const OUString& rTabName, const ScAddress& rCell,
+ const ScAddress* pCurPos, SCTAB* pTab, ScExternalRefCache::CellFormat* pFmt)
+{
+ if (pCurPos)
+ insertRefCell(nFileId, *pCurPos);
+
+ maybeLinkExternalFile(nFileId);
+
+ if (pTab)
+ *pTab = -1;
+
+ if (pFmt)
+ pFmt->mbIsSet = false;
+
+ ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
+ if (pSrcDoc)
+ {
+ // source document already loaded in memory. Re-use this instance.
+ SCTAB nTab;
+ if (!getSrcDocTable( *pSrcDoc, rTabName, nTab, nFileId))
+ {
+ // specified table name doesn't exist in the source document.
+ ScExternalRefCache::TokenRef pToken(new FormulaErrorToken(FormulaError::NoRef));
+ return pToken;
+ }
+
+ if (pTab)
+ *pTab = nTab;
+
+ ScExternalRefCache::TokenRef pToken =
+ getSingleRefTokenFromSrcDoc(
+ nFileId, *pSrcDoc, ScAddress(rCell.Col(),rCell.Row(),nTab), pFmt);
+
+ putCellDataIntoCache(maRefCache, pToken, nFileId, rTabName, rCell, pFmt);
+ return pToken;
+ }
+
+ // Check if the given table name and the cell position is cached.
+ sal_uInt32 nFmtIndex = 0;
+ ScExternalRefCache::TokenRef pToken = maRefCache.getCellData(
+ nFileId, rTabName, rCell.Col(), rCell.Row(), &nFmtIndex);
+ if (pToken)
+ {
+ // Cache hit !
+ fillCellFormat(nFmtIndex, pFmt);
+ return pToken;
+ }
+
+ // reference not cached. read from the source document.
+ pSrcDoc = getSrcDocument(nFileId);
+ if (!pSrcDoc)
+ {
+ // Source document not reachable.
+ if (!isLinkUpdateAllowedInDoc(mrDoc))
+ {
+ // Indicate with specific error.
+ pToken.reset(new FormulaErrorToken(FormulaError::LinkFormulaNeedingCheck));
+ }
+ else
+ {
+ // Throw a reference error.
+ pToken.reset(new FormulaErrorToken(FormulaError::NoRef));
+ }
+ return pToken;
+ }
+
+ SCTAB nTab;
+ if (!getSrcDocTable( *pSrcDoc, rTabName, nTab, nFileId))
+ {
+ // specified table name doesn't exist in the source document.
+ pToken.reset(new FormulaErrorToken(FormulaError::NoRef));
+ return pToken;
+ }
+
+ if (pTab)
+ *pTab = nTab;
+
+ SCCOL nDataCol1 = 0, nDataCol2 = pSrcDoc->MaxCol();
+ SCROW nDataRow1 = 0, nDataRow2 = pSrcDoc->MaxRow();
+ bool bData = pSrcDoc->ShrinkToDataArea(nTab, nDataCol1, nDataRow1, nDataCol2, nDataRow2);
+ if (!bData || rCell.Col() < nDataCol1 || nDataCol2 < rCell.Col() || rCell.Row() < nDataRow1 || nDataRow2 < rCell.Row())
+ {
+ // requested cell is outside the data area. Don't even bother caching
+ // this data, but add it to the cached range to prevent accessing the
+ // source document time and time again.
+ ScExternalRefCache::TableTypeRef pCacheTab =
+ maRefCache.getCacheTable(nFileId, rTabName, true, nullptr, nullptr);
+ if (pCacheTab)
+ pCacheTab->setCachedCell(rCell.Col(), rCell.Row());
+
+ pToken.reset(new ScEmptyCellToken(false, false));
+ return pToken;
+ }
+
+ pToken = getSingleRefTokenFromSrcDoc(
+ nFileId, *pSrcDoc, ScAddress(rCell.Col(),rCell.Row(),nTab), pFmt);
+
+ putCellDataIntoCache(maRefCache, pToken, nFileId, rTabName, rCell, pFmt);
+ return pToken;
+}
+
+ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokens(
+ sal_uInt16 nFileId, const OUString& rTabName, const ScRange& rRange, const ScAddress* pCurPos)
+{
+ if (pCurPos)
+ insertRefCell(nFileId, *pCurPos);
+
+ maybeLinkExternalFile(nFileId);
+
+ ScRange aDataRange(rRange);
+ ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
+ if (pSrcDoc)
+ {
+ // Document already loaded in memory.
+ vector<ScExternalRefCache::SingleRangeData> aCacheData;
+ ScExternalRefCache::TokenArrayRef pArray =
+ getDoubleRefTokensFromSrcDoc(*pSrcDoc, rTabName, aDataRange, aCacheData);
+
+ // Put the data into cache.
+ putRangeDataIntoCache(maRefCache, pArray, nFileId, rTabName, aCacheData, rRange, aDataRange);
+ return pArray;
+ }
+
+ // Check if the given table name and the cell position is cached.
+ ScExternalRefCache::TokenArrayRef pArray =
+ maRefCache.getCellRangeData(nFileId, rTabName, rRange);
+ if (pArray)
+ // Cache hit !
+ return pArray;
+
+ pSrcDoc = getSrcDocument(nFileId);
+ if (!pSrcDoc)
+ {
+ // Source document is not reachable. Throw a reference error.
+ pArray = std::make_shared<ScTokenArray>(maRefCache.getDoc());
+ pArray->AddToken(FormulaErrorToken(FormulaError::NoRef));
+ return pArray;
+ }
+
+ vector<ScExternalRefCache::SingleRangeData> aCacheData;
+ pArray = getDoubleRefTokensFromSrcDoc(*pSrcDoc, rTabName, aDataRange, aCacheData);
+
+ // Put the data into cache.
+ putRangeDataIntoCache(maRefCache, pArray, nFileId, rTabName, aCacheData, rRange, aDataRange);
+ return pArray;
+}
+
+ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokens(
+ sal_uInt16 nFileId, const OUString& rName, const ScAddress* pCurPos)
+{
+ if (pCurPos)
+ insertRefCell(nFileId, *pCurPos);
+
+ maybeLinkExternalFile(nFileId);
+
+ OUString aName = rName; // make a copy to have the casing corrected.
+ ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
+ if (pSrcDoc)
+ {
+ // Document already loaded in memory.
+ ScExternalRefCache::TokenArrayRef pArray =
+ getRangeNameTokensFromSrcDoc(nFileId, *pSrcDoc, aName);
+
+ if (pArray)
+ // Cache this range name array.
+ maRefCache.setRangeNameTokens(nFileId, aName, pArray);
+
+ return pArray;
+ }
+
+ ScExternalRefCache::TokenArrayRef pArray = maRefCache.getRangeNameTokens(nFileId, rName);
+ if (pArray)
+ // This range name is cached.
+ return pArray;
+
+ pSrcDoc = getSrcDocument(nFileId);
+ if (!pSrcDoc)
+ // failed to load document from disk.
+ return ScExternalRefCache::TokenArrayRef();
+
+ pArray = getRangeNameTokensFromSrcDoc(nFileId, *pSrcDoc, aName);
+
+ if (pArray)
+ // Cache this range name array.
+ maRefCache.setRangeNameTokens(nFileId, aName, pArray);
+
+ return pArray;
+}
+
+namespace {
+
+bool hasRangeName(const ScDocument& rDoc, const OUString& rName)
+{
+ ScRangeName* pExtNames = rDoc.GetRangeName();
+ OUString aUpperName = ScGlobal::getCharClass().uppercase(rName);
+ const ScRangeData* pRangeData = pExtNames->findByUpperName(aUpperName);
+ return pRangeData != nullptr;
+}
+
+}
+
+bool ScExternalRefManager::isValidRangeName(sal_uInt16 nFileId, const OUString& rName)
+{
+ maybeLinkExternalFile(nFileId);
+ ScDocument* pSrcDoc = getInMemorySrcDocument(nFileId);
+ if (pSrcDoc)
+ {
+ // Only check the presence of the name.
+ if (hasRangeName(*pSrcDoc, rName))
+ {
+ maRefCache.setRangeName(nFileId, rName);
+ return true;
+ }
+ return false;
+ }
+
+ if (maRefCache.isValidRangeName(nFileId, rName))
+ // Range name is cached.
+ return true;
+
+ pSrcDoc = getSrcDocument(nFileId);
+ if (!pSrcDoc)
+ // failed to load document from disk.
+ return false;
+
+ if (hasRangeName(*pSrcDoc, rName))
+ {
+ maRefCache.setRangeName(nFileId, rName);
+ return true;
+ }
+
+ return false;
+}
+
+void ScExternalRefManager::refreshAllRefCells(sal_uInt16 nFileId)
+{
+ RefCellMap::iterator itrFile = maRefCells.find(nFileId);
+ if (itrFile == maRefCells.end())
+ return;
+
+ RefCellSet& rRefCells = itrFile->second;
+ for_each(rRefCells.begin(), rRefCells.end(), UpdateFormulaCell());
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScTabViewShell* pVShell = pViewData->GetViewShell();
+ if (!pVShell)
+ return;
+
+ // Repainting the grid also repaints the texts, but is there a better way
+ // to refresh texts?
+ pVShell->Invalidate(FID_REPAINT);
+ pVShell->PaintGrid();
+}
+
+namespace {
+
+void insertRefCellByIterator(
+ const ScExternalRefManager::RefCellMap::iterator& itr, ScFormulaCell* pCell)
+{
+ if (pCell)
+ {
+ itr->second.insert(pCell);
+ pCell->SetIsExtRef();
+ }
+}
+
+}
+
+void ScExternalRefManager::insertRefCell(sal_uInt16 nFileId, const ScAddress& rCell)
+{
+ RefCellMap::iterator itr = maRefCells.find(nFileId);
+ if (itr == maRefCells.end())
+ {
+ RefCellSet aRefCells;
+ pair<RefCellMap::iterator, bool> r = maRefCells.emplace(
+ nFileId, aRefCells);
+ if (!r.second)
+ // insertion failed.
+ return;
+
+ itr = r.first;
+ }
+
+ insertRefCellByIterator(itr, mrDoc.GetFormulaCell(rCell));
+}
+
+void ScExternalRefManager::insertRefCellFromTemplate( ScFormulaCell* pTemplateCell, ScFormulaCell* pCell )
+{
+ if (!pTemplateCell || !pCell)
+ return;
+
+ for (RefCellMap::iterator itr = maRefCells.begin(); itr != maRefCells.end(); ++itr)
+ {
+ if (itr->second.find(pTemplateCell) != itr->second.end())
+ insertRefCellByIterator(itr, pCell);
+ }
+}
+
+bool ScExternalRefManager::hasCellExternalReference(const ScAddress& rCell)
+{
+ ScFormulaCell* pCell = mrDoc.GetFormulaCell(rCell);
+
+ if (pCell)
+ return std::any_of(maRefCells.begin(), maRefCells.end(),
+ [&pCell](const RefCellMap::value_type& rEntry) { return rEntry.second.find(pCell) != rEntry.second.end(); });
+
+ return false;
+}
+
+void ScExternalRefManager::enableDocTimer( bool bEnable )
+{
+ if (mbDocTimerEnabled == bEnable)
+ return;
+
+ mbDocTimerEnabled = bEnable;
+ if (mbDocTimerEnabled)
+ {
+ if (!maDocShells.empty())
+ {
+ for (auto& rEntry : maDocShells)
+ rEntry.second.maLastAccess = tools::Time(tools::Time::SYSTEM);
+
+ maSrcDocTimer.Start();
+ }
+ }
+ else
+ maSrcDocTimer.Stop();
+}
+
+void ScExternalRefManager::fillCellFormat(sal_uLong nFmtIndex, ScExternalRefCache::CellFormat* pFmt) const
+{
+ if (!pFmt)
+ return;
+
+ SvNumFormatType nFmtType = mrDoc.GetFormatTable()->GetType(nFmtIndex);
+ if (nFmtType != SvNumFormatType::UNDEFINED)
+ {
+ pFmt->mbIsSet = true;
+ pFmt->mnIndex = nFmtIndex;
+ pFmt->mnType = nFmtType;
+ }
+}
+
+ScExternalRefCache::TokenRef ScExternalRefManager::getSingleRefTokenFromSrcDoc(
+ sal_uInt16 nFileId, ScDocument& rSrcDoc, const ScAddress& rPos,
+ ScExternalRefCache::CellFormat* pFmt)
+{
+ // Get the cell from src doc, and convert it into a token.
+ ScRefCellValue aCell(rSrcDoc, rPos);
+ ScExternalRefCache::TokenRef pToken(convertToToken(mrDoc, rSrcDoc, aCell));
+
+ if (!pToken)
+ {
+ // Generate an error for unresolvable cells.
+ pToken.reset( new FormulaErrorToken( FormulaError::NoValue));
+ }
+
+ // Get number format information.
+ sal_uInt32 nFmtIndex = rSrcDoc.GetNumberFormat(rPos.Col(), rPos.Row(), rPos.Tab());
+ nFmtIndex = getMappedNumberFormat(nFileId, nFmtIndex, rSrcDoc);
+ fillCellFormat(nFmtIndex, pFmt);
+ return pToken;
+}
+
+ScExternalRefCache::TokenArrayRef ScExternalRefManager::getDoubleRefTokensFromSrcDoc(
+ const ScDocument& rSrcDoc, const OUString& rTabName, ScRange& rRange,
+ vector<ScExternalRefCache::SingleRangeData>& rCacheData)
+{
+ ScExternalRefCache::TokenArrayRef pArray;
+ SCTAB nTab1;
+
+ if (!rSrcDoc.GetTable(rTabName, nTab1))
+ {
+ // specified table name doesn't exist in the source document.
+ pArray = std::make_shared<ScTokenArray>(rSrcDoc);
+ pArray->AddToken(FormulaErrorToken(FormulaError::NoRef));
+ return pArray;
+ }
+
+ ScRange aRange(rRange);
+ aRange.PutInOrder();
+ SCTAB nTabSpan = aRange.aEnd.Tab() - aRange.aStart.Tab();
+
+ vector<ScExternalRefCache::SingleRangeData> aCacheData;
+ aCacheData.reserve(nTabSpan+1);
+ aCacheData.emplace_back();
+ aCacheData.back().maTableName = ScGlobal::getCharClass().uppercase(rTabName);
+
+ for (SCTAB i = 1; i < nTabSpan + 1; ++i)
+ {
+ OUString aTabName;
+ if (!rSrcDoc.GetName(nTab1 + 1, aTabName))
+ // source document doesn't have any table by the specified name.
+ break;
+
+ aCacheData.emplace_back();
+ aCacheData.back().maTableName = ScGlobal::getCharClass().uppercase(aTabName);
+ }
+
+ aRange.aStart.SetTab(nTab1);
+ aRange.aEnd.SetTab(nTab1 + nTabSpan);
+
+ pArray = convertToTokenArray(mrDoc, rSrcDoc, aRange, aCacheData);
+ rRange = aRange;
+ rCacheData.swap(aCacheData);
+ return pArray;
+}
+
+ScExternalRefCache::TokenArrayRef ScExternalRefManager::getRangeNameTokensFromSrcDoc(
+ sal_uInt16 nFileId, const ScDocument& rSrcDoc, OUString& rName)
+{
+ ScRangeName* pExtNames = rSrcDoc.GetRangeName();
+ OUString aUpperName = ScGlobal::getCharClass().uppercase(rName);
+ const ScRangeData* pRangeData = pExtNames->findByUpperName(aUpperName);
+ if (!pRangeData)
+ return ScExternalRefCache::TokenArrayRef();
+
+ // Parse all tokens in this external range data, and replace each absolute
+ // reference token with an external reference token, and cache them. Also
+ // register the source document with the link manager if it's a new
+ // source.
+
+ ScExternalRefCache::TokenArrayRef pNew = std::make_shared<ScTokenArray>(rSrcDoc);
+
+ ScTokenArray aCode(*pRangeData->GetCode());
+ FormulaTokenArrayPlainIterator aIter(aCode);
+ for (const FormulaToken* pToken = aIter.First(); pToken; pToken = aIter.Next())
+ {
+ bool bTokenAdded = false;
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ {
+ const ScSingleRefData& rRef = *pToken->GetSingleRef();
+ OUString aTabName;
+ rSrcDoc.GetName(rRef.Tab(), aTabName);
+ ScExternalSingleRefToken aNewToken(nFileId, svl::SharedString( aTabName), // string not interned
+ *pToken->GetSingleRef());
+ pNew->AddToken(aNewToken);
+ bTokenAdded = true;
+ }
+ break;
+ case svDoubleRef:
+ {
+ const ScSingleRefData& rRef = *pToken->GetSingleRef();
+ OUString aTabName;
+ rSrcDoc.GetName(rRef.Tab(), aTabName);
+ ScExternalDoubleRefToken aNewToken(nFileId, svl::SharedString( aTabName), // string not interned
+ *pToken->GetDoubleRef());
+ pNew->AddToken(aNewToken);
+ bTokenAdded = true;
+ }
+ break;
+ default:
+ ; // nothing
+ }
+
+ if (!bTokenAdded)
+ pNew->AddToken(*pToken);
+ }
+
+ rName = pRangeData->GetName(); // Get the correctly-cased name.
+ return pNew;
+}
+
+ScDocument* ScExternalRefManager::getInMemorySrcDocument(sal_uInt16 nFileId)
+{
+ const OUString* pFileName = getExternalFileName(nFileId);
+ if (!pFileName)
+ return nullptr;
+
+ // Do not load document until it was allowed.
+ if (!isLinkUpdateAllowedInDoc(mrDoc))
+ return nullptr;
+
+ ScDocument* pSrcDoc = nullptr;
+ ScDocShell* pShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(checkSfxObjectShell<ScDocShell>, false));
+ while (pShell)
+ {
+ SfxMedium* pMedium = pShell->GetMedium();
+ if (pMedium && !pMedium->GetName().isEmpty())
+ {
+ // TODO: We should make the case sensitivity platform dependent.
+ if (pFileName->equalsIgnoreAsciiCase(pMedium->GetName()))
+ {
+ // Found !
+ pSrcDoc = &pShell->GetDocument();
+ break;
+ }
+ }
+ else
+ {
+ // handle unsaved documents here
+ OUString aName = pShell->GetName();
+ if (pFileName->equalsIgnoreAsciiCase(aName))
+ {
+ // Found !
+ SrcShell aSrcDoc;
+ aSrcDoc.maShell = pShell;
+ maUnsavedDocShells.emplace(nFileId, aSrcDoc);
+ StartListening(*pShell);
+ pSrcDoc = &pShell->GetDocument();
+ break;
+ }
+ }
+ pShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pShell, checkSfxObjectShell<ScDocShell>, false));
+ }
+
+ initDocInCache(maRefCache, pSrcDoc, nFileId);
+ return pSrcDoc;
+}
+
+ScDocument* ScExternalRefManager::getSrcDocument(sal_uInt16 nFileId)
+{
+ if (!mrDoc.IsExecuteLinkEnabled())
+ return nullptr;
+
+ DocShellMap::iterator itrEnd = maDocShells.end();
+ DocShellMap::iterator itr = maDocShells.find(nFileId);
+
+ if (itr != itrEnd)
+ {
+ // document already loaded.
+
+ SfxObjectShell* p = itr->second.maShell.get();
+ itr->second.maLastAccess = tools::Time( tools::Time::SYSTEM );
+ return &static_cast<ScDocShell*>(p)->GetDocument();
+ }
+
+ itrEnd = maUnsavedDocShells.end();
+ itr = maUnsavedDocShells.find(nFileId);
+ if (itr != itrEnd)
+ {
+ //document is unsaved document
+
+ SfxObjectShell* p = itr->second.maShell.get();
+ itr->second.maLastAccess = tools::Time( tools::Time::SYSTEM );
+ return &static_cast<ScDocShell*>(p)->GetDocument();
+ }
+
+ const OUString* pFile = getExternalFileName(nFileId);
+ if (!pFile)
+ // no file name associated with this ID.
+ return nullptr;
+
+ SrcShell aSrcDoc;
+ try
+ {
+ OUString aFilter;
+ aSrcDoc.maShell = loadSrcDocument(nFileId, aFilter);
+ }
+ catch (const css::uno::Exception&)
+ {
+ }
+ if (!aSrcDoc.maShell.is())
+ {
+ // source document could not be loaded.
+ return nullptr;
+ }
+
+ return &cacheNewDocShell(nFileId, aSrcDoc);
+}
+
+SfxObjectShellRef ScExternalRefManager::loadSrcDocument(sal_uInt16 nFileId, OUString& rFilter)
+{
+ // Do not load document until it was allowed.
+ if (!isLinkUpdateAllowedInDoc(mrDoc))
+ return nullptr;
+
+ const SrcFileData* pFileData = getExternalFileData(nFileId);
+ if (!pFileData)
+ return nullptr;
+
+ // Always load the document by using the path created from the relative
+ // path. If the referenced document is not there, simply exit. The
+ // original file name should be used only when the relative path is not
+ // given.
+ OUString aFile = pFileData->maFileName;
+ maybeCreateRealFileName(nFileId);
+ if (!pFileData->maRealFileName.isEmpty())
+ aFile = pFileData->maRealFileName;
+
+ if (!isFileLoadable(aFile))
+ return nullptr;
+
+ OUString aOptions = pFileData->maFilterOptions;
+ if ( !pFileData->maFilterName.isEmpty() )
+ rFilter = pFileData->maFilterName; // don't overwrite stored filter with guessed filter
+ else
+ ScDocumentLoader::GetFilterName(aFile, rFilter, aOptions, true, false);
+ std::shared_ptr<const SfxFilter> pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName(rFilter);
+
+ if (pFileData->maRelativeName.isEmpty())
+ {
+ // Generate a relative file path.
+ INetURLObject aBaseURL(getOwnDocumentName());
+ aBaseURL.insertName(u"content.xml");
+
+ OUString aStr = URIHelper::simpleNormalizedMakeRelative(
+ aBaseURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), aFile);
+
+ setRelativeFileName(nFileId, aStr);
+ }
+
+ std::unique_ptr<SfxItemSet> pSet(new SfxAllItemSet(SfxGetpApp()->GetPool()));
+ if (!aOptions.isEmpty())
+ pSet->Put(SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
+
+ // make medium hidden to prevent assertion from progress bar
+ pSet->Put( SfxBoolItem(SID_HIDDEN, true) );
+
+ // If the current document is allowed to execute macros then the referenced
+ // document may execute macros according to the security configuration.
+ // Similar for UpdateDocMode to update links, just that if we reach here
+ // the user already allowed updates and intermediate documents are expected
+ // to update as well. When loading the document ScDocShell::Load() will
+ // check through ScDocShell::GetLinkUpdateModeState() if its location is
+ // trusted.
+ SfxObjectShell* pShell = mrDoc.GetDocumentShell();
+ if (pShell)
+ {
+ SfxMedium* pMedium = pShell->GetMedium();
+ if (pMedium)
+ {
+ const SfxUInt16Item* pItem = pMedium->GetItemSet()->GetItemIfSet( SID_MACROEXECMODE, false );
+ if (pItem &&
+ pItem->GetValue() != css::document::MacroExecMode::NEVER_EXECUTE)
+ pSet->Put( SfxUInt16Item( SID_MACROEXECMODE, css::document::MacroExecMode::USE_CONFIG));
+ }
+
+ pSet->Put( SfxUInt16Item( SID_UPDATEDOCMODE, css::document::UpdateDocMode::FULL_UPDATE));
+ }
+
+ unique_ptr<SfxMedium> pMedium(new SfxMedium(aFile, StreamMode::STD_READ, pFilter, std::move(pSet)));
+ if (pMedium->GetError() != ERRCODE_NONE)
+ return nullptr;
+
+ // To load encrypted documents with password, user interaction needs to be enabled.
+ pMedium->UseInteractionHandler(mbUserInteractionEnabled);
+
+ ScDocShell* pNewShell = new ScDocShell(SfxModelFlags::EXTERNAL_LINK);
+ SfxObjectShellRef aRef = pNewShell;
+
+ // increment the recursive link count of the source document.
+ ScExtDocOptions* pExtOpt = mrDoc.GetExtDocOptions();
+ sal_uInt32 nLinkCount = pExtOpt ? pExtOpt->GetDocSettings().mnLinkCnt : 0;
+ ScDocument& rSrcDoc = pNewShell->GetDocument();
+ rSrcDoc.EnableExecuteLink(false); // to prevent circular access of external references.
+ rSrcDoc.EnableUndo(false);
+ rSrcDoc.LockAdjustHeight();
+ rSrcDoc.EnableUserInteraction(false);
+
+ ScExtDocOptions* pExtOptNew = rSrcDoc.GetExtDocOptions();
+ if (!pExtOptNew)
+ {
+ rSrcDoc.SetExtDocOptions(std::make_unique<ScExtDocOptions>());
+ pExtOptNew = rSrcDoc.GetExtDocOptions();
+ }
+ pExtOptNew->GetDocSettings().mnLinkCnt = nLinkCount + 1;
+
+ if (!pNewShell->DoLoad(pMedium.release()))
+ {
+ aRef->DoClose();
+ aRef.clear();
+ return aRef;
+ }
+
+ // with UseInteractionHandler, options may be set by dialog during DoLoad
+ OUString aNew = ScDocumentLoader::GetOptions(*pNewShell->GetMedium());
+ if (!aNew.isEmpty() && aNew != aOptions)
+ aOptions = aNew;
+ setFilterData(nFileId, rFilter, aOptions); // update the filter data, including the new options
+
+ return aRef;
+}
+
+ScDocument& ScExternalRefManager::cacheNewDocShell( sal_uInt16 nFileId, SrcShell& rSrcShell )
+{
+ if (mbDocTimerEnabled && maDocShells.empty())
+ // If this is the first source document insertion, start up the timer.
+ maSrcDocTimer.Start();
+
+ maDocShells.emplace(nFileId, rSrcShell);
+ SfxObjectShell& rShell = *rSrcShell.maShell;
+ ScDocument& rSrcDoc = static_cast<ScDocShell&>(rShell).GetDocument();
+ initDocInCache(maRefCache, &rSrcDoc, nFileId);
+ return rSrcDoc;
+}
+
+bool ScExternalRefManager::isFileLoadable(const OUString& rFile) const
+{
+ if (rFile.isEmpty())
+ return false;
+
+ if (isOwnDocument(rFile))
+ return false;
+ OUString aPhysical;
+ if (osl::FileBase::getSystemPathFromFileURL(rFile, aPhysical)
+ == osl::FileBase::E_None)
+ {
+ // #i114504# try IsFolder/Exists only for file URLs
+
+ if (utl::UCBContentHelper::IsFolder(rFile))
+ return false;
+
+ return utl::UCBContentHelper::Exists(rFile);
+ }
+ else
+ return true; // for http and others, Exists doesn't work, but the URL can still be opened
+}
+
+void ScExternalRefManager::maybeLinkExternalFile( sal_uInt16 nFileId, bool bDeferFilterDetection )
+{
+ if (maLinkedDocs.count(nFileId))
+ // file already linked, or the link has been broken.
+ return;
+
+ // Source document not linked yet. Link it now.
+ const OUString* pFileName = getExternalFileName(nFileId);
+ if (!pFileName)
+ return;
+
+ OUString aFilter, aOptions;
+ const SrcFileData* pFileData = getExternalFileData(nFileId);
+ if (pFileData)
+ {
+ aFilter = pFileData->maFilterName;
+ aOptions = pFileData->maFilterOptions;
+ }
+
+ // Filter detection may access external links; defer it until we are allowed.
+ if (!bDeferFilterDetection)
+ bDeferFilterDetection = !isLinkUpdateAllowedInDoc(mrDoc);
+
+ // If a filter was already set (for example, loading the cached table),
+ // don't call GetFilterName which has to access the source file.
+ // If filter detection is deferred, the next successful loadSrcDocument()
+ // will update SrcFileData filter name.
+ if (aFilter.isEmpty() && !bDeferFilterDetection)
+ ScDocumentLoader::GetFilterName(*pFileName, aFilter, aOptions, true, false);
+ sfx2::LinkManager* pLinkMgr = mrDoc.GetLinkManager();
+ if (!pLinkMgr)
+ {
+ SAL_WARN( "sc.ui", "ScExternalRefManager::maybeLinkExternalFile: pLinkMgr==NULL");
+ return;
+ }
+ ScExternalRefLink* pLink = new ScExternalRefLink(mrDoc, nFileId);
+ OSL_ENSURE(pFileName, "ScExternalRefManager::maybeLinkExternalFile: file name pointer is NULL");
+ pLinkMgr->InsertFileLink(*pLink, sfx2::SvBaseLinkObjectType::ClientFile, *pFileName,
+ (aFilter.isEmpty() && bDeferFilterDetection ? nullptr : &aFilter));
+
+ pLink->SetDoRefresh(false);
+ pLink->Update();
+ pLink->SetDoRefresh(true);
+
+ maLinkedDocs.emplace(nFileId, true);
+}
+
+void ScExternalRefManager::addFilesToLinkManager()
+{
+ if (maSrcFiles.empty())
+ return;
+
+ SAL_WARN_IF( maSrcFiles.size() >= SAL_MAX_UINT16,
+ "sc.ui", "ScExternalRefManager::addFilesToLinkManager: files overflow");
+ const sal_uInt16 nSize = static_cast<sal_uInt16>( std::min<size_t>( maSrcFiles.size(), SAL_MAX_UINT16));
+ for (sal_uInt16 nFileId = 0; nFileId < nSize; ++nFileId)
+ maybeLinkExternalFile( nFileId, true);
+}
+
+void ScExternalRefManager::SrcFileData::maybeCreateRealFileName(std::u16string_view rOwnDocName)
+{
+ if (maRelativeName.isEmpty())
+ // No relative path given. Nothing to do.
+ return;
+
+ if (!maRealFileName.isEmpty())
+ // Real file name already created. Nothing to do.
+ return;
+
+ // Formulate the absolute file path from the relative path.
+ const OUString& rRelPath = maRelativeName;
+ INetURLObject aBaseURL(rOwnDocName);
+ aBaseURL.insertName(u"content.xml");
+ bool bWasAbs = false;
+ maRealFileName = aBaseURL.smartRel2Abs(rRelPath, bWasAbs).GetMainURL(INetURLObject::DecodeMechanism::NONE);
+}
+
+void ScExternalRefManager::maybeCreateRealFileName(sal_uInt16 nFileId)
+{
+ if (nFileId >= maSrcFiles.size())
+ return;
+
+ maSrcFiles[nFileId].maybeCreateRealFileName(getOwnDocumentName());
+}
+
+OUString ScExternalRefManager::getOwnDocumentName() const
+{
+ if (utl::ConfigManager::IsFuzzing())
+ return "file:///tmp/document";
+
+ SfxObjectShell* pShell = mrDoc.GetDocumentShell();
+ if (!pShell)
+ // This should not happen!
+ return OUString();
+
+ SfxMedium* pMed = pShell->GetMedium();
+ if (!pMed)
+ return OUString();
+
+ return pMed->GetName();
+}
+
+bool ScExternalRefManager::isOwnDocument(std::u16string_view rFile) const
+{
+ return getOwnDocumentName() == rFile;
+}
+
+void ScExternalRefManager::convertToAbsName(OUString& rFile) const
+{
+ // unsaved documents have no AbsName
+ ScDocShell* pShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(checkSfxObjectShell<ScDocShell>, false));
+ while (pShell)
+ {
+ if (rFile == pShell->GetName())
+ return;
+
+ pShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pShell, checkSfxObjectShell<ScDocShell>, false));
+ }
+
+ SfxObjectShell* pDocShell = mrDoc.GetDocumentShell();
+ rFile = ScGlobal::GetAbsDocName(rFile, pDocShell);
+}
+
+sal_uInt16 ScExternalRefManager::getExternalFileId(const OUString& rFile)
+{
+ vector<SrcFileData>::const_iterator itrBeg = maSrcFiles.begin(), itrEnd = maSrcFiles.end();
+ vector<SrcFileData>::const_iterator itr = find_if(itrBeg, itrEnd, FindSrcFileByName(rFile));
+ if (itr != itrEnd)
+ {
+ size_t nId = distance(itrBeg, itr);
+ return static_cast<sal_uInt16>(nId);
+ }
+
+ SrcFileData aData;
+ aData.maFileName = rFile;
+ maSrcFiles.push_back(aData);
+ return static_cast<sal_uInt16>(maSrcFiles.size() - 1);
+}
+
+const OUString* ScExternalRefManager::getExternalFileName(sal_uInt16 nFileId, bool bForceOriginal)
+{
+ if (nFileId >= maSrcFiles.size())
+ return nullptr;
+
+ if (bForceOriginal)
+ return &maSrcFiles[nFileId].maFileName;
+
+ maybeCreateRealFileName(nFileId);
+
+ if (!maSrcFiles[nFileId].maRealFileName.isEmpty())
+ return &maSrcFiles[nFileId].maRealFileName;
+
+ return &maSrcFiles[nFileId].maFileName;
+}
+
+sal_uInt16 ScExternalRefManager::convertFileIdToUsedFileId(sal_uInt16 nFileId)
+{
+ if (!mbSkipUnusedFileIds)
+ return nFileId;
+ else
+ return maConvertFileIdToUsedFileId[nFileId];
+}
+
+void ScExternalRefManager::setSkipUnusedFileIds(std::vector<sal_uInt16>& rExternFileIds)
+{
+ mbSkipUnusedFileIds = true;
+ maConvertFileIdToUsedFileId.resize(maSrcFiles.size());
+ std::fill(maConvertFileIdToUsedFileId.begin(), maConvertFileIdToUsedFileId.end(), 0);
+ int nUsedCount = 0;
+ for (auto nEntry : rExternFileIds)
+ {
+ maConvertFileIdToUsedFileId[nEntry] = nUsedCount++;
+ }
+}
+
+void ScExternalRefManager::disableSkipUnusedFileIds()
+{
+ mbSkipUnusedFileIds = false;
+}
+
+std::vector<OUString> ScExternalRefManager::getAllCachedExternalFileNames() const
+{
+ std::vector<OUString> aNames;
+ aNames.reserve(maSrcFiles.size());
+ for (const SrcFileData& rData : maSrcFiles)
+ {
+ aNames.push_back(rData.maFileName);
+ }
+
+ return aNames;
+}
+
+bool ScExternalRefManager::hasExternalFile(sal_uInt16 nFileId) const
+{
+ return nFileId < maSrcFiles.size();
+}
+
+bool ScExternalRefManager::hasExternalFile(const OUString& rFile) const
+{
+ return ::std::any_of(maSrcFiles.begin(), maSrcFiles.end(), FindSrcFileByName(rFile));
+}
+
+const ScExternalRefManager::SrcFileData* ScExternalRefManager::getExternalFileData(sal_uInt16 nFileId) const
+{
+ if (nFileId >= maSrcFiles.size())
+ return nullptr;
+
+ return &maSrcFiles[nFileId];
+}
+
+const OUString* ScExternalRefManager::getRealTableName(sal_uInt16 nFileId, const OUString& rTabName) const
+{
+ return maRefCache.getRealTableName(nFileId, rTabName);
+}
+
+const OUString* ScExternalRefManager::getRealRangeName(sal_uInt16 nFileId, const OUString& rRangeName) const
+{
+ return maRefCache.getRealRangeName(nFileId, rRangeName);
+}
+
+template<typename MapContainer>
+static void lcl_removeByFileId(sal_uInt16 nFileId, MapContainer& rMap)
+{
+ typename MapContainer::iterator itr = rMap.find(nFileId);
+ if (itr != rMap.end())
+ {
+ // Close this document shell.
+ itr->second.maShell->DoClose();
+ rMap.erase(itr);
+ }
+}
+
+void ScExternalRefManager::clearCache(sal_uInt16 nFileId)
+{
+ maRefCache.clearCache(nFileId);
+}
+
+namespace {
+
+class RefCacheFiller : public sc::ColumnSpanSet::ColumnAction
+{
+ svl::SharedStringPool& mrStrPool;
+
+ ScExternalRefCache& mrRefCache;
+ ScExternalRefCache::TableTypeRef mpRefTab;
+ sal_uInt16 mnFileId;
+ ScColumn* mpCurCol;
+ sc::ColumnBlockConstPosition maBlockPos;
+
+public:
+ RefCacheFiller( svl::SharedStringPool& rStrPool, ScExternalRefCache& rRefCache, sal_uInt16 nFileId ) :
+ mrStrPool(rStrPool), mrRefCache(rRefCache), mnFileId(nFileId), mpCurCol(nullptr) {}
+
+ virtual void startColumn( ScColumn* pCol ) override
+ {
+ mpCurCol = pCol;
+ if (!mpCurCol)
+ return;
+
+ mpCurCol->InitBlockPosition(maBlockPos);
+ mpRefTab = mrRefCache.getCacheTable(mnFileId, mpCurCol->GetTab());
+ }
+
+ virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) override
+ {
+ if (!mpCurCol || !bVal)
+ return;
+
+ if (!mpRefTab)
+ return;
+
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+ {
+ ScExternalRefCache::TokenRef pTok;
+ ScRefCellValue aCell = mpCurCol->GetCellValue(maBlockPos, nRow);
+ switch (aCell.meType)
+ {
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ {
+ OUString aStr = aCell.getString(&mpCurCol->GetDoc());
+ svl::SharedString aSS = mrStrPool.intern(aStr);
+ pTok.reset(new formula::FormulaStringToken(aSS));
+ }
+ break;
+ case CELLTYPE_VALUE:
+ pTok.reset(new formula::FormulaDoubleToken(aCell.mfValue));
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ sc::FormulaResultValue aRes = aCell.mpFormula->GetResult();
+ switch (aRes.meType)
+ {
+ case sc::FormulaResultValue::Value:
+ pTok.reset(new formula::FormulaDoubleToken(aRes.mfValue));
+ break;
+ case sc::FormulaResultValue::String:
+ {
+ // Re-intern the string to the host document pool.
+ svl::SharedString aInterned = mrStrPool.intern(aRes.maString.getString());
+ pTok.reset(new formula::FormulaStringToken(aInterned));
+ }
+ break;
+ case sc::FormulaResultValue::Error:
+ case sc::FormulaResultValue::Invalid:
+ default:
+ pTok.reset(new FormulaErrorToken(FormulaError::NoValue));
+ }
+ }
+ break;
+ default:
+ pTok.reset(new FormulaErrorToken(FormulaError::NoValue));
+ }
+
+ if (pTok)
+ {
+ // Cache this cell.
+ mpRefTab->setCell(mpCurCol->GetCol(), nRow, pTok, mpCurCol->GetNumberFormat(mpCurCol->GetDoc().GetNonThreadedContext(), nRow));
+ mpRefTab->setCachedCell(mpCurCol->GetCol(), nRow);
+ }
+ }
+ };
+};
+
+}
+
+bool ScExternalRefManager::refreshSrcDocument(sal_uInt16 nFileId)
+{
+ SfxObjectShellRef xDocShell;
+ try
+ {
+ OUString aFilter;
+ xDocShell = loadSrcDocument(nFileId, aFilter);
+ }
+ catch ( const css::uno::Exception& ) {}
+
+ if (!xDocShell.is())
+ // Failed to load the document. Bail out.
+ return false;
+
+ ScDocShell& rDocSh = static_cast<ScDocShell&>(*xDocShell);
+ ScDocument& rSrcDoc = rDocSh.GetDocument();
+
+ sc::ColumnSpanSet aCachedArea;
+ maRefCache.getAllCachedDataSpans(rSrcDoc, nFileId, aCachedArea);
+
+ // Clear the existing cache, and refill it. Make sure we keep the
+ // existing cache table instances here.
+ maRefCache.clearCacheTables(nFileId);
+ RefCacheFiller aAction(mrDoc.GetSharedStringPool(), maRefCache, nFileId);
+ aCachedArea.executeColumnAction(rSrcDoc, aAction);
+
+ DocShellMap::iterator it = maDocShells.find(nFileId);
+ if (it != maDocShells.end())
+ {
+ it->second.maShell->DoClose();
+ it->second.maShell = xDocShell;
+ it->second.maLastAccess = tools::Time(tools::Time::SYSTEM);
+ }
+ else
+ {
+ SrcShell aSrcDoc;
+ aSrcDoc.maShell = xDocShell;
+ aSrcDoc.maLastAccess = tools::Time(tools::Time::SYSTEM);
+ cacheNewDocShell(nFileId, aSrcDoc);
+ }
+
+ // Update all cells containing names from this source document.
+ refreshAllRefCells(nFileId);
+
+ notifyAllLinkListeners(nFileId, LINK_MODIFIED);
+
+ return true;
+}
+
+void ScExternalRefManager::breakLink(sal_uInt16 nFileId)
+{
+ // Turn all formula cells referencing this external document into static
+ // cells.
+ RefCellMap::iterator itrRefs = maRefCells.find(nFileId);
+ if (itrRefs != maRefCells.end())
+ {
+ // Make a copy because removing the formula cells below will modify
+ // the original container.
+ RefCellSet aSet = itrRefs->second;
+ for_each(aSet.begin(), aSet.end(), ConvertFormulaToStatic(&mrDoc));
+ maRefCells.erase(nFileId);
+ }
+
+ // Remove all named ranges that reference this document.
+
+ // Global named ranges.
+ ScRangeName* pRanges = mrDoc.GetRangeName();
+ if (pRanges)
+ removeRangeNamesBySrcDoc(*pRanges, nFileId);
+
+ // Sheet-local named ranges.
+ for (SCTAB i = 0, n = mrDoc.GetTableCount(); i < n; ++i)
+ {
+ pRanges = mrDoc.GetRangeName(i);
+ if (pRanges)
+ removeRangeNamesBySrcDoc(*pRanges, nFileId);
+ }
+
+ clearCache(nFileId);
+ lcl_removeByFileId(nFileId, maDocShells);
+
+ if (maDocShells.empty())
+ maSrcDocTimer.Stop();
+
+ LinkedDocMap::iterator itr = maLinkedDocs.find(nFileId);
+ if (itr != maLinkedDocs.end())
+ itr->second = false;
+
+ notifyAllLinkListeners(nFileId, LINK_BROKEN);
+}
+
+void ScExternalRefManager::switchSrcFile(sal_uInt16 nFileId, const OUString& rNewFile, const OUString& rNewFilter)
+{
+ maSrcFiles[nFileId].maFileName = rNewFile;
+ maSrcFiles[nFileId].maRelativeName.clear();
+ maSrcFiles[nFileId].maRealFileName.clear();
+ if (maSrcFiles[nFileId].maFilterName != rNewFilter)
+ {
+ // Filter type has changed.
+ maSrcFiles[nFileId].maFilterName = rNewFilter;
+ maSrcFiles[nFileId].maFilterOptions.clear();
+ }
+ refreshSrcDocument(nFileId);
+}
+
+void ScExternalRefManager::setRelativeFileName(sal_uInt16 nFileId, const OUString& rRelUrl)
+{
+ if (nFileId >= maSrcFiles.size())
+ return;
+ maSrcFiles[nFileId].maRelativeName = rRelUrl;
+}
+
+void ScExternalRefManager::setFilterData(sal_uInt16 nFileId, const OUString& rFilterName, const OUString& rOptions)
+{
+ if (nFileId >= maSrcFiles.size())
+ return;
+ maSrcFiles[nFileId].maFilterName = rFilterName;
+ maSrcFiles[nFileId].maFilterOptions = rOptions;
+}
+
+void ScExternalRefManager::clear()
+{
+ for (auto& rEntry : maLinkListeners)
+ {
+ for (auto& it : rEntry.second)
+ {
+ it->notify(0, OH_NO_WE_ARE_GOING_TO_DIE);
+ }
+ }
+
+ for (auto& rEntry : maDocShells)
+ rEntry.second.maShell->DoClose();
+
+ maDocShells.clear();
+ maSrcDocTimer.Stop();
+}
+
+bool ScExternalRefManager::hasExternalData() const
+{
+ return !maSrcFiles.empty();
+}
+
+void ScExternalRefManager::resetSrcFileData(const OUString& rBaseFileUrl)
+{
+ for (auto& rSrcFile : maSrcFiles)
+ {
+ // Re-generate relative file name from the absolute file name.
+ OUString aAbsName = rSrcFile.maRealFileName;
+ if (aAbsName.isEmpty())
+ aAbsName = rSrcFile.maFileName;
+
+ rSrcFile.maRelativeName = URIHelper::simpleNormalizedMakeRelative(
+ rBaseFileUrl, aAbsName);
+ }
+}
+
+void ScExternalRefManager::updateAbsAfterLoad()
+{
+ OUString aOwn( getOwnDocumentName() );
+ for (auto& rSrcFile : maSrcFiles)
+ {
+ // update maFileName to the real file name,
+ // to be called when the original name is no longer needed (after CompileXML)
+
+ rSrcFile.maybeCreateRealFileName( aOwn );
+ OUString aReal = rSrcFile.maRealFileName;
+ if (!aReal.isEmpty())
+ rSrcFile.maFileName = aReal;
+ }
+}
+
+void ScExternalRefManager::removeRefCell(ScFormulaCell* pCell)
+{
+ for_each(maRefCells.begin(), maRefCells.end(), RemoveFormulaCell(pCell));
+}
+
+void ScExternalRefManager::addLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
+{
+ LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
+ if (itr == maLinkListeners.end())
+ {
+ pair<LinkListenerMap::iterator, bool> r = maLinkListeners.emplace(
+ nFileId, LinkListeners());
+ if (!r.second)
+ {
+ OSL_FAIL("insertion of new link listener list failed");
+ return;
+ }
+
+ itr = r.first;
+ }
+
+ LinkListeners& rList = itr->second;
+ rList.insert(pListener);
+}
+
+void ScExternalRefManager::removeLinkListener(sal_uInt16 nFileId, LinkListener* pListener)
+{
+ LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
+ if (itr == maLinkListeners.end())
+ // no listeners for a specified file.
+ return;
+
+ LinkListeners& rList = itr->second;
+ rList.erase(pListener);
+
+ if (rList.empty())
+ // No more listeners for this file. Remove its entry.
+ maLinkListeners.erase(itr);
+}
+
+void ScExternalRefManager::removeLinkListener(LinkListener* pListener)
+{
+ for (auto& rEntry : maLinkListeners)
+ rEntry.second.erase(pListener);
+}
+
+void ScExternalRefManager::notifyAllLinkListeners(sal_uInt16 nFileId, LinkUpdateType eType)
+{
+ LinkListenerMap::iterator itr = maLinkListeners.find(nFileId);
+ if (itr == maLinkListeners.end())
+ // no listeners for a specified file.
+ return;
+
+ LinkListeners& rList = itr->second;
+ for_each(rList.begin(), rList.end(), NotifyLinkListener(nFileId, eType));
+}
+
+void ScExternalRefManager::purgeStaleSrcDocument(sal_Int32 nTimeOut)
+{
+ // To avoid potentially freezing Calc, we close one stale document at a time.
+ DocShellMap::iterator itr = std::find_if(maDocShells.begin(), maDocShells.end(),
+ [nTimeOut](const DocShellMap::value_type& rEntry) {
+ // in 100th of a second.
+ sal_Int32 nSinceLastAccess = (tools::Time( tools::Time::SYSTEM ) - rEntry.second.maLastAccess).GetTime();
+ return nSinceLastAccess >= nTimeOut;
+ });
+ if (itr != maDocShells.end())
+ {
+ // Timed out. Let's close this.
+ itr->second.maShell->DoClose();
+ maDocShells.erase(itr);
+ }
+
+ if (maDocShells.empty())
+ maSrcDocTimer.Stop();
+}
+
+sal_uInt32 ScExternalRefManager::getMappedNumberFormat(sal_uInt16 nFileId, sal_uInt32 nNumFmt, const ScDocument& rSrcDoc)
+{
+ NumFmtMap::iterator itr = maNumFormatMap.find(nFileId);
+ if (itr == maNumFormatMap.end())
+ {
+ // Number formatter map is not initialized for this external document.
+ pair<NumFmtMap::iterator, bool> r = maNumFormatMap.emplace(
+ nFileId, SvNumberFormatterMergeMap());
+
+ if (!r.second)
+ // insertion failed.
+ return nNumFmt;
+
+ itr = r.first;
+ mrDoc.GetFormatTable()->MergeFormatter(*rSrcDoc.GetFormatTable());
+ SvNumberFormatterMergeMap aMap = mrDoc.GetFormatTable()->ConvertMergeTableToMap();
+ itr->second.swap(aMap);
+ }
+ const SvNumberFormatterMergeMap& rMap = itr->second;
+ SvNumberFormatterMergeMap::const_iterator itrNumFmt = rMap.find(nNumFmt);
+ if (itrNumFmt != rMap.end())
+ // mapped value found.
+ return itrNumFmt->second;
+
+ return nNumFmt;
+}
+
+void ScExternalRefManager::transformUnsavedRefToSavedRef( SfxObjectShell* pShell )
+{
+ DocShellMap::iterator itr = maUnsavedDocShells.begin();
+ while( itr != maUnsavedDocShells.end() )
+ {
+ if ( itr->second.maShell.get() == pShell )
+ {
+ // found that the shell is marked as unsaved
+ OUString aFileURL = pShell->GetMedium()->GetURLObject().GetMainURL(INetURLObject::DecodeMechanism::ToIUri);
+ switchSrcFile(itr->first, aFileURL, OUString());
+ EndListening(*pShell);
+ itr = maUnsavedDocShells.erase(itr);
+ }
+ else
+ ++itr;
+ }
+}
+
+void ScExternalRefManager::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const SfxEventHint* pEventHint = dynamic_cast<const SfxEventHint*>(&rHint);
+ if ( !pEventHint )
+ return;
+
+ SfxEventHintId nEventId = pEventHint->GetEventId();
+ switch ( nEventId )
+ {
+ case SfxEventHintId::PrepareCloseDoc:
+ {
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(STR_CLOSE_WITH_UNSAVED_REFS)));
+ xWarn->run();
+ }
+ break;
+ case SfxEventHintId::SaveDocDone:
+ case SfxEventHintId::SaveAsDocDone:
+ {
+ SfxObjectShell* pObjShell = static_cast<const SfxEventHint&>( rHint ).GetObjShell();
+ transformUnsavedRefToSavedRef(pObjShell);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+IMPL_LINK(ScExternalRefManager, TimeOutHdl, Timer*, pTimer, void)
+{
+ if (pTimer == &maSrcDocTimer)
+ purgeStaleSrcDocument(SRCDOC_LIFE_SPAN);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/impex.cxx b/sc/source/ui/docshell/impex.cxx
new file mode 100644
index 000000000..3f80f88ef
--- /dev/null
+++ b/sc/source/ui/docshell/impex.cxx
@@ -0,0 +1,2887 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <i18nlangtag/languagetag.hxx>
+#include <i18nutil/unicode.hxx>
+#include <sot/formats.hxx>
+#include <sfx2/mieclip.hxx>
+#include <com/sun/star/i18n/CalendarFieldIndex.hpp>
+#include <sal/log.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/module.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <global.hxx>
+#include <docsh.hxx>
+#include <undoblk.hxx>
+#include <rangenam.hxx>
+#include <tabvwsh.hxx>
+#include <filter.hxx>
+#include <asciiopt.hxx>
+#include <formulacell.hxx>
+#include <cellform.hxx>
+#include <progress.hxx>
+#include <scitems.hxx>
+#include <editable.hxx>
+#include <compiler.hxx>
+#include <warnbox.hxx>
+#include <clipparam.hxx>
+#include <impex.hxx>
+#include <editutil.hxx>
+#include <patattr.hxx>
+#include <docpool.hxx>
+#include <stringutil.hxx>
+#include <cellvalue.hxx>
+#include <tokenarray.hxx>
+#include <documentimport.hxx>
+#include <refundo.hxx>
+#include <mtvelements.hxx>
+
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <o3tl/safeint.hxx>
+#include <tools/svlibrary.h>
+#include <unotools/configmgr.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <editeng/editobj.hxx>
+#include <svl/numformat.hxx>
+#include <rtl/character.hxx>
+#include <rtl/math.hxx>
+#include <sax/tools/converter.hxx>
+
+#include <memory>
+#include <string_view>
+
+#include <osl/endian.h>
+
+// We don't want to end up with 2GB read in one line just because of malformed
+// multiline fields, so chop it _somewhere_, which is twice supported columns
+// times arbitrary maximum cell content length, 2*1024*64K=128M, and because
+// it's sal_Unicode that's 256MB. If it's 2GB of data without LF we're out of
+// luck anyway.
+constexpr sal_Int32 nArbitraryCellLengthLimit = SAL_MAX_UINT16;
+constexpr sal_Int32 nArbitraryLineLengthLimit = 2 * MAXCOLCOUNT * nArbitraryCellLengthLimit;
+
+namespace
+{
+ const char SYLK_LF[] = "\x1b :";
+
+ bool lcl_IsEndianSwap( const SvStream& rStrm )
+ {
+ #ifdef OSL_BIGENDIAN
+ return rStrm.GetEndian() != SvStreamEndian::BIG;
+ #else
+ return rStrm.GetEndian() != SvStreamEndian::LITTLE;
+ #endif
+ }
+}
+
+namespace {
+
+enum class SylkVersion
+{
+ SCALC3, // Wrote wrongly quoted strings and unescaped semicolons.
+ OOO32, // Correct strings, plus multiline content.
+ OWN, // Place our new versions, if any, before this value.
+ OTHER // Assume that aliens wrote correct strings.
+};
+
+}
+
+// Whole document without Undo
+ScImportExport::ScImportExport( ScDocument& r )
+ : pDocSh( dynamic_cast< ScDocShell* >(r.GetDocumentShell()) ), rDoc( r ),
+ nSizeLimit( 0 ), nMaxImportRow(!utl::ConfigManager::IsFuzzing() ? rDoc.MaxRow() : SCROWS32K),
+ cSep( '\t' ), cStr( '"' ),
+ bFormulas( false ), bIncludeFiltered( true ),
+ bAll( true ), bSingle( true ), bUndo( false ),
+ bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
+ mbApi( true ), mbImportBroadcast(false), mbOverwriting( false )
+{
+ pUndoDoc = nullptr;
+ pExtOptions = nullptr;
+}
+
+// Insert am current cell without range(es)
+ScImportExport::ScImportExport( ScDocument& r, const ScAddress& rPt )
+ : pDocSh( dynamic_cast< ScDocShell* >(r.GetDocumentShell()) ), rDoc( r ),
+ aRange( rPt ),
+ nSizeLimit( 0 ), nMaxImportRow(!utl::ConfigManager::IsFuzzing() ? rDoc.MaxRow() : SCROWS32K),
+ cSep( '\t' ), cStr( '"' ),
+ bFormulas( false ), bIncludeFiltered( true ),
+ bAll( false ), bSingle( true ), bUndo( pDocSh != nullptr ),
+ bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
+ mbApi( true ), mbImportBroadcast(false), mbOverwriting( false )
+{
+ pUndoDoc = nullptr;
+ pExtOptions = nullptr;
+}
+
+// ctor with a range is only used for export
+//! ctor with a string (and bSingle=true) is also used for DdeSetData
+ScImportExport::ScImportExport( ScDocument& r, const ScRange& rRange )
+ : pDocSh( dynamic_cast<ScDocShell* >(r.GetDocumentShell()) ), rDoc( r ),
+ aRange( rRange ),
+ nSizeLimit( 0 ), nMaxImportRow(!utl::ConfigManager::IsFuzzing() ? rDoc.MaxRow() : SCROWS32K),
+ cSep( '\t' ), cStr( '"' ),
+ bFormulas( false ), bIncludeFiltered( true ),
+ bAll( false ), bSingle( false ), bUndo( pDocSh != nullptr ),
+ bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
+ mbApi( true ), mbImportBroadcast(false), mbOverwriting( false )
+{
+ pUndoDoc = nullptr;
+ pExtOptions = nullptr;
+ // Only one sheet (table) supported
+ aRange.aEnd.SetTab( aRange.aStart.Tab() );
+}
+
+// Evaluate input string - either range, cell or the whole document (when error)
+// If a View exists, the TabNo of the view will be used.
+ScImportExport::ScImportExport( ScDocument& r, const OUString& rPos )
+ : pDocSh( dynamic_cast< ScDocShell* >(r.GetDocumentShell()) ), rDoc( r ),
+ nSizeLimit( 0 ), nMaxImportRow(!utl::ConfigManager::IsFuzzing() ? rDoc.MaxRow() : SCROWS32K),
+ cSep( '\t' ), cStr( '"' ),
+ bFormulas( false ), bIncludeFiltered( true ),
+ bAll( false ), bSingle( true ), bUndo( pDocSh != nullptr ),
+ bOverflowRow( false ), bOverflowCol( false ), bOverflowCell( false ),
+ mbApi( true ), mbImportBroadcast(false), mbOverwriting( false )
+{
+ pUndoDoc = nullptr;
+ pExtOptions = nullptr;
+
+ SCTAB nTab = ScDocShell::GetCurTab();
+ aRange.aStart.SetTab( nTab );
+ OUString aPos( rPos );
+ // Named range?
+ ScRangeName* pRange = rDoc.GetRangeName();
+ if (pRange)
+ {
+ const ScRangeData* pData = pRange->findByUpperName(ScGlobal::getCharClass().uppercase(aPos));
+ if (pData)
+ {
+ if( pData->HasType( ScRangeData::Type::RefArea )
+ || pData->HasType( ScRangeData::Type::AbsArea )
+ || pData->HasType( ScRangeData::Type::AbsPos ) )
+ {
+ aPos = pData->GetSymbol();
+ }
+ }
+ }
+ formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
+ // Range?
+ if (aRange.Parse(aPos, rDoc, eConv) & ScRefFlags::VALID)
+ bSingle = false;
+ // Cell?
+ else if (aRange.aStart.Parse(aPos, rDoc, eConv) & ScRefFlags::VALID)
+ aRange.aEnd = aRange.aStart;
+ else
+ bAll = true;
+}
+
+ScImportExport::~ScImportExport() COVERITY_NOEXCEPT_FALSE
+{
+ pUndoDoc.reset();
+ pExtOptions.reset();
+}
+
+void ScImportExport::SetExtOptions( const ScAsciiOptions& rOpt )
+{
+ if ( pExtOptions )
+ *pExtOptions = rOpt;
+ else
+ pExtOptions.reset(new ScAsciiOptions( rOpt ));
+
+ // "normal" Options
+
+ cSep = ScAsciiOptions::GetWeightedFieldSep( rOpt.GetFieldSeps(), false);
+ cStr = rOpt.GetTextSep();
+}
+
+void ScImportExport::SetFilterOptions(const OUString& rFilterOptions)
+{
+ maFilterOptions = rFilterOptions;
+}
+
+bool ScImportExport::IsFormatSupported( SotClipboardFormatId nFormat )
+{
+ return nFormat == SotClipboardFormatId::STRING
+ || nFormat == SotClipboardFormatId::STRING_TSVC
+ || nFormat == SotClipboardFormatId::SYLK
+ || nFormat == SotClipboardFormatId::LINK
+ || nFormat == SotClipboardFormatId::HTML
+ || nFormat == SotClipboardFormatId::HTML_SIMPLE
+ || nFormat == SotClipboardFormatId::DIF;
+}
+
+// Prepare for Undo
+bool ScImportExport::StartPaste()
+{
+ if ( !bAll )
+ {
+ ScEditableTester aTester( rDoc, aRange );
+ if ( !aTester.IsEditable() )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(ScDocShell::GetActiveDialogParent(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(aTester.GetMessageId())));
+ xInfoBox->run();
+ return false;
+ }
+ }
+ if( bUndo && pDocSh && rDoc.IsUndoEnabled())
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
+ rDoc.CopyToDocument(aRange, InsertDeleteFlags::ALL | InsertDeleteFlags::NOCAPTIONS, false, *pUndoDoc);
+ }
+ return true;
+}
+
+// Create Undo/Redo actions, Invalidate/Repaint
+void ScImportExport::EndPaste(bool bAutoRowHeight)
+{
+ bool bHeight = bAutoRowHeight && pDocSh && pDocSh->AdjustRowHeight(
+ aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab() );
+
+ if( pUndoDoc && rDoc.IsUndoEnabled() && pDocSh )
+ {
+ ScDocumentUniquePtr pRedoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pRedoDoc->InitUndo( rDoc, aRange.aStart.Tab(), aRange.aEnd.Tab() );
+ rDoc.CopyToDocument(aRange, InsertDeleteFlags::ALL | InsertDeleteFlags::NOCAPTIONS, false, *pRedoDoc);
+ ScMarkData aDestMark(pRedoDoc->GetSheetLimits());
+ aDestMark.SetMarkArea(aRange);
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoPaste>(pDocSh, aRange, aDestMark, std::move(pUndoDoc), std::move(pRedoDoc), InsertDeleteFlags::ALL, nullptr));
+ }
+ pUndoDoc.reset();
+ if( pDocSh )
+ {
+ if (!bHeight)
+ pDocSh->PostPaint( aRange, PaintPartFlags::Grid );
+ pDocSh->SetDocumentModified();
+ }
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ if ( pViewSh )
+ pViewSh->UpdateInputHandler();
+
+}
+
+bool ScImportExport::ExportData( const OUString& rMimeType,
+ css::uno::Any & rValue )
+{
+ SvMemoryStream aStrm;
+ SotClipboardFormatId fmtId = SotExchange::GetFormatIdFromMimeType(rMimeType);
+ if (fmtId == SotClipboardFormatId::STRING)
+ aStrm.SetStreamCharSet(RTL_TEXTENCODING_UNICODE);
+ // mba: no BaseURL for data exchange
+ if (ExportStream(aStrm, OUString(), fmtId))
+ {
+ if (fmtId == SotClipboardFormatId::STRING)
+ {
+ assert(aStrm.TellEnd() % sizeof(sal_Unicode) == 0);
+ rValue <<= OUString(static_cast<const sal_Unicode*>(aStrm.GetData()),
+ aStrm.TellEnd() / sizeof(sal_Unicode));
+ }
+ else
+ {
+ aStrm.WriteUChar(0);
+ rValue <<= css::uno::Sequence<sal_Int8>(static_cast<sal_Int8 const*>(aStrm.GetData()),
+ aStrm.TellEnd());
+ }
+ return true;
+ }
+ return false;
+}
+
+bool ScImportExport::ImportString( const OUString& rText, SotClipboardFormatId nFmt )
+{
+ switch ( nFmt )
+ {
+ // formats supporting unicode
+ case SotClipboardFormatId::STRING :
+ case SotClipboardFormatId::STRING_TSVC :
+ {
+ ScImportStringStream aStrm( rText);
+ return ImportStream( aStrm, OUString(), nFmt );
+ // ImportStream must handle RTL_TEXTENCODING_UNICODE
+ }
+ default:
+ {
+ rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
+ OString aTmp( rText.getStr(), rText.getLength(), eEnc );
+ SvMemoryStream aStrm( const_cast<char *>(aTmp.getStr()), aTmp.getLength() * sizeof(char), StreamMode::READ );
+ aStrm.SetStreamCharSet( eEnc );
+ SetNoEndianSwap( aStrm ); //! no swapping in memory
+ return ImportStream( aStrm, OUString(), nFmt );
+ }
+ }
+}
+
+bool ScImportExport::ExportString( OUString& rText, SotClipboardFormatId nFmt )
+{
+ if ( nFmt != SotClipboardFormatId::STRING && nFmt != SotClipboardFormatId::STRING_TSVC )
+ {
+ SAL_WARN("sc.ui", "ScImportExport::ExportString: Unicode not supported for other formats than SotClipboardFormatId::STRING[_TSV]");
+ rtl_TextEncoding eEnc = osl_getThreadTextEncoding();
+ OString aTmp;
+ bool bOk = ExportByteString( aTmp, eEnc, nFmt );
+ rText = OStringToOUString( aTmp, eEnc );
+ return bOk;
+ }
+ // nSizeLimit not needed for OUString
+
+ SvMemoryStream aStrm;
+ aStrm.SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
+ SetNoEndianSwap( aStrm ); //! no swapping in memory
+ // mba: no BaseURL for data exc
+ if( ExportStream( aStrm, OUString(), nFmt ) )
+ {
+ aStrm.WriteUInt16( 0 );
+ rText = OUString( static_cast<const sal_Unicode*>(aStrm.GetData()) );
+ return true;
+ }
+ rText.clear();
+ return false;
+
+ // ExportStream must handle RTL_TEXTENCODING_UNICODE
+}
+
+bool ScImportExport::ExportByteString( OString& rText, rtl_TextEncoding eEnc, SotClipboardFormatId nFmt )
+{
+ OSL_ENSURE( eEnc != RTL_TEXTENCODING_UNICODE, "ScImportExport::ExportByteString: Unicode not supported" );
+ if ( eEnc == RTL_TEXTENCODING_UNICODE )
+ eEnc = osl_getThreadTextEncoding();
+
+ if (!nSizeLimit)
+ nSizeLimit = SAL_MAX_UINT16;
+
+ SvMemoryStream aStrm;
+ aStrm.SetStreamCharSet( eEnc );
+ SetNoEndianSwap( aStrm ); //! no swapping in memory
+ // mba: no BaseURL for data exchange
+ if( ExportStream( aStrm, OUString(), nFmt ) )
+ {
+ aStrm.WriteChar( 0 );
+ if( aStrm.TellEnd() <= nSizeLimit )
+ {
+ rText = static_cast<const char*>(aStrm.GetData());
+ return true;
+ }
+ }
+ rText.clear();
+ return false;
+}
+
+bool ScImportExport::ImportStream( SvStream& rStrm, const OUString& rBaseURL, SotClipboardFormatId nFmt )
+{
+ if( nFmt == SotClipboardFormatId::STRING || nFmt == SotClipboardFormatId::STRING_TSVC )
+ {
+ if( ExtText2Doc( rStrm ) ) // evaluate pExtOptions
+ return true;
+ }
+ if( nFmt == SotClipboardFormatId::SYLK )
+ {
+ if( Sylk2Doc( rStrm ) )
+ return true;
+ }
+ if( nFmt == SotClipboardFormatId::DIF )
+ {
+ if( Dif2Doc( rStrm ) )
+ return true;
+ }
+ if( nFmt == SotClipboardFormatId::RTF || nFmt == SotClipboardFormatId::RICHTEXT )
+ {
+ if( RTF2Doc( rStrm, rBaseURL ) )
+ return true;
+ }
+ if( nFmt == SotClipboardFormatId::LINK )
+ return true; // Link-Import?
+ if ( nFmt == SotClipboardFormatId::HTML )
+ {
+ if( HTML2Doc( rStrm, rBaseURL ) )
+ return true;
+ }
+ if ( nFmt == SotClipboardFormatId::HTML_SIMPLE )
+ {
+ MSE40HTMLClipFormatObj aMSE40ClpObj; // needed to skip the header data
+ SvStream* pHTML = aMSE40ClpObj.IsValid( rStrm );
+ if ( pHTML && HTML2Doc( *pHTML, rBaseURL ) )
+ return true;
+ }
+
+ return false;
+}
+
+bool ScImportExport::ExportStream( SvStream& rStrm, const OUString& rBaseURL, SotClipboardFormatId nFmt )
+{
+ if( nFmt == SotClipboardFormatId::STRING || nFmt == SotClipboardFormatId::STRING_TSVC )
+ {
+ if( Doc2Text( rStrm ) )
+ return true;
+ }
+ if( nFmt == SotClipboardFormatId::SYLK )
+ {
+ if( Doc2Sylk( rStrm ) )
+ return true;
+ }
+ if( nFmt == SotClipboardFormatId::DIF )
+ {
+ if( Doc2Dif( rStrm ) )
+ return true;
+ }
+ if( nFmt == SotClipboardFormatId::LINK && !bAll )
+ {
+ OUString aDocName;
+ if ( rDoc.IsClipboard() )
+ aDocName = ScGlobal::GetClipDocName();
+ else
+ {
+ SfxObjectShell* pShell = rDoc.GetDocumentShell();
+ if (pShell)
+ aDocName = pShell->GetTitle( SFX_TITLE_FULLNAME );
+ }
+
+ OSL_ENSURE( !aDocName.isEmpty(), "ClipBoard document has no name! :-/" );
+ if( !aDocName.isEmpty() )
+ {
+ // Always use Calc A1 syntax for paste link.
+ OUString aRefName;
+ ScRefFlags nFlags = ScRefFlags::VALID | ScRefFlags::TAB_3D;
+ if( bSingle )
+ aRefName = aRange.aStart.Format(nFlags, &rDoc, formula::FormulaGrammar::CONV_OOO);
+ else
+ {
+ if( aRange.aStart.Tab() != aRange.aEnd.Tab() )
+ nFlags |= ScRefFlags::TAB2_3D;
+ aRefName = aRange.Format(rDoc, nFlags, formula::FormulaGrammar::CONV_OOO);
+ }
+ OUString aAppName = Application::GetAppName();
+
+ // extra bits are used to tell the client to prefer external
+ // reference link.
+
+ WriteUnicodeOrByteString( rStrm, aAppName, true );
+ WriteUnicodeOrByteString( rStrm, aDocName, true );
+ WriteUnicodeOrByteString( rStrm, aRefName, true );
+ WriteUnicodeOrByteString( rStrm, "calc:extref", true );
+ if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
+ rStrm.WriteUInt16( 0 );
+ else
+ rStrm.WriteChar( 0 );
+ return rStrm.GetError() == ERRCODE_NONE;
+ }
+ }
+ if( nFmt == SotClipboardFormatId::HTML )
+ {
+ if( Doc2HTML( rStrm, rBaseURL ) )
+ return true;
+ }
+ if( nFmt == SotClipboardFormatId::RTF || nFmt == SotClipboardFormatId::RICHTEXT )
+ {
+ if( Doc2RTF( rStrm ) )
+ return true;
+ }
+
+ return false;
+}
+
+void ScImportExport::WriteUnicodeOrByteString( SvStream& rStrm, const OUString& rString, bool bZero )
+{
+ rtl_TextEncoding eEnc = rStrm.GetStreamCharSet();
+ if ( eEnc == RTL_TEXTENCODING_UNICODE )
+ {
+ if ( !lcl_IsEndianSwap( rStrm ) )
+ rStrm.WriteBytes(rString.getStr(), rString.getLength() * sizeof(sal_Unicode));
+ else
+ {
+ const sal_Unicode* p = rString.getStr();
+ const sal_Unicode* const pStop = p + rString.getLength();
+ while ( p < pStop )
+ {
+ rStrm.WriteUInt16( *p );
+ }
+ }
+ if ( bZero )
+ rStrm.WriteUInt16( 0 );
+ }
+ else
+ {
+ OString aByteStr(OUStringToOString(rString, eEnc));
+ rStrm.WriteOString( aByteStr );
+ if ( bZero )
+ rStrm.WriteChar( 0 );
+ }
+}
+
+// This function could be replaced by endlub()
+void ScImportExport::WriteUnicodeOrByteEndl( SvStream& rStrm )
+{
+ if ( rStrm.GetStreamCharSet() == RTL_TEXTENCODING_UNICODE )
+ { // same as endl() but unicode
+ switch ( rStrm.GetLineDelimiter() )
+ {
+ case LINEEND_CR :
+ rStrm.WriteUInt16( '\r' );
+ break;
+ case LINEEND_LF :
+ rStrm.WriteUInt16( '\n' );
+ break;
+ default:
+ rStrm.WriteUInt16( '\r' ).WriteUInt16( '\n' );
+ }
+ }
+ else
+ endl( rStrm );
+}
+
+sal_Int32 ScImportExport::CountVisualWidth(const OUString& rStr, sal_Int32& nIdx, sal_Int32 nMaxWidth)
+{
+ sal_Int32 nWidth = 0;
+ while(nIdx < rStr.getLength() && nWidth < nMaxWidth)
+ {
+ sal_uInt32 nCode = rStr.iterateCodePoints(&nIdx);
+
+ if (unicode::isCJKIVSCharacter(nCode) || (nCode >= 0x3000 && nCode <= 0x303F))
+ nWidth += 2;
+ else if (!unicode::isIVSSelector(nCode))
+ nWidth += 1;
+ }
+
+ if (nIdx < rStr.getLength())
+ {
+ sal_Int32 nTmpIdx = nIdx;
+ sal_uInt32 nCode = rStr.iterateCodePoints(&nTmpIdx);
+
+ if (unicode::isIVSSelector(nCode))
+ nIdx = nTmpIdx;
+ }
+ return nWidth;
+}
+
+sal_Int32 ScImportExport::CountVisualWidth(const OUString& rStr)
+{
+ sal_Int32 nIdx = 0;
+ return CountVisualWidth(rStr, nIdx, SAL_MAX_INT32);
+}
+
+void ScImportExport::SetNoEndianSwap( SvStream& rStrm )
+{
+#ifdef OSL_BIGENDIAN
+ rStrm.SetEndian( SvStreamEndian::BIG );
+#else
+ rStrm.SetEndian( SvStreamEndian::LITTLE );
+#endif
+}
+
+static inline bool lcl_isFieldEnd( sal_Unicode c, const sal_Unicode* pSeps )
+{
+ return !c || ScGlobal::UnicodeStrChr( pSeps, c);
+}
+
+namespace {
+
+enum QuoteType
+{
+ FIELDSTART_QUOTE,
+ FIRST_QUOTE,
+ SECOND_QUOTE,
+ FIELDEND_QUOTE,
+ DONTKNOW_QUOTE
+};
+
+}
+
+/** Determine if *p is a quote that ends a quoted field.
+
+ Precondition: we are parsing a quoted field already and *p is a quote.
+
+ @return
+ FIELDEND_QUOTE if end of field quote
+ DONTKNOW_QUOTE anything else
+ */
+static QuoteType lcl_isFieldEndQuote( const sal_Unicode* p, const sal_Unicode* pSeps, sal_Unicode& rcDetectSep )
+{
+ // Due to broken CSV generators that don't double embedded quotes check if
+ // a field separator immediately or with trailing spaces follows the quote,
+ // only then end the field, or at end of string.
+ constexpr sal_Unicode cBlank = ' ';
+ if (p[1] == cBlank && ScGlobal::UnicodeStrChr( pSeps, cBlank))
+ return FIELDEND_QUOTE;
+ // Detect a possible blank separator if it's not already in the list (which
+ // was checked right above for p[1]==cBlank).
+ const bool bBlankSep = (p[1] == cBlank && !rcDetectSep && p[2] && p[2] != cBlank);
+ while (p[1] == cBlank)
+ ++p;
+ if (lcl_isFieldEnd( p[1], pSeps))
+ return FIELDEND_QUOTE;
+ // Extended separator detection after a closing quote (with or without
+ // blanks). Note that nQuotes is incremented *after* the call so is not yet
+ // even here, and that with separator detection we reach here only if
+ // lcl_isEscapedOrFieldEndQuote() did not already detect FIRST_QUOTE or
+ // SECOND_QUOTE for an escaped embedded quote, thus nQuotes does not have
+ // to be checked.
+ if (!rcDetectSep)
+ {
+ constexpr sal_Unicode vSep[] = { ',', '\t', ';' };
+ for (const sal_Unicode c : vSep)
+ {
+ if (p[1] == c)
+ {
+ rcDetectSep = c;
+ return FIELDEND_QUOTE;
+ }
+ }
+ }
+ // Blank separator is least significant, after others.
+ if (bBlankSep)
+ {
+ rcDetectSep = cBlank;
+ return FIELDEND_QUOTE;
+ }
+ return DONTKNOW_QUOTE;
+}
+
+/** Determine if *p is a quote that is escaped by being doubled or ends a
+ quoted field.
+
+ Precondition: *p is a quote.
+
+ @param nQuotes
+ Quote characters encountered so far.
+ Odd (after opening quote) means either no embedded quotes or only quote
+ pairs so far.
+ Even means either not in a quoted field or already one quote
+ encountered, the first of a pair.
+
+ @return
+ FIELDSTART_QUOTE if first quote in a field, either starting content or
+ embedded so caller should check beforehand.
+ FIRST_QUOTE if first of a doubled quote
+ SECOND_QUOTE if second of a doubled quote
+ FIELDEND_QUOTE if end of field quote
+ DONTKNOW_QUOTE if an unescaped quote we don't consider as end of field,
+ do not increment nQuotes in caller then!
+ */
+static QuoteType lcl_isEscapedOrFieldEndQuote( sal_Int32 nQuotes, const sal_Unicode* p,
+ const sal_Unicode* pSeps, sal_Unicode cStr, sal_Unicode& rcDetectSep )
+{
+ if ((nQuotes & 1) == 0)
+ {
+ if (p[-1] == cStr)
+ return SECOND_QUOTE;
+ else
+ {
+ SAL_WARN( "sc", "lcl_isEscapedOrFieldEndQuote: really want a FIELDSTART_QUOTE?");
+ return FIELDSTART_QUOTE;
+ }
+ }
+ if (p[1] == cStr)
+ return FIRST_QUOTE;
+ return lcl_isFieldEndQuote( p, pSeps, rcDetectSep);
+}
+
+/** Append characters of [p1,p2) to rField.
+
+ @returns TRUE if ok; FALSE if data overflow, truncated
+ */
+static bool lcl_appendLineData( OUString& rField, const sal_Unicode* p1, const sal_Unicode* p2 )
+{
+ if (rField.getLength() + (p2 - p1) <= nArbitraryCellLengthLimit)
+ {
+ rField += std::u16string_view( p1, p2 - p1 );
+ return true;
+ }
+ else
+ {
+ SAL_WARN( "sc", "lcl_appendLineData: data overflow");
+ rField += std::u16string_view( p1, nArbitraryCellLengthLimit - rField.getLength() );
+ return false;
+ }
+}
+
+namespace {
+
+enum class DoubledQuoteMode
+{
+ KEEP_ALL, // both are taken, additionally start and end quote are included in string
+ ESCAPE, // escaped quote, one is taken, one ignored
+};
+
+}
+
+/** Scan for a quoted string.
+
+ Precondition: initial current position *p is a cStr quote.
+
+ For DoubledQuoteMode::ESCAPE, if after the closing quote there is a field
+ end (with or without trailing blanks and as determined by
+ lcl_isFieldEndQuote()), then the content is appended to rField with quotes
+ processed and removed. Else if no field end after the quoted string was
+ detected, nothing is appended and processing continues and is repeated
+ until the next quote. If no closing quote at a field end was found at all,
+ nothing is appended and the initial position is returned and caller has to
+ decide, usually just taking all as literal data.
+
+ For DoubledQuoteMode::KEEP_ALL, the string up to and including the closing
+ quote is appended to rField and the next position returned, regardless
+ whether there is a field separator following or not.
+
+ */
+static const sal_Unicode* lcl_ScanString( const sal_Unicode* p, OUString& rField,
+ const sal_Unicode* pSeps, sal_Unicode cStr, DoubledQuoteMode eMode, bool& rbOverflowCell )
+{
+ OUString aString;
+ bool bClosingQuote = (eMode == DoubledQuoteMode::KEEP_ALL);
+ const sal_Unicode* const pStart = p;
+ if (eMode != DoubledQuoteMode::KEEP_ALL)
+ p++; //! jump over opening quote
+ bool bCont;
+ do
+ {
+ bCont = false;
+ const sal_Unicode* p0 = p;
+ for( ;; )
+ {
+ if (!*p)
+ {
+ // Encountering end of data after an opening quote is not a
+ // quoted string, ReadCsvLine() concatenated lines with '\n'
+ // for a properly quoted embedded linefeed.
+ if (eMode == DoubledQuoteMode::KEEP_ALL)
+ // Caller would append that data anyway, so we can do it
+ // already here.
+ break;
+
+ return pStart;
+ }
+
+ if( *p == cStr )
+ {
+ if ( *++p != cStr )
+ {
+ // break or continue for loop
+ if (eMode == DoubledQuoteMode::ESCAPE)
+ {
+ sal_Unicode cDetectSep = 0xffff; // No separator detection here.
+ if (lcl_isFieldEndQuote( p-1, pSeps, cDetectSep) == FIELDEND_QUOTE)
+ {
+ bClosingQuote = true;
+ break;
+ }
+ else
+ continue;
+ }
+ else
+ break;
+ }
+ // doubled quote char
+ switch ( eMode )
+ {
+ case DoubledQuoteMode::KEEP_ALL :
+ p++; // both for us (not breaking for-loop)
+ break;
+ case DoubledQuoteMode::ESCAPE :
+ p++; // one for us (breaking for-loop)
+ bCont = true; // and more
+ break;
+ }
+ if ( eMode == DoubledQuoteMode::ESCAPE )
+ break;
+ }
+ else
+ p++;
+ }
+ if ( p0 < p )
+ {
+ if (!lcl_appendLineData( aString, p0, ((eMode != DoubledQuoteMode::KEEP_ALL && (*p || *(p-1) == cStr)) ? p-1 : p)))
+ rbOverflowCell = true;
+ }
+ } while ( bCont );
+
+ if (!bClosingQuote)
+ return pStart;
+
+ if (!aString.isEmpty())
+ rField += aString;
+
+ return p;
+}
+
+static void lcl_UnescapeSylk( OUString & rString, SylkVersion eVersion )
+{
+ // Older versions didn't escape the semicolon.
+ // Older versions quoted the string and doubled embedded quotes, but not
+ // the semicolons, which was plain wrong.
+ if (eVersion >= SylkVersion::OOO32)
+ rString = rString.replaceAll(";;", ";");
+ else
+ rString = rString.replaceAll("\"\"", "\"");
+
+ rString = rString.replaceAll(SYLK_LF, "\n");
+}
+
+static const sal_Unicode* lcl_ScanSylkString( const sal_Unicode* p,
+ OUString& rString, SylkVersion eVersion )
+{
+ const sal_Unicode* pStartQuote = p;
+ const sal_Unicode* pEndQuote = nullptr;
+ while( *(++p) )
+ {
+ if( *p == '"' )
+ {
+ pEndQuote = p;
+ if (eVersion >= SylkVersion::OOO32)
+ {
+ if (*(p+1) == ';')
+ {
+ if (*(p+2) == ';')
+ {
+ p += 2; // escaped ';'
+ pEndQuote = nullptr;
+ }
+ else
+ break; // end field
+ }
+ }
+ else
+ {
+ if (*(p+1) == '"')
+ {
+ ++p; // escaped '"'
+ pEndQuote = nullptr;
+ }
+ else if (*(p+1) == ';')
+ break; // end field
+ }
+ }
+ }
+ if (!pEndQuote)
+ pEndQuote = p; // Take all data as string.
+ rString += std::u16string_view(pStartQuote + 1, pEndQuote - pStartQuote - 1 );
+ lcl_UnescapeSylk( rString, eVersion);
+ return p;
+}
+
+static const sal_Unicode* lcl_ScanSylkFormula( const sal_Unicode* p,
+ OUString& rString, SylkVersion eVersion )
+{
+ const sal_Unicode* pStart = p;
+ if (eVersion >= SylkVersion::OOO32)
+ {
+ while (*p)
+ {
+ if (*p == ';')
+ {
+ if (*(p+1) == ';')
+ ++p; // escaped ';'
+ else
+ break; // end field
+ }
+ ++p;
+ }
+ rString += std::u16string_view( pStart, p - pStart);
+ lcl_UnescapeSylk( rString, eVersion);
+ }
+ else
+ {
+ // Nasty. If in old versions the formula contained a semicolon, it was
+ // quoted and embedded quotes were doubled, but semicolons were not. If
+ // there was no semicolon, it could still contain quotes and doubled
+ // embedded quotes if it was something like ="a""b", which was saved as
+ // E"a""b" as is and has to be preserved, even if older versions
+ // couldn't even load it correctly. However, theoretically another
+ // field might follow and thus the line contain a semicolon again, such
+ // as ...;E"a""b";...
+ bool bQuoted = false;
+ if (*p == '"')
+ {
+ // May be a quoted expression or just a string constant expression
+ // with quotes.
+ while (*(++p))
+ {
+ if (*p == '"')
+ {
+ if (*(p+1) == '"')
+ ++p; // escaped '"'
+ else
+ break; // closing '"', had no ';' yet
+ }
+ else if (*p == ';')
+ {
+ bQuoted = true; // ';' within quoted expression
+ break;
+ }
+ }
+ p = pStart;
+ }
+ if (bQuoted)
+ p = lcl_ScanSylkString( p, rString, eVersion);
+ else
+ {
+ while (*p && *p != ';')
+ ++p;
+ rString += std::u16string_view( pStart, p - pStart);
+ }
+ }
+ return p;
+}
+
+static void lcl_DoubleEscapeChar( OUString& rString, sal_Unicode cStr )
+{
+ sal_Int32 n = 0;
+ while( ( n = rString.indexOf( cStr, n ) ) != -1 )
+ {
+ rString = rString.replaceAt( n, 0, rtl::OUStringChar(cStr) );
+ n += 2;
+ }
+}
+
+static void lcl_WriteString( SvStream& rStrm, OUString& rString, sal_Unicode cQuote, sal_Unicode cEsc )
+{
+ if (cEsc)
+ lcl_DoubleEscapeChar( rString, cEsc );
+
+ if (cQuote)
+ {
+ rString = OUStringChar(cQuote) + rString + OUStringChar(cQuote);
+ }
+
+ ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
+}
+
+static void lcl_WriteSimpleString( SvStream& rStrm, const OUString& rString )
+{
+ ScImportExport::WriteUnicodeOrByteString( rStrm, rString );
+}
+
+bool ScImportExport::Text2Doc( SvStream& rStrm )
+{
+ bool bOk = true;
+
+ sal_Unicode pSeps[2];
+ pSeps[0] = cSep;
+ pSeps[1] = 0;
+
+ ScSetStringParam aSetStringParam;
+ aSetStringParam.mbCheckLinkFormula = true;
+
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ sal_uInt64 nOldPos = rStrm.Tell();
+ rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
+ bool bData = !bSingle;
+ if( !bSingle)
+ bOk = StartPaste();
+
+ while( bOk )
+ {
+ OUString aLine;
+ OUString aCell;
+ SCROW nRow = nStartRow;
+ rStrm.Seek( nOldPos );
+ for( ;; )
+ {
+ rStrm.ReadUniOrByteStringLine( aLine, rStrm.GetStreamCharSet(), nArbitraryLineLengthLimit );
+ // tdf#125440 When inserting tab separated string, consider quotes as field markers
+ DoubledQuoteMode mode = aLine.indexOf("\t") >= 0 ? DoubledQuoteMode::ESCAPE : DoubledQuoteMode::KEEP_ALL;
+ if( rStrm.eof() )
+ break;
+ SCCOL nCol = nStartCol;
+ const sal_Unicode* p = aLine.getStr();
+ while( *p )
+ {
+ aCell.clear();
+ const sal_Unicode* q = p;
+ if (*p == cStr)
+ {
+ // Look for a pairing quote.
+ q = p = lcl_ScanString( p, aCell, pSeps, cStr, mode, bOverflowCell );
+ }
+ // All until next separator.
+ while (*p && *p != cSep)
+ ++p;
+ if (!lcl_appendLineData( aCell, q, p))
+ bOverflowCell = true; // display warning on import
+ if (*p)
+ ++p;
+ if (rDoc.ValidCol(nCol) && rDoc.ValidRow(nRow) )
+ {
+ if( bSingle )
+ {
+ if (nCol>nEndCol) nEndCol = nCol;
+ if (nRow>nEndRow) nEndRow = nRow;
+ }
+ if( bData && nCol <= nEndCol && nRow <= nEndRow )
+ rDoc.SetString( nCol, nRow, aRange.aStart.Tab(), aCell, &aSetStringParam );
+ }
+ else // too many columns/rows
+ {
+ if (!rDoc.ValidRow(nRow))
+ bOverflowRow = true; // display warning on import
+ if (!rDoc.ValidCol(nCol))
+ bOverflowCol = true; // display warning on import
+ }
+ ++nCol;
+ }
+ ++nRow;
+ }
+
+ if( !bData )
+ {
+ aRange.aEnd.SetCol( nEndCol );
+ aRange.aEnd.SetRow( nEndRow );
+ bOk = StartPaste();
+ bData = true;
+ }
+ else
+ break;
+ }
+
+ EndPaste();
+ if (bOk && mbImportBroadcast)
+ {
+ rDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
+ pDocSh->PostDataChanged();
+ }
+
+ return bOk;
+}
+
+// Extended Ascii-Import
+
+static bool lcl_PutString(
+ ScDocumentImport& rDocImport, bool bUseDocImport,
+ SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rStr, sal_uInt8 nColFormat,
+ SvNumberFormatter* pFormatter, bool bDetectNumFormat, bool bEvaluateFormulas, bool bSkipEmptyCells,
+ const ::utl::TransliterationWrapper& rTransliteration, CalendarWrapper& rCalendar,
+ const ::utl::TransliterationWrapper* pSecondTransliteration, CalendarWrapper* pSecondCalendar )
+{
+ ScDocument& rDoc = rDocImport.getDoc();
+ bool bMultiLine = false;
+ if ( nColFormat == SC_COL_SKIP || !rDoc.ValidCol(nCol) || !rDoc.ValidRow(nRow) )
+ return bMultiLine;
+ if ( rStr.isEmpty() )
+ {
+ if ( !bSkipEmptyCells )
+ { // delete destination cell
+ if ( bUseDocImport )
+ rDocImport.setAutoInput(ScAddress(nCol, nRow, nTab), rStr );
+ else
+ rDoc.SetString( nCol, nRow, nTab, rStr );
+ }
+ return false;
+ }
+
+ const bool bForceFormulaText = (!bEvaluateFormulas && rStr[0] == '=');
+ if (nColFormat == SC_COL_TEXT || bForceFormulaText)
+ {
+ if ( bUseDocImport )
+ {
+ double fDummy;
+ sal_uInt32 nIndex = 0;
+ if (bForceFormulaText || rDoc.GetFormatTable()->IsNumberFormat(rStr, nIndex, fDummy))
+ {
+ // Set the format of this cell to Text.
+ // This is only necessary for ScDocumentImport,
+ // ScDocument::SetTextCell() forces it by ScSetStringParam.
+ sal_uInt32 nFormat = rDoc.GetFormatTable()->GetStandardFormat(SvNumFormatType::TEXT);
+ ScPatternAttr aNewAttrs(rDoc.GetPool());
+ SfxItemSet& rSet = aNewAttrs.GetItemSet();
+ rSet.Put( SfxUInt32Item(ATTR_VALUE_FORMAT, nFormat) );
+ rDoc.ApplyPattern(nCol, nRow, nTab, aNewAttrs);
+ }
+ if (ScStringUtil::isMultiline(rStr))
+ {
+ ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
+ rEngine.SetTextCurrentDefaults(rStr);
+ rDocImport.setEditCell(ScAddress(nCol, nRow, nTab), rEngine.CreateTextObject());
+ return true;
+ }
+ else
+ {
+ rDocImport.setStringCell(ScAddress(nCol, nRow, nTab), rStr);
+ return false;
+ }
+ }
+ else
+ {
+ rDoc.SetTextCell(ScAddress(nCol, nRow, nTab), rStr);
+ return bMultiLine;
+ }
+ }
+
+ if ( nColFormat == SC_COL_ENGLISH )
+ {
+ //! SetString with Extra-Flag ???
+
+ SvNumberFormatter* pDocFormatter = rDoc.GetFormatTable();
+ sal_uInt32 nEnglish = pDocFormatter->GetStandardIndex(LANGUAGE_ENGLISH_US);
+ double fVal;
+ if ( pDocFormatter->IsNumberFormat( rStr, nEnglish, fVal ) )
+ {
+ // Numberformat will not be set to English
+ if ( bUseDocImport )
+ rDocImport.setNumericCell( ScAddress( nCol, nRow, nTab ), fVal );
+ else
+ rDoc.SetValue( nCol, nRow, nTab, fVal );
+ return bMultiLine;
+ }
+ // else, continue with SetString
+ }
+ else if ( nColFormat != SC_COL_STANDARD ) // Datumformats
+ {
+ const sal_uInt16 nMaxNumberParts = 7; // Y-M-D h:m:s.t
+ const sal_Int32 nLen = rStr.getLength();
+ sal_Int32 nStart[nMaxNumberParts];
+ sal_Int32 nEnd[nMaxNumberParts];
+
+ bool bIso;
+ sal_uInt16 nDP, nMP, nYP;
+ switch ( nColFormat )
+ {
+ case SC_COL_YMD: nDP = 2; nMP = 1; nYP = 0; bIso = true; break;
+ case SC_COL_MDY: nDP = 1; nMP = 0; nYP = 2; bIso = false; break;
+ case SC_COL_DMY:
+ default: nDP = 0; nMP = 1; nYP = 2; bIso = false; break;
+ }
+
+ sal_uInt16 nFound = 0;
+ bool bInNum = false;
+ for (sal_Int32 nPos = 0; nPos < nLen && (bInNum || nFound < nMaxNumberParts); ++nPos)
+ {
+ bool bLetter = false;
+ if (rtl::isAsciiDigit(rStr[nPos]) ||
+ (((!bInNum && nFound==nMP) || (bInNum && nFound==nMP+1))
+ && (bLetter = ScGlobal::getCharClass().isLetterNumeric( rStr, nPos))))
+ {
+ if (!bInNum)
+ {
+ bInNum = true;
+ nStart[nFound] = nPos;
+ ++nFound;
+ }
+ nEnd[nFound-1] = nPos;
+ if (bIso && (bLetter || (2 <= nFound && nFound <= 6 && nPos > nStart[nFound-1] + 1)))
+ // Each M,D,h,m,s at most 2 digits.
+ bIso = false;
+ }
+ else
+ {
+ bInNum = false;
+ if (bIso)
+ {
+ // ([+-])YYYY-MM-DD([T ]hh:mm(:ss(.fff)))(([+-])TZ)
+ // XXX NOTE: timezone is accepted here, but number
+ // formatter parser will not, so the end result will be
+ // type Text to preserve timezone information.
+ switch (rStr[nPos])
+ {
+ case '+':
+ if (nFound >= 5 && nPos == nEnd[nFound-1] + 1)
+ // Accept timezone offset.
+ ;
+ else if (nPos > 0)
+ // Accept one leading sign.
+ bIso = false;
+ break;
+ case '-':
+ if (nFound >= 5 && nPos == nEnd[nFound-1] + 1)
+ // Accept timezone offset.
+ ;
+ else if (nFound == 0 && nPos > 0)
+ // Accept one leading sign.
+ bIso = false;
+ else if (nFound < 1 || 2 < nFound || nPos != nEnd[nFound-1] + 1)
+ // Not immediately after 1 or 1-2
+ bIso = false;
+ break;
+ case 'T':
+ case ' ':
+ if (nFound != 3 || nPos != nEnd[nFound-1] + 1)
+ // Not immediately after 1-2-3
+ bIso = false;
+ break;
+ case ':':
+ if (nFound < 4 || 5 < nFound || nPos != nEnd[nFound-1] + 1)
+ // Not at 1-2-3T4:5:
+ bIso = false;
+ break;
+ case '.':
+ case ',':
+ if (nFound != 6 || nPos != nEnd[nFound-1] + 1)
+ // Not at 1-2-3T4:5:6.
+ bIso = false;
+ break;
+ case 'Z':
+ if (nFound >= 5 && nPos == nEnd[nFound-1] + 1)
+ // Accept Zero timezone.
+ ;
+ else
+ bIso = false;
+ break;
+ default:
+ bIso = false;
+ }
+ }
+ }
+ }
+
+ if (nFound < 3)
+ bIso = false;
+
+ if (bIso)
+ {
+ // Leave conversion and detection of various possible number
+ // formats to the number formatter. ISO is recognized in any locale
+ // so we can directly use the document's formatter.
+ sal_uInt32 nFormat = 0;
+ double fVal = 0.0;
+ SvNumberFormatter* pDocFormatter = rDoc.GetFormatTable();
+ if (pDocFormatter->IsNumberFormat( rStr, nFormat, fVal))
+ {
+ if (pDocFormatter->GetType(nFormat) & SvNumFormatType::DATE)
+ {
+ ScAddress aPos(nCol,nRow,nTab);
+ if (bUseDocImport)
+ rDocImport.setNumericCell(aPos, fVal);
+ else
+ rDoc.SetValue(aPos, fVal);
+ rDoc.SetNumberFormat(aPos, nFormat);
+
+ return bMultiLine; // success
+ }
+ }
+ // If we reach here it is type Text (e.g. timezone or trailing
+ // characters). Handled below.
+ }
+
+ if ( nFound == 1 )
+ {
+ // try to break one number (without separators) into date fields
+
+ sal_Int32 nDateStart = nStart[0];
+ sal_Int32 nDateLen = nEnd[0] + 1 - nDateStart;
+
+ if ( nDateLen >= 5 && nDateLen <= 8 &&
+ ScGlobal::getCharClass().isNumeric( rStr.copy( nDateStart, nDateLen ) ) )
+ {
+ // 6 digits: 2 each for day, month, year
+ // 8 digits: 4 for year, 2 each for day and month
+ // 5 or 7 digits: first field is shortened by 1
+
+ bool bLongYear = ( nDateLen >= 7 );
+ bool bShortFirst = ( nDateLen == 5 || nDateLen == 7 );
+
+ sal_uInt16 nFieldStart = nDateStart;
+ for (sal_uInt16 nPos=0; nPos<3; nPos++)
+ {
+ sal_uInt16 nFieldEnd = nFieldStart + 1; // default: 2 digits
+ if ( bLongYear && nPos == nYP )
+ nFieldEnd += 2; // 2 extra digits for long year
+ if ( bShortFirst && nPos == 0 )
+ --nFieldEnd; // first field shortened?
+
+ nStart[nPos] = nFieldStart;
+ nEnd[nPos] = nFieldEnd;
+ nFieldStart = nFieldEnd + 1;
+ }
+ nFound = 3;
+ }
+ }
+
+ if (!bIso && nFound >= 3)
+ {
+ using namespace ::com::sun::star;
+ bool bSecondCal = false;
+ sal_uInt16 nDay = static_cast<sal_uInt16>(o3tl::toInt32(rStr.subView( nStart[nDP], nEnd[nDP]+1-nStart[nDP] )));
+ sal_uInt16 nYear = static_cast<sal_uInt16>(o3tl::toInt32(rStr.subView( nStart[nYP], nEnd[nYP]+1-nStart[nYP] )));
+ OUString aMStr = rStr.copy( nStart[nMP], nEnd[nMP]+1-nStart[nMP] );
+ sal_Int16 nMonth = static_cast<sal_Int16>(aMStr.toInt32());
+ if (!nMonth)
+ {
+ static constexpr OUStringLiteral aSepShortened = u"SEP";
+ uno::Sequence< i18n::CalendarItem2 > xMonths;
+ sal_Int32 i, nMonthCount;
+ // first test all month names from local international
+ xMonths = rCalendar.getMonths();
+ nMonthCount = xMonths.getLength();
+ for (i=0; i<nMonthCount && !nMonth; i++)
+ {
+ if ( rTransliteration.isEqual( aMStr, xMonths[i].FullName ) ||
+ rTransliteration.isEqual( aMStr, xMonths[i].AbbrevName ) )
+ nMonth = sal::static_int_cast<sal_Int16>( i+1 );
+ else if ( i == 8 && rTransliteration.isEqual( "SEPT",
+ xMonths[i].AbbrevName ) &&
+ rTransliteration.isEqual( aMStr, aSepShortened ) )
+ { // correct English abbreviation is SEPT,
+ // but data mostly contains SEP only
+ nMonth = sal::static_int_cast<sal_Int16>( i+1 );
+ }
+ }
+ // if none found, then test english month names
+ if ( !nMonth && pSecondCalendar && pSecondTransliteration )
+ {
+ xMonths = pSecondCalendar->getMonths();
+ nMonthCount = xMonths.getLength();
+ for (i=0; i<nMonthCount && !nMonth; i++)
+ {
+ if ( pSecondTransliteration->isEqual( aMStr, xMonths[i].FullName ) ||
+ pSecondTransliteration->isEqual( aMStr, xMonths[i].AbbrevName ) )
+ {
+ nMonth = sal::static_int_cast<sal_Int16>( i+1 );
+ bSecondCal = true;
+ }
+ else if ( i == 8 && pSecondTransliteration->isEqual(
+ aMStr, aSepShortened ) )
+ { // correct English abbreviation is SEPT,
+ // but data mostly contains SEP only
+ nMonth = sal::static_int_cast<sal_Int16>( i+1 );
+ bSecondCal = true;
+ }
+ }
+ }
+ }
+
+ SvNumberFormatter* pDocFormatter = rDoc.GetFormatTable();
+ if ( nYear < 100 )
+ nYear = pDocFormatter->ExpandTwoDigitYear( nYear );
+
+ CalendarWrapper* pCalendar = (bSecondCal ? pSecondCalendar : &rCalendar);
+ sal_Int16 nNumMonths = pCalendar->getNumberOfMonthsInYear();
+ if ( nDay && nMonth && nDay<=31 && nMonth<=nNumMonths )
+ {
+ --nMonth;
+ pCalendar->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDay );
+ pCalendar->setValue( i18n::CalendarFieldIndex::MONTH, nMonth );
+ pCalendar->setValue( i18n::CalendarFieldIndex::YEAR, nYear );
+ sal_Int16 nHour, nMinute, nSecond;
+ // #i14974# The imported value should have no fractional value, so set the
+ // time fields to zero (ICU calendar instance defaults to current date/time)
+ nHour = nMinute = nSecond = 0;
+ if (nFound > 3)
+ nHour = static_cast<sal_Int16>(o3tl::toInt32(rStr.subView( nStart[3], nEnd[3]+1-nStart[3])));
+ if (nFound > 4)
+ nMinute = static_cast<sal_Int16>(o3tl::toInt32(rStr.subView( nStart[4], nEnd[4]+1-nStart[4])));
+ if (nFound > 5)
+ nSecond = static_cast<sal_Int16>(o3tl::toInt32(rStr.subView( nStart[5], nEnd[5]+1-nStart[5])));
+ // do not use calendar's milliseconds, to avoid fractional part truncation
+ double fFrac = 0.0;
+ if (nFound > 6)
+ {
+ sal_Unicode cDec = '.';
+ OUString aT = OUStringChar(cDec) + rStr.subView( nStart[6], nEnd[6]+1-nStart[6]);
+ rtl_math_ConversionStatus eStatus;
+ double fV = rtl::math::stringToDouble( aT, cDec, 0, &eStatus );
+ if (eStatus == rtl_math_ConversionStatus_Ok)
+ fFrac = fV / 86400.0;
+ }
+ sal_Int32 nPos;
+ if (nFound > 3 && 1 <= nHour && nHour <= 12 // nHour 0 and >=13 can't be AM/PM
+ && (nPos = nEnd[nFound-1] + 1) < nLen)
+ {
+ // Dreaded AM/PM may be following.
+ while (nPos < nLen && rStr[nPos] == ' ')
+ ++nPos;
+ if (nPos < nLen)
+ {
+ sal_Int32 nStop = nPos;
+ while (nStop < nLen && rStr[nStop] != ' ')
+ ++nStop;
+ OUString aAmPm = rStr.copy( nPos, nStop - nPos);
+ // For AM only 12 needs to be treated, whereas for PM
+ // it must not. Check both, locale and second/English
+ // strings.
+ if (nHour == 12 &&
+ (rTransliteration.isEqual( aAmPm, pFormatter->GetLocaleData()->getTimeAM()) ||
+ (pSecondTransliteration && pSecondTransliteration->isEqual( aAmPm, "AM"))))
+ {
+ nHour = 0;
+ }
+ else if (nHour < 12 &&
+ (rTransliteration.isEqual( aAmPm, pFormatter->GetLocaleData()->getTimePM()) ||
+ (pSecondTransliteration && pSecondTransliteration->isEqual( aAmPm, "PM"))))
+ {
+ nHour += 12;
+ }
+ }
+ }
+ pCalendar->setValue( i18n::CalendarFieldIndex::HOUR, nHour );
+ pCalendar->setValue( i18n::CalendarFieldIndex::MINUTE, nMinute );
+ pCalendar->setValue( i18n::CalendarFieldIndex::SECOND, nSecond );
+ pCalendar->setValue( i18n::CalendarFieldIndex::MILLISECOND, 0 );
+ if ( pCalendar->isValid() )
+ {
+ double fDiff = DateTime(pDocFormatter->GetNullDate()) -
+ pCalendar->getEpochStart();
+ // #i14974# must use getLocalDateTime to get the same
+ // date values as set above
+ double fDays = pCalendar->getLocalDateTime() + fFrac;
+ fDays -= fDiff;
+
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+ LanguageType eDocLang = eLatin; //! which language for date formats?
+
+ SvNumFormatType nType = (nFound > 3 ? SvNumFormatType::DATETIME : SvNumFormatType::DATE);
+ sal_uLong nFormat = pDocFormatter->GetStandardFormat( nType, eDocLang );
+ // maybe there is a special format including seconds or milliseconds
+ if (nFound > 5)
+ nFormat = pDocFormatter->GetStandardFormat( fDays, nFormat, nType, eDocLang);
+
+ ScAddress aPos(nCol,nRow,nTab);
+ if ( bUseDocImport )
+ rDocImport.setNumericCell(aPos, fDays);
+ else
+ rDoc.SetValue( aPos, fDays );
+ rDoc.SetNumberFormat(aPos, nFormat);
+
+ return bMultiLine; // success
+ }
+ }
+ }
+ }
+
+ // Standard or date not determined -> SetString / EditCell
+ if( rStr.indexOf( '\n' ) == -1 )
+ {
+ if (!bDetectNumFormat && nColFormat == SC_COL_STANDARD)
+ {
+ // Import a strict ISO 8601 date(+time) string even without
+ // "Detect special numbers" or "Date (YMD)".
+ do
+ {
+ // Simple pre-check before calling more expensive parser.
+ // ([+-])(Y)YYYY-MM-DD
+ if (rStr.getLength() < 10)
+ break;
+ const sal_Int32 n1 = rStr.indexOf('-', 1);
+ if (n1 < 4)
+ break;
+ const sal_Int32 n2 = rStr.indexOf('-', n1 + 1);
+ if (n2 < 7 || n1 + 3 < n2)
+ break;
+
+ css::util::DateTime aDateTime;
+ if (!sax::Converter::parseDateTime( aDateTime, rStr))
+ break;
+
+ sal_uInt32 nFormat = 0;
+ double fVal = 0.0;
+ SvNumberFormatter* pDocFormatter = rDoc.GetFormatTable();
+ if (pDocFormatter->IsNumberFormat( rStr, nFormat, fVal))
+ {
+ if (pDocFormatter->GetType(nFormat) & SvNumFormatType::DATE)
+ {
+ ScAddress aPos(nCol,nRow,nTab);
+ if (bUseDocImport)
+ rDocImport.setNumericCell(aPos, fVal);
+ else
+ rDoc.SetValue(aPos, fVal);
+ rDoc.SetNumberFormat(aPos, nFormat);
+
+ return bMultiLine; // success
+ }
+ }
+ }
+ while(false);
+ }
+
+ ScSetStringParam aParam;
+ aParam.mpNumFormatter = pFormatter;
+ aParam.mbDetectNumberFormat = bDetectNumFormat;
+ aParam.meSetTextNumFormat = ScSetStringParam::SpecialNumberOnly;
+ aParam.mbHandleApostrophe = false;
+ aParam.mbCheckLinkFormula = true;
+ if ( bUseDocImport )
+ rDocImport.setAutoInput(ScAddress(nCol, nRow, nTab), rStr, &aParam);
+ else
+ rDoc.SetString( nCol, nRow, nTab, rStr, &aParam );
+ }
+ else
+ {
+ bMultiLine = true;
+ ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
+ rEngine.SetTextCurrentDefaults(rStr);
+ if ( bUseDocImport )
+ rDocImport.setEditCell(ScAddress(nCol, nRow, nTab), rEngine.CreateTextObject());
+ else
+ rDoc.SetEditText( ScAddress( nCol, nRow, nTab ), rEngine.CreateTextObject() );
+ }
+ return bMultiLine;
+}
+
+static OUString lcl_GetFixed( const OUString& rLine, sal_Int32 nStart, sal_Int32 nNext,
+ bool& rbIsQuoted, bool& rbOverflowCell )
+{
+ sal_Int32 nLen = rLine.getLength();
+ if (nNext > nLen)
+ nNext = nLen;
+ if ( nNext <= nStart )
+ return OUString();
+
+ const sal_Unicode* pStr = rLine.getStr();
+
+ sal_Int32 nSpace = nNext;
+ while ( nSpace > nStart && pStr[nSpace-1] == ' ' )
+ --nSpace;
+
+ rbIsQuoted = (pStr[nStart] == '"' && pStr[nSpace-1] == '"');
+ if (rbIsQuoted)
+ {
+ bool bFits = (nSpace - nStart - 3 <= nArbitraryCellLengthLimit);
+ if (bFits)
+ return rLine.copy(nStart+1, std::max< sal_Int32 >(0, nSpace-nStart-2));
+ else
+ {
+ SAL_WARN( "sc", "lcl_GetFixed: line doesn't fit into data");
+ rbOverflowCell = true;
+ return rLine.copy(nStart+1, nArbitraryCellLengthLimit);
+ }
+ }
+ else
+ {
+ bool bFits = (nSpace - nStart <= nArbitraryCellLengthLimit);
+ if (bFits)
+ return rLine.copy(nStart, nSpace-nStart);
+ else
+ {
+ SAL_WARN( "sc", "lcl_GetFixed: line doesn't fit into data");
+ rbOverflowCell = true;
+ return rLine.copy(nStart, nArbitraryCellLengthLimit);
+ }
+ }
+}
+
+bool ScImportExport::ExtText2Doc( SvStream& rStrm )
+{
+ if (!pExtOptions)
+ return Text2Doc( rStrm );
+
+ sal_uInt64 const nOldPos = rStrm.Tell();
+ sal_uInt64 const nRemaining = rStrm.remainingSize();
+ std::unique_ptr<ScProgress> xProgress( new ScProgress( pDocSh,
+ ScResId( STR_LOAD_DOC ), nRemaining, true ));
+ rStrm.StartReadingUnicodeText( rStrm.GetStreamCharSet() );
+
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ const SCTAB nTab = aRange.aStart.Tab();
+
+ bool bFixed = pExtOptions->IsFixedLen();
+ OUString aSeps = pExtOptions->GetFieldSeps(); // Need non-const for ReadCsvLine(),
+ const sal_Unicode* pSeps = aSeps.getStr(); // but it will be const anyway (asserted below).
+ bool bMerge = pExtOptions->IsMergeSeps();
+ bool bRemoveSpace = pExtOptions->IsRemoveSpace();
+ sal_uInt16 nInfoCount = pExtOptions->GetInfoCount();
+ const sal_Int32* pColStart = pExtOptions->GetColStart();
+ const sal_uInt8* pColFormat = pExtOptions->GetColFormat();
+ tools::Long nSkipLines = pExtOptions->GetStartRow();
+
+ LanguageType eDocLang = pExtOptions->GetLanguage();
+ SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eDocLang);
+ bool bDetectNumFormat = pExtOptions->IsDetectSpecialNumber();
+ bool bEvaluateFormulas = pExtOptions->IsEvaluateFormulas();
+ bool bSkipEmptyCells = pExtOptions->IsSkipEmptyCells();
+
+ // For date recognition
+ ::utl::TransliterationWrapper aTransliteration(
+ comphelper::getProcessComponentContext(), TransliterationFlags::IGNORE_CASE );
+ aTransliteration.loadModuleIfNeeded( eDocLang );
+ CalendarWrapper aCalendar( comphelper::getProcessComponentContext() );
+ aCalendar.loadDefaultCalendar(
+ LanguageTag::convertToLocale( eDocLang ) );
+ std::unique_ptr< ::utl::TransliterationWrapper > pEnglishTransliteration;
+ std::unique_ptr< CalendarWrapper > pEnglishCalendar;
+ if ( eDocLang != LANGUAGE_ENGLISH_US )
+ {
+ pEnglishTransliteration.reset(new ::utl::TransliterationWrapper (
+ comphelper::getProcessComponentContext(), TransliterationFlags::IGNORE_CASE ));
+ aTransliteration.loadModuleIfNeeded( LANGUAGE_ENGLISH_US );
+ pEnglishCalendar.reset(new CalendarWrapper ( comphelper::getProcessComponentContext() ));
+ pEnglishCalendar->loadDefaultCalendar(
+ LanguageTag::convertToLocale( LANGUAGE_ENGLISH_US ) );
+ }
+
+ OUString aLine;
+ OUString aCell;
+ sal_uInt16 i;
+ SCROW nRow = nStartRow;
+ sal_Unicode cDetectSep = 0xffff; // No separator detection here.
+
+ while(--nSkipLines>0)
+ {
+ aLine = ReadCsvLine(rStrm, !bFixed, aSeps, cStr, cDetectSep); // content is ignored
+ if ( rStrm.eof() )
+ break;
+ }
+
+ // Determine range for Undo.
+ // We don't need this during import of a file to a new sheet or document...
+ bool bDetermineRange = bUndo;
+ bool bColumnsAreDetermined = false;
+
+ // Row heights don't need to be adjusted on the fly if EndPaste() is called
+ // afterwards, which happens only if bDetermineRange. This variable also
+ // survives the toggle of bDetermineRange down at the end of the do{} loop.
+ bool bRangeIsDetermined = bDetermineRange;
+
+ bool bQuotedAsText = pExtOptions && pExtOptions->IsQuotedAsText();
+
+ sal_uInt64 nOriginalStreamPos = rStrm.Tell();
+
+ SCROW nFirstUpdateRowHeight = SCROW_MAX;
+ SCROW nLastUpdateRowHeight = -1;
+
+ ScDocumentImport aDocImport(rDoc);
+ do
+ {
+ for( ;; )
+ {
+ aLine = ReadCsvLine(rStrm, !bFixed, aSeps, cStr, cDetectSep);
+ if ( rStrm.eof() && aLine.isEmpty() )
+ break;
+
+ assert(pSeps == aSeps.getStr());
+
+ if ( nRow > rDoc.MaxRow() )
+ {
+ bOverflowRow = true; // display warning on import
+ break; // for
+ }
+
+ if (!bDetermineRange)
+ EmbeddedNullTreatment( aLine);
+
+ sal_Int32 nLineLen = aLine.getLength();
+ SCCOL nCol = nStartCol;
+ bool bMultiLine = false;
+ if ( bFixed ) // Fixed line length
+ {
+ if (bDetermineRange)
+ {
+ if (!bColumnsAreDetermined)
+ {
+ // Yes, the check is nCol<=rDoc.MaxCol()+1, +1 because it
+ // is only an overflow if there is really data following to
+ // be put behind the last column, which doesn't happen if
+ // info is SC_COL_SKIP.
+ for (i=0; i < nInfoCount && nCol <= rDoc.MaxCol()+1; ++i)
+ {
+ const sal_uInt8 nFmt = pColFormat[i];
+ if (nFmt != SC_COL_SKIP) // otherwise don't increment nCol either
+ {
+ if (nCol > rDoc.MaxCol())
+ bOverflowCol = true; // display warning on import
+ ++nCol;
+ }
+ }
+ bColumnsAreDetermined = true;
+ }
+ }
+ else
+ {
+ sal_Int32 nStartIdx = 0;
+ // Same maxcol+1 check reason as above.
+ for (i=0; i < nInfoCount && nCol <= rDoc.MaxCol()+1; ++i)
+ {
+ sal_Int32 nNextIdx = nStartIdx;
+ if (i + 1 < nInfoCount)
+ CountVisualWidth( aLine, nNextIdx, pColStart[i+1] - pColStart[i] );
+ else
+ nNextIdx = nLineLen;
+ sal_uInt8 nFmt = pColFormat[i];
+ if (nFmt != SC_COL_SKIP) // otherwise don't increment nCol either
+ {
+ if (nCol > rDoc.MaxCol())
+ bOverflowCol = true; // display warning on import
+ else
+ {
+ bool bIsQuoted = false;
+ aCell = lcl_GetFixed( aLine, nStartIdx, nNextIdx, bIsQuoted, bOverflowCell );
+ if (bIsQuoted && bQuotedAsText)
+ nFmt = SC_COL_TEXT;
+
+ bMultiLine |= lcl_PutString(
+ aDocImport, !mbOverwriting, nCol, nRow, nTab, aCell, nFmt,
+ &aNumFormatter, bDetectNumFormat, bEvaluateFormulas, bSkipEmptyCells,
+ aTransliteration, aCalendar,
+ pEnglishTransliteration.get(), pEnglishCalendar.get());
+ }
+ ++nCol;
+ }
+ nStartIdx = nNextIdx;
+ }
+ }
+ }
+ else // Search for the separator
+ {
+ SCCOL nSourceCol = 0;
+ sal_uInt16 nInfoStart = 0;
+ const sal_Unicode* p = aLine.getStr();
+ // Yes, the check is nCol<=rDoc.MaxCol()+1, +1 because it is only an
+ // overflow if there is really data following to be put behind
+ // the last column, which doesn't happen if info is
+ // SC_COL_SKIP.
+ while (*p && nCol <= rDoc.MaxCol()+1)
+ {
+ bool bIsQuoted = false;
+ p = ScImportExport::ScanNextFieldFromString( p, aCell,
+ cStr, pSeps, bMerge, bIsQuoted, bOverflowCell, bRemoveSpace );
+
+ sal_uInt8 nFmt = SC_COL_STANDARD;
+ for ( i=nInfoStart; i<nInfoCount; i++ )
+ {
+ if ( pColStart[i] == nSourceCol + 1 ) // pColStart is 1-based
+ {
+ nFmt = pColFormat[i];
+ nInfoStart = i + 1; // ColInfos are in succession
+ break; // for
+ }
+ }
+ if ( nFmt != SC_COL_SKIP )
+ {
+ if (nCol > rDoc.MaxCol())
+ bOverflowCol = true; // display warning on import
+ else if (!bDetermineRange)
+ {
+ if (bIsQuoted && bQuotedAsText)
+ nFmt = SC_COL_TEXT;
+
+ bMultiLine |= lcl_PutString(
+ aDocImport, !mbOverwriting, nCol, nRow, nTab, aCell, nFmt,
+ &aNumFormatter, bDetectNumFormat, bEvaluateFormulas, bSkipEmptyCells,
+ aTransliteration, aCalendar,
+ pEnglishTransliteration.get(), pEnglishCalendar.get());
+ }
+ ++nCol;
+ }
+
+ ++nSourceCol;
+ }
+ }
+ if (nEndCol < nCol)
+ nEndCol = nCol; //! points to the next free or even rDoc.MaxCol()+2
+
+ if (!bDetermineRange)
+ {
+ if (bMultiLine && !bRangeIsDetermined && pDocSh)
+ { // Adjust just once at the end for a whole range.
+ nFirstUpdateRowHeight = std::min( nFirstUpdateRowHeight, nRow );
+ nLastUpdateRowHeight = std::max( nLastUpdateRowHeight, nRow );
+ }
+ xProgress->SetStateOnPercent( rStrm.Tell() - nOldPos );
+ }
+ ++nRow;
+ }
+ // so far nRow/nEndCol pointed to the next free
+ if (nRow > nStartRow)
+ --nRow;
+ if (nEndCol > nStartCol)
+ nEndCol = ::std::min( static_cast<SCCOL>(nEndCol - 1), rDoc.MaxCol());
+
+ if (bDetermineRange)
+ {
+ aRange.aEnd.SetCol( nEndCol );
+ aRange.aEnd.SetRow( nRow );
+
+ if ( !mbApi && nStartCol != nEndCol &&
+ !rDoc.IsBlockEmpty( nStartCol + 1, nStartRow, nEndCol, nRow, nTab ) )
+ {
+ ScReplaceWarnBox aBox(ScDocShell::GetActiveDialogParent());
+ if (aBox.run() != RET_YES)
+ {
+ return false;
+ }
+ }
+
+ rStrm.Seek( nOriginalStreamPos );
+ nRow = nStartRow;
+ if (!StartPaste())
+ {
+ EndPaste(false);
+ return false;
+ }
+ }
+
+ bDetermineRange = !bDetermineRange; // toggle
+ } while (!bDetermineRange);
+
+ if ( !mbOverwriting )
+ aDocImport.finalize();
+
+ xProgress.reset(); // make room for AdjustRowHeight progress
+
+ if( nFirstUpdateRowHeight < nLastUpdateRowHeight && pDocSh )
+ pDocSh->AdjustRowHeight( nFirstUpdateRowHeight, nLastUpdateRowHeight, nTab);
+
+ if (bRangeIsDetermined)
+ EndPaste(false);
+
+ if (mbImportBroadcast && !mbOverwriting)
+ {
+ rDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
+ pDocSh->PostDataChanged();
+ }
+ return true;
+}
+
+void ScImportExport::EmbeddedNullTreatment( OUString & rStr )
+{
+ // A nasty workaround for data with embedded NULL characters. As long as we
+ // can't handle them properly as cell content (things assume 0-terminated
+ // strings at too many places) simply strip all NULL characters from raw
+ // data. Excel does the same. See fdo#57841 for sample data.
+
+ // The normal case is no embedded NULL, check first before de-/allocating
+ // ustring stuff.
+ sal_Unicode cNull = 0;
+ if (sal_Int32 pos = rStr.indexOf(cNull); pos >= 0)
+ {
+ rStr = rStr.replaceAll(std::u16string_view(&cNull, 1), u"", pos);
+ }
+}
+
+const sal_Unicode* ScImportExport::ScanNextFieldFromString( const sal_Unicode* p,
+ OUString& rField, sal_Unicode cStr, const sal_Unicode* pSeps, bool bMergeSeps, bool& rbIsQuoted,
+ bool& rbOverflowCell, bool bRemoveSpace )
+{
+ rbIsQuoted = false;
+ rField.clear();
+ const sal_Unicode cBlank = ' ';
+ if (cStr && !ScGlobal::UnicodeStrChr(pSeps, cBlank))
+ {
+ // Cope with broken generators that put leading blanks before a quoted
+ // field, like "field1", "field2", "..."
+ // NOTE: this is not in conformance with http://tools.ietf.org/html/rfc4180
+ const sal_Unicode* pb = p;
+ while (*pb == cBlank)
+ ++pb;
+ if (*pb == cStr)
+ p = pb;
+ }
+ if (cStr && *p == cStr) // String in quotes
+ {
+ rbIsQuoted = true;
+ const sal_Unicode* p1;
+ p1 = p = lcl_ScanString( p, rField, pSeps, cStr, DoubledQuoteMode::ESCAPE, rbOverflowCell );
+ while (!lcl_isFieldEnd( *p, pSeps))
+ p++;
+ // Append remaining unquoted and undelimited data (dirty, dirty) to
+ // this field.
+ if (p > p1)
+ {
+ const sal_Unicode* ptrim_f = p;
+ if ( bRemoveSpace )
+ {
+ while ( ptrim_f > p1 && ( *(ptrim_f - 1) == cBlank ) )
+ --ptrim_f;
+ }
+ if (!lcl_appendLineData( rField, p1, ptrim_f))
+ rbOverflowCell = true;
+ }
+ if( *p )
+ p++;
+ }
+ else // up to delimiter
+ {
+ const sal_Unicode* p0 = p;
+ while (!lcl_isFieldEnd( *p, pSeps))
+ p++;
+ const sal_Unicode* ptrim_i = p0;
+ const sal_Unicode* ptrim_f = p; // [ptrim_i,ptrim_f) is cell data after trimming
+ if ( bRemoveSpace )
+ {
+ while ( ptrim_i < ptrim_f && *ptrim_i == cBlank )
+ ++ptrim_i;
+ while ( ptrim_f > ptrim_i && ( *(ptrim_f - 1) == cBlank ) )
+ --ptrim_f;
+ }
+ if (!lcl_appendLineData( rField, ptrim_i, ptrim_f))
+ rbOverflowCell = true;
+ if( *p )
+ p++;
+ }
+ if ( bMergeSeps ) // skip following delimiters
+ {
+ while (*p && ScGlobal::UnicodeStrChr( pSeps, *p))
+ p++;
+ }
+ return p;
+}
+
+namespace {
+
+/**
+ * Check if a given string has any line break characters or separators.
+ *
+ * @param rStr string to inspect.
+ * @param cSep separator character.
+ */
+bool hasLineBreaksOrSeps( const OUString& rStr, sal_Unicode cSep )
+{
+ const sal_Unicode* p = rStr.getStr();
+ for (sal_Int32 i = 0, n = rStr.getLength(); i < n; ++i, ++p)
+ {
+ sal_Unicode c = *p;
+ if (c == cSep)
+ // separator found.
+ return true;
+
+ switch (c)
+ {
+ case '\n':
+ case '\r':
+ // line break found.
+ return true;
+ default:
+ ;
+ }
+ }
+ return false;
+}
+
+}
+
+bool ScImportExport::Doc2Text( SvStream& rStrm )
+{
+ SCCOL nCol;
+ SCROW nRow;
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCTAB nStartTab = aRange.aStart.Tab();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ SCTAB nEndTab = aRange.aEnd.Tab();
+
+ if (!rDoc.GetClipParam().isMultiRange() && nStartTab == nEndTab)
+ if (!rDoc.ShrinkToDataArea( nStartTab, nStartCol, nStartRow, nEndCol, nEndRow ))
+ return false;
+
+ OUString aCellStr;
+
+ bool bConvertLF = (GetSystemLineEnd() != LINEEND_LF);
+
+ // We need to cache sc::ColumnBlockPosition per each column, tab is always nStartTab.
+ std::vector< sc::ColumnBlockPosition > blockPos( nEndCol - nStartCol + 1 );
+ for( SCCOL i = nStartCol; i <= nEndCol; ++i )
+ rDoc.InitColumnBlockPosition( blockPos[ i - nStartCol ], nStartTab, i );
+ for (nRow = nStartRow; nRow <= nEndRow; nRow++)
+ {
+ if (bIncludeFiltered || !rDoc.RowFiltered( nRow, nStartTab ))
+ {
+ for (nCol = nStartCol; nCol <= nEndCol; nCol++)
+ {
+ ScAddress aPos(nCol, nRow, nStartTab);
+ sal_uInt32 nNumFmt = rDoc.GetNumberFormat(aPos);
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+
+ ScRefCellValue aCell(rDoc, aPos, blockPos[ nCol - nStartCol ]);
+ switch (aCell.meType)
+ {
+ case CELLTYPE_FORMULA:
+ {
+ if (bFormulas)
+ {
+ aCellStr = aCell.mpFormula->GetFormula();
+ if( aCellStr.indexOf( cSep ) != -1 )
+ lcl_WriteString( rStrm, aCellStr, cStr, cStr );
+ else
+ lcl_WriteSimpleString( rStrm, aCellStr );
+ }
+ else
+ {
+ const Color* pColor;
+ aCellStr = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, rDoc);
+
+ bool bMultiLineText = ( aCellStr.indexOf( '\n' ) != -1 );
+ if( bMultiLineText )
+ {
+ if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
+ aCellStr = aCellStr.replaceAll( "\n", " " );
+ else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
+ aCellStr = convertLineEnd(aCellStr, GetSystemLineEnd());
+ }
+
+ if( mExportTextOptions.mcSeparatorConvertTo && cSep )
+ aCellStr = aCellStr.replaceAll( OUStringChar(cSep), OUStringChar(mExportTextOptions.mcSeparatorConvertTo) );
+
+ if( mExportTextOptions.mbAddQuotes && ( aCellStr.indexOf( cSep ) != -1 ) )
+ lcl_WriteString( rStrm, aCellStr, cStr, cStr );
+ else
+ lcl_WriteSimpleString( rStrm, aCellStr );
+ }
+ }
+ break;
+ case CELLTYPE_VALUE:
+ {
+ const Color* pColor;
+ aCellStr = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, rDoc);
+ lcl_WriteSimpleString( rStrm, aCellStr );
+ }
+ break;
+ case CELLTYPE_NONE:
+ break;
+ default:
+ {
+ const Color* pColor;
+ aCellStr = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, rDoc);
+
+ bool bMultiLineText = ( aCellStr.indexOf( '\n' ) != -1 );
+ if( bMultiLineText )
+ {
+ if( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSpace )
+ aCellStr = aCellStr.replaceAll( "\n", " " );
+ else if ( mExportTextOptions.meNewlineConversion == ScExportTextOptions::ToSystem && bConvertLF )
+ aCellStr = convertLineEnd(aCellStr, GetSystemLineEnd());
+ }
+
+ if( mExportTextOptions.mcSeparatorConvertTo && cSep )
+ aCellStr = aCellStr.replaceAll( OUStringChar(cSep), OUStringChar(mExportTextOptions.mcSeparatorConvertTo) );
+
+ if( mExportTextOptions.mbAddQuotes && hasLineBreaksOrSeps(aCellStr, cSep) )
+ lcl_WriteString( rStrm, aCellStr, cStr, cStr );
+ else
+ lcl_WriteSimpleString( rStrm, aCellStr );
+ }
+ }
+ if( nCol < nEndCol )
+ lcl_WriteSimpleString( rStrm, OUString(cSep) );
+ }
+ // Do not append a line feed for one single cell.
+ // NOTE: this Doc2Text() is only called for clipboard via
+ // ScImportExport::ExportStream().
+ if (nStartRow != nEndRow || nStartCol != nEndCol)
+ WriteUnicodeOrByteEndl( rStrm );
+ if( rStrm.GetError() != ERRCODE_NONE )
+ break;
+ if( nSizeLimit && rStrm.Tell() > nSizeLimit )
+ break;
+ }
+ }
+
+ return rStrm.GetError() == ERRCODE_NONE;
+}
+
+bool ScImportExport::Sylk2Doc( SvStream& rStrm )
+{
+ bool bOk = true;
+ bool bMyDoc = false;
+ SylkVersion eVersion = SylkVersion::OTHER;
+
+ // US-English separators for StringToDouble
+ sal_Unicode const cDecSep = '.';
+ sal_Unicode const cGrpSep = ',';
+
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ sal_uInt64 nOldPos = rStrm.Tell();
+ bool bData = !bSingle;
+ ::std::vector< sal_uInt32 > aFormats;
+
+ if( !bSingle)
+ bOk = StartPaste();
+
+ while( bOk )
+ {
+ OUString aLine;
+ OUString aText;
+ OStringBuffer aByteLine;
+ SCCOL nCol = nStartCol;
+ SCROW nRow = nStartRow;
+ SCCOL nRefCol = nCol;
+ SCROW nRefRow = nRow;
+ rStrm.Seek( nOldPos );
+ for( ;; )
+ {
+ //! allow unicode
+ rStrm.ReadLine( aByteLine );
+ aLine = OStringToOUString(aByteLine, rStrm.GetStreamCharSet());
+ if( rStrm.eof() )
+ break;
+ bool bInvalidCol = false;
+ bool bInvalidRow = false;
+ const sal_Unicode* p = aLine.getStr();
+ sal_Unicode cTag = *p++;
+ if( cTag == 'C' ) // Content
+ {
+ if( *p++ != ';' )
+ return false;
+
+ bool bInvalidRefCol = false;
+ bool bInvalidRefRow = false;
+ while( *p )
+ {
+ sal_Unicode ch = *p++;
+ ch = ScGlobal::ToUpperAlpha( ch );
+ switch( ch )
+ {
+ case 'X':
+ {
+ bInvalidCol = false;
+ bool bFail = o3tl::checked_add<SCCOL>(o3tl::toInt32(std::u16string_view(p)), nStartCol - 1, nCol);
+ if (bFail || nCol < 0 || rDoc.MaxCol() < nCol)
+ {
+ SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;X invalid nCol=" << nCol);
+ nCol = std::clamp<SCCOL>(nCol, 0, rDoc.MaxCol());
+ bInvalidCol = bOverflowCol = true;
+ }
+ break;
+ }
+ case 'Y':
+ {
+ bInvalidRow = false;
+ bool bFail = o3tl::checked_add(o3tl::toInt32(std::u16string_view(p)), nStartRow - 1, nRow);
+ if (bFail || nRow < 0 || nMaxImportRow < nRow)
+ {
+ SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;Y invalid nRow=" << nRow);
+ nRow = std::clamp<SCROW>(nRow, 0, nMaxImportRow);
+ bInvalidRow = bOverflowRow = true;
+ }
+ break;
+ }
+ case 'C':
+ {
+ bInvalidRefCol = false;
+ bool bFail = o3tl::checked_add<SCCOL>(o3tl::toInt32(std::u16string_view(p)), nStartCol - 1, nRefCol);
+ if (bFail || nRefCol < 0 || rDoc.MaxCol() < nRefCol)
+ {
+ SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;C invalid nRefCol=" << nRefCol);
+ nRefCol = std::clamp<SCCOL>(nRefCol, 0, rDoc.MaxCol());
+ bInvalidRefCol = bOverflowCol = true;
+ }
+ break;
+ }
+ case 'R':
+ {
+ bInvalidRefRow = false;
+ bool bFail = o3tl::checked_add(o3tl::toInt32(std::u16string_view(p)), nStartRow - 1, nRefRow);
+ if (bFail || nRefRow < 0 || nMaxImportRow < nRefRow)
+ {
+ SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;R invalid nRefRow=" << nRefRow);
+ nRefRow = std::clamp<SCROW>(nRefRow, 0, nMaxImportRow);
+ bInvalidRefRow = bOverflowRow = true;
+ }
+ break;
+ }
+ case 'K':
+ {
+ if( !bSingle &&
+ ( nCol < nStartCol || nCol > nEndCol
+ || nRow < nStartRow || nRow > nEndRow
+ || nCol > rDoc.MaxCol() || nRow > nMaxImportRow
+ || bInvalidCol || bInvalidRow ) )
+ break;
+ if( !bData )
+ {
+ if( nRow > nEndRow )
+ nEndRow = nRow;
+ if( nCol > nEndCol )
+ nEndCol = nCol;
+ break;
+ }
+ bool bText;
+ if( *p == '"' )
+ {
+ bText = true;
+ aText.clear();
+ p = lcl_ScanSylkString( p, aText, eVersion);
+ }
+ else
+ bText = false;
+ const sal_Unicode* q = p;
+ while( *q && *q != ';' )
+ q++;
+ if ( (*q != ';' || *(q+1) != 'I') && !bInvalidCol && !bInvalidRow )
+ { // don't ignore value
+ if( bText )
+ {
+ rDoc.EnsureTable(aRange.aStart.Tab());
+ rDoc.SetTextCell(
+ ScAddress(nCol, nRow, aRange.aStart.Tab()), aText);
+ }
+ else
+ {
+ double fVal = rtl_math_uStringToDouble( p,
+ aLine.getStr() + aLine.getLength(),
+ cDecSep, cGrpSep, nullptr, nullptr );
+ rDoc.SetValue( nCol, nRow, aRange.aStart.Tab(), fVal );
+ }
+ }
+ }
+ break;
+ case 'E':
+ case 'M':
+ {
+ if ( ch == 'M' )
+ {
+ if ( nRefCol < nCol )
+ nRefCol = nCol;
+ if ( nRefRow < nRow )
+ nRefRow = nRow;
+ if ( !bData )
+ {
+ if( nRefRow > nEndRow )
+ nEndRow = nRefRow;
+ if( nRefCol > nEndCol )
+ nEndCol = nRefCol;
+ }
+ }
+ if( !bMyDoc || !bData )
+ break;
+ aText = "=";
+ p = lcl_ScanSylkFormula( p, aText, eVersion);
+
+ if (bInvalidCol || bInvalidRow || (ch == 'M' && (bInvalidRefCol || bInvalidRefRow)))
+ break;
+
+ ScAddress aPos( nCol, nRow, aRange.aStart.Tab() );
+ /* FIXME: do we want GRAM_ODFF_A1 instead? At the
+ * end it probably should be GRAM_ODFF_R1C1, since
+ * R1C1 is what Excel writes in SYLK, or even
+ * better GRAM_ENGLISH_XL_R1C1. */
+ const formula::FormulaGrammar::Grammar eGrammar = formula::FormulaGrammar::GRAM_PODF_A1;
+ ScCompiler aComp(rDoc, aPos, eGrammar);
+ std::unique_ptr<ScTokenArray> xCode(aComp.CompileString(aText)); // ctor/InsertMatrixFormula did copy TokenArray
+ rDoc.CheckLinkFormulaNeedingCheck(*xCode);
+ if ( ch == 'M' )
+ {
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SelectTable( aPos.Tab(), true );
+ rDoc.InsertMatrixFormula( nCol, nRow, nRefCol,
+ nRefRow, aMark, OUString(), xCode.get() );
+ }
+ else
+ {
+ ScFormulaCell* pFCell = new ScFormulaCell(
+ rDoc, aPos, *xCode, eGrammar, ScMatrixMode::NONE);
+ rDoc.SetFormulaCell(aPos, pFCell);
+ }
+ }
+ break;
+ }
+ while( *p && *p != ';' )
+ p++;
+ if( *p )
+ p++;
+ }
+ }
+ else if( cTag == 'F' ) // Format
+ {
+ if( *p++ != ';' )
+ return false;
+ sal_Int32 nFormat = -1;
+ while( *p )
+ {
+ sal_Unicode ch = *p++;
+ ch = ScGlobal::ToUpperAlpha( ch );
+ switch( ch )
+ {
+ case 'X':
+ {
+ bInvalidCol = false;
+ bool bFail = o3tl::checked_add<SCCOL>(o3tl::toInt32(std::u16string_view(p)), nStartCol - 1, nCol);
+ if (bFail || nCol < 0 || rDoc.MaxCol() < nCol)
+ {
+ SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;X invalid nCol=" << nCol);
+ nCol = std::clamp<SCCOL>(nCol, 0, rDoc.MaxCol());
+ bInvalidCol = bOverflowCol = true;
+ }
+ break;
+ }
+ case 'Y':
+ {
+ bInvalidRow = false;
+ bool bFail = o3tl::checked_add(o3tl::toInt32(std::u16string_view(p)), nStartRow - 1, nRow);
+ if (bFail || nRow < 0 || nMaxImportRow < nRow)
+ {
+ SAL_WARN("sc.ui","ScImportExport::Sylk2Doc - ;Y invalid nRow=" << nRow);
+ nRow = std::clamp<SCROW>(nRow, 0, nMaxImportRow);
+ bInvalidRow = bOverflowRow = true;
+ }
+ break;
+ }
+ case 'P' :
+ if ( bData )
+ {
+ // F;P<n> sets format code of P;P<code> at
+ // current position, or at ;X;Y if specified.
+ // Note that ;X;Y may appear after ;P
+ const sal_Unicode* p0 = p;
+ while( *p && *p != ';' )
+ p++;
+ OUString aNumber(p0, p - p0);
+ nFormat = aNumber.toInt32();
+ }
+ break;
+ }
+ while( *p && *p != ';' )
+ p++;
+ if( *p )
+ p++;
+ }
+ if ( !bData )
+ {
+ if( nRow > nEndRow )
+ nEndRow = nRow;
+ if( nCol > nEndCol )
+ nEndCol = nCol;
+ }
+ if ( 0 <= nFormat && o3tl::make_unsigned(nFormat) < aFormats.size() && !bInvalidCol && !bInvalidRow )
+ {
+ sal_uInt32 nKey = aFormats[nFormat];
+ rDoc.ApplyAttr( nCol, nRow, aRange.aStart.Tab(),
+ SfxUInt32Item( ATTR_VALUE_FORMAT, nKey ) );
+ }
+ }
+ else if( cTag == 'P' )
+ {
+ if ( bData && *p == ';' && *(p+1) == 'P' )
+ {
+ OUString aCode( p+2 );
+
+ sal_uInt32 nKey;
+ sal_Int32 nCheckPos;
+
+ if (aCode.getLength() > 2048 && utl::ConfigManager::IsFuzzing())
+ {
+ // consider an excessive length as a failure when fuzzing
+ nCheckPos = 1;
+ }
+ else
+ {
+ // unescape doubled semicolons
+ aCode = aCode.replaceAll(";;", ";");
+ // get rid of Xcl escape characters
+ aCode = aCode.replaceAll("\x1b", "");
+ SvNumFormatType nType;
+ rDoc.GetFormatTable()->PutandConvertEntry( aCode, nCheckPos, nType, nKey,
+ LANGUAGE_ENGLISH_US, ScGlobal::eLnge, false);
+ }
+
+ if ( nCheckPos )
+ nKey = 0;
+
+ aFormats.push_back( nKey );
+ }
+ }
+ else if (cTag == 'I' && *p == 'D' && aLine.getLength() > 4)
+ {
+ aLine = aLine.copy(4);
+ if (aLine == "CALCOOO32")
+ eVersion = SylkVersion::OOO32;
+ else if (aLine == "SCALC3")
+ eVersion = SylkVersion::SCALC3;
+ bMyDoc = (eVersion <= SylkVersion::OWN);
+ }
+ else if( cTag == 'E' ) // End
+ break;
+ }
+ if( !bData )
+ {
+ aRange.aEnd.SetCol( nEndCol );
+ aRange.aEnd.SetRow( nEndRow );
+ bOk = StartPaste();
+ bData = true;
+ }
+ else
+ break;
+ }
+
+ EndPaste();
+ return bOk;
+}
+
+bool ScImportExport::Doc2Sylk( SvStream& rStrm )
+{
+ SCCOL nCol;
+ SCROW nRow;
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ OUString aCellStr;
+ OUString aValStr;
+ lcl_WriteSimpleString( rStrm, "ID;PCALCOOO32" );
+ WriteUnicodeOrByteEndl( rStrm );
+
+ for (nRow = nStartRow; nRow <= nEndRow; nRow++)
+ {
+ for (nCol = nStartCol; nCol <= nEndCol; nCol++)
+ {
+ OUString aBufStr;
+ double nVal;
+ bool bForm = false;
+ SCROW r = nRow - nStartRow + 1;
+ SCCOL c = nCol - nStartCol + 1;
+ ScRefCellValue aCell(rDoc, ScAddress(nCol, nRow, aRange.aStart.Tab()));
+ CellType eType = aCell.meType;
+ switch( eType )
+ {
+ case CELLTYPE_FORMULA:
+ bForm = bFormulas;
+ if( rDoc.HasValueData( nCol, nRow, aRange.aStart.Tab()) )
+ goto hasvalue;
+ else
+ goto hasstring;
+
+ case CELLTYPE_VALUE:
+ hasvalue:
+ nVal = rDoc.GetValue( nCol, nRow, aRange.aStart.Tab() );
+
+ aValStr = ::rtl::math::doubleToUString( nVal,
+ rtl_math_StringFormat_Automatic,
+ rtl_math_DecimalPlaces_Max, '.', true );
+
+ aBufStr = "C;X"
+ + OUString::number( c )
+ + ";Y"
+ + OUString::number( r )
+ + ";K"
+ + aValStr;
+ lcl_WriteSimpleString( rStrm, aBufStr );
+ goto checkformula;
+
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ hasstring:
+ aCellStr = rDoc.GetString(nCol, nRow, aRange.aStart.Tab());
+ aCellStr = aCellStr.replaceAll("\n", SYLK_LF);
+
+ aBufStr = "C;X"
+ + OUString::number( c )
+ + ";Y"
+ + OUString::number( r )
+ + ";K";
+ lcl_WriteSimpleString( rStrm, aBufStr );
+ lcl_WriteString( rStrm, aCellStr, '"', ';' );
+
+ checkformula:
+ if( bForm )
+ {
+ const ScFormulaCell* pFCell = aCell.mpFormula;
+ switch ( pFCell->GetMatrixFlag() )
+ {
+ case ScMatrixMode::Reference :
+ aCellStr.clear();
+ break;
+ default:
+ aCellStr = pFCell->GetFormula( formula::FormulaGrammar::GRAM_PODF_A1);
+ /* FIXME: do we want GRAM_ODFF_A1 instead? At
+ * the end it probably should be
+ * GRAM_ODFF_R1C1, since R1C1 is what Excel
+ * writes in SYLK, or even better
+ * GRAM_ENGLISH_XL_R1C1. */
+ }
+ if ( pFCell->GetMatrixFlag() != ScMatrixMode::NONE &&
+ aCellStr.startsWith("{") &&
+ aCellStr.endsWith("}") )
+ { // cut off matrix {} characters
+ aCellStr = aCellStr.copy(1, aCellStr.getLength()-2);
+ }
+ if ( aCellStr[0] == '=' )
+ aCellStr = aCellStr.copy(1);
+ OUString aPrefix;
+ switch ( pFCell->GetMatrixFlag() )
+ {
+ case ScMatrixMode::Formula :
+ { // diff expression with 'M' M$-extension
+ SCCOL nC;
+ SCROW nR;
+ pFCell->GetMatColsRows( nC, nR );
+ nC += c - 1;
+ nR += r - 1;
+ aPrefix = ";R"
+ + OUString::number( nR )
+ + ";C"
+ + OUString::number( nC )
+ + ";M";
+ }
+ break;
+ case ScMatrixMode::Reference :
+ { // diff expression with 'I' M$-extension
+ ScAddress aPos;
+ (void)pFCell->GetMatrixOrigin( rDoc, aPos );
+ aPrefix = ";I;R"
+ + OUString::number( aPos.Row() - nStartRow + 1 )
+ + ";C"
+ + OUString::number( aPos.Col() - nStartCol + 1 );
+ }
+ break;
+ default:
+ // formula Expression
+ aPrefix = ";E";
+ }
+ lcl_WriteSimpleString( rStrm, aPrefix );
+ if ( !aCellStr.isEmpty() )
+ lcl_WriteString( rStrm, aCellStr, 0, ';' );
+ }
+ WriteUnicodeOrByteEndl( rStrm );
+ break;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ lcl_WriteSimpleString( rStrm, OUString( 'E' ) );
+ WriteUnicodeOrByteEndl( rStrm );
+ return rStrm.GetError() == ERRCODE_NONE;
+}
+
+bool ScImportExport::Doc2HTML( SvStream& rStrm, const OUString& rBaseURL )
+{
+ // rtl_TextEncoding is ignored in ScExportHTML, read from Load/Save HTML options
+ ScFormatFilter::Get().ScExportHTML( rStrm, rBaseURL, &rDoc, aRange, RTL_TEXTENCODING_DONTKNOW, bAll,
+ aStreamPath, aNonConvertibleChars, maFilterOptions );
+ return rStrm.GetError() == ERRCODE_NONE;
+}
+
+bool ScImportExport::Doc2RTF( SvStream& rStrm )
+{
+ // rtl_TextEncoding is ignored in ScExportRTF
+ ScFormatFilter::Get().ScExportRTF( rStrm, &rDoc, aRange, RTL_TEXTENCODING_DONTKNOW );
+ return rStrm.GetError() == ERRCODE_NONE;
+}
+
+bool ScImportExport::Doc2Dif( SvStream& rStrm )
+{
+ // for DIF in the clipboard, IBM_850 is always used
+ ScFormatFilter::Get().ScExportDif( rStrm, &rDoc, aRange, RTL_TEXTENCODING_IBM_850 );
+ return true;
+}
+
+bool ScImportExport::Dif2Doc( SvStream& rStrm )
+{
+ SCTAB nTab = aRange.aStart.Tab();
+ ScDocumentUniquePtr pImportDoc( new ScDocument( SCDOCMODE_UNDO ) );
+ pImportDoc->InitUndo( rDoc, nTab, nTab );
+
+ // for DIF in the clipboard, IBM_850 is always used
+ ScFormatFilter::Get().ScImportDif( rStrm, pImportDoc.get(), aRange.aStart, RTL_TEXTENCODING_IBM_850 );
+
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ pImportDoc->GetCellArea( nTab, nEndCol, nEndRow );
+ // if there are no cells in the imported content, nEndCol/nEndRow may be before the start
+ if ( nEndCol < aRange.aStart.Col() )
+ nEndCol = aRange.aStart.Col();
+ if ( nEndRow < aRange.aStart.Row() )
+ nEndRow = aRange.aStart.Row();
+ aRange.aEnd = ScAddress( nEndCol, nEndRow, nTab );
+
+ bool bOk = StartPaste();
+ if (bOk)
+ {
+ InsertDeleteFlags nFlags = InsertDeleteFlags::ALL & ~InsertDeleteFlags::STYLES;
+ rDoc.DeleteAreaTab( aRange, nFlags );
+ pImportDoc->CopyToDocument(aRange, nFlags, false, rDoc);
+ EndPaste();
+ }
+
+ return bOk;
+}
+
+bool ScImportExport::RTF2Doc( SvStream& rStrm, const OUString& rBaseURL )
+{
+ std::unique_ptr<ScEEAbsImport> pImp = ScFormatFilter::Get().CreateRTFImport( &rDoc, aRange );
+ if (!pImp)
+ return false;
+ pImp->Read( rStrm, rBaseURL );
+ aRange = pImp->GetRange();
+
+ bool bOk = StartPaste();
+ if (bOk)
+ {
+ InsertDeleteFlags const nFlags = InsertDeleteFlags::ALL & ~InsertDeleteFlags::STYLES;
+ rDoc.DeleteAreaTab( aRange, nFlags );
+ pImp->WriteToDocument();
+ EndPaste();
+ }
+ return bOk;
+}
+
+bool ScImportExport::HTML2Doc( SvStream& rStrm, const OUString& rBaseURL )
+{
+ std::unique_ptr<ScEEAbsImport> pImp = ScFormatFilter::Get().CreateHTMLImport( &rDoc, rBaseURL, aRange);
+ if (!pImp)
+ return false;
+ pImp->Read( rStrm, rBaseURL );
+ aRange = pImp->GetRange();
+
+ bool bOk = StartPaste();
+ if (bOk)
+ {
+ // ScHTMLImport may call ScDocument::InitDrawLayer, resulting in
+ // a Draw Layer but no Draw View -> create Draw Layer and View here
+ if (pDocSh)
+ pDocSh->MakeDrawLayer();
+
+ InsertDeleteFlags const nFlags = InsertDeleteFlags::ALL & ~InsertDeleteFlags::STYLES;
+ rDoc.DeleteAreaTab( aRange, nFlags );
+
+ if (pExtOptions)
+ {
+ // Pick up import options if available.
+ LanguageType eLang = pExtOptions->GetLanguage();
+ SvNumberFormatter aNumFormatter( comphelper::getProcessComponentContext(), eLang);
+ bool bSpecialNumber = pExtOptions->IsDetectSpecialNumber();
+ pImp->WriteToDocument(false, 1.0, &aNumFormatter, bSpecialNumber);
+ }
+ else
+ // Regular import, with no options.
+ pImp->WriteToDocument();
+
+ EndPaste();
+ }
+ return bOk;
+}
+
+#ifndef DISABLE_DYNLOADING
+
+extern "C" { static void thisModule() {} }
+
+#else
+
+extern "C" {
+ScFormatFilterPlugin* ScFilterCreate();
+}
+
+#endif
+
+typedef ScFormatFilterPlugin * (*FilterFn)();
+ScFormatFilterPlugin &ScFormatFilter::Get()
+{
+ static ScFormatFilterPlugin *plugin = []()
+ {
+#ifndef DISABLE_DYNLOADING
+ OUString sFilterLib(SVLIBRARY("scfilt"));
+ static ::osl::Module aModule;
+ bool bLoaded = aModule.is();
+ if (!bLoaded)
+ bLoaded = aModule.loadRelative(&thisModule, sFilterLib);
+ if (!bLoaded)
+ bLoaded = aModule.load(sFilterLib);
+ if (bLoaded)
+ {
+ oslGenericFunction fn = aModule.getFunctionSymbol( "ScFilterCreate" );
+ if (fn != nullptr)
+ return reinterpret_cast<FilterFn>(fn)();
+ }
+ assert(false);
+ return static_cast<ScFormatFilterPlugin*>(nullptr);
+#else
+ return ScFilterCreate();
+#endif
+ }();
+
+ return *plugin;
+}
+
+// Precondition: pStr is guaranteed to be non-NULL and points to a 0-terminated
+// array.
+static const sal_Unicode* lcl_UnicodeStrChr( const sal_Unicode* pStr,
+ sal_Unicode c )
+{
+ while (*pStr)
+ {
+ if (*pStr == c)
+ return pStr;
+ ++pStr;
+ }
+ return nullptr;
+}
+
+ScImportStringStream::ScImportStringStream( const OUString& rStr )
+ : SvMemoryStream( const_cast<sal_Unicode *>(rStr.getStr()),
+ rStr.getLength() * sizeof(sal_Unicode), StreamMode::READ)
+{
+ SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
+#ifdef OSL_BIGENDIAN
+ SetEndian(SvStreamEndian::BIG);
+#else
+ SetEndian(SvStreamEndian::LITTLE);
+#endif
+}
+
+OUString ReadCsvLine( SvStream &rStream, bool bEmbeddedLineBreak,
+ OUString& rFieldSeparators, sal_Unicode cFieldQuote, sal_Unicode& rcDetectSep, sal_uInt32 nMaxSourceLines )
+{
+ enum RetryState
+ {
+ FORBID,
+ ALLOW,
+ RETRY,
+ RETRIED
+ } eRetryState = (bEmbeddedLineBreak && rcDetectSep == 0 ? RetryState::ALLOW : RetryState::FORBID);
+
+ sal_uInt64 nStreamPos = (eRetryState == RetryState::ALLOW ? rStream.Tell() : 0);
+
+Label_RetryWithNewSep:
+
+ if (eRetryState == RetryState::RETRY)
+ {
+ eRetryState = RetryState::RETRIED;
+ rStream.Seek( nStreamPos);
+ }
+
+ OUString aStr;
+ rStream.ReadUniOrByteStringLine(aStr, rStream.GetStreamCharSet(), nArbitraryLineLengthLimit);
+
+ if (bEmbeddedLineBreak)
+ {
+ sal_Int32 nFirstLineLength = aStr.getLength();
+ sal_uInt64 nFirstLineStreamPos = rStream.Tell();
+ sal_uInt32 nLine = 0;
+
+ const sal_Unicode* pSeps = rFieldSeparators.getStr();
+
+ QuoteType eQuoteState = FIELDEND_QUOTE;
+ bool bFieldStart = true;
+
+ sal_Int32 nLastOffset = 0;
+ sal_Int32 nQuotes = 0;
+ while (!rStream.eof() && aStr.getLength() < nArbitraryLineLengthLimit)
+ {
+ const sal_Unicode * p = aStr.getStr() + nLastOffset;
+ const sal_Unicode * const pStop = aStr.getStr() + aStr.getLength();
+ while (p < pStop)
+ {
+ if (!*p)
+ {
+ // Skip embedded null-characters. They don't change
+ // anything and are handled at a higher level.
+ ++p;
+ continue;
+ }
+
+ if (nQuotes)
+ {
+ if (*p == cFieldQuote)
+ {
+ if (bFieldStart)
+ {
+ ++nQuotes;
+ bFieldStart = false;
+ eQuoteState = FIELDSTART_QUOTE;
+ nFirstLineLength = aStr.getLength();
+ nFirstLineStreamPos = rStream.Tell();
+ }
+ // Do not detect a FIELDSTART_QUOTE if not in
+ // bFieldStart mode, in which case for unquoted content
+ // we are in FIELDEND_QUOTE state.
+ else if (eQuoteState != FIELDEND_QUOTE)
+ {
+ eQuoteState = lcl_isEscapedOrFieldEndQuote( nQuotes, p, pSeps, cFieldQuote, rcDetectSep);
+
+ if (eRetryState == RetryState::ALLOW && rcDetectSep)
+ {
+ eRetryState = RetryState::RETRY;
+ rFieldSeparators += OUStringChar(rcDetectSep);
+ pSeps = rFieldSeparators.getStr();
+ goto Label_RetryWithNewSep;
+ }
+
+ // DONTKNOW_QUOTE is an embedded unescaped quote we
+ // don't count for pairing.
+ if (eQuoteState != DONTKNOW_QUOTE)
+ ++nQuotes;
+ }
+ }
+ else if (eQuoteState == FIELDEND_QUOTE)
+ {
+ if (bFieldStart)
+ // If blank is a separator it starts a field, if it
+ // is not and thus maybe leading before quote we
+ // are still at start of field regarding quotes.
+ bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != nullptr);
+ else
+ bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != nullptr);
+ }
+ }
+ else
+ {
+ if (*p == cFieldQuote && bFieldStart)
+ {
+ nQuotes = 1;
+ eQuoteState = FIELDSTART_QUOTE;
+ bFieldStart = false;
+ nFirstLineLength = aStr.getLength();
+ nFirstLineStreamPos = rStream.Tell();
+ }
+ else if (eQuoteState == FIELDEND_QUOTE)
+ {
+ // This also skips leading blanks at beginning of line
+ // if followed by a quote. It's debatable whether we
+ // actually want that or not, but congruent with what
+ // ScanNextFieldFromString() does.
+ if (bFieldStart)
+ bFieldStart = (*p == ' ' || lcl_UnicodeStrChr( pSeps, *p) != nullptr);
+ else
+ bFieldStart = (lcl_UnicodeStrChr( pSeps, *p) != nullptr);
+ }
+ }
+ // A quote character inside a field content does not start
+ // a quote.
+ ++p;
+ }
+
+ if ((nQuotes & 1) == 0)
+ // We still have a (theoretical?) problem here if due to
+ // nArbitraryLineLengthLimit (or nMaxSourceLines below) we
+ // split a string right between a doubled quote pair.
+ break;
+ else if (eQuoteState == DONTKNOW_QUOTE)
+ // A single unescaped quote somewhere in a quote started
+ // field, most likely that was not meant to have embedded
+ // linefeeds either.
+ break;
+ else if (++nLine >= nMaxSourceLines && nMaxSourceLines > 0)
+ // Unconditionally increment nLine even if nMaxSourceLines==0
+ // so it can be observed in debugger.
+ break;
+ else
+ {
+ nLastOffset = aStr.getLength();
+ OUString aNext;
+ rStream.ReadUniOrByteStringLine(aNext, rStream.GetStreamCharSet(), nArbitraryLineLengthLimit);
+ if (!rStream.eof())
+ aStr += "\n" + aNext;
+ }
+ }
+ if (nQuotes & 1)
+ {
+ // No closing quote at all. A single quote at field start => no
+ // embedded linefeeds for that field, take only first logical line.
+ aStr = aStr.copy( 0, nFirstLineLength);
+ rStream.Seek( nFirstLineStreamPos);
+ }
+ }
+ return aStr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/macromgr.cxx b/sc/source/ui/docshell/macromgr.cxx
new file mode 100644
index 000000000..39080c678
--- /dev/null
+++ b/sc/source/ui/docshell/macromgr.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 <macromgr.hxx>
+#include <document.hxx>
+
+#include <basic/basmgr.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <sfx2/objsh.hxx>
+#include <formulacell.hxx>
+#include <config_features.h>
+#include <vector>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/script/XLibraryContainer.hpp>
+
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::std::vector;
+using ::std::pair;
+
+/**
+ * A simple container to keep track of cells that depend on basic modules
+ * changes. We don't check for duplicates at insertion time; instead, we
+ * remove duplicates at query time.
+ */
+class ScUserMacroDepTracker
+{
+public:
+ void addCell(const OUString& rModuleName, ScFormulaCell* pCell)
+ {
+ ModuleCellMap::iterator itr = maCells.find(rModuleName);
+ if (itr == maCells.end())
+ {
+ pair<ModuleCellMap::iterator, bool> r = maCells.emplace(
+ rModuleName, vector<ScFormulaCell*>());
+
+ if (!r.second)
+ // insertion failed.
+ return;
+
+ itr = r.first;
+ }
+ itr->second.push_back(pCell);
+ }
+
+ void removeCell(const ScFormulaCell* pCell)
+ {
+ for (auto& rEntry : maCells)
+ {
+ rEntry.second.erase(std::remove(rEntry.second.begin(), rEntry.second.end(), pCell), rEntry.second.end() );
+ }
+ }
+
+ void getCellsByModule(const OUString& rModuleName, vector<ScFormulaCell*>& rCells)
+ {
+ ModuleCellMap::iterator itr = maCells.find(rModuleName);
+ if (itr == maCells.end())
+ return;
+
+ vector<ScFormulaCell*>& rCellList = itr->second;
+
+ // Remove duplicates.
+ std::sort(rCellList.begin(), rCellList.end());
+ auto last = std::unique(rCellList.begin(), rCellList.end());
+ rCellList.erase(last, rCellList.end());
+
+ // exception safe copy
+ vector<ScFormulaCell*> temp(rCellList);
+ rCells.swap(temp);
+ }
+
+private:
+ typedef std::unordered_map<OUString, vector<ScFormulaCell*>> ModuleCellMap;
+ ModuleCellMap maCells;
+};
+
+ScMacroManager::ScMacroManager(ScDocument& rDoc) :
+ mpDepTracker(new ScUserMacroDepTracker),
+ mrDoc(rDoc)
+{
+}
+
+ScMacroManager::~ScMacroManager()
+{
+}
+
+typedef ::cppu::WeakImplHelper< css::container::XContainerListener > ContainerListenerHelper;
+
+namespace {
+
+class VBAProjectListener : public ContainerListenerHelper
+{
+ ScMacroManager* mpMacroMgr;
+public:
+ explicit VBAProjectListener( ScMacroManager* pMacroMgr ) : mpMacroMgr( pMacroMgr ) {}
+ // XEventListener
+ virtual void SAL_CALL disposing( const lang::EventObject& /*Source*/ ) override {}
+
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const container::ContainerEvent& /*Event*/ ) override {}
+ virtual void SAL_CALL elementReplaced( const container::ContainerEvent& Event ) override
+ {
+ OUString sModuleName;
+ Event.Accessor >>= sModuleName;
+ mpMacroMgr->InitUserFuncData();
+ mpMacroMgr->BroadcastModuleUpdate(sModuleName);
+ }
+ virtual void SAL_CALL elementRemoved( const container::ContainerEvent& /*Event*/ ) override {}
+
+};
+
+}
+
+void ScMacroManager::InitUserFuncData()
+{
+ // Clear unordered_map
+ mhFuncToVolatile.clear();
+ OUString sProjectName("Standard");
+
+ Reference< container::XContainer > xModuleContainer;
+ SfxObjectShell* pShell = mrDoc.GetDocumentShell();
+ if (!pShell)
+ return;
+#if HAVE_FEATURE_SCRIPTING
+ const BasicManager *pBasicManager = pShell->GetBasicManager();
+ if (!pBasicManager->GetName().isEmpty())
+ {
+ sProjectName = pBasicManager->GetName();
+ }
+#endif
+ try
+ {
+ Reference< script::XLibraryContainer > xLibraries( pShell->GetBasicContainer(), uno::UNO_SET_THROW );
+ xModuleContainer.set( xLibraries->getByName( sProjectName ), uno::UNO_QUERY_THROW );
+
+ // remove old listener ( if there was one )
+ if ( mxContainerListener.is() )
+ xModuleContainer->removeContainerListener( mxContainerListener );
+ // Create listener
+ mxContainerListener = new VBAProjectListener( this );
+ xModuleContainer->addContainerListener( mxContainerListener );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+}
+
+void ScMacroManager::SetUserFuncVolatile( const OUString& sName, bool isVolatile )
+{
+ mhFuncToVolatile[ sName ] = isVolatile;
+}
+
+bool ScMacroManager::GetUserFuncVolatile( const OUString& sName )
+{
+ NameBoolMap::iterator it = mhFuncToVolatile.find( sName );
+ if ( it == mhFuncToVolatile.end() )
+ return false;
+ return it->second;
+}
+
+void ScMacroManager::AddDependentCell(const OUString& aModuleName, ScFormulaCell* pCell)
+{
+ mpDepTracker->addCell(aModuleName, pCell);
+}
+
+void ScMacroManager::RemoveDependentCell(const ScFormulaCell* pCell)
+{
+ mpDepTracker->removeCell(pCell);
+}
+
+void ScMacroManager::BroadcastModuleUpdate(const OUString& aModuleName)
+{
+ vector<ScFormulaCell*> aCells;
+ mpDepTracker->getCellsByModule(aModuleName, aCells);
+ for (ScFormulaCell* pCell : aCells)
+ {
+ mrDoc.PutInFormulaTree(pCell); // for F9 recalc
+
+ // for recalc on cell value change. If the cell is not volatile, the
+ // cell stops listening right away after it gets re-interpreted.
+ mrDoc.StartListeningArea(BCA_LISTEN_ALWAYS, false, pCell);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/olinefun.cxx b/sc/source/ui/docshell/olinefun.cxx
new file mode 100644
index 000000000..76ea01eae
--- /dev/null
+++ b/sc/source/ui/docshell/olinefun.cxx
@@ -0,0 +1,792 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <olinefun.hxx>
+
+#include <docsh.hxx>
+#include <olinetab.hxx>
+#include <tabvwsh.hxx>
+#include <undodat.hxx>
+#include <globstr.hrc>
+#include <sc.hrc>
+
+#include <comphelper/lok.hxx>
+
+
+static void lcl_InvalidateOutliner( SfxBindings* pBindings )
+{
+ if ( pBindings )
+ {
+ pBindings->Invalidate( SID_OUTLINE_SHOW );
+ pBindings->Invalidate( SID_OUTLINE_HIDE );
+ pBindings->Invalidate( SID_OUTLINE_REMOVE );
+
+ pBindings->Invalidate( SID_STATUS_SUM ); // because of enabling/disabling
+ pBindings->Invalidate( SID_ATTR_SIZE );
+ }
+}
+
+//! Move PaintWidthHeight to DocShell ?
+
+static void lcl_PaintWidthHeight( ScDocShell& rDocShell, SCTAB nTab,
+ bool bColumns, SCCOLROW nStart, SCCOLROW nEnd )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ PaintPartFlags nParts = PaintPartFlags::Grid;
+ SCCOL nStartCol = 0;
+ SCROW nStartRow = 0;
+ SCCOL nEndCol = rDoc.MaxCol(); // for testing if merged
+ SCROW nEndRow = rDoc.MaxRow();
+ if ( bColumns )
+ {
+ nParts |= PaintPartFlags::Top;
+ nStartCol = static_cast<SCCOL>(nStart);
+ nEndCol = static_cast<SCCOL>(nEnd);
+ }
+ else
+ {
+ nParts |= PaintPartFlags::Left;
+ nStartRow = nStart;
+ nEndRow = nEnd;
+ }
+ if (rDoc.HasAttrib( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab,
+ HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
+ {
+ nStartCol = 0;
+ nStartRow = 0;
+ }
+ rDocShell.PostPaint( nStartCol,nStartRow,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, nParts );
+}
+
+void ScOutlineDocFunc::MakeOutline( const ScRange& rRange, bool bColumns, bool bRecord, bool bApi )
+{
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nTab = rRange.aStart.Tab();
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab, true );
+ std::unique_ptr<ScOutlineTable> pUndoTab;
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ if (bRecord)
+ pUndoTab.reset(new ScOutlineTable( *pTable ));
+
+ ScOutlineArray& rArray = bColumns ? pTable->GetColArray() : pTable->GetRowArray();
+
+ bool bRes;
+ bool bSize = false;
+ if ( bColumns )
+ bRes = rArray.Insert( nStartCol, nEndCol, bSize );
+ else
+ bRes = rArray.Insert( nStartRow, nEndRow, bSize );
+
+ if ( bRes )
+ {
+ if (bRecord)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoMakeOutline>( &rDocShell,
+ nStartCol,nStartRow,nTab,nEndCol,nEndRow,nTab,
+ std::move(pUndoTab), bColumns, true ) );
+ }
+
+ rDoc.SetStreamValid(nTab, false);
+
+ PaintPartFlags nParts = PaintPartFlags::NONE; // Data range hasn't been changed
+ if ( bColumns )
+ nParts |= PaintPartFlags::Top;
+ else
+ nParts |= PaintPartFlags::Left;
+ if ( bSize )
+ nParts |= PaintPartFlags::Size;
+
+ rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, nParts );
+ rDocShell.SetDocumentModified();
+ lcl_InvalidateOutliner( rDocShell.GetViewBindings() );
+ }
+ else
+ {
+ if (!bApi)
+ rDocShell.ErrorMessage(STR_MSSG_MAKEOUTLINE_0); // "Grouping not possible"
+ }
+}
+
+void ScOutlineDocFunc::RemoveOutline( const ScRange& rRange, bool bColumns, bool bRecord, bool bApi )
+{
+ bool bDone = false;
+
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nTab = rRange.aStart.Tab();
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+ if (pTable)
+ {
+ std::unique_ptr<ScOutlineTable> pUndoTab;
+ if (bRecord)
+ pUndoTab.reset(new ScOutlineTable( *pTable ));
+
+ ScOutlineArray& rArray = bColumns ? pTable->GetColArray() : pTable->GetRowArray();
+
+ bool bRes;
+ bool bSize = false;
+ if ( bColumns )
+ bRes = rArray.Remove( nStartCol, nEndCol, bSize );
+ else
+ bRes = rArray.Remove( nStartRow, nEndRow, bSize );
+
+ if ( bRes )
+ {
+ if (bRecord)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoMakeOutline>( &rDocShell,
+ nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab,
+ std::move(pUndoTab), bColumns, false ) );
+ }
+
+ rDoc.SetStreamValid(nTab, false);
+
+ PaintPartFlags nParts = PaintPartFlags::NONE; // Data range hasn't been changed
+ if ( bColumns )
+ nParts |= PaintPartFlags::Top;
+ else
+ nParts |= PaintPartFlags::Left;
+ if ( bSize )
+ nParts |= PaintPartFlags::Size;
+
+ rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, nParts );
+ rDocShell.SetDocumentModified();
+ bDone = true;
+ lcl_InvalidateOutliner( rDocShell.GetViewBindings() );
+
+ // we are not enabling again -> no UpdatePageBreaks
+ }
+ }
+
+ if (!bDone && !bApi)
+ rDocShell.ErrorMessage(STR_MSSG_REMOVEOUTLINE_0); // "Ungrouping not possible"
+}
+
+bool ScOutlineDocFunc::RemoveAllOutlines( SCTAB nTab, bool bRecord )
+{
+ bool bSuccess = false;
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+ if (pTable)
+ {
+ if (bRecord)
+ {
+ SCCOLROW nCol1, nCol2, nRow1, nRow2;
+ pTable->GetColArray().GetRange( nCol1, nCol2 );
+ pTable->GetRowArray().GetRange( nRow1, nRow2 );
+ SCCOL nStartCol = static_cast<SCCOL>(nCol1);
+ SCROW nStartRow = nRow1;
+ SCCOL nEndCol = static_cast<SCCOL>(nCol2);
+ SCROW nEndRow = nRow2;
+
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ rDoc.CopyToDocument(nStartCol, 0, nTab, nEndCol, rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+ rDoc.CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+
+ std::unique_ptr<ScOutlineTable> pUndoTab(new ScOutlineTable( *pTable ));
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRemoveAllOutlines>( &rDocShell,
+ nStartCol, nStartRow, nTab,
+ nEndCol, nEndRow, nTab,
+ std::move(pUndoDoc), std::move(pUndoTab) ) );
+ }
+
+ SelectLevel( nTab, true, pTable->GetColArray().GetDepth(), false, false );
+ SelectLevel( nTab, false, pTable->GetRowArray().GetDepth(), false, false );
+ rDoc.SetOutlineTable( nTab, nullptr );
+
+ rDoc.UpdatePageBreaks( nTab );
+
+ rDoc.SetStreamValid(nTab, false);
+
+ rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab,
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top | PaintPartFlags::Size );
+ rDocShell.SetDocumentModified();
+ lcl_InvalidateOutliner( rDocShell.GetViewBindings() );
+ bSuccess = true;
+ }
+
+ return bSuccess;
+}
+
+void ScOutlineDocFunc::AutoOutline( const ScRange& rRange, bool bRecord )
+{
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nTab = rRange.aStart.Tab();
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScOutlineTable> pUndoTab;
+
+ if ( pTable )
+ {
+ if ( bRecord )
+ {
+ pUndoTab.reset(new ScOutlineTable( *pTable ));
+
+ SCCOLROW nCol1, nCol2, nRow1, nRow2;
+ pTable->GetColArray().GetRange( nCol1, nCol2 );
+ pTable->GetRowArray().GetRange( nRow1, nRow2 );
+ SCCOL nOutStartCol = static_cast<SCCOL>(nCol1);
+ SCROW nOutStartRow = nRow1;
+ SCCOL nOutEndCol = static_cast<SCCOL>(nCol2);
+ SCROW nOutEndRow = nRow2;
+
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ rDoc.CopyToDocument(nOutStartCol, 0, nTab, nOutEndCol, rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+ rDoc.CopyToDocument(0, nOutStartRow, nTab, rDoc.MaxCol(), nOutEndRow, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+ }
+
+ // enable
+ SelectLevel( nTab, true, pTable->GetColArray().GetDepth(), false, false );
+ SelectLevel( nTab, false, pTable->GetRowArray().GetDepth(), false, false );
+ rDoc.SetOutlineTable( nTab, nullptr );
+ }
+
+ rDoc.DoAutoOutline( nStartCol,nStartRow, nEndCol,nEndRow, nTab );
+
+ if (bRecord)
+ {
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAutoOutline>( &rDocShell,
+ nStartCol, nStartRow, nTab,
+ nEndCol, nEndRow, nTab,
+ std::move(pUndoDoc), std::move(pUndoTab) ) );
+ }
+
+ rDoc.SetStreamValid(nTab, false);
+
+ rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Left | PaintPartFlags::Top | PaintPartFlags::Size );
+ rDocShell.SetDocumentModified();
+ lcl_InvalidateOutliner( rDocShell.GetViewBindings() );
+}
+
+bool ScOutlineDocFunc::SelectLevel( SCTAB nTab, bool bColumns, sal_uInt16 nLevel,
+ bool bRecord, bool bPaint )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab ); // already there
+ if (!pTable)
+ return false;
+ ScOutlineArray& rArray = bColumns ? pTable->GetColArray() : pTable->GetRowArray();
+
+ SCCOLROW nStart, nEnd;
+ rArray.GetRange( nStart, nEnd );
+
+ // TODO undo can mess things up when another view is editing a cell in the range of group entry
+ // this is a temporarily workaround
+ if (!comphelper::LibreOfficeKit::isActive() && bRecord )
+ {
+ std::unique_ptr<ScOutlineTable> pUndoTab(new ScOutlineTable( *pTable ));
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ if (bColumns)
+ {
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true );
+ rDoc.CopyToDocument(static_cast<SCCOL>(nStart), 0, nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false,
+ *pUndoDoc);
+ }
+ else
+ {
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
+ rDoc.CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+ }
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoOutlineLevel>( &rDocShell,
+ nStart, nEnd, nTab, //! calculate start and end
+ std::move(pUndoDoc), std::move(pUndoTab),
+ bColumns, nLevel ) );
+ }
+
+ ScSubOutlineIterator aIter( &rArray ); // all entries
+ ScOutlineEntry* pEntry;
+ while ((pEntry=aIter.GetNext()) != nullptr)
+ {
+ SCCOLROW nThisStart = pEntry->GetStart();
+ SCCOLROW nThisEnd = pEntry->GetEnd();
+
+ sal_uInt16 nThisLevel = aIter.LastLevel();
+ bool bShow = (nThisLevel < nLevel);
+
+ if (!bShow && pViewSh && ScTabViewShell::isAnyEditViewInRange(pViewSh, bColumns, nThisStart, nThisEnd))
+ continue;
+
+ if (bShow) // enable
+ {
+ pEntry->SetHidden( false );
+ pEntry->SetVisible( true );
+ }
+ else if ( nThisLevel == nLevel ) // disable
+ {
+ pEntry->SetHidden( true );
+ pEntry->SetVisible( true );
+ }
+ else // hidden below
+ {
+ if (comphelper::LibreOfficeKit::isActive() && nThisLevel > 0)
+ {
+ pEntry->SetHidden( true );
+ const ScOutlineEntry* pParentEntry = rArray.GetEntryByPos(nThisLevel - 1, nThisStart);
+ if (pParentEntry && pParentEntry->IsHidden())
+ pEntry->SetVisible( false );
+ }
+ else
+ {
+ pEntry->SetVisible( false );
+ }
+ }
+
+ for (SCCOLROW i=nThisStart; i<=nThisEnd; i++)
+ {
+ if ( bColumns )
+ rDoc.ShowCol( static_cast<SCCOL>(i), nTab, bShow );
+ else
+ {
+ // show several rows together, don't show filtered rows
+ SCROW nFilterEnd = i;
+ bool bFiltered = rDoc.RowFiltered( i, nTab, nullptr, &nFilterEnd );
+ nFilterEnd = std::min( nThisEnd, nFilterEnd );
+ if ( !bShow || !bFiltered )
+ rDoc.ShowRows( i, nFilterEnd, nTab, bShow );
+ i = nFilterEnd;
+ }
+ }
+ }
+
+ rDoc.SetDrawPageSize(nTab);
+ rDoc.UpdatePageBreaks( nTab );
+
+ if ( pViewSh )
+ pViewSh->OnLOKShowHideColRow(bColumns, nStart - 1);
+
+ if (bPaint)
+ lcl_PaintWidthHeight( rDocShell, nTab, bColumns, nStart, nEnd );
+
+ rDocShell.SetDocumentModified();
+ lcl_InvalidateOutliner( rDocShell.GetViewBindings() );
+
+ return true;
+}
+
+bool ScOutlineDocFunc::ShowMarkedOutlines( const ScRange& rRange, bool bRecord )
+{
+ bool bDone = false;
+
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nTab = rRange.aStart.Tab();
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+
+ if (pTable)
+ {
+ ScOutlineEntry* pEntry;
+ SCCOLROW nStart;
+ SCCOLROW nEnd;
+ SCCOLROW nMin;
+ SCCOLROW nMax;
+ SCCOLROW i;
+
+ // TODO undo can mess things up when another view is editing a cell in the range of group entry
+ // this is a temporarily workaround
+ if ( !comphelper::LibreOfficeKit::isActive() && bRecord )
+ {
+ std::unique_ptr<ScOutlineTable> pUndoTab(new ScOutlineTable( *pTable ));
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ rDoc.CopyToDocument(nStartCol, 0, nTab, nEndCol, rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+ rDoc.CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoOutlineBlock>( &rDocShell,
+ nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab,
+ std::move(pUndoDoc), std::move(pUndoTab), true ) );
+ }
+
+ // Columns
+
+ nMin=rDoc.MaxCol();
+ nMax=0;
+ ScOutlineArray& rColArray = pTable->GetColArray();
+ ScSubOutlineIterator aColIter( &rColArray );
+ while ((pEntry=aColIter.GetNext()) != nullptr)
+ {
+ nStart = pEntry->GetStart();
+ nEnd = pEntry->GetEnd();
+ if ( nStart>=nStartCol && nEnd<=nEndCol )
+ {
+ pEntry->SetHidden( false );
+ pEntry->SetVisible( true );
+ if (nStart<nMin) nMin=nStart;
+ if (nEnd>nMax) nMax=nEnd;
+ }
+ }
+ const SCCOLROW nMinStartCol = nMin;
+ for ( i=nMin; i<=nMax; i++ )
+ rDoc.ShowCol( static_cast<SCCOL>(i), nTab, true );
+
+ // Rows
+
+ nMin=rDoc.MaxRow();
+ nMax=0;
+ ScOutlineArray& rRowArray = pTable->GetRowArray();
+ ScSubOutlineIterator aRowIter( &rRowArray );
+ while ((pEntry=aRowIter.GetNext()) != nullptr)
+ {
+ nStart = pEntry->GetStart();
+ nEnd = pEntry->GetEnd();
+ if ( nStart>=nStartRow && nEnd<=nEndRow )
+ {
+ pEntry->SetHidden( false );
+ pEntry->SetVisible( true );
+ if (nStart<nMin) nMin=nStart;
+ if (nEnd>nMax) nMax=nEnd;
+ }
+ }
+ const SCCOLROW nMinStartRow = nMin;
+ for ( i=nMin; i<=nMax; i++ )
+ {
+ // show several rows together, don't show filtered rows
+ SCROW nFilterEnd = i;
+ bool bFiltered = rDoc.RowFiltered( i, nTab, nullptr, &nFilterEnd );
+ nFilterEnd = std::min( nMax, nFilterEnd );
+ if ( !bFiltered )
+ rDoc.ShowRows( i, nFilterEnd, nTab, true );
+ i = nFilterEnd;
+ }
+
+
+ rDoc.SetDrawPageSize(nTab);
+ rDoc.UpdatePageBreaks( nTab );
+
+ ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
+ if ( pViewSh )
+ {
+ pViewSh->OnLOKShowHideColRow(/*columns: */ true, nMinStartCol - 1);
+ pViewSh->OnLOKShowHideColRow(/*columns: */ false, nMinStartRow - 1);
+ }
+
+ rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top );
+ rDocShell.SetDocumentModified();
+ bDone = true;
+
+ lcl_InvalidateOutliner( rDocShell.GetViewBindings() );
+ }
+
+ return bDone;
+}
+
+bool ScOutlineDocFunc::HideMarkedOutlines( const ScRange& rRange, bool bRecord )
+{
+ bool bDone = false;
+
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nTab = rRange.aStart.Tab();
+
+ ScDocument& rDoc = rDocShell.GetDocument();
+
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+
+ if (pTable)
+ {
+ const ScOutlineEntry* pEntry;
+ size_t nColLevel;
+ size_t nRowLevel;
+ sal_uInt16 nCount;
+ SCCOLROW nStart;
+ SCCOLROW nEnd;
+ sal_uInt16 i;
+
+ SCCOLROW nEffStartCol = nStartCol;
+ SCCOLROW nEffEndCol = nEndCol;
+ ScOutlineArray& rColArray = pTable->GetColArray();
+ rColArray.FindTouchedLevel( nStartCol, nEndCol, nColLevel );
+ rColArray.ExtendBlock( nColLevel, nEffStartCol, nEffEndCol );
+ SCCOLROW nEffStartRow = nStartRow;
+ SCCOLROW nEffEndRow = nEndRow;
+ ScOutlineArray& rRowArray = pTable->GetRowArray();
+ rRowArray.FindTouchedLevel( nStartRow, nEndRow, nRowLevel );
+ rRowArray.ExtendBlock( nRowLevel, nEffStartRow, nEffEndRow );
+
+ // TODO undo can mess things up when another view is editing a cell in the range of group entry
+ // this is a temporarily workaround
+ if ( !comphelper::LibreOfficeKit::isActive() && bRecord )
+ {
+ std::unique_ptr<ScOutlineTable> pUndoTab(new ScOutlineTable( *pTable ));
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ rDoc.CopyToDocument(static_cast<SCCOL>(nEffStartCol), 0, nTab,
+ static_cast<SCCOL>(nEffEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE,
+ false, *pUndoDoc);
+ rDoc.CopyToDocument(0, nEffStartRow, nTab, rDoc.MaxCol(), nEffEndRow, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoOutlineBlock>( &rDocShell,
+ nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab,
+ std::move(pUndoDoc), std::move(pUndoTab), false ) );
+ }
+
+ // Columns
+
+ nCount = rColArray.GetCount(nColLevel);
+ for ( i=0; i<nCount; i++ )
+ {
+ pEntry = rColArray.GetEntry(nColLevel,i);
+ nStart = pEntry->GetStart();
+ nEnd = pEntry->GetEnd();
+
+ if ( static_cast<SCCOLROW>(nStartCol)<=nEnd && static_cast<SCCOLROW>(nEndCol)>=nStart )
+ HideOutline( nTab, true, nColLevel, i, false, false );
+ }
+
+ // Rows
+
+ nCount = rRowArray.GetCount(nRowLevel);
+ for ( i=0; i<nCount; i++ )
+ {
+ pEntry = rRowArray.GetEntry(nRowLevel,i);
+ nStart = pEntry->GetStart();
+ nEnd = pEntry->GetEnd();
+
+ if ( nStartRow<=nEnd && nEndRow>=nStart )
+ HideOutline( nTab, false, nRowLevel, i, false, false );
+ }
+
+ rDoc.SetDrawPageSize(nTab);
+ rDoc.UpdatePageBreaks( nTab );
+
+ rDocShell.PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top );
+
+ rDocShell.SetDocumentModified();
+ bDone = true;
+
+ lcl_InvalidateOutliner( rDocShell.GetViewBindings() );
+ }
+
+ return bDone;
+}
+
+void ScOutlineDocFunc::ShowOutline( SCTAB nTab, bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry,
+ bool bRecord, bool bPaint )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+ ScOutlineArray& rArray = bColumns ? pTable->GetColArray() : pTable->GetRowArray();
+ ScOutlineEntry* pEntry = rArray.GetEntry( nLevel, nEntry );
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+
+ // TODO undo can mess things up when another view is editing a cell in the range of group entry
+ // this is a temporarily workaround
+ if ( !comphelper::LibreOfficeKit::isActive() && bRecord )
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ if (bColumns)
+ {
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true );
+ rDoc.CopyToDocument(static_cast<SCCOL>(nStart), 0, nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false,
+ *pUndoDoc);
+ }
+ else
+ {
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
+ rDoc.CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+ }
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDoOutline>( &rDocShell,
+ nStart, nEnd, nTab, std::move(pUndoDoc), //! calc start and end
+ bColumns, nLevel, nEntry, true ) );
+ }
+
+ pEntry->SetHidden(false);
+ SCCOLROW i;
+ for ( i = nStart; i <= nEnd; i++ )
+ {
+ if ( bColumns )
+ rDoc.ShowCol( static_cast<SCCOL>(i), nTab, true );
+ else
+ {
+ // show several rows together, don't show filtered rows
+ SCROW nFilterEnd = i;
+ bool bFiltered = rDoc.RowFiltered( i, nTab, nullptr, &nFilterEnd );
+ nFilterEnd = std::min( nEnd, nFilterEnd );
+ if ( !bFiltered )
+ rDoc.ShowRows( i, nFilterEnd, nTab, true );
+ i = nFilterEnd;
+ }
+ }
+
+ ScSubOutlineIterator aIter( &rArray, nLevel, nEntry );
+ while ((pEntry=aIter.GetNext()) != nullptr)
+ {
+ if ( pEntry->IsHidden() )
+ {
+ SCCOLROW nSubStart = pEntry->GetStart();
+ SCCOLROW nSubEnd = pEntry->GetEnd();
+ if ( bColumns )
+ for ( i = nSubStart; i <= nSubEnd; i++ )
+ rDoc.ShowCol( static_cast<SCCOL>(i), nTab, false );
+ else
+ rDoc.ShowRows( nSubStart, nSubEnd, nTab, false );
+ }
+ }
+
+ rArray.SetVisibleBelow( nLevel, nEntry, true, true );
+
+ rDoc.SetDrawPageSize(nTab);
+ rDoc.InvalidatePageBreaks(nTab);
+ rDoc.UpdatePageBreaks( nTab );
+
+ ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
+ if ( pViewSh )
+ pViewSh->OnLOKShowHideColRow(bColumns, nStart - 1);
+
+ if (bPaint)
+ lcl_PaintWidthHeight( rDocShell, nTab, bColumns, nStart, nEnd );
+
+ rDocShell.SetDocumentModified();
+
+ lcl_InvalidateOutliner( rDocShell.GetViewBindings() );
+}
+
+bool ScOutlineDocFunc::HideOutline( SCTAB nTab, bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry,
+ bool bRecord, bool bPaint )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+ ScOutlineArray& rArray = bColumns ? pTable->GetColArray() : pTable->GetRowArray();
+ ScOutlineEntry* pEntry = rArray.GetEntry( nLevel, nEntry );
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+
+ ScTabViewShell* pViewSh = rDocShell.GetBestViewShell();
+ if (pViewSh && ScTabViewShell::isAnyEditViewInRange(pViewSh, bColumns, nStart, nEnd))
+ return false;
+
+ // TODO undo can mess things up when another view is editing a cell in the range of group entry
+ // this is a temporarily workaround
+ if ( !comphelper::LibreOfficeKit::isActive() && bRecord )
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ if (bColumns)
+ {
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true );
+ rDoc.CopyToDocument(static_cast<SCCOL>(nStart), 0, nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false,
+ *pUndoDoc);
+ }
+ else
+ {
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
+ rDoc.CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+ }
+
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDoOutline>( &rDocShell,
+ nStart, nEnd, nTab, std::move(pUndoDoc),
+ bColumns, nLevel, nEntry, false ) );
+ }
+
+ pEntry->SetHidden(true);
+ SCCOLROW i;
+ if ( bColumns )
+ for ( i = nStart; i <= nEnd; i++ )
+ rDoc.ShowCol( static_cast<SCCOL>(i), nTab, false );
+ else
+ rDoc.ShowRows( nStart, nEnd, nTab, false );
+
+ rArray.SetVisibleBelow( nLevel, nEntry, false );
+
+ rDoc.SetDrawPageSize(nTab);
+ rDoc.InvalidatePageBreaks(nTab);
+ rDoc.UpdatePageBreaks( nTab );
+
+ if ( pViewSh )
+ pViewSh->OnLOKShowHideColRow(bColumns, nStart - 1);
+
+ if (bPaint)
+ lcl_PaintWidthHeight( rDocShell, nTab, bColumns, nStart, nEnd );
+
+ rDocShell.SetDocumentModified();
+
+ lcl_InvalidateOutliner( rDocShell.GetViewBindings() );
+
+
+ return true; //! always ???
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/pagedata.cxx b/sc/source/ui/docshell/pagedata.cxx
new file mode 100644
index 000000000..4ab70ed9f
--- /dev/null
+++ b/sc/source/ui/docshell/pagedata.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 <string.h>
+
+#include <pagedata.hxx>
+
+#include <osl/diagnose.h>
+
+ScPrintRangeData::ScPrintRangeData()
+{
+ bTopDown = bAutomatic = true;
+ nFirstPage = 1;
+}
+
+ScPrintRangeData::~ScPrintRangeData()
+{
+}
+
+void ScPrintRangeData::SetPagesX( size_t nCount, const SCCOL* pData )
+{
+ mvPageEndX.resize( nCount );
+ memcpy( mvPageEndX.data(), pData, nCount * sizeof(SCCOL) );
+}
+
+void ScPrintRangeData::SetPagesY( size_t nCount, const SCROW* pData )
+{
+ mvPageEndY.resize(nCount);
+ memcpy( mvPageEndY.data(), pData, nCount * sizeof(SCROW) );
+}
+
+ScPageBreakData::ScPageBreakData(size_t nMax)
+{
+ nUsed = 0;
+ if (nMax)
+ pData.reset( new ScPrintRangeData[nMax] );
+ nAlloc = nMax;
+}
+
+ScPageBreakData::~ScPageBreakData()
+{
+}
+
+ScPrintRangeData& ScPageBreakData::GetData(size_t nPos)
+{
+ OSL_ENSURE(nPos < nAlloc, "ScPageBreakData::GetData bumm");
+
+ if ( nPos >= nUsed )
+ {
+ OSL_ENSURE(nPos == nUsed, "ScPageBreakData::GetData wrong order");
+ nUsed = nPos+1;
+ }
+
+ return pData[nPos];
+}
+
+bool ScPageBreakData::operator==( const ScPageBreakData& rOther ) const
+{
+ if ( nUsed != rOther.nUsed )
+ return false;
+
+ for (size_t i=0; i<nUsed; i++)
+ if ( pData[i].GetPrintRange() != rOther.pData[i].GetPrintRange() )
+ return false;
+
+ //! compare ScPrintRangeData completely ??
+
+ return true;
+}
+
+void ScPageBreakData::AddPages()
+{
+ if ( nUsed > 1 )
+ {
+ tools::Long nPage = pData[0].GetFirstPage();
+ for (size_t i=0; i+1<nUsed; i++)
+ {
+ nPage += static_cast<tools::Long>(pData[i].GetPagesX())*pData[i].GetPagesY();
+ pData[i+1].SetFirstPage( nPage );
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/pntlock.cxx b/sc/source/ui/docshell/pntlock.cxx
new file mode 100644
index 000000000..39713941c
--- /dev/null
+++ b/sc/source/ui/docshell/pntlock.cxx
@@ -0,0 +1,43 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <pntlock.hxx>
+
+ScPaintLockData::ScPaintLockData() :
+ nLevel( 0 ),
+ nDocLevel( 0 ),
+ nParts( PaintPartFlags::NONE ),
+ bModified( false )
+{
+}
+
+ScPaintLockData::~ScPaintLockData()
+{
+}
+
+void ScPaintLockData::AddRange( const ScRange& rRange, PaintPartFlags nP )
+{
+ if (!xRangeList.is())
+ xRangeList = new ScRangeList;
+
+ xRangeList->Join( rRange );
+ nParts |= nP;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/servobj.cxx b/sc/source/ui/docshell/servobj.cxx
new file mode 100644
index 000000000..4367c7140
--- /dev/null
+++ b/sc/source/ui/docshell/servobj.cxx
@@ -0,0 +1,258 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/thread.h>
+#include <osl/diagnose.h>
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <servobj.hxx>
+#include <docsh.hxx>
+#include <impex.hxx>
+#include <brdcst.hxx>
+#include <rangenam.hxx>
+#include <unotools/charclass.hxx>
+
+using namespace formula;
+
+static bool lcl_FillRangeFromName( ScRange& rRange, ScDocShell* pDocSh, const OUString& rName )
+{
+ if (pDocSh)
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScRangeName* pNames = rDoc.GetRangeName();
+ if (pNames)
+ {
+ const ScRangeData* pData = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(rName));
+ if (pData)
+ {
+ if ( pData->IsValidReference( rRange ) )
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ScServerObjectSvtListenerForwarder::ScServerObjectSvtListenerForwarder(
+ ScServerObject* pObjP)
+ : pObj(pObjP)
+{
+}
+
+ScServerObjectSvtListenerForwarder::~ScServerObjectSvtListenerForwarder()
+{
+ //! do NOT access pObj
+}
+
+void ScServerObjectSvtListenerForwarder::Notify( const SfxHint& rHint )
+{
+ pObj->Notify( aBroadcaster, rHint);
+}
+
+ScServerObject::ScServerObject( ScDocShell* pShell, const OUString& rItem ) :
+ aForwarder( this ),
+ pDocSh( pShell ),
+ bRefreshListener( false )
+{
+ // parse item string
+
+ if ( lcl_FillRangeFromName( aRange, pDocSh, rItem ) )
+ {
+ aItemStr = rItem; // must be parsed again on ref update
+ }
+ else
+ {
+ // parse ref
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = ScDocShell::GetCurTab();
+ aRange.aStart.SetTab( nTab );
+
+ // For DDE link, we always must parse references using OOO A1 convention.
+
+ if ( aRange.Parse( rItem, rDoc, FormulaGrammar::CONV_OOO ) & ScRefFlags::VALID )
+ {
+ // area reference
+ }
+ else if ( aRange.aStart.Parse( rItem, rDoc, FormulaGrammar::CONV_OOO ) & ScRefFlags::VALID )
+ {
+ // cell reference
+ aRange.aEnd = aRange.aStart;
+ }
+ else
+ {
+ OSL_FAIL("ScServerObject: invalid item");
+ }
+ }
+
+ pDocSh->GetDocument().GetLinkManager()->InsertServer( this );
+ pDocSh->GetDocument().StartListeningArea( aRange, false, &aForwarder );
+
+ StartListening(*pDocSh); // to notice if DocShell gets deleted
+ StartListening(*SfxGetpApp()); // for SfxHintId::ScAreasChanged
+}
+
+ScServerObject::~ScServerObject()
+{
+ Clear();
+}
+
+void ScServerObject::Clear()
+{
+ if (pDocSh)
+ {
+ ScDocShell* pTemp = pDocSh;
+ pDocSh = nullptr;
+
+ pTemp->GetDocument().EndListeningArea(aRange, false, &aForwarder);
+ pTemp->GetDocument().GetLinkManager()->RemoveServer( this );
+ EndListening(*pTemp);
+ EndListening(*SfxGetpApp());
+ }
+}
+
+void ScServerObject::EndListeningAll()
+{
+ aForwarder.EndListeningAll();
+ SfxListener::EndListeningAll();
+}
+
+bool ScServerObject::GetData(
+ css::uno::Any & rData /*out param*/,
+ const OUString & rMimeType, bool /* bSynchron */ )
+{
+ if (!pDocSh)
+ return false;
+
+ // named ranges may have changed -> update aRange
+ if ( !aItemStr.isEmpty() )
+ {
+ ScRange aNew;
+ if ( lcl_FillRangeFromName( aNew, pDocSh, aItemStr ) && aNew != aRange )
+ {
+ aRange = aNew;
+ bRefreshListener = true;
+ }
+ }
+
+ if ( bRefreshListener )
+ {
+ // refresh the listeners now (this is called from a timer)
+
+ EndListeningAll();
+ pDocSh->GetDocument().StartListeningArea( aRange, false, &aForwarder );
+ StartListening(*pDocSh);
+ StartListening(*SfxGetpApp());
+ bRefreshListener = false;
+ }
+
+ OUString aDdeTextFmt = pDocSh->GetDdeTextFmt();
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ SotClipboardFormatId eFormatId = SotExchange::GetFormatIdFromMimeType( rMimeType );
+ if (SotClipboardFormatId::STRING == eFormatId || SotClipboardFormatId::STRING_TSVC == eFormatId)
+ {
+ ScImportExport aObj( rDoc, aRange );
+ if( aDdeTextFmt[0] == 'F' )
+ aObj.SetFormulas( true );
+ if( aDdeTextFmt == "SYLK" || aDdeTextFmt == "FSYLK" )
+ {
+ OString aByteData;
+ if( aObj.ExportByteString( aByteData, osl_getThreadTextEncoding(), SotClipboardFormatId::SYLK ) )
+ {
+ rData <<= css::uno::Sequence< sal_Int8 >(
+ reinterpret_cast<const sal_Int8*>(aByteData.getStr()),
+ aByteData.getLength() + 1 );
+ return true;
+ }
+ return false;
+ }
+ if( aDdeTextFmt == "CSV" || aDdeTextFmt == "FCSV" )
+ aObj.SetSeparator( ',' );
+ /* TODO: STRING_TSVC could preserve line breaks with added quotes. */
+ aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) );
+ return aObj.ExportData( rMimeType, rData );
+ }
+
+ ScImportExport aObj( rDoc, aRange );
+ aObj.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::ToSpace, ' ', false ) );
+ if( aObj.IsRef() )
+ return aObj.ExportData( rMimeType, rData );
+ return false;
+}
+
+void ScServerObject::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ bool bDataChanged = false;
+
+ // DocShell can't be tested via type info, because SfxHintId::Dying comes from the dtor
+ if ( &rBC == pDocSh )
+ {
+ // from DocShell, only SfxHintId::Dying is interesting
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocSh = nullptr;
+ EndListening(*SfxGetpApp());
+ // don't access DocShell anymore for EndListening etc.
+ }
+ }
+ else if (dynamic_cast<const SfxApplication*>( &rBC) != nullptr)
+ {
+ if ( !aItemStr.isEmpty() && rHint.GetId() == SfxHintId::ScAreasChanged )
+ {
+ // check if named range was modified
+ ScRange aNew;
+ if ( lcl_FillRangeFromName( aNew, pDocSh, aItemStr ) && aNew != aRange )
+ bDataChanged = true;
+ }
+ }
+ else
+ {
+ // must be from Area broadcasters
+
+ const ScHint* pScHint = dynamic_cast<const ScHint*>( &rHint );
+ if (pScHint && (pScHint->GetId() == SfxHintId::ScDataChanged))
+ bDataChanged = true;
+ else if (const ScAreaChangedHint *pChgHint = dynamic_cast<const ScAreaChangedHint*>(&rHint)) // position of broadcaster changed
+ {
+ const ScRange& aNewRange = pChgHint->GetRange();
+ if ( aRange != aNewRange )
+ {
+ bRefreshListener = true;
+ bDataChanged = true;
+ }
+ }
+ else
+ {
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ // If the range is being deleted, listening must be restarted
+ // after the deletion is complete (done in GetData)
+ bRefreshListener = true;
+ bDataChanged = true;
+ }
+ }
+ }
+
+ if ( bDataChanged && HasDataLinks() )
+ SvLinkSource::NotifyDataChanged();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/sizedev.cxx b/sc/source/ui/docshell/sizedev.cxx
new file mode 100644
index 000000000..c5b7e416c
--- /dev/null
+++ b/sc/source/ui/docshell/sizedev.cxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/printer.hxx>
+#include <vcl/virdev.hxx>
+
+#include <sizedev.hxx>
+#include <docsh.hxx>
+#include <scmod.hxx>
+#include <inputopt.hxx>
+
+ScSizeDeviceProvider::ScSizeDeviceProvider( ScDocShell* pDocSh )
+{
+ bool bTextWysiwyg = SC_MOD()->GetInputOptions().GetTextWysiwyg();
+ if ( bTextWysiwyg )
+ {
+ pDevice = pDocSh->GetPrinter();
+ bOwner = false;
+
+ aOldMapMode = pDevice->GetMapMode();
+ pDevice->SetMapMode(MapMode(MapUnit::MapPixel)); // GetNeededSize needs pixel MapMode
+ // printer has right DigitLanguage already
+ }
+ else
+ {
+ pDevice = VclPtr<VirtualDevice>::Create();
+ pDevice->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
+ bOwner = true;
+ }
+
+ Point aLogic = pDevice->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
+ nPPTX = aLogic.X() / 1000.0;
+ nPPTY = aLogic.Y() / 1000.0;
+
+ if ( !bTextWysiwyg )
+ nPPTX /= pDocSh->GetOutputFactor();
+}
+
+ScSizeDeviceProvider::~ScSizeDeviceProvider()
+{
+ if (bOwner)
+ pDevice.disposeAndClear();
+ else
+ pDevice->SetMapMode( aOldMapMode );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/tablink.cxx b/sc/source/ui/docshell/tablink.cxx
new file mode 100644
index 000000000..21fe08519
--- /dev/null
+++ b/sc/source/ui/docshell/tablink.cxx
@@ -0,0 +1,594 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/task/InteractionHandler.hpp>
+
+#include <sfx2/sfxsids.hrc>
+#include <sfx2/app.hxx>
+#include <svl/itemset.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <sfx2/frame.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <vcl/weld.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/transliterationwrapper.hxx>
+#include <unotools/configmgr.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <tablink.hxx>
+
+#include <scextopt.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <undoblk.hxx>
+#include <undotab.hxx>
+#include <global.hxx>
+#include <hints.hxx>
+#include <dociter.hxx>
+#include <formula/opcode.hxx>
+#include <formulaiter.hxx>
+#include <tokenarray.hxx>
+
+struct TableLink_Impl
+{
+ ScDocShell* m_pDocSh;
+ Link<sfx2::SvBaseLink&,void> m_aEndEditLink;
+
+ TableLink_Impl() : m_pDocSh( nullptr ) {}
+};
+
+
+ScTableLink::ScTableLink(ScDocShell* pDocSh, const OUString& rFile,
+ const OUString& rFilter, const OUString& rOpt,
+ sal_Int32 nRefreshDelaySeconds ):
+ ::sfx2::SvBaseLink(SfxLinkUpdateMode::ONCALL,SotClipboardFormatId::SIMPLE_FILE),
+ ScRefreshTimer( nRefreshDelaySeconds ),
+ pImpl( new TableLink_Impl ),
+ aFileName(rFile),
+ aFilterName(rFilter),
+ aOptions(rOpt),
+ bInCreate( false ),
+ bInEdit( false ),
+ bAddUndo( true )
+{
+ pImpl->m_pDocSh = pDocSh;
+}
+
+ScTableLink::ScTableLink(SfxObjectShell* pShell, const OUString& rFile,
+ const OUString& rFilter, const OUString& rOpt,
+ sal_Int32 nRefreshDelaySeconds ):
+ ::sfx2::SvBaseLink(SfxLinkUpdateMode::ONCALL,SotClipboardFormatId::SIMPLE_FILE),
+ ScRefreshTimer( nRefreshDelaySeconds ),
+ pImpl( new TableLink_Impl ),
+ aFileName(rFile),
+ aFilterName(rFilter),
+ aOptions(rOpt),
+ bInCreate( false ),
+ bInEdit( false ),
+ bAddUndo( true )
+{
+ pImpl->m_pDocSh = static_cast< ScDocShell* >( pShell );
+ SetRefreshHandler( LINK( this, ScTableLink, RefreshHdl ) );
+ SetRefreshControl( &pImpl->m_pDocSh->GetDocument().GetRefreshTimerControlAddress() );
+}
+
+ScTableLink::~ScTableLink()
+{
+ // cancel connection
+
+ StopRefreshTimer();
+ ScDocument& rDoc = pImpl->m_pDocSh->GetDocument();
+ SCTAB nCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nCount; nTab++)
+ if (rDoc.IsLinked(nTab) && aFileName == rDoc.GetLinkDoc(nTab))
+ rDoc.SetLink( nTab, ScLinkMode::NONE, "", "", "", "", 0 );
+}
+
+void ScTableLink::Edit(weld::Window* pParent, const Link<SvBaseLink&,void>& rEndEditHdl)
+{
+ pImpl->m_aEndEditLink = rEndEditHdl;
+
+ bInEdit = true;
+ SvBaseLink::Edit( pParent, LINK( this, ScTableLink, TableEndEditHdl ) );
+}
+
+::sfx2::SvBaseLink::UpdateResult ScTableLink::DataChanged(
+ const OUString&, const css::uno::Any& )
+{
+ sfx2::LinkManager* pLinkManager=pImpl->m_pDocSh->GetDocument().GetLinkManager();
+ if (pLinkManager!=nullptr)
+ {
+ OUString aFile, aFilter;
+ sfx2::LinkManager::GetDisplayNames(this, nullptr, &aFile, nullptr, &aFilter);
+
+ // the file dialog returns the filter name with the application prefix
+ // -> remove prefix
+ ScDocumentLoader::RemoveAppPrefix( aFilter );
+
+ if (!bInCreate)
+ Refresh( aFile, aFilter, nullptr, GetRefreshDelaySeconds() ); // don't load twice
+ }
+ return SUCCESS;
+}
+
+void ScTableLink::Closed()
+{
+ // delete link: Undo
+ ScDocument& rDoc = pImpl->m_pDocSh->GetDocument();
+ bool bUndo (rDoc.IsUndoEnabled());
+
+ if (bAddUndo && bUndo)
+ {
+ pImpl->m_pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRemoveLink>( pImpl->m_pDocSh, aFileName ) );
+
+ bAddUndo = false; // only once
+ }
+
+ // connection gets cancelled in the dtor
+
+ SvBaseLink::Closed();
+}
+
+bool ScTableLink::IsUsed() const
+{
+ return pImpl->m_pDocSh->GetDocument().HasLink( aFileName, aFilterName, aOptions );
+}
+
+bool ScTableLink::Refresh(const OUString& rNewFile, const OUString& rNewFilter,
+ const OUString* pNewOptions, sal_Int32 nNewRefreshDelaySeconds )
+{
+ // load document
+
+ if (rNewFile.isEmpty() || rNewFilter.isEmpty())
+ return false;
+
+ OUString aNewUrl = ScGlobal::GetAbsDocName(rNewFile, pImpl->m_pDocSh);
+ bool bNewUrlName = aFileName != aNewUrl;
+
+ std::shared_ptr<const SfxFilter> pFilter = pImpl->m_pDocSh->GetFactory().GetFilterContainer()->GetFilter4FilterName(rNewFilter);
+ if (!pFilter)
+ return false;
+
+ ScDocument& rDoc = pImpl->m_pDocSh->GetDocument();
+ rDoc.SetInLinkUpdate( true );
+
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ // if new filter has been selected, forget options
+ if (aFilterName != rNewFilter)
+ aOptions.clear();
+ if ( pNewOptions ) // options hard-specified?
+ aOptions = *pNewOptions;
+
+ // always create ItemSet, so that DocShell can set the options
+ auto pSet = std::make_shared<SfxAllItemSet>( SfxGetpApp()->GetPool() );
+ if (!aOptions.isEmpty())
+ pSet->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, aOptions ) );
+
+ SfxMedium* pMed = new SfxMedium(aNewUrl, StreamMode::STD_READ, pFilter, std::move(pSet));
+
+ if ( bInEdit ) // only if using the edit dialog,
+ pMed->UseInteractionHandler(true); // enable the filter options dialog
+
+ // aRef->DoClose() will be called explicitly, but it is still more safe to use SfxObjectShellLock here
+ ScDocShell* pSrcShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS);
+ SfxObjectShellLock aRef = pSrcShell;
+ pSrcShell->DoLoad(pMed);
+
+ // options might have been set
+ OUString aNewOpt = ScDocumentLoader::GetOptions(*pMed);
+ if (aNewOpt.isEmpty())
+ aNewOpt = aOptions;
+
+ // Undo...
+
+ ScDocumentUniquePtr pUndoDoc;
+ bool bFirst = true;
+ if (bAddUndo && bUndo)
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+
+ // copy tables
+
+ ScDocShellModificator aModificator( *pImpl->m_pDocSh );
+
+ bool bNotFound = false;
+ ScDocument& rSrcDoc = pSrcShell->GetDocument();
+
+ // from text filters that don't set the table name,
+ // use the one table regardless of link table name
+ bool bAutoTab = (rSrcDoc.GetTableCount() == 1) &&
+ ScDocShell::HasAutomaticTableName( rNewFilter );
+
+ SCTAB nCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nCount; nTab++)
+ {
+ ScLinkMode nMode = rDoc.GetLinkMode(nTab);
+ if (nMode != ScLinkMode::NONE && aFileName == rDoc.GetLinkDoc(nTab))
+ {
+ OUString aTabName = rDoc.GetLinkTab(nTab);
+
+ // Undo
+
+ if (bAddUndo && bUndo)
+ {
+ if (bFirst)
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ else
+ pUndoDoc->AddUndoTab( nTab, nTab, true, true );
+ bFirst = false;
+ ScRange aRange(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab);
+ rDoc.CopyToDocument(aRange, InsertDeleteFlags::ALL, false, *pUndoDoc);
+ pUndoDoc->TransferDrawPage( rDoc, nTab, nTab );
+ pUndoDoc->SetLink( nTab, nMode, aFileName, aFilterName,
+ aOptions, aTabName, GetRefreshDelaySeconds() );
+ pUndoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) );
+ }
+
+ // adjust table name of an ExtDocRef
+
+ if ( bNewUrlName && nMode == ScLinkMode::VALUE )
+ {
+ OUString aName;
+ rDoc.GetName( nTab, aName );
+ if ( ScGlobal::GetTransliteration().isEqual(
+ ScGlobal::GetDocTabName( aFileName, aTabName ), aName ) )
+ {
+ rDoc.RenameTab( nTab,
+ ScGlobal::GetDocTabName( aNewUrl, aTabName ),
+ true/*bExternalDocument*/ );
+ }
+ }
+
+ // copy
+
+ SCTAB nSrcTab = 0;
+ bool bFound = false;
+ /* #i71497# check if external document is loaded successfully,
+ otherwise we may find the empty default sheet "Sheet1" in
+ rSrcDoc, even if the document does not exist. */
+ if( pMed->GetError() == ERRCODE_NONE )
+ {
+ // no sheet name -> use first sheet
+ if ( !aTabName.isEmpty() && !bAutoTab )
+ bFound = rSrcDoc.GetTable( aTabName, nSrcTab );
+ else
+ bFound = true;
+ }
+
+ if (bFound)
+ rDoc.TransferTab( rSrcDoc, nSrcTab, nTab, false, // don't insert anew
+ (nMode == ScLinkMode::VALUE) ); // only values?
+ else
+ {
+ rDoc.DeleteAreaTab( 0,0,rDoc.MaxCol(),rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL );
+
+ bool bShowError = true;
+ if ( nMode == ScLinkMode::VALUE )
+ {
+ // Value link (used with external references in formulas):
+ // Look for formulas that reference the sheet, and put errors in the referenced cells.
+
+ ScRangeList aErrorCells; // cells on the linked sheets that need error values
+
+ ScCellIterator aIter(rDoc, ScRange(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB)); // all sheets
+ for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
+ {
+ if (aIter.getType() != CELLTYPE_FORMULA)
+ continue;
+
+ ScFormulaCell* pCell = aIter.getFormulaCell();
+ ScDetectiveRefIter aRefIter(rDoc, pCell);
+ ScRange aRefRange;
+ while ( aRefIter.GetNextRef( aRefRange ) )
+ {
+ if ( aRefRange.aStart.Tab() <= nTab && aRefRange.aEnd.Tab() >= nTab )
+ {
+ // use first cell of range references (don't fill potentially large ranges)
+
+ aErrorCells.Join( ScRange( aRefRange.aStart ) );
+ }
+ }
+ }
+
+ size_t nRanges = aErrorCells.size();
+ if ( nRanges ) // found any?
+ {
+ ScTokenArray aTokenArr(rDoc);
+ aTokenArr.AddOpCode( ocNotAvail );
+ aTokenArr.AddOpCode( ocOpen );
+ aTokenArr.AddOpCode( ocClose );
+ aTokenArr.AddOpCode( ocStop );
+
+ for (size_t nPos=0; nPos < nRanges; nPos++)
+ {
+ const ScRange & rRange = aErrorCells[ nPos ];
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
+ for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
+ {
+ ScAddress aDestPos( nCol, nRow, nTab );
+ rDoc.SetFormula(aDestPos, aTokenArr);
+ }
+ }
+
+ bShowError = false;
+ }
+ // if no references were found, insert error message (don't leave the sheet empty)
+ }
+
+ if ( bShowError )
+ {
+ // Normal link or no references: put error message on sheet.
+
+ rDoc.SetString( 0,0,nTab, ScResId(STR_LINKERROR) );
+ rDoc.SetString( 0,1,nTab, ScResId(STR_LINKERRORFILE) );
+ rDoc.SetString( 1,1,nTab, aNewUrl );
+ rDoc.SetString( 0,2,nTab, ScResId(STR_LINKERRORTAB) );
+ rDoc.SetString( 1,2,nTab, aTabName );
+ }
+
+ bNotFound = true;
+ }
+
+ if ( bNewUrlName || aFilterName != rNewFilter ||
+ aOptions != aNewOpt || pNewOptions ||
+ nNewRefreshDelaySeconds != GetRefreshDelaySeconds() )
+ rDoc.SetLink( nTab, nMode, aNewUrl, rNewFilter, aNewOpt,
+ aTabName, nNewRefreshDelaySeconds );
+ }
+ }
+
+ // memorize new settings
+
+ if ( bNewUrlName )
+ aFileName = aNewUrl;
+ if (aFilterName != rNewFilter)
+ aFilterName = rNewFilter;
+ if (aOptions != aNewOpt)
+ aOptions = aNewOpt;
+
+ // clean up
+
+ aRef->DoClose();
+
+ // Undo
+
+ if (bAddUndo && bUndo)
+ pImpl->m_pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRefreshLink>( pImpl->m_pDocSh, std::move(pUndoDoc) ) );
+
+ // Paint (may be several tables)
+
+ pImpl->m_pDocSh->PostPaint( ScRange(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB),
+ PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left | PaintPartFlags::Extras );
+ aModificator.SetDocumentModified();
+
+ if (bNotFound)
+ {
+ //! output error ?
+ }
+
+ rDoc.SetInLinkUpdate( false );
+
+ // notify Uno objects (for XRefreshListener)
+ //! also notify Uno objects if file name was changed!
+ ScLinkRefreshedHint aHint;
+ aHint.SetSheetLink( aFileName );
+ rDoc.BroadcastUno( aHint );
+
+ return true;
+}
+
+IMPL_LINK_NOARG(ScTableLink, RefreshHdl, Timer *, void)
+{
+ Refresh( aFileName, aFilterName, nullptr, GetRefreshDelaySeconds() );
+}
+
+IMPL_LINK( ScTableLink, TableEndEditHdl, ::sfx2::SvBaseLink&, rLink, void )
+{
+ pImpl->m_aEndEditLink.Call( rLink );
+ bInEdit = false;
+}
+
+// === ScDocumentLoader ==================================================
+
+OUString ScDocumentLoader::GetOptions( const SfxMedium& rMedium )
+{
+ SfxItemSet* pSet = rMedium.GetItemSet();
+ const SfxStringItem* pItem;
+ if ( pSet && (pItem = pSet->GetItemIfSet( SID_FILE_FILTEROPTIONS )) )
+ return pItem->GetValue();
+
+ return OUString();
+}
+
+bool ScDocumentLoader::GetFilterName( const OUString& rFileName,
+ OUString& rFilter, OUString& rOptions,
+ bool bWithContent, bool bWithInteraction )
+{
+ SfxObjectShell* pDocSh = SfxObjectShell::GetFirst( checkSfxObjectShell<ScDocShell> );
+ while ( pDocSh )
+ {
+ if ( pDocSh->HasName() )
+ {
+ SfxMedium* pMed = pDocSh->GetMedium();
+ if ( pMed->GetName() == rFileName )
+ {
+ rFilter = pMed->GetFilter()->GetFilterName();
+ rOptions = GetOptions(*pMed);
+ return true;
+ }
+ }
+ pDocSh = SfxObjectShell::GetNext( *pDocSh, checkSfxObjectShell<ScDocShell> );
+ }
+
+ INetURLObject aUrl( rFileName );
+ INetProtocol eProt = aUrl.GetProtocol();
+ if ( eProt == INetProtocol::NotValid ) // invalid URL?
+ return false; // abort without creating a medium
+
+ // Filter detection
+
+ std::shared_ptr<const SfxFilter> pSfxFilter;
+ auto pMedium = std::make_unique<SfxMedium>( rFileName, StreamMode::STD_READ );
+ if (pMedium->GetError() == ERRCODE_NONE && !utl::ConfigManager::IsFuzzing())
+ {
+ if ( bWithInteraction )
+ pMedium->UseInteractionHandler(true); // #i73992# no longer called from GuessFilter
+
+ SfxFilterMatcher aMatcher("scalc");
+ if( bWithContent )
+ aMatcher.GuessFilter( *pMedium, pSfxFilter );
+ else
+ aMatcher.GuessFilterIgnoringContent( *pMedium, pSfxFilter );
+ }
+
+ bool bOK = false;
+ if ( pMedium->GetError() == ERRCODE_NONE )
+ {
+ if ( pSfxFilter )
+ rFilter = pSfxFilter->GetFilterName();
+ else
+ rFilter = ScDocShell::GetOwnFilterName(); // otherwise Calc file
+ bOK = !rFilter.isEmpty();
+ }
+
+ return bOK;
+}
+
+void ScDocumentLoader::RemoveAppPrefix( OUString& rFilterName )
+{
+ OUString aAppPrefix( STRING_SCAPP + ": ");
+ if (rFilterName.startsWith( aAppPrefix))
+ rFilterName = rFilterName.copy( aAppPrefix.getLength());
+}
+
+SfxMedium* ScDocumentLoader::CreateMedium( const OUString& rFileName, std::shared_ptr<const SfxFilter> const & pFilter,
+ const OUString& rOptions, weld::Window* pInteractionParent )
+{
+ // Always create SfxItemSet so ScDocShell can set options.
+ auto pSet = std::make_shared<SfxAllItemSet>( SfxGetpApp()->GetPool() );
+ if ( !rOptions.isEmpty() )
+ pSet->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, rOptions ) );
+
+ if (pInteractionParent)
+ {
+ css::uno::Reference<css::uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
+ css::uno::Reference<css::task::XInteractionHandler> xIHdl(css::task::InteractionHandler::createWithParent(xContext,
+ pInteractionParent->GetXWindow()), css::uno::UNO_QUERY_THROW);
+ pSet->Put(SfxUnoAnyItem(SID_INTERACTIONHANDLER, css::uno::Any(xIHdl)));
+ }
+
+ SfxMedium *pRet = new SfxMedium( rFileName, StreamMode::STD_READ, pFilter, std::move(pSet) );
+ if (pInteractionParent)
+ pRet->UseInteractionHandler(true); // to enable the filter options dialog
+ return pRet;
+}
+
+ScDocumentLoader::ScDocumentLoader(const OUString& rFileName,
+ OUString& rFilterName, OUString& rOptions,
+ sal_uInt32 nRekCnt, weld::Window* pInteractionParent,
+ css::uno::Reference<css::io::XInputStream> xInputStream)
+ : pDocShell(nullptr)
+ , pMedium(nullptr)
+{
+ if ( rFilterName.isEmpty() )
+ GetFilterName(rFileName, rFilterName, rOptions, true, pInteractionParent != nullptr);
+
+ std::shared_ptr<const SfxFilter> pFilter = ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName( rFilterName );
+
+ pMedium = CreateMedium(rFileName, pFilter, rOptions, pInteractionParent);
+ if (xInputStream.is())
+ pMedium->setStreamToLoadFrom(xInputStream, true);
+ if ( pMedium->GetError() != ERRCODE_NONE )
+ return ;
+
+ pDocShell = new ScDocShell( SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS );
+ aRef = pDocShell;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScExtDocOptions* pExtDocOpt = rDoc.GetExtDocOptions();
+ if( !pExtDocOpt )
+ {
+ rDoc.SetExtDocOptions( std::make_unique<ScExtDocOptions>() );
+ pExtDocOpt = rDoc.GetExtDocOptions();
+ }
+ pExtDocOpt->GetDocSettings().mnLinkCnt = nRekCnt;
+
+ pDocShell->DoLoad( pMedium );
+
+ OUString aNew = GetOptions(*pMedium); // options are set per dialog on load
+ if (!aNew.isEmpty() && aNew != rOptions)
+ rOptions = aNew;
+}
+
+ScDocumentLoader::~ScDocumentLoader()
+{
+ if ( aRef.is() )
+ aRef->DoClose();
+ else
+ delete pMedium;
+}
+
+void ScDocumentLoader::ReleaseDocRef()
+{
+ if ( aRef.is() )
+ {
+ // release reference without calling DoClose - caller must
+ // have another reference to the doc and call DoClose later
+
+ pDocShell = nullptr;
+ pMedium = nullptr;
+ aRef.clear();
+ }
+}
+
+ScDocument* ScDocumentLoader::GetDocument()
+{
+ return pDocShell ? &pDocShell->GetDocument() : nullptr;
+}
+
+bool ScDocumentLoader::IsError() const
+{
+ if ( pDocShell && pMedium )
+ return pMedium->GetError() != ERRCODE_NONE;
+ else
+ return true;
+}
+
+OUString ScDocumentLoader::GetTitle() const
+{
+ if ( pDocShell )
+ return pDocShell->GetTitle();
+ else
+ return OUString();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/docshell/tpstat.cxx b/sc/source/ui/docshell/tpstat.cxx
new file mode 100644
index 000000000..226c862f3
--- /dev/null
+++ b/sc/source/ui/docshell/tpstat.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <document.hxx>
+#include <docsh.hxx>
+
+#include <tpstat.hxx>
+
+// Dokumentinfo-Tabpage:
+
+std::unique_ptr<SfxTabPage> ScDocStatPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
+{
+ return std::make_unique<ScDocStatPage>( pPage, pController, *rSet );
+}
+
+ScDocStatPage::ScDocStatPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/statisticsinfopage.ui", "StatisticsInfoPage", &rSet)
+ , m_xFtTables(m_xBuilder->weld_label("nosheets"))
+ , m_xFtCells(m_xBuilder->weld_label("nocells"))
+ , m_xFtPages(m_xBuilder->weld_label("nopages"))
+ , m_xFtFormula(m_xBuilder->weld_label("noformula"))
+ , m_xFrame(m_xBuilder->weld_frame("StatisticsInfoPage"))
+{
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ ScDocStat aDocStat;
+
+ if ( pDocSh )
+ pDocSh->GetDocStat( aDocStat );
+
+ OUString aInfo = m_xFrame->get_label() + aDocStat.aDocName;
+ m_xFrame->set_label(aInfo);
+ m_xFtTables->set_label( OUString::number( aDocStat.nTableCount ) );
+ m_xFtCells->set_label( OUString::number( aDocStat.nCellCount ) );
+ m_xFtPages->set_label( OUString::number( aDocStat.nPageCount ) );
+ m_xFtFormula->set_label( OUString::number( aDocStat.nFormulaCount ) );
+
+}
+
+ScDocStatPage::~ScDocStatPage()
+{
+}
+
+bool ScDocStatPage::FillItemSet( SfxItemSet* /* rSet */ )
+{
+ return false;
+}
+
+void ScDocStatPage::Reset( const SfxItemSet* /* rSet */ )
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/chartsh.cxx b/sc/source/ui/drawfunc/chartsh.cxx
new file mode 100644
index 000000000..ac54c435e
--- /dev/null
+++ b/sc/source/ui/drawfunc/chartsh.cxx
@@ -0,0 +1,155 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdoole2.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/graphichelper.hxx>
+
+#include <sfx2/objface.hxx>
+#include <vcl/EnumContext.hxx>
+
+#include <chartsh.hxx>
+#include <sc.hrc>
+#include <viewdata.hxx>
+#include <drawview.hxx>
+#include <gridwin.hxx>
+#include <sfx2/sidebar/SidebarController.hxx>
+#include <tabvwsh.hxx>
+
+#define ShellClass_ScChartShell
+#include <scslots.hxx>
+
+using namespace css::uno;
+using namespace sfx2::sidebar;
+
+namespace drawing = com::sun::star::drawing;
+
+namespace {
+
+bool inChartContext(const ScTabViewShell* pViewShell)
+{
+ SidebarController* pSidebar = SidebarController::GetSidebarControllerForView(pViewShell);
+ if (pSidebar)
+ return pSidebar->hasChartContextCurrently();
+
+ return false;
+}
+
+} // anonymous namespace
+
+SFX_IMPL_INTERFACE(ScChartShell, ScDrawShell)
+
+void ScChartShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT,
+ SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server,
+ ToolbarId::Draw_Objectbar);
+
+ GetStaticInterface()->RegisterPopupMenu("oleobject");
+}
+
+void ScChartShell::Activate(bool bMDI)
+{
+ if(!inChartContext(GetViewData().GetViewShell()))
+ ScDrawShell::Activate(bMDI);
+ else
+ {
+ // Avoid context changes for chart during activation / deactivation.
+ const bool bIsContextBroadcasterEnabled (SfxShell::SetContextBroadcasterEnabled(false));
+
+ SfxShell::Activate(bMDI);
+
+ SfxShell::SetContextBroadcasterEnabled(bIsContextBroadcasterEnabled);
+ }
+}
+
+void ScChartShell::Deactivate(bool bMDI)
+{
+ if(!inChartContext(GetViewData().GetViewShell()))
+ ScDrawShell::Deactivate(bMDI);
+ else
+ {
+ // Avoid context changes for chart during activation / deactivation.
+ const bool bIsContextBroadcasterEnabled (SfxShell::SetContextBroadcasterEnabled(false));
+
+ SfxShell::Deactivate(bMDI);
+
+ SfxShell::SetContextBroadcasterEnabled(bIsContextBroadcasterEnabled);
+ }
+}
+
+ScChartShell::ScChartShell(ScViewData& rData) :
+ ScDrawShell(rData)
+{
+ SetName( "ChartObject" );
+ SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Chart));
+}
+
+ScChartShell::~ScChartShell()
+{
+}
+
+void ScChartShell::GetExportAsGraphicState( SfxItemSet& rSet )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ bool bEnable = false;
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( dynamic_cast<const SdrOle2Obj*>( pObj) )
+ bEnable = true;
+ }
+
+ if (GetObjectShell()->isExportLocked())
+ bEnable = false;
+
+ if( !bEnable )
+ rSet.DisableItem( SID_EXPORT_AS_GRAPHIC );
+}
+
+void ScChartShell::ExecuteExportAsGraphic( SfxRequest& )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObject = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( dynamic_cast<const SdrOle2Obj*>( pObject) )
+ {
+ vcl::Window* pWin = GetViewData().GetActiveWin();
+ css::uno::Reference<css::lang::XComponent> xComponent;
+ const SfxObjectShell* pShell = GetObjectShell();
+ if (pShell)
+ {
+ xComponent = pShell->GetModel();
+ }
+ Reference< drawing::XShape > xSourceDoc( pObject->getUnoShape() );
+ GraphicHelper::SaveShapeAsGraphic(pWin ? pWin->GetFrameWeld() : nullptr, xComponent,
+ xSourceDoc);
+ }
+ }
+
+ Invalidate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/drawsh.cxx b/sc/source/ui/drawfunc/drawsh.cxx
new file mode 100644
index 000000000..53273c77c
--- /dev/null
+++ b/sc/source/ui/drawfunc/drawsh.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 <svx/svxdlg.hxx>
+#include <svx/dialogs.hrc>
+#include <sc.hrc>
+
+#include <editeng/eeitem.hxx>
+#include <svx/fontwork.hxx>
+#include <svx/svdpage.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/whiter.hxx>
+
+#include <drawsh.hxx>
+#include <drwlayer.hxx>
+#include <strings.hrc>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <drawview.hxx>
+#include <scresid.hxx>
+#include <svx/svdobj.hxx>
+#include <tabvwsh.hxx>
+#include <gridwin.hxx>
+#include <sfx2/bindings.hxx>
+
+#define ShellClass_ScDrawShell
+#include <scslots.hxx>
+
+#include <userdat.hxx>
+#include <svl/macitem.hxx>
+#include <sfx2/evntconf.hxx>
+#include <sfx2/viewsh.hxx>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <memory>
+#include <svx/xlnwtit.hxx>
+#include <svx/chrtitem.hxx>
+#include <svx/xlnclit.hxx>
+#include <svx/xflclit.hxx>
+#include <svx/xflgrit.hxx>
+#include <tools/UnitConversion.hxx>
+#include <comphelper/lok.hxx>
+#include <vcl/unohelp2.hxx>
+
+using namespace css;
+
+SFX_IMPL_INTERFACE(ScDrawShell, SfxShell)
+
+namespace
+{
+ void lcl_convertStringArguments(sal_uInt16 nSlot, SfxItemSet& rArgs)
+ {
+ Color aColor;
+
+ if (const SvxDoubleItem* pWidthItem = rArgs.GetItemIfSet(SID_ATTR_LINE_WIDTH_ARG, false))
+ {
+ double fValue = pWidthItem->GetValue();
+ // FIXME: different units...
+ int nPow = 100;
+ int nValue = fValue * nPow;
+
+ XLineWidthItem aItem(nValue);
+ rArgs.Put(aItem);
+ }
+ else if (const SfxStringItem* pColorItem = rArgs.GetItemIfSet(SID_ATTR_COLOR_STR, false))
+ {
+ OUString sColor = pColorItem->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);
+ rArgs.Put(aLineColorItem);
+ break;
+ }
+
+ case SID_ATTR_FILL_COLOR:
+ {
+ XFillColorItem aFillColorItem(OUString(), aColor);
+ rArgs.Put(aFillColorItem);
+ break;
+ }
+
+ case SID_ATTR_SHADOW_COLOR:
+ {
+ XColorItem aItem(SDRATTR_SHADOWCOLOR, aColor);
+ rArgs.Put(aItem);
+ break;
+ }
+ }
+ }
+ if (const SfxStringItem* pJSON = rArgs.GetItemIfSet(SID_FILL_GRADIENT_JSON, false))
+ {
+ XGradient aGradient = XGradient::fromJSON(pJSON->GetValue());
+ XFillGradientItem aItem(aGradient);
+ rArgs.Put(aItem);
+ }
+ }
+}
+
+void ScDrawShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT,
+ SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server,
+ ToolbarId::Draw_Objectbar);
+
+ GetStaticInterface()->RegisterPopupMenu("draw");
+
+ GetStaticInterface()->RegisterChildWindow(SvxFontWorkChildWindow::GetChildWindowId());
+}
+
+// disable the unwanted Accelerators
+
+void ScDrawShell::StateDisableItems( SfxItemSet &rSet )
+{
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ while (nWhich)
+ {
+ rSet.DisableItem( nWhich );
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void ScDrawShell::setModified()
+{
+ const SfxObjectShell* pShell = GetObjectShell();
+ if ( pShell )
+ {
+ css::uno::Reference< css::util::XModifiable > xModif( pShell->GetModel(), css::uno::UNO_QUERY );
+ if ( xModif.is() )
+ xModif->setModified( true );
+ }
+}
+
+static void lcl_invalidateTransformAttr(const ScTabViewShell* pViewShell)
+{
+ SfxBindings& rBindings=pViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_ATTR_TRANSFORM_WIDTH);
+ rBindings.Invalidate(SID_ATTR_TRANSFORM_HEIGHT);
+ rBindings.Invalidate(SID_ATTR_TRANSFORM_POS_X);
+ rBindings.Invalidate(SID_ATTR_TRANSFORM_POS_Y);
+ rBindings.Invalidate(SID_ATTR_TRANSFORM_ANGLE);
+ rBindings.Invalidate(SID_ATTR_TRANSFORM_ROT_X);
+ rBindings.Invalidate(SID_ATTR_TRANSFORM_ROT_Y);
+ rBindings.Invalidate(SID_ATTR_TRANSFORM_AUTOWIDTH);
+ rBindings.Invalidate(SID_ATTR_TRANSFORM_AUTOHEIGHT);
+}
+
+void ScDrawShell::ExecDrawAttr( SfxRequest& rReq )
+{
+ sal_uInt16 nSlot = rReq.GetSlot();
+ vcl::Window* pWin = rViewData.GetActiveWin();
+ ScDrawView* pView = rViewData.GetScDrawView();
+ SdrModel* pDoc = rViewData.GetDocument().GetDrawLayer();
+
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+ SdrObject* pSingleSelectedObj = nullptr;
+ if ( nMarkCount > 0 )
+ pSingleSelectedObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ switch ( nSlot )
+ {
+ case SID_ASSIGNMACRO:
+ {
+ if ( pSingleSelectedObj )
+ ExecuteMacroAssign(pSingleSelectedObj, pWin ? pWin->GetFrameWeld() : nullptr);
+ }
+ break;
+
+ case SID_TEXT_STANDARD: // delete hard text attributes
+ {
+ SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aEmptyAttr(GetPool());
+ pView->SetAttributes(aEmptyAttr, true);
+ }
+ 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());
+
+ bool bNegateX = comphelper::LibreOfficeKit::isActive() && rViewData.GetDocument().IsLayoutRTL(rViewData.GetTabNo());
+ pView->MoveShapeHandle(handleNum, Point(bNegateX ? -static_cast<tools::Long>(newPosX) : newPosX, newPosY), OrdNum ? OrdNum->GetValue() : -1);
+ }
+ }
+ break;
+
+ case SID_ATTR_LINE_STYLE:
+ case SID_ATTR_LINEEND_STYLE:
+ case SID_ATTR_LINE_START:
+ case SID_ATTR_LINE_END:
+ 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_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_TRANSPARENCE:
+ case SID_ATTR_FILL_FLOATTRANSPARENCE:
+
+ // #i25616#
+ case SID_ATTR_FILL_SHADOW:
+ case SID_ATTR_SHADOW_TRANSPARENCE:
+ case SID_ATTR_SHADOW_COLOR:
+ case SID_ATTR_SHADOW_XDISTANCE:
+ case SID_ATTR_SHADOW_YDISTANCE:
+ {
+ // if toolbar is vertical :
+ if ( !rReq.GetArgs() )
+ {
+ switch ( nSlot )
+ {
+ 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:
+ ExecuteLineDlg( rReq );
+ 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_TRANSPARENCE:
+ case SID_ATTR_FILL_FLOATTRANSPARENCE:
+
+ // #i25616#
+ case SID_ATTR_FILL_SHADOW:
+ case SID_ATTR_SHADOW_TRANSPARENCE:
+ case SID_ATTR_SHADOW_COLOR:
+ case SID_ATTR_SHADOW_XDISTANCE:
+ case SID_ATTR_SHADOW_YDISTANCE:
+ ExecuteAreaDlg( rReq );
+ break;
+
+ default:
+ break;
+ }
+
+ return;
+
+ }
+
+ if( pView->AreObjectsMarked() )
+ {
+ SfxItemSet aNewArgs = rReq.GetArgs()->CloneAsValue();
+ lcl_convertStringArguments( rReq.GetSlot(), aNewArgs );
+ pView->SetAttrToMarked( aNewArgs, false );
+ }
+ else
+ pView->SetDefaultAttr( *rReq.GetArgs(), false);
+ pView->InvalidateAttribs();
+ }
+ break;
+
+ case SID_ATTRIBUTES_LINE:
+ ExecuteLineDlg( rReq );
+ break;
+
+ case SID_ATTRIBUTES_AREA:
+ ExecuteAreaDlg( rReq );
+ break;
+
+ case SID_MEASURE_DLG:
+ ExecuteMeasureDlg( rReq );
+ break;
+
+ case SID_DRAWTEXT_ATTR_DLG:
+ ExecuteTextAttrDlg( rReq );
+ break;
+
+ case SID_EDIT_HYPERLINK:
+ if ( pSingleSelectedObj )
+ rViewData.GetDispatcher().Execute( SID_HYPERLINK_DIALOG );
+ break;
+
+ case SID_REMOVE_HYPERLINK:
+ if ( pSingleSelectedObj )
+ {
+ pSingleSelectedObj->setHyperlink(OUString());
+ setModified();
+ }
+ break;
+
+ case SID_OPEN_HYPERLINK:
+ case SID_COPY_HYPERLINK_LOCATION:
+ if ( nMarkCount == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ if ( pObj->IsGroupObject() )
+ {
+ SdrPageView* pPV = nullptr;
+ SdrObject* pHit = pView->PickObj(pWin->PixelToLogic(rViewData.GetMousePosPixel()), pView->getHitTolLog(), pPV, SdrSearchOptions::DEEP);
+ if (pHit)
+ pObj = pHit;
+ }
+
+ if (!pObj->getHyperlink().isEmpty())
+ {
+ if (nSlot == SID_OPEN_HYPERLINK)
+ {
+ ScGlobal::OpenURL(pObj->getHyperlink(), OUString(), true);
+ }
+ else if (nSlot == SID_COPY_HYPERLINK_LOCATION)
+ {
+ uno::Reference<datatransfer::clipboard::XClipboard> xClipboard
+ = GetViewShell()->GetWindow()->GetClipboard();
+ vcl::unohelper::TextDataObject::CopyStringTo(pObj->getHyperlink(), xClipboard);
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_TRANSFORM:
+ {
+ if ( pView->AreObjectsMarked() )
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ if( !pArgs )
+ {
+ if( rMarkList.GetMark(0) != nullptr )
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ std::shared_ptr<SfxRequest> pRequest = std::make_shared<SfxRequest>(rReq);
+
+ if( pObj->GetObjIdentifier() == SdrObjKind::Caption )
+ {
+ // Caption Itemset
+ SfxItemSet aNewAttr(pDoc->GetItemPool());
+ pView->GetAttributes(aNewAttr);
+ // Size and Position Itemset
+ SfxItemSet aNewGeoAttr(pView->GetGeoAttrFromMarked());
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ VclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateCaptionDialog(pWin ? pWin->GetFrameWeld() : nullptr, pView));
+
+ const WhichRangesContainer& pRange = pDlg->GetInputRanges( *aNewAttr.GetPool() );
+ SfxItemSet aCombSet( *aNewAttr.GetPool(), pRange );
+ aCombSet.Put( aNewAttr );
+ aCombSet.Put( aNewGeoAttr );
+ pDlg->SetInputSet( &aCombSet );
+
+ pDlg->StartExecuteAsync([pDlg, pRequest, pView, this](
+ sal_Int32 nResult){
+ if (nResult == RET_OK)
+ {
+ pRequest->Done(*(pDlg->GetOutputItemSet()));
+ pView->SetAttributes(*pDlg->GetOutputItemSet());
+ pView->SetGeoAttrToMarked(*pDlg->GetOutputItemSet());
+ }
+
+ lcl_invalidateTransformAttr(rViewData.GetViewShell());
+ pDlg->disposeOnce();
+ });
+ }
+ else
+ {
+ SfxItemSet aNewAttr(pView->GetGeoAttrFromMarked());
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ VclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSvxTransformTabDialog(pWin ? pWin->GetFrameWeld() : nullptr, &aNewAttr, pView));
+
+ pDlg->StartExecuteAsync([pDlg, pRequest, pView, this](
+ sal_Int32 nResult){
+ if (nResult == RET_OK)
+ {
+ pRequest->Done(*(pDlg->GetOutputItemSet()));
+ pView->SetGeoAttrToMarked(*pDlg->GetOutputItemSet());
+ }
+
+ lcl_invalidateTransformAttr(rViewData.GetViewShell());
+ pDlg->disposeOnce();
+ });
+ }
+ }
+
+ }
+ else
+ pView->SetGeoAttrToMarked( *pArgs );
+ }
+
+ lcl_invalidateTransformAttr(rViewData.GetViewShell());
+ }
+ 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())
+ pView->SetAttrToMarked(*pNewArgs, false);
+ rReq.Done();
+ break;
+
+ default:
+ break;
+ }
+}
+
+void ScDrawShell::ExecuteMacroAssign(SdrObject* pObj, weld::Window* pWin)
+{
+ SvxMacroItem aItem ( SfxGetpApp()->GetPool().GetWhich( SID_ATTR_MACROITEM ) );
+ ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( pObj, true );
+ if ( !pInfo->GetMacro().isEmpty() )
+ {
+ SvxMacroTableDtor aTab;
+ const OUString& sMacro = pInfo->GetMacro();
+ aTab.Insert(SvMacroItemId::OnClick, SvxMacro(sMacro, OUString()));
+ aItem.SetMacroTable( aTab );
+ }
+
+ // create empty itemset for macro-dlg
+ SfxItemSetFixed<SID_ATTR_MACROITEM, SID_ATTR_MACROITEM, SID_EVENTCONFIG, SID_EVENTCONFIG> aItemSet(SfxGetpApp()->GetPool() );
+ aItemSet.Put ( aItem );
+
+ SfxEventNamesItem aNamesItem(SID_EVENTCONFIG);
+ aNamesItem.AddEvent( ScResId(RID_SCSTR_ONCLICK), OUString(), SvMacroItemId::OnClick );
+ aItemSet.Put( aNamesItem );
+
+ css::uno::Reference < css::frame::XFrame > xFrame;
+ if (GetViewShell())
+ xFrame = GetViewShell()->GetViewFrame()->GetFrame().GetFrameInterface();
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractDialog> pMacroDlg(pFact->CreateEventConfigDialog( pWin, aItemSet, xFrame ));
+ if ( pMacroDlg->Execute() != RET_OK )
+ return;
+
+ const SfxItemSet* pOutSet = pMacroDlg->GetOutputItemSet();
+ const SvxMacroItem* pItem = pOutSet->GetItemIfSet( SID_ATTR_MACROITEM, false );
+ if( !pItem )
+ return;
+
+ OUString sMacro;
+ const SvxMacro* pMacro = pItem->GetMacroTable().Get( SvMacroItemId::OnClick );
+ if ( pMacro )
+ sMacro = pMacro->GetMacName();
+
+ if ( pObj->IsGroupObject() )
+ {
+ SdrObjList* pOL = pObj->GetSubList();
+ const size_t nObj = pOL->GetObjCount();
+ for ( size_t index=0; index<nObj; ++index )
+ {
+ pInfo = ScDrawLayer::GetMacroInfo( pOL->GetObj(index), true );
+ pInfo->SetMacro( sMacro );
+ }
+ }
+ else
+ pInfo->SetMacro( sMacro );
+ setModified();
+}
+
+void ScDrawShell::ExecuteLineDlg( const SfxRequest& rReq )
+{
+ ScDrawView* pView = rViewData.GetScDrawView();
+ bool bHasMarked = pView->AreObjectsMarked();
+ const SdrObject* pObj = nullptr;
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+
+ std::shared_ptr<SfxRequest> pRequest = std::make_shared<SfxRequest>(rReq);
+
+ if( rMarkList.GetMarkCount() == 1 )
+ pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ SfxItemSet aNewAttr( pView->GetDefaultAttr() );
+ if( bHasMarked )
+ pView->MergeAttrFromMarked( aNewAttr, false );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ VclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateSvxLineTabDialog( rViewData.GetDialogParent(),
+ &aNewAttr,
+ rViewData.GetDocument().GetDrawLayer(),
+ pObj,
+ bHasMarked));
+
+ pDlg->StartExecuteAsync([=](sal_Int32 nResult){
+ if ( nResult == RET_OK )
+ {
+ if( bHasMarked )
+ pView->SetAttrToMarked( *pDlg->GetOutputItemSet(), false );
+ else
+ pView->SetDefaultAttr( *pDlg->GetOutputItemSet(), false );
+
+ pView->InvalidateAttribs();
+ pRequest->Done();
+ }
+ pDlg->disposeOnce();
+ });
+}
+
+void ScDrawShell::ExecuteAreaDlg( const SfxRequest& rReq )
+{
+ ScDrawView* pView = rViewData.GetScDrawView();
+ bool bHasMarked = pView->AreObjectsMarked();
+
+ std::shared_ptr<SfxRequest> pRequest = std::make_shared<SfxRequest>(rReq);
+
+ SfxItemSet aNewAttr( pView->GetDefaultAttr() );
+ if( bHasMarked )
+ pView->MergeAttrFromMarked( aNewAttr, false );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ weld::Window* pWin = rViewData.GetDialogParent();
+ VclPtr<AbstractSvxAreaTabDialog> pDlg(pFact->CreateSvxAreaTabDialog(
+ pWin, &aNewAttr,
+ rViewData.GetDocument().GetDrawLayer(), true, false));
+
+ pDlg->StartExecuteAsync([=](sal_Int32 nResult){
+ if ( nResult == RET_OK )
+ {
+ if( bHasMarked )
+ pView->SetAttrToMarked( *pDlg->GetOutputItemSet(), false );
+ else
+ pView->SetDefaultAttr( *pDlg->GetOutputItemSet(), false );
+
+ pView->InvalidateAttribs();
+ pRequest->Done();
+ }
+ pDlg->disposeOnce();
+ });
+}
+
+void ScDrawShell::ExecuteTextAttrDlg( SfxRequest& rReq )
+{
+ ScDrawView* pView = rViewData.GetScDrawView();
+ bool bHasMarked = pView->AreObjectsMarked();
+ SfxItemSet aNewAttr ( pView->GetDefaultAttr() );
+
+ if( bHasMarked )
+ pView->MergeAttrFromMarked( aNewAttr, false );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ weld::Window* pWin = rViewData.GetDialogParent();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateTextTabDialog(pWin, &aNewAttr, pView));
+
+ sal_uInt16 nResult = pDlg->Execute();
+
+ if ( RET_OK == nResult )
+ {
+ if ( bHasMarked )
+ pView->SetAttributes( *pDlg->GetOutputItemSet() );
+ else
+ pView->SetDefaultAttr( *pDlg->GetOutputItemSet(), false );
+
+ pView->InvalidateAttribs();
+ rReq.Done();
+ }
+}
+
+void ScDrawShell::ExecuteMeasureDlg( SfxRequest& rReq )
+{
+ ScDrawView* pView = rViewData.GetScDrawView();
+ bool bHasMarked = pView->AreObjectsMarked();
+ SfxItemSet aNewAttr ( pView->GetDefaultAttr() );
+
+ if( bHasMarked )
+ pView->MergeAttrFromMarked( aNewAttr, false );
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ weld::Window* pWin = rViewData.GetDialogParent();
+ ScopedVclPtr<SfxAbstractDialog> pDlg(pFact->CreateSfxDialog(pWin, aNewAttr, pView, RID_SVXPAGE_MEASURE));
+
+ sal_uInt16 nResult = pDlg->Execute();
+
+ if ( RET_OK == nResult )
+ {
+ if ( bHasMarked )
+ pView->SetAttrToMarked( *pDlg->GetOutputItemSet(), false );
+ else
+ pView->SetDefaultAttr( *pDlg->GetOutputItemSet(), false );
+
+ pView->InvalidateAttribs();
+ rReq.Done();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/drawsh2.cxx b/sc/source/ui/drawfunc/drawsh2.cxx
new file mode 100644
index 000000000..806216137
--- /dev/null
+++ b/sc/source/ui/drawfunc/drawsh2.cxx
@@ -0,0 +1,564 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/EmbedMisc.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+
+#include <editeng/eeitem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/xdef.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/ptitem.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/extrusionbar.hxx>
+#include <svx/fontworkbar.hxx>
+#include <svx/sidebar/SelectionChangeHandler.hxx>
+#include <svx/sidebar/SelectionAnalyzer.hxx>
+#include <svx/sidebar/ContextChangeEventMultiplexer.hxx>
+#include <svx/unomid.hxx>
+
+#include <drawsh.hxx>
+#include <drawview.hxx>
+#include <viewdata.hxx>
+#include <sc.hrc>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <drwlayer.hxx>
+#include <drtxtob.hxx>
+#include <gridwin.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/xflgrit.hxx>
+#include <comphelper/lok.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+#include <svx/xflclit.hxx>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <sfx2/ipclient.hxx>
+
+using namespace com::sun::star::drawing;
+using namespace com::sun::star;
+
+
+ScDrawShell::ScDrawShell( ScViewData& rData ) :
+ SfxShell(rData.GetViewShell()),
+ rViewData( rData ),
+ mpSelectionChangeHandler(new svx::sidebar::SelectionChangeHandler(
+ [this] () { return this->GetSidebarContextName(); },
+ GetFrame()->GetFrame().GetController(),
+ vcl::EnumContext::Context::Cell))
+{
+ SetPool( &rViewData.GetScDrawView()->GetModel()->GetItemPool() );
+ SfxUndoManager* pMgr = rViewData.GetSfxDocShell()->GetUndoManager();
+ SetUndoManager( pMgr );
+ if ( !rViewData.GetDocument().IsUndoEnabled() )
+ {
+ pMgr->SetMaxUndoActionCount( 0 );
+ }
+ SetName("Drawing");
+
+ mpSelectionChangeHandler->Connect();
+}
+
+ScDrawShell::~ScDrawShell()
+{
+ mpSelectionChangeHandler->Disconnect();
+}
+
+void ScDrawShell::GetState( SfxItemSet& rSet ) // Conditions / Toggles
+{
+ ScDrawView* pView = rViewData.GetScDrawView();
+ SdrDragMode eMode = pView->GetDragMode();
+
+ rSet.Put( SfxBoolItem( SID_OBJECT_ROTATE, eMode == SdrDragMode::Rotate ) );
+ rSet.Put( SfxBoolItem( SID_OBJECT_MIRROR, eMode == SdrDragMode::Mirror ) );
+ rSet.Put( SfxBoolItem( SID_BEZIER_EDIT, !pView->IsFrameDragSingles() ) );
+
+ sal_uInt16 nFWId = ScGetFontWorkId();
+ SfxViewFrame* pViewFrm = rViewData.GetViewShell()->GetViewFrame();
+ rSet.Put(SfxBoolItem(SID_FONTWORK, pViewFrm->HasChildWindow(nFWId)));
+
+ // Notes always default to Page anchor.
+ bool bDisableAnchor = false;
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if ( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ if( ScDrawLayer::IsNoteCaption( pObj ) )
+ {
+ bDisableAnchor = true;
+ rSet.DisableItem( SID_ANCHOR_PAGE );
+ rSet.DisableItem( SID_ANCHOR_CELL );
+ rSet.DisableItem( SID_ANCHOR_CELL_RESIZE );
+ }
+ }
+
+ if ( bDisableAnchor )
+ return;
+
+ switch( pView->GetAnchorType() )
+ {
+ case SCA_PAGE:
+ rSet.Put( SfxBoolItem( SID_ANCHOR_PAGE, true ) );
+ rSet.Put( SfxBoolItem( SID_ANCHOR_CELL, false ) );
+ rSet.Put( SfxBoolItem( SID_ANCHOR_CELL_RESIZE, false ) );
+ break;
+
+ case SCA_CELL:
+ rSet.Put( SfxBoolItem( SID_ANCHOR_PAGE, false ) );
+ rSet.Put( SfxBoolItem( SID_ANCHOR_CELL, true ) );
+ rSet.Put( SfxBoolItem( SID_ANCHOR_CELL_RESIZE, false ) );
+ break;
+
+ case SCA_CELL_RESIZE:
+ rSet.Put( SfxBoolItem( SID_ANCHOR_PAGE, false ) );
+ rSet.Put( SfxBoolItem( SID_ANCHOR_CELL, false ) );
+ rSet.Put( SfxBoolItem( SID_ANCHOR_CELL_RESIZE, true ) );
+ break;
+
+ default:
+ rSet.Put( SfxBoolItem( SID_ANCHOR_PAGE, false ) );
+ rSet.Put( SfxBoolItem( SID_ANCHOR_CELL, false ) );
+ rSet.Put( SfxBoolItem( SID_ANCHOR_CELL_RESIZE, false ) );
+ break;
+ }
+}
+
+void ScDrawShell::GetDrawFuncState( SfxItemSet& rSet ) // disable functions
+{
+ ScDrawView* pView = rViewData.GetScDrawView();
+
+ // call IsMirrorAllowed first to make sure ForcePossibilities (and thus CheckMarked)
+ // is called before GetMarkCount, so the nMarkCount value is valid for the rest of this method.
+ if (!pView->IsMirrorAllowed(true,true))
+ {
+ rSet.DisableItem( SID_MIRROR_HORIZONTAL );
+ rSet.DisableItem( SID_MIRROR_VERTICAL );
+ rSet.DisableItem( SID_FLIP_HORIZONTAL );
+ rSet.DisableItem( SID_FLIP_VERTICAL );
+ }
+
+
+ if (GetObjectShell()->isContentExtractionLocked())
+ {
+ rSet.DisableItem(SID_COPY);
+ rSet.DisableItem(SID_CUT);
+ }
+
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+
+ if ( nMarkCount <= 1 || !pView->IsGroupPossible() )
+ rSet.DisableItem( SID_GROUP );
+ if ( nMarkCount == 0 || !pView->IsUnGroupPossible() )
+ rSet.DisableItem( SID_UNGROUP );
+ if ( nMarkCount != 1 || !pView->IsGroupEnterPossible() )
+ rSet.DisableItem( SID_ENTER_GROUP );
+ if ( !pView->IsGroupEntered() )
+ rSet.DisableItem( SID_LEAVE_GROUP );
+
+ if ( nMarkCount <= 1 ) // Nothing or only one object selected
+ {
+ // alignment
+ rSet.DisableItem( SID_OBJECT_ALIGN_LEFT ); // no alignment on the side
+ 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_OBJECT_ALIGN );
+
+ // pseudo slots for Format menu
+ rSet.DisableItem( SID_ALIGN_ANY_LEFT );
+ rSet.DisableItem( SID_ALIGN_ANY_HCENTER );
+ rSet.DisableItem( SID_ALIGN_ANY_RIGHT );
+ rSet.DisableItem( SID_ALIGN_ANY_TOP );
+ rSet.DisableItem( SID_ALIGN_ANY_VCENTER );
+ rSet.DisableItem( SID_ALIGN_ANY_BOTTOM );
+ }
+
+ // do not change layer of form controls
+ // #i83729# do not change layer of cell notes (on internal layer)
+ if ( !nMarkCount || pView->HasMarkedControl() || pView->HasMarkedInternal() )
+ {
+ rSet.DisableItem( SID_OBJECT_HEAVEN );
+ rSet.DisableItem( SID_OBJECT_HELL );
+ }
+ else
+ {
+ if(AreAllObjectsOnLayer(SC_LAYER_FRONT,rMarkList))
+ {
+ rSet.DisableItem( SID_OBJECT_HEAVEN );
+ }
+ else if(AreAllObjectsOnLayer(SC_LAYER_BACK,rMarkList))
+ {
+ rSet.DisableItem( SID_OBJECT_HELL );
+ }
+ }
+
+ bool bCanRename = false;
+ if ( nMarkCount > 1 )
+ {
+ // no hyperlink options for a selected group
+ rSet.DisableItem( SID_EDIT_HYPERLINK );
+ rSet.DisableItem( SID_REMOVE_HYPERLINK );
+ rSet.DisableItem( SID_OPEN_HYPERLINK );
+ rSet.DisableItem( SID_COPY_HYPERLINK_LOCATION );
+ // Fit to cell only works with a single graphic
+ rSet.DisableItem( SID_FITCELLSIZE );
+ }
+ else if ( nMarkCount == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ if (pObj->getHyperlink().isEmpty())
+ {
+ rSet.DisableItem( SID_EDIT_HYPERLINK );
+ rSet.DisableItem( SID_OPEN_HYPERLINK );
+ rSet.DisableItem( SID_REMOVE_HYPERLINK );
+ rSet.DisableItem( SID_COPY_HYPERLINK_LOCATION );
+ }
+ SdrLayerID nLayerID = pObj->GetLayer();
+ if ( nLayerID != SC_LAYER_INTERN )
+ bCanRename = true; // #i51351# anything except internal objects can be renamed
+
+ // #91929#; don't show original size entry if not possible
+ SdrObjKind nObjType = pObj->GetObjIdentifier();
+ if ( nObjType == SdrObjKind::OLE2 )
+ {
+ SdrOle2Obj* pOleObj = static_cast<SdrOle2Obj*>(rMarkList.GetMark( 0 )->GetMarkedSdrObj());
+ if (pOleObj->GetObjRef().is() &&
+ (pOleObj->GetObjRef()->getStatus( pOleObj->GetAspect() ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE) )
+ //TODO/LATER: why different slots in Draw and Calc?
+ rSet.DisableItem(SID_ORIGINALSIZE);
+ }
+ else if ( nObjType == SdrObjKind::Caption )
+ {
+ if ( nLayerID == SC_LAYER_INTERN )
+ {
+ // SdrCaptionObj() Notes cannot be cut/copy in isolation from
+ // their cells.
+ rSet.DisableItem( SID_CUT );
+ rSet.DisableItem( SID_COPY );
+ // Notes always default to Page anchor.
+ rSet.DisableItem( SID_ANCHOR_TOGGLE );
+ rSet.DisableItem( SID_ANCHOR_MENU );
+ }
+ }
+
+ // Fit to cell is only available for cell anchored graphics obviously
+ if (pView->GetAnchorType() != SCA_CELL &&
+ pView->GetAnchorType() != SCA_CELL_RESIZE)
+ rSet.DisableItem( SID_FITCELLSIZE );
+
+ // Support advanced DiagramHelper
+ if (!pObj->isDiagram())
+ {
+ rSet.DisableItem( SID_REGENERATE_DIAGRAM );
+ rSet.DisableItem( SID_EDIT_DIAGRAM );
+ }
+ }
+ if ( !bCanRename )
+ {
+ // #i68101#
+ rSet.DisableItem( SID_RENAME_OBJECT );
+ rSet.DisableItem( SID_TITLE_DESCRIPTION_OBJECT );
+ }
+
+ if ( !nMarkCount ) // nothing selected
+ {
+ // Arrangement
+ rSet.DisableItem( SID_FRAME_UP );
+ rSet.DisableItem( SID_FRAME_DOWN );
+ rSet.DisableItem( SID_FRAME_TO_TOP );
+ rSet.DisableItem( SID_FRAME_TO_BOTTOM );
+ // Clipboard / delete
+ rSet.DisableItem( SID_DELETE );
+ rSet.DisableItem( SID_DELETE_CONTENTS );
+ rSet.DisableItem( SID_CUT );
+ rSet.DisableItem( SID_COPY );
+ // other
+ rSet.DisableItem( SID_ANCHOR_TOGGLE );
+ rSet.DisableItem( SID_ANCHOR_MENU );
+ rSet.DisableItem( SID_ORIGINALSIZE );
+ rSet.DisableItem( SID_FITCELLSIZE );
+ rSet.DisableItem( SID_ATTR_TRANSFORM );
+ }
+
+ if ( rSet.GetItemState( SID_ENABLE_HYPHENATION ) != SfxItemState::UNKNOWN )
+ {
+ SfxItemSet aAttrs( pView->GetModel()->GetItemPool() );
+ pView->GetAttributes( aAttrs );
+ if( aAttrs.GetItemState( EE_PARA_HYPHENATE ) >= SfxItemState::DEFAULT )
+ {
+ bool bValue = aAttrs.Get( EE_PARA_HYPHENATE ).GetValue();
+ rSet.Put( SfxBoolItem( SID_ENABLE_HYPHENATION, bValue ) );
+ }
+ }
+
+ svx::ExtrusionBar::getState( pView, rSet );
+ svx::FontworkBar::getState( pView, rSet );
+}
+
+static void setupFillColorForChart(const SfxViewShell* pShell, SfxItemSet& rSet)
+{
+ if (!pShell)
+ return;
+
+ SfxInPlaceClient* pIPClient = pShell->GetIPClient();
+ if (!pIPClient)
+ return;
+
+ const css::uno::Reference<::css::embed::XEmbeddedObject>& xEmbObj = pIPClient->GetObject();
+ if( !xEmbObj.is() )
+ return;
+
+ ::css::uno::Reference<::css::chart2::XChartDocument> xChart( xEmbObj->getComponent(), uno::UNO_QUERY );
+ if( !xChart.is() )
+ return;
+
+ css::uno::Reference<css::beans::XPropertySet> xPropSet = xChart->getPageBackground();
+ if (!xPropSet.is())
+ return;
+
+ css::uno::Reference<css::beans::XPropertySetInfo> xInfo(xPropSet->getPropertySetInfo());
+ if (!xInfo.is())
+ return;
+
+ if (xInfo->hasPropertyByName("FillColor"))
+ {
+ sal_uInt32 nFillColor = 0;
+ xPropSet->getPropertyValue("FillColor") >>= nFillColor;
+
+ XFillColorItem aFillColorItem("", Color(ColorTransparency, nFillColor));
+ rSet.Put(aFillColorItem);
+
+ if (comphelper::LibreOfficeKit::isActive())
+ pShell->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED,
+ (".uno:FillColor=" + std::to_string(nFillColor)).c_str());
+ }
+
+ if (!(comphelper::LibreOfficeKit::isActive() && xInfo->hasPropertyByName("FillGradientName")))
+ return;
+
+ OUString aGradientName;
+ xPropSet->getPropertyValue("FillGradientName") >>= aGradientName;
+
+ ::css::uno::Reference< ::css::frame::XController > xChartController = xChart->getCurrentController();
+ if( !xChartController.is() )
+ return;
+
+ css::uno::Reference<css::lang::XMultiServiceFactory> xFact(xChartController->getModel(), css::uno::UNO_QUERY);
+
+ if (!xFact.is())
+ return;
+
+ css::uno::Reference<css::container::XNameAccess> xNameAccess(
+ xFact->createInstance("com.sun.star.drawing.GradientTable"), css::uno::UNO_QUERY);
+
+ if (xNameAccess.is() && xNameAccess->hasByName(aGradientName))
+ {
+ css::uno::Any aAny = xNameAccess->getByName(aGradientName);
+
+ XFillGradientItem aItem;
+ aItem.SetName(aGradientName);
+ aItem.PutValue(aAny, MID_FILLGRADIENT);
+
+ rSet.Put(aItem);
+ }
+}
+
+// Attributes for Drawing-Objects
+
+void ScDrawShell::GetDrawAttrState( SfxItemSet& rSet )
+{
+ Point aMousePos = rViewData.GetMousePosPixel();
+ vcl::Window* pWindow = rViewData.GetActiveWin();
+ ScDrawView* pDrView = rViewData.GetScDrawView();
+ Point aPos = pWindow->PixelToLogic(aMousePos);
+ bool bHasMarked = pDrView->AreObjectsMarked();
+
+ if( bHasMarked )
+ {
+ SfxAllItemSet aSet(pDrView->GetAttrFromMarked(false));
+ if (const SfxPoolItem* pItem = nullptr;
+ aSet.GetItemState(SDRATTR_TEXTCOLUMNS_NUMBER, false, &pItem) >= SfxItemState::DEFAULT
+ && pItem)
+ {
+ aSet.Put(pItem->CloneSetWhich(SID_ATTR_TEXTCOLUMNS_NUMBER));
+ }
+ if (const SfxPoolItem* pItem = nullptr;
+ aSet.GetItemState(SDRATTR_TEXTCOLUMNS_SPACING, false, &pItem) >= SfxItemState::DEFAULT
+ && pItem)
+ {
+ aSet.Put(pItem->CloneSetWhich(SID_ATTR_TEXTCOLUMNS_SPACING));
+ }
+ rSet.Put(aSet, false);
+ }
+ else
+ {
+ rSet.Put( pDrView->GetDefaultAttr() );
+ }
+
+ SdrPageView* pPV = pDrView->GetSdrPageView();
+ if ( !pPV )
+ return;
+
+ // #i52073# when a sheet with an active OLE object is deleted,
+ // the slot state is queried without an active page view
+
+ // Items for position and size (see ScGridWindow::UpdateStatusPosSize, #108137#)
+
+ // #i34458# The SvxSizeItem in SID_TABLE_CELL is no longer needed by
+ // SvxPosSizeStatusBarControl, it's enough to have it in SID_ATTR_SIZE.
+
+ bool bActionItem = false;
+ if ( pDrView->IsAction() ) // action rectangle
+ {
+ tools::Rectangle aRect;
+ pDrView->TakeActionRect( aRect );
+ if ( !aRect.IsEmpty() )
+ {
+ pPV->LogicToPagePos(aRect);
+ rSet.Put( SfxPointItem( SID_ATTR_POSITION, aRect.TopLeft() ) );
+ Size aSize( aRect.Right() - aRect.Left(), aRect.Bottom() - aRect.Top() );
+ rSet.Put( SvxSizeItem( SID_ATTR_SIZE, aSize ) );
+ bActionItem = true;
+ }
+
+ // Set correct colors for charts in sidebar
+ setupFillColorForChart(pDrView->GetSfxViewShell(), rSet);
+ }
+ if ( bActionItem )
+ return;
+
+ if ( pDrView->AreObjectsMarked() ) // selected objects
+ {
+ tools::Rectangle aRect = pDrView->GetAllMarkedRect();
+ pPV->LogicToPagePos(aRect);
+ rSet.Put( SfxPointItem( SID_ATTR_POSITION, aRect.TopLeft() ) );
+ Size aSize( aRect.Right() - aRect.Left(), aRect.Bottom() - aRect.Top() );
+ rSet.Put( SvxSizeItem( SID_ATTR_SIZE, aSize ) );
+ }
+ else // mouse position
+ {
+ // aPos is initialized above
+ pPV->LogicToPagePos(aPos);
+ rSet.Put( SfxPointItem( SID_ATTR_POSITION, aPos ) );
+ rSet.Put( SvxSizeItem( SID_ATTR_SIZE, Size( 0, 0 ) ) );
+ }
+}
+
+void ScDrawShell::GetAttrFuncState(SfxItemSet &rSet)
+{
+ // Disable dialogs for Draw-attributes if necessary
+
+ ScDrawView* pDrView = rViewData.GetScDrawView();
+ SfxItemSet aViewSet = pDrView->GetAttrFromMarked(false);
+ const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+ bool bShowArea = true, bShowMeasure = true;
+
+ for ( size_t i = 0; i < nMarkCount && i < 50; ++i )
+ {
+ SdrObject* pObj = rMarkList.GetMark( i )->GetMarkedSdrObj();
+ SdrObjKind nObjType = pObj->GetObjIdentifier();
+
+ if ( nObjType != SdrObjKind::Measure )
+ bShowMeasure = false;
+
+ // If marked object is 2D, disable format area command.
+ if ( nObjType == SdrObjKind::PolyLine ||
+ nObjType == SdrObjKind::Line ||
+ nObjType == SdrObjKind::PathLine ||
+ nObjType == SdrObjKind::FreehandLine ||
+ nObjType == SdrObjKind::Edge ||
+ nObjType == SdrObjKind::CircleArc ||
+ bShowMeasure )
+ bShowArea = false;
+
+ if ( !bShowArea && !bShowMeasure )
+ break;
+ }
+
+ if ( !bShowArea )
+ rSet.DisableItem( SID_ATTRIBUTES_AREA );
+
+ if ( !bShowMeasure )
+ rSet.DisableItem( SID_MEASURE_DLG );
+
+ if ( aViewSet.GetItemState( XATTR_LINESTYLE ) == SfxItemState::DEFAULT )
+ {
+ rSet.DisableItem( SID_ATTRIBUTES_LINE );
+ rSet.DisableItem( SID_ATTR_LINEEND_STYLE ); // Tbx-Controller
+ }
+
+ if ( aViewSet.GetItemState( XATTR_FILLSTYLE ) == SfxItemState::DEFAULT )
+ rSet.DisableItem( SID_ATTRIBUTES_AREA );
+}
+
+bool ScDrawShell::AreAllObjectsOnLayer(SdrLayerID nLayerNo,const SdrMarkList& rMark)
+{
+ bool bResult=true;
+ const size_t nCount = rMark.GetMarkCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ SdrObject* pObj = rMark.GetMark(i)->GetMarkedSdrObj();
+ if ( dynamic_cast<const SdrUnoObj*>( pObj) == nullptr )
+ {
+ if(nLayerNo!=pObj->GetLayer())
+ {
+ bResult=false;
+ break;
+ }
+ }
+ }
+ return bResult;
+}
+
+void ScDrawShell::GetDrawAttrStateForIFBX( SfxItemSet& rSet )
+{
+ ScDrawView* pView = rViewData.GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+
+ if( rMarkList.GetMark(0) != nullptr )
+ {
+ SfxItemSet aNewAttr(pView->GetGeoAttrFromMarked());
+ rSet.Put(aNewAttr, false);
+ }
+}
+
+void ScDrawShell::Activate (const bool)
+{
+ ContextChangeEventMultiplexer::NotifyContextChange(
+ GetFrame()->GetFrame().GetController(),
+ vcl::EnumContext::GetContextEnum(
+ GetSidebarContextName()));
+}
+
+const OUString & ScDrawShell::GetSidebarContextName()
+{
+ return vcl::EnumContext::GetContextName(
+ svx::sidebar::SelectionAnalyzer::GetContextForSelection_SC(
+ GetDrawView()->GetMarkedObjectList()));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/drawsh4.cxx b/sc/source/ui/drawfunc/drawsh4.cxx
new file mode 100644
index 000000000..fdb0efe91
--- /dev/null
+++ b/sc/source/ui/drawfunc/drawsh4.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 <svx/svdotext.hxx>
+#include <svx/xdef.hxx>
+#include <svx/svdoashp.hxx>
+#include <drawsh.hxx>
+#include <drawview.hxx>
+#include <viewdata.hxx>
+
+void ScDrawShell::GetFormTextState(SfxItemSet& rSet)
+{
+ const SdrObject* pObj = nullptr;
+ ScDrawView* pDrView = rViewData.GetScDrawView();
+ const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
+
+ 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)
+ {
+ 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 aViewAttr(pDrView->GetModel()->GetItemPool());
+ pDrView->GetAttributes(aViewAttr);
+ rSet.Set(aViewAttr);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/drawsh5.cxx b/sc/source/ui/drawfunc/drawsh5.cxx
new file mode 100644
index 000000000..b95f77f93
--- /dev/null
+++ b/sc/source/ui/drawfunc/drawsh5.cxx
@@ -0,0 +1,721 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <sfx2/viewfrm.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/bindings.hxx>
+#include <tools/urlobj.hxx>
+#include <cliputil.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/hlnkitem.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/extrusionbar.hxx>
+#include <svx/fontworkbar.hxx>
+#include <svx/svdogrp.hxx>
+#include <sfx2/docfile.hxx>
+#include <osl/diagnose.h>
+#include <svx/diagram/IDiagramHelper.hxx>
+
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+
+#include <drawsh.hxx>
+#include <drawview.hxx>
+#include <viewdata.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <undotab.hxx>
+#include <drwlayer.hxx>
+#include <drtxtob.hxx>
+#include <memory>
+
+#include <sc.hrc>
+
+using namespace com::sun::star;
+
+void ScDrawShell::GetHLinkState( SfxItemSet& rSet ) // Hyperlink
+{
+ ScDrawView* pView = rViewData.GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+
+ // Hyperlink
+
+ SvxHyperlinkItem aHLinkItem;
+
+ if ( rMarkList.GetMarkCount() == 1 ) // URL-Button marked ?
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if ( pObj && !pObj->getHyperlink().isEmpty() )
+ {
+ aHLinkItem.SetURL( pObj->getHyperlink() );
+ aHLinkItem.SetInsertMode(HLINK_FIELD);
+ }
+ SdrUnoObj* pUnoCtrl = dynamic_cast<SdrUnoObj*>( pObj );
+ if (pUnoCtrl && SdrInventor::FmForm == pUnoCtrl->GetObjInventor())
+ {
+ const uno::Reference<awt::XControlModel>& xControlModel = pUnoCtrl->GetUnoControlModel();
+ OSL_ENSURE( xControlModel.is(), "UNO-Control without model" );
+ if( !xControlModel.is() )
+ return;
+
+ uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySetInfo > xInfo = xPropSet->getPropertySetInfo();
+
+ OUString sPropButtonType( "ButtonType" );
+
+ if(xInfo->hasPropertyByName( sPropButtonType ))
+ {
+ uno::Any aAny = xPropSet->getPropertyValue( sPropButtonType );
+ form::FormButtonType eTmp;
+ if ( (aAny >>= eTmp) && eTmp == form::FormButtonType_URL )
+ {
+ OUString sTmp;
+ // Label
+ OUString sPropLabel( "Label" );
+ if(xInfo->hasPropertyByName( sPropLabel ))
+ {
+ aAny = xPropSet->getPropertyValue( sPropLabel );
+ if ( (aAny >>= sTmp) && !sTmp.isEmpty() )
+ {
+ aHLinkItem.SetName(sTmp);
+ }
+ }
+ // URL
+ OUString sPropTargetURL( "TargetURL" );
+ if(xInfo->hasPropertyByName( sPropTargetURL ))
+ {
+ aAny = xPropSet->getPropertyValue( sPropTargetURL );
+ if ( (aAny >>= sTmp) && !sTmp.isEmpty() )
+ {
+ aHLinkItem.SetURL(sTmp);
+ }
+ }
+ // Target
+ OUString sPropTargetFrame( "TargetFrame" );
+ if(xInfo->hasPropertyByName( sPropTargetFrame ))
+ {
+ aAny = xPropSet->getPropertyValue( sPropTargetFrame );
+ if ( (aAny >>= sTmp) && !sTmp.isEmpty() )
+ {
+ aHLinkItem.SetTargetFrame(sTmp);
+ }
+ }
+ aHLinkItem.SetInsertMode(HLINK_BUTTON);
+ }
+ }
+ }
+ }
+
+ rSet.Put(aHLinkItem);
+}
+
+void ScDrawShell::ExecuteHLink( const SfxRequest& rReq )
+{
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch ( nSlot )
+ {
+ case SID_HYPERLINK_SETLINK:
+ if( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs->GetItemState( SID_HYPERLINK_SETLINK, true, &pItem ) == SfxItemState::SET )
+ {
+ const SvxHyperlinkItem* pHyper = static_cast<const SvxHyperlinkItem*>(pItem);
+ const OUString& rName = pHyper->GetName();
+ const OUString& rURL = pHyper->GetURL();
+ const OUString& rTarget = pHyper->GetTargetFrame();
+ SvxLinkInsertMode eMode = pHyper->GetInsertMode();
+
+ bool bDone = false;
+ if ( eMode == HLINK_FIELD || eMode == HLINK_BUTTON )
+ {
+ ScDrawView* pView = rViewData.GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if ( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ SdrUnoObj* pUnoCtrl = dynamic_cast<SdrUnoObj*>( pObj );
+ if (pUnoCtrl && SdrInventor::FmForm == pUnoCtrl->GetObjInventor())
+ {
+ const uno::Reference<awt::XControlModel>& xControlModel =
+ pUnoCtrl->GetUnoControlModel();
+ OSL_ENSURE( xControlModel.is(), "UNO-Control without model" );
+ if( !xControlModel.is() )
+ return;
+
+ uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY );
+ uno::Reference< beans::XPropertySetInfo > xInfo = xPropSet->getPropertySetInfo();
+
+ OUString sPropTargetURL( "TargetURL" );
+
+ // Is it possible to set a URL in the object?
+ if (xInfo->hasPropertyByName( sPropTargetURL ))
+ {
+
+ OUString sPropButtonType( "ButtonType");
+ OUString sPropTargetFrame( "TargetFrame" );
+ OUString sPropLabel( "Label" );
+
+ if ( xInfo->hasPropertyByName( sPropLabel ) )
+ {
+ xPropSet->setPropertyValue( sPropLabel, uno::Any(rName) );
+ }
+
+ OUString aTmp = INetURLObject::GetAbsURL( rViewData.GetDocShell()->GetMedium()->GetBaseURL(), rURL );
+ xPropSet->setPropertyValue( sPropTargetURL, uno::Any(aTmp) );
+
+ if( !rTarget.isEmpty() && xInfo->hasPropertyByName( sPropTargetFrame ) )
+ {
+ xPropSet->setPropertyValue( sPropTargetFrame, uno::Any(rTarget) );
+ }
+
+ if ( xInfo->hasPropertyByName( sPropButtonType ) )
+ {
+ xPropSet->setPropertyValue( sPropButtonType, uno::Any(form::FormButtonType_URL) );
+ }
+
+ //! Undo ???
+ rViewData.GetDocShell()->SetDocumentModified();
+ bDone = true;
+ }
+ }
+ else
+ {
+ pObj->setHyperlink(rURL);
+ setModified();
+ bDone = true;
+ }
+ }
+ }
+
+ if (!bDone)
+ rViewData.GetViewShell()->
+ InsertURL( rName, rURL, rTarget, static_cast<sal_uInt16>(eMode) );
+
+ // If "text" is received by InsertURL of ViewShell, then the DrawShell is turned off !!!
+ }
+ }
+ break;
+ default:
+ OSL_FAIL("wrong slot");
+ }
+}
+
+// Functions on Drawing-Objects
+
+void ScDrawShell::ExecDrawFunc( SfxRequest& rReq )
+{
+ SfxBindings& rBindings = rViewData.GetBindings();
+ ScTabView* pTabView = rViewData.GetView();
+ ScDrawView* pView = pTabView->GetScDrawView();
+ sal_uInt16 nSlotId = rReq.GetSlot();
+
+ switch (nSlotId)
+ {
+ case SID_OBJECT_HEAVEN:
+ pView->SetMarkedToLayer( SC_LAYER_FRONT );
+ rBindings.Invalidate(SID_OBJECT_HEAVEN);
+ rBindings.Invalidate(SID_OBJECT_HELL);
+ break;
+ case SID_OBJECT_HELL:
+ pView->SetMarkedToLayer( SC_LAYER_BACK );
+ rBindings.Invalidate(SID_OBJECT_HEAVEN);
+ rBindings.Invalidate(SID_OBJECT_HELL);
+ // leave draw shell if nothing selected (layer may be locked)
+ rViewData.GetViewShell()->UpdateDrawShell();
+ break;
+
+ case SID_FRAME_TO_TOP:
+ pView->PutMarkedToTop();
+ break;
+ case SID_FRAME_TO_BOTTOM:
+ pView->PutMarkedToBtm();
+ break;
+ case SID_FRAME_UP:
+ pView->MovMarkedToTop();
+ break;
+ case SID_FRAME_DOWN:
+ pView->MovMarkedToBtm();
+ break;
+
+ case SID_GROUP:
+ pView->GroupMarked();
+ break;
+ case SID_UNGROUP:
+ pView->UnGroupMarked();
+ break;
+ case SID_ENTER_GROUP:
+ pView->EnterMarkedGroup();
+ break;
+ case SID_LEAVE_GROUP:
+ pView->LeaveOneGroup();
+ break;
+
+ case SID_REGENERATE_DIAGRAM:
+ case SID_EDIT_DIAGRAM:
+ {
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+
+ if (1 == rMarkList.GetMarkCount())
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ // Support advanced DiagramHelper
+ if(nullptr != pObj && pObj->isDiagram())
+ {
+ if(SID_REGENERATE_DIAGRAM == nSlotId)
+ {
+ pView->UnmarkAll();
+ pObj->getDiagramHelper()->reLayout(*static_cast<SdrObjGroup*>(pObj));
+ pView->MarkObj(pObj, pView->GetSdrPageView());
+ }
+ else // SID_EDIT_DIAGRAM
+ {
+ VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
+ vcl::Window* pWin = rViewData.GetActiveWin();
+ ScopedVclPtr<VclAbstractDialog> pDlg = pFact->CreateDiagramDialog(
+ pWin ? pWin->GetFrameWeld() : nullptr,
+ *static_cast<SdrObjGroup*>(pObj));
+ pDlg->Execute();
+ }
+ }
+ }
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_MIRROR_HORIZONTAL:
+ case SID_FLIP_HORIZONTAL:
+ pView->MirrorAllMarkedHorizontal();
+ rBindings.Invalidate( SID_ATTR_TRANSFORM_ANGLE );
+ break;
+ case SID_MIRROR_VERTICAL:
+ case SID_FLIP_VERTICAL:
+ pView->MirrorAllMarkedVertical();
+ rBindings.Invalidate( SID_ATTR_TRANSFORM_ANGLE );
+ break;
+
+ case SID_OBJECT_ALIGN_LEFT:
+ case SID_ALIGN_ANY_LEFT:
+ if (pView->IsAlignPossible())
+ pView->AlignMarkedObjects(SdrHorAlign::Left, SdrVertAlign::NONE);
+ break;
+ case SID_OBJECT_ALIGN_CENTER:
+ case SID_ALIGN_ANY_HCENTER:
+ if (pView->IsAlignPossible())
+ pView->AlignMarkedObjects(SdrHorAlign::Center, SdrVertAlign::NONE);
+ break;
+ case SID_OBJECT_ALIGN_RIGHT:
+ case SID_ALIGN_ANY_RIGHT:
+ if (pView->IsAlignPossible())
+ pView->AlignMarkedObjects(SdrHorAlign::Right, SdrVertAlign::NONE);
+ break;
+ case SID_OBJECT_ALIGN_UP:
+ case SID_ALIGN_ANY_TOP:
+ if (pView->IsAlignPossible())
+ pView->AlignMarkedObjects(SdrHorAlign::NONE, SdrVertAlign::Top);
+ break;
+ case SID_OBJECT_ALIGN_MIDDLE:
+ case SID_ALIGN_ANY_VCENTER:
+ if (pView->IsAlignPossible())
+ pView->AlignMarkedObjects(SdrHorAlign::NONE, SdrVertAlign::Center);
+ break;
+ case SID_OBJECT_ALIGN_DOWN:
+ case SID_ALIGN_ANY_BOTTOM:
+ if (pView->IsAlignPossible())
+ pView->AlignMarkedObjects(SdrHorAlign::NONE, SdrVertAlign::Bottom);
+ break;
+
+ case SID_DELETE:
+ case SID_DELETE_CONTENTS:
+ pView->DeleteMarked();
+ rViewData.GetViewShell()->UpdateDrawShell();
+ break;
+
+ case SID_CUT:
+ pView->DoCut();
+ rViewData.GetViewShell()->UpdateDrawShell();
+ break;
+
+ case SID_COPY:
+ pView->DoCopy();
+ break;
+
+ case SID_PASTE:
+ ScClipUtil::PasteFromClipboard(GetViewData(), GetViewData().GetViewShell(), true);
+ break;
+
+ case SID_SELECTALL:
+ pView->MarkAll();
+ break;
+
+ case SID_ANCHOR_PAGE:
+ pView->SetPageAnchored();
+ rBindings.Invalidate( SID_ANCHOR_PAGE );
+ rBindings.Invalidate( SID_ANCHOR_CELL );
+ rBindings.Invalidate( SID_ANCHOR_CELL_RESIZE );
+ break;
+
+ case SID_ANCHOR_CELL:
+ pView->SetCellAnchored(false);
+ rBindings.Invalidate( SID_ANCHOR_PAGE );
+ rBindings.Invalidate( SID_ANCHOR_CELL );
+ rBindings.Invalidate( SID_ANCHOR_CELL_RESIZE );
+ break;
+
+ case SID_ANCHOR_CELL_RESIZE:
+ pView->SetCellAnchored(true);
+ rBindings.Invalidate( SID_ANCHOR_PAGE );
+ rBindings.Invalidate( SID_ANCHOR_CELL );
+ rBindings.Invalidate( SID_ANCHOR_CELL_RESIZE );
+ break;
+
+ case SID_ANCHOR_TOGGLE:
+ {
+ switch( pView->GetAnchorType() )
+ {
+ case SCA_CELL:
+ case SCA_CELL_RESIZE:
+ pView->SetPageAnchored();
+ break;
+ default:
+ pView->SetCellAnchored(false);
+ break;
+ }
+ }
+ rBindings.Invalidate( SID_ANCHOR_PAGE );
+ rBindings.Invalidate( SID_ANCHOR_CELL );
+ rBindings.Invalidate( SID_ANCHOR_CELL_RESIZE );
+ break;
+
+ case SID_OBJECT_ROTATE:
+ {
+ SdrDragMode eMode;
+ if (pView->GetDragMode() == SdrDragMode::Rotate)
+ eMode = SdrDragMode::Move;
+ else
+ eMode = SdrDragMode::Rotate;
+ pView->SetDragMode( eMode );
+ rBindings.Invalidate( SID_OBJECT_ROTATE );
+ rBindings.Invalidate( SID_OBJECT_MIRROR );
+ if (eMode == SdrDragMode::Rotate && !pView->IsFrameDragSingles())
+ {
+ pView->SetFrameDragSingles();
+ rBindings.Invalidate( SID_BEZIER_EDIT );
+ }
+ }
+ break;
+ case SID_OBJECT_MIRROR:
+ {
+ SdrDragMode eMode;
+ if (pView->GetDragMode() == SdrDragMode::Mirror)
+ eMode = SdrDragMode::Move;
+ else
+ eMode = SdrDragMode::Mirror;
+ pView->SetDragMode( eMode );
+ rBindings.Invalidate( SID_OBJECT_ROTATE );
+ rBindings.Invalidate( SID_OBJECT_MIRROR );
+ if (eMode == SdrDragMode::Mirror && !pView->IsFrameDragSingles())
+ {
+ pView->SetFrameDragSingles();
+ rBindings.Invalidate( SID_BEZIER_EDIT );
+ }
+ }
+ break;
+ case SID_BEZIER_EDIT:
+ {
+ bool bOld = pView->IsFrameDragSingles();
+ pView->SetFrameDragSingles( !bOld );
+ rBindings.Invalidate( SID_BEZIER_EDIT );
+ if (bOld && pView->GetDragMode() != SdrDragMode::Move)
+ {
+ pView->SetDragMode( SdrDragMode::Move );
+ rBindings.Invalidate( SID_OBJECT_ROTATE );
+ rBindings.Invalidate( SID_OBJECT_MIRROR );
+ }
+ }
+ break;
+
+ case SID_FONTWORK:
+ {
+ sal_uInt16 nId = ScGetFontWorkId();
+ SfxViewFrame* pViewFrm = rViewData.GetViewShell()->GetViewFrame();
+
+ if ( rReq.GetArgs() )
+ pViewFrm->SetChildWindow( nId,
+ static_cast<const SfxBoolItem&>(
+ (rReq.GetArgs()->Get(SID_FONTWORK))).
+ GetValue() );
+ else
+ pViewFrm->ToggleChildWindow( nId );
+
+ rBindings.Invalidate( SID_FONTWORK );
+ rReq.Done();
+ }
+ break;
+
+ case SID_ORIGINALSIZE:
+ pView->SetMarkedOriginalSize();
+ break;
+
+ case SID_FITCELLSIZE:
+ pView->FitToCellSize();
+ break;
+
+ case SID_ENABLE_HYPHENATION:
+ {
+ const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(SID_ENABLE_HYPHENATION);
+ if( pItem )
+ {
+ SfxItemSetFixed<EE_PARA_HYPHENATE, EE_PARA_HYPHENATE> aSet( GetPool() );
+ bool bValue = pItem->GetValue();
+ aSet.Put( SfxBoolItem( EE_PARA_HYPHENATE, bValue ) );
+ pView->SetAttributes( aSet );
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_RENAME_OBJECT:
+ {
+ if(1 == pView->GetMarkedObjectCount())
+ {
+ // #i68101#
+ SdrObject* pSelected = pView->GetMarkedObjectByIndex(0);
+ OSL_ENSURE(pSelected, "ScDrawShell::ExecDrawFunc: nMarkCount, but no object (!)");
+
+ if(SC_LAYER_INTERN != pSelected->GetLayer())
+ {
+ OUString aName = pSelected->GetName();
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ vcl::Window* pWin = rViewData.GetActiveWin();
+ ScopedVclPtr<AbstractSvxObjectNameDialog> pDlg(pFact->CreateSvxObjectNameDialog(pWin ? pWin->GetFrameWeld() : nullptr, aName));
+
+ pDlg->SetCheckNameHdl(LINK(this, ScDrawShell, NameObjectHdl));
+
+ if(RET_OK == pDlg->Execute())
+ {
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ pDlg->GetName(aName);
+
+ if (aName != pSelected->GetName())
+ {
+ // handle name change
+ const SdrObjKind nObjType(pSelected->GetObjIdentifier());
+
+ if (SdrObjKind::Graphic == nObjType && aName.isEmpty())
+ {
+ // graphics objects must have names
+ // (all graphics are supposed to be in the navigator)
+ ScDrawLayer* pModel = rViewData.GetDocument().GetDrawLayer();
+
+ if(pModel)
+ {
+ aName = pModel->GetNewGraphicName();
+ }
+ }
+
+ // An undo action for renaming is missing in svdraw (99363).
+ // For OLE objects (which can be identified using the persist name),
+ // ScUndoRenameObject can be used until there is a common action for all objects.
+ if(SdrObjKind::OLE2 == nObjType)
+ {
+ const OUString aPersistName = static_cast<SdrOle2Obj*>(pSelected)->GetPersistName();
+
+ if(!aPersistName.isEmpty())
+ {
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRenameObject>(pDocSh, aPersistName, pSelected->GetName(), aName));
+ }
+ }
+
+ // set new name
+ pSelected->SetName(aName);
+ }
+
+ // ChartListenerCollectionNeedsUpdate is needed for Navigator update
+ pDocSh->GetDocument().SetChartListenerCollectionNeedsUpdate( true );
+ pDocSh->SetDrawModified();
+ }
+ }
+ }
+ break;
+ }
+
+ // #i68101#
+ case SID_TITLE_DESCRIPTION_OBJECT:
+ {
+ if(1 == pView->GetMarkedObjectCount())
+ {
+ SdrObject* pSelected = pView->GetMarkedObjectByIndex(0);
+ OSL_ENSURE(pSelected, "ScDrawShell::ExecDrawFunc: nMarkCount, but no object (!)");
+
+ if(SC_LAYER_INTERN != pSelected->GetLayer())
+ {
+ OUString aTitle(pSelected->GetTitle());
+ OUString aDescription(pSelected->GetDescription());
+
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ vcl::Window* pWin = rViewData.GetActiveWin();
+ ScopedVclPtr<AbstractSvxObjectTitleDescDialog> pDlg(pFact->CreateSvxObjectTitleDescDialog(
+ pWin ? pWin->GetFrameWeld() : nullptr, aTitle, aDescription));
+
+ if(RET_OK == pDlg->Execute())
+ {
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+
+ // handle Title and Description
+ pDlg->GetTitle(aTitle);
+ pDlg->GetDescription(aDescription);
+ pSelected->SetTitle(aTitle);
+ pSelected->SetDescription(aDescription);
+
+ // ChartListenerCollectionNeedsUpdate is needed for Navigator update
+ pDocSh->GetDocument().SetChartListenerCollectionNeedsUpdate( true );
+ pDocSh->SetDrawModified();
+ }
+ }
+ }
+ 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( pView, rReq, rBindings );
+ 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_CHARACTER_SPACING_FLOATER:
+ case SID_FONTWORK_ALIGNMENT_FLOATER:
+ case SID_FONTWORK_CHARACTER_SPACING_DIALOG:
+ svx::FontworkBar::execute( *pView, rReq, rBindings );
+ rReq.Ignore ();
+ break;
+
+ default:
+ break;
+ }
+}
+
+IMPL_LINK( ScDrawShell, NameObjectHdl, AbstractSvxObjectNameDialog&, rDialog, bool )
+{
+ OUString aName;
+ rDialog.GetName( aName );
+
+ ScDrawLayer* pModel = rViewData.GetDocument().GetDrawLayer();
+ if ( !aName.isEmpty() && pModel )
+ {
+ SCTAB nDummyTab;
+ if ( pModel->GetNamedObject( aName, SdrObjKind::NONE, nDummyTab ) )
+ {
+ // existing object found -> name invalid
+ return false;
+ }
+ }
+
+ return true; // name is valid
+}
+
+void ScDrawShell::ExecFormText(const SfxRequest& rReq)
+{
+ ScDrawView* pDrView = rViewData.GetScDrawView();
+ const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
+
+ if ( rMarkList.GetMarkCount() == 1 && rReq.GetArgs() )
+ {
+ const SfxItemSet& rSet = *rReq.GetArgs();
+
+ if ( pDrView->IsTextEdit() )
+ pDrView->ScEndTextEdit();
+
+ pDrView->SetAttributes(rSet);
+ }
+}
+
+void ScDrawShell::ExecFormatPaintbrush( const SfxRequest& rReq )
+{
+ ScViewFunc* pView = rViewData.GetView();
+ if ( pView->HasPaintBrush() )
+ {
+ // cancel paintbrush mode
+ pView->ResetBrushDocument();
+ }
+ else
+ {
+ bool bLock = false;
+ const SfxItemSet *pArgs = rReq.GetArgs();
+ if( pArgs && pArgs->Count() >= 1 )
+ bLock = pArgs->Get(SID_FORMATPAINTBRUSH).GetValue();
+
+ ScDrawView* pDrawView = rViewData.GetScDrawView();
+ if ( pDrawView && pDrawView->AreObjectsMarked() )
+ {
+ std::unique_ptr<SfxItemSet> pItemSet(new SfxItemSet( pDrawView->GetAttrFromMarked(true/*bOnlyHardAttr*/) ));
+ pView->SetDrawBrushSet( std::move(pItemSet), bLock );
+ }
+ }
+}
+
+void ScDrawShell::StateFormatPaintbrush( SfxItemSet& rSet )
+{
+ ScDrawView* pDrawView = rViewData.GetScDrawView();
+ bool bSelection = pDrawView && pDrawView->AreObjectsMarked();
+ bool bHasPaintBrush = rViewData.GetView()->HasPaintBrush();
+
+ if ( !bHasPaintBrush && !bSelection )
+ rSet.DisableItem( SID_FORMATPAINTBRUSH );
+ else
+ rSet.Put( SfxBoolItem( SID_FORMATPAINTBRUSH, bHasPaintBrush ) );
+}
+
+ScDrawView* ScDrawShell::GetDrawView()
+{
+ return rViewData.GetView()->GetScDrawView();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/drformsh.cxx b/sc/source/ui/drawfunc/drformsh.cxx
new file mode 100644
index 000000000..b91e08646
--- /dev/null
+++ b/sc/source/ui/drawfunc/drformsh.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 <sfx2/objface.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/toolbarids.hxx>
+#include <sfx2/shell.hxx>
+
+#include <drawsh.hxx>
+#include <drformsh.hxx>
+#include <vcl/EnumContext.hxx>
+
+#define ShellClass_ScDrawFormShell
+#include <scslots.hxx>
+
+SFX_IMPL_INTERFACE(ScDrawFormShell, ScDrawShell)
+
+void ScDrawFormShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT,
+ SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server,
+ ToolbarId::Objectbar_Format);
+
+ GetStaticInterface()->RegisterPopupMenu("form");
+}
+
+
+ScDrawFormShell::ScDrawFormShell(ScViewData& rData) :
+ ScDrawShell(rData)
+{
+ SetName("DrawForm");
+ SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Form));
+}
+
+ScDrawFormShell::~ScDrawFormShell()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/drtxtob.cxx b/sc/source/ui/drawfunc/drtxtob.cxx
new file mode 100644
index 000000000..12968c9d2
--- /dev/null
+++ b/sc/source/ui/drawfunc/drtxtob.cxx
@@ -0,0 +1,1238 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/string.hxx>
+#include <scitems.hxx>
+
+#include <i18nutil/transliteration.hxx>
+#include <editeng/adjustitem.hxx>
+#include <svx/clipfmtitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/flstitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/lspcitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/urlfieldhelper.hxx>
+#include <svx/hlnkitem.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/sdooitm.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/writingmodeitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svtools/cliplistener.hxx>
+#include <vcl/transfer.hxx>
+#include <svl/stritem.hxx>
+#include <svl/whiter.hxx>
+#include <svl/languageoptions.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <vcl/EnumContext.hxx>
+#include <vcl/unohelp2.hxx>
+
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <scmod.hxx>
+#include <drtxtob.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <drawview.hxx>
+#include <viewutil.hxx>
+#include <tabvwsh.hxx>
+#include <gridwin.hxx>
+
+#define ShellClass_ScDrawTextObjectBar
+#include <scslots.hxx>
+
+using namespace ::com::sun::star;
+
+SFX_IMPL_INTERFACE(ScDrawTextObjectBar, SfxShell)
+
+void ScDrawTextObjectBar::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT,
+ SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server,
+ ToolbarId::Text_Toolbox_Sc);
+
+ GetStaticInterface()->RegisterPopupMenu("drawtext");
+
+ GetStaticInterface()->RegisterChildWindow(ScGetFontWorkId());
+}
+
+
+// disable not wanted accelerators
+
+void ScDrawTextObjectBar::StateDisableItems( SfxItemSet &rSet )
+{
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ while (nWhich)
+ {
+ rSet.DisableItem( nWhich );
+ nWhich = aIter.NextWhich();
+ }
+}
+
+ScDrawTextObjectBar::ScDrawTextObjectBar(ScViewData& rData) :
+ SfxShell(rData.GetViewShell()),
+ mrViewData(rData),
+ bPastePossible(false)
+{
+ SetPool( mrViewData.GetScDrawView()->GetDefaultAttr().GetPool() );
+
+ // At the switching-over the UndoManager is changed to edit mode
+ SfxUndoManager* pMgr = mrViewData.GetSfxDocShell()->GetUndoManager();
+ SetUndoManager( pMgr );
+ if ( !mrViewData.GetDocument().IsUndoEnabled() )
+ {
+ pMgr->SetMaxUndoActionCount( 0 );
+ }
+
+ SetName("DrawText");
+ SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::DrawText));
+}
+
+ScDrawTextObjectBar::~ScDrawTextObjectBar()
+{
+ if ( mxClipEvtLstnr.is() )
+ {
+ mxClipEvtLstnr->RemoveListener( mrViewData.GetActiveWin() );
+
+ // The listener may just now be waiting for the SolarMutex and call the link
+ // afterwards, in spite of RemoveListener. So the link has to be reset, too.
+ mxClipEvtLstnr->ClearCallbackLink();
+ }
+}
+
+// Functions
+
+void ScDrawTextObjectBar::Execute( SfxRequest &rReq )
+{
+ ScDrawView* pView = mrViewData.GetScDrawView();
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+ Outliner* pOutliner = pView->GetTextEditOutliner();
+
+ if (!pOutView || !pOutliner)
+ {
+ ExecuteGlobal( rReq ); // on whole objects
+ return;
+ }
+
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch ( nSlot )
+ {
+ case SID_COPY:
+ pOutView->Copy();
+ break;
+
+ case SID_CUT:
+ pOutView->Cut();
+ break;
+
+ case SID_PASTE:
+ pOutView->PasteSpecial();
+ break;
+
+ case SID_CLIPBOARD_FORMAT_ITEMS:
+ {
+ SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
+ if (auto pIntItem = dynamic_cast<const SfxUInt32Item*>( pItem))
+ nFormat = static_cast<SotClipboardFormatId>(pIntItem->GetValue());
+
+ if ( nFormat != SotClipboardFormatId::NONE )
+ {
+ if (nFormat == SotClipboardFormatId::STRING)
+ pOutView->Paste();
+ else
+ pOutView->PasteSpecial();
+ }
+ }
+ break;
+
+ case SID_PASTE_SPECIAL:
+ ExecutePasteContents( rReq );
+ break;
+
+ case SID_PASTE_UNFORMATTED:
+ pOutView->Paste();
+ break;
+
+ case SID_SELECTALL:
+ {
+ sal_Int32 nCount = pOutliner->GetParagraphCount();
+ ESelection aSel( 0,0,nCount,0 );
+ pOutView->SetSelection( aSel );
+ }
+ break;
+
+ case SID_CHARMAP:
+ {
+ const SvxFontItem& rItem = pOutView->GetAttribs().Get(EE_CHAR_FONTINFO);
+
+ OUString aString;
+ std::shared_ptr<SvxFontItem> aNewItem(std::make_shared<SvxFontItem>(EE_CHAR_FONTINFO));
+
+ const SfxItemSet *pArgs = rReq.GetArgs();
+ const SfxPoolItem* pItem = nullptr;
+ if( pArgs )
+ pArgs->GetItemState(SID_CHARMAP, false, &pItem);
+
+ if ( pItem )
+ {
+ aString = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ const SfxStringItem* pFontItem = pArgs->GetItemIfSet( SID_ATTR_SPECIALCHAR, false);
+ if ( pFontItem )
+ {
+ const OUString& aFontName(pFontItem->GetValue());
+ vcl::Font aFont(aFontName, Size(1,1)); // Size only because of CTOR
+ aNewItem = std::make_shared<SvxFontItem>(
+ aFont.GetFamilyType(), aFont.GetFamilyName(),
+ aFont.GetStyleName(), aFont.GetPitch(),
+ aFont.GetCharSet(), ATTR_FONT);
+ }
+ else
+ {
+ aNewItem.reset(rItem.Clone());
+ }
+ }
+ else
+ ScViewUtil::ExecuteCharMap(rItem, *mrViewData.GetViewShell());
+
+ if ( !aString.isEmpty() )
+ {
+ SfxItemSet aSet( pOutliner->GetEmptyItemSet() );
+ // tdf#125054
+ // checked against original, indeed aNewItem looks as if it can have
+ // either WhichID EE_CHAR_FONTINFO or ATTR_FONT when it was reset
+ // above, original uses '= SvxFontItem(..., ATTR_FONT).
+ // BUT beware: the operator=() did not copy the WhichID when resetting,
+ // so it indeed has WhichID of EE_CHAR_FONTINFO despite copying an Item
+ // that was constructed using ATTR_FONT as WhichID (!)
+ aSet.Put( *aNewItem, EE_CHAR_FONTINFO );
+
+ // If nothing is selected, then SetAttribs of the View selects a word
+ pOutView->GetOutliner()->QuickSetAttribs( aSet, pOutView->GetSelection() );
+ pOutView->InsertText(aString);
+ }
+
+ Invalidate( SID_ATTR_CHAR_FONT );
+ }
+ break;
+
+ case SID_HYPERLINK_SETLINK:
+ if( pReqArgs )
+ {
+ if ( const SvxHyperlinkItem* pHyper = pReqArgs->GetItemIfSet( SID_HYPERLINK_SETLINK) )
+ {
+ const OUString& rName = pHyper->GetName();
+ const OUString& rURL = pHyper->GetURL();
+ const OUString& rTarget = pHyper->GetTargetFrame();
+ SvxLinkInsertMode eMode = pHyper->GetInsertMode();
+
+ bool bDone = false;
+ if (eMode == HLINK_DEFAULT || eMode == HLINK_FIELD)
+ {
+ pOutView->SelectFieldAtCursor();
+
+ // insert new field
+ SvxURLField aURLField( rURL, rName, SvxURLFormat::Repr );
+ aURLField.SetTargetFrame( rTarget );
+ SvxFieldItem aURLItem( aURLField, EE_FEATURE_FIELD );
+ pOutView->InsertField( aURLItem );
+
+ bDone = true;
+ }
+
+ if (!bDone)
+ ExecuteGlobal( rReq ); // normal at View
+
+ // If "text" is received by InsertURL of ViewShell, then the DrawShell is turned off !!!
+ }
+ }
+ break;
+
+ case SID_OPEN_HYPERLINK:
+ if (const SvxFieldData* pField = pOutView->GetFieldAtCursor())
+ {
+ if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
+ {
+ ScGlobal::OpenURL(pURLField->GetURL(), pURLField->GetTargetFrame(), true);
+ }
+ }
+ break;
+
+ case SID_EDIT_HYPERLINK:
+ {
+ // Ensure the field is selected first
+ pOutView->SelectFieldAtCursor();
+ mrViewData.GetViewShell()->GetViewFrame()->GetDispatcher()->Execute(SID_HYPERLINK_DIALOG);
+ }
+ break;
+
+ case SID_COPY_HYPERLINK_LOCATION:
+ {
+ 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);
+ }
+ }
+ break;
+
+ case SID_REMOVE_HYPERLINK:
+ {
+ // Ensure the field is selected first
+ URLFieldHelper::RemoveURLField(pOutView->GetEditView());
+ }
+ break;
+
+ case SID_ENABLE_HYPHENATION:
+ case SID_TEXTDIRECTION_LEFT_TO_RIGHT:
+ case SID_TEXTDIRECTION_TOP_TO_BOTTOM:
+ pView->ScEndTextEdit(); // end text edit before switching direction
+ ExecuteGlobal( rReq );
+ // restore consistent state between shells and functions:
+ mrViewData.GetDispatcher().Execute(SID_OBJECT_SELECT, SfxCallMode::SLOT | SfxCallMode::RECORD);
+ 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( pOutView->GetEditView(), aReplaceText );
+ }
+ break;
+
+ case SID_THESAURUS:
+ {
+ pOutView->StartThesaurus(rReq.GetFrameWeld());
+ }
+ break;
+ }
+}
+
+void ScDrawTextObjectBar::GetState( SfxItemSet& rSet )
+{
+ SfxViewFrame* pViewFrm = mrViewData.GetViewShell()->GetViewFrame();
+ bool bHasFontWork = pViewFrm->HasChildWindow(SID_FONTWORK);
+ bool bDisableFontWork = false;
+
+ if (IsNoteEdit())
+ {
+ // #i21255# notes now support rich text formatting (#i74140# but not fontwork)
+ bDisableFontWork = true;
+ }
+
+ if ( bDisableFontWork )
+ rSet.DisableItem( SID_FONTWORK );
+ else
+ rSet.Put(SfxBoolItem(SID_FONTWORK, bHasFontWork));
+
+ if ( rSet.GetItemState( SID_HYPERLINK_GETLINK ) != SfxItemState::UNKNOWN )
+ {
+ SvxHyperlinkItem aHLinkItem;
+ SdrView* pView = mrViewData.GetScDrawView();
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+ if ( pOutView )
+ {
+ bool bField = false;
+ const SvxFieldData* pField = pOutView->GetFieldAtCursor();
+ if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
+ {
+ aHLinkItem.SetName( pURLField->GetRepresentation() );
+ aHLinkItem.SetURL( pURLField->GetURL() );
+ aHLinkItem.SetTargetFrame( pURLField->GetTargetFrame() );
+ bField = true;
+ }
+
+ if (!bField)
+ {
+ // use selected text as name for urls
+ OUString sReturn = pOutView->GetSelected();
+ sal_Int32 nLen = std::min<sal_Int32>(sReturn.getLength(), 255);
+ sReturn = sReturn.copy(0, nLen);
+ aHLinkItem.SetName(comphelper::string::stripEnd(sReturn, ' '));
+ }
+ }
+ rSet.Put(aHLinkItem);
+ }
+
+ if (rSet.GetItemState(SID_OPEN_HYPERLINK) != SfxItemState::UNKNOWN
+ || rSet.GetItemState(SID_EDIT_HYPERLINK) != SfxItemState::UNKNOWN
+ || rSet.GetItemState(SID_COPY_HYPERLINK_LOCATION) != SfxItemState::UNKNOWN
+ || rSet.GetItemState(SID_REMOVE_HYPERLINK) != SfxItemState::UNKNOWN)
+ {
+ SdrView* pView = mrViewData.GetScDrawView();
+ if( !URLFieldHelper::IsCursorAtURLField(pView->GetTextEditOutlinerView()) )
+ {
+ rSet.DisableItem( SID_OPEN_HYPERLINK );
+ rSet.DisableItem( SID_EDIT_HYPERLINK );
+ rSet.DisableItem( SID_COPY_HYPERLINK_LOCATION );
+ rSet.DisableItem( SID_REMOVE_HYPERLINK );
+ }
+ }
+
+ if( rSet.GetItemState( SID_TRANSLITERATE_HALFWIDTH ) != SfxItemState::UNKNOWN )
+ ScViewUtil::HideDisabledSlot( rSet, pViewFrm->GetBindings(), SID_TRANSLITERATE_HALFWIDTH );
+ if( rSet.GetItemState( SID_TRANSLITERATE_FULLWIDTH ) != SfxItemState::UNKNOWN )
+ ScViewUtil::HideDisabledSlot( rSet, pViewFrm->GetBindings(), SID_TRANSLITERATE_FULLWIDTH );
+ if( rSet.GetItemState( SID_TRANSLITERATE_HIRAGANA ) != SfxItemState::UNKNOWN )
+ ScViewUtil::HideDisabledSlot( rSet, pViewFrm->GetBindings(), SID_TRANSLITERATE_HIRAGANA );
+ if( rSet.GetItemState( SID_TRANSLITERATE_KATAKANA ) != SfxItemState::UNKNOWN )
+ ScViewUtil::HideDisabledSlot( rSet, pViewFrm->GetBindings(), SID_TRANSLITERATE_KATAKANA );
+
+ if ( rSet.GetItemState( SID_ENABLE_HYPHENATION ) != SfxItemState::UNKNOWN )
+ {
+ SdrView* pView = mrViewData.GetScDrawView();
+ SfxItemSet aAttrs( pView->GetModel()->GetItemPool() );
+ pView->GetAttributes( aAttrs );
+ if( aAttrs.GetItemState( EE_PARA_HYPHENATE ) >= SfxItemState::DEFAULT )
+ {
+ bool bValue = aAttrs.Get( EE_PARA_HYPHENATE ).GetValue();
+ rSet.Put( SfxBoolItem( SID_ENABLE_HYPHENATION, bValue ) );
+ }
+ }
+
+ if ( rSet.GetItemState( SID_THES ) != SfxItemState::UNKNOWN ||
+ rSet.GetItemState( SID_THESAURUS ) != SfxItemState::UNKNOWN )
+ {
+ SdrView * pView = mrViewData.GetScDrawView();
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+
+ OUString aStatusVal;
+ LanguageType nLang = LANGUAGE_NONE;
+ bool bIsLookUpWord = false;
+ if ( pOutView )
+ {
+ EditView& rEditView = pOutView->GetEditView();
+ bIsLookUpWord = GetStatusValueForThesaurusFromContext( aStatusVal, nLang, rEditView );
+ }
+ rSet.Put( SfxStringItem( SID_THES, aStatusVal ) );
+
+ // disable thesaurus main menu and context menu entry if there is nothing to look up
+ bool bCanDoThesaurus = ScModule::HasThesaurusLanguage( nLang );
+ if (!bIsLookUpWord || !bCanDoThesaurus)
+ rSet.DisableItem( SID_THES );
+ if (!bCanDoThesaurus)
+ rSet.DisableItem( SID_THESAURUS );
+ }
+
+ if (GetObjectShell()->isContentExtractionLocked())
+ {
+ rSet.DisableItem(SID_COPY);
+ rSet.DisableItem(SID_CUT);
+ }
+}
+
+IMPL_LINK( ScDrawTextObjectBar, ClipboardChanged, TransferableDataHelper*, pDataHelper, void )
+{
+ bPastePossible = ( pDataHelper->HasFormat( SotClipboardFormatId::STRING ) || pDataHelper->HasFormat( SotClipboardFormatId::RTF )
+ || pDataHelper->HasFormat( SotClipboardFormatId::RICHTEXT ) );
+
+ SfxBindings& rBindings = mrViewData.GetBindings();
+ rBindings.Invalidate( SID_PASTE );
+ rBindings.Invalidate( SID_PASTE_SPECIAL );
+ rBindings.Invalidate( SID_PASTE_UNFORMATTED );
+ rBindings.Invalidate( SID_CLIPBOARD_FORMAT_ITEMS );
+}
+
+void ScDrawTextObjectBar::GetClipState( SfxItemSet& rSet )
+{
+ SdrView* pView = mrViewData.GetScDrawView();
+ if ( !pView->GetTextEditOutlinerView() )
+ {
+ GetGlobalClipState( rSet );
+ return;
+ }
+
+ if ( !mxClipEvtLstnr.is() )
+ {
+ // create listener
+ mxClipEvtLstnr = new TransferableClipboardListener( LINK( this, ScDrawTextObjectBar, ClipboardChanged ) );
+ vcl::Window* pWin = mrViewData.GetActiveWin();
+ mxClipEvtLstnr->AddListener( pWin );
+
+ // get initial state
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( mrViewData.GetActiveWin() ) );
+ bPastePossible = ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) || aDataHelper.HasFormat( SotClipboardFormatId::RTF )
+ || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) );
+ }
+
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich)
+ {
+ switch (nWhich)
+ {
+ case SID_PASTE:
+ case SID_PASTE_SPECIAL:
+ case SID_PASTE_UNFORMATTED:
+ if( !bPastePossible )
+ rSet.DisableItem( nWhich );
+ break;
+ case SID_CLIPBOARD_FORMAT_ITEMS:
+ if ( bPastePossible )
+ {
+ SvxClipboardFormatItem aFormats( SID_CLIPBOARD_FORMAT_ITEMS );
+ TransferableDataHelper aDataHelper(
+ TransferableDataHelper::CreateFromSystemClipboard( mrViewData.GetActiveWin() ) );
+
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) )
+ aFormats.AddClipbrdFormat( SotClipboardFormatId::STRING );
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
+ aFormats.AddClipbrdFormat( SotClipboardFormatId::RTF );
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) )
+ aFormats.AddClipbrdFormat( SotClipboardFormatId::RICHTEXT );
+
+ rSet.Put( aFormats );
+ }
+ else
+ rSet.DisableItem( nWhich );
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+// Attributes
+
+void ScDrawTextObjectBar::ExecuteToggle( SfxRequest &rReq )
+{
+ // Underline
+
+ SdrView* pView = mrViewData.GetScDrawView();
+
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ SfxItemSet aSet( pView->GetDefaultAttr() );
+
+ SfxItemSet aViewAttr(pView->GetModel()->GetItemPool());
+ pView->GetAttributes(aViewAttr);
+
+ // Underline
+ FontLineStyle eOld = aViewAttr.Get(EE_CHAR_UNDERLINE).GetLineStyle();
+ FontLineStyle eNew = eOld;
+ switch (nSlot)
+ {
+ case SID_ULINE_VAL_NONE:
+ eNew = LINESTYLE_NONE;
+ break;
+ 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;
+ default:
+ break;
+ }
+ aSet.Put( SvxUnderlineItem( eNew, EE_CHAR_UNDERLINE ) );
+
+ pView->SetAttributes( aSet );
+ rReq.Done();
+ mrViewData.GetScDrawView()->InvalidateDrawTextAttrs();
+}
+
+static void lcl_RemoveFields( OutlinerView& rOutView )
+{
+ //! Outliner should have RemoveFields with a selection
+
+ Outliner* pOutliner = rOutView.GetOutliner();
+ if (!pOutliner) return;
+
+ ESelection aOldSel = rOutView.GetSelection();
+ ESelection aSel = aOldSel;
+ aSel.Adjust();
+ sal_Int32 nNewEnd = aSel.nEndPos;
+
+ bool bUpdate = pOutliner->IsUpdateLayout();
+ bool bChanged = false;
+
+ //! GetPortions and GetAttribs should be const!
+ EditEngine& rEditEng = const_cast<EditEngine&>(pOutliner->GetEditEngine());
+
+ sal_Int32 nParCount = pOutliner->GetParagraphCount();
+ for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
+ if ( nPar >= aSel.nStartPara && nPar <= aSel.nEndPara )
+ {
+ std::vector<sal_Int32> aPortions;
+ rEditEng.GetPortions( nPar, aPortions );
+
+ for ( size_t nPos = aPortions.size(); nPos; )
+ {
+ --nPos;
+ sal_Int32 nEnd = aPortions[ nPos ];
+ sal_Int32 nStart = nPos ? aPortions[ nPos - 1 ] : 0;
+ // fields are single characters
+ if ( nEnd == nStart+1 &&
+ ( nPar > aSel.nStartPara || nStart >= aSel.nStartPos ) &&
+ ( nPar < aSel.nEndPara || nEnd <= aSel.nEndPos ) )
+ {
+ ESelection aFieldSel( nPar, nStart, nPar, nEnd );
+ SfxItemSet aSet = rEditEng.GetAttribs( aFieldSel );
+ if ( aSet.GetItemState( EE_FEATURE_FIELD ) == SfxItemState::SET )
+ {
+ if (!bChanged)
+ {
+ if (bUpdate)
+ pOutliner->SetUpdateLayout( false );
+ OUString aName = ScResId( STR_UNDO_DELETECONTENTS );
+ ViewShellId nViewShellId(-1);
+ if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
+ nViewShellId = pViewSh->GetViewShellId();
+ pOutliner->GetUndoManager().EnterListAction( aName, aName, 0, nViewShellId );
+ bChanged = true;
+ }
+
+ OUString aFieldText = rEditEng.GetText( aFieldSel );
+ pOutliner->QuickInsertText( aFieldText, aFieldSel );
+ if ( nPar == aSel.nEndPara )
+ {
+ nNewEnd = nNewEnd + aFieldText.getLength();
+ --nNewEnd;
+ }
+ }
+ }
+ }
+ }
+
+ if (bUpdate && bChanged)
+ {
+ pOutliner->GetUndoManager().LeaveListAction();
+ pOutliner->SetUpdateLayout( true );
+ }
+
+ if ( aOldSel == aSel ) // aSel is adjusted
+ aOldSel.nEndPos = nNewEnd;
+ else
+ aOldSel.nStartPos = nNewEnd; // if aOldSel is backwards
+ rOutView.SetSelection( aOldSel );
+}
+
+void ScDrawTextObjectBar::ExecuteAttr( SfxRequest &rReq )
+{
+ SdrView* pView = mrViewData.GetScDrawView();
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ SfxItemSet aEditAttr( pView->GetModel()->GetItemPool() );
+ pView->GetAttributes( aEditAttr );
+ SfxItemSet aNewAttr( *aEditAttr.GetPool(), aEditAttr.GetRanges() );
+
+ bool bSet = true;
+ switch ( nSlot )
+ {
+ case SID_ALIGNLEFT:
+ case SID_ALIGN_ANY_LEFT:
+ case SID_ATTR_PARA_ADJUST_LEFT:
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
+ break;
+
+ case SID_ALIGNCENTERHOR:
+ case SID_ALIGN_ANY_HCENTER:
+ case SID_ATTR_PARA_ADJUST_CENTER:
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
+ break;
+
+ case SID_ALIGNRIGHT:
+ case SID_ALIGN_ANY_RIGHT:
+ case SID_ATTR_PARA_ADJUST_RIGHT:
+ aNewAttr.Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
+ break;
+
+ case SID_ALIGNBLOCK:
+ case SID_ALIGN_ANY_JUSTIFIED:
+ 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;
+
+ case SID_TABLE_VERT_NONE:
+ case SID_TABLE_VERT_CENTER:
+ case SID_TABLE_VERT_BOTTOM:
+ {
+ SdrTextVertAdjust eTVA = SDRTEXTVERTADJUST_TOP;
+ if (nSlot == SID_TABLE_VERT_CENTER)
+ eTVA = SDRTEXTVERTADJUST_CENTER;
+ else if (nSlot == SID_TABLE_VERT_BOTTOM)
+ eTVA = SDRTEXTVERTADJUST_BOTTOM;
+ aNewAttr.Put(SdrTextVertAdjustItem(eTVA));
+ }
+ break;
+
+ case SID_PARASPACE_INCREASE:
+ case SID_PARASPACE_DECREASE:
+ {
+ SvxULSpaceItem aULSpace( aEditAttr.Get( EE_PARA_ULSPACE ) );
+ sal_uInt16 nUpper = aULSpace.GetUpper();
+ sal_uInt16 nLower = aULSpace.GetLower();
+
+ if ( nSlot == SID_PARASPACE_INCREASE )
+ {
+ nUpper += 100;
+ nLower += 100;
+ }
+ else
+ {
+ nUpper = std::max< sal_Int16 >( nUpper - 100, 0 );
+ nLower = std::max< sal_Int16 >( nLower - 100, 0 );
+ }
+
+ aULSpace.SetUpper( nUpper );
+ aULSpace.SetLower( nLower );
+ aNewAttr.Put( aULSpace );
+ }
+ break;
+
+ default:
+ bSet = false;
+ }
+
+ bool bDone = true;
+ bool bArgsInReq = ( pArgs != nullptr );
+
+ if ( !bArgsInReq )
+ {
+ switch ( nSlot )
+ {
+ case SID_TEXT_STANDARD: // delete hard text attributes
+ {
+ OutlinerView* pOutView = pView->IsTextEdit() ?
+ pView->GetTextEditOutlinerView() : nullptr;
+ if ( pOutView )
+ pOutView->Paint( tools::Rectangle() );
+
+ SfxItemSetFixed<EE_ITEMS_START, EE_ITEMS_END> aEmptyAttr( *aEditAttr.GetPool() );
+ pView->SetAttributes( aEmptyAttr, true );
+
+ if ( pOutView )
+ {
+ lcl_RemoveFields( *pOutView );
+ pOutView->ShowCursor();
+ }
+
+ rReq.Done( aEmptyAttr );
+ mrViewData.GetScDrawView()->InvalidateDrawTextAttrs();
+ bDone = false; // already happened here
+ }
+ break;
+
+ case SID_GROW_FONT_SIZE:
+ case SID_SHRINK_FONT_SIZE:
+ {
+ OutlinerView* pOutView = pView->IsTextEdit() ?
+ pView->GetTextEditOutlinerView() : nullptr;
+ if ( pOutView )
+ {
+ if (SfxObjectShell* pObjSh = SfxObjectShell::Current())
+ {
+ const SvxFontListItem* pFontListItem = static_cast< const SvxFontListItem* >
+ ( pObjSh->GetItem( SID_ATTR_CHAR_FONTLIST ) );
+ const FontList* pFontList = pFontListItem ? pFontListItem->GetFontList() : nullptr;
+ pOutView->GetEditView().ChangeFontSize( nSlot == SID_GROW_FONT_SIZE, pFontList );
+ mrViewData.GetBindings().Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ }
+ bDone = false;
+ }
+ }
+ break;
+
+ case SID_CHAR_DLG_EFFECT:
+ case SID_CHAR_DLG: // dialog button
+ case SID_ATTR_CHAR_FONT: // Controller not shown
+ case SID_ATTR_CHAR_FONTHEIGHT:
+ bDone = ExecuteCharDlg( aEditAttr, aNewAttr , nSlot);
+ break;
+
+ case SID_PARA_DLG:
+ bDone = ExecuteParaDlg( aEditAttr, aNewAttr );
+ break;
+
+ case SID_ATTR_CHAR_WEIGHT:
+ aNewAttr.Put( aEditAttr.Get( EE_CHAR_WEIGHT ) );
+ break;
+
+ case SID_ATTR_CHAR_POSTURE:
+ aNewAttr.Put( aEditAttr.Get( EE_CHAR_ITALIC ) );
+ break;
+
+ case SID_ATTR_CHAR_UNDERLINE:
+ aNewAttr.Put( aEditAttr.Get( EE_CHAR_UNDERLINE ) );
+ break;
+
+ case SID_ATTR_CHAR_OVERLINE:
+ aNewAttr.Put( aEditAttr.Get( EE_CHAR_OVERLINE ) );
+ break;
+
+ case SID_ATTR_CHAR_CONTOUR:
+ aNewAttr.Put( aEditAttr.Get( EE_CHAR_OUTLINE ) );
+ break;
+
+ case SID_ATTR_CHAR_SHADOWED:
+ aNewAttr.Put( aEditAttr.Get( EE_CHAR_SHADOW ) );
+ break;
+
+ case SID_ATTR_CHAR_STRIKEOUT:
+ aNewAttr.Put( aEditAttr.Get( EE_CHAR_STRIKEOUT ) );
+ break;
+
+ case SID_DRAWTEXT_ATTR_DLG:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateTextTabDialog(mrViewData.GetDialogParent(), &aEditAttr, pView));
+
+ bDone = ( RET_OK == pDlg->Execute() );
+
+ if ( bDone )
+ aNewAttr.Put( *pDlg->GetOutputItemSet() );
+
+ pDlg.disposeAndClear();
+
+ SfxBindings& rBindings = mrViewData.GetBindings();
+ rBindings.Invalidate( SID_TABLE_VERT_NONE );
+ rBindings.Invalidate( SID_TABLE_VERT_CENTER );
+ rBindings.Invalidate( SID_TABLE_VERT_BOTTOM );
+ }
+ break;
+ }
+ }
+
+ if ( bSet || bDone )
+ {
+ rReq.Done( aNewAttr );
+ pArgs = rReq.GetArgs();
+ }
+
+ if ( !pArgs )
+ return;
+
+ if ( bArgsInReq &&
+ ( nSlot == SID_ATTR_CHAR_FONT || nSlot == SID_ATTR_CHAR_FONTHEIGHT ||
+ nSlot == SID_ATTR_CHAR_WEIGHT || nSlot == SID_ATTR_CHAR_POSTURE ) )
+ {
+ // font items from toolbox controller have to be applied for the right script type
+
+ // #i78017 establish the same behaviour as in Writer
+ SvtScriptType nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
+ if (nSlot == SID_ATTR_CHAR_FONT)
+ nScript = pView->GetScriptType();
+
+ SfxItemPool& rPool = GetPool();
+ SvxScriptSetItem aSetItem( nSlot, rPool );
+ sal_uInt16 nWhich = rPool.GetWhich( nSlot );
+ aSetItem.PutItemForScriptType( nScript, pArgs->Get( nWhich ) );
+
+ pView->SetAttributes( aSetItem.GetItemSet() );
+ }
+ else if( nSlot == SID_ATTR_PARA_LRSPACE )
+ {
+ sal_uInt16 nId = SID_ATTR_PARA_LRSPACE;
+ const SvxLRSpaceItem& rItem = static_cast<const SvxLRSpaceItem&>(
+ pArgs->Get( nId ));
+ SfxItemSetFixed<EE_PARA_LRSPACE, EE_PARA_LRSPACE> aAttr( GetPool() );
+ nId = EE_PARA_LRSPACE;
+ SvxLRSpaceItem aLRSpaceItem( rItem.GetLeft(),
+ rItem.GetRight(), rItem.GetTextLeft(),
+ rItem.GetTextFirstLineOffset(), nId );
+ aAttr.Put( aLRSpaceItem );
+ pView->SetAttributes( aAttr );
+ }
+ else if( nSlot == SID_ATTR_PARA_LINESPACE )
+ {
+ SvxLineSpacingItem aLineSpaceItem = static_cast<const SvxLineSpacingItem&>(pArgs->Get(
+ GetPool().GetWhich(nSlot)));
+ SfxItemSetFixed<EE_PARA_SBL, EE_PARA_SBL> aAttr( GetPool() );
+ aAttr.Put( aLineSpaceItem );
+ pView->SetAttributes( aAttr );
+ }
+ else if( nSlot == SID_ATTR_PARA_ULSPACE )
+ {
+ SvxULSpaceItem aULSpaceItem = static_cast<const SvxULSpaceItem&>(pArgs->Get(
+ GetPool().GetWhich(nSlot)));
+ SfxItemSetFixed<EE_PARA_ULSPACE, EE_PARA_ULSPACE> aAttr( GetPool() );
+ aULSpaceItem.SetWhich(EE_PARA_ULSPACE);
+ aAttr.Put( aULSpaceItem );
+ pView->SetAttributes( aAttr );
+ }
+ else
+ {
+ // use args directly
+ pView->SetAttributes( *pArgs );
+ }
+ mrViewData.GetScDrawView()->InvalidateDrawTextAttrs();
+}
+
+void ScDrawTextObjectBar::GetAttrState( SfxItemSet& rDestSet )
+{
+ if ( IsNoteEdit() )
+ {
+ // issue 21255 - Notes now support rich text formatting.
+ }
+
+ bool bDisableCTLFont = !SvtCTLOptions().IsCTLFontEnabled();
+ bool bDisableVerticalText = !SvtCJKOptions::IsVerticalTextEnabled();
+
+ SdrView* pView = mrViewData.GetScDrawView();
+ SfxItemSet aAttrSet(pView->GetModel()->GetItemPool());
+ pView->GetAttributes(aAttrSet);
+
+ // direct attributes
+
+ rDestSet.Put( aAttrSet );
+
+ // choose font info according to selection script type
+
+ SvtScriptType nScript = pView->GetScriptType();
+
+ // #i55929# input-language-dependent script type (depends on input language if nothing selected)
+ SvtScriptType nInputScript = nScript;
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+ if (pOutView && !pOutView->GetSelection().HasRange())
+ {
+ LanguageType nInputLang = mrViewData.GetActiveWin()->GetInputLanguage();
+ if (nInputLang != LANGUAGE_DONTKNOW && nInputLang != LANGUAGE_SYSTEM)
+ nInputScript = SvtLanguageOptions::GetScriptTypeOfLanguage( nInputLang );
+ }
+
+ // #i55929# according to spec, nInputScript is used for font and font height only
+ if ( rDestSet.GetItemState( EE_CHAR_FONTINFO ) != SfxItemState::UNKNOWN )
+ ScViewUtil::PutItemScript( rDestSet, aAttrSet, EE_CHAR_FONTINFO, nInputScript );
+ if ( rDestSet.GetItemState( EE_CHAR_FONTHEIGHT ) != SfxItemState::UNKNOWN )
+ ScViewUtil::PutItemScript( rDestSet, aAttrSet, EE_CHAR_FONTHEIGHT, nInputScript );
+ if ( rDestSet.GetItemState( EE_CHAR_WEIGHT ) != SfxItemState::UNKNOWN )
+ ScViewUtil::PutItemScript( rDestSet, aAttrSet, EE_CHAR_WEIGHT, nScript );
+ if ( rDestSet.GetItemState( EE_CHAR_ITALIC ) != SfxItemState::UNKNOWN )
+ ScViewUtil::PutItemScript( rDestSet, aAttrSet, EE_CHAR_ITALIC, nScript );
+ // Alignment
+
+ SvxAdjust eAdj = aAttrSet.Get(EE_PARA_JUST).GetAdjust();
+ switch( eAdj )
+ {
+ case SvxAdjust::Left:
+ {
+ rDestSet.Put( SfxBoolItem( SID_ALIGNLEFT, true ) );
+ rDestSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_LEFT, true ) );
+ }
+ break;
+ case SvxAdjust::Center:
+ {
+ rDestSet.Put( SfxBoolItem( SID_ALIGNCENTERHOR, true ) );
+ rDestSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_CENTER, true ) );
+ }
+ break;
+ case SvxAdjust::Right:
+ {
+ rDestSet.Put( SfxBoolItem( SID_ALIGNRIGHT, true ) );
+ rDestSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_RIGHT, true ) );
+ }
+ break;
+ case SvxAdjust::Block:
+ {
+ rDestSet.Put( SfxBoolItem( SID_ALIGNBLOCK, true ) );
+ rDestSet.Put( SfxBoolItem( SID_ATTR_PARA_ADJUST_BLOCK, true ) );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ // pseudo slots for Format menu
+ rDestSet.Put( SfxBoolItem( SID_ALIGN_ANY_LEFT, eAdj == SvxAdjust::Left ) );
+ rDestSet.Put( SfxBoolItem( SID_ALIGN_ANY_HCENTER, eAdj == SvxAdjust::Center ) );
+ rDestSet.Put( SfxBoolItem( SID_ALIGN_ANY_RIGHT, eAdj == SvxAdjust::Right ) );
+ rDestSet.Put( SfxBoolItem( SID_ALIGN_ANY_JUSTIFIED, eAdj == SvxAdjust::Block ) );
+
+ SvxLRSpaceItem aLR = aAttrSet.Get( EE_PARA_LRSPACE );
+ aLR.SetWhich(SID_ATTR_PARA_LRSPACE);
+ rDestSet.Put(aLR);
+ Invalidate( SID_ATTR_PARA_LRSPACE );
+ SfxItemState eState = aAttrSet.GetItemState( EE_PARA_LRSPACE );
+ if ( eState == SfxItemState::DONTCARE )
+ rDestSet.InvalidateItem(SID_ATTR_PARA_LRSPACE);
+ //xuxu for Line Space
+ SvxLineSpacingItem aLineSP = aAttrSet.Get( EE_PARA_SBL );
+ aLineSP.SetWhich(SID_ATTR_PARA_LINESPACE);
+ rDestSet.Put(aLineSP);
+ Invalidate(SID_ATTR_PARA_LINESPACE);
+ eState = aAttrSet.GetItemState( EE_PARA_SBL );
+ if ( eState == SfxItemState::DONTCARE )
+ rDestSet.InvalidateItem(SID_ATTR_PARA_LINESPACE);
+ //xuxu for UL Space
+ SvxULSpaceItem aULSP = aAttrSet.Get( EE_PARA_ULSPACE );
+ aULSP.SetWhich(SID_ATTR_PARA_ULSPACE);
+ rDestSet.Put(aULSP);
+ Invalidate(SID_ATTR_PARA_ULSPACE);
+ Invalidate(SID_PARASPACE_INCREASE);
+ Invalidate(SID_PARASPACE_DECREASE);
+ eState = aAttrSet.GetItemState( EE_PARA_ULSPACE );
+ if( eState >= SfxItemState::DEFAULT )
+ {
+ if ( !aULSP.GetUpper() && !aULSP.GetLower() )
+ rDestSet.DisableItem( SID_PARASPACE_DECREASE );
+ }
+ else
+ {
+ rDestSet.DisableItem( SID_PARASPACE_INCREASE );
+ rDestSet.DisableItem( SID_PARASPACE_DECREASE );
+ rDestSet.InvalidateItem(SID_ATTR_PARA_ULSPACE);
+ }
+
+ // Line spacing
+
+ sal_uInt16 nLineSpace = aAttrSet.Get( EE_PARA_SBL ).GetPropLineSpace();
+ switch( nLineSpace )
+ {
+ case 100:
+ rDestSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_10, true ) );
+ break;
+ case 150:
+ rDestSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_15, true ) );
+ break;
+ case 200:
+ rDestSet.Put( SfxBoolItem( SID_ATTR_PARA_LINESPACE_20, true ) );
+ break;
+ }
+
+ // super-/subscript
+ SvxEscapement eEsc = static_cast<SvxEscapement>(aAttrSet.Get( EE_CHAR_ESCAPEMENT ).GetEnumValue());
+ rDestSet.Put(SfxBoolItem(SID_SET_SUPER_SCRIPT, eEsc == SvxEscapement::Superscript));
+ rDestSet.Put(SfxBoolItem(SID_SET_SUB_SCRIPT, eEsc == SvxEscapement::Subscript));
+
+ // Underline
+ eState = aAttrSet.GetItemState( EE_CHAR_UNDERLINE );
+ if ( eState == SfxItemState::DONTCARE )
+ {
+ rDestSet.InvalidateItem( SID_ULINE_VAL_NONE );
+ rDestSet.InvalidateItem( SID_ULINE_VAL_SINGLE );
+ rDestSet.InvalidateItem( SID_ULINE_VAL_DOUBLE );
+ rDestSet.InvalidateItem( SID_ULINE_VAL_DOTTED );
+ }
+ else
+ {
+ FontLineStyle eUnderline = aAttrSet.Get(EE_CHAR_UNDERLINE).GetLineStyle();
+ rDestSet.Put(SfxBoolItem(SID_ULINE_VAL_SINGLE, eUnderline == LINESTYLE_SINGLE));
+ rDestSet.Put(SfxBoolItem(SID_ULINE_VAL_DOUBLE, eUnderline == LINESTYLE_DOUBLE));
+ rDestSet.Put(SfxBoolItem(SID_ULINE_VAL_DOTTED, eUnderline == LINESTYLE_DOTTED));
+ rDestSet.Put(SfxBoolItem(SID_ULINE_VAL_NONE, eUnderline == LINESTYLE_NONE));
+ }
+
+ // horizontal / vertical
+
+ bool bLeftToRight = true;
+
+ SdrOutliner* pOutl = pView->GetTextEditOutliner();
+ if( pOutl )
+ {
+ if( pOutl->IsVertical() )
+ bLeftToRight = false;
+ }
+ else
+ bLeftToRight = aAttrSet.Get( SDRATTR_TEXTDIRECTION ).GetValue() == css::text::WritingMode_LR_TB;
+
+ if ( bDisableVerticalText )
+ {
+ rDestSet.DisableItem( SID_TEXTDIRECTION_LEFT_TO_RIGHT );
+ rDestSet.DisableItem( SID_TEXTDIRECTION_TOP_TO_BOTTOM );
+ }
+ else
+ {
+ rDestSet.Put( SfxBoolItem( SID_TEXTDIRECTION_LEFT_TO_RIGHT, bLeftToRight ) );
+ rDestSet.Put( SfxBoolItem( SID_TEXTDIRECTION_TOP_TO_BOTTOM, !bLeftToRight ) );
+ }
+
+ // left-to-right or right-to-left
+
+ if ( !bLeftToRight || bDisableCTLFont )
+ {
+ // disabled if vertical
+ rDestSet.DisableItem( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ rDestSet.DisableItem( SID_ATTR_PARA_RIGHT_TO_LEFT );
+ }
+ else if ( aAttrSet.GetItemState( EE_PARA_WRITINGDIR ) == SfxItemState::DONTCARE )
+ {
+ rDestSet.InvalidateItem( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ rDestSet.InvalidateItem( SID_ATTR_PARA_RIGHT_TO_LEFT );
+ }
+ else
+ {
+ SvxFrameDirection eAttrDir = aAttrSet.Get( EE_PARA_WRITINGDIR ).GetValue();
+ if ( eAttrDir == SvxFrameDirection::Environment )
+ {
+ // get "environment" direction from page style
+ if ( mrViewData.GetDocument().GetEditTextDirection( mrViewData.GetTabNo() ) == EEHorizontalTextDirection::R2L )
+ eAttrDir = SvxFrameDirection::Horizontal_RL_TB;
+ else
+ eAttrDir = SvxFrameDirection::Horizontal_LR_TB;
+ }
+ rDestSet.Put( SfxBoolItem( SID_ATTR_PARA_LEFT_TO_RIGHT, ( eAttrDir == SvxFrameDirection::Horizontal_LR_TB ) ) );
+ rDestSet.Put( SfxBoolItem( SID_ATTR_PARA_RIGHT_TO_LEFT, ( eAttrDir == SvxFrameDirection::Horizontal_RL_TB ) ) );
+ }
+}
+
+void ScDrawTextObjectBar::ExecuteTrans( const SfxRequest& rReq )
+{
+ TransliterationFlags nType = ScViewUtil::GetTransliterationType( rReq.GetSlot() );
+ if ( nType == TransliterationFlags::NONE )
+ return;
+
+ ScDrawView* pView = mrViewData.GetScDrawView();
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+ if ( pOutView )
+ {
+ // change selected text in object
+ pOutView->TransliterateText( nType );
+ }
+ else
+ {
+ //! apply to whole objects?
+ }
+}
+
+void ScDrawTextObjectBar::GetStatePropPanelAttr(SfxItemSet &rSet)
+{
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ SdrView* pView = mrViewData.GetScDrawView();
+
+ SfxItemSet aEditAttr(pView->GetModel()->GetItemPool());
+ pView->GetAttributes(aEditAttr);
+ //SfxItemSet aAttrs( *aEditAttr.GetPool(), aEditAttr.GetRanges() );
+
+ 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 = aEditAttr.GetItemState( SDRATTR_TEXT_CONTOURFRAME );
+ if( eConState != SfxItemState::DONTCARE )
+ {
+ bContour = aEditAttr.Get( SDRATTR_TEXT_CONTOURFRAME ).GetValue();
+ }
+ if (bContour) break;
+
+ SfxItemState eVState = aEditAttr.GetItemState( SDRATTR_TEXT_VERTADJUST );
+ //SfxItemState eHState = aAttrs.GetItemState( SDRATTR_TEXT_HORZADJUST );
+
+ //if(SfxItemState::DONTCARE != eVState && SfxItemState::DONTCARE != eHState)
+ if(SfxItemState::DONTCARE != eVState)
+ {
+ SdrTextVertAdjust eTVA = aEditAttr.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();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/drtxtob1.cxx b/sc/source/ui/drawfunc/drtxtob1.cxx
new file mode 100644
index 000000000..63dc62dae
--- /dev/null
+++ b/sc/source/ui/drawfunc/drtxtob1.cxx
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/eeitem.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <editeng/formatbreakitem.hxx>
+#include <editeng/hyphenzoneitem.hxx>
+#include <editeng/orphitem.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/spltitem.hxx>
+#include <editeng/widwitem.hxx>
+#include <editeng/editids.hrc>
+#include <svx/svxids.hrc>
+#include <vcl/transfer.hxx>
+
+#include <drtxtob.hxx>
+#include <drawview.hxx>
+#include <viewdata.hxx>
+#include <gridwin.hxx>
+
+#include <scabstdlg.hxx>
+
+bool ScDrawTextObjectBar::ExecuteCharDlg( const SfxItemSet& rArgs,
+ SfxItemSet& rOutSet , sal_uInt16 nSlot)
+{
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateScCharDlg(
+ mrViewData.GetDialogParent(), &rArgs,
+ mrViewData.GetSfxDocShell(), true));
+ if (nSlot == SID_CHAR_DLG_EFFECT)
+ {
+ pDlg->SetCurPageId("fonteffects");
+ }
+ bool bRet = ( pDlg->Execute() == RET_OK );
+
+ if ( bRet )
+ {
+ const SfxItemSet* pNewAttrs = pDlg->GetOutputItemSet();
+ if ( pNewAttrs )
+ rOutSet.Put( *pNewAttrs );
+ }
+
+ return bRet;
+}
+
+bool ScDrawTextObjectBar::ExecuteParaDlg( const SfxItemSet& rArgs,
+ SfxItemSet& rOutSet )
+{
+ SfxItemPool* pArgPool = rArgs.GetPool();
+ SfxItemSetFixed<
+ EE_ITEMS_START, EE_ITEMS_END,
+ SID_ATTR_PARA_PAGEBREAK, SID_ATTR_PARA_WIDOWS> aNewAttr(*pArgPool);
+ aNewAttr.Put( rArgs );
+
+ // Values have been taken over once to show the dialog.
+ // Has to be changed
+ // aNewAttr.Put( SvxParaDlgLimitsItem( 567 * 50, 5670) );
+
+ aNewAttr.Put( SvxHyphenZoneItem( false, SID_ATTR_PARA_HYPHENZONE ) );
+ aNewAttr.Put( SvxFormatBreakItem( SvxBreak::NONE, SID_ATTR_PARA_PAGEBREAK ) );
+ aNewAttr.Put( SvxFormatSplitItem( true, SID_ATTR_PARA_SPLIT) );
+ aNewAttr.Put( SvxWidowsItem( 0, SID_ATTR_PARA_WIDOWS) );
+ aNewAttr.Put( SvxOrphansItem( 0, SID_ATTR_PARA_ORPHANS) );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateScParagraphDlg(
+ mrViewData.GetDialogParent(), &aNewAttr));
+ bool bRet = ( pDlg->Execute() == RET_OK );
+
+ if ( bRet )
+ {
+ const SfxItemSet* pNewAttrs = pDlg->GetOutputItemSet();
+ if ( pNewAttrs )
+ rOutSet.Put( *pNewAttrs );
+ }
+
+ return bRet;
+}
+
+void ScDrawTextObjectBar::ExecutePasteContents( SfxRequest & /* rReq */ )
+{
+ SdrView* pView = mrViewData.GetScDrawView();
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractPasteDialog> pDlg(pFact->CreatePasteDialog(mrViewData.GetDialogParent()));
+
+ pDlg->Insert( SotClipboardFormatId::STRING, OUString() );
+ pDlg->Insert( SotClipboardFormatId::RTF, OUString() );
+ pDlg->Insert( SotClipboardFormatId::RICHTEXT, OUString() );
+
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( mrViewData.GetActiveWin() ) );
+
+ SotClipboardFormatId nFormat = pDlg->GetFormat( aDataHelper.GetTransferable() );
+
+ //! test if outliner view is still valid
+
+ if (nFormat != SotClipboardFormatId::NONE)
+ {
+ if (nFormat == SotClipboardFormatId::STRING)
+ pOutView->Paste();
+ else
+ pOutView->PasteSpecial();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/drtxtob2.cxx b/sc/source/ui/drawfunc/drtxtob2.cxx
new file mode 100644
index 000000000..a5b4a7394
--- /dev/null
+++ b/sc/source/ui/drawfunc/drtxtob2.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 <editeng/adjustitem.hxx>
+#include <svx/fontwork.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/writingmodeitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/request.hxx>
+#include <svl/whiter.hxx>
+#include <svx/svdoashp.hxx>
+#include <sc.hrc>
+#include <drtxtob.hxx>
+#include <viewdata.hxx>
+#include <drawview.hxx>
+#include <tabvwsh.hxx>
+#include <drwlayer.hxx>
+
+sal_uInt16 ScGetFontWorkId()
+{
+ return SvxFontWorkChildWindow::GetChildWindowId();
+}
+
+bool ScDrawTextObjectBar::IsNoteEdit() const
+{
+ return ScDrawLayer::IsNoteCaption( mrViewData.GetView()->GetScDrawView()->GetTextEditObject() );
+}
+
+// if no text edited, functions like in drawsh
+
+void ScDrawTextObjectBar::ExecuteGlobal( SfxRequest &rReq )
+{
+ ScTabView* pTabView = mrViewData.GetView();
+ ScDrawView* pView = pTabView->GetScDrawView();
+
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch ( nSlot )
+ {
+ case SID_COPY:
+ pView->DoCopy();
+ break;
+
+ case SID_CUT:
+ pView->DoCut();
+ mrViewData.GetViewShell()->UpdateDrawShell();
+ break;
+
+ case SID_PASTE:
+ case SID_PASTE_SPECIAL:
+ case SID_PASTE_UNFORMATTED:
+ case SID_CLIPBOARD_FORMAT_ITEMS:
+ case SID_HYPERLINK_SETLINK:
+ {
+ // cell methods are at cell shell, which is not available if
+ // ScDrawTextObjectBar is active
+ //! move paste etc. to view shell?
+ }
+ break;
+
+ case SID_SELECTALL:
+ pView->MarkAll();
+ break;
+
+ case SID_TEXTDIRECTION_LEFT_TO_RIGHT:
+ case SID_TEXTDIRECTION_TOP_TO_BOTTOM:
+ {
+ SfxItemSetFixed<SDRATTR_TEXTDIRECTION, SDRATTR_TEXTDIRECTION> aAttr( pView->GetModel()->GetItemPool() );
+ aAttr.Put( SvxWritingModeItem(
+ nSlot == SID_TEXTDIRECTION_LEFT_TO_RIGHT ?
+ css::text::WritingMode_LR_TB : css::text::WritingMode_TB_RL,
+ SDRATTR_TEXTDIRECTION ) );
+ pView->SetAttributes( aAttr );
+ mrViewData.GetScDrawView()->InvalidateDrawTextAttrs(); // Bidi slots may be disabled
+ rReq.Done( aAttr );
+ }
+ break;
+
+ case SID_ENABLE_HYPHENATION:
+ {
+ const SfxBoolItem* pItem = rReq.GetArg<SfxBoolItem>(SID_ENABLE_HYPHENATION);
+ if( pItem )
+ {
+ SfxItemSetFixed<EE_PARA_HYPHENATE, EE_PARA_HYPHENATE> aSet( GetPool() );
+ bool bValue = pItem->GetValue();
+ aSet.Put( SfxBoolItem( EE_PARA_HYPHENATE, bValue ) );
+ pView->SetAttributes( aSet );
+ }
+ rReq.Done();
+ }
+ break;
+ }
+}
+
+void ScDrawTextObjectBar::GetGlobalClipState( SfxItemSet& rSet )
+{
+ // cell methods are at cell shell, which is not available if
+ // ScDrawTextObjectBar is active -> disable everything
+ //! move paste etc. to view shell?
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich)
+ {
+ rSet.DisableItem( nWhich );
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void ScDrawTextObjectBar::ExecuteExtra( SfxRequest &rReq )
+{
+ ScTabView* pTabView = mrViewData.GetView();
+ ScDrawView* pView = pTabView->GetScDrawView();
+
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch ( nSlot )
+ {
+ case SID_FONTWORK:
+ {
+ sal_uInt16 nId = SvxFontWorkChildWindow::GetChildWindowId();
+ SfxViewFrame* pViewFrm = mrViewData.GetViewShell()->GetViewFrame();
+
+ if ( rReq.GetArgs() )
+ pViewFrm->SetChildWindow( nId,
+ static_cast<const SfxBoolItem&>(
+ (rReq.GetArgs()->Get(SID_FONTWORK))).
+ GetValue() );
+ else
+ pViewFrm->ToggleChildWindow( nId );
+
+ pViewFrm->GetBindings().Invalidate( SID_FONTWORK );
+ rReq.Done();
+ }
+ break;
+
+ case SID_ATTR_PARA_LEFT_TO_RIGHT:
+ case SID_ATTR_PARA_RIGHT_TO_LEFT:
+ {
+ SfxItemSetFixed<EE_PARA_WRITINGDIR, EE_PARA_WRITINGDIR,
+ EE_PARA_JUST, EE_PARA_JUST> aAttr( pView->GetModel()->GetItemPool() );
+ bool bLeft = ( nSlot == SID_ATTR_PARA_LEFT_TO_RIGHT );
+ aAttr.Put( SvxFrameDirectionItem(
+ bLeft ? SvxFrameDirection::Horizontal_LR_TB : SvxFrameDirection::Horizontal_RL_TB,
+ EE_PARA_WRITINGDIR ) );
+ aAttr.Put( SvxAdjustItem(
+ bLeft ? SvxAdjust::Left : SvxAdjust::Right,
+ EE_PARA_JUST ) );
+ pView->SetAttributes( aAttr );
+ mrViewData.GetScDrawView()->InvalidateDrawTextAttrs();
+ rReq.Done(); //! Done(aAttr) ?
+
+ }
+ break;
+ }
+}
+
+void ScDrawTextObjectBar::ExecFormText(const SfxRequest& rReq)
+{
+ ScTabView* pTabView = mrViewData.GetView();
+ ScDrawView* pDrView = pTabView->GetScDrawView();
+ const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
+
+ if ( rMarkList.GetMarkCount() == 1 && rReq.GetArgs() )
+ {
+ const SfxItemSet& rSet = *rReq.GetArgs();
+
+ if ( pDrView->IsTextEdit() )
+ pDrView->ScEndTextEdit();
+
+ pDrView->SetAttributes(rSet);
+ }
+}
+
+void ScDrawTextObjectBar::GetFormTextState(SfxItemSet& rSet)
+{
+ const SdrObject* pObj = nullptr;
+ ScDrawView* pDrView = mrViewData.GetView()->GetScDrawView();
+ const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
+
+ 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)
+ {
+ 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 aViewAttr(pDrView->GetModel()->GetItemPool());
+ pDrView->GetAttributes(aViewAttr);
+ rSet.Set(aViewAttr);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fuconarc.cxx b/sc/source/ui/drawfunc/fuconarc.cxx
new file mode 100644
index 000000000..ef9b2c0fd
--- /dev/null
+++ b/sc/source/ui/drawfunc/fuconarc.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 <fuconarc.hxx>
+#include <tabvwsh.hxx>
+#include <drawview.hxx>
+
+// Create default drawing objects via keyboard
+#include <svx/svdocirc.hxx>
+#include <svx/svxids.hrc>
+#include <svx/sxciaitm.hxx>
+#include <osl/diagnose.h>
+
+FuConstArc::FuConstArc(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
+ SdrModel* pDoc, const SfxRequest& rReq)
+ : FuConstruct(rViewSh, pWin, pViewP, pDoc, rReq)
+{
+}
+
+FuConstArc::~FuConstArc()
+{
+}
+
+bool FuConstArc::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = FuConstruct::MouseButtonDown( rMEvt );
+
+ if ( rMEvt.IsLeft() && !pView->IsAction() )
+ {
+ Point aPnt( pWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+ pWindow->CaptureMouse();
+ pView->BegCreateObj( aPnt );
+ bReturn = true;
+ }
+ return bReturn;
+}
+
+bool FuConstArc::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = false;
+
+ if ( pView->IsCreateObj() && rMEvt.IsLeft() )
+ {
+ pView->EndCreateObj( SdrCreateCmd::NextPoint );
+ bReturn = true;
+ }
+ return (FuConstruct::MouseButtonUp(rMEvt) || bReturn);
+}
+
+void FuConstArc::Activate()
+{
+ SdrObjKind aObjKind;
+
+ switch (aSfxRequest.GetSlot() )
+ {
+ case SID_DRAW_ARC:
+ aNewPointer = PointerStyle::DrawArc;
+ aObjKind = SdrObjKind::CircleArc;
+ break;
+
+ case SID_DRAW_PIE:
+ aNewPointer = PointerStyle::DrawPie;
+ aObjKind = SdrObjKind::CircleSection;
+ break;
+
+ case SID_DRAW_CIRCLECUT:
+ aNewPointer = PointerStyle::DrawCircleCut;
+ aObjKind = SdrObjKind::CircleCut;
+ break;
+
+ default:
+ aNewPointer = PointerStyle::Cross;
+ aObjKind = SdrObjKind::CircleArc;
+ break;
+ }
+
+ pView->SetCurrentObj(aObjKind);
+
+ aOldPointer = pWindow->GetPointer();
+ rViewShell.SetActivePointer( aNewPointer );
+
+ FuDraw::Activate();
+}
+
+void FuConstArc::Deactivate()
+{
+ FuDraw::Deactivate();
+ rViewShell.SetActivePointer( aOldPointer );
+}
+
+// Create default drawing objects via keyboard
+SdrObjectUniquePtr FuConstArc::CreateDefaultObject(const sal_uInt16 nID, const tools::Rectangle& rRectangle)
+{
+ // case SID_DRAW_ARC:
+ // case SID_DRAW_PIE:
+ // case SID_DRAW_CIRCLECUT:
+
+ SdrObjectUniquePtr pObj(SdrObjFactory::MakeNewObject(
+ *pDrDoc,
+ pView->GetCurrentObjInventor(),
+ pView->GetCurrentObjIdentifier()));
+
+ if(pObj)
+ {
+ if(dynamic_cast<const SdrCircObj*>( pObj.get() ) != nullptr)
+ {
+ tools::Rectangle aRect(rRectangle);
+
+ if(SID_DRAW_ARC == nID || SID_DRAW_CIRCLECUT == nID)
+ {
+ // force quadratic
+ ImpForceQuadratic(aRect);
+ }
+
+ pObj->SetLogicRect(aRect);
+
+ SfxItemSet aAttr(pDrDoc->GetItemPool());
+ aAttr.Put(makeSdrCircStartAngleItem(9000_deg100));
+ aAttr.Put(makeSdrCircEndAngleItem(0_deg100));
+
+ pObj->SetMergedItemSet(aAttr);
+ }
+ else
+ {
+ OSL_FAIL("Object is NO circle object");
+ }
+ }
+
+ return pObj;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fuconcustomshape.cxx b/sc/source/ui/drawfunc/fuconcustomshape.cxx
new file mode 100644
index 000000000..ec2e7f083
--- /dev/null
+++ b/sc/source/ui/drawfunc/fuconcustomshape.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 <fuconcustomshape.hxx>
+#include <editeng/svxenum.hxx>
+#include <svx/gallery.hxx>
+#include <sfx2/request.hxx>
+#include <svx/fmmodel.hxx>
+#include <svl/itempool.hxx>
+#include <svl/stritem.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdoashp.hxx>
+#include <svx/xfillit0.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/sdtagitm.hxx>
+#include <tabvwsh.hxx>
+#include <drawview.hxx>
+#include <editeng/adjustitem.hxx>
+
+using namespace com::sun::star;
+
+FuConstCustomShape::FuConstCustomShape(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP, SdrModel* pDoc, const SfxRequest& rReq )
+ : FuConstruct(rViewSh, pWin, pViewP, pDoc, rReq)
+{
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if ( pArgs )
+ {
+ const SfxStringItem& rItm = static_cast<const SfxStringItem&>(pArgs->Get( rReq.GetSlot() ));
+ aCustomShape = rItm.GetValue();
+ }
+}
+
+FuConstCustomShape::~FuConstCustomShape()
+{
+}
+
+bool FuConstCustomShape::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = FuConstruct::MouseButtonDown(rMEvt);
+ if ( rMEvt.IsLeft() && !pView->IsAction() )
+ {
+ Point aPnt( pWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+ pWindow->CaptureMouse();
+ pView->BegCreateObj(aPnt);
+
+ SdrObject* pObj = pView->GetCreateObj();
+ if ( pObj )
+ {
+ SetAttributes( pObj );
+ bool bForceNoFillStyle = false;
+ if ( static_cast<SdrObjCustomShape*>(pObj)->UseNoFillStyle() )
+ bForceNoFillStyle = true;
+ if ( bForceNoFillStyle )
+ pObj->SetMergedItem( XFillStyleItem( drawing::FillStyle_NONE ) );
+ }
+
+ bReturn = true;
+ }
+ return bReturn;
+}
+
+bool FuConstCustomShape::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = false;
+
+ if ( pView->IsCreateObj() && rMEvt.IsLeft() )
+ {
+ pView->EndCreateObj(SdrCreateCmd::ForceEnd);
+ bReturn = true;
+ }
+ return (FuConstruct::MouseButtonUp(rMEvt) || bReturn);
+}
+
+void FuConstCustomShape::Activate()
+{
+ pView->SetCurrentObj( SdrObjKind::CustomShape );
+
+ aNewPointer = PointerStyle::DrawRect;
+ aOldPointer = pWindow->GetPointer();
+ rViewShell.SetActivePointer( aNewPointer );
+
+ FuConstruct::Activate();
+}
+
+void FuConstCustomShape::Deactivate()
+{
+ FuConstruct::Deactivate();
+
+ rViewShell.SetActivePointer( aOldPointer );
+}
+
+// Create default drawing objects via keyboard
+SdrObjectUniquePtr FuConstCustomShape::CreateDefaultObject(const sal_uInt16 /* nID */, const tools::Rectangle& rRectangle)
+{
+ SdrObjectUniquePtr pObj(SdrObjFactory::MakeNewObject(
+ *pDrDoc,
+ pView->GetCurrentObjInventor(),
+ pView->GetCurrentObjIdentifier()));
+
+ if( pObj )
+ {
+ tools::Rectangle aRectangle( rRectangle );
+ SetAttributes( pObj.get() );
+ if ( SdrObjCustomShape::doConstructOrthogonal( aCustomShape ) )
+ ImpForceQuadratic( aRectangle );
+ pObj->SetLogicRect( aRectangle );
+ }
+
+ return pObj;
+}
+
+void FuConstCustomShape::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 SdrObject* pSourceObj = aFormModel.GetPage( 0 )->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 );
+ 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 );
+ }
+}
+
+// #i33136#
+bool FuConstCustomShape::doConstructOrthogonal() const
+{
+ return SdrObjCustomShape::doConstructOrthogonal(aCustomShape);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fuconpol.cxx b/sc/source/ui/drawfunc/fuconpol.cxx
new file mode 100644
index 000000000..6ce044ad9
--- /dev/null
+++ b/sc/source/ui/drawfunc/fuconpol.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 <fuconpol.hxx>
+#include <tabvwsh.hxx>
+#include <drawview.hxx>
+
+// Create default drawing objects via keyboard
+#include <svx/svdopath.hxx>
+#include <svx/svxids.hrc>
+#include <osl/diagnose.h>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+
+FuConstPolygon::FuConstPolygon(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
+ SdrModel* pDoc, const SfxRequest& rReq)
+ : FuConstruct(rViewSh, pWin, pViewP, pDoc, rReq)
+{
+}
+
+FuConstPolygon::~FuConstPolygon()
+{
+}
+
+bool FuConstPolygon::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = FuConstruct::MouseButtonDown(rMEvt);
+
+ SdrViewEvent aVEvt;
+ (void)pView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt);
+ if (aVEvt.meEvent == SdrEventKind::BeginTextEdit)
+ {
+ // Text input not allowed here
+ aVEvt.meEvent = SdrEventKind::BeginDragObj;
+ pView->EnableExtendedMouseEventDispatcher(false);
+ }
+ else
+ {
+ pView->EnableExtendedMouseEventDispatcher(true);
+ }
+
+ if ( pView->MouseButtonDown(rMEvt, pWindow->GetOutDev()) )
+ bReturn = true;
+
+ return bReturn;
+}
+
+bool FuConstPolygon::MouseMove(const MouseEvent& rMEvt)
+{
+ pView->MouseMove(rMEvt, pWindow->GetOutDev());
+ return FuConstruct::MouseMove(rMEvt);
+}
+
+bool FuConstPolygon::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = false;
+ bool bSimple = false;
+
+ SdrViewEvent aVEvt;
+ (void)pView->PickAnything(rMEvt, SdrMouseEventKind::BUTTONUP, aVEvt);
+
+ pView->MouseButtonUp(rMEvt, pWindow->GetOutDev());
+
+ if (aVEvt.meEvent == SdrEventKind::EndCreate)
+ {
+ bReturn = true;
+ bSimple = true; // Do not pass on double-click
+ }
+
+ bool bParent;
+ if (bSimple)
+ bParent = FuConstruct::SimpleMouseButtonUp(rMEvt);
+ else
+ bParent = FuConstruct::MouseButtonUp(rMEvt);
+
+ return (bParent || bReturn);
+}
+
+void FuConstPolygon::Activate()
+{
+ pView->EnableExtendedMouseEventDispatcher(true);
+
+ SdrObjKind eKind;
+
+ switch (GetSlotID())
+ {
+ 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;
+ }
+
+ pView->SetCurrentObj(eKind);
+
+ pView->SetEditMode(SdrViewEditMode::Create);
+
+ FuConstruct::Activate();
+
+ aNewPointer = PointerStyle::DrawPolygon;
+ aOldPointer = pWindow->GetPointer();
+ rViewShell.SetActivePointer( aNewPointer );
+}
+
+void FuConstPolygon::Deactivate()
+{
+ pView->SetEditMode(SdrViewEditMode::Edit);
+
+ pView->EnableExtendedMouseEventDispatcher(false);
+
+ FuConstruct::Deactivate();
+
+ rViewShell.SetActivePointer( aOldPointer );
+}
+
+// Create default drawing objects via keyboard
+SdrObjectUniquePtr FuConstPolygon::CreateDefaultObject(const sal_uInt16 nID, const tools::Rectangle& rRectangle)
+{
+ // case SID_DRAW_XPOLYGON:
+ // case SID_DRAW_XPOLYGON_NOFILL:
+ // case SID_DRAW_POLYGON:
+ // case SID_DRAW_POLYGON_NOFILL:
+ // case SID_DRAW_BEZIER_FILL:
+ // case SID_DRAW_BEZIER_NOFILL:
+ // case SID_DRAW_FREELINE:
+ // case SID_DRAW_FREELINE_NOFILL:
+
+ SdrObjectUniquePtr pObj(SdrObjFactory::MakeNewObject(
+ *pDrDoc,
+ pView->GetCurrentObjInventor(),
+ pView->GetCurrentObjIdentifier()));
+
+ if(pObj)
+ {
+ if(dynamic_cast<const SdrPathObj*>( pObj.get() ) != nullptr)
+ {
+ basegfx::B2DPolyPolygon aPoly;
+
+ switch(nID)
+ {
+ case SID_DRAW_BEZIER_FILL:
+ 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()));
+
+ aPoly.append(aInnerPoly);
+ break;
+ }
+ case SID_DRAW_XPOLYGON:
+ case SID_DRAW_XPOLYGON_NOFILL:
+ 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;
+ }
+ }
+
+ static_cast<SdrPathObj*>(pObj.get())->SetPathPoly(aPoly);
+ }
+ else
+ {
+ OSL_FAIL("Object is NO path object");
+ }
+
+ pObj->SetLogicRect(rRectangle);
+ }
+
+ return pObj;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fuconrec.cxx b/sc/source/ui/drawfunc/fuconrec.cxx
new file mode 100644
index 000000000..8e31015e8
--- /dev/null
+++ b/sc/source/ui/drawfunc/fuconrec.cxx
@@ -0,0 +1,449 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tabvwsh.hxx>
+#include <drawview.hxx>
+
+#include <editeng/outlobj.hxx>
+// Create default drawing objects via keyboard
+#include <svx/svdopath.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svxids.hrc>
+#include <svx/strings.hrc>
+#include <svx/xlnwtit.hxx>
+#include <svx/xlnstwit.hxx>
+#include <svx/xlnedwit.hxx>
+#include <svx/xlnedit.hxx>
+#include <svx/xlnstit.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/svdomeas.hxx>
+#include <osl/diagnose.h>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/point/b2dpoint.hxx>
+
+FuConstRectangle::FuConstRectangle(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
+ SdrModel* pDoc, const SfxRequest& rReq)
+ : FuConstruct(rViewSh, pWin, pViewP, pDoc, rReq)
+{
+}
+
+FuConstRectangle::~FuConstRectangle()
+{
+}
+
+/**
+ * set line starts and ends for the object to be created
+ */
+
+namespace {
+
+::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;
+}
+
+}
+
+bool FuConstRectangle::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = FuConstruct::MouseButtonDown(rMEvt);
+
+ if ( rMEvt.IsLeft() && !pView->IsAction() )
+ {
+ Point aPos( pWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+ pWindow->CaptureMouse();
+
+ if ( pView->GetCurrentObjIdentifier() == SdrObjKind::Caption )
+ {
+ Size aCaptionSize ( 2268, 1134 ); // 4x2cm
+
+ bReturn = pView->BegCreateCaptionObj( aPos, aCaptionSize );
+
+ // How do you set the font for writing
+ }
+ else
+ bReturn = pView->BegCreateObj(aPos);
+
+ SdrObject* pObj = pView->GetCreateObj();
+
+ if (pObj)
+ {
+ SfxItemSet aAttr(pObj->getSdrModelFromSdrObject().GetItemPool());
+ SetLineEnds(aAttr, *pObj, aSfxRequest.GetSlot());
+ pObj->SetMergedItemSet(aAttr);
+ }
+ }
+ return bReturn;
+}
+
+bool FuConstRectangle::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = false;
+
+ if ( pView->IsCreateObj() && rMEvt.IsLeft() )
+ {
+ pView->EndCreateObj(SdrCreateCmd::ForceEnd);
+
+ if (aSfxRequest.GetSlot() == SID_DRAW_CAPTION_VERTICAL)
+ {
+ // set vertical flag for caption object
+
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if (rMarkList.GetMark(0))
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ // create OutlinerParaObject now so it can be set to vertical
+ if ( auto pSdrTextObj = dynamic_cast<SdrTextObj*>( pObj) )
+ pSdrTextObj->ForceOutlinerParaObject();
+ OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
+ if( pOPO && !pOPO->IsEffectivelyVertical() )
+ pOPO->SetVertical( true );
+ }
+ }
+
+ bReturn = true;
+ }
+ return (FuConstruct::MouseButtonUp(rMEvt) || bReturn);
+}
+
+void FuConstRectangle::Activate()
+{
+ SdrObjKind aObjKind;
+
+ switch (aSfxRequest.GetSlot() )
+ {
+ case SID_DRAW_LINE:
+ case SID_DRAW_XLINE:
+ case SID_LINE_ARROW_END:
+ case SID_LINE_ARROW_CIRCLE:
+ case SID_LINE_ARROW_SQUARE:
+ case SID_LINE_ARROW_START:
+ case SID_LINE_CIRCLE_ARROW:
+ case SID_LINE_SQUARE_ARROW:
+ case SID_LINE_ARROWS:
+ aNewPointer = PointerStyle::DrawLine;
+ aObjKind = SdrObjKind::Line;
+ break;
+
+ case SID_DRAW_MEASURELINE:
+ aNewPointer = PointerStyle::DrawLine;
+ aObjKind = SdrObjKind::Measure;
+ break;
+
+ case SID_DRAW_RECT:
+ aNewPointer = PointerStyle::DrawRect;
+ aObjKind = SdrObjKind::Rectangle;
+ break;
+
+ case SID_DRAW_ELLIPSE:
+ aNewPointer = PointerStyle::DrawEllipse;
+ aObjKind = SdrObjKind::CircleOrEllipse;
+ break;
+
+ case SID_DRAW_CAPTION:
+ case SID_DRAW_CAPTION_VERTICAL:
+ aNewPointer = PointerStyle::DrawCaption;
+ aObjKind = SdrObjKind::Caption;
+ break;
+
+ default:
+ aNewPointer = PointerStyle::Cross;
+ aObjKind = SdrObjKind::Rectangle;
+ break;
+ }
+
+ pView->SetCurrentObj(aObjKind);
+
+ aOldPointer = pWindow->GetPointer();
+ rViewShell.SetActivePointer( aNewPointer );
+
+ FuConstruct::Activate();
+}
+
+void FuConstRectangle::SetLineEnds(SfxItemSet& rAttr, const SdrObject& rObj, sal_uInt16 nSlotId)
+{
+ SdrModel& rModel(rObj.getSdrModelFromSdrObject());
+
+ if ( !(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 ||
+ nSlotId == SID_DRAW_MEASURELINE) )
+ return;
+
+
+ // set attributes of line start and ends
+
+ // 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( rModel.GetItemPool() );
+ tools::Long nWidth = 200; // (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_LINE_ARROWS:
+ case SID_DRAW_MEASURELINE:
+ {
+ // 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_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_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;
+ }
+
+ // 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;
+ }
+}
+
+void FuConstRectangle::Deactivate()
+{
+ FuConstruct::Deactivate();
+ rViewShell.SetActivePointer( aOldPointer );
+}
+
+// Create default drawing objects via keyboard
+SdrObjectUniquePtr FuConstRectangle::CreateDefaultObject(const sal_uInt16 nID, const tools::Rectangle& rRectangle)
+{
+ SdrObjectUniquePtr pObj(SdrObjFactory::MakeNewObject(
+ *pDrDoc,
+ pView->GetCurrentObjInventor(),
+ pView->GetCurrentObjIdentifier()));
+
+ if(pObj)
+ {
+ tools::Rectangle aRect(rRectangle);
+ Point aStart = aRect.TopLeft();
+ Point aEnd = aRect.BottomRight();
+
+ switch(nID)
+ {
+ case SID_DRAW_LINE:
+ case SID_DRAW_XLINE:
+ case SID_LINE_ARROW_END:
+ case SID_LINE_ARROW_CIRCLE:
+ case SID_LINE_ARROW_SQUARE:
+ case SID_LINE_ARROW_START:
+ case SID_LINE_CIRCLE_ARROW:
+ case SID_LINE_SQUARE_ARROW:
+ case SID_LINE_ARROWS:
+ {
+ if(auto pPathObj = dynamic_cast<SdrPathObj*>( pObj.get() ))
+ {
+ sal_Int32 nYMiddle((aRect.Top() + aRect.Bottom()) / 2);
+ basegfx::B2DPolygon aPoly;
+ aPoly.append(basegfx::B2DPoint(aStart.X(), nYMiddle));
+ aPoly.append(basegfx::B2DPoint(aEnd.X(), nYMiddle));
+ pPathObj->SetPathPoly(basegfx::B2DPolyPolygon(aPoly));
+ }
+ 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);
+ }
+
+ 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);
+ }
+
+ // don't set default text, start edit mode instead
+ // (Edit mode is started in ScTabViewShell::ExecDraw, because
+ // it must be handled by FuText)
+
+ 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(pDrDoc->GetItemPool());
+ SetLineEnds(aAttr, *pObj, nID);
+ pObj->SetMergedItemSet(aAttr);
+ }
+
+ return pObj;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fuconstr.cxx b/sc/source/ui/drawfunc/fuconstr.cxx
new file mode 100644
index 000000000..1064a30e1
--- /dev/null
+++ b/sc/source/ui/drawfunc/fuconstr.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 <editeng/outlobj.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/dispatch.hxx>
+
+#include <fuconstr.hxx>
+#include <fudraw.hxx>
+#include <tabvwsh.hxx>
+#include <futext.hxx>
+#include <drawview.hxx>
+
+// maximal permitted mouse movement to start Drag&Drop
+//! fusel,fuconstr,futext - combine them!
+#define SC_MAXDRAGMOVE 3
+
+FuConstruct::FuConstruct(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
+ SdrModel* pDoc, const SfxRequest& rReq)
+ : FuDraw(rViewSh, pWin, pViewP, pDoc, rReq)
+{
+}
+
+FuConstruct::~FuConstruct()
+{
+}
+
+bool FuConstruct::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = FuDraw::MouseButtonDown(rMEvt);
+
+ if ( pView->IsAction() )
+ {
+ if ( rMEvt.IsRight() )
+ pView->BckAction();
+ return true;
+ }
+
+ aDragTimer.Start();
+
+ aMDPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() );
+
+ if ( rMEvt.IsLeft() )
+ {
+ pWindow->CaptureMouse();
+
+ SdrHdl* pHdl = pView->PickHandle(aMDPos);
+
+ if ( pHdl != nullptr || pView->IsMarkedHit(aMDPos) )
+ {
+ pView->BegDragObj(aMDPos, nullptr, pHdl, 1);
+ bReturn = true;
+ }
+ else if ( pView->AreObjectsMarked() )
+ {
+ pView->UnmarkAll();
+ bReturn = true;
+ }
+ }
+
+ bIsInDragMode = false;
+
+ return bReturn;
+}
+
+bool FuConstruct::MouseMove(const MouseEvent& rMEvt)
+{
+ FuDraw::MouseMove(rMEvt);
+
+ if (aDragTimer.IsActive() )
+ {
+ Point aOldPixel = pWindow->LogicToPixel( aMDPos );
+ Point aNewPixel = rMEvt.GetPosPixel();
+ if ( std::abs( aOldPixel.X() - aNewPixel.X() ) > SC_MAXDRAGMOVE ||
+ std::abs( aOldPixel.Y() - aNewPixel.Y() ) > SC_MAXDRAGMOVE )
+ aDragTimer.Stop();
+ }
+
+ Point aPix(rMEvt.GetPosPixel());
+ Point aPnt( pWindow->PixelToLogic(aPix) );
+
+ if ( pView->IsAction() )
+ {
+ ForceScroll(aPix);
+ pView->MovAction(aPnt);
+ }
+ else
+ {
+ SdrHdl* pHdl=pView->PickHandle(aPnt);
+
+ if ( pHdl != nullptr )
+ {
+ rViewShell.SetActivePointer(pHdl->GetPointer());
+ }
+ else if ( pView->IsMarkedHit(aPnt) )
+ {
+ rViewShell.SetActivePointer(PointerStyle::Move);
+ }
+ else
+ {
+ rViewShell.SetActivePointer( aNewPointer );
+ }
+ }
+ return true;
+}
+
+bool FuConstruct::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = SimpleMouseButtonUp( rMEvt );
+
+ // Double-click on text object? (->fusel)
+
+ sal_uInt16 nClicks = rMEvt.GetClicks();
+ if ( nClicks == 2 && rMEvt.IsLeft() )
+ {
+ if ( pView->AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ // if Uno-Controls no text mode
+ if ( dynamic_cast<const SdrTextObj*>( pObj) != nullptr && dynamic_cast<const SdrUnoObj*>( pObj) == nullptr )
+ {
+ OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
+ bool bVertical = ( pOPO && pOPO->IsEffectivelyVertical() );
+ sal_uInt16 nTextSlotId = bVertical ? SID_DRAW_TEXT_VERTICAL : SID_DRAW_TEXT;
+
+ rViewShell.GetViewData().GetDispatcher().
+ Execute(nTextSlotId, SfxCallMode::SLOT | SfxCallMode::RECORD);
+
+ // Get the created FuText now and change into EditMode
+ FuPoor* pPoor = rViewShell.GetViewData().GetView()->GetDrawFuncPtr();
+ if ( pPoor && pPoor->GetSlotID() == nTextSlotId ) // has no RTTI
+ {
+ FuText* pText = static_cast<FuText*>(pPoor);
+ Point aMousePixel = rMEvt.GetPosPixel();
+ pText->SetInEditMode( pObj, &aMousePixel );
+ }
+ bReturn = true;
+ }
+ }
+ }
+ }
+
+ FuDraw::MouseButtonUp(rMEvt);
+
+ return bReturn;
+}
+
+// SimpleMouseButtonUp - no test on double-click
+
+bool FuConstruct::SimpleMouseButtonUp(const MouseEvent& rMEvt)
+{
+ bool bReturn = true;
+
+ if (aDragTimer.IsActive() )
+ {
+ aDragTimer.Stop();
+ }
+
+ Point aPnt( pWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ if ( pView->IsDragObj() )
+ pView->EndDragObj( rMEvt.IsMod1() );
+
+ else if ( pView->IsMarkObj() )
+ pView->EndMarkObj();
+
+ else bReturn = false;
+
+ if ( !pView->IsAction() )
+ {
+ pWindow->ReleaseMouse();
+
+ if ( !pView->AreObjectsMarked() && rMEvt.GetClicks() < 2 )
+ {
+ pView->MarkObj(aPnt, -2, false, rMEvt.IsMod1());
+
+ SfxDispatcher& rDisp = rViewShell.GetViewData().GetDispatcher();
+ if ( pView->AreObjectsMarked() )
+ rDisp.Execute(SID_OBJECT_SELECT, SfxCallMode::SLOT | SfxCallMode::RECORD);
+ else
+ rDisp.Execute(aSfxRequest.GetSlot(), SfxCallMode::SLOT | SfxCallMode::RECORD);
+ }
+ }
+
+ return bReturn;
+}
+
+// If we handle a KeyEvent, then the return value is sal_True else FALSE.
+bool FuConstruct::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bReturn = false;
+
+ switch ( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_ESCAPE:
+ if ( pView->IsAction() )
+ {
+ pView->BrkAction();
+ pWindow->ReleaseMouse();
+ bReturn = true;
+ }
+ else // end drawing mode
+ {
+ rViewShell.GetViewData().GetDispatcher().
+ Execute(aSfxRequest.GetSlot(), SfxCallMode::SLOT | SfxCallMode::RECORD);
+ }
+ break;
+
+ case KEY_DELETE:
+ pView->DeleteMarked();
+ bReturn = true;
+ break;
+ }
+
+ if ( !bReturn )
+ {
+ bReturn = FuDraw::KeyInput(rKEvt);
+ }
+
+ return bReturn;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fuconuno.cxx b/sc/source/ui/drawfunc/fuconuno.cxx
new file mode 100644
index 000000000..e4e3c3e37
--- /dev/null
+++ b/sc/source/ui/drawfunc/fuconuno.cxx
@@ -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 .
+ */
+
+#include <fuconuno.hxx>
+#include <tabvwsh.hxx>
+#include <drawview.hxx>
+
+#include <svx/svxids.hrc>
+
+FuConstUnoControl::FuConstUnoControl(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
+ SdrModel* pDoc, const SfxRequest& rReq)
+ : FuConstruct(rViewSh, pWin, pViewP, pDoc, rReq)
+ , nInventor(SdrInventor::Unknown)
+ , nIdentifier(SdrObjKind::NONE)
+{
+ 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());
+}
+
+FuConstUnoControl::~FuConstUnoControl()
+{
+}
+
+bool FuConstUnoControl::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = FuConstruct::MouseButtonDown(rMEvt);
+
+ if ( rMEvt.IsLeft() && !pView->IsAction() )
+ {
+ Point aPnt( pWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+ pWindow->CaptureMouse();
+ pView->BegCreateObj(aPnt);
+ bReturn = true;
+ }
+ return bReturn;
+}
+
+bool FuConstUnoControl::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = false;
+
+ if ( pView->IsCreateObj() && rMEvt.IsLeft() )
+ {
+ pView->EndCreateObj(SdrCreateCmd::ForceEnd);
+ bReturn = true;
+ }
+ return (FuConstruct::MouseButtonUp(rMEvt) || bReturn);
+}
+
+void FuConstUnoControl::Activate()
+{
+ pView->SetCurrentObj( nIdentifier, nInventor );
+
+ aNewPointer = PointerStyle::DrawRect;
+ aOldPointer = pWindow->GetPointer();
+ rViewShell.SetActivePointer( aNewPointer );
+
+ SdrLayer* pLayer = pView->GetModel()->GetLayerAdmin().GetLayerPerID(SC_LAYER_CONTROLS);
+ if (pLayer)
+ pView->SetActiveLayer( pLayer->GetName() );
+
+ FuConstruct::Activate();
+}
+
+void FuConstUnoControl::Deactivate()
+{
+ FuConstruct::Deactivate();
+
+ SdrLayer* pLayer = pView->GetModel()->GetLayerAdmin().GetLayerPerID(SC_LAYER_FRONT);
+ if (pLayer)
+ pView->SetActiveLayer( pLayer->GetName() );
+
+ rViewShell.SetActivePointer( aOldPointer );
+}
+
+// Create default drawing objects via keyboard
+SdrObjectUniquePtr FuConstUnoControl::CreateDefaultObject(const sal_uInt16 /* nID */, const tools::Rectangle& rRectangle)
+{
+ // case SID_FM_CREATE_CONTROL:
+
+ SdrObjectUniquePtr pObj(SdrObjFactory::MakeNewObject(
+ *pDrDoc,
+ pView->GetCurrentObjInventor(),
+ pView->GetCurrentObjIdentifier()));
+
+ if(pObj)
+ {
+ pObj->SetLogicRect(rRectangle);
+ // tdf#140252 Controls are always on layer "controls"
+ pObj->NbcSetLayer(SC_LAYER_CONTROLS);
+ }
+
+ return pObj;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fudraw.cxx b/sc/source/ui/drawfunc/fudraw.cxx
new file mode 100644
index 000000000..ee9090765
--- /dev/null
+++ b/sc/source/ui/drawfunc/fudraw.cxx
@@ -0,0 +1,766 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/editeng.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+
+#include <sc.hrc>
+#include <fudraw.hxx>
+#include <futext.hxx>
+#include <tabvwsh.hxx>
+#include <drwlayer.hxx>
+#include <userdat.hxx>
+#include <docsh.hxx>
+#include <drawview.hxx>
+#include <comphelper/lok.hxx>
+#include <com/sun/star/embed/EmbedVerbs.hpp>
+
+namespace
+{
+
+void collectUIInformation( const OUString& aevent )
+{
+ EventDescription aDescription;
+ aDescription.aID = "grid_window";
+ aDescription.aParameters = {{ aevent , ""}};
+ aDescription.aAction = "COMMENT";
+ aDescription.aParent = "MainWindow";
+ aDescription.aKeyWord = "ScGridWinUIObject";
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+// base class for draw module specific functions
+FuDraw::FuDraw(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
+ SdrModel* pDoc, const SfxRequest& rReq)
+ : FuPoor(rViewSh, pWin, pViewP, pDoc, rReq)
+ , aNewPointer(PointerStyle::Arrow)
+ , aOldPointer(PointerStyle::Arrow)
+{
+}
+
+FuDraw::~FuDraw()
+{
+}
+
+void FuDraw::DoModifiers(const MouseEvent& rMEvt)
+{
+ // Shift = Ortho and AngleSnap
+ // Control = Snap (Toggle)
+ // Alt = centric
+
+ bool bShift = rMEvt.IsShift();
+ bool bAlt = rMEvt.IsMod2();
+
+ bool bOrtho = bShift;
+ bool bAngleSnap = bShift;
+ bool bCenter = bAlt;
+
+ // #i33136#
+ if(doConstructOrthogonal())
+ {
+ bOrtho = !bShift;
+ }
+
+ if (pView->IsOrtho() != bOrtho)
+ pView->SetOrtho(bOrtho);
+ if (pView->IsAngleSnapEnabled() != bAngleSnap)
+ pView->SetAngleSnapEnabled(bAngleSnap);
+
+ if (pView->IsCreate1stPointAsCenter() != bCenter)
+ pView->SetCreate1stPointAsCenter(bCenter);
+ if (pView->IsResizeAtCenter() != bCenter)
+ pView->SetResizeAtCenter(bCenter);
+
+}
+
+void FuDraw::ResetModifiers()
+{
+ if (!pView)
+ return;
+
+ ScViewData& rViewData = rViewShell.GetViewData();
+ const ScViewOptions& rOpt = rViewData.GetOptions();
+ const ScGridOptions& rGrid = rOpt.GetGridOptions();
+ bool bGridOpt = rGrid.GetUseGridSnap();
+
+ if (pView->IsOrtho())
+ pView->SetOrtho(false);
+ if (pView->IsAngleSnapEnabled())
+ pView->SetAngleSnapEnabled(false);
+
+ if (pView->IsGridSnap() != bGridOpt)
+ pView->SetGridSnap(bGridOpt);
+ if (pView->IsSnapEnabled() != bGridOpt)
+ pView->SetSnapEnabled(bGridOpt);
+
+ if (pView->IsCreate1stPointAsCenter())
+ pView->SetCreate1stPointAsCenter(false);
+ if (pView->IsResizeAtCenter())
+ pView->SetResizeAtCenter(false);
+}
+
+bool FuDraw::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ DoModifiers( rMEvt );
+ return false;
+}
+
+bool FuDraw::MouseMove(const MouseEvent& rMEvt)
+{
+ // evaluate modifiers only if in a drawing layer action
+ // (don't interfere with keyboard shortcut handling)
+ if (pView->IsAction())
+ DoModifiers( rMEvt );
+
+ return false;
+}
+
+bool FuDraw::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ ResetModifiers();
+ return false;
+}
+
+// Process Keyboard events. Return true if an event is being handled
+static bool lcl_KeyEditMode( SdrObject* pObj, ScTabViewShell& rViewShell, const KeyEvent* pInitialKey )
+{
+ bool bReturn = false;
+ if ( dynamic_cast<const SdrTextObj*>( pObj) != nullptr && dynamic_cast<const SdrUnoObj*>( pObj) == nullptr )
+ {
+ // start text edit - like FuSelection::MouseButtonUp,
+ // but with bCursorToEnd instead of mouse position
+
+ OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
+ bool bVertical = ( pOPO && pOPO->IsEffectivelyVertical() );
+ sal_uInt16 nTextSlotId = bVertical ? SID_DRAW_TEXT_VERTICAL : SID_DRAW_TEXT;
+
+ // don't switch shells if text shell is already active
+ FuPoor* pPoor = rViewShell.GetViewData().GetView()->GetDrawFuncPtr();
+ if ( !pPoor || pPoor->GetSlotID() != nTextSlotId )
+ {
+ rViewShell.GetViewData().GetDispatcher().
+ Execute(nTextSlotId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD);
+ }
+
+ // get the resulting FuText and set in edit mode
+ pPoor = rViewShell.GetViewData().GetView()->GetDrawFuncPtr();
+ if ( pPoor && pPoor->GetSlotID() == nTextSlotId ) // no RTTI
+ {
+ FuText* pText = static_cast<FuText*>(pPoor);
+ pText->SetInEditMode( pObj, nullptr, true, pInitialKey );
+ //! set cursor to end of text
+ }
+ bReturn = true;
+ }
+ return bReturn;
+}
+
+bool FuDraw::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bReturn = false;
+ ScViewData& rViewData = rViewShell.GetViewData();
+
+ switch ( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_ESCAPE:
+ if ( rViewShell.IsDrawTextShell() || aSfxRequest.GetSlot() == SID_DRAW_NOTEEDIT )
+ {
+ collectUIInformation("CLOSE");
+ // if object selected -> normal draw-shell, else turn off drawing
+ rViewData.GetDispatcher().Execute(aSfxRequest.GetSlot(), SfxCallMode::SLOT | SfxCallMode::RECORD);
+ bReturn = true;
+ }
+ else if ( rViewShell.IsDrawSelMode() )
+ {
+ pView->UnmarkAll();
+ rViewData.GetDispatcher().Execute(SID_OBJECT_SELECT, SfxCallMode::SLOT | SfxCallMode::RECORD);
+ bReturn = true;
+ }
+ else if ( pView->AreObjectsMarked() )
+ {
+ // III
+ SdrHdlList& rHdlList = const_cast< SdrHdlList& >( pView->GetHdlList() );
+ if( rHdlList.GetFocusHdl() )
+ rHdlList.ResetFocusHdl();
+ else
+ pView->UnmarkAll();
+
+ // while bezier editing, object is selected
+ if (!pView->AreObjectsMarked())
+ rViewShell.SetDrawShell( false );
+
+ bReturn = true;
+ }
+ break;
+
+ case KEY_DELETE: //! via accelerator
+ pView->DeleteMarked();
+ bReturn = true;
+ break;
+
+ case KEY_RETURN:
+ {
+ if( rKEvt.GetKeyCode().GetModifier() == 0 )
+ {
+ // activate OLE object on RETURN for selected object
+ // put selected text object in edit mode
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() )
+ {
+ bool bOle = rViewShell.GetViewFrame()->GetFrame().IsInPlace();
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ auto pOleObj = dynamic_cast<SdrOle2Obj*>(pObj);
+ if( pOleObj && !bOle )
+ {
+ rViewShell.ActivateObject(pOleObj, css::embed::EmbedVerbs::MS_OLEVERB_PRIMARY);
+
+ // consumed
+ bReturn = true;
+ }
+ else if ( lcl_KeyEditMode( pObj, rViewShell, nullptr ) ) // start text edit for suitable object
+ bReturn = true;
+ }
+ }
+ }
+ break;
+
+ case KEY_F2:
+ {
+ if( rKEvt.GetKeyCode().GetModifier() == 0 )
+ {
+ // put selected text object in edit mode
+ // (this is not SID_SETINPUTMODE, but F2 hardcoded, like in Writer)
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ bool isMobilePhone = comphelper::LibreOfficeKit::isActive() && rViewShell.isLOKMobilePhone();
+ // Double tapping on charts on phone may result in activating the edit mode which is not wanted.
+ // It happens due to the delay of selection message of the object from kit to javascript
+ // in that case F2 is sent instead of double click
+ if (isMobilePhone && ScDocument::IsChart(pObj))
+ {
+ rViewShell.ActivateObject(static_cast<SdrOle2Obj*>(pObj), css::embed::EmbedVerbs::MS_OLEVERB_PRIMARY);
+ break;
+ }
+ if ( lcl_KeyEditMode( pObj, rViewShell, nullptr ) ) // start text edit for suitable object
+ bReturn = true;
+ }
+ }
+ }
+ break;
+
+ case KEY_TAB:
+ {
+ // in calc do NOT start draw object selection using TAB/SHIFT-TAB when
+ // there is not yet an object selected
+ if(pView->AreObjectsMarked())
+ {
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ if ( !aCode.IsMod1() && !aCode.IsMod2() )
+ {
+ // changeover to the next object
+ if(!pView->MarkNextObj( !aCode.IsShift() ))
+ {
+ //If there is only one object, don't do the UnmarkAllObj() & MarkNextObj().
+ if ( pView->HasMultipleMarkableObjects() && pView->HasMarkableObj() )
+ {
+ // No next object: go over open end and
+ // get first from the other side
+ pView->UnmarkAllObj();
+ pView->MarkNextObj(!aCode.IsShift());
+ }
+ }
+
+ // II
+ if(pView->AreObjectsMarked())
+ pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow);
+
+ bReturn = true;
+ }
+
+ // handle Mod1 and Mod2 to get travelling running on different systems
+ if(rKEvt.GetKeyCode().IsMod1() || rKEvt.GetKeyCode().IsMod2())
+ {
+ // II do something with a selected handle?
+ const SdrHdlList& rHdlList = pView->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));
+ pView->MakeVisible(aVisRect, *pWindow);
+ }
+
+ // consumed
+ bReturn = true;
+ }
+ }
+ }
+ break;
+
+ case KEY_END:
+ {
+ // in calc do NOT select the last draw object when
+ // there is not yet an object selected
+ if(pView->AreObjectsMarked())
+ {
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ if ( aCode.IsMod1() )
+ {
+ // mark last object
+ pView->UnmarkAllObj();
+ pView->MarkNextObj();
+
+ // II
+ if(pView->AreObjectsMarked())
+ pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow);
+
+ bReturn = true;
+ }
+ }
+ }
+ break;
+
+ case KEY_HOME:
+ {
+ // in calc do NOT select the first draw object when
+ // there is not yet an object selected
+ if(pView->AreObjectsMarked())
+ {
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+
+ if ( aCode.IsMod1() )
+ {
+ // mark first object
+ pView->UnmarkAllObj();
+ pView->MarkNextObj(true);
+
+ // II
+ if(pView->AreObjectsMarked())
+ pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow);
+
+ bReturn = true;
+ }
+ }
+ }
+ break;
+
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ {
+ // in calc do cursor travelling of draw objects only when
+ // there is an object selected yet
+ if(pView->AreObjectsMarked())
+ {
+
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if(rMarkList.GetMarkCount() == 1)
+ {
+ // disable cursor travelling on note objects as the tail connector position
+ // must not move.
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ if( ScDrawLayer::IsNoteCaption( pObj ) )
+ break;
+ }
+
+ 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;
+ }
+
+ bool bReadOnly = rViewData.GetDocShell()->IsReadOnly();
+
+ if(!rKEvt.GetKeyCode().IsMod1() && !bReadOnly)
+ {
+ if(rKEvt.GetKeyCode().IsMod2())
+ {
+ // move in 1 pixel distance
+ Size aLogicSizeOnePixel = pWindow ? pWindow->PixelToLogic(Size(1,1)) : Size(100, 100);
+ nX *= aLogicSizeOnePixel.Width();
+ nY *= aLogicSizeOnePixel.Height();
+ }
+ else if(rKEvt.GetKeyCode().IsShift()) // #i121236# Support for shift key in calc
+ {
+ nX *= 1000;
+ nY *= 1000;
+ }
+ else
+ {
+ // old, fixed move distance
+ nX *= 100;
+ nY *= 100;
+ }
+
+ // is there a movement to do?
+ if(0 != nX || 0 != nY)
+ {
+ // II
+ const SdrHdlList& rHdlList = pView->GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if(nullptr == pHdl)
+ {
+ // only take action when move is allowed
+ if(pView->IsMoveAllowed())
+ {
+ // restrict movement to WorkArea
+ const tools::Rectangle& rWorkArea = pView->GetWorkArea();
+
+ if(!rWorkArea.IsEmpty())
+ {
+ tools::Rectangle aMarkRect(pView->GetMarkedObjRect());
+ aMarkRect.Move(nX, nY);
+
+ if(!aMarkRect.Contains(rWorkArea))
+ {
+ if(aMarkRect.Left() < rWorkArea.Left())
+ {
+ nX += rWorkArea.Left() - aMarkRect.Left();
+ }
+
+ if(aMarkRect.Right() > rWorkArea.Right())
+ {
+ nX -= aMarkRect.Right() - rWorkArea.Right();
+ }
+
+ if(aMarkRect.Top() < rWorkArea.Top())
+ {
+ nY += rWorkArea.Top() - aMarkRect.Top();
+ }
+
+ if(aMarkRect.Bottom() > rWorkArea.Bottom())
+ {
+ nY -= aMarkRect.Bottom() - rWorkArea.Bottom();
+ }
+ }
+ }
+
+ // now move the selected draw objects
+ pView->MoveAllMarked(Size(nX, nY));
+
+ // II
+ pView->MakeVisible(pView->GetAllMarkedRect(), *pWindow);
+
+ bReturn = true;
+ }
+ }
+ else
+ {
+ // move handle with index nHandleIndex
+ if (nX || nY)
+ {
+ // now move the Handle (nX, nY)
+ Point aStartPoint(pHdl->GetPos());
+ Point aEndPoint(pHdl->GetPos() + Point(nX, nY));
+ const SdrDragStat& rDragStat = pView->GetDragStat();
+
+ // start dragging
+ pView->BegDragObj(aStartPoint, nullptr, pHdl, 0);
+
+ if(pView->IsDragObj())
+ {
+ bool bWasNoSnap = rDragStat.IsNoSnap();
+ bool bWasSnapEnabled = pView->IsSnapEnabled();
+
+ // switch snapping off
+ if(!bWasNoSnap)
+ const_cast<SdrDragStat&>(rDragStat).SetNoSnap();
+ if(bWasSnapEnabled)
+ pView->SetSnapEnabled(false);
+
+ pView->MovAction(aEndPoint);
+ pView->EndDragObj();
+
+ // restore snap
+ if(!bWasNoSnap)
+ const_cast<SdrDragStat&>(rDragStat).SetNoSnap(bWasNoSnap);
+ if(bWasSnapEnabled)
+ pView->SetSnapEnabled(bWasSnapEnabled);
+ }
+
+ // make moved handle visible
+ tools::Rectangle aVisRect(aEndPoint - Point(100, 100), Size(200, 200));
+ pView->MakeVisible(aVisRect, *pWindow);
+
+ bReturn = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case KEY_SPACE:
+ {
+ // in calc do only something when draw objects are selected
+ if(pView->AreObjectsMarked())
+ {
+ const SdrHdlList& rHdlList = pView->GetHdlList();
+ SdrHdl* pHdl = rHdlList.GetFocusHdl();
+
+ if(pHdl)
+ {
+ if(pHdl->GetKind() == SdrHdlKind::Poly)
+ {
+ // rescue ID of point with focus
+ sal_uInt32 nPol(pHdl->GetPolyNum());
+ sal_uInt32 nPnt(pHdl->GetPointNum());
+
+ if(pView->IsPointMarked(*pHdl))
+ {
+ if(rKEvt.GetKeyCode().IsShift())
+ {
+ pView->UnmarkPoint(*pHdl);
+ }
+ }
+ else
+ {
+ if(!rKEvt.GetKeyCode().IsShift())
+ {
+ pView->UnmarkAllPoints();
+ }
+
+ pView->MarkPoint(*pHdl);
+ }
+
+ if(nullptr == rHdlList.GetFocusHdl())
+ {
+ // restore point with focus
+ SdrHdl* pNewOne = nullptr;
+
+ for(size_t a = 0; !pNewOne && a < rHdlList.GetHdlCount(); ++a)
+ {
+ SdrHdl* pAct = rHdlList.GetHdl(a);
+
+ if(pAct
+ && pAct->GetKind() == SdrHdlKind::Poly
+ && pAct->GetPolyNum() == nPol
+ && pAct->GetPointNum() == nPnt)
+ {
+ pNewOne = pAct;
+ }
+ }
+
+ if(pNewOne)
+ {
+ const_cast<SdrHdlList&>(rHdlList).SetFocusHdl(pNewOne);
+ }
+ }
+
+ bReturn = true;
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ if (!bReturn)
+ {
+ bReturn = FuPoor::KeyInput(rKEvt);
+ }
+
+ if (!bReturn)
+ {
+ // allow direct typing into a selected text object
+
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if( !pView->IsTextEdit() && 1 == rMarkList.GetMarkCount() && EditEngine::IsSimpleCharInput(rKEvt) )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ // start text edit for suitable object, pass key event to OutlinerView
+ if ( lcl_KeyEditMode( pObj, rViewShell, &rKEvt ) )
+ bReturn = true;
+ }
+ }
+
+ return bReturn;
+}
+
+// toggle mouse-pointer
+static bool lcl_UrlHit( const SdrView* pView, const Point& rPosPixel, const vcl::Window* pWindow )
+{
+ SdrViewEvent aVEvt;
+ MouseEvent aMEvt( rPosPixel, 1, MouseEventModifiers::NONE, MOUSE_LEFT );
+ SdrHitKind eHit = pView->PickAnything( aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt );
+
+ if (eHit != SdrHitKind::NONE && aVEvt.mpObj != nullptr)
+ {
+ if ( SvxIMapInfo::GetIMapInfo(aVEvt.mpObj) && SvxIMapInfo::GetHitIMapObject(
+ aVEvt.mpObj, pWindow->PixelToLogic(rPosPixel), pWindow->GetOutDev() ) )
+ return true;
+
+ if (aVEvt.meEvent == SdrEventKind::ExecuteUrl)
+ return true;
+ }
+
+ return false;
+}
+
+void FuDraw::ForcePointer(const MouseEvent* pMEvt)
+{
+ if ( pView->IsAction() )
+ return;
+
+ Point aPosPixel = pWindow->GetPointerPosPixel();
+ bool bAlt = pMEvt && pMEvt->IsMod2();
+ Point aPnt = pWindow->PixelToLogic( aPosPixel );
+ SdrHdl* pHdl = pView->PickHandle(aPnt);
+ SdrPageView* pPV;
+ SdrObject* pMacroPickObj;
+
+ ScMacroInfo* pInfo = nullptr;
+ SdrObject* pObj = pView->PickObj(aPnt, pView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
+ if (pObj)
+ {
+ if ( pObj->IsGroupObject() )
+ {
+ SdrObject* pHit = pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::DEEP);
+ if (pHit)
+ pObj = pHit;
+ }
+ pInfo = ScDrawLayer::GetMacroInfo( pObj );
+ }
+
+ if ( pView->IsTextEdit() )
+ {
+ rViewShell.SetActivePointer(PointerStyle::Text); // can't be ?
+ }
+ else if ( pHdl )
+ {
+ rViewShell.SetActivePointer(
+ pView->GetPreferredPointer( aPnt, pWindow->GetOutDev() ) );
+ }
+ else if ( pView->IsMarkedHit(aPnt) )
+ {
+ rViewShell.SetActivePointer( PointerStyle::Move );
+ }
+ else if ( !bAlt && ( !pMEvt || !pMEvt->GetButtons() )
+ && lcl_UrlHit( pView, aPosPixel, pWindow ) )
+ {
+ // could be suppressed with ALT
+ pWindow->SetPointer( PointerStyle::RefHand ); // Text-URL / ImageMap
+ }
+ else if ( !bAlt && (pMacroPickObj = pView->PickObj(aPnt, pView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO)) )
+ {
+ // could be suppressed with ALT
+ SdrObjMacroHitRec aHitRec; //! something missing ????
+ rViewShell.SetActivePointer(pMacroPickObj->GetMacroPointer(aHitRec));
+ }
+ else if ( !bAlt && pInfo && (!pInfo->GetMacro().isEmpty() || !pObj->getHyperlink().isEmpty()) )
+ pWindow->SetPointer( PointerStyle::RefHand );
+ else if ( IsDetectiveHit( aPnt ) )
+ rViewShell.SetActivePointer( PointerStyle::Detective );
+ else
+ {
+ const bool bIsThemed = rViewShell.GetViewData().IsThemedCursor();
+ rViewShell.SetActivePointer( bIsThemed ? PointerStyle::FatCross : PointerStyle::Arrow ); //! in Gridwin?
+ }
+}
+
+bool FuDraw::IsEditingANote() const
+{
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ const size_t backval=rMarkList.GetMarkCount();
+ for (size_t nlv1=0; nlv1<backval; ++nlv1)
+ {
+ SdrObject* pObj = rMarkList.GetMark( nlv1 )->GetMarkedSdrObj();
+ if ( ScDrawLayer::IsNoteCaption( pObj ) )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool FuDraw::IsSizingOrMovingNote( const MouseEvent& rMEvt ) const
+{
+ bool bIsSizingOrMoving = false;
+ if ( rMEvt.IsLeft() )
+ {
+ const SdrMarkList& rNoteMarkList = pView->GetMarkedObjectList();
+ if(rNoteMarkList.GetMarkCount() == 1)
+ {
+ SdrObject* pObj = rNoteMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ if ( ScDrawLayer::IsNoteCaption( pObj ) )
+ {
+ Point aMPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() );
+ bIsSizingOrMoving =
+ pView->PickHandle( aMPos ) || // handles to resize the note
+ pView->IsTextEditFrameHit( aMPos ); // frame for moving the note
+ }
+ }
+ }
+ return bIsSizingOrMoving;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fuins1.cxx b/sc/source/ui/drawfunc/fuins1.cxx
new file mode 100644
index 000000000..c6f2f69da
--- /dev/null
+++ b/sc/source/ui/drawfunc/fuins1.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 <config_features.h>
+
+#include <officecfg/Office/Common.hxx>
+#include <editeng/sizeitem.hxx>
+#include <sal/log.hxx>
+#include <sfx2/opengrf.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdomedia.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <svx/linkwarn.hxx>
+#include <svx/svxids.hrc>
+#include <vcl/graphicfilter.hxx>
+#include <svl/stritem.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/GraphicNativeTransform.hxx>
+#include <vcl/GraphicNativeMetadata.hxx>
+#include <fuinsert.hxx>
+#include <tabvwsh.hxx>
+#include <drwlayer.hxx>
+#include <drawview.hxx>
+#include <document.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <globstr.hrc>
+#include <comphelper/lok.hxx>
+
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+#include <com/sun/star/media/XPlayer.hpp>
+#include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp>
+#include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp>
+#include <com/sun/star/ui/dialogs/ListboxControlActions.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+void ScLimitSizeOnDrawPage( Size& rSize, Point& rPos, const Size& rPage )
+{
+ if ( !rPage.Width() || !rPage.Height() )
+ return;
+
+ Size aPageSize = rPage;
+ bool bNegative = aPageSize.Width() < 0;
+ if ( bNegative )
+ {
+ // make everything positive temporarily
+ aPageSize.setWidth( -aPageSize.Width() );
+ rPos.setX( -rPos.X() - rSize.Width() );
+ }
+
+ if ( rSize.Width() > aPageSize.Width() || rSize.Height() > aPageSize.Height() )
+ {
+ double fX = aPageSize.Width() / static_cast<double>(rSize.Width());
+ double fY = aPageSize.Height() / static_cast<double>(rSize.Height());
+
+ if ( fX < fY )
+ {
+ rSize.setWidth( aPageSize.Width() );
+ rSize.setHeight( static_cast<tools::Long>( rSize.Height() * fX ) );
+ }
+ else
+ {
+ rSize.setHeight( aPageSize.Height() );
+ rSize.setWidth( static_cast<tools::Long>( rSize.Width() * fY ) );
+ }
+
+ if (!rSize.Width())
+ rSize.setWidth( 1 );
+ if (!rSize.Height())
+ rSize.setHeight( 1 );
+ }
+
+ if ( rPos.X() + rSize.Width() > aPageSize.Width() )
+ rPos.setX( aPageSize.Width() - rSize.Width() );
+ if ( rPos.Y() + rSize.Height() > aPageSize.Height() )
+ rPos.setY( aPageSize.Height() - rSize.Height() );
+
+ if ( bNegative )
+ rPos.setX( -rPos.X() - rSize.Width() ); // back to real position
+}
+
+static void lcl_InsertGraphic( const Graphic& rGraphic,
+ const OUString& rFileName, bool bAsLink, bool bApi,
+ ScTabViewShell& rViewSh, const vcl::Window* pWindow, SdrView* pView,
+ ScAnchorType aAnchorType = SCA_CELL )
+{
+ Graphic& rGraphic1 = const_cast<Graphic &>(rGraphic);
+ GraphicNativeMetadata aMetadata;
+ if ( aMetadata.read(rGraphic1) )
+ {
+ const Degree10 aRotation = aMetadata.getRotation();
+ if (aRotation)
+ {
+ GraphicNativeTransform aTransform( rGraphic1 );
+ aTransform.rotate( aRotation );
+ }
+ }
+ ScDrawView* pDrawView = rViewSh.GetScDrawView();
+
+ // #i123922# check if an existing object is selected; if yes, evtl. replace
+ // the graphic for a SdrGraphObj (including link state updates) or adapt the fill
+ // style for other objects
+ if(pDrawView && 1 == pDrawView->GetMarkedObjectCount())
+ {
+ SdrObject* pPickObj = pDrawView->GetMarkedObjectByIndex(0);
+
+ if(pPickObj)
+ {
+ //sal_Int8 nAction(DND_ACTION_MOVE);
+ //Point aPos;
+ const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
+
+ SdrObject* pResult = pDrawView->ApplyGraphicToObject(
+ *pPickObj,
+ rGraphic1,
+ aBeginUndo,
+ bAsLink ? rFileName : OUString());
+
+ if(pResult)
+ {
+ // we are done; mark the modified/new object
+ pDrawView->MarkObj(pResult, pDrawView->GetSdrPageView());
+ return;
+ }
+ }
+ }
+
+ // set the size so the graphic has its original pixel size
+ // at 100% view scale (as in SetMarkedOriginalSize),
+ // instead of respecting the current view scale
+ MapMode aSourceMap = rGraphic.GetPrefMapMode();
+ MapMode aDestMap( MapUnit::Map100thMM );
+ if ( aSourceMap.GetMapUnit() == MapUnit::MapPixel && pDrawView )
+ {
+ Fraction aScaleX, aScaleY;
+ pDrawView->CalcNormScale( aScaleX, aScaleY );
+ aDestMap.SetScaleX(aScaleX);
+ aDestMap.SetScaleY(aScaleY);
+ }
+ Size aLogicSize = pWindow->LogicToLogic(
+ rGraphic.GetPrefSize(), &aSourceMap, &aDestMap );
+
+ // Limit size
+
+ SdrPageView* pPV = pView->GetSdrPageView();
+ SdrPage* pPage = pPV->GetPage();
+ Point aInsertPos = rViewSh.GetInsertPos();
+
+ ScViewData& rData = rViewSh.GetViewData();
+ if ( rData.GetDocument().IsNegativePage( rData.GetTabNo() ) )
+ aInsertPos.AdjustX( -(aLogicSize.Width()) ); // move position to left edge
+
+ ScLimitSizeOnDrawPage( aLogicSize, aInsertPos, pPage->GetSize() );
+
+ tools::Rectangle aRect ( aInsertPos, aLogicSize );
+
+ SdrGrafObj* pObj = new SdrGrafObj(
+ pView->getSdrModelFromSdrView(), // TTTT pView should be reference
+ rGraphic1,
+ aRect);
+
+ // calling SetGraphicLink here doesn't work
+ // Yes, due to the SdrObject had no SdrModel
+ // Path is no longer used as name for the graphics object
+
+ ScDrawLayer* pLayer = static_cast<ScDrawLayer*>(pView->GetModel());
+ OUString aName = pLayer->GetNewGraphicName(); // "Graphics"
+ pObj->SetName(aName);
+
+ if (aAnchorType == SCA_CELL || aAnchorType == SCA_CELL_RESIZE)
+ ScDrawLayer::SetCellAnchoredFromPosition(*pObj, rData.GetDocument(), rData.GetTabNo(),
+ aAnchorType == SCA_CELL_RESIZE);
+
+ // don't select if from (dispatch) API, to allow subsequent cell operations
+ SdrInsertFlags nInsOptions = (bApi && !comphelper::LibreOfficeKit::isActive()) ? SdrInsertFlags::DONTMARK : SdrInsertFlags::NONE;
+ bool bSuccess = pView->InsertObjectAtView( pObj, *pPV, nInsOptions );
+
+ // SetGraphicLink has to be used after inserting the object,
+ // otherwise an empty graphic is swapped in and the contact stuff crashes.
+ // See #i37444#.
+ if (bSuccess && bAsLink)
+ pObj->SetGraphicLink( rFileName );
+}
+
+static void lcl_InsertMedia( const OUString& rMediaURL, bool bApi,
+ ScTabViewShell* pViewSh, const vcl::Window* pWindow, SdrView* pView,
+ const Size& rPrefSize, bool const bLink )
+{
+ SdrPageView* pPV = pView->GetSdrPageView();
+ SdrPage* pPage = pPV->GetPage();
+ ScViewData& rData = pViewSh->GetViewData();
+ Point aInsertPos( pViewSh->GetInsertPos() );
+ Size aSize;
+
+ if( rPrefSize.Width() && rPrefSize.Height() )
+ {
+ if( pWindow )
+ aSize = pWindow->PixelToLogic(rPrefSize, MapMode(MapUnit::Map100thMM));
+ else
+ aSize = Application::GetDefaultDevice()->PixelToLogic(rPrefSize, MapMode(MapUnit::Map100thMM));
+ }
+ else
+ aSize = Size( 5000, 5000 );
+
+ ScLimitSizeOnDrawPage( aSize, aInsertPos, pPage->GetSize() );
+
+ if( rData.GetDocument().IsNegativePage( rData.GetTabNo() ) )
+ aInsertPos.AdjustX( -(aSize.Width()) );
+
+ OUString realURL;
+ if (bLink)
+ {
+ realURL = rMediaURL;
+ }
+ else
+ {
+ uno::Reference<frame::XModel> const xModel(
+ rData.GetDocument().GetDocumentShell()->GetModel());
+#if HAVE_FEATURE_AVMEDIA
+ bool const bRet = ::avmedia::EmbedMedia(xModel, rMediaURL, realURL);
+ if (!bRet) { return; }
+#else
+ return;
+#endif
+ }
+
+ SdrMediaObj* pObj = new SdrMediaObj(
+ *rData.GetDocument().GetDrawLayer(),
+ tools::Rectangle(aInsertPos, aSize));
+
+ pObj->setURL( realURL, ""/*TODO?*/ );
+ pView->InsertObjectAtView( pObj, *pPV, bApi ? SdrInsertFlags::DONTMARK : SdrInsertFlags::NONE );
+}
+
+FuInsertGraphic::FuInsertGraphic( ScTabViewShell& rViewSh,
+ vcl::Window* pWin,
+ ScDrawView* pViewP,
+ SdrModel* pDoc,
+ SfxRequest& rReq )
+ : FuPoor(rViewSh, pWin, pViewP, pDoc, rReq)
+{
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ const SfxStringItem* pGraphicItem;
+ if ( pReqArgs &&
+ (pGraphicItem = pReqArgs->GetItemIfSet( SID_INSERT_GRAPHIC, true )) )
+ {
+ OUString aFileName = pGraphicItem->GetValue();
+
+ OUString aFilterName;
+ if ( const SfxStringItem* pFilterItem = pReqArgs->GetItemIfSet( FN_PARAM_FILTER ) )
+ aFilterName = pFilterItem->GetValue();
+
+ bool bAsLink = false;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs->GetItemState( FN_PARAM_1, true, &pItem ) == SfxItemState::SET )
+ bAsLink = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ Graphic aGraphic;
+ ErrCode nError = GraphicFilter::LoadGraphic( aFileName, aFilterName, aGraphic, &GraphicFilter::GetGraphicFilter() );
+ if ( nError == ERRCODE_NONE )
+ {
+ lcl_InsertGraphic( aGraphic, aFileName, bAsLink, true, rViewSh, pWindow, pView );
+ }
+ }
+ else
+ {
+ SvxOpenGraphicDialog aDlg(ScResId(STR_INSERTGRAPHIC), pWin ? pWin->GetFrameWeld() : nullptr,
+ ui::dialogs::TemplateDescription::FILEOPEN_LINK_PREVIEW_IMAGE_ANCHOR);
+
+ Reference<ui::dialogs::XFilePickerControlAccess> xCtrlAcc = aDlg.GetFilePickerControlAccess();
+ sal_Int16 nSelect = 0;
+ Sequence<OUString> aListBoxEntries {
+ ScResId(STR_ANCHOR_TO_CELL),
+ ScResId(STR_ANCHOR_TO_CELL_RESIZE),
+ ScResId(STR_ANCHOR_TO_PAGE)
+ };
+ try
+ {
+ Any aTemplates(&aListBoxEntries, cppu::UnoType<decltype(aListBoxEntries)>::get());
+
+ xCtrlAcc->setValue(ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR,
+ ui::dialogs::ListboxControlActions::ADD_ITEMS, aTemplates);
+
+ Any aSelectPos(&nSelect, cppu::UnoType<decltype(nSelect)>::get());
+ xCtrlAcc->setValue(ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR,
+ ui::dialogs::ListboxControlActions::SET_SELECT_ITEM, aSelectPos);
+ }
+ catch (const Exception&)
+ {
+ SAL_WARN("sc", "control access failed");
+ }
+
+ if( aDlg.Execute() == ERRCODE_NONE )
+ {
+ Graphic aGraphic;
+ ErrCode nError = aDlg.GetGraphic(aGraphic);
+ if( nError == ERRCODE_NONE )
+ {
+ OUString aFileName = aDlg.GetPath();
+ const OUString& aFilterName = aDlg.GetDetectedFilter();
+ bool bAsLink = aDlg.IsAsLink();
+
+ // really store as link only?
+ if( bAsLink && officecfg::Office::Common::Misc::ShowLinkWarningDialog::get() )
+ {
+ SvxLinkWarningDialog aWarnDlg(pWin ? pWin->GetFrameWeld() : nullptr, aFileName);
+ if (aWarnDlg.run() != RET_OK)
+ bAsLink = false; // don't store as link
+ }
+
+ // Anchor to cell or to page?
+ Any aAnchorValue = xCtrlAcc->getValue(
+ ui::dialogs::ExtendedFilePickerElementIds::LISTBOX_IMAGE_ANCHOR,
+ ui::dialogs::ListboxControlActions::GET_SELECTED_ITEM );
+ OUString sAnchor;
+ aAnchorValue >>= sAnchor;
+
+ ScAnchorType aAnchorType;
+ if (sAnchor == ScResId(STR_ANCHOR_TO_CELL))
+ aAnchorType = SCA_CELL;
+ else if (sAnchor == ScResId(STR_ANCHOR_TO_CELL_RESIZE))
+ aAnchorType = SCA_CELL_RESIZE;
+ else if (sAnchor == ScResId(STR_ANCHOR_TO_PAGE))
+ aAnchorType = SCA_PAGE;
+ else
+ aAnchorType = SCA_DONTKNOW;
+
+ lcl_InsertGraphic( aGraphic, aFileName, bAsLink, false, rViewSh, pWindow, pView, aAnchorType );
+
+ // append items for recording
+ rReq.AppendItem( SfxStringItem( SID_INSERT_GRAPHIC, aFileName ) );
+ rReq.AppendItem( SfxStringItem( FN_PARAM_FILTER, aFilterName ) );
+ rReq.AppendItem( SfxBoolItem( FN_PARAM_1, bAsLink ) );
+ rReq.Done();
+ }
+ else
+ {
+ // error is handled in SvxOpenGraphicDialog::GetGraphic
+ }
+ }
+ }
+}
+
+FuInsertGraphic::~FuInsertGraphic()
+{
+}
+
+FuInsertMedia::FuInsertMedia( ScTabViewShell& rViewSh,
+ vcl::Window* pWin,
+ ScDrawView* pViewP,
+ SdrModel* pDoc,
+ const SfxRequest& rReq ) :
+ FuPoor(rViewSh, pWin, pViewP, pDoc, 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.getLength();
+ }
+ }
+
+ bool bLink(pLinkItem ? pLinkItem->GetValue() : true);
+ bool bInsertMedia = bAPI;
+ if (!bInsertMedia)
+ bInsertMedia = ::avmedia::MediaWindow::executeMediaURLDialog(pWin ? pWin->GetFrameWeld() : nullptr, aURL, &bLink);
+ if (!bInsertMedia)
+ return;
+
+ if (!bSizeUnknown)
+ {
+ aPrefSize = pSizeItem->GetSize();
+ }
+ else
+ {
+ if( pWin )
+ pWin->EnterWait();
+
+ css::uno::Reference<css::frame::XDispatchProvider> xDispatchProvider(rViewShell.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, ""/*TODO?*/, true, xPlayerListener);
+
+ if( pWin )
+ pWin->LeaveWait();
+
+ if (!bIsMediaURL && !bAPI)
+ ::avmedia::MediaWindow::executeFormatErrorBox(pWindow ? pWindow->GetFrameWeld() : nullptr);
+
+ return;
+ }
+
+ if (pWin)
+ pWin->EnterWait();
+
+ lcl_InsertMedia(aURL, bAPI, &rViewSh, pWindow, pView, aPrefSize, bLink);
+
+ if (pWin)
+ pWin->LeaveWait();
+#endif
+}
+
+FuInsertMedia::~FuInsertMedia()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fuins2.cxx b/sc/source/ui/drawfunc/fuins2.cxx
new file mode 100644
index 000000000..380a5b9ca
--- /dev/null
+++ b/sc/source/ui/drawfunc/fuins2.cxx
@@ -0,0 +1,689 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/Aspects.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <sot/exchange.hxx>
+#include <svl/globalnameitem.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/stritem.hxx>
+#include <svx/svdoole2.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <svtools/insdlg.hxx>
+#include <svtools/embedhlp.hxx>
+#include <svx/svxdlg.hxx>
+#include <comphelper/classids.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdundo.hxx>
+#include <sfx2/msgpool.hxx>
+#include <sfx2/msg.hxx>
+#include <scmod.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <comphelper/lok.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <com/sun/star/embed/EmbedVerbs.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/chart2/data/XDataReceiver.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <cppuhelper/bootstrap.hxx>
+#include <svtools/dialogclosedlistener.hxx>
+
+#include <PivotTableDataProvider.hxx>
+#include <chart2uno.hxx>
+#include <fuinsert.hxx>
+#include <tabvwsh.hxx>
+#include <sc.hrc>
+#include <chartpos.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <undotab.hxx>
+#include <uiitems.hxx>
+#include <drawview.hxx>
+#include <markdata.hxx>
+#include <dpobject.hxx>
+#include <memory>
+
+using namespace css;
+
+namespace
+{
+
+void lcl_ChartInit(const uno::Reference <embed::XEmbeddedObject>& xObj, ScViewData* pViewData,
+ const OUString& rRangeParam, bool bRangeIsPivotTable)
+{
+ ScDocShell* pDocShell = pViewData->GetDocShell();
+ ScDocument& rScDoc = pDocShell->GetDocument();
+
+ OUString aRangeString(rRangeParam);
+
+ if (aRangeString.isEmpty() && !bRangeIsPivotTable)
+ {
+ SCCOL nCol1 = 0;
+ SCROW nRow1 = 0;
+ SCTAB nTab1 = 0;
+ SCCOL nCol2 = 0;
+ SCROW nRow2 = 0;
+ SCTAB nTab2 = 0;
+
+ ScMarkData& rMark = pViewData->GetMarkData();
+ if ( !rMark.IsMarked() )
+ pViewData->GetView()->MarkDataArea();
+
+ if ( pViewData->GetSimpleArea( nCol1,nRow1,nTab1, nCol2,nRow2,nTab2 ) == SC_MARK_SIMPLE )
+ {
+ PutInOrder( nCol1, nCol2 );
+ PutInOrder( nRow1, nRow2 );
+ if (nCol2 >= nCol1 || nRow2 >= nRow1)
+ {
+ ScDocument& rDoc = pViewData->GetDocument();
+ rDoc.LimitChartArea( nTab1, nCol1,nRow1, nCol2,nRow2 );
+
+ ScRange aRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ aRangeString = aRange.Format(rScDoc, ScRefFlags::RANGE_ABS_3D, rScDoc.GetAddressConvention());
+ }
+ }
+ }
+
+ if (aRangeString.isEmpty())
+ return;
+
+ // connect to Calc data (if no range string, leave chart alone, with its own data)
+
+ uno::Reference< css::chart2::data::XDataReceiver > xReceiver;
+ if( xObj.is())
+ xReceiver.set( xObj->getComponent(), uno::UNO_QUERY );
+ OSL_ASSERT( xReceiver.is());
+ if( !xReceiver.is() )
+ return;
+
+ uno::Reference<chart2::data::XDataProvider> xDataProvider;
+ if (bRangeIsPivotTable)
+ {
+ rtl::Reference<sc::PivotTableDataProvider> pPivotTableDataProvider(new sc::PivotTableDataProvider(rScDoc));
+ pPivotTableDataProvider->setPivotTableName(aRangeString);
+ xDataProvider = pPivotTableDataProvider;
+ }
+ else
+ {
+ xDataProvider.set(new ScChart2DataProvider(&rScDoc));
+ }
+
+ xReceiver->attachDataProvider(xDataProvider);
+
+ uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( pDocShell->GetModel(), uno::UNO_QUERY );
+ xReceiver->attachNumberFormatsSupplier( xNumberFormatsSupplier );
+
+ // Same behavior as with old chart: Always assume data series in columns
+ chart::ChartDataRowSource eDataRowSource = chart::ChartDataRowSource_COLUMNS;
+ bool bHasCategories = false;
+ bool bFirstCellAsLabel = false;
+
+ // use ScChartPositioner to auto-detect column/row headers (like ScChartArray in old version)
+ ScRangeListRef aRangeListRef( new ScRangeList );
+ aRangeListRef->Parse( aRangeString, rScDoc, rScDoc.GetAddressConvention() );
+ if ( !aRangeListRef->empty() )
+ {
+ rScDoc.LimitChartIfAll( aRangeListRef ); // limit whole columns/rows to used area
+
+ // update string from modified ranges. The ranges must be in the current formula syntax.
+ OUString aTmpStr;
+ aRangeListRef->Format( aTmpStr, ScRefFlags::RANGE_ABS_3D, rScDoc, rScDoc.GetAddressConvention() );
+ aRangeString = aTmpStr;
+
+ ScChartPositioner aChartPositioner( rScDoc, aRangeListRef );
+ const ScChartPositionMap* pPositionMap( aChartPositioner.GetPositionMap() );
+ if( pPositionMap )
+ {
+ SCSIZE nRowCount = pPositionMap->GetRowCount();
+ if( 1==nRowCount )
+ eDataRowSource = chart::ChartDataRowSource_ROWS;
+ }
+ if ( eDataRowSource == chart::ChartDataRowSource_COLUMNS )
+ {
+ bHasCategories = aChartPositioner.HasRowHeaders();
+ bFirstCellAsLabel = aChartPositioner.HasColHeaders();
+ }
+ else // in case the default is changed
+ {
+ bHasCategories = aChartPositioner.HasColHeaders();
+ bFirstCellAsLabel = aChartPositioner.HasRowHeaders();
+ }
+ }
+
+ uno::Sequence< beans::PropertyValue > aArgs{
+ beans::PropertyValue(
+ "CellRangeRepresentation", -1,
+ uno::Any( aRangeString ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "HasCategories", -1,
+ uno::Any( bHasCategories ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "FirstCellAsLabel", -1,
+ uno::Any( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "DataRowSource", -1,
+ uno::Any( eDataRowSource ), beans::PropertyState_DIRECT_VALUE )
+ };
+
+ try
+ {
+ xReceiver->setArguments( aArgs );
+ }
+ catch (const lang::IllegalArgumentException&)
+ {
+ // Can happen for invalid aRangeString, in which case a Chart
+ // will be created nevertheless and the range string can be
+ // edited.
+ TOOLS_WARN_EXCEPTION("sc.ui",
+ "lcl_ChartInit - caught IllegalArgumentException might be due to aRangeString: " << aRangeString);
+ }
+
+ // don't create chart listener here (range may be modified in chart dialog)
+}
+
+}
+
+FuInsertOLE::FuInsertOLE(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
+ SdrModel* pDoc, SfxRequest& rReq)
+ : FuPoor(rViewSh, pWin, pViewP, pDoc, rReq)
+{
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+
+ //! initialize DLLs here, so that the factories exist?
+
+ uno::Reference < embed::XEmbeddedObject > xObj;
+ uno::Reference < embed::XStorage > xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
+ bool bIsFromFile = false;
+ OUString aName;
+
+ sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
+ OUString aIconMediaType;
+ uno::Reference< io::XInputStream > xIconMetaFile;
+
+ const sal_uInt16 nSlot = rReq.GetSlot();
+ const SfxGlobalNameItem* pNameItem = rReq.GetArg<SfxGlobalNameItem>(SID_INSERT_OBJECT);
+ if ( nSlot == SID_INSERT_OBJECT && pNameItem )
+ {
+ const SvGlobalName& aClassName = pNameItem->GetValue();
+ xObj = rViewShell.GetViewFrame()->GetObjectShell()->GetEmbeddedObjectContainer().CreateEmbeddedObject( aClassName.GetByteSequence(), aName );
+ }
+ else if ( nSlot == SID_INSERT_SMATH )
+ {
+ if ( SvtModuleOptions().IsMath() )
+ {
+ xObj = rViewShell.GetViewFrame()->GetObjectShell()->GetEmbeddedObjectContainer().CreateEmbeddedObject( SvGlobalName( SO3_SM_CLASSID_60 ).GetByteSequence(), aName );
+ rReq.AppendItem( SfxGlobalNameItem( SID_INSERT_OBJECT, SvGlobalName( SO3_SM_CLASSID_60 ) ) );
+ }
+ }
+ else
+ {
+ SvObjectServerList aServerLst;
+ switch ( nSlot )
+ {
+ case SID_INSERT_OBJECT :
+ aServerLst.FillInsertObjects();
+ aServerLst.Remove( ScDocShell::Factory().GetClassId() ); // Do not show Starcalc
+ //TODO/LATER: currently no inserting of ClassId into SfxRequest!
+ [[fallthrough]]; //TODO ???
+ case SID_INSERT_FLOATINGFRAME :
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractInsertObjectDialog> pDlg(
+ pFact->CreateInsertObjectDialog( rViewShell.GetFrameWeld(), SC_MOD()->GetSlotPool()->GetSlot(nSlot)->GetCommandString(),
+ xStorage, &aServerLst ));
+ if ( pDlg )
+ {
+ pDlg->Execute();
+ xObj = pDlg->GetObject();
+
+ xIconMetaFile = pDlg->GetIconIfIconified( &aIconMediaType );
+ if ( xIconMetaFile.is() )
+ nAspect = embed::Aspects::MSOLE_ICON;
+
+ if ( xObj.is() )
+ rViewSh.GetObjectShell()->GetEmbeddedObjectContainer().InsertEmbeddedObject( xObj, aName );
+ // to activate DrawShell (no need to activate Object)
+ bIsFromFile = !pDlg->IsCreateNew();
+ }
+
+ break;
+ }
+ }
+ }
+
+ // SvInsertObjectDialog (everything in one Dialog) are not used anymore
+ if (xObj.is())
+ {
+ pView->UnmarkAll();
+
+ try
+ {
+ ::svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
+ Size aSize;
+ MapMode aMap100( MapUnit::Map100thMM );
+ MapUnit aMapUnit = MapUnit::Map100thMM;
+
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ {
+ aObjRef.SetGraphicStream( xIconMetaFile, aIconMediaType );
+ aSize = aObjRef.GetSize( &aMap100 );
+ }
+ else
+ {
+ 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( 5000 );
+ aSize.setHeight( 5000 );
+ Size aTmp = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aMapUnit));
+ aSz.Width = aTmp.Width();
+ aSz.Height = aTmp.Height();
+ xObj->setVisualAreaSize( nAspect, aSz );
+
+ // re-convert aSize to 1/100th mm to avoid rounding errors in comparison below
+ aSize = OutputDevice::LogicToLogic( aTmp,
+ MapMode( aMapUnit ), aMap100 );
+ }
+ else
+ aSize = OutputDevice::LogicToLogic( aSize,
+ MapMode( aMapUnit ), aMap100 );
+ }
+
+ // initialize chart ?
+ if ( SvtModuleOptions().IsChart() && SotExchange::IsChart( SvGlobalName( xObj->getClassID() ) ) )
+ lcl_ChartInit(xObj, &rViewSh.GetViewData(), OUString(), false);
+
+ ScViewData& rData = rViewSh.GetViewData();
+
+ Point aPnt = rViewSh.GetInsertPos();
+ if ( rData.GetDocument().IsNegativePage( rData.GetTabNo() ) )
+ aPnt.AdjustX( -(aSize.Width()) ); // move position to left edge
+ tools::Rectangle aRect (aPnt, aSize);
+ SdrOle2Obj* pObj = new SdrOle2Obj(
+ *pDoc, // TTTT should be reference
+ aObjRef,
+ aName,
+ aRect);
+ SdrPageView* pPV = pView->GetSdrPageView();
+ bool bSuccess = pView->InsertObjectAtView(pObj, *pPV);
+
+ if (bSuccess && nAspect != embed::Aspects::MSOLE_ICON)
+ {
+ // Math objects change their object size during InsertObject.
+ // New size must be set in SdrObject, or a wrong scale will be set at
+ // ActivateObject.
+
+ try
+ {
+ awt::Size aSz = xObj->getVisualAreaSize( nAspect );
+
+ Size aNewSize( aSz.Width, aSz.Height );
+ aNewSize = OutputDevice::LogicToLogic(aNewSize, MapMode(aMapUnit), MapMode(MapUnit::Map100thMM));
+
+ if ( aNewSize != aSize )
+ {
+ aRect.SetSize( aNewSize );
+ pObj->SetLogicRect( aRect );
+ }
+ }
+ catch( embed::NoVisualAreaSizeException& )
+ {}
+ }
+
+ if ( !rReq.IsAPI() )
+ {
+ // XXX Activate from macro is deadly !!! ???
+ if (bIsFromFile)
+ {
+ // Object selected, activate Draw-Shell
+ rViewShell.SetDrawShell( true );
+ }
+ else if (bSuccess)
+ {
+ rViewShell.ActivateObject(pObj, embed::EmbedVerbs::MS_OLEVERB_SHOW);
+ }
+ }
+
+ rReq.Done();
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( "May need error handling here!" );
+ }
+ }
+ else
+ rReq.Ignore();
+}
+
+FuInsertChart::FuInsertChart(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
+ SdrModel* pDoc, SfxRequest& rReq, const Link<css::ui::dialogs::DialogClosedEvent*, void>& rLink)
+ : FuPoor(rViewSh, pWin, pViewP, pDoc, rReq)
+{
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+
+ if (!SvtModuleOptions().IsChart())
+ return;
+
+ // BM/IHA --
+
+ // get range
+ OUString aRangeString;
+ bool bRangeIsPivotTable = false;
+ ScRange aPositionRange; // cell range for chart positioning
+ ScMarkData aMark = rViewSh.GetViewData().GetMarkData();
+ if( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ if( pReqArgs->HasItem( FN_PARAM_5, &pItem ) )
+ aRangeString = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ aPositionRange = rViewSh.GetViewData().GetCurPos();
+ }
+ else
+ {
+ ScDocument& rDocument = rViewSh.GetViewData().GetDocument();
+ ScDPObject* pObject = rDocument.GetDPAtCursor(rViewSh.GetViewData().GetCurX(),
+ rViewSh.GetViewData().GetCurY(),
+ rViewSh.GetViewData().GetTabNo());
+ if (pObject)
+ {
+ aRangeString = pObject->GetName();
+ bRangeIsPivotTable = true;
+ }
+ else
+ {
+ bool bAutomaticMark = false;
+ if ( !aMark.IsMarked() && !aMark.IsMultiMarked() )
+ {
+ rViewSh.GetViewData().GetView()->MarkDataArea();
+ bAutomaticMark = true;
+ }
+
+ ScMarkData aMultiMark( aMark );
+ aMultiMark.MarkToMulti();
+
+ ScRangeList aRanges;
+ aMultiMark.FillRangeListWithMarks( &aRanges, false );
+ OUString aStr;
+ aRanges.Format( aStr, ScRefFlags::RANGE_ABS_3D, rDocument, rDocument.GetAddressConvention() );
+ aRangeString = aStr;
+
+ // get "total" range for positioning
+ if ( !aRanges.empty() )
+ {
+ aPositionRange = aRanges[ 0 ];
+ for ( size_t i = 1, nCount = aRanges.size(); i < nCount; ++i )
+ {
+ aPositionRange.ExtendTo( aRanges[ i ] );
+ }
+ }
+
+ if(bAutomaticMark)
+ rViewSh.GetViewData().GetView()->Unmark();
+ }
+ }
+
+ // adapted old code
+ pView->UnmarkAll();
+
+ OUString aName;
+ const sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
+
+ uno::Reference < embed::XEmbeddedObject > xObj =
+ rViewShell.GetObjectShell()->GetEmbeddedObjectContainer().CreateEmbeddedObject( SvGlobalName( SO3_SCH_CLASSID_60 ).GetByteSequence(), aName );
+
+ uno::Reference< css::chart2::data::XDataReceiver > xReceiver;
+ if( xObj.is())
+ xReceiver.set( xObj->getComponent(), uno::UNO_QUERY );
+
+ uno::Reference<chart2::XChartDocument> xChartDoc(xReceiver, uno::UNO_QUERY);
+ if (xChartDoc.is())
+ xChartDoc->createDefaultChart();
+
+ // lock the model to suppress any internal updates
+ uno::Reference< frame::XModel > xChartModel( xReceiver, uno::UNO_QUERY );
+ if( xChartModel.is() )
+ xChartModel->lockControllers();
+
+ // object size
+ awt::Size aSz = xObj->getVisualAreaSize( nAspect );
+ Size aSize( aSz.Width, aSz.Height );
+
+ MapUnit aMapUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
+
+ bool bSizeCh = false;
+ if (aSize.IsEmpty())
+ {
+ aSize.setWidth( 5000 );
+ aSize.setHeight( 5000 );
+ bSizeCh = true;
+ }
+ if (bSizeCh)
+ {
+ aSize = OutputDevice::LogicToLogic( aSize, MapMode( MapUnit::Map100thMM ), MapMode( aMapUnit ) );
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+ xObj->setVisualAreaSize( nAspect, aSz );
+ }
+
+ ScViewData& rData = rViewSh.GetViewData();
+ ScDocShell* pScDocSh = rData.GetDocShell();
+ ScDocument& rScDoc = pScDocSh->GetDocument();
+ bool bUndo (rScDoc.IsUndoEnabled());
+
+ if( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ sal_uInt16 nToTable = 0;
+
+ if( pReqArgs->HasItem( FN_PARAM_4, &pItem ) )
+ {
+ if ( auto pUInt16Item = dynamic_cast<const SfxUInt16Item*>( pItem) )
+ nToTable = pUInt16Item->GetValue();
+ else if ( auto pBoolItem = dynamic_cast<const SfxBoolItem*>( pItem) )
+ {
+ // In IDL for Basic FN_PARAM_4 means SfxBoolItem
+ // -> if set new table, else current table
+
+ if ( pBoolItem->GetValue() )
+ nToTable = static_cast<sal_uInt16>(rScDoc.GetTableCount());
+ else
+ nToTable = static_cast<sal_uInt16>(rData.GetTabNo());
+ }
+ }
+ else
+ {
+ rReq.AppendItem( SfxUInt16Item( FN_PARAM_4, nToTable ) );
+ }
+
+ // Output on new table?
+ if ( nToTable == rScDoc.GetTableCount() )
+ {
+ // Let's go...
+ OUString aTabName;
+ SCTAB nNewTab = rScDoc.GetTableCount();
+
+ rScDoc.CreateValidTabName( aTabName );
+
+ if ( rScDoc.InsertTab( nNewTab, aTabName ) )
+ {
+ if (bUndo)
+ {
+ pScDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoInsertTab>( pScDocSh, nNewTab,
+ true/*bAppend*/, aTabName ) );
+ }
+
+ pScDocSh->Broadcast( ScTablesHint( SC_TAB_INSERTED, nNewTab ) );
+ rViewSh.SetTabNo( nNewTab, true );
+ pScDocSh->PostPaintExtras(); //! done afterwards ???
+ }
+ else
+ {
+ OSL_FAIL( "Could not create new table :-/" );
+ }
+ }
+ else if ( nToTable != rData.GetTabNo() )
+ {
+ rViewSh.SetTabNo( nToTable, true );
+ }
+ }
+
+ lcl_ChartInit(xObj, &rData, aRangeString, bRangeIsPivotTable); // set source range, auto-detect column/row headers
+
+ // object position
+
+ // get chart position (from window size and data range)
+ Point aStart = rViewSh.GetChartInsertPos( aSize, aPositionRange );
+
+ tools::Rectangle aRect (aStart, aSize);
+ SdrOle2Obj* pObj = new SdrOle2Obj(
+ *pDoc, // TTTT should be reference
+ svt::EmbeddedObjectRef(xObj, nAspect),
+ aName,
+ aRect);
+ SdrPageView* pPV = pView->GetSdrPageView();
+
+ // #i121334# This call will change the chart's default background fill from white to transparent.
+ // Add here again if this is wanted (see task description for details)
+ // ChartHelper::AdaptDefaultsForChart( xObj );
+
+// pView->InsertObjectAtView(pObj, *pPV);//this call leads to an immediate redraw and asks the chart for a visual representation
+
+ // use the page instead of the view to insert, so no undo action is created yet
+ SdrPage* pPage = pPV->GetPage();
+ pPage->InsertObject( pObj );
+ pView->UnmarkAllObj();
+ pView->MarkObj( pObj, pPV );
+
+ if (rReq.IsAPI())
+ {
+ if( xChartModel.is() )
+ xChartModel->unlockControllers();
+ }
+ else if (!rViewSh.isLOKMobilePhone())
+ {
+ //the controller will be unlocked by the dialog when the dialog is told to do so
+
+ // only activate object if not called via API (e.g. macro)
+ if (!comphelper::LibreOfficeKit::isActive())
+ rViewShell.ActivateObject(pObj, embed::EmbedVerbs::MS_OLEVERB_SHOW);
+
+ //open wizard
+ //@todo get context from calc if that has one
+ uno::Reference< uno::XComponentContext > xContext(
+ ::cppu::defaultBootstrap_InitialComponentContext() );
+ if(xContext.is())
+ {
+ uno::Reference< lang::XMultiComponentFactory > xMCF( xContext->getServiceManager() );
+ if(xMCF.is())
+ {
+ css::uno::Reference<css::ui::dialogs::XAsynchronousExecutableDialog> xDialog(
+ xMCF->createInstanceWithContext(
+ "com.sun.star.comp.chart2.WizardDialog"
+ , xContext), uno::UNO_QUERY);
+ uno::Reference< lang::XInitialization > xInit( xDialog, uno::UNO_QUERY );
+ if( xChartModel.is() && xInit.is() )
+ {
+ uno::Sequence<uno::Any> aSeq(comphelper::InitAnyPropertySequence(
+ {
+ {"ParentWindow", uno::Any(uno::Reference< awt::XWindow >())},
+ {"ChartModel", uno::Any(xChartModel)}
+ }));
+ xInit->initialize( aSeq );
+
+ // try to set the dialog's position so it doesn't hide the chart
+ uno::Reference < beans::XPropertySet > xDialogProps( xDialog, uno::UNO_QUERY );
+ if ( xDialogProps.is() )
+ {
+ try
+ {
+ //get dialog size:
+ awt::Size aDialogAWTSize;
+ if( xDialogProps->getPropertyValue("Size")
+ >>= aDialogAWTSize )
+ {
+ Size aDialogSize( aDialogAWTSize.Width, aDialogAWTSize.Height );
+ if ( !aDialogSize.IsEmpty() )
+ {
+ //calculate and set new position
+ Point aDialogPos = rViewShell.GetChartDialogPos( aDialogSize, aRect );
+ xDialogProps->setPropertyValue("Position",
+ uno::Any( awt::Point(aDialogPos.getX(),aDialogPos.getY()) ) );
+ }
+ }
+ //tell the dialog to unlock controller
+ xDialogProps->setPropertyValue("UnlockControllersOnExecute",
+ uno::Any( true ) );
+
+ }
+ catch( uno::Exception& )
+ {
+ OSL_FAIL( "Chart wizard couldn't be positioned automatically" );
+ }
+ }
+
+ pView->AddUndo(std::make_unique<SdrUndoNewObj>(*pObj));
+ rtl::Reference<::svt::DialogClosedListener> pListener = new ::svt::DialogClosedListener();
+ pListener->SetDialogClosedLink( rLink );
+
+ xDialog->startExecuteModal( pListener );
+ }
+ else
+ {
+ uno::Reference< lang::XComponent > xComponent( xDialog, uno::UNO_QUERY );
+ if( xComponent.is())
+ xComponent->dispose();
+ }
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fupoor.cxx b/sc/source/ui/drawfunc/fupoor.cxx
new file mode 100644
index 000000000..decfacebe
--- /dev/null
+++ b/sc/source/ui/drawfunc/fupoor.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 <editeng/outliner.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svxids.hrc>
+
+#include <fupoor.hxx>
+#include <tabvwsh.hxx>
+#include <drawview.hxx>
+#include <detfunc.hxx>
+#include <document.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/sdrhittesthelper.hxx>
+
+FuPoor::FuPoor(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
+ SdrModel* pDoc, const SfxRequest& rReq) :
+ pView(pViewP),
+ rViewShell(rViewSh),
+ pWindow(pWin),
+ pDrDoc(pDoc),
+ aSfxRequest(rReq),
+ aScrollTimer("sc FuPoor aScrollTimer"),
+ aDragTimer("sc FuPoor aDragTimer"),
+ bIsInDragMode(false),
+ // remember MouseButton state
+ mnCode(0)
+{
+ aScrollTimer.SetInvokeHandler( LINK(this, FuPoor, ScrollHdl) );
+ aScrollTimer.SetTimeout(SELENG_AUTOREPEAT_INTERVAL);
+
+ aDragTimer.SetInvokeHandler( LINK(this, FuPoor, DragTimerHdl) );
+ aDragTimer.SetTimeout(SELENG_DRAGDROP_TIMEOUT);
+}
+
+FuPoor::~FuPoor()
+{
+ aDragTimer.Stop();
+ aScrollTimer.Stop();
+}
+
+void FuPoor::Activate()
+{
+}
+
+void FuPoor::Deactivate()
+{
+ aDragTimer.Stop();
+ aScrollTimer.Stop();
+}
+
+// Scroll when reached the window border; is called from MouseMove
+void FuPoor::ForceScroll(const Point& aPixPos)
+{
+ aScrollTimer.Stop();
+
+ Size aSize = pWindow->GetSizePixel();
+ SCCOL dx = 0;
+ SCROW dy = 0;
+
+ if ( aPixPos.X() <= 0 ) dx = -1;
+ if ( aPixPos.X() >= aSize.Width() ) dx = 1;
+ if ( aPixPos.Y() <= 0 ) dy = -1;
+ if ( aPixPos.Y() >= aSize.Height() ) dy = 1;
+
+ ScViewData& rViewData = rViewShell.GetViewData();
+ if ( rViewData.GetDocument().IsNegativePage( rViewData.GetTabNo() ) )
+ dx = -dx;
+
+ ScSplitPos eWhich = rViewData.GetActivePart();
+ if ( dx > 0 && rViewData.GetHSplitMode() == SC_SPLIT_FIX && WhichH(eWhich) == SC_SPLIT_LEFT )
+ {
+ rViewShell.ActivatePart( ( eWhich == SC_SPLIT_TOPLEFT ) ?
+ SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT );
+ dx = 0;
+ }
+ if ( dy > 0 && rViewData.GetVSplitMode() == SC_SPLIT_FIX && WhichV(eWhich) == SC_SPLIT_TOP )
+ {
+ rViewShell.ActivatePart( ( eWhich == SC_SPLIT_TOPLEFT ) ?
+ SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT );
+ dy = 0;
+ }
+
+ if ( dx != 0 || dy != 0 )
+ {
+ rViewShell.ScrollLines(2*dx, 4*dy);
+ aScrollTimer.Start();
+ }
+}
+
+// Timer handler for window scrolling
+IMPL_LINK_NOARG(FuPoor, ScrollHdl, Timer *, void)
+{
+ Point aPosPixel = pWindow->GetPointerPosPixel();
+
+ // use remembered MouseButton state to create correct
+ // MouseEvents for this artificial MouseMove.
+ MouseMove(MouseEvent(aPosPixel, 1, MouseEventModifiers::NONE, GetMouseButtonCode()));
+}
+
+bool FuPoor::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ return false;
+}
+
+bool FuPoor::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ return false;
+}
+
+// If we handle a KeyEvent, then the return value is sal_True else FALSE.
+bool FuPoor::KeyInput(const KeyEvent& /* rKEvt */)
+{
+ return false;
+}
+
+sal_uInt8 FuPoor::Command(const CommandEvent& rCEvt)
+{
+ if ( CommandEventId::StartDrag == rCEvt.GetCommand() )
+ {
+ // Only if a selection is in Outliner, then Command is allowed
+ // to return sal_True
+
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+
+ if ( pOutView )
+ return pOutView->HasSelection() ? (pView->Command(rCEvt,pWindow) ? 1 : 0) : SC_CMD_NONE;
+ else
+ return pView->Command(rCEvt,pWindow) ? 1 : 0;
+ }
+ else
+ return pView->Command(rCEvt,pWindow) ? 1 : 0;
+}
+
+// Timer-Handler for Drag&Drop
+IMPL_LINK_NOARG(FuPoor, DragTimerHdl, Timer *, void)
+{
+ // Calling ExecuteDrag (and that associated reschedule) directly from
+ // the Timer, will confuse the VCL-Timer-Management, if (e.g during Drop)
+ // a new timer is started (e.g ComeBack-Timer of DrawView for
+ // Solid Handles / ModelHasChanged) - the new timer will end with a delay
+ // of the duration of the Drag&Drop.
+ // Therefore Drag&Drop from own event:
+
+ Application::PostUserEvent( LINK( this, FuPoor, DragHdl ) );
+}
+
+IMPL_LINK_NOARG(FuPoor, DragHdl, void*, void)
+{
+ SdrHdl* pHdl = pView->PickHandle(aMDPos);
+
+ if ( pHdl==nullptr && pView->IsMarkedHit(aMDPos) )
+ {
+ pWindow->ReleaseMouse();
+ bIsInDragMode = true;
+ rViewShell.GetScDrawView()->BeginDrag(pWindow, aMDPos);
+ }
+}
+
+// Detective-line
+bool FuPoor::IsDetectiveHit( const Point& rLogicPos )
+{
+ SdrPageView* pPV = pView->GetSdrPageView();
+ if (!pPV)
+ return false;
+
+ bool bFound = false;
+ SdrObjListIter aIter( pPV->GetObjList(), SdrIterMode::Flat );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bFound)
+ {
+ if (ScDetectiveFunc::IsNonAlienArrow( pObject ))
+ {
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(pWindow->PixelToLogic(
+ Size(pView->GetHitTolerancePixel(),0)).Width());
+ if(SdrObjectPrimitiveHit(*pObject, rLogicPos, nHitLog, *pPV, nullptr, false))
+ {
+ bFound = true;
+ }
+ }
+
+ pObject = aIter.Next();
+ }
+ return bFound;
+}
+
+void FuPoor::StopDragTimer()
+{
+ if (aDragTimer.IsActive() )
+ aDragTimer.Stop();
+}
+
+// Create default drawing objects via keyboard
+SdrObjectUniquePtr FuPoor::CreateDefaultObject(const sal_uInt16 /* nID */, const tools::Rectangle& /* rRectangle */)
+{
+ // 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()));
+ }
+}
+
+// #i33136# fdo#88339
+bool FuPoor::doConstructOrthogonal() const
+{
+ // Detect whether we're moving an object or resizing.
+ if (pView->IsDragObj())
+ {
+ const SdrHdl* pHdl = pView->GetDragStat().GetHdl();
+ if (!pHdl || (!pHdl->IsCornerHdl() && !pHdl->IsVertexHdl()))
+ {
+ return false;
+ }
+ }
+
+ // Detect image/media and resize proportionally, but don't constrain movement by default
+ if (pView->AreObjectsMarked())
+ {
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrObjKind aObjIdentifier = rMarkList.GetMark(0)->GetMarkedSdrObj()->GetObjIdentifier();
+ bool bIsMediaSelected = aObjIdentifier == SdrObjKind::Graphic ||
+ aObjIdentifier == SdrObjKind::Media ||
+ aObjIdentifier == SdrObjKind::OLE2;
+
+ SdrHdl* pHdl = pView->PickHandle(aMDPos);
+ // Resize proportionally when media is selected and the user drags on a corner
+ if (pHdl)
+ return bIsMediaSelected && pHdl->IsCornerHdl();
+ return bIsMediaSelected;
+ }
+ }
+ else if (aSfxRequest.GetSlot() == SID_DRAW_XPOLYGON
+ || aSfxRequest.GetSlot() == SID_DRAW_XPOLYGON_NOFILL
+ || aSfxRequest.GetSlot() == SID_DRAW_XLINE)
+ return true;
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fusel.cxx b/sc/source/ui/drawfunc/fusel.cxx
new file mode 100644
index 000000000..46b7fc47d
--- /dev/null
+++ b/sc/source/ui/drawfunc/fusel.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 <com/sun/star/embed/EmbedVerbs.hpp>
+#include <editeng/flditem.hxx>
+#include <svx/svddrgmt.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdotext.hxx>
+#include <sfx2/dispatch.hxx>
+#include <vcl/imapobj.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdomedia.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <editeng/outlobj.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/ipclient.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <comphelper/lok.hxx>
+
+#include <fusel.hxx>
+#include <sc.hrc>
+#include <fudraw.hxx>
+#include <futext.hxx>
+#include <drawview.hxx>
+#include <tabvwsh.hxx>
+#include <drwlayer.hxx>
+#include <userdat.hxx>
+#include <scmod.hxx>
+#include <charthelper.hxx>
+#include <docuno.hxx>
+#include <docsh.hxx>
+
+// maximal permitted mouse movement to start Drag&Drop
+//! fusel,fuconstr,futext - combine them!
+#define SC_MAXDRAGMOVE 3
+// Min necessary mouse motion for normal dragging
+#define SC_MINDRAGMOVE 2
+
+using namespace com::sun::star;
+
+FuSelection::FuSelection(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
+ SdrModel* pDoc, const SfxRequest& rReq)
+ : FuDraw(rViewSh, pWin, pViewP, pDoc, rReq)
+{
+}
+
+FuSelection::~FuSelection()
+{
+}
+
+bool FuSelection::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+ const bool bSelectionOnly = rMEvt.IsRight();
+ if ( pView->IsAction() )
+ {
+ if ( bSelectionOnly )
+ pView->BckAction();
+ return true;
+ }
+
+ bIsInDragMode = false; // somewhere it has to be reset (#50033#)
+
+ bool bReturn = FuDraw::MouseButtonDown(rMEvt);
+ auto aLogicPosition = rMEvt.getLogicPosition();
+ if (aLogicPosition)
+ aMDPos = *aLogicPosition;
+ else
+ aMDPos = pWindow->PixelToLogic(rMEvt.GetPosPixel());
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScViewData& rViewData = rViewShell.GetViewData();
+ ScDocument& rDocument = rViewData.GetDocument();
+ if (rDocument.IsNegativePage(rViewData.GetTabNo()))
+ aMDPos.setX(-aMDPos.X());
+ }
+
+ if ( rMEvt.IsLeft() )
+ {
+ SdrHdl* pHdl = pView->PickHandle(aMDPos);
+
+ if ( pHdl!=nullptr || pView->IsMarkedHit(aMDPos) )
+ {
+ // Determine if this is the tail of a SdrCaptionObj i.e.
+ // we need to disable the drag option on the tail of a note
+ // object. Also, disable the ability to use the circular
+ // drag of a note object.
+ bool bDrag = false;
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pMarkedObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ if( ScDrawLayer::IsNoteCaption( pMarkedObj ) )
+ {
+ // move using the valid caption handles for note text box.
+ if(pHdl && (pHdl->GetKind() != SdrHdlKind::Poly && pHdl->GetKind() != SdrHdlKind::Circle))
+ bDrag = true;
+ // move the complete note box.
+ else if(!pHdl)
+ bDrag = true;
+ }
+ else
+ bDrag = true; // different object
+ }
+ else
+ bDrag = true; // several objects
+
+ if ( bDrag )
+ {
+ aDragTimer.Start();
+ if (pView->BegDragObj(aMDPos, nullptr, pHdl))
+ pView->GetDragMethod()->SetShiftPressed( rMEvt.IsShift() );
+ bReturn = true;
+ }
+ }
+ else
+ {
+ SdrPageView* pPV = nullptr;
+ bool bAlt = rMEvt.IsMod2();
+ SdrObject* pObj = !bAlt ? pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::PICKMACRO) : nullptr;
+ if (pObj)
+ {
+ pView->BegMacroObj(aMDPos, pObj, pPV, pWindow);
+ bReturn = true;
+ }
+ else
+ {
+ OUString sURL, sTarget;
+ pObj = !bAlt ? pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER) : nullptr;
+ if (pObj)
+ {
+ // Support for imported Excel docs
+ // Excel is of course not consistent and allows
+ // a hyperlink to be assigned for an object group
+ // and even though the hyperlink is exported in the Escher layer
+ // its never used, when dealing with a group object the link
+ // associated with the clicked object is used only
+
+ // additionally you can also select a macro in Excel for a grouped
+ // objects and this *usually* results in the macro being set
+ // for the elements in the group and no macro is exported
+ // for the group itself ( this however is not always true )
+ // if a macro and hlink are defined favour the hlink
+ // If a group object has no hyperlink use the hyperlink of the
+ // object clicked
+
+ if ( pObj->IsGroupObject() )
+ {
+ ScMacroInfo* pTmpInfo = ScDrawLayer::GetMacroInfo( pObj );
+ if ( !pTmpInfo || pTmpInfo->GetMacro().isEmpty() )
+ {
+ SdrObject* pHit = pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::DEEP);
+ if (pHit)
+ pObj = pHit;
+ }
+ }
+
+ ScMacroInfo* pInfo = ScDrawLayer::GetMacroInfo( pObj, true );
+ // For interoperability favour links over macros if both are defined
+ if ( !pObj->getHyperlink().isEmpty() )
+ {
+ sURL = pObj->getHyperlink();
+ }
+ else if ( !pInfo->GetMacro().isEmpty() )
+ {
+ SfxObjectShell* pObjSh = SfxObjectShell::Current();
+ if ( pObjSh && SfxApplication::IsXScriptURL( pInfo->GetMacro() ) )
+ {
+ uno::Reference< beans::XPropertySet > xProps( pObj->getUnoShape(), uno::UNO_QUERY );
+ uno::Any aCaller;
+ if ( xProps.is() )
+ {
+ try
+ {
+ aCaller = xProps->getPropertyValue("Name");
+ }
+ catch( uno::Exception& ) {}
+ }
+ uno::Any aRet;
+ uno::Sequence< sal_Int16 > aOutArgsIndex;
+ uno::Sequence< uno::Any > aOutArgs;
+ uno::Sequence< uno::Any > aInArgs;
+ pObjSh->CallXScript( pInfo->GetMacro(),
+ aInArgs, aRet, aOutArgsIndex, aOutArgs, true, &aCaller );
+ rViewShell.FakeButtonUp( rViewShell.GetViewData().GetActivePart() );
+ return true; // no CaptureMouse etc.
+ }
+ }
+ }
+
+ // URL / ImageMap
+
+ SdrViewEvent aVEvt;
+ if ( !bAlt &&
+ pView->PickAnything( rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt ) != SdrHitKind::NONE &&
+ aVEvt.mpObj != nullptr )
+ {
+ if ( SvxIMapInfo::GetIMapInfo( aVEvt.mpObj ) ) // ImageMap
+ {
+ const IMapObject* pIMapObj =
+ SvxIMapInfo::GetHitIMapObject( aVEvt.mpObj, aMDPos, pWindow->GetOutDev() );
+ if ( pIMapObj && !pIMapObj->GetURL().isEmpty() )
+ {
+ sURL = pIMapObj->GetURL();
+ sTarget = pIMapObj->GetTarget();
+ }
+ }
+ if ( aVEvt.meEvent == SdrEventKind::ExecuteUrl && aVEvt.mpURLField ) // URL
+ {
+ sURL = aVEvt.mpURLField->GetURL();
+ sTarget = aVEvt.mpURLField->GetTargetFrame();
+ }
+ }
+
+ // open hyperlink, if found at object or in object's text
+ // Fragments pointing into the current document should be always opened.
+ if ( !sURL.isEmpty() && (ScGlobal::ShouldOpenURL() || sURL.startsWith("#")) )
+ {
+ ScGlobal::OpenURL( sURL, sTarget );
+ rViewShell.FakeButtonUp( rViewShell.GetViewData().GetActivePart() );
+ return true; // no CaptureMouse etc.
+ }
+
+ // Is another object being edited in this view?
+ // (Editing is ended in MarkListHasChanged - test before UnmarkAll)
+ SfxInPlaceClient* pClient = rViewShell.GetIPClient();
+ bool bWasOleActive = ( pClient && pClient->IsObjectInPlaceActive() );
+
+ // Selection
+
+ // do not allow multiselection with note caption
+ bool bCaptionClicked = IsNoteCaptionClicked( aMDPos );
+ if ( !rMEvt.IsShift() || bCaptionClicked || IsNoteCaptionMarked() )
+ pView->UnmarkAll();
+
+ /* Unlock internal layer, if a note caption is clicked. The
+ layer will be relocked in ScDrawView::MarkListHasChanged(). */
+ if( bCaptionClicked )
+ pView->UnlockInternalLayer();
+
+ // try to select the clicked object
+ if ( pView->MarkObj( aMDPos, -2, false, rMEvt.IsMod1() ) )
+ {
+
+ // move object
+
+ if (pView->IsMarkedHit(aMDPos))
+ {
+ // Don't start drag timer if inplace editing of an OLE object
+ // was just ended with this mouse click - the view will be moved
+ // (different tool bars) and the object that was clicked on would
+ // be moved unintentionally.
+ if ( !bWasOleActive )
+ aDragTimer.Start();
+
+ pHdl=pView->PickHandle(aMDPos);
+ pView->BegDragObj(aMDPos, nullptr, pHdl);
+ bReturn = true;
+ }
+ else // object at the edge
+ if (rViewShell.IsDrawSelMode())
+ bReturn = true;
+ }
+ else
+ {
+ if (rViewShell.IsDrawSelMode())
+ {
+
+ // select object
+
+ pView->BegMarkObj(aMDPos);
+ bReturn = true;
+ }
+ }
+ }
+ }
+
+ }
+
+ if (!bIsInDragMode)
+ {
+ // VC calls CaptureMouse itself
+ pWindow->CaptureMouse();
+ ForcePointer(&rMEvt);
+ }
+
+ return bReturn;
+}
+
+bool FuSelection::MouseMove(const MouseEvent& rMEvt)
+{
+ bool bReturn = FuDraw::MouseMove(rMEvt);
+
+ if (aDragTimer.IsActive() )
+ {
+ Point aOldPixel = pWindow->LogicToPixel( aMDPos );
+ Point aNewPixel = rMEvt.GetPosPixel();
+ if ( std::abs( aOldPixel.X() - aNewPixel.X() ) > SC_MAXDRAGMOVE ||
+ std::abs( aOldPixel.Y() - aNewPixel.Y() ) > SC_MAXDRAGMOVE )
+ aDragTimer.Stop();
+ }
+
+ if ( pView->IsAction() )
+ {
+ Point aPix(rMEvt.GetPosPixel());
+ Point aPnt(pWindow->PixelToLogic(aPix));
+
+ ForceScroll(aPix);
+ pView->MovAction(aPnt);
+ bReturn = true;
+ }
+
+ ForcePointer(&rMEvt);
+
+ return bReturn;
+}
+
+bool FuSelection::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ bool bReturn = FuDraw::MouseButtonUp(rMEvt);
+ bool bOle = rViewShell.GetViewFrame()->GetFrame().IsInPlace();
+
+ SdrObject* pObj = nullptr;
+ if (aDragTimer.IsActive() )
+ {
+ aDragTimer.Stop();
+ }
+
+ sal_uInt16 nDrgLog = sal_uInt16 ( pWindow->PixelToLogic(Size(SC_MINDRAGMOVE,0)).Width() );
+ auto aLogicPosition = rMEvt.getLogicPosition();
+ Point aPnt(aLogicPosition ? *aLogicPosition : pWindow->PixelToLogic(rMEvt.GetPosPixel()));
+
+ bool bCopy = false;
+ ScViewData& rViewData = rViewShell.GetViewData();
+ ScDocument& rDocument = rViewData.GetDocument();
+ SdrPageView* pPageView = ( pView ? pView->GetSdrPageView() : nullptr );
+ SdrPage* pPage = ( pPageView ? pPageView->GetPage() : nullptr );
+ ::std::vector< OUString > aExcludedChartNames;
+ ScRangeListVector aProtectedChartRangesVector;
+
+ if (comphelper::LibreOfficeKit::isActive() && rDocument.IsNegativePage(rViewData.GetTabNo()))
+ aPnt.setX(-aPnt.X());
+
+ if (pView && rMEvt.IsLeft())
+ {
+ if ( pView->IsDragObj() )
+ {
+ // object was moved
+ if ( rMEvt.IsMod1() )
+ {
+ if ( pPage )
+ {
+ ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
+ }
+ if ( pView )
+ {
+ const SdrMarkList& rSdrMarkList = pView->GetMarkedObjectList();
+ const size_t nMarkCount = rSdrMarkList.GetMarkCount();
+ for ( size_t i = 0; i < nMarkCount; ++i )
+ {
+ SdrMark* pMark = rSdrMarkList.GetMark( i );
+ pObj = ( pMark ? pMark->GetMarkedSdrObj() : nullptr );
+ if ( pObj )
+ {
+ ScChartHelper::AddRangesIfProtectedChart( aProtectedChartRangesVector, rDocument, pObj );
+ }
+ }
+ }
+ bCopy = true;
+ }
+
+ if (!rMEvt.IsShift() && !rMEvt.IsMod1() && !rMEvt.IsMod2() &&
+ 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 = nullptr;
+ pObj = pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::BEFOREMARK);
+ if (pObj)
+ {
+ pView->UnmarkAllObj();
+ pView->MarkObj(pObj,pPV);
+ return true;
+ }
+ }
+ pView->EndDragObj( rMEvt.IsMod1() );
+ pView->ForceMarkedToAnotherPage();
+
+ bReturn = true;
+ }
+ else if (pView->IsAction() )
+ {
+ // unlock internal layer to include note captions
+ pView->UnlockInternalLayer();
+ pView->EndAction();
+ if ( pView->AreObjectsMarked() )
+ {
+ bReturn = true;
+
+ /* if multi-selection contains a note caption object, remove
+ all other objects from selection. */
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ const size_t nCount = rMarkList.GetMarkCount();
+ if( nCount > 1 )
+ {
+ bool bFound = false;
+ for( size_t nIdx = 0; !bFound && (nIdx < nCount); ++nIdx )
+ {
+ pObj = rMarkList.GetMark( nIdx )->GetMarkedSdrObj();
+ bFound = ScDrawLayer::IsNoteCaption( pObj );
+ if( bFound )
+ {
+ pView->UnMarkAll();
+ pView->MarkObj( pObj, pView->GetSdrPageView() );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // maybe consider OLE object
+ SfxInPlaceClient* pIPClient = rViewShell.GetIPClient();
+
+ if (pIPClient)
+ {
+ ScModule* pScMod = SC_MOD();
+ bool bUnoRefDialog = pScMod->IsRefDialogOpen() && pScMod->GetCurRefDlgId() == WID_SIMPLE_REF;
+
+ if ( pIPClient->IsObjectInPlaceActive() && !bUnoRefDialog )
+ pIPClient->DeactivateObject();
+ }
+
+ sal_uInt16 nClicks = rMEvt.GetClicks();
+ if (pView && nClicks == 2 && rMEvt.IsLeft())
+ {
+ if ( pView->AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ pObj = pMark->GetMarkedSdrObj();
+
+ // only activate, when the mouse also is over the selected object
+
+ SdrViewEvent aVEvt;
+ SdrHitKind eHit = pView->PickAnything( rMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt );
+ if (eHit != SdrHitKind::NONE && aVEvt.mpObj == pObj)
+ {
+ SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
+
+ // OLE: activate
+
+ if (nSdrObjKind == SdrObjKind::OLE2)
+ {
+ if (!bOle)
+ {
+ if (static_cast<SdrOle2Obj*>(pObj)->GetObjRef().is())
+ {
+ rViewShell.ActivateObject(static_cast<SdrOle2Obj*>(pObj), css::embed::EmbedVerbs::MS_OLEVERB_PRIMARY);
+ }
+ }
+ }
+
+ // Edit text
+ // not in UNO controls
+ // #i32352# not in media objects
+
+ else if ( dynamic_cast<const SdrTextObj*>( pObj) != nullptr && dynamic_cast<const SdrUnoObj*>( pObj) == nullptr && dynamic_cast<const SdrMediaObj*>( pObj) == nullptr )
+ {
+ OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
+ bool bVertical = ( pOPO && pOPO->IsEffectivelyVertical() );
+ sal_uInt16 nTextSlotId = bVertical ? SID_DRAW_TEXT_VERTICAL : SID_DRAW_TEXT;
+
+ rViewShell.GetViewData().GetDispatcher().
+ Execute(nTextSlotId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD);
+
+ // Get the created FuText now and change into EditMode
+ FuPoor* pPoor = rViewShell.GetViewData().GetView()->GetDrawFuncPtr();
+ if ( pPoor && pPoor->GetSlotID() == nTextSlotId ) // has no RTTI
+ {
+ FuText* pText = static_cast<FuText*>(pPoor);
+ Point aMousePixel = rMEvt.GetPosPixel();
+ pText->SetInEditMode( pObj, &aMousePixel );
+ }
+ bReturn = true;
+ }
+ }
+ }
+ }
+ else if ( TestDetective( pView->GetSdrPageView(), aPnt ) )
+ bReturn = true;
+ }
+
+ ForcePointer(&rMEvt);
+
+ if (pWindow->IsMouseCaptured())
+ pWindow->ReleaseMouse();
+
+ // command handler for context menu follows after MouseButtonUp,
+ // therefore here the hard IsLeft call
+ if ( !bReturn && rMEvt.IsLeft() )
+ if (rViewShell.IsDrawSelMode())
+ rViewShell.GetViewData().GetDispatcher().
+ Execute(SID_OBJECT_SELECT, SfxCallMode::SLOT | SfxCallMode::RECORD);
+
+ if ( bCopy && pPage )
+ {
+ ScDocShell* pDocShell = rViewData.GetDocShell();
+ ScModelObj* pModelObj = ( pDocShell ? comphelper::getFromUnoTunnel<ScModelObj>( pDocShell->GetModel() ) : nullptr );
+ if ( pModelObj )
+ {
+ SCTAB nTab = rViewData.GetTabNo();
+ ScChartHelper::CreateProtectedChartListenersAndNotify( rDocument, pPage, pModelObj, nTab,
+ aProtectedChartRangesVector, aExcludedChartNames );
+ }
+ }
+
+ return bReturn;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/fusel2.cxx b/sc/source/ui/drawfunc/fusel2.cxx
new file mode 100644
index 000000000..0d18fea87
--- /dev/null
+++ b/sc/source/ui/drawfunc/fusel2.cxx
@@ -0,0 +1,159 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svditer.hxx>
+#include <svx/svdpagv.hxx>
+
+#include <fusel.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <detfunc.hxx>
+#include <attrib.hxx>
+#include <scitems.hxx>
+#include <userdat.hxx>
+#include <drwlayer.hxx>
+#include <docsh.hxx>
+#include <drawview.hxx>
+#include <svx/sdrhittesthelper.hxx>
+
+static tools::Long Diff( const Point& rP1, const Point& rP2 )
+{
+ tools::Long nX = rP1.X() - rP2.X();
+ if (nX<0) nX = -nX;
+ tools::Long nY = rP1.Y() - rP2.Y();
+ if (nY<0) nY = -nY;
+ return nX+nY;
+}
+
+bool FuSelection::TestDetective( const SdrPageView* pPV, const Point& rPos )
+{
+ if (!pPV)
+ return false;
+
+ bool bFound = false;
+ SdrObjListIter aIter( pPV->GetObjList(), SdrIterMode::Flat );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bFound)
+ {
+ if (ScDetectiveFunc::IsNonAlienArrow( pObject ))
+ {
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(pWindow->PixelToLogic(
+ Size(pView->GetHitTolerancePixel(),0)).Width());
+ if (SdrObjectPrimitiveHit(*pObject, rPos, nHitLog, *pPV, nullptr, false))
+ {
+ ScViewData& rViewData = rViewShell.GetViewData();
+ ScSplitPos ePos = rViewShell.FindWindow( pWindow );
+ Point aLineStart = pObject->GetPoint(0);
+ Point aLineEnd = pObject->GetPoint(1);
+ Point aPixel = pWindow->LogicToPixel( aLineStart );
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ rViewData.GetPosFromPixel( aPixel.X(), aPixel.Y(), ePos, nStartCol, nStartRow );
+ aPixel = pWindow->LogicToPixel( aLineEnd );
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ rViewData.GetPosFromPixel( aPixel.X(), aPixel.Y(), ePos, nEndCol, nEndRow );
+ SCCOL nCurX = rViewData.GetCurX();
+ SCROW nCurY = rViewData.GetCurY();
+ bool bStart = ( Diff( rPos,aLineStart ) > Diff( rPos,aLineEnd ) );
+ if ( nCurX == nStartCol && nCurY == nStartRow )
+ bStart = false;
+ else if ( nCurX == nEndCol && nCurY == nEndRow )
+ bStart = true;
+
+ SCCOL nDifX;
+ SCROW nDifY;
+ if ( bStart )
+ {
+ nDifX = nStartCol - nCurX;
+ nDifY = nStartRow - nCurY;
+ }
+ else
+ {
+ nDifX = nEndCol - nCurX;
+ nDifY = nEndRow - nCurY;
+ }
+ rViewShell.MoveCursorRel( nDifX, nDifY, SC_FOLLOW_JUMP, false );
+
+ bFound = true;
+ }
+ }
+
+ pObject = aIter.Next();
+ }
+ return bFound;
+}
+
+bool FuSelection::IsNoteCaptionMarked() const
+{
+ if( pView )
+ {
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ return ScDrawLayer::IsNoteCaption( pObj );
+ }
+ }
+ return false;
+}
+
+bool FuSelection::IsNoteCaptionClicked( const Point& rPos ) const
+{
+ SdrPageView* pPageView = pView ? pView->GetSdrPageView() : nullptr;
+ if( pPageView )
+ {
+ const ScViewData& rViewData = rViewShell.GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ bool bProtectDoc = rDoc.IsTabProtected( nTab ) || (pDocSh && pDocSh->IsReadOnly());
+
+ // search the last object (on top) in the object list
+ SdrObjListIter aIter( pPageView->GetObjList(), SdrIterMode::DeepNoGroups, true );
+ for( SdrObject* pObj = aIter.Next(); pObj; pObj = aIter.Next() )
+ {
+ if( pObj->GetLogicRect().Contains( rPos ) )
+ {
+ if( const ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( pObj, nTab ) )
+ {
+ const ScAddress& rNotePos = pCaptData->maStart;
+ // skip caption objects of notes in protected cells
+ const ScProtectionAttr* pProtAttr = rDoc.GetAttr( rNotePos.Col(), rNotePos.Row(), nTab, ATTR_PROTECTION );
+ bool bProtectAttr = pProtAttr->GetProtection() || pProtAttr->GetHideCell();
+ if( !bProtectAttr || !bProtectDoc )
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void FuSelection::ActivateNoteHandles(SdrObject* pObject)
+{
+ if( pView && ScDrawLayer::IsNoteCaption( pObject ) )
+ {
+ // Leave the internal layer unlocked - relock in ScDrawView::MarkListHasChanged()
+ pView->UnlockInternalLayer();
+ pView->MarkObj( pObject, pView->GetSdrPageView() );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/futext.cxx b/sc/source/ui/drawfunc/futext.cxx
new file mode 100644
index 000000000..d907a0a72
--- /dev/null
+++ b/sc/source/ui/drawfunc/futext.cxx
@@ -0,0 +1,687 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/svddef.hxx>
+#include <svx/svdoutl.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/sdtaaitm.hxx>
+#include <svx/sdtacitm.hxx>
+#include <svx/svdotext.hxx>
+#include <svx/sdtagitm.hxx>
+#include <editeng/unolingu.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/svxids.hrc>
+#include <editeng/eeitem.hxx>
+#include <svl/itemset.hxx>
+#include <osl/diagnose.h>
+
+#include <futext.hxx>
+#include <drwlayer.hxx>
+#include <sc.hrc>
+#include <tabvwsh.hxx>
+#include <drawview.hxx>
+
+// maximum of mouse movement which allows to start Drag&Drop
+//! fusel,fuconstr,futext - combined!
+#define SC_MAXDRAGMOVE 3
+
+static void lcl_InvalidateAttribs( SfxBindings& rBindings )
+{
+ rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
+ rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
+ rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
+ rBindings.Invalidate( SID_ULINE_VAL_NONE );
+ rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
+ rBindings.Invalidate( SID_ATTR_CHAR_OVERLINE );
+ rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
+ rBindings.Invalidate( SID_ATTR_CHAR_BACK_COLOR );
+ rBindings.Invalidate( SID_ATTR_CHAR_FONT );
+ rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_LEFT );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_RIGHT );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_BLOCK );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_CENTER);
+ rBindings.Invalidate( SID_ALIGNLEFT );
+ rBindings.Invalidate( SID_ALIGNCENTERHOR );
+ rBindings.Invalidate( SID_ALIGNRIGHT );
+ rBindings.Invalidate( SID_ALIGNBLOCK );
+ rBindings.Invalidate( SID_ATTR_PARA_LINESPACE_10 );
+ rBindings.Invalidate( SID_ATTR_PARA_LINESPACE_15 );
+ rBindings.Invalidate( SID_ATTR_PARA_LINESPACE_20 );
+ rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
+ rBindings.Invalidate( SID_SET_SUB_SCRIPT );
+ rBindings.Invalidate( SID_HYPERLINK_GETLINK );
+ rBindings.Invalidate( SID_TEXTDIRECTION_LEFT_TO_RIGHT );
+ rBindings.Invalidate( SID_TEXTDIRECTION_TOP_TO_BOTTOM );
+ rBindings.Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ rBindings.Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT );
+ rBindings.Invalidate( SID_TABLE_VERT_NONE );
+ rBindings.Invalidate( SID_TABLE_VERT_CENTER );
+ rBindings.Invalidate( SID_TABLE_VERT_BOTTOM );
+ // pseudo slots for Format menu
+ rBindings.Invalidate( SID_ALIGN_ANY_LEFT );
+ rBindings.Invalidate( SID_ALIGN_ANY_HCENTER );
+ rBindings.Invalidate( SID_ALIGN_ANY_RIGHT );
+ rBindings.Invalidate( SID_ALIGN_ANY_JUSTIFIED );
+ rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
+ rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
+ rBindings.Invalidate( SID_SET_SUB_SCRIPT );
+ rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
+ rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
+}
+
+static void lcl_UpdateHyphenator( Outliner& rOutliner, const SdrObject* pObj )
+{
+ // use hyphenator only if hyphenation attribute is set
+ if ( pObj && pObj->GetMergedItem(EE_PARA_HYPHENATE).GetValue() ) {
+ css::uno::Reference<css::linguistic2::XHyphenator> xHyphenator( LinguMgr::GetHyphenator() );
+ rOutliner.SetHyphenator( xHyphenator );
+ }
+}
+
+FuText::FuText(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pViewP,
+ SdrModel* pDoc, const SfxRequest& rReq)
+ : FuConstruct(rViewSh, pWin, pViewP, pDoc, rReq)
+{
+}
+
+FuText::~FuText()
+{
+// StopEditMode(); // in Deactivate !
+}
+
+bool FuText::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+ bool bStraightEnter = true;
+
+ if ( pView->MouseButtonDown(rMEvt, pWindow->GetOutDev()) )
+ return true; // event handled from SdrView
+
+ if ( pView->IsTextEdit() )
+ {
+ if ( IsEditingANote() )
+ {
+ if( !IsSizingOrMovingNote(rMEvt) )
+ {
+ StopEditMode(); // Clicked outside, ending edit
+ bStraightEnter = false;
+ }
+ }
+ else
+ {
+ StopEditMode(); // Clicked outside, ending edit
+ pView->UnmarkAll();
+ bStraightEnter = false;
+ }
+ pView->SetCreateMode();
+ }
+
+ aMDPos = pWindow->PixelToLogic( rMEvt.GetPosPixel() );
+
+ if ( rMEvt.IsLeft() )
+ {
+ SdrHdl* pHdl = pView->PickHandle(aMDPos);
+ const size_t nHdlNum = pView->GetHdlNum(pHdl);
+ if (pHdl != nullptr)
+ {
+ if (pView->HasMarkablePoints() && pView->IsPointMarkable(*pHdl))
+ {
+ bool bPointMarked=pView->IsPointMarked(*pHdl);
+
+ if ( rMEvt.IsShift() )
+ {
+ if (!bPointMarked)
+ {
+ pView->MarkPoint(*pHdl);
+ }
+ else
+ {
+ pView->UnmarkPoint(*pHdl);
+ }
+ }
+ else
+ {
+ if (!bPointMarked)
+ {
+ pView->UnmarkAllPoints();
+ pView->MarkPoint(*pHdl);
+ }
+ }
+ pHdl=pView->GetHdl(nHdlNum);
+ }
+ }
+
+ SdrPageView* pPV = nullptr;
+
+ if ( pHdl != nullptr || pView->IsMarkedHit(aMDPos) )
+ {
+ SdrObject* pObj = (pHdl == nullptr) ?
+ pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::PICKTEXTEDIT) :
+ nullptr;
+ if (pObj)
+ {
+ std::unique_ptr<SdrOutliner> pO = MakeOutliner();
+ lcl_UpdateHyphenator( *pO, pObj );
+
+ // vertical flag:
+ // deduced from slot ids only if text object has no content
+ sal_uInt16 nSlotID = aSfxRequest.GetSlot();
+ bool bVertical = ( nSlotID == SID_DRAW_TEXT_VERTICAL );
+ OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
+ if ( pOPO )
+ bVertical = pOPO->IsEffectivelyVertical(); // content wins
+ pO->SetVertical( bVertical );
+
+ //!?? the default values are not correct when result is without outliner ???!?
+ auto pOTemp = pO.get();
+ if ( pView->SdrBeginTextEdit(pObj, pPV, pWindow, true, pO.release()) )
+ {
+ // subscribe EditEngine-UndoManager
+ rViewShell.SetDrawTextUndo( &pOTemp->GetUndoManager() );
+
+ OutlinerView* pOLV = pView->GetTextEditOutlinerView();
+ if ( pOLV->MouseButtonDown(rMEvt) )
+ return true; // Event to the Outliner
+ }
+ }
+ else
+ {
+ // disable tail & circular move for caption objects.
+ bool bDrag = false;
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pMarkedObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ if( ScDrawLayer::IsNoteCaption( pMarkedObj ) )
+ {
+ if(pHdl->GetKind() != SdrHdlKind::Poly && pHdl->GetKind() != SdrHdlKind::Circle)
+ bDrag = true;
+ }
+ else
+ bDrag = true; // different object
+ }
+ else
+ bDrag = true; // several objects
+
+ if ( bDrag )
+ {
+ aDragTimer.Start();
+ pView->BegDragObj(aMDPos, nullptr, pHdl);
+ }
+ }
+ }
+ else
+ {
+ if (pView->IsEditMode())
+ {
+ bool bPointMode=pView->HasMarkablePoints();
+
+ if (!rMEvt.IsShift())
+ {
+ if (bPointMode)
+ {
+ pView->UnmarkAllPoints();
+ }
+ else
+ {
+ pView->UnmarkAll();
+ }
+
+ pView->SetDragMode(SdrDragMode::Move);
+ SfxBindings& rBindings = rViewShell.GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_OBJECT_ROTATE );
+ rBindings.Invalidate( SID_OBJECT_MIRROR );
+ }
+
+ if ( pView->MarkObj(aMDPos, -2, false, rMEvt.IsMod1()) )
+ {
+ aDragTimer.Start();
+
+ pHdl=pView->PickHandle(aMDPos);
+
+ if (pHdl!=nullptr)
+ {
+ pView->MarkPoint(*pHdl);
+ pHdl=pView->GetHdl(nHdlNum);
+ }
+
+ pView->BegDragObj(aMDPos, nullptr, pHdl);
+ }
+ else
+ {
+ if (bPointMode)
+ {
+ pView->BegMarkPoints(aMDPos);
+ }
+ else
+ {
+ pView->BegMarkObj(aMDPos);
+ }
+ }
+ }
+ else if (aSfxRequest.GetSlot() == SID_DRAW_NOTEEDIT )
+ {
+ // Edit notes -> create no new text objects
+ // and leave text mode
+ rViewShell.GetViewData().GetDispatcher().
+ Execute(aSfxRequest.GetSlot(), SfxCallMode::SLOT | SfxCallMode::RECORD);
+ }
+ else
+ {
+ if (bStraightEnter)//Hack for that silly idea that creating text fields is inside the text routine
+ {
+ // create object
+ pView->BegCreateObj(aMDPos);
+ }
+ else if (SdrObject* pObj = pView->PickObj(aMDPos, pView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER | SdrSearchOptions::BEFOREMARK))
+ {
+ pView->UnmarkAllObj();
+ ScViewData& rViewData = rViewShell.GetViewData();
+ rViewData.GetDispatcher().Execute(aSfxRequest.GetSlot(), SfxCallMode::SLOT | SfxCallMode::RECORD);
+ pView->MarkObj(pObj,pPV);
+
+ pHdl=pView->PickHandle(aMDPos);
+ pView->BegDragObj(aMDPos, nullptr, pHdl);
+ return true;
+ }
+ }
+ }
+ }
+
+ if (!bIsInDragMode)
+ {
+ pWindow->CaptureMouse();
+// ForcePointer(&rMEvt);
+ lcl_InvalidateAttribs( rViewShell.GetViewFrame()->GetBindings() );
+ }
+
+ rViewShell.SetActivePointer(pView->GetPreferredPointer(
+ pWindow->PixelToLogic(rMEvt.GetPosPixel()), pWindow->GetOutDev() ));
+ if (!bStraightEnter)
+ {
+ pView->UnmarkAll();
+ ScViewData& rViewData = rViewShell.GetViewData();
+ rViewData.GetDispatcher().Execute(aSfxRequest.GetSlot(), SfxCallMode::SLOT | SfxCallMode::RECORD);
+ }
+
+ return true;
+}
+
+bool FuText::MouseMove(const MouseEvent& rMEvt)
+{
+ rViewShell.SetActivePointer(pView->GetPreferredPointer(
+ pWindow->PixelToLogic(rMEvt.GetPosPixel()), pWindow->GetOutDev() ));
+
+ if (aDragTimer.IsActive() )
+ {
+ Point aOldPixel = pWindow->LogicToPixel( aMDPos );
+ Point aNewPixel = rMEvt.GetPosPixel();
+ if ( std::abs( aOldPixel.X() - aNewPixel.X() ) > SC_MAXDRAGMOVE ||
+ std::abs( aOldPixel.Y() - aNewPixel.Y() ) > SC_MAXDRAGMOVE )
+ aDragTimer.Stop();
+ }
+
+ Point aPix(rMEvt.GetPosPixel());
+ Point aPnt(pWindow->PixelToLogic(aPix));
+
+ if ( pView->MouseMove(rMEvt, pWindow->GetOutDev()) )
+ return true; // event handled from SdrView
+
+ if ( pView->IsAction() )
+ {
+ ForceScroll(aPix);
+ pView->MovAction(aPnt);
+ }
+
+ return false;
+}
+
+bool FuText::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ // remember button state for creation of own MouseEvents
+ SetMouseButtonCode(rMEvt.GetButtons());
+
+ if (aDragTimer.IsActive() )
+ {
+ aDragTimer.Stop();
+ }
+
+ lcl_InvalidateAttribs( rViewShell.GetViewFrame()->GetBindings() );
+
+ Point aPnt( pWindow->PixelToLogic( rMEvt.GetPosPixel() ) );
+
+ if ( pView->MouseButtonUp(rMEvt, pWindow->GetOutDev()) )
+ return true; // Event evaluated by SdrView
+
+ if ( pView->IsDragObj() )
+ {
+ pView->EndDragObj( rMEvt.IsShift() );
+ pView->ForceMarkedToAnotherPage();
+ }
+ else if ( pView->IsCreateObj() )
+ {
+ if (rMEvt.IsLeft())
+ {
+ pView->EndCreateObj(SdrCreateCmd::ForceEnd);
+ if (aSfxRequest.GetSlot() == SID_DRAW_TEXT_MARQUEE)
+ {
+ // create marquee-object?
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if (rMarkList.GetMark(0))
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ // set needed attributes for scrolling
+ SfxItemSetFixed<SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST> aItemSet( pDrDoc->GetItemPool());
+
+ aItemSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
+ aItemSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
+ aItemSet.Put( SdrTextAniKindItem( SdrTextAniKind::Slide ) );
+ aItemSet.Put( SdrTextAniDirectionItem( SdrTextAniDirection::Left ) );
+ aItemSet.Put( SdrTextAniCountItem( 1 ) );
+ aItemSet.Put( SdrTextAniAmountItem(
+ static_cast<sal_Int16>(pWindow->PixelToLogic(Size(2,1)).Width())) );
+ pObj->SetMergedItemSetAndBroadcast(aItemSet);
+ }
+ }
+
+ // init object different when vertical writing
+ sal_uInt16 nSlotID(aSfxRequest.GetSlot());
+ bool bVertical = (SID_DRAW_TEXT_VERTICAL == nSlotID);
+ if(bVertical)
+ {
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if(rMarkList.GetMark(0))
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if(auto pText = dynamic_cast<SdrTextObj*>( pObj))
+ {
+ SfxItemSet aSet(pDrDoc->GetItemPool());
+
+ pText->SetVerticalWriting(true);
+
+ aSet.Put(makeSdrTextAutoGrowWidthItem(true));
+ aSet.Put(makeSdrTextAutoGrowHeightItem(false));
+ aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP));
+ aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
+
+ pText->SetMergedItemSet(aSet);
+ }
+ }
+ }
+
+ SetInEditMode();
+
+ // leave mode when sole click (-> fuconstr)
+ if ( !pView->AreObjectsMarked() )
+ {
+ pView->MarkObj(aPnt, -2, false, rMEvt.IsMod1());
+
+ SfxDispatcher& rDisp = rViewShell.GetViewData().GetDispatcher();
+ if ( pView->AreObjectsMarked() )
+ rDisp.Execute(SID_OBJECT_SELECT, SfxCallMode::SLOT | SfxCallMode::RECORD);
+ else
+ rDisp.Execute(aSfxRequest.GetSlot(), SfxCallMode::SLOT | SfxCallMode::RECORD);
+ }
+ }
+ }
+ else if ( pView->IsAction() )
+ {
+ pView->EndAction();
+ }
+ else if( !pView->IsAction() )
+ {
+ pWindow->ReleaseMouse();
+
+ if ( !pView->AreObjectsMarked() && rMEvt.GetClicks() < 2 )
+ {
+ pView->MarkObj(aPnt, -2, false, rMEvt.IsMod1());
+
+ SfxDispatcher& rDisp = rViewShell.GetViewData().GetDispatcher();
+ if ( pView->AreObjectsMarked() )
+ rDisp.Execute(SID_OBJECT_SELECT, SfxCallMode::SLOT | SfxCallMode::RECORD);
+ else
+ rDisp.Execute(aSfxRequest.GetSlot(), SfxCallMode::SLOT | SfxCallMode::RECORD);
+ }
+ }
+
+ return false;
+}
+
+// switch mouse-pointer
+void FuText::ForcePointer(const MouseEvent* /* pMEvt */)
+{
+ rViewShell.SetActivePointer( aNewPointer );
+}
+
+// modify keyboard events
+// if a KeyEvent is being processed, then the return value is sal_True, else FALSE.
+bool FuText::KeyInput(const KeyEvent& rKEvt)
+{
+ bool bReturn = false;
+
+ if ( pView->KeyInput(rKEvt, pWindow) )
+ {
+ bReturn = true;
+ lcl_InvalidateAttribs( rViewShell.GetViewFrame()->GetBindings() );
+ }
+ else
+ {
+ bReturn = FuDraw::KeyInput(rKEvt);
+ }
+
+ return bReturn;
+}
+
+void FuText::Activate()
+{
+ pView->SetDragMode(SdrDragMode::Move);
+ SfxBindings& rBindings = rViewShell.GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_OBJECT_ROTATE );
+ rBindings.Invalidate( SID_OBJECT_MIRROR );
+
+// instant set the edit mode
+// SetInEditMode();
+
+// if (!pTextObj)
+ {
+ // no text object in EditMode, therefore set CreateMode
+
+ pView->SetCurrentObj(SdrObjKind::Text);
+
+ pView->SetCreateMode();
+ }
+
+ aNewPointer = PointerStyle::Text;
+
+ aOldPointer = pWindow->GetPointer();
+ rViewShell.SetActivePointer( aNewPointer );
+
+ FuConstruct::Activate();
+}
+
+void FuText::Deactivate()
+{
+ FuConstruct::Deactivate();
+ rViewShell.SetActivePointer( aOldPointer );
+ StopEditMode();
+}
+
+// switch object to Edit-Mode
+void FuText::SetInEditMode(SdrObject* pObj, const Point* pMousePixel,
+ bool bCursorToEnd, const KeyEvent* pInitialKey)
+{
+ /* It is possible to pass a special (unselected) object in pObj, e.g. the
+ caption object of a cell note. If pObj is 0, then the selected object
+ is used. The layer will be relocked in FuText::StopEditMode(). */
+ if ( pObj && (pObj->GetLayer() == SC_LAYER_INTERN) )
+ pView->UnlockInternalLayer();
+
+ if ( !pObj && pView->AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ pObj = pMark->GetMarkedSdrObj();
+ }
+ }
+
+ if ( !pObj )
+ return;
+
+ SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
+
+ if (!(nSdrObjKind == SdrObjKind::Text ||
+ nSdrObjKind == SdrObjKind::TitleText ||
+ nSdrObjKind == SdrObjKind::OutlineText ||
+ dynamic_cast<const SdrTextObj*>( pObj) != nullptr))
+ return;
+
+ SdrPageView* pPV = pView->GetSdrPageView();
+
+ if ( !pObj->HasTextEdit() )
+ return;
+
+ std::unique_ptr<SdrOutliner> pO = MakeOutliner();
+ lcl_UpdateHyphenator( *pO, pObj );
+
+ // vertical flag:
+ // deduced from slot ids only if text object has no content
+
+ sal_uInt16 nSlotID = aSfxRequest.GetSlot();
+ bool bVertical = ( nSlotID == SID_DRAW_TEXT_VERTICAL );
+ OutlinerParaObject* pOPO = pObj->GetOutlinerParaObject();
+ if ( pOPO )
+ bVertical = pOPO->IsEffectivelyVertical(); // content wins
+ pO->SetVertical( bVertical );
+
+ //!?? without returned Outliner the defaults are not correct ???!?
+ auto pOTemp = pO.get();
+ if ( !pView->SdrBeginTextEdit(pObj, pPV, pWindow, true, pO.release()) )
+ return;
+
+ // Toggle out of paste mode if we are in it, otherwise
+ // pressing return in this object will instead go to the
+ // sheet and be considered an overwrite-cell instruction
+ rViewShell.GetViewData().SetPasteMode(ScPasteFlags::NONE);
+ rViewShell.UpdateCopySourceOverlay();
+
+ // EditEngine-UndoManager anmelden
+ rViewShell.SetDrawTextUndo( &pOTemp->GetUndoManager() );
+
+ pView->SetEditMode();
+
+ // set text cursor to click position or to end,
+ // pass initial key event to outliner view
+ if ( !(pMousePixel || bCursorToEnd || pInitialKey) )
+ return;
+
+ OutlinerView* pOLV = pView->GetTextEditOutlinerView();
+ if (!pOLV)
+ return;
+
+ if ( pMousePixel )
+ {
+ MouseEvent aEditEvt( *pMousePixel, 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0 );
+ pOLV->MouseButtonDown(aEditEvt);
+ pOLV->MouseButtonUp(aEditEvt);
+ }
+ else if ( bCursorToEnd )
+ {
+ ESelection aNewSelection(EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND, EE_PARA_NOT_FOUND, EE_INDEX_NOT_FOUND);
+ pOLV->SetSelection(aNewSelection);
+ }
+
+ if ( pInitialKey )
+ pOLV->PostKeyEvent( *pInitialKey );
+}
+
+// Create default drawing objects via keyboard
+SdrObjectUniquePtr FuText::CreateDefaultObject(const sal_uInt16 nID, const tools::Rectangle& rRectangle)
+{
+ // case SID_DRAW_TEXT:
+ // case SID_DRAW_TEXT_VERTICAL:
+ // case SID_DRAW_TEXT_MARQUEE:
+ // case SID_DRAW_NOTEEDIT:
+
+ SdrObjectUniquePtr pObj(SdrObjFactory::MakeNewObject(
+ *pDrDoc,
+ pView->GetCurrentObjInventor(),
+ pView->GetCurrentObjIdentifier()));
+
+ if(pObj)
+ {
+ if(auto pText = dynamic_cast<SdrTextObj*>( pObj.get() ))
+ {
+ pText->SetLogicRect(rRectangle);
+
+ // don't set default text, start edit mode instead
+ // String aText(ScResId(STR_CAPTION_DEFAULT_TEXT));
+ // pText->SetText(aText);
+
+ bool bVertical = (SID_DRAW_TEXT_VERTICAL == nID);
+ bool bMarquee = (SID_DRAW_TEXT_MARQUEE == nID);
+
+ pText->SetVerticalWriting(bVertical);
+
+ if(bVertical)
+ {
+ SfxItemSet aSet(pDrDoc->GetItemPool());
+
+ aSet.Put(makeSdrTextAutoGrowWidthItem(true));
+ aSet.Put(makeSdrTextAutoGrowHeightItem(false));
+ aSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP));
+ aSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT));
+
+ pText->SetMergedItemSet(aSet);
+ }
+
+ if(bMarquee)
+ {
+ SfxItemSetFixed<SDRATTR_MISC_FIRST, SDRATTR_MISC_LAST> aSet(pDrDoc->GetItemPool());
+
+ aSet.Put( makeSdrTextAutoGrowWidthItem( false ) );
+ aSet.Put( makeSdrTextAutoGrowHeightItem( false ) );
+ aSet.Put( SdrTextAniKindItem( SdrTextAniKind::Slide ) );
+ aSet.Put( SdrTextAniDirectionItem( SdrTextAniDirection::Left ) );
+ aSet.Put( SdrTextAniCountItem( 1 ) );
+ aSet.Put( SdrTextAniAmountItem( static_cast<sal_Int16>(pWindow->PixelToLogic(Size(2,1)).Width())) );
+
+ pObj->SetMergedItemSetAndBroadcast(aSet);
+ }
+
+ SetInEditMode( pObj.get() ); // start edit mode
+ }
+ else
+ {
+ OSL_FAIL("Object is NO text object");
+ }
+ }
+
+ return pObj;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/futext2.cxx b/sc/source/ui/drawfunc/futext2.cxx
new file mode 100644
index 000000000..8f30cb4a6
--- /dev/null
+++ b/sc/source/ui/drawfunc/futext2.cxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdmodel.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdetc.hxx>
+
+#include <futext.hxx>
+#include <tabvwsh.hxx>
+
+std::unique_ptr<SdrOutliner> FuText::MakeOutliner()
+{
+ ScViewData& rViewData = rViewShell.GetViewData();
+ std::unique_ptr<SdrOutliner> pOutl = SdrMakeOutliner(OutlinerMode::OutlineObject, *pDrDoc);
+
+ rViewData.UpdateOutlinerFlags(*pOutl);
+
+ // The EditEngine uses during RTF export (Clipboard / Drag&Drop)
+ // the MapMode of RefDevice to set the font size
+
+ // #i10426# The ref device isn't set to the EditEngine before SdrBeginTextEdit now,
+ // so the device must be taken from the model here.
+ OutputDevice* pRef = pDrDoc->GetRefDevice();
+ if (pRef && pRef != pWindow->GetOutDev())
+ pRef->SetMapMode(MapMode(MapUnit::Map100thMM));
+
+ return pOutl;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/futext3.cxx b/sc/source/ui/drawfunc/futext3.cxx
new file mode 100644
index 000000000..df601ea0d
--- /dev/null
+++ b/sc/source/ui/drawfunc/futext3.cxx
@@ -0,0 +1,182 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdocapt.hxx>
+#include <svx/svdundo.hxx>
+#include <vcl/cursor.hxx>
+#include <osl/diagnose.h>
+
+#include <global.hxx>
+#include <drwlayer.hxx>
+#include <userdat.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <futext.hxx>
+#include <docsh.hxx>
+#include <postit.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <drawview.hxx>
+#include <undocell.hxx>
+
+// Editing of Note-Key-Objects has to be stopped always via StopEditMode,
+// so that changes are taken over into the document!
+// (Fontwork-Execute in drawsh and drtxtob does not happen for Key-Objects)
+
+void FuText::StopEditMode()
+{
+ SdrObject* pObject = pView->GetTextEditObject();
+ if( !pObject ) return;
+
+ // relock the internal layer that has been unlocked in FuText::SetInEditMode()
+ if ( pObject->GetLayer() == SC_LAYER_INTERN )
+ pView->LockInternalLayer();
+
+ ScViewData& rViewData = rViewShell.GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ OSL_ENSURE( pDrawLayer && (pDrawLayer == pDrDoc), "FuText::StopEditMode - missing or different drawing layers" );
+
+ ScAddress aNotePos;
+ ScPostIt* pNote = nullptr;
+ if( const ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( pObject, rViewData.GetTabNo() ) )
+ {
+ aNotePos = pCaptData->maStart;
+ pNote = rDoc.GetNote( aNotePos );
+ OSL_ENSURE( pNote && (pNote->GetCaption() == pObject), "FuText::StopEditMode - missing or invalid cell note" );
+ }
+
+ ScDocShell* pDocShell = rViewData.GetDocShell();
+ SfxUndoManager* pUndoMgr = rDoc.IsUndoEnabled() ? pDocShell->GetUndoManager() : nullptr;
+ bool bNewNote = false;
+ if( pNote && pUndoMgr )
+ {
+ /* Put all undo actions already collected (e.g. create caption object)
+ and all following undo actions (text changed) together into a ListAction. */
+ std::unique_ptr<SdrUndoGroup> pCalcUndo = pDrawLayer->GetCalcUndo();
+
+ if(pCalcUndo)
+ {
+ const OUString aUndoStr = ScResId( STR_UNDO_EDITNOTE );
+ pUndoMgr->EnterListAction( aUndoStr, aUndoStr, 0, rViewShell.GetViewShellId() );
+
+ /* Note has been created before editing, if first undo action is
+ an insert action. Needed below to decide whether to drop the
+ undo if editing a new note has been cancelled. */
+ bNewNote = (pCalcUndo->GetActionCount() > 0) && dynamic_cast< SdrUndoNewObj* >(pCalcUndo->GetAction( 0 ));
+
+ // create a "insert note" undo action if needed
+ if( bNewNote )
+ pUndoMgr->AddUndoAction( std::make_unique<ScUndoReplaceNote>( *pDocShell, aNotePos, pNote->GetNoteData(), true, std::move(pCalcUndo) ) );
+ else
+ pUndoMgr->AddUndoAction( std::move(pCalcUndo) );
+ }
+ }
+
+ if( pNote )
+ rDoc.LockStreamValid(true); // only the affected sheet is invalidated below
+
+ /* SdrObjEditView::SdrEndTextEdit() may try to delete the entire drawing
+ object, if it does not contain text and has invisible border and fill.
+ This must not happen for note caption objects. They will be removed
+ below together with the cell note if the text is empty (independent of
+ border and area formatting). It is possible to prevent automatic
+ deletion by passing sal_True to this function. The return value changes
+ from SdrEndTextEditKind::Deleted to SdrEndTextEditKind::ShouldBeDeleted in this
+ case. */
+ /*SdrEndTextEditKind eResult =*/ pView->SdrEndTextEdit( pNote != nullptr );
+
+ // or ScEndTextEdit (with drawview.hxx)
+ rViewShell.SetDrawTextUndo( nullptr );
+
+ vcl::Cursor* pCur = pWindow->GetCursor();
+ if( pCur && pCur->IsVisible() )
+ pCur->Hide();
+
+ if( !pNote )
+ return;
+
+ ScTabView::OnLOKNoteStateChanged( pNote );
+
+ // hide the caption object if it is in hidden state
+ pNote->ShowCaptionTemp( aNotePos, false );
+
+ // update author and date
+ pNote->AutoStamp();
+
+ /* If the entire text has been cleared, the cell note and its caption
+ object have to be removed. */
+ SdrTextObj* pTextObject = dynamic_cast< SdrTextObj* >( pObject );
+ bool bDeleteNote = !pTextObject || !pTextObject->HasText();
+ if( bDeleteNote )
+ {
+ if( pUndoMgr )
+ {
+ // collect the "remove object" drawing undo action created by DeleteNote()
+ pDrawLayer->BeginCalcUndo(false);
+ // rescue note data before deletion
+ ScNoteData aNoteData( pNote->GetNoteData() );
+ // delete note from document (removes caption, but does not delete it)
+ rDoc.ReleaseNote(aNotePos);
+ // create undo action for removed note
+ pUndoMgr->AddUndoAction( std::make_unique<ScUndoReplaceNote>( *pDocShell, aNotePos, aNoteData, false, pDrawLayer->GetCalcUndo() ) );
+ }
+ else
+ {
+ rDoc.ReleaseNote(aNotePos);
+ }
+ // ScDocument::DeleteNote has deleted the note that pNote points to
+ pNote = nullptr;
+ }
+
+ // finalize the undo list action
+ if( pUndoMgr )
+ {
+ pUndoMgr->LeaveListAction();
+
+ /* #i94039# Update the default name "Edit Note" of the undo action
+ if the note has been created before editing or is deleted due
+ to deleted text. If the note has been created *and* is deleted,
+ the last undo action can be removed completely. Note: The
+ function LeaveListAction() removes the last action by itself,
+ if it is empty (when result is SdrEndTextEditKind::Unchanged). */
+ if( bNewNote && bDeleteNote )
+ {
+ pUndoMgr->RemoveLastUndoAction();
+
+ // Make sure the former area of the note anchor is invalidated.
+ ScRangeList aRangeList(aNotePos);
+ ScMarkData aMarkData(rDoc.GetSheetLimits(), aRangeList);
+ rViewShell.UpdateSelectionArea(aMarkData);
+ }
+ else if( bNewNote || bDeleteNote )
+ {
+ SfxListUndoAction* pAction = dynamic_cast< SfxListUndoAction* >( pUndoMgr->GetUndoAction() );
+ OSL_ENSURE( pAction, "FuText::StopEditMode - list undo action expected" );
+ if( pAction )
+ pAction->SetComment( ScResId( bNewNote ? STR_UNDO_INSERTNOTE : STR_UNDO_DELETENOTE ) );
+ }
+ }
+
+ // invalidate stream positions only for the affected sheet
+ rDoc.LockStreamValid(false);
+ rDoc.SetStreamValid(aNotePos.Tab(), false);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/graphsh.cxx b/sc/source/ui/drawfunc/graphsh.cxx
new file mode 100644
index 000000000..c4487d45d
--- /dev/null
+++ b/sc/source/ui/drawfunc/graphsh.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 <sfx2/objface.hxx>
+#include <vcl/EnumContext.hxx>
+#include <sfx2/opengrf.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/grfflt.hxx>
+#include <svx/grafctrl.hxx>
+#include <svx/compressgraphicdialog.hxx>
+#include <svx/graphichelper.hxx>
+#include <svx/svxids.hrc>
+
+#include <graphsh.hxx>
+#include <strings.hrc>
+#include <viewdata.hxx>
+#include <drawview.hxx>
+#include <gridwin.hxx>
+#include <scresid.hxx>
+#include <svx/extedit.hxx>
+
+#define ShellClass_ScGraphicShell
+#include <scslots.hxx>
+
+SFX_IMPL_INTERFACE(ScGraphicShell, ScDrawShell)
+
+void ScGraphicShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT,
+ SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server,
+ ToolbarId::Graphic_Objectbar);
+
+ GetStaticInterface()->RegisterPopupMenu("graphic");
+}
+
+
+ScGraphicShell::ScGraphicShell(ScViewData& rData) :
+ ScDrawShell(rData)
+{
+ SetName("GraphicObject");
+ SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Graphic));
+}
+
+ScGraphicShell::~ScGraphicShell()
+{
+}
+
+void ScGraphicShell::GetAttrState( SfxItemSet& rSet )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+
+ if( pView )
+ SvxGrafAttrHelper::GetGrafAttrState( rSet, *pView );
+}
+
+void ScGraphicShell::Execute( SfxRequest& rReq )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+
+ if( pView )
+ {
+ SvxGrafAttrHelper::ExecuteGrafAttr( rReq, *pView );
+ Invalidate();
+ }
+}
+
+void ScGraphicShell::GetFilterState( SfxItemSet& rSet )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ bool bEnable = false;
+
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGraphicObj = dynamic_cast<SdrGrafObj*>( pObj) )
+ if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap )
+ bEnable = true;
+ }
+
+ if( !bEnable )
+ SvxGraphicFilter::DisableGraphicFilterSlots( rSet );
+}
+
+void ScGraphicShell::ExecuteFilter( const SfxRequest& rReq )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGraphicObj = dynamic_cast<SdrGrafObj*>( pObj) )
+ if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap )
+ {
+ GraphicObject aFilterObj( pGraphicObj->GetGraphicObject() );
+
+ if( SvxGraphicFilterResult::NONE ==
+ SvxGraphicFilter::ExecuteGrfFilterSlot( rReq, aFilterObj ) )
+ {
+ SdrPageView* pPageView = pView->GetSdrPageView();
+
+ if( pPageView )
+ {
+ SdrGrafObj* pFilteredObj(static_cast<SdrGrafObj*>(pObj->CloneSdrObject(pObj->getSdrModelFromSdrObject())));
+ OUString aStr = pView->GetDescriptionOfMarkedObjects() + " " + ScResId(SCSTR_UNDO_GRAFFILTER);
+ pView->BegUndo( aStr );
+ pFilteredObj->SetGraphicObject( aFilterObj );
+ pView->ReplaceObjectAtView( pObj, *pPageView, pFilteredObj );
+ pView->EndUndo();
+ }
+ }
+ }
+ }
+
+ Invalidate();
+}
+
+void ScGraphicShell::GetExternalEditState( SfxItemSet& rSet )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ bool bEnable = false;
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGraphicObj = dynamic_cast<SdrGrafObj*>( pObj) )
+ if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap )
+ bEnable = true;
+ }
+
+ if (GetObjectShell()->isExportLocked())
+ bEnable = false;
+
+ if( !bEnable )
+ rSet.DisableItem( SID_EXTERNAL_EDIT );
+}
+
+void ScGraphicShell::ExecuteExternalEdit( SAL_UNUSED_PARAMETER SfxRequest& )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->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>(
+ pView, pObj));
+ m_ExternalEdits.back()->Edit( &aGraphicObject );
+ }
+ }
+
+ Invalidate();
+}
+
+void ScGraphicShell::GetCompressGraphicState( SfxItemSet& rSet )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ bool bEnable = false;
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGraphicObj = dynamic_cast<const SdrGrafObj*>( pObj) )
+ if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap )
+ bEnable = true;
+ }
+
+ if( !bEnable )
+ rSet.DisableItem( SID_COMPRESS_GRAPHIC );
+}
+
+void ScGraphicShell::ExecuteCompressGraphic( SAL_UNUSED_PARAMETER SfxRequest& )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->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(GetViewData().GetDialogParent(), pGraphicObj, GetViewData().GetBindings());
+ if (dialog.run() == RET_OK)
+ {
+ SdrGrafObj* pNewObject = dialog.GetCompressedSdrGrafObj();
+ SdrPageView* pPageView = pView->GetSdrPageView();
+ OUString aUndoString = pView->GetDescriptionOfMarkedObjects() + " Compress";
+ pView->BegUndo( aUndoString );
+ pView->ReplaceObjectAtView( pObj, *pPageView, pNewObject );
+ pView->EndUndo();
+ }
+ }
+ }
+
+ Invalidate();
+}
+
+void ScGraphicShell::GetCropGraphicState( SfxItemSet& rSet )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ bool bEnable = false;
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGraphicObj = dynamic_cast<const SdrGrafObj*>( pObj) )
+ if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap )
+ bEnable = true;
+ }
+
+ if( !bEnable )
+ rSet.DisableItem( SID_OBJECT_CROP );
+}
+
+void ScGraphicShell::ExecuteCropGraphic( SAL_UNUSED_PARAMETER SfxRequest& )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGraphicObj = dynamic_cast<const SdrGrafObj*>( pObj) )
+ if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap )
+ {
+ pView->SetEditMode(SdrViewEditMode::Edit);
+ pView->SetDragMode(SdrDragMode::Crop);
+ }
+ }
+
+ Invalidate();
+}
+
+void ScGraphicShell::ExecuteSaveGraphic( SAL_UNUSED_PARAMETER SfxRequest& /*rReq*/)
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ const SdrGrafObj* pObj = dynamic_cast<const SdrGrafObj*>(rMarkList.GetMark( 0 )->GetMarkedSdrObj());
+ if( pObj && pObj->GetGraphicType() == GraphicType::Bitmap )
+ {
+ GraphicAttr aGraphicAttr = pObj->GetGraphicAttr();
+ short nState = RET_CANCEL;
+ vcl::Window* pWin = GetViewData().GetActiveWin();
+ weld::Window* pWinFrame = pWin ? pWin->GetFrameWeld() : nullptr;
+ if (aGraphicAttr != GraphicAttr()) // the image has been modified
+ {
+ if (pWin)
+ {
+ nState = GraphicHelper::HasToSaveTransformedImage(pWinFrame);
+ }
+ }
+ else
+ {
+ nState = RET_NO;
+ }
+
+ if (nState == RET_YES)
+ {
+ GraphicHelper::ExportGraphic(pWinFrame, pObj->GetTransformedGraphic(), "");
+ }
+ else if (nState == RET_NO)
+ {
+ const GraphicObject& aGraphicObject(pObj->GetGraphicObject());
+ GraphicHelper::ExportGraphic(pWinFrame, aGraphicObject.GetGraphic(), "");
+ }
+ }
+ }
+
+ Invalidate();
+}
+
+void ScGraphicShell::GetSaveGraphicState(SfxItemSet &rSet)
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ bool bEnable = false;
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGraphicObj = dynamic_cast<const SdrGrafObj*>( pObj) )
+ if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap )
+ bEnable = true;
+ }
+
+ if (GetObjectShell()->isExportLocked())
+ bEnable = false;
+
+ if( !bEnable )
+ rSet.DisableItem( SID_SAVE_GRAPHIC );
+}
+
+void ScGraphicShell::ExecuteChangePicture( SAL_UNUSED_PARAMETER SfxRequest& /*rReq*/)
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGraphicObj = dynamic_cast<SdrGrafObj*>( pObj) )
+ if( pGraphicObj->GetGraphicType() == GraphicType::Bitmap )
+ {
+ vcl::Window* pWin = GetViewData().GetActiveWin();
+ SvxOpenGraphicDialog aDlg(ScResId(STR_INSERTGRAPHIC), pWin ? pWin->GetFrameWeld() : nullptr);
+
+ if( aDlg.Execute() == ERRCODE_NONE )
+ {
+ Graphic aGraphic;
+ ErrCode nError = aDlg.GetGraphic(aGraphic);
+ if( nError == ERRCODE_NONE )
+ {
+ SdrGrafObj* pNewObject(pGraphicObj->CloneSdrObject(pGraphicObj->getSdrModelFromSdrObject()));
+ pNewObject->SetGraphic( aGraphic );
+ SdrPageView* pPageView = pView->GetSdrPageView();
+ OUString aUndoString = pView->GetDescriptionOfMarkedObjects() + " Change";
+ pView->BegUndo( aUndoString );
+ pView->ReplaceObjectAtView( pObj, *pPageView, pNewObject );
+ pView->EndUndo();
+ }
+ }
+ }
+ }
+
+ Invalidate();
+}
+
+void ScGraphicShell::GetChangePictureState(SfxItemSet &rSet)
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ bool bEnable = false;
+ if( rMarkList.GetMarkCount() == 1 )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+
+ if( auto pGrafObj = dynamic_cast<const SdrGrafObj*>( pObj) )
+ if( pGrafObj->GetGraphicType() == GraphicType::Bitmap )
+ bEnable = true;
+ }
+
+ if( !bEnable )
+ rSet.DisableItem( SID_CHANGE_PICTURE );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/mediash.cxx b/sc/source/ui/drawfunc/mediash.cxx
new file mode 100644
index 000000000..f5b3350ba
--- /dev/null
+++ b/sc/source/ui/drawfunc/mediash.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 <sfx2/objface.hxx>
+#include <vcl/EnumContext.hxx>
+#include <svx/MediaShellHelpers.hxx>
+
+#include <mediash.hxx>
+#include <strings.hrc>
+#include <viewdata.hxx>
+#include <drawview.hxx>
+#include <scresid.hxx>
+
+#define ShellClass_ScMediaShell
+#include <scslots.hxx>
+
+using namespace svx;
+
+SFX_IMPL_INTERFACE(ScMediaShell, ScDrawShell)
+
+void ScMediaShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT, SfxVisibilityFlags::Invisible,
+ ToolbarId::Media_Objectbar);
+
+ GetStaticInterface()->RegisterPopupMenu("media");
+}
+
+ScMediaShell::ScMediaShell(ScViewData& rData)
+ : ScDrawShell(rData)
+{
+ SetName(ScResId(SCSTR_MEDIASHELL));
+ SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Media));
+}
+
+ScMediaShell::~ScMediaShell() {}
+
+void ScMediaShell::GetMediaState(SfxItemSet& rSet)
+{
+ MediaShellHelpers::GetState(GetViewData().GetScDrawView(), rSet);
+}
+
+void ScMediaShell::ExecuteMedia(const SfxRequest& rReq)
+{
+ MediaShellHelpers::Execute(GetViewData().GetScDrawView(), rReq);
+ Invalidate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/drawfunc/oleobjsh.cxx b/sc/source/ui/drawfunc/oleobjsh.cxx
new file mode 100644
index 000000000..0e9f0075d
--- /dev/null
+++ b/sc/source/ui/drawfunc/oleobjsh.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/objface.hxx>
+
+#include <oleobjsh.hxx>
+#include <vcl/EnumContext.hxx>
+
+#define ShellClass_ScOleObjectShell
+#include <scslots.hxx>
+
+SFX_IMPL_INTERFACE(ScOleObjectShell, ScDrawShell)
+
+void ScOleObjectShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT,
+ SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server,
+ ToolbarId::Draw_Objectbar);
+
+ GetStaticInterface()->RegisterPopupMenu("oleobject");
+}
+
+
+ScOleObjectShell::ScOleObjectShell(ScViewData& rData) :
+ ScDrawShell(rData)
+{
+ SetName("OleObject");
+ SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::OLE));
+}
+
+ScOleObjectShell::~ScOleObjectShell()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/formdlg/dwfunctr.cxx b/sc/source/ui/formdlg/dwfunctr.cxx
new file mode 100644
index 000000000..424c0ee99
--- /dev/null
+++ b/sc/source/ui/formdlg/dwfunctr.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 <comphelper/string.hxx>
+#include <editeng/editview.hxx>
+#include <sfx2/viewsh.hxx>
+#include <formula/funcvarargs.h>
+
+#include <global.hxx>
+#include <scmod.hxx>
+#include <inputhdl.hxx>
+#include <tabvwsh.hxx>
+#include <funcdesc.hxx>
+
+#include <dwfunctr.hxx>
+
+/*************************************************************************
+#* Member: ScFunctionWin
+#*------------------------------------------------------------------------
+#*
+#* Class: ScFunctionWin
+#*
+#* Function: Constructor of ScFunctionWin Class
+#*
+#* Input: Sfx - links, window, resource
+#*
+#* Output: ---
+#*
+#************************************************************************/
+
+ScFunctionWin::ScFunctionWin(weld::Widget* pParent)
+ : PanelLayout(pParent, "FunctionPanel", "modules/scalc/ui/functionpanel.ui")
+ , xCatBox(m_xBuilder->weld_combo_box("category"))
+ , xFuncList(m_xBuilder->weld_tree_view("funclist"))
+ , xInsertButton(m_xBuilder->weld_button("insert"))
+ , xFiFuncDesc(m_xBuilder->weld_label("funcdesc"))
+ , xConfigListener(new comphelper::ConfigurationListener("/org.openoffice.Office.Calc/Formula/Syntax"))
+ , xConfigChange(std::make_unique<EnglishFunctionNameChange>(xConfigListener, this))
+ , pFuncDesc(nullptr)
+{
+ xFuncList->set_size_request(-1, xFuncList->get_height_rows(10));
+
+ InitLRUList();
+
+ nArgs=0;
+ xFiFuncDesc->set_size_request(-1, 5 * xFiFuncDesc->get_text_height());
+
+ xCatBox->connect_changed(LINK( this, ScFunctionWin, SelComboHdl));
+ xFuncList->connect_changed(LINK( this, ScFunctionWin, SelTreeHdl));
+
+ xFuncList->connect_row_activated(LINK( this, ScFunctionWin, SetRowActivatedHdl));
+ xInsertButton->connect_clicked(LINK( this, ScFunctionWin, SetSelectionClickHdl));
+
+ xCatBox->set_active(0);
+
+ SelComboHdl(*xCatBox);
+}
+
+/*************************************************************************
+#* Member: ScFunctionWin
+#*------------------------------------------------------------------------
+#*
+#* Class: ScFunctionWin
+#*
+#* Function: Destructor of ScFunctionWin Class
+#*
+#* Input: ---
+#*
+#* Output: ---
+#*
+#************************************************************************/
+
+ScFunctionWin::~ScFunctionWin()
+{
+ xConfigChange.reset();
+ xConfigListener->dispose();
+ xConfigListener.clear();
+
+ xCatBox.reset();
+ xFuncList.reset();
+ xInsertButton.reset();
+ xFiFuncDesc.reset();
+}
+
+/*************************************************************************
+#* Member: UpdateFunctionList
+#*------------------------------------------------------------------------
+#*
+#* Class: ScFunctionWin
+#*
+#* Function: Updates the list of functions depending on the set category
+#*
+#* Input: ---
+#*
+#* Output: ---
+#*
+#************************************************************************/
+
+void ScFunctionWin::InitLRUList()
+{
+ ScFunctionMgr* pFuncMgr = ScGlobal::GetStarCalcFunctionMgr();
+ pFuncMgr->fillLastRecentlyUsedFunctions(aLRUList);
+
+ sal_Int32 nSelPos = xCatBox->get_active();
+
+ if (nSelPos == 0)
+ UpdateFunctionList();
+}
+
+/*************************************************************************
+#* Member: UpdateFunctionList
+#*------------------------------------------------------------------------
+#*
+#* Class: ScFunctionWin
+#*
+#* Function: Updates the list of last used functions.
+#*
+#* Input: ---
+#*
+#* Output: ---
+#*
+#************************************************************************/
+
+void ScFunctionWin::UpdateLRUList()
+{
+ if (pFuncDesc && pFuncDesc->nFIndex!=0)
+ {
+ ScModule* pScMod = SC_MOD();
+ pScMod->InsertEntryToLRUList(pFuncDesc->nFIndex);
+ }
+}
+
+/*************************************************************************
+#* Member: SetDescription
+#*------------------------------------------------------------------------
+#*
+#* Class: ScFunctionWin
+#*
+#* Function:
+#*
+#* Input: ---
+#*
+#* Output: ---
+#*
+#************************************************************************/
+
+void ScFunctionWin::SetDescription()
+{
+ xFiFuncDesc->set_label(OUString());
+ const ScFuncDesc* pDesc =
+ weld::fromId<const ScFuncDesc*>(xFuncList->get_selected_id());
+ if (pDesc)
+ {
+ pDesc->initArgumentInfo(); // full argument info is needed
+
+ OUString aBuf = xFuncList->get_selected_text() +
+ ":\n\n" +
+ pDesc->GetParamList() +
+ "\n\n" +
+ *pDesc->mxFuncDesc;
+
+ xFiFuncDesc->set_label(aBuf);
+ }
+}
+
+/*************************************************************************
+#* Member: UpdateFunctionList
+#*------------------------------------------------------------------------
+#*
+#* Class: ScFunctionWin
+#*
+#* Function: Updates the list of functions depending on the set category
+#*
+#* Input: ---
+#*
+#* Output: ---
+#*
+#************************************************************************/
+
+void ScFunctionWin::UpdateFunctionList()
+{
+ sal_Int32 nSelPos = xCatBox->get_active();
+ sal_Int32 nCategory = ( -1 != nSelPos )
+ ? (nSelPos-1) : 0;
+
+ xFuncList->clear();
+ xFuncList->freeze();
+
+ if ( nSelPos > 0 )
+ {
+ ScFunctionMgr* pFuncMgr = ScGlobal::GetStarCalcFunctionMgr();
+
+ const ScFuncDesc* pDesc = pFuncMgr->First( nCategory );
+ while ( pDesc )
+ {
+ xFuncList->append(weld::toId(pDesc), *(pDesc->mxFuncName));
+ pDesc = pFuncMgr->Next();
+ }
+ }
+ else // LRU list
+ {
+ for (const formula::IFunctionDescription* pDesc : aLRUList)
+ {
+ if (pDesc)
+ {
+ xFuncList->append(weld::toId(pDesc), pDesc->getFunctionName());
+ }
+ }
+ }
+
+ xFuncList->thaw();
+
+ if (xFuncList->n_children() > 0)
+ {
+ xFuncList->set_sensitive(true);
+ xFuncList->select(0);
+ }
+ else
+ {
+ xFuncList->set_sensitive(false);
+ }
+}
+
+/*************************************************************************
+#* Member: DoEnter
+#*------------------------------------------------------------------------
+#*
+#* Class: ScFunctionWin
+#*
+#* Function: Save input into document. Is called after clicking the
+#* Apply button or a double-click on the function list.
+#*
+#* Input: ---
+#*
+#* Output: ---
+#*
+#************************************************************************/
+
+void ScFunctionWin::DoEnter()
+{
+ OUStringBuffer aArgStr;
+ OUString aString=xFuncList->get_selected_text();
+ SfxViewShell* pCurSh = SfxViewShell::Current();
+ nArgs=0;
+
+ if(!aString.isEmpty())
+ {
+ OUString aFirstArgStr;
+ ScModule* pScMod = SC_MOD();
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( pCurSh );
+ ScInputHandler* pHdl = pScMod->GetInputHdl( pViewSh );
+ if(!pScMod->IsEditMode())
+ {
+ rtl::Reference<comphelper::ConfigurationListener> xDetectDisposed(xConfigListener);
+ pScMod->SetInputMode(SC_INPUT_TABLE);
+ // the above call can result in us being disposed
+ if (xDetectDisposed->isDisposed())
+ return;
+ aString = "=" + xFuncList->get_selected_text();
+ if (pHdl)
+ pHdl->ClearText();
+ }
+ const ScFuncDesc* pDesc =
+ weld::fromId<const ScFuncDesc*>(xFuncList->get_selected_id());
+ if (pDesc)
+ {
+ pFuncDesc=pDesc;
+ UpdateLRUList();
+ nArgs = pDesc->nArgCount;
+ if(nArgs>0)
+ {
+ // NOTE: Theoretically the first parameter could have the
+ // suppress flag as well, but practically it doesn't.
+ aFirstArgStr = pDesc->maDefArgNames[0];
+ aFirstArgStr = comphelper::string::strip(aFirstArgStr, ' ');
+ aFirstArgStr = aFirstArgStr.replaceAll(" ", "_");
+ aArgStr = aFirstArgStr;
+ if ( nArgs != VAR_ARGS && nArgs != PAIRED_VAR_ARGS )
+ { // no VarArgs or Fix plus VarArgs, but not VarArgs only
+ sal_uInt16 nFix;
+ if (nArgs >= PAIRED_VAR_ARGS)
+ nFix = nArgs - PAIRED_VAR_ARGS + 2;
+ else if (nArgs >= VAR_ARGS)
+ nFix = nArgs - VAR_ARGS + 1;
+ else
+ nFix = nArgs;
+ for ( sal_uInt16 nArg = 1;
+ nArg < nFix && !pDesc->pDefArgFlags[nArg].bOptional; nArg++ )
+ {
+ aArgStr.append("; ");
+ OUString sTmp = pDesc->maDefArgNames[nArg];
+ sTmp = comphelper::string::strip(sTmp, ' ');
+ sTmp = sTmp.replaceAll(" ", "_");
+ aArgStr.append(sTmp);
+ }
+ }
+ }
+ }
+ if (pHdl)
+ {
+ if (pHdl->GetEditString().isEmpty())
+ {
+ aString = "=" + xFuncList->get_selected_text();
+ }
+ EditView *pEdView=pHdl->GetActiveView();
+ if(pEdView!=nullptr) // @ needed because of crash during setting a name
+ {
+ if(nArgs>0)
+ {
+ pHdl->InsertFunction(aString);
+ pEdView->InsertText(aArgStr.makeStringAndClear(),true);
+ ESelection aESel=pEdView->GetSelection();
+ aESel.nEndPos = aESel.nStartPos + aFirstArgStr.getLength();
+ pEdView->SetSelection(aESel);
+ pHdl->DataChanged();
+ }
+ else
+ {
+ aString += "()";
+ pEdView->InsertText(aString);
+ pHdl->DataChanged();
+ }
+ }
+ }
+ InitLRUList();
+ }
+ if ( pCurSh )
+ {
+ vcl::Window* pShellWnd = pCurSh->GetWindow();
+
+ if ( pShellWnd )
+ pShellWnd->GrabFocus();
+ }
+
+}
+
+/*************************************************************************
+#* Handle: SelHdl
+#*------------------------------------------------------------------------
+#*
+#* Class: ScFunctionWin
+#*
+#* Function: A change of the category will update the list of functions.
+#*
+#* Input: ---
+#*
+#* Output: ---
+#*
+#************************************************************************/
+
+IMPL_LINK_NOARG(ScFunctionWin, SelComboHdl, weld::ComboBox&, void)
+{
+ UpdateFunctionList();
+ SetDescription();
+}
+
+IMPL_LINK_NOARG(ScFunctionWin, SelTreeHdl, weld::TreeView&, void)
+{
+ SetDescription();
+}
+
+/*************************************************************************
+#* Handle: SelHdl
+#*------------------------------------------------------------------------
+#*
+#* Class: ScFunctionWin
+#*
+#* Function: A change of the category will update the list of functions.
+#*
+#* Input: ---
+#*
+#* Output: ---
+#*
+#************************************************************************/
+
+IMPL_LINK_NOARG( ScFunctionWin, SetSelectionClickHdl, weld::Button&, void )
+{
+ DoEnter(); // saves the input
+}
+
+IMPL_LINK_NOARG( ScFunctionWin, SetRowActivatedHdl, weld::TreeView&, bool )
+{
+ DoEnter(); // saves the input
+ return true;
+}
+
+void EnglishFunctionNameChange::setProperty(const css::uno::Any &rProperty)
+{
+ ConfigurationListenerProperty::setProperty(rProperty);
+ m_pFunctionWin->InitLRUList();
+ m_pFunctionWin->UpdateFunctionList();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/formdlg/formdata.cxx b/sc/source/ui/formdlg/formdata.cxx
new file mode 100644
index 000000000..aabce7653
--- /dev/null
+++ b/sc/source/ui/formdlg/formdata.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 <formdata.hxx>
+
+ScFormEditData::ScFormEditData()
+ : pInputHandler(nullptr)
+ , pScDocShell(nullptr)
+{
+ Reset();
+}
+
+ScFormEditData::~ScFormEditData() {}
+
+void ScFormEditData::SaveValues() { Reset(); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/formdlg/formula.cxx b/sc/source/ui/formdlg/formula.cxx
new file mode 100644
index 000000000..6f4dfab2c
--- /dev/null
+++ b/sc/source/ui/formdlg/formula.cxx
@@ -0,0 +1,691 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <scitems.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/numformat.hxx>
+#include <svl/stritem.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <tools/urlobj.hxx>
+#include <formula/formulahelper.hxx>
+#include <formula/IFunctionDescription.hxx>
+#include <formula/errorcodes.hxx>
+
+#include <compiler.hxx>
+#include <formula.hxx>
+#include <formdata.hxx>
+#include <reffact.hxx>
+#include <document.hxx>
+#include <simpleformulacalc.hxx>
+#include <scmod.hxx>
+#include <inputhdl.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <funcdesc.hxx>
+#include <tokenarray.hxx>
+#include <sc.hrc>
+#include <servuno.hxx>
+#include <unonames.hxx>
+#include <externalrefmgr.hxx>
+
+#include <com/sun/star/table/CellAddress.hpp>
+#include <com/sun/star/sheet/XFormulaOpCodeMapper.hpp>
+#include <com/sun/star/sheet/XFormulaParser.hpp>
+
+using namespace formula;
+using namespace com::sun::star;
+
+// init/ shared functions for dialog
+
+ScFormulaDlg::ScFormulaDlg(SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, const ScViewData& rViewData, const formula::IFunctionManager* _pFunctionMgr)
+ : formula::FormulaDlg(pB, pCW, pParent, _pFunctionMgr, this)
+ , m_aHelper(this,pB)
+ , m_pViewShell( nullptr )
+{
+ m_aHelper.SetDialog(m_xDialog.get());
+ ScModule* pScMod = SC_MOD();
+ pScMod->InputEnterHandler();
+ m_pViewShell = nullptr;
+
+ // title has to be from the view that opened the dialog,
+ // even if it's not the current view
+
+ if ( pB )
+ {
+ SfxDispatcher* pMyDisp = pB->GetDispatcher();
+ if (pMyDisp)
+ {
+ SfxViewFrame* pMyViewFrm = pMyDisp->GetFrame();
+ if (pMyViewFrm)
+ {
+ m_pViewShell = dynamic_cast<ScTabViewShell*>( pMyViewFrm->GetViewShell() );
+ if( m_pViewShell )
+ m_pViewShell->UpdateInputHandler(true);
+ }
+ }
+ }
+
+ m_pDoc = &rViewData.GetDocument();
+ m_xParser.set(ScServiceProvider::MakeInstance(ScServiceProvider::Type::FORMULAPARS,
+ static_cast<ScDocShell*>(m_pDoc->GetDocumentShell())),uno::UNO_QUERY);
+ uno::Reference< beans::XPropertySet> xSet(m_xParser,uno::UNO_QUERY);
+ xSet->setPropertyValue(SC_UNO_COMPILEFAP, uno::Any(true));
+
+ m_xOpCodeMapper.set(ScServiceProvider::MakeInstance(ScServiceProvider::Type::OPCODEMAPPER,
+ static_cast<ScDocShell*>(m_pDoc->GetDocumentShell())),uno::UNO_QUERY);
+
+ ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl(m_pViewShell);
+
+ assert(pInputHdl && "Missing input handler :-/");
+
+ pInputHdl->NotifyChange( nullptr );
+
+ ScFormulaReferenceHelper::enableInput( true );
+ ScFormulaReferenceHelper::EnableSpreadsheets();
+ m_aHelper.Init();
+ m_aHelper.SetDispatcherLock( true );
+
+ notifyChange();
+ fill();
+
+ ScFormEditData* pData = m_pViewShell->GetFormEditData();
+ if (pData)
+ return;
+
+ pScMod->SetRefInputHdl(pInputHdl);
+
+ m_pDoc = &rViewData.GetDocument();
+ SCCOL nCol = rViewData.GetCurX();
+ SCROW nRow = rViewData.GetCurY();
+ SCTAB nTab = rViewData.GetTabNo();
+ m_CursorPos = ScAddress( nCol, nRow, nTab );
+
+ m_pViewShell->InitFormEditData(); // create new
+ pData = m_pViewShell->GetFormEditData();
+ pData->SetInputHandler(pInputHdl);
+ pData->SetDocShell(rViewData.GetDocShell());
+
+ OSL_ENSURE(pData,"FormEditData not available");
+
+ formula::FormulaDlgMode eMode = FormulaDlgMode::Formula; // default...
+
+ // edit if formula exists
+
+ OUString aFormula = m_pDoc->GetFormula( nCol, nRow, nTab );
+ bool bEdit = ( aFormula.getLength() > 1 );
+ bool bMatrix = false;
+ if ( bEdit )
+ {
+ bMatrix = CheckMatrix(aFormula);
+
+ sal_Int32 nFStart = 0;
+ sal_Int32 nFEnd = 0;
+ if ( GetFormulaHelper().GetNextFunc( aFormula, false, nFStart, &nFEnd) )
+ {
+ pInputHdl->InputReplaceSelection( aFormula );
+ pInputHdl->InputSetSelection( nFStart, nFEnd );
+ sal_Int32 PrivStart, PrivEnd;
+ pInputHdl->InputGetSelection( PrivStart, PrivEnd);
+
+ eMode = SetMeText(pInputHdl->GetFormString(),PrivStart, PrivEnd, bMatrix, true, true);
+ pData->SetFStart( nFStart );
+ }
+ else
+ bEdit = false;
+ }
+
+ if ( !bEdit )
+ {
+ OUString aNewFormula('=');
+ if ( aFormula.startsWith("=") )
+ aNewFormula = aFormula;
+
+ pInputHdl->InputReplaceSelection( aNewFormula );
+ pInputHdl->InputSetSelection( 1, aNewFormula.getLength()+1 );
+ sal_Int32 PrivStart, PrivEnd;
+ pInputHdl->InputGetSelection( PrivStart, PrivEnd);
+ SetMeText(pInputHdl->GetFormString(),PrivStart, PrivEnd,bMatrix,false,false);
+
+ pData->SetFStart( 1 ); // after "="
+ }
+
+ pData->SetMode( eMode );
+ OUString rStrExp = GetMeText();
+
+ Update(rStrExp);
+
+}
+
+void ScFormulaDlg::notifyChange()
+{
+ ScInputHandler* pInputHdl = m_pViewShell->GetInputHandler();
+ if ( pInputHdl )
+ pInputHdl->NotifyChange( nullptr );
+}
+
+void ScFormulaDlg::fill()
+{
+ ScModule* pScMod = SC_MOD();
+ ScFormEditData* pData = static_cast<ScFormEditData*>(getFormEditData());
+ notifyChange();
+ OUString rStrExp;
+ if (!pData)
+ return;
+
+ // data exists -> restore state (after switch)
+ // don't reinitialise m_pDoc and m_CursorPos
+ //pDoc = rViewData.GetDocument();
+ if(IsInputHdl(pData->GetInputHandler()))
+ {
+ pScMod->SetRefInputHdl(pData->GetInputHandler());
+ }
+ else
+ {
+ ScTabViewShell* pTabViewShell;
+ ScInputHandler* pInputHdl = GetNextInputHandler(pData->GetDocShell(),&pTabViewShell);
+
+ if ( pInputHdl == nullptr ) //no more InputHandler for DocShell
+ {
+ disableOk();
+ pInputHdl = pScMod->GetInputHdl();
+ }
+ else
+ {
+ pInputHdl->SetRefViewShell(pTabViewShell);
+ }
+ pScMod->SetRefInputHdl(pInputHdl);
+ pData->SetInputHandler(pInputHdl);
+ }
+
+ OUString aOldFormulaTmp(pData->GetInputHandler()->GetFormString());
+ pData->GetInputHandler()->InputSetSelection( 0, aOldFormulaTmp.getLength());
+
+ rStrExp=pData->GetUndoStr();
+ pData->GetInputHandler()->InputReplaceSelection(rStrExp);
+
+ SetMeText(rStrExp);
+
+ Update();
+ // switch back, maybe new Doc has been opened
+ pScMod->SetRefInputHdl(nullptr);
+}
+
+ScFormulaDlg::~ScFormulaDlg() COVERITY_NOEXCEPT_FALSE
+{
+ ScFormEditData* pData = m_pViewShell->GetFormEditData();
+
+ m_aHelper.dispose();
+
+ if (pData) // close doesn't destroy;
+ {
+ //set back reference input handler
+ SC_MOD()->SetRefInputHdl(nullptr);
+ StoreFormEditData(pData);
+ }
+
+ m_pViewShell->ClearFormEditData();
+}
+
+bool ScFormulaDlg::IsInputHdl(const ScInputHandler* pHdl)
+{
+ bool bAlive = false;
+
+ // belongs InputHandler to a ViewShell?
+
+ SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
+ while ( pSh && !bAlive )
+ {
+ if (static_cast<ScTabViewShell*>(pSh)->GetInputHandler() == pHdl)
+ bAlive = true;
+ pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
+ }
+
+ return bAlive;
+
+}
+
+ScInputHandler* ScFormulaDlg::GetNextInputHandler(const ScDocShell* pDocShell, ScTabViewShell** ppViewSh)
+{
+ ScInputHandler* pHdl=nullptr;
+
+ SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell );
+ while( pFrame && pHdl==nullptr)
+ {
+ SfxViewShell* p = pFrame->GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p );
+ if(pViewSh!=nullptr)
+ {
+ pHdl=pViewSh->GetInputHandler();
+ if(ppViewSh!=nullptr) *ppViewSh=pViewSh;
+ }
+ pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell );
+ }
+
+ return pHdl;
+}
+
+void ScFormulaDlg::Close()
+{
+ if (IsClosing())
+ return;
+
+ DoEnter();
+}
+
+// functions for right side
+
+bool ScFormulaDlg::calculateValue( const OUString& rStrExp, OUString& rStrResult, bool bMatrixFormula )
+{
+ std::optional<ScSimpleFormulaCalculator> pFCell(std::in_place,
+ *m_pDoc, m_CursorPos, rStrExp, bMatrixFormula);
+ pFCell->SetLimitString(true);
+
+ // HACK! to avoid neither #REF! from ColRowNames
+ // if a name is added as actually range in the overall formula,
+ // but is interpreted at the individual representation as single-cell reference
+ bool bColRowName = pFCell->HasColRowName();
+ if ( bColRowName )
+ {
+ // ColRowName from RPN-Code?
+ if ( pFCell->GetCode()->GetCodeLen() <= 1 )
+ { // ==1: area
+ // ==0: would be an area if...
+ OUString aBraced = "(" + rStrExp + ")";
+ pFCell.emplace(*m_pDoc, m_CursorPos, aBraced, bMatrixFormula);
+ pFCell->SetLimitString(true);
+ }
+ else
+ bColRowName = false;
+ }
+
+ FormulaError nErrCode = pFCell->GetErrCode();
+ if ( nErrCode == FormulaError::NONE || pFCell->IsMatrix() )
+ {
+ SvNumberFormatter& aFormatter = *(m_pDoc->GetFormatTable());
+ const Color* pColor;
+ if (pFCell->IsMatrix())
+ {
+ rStrResult = pFCell->GetString().getString();
+ }
+ else if (pFCell->IsValue())
+ {
+ double n = pFCell->GetValue();
+ sal_uLong nFormat = aFormatter.GetStandardFormat( n, 0,
+ pFCell->GetFormatType(), ScGlobal::eLnge );
+ aFormatter.GetOutputString( n, nFormat, rStrResult, &pColor );
+ }
+ else
+ {
+ sal_uLong nFormat = aFormatter.GetStandardFormat(
+ pFCell->GetFormatType(), ScGlobal::eLnge);
+ aFormatter.GetOutputString( pFCell->GetString().getString(), nFormat,
+ rStrResult, &pColor );
+ // Indicate it's a string, so a number string doesn't look numeric.
+ // Escape embedded quotation marks first by doubling them, as
+ // usual. Actually the result can be copy-pasted from the result
+ // box as literal into a formula expression.
+ rStrResult = "\"" + rStrResult.replaceAll( "\"", "\"\"") + "\"";
+ }
+
+ ScRange aTestRange;
+ if ( bColRowName || (aTestRange.Parse(rStrExp, *m_pDoc) & ScRefFlags::VALID) )
+ rStrResult += " ...";
+ // area
+ }
+ else
+ rStrResult += ScGlobal::GetErrorString(nErrCode);
+
+ return true;
+}
+
+std::shared_ptr<formula::FormulaCompiler> ScFormulaDlg::getCompiler() const
+{
+ if (!m_xCompiler)
+ m_xCompiler = std::make_shared<ScCompiler>(*m_pDoc, m_CursorPos, m_pDoc->GetGrammar());
+ return m_xCompiler;
+}
+
+std::unique_ptr<formula::FormulaCompiler> ScFormulaDlg::createCompiler( formula::FormulaTokenArray& rArray ) const
+{
+ ScCompiler* pCompiler = nullptr;
+ ScTokenArray* pArr = dynamic_cast<ScTokenArray*>(&rArray);
+ assert(pArr); // violation of contract and not created using convertToTokenArray()?
+ if (pArr)
+ pCompiler = new ScCompiler(*m_pDoc, m_CursorPos, *pArr, m_pDoc->GetGrammar());
+ return std::unique_ptr<formula::FormulaCompiler>(pCompiler);
+}
+
+// virtual methods of ScAnyRefDlg:
+void ScFormulaDlg::RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton )
+{
+ pEdit->SelectAll();
+ ::std::pair<formula::RefButton*,formula::RefEdit*> aPair = RefInputStartBefore( pEdit, pButton );
+ m_aHelper.RefInputStart( aPair.second, aPair.first);
+ RefInputStartAfter();
+}
+
+void ScFormulaDlg::RefInputDone( bool bForced )
+{
+ m_aHelper.RefInputDone( bForced );
+ RefInputDoneAfter( bForced );
+}
+
+void ScFormulaDlg::SetReference( const ScRange& rRef, ScDocument& rRefDoc )
+{
+ const IFunctionDescription* pFunc = getCurrentFunctionDescription();
+ if ( !(pFunc && pFunc->getSuppressedArgumentCount() > 0) )
+ return;
+
+ Selection theSel;
+ bool bRefNull = UpdateParaWin(theSel);
+
+ if ( rRef.aStart != rRef.aEnd && bRefNull )
+ {
+ RefInputStart(GetActiveEdit());
+ }
+
+ // Pointer-selected => absolute range references for the non-single
+ // dimensions, so in the other dimension (if any) it's still
+ // copy-adjustable.
+ constexpr ScRefFlags eColFlags = ScRefFlags::COL_ABS | ScRefFlags::COL2_ABS;
+ constexpr ScRefFlags eRowFlags = ScRefFlags::ROW_ABS | ScRefFlags::ROW2_ABS;
+ ScRefFlags eRangeFlags = ScRefFlags::ZERO;
+ if (rRef.aStart.Col() != rRef.aEnd.Col())
+ eRangeFlags |= eColFlags;
+ if (rRef.aStart.Row() != rRef.aEnd.Row())
+ eRangeFlags |= eRowFlags;
+ OUString aRefStr;
+ bool bOtherDoc = (&rRefDoc != m_pDoc && rRefDoc.GetDocumentShell()->HasName());
+ if ( bOtherDoc )
+ {
+ // reference to other document - like inputhdl.cxx
+
+ OSL_ENSURE(rRef.aStart.Tab()==rRef.aEnd.Tab(), "nStartTab!=nEndTab");
+
+ // Sheet always 3D and absolute.
+ OUString aTmp( rRef.Format(rRefDoc, ScRefFlags::VALID | ScRefFlags::TAB_ABS_3D | eRangeFlags));
+
+ SfxObjectShell* pObjSh = rRefDoc.GetDocumentShell();
+
+ // #i75893# convert escaped URL of the document to something user friendly
+// OUString aFileName = pObjSh->GetMedium()->GetName();
+ OUString aFileName = pObjSh->GetMedium()->GetURLObject().GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+
+ aRefStr = "'" + aFileName + "'#" + aTmp;
+ }
+ else
+ {
+ // We can't use ScRange::Format here because in R1C1 mode we need
+ // to display the reference position relative to the cursor
+ // position.
+ ScTokenArray aArray(rRefDoc);
+ ScComplexRefData aRefData;
+ aRefData.InitRangeRel(rRefDoc, rRef, m_CursorPos);
+ if ((eRangeFlags & eColFlags) == eColFlags)
+ {
+ aRefData.Ref1.SetAbsCol( rRef.aStart.Col() );
+ aRefData.Ref2.SetAbsCol( rRef.aEnd.Col() );
+ }
+ if ((eRangeFlags & eRowFlags) == eRowFlags)
+ {
+ aRefData.Ref1.SetAbsRow( rRef.aStart.Row() );
+ aRefData.Ref2.SetAbsRow( rRef.aEnd.Row() );
+ }
+ bool bSingle = aRefData.Ref1 == aRefData.Ref2;
+ if (m_CursorPos.Tab() != rRef.aStart.Tab())
+ {
+ // pointer-selected => absolute sheet reference
+ aRefData.Ref1.SetAbsTab( rRef.aStart.Tab() );
+ aRefData.Ref1.SetFlag3D(true);
+ }
+ if (bSingle)
+ aArray.AddSingleReference(aRefData.Ref1);
+ else
+ aArray.AddDoubleReference(aRefData);
+ ScCompiler aComp(*m_pDoc, m_CursorPos, aArray, m_pDoc->GetGrammar());
+ OUStringBuffer aBuf;
+ aComp.CreateStringFromTokenArray(aBuf);
+ aRefStr = aBuf.makeStringAndClear();
+ }
+
+ UpdateParaWin(theSel,aRefStr);
+}
+
+bool ScFormulaDlg::IsRefInputMode() const
+{
+ const IFunctionDescription* pDesc = getCurrentFunctionDescription();
+ bool bRef = (pDesc && (pDesc->getSuppressedArgumentCount() > 0)) && (m_pDoc != nullptr);
+ return bRef;
+}
+
+bool ScFormulaDlg::IsDocAllowed(SfxObjectShell* pDocSh) const
+{
+ // not allowed: different from this doc, and no name
+ // pDocSh is always a ScDocShell
+ return !pDocSh || &static_cast<ScDocShell*>(pDocSh)->GetDocument() == m_pDoc || pDocSh->HasName(); // everything else is allowed
+}
+
+void ScFormulaDlg::SetActive()
+{
+ const IFunctionDescription* pFunc = getCurrentFunctionDescription();
+ if ( pFunc && pFunc->getSuppressedArgumentCount() > 0 )
+ {
+ RefInputDone();
+ SetEdSelection();
+ }
+}
+
+void ScFormulaDlg::SaveLRUEntry(const ScFuncDesc* pFuncDescP)
+{
+ if (pFuncDescP && pFuncDescP->nFIndex!=0)
+ {
+ ScModule* pScMod = SC_MOD();
+ pScMod->InsertEntryToLRUList(pFuncDescP->nFIndex);
+ }
+}
+
+void ScFormulaDlg::doClose(bool /*_bOk*/)
+{
+ m_aHelper.DoClose( ScFormulaDlgWrapper::GetChildWindowId() );
+}
+void ScFormulaDlg::insertEntryToLRUList(const formula::IFunctionDescription* _pDesc)
+{
+ const ScFuncDesc* pDesc = dynamic_cast<const ScFuncDesc*>(_pDesc);
+ SaveLRUEntry(pDesc);
+}
+void ScFormulaDlg::showReference(const OUString& _sFormula)
+{
+ ShowReference(_sFormula);
+}
+void ScFormulaDlg::ShowReference(const OUString& _sFormula)
+{
+ m_aHelper.ShowReference(_sFormula);
+}
+void ScFormulaDlg::HideReference( bool bDoneRefMode )
+{
+ m_aHelper.HideReference(bDoneRefMode);
+}
+void ScFormulaDlg::ViewShellChanged()
+{
+ ScFormulaReferenceHelper::ViewShellChanged();
+}
+void ScFormulaDlg::AddRefEntry( )
+{
+
+}
+bool ScFormulaDlg::IsTableLocked( ) const
+{
+ // default: reference input can also be used to switch the table
+ return false;
+}
+
+void ScFormulaDlg::ToggleCollapsed( formula::RefEdit* pEdit, formula::RefButton* pButton)
+{
+ m_aHelper.ToggleCollapsed(pEdit,pButton);
+}
+
+void ScFormulaDlg::ReleaseFocus( formula::RefEdit* pEdit)
+{
+ m_aHelper.ReleaseFocus(pEdit);
+}
+
+void ScFormulaDlg::dispatch(bool _bOK, bool _bMatrixChecked)
+{
+ SfxBoolItem aRetItem( SID_DLG_RETOK, _bOK );
+ SfxBoolItem aMatItem( SID_DLG_MATRIX, _bMatrixChecked );
+ SfxStringItem aStrItem( SCITEM_STRING, getCurrentFormula() );
+
+ // if edit line is empty (caused by document switching) -> string is empty
+ // -> don't delete old formula
+ if ( aStrItem.GetValue().isEmpty() )
+ aRetItem.SetValue( false ); // sal_False = Cancel
+
+ m_aHelper.SetDispatcherLock( false ); // turn off modal-mode
+
+ clear();
+
+ GetBindings().GetDispatcher()->ExecuteList( SID_INS_FUNCTION,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aRetItem, &aStrItem, &aMatItem });
+}
+void ScFormulaDlg::setDispatcherLock( bool bLock )
+{
+ m_aHelper.SetDispatcherLock( bLock );
+}
+void ScFormulaDlg::deleteFormData()
+{
+ if (m_pViewShell)
+ m_pViewShell->ClearFormEditData(); // pData is invalid!
+}
+void ScFormulaDlg::clear()
+{
+ m_pDoc = nullptr;
+
+ //restore reference inputhandler
+ ScModule* pScMod = SC_MOD();
+ pScMod->SetRefInputHdl(nullptr);
+
+ // force Enable() of edit line
+ ScTabViewShell* pScViewShell = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( pScViewShell )
+ pScViewShell->UpdateInputHandler();
+}
+void ScFormulaDlg::switchBack()
+{
+ // back to the document
+ // (foreign doc could be above - #34222#)
+ ScInputHandler* pHdl = m_pViewShell->GetInputHandler();
+ if ( pHdl )
+ {
+ pHdl->ViewShellGone(nullptr); // -> get active view
+ pHdl->ShowRefFrame();
+ }
+
+ // restore current chart (cause mouse-RefInput)
+ ScTabViewShell* pScViewShell = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ if ( !pScViewShell )
+ return;
+
+ ScViewData& rVD=pScViewShell->GetViewData();
+ SCTAB nExecTab = m_CursorPos.Tab();
+ if ( nExecTab != rVD.GetTabNo() )
+ pScViewShell->SetTabNo( nExecTab );
+
+ SCROW nRow = m_CursorPos.Row();
+ SCCOL nCol = m_CursorPos.Col();
+
+ if(rVD.GetCurX()!=nCol || rVD.GetCurY()!=nRow)
+ pScViewShell->SetCursor(nCol,nRow);
+}
+formula::FormEditData* ScFormulaDlg::getFormEditData() const
+{
+ ScTabViewShell* pViewShell = m_pViewShell;
+ if (pViewShell)
+ return pViewShell->GetFormEditData();
+ return nullptr;
+}
+void ScFormulaDlg::setCurrentFormula(const OUString& _sReplacement)
+{
+ ScModule* pScMod = SC_MOD();
+ {
+ //fdo#69971 We need the EditEngine Modification handler of the inputbar that we
+ //are feeding to be disabled while this dialog is open. Otherwise we end up in
+ //a situation where...
+ //a) this ScFormulaDlg changes the editengine
+ //b) the modify callback gets called
+ //c) which also modifies the editengine
+ //d) on return from that modify handler the editengine attempts to use
+ // old node pointers which were replaced and removed by c
+ //
+ //We turn it off in the ctor and back on in the dtor, but if calc has
+ //to repaint, e.g. when switching to another window and back, then in
+ //ScMultiTextWnd::Paint a new editengine will have been created via
+ //GetEditView with its default Modification handler enabled. So ensure
+ //its off when we will access it via InputReplaceSelection
+ pScMod->InputTurnOffWinEngine();
+ }
+ pScMod->InputReplaceSelection(_sReplacement);
+}
+void ScFormulaDlg::setSelection(sal_Int32 _nStart, sal_Int32 _nEnd)
+{
+ ScModule* pScMod = SC_MOD();
+ pScMod->InputSetSelection( _nStart, _nEnd );
+}
+void ScFormulaDlg::getSelection(sal_Int32& _nStart, sal_Int32& _nEnd) const
+{
+ ScModule* pScMod = SC_MOD();
+ pScMod->InputGetSelection( _nStart, _nEnd );
+}
+OUString ScFormulaDlg::getCurrentFormula() const
+{
+ ScFormEditData* pData = m_pViewShell->GetFormEditData();
+ if (pData && pData->GetInputHandler())
+ return pData->GetInputHandler()->GetFormString();
+ return "";
+}
+formula::IFunctionManager* ScFormulaDlg::getFunctionManager()
+{
+ return ScGlobal::GetStarCalcFunctionMgr();
+}
+uno::Reference< sheet::XFormulaParser> ScFormulaDlg::getFormulaParser() const
+{
+ return m_xParser;
+}
+uno::Reference< sheet::XFormulaOpCodeMapper> ScFormulaDlg::getFormulaOpCodeMapper() const
+{
+ return m_xOpCodeMapper;
+}
+
+table::CellAddress ScFormulaDlg::getReferencePosition() const
+{
+ return table::CellAddress(m_CursorPos.Tab(), m_CursorPos.Col(), m_CursorPos.Row());
+}
+
+::std::unique_ptr<formula::FormulaTokenArray> ScFormulaDlg::convertToTokenArray(const uno::Sequence< sheet::FormulaToken >& _aTokenList)
+{
+ ::std::unique_ptr<formula::FormulaTokenArray> pArray(new ScTokenArray(*m_pDoc));
+ pArray->Fill(_aTokenList, m_pDoc->GetSharedStringPool(), m_pDoc->GetExternalRefManager());
+ return pArray;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibilityHints.hxx b/sc/source/ui/inc/AccessibilityHints.hxx
new file mode 100644
index 000000000..41b8415a6
--- /dev/null
+++ b/sc/source/ui/inc/AccessibilityHints.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 "viewdata.hxx"
+#include <svl/hint.hxx>
+
+class ScAccWinFocusLostHint : public SfxHint
+{
+public:
+ virtual ~ScAccWinFocusLostHint() override;
+};
+
+class ScAccWinFocusGotHint : public SfxHint
+{
+public:
+ virtual ~ScAccWinFocusGotHint() override;
+};
+
+class ScAccGridWinFocusLostHint : public ScAccWinFocusLostHint
+{
+ ScSplitPos eOldGridWin;
+public:
+ ScAccGridWinFocusLostHint( ScSplitPos eOldGridWin );
+ virtual ~ScAccGridWinFocusLostHint() override;
+
+ ScSplitPos GetOldGridWin() const { return eOldGridWin; }
+};
+
+class ScAccGridWinFocusGotHint : public ScAccWinFocusGotHint
+{
+ ScSplitPos eNewGridWin;
+public:
+ ScAccGridWinFocusGotHint( ScSplitPos eNewGridWin );
+ virtual ~ScAccGridWinFocusGotHint() override;
+
+ ScSplitPos GetNewGridWin() const { return eNewGridWin; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibleCell.hxx b/sc/source/ui/inc/AccessibleCell.hxx
new file mode 100644
index 000000000..c47b73957
--- /dev/null
+++ b/sc/source/ui/inc/AccessibleCell.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <memory>
+#include "AccessibleCellBase.hxx"
+#include "viewdata.hxx"
+#include <com/sun/star/accessibility/XAccessibleExtendedAttributes.hpp>
+#include <rtl/ref.hxx>
+#include <editeng/AccessibleStaticTextBase.hxx>
+#include <comphelper/uno3.hxx>
+
+namespace com::sun::star::accessibility { class XAccessibleRelationSet; }
+namespace utl { class AccessibleRelationSetHelper; }
+
+class ScTabViewShell;
+class ScAccessibleDocument;
+
+typedef cppu::ImplHelper1< css::accessibility::XAccessibleExtendedAttributes>
+ ScAccessibleCellAttributeImpl;
+
+/** @descr
+ This base class provides an implementation of the
+ <code>AccessibleCell</code> service.
+*/
+class ScAccessibleCell
+ : public ScAccessibleCellBase,
+ public accessibility::AccessibleStaticTextBase,
+ public ScAccessibleCellAttributeImpl
+{
+public:
+ static rtl::Reference<ScAccessibleCell> create(
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScTabViewShell* pViewShell,
+ const ScAddress& rCellAddress,
+ sal_Int32 nIndex,
+ ScSplitPos eSplitPos,
+ ScAccessibleDocument* pAccDoc);
+
+private:
+ ScAccessibleCell(
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScTabViewShell* pViewShell,
+ const ScAddress& rCellAddress,
+ sal_Int32 nIndex,
+ ScSplitPos eSplitPos,
+ ScAccessibleDocument* pAccDoc);
+
+ virtual void Init() override;
+
+ using ScAccessibleCellBase::disposing;
+ virtual void SAL_CALL disposing() override;
+
+protected:
+ virtual ~ScAccessibleCell() override;
+
+ using ScAccessibleCellBase::IsDefunc;
+
+public:
+ ///===== XInterface =====================================================
+
+ DECLARE_XINTERFACE()
+
+ ///===== XTypeProvider ===================================================
+
+ DECLARE_XTYPEPROVIDER()
+
+ ///===== XAccessibleComponent ============================================
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ SAL_CALL getAccessibleAtPoint( const css::awt::Point& rPoint ) override;
+
+ virtual void SAL_CALL grabFocus( ) override;
+
+protected:
+ /// Return the object's current bounding box relative to the desktop.
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const override;
+
+ /// Return the object's current bounding box relative to the parent object.
+ virtual tools::Rectangle GetBoundingBox() const override;
+
+public:
+ ///===== XAccessibleContext ==============================================
+
+ /// Return the number of currently visible children.
+ /// override to calculate this on demand
+ virtual sal_Int32 SAL_CALL
+ getAccessibleChildCount() override;
+
+ /// Return the specified child or NULL if index is invalid.
+ /// override to calculate this on demand
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild(sal_Int32 nIndex) override;
+
+ /// Return the set of current states.
+ virtual css::uno::Reference<
+ css::accessibility::XAccessibleStateSet> SAL_CALL
+ getAccessibleStateSet() override;
+
+ virtual css::uno::Reference<
+ css::accessibility::XAccessibleRelationSet> SAL_CALL
+ getAccessibleRelationSet() override;
+
+ ///===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ /** Returns a list of all supported services.
+ */
+ virtual css::uno::Sequence< OUString> SAL_CALL
+ getSupportedServiceNames() override;
+
+ virtual css::uno::Any SAL_CALL getExtendedAttributes() override;
+
+ // Override this method to handle cell's ParaIndent attribute specially.
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getCharacterAttributes( sal_Int32 nIndex, const css::uno::Sequence< OUString >& aRequestedAttributes ) override;
+private:
+ ScTabViewShell* mpViewShell;
+ ScAccessibleDocument* mpAccDoc;
+
+ ScSplitPos meSplitPos;
+
+ bool IsDefunc(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates);
+ virtual bool IsEditable(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates) override;
+ bool IsOpaque() const;
+ bool IsFocused() const;
+ bool IsSelected();
+
+ static ScDocument* GetDocument(ScTabViewShell* mpViewShell);
+
+ ::std::unique_ptr< SvxEditSource > CreateEditSource(ScTabViewShell* pViewShell, ScAddress aCell, ScSplitPos eSplitPos);
+
+ void FillDependents(utl::AccessibleRelationSetHelper* pRelationSet);
+ void FillPrecedents(utl::AccessibleRelationSetHelper* pRelationSet);
+ void AddRelation(const ScAddress& rCell,
+ const sal_uInt16 aRelationType,
+ ::utl::AccessibleRelationSetHelper* pRelationSet);
+ void AddRelation(const ScRange& rRange,
+ const sal_uInt16 aRelationType,
+ ::utl::AccessibleRelationSetHelper* pRelationSet);
+ bool IsFormulaMode();
+ bool IsDropdown() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibleCellBase.hxx b/sc/source/ui/inc/AccessibleCellBase.hxx
new file mode 100644
index 000000000..4779c66dd
--- /dev/null
+++ b/sc/source/ui/inc/AccessibleCellBase.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 "AccessibleContextBase.hxx"
+#include <address.hxx>
+#include <com/sun/star/accessibility/XAccessibleValue.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+typedef cppu::ImplHelper1< css::accessibility::XAccessibleValue>
+ ScAccessibleCellBaseImpl;
+
+class ScAccessibleCellBase
+ : public ScAccessibleContextBase,
+ public ScAccessibleCellBaseImpl
+{
+public:
+ //===== internal ========================================================
+ ScAccessibleCellBase(
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScDocument* pDoc,
+ const ScAddress& rCellAddress,
+ sal_Int32 nIndex);
+protected:
+ virtual ~ScAccessibleCellBase() override;
+public:
+
+ virtual bool isVisible() override;
+
+ ///===== XInterface =====================================================
+
+ virtual css::uno::Any SAL_CALL queryInterface(
+ css::uno::Type const & rType ) override;
+
+ virtual void SAL_CALL acquire() noexcept override;
+
+ virtual void SAL_CALL release() noexcept override;
+
+ ///===== XAccessibleComponent ============================================
+
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ ///===== XAccessibleContext ==============================================
+
+ /// Return this objects index among the parents children.
+ virtual sal_Int32 SAL_CALL
+ getAccessibleIndexInParent() override;
+
+protected:
+ /// Return this object's description.
+ virtual OUString
+ createAccessibleDescription() override;
+
+ /// Return the object's current name.
+ virtual OUString
+ createAccessibleName() override;
+
+public:
+ ///===== XAccessibleValue ================================================
+
+ virtual css::uno::Any SAL_CALL
+ getCurrentValue() override;
+
+ virtual sal_Bool SAL_CALL
+ setCurrentValue( const css::uno::Any& aNumber ) override;
+
+ virtual css::uno::Any SAL_CALL
+ getMaximumValue( ) override;
+
+ virtual css::uno::Any SAL_CALL
+ getMinimumValue( ) override;
+
+ virtual css::uno::Any SAL_CALL
+ getMinimumIncrement( ) override;
+
+ ///===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ ///===== XTypeProvider ===================================================
+
+ /// returns the possible types
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL
+ getTypes() override;
+
+ /** Returns an implementation id.
+ */
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL
+ getImplementationId() override;
+
+protected:
+ ScAddress maCellAddress;
+
+ ScDocument* mpDoc;
+
+ sal_Int32 mnIndex;
+
+private:
+ virtual bool IsEditable(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates);
+protected:
+ /// @throw css::uno::RuntimeException
+ OUString GetNote() const;
+
+ /// @throw css::uno::RuntimeException
+ OUString GetAllDisplayNote() const;
+ /// @throw css::uno::RuntimeException
+ OUString getShadowAttrs() const;
+ /// @throw css::uno::RuntimeException
+ OUString getBorderAttrs();
+public:
+ const ScAddress& GetCellAddress() const { return maCellAddress; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibleContextBase.hxx b/sc/source/ui/inc/AccessibleContextBase.hxx
new file mode 100644
index 000000000..fe71688b3
--- /dev/null
+++ b/sc/source/ui/inc/AccessibleContextBase.hxx
@@ -0,0 +1,286 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <com/sun/star/accessibility/XAccessibleContext.hpp>
+#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/interfacecontainer.h>
+
+#include <svl/lstner.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase5.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+namespace tools { class Rectangle; }
+
+/** @descr
+ This base class provides an implementation of the
+ <code>AccessibleContext</code> service.
+*/
+
+typedef cppu::WeakAggComponentImplHelper5<
+ css::accessibility::XAccessible,
+ css::accessibility::XAccessibleComponent,
+ css::accessibility::XAccessibleContext,
+ css::accessibility::XAccessibleEventBroadcaster,
+ css::lang::XServiceInfo
+ > ScAccessibleContextBaseWeakImpl;
+
+typedef cppu::ImplHelper1<
+ css::accessibility::XAccessibleEventListener
+ > ScAccessibleContextBaseImplEvent;
+
+class ScAccessibleContextBase
+ : public cppu::BaseMutex,
+ public ScAccessibleContextBaseWeakImpl,
+ public ScAccessibleContextBaseImplEvent,
+ public SfxListener
+{
+public:
+ //===== internal ========================================================
+ ScAccessibleContextBase(
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ const sal_Int16 aRole);
+
+ virtual void Init();
+ virtual void SAL_CALL disposing() override;
+protected:
+ virtual ~ScAccessibleContextBase() override;
+public:
+
+ /// @throws css::uno::RuntimeException
+ bool isShowing();
+
+ /// @throws css::uno::RuntimeException
+ virtual bool isVisible();
+
+ ///===== SfxListener =====================================================
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ ///===== XInterface =====================================================
+
+ virtual css::uno::Any SAL_CALL queryInterface(
+ css::uno::Type const & rType ) override;
+
+ virtual void SAL_CALL acquire() noexcept override;
+
+ virtual void SAL_CALL release() noexcept override;
+
+ ///===== XAccessible =====================================================
+
+ /// Return the XAccessibleContext.
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext> SAL_CALL
+ getAccessibleContext() override;
+
+ ///===== XAccessibleComponent ============================================
+
+ virtual sal_Bool SAL_CALL containsPoint(
+ const css::awt::Point& rPoint ) override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ SAL_CALL getAccessibleAtPoint(
+ const css::awt::Point& rPoint ) override;
+
+ virtual css::awt::Rectangle SAL_CALL getBounds( ) override;
+
+ virtual css::awt::Point SAL_CALL getLocation( ) override;
+
+ virtual css::awt::Point SAL_CALL getLocationOnScreen( ) override;
+
+ virtual css::awt::Size SAL_CALL getSize( ) override;
+
+ virtual void SAL_CALL grabFocus( ) override;
+
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ ///===== XAccessibleContext ==============================================
+
+ /// Return the number of currently visible children.
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+
+ /// Return the specified child or NULL if index is invalid.
+ 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;
+
+ ///===== XAccessibleEventBroadcaster =====================================
+
+ /** Add listener that is informed of future changes of name,
+ description and so on events.
+ */
+ virtual void SAL_CALL
+ addAccessibleEventListener(
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener>& xListener) override;
+
+ // Remove an existing event listener.
+ virtual void SAL_CALL
+ removeAccessibleEventListener(
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener>& xListener) override;
+
+ ///===== XAccessibleEventListener ========================================
+
+ virtual void SAL_CALL
+ disposing( const css::lang::EventObject& Source ) override;
+
+ virtual void SAL_CALL
+ notifyEvent(
+ const css::accessibility::AccessibleEventObject& aEvent ) 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. In this case that is just
+ the AccessibleContext and Accessible service.
+ */
+ virtual css::uno::Sequence< OUString> SAL_CALL
+ getSupportedServiceNames() override;
+
+ ///===== XTypeProvider ===================================================
+
+ /// returns the possible types
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL
+ getTypes() override;
+
+ /** Returns an implementation id.
+ */
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL
+ getImplementationId() override;
+
+protected:
+ /// Return this object's description.
+ ///
+ /// @throws css::uno::RuntimeException
+ virtual OUString
+ createAccessibleDescription();
+
+ /// Return the object's current name.
+ ///
+ /// @throws css::uno::RuntimeException
+ virtual OUString
+ createAccessibleName();
+
+ /// Return the object's current bounding box relative to the desktop.
+ ///
+ /// @throws css::uno::RuntimeException
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const;
+
+ /// Return the object's current bounding box relative to the parent object.
+ ///
+ /// @throws css::uno::RuntimeException
+ virtual tools::Rectangle GetBoundingBox() const;
+
+public:
+ /// Calls all Listener to tell they the change.
+ void
+ CommitChange(const css::accessibility::AccessibleEventObject& rEvent) const;
+
+ /// Use this method to set initial Name without notification
+ void SetName(const OUString& rName) { msName = rName; }
+
+ /// Use this method to set initial Description without notification
+ void SetDescription(const OUString& rDesc) { msDescription = rDesc; }
+
+ void SetParent(const css::uno::Reference<css::accessibility::XAccessible>& rParent) { mxParent = rParent; }
+
+protected:
+ /// Calls all FocusListener to tell they that the focus is gained.
+ void CommitFocusGained() const;
+
+ /// Calls all FocusListener to tell they that the focus is lost.
+ void CommitFocusLost() const;
+
+ bool IsDefunc() const { return rBHelper.bDisposed; }
+
+ /// @throws css::lang::DisposedException
+ void IsObjectValid() const;
+
+ /// Reference to the parent object.
+ css::uno::Reference<css::accessibility::XAccessible> mxParent;
+
+private:
+ /** Description of this object. This is not a constant because it can
+ be set from the outside. Furthermore, it changes according to the
+ draw page's display mode.
+ */
+ OUString msDescription;
+
+ /** Name of this object. It changes according the draw page's
+ display mode.
+ */
+ OUString msName;
+
+ /// client id in the AccessibleEventNotifier queue
+ sal_uInt32 mnClientId;
+
+ /** This is the role of this object.
+ */
+ sal_Int16 maRole;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibleCsvControl.hxx b/sc/source/ui/inc/AccessibleCsvControl.hxx
new file mode 100644
index 000000000..10a65fd9e
--- /dev/null
+++ b/sc/source/ui/inc/AccessibleCsvControl.hxx
@@ -0,0 +1,511 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <com/sun/star/accessibility/AccessibleRole.hpp>
+#include <com/sun/star/accessibility/AccessibleScrollType.hpp>
+#include <com/sun/star/accessibility/XAccessibleText.hpp>
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <tools/gen.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <comphelper/accessiblecomponenthelper.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <cppuhelper/implbase2.hxx>
+#include <cppuhelper/implbase3.hxx>
+#include <editeng/AccessibleStaticTextBase.hxx>
+#include <comphelper/uno3.hxx>
+#include <map>
+
+class ScCsvControl;
+namespace utl { class AccessibleStateSetHelper; }
+
+/** Accessible base class used for CSV controls. */
+class ScAccessibleCsvControl : public comphelper::OAccessibleComponentHelper
+{
+private:
+ ScCsvControl* mpControl; /// Pointer to the VCL control.
+
+public:
+ explicit ScAccessibleCsvControl(ScCsvControl& rControl);
+ virtual ~ScAccessibleCsvControl() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ virtual void SAL_CALL grabFocus( ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+
+ // events -----------------------------------------------------------------
+public:
+ /** Sends a GetFocus or LoseFocus event to all listeners. */
+ virtual void SendFocusEvent( bool bFocused );
+ /** Sends a caret changed event to all listeners. */
+ virtual void SendCaretEvent();
+ /** Sends a visible area changed event to all listeners. */
+ void SendVisibleEvent();
+ /** Sends a selection changed event to all listeners. */
+ void SendSelectionEvent();
+ /** Sends a table model changed event for changed cell contents to all listeners. */
+ virtual void SendTableUpdateEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn, bool bAllRows );
+ /** Sends a table model changed event for an inserted column to all listeners. */
+ virtual void SendInsertColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn );
+ /** Sends a table model changed event for a removed column to all listeners. */
+ virtual void SendRemoveColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn );
+
+ // helpers ----------------------------------------------------------------
+protected:
+ virtual css::awt::Rectangle implGetBounds() override;
+
+ /** Returns the VCL control. Assumes a living object. */
+ ScCsvControl& implGetControl() const;
+
+ /** Creates a StateSetHelper and fills it with DEFUNC, OPAQUE, ENABLED, SHOWING and VISIBLE. */
+ rtl::Reference<::utl::AccessibleStateSetHelper> implCreateStateSet();
+};
+
+class ScCsvRuler;
+
+typedef ::cppu::ImplHelper2<css::accessibility::XAccessible,
+ css::accessibility::XAccessibleText> ScAccessibleCsvRulerImpl;
+
+/** Accessible class representing the CSV ruler control. */
+class ScAccessibleCsvRuler : public ScAccessibleCsvControl, public ScAccessibleCsvRulerImpl
+{
+private:
+ OUStringBuffer maBuffer; /// Contains the text representation of the ruler.
+
+public:
+ explicit ScAccessibleCsvRuler( ScCsvRuler& rRuler );
+ virtual ~ScAccessibleCsvRuler() override;
+
+ // XAccessibleComponent -----------------------------------------------------
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override { return this; }
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ // XAccessibleContext -----------------------------------------------------
+
+ /** Returns the child count (the ruler does not have children). */
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+
+ /** Throws an exception (the ruler does not have children). */
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 nIndex ) override;
+
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override { return css::accessibility::AccessibleRole::TEXT; }
+
+ /** Returns the relation to the grid control. */
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet() override;
+
+ /** Returns the current set of states. */
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet() override;
+
+ // XAccessibleText --------------------------------------------------------
+
+ /** Return the position of the caret. */
+ virtual sal_Int32 SAL_CALL getCaretPosition() override;
+
+ /** Sets the position of the caret. */
+ virtual sal_Bool SAL_CALL setCaretPosition( sal_Int32 nIndex ) override;
+
+ /** Returns the specified character. */
+ virtual sal_Unicode SAL_CALL getCharacter( sal_Int32 nIndex ) override;
+
+ /** Returns the attributes of the specified character. */
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getCharacterAttributes( sal_Int32 nIndex, const css::uno::Sequence< OUString >& aRequestedAttributes ) override;
+
+ /** Returns the screen coordinates of the specified character. */
+ virtual css::awt::Rectangle SAL_CALL getCharacterBounds( sal_Int32 nIndex ) override;
+
+ /** Returns the count of characters. */
+ virtual sal_Int32 SAL_CALL getCharacterCount() override;
+
+ /** Returns the character index at the specified coordinate (object's coordinate system). */
+ virtual sal_Int32 SAL_CALL getIndexAtPoint( const css::awt::Point& rPoint ) override;
+
+ /** Returns the selected text (ruler returns empty string). */
+ virtual OUString SAL_CALL getSelectedText() override;
+
+ /** Returns the start index of the selection (ruler returns -1). */
+ virtual sal_Int32 SAL_CALL getSelectionStart() override;
+
+ /** Returns the end index of the selection (ruler returns -1). */
+ virtual sal_Int32 SAL_CALL getSelectionEnd() override;
+
+ /** Selects a part of the text (ruler does nothing). */
+ virtual sal_Bool SAL_CALL setSelection( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) override;
+
+ /** Returns the entire text. */
+ virtual OUString SAL_CALL getText() override;
+
+ /** Returns the specified range [Start,End) of the text. */
+ virtual OUString SAL_CALL getTextRange( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) override;
+
+ /** Returns the specified text portion. */
+ virtual css::accessibility::TextSegment SAL_CALL getTextAtIndex( sal_Int32 nIndex, sal_Int16 aTextType ) override;
+ virtual css::accessibility::TextSegment SAL_CALL getTextBeforeIndex( sal_Int32 nIndex, sal_Int16 aTextType ) override;
+ virtual css::accessibility::TextSegment SAL_CALL getTextBehindIndex( sal_Int32 nIndex, sal_Int16 aTextType ) override;
+
+ /** Copies the specified text range into the clipboard (ruler does nothing). */
+ virtual sal_Bool SAL_CALL copyText( sal_Int32 nStartIndex, sal_Int32 nEndIndex ) override;
+
+ virtual sal_Bool SAL_CALL scrollSubstringTo( sal_Int32 nStartIndex, sal_Int32 nEndIndex, css::accessibility::AccessibleScrollType aScrollType) override;
+
+ // XInterface -------------------------------------------------------------
+
+ DECLARE_XINTERFACE()
+
+ // XTypeProvider ----------------------------------------------------------
+
+ DECLARE_XTYPEPROVIDER()
+
+ // events -----------------------------------------------------------------
+public:
+ /** Sends a caret changed event to all listeners. */
+ virtual void SendCaretEvent() override;
+
+ // helpers ----------------------------------------------------------------
+private:
+
+ /** @throws css::lang::IndexOutOfBoundsException if the specified character position is invalid (outside 0..len-1). */
+ void ensureValidIndex( sal_Int32 nIndex ) const;
+ /** @throws css::lang::IndexOutOfBoundsException if the specified character position is invalid (outside 0..len). */
+ void ensureValidIndexWithEnd( sal_Int32 nIndex ) const;
+ /** @throws css::lang::IndexOutOfBoundsException if the specified character range [Start,End) is invalid.
+ @descr If Start>End, swaps Start and End before checking. */
+ void ensureValidRange( sal_Int32& rnStartIndex, sal_Int32& rnEndIndex ) const;
+
+ /** Returns the VCL ruler control. Assumes a living object. */
+ ScCsvRuler& implGetRuler() const;
+
+ /** Builds the entire string buffer.
+
+ @throws css::uno::RuntimeException
+ */
+ void constructStringBuffer();
+ /** Returns the character count of the text. */
+ sal_Int32 implGetTextLength() const;
+
+ /** Returns true, if the character at the specified index has a split. */
+ bool implHasSplit( sal_Int32 nApiPos );
+
+ /** Returns the first character index with equal formatting as at nApiPos. */
+ sal_Int32 implGetFirstEqualFormatted( sal_Int32 nApiPos );
+ /** Returns the last character index with equal formatting as at nApiPos. */
+ sal_Int32 implGetLastEqualFormatted( sal_Int32 nApiPos );
+};
+
+class ScCsvGrid;
+class ScAccessibleCsvCell;
+
+typedef ::cppu::ImplHelper3<
+ css::accessibility::XAccessible,
+ css::accessibility::XAccessibleTable,
+ css::accessibility::XAccessibleSelection >
+ ScAccessibleCsvGridImpl;
+
+/** Accessible class representing the CSV grid control. */
+class ScAccessibleCsvGrid : public ScAccessibleCsvControl, public ScAccessibleCsvGridImpl
+{
+protected:
+ typedef std::map< sal_Int32, rtl::Reference<ScAccessibleCsvCell> > XAccessibleSet;
+
+private:
+ XAccessibleSet maAccessibleChildren;
+
+public:
+ explicit ScAccessibleCsvGrid( ScCsvGrid& rGrid );
+ virtual ~ScAccessibleCsvGrid() override;
+ virtual void SAL_CALL disposing() override;
+
+ // XAccessibleComponent ---------------------------------------------------
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override { return this; }
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+
+ /** Returns the cell at the specified point. */
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleAtPoint( const css::awt::Point& rPoint ) override;
+
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override { return css::accessibility::AccessibleRole::TABLE; }
+
+ // XAccessibleContext -----------------------------------------------------
+
+ /** Returns the child count (count of cells in the table). */
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+
+ /** Returns the specified child cell. */
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 nIndex ) override;
+
+ /** Returns the relation to the ruler control. */
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet() override;
+
+ /** Returns the current set of states. */
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet() override;
+
+ // XAccessibleTable -------------------------------------------------------
+
+ /** Returns the number of rows in the table. */
+ virtual sal_Int32 SAL_CALL getAccessibleRowCount() override;
+
+ /** Returns the number of columns in the table. */
+ virtual sal_Int32 SAL_CALL getAccessibleColumnCount() override;
+
+ /** Returns the description of the specified row in the table. */
+ virtual OUString SAL_CALL getAccessibleRowDescription( sal_Int32 nRow ) override;
+
+ /** Returns the description text of the specified column in the table. */
+ virtual OUString SAL_CALL getAccessibleColumnDescription( sal_Int32 nColumn ) override;
+
+ /** Returns the number of rows occupied at a specified row and column.
+ @descr Returns always 1 (Merged cells not supported). */
+ virtual sal_Int32 SAL_CALL getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ /** Returns the number of rows occupied at a specified row and column.
+ @descr Returns always 1 (Merged cells not supported). */
+ virtual sal_Int32 SAL_CALL getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ /** Returns the row headers as an AccessibleTable. */
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL getAccessibleRowHeaders() override;
+
+ /** Returns the column headers as an AccessibleTable. */
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL getAccessibleColumnHeaders() override;
+
+ /** Returns the selected rows as a sequence. */
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getSelectedAccessibleRows() override;
+
+ /** Returns the selected columns as a sequence. */
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getSelectedAccessibleColumns() override;
+
+ /** Returns true, if the specified row is selected. */
+ virtual sal_Bool SAL_CALL isAccessibleRowSelected( sal_Int32 nRow ) override;
+
+ /** Returns true, if the specified column is selected. */
+ virtual sal_Bool SAL_CALL isAccessibleColumnSelected( sal_Int32 nColumn ) override;
+
+ /** Returns the accessible cell object at the specified position. */
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ /** Returns the caption object of the table. */
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleCaption() override;
+
+ /** Returns the summary description object of the table. */
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleSummary() override;
+
+ /** Returns true, if the cell at a specified position is selected. */
+ virtual sal_Bool SAL_CALL isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ /** Returns the child index of the cell at the specified position. */
+ virtual sal_Int32 SAL_CALL getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ /** Returns the row index of the specified child. */
+ virtual sal_Int32 SAL_CALL getAccessibleRow( sal_Int32 nChildIndex ) override;
+
+ /** Returns the column index of the specified child. */
+ virtual sal_Int32 SAL_CALL getAccessibleColumn( sal_Int32 nChildIndex ) override;
+
+ // XAccessibleSelection ---------------------------------------------------
+
+ /** Selects the specified child (selects the entire column or the entire table). */
+ virtual void SAL_CALL selectAccessibleChild( sal_Int32 nChildIndex ) override;
+
+ /** Returns true, if the specified child is selected. */
+ virtual sal_Bool SAL_CALL isAccessibleChildSelected( sal_Int32 nChildIndex ) override;
+
+ /** Deselects all cells. */
+ virtual void SAL_CALL clearAccessibleSelection() override;
+
+ /** Selects all cells. */
+ virtual void SAL_CALL selectAllAccessibleChildren() override;
+
+ /** Returns the count of selected children. */
+ virtual sal_Int32 SAL_CALL getSelectedAccessibleChildCount() override;
+
+ /** Returns the child with the specified index in all selected children. */
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) override;
+
+ /** Deselects the child with the specified index in all selected children. */
+ virtual void SAL_CALL deselectAccessibleChild( sal_Int32 nSelectedChildIndex ) 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;
+
+ // XTypeProvider ----------------------------------------------------------
+
+ /** Returns a sequence with all supported interface types. */
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+
+ /** Returns an implementation ID. */
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // events -----------------------------------------------------------------
+public:
+ /** Sends a GetFocus or LoseFocus event to all listeners. */
+ virtual void SendFocusEvent( bool bFocused ) override;
+ /** Sends a table model changed event for changed cell contents to all listeners. */
+ virtual void SendTableUpdateEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn, bool bAllRows ) override;
+ /** Sends a table model changed event for an inserted column to all listeners. */
+ virtual void SendInsertColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn ) override;
+ /** Sends a table model changed event for a removed column to all listeners. */
+ virtual void SendRemoveColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn ) override;
+
+ // helpers ----------------------------------------------------------------
+private:
+
+ /** @throws css::lang::IndexOutOfBoundsException if nIndex is not a valid child index. */
+ void ensureValidIndex( sal_Int32 nIndex ) const;
+ /** @Throws css::lang::IndexOutOfBoundsException if the specified position is invalid. */
+ void ensureValidPosition( sal_Int32 nRow, sal_Int32 nColumn ) const;
+
+ /** Returns the VCL grid control. Assumes a living object. */
+ ScCsvGrid& implGetGrid() const;
+
+ /** Returns true, if the specified column (including header) is selected. */
+ bool implIsColumnSelected( sal_Int32 nColumn ) const;
+ /** Selects the specified column (including header). */
+ void implSelectColumn( sal_Int32 nColumn, bool bSelect );
+
+ /** Returns the count of visible rows in the table (including header). */
+ sal_Int32 implGetRowCount() const;
+ /** Returns the total column count in the table (including header). */
+ sal_Int32 implGetColumnCount() const;
+ /** Returns the count of selected columns in the table. */
+ sal_Int32 implGetSelColumnCount() const;
+ /** Returns the total cell count in the table (including header). */
+ sal_Int32 implGetCellCount() const { return implGetRowCount() * implGetColumnCount(); }
+
+ /** Returns the row index from cell index (including header). */
+ sal_Int32 implGetRow( sal_Int32 nIndex ) const { return nIndex / implGetColumnCount(); }
+ /** Returns the column index from cell index (including header). */
+ sal_Int32 implGetColumn( sal_Int32 nIndex ) const { return nIndex % implGetColumnCount(); }
+ /** Returns the absolute column index of the nSelColumn-th selected column. */
+ sal_Int32 implGetSelColumn( sal_Int32 nSelColumn ) const;
+ /** Returns the child index from cell position (including header). */
+ sal_Int32 implGetIndex( sal_Int32 nRow, sal_Int32 nColumn ) const { return nRow * implGetColumnCount() + nColumn; }
+
+ /** Returns the contents of the specified cell (including header). Indexes must be valid. */
+ OUString implGetCellText( sal_Int32 nRow, sal_Int32 nColumn ) const;
+ /** Creates a new accessible object of the specified cell. Indexes must be valid. */
+ rtl::Reference<ScAccessibleCsvCell> implCreateCellObj(sal_Int32 nRow, sal_Int32 nColumn);
+
+ css::uno::Reference<css::accessibility::XAccessible> getAccessibleCell(sal_Int32 nRow, sal_Int32 nColumn);
+};
+
+/** Accessible class representing a cell of the CSV grid control. */
+class ScAccessibleCsvCell : public ScAccessibleCsvControl
+ , public cppu::ImplHelper1<css::accessibility::XAccessible>
+ , public ::accessibility::AccessibleStaticTextBase
+{
+protected:
+ typedef ::std::unique_ptr< SvxEditSource > SvxEditSourcePtr;
+
+private:
+ OUString maCellText; /// The text contents of this cell.
+ sal_Int32 mnLine; /// The grid line index (core index).
+ sal_uInt32 mnColumn; /// The grid column index (core index).
+ sal_Int32 mnIndex; /// The index of the cell in the table.
+
+public:
+ explicit ScAccessibleCsvCell(
+ ScCsvGrid& rGrid,
+ const OUString& rCellText,
+ sal_Int32 nRow, sal_Int32 nColumn);
+ virtual ~ScAccessibleCsvCell() override;
+
+ virtual void SAL_CALL disposing() override;
+
+ // XAccessibleComponent ---------------------------------------------------
+
+ /** Sets the focus to the column of this cell. */
+ virtual void SAL_CALL grabFocus() override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent( ) override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleContext > SAL_CALL getAccessibleContext( ) override { return this; }
+
+ virtual OUString SAL_CALL getAccessibleDescription( ) override;
+ virtual OUString SAL_CALL getAccessibleName( ) override;
+ virtual sal_Int16 SAL_CALL getAccessibleRole( ) override { return css::accessibility::AccessibleRole::TEXT; }
+
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ // XAccessibleContext -----------------------------------------------------
+
+ /** Returns the child count. */
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+
+ /** Returns the specified child. */
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleChild( sal_Int32 nIndex ) override;
+
+ /** Returns the index of this cell in the table. */
+ virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override;
+
+ /** Returns the relation to the ruler control. */
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet() override;
+
+ /** Returns the current set of states. */
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL getAccessibleStateSet() override;
+
+ // XInterface -------------------------------------------------------------
+
+ DECLARE_XINTERFACE()
+
+ // XTypeProvider ----------------------------------------------------------
+
+ DECLARE_XTYPEPROVIDER()
+
+private:
+ /** Returns the VCL grid control. Assumes a living object. */
+ ScCsvGrid& implGetGrid() const;
+ /** Returns the pixel position of the cell (rel. to parent), regardless of visibility. */
+ Point implGetRealPos() const;
+ /** Returns the width of the character count */
+ sal_uInt32 implCalcPixelWidth(sal_uInt32 nChars) const;
+ /** Returns the pixel size of the cell, regardless of visibility. */
+ Size implGetRealSize() const;
+ /** Returns the bounding box of the cell relative in the table. */
+ virtual css::awt::Rectangle implGetBounds() override;
+
+ /** Creates the edit source the text helper needs. */
+ ::std::unique_ptr< SvxEditSource > implCreateEditSource();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibleDocument.hxx b/sc/source/ui/inc/AccessibleDocument.hxx
new file mode 100644
index 000000000..04a1eec44
--- /dev/null
+++ b/sc/source/ui/inc/AccessibleDocument.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "AccessibleDocumentBase.hxx"
+#include "viewdata.hxx"
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/view/XSelectionChangeListener.hpp>
+#include <cppuhelper/implbase3.hxx>
+#include <com/sun/star/accessibility/XAccessibleExtendedAttributes.hpp>
+#include <svx/IAccessibleViewForwarder.hxx>
+
+class ScTabViewShell;
+class ScAccessibleSpreadsheet;
+class ScChildrenShapes;
+class ScAccessibleEditObject;
+class VclWindowEvent;
+
+namespace utl
+{
+ class AccessibleRelationSetHelper;
+}
+
+/** @descr
+ This base class provides an implementation of the
+ <code>AccessibleContext</code> service.
+*/
+
+typedef cppu::ImplHelper3< css::accessibility::XAccessibleSelection,
+ css::accessibility::XAccessibleExtendedAttributes,
+ css::view::XSelectionChangeListener >
+ ScAccessibleDocumentImpl;
+
+class ScAccessibleDocument
+ : public ScAccessibleDocumentBase,
+ public ScAccessibleDocumentImpl,
+ public accessibility::IAccessibleViewForwarder
+{
+public:
+ //===== internal ========================================================
+ ScAccessibleDocument(
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScTabViewShell* pViewShell,
+ ScSplitPos eSplitPos);
+
+ void PreInit();
+
+ virtual void Init() override;
+
+ DECL_LINK( WindowChildEventListener, VclWindowEvent&, void );
+protected:
+ virtual ~ScAccessibleDocument() override;
+
+ using ScAccessibleDocumentBase::IsDefunc;
+
+public:
+
+ virtual void SAL_CALL disposing() override;
+
+ ///===== SfxListener =====================================================
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ ///===== XInterface =====================================================
+
+ virtual css::uno::Any SAL_CALL queryInterface(
+ css::uno::Type const & rType ) override;
+
+ virtual void SAL_CALL acquire() noexcept override;
+
+ virtual void SAL_CALL release() noexcept override;
+
+ ///===== XAccessibleComponent ============================================
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ SAL_CALL getAccessibleAtPoint(
+ const css::awt::Point& rPoint ) override;
+
+ virtual void SAL_CALL grabFocus( ) override;
+
+ ///===== XAccessibleContext ==============================================
+
+ /// Return the number of currently visible children.
+ virtual sal_Int32 SAL_CALL
+ getAccessibleChildCount() override;
+
+ /// Return the specified child or NULL if index is invalid.
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild(sal_Int32 nIndex) override;
+
+ /// Return the set of current states.
+ virtual css::uno::Reference<
+ css::accessibility::XAccessibleStateSet> SAL_CALL
+ getAccessibleStateSet() override;
+
+ virtual OUString SAL_CALL
+ getAccessibleName() override;
+
+ virtual css::uno::Any SAL_CALL getExtendedAttributes() override ;
+ ///===== XAccessibleSelection ===========================================
+
+ virtual void SAL_CALL
+ selectAccessibleChild( sal_Int32 nChildIndex ) override;
+
+ virtual sal_Bool SAL_CALL
+ isAccessibleChildSelected( sal_Int32 nChildIndex ) override;
+
+ virtual void SAL_CALL
+ clearAccessibleSelection( ) override;
+
+ virtual void SAL_CALL
+ selectAllAccessibleChildren( ) override;
+
+ virtual sal_Int32 SAL_CALL
+ getSelectedAccessibleChildCount( ) override;
+
+ virtual css::uno::Reference<
+ css::accessibility::XAccessible > SAL_CALL
+ getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) override;
+
+ virtual void SAL_CALL
+ deselectAccessibleChild( sal_Int32 nChildIndex ) override;
+
+ ///===== XSelectionListener =============================================
+
+ virtual void SAL_CALL selectionChanged( const css::lang::EventObject& aEvent ) override;
+
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ ///===== XServiceInfo ===================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ /** Returns a list of all supported services.
+ */
+ virtual css::uno::Sequence< OUString> SAL_CALL
+ getSupportedServiceNames() override;
+
+ ///===== XTypeProvider ===================================================
+
+ /// returns the possible types
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL
+ getTypes() override;
+
+ /** Returns an implementation id.
+ */
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL
+ getImplementationId() 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. The values
+ are, contrary to the base class, in internal coordinates.
+ */
+ 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
+ * oriented pixel size.
+
+ @param rSize
+ Size in internal coordinates.
+
+ @return
+ The same size but in screen coordinates.
+ */
+ virtual Size LogicToPixel (const Size& rSize) const override;
+
+ ///======== internal =====================================================
+
+ rtl::Reference<utl::AccessibleRelationSetHelper> GetRelationSet(const ScAddress* pAddress) const;
+
+ css::uno::Reference< css::accessibility::XAccessible >
+ GetAccessibleSpreadsheet();
+
+protected:
+ /// Return this object's description.
+ virtual OUString
+ createAccessibleDescription() override;
+
+ /// Return the object's current name.
+ virtual OUString
+ createAccessibleName() override;
+
+ /// Return the object's current bounding box relative to the desktop.
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const override;
+
+ /// Return the object's current bounding box relative to the parent object.
+ virtual tools::Rectangle GetBoundingBox() const override;
+
+private:
+ ScTabViewShell* mpViewShell;
+ ScSplitPos meSplitPos;
+ rtl::Reference<ScAccessibleSpreadsheet> mpAccessibleSpreadsheet;
+ std::unique_ptr<ScChildrenShapes> mpChildrenShapes;
+ rtl::Reference<ScAccessibleEditObject> mpTempAccEdit;
+ css::uno::Reference<css::accessibility::XAccessible> mxTempAcc;
+ tools::Rectangle maVisArea;
+ bool mbCompleteSheetSelected;
+
+public:
+ SCTAB getVisibleTable() const; // use it in ScChildrenShapes
+
+private:
+ void FreeAccessibleSpreadsheet();
+
+ bool IsTableSelected() const;
+
+ bool IsDefunc(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates);
+
+ void AddChild(const css::uno::Reference<css::accessibility::XAccessible>& xAcc, bool bFireEvent);
+ void RemoveChild(const css::uno::Reference<css::accessibility::XAccessible>& xAcc, bool bFireEvent);
+
+ OUString GetCurrentCellName() const;
+ static OUString GetCurrentCellDescription();
+
+ tools::Rectangle GetVisibleArea_Impl() const;
+public:
+ ScDocument *GetDocument() const ;
+ ScAddress GetCurCellAddress() const;
+
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibleDocumentBase.hxx b/sc/source/ui/inc/AccessibleDocumentBase.hxx
new file mode 100644
index 000000000..23a984f66
--- /dev/null
+++ b/sc/source/ui/inc/AccessibleDocumentBase.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "AccessibleContextBase.hxx"
+
+class ScAccessibleDocumentBase : public ScAccessibleContextBase
+{
+public:
+ //===== internal ========================================================
+ ScAccessibleDocumentBase(const css::uno::Reference<css::accessibility::XAccessible>& rxParent);
+
+protected:
+ virtual ~ScAccessibleDocumentBase() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibleDocumentPagePreview.hxx b/sc/source/ui/inc/AccessibleDocumentPagePreview.hxx
new file mode 100644
index 000000000..45f9d2481
--- /dev/null
+++ b/sc/source/ui/inc/AccessibleDocumentPagePreview.hxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <rtl/ref.hxx>
+
+#include "AccessibleDocumentBase.hxx"
+
+class ScPreviewShell;
+class ScNotesChildren;
+class ScShapeChildren;
+class ScAccessiblePreviewTable;
+class ScAccessiblePageHeader;
+
+class ScAccessibleDocumentPagePreview
+ : public ScAccessibleDocumentBase
+{
+public:
+ //===== internal ========================================================
+ ScAccessibleDocumentPagePreview(
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScPreviewShell* pViewShell );
+protected:
+ virtual ~ScAccessibleDocumentPagePreview() override;
+
+ using ScAccessibleDocumentBase::IsDefunc;
+
+public:
+ using ScAccessibleContextBase::disposing;
+
+ virtual void SAL_CALL disposing() override;
+
+ ///===== SfxListener =====================================================
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ ///===== XAccessibleComponent ============================================
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ SAL_CALL getAccessibleAtPoint(
+ const css::awt::Point& rPoint ) override;
+
+ virtual void SAL_CALL grabFocus( ) override;
+
+ ///===== XAccessibleContext ==============================================
+
+ /// Return the number of currently visible children.
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+
+ /// Return the specified child or NULL if index is invalid.
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild(sal_Int32 nIndex) override;
+
+ /// Return the set of current states.
+ virtual css::uno::Reference<
+ css::accessibility::XAccessibleStateSet> SAL_CALL
+ getAccessibleStateSet() override;
+
+ virtual OUString SAL_CALL getAccessibleName() override;
+ ///===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ /** Returns a list of all supported services.
+ */
+ virtual css::uno::Sequence< OUString> SAL_CALL
+ getSupportedServiceNames() override;
+
+ ///===== XTypeProvider ===================================================
+
+ /** Returns an implementation id.
+ */
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL
+ getImplementationId() override;
+
+ ///===== internal ========================================================
+
+protected:
+ /// Return this object's description.
+ virtual OUString
+ createAccessibleDescription() override;
+
+ /// Return the object's current name.
+ virtual OUString
+ createAccessibleName() override;
+
+public: // needed in ScShapeChildren
+ /// Return the object's current bounding box relative to the desktop.
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const override;
+
+protected:
+ /// Return the object's current bounding box relative to the parent object.
+ virtual tools::Rectangle GetBoundingBox() const override;
+
+private:
+ ScPreviewShell* mpViewShell;
+ std::unique_ptr<ScNotesChildren> mpNotesChildren;
+ std::unique_ptr<ScShapeChildren> mpShapeChildren;
+ rtl::Reference<ScAccessiblePreviewTable> mpTable;
+ rtl::Reference<ScAccessiblePageHeader> mpHeader;
+ rtl::Reference<ScAccessiblePageHeader> mpFooter;
+
+ bool IsDefunc(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates);
+
+ ScNotesChildren* GetNotesChildren();
+ ScShapeChildren* GetShapeChildren();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibleEditObject.hxx b/sc/source/ui/inc/AccessibleEditObject.hxx
new file mode 100644
index 000000000..43a4cba6b
--- /dev/null
+++ b/sc/source/ui/inc/AccessibleEditObject.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 "AccessibleContextBase.hxx"
+
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <address.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/customweld.hxx>
+
+#include <memory>
+
+namespace accessibility
+{
+ class AccessibleTextHelper;
+}
+class EditView;
+class ScTextWnd;
+namespace vcl { class Window; }
+
+/** @descr
+ This base class provides an implementation of the
+ <code>AccessibleCell</code> service.
+*/
+class ScAccessibleEditObject
+ : public ScAccessibleContextBase,
+ public css::accessibility::XAccessibleSelection
+{
+public:
+ enum EditObjectType
+ {
+ CellInEditMode,
+ EditLine,
+ EditControl
+ };
+
+ ScAccessibleEditObject(
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ EditView* pEditView, vcl::Window* pWin, const OUString& rName,
+ const OUString& rDescription, EditObjectType eObjectType);
+
+ void InitAcc(
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ EditView* pEditView, const OUString& rName, const OUString& rDescription);
+
+protected:
+ virtual ~ScAccessibleEditObject() override;
+
+ ScAccessibleEditObject(EditObjectType eObjectType);
+
+ using ScAccessibleContextBase::IsDefunc;
+
+public:
+ using ScAccessibleContextBase::disposing;
+
+ virtual void SAL_CALL disposing() override;
+
+ void LostFocus();
+
+ void GotFocus();
+///===== XInterface =====================================================
+
+ virtual css::uno::Any SAL_CALL queryInterface(
+ css::uno::Type const & rType ) override;
+
+ virtual void SAL_CALL acquire() noexcept override;
+
+ virtual void SAL_CALL release() noexcept override;
+ ///===== XAccessibleComponent ============================================
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ SAL_CALL getAccessibleAtPoint(
+ const css::awt::Point& rPoint ) override;
+
+ virtual OutputDevice* GetOutputDeviceForView();
+
+protected:
+ /// Return the object's current bounding box relative to the desktop.
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const override;
+
+ /// Return the object's current bounding box relative to the parent object.
+ virtual tools::Rectangle GetBoundingBox() const override;
+
+public:
+ ///===== XAccessibleContext ==============================================
+
+ /// Return the number of currently visible children.
+ /// override to calculate this on demand
+ virtual sal_Int32 SAL_CALL
+ getAccessibleChildCount() override;
+
+ /// Return the specified child or NULL if index is invalid.
+ /// override to calculate this on demand
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild(sal_Int32 nIndex) override;
+
+ /// Return the set of current states.
+ virtual css::uno::Reference<
+ css::accessibility::XAccessibleStateSet> SAL_CALL
+ getAccessibleStateSet() 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;
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+protected:
+ /// Return this object's description.
+ virtual OUString
+ createAccessibleDescription() override;
+
+ /// Return the object's current name.
+ virtual OUString
+ createAccessibleName() override;
+
+public:
+ ///===== XAccessibleEventBroadcaster =====================================
+
+ /** Add listener that is informed of future changes of name,
+ description and so on events.
+ */
+ virtual void SAL_CALL
+ addAccessibleEventListener(
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener>& xListener) override;
+
+ // Remove an existing event listener.
+ 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;
+
+ ///===== XTypeProvider ===================================================
+
+ /** Returns an implementation id.
+ */
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL
+ getImplementationId() override;
+
+private:
+ std::unique_ptr<accessibility::AccessibleTextHelper> mpTextHelper;
+ EditView* mpEditView;
+ VclPtr<vcl::Window> mpWindow;
+protected:
+ ScTextWnd* mpTextWnd;
+private:
+ EditObjectType meObjectType;
+ bool mbHasFocus;
+
+ bool IsDefunc(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates);
+
+ void CreateTextHelper();
+ ScDocument *m_pScDoc;
+ ScAddress m_curCellAddress;
+
+ ///===== XAccessibleComponent ============================================
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ sal_Int32 GetFgBgColor( const OUString &strPropColor) ;
+};
+
+class ScAccessibleEditControlObject : public ScAccessibleEditObject
+{
+private:
+ weld::CustomWidgetController* m_pController;
+
+protected:
+ /// Return the object's current bounding box relative to the desktop.
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const override;
+
+ /// Return the object's current bounding box relative to the parent object.
+ virtual tools::Rectangle GetBoundingBox() const override;
+
+public:
+ ScAccessibleEditControlObject(weld::CustomWidgetController* pController, EditObjectType eObjectType)
+ : ScAccessibleEditObject(eObjectType)
+ , m_pController(pController)
+ {
+ }
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleRelationSet > SAL_CALL getAccessibleRelationSet( ) override;
+
+ // for mapping positions/sizes within the TextView to a11y
+ virtual OutputDevice* GetOutputDeviceForView() override;
+
+ using ScAccessibleContextBase::disposing;
+ virtual void SAL_CALL disposing() override;
+};
+
+class ScAccessibleEditLineObject : public ScAccessibleEditControlObject
+{
+public:
+ ScAccessibleEditLineObject(ScTextWnd* pTextWnd);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessiblePageHeader.hxx b/sc/source/ui/inc/AccessiblePageHeader.hxx
new file mode 100644
index 000000000..3e43671b5
--- /dev/null
+++ b/sc/source/ui/inc/AccessiblePageHeader.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 "AccessibleContextBase.hxx"
+#include <editeng/svxenum.hxx>
+#include <rtl/ref.hxx>
+
+class ScPreviewShell;
+class EditTextObject;
+class ScAccessiblePageHeaderArea;
+
+class ScAccessiblePageHeader : public ScAccessibleContextBase
+{
+public:
+ ScAccessiblePageHeader( const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScPreviewShell* pViewShell, bool bHeader, sal_Int32 nIndex );
+
+protected:
+ virtual ~ScAccessiblePageHeader() override;
+
+ using ScAccessibleContextBase::IsDefunc;
+
+public:
+ using ScAccessibleContextBase::disposing;
+ virtual void SAL_CALL disposing() override;
+
+ //===== SfxListener =====================================================
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ //===== XAccessibleComponent ============================================
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+ virtual void SAL_CALL grabFocus() override;
+
+ //===== XAccessibleContext ==============================================
+
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleChild( sal_Int32 i ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL
+ getAccessibleStateSet() override;
+
+ //===== XServiceInfo ====================================================
+
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+protected:
+ virtual OUString createAccessibleDescription() override;
+ virtual OUString createAccessibleName() override;
+
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const override;
+ virtual tools::Rectangle GetBoundingBox() const override;
+
+private:
+ ScPreviewShell* mpViewShell;
+ sal_Int32 mnIndex;
+ bool mbHeader;
+ std::vector< rtl::Reference<ScAccessiblePageHeaderArea> >
+ maAreas;
+ sal_Int32 mnChildCount;
+
+ bool IsDefunc(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates);
+
+ void AddChild(const EditTextObject* pArea, sal_uInt32 nIndex, SvxAdjust eAdjust);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessiblePageHeaderArea.hxx b/sc/source/ui/inc/AccessiblePageHeaderArea.hxx
new file mode 100644
index 000000000..773447f15
--- /dev/null
+++ b/sc/source/ui/inc/AccessiblePageHeaderArea.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "AccessibleContextBase.hxx"
+#include <editeng/svxenum.hxx>
+
+class EditTextObject;
+namespace accessibility
+{
+ class AccessibleTextHelper;
+}
+class ScPreviewShell;
+
+class ScAccessiblePageHeaderArea
+ : public ScAccessibleContextBase
+{
+public:
+ //===== internal ========================================================
+ ScAccessiblePageHeaderArea(
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScPreviewShell* pViewShell,
+ const EditTextObject* pEditObj,
+ SvxAdjust eAdjust);
+protected:
+ virtual ~ScAccessiblePageHeaderArea() override;
+public:
+ const EditTextObject* GetEditTextObject() const { return mpEditObj.get(); }
+
+ using ScAccessibleContextBase::disposing;
+ virtual void SAL_CALL disposing() override;
+
+ ///===== SfxListener =====================================================
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ ///===== XAccessibleComponent ============================================
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ SAL_CALL getAccessibleAtPoint(
+ const css::awt::Point& rPoint ) override;
+
+ ///===== XAccessibleContext ==============================================
+
+ /// Return the number of currently visible children.
+ /// override to calculate this on demand
+ virtual sal_Int32 SAL_CALL
+ getAccessibleChildCount() override;
+
+ /// Return the specified child or NULL if index is invalid.
+ /// override to calculate this on demand
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild(sal_Int32 nIndex) override;
+
+ /// Return the set of current states.
+ virtual css::uno::Reference<
+ css::accessibility::XAccessibleStateSet> SAL_CALL
+ getAccessibleStateSet() override;
+
+ ///===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ /** Returns a list of all supported services. In this case that is just
+ the AccessibleContext and Accessible service.
+ */
+ virtual css::uno::Sequence< OUString> SAL_CALL
+ getSupportedServiceNames() override;
+
+ ///===== XTypeProvider ===================================================
+
+ /** Returns an implementation id.
+ */
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL
+ getImplementationId() override;
+
+protected:
+ virtual OUString createAccessibleDescription() override;
+ virtual OUString createAccessibleName() override;
+
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const override;
+ virtual tools::Rectangle GetBoundingBox() const override;
+
+private:
+ std::unique_ptr<EditTextObject> mpEditObj;
+ std::unique_ptr<accessibility::AccessibleTextHelper> mpTextHelper;
+ ScPreviewShell* mpViewShell;
+ SvxAdjust meAdjust;
+
+ void CreateTextHelper();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessiblePreviewCell.hxx b/sc/source/ui/inc/AccessiblePreviewCell.hxx
new file mode 100644
index 000000000..7d34e5da1
--- /dev/null
+++ b/sc/source/ui/inc/AccessiblePreviewCell.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "AccessibleCellBase.hxx"
+
+class ScPreviewShell;
+
+namespace accessibility
+{
+ class AccessibleTextHelper;
+}
+
+class ScAccessiblePreviewCell : public ScAccessibleCellBase
+{
+public:
+ //===== internal ========================================================
+ ScAccessiblePreviewCell(
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScPreviewShell* pViewShell, const ScAddress& rCellAddress, sal_Int32 nIndex );
+
+protected:
+ virtual ~ScAccessiblePreviewCell() override;
+
+ using ScAccessibleCellBase::IsDefunc;
+
+public:
+ using ScAccessibleCellBase::disposing;
+ virtual void SAL_CALL disposing() override;
+
+ ///===== SfxListener =====================================================
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ //===== XAccessibleComponent ============================================
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+ virtual void SAL_CALL grabFocus() override;
+
+ //===== XAccessibleContext ==============================================
+
+ // override to calculate this on demand
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleChild( sal_Int32 i ) override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL
+ getAccessibleStateSet() override;
+
+ //===== XServiceInfo ====================================================
+
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
+
+ ///===== XTypeProvider ===================================================
+
+ /** Returns an implementation id.
+ */
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL
+ getImplementationId() override;
+
+protected:
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const override;
+ virtual tools::Rectangle GetBoundingBox() const override;
+
+private:
+ ScPreviewShell* mpViewShell;
+
+ std::unique_ptr<accessibility::AccessibleTextHelper> mpTextHelper;
+
+ bool IsDefunc(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates);
+ virtual bool IsEditable(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates) override;
+ bool IsOpaque() const;
+
+ void CreateTextHelper();
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessiblePreviewHeaderCell.hxx b/sc/source/ui/inc/AccessiblePreviewHeaderCell.hxx
new file mode 100644
index 000000000..57612acfc
--- /dev/null
+++ b/sc/source/ui/inc/AccessiblePreviewHeaderCell.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "AccessibleContextBase.hxx"
+#include <com/sun/star/accessibility/XAccessibleValue.hpp>
+#include <tools/gen.hxx>
+#include <address.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+class ScPreviewShell;
+class ScPreviewTableInfo;
+namespace accessibility {
+ class AccessibleTextHelper;
+}
+
+typedef cppu::ImplHelper1< css::accessibility::XAccessibleValue>
+ ScAccessiblePreviewHeaderCellImpl;
+
+class ScAccessiblePreviewHeaderCell :
+ public ScAccessibleContextBase,
+ public ScAccessiblePreviewHeaderCellImpl
+{
+public:
+ ScAccessiblePreviewHeaderCell( const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScPreviewShell* pViewShell,
+ const ScAddress& rCellPos, bool bIsColHdr, bool bIsRowHdr,
+ sal_Int32 nIndex );
+
+protected:
+ virtual ~ScAccessiblePreviewHeaderCell() override;
+
+ using ScAccessibleContextBase::IsDefunc;
+
+public:
+ using ScAccessibleContextBase::disposing;
+ virtual void SAL_CALL disposing() override;
+
+ //===== SfxListener =====================================================
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ ///===== XInterface =====================================================
+
+ virtual css::uno::Any SAL_CALL queryInterface(
+ css::uno::Type const & rType ) override;
+
+ virtual void SAL_CALL acquire() noexcept override;
+
+ virtual void SAL_CALL release() noexcept override;
+
+ //===== XAccessibleValue ================================================
+
+ virtual css::uno::Any SAL_CALL getCurrentValue() override;
+ virtual sal_Bool SAL_CALL setCurrentValue( const css::uno::Any& aNumber ) override;
+ virtual css::uno::Any SAL_CALL getMaximumValue() override;
+ virtual css::uno::Any SAL_CALL getMinimumValue() override;
+ virtual css::uno::Any SAL_CALL getMinimumIncrement() override;
+
+ //===== XAccessibleComponent ============================================
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+ virtual void SAL_CALL grabFocus() override;
+
+ //===== XAccessibleContext ==============================================
+
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleChild( sal_Int32 i ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL
+ getAccessibleStateSet() override;
+
+ //===== XServiceInfo ====================================================
+
+ 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;
+
+ /** Returns an implementation id.
+ */
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL
+ getImplementationId() override;
+
+protected:
+ virtual OUString createAccessibleDescription() override;
+ virtual OUString createAccessibleName() override;
+
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const override;
+ virtual tools::Rectangle GetBoundingBox() const override;
+
+private:
+ ScPreviewShell* mpViewShell;
+ std::unique_ptr<accessibility::AccessibleTextHelper> mxTextHelper;
+ sal_Int32 mnIndex;
+ ScAddress maCellPos;
+ bool mbColumnHeader;
+ bool mbRowHeader;
+ mutable std::unique_ptr<ScPreviewTableInfo> mpTableInfo;
+
+ bool IsDefunc(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates);
+
+ void CreateTextHelper();
+ void FillTableInfo() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessiblePreviewTable.hxx b/sc/source/ui/inc/AccessiblePreviewTable.hxx
new file mode 100644
index 000000000..555828801
--- /dev/null
+++ b/sc/source/ui/inc/AccessiblePreviewTable.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 "AccessibleContextBase.hxx"
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+#include <cppuhelper/implbase1.hxx>
+
+class ScPreviewShell;
+class ScPreviewTableInfo;
+
+typedef cppu::ImplHelper1< css::accessibility::XAccessibleTable>
+ ScAccessiblePreviewTableImpl;
+
+class ScAccessiblePreviewTable :
+ public ScAccessibleContextBase,
+ public ScAccessiblePreviewTableImpl
+{
+public:
+ ScAccessiblePreviewTable( const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScPreviewShell* pViewShell, sal_Int32 nIndex );
+
+protected:
+ virtual ~ScAccessiblePreviewTable() override;
+
+ using ScAccessibleContextBase::IsDefunc;
+
+public:
+ using ScAccessibleContextBase::disposing;
+ virtual void SAL_CALL disposing() override;
+
+ //===== SfxListener =====================================================
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ ///===== XInterface =====================================================
+
+ virtual css::uno::Any SAL_CALL queryInterface(
+ css::uno::Type const & rType ) override;
+
+ virtual void SAL_CALL acquire() noexcept override;
+
+ virtual void SAL_CALL release() noexcept override;
+
+ //===== XAccessibleTable ================================================
+
+ virtual sal_Int32 SAL_CALL getAccessibleRowCount() override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumnCount() override;
+ virtual OUString SAL_CALL getAccessibleRowDescription( sal_Int32 nRow ) override;
+ virtual OUString SAL_CALL getAccessibleColumnDescription( sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL
+ getAccessibleRowHeaders() override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL
+ getAccessibleColumnHeaders() override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getSelectedAccessibleRows() override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL getSelectedAccessibleColumns() override;
+ virtual sal_Bool SAL_CALL isAccessibleRowSelected( sal_Int32 nRow ) override;
+ virtual sal_Bool SAL_CALL isAccessibleColumnSelected( sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleCaption() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleSummary() override;
+ virtual sal_Bool SAL_CALL isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleRow( sal_Int32 nChildIndex ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleColumn( sal_Int32 nChildIndex ) override;
+
+ //===== XAccessibleComponent ============================================
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleAtPoint( const css::awt::Point& aPoint ) override;
+ virtual void SAL_CALL grabFocus() override;
+
+ //===== XAccessibleContext ==============================================
+
+ virtual sal_Int32 SAL_CALL getAccessibleChildCount() override;
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleChild( sal_Int32 i ) override;
+ virtual sal_Int32 SAL_CALL getAccessibleIndexInParent() override;
+ virtual css::uno::Reference< css::accessibility::XAccessibleStateSet > SAL_CALL
+ getAccessibleStateSet() override;
+
+ //===== XServiceInfo ====================================================
+
+ 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;
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+protected:
+ virtual OUString createAccessibleDescription() override;
+ virtual OUString createAccessibleName() override;
+
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const override;
+ virtual tools::Rectangle GetBoundingBox() const override;
+
+private:
+ ScPreviewShell* mpViewShell;
+ sal_Int32 mnIndex;
+ mutable std::unique_ptr<ScPreviewTableInfo> mpTableInfo;
+
+ bool IsDefunc(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates);
+
+ void FillTableInfo() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibleSpreadsheet.hxx b/sc/source/ui/inc/AccessibleSpreadsheet.hxx
new file mode 100644
index 000000000..2c708bd77
--- /dev/null
+++ b/sc/source/ui/inc/AccessibleSpreadsheet.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 <sal/config.h>
+
+#include <rtl/ref.hxx>
+
+#include "AccessibleTableBase.hxx"
+#include "viewdata.hxx"
+
+#include <vector>
+
+#include <rangelst.hxx>
+#include <map>
+
+class ScMyAddress : public ScAddress
+{
+public:
+ ScMyAddress(SCCOL nColP, SCROW nRowP, SCTAB nTabP) : ScAddress(nColP, nRowP, nTabP) {}
+ ScMyAddress(const ScAddress& rAddress) : ScAddress(rAddress) {}
+
+ bool operator< ( const ScMyAddress& rAddress ) const
+ {
+ if( Row() != rAddress.Row() )
+ return (Row() < rAddress.Row());
+ else
+ return (Col() < rAddress.Col());
+ }
+};
+
+class ScTabViewShell;
+class ScAccessibleDocument;
+class ScAccessibleCell;
+
+/** @descr
+ This base class provides an implementation of the
+ <code>AccessibleTable</code> service.
+*/
+class ScAccessibleSpreadsheet final : public ScAccessibleTableBase
+{
+public:
+ ScAccessibleSpreadsheet(
+ ScAccessibleDocument* pAccDoc,
+ ScTabViewShell* pViewShell,
+ SCTAB nTab,
+ ScSplitPos eSplitPos);
+
+ using ScAccessibleTableBase::disposing;
+
+ virtual void SAL_CALL disposing() override;
+
+ void CompleteSelectionChanged(bool bNewState);
+
+ void LostFocus();
+ void GotFocus();
+
+ void BoundingBoxChanged();
+ void VisAreaChanged();
+ void FireFirstCellFocus();
+
+ bool IsScAddrFormulaSel (const ScAddress &addr) const;
+ bool IsFormulaMode();
+ ScMyAddress CalcScAddressFromRangeList(ScRangeList *pMarkedRanges,sal_Int32 nSelectedChildIndex);
+ static bool CalcScRangeDifferenceMax(const ScRange & rSrc, const ScRange & rDest,int nMax,std::vector<ScMyAddress> &vecRet,int &nSize);
+ static bool CalcScRangeListDifferenceMax(ScRangeList *pSrc,ScRangeList *pDest,int nMax,std::vector<ScMyAddress> &vecRet);
+
+private:
+ ScAccessibleSpreadsheet(
+ ScAccessibleSpreadsheet& rParent,
+ const ScRange& rRange );
+
+ virtual ~ScAccessibleSpreadsheet() override;
+
+ void ConstructScAccessibleSpreadsheet(
+ ScAccessibleDocument* pAccDoc,
+ ScTabViewShell* pViewShell,
+ SCTAB nTab,
+ ScSplitPos eSplitPos);
+
+ using ScAccessibleTableBase::IsDefunc;
+
+ ///===== SfxListener =====================================================
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ ///===== XAccessibleTable ================================================
+
+ /// Returns the row headers as an AccessibleTable.
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL
+ getAccessibleRowHeaders( ) override;
+
+ /// Returns the column headers as an AccessibleTable.
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL
+ getAccessibleColumnHeaders( ) override;
+
+ /// Returns the selected rows in a table.
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL
+ getSelectedAccessibleRows( ) override;
+
+ /// Returns the selected columns in a table.
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL
+ getSelectedAccessibleColumns( ) override;
+
+ /// Returns a boolean value indicating whether the specified row is selected.
+ virtual sal_Bool SAL_CALL
+ isAccessibleRowSelected( sal_Int32 nRow ) override;
+
+ /// Returns a boolean value indicating whether the specified column is selected.
+ virtual sal_Bool SAL_CALL
+ isAccessibleColumnSelected( sal_Int32 nColumn ) override;
+
+ /// Returns the Accessible at a specified row and column in the table.
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ rtl::Reference<ScAccessibleCell> GetAccessibleCellAt(sal_Int32 nRow, sal_Int32 nColumn);
+
+ /// Returns a boolean value indicating whether the accessible at a specified row and column is selected.
+ virtual sal_Bool SAL_CALL
+ isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ ///===== XAccessibleComponent ============================================
+
+ virtual css::uno::Reference< css::accessibility::XAccessible >
+ SAL_CALL getAccessibleAtPoint(
+ const css::awt::Point& rPoint ) override;
+
+ virtual void SAL_CALL grabFocus( ) override;
+
+ virtual sal_Int32 SAL_CALL getForeground( ) override;
+
+ virtual sal_Int32 SAL_CALL getBackground( ) override;
+
+ ///===== XAccessibleContext ==============================================
+
+ /// 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;
+
+ ///===== XAccessibleSelection ===========================================
+
+ virtual void SAL_CALL
+ selectAccessibleChild( sal_Int32 nChildIndex ) override;
+
+ virtual void SAL_CALL
+ clearAccessibleSelection( ) override;
+
+ virtual void SAL_CALL
+ selectAllAccessibleChildren( ) override;
+
+ virtual sal_Int32 SAL_CALL
+ getSelectedAccessibleChildCount( ) override;
+
+ virtual css::uno::Reference<css::accessibility::XAccessible > SAL_CALL
+ getSelectedAccessibleChild( sal_Int32 nSelectedChildIndex ) override;
+
+ virtual void SAL_CALL
+ deselectAccessibleChild( sal_Int32 nChildIndex ) override;
+
+ ///===== XServiceInfo ====================================================
+
+ /** Returns an identifier for the implementation of this object.
+ */
+ virtual OUString SAL_CALL
+ getImplementationName() override;
+
+ /** Returns a list of all supported services.
+ */
+ virtual css::uno::Sequence< OUString> SAL_CALL
+ getSupportedServiceNames() override;
+
+ ///===== XTypeProvider ===================================================
+
+ /** Returns an implementation id.
+ */
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL
+ getImplementationId() override;
+
+ ///===== XAccessibleEventBroadcaster =====================================
+
+ /** Add listener that is informed of future changes of name,
+ description and so on events.
+ */
+ virtual void SAL_CALL
+ addAccessibleEventListener(
+ const css::uno::Reference<css::accessibility::XAccessibleEventListener>& xListener) override;
+
+ //===== XAccessibleTableSelection ============================================
+
+ virtual sal_Bool SAL_CALL selectRow( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL selectColumn( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL unselectRow( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL unselectColumn( sal_Int32 column ) override;
+
+ /// Return the object's current bounding box relative to the desktop.
+ virtual tools::Rectangle GetBoundingBoxOnScreen() const override;
+
+ /// Return the object's current bounding box relative to the parent object.
+ virtual tools::Rectangle GetBoundingBox() const override;
+
+ bool IsDefunc(
+ const css::uno::Reference<css::accessibility::XAccessibleStateSet>& rxParentStates);
+ bool IsEditable();
+ bool IsFocused();
+ bool IsCompleteSheetSelected();
+
+ void SelectCell(sal_Int32 nRow, sal_Int32 nCol, bool bDeselect);
+
+ static ScDocument* GetDocument(ScTabViewShell* pViewShell);
+
+ void RemoveSelection(const ScMarkData &refScMarkData);
+ void CommitFocusCell(const ScAddress &aNewCell);
+
+ sal_Int32 GetRowAll() const { return m_nMaxY - m_nMinY + 1 ; }
+ sal_uInt16 GetColAll() const { return m_nMaxX - m_nMinX + 1; }
+ void NotifyRefMode();
+ void RemoveFormulaSelection(bool bRemoveAll = false);
+ bool CheckChildIndex(sal_Int32) const;
+ ScAddress GetChildIndexAddress(sal_Int32) const;
+ sal_Int32 GetAccessibleIndexFormula( sal_Int32 nRow, sal_Int32 nColumn );
+ bool GetFormulaCurrentFocusCell(ScAddress &addr);
+
+ ScTabViewShell* mpViewShell;
+ std::unique_ptr<ScRangeList> mpMarkedRanges;
+ ScAccessibleDocument* mpAccDoc;
+ rtl::Reference<ScAccessibleCell> mpAccCell;
+ ScSplitPos meSplitPos;
+ ScAddress maActiveCell;
+ SCTAB mnTab;
+ bool mbIsSpreadsheet;
+ bool mbDelIns;
+ bool mbIsFocusSend;
+ typedef std::map<ScMyAddress,css::uno::Reference< css::accessibility::XAccessible > >
+ MAP_ADDR_XACC;
+ MAP_ADDR_XACC m_mapSelectionSend;
+ bool m_bFormulaMode;
+ bool m_bFormulaLastMode;
+ ScAddress m_aFormulaActiveCell;
+ MAP_ADDR_XACC m_mapFormulaSelectionSend;
+ std::vector<ScMyAddress> m_vecFormulaLastMyAddr;
+ rtl::Reference<ScAccessibleCell> m_pAccFormulaCell;
+ sal_uInt16 m_nMinX;
+ sal_uInt16 m_nMaxX;
+ sal_Int32 m_nMinY;
+ sal_Int32 m_nMaxY;
+ ScRange m_aLastWithInMarkRange;
+ OUString m_strCurCellValue;
+ ScRangeList m_LastMarkedRanges;
+ OUString m_strOldTabName;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibleTableBase.hxx b/sc/source/ui/inc/AccessibleTableBase.hxx
new file mode 100644
index 000000000..a9b56ff68
--- /dev/null
+++ b/sc/source/ui/inc/AccessibleTableBase.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "AccessibleContextBase.hxx"
+#include <address.hxx>
+#include <com/sun/star/accessibility/XAccessibleTable.hpp>
+#include <com/sun/star/accessibility/XAccessibleSelection.hpp>
+#include <com/sun/star/accessibility/XAccessibleTableSelection.hpp>
+#include <cppuhelper/implbase2.hxx>
+
+/** @descr
+ This base class provides an implementation of the
+ <code>AccessibleTable</code> service.
+*/
+
+typedef cppu::ImplHelper2< css::accessibility::XAccessibleTable,
+ css::accessibility::XAccessibleSelection>
+ ScAccessibleTableBaseImpl;
+
+class ScAccessibleTableBase :
+ public ScAccessibleContextBase,
+ public css::accessibility::XAccessibleTableSelection,
+ public ScAccessibleTableBaseImpl
+{
+public:
+ //===== internal ========================================================
+ ScAccessibleTableBase(
+ const css::uno::Reference<css::accessibility::XAccessible>& rxParent,
+ ScDocument* pDoc,
+ const ScRange& rRange);
+protected:
+ virtual ~ScAccessibleTableBase() override;
+public:
+
+ using ScAccessibleContextBase::disposing;
+ virtual void SAL_CALL disposing() override;
+
+ ///===== XInterface =====================================================
+
+ virtual css::uno::Any SAL_CALL queryInterface(
+ css::uno::Type const & rType ) override;
+
+ virtual void SAL_CALL acquire() noexcept override;
+
+ virtual void SAL_CALL release() noexcept override;
+
+ ///===== XAccessibleTable ================================================
+
+ /// Returns the number of rows in the table.
+ virtual sal_Int32 SAL_CALL
+ getAccessibleRowCount( ) override;
+
+ /// Returns the number of columns in the table.
+ virtual sal_Int32 SAL_CALL
+ getAccessibleColumnCount( ) override;
+
+ /// Returns the description of the specified row in the table.
+ virtual OUString SAL_CALL
+ getAccessibleRowDescription( sal_Int32 nRow ) override;
+
+ /// Returns the description text of the specified column in the table.
+ virtual OUString SAL_CALL
+ getAccessibleColumnDescription( sal_Int32 nColumn ) override;
+
+ /** Returns the number of rows occupied by the Accessible at a specified row and column in the table.
+ Returns 1 if it is only a cell and the number of rows the cell is merged if the cell is a merged cell.
+ */
+ virtual sal_Int32 SAL_CALL
+ getAccessibleRowExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ /** Returns the number of columns occupied by the Accessible at a specified row and column in the table.
+ Returns 1 if it is only a cell and the number of columns the cell is merged if the cell is a merged cell.
+ */
+ virtual sal_Int32 SAL_CALL
+ getAccessibleColumnExtentAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ /// Returns the row headers as an AccessibleTable.
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL
+ getAccessibleRowHeaders( ) override;
+
+ /// Returns the column headers as an AccessibleTable.
+ virtual css::uno::Reference< css::accessibility::XAccessibleTable > SAL_CALL
+ getAccessibleColumnHeaders( ) override;
+
+ /// Returns the selected rows in a table.
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL
+ getSelectedAccessibleRows( ) override;
+
+ /// Returns the selected columns in a table.
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL
+ getSelectedAccessibleColumns( ) override;
+
+ /// Returns a boolean value indicating whether the specified row is selected.
+ virtual sal_Bool SAL_CALL
+ isAccessibleRowSelected( sal_Int32 nRow ) override;
+
+ /// Returns a boolean value indicating whether the specified column is selected.
+ virtual sal_Bool SAL_CALL
+ isAccessibleColumnSelected( sal_Int32 nColumn ) override;
+
+ /// Returns the Accessible at a specified row and column in the table.
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleCellAt( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ /// Returns the caption for the table.
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleCaption( ) override;
+
+ /// Returns the summary description of the table.
+ virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL
+ getAccessibleSummary( ) override;
+
+ /// Returns a boolean value indicating whether the accessible at a specified row and column is selected.
+ virtual sal_Bool SAL_CALL
+ isAccessibleSelected( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ ///===== XAccessibleExtendedTable ========================================
+
+ /// Returns the index of the cell on the given position.
+ virtual sal_Int32 SAL_CALL
+ getAccessibleIndex( sal_Int32 nRow, sal_Int32 nColumn ) override;
+
+ /// Returns the row number of an index in the table.
+ virtual sal_Int32 SAL_CALL
+ getAccessibleRow( sal_Int32 nChildIndex ) override;
+
+ /// Returns the column number of an index in the table.
+ virtual sal_Int32 SAL_CALL
+ getAccessibleColumn( sal_Int32 nChildIndex ) override;
+
+ //===== XAccessibleContext ==============================================
+
+ /// Return the number of currently visible children.
+ /// override to calculate this on demand
+ virtual sal_Int32 SAL_CALL
+ getAccessibleChildCount() override;
+
+ /// Return the specified child or NULL if index is invalid.
+ /// override to calculate this on demand
+ virtual css::uno::Reference< css::accessibility::XAccessible> SAL_CALL
+ getAccessibleChild(sal_Int32 nIndex) override;
+ virtual sal_Bool SAL_CALL selectRow( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL selectColumn( sal_Int32 column ) override;
+ virtual sal_Bool SAL_CALL unselectRow( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL unselectColumn( sal_Int32 column ) override;
+
+protected:
+ /// Return this object's description.
+ virtual OUString
+ createAccessibleDescription() override;
+
+ /// Return the object's current name.
+ virtual OUString
+ createAccessibleName() override;
+
+public:
+ /// 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.
+ // perhaps sometimes to be implemented
+ virtual css::uno::Reference<css::accessibility::XAccessibleStateSet> SAL_CALL
+ getAccessibleStateSet() 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;
+
+ ///===== XTypeProvider ===================================================
+
+ /// returns the possible types
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL
+ getTypes() override;
+
+ /** Returns an implementation id.
+ */
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL
+ getImplementationId() override;
+
+protected:
+ /// contains the range of the table, because it could be a subrange of the complete table
+ ScRange maRange;
+
+ ScDocument* mpDoc;
+
+ void CommitTableModelChange(sal_Int32 nStartRow, sal_Int32 nStartCol, sal_Int32 nEndRow, sal_Int32 nEndCol, sal_uInt16 nId);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AccessibleText.hxx b/sc/source/ui/inc/AccessibleText.hxx
new file mode 100644
index 000000000..23fdb3cb2
--- /dev/null
+++ b/sc/source/ui/inc/AccessibleText.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <textuno.hxx>
+#include <address.hxx>
+#include "viewdata.hxx"
+#include <editeng/svxenum.hxx>
+#include <svl/SfxBroadcaster.hxx>
+
+#include <memory>
+
+class ScDocShell;
+class ScViewForwarder;
+class ScEditObjectViewForwarder;
+class ScPreviewViewForwarder;
+class ScEditViewForwarder;
+class ScPreviewShell;
+class EditTextObject;
+class ScCsvViewForwarder;
+class ScAccessibleCell;
+class ScTextWnd;
+
+class ScAccessibleTextData : public SfxListener
+{
+public:
+ ScAccessibleTextData() {}
+
+ virtual ScAccessibleTextData* Clone() const = 0;
+
+ virtual void Notify( SfxBroadcaster& /* rBC */, const SfxHint& /* rHint */ ) override {}
+
+ virtual SvxTextForwarder* GetTextForwarder() = 0;
+ virtual SvxViewForwarder* GetViewForwarder() = 0;
+ virtual SvxEditViewForwarder* GetEditViewForwarder( bool bCreate ) = 0;
+ SfxBroadcaster& GetBroadcaster() const { return maBroadcaster; }
+
+ virtual void UpdateData() = 0;
+ DECL_LINK( NotifyHdl, EENotify&, void );
+
+private:
+ mutable SfxBroadcaster maBroadcaster;
+
+};
+
+class ScAccessibleCellBaseTextData : public ScAccessibleTextData,
+ public ScCellTextData
+{
+public:
+ ScAccessibleCellBaseTextData(ScDocShell* pDocShellP,
+ const ScAddress& rP)
+ : ScCellTextData(pDocShellP, rP) {}
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override { ScCellTextData::Notify(rBC, rHint); }
+
+ virtual void UpdateData() override { ScCellTextData::UpdateData(); }
+};
+
+// ScAccessibleCellTextData: shared data between sub objects of an accessible cell text object
+
+class ScAccessibleCellTextData : public ScAccessibleCellBaseTextData
+{
+public:
+ ScAccessibleCellTextData(ScTabViewShell* pViewShell,
+ const ScAddress& rP, ScSplitPos eSplitPos, ScAccessibleCell* pAccCell);
+ virtual ~ScAccessibleCellTextData() override;
+
+ virtual ScAccessibleTextData* Clone() const override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual SvxTextForwarder* GetTextForwarder() override;
+ virtual SvxViewForwarder* GetViewForwarder() override;
+ virtual SvxEditViewForwarder* GetEditViewForwarder( bool bCreate ) override;
+
+private:
+ std::unique_ptr<ScViewForwarder> mpViewForwarder;
+ ScTabViewShell* mpViewShell;
+ ScSplitPos meSplitPos;
+ ScAccessibleCell* mpAccessibleCell;
+
+ using ScAccessibleCellBaseTextData::GetDocShell;
+ static ScDocShell* GetDocShell(ScTabViewShell* pViewShell);
+};
+
+class ScAccessibleEditObjectTextData : public ScAccessibleTextData
+{
+public:
+ // Add a para to indicate whether the object is cloned
+ ScAccessibleEditObjectTextData(EditView* pEditView, OutputDevice* pWin, bool isClone = false);
+ virtual ~ScAccessibleEditObjectTextData() override;
+
+ virtual ScAccessibleTextData* Clone() const override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual SvxTextForwarder* GetTextForwarder() override;
+ virtual SvxViewForwarder* GetViewForwarder() override;
+ virtual SvxEditViewForwarder* GetEditViewForwarder( bool bCreate ) override;
+
+ virtual void UpdateData() override { }
+
+ DECL_LINK( NotifyHdl, EENotify&, void );
+protected:
+ std::unique_ptr<ScEditObjectViewForwarder> mpViewForwarder;
+ std::unique_ptr<ScEditViewForwarder> mpEditViewForwarder;
+ EditView* mpEditView;
+ EditEngine* mpEditEngine;
+ std::unique_ptr<SvxEditEngineForwarder> mpForwarder;
+ VclPtr<OutputDevice> mpWindow;
+ bool mbIsCloned;
+};
+
+class ScAccessibleEditLineTextData : public ScAccessibleEditObjectTextData
+{
+public:
+ ScAccessibleEditLineTextData(EditView* pEditView,
+ OutputDevice* pWin,
+ ScTextWnd* pTextWnd);
+ virtual ~ScAccessibleEditLineTextData() override;
+
+ virtual ScAccessibleTextData* Clone() const override;
+
+ virtual SvxTextForwarder* GetTextForwarder() override;
+ virtual SvxEditViewForwarder* GetEditViewForwarder( bool bCreate ) override;
+
+ void Dispose();
+ void TextChanged();
+ void StartEdit();
+ void EndEdit();
+private:
+ void ResetEditMode();
+
+ ScTextWnd* mpTxtWnd;
+ bool mbEditEngineCreated;
+};
+
+class ScAccessiblePreviewCellTextData : public ScAccessibleCellBaseTextData
+{
+public:
+ ScAccessiblePreviewCellTextData(ScPreviewShell* pViewShell,
+ const ScAddress& rP);
+ virtual ~ScAccessiblePreviewCellTextData() override;
+
+ virtual ScAccessibleTextData* Clone() const override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual SvxTextForwarder* GetTextForwarder() override;
+ virtual SvxViewForwarder* GetViewForwarder() override;
+ virtual SvxEditViewForwarder* GetEditViewForwarder( bool /* bCreate */ ) override { return nullptr; }
+
+private:
+ std::unique_ptr<ScPreviewViewForwarder> mpViewForwarder;
+ ScPreviewShell* mpViewShell;
+
+ using ScAccessibleCellBaseTextData::GetDocShell;
+ static ScDocShell* GetDocShell(ScPreviewShell* pViewShell);
+};
+
+class ScAccessiblePreviewHeaderCellTextData : public ScAccessibleCellBaseTextData
+{
+public:
+ ScAccessiblePreviewHeaderCellTextData(ScPreviewShell* pViewShell,
+ const OUString& rText, const ScAddress& rP, bool bColHeader, bool bRowHeader);
+ virtual ~ScAccessiblePreviewHeaderCellTextData() override;
+
+ virtual ScAccessibleTextData* Clone() const override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual SvxTextForwarder* GetTextForwarder() override;
+ virtual SvxViewForwarder* GetViewForwarder() override;
+ virtual SvxEditViewForwarder* GetEditViewForwarder( bool /* bCreate */ ) override { return nullptr; }
+
+private:
+ std::unique_ptr<ScPreviewViewForwarder> mpViewForwarder;
+ ScPreviewShell* mpViewShell;
+ OUString maText;
+ bool mbColHeader;
+ bool mbRowHeader;
+
+ using ScAccessibleCellBaseTextData::GetDocShell;
+ static ScDocShell* GetDocShell(ScPreviewShell* pViewShell);
+};
+
+class ScAccessibleHeaderTextData : public ScAccessibleTextData
+{
+public:
+ ScAccessibleHeaderTextData(ScPreviewShell* pViewShell,
+ const EditTextObject* pEditObj, SvxAdjust eAdjust);
+ virtual ~ScAccessibleHeaderTextData() override;
+
+ virtual ScAccessibleTextData* Clone() const override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual SvxTextForwarder* GetTextForwarder() override;
+ virtual SvxViewForwarder* GetViewForwarder() override;
+ virtual SvxEditViewForwarder* GetEditViewForwarder( bool /* bCreate */ ) override { return nullptr; }
+
+ virtual void UpdateData() override { }
+private:
+ std::unique_ptr<ScPreviewViewForwarder> mxViewForwarder;
+ ScPreviewShell* mpViewShell;
+ std::unique_ptr<ScEditEngineDefaulter> mpEditEngine;
+ std::unique_ptr<SvxEditEngineForwarder> mpForwarder;
+ ScDocShell* mpDocSh;
+ const EditTextObject* mpEditObj;
+ bool mbDataValid;
+ SvxAdjust meAdjust;
+};
+
+class ScAccessibleNoteTextData : public ScAccessibleTextData
+{
+public:
+ ScAccessibleNoteTextData(ScPreviewShell* pViewShell,
+ const OUString& sText, const ScAddress& aCellPos, bool bMarkNote);
+ virtual ~ScAccessibleNoteTextData() override;
+
+ virtual ScAccessibleTextData* Clone() const override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual SvxTextForwarder* GetTextForwarder() override;
+ virtual SvxViewForwarder* GetViewForwarder() override;
+ virtual SvxEditViewForwarder* GetEditViewForwarder( bool /* bCreate */ ) override { return nullptr; }
+
+ virtual void UpdateData() override { }
+private:
+ std::unique_ptr<ScPreviewViewForwarder> mxViewForwarder;
+ ScPreviewShell* mpViewShell;
+ std::unique_ptr<ScEditEngineDefaulter> mpEditEngine;
+ std::unique_ptr<SvxEditEngineForwarder> mpForwarder;
+ ScDocShell* mpDocSh;
+ OUString msText;
+ ScAddress maCellPos;
+ bool mbMarkNote;
+ bool mbDataValid;
+};
+
+class ScAccessibleCsvTextData : public ScAccessibleTextData
+{
+private:
+ typedef ::std::unique_ptr< SvxTextForwarder > TextForwarderPtr;
+ typedef ::std::unique_ptr< ScCsvViewForwarder > ViewForwarderPtr;
+
+ VclPtr<OutputDevice> mpWindow;
+ EditEngine* mpEditEngine;
+ TextForwarderPtr mpTextForwarder;
+ ViewForwarderPtr mpViewForwarder;
+ OUString maCellText;
+ Size maCellSize;
+
+public:
+ explicit ScAccessibleCsvTextData(
+ OutputDevice* pWindow,
+ EditEngine* pEditEngine,
+ const OUString& rCellText,
+ const Size& rCellSize );
+ virtual ~ScAccessibleCsvTextData() override;
+
+ virtual ScAccessibleTextData* Clone() const override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual SvxTextForwarder* GetTextForwarder() override;
+ virtual SvxViewForwarder* GetViewForwarder() override;
+ virtual SvxEditViewForwarder* GetEditViewForwarder( bool bCreate ) override;
+
+ virtual void UpdateData() override {}
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/AnalysisOfVarianceDialog.hxx b/sc/source/ui/inc/AnalysisOfVarianceDialog.hxx
new file mode 100644
index 000000000..35c53e727
--- /dev/null
+++ b/sc/source/ui/inc/AnalysisOfVarianceDialog.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 <address.hxx>
+#include "viewdata.hxx"
+
+#include "StatisticsInputOutputDialog.hxx"
+
+class FormulaTemplate;
+class AddressWalkerWriter;
+
+class ScAnalysisOfVarianceDialog : public ScStatisticsInputOutputDialog
+{
+private:
+ enum AnovaFactor
+ {
+ SINGLE_FACTOR,
+ TWO_FACTOR
+ };
+
+ DECL_LINK(FactorChanged, weld::Toggleable&, void);
+ void FactorChanged();
+
+ AnovaFactor meFactor;
+
+ std::unique_ptr<weld::SpinButton> mxAlphaField;
+ std::unique_ptr<weld::RadioButton> mxSingleFactorRadio;
+ std::unique_ptr<weld::RadioButton> mxTwoFactorRadio;
+ std::unique_ptr<weld::SpinButton> mxRowsPerSampleField;
+
+ static void RowColumn(ScRangeList& rRangeList, AddressWalkerWriter& aOutput,
+ FormulaTemplate& aTemplate, const OUString& sFormula,
+ GroupedBy aGroupedBy, ScRange* pResultRange);
+
+ void AnovaSingleFactor(AddressWalkerWriter& output, FormulaTemplate& aTemplate);
+ void AnovaTwoFactor(AddressWalkerWriter& output, FormulaTemplate& aTemplate);
+
+public:
+ ScAnalysisOfVarianceDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData );
+
+ virtual ~ScAnalysisOfVarianceDialog() override;
+
+ virtual void Close() override;
+
+protected:
+ virtual TranslateId GetUndoNameId() override;
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/ChartRangeSelectionListener.hxx b/sc/source/ui/inc/ChartRangeSelectionListener.hxx
new file mode 100644
index 000000000..b7033c413
--- /dev/null
+++ b/sc/source/ui/inc/ChartRangeSelectionListener.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 <comphelper/compbase.hxx>
+#include <com/sun/star/view/XSelectionChangeListener.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+class ScTabViewShell;
+
+typedef comphelper::WeakComponentImplHelper<
+ css::view::XSelectionChangeListener,
+ css::lang::XServiceInfo >
+ ScChartRangeSelectionListener_Base;
+
+class ScChartRangeSelectionListener :
+ public ScChartRangeSelectionListener_Base
+{
+public:
+ explicit ScChartRangeSelectionListener( ScTabViewShell * pViewShell );
+ virtual ~ScChartRangeSelectionListener() override;
+
+protected:
+ // ____ XSelectionChangeListener ____
+ virtual void SAL_CALL selectionChanged(
+ const css::lang::EventObject& aEvent ) override;
+
+ // ____ XEventListener (base of XSelectionChangeListener) ____
+ virtual void SAL_CALL disposing(
+ const css::lang::EventObject& Source ) override;
+
+ // ____ WeakComponentImplHelperBase ____
+ // is called when dispose() is called at this component
+ 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;
+
+private:
+ ScTabViewShell * m_pViewShell;
+};
+
+// INCLUDED_SC_SOURCE_UI_INC_CHARTRANGESELECTIONLISTENER_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/ChiSquareTestDialog.hxx b/sc/source/ui/inc/ChiSquareTestDialog.hxx
new file mode 100644
index 000000000..20e7d696c
--- /dev/null
+++ b/sc/source/ui/inc/ChiSquareTestDialog.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/.
+ *
+ */
+
+#pragma once
+
+#include "StatisticsInputOutputDialog.hxx"
+
+class ScChiSquareTestDialog : public ScStatisticsInputOutputDialog
+{
+public:
+ ScChiSquareTestDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData );
+
+ virtual ~ScChiSquareTestDialog() override;
+
+ virtual void Close() override;
+
+protected:
+ virtual TranslateId GetUndoNameId() override;
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/ChildWindowWrapper.hxx b/sc/source/ui/inc/ChildWindowWrapper.hxx
new file mode 100644
index 000000000..afc4a2df5
--- /dev/null
+++ b/sc/source/ui/inc/ChildWindowWrapper.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/.
+ *
+ */
+
+#pragma once
+
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/childwin.hxx>
+#include <osl/diagnose.h>
+
+#include "tabvwsh.hxx"
+
+template <sal_Int16 WindowID>
+class ChildControllerWrapper : public SfxChildWindow
+{
+public:
+ ChildControllerWrapper(vcl::Window* pParentP, sal_uInt16 nId,
+ SfxBindings* pBindings, const SfxChildWinInfo* pInfo)
+ : SfxChildWindow(pParentP, nId)
+ {
+ ScTabViewShell* pViewShell = getTabViewShell( pBindings );
+ if (!pViewShell)
+ pViewShell = dynamic_cast< ScTabViewShell *>( SfxViewShell::Current() );
+ OSL_ENSURE(pViewShell, "Missing view shell!");
+
+ if (pViewShell)
+ SetController(pViewShell->CreateRefDialogController(pBindings, this, pInfo, pParentP->GetFrameWeld(), WindowID));
+
+ if (pViewShell && !GetController())
+ pViewShell->GetViewFrame()->SetChildWindow( nId, false );
+ }
+
+ static std::unique_ptr<SfxChildWindow> CreateImpl(
+ vcl::Window *pParent, sal_uInt16 nId,
+ SfxBindings *pBindings, SfxChildWinInfo* pInfo )
+ {
+ return std::make_unique<ChildControllerWrapper>(pParent, nId, pBindings, pInfo);
+ }
+
+ static void RegisterChildWindow (
+ bool bVisible = false,
+ SfxModule* pModule = nullptr,
+ SfxChildWindowFlags nFlags = SfxChildWindowFlags::NONE)
+ {
+ SfxChildWinFactory aFactory(ChildControllerWrapper::CreateImpl, WindowID, CHILDWIN_NOPOS );
+ aFactory.aInfo.nFlags |= nFlags;
+ aFactory.aInfo.bVisible = bVisible;
+ SfxChildWindow::RegisterChildWindow(pModule, aFactory);
+ }
+
+ static sal_uInt16 GetChildWindowId()
+ {
+ return WindowID;
+ }
+
+private:
+ static ScTabViewShell* getTabViewShell( const SfxBindings *pBindings )
+ {
+ if( !pBindings )
+ return nullptr;
+ SfxDispatcher* pDispacher = pBindings ->GetDispatcher();
+ if( !pDispacher )
+ return nullptr;
+ SfxViewFrame* pFrame = pDispacher->GetFrame();
+ if( !pFrame )
+ return nullptr;
+ SfxViewShell* pViewShell = pFrame->GetViewShell();
+ if( !pViewShell )
+ return nullptr;
+ return dynamic_cast<ScTabViewShell*>( pViewShell );
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/CorrelationDialog.hxx b/sc/source/ui/inc/CorrelationDialog.hxx
new file mode 100644
index 000000000..5200c3f55
--- /dev/null
+++ b/sc/source/ui/inc/CorrelationDialog.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/.
+ *
+ */
+
+#pragma once
+
+#include "MatrixComparisonGenerator.hxx"
+
+class ScCorrelationDialog : public ScMatrixComparisonGenerator
+{
+public:
+ ScCorrelationDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData);
+
+ virtual void Close() override;
+
+protected:
+ virtual OUString getLabel() override;
+ virtual OUString getTemplate() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/CovarianceDialog.hxx b/sc/source/ui/inc/CovarianceDialog.hxx
new file mode 100644
index 000000000..181bebeac
--- /dev/null
+++ b/sc/source/ui/inc/CovarianceDialog.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/.
+ *
+ */
+
+#pragma once
+
+#include "MatrixComparisonGenerator.hxx"
+
+class ScCovarianceDialog : public ScMatrixComparisonGenerator
+{
+public:
+ ScCovarianceDialog(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData);
+
+ virtual void Close() override;
+
+protected:
+ virtual OUString getLabel() override;
+ virtual OUString getTemplate() override;
+ virtual TranslateId GetUndoNameId() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/DescriptiveStatisticsDialog.hxx b/sc/source/ui/inc/DescriptiveStatisticsDialog.hxx
new file mode 100644
index 000000000..dd2488450
--- /dev/null
+++ b/sc/source/ui/inc/DescriptiveStatisticsDialog.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/.
+ *
+ */
+
+#pragma once
+
+#include "StatisticsInputOutputDialog.hxx"
+
+class ScDescriptiveStatisticsDialog : public ScStatisticsInputOutputDialog
+{
+public:
+ ScDescriptiveStatisticsDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData );
+
+ virtual ~ScDescriptiveStatisticsDialog() override;
+
+ virtual void Close() override;
+
+protected:
+ virtual TranslateId GetUndoNameId() override;
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/DrawModelBroadcaster.hxx b/sc/source/ui/inc/DrawModelBroadcaster.hxx
new file mode 100644
index 000000000..a4c58dbba
--- /dev/null
+++ b/sc/source/ui/inc/DrawModelBroadcaster.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 <svl/lstner.hxx>
+#include <comphelper/interfacecontainer4.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/document/XEventBroadcaster.hpp>
+#include <com/sun/star/document/XShapeEventBroadcaster.hpp>
+#include <mutex>
+#include <unordered_map>
+
+class SdrModel;
+
+class ScDrawModelBroadcaster : public SfxListener,
+ public ::cppu::WeakImplHelper< css::document::XShapeEventBroadcaster >
+{
+ mutable std::mutex maListenerMutex;
+ ::comphelper::OInterfaceContainerHelper4<css::document::XEventListener> maEventListeners;
+ std::unordered_map<css::uno::Reference< css::drawing::XShape >, css::uno::Reference< css::document::XShapeEventListener >> maShapeListeners;
+ SdrModel *mpDrawModel;
+
+public:
+
+ ScDrawModelBroadcaster( SdrModel *pDrawModel );
+ virtual ~ScDrawModelBroadcaster() override;
+
+ // css::document::XEventBroadcaster
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::document::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::document::XEventListener >& xListener ) override;
+ // css::document::XShapeEventBroadcaster
+ virtual void SAL_CALL addShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;
+ virtual void SAL_CALL removeShapeEventListener( const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::document::XShapeEventListener >& xListener ) override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/ExponentialSmoothingDialog.hxx b/sc/source/ui/inc/ExponentialSmoothingDialog.hxx
new file mode 100644
index 000000000..54b877167
--- /dev/null
+++ b/sc/source/ui/inc/ExponentialSmoothingDialog.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 <address.hxx>
+#include "viewdata.hxx"
+
+#include "StatisticsInputOutputDialog.hxx"
+
+class ScExponentialSmoothingDialog : public ScStatisticsInputOutputDialog
+{
+private:
+ std::unique_ptr<weld::SpinButton> mxSmoothingFactor;
+
+public:
+ ScExponentialSmoothingDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData );
+
+ virtual ~ScExponentialSmoothingDialog() override;
+
+ virtual void Close() override;
+
+protected:
+ virtual TranslateId GetUndoNameId() override;
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/FTestDialog.hxx b/sc/source/ui/inc/FTestDialog.hxx
new file mode 100644
index 000000000..efd477ce0
--- /dev/null
+++ b/sc/source/ui/inc/FTestDialog.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/.
+ *
+ */
+
+#pragma once
+
+#include "StatisticsTwoVariableDialog.hxx"
+
+class ScFTestDialog : public ScStatisticsTwoVariableDialog
+{
+public:
+ ScFTestDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData );
+
+ virtual ~ScFTestDialog() override;
+
+ virtual void Close() override;
+
+protected:
+ virtual TranslateId GetUndoNameId() override;
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/FilterListBox.hxx b/sc/source/ui/inc/FilterListBox.hxx
new file mode 100644
index 000000000..a17a1694a
--- /dev/null
+++ b/sc/source/ui/inc/FilterListBox.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 <types.hxx>
+
+#include <tools/solar.h>
+#include <vcl/weld.hxx>
+
+class ScGridWindow;
+struct ImplSVEvent;
+
+enum class ScFilterBoxMode
+{
+ DataSelect,
+ Scenario
+};
+
+class ScFilterListBox final : public std::enable_shared_from_this<ScFilterListBox>
+{
+private:
+ std::unique_ptr<weld::Builder> xBuilder;
+ std::unique_ptr<weld::Popover> xPopover;
+ std::unique_ptr<weld::TreeView> xTreeView;
+ VclPtr<ScGridWindow> pGridWin;
+ SCCOL nCol;
+ SCROW nRow;
+ bool bInit;
+ bool bCancelled;
+ bool bGridHadMouseCaptured;
+ sal_uLong nSel;
+ ScFilterBoxMode eMode;
+ ImplSVEvent* nAsyncSelectHdl;
+
+ DECL_LINK(SelectHdl, weld::TreeView&, bool);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(AsyncSelectHdl, void*, void);
+
+public:
+ ScFilterListBox(weld::Window* pParent, ScGridWindow* pGrid, SCCOL nNewCol, SCROW nNewRow,
+ ScFilterBoxMode eNewMode);
+ void popup_at_rect(weld::Widget* pParent, const tools::Rectangle& rRect)
+ {
+ xPopover->popup_at_rect(pParent, rRect);
+ }
+ void connect_closed(const Link<weld::Popover&, void>& rLink)
+ {
+ xPopover->connect_closed(rLink);
+ }
+ void popdown() { xPopover->popdown(); }
+ ~ScFilterListBox();
+
+ weld::TreeView& get_widget() { return *xTreeView; }
+
+ SCCOL GetCol() const { return nCol; }
+ SCROW GetRow() const { return nRow; }
+ ScFilterBoxMode GetMode() const { return eMode; }
+ void EndInit();
+ bool IsInInit() const { return bInit; }
+ bool MouseWasCaptured() const { return bGridHadMouseCaptured; }
+ void SetCancelled() { bCancelled = true; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/FourierAnalysisDialog.hxx b/sc/source/ui/inc/FourierAnalysisDialog.hxx
new file mode 100644
index 000000000..f839b274e
--- /dev/null
+++ b/sc/source/ui/inc/FourierAnalysisDialog.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/.
+ *
+ */
+
+#pragma once
+
+#include "StatisticsInputOutputDialog.hxx"
+
+class ScFourierAnalysisDialog : public ScStatisticsInputOutputDialog
+{
+ ScAddress maLabelAddr;
+ ScRange maActualInputRange;
+ SCSIZE mnLen;
+
+ double mfMinMag;
+
+ bool mbUse3DAddresses : 1;
+ bool mbGroupedByColumn : 1;
+ bool mbWithLabels : 1;
+ bool mbInverse : 1;
+ bool mbPolar : 1;
+
+ std::unique_ptr<weld::CheckButton> mxWithLabelsCheckBox;
+ std::unique_ptr<weld::CheckButton> mxInverseCheckBox;
+ std::unique_ptr<weld::CheckButton> mxPolarCheckBox;
+ std::unique_ptr<weld::SpinButton> mxMinMagnitudeField;
+ std::unique_ptr<weld::Label> mxErrorMessage;
+
+public:
+ ScFourierAnalysisDialog(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScViewData& rViewData);
+
+ virtual ~ScFourierAnalysisDialog() override;
+
+ virtual void Close() override;
+
+protected:
+ virtual TranslateId GetUndoNameId() override;
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) override;
+ virtual bool InputRangesValid() override;
+
+private:
+ void getOptions();
+ void getDataLabel(OUString& rLabel);
+ void genFormula(OUString& rFormula);
+
+ DECL_LINK(CheckBoxHdl, weld::Toggleable&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/IAnyRefDialog.hxx b/sc/source/ui/inc/IAnyRefDialog.hxx
new file mode 100644
index 000000000..acc8a5bfc
--- /dev/null
+++ b/sc/source/ui/inc/IAnyRefDialog.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 <formula/IControlReferenceHandler.hxx>
+
+class ScRange;
+class ScDocument;
+class SfxObjectShell;
+namespace formula
+{
+class RefEdit;
+class RefButton;
+}
+class SAL_NO_VTABLE IAnyRefDialog : public formula::IControlReferenceHandler
+{
+public:
+ virtual ~IAnyRefDialog() COVERITY_NOEXCEPT_FALSE {}
+
+ virtual void SetReference(const ScRange& rRef, ScDocument& rDoc) = 0;
+ virtual void RefInputStart(formula::RefEdit* pEdit, formula::RefButton* pButton = nullptr) = 0;
+ virtual void RefInputDone(bool bForced = false) = 0;
+ virtual bool IsTableLocked() const = 0;
+ virtual bool IsRefInputMode() const = 0;
+
+ virtual bool IsDocAllowed(SfxObjectShell* pDocSh) const = 0;
+ virtual void AddRefEntry() = 0;
+ virtual void SetActive() = 0;
+ virtual void ViewShellChanged() = 0;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/MatrixComparisonGenerator.hxx b/sc/source/ui/inc/MatrixComparisonGenerator.hxx
new file mode 100644
index 000000000..058b9611a
--- /dev/null
+++ b/sc/source/ui/inc/MatrixComparisonGenerator.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/.
+ *
+ */
+
+#pragma once
+
+#include <address.hxx>
+#include "viewdata.hxx"
+
+#include "StatisticsInputOutputDialog.hxx"
+
+class ScMatrixComparisonGenerator : public ScStatisticsInputOutputDialog
+{
+public:
+ ScMatrixComparisonGenerator(
+ SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pParent, ScViewData& rViewData,
+ const OUString& rUiXmlDescription, const OString& rID);
+
+ virtual ~ScMatrixComparisonGenerator() override;
+
+protected:
+ virtual TranslateId GetUndoNameId() override;
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) override;
+
+ virtual OUString getLabel() = 0;
+ virtual OUString getTemplate() = 0;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/MovingAverageDialog.hxx b/sc/source/ui/inc/MovingAverageDialog.hxx
new file mode 100644
index 000000000..216b67c8b
--- /dev/null
+++ b/sc/source/ui/inc/MovingAverageDialog.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 <address.hxx>
+#include "viewdata.hxx"
+
+#include "StatisticsInputOutputDialog.hxx"
+
+class ScMovingAverageDialog : public ScStatisticsInputOutputDialog
+{
+private:
+ std::unique_ptr<weld::CheckButton> mxTrimRangeCheck;
+ std::unique_ptr<weld::SpinButton> mxIntervalSpin;
+
+public:
+ ScMovingAverageDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData );
+
+ virtual ~ScMovingAverageDialog() override;
+
+ virtual void Close() override;
+
+protected:
+ virtual TranslateId GetUndoNameId() override;
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/PivotLayoutDialog.hxx b/sc/source/ui/inc/PivotLayoutDialog.hxx
new file mode 100644
index 000000000..0ce026bf4
--- /dev/null
+++ b/sc/source/ui/inc/PivotLayoutDialog.hxx
@@ -0,0 +1,140 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#pragma once
+
+#include "anyrefdg.hxx"
+#include <dpobject.hxx>
+#include "viewdata.hxx"
+
+#include "PivotLayoutTreeList.hxx"
+#include "PivotLayoutTreeListData.hxx"
+#include "PivotLayoutTreeListLabel.hxx"
+
+class ScItemValue final
+{
+public:
+ OUString maName;
+ ScPivotFuncData maFunctionData;
+ ScItemValue* mpOriginalItemValue;
+
+ ScItemValue(OUString const & aName, SCCOL nColumn, PivotFunc nFunctionMask);
+ ScItemValue(const ScItemValue* pInputItemValue);
+
+ ~ScItemValue();
+};
+
+class ScPivotLayoutDialog : public ScAnyRefDlgController
+{
+public:
+ ScDPObject maPivotTableObject;
+
+ ScPivotLayoutTreeListBase* mpPreviouslyFocusedListBox;
+
+private:
+ ScViewData* mpViewData;
+ ScDocument& mrDocument;
+
+ bool mbNewPivotTable;
+
+ ScAddress::Details maAddressDetails;
+ bool mbDialogLostFocus;
+
+ formula::RefEdit* mpActiveEdit;
+ std::unique_ptr<ScPivotLayoutTreeListLabel> mxListBoxField;
+ std::unique_ptr<ScPivotLayoutTreeList> mxListBoxPage;
+ std::unique_ptr<ScPivotLayoutTreeList> mxListBoxColumn;
+ std::unique_ptr<ScPivotLayoutTreeList> mxListBoxRow;
+ std::unique_ptr<ScPivotLayoutTreeListData> mxListBoxData;
+
+ std::unique_ptr<weld::CheckButton> mxCheckIgnoreEmptyRows;
+ std::unique_ptr<weld::CheckButton> mxCheckTotalColumns;
+ std::unique_ptr<weld::CheckButton> mxCheckAddFilter;
+ std::unique_ptr<weld::CheckButton> mxCheckIdentifyCategories;
+ std::unique_ptr<weld::CheckButton> mxCheckTotalRows;
+ std::unique_ptr<weld::CheckButton> mxCheckDrillToDetail;
+
+ std::unique_ptr<weld::RadioButton> mxSourceRadioNamedRange;
+ std::unique_ptr<weld::RadioButton> mxSourceRadioSelection;
+
+ std::unique_ptr<weld::ComboBox> mxSourceListBox;
+ std::unique_ptr<formula::RefEdit> mxSourceEdit;
+ std::unique_ptr<formula::RefButton> mxSourceButton;
+
+ std::unique_ptr<weld::RadioButton> mxDestinationRadioNewSheet;
+ std::unique_ptr<weld::RadioButton> mxDestinationRadioNamedRange;
+ std::unique_ptr<weld::RadioButton> mxDestinationRadioSelection;
+
+ std::unique_ptr<weld::ComboBox> mxDestinationListBox;
+ std::unique_ptr<formula::RefEdit> mxDestinationEdit;
+ std::unique_ptr<formula::RefButton> mxDestinationButton;
+
+ std::unique_ptr<weld::Button> mxBtnOK;
+ std::unique_ptr<weld::Button> mxBtnCancel;
+
+ std::unique_ptr<weld::Frame> mxSourceFrame;
+ std::unique_ptr<weld::Label> mxSourceLabel;
+ std::unique_ptr<weld::Frame> mxDestFrame;
+ std::unique_ptr<weld::Label> mxDestLabel;
+
+ std::unique_ptr<weld::Expander> mxOptions;
+ std::unique_ptr<weld::Expander> mxMore;
+
+ DECL_LINK(CancelClicked, weld::Button&, void);
+ DECL_LINK(OKClicked, weld::Button&, void);
+ DECL_LINK(GetEditFocusHandler, formula::RefEdit&, void);
+ DECL_LINK(GetButtonFocusHandler, formula::RefButton&, void);
+ DECL_LINK(LoseEditFocusHandler, formula::RefEdit&, void);
+ DECL_LINK(LoseButtonFocusHandler, formula::RefButton&, void);
+ DECL_LINK(ToggleSource, weld::Toggleable&, void);
+ DECL_LINK(ToggleDestination, weld::Toggleable&, void);
+ DECL_LINK(SourceListSelected, weld::ComboBox&, void);
+ DECL_LINK(SourceEditModified, formula::RefEdit&, void);
+ void ToggleSource();
+ void ToggleDestination();
+ virtual void Close() override;
+
+ ScPivotParam maPivotParameters;
+
+ // UI
+ void SetupSource();
+ void SetupDestination();
+ void FillValuesToListBoxes();
+
+ // Other
+ bool GetDestination(ScRange& aDestinationRange, bool& bToNewSheet);
+
+public:
+ ScPivotLayoutDialog(SfxBindings* pSfxBindings, SfxChildWindow* pChildWindow, weld::Window* pParent,
+ ScViewData* pViewData, const ScDPObject* pPivotTableObject, bool bCreateNewPivotTable);
+ virtual ~ScPivotLayoutDialog() override;
+
+ virtual void SetReference(const ScRange& rReferenceRange, ScDocument& rDocument) override;
+ virtual void SetActive() override;
+ virtual bool IsRefInputMode() const override;
+
+ void ItemInserted(const ScItemValue* pItemValue, ScPivotLayoutTreeList::SvPivotTreeListType eType);
+
+ void UpdateSourceRange();
+
+ void ApplyChanges();
+ void ApplySaveData(ScDPSaveData& rSaveData);
+ void ApplyLabelData(const ScDPSaveData& rSaveData);
+
+ ScItemValue* GetItem(SCCOL nColumn);
+ bool IsDataElement(SCCOL nColumn);
+
+ ScDPLabelData& GetLabelData(SCCOL nColumn);
+ ScDPLabelDataVector& GetLabelDataVector() { return maPivotParameters.maLabelArray;}
+ void PushDataFieldNames(std::vector<ScDPName>& rDataFieldNames);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+
diff --git a/sc/source/ui/inc/PivotLayoutTreeList.hxx b/sc/source/ui/inc/PivotLayoutTreeList.hxx
new file mode 100644
index 000000000..14faa13d0
--- /dev/null
+++ b/sc/source/ui/inc/PivotLayoutTreeList.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/.
+ *
+ */
+
+#pragma once
+
+#include <memory>
+#include "PivotLayoutTreeListBase.hxx"
+#include <scabstdlg.hxx>
+
+class ScPivotLayoutTreeList : public ScPivotLayoutTreeListBase
+{
+private:
+ std::vector<std::unique_ptr<ScItemValue>> maItemValues;
+ std::vector<ScDPName> maDataFieldNames;
+
+ VclPtr<AbstractScDPSubtotalDlg> mpSubtotalDlg;
+
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(DoubleClickHdl, weld::TreeView&, bool);
+
+public:
+ ScPivotLayoutTreeList(std::unique_ptr<weld::TreeView> xControl);
+ virtual ~ScPivotLayoutTreeList() override;
+
+ void Setup(ScPivotLayoutDialog* pParent, SvPivotTreeListType eType);
+ void FillFields(ScPivotFieldVector& rFieldVector);
+
+ virtual void InsertEntryForSourceTarget(weld::TreeView& rSource, int nTarget) override;
+
+protected:
+ void InsertEntryForItem(const ScItemValue* pItemValue, int nPosition);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/PivotLayoutTreeListBase.hxx b/sc/source/ui/inc/PivotLayoutTreeListBase.hxx
new file mode 100644
index 000000000..51858de68
--- /dev/null
+++ b/sc/source/ui/inc/PivotLayoutTreeListBase.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/.
+ *
+ */
+
+#pragma once
+
+#include <vcl/transfer.hxx>
+#include <vcl/weld.hxx>
+#include <pivot.hxx>
+
+class ScPivotLayoutDialog;
+class ScPivotLayoutTreeListBase;
+class ScItemValue;
+
+class ScPivotLayoutTreeDropTarget : public DropTargetHelper
+{
+private:
+ ScPivotLayoutTreeListBase& m_rTreeView;
+
+ virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override;
+ virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override;
+
+public:
+ ScPivotLayoutTreeDropTarget(ScPivotLayoutTreeListBase& rTreeView);
+};
+
+class ScPivotLayoutTreeListBase
+{
+public:
+ enum SvPivotTreeListType
+ {
+ UNDEFINED,
+ LABEL_LIST,
+ PAGE_LIST,
+ ROW_LIST,
+ COLUMN_LIST
+ };
+
+protected:
+ std::unique_ptr<weld::TreeView> mxControl;
+ ScPivotLayoutTreeDropTarget maDropTargetHelper;
+ SvPivotTreeListType meType;
+ ScPivotLayoutDialog* mpParent;
+
+ DECL_LINK(GetFocusHdl, weld::Widget&, void);
+ DECL_LINK(MnemonicActivateHdl, weld::Widget&, bool);
+ DECL_LINK(LoseFocusHdl, weld::Widget&, void);
+
+public:
+ void Setup(ScPivotLayoutDialog* pParent);
+
+ ScPivotLayoutTreeListBase(std::unique_ptr<weld::TreeView> xControl,
+ SvPivotTreeListType eType = UNDEFINED);
+ weld::TreeView& get_widget() { return *mxControl; }
+ virtual ~ScPivotLayoutTreeListBase();
+
+ void PushEntriesToPivotFieldVector(ScPivotFieldVector& rVector);
+
+ void RemoveEntryForItem(const ScItemValue* pItemValue);
+
+ virtual void InsertEntryForSourceTarget(weld::TreeView& rSource, int nTarget);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/PivotLayoutTreeListData.hxx b/sc/source/ui/inc/PivotLayoutTreeListData.hxx
new file mode 100644
index 000000000..89e83abad
--- /dev/null
+++ b/sc/source/ui/inc/PivotLayoutTreeListData.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 "PivotLayoutTreeListBase.hxx"
+#include <vector>
+#include <memory>
+#include <scabstdlg.hxx>
+
+class ScPivotLayoutTreeListData final : public ScPivotLayoutTreeListBase
+{
+private:
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(DoubleClickHdl, weld::TreeView&, bool);
+
+public:
+ ScPivotLayoutTreeListData(std::unique_ptr<weld::TreeView> xControl);
+ virtual ~ScPivotLayoutTreeListData() override;
+
+ void FillDataField(ScPivotFieldVector& rDataFields);
+ void PushDataFieldNames(std::vector<ScDPName>& rDataFieldNames);
+ virtual void InsertEntryForSourceTarget(weld::TreeView& rSource, int nTarget) override;
+
+private:
+ void InsertEntryForItem(ScItemValue* pItemValue, int nPosition);
+
+ void AdjustDuplicateCount(ScItemValue* pInputItemValue);
+
+ std::vector<std::unique_ptr<ScItemValue>> maDataItemValues;
+
+ VclPtr<AbstractScDPFunctionDlg> mpFunctionDlg;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/PivotLayoutTreeListLabel.hxx b/sc/source/ui/inc/PivotLayoutTreeListLabel.hxx
new file mode 100644
index 000000000..d551798e3
--- /dev/null
+++ b/sc/source/ui/inc/PivotLayoutTreeListLabel.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#pragma once
+
+#include "PivotLayoutTreeListBase.hxx"
+#include <vector>
+#include <memory>
+
+class ScPivotLayoutTreeListLabel : public ScPivotLayoutTreeListBase
+{
+private:
+ std::vector<std::unique_ptr<ScItemValue>> maItemValues;
+ SCCOL maDataItem;
+
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+
+public:
+ ScPivotLayoutTreeListLabel(std::unique_ptr<weld::TreeView> xControl);
+ virtual ~ScPivotLayoutTreeListLabel() override;
+ void FillLabelFields(ScDPLabelDataVector& rLabelVector);
+ ScItemValue* GetItem(SCCOL nColumn);
+ bool IsDataElement(SCCOL nColumn);
+ virtual void InsertEntryForSourceTarget(weld::TreeView& rSource, int nTarget) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/RandomNumberGeneratorDialog.hxx b/sc/source/ui/inc/RandomNumberGeneratorDialog.hxx
new file mode 100644
index 000000000..0f890fc79
--- /dev/null
+++ b/sc/source/ui/inc/RandomNumberGeneratorDialog.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/.
+ *
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <optional>
+
+#include <address.hxx>
+#include "anyrefdg.hxx"
+#include "viewdata.hxx"
+
+class ScRandomNumberGeneratorDialog : public ScAnyRefDlgController
+{
+public:
+ ScRandomNumberGeneratorDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData );
+
+ virtual ~ScRandomNumberGeneratorDialog() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+ virtual void SetActive() override;
+ virtual void Close() override;
+
+private:
+ // Data
+ ScViewData& mrViewData;
+ const ScDocument& mrDoc;
+
+ ScRange maInputRange;
+
+ bool mbDialogLostFocus;
+
+ // Widgets
+ std::unique_ptr<weld::Label> mxInputRangeText;
+ std::unique_ptr<formula::RefEdit> mxInputRangeEdit;
+ std::unique_ptr<formula::RefButton> mxInputRangeButton;
+ std::unique_ptr<weld::ComboBox> mxDistributionCombo;
+ std::unique_ptr<weld::Label> mxParameter1Text;
+ std::unique_ptr<weld::SpinButton> mxParameter1Value;
+ std::unique_ptr<weld::Label> mxParameter2Text;
+ std::unique_ptr<weld::SpinButton> mxParameter2Value;
+ std::unique_ptr<weld::SpinButton> mxSeed;
+ std::unique_ptr<weld::CheckButton> mxEnableSeed;
+ std::unique_ptr<weld::SpinButton> mxDecimalPlaces;
+ std::unique_ptr<weld::CheckButton> mxEnableRounding;
+ std::unique_ptr<weld::Button> mxButtonApply;
+ std::unique_ptr<weld::Button> mxButtonOk;
+ std::unique_ptr<weld::Button> mxButtonClose;
+
+ void Init();
+ void GetRangeFromSelection();
+
+ template<class RNG>
+
+ void GenerateNumbers(RNG& randomGenerator, TranslateId pDistributionStringId, const std::optional<sal_Int8> aDecimalPlaces);
+
+ void SelectGeneratorAndGenerateNumbers();
+
+ DECL_LINK( OkClicked, weld::Button&, void );
+ DECL_LINK( CloseClicked, weld::Button&, void );
+ DECL_LINK( ApplyClicked, weld::Button&, void );
+ DECL_LINK( GetEditFocusHandler, formula::RefEdit&, void );
+ DECL_LINK( GetButtonFocusHandler, formula::RefButton&, void );
+ DECL_LINK( LoseEditFocusHandler, formula::RefEdit&, void );
+ DECL_LINK( LoseButtonFocusHandler, formula::RefButton&, void );
+
+ DECL_LINK( InputRangeModified, formula::RefEdit&, void );
+ DECL_LINK( Parameter1ValueModified, weld::SpinButton&, void );
+ DECL_LINK( Parameter2ValueModified, weld::SpinButton&, void );
+ DECL_LINK( DistributionChanged, weld::ComboBox&, void );
+ DECL_LINK( CheckChanged, weld::Toggleable&, void );
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/RegressionDialog.hxx b/sc/source/ui/inc/RegressionDialog.hxx
new file mode 100644
index 000000000..59accf265
--- /dev/null
+++ b/sc/source/ui/inc/RegressionDialog.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/.
+ *
+ */
+
+#pragma once
+
+#include "StatisticsTwoVariableDialog.hxx"
+#include "TableFillingAndNavigationTools.hxx"
+
+class ScRegressionDialog : public ScStatisticsTwoVariableDialog
+{
+ bool mbUnivariate;
+ size_t mnNumIndependentVars;
+ size_t mnNumObservations;
+ bool mbUse3DAddresses;
+ bool mbCalcIntercept;
+
+ std::unique_ptr<weld::CheckButton> mxWithLabelsCheckBox;
+ std::unique_ptr<weld::RadioButton> mxLinearRadioButton;
+ std::unique_ptr<weld::RadioButton> mxLogarithmicRadioButton;
+ std::unique_ptr<weld::RadioButton> mxPowerRadioButton;
+ std::unique_ptr<weld::Label> mxErrorMessage;
+ std::unique_ptr<weld::SpinButton> mxConfidenceLevelField;
+ std::unique_ptr<weld::CheckButton> mxCalcResidualsCheckBox;
+ std::unique_ptr<weld::CheckButton> mxNoInterceptCheckBox;
+
+public:
+ ScRegressionDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData );
+
+ virtual ~ScRegressionDialog() override;
+
+ virtual void Close() override;
+
+protected:
+ virtual TranslateId GetUndoNameId() override;
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) override;
+ virtual bool InputRangesValid() override;
+
+private:
+
+ using CellValueGetter = const OUString&(size_t, size_t);
+ using CellWriter = void(const OUString&, size_t, size_t);
+
+ size_t GetRegressionTypeIndex() const;
+ ScRange GetDataRange(const ScRange& rRange);
+ OUString GetVariableNameFormula(bool bXVar, size_t nIndex, bool bWithLog);
+ OUString GetXVariableNameFormula(size_t nIndex, bool bWithLog);
+ OUString GetYVariableNameFormula(bool bWithLog);
+
+ // Helper methods for writing different parts of regression results.
+ void WriteRawRegressionResults(AddressWalkerWriter& rOutput,
+ FormulaTemplate& rTemplate,
+ size_t nRegressionIndex);
+ void WriteRegressionStatistics(AddressWalkerWriter& rOutput,
+ FormulaTemplate& rTemplate);
+ void WriteRegressionANOVAResults(AddressWalkerWriter& rOutput,
+ FormulaTemplate& rTemplate);
+ void WriteRegressionEstimatesWithCI(AddressWalkerWriter& rOutput,
+ FormulaTemplate& rTemplate,
+ bool bTakeLogX);
+ void WritePredictionsWithResiduals(AddressWalkerWriter& rOutput,
+ FormulaTemplate& rTemplate,
+ size_t nRegressionIndex);
+ // Generic table writer
+ static void WriteTable(const std::function<CellValueGetter>& rCellGetter, size_t nRowsInTable,
+ size_t nColsInTable, AddressWalkerWriter& rOutput,
+ const std::function<CellWriter>& rFunc);
+
+ DECL_LINK( CheckBoxHdl, weld::Toggleable&, void );
+ DECL_LINK( NumericFieldHdl, weld::SpinButton&, void );
+};
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/SamplingDialog.hxx b/sc/source/ui/inc/SamplingDialog.hxx
new file mode 100644
index 000000000..e561092a8
--- /dev/null
+++ b/sc/source/ui/inc/SamplingDialog.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 <address.hxx>
+#include "anyrefdg.hxx"
+#include "viewdata.hxx"
+
+class ScSamplingDialog : public ScAnyRefDlgController
+{
+public:
+ ScSamplingDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData );
+
+ virtual ~ScSamplingDialog() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+ virtual void SetActive() override;
+ virtual void Close() override;
+
+private:
+ formula::RefEdit* mpActiveEdit;
+
+ // Data
+ ScViewData& mViewData;
+ const ScDocument& mDocument;
+
+ ScRange mInputRange;
+ ScAddress::Details mAddressDetails;
+ ScAddress mOutputAddress;
+
+ ScAddress mCurrentAddress;
+
+ sal_Int64 mnLastSampleSizeValue;
+ sal_Int64 mnLastPeriodValue;
+
+ bool mDialogLostFocus;
+
+ // Widgets
+ std::unique_ptr<weld::Label> mxInputRangeLabel;
+ std::unique_ptr<formula::RefEdit> mxInputRangeEdit;
+ std::unique_ptr<formula::RefButton> mxInputRangeButton;
+
+ std::unique_ptr<weld::Label> mxOutputRangeLabel;
+ std::unique_ptr<formula::RefEdit> mxOutputRangeEdit;
+ std::unique_ptr<formula::RefButton> mxOutputRangeButton;
+
+ std::unique_ptr<weld::SpinButton> mxSampleSize;
+ std::unique_ptr<weld::SpinButton> mxPeriod;
+
+ std::unique_ptr<weld::RadioButton> mxRandomMethodRadio;
+ std::unique_ptr<weld::CheckButton> mxWithReplacement;
+ std::unique_ptr<weld::CheckButton> mxKeepOrder;
+ std::unique_ptr<weld::RadioButton> mxPeriodicMethodRadio;
+
+ std::unique_ptr<weld::Button> mxButtonOk;
+ std::unique_ptr<weld::Button> mxButtonCancel;
+
+ void Init();
+ void GetRangeFromSelection();
+ void PerformSampling();
+ sal_Int64 GetPopulationSize() const;
+ void LimitSampleSizeAndPeriod();
+
+ ScRange PerformRandomSampling(ScDocShell* pDocShell);
+ ScRange PerformRandomSamplingKeepOrder(ScDocShell* pDocShell);
+ ScRange PerformPeriodicSampling(ScDocShell* pDocShell);
+
+ DECL_LINK( ButtonClicked, weld::Button&, void );
+ DECL_LINK( GetEditFocusHandler, formula::RefEdit&, void );
+ DECL_LINK( GetButtonFocusHandler, formula::RefButton&, void );
+ DECL_LINK( LoseEditFocusHandler, formula::RefEdit&, void );
+ DECL_LINK( LoseButtonFocusHandler, formula::RefButton&, void );
+ DECL_LINK( SamplingSizeValueModified, weld::SpinButton&, void );
+ DECL_LINK( PeriodValueModified, weld::SpinButton&, void );
+ DECL_LINK( ToggleSamplingMethod, weld::Toggleable&, void );
+ DECL_LINK( RefInputModifyHandler, formula::RefEdit&, void );
+ DECL_LINK( CheckHdl, weld::Toggleable&, void );
+ void ToggleSamplingMethod();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/SparklineDataRangeDialog.hxx b/sc/source/ui/inc/SparklineDataRangeDialog.hxx
new file mode 100644
index 000000000..32d3ed035
--- /dev/null
+++ b/sc/source/ui/inc/SparklineDataRangeDialog.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/.
+ */
+
+#pragma once
+
+#include <address.hxx>
+#include "anyrefdg.hxx"
+#include "viewdata.hxx"
+
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
+class ColorListBox;
+
+namespace sc
+{
+/** Dialog to change input data range for a sparkline */
+class SparklineDataRangeDialog : public ScAnyRefDlgController
+{
+private:
+ ScViewData& mrViewData;
+ ScDocument& mrDocument;
+
+ std::shared_ptr<sc::Sparkline> mpSparkline;
+
+ ScRange maDataRange;
+
+ formula::RefEdit* mpActiveEdit;
+ bool mbDialogLostFocus;
+
+ std::unique_ptr<weld::Button> mxButtonOk;
+ std::unique_ptr<weld::Button> mxButtonCancel;
+
+ std::unique_ptr<weld::Label> mxDataRangeLabel;
+ std::unique_ptr<formula::RefEdit> mxDataRangeEdit;
+ std::unique_ptr<formula::RefButton> mxDataRangeButton;
+
+ DECL_LINK(ButtonClicked, weld::Button&, void);
+ DECL_LINK(EditFocusHandler, formula::RefEdit&, void);
+ DECL_LINK(ButtonFocusHandler, formula::RefButton&, void);
+ DECL_LINK(LoseEditFocusHandler, formula::RefEdit&, void);
+ DECL_LINK(LoseButtonFocusHandler, formula::RefButton&, void);
+ DECL_LINK(RefInputModifyHandler, formula::RefEdit&, void);
+
+ void setupValues();
+
+ void perform();
+ bool checkValidInputOutput();
+
+public:
+ SparklineDataRangeDialog(SfxBindings* pBindings, SfxChildWindow* pChildWindow,
+ weld::Window* pWindow, ScViewData& rViewData);
+ virtual ~SparklineDataRangeDialog() override;
+
+ void SetReference(const ScRange& rRef, ScDocument& rDocument) override;
+ void SetActive() override;
+ void Close() override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/SparklineDialog.hxx b/sc/source/ui/inc/SparklineDialog.hxx
new file mode 100644
index 000000000..f3f309c56
--- /dev/null
+++ b/sc/source/ui/inc/SparklineDialog.hxx
@@ -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/.
+ */
+
+#pragma once
+
+#include <address.hxx>
+#include "anyrefdg.hxx"
+#include "viewdata.hxx"
+
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
+class ColorListBox;
+
+namespace sc
+{
+/** Dialog to create or edit sparkline group attributes */
+class SparklineDialog : public ScAnyRefDlgController
+{
+private:
+ ScViewData& mrViewData;
+ ScDocument& mrDocument;
+
+ ScRange maInputRange;
+ ScRange maOutputRange;
+
+ formula::RefEdit* mpActiveEdit;
+ bool mbDialogLostFocus;
+
+ std::unique_ptr<weld::Button> mxButtonOk;
+ std::unique_ptr<weld::Button> mxButtonCancel;
+
+ std::unique_ptr<weld::Frame> mxFrameData;
+
+ std::unique_ptr<weld::Label> mxInputRangeLabel;
+ std::unique_ptr<formula::RefEdit> mxInputRangeEdit;
+ std::unique_ptr<formula::RefButton> mxInputRangeButton;
+
+ std::unique_ptr<weld::Label> mxOutputRangeLabel;
+ std::unique_ptr<formula::RefEdit> mxOutputRangeEdit;
+ std::unique_ptr<formula::RefButton> mxOutputRangeButton;
+
+ std::unique_ptr<ColorListBox> mxColorSeries;
+ std::unique_ptr<ColorListBox> mxColorNegative;
+ std::unique_ptr<ColorListBox> mxColorMarker;
+ std::unique_ptr<ColorListBox> mxColorHigh;
+ std::unique_ptr<ColorListBox> mxColorLow;
+ std::unique_ptr<ColorListBox> mxColorFirst;
+ std::unique_ptr<ColorListBox> mxColorLast;
+
+ std::unique_ptr<weld::CheckButton> mxCheckButtonNegative;
+ std::unique_ptr<weld::CheckButton> mxCheckButtonMarker;
+ std::unique_ptr<weld::CheckButton> mxCheckButtonHigh;
+ std::unique_ptr<weld::CheckButton> mxCheckButtonLow;
+ std::unique_ptr<weld::CheckButton> mxCheckButtonFirst;
+ std::unique_ptr<weld::CheckButton> mxCheckButtonLast;
+
+ std::unique_ptr<weld::SpinButton> mxSpinLineWidth;
+ std::unique_ptr<weld::ComboBox> mxType;
+
+ std::unique_ptr<weld::CheckButton> mxCheckDisplayXAxis;
+ std::unique_ptr<weld::CheckButton> mxCheckDisplayHidden;
+ std::unique_ptr<weld::CheckButton> mxCheckRightToLeft;
+
+ std::unique_ptr<weld::ComboBox> mxDisplayEmptyGap;
+
+ std::unique_ptr<weld::ComboBox> mxComboMinAxisType;
+ std::unique_ptr<weld::ComboBox> mxComboMaxAxisType;
+
+ std::unique_ptr<weld::FormattedSpinButton> mxSpinCustomMin;
+ std::unique_ptr<weld::FormattedSpinButton> mxSpinCustomMax;
+
+ DECL_LINK(ButtonClicked, weld::Button&, void);
+ DECL_LINK(EditFocusHandler, formula::RefEdit&, void);
+ DECL_LINK(ButtonFocusHandler, formula::RefButton&, void);
+ DECL_LINK(LoseEditFocusHandler, formula::RefEdit&, void);
+ DECL_LINK(LoseButtonFocusHandler, formula::RefButton&, void);
+ DECL_LINK(RefInputModifyHandler, formula::RefEdit&, void);
+ DECL_LINK(ToggleHandler, weld::Toggleable&, void);
+ DECL_LINK(SelectSparklineType, weld::ComboBox&, void);
+ DECL_LINK(ComboValueChanged, weld::ComboBox&, void);
+ DECL_LINK(SpinLineWidthChanged, weld::SpinButton&, void);
+ DECL_LINK(SpinCustomChanged, weld::FormattedSpinButton&, void);
+
+ std::shared_ptr<sc::SparklineGroup> mpSparklineGroup;
+ sc::SparklineAttributes maAttributes;
+
+ bool mbEditMode;
+
+ void setupValues();
+ void setInputSelection();
+
+ void perform();
+ bool checkValidInputOutput();
+
+public:
+ SparklineDialog(SfxBindings* pBindings, SfxChildWindow* pChildWindow, weld::Window* pWindow,
+ ScViewData& rViewData);
+ virtual ~SparklineDialog() override;
+
+ virtual void SetReference(const ScRange& rRef, ScDocument& rDocument) override;
+ virtual void SetActive() override;
+ virtual void Close() override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/SparklineRenderer.hxx b/sc/source/ui/inc/SparklineRenderer.hxx
new file mode 100644
index 000000000..616d667ec
--- /dev/null
+++ b/sc/source/ui/inc/SparklineRenderer.hxx
@@ -0,0 +1,576 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <document.hxx>
+
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <comphelper/scopeguard.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
+namespace sc
+{
+/** Contains the marker polygon and the color of a marker */
+struct SparklineMarker
+{
+ basegfx::B2DPolygon maPolygon;
+ Color maColor;
+};
+
+/** Sparkline value and action that needs to me performed on the value */
+struct SparklineValue
+{
+ enum class Action
+ {
+ None, // No action on the value
+ Skip, // Skip the value
+ Interpolate // Interpolate the value
+ };
+
+ double maValue;
+ Action meAction;
+
+ SparklineValue(double aValue, Action eAction)
+ : maValue(aValue)
+ , meAction(eAction)
+ {
+ }
+};
+
+/** Contains and manages the values of the sparkline.
+ *
+ * It automatically keeps track of the minimums and maximums, and
+ * skips or interpolates the sparkline values if needed, depending on
+ * the input. This is done so it is easier to handle the sparkline
+ * values later on.
+ */
+class SparklineValues
+{
+private:
+ double mfPreviousValue = 0.0;
+ size_t mnPreviousIndex = std::numeric_limits<size_t>::max();
+
+ std::vector<size_t> maToInterpolateIndex;
+
+ std::vector<SparklineValue> maValueList;
+
+public:
+ size_t mnFirstIndex = std::numeric_limits<size_t>::max();
+ size_t mnLastIndex = 0;
+
+ double mfMinimum = std::numeric_limits<double>::max();
+ double mfMaximum = std::numeric_limits<double>::min();
+
+ std::vector<SparklineValue> const& getValuesList() const { return maValueList; }
+
+ void add(double fValue, SparklineValue::Action eAction)
+ {
+ maValueList.emplace_back(fValue, eAction);
+ size_t nCurrentIndex = maValueList.size() - 1;
+
+ if (eAction == SparklineValue::Action::None)
+ {
+ mnLastIndex = nCurrentIndex;
+
+ if (mnLastIndex < mnFirstIndex)
+ mnFirstIndex = mnLastIndex;
+
+ if (fValue < mfMinimum)
+ mfMinimum = fValue;
+
+ if (fValue > mfMaximum)
+ mfMaximum = fValue;
+
+ interpolatePastValues(fValue, nCurrentIndex);
+
+ mnPreviousIndex = nCurrentIndex;
+ mfPreviousValue = fValue;
+ }
+ else if (eAction == SparklineValue::Action::Interpolate)
+ {
+ maToInterpolateIndex.push_back(nCurrentIndex);
+ maValueList.back().meAction = SparklineValue::Action::Skip;
+ }
+ }
+
+ static constexpr double interpolate(double x1, double y1, double x2, double y2, double x)
+ {
+ return (y1 * (x2 - x) + y2 * (x - x1)) / (x2 - x1);
+ }
+
+ void interpolatePastValues(double nCurrentValue, size_t nCurrentIndex)
+ {
+ if (maToInterpolateIndex.empty())
+ return;
+
+ if (mnPreviousIndex == std::numeric_limits<size_t>::max())
+ {
+ for (size_t nIndex : maToInterpolateIndex)
+ {
+ auto& rValue = maValueList[nIndex];
+ rValue.meAction = SparklineValue::Action::Skip;
+ }
+ }
+ else
+ {
+ for (size_t nIndex : maToInterpolateIndex)
+ {
+ double fInterpolated = interpolate(mnPreviousIndex, mfPreviousValue, nCurrentIndex,
+ nCurrentValue, nIndex);
+
+ auto& rValue = maValueList[nIndex];
+ rValue.maValue = fInterpolated;
+ rValue.meAction = SparklineValue::Action::None;
+ }
+ }
+ maToInterpolateIndex.clear();
+ }
+
+ void convertToStacked()
+ {
+ // transform the data to 1, -1
+ for (auto& rValue : maValueList)
+ {
+ if (rValue.maValue != 0.0)
+ {
+ double fNewValue = rValue.maValue > 0.0 ? 1.0 : -1.0;
+
+ if (rValue.maValue == mfMinimum)
+ fNewValue -= 0.01;
+
+ if (rValue.maValue == mfMaximum)
+ fNewValue += 0.01;
+
+ rValue.maValue = fNewValue;
+ }
+ }
+ mfMinimum = -1.01;
+ mfMaximum = 1.01;
+ }
+
+ void reverse() { std::reverse(maValueList.begin(), maValueList.end()); }
+};
+
+/** Iterator to traverse the addresses in a range if the range is one dimensional.
+ *
+ * The direction to traverse is detected automatically or hasNext returns
+ * false if it is not possible to detect.
+ *
+ */
+class RangeTraverser
+{
+ enum class Direction
+ {
+ UNKNOWN,
+ ROW,
+ COLUMN
+ };
+
+ ScAddress m_aCurrent;
+ ScRange m_aRange;
+ Direction m_eDirection;
+
+public:
+ RangeTraverser(ScRange const& rRange)
+ : m_aCurrent(ScAddress::INITIALIZE_INVALID)
+ , m_aRange(rRange)
+ , m_eDirection(Direction::UNKNOWN)
+
+ {
+ }
+
+ ScAddress const& first()
+ {
+ m_aCurrent.SetInvalid();
+
+ if (m_aRange.aStart.Row() == m_aRange.aEnd.Row())
+ {
+ m_eDirection = Direction::COLUMN;
+ m_aCurrent = m_aRange.aStart;
+ }
+ else if (m_aRange.aStart.Col() == m_aRange.aEnd.Col())
+ {
+ m_eDirection = Direction::ROW;
+ m_aCurrent = m_aRange.aStart;
+ }
+
+ return m_aCurrent;
+ }
+
+ bool hasNext()
+ {
+ if (m_eDirection == Direction::COLUMN)
+ return m_aCurrent.Col() <= m_aRange.aEnd.Col();
+ else if (m_eDirection == Direction::ROW)
+ return m_aCurrent.Row() <= m_aRange.aEnd.Row();
+ else
+ return false;
+ }
+
+ void next()
+ {
+ if (hasNext())
+ {
+ if (m_eDirection == Direction::COLUMN)
+ m_aCurrent.IncCol();
+ else if (m_eDirection == Direction::ROW)
+ m_aCurrent.IncRow();
+ }
+ }
+};
+
+/** Render a provided sparkline into the input rectangle */
+class SparklineRenderer
+{
+private:
+ ScDocument& mrDocument;
+ tools::Long mnOneX;
+ tools::Long mnOneY;
+
+ double mfScaleX;
+ double mfScaleY;
+
+ void createMarker(std::vector<SparklineMarker>& rMarkers, double x, double y,
+ Color const& rColor)
+ {
+ auto& rMarker = rMarkers.emplace_back();
+ const double nHalfSizeX = double(mnOneX * 2 * mfScaleX);
+ const double nHalfSizeY = double(mnOneY * 2 * mfScaleY);
+ basegfx::B2DRectangle aRectangle(std::round(x - nHalfSizeX), std::round(y - nHalfSizeY),
+ std::round(x + nHalfSizeX), std::round(y + nHalfSizeY));
+ rMarker.maPolygon = basegfx::utils::createPolygonFromRect(aRectangle);
+ rMarker.maColor = rColor;
+ }
+
+ void drawLine(vcl::RenderContext& rRenderContext, tools::Rectangle const& rRectangle,
+ SparklineValues const& rSparklineValues,
+ sc::SparklineAttributes const& rAttributes)
+ {
+ double nMax = rSparklineValues.mfMaximum;
+ if (rAttributes.getMaxAxisType() == sc::AxisType::Custom && rAttributes.getManualMax())
+ nMax = *rAttributes.getManualMax();
+
+ double nMin = rSparklineValues.mfMinimum;
+ if (rAttributes.getMinAxisType() == sc::AxisType::Custom && rAttributes.getManualMin())
+ nMin = *rAttributes.getManualMin();
+
+ std::vector<SparklineValue> const& rValueList = rSparklineValues.getValuesList();
+ std::vector<basegfx::B2DPolygon> aPolygons;
+ aPolygons.emplace_back();
+ double numebrOfSteps = rValueList.size() - 1;
+ double xStep = 0;
+ double nDelta = nMax - nMin;
+
+ std::vector<SparklineMarker> aMarkers;
+ size_t nValueIndex = 0;
+
+ for (auto const& rSparklineValue : rValueList)
+ {
+ if (rSparklineValue.meAction == SparklineValue::Action::Skip)
+ {
+ aPolygons.emplace_back();
+ }
+ else
+ {
+ auto& aPolygon = aPolygons.back();
+ double nValue = rSparklineValue.maValue;
+
+ double nP = (nValue - nMin) / nDelta;
+ double x = rRectangle.GetWidth() * (xStep / numebrOfSteps);
+ double y = rRectangle.GetHeight() - rRectangle.GetHeight() * nP;
+
+ aPolygon.append({ x, y });
+
+ if (rAttributes.isFirst() && nValueIndex == rSparklineValues.mnFirstIndex)
+ {
+ createMarker(aMarkers, x, y, rAttributes.getColorFirst());
+ }
+ else if (rAttributes.isLast() && nValueIndex == rSparklineValues.mnLastIndex)
+ {
+ createMarker(aMarkers, x, y, rAttributes.getColorLast());
+ }
+ else if (rAttributes.isHigh() && nValue == rSparklineValues.mfMaximum)
+ {
+ createMarker(aMarkers, x, y, rAttributes.getColorHigh());
+ }
+ else if (rAttributes.isLow() && nValue == rSparklineValues.mfMinimum)
+ {
+ createMarker(aMarkers, x, y, rAttributes.getColorLow());
+ }
+ else if (rAttributes.isNegative() && nValue < 0.0)
+ {
+ createMarker(aMarkers, x, y, rAttributes.getColorNegative());
+ }
+ else if (rAttributes.isMarkers())
+ {
+ createMarker(aMarkers, x, y, rAttributes.getColorMarkers());
+ }
+ }
+
+ xStep++;
+ nValueIndex++;
+ }
+
+ basegfx::B2DHomMatrix aMatrix;
+ aMatrix.translate(rRectangle.Left(), rRectangle.Top());
+
+ if (rAttributes.shouldDisplayXAxis())
+ {
+ double nZero = 0 - nMin / nDelta;
+
+ if (nZero >= 0) // if nZero < 0, the axis is not visible
+ {
+ double x1 = 0.0;
+ double x2 = double(rRectangle.GetWidth());
+ double y = rRectangle.GetHeight() - rRectangle.GetHeight() * nZero;
+
+ basegfx::B2DPolygon aAxisPolygon;
+ aAxisPolygon.append({ x1, y });
+ aAxisPolygon.append({ x2, y });
+
+ rRenderContext.SetLineColor(rAttributes.getColorAxis());
+ rRenderContext.DrawPolyLineDirect(aMatrix, aAxisPolygon, 0.2 * mfScaleX);
+ }
+ }
+
+ rRenderContext.SetLineColor(rAttributes.getColorSeries());
+
+ for (auto& rPolygon : aPolygons)
+ {
+ rRenderContext.DrawPolyLineDirect(aMatrix, rPolygon,
+ rAttributes.getLineWeight() * mfScaleX, 0.0, nullptr,
+ basegfx::B2DLineJoin::Round);
+ }
+
+ for (auto& rMarker : aMarkers)
+ {
+ rRenderContext.SetLineColor(rMarker.maColor);
+ rRenderContext.SetFillColor(rMarker.maColor);
+ auto& rPolygon = rMarker.maPolygon;
+ rPolygon.transform(aMatrix);
+ rRenderContext.DrawPolygon(rPolygon);
+ }
+ }
+
+ static void setFillAndLineColor(vcl::RenderContext& rRenderContext,
+ sc::SparklineAttributes const& rAttributes, double nValue,
+ size_t nValueIndex, SparklineValues const& rSparklineValues)
+ {
+ if (rAttributes.isFirst() && nValueIndex == rSparklineValues.mnFirstIndex)
+ {
+ rRenderContext.SetLineColor(rAttributes.getColorFirst());
+ rRenderContext.SetFillColor(rAttributes.getColorFirst());
+ }
+ else if (rAttributes.isLast() && nValueIndex == rSparklineValues.mnLastIndex)
+ {
+ rRenderContext.SetLineColor(rAttributes.getColorLast());
+ rRenderContext.SetFillColor(rAttributes.getColorLast());
+ }
+ else if (rAttributes.isHigh() && nValue == rSparklineValues.mfMaximum)
+ {
+ rRenderContext.SetLineColor(rAttributes.getColorHigh());
+ rRenderContext.SetFillColor(rAttributes.getColorHigh());
+ }
+ else if (rAttributes.isLow() && nValue == rSparklineValues.mfMinimum)
+ {
+ rRenderContext.SetLineColor(rAttributes.getColorLow());
+ rRenderContext.SetFillColor(rAttributes.getColorLow());
+ }
+ else if (rAttributes.isNegative() && nValue < 0.0)
+ {
+ rRenderContext.SetLineColor(rAttributes.getColorNegative());
+ rRenderContext.SetFillColor(rAttributes.getColorNegative());
+ }
+ else
+ {
+ rRenderContext.SetLineColor(rAttributes.getColorSeries());
+ rRenderContext.SetFillColor(rAttributes.getColorSeries());
+ }
+ }
+
+ void drawColumn(vcl::RenderContext& rRenderContext, tools::Rectangle const& rRectangle,
+ SparklineValues const& rSparklineValues,
+ sc::SparklineAttributes const& rAttributes)
+ {
+ double nMax = rSparklineValues.mfMaximum;
+ if (rAttributes.getMaxAxisType() == sc::AxisType::Custom && rAttributes.getManualMax())
+ nMax = *rAttributes.getManualMax();
+
+ double nMin = rSparklineValues.mfMinimum;
+ if (rAttributes.getMinAxisType() == sc::AxisType::Custom && rAttributes.getManualMin())
+ nMin = *rAttributes.getManualMin();
+
+ std::vector<SparklineValue> const& rValueList = rSparklineValues.getValuesList();
+
+ basegfx::B2DPolygon aPolygon;
+ basegfx::B2DHomMatrix aMatrix;
+ aMatrix.translate(rRectangle.Left(), rRectangle.Top());
+
+ double xStep = 0;
+ double numberOfSteps = rValueList.size();
+ double nDelta = nMax - nMin;
+
+ double nColumnSize = rRectangle.GetWidth() / numberOfSteps;
+ nColumnSize = nColumnSize - (nColumnSize * 0.3);
+
+ double nZero = (0 - nMin) / nDelta;
+ double nZeroPosition = 0.0;
+ if (nZero >= 0)
+ {
+ nZeroPosition = rRectangle.GetHeight() - rRectangle.GetHeight() * nZero;
+
+ if (rAttributes.shouldDisplayXAxis())
+ {
+ double x1 = 0.0;
+ double x2 = double(rRectangle.GetWidth());
+
+ basegfx::B2DPolygon aAxisPolygon;
+ aAxisPolygon.append({ x1, nZeroPosition });
+ aAxisPolygon.append({ x2, nZeroPosition });
+
+ rRenderContext.SetLineColor(rAttributes.getColorAxis());
+ rRenderContext.DrawPolyLineDirect(aMatrix, aAxisPolygon, 0.2 * mfScaleX);
+ }
+ }
+ else
+ nZeroPosition = rRectangle.GetHeight();
+
+ size_t nValueIndex = 0;
+
+ for (auto const& rSparklineValue : rValueList)
+ {
+ double nValue = rSparklineValue.maValue;
+
+ if (nValue != 0.0)
+ {
+ setFillAndLineColor(rRenderContext, rAttributes, nValue, nValueIndex,
+ rSparklineValues);
+
+ double nP = (nValue - nMin) / nDelta;
+ double x = rRectangle.GetWidth() * (xStep / numberOfSteps);
+ double y = rRectangle.GetHeight() - rRectangle.GetHeight() * nP;
+
+ basegfx::B2DRectangle aRectangle(x, y, x + nColumnSize, nZeroPosition);
+ aPolygon = basegfx::utils::createPolygonFromRect(aRectangle);
+
+ aPolygon.transform(aMatrix);
+ rRenderContext.DrawPolygon(aPolygon);
+ }
+ xStep++;
+ nValueIndex++;
+ }
+ }
+
+ bool isCellHidden(ScAddress const& rAddress)
+ {
+ return mrDocument.RowHidden(rAddress.Row(), rAddress.Tab())
+ || mrDocument.ColHidden(rAddress.Col(), rAddress.Tab());
+ }
+
+public:
+ SparklineRenderer(ScDocument& rDocument)
+ : mrDocument(rDocument)
+ , mnOneX(1)
+ , mnOneY(1)
+ , mfScaleX(1.0)
+ , mfScaleY(1.0)
+ {
+ }
+
+ void render(std::shared_ptr<sc::Sparkline> const& pSparkline,
+ vcl::RenderContext& rRenderContext, tools::Rectangle const& rRectangle,
+ tools::Long nOneX, tools::Long nOneY, double fScaleX, double fScaleY)
+ {
+ rRenderContext.Push();
+ comphelper::ScopeGuard aPushPopGuard([&rRenderContext]() { rRenderContext.Pop(); });
+
+ rRenderContext.SetAntialiasing(AntialiasingFlags::Enable);
+ rRenderContext.SetClipRegion(vcl::Region(rRectangle));
+
+ tools::Rectangle aOutputRectangle(rRectangle);
+ aOutputRectangle.shrink(6); // provide border
+
+ mnOneX = nOneX;
+ mnOneY = nOneY;
+ mfScaleX = fScaleX;
+ mfScaleY = fScaleY;
+
+ auto const& rRangeList = pSparkline->getInputRange();
+
+ if (rRangeList.empty())
+ {
+ return;
+ }
+
+ auto pSparklineGroup = pSparkline->getSparklineGroup();
+ auto const& rAttributes = pSparklineGroup->getAttributes();
+
+ ScRange aRange = rRangeList[0];
+
+ SparklineValues aSparklineValues;
+
+ RangeTraverser aTraverser(aRange);
+ for (ScAddress const& rCurrent = aTraverser.first(); aTraverser.hasNext();
+ aTraverser.next())
+ {
+ // Skip if the cell is hidden and "displayHidden" attribute is not selected
+ if (!rAttributes.shouldDisplayHidden() && isCellHidden(rCurrent))
+ continue;
+
+ double fCellValue = 0.0;
+ SparklineValue::Action eAction = SparklineValue::Action::None;
+ CellType eType = mrDocument.GetCellType(rCurrent);
+
+ if (eType == CELLTYPE_NONE) // if cell is empty
+ {
+ auto eDisplayEmpty = rAttributes.getDisplayEmptyCellsAs();
+ if (eDisplayEmpty == sc::DisplayEmptyCellsAs::Gap)
+ eAction = SparklineValue::Action::Skip;
+ else if (eDisplayEmpty == sc::DisplayEmptyCellsAs::Span)
+ eAction = SparklineValue::Action::Interpolate;
+ }
+ else
+ {
+ fCellValue = mrDocument.GetValue(rCurrent);
+ }
+
+ aSparklineValues.add(fCellValue, eAction);
+ }
+
+ if (rAttributes.isRightToLeft())
+ aSparklineValues.reverse();
+
+ if (rAttributes.getType() == sc::SparklineType::Column)
+ {
+ drawColumn(rRenderContext, aOutputRectangle, aSparklineValues,
+ pSparklineGroup->getAttributes());
+ }
+ else if (rAttributes.getType() == sc::SparklineType::Stacked)
+ {
+ aSparklineValues.convertToStacked();
+ drawColumn(rRenderContext, aOutputRectangle, aSparklineValues,
+ pSparklineGroup->getAttributes());
+ }
+ else if (rAttributes.getType() == sc::SparklineType::Line)
+ {
+ drawLine(rRenderContext, aOutputRectangle, aSparklineValues,
+ pSparklineGroup->getAttributes());
+ }
+ }
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/SparklineShell.hxx b/sc/source/ui/inc/SparklineShell.hxx
new file mode 100644
index 000000000..912928d14
--- /dev/null
+++ b/sc/source/ui/inc/SparklineShell.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/.
+ *
+ */
+
+#pragma once
+
+#include <sfx2/shell.hxx>
+
+#include <shellids.hxx>
+
+class ScTabViewShell;
+class SfxModule;
+
+namespace sc
+{
+/** Shell to handle the sparkline context */
+class SparklineShell final : public SfxShell
+{
+public:
+ SFX_DECL_INTERFACE(SCID_SPARKLINE_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ SparklineShell(ScTabViewShell* pView);
+ virtual ~SparklineShell() override;
+
+private:
+ ScTabViewShell* m_pViewShell;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/StatisticsInputOutputDialog.hxx b/sc/source/ui/inc/StatisticsInputOutputDialog.hxx
new file mode 100644
index 000000000..2de05951b
--- /dev/null
+++ b/sc/source/ui/inc/StatisticsInputOutputDialog.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/.
+ *
+ */
+
+#pragma once
+
+#include <address.hxx>
+#include "anyrefdg.hxx"
+#include "viewdata.hxx"
+
+class ScStatisticsInputOutputDialog : public ScAnyRefDlgController
+{
+public:
+ enum GroupedBy {
+ BY_COLUMN,
+ BY_ROW
+ };
+
+ ScStatisticsInputOutputDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData,
+ const OUString& rUIXMLDescription,
+ const OString& rID);
+
+ virtual ~ScStatisticsInputOutputDialog() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+ virtual void SetActive() override;
+
+protected:
+ void CalculateInputAndWriteToOutput();
+
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) = 0;
+ virtual TranslateId GetUndoNameId() = 0;
+ virtual bool InputRangesValid();
+ void ValidateDialogInput();
+
+ // Widgets
+ std::unique_ptr<weld::Label> mxInputRangeLabel;
+ std::unique_ptr<formula::RefEdit> mxInputRangeEdit;
+ std::unique_ptr<formula::RefButton> mxInputRangeButton;
+
+ std::unique_ptr<weld::Label> mxOutputRangeLabel;
+ std::unique_ptr<formula::RefEdit> mxOutputRangeEdit;
+ std::unique_ptr<formula::RefButton> mxOutputRangeButton;
+
+ std::unique_ptr<weld::RadioButton> mxGroupByColumnsRadio;
+ std::unique_ptr<weld::RadioButton> mxGroupByRowsRadio;
+
+ // Data
+ ScViewData& mViewData;
+ ScDocument& mDocument;
+
+ ScRange mInputRange;
+ ScAddress::Details mAddressDetails;
+ ScAddress mOutputAddress;
+ GroupedBy mGroupedBy;
+
+ static ScRangeList MakeColumnRangeList(SCTAB aTab, ScAddress const & aStart, ScAddress const & aEnd);
+ static ScRangeList MakeRowRangeList(SCTAB aTab, ScAddress const & aStart, ScAddress const & aEnd);
+
+private:
+ // Widgets
+ std::unique_ptr<weld::Button> mxButtonOk;
+ std::unique_ptr<weld::Button> mxButtonCancel;
+
+ formula::RefEdit* mpActiveEdit;
+ ScAddress mCurrentAddress;
+ bool mDialogLostFocus;
+
+ void Init();
+ void GetRangeFromSelection();
+
+ DECL_LINK( GroupByChanged, weld::Toggleable&, void );
+ DECL_LINK( ButtonClicked, weld::Button&, void );
+ DECL_LINK( GetEditFocusHandler, formula::RefEdit&, void );
+ DECL_LINK( GetButtonFocusHandler, formula::RefButton&, void );
+ DECL_LINK( LoseEditFocusHandler, formula::RefEdit&, void );
+ DECL_LINK( LoseButtonFocusHandler, formula::RefButton&, void );
+ DECL_LINK( RefInputModifyHandler, formula::RefEdit&, void );
+};
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/StatisticsTwoVariableDialog.hxx b/sc/source/ui/inc/StatisticsTwoVariableDialog.hxx
new file mode 100644
index 000000000..3b1d5e467
--- /dev/null
+++ b/sc/source/ui/inc/StatisticsTwoVariableDialog.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 <address.hxx>
+#include "anyrefdg.hxx"
+#include "viewdata.hxx"
+
+class ScStatisticsTwoVariableDialog : public ScAnyRefDlgController
+{
+public:
+ enum GroupedBy {
+ BY_COLUMN,
+ BY_ROW
+ };
+
+ ScStatisticsTwoVariableDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData,
+ const OUString& rUIXMLDescription, const OString& rID);
+
+ virtual ~ScStatisticsTwoVariableDialog() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+ virtual void SetActive() override;
+
+protected:
+ void CalculateInputAndWriteToOutput();
+
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) = 0;
+ virtual TranslateId GetUndoNameId() = 0;
+ virtual bool InputRangesValid();
+ void ValidateDialogInput();
+
+ // Widgets
+ std::unique_ptr<weld::Label> mxVariable1RangeLabel;
+ std::unique_ptr<formula::RefEdit> mxVariable1RangeEdit;
+ std::unique_ptr<formula::RefButton> mxVariable1RangeButton;
+
+ std::unique_ptr<weld::Label> mxVariable2RangeLabel;
+ std::unique_ptr<formula::RefEdit> mxVariable2RangeEdit;
+ std::unique_ptr<formula::RefButton> mxVariable2RangeButton;
+
+ std::unique_ptr<weld::Label> mxOutputRangeLabel;
+ std::unique_ptr<formula::RefEdit> mxOutputRangeEdit;
+ std::unique_ptr<formula::RefButton> mxOutputRangeButton;
+
+ // Data
+ ScViewData& mViewData;
+ ScDocument& mDocument;
+
+ ScRange mVariable1Range;
+ ScRange mVariable2Range;
+
+ ScAddress::Details const mAddressDetails;
+ ScAddress mOutputAddress;
+ GroupedBy mGroupedBy;
+
+private:
+ // Widgets
+ std::unique_ptr<weld::Button> mxButtonOk;
+ std::unique_ptr<weld::Button> mxButtonCancel;
+
+ std::unique_ptr<weld::RadioButton> mxGroupByColumnsRadio;
+ std::unique_ptr<weld::RadioButton> mxGroupByRowsRadio;
+
+ formula::RefEdit* mpActiveEdit;
+ ScAddress mCurrentAddress;
+ bool mDialogLostFocus;
+
+ void Init();
+ void GetRangeFromSelection();
+
+ DECL_LINK( GroupByChanged, weld::Toggleable&, void );
+ DECL_LINK( ButtonClicked, weld::Button&, void );
+ DECL_LINK( GetEditFocusHandler, formula::RefEdit&, void );
+ DECL_LINK( GetButtonFocusHandler, formula::RefButton&, void );
+ DECL_LINK( LoseEditFocusHandler, formula::RefEdit&, void );
+ DECL_LINK( LoseButtonFocusHandler, formula::RefButton&, void );
+ DECL_LINK( RefInputModifyHandler, formula::RefEdit&, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/TTestDialog.hxx b/sc/source/ui/inc/TTestDialog.hxx
new file mode 100644
index 000000000..0ed370dce
--- /dev/null
+++ b/sc/source/ui/inc/TTestDialog.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/.
+ *
+ */
+
+#pragma once
+
+#include "StatisticsTwoVariableDialog.hxx"
+
+class ScTTestDialog : public ScStatisticsTwoVariableDialog
+{
+public:
+ ScTTestDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData );
+
+ virtual ~ScTTestDialog() override;
+
+ virtual void Close() override;
+
+protected:
+ virtual TranslateId GetUndoNameId() override;
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/TableFillingAndNavigationTools.hxx b/sc/source/ui/inc/TableFillingAndNavigationTools.hxx
new file mode 100644
index 000000000..454055911
--- /dev/null
+++ b/sc/source/ui/inc/TableFillingAndNavigationTools.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/.
+ *
+ */
+
+#pragma once
+
+#include <address.hxx>
+#include <rangelst.hxx>
+
+#include <map>
+#include <vector>
+
+class FormulaTemplate
+{
+private:
+ OUString mTemplate;
+ ScDocument* mpDoc;
+ bool mbUse3D;
+
+ typedef std::map<OUString, ScRange> RangeReplacementMap;
+ typedef std::map<OUString, ScAddress> AddressReplacementMap;
+
+ AddressReplacementMap mAddressReplacementMap;
+ RangeReplacementMap mRangeReplacementMap;
+
+public:
+ FormulaTemplate(ScDocument* pDoc);
+
+ void setTemplate(const OUString& aTemplate);
+ void setTemplate(const char* aTemplate);
+ const OUString& getTemplate();
+
+ void autoReplaceRange(const OUString& aVariable, const ScRange& rRange);
+ void autoReplaceAddress(const OUString& aVariable, ScAddress const & aAddress);
+ void autoReplaceUses3D(bool bUse3D) { mbUse3D = bUse3D; }
+
+ void applyRange(std::u16string_view aVariable, const ScRange& aRange, bool b3D = true);
+ void applyRangeList(std::u16string_view aVariable, const ScRangeList& aRangeList, sal_Unicode cDelimiter );
+ void applyAddress(std::u16string_view aVariable, const ScAddress& aAddress, bool b3D = true);
+ void applyString(std::u16string_view aVariable, std::u16string_view aValue);
+ void applyNumber(std::u16string_view aVariable, sal_Int32 aValue);
+};
+
+class AddressWalker
+{
+public:
+ std::vector<ScAddress> mAddressStack;
+
+ ScAddress mCurrentAddress;
+ ScAddress mMinimumAddress;
+ ScAddress mMaximumAddress;
+
+ AddressWalker(const ScAddress& aInitialAddress);
+
+ ScAddress current(SCCOL aRelativeCol = 0, SCROW aRelativeRow = 0, SCTAB aRelativeTab = 0);
+
+ void reset();
+ void resetColumn();
+ void resetRow();
+ void nextColumn();
+ void nextRow();
+ void newLine();
+ void push(SCCOL aRelativeCol = 0, SCROW aRelativeRow = 0, SCTAB aRelativeTab = 0);
+};
+
+class AddressWalkerWriter : public AddressWalker
+{
+public:
+ ScDocShell* mpDocShell;
+ ScDocument& mrDocument;
+ formula::FormulaGrammar::Grammar meGrammar;
+
+ AddressWalkerWriter(const ScAddress& aInitialAddress, ScDocShell* pDocShell, ScDocument& rDocument,
+ formula::FormulaGrammar::Grammar eGrammar );
+
+ void writeFormula(const OUString& aFormula);
+ void writeFormulas(const std::vector<OUString>& rFormulas);
+ void writeMatrixFormula(const OUString& aFormula, SCCOL nCols = 1, SCROW nRows = 1);
+ void writeString(const OUString& aString);
+ void writeString(const char* aCharArray);
+ void writeBoldString(const OUString& aString);
+ void writeValue(double aValue);
+};
+
+class DataCellIterator final
+{
+private:
+ ScRange mInputRange;
+ bool mByColumn;
+ SCCOL mCol;
+ SCROW mRow;
+
+public:
+ DataCellIterator(const ScRange& aInputRange, bool aByColumn);
+
+ bool hasNext() const;
+ ScAddress get();
+ void next();
+ ScAddress getRelative(int aDelta);
+};
+
+class DataRangeIterator
+{
+protected:
+ ScRange mInputRange;
+ sal_Int32 mIndex;
+
+public:
+ DataRangeIterator(const ScRange& aInputRange);
+ virtual ~DataRangeIterator();
+
+ virtual bool hasNext() = 0;
+ virtual ScRange get() = 0;
+ virtual size_t size() = 0;
+ virtual void next() = 0;
+ virtual void reset() = 0;
+
+ sal_Int32 index();
+
+ virtual DataCellIterator iterateCells() = 0;
+};
+
+class DataRangeByColumnIterator final : public DataRangeIterator
+{
+ SCCOL mCol;
+
+public:
+ DataRangeByColumnIterator(const ScRange& aInputRange);
+
+ virtual bool hasNext() override;
+ virtual void next() override;
+ virtual ScRange get() override;
+ virtual size_t size() override;
+ virtual void reset() override;
+ virtual DataCellIterator iterateCells() override;
+};
+
+class DataRangeByRowIterator final : public DataRangeIterator
+{
+ SCROW mRow;
+
+public:
+ DataRangeByRowIterator(const ScRange& aInputRange);
+
+ virtual bool hasNext() override;
+ virtual void next() override;
+ virtual ScRange get() override;
+ virtual size_t size() override;
+ virtual void reset() override;
+ virtual DataCellIterator iterateCells() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/ZTestDialog.hxx b/sc/source/ui/inc/ZTestDialog.hxx
new file mode 100644
index 000000000..2476c38f3
--- /dev/null
+++ b/sc/source/ui/inc/ZTestDialog.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/.
+ *
+ */
+
+#pragma once
+
+#include "StatisticsTwoVariableDialog.hxx"
+
+class ScZTestDialog : public ScStatisticsTwoVariableDialog
+{
+public:
+ ScZTestDialog(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, ScViewData& rViewData );
+
+ virtual ~ScZTestDialog() override;
+
+ virtual void Close() override;
+
+protected:
+ virtual TranslateId GetUndoNameId() override;
+ virtual ScRange ApplyOutput(ScDocShell* pDocShell) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/acredlin.hxx b/sc/source/ui/inc/acredlin.hxx
new file mode 100644
index 000000000..f939b9205
--- /dev/null
+++ b/sc/source/ui/inc/acredlin.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 <svx/ctredlin.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/bindings.hxx>
+#include <chgtrack.hxx>
+#include <chgviset.hxx>
+#include <vcl/idle.hxx>
+
+class ScViewData;
+class ScDocument;
+
+struct SfxChildWinInfo;
+
+class ScRedlinData : public RedlinData
+{
+public:
+ ScRedlinData();
+ virtual ~ScRedlinData() override;
+ sal_uLong nActionNo;
+ sal_uLong nInfo;
+ SCTAB nTable;
+ SCCOL nCol;
+ SCROW nRow;
+ bool bIsRejectable;
+ bool bIsAcceptable;
+};
+
+class ScAcceptChgDlg final : public SfxModelessDialogController
+{
+ Idle aSelectionIdle;
+ Idle aReOpenIdle;
+ ScViewData* pViewData;
+ ScDocument* pDoc;
+ ScRangeList aRangeList;
+ ScChangeViewSettings aChangeViewSet;
+ OUString aStrInsertCols;
+ OUString aStrInsertRows;
+ OUString aStrInsertTabs;
+ OUString aStrDeleteCols;
+ OUString aStrDeleteRows;
+ OUString aStrDeleteTabs;
+ OUString aStrMove;
+ OUString aStrContent;
+ OUString aStrReject;
+ OUString aStrAllAccepted;
+ OUString aStrAllRejected;
+ OUString aStrNoEntry;
+ OUString aStrContentWithChild;
+ OUString aStrChildContent;
+ OUString aStrChildOrgContent;
+ OUString aStrEmpty;
+ OUString aUnknown;
+ sal_uLong nAcceptCount;
+ sal_uLong nRejectCount;
+ bool bIgnoreMsg:1;
+ bool bNoSelection:1;
+ bool bHasFilterEntry:1;
+ bool bUseColor:1;
+
+ SvxTPFilter* pTPFilter;
+ SvxTPView* pTPView;
+ SvxRedlinTable* pTheView; // #i48648 now SvHeaderTabListBox
+
+ std::unique_ptr<weld::Container> m_xContentArea;
+ std::unique_ptr<weld::Menu> m_xPopup, m_xSortMenu;
+ std::unique_ptr<SvxAcceptChgCtr> m_xAcceptChgCtr;
+
+ void Init();
+
+ DECL_LINK( FilterHandle, SvxTPFilter*, void );
+ DECL_LINK( RefHandle, SvxTPFilter*, void );
+ DECL_LINK( RejectHandle, SvxTPView*, void );
+ DECL_LINK( AcceptHandle, SvxTPView*, void );
+ DECL_LINK( RejectAllHandle, SvxTPView*, void );
+ DECL_LINK( AcceptAllHandle, SvxTPView*, void );
+ DECL_LINK( ExpandingHandle, const weld::TreeIter&, bool );
+ DECL_LINK( SelectHandle, weld::TreeView&, void );
+ DECL_LINK( RefInfoHandle, const OUString*, void );
+
+ DECL_LINK( UpdateSelectionHdl, Timer*, void );
+ DECL_LINK( ChgTrackModHdl, ScChangeTrack&, void );
+ DECL_LINK( CommandHdl, const CommandEvent&, bool );
+ DECL_LINK( ReOpenTimerHdl, Timer*, void );
+
+ int ColCompareHdl(const weld::TreeIter& rLeft, const weld::TreeIter& rRight) const;
+
+ void RejectFiltered();
+ void AcceptFiltered();
+
+ bool IsValidAction(const ScChangeAction* pScChangeAction);
+
+ OUString* MakeTypeString(ScChangeActionType eType);
+
+ std::unique_ptr<weld::TreeIter> AppendChangeAction(
+ const ScChangeAction* pScChangeAction, bool bCreateOnDemand,
+ const weld::TreeIter* pParent = nullptr, bool bDelMaster = false,
+ bool bDisabled = false);
+
+ std::unique_ptr<weld::TreeIter> AppendFilteredAction(
+ const ScChangeAction* pScChangeAction,ScChangeActionState eState,
+ bool bCreateOnDemand,
+ const weld::TreeIter* pParent = nullptr, bool bDelMaster = false,
+ bool bDisabled = false);
+
+ std::unique_ptr<weld::TreeIter> InsertChangeActionContent(const ScChangeActionContent* pScChangeAction,
+ const weld::TreeIter& rParent, sal_uLong nSpecial);
+
+ void GetDependents(const ScChangeAction* pScChangeAction,
+ ScChangeActionMap& aActionMap,
+ const weld::TreeIter& rEntry);
+
+ bool InsertContentChildren(ScChangeActionMap* pActionMap, const weld::TreeIter& rParent);
+
+ bool InsertAcceptedORejected(const weld::TreeIter& rParent);
+
+ bool InsertDeletedChildren(const ScChangeAction* pChangeAction, ScChangeActionMap* pActionMap,
+ const weld::TreeIter& rParent);
+
+ bool InsertChildren(ScChangeActionMap* pActionMap, const weld::TreeIter& rParent);
+
+ void AppendChanges(const ScChangeTrack* pChanges,sal_uLong nStartAction, sal_uLong nEndAction);
+
+ void RemoveEntries(sal_uLong nStartAction,sal_uLong nEndAction);
+ void UpdateEntries(const ScChangeTrack* pChgTrack, sal_uLong nStartAction,sal_uLong nEndAction);
+
+ void UpdateView();
+ void ClearView();
+
+ bool Expand(const ScChangeTrack* pChanges,const ScChangeAction* pScChangeAction,
+ const weld::TreeIter& rEntry, bool bFilter = false);
+
+public:
+ ScAcceptChgDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScViewData* ptrViewData);
+ virtual ~ScAcceptChgDlg() override;
+
+ void ReInit(ScViewData* ptrViewData);
+
+ void Initialize (SfxChildWinInfo* pInfo);
+ virtual void FillInfo(SfxChildWinInfo&) const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/anyrefdg.hxx b/sc/source/ui/inc/anyrefdg.hxx
new file mode 100644
index 000000000..9109974a8
--- /dev/null
+++ b/sc/source/ui/inc/anyrefdg.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 <sfx2/basedlgs.hxx>
+#include <address.hxx>
+#include <formula/funcutl.hxx>
+#include "IAnyRefDialog.hxx"
+
+#include <memory>
+
+class SfxObjectShell;
+class ScDocument;
+class ScRangeList;
+class ScCompiler;
+
+class ScFormulaReferenceHelper
+{
+ IAnyRefDialog* m_pDlg;
+ ::std::unique_ptr<ScCompiler> m_pRefComp;
+ formula::RefEdit* m_pRefEdit; // active input field
+ formula::RefButton* m_pRefBtn; // associated button
+ weld::Dialog* m_pDialog;
+ SfxBindings* m_pBindings;
+ SCTAB m_nRefTab; // used for ShowReference
+
+ OUString m_sOldDialogText; // Original title of the dialog window
+
+ bool m_bEnableColorRef;
+ bool m_bHighlightRef;
+
+ DECL_LINK( ActivateHdl, weld::Widget&, bool );
+
+public:
+ ScFormulaReferenceHelper(IAnyRefDialog* _pDlg, SfxBindings* _pBindings);
+ ~ScFormulaReferenceHelper() COVERITY_NOEXCEPT_FALSE;
+ void dispose();
+
+ void ShowSimpleReference(std::u16string_view rStr);
+ void ShowFormulaReference(const OUString& rStr);
+ bool ParseWithNames( ScRangeList& rRanges, std::u16string_view rStr, const ScDocument& rDoc );
+ void Init();
+
+ void ShowReference(const OUString& rStr);
+ void ReleaseFocus( formula::RefEdit* pEdit );
+ void HideReference( bool bDoneRefMode = true );
+ void RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton );
+ void RefInputDone( bool bForced );
+ void ToggleCollapsed( formula::RefEdit* pEdit, formula::RefButton* pButton );
+
+ void SetDialog(weld::Dialog* pDialog) { m_pDialog = pDialog; }
+ void DoClose( sal_uInt16 nId );
+ void SetDispatcherLock( bool bLock );
+ static void EnableSpreadsheets( bool bFlag = true );
+ static void ViewShellChanged();
+
+ static void enableInput(bool _bInput);
+
+public:
+ static bool CanInputStart( const formula::RefEdit *pEdit ){ return !!pEdit; }
+ bool CanInputDone(bool bForced) const { return m_pRefEdit && (bForced || !m_pRefBtn); }
+};
+
+class ScRefHandler : public IAnyRefDialog
+{
+ weld::DialogController* m_pController;
+ bool m_bInRefMode;
+
+private:
+ ScFormulaReferenceHelper
+ m_aHelper;
+ SfxBindings* m_pMyBindings;
+
+ OUString m_aDocName; // document on which the dialog was opened
+
+protected:
+ void disposeRefHandler();
+ bool DoClose( sal_uInt16 nId );
+
+ void SetDispatcherLock( bool bLock );
+
+ virtual void RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton = nullptr ) override;
+ virtual void RefInputDone( bool bForced = false ) override;
+
+ bool ParseWithNames( ScRangeList& rRanges, std::u16string_view rStr, const ScDocument& pDoc );
+
+public:
+ ScRefHandler(SfxDialogController &rController, SfxBindings* pB, bool bBindRef);
+ virtual ~ScRefHandler() COVERITY_NOEXCEPT_FALSE override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override = 0;
+ virtual void AddRefEntry() override;
+
+ virtual bool IsRefInputMode() const override;
+ virtual bool IsTableLocked() const override;
+ virtual bool IsDocAllowed( SfxObjectShell* pDocSh ) const override;
+
+ virtual void ShowReference(const OUString& rStr) override;
+ virtual void HideReference( bool bDoneRefMode = true ) override;
+
+ virtual void ToggleCollapsed( formula::RefEdit* pEdit, formula::RefButton* pButton ) override;
+ virtual void ReleaseFocus( formula::RefEdit* pEdit ) override;
+
+ virtual void ViewShellChanged() override;
+ void SwitchToDocument();
+
+ virtual void SetActive() override = 0;
+
+public:
+ bool EnterRefMode();
+ bool LeaveRefMode();
+ static bool CanInputStart( const formula::RefEdit *pEdit )
+ {
+ return ScFormulaReferenceHelper::CanInputStart( pEdit );
+ }
+ bool CanInputDone( bool bForced )
+ {
+ return m_aHelper.CanInputDone( bForced );
+ }
+};
+
+template<class TBase, bool bBindRef = true>
+struct ScRefHdlrControllerImpl : public TBase, public ScRefHandler
+{
+ enum { UNKNOWN_SLOTID = 0U, SLOTID = UNKNOWN_SLOTID };
+
+ ScRefHdlrControllerImpl(weld::Window* pParent, const OUString& rUIXMLDescription, const OString& rID, const SfxItemSet* pArg, SfxBindings *pB)
+ : TBase(pParent, rUIXMLDescription, rID, pArg)
+ , ScRefHandler(*static_cast<TBase*>(this), pB, bBindRef)
+ {
+ }
+
+ ScRefHdlrControllerImpl(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, const OUString& rUIXMLDescription, const OString& rID)
+ : TBase(pB, pCW, pParent, rUIXMLDescription, rID)
+ , ScRefHandler(*static_cast<TBase*>(this), pB, bBindRef)
+ {
+ }
+};
+
+struct ScAnyRefDlgController : ScRefHdlrControllerImpl<SfxModelessDialogController>
+{
+ ScAnyRefDlgController(SfxBindings* rt1, SfxChildWindow* rt2, weld::Window* rt3, const OUString& rt4, const OString& rt5)
+ : ScRefHdlrControllerImpl<SfxModelessDialogController>(rt1, rt2, rt3, rt4, rt5)
+ {
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/areasave.hxx b/sc/source/ui/inc/areasave.hxx
new file mode 100644
index 000000000..0b317c6ee
--- /dev/null
+++ b/sc/source/ui/inc/areasave.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 <address.hxx>
+
+#include <memory>
+#include <vector>
+
+class ScDocument;
+class ScAreaLink;
+
+class ScAreaLinkSaver
+{
+private:
+ OUString aFileName;
+ OUString aFilterName;
+ OUString aOptions;
+ OUString aSourceArea;
+ ScRange aDestArea;
+ sal_Int32 nRefreshDelaySeconds;
+
+public:
+ ScAreaLinkSaver( const ScAreaLink& rSource );
+
+ bool IsEqual( const ScAreaLink& rCompare ) const;
+ bool IsEqualSource( const ScAreaLink& rCompare ) const;
+
+ void WriteToLink( ScAreaLink& rLink ) const;
+ void InsertNewLink( ScDocument* pDoc );
+};
+
+class ScAreaLinkSaveCollection
+{
+ typedef ::std::vector<ScAreaLinkSaver> DataType;
+ DataType maData;
+public:
+ ScAreaLinkSaveCollection();
+ ~ScAreaLinkSaveCollection();
+
+ bool IsEqual( const ScDocument* pDoc ) const;
+ void Restore( ScDocument* pDoc );
+
+ // returns NULL if empty
+ static std::unique_ptr<ScAreaLinkSaveCollection> CreateFromDoc( const ScDocument* pDoc );
+
+ ScAreaLinkSaver& operator[](size_t nIndex);
+ const ScAreaLinkSaver& operator[](size_t nIndex) const;
+ size_t size() const;
+ void push_back(const ScAreaLinkSaver&);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/areasdlg.hxx b/sc/source/ui/inc/areasdlg.hxx
new file mode 100644
index 000000000..be4d778d4
--- /dev/null
+++ b/sc/source/ui/inc/areasdlg.hxx
@@ -0,0 +1,88 @@
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <address.hxx>
+
+#include "anyrefdg.hxx"
+
+class ScDocument;
+class ScViewData;
+class SfxStringItem;
+
+class ScPrintAreasDlg : public ScAnyRefDlgController
+{
+public:
+ ScPrintAreasDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent);
+ virtual ~ScPrintAreasDlg() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+ virtual void AddRefEntry() override;
+
+ virtual bool IsTableLocked() const override;
+
+ virtual void SetActive() override;
+ virtual void Deactivate() override;
+ virtual void Close() override;
+
+private:
+ bool bDlgLostFocus;
+ ScDocument* pDoc;
+ ScViewData* pViewData;
+ SCTAB nCurTab;
+
+ formula::RefEdit* m_pRefInputEdit;
+
+ std::unique_ptr<weld::ComboBox> m_xLbPrintArea;
+ std::unique_ptr<formula::RefEdit> m_xEdPrintArea;
+ std::unique_ptr<formula::RefButton> m_xRbPrintArea;
+
+ std::unique_ptr<weld::ComboBox> m_xLbRepeatRow;
+ std::unique_ptr<formula::RefEdit> m_xEdRepeatRow;
+ std::unique_ptr<formula::RefButton> m_xRbRepeatRow;
+
+ std::unique_ptr<weld::ComboBox> m_xLbRepeatCol;
+ std::unique_ptr<formula::RefEdit> m_xEdRepeatCol;
+ std::unique_ptr<formula::RefButton> m_xRbRepeatCol;
+
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+ std::unique_ptr<weld::Frame> m_xPrintFrame;
+ std::unique_ptr<weld::Frame> m_xRowFrame;
+ std::unique_ptr<weld::Frame> m_xColFrame;
+
+ std::unique_ptr<weld::Label> m_xPrintFrameFT;
+ std::unique_ptr<weld::Label> m_xRowFrameFT;
+ std::unique_ptr<weld::Label> m_xColFrameFT;
+
+ void Impl_Reset();
+ bool Impl_CheckRefStrings();
+ void Impl_FillLists();
+ bool Impl_GetItem( const formula::RefEdit* pEd, SfxStringItem& rItem );
+
+ // Handler:
+ DECL_LINK( Impl_SelectHdl, weld::ComboBox&, void );
+ DECL_LINK( Impl_ModifyHdl, formula::RefEdit&, void );
+ DECL_LINK( Impl_BtnHdl, weld::Button&, void );
+ DECL_LINK( Impl_GetEditFocusHdl, formula::RefEdit&, void );
+ DECL_LINK( Impl_GetFocusHdl, weld::Widget&, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/asciiopt.hxx b/sc/source/ui/inc/asciiopt.hxx
new file mode 100644
index 000000000..c1b9c33d6
--- /dev/null
+++ b/sc/source/ui/inc/asciiopt.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 <rtl/ustring.hxx>
+#include <i18nlangtag/lang.h>
+
+#include "csvcontrol.hxx"
+
+class ScAsciiOptions
+{
+private:
+ bool bFixedLen;
+ OUString aFieldSeps;
+ bool bMergeFieldSeps;
+ bool bRemoveSpace;
+ bool bQuotedFieldAsText;
+ bool bDetectSpecialNumber;
+ bool bEvaluateFormulas;
+ bool bSkipEmptyCells;
+ bool bSaveAsShown;
+ bool bSaveFormulas;
+ sal_Unicode cTextSep;
+ rtl_TextEncoding eCharSet;
+ LanguageType eLang;
+ bool bCharSetSystem;
+ sal_Int32 nStartRow;
+ std::vector<sal_Int32> mvColStart;
+ std::vector<sal_uInt8> mvColFormat;
+
+public:
+ ScAsciiOptions();
+
+ static const sal_Unicode cDefaultTextSep = '"';
+
+ void ReadFromString( std::u16string_view rString );
+ OUString WriteToString() const;
+
+ rtl_TextEncoding GetCharSet() const { return eCharSet; }
+ const OUString& GetFieldSeps() const { return aFieldSeps; }
+ bool IsMergeSeps() const { return bMergeFieldSeps; }
+ bool IsRemoveSpace() const { return bRemoveSpace; }
+ bool IsQuotedAsText() const { return bQuotedFieldAsText; }
+ bool IsDetectSpecialNumber() const { return bDetectSpecialNumber; }
+ bool IsEvaluateFormulas() const { return bEvaluateFormulas; }
+ bool IsSkipEmptyCells() const { return bSkipEmptyCells; }
+ sal_Unicode GetTextSep() const { return cTextSep; }
+ bool IsFixedLen() const { return bFixedLen; }
+ sal_uInt16 GetInfoCount() const { return mvColStart.size(); }
+ const sal_Int32* GetColStart() const { return mvColStart.data(); }
+ const sal_uInt8* GetColFormat() const { return mvColFormat.data(); }
+ sal_Int32 GetStartRow() const { return nStartRow; }
+ LanguageType GetLanguage() const { return eLang; }
+
+ void SetCharSet( rtl_TextEncoding eNew ) { eCharSet = eNew; }
+ void SetCharSetSystem( bool bSet ) { bCharSetSystem = bSet; }
+ void SetFixedLen( bool bSet ) { bFixedLen = bSet; }
+ void SetFieldSeps( const OUString& rStr ) { aFieldSeps = rStr; }
+ void SetMergeSeps( bool bSet ) { bMergeFieldSeps = bSet; }
+ void SetRemoveSpace( bool bSet ) { bRemoveSpace = bSet; }
+ void SetQuotedAsText(bool bSet) { bQuotedFieldAsText = bSet; }
+ void SetDetectSpecialNumber(bool bSet) { bDetectSpecialNumber = bSet; }
+ void SetEvaluateFormulas(bool bSet) { bEvaluateFormulas = bSet; }
+ void SetSkipEmptyCells(bool bSet) { bSkipEmptyCells = bSet; }
+ void SetTextSep( sal_Unicode c ) { cTextSep = c; }
+ void SetStartRow( sal_Int32 nRow) { nStartRow= nRow; }
+ void SetLanguage(LanguageType e) { eLang = e; }
+
+ void SetColumnInfo( const ScCsvExpDataVec& rDataVec );
+
+ /** From the import field separators obtain the one most likely to be used
+ for export, if multiple separators weighted comma, tab, semicolon,
+ space and other.
+
+ @param bDecodeNumbers
+ If TRUE, the separators are encoded as numbers and need to be
+ decoded before characters can be extracted, for example "59/44"
+ to ";,".
+ If FALSE, the string is taken as is and each character is
+ expected to be one separator.
+ */
+ static sal_Unicode GetWeightedFieldSep( const OUString & rFieldSeps, bool bDecodeNumbers );
+};
+
+/// How ScImportAsciiDlg is called
+enum ScImportAsciiCall {
+ SC_IMPORTFILE, // with File > Open: Text - CSV
+ SC_PASTETEXT, // with Paste > Unformatted Text
+ SC_TEXTTOCOLUMNS }; // with Data > Text to Columns
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/attrdlg.hxx b/sc/source/ui/inc/attrdlg.hxx
new file mode 100644
index 000000000..67b9aa25a
--- /dev/null
+++ b/sc/source/ui/inc/attrdlg.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/tabdlg.hxx>
+
+namespace weld
+{
+class Window;
+}
+class SfxItemSet;
+
+class ScAttrDlg : public SfxTabDialogController
+{
+public:
+ ScAttrDlg(weld::Window* pParent, const SfxItemSet* pCellAttrs);
+ virtual ~ScAttrDlg() override;
+
+protected:
+ virtual void PageCreated(const OString& rPageId, SfxTabPage& rTabPage) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/auditsh.hxx b/sc/source/ui/inc/auditsh.hxx
new file mode 100644
index 000000000..74a17ccca
--- /dev/null
+++ b/sc/source/ui/inc/auditsh.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 <sfx2/shell.hxx>
+
+#include <shellids.hxx>
+
+class ScViewData;
+
+class ScAuditingShell : public SfxShell
+{
+private:
+ ScViewData& rViewData;
+ sal_uInt16 nFunction;
+
+public:
+ SFX_DECL_INTERFACE(SCID_AUDITING_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScAuditingShell(ScViewData& rData);
+ virtual ~ScAuditingShell() override;
+
+ void Execute(const SfxRequest& rReq);
+ void GetState(SfxItemSet& rSet);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/autofmt.hxx b/sc/source/ui/inc/autofmt.hxx
new file mode 100644
index 000000000..b0bc8b61b
--- /dev/null
+++ b/sc/source/ui/inc/autofmt.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 <svx/framelinkarray.hxx>
+#include <scdllapi.h>
+#include <vcl/customweld.hxx>
+
+namespace com::sun::star::i18n { class XBreakIterator; }
+
+class ScAutoFormatData;
+class SvxBoxItem;
+class SvxLineItem;
+class SvNumberFormatter;
+class VirtualDevice;
+class ScViewData;
+
+class SC_DLLPUBLIC ScAutoFmtPreview : public weld::CustomWidgetController
+{
+public:
+ ScAutoFmtPreview();
+ void DetectRTL(const ScViewData& rViewData);
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ virtual ~ScAutoFmtPreview() override;
+
+ void NotifyChange( ScAutoFormatData* pNewData );
+
+protected:
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+ virtual void Resize() override;
+
+private:
+ ScAutoFormatData* pCurData;
+ ScopedVclPtrInstance<VirtualDevice> aVD;
+ css::uno::Reference<css::i18n::XBreakIterator> xBreakIter;
+ bool bFitWidth;
+ svx::frame::Array maArray; /// Implementation to draw the frame borders.
+ bool mbRTL;
+ Size aPrvSize;
+ tools::Long mnLabelColWidth;
+ tools::Long mnDataColWidth1;
+ tools::Long mnDataColWidth2;
+ tools::Long mnRowHeight;
+ const OUString aStrJan;
+ const OUString aStrFeb;
+ const OUString aStrMar;
+ const OUString aStrNorth;
+ const OUString aStrMid;
+ const OUString aStrSouth;
+ const OUString aStrSum;
+ std::unique_ptr<SvNumberFormatter> pNumFmt;
+
+ SAL_DLLPRIVATE void Init();
+ SAL_DLLPRIVATE void DoPaint(vcl::RenderContext& rRenderContext);
+ SAL_DLLPRIVATE void CalcCellArray(bool bFitWidth);
+ SAL_DLLPRIVATE void CalcLineMap();
+ SAL_DLLPRIVATE void PaintCells(vcl::RenderContext& rRenderContext);
+
+/* Usage of type size_t instead of SCCOL/SCROW is correct here - used in
+ conjunction with class svx::frame::Array (svx/framelinkarray.hxx), which
+ expects size_t coordinates. */
+
+ SAL_DLLPRIVATE sal_uInt16 GetFormatIndex( size_t nCol, size_t nRow ) const;
+ SAL_DLLPRIVATE const SvxBoxItem& GetBoxItem( size_t nCol, size_t nRow ) const;
+ SAL_DLLPRIVATE const SvxLineItem& GetDiagItem( size_t nCol, size_t nRow, bool bTLBR ) const;
+
+ SAL_DLLPRIVATE void DrawString(vcl::RenderContext& rRenderContext, size_t nCol, size_t nRow);
+ SAL_DLLPRIVATE void DrawBackground(vcl::RenderContext& rRenderContext);
+
+ SAL_DLLPRIVATE void MakeFonts(vcl::RenderContext const& rRenderContext, sal_uInt16 nIndex,
+ vcl::Font& rFont, vcl::Font& rCJKFont, vcl::Font& rCTLFont);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/autostyl.hxx b/sc/source/ui/inc/autostyl.hxx
new file mode 100644
index 000000000..a0c0cd9eb
--- /dev/null
+++ b/sc/source/ui/inc/autostyl.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 <address.hxx>
+#include <vector>
+#include <rtl/ustring.hxx>
+#include <tools/solar.h>
+#include <vcl/timer.hxx>
+#include <vcl/idle.hxx>
+
+class ScDocShell;
+class ScRange;
+
+struct ScAutoStyleData
+{
+ sal_uLong nTimeout;
+ ScRange aRange;
+ OUString aStyle;
+
+ ScAutoStyleData( sal_uLong nT, const ScRange& rR, const OUString& rT ) :
+ nTimeout(nT), aRange(rR), aStyle(rT) {}
+};
+struct ScAutoStyleInitData
+{
+ ScRange aRange;
+ OUString aStyle1;
+ sal_uLong nTimeout;
+ OUString aStyle2;
+
+ ScAutoStyleInitData( const ScRange& rR, const OUString& rSt1, sal_uLong nT, const OUString& rSt2 ) :
+ aRange(rR), aStyle1(rSt1), nTimeout(nT), aStyle2(rSt2) {}
+};
+
+
+class ScAutoStyleList
+{
+private:
+
+ ScDocShell* pDocSh;
+ Timer aTimer;
+ Idle aInitIdle;
+ sal_uLong nTimerStart;
+ std::vector<ScAutoStyleData> aEntries;
+ std::vector<ScAutoStyleInitData> aInitials;
+
+ void ExecuteEntries();
+ void AdjustEntries(sal_uLong nDiff);
+ void StartTimer(sal_uLong nNow);
+ DECL_LINK( TimerHdl, Timer*, void );
+ DECL_LINK( InitHdl, Timer*, void );
+
+public:
+ ScAutoStyleList(ScDocShell* pShell);
+ ~ScAutoStyleList();
+
+ void AddInitial( const ScRange& rRange, const OUString& rStyle1,
+ sal_uLong nTimeout, const OUString& rStyle2 );
+ void AddEntry( sal_uLong nTimeout, const ScRange& rRange, const OUString& rStyle );
+
+ void ExecuteAllNow();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/cbnumberformat.hxx b/sc/source/ui/inc/cbnumberformat.hxx
new file mode 100644
index 000000000..5f2920ab4
--- /dev/null
+++ b/sc/source/ui/inc/cbnumberformat.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/InterimItemWindow.hxx>
+
+class ScNumberFormat final : public InterimItemWindow
+{
+public:
+ explicit ScNumberFormat(vcl::Window* pParent);
+ virtual void dispose() override;
+ virtual ~ScNumberFormat() override;
+
+ virtual void GetFocus() override;
+
+ void set_active(int nPos) { m_xWidget->set_active(nPos); }
+
+private:
+ std::unique_ptr<weld::ComboBox> m_xWidget;
+
+ DECL_STATIC_LINK(ScNumberFormat, NumFormatSelectHdl, weld::ComboBox&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/cbutton.hxx b/sc/source/ui/inc/cbutton.hxx
new file mode 100644
index 000000000..5b22c1a83
--- /dev/null
+++ b/sc/source/ui/inc/cbutton.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 <tools/gen.hxx>
+#include <vcl/vclptr.hxx>
+
+class OutputDevice;
+
+class ScDDComboBoxButton final
+{
+public:
+ ScDDComboBoxButton( OutputDevice* pOutputDevice );
+ ~ScDDComboBoxButton();
+
+ void SetOutputDevice( OutputDevice* pOutputDevice );
+
+ void Draw( const Point& rAt,
+ const Size& rSize );
+ void Draw()
+ { Draw( aBtnPos, aBtnSize ); }
+
+ void SetOptSizePixel();
+
+ void SetPosPixel( const Point& rNewPos ) { aBtnPos = rNewPos; }
+ const Point& GetPosPixel() const { return aBtnPos; }
+
+ void SetSizePixel( const Size& rNewSize ) { aBtnSize = rNewSize; }
+ const Size& GetSizePixel() const { return aBtnSize; }
+
+private:
+ void ImpDrawArrow( const tools::Rectangle& rRect );
+
+ VclPtr<OutputDevice> pOut;
+ Point aBtnPos;
+ Size aBtnSize;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/cellmergeoption.hxx b/sc/source/ui/inc/cellmergeoption.hxx
new file mode 100644
index 000000000..600a5e03d
--- /dev/null
+++ b/sc/source/ui/inc/cellmergeoption.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <address.hxx>
+
+#include <set>
+
+struct ScCellMergeOption
+{
+ ::std::set<SCTAB> maTabs;
+ SCCOL mnStartCol;
+ SCROW mnStartRow;
+ SCCOL mnEndCol;
+ SCROW mnEndRow;
+ bool mbCenter;
+
+ explicit ScCellMergeOption(const ScRange& rRange);
+ SC_DLLPUBLIC explicit ScCellMergeOption(SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow,
+ bool bCenter = false);
+
+ ScRange getSingleRange(SCTAB nTab) const;
+ ScRange getFirstSingleRange() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/cellsh.hxx b/sc/source/ui/inc/cellsh.hxx
new file mode 100644
index 000000000..023d51608
--- /dev/null
+++ b/sc/source/ui/inc/cellsh.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 <sfx2/shell.hxx>
+#include <shellids.hxx>
+#include <unotools/caserotate.hxx>
+#include <tools/link.hxx>
+#include <memory>
+#include "formatsh.hxx"
+#include <rtl/ref.hxx>
+#include <sot/formats.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/window.hxx>
+
+class SvxClipboardFormatItem;
+class TransferableDataHelper;
+class TransferableClipboardListener;
+class AbstractScLinkedAreaDlg;
+
+struct CellShell_Impl
+{
+ rtl::Reference<TransferableClipboardListener>
+ m_xClipEvtLstnr;
+ VclPtr<AbstractScLinkedAreaDlg> m_pLinkedDlg;
+ SfxRequest* m_pRequest;
+
+ CellShell_Impl();
+ ~CellShell_Impl();
+};
+
+class ScCellShell final : public ScFormatShell
+{
+private:
+ std::unique_ptr<CellShell_Impl> pImpl;
+ bool bPastePossible;
+
+ void GetPossibleClipboardFormats( SvxClipboardFormatItem& rFormats );
+ bool HasClipboardFormat( SotClipboardFormatId nFormatId );
+ void ExecuteExternalSource(
+ const OUString& _rFile, const OUString& _rFilter, const OUString& _rOptions,
+ const OUString& _rSource, sal_Int32 _nRefreshDelaySeconds, SfxRequest& _rRequest );
+
+ void ExecuteDataPilotDialog();
+ void ExecuteXMLSourceDialog();
+ void ExecuteSubtotals(SfxRequest& rReq);
+
+ void ExecuteFillSingleEdit();
+
+ DECL_LINK( ClipboardChanged, TransferableDataHelper*, void );
+
+ RotateTransliteration m_aRotateCase;
+
+ VclPtr<vcl::Window> pFrameWin;
+
+public:
+ SFX_DECL_INTERFACE(SCID_CELL_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScCellShell( ScViewData& rData, const VclPtr<vcl::Window>& pFrameWin );
+ virtual ~ScCellShell() override;
+
+ void Execute(SfxRequest &);
+ void GetState(SfxItemSet &);
+
+ void ExecuteEdit( SfxRequest& rReq );
+ void ExecuteTrans( SfxRequest& rReq );
+ void ExecuteRotateTrans( const SfxRequest& rReq );
+
+ void GetBlockState( SfxItemSet& rSet );
+ void GetCellState( SfxItemSet& rSet );
+
+ void ExecuteDB( SfxRequest& rReq );
+ void GetDBState( SfxItemSet& rSet );
+
+ void GetClipState( SfxItemSet& rSet );
+ void GetHLinkState( SfxItemSet& rSet );
+
+ void ExecuteCursor( SfxRequest& rReq );
+ void ExecuteCursorSel( SfxRequest& rReq );
+ void ExecutePage( SfxRequest& rReq );
+ void ExecutePageSel( SfxRequest& rReq );
+ void ExecuteMove( SfxRequest& rReq );
+
+ static void GetStateCursor( SfxItemSet& rSet );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/chartsh.hxx b/sc/source/ui/inc/chartsh.hxx
new file mode 100644
index 000000000..9eee30a1a
--- /dev/null
+++ b/sc/source/ui/inc/chartsh.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/shell.hxx>
+#include <shellids.hxx>
+#include "drawsh.hxx"
+
+class ScViewData;
+
+class ScChartShell final : public ScDrawShell
+{
+public:
+ SFX_DECL_INTERFACE(SCID_CHART_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+ virtual void Activate(bool bMDI) override;
+ virtual void Deactivate(bool bMDI) override;
+
+public:
+ ScChartShell(ScViewData& rData);
+ virtual ~ScChartShell() override;
+
+ void ExecuteExportAsGraphic(SfxRequest& rReq);
+ void GetExportAsGraphicState(SfxItemSet& rSet);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/checklistmenu.hxx b/sc/source/ui/inc/checklistmenu.hxx
new file mode 100644
index 000000000..5585bc3e8
--- /dev/null
+++ b/sc/source/ui/inc/checklistmenu.hxx
@@ -0,0 +1,381 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <vcl/virdev.hxx>
+#include <vcl/weld.hxx>
+
+#include <memory>
+#include <unordered_set>
+#include <map>
+#include <set>
+
+class ScCheckListMenuControl;
+class ScViewData;
+struct ScCheckListMember;
+struct ImplSVEvent;
+
+struct ScCheckListMember
+{
+ enum DatePartType
+ {
+ YEAR,
+ MONTH,
+ DAY,
+ };
+
+ OUString maName; // node name
+ OUString maRealName;
+ double mnValue; // number value of filter condition
+ bool mbVisible;
+ bool mbDate;
+ bool mbLeaf;
+ bool mbValue; // true if the filter condition is value
+ DatePartType meDatePartType;
+ // To store Year and Month if the member if DAY type
+ std::vector<OUString> maDateParts;
+ ScCheckListMember();
+ std::unique_ptr<weld::TreeIter> mxParent;
+};
+
+class ScCheckListMenuWindow;
+class ScListSubMenuControl;
+
+/**
+ * This class implements a popup window for the auto filter dropdown.
+ */
+class ScCheckListMenuControl final
+{
+public:
+ static constexpr size_t MENU_NOT_SELECTED = 999;
+
+ /**
+ * Action to perform when an event takes place. Create a sub-class of
+ * this to implement the desired action.
+ */
+ class Action
+ {
+ public:
+ virtual ~Action() {}
+ // return true to dismiss the popup
+ virtual bool execute() = 0;
+ };
+
+ struct ResultEntry
+ {
+ OUString aName;
+ double nValue; // number value of filter condition
+ bool bValid;
+ bool bDate;
+ bool bValue; // true if the filter condition is value
+
+ bool operator<(const ResultEntry& rhs) const
+ {
+ return aName < rhs.aName;
+ }
+
+ bool operator == (const ResultEntry& rhs) const
+ {
+ return aName == rhs.aName &&
+ bValid == rhs.bValid &&
+ bDate == rhs.bDate &&
+ bValue == rhs.bValue &&
+ nValue == rhs.nValue;
+ }
+ };
+ typedef std::set<ResultEntry> ResultType;
+
+ struct MenuItemData
+ {
+ bool mbEnabled:1;
+ std::shared_ptr<Action> mxAction;
+ std::unique_ptr<ScListSubMenuControl> mxSubMenuWin;
+
+ MenuItemData();
+ };
+
+ /**
+ * Extended data that the client code may need to store. Create a
+ * sub-class of this and store data there.
+ */
+ struct ExtendedData {
+
+ virtual ~ExtendedData() {}
+
+ };
+
+ /**
+ * Configuration options for this popup window.
+ */
+ struct Config
+ {
+ bool mbAllowEmptySet;
+ bool mbRTL;
+ Config();
+ };
+
+ ScCheckListMenuControl(weld::Widget* pParent, ScViewData& rViewData,
+ bool bTreeMode, int nWidth);
+ ~ScCheckListMenuControl();
+
+ void addMenuItem(const OUString& rText, Action* pAction);
+ void addSeparator();
+ ScListSubMenuControl* addSubMenuItem(const OUString& rText, bool bEnabled, bool bColorMenu);
+
+ void selectMenuItem(size_t nPos, bool bSubMenuTimer);
+ void queueLaunchSubMenu(size_t nPos, ScListSubMenuControl* pMenu);
+
+ void setMemberSize(size_t n);
+ void addDateMember(const OUString& rName, double nVal, bool bVisible);
+ void addMember(const OUString& rName, const double nVal, bool bVisible,
+ bool bValue = false);
+ size_t initMembers(int nMaxMemberWidth = -1);
+ void setConfig(const Config& rConfig);
+
+ bool isAllSelected() const;
+ void getResult(ResultType& rResult);
+ void launch(weld::Widget* pWidget, const tools::Rectangle& rRect);
+ void close(bool bOK);
+
+ void StartPopupMode(weld::Widget* pParent, const tools::Rectangle& rRect);
+ void EndPopupMode();
+
+ size_t getSubMenuPos(const ScListSubMenuControl* pSubMenu);
+ void setSubMenuFocused(const ScListSubMenuControl* pSubMenu);
+ void queueCloseSubMenu();
+ void clearSelectedMenuItem();
+
+ /**
+ * Set auxiliary data that the client code might need. Note that this
+ * popup window class manages its life time; no explicit deletion of the
+ * instance is needed in the client code.
+ */
+ void setExtendedData(std::unique_ptr<ExtendedData> p);
+
+ /**
+ * Get the store auxiliary data, or NULL if no such data is stored.
+ */
+ ExtendedData* getExtendedData();
+
+ ScViewData& GetViewData() const { return mrViewData; }
+
+ void GrabFocus();
+
+ void setOKAction(Action* p);
+ void setPopupEndAction(Action* p);
+
+ int GetTextWidth(const OUString& rsName) const;
+ int IncreaseWindowWidthToFitText(int nMaxTextWidth);
+
+ /**
+ * Dismiss all visible popup menus and set focus back to the application
+ * window. This method is called e.g. when a menu action is fired.
+ */
+ void terminateAllPopupMenus();
+
+ void endSubMenu(ScListSubMenuControl& rSubMenu);
+private:
+
+ std::vector<MenuItemData> maMenuItems;
+
+ /**
+ * Calculate the appropriate window size based on the menu items.
+ */
+ void prepWindow();
+ void setAllMemberState(bool bSet);
+ void selectCurrentMemberOnly(bool bSet);
+ void updateMemberParents(const weld::TreeIter* pLeaf, size_t nIdx);
+
+ std::unique_ptr<weld::TreeIter> ShowCheckEntry(const OUString& sName, ScCheckListMember& rMember, bool bShow = true, bool bCheck = true);
+ void CheckEntry(std::u16string_view sName, const weld::TreeIter* pParent, bool bCheck);
+ void CheckEntry(const weld::TreeIter& rEntry, bool bCheck);
+ void GetRecursiveChecked(const weld::TreeIter* pEntry, std::unordered_set<OUString>& vOut, OUString& rLabel);
+ std::unordered_set<OUString> GetAllChecked();
+ bool IsChecked(std::u16string_view sName, const weld::TreeIter* pParent);
+ int GetCheckedEntryCount() const;
+ void CheckAllChildren(const weld::TreeIter& rEntry, bool bCheck);
+
+ void setSelectedMenuItem(size_t nPos);
+
+ std::unique_ptr<weld::TreeIter> FindEntry(const weld::TreeIter* pParent, std::u16string_view sNode);
+
+ void executeMenuItem(size_t nPos);
+
+ /**
+ * Get the area of the active row. Suitable as the parent rectangle
+ * argument for Executing a popup
+ */
+ tools::Rectangle GetSubMenuParentRect();
+
+ struct SubMenuItemData;
+
+ void handleMenuTimeout(const SubMenuItemData* pTimer);
+
+ void launchSubMenu();
+
+ void CreateDropDown();
+
+ DECL_LINK(ButtonHdl, weld::Button&, void);
+ DECL_LINK(TriStateHdl, weld::Toggleable&, void);
+
+ void Check(const weld::TreeIter* pIter);
+
+ DECL_LINK(CheckHdl, const weld::TreeView::iter_col&, void);
+
+ DECL_LINK(PopupModeEndHdl, weld::Popover&, void);
+
+ DECL_LINK(EdModifyHdl, weld::Entry&, void);
+ DECL_LINK(EdActivateHdl, weld::Entry&, bool);
+
+ DECL_LINK(RowActivatedHdl, weld::TreeView& rMEvt, bool);
+ DECL_LINK(SelectHdl, weld::TreeView&, void);
+ DECL_LINK(TreeSizeAllocHdl, const Size&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(MenuKeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(MouseEnterHdl, const MouseEvent&, bool);
+
+ DECL_LINK(PostPopdownHdl, void*, void);
+
+ void SetDropdownPos();
+
+ DECL_LINK(SetDropdownPosHdl, void*, void);
+
+ DECL_LINK(CommandHdl, const CommandEvent&, bool);
+
+ void ResizeToRequest();
+
+ void DropPendingEvents();
+
+private:
+ std::unique_ptr<weld::Builder> mxBuilder;
+ std::unique_ptr<weld::Popover> mxPopover;
+ std::unique_ptr<weld::Container> mxContainer;
+ std::unique_ptr<weld::TreeView> mxMenu;
+ std::unique_ptr<weld::TreeIter> mxScratchIter;
+ std::unique_ptr<weld::Widget> mxNonMenu;
+ std::unique_ptr<weld::Entry> mxEdSearch;
+ std::unique_ptr<weld::Widget> mxBox;
+ std::unique_ptr<weld::TreeView> mxListChecks;
+ std::unique_ptr<weld::TreeView> mxTreeChecks;
+ weld::TreeView* mpChecks;
+
+ std::unique_ptr<weld::CheckButton> mxChkToggleAll;
+ std::unique_ptr<weld::Button> mxBtnSelectSingle;
+ std::unique_ptr<weld::Button> mxBtnUnselectSingle;
+
+ std::unique_ptr<weld::Box> mxButtonBox;
+ std::unique_ptr<weld::Button> mxBtnOk;
+ std::unique_ptr<weld::Button> mxBtnCancel;
+ std::unique_ptr<weld::Menu> mxContextMenu;
+
+ ScopedVclPtr<VirtualDevice> mxDropDown;
+
+ std::vector<ScCheckListMember> maMembers;
+ // For Dates
+ std::map<OUString, size_t> maYearMonthMap;
+
+ std::unique_ptr<ExtendedData> mxExtendedData;
+ std::unique_ptr<Action> mxOKAction;
+ std::unique_ptr<Action> mxPopupEndAction;
+
+ Config maConfig;
+ Size maAllocatedSize;
+ int mnCheckWidthReq; /// matching width request for mxChecks
+ int mnWndWidth; /// whole window width.
+ int mnCheckListVisibleRows;
+ TriState mePrevToggleAllState;
+
+ size_t mnSelectedMenu;
+
+ ScViewData& mrViewData;
+
+ ImplSVEvent* mnAsyncPostPopdownId;
+ ImplSVEvent* mnAsyncSetDropdownPosId;
+
+ bool mbHasDates;
+ bool mbIsPoppedUp;
+
+ struct SubMenuItemData
+ {
+ Timer maTimer;
+ ScListSubMenuControl* mpSubMenu;
+ size_t mnMenuPos;
+
+ DECL_LINK( TimeoutHdl, Timer*, void );
+
+ SubMenuItemData(ScCheckListMenuControl* pParent);
+ void reset();
+
+ private:
+ ScCheckListMenuControl* mpParent;
+ };
+
+ SubMenuItemData maOpenTimer;
+ SubMenuItemData maCloseTimer;
+};
+
+class ScListSubMenuControl final
+{
+public:
+ ScListSubMenuControl(weld::Widget* pParent, ScCheckListMenuControl& rParentControl, bool bColorMenu);
+
+ void setPopupStartAction(ScCheckListMenuControl::Action* p);
+
+ void GrabFocus();
+ bool IsVisible() const;
+
+ void StartPopupMode(weld::Widget* pParent, const tools::Rectangle& rRect);
+ void EndPopupMode();
+
+ void addMenuItem(const OUString& rText, ScCheckListMenuControl::Action* pAction);
+ // nMenu of 0 for background color, nMenu of 1 for text color
+ void addMenuColorItem(const OUString& rText, bool bActive, VirtualDevice& rImage,
+ int nMenu, ScCheckListMenuControl::Action* pAction);
+ void addSeparator();
+ void clearMenuItems();
+ void resizeToFitMenuItems();
+
+ ScViewData& GetViewData() const { return mrParentControl.GetViewData(); }
+ ScCheckListMenuControl::ExtendedData* getExtendedData() { return mrParentControl.getExtendedData(); }
+ VclPtr<VirtualDevice> create_virtual_device() const { return mxMenu->create_virtual_device(); }
+
+ /**
+ * Dismiss all visible popup menus and set focus back to the application
+ * window. This method is called e.g. when a menu action is fired.
+ */
+ void terminateAllPopupMenus();
+
+private:
+ std::unique_ptr<weld::Builder> mxBuilder;
+ std::unique_ptr<weld::Popover> mxPopover;
+ std::unique_ptr<weld::Container> mxContainer;
+ std::unique_ptr<weld::TreeView> mxMenu;
+ std::unique_ptr<weld::TreeView> mxBackColorMenu;
+ std::unique_ptr<weld::TreeView> mxTextColorMenu;
+ std::unique_ptr<weld::TreeIter> mxScratchIter;
+ std::unique_ptr<ScCheckListMenuControl::Action> mxPopupStartAction;
+ std::vector<ScCheckListMenuControl::MenuItemData> maMenuItems;
+ ScCheckListMenuControl& mrParentControl;
+ int mnBackColorMenuPrefHeight;
+ int mnTextColorMenuPrefHeight;
+ bool mbColorMenu;
+
+ DECL_LINK(RowActivatedHdl, weld::TreeView& rMEvt, bool);
+ DECL_LINK(ColorSelChangedHdl, weld::TreeView&, void);
+ DECL_LINK(MenuKeyInputHdl, const KeyEvent&, bool);
+
+ void SetupMenu(weld::TreeView& rMenu);
+
+ void executeMenuItem(ScCheckListMenuControl::Action* pAction);
+ void addItem(ScCheckListMenuControl::Action* pAction);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/client.hxx b/sc/source/ui/inc/client.hxx
new file mode 100644
index 000000000..bff5079d1
--- /dev/null
+++ b/sc/source/ui/inc/client.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 <sfx2/ipclient.hxx>
+
+class ScTabViewShell;
+class SdrOle2Obj;
+class SdrModel;
+
+class ScClient final : public SfxInPlaceClient
+{
+private:
+ SdrModel* pModel;
+
+ virtual void ObjectAreaChanged() override;
+ virtual void RequestNewObjectArea( tools::Rectangle& ) override;
+ virtual void ViewChanged() override;
+
+public:
+ ScClient( ScTabViewShell* pViewShell, vcl::Window* pDraw, SdrModel* pSdrModel, const SdrOle2Obj* pObj );
+ virtual ~ScClient() override;
+
+ SdrOle2Obj* GetDrawObj();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/cliputil.hxx b/sc/source/ui/inc/cliputil.hxx
new file mode 100644
index 000000000..dc0ee5b9b
--- /dev/null
+++ b/sc/source/ui/inc/cliputil.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/.
+ */
+
+#pragma once
+
+#include <types.hxx>
+#include <scdllapi.h>
+
+class ScViewData;
+class ScTabViewShell;
+class ScDocument;
+class ScMarkData;
+class ScRangeList;
+
+namespace ScClipUtil
+{
+
+SC_DLLPUBLIC void PasteFromClipboard( ScViewData& rViewData, ScTabViewShell* pTabViewShell, bool bShowDialog );
+
+bool CheckDestRanges(
+ const ScDocument& rDoc, SCCOL nSrcCols, SCROW nSrcRows, const ScMarkData& rMark,
+ const ScRangeList& rDest);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/colorformat.hxx b/sc/source/ui/inc/colorformat.hxx
new file mode 100644
index 000000000..051c48de0
--- /dev/null
+++ b/sc/source/ui/inc/colorformat.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/.
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <svx/colorbox.hxx>
+#include <address.hxx>
+
+struct ScDataBarFormatData;
+class ScDocument;
+class SvNumberFormatter;
+
+class ScDataBarSettingsDlg : public weld::GenericDialogController
+{
+private:
+ OUString maStrWarnSameValue;
+ SvNumberFormatter* mpNumberFormatter;
+
+ ScDocument* mpDoc;
+ ScAddress maPos;
+
+ std::unique_ptr<weld::Button> mxBtnOk;
+ std::unique_ptr<weld::Button> mxBtnCancel;
+
+ std::unique_ptr<ColorListBox> mxLbPos;
+ std::unique_ptr<ColorListBox> mxLbNeg;
+ std::unique_ptr<ColorListBox> mxLbAxisCol;
+
+ std::unique_ptr<weld::ComboBox> mxLbFillType;
+ std::unique_ptr<weld::ComboBox> mxLbTypeMin;
+ std::unique_ptr<weld::ComboBox> mxLbTypeMax;
+ std::unique_ptr<weld::ComboBox> mxLbAxisPos;
+
+ std::unique_ptr<weld::Entry> mxEdMin;
+ std::unique_ptr<weld::Entry> mxEdMax;
+ std::unique_ptr<weld::Entry> mxLenMin;
+ std::unique_ptr<weld::Entry> mxLenMax;
+
+ std::unique_ptr<weld::CheckButton> mxCbOnlyBar;
+
+ std::unique_ptr<weld::Label> mxStrSameValueFT;
+
+ DECL_LINK(OkBtnHdl, weld::Button&, void);
+ DECL_LINK(TypeSelectHdl, weld::ComboBox&, void);
+ DECL_LINK(PosSelectHdl, weld::ComboBox&, void);
+
+ void Init();
+
+public:
+ ScDataBarSettingsDlg(weld::Window* pParent, const ScDataBarFormatData& rData, ScDocument* pDoc,
+ const ScAddress& rPos);
+ virtual ~ScDataBarSettingsDlg() override;
+
+ ScDataBarFormatData* GetData();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/colrowba.hxx b/sc/source/ui/inc/colrowba.hxx
new file mode 100644
index 000000000..536a78dd1
--- /dev/null
+++ b/sc/source/ui/inc/colrowba.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 "hdrcont.hxx"
+#include "viewdata.hxx"
+
+class ScHeaderFunctionSet;
+class ScHeaderSelectionEngine;
+class ScTabView;
+
+class ScColBar : public ScHeaderControl
+{
+ ScHSplitPos meWhich;
+ ScHeaderFunctionSet* mpFuncSet;
+
+public:
+ ScColBar( vcl::Window* pParent, ScHSplitPos eWhich,
+ ScHeaderFunctionSet* pFuncSet, ScHeaderSelectionEngine* pEng,
+ ScTabView* pTab );
+ virtual ~ScColBar() override;
+
+ virtual SCCOLROW GetPos() const override;
+ virtual sal_uInt16 GetEntrySize( SCCOLROW nEntryNo ) const override;
+ virtual OUString GetEntryText( SCCOLROW nEntryNo ) const override;
+
+ virtual bool IsLayoutRTL() const override;
+
+ virtual void SetEntrySize( SCCOLROW nPos, sal_uInt16 nNewSize ) override;
+ virtual void HideEntries( SCCOLROW nStart, SCCOLROW nEnd ) override;
+
+ virtual void SetMarking( bool bSet ) override;
+ virtual void SelectWindow() override;
+ virtual bool IsDisabled() const override;
+ virtual bool ResizeAllowed() const override;
+
+ virtual void DrawInvert( tools::Long nDragPos ) override;
+
+ virtual OUString GetDragHelp( tools::Long nVal ) override;
+};
+
+class ScRowBar : public ScHeaderControl
+{
+ ScVSplitPos meWhich;
+ ScHeaderFunctionSet* mpFuncSet;
+
+public:
+ ScRowBar( vcl::Window* pParent, ScVSplitPos eWhich,
+ ScHeaderFunctionSet* pFuncSet, ScHeaderSelectionEngine* pEng,
+ ScTabView* pTab );
+ virtual ~ScRowBar() override;
+
+ virtual SCCOLROW GetPos() const override;
+ virtual sal_uInt16 GetEntrySize( SCCOLROW nEntryNo ) const override;
+ virtual OUString GetEntryText( SCCOLROW nEntryNo ) const override;
+
+ virtual bool IsMirrored() const override;
+ virtual SCCOLROW GetHiddenCount( SCCOLROW nEntryNo ) const override;
+
+ virtual void SetEntrySize( SCCOLROW nPos, sal_uInt16 nNewSize ) override;
+ virtual void HideEntries( SCCOLROW nStart, SCCOLROW nEnd ) override;
+
+ virtual void SetMarking( bool bSet ) override;
+ virtual void SelectWindow() override;
+ virtual bool IsDisabled() const override;
+ virtual bool ResizeAllowed() const override;
+
+ virtual void DrawInvert( tools::Long nDragPos ) override;
+
+ virtual OUString GetDragHelp( tools::Long nVal ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/condformatdlg.hxx b/sc/source/ui/inc/condformatdlg.hxx
new file mode 100644
index 000000000..51f92750d
--- /dev/null
+++ b/sc/source/ui/inc/condformatdlg.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/.
+ */
+
+#pragma once
+
+#include <rangelst.hxx>
+#include "condformatdlgitem.hxx"
+#include "condformatdlgentry.hxx"
+
+#include "anyrefdg.hxx"
+
+#include <memory>
+
+#define DLG_RET_ADD 8
+#define DLG_RET_EDIT 16
+
+class ScDocument;
+class ScConditionalFormat;
+class ScViewData;
+
+class ScCondFormatDlg;
+
+class ScCondFormatList
+{
+private:
+ std::unique_ptr<weld::ScrolledWindow> mxScrollWindow;
+ std::unique_ptr<weld::Container> mxGrid;
+
+ typedef std::vector<std::unique_ptr<ScCondFrmtEntry>> EntryContainer;
+ EntryContainer maEntries;
+
+ bool mbFrozen;
+ bool mbNewEntry;
+
+ ScDocument* mpDoc;
+ ScAddress maPos;
+ ScRangeList maRanges;
+ ScCondFormatDlg* mpDialogParent;
+
+public:
+ ScCondFormatList(ScCondFormatDlg* pParent,
+ std::unique_ptr<weld::ScrolledWindow> xWindow,
+ std::unique_ptr<weld::Container> xGrid);
+ weld::Container* GetContainer() { return mxGrid.get(); }
+ ~ScCondFormatList();
+
+ void init(ScDocument& rDoc, const ScConditionalFormat* pFormat,
+ const ScRangeList& rRanges, const ScAddress& rPos,
+ condformat::dialog::ScCondFormatDialogType eType);
+
+ void SetRange(const ScRangeList& rRange);
+
+ std::unique_ptr<ScConditionalFormat> GetConditionalFormat() const;
+ weld::Window* GetFrameWeld();
+ void Freeze() { mbFrozen = true; }
+ void Thaw() { mbFrozen = false; }
+ void RecalcAll();
+
+ DECL_LINK( AddBtnHdl, weld::Button&, void );
+ DECL_LINK( RemoveBtnHdl, weld::Button&, void );
+ DECL_LINK( UpBtnHdl, weld::Button&, void );
+ DECL_LINK( DownBtnHdl, weld::Button&, void );
+ DECL_LINK( EntrySelectHdl, ScCondFrmtEntry&, void );
+
+ DECL_LINK( TypeListHdl, weld::ComboBox&, void );
+ DECL_LINK( AfterTypeListHdl, void*, void );
+ DECL_LINK( ColFormatTypeHdl, weld::ComboBox&, void );
+ DECL_LINK( AfterColFormatTypeHdl, void*, void );
+};
+
+class ScCondFormatDlg : public ScAnyRefDlgController
+{
+private:
+ sal_Int32 mnKey;
+
+ ScAddress maPos;
+ ScViewData* mpViewData;
+
+ std::shared_ptr<ScCondFormatDlgItem> mpDlgItem;
+
+ OUString msBaseTitle;
+
+ formula::RefEdit* mpLastEdit;
+ std::unique_ptr<weld::Button> mxBtnOk;
+ std::unique_ptr<weld::Button> mxBtnAdd;
+ std::unique_ptr<weld::Button> mxBtnRemove;
+ std::unique_ptr<weld::Button> mxBtnUp;
+ std::unique_ptr<weld::Button> mxBtnDown;
+ std::unique_ptr<weld::Button> mxBtnCancel;
+ std::unique_ptr<weld::Label> mxFtRange;
+ std::unique_ptr<formula::RefEdit> mxEdRange;
+ std::unique_ptr<formula::RefButton> mxRbRange;
+ std::unique_ptr<ScCondFormatList> mxCondFormList;
+
+ void updateTitle();
+ DECL_LINK( EdRangeModifyHdl, formula::RefEdit&, void );
+protected:
+
+ virtual void RefInputDone( bool bForced = false ) override;
+ void OkPressed();
+ void CancelPressed();
+
+public:
+ ScCondFormatDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pWindow,
+ ScViewData* pViewData, const ScCondFormatDlgItem* pDlgItem);
+ virtual ~ScCondFormatDlg() override;
+
+ std::unique_ptr<ScConditionalFormat> GetConditionalFormat() const;
+
+ virtual void SetReference(const ScRange&, ScDocument&) override;
+ virtual bool IsRefInputMode() const override;
+ virtual void SetActive() override;
+ virtual bool IsTableLocked() const override;
+ virtual void Close() override;
+
+ void InvalidateRefData();
+ void OnSelectionChange(size_t nIndex, size_t nSize, bool bSelected = true);
+
+ DECL_LINK( BtnPressedHdl, weld::Button&, void );
+ DECL_LINK( RangeGetFocusHdl, formula::RefEdit&, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/condformatdlgentry.hxx b/sc/source/ui/inc/condformatdlgentry.hxx
new file mode 100644
index 000000000..6725ef94c
--- /dev/null
+++ b/sc/source/ui/inc/condformatdlgentry.hxx
@@ -0,0 +1,331 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <conditio.hxx>
+#include <formula/funcutl.hxx>
+#include <vcl/weld.hxx>
+#include <svl/lstner.hxx>
+#include <svx/fntctrl.hxx>
+
+class ScIconSetFrmtDataEntry;
+class ScCondFormatDlg;
+class ScCondFormatList;
+class ColorListBox;
+class ScColorScaleFormat;
+class ScDataBarFormat;
+class ScIconSetFormat;
+struct ScDataBarFormatData;
+
+namespace condformat::entry {
+
+enum ScCondFrmtEntryType
+{
+ CONDITION,
+ FORMULA,
+ COLORSCALE2,
+ COLORSCALE3,
+ DATABAR,
+ ICONSET,
+ DATE
+};
+
+}
+
+class ScCondFrmtEntry
+{
+protected:
+ ScCondFormatList* mpParent;
+ std::unique_ptr<weld::Builder> mxBuilder;
+
+private:
+ //general ui elements
+ std::unique_ptr<weld::Widget> mxBorder;
+ std::unique_ptr<weld::Container> mxGrid;
+ std::unique_ptr<weld::Label> mxFtCondNr;
+ std::unique_ptr<weld::Label> mxFtCondition;
+
+ bool mbActive;
+ OUString const maStrCondition;
+ Link<ScCondFrmtEntry&,void> maClickHdl;
+
+ DECL_LINK( EntrySelectHdl, const MouseEvent&, bool );
+
+protected:
+ std::unique_ptr<weld::ComboBox> mxLbType;
+
+ ScDocument* mpDoc;
+ ScAddress maPos;
+
+ virtual void Select();
+ virtual void Deselect();
+
+ virtual OUString GetExpressionString() = 0;
+
+public:
+ ScCondFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos);
+ virtual ~ScCondFrmtEntry();
+
+ void Show() { mxGrid->show(); }
+
+ void set_grid_top_attach(int nAttach) { mxBorder->set_grid_top_attach(nAttach); }
+ int get_preferred_height() const { return mxBorder->get_preferred_size().Height(); }
+
+ void SetPos(const ScAddress& rPos) { maPos = rPos; };
+ bool IsSelected() const { return mbActive;}
+ void SetIndex(sal_Int32 nIndex);
+
+ virtual ScFormatEntry* GetEntry() const = 0;
+ virtual void SetActive() = 0;
+ virtual void SetInactive() = 0;
+
+ virtual condformat::entry::ScCondFrmtEntryType GetType() = 0;
+};
+
+class ScConditionFrmtEntry : public ScCondFrmtEntry, public SfxListener
+{
+ //cond format ui elements
+ SvxFontPrevWindow maWdPreview;
+ std::unique_ptr<weld::ComboBox> mxLbCondType;
+ std::unique_ptr<formula::RefEdit> mxEdVal1;
+ std::unique_ptr<formula::RefEdit> mxEdVal2;
+ std::unique_ptr<weld::Label> mxFtVal;
+ std::unique_ptr<weld::Label> mxFtStyle;
+ std::unique_ptr<weld::ComboBox> mxLbStyle;
+ std::unique_ptr<weld::Widget> mxWdPreviewWin;
+ std::unique_ptr<weld::CustomWeld> mxWdPreview;
+ bool mbIsInStyleCreate;
+
+ static const sal_Int32 NUM_COND_ENTRIES = 24;
+ // Lookup table from positions in maLbCondType to the condition mode enum
+ static const ScConditionMode mpEntryToCond[NUM_COND_ENTRIES];
+
+ ScFormatEntry* createConditionEntry() const;
+
+ virtual OUString GetExpressionString() override;
+ void Init(ScCondFormatDlg* pDialogParent);
+ DECL_LINK( StyleSelectHdl, weld::ComboBox&, void );
+ DECL_LINK( ConditionTypeSelectHdl, weld::ComboBox&, void );
+ DECL_LINK( OnEdChanged, formula::RefEdit&, void );
+
+ // Searches the lookup table for the entry position, given condition mode
+ static sal_Int32 ConditionModeToEntryPos( ScConditionMode eMode );
+ // Accesses the lookup table for the condition mode, given entry position
+ static ScConditionMode EntryPosToConditionMode( sal_Int32 aEntryPos );
+ // Returns the number of edit fields used for a given condition mode
+ static sal_Int32 GetNumberEditFields( ScConditionMode eMode );
+
+protected:
+ virtual void Select() override;
+ virtual void Deselect() override;
+
+public:
+ ScConditionFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, ScCondFormatDlg* pDialogParent,
+ const ScAddress& rPos, const ScCondFormatEntry* pFormatEntry = nullptr);
+ virtual ~ScConditionFrmtEntry() override;
+
+ virtual ScFormatEntry* GetEntry() const override;
+ virtual void SetActive() override;
+ virtual void SetInactive() override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual condformat::entry::ScCondFrmtEntryType GetType() override { return condformat::entry::CONDITION; }
+};
+
+class ScFormulaFrmtEntry : public ScCondFrmtEntry
+{
+ SvxFontPrevWindow maWdPreview;
+ std::unique_ptr<weld::Label> mxFtStyle;
+ std::unique_ptr<weld::ComboBox> mxLbStyle;
+ std::unique_ptr<weld::Widget> mxWdPreviewWin;
+ std::unique_ptr<weld::CustomWeld> mxWdPreview;
+ std::unique_ptr<formula::RefEdit> mxEdFormula;
+
+ ScFormatEntry* createFormulaEntry() const;
+ virtual OUString GetExpressionString() override;
+ void Init(ScCondFormatDlg* pDialogParent);
+
+ DECL_LINK(StyleSelectHdl, weld::ComboBox&, void);
+
+public:
+ ScFormulaFrmtEntry(ScCondFormatList* pParent, ScDocument* PDoc, ScCondFormatDlg* pDialogParent, const ScAddress& rPos, const ScCondFormatEntry* pFormatEntry = nullptr);
+ virtual ~ScFormulaFrmtEntry() override;
+
+ virtual ScFormatEntry* GetEntry() const override;
+ virtual void SetActive() override;
+ virtual void SetInactive() override;
+ virtual condformat::entry::ScCondFrmtEntryType GetType() override { return condformat::entry::FORMULA; }
+};
+
+class ScColorScale2FrmtEntry : public ScCondFrmtEntry
+{
+
+ //color format ui elements
+ std::unique_ptr<weld::ComboBox> mxLbColorFormat;
+
+ //color scale ui elements
+ std::unique_ptr<weld::ComboBox> mxLbEntryTypeMin;
+ std::unique_ptr<weld::ComboBox> mxLbEntryTypeMax;
+
+ std::unique_ptr<weld::Entry> mxEdMin;
+ std::unique_ptr<weld::Entry> mxEdMax;
+
+ std::unique_ptr<ColorListBox> mxLbColMin;
+ std::unique_ptr<ColorListBox> mxLbColMax;
+
+ std::unique_ptr<weld::Label> mxFtMin;
+ std::unique_ptr<weld::Label> mxFtMax;
+
+ ScFormatEntry* createColorscaleEntry() const;
+
+ virtual OUString GetExpressionString() override;
+ void Init();
+
+ DECL_LINK( EntryTypeHdl, weld::ComboBox&, void );
+public:
+ ScColorScale2FrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScColorScaleFormat* pFormat = nullptr);
+ virtual ~ScColorScale2FrmtEntry() override;
+ virtual ScFormatEntry* GetEntry() const override;
+ virtual void SetActive() override;
+ virtual void SetInactive() override;
+ virtual condformat::entry::ScCondFrmtEntryType GetType() override { return condformat::entry::COLORSCALE2; }
+};
+
+class ScColorScale3FrmtEntry : public ScCondFrmtEntry
+{
+
+ //color format ui elements
+ std::unique_ptr<weld::ComboBox> mxLbColorFormat;
+
+ //color scale ui elements
+ std::unique_ptr<weld::ComboBox> mxLbEntryTypeMin;
+ std::unique_ptr<weld::ComboBox> mxLbEntryTypeMiddle;
+ std::unique_ptr<weld::ComboBox> mxLbEntryTypeMax;
+
+ std::unique_ptr<weld::Entry> mxEdMin;
+ std::unique_ptr<weld::Entry> mxEdMiddle;
+ std::unique_ptr<weld::Entry> mxEdMax;
+
+ std::unique_ptr<ColorListBox> mxLbColMin;
+ std::unique_ptr<ColorListBox> mxLbColMiddle;
+ std::unique_ptr<ColorListBox> mxLbColMax;
+
+ std::unique_ptr<weld::Label> mxFtMin;
+ std::unique_ptr<weld::Label> mxFtMax;
+
+ ScFormatEntry* createColorscaleEntry() const;
+
+ virtual OUString GetExpressionString() override;
+ void Init();
+
+ DECL_LINK( EntryTypeHdl, weld::ComboBox&, void );
+public:
+ ScColorScale3FrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScColorScaleFormat* pFormat = nullptr);
+ virtual ~ScColorScale3FrmtEntry() override;
+ virtual ScFormatEntry* GetEntry() const override;
+ virtual void SetActive() override;
+ virtual void SetInactive() override;
+ virtual condformat::entry::ScCondFrmtEntryType GetType() override { return condformat::entry::COLORSCALE3; }
+};
+
+class ScDataBarFrmtEntry : public ScCondFrmtEntry
+{
+ //color format ui elements
+ std::unique_ptr<weld::ComboBox> mxLbColorFormat;
+
+ //data bar ui elements
+ std::unique_ptr<weld::ComboBox> mxLbDataBarMinType;
+ std::unique_ptr<weld::ComboBox> mxLbDataBarMaxType;
+ std::unique_ptr<weld::Entry> mxEdDataBarMin;
+ std::unique_ptr<weld::Entry> mxEdDataBarMax;
+ std::unique_ptr<weld::Button> mxBtOptions;
+
+ std::unique_ptr<weld::Label> mxFtMin;
+ std::unique_ptr<weld::Label> mxFtMax;
+
+ std::unique_ptr<ScDataBarFormatData> mpDataBarData;
+
+ ScFormatEntry* createDatabarEntry() const;
+
+ virtual OUString GetExpressionString() override;
+ void Init();
+
+ DECL_LINK( OptionBtnHdl, weld::Button&, void );
+ DECL_LINK( DataBarTypeSelectHdl, weld::ComboBox&, void );
+public:
+ ScDataBarFrmtEntry(ScCondFormatList* pParemt, ScDocument* pDoc, const ScAddress& rPos, const ScDataBarFormat* pFormat = nullptr);
+ virtual ~ScDataBarFrmtEntry() override;
+ virtual ScFormatEntry* GetEntry() const override;
+ virtual void SetActive() override;
+ virtual void SetInactive() override;
+
+ virtual condformat::entry::ScCondFrmtEntryType GetType() override { return condformat::entry::DATABAR; }
+};
+
+class ScDateFrmtEntry : public ScCondFrmtEntry, public SfxListener
+{
+public:
+ ScDateFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScCondDateFormatEntry* pFormat = nullptr);
+ virtual ~ScDateFrmtEntry() override;
+ virtual ScFormatEntry* GetEntry() const override;
+ virtual void SetActive() override;
+ virtual void SetInactive() override;
+ virtual condformat::entry::ScCondFrmtEntryType GetType() override { return condformat::entry::DATE; }
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+protected:
+ virtual OUString GetExpressionString() override;
+
+private:
+ void Init();
+
+ DECL_LINK( StyleSelectHdl, weld::ComboBox&, void );
+
+ SvxFontPrevWindow maWdPreview;
+ std::unique_ptr<weld::ComboBox> mxLbDateEntry;
+ std::unique_ptr<weld::Label> mxFtStyle;
+ std::unique_ptr<weld::ComboBox> mxLbStyle;
+ std::unique_ptr<weld::Widget> mxWdPreviewWin;
+ std::unique_ptr<weld::CustomWeld> mxWdPreview;
+
+ bool mbIsInStyleCreate;
+};
+
+class ScIconSetFrmtEntry : public ScCondFrmtEntry
+{
+ //color format ui elements
+ std::unique_ptr<weld::ComboBox> mxLbColorFormat;
+
+ // icon set ui elements
+ std::unique_ptr<weld::ComboBox> mxLbIconSetType;
+
+ std::unique_ptr<weld::Container> mxIconParent;
+
+ typedef std::vector<std::unique_ptr<ScIconSetFrmtDataEntry>> ScIconSetFrmtDataEntriesType;
+ ScIconSetFrmtDataEntriesType maEntries;
+
+ virtual OUString GetExpressionString() override;
+
+ void Init();
+
+ DECL_LINK(IconSetTypeHdl, weld::ComboBox&, void);
+
+public:
+ ScIconSetFrmtEntry(ScCondFormatList* pParent, ScDocument* pDoc, const ScAddress& rPos, const ScIconSetFormat* pFormat = nullptr);
+ virtual ~ScIconSetFrmtEntry() override;
+ virtual ScFormatEntry* GetEntry() const override;
+ virtual void SetActive() override;
+ virtual void SetInactive() override;
+ virtual condformat::entry::ScCondFrmtEntryType GetType() override { return condformat::entry::ICONSET; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/condformatdlgitem.hxx b/sc/source/ui/inc/condformatdlgitem.hxx
new file mode 100644
index 000000000..b50b1d417
--- /dev/null
+++ b/sc/source/ui/inc/condformatdlgitem.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 <svl/poolitem.hxx>
+
+#include <memory>
+
+namespace condformat::dialog
+{
+enum ScCondFormatDialogType
+{
+ NONE,
+ CONDITION,
+ COLORSCALE,
+ DATABAR,
+ ICONSET,
+ DATE
+};
+}
+
+class ScConditionalFormatList;
+
+class ScCondFormatDlgItem : public SfxPoolItem
+{
+public:
+ ScCondFormatDlgItem(std::shared_ptr<ScConditionalFormatList> pCondFormats, sal_Int32 nItem,
+ bool bManaged);
+
+ virtual ~ScCondFormatDlgItem() override;
+
+ ScCondFormatDlgItem(ScCondFormatDlgItem const&) = default;
+ ScCondFormatDlgItem(ScCondFormatDlgItem&&) = default;
+ ScCondFormatDlgItem& operator=(ScCondFormatDlgItem const&) = delete; // due to SfxPoolItem
+ ScCondFormatDlgItem& operator=(ScCondFormatDlgItem&&) = delete; // due to SfxPoolItem
+
+ virtual bool operator==(const SfxPoolItem&) const override;
+ virtual ScCondFormatDlgItem* Clone(SfxItemPool* pPool = nullptr) const override;
+
+ bool IsManaged() const;
+ condformat::dialog::ScCondFormatDialogType GetDialogType() const;
+ sal_Int32 GetIndex() const;
+
+ void SetDialogType(condformat::dialog::ScCondFormatDialogType eType);
+
+ ScConditionalFormatList* GetConditionalFormatList();
+
+private:
+ std::shared_ptr<ScConditionalFormatList> mpCondFormats;
+ sal_Int32 mnItem;
+ condformat::dialog::ScCondFormatDialogType meDialogType;
+ bool mbManaged;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/condformathelper.hxx b/sc/source/ui/inc/condformathelper.hxx
new file mode 100644
index 000000000..9e4a0768d
--- /dev/null
+++ b/sc/source/ui/inc/condformathelper.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/.
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+#include <address.hxx>
+
+class ScConditionalFormat;
+
+enum ScCondFormatEntryType
+{
+ CONDITION,
+ COLORSCALE,
+ DATABAR,
+ FORMULA,
+ ICONSET,
+ DATE
+};
+
+class ScCondFormatHelper
+{
+public:
+ static SC_DLLPUBLIC OUString GetExpression(const ScConditionalFormat& rFormat, const ScAddress& rPos);
+
+ static SC_DLLPUBLIC OUString GetExpression( ScCondFormatEntryType eType, sal_Int32 nIndex,
+ std::u16string_view aStr1 = std::u16string_view(), std::u16string_view aStr2 = std::u16string_view() );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/condformatmgr.hxx b/sc/source/ui/inc/condformatmgr.hxx
new file mode 100644
index 000000000..ca9f16e8a
--- /dev/null
+++ b/sc/source/ui/inc/condformatmgr.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 <vcl/weld.hxx>
+
+class ScDocument;
+class ScConditionalFormat;
+class ScConditionalFormatList;
+
+class ScCondFormatManagerWindow
+{
+private:
+ void Init();
+ void setColSizes();
+
+ weld::TreeView& mrTreeView;
+ ScDocument& mrDoc;
+ ScConditionalFormatList* mpFormatList;
+
+public:
+ ScCondFormatManagerWindow(weld::TreeView& rTreeView, ScDocument& rDoc, ScConditionalFormatList* pFormatList);
+
+ void DeleteSelection();
+ ScConditionalFormat* GetSelection();
+};
+
+class ScCondFormatManagerDlg : public weld::GenericDialogController
+{
+public:
+ ScCondFormatManagerDlg(weld::Window* pParent, ScDocument& rDoc, const ScConditionalFormatList* pFormatList);
+ virtual ~ScCondFormatManagerDlg() override;
+
+ std::unique_ptr<ScConditionalFormatList> GetConditionalFormatList();
+
+ bool CondFormatsChanged() const;
+ void SetModified();
+
+ ScConditionalFormat* GetCondFormatSelected();
+
+private:
+ bool m_bModified;
+ std::unique_ptr<ScConditionalFormatList> m_xFormatList;
+
+ std::unique_ptr<weld::Button> m_xBtnAdd;
+ std::unique_ptr<weld::Button> m_xBtnRemove;
+ std::unique_ptr<weld::Button> m_xBtnEdit;
+ std::unique_ptr<weld::TreeView> m_xTreeView;
+ std::unique_ptr<ScCondFormatManagerWindow> m_xCtrlManager;
+
+ void UpdateButtonSensitivity();
+
+ DECL_LINK(RemoveBtnHdl, weld::Button&, void);
+ DECL_LINK(EditBtnClickHdl, weld::Button&, void);
+ DECL_LINK(AddBtnHdl, weld::Button&, void);
+ DECL_LINK(EditBtnHdl, weld::TreeView&, bool);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/condformatuno.hxx b/sc/source/ui/inc/condformatuno.hxx
new file mode 100644
index 000000000..253aed098
--- /dev/null
+++ b/sc/source/ui/inc/condformatuno.hxx
@@ -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/.
+ */
+
+#pragma once
+
+#include <types.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sheet/XConditionalFormats.hpp>
+#include <com/sun/star/sheet/XConditionalFormat.hpp>
+#include <com/sun/star/sheet/XConditionEntry.hpp>
+#include <com/sun/star/sheet/XColorScaleEntry.hpp>
+#include <com/sun/star/sheet/XDataBarEntry.hpp>
+#include <com/sun/star/sheet/XIconSetEntry.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <svl/itemprop.hxx>
+#include <svl/lstner.hxx>
+#include <rtl/ref.hxx>
+
+class ScDocShell;
+class ScConditionalFormatList;
+class ScConditionalFormat;
+class ScIconSetFormat;
+class ScDataBarFormat;
+class ScColorScaleFormat;
+class ScCondFormatEntry;
+class ScColorScaleEntry;
+class ScCondDateFormatEntry;
+
+using namespace com::sun::star;
+
+namespace com::sun::star::sheet { class XSheetCellRanges; }
+
+class ScCondFormatsObj : public cppu::WeakImplHelper<css::sheet::XConditionalFormats>,
+ public SfxListener
+{
+public:
+ ScCondFormatsObj(ScDocShell* pDocShell, SCTAB nTab);
+
+ virtual ~ScCondFormatsObj() override;
+
+ virtual void Notify(SfxBroadcaster& rBC, const SfxHint& rHint) override;
+
+ // XConditionalFormats
+ virtual sal_Int32 SAL_CALL createByRange(const uno::Reference<sheet::XSheetCellRanges>& xRanges) override;
+
+ virtual void SAL_CALL removeByID( const sal_Int32 nID ) override;
+
+ virtual uno::Sequence< uno::Reference< sheet::XConditionalFormat > > SAL_CALL getConditionalFormats() override;
+
+ virtual sal_Int32 SAL_CALL getLength() override;
+
+ ScConditionalFormatList* getCoreObject();
+
+private:
+ SCTAB mnTab;
+ ScDocShell* mpDocShell;
+};
+
+class ScCondFormatObj : public cppu::WeakImplHelper<css::sheet::XConditionalFormat,
+ css::beans::XPropertySet>
+{
+public:
+ ScCondFormatObj(ScDocShell* pDocShell, rtl::Reference<ScCondFormatsObj> const & xCondFormats, sal_Int32 nKey);
+
+ virtual ~ScCondFormatObj() override;
+
+ ScDocShell* getDocShell();
+
+ // XConditionalFormat
+ virtual void SAL_CALL createEntry(const sal_Int32 nType, const sal_Int32 nPos) override;
+
+ virtual void SAL_CALL removeByIndex(const sal_Int32 nIndex) override;
+
+ // XIndexAccess
+
+ virtual uno::Type SAL_CALL getElementType() override;
+
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+ virtual sal_Int32 SAL_CALL getCount() override;
+
+ virtual uno::Any SAL_CALL getByIndex(sal_Int32 nIndex) 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;
+
+ ScConditionalFormat* getCoreObject();
+
+private:
+ rtl::Reference<ScCondFormatsObj> mxCondFormatList;
+ ScDocShell* mpDocShell;
+ SfxItemPropertySet maPropSet;
+ sal_Int32 mnKey;
+};
+
+class ScConditionEntryObj : public cppu::WeakImplHelper<css::beans::XPropertySet,
+ css::sheet::XConditionEntry>
+{
+public:
+
+ ScConditionEntryObj(rtl::Reference<ScCondFormatObj> const & xParent,
+ const ScCondFormatEntry* pFormat);
+ virtual ~ScConditionEntryObj() override;
+
+ ScCondFormatEntry* getCoreObject();
+
+ // XConditionEntry
+ virtual sal_Int32 SAL_CALL getType() 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;
+
+private:
+ ScDocShell* mpDocShell;
+ rtl::Reference<ScCondFormatObj> mxParent;
+ SfxItemPropertySet maPropSet;
+ const ScCondFormatEntry* mpFormat;
+};
+
+class ScColorScaleFormatObj : public cppu::WeakImplHelper<css::beans::XPropertySet,
+ css::sheet::XConditionEntry>
+{
+public:
+
+ ScColorScaleFormatObj(rtl::Reference<ScCondFormatObj> const & xParent, const ScColorScaleFormat* pFormat);
+ virtual ~ScColorScaleFormatObj() override;
+
+ // XConditionEntry
+ virtual sal_Int32 SAL_CALL getType() override;
+
+
+ ScColorScaleFormat* getCoreObject();
+
+ // 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;
+
+private:
+ rtl::Reference<ScCondFormatObj> mxParent;
+ SfxItemPropertySet maPropSet;
+ const ScColorScaleFormat* mpFormat;
+};
+
+class ScColorScaleEntryObj : public cppu::WeakImplHelper<css::sheet::XColorScaleEntry>
+{
+public:
+ ScColorScaleEntryObj(rtl::Reference<ScColorScaleFormatObj> const & xParent, size_t nPos);
+
+ virtual ~ScColorScaleEntryObj() override;
+
+ virtual sal_Int32 SAL_CALL getColor() override;
+
+ virtual void SAL_CALL setColor(sal_Int32 aColor) override;
+
+ virtual sal_Int32 SAL_CALL getType() override;
+
+ virtual void SAL_CALL setType(sal_Int32 nType) override;
+
+ virtual OUString SAL_CALL getFormula() override;
+
+ virtual void SAL_CALL setFormula(const OUString& rString) override;
+
+private:
+ ScColorScaleEntry* getCoreObject();
+
+ rtl::Reference<ScColorScaleFormatObj> mxParent;
+ size_t mnPos;
+};
+
+class ScDataBarFormatObj : public cppu::WeakImplHelper<css::beans::XPropertySet,
+ css::sheet::XConditionEntry>
+{
+public:
+ ScDataBarFormatObj(rtl::Reference<ScCondFormatObj> const & xParent,
+ const ScDataBarFormat* pFormat);
+ virtual ~ScDataBarFormatObj() override;
+
+ ScDataBarFormat* getCoreObject();
+
+ // XConditionEntry
+ virtual sal_Int32 SAL_CALL getType() 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;
+
+private:
+ rtl::Reference<ScCondFormatObj> mxParent;
+ SfxItemPropertySet maPropSet;
+ const ScDataBarFormat* mpFormat;
+};
+
+class ScDataBarEntryObj : public cppu::WeakImplHelper<css::sheet::XDataBarEntry>
+{
+public:
+ ScDataBarEntryObj(rtl::Reference<ScDataBarFormatObj> const & xParent, size_t nPos);
+
+ virtual ~ScDataBarEntryObj() override;
+
+ virtual sal_Int32 SAL_CALL getType() override;
+
+ virtual void SAL_CALL setType(sal_Int32 nType) override;
+
+ virtual OUString SAL_CALL getFormula() override;
+
+ virtual void SAL_CALL setFormula(const OUString& rString) override;
+
+private:
+ ScColorScaleEntry* getCoreObject();
+
+ rtl::Reference<ScDataBarFormatObj> mxParent;
+ size_t mnPos;
+};
+
+class ScIconSetFormatObj : public cppu::WeakImplHelper<css::beans::XPropertySet,
+ css::sheet::XConditionEntry>
+{
+public:
+ ScIconSetFormatObj(rtl::Reference<ScCondFormatObj> const & xParent,
+ const ScIconSetFormat* pFormat);
+ virtual ~ScIconSetFormatObj() override;
+
+ ScIconSetFormat* getCoreObject();
+
+ // XConditionEntry
+ virtual sal_Int32 SAL_CALL getType() 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;
+
+private:
+ rtl::Reference<ScCondFormatObj> mxParent;
+ SfxItemPropertySet maPropSet;
+ const ScIconSetFormat* mpFormat;
+};
+
+class ScIconSetEntryObj : public cppu::WeakImplHelper<css::sheet::XIconSetEntry>
+{
+public:
+ ScIconSetEntryObj(rtl::Reference<ScIconSetFormatObj> const & xParent, size_t nPos);
+
+ virtual ~ScIconSetEntryObj() override;
+
+ virtual sal_Int32 SAL_CALL getType() override;
+
+ virtual void SAL_CALL setType(sal_Int32 nType) override;
+
+ virtual OUString SAL_CALL getFormula() override;
+
+ virtual void SAL_CALL setFormula(const OUString& rString) override;
+
+private:
+ ScColorScaleEntry* getCoreObject();
+
+ rtl::Reference<ScIconSetFormatObj> mxParent;
+ size_t mnPos;
+};
+
+class ScCondDateFormatObj : public cppu::WeakImplHelper<css::beans::XPropertySet,
+ css::sheet::XConditionEntry>
+{
+public:
+ ScCondDateFormatObj(rtl::Reference<ScCondFormatObj> const & xParent,
+ const ScCondDateFormatEntry* pFormat);
+
+ virtual ~ScCondDateFormatObj() override;
+
+ ScCondDateFormatEntry* getCoreObject();
+
+ // XConditionEntry
+ virtual sal_Int32 SAL_CALL getType() 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;
+
+private:
+ rtl::Reference<ScCondFormatObj> mxParent;
+ SfxItemPropertySet maPropSet;
+ const ScCondDateFormatEntry* mpFormat;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/conflictsdlg.hxx b/sc/source/ui/inc/conflictsdlg.hxx
new file mode 100644
index 000000000..f0ab643e0
--- /dev/null
+++ b/sc/source/ui/inc/conflictsdlg.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/idle.hxx>
+#include <svx/ctredlin.hxx>
+
+#include "docsh.hxx"
+
+class ScViewData;
+class ScChangeTrack;
+class ScChangeAction;
+
+enum ScConflictAction
+{
+ SC_CONFLICT_ACTION_NONE,
+ SC_CONFLICT_ACTION_KEEP_MINE,
+ SC_CONFLICT_ACTION_KEEP_OTHER
+};
+
+// struct ScConflictsListEntry
+
+struct ScConflictsListEntry
+{
+ ScConflictAction meConflictAction;
+ std::vector<sal_uLong> maSharedActions;
+ std::vector<sal_uLong> maOwnActions;
+
+ bool HasSharedAction( sal_uLong nSharedAction ) const;
+ bool HasOwnAction( sal_uLong nOwnAction ) const;
+};
+
+typedef ::std::vector< ScConflictsListEntry > ScConflictsList;
+
+
+class ScConflictsListHelper
+{
+private:
+ static void Transform_Impl( std::vector<sal_uLong>& rActionList, ScChangeActionMergeMap* pMergeMap );
+
+public:
+ static bool HasOwnAction( ScConflictsList& rConflictsList, sal_uLong nOwnAction );
+
+ static ScConflictsListEntry* GetSharedActionEntry( ScConflictsList& rConflictsList, sal_uLong nSharedAction );
+ static ScConflictsListEntry* GetOwnActionEntry( ScConflictsList& rConflictsList, sal_uLong nOwnAction );
+
+ static void TransformConflictsList( ScConflictsList& rConflictsList,
+ ScChangeActionMergeMap* pSharedMap, ScChangeActionMergeMap* pOwnMap );
+};
+
+
+class ScConflictsFinder final
+{
+private:
+ ScChangeTrack* mpTrack;
+ sal_uLong mnStartShared;
+ sal_uLong mnEndShared;
+ sal_uLong mnStartOwn;
+ sal_uLong mnEndOwn;
+ ScConflictsList& mrConflictsList;
+
+ static bool DoActionsIntersect( const ScChangeAction* pAction1, const ScChangeAction* pAction2 );
+ ScConflictsListEntry* GetIntersectingEntry( const ScChangeAction* pAction ) const;
+ ScConflictsListEntry& GetEntry(sal_uLong nSharedAction, const std::vector<sal_uLong>& rOwnActions);
+
+public:
+ ScConflictsFinder( ScChangeTrack* pTrack, sal_uLong nStartShared, sal_uLong nEndShared,
+ sal_uLong nStartOwn, sal_uLong nEndOwn, ScConflictsList& rConflictsList );
+
+ bool Find();
+};
+
+
+class ScConflictsResolver final
+{
+private:
+ ScChangeTrack* mpTrack;
+ ScConflictsList& mrConflictsList;
+
+public:
+ ScConflictsResolver( ScChangeTrack* pTrack, ScConflictsList& rConflictsList );
+
+ void HandleAction( ScChangeAction* pAction, bool bIsSharedAction,
+ bool bHandleContentAction, bool bHandleNonContentAction );
+};
+
+
+class ScConflictsDlg : public weld::GenericDialogController
+{
+private:
+ OUString maStrUnknownUser;
+
+ ScViewData* const mpViewData;
+ ScDocument* mpOwnDoc;
+ ScChangeTrack* mpOwnTrack;
+ ScDocument* const mpSharedDoc;
+ ScChangeTrack* mpSharedTrack;
+ ScConflictsList& mrConflictsList;
+
+ Idle maSelectionIdle;
+ bool mbInSelectHdl;
+
+ std::unique_ptr<weld::Button> m_xBtnKeepMine;
+ std::unique_ptr<weld::Button> m_xBtnKeepOther;
+ std::unique_ptr<weld::Button> m_xBtnKeepAllMine;
+ std::unique_ptr<weld::Button> m_xBtnKeepAllOthers;
+ std::unique_ptr<SvxRedlinTable> m_xLbConflicts;
+
+ OUString GetConflictString( const ScConflictsListEntry& rConflictEntry );
+ void SetActionString(const ScChangeAction* pAction, ScDocument* pDoc, const weld::TreeIter& rEntry);
+ void HandleListBoxSelection();
+
+ void SetConflictAction(const weld::TreeIter& rRootEntry, ScConflictAction eConflictAction);
+ void KeepHandler( bool bMine );
+ void KeepAllHandler( bool bMine );
+
+ DECL_LINK( SelectHandle, weld::TreeView&, void );
+ DECL_LINK( UpdateSelectionHdl, Timer*, void );
+ DECL_LINK( KeepMineHandle, weld::Button&, void );
+ DECL_LINK( KeepOtherHandle, weld::Button&, void );
+ DECL_LINK( KeepAllMineHandle, weld::Button&, void );
+ DECL_LINK( KeepAllOthersHandle, weld::Button&, void );
+
+public:
+ ScConflictsDlg(weld::Window* pParent, ScViewData* pViewData, ScDocument* pSharedDoc, ScConflictsList& rConflictsList);
+ virtual ~ScConflictsDlg() override;
+
+ void UpdateView();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/consdlg.hxx b/sc/source/ui/inc/consdlg.hxx
new file mode 100644
index 000000000..140472cbb
--- /dev/null
+++ b/sc/source/ui/inc/consdlg.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <global.hxx>
+#include "anyrefdg.hxx"
+
+class ScViewData;
+class ScDocument;
+class ScRangeUtil;
+class ScAreaData;
+
+class ScConsolidateDlg : public ScAnyRefDlgController
+{
+public:
+ ScConsolidateDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ const SfxItemSet& rArgSet);
+ virtual ~ScConsolidateDlg() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+
+ virtual bool IsRefInputMode() const override { return true; }
+ virtual void SetActive() override;
+
+ virtual void Close() override;
+ virtual void Deactivate() override;
+
+private:
+ OUString aStrUndefined;
+
+ ScConsolidateParam theConsData;
+ ScViewData& rViewData;
+ ScDocument& rDoc;
+ std::unique_ptr<ScAreaData[]> pAreaData;
+ size_t nAreaDataCount;
+ sal_uInt16 nWhichCons;
+ bool bDlgLostFocus;
+
+ formula::RefEdit* m_pRefInputEdit;
+
+ std::unique_ptr<weld::ComboBox> m_xLbFunc;
+ std::unique_ptr<weld::TreeView> m_xLbConsAreas;
+
+ std::unique_ptr<weld::ComboBox> m_xLbDataArea;
+ std::unique_ptr<formula::RefEdit> m_xEdDataArea;
+ std::unique_ptr<formula::RefButton> m_xRbDataArea;
+
+ std::unique_ptr<weld::ComboBox> m_xLbDestArea;
+ std::unique_ptr<formula::RefEdit> m_xEdDestArea;
+ std::unique_ptr<formula::RefButton> m_xRbDestArea;
+
+ std::unique_ptr<weld::Expander> m_xExpander;
+ std::unique_ptr<weld::CheckButton> m_xBtnByRow;
+ std::unique_ptr<weld::CheckButton> m_xBtnByCol;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnRefs;
+
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+ std::unique_ptr<weld::Button> m_xBtnAdd;
+ std::unique_ptr<weld::Button> m_xBtnRemove;
+
+ std::unique_ptr<weld::Label> m_xDataFT;
+ std::unique_ptr<weld::Label> m_xDestFT;
+
+ void Init ();
+ void FillAreaLists ();
+ bool VerifyEdit(formula::RefEdit* pEd);
+
+ DECL_LINK( OkHdl, weld::Button&, void );
+ DECL_LINK( ClickHdl, weld::Button&, void );
+ DECL_LINK( GetFocusHdl, weld::Widget&, void );
+ DECL_LINK( GetEditFocusHdl, formula::RefEdit&, void );
+ DECL_LINK( ModifyHdl, formula::RefEdit&, void );
+ DECL_LINK( SelectTVHdl, weld::TreeView&, void );
+ DECL_LINK( SelectCBHdl, weld::ComboBox&, void );
+
+ static ScSubTotalFunc LbPosToFunc( sal_Int32 nPos );
+ static sal_Int32 FuncToLbPos( ScSubTotalFunc eFunc );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/content.hxx b/sc/source/ui/inc/content.hxx
new file mode 100644
index 000000000..9cd7e9773
--- /dev/null
+++ b/sc/source/ui/inc/content.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 <vcl/weld.hxx>
+#include <address.hxx>
+#include <tools/solar.h>
+#include <o3tl/enumarray.hxx>
+
+class ScAreaLink;
+class ScLinkTransferObj;
+class ScDocument;
+class ScDocShell;
+class ScNavigatorDlg;
+struct ImplSVEvent;
+enum class SdrObjKind : sal_uInt16;
+
+enum class ScContentId {
+ ROOT, TABLE, RANGENAME, DBAREA,
+ GRAPHIC, OLEOBJECT, NOTE, AREALINK,
+ DRAWING, LAST = DRAWING
+};
+
+const sal_uLong SC_CONTENT_NOCHILD = ~0UL;
+
+class ScContentTree
+{
+ std::unique_ptr<weld::TreeView> m_xTreeView;
+ std::unique_ptr<weld::TreeIter> m_xScratchIter;
+ rtl::Reference<ScLinkTransferObj> m_xTransferObj;
+ ScNavigatorDlg* pParentWindow;
+ o3tl::enumarray<ScContentId, std::unique_ptr<weld::TreeIter>> m_aRootNodes;
+ ScContentId nRootType; // set as Root
+ OUString aManualDoc; // Switched in Navigator (Title)
+ bool bHiddenDoc; // Hidden active?
+ OUString aHiddenName; // URL to load
+ OUString aHiddenTitle; // for display
+ ScDocument* pHiddenDocument; // temporary
+ bool bIsInNavigatorDlg;
+ bool m_bFreeze;
+ ImplSVEvent* m_nAsyncMouseReleaseId;
+
+ o3tl::enumarray<ScContentId, sal_uInt16> pPosList; // for the sequence
+
+ ScDocShell* GetManualOrCurrent();
+
+ void InitRoot(ScContentId nType);
+ void ClearType(ScContentId nType);
+ void ClearAll();
+ void InsertContent( ScContentId nType, const OUString& rValue );
+ void GetDrawNames( ScContentId nType );
+
+ void GetTableNames();
+ void GetAreaNames();
+ void GetDbNames();
+ void GetLinkNames();
+ void GetGraphicNames();
+ void GetOleNames();
+ void GetDrawingNames();
+ void GetNoteStrings();
+
+ static bool IsPartOfType( ScContentId nContentType, SdrObjKind nObjIdentifier );
+
+ bool DrawNamesChanged( ScContentId nType );
+ bool NoteStringsChanged();
+
+ ScAddress GetNotePos( sal_uLong nIndex );
+ const ScAreaLink* GetLink( sal_uLong nIndex );
+
+ /** Returns the indexes of the specified listbox entry.
+ @param rnRootIndex Root index of specified entry is returned.
+ @param rnChildIndex Index of the entry inside its root is returned (or SC_CONTENT_NOCHILD if entry is root).
+ @param pEntry The entry to examine. */
+ void GetEntryIndexes(ScContentId& rnRootIndex, sal_uLong& rnChildIndex, const weld::TreeIter* pEntry) const;
+
+ /** Returns the child index of the specified listbox entry.
+ @param pEntry The entry to examine or NULL for the selected entry.
+ @return Index of the entry inside its root or SC_CONTENT_NOCHILD if entry is root. */
+ sal_uLong GetChildIndex(const weld::TreeIter* pEntry) const;
+
+ ScDocument* GetSourceDocument();
+
+ void freeze()
+ {
+ m_xTreeView->freeze();
+ m_bFreeze = true;
+ }
+
+ void thaw()
+ {
+ m_xTreeView->thaw();
+ m_bFreeze = false;
+ }
+
+ void LaunchAsyncStoreNavigatorSettings();
+
+ DECL_LINK(ContentDoubleClickHdl, weld::TreeView&, bool);
+ DECL_LINK(MouseReleaseHdl, const MouseEvent&, bool);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(AsyncStoreNavigatorSettings, void*, void);
+ DECL_LINK(CommandHdl, const CommandEvent&, bool);
+ DECL_LINK(QueryTooltipHdl, const weld::TreeIter&, OUString);
+ DECL_LINK(DragBeginHdl, bool&, bool);
+
+public:
+ ScContentTree(std::unique_ptr<weld::TreeView> xTreeView, ScNavigatorDlg* pNavigatorDlg);
+ ~ScContentTree();
+
+ void SetNavigatorDlgFlag(bool isInNavigateDlg){ bIsInNavigatorDlg=isInNavigateDlg;};
+
+ void hide()
+ {
+ m_xTreeView->hide();
+ }
+
+ void show()
+ {
+ m_xTreeView->show();
+ }
+
+ void Refresh( ScContentId nType = ScContentId::ROOT );
+
+ void ToggleRoot();
+ void SetRootType( ScContentId nNew );
+ ScContentId GetRootType() const { return nRootType; }
+
+ // return true if Refresh was called to allow detecting that the navigator
+ // tree is now up to date
+ bool ActiveDocChanged();
+ void ResetManualDoc();
+ void SetManualDoc(const OUString& rName);
+ void LoadFile(const OUString& rUrl);
+ void SelectDoc(const OUString& rName);
+ void SelectEntryByName(const ScContentId nRoot, std::u16string_view rName);
+
+ const OUString& GetHiddenTitle() const { return aHiddenTitle; }
+
+ /** Applies the navigator settings to the listbox. */
+ void ApplyNavigatorSettings();
+ /** Stores the current listbox state in the navigator settings. */
+ void StoreNavigatorSettings();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/corodlg.hxx b/sc/source/ui/inc/corodlg.hxx
new file mode 100644
index 000000000..68e5fd0f1
--- /dev/null
+++ b/sc/source/ui/inc/corodlg.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 <vcl/weld.hxx>
+
+class ScColRowLabelDlg : public weld::GenericDialogController
+{
+public:
+ ScColRowLabelDlg(weld::Window* pParent, bool bCol, bool bRow)
+ : GenericDialogController(pParent, "modules/scalc/ui/changesourcedialog.ui",
+ "ChangeSourceDialog")
+ , m_xBtnRow(m_xBuilder->weld_check_button("row"))
+ , m_xBtnCol(m_xBuilder->weld_check_button("col"))
+ {
+ m_xBtnCol->set_active(bCol);
+ m_xBtnRow->set_active(bRow);
+ }
+
+ bool IsCol() const { return m_xBtnCol->get_active(); }
+ bool IsRow() const { return m_xBtnRow->get_active(); }
+
+private:
+ std::unique_ptr<weld::CheckButton> m_xBtnRow;
+ std::unique_ptr<weld::CheckButton> m_xBtnCol;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/crdlg.hxx b/sc/source/ui/inc/crdlg.hxx
new file mode 100644
index 000000000..56e16c5c8
--- /dev/null
+++ b/sc/source/ui/inc/crdlg.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 <vcl/weld.hxx>
+
+class ScColOrRowDlg : public weld::GenericDialogController
+{
+public:
+ ScColOrRowDlg(weld::Window* pParent, const OUString& rStrTitle, const OUString& rStrLabel);
+ virtual ~ScColOrRowDlg() override;
+
+private:
+ std::unique_ptr<weld::Frame> m_xFrame;
+ std::unique_ptr<weld::RadioButton> m_xBtnRows;
+ std::unique_ptr<weld::RadioButton> m_xBtnCols;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+
+ DECL_LINK(OkHdl, weld::Button&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/crnrdlg.hxx b/sc/source/ui/inc/crnrdlg.hxx
new file mode 100644
index 000000000..5bff6d2e8
--- /dev/null
+++ b/sc/source/ui/inc/crnrdlg.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 "anyrefdg.hxx"
+#include <rangelst.hxx>
+
+#include <unordered_map>
+
+class ScViewData;
+class ScDocument;
+
+class ScColRowNameRangesDlg : public ScAnyRefDlgController
+{
+public:
+ ScColRowNameRangesDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScViewData& rViewData);
+ virtual ~ScColRowNameRangesDlg() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+
+ virtual bool IsRefInputMode() const override;
+ virtual void SetActive() override;
+ virtual void Close() override;
+
+private:
+ ScRange theCurArea;
+ ScRange theCurData;
+
+ ScRangePairListRef xColNameRanges;
+ ScRangePairListRef xRowNameRanges;
+
+ typedef std::unordered_map< OUString, ScRange > NameRangeMap;
+ NameRangeMap aRangeMap;
+ ScViewData& m_rViewData;
+ ScDocument& rDoc;
+ bool bDlgLostFocus;
+
+ formula::RefEdit* m_pEdActive;
+ std::unique_ptr<weld::TreeView> m_xLbRange;
+
+ std::unique_ptr<formula::RefEdit> m_xEdAssign;
+ std::unique_ptr<formula::RefButton> m_xRbAssign;
+ std::unique_ptr<weld::RadioButton> m_xBtnColHead;
+ std::unique_ptr<weld::RadioButton> m_xBtnRowHead;
+ std::unique_ptr<formula::RefEdit> m_xEdAssign2;
+ std::unique_ptr<formula::RefButton> m_xRbAssign2;
+
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+ std::unique_ptr<weld::Button> m_xBtnAdd;
+ std::unique_ptr<weld::Button> m_xBtnRemove;
+
+ std::unique_ptr<weld::Frame> m_xRangeFrame;
+ std::unique_ptr<weld::Label> m_xRangeFT;
+ std::unique_ptr<weld::Label> m_xDataFT;
+
+ void Init ();
+ void UpdateNames ();
+ void UpdateRangeData ( const ScRange& rRange, bool bColName );
+ void SetColRowData( const ScRange& rLabelRange, bool bRef=false);
+ void AdjustColRowData( const ScRange& rDataRange, bool bRef=false);
+ DECL_LINK( CancelBtnHdl, weld::Button&, void );
+ DECL_LINK( OkBtnHdl, weld::Button&, void );
+ DECL_LINK( AddBtnHdl, weld::Button&, void );
+ DECL_LINK( RemoveBtnHdl, weld::Button&, void );
+ DECL_LINK( Range1SelectHdl, weld::TreeView&, void );
+ DECL_LINK( Range1DataModifyHdl, formula::RefEdit&, void );
+ DECL_LINK( ColRowToggleHdl, weld::Toggleable&, void );
+ DECL_LINK( Range2DataModifyHdl, formula::RefEdit&, void );
+ DECL_LINK( GetEditFocusHdl, formula::RefEdit&, void );
+ DECL_LINK( LoseEditFocusHdl, formula::RefEdit&, void );
+ DECL_LINK( GetButtonFocusHdl, formula::RefButton&, void );
+ DECL_LINK( LoseButtonFocusHdl, formula::RefButton&, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/csvcontrol.hxx b/sc/source/ui/inc/csvcontrol.hxx
new file mode 100644
index 000000000..8da12e378
--- /dev/null
+++ b/sc/source/ui/inc/csvcontrol.hxx
@@ -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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <scdllapi.h>
+#include <address.hxx>
+#include "csvsplits.hxx"
+#include <o3tl/typed_flags_set.hxx>
+#include <rtl/ref.hxx>
+#include <vcl/customweld.hxx>
+#include "AccessibleCsvControl.hxx"
+
+namespace com::sun::star::accessibility { class XAccessible; }
+
+/** Minimum character count for a column in separators mode. */
+const sal_Int32 CSV_MINCOLWIDTH = 8;
+/** Maximum length of a cell string. */
+const sal_Int32 CSV_MAXSTRLEN = 0x7FFF;
+/** Transparency for header color of selected columns. */
+const sal_uInt16 CSV_HDR_TRANSPARENCY = 85;
+/** Minimum distance to border for auto scroll. */
+const sal_Int32 CSV_SCROLL_DIST = 3;
+
+//! TODO make string array dynamic
+const sal_Int32 CSV_PREVIEW_LINES = 32; // maximum count of preview lines
+/** Maximum count of columns. */
+const sal_Int32 CSV_MAXCOLCOUNT = MAXCOLCOUNT;
+
+/** Default column data type. */
+const sal_Int32 CSV_TYPE_DEFAULT = 0;
+/** Multi selection with different types. */
+const sal_Int32 CSV_TYPE_MULTI = -1;
+/** No column selected. */
+const sal_Int32 CSV_TYPE_NOSELECTION = -2;
+
+// External used column types.
+const sal_uInt8 SC_COL_STANDARD = 1;
+const sal_uInt8 SC_COL_TEXT = 2;
+const sal_uInt8 SC_COL_MDY = 3;
+const sal_uInt8 SC_COL_DMY = 4;
+const sal_uInt8 SC_COL_YMD = 5;
+const sal_uInt8 SC_COL_SKIP = 9;
+const sal_uInt8 SC_COL_ENGLISH = 10;
+
+/** Exported data of a column (data used in the dialog). */
+struct ScCsvExpData
+{
+ sal_Int32 mnIndex; /// Index of a column.
+ sal_uInt8 mnType; /// External type of the column.
+
+ ScCsvExpData() : mnIndex( 0 ), mnType( SC_COL_STANDARD ) {}
+ ScCsvExpData( sal_Int32 nIndex, sal_uInt8 nType ) :
+ mnIndex( nIndex ), mnType( nType ) {}
+};
+
+typedef ::std::vector< ScCsvExpData > ScCsvExpDataVec;
+
+/** Specifies which element should be used to perform an action. */
+enum ScMoveMode
+{
+ MOVE_NONE, /// No action.
+ MOVE_FIRST, /// First element in current context.
+ MOVE_LAST, /// Last element in current context.
+ MOVE_PREV, /// Predecessor of current element in current context.
+ MOVE_NEXT, /// Successor of current element in current context.
+ MOVE_PREVPAGE, /// Previous page relative to current context.
+ MOVE_NEXTPAGE /// Next page relative to current context.
+};
+
+/** Flags for comparison of old and new control layout data. */
+enum class ScCsvDiff : sal_uInt32 {
+ Equal = 0x0000,
+ PosCount = 0x0001,
+ PosOffset = 0x0002,
+ HeaderWidth = 0x0004,
+ CharWidth = 0x0008,
+ LineCount = 0x0010,
+ LineOffset = 0x0020,
+ HeaderHeight = 0x0040,
+ LineHeight = 0x0080,
+ RulerCursor = 0x0100,
+ GridCursor = 0x0200,
+
+ HorizontalMask = PosCount | PosOffset | HeaderWidth | CharWidth,
+ VerticalMask = LineCount | LineOffset | HeaderHeight | LineHeight
+};
+namespace o3tl {
+ template<> struct typed_flags<ScCsvDiff> : is_typed_flags<ScCsvDiff, 0x03ff> {};
+}
+
+
+/** A structure containing all layout data valid for both ruler and data grid
+ (i.e. scroll position or column width). */
+struct ScCsvLayoutData
+{
+ // horizontal settings
+ sal_Int32 mnPosCount; /// Number of positions.
+ sal_Int32 mnPosOffset; /// Horizontal scroll offset.
+
+ sal_Int32 mnWinWidth; /// Width of ruler and data grid.
+ sal_Int32 mnHdrWidth; /// Width of the header column.
+ sal_Int32 mnCharWidth; /// Pixel width of one character.
+
+ // vertical settings
+ sal_Int32 mnLineCount; /// Number of data lines.
+ sal_Int32 mnLineOffset; /// Index of first visible line (0-based).
+
+ sal_Int32 mnWinHeight; /// Height of entire data grid (incl. header).
+ sal_Int32 mnHdrHeight; /// Height of the header line.
+ sal_Int32 mnLineHeight; /// Height of a data line.
+
+ // cursor settings
+ sal_Int32 mnPosCursor; /// Position of ruler cursor.
+ sal_Int32 mnColCursor; /// Position of grid column cursor.
+
+ mutable sal_Int32 mnNoRepaint; /// >0 = no repaint.
+ bool mbAppRTL; /// true = application in RTL mode.
+
+ explicit ScCsvLayoutData();
+
+ /** Returns differences to rData.
+ @descr For each difference the appropriate bit is set in the returned value. */
+ ScCsvDiff GetDiff( const ScCsvLayoutData& rData ) const;
+};
+
+inline bool operator==( const ScCsvLayoutData& rData1, const ScCsvLayoutData& rData2 )
+{
+ return rData1.GetDiff( rData2 ) == ScCsvDiff::Equal;
+}
+
+inline bool operator!=( const ScCsvLayoutData& rData1, const ScCsvLayoutData& rData2 )
+{
+ return !(rData1 == rData2);
+}
+
+/** Enumeration of possible commands to change any settings of the CSV controls.
+ @descr Controls have to send commands instead of changing their settings directly.
+ This helps to keep the different controls consistent to each other.
+ A command can contain 0 to 2 sal_Int32 parameters. In the description of each
+ command the required parameters are shown in brackets. [-] means no parameter. */
+enum ScCsvCmdType
+{
+ // misc
+ CSVCMD_NONE, /// No command. [-]
+ CSVCMD_REPAINT, /// Repaint all controls. [-]
+
+ // modify horizontal dimensions
+ CSVCMD_SETPOSCOUNT, /// Change position/column count. [character count]
+ CSVCMD_SETPOSOFFSET, /// Change position offset (scroll pos). [position]
+ CSVCMD_SETHDRWIDTH, /// Change width of the header column. [width in pixel]
+ CSVCMD_SETCHARWIDTH, /// Change character pixel width. [width in pixel]
+
+ // modify vertical dimensions
+ CSVCMD_SETLINECOUNT, /// Change number of data lines. [line count]
+ CSVCMD_SETLINEOFFSET, /// Change first visible line. [line index]
+ CSVCMD_SETHDRHEIGHT, /// Change height of top header line. [height in pixel]
+ CSVCMD_SETLINEHEIGHT, /// Change data line pixel height. [height in pixel}
+
+ // cursors/positions
+ CSVCMD_MOVERULERCURSOR, /// Move ruler cursor to new position. [position]
+ CSVCMD_MOVEGRIDCURSOR, /// Move data grid cursor to new column. [position]
+ CSVCMD_MAKEPOSVISIBLE, /// Move to make passed position visible (for mouse tracking). [position]
+
+ // table contents
+ CSVCMD_NEWCELLTEXTS, /// Recalculate splits and cell texts. [-]
+ CSVCMD_UPDATECELLTEXTS, /// Update cell texts with current split settings. [-]
+ CSVCMD_SETCOLUMNTYPE, /// Change data type of selected columns. [column type]
+ CSVCMD_EXPORTCOLUMNTYPE, /// Send selected column type to external controls. [-]
+ CSVCMD_SETFIRSTIMPORTLINE, /// Set number of first imported line. [line index]
+
+ // splits
+ CSVCMD_INSERTSPLIT, /// Insert a split. [position]
+ CSVCMD_REMOVESPLIT, /// Remove a split. [position]
+ CSVCMD_TOGGLESPLIT, /// Inserts or removes a split. [position]
+ CSVCMD_MOVESPLIT, /// Move a split. [old position, new position]
+ CSVCMD_REMOVEALLSPLITS /// Remove all splits. [-]
+};
+
+/** Data for a CSV control command. The stored position data is always character based,
+ it's never a column index (required for internal consistency). */
+class ScCsvCmd
+{
+private:
+ ScCsvCmdType meType; /// The command.
+ sal_Int32 mnParam1; /// First parameter.
+ sal_Int32 mnParam2; /// Second parameter.
+
+public:
+ explicit ScCsvCmd() : meType( CSVCMD_NONE ),
+ mnParam1( CSV_POS_INVALID ), mnParam2( CSV_POS_INVALID ) {}
+
+ inline void Set( ScCsvCmdType eType, sal_Int32 nParam1, sal_Int32 nParam2 );
+
+ ScCsvCmdType GetType() const { return meType; }
+ sal_Int32 GetParam1() const { return mnParam1; }
+ sal_Int32 GetParam2() const { return mnParam2; }
+};
+
+inline void ScCsvCmd::Set( ScCsvCmdType eType, sal_Int32 nParam1, sal_Int32 nParam2 )
+{
+ meType = eType; mnParam1 = nParam1; mnParam2 = nParam2;
+}
+
+/** Base class for the CSV ruler and the data grid control. Implements command handling. */
+class SC_DLLPUBLIC ScCsvControl : public weld::CustomWidgetController
+{
+private:
+ Link<ScCsvControl&,void> maCmdHdl; /// External command handler.
+ ScCsvCmd maCmd; /// Data of last command.
+ const ScCsvLayoutData& mrData; /// Shared layout data.
+
+ bool mbValidGfx; /// Content of virtual devices valid?
+
+protected:
+ rtl::Reference<ScAccessibleCsvControl> mxAccessible; /// Reference to the accessible implementation object.
+
+public:
+ explicit ScCsvControl(const ScCsvLayoutData& rData);
+ virtual ~ScCsvControl() override;
+
+ // event handling ---------------------------------------------------------
+
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+
+ /** Sends a GetFocus or LoseFocus event to the accessibility object. */
+ void AccSendFocusEvent( bool bFocused );
+ /** Sends a caret changed event to the accessibility object. */
+ void AccSendCaretEvent();
+ /** Sends a visible area changed event to the accessibility object. */
+ void AccSendVisibleEvent();
+ /** Sends a selection changed event to the accessibility object. */
+ void AccSendSelectionEvent();
+ /** Sends a table model changed event for changed cell contents to the accessibility object. */
+ void AccSendTableUpdateEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn, bool bAllRows = true );
+ /** Sends a table model changed event for an inserted column to the accessibility object. */
+ void AccSendInsertColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn );
+ /** Sends a table model changed event for a removed column to the accessibility object. */
+ void AccSendRemoveColumnEvent( sal_uInt32 nFirstColumn, sal_uInt32 nLastColumn );
+
+ ScAccessibleCsvControl* GetAccessible() { return mxAccessible.get(); }
+
+ // repaint helpers --------------------------------------------------------
+
+ /** Sets the graphic invalid (next Redraw() will not use cached graphic). */
+ void InvalidateGfx() { mbValidGfx = false; }
+ /** Sets the graphic valid (next Redraw() will use cached graphic). */
+ void ValidateGfx() { mbValidGfx = true; }
+ /** Returns true, if cached graphic is valid. */
+ bool IsValidGfx() const { return mbValidGfx; }
+
+ /** Repaints all controls.
+ @param bInvalidate true = invalidates graphics of this control (not all). */
+ void Repaint( bool bInvalidate = false );
+ /** Increases no-repaint counter (controls do not repaint until the last EnableRepaint()). */
+ void DisableRepaint();
+ /** Decreases no-repaint counter and repaints if counter reaches 0. */
+ void EnableRepaint();
+ /** Returns true, if controls will not repaint. */
+ bool IsNoRepaint() const { return mrData.mnNoRepaint > 0; }
+
+ // command handling -------------------------------------------------------
+
+ /** Sets a new command handler. */
+ void SetCmdHdl( const Link<ScCsvControl&,void>& rHdl ) { maCmdHdl = rHdl; }
+ /** Returns data of the last command. */
+ const ScCsvCmd& GetCmd() const { return maCmd; }
+
+ /** Executes a command by calling command handler. */
+ void Execute(
+ ScCsvCmdType eType,
+ sal_Int32 nParam1 = CSV_POS_INVALID,
+ sal_Int32 nParam2 = CSV_POS_INVALID );
+
+ // layout helpers ---------------------------------------------------------
+
+ /** Returns a reference to the current layout data. */
+ const ScCsvLayoutData& GetLayoutData() const { return mrData; }
+ /** Returns true, if the Right-to-Left layout mode is active. */
+ bool IsRTL() const { return mrData.mbAppRTL; }
+
+ /** Returns the number of available positions. */
+ sal_Int32 GetPosCount() const { return mrData.mnPosCount; }
+ /** Returns the number of visible positions. */
+ sal_Int32 GetVisPosCount() const;
+ /** Returns the first visible position. */
+ sal_Int32 GetFirstVisPos() const { return mrData.mnPosOffset; }
+ /** Returns the last visible position. */
+ sal_Int32 GetLastVisPos() const { return GetFirstVisPos() + GetVisPosCount(); }
+ /** Returns highest possible position for first visible character. */
+ sal_Int32 GetMaxPosOffset() const;
+
+ /** Returns true, if it is allowed to set a split at nPos. */
+ bool IsValidSplitPos( sal_Int32 nPos ) const;
+ /** Returns true, if nPos is an allowed AND visible split position. */
+ bool IsVisibleSplitPos( sal_Int32 nPos ) const;
+
+ /** Returns the width of the header column. */
+ sal_Int32 GetHdrWidth() const { return mrData.mnHdrWidth; }
+ /** Returns the width of one character column. */
+ sal_Int32 GetCharWidth() const { return mrData.mnCharWidth; }
+ /** Returns the start position of the header column. */
+ sal_Int32 GetHdrX() const;
+ /** Returns the X position of the first pixel of the data area. */
+ sal_Int32 GetFirstX() const;
+ /** Returns the X position of the last pixel of the data area. */
+ sal_Int32 GetLastX() const;
+ /** Returns output X coordinate of the specified position. */
+ sal_Int32 GetX( sal_Int32 nPos ) const;
+ /** Returns position from output coordinate. */
+ sal_Int32 GetPosFromX( sal_Int32 nX ) const;
+
+ /** Returns the number of data lines. */
+ sal_Int32 GetLineCount() const { return mrData.mnLineCount; }
+ /** Returns the number of visible lines (including partly visible bottom line). */
+ sal_Int32 GetVisLineCount() const;
+ /** Returns index of first visible line. */
+ sal_Int32 GetFirstVisLine() const { return mrData.mnLineOffset; }
+ /** Returns index of last visible line. */
+ sal_Int32 GetLastVisLine() const;
+ /** Returns highest possible index for first line. */
+ sal_Int32 GetMaxLineOffset() const;
+
+ /** Returns true, if nLine is a valid line index. */
+ bool IsValidLine( sal_Int32 nLine ) const;
+ /** Returns true, if nLine is a valid and visible line index. */
+ bool IsVisibleLine( sal_Int32 nLine ) const;
+
+ /** Returns the height of the header line. */
+ sal_Int32 GetHdrHeight() const { return mrData.mnHdrHeight; }
+ /** Returns the height of one line. */
+ sal_Int32 GetLineHeight() const { return mrData.mnLineHeight; }
+ /** Returns output Y coordinate of the specified line. */
+ sal_Int32 GetY( sal_Int32 nLine ) const;
+ /** Returns line index from output coordinate. */
+ sal_Int32 GetLineFromY( sal_Int32 nY ) const;
+
+ /** Returns the ruler cursor position. */
+ sal_Int32 GetRulerCursorPos() const { return mrData.mnPosCursor; }
+ /** Returns the data grid cursor position (not column index!). */
+ sal_Int32 GetGridCursorPos() const { return mrData.mnColCursor; }
+
+ // static helpers ---------------------------------------------------------
+
+ /** Inverts a rectangle in the specified output device. */
+ static void ImplInvertRect( OutputDevice& rOutDev, const tools::Rectangle& rRect );
+
+ /** Returns direction code for the keys LEFT, RIGHT, HOME, END.
+ @param bHomeEnd false = ignore HOME and END key. */
+ static ScMoveMode GetHorzDirection( sal_uInt16 nCode, bool bHomeEnd );
+ /** Returns direction code for the keys UP, DOWN, HOME, END, PAGE UP, PAGE DOWN.
+ @param bHomeEnd false = ignore HOME and END key. */
+ static ScMoveMode GetVertDirection( sal_uInt16 nCode, bool bHomeEnd );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/csvgrid.hxx b/sc/source/ui/inc/csvgrid.hxx
new file mode 100644
index 000000000..c729d9815
--- /dev/null
+++ b/sc/source/ui/inc/csvgrid.hxx
@@ -0,0 +1,315 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/virdev.hxx>
+#include <unotools/options.hxx>
+
+#include <vector>
+#include <memory>
+#include <scdllapi.h>
+#include <editutil.hxx>
+#include "csvcontrol.hxx"
+#include "csvsplits.hxx"
+
+namespace svtools { class ColorConfig; }
+class EditEngine;
+class ScAsciiOptions;
+class ScAccessibleCsvControl;
+class ScCsvTableBox;
+
+const sal_uInt32 CSV_COLUMN_INVALID = CSV_VEC_NOTFOUND;
+
+/** This struct contains the state of one table column. */
+struct ScCsvColState
+{
+ sal_Int32 mnType; /// Data type.
+ bool mbColumnSelected;
+
+ explicit ScCsvColState( sal_Int32 nType = CSV_TYPE_DEFAULT ) :
+ mnType( nType ), mbColumnSelected( false ) {}
+
+ bool IsSelected() const { return mbColumnSelected; }
+ void Select( bool bSel ) { mbColumnSelected = bSel; }
+};
+
+typedef ::std::vector< ScCsvColState > ScCsvColStateVec;
+
+/** A data grid control for the CSV import dialog. The design of this control
+ simulates a Calc spreadsheet with row and column headers. */
+class SC_DLLPUBLIC ScCsvGrid : public ScCsvControl, public utl::ConfigurationListener
+{
+private:
+ ScCsvTableBox* mpTableBox; /// Grid Parent
+ VclPtr<VirtualDevice> mpBackgrDev; /// Grid background, headers, cell texts.
+ VclPtr<VirtualDevice> mpGridDev; /// Data grid with selection and cursor.
+ std::unique_ptr<weld::Menu> mxPopup; /// Popup menu for column types.
+
+ ::svtools::ColorConfig* mpColorConfig; /// Application color configuration.
+ Color maBackColor; /// Cell background color.
+ Color maGridColor; /// Table grid color.
+ Color maGridPBColor; /// Grid color for "first imported line" delimiter.
+ Color maAppBackColor; /// Background color for unused area.
+ Color maTextColor; /// Text color for data area.
+ Color maHeaderBackColor; /// Background color for headers.
+ Color maHeaderGridColor; /// Grid color for headers.
+ Color maHeaderTextColor; /// Text color for headers.
+ Color maSelectColor; /// Header color of selected columns.
+
+ std::unique_ptr< ScEditEngineDefaulter >
+ mpEditEngine; /// For drawing cell texts.
+ vcl::Font maHeaderFont; /// Font for column and row headers.
+ vcl::Font maMonoFont; /// Monospace font for data cells.
+ Size maWinSize; /// Size of the control.
+ Size maEdEngSize; /// Paper size for edit engine.
+
+ ScCsvSplits maSplits; /// Vector with split positions.
+ ScCsvColStateVec maColStates; /// State of each column.
+ std::vector<OUString> maTypeNames; /// UI names of data types.
+ std::vector< std::vector<OUString> > maTexts; /// 2D-vector for cell texts.
+
+ sal_Int32 mnFirstImpLine; /// First imported line (0-based).
+ sal_uInt32 mnRecentSelCol; /// Index of most recently selected column.
+ sal_uInt32 mnMTCurrCol; /// Current column of mouse tracking.
+ bool mbTracking; /// True if Mouse tracking
+ bool mbMTSelecting; /// Mouse tracking mode: true = select, false = deselect.
+
+public:
+ explicit ScCsvGrid(const ScCsvLayoutData& rData, std::unique_ptr<weld::Menu> xPopup, ScCsvTableBox* pTableBox);
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ ScCsvTableBox* GetTableBox() { return mpTableBox; }
+ virtual ~ScCsvGrid() override;
+
+ /** Finishes initialization. Must be called after constructing a new object. */
+ void Init();
+
+ // common grid handling ---------------------------------------------------
+public:
+ /** Updates layout data dependent from the control's state. */
+ void UpdateLayoutData();
+ /** Updates X coordinate of first visible position dependent from line numbers. */
+ void UpdateOffsetX();
+ /** Apply current layout data to the grid control. */
+ void ApplyLayout( const ScCsvLayoutData& rOldData );
+ /** Sets the number of the first imported line (for visual feedback). nLine is 0-based! */
+ void SetFirstImportedLine( sal_Int32 nLine );
+
+ /** Finds a column position nearest to nPos which does not cause scrolling the visible area. */
+ sal_Int32 GetNoScrollCol( sal_Int32 nPos ) const;
+
+private:
+ /** Reads colors from system settings. */
+ SAL_DLLPRIVATE void InitColors();
+ /** Initializes all font settings. */
+ SAL_DLLPRIVATE void InitFonts();
+ /** Initializes all data dependent from the control's size. */
+ SAL_DLLPRIVATE void InitSizeData();
+
+ // split handling ---------------------------------------------------------
+public:
+ /** Inserts a split. */
+ void InsertSplit( sal_Int32 nPos );
+ /** Removes a split. */
+ void RemoveSplit( sal_Int32 nPos );
+ /** Inserts a new or removes an existing split. */
+ void MoveSplit( sal_Int32 nPos, sal_Int32 nNewPos );
+ /** Removes all splits. */
+ void RemoveAllSplits();
+ /** Removes all splits and inserts the splits from rSplits. */
+ void SetSplits( const ScCsvSplits& rSplits );
+
+private:
+ /** Inserts a split and adjusts column data. */
+ SAL_DLLPRIVATE bool ImplInsertSplit( sal_Int32 nPos );
+ /** Removes a split and adjusts column data. */
+ SAL_DLLPRIVATE bool ImplRemoveSplit( sal_Int32 nPos );
+ /** Clears the split array and re-inserts boundary splits. */
+ SAL_DLLPRIVATE void ImplClearSplits();
+
+ // columns/column types ---------------------------------------------------
+public:
+ /** Returns the number of columns. */
+ sal_uInt32 GetColumnCount() const { return maColStates.size(); }
+ /** Returns the index of the first visible column. */
+ sal_uInt32 GetFirstVisColumn() const;
+ /** Returns the index of the last visible column. */
+ sal_uInt32 GetLastVisColumn() const;
+
+ /** Returns true, if nColIndex points to an existing column. */
+ bool IsValidColumn( sal_uInt32 nColIndex ) const;
+ /** Returns true, if column with index nColIndex is (at least partly) visible. */
+ bool IsVisibleColumn( sal_uInt32 nColIndex ) const;
+
+ /** Returns X coordinate of the specified column. */
+ sal_Int32 GetColumnX( sal_uInt32 nColIndex ) const;
+ /** Returns column index from output coordinate. */
+ sal_uInt32 GetColumnFromX( sal_Int32 nX ) const;
+
+ /** Returns start position of the column with the specified index. */
+ sal_Int32 GetColumnPos( sal_uInt32 nColIndex ) const { return maSplits[ nColIndex ]; }
+ /** Returns column index from position. A split counts to its following column. */
+ sal_uInt32 GetColumnFromPos( sal_Int32 nPos ) const;
+ /** Returns the character width of the column with the specified index. */
+ sal_Int32 GetColumnWidth( sal_uInt32 nColIndex ) const;
+
+ /** Returns the vector with the states of all columns. */
+ const ScCsvColStateVec& GetColumnStates() const { return maColStates; }
+ /** Sets all column states to the values in the passed vector. */
+ void SetColumnStates( ScCsvColStateVec&& rColStates );
+ /** Returns the data type of the selected columns. */
+ sal_Int32 GetSelColumnType() const;
+ /** Changes the data type of all selected columns. */
+ void SetSelColumnType( sal_Int32 nType );
+ /** Sets new UI data type names. */
+ void SetTypeNames( std::vector<OUString>&& rTypeNames );
+ /** Returns the UI type name of the specified column. */
+ OUString GetColumnTypeName( sal_uInt32 nColIndex ) const;
+
+ /** Fills the options object with column data for separators mode. */
+ void FillColumnDataSep( ScAsciiOptions& rOptions ) const;
+ /** Fills the options object with column data for fixed width mode. */
+ void FillColumnDataFix( ScAsciiOptions& rOptions ) const;
+
+private:
+ /** Returns the data type of the specified column. */
+ SAL_DLLPRIVATE sal_Int32 GetColumnType( sal_uInt32 nColIndex ) const;
+ /** Sets the data type of the specified column. */
+ SAL_DLLPRIVATE void SetColumnType( sal_uInt32 nColIndex, sal_Int32 nColType );
+
+ /** Scrolls data grid vertically. */
+ SAL_DLLPRIVATE void ScrollVertRel( ScMoveMode eDir );
+ /** Executes the data type popup menu. */
+ SAL_DLLPRIVATE void ExecutePopup( const Point& rPos );
+
+ // selection handling -----------------------------------------------------
+public:
+ /** Returns true, if the specified column is selected. */
+ bool IsSelected( sal_uInt32 nColIndex ) const;
+ /** Returns index of the first selected column. */
+ sal_uInt32 GetFirstSelected() const;
+ /** Returns index of the first selected column really after nFromIndex. */
+ sal_uInt32 GetNextSelected( sal_uInt32 nFromIndex ) const;
+ /** Selects or deselects the specified column. */
+ void Select( sal_uInt32 nColIndex, bool bSelect = true );
+ /** Toggles selection of the specified column. */
+ void ToggleSelect( sal_uInt32 nColIndex );
+ /** Selects or deselects the specified column range. */
+ void SelectRange( sal_uInt32 nColIndex1, sal_uInt32 nColIndex2, bool bSelect = true );
+ /** Selects or deselects all columns. */
+ void SelectAll( bool bSelect = true );
+
+ /** Returns index of the focused column. */
+ sal_uInt32 GetFocusColumn() const { return GetColumnFromPos( GetGridCursorPos() ); }
+
+private:
+ /** Moves column cursor to a new position. */
+ SAL_DLLPRIVATE void MoveCursor( sal_uInt32 nColIndex );
+ /** Moves column cursor to the given direction. */
+ SAL_DLLPRIVATE void MoveCursorRel( ScMoveMode eDir );
+
+ /** Clears the entire selection without notify. */
+ SAL_DLLPRIVATE void ImplClearSelection();
+
+ /** Executes selection action for a specific column. */
+ SAL_DLLPRIVATE void DoSelectAction( sal_uInt32 nColIndex, sal_uInt16 nModifier );
+
+ // cell contents ----------------------------------------------------------
+public:
+ /** Fills all cells of a line with the passed text (separators mode). */
+ void ImplSetTextLineSep(
+ sal_Int32 nLine, const OUString& rTextLine,
+ const OUString& rSepChars, sal_Unicode cTextSep, bool bMergeSep, bool bRemoveSpace = false );
+ /** Fills all cells of a line with the passed text (fixed width mode). */
+ void ImplSetTextLineFix( sal_Int32 nLine, const OUString& rTextLine );
+
+ /** Returns the text of the specified cell. */
+ OUString GetCellText( sal_uInt32 nColIndex, sal_Int32 nLine ) const;
+
+ // event handling ---------------------------------------------------------
+protected:
+ virtual void Resize() override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+
+ virtual bool MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual bool MouseMove( const MouseEvent& rMEvt ) override;
+ virtual bool MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual bool KeyInput( const KeyEvent& rKEvt ) override;
+ virtual bool Command( const CommandEvent& rCEvt ) override;
+
+ virtual tools::Rectangle GetFocusRect() override;
+
+ virtual void StyleUpdated() override;
+
+ virtual void ConfigurationChanged( ::utl::ConfigurationBroadcaster*, ConfigurationHints ) override;
+
+ // painting ---------------------------------------------------------------
+protected:
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& ) override;
+
+public:
+ /** Redraws the entire data grid. */
+ void ImplRedraw(vcl::RenderContext& rRenderContext);
+ /** Returns a pointer to the used edit engine. */
+ EditEngine* GetEditEngine();
+
+private:
+ /** Returns the width of the control. */
+ sal_Int32 GetWidth() const { return maWinSize.Width(); }
+ /** Returns the height of the control. */
+ sal_Int32 GetHeight() const { return maWinSize.Height(); }
+
+ /** Sets a clip region in the specified output device for the specified column. */
+ SAL_DLLPRIVATE void ImplSetColumnClipRegion( OutputDevice& rOutDev, sal_uInt32 nColIndex );
+ /** Draws the header of the specified column to the specified output device. */
+ SAL_DLLPRIVATE void ImplDrawColumnHeader( OutputDevice& rOutDev, sal_uInt32 nColIndex, Color aFillColor );
+
+ /** Draws the text at the specified position to maBackgrDev. */
+ SAL_DLLPRIVATE void ImplDrawCellText( const Point& rPos, const OUString& rText );
+ /** Draws the "first imported line" separator to maBackgrDev (or erases, if bSet is false). */
+ SAL_DLLPRIVATE void ImplDrawFirstLineSep( bool bSet );
+ /** Draws the column with index nColIndex to maBackgrDev. */
+ SAL_DLLPRIVATE void ImplDrawColumnBackgr( sal_uInt32 nColIndex );
+ /** Draws the row headers column to maBackgrDev. */
+ SAL_DLLPRIVATE void ImplDrawRowHeaders();
+ /** Draws all columns and the row headers column to maBackgrDev. */
+ SAL_DLLPRIVATE void ImplDrawBackgrDev();
+
+ /** Draws the column with index nColIndex with its selection state to maGridDev. */
+ SAL_DLLPRIVATE void ImplDrawColumnSelection( sal_uInt32 nColIndex );
+ /** Draws all columns with selection and cursor to maGridDev. */
+ SAL_DLLPRIVATE void ImplDrawGridDev();
+
+ /** Redraws the entire column (background and selection). */
+ SAL_DLLPRIVATE void ImplDrawColumn( sal_uInt32 nColIndex );
+
+ /** Optimized drawing: Scrolls horizontally and redraws only missing parts. */
+ SAL_DLLPRIVATE void ImplDrawHorzScrolled( sal_Int32 nOldPos );
+
+ /** Inverts the cursor bar at the specified position in maGridDev. */
+ SAL_DLLPRIVATE void ImplInvertCursor( sal_Int32 nPos );
+
+ // accessibility ----------------------------------------------------------
+protected:
+ /** Creates a new accessible object. */
+ virtual css::uno::Reference<css::accessibility::XAccessible> CreateAccessible() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/csvruler.hxx b/sc/source/ui/inc/csvruler.hxx
new file mode 100644
index 000000000..5173f0d20
--- /dev/null
+++ b/sc/source/ui/inc/csvruler.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 "csvcontrol.hxx"
+#include "csvsplits.hxx"
+
+#include <vcl/virdev.hxx>
+
+class ScAccessibleCsvControl;
+class ScCsvTableBox;
+
+/** A ruler control for the CSV import dialog. Supports setting and moving
+ splits (which divide lines of data into several columns). */
+class ScCsvRuler : public ScCsvControl
+{
+private:
+ ScCsvTableBox* mpTableBox; /// Grid Parent
+
+ ScopedVclPtrInstance<VirtualDevice> maBackgrDev;/// Ruler background, scaling.
+ ScopedVclPtrInstance<VirtualDevice> maRulerDev; /// Ruler with splits and cursor.
+
+ Color maBackColor; /// Background color.
+ Color maActiveColor; /// Color for active part of ruler.
+ Color maTextColor; /// Text and scale color.
+ Color maSplitColor; /// Split area color.
+
+ ScCsvSplits maSplits; /// Vector with split positions.
+ ScCsvSplits maOldSplits; /// Old state for cancellation.
+
+ sal_Int32 mnPosCursorLast; /// Last valid position of cursor.
+ sal_Int32 mnPosMTStart; /// Start position of mouse tracking.
+ sal_Int32 mnPosMTCurr; /// Current position of mouse tracking.
+ bool mbPosMTMoved; /// Tracking: Anytime moved to another position?
+
+ Size maWinSize; /// Size of the control.
+ tools::Rectangle maActiveRect; /// The active area of the ruler.
+ sal_Int32 mnSplitSize; /// Size of a split circle.
+ bool mbTracking; /// If currently mouse tracking
+
+public:
+ explicit ScCsvRuler(const ScCsvLayoutData& rData, ScCsvTableBox* pTableBox);
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ ScCsvTableBox* GetTableBox() { return mpTableBox; }
+ virtual ~ScCsvRuler() override;
+
+ // common ruler handling --------------------------------------------------
+public:
+ /** Apply current layout data to the ruler. */
+ void ApplyLayout( const ScCsvLayoutData& rOldData );
+
+private:
+ /** Reads colors from system settings. */
+ void InitColors();
+ /** Initializes all data dependent from the control's size. */
+ void InitSizeData();
+
+ /** Moves cursor to a new position.
+ @param bScroll sal_True = The method may scroll the ruler. */
+ void MoveCursor( sal_Int32 nPos, bool bScroll = true );
+ /** Moves cursor to the given direction. */
+ void MoveCursorRel( ScMoveMode eDir );
+ /** Sets cursor to an existing split, according to eDir. */
+ void MoveCursorToSplit( ScMoveMode eDir );
+ /** Scrolls data grid vertically. */
+ void ScrollVertRel( ScMoveMode eDir );
+
+ // split handling ---------------------------------------------------------
+public:
+ /** Returns the split array. */
+ const ScCsvSplits& GetSplits() const { return maSplits; }
+ /** Returns the number of splits. */
+ sal_uInt32 GetSplitCount() const
+ { return maSplits.Count(); }
+ /** Returns the position of the specified split. */
+ sal_Int32 GetSplitPos( sal_uInt32 nIndex ) const
+ { return maSplits[ nIndex ]; }
+ /** Finds a position nearest to nPos which does not cause scrolling the visible area. */
+ sal_Int32 GetNoScrollPos( sal_Int32 nPos ) const;
+
+ /** Returns true if at position nPos is a split. */
+ bool HasSplit( sal_Int32 nPos ) const { return maSplits.HasSplit( nPos ); }
+ /** Inserts a split. */
+ void InsertSplit( sal_Int32 nPos );
+ /** Removes a split. */
+ void RemoveSplit( sal_Int32 nPos );
+ /** Moves a split from nPos to nNewPos. */
+ void MoveSplit( sal_Int32 nPos, sal_Int32 nNewPos );
+ /** Removes all splits of the ruler. */
+ void RemoveAllSplits();
+
+private:
+ /** Finds next position without a split. */
+ sal_Int32 FindEmptyPos( sal_Int32 nPos, ScMoveMode eDir ) const;
+
+ /** Moves split and cursor to nNewPos and commits event. */
+ void MoveCurrSplit( sal_Int32 nNewPos );
+ /** Moves split and cursor to the given direction and commits event. */
+ void MoveCurrSplitRel( ScMoveMode eDir );
+
+ // event handling ---------------------------------------------------------
+protected:
+ virtual void Resize() override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+ virtual void StyleUpdated() override;
+
+ virtual bool MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual bool MouseMove( const MouseEvent& rMEvt ) override;
+ virtual bool MouseButtonUp( const MouseEvent& rMEvt ) override;
+
+ virtual bool KeyInput( const KeyEvent& rKEvt ) override;
+
+ virtual tools::Rectangle GetFocusRect() override;
+
+private:
+ /** Starts tracking at the specified position. */
+ void StartMouseTracking( sal_Int32 nPos );
+ /** Moves tracking to a new position. */
+ void MoveMouseTracking( sal_Int32 nPos );
+ /** Applies tracking action for the current tracking position */
+ void EndMouseTracking();
+
+ // painting ---------------------------------------------------------------
+protected:
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& ) override;
+
+public:
+ /** Redraws the entire ruler. */
+ void ImplRedraw(vcl::RenderContext& rRenderContext);
+
+private:
+ /** Returns the width of the control. */
+ sal_Int32 GetWidth() const { return maWinSize.Width(); }
+ /** Returns the height of the control. */
+ sal_Int32 GetHeight() const { return maWinSize.Height(); }
+ /** Update the split size depending on the last width set by CSVCMD_SETCHARWIDTH */
+ void UpdateSplitSize();
+
+ /** Draws the background and active area to maBackgrDev (only the given X range). */
+ void ImplDrawArea( sal_Int32 nPosX, sal_Int32 nWidth );
+ /** Draws the entire ruler background with scaling to maBackgrDev. */
+ void ImplDrawBackgrDev();
+
+ /** Draws a split to maRulerDev. */
+ void ImplDrawSplit( sal_Int32 nPos );
+ /** Erases a split from maRulerDev. */
+ void ImplEraseSplit( sal_Int32 nPos );
+ /** Draws the ruler background, all splits and the cursor to maRulerDev. */
+ void ImplDrawRulerDev();
+
+ /** Inverts the cursor bar at the specified position in maRulerDev. */
+ void ImplInvertCursor( sal_Int32 nPos );
+
+ /** Sets arrow or horizontal split pointer. */
+ void ImplSetMousePointer( sal_Int32 nPos );
+
+ // accessibility ----------------------------------------------------------
+protected:
+ /** Creates a new accessible object. */
+ virtual css::uno::Reference<css::accessibility::XAccessible> CreateAccessible() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/csvsplits.hxx b/sc/source/ui/inc/csvsplits.hxx
new file mode 100644
index 000000000..d10e72cc7
--- /dev/null
+++ b/sc/source/ui/inc/csvsplits.hxx
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sal/types.h>
+
+#include <vector>
+
+/** Constant for an invalid vector index. */
+const sal_uInt32 CSV_VEC_NOTFOUND = SAL_MAX_UINT32;
+/** Constant for an invalid ruler position. */
+const sal_Int32 CSV_POS_INVALID = -1;
+
+/** A vector of column splits that supports inserting, removing and moving splits. */
+class ScCsvSplits
+{
+private:
+ typedef ::std::vector< sal_Int32 > ScSplitVector;
+ typedef ScSplitVector::const_iterator const_iterator;
+
+ ScSplitVector maVec; /// The split container.
+
+public:
+ // *** access by position *** ---------------------------------------------
+
+ /** Inserts a new split at position nPos into the vector.
+ @return true = split inserted (nPos was valid and empty). */
+ bool Insert( sal_Int32 nPos );
+ /** Removes a split by position.
+ @return true = split found and removed. */
+ bool Remove( sal_Int32 nPos );
+ /** Removes a range of splits in the given position range. */
+ void RemoveRange( sal_Int32 nPosStart, sal_Int32 nPosEnd );
+ /** Removes all elements from the vector. */
+ void Clear();
+
+ /** Returns true if at position nPos is a split. */
+ bool HasSplit( sal_Int32 nPos ) const;
+
+ // *** access by index *** ------------------------------------------------
+
+ /** Searches for a split at position nPos.
+ @return the vector index of the split. */
+ sal_uInt32 GetIndex( sal_Int32 nPos ) const;
+ /** Returns index of the first split greater than or equal to nPos. */
+ sal_uInt32 LowerBound( sal_Int32 nPos ) const;
+ /** Returns index of the last split less than or equal to nPos. */
+ sal_uInt32 UpperBound( sal_Int32 nPos ) const;
+
+ /** Returns the number of splits. */
+ sal_uInt32 Count() const
+ { return static_cast<sal_uInt32>(maVec.size()); }
+ /** Returns the position of the specified split. */
+ sal_Int32 GetPos( sal_uInt32 nIndex ) const;
+ /** Returns the position of the specified split. */
+ sal_Int32 operator[]( sal_uInt32 nIndex ) const
+ { return GetPos( nIndex ); }
+
+private:
+ /** Returns the vector index of an iterator. */
+ sal_uInt32 GetIterIndex( const_iterator const & aIter ) const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/csvtablebox.hxx b/sc/source/ui/inc/csvtablebox.hxx
new file mode 100644
index 000000000..e2392a478
--- /dev/null
+++ b/sc/source/ui/inc/csvtablebox.hxx
@@ -0,0 +1,132 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/idle.hxx>
+#include <vcl/weld.hxx>
+#include <scdllapi.h>
+#include "csvcontrol.hxx"
+#include "csvruler.hxx"
+#include "csvgrid.hxx"
+
+class ScAsciiOptions;
+namespace weld {
+ class ComboBox;
+}
+
+/* ============================================================================
+Position: Positions between the characters (the dots in the ruler).
+Character: The characters (the range from one position to the next).
+Split: Positions which contain a split to divide characters into groups (columns).
+Column: The range between two splits.
+============================================================================ */
+
+/** The control in the CSV import dialog that contains a ruler and a data grid
+ to visualize and modify the current import settings. */
+class SC_DLLPUBLIC ScCsvTableBox
+{
+private:
+ ScCsvLayoutData maData; /// Current layout data of the controls.
+
+ std::unique_ptr<ScCsvRuler> mxRuler; /// The ruler for fixed width mode.
+ std::unique_ptr<ScCsvGrid> mxGrid; /// Calc-like data table for fixed width mode.
+ std::unique_ptr<weld::ScrolledWindow> mxScroll; /// Scrolled Window
+ std::unique_ptr<weld::CustomWeld> mxRulerWeld; /// Connect the ruler to its drawingarea
+ std::unique_ptr<weld::CustomWeld> mxGridWeld; /// connect the grid to its drawingarea
+
+ Link<ScCsvTableBox&,void> maUpdateTextHdl; /// Updates all cell texts.
+ Link<ScCsvTableBox&,void> maColTypeHdl; /// Handler for exporting the column type.
+
+ Idle maEndScrollIdle; /// Called when horizontal scrolling has ended
+
+ ScCsvColStateVec maFixColStates; /// Column states in fixed width mode.
+ ScCsvColStateVec maSepColStates; /// Column states in separators mode.
+
+ sal_Int32 mnFixedWidth; /// Cached total width for fixed width mode.
+
+ bool mbFixedMode; /// false = Separators, true = Fixed width.
+
+public:
+ explicit ScCsvTableBox(weld::Builder& rBuilder);
+ ~ScCsvTableBox();
+
+ /** Finishes initialization. Must be called after constructing a new object. */
+ void Init();
+
+ // common table box handling ----------------------------------------------
+public:
+ /** Sets the control to separators mode. */
+ void SetSeparatorsMode();
+ /** Sets the control to fixed width mode. */
+ void SetFixedWidthMode();
+
+ ScCsvRuler& GetRuler() { return *mxRuler; }
+ ScCsvGrid& GetGrid() { return *mxGrid; }
+
+ /** Initializes the children controls (pos/size, scroll bars, ...). */
+ SAL_DLLPRIVATE void InitControls();
+
+private:
+ /** Initializes size and position data of horizontal scrollbar. */
+ SAL_DLLPRIVATE void InitHScrollBar();
+ /** Initializes size and position data of vertical scrollbar. */
+ SAL_DLLPRIVATE void InitVScrollBar();
+
+ /** Calculates and sets valid position offset nearest to nPos. */
+ SAL_DLLPRIVATE void ImplSetPosOffset( sal_Int32 nPos )
+ { maData.mnPosOffset = std::clamp( nPos, sal_Int32(0), mxGrid->GetMaxPosOffset() ); }
+ /** Calculates and sets valid line offset nearest to nLine. */
+ SAL_DLLPRIVATE void ImplSetLineOffset( sal_Int32 nLine )
+ { maData.mnLineOffset = std::clamp( nLine, sal_Int32(0), mxGrid->GetMaxLineOffset() ); }
+ /** Moves controls (not cursors!) so that nPos becomes visible. */
+ SAL_DLLPRIVATE void MakePosVisible( sal_Int32 nPos );
+
+ // cell contents ----------------------------------------------------------
+public:
+ /** Fills all cells of all lines with the passed texts (Unicode strings). */
+ void SetUniStrings(
+ const OUString* pTextLines, const OUString& rSepChars,
+ sal_Unicode cTextSep, bool bMergeSep, bool bRemoveSpace );
+
+ // column settings --------------------------------------------------------
+public:
+ /** Reads UI strings for data types from the list box. */
+ void InitTypes(const weld::ComboBox& rListBox);
+ /** Returns the data type of the selected columns. */
+ sal_Int32 GetSelColumnType() const { return mxGrid->GetSelColumnType(); }
+
+ /** Fills the options object with current column data. */
+ void FillColumnData( ScAsciiOptions& rOptions ) const;
+
+ // event handling ---------------------------------------------------------
+public:
+ /** Sets a new handler for "update cell texts" requests. */
+ void SetUpdateTextHdl( const Link<ScCsvTableBox&,void>& rHdl ) { maUpdateTextHdl = rHdl; }
+ /** Sets a new handler for "column selection changed" events. */
+ void SetColTypeHdl( const Link<ScCsvTableBox&,void>& rHdl ) { maColTypeHdl = rHdl; }
+
+private:
+ DECL_DLLPRIVATE_LINK( CsvCmdHdl, ScCsvControl&, void );
+ DECL_DLLPRIVATE_LINK( HScrollHdl, weld::ScrolledWindow&, void );
+ DECL_DLLPRIVATE_LINK( VScrollHdl, weld::ScrolledWindow&, void );
+ DECL_DLLPRIVATE_LINK( ScrollEndHdl, Timer*, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/dapidata.hxx b/sc/source/ui/inc/dapidata.hxx
new file mode 100644
index 000000000..ebad1d2e6
--- /dev/null
+++ b/sc/source/ui/inc/dapidata.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 <vcl/weld.hxx>
+
+struct ScImportSourceDesc;
+
+class ScDataPilotDatabaseDlg : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::ComboBox> m_xLbDatabase;
+ std::unique_ptr<weld::ComboBox> m_xCbObject;
+ std::unique_ptr<weld::ComboBox> m_xLbType;
+
+ void FillObjects();
+
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+
+public:
+ ScDataPilotDatabaseDlg(weld::Window* pParent);
+ virtual ~ScDataPilotDatabaseDlg() override;
+
+ void GetValues(ScImportSourceDesc& rDesc);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/dapitype.hxx b/sc/source/ui/inc/dapitype.hxx
new file mode 100644
index 000000000..e45400cdf
--- /dev/null
+++ b/sc/source/ui/inc/dapitype.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 <vcl/weld.hxx>
+
+class ScDataPilotSourceTypeDlg : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::RadioButton> m_xBtnSelection;
+ std::unique_ptr<weld::RadioButton> m_xBtnNamedRange;
+ std::unique_ptr<weld::RadioButton> m_xBtnDatabase;
+ std::unique_ptr<weld::RadioButton> m_xBtnExternal;
+ std::unique_ptr<weld::ComboBox> m_xLbNamedRange;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+public:
+ ScDataPilotSourceTypeDlg(weld::Window* pParent, bool bEnableExternal);
+ virtual ~ScDataPilotSourceTypeDlg() override;
+ bool IsDatabase() const;
+ bool IsExternal() const;
+ bool IsNamedRange() const;
+ OUString GetSelectedNamedRange() const;
+ void AppendNamedRange(const OUString& rNames);
+
+private:
+ DECL_LINK(RadioClickHdl, weld::Toggleable&, void);
+ DECL_LINK(ResponseHdl, weld::Button&, void);
+};
+
+class ScDataPilotServiceDlg : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::ComboBox> m_xLbService;
+ std::unique_ptr<weld::Entry> m_xEdSource;
+ std::unique_ptr<weld::Entry> m_xEdName;
+ std::unique_ptr<weld::Entry> m_xEdUser;
+ std::unique_ptr<weld::Entry> m_xEdPasswd;
+
+public:
+ ScDataPilotServiceDlg(weld::Window* pParent, const std::vector<OUString>& rServices);
+ virtual ~ScDataPilotServiceDlg() override;
+
+ OUString GetServiceName() const;
+ OUString GetParSource() const;
+ OUString GetParName() const;
+ OUString GetParUser() const;
+ OUString GetParPass() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/datafdlg.hxx b/sc/source/ui/inc/datafdlg.hxx
new file mode 100644
index 000000000..4a05cbf1a
--- /dev/null
+++ b/sc/source/ui/inc/datafdlg.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/.
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <types.hxx>
+#include "viewfunc.hxx"
+
+class ScTabViewShell;
+class ScDocument;
+
+#define MAX_DATAFORM_COLS 256
+#define MAX_DATAFORM_ROWS 32000
+
+class ScDataFormDlg : public weld::GenericDialogController
+{
+private:
+ OUString sNewRecord;
+
+ ScTabViewShell* pTabViewShell;
+ ScDocument* pDoc;
+ sal_uInt16 aColLength;
+ SCROW nCurrentRow;
+ SCCOL nStartCol;
+ SCCOL nEndCol;
+ SCROW nStartRow;
+ SCROW nEndRow;
+ SCTAB nTab;
+
+ std::unique_ptr<weld::Button> m_xBtnNew;
+ std::unique_ptr<weld::Button> m_xBtnDelete;
+ std::unique_ptr<weld::Button> m_xBtnRestore;
+ std::unique_ptr<weld::Button> m_xBtnPrev;
+ std::unique_ptr<weld::Button> m_xBtnNext;
+ std::unique_ptr<weld::Button> m_xBtnClose;
+ std::unique_ptr<weld::ScrolledWindow> m_xSlider;
+ std::unique_ptr<weld::Container> m_xGrid;
+ std::unique_ptr<weld::Label> m_xFixedText;
+ std::vector<std::unique_ptr<ScDataFormFragment>> m_aEntries;
+
+public:
+ ScDataFormDlg(weld::Window* pParent, ScTabViewShell* pTabViewShell);
+ virtual ~ScDataFormDlg() override;
+
+ void FillCtrls();
+private:
+
+ void SetButtonState();
+
+ // Handler:
+ DECL_LINK(Impl_NewHdl, weld::Button&, void);
+ DECL_LINK(Impl_PrevHdl, weld::Button&, void);
+ DECL_LINK(Impl_NextHdl, weld::Button&, void);
+
+ DECL_LINK(Impl_RestoreHdl, weld::Button&, void);
+ DECL_LINK(Impl_DeleteHdl, weld::Button&, void);
+ DECL_LINK(Impl_CloseHdl, weld::Button&, void);
+
+ DECL_LINK(Impl_ScrollHdl, weld::ScrolledWindow&, void);
+ DECL_LINK(Impl_DataModifyHdl, weld::Entry&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/dataprovider.hxx b/sc/source/ui/inc/dataprovider.hxx
new file mode 100644
index 000000000..e6457c48e
--- /dev/null
+++ b/sc/source/ui/inc/dataprovider.hxx
@@ -0,0 +1,149 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string_view>
+#include <salhelper/thread.hxx>
+#include <rtl/ustring.hxx>
+#include <rtl/ref.hxx>
+#include <osl/mutex.hxx>
+#include <document.hxx>
+
+#include <rtl/strbuf.hxx>
+
+#include <vector>
+//#include <map>
+
+#include <orcus/csv_parser.hpp>
+
+class SvStream;
+class ScDBData;
+
+namespace sc {
+
+class DataTransformation;
+class ExternalDataSource;
+
+class CSVFetchThread : public salhelper::Thread
+{
+ ScDocument& mrDocument;
+ OUString maURL;
+
+ bool mbTerminate;
+ osl::Mutex maMtxTerminate;
+
+ orcus::csv::parser_config maConfig;
+
+ std::vector<std::shared_ptr<sc::DataTransformation>> maDataTransformations;
+
+ std::function<void()> maImportFinishedHdl;
+
+
+public:
+ CSVFetchThread(ScDocument& rDoc, const OUString&, std::function<void()> aImportFinishedHdl,
+ std::vector<std::shared_ptr<sc::DataTransformation>>&& mrDataTransformations);
+ virtual ~CSVFetchThread() override;
+
+ void RequestTerminate();
+ bool IsRequestedTerminate();
+ void Terminate();
+ void EndThread();
+
+ virtual void execute() override;
+};
+
+/**
+ * Abstract class for all data provider.
+ *
+ */
+class DataProvider
+{
+protected:
+ /**
+ * If true make the threaded import deterministic for the tests.
+ */
+ bool mbDeterministic;
+ sc::ExternalDataSource& mrDataSource;
+
+public:
+ DataProvider(sc::ExternalDataSource& rDataSource);
+
+ virtual ~DataProvider();
+
+ virtual void Import() = 0;
+
+ virtual const OUString& GetURL() const = 0;
+
+ static std::unique_ptr<SvStream> FetchStreamFromURL(const OUString&, OStringBuffer& rBuffer);
+
+ void setDeterministic();
+};
+
+class CSVDataProvider : public DataProvider
+{
+ rtl::Reference<CSVFetchThread> mxCSVFetchThread;
+ ScDocument* mpDocument;
+ ScDocumentUniquePtr mpDoc;
+
+ void Refresh();
+
+public:
+ CSVDataProvider (ScDocument* pDoc, sc::ExternalDataSource& rDataSource);
+ virtual ~CSVDataProvider() override;
+
+ virtual void Import() override;
+
+ const OUString& GetURL() const override;
+ void ImportFinished();
+};
+
+/**
+ * This class handles the copying of the data from the imported
+ * temporary document to the actual document. Additionally, in the future
+ * we may decide to store data transformations in this class.
+ *
+ * In addition this class also handles how to deal with excess data by for example extending the ScDBData or by only showing the first or last entries.
+ *
+ * TODO: move the DataProvider::WriteToDoc here
+ *
+ */
+class ScDBDataManager
+{
+ OUString maDBName;
+ ScDocument* mpDoc;
+
+public:
+ ScDBDataManager(const OUString& rDBName, ScDocument* pDoc);
+ ~ScDBDataManager();
+
+ void SetDatabase(const OUString& rDBName);
+
+ ScDBData* getDBData();
+
+ void WriteToDoc(ScDocument& rDoc);
+};
+
+class DataProviderFactory
+{
+private:
+
+ static bool isInternalDataProvider(std::u16string_view rProvider);
+
+public:
+
+ static std::shared_ptr<DataProvider> getDataProvider(ScDocument* pDoc, sc::ExternalDataSource& rDataSource);
+
+ static std::vector<OUString> getDataProviders();
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/dataproviderdlg.hxx b/sc/source/ui/inc/dataproviderdlg.hxx
new file mode 100644
index 000000000..127b6361a
--- /dev/null
+++ b/sc/source/ui/inc/dataproviderdlg.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/.
+ */
+
+#pragma once
+
+#include <datamapper.hxx>
+
+#include <sal/config.h>
+
+#include <com/sun/star/awt/XWindow.hpp>
+#include <vcl/idle.hxx>
+#include <vcl/weld.hxx>
+#include "datatableview.hxx"
+#include <memory>
+
+class ScDocument;
+class ScDataTransformationBaseControl;
+class ScDBData;
+
+class ScDataProviderDlg : public weld::GenericDialogController
+{
+private:
+ std::shared_ptr<ScDocument> mxDoc;
+ std::unique_ptr<weld::Container> mxBox;
+ css::uno::Reference<css::awt::XWindow> m_xTableParent;
+ VclPtr<ScDataTableView> mxTable;
+ std::unique_ptr<weld::Container> mxList;
+ std::unique_ptr<weld::ComboBox> mxDBRanges;
+ std::unique_ptr<weld::Button> mxOKBtn;
+ std::unique_ptr<weld::Button> mxCancelBtn;
+ std::unique_ptr<weld::Button> mxAddTransformationBtn;
+ std::unique_ptr<weld::ScrolledWindow> mxScroll;
+ std::unique_ptr<weld::Container> mxTransformationList;
+ std::unique_ptr<weld::ComboBox> mxTransformationBox;
+ std::unique_ptr<weld::ComboBox> mxProviderList;
+ std::unique_ptr<weld::Entry> mxEditURL;
+ std::unique_ptr<weld::Entry> mxEditID;
+ std::unique_ptr<weld::Button> mxApplyBtn;
+ std::unique_ptr<weld::Button> mxBrowseBtn;
+
+ OUString msApplyTooltip;
+ OUString msAddTransformationToolTip;
+
+ std::vector<std::unique_ptr<ScDataTransformationBaseControl>> maControls;
+
+ Idle maIdle;
+
+ sal_uInt32 mnIndex;
+ ScDBData* pDBData;
+
+ DECL_LINK(StartMenuHdl, const OString&, void);
+ DECL_LINK(ColumnMenuHdl, const weld::ComboBox&, void);
+ DECL_LINK(ScrollToEnd, Timer*, void);
+ DECL_LINK(ApplyQuitHdl, weld::Button&, void);
+ DECL_LINK(CancelQuitHdl, weld::Button&, void);
+ DECL_LINK(TransformationListHdl, weld::Button&, void);
+ DECL_LINK(ProviderSelectHdl, weld::ComboBox&, void);
+ DECL_LINK(TransformationSelectHdl, weld::ComboBox&, void);
+ DECL_LINK(IDEditHdl, weld::Entry&, void);
+ DECL_LINK(URLEditHdl, weld::Entry&, void);
+ DECL_LINK(ApplyBtnHdl, weld::Button&, void);
+ DECL_LINK(BrowseBtnHdl, weld::Button&, void);
+
+public:
+ ScDataProviderDlg(weld::Window* pWindow, std::shared_ptr<ScDocument> pDoc,
+ const ScDocument* pDocument);
+ virtual ~ScDataProviderDlg() override;
+
+ void applyAndQuit();
+ void cancelAndQuit();
+
+ void deleteColumn();
+ void splitColumn();
+ void mergeColumns();
+ void textTransformation();
+ void sortTransformation();
+ void aggregateFunction();
+ void numberTransformation();
+ void deletefromList(sal_uInt32 nIndex);
+ void replaceNullTransformation();
+ void dateTimeTransformation();
+ void findReplaceTransformation();
+ void deleteRowTransformation();
+ void swapRowsTransformation();
+
+ void updateApplyBtn(bool bValidConfig);
+ void isValid();
+
+ sc::ExternalDataSource getDataSource(ScDocument* pDoc);
+
+ void import(ScDocument& rDoc, bool bInternal = false);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/datastream.hxx b/sc/source/ui/inc/datastream.hxx
new file mode 100644
index 000000000..790b85a6d
--- /dev/null
+++ b/sc/source/ui/inc/datastream.hxx
@@ -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/.
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <rtl/ref.hxx>
+#include <rtl/ustring.hxx>
+#include <vcl/timer.hxx>
+#include <address.hxx>
+
+#include <vector>
+
+#include <documentstreamaccess.hxx>
+
+class ScDocShell;
+
+namespace sc {
+
+namespace datastreams {
+ class ReaderThread;
+}
+
+class DataStream
+{
+public:
+ DataStream(const DataStream&) = delete;
+ const DataStream& operator=(const DataStream&) = delete;
+
+ struct Cell
+ {
+ struct Str
+ {
+ size_t Pos;
+ size_t Size;
+ };
+
+ union
+ {
+ Str maStr;
+ double mfValue;
+ };
+
+ bool mbValue;
+
+ Cell();
+ Cell( const Cell& r );
+ };
+
+ struct Line
+ {
+ OString maLine;
+ std::vector<Cell> maCells;
+ };
+ typedef std::vector<Line> LinesType;
+
+ enum MoveType { NO_MOVE, RANGE_DOWN, MOVE_DOWN, MOVE_UP };
+ enum { VALUES_IN_LINE = 2 };
+
+ static void MakeToolbarVisible();
+ static DataStream* Set(ScDocShell *pShell, const OUString& rURL, const ScRange& rRange,
+ sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings);
+
+ DataStream(
+ ScDocShell *pShell, const OUString& rURL, const ScRange& rRange,
+ sal_Int32 nLimit, MoveType eMove, sal_uInt32 nSettings);
+
+ ~DataStream();
+
+ ScRange GetRange() const;
+ const OUString& GetURL() const { return msURL; }
+ MoveType GetMove() const { return meOrigMove;}
+ bool IsRefreshOnEmptyLine() const { return mbRefreshOnEmptyLine;}
+
+ void Decode(
+ const OUString& rURL, const ScRange& rRange, sal_Int32 nLimit,
+ MoveType eMove, const sal_uInt32 nSettings);
+
+ bool ImportData();
+ void StartImport();
+ void StopImport();
+
+ void SetRefreshOnEmptyLine( bool bVal );
+
+private:
+ Line ConsumeLine();
+ void MoveData();
+ void Text2Doc();
+ void Refresh();
+
+ DECL_LINK( ImportTimerHdl, Timer*, void );
+
+private:
+ ScDocShell* mpDocShell;
+ DocumentStreamAccess maDocAccess;
+ OUString msURL;
+ sal_uInt32 mnSettings;
+ MoveType meOrigMove; // Initial move setting. This one gets saved to file.
+ MoveType meMove; // move setting during streaming, which may change in the middle.
+ bool mbRunning;
+ bool mbValuesInLine;
+ bool mbRefreshOnEmptyLine;
+ std::unique_ptr<LinesType> mpLines;
+ size_t mnLinesCount;
+ size_t mnLinesSinceRefresh;
+ double mfLastRefreshTime;
+ SCROW mnCurRow;
+ ScRange maStartRange;
+ ScRange maEndRange;
+
+ Timer maImportTimer;
+
+ rtl::Reference<datastreams::ReaderThread> mxReaderThread;
+ bool mbIsFirst;
+ bool mbIsUpdate;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/datastreamdlg.hxx b/sc/source/ui/inc/datastreamdlg.hxx
new file mode 100644
index 000000000..5f1f7eec4
--- /dev/null
+++ b/sc/source/ui/inc/datastreamdlg.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 <vcl/weld.hxx>
+
+class ScDocShell;
+class SvtURLBox;
+class ScRange;
+
+namespace sc
+{
+class DataStream;
+
+class DataStreamDlg : public weld::GenericDialogController
+{
+ ScDocShell* m_pDocShell;
+
+ std::unique_ptr<SvtURLBox> m_xCbUrl;
+ std::unique_ptr<weld::Button> m_xBtnBrowse;
+ std::unique_ptr<weld::RadioButton> m_xRBValuesInLine;
+ std::unique_ptr<weld::RadioButton> m_xRBAddressValue;
+ std::unique_ptr<weld::CheckButton> m_xCBRefreshOnEmpty;
+ std::unique_ptr<weld::RadioButton> m_xRBDataDown;
+ std::unique_ptr<weld::RadioButton> m_xRBRangeDown;
+ std::unique_ptr<weld::RadioButton> m_xRBNoMove;
+ std::unique_ptr<weld::RadioButton> m_xRBMaxLimit;
+ std::unique_ptr<weld::RadioButton> m_xRBUnlimited;
+ std::unique_ptr<weld::Entry> m_xEdRange;
+ std::unique_ptr<weld::Entry> m_xEdLimit;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Frame> m_xVclFrameLimit;
+ std::unique_ptr<weld::Frame> m_xVclFrameMove;
+
+ DECL_LINK(UpdateClickHdl, weld::Toggleable&, void);
+ DECL_LINK(UpdateHdl, weld::Entry&, void);
+ DECL_LINK(UpdateComboBoxHdl, weld::ComboBox&, void);
+ DECL_LINK(BrowseHdl, weld::Button&, void);
+
+ void UpdateEnable();
+ ScRange GetStartRange();
+
+public:
+ DataStreamDlg(ScDocShell* pDocShell, weld::Window* pParent);
+ virtual ~DataStreamDlg() override;
+
+ void Init(const DataStream& rStrm);
+
+ void StartStream();
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/datatableview.hxx b/sc/source/ui/inc/datatableview.hxx
new file mode 100644
index 000000000..8eaac9084
--- /dev/null
+++ b/sc/source/ui/inc/datatableview.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 <com/sun/star/awt/XWindow.hpp>
+#include <vcl/ctrl.hxx>
+#include <vcl/scrbar.hxx>
+#include <types.hxx>
+#include "hdrcont.hxx"
+
+class ScDocument;
+
+class ScDataTableColView : public ScHeaderControl
+{
+ ScDocument* mpDoc;
+ SCCOL mnCol;
+
+public:
+ ScDataTableColView(vcl::Window* pParent, ScDocument* pDoc, SelectionEngine* pSelectionEngine);
+
+ void SetPos(SCCOLROW nRow);
+
+ virtual SCCOLROW GetPos() const override;
+ virtual sal_uInt16 GetEntrySize(SCCOLROW nPos) const override;
+ virtual OUString GetEntryText(SCCOLROW nPos) const override;
+ virtual bool IsLayoutRTL() const override;
+ virtual void SetEntrySize(SCCOLROW nPos, sal_uInt16 nWidth) override;
+ virtual void HideEntries(SCCOLROW nPos, SCCOLROW nEndPos) override;
+};
+
+class ScDataTableRowView : public ScHeaderControl
+{
+ ScDocument* mpDoc;
+ SCROW mnRow;
+
+public:
+ ScDataTableRowView(vcl::Window* pParent, ScDocument* pDoc, SelectionEngine* pSelectionEngine);
+
+ void SetPos(SCCOLROW nRow);
+
+ virtual SCCOLROW GetPos() const override;
+ virtual sal_uInt16 GetEntrySize(SCCOLROW nPos) const override;
+ virtual OUString GetEntryText(SCCOLROW nPos) const override;
+ virtual bool IsLayoutRTL() const override;
+ virtual void SetEntrySize(SCCOLROW nPos, sal_uInt16 nWidth) override;
+ virtual void HideEntries(SCCOLROW nPos, SCCOLROW nEndPos) override;
+};
+
+/*
+ * A simple UI component that presents a data table.
+ *
+ * Shares as much code as possible with the normal
+ * Calc grid rendering.
+ *
+ * This class should only depend on ScDocument and not
+ * on some of the Calc view shells.
+ */
+class ScDataTableView : public Control
+{
+ std::shared_ptr<ScDocument> mpDoc;
+ std::unique_ptr<SelectionEngine> mpSelectionEngine;
+ VclPtr<ScrollBarBox> mpTopLeft;
+ VclPtr<ScDataTableColView> mpColView;
+ VclPtr<ScDataTableRowView> mpRowView;
+ VclPtr<ScrollBar> mpVScroll;
+ VclPtr<ScrollBar> mpHScroll;
+
+ SCROW mnFirstVisibleRow;
+ SCCOL mnFirstVisibleCol;
+
+ std::unique_ptr<MouseEvent> mpMouseEvent;
+
+ DECL_LINK(ScrollHdl, ScrollBar*, void);
+
+public:
+ ScDataTableView(const css::uno::Reference<css::awt::XWindow>& rParent,
+ std::shared_ptr<ScDocument> pDoc);
+ ~ScDataTableView() override;
+
+ virtual void dispose() override;
+
+ virtual void MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual void MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual void Resize() override;
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+ virtual Size GetOptimalSize() const override;
+
+ void getColRange(SCCOL& rStartCol, SCCOL& rEndCol) const;
+ void getRowRange(SCROW& rStartRow, SCROW& rEndRow) const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/datatransformation.hxx b/sc/source/ui/inc/datatransformation.hxx
new file mode 100644
index 000000000..e69b21f42
--- /dev/null
+++ b/sc/source/ui/inc/datatransformation.hxx
@@ -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/.
+ */
+
+#pragma once
+
+#include <types.hxx>
+#include <scdllapi.h>
+
+#include <sortparam.hxx>
+
+#include <set>
+
+class ScDocument;
+
+namespace sc {
+
+enum class TransformationType
+{
+ MERGE_TRANSFORMATION,
+ SPLIT_TRANSFORMATION,
+ DELETE_TRANSFORMATION,
+ SORT_TRANSFORMATION,
+ TEXT_TRANSFORMATION,
+ AGGREGATE_FUNCTION,
+ NUMBER_TRANSFORMATION,
+ REMOVE_NULL_TRANSFORMATION,
+ DATETIME_TRANSFORMATION,
+ FINDREPLACE_TRANSFORMATION,
+ DELETEROW_TRANSFORMATION,
+ SWAPROWS_TRANSFORMATION
+};
+
+enum class TEXT_TRANSFORM_TYPE { TO_LOWER, TO_UPPER, CAPITALIZE, TRIM };
+
+enum class AGGREGATE_FUNCTION { SUM, AVERAGE, MIN, MAX };
+
+enum class NUMBER_TRANSFORM_TYPE { ROUND, ROUND_UP, ROUND_DOWN, ABSOLUTE, LOG_E, LOG_10, CUBE,
+ SQUARE, SQUARE_ROOT, EXPONENT, IS_EVEN, IS_ODD, SIGN };
+
+enum class DATETIME_TRANSFORMATION_TYPE { DATE_STRING, YEAR, START_OF_YEAR, END_OF_YEAR, MONTH,
+ MONTH_NAME, START_OF_MONTH, END_OF_MONTH, DAY, DAY_OF_WEEK, DAY_OF_YEAR, QUARTER, START_OF_QUARTER,
+ END_OF_QUARTER, TIME, HOUR, MINUTE, SECOND };
+
+class SC_DLLPUBLIC DataTransformation
+{
+protected:
+
+ static SCROW getLastRow(const ScDocument& rDoc, SCCOL nCol);
+
+public:
+ virtual ~DataTransformation();
+
+ virtual void Transform(ScDocument& rDoc) const = 0;
+
+ virtual TransformationType getTransformationType() const = 0;
+
+};
+
+class SC_DLLPUBLIC ColumnRemoveTransformation : public DataTransformation
+{
+ std::set<SCCOL> maColumns;
+
+public:
+
+ ColumnRemoveTransformation(std::set<SCCOL>&& rColumns);
+ virtual ~ColumnRemoveTransformation() override;
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ const std::set<SCCOL> & getColumns() const;
+};
+
+class SC_DLLPUBLIC SplitColumnTransformation : public DataTransformation
+{
+ SCCOL mnCol;
+ sal_Unicode mcSeparator;
+
+public:
+
+ SplitColumnTransformation(SCCOL nCol, sal_Unicode cSeparator);
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ SCCOL getColumn() const;
+ sal_Unicode getSeparator() const;
+};
+
+class SC_DLLPUBLIC MergeColumnTransformation : public DataTransformation
+{
+ std::set<SCCOL> maColumns;
+ OUString maMergeString;
+
+public:
+
+ MergeColumnTransformation(std::set<SCCOL>&& rColumns, const OUString& rMergeString);
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ const OUString & getMergeString() const;
+ const std::set<SCCOL> & getColumns() const;
+};
+
+class SortTransformation : public DataTransformation
+{
+ ScSortParam maSortParam;
+public:
+
+ SortTransformation(const ScSortParam& rParam);
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ const ScSortParam & getSortParam() const;
+};
+
+class SC_DLLPUBLIC TextTransformation : public DataTransformation
+{
+ std::set<SCCOL> mnCol;
+ TEXT_TRANSFORM_TYPE maType;
+
+ public:
+ TextTransformation(std::set<SCCOL>&& nCol, const TEXT_TRANSFORM_TYPE rType);
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ TEXT_TRANSFORM_TYPE getTextTransformationType() const;
+ const std::set<SCCOL>& getColumns() const;
+};
+
+class SC_DLLPUBLIC AggregateFunction : public DataTransformation
+{
+ std::set<SCCOL> maColumns;
+ AGGREGATE_FUNCTION maType;
+
+ public:
+ AggregateFunction(std::set<SCCOL>&& rColumns, const AGGREGATE_FUNCTION rType);
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ AGGREGATE_FUNCTION getAggregateType() const;
+ const std::set<SCCOL>& getColumns() const;
+};
+
+class SC_DLLPUBLIC NumberTransformation : public DataTransformation
+{
+ std::set<SCCOL> mnCol;
+ NUMBER_TRANSFORM_TYPE maType;
+ int maPrecision;
+
+ public:
+ NumberTransformation(std::set<SCCOL>&& nCol, const NUMBER_TRANSFORM_TYPE rType);
+ NumberTransformation(std::set<SCCOL>&& nCol, const NUMBER_TRANSFORM_TYPE rType,
+ int nPrecision);
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ NUMBER_TRANSFORM_TYPE getNumberTransformationType() const;
+ int getPrecision() const;
+ const std::set<SCCOL>& getColumn() const;
+};
+
+class SC_DLLPUBLIC ReplaceNullTransformation : public DataTransformation
+{
+ std::set<SCCOL> mnCol;
+ OUString msReplaceWith;
+
+ public:
+ ReplaceNullTransformation(std::set<SCCOL>&& nCol, const OUString& sReplaceWith);
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ const std::set<SCCOL>& getColumn() const;
+ const OUString& getReplaceString() const;
+};
+
+class SC_DLLPUBLIC DateTimeTransformation : public DataTransformation
+{
+ std::set<SCCOL> mnCol;
+ DATETIME_TRANSFORMATION_TYPE maType;
+
+ public:
+ DateTimeTransformation(std::set<SCCOL>&& nCol,
+ const DATETIME_TRANSFORMATION_TYPE rType);
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ DATETIME_TRANSFORMATION_TYPE getDateTimeTransformationType() const;
+ const std::set<SCCOL>& getColumn() const;
+};
+
+class FindReplaceTransformation : public DataTransformation
+{
+ SCCOL mnCol;
+ OUString maFindString;
+ OUString maReplaceString;
+
+ public:
+ FindReplaceTransformation(SCCOL nCol, const OUString& aFindString, const OUString& aReplaceString);
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ SCCOL getColumn() const;
+ const OUString & getFindString() const;
+ const OUString & getReplaceString() const;
+};
+
+class DeleteRowTransformation : public DataTransformation
+{
+ SCCOL mnCol;
+ OUString maFindString;
+
+ public:
+ DeleteRowTransformation(SCCOL nCol, const OUString& aFindString);
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ SCCOL getColumn() const;
+ const OUString & getFindString() const;
+};
+
+class SwapRowsTransformation : public DataTransformation
+{
+ SCROW mxRow, nxRow;
+
+ public:
+ SwapRowsTransformation(SCROW mRow, SCROW nRow);
+ virtual void Transform(ScDocument& rDoc) const override;
+ virtual TransformationType getTransformationType() const override;
+ SCROW getFirstRow() const;
+ SCROW getSecondRow() const;
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/dbdocfun.hxx b/sc/source/ui/inc/dbdocfun.hxx
new file mode 100644
index 000000000..780e523b5
--- /dev/null
+++ b/sc/source/ui/inc/dbdocfun.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 <address.hxx>
+#include <vector>
+
+struct ScImportParam;
+struct ScQueryParam;
+struct ScSortParam;
+struct ScSubTotalParam;
+
+class SfxViewFrame;
+class ScDBData;
+class ScDocShell;
+class ScDPObject;
+class ScDBCollection;
+
+namespace com::sun::star::uno { template <typename > class Sequence; }
+namespace com::sun::star::beans { struct PropertyValue; }
+
+namespace svx {
+ class ODataAccessDescriptor;
+}
+
+class ScDBDocFunc
+{
+friend class ScDBFunc;
+
+private:
+ ScDocShell& rDocShell;
+
+public:
+ ScDBDocFunc( ScDocShell& rDocSh ): rDocShell(rDocSh) {}
+
+ void UpdateImport( const OUString& rTarget, const svx::ODataAccessDescriptor& rDescriptor );
+
+ bool DoImport( SCTAB nTab, const ScImportParam& rParam,
+ const svx::ODataAccessDescriptor* pDescriptor); // used for selection an existing ResultSet
+
+ void DoImportUno( const ScAddress& rPos,
+ const css::uno::Sequence<css::beans::PropertyValue>& aArgs );
+
+ static void ShowInBeamer( const ScImportParam& rParam, const SfxViewFrame* pFrame );
+
+ SC_DLLPUBLIC bool Sort(
+ SCTAB nTab, const ScSortParam& rSortParam, bool bRecord, bool bPaint, bool bApi );
+
+ SC_DLLPUBLIC bool Query( SCTAB nTab, const ScQueryParam& rQueryParam,
+ const ScRange* pAdvSource, bool bRecord, bool bApi );
+
+ void DoSubTotals( SCTAB nTab, const ScSubTotalParam& rParam,
+ bool bRecord, bool bApi );
+
+ bool AddDBRange( const OUString& rName, const ScRange& rRange );
+ bool DeleteDBRange( const OUString& rName );
+ bool RenameDBRange( const OUString& rOld, const OUString& rNew );
+ void ModifyDBData( const ScDBData& rNewData ); // Name unveraendert
+
+ void ModifyAllDBData( const ScDBCollection& rNewColl, const std::vector<ScRange>& rDelAreaList );
+
+ bool RepeatDB( const OUString& rDBName, bool bApi, bool bIsUnnamed, SCTAB aTab = 0);
+
+ bool DataPilotUpdate( ScDPObject* pOldObj, const ScDPObject* pNewObj,
+ bool bRecord, bool bApi, bool bAllowMove = false );
+
+ bool RemovePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi);
+ bool CreatePivotTable(const ScDPObject& rDPObj, bool bRecord, bool bApi);
+ bool UpdatePivotTable(ScDPObject& rDPObj, bool bRecord, bool bApi);
+
+ /**
+ * Reload the referenced pivot cache, and refresh all pivot tables that
+ * reference the cache.
+ */
+ void RefreshPivotTables(const ScDPObject* pDPObj, bool bApi);
+
+ /**
+ * Refresh the group dimensions of all pivot tables referencing the same
+ * cache.
+ */
+ void RefreshPivotTableGroups(ScDPObject* pDPObj);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/dbfunc.hxx b/sc/source/ui/inc/dbfunc.hxx
new file mode 100644
index 000000000..e953f4aef
--- /dev/null
+++ b/sc/source/ui/inc/dbfunc.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 "viewfunc.hxx"
+#include <dptypes.hxx>
+
+namespace com::sun::star::sheet { struct DataPilotFieldFilter; }
+struct ScSortParam;
+struct ScQueryParam;
+class ScDBData;
+class ScDPObject;
+class ScDPSaveData;
+struct ScDPNumGroupInfo;
+struct ScSubTotalParam;
+
+class SAL_DLLPUBLIC_RTTI ScDBFunc : public ScViewFunc
+{
+private:
+ void GetSelectedMemberList(ScDPUniqueStringSet& rEntries, tools::Long& rDimension);
+
+public:
+ ScDBFunc( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell );
+ virtual ~ScDBFunc();
+
+ // only UISort repeat the partial results if necessary
+
+ void UISort( const ScSortParam& rSortParam );
+
+ void Sort( const ScSortParam& rSortParam,
+ bool bRecord = true, bool bPaint = true );
+ SC_DLLPUBLIC void Query( const ScQueryParam& rQueryParam,
+ const ScRange* pAdvSource, bool bRecord );
+ void DoSubTotals( const ScSubTotalParam& rParam, bool bRecord = true,
+ const ScSortParam* pForceNewSort = nullptr );
+
+ void ToggleAutoFilter();
+ void HideAutoFilter();
+
+ void RepeatDB( bool bRecord = true );
+
+ bool ImportData( const ScImportParam& rParam );
+
+ void GotoDBArea( const OUString& rDBName );
+
+ // DB range from Cursor
+ ScDBData* GetDBData( bool bMarkArea = true, ScGetDBMode eMode = SC_DB_MAKE, ScGetDBSelection eSel = ScGetDBSelection::Keep);
+ ScDBData* GetAnonymousDBData();
+
+ void Consolidate( const ScConsolidateParam& rParam );
+
+ bool MakePivotTable(
+ const ScDPSaveData& rData, const ScRange& rDest, bool bNewTable,
+ const ScDPObject& rSource );
+
+ void DeletePivotTable();
+ void RecalcPivotTable();
+ bool HasSelectionForDateGroup( ScDPNumGroupInfo& rOldInfo, sal_Int32& rParts );
+ bool HasSelectionForNumGroup( ScDPNumGroupInfo& rOldInfo );
+ void GroupDataPilot();
+ void DateGroupDataPilot( const ScDPNumGroupInfo& rInfo, sal_Int32 nParts );
+ void NumGroupDataPilot( const ScDPNumGroupInfo& rInfo );
+ void UngroupDataPilot();
+ void DataPilotInput( const ScAddress& rPos, const OUString& rString );
+
+ void DataPilotSort(ScDPObject* pDPObject, tools::Long nDimIndex, bool bAscending, const sal_uInt16* pUserListId = nullptr);
+ bool DataPilotMove( const ScRange& rSource, const ScAddress& rDest );
+
+ bool HasSelectionForDrillDown( css::sheet::DataPilotFieldOrientation& rOrientation );
+ void SetDataPilotDetails(bool bShow, const OUString* pNewDimensionName = nullptr);
+
+ void ShowDataPilotSourceData( ScDPObject& rDPObj,
+ const css::uno::Sequence< css::sheet::DataPilotFieldFilter >& rFilters );
+
+ void MakeOutline( bool bColumns, bool bRecord = true );
+ void RemoveOutline( bool bColumns, bool bRecord = true );
+ void RemoveAllOutlines( bool bRecord = true );
+ void TestRemoveOutline( bool& rCol, bool& rRow );
+
+ void AutoOutline();
+
+ void SelectLevel( bool bColumns, sal_uInt16 nLevel,
+ bool bRecord = true );
+ void SetOutlineState( bool bColumn, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bHidden);
+ void ShowOutline( bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry,
+ bool bRecord = true, bool bPaint = true );
+ void HideOutline( bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry,
+ bool bRecord = true, bool bPaint = true );
+
+ void ShowMarkedOutlines( bool bRecord = true );
+ void HideMarkedOutlines( bool bRecord = true );
+ bool OutlinePossible(bool bHide);
+
+ void UpdateCharts(bool bAllCharts); // Default: at the Cursor
+
+ static sal_uInt16 DoUpdateCharts( const ScAddress& rPos, ScDocument& rDoc, bool bAllCharts );
+
+ void OnLOKShowHideColRow(bool bColumns, SCCOLROW nStartRow);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/dbnamdlg.hxx b/sc/source/ui/inc/dbnamdlg.hxx
new file mode 100644
index 000000000..4958f121d
--- /dev/null
+++ b/sc/source/ui/inc/dbnamdlg.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 <vector>
+#include "anyrefdg.hxx"
+#include <dbdata.hxx>
+
+class ScViewData;
+class ScDocument;
+
+class ScDbNameDlg : public ScAnyRefDlgController
+{
+public:
+ ScDbNameDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScViewData& rViewData);
+ virtual ~ScDbNameDlg() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+
+ virtual bool IsRefInputMode() const override;
+ virtual void SetActive() override;
+ virtual void Close() override;
+
+private:
+ bool bSaved;
+ bool bInvalid;
+
+ OUString aStrAdd;
+ OUString aStrModify;
+ OUString aStrInvalid;
+
+ OUString aStrSource;
+ OUString aStrOperations;
+
+ ScViewData& m_rViewData;
+ const ScDocument& rDoc;
+ bool bRefInputMode;
+ ScAddress::Details aAddrDetails;
+
+ ScDBCollection aLocalDbCol;
+ ScRange theCurArea;
+ std::vector<ScRange> aRemoveList;
+
+ std::unique_ptr<weld::EntryTreeView> m_xEdName;
+
+ std::unique_ptr<weld::Frame> m_xAssignFrame;
+ std::unique_ptr<formula::RefEdit> m_xEdAssign;
+ std::unique_ptr<formula::RefButton> m_xRbAssign;
+
+ std::unique_ptr<weld::Widget> m_xOptions;
+ std::unique_ptr<weld::CheckButton> m_xBtnHeader;
+ std::unique_ptr<weld::CheckButton> m_xBtnTotals;
+ std::unique_ptr<weld::CheckButton> m_xBtnDoSize;
+ std::unique_ptr<weld::CheckButton> m_xBtnKeepFmt;
+ std::unique_ptr<weld::CheckButton> m_xBtnStripData;
+ std::unique_ptr<weld::Label> m_xFTSource;
+ std::unique_ptr<weld::Label> m_xFTOperations;
+
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+ std::unique_ptr<weld::Button> m_xBtnAdd;
+ std::unique_ptr<weld::Button> m_xBtnRemove;
+
+ std::unique_ptr<weld::Button> m_xModifyPB;
+ std::unique_ptr<weld::Label> m_xInvalidFT;
+
+ std::unique_ptr<weld::Label> m_xFrameLabel;
+ std::unique_ptr<weld::Expander> m_xExpander;
+private:
+ void Init();
+ void UpdateNames();
+ void UpdateDBData( const OUString& rStrName );
+ void SetInfoStrings( const ScDBData* pDBData );
+
+ DECL_LINK( CancelBtnHdl, weld::Button&, void );
+ DECL_LINK( OkBtnHdl, weld::Button&, void );
+ DECL_LINK( AddBtnHdl, weld::Button&, void );
+ DECL_LINK( RemoveBtnHdl, weld::Button&, void );
+ DECL_LINK( NameModifyHdl, weld::ComboBox&, void );
+ DECL_LINK( AssModifyHdl, formula::RefEdit&, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/delcldlg.hxx b/sc/source/ui/inc/delcldlg.hxx
new file mode 100644
index 000000000..4537b3df2
--- /dev/null
+++ b/sc/source/ui/inc/delcldlg.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 <vcl/weld.hxx>
+
+#include <global.hxx>
+
+class ScDeleteCellDlg : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::RadioButton> m_xBtnCellsUp;
+ std::unique_ptr<weld::RadioButton> m_xBtnCellsLeft;
+ std::unique_ptr<weld::RadioButton> m_xBtnDelRows;
+ std::unique_ptr<weld::RadioButton> m_xBtnDelCols;
+
+public:
+ ScDeleteCellDlg(weld::Window* pParent, bool bDisallowCellMove);
+ virtual ~ScDeleteCellDlg() override;
+
+ DelCellCmd GetDelCellCmd() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/delcodlg.hxx b/sc/source/ui/inc/delcodlg.hxx
new file mode 100644
index 000000000..c23deed4f
--- /dev/null
+++ b/sc/source/ui/inc/delcodlg.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 <vcl/weld.hxx>
+#include <global.hxx>
+
+class ScDeleteContentsDlg : public weld::GenericDialogController
+{
+private:
+ bool m_bObjectsDisabled;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnDelAll;
+ std::unique_ptr<weld::CheckButton> m_xBtnDelStrings;
+ std::unique_ptr<weld::CheckButton> m_xBtnDelNumbers;
+ std::unique_ptr<weld::CheckButton> m_xBtnDelDateTime;
+ std::unique_ptr<weld::CheckButton> m_xBtnDelFormulas;
+ std::unique_ptr<weld::CheckButton> m_xBtnDelNotes;
+ std::unique_ptr<weld::CheckButton> m_xBtnDelAttrs;
+ std::unique_ptr<weld::CheckButton> m_xBtnDelObjects;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+
+ static bool bPreviousAllCheck;
+ static InsertDeleteFlags nPreviousChecks;
+
+ void DisableChecks(bool bDelAllChecked);
+ DECL_LINK(DelAllHdl, weld::Toggleable&, void);
+
+public:
+ ScDeleteContentsDlg(weld::Window* pParent);
+ virtual ~ScDeleteContentsDlg() override;
+ void DisableObjects();
+
+ InsertDeleteFlags GetDelContentsCmdBits() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/docfunc.hxx b/sc/source/ui/inc/docfunc.hxx
new file mode 100644
index 000000000..f7ca3e422
--- /dev/null
+++ b/sc/source/ui/inc/docfunc.hxx
@@ -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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in 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/solar.h>
+#include <global.hxx>
+#include <formula/grammar.hxx>
+#include <tabbgcolor.hxx>
+#include <unotools/resmgr.hxx>
+
+#include <memory>
+#include <vector>
+#include <map>
+
+class ScEditEngineDefaulter;
+class SdrUndoAction;
+class ScAddress;
+class ScDocShell;
+class ScMarkData;
+class ScPatternAttr;
+class ScRange;
+class ScRangeList;
+class ScFormulaCell;
+class ScTokenArray;
+struct ScTabOpParam;
+class ScTableProtection;
+class ScDocProtection;
+struct ScCellMergeOption;
+class ScConditionalFormat;
+class ScConditionalFormatList;
+class ScUndoRemoveMerge;
+class ScRangeName;
+class ScPostIt;
+
+enum class TransliterationFlags;
+enum class CreateNameFlags;
+namespace sc
+{
+ struct ColRowSpan;
+ class SparklineAttributes;
+ class SparklineGroup;
+ class Sparkline;
+}
+
+class ScDocFunc
+{
+protected:
+ ScDocShell& rDocShell;
+
+ bool AdjustRowHeight( const ScRange& rRange, bool bPaint, bool bApi );
+ void CreateOneName( ScRangeName& rList,
+ SCCOL nPosX, SCROW nPosY, SCTAB nTab,
+ SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ bool& rCancel, bool bApi );
+ void NotifyInputHandler( const ScAddress& rPos );
+
+ ScDocFunc( ScDocShell& rDocSh ): rDocShell(rDocSh) {}
+public:
+ virtual ~ScDocFunc() {}
+
+ void NotifyDrawUndo(std::unique_ptr<SdrUndoAction>);
+
+ // for grouping multiple operations into one with a new name
+ void EnterListAction(TranslateId pNameResId);
+ void EndListAction();
+
+ bool DetectiveAddPred(const ScAddress& rPos);
+ bool DetectiveDelPred(const ScAddress& rPos);
+ bool DetectiveAddSucc(const ScAddress& rPos);
+ bool DetectiveDelSucc(const ScAddress& rPos);
+ bool DetectiveAddError(const ScAddress& rPos);
+ bool DetectiveMarkInvalid(SCTAB nTab);
+ bool DetectiveDelAll(SCTAB nTab);
+ bool DetectiveRefresh(bool bAutomatic = false);
+ void DetectiveCollectAllPreds(const ScRangeList& rSrcRanges, ::std::vector<ScTokenRef>& rRefTokens);
+ void DetectiveCollectAllSuccs(const ScRangeList& rSrcRanges, ::std::vector<ScTokenRef>& rRefTokens);
+
+ SC_DLLPUBLIC bool DeleteContents(
+ const ScMarkData& rMark, InsertDeleteFlags nFlags, bool bRecord, bool bApi );
+
+ bool DeleteCell(
+ const ScAddress& rPos, const ScMarkData& rMark, InsertDeleteFlags nFlags, bool bRecord, bool bApi );
+
+ bool TransliterateText( const ScMarkData& rMark, TransliterationFlags nType,
+ bool bApi );
+
+ bool SetNormalString( bool& o_rbNumFmtSet, const ScAddress& rPos, const OUString& rText, bool bApi );
+ bool SetValueCell( const ScAddress& rPos, double fVal, bool bInteraction );
+ void SetValueCells( const ScAddress& rPos, const std::vector<double>& aVals, bool bInteraction );
+ bool SetStringCell( const ScAddress& rPos, const OUString& rStr, bool bInteraction );
+ bool SetEditCell( const ScAddress& rPos, const EditTextObject& rStr, bool bInteraction );
+
+ bool SetStringOrEditCell( const ScAddress& rPos, const OUString& rStr, bool bInteraction );
+
+ /**
+ * Below two methods take ownership of the formula cell instance(s). The caller
+ * must not delete it after passing it to this call.
+ */
+ bool SetFormulaCell( const ScAddress& rPos, ScFormulaCell* pCell, bool bInteraction );
+ bool SetFormulaCells( const ScAddress& rPos, std::vector<ScFormulaCell*>& rCells, bool bInteraction );
+ void PutData( const ScAddress& rPos, ScEditEngineDefaulter& rEngine, bool bApi );
+ bool SetCellText(
+ const ScAddress& rPos, const OUString& rText, bool bInterpret, bool bEnglish, bool bApi,
+ const formula::FormulaGrammar::Grammar eGrammar );
+
+ SC_DLLPUBLIC bool ShowNote( const ScAddress& rPos, bool bShow );
+
+ void SetNoteText( const ScAddress& rPos, const OUString& rNoteText, bool bApi );
+ void ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, const OUString* pAuthor, const OUString* pDate, bool bApi );
+ SC_DLLPUBLIC ScPostIt* ImportNote( const ScAddress& rPos, const OUString& rNoteText );
+
+ bool ApplyAttributes( const ScMarkData& rMark, const ScPatternAttr& rPattern,
+ bool bApi );
+ bool ApplyStyle( const ScMarkData& rMark, const OUString& rStyleName,
+ bool bApi );
+
+ bool InsertCells( const ScRange& rRange,const ScMarkData* pTabMark,
+ InsCellCmd eCmd, bool bRecord, bool bApi, bool bPartOfPaste = false );
+
+ bool DeleteCells( const ScRange& rRange, const ScMarkData* pTabMark,
+ DelCellCmd eCmd, bool bApi );
+
+ bool MoveBlock( const ScRange& rSource, const ScAddress& rDestPos,
+ bool bCut, bool bRecord, bool bPaint, bool bApi );
+
+ SC_DLLPUBLIC bool InsertTable( SCTAB nTab, const OUString& rName, bool bRecord, bool bApi );
+ bool RenameTable( SCTAB nTab, const OUString& rName, bool bRecord, bool bApi );
+ bool DeleteTable( SCTAB nTab, bool bRecord );
+
+ bool SetTabBgColor( SCTAB nTab, const Color& rColor, bool bRecord, bool bApi );
+ bool SetTabBgColor( ScUndoTabColorInfo::List& rUndoTabColorList, bool bApi );
+
+ void SetTableVisible( SCTAB nTab, bool bVisible, bool bApi );
+
+ bool SetLayoutRTL( SCTAB nTab, bool bRTL );
+
+ SC_DLLPUBLIC bool SetWidthOrHeight(
+ bool bWidth, const std::vector<sc::ColRowSpan>& rRanges, SCTAB nTab,
+ ScSizeMode eMode, sal_uInt16 nSizeTwips, bool bRecord, bool bApi );
+
+ bool InsertPageBreak( bool bColumn, const ScAddress& rPos,
+ bool bRecord, bool bSetModified );
+ bool RemovePageBreak( bool bColumn, const ScAddress& rPos,
+ bool bRecord, bool bSetModified );
+
+ void ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect );
+
+ bool Protect( SCTAB nTab, const OUString& rPassword );
+ bool Unprotect( SCTAB nTab, const OUString& rPassword, bool bApi );
+
+ void ClearItems( const ScMarkData& rMark, const sal_uInt16* pWhich, bool bApi );
+ bool ChangeIndent( const ScMarkData& rMark, bool bIncrement, bool bApi );
+ bool AutoFormat( const ScRange& rRange, const ScMarkData* pTabMark,
+ sal_uInt16 nFormatNo, bool bApi );
+
+ SC_DLLPUBLIC bool
+ EnterMatrix( const ScRange& rRange, const ScMarkData* pTabMark,
+ const ScTokenArray* pTokenArray,
+ const OUString& rString, bool bApi, bool bEnglish,
+ const OUString& rFormulaNmsp,
+ const formula::FormulaGrammar::Grammar );
+
+ bool TabOp( const ScRange& rRange, const ScMarkData* pTabMark,
+ const ScTabOpParam& rParam, bool bRecord, bool bApi );
+
+ bool FillSimple( const ScRange& rRange, const ScMarkData* pTabMark,
+ FillDir eDir, bool bApi );
+ bool FillSeries( const ScRange& rRange, const ScMarkData* pTabMark,
+ FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd,
+ double fStart, double fStep, double fMax,
+ bool bApi );
+
+ // FillAuto: rRange is change from Source-Range to Dest-Range
+ SC_DLLPUBLIC bool
+ FillAuto( ScRange& rRange, const ScMarkData* pTabMark, FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, sal_uLong nCount, double fStep, double fMax, bool bRecord, bool bApi );
+
+ bool FillAuto( ScRange& rRange, const ScMarkData* pTabMark,
+ FillDir eDir, sal_uLong nCount, bool bApi );
+
+ void ResizeMatrix( const ScRange& rOldRange, const ScAddress& rNewEnd );
+
+ SC_DLLPUBLIC bool
+ MergeCells( const ScCellMergeOption& rOption, bool bContents,
+ bool bRecord, bool bApi, bool bEmptyMergedCells = false );
+ bool UnmergeCells( const ScRange& rRange, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge );
+ SC_DLLPUBLIC bool
+ UnmergeCells( const ScCellMergeOption& rOption, bool bRecord, ScUndoRemoveMerge* pUndoRemoveMerge );
+
+ // takes ownership of pNewRanges, nTab = -1 for local range names
+ void SetNewRangeNames( std::unique_ptr<ScRangeName> pNewRanges, bool bModifyDoc, SCTAB nTab );
+ void ModifyRangeNames( const ScRangeName& rNewRanges, SCTAB nTab = -1 );
+ /**
+ * Modify all range names, global scope names as well as sheet local ones,
+ * in one go. Note that this method will <b>not</b> destroy the instances
+ * passed as arguments (it creates copies); the caller is responsible for
+ * destroying them.
+ */
+ void ModifyAllRangeNames(const std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap);
+
+ bool CreateNames( const ScRange& rRange, CreateNameFlags nFlags, bool bApi, SCTAB nTab = -1 ); // -1 for global range names
+ bool InsertNameList( const ScAddress& rStartPos, bool bApi );
+
+ void InsertAreaLink( const OUString& rFile, const OUString& rFilter,
+ const OUString& rOptions, const OUString& rSource,
+ const ScRange& rDestRange, sal_Int32 nRefreshDelaySeconds,
+ bool bFitBlock, bool bApi );
+
+ /**
+ * @param nOldIndex If 0 don't delete an old format
+ * @param pFormat if NULL only delete an old format
+ */
+ void ReplaceConditionalFormat( sal_uLong nOldIndex, std::unique_ptr<ScConditionalFormat> pFormat, SCTAB nTab, const ScRangeList& rRanges );
+
+ /**
+ * Sets or replaces the conditional format list of a table
+ *
+ * @param pList the new ScConditionalFormatList, method takes ownership
+ * @param nTab the tab to which the conditional format list belongs
+ */
+ void SetConditionalFormatList( ScConditionalFormatList* pList, SCTAB nTab );
+
+ void ConvertFormulaToValue( const ScRange& rRange, bool bInteraction );
+
+ SC_DLLPUBLIC bool InsertSparklines(ScRange const& rDataRange, ScRange const& rSparklineRange,
+ std::shared_ptr<sc::SparklineGroup> pSparklineGroup);
+
+ SC_DLLPUBLIC bool DeleteSparkline(ScAddress const& rAddress);
+ SC_DLLPUBLIC bool DeleteSparklineGroup(std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup, SCTAB nTab);
+ SC_DLLPUBLIC bool ChangeSparklineGroupAttributes(std::shared_ptr<sc::SparklineGroup> const& pExistingSparklineGroup,
+ sc::SparklineAttributes const& rNewAttributes);
+ SC_DLLPUBLIC bool GroupSparklines(ScRange const& rRange, std::shared_ptr<sc::SparklineGroup> const& rpGroup);
+ SC_DLLPUBLIC bool UngroupSparklines(ScRange const& rRange);
+ SC_DLLPUBLIC bool ChangeSparkline(std::shared_ptr<sc::Sparkline> const& rpSparkline, SCTAB nTab, ScRangeList const& rDataRange);
+
+private:
+ void ProtectDocument(const ScDocProtection& rProtect);
+};
+
+class ScDocFuncDirect final : public ScDocFunc
+{
+public:
+ ScDocFuncDirect( ScDocShell& rDocSh ) : ScDocFunc( rDocSh ) {}
+};
+
+void VBA_DeleteModule( ScDocShell& rDocSh, const OUString& sModuleName );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/docfuncutil.hxx b/sc/source/ui/inc/docfuncutil.hxx
new file mode 100644
index 000000000..c0b439d3e
--- /dev/null
+++ b/sc/source/ui/inc/docfuncutil.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 "undobase.hxx"
+
+#include <memory>
+
+class ScMarkData;
+class ScRange;
+enum class InsertDeleteFlags : sal_uInt16;
+
+namespace sc {
+
+class DocFuncUtil
+{
+public:
+
+ static bool hasProtectedTab( const ScDocument& rDoc, const ScMarkData& rMark );
+
+ static ScDocumentUniquePtr createDeleteContentsUndoDoc(
+ ScDocument& rDoc, const ScMarkData& rMark, const ScRange& rRange,
+ InsertDeleteFlags nFlags, bool bOnlyMarked );
+
+ static void addDeleteContentsUndo(
+ SfxUndoManager* pUndoMgr, ScDocShell* pDocSh, const ScMarkData& rMark,
+ const ScRange& rRange, ScDocumentUniquePtr&& pUndoDoc, InsertDeleteFlags nFlags,
+ const std::shared_ptr<ScSimpleUndo::DataSpansType>& pSpans,
+ bool bMulti, bool bDrawUndo );
+
+ static std::shared_ptr<ScSimpleUndo::DataSpansType> getNonEmptyCellSpans(
+ const ScDocument& rDoc, const ScMarkData& rMark, const ScRange& rRange );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/docsh.hxx b/sc/source/ui/inc/docsh.hxx
new file mode 100644
index 000000000..95bd297ef
--- /dev/null
+++ b/sc/source/ui/inc/docsh.hxx
@@ -0,0 +1,504 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/objsh.hxx>
+#include <sfx2/docfac.hxx>
+#include <sfx2/sfxmodelfactory.hxx>
+#include <sfx2/viewsh.hxx>
+#include <o3tl/deleter.hxx>
+#include <comphelper/servicehelper.hxx>
+
+#include <scdllapi.h>
+#include <document.hxx>
+#include <shellids.hxx>
+#include <optutil.hxx>
+#include <docuno.hxx>
+
+#include <memory>
+#include <string_view>
+#include <unordered_map>
+#include <map>
+
+class ScRefreshTimerProtector;
+class ScEditEngineDefaulter;
+class SfxStyleSheetBasePool;
+class SfxStyleSheetHint;
+class INetURLObject;
+
+class ScViewData;
+class ScDocFunc;
+class ScDrawLayer;
+class ScTabViewShell;
+class ScAutoStyleList;
+class ScMarkData;
+class ScPaintLockData;
+class ScChangeAction;
+class ScImportOptions;
+class ScDocShellModificator;
+class ScOptSolverSave;
+class ScSheetSaveData;
+class ScFlatBoolRowSegments;
+struct ScColWidthParam;
+class ScFormulaOptions;
+namespace com::sun::star::script::vba { class XVBAScriptListener; }
+namespace ooo::vba::excel { class XWorkbook; }
+namespace com::sun::star::datatransfer { class XTransferable2; }
+namespace sfx2 { class FileDialogHelper; }
+struct DocShell_Impl;
+
+typedef std::unordered_map< sal_uLong, sal_uLong > ScChangeActionMergeMap;
+
+//enum ScDBFormat { SC_FORMAT_SDF, SC_FORMAT_DBF };
+
+enum class LOKCommentNotificationType { Add, Modify, Remove };
+
+extern "C" SAL_DLLPUBLIC_EXPORT bool TestImportDBF(SvStream &rStream);
+
+ // Extra flags for Repaint
+#define SC_PF_LINES 1
+#define SC_PF_TESTMERGE 2
+#define SC_PF_WHOLEROWS 4
+
+class SC_DLLPUBLIC ScDocShell final: public SfxObjectShell, public SfxListener
+{
+ std::shared_ptr<ScDocument> m_pDocument;
+
+ OUString m_aDdeTextFmt;
+
+ double m_nPrtToScreenFactor;
+ std::unique_ptr<DocShell_Impl> m_pImpl;
+ std::unique_ptr<ScDocFunc> m_pDocFunc;
+
+ bool m_bHeaderOn;
+ bool m_bFooterOn;
+ bool m_bIsInplace:1; // Is set by the View
+ bool m_bIsEmpty:1;
+ bool m_bIsInUndo:1;
+ bool m_bDocumentModifiedPending:1;
+ bool m_bUpdateEnabled:1;
+ bool m_bUcalcTest:1; // avoid loading the styles in the ucalc test
+ bool m_bAreasChangedNeedBroadcast:1;
+ sal_uInt16 m_nDocumentLock;
+ sal_Int16 m_nCanUpdate; // stores the UpdateDocMode from loading a document till update links
+
+ std::unique_ptr<ScDBData> m_pOldAutoDBRange;
+
+ std::unique_ptr<ScAutoStyleList> m_pAutoStyleList;
+ std::unique_ptr<ScPaintLockData> m_pPaintLockData;
+ std::unique_ptr<ScOptSolverSave> m_pSolverSaveData;
+ std::unique_ptr<ScSheetSaveData> m_pSheetSaveData;
+ std::unique_ptr<ScFormatSaveData> m_pFormatSaveData;
+
+ std::unique_ptr<ScDocShellModificator, o3tl::default_delete<ScDocShellModificator>> m_pModificator; // #109979#; is used to load XML (created in BeforeXMLLoading and destroyed in AfterXMLLoading)
+
+ css::uno::Reference< ooo::vba::excel::XWorkbook> mxAutomationWorkbookObject;
+
+ // Only used by Vba helper functions
+ css::uno::Reference<css::script::vba::XVBAScriptListener> m_xVBAListener;
+ css::uno::Reference<css::datatransfer::XTransferable2> m_xClipData;
+
+ SAL_DLLPRIVATE void InitItems();
+ SAL_DLLPRIVATE void DoEnterHandler();
+ SAL_DLLPRIVATE void InitOptions(bool bForLoading);
+ SAL_DLLPRIVATE void ResetDrawObjectShell();
+
+ /** Do things that need to be done before saving to our own format and
+ necessary clean ups in dtor. */
+ class SAL_DLLPRIVATE PrepareSaveGuard
+ {
+ public:
+ explicit PrepareSaveGuard( ScDocShell & rDocShell );
+ ~PrepareSaveGuard() COVERITY_NOEXCEPT_FALSE;
+ private:
+ ScDocShell & mrDocShell;
+ };
+
+ SAL_DLLPRIVATE bool LoadXML( SfxMedium* pMedium, const css::uno::Reference< css::embed::XStorage >& );
+ SAL_DLLPRIVATE bool SaveXML( SfxMedium* pMedium, const css::uno::Reference< css::embed::XStorage >& );
+ SAL_DLLPRIVATE SCTAB GetSaveTab();
+
+ friend bool TestImportDBF(SvStream &rStream);
+
+ SAL_DLLPRIVATE ErrCode DBaseImport( const OUString& rFullFileName, rtl_TextEncoding eCharSet,
+ std::map<SCCOL, ScColWidthParam>& aColWidthParam, ScFlatBoolRowSegments& rRowHeightsRecalc );
+ SAL_DLLPRIVATE ErrCode DBaseExport(
+ const OUString& rFullFileName, rtl_TextEncoding eCharSet, bool& bHasMemo );
+
+ SAL_DLLPRIVATE static bool MoveFile( const INetURLObject& rSource, const INetURLObject& rDest );
+ SAL_DLLPRIVATE static bool KillFile( const INetURLObject& rURL );
+ SAL_DLLPRIVATE static bool IsDocument( const INetURLObject& rURL );
+
+ SAL_DLLPRIVATE void LockPaint_Impl(bool bDoc);
+ SAL_DLLPRIVATE void UnlockPaint_Impl(bool bDoc);
+ SAL_DLLPRIVATE void LockDocument_Impl(sal_uInt16 nNew);
+ SAL_DLLPRIVATE void UnlockDocument_Impl(sal_uInt16 nNew);
+
+ SAL_DLLPRIVATE void EnableSharedSettings( bool bEnable );
+ SAL_DLLPRIVATE css::uno::Reference< css::frame::XModel > LoadSharedDocument();
+
+ SAL_DLLPRIVATE void UseSheetSaveEntries();
+
+ SAL_DLLPRIVATE std::unique_ptr<ScDocFunc> CreateDocFunc();
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+public:
+ SFX_DECL_INTERFACE(SCID_DOC_SHELL)
+ SFX_DECL_OBJECTFACTORY();
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ explicit ScDocShell( const ScDocShell& rDocShell ) = delete;
+ explicit ScDocShell( const SfxModelFlags i_nSfxCreationFlags = SfxModelFlags::EMBEDDED_OBJECT, const std::shared_ptr<ScDocument>& pDoc = {} );
+ virtual ~ScDocShell() override;
+
+ virtual SfxUndoManager*
+ GetUndoManager() override;
+
+ virtual void FillClass( SvGlobalName * pClassName,
+ SotClipboardFormatId * pFormat,
+ OUString * pFullTypeName,
+ sal_Int32 nFileFormat,
+ bool bTemplate = false ) const override;
+
+ virtual std::set<Color> GetDocColors() override;
+
+ virtual bool InitNew( const css::uno::Reference< css::embed::XStorage >& ) override;
+ virtual bool Load( SfxMedium& rMedium ) override;
+ virtual bool LoadFrom( SfxMedium& rMedium ) override;
+ virtual bool ConvertFrom( SfxMedium &rMedium ) override;
+ virtual bool LoadExternal( SfxMedium& rMedium ) override;
+ virtual bool Save() override;
+ virtual bool SaveAs( SfxMedium& rMedium ) override;
+ virtual bool ConvertTo( SfxMedium &rMedium ) override;
+ virtual bool PrepareClose( bool bUI = true ) override;
+ virtual void LoadStyles( SfxObjectShell &rSource ) override;
+
+ virtual bool DoSaveCompleted( SfxMedium * pNewStor=nullptr, bool bRegisterRecent=true ) override; // SfxObjectShell
+ virtual bool QuerySlotExecutable( sal_uInt16 nSlotId ) override;
+
+ virtual void Draw( OutputDevice *, const JobSetup & rSetup, sal_uInt16 nAspect ) override;
+
+ virtual void SetVisArea( const tools::Rectangle & rVisArea ) override;
+
+ virtual void TerminateEditing() override;
+
+ using SfxObjectShell::GetVisArea;
+ virtual tools::Rectangle GetVisArea( sal_uInt16 nAspect ) const override;
+
+ virtual Printer* GetDocumentPrinter() override;
+
+ virtual void SetModified( bool = true ) override;
+
+ void SetVisAreaOrSize( const tools::Rectangle& rVisArea );
+
+ virtual std::shared_ptr<SfxDocumentInfoDialog> CreateDocumentInfoDialog(weld::Window* pParent, const SfxItemSet &rSet) override;
+
+ void GetDocStat( ScDocStat& rDocStat );
+
+ const ScDocument& GetDocument() const { return *m_pDocument; }
+ ScDocument& GetDocument() { return *m_pDocument; }
+ ScDocFunc& GetDocFunc() { return *m_pDocFunc; }
+
+ css::uno::Reference<css::datatransfer::XTransferable2> const & GetClipData() const { return m_xClipData; }
+ void SetClipData(const css::uno::Reference<css::datatransfer::XTransferable2>& xTransferable) { m_xClipData = xTransferable; }
+
+ SfxPrinter* GetPrinter( bool bCreateIfNotExist = true );
+ sal_uInt16 SetPrinter( VclPtr<SfxPrinter> const & pNewPrinter, SfxPrinterChangeFlags nDiffFlags = SFX_PRINTER_ALL );
+
+ void UpdateFontList();
+
+ ScDrawLayer* MakeDrawLayer();
+
+ void AsciiSave( SvStream& rStream, const ScImportOptions& rOpt, SCTAB nTab );
+
+ void Execute( SfxRequest& rReq );
+ void GetState( SfxItemSet &rSet );
+ void ExecutePageStyle ( const SfxViewShell& rCaller, SfxRequest& rReq, SCTAB nCurTab );
+ void GetStatePageStyle( SfxItemSet& rSet, SCTAB nCurTab );
+
+ void CompareDocument( ScDocument& rOtherDoc );
+ void MergeDocument( ScDocument& rOtherDoc, bool bShared = false, bool bCheckDuplicates = false, sal_uLong nOffset = 0, ScChangeActionMergeMap* pMergeMap = nullptr, bool bInverseMap = false );
+ bool MergeSharedDocument( ScDocShell* pSharedDocShell );
+
+ ScChangeAction* GetChangeAction( const ScAddress& rPos );
+ void SetChangeComment( ScChangeAction* pAction, const OUString& rComment );
+ void ExecuteChangeCommentDialog( ScChangeAction* pAction, weld::Window* pParent, bool bPrevNext = true );
+ /// Protect/unprotect ChangeTrack and return <TRUE/> if
+ /// protection was successfully changed.
+ /// If bJustQueryIfProtected==sal_True protection is not
+ /// changed and <TRUE/> is returned if not protected or
+ /// password was entered correctly.
+ bool ExecuteChangeProtectionDialog( bool bJustQueryIfProtected = false );
+
+ void SetPrintZoom( SCTAB nTab, sal_uInt16 nScale, sal_uInt16 nPages );
+ bool AdjustPrintZoom( const ScRange& rRange );
+
+ void LoadStylesArgs( ScDocShell& rSource, bool bReplace, bool bCellStyles, bool bPageStyles );
+
+ void PageStyleModified( std::u16string_view rStyleName, bool bApi );
+
+ void NotifyStyle( const SfxStyleSheetHint& rHint );
+ void DoAutoStyle( const ScRange& rRange, const OUString& rStyle );
+
+ static weld::Window* GetActiveDialogParent();
+ void ErrorMessage(TranslateId pGlobStrId);
+ bool IsEditable() const;
+
+ bool AdjustRowHeight( SCROW nStartRow, SCROW nEndRow, SCTAB nTab );
+ void UpdateAllRowHeights( const ScMarkData* pTabMark = nullptr );
+ void UpdatePendingRowHeights( SCTAB nUpdateTab, bool bBefore = false );
+
+ void RefreshPivotTables( const ScRange& rSource );
+ void DoConsolidate( const ScConsolidateParam& rParam, bool bRecord = true );
+ void UseScenario( SCTAB nTab, const OUString& rName, bool bRecord = true );
+ SCTAB MakeScenario(SCTAB nTab, const OUString& rName, const OUString& rComment,
+ const Color& rColor, ScScenarioFlags nFlags,
+ ScMarkData& rMark, bool bRecord = true);
+ void ModifyScenario(SCTAB nTab, const OUString& rName, const OUString& rComment,
+ const Color& rColor, ScScenarioFlags nFlags);
+ sal_uLong TransferTab( ScDocShell& rSrcDocShell, SCTAB nSrcPos,
+ SCTAB nDestPos, bool bInsertNew,
+ bool bNotifyAndPaint );
+
+ bool MoveTable( SCTAB nSrcTab, SCTAB nDestTab, bool bCopy, bool bRecord );
+
+ void DoRecalc( bool bApi );
+ void DoHardRecalc();
+
+ void UpdateOle(const ScViewData& rViewData, bool bSnapSize = false);
+ bool IsOle() const;
+
+ void DBAreaDeleted( SCTAB nTab, SCCOL nX1, SCROW nY1, SCCOL nX2 );
+ ScDBData* GetDBData( const ScRange& rMarked, ScGetDBMode eMode, ScGetDBSelection eSel );
+ ScDBData* GetAnonymousDBData(const ScRange& rRange);
+ std::unique_ptr<ScDBData> GetOldAutoDBRange();
+ void CancelAutoDBRange(); // called when dialog is cancelled
+
+ virtual void ReconnectDdeLink(SfxObjectShell& rServer) override;
+ void UpdateLinks() override;
+ void SetInitialLinkUpdate( const SfxMedium* pMedium );
+ void AllowLinkUpdate();
+ void ReloadAllLinks();
+ void ReloadTabLinks();
+ ScLkUpdMode GetLinkUpdateModeState() const;
+
+ void SetFormulaOptions( const ScFormulaOptions& rOpt, bool bForLoading = false );
+ /**
+ * Called when the Options dialog is dismissed with the OK button, to
+ * handle potentially conflicting option settings.
+ */
+ void CheckConfigOptions();
+
+ void PostEditView( ScEditEngineDefaulter* pEditEngine, const ScAddress& rCursorPos );
+
+ void PostPaint( SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, PaintPartFlags nPart,
+ sal_uInt16 nExtFlags = 0 );
+ void PostPaint( const ScRangeList& rRanges, PaintPartFlags nPart, sal_uInt16 nExtFlags = 0 );
+
+ void PostPaintCell( SCCOL nCol, SCROW nRow, SCTAB nTab );
+ void PostPaintCell( const ScAddress& rPos );
+ void PostPaintGridAll();
+ void PostPaintExtras();
+
+ bool IsPaintLocked() const { return m_pPaintLockData != nullptr; }
+
+ void PostDataChanged();
+
+ void UpdatePaintExt( sal_uInt16& rExtFlags, SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab,
+ SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab );
+ void UpdatePaintExt( sal_uInt16& rExtFlags, const ScRange& rRange );
+
+ void SetDocumentModified();
+ void SetDrawModified();
+
+ void LockPaint();
+ void UnlockPaint();
+ sal_uInt16 GetLockCount() const { return m_nDocumentLock;}
+ void SetLockCount(sal_uInt16 nNew);
+
+ void LockDocument();
+ void UnlockDocument();
+
+ DECL_DLLPRIVATE_LINK( DialogClosedHdl, sfx2::FileDialogHelper*, void );
+ DECL_DLLPRIVATE_LINK( ReloadAllLinksHdl, weld::Button&, void );
+
+ virtual SfxStyleSheetBasePool* GetStyleSheetPool() override;
+
+ void SetInplace( bool bInplace );
+ bool IsEmpty() const { return m_bIsEmpty; }
+ void SetEmpty(bool bSet);
+
+ bool IsInUndo() const { return m_bIsInUndo; }
+ void SetInUndo(bool bSet);
+
+ void CalcOutputFactor();
+ double GetOutputFactor() const { return m_nPrtToScreenFactor;}
+ void GetPageOnFromPageStyleSet( const SfxItemSet* pStyleSet,
+ SCTAB nCurTab,
+ bool& rbHeader,
+ bool& rbFooter );
+
+#if defined(_WIN32)
+ virtual bool DdeGetData( const OUString& rItem, const OUString& rMimeType,
+ css::uno::Any & rValue ) override;
+ virtual bool DdeSetData( const OUString& rItem, const OUString& rMimeType,
+ const css::uno::Any & rValue ) override;
+#endif
+
+ virtual ::sfx2::SvLinkSource* DdeCreateLinkSource( const OUString& rItem ) override;
+
+ const OUString& GetDdeTextFmt() const { return m_aDdeTextFmt; }
+
+ SfxBindings* GetViewBindings();
+
+ ScTabViewShell* GetBestViewShell( bool bOnlyVisible = true );
+
+ void SetDocumentModifiedPending( bool bVal )
+ { m_bDocumentModifiedPending = bVal; }
+ bool IsDocumentModifiedPending() const
+ { return m_bDocumentModifiedPending; }
+
+ bool IsUpdateEnabled() const
+ { return m_bUpdateEnabled; }
+ void SetUpdateEnabled(bool bValue)
+ { m_bUpdateEnabled = bValue; }
+
+ void SetAreasChangedNeedBroadcast()
+ { m_bAreasChangedNeedBroadcast = true; }
+
+ OutputDevice* GetRefDevice(); // WYSIWYG: Printer, otherwise VirtualDevice...
+
+ static ScViewData* GetViewData();
+ static SCTAB GetCurTab();
+
+ static ScDocShell* GetShellByNum( sal_uInt16 nDocNo );
+ static OUString GetOwnFilterName();
+ static OUString GetHtmlFilterName();
+ static OUString GetWebQueryFilterName();
+ static OUString GetAsciiFilterName();
+ static OUString GetLotusFilterName();
+ static OUString GetDBaseFilterName();
+ static OUString GetDifFilterName();
+ static bool HasAutomaticTableName( std::u16string_view rFilter );
+ static void LOKCommentNotify(LOKCommentNotificationType nType, const ScDocument* pDocument, const ScAddress& rPos, const ScPostIt* pNote);
+
+ DECL_DLLPRIVATE_LINK( RefreshDBDataHdl, Timer*, void );
+
+ void BeforeXMLLoading();
+ void AfterXMLLoading(bool bRet);
+
+ virtual HiddenInformation GetHiddenInformationState( HiddenInformation nStates ) override;
+
+ const ScOptSolverSave* GetSolverSaveData() const { return m_pSolverSaveData.get(); } // may be null
+ void SetSolverSaveData( std::unique_ptr<ScOptSolverSave> pData );
+ ScSheetSaveData* GetSheetSaveData();
+ ScFormatSaveData* GetFormatSaveData();
+
+ static void ResetKeyBindings( ScOptionsUtil::KeyBindingType eType );
+
+ // password protection for Calc (derived from SfxObjectShell)
+ // see also: FID_CHG_RECORD, SID_CHG_PROTECT
+ virtual bool IsChangeRecording() const override;
+ virtual bool HasChangeRecordProtection() const override;
+ virtual void SetChangeRecording( bool bActivate, bool bLockAllViews = false ) override;
+ virtual void SetProtectionPassword( const OUString &rPassword ) override;
+ virtual bool GetProtectionHash( /*out*/ css::uno::Sequence< sal_Int8 > &rPasswordHash ) override;
+
+ void SnapVisArea( tools::Rectangle& rRect ) const;
+
+ void SetIsInUcalc();
+
+ void RegisterAutomationWorkbookObject(css::uno::Reference< ooo::vba::excel::XWorkbook > const& xWorkbook);
+};
+
+void UpdateAcceptChangesDialog();
+
+typedef tools::SvRef<ScDocShell> ScDocShellRef;
+
+/** Create before modifications of the document and destroy thereafter.
+ Call SetDocumentModified() at an instance of this class instead of at
+ ScDocShell.
+
+ Remembers in the ctor ScDocument's AutoCalcShellDisabled and IdleDisabled,
+ switches them off and restores them in the dtor, AutoCalcShellDisabled
+ also before a ScDocShell::SetDocumentModified() call if necessary.
+ In the dtor, if ScDocShell's bDocumentModifiedPending is set and
+ bAutoCalcShellDisabled is not set, then ScDocShell::SetDocumentModified()
+ is called.
+
+ Several instances can be used in nested calls to ScDocFunc or ScDocShell
+ methods to avoid multiple modified status changes, only the last instance
+ destroyed calls ScDocShell::SetDocumentModified().
+ */
+class ScDocShellModificator
+{
+ ScDocShell& rDocShell;
+ std::unique_ptr<ScRefreshTimerProtector> mpProtector;
+ bool bAutoCalcShellDisabled;
+ bool bIdleEnabled;
+
+ ScDocShellModificator( const ScDocShellModificator& ) = delete;
+ ScDocShellModificator& operator=( const ScDocShellModificator& ) = delete;
+
+public:
+ explicit ScDocShellModificator( ScDocShell& );
+ ~ScDocShellModificator() COVERITY_NOEXCEPT_FALSE;
+ void SetDocumentModified();
+};
+
+//#i97876# Spreadsheet data changes are not notified
+namespace HelperNotifyChanges
+{
+ inline ScModelObj* getMustPropagateChangesModel(const ScDocShell &rDocShell)
+ {
+ ScModelObj* pModelObj = comphelper::getFromUnoTunnel<ScModelObj>(rDocShell.GetModel());
+ if (pModelObj && pModelObj->HasChangesListeners())
+ return pModelObj;
+ return nullptr;
+ }
+
+ inline void Notify(ScModelObj &rModelObj, const ScRangeList &rChangeRanges,
+ const OUString &rType = OUString("cell-change"),
+ const css::uno::Sequence< css::beans::PropertyValue >& rProperties =
+ css::uno::Sequence< css::beans::PropertyValue >())
+ {
+ rModelObj.NotifyChanges(rType, rChangeRanges, rProperties);
+ }
+
+ inline void NotifyIfChangesListeners(const ScDocShell &rDocShell, const ScRange &rRange,
+ const OUString &rType = OUString("cell-change"))
+ {
+ if (ScModelObj* pModelObj = getMustPropagateChangesModel(rDocShell))
+ {
+ ScRangeList aChangeRanges(rRange);
+ Notify(*pModelObj, aChangeRanges, rType);
+ }
+ }
+};
+
+void VBA_InsertModule( ScDocument& rDoc, SCTAB nTab, const OUString& sModuleSource );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/dpcontrol.hxx b/sc/source/ui/inc/dpcontrol.hxx
new file mode 100644
index 000000000..2d656006e
--- /dev/null
+++ b/sc/source/ui/inc/dpcontrol.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/ustring.hxx>
+#include <tools/gen.hxx>
+#include <tools/fract.hxx>
+#include <vcl/vclptr.hxx>
+#include <vcl/outdev.hxx>
+
+class StyleSettings;
+class ScDocument;
+
+/**
+ * This class takes care of physically drawing field button controls inside
+ * data pilot tables.
+ */
+class ScDPFieldButton
+{
+public:
+ ScDPFieldButton(OutputDevice* pOutDev, const StyleSettings* pStyle, const Fraction* pZoomY = nullptr,
+ ScDocument* pDoc = nullptr);
+ ~ScDPFieldButton();
+
+ void setText(const OUString& rText);
+ void setBoundingBox(const Point& rPos, const Size& rSize, bool bLayoutRTL);
+ void setDrawBaseButton(bool b);
+ void setDrawPopupButton(bool b);
+ void setHasHiddenMember(bool b);
+ void setPopupPressed(bool b);
+ void setPopupLeft(bool b);
+ void draw();
+
+ void getPopupBoundingBox(Point& rPos, Size& rSize) const;
+
+private:
+ void drawPopupButton();
+
+private:
+ Point maPos;
+ Size maSize;
+ OUString maText;
+ Fraction maZoomY;
+ ScDocument* mpDoc;
+ VclPtr<OutputDevice> mpOutDev;
+ const StyleSettings* mpStyle;
+ bool mbBaseButton;
+ bool mbPopupButton;
+ bool mbHasHiddenMember;
+ bool mbPopupPressed;
+ bool mbPopupLeft;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/dpgroupdlg.hxx b/sc/source/ui/inc/dpgroupdlg.hxx
new file mode 100644
index 000000000..d3c390f46
--- /dev/null
+++ b/sc/source/ui/inc/dpgroupdlg.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 <vcl/weld.hxx>
+#include <dpnumgroupinfo.hxx>
+
+class ScDoubleField;
+class SvtCalendarBox;
+
+class ScDPGroupEditHelper
+{
+public:
+ explicit ScDPGroupEditHelper(weld::RadioButton& rRbAuto,
+ weld::RadioButton& rRbMan,
+ weld::Widget& rEdValue);
+
+ bool IsAuto() const;
+ double GetValue() const;
+ void SetValue( bool bAuto, double fValue );
+
+protected:
+ ~ScDPGroupEditHelper() {}
+
+private:
+ virtual bool ImplGetValue( double& rfValue ) const = 0;
+ virtual void ImplSetValue( double fValue ) = 0;
+
+ DECL_LINK(ToggleHdl, weld::Toggleable&, void);
+
+private:
+ weld::RadioButton& mrRbAuto;
+ weld::RadioButton& mrRbMan;
+ weld::Widget& mrEdValue;
+};
+
+class ScDPNumGroupEditHelper : public ScDPGroupEditHelper
+{
+public:
+ explicit ScDPNumGroupEditHelper(weld::RadioButton& rRbAuto,
+ weld::RadioButton& rRbMan,
+ ScDoubleField& rEdValue);
+
+ virtual ~ScDPNumGroupEditHelper() {}
+private:
+ virtual bool ImplGetValue( double& rfValue ) const override;
+ virtual void ImplSetValue( double fValue ) override;
+
+private:
+ ScDoubleField& mrEdValue;
+};
+
+class ScDPDateGroupEditHelper : public ScDPGroupEditHelper
+{
+public:
+ explicit ScDPDateGroupEditHelper(weld::RadioButton& rRbAuto,
+ weld::RadioButton& rRbMan,
+ SvtCalendarBox& rEdValue,
+ const Date& rNullDate);
+
+ virtual ~ScDPDateGroupEditHelper() {}
+
+private:
+ virtual bool ImplGetValue( double& rfValue ) const override;
+ virtual void ImplSetValue( double fValue ) override;
+
+private:
+ SvtCalendarBox& mrEdValue;
+ Date maNullDate;
+};
+
+class ScDPNumGroupDlg : public weld::GenericDialogController
+{
+public:
+ explicit ScDPNumGroupDlg(weld::Window* pParent, const ScDPNumGroupInfo& rInfo);
+ virtual ~ScDPNumGroupDlg() override;
+ ScDPNumGroupInfo GetGroupInfo() const;
+
+private:
+ std::unique_ptr<weld::RadioButton> mxRbAutoStart;
+ std::unique_ptr<weld::RadioButton> mxRbManStart;
+ std::unique_ptr<ScDoubleField> mxEdStart;
+ std::unique_ptr<weld::RadioButton> mxRbAutoEnd;
+ std::unique_ptr<weld::RadioButton> mxRbManEnd;
+ std::unique_ptr<ScDoubleField> mxEdEnd;
+ std::unique_ptr<ScDoubleField> mxEdBy;
+ ScDPNumGroupEditHelper maStartHelper;
+ ScDPNumGroupEditHelper maEndHelper;
+};
+
+class ScDPDateGroupDlg : public weld::GenericDialogController
+{
+public:
+ explicit ScDPDateGroupDlg(weld::Window* pParent, const ScDPNumGroupInfo& rInfo,
+ sal_Int32 nDatePart, const Date& rNullDate);
+ virtual ~ScDPDateGroupDlg() override;
+ ScDPNumGroupInfo GetGroupInfo() const;
+ sal_Int32 GetDatePart() const;
+
+private:
+ DECL_LINK(ToggleHdl, weld::Toggleable&, void);
+ DECL_LINK(CheckHdl, const weld::TreeView::iter_col&, void);
+
+ void Check();
+private:
+ std::unique_ptr<weld::RadioButton> mxRbAutoStart;
+ std::unique_ptr<weld::RadioButton> mxRbManStart;
+ std::unique_ptr<SvtCalendarBox> mxEdStart;
+ std::unique_ptr<weld::RadioButton> mxRbAutoEnd;
+ std::unique_ptr<weld::RadioButton> mxRbManEnd;
+ std::unique_ptr<SvtCalendarBox> mxEdEnd;
+ std::unique_ptr<weld::RadioButton> mxRbNumDays;
+ std::unique_ptr<weld::RadioButton> mxRbUnits;
+ std::unique_ptr<weld::SpinButton> mxEdNumDays;
+ std::unique_ptr<weld::TreeView> mxLbUnits;
+ std::unique_ptr<weld::Button> mxBtnOk;
+ ScDPDateGroupEditHelper maStartHelper;
+ ScDPDateGroupEditHelper maEndHelper;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/drawsh.hxx b/sc/source/ui/inc/drawsh.hxx
new file mode 100644
index 000000000..ae78ad102
--- /dev/null
+++ b/sc/source/ui/inc/drawsh.hxx
@@ -0,0 +1,96 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/shell.hxx>
+#include <shellids.hxx>
+#include <svx/svdtypes.hxx>
+#include <tools/link.hxx>
+#include <rtl/ref.hxx>
+
+class AbstractSvxObjectNameDialog;
+class ScViewData;
+class ScDrawView;
+class SdrMarkList;
+class SfxModule;
+class SdrObject;
+
+namespace weld { class Window; }
+
+namespace svx::sidebar { class SelectionChangeHandler; }
+
+class ScDrawShell : public SfxShell
+{
+ ScViewData& rViewData;
+ ::rtl::Reference<svx::sidebar::SelectionChangeHandler> mpSelectionChangeHandler;
+
+ DECL_LINK( NameObjectHdl, AbstractSvxObjectNameDialog&, bool );
+
+protected:
+ virtual void Activate(bool bMDI) override;
+ ScViewData& GetViewData() { return rViewData; }
+
+public:
+ SFX_DECL_INTERFACE(SCID_DRAW_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScDrawShell(ScViewData& rData);
+ virtual ~ScDrawShell() override;
+
+ static void StateDisableItems( SfxItemSet &rSet );
+
+ void ExecDrawAttr(SfxRequest& rReq);
+ void GetDrawAttrState(SfxItemSet &rSet);
+ void GetAttrFuncState(SfxItemSet &rSet);
+
+ void ExecDrawFunc(SfxRequest& rReq);
+ void GetDrawFuncState(SfxItemSet &rSet);
+ void GetState(SfxItemSet &rSet);
+
+ void ExecFormText(const SfxRequest& rReq); // StarFontWork
+ void GetFormTextState(SfxItemSet& rSet);
+
+ void ExecuteHLink(const SfxRequest& rReq); // Hyperlink
+ void GetHLinkState(SfxItemSet& rSet);
+
+ void ExecFormatPaintbrush(const SfxRequest& rReq);
+ void StateFormatPaintbrush(SfxItemSet& rSet);
+
+ void ExecuteMacroAssign(SdrObject* pObj, weld::Window* pWin);
+ void ExecuteLineDlg( const SfxRequest& rReq );
+ void ExecuteAreaDlg( const SfxRequest& rReq );
+ void ExecuteTextAttrDlg( SfxRequest& rReq );
+ void ExecuteMeasureDlg( SfxRequest& rReq );
+
+ ScDrawView* GetDrawView();
+
+ static bool AreAllObjectsOnLayer(SdrLayerID nLayerNo,const SdrMarkList& rMark);
+
+ void GetDrawAttrStateForIFBX( SfxItemSet& rSet );
+ OUString const & GetSidebarContextName();
+
+ void setModified();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/drawutil.hxx b/sc/source/ui/inc/drawutil.hxx
new file mode 100644
index 000000000..7a241c4f9
--- /dev/null
+++ b/sc/source/ui/inc/drawutil.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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <types.hxx>
+
+class Fraction;
+class OutputDevice;
+class ScDocument;
+
+class ScDrawUtil
+{
+public:
+ static void CalcScale( const ScDocument& rDoc, SCTAB nTab,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ const OutputDevice* pDev, const Fraction& rZoomX, const Fraction& rZoomY,
+ double nPPTX, double nPPTY,
+ Fraction& rScaleX, Fraction& rScaleY );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/drawview.hxx b/sc/source/ui/inc/drawview.hxx
new file mode 100644
index 000000000..816a3428a
--- /dev/null
+++ b/sc/source/ui/inc/drawview.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 <svx/fmview.hxx>
+
+#include <global.hxx>
+
+namespace com::sun::star::datatransfer { class XTransferable; }
+
+class ScDocument;
+class ScViewData;
+class ScDrawObjData;
+class SdrUndoManager;
+
+class ScDrawView final : public FmFormView
+{
+ ScViewData* pViewData;
+ VclPtr<OutputDevice> pDev; //! needed ?
+ ScDocument& rDoc;
+ SCTAB nTab;
+ Fraction aScaleX; // Factor for Drawing-MapMode
+ Fraction aScaleY;
+ std::unique_ptr<SdrDropMarkerOverlay> pDropMarker;
+ SdrObject* pDropMarkObj;
+ bool bInConstruct;
+
+ void Construct();
+
+ virtual void ModelHasChanged() override;
+
+ // add custom handles (used by other apps, e.g. AnchorPos)
+ virtual void AddCustomHdl() override;
+
+ void ImplClearCalcDropMarker();
+
+ // Create a local UndoManager
+ std::unique_ptr<SdrUndoManager> createLocalTextUndoManager() override;
+
+public:
+ ScDrawView(
+ OutputDevice* pOut,
+ ScViewData* pData);
+
+ virtual ~ScDrawView() override;
+
+ virtual void MarkListHasChanged() override;
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual void DoConnect(SdrOle2Obj* pOleObj) override;
+
+ virtual void MakeVisible( const tools::Rectangle& rRect, vcl::Window& rWin ) override;
+
+ virtual void DeleteMarked() 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;
+
+ void MarkDropObj( SdrObject* pObj );
+
+ void SetMarkedToLayer( SdrLayerID nLayerNo );
+
+ void InvalidateAttribs();
+ void InvalidateDrawTextAttrs();
+
+ void BeginDrag( vcl::Window* pWindow, const Point& rStartPos );
+ void DoCut();
+ void DoCopy();
+
+ void GetScale( Fraction& rFractX, Fraction& rFractY ) const;
+ void RecalcScale();
+ void UpdateWorkArea();
+ SCTAB GetTab() const { return nTab; }
+
+ void CalcNormScale( Fraction& rFractX, Fraction& rFractY ) const;
+
+ void SetPageAnchored();
+ void SetCellAnchored(bool bResizeWithCell);
+ ScAnchorType GetAnchorType() const;
+
+ void UpdateIMap( SdrObject* pObj );
+
+ void UpdateUserViewOptions();
+
+ void SetMarkedOriginalSize();
+ void FitToCellSize();
+
+ bool SelectObject( std::u16string_view rName );
+ bool HasMarkedControl() const;
+ bool HasMarkedInternal() const;
+
+ bool InsertObjectSafe(SdrObject* pObj, SdrPageView& rPV);
+
+ /** Returns the selected object, if it is the caption object of a cell note.
+ @param ppCaptData (out-param) If not null, returns the pointer to the caption object data. */
+ SdrObject* GetMarkedNoteCaption( ScDrawObjData** ppCaptData );
+
+ /** Locks/unlocks the specified layer in the draw page.
+ Unlocked layer is required to be able to edit the contained objects. */
+ void LockCalcLayer( SdrLayerID nLayer, bool bLock );
+
+ /** Locks/unlocks the background layer that contains background objects.
+ Unlocked layer is required to be able to edit the objects. */
+ void LockBackgroundLayer( bool bLock ) { LockCalcLayer( SC_LAYER_BACK, bLock ); }
+
+ /** Locks/unlocks the internal layer that contains caption objects of cell notes.
+ Unlocked layer is required to be able to edit the contained objects. */
+ void LockInternalLayer( bool bLock = true ) { LockCalcLayer( SC_LAYER_INTERN, bLock ); }
+ /** Unlocks the internal layer that contains caption objects of cell notes. */
+ void UnlockInternalLayer() { LockInternalLayer( false ); }
+
+ SdrEndTextEditKind ScEndTextEdit(); // calls SetDrawTextUndo(0)
+ css::uno::Reference< css::datatransfer::XTransferable > CopyToTransferable();
+
+ SdrObject* GetObjectByName(std::u16string_view rName);
+ bool GetObjectIsMarked( const SdrObject * pObject );
+ void SelectCurrentViewObject( std::u16string_view rName );
+
+ // #i123922# helper which checks if a Graphic may be applied to an existing
+ // SdrObject; if it's a SdrGrafObj the fill will be replaced. If it's a
+ // fillable, non-OLE SdrObject, the FillStyle will be adapted
+ SdrObject* ApplyGraphicToObject(
+ SdrObject& rHitObject,
+ const Graphic& rGraphic,
+ const OUString& rBeginUndoText,
+ const OUString& rFile);
+
+ static void CheckOle( const SdrMarkList& rMarkList, bool& rAnyOle, bool& rOneOle );
+
+ void SyncForGrid( SdrObject* pObj );
+
+ bool calculateGridOffsetForSdrObject(
+ SdrObject& rSdrObject,
+ basegfx::B2DVector& rTarget) const;
+ bool calculateGridOffsetForB2DRange(
+ const basegfx::B2DRange& rB2DRange,
+ basegfx::B2DVector& rTarget) const;
+ void resetGridOffsetsForAllSdrPageViews();
+
+ /// See SdrMarkView::GetSfxViewShell().
+ SfxViewShell* GetSfxViewShell() const override;
+
+ // Do not create ObjectContact locally, but offer a call to allow override
+ // and to create own derivations of ObjectContact
+ virtual sdr::contact::ObjectContact* createViewSpecificObjectContact(
+ SdrPageWindow& rPageWindow,
+ const char* pDebugName) const override;
+};
+
+extern Point aDragStartDiff;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/drformsh.hxx b/sc/source/ui/inc/drformsh.hxx
new file mode 100644
index 000000000..97da8dee1
--- /dev/null
+++ b/sc/source/ui/inc/drformsh.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 <sfx2/shell.hxx>
+#include <shellids.hxx>
+#include "drawsh.hxx"
+
+class ScViewData;
+class SfxModule;
+
+class ScDrawFormShell final : public ScDrawShell
+{
+public:
+ SFX_DECL_INTERFACE(SCID_FORM_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScDrawFormShell(ScViewData& rData);
+ virtual ~ScDrawFormShell() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/drtxtob.hxx b/sc/source/ui/inc/drtxtob.hxx
new file mode 100644
index 000000000..4690c4625
--- /dev/null
+++ b/sc/source/ui/inc/drtxtob.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 <sfx2/shell.hxx>
+#include <tools/link.hxx>
+#include <rtl/ref.hxx>
+
+#include <shellids.hxx>
+
+sal_uInt16 ScGetFontWorkId(); // instead of SvxFontWorkChildWindow::GetChildWindowId()
+
+class SfxModule;
+class ScViewData;
+class TransferableDataHelper;
+class TransferableClipboardListener;
+
+class ScDrawTextObjectBar final : public SfxShell
+{
+ ScViewData& mrViewData;
+ rtl::Reference<TransferableClipboardListener> mxClipEvtLstnr;
+ bool bPastePossible;
+
+ DECL_LINK( ClipboardChanged, TransferableDataHelper*, void );
+
+public:
+ SFX_DECL_INTERFACE(SCID_DRAW_TEXT_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScDrawTextObjectBar(ScViewData& rData);
+ virtual ~ScDrawTextObjectBar() override;
+
+ static void StateDisableItems( SfxItemSet &rSet );
+
+ void Execute( SfxRequest &rReq );
+ void ExecuteTrans( const SfxRequest& rReq );
+ void GetState( SfxItemSet& rSet );
+ void GetClipState( SfxItemSet& rSet );
+
+ void ExecuteAttr( SfxRequest &rReq );
+ void GetAttrState( SfxItemSet& rSet );
+ void ExecuteToggle( SfxRequest &rReq );
+ void GetStatePropPanelAttr(SfxItemSet &);
+
+ bool ExecuteCharDlg( const SfxItemSet& rArgs, SfxItemSet& rOutSet , sal_uInt16 nSlot);
+ bool ExecuteParaDlg( const SfxItemSet& rArgs, SfxItemSet& rOutSet );
+
+ void ExecuteExtra( SfxRequest &rReq );
+ void ExecFormText(const SfxRequest& rReq); // StarFontWork
+ void GetFormTextState(SfxItemSet& rSet);
+
+private:
+ void ExecuteGlobal( SfxRequest &rReq ); // called by Execute for all objects
+ static void GetGlobalClipState( SfxItemSet& rSet );
+ void ExecutePasteContents( SfxRequest &rReq );
+ bool IsNoteEdit() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/drwtrans.hxx b/sc/source/ui/inc/drwtrans.hxx
new file mode 100644
index 000000000..99fdcf0d4
--- /dev/null
+++ b/sc/source/ui/inc/drwtrans.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+#include <vcl/transfer.hxx>
+
+#include <sfx2/objsh.hxx>
+#include <charthelper.hxx>
+
+class SdrModel;
+class ScDocShell;
+class INetBookmark;
+class SdrObject;
+class SdrView;
+class ScDrawView;
+class SdrOle2Obj;
+enum class ScDragSrc;
+
+class ScDrawTransferObj final : public TransferDataContainer
+{
+private:
+ std::unique_ptr<SdrModel> m_pModel;
+ TransferableDataHelper m_aOleData;
+ TransferableObjectDescriptor m_aObjDesc;
+ SfxObjectShellRef m_aDocShellRef;
+ SfxObjectShellRef m_aDrawPersistRef;
+
+ // extracted from model in ctor:
+ Size m_aSrcSize;
+ std::unique_ptr<INetBookmark> m_pBookmark;
+ bool m_bGraphic;
+ bool m_bGrIsBit;
+ bool m_bOleObj;
+ // source information for drag&drop:
+ // (view is needed to handle drawing objects)
+ std::unique_ptr<SdrView> m_pDragSourceView;
+ ScDragSrc m_nDragSourceFlags;
+ bool m_bDragWasInternal;
+
+ ScRangeListVector m_aProtectedChartRangesVector;
+
+ OUString maShellID;
+
+ void InitDocShell();
+ SdrOle2Obj* GetSingleObject();
+
+ void CreateOLEData();
+
+public:
+ ScDrawTransferObj( std::unique_ptr<SdrModel> pClipModel, ScDocShell* pContainerShell,
+ const TransferableObjectDescriptor& rDesc );
+ virtual ~ScDrawTransferObj() override;
+
+ 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 DragFinished( sal_Int8 nDropAction ) override;
+
+ SdrModel* GetModel() const { return m_pModel.get(); }
+
+ void SetDrawPersist( const SfxObjectShellRef& rRef );
+ void SetDragSource( const ScDrawView* pView );
+ void SetDragSourceObj( SdrObject& rObj, SCTAB nTab );
+ void SetDragSourceFlags( ScDragSrc nFlags );
+ void SetDragWasInternal();
+
+ const OUString& GetShellID() const;
+
+ SdrView* GetDragSourceView() { return m_pDragSourceView.get(); }
+ ScDragSrc GetDragSourceFlags() const { return m_nDragSourceFlags; }
+
+ static ScDrawTransferObj* GetOwnClipboard(const css::uno::Reference<css::datatransfer::XTransferable2>&);
+
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& rId ) override;
+ static const css::uno::Sequence< sal_Int8 >& getUnoTunnelId();
+
+ const ScRangeListVector& GetProtectedChartRangesVector() const { return m_aProtectedChartRangesVector; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/dwfunctr.hxx b/sc/source/ui/inc/dwfunctr.hxx
new file mode 100644
index 000000000..eda067e0b
--- /dev/null
+++ b/sc/source/ui/inc/dwfunctr.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 <comphelper/configurationlistener.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+
+class ScFuncDesc;
+namespace formula { class IFunctionDescription; }
+
+class ScFunctionWin;
+
+class EnglishFunctionNameChange : public comphelper::ConfigurationListenerProperty<bool>
+{
+ ScFunctionWin* m_pFunctionWin;
+protected:
+ virtual void setProperty(const css::uno::Any &rProperty) override;
+public:
+ EnglishFunctionNameChange(const rtl::Reference<comphelper::ConfigurationListener> &rListener, ScFunctionWin* pFunctionWin)
+ : ConfigurationListenerProperty(rListener, "EnglishFunctionName")
+ , m_pFunctionWin(pFunctionWin)
+ {
+ }
+};
+
+class ScFunctionWin : public PanelLayout
+{
+
+private:
+ std::unique_ptr<weld::ComboBox> xCatBox;
+ std::unique_ptr<weld::TreeView> xFuncList;
+ std::unique_ptr<weld::Button> xInsertButton;
+ std::unique_ptr<weld::Label> xFiFuncDesc;
+
+ rtl::Reference<comphelper::ConfigurationListener> xConfigListener;
+ std::unique_ptr<EnglishFunctionNameChange> xConfigChange;
+ const ScFuncDesc* pFuncDesc;
+ sal_uInt16 nArgs;
+
+ ::std::vector< const formula::IFunctionDescription*> aLRUList;
+
+ void UpdateLRUList();
+ void DoEnter();
+ void SetDescription();
+
+ DECL_LINK( SetRowActivatedHdl, weld::TreeView&, bool );
+ DECL_LINK( SetSelectionClickHdl, weld::Button&, void );
+ DECL_LINK( SelComboHdl, weld::ComboBox&, void );
+ DECL_LINK( SelTreeHdl, weld::TreeView&, void );
+
+public:
+ ScFunctionWin(weld::Widget* pParent);
+
+ virtual ~ScFunctionWin() override;
+
+ void InitLRUList();
+ void UpdateFunctionList();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/editable.hxx b/sc/source/ui/inc/editable.hxx
new file mode 100644
index 000000000..1c229a1b1
--- /dev/null
+++ b/sc/source/ui/inc/editable.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 <address.hxx>
+#include <unotools/resmgr.hxx>
+
+class ScDocument;
+class ScViewFunc;
+class ScMarkData;
+
+namespace sc {
+
+enum class ColRowEditAction;
+
+}
+
+class ScEditableTester
+{
+ bool mbIsEditable;
+ bool mbOnlyMatrix;
+
+public:
+ ScEditableTester();
+
+ // calls TestBlock
+ /** @param bNoMatrixAtAll
+ TRUE if there must not be any matrix, not even entirely
+ contained; for example in sorting. */
+ ScEditableTester( const ScDocument& rDoc, SCTAB nTab,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ bool bNoMatrixAtAll = false );
+
+ // calls TestSelectedBlock
+ ScEditableTester( const ScDocument& rDoc,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark );
+
+ // calls TestRange
+ ScEditableTester( const ScDocument& rDoc, const ScRange& rRange );
+
+ // calls TestSelection
+ ScEditableTester( const ScDocument& rDoc, const ScMarkData& rMark );
+
+ // calls TestView
+ ScEditableTester( ScViewFunc* pView );
+
+ ScEditableTester(
+ const ScDocument& rDoc, sc::ColRowEditAction eAction, SCCOLROW nStart, SCCOLROW nEnd,
+ const ScMarkData& rMark );
+
+ // Several calls to the Test... methods check if *all* of the ranges
+ // are editable. For several independent checks, Reset() has to be used.
+ void TestBlock( const ScDocument& rDoc, SCTAB nTab,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ bool bNoMatrixAtAll = false );
+ void TestSelectedBlock( const ScDocument& rDoc,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ const ScMarkData& rMark );
+ void TestRange( const ScDocument& rDoc, const ScRange& rRange );
+ void TestSelection( const ScDocument& rDoc, const ScMarkData& rMark );
+
+ void TestBlockForAction(
+ const ScDocument& rDoc, sc::ColRowEditAction eAction, SCCOLROW nStart, SCCOLROW nEnd,
+ const ScMarkData& rMark );
+
+ bool IsEditable() const { return mbIsEditable; }
+ bool IsFormatEditable() const { return mbIsEditable || mbOnlyMatrix; }
+ TranslateId GetMessageId() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/editfield.hxx b/sc/source/ui/inc/editfield.hxx
new file mode 100644
index 000000000..103919d1b
--- /dev/null
+++ b/sc/source/ui/inc/editfield.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 <vcl/weld.hxx>
+
+/** An edit control that contains a double precision floating-point value. */
+class ScDoubleField
+{
+private:
+ std::unique_ptr<weld::Entry> m_xEntry;
+
+public:
+ explicit ScDoubleField(std::unique_ptr<weld::Entry> xEntry);
+
+ bool GetValue(double& rfValue) const;
+ void SetValue(double fValue, sal_Int32 nDecPlaces = 12);
+
+ weld::Entry& get_widget() { return *m_xEntry; }
+
+ void grab_focus() { m_xEntry->grab_focus(); }
+ bool get_sensitive() const { return m_xEntry->get_sensitive(); }
+ void set_sensitive(bool bSensitive) { m_xEntry->set_sensitive(bSensitive); }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/editsh.hxx b/sc/source/ui/inc/editsh.hxx
new file mode 100644
index 000000000..5fb8a3c9a
--- /dev/null
+++ b/sc/source/ui/inc/editsh.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 <sfx2/shell.hxx>
+#include <tools/link.hxx>
+#include <rtl/ref.hxx>
+
+#include <shellids.hxx>
+
+class SfxModule;
+class EditView;
+class ScViewData;
+class ScInputHandler;
+class SvxURLField;
+class TransferableDataHelper;
+class TransferableClipboardListener;
+
+class ScEditShell final : public SfxShell
+{
+private:
+ EditView* pEditView;
+ ScViewData& rViewData;
+ rtl::Reference<TransferableClipboardListener> mxClipEvtLstnr;
+ bool bPastePossible;
+ bool bIsInsertMode;
+
+ // tdf#140361 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;
+
+ const SvxURLField* GetURLField();
+ ScInputHandler* GetMyInputHdl();
+
+ DECL_LINK( ClipboardChanged, TransferableDataHelper*, void );
+
+public:
+ SFX_DECL_INTERFACE(SCID_EDIT_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScEditShell(EditView* pView, ScViewData& rData);
+ virtual ~ScEditShell() override;
+
+ void SetEditView(EditView* pView);
+ EditView* GetEditView() {return pEditView;}
+
+ void Execute(SfxRequest& rReq);
+ void ExecuteTrans(const SfxRequest& rReq);
+ void GetState(SfxItemSet &rSet);
+ void GetClipState(SfxItemSet& rSet);
+
+ void ExecuteAttr(SfxRequest& rReq);
+ void GetAttrState(SfxItemSet &rSet);
+
+ void ExecuteUndo(const SfxRequest& rReq);
+ void GetUndoState(SfxItemSet &rSet);
+
+ OUString GetSelectionText( bool bWholeWord );
+
+ /// 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();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/filldlg.hxx b/sc/source/ui/inc/filldlg.hxx
new file mode 100644
index 000000000..c52452841
--- /dev/null
+++ b/sc/source/ui/inc/filldlg.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 <vcl/weld.hxx>
+#include <global.hxx>
+
+class ScDocument;
+
+class ScFillSeriesDlg : public weld::GenericDialogController
+{
+public:
+ ScFillSeriesDlg( weld::Window* pParent,
+ ScDocument& rDocument,
+ FillDir eFillDir,
+ FillCmd eFillCmd,
+ FillDateCmd eFillDateCmd,
+ const OUString& aStartStr,
+ double fStep,
+ double fMax,
+ SCSIZE nSelectHeight,
+ SCSIZE nSelectWidth,
+ sal_uInt16 nPossDir );
+ virtual ~ScFillSeriesDlg() override;
+
+ FillDir GetFillDir() const { return theFillDir; }
+ FillCmd GetFillCmd() const { return theFillCmd; }
+ FillDateCmd GetFillDateCmd() const { return theFillDateCmd; }
+ double GetStart() const { return fStartVal; }
+ double GetStep() const { return fIncrement; }
+ double GetMax() const { return fEndVal; }
+
+ OUString GetStartStr() const { return m_xEdStartVal->get_text(); }
+
+ void SetEdStartValEnabled(bool bFlag);
+
+private:
+ const OUString aStartStrVal;
+ const OUString aErrMsgInvalidVal;
+
+ ScDocument& rDoc;
+ FillDir theFillDir;
+ FillCmd theFillCmd;
+ FillDateCmd theFillDateCmd;
+ double fStartVal;
+ double fIncrement;
+ double fEndVal;
+ const SCSIZE m_nSelectHeight;
+ const SCSIZE m_nSelectWidth;
+
+ std::unique_ptr<weld::Label> m_xFtStartVal;
+ std::unique_ptr<weld::Entry> m_xEdStartVal;
+
+ std::unique_ptr<weld::Label> m_xFtEndVal;
+ std::unique_ptr<weld::Entry> m_xEdEndVal;
+
+ std::unique_ptr<weld::Label> m_xFtIncrement;
+ std::unique_ptr<weld::Entry> m_xEdIncrement;
+ std::unique_ptr<weld::RadioButton> m_xBtnDown;
+ std::unique_ptr<weld::RadioButton> m_xBtnRight;
+ std::unique_ptr<weld::RadioButton> m_xBtnUp;
+ std::unique_ptr<weld::RadioButton> m_xBtnLeft;
+
+ std::unique_ptr<weld::RadioButton> m_xBtnArithmetic;
+ std::unique_ptr<weld::RadioButton> m_xBtnGeometric;
+ std::unique_ptr<weld::RadioButton> m_xBtnDate;
+ std::unique_ptr<weld::RadioButton> m_xBtnAutoFill;
+
+ std::unique_ptr<weld::Label> m_xFtTimeUnit;
+ std::unique_ptr<weld::RadioButton> m_xBtnDay;
+ std::unique_ptr<weld::RadioButton> m_xBtnDayOfWeek;
+ std::unique_ptr<weld::RadioButton> m_xBtnMonth;
+ std::unique_ptr<weld::RadioButton> m_xBtnYear;
+
+ std::unique_ptr<weld::Button> m_xBtnOk;
+
+ void Init( sal_uInt16 nPossDir );
+ weld::Entry* CheckValues();
+
+ DECL_LINK(OKHdl, weld::Button&, void);
+ DECL_LINK(DisableHdl, weld::Toggleable&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/filtdlg.hxx b/sc/source/ui/inc/filtdlg.hxx
new file mode 100644
index 000000000..cac9bc71e
--- /dev/null
+++ b/sc/source/ui/inc/filtdlg.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <address.hxx>
+#include "anyrefdg.hxx"
+#include <queryparam.hxx>
+#include <filterentries.hxx>
+#include <queryentry.hxx>
+
+#include <memory>
+#include <deque>
+#include <vector>
+#include <map>
+
+class ScFilterOptionsMgr;
+class ScViewData;
+class ScDocument;
+class ScQueryItem;
+
+class ScFilterDlg : public ScAnyRefDlgController
+{
+ struct EntryList
+ {
+ ScFilterEntries maFilterEntries;
+ size_t mnHeaderPos;
+
+ EntryList(const EntryList&) = delete;
+ const EntryList& operator=(const EntryList&) = delete;
+
+ EntryList();
+ };
+ typedef std::map<SCCOL, std::unique_ptr<EntryList>> EntryListsMap;
+public:
+ ScFilterDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ const SfxItemSet& rArgSet);
+ virtual ~ScFilterDlg() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+
+ virtual bool IsRefInputMode() const override;
+ virtual void SetActive() override;
+
+ virtual void Close() override;
+ void SliderMoved();
+ size_t GetSliderPos() const;
+ void RefreshEditRow( size_t nOffset );
+
+private:
+ const OUString aStrUndefined;
+ const OUString aStrNone;
+
+ const OUString aStrEmpty;
+ const OUString aStrNotEmpty;
+ const OUString aStrColumn;
+ const OUString aStrTextColor;
+ const OUString aStrBackgroundColor;
+
+ std::unique_ptr<ScFilterOptionsMgr> pOptionsMgr;
+
+ const sal_uInt16 nWhichQuery;
+ ScQueryParam theQueryData;
+ std::unique_ptr<ScQueryItem> pOutItem;
+ ScViewData* pViewData;
+ ScDocument* pDoc;
+ SCTAB nSrcTab;
+
+ std::vector<weld::ComboBox*> maValueEdArr;
+ std::vector<weld::ComboBox*> maFieldLbArr;
+ std::vector<weld::ComboBox*> maCondLbArr;
+ std::vector<weld::ComboBox*> maConnLbArr;
+ std::vector<weld::ComboBox*> maColorLbArr;
+ std::vector<weld::Button*> maRemoveBtnArr;
+
+ std::deque<bool> maHasDates;
+ std::deque<bool> maRefreshExceptQuery;
+ bool bRefInputMode;
+
+ EntryListsMap m_EntryLists;
+
+ // Hack: RefInput control
+ std::unique_ptr<Timer> pTimer;
+
+ std::unique_ptr<weld::ComboBox> m_xLbConnect1;
+ std::unique_ptr<weld::ComboBox> m_xLbField1;
+ std::unique_ptr<weld::ComboBox> m_xLbCond1;
+ std::unique_ptr<weld::ComboBox> m_xEdVal1;
+ std::unique_ptr<weld::ComboBox> m_xLbColor1;
+ std::unique_ptr<weld::Button> m_xBtnRemove1;
+
+ std::unique_ptr<weld::ComboBox> m_xLbConnect2;
+ std::unique_ptr<weld::ComboBox> m_xLbField2;
+ std::unique_ptr<weld::ComboBox> m_xLbCond2;
+ std::unique_ptr<weld::ComboBox> m_xEdVal2;
+ std::unique_ptr<weld::ComboBox> m_xLbColor2;
+ std::unique_ptr<weld::Button> m_xBtnRemove2;
+
+ std::unique_ptr<weld::ComboBox> m_xLbConnect3;
+ std::unique_ptr<weld::ComboBox> m_xLbField3;
+ std::unique_ptr<weld::ComboBox> m_xLbCond3;
+ std::unique_ptr<weld::ComboBox> m_xEdVal3;
+ std::unique_ptr<weld::ComboBox> m_xLbColor3;
+ std::unique_ptr<weld::Button> m_xBtnRemove3;
+
+ std::unique_ptr<weld::ComboBox> m_xLbConnect4;
+ std::unique_ptr<weld::ComboBox> m_xLbField4;
+ std::unique_ptr<weld::ComboBox> m_xLbCond4;
+ std::unique_ptr<weld::ComboBox> m_xEdVal4;
+ std::unique_ptr<weld::ComboBox> m_xLbColor4;
+ std::unique_ptr<weld::Button> m_xBtnRemove4;
+
+ std::unique_ptr<weld::Widget> m_xContents;
+ std::unique_ptr<weld::ScrolledWindow> m_xScrollBar;
+ std::unique_ptr<weld::Expander> m_xExpander;
+
+ std::unique_ptr<weld::Button> m_xBtnClear;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnCase;
+ std::unique_ptr<weld::CheckButton> m_xBtnRegExp;
+ std::unique_ptr<weld::CheckButton> m_xBtnHeader;
+ std::unique_ptr<weld::CheckButton> m_xBtnUnique;
+ std::unique_ptr<weld::CheckButton> m_xBtnCopyResult;
+ std::unique_ptr<weld::ComboBox> m_xLbCopyArea;
+ std::unique_ptr<formula::RefEdit> m_xEdCopyArea;
+ std::unique_ptr<formula::RefButton> m_xRbCopyArea;
+ std::unique_ptr<weld::CheckButton> m_xBtnDestPers;
+ std::unique_ptr<weld::Label> m_xFtDbAreaLabel;
+ std::unique_ptr<weld::Label> m_xFtDbArea;
+
+private:
+ void Init ( const SfxItemSet& rArgSet );
+ void FillFieldLists ();
+ void UpdateValueList ( size_t nList );
+ void UpdateHdrInValueList( size_t nList );
+ void ClearValueList ( size_t nList );
+ void UpdateColorList ( size_t nList );
+ size_t GetFieldSelPos ( SCCOL nField );
+ ScQueryItem* GetOutputItem ();
+ void SetValString ( const OUString& rQueryStr,
+ const ScQueryEntry::Item& rItem,
+ OUString& rValStr );
+
+ // Handler:
+ DECL_LINK( LbSelectHdl, weld::ComboBox&, void );
+ DECL_LINK( ValModifyHdl, weld::ComboBox&, void );
+ DECL_LINK( CheckBoxHdl, weld::Toggleable&, void );
+ DECL_LINK( BtnClearHdl, weld::Button&, void );
+ DECL_LINK( BtnRemoveHdl, weld::Button&, void );
+ DECL_LINK( EndDlgHdl, weld::Button&, void );
+ DECL_LINK( ScrollHdl, weld::ScrolledWindow&, void );
+ DECL_LINK( MoreExpandedHdl, weld::Expander&, void );
+
+ // Hack: RefInput control
+ DECL_LINK( TimeOutHdl, Timer*, void );
+};
+
+class ScSpecialFilterDlg : public ScAnyRefDlgController
+{
+public:
+ ScSpecialFilterDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ const SfxItemSet& rArgSet);
+ virtual ~ScSpecialFilterDlg() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+
+ virtual bool IsRefInputMode() const override;
+ virtual void SetActive() override;
+
+ virtual void Close() override;
+
+private:
+ const OUString aStrUndefined;
+
+ std::unique_ptr<ScFilterOptionsMgr> pOptionsMgr;
+
+ const sal_uInt16 nWhichQuery;
+ const ScQueryParam theQueryData;
+ std::unique_ptr<ScQueryItem> pOutItem;
+ ScViewData* pViewData;
+ ScDocument* pDoc;
+
+ bool bRefInputMode;
+
+ formula::RefEdit* m_pRefInputEdit;
+
+ std::unique_ptr<weld::ComboBox> m_xLbFilterArea;
+ std::unique_ptr<formula::RefEdit> m_xEdFilterArea;
+ std::unique_ptr<formula::RefButton> m_xRbFilterArea;
+
+ std::unique_ptr<weld::Expander> m_xExpander;
+ std::unique_ptr<weld::CheckButton> m_xBtnCase;
+ std::unique_ptr<weld::CheckButton> m_xBtnRegExp;
+ std::unique_ptr<weld::CheckButton> m_xBtnHeader;
+ std::unique_ptr<weld::CheckButton> m_xBtnUnique;
+ std::unique_ptr<weld::CheckButton> m_xBtnCopyResult;
+ std::unique_ptr<weld::ComboBox> m_xLbCopyArea;
+ std::unique_ptr<formula::RefEdit> m_xEdCopyArea;
+ std::unique_ptr<formula::RefButton> m_xRbCopyArea;
+ std::unique_ptr<weld::CheckButton> m_xBtnDestPers;
+ std::unique_ptr<weld::Label> m_xFtDbAreaLabel;
+ std::unique_ptr<weld::Label> m_xFtDbArea;
+
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+ std::unique_ptr<weld::Frame> m_xFilterFrame;
+ std::unique_ptr<weld::Label> m_xFilterLabel;
+
+private:
+ void Init( const SfxItemSet& rArgSet );
+ ScQueryItem* GetOutputItem( const ScQueryParam& rParam,
+ const ScRange& rSource );
+
+ // Handler
+ DECL_LINK( FilterAreaSelHdl, weld::ComboBox&, void );
+ DECL_LINK( FilterAreaModHdl, formula::RefEdit&, void );
+ DECL_LINK( EndDlgHdl, weld::Button&, void );
+
+ // RefInput control
+ DECL_LINK( RefInputEditHdl, formula::RefEdit&, void );
+ DECL_LINK( RefInputButtonHdl, formula::RefButton&, void );
+ void RefInputHdl();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/foptmgr.hxx b/sc/source/ui/inc/foptmgr.hxx
new file mode 100644
index 000000000..661feac98
--- /dev/null
+++ b/sc/source/ui/inc/foptmgr.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 <vcl/weld.hxx>
+
+namespace formula
+{
+ class RefButton;
+ class RefButton;
+ class RefEdit;
+}
+struct ScQueryParam;
+class ScDocument;
+class ScViewData;
+
+class ScFilterOptionsMgr
+{
+public:
+ ScFilterOptionsMgr(ScViewData* ptrViewData,
+ const ScQueryParam& refQueryData,
+ weld::CheckButton* refBtnCase,
+ weld::CheckButton* refBtnRegExp,
+ weld::CheckButton* refBtnHeader,
+ weld::CheckButton* refBtnUnique,
+ weld::CheckButton* refBtnCopyResult,
+ weld::CheckButton* refBtnDestPers,
+ weld::ComboBox* refLbCopyArea,
+ formula::RefEdit* refEdCopyArea,
+ formula::RefButton* refRbCopyArea,
+ weld::Label* refFtDbAreaLabel,
+ weld::Label* refFtDbArea,
+ const OUString& refStrUndefined );
+ bool VerifyPosStr ( const OUString& rPosStr ) const;
+
+private:
+ ScViewData* pViewData;
+ ScDocument* pDoc;
+
+ weld::CheckButton* pBtnCase;
+ weld::CheckButton* pBtnRegExp;
+ weld::CheckButton* pBtnHeader;
+ weld::CheckButton* pBtnUnique;
+ weld::CheckButton* pBtnCopyResult;
+ weld::CheckButton* pBtnDestPers;
+ weld::ComboBox* pLbCopyArea;
+ formula::RefEdit* pEdCopyArea;
+ formula::RefButton* pRbCopyArea;
+ weld::Label* pFtDbAreaLabel;
+ weld::Label* pFtDbArea;
+
+ const OUString& rStrUndefined;
+
+ const ScQueryParam& rQueryData;
+
+private:
+ void Init();
+
+ // Handler:
+ DECL_LINK( EdAreaModifyHdl, formula::RefEdit&, void );
+ DECL_LINK( LbAreaSelHdl, weld::ComboBox&, void );
+ DECL_LINK( BtnCopyResultHdl, weld::Toggleable&, void );
+};
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/formatsh.hxx b/sc/source/ui/inc/formatsh.hxx
new file mode 100644
index 000000000..193c98e04
--- /dev/null
+++ b/sc/source/ui/inc/formatsh.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 <sfx2/shell.hxx>
+#include <shellids.hxx>
+
+class SfxModule;
+class ScViewData;
+enum class SvNumFormatType : sal_Int16;
+
+class ScFormatShell: public SfxShell
+{
+ ScViewData& rViewData;
+
+protected:
+ ScViewData& GetViewData() { return rViewData; }
+ const ScViewData& GetViewData() const { return rViewData; }
+
+public:
+ SFX_DECL_INTERFACE(SCID_FORMAT_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScFormatShell(ScViewData& rData);
+ virtual ~ScFormatShell() override;
+
+ void ExecuteNumFormat( SfxRequest& rReq );
+ void GetNumFormatState( SfxItemSet& rSet );
+
+ void ExecuteAttr( SfxRequest& rReq );
+ void GetAttrState( SfxItemSet& rSet );
+
+ void ExecuteAlignment( SfxRequest& rReq );
+
+ void ExecuteTextAttr( SfxRequest& rReq );
+ void GetTextAttrState( SfxItemSet& rSet );
+
+ void GetAlignState( SfxItemSet& rSet );
+ void GetBorderState( SfxItemSet& rSet );
+
+ void ExecuteStyle( SfxRequest& rReq );
+ void GetStyleState( SfxItemSet& rSet );
+
+ void ExecuteTextDirection( const SfxRequest& rReq );
+ void GetTextDirectionState( SfxItemSet& rSet );
+
+ void ExecFormatPaintbrush( const SfxRequest& rReq );
+ void StateFormatPaintbrush( SfxItemSet& rSet );
+
+private:
+ SvNumFormatType GetCurrentNumberFormatType();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/formdata.hxx b/sc/source/ui/inc/formdata.hxx
new file mode 100644
index 000000000..a2cecbffa
--- /dev/null
+++ b/sc/source/ui/inc/formdata.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 <formula/formdata.hxx>
+class ScInputHandler;
+class ScDocShell;
+
+class ScFormEditData : public formula::FormEditData
+{
+public:
+ ScFormEditData();
+ virtual ~ScFormEditData() override;
+
+ ScInputHandler* GetInputHandler() { return pInputHandler;}
+ ScDocShell* GetDocShell() { return pScDocShell;}
+
+ void SetInputHandler(ScInputHandler* pHdl) { pInputHandler=pHdl;}
+ void SetDocShell(ScDocShell* pSds) { pScDocShell=pSds;}
+
+ virtual void SaveValues() override;
+
+private:
+ ScFormEditData(ScFormEditData const &) = delete;
+ void operator =(ScFormEditData const &) = delete;
+
+ ScInputHandler* pInputHandler;
+ ScDocShell* pScDocShell;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/formula.hxx b/sc/source/ui/inc/formula.hxx
new file mode 100644
index 000000000..02ee866c1
--- /dev/null
+++ b/sc/source/ui/inc/formula.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 <memory>
+#include "anyrefdg.hxx"
+
+#include <scmod.hxx>
+#include <formula/formula.hxx>
+#include "IAnyRefDialog.hxx"
+
+class ScViewData;
+class ScDocument;
+class ScFuncDesc;
+class ScInputHandler;
+class ScDocShell;
+
+class ScFormulaDlg final : public formula::FormulaDlg,
+ public IAnyRefDialog
+{
+ ScFormulaReferenceHelper m_aHelper;
+ css::uno::Reference< css::sheet::XFormulaParser> m_xParser;
+ css::uno::Reference< css::sheet::XFormulaOpCodeMapper> m_xOpCodeMapper;
+
+ ScDocument* m_pDoc;
+ ScAddress m_CursorPos;
+ ScTabViewShell* m_pViewShell;
+ mutable std::shared_ptr<ScCompiler> m_xCompiler;
+
+public:
+ ScFormulaDlg( SfxBindings* pB, SfxChildWindow* pCW,
+ weld::Window* pParent, const ScViewData& rViewData, const formula::IFunctionManager* _pFunctionMgr);
+ virtual ~ScFormulaDlg() COVERITY_NOEXCEPT_FALSE override;
+
+ // IFormulaEditorHelper
+ virtual void notifyChange() override;
+ virtual void fill() override;
+ virtual bool calculateValue(const OUString& _sExpression, OUString& _rResult, bool bMatrixFormula) override;
+ virtual std::shared_ptr<formula::FormulaCompiler> getCompiler() const override;
+ virtual std::unique_ptr<formula::FormulaCompiler> createCompiler( formula::FormulaTokenArray& rArray ) const override;
+ virtual void doClose(bool _bOk) override;
+ virtual void insertEntryToLRUList(const formula::IFunctionDescription* pDesc) override;
+ virtual void showReference(const OUString& _sFormula) override;
+ virtual void dispatch(bool _bOK, bool _bMatrixChecked) override;
+ virtual void setDispatcherLock( bool bLock ) override;
+ virtual void deleteFormData() override;
+ virtual void clear() override;
+ virtual void switchBack() override;
+ virtual formula::FormEditData* getFormEditData() const override;
+ virtual void setCurrentFormula(const OUString& _sReplacement) override;
+ virtual void setSelection(sal_Int32 _nStart, sal_Int32 _nEnd) override;
+ virtual void getSelection(sal_Int32& _nStart, sal_Int32& _nEnd) const override;
+ virtual OUString getCurrentFormula() const override;
+
+ virtual formula::IFunctionManager* getFunctionManager() override;
+ virtual ::std::unique_ptr<formula::FormulaTokenArray> convertToTokenArray(const css::uno::Sequence< css::sheet::FormulaToken >& _aTokenList) override;
+ virtual css::uno::Reference< css::sheet::XFormulaParser> getFormulaParser() const override;
+ virtual css::uno::Reference< css::sheet::XFormulaOpCodeMapper> getFormulaOpCodeMapper() const override;
+ virtual css::table::CellAddress getReferencePosition() const override;
+
+ virtual void Close() override;
+
+ // sc::IAnyRefDialog
+ virtual void ShowReference(const OUString& _sRef) override;
+ virtual void HideReference( bool bDoneRefMode = true ) override;
+ virtual void SetReference( const ScRange& rRef, ScDocument& rD ) override;
+
+ virtual void ReleaseFocus( formula::RefEdit* pEdit ) override;
+ virtual void ToggleCollapsed( formula::RefEdit* pEdit, formula::RefButton* pButton ) override;
+ virtual void RefInputDone( bool bForced = false ) override;
+ virtual bool IsTableLocked() const override;
+ virtual bool IsRefInputMode() const override;
+
+ virtual bool IsDocAllowed( SfxObjectShell* pDocSh ) const override;
+ virtual void AddRefEntry() override;
+ virtual void SetActive() override;
+ virtual void ViewShellChanged() override;
+
+private:
+ virtual void RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton = nullptr ) override;
+ static void SaveLRUEntry(const ScFuncDesc* pFuncDesc);
+
+ static bool IsInputHdl(const ScInputHandler* pHdl);
+ static ScInputHandler* GetNextInputHandler(const ScDocShell* pDocShell, ScTabViewShell** ppViewSh);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/fuconarc.hxx b/sc/source/ui/inc/fuconarc.hxx
new file mode 100644
index 000000000..d1fb31aad
--- /dev/null
+++ b/sc/source/ui/inc/fuconarc.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 "fuconstr.hxx"
+
+/** Draw rectangle */
+class FuConstArc : public FuConstruct
+{
+public:
+ FuConstArc(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, const SfxRequest& rReq);
+
+ virtual ~FuConstArc() 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;
+
+ // Create default drawing objects via keyboard
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const tools::Rectangle& rRectangle) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/fuconcustomshape.hxx b/sc/source/ui/inc/fuconcustomshape.hxx
new file mode 100644
index 000000000..89f22d17a
--- /dev/null
+++ b/sc/source/ui/inc/fuconcustomshape.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 "fuconstr.hxx"
+
+class SAL_DLLPUBLIC_RTTI FuConstCustomShape : public FuConstruct
+{
+ OUString aCustomShape;
+
+ void SetAttributes( SdrObject* pObj );
+
+public:
+ FuConstCustomShape(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, const SfxRequest& rReq);
+
+ virtual ~FuConstCustomShape() 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;
+
+ // Create default drawing objects via keyboard
+ virtual SdrObjectUniquePtr CreateDefaultObject( const sal_uInt16 nID, const tools::Rectangle& rRectangle ) override;
+
+ // #i33136#
+ virtual bool doConstructOrthogonal() const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/fuconpol.hxx b/sc/source/ui/inc/fuconpol.hxx
new file mode 100644
index 000000000..e09225136
--- /dev/null
+++ b/sc/source/ui/inc/fuconpol.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 "fuconstr.hxx"
+
+/** Base class for all functions */
+class FuConstPolygon : public FuConstruct
+{
+public:
+ FuConstPolygon(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, const SfxRequest& rReq);
+
+ virtual ~FuConstPolygon() override;
+ // 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;
+
+ // Create default drawing objects via keyboard
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const tools::Rectangle& rRectangle) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/fuconrec.hxx b/sc/source/ui/inc/fuconrec.hxx
new file mode 100644
index 000000000..1f3fbb8ee
--- /dev/null
+++ b/sc/source/ui/inc/fuconrec.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 "fuconstr.hxx"
+
+/** Draw rectangle */
+class FuConstRectangle : public FuConstruct
+{
+public:
+ FuConstRectangle(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, const SfxRequest& rReq);
+
+ virtual ~FuConstRectangle() 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;
+ static void SetLineEnds(SfxItemSet& rAttr, const SdrObject& rObj, sal_uInt16 nSlotId);
+
+ // Create default drawing objects via keyboard
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const tools::Rectangle& rRectangle) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/fuconstr.hxx b/sc/source/ui/inc/fuconstr.hxx
new file mode 100644
index 000000000..a9076ee3e
--- /dev/null
+++ b/sc/source/ui/inc/fuconstr.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 "fudraw.hxx"
+
+#include <scdllapi.h> // SC_DLLPUBLIC is needed for unittest
+
+/** Draw rectangle */
+class SAL_DLLPUBLIC_RTTI FuConstruct : public FuDraw
+{
+public:
+ FuConstruct(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, const SfxRequest& rReq);
+
+ virtual ~FuConstruct() override;
+ // Mouse- & Key-Events
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+ SC_DLLPUBLIC virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ bool SimpleMouseButtonUp(const MouseEvent& rMEvt);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/fuconuno.hxx b/sc/source/ui/inc/fuconuno.hxx
new file mode 100644
index 000000000..1c58d5db3
--- /dev/null
+++ b/sc/source/ui/inc/fuconuno.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 "fuconstr.hxx"
+
+#include <scdllapi.h> // SC_DLLPUBLIC is needed for unittest
+
+enum class SdrInventor : sal_uInt32;
+
+/** Draw Control */
+class SAL_DLLPUBLIC_RTTI FuConstUnoControl final : public FuConstruct
+{
+ SdrInventor nInventor;
+ SdrObjKind nIdentifier;
+
+public:
+ FuConstUnoControl(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, const SfxRequest& rReq);
+
+ virtual ~FuConstUnoControl() override;
+ // Mouse- & Key-Events
+ SC_DLLPUBLIC virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ SC_DLLPUBLIC virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ SC_DLLPUBLIC virtual void Activate() override;
+ SC_DLLPUBLIC virtual void Deactivate() override;
+
+ // Create default drawing objects via keyboard
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const tools::Rectangle& rRectangle) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/fudraw.hxx b/sc/source/ui/inc/fudraw.hxx
new file mode 100644
index 000000000..0fdd6f9e8
--- /dev/null
+++ b/sc/source/ui/inc/fudraw.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"
+
+enum class PointerStyle;
+
+/** Base class for all Drawmodule specific functions */
+class FuDraw : public FuPoor
+{
+protected:
+ PointerStyle aNewPointer;
+ PointerStyle aOldPointer;
+
+public:
+ FuDraw(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView, SdrModel* pDoc,
+ const SfxRequest& rReq);
+ virtual ~FuDraw() override;
+
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+
+ virtual void ForcePointer(const MouseEvent* pMEvt);
+
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ bool IsEditingANote() const;
+ bool IsSizingOrMovingNote(const MouseEvent& rMEvt) const;
+
+private:
+ void DoModifiers(const MouseEvent& rMEvt);
+ void ResetModifiers();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/fuinsert.hxx b/sc/source/ui/inc/fuinsert.hxx
new file mode 100644
index 000000000..3018d66fe
--- /dev/null
+++ b/sc/source/ui/inc/fuinsert.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 "fupoor.hxx"
+#include <scdllapi.h>
+#include <com/sun/star/ui/dialogs/DialogClosedEvent.hpp>
+
+class FuInsertGraphic : public FuPoor
+{
+public:
+ FuInsertGraphic(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, SfxRequest& rReq);
+ virtual ~FuInsertGraphic() override;
+};
+
+class FuInsertOLE : public FuPoor
+{
+public:
+ FuInsertOLE(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, SfxRequest& rReq);
+};
+
+class FuInsertChart : public FuPoor
+{
+ public:
+ FuInsertChart( ScTabViewShell& pViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, SfxRequest& rReq,
+ const Link<css::ui::dialogs::DialogClosedEvent*, void>& rLink);
+};
+
+class FuInsertMedia : public FuPoor
+{
+public:
+ FuInsertMedia(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, const SfxRequest& rReq);
+ virtual ~FuInsertMedia() override;
+};
+
+void SC_DLLPUBLIC ScLimitSizeOnDrawPage( Size& rSize, Point& rPos, const Size& rPage );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/fupoor.hxx b/sc/source/ui/inc/fupoor.hxx
new file mode 100644
index 000000000..978a2ca09
--- /dev/null
+++ b/sc/source/ui/inc/fupoor.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 <vcl/timer.hxx>
+#include <sfx2/request.hxx>
+#include <svx/svdobj.hxx>
+#include <vcl/window.hxx>
+
+class ScDrawView;
+class ScTabViewShell;
+class SdrModel;
+class CommandEvent;
+class KeyEvent;
+class MouseEvent;
+
+// Return values for command
+#define SC_CMD_NONE 0
+#define SC_CMD_USED 1
+
+/** Base class for all functions */
+class FuPoor
+{
+protected:
+ ScDrawView* pView;
+ ScTabViewShell& rViewShell;
+ VclPtr<vcl::Window> pWindow;
+ SdrModel* pDrDoc;
+
+ SfxRequest aSfxRequest;
+
+ Timer aScrollTimer; // for Autoscrolling
+ DECL_LINK( ScrollHdl, Timer *, void );
+ void ForceScroll(const Point& aPixPos);
+
+ Timer aDragTimer; // for Drag&Drop
+ DECL_LINK( DragTimerHdl, Timer *, void );
+ DECL_LINK( DragHdl, void *, void );
+ bool bIsInDragMode;
+ Point aMDPos; // Position of MouseButtonDown
+
+ // member to hold state of the mouse buttons for creation
+ // of own MouseEvents (like in ScrollHdl)
+private:
+ sal_uInt16 mnCode;
+
+public:
+ FuPoor(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, const SfxRequest& rReq);
+ virtual ~FuPoor();
+
+ // see member
+ void SetMouseButtonCode(sal_uInt16 nNew) { if(nNew != mnCode) mnCode = nNew; }
+ sal_uInt16 GetMouseButtonCode() const { return mnCode; }
+
+ // Mouse- & Key-Events; return value=TRUE: Event was processed
+ virtual bool KeyInput(const KeyEvent& rKEvt);
+ virtual bool MouseMove(const MouseEvent&) { return false; }
+
+ // moved from inline to *.cxx
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt); // { return FALSE; }
+
+ // moved from inline to *.cxx
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt); // { return FALSE; }
+
+ sal_uInt8 Command(const CommandEvent& rCEvt);
+
+ virtual void Activate();
+ virtual void Deactivate();
+
+ void SetWindow(vcl::Window* pWin) { pWindow = pWin; }
+
+ sal_uInt16 GetSlotID() const { return aSfxRequest.GetSlot(); }
+
+ bool IsDetectiveHit( const Point& rLogicPos );
+
+ void StopDragTimer();
+
+ // Create default drawing objects via keyboard
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const tools::Rectangle& rRectangle);
+
+protected:
+ static void ImpForceQuadratic(tools::Rectangle& rRect);
+
+public:
+ // #i33136#
+ virtual bool doConstructOrthogonal() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/fusel.hxx b/sc/source/ui/inc/fusel.hxx
new file mode 100644
index 000000000..2326e5ad7
--- /dev/null
+++ b/sc/source/ui/inc/fusel.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 "fudraw.hxx"
+
+class SdrPageView;
+
+/** Base class for all functions */
+class FuSelection : public FuDraw
+{
+public:
+ FuSelection(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, const SfxRequest& rReq );
+
+ virtual ~FuSelection() override;
+ // Mouse- & Key-Events
+ virtual bool MouseMove(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonUp(const MouseEvent& rMEvt) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+
+ void ActivateNoteHandles(SdrObject* pObj);
+
+private:
+ bool TestDetective( const SdrPageView* pPV, const Point& rPos ); // -> fusel2
+
+ bool IsNoteCaptionMarked() const;
+ bool IsNoteCaptionClicked( const Point& rPos ) const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/futext.hxx b/sc/source/ui/inc/futext.hxx
new file mode 100644
index 000000000..c53a5b388
--- /dev/null
+++ b/sc/source/ui/inc/futext.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 "fuconstr.hxx"
+
+class SdrOutliner;
+
+/** Base class for Text functions */
+class FuText : public FuConstruct
+{
+public:
+ FuText(ScTabViewShell& rViewSh, vcl::Window* pWin, ScDrawView* pView,
+ SdrModel* pDoc, const SfxRequest& rReq);
+
+ virtual ~FuText() 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 Activate() override;
+ virtual void Deactivate() override;
+
+ virtual void ForcePointer(const MouseEvent* pMEvt) override;
+
+ void SetInEditMode( SdrObject* pObj = nullptr, const Point* pMousePixel = nullptr,
+ bool bCursorToEnd = false, const KeyEvent* pInitialKey = nullptr );
+ void StopEditMode();
+
+ // Create default drawing objects via keyboard
+ virtual SdrObjectUniquePtr CreateDefaultObject(const sal_uInt16 nID, const tools::Rectangle& rRectangle) override;
+
+private:
+ std::unique_ptr<SdrOutliner> MakeOutliner();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/gototabdlg.hxx b/sc/source/ui/inc/gototabdlg.hxx
new file mode 100644
index 000000000..827f56b17
--- /dev/null
+++ b/sc/source/ui/inc/gototabdlg.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 <vcl/weld.hxx>
+
+class ScGoToTabDlg : public weld::GenericDialogController
+{
+private:
+ std::vector<OUString> maCacheSheetsNames;
+
+ std::unique_ptr<weld::Frame> m_xFrameMask;
+ std::unique_ptr<weld::Entry> m_xEnNameMask;
+ std::unique_ptr<weld::Frame> m_xFrameSheets;
+ std::unique_ptr<weld::TreeView> m_xLb;
+
+ DECL_LINK(DblClkHdl, weld::TreeView&, bool);
+ DECL_LINK(FindNameHdl, weld::Entry&, void);
+
+public:
+ ScGoToTabDlg(weld::Window* pParent);
+ virtual ~ScGoToTabDlg() override;
+
+ /** Sets dialog title, label texts and help IDs. */
+ void SetDescription(const OUString& rTitle, const OUString& rEntryLabel,
+ const OUString& rListLabel, const OString& rDlgHelpId,
+ const OString& rEnHelpId, const OString& rLbHelpId);
+
+ /** Inserts a string into the weld::TreeView. */
+ void Insert(const OUString& rString, bool bSelected);
+
+ OUString GetSelectedEntry() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/graphsh.hxx b/sc/source/ui/inc/graphsh.hxx
new file mode 100644
index 000000000..cae5ac69b
--- /dev/null
+++ b/sc/source/ui/inc/graphsh.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 <vector>
+#include <sfx2/shell.hxx>
+#include <shellids.hxx>
+#include "drawsh.hxx"
+
+class SdrExternalToolEdit;
+class ScViewData;
+class SfxModule;
+
+
+class ScGraphicShell final : public ScDrawShell
+{
+public:
+ SFX_DECL_INTERFACE(SCID_GRAPHIC_SHELL)
+
+private:
+ std::vector<std::unique_ptr<SdrExternalToolEdit>> m_ExternalEdits;
+
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScGraphicShell(ScViewData& rData);
+ virtual ~ScGraphicShell() override;
+
+ void Execute(SfxRequest& rReq);
+ void GetAttrState(SfxItemSet &rSet);
+
+ void ExecuteFilter(const SfxRequest& rReq);
+ void GetFilterState(SfxItemSet &rSet);
+
+ void ExecuteExternalEdit(SfxRequest& rReq);
+ void GetExternalEditState(SfxItemSet &rSet);
+
+ void ExecuteCompressGraphic(SfxRequest& rReq);
+ void GetCompressGraphicState(SfxItemSet &rSet);
+
+ void ExecuteCropGraphic(SfxRequest& rReq);
+ void GetCropGraphicState(SfxItemSet &rSet);
+
+ void ExecuteSaveGraphic(SfxRequest& rReq);
+ void GetSaveGraphicState(SfxItemSet &rSet);
+
+ void ExecuteChangePicture(SfxRequest& rReq);
+ void GetChangePictureState(SfxItemSet &rSet);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/gridmerg.hxx b/sc/source/ui/inc/gridmerg.hxx
new file mode 100644
index 000000000..62e9fdcbe
--- /dev/null
+++ b/sc/source/ui/inc/gridmerg.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 <tools/long.hxx>
+#include <vcl/vclptr.hxx>
+
+class OutputDevice;
+
+class ScGridMerger
+{
+private:
+ VclPtr<OutputDevice> pDev;
+ tools::Long nOneX;
+ tools::Long nOneY;
+ tools::Long nFixStart;
+ tools::Long nFixEnd;
+ tools::Long nVarStart;
+ tools::Long nVarDiff;
+ tools::Long nCount;
+ bool bVertical;
+ bool bOptimize;
+
+ void AddLine( tools::Long nStart, tools::Long nEnd, tools::Long nPos );
+
+public:
+ ScGridMerger( OutputDevice* pOutDev, tools::Long nOnePixelX, tools::Long nOnePixelY );
+ ~ScGridMerger();
+
+ void AddHorLine(bool bWorksInPixels, tools::Long nX1, tools::Long nX2, tools::Long nY, bool bDashed = false);
+ void AddVerLine(bool bWorksInPixels, tools::Long nX, tools::Long nY1, tools::Long nY2, bool bDashed = false);
+ void Flush();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx
new file mode 100644
index 000000000..93d7abd09
--- /dev/null
+++ b/sc/source/ui/inc/gridwin.hxx
@@ -0,0 +1,527 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/transfer.hxx>
+#include "viewutil.hxx"
+#include "viewdata.hxx"
+#include "cbutton.hxx"
+#include "checklistmenu.hxx"
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <o3tl/deleter.hxx>
+#include <vcl/window.hxx>
+
+#include <memory>
+#include <vector>
+
+
+namespace editeng {
+ struct MisspellRanges;
+}
+
+namespace sc {
+ class SpellCheckContext;
+}
+
+namespace sdr::overlay { class OverlayManager; }
+
+class FmFormView;
+struct ScTableInfo;
+struct ScDragData;
+class ScDPObject;
+class ScDPFieldButton;
+class ScOutputData;
+class SdrObject;
+class SdrEditView;
+class ScNoteMarker;
+class SdrHdlList;
+class ScTransferObj;
+struct SpellCallbackInfo;
+class ScLokRTLContext;
+
+ // mouse status (nMouseStatus)
+
+#define SC_GM_NONE 0
+#define SC_GM_TABDOWN 1
+#define SC_GM_DBLDOWN 2
+#define SC_GM_FILTER 3
+#define SC_GM_IGNORE 4
+#define SC_GM_WATERUNDO 5
+#define SC_GM_URLDOWN 6
+
+ // page drag mode
+
+#define SC_PD_NONE 0
+#define SC_PD_RANGE_L 1
+#define SC_PD_RANGE_R 2
+#define SC_PD_RANGE_T 4
+#define SC_PD_RANGE_B 8
+#define SC_PD_RANGE_TL (SC_PD_RANGE_T|SC_PD_RANGE_L)
+#define SC_PD_RANGE_TR (SC_PD_RANGE_T|SC_PD_RANGE_R)
+#define SC_PD_RANGE_BL (SC_PD_RANGE_B|SC_PD_RANGE_L)
+#define SC_PD_RANGE_BR (SC_PD_RANGE_B|SC_PD_RANGE_R)
+#define SC_PD_BREAK_H 16
+#define SC_PD_BREAK_V 32
+
+// predefines
+namespace sdr::overlay { class OverlayObjectList; }
+
+class ScFilterListBox;
+
+class SAL_DLLPUBLIC_RTTI ScGridWindow : public vcl::Window, public DropTargetHelper, public DragSourceHelper
+{
+ // ScFilterListBox is always used for selection list
+ friend class ScFilterListBox;
+
+ enum RfCorner
+ {
+ NONE,
+ LEFT_UP,
+ RIGHT_UP,
+ LEFT_DOWN,
+ RIGHT_DOWN
+ };
+
+ std::unique_ptr<sdr::overlay::OverlayObjectList> mpOOCursors;
+ std::unique_ptr<sdr::overlay::OverlayObjectList> mpOOSelection;
+ std::unique_ptr<sdr::overlay::OverlayObjectList> mpOOSelectionBorder;
+ std::unique_ptr<sdr::overlay::OverlayObjectList> mpOOAutoFill;
+ std::unique_ptr<sdr::overlay::OverlayObjectList> mpOODragRect;
+ std::unique_ptr<sdr::overlay::OverlayObjectList> mpOOHeader;
+ std::unique_ptr<sdr::overlay::OverlayObjectList> mpOOShrink;
+ std::unique_ptr<sdr::overlay::OverlayObjectList> mpOOSparklineGroup;
+
+ std::optional<tools::Rectangle> mpAutoFillRect;
+
+ /// LibreOfficeKit needs a persistent FmFormView for tiled rendering,
+ /// otherwise the invalidations from drawinglayer do not work.
+ std::unique_ptr<FmFormView> mpLOKDrawView;
+
+ struct MouseEventState;
+
+ /**
+ * Stores current visible column and row ranges, used to avoid expensive
+ * operations on objects that are outside visible area.
+ */
+ struct VisibleRange
+ {
+ SCCOL mnCol1;
+ SCCOL mnCol2;
+ SCROW mnRow1;
+ SCROW mnRow2;
+
+ VisibleRange(const ScDocument&);
+
+ bool isInside(SCCOL nCol, SCROW nRow) const;
+ bool set(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2);
+ };
+
+ VisibleRange maVisibleRange;
+
+ struct LOKCursorEntry
+ {
+ Fraction aScaleX;
+ Fraction aScaleY;
+ tools::Rectangle aRect;
+ };
+
+ // Stores the last cursor position in twips for all
+ // zoom levels demanded from a ScGridWindow instance.
+ std::vector<LOKCursorEntry> maLOKLastCursor;
+
+ std::shared_ptr<sc::SpellCheckContext> mpSpellCheckCxt;
+
+ ScViewData& mrViewData;
+ ScSplitPos eWhich;
+ ScHSplitPos eHWhich;
+ ScVSplitPos eVWhich;
+
+ std::unique_ptr<ScNoteMarker, o3tl::default_delete<ScNoteMarker>> mpNoteMarker;
+
+ std::shared_ptr<ScFilterListBox> mpFilterBox;
+ std::unique_ptr<ScCheckListMenuControl> mpAutoFilterPopup;
+ std::unique_ptr<ScCheckListMenuControl> mpDPFieldPopup;
+ std::unique_ptr<ScDPFieldButton> mpFilterButton;
+
+ ScCheckListMenuControl::ResultType aSaveAutoFilterResult;
+
+ sal_uInt16 nCursorHideCount;
+
+ sal_uInt16 nButtonDown;
+ sal_uInt8 nMouseStatus;
+ enum class ScNestedButtonState { NONE, Down, Up };
+ ScNestedButtonState nNestedButtonState; // track nested button up/down calls
+
+ tools::Long nDPField;
+ ScDPObject* pDragDPObj; //! name?
+
+ sal_uInt16 nRFIndex;
+ SCCOL nRFAddX;
+ SCROW nRFAddY;
+
+ sal_uInt16 nPagebreakMouse; // Page break mode, Drag
+ SCCOLROW nPagebreakBreak;
+ SCCOLROW nPagebreakPrev;
+ ScRange aPagebreakSource;
+ ScRange aPagebreakDrag;
+
+ SvtScriptType nPageScript;
+
+ SCCOL nDragStartX;
+ SCROW nDragStartY;
+ SCCOL nDragEndX;
+ SCROW nDragEndY;
+ InsCellCmd meDragInsertMode;
+
+ ScDDComboBoxButton aComboButton;
+
+ Point aCurMousePos;
+
+ sal_uInt16 nPaintCount;
+ tools::Rectangle aRepaintPixel;
+
+ ScAddress aAutoMarkPos;
+ ScAddress aListValPos;
+
+ tools::Rectangle aInvertRect;
+
+ RfCorner aRFSelectedCorned;
+
+ Timer maShowPageBreaksTimer;
+
+ bool bEEMouse:1; // Edit Engine has mouse
+ bool bDPMouse:1; // DataPilot D&D (new Pivot table)
+ bool bRFMouse:1; // RangeFinder drag
+ bool bRFSize:1;
+ bool bPagebreakDrawn:1;
+ bool bDragRect:1;
+ bool bIsInPaint:1;
+ bool bNeedsRepaint:1;
+ bool bAutoMarkVisible:1;
+ bool bListValButton:1;
+ bool bInitialPageBreaks:1;
+
+ DECL_DLLPRIVATE_LINK( PopupModeEndHdl, weld::Popover&, void );
+ DECL_DLLPRIVATE_LINK( PopupSpellingHdl, SpellCallbackInfo&, void );
+
+ bool TestMouse( const MouseEvent& rMEvt, bool bAction );
+
+ bool DoPageFieldSelection( SCCOL nCol, SCROW nRow );
+ bool DoAutoFilterButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt );
+ void DoPushPivotButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt, bool bButton, bool bPopup );
+
+ void DPMouseMove( const MouseEvent& rMEvt );
+ void DPMouseButtonUp( const MouseEvent& rMEvt );
+ void DPTestMouse( const MouseEvent& rMEvt, bool bMove );
+
+ /**
+ * Check if the mouse click is on a field popup button.
+ *
+ * @return true if the field popup menu has been launched and no further
+ * mouse event handling is necessary, false otherwise.
+ */
+ bool DPTestFieldPopupArrow(const MouseEvent& rMEvt, const ScAddress& rPos, const ScAddress& rDimPos, ScDPObject* pDPObj);
+
+ void DPLaunchFieldPopupMenu(const Point& rScrPos, const Size& rScrSize, const ScAddress& rPos, ScDPObject* pDPObj);
+
+ void RFMouseMove( const MouseEvent& rMEvt, bool bUp );
+
+ void PagebreakMove( const MouseEvent& rMEvt, bool bUp );
+
+ void UpdateDragRect( bool bShowRange, const tools::Rectangle& rPosRect );
+
+ bool IsAutoFilterActive( SCCOL nCol, SCROW nRow, SCTAB nTab );
+ void FilterSelect( sal_uLong nSel );
+
+ void ExecDataSelect( SCCOL nCol, SCROW nRow, const OUString& rStr );
+
+ bool HasScenarioButton( const Point& rPosPixel, ScRange& rScenRange );
+
+ void DropScroll( const Point& rMousePos );
+
+ sal_Int8 AcceptPrivateDrop( const AcceptDropEvent& rEvt, const ScDragData& rData );
+ sal_Int8 ExecutePrivateDrop( const ExecuteDropEvent& rEvt, const ScDragData& rData );
+ sal_Int8 DropTransferObj( ScTransferObj* pTransObj, SCCOL nDestPosX, SCROW nDestPosY,
+ const Point& rLogicPos, sal_Int8 nDndAction );
+
+ void HandleMouseButtonDown( const MouseEvent& rMEvt, MouseEventState& rState );
+
+ bool DrawMouseButtonDown(const MouseEvent& rMEvt);
+ bool DrawMouseButtonUp(const MouseEvent& rMEvt);
+ bool DrawMouseMove(const MouseEvent& rMEvt);
+ bool DrawKeyInput(const KeyEvent& rKEvt, vcl::Window* pWin);
+ bool DrawCommand(const CommandEvent& rCEvt);
+ bool DrawHasMarkedObj();
+ void DrawEndAction();
+ void DrawMarkDropObj( SdrObject* pObj );
+ bool IsMyModel(const SdrEditView* pSdrView);
+
+ void DrawRedraw( ScOutputData& rOutputData, SdrLayerID nLayer );
+ void DrawSdrGrid( const tools::Rectangle& rDrawingRect, OutputDevice* pContentDev );
+ void DrawAfterScroll();
+ tools::Rectangle GetListValButtonRect( const ScAddress& rButtonPos );
+
+ void DrawHiddenIndicator( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, vcl::RenderContext& rRenderContext);
+ void DrawPagePreview( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, vcl::RenderContext& rRenderContext);
+
+ bool GetEditUrl( const Point& rPos,
+ OUString* pName=nullptr, OUString* pUrl=nullptr, OUString* pTarget=nullptr );
+
+ bool HitRangeFinder( const Point& rMouse, RfCorner& rCorner, sal_uInt16* pIndex,
+ SCCOL* pAddX, SCROW* pAddY );
+
+ sal_uInt16 HitPageBreak( const Point& rMouse, ScRange* pSource,
+ SCCOLROW* pBreak, SCCOLROW* pPrev );
+
+ /** The cell may be covered by text that overflows from a previous cell.
+
+ @return if true, the given cell is covered by (overflowing) text and
+ rTextStartPosX returns the column where the text that overflows
+ starts.
+ */
+ bool IsCellCoveredByText(SCCOL nPosX, SCROW nPosY, SCTAB nTab, SCCOL &rTextStartPosX);
+
+ void PasteSelection( const Point& rPosPixel );
+
+ void SelectForContextMenu( const Point& rPosPixel, SCCOL nCellX, SCROW nCellY );
+
+ void GetSelectionRects( ::std::vector< tools::Rectangle >& rPixelRects ) const;
+ void GetSelectionRectsPrintTwips(::std::vector< tools::Rectangle >& rRects) const;
+ void GetPixelRectsFor( const ScMarkData &rMarkData,
+ ::std::vector< tools::Rectangle >& rPixelRects ) const;
+ void GetRectsAnyFor(const ScMarkData &rMarkData,
+ ::std::vector< tools::Rectangle >& rRects, bool bInPrintTwips) const;
+ void UpdateKitSelection(const std::vector<tools::Rectangle>& rRectangles,
+ std::vector<tools::Rectangle>* pLogicRects = nullptr);
+ bool NeedLOKCursorInvalidation(const tools::Rectangle& rCursorRect,
+ const Fraction aScaleX, const Fraction aScaleY);
+ void InvalidateLOKViewCursor(const tools::Rectangle& rCursorRect,
+ const Fraction aScaleX, const Fraction aScaleY);
+
+ void SetupInitialPageBreaks(const ScDocument& rDoc, SCTAB nTab);
+ DECL_DLLPRIVATE_LINK(InitiatePageBreaksTimer, Timer*, void);
+
+protected:
+ virtual void PrePaint(vcl::RenderContext& rRenderContext) override;
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+
+ virtual void RequestHelp( const HelpEvent& rEvt ) override;
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+ virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override;
+
+public:
+ enum class AutoFilterMode
+ {
+ Normal,
+ Empty,
+ NonEmpty,
+ Top10,
+ Bottom10,
+ Custom,
+ TextColor,
+ BackgroundColor,
+ SortAscending,
+ SortDescending,
+ Clear
+ };
+
+ ScGridWindow( vcl::Window* pParent, ScViewData& rData, ScSplitPos eWhichPos );
+ virtual ~ScGridWindow() override;
+ virtual void dispose() override;
+
+ virtual void KeyInput(const KeyEvent& rKEvt) override;
+ // #i70788# flush and get overlay
+ rtl::Reference<sdr::overlay::OverlayManager> getOverlayManager() const;
+ void flushOverlayManager();
+
+ virtual OUString GetSurroundingText() const override;
+ virtual Selection GetSurroundingTextSelection() const override;
+ virtual bool DeleteSurroundingText(const Selection& rSelection) override;
+
+ virtual void Command( const CommandEvent& rCEvt ) override;
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual bool PreNotify( NotifyEvent& rNEvt ) override;
+ virtual void Tracking( const TrackingEvent& rTEvt ) override;
+
+ void PaintTile( VirtualDevice& rDevice,
+ int nOutputWidth, int nOutputHeight,
+ int nTilePosX, int nTilePosY,
+ tools::Long nTileWidth, tools::Long nTileHeight );
+
+ /// @see Window::LogicInvalidate().
+ void LogicInvalidate(const tools::Rectangle* pRectangle) override;
+
+ /// Update the cell selection according to what handles have been dragged.
+ /// @see vcl::ITiledRenderable::setTextSelection() for the values of nType.
+ /// Coordinates are in pixels.
+ void SetCellSelectionPixel(int nType, int nPixelX, int nPixelY);
+ /// Get the cell selection, coordinates are in logic units.
+ void GetCellSelection(std::vector<tools::Rectangle>& rLogicRects);
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override;
+
+ void FakeButtonUp();
+
+ const Point& GetMousePosPixel() const { return aCurMousePos; }
+ void UpdateStatusPosSize();
+
+ void ClickExtern();
+
+ using Window::SetPointer;
+
+ void MoveMouseStatus( ScGridWindow &rDestWin );
+
+ void ScrollPixel( tools::Long nDifX, tools::Long nDifY );
+ void UpdateEditViewPos();
+
+ void UpdateFormulas(SCCOL nX1 = -1, SCROW nY1 = -1, SCCOL nX2 = -1, SCROW nY2 = -1);
+
+ void ShowFilterMenu(weld::Window* pParent, const tools::Rectangle& rCellRect, bool bLayoutRTL);
+
+ void LaunchDataSelectMenu( SCCOL nCol, SCROW nRow );
+ void DoScenarioMenu( const ScRange& rScenRange );
+
+ void LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow);
+ void RefreshAutoFilterButton(const ScAddress& rPos);
+ void UpdateAutoFilterFromMenu(AutoFilterMode eMode);
+
+ void LaunchPageFieldMenu( SCCOL nCol, SCROW nRow );
+ void LaunchDPFieldMenu( SCCOL nCol, SCROW nRow );
+
+ css::sheet::DataPilotFieldOrientation GetDPFieldOrientation( SCCOL nCol, SCROW nRow ) const;
+
+ void DPLaunchFieldPopupMenu(const Point& rScrPos, const Size& rScrSize,
+ tools::Long nDimIndex, ScDPObject* pDPObj);
+
+ void DrawButtons(SCCOL nX1, SCCOL nX2, const ScTableInfo& rTabInfo, OutputDevice* pContentDev,
+ const ScLokRTLContext* pLokRTLContext);
+
+ using Window::Draw;
+ void Draw( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ ScUpdateMode eMode );
+
+ /// Draw content of the gridwindow; shared between the desktop and the tiled rendering.
+ void DrawContent(OutputDevice &rDevice, const ScTableInfo& rTableInfo, ScOutputData& aOutputData, bool bLogicText);
+
+ void CreateAnchorHandle(SdrHdlList& rHdl, const ScAddress& rAddress);
+
+ void HideCursor();
+ void ShowCursor();
+ void UpdateAutoFillMark(bool bMarked, const ScRange& rMarkRange);
+
+ void UpdateListValPos( bool bVisible, const ScAddress& rPos );
+
+ bool ShowNoteMarker( SCCOL nPosX, SCROW nPosY, bool bKeyboard );
+ void HideNoteMarker();
+
+ /// MapMode for the drawinglayer objects.
+ MapMode GetDrawMapMode( bool bForce = false );
+
+ void StopMarking();
+ void UpdateInputContext();
+
+ bool NeedsRepaint() const { return bNeedsRepaint; }
+
+ void DoInvertRect( const tools::Rectangle& rPixel );
+
+ void CheckNeedsRepaint();
+
+ void UpdateDPFromFieldPopupMenu();
+ bool UpdateVisibleRange();
+
+ void CursorChanged();
+ void DrawLayerCreated();
+ void SetAutoSpellContext( const std::shared_ptr<sc::SpellCheckContext> &ctx );
+ void ResetAutoSpell();
+ void ResetAutoSpellForContentChange();
+ void SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const std::vector<editeng::MisspellRanges>* pRanges );
+ const std::vector<editeng::MisspellRanges>* GetAutoSpellData( SCCOL nPosX, SCROW nPosY );
+ bool InsideVisibleRange( SCCOL nPosX, SCROW nPosY );
+
+ void UpdateSparklineGroupOverlay();
+ void DeleteSparklineGroupOverlay();
+ void DeleteCopySourceOverlay();
+ void UpdateCopySourceOverlay();
+ void DeleteCursorOverlay();
+ void UpdateCursorOverlay();
+ void DeleteSelectionOverlay();
+ void UpdateSelectionOverlay();
+ void DeleteAutoFillOverlay();
+ void UpdateAutoFillOverlay();
+ void DeleteDragRectOverlay();
+ void UpdateDragRectOverlay();
+ void DeleteHeaderOverlay();
+ void UpdateHeaderOverlay();
+ void DeleteShrinkOverlay();
+ void UpdateShrinkOverlay();
+ void UpdateAllOverlays();
+
+ /// get Cell cursor in this view's co-ordinate system @see ScModelObj::getCellCursor().
+ OString getCellCursor() const;
+ void notifyKitCellCursor() const;
+ void notifyKitCellViewCursor(const SfxViewShell* pForShell) const;
+ void updateKitCellCursor(const SfxViewShell* pOtherShell) const;
+ /// notify this view with new positions for other view's cursors (after zoom)
+ void updateKitOtherCursors() const;
+ void updateOtherKitSelections() const;
+
+ void notifyKitCellFollowJump() const;
+
+
+ /// 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;
+
+ ScViewData& getViewData();
+ virtual FactoryFunction GetUITestFactory() const override;
+
+ void updateLOKValListButton(bool bVisible, const ScAddress& rPos) const;
+ void updateLOKInputHelp(const OUString& title, const OUString& content) const;
+
+ void initiatePageBreaks();
+
+protected:
+ void ImpCreateOverlayObjects();
+ void ImpDestroyOverlayObjects();
+
+private:
+
+#ifdef DBG_UTIL
+ void dumpCellProperties();
+ void dumpColumnInformationPixel();
+ void dumpColumnInformationHmm();
+ void dumpGraphicInformation();
+ void dumpColumnCellStorage();
+#endif
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/groupdlg.hxx b/sc/source/ui/inc/groupdlg.hxx
new file mode 100644
index 000000000..26c3129b3
--- /dev/null
+++ b/sc/source/ui/inc/groupdlg.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 <vcl/weld.hxx>
+
+class ScGroupDlg : public weld::GenericDialogController
+{
+public:
+ ScGroupDlg(weld::Window* pParent, bool bUnGroup, bool bRows);
+ virtual ~ScGroupDlg() override;
+ bool GetColsChecked() const;
+
+private:
+ std::unique_ptr<weld::RadioButton> m_xBtnRows;
+ std::unique_ptr<weld::RadioButton> m_xBtnCols;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/hdrcont.hxx b/sc/source/ui/inc/hdrcont.hxx
new file mode 100644
index 000000000..149db145e
--- /dev/null
+++ b/sc/source/ui/inc/hdrcont.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <vcl/window.hxx>
+#include <vcl/timer.hxx>
+#include <types.hxx>
+
+#define HDR_SIZE_OPTIMUM 0xFFFF
+
+// Size of the sliders
+#define HDR_SLIDERSIZE 2
+
+class ScTabView;
+class SelectionEngine;
+
+class ScHeaderControl : public vcl::Window
+{
+private:
+ SelectionEngine* pSelEngine;
+ Timer aShowHelpTimer;
+ vcl::Font aNormFont;
+ vcl::Font aBoldFont;
+ vcl::Font aAutoFilterFont;
+ bool bBoldSet;
+ bool bAutoFilterSet;
+
+ bool bVertical; // Vertical = Row header
+
+ tools::Long nWidth;
+ tools::Long nSmallWidth;
+ tools::Long nBigWidth;
+
+ SCCOLROW nSize;
+
+ SCCOLROW nMarkStart;
+ SCCOLROW nMarkEnd;
+ bool bMarkRange;
+
+ bool bDragging; // Resizing
+ SCCOLROW nDragNo;
+ tools::Long nDragStart;
+ tools::Long nDragPos;
+ void* nTipVisible;
+ bool bDragMoved;
+
+ bool bIgnoreMove;
+
+ bool bInRefMode;
+
+ tools::Long GetScrPos( SCCOLROW nEntryNo ) const;
+ SCCOLROW GetMousePos(const Point& rPos, bool& rBorder) const;
+ bool IsSelectionAllowed(SCCOLROW nPos) const;
+ void ShowDragHelp();
+ void HideDragHelp();
+
+ void DoPaint( SCCOLROW nStart, SCCOLROW nEnd );
+
+ DECL_LINK(ShowDragHelpHdl, Timer*, void);
+
+protected:
+ ScTabView* pTabView;
+
+ // Window overrides
+
+ 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 Tracking( const TrackingEvent& rTEvt ) override;
+
+ virtual void RequestHelp( const HelpEvent& rHEvt ) override;
+
+ // new methods
+
+ virtual SCCOLROW GetPos() const = 0; // current position (Scrolling)
+ virtual sal_uInt16 GetEntrySize( SCCOLROW nEntryNo ) const = 0; // width / height (Pixel)
+ virtual OUString GetEntryText( SCCOLROW nEntryNo ) const = 0;
+
+ virtual SCCOLROW GetHiddenCount( SCCOLROW nEntryNo ) const;
+ virtual bool IsLayoutRTL() const;
+ virtual bool IsMirrored() const;
+
+ virtual void SetEntrySize( SCCOLROW nPos, sal_uInt16 nNewWidth ) = 0;
+ virtual void HideEntries( SCCOLROW nStart, SCCOLROW nEnd ) = 0;
+
+ virtual void SetMarking( bool bSet );
+ virtual void SelectWindow();
+ virtual bool IsDisabled() const;
+ virtual bool ResizeAllowed() const;
+ virtual OUString GetDragHelp( tools::Long nVal );
+
+ virtual void DrawInvert( tools::Long nDragPos );
+ virtual void Command( const CommandEvent& rCEvt ) override;
+ virtual void dispose() override;
+
+public:
+ ScHeaderControl( vcl::Window* pParent, SelectionEngine* pSelectionEngine,
+ SCCOLROW nNewSize, bool bNewVertical, ScTabView* pTab );
+ virtual ~ScHeaderControl() override;
+
+ void SetIgnoreMove(bool bSet) { bIgnoreMove = bSet; }
+
+ void StopMarking();
+
+ void SetMark( bool bNewSet, SCCOLROW nNewStart, SCCOLROW nNewEnd );
+
+ tools::Long GetWidth() const { return nWidth; }
+ tools::Long GetSmallWidth() const { return nSmallWidth; }
+ tools::Long GetBigWidth() const { return nBigWidth; }
+ void SetWidth( tools::Long nNew );
+ void GetMarkRange(SCCOLROW& rStart, SCCOLROW& rEnd) const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/hfedtdlg.hxx b/sc/source/ui/inc/hfedtdlg.hxx
new file mode 100644
index 000000000..61d02f9c6
--- /dev/null
+++ b/sc/source/ui/inc/hfedtdlg.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 <sal/config.h>
+
+#include <string_view>
+
+#include <sfx2/tabdlg.hxx>
+#include <editeng/svxenum.hxx>
+
+class ScHFEditDlg : public SfxTabDialogController
+{
+ SvxNumType eNumType;
+protected:
+ ScHFEditDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle,
+ const OUString& rUIXMLDescription, const OString& rID);
+public:
+ virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override;
+};
+
+class ScHFEditHeaderDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditHeaderDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditFooterDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditFooterDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditSharedFirstHeaderDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditSharedFirstHeaderDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditSharedFirstFooterDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditSharedFirstFooterDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditSharedLeftHeaderDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditSharedLeftHeaderDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditSharedLeftFooterDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditSharedLeftFooterDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditFirstHeaderDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditFirstHeaderDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditLeftHeaderDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditLeftHeaderDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditRightHeaderDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditRightHeaderDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditFirstFooterDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditFirstFooterDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditLeftFooterDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditLeftFooterDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditRightFooterDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditRightFooterDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditSharedHeaderDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditSharedHeaderDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditSharedFooterDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditSharedFooterDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditAllDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditAllDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+class ScHFEditActiveDlg : public ScHFEditDlg
+{
+public:
+ ScHFEditActiveDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet, std::u16string_view rPageStyle);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/highred.hxx b/sc/source/ui/inc/highred.hxx
new file mode 100644
index 000000000..cfb706a8e
--- /dev/null
+++ b/sc/source/ui/inc/highred.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 "anyrefdg.hxx"
+
+#include <svx/ctredlin.hxx>
+#include <chgviset.hxx>
+
+class ScViewData;
+class ScDocument;
+
+
+class ScHighlightChgDlg : public ScAnyRefDlgController
+{
+private:
+ ScViewData& m_rViewData;
+ ScDocument& rDoc;
+ ScChangeViewSettings aChangeViewSet;
+
+ std::unique_ptr<weld::CheckButton> m_xHighlightBox;
+ std::unique_ptr<weld::CheckButton> m_xCbAccept;
+ std::unique_ptr<weld::CheckButton> m_xCbReject;
+ std::unique_ptr<weld::Button> m_xOkButton;
+
+ std::unique_ptr<formula::RefEdit> m_xEdAssign;
+ std::unique_ptr<formula::RefButton> m_xRbAssign;
+
+ std::unique_ptr<weld::Container> m_xBox;
+
+ std::unique_ptr<SvxTPFilter> m_xFilterCtr;
+
+ void Init();
+
+ DECL_LINK( RefHandle, SvxTPFilter*, void );
+ DECL_LINK( HighlightHandle, weld::Toggleable&, void );
+ DECL_LINK( OKBtnHdl, weld::Button&, void );
+
+protected:
+
+ virtual void RefInputDone( bool bForced = false ) override;
+
+public:
+ ScHighlightChgDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScViewData& rViewData);
+
+ virtual ~ScHighlightChgDlg() override;
+
+ virtual void SetActive() override;
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+ virtual void Close() override;
+ virtual bool IsRefInputMode() const override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/hiranges.hxx b/sc/source/ui/inc/hiranges.hxx
new file mode 100644
index 000000000..9689e3593
--- /dev/null
+++ b/sc/source/ui/inc/hiranges.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <tools/color.hxx>
+#include <address.hxx>
+
+struct ScHighlightEntry
+{
+ ScRange aRef;
+ Color aColor;
+
+ ScHighlightEntry( const ScRange& rR, const Color& rC ) :
+ aRef(rR), aColor(rC) {}
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/imoptdlg.hxx b/sc/source/ui/inc/imoptdlg.hxx
new file mode 100644
index 000000000..2ffe9f4df
--- /dev/null
+++ b/sc/source/ui/inc/imoptdlg.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 <rtl/textenc.h>
+#include <rtl/ustring.hxx>
+#include <scdllapi.h>
+
+class SC_DLLPUBLIC ScImportOptions
+{
+public:
+ ScImportOptions( std::u16string_view rStr );
+
+ ScImportOptions( sal_Unicode nFieldSep, sal_Unicode nTextSep, rtl_TextEncoding nEnc )
+ : nFieldSepCode(nFieldSep), nTextSepCode(nTextSep),
+ bFixedWidth(false), bSaveAsShown(false), bQuoteAllText(false),
+ bSaveNumberAsSuch(true), bSaveFormulas(false), bRemoveSpace(false),
+ bEvaluateFormulas(true), nSheetToExport(0)
+ { SetTextEncoding( nEnc ); }
+
+ ScImportOptions& operator=( const ScImportOptions& rCpy ) = default;
+
+ OUString BuildString() const;
+
+ void SetTextEncoding( rtl_TextEncoding nEnc );
+
+ sal_Unicode nFieldSepCode;
+ sal_Unicode nTextSepCode;
+ OUString aStrFont;
+ rtl_TextEncoding eCharSet;
+ bool bFixedWidth;
+ bool bSaveAsShown;
+ bool bQuoteAllText;
+ bool bSaveNumberAsSuch;
+ bool bSaveFormulas;
+ bool bRemoveSpace;
+ bool bEvaluateFormulas;
+ // "0" for 'current sheet', "-1" for all sheets (each to a separate file),
+ // or 1-based specific sheet number (to a separate file).
+ sal_Int32 nSheetToExport;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/impex.hxx b/sc/source/ui/inc/impex.hxx
new file mode 100644
index 000000000..aafeb00c9
--- /dev/null
+++ b/sc/source/ui/inc/impex.hxx
@@ -0,0 +1,241 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in 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/deleter.hxx>
+#include <sot/formats.hxx>
+#include <address.hxx>
+#include <tools/stream.hxx>
+
+#include <com/sun/star/uno/Any.hxx>
+
+class ScDocShell;
+class ScDocument;
+class ScAsciiOptions;
+
+/**
+ * These options control how multi-line cells are converted during export in
+ * certain lossy formats (such as csv).
+ */
+struct ScExportTextOptions
+{
+ enum NewlineConversion { ToSystem, ToSpace, None };
+ ScExportTextOptions( NewlineConversion eNewlineConversion = ToSystem, sal_Unicode cSeparatorConvertTo = 0, bool bAddQuotes = false ) :
+ meNewlineConversion( eNewlineConversion ), mcSeparatorConvertTo( cSeparatorConvertTo ), mbAddQuotes( bAddQuotes ) {}
+
+ NewlineConversion meNewlineConversion;
+ sal_Unicode mcSeparatorConvertTo; // Convert separator to this character
+ bool mbAddQuotes;
+};
+
+class SC_DLLPUBLIC ScImportExport
+{
+ ScDocShell* pDocSh;
+ ScDocument& rDoc;
+ std::unique_ptr<ScDocument, o3tl::default_delete<ScDocument>> pUndoDoc;
+ ScRange aRange;
+ OUString aStreamPath;
+ OUString aNonConvertibleChars;
+ OUString maFilterOptions;
+ sal_uInt32 nSizeLimit;
+ SCROW nMaxImportRow;
+ sal_Unicode cSep; // Separator
+ sal_Unicode cStr; // String Delimiter
+ bool bFormulas; // Formula in Text?
+ bool bIncludeFiltered; // include filtered rows? (default true)
+ bool bAll; // no selection
+ bool bSingle; // Single selection
+ bool bUndo; // with Undo?
+ bool bOverflowRow; // too many rows
+ bool bOverflowCol; // too many columns
+ bool bOverflowCell; // too much data for a cell
+ bool mbApi;
+ bool mbImportBroadcast; // whether or not to broadcast after data import.
+ bool mbOverwriting; // Whether we could be overwriting existing values (paste).
+ // In this case we cannot use the insert optimization, but we
+ // do not need to broadcast after the import.
+ ScExportTextOptions mExportTextOptions;
+
+ std::unique_ptr<ScAsciiOptions> pExtOptions; // extended options
+
+ bool StartPaste(); // Protect check, set up Undo
+ void EndPaste(bool bAutoRowHeight = true); // Undo/Redo actions, Repaint
+ bool Doc2Text( SvStream& );
+ bool Text2Doc( SvStream& );
+ bool Doc2Sylk( SvStream& );
+ bool Sylk2Doc( SvStream& );
+ bool Doc2HTML( SvStream&, const OUString& );
+ bool Doc2RTF( SvStream& );
+ bool Doc2Dif( SvStream& );
+ bool Dif2Doc( SvStream& );
+ bool ExtText2Doc( SvStream& ); // with pExtOptions
+ bool RTF2Doc( SvStream&, const OUString& rBaseURL );
+ bool HTML2Doc( SvStream&, const OUString& rBaseURL );
+
+public:
+ ScImportExport( ScDocument& ); // the whole document
+ ScImportExport( ScDocument&, const OUString& ); // Range/cell input
+ ScImportExport( ScDocument&, const ScAddress& );
+ ScImportExport( ScDocument&, const ScRange& );
+ ~ScImportExport() COVERITY_NOEXCEPT_FALSE;
+
+ void SetExtOptions( const ScAsciiOptions& rOpt );
+ void SetFilterOptions( const OUString& rFilterOptions );
+ bool IsRef() const { return !bAll; }
+
+ const ScRange& GetRange() const { return aRange; }
+
+ static void EmbeddedNullTreatment( OUString & rStr );
+
+ static bool IsFormatSupported( SotClipboardFormatId nFormat );
+ static const sal_Unicode* ScanNextFieldFromString( const sal_Unicode* p,
+ OUString& rField, sal_Unicode cStr, const sal_Unicode* pSeps,
+ bool bMergeSeps, bool& rbIsQuoted, bool& rbOverflowCell, bool bRemoveSpace );
+ static void WriteUnicodeOrByteString( SvStream& rStrm, const OUString& rString, bool bZero = false );
+ static void WriteUnicodeOrByteEndl( SvStream& rStrm );
+
+ /** ScImportExport::CountVisualWidth
+ Count the width of string visually ( in multiple of western characters), considering CJK
+ ideographs and CJK symbols (U+3000-U+303F) as twice the width of western characters.
+ @param rStr the string.
+ @param nIdx the starting index, index is incremented for each counted character.
+ @param nMaxWidth the maximum width to count.
+ @return the sum of the width of counted characters.
+ **/
+ static sal_Int32 CountVisualWidth(const OUString& rStr, sal_Int32& nIdx, sal_Int32 nMaxWidth);
+
+ /** ScImportExport::CountVisualWidth
+ @return the sum of the visual width of the whole string.
+ **/
+ static sal_Int32 CountVisualWidth(const OUString& rStr);
+
+ //! only if stream is only used in own (!) memory
+ static void SetNoEndianSwap( SvStream& rStrm );
+
+ void SetSeparator( sal_Unicode c ) { cSep = c; }
+ void SetDelimiter( sal_Unicode c ) { cStr = c; }
+ void SetFormulas( bool b ) { bFormulas = b; }
+ void SetIncludeFiltered( bool b ) { bIncludeFiltered = b; }
+
+ void SetStreamPath( const OUString& rPath ) { aStreamPath = rPath; }
+
+ bool ImportString( const OUString&, SotClipboardFormatId );
+ bool ExportString( OUString&, SotClipboardFormatId );
+ bool ExportByteString( OString&, rtl_TextEncoding, SotClipboardFormatId );
+
+ bool ImportStream( SvStream&, const OUString& rBaseURL, SotClipboardFormatId );
+ bool ExportStream( SvStream&, const OUString& rBaseURL, SotClipboardFormatId );
+
+ bool ExportData( const OUString& rMimeType,
+ css::uno::Any & rValue );
+
+ // after import
+ bool IsOverflowRow() const { return bOverflowRow; }
+ bool IsOverflowCol() const { return bOverflowCol; }
+ bool IsOverflowCell() const { return bOverflowCell; }
+ bool IsOverflow() const { return bOverflowRow || bOverflowCol || bOverflowCell; }
+
+ const OUString& GetNonConvertibleChars() const { return aNonConvertibleChars; }
+
+ void SetApi( bool bApi ) { mbApi = bApi; }
+ void SetImportBroadcast( bool b ) { mbImportBroadcast = b; }
+ void SetOverwriting( const bool bOverwriting ) { mbOverwriting = bOverwriting; }
+ void SetExportTextOptions( const ScExportTextOptions& options ) { mExportTextOptions = options; }
+};
+
+// Helper class for importing clipboard strings as streams.
+class ScImportStringStream : public SvMemoryStream
+{
+public:
+ ScImportStringStream(const OUString& rStr);
+};
+
+/** Read a CSV (comma separated values) data line using
+ ReadUniOrByteStringLine().
+
+ @param bEmbeddedLineBreak
+ If TRUE and a line-break occurs inside a field of data,
+ a line feed LF '\n' and the next line are appended. Repeats
+ until a line-break is not in a field. A field is determined
+ by delimiting rFieldSeparators and optionally surrounded by
+ a pair of cFieldQuote characters. For a line-break to be
+ within a field, the field content MUST be surrounded by
+ cFieldQuote characters, and the opening cFieldQuote MUST be
+ at the very start of a line or follow right behind a field
+ separator with no extra characters in between, with the
+ exception of blanks contradictory to RFC 4180. Anything,
+ including field separators and escaped quotes (by doubling
+ them) may appear in a quoted field.
+
+ If bEmbeddedLineBreak==FALSE, nothing is parsed and the
+ string returned is simply one ReadUniOrByteStringLine().
+
+ @param rFieldSeparators
+ A list of characters that each may act as a field separator.
+ If rcDetectSep was 0 and a separator is detected then it is appended to
+ rFieldSeparators.
+
+ @param cFieldQuote
+ The quote character used.
+
+ @param rcDetectSep
+ If 0 then attempt to detect a possible separator if
+ rFieldSeparators doesn't include it already. This can be necessary because
+ of the "accept broken misquoted CSV fields" feature that tries to ignore
+ trailing blanks after a quoted field and if no separator follows continues
+ to add content to the field assuming the single double quote was in error.
+ It is also necessary if the only possible separator was not selected and
+ not included in rFieldSeparators and a line starts with a quoted field, in
+ which case appending lines is tried until end of file.
+ If a separator is detected it is added to rFieldSeparators and the
+ line is reread with the new separators
+
+ @param nMaxSourceLines
+ Maximum source lines to read and combine into one logical line for embedded
+ new line purpose. Should be limited for the preview dialog because only
+ non-matching separators selected otherwise would lead to trying to
+ concatenate lines until file end.
+ If 0 no limit other than the internal arbitrary resulting line length
+ limit.
+
+ check Stream::good() to detect IO problems during read
+
+ @ATTENTION
+ Note that the string returned may be truncated even inside
+ a quoted field if some (arbitrary) maximum length was reached.
+ There currently is no way to exactly determine the conditions,
+ whether this was at a line end, or whether open quotes
+ would have closed the field before the line end, as even a
+ ReadUniOrByteStringLine() may return prematurely but the
+ stream was positioned ahead until the real end of line.
+ Additionally, due to character encoding conversions, string
+ length and bytes read don't necessarily match, and
+ resyncing to a previous position matching the string's
+ length isn't always possible. As a result, a logical line
+ with embedded line breaks and more than the maximum length
+ characters will be spoiled, and a subsequent ReadCsvLine()
+ may start under false preconditions.
+
+ */
+SC_DLLPUBLIC OUString ReadCsvLine( SvStream &rStream, bool bEmbeddedLineBreak,
+ OUString& rFieldSeparators, sal_Unicode cFieldQuote, sal_Unicode& rcDetectSep,
+ sal_uInt32 nMaxSourceLines = 0 );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/inputhdl.hxx b/sc/source/ui/inc/inputhdl.hxx
new file mode 100644
index 000000000..ca70287ef
--- /dev/null
+++ b/sc/source/ui/inc/inputhdl.hxx
@@ -0,0 +1,334 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <global.hxx>
+#include <address.hxx>
+#include <tools/solar.h>
+#include <typedstrdata.hxx>
+
+#include <tools/fract.hxx>
+#include <tools/gen.hxx>
+#include <tools/link.hxx>
+#include <vcl/vclptr.hxx>
+#include <editeng/svxenum.hxx>
+#include "viewdata.hxx"
+
+#include <set>
+#include <memory>
+#include <vector>
+
+class ScDocument;
+class ScTabViewShell;
+class ScInputWindow;
+class ScPatternAttr;
+class ScEditEngineDefaulter;
+class EditView;
+class EditTextObject;
+class ScInputHdlState;
+class ScRangeFindList;
+class Timer;
+class KeyEvent;
+class CommandEvent;
+class VclWindowEvent;
+namespace vcl { class Window; }
+struct ReferenceMark;
+struct ESelection;
+
+// ScInputHandler
+
+class ScInputHandler final
+{
+private:
+ VclPtr<ScInputWindow> pInputWin;
+
+ std::unique_ptr<ScEditEngineDefaulter> mpEditEngine; ///< Edited data in the sheet (when the user clicks into the sheet, and starts writing there).
+ EditView* pTableView; // associated active EditView
+ EditView* pTopView; // EditView in the input row
+
+ std::unique_ptr<ScTypedCaseStrSet> pColumnData;
+ std::unique_ptr<ScTypedCaseStrSet> pFormulaData;
+ std::unique_ptr<ScTypedCaseStrSet> pFormulaDataPara;
+ ScTypedCaseStrSet::const_iterator miAutoPosColumn;
+ ScTypedCaseStrSet::const_iterator miAutoPosFormula;
+ std::set<sal_Unicode> maFormulaChar;
+
+ VclPtr<vcl::Window> pTipVisibleParent;
+ void* nTipVisible;
+ VclPtr<vcl::Window> pTipVisibleSecParent;
+ void* nTipVisibleSec;
+ OUString aManualTip;
+ OUString aAutoSearch;
+
+ OUString aCurrentText;
+
+ OUString aFormText; // for autopilot function
+ sal_Int32 nFormSelStart; // Selection for autopilot function
+ sal_Int32 nFormSelEnd;
+
+ sal_Unicode nCellPercentFormatDecSep; // 0:= no percent format, else which decimal separator
+
+ sal_uInt16 nAutoPar; // autom.parentheses than can be overwritten
+
+ ScAddress aCursorPos;
+ ScInputMode eMode;
+ bool bUseTab:1; // Scrolling possible
+ bool bTextValid:1; // Text is not in edit engine
+ bool bModified:1;
+ bool bSelIsRef:1;
+ bool bFormulaMode:1;
+ bool bInRangeUpdate:1;
+ bool bParenthesisShown:1;
+ bool bCreatingFuncView:1;
+ bool bInEnterHandler:1;
+ bool bCommandErrorShown:1;
+ bool bInOwnChange:1;
+
+ bool bProtected:1;
+ bool bLastIsSymbol:1;
+ bool mbDocumentDisposing:1;
+ /// To indicate if there is a partial prefix completion.
+ bool mbPartialPrefix:1;
+ bool mbEditingExistingContent:1;
+
+ sal_uLong nValidation;
+ SvxCellHorJustify eAttrAdjust;
+
+ Fraction aScaleX; // for ref MapMode
+ Fraction aScaleY;
+
+ ScTabViewShell* pRefViewSh;
+ ScTabViewShell* pActiveViewSh;
+
+ const ScPatternAttr* pLastPattern;
+ std::unique_ptr<SfxItemSet>
+ pEditDefaults;
+
+ std::unique_ptr<ScInputHdlState>
+ pLastState;
+ std::unique_ptr<Timer> pDelayTimer;
+
+ std::unique_ptr<ScRangeFindList>
+ pRangeFindList;
+
+private:
+ void UpdateActiveView();
+ void SyncViews( const EditView* pSourceView = nullptr );
+ /**
+ * @param cTyped typed character. If 0, look at existing document content
+ * for text or number.
+ * @param bInputActivated true if the cell input mode is activated (via
+ * F2), false otherwise.
+ * @param pTopEngine top window input line EditEngine. If not nullptr then
+ * some default attributes are merged to it from the
+ * table EditEngine.
+ * @return true if the new edit mode has been started.
+ */
+ bool StartTable( sal_Unicode cTyped, bool bFromCommand, bool bInputActivated,
+ ScEditEngineDefaulter* pTopEngine );
+ void RemoveSelection();
+ bool StartsLikeFormula( std::u16string_view rStr ) const;
+ void UpdateFormulaMode();
+ static void InvalidateAttribs();
+ void ImplCreateEditEngine();
+ DECL_LINK( DelayTimer, Timer*, void );
+ void GetColData();
+ void UseColData();
+ void NextAutoEntry( bool bBack );
+ void UpdateAdjust( sal_Unicode cTyped );
+ void GetFormulaData();
+ void UseFormulaData();
+ void NextFormulaEntry( bool bBack );
+ void PasteFunctionData();
+ void PasteManualTip();
+ EditView* GetFuncEditView();
+ void RemoveAdjust();
+ void RemoveRangeFinder();
+ void DeleteRangeFinder();
+ void UpdateParenthesis();
+ void UpdateAutoCorrFlag();
+ void ResetAutoPar();
+ void AutoParAdded();
+ bool CursorAtClosingPar();
+ void SkipClosingPar();
+ bool GetFuncName( OUString& aStart, OUString& aResult ); // fdo75264
+ void ShowArgumentsTip( OUString& rSelText );
+ DECL_LINK( ModifyHdl, LinkParamNone*, void );
+ DECL_LINK( ShowHideTipVisibleParentListener, VclWindowEvent&, void );
+ DECL_LINK( ShowHideTipVisibleSecParentListener, VclWindowEvent&, void );
+
+public:
+ ScInputHandler(const ScInputHandler&) = delete;
+ const ScInputHandler& operator=(const ScInputHandler&) = delete;
+
+ ScInputHandler();
+ ~ScInputHandler();
+
+ void SetMode( ScInputMode eNewMode, const OUString* pInitText = nullptr,
+ ScEditEngineDefaulter* pTopEngine = nullptr );
+ bool IsInputMode() const { return (eMode != SC_INPUT_NONE); }
+ bool IsEditMode() const { return (eMode != SC_INPUT_NONE &&
+ eMode != SC_INPUT_TYPE); }
+ bool IsTopMode() const { return (eMode == SC_INPUT_TOP); }
+
+ const OUString& GetEditString();
+ const OUString& GetFormString() const { return aFormText; }
+
+ const ScAddress& GetCursorPos() const { return aCursorPos; }
+
+ bool GetTextAndFields( ScEditEngineDefaulter& rDestEngine );
+ void MergeLanguageAttributes( ScEditEngineDefaulter& rDestEngine ) const;
+
+ bool KeyInput( const KeyEvent& rKEvt, bool bStartEdit );
+ void EnterHandler( ScEnterMode nBlockMode = ScEnterMode::NORMAL, bool bBeforeSavingInLOK = false );
+ void CancelHandler();
+ void SetReference( const ScRange& rRef, const ScDocument& rDoc );
+ void AddRefEntry();
+
+ void InputCommand( const CommandEvent& rCEvt );
+
+ OUString GetSurroundingText();
+ Selection GetSurroundingTextSelection();
+ bool DeleteSurroundingText(const Selection& rSelection);
+
+ void InsertFunction( const OUString& rFuncName, bool bAddPar = true );
+ void ClearText();
+
+ void InputSelection( const EditView* pView );
+ void InputChanged( const EditView* pView, bool bFromNotify );
+
+ void ViewShellGone(const ScTabViewShell* pViewSh);
+ void SetRefViewShell(ScTabViewShell* pRefVsh) {pRefViewSh=pRefVsh;}
+
+ void NotifyChange( const ScInputHdlState* pState, bool bForce = false,
+ ScTabViewShell* pSourceSh = nullptr,
+ bool bStopEditing = true);
+ void UpdateCellAdjust( SvxCellHorJustify eJust );
+
+ void ResetDelayTimer(); //BugId 54702
+
+ void HideTip();
+ void HideTipBelow();
+ void ShowTipCursor();
+ void ShowTip( const OUString& rText ); // at Cursor
+ void ShowTipBelow( const OUString& rText );
+ void ShowFuncList( const ::std::vector< OUString > & rFuncStrVec );
+
+ void SetRefScale( const Fraction& rX, const Fraction& rY );
+ void UpdateRefDevice();
+
+ EditView* GetActiveView();
+ EditView* GetTableView() { return pTableView; }
+ EditView* GetTopView() { return pTopView; }
+
+ bool DataChanging( sal_Unicode cTyped = 0, bool bFromCommand = false );
+ void DataChanged( bool bFromTopNotify = false, bool bSetModified = true );
+
+ bool TakesReturn() const { return ( nTipVisible != nullptr ); }
+
+ void SetModified() { bModified = true; }
+
+ bool GetSelIsRef() const { return bSelIsRef; }
+ void SetSelIsRef(bool bSet) { bSelIsRef = bSet; }
+
+ void ShowRefFrame();
+
+ ScRangeFindList* GetRangeFindList() { return pRangeFindList.get(); }
+
+ void UpdateRange( sal_uInt16 nIndex, const ScRange& rNew );
+
+ // Communication with the autopilot function
+ void InputGetSelection ( sal_Int32& rStart, sal_Int32& rEnd );
+ void InputSetSelection ( sal_Int32 nStart, sal_Int32 nEnd );
+ void InputReplaceSelection ( const OUString& rStr );
+ void InputTurnOffWinEngine();
+
+ bool IsFormulaMode() const { return bFormulaMode; }
+ ScInputWindow* GetInputWindow() { return pInputWin; }
+ void SetInputWindow( ScInputWindow* pNew );
+ void StopInputWinEngine( bool bAll );
+
+ bool IsInEnterHandler() const { return bInEnterHandler; }
+ bool IsInOwnChange() const { return bInOwnChange; }
+
+ /// Returns true if there is a partial autocomplete suggestion.
+ bool HasPartialComplete() const { return mbPartialPrefix; };
+
+ bool IsModalMode( const SfxObjectShell* pDocSh );
+
+ void ForgetLastPattern();
+
+ void UpdateSpellSettings( bool bFromStartTab = false );
+
+ void FormulaPreview();
+
+ Size GetTextSize(); // in 1/100mm
+
+ // actually private, public for SID_INPUT_SUM
+ void InitRangeFinder(const OUString& rFormula);
+
+ void UpdateLokReferenceMarks();
+ static void SendReferenceMarks( const SfxViewShell* pViewShell,
+ const std::vector<ReferenceMark>& rReferenceMarks );
+
+ void SetDocumentDisposing( bool b );
+
+ static ReferenceMark GetReferenceMark( const ScViewData& rViewData, ScDocShell* pDocSh,
+ tools::Long nX1, tools::Long nX2, tools::Long nY1, tools::Long nY2,
+ tools::Long nTab, const Color& rColor );
+
+ void LOKPasteFunctionData(const OUString& rFunctionName);
+ static void LOKSendFormulabarUpdate(const SfxViewShell* pActiveViewSh,
+ const OUString& rText, const ESelection& rSelection);
+};
+
+// ScInputHdlState
+
+class ScInputHdlState
+{
+ friend class ScInputHandler;
+
+public:
+ ScInputHdlState( const ScAddress& rCurPos,
+ const ScAddress& rStartPos,
+ const ScAddress& rEndPos,
+ const OUString& rString,
+ const EditTextObject* pData );
+ ScInputHdlState( const ScInputHdlState& rCpy );
+ ~ScInputHdlState();
+
+ ScInputHdlState& operator= ( const ScInputHdlState& r );
+ bool operator==( const ScInputHdlState& r ) const;
+
+ const ScAddress& GetPos() const { return aCursorPos; }
+ const ScAddress& GetStartPos() const { return aStartPos; }
+ const ScAddress& GetEndPos() const { return aEndPos; }
+ const OUString& GetString() const { return aString; }
+ const EditTextObject* GetEditData() const { return pEditData.get(); }
+
+private:
+ ScAddress aCursorPos;
+ ScAddress aStartPos;
+ ScAddress aEndPos;
+ OUString aString;
+ std::unique_ptr<EditTextObject> pEditData;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/inputwin.hxx b/sc/source/ui/inc/inputwin.hxx
new file mode 100644
index 000000000..e3676b6e8
--- /dev/null
+++ b/sc/source/ui/inc/inputwin.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <vector>
+#include <memory>
+#include <vcl/customweld.hxx>
+#include <vcl/toolbox.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <sfx2/childwin.hxx>
+#include <svl/lstner.hxx>
+#include <svtools/stringtransfer.hxx>
+#include <vcl/window.hxx>
+#include <formula/opcode.hxx>
+#include <svx/weldeditview.hxx>
+
+namespace com::sun::star::accessibility { class XAccessible; }
+
+class EditView;
+class ScAccessibleEditLineTextData;
+class ScAccessibleEditObject;
+class ScEditEngineDefaulter;
+class ScTextWndGroup;
+class ScInputBarGroup;
+class ScInputHandler;
+class ScTabViewShell;
+struct EENotify;
+
+class ScTextWndBase
+{
+public:
+ virtual void InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData ) = 0;
+ virtual void RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData ) = 0;
+ virtual void SetTextString( const OUString& rString ) = 0;
+ virtual const OUString& GetTextString() const = 0;
+ virtual void StartEditEngine() = 0;
+ virtual void StopEditEngine( bool bAll ) = 0;
+ virtual EditView* GetEditView() const = 0;
+ virtual bool HasEditView() const = 0;
+ virtual void MakeDialogEditView() = 0;
+ virtual void SetFormulaMode( bool bSet ) = 0;
+ virtual bool IsInputActive() = 0;
+ virtual void TextGrabFocus() = 0;
+ virtual tools::Long GetNumLines() const = 0;
+ virtual ~ScTextWndBase() {}
+};
+
+class ScTextWnd : public WeldEditView
+ , public ScTextWndBase
+{
+public:
+ ScTextWnd(ScTextWndGroup& rParent, ScTabViewShell* pViewSh);
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ virtual ~ScTextWnd() override;
+
+ virtual void SetTextString( const OUString& rString ) override;
+ virtual const OUString& GetTextString() const override;
+
+ bool IsInputActive() override;
+ virtual EditView* GetEditView() const override;
+ virtual bool HasEditView() const override;
+
+ const OutputDevice& GetEditViewDevice() const;
+
+ // for function autopilots
+ virtual void MakeDialogEditView() override;
+
+ virtual void StartEditEngine() override;
+ virtual void StopEditEngine( bool bAll ) override;
+
+ virtual void TextGrabFocus() override;
+
+ virtual void StyleUpdated() override;
+
+ // Triggered if scroll bar state should change
+ virtual void EditViewScrollStateChange() override;
+
+ virtual void SetFormulaMode( bool bSet ) override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override;
+
+ virtual void InsertAccessibleTextData( ScAccessibleEditLineTextData& rTextData ) override;
+ virtual void RemoveAccessibleTextData( ScAccessibleEditLineTextData& rTextData ) override;
+
+ virtual void Resize() override;
+
+ int GetPixelHeightForLines(tools::Long nLines);
+ int GetEditEngTxtHeight() const;
+
+ virtual tools::Long GetNumLines() const override;
+ void SetNumLines(tools::Long nLines);
+ tools::Long GetLastNumExpandedLines() const { return mnLastExpandedLines; }
+ void SetLastNumExpandedLines(tools::Long nLastExpandedLines) { mnLastExpandedLines = nLastExpandedLines; }
+
+ void DoScroll();
+
+ DECL_LINK(ModifyHdl, LinkParamNone*, void);
+ DECL_LINK(EditStatusHdl, EditStatus&, void);
+
+protected:
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+
+ virtual bool MouseMove( const MouseEvent& rMEvt ) override;
+ virtual bool MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual bool MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual bool Command( const CommandEvent& rCEvt ) override;
+ virtual bool KeyInput(const KeyEvent& rKEvt) override;
+ virtual bool CanFocus() const override;
+ virtual void GetFocus() override;
+
+ virtual bool StartDrag() override;
+
+private:
+ void ImplInitSettings();
+ void UpdateAutoCorrFlag();
+
+ void SetScrollBarRange();
+
+ void InitEditEngine();
+
+ rtl::Reference<svt::OStringTransferable> m_xHelper;
+
+ typedef ::std::vector< ScAccessibleEditLineTextData* > AccTextDataVector;
+
+ rtl::Reference<ScAccessibleEditObject> pAcc;
+
+ OUString aString;
+ vcl::Font aTextFont;
+ AccTextDataVector maAccTextDatas; // #i105267# text data may be cloned, remember all copies
+ bool bIsRTL;
+ bool bIsInsertMode;
+ bool bFormulaMode;
+
+ // #102710#; this flag should be true if a key input or a command is handled
+ // it prevents the call of InputChanged in the ModifyHandler of the EditEngine
+ bool bInputMode;
+
+ ScTabViewShell* mpViewShell;
+ ScTextWndGroup& mrGroupBar;
+ tools::Long mnLastExpandedLines;
+ bool mbInvalidate;
+};
+
+class ScPosWnd final : public InterimItemWindow, public SfxListener // Display position
+{
+private:
+ std::unique_ptr<weld::ComboBox> m_xWidget;
+
+ ImplSVEvent* m_nAsyncGetFocusId;
+
+ OUString aPosStr;
+ void* nTipVisible;
+ bool bFormulaMode;
+
+public:
+ ScPosWnd( vcl::Window* pParent );
+ virtual ~ScPosWnd() override;
+ virtual void dispose() override;
+
+ void SetPos( const OUString& rPosStr ); // Displayed Text
+ void SetFormulaMode( bool bSet );
+
+ static OUString createLocalRangeName(std::u16string_view rName, std::u16string_view rTableName);
+
+private:
+ DECL_LINK(OnAsyncGetFocus, void*, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
+ DECL_LINK(ModifyHdl, weld::ComboBox&, void);
+ DECL_LINK(FocusInHdl, weld::Widget&, void);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+private:
+ void FillRangeNames();
+ void FillFunctions();
+ void DoEnter();
+ void HideTip();
+
+ void ReleaseFocus_Impl();
+};
+
+class ScTextWndGroup : public ScTextWndBase
+{
+public:
+ ScTextWndGroup(ScInputBarGroup& pParent, ScTabViewShell* pViewSh);
+ virtual ~ScTextWndGroup() override;
+
+ virtual void InsertAccessibleTextData(ScAccessibleEditLineTextData& rTextData) override;
+ virtual EditView* GetEditView() const override;
+ const OutputDevice& GetEditViewDevice() const;
+ Point GetCursorScreenPixelPos(bool bBelowLine);
+ tools::Long GetLastNumExpandedLines() const;
+ void SetLastNumExpandedLines(tools::Long nLastExpandedLines);
+ virtual tools::Long GetNumLines() const override;
+ int GetPixelHeightForLines(tools::Long nLines);
+ weld::ScrolledWindow& GetScrollWin();
+ virtual const OUString& GetTextString() const override;
+ virtual bool HasEditView() const override;
+ virtual bool IsInputActive() override;
+ virtual void MakeDialogEditView() override;
+ virtual void RemoveAccessibleTextData(ScAccessibleEditLineTextData& rTextData) override;
+ void SetScrollPolicy();
+ void SetNumLines(tools::Long nLines);
+ virtual void SetFormulaMode(bool bSet) override;
+ virtual void SetTextString(const OUString& rString) override;
+ virtual void StartEditEngine() override;
+ virtual void StopEditEngine(bool bAll) override;
+ virtual void TextGrabFocus() override;
+
+ vcl::Window& GetVclParent() { return mrParent; }
+
+private:
+ std::unique_ptr<ScTextWnd> mxTextWnd;
+ std::unique_ptr<weld::ScrolledWindow> mxScrollWin;
+ std::unique_ptr<weld::CustomWeld> mxTextWndWin;
+ vcl::Window& mrParent;
+
+ DECL_LINK(Impl_ScrollHdl, weld::ScrolledWindow&, void);
+};
+
+class ScInputBarGroup : public InterimItemWindow
+ , public ScTextWndBase
+{
+public:
+ ScInputBarGroup(vcl::Window* Parent, ScTabViewShell* pViewSh);
+ virtual ~ScInputBarGroup() override;
+ virtual void dispose() override;
+ virtual void InsertAccessibleTextData(ScAccessibleEditLineTextData& rTextData) override;
+ virtual void RemoveAccessibleTextData(ScAccessibleEditLineTextData& rTextData) override;
+ void SetTextString(const OUString& rString) override;
+ void StartEditEngine() override;
+ virtual EditView* GetEditView() const override;
+ virtual bool HasEditView() const override;
+ Point GetCursorScreenPixelPos(bool bBelowLine);
+ virtual void Resize() override;
+ virtual const OUString& GetTextString() const override;
+ virtual void StopEditEngine(bool bAll) override;
+ virtual void TextGrabFocus() override;
+ void SetFormulaMode(bool bSet) override;
+ void MakeDialogEditView() override;
+ bool IsInputActive() override;
+ void IncrementVerticalSize();
+ void DecrementVerticalSize();
+ void NumLinesChanged();
+ virtual tools::Long GetNumLines() const override { return mxTextWndGroup->GetNumLines(); }
+
+ int GetPixelHeightForLines(tools::Long nLines) const
+ {
+ return mxTextWndGroup->GetPixelHeightForLines(nLines);
+ }
+
+ weld::Builder& GetBuilder() { return *m_xBuilder; }
+
+private:
+ void TriggerToolboxLayout();
+
+ std::unique_ptr<weld::Container> mxBackground;
+ std::unique_ptr<ScTextWndGroup> mxTextWndGroup;
+ std::unique_ptr<weld::Button> mxButtonUp;
+ std::unique_ptr<weld::Button> mxButtonDown;
+
+ DECL_LINK(ClickHdl, weld::Button&, void);
+};
+
+class ScInputWindow final : public ToolBox // Parent toolbox
+{
+public:
+ ScInputWindow( vcl::Window* pParent, const SfxBindings* pBind );
+ virtual ~ScInputWindow() override;
+ virtual void dispose() override;
+
+ virtual void PixelInvalidate(const tools::Rectangle* pRectangle) override;
+ virtual void SetSizePixel( const Size& rNewSize ) override;
+ virtual void Resize() override;
+ virtual void Select() override;
+
+ void SetFuncString( const OUString& rString, bool bDoEdit = true );
+ void SetPosString( const OUString& rStr );
+ void SetTextString( const OUString& rString );
+
+ void SetOkCancelMode();
+ void SetSumAssignMode();
+ void EnableButtons( bool bEnable );
+ /// Update Input bar after the number of lines was changed externally
+ void NumLinesChanged();
+
+ void StartFormula();
+ void SetFormulaMode( bool bSet );
+
+ bool IsInputActive();
+ EditView* GetEditView();
+ vcl::Window* GetEditWindow();
+ Point GetCursorScreenPixelPos(bool bBelowLine = false);
+
+ void TextGrabFocus();
+ void TextInvalidate();
+ void SwitchToTextWin();
+
+ void PosGrabFocus();
+
+ // For function autopilots
+ void MakeDialogEditView();
+
+ void StopEditEngine( bool bAll );
+
+ void SetInputHandler( ScInputHandler* pNew );
+
+ ScInputHandler* GetInputHandler(){ return pInputHdl;}
+
+ void StateChanged( StateChangedType nType ) override;
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+
+ void NotifyLOKClient();
+
+ void MenuHdl(std::string_view command);
+ DECL_LINK( DropdownClickHdl, ToolBox*, void );
+
+ void AutoSum( bool& bRangeFinder, bool& bSubTotal, OpCode eCode );
+
+private:
+ bool IsPointerAtResizePos();
+
+ VclPtr<ScPosWnd> aWndPos;
+ VclPtr<ScInputBarGroup> mxTextWindow;
+ ScInputHandler* pInputHdl;
+ ScTabViewShell* mpViewShell;
+ tools::Long mnMaxY;
+ tools::Long mnStandardItemHeight;
+ bool bIsOkCancelMode;
+ bool bInResize;
+};
+
+class ScInputWindowWrapper : public SfxChildWindow
+{
+public:
+ ScInputWindowWrapper( vcl::Window* pParent,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo );
+
+ SFX_DECL_CHILDWINDOW_WITHID(ScInputWindowWrapper);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/inscldlg.hxx b/sc/source/ui/inc/inscldlg.hxx
new file mode 100644
index 000000000..d159c65cd
--- /dev/null
+++ b/sc/source/ui/inc/inscldlg.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+
+#include <global.hxx>
+
+class ScInsertCellDlg : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::RadioButton> m_xBtnCellsDown;
+ std::unique_ptr<weld::RadioButton> m_xBtnCellsRight;
+ std::unique_ptr<weld::RadioButton> m_xBtnInsRow;
+ std::unique_ptr<weld::RadioButton> m_xBtnInsCol;
+ std::unique_ptr<weld::Label> m_xLbCellsRight;
+
+public:
+ ScInsertCellDlg(weld::Window* pParent, bool bDisallowCellMove);
+ virtual ~ScInsertCellDlg() override;
+
+ InsCellCmd GetInsCellCmd() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/inscodlg.hxx b/sc/source/ui/inc/inscodlg.hxx
new file mode 100644
index 000000000..a30cffe0b
--- /dev/null
+++ b/sc/source/ui/inc/inscodlg.hxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <global.hxx>
+
+#include "scui_def.hxx"
+
+class ScInsertContentsDlg : public weld::GenericDialogController
+{
+public:
+ ScInsertContentsDlg( weld::Window* pParent,
+ const OUString* pStrTitle );
+ virtual ~ScInsertContentsDlg() override;
+
+ InsertDeleteFlags GetInsContentsCmdBits() const;
+ ScPasteFunc GetFormulaCmdBits() const;
+
+ bool IsSkipEmptyCells() const;
+ bool IsTranspose() const;
+ bool IsLink() const;
+ InsCellCmd GetMoveMode() const;
+
+ void SetOtherDoc( bool bSet );
+ void SetFillMode( bool bSet );
+ void SetChangeTrack( bool bSet );
+ void SetCellShiftDisabled( CellShiftDisabledFlags nDisable );
+
+private:
+ bool bOtherDoc;
+ bool bFillMode;
+ bool bChangeTrack;
+ bool bMoveDownDisabled;
+ bool bMoveRightDisabled;
+ void SetInsContentsCmdBits(const InsertDeleteFlags eFlags);
+ void SetFormulaCmdBits(const ScPasteFunc eFlags);
+ void SetCellCmdFlags(const InsCellCmd eFlags);
+ void SetContentsFlags(const InsertContentsFlags eFlags);
+
+ std::unique_ptr<weld::CheckButton> mxBtnInsAll;
+ std::unique_ptr<weld::CheckButton> mxBtnInsStrings;
+ std::unique_ptr<weld::CheckButton> mxBtnInsNumbers;
+ std::unique_ptr<weld::CheckButton> mxBtnInsDateTime;
+ std::unique_ptr<weld::CheckButton> mxBtnInsFormulas;
+ std::unique_ptr<weld::CheckButton> mxBtnInsNotes;
+ std::unique_ptr<weld::CheckButton> mxBtnInsAttrs;
+ std::unique_ptr<weld::CheckButton> mxBtnInsObjects;
+
+ std::unique_ptr<weld::CheckButton> mxBtnSkipEmptyCells;
+ std::unique_ptr<weld::CheckButton> mxBtnTranspose;
+ std::unique_ptr<weld::CheckButton> mxBtnLink;
+
+ std::unique_ptr<weld::RadioButton> mxRbNoOp;
+ std::unique_ptr<weld::RadioButton> mxRbAdd;
+ std::unique_ptr<weld::RadioButton> mxRbSub;
+ std::unique_ptr<weld::RadioButton> mxRbMul;
+ std::unique_ptr<weld::RadioButton> mxRbDiv;
+
+ std::unique_ptr<weld::RadioButton> mxRbMoveNone;
+ std::unique_ptr<weld::RadioButton> mxRbMoveDown;
+ std::unique_ptr<weld::RadioButton> mxRbMoveRight;
+
+ std::unique_ptr<weld::Button> mxBtnShortCutPasteValuesOnly;
+ std::unique_ptr<weld::Button> mxBtnShortCutPasteValuesFormats;
+ std::unique_ptr<weld::Button> mxBtnShortCutPasteTranspose;
+ std::unique_ptr<weld::Button> mxBtnShortCutPasteFormats;
+
+ std::unique_ptr<weld::CheckButton> mxImmediately;
+
+ static InsertDeleteFlags nPreviousChecks;
+ static InsertContentsFlags nPreviousChecks2;
+ static ScPasteFunc nPreviousFormulaChecks;
+ static InsCellCmd nPreviousMoveMode;
+
+ void DisableChecks( bool bInsAllChecked );
+ void TestModes();
+
+ // Handler
+ DECL_LINK( InsAllHdl, weld::Toggleable&, void );
+ DECL_LINK( LinkBtnHdl, weld::Toggleable&, void );
+ DECL_LINK( ShortCutHdl, weld::Button&, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/instbdlg.hxx b/sc/source/ui/inc/instbdlg.hxx
new file mode 100644
index 000000000..618177fe0
--- /dev/null
+++ b/sc/source/ui/inc/instbdlg.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/objsh.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/weld.hxx>
+#include <types.hxx>
+
+class ScViewData;
+class ScDocument;
+class ScDocShell;
+
+namespace sfx2 { class DocumentInserter; }
+namespace sfx2 { class FileDialogHelper; }
+
+class ScInsertTableDlg : public weld::GenericDialogController
+{
+public:
+ ScInsertTableDlg(weld::Window* pParent, ScViewData& rViewData, SCTAB nTabCount, bool bFromFile);
+ virtual ~ScInsertTableDlg() override;
+
+ virtual short run() override; // override to set parent dialog
+
+ bool GetTablesFromFile() const { return m_xBtnFromFile->get_active(); }
+ bool GetTablesAsLink() const { return m_xBtnLink->get_active(); }
+
+ const OUString* GetFirstTable( sal_uInt16* pN );
+ const OUString* GetNextTable( sal_uInt16* pN );
+ ScDocShell* GetDocShellTables() { return pDocShTables; }
+ bool IsTableBefore() const { return m_xBtnBefore->get_active(); }
+ SCTAB GetTableCount() const { return nTableCount;}
+
+private:
+ Timer aBrowseTimer;
+ ScViewData& rViewData;
+ ScDocument& rDoc;
+ ScDocShell* pDocShTables;
+ std::unique_ptr<sfx2::DocumentInserter> pDocInserter;
+ SfxObjectShellRef aDocShTablesRef;
+
+ bool bMustClose;
+ sal_uInt16 nSelTabIndex; // for GetFirstTable() / GetNextTable()
+ OUString aStrCurSelTable;
+ SCTAB nTableCount;
+ OUString m_sSheetDotDotDot;
+
+ std::unique_ptr<weld::RadioButton> m_xBtnBefore;
+ std::unique_ptr<weld::RadioButton> m_xBtnBehind;
+ std::unique_ptr<weld::RadioButton> m_xBtnNew;
+ std::unique_ptr<weld::RadioButton> m_xBtnFromFile;
+ std::unique_ptr<weld::Label> m_xFtCount;
+ std::unique_ptr<weld::SpinButton> m_xNfCount;
+ std::unique_ptr<weld::Label> m_xFtName;
+ std::unique_ptr<weld::Entry> m_xEdName;
+ std::unique_ptr<weld::TreeView> m_xLbTables;
+ std::unique_ptr<weld::Label> m_xFtPath;
+ std::unique_ptr<weld::Button> m_xBtnBrowse;
+ std::unique_ptr<weld::CheckButton> m_xBtnLink;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+
+ void Init_Impl( bool bFromFile );
+ void SetNewTable_Impl();
+ void SetFromTo_Impl();
+ void FillTables_Impl( const ScDocument* pSrcDoc );
+ void DoEnable_Impl();
+
+ DECL_LINK( BrowseHdl_Impl, weld::Button&, void );
+ DECL_LINK( ChoiceHdl_Impl, weld::Toggleable&, void );
+ DECL_LINK( SelectHdl_Impl, weld::TreeView&, void );
+ DECL_LINK( CountHdl_Impl, weld::SpinButton&, void );
+ DECL_LINK( DoEnterHdl, weld::Button&, void );
+ DECL_LINK( BrowseTimeoutHdl, Timer *, void );
+ DECL_LINK( DialogClosedHdl, sfx2::FileDialogHelper*, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/invmerge.hxx b/sc/source/ui/inc/invmerge.hxx
new file mode 100644
index 000000000..54dd8c160
--- /dev/null
+++ b/sc/source/ui/inc/invmerge.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 <tools/gen.hxx>
+
+#include <vector>
+
+class ScInvertMerger
+{
+private:
+ ::std::vector< tools::Rectangle >* pRects;
+ tools::Rectangle aTotalRect;
+ tools::Rectangle aLineRect;
+
+ void FlushLine();
+ void FlushTotal();
+
+public:
+ ScInvertMerger( ::std::vector< tools::Rectangle >* pRectangles );
+ ~ScInvertMerger();
+
+ void AddRect( const tools::Rectangle& rRect );
+ void Flush();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/lbseldlg.hxx b/sc/source/ui/inc/lbseldlg.hxx
new file mode 100644
index 000000000..cf313c06b
--- /dev/null
+++ b/sc/source/ui/inc/lbseldlg.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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in 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 ScSelEntryDlg : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::TreeView> m_xLb;
+
+ DECL_LINK(DblClkHdl, weld::TreeView&, bool);
+
+public:
+ ScSelEntryDlg(weld::Window* pParent, const std::vector<OUString>& rEntryList);
+ virtual ~ScSelEntryDlg() override;
+
+ OUString GetSelectedEntry() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/linkarea.hxx b/sc/source/ui/inc/linkarea.hxx
new file mode 100644
index 000000000..a209d3b8a
--- /dev/null
+++ b/sc/source/ui/inc/linkarea.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 <sfx2/objsh.hxx>
+#include <vcl/weld.hxx>
+
+namespace sfx2 { class DocumentInserter; }
+namespace sfx2 { class FileDialogHelper; }
+
+class ScDocShell;
+class SvtURLBox;
+
+class ScLinkedAreaDlg : public weld::GenericDialogController
+{
+private:
+ ScDocShell* m_pSourceShell;
+ std::unique_ptr<sfx2::DocumentInserter> m_xDocInserter;
+ SfxObjectShellRef aSourceRef;
+
+ std::unique_ptr<SvtURLBox> m_xCbUrl;
+ std::unique_ptr<weld::Button> m_xBtnBrowse;
+ std::unique_ptr<weld::TreeView> m_xLbRanges;
+ std::unique_ptr<weld::CheckButton> m_xBtnReload;
+ std::unique_ptr<weld::SpinButton> m_xNfDelay;
+ std::unique_ptr<weld::Label> m_xFtSeconds;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+
+ DECL_LINK(FileHdl, weld::ComboBox&, bool);
+ DECL_LINK(BrowseHdl, weld::Button&, void);
+ DECL_LINK(RangeHdl, weld::TreeView&, void);
+ DECL_LINK(ReloadHdl, weld::Toggleable&, void);
+ DECL_LINK(DialogClosedHdl, sfx2::FileDialogHelper*, void);
+
+ void UpdateSourceRanges();
+ void UpdateEnable();
+ void LoadDocument( const OUString& rFile, const OUString& rFilter,
+ const OUString& rOptions );
+
+public:
+ ScLinkedAreaDlg(weld::Widget* pParent);
+ virtual ~ScLinkedAreaDlg() override;
+
+ void InitFromOldLink( const OUString& rFile, const OUString& rFilter,
+ const OUString& rOptions, std::u16string_view rSource,
+ sal_Int32 nRefreshDelaySeconds );
+
+ OUString GetURL() const;
+ OUString GetFilter() const; // may be empty
+ OUString GetOptions() const; // filter options
+ OUString GetSource() const; // separated by ";"
+ sal_Int32 GetRefreshDelaySeconds() const; // 0 if disabled
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/lnktrans.hxx b/sc/source/ui/inc/lnktrans.hxx
new file mode 100644
index 000000000..2ef546907
--- /dev/null
+++ b/sc/source/ui/inc/lnktrans.hxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/transfer.hxx>
+#include <rtl/ustring.hxx>
+
+class ScLinkTransferObj : public TransferDataContainer
+{
+private:
+ OUString aLinkURL;
+ OUString aLinkText;
+
+public:
+ ScLinkTransferObj();
+ virtual ~ScLinkTransferObj() override;
+
+ void SetLinkURL( const OUString& rURL, const OUString& rText );
+
+ virtual void AddSupportedFormats() override;
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+ virtual void DragFinished( sal_Int8 nDropAction ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/mediash.hxx b/sc/source/ui/inc/mediash.hxx
new file mode 100644
index 000000000..471902b28
--- /dev/null
+++ b/sc/source/ui/inc/mediash.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 <shellids.hxx>
+#include "drawsh.hxx"
+
+class ScViewData;
+class SfxModule;
+
+class ScMediaShell final : public ScDrawShell
+{
+public:
+ SFX_DECL_INTERFACE(SCID_MEDIA_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScMediaShell(ScViewData& rData);
+ virtual ~ScMediaShell() override;
+
+ void ExecuteMedia(const SfxRequest& rReq);
+ void GetMediaState(SfxItemSet& rSet);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/mergecellsdialog.hxx b/sc/source/ui/inc/mergecellsdialog.hxx
new file mode 100644
index 000000000..33370d793
--- /dev/null
+++ b/sc/source/ui/inc/mergecellsdialog.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/.
+ *
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+
+enum ScMergeCellsOption
+{
+ MoveContentHiddenCells,
+ KeepContentHiddenCells,
+ EmptyContentHiddenCells
+};
+
+class ScMergeCellsDialog : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::RadioButton> m_xRBMoveContent;
+ std::unique_ptr<weld::RadioButton> m_xRBKeepContent;
+ std::unique_ptr<weld::RadioButton> m_xRBEmptyContent;
+
+public:
+ ScMergeCellsDialog(weld::Window* pParent);
+ virtual ~ScMergeCellsDialog() override;
+
+ ScMergeCellsOption GetMergeCellsOption() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/msgpool.hxx b/sc/source/ui/inc/msgpool.hxx
new file mode 100644
index 000000000..926fb38bf
--- /dev/null
+++ b/sc/source/ui/inc/msgpool.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/srchitem.hxx>
+
+#include <svl/itempool.hxx>
+#include <svl/stritem.hxx>
+
+#include "uiitems.hxx"
+#include "condformatdlgitem.hxx"
+
+class ScDocumentPool;
+
+class ScMessagePool final : public SfxItemPool
+{
+ SfxStringItem aGlobalStringItem;
+ SvxSearchItem aGlobalSearchItem;
+ ScSortItem aGlobalSortItem;
+ ScQueryItem aGlobalQueryItem;
+ ScSubTotalItem aGlobalSubTotalItem;
+ ScConsolidateItem aGlobalConsolidateItem;
+ ScPivotItem aGlobalPivotItem;
+ ScSolveItem aGlobalSolveItem;
+ ScUserListItem aGlobalUserListItem;
+ ScCondFormatDlgItem aCondFormatDlgItem;
+
+ std::vector<SfxPoolItem*> mvPoolDefaults;
+ rtl::Reference<ScDocumentPool> pDocPool;
+
+public:
+ ScMessagePool();
+private:
+ virtual ~ScMessagePool() override;
+public:
+
+ virtual MapUnit GetMetric( sal_uInt16 nWhich ) const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/mtrindlg.hxx b/sc/source/ui/inc/mtrindlg.hxx
new file mode 100644
index 000000000..fc4163a55
--- /dev/null
+++ b/sc/source/ui/inc/mtrindlg.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 ScMetricInputDlg : public weld::GenericDialogController
+{
+public:
+ ScMetricInputDlg( weld::Window* pParent,
+ const OString& sDialogName,
+ tools::Long nCurrent,
+ tools::Long nDefault,
+ FieldUnit eFUnit,
+ sal_uInt16 nDecimals,
+ tools::Long nMaximum,
+ tools::Long nMinimum);
+ virtual ~ScMetricInputDlg() override;
+
+ int GetInputValue() const;
+
+private:
+ std::unique_ptr<weld::MetricSpinButton> m_xEdValue;
+ std::unique_ptr<weld::CheckButton> m_xBtnDefVal;
+ int nDefaultValue;
+ int nCurrentValue;
+
+ DECL_LINK(SetDefValHdl, weld::Toggleable&, void);
+ DECL_LINK(ModifyHdl, weld::MetricSpinButton&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/mvtabdlg.hxx b/sc/source/ui/inc/mvtabdlg.hxx
new file mode 100644
index 000000000..9d121a928
--- /dev/null
+++ b/sc/source/ui/inc/mvtabdlg.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 <types.hxx>
+#include <vcl/weld.hxx>
+
+class ScDocument;
+
+class ScMoveTableDlg : public weld::GenericDialogController
+{
+public:
+ ScMoveTableDlg(weld::Window* pParent, const OUString& rDefault);
+ virtual ~ScMoveTableDlg() override;
+
+ sal_uInt16 GetSelectedDocument () const { return nDocument; }
+ SCTAB GetSelectedTable () const { return nTable; }
+ bool GetCopyTable () const { return bCopyTable; }
+ bool GetRenameTable () const { return bRenameTable; }
+ void GetTabNameString( OUString& rString ) const;
+ void SetForceCopyTable ();
+ void EnableRenameTable (bool bFlag);
+ void SetOkBtnLabel ();
+
+private:
+ void ResetRenameInput();
+ void CheckNewTabName();
+ ScDocument* GetSelectedDoc();
+
+private:
+ OUString msCurrentDoc;
+ OUString msNewDoc;
+
+ OUString msStrTabNameUsed;
+ OUString msStrTabNameEmpty;
+ OUString msStrTabNameInvalid;
+
+ const OUString maDefaultName;
+
+ sal_uInt16 mnCurrentDocPos;
+ sal_uInt16 nDocument;
+ SCTAB nTable;
+ bool bCopyTable:1;
+ bool bRenameTable:1;
+ bool mbEverEdited:1;
+
+ std::unique_ptr<weld::RadioButton> m_xBtnMove;
+ std::unique_ptr<weld::RadioButton> m_xBtnCopy;
+ std::unique_ptr<weld::Label> m_xFtDoc;
+ std::unique_ptr<weld::ComboBox> m_xLbDoc;
+ std::unique_ptr<weld::TreeView> m_xLbTable;
+ std::unique_ptr<weld::Entry> m_xEdTabName;
+ std::unique_ptr<weld::Label> m_xFtWarn;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Label> m_xUnusedLabel;
+ std::unique_ptr<weld::Label> m_xEmptyLabel;
+ std::unique_ptr<weld::Label> m_xInvalidLabel;
+
+ void Init ();
+ void InitDocListBox ();
+ DECL_LINK(OkHdl, weld::Button&, void);
+ DECL_LINK(SelHdl, weld::ComboBox&, void);
+ DECL_LINK(CheckBtnHdl, weld::Toggleable&, void);
+ DECL_LINK(CheckNameHdl, weld::Entry&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/namecrea.hxx b/sc/source/ui/inc/namecrea.hxx
new file mode 100644
index 000000000..89adb8216
--- /dev/null
+++ b/sc/source/ui/inc/namecrea.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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in 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 "scui_def.hxx"
+
+class ScNameCreateDlg final : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::CheckButton> m_xTopBox;
+ std::unique_ptr<weld::CheckButton> m_xLeftBox;
+ std::unique_ptr<weld::CheckButton> m_xBottomBox;
+ std::unique_ptr<weld::CheckButton> m_xRightBox;
+
+public:
+ ScNameCreateDlg(weld::Window* pParent, CreateNameFlags nFlags);
+ virtual ~ScNameCreateDlg() override;
+ CreateNameFlags GetFlags() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/namedefdlg.hxx b/sc/source/ui/inc/namedefdlg.hxx
new file mode 100644
index 000000000..fe05059e8
--- /dev/null
+++ b/sc/source/ui/inc/namedefdlg.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/.
+ */
+
+#pragma once
+
+#include "anyrefdg.hxx"
+
+#include <map>
+
+class ScRangeName;
+class ScDocument;
+class ScDocShell;
+class ScViewData;
+
+class ScNameDefDlg : public ScAnyRefDlgController
+{
+private:
+ bool mbUndo; //if true we need to add an undo action after creating a range name
+ ScDocument& mrDoc;
+ ScDocShell* mpDocShell;
+
+ ScAddress maCursorPos;
+ OUString maStrInfoDefault;
+ const OUString maGlobalNameStr;
+ const OUString maErrInvalidNameStr;
+ const OUString maErrInvalidNameCellRefStr;
+ const OUString maErrNameInUse;
+
+ //hack to call this dialog from Manage Names
+ OUString maName;
+ OUString maScope;
+
+ std::map<OUString, ScRangeName*> maRangeMap;
+
+ std::unique_ptr<weld::Entry> m_xEdName;
+
+ std::unique_ptr<formula::RefEdit> m_xEdRange;
+ std::unique_ptr<formula::RefButton> m_xRbRange;
+
+ std::unique_ptr<weld::ComboBox> m_xLbScope;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnRowHeader;
+ std::unique_ptr<weld::CheckButton> m_xBtnColHeader;
+ std::unique_ptr<weld::CheckButton> m_xBtnPrintArea;
+ std::unique_ptr<weld::CheckButton> m_xBtnCriteria;
+
+ std::unique_ptr<weld::Button> m_xBtnAdd;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+ std::unique_ptr<weld::Label> m_xFtInfo;
+ std::unique_ptr<weld::Expander> m_xExpander;
+ std::unique_ptr<weld::Label> m_xFtRange;
+
+ void CancelPushed();
+ void AddPushed();
+
+ bool IsNameValid();
+ bool IsFormulaValid();
+
+ DECL_LINK(CancelBtnHdl, weld::Button&, void);
+ DECL_LINK(AddBtnHdl, weld::Button&, void);
+ DECL_LINK(NameModifyHdl, weld::Entry&, void);
+ DECL_LINK(AssignGetFocusHdl, formula::RefEdit&, void);
+
+protected:
+ virtual void RefInputDone(bool bForced = false) override;
+
+public:
+ ScNameDefDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ const ScViewData& rViewData, std::map<OUString, ScRangeName*>&& aRangeMap,
+ const ScAddress& aCursorPos, const bool bUndo);
+
+ virtual ~ScNameDefDlg() override;
+
+ virtual void SetReference(const ScRange& rRef, ScDocument& rDoc) override;
+ virtual bool IsRefInputMode() const override;
+
+ virtual void SetActive() override;
+ virtual void Close() override;
+
+ void GetNewData(OUString& rName, OUString& rScope);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/namedlg.hxx b/sc/source/ui/inc/namedlg.hxx
new file mode 100644
index 000000000..73b8dbcd7
--- /dev/null
+++ b/sc/source/ui/inc/namedlg.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 "anyrefdg.hxx"
+#include "namemgrtable.hxx"
+
+#include <memory>
+#include <map>
+
+class ScViewData;
+class ScDocument;
+
+//logic behind the manage names dialog
+class ScNameDlg : public ScAnyRefDlgController
+{
+private:
+ const OUString maGlobalNameStr;
+ const OUString maErrInvalidNameStr;
+ const OUString maErrNameInUse;
+ const OUString maStrMultiSelect;
+ OUString maStrInfoDefault;
+
+ ScViewData& mrViewData;
+ ScDocument& mrDoc;
+ const ScAddress maCursorPos;
+
+ bool mbDataChanged;
+ //ugly hack to call DefineNames from ManageNames
+ bool mbCloseWithoutUndo;
+
+ typedef std::map<OUString, std::unique_ptr<ScRangeName>> RangeNameContainer;
+
+ RangeNameContainer m_RangeMap;
+
+ std::unique_ptr<weld::Entry> m_xEdName;
+ std::unique_ptr<weld::Label> m_xFtAssign;
+ std::unique_ptr<formula::RefEdit> m_xEdAssign;
+ std::unique_ptr<formula::RefButton> m_xRbAssign;
+ std::unique_ptr<weld::ComboBox> m_xLbScope;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnPrintArea;
+ std::unique_ptr<weld::CheckButton> m_xBtnColHeader;
+ std::unique_ptr<weld::CheckButton> m_xBtnCriteria;
+ std::unique_ptr<weld::CheckButton> m_xBtnRowHeader;
+
+ std::unique_ptr<weld::Button> m_xBtnAdd;
+ std::unique_ptr<weld::Button> m_xBtnDelete;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+ std::unique_ptr<weld::Label> m_xFtInfo;
+
+ std::unique_ptr<weld::Expander> m_xExpander;
+
+ std::unique_ptr<ScRangeManagerTable> m_xRangeManagerTable;
+
+private:
+ void Init();
+ void UpdateChecks(const ScRangeData* pData);
+ void ShowOptions(const ScRangeNameLine& rLine);
+
+ bool IsNameValid();
+ bool IsFormulaValid();
+ void CheckForEmptyTable();
+
+ ScRangeName* GetRangeName(const OUString& rScope);
+
+ void AddPushed();
+ void RemovePushed();
+ void ScopeChanged();
+ void NameModified();
+
+ void SelectionChanged();
+
+ // Handler:
+ DECL_LINK(OkBtnHdl, weld::Button&, void);
+ DECL_LINK(CancelBtnHdl, weld::Button&, void);
+ DECL_LINK(AddBtnHdl, weld::Button&, void);
+ DECL_LINK(RemoveBtnHdl, weld::Button&, void);
+ DECL_LINK(EdModifyHdl, weld::Entry&, void);
+ DECL_LINK(RefEdModifyHdl, formula::RefEdit&, void);
+ DECL_LINK(EdModifyCheckBoxHdl, weld::Toggleable&, void);
+ DECL_LINK(AssignGetFocusHdl, formula::RefEdit&, void);
+ DECL_LINK(SelectionChangedHdl_Impl, weld::TreeView&, void);
+ DECL_LINK(ScopeChangedHdl, weld::ComboBox&, void);
+
+protected:
+ virtual void RefInputDone(bool bForced = false) override;
+
+public:
+ ScNameDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, ScViewData& rViewData,
+ const ScAddress& aCursorPos,
+ std::map<OUString, std::unique_ptr<ScRangeName>>* pRangeMap = nullptr);
+ virtual ~ScNameDlg() override;
+
+ virtual void SetReference(const ScRange& rRef, ScDocument& rDoc) override;
+ virtual bool IsRefInputMode() const override;
+
+ virtual void SetActive() override;
+ virtual void Close() override;
+
+ void GetRangeNames(std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap);
+ void SetEntry(const OUString& rName, const OUString& rScope);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/namemgrtable.hxx b/sc/source/ui/inc/namemgrtable.hxx
new file mode 100644
index 000000000..da5b93dfb
--- /dev/null
+++ b/sc/source/ui/inc/namemgrtable.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 <vcl/weld.hxx>
+
+#include <address.hxx>
+
+#include <memory>
+#include <vector>
+#include <map>
+
+class ScRangeName;
+class ScRangeData;
+
+struct ScRangeNameLine
+{
+ OUString aName;
+ OUString aExpression;
+ OUString aScope;
+};
+
+class SC_DLLPUBLIC ScRangeManagerTable
+{
+private:
+ std::unique_ptr<weld::TreeView> m_xTreeView;
+
+ OUString maGlobalString;
+
+ // should be const because we should not modify it here
+ const std::map<OUString, std::unique_ptr<ScRangeName>>& m_RangeMap;
+ // for performance, save which entries already have the formula entry
+ // otherwise opening the dialog with a lot of range names is extremely slow because
+ // we would calculate all formula strings during opening
+ std::map<OUString, bool> maCalculatedFormulaEntries;
+ const ScAddress maPos;
+
+ int m_nId;
+
+ bool mbNeedUpdate;
+
+ void GetLine(ScRangeNameLine& aLine, const weld::TreeIter& rEntry);
+ void Init();
+ const ScRangeData* findRangeData(const ScRangeNameLine& rLine);
+
+ DECL_DLLPRIVATE_LINK(SizeAllocHdl, const Size&, void);
+ DECL_DLLPRIVATE_LINK(VisRowsScrolledHdl, weld::TreeView&, void);
+
+public:
+ ScRangeManagerTable(std::unique_ptr<weld::TreeView>,
+ const std::map<OUString, std::unique_ptr<ScRangeName>>& rTabRangeNames,
+ const ScAddress& rPos);
+
+ void CheckForFormulaString();
+
+ int n_children() const { return m_xTreeView->n_children(); }
+ void connect_changed(const Link<weld::TreeView&, void>& rLink) { m_xTreeView->connect_changed(rLink); }
+ void set_cursor(int nPos) { m_xTreeView->set_cursor(nPos); }
+
+ void addEntry(const ScRangeNameLine& rLine, bool bSetCurEntry);
+ void DeleteSelectedEntries();
+ void SetEntry( const ScRangeNameLine& rLine );
+
+ void GetCurrentLine(ScRangeNameLine& rLine);
+ bool IsMultiSelection() const;
+ std::vector<ScRangeNameLine> GetSelectedEntries();
+
+ void BlockUpdate()
+ {
+ mbNeedUpdate = false;
+ }
+
+ bool UpdatesBlocked() const
+ {
+ return !mbNeedUpdate;
+ }
+
+ void UnblockUpdate()
+ {
+ mbNeedUpdate = true;
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/namepast.hxx b/sc/source/ui/inc/namepast.hxx
new file mode 100644
index 000000000..79947bbcd
--- /dev/null
+++ b/sc/source/ui/inc/namepast.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 <vcl/weld.hxx>
+#include "namemgrtable.hxx"
+#include <memory>
+#include <vector>
+#include <map>
+
+class ScRangeName;
+class ScDocShell;
+
+class ScNamePasteDlg : public weld::GenericDialogController
+{
+ DECL_LINK(ButtonHdl, weld::Button&, void);
+
+private:
+ std::unique_ptr<weld::Button> m_xBtnPasteAll;
+ std::unique_ptr<weld::Button> m_xBtnPaste;
+ std::unique_ptr<weld::Button> m_xBtnClose;
+ std::unique_ptr<ScRangeManagerTable> m_xTable;
+
+ std::vector<OUString> maSelectedNames;
+ std::map<OUString, std::unique_ptr<ScRangeName>> m_RangeMap;
+ OUString m_aSheetSep;
+
+public:
+ ScNamePasteDlg(weld::Window* pParent, ScDocShell* pShell);
+
+ virtual ~ScNamePasteDlg() override;
+
+ const std::vector<OUString>& GetSelectedNames() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/navcitem.hxx b/sc/source/ui/inc/navcitem.hxx
new file mode 100644
index 000000000..17131afba
--- /dev/null
+++ b/sc/source/ui/inc/navcitem.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/ctrlitem.hxx>
+
+class ScNavigatorDlg;
+
+class ScNavigatorControllerItem : public SfxControllerItem
+{
+public:
+ ScNavigatorControllerItem( sal_uInt16 nId,
+ ScNavigatorDlg& rDlg,
+ SfxBindings& rBindings );
+protected:
+ virtual void StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState,
+ const SfxPoolItem* pItem ) override;
+
+private:
+ ScNavigatorDlg& rNavigatorDlg;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/navipi.hxx b/sc/source/ui/inc/navipi.hxx
new file mode 100644
index 000000000..ecfe71cfd
--- /dev/null
+++ b/sc/source/ui/inc/navipi.hxx
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vector>
+#include <vcl/idle.hxx>
+#include <svl/lstner.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/navigat.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include "content.hxx"
+
+class SfxPoolItem;
+class ScTabViewShell;
+class ScViewData;
+class ScArea;
+class ScScenarioWindow;
+class ScNavigatorControllerItem;
+class ScNavigatorDlg;
+class ScNavigatorSettings;
+
+#define SC_DROPMODE_URL 0
+#define SC_DROPMODE_LINK 1
+#define SC_DROPMODE_COPY 2
+
+enum NavListMode { NAV_LMODE_NONE = 0x4000,
+ NAV_LMODE_AREAS = 0x2000,
+ NAV_LMODE_SCENARIOS = 0x400 };
+
+class ScScenarioWindow
+{
+public:
+ ScScenarioWindow(weld::Builder& rBuilder, const OUString& rQH_List, const OUString& rQH_Comment);
+ ~ScScenarioWindow();
+ void NotifyState(const SfxPoolItem* pState);
+ void SetComment(const OUString& rComment)
+ {
+ m_xEdComment->set_text(rComment);
+ }
+
+private:
+ std::unique_ptr<weld::TreeView> m_xLbScenario;
+ std::unique_ptr<weld::TextView> m_xEdComment;
+
+ struct ScenarioEntry
+ {
+ OUString maName;
+ OUString maComment;
+ bool mbProtected;
+
+ explicit ScenarioEntry() : mbProtected( false ) {}
+ };
+
+ std::vector< ScenarioEntry > m_aEntries;
+
+ void UpdateEntries(const std::vector<OUString> &rNewEntryList);
+ void SelectScenario();
+ void ExecuteScenarioSlot(sal_uInt16 nSlotId);
+ void EditScenario();
+ void DeleteScenario();
+ const ScenarioEntry* GetSelectedScenarioEntry() const;
+
+ DECL_LINK(SelectHdl, weld::TreeView&, void);
+ DECL_LINK(DoubleClickHdl, weld::TreeView&, bool);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ContextMenuHdl, const CommandEvent&, bool);
+};
+
+class ScNavigatorDlg : public PanelLayout, public SfxListener
+{
+friend class ScNavigatorWin;
+friend class ScNavigatorControllerItem;
+friend class ScContentTree;
+
+private:
+ static constexpr int CTRL_ITEMS = 4;
+
+ SfxBindings& rBindings; // must be first member
+
+ std::unique_ptr<weld::SpinButton> m_xEdCol;
+ std::unique_ptr<weld::SpinButton> m_xEdRow;
+ std::unique_ptr<weld::Toolbar> m_xTbxCmd1;
+ std::unique_ptr<weld::Toolbar> m_xTbxCmd2;
+ std::unique_ptr<ScContentTree> m_xLbEntries;
+ std::unique_ptr<weld::Widget> m_xScenarioBox;
+ std::unique_ptr<ScScenarioWindow> m_xWndScenarios;
+ std::unique_ptr<weld::ComboBox> m_xLbDocuments;
+ std::unique_ptr<weld::Menu> m_xDragModeMenu;
+
+ VclPtr<SfxNavigator> m_xNavigatorDlg;
+
+ Size aExpandedSize;
+ Idle aContentIdle;
+
+ OUString aStrActive;
+ OUString aStrNotActive;
+ OUString aStrHidden;
+ OUString aStrActiveWin;
+
+ std::unique_ptr<ScArea> pMarkArea;
+ ScViewData* pViewData;
+
+ NavListMode eListMode;
+ sal_uInt16 nDropMode;
+ SCCOL nCurCol;
+ SCROW nCurRow;
+ SCTAB nCurTab;
+
+ std::array<std::unique_ptr<ScNavigatorControllerItem>,CTRL_ITEMS> mvBoundItems;
+
+ DECL_LINK(TimeHdl, Timer*, void);
+ DECL_LINK(DocumentSelectHdl, weld::ComboBox&, void);
+ DECL_LINK(ExecuteRowHdl, weld::Entry&, bool);
+ DECL_LINK(ExecuteColHdl, weld::Entry&, bool);
+ DECL_LINK(ToolBoxSelectHdl, const OString&, void);
+ DECL_LINK(ToolBoxDropdownClickHdl, const OString&, void);
+ DECL_LINK(MenuSelectHdl, const OString&, void);
+ DECL_LINK(FormatRowOutputHdl, weld::SpinButton&, void);
+ DECL_LINK(ParseRowInputHdl, int*, bool);
+
+ void UpdateButtons();
+ void SetCurrentCell( SCCOL nCol, SCROW Row );
+ void SetCurrentCellStr( const OUString& rName );
+ void SetCurrentTable( SCTAB nTab );
+ void SetCurrentTableStr( std::u16string_view rName );
+ void SetCurrentObject( const OUString& rName );
+ void SetCurrentDoc( const OUString& rDocName );
+ void UpdateSelection();
+ void ContentUpdated(); // stop aContentIdle because content is up to date
+
+ static ScTabViewShell* GetTabViewShell();
+ static ScNavigatorSettings* GetNavigatorSettings();
+ ScViewData* GetViewData();
+
+ void UpdateSheetLimits();
+
+ void UpdateColumn ( const SCCOL* pCol = nullptr );
+ void UpdateRow ( const SCROW* pRow = nullptr );
+ void UpdateTable ( const SCTAB* pTab );
+ void UpdateAll ();
+
+ void GetDocNames(const OUString* pSelEntry);
+
+ void SetListMode(NavListMode eMode);
+ void ShowList(bool bShow);
+ void ShowScenarios();
+
+ void SetDropMode(sal_uInt16 nNew);
+ sal_uInt16 GetDropMode() const { return nDropMode; }
+
+ void MarkDataArea ();
+ void UnmarkDataArea ();
+ void StartOfDataArea ();
+ void EndOfDataArea ();
+
+ void UpdateInitShow();
+
+ static void ReleaseFocus();
+
+public:
+ ScNavigatorDlg(SfxBindings* pB, weld::Widget* pParent, SfxNavigator* pNavigatorDlg);
+ virtual weld::Window* GetFrameWeld() const override;
+ virtual ~ScNavigatorDlg() override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+};
+
+class ScNavigatorWrapper final : public SfxNavigatorWrapper
+{
+public:
+ ScNavigatorWrapper(vcl::Window *pParent, sal_uInt16 nId,
+ SfxBindings* pBindings, SfxChildWinInfo* pInfo);
+ SFX_DECL_CHILDWINDOW(ScNavigatorWrapper);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/navsett.hxx b/sc/source/ui/inc/navsett.hxx
new file mode 100644
index 000000000..c77bf259f
--- /dev/null
+++ b/sc/source/ui/inc/navsett.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 <tools/solar.h>
+
+#include <o3tl/enumarray.hxx>
+#include "content.hxx"
+
+/** Contains settings of the navigator listbox. This includes the expand state
+ of each listbox entry and the index of the selected entry and sub entry. */
+class ScNavigatorSettings
+{
+private:
+ o3tl::enumarray<ScContentId,bool> maExpandedVec; /// Array of Booleans for expand state.
+ ScContentId mnRootSelected; /// Index of selected root entry.
+ sal_uLong mnChildSelected; /// Index of selected child entry.
+
+public:
+ ScNavigatorSettings();
+
+ void SetExpanded( ScContentId nIndex, bool bExpand ) { maExpandedVec[ nIndex ] = bExpand; }
+ bool IsExpanded( ScContentId nIndex ) const { return maExpandedVec[ nIndex ]; }
+
+ void SetRootSelected( ScContentId nIndex ) { mnRootSelected = nIndex; }
+ ScContentId GetRootSelected() const { return mnRootSelected; }
+
+ void SetChildSelected( sal_uLong nIndex ) { mnChildSelected = nIndex; }
+ sal_uLong GetChildSelected() const { return mnChildSelected; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/notemark.hxx b/sc/source/ui/inc/notemark.hxx
new file mode 100644
index 000000000..1ed812d0f
--- /dev/null
+++ b/sc/source/ui/inc/notemark.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 <vcl/mapmod.hxx>
+#include <vcl/timer.hxx>
+#include <vcl/vclptr.hxx>
+#include <tools/gen.hxx>
+#include <address.hxx>
+#include <postit.hxx>
+
+namespace vcl { class Window; }
+
+class SdrModel;
+class SdrCaptionObj;
+
+class ScNoteMarker
+{
+private:
+ VclPtr<vcl::Window> m_pWindow;
+ VclPtr<vcl::Window> m_pRightWin;
+ VclPtr<vcl::Window> m_pBottomWin;
+ VclPtr<vcl::Window> m_pDiagWin;
+ ScDocument* m_pDoc;
+ ScAddress m_aDocPos;
+ OUString m_aUserText;
+ tools::Rectangle m_aVisRect;
+ Timer m_aTimer;
+ MapMode m_aMapMode;
+ bool m_bLeft;
+ bool m_bByKeyboard;
+
+ tools::Rectangle m_aRect;
+ std::unique_ptr<SdrModel> m_pModel;
+ ScCaptionPtr m_xObject;
+ bool m_bVisible;
+ DECL_LINK( TimeHdl, Timer*, void );
+
+public:
+ ScNoteMarker( vcl::Window* pWin, vcl::Window* pRight, vcl::Window* pBottom, vcl::Window* pDiagonal,
+ ScDocument* pD, const ScAddress& aPos, const OUString& rUser,
+ const MapMode& rMap, bool bLeftEdge, bool bForce, bool bKeyboard);
+ ~ScNoteMarker();
+
+ void Draw();
+ void InvalidateWin();
+
+ const ScAddress& GetDocPos() const { return m_aDocPos; }
+ bool IsByKeyboard() const { return m_bByKeyboard; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/oleobjsh.hxx b/sc/source/ui/inc/oleobjsh.hxx
new file mode 100644
index 000000000..88be75adc
--- /dev/null
+++ b/sc/source/ui/inc/oleobjsh.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 <sfx2/shell.hxx>
+#include <shellids.hxx>
+#include "drawsh.hxx"
+
+class ScViewData;
+class SfxModule;
+
+class ScOleObjectShell final : public ScDrawShell
+{
+public:
+ SFX_DECL_INTERFACE(SCID_OLEOBJECT_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScOleObjectShell(ScViewData& rData);
+ virtual ~ScOleObjectShell() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/olinefun.hxx b/sc/source/ui/inc/olinefun.hxx
new file mode 100644
index 000000000..ec167a8e4
--- /dev/null
+++ b/sc/source/ui/inc/olinefun.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 <types.hxx>
+
+class ScDocShell;
+class ScRange;
+
+class ScOutlineDocFunc
+{
+private:
+ ScDocShell& rDocShell;
+
+public:
+ ScOutlineDocFunc( ScDocShell& rDocSh ): rDocShell(rDocSh) {}
+
+ void MakeOutline( const ScRange& rRange, bool bColumns, bool bRecord, bool bApi );
+ void RemoveOutline( const ScRange& rRange, bool bColumns, bool bRecord, bool bApi );
+ bool RemoveAllOutlines( SCTAB nTab, bool bRecord );
+ void AutoOutline( const ScRange& rRange, bool bRecord );
+
+ bool SelectLevel( SCTAB nTab, bool bColumns, sal_uInt16 nLevel,
+ bool bRecord, bool bPaint );
+
+ bool ShowMarkedOutlines( const ScRange& rRange, bool bRecord );
+ bool HideMarkedOutlines( const ScRange& rRange, bool bRecord );
+
+ void ShowOutline( SCTAB nTab, bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry,
+ bool bRecord, bool bPaint );
+ bool HideOutline( SCTAB nTab, bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry,
+ bool bRecord, bool bPaint );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/olinewin.hxx b/sc/source/ui/inc/olinewin.hxx
new file mode 100644
index 000000000..7f99ae662
--- /dev/null
+++ b/sc/source/ui/inc/olinewin.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 <vcl/window.hxx>
+#include "viewdata.hxx"
+
+class ScOutlineEntry;
+class ScOutlineArray;
+
+enum ScOutlineMode { SC_OUTLINE_HOR, SC_OUTLINE_VER };
+
+/** The window left of or above the spreadsheet containing the outline groups
+ and controls to expand/collapse them. */
+class ScOutlineWindow : public vcl::Window
+{
+private:
+ ScViewData& mrViewData; /// View data containing the document.
+ ScSplitPos meWhich; /// Which area in split window.
+ bool mbHoriz; /// true = Horizontal orientation.
+ bool mbMirrorEntries; /// true = mirror the order of entries (including header)
+ bool mbMirrorLevels; /// true = mirror the order of levels, including the border
+
+ Color maLineColor; /// Line color for expanded groups.
+ tools::Long mnHeaderSize; /// Size of the header area in entry direction.
+ tools::Long mnHeaderPos; /// Position of the header area in entry direction.
+ tools::Long mnMainFirstPos; /// First position of main area in entry direction.
+ tools::Long mnMainLastPos; /// Last position of main area in entry direction.
+
+ size_t mnMTLevel; /// Mouse tracking: Level of active button.
+ size_t mnMTEntry; /// Mouse tracking: Entry index of active button.
+ bool mbMTActive; /// Mouse tracking active?
+ bool mbMTPressed; /// Mouse tracking: Button currently drawn pressed?
+
+ tools::Rectangle maFocusRect; /// Focus rectangle on screen.
+ size_t mnFocusLevel; /// Level of focused button.
+ size_t mnFocusEntry; /// Entry index of focused button.
+ bool mbDontDrawFocus; /// Do not redraw focus in next Paint().
+
+public:
+ ScOutlineWindow(
+ vcl::Window* pParent,
+ ScOutlineMode eMode,
+ ScViewData* pViewData,
+ ScSplitPos eWhich );
+ virtual ~ScOutlineWindow() override;
+ virtual void dispose() override;
+
+ /** Sets the size of the header area (width/height dep. on window type). */
+ void SetHeaderSize( tools::Long nNewSize );
+ /** Returns the width/height the window needs to show all levels. */
+ tools::Long GetDepthSize() const;
+
+ /** Scrolls the window content by the specified amount of pixels. */
+ void ScrollPixel( tools::Long nDiff );
+
+ using Window::ShowFocus;
+
+private:
+ /** Initializes color and image settings. */
+ void InitSettings();
+
+ /** Returns the calc document. */
+ ScDocument& GetDoc() const { return mrViewData.GetDocument(); }
+ /** Returns the current sheet index. */
+ SCTAB GetTab() const { return mrViewData.GetTabNo(); }
+ /** Returns the outline array of the corresponding document. */
+ const ScOutlineArray* GetOutlineArray() const;
+ /** Returns the specified outline entry. */
+ const ScOutlineEntry* GetOutlineEntry( size_t nLevel, size_t nEntry ) const;
+
+ /** Returns true, if the column/row is hidden. */
+ bool IsHidden( SCCOLROW nColRowIndex ) const;
+ /** Returns true, if the column/row is filtered. */
+ bool IsFiltered( SCCOLROW nColRowIndex ) const;
+ /** Returns true, if all columns/rows before nColRowIndex are hidden. */
+ bool IsFirstVisible( SCCOLROW nColRowIndex ) const;
+ /** Returns the currently visible column/row range. */
+ void GetVisibleRange( SCCOLROW& rnColRowStart, SCCOLROW& rnColRowEnd ) const;
+
+ /** Returns the point in the window of the specified position. */
+ Point GetPoint( tools::Long nLevelPos, tools::Long nEntryPos ) const;
+ /** Returns the rectangle in the window of the specified position. */
+ tools::Rectangle GetRectangle(
+ tools::Long nLevelStart, tools::Long nEntryStart,
+ tools::Long nLevelEnd, tools::Long nEntryEnd ) const;
+
+ /** Returns the window size for the level coordinate. */
+ tools::Long GetOutputSizeLevel() const;
+ /** Returns the window size for the entry coordinate. */
+ tools::Long GetOutputSizeEntry() const;
+
+ /** Returns the count of levels of the outline array. 0 means no outlines. */
+ size_t GetLevelCount() const;
+ /** Returns the pixel position of the specified level. */
+ tools::Long GetLevelPos( size_t nLevel ) const;
+ /** Returns the level of the passed pixel position. */
+ size_t GetLevelFromPos( tools::Long nLevelPos ) const;
+
+ /** Returns the start coordinate of the specified column/row in the window. */
+ tools::Long GetColRowPos( SCCOLROW nColRowIndex ) const;
+ /** Returns the entry position of header images. */
+ tools::Long GetHeaderEntryPos() const;
+ /** Calculates the coordinates the outline entry takes in the window.
+ @return false = no part of the group is visible (outside window or collapsed by parent group). */
+ bool GetEntryPos(
+ size_t nLevel, size_t nEntry,
+ tools::Long& rnStartPos, tools::Long& rnEndPos, tools::Long& rnImagePos ) const;
+ /** Calculates the absolute position of the image of the specified outline entry.
+ @param nLevel The level of the entry.
+ @param nEntry The entry index or SC_OL_HEADERENTRY for the header image.
+ @return false = image is not visible. */
+ bool GetImagePos( size_t nLevel, size_t nEntry, Point& rPos ) const;
+ /** Returns true, if the button of the specified entry is visible in the window. */
+ bool IsButtonVisible( size_t nLevel, size_t nEntry ) const;
+
+ /** Returns true, if rPos is inside of a button or over the line of an expanded
+ group. The outline entry data is stored in the passed variables. */
+ bool ItemHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry, bool& rbButton ) const;
+ /** Returns true, if rPos is inside of a button.
+ The button data is stored in the passed variables. */
+ bool ButtonHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry ) const;
+ /** Returns true, if rPos is over the line of an expanded group.
+ The outline entry data is stored in the passed variables. */
+ bool LineHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry ) const;
+
+ /** Performs an action with the specified item.
+ @param nLevel The level of the entry.
+ @param nEntry The entry index or SC_OL_HEADERENTRY for the header entry. */
+ void DoFunction( size_t nLevel, size_t nEntry ) const;
+ /** Expands the specified entry (does nothing with header entries). */
+ void DoExpand( size_t nLevel, size_t nEntry ) const;
+ /** Collapses the specified entry (does nothing with header entries). */
+ void DoCollapse( size_t nLevel, size_t nEntry ) const;
+
+ /** Returns true, if the focused button is visible in the window. */
+ bool IsFocusButtonVisible() const;
+
+ /** Calculates index of next/previous focus button in the current level (no paint).
+ @param bFindVisible true = repeats until a visible button has been found.
+ @return true = focus wrapped from end to start or vice versa. */
+ bool ImplMoveFocusByEntry( bool bForward, bool bFindVisible );
+ /** Calculates position of focus button in next/previous level (no paint).
+ @return true = focus wrapped from end to start or vice versa. */
+ bool ImplMoveFocusByLevel( bool bForward );
+ /** Calculates position of focus button in tab order.
+ Repeats until a visible button has been found.
+ @return true = focus wrapped from end to start or vice versa. */
+ bool ImplMoveFocusByTabOrder( bool bForward );
+
+ /** If the focused entry is invisible, tries to move to visible position. */
+ void ImplMoveFocusToVisible( bool bForward );
+
+ /** Focuses next/previous button in the current level. */
+ void MoveFocusByEntry( bool bForward );
+ /** Focuses button in next/previous level. */
+ void MoveFocusByLevel( bool bForward );
+ /** Focuses next/previous button in tab order. */
+ void MoveFocusByTabOrder( bool bForward );
+
+ /** Starts mouse tracking after click on a button. */
+ void StartMouseTracking( size_t nLevel, size_t nEntry );
+ /** Returns whether mouse tracking mode is active. */
+ bool IsMouseTracking() const { return mbMTActive; }
+ /** Ends mouse tracking. */
+ void EndMouseTracking();
+
+ /** Sets a clip region for the window area without header. */
+ void SetEntryAreaClipRegion();
+ /** Converts coordinates to real window points and draws the line. */
+ void DrawLineRel(
+ tools::Long nLevelStart, tools::Long nEntryStart,
+ tools::Long nLevelEnd, tools::Long nEntryEnd );
+ /** Converts coordinates to real window points and draws the rectangle. */
+ void DrawRectRel(
+ tools::Long nLevelStart, tools::Long nEntryStart,
+ tools::Long nLevelEnd, tools::Long nEntryEnd );
+ /** Draws the specified image unpressed. */
+ void DrawImageRel(tools::Long nLevelPos, tools::Long nEntryPos, const OUString& rId);
+ /** Draws a pressed or unpressed border. */
+ void DrawBorderRel(size_t nLevel, size_t nEntry, bool bPressed);
+
+ /** Draws the focus rectangle into the focused button. */
+ void ShowFocus();
+ /** Erases the focus rectangle from the focused button. */
+ void HideFocus();
+
+ /** Scrolls the specified range of the window in entry-relative direction. */
+ void ScrollRel( tools::Long nEntryDiff, tools::Long nEntryStart, tools::Long nEntryEnd );
+
+protected:
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+
+ virtual void Resize() override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+
+ virtual void KeyInput( const KeyEvent& rKEvt ) override;
+
+public:
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/opredlin.hxx b/sc/source/ui/inc/opredlin.hxx
new file mode 100644
index 000000000..e26591e87
--- /dev/null
+++ b/sc/source/ui/inc/opredlin.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 ColorListBox;
+
+class ScRedlineOptionsTabPage : public SfxTabPage
+{
+ std::unique_ptr<ColorListBox> m_xContentColorLB;
+ std::unique_ptr<ColorListBox> m_xRemoveColorLB;
+ std::unique_ptr<ColorListBox> m_xInsertColorLB;
+ std::unique_ptr<ColorListBox> m_xMoveColorLB;
+
+public:
+ ScRedlineOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet );
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet );
+ virtual ~ScRedlineOptionsTabPage() override;
+
+ virtual bool FillItemSet( SfxItemSet* rSet ) override;
+ virtual void Reset( const SfxItemSet* rSet ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/optsolver.hxx b/sc/source/ui/inc/optsolver.hxx
new file mode 100644
index 000000000..538a4a536
--- /dev/null
+++ b/sc/source/ui/inc/optsolver.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 <address.hxx>
+#include "anyrefdg.hxx"
+#include "docsh.hxx"
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <string_view>
+#include <vector>
+
+namespace com::sun::star {
+ namespace beans { struct PropertyValue; }
+}
+
+class ScCursorRefEdit : public formula::RefEdit
+{
+ Link<ScCursorRefEdit&,void> maCursorUpLink;
+ Link<ScCursorRefEdit&,void> maCursorDownLink;
+
+public:
+ ScCursorRefEdit(std::unique_ptr<weld::Entry> xEntry);
+ void SetCursorLinks( const Link<ScCursorRefEdit&,void>& rUp, const Link<ScCursorRefEdit&,void>& rDown );
+
+protected:
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+};
+
+/// The dialog's content for a row, not yet parsed
+struct ScOptConditionRow
+{
+ OUString aLeftStr;
+ sal_uInt16 nOperator;
+ OUString aRightStr;
+
+ ScOptConditionRow() : nOperator(0) {}
+ bool IsDefault() const { return aLeftStr.isEmpty() && aRightStr.isEmpty() && nOperator == 0; }
+};
+
+/// All settings from the dialog, saved with the DocShell for the next call
+class ScOptSolverSave
+{
+ OUString maObjective;
+ bool mbMax;
+ bool mbMin;
+ bool mbValue;
+ OUString maTarget;
+ OUString maVariable;
+ std::vector<ScOptConditionRow> maConditions;
+ OUString maEngine;
+ css::uno::Sequence<css::beans::PropertyValue> maProperties;
+
+public:
+ ScOptSolverSave( const OUString& rObjective, bool bMax, bool bMin, bool bValue,
+ const OUString& rTarget, const OUString& rVariable,
+ std::vector<ScOptConditionRow>&& rConditions,
+ const OUString& rEngine,
+ const css::uno::Sequence<css::beans::PropertyValue>& rProperties );
+
+ const OUString& GetObjective() const { return maObjective; }
+ bool GetMax() const { return mbMax; }
+ bool GetMin() const { return mbMin; }
+ bool GetValue() const { return mbValue; }
+ const OUString& GetTarget() const { return maTarget; }
+ const OUString& GetVariable() const { return maVariable; }
+ const std::vector<ScOptConditionRow>& GetConditions() const { return maConditions; }
+ const OUString& GetEngine() const { return maEngine; }
+ const css::uno::Sequence<css::beans::PropertyValue>& GetProperties() const
+ { return maProperties; }
+};
+
+class ScSolverOptionsDialog;
+
+class ScOptSolverDlg : public ScAnyRefDlgController
+{
+public:
+ ScOptSolverDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScDocShell* pDocSh, const ScAddress& aCursorPos );
+ virtual ~ScOptSolverDlg() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+ virtual bool IsRefInputMode() const override;
+ virtual void SetActive() override;
+ virtual void Close() override;
+
+private:
+ OUString maInputError;
+ OUString maConditionError;
+
+ ScDocShell* mpDocShell;
+ ScDocument& mrDoc;
+ const SCTAB mnCurTab;
+ bool mbDlgLostFocus;
+
+ std::vector<ScOptConditionRow> maConditions;
+ tools::Long nScrollPos;
+
+ css::uno::Sequence<OUString> maImplNames;
+ css::uno::Sequence<OUString> maDescriptions;
+ OUString maEngine;
+ css::uno::Sequence<css::beans::PropertyValue> maProperties;
+
+ static const sal_uInt16 EDIT_ROW_COUNT = 4;
+ ScCursorRefEdit* mpLeftEdit[EDIT_ROW_COUNT];
+ formula::RefButton* mpLeftButton[EDIT_ROW_COUNT];
+ ScCursorRefEdit* mpRightEdit[EDIT_ROW_COUNT];
+ formula::RefButton* mpRightButton[EDIT_ROW_COUNT];
+ weld::ComboBox* mpOperator[EDIT_ROW_COUNT];
+ weld::Button* mpDelButton[EDIT_ROW_COUNT];
+
+ formula::RefEdit* mpEdActive;
+
+ std::unique_ptr<weld::Label> m_xFtObjectiveCell;
+ std::unique_ptr<formula::RefEdit> m_xEdObjectiveCell;
+ std::unique_ptr<formula::RefButton> m_xRBObjectiveCell;
+
+ std::unique_ptr<weld::RadioButton> m_xRbMax;
+ std::unique_ptr<weld::RadioButton> m_xRbMin;
+ std::unique_ptr<weld::RadioButton> m_xRbValue;
+ std::unique_ptr<formula::RefEdit> m_xEdTargetValue;
+ std::unique_ptr<formula::RefButton> m_xRBTargetValue;
+
+ std::unique_ptr<weld::Label> m_xFtVariableCells;
+ std::unique_ptr<formula::RefEdit> m_xEdVariableCells;
+ std::unique_ptr<formula::RefButton> m_xRBVariableCells;
+
+ std::unique_ptr<weld::Label> m_xFtCellRef; // labels are together with controls for the first row
+ std::unique_ptr<ScCursorRefEdit> m_xEdLeft1;
+ std::unique_ptr<formula::RefButton> m_xRBLeft1;
+ std::unique_ptr<weld::Label> m_xFtOperator;
+ std::unique_ptr<weld::ComboBox> m_xLbOp1;
+ std::unique_ptr<weld::Label> m_xFtConstraint;
+ std::unique_ptr<ScCursorRefEdit> m_xEdRight1;
+ std::unique_ptr<formula::RefButton> m_xRBRight1;
+ std::unique_ptr<weld::Button> m_xBtnDel1;
+
+ std::unique_ptr<ScCursorRefEdit> m_xEdLeft2;
+ std::unique_ptr<formula::RefButton> m_xRBLeft2;
+ std::unique_ptr<weld::ComboBox> m_xLbOp2;
+ std::unique_ptr<ScCursorRefEdit> m_xEdRight2;
+ std::unique_ptr<formula::RefButton> m_xRBRight2;
+ std::unique_ptr<weld::Button> m_xBtnDel2;
+
+ std::unique_ptr<ScCursorRefEdit> m_xEdLeft3;
+ std::unique_ptr<formula::RefButton> m_xRBLeft3;
+ std::unique_ptr<weld::ComboBox> m_xLbOp3;
+ std::unique_ptr<ScCursorRefEdit> m_xEdRight3;
+ std::unique_ptr<formula::RefButton> m_xRBRight3;
+ std::unique_ptr<weld::Button> m_xBtnDel3;
+
+ std::unique_ptr<ScCursorRefEdit> m_xEdLeft4;
+ std::unique_ptr<formula::RefButton> m_xRBLeft4;
+ std::unique_ptr<weld::ComboBox> m_xLbOp4;
+ std::unique_ptr<ScCursorRefEdit> m_xEdRight4;
+ std::unique_ptr<formula::RefButton> m_xRBRight4;
+ std::unique_ptr<weld::Button> m_xBtnDel4;
+
+ std::unique_ptr<weld::ScrolledWindow> m_xScrollBar;
+
+ std::unique_ptr<weld::Button> m_xBtnOpt;
+ std::unique_ptr<weld::Button> m_xBtnClose;
+ std::unique_ptr<weld::Button> m_xBtnSolve;
+ std::unique_ptr<weld::Button> m_xBtnResetAll;
+
+ std::unique_ptr<weld::Label> m_xResultFT;
+ std::unique_ptr<weld::Widget> m_xContents;
+
+ std::shared_ptr<ScSolverOptionsDialog> m_xOptDlg;
+
+ void Init(const ScAddress& rCursorPos);
+ bool CallSolver();
+ void ReadConditions();
+ void ShowConditions();
+ void EnableButtons();
+ bool ParseRef( ScRange& rRange, const OUString& rInput, bool bAllowRange );
+ bool FindTimeout( sal_Int32& rTimeout );
+ void ShowError( bool bCondition, formula::RefEdit* pFocus );
+
+ DECL_LINK( BtnHdl, weld::Button&, void );
+ DECL_LINK( DelBtnHdl, weld::Button&, void );
+ DECL_LINK( GetEditFocusHdl, formula::RefEdit&, void );
+ DECL_LINK( GetButtonFocusHdl, formula::RefButton&, void );
+ DECL_LINK( GetFocusHdl, weld::Widget&, void );
+ DECL_LINK( LoseEditFocusHdl, formula::RefEdit&, void );
+ DECL_LINK( LoseButtonFocusHdl, formula::RefButton&, void );
+ DECL_LINK( ScrollHdl, weld::ScrolledWindow&, void);
+ DECL_LINK( CursorUpHdl, ScCursorRefEdit&, void );
+ DECL_LINK( CursorDownHdl, ScCursorRefEdit&, void );
+ DECL_LINK( CondModifyHdl, formula::RefEdit&, void );
+ DECL_LINK( TargetModifyHdl, formula::RefEdit&, void );
+ DECL_LINK( SelectHdl, weld::ComboBox&, void );
+};
+
+class ScSolverProgressDialog : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::Label> m_xFtTime;
+
+public:
+ ScSolverProgressDialog(weld::Window* pParent);
+ virtual ~ScSolverProgressDialog() override;
+
+ void HideTimeLimit();
+ void SetTimeLimit( sal_Int32 nSeconds );
+};
+
+class ScSolverNoSolutionDialog : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::Label> m_xFtErrorText;
+
+public:
+ ScSolverNoSolutionDialog(weld::Window* pParent, const OUString& rErrorText);
+ virtual ~ScSolverNoSolutionDialog() override;
+};
+
+class ScSolverSuccessDialog : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::Label> m_xFtResult;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+ DECL_LINK(ClickHdl, weld::Button&, void);
+
+public:
+ ScSolverSuccessDialog(weld::Window* pParent, std::u16string_view rSolution);
+ virtual ~ScSolverSuccessDialog() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/output.hxx b/sc/source/ui/inc/output.hxx
new file mode 100644
index 000000000..d44f70525
--- /dev/null
+++ b/sc/source/ui/inc/output.hxx
@@ -0,0 +1,388 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <address.hxx>
+#include <cellvalue.hxx>
+#include <tools/color.hxx>
+#include <tools/fract.hxx>
+#include <tools/gen.hxx>
+#include <editeng/svxenum.hxx>
+#include <vcl/outdev.hxx>
+#include <tools/degree.hxx>
+#include <o3tl/deleter.hxx>
+#include <optional>
+
+namespace sc {
+ class SpellCheckContext;
+}
+
+namespace editeng {
+ struct MisspellRanges;
+}
+namespace drawinglayer::processor2d { class BaseProcessor2D; }
+
+namespace vcl { class Font; }
+class EditEngine;
+class ScDocument;
+class ScPatternAttr;
+struct RowInfo;
+struct ScTableInfo;
+class ScTabViewShell;
+class ScPageBreakData;
+class FmFormView;
+class ScFieldEditEngine;
+class SdrPaintWindow;
+
+#define SC_SCENARIO_HSPACE 60
+#define SC_SCENARIO_VSPACE 50
+
+enum ScOutputType { OUTTYPE_WINDOW, OUTTYPE_PRINTER };
+
+class ClearableClipRegion;
+typedef std::unique_ptr<ClearableClipRegion, o3tl::default_delete<ClearableClipRegion>> ClearableClipRegionPtr;
+
+/// Describes reference mark to be drawn, position & size in TWIPs
+struct ReferenceMark {
+ tools::Long nX;
+ tools::Long nY;
+ tools::Long nWidth;
+ tools::Long nHeight;
+ tools::Long nTab;
+ Color aColor;
+
+ ReferenceMark()
+ : nX( 0 )
+ , nY( 0 )
+ , nWidth( 0 )
+ , nHeight( 0 )
+ , nTab( 0 )
+ , aColor( COL_AUTO ) {}
+
+ ReferenceMark( tools::Long aX,
+ tools::Long aY,
+ tools::Long aWidth,
+ tools::Long aHeight,
+ tools::Long aTab,
+ const Color& rColor )
+ : nX( aX )
+ , nY( aY )
+ , nWidth( aWidth )
+ , nHeight( aHeight )
+ , nTab( aTab )
+ , aColor( rColor ) {}
+
+ bool Is() const { return ( nWidth > 0 && nHeight > 0 ); }
+};
+
+class ScOutputData
+{
+friend class ScDrawStringsVars;
+friend class ScGridWindow;
+private:
+ struct OutputAreaParam
+ {
+ tools::Rectangle maAlignRect;
+ tools::Rectangle maClipRect;
+ tools::Long mnColWidth;
+ tools::Long mnLeftClipLength; /// length of the string getting cut off on the left.
+ tools::Long mnRightClipLength; /// length of the string getting cut off on the right.
+ bool mbLeftClip;
+ bool mbRightClip;
+ };
+
+ class DrawEditParam
+ {
+ public:
+ SvxCellHorJustify meHorJustAttr; ///< alignment attribute
+ SvxCellHorJustify meHorJustContext; ///< context depending on attribute, content and direction
+ SvxCellHorJustify meHorJustResult; ///< result for EditEngine
+ SvxCellVerJustify meVerJust;
+ SvxCellJustifyMethod meHorJustMethod;
+ SvxCellJustifyMethod meVerJustMethod;
+ SvxCellOrientation meOrient;
+ SCSIZE mnArrY;
+ SCCOL mnX;
+ SCCOL mnCellX;
+ SCROW mnCellY;
+ tools::Long mnPosX;
+ tools::Long mnPosY;
+ tools::Long mnInitPosX;
+ bool mbBreak:1;
+ bool mbCellIsValue:1;
+ bool mbAsianVertical:1;
+ bool mbPixelToLogic:1;
+ bool mbHyphenatorSet:1;
+ ScFieldEditEngine* mpEngine;
+ ScRefCellValue maCell;
+ const ScPatternAttr* mpPattern;
+ const SfxItemSet* mpCondSet;
+ const SfxItemSet* mpPreviewFontSet;
+ const ScPatternAttr* mpOldPattern;
+ const SfxItemSet* mpOldCondSet;
+ const SfxItemSet* mpOldPreviewFontSet;
+ RowInfo* mpThisRowInfo;
+ const std::vector<editeng::MisspellRanges>* mpMisspellRanges;
+
+ explicit DrawEditParam(const ScPatternAttr* pPattern, const SfxItemSet* pCondSet, bool bCellIsValue);
+
+ bool readCellContent(const ScDocument* pDoc, bool bShowNullValues, bool bShowFormulas, bool bSyntaxMode, bool bUseStyleColor, bool bForceAutoColor, bool& rWrapFields);
+ void setPatternToEngine(bool bUseStyleColor);
+ void calcMargins(tools::Long& rTop, tools::Long& rLeft, tools::Long& rBottom, tools::Long& rRight, double nPPTX, double nPPTY) const;
+ void calcPaperSize(Size& rPaperSize, const tools::Rectangle& rAlignRect, double nPPTX, double nPPTY) const;
+ void getEngineSize(ScFieldEditEngine* pEngine, tools::Long& rWidth, tools::Long& rHeight) const;
+ bool hasLineBreak() const;
+ bool isHyperlinkCell() const;
+
+ /**
+ * When the text is vertically oriented, the text is either rotated 90
+ * degrees to the right or 90 degrees to the left. Note that this is
+ * different from being vertically stacked.
+ */
+ bool isVerticallyOriented() const;
+
+ /**
+ * Calculate offset position for vertically oriented (either
+ * top-bottom or bottom-top orientation) text.
+ *
+ * @param rLogicStart initial position in pixels. When the call is
+ * finished, this parameter will store the new
+ * position.
+ */
+ void calcStartPosForVertical(Point& rLogicStart, tools::Long nCellWidth, tools::Long nEngineWidth, tools::Long nTopM, const OutputDevice* pRefDevice);
+
+ void setAlignmentToEngine();
+ bool adjustHorAlignment(ScFieldEditEngine* pEngine);
+ void adjustForHyperlinkInPDF(Point aURLStart, const OutputDevice* pDev);
+ };
+
+ VclPtr<OutputDevice> mpDev; // Device
+ VclPtr<OutputDevice> mpRefDevice; // printer if used for preview
+ VclPtr<OutputDevice> pFmtDevice; // reference for text formatting
+ ScTableInfo& mrTabInfo;
+ RowInfo* pRowInfo; // Info block
+ SCSIZE nArrCount; // occupied lines in info block
+ ScDocument* mpDoc; // Document
+ SCTAB nTab; // sheet
+ tools::Long nScrX; // Output Startpos. (Pixel)
+ tools::Long nScrY;
+ tools::Long nScrW; // Output size (Pixel)
+ tools::Long nScrH;
+ tools::Long nMirrorW; // Visible output width for mirroring (default: nScrW)
+ SCCOL nX1; // Start-/End coordinates
+ SCROW nY1; // ( incl. hidden )
+ SCCOL nX2;
+ SCROW nY2;
+ SCCOL nVisX1; // Start-/End coordinates
+ SCROW nVisY1; // ( visible range )
+ SCCOL nVisX2;
+ SCROW nVisY2;
+ ScOutputType eType; // Screen/Printer ...
+ double mnPPTX; // Pixel per Twips
+ double mnPPTY;
+ Fraction aZoomX;
+ Fraction aZoomY;
+
+ ScTabViewShell* pViewShell; // for connect from visible plug-ins
+
+ FmFormView* pDrawView; // SdrView to paint to
+
+ bool bEditMode; // InPlace edited cell - do not output
+ SCCOL nEditCol;
+ SCROW nEditRow;
+
+ bool bMetaFile; // Output to metafile (not pixels!)
+
+ bool bPagebreakMode; // Page break preview
+ bool bSolidBackground; // white instead of transparent
+
+ bool mbUseStyleColor;
+ bool mbForceAutoColor;
+
+ bool mbSyntaxMode; // Syntax highlighting
+ std::optional<Color> mxValueColor;
+ std::optional<Color> mxTextColor;
+ std::optional<Color> mxFormulaColor;
+
+ Color aGridColor;
+
+ bool mbShowNullValues;
+ bool mbShowFormulas;
+ bool bShowSpellErrors; // Show spelling errors in EditObjects
+ bool bMarkClipped;
+
+ bool bSnapPixel;
+
+ bool bAnyClipped; // internal
+ bool bVertical;
+ bool bTabProtected;
+ bool bLayoutRTL;
+
+ // #i74769# use SdrPaintWindow direct, remember it during BeginDrawLayers/EndDrawLayers
+ SdrPaintWindow* mpTargetPaintWindow;
+ const sc::SpellCheckContext* mpSpellCheckCxt;
+
+ // private methods
+
+ bool GetMergeOrigin( SCCOL nX, SCROW nY, SCSIZE nArrY,
+ SCCOL& rOverX, SCROW& rOverY, bool bVisRowChanged );
+ bool IsEmptyCellText( const RowInfo* pThisRowInfo, SCCOL nX, SCROW nY );
+ void GetVisibleCell( SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue& rCell );
+
+ bool IsAvailable( SCCOL nX, SCROW nY );
+
+ void GetOutputArea( SCCOL nX, SCSIZE nArrY, tools::Long nPosX, tools::Long nPosY,
+ SCCOL nCellX, SCROW nCellY, tools::Long nNeeded,
+ const ScPatternAttr& rPattern,
+ sal_uInt16 nHorJustify, bool bCellIsValue,
+ bool bBreak, bool bOverwrite,
+ OutputAreaParam& rParam );
+
+ void ShrinkEditEngine( EditEngine& rEngine, const tools::Rectangle& rAlignRect,
+ tools::Long nLeftM, tools::Long nTopM, tools::Long nRightM, tools::Long nBottomM,
+ bool bWidth, SvxCellOrientation nOrient, Degree100 nAttrRotate, bool bPixelToLogic,
+ tools::Long& rEngineWidth, tools::Long& rEngineHeight, tools::Long& rNeededPixel,
+ bool& rLeftClip, bool& rRightClip );
+
+ void SetSyntaxColor( vcl::Font* pFont, const ScRefCellValue& rCell );
+ void SetEditSyntaxColor( EditEngine& rEngine, const ScRefCellValue& rCell );
+
+ double GetStretch() const;
+
+ void DrawRotatedFrame(vcl::RenderContext& rRenderContext); // pixel
+
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> CreateProcessor2D( );
+
+ void DrawEditStandard(DrawEditParam& rParam);
+ void DrawEditBottomTop(DrawEditParam& rParam);
+ void DrawEditTopBottom(DrawEditParam& rParam);
+ void DrawEditStacked(DrawEditParam& rParam);
+ void DrawEditAsianVertical(DrawEditParam& rParam);
+
+ std::unique_ptr<ScFieldEditEngine> CreateOutputEditEngine();
+
+ void ShowClipMarks( DrawEditParam& rParam, tools::Long nEngineWidth, const Size& aCellSize,
+ bool bMerged, OutputAreaParam& aAreaParam, bool bTop );
+
+ ClearableClipRegionPtr Clip(DrawEditParam& rParam, const Size& aCellSize, OutputAreaParam& aAreaParam,
+ tools::Long nEngineWidth, bool bWrapFields, bool bTop);
+
+ bool AdjustAreaParamClipRect(OutputAreaParam& rAreaParam);
+ tools::Long SetEngineTextAndGetWidth( DrawEditParam& rParam, const OUString& rSetString,
+ tools::Long& rNeededPixel, tools::Long nAddWidthPixels );
+
+ // Check for and set cell rotations at OutputData to have it available
+ // in the svx tooling to render the borders. Moved to private section
+ // and the single call to end of constructor to be sure this always happens
+ void SetCellRotations();
+
+public:
+
+ /**
+ * @param nNewScrX: X-Offset in the output device for the table
+ * @param nNewScrY: Y-Offset in the output device for the table
+ *
+ */
+ ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType,
+ ScTableInfo& rTabInfo, ScDocument* pNewDoc,
+ SCTAB nNewTab, tools::Long nNewScrX, tools::Long nNewScrY,
+ SCCOL nNewX1, SCROW nNewY1, SCCOL nNewX2, SCROW nNewY2,
+ double nPixelPerTwipsX, double nPixelPerTwipsY,
+ const Fraction* pZoomX = nullptr,
+ const Fraction* pZoomY = nullptr );
+
+ ~ScOutputData();
+
+ void SetSpellCheckContext( const sc::SpellCheckContext* pCxt );
+ void SetContentDevice( OutputDevice* pContentDev );
+
+ void SetRefDevice( OutputDevice* pRDev ) { mpRefDevice = pFmtDevice = pRDev; }
+ void SetFmtDevice( OutputDevice* pRDev ) { pFmtDevice = pRDev; }
+ void SetViewShell( ScTabViewShell* pSh ) { pViewShell = pSh; }
+
+ void SetDrawView( FmFormView* pNew ) { pDrawView = pNew; }
+
+ void SetSolidBackground( bool bSet ) { bSolidBackground = bSet; }
+ void SetUseStyleColor( bool bSet ) { mbUseStyleColor = bSet; }
+
+ void SetEditCell( SCCOL nCol, SCROW nRow );
+ void SetSyntaxMode( bool bNewMode );
+ void SetMetaFileMode( bool bNewMode );
+ void SetGridColor( const Color& rColor );
+ void SetMarkClipped( bool bSet );
+ void SetShowNullValues ( bool bSet );
+ void SetShowFormulas ( bool bSet );
+ void SetShowSpellErrors( bool bSet );
+ void SetMirrorWidth( tools::Long nNew );
+ tools::Long GetScrW() const { return nScrW; }
+ tools::Long GetScrH() const { return nScrH; }
+
+ void SetSnapPixel();
+
+ void DrawGrid(vcl::RenderContext& rRenderContext, bool bGrid, bool bPage, bool bMergeCover = false);
+ void DrawStrings( bool bPixelToLogic = false );
+
+ /// Draw all strings, or provide Rectangle where the text (defined by rAddress) would be drawn.
+ tools::Rectangle LayoutStrings(bool bPixelToLogic, bool bPaint = true, const ScAddress &rAddress = ScAddress());
+
+ void DrawDocumentBackground();
+ void DrawBackground(vcl::RenderContext& rRenderContext);
+ void DrawShadow();
+ void DrawExtraShadow(bool bLeft, bool bTop, bool bRight, bool bBottom);
+ void DrawFrame(vcl::RenderContext& rRenderContext);
+
+ // with logic MapMode set!
+ void DrawEdit(bool bPixelToLogic);
+ void DrawRotated(bool bPixelToLogic); // logical
+
+ void DrawClear();
+
+ // #i72502# printer only command set
+ Point PrePrintDrawingLayer(tools::Long nLogStX, tools::Long nLogStY );
+ void PostPrintDrawingLayer(const Point& rMMOffset); // #i74768# need offset for FormLayer
+ void PrintDrawingLayer(SdrLayerID nLayer, const Point& rMMOffset);
+
+ // only screen:
+ void DrawSelectiveObjects(SdrLayerID nLayer);
+
+ bool SetChangedClip(); // sal_False = not
+ vcl::Region GetChangedAreaRegion();
+
+ void FindChanged();
+ void SetPagebreakMode( ScPageBreakData* pPageData );
+ /// Draws reference mark and returns its properties
+ void DrawRefMark( SCCOL nRefStartX, SCROW nRefStartY,
+ SCCOL nRefEndX, SCROW nRefEndY,
+ const Color& rColor, bool bHandle );
+ ReferenceMark FillReferenceMark( SCCOL nRefStartX, SCROW nRefStartY,
+ SCCOL nRefEndX, SCROW nRefEndY,
+ const Color& rColor );
+ void DrawOneChange( SCCOL nRefStartX, SCROW nRefStartY,
+ SCCOL nRefEndX, SCROW nRefEndY,
+ const Color& rColor, sal_uInt16 nType );
+ void DrawChangeTrack();
+ void DrawClipMarks();
+
+ void DrawNoteMarks(vcl::RenderContext& rRenderContext);
+ void AddPDFNotes();
+ void DrawSparklines(vcl::RenderContext& rRenderContext);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/overlayobject.hxx b/sc/source/ui/inc/overlayobject.hxx
new file mode 100644
index 000000000..ea7a4adf3
--- /dev/null
+++ b/sc/source/ui/inc/overlayobject.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 <svx/sdr/overlay/overlayobject.hxx>
+#include <vcl/font.hxx>
+#include <vcl/mapmod.hxx>
+
+class ScOverlayDashedBorder : public sdr::overlay::OverlayObject
+{
+public:
+ ScOverlayDashedBorder(const ::basegfx::B2DRange& rRange, const Color& rColor);
+ virtual ~ScOverlayDashedBorder() override;
+
+ virtual void Trigger(sal_uInt32 nTime) override;
+
+ virtual void stripeDefinitionHasChanged() override;
+
+protected:
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+private:
+ ::basegfx::B2DRange maRange;
+ bool mbToggle;
+};
+
+class ScOverlayHint : public sdr::overlay::OverlayObject
+{
+public:
+ ScOverlayHint(const OUString& rTit, const OUString& rMsg, const Color& rColor, const vcl::Font& rFont);
+ Size GetSizePixel() const;
+ void SetPos(const Point& rPos, const MapMode& rMode);
+
+public:
+ virtual drawinglayer::primitive2d::Primitive2DContainer createOverlayObjectPrimitive2DSequence() override;
+
+private:
+ drawinglayer::primitive2d::Primitive2DContainer createOverlaySequence(sal_Int32 nLeft, sal_Int32 nTop, const MapMode &rMapMode, basegfx::B2DRange &rRange) const;
+
+ const OUString m_aTitle;
+ const OUString m_aMessage;
+ const vcl::Font m_aTextFont;
+ MapMode m_aMapMode;
+ sal_Int32 m_nLeft;
+ sal_Int32 m_nTop;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/pagedata.hxx b/sc/source/ui/inc/pagedata.hxx
new file mode 100644
index 000000000..265a85743
--- /dev/null
+++ b/sc/source/ui/inc/pagedata.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 <tools/long.hxx>
+#include <address.hxx>
+#include <memory>
+#include <vector>
+
+class ScPrintRangeData
+{
+private:
+ ScRange aPrintRange;
+ std::vector<SCCOL>
+ mvPageEndX;
+ std::vector<SCROW>
+ mvPageEndY;
+ tools::Long nFirstPage;
+ bool bTopDown;
+ bool bAutomatic;
+
+public:
+ ScPrintRangeData();
+ ~ScPrintRangeData();
+
+ void SetPrintRange( const ScRange& rNew ) { aPrintRange = rNew; }
+ const ScRange& GetPrintRange() const { return aPrintRange; }
+
+ void SetPagesX( size_t nCount, const SCCOL* pEnd );
+ void SetPagesY( size_t nCount, const SCROW* pEnd );
+
+ size_t GetPagesX() const { return mvPageEndX.size(); }
+ const SCCOL* GetPageEndX() const { return mvPageEndX.data(); }
+ size_t GetPagesY() const { return mvPageEndY.size(); }
+ const SCROW* GetPageEndY() const { return mvPageEndY.data(); }
+
+ void SetFirstPage( tools::Long nNew ) { nFirstPage = nNew; }
+ tools::Long GetFirstPage() const { return nFirstPage; }
+ void SetTopDown( bool bSet ) { bTopDown = bSet; }
+ bool IsTopDown() const { return bTopDown; }
+ void SetAutomatic( bool bSet ) { bAutomatic = bSet; }
+ bool IsAutomatic() const { return bAutomatic; }
+};
+
+class ScPageBreakData
+{
+private:
+ size_t nAlloc;
+ size_t nUsed;
+ std::unique_ptr<ScPrintRangeData[]> pData;
+
+public:
+ ScPageBreakData(size_t nMax);
+ ~ScPageBreakData();
+
+ size_t GetCount() const { return nUsed; }
+ ScPrintRangeData& GetData(size_t i);
+
+ bool operator==( const ScPageBreakData& rOther ) const;
+
+ void AddPages();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/pfiltdlg.hxx b/sc/source/ui/inc/pfiltdlg.hxx
new file mode 100644
index 000000000..892d86552
--- /dev/null
+++ b/sc/source/ui/inc/pfiltdlg.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 <vcl/weld.hxx>
+#include <address.hxx>
+#include <queryparam.hxx>
+#include <array>
+#include <memory>
+
+class ScViewData;
+class ScDocument;
+class ScQueryItem;
+class SfxItemSet;
+struct ScFilterEntries;
+
+class ScPivotFilterDlg : public weld::GenericDialogController
+{
+public:
+ ScPivotFilterDlg(weld::Window* pParent, const SfxItemSet& rArgSet, SCTAB nSourceTab);
+ virtual ~ScPivotFilterDlg() override;
+
+ const ScQueryItem& GetOutputItem();
+
+private:
+ const OUString aStrNone;
+ const OUString aStrEmpty;
+ const OUString aStrNotEmpty;
+ const OUString aStrColumn;
+
+ const sal_uInt16 nWhichQuery;
+ const ScQueryParam theQueryData;
+ std::unique_ptr<ScQueryItem> pOutItem;
+ ScViewData* pViewData;
+ ScDocument* pDoc;
+ SCTAB nSrcTab;
+
+ std::unique_ptr<weld::ComboBox> m_xLbField1;
+ std::unique_ptr<weld::ComboBox> m_xLbCond1;
+ std::unique_ptr<weld::ComboBox> m_xEdVal1;
+
+ std::unique_ptr<weld::ComboBox> m_xLbConnect1;
+ std::unique_ptr<weld::ComboBox> m_xLbField2;
+ std::unique_ptr<weld::ComboBox> m_xLbCond2;
+ std::unique_ptr<weld::ComboBox> m_xEdVal2;
+
+ std::unique_ptr<weld::ComboBox> m_xLbConnect2;
+ std::unique_ptr<weld::ComboBox> m_xLbField3;
+ std::unique_ptr<weld::ComboBox> m_xLbCond3;
+ std::unique_ptr<weld::ComboBox> m_xEdVal3;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnCase;
+ std::unique_ptr<weld::CheckButton> m_xBtnRegExp;
+ std::unique_ptr<weld::CheckButton> m_xBtnUnique;
+ std::unique_ptr<weld::Label> m_xFtDbArea;
+
+ weld::ComboBox* aValueEdArr[3];
+ weld::ComboBox* aFieldLbArr[3];
+ weld::ComboBox* aCondLbArr[3];
+
+ std::array<std::unique_ptr<ScFilterEntries>, MAXCOLCOUNT> m_pEntryLists;
+
+private:
+ void Init ( const SfxItemSet& rArgSet );
+ void FillFieldLists ();
+ void UpdateValueList ( sal_uInt16 nList );
+ void ClearValueList ( sal_uInt16 nList );
+ sal_uInt16 GetFieldSelPos ( SCCOL nField );
+
+ // Handler:
+ DECL_LINK( LbSelectHdl, weld::ComboBox&, void );
+ DECL_LINK( ValModifyHdl, weld::ComboBox&, void );
+ DECL_LINK( CheckBoxHdl, weld::Toggleable&, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/pfuncache.hxx b/sc/source/ui/inc/pfuncache.hxx
new file mode 100644
index 000000000..c3324e2f6
--- /dev/null
+++ b/sc/source/ui/inc/pfuncache.hxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vector>
+#include <tools/gen.hxx>
+#include <rangelst.hxx>
+#include <printopt.hxx>
+
+class ScDocShell;
+class ScMarkData;
+class OutputDevice;
+
+/** Possible types of selection for print functions */
+
+enum class ScPrintSelectionMode
+{
+ Invalid,
+ Document,
+ Cursor,
+ Range,
+ RangeExclusivelyOleAndDrawObjects
+};
+
+/** Stores the selection in the ScPrintFuncCache so it is only used
+ for the same selection again. */
+
+class ScPrintSelectionStatus
+{
+ ScPrintSelectionMode eMode;
+ ScRangeList aRanges;
+ ScPrintOptions aOptions;
+
+public:
+ ScPrintSelectionStatus() : eMode(ScPrintSelectionMode::Invalid) {}
+
+ void SetMode(ScPrintSelectionMode eNew) { eMode = eNew; }
+ void SetRanges(const ScRangeList& rNew) { aRanges = rNew; }
+ void SetOptions(const ScPrintOptions& rNew) { aOptions = rNew; }
+
+ bool operator==(const ScPrintSelectionStatus& rOther) const
+ { return eMode == rOther.eMode && aRanges == rOther.aRanges && aOptions == rOther.aOptions; }
+
+ ScPrintSelectionMode GetMode() const { return eMode; }
+ const ScPrintOptions& GetOptions() const { return aOptions; }
+};
+
+/** The range that is printed on a page (excluding repeated columns/rows),
+ and its position on the page, used to find hyperlink targets. */
+
+struct ScPrintPageLocation
+{
+ tools::Long nPage;
+ ScRange aCellRange;
+ tools::Rectangle aRectangle; // pixels
+
+ ScPrintPageLocation() :
+ nPage(-1) {} // default: invalid
+
+ ScPrintPageLocation( tools::Long nP, const ScRange& rRange, const tools::Rectangle& rRect ) :
+ nPage(nP), aCellRange(rRange), aRectangle(rRect) {}
+};
+
+/** Stores the data for printing that is needed from several sheets,
+ so it doesn't have to be calculated for rendering each page. */
+
+class ScPrintFuncCache
+{
+ ScPrintSelectionStatus aSelection;
+ ScDocShell* pDocSh;
+ tools::Long nTotalPages;
+ std::vector<tools::Long> nPages;
+ std::vector<tools::Long> nFirstAttr;
+ std::vector<ScPrintPageLocation> aLocations;
+ bool bLocInitialized;
+
+public:
+ ScPrintFuncCache( ScDocShell* pD, const ScMarkData& rMark,
+ const ScPrintSelectionStatus& rStatus );
+ ~ScPrintFuncCache();
+
+ bool IsSameSelection( const ScPrintSelectionStatus& rStatus ) const;
+
+ void InitLocations( const ScMarkData& rMark, OutputDevice* pDev );
+ bool FindLocation( const ScAddress& rCell, ScPrintPageLocation& rLocation ) const;
+
+ tools::Long GetPageCount() const { return nTotalPages; }
+ tools::Long GetFirstAttr( SCTAB nTab ) const { return nFirstAttr[nTab]; }
+ SCTAB GetTabForPage( tools::Long nPage ) const;
+ tools::Long GetTabStart( SCTAB nTab ) const;
+ tools::Long GetDisplayStart( SCTAB nTab ) const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/pgbrksh.hxx b/sc/source/ui/inc/pgbrksh.hxx
new file mode 100644
index 000000000..7b00f315b
--- /dev/null
+++ b/sc/source/ui/inc/pgbrksh.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 <sfx2/shell.hxx>
+
+#include <shellids.hxx>
+
+class SfxModule;
+class ScTabViewShell;
+
+class ScPageBreakShell final : public SfxShell
+{
+public:
+ SFX_DECL_INTERFACE(SCID_PAGEBREAK_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScPageBreakShell(ScTabViewShell* pView);
+ virtual ~ScPageBreakShell() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/pivotsh.hxx b/sc/source/ui/inc/pivotsh.hxx
new file mode 100644
index 000000000..d69b80ee4
--- /dev/null
+++ b/sc/source/ui/inc/pivotsh.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/shell.hxx>
+
+#include <shellids.hxx>
+
+class ScTabViewShell;
+class ScDPObject;
+class SfxModule;
+
+class ScPivotShell final : public SfxShell
+{
+public:
+ SFX_DECL_INTERFACE(SCID_PIVOT_SHELL)
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScPivotShell(ScTabViewShell* pView);
+ virtual ~ScPivotShell() override;
+
+ void Execute(const SfxRequest& rReq);
+ void GetState(SfxItemSet& rSet);
+
+private:
+ ScTabViewShell* pViewShell;
+
+ ScDPObject* GetCurrDPObject();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/pntlock.hxx b/sc/source/ui/inc/pntlock.hxx
new file mode 100644
index 000000000..a6c569e49
--- /dev/null
+++ b/sc/source/ui/inc/pntlock.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 <rangelst.hxx>
+
+class ScPaintLockData
+{
+private:
+ ScRangeListRef xRangeList;
+ sal_uInt16 nLevel;
+ sal_uInt16 nDocLevel;
+ PaintPartFlags nParts;
+ bool bModified;
+
+public:
+ ScPaintLockData();
+ ~ScPaintLockData();
+
+ void AddRange( const ScRange& rRange, PaintPartFlags nP );
+
+ void SetModified() { bModified = true; }
+ void IncLevel(bool bDoc)
+ { if (bDoc) ++nDocLevel; else ++nLevel; }
+ void DecLevel(bool bDoc)
+ { if (bDoc) --nDocLevel; else --nLevel; }
+
+ const ScRangeListRef& GetRangeList() const { return xRangeList; }
+ PaintPartFlags GetParts() const { return nParts; }
+ sal_uInt16 GetLevel(bool bDoc) const
+ { return bDoc ? nDocLevel : nLevel; }
+ bool GetModified() const { return bModified; }
+
+ /** for recovery after reset */
+ void SetDocLevel(sal_uInt16 nNew)
+ { nDocLevel = nNew; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/preview.hxx b/sc/source/ui/inc/preview.hxx
new file mode 100644
index 000000000..606454d99
--- /dev/null
+++ b/sc/source/ui/inc/preview.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 <vcl/window.hxx>
+#include "printfun.hxx"
+#include <markdata.hxx>
+
+#include <vector>
+
+class ScDocShell;
+class ScPreviewShell;
+class FmFormView;
+
+class SAL_DLLPUBLIC_RTTI ScPreview : public vcl::Window
+{
+private:
+ ScMarkData::MarkedTabsType maSelectedTabs;
+ // set:
+ tools::Long nPageNo; // Pages in document
+ sal_uInt16 nZoom; // set Zoom
+ Point aOffset; // positive
+
+ // calculated:
+ SCTAB nTabCount;
+ SCTAB nTabsTested; // for how many sheets is nPages valid?
+ std::vector<tools::Long> nPages;
+ std::vector<tools::Long> nFirstAttr;
+ SCTAB nTab; // Sheet
+ tools::Long nTabPage; // Page of sheet
+ tools::Long nTabStart; // First (real) page of the sheet
+ tools::Long nDisplayStart; // same as above, relative to the start of counting
+ DateTime aDateTime;
+ tools::Long nTotalPages;
+ ScPrintState aState;
+ std::unique_ptr<ScPreviewLocationData> pLocationData; // stores table layout for accessibility API
+ std::unique_ptr<FmFormView> pDrawView;
+
+ // internal:
+ ScDocShell* pDocShell;
+ ScPreviewShell* pViewShell;
+
+ bool bInGetState:1;
+ bool bValid:1; // the following values true
+ bool bStateValid:1;
+ bool bLocationValid:1;
+ bool bInPaint:1;
+ bool bInSetZoom:1;
+ bool bLeftRulerMove:1;
+ bool bRightRulerMove:1;
+ bool bTopRulerMove:1;
+ bool bBottomRulerMove:1;
+ bool bHeaderRulerMove:1;
+ bool bFooterRulerMove:1;
+ bool bLeftRulerChange:1;
+ bool bRightRulerChange:1;
+ bool bTopRulerChange:1;
+ bool bBottomRulerChange:1;
+ bool bHeaderRulerChange:1;
+ bool bFooterRulerChange:1;
+ bool bPageMargin:1;
+ bool bColRulerMove:1;
+ bool mbHasEmptyRangeTable:1; /// we have at least one sheet with empty print range (print range set to '- none -').
+
+ ScRange aPageArea;
+ std::vector<tools::Long> mvRight;
+ tools::Long nLeftPosition;
+ tools::Long mnScale;
+ SCCOL nColNumberButtonDown;
+ Point aButtonDownChangePoint;
+ Point aButtonDownPt;
+ Point aButtonUpPt;
+ tools::Long nHeaderHeight;
+ tools::Long nFooterHeight;
+
+ void TestLastPage();
+ void CalcPages();
+ void RecalcPages();
+ void UpdateDrawView();
+ void DoPrint( ScPreviewLocationData* pFillLocation );
+
+ void InvalidateLocationData( SfxHintId nId );
+
+ using Window::SetZoom;
+
+protected:
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+ virtual void Command( const CommandEvent& rCEvt ) override;
+ virtual void KeyInput( const KeyEvent& rKEvt ) override;
+ virtual void MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override;
+
+public:
+ ScPreview( vcl::Window* pParent, ScDocShell* pDocSh, ScPreviewShell* pViewSh );
+ virtual ~ScPreview() override;
+ virtual void dispose() override;
+
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+
+ SC_DLLPUBLIC void DataChanged(bool bNewTime); // Instead of calling Invalidate
+ void DoInvalidate();
+
+ void SetXOffset( tools::Long nX );
+ void SetYOffset( tools::Long nY );
+ void SetZoom(sal_uInt16 nNewZoom);
+ SC_DLLPUBLIC void SetPageNo( tools::Long nPage );
+
+ bool GetPageMargins() const { return bPageMargin; }
+ void SetPageMargins( bool bVal ) { bPageMargin = bVal; }
+ void DrawInvert( tools::Long nDragPos, PointerStyle nFlags );
+ void DragMove( tools::Long nDragMovePos, PointerStyle nFlags );
+
+ const ScPreviewLocationData& GetLocationData();
+
+ OUString GetPosString();
+
+ tools::Long GetPageNo() const { return nPageNo; }
+ sal_uInt16 GetZoom() const { return nZoom; }
+ const Point& GetOffset() const { return aOffset; }
+
+ SCTAB GetTab() { if (!bValid) { CalcPages(); RecalcPages(); } return nTab; }
+ tools::Long GetTotalPages() { if (!bValid) { CalcPages(); RecalcPages(); } return nTotalPages; }
+
+ bool AllTested() const { return bValid && nTabsTested >= nTabCount; }
+
+ sal_uInt16 GetOptimalZoom(bool bWidthOnly);
+ SC_DLLPUBLIC tools::Long GetFirstPage(SCTAB nTab);
+
+ void CalcAll() { CalcPages(); }
+ void SetInGetState(bool bSet) { bInGetState = bSet; }
+
+ DECL_DLLPRIVATE_STATIC_LINK( ScPreview, InvalidateHdl, void*, void );
+ static void StaticInvalidate();
+
+ FmFormView* GetDrawView() { return pDrawView.get(); }
+
+ SC_DLLPUBLIC void SetSelectedTabs(const ScMarkData& rMark);
+ const ScMarkData::MarkedTabsType& GetSelectedTabs() const { return maSelectedTabs; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/prevloc.hxx b/sc/source/ui/inc/prevloc.hxx
new file mode 100644
index 000000000..17a7353b7
--- /dev/null
+++ b/sc/source/ui/inc/prevloc.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 <sal/types.h>
+
+#include <address.hxx>
+
+#include <vcl/mapmod.hxx>
+#include <vcl/vclptr.hxx>
+#include <tools/gen.hxx>
+
+#include <memory>
+#include <list>
+
+#define SC_PREVIEW_MAXRANGES 4
+#define SC_PREVIEW_RANGE_EDGE 0
+#define SC_PREVIEW_RANGE_REPCOL 1
+#define SC_PREVIEW_RANGE_REPROW 2
+#define SC_PREVIEW_RANGE_TAB 3
+
+class OutputDevice;
+class ScDocument;
+struct ScPreviewLocationEntry;
+
+struct ScPreviewColRowInfo
+{
+ bool bIsHeader;
+ SCCOLROW nDocIndex;
+ tools::Long nPixelStart;
+ tools::Long nPixelEnd;
+
+ void Set( bool bHeader, SCCOLROW nIndex, tools::Long nStart, tools::Long nEnd )
+ {
+ bIsHeader = bHeader;
+ nDocIndex = nIndex;
+ nPixelStart = nStart;
+ nPixelEnd = nEnd;
+ }
+};
+
+class ScPreviewTableInfo
+{
+ SCTAB nTab;
+ SCCOL nCols;
+ SCROW nRows;
+ std::unique_ptr<ScPreviewColRowInfo[]>
+ pColInfo;
+ std::unique_ptr<ScPreviewColRowInfo[]>
+ pRowInfo;
+
+public:
+ ScPreviewTableInfo();
+ ~ScPreviewTableInfo();
+
+ SCTAB GetTab() const { return nTab; }
+ SCCOL GetCols() const { return nCols; }
+ SCROW GetRows() const { return nRows; }
+ const ScPreviewColRowInfo* GetColInfo() const { return pColInfo.get(); }
+ const ScPreviewColRowInfo* GetRowInfo() const { return pRowInfo.get(); }
+
+ void SetTab( SCTAB nNewTab );
+ void SetColInfo( SCCOL nCount, ScPreviewColRowInfo* pNewInfo );
+ void SetRowInfo( SCROW nCount, ScPreviewColRowInfo* pNewInfo );
+ void LimitToArea( const tools::Rectangle& rPixelArea );
+};
+
+class ScPreviewLocationData
+{
+public:
+ typedef std::list<std::unique_ptr<ScPreviewLocationEntry>> Entries_t;
+private:
+ VclPtr<OutputDevice> pWindow;
+ ScDocument* pDoc;
+ MapMode aCellMapMode;
+ MapMode aDrawMapMode[SC_PREVIEW_MAXRANGES];
+ tools::Rectangle aDrawRectangle[SC_PREVIEW_MAXRANGES];
+ sal_uInt8 aDrawRangeId[SC_PREVIEW_MAXRANGES];
+ sal_uInt16 nDrawRanges;
+ SCTAB nPrintTab;
+ Entries_t m_Entries;
+
+ tools::Rectangle GetOffsetPixel( const ScAddress& rCellPos, const ScRange& rRange ) const;
+
+public:
+ ScPreviewLocationData( ScDocument* pDocument, OutputDevice* pWin );
+ ~ScPreviewLocationData();
+
+ void SetCellMapMode( const MapMode& rMapMode );
+ void SetPrintTab( SCTAB nNew );
+ void Clear();
+ void AddCellRange( const tools::Rectangle& rRect, const ScRange& rRange, bool bRepCol, bool bRepRow,
+ const MapMode& rDrawMap );
+ void AddColHeaders( const tools::Rectangle& rRect, SCCOL nStartCol, SCCOL nEndCol, bool bRepCol );
+ void AddRowHeaders( const tools::Rectangle& rRect, SCROW nStartRow, SCROW nEndRow, bool bRepRow );
+ void AddHeaderFooter( const tools::Rectangle& rRect, bool bHeader, bool bLeft );
+ void AddNoteMark( const tools::Rectangle& rRect, const ScAddress& rPos );
+ void AddNoteText( const tools::Rectangle& rRect, const ScAddress& rPos );
+
+ SCTAB GetPrintTab() const { return nPrintTab; }
+
+ // Get info on visible columns/rows in the visible area
+ void GetTableInfo( const tools::Rectangle& rVisiblePixel, ScPreviewTableInfo& rInfo ) const;
+
+ sal_uInt16 GetDrawRanges() const { return nDrawRanges; }
+ void GetDrawRange( sal_uInt16 nPos, tools::Rectangle& rPixelRect, MapMode& rMapMode, sal_uInt8& rRangeId ) const;
+
+ bool GetHeaderPosition( tools::Rectangle& rHeaderRect ) const;
+ bool GetFooterPosition( tools::Rectangle& rFooterRect ) const;
+ bool IsHeaderLeft() const;
+ bool IsFooterLeft() const;
+
+ tools::Long GetNoteCountInRange( const tools::Rectangle& rVisiblePixel, bool bNoteMarks ) const;
+ bool GetNoteInRange( const tools::Rectangle& rVisiblePixel, tools::Long nIndex, bool bNoteMarks,
+ ScAddress& rCellPos, tools::Rectangle& rNoteRect ) const;
+ tools::Rectangle GetNoteInRangeOutputRect(const tools::Rectangle& rVisiblePixel, bool bNoteMarks,
+ const ScAddress& aCellPos) const;
+
+ // Check if any cells (including column/row headers) are in the visible area
+ bool HasCellsInRange( const tools::Rectangle& rVisiblePixel ) const;
+
+ void GetCellPosition( const ScAddress& rCellPos, tools::Rectangle& rCellRect ) const;
+
+ // returns the rectangle where the EditEngine draws the text of a Header Cell
+ // if bColHeader is true it returns the rectangle of the header of the column in rCellPos
+ // otherwise of the header of the row in rCellPos
+ tools::Rectangle GetHeaderCellOutputRect(const tools::Rectangle& rVisRect, const ScAddress& rCellPos, bool bColHeader) const;
+ tools::Rectangle GetCellOutputRect(const ScAddress& rCellPos) const;
+
+ // Query the range and rectangle of the main (non-repeat) cell range.
+ // Returns sal_False if not contained.
+ bool GetMainCellRange( ScRange& rRange, tools::Rectangle& rPixRect ) const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/prevwsh.hxx b/sc/source/ui/inc/prevwsh.hxx
new file mode 100644
index 000000000..5f306cb1c
--- /dev/null
+++ b/sc/source/ui/inc/prevwsh.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 <types.hxx>
+#include <scdllapi.h>
+
+#include <sfx2/viewsh.hxx>
+#include <sfx2/zoomitem.hxx>
+#include <vcl/syswin.hxx>
+
+#include <shellids.hxx>
+
+class ScDocument;
+class ScDocShell;
+class ScPreview;
+struct ScHeaderFieldData;
+class ScPreviewLocationData;
+class CommandEvent;
+class SfxViewFactory;
+
+class SC_DLLPUBLIC ScPreviewShell final : public SfxViewShell
+{
+ ScDocShell* pDocShell;
+
+ VclPtr<SystemWindow> mpFrameWindow;
+ VclPtr<ScPreview> pPreview; // Output window
+ VclPtr<ScrollBar> pHorScroll;
+ VclPtr<ScrollBar> pVerScroll;
+ VclPtr<vcl::Window> pCorner;
+
+ TriState nSourceDesignMode; // form design mode from TabView
+ SvxZoomType eZoom;
+ tools::Long nMaxVertPos;
+
+ std::unique_ptr<SfxBroadcaster> pAccessibilityBroadcaster;
+ bool GetPageSize( Size& aPageSize );
+private:
+ void Construct( vcl::Window* pParent );
+ DECL_DLLPRIVATE_LINK( ScrollHandler, ScrollBar*, void );
+ DECL_DLLPRIVATE_LINK( CloseHdl, SystemWindow&, void);
+ void DoScroll( sal_uInt16 nMode );
+ void ExitPreview();
+
+ virtual void Activate(bool bMDI) override;
+ void AdjustPosSizePixel( const Point &rPos, const Size &rSize );
+
+ virtual void InnerResizePixel( const Point &rOfs, const Size &rSize, bool inplaceEditModeChange ) override;
+ virtual void OuterResizePixel( const Point &rOfs, const Size &rSize ) override;
+
+ virtual void WriteUserData(OUString &, bool bBrowse = false) override;
+ virtual void ReadUserData(const OUString &, bool bBrowse = false) override;
+
+ virtual void WriteUserDataSequence (css::uno::Sequence < css::beans::PropertyValue >& ) override;
+ virtual void ReadUserDataSequence (const css::uno::Sequence < css::beans::PropertyValue >& ) override;
+
+public:
+ SFX_DECL_INTERFACE(SCID_PREVIEW_SHELL)
+ SFX_DECL_VIEWFACTORY(ScPreviewShell);
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ ScPreviewShell( SfxViewFrame* pViewFrame,
+ SfxViewShell* pOldSh );
+
+ virtual ~ScPreviewShell() override;
+
+ void InitStartTable(SCTAB nTab);
+
+ void UpdateScrollBars();
+ void UpdateNeededScrollBars(bool bFromZoom);
+ bool ScrollCommand( const CommandEvent& rCEvt );
+
+ void Execute( SfxRequest& rReq );
+ void GetState( SfxItemSet& rSet );
+
+ void FillFieldData( ScHeaderFieldData& rData );
+
+ TriState GetSourceDesignMode() const { return nSourceDesignMode; }
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ virtual SfxPrinter* GetPrinter( bool bCreate = false ) override;
+ virtual sal_uInt16 SetPrinter( SfxPrinter* pNewPrinter, SfxPrinterChangeFlags nDiffFlags = SFX_PRINTER_ALL ) override;
+ virtual bool HasPrintOptionsPage() const override;
+ virtual std::unique_ptr<SfxTabPage> CreatePrintOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rOptions) override;
+
+ void AddAccessibilityObject( SfxListener& rObject );
+ void RemoveAccessibilityObject( SfxListener& rObject );
+ void BroadcastAccessibility( const SfxHint &rHint );
+ bool HasAccessibilityObjects() const;
+
+ const ScPreviewLocationData& GetLocationData();
+ ScDocument& GetDocument();
+ ScPreview* GetPreview() { return pPreview; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/printfun.hxx b/sc/source/ui/inc/printfun.hxx
new file mode 100644
index 000000000..b58acd9f4
--- /dev/null
+++ b/sc/source/ui/inc/printfun.hxx
@@ -0,0 +1,399 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in 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 <map>
+#include <pagepar.hxx>
+#include <editutil.hxx>
+
+class SfxPrinter;
+class ScDocShell;
+class ScDocument;
+class ScViewData;
+class SfxItemSet;
+class ScPageHFItem;
+class EditTextObject;
+class MultiSelection;
+class ScPageBreakData;
+class ScPreviewLocationData;
+class ScPrintOptions;
+class SvxBoxItem;
+class SvxBrushItem;
+class SvxShadowItem;
+class FmFormView;
+
+#define RANGENO_NORANGE USHRT_MAX
+
+constexpr sal_Int64 PRINT_HEADER_WIDTH = o3tl::toTwips(1, o3tl::Length::cm);
+constexpr sal_Int64 PRINT_HEADER_HEIGHT = o3tl::toTwips(12.8, o3tl::Length::pt);
+
+ // Settings for headers/footers
+struct ScPrintHFParam
+{
+ bool bEnable;
+ bool bDynamic;
+ bool bShared;
+ bool bSharedFirst;
+ tools::Long nHeight; // in total (height + distance + frames)
+ tools::Long nManHeight; // set size (min when dynamic)
+ sal_uInt16 nDistance;
+ sal_uInt16 nLeft; // edges
+ sal_uInt16 nRight;
+ const ScPageHFItem* pLeft;
+ const ScPageHFItem* pRight;
+ const ScPageHFItem* pFirst;
+ const SvxBoxItem* pBorder;
+ const SvxBrushItem* pBack;
+ const SvxShadowItem* pShadow;
+};
+
+class ScPageRowEntry
+{
+private:
+ SCROW nStartRow;
+ SCROW nEndRow;
+ size_t nPagesX;
+ std::vector<bool> aHidden;
+ //! Cache Number of really visible?
+
+public:
+ ScPageRowEntry() { nStartRow = nEndRow = 0; nPagesX = 0; }
+
+ ScPageRowEntry(const ScPageRowEntry& r);
+ ScPageRowEntry& operator=(const ScPageRowEntry& r);
+
+ SCROW GetStartRow() const { return nStartRow; }
+ SCROW GetEndRow() const { return nEndRow; }
+ size_t GetPagesX() const { return nPagesX; }
+ void SetStartRow(SCROW n) { nStartRow = n; }
+ void SetEndRow(SCROW n) { nEndRow = n; }
+
+ void SetPagesX(size_t nNew);
+ void SetHidden(size_t nX);
+ bool IsHidden(size_t nX) const;
+
+ size_t CountVisible() const;
+};
+
+namespace sc
+{
+
+struct PrintPageRangesInput
+{
+ bool m_bSkipEmpty;
+ bool m_bPrintArea;
+ SCROW m_nStartRow;
+ SCROW m_nEndRow;
+ SCCOL m_nStartCol;
+ SCCOL m_nEndCol;
+ SCTAB m_nPrintTab;
+ Size m_aDocSize;
+
+ PrintPageRangesInput()
+ : m_bSkipEmpty(false)
+ , m_bPrintArea(false)
+ , m_nStartRow(0)
+ , m_nEndRow(0)
+ , m_nStartCol(0)
+ , m_nEndCol(0)
+ , m_nPrintTab(0)
+ {}
+};
+
+class PrintPageRanges
+{
+public:
+ PrintPageRanges();
+
+ // use shared_ptr to avoid copying this (potentially large) data back and forth
+ std::shared_ptr<std::vector<SCCOL>> m_xPageEndX;
+ std::shared_ptr<std::vector<SCROW>> m_xPageEndY;
+ std::shared_ptr<std::map<size_t, ScPageRowEntry>> m_xPageRows;
+
+ size_t m_nPagesX;
+ size_t m_nPagesY;
+ size_t m_nTotalY;
+
+ PrintPageRangesInput m_aInput;
+
+ bool checkIfAlreadyCalculatedAndSet(bool bSkipEmpty, bool bPrintArea,
+ SCROW nStartRow, SCROW nEndRow,
+ SCCOL nStartCol, SCCOL nEndCol,
+ SCTAB nPrintTab, Size const & aDocSize);
+
+ void calculate(ScDocument& rDoc, bool bSkipEmpty, bool bPrintArea,
+ SCROW nStartRow, SCROW nEndRow, SCCOL nStartCol, SCCOL nEndCol,
+ SCTAB nPrintTab, Size const & aDocSize);
+};
+
+}
+
+struct ScPrintState // Save Variables from ScPrintFunc
+{
+ SCTAB nPrintTab;
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ bool bPrintAreaValid; // the 4 variables above are set
+ sal_uInt16 nZoom;
+ size_t nPagesX;
+ size_t nPagesY;
+ tools::Long nTabPages;
+ tools::Long nTotalPages;
+ tools::Long nPageStart;
+ tools::Long nDocPages;
+
+ // Additional state of page ranges
+ bool bSavedStateRanges;
+ sc::PrintPageRangesInput aPrintPageRangesInput;
+ size_t nTotalY;
+ // use shared_ptr to avoid copying this (potentially large) map back and forth
+ std::shared_ptr<std::vector<SCCOL>> xPageEndX;
+ std::shared_ptr<std::vector<SCROW>> xPageEndY;
+ std::shared_ptr<std::map<size_t, ScPageRowEntry>> xPageRows;
+
+ ScPrintState()
+ : nPrintTab(0)
+ , nStartCol(0)
+ , nStartRow(0)
+ , nEndCol(0)
+ , nEndRow(0)
+ , bPrintAreaValid(false)
+ , nZoom(0)
+ , nPagesX(0)
+ , nPagesY(0)
+ , nTabPages(0)
+ , nTotalPages(0)
+ , nPageStart(0)
+ , nDocPages(0)
+ , bSavedStateRanges(false)
+ , nTotalY(0)
+ {}
+};
+
+class ScPrintFunc
+{
+private:
+ ScDocShell* pDocShell;
+ ScDocument& rDoc;
+ VclPtr<SfxPrinter> pPrinter;
+ VclPtr<OutputDevice> pDev;
+ FmFormView* pDrawView;
+
+ MapMode aOldPrinterMode; // MapMode before the call
+
+ Point aSrcOffset; // Paper-1/100 mm
+ Point aOffset; // scaled by a factor of page size
+ sal_uInt16 nManualZoom; // Zoom in Preview (percent)
+ bool bClearWin; // Clear output before
+ bool bUseStyleColor;
+ bool bIsRender;
+
+ SCTAB nPrintTab;
+ tools::Long nPageStart; // Offset for the first page
+ tools::Long nDocPages; // Number of Pages in Document
+
+ const ScRange* pUserArea; // Selection, if set in dialog
+
+ const SfxItemSet* pParamSet; // Selected template
+ bool bFromPrintState; // created from State-struct
+
+ // Parameter from template:
+ sal_uInt16 nLeftMargin;
+ sal_uInt16 nTopMargin;
+ sal_uInt16 nRightMargin;
+ sal_uInt16 nBottomMargin;
+ bool bCenterHor;
+ bool bCenterVer;
+ bool bLandscape;
+ bool bSourceRangeValid;
+
+ SvxPageUsage nPageUsage;
+ Size aPageSize; // Printer Twips
+ const SvxBoxItem* pBorderItem;
+ const SvxBrushItem* pBackgroundItem;
+ const SvxShadowItem* pShadowItem;
+
+ ScRange aLastSourceRange;
+ ScPrintHFParam aHdr;
+ ScPrintHFParam aFtr;
+ ScPageTableParam aTableParam;
+ ScPageAreaParam aAreaParam;
+
+ // Calculated values:
+ sal_uInt16 nZoom;
+ bool bPrintCurrentTable;
+ bool bMultiArea;
+ bool mbHasPrintRange;
+ tools::Long nTabPages;
+ tools::Long nTotalPages;
+
+ tools::Rectangle aPageRect; // Document Twips
+
+ MapMode aLogicMode; // Set in DoPrint
+ MapMode aOffsetMode;
+ MapMode aTwipMode;
+ double nScaleX;
+ double nScaleY;
+
+ SCCOL nRepeatStartCol;
+ SCCOL nRepeatEndCol;
+ SCROW nRepeatStartRow;
+ SCROW nRepeatEndRow;
+
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ bool bPrintAreaValid; // the 4 variables above are set
+
+ sc::PrintPageRanges m_aRanges;
+
+ std::unique_ptr<ScHeaderEditEngine> pEditEngine;
+ std::unique_ptr<SfxItemSet> pEditDefaults;
+
+ ScHeaderFieldData aFieldData;
+
+ std::vector<ScAddress> aNotePosList; // The order of notes
+
+ ScPageBreakData* pPageData; // for recording the breaks etc.
+
+public:
+ ScPrintFunc( ScDocShell* pShell, SfxPrinter* pNewPrinter, SCTAB nTab,
+ tools::Long nPage = 0, tools::Long nDocP = 0,
+ const ScRange* pArea = nullptr,
+ const ScPrintOptions* pOptions = nullptr,
+ ScPageBreakData* pData = nullptr );
+
+ ScPrintFunc( ScDocShell* pShell, SfxPrinter* pNewPrinter,
+ const ScPrintState& rState, const ScPrintOptions* pOptions );
+
+ // ctors for device other than printer - for preview and pdf:
+
+ ScPrintFunc( OutputDevice* pOutDev, ScDocShell* pShell, SCTAB nTab,
+ tools::Long nPage = 0, tools::Long nDocP = 0,
+ const ScRange* pArea = nullptr,
+ const ScPrintOptions* pOptions = nullptr );
+
+ ScPrintFunc( OutputDevice* pOutDev, ScDocShell* pShell,
+ const ScPrintState& rState,
+ const ScPrintOptions* pOptions );
+
+ ~ScPrintFunc();
+
+ static void DrawToDev( ScDocument& rDoc, OutputDevice* pDev, double nPrintFactor,
+ const tools::Rectangle& rBound, ScViewData* pViewData, bool bMetaFile );
+
+ void SetDrawView( FmFormView* pNew );
+
+ void SetOffset( const Point& rOfs );
+ void SetManualZoom( sal_uInt16 nNewZoom );
+ void SetDateTime( const DateTime& );
+
+ void SetClearFlag( bool bFlag );
+ void SetUseStyleColor( bool bFlag );
+ void SetRenderFlag( bool bFlag );
+
+ void SetExclusivelyDrawOleAndDrawObjects();//for printing selected objects without surrounding cell contents
+
+ bool UpdatePages();
+
+ void ApplyPrintSettings(); // Already called from DoPrint()
+ tools::Long DoPrint( const MultiSelection& rPageRanges,
+ tools::Long nStartPage, tools::Long nDisplayStart, bool bDoPrint,
+ ScPreviewLocationData* pLocationData );
+
+ // Query values - immediately
+
+ const Size& GetPageSize() const { return aPageSize; }
+ Size GetDataSize() const;
+ void GetScaleData( Size& rPhysSize, tools::Long& rDocHdr, tools::Long& rDocFtr );
+ tools::Long GetFirstPageNo() const { return aTableParam.nFirstPageNo; }
+
+ tools::Long GetTotalPages() const { return nTotalPages; }
+ sal_uInt16 GetZoom() const { return nZoom; }
+
+ void ResetBreaks( SCTAB nTab );
+
+ void GetPrintState(ScPrintState& rState, bool bSavePageRanges = false);
+ bool GetLastSourceRange( ScRange& rRange ) const;
+ sal_uInt16 GetLeftMargin() const{return nLeftMargin;}
+ sal_uInt16 GetRightMargin() const{return nRightMargin;}
+ sal_uInt16 GetTopMargin() const{return nTopMargin;}
+ sal_uInt16 GetBottomMargin() const{return nBottomMargin;}
+ const ScPrintHFParam& GetHeader() const {return aHdr;}
+ const ScPrintHFParam& GetFooter() const {return aFtr;}
+
+ bool HasPrintRange() const { return mbHasPrintRange;}
+
+private:
+ void Construct( const ScPrintOptions* pOptions );
+ void InitParam( const ScPrintOptions* pOptions );
+ void CalcZoom( sal_uInt16 nRangeNo );
+ void CalcPages();
+ tools::Long CountPages();
+ tools::Long CountNotePages();
+
+ bool AdjustPrintArea( bool bNew );
+
+ Size GetDocPageSize();
+
+ tools::Long TextHeight( const EditTextObject* pObject );
+ void MakeEditEngine();
+ void UpdateHFHeight( ScPrintHFParam& rParam );
+
+ void InitModes();
+
+ bool IsLeft( tools::Long nPageNo );
+ bool IsMirror( tools::Long nPageNo );
+ void MakeTableString(); // sets aTableStr
+
+ void PrintPage( tools::Long nPageNo,
+ SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ bool bDoPrint, ScPreviewLocationData* pLocationData );
+ void PrintArea( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ tools::Long nScrX, tools::Long nScrY,
+ bool bShLeft, bool bShTop, bool bShRight, bool bShBottom );
+ void LocateArea( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ tools::Long nScrX, tools::Long nScrY, bool bRepCol, bool bRepRow,
+ ScPreviewLocationData& rLocationData );
+ void PrintColHdr( SCCOL nX1, SCCOL nX2, tools::Long nScrX, tools::Long nScrY );
+ void PrintRowHdr( SCROW nY1, SCROW nY2, tools::Long nScrX, tools::Long nScrY );
+ void LocateColHdr( SCCOL nX1, SCCOL nX2, tools::Long nScrX, tools::Long nScrY,
+ bool bRepCol, ScPreviewLocationData& rLocationData );
+ void LocateRowHdr( SCROW nY1, SCROW nY2, tools::Long nScrX, tools::Long nScrY,
+ bool bRepRow, ScPreviewLocationData& rLocationData );
+ void PrintHF( tools::Long nPageNo, bool bHeader, tools::Long nStartY,
+ bool bDoPrint, ScPreviewLocationData* pLocationData );
+
+ tools::Long PrintNotes( tools::Long nPageNo, tools::Long nNoteStart, bool bDoPrint, ScPreviewLocationData* pLocationData );
+ tools::Long DoNotes( tools::Long nNoteStart, bool bDoPrint, ScPreviewLocationData* pLocationData );
+
+ void DrawBorder( tools::Long nScrX, tools::Long nScrY, tools::Long nScrW, tools::Long nScrH,
+ const SvxBoxItem* pBorderData,
+ const SvxBrushItem* pBackground,
+ const SvxShadowItem* pShadow );
+
+ void FillPageData();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/protectiondlg.hxx b/sc/source/ui/inc/protectiondlg.hxx
new file mode 100644
index 000000000..d36c8a820
--- /dev/null
+++ b/sc/source/ui/inc/protectiondlg.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>
+
+class ScTableProtection;
+
+class ScTableProtectionDlg : public weld::GenericDialogController
+{
+public:
+ ScTableProtectionDlg() = delete;
+ explicit ScTableProtectionDlg(weld::Window* pParent);
+ virtual ~ScTableProtectionDlg() override;
+
+ void SetDialogData(const ScTableProtection& rData);
+
+ void WriteData(ScTableProtection& rData) const;
+
+private:
+ void Init();
+
+ void EnableOptionalWidgets(bool bEnable);
+
+ OUString m_aSelectLockedCells;
+ OUString m_aSelectUnlockedCells;
+ OUString m_aInsertColumns;
+ OUString m_aInsertRows;
+ OUString m_aDeleteColumns;
+ OUString m_aDeleteRows;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnProtect;
+ std::unique_ptr<weld::Container> m_xPasswords;
+ std::unique_ptr<weld::Container> m_xOptions;
+ std::unique_ptr<weld::Entry> m_xPassword1Edit;
+ std::unique_ptr<weld::Entry> m_xPassword2Edit;
+ std::unique_ptr<weld::TreeView> m_xOptionsListBox;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Label> m_xProtected;
+ std::unique_ptr<weld::Label> m_xUnprotected;
+ std::unique_ptr<weld::Label> m_xInsertColumns;
+ std::unique_ptr<weld::Label> m_xInsertRows;
+ std::unique_ptr<weld::Label> m_xDeleteColumns;
+ std::unique_ptr<weld::Label> m_xDeleteRows;
+
+ void InsertEntry(const OUString& rTxt);
+
+ DECL_LINK(OKHdl, weld::Button&, void);
+ DECL_LINK(CheckBoxHdl, weld::Toggleable&, void);
+ DECL_LINK(PasswordModifyHdl, weld::Entry&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/pvfundlg.hxx b/sc/source/ui/inc/pvfundlg.hxx
new file mode 100644
index 000000000..17a20526b
--- /dev/null
+++ b/sc/source/ui/inc/pvfundlg.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/sheet/DataPilotFieldReference.hpp>
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+
+#include <vcl/weld.hxx>
+#include <pivot.hxx>
+
+#include <memory>
+#include <unordered_map>
+
+class ScDPObject;
+
+class ScDPFunctionListBox
+{
+public:
+ ScDPFunctionListBox(std::unique_ptr<weld::TreeView> xControl);
+
+ void SetSelection( PivotFunc nFuncMask );
+ PivotFunc GetSelection() const;
+
+ void set_sensitive(bool sensitive) { m_xControl->set_sensitive(sensitive); }
+ void set_selection_mode(SelectionMode eMode) { m_xControl->set_selection_mode(eMode); }
+ void connect_row_activated(const Link<weld::TreeView&, bool>& rLink) { m_xControl->connect_row_activated(rLink); }
+ int get_height_rows(int nRows) const { return m_xControl->get_height_rows(nRows); }
+ void set_size_request(int nWidth, int nHeight) { m_xControl->set_size_request(nWidth, nHeight); }
+
+private:
+ std::unique_ptr<weld::TreeView> m_xControl;
+ void FillFunctionNames();
+};
+
+class ScDPFunctionDlg : public weld::GenericDialogController
+{
+ typedef std::unordered_map< OUString, OUString > NameMapType;
+public:
+ explicit ScDPFunctionDlg(weld::Widget* pParent, const ScDPLabelDataVector& rLabelVec,
+ const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData );
+ virtual ~ScDPFunctionDlg() override;
+ PivotFunc GetFuncMask() const;
+ css::sheet::DataPilotFieldReference GetFieldRef() const;
+
+private:
+ void Init( const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData );
+
+ const OUString& GetBaseFieldName(const OUString& rLayoutName) const;
+ const OUString& GetBaseItemName(const OUString& rLayoutName) const;
+
+ /** Searches for a listbox entry, starts search at specified position. */
+ sal_Int32 FindBaseItemPos( std::u16string_view rEntry, sal_Int32 nStartPos ) const;
+
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(DblClickHdl, weld::TreeView&, bool);
+ DECL_LINK(ButtonClicked, weld::Button&, void);
+
+private:
+ std::unique_ptr<ScDPFunctionListBox> mxLbFunc;
+ std::unique_ptr<weld::Label> mxFtName;
+ std::unique_ptr<weld::ComboBox> mxLbType;
+ std::unique_ptr<weld::Label> mxFtBaseField;
+ std::unique_ptr<weld::ComboBox> mxLbBaseField;
+ std::unique_ptr<weld::Label> mxFtBaseItem;
+ std::unique_ptr<weld::ComboBox> mxLbBaseItem;
+ std::unique_ptr<weld::Button> mxBtnOk;
+ std::unique_ptr<weld::Button> mxBtnCancel;
+ std::unique_ptr<weld::Expander> mxExpander;
+
+ NameMapType maBaseFieldNameMap; // cache for base field display -> original name.
+ NameMapType maBaseItemNameMap; // cache for base item display -> original name.
+
+ const ScDPLabelDataVector& mrLabelVec; /// Data of all labels.
+ bool mbEmptyItem; /// true = Empty base item in listbox.
+};
+
+class ScDPSubtotalOptDlg;
+
+class ScDPSubtotalDlg : public weld::GenericDialogController
+{
+public:
+ explicit ScDPSubtotalDlg(weld::Widget* pParent, ScDPObject& rDPObj,
+ const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData,
+ const ScDPNameVec& rDataFields, bool bEnableLayout);
+ virtual ~ScDPSubtotalDlg() override;
+ PivotFunc GetFuncMask() const;
+
+ void FillLabelData( ScDPLabelData& rLabelData ) const;
+
+private:
+ void Init( const ScDPLabelData& rLabelData, const ScPivotFuncData& rFuncData );
+ void CloseSubdialog();
+
+ DECL_LINK( DblClickHdl, weld::TreeView&, bool );
+ DECL_LINK( RadioClickHdl, weld::Toggleable&, void );
+ DECL_LINK( ClickHdl, weld::Button&, void );
+ DECL_LINK( ButtonClicked, weld::Button&, void );
+
+private:
+ ScDPObject& mrDPObj; /// The DataPilot object (for member names).
+ const ScDPNameVec& mrDataFields; /// The list of all data field names.
+
+ ScDPLabelData maLabelData; /// Cache for sub dialog.
+ bool mbEnableLayout; /// true = Enable Layout mode controls.
+
+ std::unique_ptr<weld::RadioButton> mxRbNone;
+ std::unique_ptr<weld::RadioButton> mxRbAuto;
+ std::unique_ptr<weld::RadioButton> mxRbUser;
+ std::unique_ptr<ScDPFunctionListBox> mxLbFunc;
+ std::unique_ptr<weld::Label> mxFtName;
+ std::unique_ptr<weld::CheckButton> mxCbShowAll;
+ std::unique_ptr<weld::Button> mxBtnOk;
+ std::unique_ptr<weld::Button> mxBtnCancel;
+ std::unique_ptr<weld::Button> mxBtnOptions;
+
+ std::shared_ptr<ScDPSubtotalOptDlg> mxOptionsDlg;
+};
+
+class ScDPSubtotalOptDlg : public weld::GenericDialogController
+{
+public:
+ explicit ScDPSubtotalOptDlg(weld::Window* pParent, ScDPObject& rDPObj,
+ const ScDPLabelData& rLabelData, const ScDPNameVec& rDataFields,
+ bool bEnableLayout );
+ virtual ~ScDPSubtotalOptDlg() override;
+ void FillLabelData( ScDPLabelData& rLabelData ) const;
+
+private:
+ void Init( const ScDPNameVec& rDataFields, bool bEnableLayout );
+ void InitHideListBox();
+
+ ScDPName GetFieldName(const OUString& rLayoutName) const;
+
+ /** Searches for a listbox entry, starts search at specified position. */
+ sal_Int32 FindListBoxEntry( const weld::ComboBox& rLBox, std::u16string_view rEntry, sal_Int32 nStartPos ) const;
+
+ DECL_LINK( RadioClickHdl, weld::Toggleable&, void );
+ DECL_LINK( CheckHdl, weld::Toggleable&, void );
+ DECL_LINK( SelectHdl, weld::ComboBox&, void );
+ DECL_LINK( ButtonClicked, weld::Button&, void );
+
+private:
+ std::unique_ptr<weld::ComboBox> m_xLbSortBy;
+ std::unique_ptr<weld::RadioButton> m_xRbSortAsc;
+ std::unique_ptr<weld::RadioButton> m_xRbSortDesc;
+ std::unique_ptr<weld::RadioButton> m_xRbSortMan;
+ std::unique_ptr<weld::Widget> m_xLayoutFrame;
+ std::unique_ptr<weld::ComboBox> m_xLbLayout;
+ std::unique_ptr<weld::CheckButton> m_xCbLayoutEmpty;
+ std::unique_ptr<weld::CheckButton> m_xCbRepeatItemLabels;
+ std::unique_ptr<weld::CheckButton> m_xCbShow;
+ std::unique_ptr<weld::SpinButton> m_xNfShow;
+ std::unique_ptr<weld::Label> m_xFtShow;
+ std::unique_ptr<weld::Label> m_xFtShowFrom;
+ std::unique_ptr<weld::ComboBox> m_xLbShowFrom;
+ std::unique_ptr<weld::Label> m_xFtShowUsing;
+ std::unique_ptr<weld::ComboBox> m_xLbShowUsing;
+ std::unique_ptr<weld::Widget> m_xHideFrame;
+ std::unique_ptr<weld::TreeView> m_xLbHide;
+ std::unique_ptr<weld::Label> m_xFtHierarchy;
+ std::unique_ptr<weld::ComboBox> m_xLbHierarchy;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+ ScDPObject& mrDPObj; /// The DataPilot object (for member names).
+ ScDPLabelData maLabelData; /// Cache for members data.
+
+ typedef std::unordered_map<OUString, ScDPName> NameMapType;
+ NameMapType maDataFieldNameMap; /// Cache for displayed name to field name mapping.
+};
+
+class ScDPShowDetailDlg : public weld::GenericDialogController
+{
+public:
+ explicit ScDPShowDetailDlg(weld::Window* pParent, ScDPObject& rDPObj,
+ css::sheet::DataPilotFieldOrientation nOrient);
+ virtual ~ScDPShowDetailDlg() override;
+
+ virtual short run() override;
+
+ /**
+ * @return String internal name of the selected field. Note that this may
+ * be different from the name displayed in the dialog if the field
+ * has a layout name.
+ */
+ OUString GetDimensionName() const;
+
+private:
+ DECL_LINK(DblClickHdl, weld::TreeView&, bool);
+
+private:
+ typedef std::unordered_map<OUString, tools::Long> DimNameIndexMap;
+ DimNameIndexMap maNameIndexMap;
+ ScDPObject& mrDPObj;
+
+ std::unique_ptr<weld::TreeView> mxLbDims;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/redcom.hxx b/sc/source/ui/inc/redcom.hxx
new file mode 100644
index 000000000..893b8cf1a
--- /dev/null
+++ b/sc/source/ui/inc/redcom.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 <tools/link.hxx>
+#include <vcl/vclptr.hxx>
+
+namespace weld { class Window; }
+class ScChangeAction;
+class SfxItemSet;
+class ScDocShell;
+class AbstractSvxPostItDialog;
+
+class ScRedComDialog final
+{
+ ScChangeAction *pChangeAction;
+ ScDocShell *pDocShell;
+ OUString aComment;
+ VclPtr<AbstractSvxPostItDialog> pDlg;
+
+ DECL_LINK( PrevHdl, AbstractSvxPostItDialog&, void );
+ DECL_LINK( NextHdl, AbstractSvxPostItDialog&, void );
+
+ void ReInit(ScChangeAction *);
+ void SelectCell();
+
+ ScChangeAction *FindPrev(ScChangeAction *pAction);
+ ScChangeAction *FindNext(ScChangeAction *pAction);
+
+public:
+
+ ScRedComDialog( weld::Window* pParent, const SfxItemSet& rCoreSet,
+ ScDocShell *pShell, ScChangeAction *pAction, bool bPrevNext);
+ ~ScRedComDialog();
+
+ void Execute();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/reffact.hxx b/sc/source/ui/inc/reffact.hxx
new file mode 100644
index 000000000..d6c2b1d2c
--- /dev/null
+++ b/sc/source/ui/inc/reffact.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <sfx2/childwin.hxx>
+#include "ChildWindowWrapper.hxx"
+
+#include <sc.hrc>
+
+#define DECL_WRAPPER_WITHID(Class) \
+ class Class : public SfxChildWindow \
+ { \
+ public: \
+ Class( vcl::Window*, sal_uInt16, SfxBindings*, const SfxChildWinInfo* ); \
+ SFX_DECL_CHILDWINDOW_WITHID(Class); \
+ };
+
+DECL_WRAPPER_WITHID(ScNameDlgWrapper)
+DECL_WRAPPER_WITHID(ScNameDefDlgWrapper)
+DECL_WRAPPER_WITHID(ScSolverDlgWrapper)
+DECL_WRAPPER_WITHID(ScOptSolverDlgWrapper)
+DECL_WRAPPER_WITHID(ScXMLSourceDlgWrapper)
+DECL_WRAPPER_WITHID(ScPivotLayoutWrapper)
+DECL_WRAPPER_WITHID(ScTabOpDlgWrapper)
+DECL_WRAPPER_WITHID(ScFilterDlgWrapper)
+DECL_WRAPPER_WITHID(ScSpecialFilterDlgWrapper)
+DECL_WRAPPER_WITHID(ScDbNameDlgWrapper)
+DECL_WRAPPER_WITHID(ScConsolidateDlgWrapper)
+DECL_WRAPPER_WITHID(ScPrintAreasDlgWrapper)
+DECL_WRAPPER_WITHID(ScColRowNameRangesDlgWrapper)
+DECL_WRAPPER_WITHID(ScFormulaDlgWrapper)
+DECL_WRAPPER_WITHID(ScHighlightChgDlgWrapper)
+DECL_WRAPPER_WITHID(ScCondFormatDlgWrapper)
+
+class ScDescriptiveStatisticsDialogWrapper :
+ public ChildControllerWrapper<SID_DESCRIPTIVE_STATISTICS_DIALOG>
+{
+private:
+ ScDescriptiveStatisticsDialogWrapper() = delete;
+};
+
+class ScSamplingDialogWrapper :
+ public ChildControllerWrapper<SID_SAMPLING_DIALOG>
+{
+private:
+ ScSamplingDialogWrapper() = delete;
+};
+
+class ScRandomNumberGeneratorDialogWrapper :
+ public ChildControllerWrapper<SID_RANDOM_NUMBER_GENERATOR_DIALOG>
+{
+private:
+ ScRandomNumberGeneratorDialogWrapper() = delete;
+};
+
+class ScAnalysisOfVarianceDialogWrapper :
+ public ChildControllerWrapper<SID_ANALYSIS_OF_VARIANCE_DIALOG>
+{
+private:
+ ScAnalysisOfVarianceDialogWrapper() = delete;
+};
+
+class ScCorrelationDialogWrapper :
+ public ChildControllerWrapper<SID_CORRELATION_DIALOG>
+{
+private:
+ ScCorrelationDialogWrapper() = delete;
+};
+
+class ScCovarianceDialogWrapper :
+ public ChildControllerWrapper<SID_COVARIANCE_DIALOG>
+{
+private:
+ ScCovarianceDialogWrapper() = delete;
+};
+
+class ScExponentialSmoothingDialogWrapper :
+ public ChildControllerWrapper<SID_EXPONENTIAL_SMOOTHING_DIALOG>
+{
+private:
+ ScExponentialSmoothingDialogWrapper() = delete;
+};
+
+class ScMovingAverageDialogWrapper :
+ public ChildControllerWrapper<SID_MOVING_AVERAGE_DIALOG>
+{
+private:
+ ScMovingAverageDialogWrapper() = delete;
+};
+
+class ScRegressionDialogWrapper :
+ public ChildControllerWrapper<SID_REGRESSION_DIALOG>
+{
+private:
+ ScRegressionDialogWrapper() = delete;
+};
+
+class ScTTestDialogWrapper :
+ public ChildControllerWrapper<SID_TTEST_DIALOG>
+{
+private:
+ ScTTestDialogWrapper() = delete;
+};
+
+class ScFTestDialogWrapper :
+ public ChildControllerWrapper<SID_FTEST_DIALOG>
+{
+private:
+ ScFTestDialogWrapper() = delete;
+};
+
+class ScZTestDialogWrapper :
+ public ChildControllerWrapper<SID_ZTEST_DIALOG>
+{
+private:
+ ScZTestDialogWrapper() = delete;
+};
+
+class ScChiSquareTestDialogWrapper :
+ public ChildControllerWrapper<SID_CHI_SQUARE_TEST_DIALOG>
+{
+private:
+ ScChiSquareTestDialogWrapper() = delete;
+};
+
+class ScFourierAnalysisDialogWrapper :
+ public ChildControllerWrapper<SID_FOURIER_ANALYSIS_DIALOG>
+{
+private:
+ ScFourierAnalysisDialogWrapper() = delete;
+};
+
+namespace sc
+{
+/** Wrapper for the sparkline properties dialog */
+class SparklineDialogWrapper :
+ public ChildControllerWrapper<SID_SPARKLINE_DIALOG>
+{
+private:
+ SparklineDialogWrapper() = delete;
+};
+
+/** Wrapper for the sparkline data range dialog */
+class SparklineDataRangeDialogWrapper :
+ public ChildControllerWrapper<SID_SPARKLINE_DATA_RANGE_DIALOG>
+{
+private:
+ SparklineDataRangeDialogWrapper() = delete;
+};
+
+}
+
+class ScAcceptChgDlgWrapper : public SfxChildWindow
+{
+public:
+ ScAcceptChgDlgWrapper( vcl::Window*,
+ sal_uInt16,
+ SfxBindings*,
+ SfxChildWinInfo* );
+
+ SFX_DECL_CHILDWINDOW_WITHID(Class);
+
+ void ReInitDlg();
+};
+
+class ScSimpleRefDlgWrapper: public SfxChildWindow
+{
+public:
+ ScSimpleRefDlgWrapper(vcl::Window*,
+ sal_uInt16,
+ SfxBindings*,
+ SfxChildWinInfo*);
+
+ SFX_DECL_CHILDWINDOW_WITHID(Class);
+
+ void SetRefString(const OUString& rStr);
+ void SetCloseHdl( const Link<const OUString*,void>& rLink );
+ void SetUnoLinks( const Link<const OUString&,void>& rDone, const Link<const OUString&,void>& rAbort,
+ const Link<const OUString&,void>& rChange );
+ void SetFlags( bool bCloseOnButtonUp, bool bSingleCell, bool bMultiSelection );
+ static void SetAutoReOpen(bool bFlag);
+
+ void StartRefInput();
+};
+
+class ScValidityRefChildWin : public SfxChildWindow
+{
+ bool m_bVisibleLock:1;
+ bool m_bFreeWindowLock:1;
+public:
+ ScValidityRefChildWin( vcl::Window*, sal_uInt16, const SfxBindings*, SfxChildWinInfo* );
+ SFX_DECL_CHILDWINDOW_WITHID(ScValidityRefChildWin);
+ virtual ~ScValidityRefChildWin() override;
+ bool LockVisible( bool bLock ){ bool bVis = m_bVisibleLock; m_bVisibleLock = bLock; return bVis; }
+ bool LockFreeWindow( bool bLock ){ bool bFreeWindow = m_bFreeWindowLock; m_bFreeWindowLock = bLock; return bFreeWindow; }
+ void Hide() override { if( !m_bVisibleLock) SfxChildWindow::Hide(); }
+ void Show( ShowFlags nFlags ) override { if( !m_bVisibleLock ) SfxChildWindow::Show( nFlags ); }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/refundo.hxx b/sc/source/ui/inc/refundo.hxx
new file mode 100644
index 000000000..bf0eb62e9
--- /dev/null
+++ b/sc/source/ui/inc/refundo.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 <memory>
+#include <scdllapi.h>
+
+class ScDocument;
+class ScDBCollection;
+class ScRangeName;
+class ScPrintRangeSaver;
+class ScDPCollection;
+class ScDetOpList;
+class ScChartListenerCollection;
+class ScAreaLinkSaveCollection;
+class ScUnoRefList;
+
+class SC_DLLPUBLIC ScRefUndoData
+{
+private:
+ std::unique_ptr<ScDBCollection> pDBCollection;
+ std::unique_ptr<ScRangeName> pRangeName;
+ std::unique_ptr<ScPrintRangeSaver> pPrintRanges;
+ std::unique_ptr<ScDPCollection> pDPCollection;
+ std::unique_ptr<ScDetOpList> pDetOpList;
+ std::unique_ptr<ScChartListenerCollection> pChartListenerCollection;
+ std::unique_ptr<ScAreaLinkSaveCollection> pAreaLinks;
+ std::unique_ptr<ScUnoRefList> pUnoRefs;
+
+public:
+ ScRefUndoData( const ScDocument* pDoc );
+ ~ScRefUndoData();
+
+ void DeleteUnchanged( const ScDocument* pDoc );
+ void DoUndo( ScDocument* pDoc, bool bUndoRefFirst );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/retypepassdlg.hxx b/sc/source/ui/inc/retypepassdlg.hxx
new file mode 100644
index 000000000..cf4598c3f
--- /dev/null
+++ b/sc/source/ui/inc/retypepassdlg.hxx
@@ -0,0 +1,128 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <tabprotection.hxx>
+#include <memory>
+
+class ScDocument;
+
+struct PassFragment
+{
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Container> m_xSheetsBox;
+ std::unique_ptr<weld::Label> m_xName;
+ std::unique_ptr<weld::Label> m_xStatus;
+ std::unique_ptr<weld::Button> m_xButton;
+
+ PassFragment(weld::Widget* pParent);
+};
+
+class ScRetypePassDlg : public weld::GenericDialogController
+{
+public:
+ explicit ScRetypePassDlg(weld::Window* pParent);
+ virtual ~ScRetypePassDlg() override;
+
+ virtual short run() override;
+
+ void SetDataFromDocument(const ScDocument& rDoc);
+ void SetDesiredHash(ScPasswordHash eHash);
+
+ /** Write the new set of password data to the document instance to
+ overwrite the current ones. */
+ void WriteNewDataToDocument(ScDocument& rDoc) const;
+
+private:
+ void Init();
+ void PopulateDialog();
+ void SetDocData();
+ void SetTableData(size_t nRowPos, SCTAB nTab);
+
+ /** Check the status of all hash values to see if it's okay to enable
+ the OK button. */
+ void CheckHashStatus();
+
+ void DeleteSheets();
+
+private:
+ OUString maTextNotProtected;
+ OUString maTextNotPassProtected;
+ OUString maTextHashBad;
+ OUString maTextHashGood;
+
+ DECL_LINK(OKHdl, weld::Button&, void);
+ DECL_LINK(RetypeBtnHdl, weld::Button&, void);
+
+ struct TableItem
+ {
+ OUString maName;
+ std::shared_ptr<ScTableProtection> mpProtect;
+ };
+ ::std::vector<TableItem> maTableItems;
+
+ std::shared_ptr<ScDocProtection> mpDocItem;
+ ScPasswordHash meDesiredHash;
+
+ std::unique_ptr<weld::Button> mxBtnOk;
+ std::unique_ptr<weld::Label> mxTextDocStatus;
+ std::unique_ptr<weld::Button> mxBtnRetypeDoc;
+ std::unique_ptr<weld::ScrolledWindow> mxScrolledWindow;
+ std::unique_ptr<weld::Container> mxSheetsBox;
+ std::vector<std::unique_ptr<PassFragment>> maSheets;
+};
+
+class ScRetypePassInputDlg : public weld::GenericDialogController
+{
+public:
+ ScRetypePassInputDlg() = delete;
+ explicit ScRetypePassInputDlg(weld::Window* pParent, ScPassHashProtectable* pProtected);
+ virtual ~ScRetypePassInputDlg() override;
+
+ bool IsRemovePassword() const;
+ OUString GetNewPassword() const;
+
+private:
+ void Init();
+ void CheckPasswordInput();
+
+private:
+ ScPassHashProtectable* m_pProtected;
+
+ std::unique_ptr<weld::Button> m_xBtnOk;
+
+ std::unique_ptr<weld::RadioButton> m_xBtnRetypePassword;
+
+ std::unique_ptr<weld::Widget> m_xPasswordGrid;
+ std::unique_ptr<weld::Entry> m_xPassword1Edit;
+ std::unique_ptr<weld::Entry> m_xPassword2Edit;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnMatchOldPass;
+
+ std::unique_ptr<weld::RadioButton> m_xBtnRemovePassword;
+
+ DECL_LINK(OKHdl, weld::Button&, void);
+ DECL_LINK(RadioBtnHdl, weld::Toggleable&, void);
+ DECL_LINK(CheckBoxHdl, weld::Toggleable&, void);
+ DECL_LINK(PasswordModifyHdl, weld::Entry&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/rfindlst.hxx b/sc/source/ui/inc/rfindlst.hxx
new file mode 100644
index 000000000..bd8f6cff1
--- /dev/null
+++ b/sc/source/ui/inc/rfindlst.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 <tools/color.hxx>
+#include <address.hxx>
+#include <tools/solar.h>
+
+#include <vector>
+
+struct ScRangeFindData
+{
+ ScRange aRef;
+ ScRefFlags nFlags;
+ sal_Int32 nSelStart;
+ sal_Int32 nSelEnd;
+ Color nColor;
+
+ ScRangeFindData( const ScRange& rR, ScRefFlags nF, sal_Int32 nS, sal_Int32 nE ) :
+ aRef(rR), nFlags(nF), nSelStart(nS), nSelEnd(nE) {}
+};
+
+class ScRangeFindList
+{
+ std::vector<ScRangeFindData> maEntries;
+ OUString aDocName;
+ bool bHidden;
+ sal_uInt16 nIndexColor;
+
+public:
+ ScRangeFindList(const OUString& rName);
+
+ sal_uLong Count() const { return maEntries.size(); }
+ Color Insert( const ScRangeFindData &rNew );
+
+ ScRangeFindData& GetObject( sal_uLong nIndex ) { return maEntries[nIndex]; }
+
+ void SetHidden( bool bSet ) { bHidden = bSet; }
+
+ const OUString& GetDocName() const { return aDocName; }
+ bool IsHidden() const { return bHidden; }
+
+ static Color GetColorName(const size_t nIndex);
+ Color FindColor(const ScRange& rRef, const size_t nIndex);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/scendlg.hxx b/sc/source/ui/inc/scendlg.hxx
new file mode 100644
index 000000000..07ee1f3ef
--- /dev/null
+++ b/sc/source/ui/inc/scendlg.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 <vcl/weld.hxx>
+
+enum class ScScenarioFlags;
+
+class ColorListBox;
+
+class ScNewScenarioDlg : public weld::GenericDialogController
+{
+public:
+ ScNewScenarioDlg(weld::Window* pParent, const OUString& rName, bool bEdit, bool bSheetProtected);
+ virtual ~ScNewScenarioDlg() override;
+ void SetScenarioData( const OUString& rName, const OUString& rComment,
+ const Color& rColor, ScScenarioFlags nFlags );
+
+ void GetScenarioData(OUString& rName, OUString& rComment,
+ Color& rColor, ScScenarioFlags &rFlags) const;
+
+private:
+ OUString aDefScenarioName;
+ bool bIsEdit;
+ std::unique_ptr<weld::Entry> m_xEdName;
+ std::unique_ptr<weld::TextView> m_xEdComment;
+ std::unique_ptr<weld::CheckButton> m_xCbShowFrame;
+ std::unique_ptr<ColorListBox> m_xLbColor;
+ std::unique_ptr<weld::CheckButton> m_xCbTwoWay;
+ std::unique_ptr<weld::CheckButton> m_xCbCopyAll;
+ std::unique_ptr<weld::CheckButton> m_xCbProtect;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Label> m_xAltTitle;
+ std::unique_ptr<weld::Label> m_xCreatedFt;
+ std::unique_ptr<weld::Label> m_xOnFt;
+
+ DECL_LINK(OkHdl, weld::Button&, void);
+ DECL_LINK(EnableHdl, weld::Toggleable&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/scui_def.hxx b/sc/source/ui/inc/scui_def.hxx
new file mode 100644
index 000000000..af4252ba4
--- /dev/null
+++ b/sc/source/ui/inc/scui_def.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 <o3tl/typed_flags_set.hxx>
+
+#define SCRET_COLS 0x42
+#define SCRET_ROWS 0x43
+
+#define FDS_OPT_NONE 0 // from filldlg.hxx
+#define FDS_OPT_HORZ 1 // from filldlg.hxx
+#define FDS_OPT_VERT 2 // from filldlg.hxx
+
+enum class InsertContentsFlags {
+ NONE = 0x00,
+ NoEmpty = 0x01, //from inscodlg.hxx
+ Trans = 0x02, //from inscodlg.hxx
+ Link = 0x04 //from inscodlg.hxx
+};
+namespace o3tl {
+ template<> struct typed_flags<InsertContentsFlags> : is_typed_flags<InsertContentsFlags, 0x07> {};
+}
+
+enum class CellShiftDisabledFlags {
+ NONE = 0x00,
+ Down = 0x01, //from inscodlg.hxx
+ Right = 0x02 //from inscodlg.hxx
+};
+namespace o3tl {
+ template<> struct typed_flags<CellShiftDisabledFlags> : is_typed_flags<CellShiftDisabledFlags, 0x3> {};
+}
+
+enum class CreateNameFlags {
+ NONE = 0,
+ Top = 1, //from namecrea.hxx
+ Left = 2, //from namecrea.hxx
+ Bottom = 4, //from namecrea.hxx
+ Right = 8, //from namecrea.hxx
+};
+namespace o3tl {
+ template<> struct typed_flags<CreateNameFlags> : is_typed_flags<CreateNameFlags, 0xf> {};
+}
+
+#define BTN_PASTE_NAME 100 // from namepast.hxx
+#define BTN_PASTE_LIST 101 // from namepast.hxx
+#define BTN_PASTE_CLOSE 102 // from namepast.hxx
+
+#define BTN_EXTEND_RANGE 150
+#define BTN_CURRENT_SELECTION 151
+#define SCRET_REMOVE 0x42 //from subtdlg.hxx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/scuiasciiopt.hxx b/sc/source/ui/inc/scuiasciiopt.hxx
new file mode 100644
index 000000000..ee7f512b3
--- /dev/null
+++ b/sc/source/ui/inc/scuiasciiopt.hxx
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in 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/langbox.hxx>
+#include <tools/solar.h>
+#include <tools/stream.hxx>
+#include <vcl/weld.hxx>
+
+#include "asciiopt.hxx"
+
+class ScCsvTableBox;
+class SvxTextEncodingBox;
+
+class ScImportAsciiDlg : public weld::GenericDialogController
+{
+ SvStream* mpDatStream;
+ sal_uLong mnStreamPos;
+ std::unique_ptr<sal_uLong[]> mpRowPosArray;
+ sal_uLong mnRowPosCount;
+
+ OUString maPreviewLine[ CSV_PREVIEW_LINES ];
+
+ OUString maFieldSeparators; // selected field separators
+ sal_Unicode mcTextSep;
+
+ rtl_TextEncoding meCharSet; /// Selected char set.
+ bool mbCharSetSystem; /// Is System char set selected?
+ ScImportAsciiCall meCall; /// How the dialog is called (see asciiopt.hxx)
+ bool mbDetectSep; /// Whether to detect a possible separator.
+
+ std::unique_ptr<weld::Label> mxFtCharSet;
+ std::unique_ptr<SvxTextEncodingBox> mxLbCharSet;
+ std::unique_ptr<weld::Label> mxFtCustomLang;
+ std::unique_ptr<SvxLanguageBox> mxLbCustomLang;
+
+ std::unique_ptr<weld::Label> mxFtRow;
+ std::unique_ptr<weld::SpinButton> mxNfRow;
+
+ std::unique_ptr<weld::RadioButton> mxRbFixed;
+ std::unique_ptr<weld::RadioButton> mxRbSeparated;
+
+ std::unique_ptr<weld::CheckButton> mxCkbTab;
+ std::unique_ptr<weld::CheckButton> mxCkbSemicolon;
+ std::unique_ptr<weld::CheckButton> mxCkbComma;
+ std::unique_ptr<weld::CheckButton> mxCkbRemoveSpace;
+ std::unique_ptr<weld::CheckButton> mxCkbSpace;
+ std::unique_ptr<weld::CheckButton> mxCkbOther;
+ std::unique_ptr<weld::Entry> mxEdOther;
+ std::unique_ptr<weld::CheckButton> mxCkbAsOnce;
+
+ std::unique_ptr<weld::Label> mxFtTextSep;
+ std::unique_ptr<weld::ComboBox> mxCbTextSep;
+
+ std::unique_ptr<weld::CheckButton> mxCkbQuotedAsText;
+ std::unique_ptr<weld::CheckButton> mxCkbDetectNumber;
+ std::unique_ptr<weld::CheckButton> mxCkbEvaluateFormulas;
+ std::unique_ptr<weld::CheckButton> mxCkbSkipEmptyCells;
+
+ std::unique_ptr<weld::Label> mxFtType;
+ std::unique_ptr<weld::ComboBox> mxLbType;
+ std::unique_ptr<weld::Label> mxAltTitle;
+
+ std::unique_ptr<ScCsvTableBox> mxTableBox;
+
+public:
+ ScImportAsciiDlg(
+ weld::Window* pParent, const OUString& aDatName,
+ SvStream* pInStream, ScImportAsciiCall eCall );
+ virtual ~ScImportAsciiDlg() override;
+
+ void GetOptions( ScAsciiOptions& rOpt );
+ void SaveParameters();
+
+private:
+ /** Sets the selected char set data to meCharSet and mbCharSetSystem. */
+ void SetSelectedCharSet();
+ /** Set separators in ui from maFieldSeparators or an optionally defined
+ separator. */
+ void SetSeparators( sal_Unicode cSep );
+ /** Returns all separator characters in a string. */
+ OUString GetSeparators() const;
+
+ /** Enables or disables all separator checkboxes and edit fields. */
+ void SetupSeparatorCtrls();
+
+ bool GetLine( sal_uLong nLine, OUString &rText, sal_Unicode& rcDetectSep );
+ void UpdateVertical();
+ inline bool Seek( sal_uLong nPos ); // synced to and from mnStreamPos
+ void RbSepFix();
+
+ DECL_LINK( CharSetHdl, weld::ComboBox&, void );
+ DECL_LINK( FirstRowHdl, weld::SpinButton&, void );
+ DECL_LINK( RbSepFixHdl, weld::Toggleable&, void );
+ DECL_LINK( SeparatorEditHdl, weld::Entry&, void );
+ DECL_LINK( SeparatorClickHdl, weld::Toggleable&, void );
+ DECL_LINK( SeparatorComboBoxHdl, weld::ComboBox&, void );
+ void SeparatorHdl(const weld::Widget*);
+ DECL_LINK( LbColTypeHdl, weld::ComboBox&, void );
+ DECL_LINK( UpdateTextHdl, ScCsvTableBox&, void );
+ DECL_LINK( ColTypeHdl, ScCsvTableBox&, void );
+ DECL_STATIC_LINK(ScImportAsciiDlg, InstallLOKNotifierHdl, void*, vcl::ILibreOfficeKitNotifier*);
+
+};
+
+inline bool ScImportAsciiDlg::Seek(sal_uLong nPos)
+{
+ bool bSuccess = true;
+ if (nPos != mnStreamPos && mpDatStream)
+ {
+ if (mpDatStream->Seek( nPos ) != nPos)
+ bSuccess = false;
+ else
+ mnStreamPos = nPos;
+ }
+ return bSuccess;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/scuiautofmt.hxx b/sc/source/ui/inc/scuiautofmt.hxx
new file mode 100644
index 000000000..a89d508a2
--- /dev/null
+++ b/sc/source/ui/inc/scuiautofmt.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 <vcl/customweld.hxx>
+#include <autoform.hxx>
+#include "autofmt.hxx"
+
+class ScAutoFormatDlg : public weld::GenericDialogController
+{
+public:
+ ScAutoFormatDlg(weld::Window* pParent,
+ ScAutoFormat* pAutoFormat,
+ const ScAutoFormatData* pSelFormatData,
+ const ScViewData& rViewData);
+ virtual ~ScAutoFormatDlg() override;
+
+ sal_uInt16 GetIndex() const { return nIndex; }
+ OUString GetCurrFormatName();
+
+private:
+ OUString aStrTitle;
+ OUString aStrLabel;
+ OUString aStrClose;
+ OUString aStrDelMsg;
+ OUString aStrRename;
+
+ ScAutoFormat* pFormat;
+ const ScAutoFormatData* pSelFmtData;
+ sal_uInt16 nIndex;
+ bool bCoreDataChanged;
+ bool bFmtInserted;
+
+ ScAutoFmtPreview m_aWndPreview;
+ std::unique_ptr<weld::TreeView> m_xLbFormat;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+ std::unique_ptr<weld::Button> m_xBtnAdd;
+ std::unique_ptr<weld::Button> m_xBtnRemove;
+ std::unique_ptr<weld::Button> m_xBtnRename;
+ std::unique_ptr<weld::CheckButton> m_xBtnNumFormat;
+ std::unique_ptr<weld::CheckButton> m_xBtnBorder;
+ std::unique_ptr<weld::CheckButton> m_xBtnFont;
+ std::unique_ptr<weld::CheckButton> m_xBtnPattern;
+ std::unique_ptr<weld::CheckButton> m_xBtnAlignment;
+ std::unique_ptr<weld::CheckButton> m_xBtnAdjust;
+ std::unique_ptr<weld::CustomWeld> m_xWndPreview;
+
+ void Init ();
+ void UpdateChecks ();
+
+ DECL_LINK( CheckHdl, weld::Toggleable&, void );
+ DECL_LINK( AddHdl, weld::Button&, void );
+ DECL_LINK( RemoveHdl, weld::Button&, void );
+ DECL_LINK( SelFmtHdl, weld::TreeView&, void );
+ DECL_LINK( CloseHdl, weld::Button&, void );
+ DECL_LINK( DblClkHdl, weld::TreeView&, bool );
+ DECL_LINK( RenameHdl, weld::Button&, void );
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/scuiimoptdlg.hxx b/sc/source/ui/inc/scuiimoptdlg.hxx
new file mode 100644
index 000000000..03d488524
--- /dev/null
+++ b/sc/source/ui/inc/scuiimoptdlg.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 <vcl/weld.hxx>
+
+class ScDelimiterTable;
+class ScImportOptions;
+class SvxTextEncodingBox;
+class SvxTextEncodingTreeView;
+
+class ScImportOptionsDlg : public weld::GenericDialogController
+{
+public:
+ ScImportOptionsDlg(weld::Window* pParent,
+ bool bAscii,
+ const ScImportOptions* pOptions,
+ const OUString* pStrTitle,
+ bool bMultiByte,
+ bool bOnlyDbtoolsEncodings,
+ bool bImport);
+
+ virtual ~ScImportOptionsDlg() override;
+
+ void GetImportOptions( ScImportOptions& rOptions ) const;
+ void SaveImportOptions() const;
+
+private:
+ std::unique_ptr<ScDelimiterTable> pFieldSepTab;
+ std::unique_ptr<ScDelimiterTable> pTextSepTab;
+
+ bool m_bIsAsciiImport;
+
+ std::unique_ptr<weld::Frame> m_xFieldFrame;
+ std::unique_ptr<weld::Label> m_xFtCharset;
+ std::unique_ptr<weld::Widget> m_xEncGrid;
+ std::unique_ptr<weld::Label> m_xFtFieldSep;
+ std::unique_ptr<weld::ComboBox> m_xEdFieldSep;
+ std::unique_ptr<weld::Label> m_xFtTextSep;
+ std::unique_ptr<weld::ComboBox> m_xEdTextSep;
+ std::unique_ptr<weld::CheckButton> m_xCbShown;
+ std::unique_ptr<weld::CheckButton> m_xCbFormulas;
+ std::unique_ptr<weld::CheckButton> m_xCbQuoteAll;
+ std::unique_ptr<weld::CheckButton> m_xCbFixed;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<SvxTextEncodingBox> m_xLbCharset;
+ std::unique_ptr<SvxTextEncodingTreeView> m_xTvCharset;
+
+private:
+ sal_uInt16 GetCodeFromCombo( const weld::ComboBox& rEd ) const;
+ void FillFromTextEncodingTable(bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags = 0);
+ void FillFromDbTextEncodingMap(bool bExcludeImportSubsets, sal_uInt32 nExcludeInfoFlags = 0);
+
+ DECL_LINK(FixedWidthHdl, weld::Toggleable&, void);
+ DECL_LINK(DoubleClickHdl, weld::TreeView&, bool);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/scuitphfedit.hxx b/sc/source/ui/inc/scuitphfedit.hxx
new file mode 100644
index 000000000..79e1077d4
--- /dev/null
+++ b/sc/source/ui/inc/scuitphfedit.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "tphfedit.hxx"
+#include <sfx2/tabdlg.hxx>
+#include <vcl/customweld.hxx>
+#include <vcl/weld.hxx>
+
+enum ScHFEntryId
+{
+ eNoneEntry ,
+ ePageEntry ,
+ ePagesEntry ,
+ eSheetEntry ,
+ eConfidentialEntry ,
+ eFileNamePageEntry ,
+ eExtFileNameEntry ,
+ ePageSheetEntry ,
+ ePageFileNameEntry ,
+ ePageExtFileNameEntry ,
+ eUserNameEntry ,
+ eCreatedByEntry ,
+ eEntryCount
+};
+
+class EditTextObject;
+class EditEngine;
+
+class ScHFEditPage : public SfxTabPage
+{
+public:
+ virtual bool FillItemSet ( SfxItemSet* rCoreSet ) override;
+ virtual void Reset ( const SfxItemSet* rCoreSet ) override;
+
+ void SetNumType(SvxNumType eNumType);
+ void ClearTextAreas();
+
+protected:
+ ScHFEditPage( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet& rCoreSet,
+ TypedWhichId<ScPageHFItem> nWhich,
+ bool bHeader );
+ virtual ~ScHFEditPage() override;
+
+private:
+ TypedWhichId<ScPageHFItem> nWhich;
+ bool m_bDropDownActive;
+ sal_Int64 m_nTimeToggled;
+
+ std::unique_ptr<weld::Label> m_xFtDefinedHF;
+ std::unique_ptr<weld::ComboBox> m_xLbDefined;
+ std::unique_ptr<weld::Label> m_xFtCustomHF;
+ std::unique_ptr<weld::Button> m_xBtnText;
+ std::unique_ptr<weld::MenuButton> m_xBtnFile;
+ std::unique_ptr<weld::Button> m_xBtnTable;
+ std::unique_ptr<weld::Button> m_xBtnPage;
+ std::unique_ptr<weld::Button> m_xBtnLastPage;
+ std::unique_ptr<weld::Button> m_xBtnDate;
+ std::unique_ptr<weld::Button> m_xBtnTime;
+
+ std::unique_ptr<weld::Label> m_xFtConfidential;
+ std::unique_ptr<weld::Label> m_xFtPage;
+ std::unique_ptr<weld::Label> m_xFtOfQuestion;
+ std::unique_ptr<weld::Label> m_xFtOf;
+ std::unique_ptr<weld::Label> m_xFtNone;
+ std::unique_ptr<weld::Label> m_xFtCreatedBy;
+ std::unique_ptr<weld::Label> m_xFtCustomized;
+
+ std::unique_ptr<weld::Widget> m_xLeft;
+ std::unique_ptr<weld::Widget> m_xRight;
+
+ std::unique_ptr<ScEditWindow> m_xWndLeft;
+ std::unique_ptr<ScEditWindow> m_xWndCenter;
+ std::unique_ptr<ScEditWindow> m_xWndRight;
+ std::unique_ptr<weld::CustomWeld> m_xWndLeftWnd;
+ std::unique_ptr<weld::CustomWeld> m_xWndCenterWnd;
+ std::unique_ptr<weld::CustomWeld> m_xWndRightWnd;
+
+ ScEditWindow * m_pEditFocus; ///one of m_pWndLeft, m_pWndCenter, m_pWndRight
+
+ DECL_LINK( ObjectSelectHdl, ScEditWindow&, void );
+
+private:
+ void InitPreDefinedList();
+ void ProcessDefinedListSel(ScHFEntryId eSel, bool bTravelling);
+ void InsertToDefinedList();
+ void RemoveFromDefinedList();
+ void SetSelectDefinedList();
+ bool IsPageEntry(EditEngine*pEngine, const EditTextObject* pTextObj);
+ static bool IsDateEntry(const EditTextObject* pTextObj);
+ static bool IsExtFileNameEntry(const EditTextObject* pTextObj);
+ DECL_LINK( ListHdl_Impl, weld::ComboBox&, void);
+ DECL_LINK( ListToggleHdl_Impl, weld::ComboBox&, void);
+ DECL_LINK( ClickHdl, weld::Button&, void );
+ DECL_LINK( MenuHdl, const OString&, void );
+};
+
+class ScFirstHeaderEditPage : public ScHFEditPage
+{
+public:
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet );
+ ScFirstHeaderEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet );
+};
+
+class ScRightHeaderEditPage : public ScHFEditPage
+{
+public:
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet );
+ ScRightHeaderEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet );
+};
+
+class ScLeftHeaderEditPage : public ScHFEditPage
+{
+public:
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet );
+ ScLeftHeaderEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet );
+};
+
+class ScFirstFooterEditPage : public ScHFEditPage
+{
+public:
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet );
+ ScFirstFooterEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet );
+};
+
+class ScRightFooterEditPage : public ScHFEditPage
+{
+public:
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet );
+ ScRightFooterEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet );
+};
+
+class ScLeftFooterEditPage : public ScHFEditPage
+{
+public:
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet );
+ ScLeftFooterEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/searchresults.hxx b/sc/source/ui/inc/searchresults.hxx
new file mode 100644
index 000000000..c10e60143
--- /dev/null
+++ b/sc/source/ui/inc/searchresults.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/.
+ */
+
+#pragma once
+
+#include <vcl/weld.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/childwin.hxx>
+
+class ScDocument;
+class ScRangeList;
+
+namespace sc {
+
+class SearchResultsDlg : public SfxDialogController
+{
+ OUString aSkipped;
+ SfxBindings* mpBindings;
+ ScDocument* mpDoc;
+ bool mbSorted;
+ std::unique_ptr<weld::TreeView> mxList;
+ std::unique_ptr<weld::Label> mxSearchResults;
+ std::unique_ptr<weld::CheckButton> mxShowDialog;
+
+ DECL_LINK(ListSelectHdl, weld::TreeView&, void);
+ DECL_LINK(HeaderBarClick, int, void);
+ DECL_STATIC_LINK(SearchResultsDlg, OnShowToggled, weld::Toggleable&, void);
+public:
+ SearchResultsDlg(SfxBindings* _pBindings, weld::Window* pParent);
+ virtual ~SearchResultsDlg() override;
+
+ virtual void Close() override;
+
+ void FillResults( ScDocument& rDoc, const ScRangeList& rMatchedRanges, bool bCellNotes, bool bEmptyCells );
+};
+
+class SearchResultsDlgWrapper : public SfxChildWindow
+{
+ std::shared_ptr<SearchResultsDlg> m_xDialog;
+public:
+ SearchResultsDlgWrapper(
+ vcl::Window* _pParent, sal_uInt16 nId, SfxBindings* pBindings, SfxChildWinInfo* pInfo );
+
+ virtual ~SearchResultsDlgWrapper() override;
+
+ SFX_DECL_CHILDWINDOW_WITHID(SearchResultsDlgWrapper);
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/select.hxx b/sc/source/ui/inc/select.hxx
new file mode 100644
index 000000000..ea3082f97
--- /dev/null
+++ b/sc/source/ui/inc/select.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 <vcl/seleng.hxx>
+
+#include "viewdata.hxx"
+
+class ScTabView;
+
+class ScViewSelectionEngine : public SelectionEngine
+{
+private:
+ ScSplitPos eWhich;
+public:
+ ScViewSelectionEngine( vcl::Window* pWindow, ScTabView* pView,
+ ScSplitPos eSplitPos );
+
+ ScSplitPos GetWhich() const { return eWhich; }
+ void SetWhich(ScSplitPos eNew) { eWhich = eNew; }
+};
+
+class ScViewFunctionSet : public FunctionSet // View (Gridwin / keyboard)
+{
+private:
+ ScViewData* pViewData;
+ ScViewSelectionEngine* pEngine;
+
+ bool bAnchor;
+ bool bStarted;
+ ScAddress aAnchorPos;
+
+ ScSplitPos GetWhich() const;
+
+ sal_uLong CalcUpdateInterval( const Size& rWinSize, const Point& rEffPos,
+ bool bLeftScroll, bool bTopScroll, bool bRightScroll, bool bBottomScroll );
+
+public:
+ ScViewFunctionSet( ScViewData* pNewViewData );
+
+ void SetSelectionEngine( ScViewSelectionEngine* pSelEngine );
+
+ void SetAnchor( SCCOL nPosX, SCROW nPosY );
+ void SetAnchorFlag( bool bSet );
+
+ virtual void BeginDrag() override;
+ virtual void CreateAnchor() override;
+ virtual void DestroyAnchor() override;
+ virtual void SetCursorAtPoint( const Point& rPointPixel, bool bDontSelectAtCursor = false ) override;
+ virtual bool IsSelectionAtPoint( const Point& rPointPixel ) override;
+ virtual void DeselectAtPoint( const Point& rPointPixel ) override;
+ virtual void DeselectAll() override;
+
+ bool SetCursorAtCell( SCCOL nPosX, SCROW nPosY, bool bScroll );
+ bool CheckRefBounds(SCCOL nPosX, SCROW nPosY);
+};
+
+class ScHeaderFunctionSet : public FunctionSet // Column / row headers
+{
+private:
+ ScViewData* pViewData;
+ bool bColumn; // Col- / Rowbar
+ ScSplitPos eWhich;
+
+ bool bAnchor;
+ SCCOLROW nCursorPos;
+
+public:
+ ScHeaderFunctionSet( ScViewData* pNewViewData );
+
+ void SetColumn( bool bSet );
+ void SetWhich( ScSplitPos eNew );
+
+ virtual void BeginDrag() override;
+ virtual void CreateAnchor() override;
+ virtual void DestroyAnchor() override;
+ virtual void SetCursorAtPoint( const Point& rPointPixel, bool bDontSelectAtCursor = false ) override;
+ virtual bool IsSelectionAtPoint( const Point& rPointPixel ) override;
+ virtual void DeselectAtPoint( const Point& rPointPixel ) override;
+ virtual void DeselectAll() override;
+
+ void SetAnchorFlag(bool bSet) { bAnchor = bSet; }
+};
+
+class ScHeaderSelectionEngine : public SelectionEngine
+{
+public:
+ ScHeaderSelectionEngine( vcl::Window* pWindow, ScHeaderFunctionSet* pFuncSet );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/selectionstate.hxx b/sc/source/ui/inc/selectionstate.hxx
new file mode 100644
index 000000000..4243e618e
--- /dev/null
+++ b/sc/source/ui/inc/selectionstate.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 <editeng/editdata.hxx>
+#include <address.hxx>
+
+/** Enumerates all possible types of selections in a Calc document. */
+enum ScSelectionType
+{
+ SC_SELECTTYPE_NONE, /// No selection, simple cell cursor.
+ SC_SELECTTYPE_SHEET, /// Single cell, cell range, or multi range selection.
+ SC_SELECTTYPE_EDITCELL, /// Cell in edit mode (with or without selection).
+};
+
+class ScViewData;
+
+/** Contains all available data about any possible selection in a Calc document. */
+class ScSelectionState
+{
+public:
+ explicit ScSelectionState( ScViewData& rViewData );
+
+ /** Returns the type of the selection this object contains. */
+ ScSelectionType GetSelectionType() const { return meType; }
+
+ /** Returns the position of the cell cursor. */
+ const ScAddress& GetCellCursor() const { return maCursor; }
+ /** Returns the edit engine selection. */
+ const ESelection& GetEditSelection() const { return maEditSel; }
+
+private:
+ ScSelectionType meType; /// Type of the selection.
+ ScAddress maCursor; /// Cell cursor position.
+ ESelection maEditSel; /// Selection in edit mode.
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/seltrans.hxx b/sc/source/ui/inc/seltrans.hxx
new file mode 100644
index 000000000..f783e58fa
--- /dev/null
+++ b/sc/source/ui/inc/seltrans.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 <vcl/transfer.hxx>
+#include <rtl/ref.hxx>
+
+class ScTabView;
+class ScTransferObj;
+class ScDrawTransferObj;
+
+enum ScSelectionTransferMode
+{
+ SC_SELTRANS_INVALID,
+ SC_SELTRANS_CELL,
+ SC_SELTRANS_CELLS,
+ SC_SELTRANS_DRAW_BITMAP,
+ SC_SELTRANS_DRAW_GRAPHIC,
+ SC_SELTRANS_DRAW_BOOKMARK,
+ SC_SELTRANS_DRAW_OLE,
+ SC_SELTRANS_DRAW_OTHER
+};
+
+class ScSelectionTransferObj : public TransferableHelper
+{
+private:
+ ScTabView* pView;
+ ScSelectionTransferMode eMode;
+ rtl::Reference<ScTransferObj> mxCellData;
+ rtl::Reference<ScDrawTransferObj> mxDrawData;
+
+ ScSelectionTransferObj( ScTabView* pSource, ScSelectionTransferMode eNewMode );
+ void CreateCellData();
+ void CreateDrawData();
+
+public:
+ // creates an object if the view has a valid selection,
+ // returns NULL otherwise
+ static rtl::Reference<ScSelectionTransferObj> CreateFromView( ScTabView* pSource );
+
+ virtual ~ScSelectionTransferObj() override;
+
+ void ForgetView();
+ ScTabView* GetView() const { return pView; }
+
+ ScTransferObj* GetCellData();
+ ScDrawTransferObj* GetDrawData();
+
+ virtual void AddSupportedFormats() override;
+ virtual bool GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& rDestDoc ) override;
+ virtual void ObjectReleased() override;
+ virtual sal_Bool SAL_CALL isComplex() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/servobj.hxx b/sc/source/ui/inc/servobj.hxx
new file mode 100644
index 000000000..2bb36aa6d
--- /dev/null
+++ b/sc/source/ui/inc/servobj.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 <svl/lstner.hxx>
+#include <svl/listener.hxx>
+#include <sfx2/linksrc.hxx>
+#include <address.hxx>
+#include <svl/SfxBroadcaster.hxx>
+
+class ScDocShell;
+class ScServerObject;
+
+class ScServerObjectSvtListenerForwarder : public SvtListener
+{
+ ScServerObject* pObj;
+ SfxBroadcaster aBroadcaster;
+public:
+ ScServerObjectSvtListenerForwarder( ScServerObject* pObjP);
+ virtual ~ScServerObjectSvtListenerForwarder() override;
+ virtual void Notify( const SfxHint& rHint ) override;
+};
+
+class ScServerObject : public ::sfx2::SvLinkSource, public SfxListener
+{
+private:
+ ScServerObjectSvtListenerForwarder aForwarder;
+ ScDocShell* pDocSh;
+ ScRange aRange;
+ OUString aItemStr;
+ bool bRefreshListener;
+
+ void Clear();
+
+public:
+ ScServerObject( ScDocShell* pShell, const OUString& rItem );
+ virtual ~ScServerObject() override;
+
+ virtual bool GetData( css::uno::Any & rData /*out param*/,
+ const OUString & rMimeType,
+ bool bSynchron = false ) override;
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+ void EndListeningAll();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/sharedocdlg.hxx b/sc/source/ui/inc/sharedocdlg.hxx
new file mode 100644
index 000000000..d6dcc4810
--- /dev/null
+++ b/sc/source/ui/inc/sharedocdlg.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 <vcl/weld.hxx>
+
+class ScViewData;
+class ScDocShell;
+
+
+class ScShareDocumentDlg : public weld::GenericDialogController
+{
+private:
+ OUString m_aStrNoUserData;
+ OUString m_aStrUnknownUser;
+ OUString m_aStrExclusiveAccess;
+
+ ScDocShell* mpDocShell;
+
+ std::unique_ptr<weld::CheckButton> m_xCbShare;
+ std::unique_ptr<weld::Label> m_xFtWarning;
+ std::unique_ptr<weld::TreeView> m_xLbUsers;
+
+ DECL_LINK(ToggleHandle, weld::Toggleable&, void);
+ DECL_LINK(SizeAllocated, const Size&, void);
+
+public:
+ ScShareDocumentDlg(weld::Window* pParent, const ScViewData* pViewData);
+ virtual ~ScShareDocumentDlg() override;
+
+ bool IsShareDocumentChecked() const;
+ void UpdateView();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/shtabdlg.hxx b/sc/source/ui/inc/shtabdlg.hxx
new file mode 100644
index 000000000..9a1bb23ed
--- /dev/null
+++ b/sc/source/ui/inc/shtabdlg.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 <vcl/weld.hxx>
+
+class ScShowTabDlg : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::Frame> m_xFrame;
+ std::unique_ptr<weld::TreeView> m_xLb;
+
+ DECL_LINK(DblClkHdl, weld::TreeView&, bool);
+
+public:
+ ScShowTabDlg(weld::Window* pParent);
+ virtual ~ScShowTabDlg() override;
+
+ /** Sets dialog title, fixed text for listbox and help IDs. */
+ void SetDescription(const OUString& rTitle, const OUString& rFixedText,
+ const OString& nDlgHelpId, const OString& nLbHelpId);
+
+ /** Inserts a string into the weld::TreeView. */
+ void Insert(const OUString& rString, bool bSelected);
+
+ std::vector<sal_Int32> GetSelectedRows() const;
+ OUString GetEntry(sal_Int32 nPos) const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/simpref.hxx b/sc/source/ui/inc/simpref.hxx
new file mode 100644
index 000000000..0286aa6cf
--- /dev/null
+++ b/sc/source/ui/inc/simpref.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 "anyrefdg.hxx"
+
+class ScDocument;
+
+class ScSimpleRefDlg: public ScAnyRefDlgController
+{
+private:
+ Link<const OUString*,void> aCloseHdl;
+ Link<const OUString&,void> aDoneHdl;
+ Link<const OUString&,void> aAbortedHdl;
+ Link<const OUString&,void> aChangeHdl;
+
+ ScRange theCurArea;
+ bool bCloseFlag;
+ bool bAutoReOpen;
+ bool bCloseOnButtonUp;
+ bool bSingleCell;
+ bool bMultiSelection;
+
+ std::unique_ptr<weld::Label> m_xFtAssign;
+ std::unique_ptr<formula::RefEdit> m_xEdAssign;
+ std::unique_ptr<formula::RefButton> m_xRbAssign;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+ void Init();
+
+ DECL_LINK( CancelBtnHdl, weld::Button&, void );
+ DECL_LINK( OkBtnHdl, weld::Button&, void );
+
+protected:
+
+ virtual void RefInputDone( bool bForced = false ) override;
+
+public:
+ ScSimpleRefDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent);
+ virtual ~ScSimpleRefDlg() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+
+ virtual bool IsRefInputMode() const override;
+ virtual void SetActive() override;
+ virtual void Close() override;
+
+ void StartRefInput();
+
+ void SetRefString(const OUString &rStr);
+ virtual void FillInfo(SfxChildWinInfo&) const override;
+
+ void SetCloseHdl( const Link<const OUString*,void>& rLink );
+ void SetUnoLinks( const Link<const OUString&,void>& rDone, const Link<const OUString&,void>& rAbort,
+ const Link<const OUString&,void>& rChange );
+
+ void SetFlags( bool bSetCloseOnButtonUp, bool bSetSingleCell, bool bSetMultiSelection );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/sizedev.hxx b/sc/source/ui/inc/sizedev.hxx
new file mode 100644
index 000000000..8bf98be8e
--- /dev/null
+++ b/sc/source/ui/inc/sizedev.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 <vcl/mapmod.hxx>
+#include <vcl/vclptr.hxx>
+
+class OutputDevice;
+class ScDocShell;
+
+class ScSizeDeviceProvider
+{
+ VclPtr<OutputDevice> pDevice;
+ bool bOwner;
+ double nPPTX;
+ double nPPTY;
+ MapMode aOldMapMode;
+
+public:
+ ScSizeDeviceProvider( ScDocShell* pDocSh );
+ ~ScSizeDeviceProvider();
+
+ OutputDevice* GetDevice() const { return pDevice.get(); }
+ double GetPPTX() const { return nPPTX; }
+ double GetPPTY() const { return nPPTY; }
+ bool IsPrinter() const { return !bOwner; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/solveroptions.hxx b/sc/source/ui/inc/solveroptions.hxx
new file mode 100644
index 000000000..5e39ef758
--- /dev/null
+++ b/sc/source/ui/inc/solveroptions.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 <vcl/weld.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+namespace com::sun::star {
+ namespace beans { struct PropertyValue; }
+}
+
+class ScSolverOptionsString
+{
+ bool mbIsDouble;
+ double mfDoubleValue;
+ sal_Int32 mnIntValue;
+ OUString msStr;
+
+public:
+ explicit ScSolverOptionsString(const OUString& rStr)
+ : mbIsDouble(false)
+ , mfDoubleValue(0.0)
+ , mnIntValue(0)
+ , msStr(rStr)
+ {
+ }
+
+ bool IsDouble() const { return mbIsDouble; }
+ double GetDoubleValue() const { return mfDoubleValue; }
+ sal_Int32 GetIntValue() const { return mnIntValue; }
+ const OUString& GetText() const { return msStr; }
+
+ void SetDoubleValue( double fNew ) { mbIsDouble = true; mfDoubleValue = fNew; }
+ void SetIntValue( sal_Int32 nNew ) { mbIsDouble = false; mnIntValue = nNew; }
+};
+
+class ScSolverIntegerDialog;
+class ScSolverValueDialog;
+
+class ScSolverOptionsDialog : public weld::GenericDialogController
+{
+ css::uno::Sequence<OUString> maImplNames;
+ OUString maEngine;
+ css::uno::Sequence<css::beans::PropertyValue> maProperties;
+
+ std::vector<std::unique_ptr<ScSolverOptionsString>> m_aOptions;
+
+ std::unique_ptr<weld::ComboBox> m_xLbEngine;
+ std::unique_ptr<weld::TreeView> m_xLbSettings;
+ std::unique_ptr<weld::Button> m_xBtnEdit;
+
+ std::shared_ptr<ScSolverIntegerDialog> m_xIntDialog;
+ std::shared_ptr<ScSolverValueDialog> m_xValDialog;
+
+ DECL_LINK( EngineSelectHdl, weld::ComboBox&, void );
+ DECL_LINK( SettingsSelHdl, weld::TreeView&, void );
+ DECL_LINK( SettingsDoubleClickHdl, weld::TreeView&, bool );
+ DECL_LINK( ButtonHdl, weld::Button&, void );
+
+ void ReadFromComponent();
+ void FillListBox();
+ void EditOption();
+
+public:
+ ScSolverOptionsDialog( weld::Window* pParent,
+ const css::uno::Sequence<OUString>& rImplNames,
+ const css::uno::Sequence<OUString>& rDescriptions,
+ const OUString& rEngine,
+ const css::uno::Sequence<css::beans::PropertyValue>& rProperties );
+ virtual ~ScSolverOptionsDialog() override;
+
+ // already updated in selection handler
+ const OUString& GetEngine() const { return maEngine; }
+ const css::uno::Sequence<css::beans::PropertyValue>& GetProperties();
+};
+
+class ScSolverIntegerDialog : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::Frame> m_xFrame;
+ std::unique_ptr<weld::SpinButton> m_xNfValue;
+
+public:
+ ScSolverIntegerDialog(weld::Window* pParent);
+ virtual ~ScSolverIntegerDialog() override;
+
+ void SetOptionName( const OUString& rName );
+ void SetValue( sal_Int32 nValue );
+ void SetMax( sal_Int32 nValue );
+ sal_Int32 GetValue() const;
+};
+
+class ScSolverValueDialog : public weld::GenericDialogController
+{
+ std::unique_ptr<weld::Frame> m_xFrame;
+ std::unique_ptr<weld::Entry> m_xEdValue;
+ double m_fMaxValue;
+
+public:
+ ScSolverValueDialog(weld::Window* pParent);
+ virtual ~ScSolverValueDialog() override;
+
+ void SetOptionName( const OUString& rName );
+ void SetValue( double fValue );
+ void SetMax( double fValue );
+ double GetValue() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/solverutil.hxx b/sc/source/ui/inc/solverutil.hxx
new file mode 100644
index 000000000..34cdbb51a
--- /dev/null
+++ b/sc/source/ui/inc/solverutil.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 <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+namespace com::sun::star {
+ namespace beans { struct PropertyValue; }
+ namespace sheet { class XSolver; }
+}
+
+class ScSolverUtil
+{
+public:
+ static void GetImplementations( css::uno::Sequence<OUString>& rImplNames,
+ css::uno::Sequence<OUString>& rDescriptions );
+ static css::uno::Reference<css::sheet::XSolver> GetSolver( std::u16string_view rImplName );
+ static css::uno::Sequence<css::beans::PropertyValue> GetDefaults( std::u16string_view rImplName );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/solvrdlg.hxx b/sc/source/ui/inc/solvrdlg.hxx
new file mode 100644
index 000000000..8b5026ba2
--- /dev/null
+++ b/sc/source/ui/inc/solvrdlg.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 <address.hxx>
+#include "anyrefdg.hxx"
+
+enum ScSolverErr
+ {
+ SOLVERR_NOFORMULA,
+ SOLVERR_INVALID_FORMULA,
+ SOLVERR_INVALID_VARIABLE,
+ SOLVERR_INVALID_TARGETVALUE
+ };
+
+class ScSolverDlg : public ScAnyRefDlgController
+{
+public:
+ ScSolverDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScDocument* pDocument,
+ const ScAddress& aCursorPos );
+ virtual ~ScSolverDlg() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+ virtual bool IsRefInputMode() const override;
+ virtual void SetActive() override;
+ virtual void Close() override;
+
+private:
+ ScAddress theFormulaCell;
+ ScAddress theVariableCell;
+ OUString theTargetValStr;
+
+ ScDocument* pDoc;
+ const SCTAB nCurTab;
+ bool bDlgLostFocus;
+ const OUString errMsgInvalidVar;
+ const OUString errMsgInvalidForm;
+ const OUString errMsgNoFormula;
+ const OUString errMsgInvalidVal;
+
+ formula::RefEdit* m_pEdActive;
+
+ std::unique_ptr<weld::Label> m_xFtFormulaCell;
+ std::unique_ptr<formula::RefEdit> m_xEdFormulaCell;
+ std::unique_ptr<formula::RefButton> m_xRBFormulaCell;
+
+ std::unique_ptr<weld::Entry> m_xEdTargetVal;
+
+ std::unique_ptr<weld::Label> m_xFtVariableCell;
+ std::unique_ptr<formula::RefEdit> m_xEdVariableCell;
+ std::unique_ptr<formula::RefButton> m_xRBVariableCell;
+
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+ std::shared_ptr<weld::MessageDialog> m_xMessageBox;
+
+ void Init();
+ bool CheckTargetValue( const OUString& rStrVal );
+ void RaiseError( ScSolverErr eError );
+
+ DECL_LINK( BtnHdl, weld::Button&, void );
+ DECL_LINK( GetEditFocusHdl, formula::RefEdit&, void );
+ DECL_LINK( LoseEditFocusHdl, formula::RefEdit&, void );
+
+ DECL_LINK( GetButtonFocusHdl, formula::RefButton&, void );
+ DECL_LINK( LoseButtonFocusHdl, formula::RefButton&, void );
+
+ DECL_LINK( GetFocusHdl, weld::Widget&, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/sortdlg.hxx b/sc/source/ui/inc/sortdlg.hxx
new file mode 100644
index 000000000..10d4268d7
--- /dev/null
+++ b/sc/source/ui/inc/sortdlg.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 <sfx2/tabdlg.hxx>
+#include <vcl/weld.hxx>
+
+class ScSortDlg : public SfxTabDialogController
+{
+public:
+ ScSortDlg(weld::Window* pParent, const SfxItemSet* pArgSet);
+};
+
+class ScSortWarningDlg : public weld::GenericDialogController
+{
+public:
+ ScSortWarningDlg(weld::Window* pParent, std::u16string_view rExtendText, std::u16string_view rCurrentText);
+ virtual ~ScSortWarningDlg() override;
+ DECL_LINK(BtnHdl, weld::Button&, void);
+private:
+ std::unique_ptr<weld::Label> m_xFtText;
+ std::unique_ptr<weld::Button> m_xBtnExtSort;
+ std::unique_ptr<weld::Button> m_xBtnCurSort;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/sortkeydlg.hxx b/sc/source/ui/inc/sortkeydlg.hxx
new file mode 100644
index 000000000..2c702e610
--- /dev/null
+++ b/sc/source/ui/inc/sortkeydlg.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 <vector>
+#include <memory>
+
+#include <vcl/weld.hxx>
+
+struct ScSortKeyItem
+{
+ std::unique_ptr<weld::Builder> m_xBuilder;
+
+ std::unique_ptr<weld::Frame> m_xFrame;
+ std::unique_ptr<weld::ComboBox> m_xLbSort;
+ std::unique_ptr<weld::RadioButton> m_xBtnUp;
+ std::unique_ptr<weld::RadioButton> m_xBtnDown;
+ std::unique_ptr<weld::Label> m_xLabel;
+ weld::Container* m_pParent;
+
+ ScSortKeyItem(weld::Container* pParent);
+ ~ScSortKeyItem();
+
+ void DisableField();
+ void EnableField();
+};
+
+typedef std::vector<std::unique_ptr<ScSortKeyItem>> ScSortKeyItems;
+
+class ScSortKeyWindow
+{
+public:
+ ScSortKeyItems m_aSortKeyItems;
+
+private:
+ weld::Container* m_pBox;
+
+public:
+ ScSortKeyWindow(weld::Container* pBox);
+ ~ScSortKeyWindow();
+
+ void AddSortKey(sal_uInt16 nItem);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/spelldialog.hxx b/sc/source/ui/inc/spelldialog.hxx
new file mode 100644
index 000000000..2319866af
--- /dev/null
+++ b/sc/source/ui/inc/spelldialog.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 <memory>
+#include <svx/SpellDialogChildWindow.hxx>
+#include <document.hxx>
+
+class ScConversionEngineBase;
+class ScSelectionState;
+class ScTabViewShell;
+class ScViewData;
+class ScRangeList;
+
+/** Specialized spell check dialog child window for Calc.
+
+ This derivation of the svx::SpellDialogChildWindow base class provides
+ Calc specific implementations of the virtual functions GetNextWrongSentence()
+ and ApplyChangedSentence().
+ */
+class ScSpellDialogChildWindow : public svx::SpellDialogChildWindow
+{
+public:
+ SFX_DECL_CHILDWINDOW_WITHID( ScSpellDialogChildWindow );
+
+ explicit ScSpellDialogChildWindow( vcl::Window* pParent, sal_uInt16 nId,
+ SfxBindings* pBindings, SfxChildWinInfo* pInfo );
+ virtual ~ScSpellDialogChildWindow() 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();
+
+protected:
+ /** 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;
+
+private:
+ void Reset();
+ void Init();
+
+ bool IsSelectionChanged();
+
+private:
+ typedef ::std::unique_ptr< ScConversionEngineBase > ScConvEnginePtr;
+ typedef ::std::unique_ptr< ScSelectionState > ScSelectionStatePtr;
+
+ ScConvEnginePtr mxEngine;
+ ScDocumentUniquePtr mxUndoDoc;
+ ScDocumentUniquePtr mxRedoDoc;
+ ScSelectionStatePtr mxOldSel; /// For cursor position in selection
+ tools::SvRef< ScRangeList >
+ mxOldRangeList; /// Original selection range for comparison.
+ ScTabViewShell* mpViewShell;
+ ScViewData* mpViewData;
+ ScDocShell* mpDocShell;
+ ScDocument* mpDoc;
+ bool mbNeedNextObj;
+ bool mbOldIdleEnabled;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/spelleng.hxx b/sc/source/ui/inc/spelleng.hxx
new file mode 100644
index 000000000..c6d75675d
--- /dev/null
+++ b/sc/source/ui/inc/spelleng.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 <editutil.hxx>
+#include "selectionstate.hxx"
+#include "spellparam.hxx"
+
+class ScViewData;
+class ScDocShell;
+class ScDocument;
+class SfxItemPool;
+
+namespace weld { class Widget; }
+
+/** Base class for special type of edit engines, i.e. for spell checker and text conversion. */
+class ScConversionEngineBase : public ScEditEngineDefaulter
+{
+public:
+ explicit ScConversionEngineBase(
+ SfxItemPool* pEnginePool, ScViewData& rViewData,
+ ScDocument* pUndoDoc, ScDocument* pRedoDoc );
+
+ virtual ~ScConversionEngineBase() override;
+
+ /** Derived classes implement to convert all cells in the selection or sheet. */
+ virtual void ConvertAll(weld::Widget* pDialogParent, EditView& rEditView) = 0;
+
+ /** Returns true, if at least one cell has been modified. */
+ bool IsAnyModified() const { return mbIsAnyModified; }
+ /** Returns true, if the entire document/selection has been finished. */
+ bool IsFinished() const { return mbFinished; }
+
+protected:
+ /** Implementation of cell iteration. Finds a cell that needs conversion.
+ @return true = Current cell needs conversion (i.e. spelling error found). */
+ bool FindNextConversionCell();
+ /** Restores the initial cursor position. */
+ void RestoreCursorPos();
+
+ /** Derived classes return, if the current text needs conversion (i.e. spelling error found).
+ @return true = Current edit text needs conversion. */
+ virtual bool NeedsConversion() = 0;
+
+ /** Derived classes may show a query box that asks whether to restart at top of the sheet.
+ @descr Default here is no dialog and restart always.
+ @return true = Restart at top, false = Stop the conversion. */
+ virtual bool ShowTableWrapDialog();
+ /** Derived classes may show a message box stating that the conversion is finished.
+ @descr Default here is no dialog. */
+ virtual void ShowFinishDialog();
+
+private:
+ /** Fills the edit engine from a document cell. */
+ void FillFromCell( SCCOL nCol, SCROW nRow, SCTAB nTab );
+
+protected: // for usage in derived classes
+ ScViewData& mrViewData;
+ ScDocShell& mrDocShell;
+ ScDocument& mrDoc;
+
+private:
+ ScSelectionState maSelState; /// Selection data of the document.
+ ScDocument* mpUndoDoc; /// Document stores all old cells for UNDO action.
+ ScDocument* mpRedoDoc; /// Document stores all new cells for REDO action.
+ LanguageType meCurrLang; /// Current cell language.
+ SCCOL mnStartCol; /// Initial column index.
+ SCROW mnStartRow; /// Initial row index.
+ SCTAB mnStartTab; /// Initial sheet index.
+ SCCOL mnCurrCol; /// Current column index.
+ SCROW mnCurrRow; /// Current row index.
+ bool mbIsAnyModified; /// true = At least one cell has been changed.
+ bool mbInitialState; /// true = Not searched for a cell yet.
+ bool mbWrappedInTable; /// true = Already restarted at top of the sheet.
+ bool mbFinished; /// true = Entire document/selection finished.
+};
+
+/** Edit engine for spell checking. */
+class ScSpellingEngine : public ScConversionEngineBase
+{
+public:
+ explicit ScSpellingEngine(
+ SfxItemPool* pEnginePool,
+ ScViewData& rViewData,
+ ScDocument* pUndoDoc,
+ ScDocument* pRedoDoc,
+ css::uno::Reference< css::linguistic2::XSpellChecker1 > const & xSpeller );
+
+ /** Checks spelling of all cells in the selection or sheet. */
+ virtual void ConvertAll(weld::Widget* pDialogParent, EditView& rEditView) override;
+
+protected:
+ /** Callback from edit engine to check the next cell. */
+ virtual bool SpellNextDocument() override;
+
+ /** Returns true, if the current text contains a spelling error. */
+ virtual bool NeedsConversion() override;
+
+ /** Show a query box that asks whether to restart at top of the sheet.
+ @return true = Restart at top, false = Stop the conversion. */
+ virtual bool ShowTableWrapDialog() override;
+ /** Show a message box stating that spell checking is finished. */
+ virtual void ShowFinishDialog() override;
+
+private:
+ /** Returns the spelling dialog if it is open. */
+ weld::Widget* GetDialogParent();
+};
+
+/** Edit engine for text conversion. */
+class ScTextConversionEngine : public ScConversionEngineBase
+{
+public:
+ explicit ScTextConversionEngine(
+ SfxItemPool* pEnginePool,
+ ScViewData& rViewData,
+ const ScConversionParam& rConvParam,
+ ScDocument* pUndoDoc,
+ ScDocument* pRedoDoc );
+
+ /** Converts all cells in the selection or sheet according to set language. */
+ virtual void ConvertAll(weld::Widget* pDialogParent, EditView& rEditView) override;
+
+protected:
+ /** Callback from edit engine to convert the next cell. */
+ virtual bool ConvertNextDocument() override;
+
+ /** Returns true, if the current text contains text to convert. */
+ virtual bool NeedsConversion() override;
+
+private:
+ ScConversionParam maConvParam; /// Conversion parameters.
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/spellparam.hxx b/sc/source/ui/inc/spellparam.hxx
new file mode 100644
index 000000000..ba6f56d7f
--- /dev/null
+++ b/sc/source/ui/inc/spellparam.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 <vcl/font.hxx>
+
+/** Specifiers for sheet conversion (functions iterating over the sheet and modifying cells). */
+enum ScConversionType
+{
+ SC_CONVERSION_SPELLCHECK, /// Spell checker.
+ SC_CONVERSION_HANGULHANJA, /// Hangul-Hanja converter.
+ SC_CONVERSION_CHINESE_TRANSL /// Chinese simplified/traditional converter.
+};
+
+/** Parameters for conversion. */
+class ScConversionParam
+{
+public:
+ /** Constructs an empty parameter struct with the passed conversion type. */
+ explicit ScConversionParam( ScConversionType eConvType );
+
+ /** Constructs parameter struct for text conversion without changing the language. */
+ explicit ScConversionParam(
+ ScConversionType eConvType,
+ LanguageType eLang,
+ sal_Int32 nOptions,
+ bool bIsInteractive );
+
+ /** Constructs parameter struct for text conversion with language change. */
+ explicit ScConversionParam(
+ ScConversionType eConvType,
+ LanguageType eSourceLang,
+ LanguageType eTargetLang,
+ const vcl::Font& rTargetFont,
+ sal_Int32 nOptions,
+ bool bIsInteractive );
+
+ ScConversionType GetType() const { return meConvType; }
+ LanguageType GetSourceLang() const { return meSourceLang; }
+ LanguageType GetTargetLang() const { return meTargetLang; }
+ const vcl::Font* GetTargetFont() const { return mbUseTargetFont ? &maTargetFont : nullptr; }
+ sal_Int32 GetOptions() const { return mnOptions; }
+ bool IsInteractive() const { return mbIsInteractive; }
+
+private:
+ ScConversionType meConvType; /// Type of the conversion.
+ LanguageType meSourceLang; /// Source language for conversion.
+ LanguageType meTargetLang; /// Target language for conversion.
+ vcl::Font maTargetFont; /// Target font to be used if language has to be changed.
+ sal_Int32 mnOptions; /// Conversion options.
+ bool mbUseTargetFont; /// True = Use maTargetFont to change font during conversion.
+ bool mbIsInteractive; /// True = Text conversion has (specific) dialog that may be raised.
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/strindlg.hxx b/sc/source/ui/inc/strindlg.hxx
new file mode 100644
index 000000000..6b1490349
--- /dev/null
+++ b/sc/source/ui/inc/strindlg.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 <vcl/weld.hxx>
+
+class ScStringInputDlg : public weld::GenericDialogController
+{
+private:
+ std::unique_ptr<weld::Label> m_xLabel;
+ std::unique_ptr<weld::Entry> m_xEdInput;
+
+public:
+ ScStringInputDlg(weld::Window* pParent,
+ const OUString& rTitle,
+ const OUString& rEditTitle,
+ const OUString& rDefault,
+ const OString& sHelpId, const OString& sEditHelpId);
+
+ OUString GetInputString() const
+ {
+ return m_xEdInput->get_text();
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/styledlg.hxx b/sc/source/ui/inc/styledlg.hxx
new file mode 100644
index 000000000..2f43e0474
--- /dev/null
+++ b/sc/source/ui/inc/styledlg.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/styledlg.hxx>
+
+class SfxStyleSheetBase;
+
+class ScStyleDlg : public SfxStyleDialogController
+{
+public:
+ ScStyleDlg(weld::Window* pParent,
+ SfxStyleSheetBase& rStyleBase,
+ bool bPage);
+
+protected:
+ virtual void PageCreated(const OString& rPageId, SfxTabPage& rTabPage) override;
+ virtual void RefreshInputSet() override;
+
+private:
+ bool m_bPage;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/subtdlg.hxx b/sc/source/ui/inc/subtdlg.hxx
new file mode 100644
index 000000000..b0c97b09e
--- /dev/null
+++ b/sc/source/ui/inc/subtdlg.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+
+class ScSubTotalDlg : public SfxTabDialogController
+{
+public:
+ ScSubTotalDlg(weld::Window* pParent, const SfxItemSet& rArgSet);
+ virtual ~ScSubTotalDlg() override;
+
+private:
+ std::unique_ptr<weld::Button> m_xBtnRemove;
+ DECL_LINK(RemoveHdl, weld::Button&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tabbgcolordlg.hxx b/sc/source/ui/inc/tabbgcolordlg.hxx
new file mode 100644
index 000000000..94323f676
--- /dev/null
+++ b/sc/source/ui/inc/tabbgcolordlg.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 <svx/SvxColorValueSet.hxx>
+#include <svx/PaletteManager.hxx>
+
+class ScTabBgColorDlg : public weld::GenericDialogController
+{
+public:
+ ScTabBgColorDlg(weld::Window* pParent,
+ const OUString& rTitle,
+ const OUString& rTabBgColorNoColorText,
+ const Color& rDefaultColor);
+ virtual ~ScTabBgColorDlg() override;
+
+ void GetSelectedColor( Color& rColor ) const;
+
+ class ScTabBgColorValueSet : public SvxColorValueSet
+ {
+ public:
+ ScTabBgColorValueSet(std::unique_ptr<weld::ScrolledWindow> pWindow);
+ virtual ~ScTabBgColorValueSet() override;
+
+ void SetDialog(ScTabBgColorDlg* pTabBgColorDlg)
+ {
+ m_pTabBgColorDlg = pTabBgColorDlg;
+ }
+
+ virtual bool KeyInput( const KeyEvent& rKEvt ) override;
+ private:
+ ScTabBgColorDlg* m_pTabBgColorDlg;
+ };
+
+private:
+ PaletteManager m_aPaletteManager;
+ Color m_aTabBgColor;
+
+ std::unique_ptr<weld::ComboBox> m_xSelectPalette;
+ std::unique_ptr<ScTabBgColorValueSet> m_xTabBgColorSet;
+ std::unique_ptr<weld::CustomWeld> m_xTabBgColorSetWin;
+ std::unique_ptr<weld::Button> m_xBtnOk;
+
+ void FillPaletteLB();
+
+ DECL_LINK(SelectPaletteLBHdl, weld::ComboBox&, void);
+ DECL_LINK(TabBgColorDblClickHdl_Impl, ValueSet*, void);
+ DECL_LINK(TabBgColorOKHdl_Impl, weld::Button&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tabcont.hxx b/sc/source/ui/inc/tabcont.hxx
new file mode 100644
index 000000000..6a12c1d07
--- /dev/null
+++ b/sc/source/ui/inc/tabcont.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 <types.hxx>
+#include <svtools/tabbar.hxx>
+#include <vcl/transfer.hxx>
+
+class ScViewData;
+
+// initial size
+#define SC_TABBAR_DEFWIDTH 270
+
+class ScTabControl : public TabBar, public DropTargetHelper, public DragSourceHelper
+{
+private:
+ ScViewData* pViewData;
+ sal_uInt16 nMouseClickPageId; /// Last page ID after mouse button down/up
+ sal_uInt16 nSelPageIdByMouse; /// Selected page ID, if selected with mouse
+ bool bErrorShown;
+
+ void DoDrag();
+
+ sal_uInt16 GetMaxId() const;
+ SCTAB GetPrivatDropPos(const Point& rPos );
+
+ DECL_LINK(ShowPageList, const CommandEvent&, void);
+
+protected:
+ virtual void Select() override;
+ virtual void Command( const CommandEvent& rCEvt ) override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual void MouseButtonUp( const MouseEvent& rMEvt ) override;
+
+ virtual sal_Int8 AcceptDrop( const AcceptDropEvent& rEvt ) override;
+ virtual sal_Int8 ExecuteDrop( const ExecuteDropEvent& rEvt ) override;
+
+ virtual void StartDrag( sal_Int8 nAction, const Point& rPosPixel ) override;
+
+ virtual bool StartRenaming() override;
+ virtual TabBarAllowRenamingReturnCode AllowRenaming() override;
+ virtual void EndRenaming() override;
+ virtual void Mirror() override;
+
+ virtual void AddTabClick() override;
+
+public:
+ ScTabControl( vcl::Window* pParent, ScViewData* pData );
+ virtual void dispose() override;
+ virtual ~ScTabControl() override;
+
+ using TabBar::StartDrag;
+
+ void UpdateInputContext();
+ void UpdateStatus();
+
+ void SetSheetLayoutRTL( bool bSheetRTL );
+ void SwitchToPageId( sal_uInt16 nId );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tabopdlg.hxx b/sc/source/ui/inc/tabopdlg.hxx
new file mode 100644
index 000000000..2e39e94d5
--- /dev/null
+++ b/sc/source/ui/inc/tabopdlg.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 <address.hxx>
+#include "anyrefdg.hxx"
+
+enum ScTabOpErr
+{
+ TABOPERR_NOFORMULA = 1,
+ TABOPERR_NOCOLROW,
+ TABOPERR_WRONGFORMULA,
+ TABOPERR_WRONGROW,
+ TABOPERR_NOCOLFORMULA,
+ TABOPERR_WRONGCOL,
+ TABOPERR_NOROWFORMULA
+};
+
+class ScTabOpDlg : public ScAnyRefDlgController
+{
+public:
+ ScTabOpDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScDocument* pDocument,
+ const ScRefAddress& rCursorPos);
+ virtual ~ScTabOpDlg() override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override;
+ virtual bool IsRefInputMode() const override { return true; }
+ virtual void SetActive() override;
+
+ virtual void Close() override;
+
+private:
+ ScRefAddress theFormulaCell;
+ ScRefAddress theFormulaEnd;
+ ScRefAddress theRowCell;
+ ScRefAddress theColCell;
+
+ ScDocument* pDoc;
+ const SCTAB nCurTab;
+ bool bDlgLostFocus;
+ const OUString errMsgNoFormula;
+ const OUString errMsgNoColRow;
+ const OUString errMsgWrongFormula;
+ const OUString errMsgWrongRowCol;
+ const OUString errMsgNoColFormula;
+ const OUString errMsgNoRowFormula;
+
+ formula::RefEdit* m_pEdActive;
+ std::unique_ptr<weld::Label> m_xFtFormulaRange;
+ std::unique_ptr<formula::RefEdit> m_xEdFormulaRange;
+ std::unique_ptr<formula::RefButton> m_xRBFormulaRange;
+
+ std::unique_ptr<weld::Label> m_xFtRowCell;
+ std::unique_ptr<formula::RefEdit> m_xEdRowCell;
+ std::unique_ptr<formula::RefButton> m_xRBRowCell;
+
+ std::unique_ptr<weld::Label> m_xFtColCell;
+ std::unique_ptr<formula::RefEdit> m_xEdColCell;
+ std::unique_ptr<formula::RefButton> m_xRBColCell;
+
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::Button> m_xBtnCancel;
+
+ void Init();
+ void RaiseError( ScTabOpErr eError );
+
+ DECL_LINK( BtnHdl, weld::Button&, void );
+ DECL_LINK( GetEditFocusHdl, formula::RefEdit&, void );
+ DECL_LINK( LoseEditFocusHdl, formula::RefEdit&, void );
+ DECL_LINK( GetButtonFocusHdl, formula::RefButton&, void );
+ DECL_LINK( LoseButtonFocusHdl, formula::RefButton&, void );
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tabpages.hxx b/sc/source/ui/inc/tabpages.hxx
new file mode 100644
index 000000000..37d751523
--- /dev/null
+++ b/sc/source/ui/inc/tabpages.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 <sfx2/tabdlg.hxx>
+
+class ScTabPageProtection : public SfxTabPage
+{
+ static const WhichRangesContainer pProtectionRanges;
+public:
+ ScTabPageProtection(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rAttrSet);
+ virtual ~ScTabPageProtection() override;
+
+ static WhichRangesContainer GetRanges () { return pProtectionRanges; }
+ virtual bool FillItemSet ( SfxItemSet* rCoreAttrs ) override;
+ virtual void Reset ( const SfxItemSet* ) override;
+
+protected:
+ virtual DeactivateRC DeactivatePage ( SfxItemSet* pSet ) override;
+
+private:
+ // current status:
+ bool bTriEnabled; // if before - DontCare
+ bool bDontCare; // all in TriState
+ bool bProtect; // secure individual settings for TriState
+ bool bHideForm;
+ bool bHideCell;
+ bool bHidePrint;
+
+ weld::TriStateEnabled aHideCellState;
+ weld::TriStateEnabled aProtectState;
+ weld::TriStateEnabled aHideFormulaState;
+ weld::TriStateEnabled aHidePrintState;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnHideCell;
+ std::unique_ptr<weld::CheckButton> m_xBtnProtect;
+ std::unique_ptr<weld::CheckButton> m_xBtnHideFormula;
+ std::unique_ptr<weld::CheckButton> m_xBtnHidePrint;
+
+ // Handler:
+ DECL_LINK(ProtectClickHdl, weld::Toggleable&, void);
+ DECL_LINK(HideCellClickHdl, weld::Toggleable&, void);
+ DECL_LINK(HideFormulaClickHdl, weld::Toggleable&, void);
+ DECL_LINK(HidePrintClickHdl, weld::Toggleable&, void);
+ void ButtonClick(const weld::Toggleable& rBox);
+ void UpdateButtons();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tabsplit.hxx b/sc/source/ui/inc/tabsplit.hxx
new file mode 100644
index 000000000..ce09efddc
--- /dev/null
+++ b/sc/source/ui/inc/tabsplit.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 <vcl/split.hxx>
+
+class ScViewData;
+
+class ScTabSplitter : public Splitter
+{
+private:
+ const ScViewData *const pViewData;
+ bool bFixed;
+
+protected:
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+
+public:
+ ScTabSplitter( vcl::Window* pParent, WinBits nWinStyle,
+ const ScViewData* pData );
+ virtual ~ScTabSplitter() override;
+
+ void SetFixed(bool bSet);
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rPaintRect ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tabview.hxx b/sc/source/ui/inc/tabview.hxx
new file mode 100644
index 000000000..81151f10f
--- /dev/null
+++ b/sc/source/ui/inc/tabview.hxx
@@ -0,0 +1,612 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in 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 <array>
+#include <memory>
+#include <vcl/scrbar.hxx>
+#include <vcl/help.hxx>
+
+#include "hiranges.hxx"
+#include "viewutil.hxx"
+#include "select.hxx"
+#include "gridwin.hxx"
+#include "drawview.hxx"
+
+namespace editeng {
+ struct MisspellRanges;
+}
+
+class ScEditEngineDefaulter;
+class ScOutlineWindow;
+class ScRowBar;
+class ScColBar;
+class ScTabControl;
+class ScTabViewShell;
+struct ScRangeFindData;
+class SvBorder;
+class FuPoor;
+class Splitter;
+class ScTabSplitter;
+class SdrView;
+class SdrObject;
+class ScPageBreakData;
+class SdrHdlList;
+class TabBar;
+namespace com::sun::star::chart2::data { struct HighlightedRange; }
+namespace tools { class JsonWriter; }
+
+enum HeaderType
+{
+ COLUMN_HEADER,
+ ROW_HEADER,
+ BOTH_HEADERS
+};
+
+// Help - Window
+
+class ScCornerButton : public vcl::Window
+{
+private:
+ ScViewData* pViewData;
+
+protected:
+ virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
+ virtual void Resize() override;
+ virtual void MouseButtonDown( const MouseEvent& rMEvt ) override;
+public:
+ ScCornerButton( vcl::Window* pParent, ScViewData* pData );
+ virtual ~ScCornerButton() override;
+
+ virtual void StateChanged( StateChangedType nType ) override;
+ virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+};
+
+class ScExtraEditViewManager
+{
+private:
+ enum ModifierTagType { Adder, Remover };
+
+public:
+ ScExtraEditViewManager(ScTabViewShell* pThisViewShell, std::array<VclPtr<ScGridWindow>, 4> const & pGridWin)
+ : mpThisViewShell(pThisViewShell)
+ , mpGridWin(pGridWin)
+ , mpOtherEditView(nullptr)
+ , nTotalWindows(0)
+ {}
+
+ ~ScExtraEditViewManager();
+
+ void Add(SfxViewShell* pViewShell, ScSplitPos eWhich);
+
+ void Remove(SfxViewShell* pViewShell, ScSplitPos eWhich);
+
+private:
+ template<ModifierTagType ModifierTag>
+ void Apply(SfxViewShell* pViewShell, ScSplitPos eWhich);
+
+ template<ModifierTagType ModifierTag>
+ void Modifier(ScGridWindow* pWin);
+
+private:
+ ScTabViewShell* mpThisViewShell;
+ std::array<VclPtr<ScGridWindow>, 4> const & mpGridWin;
+ EditView* mpOtherEditView;
+ int nTotalWindows;
+};
+
+class ScTabView
+{
+private:
+ enum BlockMode { None = 0, Normal = 1, Own = 2 };
+
+ VclPtr<vcl::Window> pFrameWin; // First !!!
+ ScViewData aViewData; // must be at the front !
+
+ std::unique_ptr<ScViewSelectionEngine> pSelEngine;
+ ScViewFunctionSet aFunctionSet;
+
+ std::unique_ptr<ScHeaderSelectionEngine> pHdrSelEng;
+ ScHeaderFunctionSet aHdrFunc;
+
+ std::unique_ptr<ScDrawView> pDrawView;
+
+ Size aFrameSize; // passed on as for DoResize
+ Point aBorderPos;
+
+ // The ownership of these two is rather weird. we seem to need
+ // to keep an old copy alive for some period of time to avoid crashing.
+ FuPoor* pDrawActual;
+ FuPoor* pDrawOld;
+
+ std::shared_ptr<weld::MessageDialog> m_xMessageBox;
+
+ std::array<VclPtr<ScGridWindow>, 4> pGridWin;
+ std::array<VclPtr<ScColBar>, 2> pColBar;
+ std::array<VclPtr<ScRowBar>, 2> pRowBar;
+ std::array<VclPtr<ScOutlineWindow>, 2> pColOutline;
+ std::array<VclPtr<ScOutlineWindow>, 2> pRowOutline;
+ VclPtr<ScTabSplitter> pHSplitter;
+ VclPtr<ScTabSplitter> pVSplitter;
+ VclPtr<ScTabControl> pTabControl;
+ VclPtr<ScrollBar> aVScrollTop;
+ VclPtr<ScrollBar> aVScrollBottom; // initially visible
+ VclPtr<ScrollBar> aHScrollLeft; // initially visible
+ VclPtr<ScrollBar> aHScrollRight;
+ VclPtr<ScCornerButton> aCornerButton;
+ VclPtr<ScCornerButton> aTopButton;
+ VclPtr<ScrollBarBox> aScrollBarBox;
+
+ std::shared_ptr<sc::SpellCheckContext> mpSpellCheckCxt;
+
+ std::unique_ptr<sdr::overlay::OverlayObjectList> mxInputHintOO; // help hint for data validation
+
+ std::unique_ptr<ScPageBreakData> pPageBreakData;
+ std::vector<ScHighlightEntry> maHighlightRanges;
+
+ ScDocumentUniquePtr pBrushDocument; // cell formats for format paint brush
+ std::unique_ptr<SfxItemSet> pDrawBrushSet; // drawing object attributes for paint brush
+
+ Timer aScrollTimer;
+ VclPtr<ScGridWindow> pTimerWindow;
+ MouseEvent aTimerMEvt;
+
+ ScExtraEditViewManager aExtraEditViewManager;
+
+ void* nTipVisible;
+ tools::Rectangle aTipRectangle;
+ QuickHelpFlags nTipAlign;
+ OUString sTipString;
+ VclPtr<vcl::Window> sTopParent;
+
+ tools::Long nPrevDragPos;
+
+ BlockMode meBlockMode; // Marks block
+
+ SCCOL nBlockStartX;
+ SCCOL nBlockStartXOrig;
+ SCCOL nBlockEndX;
+
+ SCROW nBlockStartY;
+ SCROW nBlockStartYOrig;
+ SCROW nBlockEndY;
+
+ SCTAB nBlockStartZ;
+ SCTAB nBlockEndZ;
+
+ SCCOL nOldCurX;
+ SCROW nOldCurY;
+
+ double mfPendingTabBarWidth; // Tab bar width relative to frame window width.
+
+ SCROW mnLOKStartHeaderRow;
+ SCROW mnLOKEndHeaderRow;
+ SCCOL mnLOKStartHeaderCol;
+ SCCOL mnLOKEndHeaderCol;
+
+ bool bMinimized:1;
+ bool bInUpdateHeader:1;
+ bool bInActivatePart:1;
+ bool bInZoomUpdate:1;
+ bool bMoveIsShift:1;
+ bool bDrawSelMode:1; // Only select draw objects ?
+ bool bLockPaintBrush:1; // keep for more than one use?
+ bool bDragging:1; // for scroll bars
+ bool bBlockNeg:1; // is no longer highlighted?
+ bool bBlockCols:1; // are whole columns selected?
+ bool bBlockRows:1; // are whole rows selected?
+ bool mbInlineWithScrollbar:1; // should inline with scrollbar?
+
+ void Init();
+
+ void DoAddWin( ScGridWindow* pWin );
+
+ void InitScrollBar( ScrollBar& rScrollBar, tools::Long nMaxVal );
+ DECL_LINK(ScrollHdl, ScrollBar*, void );
+ DECL_LINK(EndScrollHdl, ScrollBar*, void );
+
+ DECL_LINK(SplitHdl, Splitter*, void);
+ void DoHSplit(tools::Long nSplitPos);
+ void DoVSplit(tools::Long nSplitPos);
+
+ DECL_LINK( TimerHdl, Timer*, void );
+
+ void UpdateVarZoom();
+
+ static void SetScrollBar( ScrollBar& rScroll, tools::Long nRangeMax, tools::Long nVisible, tools::Long nPos, bool bLayoutRTL );
+ static tools::Long GetScrollBarPos( const ScrollBar& rScroll );
+
+ void GetAreaMoveEndPosition(SCCOL nMovX, SCROW nMovY, ScFollowMode eMode,
+ SCCOL& rAreaX, SCROW& rAreaY, ScFollowMode& rMode);
+
+ void SkipCursorHorizontal(SCCOL& rCurX, SCROW& rCurY, SCCOL nOldX, SCCOL nMovX);
+ void SkipCursorVertical(SCCOL& rCurX, SCROW& rCurY, SCROW nOldY, SCROW nMovY);
+
+ /**
+ *
+ * @brief Update marks for a selected Range. This is a helper function
+ * for PaintRangeFinder.
+ *
+ * @param pData: Range to update for painting.
+ * @param nTab: Current tab.
+ *
+ **/
+
+ void PaintRangeFinderEntry (const ScRangeFindData* pData, SCTAB nTab);
+
+protected:
+ void UpdateHeaderWidth( const ScVSplitPos* pWhich = nullptr,
+ const SCROW* pPosY = nullptr );
+
+ void HideTip();
+ void ShowRefTip();
+
+ void ZoomChanged();
+ void UpdateShow();
+ bool UpdateVisibleRange();
+ void GetBorderSize( SvBorder& rBorder, const Size& rSize );
+
+ void ResetDrawDragMode();
+ bool IsDrawTextEdit() const;
+ void DrawEnableAnim(bool bSet);
+
+ void MakeDrawView( TriState nForceDesignMode );
+
+ void HideNoteMarker();
+
+ void UpdateIMap( SdrObject* pObj );
+
+public:
+ /** make noncopyable */
+ ScTabView(const ScTabView&) = delete;
+ const ScTabView& operator=(const ScTabView&) = delete;
+
+ ScTabView( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell );
+ ~ScTabView();
+
+ enum SplitMethod { SC_SPLIT_METHOD_COL, SC_SPLIT_METHOD_ROW, SC_SPLIT_METHOD_CURSOR };
+
+ void MakeDrawLayer();
+
+ void HideListBox();
+
+ bool HasHintWindow() const;
+ void RemoveHintWindow();
+ void TestHintWindow();
+
+ DECL_LINK( TabBarResize, ::TabBar*, void );
+ /** Sets an absolute tab bar width (in pixels). */
+ void SetTabBarWidth( tools::Long nNewWidth );
+ /** Sets a relative tab bar width.
+ @param fRelTabBarWidth Tab bar width relative to frame window width (0.0 ... 1.0). */
+ SC_DLLPUBLIC void SetRelTabBarWidth( double fRelTabBarWidth );
+ /** Sets a relative tab bar width. Tab bar is resized again in next DoResize().
+ @param fRelTabBarWidth Tab bar width relative to frame window width (0.0 ... 1.0). */
+ void SetPendingRelTabBarWidth( double fRelTabBarWidth );
+ /** Returns the current tab bar width in pixels. */
+ tools::Long GetTabBarWidth() const;
+ /** Returns the current tab bar width relative to the frame window width (0.0 ... 1.0). */
+ SC_DLLPUBLIC static double GetRelTabBarWidth();
+ /** Returns the pending tab bar width relative to the frame window width (0.0 ... 1.0). */
+ double GetPendingRelTabBarWidth() const { return mfPendingTabBarWidth;}
+
+ void DoResize( const Point& rOffset, const Size& rSize, bool bInner = false );
+ void RepeatResize( bool bUpdateFix = true );
+ void UpdateFixPos();
+ Point GetGridOffset() const;
+
+ bool IsDrawSelMode() const { return bDrawSelMode; }
+ void SetDrawSelMode(bool bNew) { bDrawSelMode = bNew; }
+
+ void SetDrawFuncPtr(FuPoor* pFuncPtr) { pDrawActual = pFuncPtr; }
+ void SetDrawFuncOldPtr(FuPoor* pFuncPtr) { pDrawOld = pFuncPtr; }
+ FuPoor* GetDrawFuncPtr() { return pDrawActual; }
+ FuPoor* GetDrawFuncOldPtr() { return pDrawOld; }
+
+ void DrawDeselectAll();
+ void DrawMarkListHasChanged();
+ void UpdateAnchorHandles();
+
+ ScPageBreakData* GetPageBreakData() { return pPageBreakData.get(); }
+ const std::vector<ScHighlightEntry>& GetHighlightRanges() const { return maHighlightRanges; }
+
+ void UpdatePageBreakData( bool bForcePaint = false );
+
+ ScViewData& GetViewData() { return aViewData; }
+ const ScViewData& GetViewData() const { return aViewData; }
+
+ ScViewFunctionSet& GetFunctionSet() { return aFunctionSet; }
+ ScViewSelectionEngine* GetSelEngine() { return pSelEngine.get(); }
+
+ bool SelMouseButtonDown( const MouseEvent& rMEvt );
+
+ ScDrawView* GetScDrawView() { return pDrawView.get(); }
+
+ bool IsMinimized() const { return bMinimized; }
+
+ /**
+ * Called after moving, copying, inserting or deleting a sheet.
+ *
+ * @param bSameTabButMoved true if the same sheet as before is activated.
+ */
+ void TabChanged( bool bSameTabButMoved = false );
+ void SetZoom( const Fraction& rNewX, const Fraction& rNewY, bool bAll );
+ SC_DLLPUBLIC void RefreshZoom();
+ void SetPagebreakMode( bool bSet );
+
+ void UpdateLayerLocks();
+
+ void UpdateDrawTextOutliner();
+ void DigitLanguageChanged();
+
+ static void UpdateInputLine();
+
+ void InitRefMode( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, ScRefType eType );
+ void DoneRefMode( bool bContinue = false );
+ void UpdateRef( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ );
+ void StopRefMode();
+
+ void StopMarking();
+ void FakeButtonUp( ScSplitPos eWhich );
+
+ ScGridWindow* GetActiveWin();
+ vcl::Window* GetWindowByPos( ScSplitPos ePos ) const { return pGridWin[ePos]; }
+
+ ScSplitPos FindWindow( const vcl::Window* pWindow ) const;
+
+ void SetActivePointer( PointerStyle nPointer );
+
+ void ActiveGrabFocus();
+
+ void ClickCursor( SCCOL nPosX, SCROW nPosY, bool bControl );
+
+ SC_DLLPUBLIC void SetCursor( SCCOL nPosX, SCROW nPosY, bool bNew = false );
+
+ SC_DLLPUBLIC void CellContentChanged();
+ void SelectionChanged( bool bFromPaste = false );
+ void CursorPosChanged();
+ void UpdateInputContext();
+
+ void CheckSelectionTransfer();
+
+ void InvertHorizontal( ScVSplitPos eWhich, tools::Long nDragPos );
+ void InvertVertical( ScHSplitPos eWhich, tools::Long nDragPos );
+
+ Point GetInsertPos() const;
+
+ Point GetChartInsertPos( const Size& rSize, const ScRange& rCellRange );
+ Point GetChartDialogPos( const Size& rDialogSize, const tools::Rectangle& rLogicChart );
+
+ void UpdateAutoFillMark( bool bFromPaste = false );
+
+ void ShowCursor();
+ void HideAllCursors();
+ void ShowAllCursors();
+
+ void AlignToCursor( SCCOL nCurX, SCROW nCurY, ScFollowMode eMode,
+ const ScSplitPos* pWhich = nullptr );
+
+ SvxZoomType GetZoomType() const;
+ void SetZoomType( SvxZoomType eNew, bool bAll );
+ sal_uInt16 CalcZoom( SvxZoomType eType, sal_uInt16 nOldZoom );
+
+ bool HasPageFieldDataAtCursor() const;
+ void StartDataSelect();
+
+ // MoveCursorAbs - absolute
+ // MoveCursorRel - single cells
+ // MoveCursorPage - screen
+ // MoveCursorArea - Data block
+ // MoveCursorEnd - top left / user range
+
+ SC_DLLPUBLIC void MoveCursorAbs( SCCOL nCurX, SCROW nCurY, ScFollowMode eMode,
+ bool bShift, bool bControl,
+ bool bKeepOld = false, bool bKeepSel = false );
+ void MoveCursorRel( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode,
+ bool bShift, bool bKeepSel = false );
+ void MoveCursorPage( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode,
+ bool bShift, bool bKeepSel = false );
+ void MoveCursorArea( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode,
+ bool bShift, bool bKeepSel = false );
+ void MoveCursorEnd( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode,
+ bool bShift, bool bKeepSel = false );
+ void MoveCursorScreen( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift );
+
+ void MoveCursorEnter( bool bShift ); // Shift for direction (select nothing)
+
+ bool MoveCursorKeyInput( const KeyEvent& rKeyEvent );
+
+ void FindNextUnprot( bool bShift, bool bInSelection );
+
+ void GetPageMoveEndPosition(SCCOL nMovX, SCROW nMovY, SCCOL& rPageX, SCROW& rPageY);
+
+ SC_DLLPUBLIC void SetTabNo( SCTAB nTab, bool bNew = false, bool bExtendSelection = false, bool bSameTabButMoved = false );
+ void SelectNextTab( short nDir, bool bExtendSelection );
+ void SelectTabPage( const sal_uInt16 nTab );
+
+ void ActivateView( bool bActivate, bool bFirst );
+ void ActivatePart( ScSplitPos eWhich );
+ bool IsInActivatePart() const { return bInActivatePart; }
+
+ void SetTimer( ScGridWindow* pWin, const MouseEvent& rMEvt );
+ void ResetTimer();
+
+ void ScrollX( tools::Long nDeltaX, ScHSplitPos eWhich, bool bUpdBars = true );
+ void ScrollY( tools::Long nDeltaY, ScVSplitPos eWhich, bool bUpdBars = true );
+ SC_DLLPUBLIC void ScrollLines( tools::Long nDeltaX, tools::Long nDeltaY ); // active
+
+ bool ScrollCommand( const CommandEvent& rCEvt, ScSplitPos ePos );
+
+ void ScrollToObject( const SdrObject* pDrawObj );
+ void MakeVisible( const tools::Rectangle& rHMMRect );
+
+ // Drawing
+
+ void PaintArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ ScUpdateMode eMode = ScUpdateMode::All );
+
+ void PaintGrid();
+
+ void PaintTopArea( SCCOL nStartCol, SCCOL nEndCol );
+ void PaintTop();
+
+ void PaintLeftArea( SCROW nStartRow, SCROW nEndRow );
+ void PaintLeft();
+
+ bool PaintExtras();
+
+ void RecalcPPT();
+
+ void CreateAnchorHandles(SdrHdlList& rHdl, const ScAddress& rAddress);
+
+ void UpdateCopySourceOverlay();
+ void UpdateSelectionOverlay();
+ void UpdateShrinkOverlay();
+ void UpdateAllOverlays();
+
+ void UpdateFormulas( SCCOL nStartCol = -1, SCROW nStartRow = -1, SCCOL nEndCol = -1, SCROW nEndRow = -1 );
+ void InterpretVisible();
+ void CheckNeedsRepaint();
+ bool NeedsRepaint();
+
+ void PaintRangeFinder( tools::Long nNumber );
+ void AddHighlightRange( const ScRange& rRange, const Color& rColor );
+ void ClearHighlightRanges();
+
+ void DoChartSelection( const css::uno::Sequence< css::chart2::data::HighlightedRange > & rHilightRanges );
+ void DoDPFieldPopup(std::u16string_view rPivotTableName, sal_Int32 nDimensionIndex, Point aPoint, Size aSize);
+
+ tools::Long GetGridWidth( ScHSplitPos eWhich );
+ tools::Long GetGridHeight( ScVSplitPos eWhich );
+
+ void UpdateScrollBars( HeaderType eHeaderType = BOTH_HEADERS );
+ void SetNewVisArea();
+ void SetTabProtectionSymbol( SCTAB nTab, const bool bProtect ); // for protection icon of a tab on tabbar
+
+ void InvalidateAttribs();
+
+ void OnLibreOfficeKitTabChanged();
+ void AddWindowToForeignEditView(SfxViewShell* pViewShell, ScSplitPos eWhich);
+ void RemoveWindowFromForeignEditView(SfxViewShell* pViewShell, ScSplitPos eWhich);
+ void MakeEditView( ScEditEngineDefaulter* pEngine, SCCOL nCol, SCROW nRow );
+ void KillEditView( bool bNoPaint );
+ void UpdateEditView();
+
+ // Blocks
+
+ void SelectAll( bool bContinue = false );
+ void SelectAllTables();
+ void DeselectAllTables();
+
+ void MarkCursor( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
+ bool bCols = false, bool bRows = false, bool bCellSelection = false );
+ void InitBlockMode( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
+ bool bTestNeg = false,
+ bool bCols = false, bool bRows = false, bool bForceNeg = false );
+ void InitOwnBlockMode( const ScRange& rMarkRange );
+ void DoneBlockMode( bool bContinue = false );
+
+ bool IsBlockMode() const;
+
+ void ExpandBlock(SCCOL nMovX, SCROW nMovY, ScFollowMode eMode);
+ void ExpandBlockPage(SCCOL nMovX, SCROW nMovY);
+ void ExpandBlockArea(SCCOL nMovX, SCROW nMovY);
+
+ void MarkColumns();
+ void MarkRows();
+
+ /**
+ * Called to select the specified full column.
+ *
+ * @param nCol: Column number to do operation on
+ * @param nModifier: 0, KEY_SHIFT, KEY_MOD1, KEY_SHIFT | KEY_MOD1
+ */
+
+ void MarkColumns(SCCOL nCol, sal_Int16 nModifier);
+ /**
+ * Called to select the specified full row.
+ *
+ * @param nRow: Row number to do operation on
+ * @param nModifier: 0, KEY_SHIFT, KEY_MOD1, KEY_SHIFT | KEY_MOD1
+ */
+ void MarkRows(SCROW nRow, sal_Int16 nModifier);
+
+ void MarkDataArea( bool bIncludeCursor = true );
+ void MarkMatrixFormula();
+ void Unmark();
+
+ void MarkRange( const ScRange& rRange, bool bSetCursor = true, bool bContinue = false );
+
+ bool IsMarking( SCCOL nCol, SCROW nRow, SCTAB nTab ) const;
+
+ void PaintMarks( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow );
+ void PaintBlock( bool bReset );
+
+ void SetMarkData( const ScMarkData& rNew );
+ void MarkDataChanged();
+
+ void LockModifiers( sal_uInt16 nModifiers );
+ sal_uInt16 GetLockedModifiers() const;
+ void ViewOptionsHasChanged( bool bHScrollChanged,
+ bool bGraphicsChanged);
+
+ Point GetMousePosPixel();
+
+ void FreezeSplitters( bool bFreeze, SplitMethod eSplitMethod = SC_SPLIT_METHOD_CURSOR, SCCOLROW nFreezeIndex = -1 );
+ void RemoveSplit();
+ void SplitAtCursor();
+ void SplitAtPixel( const Point& rPixel );
+ void InvalidateSplit();
+
+ void ErrorMessage(TranslateId pGlobStrId);
+
+ void EnableRefInput(bool bFlag);
+
+ vcl::Window* GetFrameWin() const { return pFrameWin; }
+
+ bool HasPaintBrush() const { return pBrushDocument || pDrawBrushSet; }
+ ScDocument* GetBrushDocument() const { return pBrushDocument.get(); }
+ SfxItemSet* GetDrawBrushSet() const { return pDrawBrushSet.get(); }
+ bool IsPaintBrushLocked() const { return bLockPaintBrush; }
+ void SetBrushDocument( ScDocumentUniquePtr pNew, bool bLock );
+ void SetDrawBrushSet( std::unique_ptr<SfxItemSet> pNew, bool bLock );
+ void ResetBrushDocument();
+
+ void EnableAutoSpell( bool bEnable );
+ void ResetAutoSpell();
+ void ResetAutoSpellForContentChange();
+ void SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const std::vector<editeng::MisspellRanges>* pRanges );
+ /// @see ScModelObj::getRowColumnHeaders().
+ void getRowColumnHeaders(const tools::Rectangle& rRectangle, tools::JsonWriter& rJsonWriter);
+ /// @see ScModelObj::getSheetGeometryData()
+ OString getSheetGeometryData(bool bColumns, bool bRows, bool bSizes, bool bHidden,
+ bool bFiltered, bool bGroups);
+ void extendTiledAreaIfNeeded();
+
+ static void OnLOKNoteStateChanged(const ScPostIt* pNote);
+
+ SCROW GetLOKStartHeaderRow() const { return mnLOKStartHeaderRow; }
+ SCROW GetLOKEndHeaderRow() const { return mnLOKEndHeaderRow; }
+ SCCOL GetLOKStartHeaderCol() const { return mnLOKStartHeaderCol; }
+ SCCOL GetLOKEndHeaderCol() const { return mnLOKEndHeaderCol; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tabvwsh.hxx b/sc/source/ui/inc/tabvwsh.hxx
new file mode 100644
index 000000000..d1a7e5ef8
--- /dev/null
+++ b/sc/source/ui/inc/tabvwsh.hxx
@@ -0,0 +1,425 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <formula/errorcodes.hxx>
+#include <formula/opcode.hxx>
+#include <svx/fmshell.hxx>
+#include <sfx2/viewsh.hxx>
+#include <editeng/svxenum.hxx>
+#include <o3tl/deleter.hxx>
+#include <scdllapi.h>
+#include "dbfunc.hxx"
+#include "target.hxx"
+#include <shellids.hxx>
+#include <tabprotection.hxx>
+#include <com/sun/star/ui/dialogs/DialogClosedEvent.hpp>
+#include <dragdata.hxx>
+
+#include <memory>
+#include <map>
+
+class SdrOle2Obj;
+class SfxBindings;
+class SfxChildWindow;
+class SvxNumberInfoItem;
+struct SfxChildWinInfo;
+
+class ScArea;
+class ScAuditingShell;
+class ScDrawShell;
+class ScDrawTextObjectBar;
+class ScEditShell;
+class ScInputHandler;
+class ScPivotShell;
+class ScDrawFormShell;
+class ScCellShell;
+class ScOleObjectShell;
+class ScGraphicShell;
+class ScMediaShell;
+class ScChartShell;
+class ScPageBreakShell;
+class ScDPObject;
+class ScNavigatorSettings;
+class ScRangeName;
+class ScDrawTransferObj;
+namespace sc { class SparklineShell; }
+
+struct ScHeaderFieldData;
+
+namespace editeng { class SvxBorderLine; }
+
+namespace com::sun::star::frame { class XDispatchProviderInterceptor; }
+
+namespace svx {
+ class ExtrusionBar;
+ class FontworkBar;
+}
+
+enum ObjectSelectionType
+{
+ OST_NONE,
+ OST_Cell,
+ OST_Editing,
+ OST_DrawText,
+ OST_Drawing,
+ OST_DrawForm,
+ OST_Pivot,
+ OST_Auditing,
+ OST_OleObject,
+ OST_Chart,
+ OST_Graphic,
+ OST_Media,
+ OST_Sparkline,
+};
+
+class ScFormEditData;
+class SC_DLLPUBLIC ScTabViewShell: public SfxViewShell, public ScDBFunc
+{
+private:
+ ObjectSelectionType eCurOST;
+ sal_uInt16 nDrawSfxId;
+ SdrObjKind eFormObjKind;
+ OUString sDrawCustom; // current custom shape type
+ std::unique_ptr<ScDrawShell> pDrawShell;
+ std::unique_ptr<ScDrawTextObjectBar> pDrawTextShell;
+ std::unique_ptr<ScEditShell> pEditShell;
+ std::unique_ptr<ScPivotShell> pPivotShell;
+ std::unique_ptr<sc::SparklineShell> m_pSparklineShell;
+ std::unique_ptr<ScAuditingShell> pAuditingShell;
+ std::unique_ptr<ScDrawFormShell> pDrawFormShell;
+ std::unique_ptr<ScCellShell> pCellShell;
+ std::unique_ptr<ScOleObjectShell> pOleObjectShell;
+ std::unique_ptr<ScChartShell> pChartShell;
+ std::unique_ptr<ScGraphicShell> pGraphicShell;
+ std::unique_ptr<ScMediaShell> pMediaShell;
+ std::unique_ptr<ScPageBreakShell> pPageBreakShell;
+ std::unique_ptr<svx::ExtrusionBar> pExtrusionBarShell;
+ std::unique_ptr<svx::FontworkBar> pFontworkBarShell;
+
+ std::unique_ptr<FmFormShell> pFormShell;
+
+ std::unique_ptr<ScFormEditData> mpFormEditData;
+ std::unique_ptr<ScInputHandler, o3tl::default_delete<ScInputHandler>> mpInputHandler; // for OLE input cell
+
+ std::unique_ptr<::editeng::SvxBorderLine> pCurFrameLine;
+
+ css::uno::Reference< css::frame::XDispatchProviderInterceptor >
+ xDisProvInterceptor;
+
+ Point aWinPos;
+
+ ScTabViewTarget aTarget;
+ std::unique_ptr<ScDPObject> pDialogDPObject;
+
+ std::unique_ptr<ScNavigatorSettings> pNavSettings;
+
+ // used in first Activate
+ bool bFirstActivate;
+
+ bool bActiveDrawSh;
+ bool bActiveDrawTextSh;
+ bool bActiveDrawFormSh;
+ bool bActiveOleObjectSh;
+ bool bActiveChartSh;
+ bool bActiveGraphicSh;
+ bool bActiveMediaSh;
+ bool bActiveEditSh;
+
+ bool bFormShellAtTop; // does the FormShell need to be on top?
+
+ bool bDontSwitch; // Don't turn off EditShell
+ bool bInFormatDialog; // for GetSelectionText
+
+ bool bReadOnly; // to detect status changes
+
+ bool bIsActive;
+
+ bool bForceFocusOnCurCell; // #i123629#
+
+ bool bInPrepareClose;
+ bool bInDispose;
+
+ sal_uInt16 nCurRefDlgId;
+
+ std::unique_ptr<SfxBroadcaster> pAccessibilityBroadcaster;
+
+ // ugly hack for Add button in ScNameDlg
+ std::map<OUString, std::unique_ptr<ScRangeName>> m_RangeMap;
+ bool mbInSwitch;
+ OUString maName;
+ OUString maScope;
+
+ std::unique_ptr<ScDragData> m_pDragData;
+private:
+ void Construct( TriState nForceDesignMode );
+
+ SfxShell* GetMySubShell() const;
+
+ void DoReadUserData( std::u16string_view rData );
+ void DoReadUserDataSequence( const css::uno::Sequence< css::beans::PropertyValue >& rSettings );
+ bool IsSignatureLineSelected();
+ bool IsSignatureLineSigned();
+ bool IsQRCodeSelected();
+
+ DECL_DLLPRIVATE_LINK( SimpleRefClose, const OUString*, void );
+ DECL_DLLPRIVATE_LINK( SimpleRefDone, const OUString&, void );
+ DECL_DLLPRIVATE_LINK( SimpleRefAborted, const OUString&, void );
+ DECL_DLLPRIVATE_LINK( SimpleRefChange, const OUString&, void );
+ DECL_DLLPRIVATE_LINK( FormControlActivated, LinkParamNone*, void );
+ DECL_DLLPRIVATE_LINK( DialogClosedHdl, css::ui::dialogs::DialogClosedEvent*, void );
+
+protected:
+ virtual void Activate(bool bMDI) override;
+ virtual void Deactivate(bool bMDI) override;
+ virtual bool PrepareClose( bool bUI = true ) override;
+
+ virtual void ShowCursor(bool bOn) override;
+
+ virtual void Move() override; // notification
+
+ virtual void InnerResizePixel( const Point &rOfs, const Size &rSize, bool inplaceEditModeChange ) override; // new
+ virtual void OuterResizePixel( const Point &rOfs, const Size &rSize ) override;
+ virtual void SetZoomFactor( const Fraction &rZoomX, const Fraction &rZoomY ) override;
+
+ virtual void QueryObjAreaPixel( tools::Rectangle& rRect ) const override;
+
+ virtual OUString GetSelectionText( bool bWholeWord = false, bool bOnlyASample = false ) override;
+ virtual bool HasSelection( bool bText = true ) const override;
+
+ virtual void WriteUserData(OUString &, bool bBrowse = false) override;
+ virtual void ReadUserData(const OUString &, bool bBrowse = false) override;
+ virtual void WriteUserDataSequence (css::uno::Sequence < css::beans::PropertyValue >& ) override;
+ virtual void ReadUserDataSequence (const css::uno::Sequence < css::beans::PropertyValue >& ) override;
+
+ virtual void UIDeactivated( SfxInPlaceClient* pClient ) override;
+
+ virtual bool KeyInput( const KeyEvent &rKeyEvent ) override;
+ virtual SdrView* GetDrawView() const override;
+
+public:
+ SFX_DECL_INTERFACE(SCID_TABVIEW_SHELL)
+ SFX_DECL_VIEWFACTORY(ScTabViewShell);
+
+private:
+ /// SfxInterface initializer.
+ static void InitInterface_Impl();
+
+public:
+ /** -> Clone Method for Factory
+ Created from a general shell and inherit as much as possible */
+ ScTabViewShell( SfxViewFrame* pViewFrame,
+ SfxViewShell* pOldSh );
+
+ virtual ~ScTabViewShell() override;
+
+ weld::Window* GetDialogParent();
+
+ bool IsRefInputMode() const;
+ void ExecuteInputDirect();
+
+ const ScInputHandler* GetInputHandler() const { return mpInputHandler.get(); }
+ ScInputHandler* GetInputHandler() { return mpInputHandler.get(); }
+ void UpdateInputHandler( bool bForce = false, bool bStopEditing = true );
+ void UpdateInputHandlerCellAdjust( SvxCellHorJustify eJust );
+ bool TabKeyInput(const KeyEvent& rKEvt);
+ bool SfxKeyInput(const KeyEvent& rKEvt);
+
+ void SetActive();
+
+ ::editeng::SvxBorderLine* GetDefaultFrameLine() const { return pCurFrameLine.get(); }
+ void SetDefaultFrameLine(const ::editeng::SvxBorderLine* pLine );
+
+ void Execute( SfxRequest& rReq );
+ void GetState( SfxItemSet& rSet );
+
+ void ExecuteTable( SfxRequest& rReq );
+ void GetStateTable( SfxItemSet& rSet );
+
+ void WindowChanged();
+ void ExecDraw(SfxRequest&);
+ void ExecDrawIns(SfxRequest& rReq);
+ void GetDrawState(SfxItemSet &rSet);
+ void GetDrawInsState(SfxItemSet &rSet);
+ void ExecGallery(const SfxRequest& rReq);
+
+ void ExecChildWin(const SfxRequest& rReq);
+
+ void ExecImageMap( SfxRequest& rReq );
+ void GetImageMapState( SfxItemSet& rSet );
+
+ void ExecuteSave( SfxRequest& rReq );
+ void GetSaveState( SfxItemSet& rSet );
+ void ExecSearch( SfxRequest& rReq );
+
+ void ExecuteUndo(SfxRequest& rReq);
+ void GetUndoState(SfxItemSet &rSet);
+
+ void ExecuteObject(const SfxRequest& rReq);
+ void GetObjectState(SfxItemSet &rSet);
+
+ void ExecDrawOpt(const SfxRequest& rReq);
+ void GetDrawOptState(SfxItemSet &rSet);
+
+ void UpdateDrawShell();
+ void SetDrawShell( bool bActive );
+ void SetDrawTextShell( bool bActive );
+
+ void SetPivotShell( bool bActive );
+ void SetSparklineShell(bool bActive);
+ void SetDialogDPObject( std::unique_ptr<ScDPObject> pObj );
+ const ScDPObject* GetDialogDPObject() const { return pDialogDPObject.get(); }
+
+ void SetDontSwitch(bool bFlag){bDontSwitch=bFlag;}
+
+ void SetAuditShell( bool bActive );
+ void SetDrawFormShell( bool bActive );
+ void SetEditShell(EditView* pView, bool bActive );
+ void SetOleObjectShell( bool bActive );
+ void SetChartShell( bool bActive );
+ void SetGraphicShell( bool bActive );
+ void SetMediaShell( bool bActive );
+
+ void SetDrawShellOrSub();
+ void SetCurSubShell( ObjectSelectionType eOST, bool bForce = false );
+
+ void SetFormShellAtTop( bool bSet );
+
+ ObjectSelectionType GetCurObjectSelectionType() const { return eCurOST; }
+
+ virtual ErrCode DoVerb(sal_Int32 nVerb) override;
+
+ void StopEditShell();
+ bool IsDrawTextShell() const;
+ bool IsAuditShell() const;
+
+ void SetDrawTextUndo( SfxUndoManager* pUndoMgr );
+
+ void FillFieldData( ScHeaderFieldData& rData );
+
+ virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
+
+ ScNavigatorSettings* GetNavigatorSettings();
+
+ // Drucken:
+ virtual SfxPrinter* GetPrinter( bool bCreate = false ) override;
+ virtual sal_uInt16 SetPrinter( SfxPrinter* pNewPrinter,
+ SfxPrinterChangeFlags nDiffFlags = SFX_PRINTER_ALL ) override;
+
+ virtual bool HasPrintOptionsPage() const override;
+ virtual std::unique_ptr<SfxTabPage> CreatePrintOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rOptions) override;
+
+ void ConnectObject( const SdrOle2Obj* pObj );
+ void ActivateObject(SdrOle2Obj* pObj, sal_Int32 nVerb);
+
+ void DeactivateOle();
+
+ static ScTabViewShell* GetActiveViewShell();
+
+ std::shared_ptr<SfxModelessDialogController> CreateRefDialogController(SfxBindings* pB, SfxChildWindow* pCW,
+ const SfxChildWinInfo* pInfo,
+ weld::Window* pParent, sal_uInt16 nSlotId);
+
+ void UpdateOleZoom();
+
+ virtual const FmFormShell* GetFormShell() const override { return pFormShell.get(); }
+ virtual FmFormShell* GetFormShell() override { return pFormShell.get(); }
+
+ void InsertURL( const OUString& rName, const OUString& rURL, const OUString& rTarget,
+ sal_uInt16 nMode );
+ void InsertURLButton( const OUString& rName, const OUString& rURL, const OUString& rTarget,
+ const Point* pInsPos );
+ void InsertURLField( const OUString& rName, const OUString& rURL, const OUString& rTarget );
+
+ bool SelectObject( std::u16string_view rName );
+
+ void SetInFormatDialog(bool bFlag) {bInFormatDialog=bFlag;}
+
+ void ForceMove() { Move(); }
+
+ static std::unique_ptr<SvxNumberInfoItem> MakeNumberInfoItem( ScDocument& rDoc, const ScViewData& rViewData );
+
+ static void UpdateNumberFormatter( const SvxNumberInfoItem& rInfoItem );
+
+ void ExecuteCellFormatDlg( SfxRequest& rReq, const OString &rTabPage);
+
+ bool GetFunction( OUString& rFuncStr, FormulaError nErrCode );
+
+ void StartSimpleRefDialog( const OUString& rTitle, const OUString& rInitVal,
+ bool bCloseOnButtonUp, bool bSingleCell, bool bMultiSelection );
+ void StopSimpleRefDialog();
+
+ void SetCurRefDlgId( sal_uInt16 nNew );
+
+ void AddAccessibilityObject( SfxListener& rObject );
+ void RemoveAccessibilityObject( SfxListener& rObject );
+ void BroadcastAccessibility( const SfxHint &rHint );
+ bool HasAccessibilityObjects() const;
+
+ bool ExecuteRetypePassDlg(ScPasswordHash eDesiredHash);
+
+ using ScTabView::ShowCursor;
+
+ bool IsActive() const { return bIsActive; }
+ OUString GetFormula(const ScAddress& rAddress);
+ bool UseSubTotal(ScRangeList* pRangeList);
+ OUString DoAutoSum(bool& rRangeFinder, bool& rSubTotal, const OpCode eCode);
+
+ // ugly hack to call Define Names from Manage Names
+ void SwitchBetweenRefDialogs(SfxModelessDialogController* pDialog);
+ // #i123629#
+ bool GetForceFocusOnCurCell() const { return bForceFocusOnCurCell; }
+ void SetForceFocusOnCurCell(bool bFlag) { bForceFocusOnCurCell=bFlag; }
+ /// See SfxViewShell::getPart().
+ int getPart() const override;
+ /// See SfxViewShell::afterCallbackRegistered().
+ void afterCallbackRegistered() override;
+ /// See SfxViewShell::NotifyCursor().
+ void NotifyCursor(SfxViewShell* pViewShell) const override;
+ /// Emits a LOK_CALLBACK_INVALIDATE_HEADER for all views whose current tab is equal to nCurrentTabIndex
+ static void notifyAllViewsHeaderInvalidation(const SfxViewShell* pForViewShell, HeaderType eHeaderType, SCTAB nCurrentTabIndex);
+ static bool isAnyEditViewInRange(const SfxViewShell* pForViewShell, bool bColumns, SCCOLROW nStart, SCCOLROW nEnd);
+ /// Emits a LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY for all views whose current tab
+ /// is equal to nCurrentTabIndex
+ static void notifyAllViewsSheetGeomInvalidation(const SfxViewShell* pForViewShell, bool bColumns, bool bRows, bool bSizes,
+ bool bHidden, bool bFiltered, bool bGroups, SCTAB nCurrentTabIndex);
+ css::uno::Reference<css::drawing::XShapes> getSelectedXShapes();
+ static css::uno::Reference<css::datatransfer::XTransferable2> GetClipData(vcl::Window* pWin);
+
+ void InitFormEditData();
+ void ClearFormEditData();
+ ScFormEditData* GetFormEditData() { return mpFormEditData.get(); }
+
+ /// 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();
+
+ virtual tools::Rectangle getLOKVisibleArea() const override;
+
+ const ScDragData& GetDragData() const { return *m_pDragData; }
+ void SetDragObject(ScTransferObj* pCellObj, ScDrawTransferObj* pDrawObj);
+ void ResetDragObject();
+ void SetDragLink(const OUString& rDoc, const OUString& rTab, const OUString& rArea);
+ void SetDragJump(ScDocument* pLocalDoc, const OUString& rTarget, const OUString& rText);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/target.hxx b/sc/source/ui/inc/target.hxx
new file mode 100644
index 000000000..b7c5c78e2
--- /dev/null
+++ b/sc/source/ui/inc/target.hxx
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <svl/undo.hxx>
+
+class ScTabViewShell;
+
+class ScTabViewTarget : public SfxRepeatTarget
+{
+private:
+ ScTabViewShell* pViewShell;
+
+public:
+
+ ScTabViewTarget( ScTabViewShell* pShell ) : pViewShell( pShell ) {}
+ virtual ~ScTabViewTarget() override;
+
+ ScTabViewShell* GetViewShell() const { return pViewShell; }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tbzoomsliderctrl.hxx b/sc/source/ui/inc/tbzoomsliderctrl.hxx
new file mode 100644
index 000000000..36710d6bb
--- /dev/null
+++ b/sc/source/ui/inc/tbzoomsliderctrl.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 <vcl/customweld.hxx>
+#include <vcl/image.hxx>
+#include <vcl/window.hxx>
+#include <svl/poolitem.hxx>
+#include <vcl/InterimItemWindow.hxx>
+#include <sfx2/tbxctrl.hxx>
+
+namespace com::sun::star::frame { class XDispatchProvider; }
+
+class SvxZoomSliderItem;
+
+class ScZoomSliderControl : public SfxToolBoxControl
+{
+public:
+ SFX_DECL_TOOLBOX_CONTROL();
+ ScZoomSliderControl( sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx );
+ virtual ~ScZoomSliderControl() override;
+
+ virtual void StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState eState, const SfxPoolItem* pState ) override;
+ virtual VclPtr<InterimItemWindow> CreateItemWindow( vcl::Window *pParent ) override;
+};
+
+class ScZoomSlider final : public weld::CustomWidgetController
+{
+private:
+ sal_uInt16 mnCurrentZoom;
+ sal_uInt16 mnMinZoom;
+ sal_uInt16 mnMaxZoom;
+ std::vector< tools::Long > maSnappingPointOffsets;
+ std::vector< sal_uInt16 > maSnappingPointZooms;
+ Image maSliderButton;
+ Image maIncreaseButton;
+ Image maDecreaseButton;
+ bool mbOmitPaint;
+ css::uno::Reference<css::frame::XDispatchProvider> m_xDispatchProvider;
+
+ sal_uInt16 Offset2Zoom(tools::Long nOffset) const;
+ tools::Long Zoom2Offset(sal_uInt16 nZoom) const;
+
+ void DoPaint(vcl::RenderContext& rRenderContext);
+public:
+ ScZoomSlider(const css::uno::Reference<css::frame::XDispatchProvider>& rDispatchProvider,
+ sal_uInt16 nCurrentZoom);
+
+ void UpdateFromItem(const SvxZoomSliderItem* pZoomSliderItem);
+
+ virtual bool MouseButtonDown( const MouseEvent& rMEvt ) override;
+ virtual bool MouseMove( const MouseEvent& rMEvt ) override;
+ virtual void Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect) override;
+};
+
+class ScZoomSliderWnd final : public InterimItemWindow
+{
+private:
+ std::unique_ptr<ScZoomSlider> mxWidget;
+ std::unique_ptr<weld::CustomWeld> mxWeld;
+
+public:
+ ScZoomSliderWnd(vcl::Window* pParent, const css::uno::Reference<css::frame::XDispatchProvider>& rDispatchProvider,
+ sal_uInt16 nCurrentZoom);
+ virtual ~ScZoomSliderWnd() override;
+ virtual void dispose() override;
+ void UpdateFromItem( const SvxZoomSliderItem* pZoomSliderItem );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/textdlgs.hxx b/sc/source/ui/inc/textdlgs.hxx
new file mode 100644
index 000000000..0bffe3a24
--- /dev/null
+++ b/sc/source/ui/inc/textdlgs.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 <sfx2/tabdlg.hxx>
+
+class SfxObjectShell;
+
+class ScCharDlg : public SfxTabDialogController
+{
+private:
+ const SfxObjectShell& rDocShell;
+
+ virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override;
+
+public:
+ ScCharDlg(weld::Window* pParent, const SfxItemSet* pAttr, const SfxObjectShell* pDocShell,
+ bool bDrawText);
+};
+
+class ScParagraphDlg : public SfxTabDialogController
+{
+private:
+ virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override;
+
+public:
+ ScParagraphDlg(weld::Window* pParent, const SfxItemSet* pAttr);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/textimportoptions.hxx b/sc/source/ui/inc/textimportoptions.hxx
new file mode 100644
index 000000000..35e2fffa1
--- /dev/null
+++ b/sc/source/ui/inc/textimportoptions.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 <vcl/weld.hxx>
+#include <i18nlangtag/lang.h>
+
+class SvxLanguageBox;
+
+class ScTextImportOptionsDlg : public weld::GenericDialogController
+{
+public:
+ ScTextImportOptionsDlg(weld::Window* pParent);
+ virtual ~ScTextImportOptionsDlg() override;
+
+ LanguageType getLanguageType() const;
+ bool isDateConversionSet() const;
+ bool isKeepAskingSet() const;
+
+private:
+ void init();
+
+private:
+ std::unique_ptr<weld::Button> m_xBtnOk;
+ std::unique_ptr<weld::RadioButton> m_xRbAutomatic;
+ std::unique_ptr<weld::RadioButton> m_xRbCustom;
+ std::unique_ptr<weld::CheckButton> m_xBtnConvertDate;
+ std::unique_ptr<weld::CheckButton> m_xBtnKeepAsking;
+ std::unique_ptr<SvxLanguageBox> m_xLbCustomLang;
+
+ DECL_LINK(OKHdl, weld::Button&, void);
+ DECL_LINK(RadioHdl, weld::Toggleable&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tpcalc.hxx b/sc/source/ui/inc/tpcalc.hxx
new file mode 100644
index 000000000..558eec388
--- /dev/null
+++ b/sc/source/ui/inc/tpcalc.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 <sfx2/tabdlg.hxx>
+#include "editfield.hxx"
+
+class ScDocOptions;
+
+class ScTpCalcOptions : public SfxTabPage
+{
+public:
+ ScTpCalcOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet);
+ virtual ~ScTpCalcOptions() override;
+ virtual bool FillItemSet ( SfxItemSet* rCoreSet ) override;
+ virtual void Reset ( const SfxItemSet* rCoreSet ) override;
+ virtual DeactivateRC DeactivatePage ( SfxItemSet* pSet ) override;
+
+private:
+ std::unique_ptr<ScDocOptions> pOldOptions;
+ std::unique_ptr<ScDocOptions> pLocalOptions;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnIterate;
+ std::unique_ptr<weld::Label> m_xFtSteps;
+ std::unique_ptr<weld::SpinButton> m_xEdSteps;
+ std::unique_ptr<weld::Label> m_xFtEps;
+ std::unique_ptr<ScDoubleField> m_xEdEps;
+
+ std::unique_ptr<weld::RadioButton> m_xBtnDateStd;
+ std::unique_ptr<weld::RadioButton> m_xBtnDateSc10;
+ std::unique_ptr<weld::RadioButton> m_xBtnDate1904;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnCase;
+ std::unique_ptr<weld::CheckButton> m_xBtnCalc;
+ std::unique_ptr<weld::CheckButton> m_xBtnMatch;
+ std::unique_ptr<weld::RadioButton> m_xBtnWildcards;
+ std::unique_ptr<weld::RadioButton> m_xBtnRegex;
+ std::unique_ptr<weld::RadioButton> m_xBtnLiteral;
+ std::unique_ptr<weld::CheckButton> m_xBtnLookUp;
+ std::unique_ptr<weld::CheckButton> m_xBtnGeneralPrec;
+
+ std::unique_ptr<weld::Label> m_xFtPrec;
+ std::unique_ptr<weld::SpinButton> m_xEdPrec;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnThread;
+
+private:
+ void Init();
+
+ // Handler:
+ DECL_LINK( RadioClickHdl, weld::Toggleable&, void );
+ DECL_LINK( CheckClickHdl, weld::Toggleable&, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tpcompatibility.hxx b/sc/source/ui/inc/tpcompatibility.hxx
new file mode 100644
index 000000000..c2fe28358
--- /dev/null
+++ b/sc/source/ui/inc/tpcompatibility.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/.
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+
+class ScTpCompatOptions : public SfxTabPage
+{
+public:
+ explicit ScTpCompatOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreAttrs);
+ virtual ~ScTpCompatOptions() override;
+
+ virtual bool FillItemSet(SfxItemSet* rCoreAttrs) override;
+ virtual void Reset(const SfxItemSet* rCoreAttrs) override;
+ virtual DeactivateRC DeactivatePage(SfxItemSet* pSet ) override;
+
+private:
+ std::unique_ptr<weld::ComboBox> m_xLbKeyBindings;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tpdefaults.hxx b/sc/source/ui/inc/tpdefaults.hxx
new file mode 100644
index 000000000..cabcf5710
--- /dev/null
+++ b/sc/source/ui/inc/tpdefaults.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 <sfx2/tabdlg.hxx>
+
+class ScTpDefaultsOptions : public SfxTabPage
+{
+public:
+ explicit ScTpDefaultsOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet);
+ virtual ~ScTpDefaultsOptions() override;
+
+ virtual bool FillItemSet(SfxItemSet* rCoreSet) override;
+ virtual void Reset(const SfxItemSet* rCoreSet) override;
+ virtual DeactivateRC DeactivatePage(SfxItemSet* pSet) override;
+
+private:
+ void CheckNumSheets();
+ void CheckPrefix();
+ void OnFocusPrefixInput();
+
+ DECL_LINK( NumModifiedHdl, weld::Entry&, void );
+ DECL_LINK( PrefixModifiedHdl, weld::Entry&, void );
+ DECL_LINK( PrefixEditOnFocusHdl, weld::Widget&, void );
+
+private:
+ // Stores old Sheet Prefix
+ OUString maOldPrefixValue;
+
+ std::unique_ptr<weld::SpinButton> m_xEdNSheets;
+ std::unique_ptr<weld::Entry> m_xEdSheetPrefix;
+ std::unique_ptr<weld::CheckButton> m_xEdJumboSheets;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tpformula.hxx b/sc/source/ui/inc/tpformula.hxx
new file mode 100644
index 000000000..abc14f4fd
--- /dev/null
+++ b/sc/source/ui/inc/tpformula.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 <sfx2/tabdlg.hxx>
+
+#include <calcconfig.hxx>
+#include <docoptio.hxx>
+
+class ScTpFormulaOptions : public SfxTabPage
+{
+public:
+ explicit ScTpFormulaOptions(weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet& rCoreSet);
+ static std::unique_ptr<SfxTabPage>
+ Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet);
+ virtual ~ScTpFormulaOptions() override;
+
+ virtual bool FillItemSet(SfxItemSet* rCoreSet) override;
+ virtual void Reset(const SfxItemSet* rCoreSet) override;
+ virtual DeactivateRC DeactivatePage(SfxItemSet* pSet) override;
+
+private:
+ void ResetSeparators();
+ void OnFocusSeparatorInput(weld::Entry* pEdit);
+ void UpdateCustomCalcRadioButtons(bool bDefault);
+ void LaunchCustomCalcSettings();
+
+ bool IsValidSeparator(const OUString& rSep, bool bArray) const;
+
+ DECL_LINK(ButtonHdl, weld::Button&, void);
+ DECL_LINK(ToggleHdl, weld::Toggleable&, void);
+ DECL_LINK(SepInsertTextHdl, OUString&, bool);
+ DECL_LINK(ColSepInsertTextHdl, OUString&, bool);
+ DECL_LINK(RowSepInsertTextHdl, OUString&, bool);
+ DECL_LINK(SepModifyHdl, weld::Entry&, void);
+ DECL_LINK(SepEditOnFocusHdl, weld::Widget&, void);
+
+private:
+ /** Stores old separator value of currently focused separator edit box.
+ This value is used to revert undesired value change. */
+ OUString maOldSepValue;
+
+ ScCalcConfig maSavedConfig;
+ ScCalcConfig maCurrentConfig;
+
+ ScDocOptions maSavedDocOptions;
+ ScDocOptions maCurrentDocOptions;
+
+ sal_Unicode mnDecSep;
+
+ std::unique_ptr<weld::ComboBox> mxLbFormulaSyntax;
+ std::unique_ptr<weld::CheckButton> mxCbEnglishFuncName;
+
+ std::unique_ptr<weld::RadioButton> mxBtnCustomCalcDefault;
+ std::unique_ptr<weld::RadioButton> mxBtnCustomCalcCustom;
+ std::unique_ptr<weld::Button> mxBtnCustomCalcDetails;
+
+ std::unique_ptr<weld::Entry> mxEdSepFuncArg;
+ std::unique_ptr<weld::Entry> mxEdSepArrayCol;
+ std::unique_ptr<weld::Entry> mxEdSepArrayRow;
+ std::unique_ptr<weld::Button> mxBtnSepReset;
+
+ std::unique_ptr<weld::ComboBox> mxLbOOXMLRecalcOptions;
+ std::unique_ptr<weld::ComboBox> mxLbODFRecalcOptions;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tphf.hxx b/sc/source/ui/inc/tphf.hxx
new file mode 100644
index 000000000..9af97f6d7
--- /dev/null
+++ b/sc/source/ui/inc/tphf.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 <svx/hdft.hxx>
+
+class ScStyleDlg;
+
+class ScHFPage : public SvxHFPage
+{
+public:
+ virtual ~ScHFPage() override;
+
+ virtual void Reset( const SfxItemSet* rSet ) override;
+ virtual bool FillItemSet( SfxItemSet* rOutSet ) override;
+
+ void SetPageStyle( const OUString& rName ) { aStrPageStyle = rName; }
+ void SetStyleDlg ( ScStyleDlg* pDlg ) { pStyleDlg = pDlg; }
+
+protected:
+ ScHFPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet, sal_uInt16 nSetId);
+
+ virtual void ActivatePage( const SfxItemSet& rSet ) override;
+ virtual DeactivateRC DeactivatePage( SfxItemSet* pSet ) override;
+
+private:
+ SfxItemSet aDataSet;
+ OUString aStrPageStyle;
+ SvxPageUsage nPageUsage;
+ ScStyleDlg* pStyleDlg;
+ std::unique_ptr<weld::Button> m_xBtnEdit;
+
+ DECL_LINK(BtnHdl, weld::Button&, void);
+ DECL_LINK(TurnOnHdl, weld::Toggleable&, void);
+};
+
+class ScHeaderPage : public ScHFPage
+{
+public:
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet );
+ ScHeaderPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet);
+ static WhichRangesContainer GetRanges();
+};
+
+class ScFooterPage : public ScHFPage
+{
+public:
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet );
+ ScFooterPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet);
+ static WhichRangesContainer GetRanges();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tphfedit.hxx b/sc/source/ui/inc/tphfedit.hxx
new file mode 100644
index 000000000..4247f2ad9
--- /dev/null
+++ b/sc/source/ui/inc/tphfedit.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 <scdllapi.h>
+#include <editutil.hxx>
+#include <svx/weldeditview.hxx>
+#include <editeng/svxenum.hxx>
+#include <unotools/weakref.hxx>
+
+#include <functional>
+
+namespace com::sun::star::accessibility { class XAccessible; }
+
+class ScPatternAttr;
+class EditView;
+class EditTextObject;
+class SvxFieldItem;
+class ScAccessibleEditObject;
+
+enum ScEditWindowLocation
+{
+ Left,
+ Center,
+ Right
+};
+
+class SC_DLLPUBLIC ScEditWindow : public WeldEditView
+{
+public:
+ ScEditWindow(ScEditWindowLocation eLoc, weld::Window* pParent);
+ virtual void SetDrawingArea(weld::DrawingArea* pArea) override;
+ virtual ~ScEditWindow() override;
+
+ void SetFont( const ScPatternAttr& rPattern );
+ void SetText( const EditTextObject& rTextObject );
+ std::unique_ptr<EditTextObject> CreateTextObject();
+ void SetCharAttributes();
+
+ void InsertField( const SvxFieldItem& rFld );
+
+ void SetNumType(SvxNumType eNumType);
+
+ virtual css::uno::Reference< css::accessibility::XAccessible > CreateAccessible() override;
+
+ ScHeaderEditEngine* GetEditEngine() const override;
+ void SetObjectSelectHdl( const Link<ScEditWindow&,void>& aLink) { aObjectSelectLink = aLink; }
+ void SetGetFocusHdl(const std::function<void (ScEditWindow&)>& rLink) { m_GetFocusLink = rLink; }
+
+protected:
+ virtual void makeEditEngine() override;
+ virtual bool KeyInput( const KeyEvent& rKEvt ) override;
+ virtual bool MouseButtonDown(const MouseEvent& rMEvt) override;
+ virtual void GetFocus() override;
+ virtual void LoseFocus() override;
+
+private:
+ ScEditWindowLocation eLocation;
+ bool mbRTL;
+ weld::Window* mpDialog;
+
+ unotools::WeakReference<ScAccessibleEditObject> mxAcc;
+
+ Link<ScEditWindow&,void> aObjectSelectLink;
+ std::function<void (ScEditWindow&)> m_GetFocusLink;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tpprint.hxx b/sc/source/ui/inc/tpprint.hxx
new file mode 100644
index 000000000..09e78eb37
--- /dev/null
+++ b/sc/source/ui/inc/tpprint.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/tabdlg.hxx>
+
+class ScTpPrintOptions : public SfxTabPage
+{
+ std::unique_ptr<weld::CheckButton> m_xSkipEmptyPagesCB;
+ std::unique_ptr<weld::CheckButton> m_xSelectedSheetsCB;
+ std::unique_ptr<weld::CheckButton> m_xForceBreaksCB;
+
+public:
+ ScTpPrintOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet);
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet );
+ virtual ~ScTpPrintOptions() override;
+
+ virtual bool FillItemSet( SfxItemSet* rCoreSet ) override;
+ virtual void Reset( const SfxItemSet* rCoreSet ) override;
+ virtual DeactivateRC DeactivatePage( SfxItemSet* pSet ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tpsort.hxx b/sc/source/ui/inc/tpsort.hxx
new file mode 100644
index 000000000..655f3a773
--- /dev/null
+++ b/sc/source/ui/inc/tpsort.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 <vector>
+
+#include <sfx2/tabdlg.hxx>
+#include <svtools/collatorres.hxx>
+#include <svx/langbox.hxx>
+#include <unotools/collatorwrapper.hxx>
+#include <vcl/idle.hxx>
+
+#include "sortkeydlg.hxx"
+
+#include <address.hxx>
+#include <sheetlimits.hxx>
+#include <sortparam.hxx>
+
+// +1 because one field is reserved for the "- undefined -" entry
+inline SCCOL SC_MAXFIELDS(const ScSheetLimits& rLimits) { return rLimits.GetMaxColCount() + 1; }
+
+class ScSortItem;
+class ScViewData;
+
+// Sort Criteria
+
+class ScTabPageSortFields : public SfxTabPage
+{
+public:
+ ScTabPageSortFields(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet);
+ virtual ~ScTabPageSortFields() override;
+
+ virtual bool FillItemSet ( SfxItemSet* rArgSet ) override;
+ virtual void Reset ( const SfxItemSet* rArgSet ) override;
+
+protected:
+ virtual void ActivatePage ( const SfxItemSet& rSet ) override;
+ virtual DeactivateRC DeactivatePage ( SfxItemSet* pSet ) override;
+
+private:
+ Idle m_aIdle;
+
+ OUString aStrUndefined;
+ OUString aStrColumn;
+ OUString aStrRow;
+ OUString aStrRowLabel;
+ OUString aStrColLabel;
+
+ TypedWhichId<ScSortItem> nWhichSort;
+ ScViewData* pViewData;
+ ScSortParam aSortData;
+ std::vector<SCCOLROW> nFieldArr;
+ sal_uInt16 nFieldCount;
+ sal_uInt16 nSortKeyCount;
+
+ std::unique_ptr<weld::Container> m_xTop;
+ std::unique_ptr<weld::CheckButton> m_xBtnHeader;
+ std::unique_ptr<weld::RadioButton> m_xBtnTopDown;
+ std::unique_ptr<weld::RadioButton> m_xBtnLeftRight;
+ std::unique_ptr<weld::ScrolledWindow> m_xScrolledWindow;
+ std::unique_ptr<weld::Container> m_xBox;
+ ScSortKeyWindow m_aSortWin;
+
+ void AddSortKey( sal_uInt16 nItem );
+
+private:
+ void Init ();
+ void FillFieldLists ( sal_uInt16 nStartField );
+ sal_uInt16 GetFieldSelPos ( SCCOLROW nField );
+ void SetLastSortKey( sal_uInt16 nItem );
+
+ // Handler ------------------------
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(ScrollToEndHdl, Timer*, void);
+ DECL_LINK(SortDirHdl, weld::Toggleable&, void);
+
+};
+
+// Sort Options
+
+class ScDocument;
+
+class ScTabPageSortOptions : public SfxTabPage
+{
+public:
+ ScTabPageSortOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* pArgSet);
+
+ virtual bool FillItemSet ( SfxItemSet* rArgSet ) override;
+ virtual void Reset ( const SfxItemSet* rArgSet ) override;
+
+protected:
+ virtual void ActivatePage ( const SfxItemSet& rSet ) override;
+ virtual DeactivateRC DeactivatePage ( SfxItemSet* pSet ) override;
+
+private:
+ OUString aStrUndefined;
+
+ TypedWhichId<ScSortItem> nWhichSort;
+ ScSortParam aSortData;
+ ScViewData* pViewData;
+ ScDocument* pDoc;
+ ScAddress theOutPos;
+
+ std::unique_ptr<CollatorResource> m_xColRes;
+ std::unique_ptr<CollatorWrapper> m_xColWrap;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnCase;
+ std::unique_ptr<weld::CheckButton> m_xBtnFormats;
+ std::unique_ptr<weld::CheckButton> m_xBtnNaturalSort;
+ std::unique_ptr<weld::CheckButton> m_xBtnCopyResult;
+ std::unique_ptr<weld::ComboBox> m_xLbOutPos;
+ std::unique_ptr<weld::Entry> m_xEdOutPos;
+ std::unique_ptr<weld::CheckButton> m_xBtnSortUser;
+ std::unique_ptr<weld::ComboBox> m_xLbSortUser;
+ std::unique_ptr<SvxLanguageBox> m_xLbLanguage;
+ std::unique_ptr<weld::Label> m_xFtAlgorithm;
+ std::unique_ptr<weld::ComboBox> m_xLbAlgorithm;
+ std::unique_ptr<weld::CheckButton> m_xBtnIncComments;
+ std::unique_ptr<weld::CheckButton> m_xBtnIncImages;
+
+private:
+ void Init ();
+ void FillUserSortListBox ();
+
+ // Handler ------------------------
+ DECL_LINK( EnableHdl, weld::Toggleable&, void );
+ DECL_LINK( SelOutPosHdl, weld::ComboBox&, void );
+ void EdOutPosModHdl();
+ void FillAlgor();
+ DECL_LINK( FillAlgorHdl, weld::ComboBox&, void );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tpstat.hxx b/sc/source/ui/inc/tpstat.hxx
new file mode 100644
index 000000000..bb57d7212
--- /dev/null
+++ b/sc/source/ui/inc/tpstat.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 <sfx2/tabdlg.hxx>
+
+class ScDocStatPage: public SfxTabPage
+{
+public:
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet);
+ ScDocStatPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet);
+ virtual ~ScDocStatPage() override;
+
+protected:
+ virtual bool FillItemSet( SfxItemSet* rSet ) override;
+ virtual void Reset ( const SfxItemSet* rSet ) override;
+
+private:
+ std::unique_ptr<weld::Label> m_xFtTables;
+ std::unique_ptr<weld::Label> m_xFtCells;
+ std::unique_ptr<weld::Label> m_xFtPages;
+ std::unique_ptr<weld::Label> m_xFtFormula;
+ std::unique_ptr<weld::Frame> m_xFrame;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tpsubt.hxx b/sc/source/ui/inc/tpsubt.hxx
new file mode 100644
index 000000000..a6dfc3cb5
--- /dev/null
+++ b/sc/source/ui/inc/tpsubt.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 <sfx2/tabdlg.hxx>
+#include <global.hxx>
+
+class ScViewData;
+class ScDocument;
+struct ScSubTotalParam;
+class ScSubTotalItem;
+
+class ScTpSubTotalGroup : public SfxTabPage
+{
+protected:
+ ScTpSubTotalGroup(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet, const sal_uInt16& nTabNumber);
+
+public:
+ virtual ~ScTpSubTotalGroup() override;
+
+ bool DoReset ( sal_uInt16 nGroupNo,
+ const SfxItemSet& rArgSet );
+ bool DoFillItemSet ( sal_uInt16 nGroupNo,
+ SfxItemSet& rArgSet );
+protected:
+ const OUString aStrNone;
+ const OUString aStrColumn;
+
+ ScViewData* pViewData;
+ ScDocument* pDoc;
+
+ const TypedWhichId<ScSubTotalItem> nWhichSubTotals;
+ const ScSubTotalParam& rSubTotalData;
+ std::vector<SCCOL> mnFieldArr;
+ sal_uInt16 nFieldCount;
+
+ std::unique_ptr<weld::ComboBox> mxLbGroup;
+ std::unique_ptr<weld::TreeView> mxLbColumns;
+ std::unique_ptr<weld::TreeView> mxLbFunctions;
+ std::unique_ptr<weld::CheckButton> mxLbSelectAllColumns;
+
+private:
+ void Init ();
+ void FillListBoxes ();
+ static ScSubTotalFunc LbPosToFunc ( sal_uInt16 nPos );
+ static sal_uInt16 FuncToLbPos ( ScSubTotalFunc eFunc );
+ sal_uInt16 GetFieldSelPos ( SCCOL nField );
+
+ // Handler ------------------------
+ DECL_LINK( SelectListBoxHdl, weld::ComboBox&, void );
+ DECL_LINK( SelectTreeListBoxHdl, weld::TreeView&, void );
+ DECL_LINK(CheckHdl, const weld::TreeView::iter_col&, void);
+ DECL_LINK(CheckBoxHdl, weld::Toggleable&, void);
+ void SelectHdl(const weld::Widget*);
+};
+
+class ScTpSubTotalGroup1 final : public ScTpSubTotalGroup
+{
+public:
+ ScTpSubTotalGroup1( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet& rArgSet );
+ static std::unique_ptr<SfxTabPage> Create ( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rArgSet );
+ virtual ~ScTpSubTotalGroup1() override;
+
+ virtual bool FillItemSet ( SfxItemSet* rArgSet ) override;
+ virtual void Reset ( const SfxItemSet* rArgSet ) override;
+};
+
+class ScTpSubTotalGroup2 final : public ScTpSubTotalGroup
+{
+public:
+ ScTpSubTotalGroup2( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet& rArgSet );
+ static std::unique_ptr<SfxTabPage> Create ( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rArgSet );
+ virtual ~ScTpSubTotalGroup2() override;
+
+ virtual bool FillItemSet ( SfxItemSet* rArgSet ) override;
+ virtual void Reset ( const SfxItemSet* rArgSet ) override;
+};
+
+class ScTpSubTotalGroup3 final : public ScTpSubTotalGroup
+{
+public:
+ ScTpSubTotalGroup3( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet& rArgSet );
+ static std::unique_ptr<SfxTabPage> Create ( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rArgSet );
+ virtual ~ScTpSubTotalGroup3() override;
+
+ virtual bool FillItemSet ( SfxItemSet* rArgSet ) override;
+ virtual void Reset ( const SfxItemSet* rArgSet ) override;
+};
+
+class ScTpSubTotalOptions final : public SfxTabPage
+{
+public:
+ ScTpSubTotalOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet);
+ static std::unique_ptr<SfxTabPage> Create ( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rArgSet );
+ virtual ~ScTpSubTotalOptions() override;
+
+ virtual bool FillItemSet ( SfxItemSet* rArgSet ) override;
+ virtual void Reset ( const SfxItemSet* rArgSet ) override;
+
+private:
+ void Init ();
+ void FillUserSortListBox ();
+
+ // Handler ------------------------
+ DECL_LINK(CheckHdl, weld::Toggleable&, void);
+
+ ScViewData* pViewData;
+ ScDocument* pDoc;
+ const TypedWhichId<ScSubTotalItem> nWhichSubTotals;
+ const ScSubTotalParam& rSubTotalData;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnPagebreak;
+ std::unique_ptr<weld::CheckButton> m_xBtnCase;
+ std::unique_ptr<weld::CheckButton> m_xBtnSort;
+ std::unique_ptr<weld::Label> m_xFlSort;
+ std::unique_ptr<weld::RadioButton> m_xBtnAscending;
+ std::unique_ptr<weld::RadioButton> m_xBtnDescending;
+ std::unique_ptr<weld::CheckButton> m_xBtnFormats;
+ std::unique_ptr<weld::CheckButton> m_xBtnUserDef;
+ std::unique_ptr<weld::ComboBox> m_xLbUserDef;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tptable.hxx b/sc/source/ui/inc/tptable.hxx
new file mode 100644
index 000000000..e843f769c
--- /dev/null
+++ b/sc/source/ui/inc/tptable.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 <sfx2/tabdlg.hxx>
+
+class ScTablePage : public SfxTabPage
+{
+ static const WhichRangesContainer pPageTableRanges;
+public:
+ ScTablePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet);
+ virtual ~ScTablePage() override;
+
+ static WhichRangesContainer GetRanges () { return pPageTableRanges; }
+ virtual bool FillItemSet ( SfxItemSet* rCoreSet ) override;
+ virtual void Reset ( const SfxItemSet* rCoreSet ) override;
+ virtual DeactivateRC DeactivatePage ( SfxItemSet* pSet ) override;
+
+private:
+ void ShowImage();
+
+private:
+ sal_uInt16 m_nOrigScalePageWidth;
+ sal_uInt16 m_nOrigScalePageHeight;
+
+ std::unique_ptr<weld::RadioButton> m_xBtnTopDown;
+ std::unique_ptr<weld::RadioButton> m_xBtnLeftRight;
+ std::unique_ptr<weld::Image> m_xBmpPageDir;
+ std::unique_ptr<weld::CheckButton> m_xBtnPageNo;
+ std::unique_ptr<weld::SpinButton> m_xEdPageNo;
+
+ std::unique_ptr<weld::CheckButton> m_xBtnHeaders;
+ std::unique_ptr<weld::CheckButton> m_xBtnGrid;
+ std::unique_ptr<weld::CheckButton> m_xBtnNotes;
+ std::unique_ptr<weld::CheckButton> m_xBtnObjects;
+ std::unique_ptr<weld::CheckButton> m_xBtnCharts;
+ std::unique_ptr<weld::CheckButton> m_xBtnDrawings;
+ std::unique_ptr<weld::CheckButton> m_xBtnFormulas;
+ std::unique_ptr<weld::CheckButton> m_xBtnNullVals;
+
+ std::unique_ptr<weld::ComboBox> m_xLbScaleMode;
+ std::unique_ptr<weld::Widget> m_xBxScaleAll;
+ std::unique_ptr<weld::MetricSpinButton> m_xEdScaleAll;
+ std::unique_ptr<weld::Widget> m_xGrHeightWidth;
+ std::unique_ptr<weld::SpinButton> m_xEdScalePageWidth;
+ std::unique_ptr<weld::CheckButton> m_xCbScalePageWidth;
+ std::unique_ptr<weld::SpinButton> m_xEdScalePageHeight;
+ std::unique_ptr<weld::CheckButton> m_xCbScalePageHeight;
+ std::unique_ptr<weld::Widget> m_xBxScalePageNum;
+ std::unique_ptr<weld::SpinButton> m_xEdScalePageNum;
+
+private:
+
+ // Handler:
+ DECL_LINK(PageDirHdl, weld::Toggleable&, void);
+ DECL_LINK(PageNoHdl, weld::Toggleable&, void);
+ void PageNoHdl(const weld::Toggleable* pBtn);
+ DECL_LINK(ScaleHdl, weld::ComboBox&, void);
+ DECL_LINK(ToggleHdl, weld::Toggleable&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tpusrlst.hxx b/sc/source/ui/inc/tpusrlst.hxx
new file mode 100644
index 000000000..ead6ee662
--- /dev/null
+++ b/sc/source/ui/inc/tpusrlst.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 <sfx2/tabdlg.hxx>
+
+class ScUserList;
+class ScDocument;
+class ScViewData;
+class ScRefAddress;
+
+class ScTpUserLists : public SfxTabPage
+{
+public:
+ ScTpUserLists(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rAttrSet);
+ virtual ~ScTpUserLists() override;
+ virtual bool FillItemSet ( SfxItemSet* rCoreAttrs ) override;
+ virtual void Reset ( const SfxItemSet* rCoreAttrs ) override;
+ virtual DeactivateRC DeactivatePage ( SfxItemSet* pSet ) override;
+
+private:
+ std::unique_ptr<weld::Label> mxFtLists;
+ std::unique_ptr<weld::TreeView> mxLbLists;
+ std::unique_ptr<weld::Label> mxFtEntries;
+ std::unique_ptr<weld::TextView> mxEdEntries;
+ std::unique_ptr<weld::Label> mxFtCopyFrom;
+ std::unique_ptr<weld::Entry> mxEdCopyFrom;
+ std::unique_ptr<weld::Button> mxBtnNew;
+ std::unique_ptr<weld::Button> mxBtnDiscard;
+ std::unique_ptr<weld::Button> mxBtnAdd;
+ std::unique_ptr<weld::Button> mxBtnModify;
+ std::unique_ptr<weld::Button> mxBtnRemove;
+ std::unique_ptr<weld::Button> mxBtnCopy;
+
+ const OUString aStrQueryRemove;
+ const OUString aStrCopyList;
+ const OUString aStrCopyFrom;
+ const OUString aStrCopyErr;
+
+ const sal_uInt16 nWhichUserLists;
+ std::unique_ptr<ScUserList> pUserLists;
+
+ ScDocument* pDoc;
+ ScViewData* pViewData;
+ OUString aStrSelectedArea;
+
+ bool bModifyMode;
+ bool bCancelMode;
+ bool bCopyDone;
+ sal_Int32 nCancelPos;
+
+ void Init ();
+ size_t UpdateUserListBox ();
+ void UpdateEntries ( size_t nList );
+ static void MakeListStr ( OUString& rListStr );
+ void AddNewList ( const OUString& rEntriesStr );
+ void RemoveList ( size_t nList );
+ void ModifyList ( size_t nSelList,
+ const OUString& rEntriesStr );
+ void CopyListFromArea ( const ScRefAddress& rStartPos,
+ const ScRefAddress& rEndPos );
+
+ // Handler:
+ DECL_LINK( LbSelectHdl, weld::TreeView&, void );
+ DECL_LINK( BtnClickHdl, weld::Button&, void );
+ DECL_LINK( EdEntriesModHdl, weld::TextView&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/tpview.hxx b/sc/source/ui/inc/tpview.hxx
new file mode 100644
index 000000000..ee35ce6f6
--- /dev/null
+++ b/sc/source/ui/inc/tpview.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 <sfx2/tabdlg.hxx>
+#include <svx/colorbox.hxx>
+
+class ScViewOptions;
+
+class ScTpContentOptions : public SfxTabPage
+{
+ std::unique_ptr<ScViewOptions> m_xLocalOptions;
+
+ std::unique_ptr<weld::ComboBox> m_xGridLB;
+ std::unique_ptr<weld::Label> m_xColorFT;
+ std::unique_ptr<ColorListBox> m_xColorLB;
+ std::unique_ptr<weld::CheckButton> m_xBreakCB;
+ std::unique_ptr<weld::CheckButton> m_xGuideLineCB;
+
+ std::unique_ptr<weld::CheckButton> m_xFormulaCB;
+ std::unique_ptr<weld::CheckButton> m_xNilCB;
+ std::unique_ptr<weld::CheckButton> m_xAnnotCB;
+ std::unique_ptr<weld::CheckButton> m_xValueCB;
+ std::unique_ptr<weld::CheckButton> m_xAnchorCB;
+ std::unique_ptr<weld::CheckButton> m_xClipMarkCB;
+ std::unique_ptr<weld::CheckButton> m_xRangeFindCB;
+
+ std::unique_ptr<weld::ComboBox> m_xObjGrfLB;
+ std::unique_ptr<weld::ComboBox> m_xDiagramLB;
+ std::unique_ptr<weld::ComboBox> m_xDrawLB;
+
+ std::unique_ptr<weld::CheckButton> m_xSyncZoomCB;
+
+ std::unique_ptr<weld::CheckButton> m_xRowColHeaderCB;
+ std::unique_ptr<weld::CheckButton> m_xHScrollCB;
+ std::unique_ptr<weld::CheckButton> m_xVScrollCB;
+ std::unique_ptr<weld::CheckButton> m_xTblRegCB;
+ std::unique_ptr<weld::CheckButton> m_xOutlineCB;
+ std::unique_ptr<weld::CheckButton> m_xSummaryCB;
+ std::unique_ptr<weld::RadioButton> m_xThemedCursorRB;
+ std::unique_ptr<weld::RadioButton> m_xSystemCursorRB;
+
+ void InitGridOpt();
+ DECL_LINK( GridHdl, weld::ComboBox&, void );
+ DECL_LINK( SelLbObjHdl, weld::ComboBox&, void );
+ DECL_LINK( CBHdl, weld::Toggleable&, void );
+
+public:
+ ScTpContentOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet);
+ virtual ~ScTpContentOptions() override;
+ virtual bool FillItemSet ( SfxItemSet* rCoreSet ) override;
+ virtual void Reset ( const SfxItemSet* rCoreSet ) override;
+ virtual void ActivatePage( const SfxItemSet& ) override;
+ virtual DeactivateRC DeactivatePage( SfxItemSet* pSet ) override;
+
+};
+
+class ScDocument;
+class ScTpLayoutOptions : public SfxTabPage
+{
+ ScDocument *pDoc;
+
+ std::unique_ptr<weld::ComboBox> m_xUnitLB;
+ std::unique_ptr<weld::MetricSpinButton> m_xTabMF;
+
+ std::unique_ptr<weld::RadioButton> m_xAlwaysRB;
+ std::unique_ptr<weld::RadioButton> m_xRequestRB;
+ std::unique_ptr<weld::RadioButton> m_xNeverRB;
+
+ std::unique_ptr<weld::CheckButton> m_xAlignCB;
+ std::unique_ptr<weld::ComboBox> m_xAlignLB;
+ std::unique_ptr<weld::CheckButton> m_xEditModeCB;
+ std::unique_ptr<weld::CheckButton> m_xFormatCB;
+ std::unique_ptr<weld::CheckButton> m_xExpRefCB;
+ std::unique_ptr<weld::CheckButton> m_xSortRefUpdateCB;
+ std::unique_ptr<weld::CheckButton> m_xMarkHdrCB;
+ std::unique_ptr<weld::CheckButton> m_xTextFmtCB;
+ std::unique_ptr<weld::CheckButton> m_xReplWarnCB;
+ std::unique_ptr<weld::CheckButton> m_xLegacyCellSelectionCB;
+ std::unique_ptr<weld::CheckButton> m_xEnterPasteModeCB;
+
+ DECL_LINK(MetricHdl, weld::ComboBox&, void );
+ DECL_LINK( AlignHdl, weld::Toggleable&, void );
+
+
+public:
+ ScTpLayoutOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet );
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rCoreSet);
+ virtual ~ScTpLayoutOptions() override;
+ virtual bool FillItemSet ( SfxItemSet* rCoreSet ) override;
+ virtual void Reset ( const SfxItemSet* rCoreSet ) override;
+ virtual void ActivatePage( const SfxItemSet& ) override;
+ virtual DeactivateRC DeactivatePage( SfxItemSet* pSet ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/transobj.hxx b/sc/source/ui/inc/transobj.hxx
new file mode 100644
index 000000000..adc58b6a5
--- /dev/null
+++ b/sc/source/ui/inc/transobj.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 <vcl/transfer.hxx>
+#include <address.hxx>
+#include <document.hxx>
+#include <sfx2/objsh.hxx>
+
+
+class ScDocShell;
+class ScMarkData;
+enum class ScDragSrc;
+
+namespace com::sun::star {
+ namespace sheet {
+ class XSheetCellRanges;
+ }
+}
+
+class SAL_DLLPUBLIC_RTTI ScTransferObj : public TransferDataContainer
+{
+private:
+ std::shared_ptr<ScDocument> m_pDoc;
+ ScRange m_aBlock;
+ SCROW m_nNonFiltered; // non-filtered rows
+ TransferableObjectDescriptor m_aObjDesc;
+ SfxObjectShellRef m_aDocShellRef;
+ SfxObjectShellRef m_aDrawPersistRef;
+ css::uno::Reference<css::sheet::XSheetCellRanges> m_xDragSourceRanges;
+ SCCOL m_nDragHandleX;
+ SCROW m_nDragHandleY;
+ SCCOL m_nSourceCursorX;
+ SCROW m_nSourceCursorY;
+ SCTAB m_nVisibleTab;
+ ScDragSrc m_nDragSourceFlags;
+ bool m_bDragWasInternal;
+ bool m_bUsedForLink;
+ bool m_bHasFiltered; // if has filtered rows
+ bool m_bUseInApi; // to recognize clipboard content copied from API
+
+ // #i123405# added parameter to allow size calculation without limitation
+ // to PageSize, e.g. used for Metafile creation for clipboard.
+ void InitDocShell(bool bLimitToPageSize);
+ static void StripRefs( ScDocument& rDoc, SCCOL nStartX, SCROW nStartY,
+ SCCOL nEndX, SCROW nEndY,
+ ScDocument& rDestDoc );
+ static void PaintToDev( OutputDevice* pDev, ScDocument& rDoc, double nPrintFactor,
+ const ScRange& rBlock );
+ static void GetAreaSize( const ScDocument& rDoc, SCTAB nTab1, SCTAB nTab2, SCROW& nRow, SCCOL& nCol );
+
+public:
+ ScTransferObj( const std::shared_ptr<ScDocument>& pClipDoc, const TransferableObjectDescriptor& rDesc );
+ virtual ~ScTransferObj() override;
+
+ 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 DragFinished( sal_Int8 nDropAction ) override;
+ virtual sal_Bool SAL_CALL isComplex() override;
+
+ ScDocument* GetDocument() const { return m_pDoc.get(); } // owned by ScTransferObj
+ const ScRange& GetRange() const { return m_aBlock; }
+ SCROW GetNonFilteredRows() const { return m_nNonFiltered; }
+ SCCOL GetDragHandleX() const { return m_nDragHandleX; }
+ SCROW GetDragHandleY() const { return m_nDragHandleY; }
+ bool WasSourceCursorInSelection() const;
+ SCCOL GetSourceCursorX() const { return m_nSourceCursorX; }
+ SCROW GetSourceCursorY() const { return m_nSourceCursorY; }
+ SCTAB GetVisibleTab() const { return m_nVisibleTab; }
+ ScDragSrc GetDragSourceFlags() const { return m_nDragSourceFlags; }
+ bool HasFilteredRows() const { return m_bHasFiltered; }
+ bool GetUseInApi() const { return m_bUseInApi; }
+ ScDocShell* GetSourceDocShell();
+ ScDocument* GetSourceDocument();
+ ScMarkData GetSourceMarkData() const;
+
+ void SetDrawPersist( const SfxObjectShellRef& rRef );
+ void SetDragHandlePos( SCCOL nX, SCROW nY );
+ void SetSourceCursorPos( SCCOL nX, SCROW nY );
+ void SetVisibleTab( SCTAB nNew );
+ void SetDragSource( ScDocShell* pSourceShell, const ScMarkData& rMark );
+ void SetDragSourceFlags( ScDragSrc nFlags );
+ void SetDragWasInternal();
+ SC_DLLPUBLIC void SetUseInApi( bool bSet );
+
+ static SC_DLLPUBLIC ScTransferObj* GetOwnClipboard(const css::uno::Reference<css::datatransfer::XTransferable2>&);
+
+ static SfxObjectShell* SetDrawClipDoc(bool bAnyOle, const std::shared_ptr<ScDocument>& = {} ); // update ScGlobal::xDrawClipDocShellRef
+ virtual sal_Int64 SAL_CALL getSomething( const com::sun::star::uno::Sequence< sal_Int8 >& rId ) override;
+ static const com::sun::star::uno::Sequence< sal_Int8 >& getUnoTunnelId();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/uiitems.hxx b/sc/source/ui/inc/uiitems.hxx
new file mode 100644
index 000000000..7a16c79f2
--- /dev/null
+++ b/sc/source/ui/inc/uiitems.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <scdllapi.h>
+#include <sortparam.hxx>
+#include <subtotalparam.hxx>
+#include <paramisc.hxx>
+#include <svl/poolitem.hxx>
+
+#include <memory>
+#include <vector>
+
+namespace editeng {
+ struct MisspellRanges;
+}
+
+class ScEditEngineDefaulter;
+class EditTextObject;
+class ScViewData;
+class ScDPSaveData;
+struct ScQueryParam;
+
+// Items
+
+class ScInputStatusItem : public SfxPoolItem
+{
+ ScAddress aCursorPos;
+ ScAddress aStartPos;
+ ScAddress aEndPos;
+ OUString aString;
+ std::unique_ptr<EditTextObject> pEditData;
+ const std::vector<editeng::MisspellRanges>* mpMisspellRanges;
+
+public:
+
+ ScInputStatusItem( sal_uInt16 nWhich,
+ const ScAddress& rCurPos,
+ const ScAddress& rStartPos,
+ const ScAddress& rEndPos,
+ const OUString& rString,
+ const EditTextObject* pData );
+ ScInputStatusItem( const ScInputStatusItem& rItem );
+ virtual ~ScInputStatusItem() override;
+
+ virtual bool operator==( const SfxPoolItem& ) const override;
+ virtual ScInputStatusItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+
+ const ScAddress& GetPos() const { return aCursorPos; }
+
+ const OUString& GetString() const { return aString; }
+ const EditTextObject* GetEditData() const { return pEditData.get(); }
+
+ void SetMisspellRanges( const std::vector<editeng::MisspellRanges>* pRanges );
+ const std::vector<editeng::MisspellRanges>* GetMisspellRanges() const { return mpMisspellRanges;}
+};
+
+#define SC_TAB_INSERTED 1
+#define SC_TAB_DELETED 2
+#define SC_TAB_MOVED 3
+#define SC_TAB_COPIED 4
+#define SC_TAB_HIDDEN 5
+#define SC_TABS_INSERTED 6
+#define SC_TABS_DELETED 7
+
+class ScTablesHint : public SfxHint
+{
+ sal_uInt16 nId;
+ SCTAB nTab1;
+ SCTAB nTab2;
+
+public:
+ ScTablesHint(sal_uInt16 nNewId, SCTAB nTable1, SCTAB nTable2=0);
+ virtual ~ScTablesHint() override;
+
+ sal_uInt16 GetTablesHintId() const { return nId; }
+ SCTAB GetTab1() const { return nTab1; }
+ SCTAB GetTab2() const { return nTab2; }
+};
+
+class ScEditViewHint : public SfxHint
+{
+ ScEditEngineDefaulter* pEditEngine;
+ ScAddress aCursorPos;
+
+public:
+ ScEditViewHint() = delete;
+ ScEditViewHint( ScEditEngineDefaulter* pEngine, const ScAddress& rCurPos );
+ virtual ~ScEditViewHint() override;
+
+ SCCOL GetCol() const { return aCursorPos.Col(); }
+ SCROW GetRow() const { return aCursorPos.Row(); }
+ SCTAB GetTab() const { return aCursorPos.Tab(); }
+ ScEditEngineDefaulter* GetEngine() const { return pEditEngine; }
+};
+
+class ScIndexHint : public SfxHint
+{
+ sal_uInt16 nIndex;
+
+public:
+ ScIndexHint(SfxHintId nNewId, sal_uInt16 nIdx);
+ virtual ~ScIndexHint() override;
+
+ sal_uInt16 GetIndex() const { return nIndex; }
+};
+
+// Parameter item for the sort dialog:
+
+class SC_DLLPUBLIC ScSortItem : public SfxPoolItem
+{
+public:
+ ScSortItem( sal_uInt16 nWhich,
+ ScViewData* ptrViewData,
+ const ScSortParam* pSortData );
+ ScSortItem( sal_uInt16 nWhich,
+ const ScSortParam* pSortData );
+
+ virtual bool operator==( const SfxPoolItem& ) const override;
+ virtual ScSortItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+ virtual bool QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override;
+
+ ScViewData* GetViewData () const { return pViewData; }
+ const ScSortParam& GetSortData () const { return theSortData; }
+
+private:
+ ScViewData* pViewData;
+ ScSortParam theSortData;
+};
+
+class SC_DLLPUBLIC ScQueryItem : public SfxPoolItem
+{
+public:
+ ScQueryItem( sal_uInt16 nWhich,
+ ScViewData* ptrViewData,
+ const ScQueryParam* pQueryData );
+ ScQueryItem( sal_uInt16 nWhich,
+ const ScQueryParam* pQueryData );
+ ScQueryItem( const ScQueryItem& rItem );
+ virtual ~ScQueryItem() override;
+
+ virtual bool operator==( const SfxPoolItem& ) const override;
+ virtual ScQueryItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+
+ ScViewData* GetViewData () const { return pViewData; }
+ const ScQueryParam& GetQueryData() const;
+
+ bool GetAdvancedQuerySource(ScRange& rSource) const;
+ void SetAdvancedQuerySource(const ScRange* pSource);
+
+private:
+ std::unique_ptr<ScQueryParam> mpQueryData;
+ ScViewData* pViewData;
+ ScRange aAdvSource;
+ bool bIsAdvanced;
+};
+
+class SC_DLLPUBLIC ScSubTotalItem : public SfxPoolItem
+{
+public:
+ ScSubTotalItem( sal_uInt16 nWhich,
+ ScViewData* ptrViewData,
+ const ScSubTotalParam* pSubTotalData );
+
+ virtual bool operator==( const SfxPoolItem& ) const override;
+ virtual ScSubTotalItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+ virtual bool QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override;
+
+ ScViewData* GetViewData () const { return pViewData; }
+ const ScSubTotalParam& GetSubTotalData() const { return theSubTotalData; }
+
+private:
+ ScViewData* pViewData;
+ ScSubTotalParam theSubTotalData;
+};
+
+class SC_DLLPUBLIC ScUserListItem : public SfxPoolItem
+{
+public:
+ ScUserListItem( sal_uInt16 nWhich );
+ ScUserListItem( const ScUserListItem& rItem );
+ virtual ~ScUserListItem() override;
+
+ virtual bool operator==( const SfxPoolItem& ) const override;
+ virtual ScUserListItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+
+ void SetUserList ( const ScUserList& rUserList );
+ ScUserList* GetUserList () const { return pUserList.get(); }
+
+private:
+ std::unique_ptr<ScUserList> pUserList;
+};
+
+class ScConsolidateItem : public SfxPoolItem
+{
+public:
+ ScConsolidateItem( sal_uInt16 nWhich,
+ const ScConsolidateParam* pParam );
+
+ virtual bool operator==( const SfxPoolItem& ) const override;
+ virtual ScConsolidateItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+
+ const ScConsolidateParam& GetData() const { return theConsData; }
+
+private:
+ ScConsolidateParam theConsData;
+};
+
+class ScPivotItem : public SfxPoolItem
+{
+public:
+ ScPivotItem( sal_uInt16 nWhich, const ScDPSaveData* pData,
+ const ScRange* pRange, bool bNew );
+ ScPivotItem( const ScPivotItem& rItem );
+ virtual ~ScPivotItem() override;
+
+ virtual bool operator==( const SfxPoolItem& ) const override;
+ virtual ScPivotItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+
+ const ScDPSaveData& GetData() const { return *pSaveData; }
+ const ScRange& GetDestRange() const { return aDestRange; }
+ bool IsNewSheet() const { return bNewSheet; }
+
+private:
+ std::unique_ptr<ScDPSaveData> pSaveData;
+ ScRange aDestRange;
+ bool bNewSheet;
+};
+
+class ScSolveItem : public SfxPoolItem
+{
+public:
+ ScSolveItem( sal_uInt16 nWhich,
+ const ScSolveParam* pParam );
+
+ virtual bool operator==( const SfxPoolItem& ) const override;
+ virtual ScSolveItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+
+ const ScSolveParam& GetData() const { return theSolveData; }
+
+private:
+ ScSolveParam theSolveData;
+};
+
+class ScTabOpItem : public SfxPoolItem
+{
+public:
+ ScTabOpItem( sal_uInt16 nWhich,
+ const ScTabOpParam* pParam );
+
+ virtual bool operator==( const SfxPoolItem& ) const override;
+ virtual ScTabOpItem* Clone( SfxItemPool *pPool = nullptr ) const override;
+
+ const ScTabOpParam& GetData() const { return theTabOpData; }
+
+private:
+ ScTabOpParam theTabOpData;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/uiobject.hxx b/sc/source/ui/inc/uiobject.hxx
new file mode 100644
index 000000000..4545c50e7
--- /dev/null
+++ b/sc/source/ui/inc/uiobject.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/.
+ */
+
+#include "gridwin.hxx"
+#include <memory>
+#include <vcl/uitest/uiobject.hxx>
+
+class ScGridWindow;
+class ScDBFunc;
+class ScDrawView;
+class ScTabViewShell;
+class ScViewFunc;
+
+class ScGridWinUIObject : public WindowUIObject
+{
+ VclPtr<ScGridWindow> mxGridWindow;
+
+public:
+ ScGridWinUIObject(const VclPtr<ScGridWindow>& xGridWin);
+
+ 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;
+
+ static std::unique_ptr<UIObject> create(vcl::Window* pWindow);
+
+ virtual std::set<OUString> get_children() const override;
+
+protected:
+ virtual OUString get_name() const override;
+
+private:
+ ScDBFunc* getDBFunc();
+ ScDrawView* getDrawView();
+ ScTabViewShell* getViewShell();
+ ScViewFunc* getViewFunc();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undo/UndoDeleteSparkline.hxx b/sc/source/ui/inc/undo/UndoDeleteSparkline.hxx
new file mode 100644
index 000000000..97fcd77d9
--- /dev/null
+++ b/sc/source/ui/inc/undo/UndoDeleteSparkline.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 <undobase.hxx>
+#include <address.hxx>
+#include <memory>
+
+namespace sc
+{
+class SparklineGroup;
+struct SparklineData;
+
+/** Undo action for deleting a Sparkline */
+class UndoDeleteSparkline : public ScSimpleUndo
+{
+private:
+ std::shared_ptr<sc::SparklineGroup> mpSparklineGroup;
+ ScAddress maSparklinePosition;
+
+public:
+ UndoDeleteSparkline(ScDocShell& rDocShell, ScAddress const& rSparklinePosition);
+
+ virtual ~UndoDeleteSparkline() override;
+
+ void Undo() override;
+ void Redo() override;
+ bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+ void Repeat(SfxRepeatTarget& rTarget) override;
+ OUString GetComment() const override;
+};
+
+} // namespace sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undo/UndoDeleteSparklineGroup.hxx b/sc/source/ui/inc/undo/UndoDeleteSparklineGroup.hxx
new file mode 100644
index 000000000..081a741ab
--- /dev/null
+++ b/sc/source/ui/inc/undo/UndoDeleteSparklineGroup.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 <undobase.hxx>
+#include <address.hxx>
+#include <memory>
+
+namespace sc
+{
+class SparklineGroup;
+
+/** Undo action for deleting a sparkline group and all associated sparklines */
+class UndoDeleteSparklineGroup : public ScSimpleUndo
+{
+private:
+ std::shared_ptr<sc::SparklineGroup> mpSparklineGroup;
+ std::vector<std::shared_ptr<sc::Sparkline>> maSparklines;
+ SCTAB mnTab;
+
+public:
+ UndoDeleteSparklineGroup(ScDocShell& rDocShell,
+ std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup,
+ SCTAB nSheetIndex);
+
+ virtual ~UndoDeleteSparklineGroup() override;
+
+ void Undo() override;
+ void Redo() override;
+ bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+ void Repeat(SfxRepeatTarget& rTarget) override;
+ OUString GetComment() const override;
+};
+
+} // namespace sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undo/UndoEditSparkline.hxx b/sc/source/ui/inc/undo/UndoEditSparkline.hxx
new file mode 100644
index 000000000..4e33eaa1f
--- /dev/null
+++ b/sc/source/ui/inc/undo/UndoEditSparkline.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/.
+ *
+ */
+
+#pragma once
+
+#include <undobase.hxx>
+#include <address.hxx>
+#include <rangelst.hxx>
+#include <memory>
+
+namespace sc
+{
+class Sparkline;
+struct SparklineData;
+
+/** Undo action for editing a Sparkline */
+class UndoEditSparkline : public ScSimpleUndo
+{
+private:
+ std::shared_ptr<sc::Sparkline> mpSparkline;
+ SCTAB mnTab;
+ ScRangeList maOldDataRange;
+ ScRangeList maNewDataRange;
+
+public:
+ UndoEditSparkline(ScDocShell& rDocShell, std::shared_ptr<sc::Sparkline> const& rpSparkline,
+ SCTAB nTab, ScRangeList const& rDataRange);
+
+ virtual ~UndoEditSparkline() override;
+
+ void Undo() override;
+ void Redo() override;
+ bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+ void Repeat(SfxRepeatTarget& rTarget) override;
+ OUString GetComment() const override;
+};
+
+} // namespace sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undo/UndoEditSparklineGroup.hxx b/sc/source/ui/inc/undo/UndoEditSparklineGroup.hxx
new file mode 100644
index 000000000..4ab3e6a4e
--- /dev/null
+++ b/sc/source/ui/inc/undo/UndoEditSparklineGroup.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/.
+ *
+ */
+
+#pragma once
+
+#include <undobase.hxx>
+#include <memory>
+
+#include <SparklineAttributes.hxx>
+#include <SparklineGroup.hxx>
+
+namespace sc
+{
+/** Undo action for editing a Sparkline */
+class UndoEditSparklneGroup : public ScSimpleUndo
+{
+private:
+ std::shared_ptr<sc::SparklineGroup> m_pSparklineGroup;
+ sc::SparklineAttributes m_aNewAttributes;
+ sc::SparklineAttributes m_aOriginalAttributes;
+
+public:
+ UndoEditSparklneGroup(ScDocShell& rDocShell,
+ std::shared_ptr<sc::SparklineGroup> const& rSparklineGroup,
+ sc::SparklineAttributes const& rAttributes);
+ virtual ~UndoEditSparklneGroup() override;
+
+ void Undo() override;
+ void Redo() override;
+ bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+ void Repeat(SfxRepeatTarget& rTarget) override;
+ OUString GetComment() const override;
+};
+
+} // namespace sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undo/UndoGroupSparklines.hxx b/sc/source/ui/inc/undo/UndoGroupSparklines.hxx
new file mode 100644
index 000000000..bcbc470bc
--- /dev/null
+++ b/sc/source/ui/inc/undo/UndoGroupSparklines.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/.
+ *
+ */
+
+#pragma once
+
+#include <undobase.hxx>
+#include <memory>
+
+namespace sc
+{
+/** Previous sparkline group data, which is restored at Undo grouping */
+struct UndoGroupSparklinesData
+{
+ UndoGroupSparklinesData(ScAddress const& rAddress, ScRangeList const& rDataRangeList,
+ std::shared_ptr<sc::SparklineGroup> const& rpGroup)
+ : m_aAddress(rAddress)
+ , m_aDataRangeList(rDataRangeList)
+ , m_pSparklineGroup(rpGroup)
+ {
+ }
+
+ ScAddress m_aAddress;
+ ScRangeList m_aDataRangeList;
+ std::shared_ptr<sc::SparklineGroup> m_pSparklineGroup;
+};
+
+/** Undo action for grouping sparklines */
+class UndoGroupSparklines : public ScSimpleUndo
+{
+private:
+ ScRange m_aRange;
+ std::shared_ptr<sc::SparklineGroup> m_pSparklineGroup;
+ std::vector<UndoGroupSparklinesData> m_aUndoData;
+
+public:
+ UndoGroupSparklines(ScDocShell& rDocShell, ScRange const& rRange,
+ std::shared_ptr<sc::SparklineGroup> const& rpSparklineGroup);
+ virtual ~UndoGroupSparklines() override;
+
+ void Undo() override;
+ void Redo() override;
+ bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+ void Repeat(SfxRepeatTarget& rTarget) override;
+ OUString GetComment() const override;
+};
+
+} // namespace sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undo/UndoInsertSparkline.hxx b/sc/source/ui/inc/undo/UndoInsertSparkline.hxx
new file mode 100644
index 000000000..d9e1885f1
--- /dev/null
+++ b/sc/source/ui/inc/undo/UndoInsertSparkline.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 <undobase.hxx>
+#include <address.hxx>
+#include <memory>
+
+namespace sc
+{
+class SparklineGroup;
+struct SparklineData;
+
+/** Undo action for inserting a Sparkline */
+class UndoInsertSparkline : public ScSimpleUndo
+{
+private:
+ std::vector<sc::SparklineData> maSparklineDataVector;
+ std::shared_ptr<sc::SparklineGroup> mpSparklineGroup;
+
+public:
+ UndoInsertSparkline(ScDocShell& rDocShell,
+ std::vector<SparklineData> const& rSparklineDataVector,
+ std::shared_ptr<sc::SparklineGroup> pSparklineGroup);
+
+ virtual ~UndoInsertSparkline() override;
+
+ void Undo() override;
+ void Redo() override;
+ bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+ void Repeat(SfxRepeatTarget& rTarget) override;
+ OUString GetComment() const override;
+};
+
+} // namespace sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undo/UndoUngroupSparklines.hxx b/sc/source/ui/inc/undo/UndoUngroupSparklines.hxx
new file mode 100644
index 000000000..ce49d701e
--- /dev/null
+++ b/sc/source/ui/inc/undo/UndoUngroupSparklines.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/.
+ *
+ */
+
+#pragma once
+
+#include <undobase.hxx>
+#include <memory>
+
+namespace sc
+{
+/** Previous sparkline group data, which is restored at undo ungroupping */
+struct SparklineUndoData
+{
+ SparklineUndoData(ScAddress const& rAddress, ScRangeList const& rDataRangeList,
+ std::shared_ptr<sc::SparklineGroup> const& rpGroup)
+ : m_aAddress(rAddress)
+ , m_aDataRangeList(rDataRangeList)
+ , m_pSparklineGroup(rpGroup)
+ {
+ }
+
+ ScAddress m_aAddress;
+ ScRangeList m_aDataRangeList;
+ std::shared_ptr<sc::SparklineGroup> m_pSparklineGroup;
+};
+
+/** Undo action for ungrouping sparklines */
+class UndoUngroupSparklines : public ScSimpleUndo
+{
+private:
+ ScRange m_aRange;
+ std::vector<SparklineUndoData> m_aUndoData;
+
+public:
+ UndoUngroupSparklines(ScDocShell& rDocShell, ScRange const& rRange);
+ virtual ~UndoUngroupSparklines() override;
+
+ void Undo() override;
+ void Redo() override;
+ bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+ void Repeat(SfxRepeatTarget& rTarget) override;
+ OUString GetComment() const override;
+};
+
+} // namespace sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undobase.hxx b/sc/source/ui/inc/undobase.hxx
new file mode 100644
index 000000000..4e07e6ae5
--- /dev/null
+++ b/sc/source/ui/inc/undobase.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <svl/undo.hxx>
+#include <address.hxx>
+#include "docsh.hxx"
+
+#include <memory>
+#include <map>
+
+class SdrUndoAction;
+class ScRefUndoData;
+class ScDBData;
+
+class SC_DLLPUBLIC ScSimpleUndo: public SfxUndoAction
+{
+ ScSimpleUndo(const ScSimpleUndo&) = delete;
+
+public:
+ typedef std::map<SCTAB, std::unique_ptr<sc::ColumnSpanSet>> DataSpansType;
+
+ ScSimpleUndo( ScDocShell* pDocSh );
+
+ virtual bool Merge( SfxUndoAction *pNextAction ) override;
+ /// See SfxUndoAction::GetViewShellId().
+ ViewShellId GetViewShellId() const override;
+
+protected:
+ ScDocShell* pDocShell;
+ std::unique_ptr<SfxUndoAction>
+ pDetectiveUndo;
+ ViewShellId mnViewShellId;
+
+ bool IsPaintLocked() const { return pDocShell->IsPaintLocked(); }
+
+ bool SetViewMarkData( const ScMarkData& rMarkData );
+
+ void BeginUndo();
+ void EndUndo();
+ void BeginRedo();
+ void EndRedo();
+
+ void BroadcastChanges( const ScRange& rRange );
+
+ /**
+ * Broadcast changes on specified spans.
+ *
+ * @param rSpans container that specifies all spans whose changes need to
+ * be broadcasted.
+ */
+ void BroadcastChanges( const DataSpansType& rSpans );
+
+ static void ShowTable( SCTAB nTab );
+ static void ShowTable( const ScRange& rRange );
+};
+
+enum ScBlockUndoMode { SC_UNDO_SIMPLE, SC_UNDO_MANUALHEIGHT, SC_UNDO_AUTOHEIGHT };
+
+class ScBlockUndo: public ScSimpleUndo
+{
+public:
+ ScBlockUndo( ScDocShell* pDocSh, const ScRange& rRange,
+ ScBlockUndoMode eBlockMode );
+ virtual ~ScBlockUndo() override;
+
+protected:
+ ScRange aBlockRange;
+ std::unique_ptr<SdrUndoAction> pDrawUndo;
+ ScBlockUndoMode eMode;
+
+ void BeginUndo();
+ void EndUndo();
+// void BeginRedo();
+ void EndRedo();
+
+ bool AdjustHeight();
+ void ShowBlock();
+};
+
+class SC_DLLPUBLIC ScMultiBlockUndo: public ScSimpleUndo
+{
+public:
+ ScMultiBlockUndo(ScDocShell* pDocSh, const ScRangeList& rRanges);
+ virtual ~ScMultiBlockUndo() override;
+
+protected:
+ ScRangeList maBlockRanges;
+ std::unique_ptr<SdrUndoAction> mpDrawUndo;
+
+ void BeginUndo();
+ void EndUndo();
+ void EndRedo();
+
+ void ShowBlock();
+};
+
+// for functions that act on a database range - takes care of the unnamed database range
+// (collected separately, before the undo action, for showing dialogs etc.)
+
+class ScDBFuncUndo: public ScSimpleUndo
+{
+protected:
+ std::unique_ptr<ScDBData> pAutoDBRange;
+ ScRange aOriginalRange;
+
+public:
+ ScDBFuncUndo( ScDocShell* pDocSh, const ScRange& rOriginal );
+ virtual ~ScDBFuncUndo() override;
+
+ void BeginUndo();
+ void EndUndo();
+ void BeginRedo();
+ void EndRedo();
+};
+
+class ScMoveUndo: public ScSimpleUndo // with references
+{
+public:
+ ScMoveUndo( ScDocShell* pDocSh,
+ ScDocumentUniquePtr pRefDoc, std::unique_ptr<ScRefUndoData> pRefData );
+ virtual ~ScMoveUndo() override;
+
+protected:
+ std::unique_ptr<SdrUndoAction> pDrawUndo;
+ ScDocumentUniquePtr pRefUndoDoc;
+ std::unique_ptr<ScRefUndoData> pRefUndoData;
+
+ void BeginUndo();
+ void EndUndo();
+// void BeginRedo();
+// void EndRedo();
+
+private:
+ void UndoRef();
+};
+
+class ScUndoWrapper: public SfxUndoAction // for manual merging of actions
+{
+ std::unique_ptr<SfxUndoAction> pWrappedUndo;
+ ViewShellId mnViewShellId;
+
+public:
+ ScUndoWrapper( std::unique_ptr<SfxUndoAction> pUndo );
+ virtual ~ScUndoWrapper() override;
+
+ SfxUndoAction* GetWrappedUndo() { return pWrappedUndo.get(); }
+ void ForgetWrappedUndo();
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+ virtual bool Merge( SfxUndoAction *pNextAction ) override;
+ virtual OUString GetComment() const override;
+ virtual OUString GetRepeatComment(SfxRepeatTarget&) const override;
+ /// See SfxUndoAction::GetViewShellId().
+ ViewShellId GetViewShellId() const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undoblk.hxx b/sc/source/ui/inc/undoblk.hxx
new file mode 100644
index 000000000..a0de06cb6
--- /dev/null
+++ b/sc/source/ui/inc/undoblk.hxx
@@ -0,0 +1,983 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "undobase.hxx"
+#include <markdata.hxx>
+#include "spellparam.hxx"
+#include "cellmergeoption.hxx"
+#include <paramisc.hxx>
+#include <editeng/boxitem.hxx>
+
+#include <memory>
+
+class ScDocShell;
+class ScOutlineTable;
+class ScPatternAttr;
+class SvxSearchItem;
+class SdrUndoAction;
+class ScEditDataArray;
+
+class ScUndoInsertCells: public ScMoveUndo
+{
+public:
+ ScUndoInsertCells( ScDocShell* pNewDocShell,
+ const ScRange& rRange,
+ SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
+ InsCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData,
+ bool bNewPartOfPaste );
+ virtual ~ScUndoInsertCells() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat( SfxRepeatTarget& rTarget ) override;
+ virtual bool CanRepeat( SfxRepeatTarget& rTarget ) const override;
+
+ virtual OUString GetComment() const override;
+
+ virtual bool Merge( SfxUndoAction *pNextAction ) override;
+
+private:
+ ScRange aEffRange;
+ SCTAB nCount;
+ std::unique_ptr<SCTAB[]>
+ pTabs;
+ std::unique_ptr<SCTAB[]>
+ pScenarios;
+ sal_uLong nEndChangeAction;
+ InsCellCmd eCmd;
+ bool bPartOfPaste;
+ std::unique_ptr<SfxUndoAction>
+ pPasteUndo;
+
+ void DoChange ( const bool bUndo );
+ void SetChangeTrack();
+};
+
+class ScUndoDeleteCells: public ScMoveUndo
+{
+public:
+ ScUndoDeleteCells( ScDocShell* pNewDocShell,
+ const ScRange& rRange,
+ SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
+ DelCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData );
+ virtual ~ScUndoDeleteCells() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScRange aEffRange;
+ SCTAB nCount;
+ std::unique_ptr<SCTAB[]>
+ pTabs;
+ std::unique_ptr<SCTAB[]>
+ pScenarios;
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+ DelCellCmd eCmd;
+
+ void DoChange ( const bool bUndo );
+ void SetChangeTrack();
+};
+
+class ScUndoDeleteMulti: public ScMoveUndo
+{
+public:
+
+ ScUndoDeleteMulti( ScDocShell* pNewDocShell,
+ bool bNewRows, bool bNeedsRefresh, SCTAB nNewTab,
+ std::vector<sc::ColRowSpan>&& rSpans,
+ ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData );
+
+ virtual ~ScUndoDeleteMulti() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ bool mbRows:1;
+ bool mbRefresh:1;
+ SCTAB nTab;
+ std::vector<sc::ColRowSpan> maSpans;
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+
+ void DoChange() const;
+ void SetChangeTrack();
+};
+
+class SC_DLLPUBLIC ScUndoCut: public ScBlockUndo
+{
+public:
+ ScUndoCut(ScDocShell* pNewDocShell,
+ const ScRange& aRange, // adjusted for merged cells
+ const ScAddress& aOldEnd, // end position without adjustment
+ const ScMarkData& rMark, // selected sheets
+ ScDocumentUniquePtr pNewUndoDoc);
+ virtual ~ScUndoCut() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScMarkData aMarkData;
+ ScDocumentUniquePtr
+ pUndoDoc;
+ ScRange aExtendedRange;
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+
+ void DoChange( const bool bUndo );
+ void SetChangeTrack();
+};
+
+struct ScUndoPasteOptions
+{
+ ScPasteFunc nFunction;
+ bool bSkipEmptyCells;
+ bool bTranspose;
+ bool bAsLink;
+ InsCellCmd eMoveMode;
+
+ ScUndoPasteOptions() :
+ nFunction( ScPasteFunc::NONE ),
+ bSkipEmptyCells( false ),
+ bTranspose( false ),
+ bAsLink( false ),
+ eMoveMode( INS_NONE )
+ {}
+};
+
+class SC_DLLPUBLIC ScUndoPaste: public ScMultiBlockUndo
+{
+public:
+ ScUndoPaste(ScDocShell* pNewDocShell, const ScRangeList& rRanges,
+ const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
+ InsertDeleteFlags nNewFlags,
+ std::unique_ptr<ScRefUndoData> pRefData,
+ bool bRedoIsFilled = true,
+ const ScUndoPasteOptions* pOptions = nullptr);
+ virtual ~ScUndoPaste() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScMarkData aMarkData;
+ ScDocumentUniquePtr pUndoDoc;
+ ScDocumentUniquePtr pRedoDoc;
+ InsertDeleteFlags nFlags;
+ std::unique_ptr<ScRefUndoData> pRefUndoData;
+ std::unique_ptr<ScRefUndoData> pRefRedoData;
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+ bool bRedoFilled;
+ ScUndoPasteOptions aPasteOptions;
+
+ void DoChange(bool bUndo);
+ void SetChangeTrack();
+};
+
+class ScUndoDragDrop: public ScMoveUndo
+{
+public:
+ ScUndoDragDrop( ScDocShell* pNewDocShell,
+ const ScRange& rRange, const ScAddress& aNewDestPos, bool bNewCut,
+ ScDocumentUniquePtr pUndoDocument,
+ bool bScenario );
+ virtual ~ScUndoDragDrop() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ sal_uInt16 mnPaintExtFlags;
+ ScRangeList maPaintRanges;
+
+ ScRange aSrcRange;
+ ScRange aDestRange;
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+ bool bCut;
+ bool bKeepScenarioFlags;
+
+ void PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const;
+ void DoUndo( ScRange aRange );
+
+ void SetChangeTrack();
+};
+
+class ScUndoDeleteContents: public ScSimpleUndo
+{
+public:
+ ScUndoDeleteContents( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ const ScRange& rRange,
+ ScDocumentUniquePtr&& pNewUndoDoc, bool bNewMulti,
+ InsertDeleteFlags nNewFlags, bool bObjects );
+ virtual ~ScUndoDeleteContents() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+ void SetDataSpans( const std::shared_ptr<DataSpansType>& pSpans );
+
+private:
+ std::shared_ptr<DataSpansType> mpDataSpans; // Spans of non-empty cells.
+
+ ScRange aRange;
+ ScMarkData aMarkData;
+ ScDocumentUniquePtr pUndoDoc; // Block mark and deleted data
+ std::unique_ptr<SdrUndoAction> pDrawUndo; // Deleted objects
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+ InsertDeleteFlags nFlags;
+ bool bMulti; // Multi selection
+
+ void DoChange( const bool bUndo );
+ void SetChangeTrack();
+};
+
+class ScUndoFillTable: public ScSimpleUndo
+{
+public:
+ ScUndoFillTable( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, bool bNewMulti, SCTAB nSrc,
+ InsertDeleteFlags nFlg, ScPasteFunc nFunc, bool bSkip, bool bLink );
+ virtual ~ScUndoFillTable() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScRange aRange;
+ ScMarkData aMarkData;
+ ScDocumentUniquePtr
+ pUndoDoc; // Block mark and deleted data
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+ InsertDeleteFlags nFlags;
+ ScPasteFunc nFunction;
+ SCTAB nSrcTab;
+ bool bMulti; // Multi selection
+ bool bSkipEmpty;
+ bool bAsLink;
+
+ void DoChange( const bool bUndo );
+ void SetChangeTrack();
+};
+
+class ScUndoSelectionAttr: public ScSimpleUndo
+{
+public:
+ ScUndoSelectionAttr( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, bool bNewMulti,
+ const ScPatternAttr* pNewApply,
+ const SvxBoxItem* pNewOuter = nullptr,
+ const SvxBoxInfoItem* pNewInner = nullptr,
+ const ScRange* pRangeCover = nullptr );
+ virtual ~ScUndoSelectionAttr() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+ ScEditDataArray* GetDataArray();
+private:
+ ScMarkData aMarkData;
+ ScRange aRange;
+ ScRange aRangeCover;
+ std::unique_ptr<ScEditDataArray> mpDataArray;
+ ScDocumentUniquePtr pUndoDoc;
+ bool bMulti;
+ ScPatternAttr* pApplyPattern;
+ SvxBoxItem* pLineOuter;
+ SvxBoxInfoItem* pLineInner;
+
+ void DoChange( const bool bUndo );
+ void ChangeEditData( const bool bUndo );
+};
+
+class ScUndoWidthOrHeight: public ScSimpleUndo
+{
+public:
+ ScUndoWidthOrHeight( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ SCCOLROW nNewStart, SCTAB nNewStartTab,
+ SCCOLROW nNewEnd, SCTAB nNewEndTab,
+ ScDocumentUniquePtr pNewUndoDoc,
+ std::vector<sc::ColRowSpan>&& rRanges,
+ std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ ScSizeMode eNewMode, sal_uInt16 nNewSizeTwips,
+ bool bNewWidth );
+ virtual ~ScUndoWidthOrHeight() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScMarkData aMarkData;
+ SCCOLROW nStart;
+ SCCOLROW nEnd;
+ SCTAB nStartTab;
+ SCTAB nEndTab;
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScOutlineTable> pUndoTab;
+ std::vector<sc::ColRowSpan> maRanges;
+ sal_uInt16 nNewSize;
+ bool bWidth;
+ ScSizeMode eMode;
+ std::unique_ptr<SdrUndoAction> pDrawUndo;
+};
+
+class ScUndoAutoFill: public ScBlockUndo
+{
+public:
+ ScUndoAutoFill( ScDocShell* pNewDocShell,
+ const ScRange& rRange, const ScRange& rSourceArea,
+ ScDocumentUniquePtr pNewUndoDoc, const ScMarkData& rMark,
+ FillDir eNewFillDir,
+ FillCmd eNewFillCmd, FillDateCmd eNewFillDateCmd,
+ double fNewStartValue, double fNewStepValue, double fNewMaxValue );
+ virtual ~ScUndoAutoFill() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScRange aSource;
+ ScMarkData aMarkData;
+ ScDocumentUniquePtr
+ pUndoDoc;
+ FillDir eFillDir;
+ FillCmd eFillCmd;
+ FillDateCmd eFillDateCmd;
+ double fStartValue;
+ double fStepValue;
+ double fMaxValue;
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+
+ void SetChangeTrack();
+};
+
+class ScUndoMerge: public ScSimpleUndo
+{
+public:
+ ScUndoMerge( ScDocShell* pNewDocShell, const ScCellMergeOption& rOption,
+ bool bMergeContents, ScDocumentUniquePtr pUndoDoc,
+ std::unique_ptr<SdrUndoAction> pDrawUndo);
+ virtual ~ScUndoMerge() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScCellMergeOption maOption;
+ bool mbMergeContents; // Merge contents in Redo().
+ ScDocumentUniquePtr mxUndoDoc; // when data is merged
+ std::unique_ptr<SdrUndoAction> mpDrawUndo;
+
+ void DoChange( bool bUndo ) const;
+};
+
+class ScUndoAutoFormat: public ScBlockUndo
+{
+public:
+ ScUndoAutoFormat( ScDocShell* pNewDocShell,
+ const ScRange& rRange, ScDocumentUniquePtr pNewUndoDoc,
+ const ScMarkData& rMark,
+ bool bNewSize, sal_uInt16 nNewFormatNo );
+ virtual ~ScUndoAutoFormat() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScDocumentUniquePtr
+ pUndoDoc; // deleted data
+ ScMarkData aMarkData;
+ bool bSize;
+ sal_uInt16 nFormatNo;
+};
+
+class ScUndoReplace: public ScSimpleUndo
+{
+public:
+ ScUndoReplace( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
+ const OUString& rNewUndoStr, ScDocumentUniquePtr pNewUndoDoc,
+ const SvxSearchItem* pItem );
+ virtual ~ScUndoReplace() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScAddress aCursorPos;
+ ScMarkData aMarkData;
+ OUString aUndoStr; // Data at single selection
+ ScDocumentUniquePtr pUndoDoc; // Block mark and deleted data
+ std::unique_ptr<SvxSearchItem> pSearchItem;
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+
+ void SetChangeTrack();
+};
+
+class ScUndoTabOp: public ScSimpleUndo
+{
+public:
+ ScUndoTabOp( ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc,
+ const ScRefAddress& rFormulaCell,
+ const ScRefAddress& rFormulaEnd,
+ const ScRefAddress& rRowCell,
+ const ScRefAddress& rColCell,
+ ScTabOpParam::Mode eMode );
+ virtual ~ScUndoTabOp() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScRange aRange;
+ ScDocumentUniquePtr
+ pUndoDoc; // Deleted data
+ ScRefAddress theFormulaCell;
+ ScRefAddress theFormulaEnd;
+ ScRefAddress theRowCell;
+ ScRefAddress theColCell;
+ ScTabOpParam::Mode meMode;
+};
+
+class ScUndoConversion : public ScSimpleUndo
+{
+public:
+
+ ScUndoConversion( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, ScDocumentUniquePtr pNewUndoDoc,
+ SCCOL nNewX, SCROW nNewY, SCTAB nNewZ, ScDocumentUniquePtr pNewRedoDoc,
+ const ScConversionParam& rConvParam );
+ virtual ~ScUndoConversion() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScMarkData aMarkData;
+ ScAddress aCursorPos;
+ ScDocumentUniquePtr pUndoDoc; // Block mark and deleted data
+ ScAddress aNewCursorPos;
+ ScDocumentUniquePtr pRedoDoc; // Block mark and new data
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+ ScConversionParam maConvParam; /// Conversion type and parameters.
+
+ void DoChange( ScDocument* pRefDoc, const ScAddress& rCursorPos );
+ void SetChangeTrack();
+};
+
+class ScUndoRefConversion: public ScSimpleUndo
+{
+public:
+ ScUndoRefConversion( ScDocShell* pNewDocShell,
+ const ScRange& aMarkRange, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc, bool bNewMulti);
+ virtual ~ScUndoRefConversion() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScMarkData aMarkData;
+ ScDocumentUniquePtr pUndoDoc;
+ ScDocumentUniquePtr pRedoDoc;
+ ScRange aRange;
+ bool bMulti;
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+
+ void DoChange( ScDocument* pRefDoc);
+ void SetChangeTrack();
+};
+
+class ScUndoListNames: public ScBlockUndo
+{
+public:
+ ScUndoListNames(ScDocShell* pNewDocShell,
+ const ScRange& rRange,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScDocumentUniquePtr xUndoDoc;
+ ScDocumentUniquePtr xRedoDoc;
+
+ void DoChange( ScDocument* pSrcDoc ) const;
+};
+
+class ScUndoConditionalFormat : public ScSimpleUndo
+{
+public:
+ ScUndoConditionalFormat( ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pUndoDoc, ScDocumentUniquePtr pRedoDoc, const ScRange& rRange);
+ virtual ~ScUndoConditionalFormat() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ void DoChange(ScDocument* pDoc);
+ ScDocumentUniquePtr mpUndoDoc;
+ ScDocumentUniquePtr mpRedoDoc;
+ ScRange maRange;
+};
+
+class ScUndoConditionalFormatList : public ScSimpleUndo
+{
+public:
+ ScUndoConditionalFormatList( ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pUndoDoc, ScDocumentUniquePtr pRedoDoc, SCTAB nTab);
+ virtual ~ScUndoConditionalFormatList() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ void DoChange(const ScDocument* pDoc);
+ ScDocumentUniquePtr mpUndoDoc;
+ ScDocumentUniquePtr mpRedoDoc;
+ SCTAB mnTab;
+};
+
+class ScUndoUseScenario: public ScSimpleUndo
+{
+public:
+ ScUndoUseScenario( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ const ScArea& rDestArea, ScDocumentUniquePtr pNewUndoDoc,
+ const OUString& rNewName );
+ virtual ~ScUndoUseScenario() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScDocumentUniquePtr
+ pUndoDoc;
+ ScRange aRange;
+ ScMarkData aMarkData;
+ OUString aName;
+};
+
+class ScUndoSelectionStyle: public ScSimpleUndo
+{
+public:
+ ScUndoSelectionStyle( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ const ScRange& rRange,
+ const OUString& rName,
+ ScDocumentUniquePtr pNewUndoDoc );
+ virtual ~ScUndoSelectionStyle() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScMarkData aMarkData;
+ ScDocumentUniquePtr
+ pUndoDoc;
+ OUString aStyleName;
+ ScRange aRange;
+
+ void DoChange( const bool bUndo );
+};
+
+class ScUndoRefreshLink: public ScSimpleUndo
+{
+public:
+ ScUndoRefreshLink(ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pNewUndoDoc);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScDocumentUniquePtr xUndoDoc;
+ ScDocumentUniquePtr xRedoDoc;
+};
+
+class ScUndoEnterMatrix: public ScBlockUndo
+{
+public:
+ ScUndoEnterMatrix( ScDocShell* pNewDocShell,
+ const ScRange& rArea,
+ ScDocumentUniquePtr pNewUndoDoc,
+ const OUString& rForm );
+ virtual ~ScUndoEnterMatrix() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScDocumentUniquePtr
+ pUndoDoc;
+ OUString aFormula;
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+
+ void SetChangeTrack();
+};
+
+class ScUndoInsertAreaLink : public ScSimpleUndo
+{
+public:
+ ScUndoInsertAreaLink( ScDocShell* pShell,
+ const OUString& rDocName,
+ const OUString& rFltName, const OUString& rOptions,
+ const OUString& rAreaName, const ScRange& rDestRange,
+ sal_uLong nRefreshDelay );
+ virtual ~ScUndoInsertAreaLink() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ OUString aDocName;
+ OUString aFltName;
+ OUString aOptions;
+ OUString aAreaName;
+ ScRange aRange;
+ sal_uLong nRefreshDelay;
+};
+
+class ScUndoRemoveAreaLink : public ScSimpleUndo
+{
+public:
+ ScUndoRemoveAreaLink( ScDocShell* pShell,
+ const OUString& rDocName,
+ const OUString& rFltName, const OUString& rOptions,
+ const OUString& rAreaName, const ScRange& rDestRange,
+ sal_uLong nRefreshDelay );
+ virtual ~ScUndoRemoveAreaLink() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ OUString aDocName;
+ OUString aFltName;
+ OUString aOptions;
+ OUString aAreaName;
+ ScRange aRange;
+ sal_uLong nRefreshDelay;
+};
+
+class ScUndoUpdateAreaLink : public ScSimpleUndo //! also change BlockUndo?
+{
+public:
+ ScUndoUpdateAreaLink(ScDocShell* pShell,
+ const OUString& rOldD,
+ const OUString& rOldF, const OUString& rOldO,
+ const OUString& rOldA, const ScRange& rOldR,
+ sal_uLong nOldRD,
+ const OUString& rNewD,
+ const OUString& rNewF, const OUString& rNewO,
+ const OUString& rNewA, const ScRange& rNewR,
+ sal_uLong nNewRD,
+ ScDocumentUniquePtr pUndo, ScDocumentUniquePtr pRedo,
+ bool bDoInsert);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ OUString aOldDoc;
+ OUString aOldFlt;
+ OUString aOldOpt;
+ OUString aOldArea;
+ ScRange aOldRange;
+ OUString aNewDoc;
+ OUString aNewFlt;
+ OUString aNewOpt;
+ OUString aNewArea;
+ ScRange aNewRange;
+ ScDocumentUniquePtr xUndoDoc;
+ ScDocumentUniquePtr xRedoDoc;
+ sal_uLong nOldRefresh;
+ sal_uLong nNewRefresh;
+ bool bWithInsert;
+
+ void DoChange( const bool bUndo ) const;
+};
+
+class ScUndoIndent: public ScBlockUndo
+{
+public:
+ ScUndoIndent( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, bool bIncrement );
+ virtual ~ScUndoIndent() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScMarkData aMarkData;
+ ScDocumentUniquePtr
+ pUndoDoc;
+ bool bIsIncrement;
+};
+
+class ScUndoTransliterate: public ScBlockUndo
+{
+public:
+ ScUndoTransliterate( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, TransliterationFlags nType );
+ virtual ~ScUndoTransliterate() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScMarkData aMarkData;
+ ScDocumentUniquePtr
+ pUndoDoc;
+ TransliterationFlags
+ nTransliterationType;
+};
+
+class ScUndoClearItems: public ScBlockUndo
+{
+public:
+ ScUndoClearItems( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, const sal_uInt16* pW );
+ virtual ~ScUndoClearItems() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScMarkData aMarkData;
+ ScDocumentUniquePtr
+ pUndoDoc;
+ std::unique_ptr<sal_uInt16[]>
+ pWhich;
+};
+
+class ScUndoRemoveBreaks: public ScSimpleUndo
+{
+public:
+ ScUndoRemoveBreaks( ScDocShell* pNewDocShell,
+ SCTAB nNewTab, ScDocumentUniquePtr pNewUndoDoc );
+ virtual ~ScUndoRemoveBreaks() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCTAB nTab;
+ ScDocumentUniquePtr
+ pUndoDoc;
+};
+
+class ScUndoRemoveMerge: public ScBlockUndo
+{
+public:
+ ScUndoRemoveMerge( ScDocShell* pNewDocShell,
+ const ScCellMergeOption& rOption,
+ ScDocumentUniquePtr pNewUndoDoc );
+ ScUndoRemoveMerge( ScDocShell* pNewDocShell,
+ const ScRange& rRange,
+ ScDocumentUniquePtr pNewUndoDoc );
+ virtual ~ScUndoRemoveMerge() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+ ScDocument* GetUndoDoc();
+ void AddCellMergeOption( const ScCellMergeOption& rOption );
+
+private:
+ void SetCurTab();
+
+ std::vector<ScCellMergeOption> maOptions;
+ ScDocumentUniquePtr pUndoDoc;
+};
+
+class ScUndoBorder: public ScBlockUndo
+{
+public:
+ ScUndoBorder(ScDocShell* pNewDocShell,
+ const ScRangeList& rRangeList,
+ ScDocumentUniquePtr pNewUndoDoc,
+ const SvxBoxItem& rNewOuter,
+ const SvxBoxInfoItem& rNewInner);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScDocumentUniquePtr xUndoDoc;
+ std::unique_ptr<ScRangeList> xRanges;
+ std::unique_ptr<SvxBoxItem> xOuter;
+ std::unique_ptr<SvxBoxInfoItem> xInner;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undocell.hxx b/sc/source/ui/inc/undocell.hxx
new file mode 100644
index 000000000..b013e084f
--- /dev/null
+++ b/sc/source/ui/inc/undocell.hxx
@@ -0,0 +1,369 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "undobase.hxx"
+#include <detdata.hxx>
+#include <postit.hxx>
+#include <cellvalue.hxx>
+#include <cellvalues.hxx>
+#include <editeng/editobj.hxx>
+
+#include <memory>
+
+class ScDocShell;
+class ScPatternAttr;
+class ScRangeName;
+class ScFormulaCell;
+
+class ScUndoCursorAttr: public ScSimpleUndo
+{
+public:
+ ScUndoCursorAttr( ScDocShell* pNewDocShell,
+ SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
+ const ScPatternAttr* pOldPat, const ScPatternAttr* pNewPat,
+ const ScPatternAttr* pApplyPat );
+ virtual ~ScUndoCursorAttr() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+ /** once the objects are passed to this class, their life-cycle is
+ managed by this class; the calling function must pass new'ed
+ objects to this method. */
+ void SetEditData( std::unique_ptr<EditTextObject> pOld, std::unique_ptr<EditTextObject> pNew );
+
+private:
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ ScPatternAttr* pOldPattern;
+ ScPatternAttr* pNewPattern;
+ ScPatternAttr* pApplyPattern;
+ std::unique_ptr<EditTextObject> pOldEditData;
+ std::unique_ptr<EditTextObject> pNewEditData;
+
+ void DoChange( const ScPatternAttr* pWhichPattern, const std::unique_ptr<EditTextObject>& pEditData ) const;
+};
+
+class ScUndoEnterData: public ScSimpleUndo
+{
+public:
+
+ struct Value
+ {
+ SCTAB mnTab;
+ bool mbHasFormat;
+ sal_uInt32 mnFormat;
+ ScCellValue maCell;
+
+ Value();
+ };
+
+ typedef std::vector<Value> ValuesType;
+
+ ScUndoEnterData(
+ ScDocShell* pNewDocShell, const ScAddress& rPos,
+ ValuesType& rOldValues, const OUString& rNewStr, std::unique_ptr<EditTextObject> pObj );
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ValuesType maOldValues;
+
+ OUString maNewString;
+ std::unique_ptr<EditTextObject> mpNewEditData;
+ sal_uLong mnEndChangeAction;
+ ScAddress maPos;
+
+ void DoChange() const;
+ void SetChangeTrack();
+};
+
+class ScUndoEnterValue: public ScSimpleUndo
+{
+public:
+ ScUndoEnterValue(
+ ScDocShell* pNewDocShell, const ScAddress& rNewPos,
+ const ScCellValue& rUndoCell, double nVal );
+
+ virtual ~ScUndoEnterValue() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScAddress aPos;
+ ScCellValue maOldCell;
+ double nValue;
+ sal_uLong nEndChangeAction;
+
+ void SetChangeTrack();
+};
+
+class ScUndoSetCell : public ScSimpleUndo
+{
+public:
+ ScUndoSetCell( ScDocShell* pDocSh, const ScAddress& rPos, const ScCellValue& rOldVal, const ScCellValue& rNewVal );
+
+ virtual ~ScUndoSetCell() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat( SfxRepeatTarget& rTarget ) override;
+ virtual bool CanRepeat( SfxRepeatTarget& rTarget ) const override;
+ virtual OUString GetComment() const override;
+
+private:
+ void SetChangeTrack();
+ void SetValue( const ScCellValue& rVal );
+ void MoveCursorToCell();
+
+private:
+ ScAddress maPos;
+ ScCellValue maOldValue;
+ ScCellValue maNewValue;
+ sal_uLong mnEndChangeAction;
+};
+
+class ScUndoPageBreak: public ScSimpleUndo
+{
+public:
+ ScUndoPageBreak( ScDocShell* pNewDocShell,
+ SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
+ bool bNewColumn, bool bNewInsert );
+ virtual ~ScUndoPageBreak() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ bool bColumn; // Column or row break
+ bool bInsert; // Insert or Delete
+
+ void DoChange( bool bInsert ) const;
+};
+
+class ScUndoPrintZoom: public ScSimpleUndo
+{
+public:
+ ScUndoPrintZoom( ScDocShell* pNewDocShell, SCTAB nT,
+ sal_uInt16 nOS, sal_uInt16 nOP, sal_uInt16 nNS, sal_uInt16 nNP );
+ virtual ~ScUndoPrintZoom() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCTAB nTab;
+ sal_uInt16 nOldScale;
+ sal_uInt16 nOldPages;
+ sal_uInt16 nNewScale;
+ sal_uInt16 nNewPages;
+
+ void DoChange( bool bUndo );
+};
+
+class ScUndoThesaurus: public ScSimpleUndo
+{
+public:
+ ScUndoThesaurus( ScDocShell* pNewDocShell,
+ SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
+ const ScCellValue& rOldText, const ScCellValue& rNewText );
+ virtual ~ScUndoThesaurus() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ sal_uLong nEndChangeAction;
+
+ ScCellValue maOldText;
+ ScCellValue maNewText;
+
+ void DoChange( bool bUndo, const ScCellValue& rText );
+ void SetChangeTrack( const ScCellValue& rOldCell );
+};
+
+/** Undo action for inserting, removing, and replacing a cell note. */
+class ScUndoReplaceNote : public ScSimpleUndo
+{
+public:
+
+ /** Constructs an undo action for inserting or removing a cell note. */
+ ScUndoReplaceNote(
+ ScDocShell& rDocShell,
+ const ScAddress& rPos,
+ const ScNoteData& rNoteData,
+ bool bInsert,
+ std::unique_ptr<SdrUndoAction> pDrawUndo );
+
+ /** Constructs an undo action for replacing a cell note with another. */
+ ScUndoReplaceNote(
+ ScDocShell& rDocShell,
+ const ScAddress& rPos,
+ const ScNoteData& rOldData,
+ const ScNoteData& rNewData,
+ std::unique_ptr<SdrUndoAction> pDrawUndo );
+
+ virtual ~ScUndoReplaceNote() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat( SfxRepeatTarget& rTarget ) override;
+ virtual bool CanRepeat( SfxRepeatTarget& rTarget ) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ void DoInsertNote( const ScNoteData& rNoteData );
+ void DoRemoveNote( const ScNoteData& rNoteData );
+
+private:
+ ScAddress maPos;
+ ScNoteData maOldData;
+ ScNoteData maNewData;
+ std::unique_ptr<SdrUndoAction> mpDrawUndo;
+};
+
+/** Undo action for showing or hiding a cell note caption. */
+class ScUndoShowHideNote : public ScSimpleUndo
+{
+public:
+ ScUndoShowHideNote( ScDocShell& rDocShell, const ScAddress& rPos, bool bShow );
+ virtual ~ScUndoShowHideNote() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat( SfxRepeatTarget& rTarget ) override;
+ virtual bool CanRepeat( SfxRepeatTarget& rTarget ) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScAddress maPos;
+ bool mbShown;
+};
+
+class ScUndoDetective: public ScSimpleUndo
+{
+public:
+ ScUndoDetective( ScDocShell* pNewDocShell,
+ std::unique_ptr<SdrUndoAction> pDraw, const ScDetOpData* pOperation,
+ std::unique_ptr<ScDetOpList> pUndoList = nullptr );
+ virtual ~ScUndoDetective() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ bool bIsDelete;
+ std::unique_ptr<ScDetOpList> pOldList;
+ sal_uInt16 nAction;
+ ScAddress aPos;
+ std::unique_ptr<SdrUndoAction> pDrawUndo;
+};
+
+class ScUndoRangeNames: public ScSimpleUndo
+{
+public:
+ //use nTab = -1 for global range names
+ ScUndoRangeNames( ScDocShell* pNewDocShell,
+ std::unique_ptr<ScRangeName> pOld, std::unique_ptr<ScRangeName> pNew , SCTAB nTab);
+ virtual ~ScUndoRangeNames() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ std::unique_ptr<ScRangeName> pOldRanges;
+ std::unique_ptr<ScRangeName> pNewRanges;
+ SCTAB mnTab;
+
+ void DoChange( bool bUndo );
+};
+
+namespace sc {
+
+class UndoSetCells : public ScSimpleUndo
+{
+ ScAddress maTopPos;
+ CellValues maOldValues;
+ CellValues maNewValues;
+
+ void DoChange( const CellValues& rValues );
+
+public:
+ UndoSetCells( ScDocShell* pDocSh, const ScAddress& rTopPos );
+ virtual ~UndoSetCells() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+ virtual bool CanRepeat( SfxRepeatTarget& ) const override;
+ virtual OUString GetComment() const override;
+
+ CellValues& GetOldValues() { return maOldValues;}
+ void SetNewValues( const std::vector<double>& rVals );
+ void SetNewValues( const std::vector<ScFormulaCell*>& rVals );
+};
+
+} // namespace sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undoconvert.hxx b/sc/source/ui/inc/undoconvert.hxx
new file mode 100644
index 000000000..428710d83
--- /dev/null
+++ b/sc/source/ui/inc/undoconvert.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "undobase.hxx"
+#include <cellvalues.hxx>
+
+namespace sc
+{
+class UndoFormulaToValue : public ScSimpleUndo
+{
+ TableValues maUndoValues;
+
+public:
+ UndoFormulaToValue(ScDocShell* pDocSh, TableValues& rUndoValues);
+
+ virtual OUString GetComment() const override;
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+private:
+ void Execute();
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undodat.hxx b/sc/source/ui/inc/undodat.hxx
new file mode 100644
index 000000000..486fe07d1
--- /dev/null
+++ b/sc/source/ui/inc/undodat.hxx
@@ -0,0 +1,446 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "undobase.hxx"
+#include "refundo.hxx"
+#include <dpobject.hxx>
+#include <olinetab.hxx>
+#include <rangeutl.hxx>
+#include <rangelst.hxx>
+#include <queryparam.hxx>
+#include <subtotalparam.hxx>
+
+#include <memory>
+
+class ScDocShell;
+class SdrUndoAction;
+
+class ScUndoDoOutline: public ScSimpleUndo
+{
+public:
+ ScUndoDoOutline( ScDocShell* pNewDocShell,
+ SCCOLROW nNewStart, SCCOLROW nNewEnd, SCTAB nNewTab,
+ ScDocumentUniquePtr pNewUndoDoc, bool bNewColumns,
+ sal_uInt16 nNewLevel, sal_uInt16 nNewEntry, bool bNewShow );
+ virtual ~ScUndoDoOutline() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCCOLROW nStart;
+ SCCOLROW nEnd;
+ SCTAB nTab;
+ ScDocumentUniquePtr
+ pUndoDoc;
+ bool bColumns;
+ sal_uInt16 nLevel;
+ sal_uInt16 nEntry;
+ bool bShow;
+};
+
+class ScUndoMakeOutline: public ScSimpleUndo
+{
+public:
+ ScUndoMakeOutline( ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ bool bNewColumns, bool bNewMake );
+ virtual ~ScUndoMakeOutline() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScAddress aBlockStart;
+ ScAddress aBlockEnd;
+ std::unique_ptr<ScOutlineTable>
+ pUndoTable;
+ bool bColumns;
+ bool bMake;
+};
+
+class ScUndoOutlineLevel: public ScSimpleUndo
+{
+public:
+ ScUndoOutlineLevel(ScDocShell* pNewDocShell,
+ SCCOLROW nNewStart, SCCOLROW nNewEnd, SCTAB nNewTab,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ bool bNewColumns, sal_uInt16 nNewLevel);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCCOLROW nStart;
+ SCCOLROW nEnd;
+ SCTAB nTab;
+ ScDocumentUniquePtr xUndoDoc;
+ std::unique_ptr<ScOutlineTable> xUndoTable;
+ bool bColumns;
+ sal_uInt16 nLevel;
+};
+
+class ScUndoOutlineBlock: public ScSimpleUndo
+{
+public:
+ ScUndoOutlineBlock(ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ bool bNewShow);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScAddress aBlockStart;
+ ScAddress aBlockEnd;
+ ScDocumentUniquePtr xUndoDoc;
+ std::unique_ptr<ScOutlineTable> xUndoTable;
+ bool bShow;
+};
+
+class ScUndoRemoveAllOutlines: public ScSimpleUndo
+{
+public:
+ ScUndoRemoveAllOutlines(ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScAddress aBlockStart;
+ ScAddress aBlockEnd;
+ ScDocumentUniquePtr xUndoDoc;
+ std::unique_ptr<ScOutlineTable> xUndoTable;
+};
+
+class ScUndoAutoOutline: public ScSimpleUndo
+{
+public:
+ ScUndoAutoOutline(ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScAddress aBlockStart;
+ ScAddress aBlockEnd;
+ ScDocumentUniquePtr xUndoDoc;
+ std::unique_ptr<ScOutlineTable> xUndoTable;
+};
+
+class ScUndoSubTotals: public ScDBFuncUndo
+{
+public:
+ ScUndoSubTotals(ScDocShell* pNewDocShell, SCTAB nNewTab,
+ const ScSubTotalParam& rNewParam, SCROW nNewEndY,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ std::unique_ptr<ScRangeName> pNewUndoRange, std::unique_ptr<ScDBCollection> pNewUndoDB);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCTAB nTab;
+ ScSubTotalParam aParam; // The original passed parameter
+ SCROW nNewEndRow; // Size of result
+ ScDocumentUniquePtr xUndoDoc;
+ std::unique_ptr<ScOutlineTable> xUndoTable;
+ std::unique_ptr<ScRangeName> xUndoRange;
+ std::unique_ptr<ScDBCollection> xUndoDB;
+};
+
+class ScUndoQuery: public ScDBFuncUndo
+{
+public:
+ ScUndoQuery( ScDocShell* pNewDocShell, SCTAB nNewTab,
+ const ScQueryParam& rParam, ScDocumentUniquePtr pNewUndoDoc,
+ std::unique_ptr<ScDBCollection> pNewUndoDB, const ScRange* pOld,
+ bool bSize, const ScRange* pAdvSrc );
+ virtual ~ScUndoQuery() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ std::unique_ptr<SdrUndoAction> pDrawUndo;
+ SCTAB nTab;
+ ScQueryParam aQueryParam;
+ ScDocumentUniquePtr xUndoDoc;
+ std::unique_ptr<ScDBCollection> xUndoDB; // due to source and target range
+ ScRange aOldDest;
+ ScRange aAdvSource;
+ bool bIsAdvanced;
+ bool bDestArea;
+ bool bDoSize;
+};
+
+class ScUndoAutoFilter: public ScDBFuncUndo
+{
+private:
+ OUString aDBName;
+ bool bFilterSet;
+
+ void DoChange( bool bUndo );
+
+public:
+ ScUndoAutoFilter( ScDocShell* pNewDocShell, const ScRange& rRange,
+ const OUString& rName, bool bSet );
+ virtual ~ScUndoAutoFilter() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+};
+
+class ScUndoDBData: public ScSimpleUndo
+{
+public:
+ ScUndoDBData( ScDocShell* pNewDocShell,
+ std::unique_ptr<ScDBCollection> pNewUndoColl,
+ std::unique_ptr<ScDBCollection> pNewRedoColl );
+ virtual ~ScUndoDBData() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ std::unique_ptr<ScDBCollection> pUndoColl;
+ std::unique_ptr<ScDBCollection> pRedoColl;
+};
+
+class ScUndoImportData: public ScSimpleUndo
+{
+public:
+ ScUndoImportData(ScDocShell* pNewDocShell, SCTAB nNewTab,
+ const ScImportParam& rParam, SCCOL nNewEndX, SCROW nNewEndY,
+ SCCOL nNewFormula,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
+ std::unique_ptr<ScDBData> pNewUndoData, std::unique_ptr<ScDBData> pNewRedoData);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCTAB nTab;
+ ScImportParam aImportParam;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ ScDocumentUniquePtr xUndoDoc;
+ ScDocumentUniquePtr xRedoDoc;
+ std::unique_ptr<ScDBData> xUndoDBData;
+ std::unique_ptr<ScDBData> xRedoDBData;
+ SCCOL nFormulaCols;
+ bool bRedoFilled;
+};
+
+class ScUndoRepeatDB: public ScSimpleUndo
+{
+public:
+ ScUndoRepeatDB(ScDocShell* pNewDocShell, SCTAB nNewTab,
+ SCCOL nStartX, SCROW nStartY, SCCOL nEndX, SCROW nEndY,
+ SCROW nResultEndRow, SCCOL nCurX, SCROW nCurY,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ std::unique_ptr<ScRangeName> pNewUndoRange, std::unique_ptr<ScDBCollection> pNewUndoDB,
+ const ScRange* pOldQ, const ScRange* pNewQ);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScAddress aBlockStart;
+ ScAddress aBlockEnd;
+ SCROW nNewEndRow;
+ ScAddress aCursorPos;
+ ScDocumentUniquePtr xUndoDoc;
+ std::unique_ptr<ScOutlineTable> xUndoTable;
+ std::unique_ptr<ScRangeName> xUndoRange;
+ std::unique_ptr<ScDBCollection> xUndoDB;
+ ScRange aOldQuery;
+ ScRange aNewQuery;
+ bool bQuerySize;
+};
+
+class ScUndoDataPilot: public ScSimpleUndo
+{
+public:
+ ScUndoDataPilot(ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pOldDoc, ScDocumentUniquePtr pNewDoc,
+ const ScDPObject* pOldObj, const ScDPObject* pNewObj,
+ bool bMove);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScDocumentUniquePtr xOldUndoDoc;
+ ScDocumentUniquePtr xNewUndoDoc;
+ std::unique_ptr<ScDPObject> xOldDPObject;
+ std::unique_ptr<ScDPObject> xNewDPObject;
+ bool bAllowMove;
+};
+
+class ScUndoConsolidate: public ScSimpleUndo
+{
+public:
+ ScUndoConsolidate(ScDocShell* pNewDocShell,
+ const ScArea& rArea, const ScConsolidateParam& rPar,
+ ScDocumentUniquePtr pNewUndoDoc, bool bReference,
+ SCROW nInsCount, std::unique_ptr<ScOutlineTable> pTab,
+ std::unique_ptr<ScDBData> pData);
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScArea aDestArea;
+ ScDocumentUniquePtr xUndoDoc;
+ ScConsolidateParam aParam;
+ bool bInsRef;
+ SCSIZE nInsertCount;
+ std::unique_ptr<ScOutlineTable> xUndoTab;
+ std::unique_ptr<ScDBData> xUndoData;
+};
+
+class ScUndoChartData: public ScSimpleUndo
+{
+public:
+ ScUndoChartData( ScDocShell* pNewDocShell,
+ const OUString& rName, const ScRange& rNew,
+ bool bColHdr, bool bRowHdr, bool bAdd );
+ ScUndoChartData( ScDocShell* pNewDocShell,
+ const OUString& rName, const ScRangeListRef& rNew,
+ bool bColHdr, bool bRowHdr, bool bAdd );
+ virtual ~ScUndoChartData() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ OUString aChartName;
+ ScRangeListRef aOldRangeListRef;
+ bool bOldColHeaders;
+ bool bOldRowHeaders;
+// ScRange aNewRange;
+ ScRangeListRef aNewRangeListRef;
+ bool bNewColHeaders;
+ bool bNewRowHeaders;
+ bool bAddRange;
+
+ void Init();
+};
+
+class ScUndoDataForm: public ScBlockUndo
+{
+public:
+ ScUndoDataForm(ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
+ std::unique_ptr<ScRefUndoData> pRefData);
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ std::unique_ptr<ScMarkData> mxMarkData;
+ ScDocumentUniquePtr xUndoDoc;
+ ScDocumentUniquePtr xRedoDoc;
+ std::unique_ptr<ScRefUndoData> xRefUndoData;
+ std::unique_ptr<ScRefUndoData> xRefRedoData;
+ bool bRedoFilled;
+
+ void DoChange( const bool bUndo );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undodraw.hxx b/sc/source/ui/inc/undodraw.hxx
new file mode 100644
index 000000000..b12eebdb3
--- /dev/null
+++ b/sc/source/ui/inc/undodraw.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 <memory>
+#include <svl/undo.hxx>
+
+class ScDocShell;
+
+class ScUndoDraw: public SfxUndoAction
+{
+ std::unique_ptr<SfxUndoAction> pDrawUndo;
+ ScDocShell* pDocShell;
+ ViewShellId mnViewShellId;
+
+ void UpdateSubShell();
+
+public:
+ ScUndoDraw( std::unique_ptr<SfxUndoAction> pUndo, ScDocShell* pDocSh );
+ virtual ~ScUndoDraw() override;
+
+ std::unique_ptr<SfxUndoAction> ReleaseDrawUndo() { return std::move(pDrawUndo); }
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+ virtual bool Merge( SfxUndoAction *pNextAction ) override;
+ virtual OUString GetComment() const override;
+ virtual OUString GetRepeatComment(SfxRepeatTarget&) const override;
+ /// See SfxUndoAction::GetViewShellId().
+ ViewShellId GetViewShellId() const override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undoolk.hxx b/sc/source/ui/inc/undoolk.hxx
new file mode 100644
index 000000000..67d519438
--- /dev/null
+++ b/sc/source/ui/inc/undoolk.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>
+
+class SdrUndoAction;
+class ScDocument;
+
+std::unique_ptr<SdrUndoAction> GetSdrUndoAction( ScDocument* pDoc );
+void DoSdrUndoAction ( SdrUndoAction* pUndoAction, ScDocument* pDoc );
+void RedoSdrUndoAction ( SdrUndoAction* pUndoAction );
+void EnableDrawAdjust ( ScDocument* pDoc, bool bEnable );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undosort.hxx b/sc/source/ui/inc/undosort.hxx
new file mode 100644
index 000000000..64b4f0da7
--- /dev/null
+++ b/sc/source/ui/inc/undosort.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include "undobase.hxx"
+#include <sortparam.hxx>
+
+namespace sc {
+
+class UndoSort : public ScSimpleUndo
+{
+ ReorderParam maParam;
+
+public:
+ UndoSort( ScDocShell* pDocSh, const ReorderParam& rParam );
+
+ virtual OUString GetComment() const override;
+ virtual void Undo() override;
+ virtual void Redo() override;
+
+private:
+ void Execute( bool bUndo );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undostyl.hxx b/sc/source/ui/inc/undostyl.hxx
new file mode 100644
index 000000000..6c169c43e
--- /dev/null
+++ b/sc/source/ui/inc/undostyl.hxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <optional>
+#include <svl/style.hxx>
+#include <svl/itemset.hxx>
+#include "undobase.hxx"
+
+class ScDocShell;
+
+class ScStyleSaveData
+{
+private:
+ OUString aName;
+ OUString aParent;
+ std::optional<SfxItemSet> moItems;
+
+public:
+ ScStyleSaveData();
+ ScStyleSaveData( const ScStyleSaveData& rOther );
+ ScStyleSaveData& operator=( const ScStyleSaveData& rOther );
+
+ void InitFromStyle( const SfxStyleSheetBase* pSource );
+
+ const OUString& GetName() const { return aName; }
+ const OUString& GetParent() const { return aParent; }
+ const std::optional<SfxItemSet>& GetItems() const { return moItems; }
+};
+
+class ScUndoModifyStyle: public ScSimpleUndo
+{
+private:
+ SfxStyleFamily eFamily;
+ ScStyleSaveData aOldData;
+ ScStyleSaveData aNewData;
+
+ static void DoChange( ScDocShell* pDocSh,
+ const OUString& rName, SfxStyleFamily eStyleFamily,
+ const ScStyleSaveData& rData );
+
+public:
+ ScUndoModifyStyle( ScDocShell* pDocSh,
+ SfxStyleFamily eFam,
+ const ScStyleSaveData& rOld,
+ const ScStyleSaveData& rNew );
+ virtual ~ScUndoModifyStyle() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+};
+
+class ScUndoApplyPageStyle: public ScSimpleUndo
+{
+public:
+ ScUndoApplyPageStyle( ScDocShell* pDocSh, const OUString& rNewStyle );
+ virtual ~ScUndoApplyPageStyle() override;
+
+ void AddSheetAction( SCTAB nTab, const OUString& rOld );
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ struct ApplyStyleEntry
+ {
+ SCTAB mnTab;
+ OUString maOldStyle;
+ explicit ApplyStyleEntry( SCTAB nTab, const OUString& rOldStyle );
+ };
+ typedef ::std::vector< ApplyStyleEntry > ApplyStyleVec;
+
+ ApplyStyleVec maEntries;
+ OUString maNewStyle;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undotab.hxx b/sc/source/ui/inc/undotab.hxx
new file mode 100644
index 000000000..2d94d6965
--- /dev/null
+++ b/sc/source/ui/inc/undotab.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include "undobase.hxx"
+#include <tools/color.hxx>
+#include <tabbgcolor.hxx>
+
+#include <memory>
+#include <vector>
+
+class ScDocShell;
+class SdrUndoAction;
+class ScPrintRangeSaver;
+class SdrObject;
+class ScDocProtection;
+class ScTableProtection;
+class ScMarkData;
+
+class ScUndoInsertTab : public ScSimpleUndo
+{
+public:
+ ScUndoInsertTab(
+ ScDocShell* pNewDocShell,
+ SCTAB nTabNum,
+ bool bApp,
+ const OUString& rNewName);
+ virtual ~ScUndoInsertTab() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ OUString sNewName;
+ std::unique_ptr<SdrUndoAction> pDrawUndo;
+ sal_uLong nEndChangeAction;
+ SCTAB nTab;
+ bool bAppend;
+
+ void SetChangeTrack();
+};
+
+class ScUndoInsertTables : public ScSimpleUndo
+{
+public:
+ ScUndoInsertTables(
+ ScDocShell* pNewDocShell,
+ SCTAB nTabNum,
+ std::vector<OUString>&& newNameList);
+ virtual ~ScUndoInsertTables() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+
+ std::unique_ptr<SdrUndoAction> pDrawUndo;
+ std::vector<OUString> aNameList;
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+ SCTAB nTab;
+
+ void SetChangeTrack();
+};
+
+class ScUndoDeleteTab: public ScMoveUndo
+{
+public:
+ ScUndoDeleteTab(
+ ScDocShell* pNewDocShell,
+ const std::vector<SCTAB> &theTabs, //SCTAB nNewTab,
+ ScDocumentUniquePtr pUndoDocument,
+ std::unique_ptr<ScRefUndoData> pRefData );
+ virtual ~ScUndoDeleteTab() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ std::vector<SCTAB> theTabs;
+ sal_uLong nStartChangeAction;
+ sal_uLong nEndChangeAction;
+
+ void SetChangeTrack();
+};
+
+class ScUndoRenameTab: public ScSimpleUndo
+{
+public:
+ ScUndoRenameTab(
+ ScDocShell* pNewDocShell,
+ SCTAB nT,
+ const OUString& rOldName,
+ const OUString& rNewName);
+ virtual ~ScUndoRenameTab() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCTAB nTab;
+ OUString sOldName;
+ OUString sNewName;
+
+ void DoChange( SCTAB nTab, const OUString& rName ) const;
+};
+
+class ScUndoMoveTab: public ScSimpleUndo
+{
+public:
+ ScUndoMoveTab(
+ ScDocShell* pNewDocShell,
+ std::unique_ptr<std::vector<SCTAB>> pOldTabs,
+ std::unique_ptr<std::vector<SCTAB>> pNewTabs,
+ std::unique_ptr<std::vector< OUString>> pOldNames = nullptr,
+ std::unique_ptr<std::vector< OUString>> pNewNames = nullptr );
+
+ virtual ~ScUndoMoveTab() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ std::unique_ptr< ::std::vector<SCTAB> > mpOldTabs;
+ std::unique_ptr< ::std::vector<SCTAB> > mpNewTabs;
+ std::unique_ptr< ::std::vector< OUString> > mpOldNames;
+ std::unique_ptr< ::std::vector< OUString> > mpNewNames;
+
+ void DoChange( bool bUndo ) const;
+};
+
+class ScUndoCopyTab: public ScSimpleUndo
+{
+public:
+ ScUndoCopyTab(
+ ScDocShell* pNewDocShell,
+ std::unique_ptr<std::vector<SCTAB>> pOldTabs,
+ std::unique_ptr<std::vector<SCTAB>> pNewTabs,
+ std::unique_ptr<std::vector< OUString>> pNewNames = nullptr );
+
+ virtual ~ScUndoCopyTab() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ std::unique_ptr< ::std::vector<SCTAB> > mpOldTabs;
+ std::unique_ptr< ::std::vector<SCTAB> > mpNewTabs;
+ std::unique_ptr< ::std::vector< OUString> > mpNewNames;
+ std::unique_ptr<SdrUndoAction> pDrawUndo;
+
+ void DoChange() const;
+};
+
+class ScUndoTabColor: public ScSimpleUndo
+{
+public:
+ ScUndoTabColor(
+ ScDocShell* pNewDocShell,
+ SCTAB nT,
+ const Color& aOTabBgColor,
+ const Color& aNTabBgColor);
+ ScUndoTabColor(
+ ScDocShell* pNewDocShell,
+ ScUndoTabColorInfo::List&& rUndoTabColorList);
+ virtual ~ScUndoTabColor() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ScUndoTabColorInfo::List aTabColorList;
+
+ void DoChange(bool bUndoType) const;
+};
+
+class ScUndoMakeScenario: public ScSimpleUndo
+{
+public:
+ ScUndoMakeScenario(
+ ScDocShell* pNewDocShell,
+ SCTAB nSrc, SCTAB nDest,
+ const OUString& rN, const OUString& rC,
+ const Color& rCol, ScScenarioFlags nF,
+ const ScMarkData& rMark );
+ virtual ~ScUndoMakeScenario() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ std::unique_ptr<ScMarkData> mpMarkData;
+ SCTAB nSrcTab;
+ SCTAB nDestTab;
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ std::unique_ptr<SdrUndoAction> pDrawUndo;
+};
+
+class ScUndoImportTab : public ScSimpleUndo
+{
+public:
+ ScUndoImportTab(
+ ScDocShell* pShell,
+ SCTAB nNewTab, SCTAB nNewCount );
+ virtual ~ScUndoImportTab() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCTAB nTab;
+ SCTAB nCount;
+ ScDocumentUniquePtr xRedoDoc;
+ std::unique_ptr<SdrUndoAction> pDrawUndo;
+
+ void DoChange() const;
+};
+
+class ScUndoRemoveLink : public ScSimpleUndo
+{
+public:
+ ScUndoRemoveLink( // Call before delete!
+ ScDocShell* pShell,
+ const OUString& rDoc );
+ virtual ~ScUndoRemoveLink() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ OUString aDocName;
+ OUString aFltName;
+ OUString aOptions;
+ sal_uLong nRefreshDelay;
+ sal_uInt16 nCount;
+ std::unique_ptr<SCTAB[]>
+ pTabs;
+ std::unique_ptr<ScLinkMode[]>
+ pModes;
+ std::unique_ptr<OUString[]>
+ pTabNames;
+
+ void DoChange( bool bLink ) const;
+};
+
+class ScUndoShowHideTab : public ScSimpleUndo
+{
+public:
+ ScUndoShowHideTab(
+ ScDocShell* pShell,
+ std::vector<SCTAB>&& newUndoTabs,
+ bool bNewShow );
+ virtual ~ScUndoShowHideTab() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ std::vector<SCTAB> undoTabs;
+ bool bShow;
+
+ void DoChange( bool bShow ) const;
+};
+
+/** This class implements undo & redo of document protect & unprotect
+ operations. */
+class ScUndoDocProtect : public ScSimpleUndo
+{
+public:
+ ScUndoDocProtect(ScDocShell* pShell, ::std::unique_ptr<ScDocProtection> && pProtectSettings);
+ virtual ~ScUndoDocProtect() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ ::std::unique_ptr<ScDocProtection> mpProtectSettings;
+
+ void DoProtect(bool bProtect);
+};
+
+/** This class implements undo & redo of both protect and unprotect of
+ sheet. */
+class ScUndoTabProtect : public ScSimpleUndo
+{
+public:
+ ScUndoTabProtect(ScDocShell* pShell, SCTAB nTab,
+ std::unique_ptr<ScTableProtection> && pProtectSettings);
+ virtual ~ScUndoTabProtect() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCTAB mnTab;
+ ::std::unique_ptr<ScTableProtection> mpProtectSettings;
+
+ void DoProtect(bool bProtect);
+};
+
+class ScUndoPrintRange : public ScSimpleUndo
+{
+public:
+ ScUndoPrintRange( ScDocShell* pShell, SCTAB nNewTab,
+ std::unique_ptr<ScPrintRangeSaver> pOld,
+ std::unique_ptr<ScPrintRangeSaver> pNew );
+ virtual ~ScUndoPrintRange() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCTAB nTab;
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges;
+ std::unique_ptr<ScPrintRangeSaver> pNewRanges;
+
+ void DoChange( bool bUndo );
+};
+
+class ScUndoScenarioFlags: public ScSimpleUndo
+{
+public:
+ ScUndoScenarioFlags(
+ ScDocShell* pNewDocShell, SCTAB nT,
+ const OUString& rON, const OUString& rNN,
+ const OUString& rOC, const OUString& rNC,
+ const Color& rOCol, const Color& rNCol,
+ ScScenarioFlags nOF, ScScenarioFlags nNF);
+
+ virtual ~ScUndoScenarioFlags() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCTAB nTab;
+ OUString aOldName;
+ OUString aNewName;
+ OUString aOldComment;
+ OUString aNewComment;
+ Color aOldColor;
+ Color aNewColor;
+ ScScenarioFlags nOldFlags;
+ ScScenarioFlags nNewFlags;
+};
+
+class ScUndoRenameObject: public ScSimpleUndo
+{
+public:
+ ScUndoRenameObject(
+ ScDocShell* pNewDocShell, const OUString& rPN,
+ const OUString& rON, const OUString& rNN );
+
+ virtual ~ScUndoRenameObject() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ OUString aPersistName; // to find object (works only for OLE objects)
+ OUString aOldName;
+ OUString aNewName;
+
+ SdrObject* GetObject();
+};
+
+class ScUndoLayoutRTL : public ScSimpleUndo
+{
+public:
+ ScUndoLayoutRTL( ScDocShell* pShell, SCTAB nNewTab, bool bNewRTL );
+ virtual ~ScUndoLayoutRTL() override;
+
+ virtual void Undo() override;
+ virtual void Redo() override;
+ virtual void Repeat(SfxRepeatTarget& rTarget) override;
+ virtual bool CanRepeat(SfxRepeatTarget& rTarget) const override;
+
+ virtual OUString GetComment() const override;
+
+private:
+ SCTAB nTab;
+ bool bRTL;
+
+ void DoChange( bool bNew );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/undoutil.hxx b/sc/source/ui/inc/undoutil.hxx
new file mode 100644
index 000000000..59887e570
--- /dev/null
+++ b/sc/source/ui/inc/undoutil.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 <address.hxx>
+
+class ScDocShell;
+class ScDBData;
+class ScDocument;
+
+class ScUndoUtil
+{
+public:
+ /** Mark Block (invisible - has to be repainted) */
+ static void MarkSimpleBlock( const ScDocShell* pDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ );
+ static void MarkSimpleBlock( const ScDocShell* pDocShell,
+ const ScAddress& rBlockStart,
+ const ScAddress& rBlockEnd );
+ static void MarkSimpleBlock( const ScDocShell* pDocShell,
+ const ScRange& rRange );
+
+ static void PaintMore( ScDocShell* pDocShell,
+ const ScRange& rRange );
+
+ /** Search for Data base range in Document ("untitled" or by region)
+ create new if not found */
+ static ScDBData* GetOldDBData( const ScDBData* pUndoData, ScDocument* pDoc, SCTAB nTab,
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/validate.hxx b/sc/source/ui/inc/validate.hxx
new file mode 100644
index 000000000..618cfb23f
--- /dev/null
+++ b/sc/source/ui/inc/validate.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <sfx2/tabdlg.hxx>
+
+#include "anyrefdg.hxx"
+#include <sc.hrc>
+#include <scmod.hxx>
+
+struct ScRefHandlerCaller{
+ virtual ~ScRefHandlerCaller(){}
+};
+
+class ScRefHandlerHelper
+{
+protected:
+ ScRefHandlerCaller* m_pHandler;
+// workaround VS2013 issue with pointers to things that contain virtual base class
+#ifdef _WIN32
+ #pragma pack(push, 16)
+#endif
+ void (ScRefHandlerCaller::*m_pSetReferenceHdl)( const ScRange& , const ScDocument& );
+ void (ScRefHandlerCaller::*m_pSetActiveHdl)();
+ void (ScRefHandlerCaller::*m_pRefInputStartPreHdl)( formula::RefEdit* pEdit, const formula::RefButton* pButton );
+ void (ScRefHandlerCaller::*m_pRefInputDonePostHdl)();
+#if defined( _WIN32)
+ #pragma pack(pop)
+#endif
+
+public:
+ typedef void (ScRefHandlerCaller::*PFUNCSETREFHDLTYPE)( const ScRange& , const ScDocument& );
+ typedef void (ScRefHandlerCaller::*PCOMMONHDLTYPE)();
+ typedef void (ScRefHandlerCaller::*PINPUTSTARTDLTYPE)( formula::RefEdit* pEdit, const formula::RefButton* pButton );
+
+ void SetSetRefHdl( PFUNCSETREFHDLTYPE pNewHdl )
+ {
+ m_pSetReferenceHdl = pNewHdl;
+ }
+
+ void SetSetActHdl( PCOMMONHDLTYPE pNewHdl )
+ {
+ m_pSetActiveHdl = pNewHdl;
+ }
+
+ void SetHandler( ScRefHandlerCaller *pNewHandler )
+ {
+ m_pHandler = pNewHandler;
+ }
+ void SetRefInputStartPreHdl( PINPUTSTARTDLTYPE pNewHdl ){ m_pRefInputStartPreHdl = pNewHdl; }
+ void SetRefInputDonePostHdl( void (ScRefHandlerCaller::*pNewHdl)() ){ m_pRefInputDonePostHdl = pNewHdl; }
+
+ ScRefHandlerHelper():m_pHandler(nullptr), m_pSetReferenceHdl( nullptr ), m_pSetActiveHdl(nullptr), m_pRefInputStartPreHdl( nullptr ), m_pRefInputDonePostHdl( nullptr ){}
+};
+
+class ScValidationDlg;
+
+/** The tab page "Criteria" from the Validation dialog. */
+class ScTPValidationValue : public ScRefHandlerCaller, public SfxTabPage
+{
+ static const WhichRangesContainer pValueRanges;
+public:
+ explicit ScTPValidationValue(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet);
+ static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet );
+ virtual ~ScTPValidationValue() override;
+
+ static const WhichRangesContainer& GetRanges() { return pValueRanges; }
+
+ virtual bool FillItemSet( SfxItemSet* rArgSet ) override;
+ virtual void Reset( const SfxItemSet* rArgSet ) override;
+
+private:
+ void Init();
+
+ OUString GetFirstFormula() const;
+ OUString GetSecondFormula() const;
+
+ void SetFirstFormula( const OUString& rFmlaStr );
+ void SetSecondFormula( const OUString& rFmlaStr );
+
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(CheckHdl, weld::Toggleable&, void);
+
+ OUString maStrMin;
+ OUString maStrMax;
+ OUString maStrValue;
+ OUString maStrFormula;
+ OUString maStrRange;
+ OUString maStrList;
+ sal_Unicode mcFmlaSep; /// List separator in formulas.
+
+ DECL_LINK( EditSetFocusHdl, formula::RefEdit&, void );
+ DECL_LINK( KillEditFocusHdl, formula::RefEdit&, void );
+ DECL_LINK( KillButtonFocusHdl, formula::RefButton&, void );
+ DECL_LINK( ClickHdl, formula::RefButton&, void );
+
+ formula::RefEdit* m_pRefEdit;
+
+ std::unique_ptr<weld::ComboBox> m_xLbAllow;
+ std::unique_ptr<weld::CheckButton> m_xCbAllow; /// Allow blank cells.
+ std::unique_ptr<weld::CheckButton> m_xCbShow; /// Show selection list in cell.
+ std::unique_ptr<weld::CheckButton> m_xCbSort; /// Sort selection list in cell.
+ std::unique_ptr<weld::Label> m_xFtValue;
+ std::unique_ptr<weld::ComboBox> m_xLbValue;
+ std::unique_ptr<weld::Label> m_xFtMin;
+ std::unique_ptr<weld::Widget> m_xMinGrid;
+ std::unique_ptr<formula::RefEdit> m_xEdMin;
+ std::unique_ptr<weld::TextView> m_xEdList; /// Entries for explicit list
+ std::unique_ptr<weld::Label> m_xFtMax;
+ std::unique_ptr<formula::RefEdit> m_xEdMax;
+ std::unique_ptr<weld::Label> m_xFtHint; /// Hint text for cell range validity.
+ std::unique_ptr<formula::RefButton> m_xBtnRef;
+ std::unique_ptr<weld::Container> m_xRefGrid;
+
+ weld::Container* m_pRefEditParent;
+ weld::Container* m_pBtnRefParent;
+
+ void SetReferenceHdl( const ScRange& , const ScDocument& );
+ void SetActiveHdl();
+ void RefInputStartPreHdl(formula::RefEdit* pEdit, const formula::RefButton* pButton);
+ void RefInputDonePostHdl();
+ ScValidationDlg * GetValidationDlg();
+public:
+ void SetupRefDlg();
+ void RemoveRefDlg(bool bRestoreModal);
+};
+
+/** The "Validity" tab dialog. */
+class ScValidationDlg
+ : public ScRefHdlrControllerImpl<SfxTabDialogController, false>
+ , public ScRefHandlerHelper
+{
+ typedef ScRefHdlrControllerImpl<SfxTabDialogController, false> ScValidationDlgBase;
+
+ ScTabViewShell * m_pTabVwSh;
+ OString m_sValuePageId;
+ bool m_bOwnRefHdlr:1;
+ bool m_bRefInputting:1;
+
+ std::unique_ptr<weld::Container> m_xHBox;
+
+ bool EnterRefStatus();
+ bool LeaveRefStatus();
+
+public:
+ explicit ScValidationDlg(weld::Window* pParent, const SfxItemSet* pArgSet, ScTabViewShell* pTabViewSh);
+ virtual ~ScValidationDlg() override;
+ static std::shared_ptr<SfxDialogController> Find1AliveObject(const weld::Window *pAncestor)
+ {
+ return SC_MOD()->Find1RefWindow(SLOTID, pAncestor);
+ }
+ ScTabViewShell *GetTabViewShell()
+ {
+ return m_pTabVwSh;
+ }
+
+ bool SetupRefDlg();
+ bool RemoveRefDlg(bool bRestoreModal);
+
+ void SetModal(bool bModal) { m_xDialog->set_modal(bModal); }
+
+ virtual void EndDialog(int nResponse) override;
+
+ virtual void SetReference( const ScRange& rRef, ScDocument& rDoc ) override
+ {
+ if ( m_pHandler && m_pSetReferenceHdl )
+ (m_pHandler->*m_pSetReferenceHdl)( rRef, rDoc );
+ }
+
+ virtual void SetActive() override
+ {
+ if ( m_pHandler && m_pSetActiveHdl )
+ (m_pHandler->*m_pSetActiveHdl)();
+ }
+
+ bool IsRefInputting() const { return m_bRefInputting; }
+ weld::Container* get_refinput_shrink_parent() { return m_xHBox.get(); }
+
+ virtual void RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton = nullptr ) override
+ {
+ if( !CanInputStart( pEdit ) )
+ return;
+
+ if ( m_pHandler && m_pRefInputStartPreHdl )
+ (m_pHandler->*m_pRefInputStartPreHdl)( pEdit, pButton );
+ m_bRefInputting = true;
+ ScValidationDlgBase::RefInputStart( pEdit, pButton );
+ }
+
+ virtual void RefInputDone( bool bForced = false ) override
+ {
+ if( !CanInputDone( bForced ) )
+ return;
+
+ ScValidationDlgBase::RefInputDone( bForced );
+ m_bRefInputting = false;
+
+ if ( m_pHandler && m_pRefInputDonePostHdl )
+ (m_pHandler->*m_pRefInputDonePostHdl)();
+ }
+
+ bool IsChildFocus() const;
+
+ enum { SLOTID = SID_VALIDITY_REFERENCE };
+
+ virtual void Close() override
+ {
+ if (m_bOwnRefHdlr)
+ {
+ if (SfxTabPage* pPage = GetTabPage(m_sValuePageId))
+ static_cast<ScTPValidationValue*>(pPage)->RemoveRefDlg(false);
+ }
+ ScValidationDlgBase::Close();
+ }
+};
+
+class ScTPValidationHelp : public SfxTabPage
+{
+private:
+ std::unique_ptr<weld::CheckButton> m_xTsbHelp;
+ std::unique_ptr<weld::Entry> m_xEdtTitle;
+ std::unique_ptr<weld::TextView> m_xEdInputHelp;
+
+public:
+ ScTPValidationHelp(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet);
+ virtual ~ScTPValidationHelp() override;
+
+ virtual bool FillItemSet ( SfxItemSet* rArgSet ) override;
+ virtual void Reset ( const SfxItemSet* rArgSet ) override;
+};
+
+class ScTPValidationError : public SfxTabPage
+{
+private:
+ std::unique_ptr<weld::CheckButton> m_xTsbShow;
+ std::unique_ptr<weld::ComboBox> m_xLbAction;
+ std::unique_ptr<weld::Button> m_xBtnSearch;
+ std::unique_ptr<weld::Entry> m_xEdtTitle;
+ std::unique_ptr<weld::Label> m_xFtError;
+ std::unique_ptr<weld::TextView> m_xEdError;
+
+ void Init();
+
+ // Handler ------------------------
+ DECL_LINK(SelectActionHdl, weld::ComboBox&, void);
+ DECL_LINK(ClickSearchHdl, weld::Button&, void);
+
+public:
+ ScTPValidationError(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet);
+ static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rArgSet);
+ virtual ~ScTPValidationError() override;
+
+ virtual bool FillItemSet ( SfxItemSet* rArgSet ) override;
+ virtual void Reset ( const SfxItemSet* rArgSet ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/viewdata.hxx b/sc/source/ui/inc/viewdata.hxx
new file mode 100644
index 000000000..34bc8c49c
--- /dev/null
+++ b/sc/source/ui/inc/viewdata.hxx
@@ -0,0 +1,734 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in 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 <sfx2/zoomitem.hxx>
+#include <rangelst.hxx>
+#include <scdllapi.h>
+#include <viewopti.hxx>
+#include "docsh.hxx"
+
+#include <memory>
+#include <o3tl/typed_flags_set.hxx>
+
+#define SC_SIZE_NONE 65535
+
+enum class ScFillMode
+{
+ NONE = 0,
+ FILL = 1,
+ EMBED_LT = 2,
+ EMBED_RB = 3,
+ MATRIX = 4,
+};
+
+enum ScSplitMode { SC_SPLIT_NONE = 0, SC_SPLIT_NORMAL, SC_SPLIT_FIX, SC_SPLIT_MODE_MAX_ENUM = SC_SPLIT_FIX };
+
+enum ScSplitPos { SC_SPLIT_TOPLEFT, SC_SPLIT_TOPRIGHT, SC_SPLIT_BOTTOMLEFT, SC_SPLIT_BOTTOMRIGHT, SC_SPLIT_POS_MAX_ENUM = SC_SPLIT_BOTTOMRIGHT };
+enum ScHSplitPos { SC_SPLIT_LEFT, SC_SPLIT_RIGHT };
+enum ScVSplitPos { SC_SPLIT_TOP, SC_SPLIT_BOTTOM };
+
+inline ScHSplitPos WhichH( ScSplitPos ePos );
+inline ScVSplitPos WhichV( ScSplitPos ePos );
+
+/** Screen behavior related to cursor movements */
+enum ScFollowMode { SC_FOLLOW_NONE, SC_FOLLOW_LINE, SC_FOLLOW_FIX, SC_FOLLOW_JUMP };
+
+/** Mouse mode to select areas */
+enum ScRefType { SC_REFTYPE_NONE, SC_REFTYPE_REF, SC_REFTYPE_FILL,
+ SC_REFTYPE_EMBED_LT, SC_REFTYPE_EMBED_RB };
+
+/** States GetSimpleArea() returns for the underlying selection marks, so the
+ caller can react if the result is not of type SC_MARK_SIMPLE. */
+enum ScMarkType
+{
+ SC_MARK_NONE = 0, // Not returned by GetSimpleArea(), used internally.
+ // Nothing marked always results in the
+ // current cursor position being selected and a simple mark.
+ SC_MARK_SIMPLE = 1, // Simple rectangular area marked, no filtered rows.
+ SC_MARK_FILTERED = 2, // At least one mark contains filtered rows.
+ SC_MARK_SIMPLE_FILTERED = // Simple rectangular area marked containing filtered rows.
+ SC_MARK_SIMPLE |
+ SC_MARK_FILTERED, // 3
+ SC_MARK_MULTI = 4 // Multiple selection marks.
+ /* TODO: if filtered multi-selection was implemented, this would be the value to use. */
+#if 0
+ ,
+ SC_MARK_MULTI_FILTERED = // Multiple selection marks containing filtered rows.
+ SC_MARK_MULTI |
+ SC_MARK_FILTERED // 6
+#endif
+};
+
+enum class ScPasteFlags
+{
+ NONE = 0, // No flags specified
+ Mode = 1, // Enable paste-mode
+ Border = 2, // Show a border around the source cells
+};
+namespace o3tl {
+ template<> struct typed_flags<ScPasteFlags> : is_typed_flags<ScPasteFlags, 0x03> {};
+}
+
+// for internal Drag&Drop:
+enum class ScDragSrc{
+ Undefined = 0,
+ Navigator = 1,
+ Table = 2
+};
+namespace o3tl {
+ template<> struct typed_flags<ScDragSrc> : is_typed_flags<ScDragSrc, 0x00000003> {};
+}
+
+class ScDocFunc;
+class ScDocument;
+class ScDBFunc;
+class ScTabViewShell;
+class ScDrawView;
+class ScEditEngineDefaulter;
+class EditView;
+class EditStatus;
+class Outliner;
+namespace vcl { class Window; }
+class SfxObjectShell;
+class SfxBindings;
+class SfxDispatcher;
+class ScPatternAttr;
+class ScExtDocOptions;
+class ScViewData;
+class ScMarkData;
+class ScGridWindow;
+
+class ScPositionHelper
+{
+public:
+ typedef SCCOLROW index_type;
+ typedef std::pair<index_type, tools::Long> value_type;
+ static_assert(std::numeric_limits<index_type>::is_signed, "ScPositionCache: index type is not signed");
+
+private:
+ static const index_type null = std::numeric_limits<index_type>::min();
+
+ class Comp
+ {
+ public:
+ bool operator() (const value_type& rValue1, const value_type& rValue2) const;
+ };
+
+ index_type MAX_INDEX;
+ std::set<value_type, Comp> mData;
+
+public:
+ ScPositionHelper(const ScDocument *pDoc, bool bColumn);
+ void setDocument(const ScDocument& rDoc, bool bColumn);
+
+ void insert(index_type nIndex, tools::Long nPos);
+ void removeByIndex(index_type nIndex);
+ void invalidateByIndex(index_type nIndex);
+ void invalidateByPosition(tools::Long nPos);
+ const value_type& getNearestByIndex(index_type nIndex) const;
+ const value_type& getNearestByPosition(tools::Long nPos) const;
+ tools::Long getPosition(index_type nIndex) const;
+ tools::Long computePosition(index_type nIndex, const std::function<long (index_type)>& getSizePx);
+};
+
+class ScBoundsProvider
+{
+ typedef ScPositionHelper::value_type value_type;
+ typedef SCCOLROW index_type;
+
+ ScDocument& rDoc;
+ const SCTAB nTab;
+ const bool bColumnHeader;
+ const index_type MAX_INDEX;
+
+ double mfPPTX;
+ double mfPPTY;
+ index_type nFirstIndex;
+ index_type nSecondIndex;
+ tools::Long nFirstPositionPx;
+ tools::Long nSecondPositionPx;
+
+public:
+ ScBoundsProvider(const ScViewData &rView, SCTAB nT, bool bColumnHeader);
+
+ void GetStartIndexAndPosition(SCCOL& nIndex, tools::Long& nPosition) const;
+ void GetEndIndexAndPosition(SCCOL& nIndex, tools::Long& nPosition) const;
+ void GetStartIndexAndPosition(SCROW& nIndex, tools::Long& nPosition) const;
+ void GetEndIndexAndPosition(SCROW& nIndex, tools::Long& nPosition) const;
+
+ void Compute(value_type aFirstNearest, value_type aSecondNearest,
+ tools::Long nFirstBound, tools::Long nSecondBound);
+
+ void EnlargeStartBy(tools::Long nOffset);
+
+ void EnlargeEndBy(tools::Long nOffset);
+
+ void EnlargeBy(tools::Long nOffset)
+ {
+ EnlargeStartBy(nOffset);
+ EnlargeEndBy(nOffset);
+ }
+
+private:
+ tools::Long GetSize(index_type nIndex) const;
+
+ void GetIndexAndPos(index_type nNearestIndex, tools::Long nNearestPosition,
+ tools::Long nBound, index_type& nFoundIndex, tools::Long& nPosition,
+ bool bTowards, tools::Long nDiff);
+
+ void GeIndexBackwards(index_type nNearestIndex, tools::Long nNearestPosition,
+ tools::Long nBound, index_type& nFoundIndex, tools::Long& nPosition,
+ bool bTowards);
+
+ void GetIndexTowards(index_type nNearestIndex, tools::Long nNearestPosition,
+ tools::Long nBound, index_type& nFoundIndex, tools::Long& nPosition,
+ bool bTowards);
+};
+
+class ScViewDataTable // per-sheet data
+{
+friend class ScViewData;
+private:
+ SvxZoomType eZoomType; // selected zoom type (normal view)
+ Fraction aZoomX; // selected zoom X
+ Fraction aZoomY; // selected zoom Y (displayed)
+ Fraction aPageZoomX; // zoom in page break preview mode
+ Fraction aPageZoomY;
+
+ tools::Long nTPosX[2]; // MapMode - Offset (Twips)
+ tools::Long nTPosY[2];
+ tools::Long nMPosX[2]; // MapMode - Offset (1/100 mm)
+ tools::Long nMPosY[2];
+ tools::Long nPixPosX[2]; // Offset in Pixels
+ tools::Long nPixPosY[2];
+ tools::Long nHSplitPos;
+ tools::Long nVSplitPos;
+
+ ScSplitMode eHSplitMode;
+ ScSplitMode eVSplitMode;
+ ScSplitPos eWhichActive;
+
+ SCCOL nFixPosX; // Cell position of the splitter when freeze pane
+ SCROW nFixPosY;
+
+ SCCOL nCurX;
+ SCROW nCurY;
+ SCCOL nOldCurX;
+ SCROW nOldCurY;
+
+ ScPositionHelper aWidthHelper;
+ ScPositionHelper aHeightHelper;
+
+ SCCOL nPosX[2]; ///< X position of the top left cell of the visible area.
+ SCROW nPosY[2]; ///< Y position of the top left cell of the visible area.
+ SCCOL nMaxTiledCol;
+ SCROW nMaxTiledRow;
+
+ bool bShowGrid; // per sheet show grid lines option.
+ bool mbOldCursorValid; // "virtual" Cursor position when combined
+ ScViewDataTable(const ScDocument *pDoc = nullptr);
+
+ void InitData(const ScDocument& rDoc);
+ void WriteUserDataSequence(
+ css::uno::Sequence <css::beans::PropertyValue>& rSettings,
+ const ScViewData& rViewData, SCTAB nTab ) const;
+
+ void ReadUserDataSequence(
+ const css::uno::Sequence <css::beans::PropertyValue>& rSettings,
+ ScViewData& rViewData, SCTAB nTab, bool& rHasZoom);
+
+ /** Sanitize the active split range value to not point into a grid window
+ that would never be initialized due to non-matching split modes.
+
+ This is to be done when reading settings from file formats or
+ configurations that could have arbitrary values. The caller is
+ responsible for actually assigning the new value to eWhichActive because
+ we want this function to be const to be able to call the check from
+ anywhere.
+ */
+ [[nodiscard]] ScSplitPos SanitizeWhichActive() const;
+};
+
+class SC_DLLPUBLIC ScViewData
+{
+private:
+ double nPPTX, nPPTY; // Scaling factors
+
+ ::std::vector<std::unique_ptr<ScViewDataTable>> maTabData;
+ ScMarkData maMarkData;
+ ScViewDataTable* pThisTab; // Data of the displayed sheet
+ ScDocShell* pDocShell;
+ ScDocument& mrDoc;
+ ScTabViewShell* pView;
+ std::unique_ptr<EditView> pEditView[4]; // Belongs to the window
+ ScViewOptions maOptions;
+ EditView* pSpellingView;
+
+ Size aScenButSize;
+
+ Size aScrSize;
+ MapMode aLogicMode; // skalierter 1/100mm-MapMode
+
+ SvxZoomType eDefZoomType; // default zoom and type for missing TabData
+ Fraction aDefZoomX;
+ Fraction aDefZoomY;
+ Fraction aDefPageZoomX; // zoom in page break preview mode
+ Fraction aDefPageZoomY;
+
+ ScRefType eRefType;
+
+ SCTAB nTabNo; // displayed sheet
+ SCTAB nRefTabNo; // sheet which contains RefInput
+ SCCOL nRefStartX;
+ SCROW nRefStartY;
+ SCTAB nRefStartZ;
+ SCCOL nRefEndX;
+ SCROW nRefEndY;
+ SCTAB nRefEndZ;
+ SCCOL nFillStartX; // Fill Cursor
+ SCROW nFillStartY;
+ SCCOL nFillEndX;
+ SCROW nFillEndY;
+ SCCOL nEditCol; // Related position
+ SCROW nEditRow;
+ SCCOL nEditStartCol;
+ SCCOL nEditEndCol; // End of Edit View
+ SCROW nEditEndRow;
+ SCCOL nTabStartCol; // for Enter after Tab
+ ScRange aDelRange; // for delete AutoFill
+
+ ScPasteFlags nPasteFlags;
+
+ ScSplitPos eEditActivePart; // the part that was active when edit mode was started
+ ScFillMode nFillMode;
+ SvxAdjust eEditAdjust;
+ bool bEditActive[4] = {}; // Active?
+ bool bActive:1; // Active Window ?
+ bool bIsRefMode:1; // Reference input
+ bool bDelMarkValid:1; // Only valid at SC_REFTYPE_FILL
+ bool bPagebreak:1; // Page break preview mode
+ bool bSelCtrlMouseClick:1; // special selection handling for ctrl-mouse-click
+ bool bMoveArea:1;
+
+ bool bGrowing;
+ sal_Int16 nFormulaBarLines; // Visible lines in the formula bar
+
+ tools::Long m_nLOKPageUpDownOffset;
+ tools::Rectangle maLOKVisibleArea;///< The visible area in the LibreOfficeKit client.
+
+ DECL_DLLPRIVATE_LINK( EditEngineHdl, EditStatus&, void );
+
+
+ SAL_DLLPRIVATE void CalcPPT();
+ SAL_DLLPRIVATE void CreateTabData( SCTAB nNewTab );
+ SAL_DLLPRIVATE void CreateTabData( std::vector< SCTAB >& rvTabs );
+ SAL_DLLPRIVATE void CreateSelectedTabData();
+ SAL_DLLPRIVATE void EnsureTabDataSize(size_t nSize);
+ SAL_DLLPRIVATE void UpdateCurrentTab();
+
+ ScViewData(ScDocument* pDoc, ScDocShell* pDocSh, ScTabViewShell* pViewSh);
+
+public:
+ ScViewData( ScDocShell& rDocSh, ScTabViewShell* pViewSh );
+ ScViewData( ScDocument& rDoc );
+ ~ScViewData() COVERITY_NOEXCEPT_FALSE;
+
+ ScDocShell* GetDocShell() const { return pDocShell; }
+ ScDocFunc& GetDocFunc() const;
+ ScDBFunc* GetView() const;
+ ScTabViewShell* GetViewShell() const { return pView; }
+ SfxObjectShell* GetSfxDocShell() const { return pDocShell; }
+ SfxBindings& GetBindings(); // from ViewShell's ViewFrame
+ SfxDispatcher& GetDispatcher(); // from ViewShell's ViewFrame
+
+ ScMarkData& GetMarkData();
+ const ScMarkData& GetMarkData() const;
+
+ weld::Window* GetDialogParent(); // forwarded from tabvwsh
+ ScGridWindow* GetActiveWin(); // from View
+ const ScGridWindow* GetActiveWin() const;
+ ScDrawView* GetScDrawView(); // from View
+ bool IsMinimized() const; // from View
+
+ void UpdateInputHandler( bool bForce = false );
+
+ void WriteUserData(OUString& rData);
+ void ReadUserData(std::u16string_view rData);
+ void WriteExtOptions( ScExtDocOptions& rOpt ) const;
+ void ReadExtOptions( const ScExtDocOptions& rOpt );
+ void WriteUserDataSequence(css::uno::Sequence <css::beans::PropertyValue>& rSettings) const;
+ void ReadUserDataSequence(const css::uno::Sequence <css::beans::PropertyValue>& rSettings);
+
+ ScDocument& GetDocument() const { return mrDoc; }
+
+ bool IsActive() const { return bActive; }
+ void Activate(bool bActivate) { bActive = bActivate; }
+
+ void InsertTab( SCTAB nTab );
+ void InsertTabs( SCTAB nTab, SCTAB nNewSheets );
+ void DeleteTab( SCTAB nTab );
+ void DeleteTabs( SCTAB nTab, SCTAB nSheets );
+ void CopyTab( SCTAB nSrcTab, SCTAB nDestTab );
+ void MoveTab( SCTAB nSrcTab, SCTAB nDestTab );
+
+ SCTAB GetRefTabNo() const { return nRefTabNo; }
+ void SetRefTabNo( SCTAB nNewTab ) { nRefTabNo = nNewTab; }
+
+ SCTAB GetTabNo() const { return nTabNo; }
+ SCCOL MaxCol() const { return mrDoc.MaxCol(); }
+ SCROW MaxRow() const { return mrDoc.MaxRow(); }
+ ScSplitPos GetActivePart() const { return pThisTab->eWhichActive; }
+ SCCOL GetPosX( ScHSplitPos eWhich, SCTAB nForTab = -1 ) const;
+ SCROW GetPosY( ScVSplitPos eWhich, SCTAB nForTab = -1 ) const;
+ SCCOL GetCurX() const { return pThisTab->nCurX; }
+ SCROW GetCurY() const { return pThisTab->nCurY; }
+ SCCOL GetCurXForTab( SCTAB nTabIndex ) const;
+ SCROW GetCurYForTab( SCTAB nTabIndex ) const;
+ SCCOL GetOldCurX() const;
+ SCROW GetOldCurY() const;
+ tools::Long GetLOKDocWidthPixel() const { return pThisTab->aWidthHelper.getPosition(pThisTab->nMaxTiledCol); }
+ tools::Long GetLOKDocHeightPixel() const { return pThisTab->aHeightHelper.getPosition(pThisTab->nMaxTiledRow); }
+
+ ScPositionHelper& GetLOKWidthHelper() { return pThisTab->aWidthHelper; }
+ ScPositionHelper& GetLOKHeightHelper() { return pThisTab->aHeightHelper; }
+
+ ScPositionHelper* GetLOKWidthHelper(SCTAB nTabIndex);
+ ScPositionHelper* GetLOKHeightHelper(SCTAB nTabIndex);
+
+ ScSplitMode GetHSplitMode() const { return pThisTab->eHSplitMode; }
+ ScSplitMode GetVSplitMode() const { return pThisTab->eVSplitMode; }
+ tools::Long GetHSplitPos() const { return pThisTab->nHSplitPos; }
+ tools::Long GetVSplitPos() const { return pThisTab->nVSplitPos; }
+ SCCOL GetFixPosX() const { return pThisTab->nFixPosX; }
+ SCROW GetFixPosY() const { return pThisTab->nFixPosY; }
+ SCCOL GetMaxTiledCol() const { return pThisTab->nMaxTiledCol; }
+ SCROW GetMaxTiledRow() const { return pThisTab->nMaxTiledRow; }
+
+ bool IsPagebreakMode() const { return bPagebreak; }
+ bool IsPasteMode() const { return bool(nPasteFlags & ScPasteFlags::Mode); }
+ bool ShowPasteSource() const { return bool(nPasteFlags & ScPasteFlags::Border); }
+
+ void SetPosX( ScHSplitPos eWhich, SCCOL nNewPosX );
+ void SetPosY( ScVSplitPos eWhich, SCROW nNewPosY );
+ void SetCurX( SCCOL nNewCurX ) { pThisTab->nCurX = nNewCurX; }
+ void SetCurY( SCROW nNewCurY ) { pThisTab->nCurY = nNewCurY; }
+ void SetCurXForTab( SCCOL nNewCurX, SCTAB nTabIndex );
+ void SetCurYForTab( SCCOL nNewCurY, SCTAB nTabIndex );
+ void SetOldCursor( SCCOL nNewX, SCROW nNewY );
+ void ResetOldCursor();
+
+ void SetHSplitMode( ScSplitMode eMode ) { pThisTab->eHSplitMode = eMode; }
+ void SetVSplitMode( ScSplitMode eMode ) { pThisTab->eVSplitMode = eMode; }
+ void SetHSplitPos( tools::Long nPos ) { pThisTab->nHSplitPos = nPos; }
+ void SetVSplitPos( tools::Long nPos ) { pThisTab->nVSplitPos = nPos; }
+ void SetFixPosX( SCCOL nPos ) { pThisTab->nFixPosX = nPos; }
+ void SetFixPosY( SCROW nPos ) { pThisTab->nFixPosY = nPos; }
+ void SetMaxTiledCol( SCCOL nCol );
+ void SetMaxTiledRow( SCROW nRow );
+
+ void SetPagebreakMode( bool bSet );
+ void SetPasteMode ( ScPasteFlags nFlags ) { nPasteFlags = nFlags; }
+
+ void SetZoomType( SvxZoomType eNew, bool bAll );
+ void SetZoomType( SvxZoomType eNew, std::vector< SCTAB >& tabs );
+ void SetZoom( const Fraction& rNewX, const Fraction& rNewY, std::vector< SCTAB >& tabs );
+ void SetZoom( const Fraction& rNewX, const Fraction& rNewY, bool bAll );
+ void RefreshZoom();
+
+ void SetSelCtrlMouseClick( bool bTmp ) { bSelCtrlMouseClick = bTmp; }
+
+ SvxZoomType GetZoomType() const { return pThisTab->eZoomType; }
+ const Fraction& GetZoomX() const { return bPagebreak ? pThisTab->aPageZoomX : pThisTab->aZoomX; }
+ const Fraction& GetZoomY() const { return bPagebreak ? pThisTab->aPageZoomY : pThisTab->aZoomY; }
+
+ void SetShowGrid( bool bShow );
+ bool GetShowGrid() const { return pThisTab->bShowGrid; }
+
+ const MapMode& GetLogicMode( ScSplitPos eWhich );
+ const MapMode& GetLogicMode(); // Offset 0
+
+ double GetPPTX() const { return nPPTX; }
+ double GetPPTY() const { return nPPTY; }
+
+ void SetFormulaBarLines(sal_Int16 nLines)
+ {
+ // Formula bar must be between 1 and 25 lines (see SpreadsheetViewSettings.idl)
+ nLines = std::max(nLines, static_cast<sal_Int16>(1));
+ nLines = std::min(nLines, static_cast<sal_Int16>(25));
+ nFormulaBarLines = nLines;
+ }
+ sal_Int16 GetFormulaBarLines() const { return nFormulaBarLines; };
+
+ ScMarkType GetSimpleArea( SCCOL& rStartCol, SCROW& rStartRow, SCTAB& rStartTab,
+ SCCOL& rEndCol, SCROW& rEndRow, SCTAB& rEndTab ) const;
+ ScMarkType GetSimpleArea( ScRange& rRange ) const;
+ /// May modify rNewMark using MarkToSimple().
+ ScMarkType GetSimpleArea( ScRange & rRange, ScMarkData & rNewMark ) const;
+ void GetMultiArea( ScRangeListRef& rRange ) const;
+
+ bool SimpleColMarked();
+ bool SimpleRowMarked();
+
+ bool IsMultiMarked() const;
+
+ /** Disallow Paste on Ctrl+A all selected or another high
+ amount of selected cells that is not the same size in
+ one direction as the clipboard source.
+ To prevent DOOM.
+ */
+ bool SelectionForbidsPaste( ScDocument* pClipDoc = nullptr );
+ bool SelectionForbidsPaste( SCCOL nSrcCols, SCROW nSrcRows );
+
+ /** Disallow cell fill (Fill,Enter,...) on Ctrl+A all
+ selected or another high amount of selected cells.
+ We'd go DOOM.
+ */
+ bool SelectionForbidsCellFill();
+ /// Determine DOOM condition, i.e. from selected range.
+ static bool SelectionFillDOOM( const ScRange& rRange );
+
+ void SetFillMode( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow );
+ void SetDragMode( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ ScFillMode nMode );
+ void GetFillData( SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow );
+ void ResetFillMode();
+ bool IsAnyFillMode() const { return nFillMode != ScFillMode::NONE; }
+ bool IsFillMode() const { return nFillMode == ScFillMode::FILL; }
+ ScFillMode GetFillMode() const { return nFillMode; }
+
+ SvxAdjust GetEditAdjust() const {return eEditAdjust; }
+ void SetEditAdjust( SvxAdjust eNewEditAdjust ) { eEditAdjust = eNewEditAdjust; }
+
+ // TRUE: Cell is merged
+ bool GetMergeSizePixel( SCCOL nX, SCROW nY, tools::Long& rSizeXPix, tools::Long& rSizeYPix ) const;
+ bool GetMergeSizePrintTwips( SCCOL nX, SCROW nY, tools::Long& rSizeXTwips, tools::Long& rSizeYTwips ) const;
+ void GetPosFromPixel( tools::Long nClickX, tools::Long nClickY, ScSplitPos eWhich,
+ SCCOL& rPosX, SCROW& rPosY,
+ bool bTestMerge = true, bool bRepair = false, SCTAB nForTab = -1 );
+ void GetMouseQuadrant( const Point& rClickPos, ScSplitPos eWhich,
+ SCCOL nPosX, SCROW nPosY, bool& rLeft, bool& rTop );
+
+ bool IsRefMode() const { return bIsRefMode; }
+ ScRefType GetRefType() const { return eRefType; }
+ SCCOL GetRefStartX() const { return nRefStartX; }
+ SCROW GetRefStartY() const { return nRefStartY; }
+ SCTAB GetRefStartZ() const { return nRefStartZ; }
+ SCCOL GetRefEndX() const { return nRefEndX; }
+ SCROW GetRefEndY() const { return nRefEndY; }
+ SCTAB GetRefEndZ() const { return nRefEndZ; }
+
+ void SetRefMode( bool bNewMode, ScRefType eNewType )
+ { bIsRefMode = bNewMode; eRefType = eNewType; }
+
+ void SetRefStart( SCCOL nNewX, SCROW nNewY, SCTAB nNewZ );
+ void SetRefEnd( SCCOL nNewX, SCROW nNewY, SCTAB nNewZ );
+
+ void ResetDelMark() { bDelMarkValid = false; }
+ void SetDelMark( const ScRange& rRange )
+ { aDelRange = rRange; bDelMarkValid = true; }
+
+ bool GetDelMark( ScRange& rRange ) const
+ { rRange = aDelRange; return bDelMarkValid; }
+
+ inline void GetMoveCursor( SCCOL& rCurX, SCROW& rCurY );
+
+ const ScViewOptions& GetOptions() const { return maOptions; }
+ void SetOptions( const ScViewOptions& rOpt );
+
+ bool IsGridMode () const { return maOptions.GetOption(VOPT_GRID); }
+ bool IsSyntaxMode () const { return maOptions.GetOption(VOPT_SYNTAX); }
+ void SetSyntaxMode ( bool bNewMode ) { maOptions.SetOption(VOPT_SYNTAX, bNewMode); }
+ bool IsHeaderMode () const { return maOptions.GetOption(VOPT_HEADER); }
+ void SetHeaderMode ( bool bNewMode ) { maOptions.SetOption(VOPT_HEADER, bNewMode); }
+ bool IsTabMode () const { return maOptions.GetOption(VOPT_TABCONTROLS); }
+ bool IsVScrollMode () const { return maOptions.GetOption(VOPT_VSCROLL); }
+ bool IsHScrollMode () const { return maOptions.GetOption(VOPT_HSCROLL); }
+ bool IsOutlineMode () const { return maOptions.GetOption(VOPT_OUTLINER); }
+ bool IsThemedCursor () const { return maOptions.GetOption(VOPT_THEMEDCURSOR); }
+
+ /// Force page size for PgUp/PgDown to overwrite the computation based on m_aVisArea.
+ void ForcePageUpDownOffset(tools::Long nTwips) { m_nLOKPageUpDownOffset = nTwips; }
+ tools::Long GetPageUpDownOffset() const { return m_nLOKPageUpDownOffset; }
+
+ /// The visible area in the client (set by setClientVisibleArea).
+ const tools::Rectangle& getLOKVisibleArea() const { return maLOKVisibleArea; }
+ void setLOKVisibleArea(const tools::Rectangle& rArea) { maLOKVisibleArea = rArea; }
+
+ void KillEditView();
+ void ResetEditView();
+ void SetEditEngine( ScSplitPos eWhich,
+ ScEditEngineDefaulter* pNewEngine,
+ vcl::Window* pWin, SCCOL nNewX, SCROW nNewY );
+ void GetEditView( ScSplitPos eWhich, EditView*& rViewPtr, SCCOL& rCol, SCROW& rRow );
+ bool HasEditView( ScSplitPos eWhich ) const
+ { return pEditView[eWhich] && bEditActive[eWhich]; }
+ EditView* GetEditView( ScSplitPos eWhich ) const
+ { return pEditView[eWhich].get(); }
+
+ /**
+ * Extend the output area for the edit engine view in a horizontal
+ * direction as needed.
+ */
+ void EditGrowX();
+
+ /**
+ * Extend the output area for the edit engine view in a vertical direction
+ * as needed.
+ *
+ * @param bInitial when true, then the call originates from a brand-new
+ * edit engine instance.
+ */
+ void EditGrowY( bool bInitial = false );
+
+ ScSplitPos GetEditActivePart() const { return eEditActivePart; }
+ SCCOL GetEditViewCol() const { return nEditCol; }
+ SCROW GetEditViewRow() const { return nEditRow; }
+ SCCOL GetEditStartCol() const { return nEditStartCol; }
+ SCROW GetEditStartRow() const { return nEditRow; } // never editing above the cell
+ SCCOL GetEditEndCol() const { return nEditEndCol; }
+ SCROW GetEditEndRow() const { return nEditEndRow; }
+
+ tools::Rectangle GetEditArea( ScSplitPos eWhich, SCCOL nPosX, SCROW nPosY, vcl::Window* pWin,
+ const ScPatternAttr* pPattern, bool bForceToTop, bool bInPrintTwips = false );
+
+ void SetTabNo( SCTAB nNewTab );
+ void SetActivePart( ScSplitPos eNewActive );
+
+ Point GetScrPos( SCCOL nWhereX, SCROW nWhereY, ScSplitPos eWhich,
+ bool bAllowNeg = false, SCTAB nForTab = -1 ) const;
+ Point GetScrPos( SCCOL nWhereX, SCROW nWhereY, ScHSplitPos eWhich ) const;
+ Point GetScrPos( SCCOL nWhereX, SCROW nWhereY, ScVSplitPos eWhich ) const;
+ /// returns the position (top-left corner) of the requested cell in print twips coordinates.
+ Point GetPrintTwipsPos( SCCOL nCol, SCROW nRow ) const;
+ Point GetPrintTwipsPosFromTileTwips(const Point& rTileTwipsPos) const;
+
+ /// return json for our cursor position.
+ OString describeCellCursor() const { return describeCellCursorAt(GetCurX(), GetCurY()); }
+ OString describeCellCursorInPrintTwips() const { return describeCellCursorAt(GetCurX(), GetCurY(), false); }
+ OString describeCellCursorAt( SCCOL nCol, SCROW nRow, bool bPixelAligned = true ) const;
+
+ SCCOL CellsAtX( SCCOL nPosX, SCCOL nDir, ScHSplitPos eWhichX, sal_uInt16 nScrSizeY = SC_SIZE_NONE ) const;
+ SCROW CellsAtY( SCROW nPosY, SCROW nDir, ScVSplitPos eWhichY, sal_uInt16 nScrSizeX = SC_SIZE_NONE ) const;
+
+ SCCOL VisibleCellsX( ScHSplitPos eWhichX ) const; // Completely visible cell
+ SCROW VisibleCellsY( ScVSplitPos eWhichY ) const;
+ SCCOL PrevCellsX( ScHSplitPos eWhichX ) const; // Cells on the preceding page
+ SCROW PrevCellsY( ScVSplitPos eWhichY ) const;
+
+ bool IsOle() const;
+ void SetScreen( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
+ void SetScreen( const tools::Rectangle& rVisArea );
+ void SetScreenPos( const Point& rVisAreaStart );
+
+ void UpdateScreenZoom( const Fraction& rNewX, const Fraction& rNewY );
+
+ const Size& GetScrSize() const { return aScrSize; }
+
+ void RecalcPixPos();
+ Point GetPixPos( ScSplitPos eWhich ) const
+ { return Point( pThisTab->nPixPosX[WhichH(eWhich)],
+ pThisTab->nPixPosY[WhichV(eWhich)] ); }
+ void SetSpellingView( EditView* pSpView) { pSpellingView = pSpView; }
+ EditView* GetSpellingView() const { return pSpellingView; }
+
+ void UpdateOutlinerFlags( Outliner& rOutl ) const;
+
+ Point GetMousePosPixel();
+
+ bool UpdateFixX(SCTAB nTab = MAXTAB+1);
+ bool UpdateFixY(SCTAB nTab = MAXTAB+1);
+
+ SCCOL GetTabStartCol() const { return nTabStartCol; }
+ void SetTabStartCol(SCCOL nNew) { nTabStartCol = nNew; }
+
+ ScAddress GetCurPos() const;
+
+ const Size& GetScenButSize() const { return aScenButSize; }
+ void SetScenButSize(const Size& rNew) { aScenButSize = rNew; }
+
+ bool IsSelCtrlMouseClick() const { return bSelCtrlMouseClick; }
+
+ SCCOLROW GetLOKSheetFreezeIndex(bool bIsCol) const;
+ bool SetLOKSheetFreezeIndex(const SCCOLROW nFreezeIndex, bool bIsCol, SCTAB nForTab = -1);
+ bool RemoveLOKFreeze();
+ void DeriveLOKFreezeAllSheets();
+ void DeriveLOKFreezeIfNeeded(SCTAB nForTab);
+ void OverrideWithLOKFreeze(ScSplitMode& eExHSplitMode, ScSplitMode& eExVSplitMode,
+ SCCOL& nExFixPosX, SCROW& nExFixPosY,
+ tools::Long& nExHSplitPos, tools::Long& nExVSplitPos, SCTAB nForTab) const;
+
+ static inline tools::Long ToPixel( sal_uInt16 nTwips, double nFactor );
+
+ /** while (rScrY <= nEndPixels && rPosY <= nEndRow) add pixels of row
+ heights converted with nPPTY to rScrY, optimized for row height
+ segments. Upon return rPosY is the last row evaluated <= nEndRow, rScrY
+ may be > nEndPixels!
+ */
+ static void AddPixelsWhile( tools::Long & rScrY, tools::Long nEndPixels,
+ SCROW & rPosY, SCROW nEndRow, double nPPTY,
+ const ScDocument * pDoc, SCTAB nTabNo );
+
+ /** while (rScrY <= nEndPixels && rPosY >= nStartRow) add pixels of row
+ heights converted with nPPTY to rScrY, optimized for row height
+ segments. Upon return rPosY is the last row evaluated >= nStartRow,
+ rScrY may be > nEndPixels!
+ */
+ static void AddPixelsWhileBackward( tools::Long & rScrY, tools::Long nEndPixels,
+ SCROW & rPosY, SCROW nStartRow, double nPPTY,
+ const ScDocument * pDoc, SCTAB nTabNo );
+};
+
+inline tools::Long ScViewData::ToPixel( sal_uInt16 nTwips, double nFactor )
+{
+ tools::Long nRet = static_cast<tools::Long>( nTwips * nFactor );
+ if ( !nRet && nTwips )
+ nRet = 1;
+ return nRet;
+}
+
+inline void ScViewData::GetMoveCursor( SCCOL& rCurX, SCROW& rCurY )
+{
+ if ( bIsRefMode )
+ {
+ rCurX = nRefEndX;
+ rCurY = nRefEndY;
+ }
+ else
+ {
+ rCurX = GetCurX();
+ rCurY = GetCurY();
+ }
+}
+
+inline ScHSplitPos WhichH( ScSplitPos ePos )
+{
+ return (ePos==SC_SPLIT_TOPLEFT || ePos==SC_SPLIT_BOTTOMLEFT) ?
+ SC_SPLIT_LEFT : SC_SPLIT_RIGHT;
+}
+
+inline ScVSplitPos WhichV( ScSplitPos ePos )
+{
+ return (ePos==SC_SPLIT_TOPLEFT || ePos==SC_SPLIT_TOPRIGHT) ?
+ SC_SPLIT_TOP : SC_SPLIT_BOTTOM;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/viewfunc.hxx b/sc/source/ui/inc/viewfunc.hxx
new file mode 100644
index 000000000..0d8d75154
--- /dev/null
+++ b/sc/source/ui/inc/viewfunc.hxx
@@ -0,0 +1,384 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include "tabview.hxx"
+
+#include <tabbgcolor.hxx>
+
+#include <com/sun/star/embed/Aspects.hpp>
+#include <vector>
+
+class ScPatternAttr;
+class ScAutoFormatData;
+class SvxSearchItem;
+class SfxItemSet;
+class SvxBoxItem;
+class SvxBoxInfoItem;
+class SfxStyleSheetBase;
+class SfxStyleSheet;
+class SfxPoolItem;
+class EditTextObject;
+struct ScSolveParam;
+struct ScTabOpParam;
+class ScValidationData;
+class ScConversionParam;
+class SdrModel;
+class Graphic;
+class ScRangeList;
+class SvxHyperlinkItem;
+class ScTransferObj;
+class ScTableProtection;
+enum class CreateNameFlags;
+
+namespace editeng { class SvxBorderLine; }
+namespace com::sun::star::embed { class XEmbeddedObject; }
+
+namespace sc {
+
+struct ColRowSpan;
+
+}
+
+namespace com::sun::star::datatransfer { class XTransferable; }
+
+struct ScDataFormFragment
+{
+ std::unique_ptr<weld::Builder> m_xBuilder;
+ std::unique_ptr<weld::Label> m_xLabel;
+ std::unique_ptr<weld::Entry> m_xEdit;
+
+ ScDataFormFragment(weld::Container* pGrid, int nLine);
+};
+
+class ScViewFunc : public ScTabView
+{
+private:
+ ScAddress aFormatSource; // for automatic extension of formatting
+ ScRange aFormatArea;
+ bool bFormatValid;
+
+public:
+ ScViewFunc( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell );
+ ~ScViewFunc();
+
+ SC_DLLPUBLIC const ScPatternAttr* GetSelectionPattern ();
+ void GetSelectionFrame(
+ std::shared_ptr<SvxBoxItem>& rLineOuter,
+ std::shared_ptr<SvxBoxInfoItem>& rLineInner );
+
+ SvtScriptType GetSelectionScriptType();
+
+ bool GetAutoSumArea( ScRangeList& rRangeList );
+ void EnterAutoSum( const ScRangeList& rRangeList, bool bSubTotal, const ScAddress& rAddr, const OpCode eCode );
+ bool AutoSum( const ScRange& rRange, bool bSubTotal, bool bSetCursor, bool bContinue, const OpCode eCode );
+ OUString GetAutoSumFormula( const ScRangeList& rRangeList, bool bSubTotal, const ScAddress& rAddr, const OpCode eCode );
+
+ void EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab, const OUString& rString,
+ const EditTextObject* pData = nullptr, bool bMatrixExpand = false );
+ void EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ const EditTextObject& rData, bool bTestSimple = false );
+ void EnterValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rValue );
+
+ void EnterMatrix( const OUString& rString, ::formula::FormulaGrammar::Grammar eGram );
+
+ /**
+ * @param pData The caller must manage the life cycle of the object this
+ * pointer points to. NULL is allowed.
+ */
+ void EnterBlock( const OUString& rString, const EditTextObject* pData );
+
+ void EnterDataAtCursor( const OUString& rString );
+
+ SC_DLLPUBLIC void CutToClip();
+ SC_DLLPUBLIC bool CopyToClip( ScDocument* pClipDoc, bool bCut, bool bApi = false,
+ bool bIncludeObjects = false, bool bStopEdit = true );
+ SC_DLLPUBLIC bool CopyToClip( ScDocument* pClipDoc, const ScRangeList& rRange, bool bCut,
+ bool bApi = false, bool bIncludeObjects = false, bool bStopEdit = true );
+ bool CopyToClipSingleRange( ScDocument* pClipDoc, const ScRangeList& rRanges, bool bCut,
+ bool bIncludeObjects );
+ bool CopyToClipMultiRange( const ScDocument* pClipDoc, const ScRangeList& rRanges, bool bCut,
+ bool bApi, bool bIncludeObjects );
+ rtl::Reference<ScTransferObj> CopyToTransferable();
+
+ SC_DLLPUBLIC bool PasteFromClip(
+ InsertDeleteFlags nFlags, ScDocument* pClipDoc,
+ ScPasteFunc nFunction = ScPasteFunc::NONE, bool bSkipEmptyCells = false,
+ bool bTranspose = false, bool bAsLink = false,
+ InsCellCmd eMoveMode = INS_NONE,
+ InsertDeleteFlags nUndoExtraFlags = InsertDeleteFlags::NONE,
+ bool bAllowDialogs = false );
+
+ void FillTab( InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bAsLink );
+
+ SC_DLLPUBLIC void PasteFromSystem();
+ SC_DLLPUBLIC bool PasteFromSystem( SotClipboardFormatId nFormatId, bool bApi = false );
+ void PasteFromTransferable( const css::uno::Reference<
+ css::datatransfer::XTransferable >& rxTransferable );
+
+ void PasteDraw();
+ void PasteDraw( const Point& rLogicPos, SdrModel* pModel, bool bGroup,
+ std::u16string_view rSrcShellID, std::u16string_view rDestShellID );
+
+ bool PasteOnDrawObjectLinked(
+ const css::uno::Reference< css::datatransfer::XTransferable >& rxTransferable,
+ SdrObject& rHitObj);
+
+ bool PasteDataFormat( SotClipboardFormatId nFormatId,
+ const css::uno::Reference< css::datatransfer::XTransferable >& rxTransferable,
+ SCCOL nPosX, SCROW nPosY, const Point* pLogicPos,
+ bool bLink = false, bool bAllowDialogs = false );
+
+ bool PasteFile( const Point&, const OUString&, bool bLink );
+ bool PasteObject( const Point&, const css::uno::Reference < css::embed::XEmbeddedObject >&, const Size*, const Graphic* = nullptr, const OUString& = OUString(), sal_Int64 nAspect = css::embed::Aspects::MSOLE_CONTENT );
+ bool PasteBitmapEx( const Point&, const BitmapEx& );
+ bool PasteMetaFile( const Point&, const GDIMetaFile& );
+ bool PasteGraphic( const Point& rPos, const Graphic& rGraphic,
+ const OUString& rFile );
+ bool PasteBookmark( SotClipboardFormatId nFormatId,
+ const css::uno::Reference< css::datatransfer::XTransferable >& rxTransferable,
+ SCCOL nPosX, SCROW nPosY );
+ bool PasteLink( const css::uno::Reference< css::datatransfer::XTransferable >& rxTransferable );
+
+ void InsertBookmark( const OUString& rDescription, const OUString& rURL,
+ SCCOL nPosX, SCROW nPosY, const OUString* pTarget = nullptr,
+ bool bTryReplace = false );
+ bool HasBookmarkAtCursor( SvxHyperlinkItem* pContent );
+
+ bool MoveBlockTo( const ScRange& rSource, const ScAddress& rDestPos,
+ bool bCut );
+
+ bool LinkBlock( const ScRange& rSource, const ScAddress& rDestPos );
+
+ void CreateNames( CreateNameFlags nFlags );
+ CreateNameFlags GetCreateNameFlags();
+ void InsertNameList();
+ bool InsertName( const OUString& rName, const OUString& rSymbol,
+ const OUString& rType );
+
+ void ApplyAttributes( const SfxItemSet* pDialogSet, const SfxItemSet* pOldSet, bool bAdjustBlockHeight = true );
+ void ApplyAttr( const SfxPoolItem& rAttrItem, bool bAdjustBlockHeight = true );
+
+ void ApplySelectionPattern( const ScPatternAttr& rAttr,
+ bool bCursorOnly = false);
+ void ApplyPatternLines(const ScPatternAttr& rAttr,
+ const SvxBoxItem& rNewOuter,
+ const SvxBoxInfoItem* pNewInner);
+
+ void ApplyUserItemSet( const SfxItemSet& rItemSet );
+
+ const SfxStyleSheet*
+ GetStyleSheetFromMarked();
+ void SetStyleSheetToMarked( const SfxStyleSheet* pStyleSheet );
+ void RemoveStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet );
+ void UpdateStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet );
+
+ void SetNumberFormat( SvNumFormatType nFormatType, sal_uLong nAdd = 0 );
+ void SetNumFmtByStr( const OUString& rCode );
+ void ChangeNumFmtDecimals( bool bIncrement );
+
+ void SetValidation( const ScValidationData& rNew );
+
+ void ChangeIndent( bool bIncrement );
+
+ void ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect );
+
+ void ProtectDoc( const OUString& rPassword );
+ bool Unprotect( SCTAB nTab, const OUString& rPassword );
+
+ void DeleteCells( DelCellCmd eCmd );
+ bool InsertCells( InsCellCmd eCmd, bool bRecord = true, bool bPartOfPaste = false );
+ void DeleteMulti( bool bRows );
+
+ void DeleteContents( InsertDeleteFlags nFlags );
+
+ void SetWidthOrHeight(
+ bool bWidth, const std::vector<sc::ColRowSpan>& rRanges, ScSizeMode eMode,
+ sal_uInt16 nSizeTwips, bool bRecord = true, const ScMarkData* pMarkData = nullptr );
+
+ void SetMarkedWidthOrHeight( bool bWidth, ScSizeMode eMode, sal_uInt16 nSizeTwips );
+
+ bool AdjustBlockHeight( bool bPaint = true, ScMarkData* pMarkData = nullptr );
+ bool AdjustRowHeight( SCROW nStartRow, SCROW nEndRow, bool bApi );
+
+ void ModifyCellSize( ScDirection eDir, bool bOptimal );
+
+ SC_DLLPUBLIC void
+ InsertPageBreak( bool bColumn, bool bRecord = true,
+ const ScAddress* pPos = nullptr,
+ bool bSetModified = true );
+ SC_DLLPUBLIC void
+ DeletePageBreak( bool bColumn, bool bRecord = true,
+ const ScAddress* pPos = nullptr,
+ bool bSetModified = true );
+
+ void RemoveManualBreaks();
+
+ void SetPrintZoom(sal_uInt16 nScale);
+ void AdjustPrintZoom();
+
+ bool TestMergeCells();
+ bool TestRemoveMerge();
+
+ bool MergeCells( bool bApi, bool& rDoContents, bool bCenter );
+ bool RemoveMerge();
+
+ SC_DLLPUBLIC void
+ FillSimple( FillDir eDir );
+ void FillSeries( FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd,
+ double fStart, double fStep, double fMax );
+ SC_DLLPUBLIC void
+ FillAuto( FillDir eDir, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount );
+ void FillCrossDblClick();
+ void ConvertFormulaToValue();
+
+ void TransliterateText( TransliterationFlags nType );
+
+ ScAutoFormatData* CreateAutoFormatData();
+ void AutoFormat( sal_uInt16 nFormatNo );
+
+ bool SearchAndReplace( const SvxSearchItem* pSearchItem,
+ bool bAddUndo, bool bIsApi );
+
+ void Solve( const ScSolveParam& rParam );
+ void TabOp( const ScTabOpParam& rParam, bool bRecord = true );
+
+ bool InsertTable( const OUString& rName, SCTAB nTabNr, bool bRecord = true );
+ void InsertTables(std::vector<OUString>& aNames, SCTAB nTab, SCTAB nCount, bool bRecord = true);
+
+ bool AppendTable( const OUString& rName, bool bRecord = true );
+
+ void DeleteTable( SCTAB nTabNr, bool bRecord = true );
+ bool DeleteTables(const std::vector<SCTAB>& TheTabs, bool bRecord = true );
+ void DeleteTables(SCTAB nTab, SCTAB nSheets);
+
+ bool RenameTable( const OUString& rName, SCTAB nTabNr );
+ void MoveTable( sal_uInt16 nDestDocNo, SCTAB nDestTab, bool bCopy, const OUString* pNewTabName = nullptr );
+ void ImportTables( ScDocShell* pSrcShell,
+ SCTAB nCount, const SCTAB* pSrcTabs,
+ bool bLink,SCTAB nTab);
+
+ bool SetTabBgColor( const Color& rColor, SCTAB nTabNr );
+ bool SetTabBgColor( ScUndoTabColorInfo::List& rUndoSetTabBgColorInfoList );
+
+ void InsertTableLink( const OUString& rFile,
+ const OUString& rFilter, const OUString& rOptions,
+ std::u16string_view rTabName );
+ void InsertAreaLink( const OUString& rFile,
+ const OUString& rFilter, const OUString& rOptions,
+ const OUString& rSource );
+
+ void ShowTable( const std::vector<OUString>& rNames );
+ void HideTable( const ScMarkData& rMark, SCTAB nTabToSelect = -1);
+
+ void MakeScenario(const OUString& rName, const OUString& rComment,
+ const Color& rColor, ScScenarioFlags nFlags);
+ void ExtendScenario();
+ void UseScenario( const OUString& rName );
+
+ void InsertSpecialChar( const OUString& rStr, const vcl::Font& rFont );
+
+ void SetSelectionFrameLines( const ::editeng::SvxBorderLine* pLine,
+ bool bColorOnly );
+
+ void SetNoteText( const ScAddress& rPos, const OUString& rNoteText );
+ void ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, const OUString* pAuthor, const OUString* pDate );
+ void DoRefConversion();
+
+ void DoHangulHanjaConversion();
+ void DoThesaurus();
+
+ /** Generic implementation of sheet conversion functions. */
+ void DoSheetConversion( const ScConversionParam& rParam );
+
+ void SetPrintRanges( bool bEntireSheet,
+ const OUString* pPrint,
+ const OUString* pRepCol, const OUString* pRepRow,
+ bool bAddPrint );
+
+ void DetectiveAddPred();
+ void DetectiveDelPred();
+ void DetectiveAddSucc();
+ void DetectiveDelSucc();
+ void DetectiveAddError();
+ void DetectiveMarkInvalid();
+ void DetectiveDelAll();
+ void DetectiveRefresh();
+ void DetectiveMarkPred();
+ void DetectiveMarkSucc();
+
+ void InsertCurrentTime(SvNumFormatType nCellFmt, const OUString& rUndoStr);
+
+ void ShowNote( bool bShow );
+ void EditNote();
+
+ bool SelectionEditable( bool* pOnlyNotBecauseOfMatrix = nullptr );
+
+ SC_DLLPUBLIC void
+ DataFormPutData(SCROW nCurrentRow ,
+ SCROW nStartRow , SCCOL nStartCol ,
+ SCROW nEndRow , SCCOL nEndCol ,
+ std::vector<std::unique_ptr<ScDataFormFragment>>& rEdits,
+ sal_uInt16 aColLength);
+ void UpdateSelectionArea( const ScMarkData& rSel, ScPatternAttr* pAttr = nullptr );
+
+ void OnLOKInsertDeleteColumn(SCCOL nStartCol, tools::Long nOffset);
+ void OnLOKInsertDeleteRow(SCROW nStartRow, tools::Long nOffset);
+ void OnLOKSetWidthOrHeight(SCCOLROW nStart, bool bWidth);
+
+ // Internal helper functions
+protected:
+ static void UpdateLineAttrs( ::editeng::SvxBorderLine& rLine,
+ const ::editeng::SvxBorderLine* pDestLine,
+ const ::editeng::SvxBorderLine* pSrcLine,
+ bool bColor );
+
+private:
+ void PasteRTF( SCCOL nCol, SCROW nStartRow,
+ const css::uno::Reference< css::datatransfer::XTransferable >& rxTransferable );
+
+ bool PasteMultiRangesFromClip(
+ InsertDeleteFlags nFlags, ScDocument* pClipDoc,
+ ScPasteFunc nFunction, bool bSkipEmptyCells,
+ bool bTranspose, bool bAsLink, bool bAllowDialogs,
+ InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags );
+
+ bool PasteFromClipToMultiRanges(
+ InsertDeleteFlags nFlags, ScDocument* pClipDoc, ScPasteFunc nFunction,
+ bool bSkipEmptyCells, bool bTranspose, bool bAsLink, bool bAllowDialogs,
+ InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags );
+
+ void PostPasteFromClip(const ScRangeList& rPasteRanges, const ScMarkData& rMark);
+
+ sal_uInt16 GetOptimalColWidth( SCCOL nCol, SCTAB nTab, bool bFormula );
+
+ void StartFormatArea();
+ bool TestFormatArea( SCCOL nCol, SCROW nRow, SCTAB nTab, bool bAttrChanged );
+ void DoAutoAttributes( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ bool bAttrChanged );
+
+ void MarkAndJumpToRanges(const ScRangeList& rRanges);
+ void CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount );
+};
+
+extern bool bPasteIsMove;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/viewutil.hxx b/sc/source/ui/inc/viewutil.hxx
new file mode 100644
index 000000000..41367e672
--- /dev/null
+++ b/sc/source/ui/inc/viewutil.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 <address.hxx>
+#include <sal/types.h>
+#include <i18nlangtag/lang.h>
+
+class SfxItemSet;
+class SfxBindings;
+class SvxFontItem;
+class SfxViewShell;
+class SfxViewFrame;
+class ScChangeAction;
+class ScChangeViewSettings;
+class ScDocument;
+class ScMarkData;
+class ScTabViewShell;
+enum class SvtScriptType : sal_uInt8;
+enum class TransliterationFlags;
+
+
+enum class ScUpdateMode { All, Marks };
+
+class SC_DLLPUBLIC ScViewUtil
+{
+public:
+ static void ExecuteCharMap(const SvxFontItem& rOldFont, const ScTabViewShell& rShell);
+
+ static bool IsActionShown( const ScChangeAction& rAction,
+ const ScChangeViewSettings& rSettings,
+ ScDocument& rDocument );
+
+ static void PutItemScript( SfxItemSet& rShellSet, const SfxItemSet& rCoreSet,
+ sal_uInt16 nWhichId, SvtScriptType nScript );
+
+ static LanguageType GetEffLanguage( ScDocument& rDoc, const ScAddress& rPos );
+
+ static TransliterationFlags GetTransliterationType( sal_uInt16 nSlotID );
+
+ static bool HasFiltered( const ScRange& rRange, const ScDocument& rDoc );
+ /** Fit a range to cover nRows number of unfiltered rows.
+ @return <TRUE/> if the resulting range covers nRows unfiltered rows. */
+ static bool FitToUnfilteredRows( ScRange & rRange, const ScDocument& rDoc, size_t nRows );
+ static void UnmarkFiltered( ScMarkData& rMark, const ScDocument& rDoc );
+
+ static void HideDisabledSlot( SfxItemSet& rSet, SfxBindings& rBindings, sal_uInt16 nSlotId );
+
+ /** Returns true, if the passed view shell is in full screen mode. */
+ static bool IsFullScreen( const SfxViewShell& rViewShell );
+ /** Enters or leaves full screen mode at the passed view shell. */
+ static void SetFullScreen( const SfxViewShell& rViewShell, bool bSet );
+};
+
+class ScUpdateRect
+{
+private:
+ SCCOL nOldStartX;
+ SCROW nOldStartY;
+ SCCOL nOldEndX;
+ SCROW nOldEndY;
+ SCCOL nNewStartX;
+ SCROW nNewStartY;
+ SCCOL nNewEndX;
+ SCROW nNewEndY;
+public:
+ ScUpdateRect( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2 );
+ void SetNew( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2 );
+ bool GetDiff( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/warnbox.hxx b/sc/source/ui/inc/warnbox.hxx
new file mode 100644
index 000000000..f3a437b5e
--- /dev/null
+++ b/sc/source/ui/inc/warnbox.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 <vcl/weld.hxx>
+
+/** Warning box for "Replace cell contents?".
+ With warning image and "Do not show again" checkbox. */
+class ScReplaceWarnBox : public weld::MessageDialogController
+{
+ std::unique_ptr<weld::CheckButton> m_xWarningOnBox;
+
+public:
+ ScReplaceWarnBox(weld::Window* pParent);
+
+ /** Opens dialog if IsDialogEnabled() returns true.
+ @descr If after executing the dialog the checkbox "Do not show again" is set,
+ the method DisableDialog() will be called. */
+ virtual short run() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/inc/xmlsourcedlg.hxx b/sc/source/ui/inc/xmlsourcedlg.hxx
new file mode 100644
index 000000000..3d45d27a8
--- /dev/null
+++ b/sc/source/ui/inc/xmlsourcedlg.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/.
+ */
+
+#pragma once
+
+#include "anyrefdg.hxx"
+#include <orcusxml.hxx>
+
+#include <set>
+#include <memory>
+
+class ScDocument;
+class ScRange;
+class ScOrcusXMLContext;
+
+struct CustomCompare
+{
+ weld::TreeView& mrLbTree;
+ CustomCompare(weld::TreeView& rLbTree)
+ : mrLbTree(rLbTree)
+ {
+ }
+ bool operator()(const std::unique_ptr<weld::TreeIter>& lhs,
+ const std::unique_ptr<weld::TreeIter>& rhs) const
+ {
+ return mrLbTree.iter_compare(*lhs, *rhs) == -1;
+ }
+};
+
+class ScXMLSourceDlg : public ScAnyRefDlgController
+{
+ OUString maSrcPath;
+
+ ScOrcusXMLTreeParam maXMLParam;
+ std::unique_ptr<weld::TreeIter> mxCurRefEntry;
+ std::unique_ptr<ScOrcusXMLContext> mpXMLContext;
+
+ ScDocument* mpDoc;
+ bool mbDlgLostFocus;
+
+ formula::RefEdit* mpActiveEdit;
+ std::unique_ptr<weld::Button> mxBtnSelectSource;
+ std::unique_ptr<weld::Label> mxFtSourceFile;
+
+ std::unique_ptr<weld::Container> mxMapGrid;
+
+ std::unique_ptr<weld::TreeView> mxLbTree;
+ std::unique_ptr<formula::RefEdit> mxRefEdit;
+ std::unique_ptr<formula::RefButton> mxRefBtn;
+
+ std::unique_ptr<weld::Button> mxBtnOk;
+ std::unique_ptr<weld::Button> mxBtnCancel;
+
+ CustomCompare maCustomCompare;
+
+ std::set<std::unique_ptr<weld::TreeIter>, CustomCompare> maCellLinks;
+ std::set<std::unique_ptr<weld::TreeIter>, CustomCompare> maRangeLinks;
+
+public:
+ ScXMLSourceDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, ScDocument* pDoc);
+ virtual ~ScXMLSourceDlg() override;
+
+ virtual bool IsRefInputMode() const override;
+ virtual void SetReference(const ScRange& rRange, ScDocument& rDoc) override;
+ virtual void Deactivate() override;
+ virtual void SetActive() override;
+ virtual void Close() override;
+
+private:
+ void SelectSourceFile();
+ void LoadSourceFileStructure(const OUString& rPath);
+ void TreeItemSelected();
+ void DefaultElementSelected(const weld::TreeIter& rEntry);
+ void RepeatElementSelected(const weld::TreeIter& rEntry);
+ void AttributeSelected(const weld::TreeIter& rEntry);
+
+ void SetNonLinkable();
+ void SetSingleLinkable();
+ void SetRangeLinkable();
+ void SelectAllChildEntries(const weld::TreeIter& rEntry);
+
+ /**
+ * Check if any of its parents is linked or repeated. The passed entry is
+ * not checked; its parent is the first one to be checked, then all its
+ * parents get checked all the way to the root.
+ */
+ bool IsParentDirty(const weld::TreeIter* pEntry) const;
+
+ bool IsChildrenDirty(const weld::TreeIter* pEntry) const;
+
+ void OkPressed();
+ void CancelPressed();
+ void RefEditModified();
+
+ DECL_LINK(BtnPressedHdl, weld::Button&, void);
+ DECL_LINK(TreeItemSelectHdl, weld::TreeView&, void);
+ DECL_LINK(RefModifiedHdl, formula::RefEdit&, void);
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/acredlin.cxx b/sc/source/ui/miscdlgs/acredlin.cxx
new file mode 100644
index 000000000..87292fe06
--- /dev/null
+++ b/sc/source/ui/miscdlgs/acredlin.cxx
@@ -0,0 +1,1792 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/undo.hxx>
+#include <unotools/textsearch.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <unotools/collatorwrapper.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <vcl/commandevent.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <acredlin.hxx>
+#include <global.hxx>
+#include <reffact.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <scmod.hxx>
+#include <tabvwsh.hxx>
+
+// defines -------------------------------------------------------------------
+
+#define RD_SPECIAL_NONE 0
+#define RD_SPECIAL_CONTENT 1
+#define RD_SPECIAL_VISCONTENT 2
+
+
+ScRedlinData::ScRedlinData()
+{
+ nInfo=RD_SPECIAL_NONE;
+ nActionNo=0;
+ pData=nullptr;
+ bDisabled=false;
+ bIsRejectable=false;
+ bIsAcceptable=false;
+ nTable=SCTAB_MAX;
+ nCol=SCCOL_MAX;
+ nRow=SCROW_MAX;
+}
+
+ScRedlinData::~ScRedlinData()
+{
+ nInfo=RD_SPECIAL_NONE;
+ nActionNo=0;
+ pData=nullptr;
+ bDisabled=false;
+ bIsRejectable=false;
+ bIsAcceptable=false;
+}
+
+
+ScAcceptChgDlg::ScAcceptChgDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScViewData* ptrViewData)
+ : SfxModelessDialogController(pB, pCW, pParent,
+ "svx/ui/acceptrejectchangesdialog.ui", "AcceptRejectChangesDialog")
+ , aSelectionIdle( "ScAcceptChgDlg aSelectionIdle" )
+ , aReOpenIdle("ScAcceptChgDlg ReOpenIdle")
+ , pViewData( ptrViewData )
+ , pDoc( &ptrViewData->GetDocument() )
+ , aStrInsertCols(ScResId(STR_CHG_INSERT_COLS))
+ , aStrInsertRows(ScResId(STR_CHG_INSERT_ROWS))
+ , aStrInsertTabs(ScResId(STR_CHG_INSERT_TABS))
+ , aStrDeleteCols(ScResId(STR_CHG_DELETE_COLS))
+ , aStrDeleteRows(ScResId(STR_CHG_DELETE_ROWS))
+ , aStrDeleteTabs(ScResId(STR_CHG_DELETE_TABS))
+ , aStrMove(ScResId(STR_CHG_MOVE))
+ , aStrContent(ScResId(STR_CHG_CONTENT))
+ , aStrReject(ScResId(STR_CHG_REJECT))
+ , aStrAllAccepted(ScResId(STR_CHG_ACCEPTED))
+ , aStrAllRejected(ScResId(STR_CHG_REJECTED))
+ , aStrNoEntry(ScResId(STR_CHG_NO_ENTRY))
+ , aStrContentWithChild(ScResId(STR_CHG_CONTENT_WITH_CHILD))
+ , aStrChildContent(ScResId(STR_CHG_CHILD_CONTENT))
+ , aStrChildOrgContent(ScResId(STR_CHG_CHILD_ORGCONTENT))
+ , aStrEmpty(ScResId(STR_CHG_EMPTY))
+ , aUnknown("Unknown")
+ , bIgnoreMsg(false)
+ , bNoSelection(false)
+ , bHasFilterEntry(false)
+ , bUseColor(false)
+ , m_xContentArea(m_xDialog->weld_content_area())
+ , m_xPopup(m_xBuilder->weld_menu("calcmenu"))
+ , m_xSortMenu(m_xBuilder->weld_menu("calcsortmenu"))
+{
+ m_xAcceptChgCtr.reset(new SvxAcceptChgCtr(m_xContentArea.get()));
+ nAcceptCount=0;
+ nRejectCount=0;
+ aReOpenIdle.SetInvokeHandler(LINK( this, ScAcceptChgDlg, ReOpenTimerHdl ));
+
+ pTPFilter = m_xAcceptChgCtr->GetFilterPage();
+ pTPView = m_xAcceptChgCtr->GetViewPage();
+
+ // tdf#136062 Don't use "Reject/Clear formatting" instead of "Reject" buttons in Calc
+ pTPView->EnableClearFormat(false);
+ pTPView->EnableClearFormatAll(false);
+
+ pTheView = pTPView->GetTableControl();
+ pTheView->SetCalcView();
+ aSelectionIdle.SetInvokeHandler(LINK( this, ScAcceptChgDlg, UpdateSelectionHdl ));
+
+ pTPFilter->SetReadyHdl(LINK( this, ScAcceptChgDlg, FilterHandle ));
+ pTPFilter->SetRefHdl(LINK( this, ScAcceptChgDlg, RefHandle ));
+ pTPFilter->HideRange(false);
+ pTPView->SetRejectClickHdl( LINK( this, ScAcceptChgDlg,RejectHandle));
+ pTPView->SetAcceptClickHdl( LINK(this, ScAcceptChgDlg, AcceptHandle));
+ pTPView->SetRejectAllClickHdl( LINK( this, ScAcceptChgDlg,RejectAllHandle));
+ pTPView->SetAcceptAllClickHdl( LINK(this, ScAcceptChgDlg, AcceptAllHandle));
+
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ rTreeView.connect_expanding(LINK(this, ScAcceptChgDlg, ExpandingHandle));
+ rTreeView.connect_changed(LINK(this, ScAcceptChgDlg, SelectHandle));
+ rTreeView.connect_popup_menu(LINK(this, ScAcceptChgDlg, CommandHdl));
+ rTreeView.set_sort_func([this](const weld::TreeIter& rLeft, const weld::TreeIter& rRight){
+ return ColCompareHdl(rLeft, rRight);
+ });
+ rTreeView.set_selection_mode(SelectionMode::Multiple);
+
+ Init();
+
+ UpdateView();
+
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xEntry))
+ rTreeView.select(*xEntry);
+}
+
+ScAcceptChgDlg::~ScAcceptChgDlg()
+{
+ ClearView();
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+
+ if (pChanges)
+ {
+ Link<ScChangeTrack&,void> aLink;
+ pChanges->SetModifiedLink(aLink);
+ }
+}
+
+void ScAcceptChgDlg::ReInit(ScViewData* ptrViewData)
+{
+ pViewData=ptrViewData;
+ if (pViewData)
+ pDoc = &ptrViewData->GetDocument();
+ else
+ pDoc = nullptr;
+
+ bNoSelection=false;
+ bIgnoreMsg=false;
+ nAcceptCount=0;
+ nRejectCount=0;
+
+ // don't call Init here (switching between views), just set link below
+ // (dialog is just hidden, not deleted anymore, when switching views)
+ ClearView();
+ UpdateView();
+
+ if ( pDoc )
+ {
+ ScChangeTrack* pChanges = pDoc->GetChangeTrack();
+ if ( pChanges )
+ pChanges->SetModifiedLink( LINK( this, ScAcceptChgDlg, ChgTrackModHdl ) );
+ }
+}
+
+void ScAcceptChgDlg::Init()
+{
+ OSL_ENSURE( pViewData && pDoc, "ViewData or Document not found!" );
+
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+
+ if(pChanges!=nullptr)
+ {
+ pChanges->SetModifiedLink( LINK( this, ScAcceptChgDlg,ChgTrackModHdl));
+ aChangeViewSet.SetTheAuthorToShow(pChanges->GetUser());
+ pTPFilter->ClearAuthors();
+ const std::set<OUString>& rUserColl = pChanges->GetUserCollection();
+ for (const auto& rItem : rUserColl)
+ pTPFilter->InsertAuthor(rItem);
+ }
+
+ ScChangeViewSettings* pViewSettings=pDoc->GetChangeViewSettings();
+ if ( pViewSettings!=nullptr )
+ aChangeViewSet = *pViewSettings;
+ // adjust TimeField for filter tabpage
+ aChangeViewSet.AdjustDateMode( *pDoc );
+
+ pTPFilter->CheckDate(aChangeViewSet.HasDate());
+
+ DateTime aEmpty(DateTime::EMPTY);
+
+ DateTime aDateTime(aChangeViewSet.GetTheFirstDateTime());
+ if (aDateTime != aEmpty)
+ {
+ pTPFilter->SetFirstDate(aDateTime);
+ pTPFilter->SetFirstTime(aDateTime);
+ }
+ aDateTime = aChangeViewSet.GetTheLastDateTime();
+ if (aDateTime != aEmpty)
+ {
+ pTPFilter->SetLastDate(aDateTime);
+ pTPFilter->SetLastTime(aDateTime);
+ }
+
+ pTPFilter->SetDateMode(static_cast<sal_uInt16>(aChangeViewSet.GetTheDateMode()));
+ pTPFilter->CheckComment(aChangeViewSet.HasComment());
+ pTPFilter->SetComment(aChangeViewSet.GetTheComment());
+
+ pTPFilter->CheckAuthor(aChangeViewSet.HasAuthor());
+ OUString aString=aChangeViewSet.GetTheAuthorToShow();
+ if(!aString.isEmpty())
+ {
+ pTPFilter->SelectAuthor(aString);
+ if(pTPFilter->GetSelectedAuthor()!=aString)
+ {
+ pTPFilter->InsertAuthor(aString);
+ pTPFilter->SelectAuthor(aString);
+ }
+ }
+ else
+ pTPFilter->SelectedAuthorPos(0);
+
+ pTPFilter->CheckRange(aChangeViewSet.HasRange());
+
+ aRangeList=aChangeViewSet.GetTheRangeList();
+
+ if( !aChangeViewSet.GetTheRangeList().empty() )
+ {
+ const ScRange & rRangeEntry = aChangeViewSet.GetTheRangeList().front();
+ OUString aRefStr(rRangeEntry.Format(*pDoc, ScRefFlags::RANGE_ABS_3D));
+ pTPFilter->SetRange(aRefStr);
+ }
+
+ // init filter
+ if(!(pTPFilter->IsDate()||pTPFilter->IsRange()||
+ pTPFilter->IsAuthor()||pTPFilter->IsComment()))
+ return;
+
+ pTheView->SetFilterDate(pTPFilter->IsDate());
+ pTheView->SetDateTimeMode(pTPFilter->GetDateMode());
+ pTheView->SetFirstDate(pTPFilter->GetFirstDate());
+ pTheView->SetLastDate(pTPFilter->GetLastDate());
+ pTheView->SetFirstTime(pTPFilter->GetFirstTime());
+ pTheView->SetLastTime(pTPFilter->GetLastTime());
+ pTheView->SetFilterAuthor(pTPFilter->IsAuthor());
+ pTheView->SetAuthor(pTPFilter->GetSelectedAuthor());
+
+ pTheView->SetFilterComment(pTPFilter->IsComment());
+
+ utl::SearchParam aSearchParam( pTPFilter->GetComment(),
+ utl::SearchParam::SearchType::Regexp,false );
+
+ pTheView->SetCommentParams(&aSearchParam);
+
+ pTheView->UpdateFilterTest();
+}
+
+void ScAcceptChgDlg::ClearView()
+{
+ nAcceptCount=0;
+ nRejectCount=0;
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ rTreeView.all_foreach(
+ [&rTreeView](weld::TreeIter& rEntry)
+ {
+ ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rEntry));
+ delete pEntryData;
+ return false;
+ });
+ rTreeView.freeze();
+ rTreeView.clear();
+ rTreeView.thaw();
+}
+
+OUString* ScAcceptChgDlg::MakeTypeString(ScChangeActionType eType)
+{
+ OUString* pStr;
+
+ switch(eType)
+ {
+
+ case SC_CAT_INSERT_COLS: pStr=&aStrInsertCols;break;
+ case SC_CAT_INSERT_ROWS: pStr=&aStrInsertRows;break;
+ case SC_CAT_INSERT_TABS: pStr=&aStrInsertTabs;break;
+ case SC_CAT_DELETE_COLS: pStr=&aStrDeleteCols;break;
+ case SC_CAT_DELETE_ROWS: pStr=&aStrDeleteRows;break;
+ case SC_CAT_DELETE_TABS: pStr=&aStrDeleteTabs;break;
+ case SC_CAT_MOVE: pStr=&aStrMove;break;
+ case SC_CAT_CONTENT: pStr=&aStrContent;break;
+ case SC_CAT_REJECT: pStr=&aStrReject;break;
+ default: pStr=&aUnknown;break;
+ }
+ return pStr;
+}
+
+bool ScAcceptChgDlg::IsValidAction(const ScChangeAction* pScChangeAction)
+{
+ if(pScChangeAction==nullptr) return false;
+
+ bool bFlag = false;
+
+ ScRange aRef=pScChangeAction->GetBigRange().MakeRange(*pDoc);
+ OUString aUser=pScChangeAction->GetUser();
+ DateTime aDateTime=pScChangeAction->GetDateTime();
+
+ ScChangeActionType eType=pScChangeAction->GetType();
+ OUString aDesc;
+
+ OUString aComment = pScChangeAction->GetComment().replaceAll("\n", "");
+
+ if(eType==SC_CAT_CONTENT)
+ {
+ if(!pScChangeAction->IsDialogParent())
+ aDesc = pScChangeAction->GetDescription(*pDoc, true);
+ }
+ else
+ aDesc = pScChangeAction->GetDescription(*pDoc, !pScChangeAction->IsMasterDelete());
+
+ if (!aDesc.isEmpty())
+ {
+ aComment += " (" + aDesc + ")";
+ }
+
+ if (pTheView->IsValidEntry(aUser, aDateTime, aComment))
+ {
+ if(pTPFilter->IsRange())
+ {
+ for ( size_t i = 0, nRanges = aRangeList.size(); i < nRanges; ++i )
+ {
+ ScRange const & rRangeEntry = aRangeList[ i ];
+ if (rRangeEntry.Intersects(aRef)) {
+ bFlag = true;
+ break;
+ }
+ }
+ }
+ else
+ bFlag=true;
+ }
+
+ return bFlag;
+}
+
+std::unique_ptr<weld::TreeIter> ScAcceptChgDlg::AppendChangeAction(
+ const ScChangeAction* pScChangeAction, bool bCreateOnDemand,
+ const weld::TreeIter* pParent, bool bDelMaster, bool bDisabled)
+{
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+
+ if(pScChangeAction==nullptr || pChanges==nullptr) return nullptr;
+
+ bool bFlag = false;
+
+ ScRange aRef=pScChangeAction->GetBigRange().MakeRange(*pDoc);
+ DateTime aDateTime=pScChangeAction->GetDateTime();
+
+ ScChangeActionType eType=pScChangeAction->GetType();
+ OUString aActionString;
+ OUString aRefStr;
+ OUString aUser;
+ OUString aDate;
+ OUString aDesc;
+
+ std::unique_ptr<ScRedlinData> pNewData(new ScRedlinData);
+ pNewData->pData=const_cast<ScChangeAction *>(pScChangeAction);
+ pNewData->nActionNo=pScChangeAction->GetActionNumber();
+ pNewData->bIsAcceptable=pScChangeAction->IsClickable();
+ pNewData->bIsRejectable=pScChangeAction->IsRejectable();
+ pNewData->bDisabled=!pNewData->bIsAcceptable || bDisabled;
+ pNewData->aDateTime=aDateTime;
+ pNewData->nRow = aRef.aStart.Row();
+ pNewData->nCol = aRef.aStart.Col();
+ pNewData->nTable= aRef.aStart.Tab();
+
+ if(eType==SC_CAT_CONTENT)
+ {
+ if(pScChangeAction->IsDialogParent())
+ {
+ aActionString = aStrContentWithChild;
+ pNewData->nInfo=RD_SPECIAL_VISCONTENT;
+ pNewData->bIsRejectable=false;
+ pNewData->bIsAcceptable=false;
+ }
+ else
+ {
+ aActionString = *MakeTypeString(eType);
+ aDesc = pScChangeAction->GetDescription(*pDoc, true);
+ }
+ }
+ else
+ {
+ aActionString = *MakeTypeString(eType);
+
+ if(bDelMaster)
+ {
+ aDesc = pScChangeAction->GetDescription(*pDoc,true);
+ pNewData->bDisabled=true;
+ pNewData->bIsRejectable=false;
+ }
+ else
+ aDesc = pScChangeAction->GetDescription(*pDoc, !pScChangeAction->IsMasterDelete());
+
+ }
+
+ aRefStr = pScChangeAction->GetRefString(*pDoc, true);
+
+ bool bIsGenerated = false;
+
+ if(!pChanges->IsGenerated(pScChangeAction->GetActionNumber()))
+ {
+ aUser = pScChangeAction->GetUser();
+ aDate = ScGlobal::getLocaleData().getDate(aDateTime) + " " + ScGlobal::getLocaleData().getTime(aDateTime);
+ bIsGenerated = false;
+ }
+ else
+ {
+ bIsGenerated = true;
+ }
+
+ OUString aComment = pScChangeAction->GetComment().replaceAll("\n", "");
+
+ if (!aDesc.isEmpty())
+ {
+ aComment += " (" + aDesc + ")";
+ }
+
+ if (pTheView->IsValidEntry(aUser, aDateTime) || bIsGenerated)
+ {
+ if (pTheView->IsValidComment(aComment))
+ {
+ if(pTPFilter->IsRange())
+ {
+ for ( size_t i = 0, nRanges = aRangeList.size(); i < nRanges; ++i )
+ {
+ ScRange const & rRangeEntry = aRangeList[ i ];
+ if( rRangeEntry.Intersects(aRef) )
+ {
+ bHasFilterEntry=true;
+ bFlag=true;
+ break;
+ }
+ }
+ }
+ else if(!bIsGenerated)
+ {
+ bHasFilterEntry=true;
+ bFlag=true;
+ }
+ }
+ }
+
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ OUString sId(weld::toId(pNewData.release()));
+ rTreeView.insert(pParent, -1, &aActionString, &sId, nullptr, nullptr, bCreateOnDemand, xEntry.get());
+ rTreeView.set_text( *xEntry, aRefStr, 1);
+ if (!aUser.isEmpty())
+ rTreeView.set_text( *xEntry, aUser, 2);
+ if (!aDate.isEmpty())
+ rTreeView.set_text( *xEntry, aDate, 3);
+ if (!aComment.isEmpty())
+ rTreeView.set_text( *xEntry, aComment, 4);
+ if (!bFlag && bUseColor && !pParent)
+ {
+ rTreeView.set_font_color(*xEntry, COL_LIGHTBLUE);
+ }
+ else if (bFlag && bUseColor && pParent)
+ {
+ rTreeView.set_font_color(*xEntry, COL_GREEN);
+
+ std::unique_ptr<weld::TreeIter> xExpEntry(rTreeView.make_iterator(pParent));
+
+ while (!rTreeView.get_row_expanded(*xExpEntry))
+ {
+ if (rTreeView.get_iter_depth(*xExpEntry))
+ rTreeView.expand_row(*xExpEntry);
+
+ if (!rTreeView.iter_parent(*xExpEntry))
+ break;
+ }
+ }
+ return xEntry;
+}
+
+std::unique_ptr<weld::TreeIter> ScAcceptChgDlg::AppendFilteredAction(
+ const ScChangeAction* pScChangeAction, ScChangeActionState eState,
+ bool bCreateOnDemand,
+ const weld::TreeIter* pParent, bool bDelMaster, bool bDisabled)
+{
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+
+ if(pScChangeAction==nullptr || pChanges==nullptr) return nullptr;
+
+ bool bIsGenerated = pChanges->IsGenerated(pScChangeAction->GetActionNumber());
+
+ bool bFlag = false;
+
+ ScRange aRef=pScChangeAction->GetBigRange().MakeRange(*pDoc);
+ OUString aUser=pScChangeAction->GetUser();
+ DateTime aDateTime=pScChangeAction->GetDateTime();
+
+ if (pTheView->IsValidEntry(aUser, aDateTime) || bIsGenerated)
+ {
+ if(pTPFilter->IsRange())
+ {
+ for ( size_t i = 0, nRanges = aRangeList.size(); i < nRanges; ++i )
+ {
+ ScRange const & rRangeEntry=aRangeList[ i ];
+ if( rRangeEntry.Intersects(aRef) )
+ {
+ if( pScChangeAction->GetState()==eState )
+ bFlag = true;
+ break;
+ }
+ }
+ }
+ else if(pScChangeAction->GetState()==eState && !bIsGenerated)
+ bFlag = true;
+ }
+
+ std::unique_ptr<weld::TreeIter> xEntry;
+ if(bFlag)
+ {
+ ScChangeActionType eType=pScChangeAction->GetType();
+ OUString aActionString;
+ OUString aDesc;
+
+ std::unique_ptr<ScRedlinData> pNewData(new ScRedlinData);
+ pNewData->pData=const_cast<ScChangeAction *>(pScChangeAction);
+ pNewData->nActionNo=pScChangeAction->GetActionNumber();
+ pNewData->bIsAcceptable=pScChangeAction->IsClickable();
+ pNewData->bIsRejectable=pScChangeAction->IsRejectable();
+ pNewData->bDisabled=!pNewData->bIsAcceptable || bDisabled;
+ pNewData->aDateTime=aDateTime;
+ pNewData->nRow = aRef.aStart.Row();
+ pNewData->nCol = aRef.aStart.Col();
+ pNewData->nTable= aRef.aStart.Tab();
+
+ if(eType==SC_CAT_CONTENT)
+ {
+ if(pScChangeAction->IsDialogParent())
+ {
+ aActionString=aStrContentWithChild;
+ pNewData->nInfo=RD_SPECIAL_VISCONTENT;
+ pNewData->bIsRejectable=false;
+ pNewData->bIsAcceptable=false;
+ }
+ else
+ {
+ aActionString=*MakeTypeString(eType);
+ aDesc = pScChangeAction->GetDescription(*pDoc, true);
+ }
+ }
+ else
+ {
+ aActionString=*MakeTypeString(eType);
+
+ if(bDelMaster)
+ {
+ aDesc = pScChangeAction->GetDescription(*pDoc,true);
+ pNewData->bDisabled=true;
+ pNewData->bIsRejectable=false;
+ }
+ else
+ aDesc = pScChangeAction->GetDescription(*pDoc,!pScChangeAction->IsMasterDelete());
+
+ }
+
+
+ OUString aComment = pScChangeAction->GetComment().replaceAll("\n", "");
+ if (!aDesc.isEmpty())
+ {
+ aComment += " (" + aDesc + ")";
+ }
+ if (pTheView->IsValidComment(aComment))
+ {
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ xEntry = rTreeView.make_iterator();
+ OUString sId(weld::toId(pNewData.release()));
+ rTreeView.insert(pParent, -1, &aActionString, &sId, nullptr, nullptr, bCreateOnDemand, xEntry.get());
+
+ OUString aRefStr = pScChangeAction->GetRefString(*pDoc, true);
+ rTreeView.set_text(*xEntry, aRefStr, 1);
+
+ if (!bIsGenerated)
+ {
+ rTreeView.set_text(*xEntry, aUser, 2);
+ OUString sDate = ScGlobal::getLocaleData().getDate(aDateTime) + " " + ScGlobal::getLocaleData().getTime(aDateTime);
+ rTreeView.set_text(*xEntry, sDate, 3);
+ }
+
+ rTreeView.set_text(*xEntry, aComment, 4);
+ }
+ }
+ return xEntry;
+}
+
+std::unique_ptr<weld::TreeIter> ScAcceptChgDlg::InsertChangeActionContent(const ScChangeActionContent* pScChangeAction,
+ const weld::TreeIter& rParent, sal_uLong nSpecial)
+{
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+
+ if(pScChangeAction==nullptr || pChanges==nullptr) return nullptr;
+
+ bool bIsGenerated = pChanges->IsGenerated(pScChangeAction->GetActionNumber());
+
+ bool bFlag = false;
+
+ ScRange aRef=pScChangeAction->GetBigRange().MakeRange(*pDoc);
+ OUString aUser=pScChangeAction->GetUser();
+ DateTime aDateTime=pScChangeAction->GetDateTime();
+
+ if (pTheView->IsValidEntry(aUser, aDateTime) || bIsGenerated)
+ {
+ if(pTPFilter->IsRange())
+ {
+ for ( size_t i = 0, nRanges = aRangeList.size(); i < nRanges; ++i )
+ {
+ ScRange const & rRangeEntry = aRangeList[ i ];
+ if( rRangeEntry.Intersects(aRef) )
+ {
+ bFlag=true;
+ break;
+ }
+ }
+ }
+ else if(!bIsGenerated)
+ bFlag=true;
+ }
+
+ OUString aContent;
+ OUString aRefStr;
+ OUString aDate;
+ OUString aDesc;
+
+ if(nSpecial==RD_SPECIAL_CONTENT)
+ {
+ aContent = pScChangeAction->GetOldString(pDoc);
+ if (aContent.isEmpty())
+ aContent = aStrEmpty;
+ aDesc = aStrChildOrgContent + ": " + aContent;
+ }
+ else
+ {
+ const OUString aTmp( pScChangeAction->GetNewString(pDoc));
+ if (aTmp.isEmpty())
+ aContent = aStrEmpty;
+ else
+ aContent = "\'" + aTmp + "\'";
+ aDesc = aStrChildContent + aContent;
+ }
+
+ aRefStr = pScChangeAction->GetRefString(*pDoc, true);
+
+ if(!bIsGenerated)
+ {
+ // aUser is kept.
+ aDate = ScGlobal::getLocaleData().getDate(aDateTime) + " " + ScGlobal::getLocaleData().getTime(aDateTime);
+ }
+ else
+ {
+ aUser.clear();
+ }
+
+ OUString aComment = pScChangeAction->GetComment().replaceAll("\n", "");
+
+ if(!aDesc.isEmpty())
+ {
+ aComment += " (" + aDesc + ")";
+ }
+
+ std::unique_ptr<ScRedlinData> pNewData(new ScRedlinData);
+ pNewData->nInfo=nSpecial;
+ pNewData->pData=const_cast<ScChangeActionContent *>(pScChangeAction);
+ pNewData->nActionNo=pScChangeAction->GetActionNumber();
+ pNewData->bIsAcceptable=pScChangeAction->IsClickable();
+ pNewData->bIsRejectable=false;
+ pNewData->bDisabled=!pNewData->bIsAcceptable;
+ pNewData->aDateTime=aDateTime;
+ pNewData->nRow = aRef.aStart.Row();
+ pNewData->nCol = aRef.aStart.Col();
+ pNewData->nTable= aRef.aStart.Tab();
+
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ OUString sId(weld::toId(pNewData.release()));
+ rTreeView.insert(&rParent, -1, &aContent, &sId, nullptr, nullptr, false, xEntry.get());
+ rTreeView.set_text( *xEntry, aRefStr, 1);
+ if (!aUser.isEmpty())
+ rTreeView.set_text( *xEntry, aUser, 2);
+ if (!aDate.isEmpty())
+ rTreeView.set_text( *xEntry, aDate, 3);
+ if (!aComment.isEmpty())
+ rTreeView.set_text( *xEntry, aComment, 4);
+ if (pTheView->IsValidComment(aComment) && bFlag)
+ bHasFilterEntry=true;
+ else
+ {
+ rTreeView.set_font_color(*xEntry, COL_LIGHTBLUE);
+ }
+ return xEntry;
+}
+
+void ScAcceptChgDlg::UpdateView()
+{
+ std::unique_ptr<weld::TreeIter> xParent;
+ ScChangeTrack* pChanges=nullptr;
+ const ScChangeAction* pScChangeAction=nullptr;
+ m_xDialog->set_busy_cursor(true);
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ rTreeView.freeze();
+ bool bFilterFlag = pTPFilter->IsDate() || pTPFilter->IsRange() ||
+ pTPFilter->IsAuthor() || pTPFilter->IsComment();
+
+ bUseColor = bFilterFlag;
+
+ if(pDoc!=nullptr)
+ {
+ pChanges=pDoc->GetChangeTrack();
+ if(pChanges!=nullptr)
+ pScChangeAction=pChanges->GetFirst();
+ }
+ bool bTheFlag = false;
+
+ while(pScChangeAction!=nullptr)
+ {
+ bHasFilterEntry=false;
+ switch (pScChangeAction->GetState())
+ {
+ case SC_CAS_VIRGIN:
+
+ if (pScChangeAction->IsDialogRoot())
+ {
+ bool bOnDemandChildren = !bFilterFlag && pScChangeAction->IsDialogParent();
+ if (pScChangeAction->IsDialogParent())
+ xParent = AppendChangeAction(pScChangeAction, bOnDemandChildren);
+ else
+ xParent = AppendFilteredAction(pScChangeAction, SC_CAS_VIRGIN, bOnDemandChildren);
+ }
+ else
+ xParent.reset();
+
+ bTheFlag=true;
+ break;
+
+ case SC_CAS_ACCEPTED:
+ xParent.reset();
+ nAcceptCount++;
+ break;
+
+ case SC_CAS_REJECTED:
+ xParent.reset();
+ nRejectCount++;
+ break;
+ }
+
+ if (xParent && pScChangeAction->IsDialogParent() && bFilterFlag)
+ {
+ bool bTestFlag = bHasFilterEntry;
+ bHasFilterEntry=false;
+ if (Expand(pChanges, pScChangeAction, *xParent, !bTestFlag) && !bTestFlag)
+ rTreeView.remove(*xParent);
+ }
+
+ pScChangeAction=pScChangeAction->GetNext();
+ }
+
+ if( bTheFlag && (!pDoc->IsDocEditable() || pChanges->IsProtected()) )
+ bTheFlag=false;
+
+ pTPView->EnableAccept(bTheFlag);
+ pTPView->EnableAcceptAll(bTheFlag);
+ pTPView->EnableReject(bTheFlag);
+ pTPView->EnableRejectAll(bTheFlag);
+
+ if (nAcceptCount>0)
+ rTreeView.insert(nullptr, -1, &aStrAllAccepted, nullptr, nullptr, nullptr, true, nullptr);
+ if (nRejectCount>0)
+ rTreeView.insert(nullptr, -1, &aStrAllRejected, nullptr, nullptr, nullptr, true, nullptr);
+ rTreeView.thaw();
+ m_xDialog->set_busy_cursor(false);
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xEntry))
+ rTreeView.select(*xEntry);
+}
+
+IMPL_LINK_NOARG(ScAcceptChgDlg, RefHandle, SvxTPFilter*, void)
+{
+ sal_uInt16 nId =ScSimpleRefDlgWrapper::GetChildWindowId();
+
+ SC_MOD()->SetRefDialog( nId, true );
+
+ SfxViewFrame* pViewFrm = pViewData->GetViewShell()->GetViewFrame();
+ ScSimpleRefDlgWrapper* pWnd = static_cast<ScSimpleRefDlgWrapper*>(pViewFrm->GetChildWindow( nId ));
+
+ if(pWnd!=nullptr)
+ {
+ sal_uInt16 nAcceptId=ScAcceptChgDlgWrapper::GetChildWindowId();
+ pViewFrm->ShowChildWindow(nAcceptId,false);
+ pWnd->SetCloseHdl(LINK( this, ScAcceptChgDlg,RefInfoHandle));
+ pWnd->SetRefString(pTPFilter->GetRange());
+ ScSimpleRefDlgWrapper::SetAutoReOpen(false);
+ auto xWin = pWnd->GetController();
+ m_xDialog->hide();
+ xWin->set_title(m_xDialog->get_title());
+ pWnd->StartRefInput();
+ }
+}
+
+IMPL_LINK( ScAcceptChgDlg, RefInfoHandle, const OUString*, pResult, void)
+{
+ sal_uInt16 nId = ScAcceptChgDlgWrapper::GetChildWindowId();
+
+ ScSimpleRefDlgWrapper::SetAutoReOpen(true);
+
+ SfxViewFrame* pViewFrm = pViewData->GetViewShell()->GetViewFrame();
+ if (pResult)
+ {
+ pTPFilter->SetRange(*pResult);
+ FilterHandle(pTPFilter);
+
+ pViewFrm->ShowChildWindow(nId);
+ }
+ else
+ {
+ pViewFrm->SetChildWindow(nId, false);
+ }
+}
+
+IMPL_LINK( ScAcceptChgDlg, FilterHandle, SvxTPFilter*, pRef, void )
+{
+ if(pRef!=nullptr)
+ {
+ ClearView();
+ aRangeList.RemoveAll();
+ aRangeList.Parse(pTPFilter->GetRange(), *pDoc);
+ UpdateView();
+ }
+}
+
+IMPL_LINK( ScAcceptChgDlg, RejectHandle, SvxTPView*, pRef, void )
+{
+ m_xDialog->set_busy_cursor(true);
+
+ bIgnoreMsg=true;
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+
+ if(pRef!=nullptr)
+ {
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ rTreeView.selected_foreach([this, pChanges, &rTreeView](weld::TreeIter& rEntry){
+ ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rEntry));
+ if (pEntryData)
+ {
+ ScChangeAction* pScChangeAction= static_cast<ScChangeAction*>(pEntryData->pData);
+ if (pScChangeAction->GetType()==SC_CAT_INSERT_TABS)
+ pViewData->SetTabNo(0);
+ pChanges->Reject(pScChangeAction);
+ }
+ return false;
+ });
+ ScDocShell* pDocSh=pViewData->GetDocShell();
+ pDocSh->PostPaintExtras();
+ pDocSh->PostPaintGridAll();
+ pDocSh->GetUndoManager()->Clear();
+ pDocSh->SetDocumentModified();
+ ClearView();
+ UpdateView();
+ }
+
+ m_xDialog->set_busy_cursor(false);
+
+ bIgnoreMsg=false;
+}
+IMPL_LINK( ScAcceptChgDlg, AcceptHandle, SvxTPView*, pRef, void )
+{
+ m_xDialog->set_busy_cursor(true);
+
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+ bIgnoreMsg=true;
+ if(pRef!=nullptr)
+ {
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ rTreeView.selected_foreach([pChanges, &rTreeView](weld::TreeIter& rEntry) {
+ ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rEntry));
+ if (pEntryData)
+ {
+ ScChangeAction* pScChangeAction=
+ static_cast<ScChangeAction*>(pEntryData->pData);
+ if(pScChangeAction->GetType()==SC_CAT_CONTENT)
+ {
+ if(pEntryData->nInfo==RD_SPECIAL_CONTENT)
+ pChanges->SelectContent(pScChangeAction,true);
+ else
+ pChanges->SelectContent(pScChangeAction);
+ }
+ else
+ pChanges->Accept(pScChangeAction);
+ }
+ return false;
+ });
+ ScDocShell* pDocSh=pViewData->GetDocShell();
+ pDocSh->PostPaintExtras();
+ pDocSh->PostPaintGridAll();
+ pDocSh->SetDocumentModified();
+ ClearView();
+ UpdateView();
+ }
+ m_xDialog->set_busy_cursor(false);
+ bIgnoreMsg=false;
+}
+
+void ScAcceptChgDlg::RejectFiltered()
+{
+ if(pDoc==nullptr) return;
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+ const ScChangeAction* pScChangeAction=nullptr;
+
+ if(pChanges!=nullptr)
+ {
+ pScChangeAction=pChanges->GetLast();
+ }
+
+ while(pScChangeAction!=nullptr)
+ {
+ if(pScChangeAction->IsDialogRoot())
+ if(IsValidAction(pScChangeAction))
+ pChanges->Reject(const_cast<ScChangeAction*>(pScChangeAction));
+
+ pScChangeAction=pScChangeAction->GetPrev();
+ }
+}
+void ScAcceptChgDlg::AcceptFiltered()
+{
+ if(pDoc==nullptr) return;
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+ const ScChangeAction* pScChangeAction=nullptr;
+
+ if(pChanges!=nullptr)
+ pScChangeAction=pChanges->GetLast();
+
+ while(pScChangeAction!=nullptr)
+ {
+ if(pScChangeAction->IsDialogRoot())
+ if(IsValidAction(pScChangeAction))
+ pChanges->Accept(const_cast<ScChangeAction*>(pScChangeAction));
+
+ pScChangeAction=pScChangeAction->GetPrev();
+ }
+}
+
+IMPL_LINK_NOARG(ScAcceptChgDlg, RejectAllHandle, SvxTPView*, void)
+{
+ m_xDialog->set_busy_cursor(true);
+ bIgnoreMsg=true;
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+ if(pChanges!=nullptr)
+ {
+ if(pTPFilter->IsDate()||pTPFilter->IsAuthor()||pTPFilter->IsRange()||pTPFilter->IsComment())
+ RejectFiltered();
+ else
+ pChanges->RejectAll();
+
+ pViewData->SetTabNo(0);
+
+ ScDocShell* pDocSh=pViewData->GetDocShell();
+ pDocSh->PostPaintExtras();
+ pDocSh->PostPaintGridAll();
+ pDocSh->GetUndoManager()->Clear();
+ pDocSh->SetDocumentModified();
+ ClearView();
+ UpdateView();
+ }
+ m_xDialog->set_busy_cursor(false);
+
+ bIgnoreMsg=false;
+}
+
+IMPL_LINK_NOARG(ScAcceptChgDlg, AcceptAllHandle, SvxTPView*, void)
+{
+ m_xDialog->set_busy_cursor(true);
+
+ bIgnoreMsg=true;
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+ if(pChanges!=nullptr)
+ {
+ if(pTPFilter->IsDate()||pTPFilter->IsAuthor()||pTPFilter->IsRange()||pTPFilter->IsComment())
+ AcceptFiltered();
+ else
+ pChanges->AcceptAll();
+
+ ScDocShell* pDocSh=pViewData->GetDocShell();
+ pDocSh->PostPaintExtras();
+ pDocSh->PostPaintGridAll();
+ pDocSh->SetDocumentModified();
+ ClearView();
+ UpdateView();
+ }
+ bIgnoreMsg=false;
+
+ m_xDialog->set_busy_cursor(false);
+}
+
+IMPL_LINK_NOARG(ScAcceptChgDlg, SelectHandle, weld::TreeView&, void)
+{
+ if (!bNoSelection)
+ aSelectionIdle.Start();
+
+ bNoSelection=false;
+}
+
+void ScAcceptChgDlg::GetDependents(const ScChangeAction* pScChangeAction,
+ ScChangeActionMap& aActionMap,
+ const weld::TreeIter& rEntry)
+{
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xParent(rTreeView.make_iterator(&rEntry));
+ if (rTreeView.iter_parent(*xParent))
+ {
+ ScRedlinData *pParentData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xParent));
+ ScChangeAction* pParentAction=static_cast<ScChangeAction*>(pParentData->pData);
+
+ if(pParentAction!=pScChangeAction)
+ pChanges->GetDependents(const_cast<ScChangeAction*>(pScChangeAction),
+ aActionMap,pScChangeAction->IsMasterDelete());
+ else
+ pChanges->GetDependents( const_cast<ScChangeAction*>(pScChangeAction),
+ aActionMap );
+ }
+ else
+ pChanges->GetDependents(const_cast<ScChangeAction*>(pScChangeAction),
+ aActionMap, pScChangeAction->IsMasterDelete() );
+}
+
+bool ScAcceptChgDlg::InsertContentChildren(ScChangeActionMap* pActionMap, const weld::TreeIter& rParent)
+{
+ bool bTheTestFlag = true;
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rParent));
+ const ScChangeAction* pScChangeAction = static_cast<ScChangeAction*>(pEntryData->pData);
+ bool bParentInserted = false;
+ // If the parent is a MatrixOrigin then place it in the right order before
+ // the MatrixReferences. Also if it is the first content change at this
+ // position don't insert the first dependent MatrixReference as the special
+ // content (original value) but insert the predecessor of the MatrixOrigin
+ // itself instead.
+ if ( pScChangeAction->GetType() == SC_CAT_CONTENT &&
+ static_cast<const ScChangeActionContent*>(pScChangeAction)->IsMatrixOrigin() )
+ {
+ pActionMap->insert( ::std::make_pair( pScChangeAction->GetActionNumber(),
+ const_cast<ScChangeAction*>( pScChangeAction ) ) );
+ bParentInserted = true;
+ }
+
+ ScChangeActionMap::iterator itChangeAction = std::find_if(pActionMap->begin(), pActionMap->end(),
+ [](const std::pair<sal_uLong, ScChangeAction*>& rEntry) { return rEntry.second->GetState() == SC_CAS_VIRGIN; });
+
+ if( itChangeAction == pActionMap->end() )
+ return true;
+
+ std::unique_ptr<weld::TreeIter> xOriginal = InsertChangeActionContent(
+ dynamic_cast<const ScChangeActionContent*>( itChangeAction->second ),
+ rParent, RD_SPECIAL_CONTENT );
+
+ if (xOriginal)
+ {
+ bTheTestFlag=false;
+ ScRedlinData *pParentData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xOriginal));
+ pParentData->pData=const_cast<ScChangeAction *>(pScChangeAction);
+ pParentData->nActionNo=pScChangeAction->GetActionNumber();
+ pParentData->bIsAcceptable=pScChangeAction->IsRejectable(); // select old value
+ pParentData->bIsRejectable=false;
+ pParentData->bDisabled=false;
+ }
+ while( itChangeAction != pActionMap->end() )
+ {
+ if( itChangeAction->second->GetState() == SC_CAS_VIRGIN )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry =
+ InsertChangeActionContent( dynamic_cast<const ScChangeActionContent*>( itChangeAction->second ),
+ rParent, RD_SPECIAL_NONE );
+
+ if (xEntry)
+ bTheTestFlag=false;
+ }
+ ++itChangeAction;
+ }
+
+ if ( !bParentInserted )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry =
+ InsertChangeActionContent(static_cast<const ScChangeActionContent*>(
+ pScChangeAction),rParent,RD_SPECIAL_NONE);
+
+ if (xEntry)
+ {
+ bTheTestFlag=false;
+ ScRedlinData *pParentData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry));
+ pParentData->pData=const_cast<ScChangeAction *>(pScChangeAction);
+ pParentData->nActionNo=pScChangeAction->GetActionNumber();
+ pParentData->bIsAcceptable=pScChangeAction->IsClickable();
+ pParentData->bIsRejectable=false;
+ pParentData->bDisabled=false;
+ }
+ }
+
+ return bTheTestFlag;
+}
+
+bool ScAcceptChgDlg::InsertAcceptedORejected(const weld::TreeIter& rParent)
+{
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+ bool bTheTestFlag = true;
+
+ ScChangeActionState eState = SC_CAS_VIRGIN;
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ OUString aString = rTreeView.get_text(rParent, 0);
+ OUString a2String = aString.copy(0, aStrAllAccepted.getLength());
+ if (a2String == aStrAllAccepted)
+ eState=SC_CAS_ACCEPTED;
+ else
+ {
+ a2String = aString.copy(0, aStrAllRejected.getLength());
+ if (a2String == aStrAllRejected)
+ eState=SC_CAS_REJECTED;
+ }
+
+ ScChangeAction* pScChangeAction = pChanges->GetFirst();
+ while (pScChangeAction)
+ {
+ if (pScChangeAction->GetState()==eState &&
+ AppendFilteredAction(pScChangeAction, eState, false, &rParent))
+ bTheTestFlag=false;
+ pScChangeAction=pScChangeAction->GetNext();
+ }
+ return bTheTestFlag;
+}
+
+bool ScAcceptChgDlg::InsertChildren(ScChangeActionMap* pActionMap, const weld::TreeIter& rParent)
+{
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+ bool bTheTestFlag = true;
+
+ for( const auto& rChangeAction : *pActionMap )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry = AppendChangeAction(rChangeAction.second, false, &rParent, false, true);
+
+ if (xEntry)
+ {
+ bTheTestFlag=false;
+
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry));
+ pEntryData->bIsRejectable=false;
+ pEntryData->bIsAcceptable=false;
+ pEntryData->bDisabled=true;
+
+ if (rChangeAction.second->IsDialogParent())
+ Expand(pChanges, rChangeAction.second, *xEntry);
+ }
+ }
+ return bTheTestFlag;
+}
+
+bool ScAcceptChgDlg::InsertDeletedChildren(const ScChangeAction* pScChangeAction,
+ ScChangeActionMap* pActionMap, const weld::TreeIter& rParent)
+{
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+ bool bTheTestFlag = true;
+ std::unique_ptr<weld::TreeIter> xEntry;
+
+ for( const auto& rChangeAction : *pActionMap )
+ {
+
+ if( pScChangeAction != rChangeAction.second )
+ xEntry = AppendChangeAction(rChangeAction.second, false, &rParent, false, true);
+ else
+ xEntry = AppendChangeAction(rChangeAction.second, false, &rParent, true, true);
+
+ if (xEntry)
+ {
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry));
+ pEntryData->bIsRejectable=false;
+ pEntryData->bIsAcceptable=false;
+ pEntryData->bDisabled=true;
+
+ bTheTestFlag=false;
+
+ if (rChangeAction.second->IsDialogParent())
+ Expand(pChanges, rChangeAction.second, *xEntry);
+ }
+ }
+ return bTheTestFlag;
+}
+
+bool ScAcceptChgDlg::Expand(const ScChangeTrack* pChanges, const ScChangeAction* pScChangeAction,
+ const weld::TreeIter& rEntry, bool bFilter)
+{
+ bool bTheTestFlag = true;
+
+ if (pChanges && pScChangeAction)
+ {
+ ScChangeActionMap aActionMap;
+
+ GetDependents(pScChangeAction, aActionMap, rEntry);
+
+ switch(pScChangeAction->GetType())
+ {
+ case SC_CAT_CONTENT:
+ {
+ InsertContentChildren(&aActionMap, rEntry);
+ bTheTestFlag=!bHasFilterEntry;
+ break;
+ }
+ case SC_CAT_DELETE_COLS:
+ case SC_CAT_DELETE_ROWS:
+ case SC_CAT_DELETE_TABS:
+ {
+ InsertDeletedChildren(pScChangeAction, &aActionMap, rEntry);
+ bTheTestFlag=!bHasFilterEntry;
+ break;
+ }
+ default:
+ {
+ if(!bFilter)
+ bTheTestFlag = InsertChildren(&aActionMap, rEntry);
+ break;
+ }
+ }
+ aActionMap.clear();
+ }
+ return bTheTestFlag;
+}
+
+IMPL_LINK(ScAcceptChgDlg, ExpandingHandle, const weld::TreeIter&, rEntry, bool)
+{
+ ScChangeTrack* pChanges=pDoc->GetChangeTrack();
+ if (pChanges)
+ {
+ m_xDialog->set_busy_cursor(true);
+ ScChangeActionMap aActionMap;
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rEntry));
+ if (!rTreeView.iter_has_child(rEntry))
+ {
+ bool bTheTestFlag = true;
+
+ if (pEntryData)
+ {
+ ScChangeAction* pScChangeAction=static_cast<ScChangeAction*>(pEntryData->pData);
+
+ GetDependents(pScChangeAction, aActionMap, rEntry);
+
+ switch (pScChangeAction->GetType())
+ {
+ case SC_CAT_CONTENT:
+ {
+ bTheTestFlag = InsertContentChildren( &aActionMap, rEntry );
+ break;
+ }
+ case SC_CAT_DELETE_COLS:
+ case SC_CAT_DELETE_ROWS:
+ case SC_CAT_DELETE_TABS:
+ {
+ bTheTestFlag = InsertDeletedChildren( pScChangeAction, &aActionMap, rEntry );
+ break;
+ }
+ default:
+ {
+ bTheTestFlag = InsertChildren( &aActionMap, rEntry );
+ break;
+ }
+ }
+ aActionMap.clear();
+
+ }
+ else
+ {
+ bTheTestFlag = InsertAcceptedORejected(rEntry);
+ }
+ if (bTheTestFlag)
+ {
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ rTreeView.insert(&rEntry, -1, &aStrNoEntry, nullptr, nullptr, nullptr, false, xEntry.get());
+ rTreeView.set_font_color(*xEntry, COL_GRAY);
+ }
+ }
+ m_xDialog->set_busy_cursor(false);
+ }
+ return true;
+}
+
+void ScAcceptChgDlg::AppendChanges(const ScChangeTrack* pChanges,sal_uLong nStartAction,
+ sal_uLong nEndAction)
+{
+ if(pChanges==nullptr)
+ return;
+
+ std::unique_ptr<weld::TreeIter> xParent;
+ m_xDialog->set_busy_cursor(true);
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ rTreeView.freeze();
+
+ bool bTheFlag = false;
+
+ bool bFilterFlag = pTPFilter->IsDate() || pTPFilter->IsRange() ||
+ pTPFilter->IsAuthor() || pTPFilter->IsComment();
+
+ bUseColor = bFilterFlag;
+
+ for(sal_uLong i=nStartAction;i<=nEndAction;i++)
+ {
+ const ScChangeAction* pScChangeAction=pChanges->GetAction(i);
+ if(pScChangeAction==nullptr) continue;
+
+ switch (pScChangeAction->GetState())
+ {
+ case SC_CAS_VIRGIN:
+
+ if (pScChangeAction->IsDialogRoot())
+ {
+ bool bOnDemandChildren = !bFilterFlag && pScChangeAction->IsDialogParent();
+ if (pScChangeAction->IsDialogParent())
+ xParent = AppendChangeAction(pScChangeAction, bOnDemandChildren);
+ else
+ xParent = AppendFilteredAction(pScChangeAction, SC_CAS_VIRGIN, bOnDemandChildren);
+ }
+ else
+ xParent.reset();
+
+ bTheFlag=true;
+ break;
+
+ case SC_CAS_ACCEPTED:
+ xParent.reset();
+ nAcceptCount++;
+ break;
+
+ case SC_CAS_REJECTED:
+ xParent.reset();
+ nRejectCount++;
+ break;
+ }
+
+ if (xParent && pScChangeAction->IsDialogParent() && bFilterFlag)
+ {
+ bool bTestFlag = bHasFilterEntry;
+ bHasFilterEntry = false;
+ if (Expand(pChanges,pScChangeAction,*xParent,!bTestFlag)&&!bTestFlag)
+ rTreeView.remove(*xParent);
+ }
+ }
+
+ if( bTheFlag && (!pDoc->IsDocEditable() || pChanges->IsProtected()) )
+ bTheFlag=false;
+
+ pTPView->EnableAccept(bTheFlag);
+ pTPView->EnableAcceptAll(bTheFlag);
+ pTPView->EnableReject(bTheFlag);
+ pTPView->EnableRejectAll(bTheFlag);
+
+ rTreeView.thaw();
+ m_xDialog->set_busy_cursor(false);
+}
+
+void ScAcceptChgDlg::RemoveEntries(sal_uLong nStartAction,sal_uLong nEndAction)
+{
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+
+ ScRedlinData *pEntryData=nullptr;
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ if (rTreeView.get_cursor(xEntry.get()))
+ pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry));
+
+ if (!rTreeView.get_iter_first(*xEntry))
+ return;
+
+ sal_uLong nAction=0;
+ if (pEntryData)
+ nAction=pEntryData->nActionNo;
+
+ if (nAction>=nStartAction && nAction<=nEndAction)
+ rTreeView.set_cursor(*xEntry);
+
+ std::vector<OUString> aIdsToRemove;
+
+ do
+ {
+ OUString sId(rTreeView.get_id(*xEntry));
+ pEntryData = weld::fromId<ScRedlinData*>(sId);
+ if (pEntryData)
+ {
+ nAction = pEntryData->nActionNo;
+ if (nStartAction <= nAction && nAction <= nEndAction)
+ {
+ aIdsToRemove.push_back(sId);
+ delete pEntryData;
+ }
+ }
+ }
+ while (rTreeView.iter_next(*xEntry));
+
+ rTreeView.freeze();
+
+ // MUST do it backwards, don't delete parents before children and GPF
+ for (auto it = aIdsToRemove.rbegin(); it != aIdsToRemove.rend(); ++it)
+ rTreeView.remove_id(*it);
+
+ rTreeView.thaw();
+}
+
+void ScAcceptChgDlg::UpdateEntries(const ScChangeTrack* pChgTrack, sal_uLong nStartAction,sal_uLong nEndAction)
+{
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ rTreeView.freeze();
+
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ std::unique_ptr<weld::TreeIter> xLastEntry(rTreeView.make_iterator());
+ std::unique_ptr<weld::TreeIter> xNextEntry(rTreeView.make_iterator());
+
+ bool bEntry = rTreeView.get_iter_first(*xEntry);
+ bool bLastEntry = false;
+
+ while (bEntry)
+ {
+ bool bRemove = false;
+ ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry));
+ if (pEntryData)
+ {
+ ScChangeAction* pScChangeAction=
+ static_cast<ScChangeAction*>(pEntryData->pData);
+
+ sal_uLong nAction=pScChangeAction->GetActionNumber();
+
+ if(nStartAction<=nAction && nAction<=nEndAction) bRemove=true;
+ }
+
+ bool bNextEntry;
+ if (bRemove)
+ {
+ rTreeView.remove(*xEntry);
+ delete pEntryData;
+
+ if (!bLastEntry)
+ bLastEntry = rTreeView.get_iter_first(*xLastEntry);
+ if (bLastEntry)
+ {
+ rTreeView.copy_iterator(*xLastEntry, *xNextEntry);
+ bNextEntry = rTreeView.iter_next(*xNextEntry);
+ if (!bNextEntry)
+ {
+ rTreeView.copy_iterator(*xLastEntry, *xNextEntry);
+ bLastEntry = false;
+ }
+ }
+ else
+ bNextEntry = false;
+ }
+ else
+ {
+ rTreeView.copy_iterator(*xEntry, *xLastEntry);
+ bLastEntry = true;
+
+ rTreeView.copy_iterator(*xEntry, *xNextEntry);
+ bNextEntry = rTreeView.iter_next(*xNextEntry);
+ }
+
+ rTreeView.copy_iterator(*xNextEntry, *xEntry);
+ bEntry = bNextEntry;
+ }
+
+ AppendChanges(pChgTrack,nStartAction,nEndAction);
+
+ rTreeView.thaw();
+}
+
+IMPL_LINK( ScAcceptChgDlg, ChgTrackModHdl, ScChangeTrack&, rChgTrack, void)
+{
+ ScChangeTrackMsgQueue& aMsgQueue= rChgTrack.GetMsgQueue();
+
+ sal_uLong nStartAction;
+ sal_uLong nEndAction;
+
+ for (const auto& rMsg : aMsgQueue)
+ {
+ nStartAction = rMsg.nStartAction;
+ nEndAction = rMsg.nEndAction;
+
+ if(!bIgnoreMsg)
+ {
+ bNoSelection=true;
+
+ switch(rMsg.eMsgType)
+ {
+ case ScChangeTrackMsgType::Append:
+ AppendChanges(&rChgTrack,nStartAction,nEndAction);
+ break;
+ case ScChangeTrackMsgType::Remove:
+ RemoveEntries(nStartAction,nEndAction);
+ break;
+ case ScChangeTrackMsgType::Parent:
+ case ScChangeTrackMsgType::Change: //bNeedsUpdate=true;
+ UpdateEntries(&rChgTrack,nStartAction,nEndAction);
+ break;
+ default: assert(false); break;
+ }
+ }
+ }
+
+ aMsgQueue.clear();
+}
+
+IMPL_LINK_NOARG(ScAcceptChgDlg, ReOpenTimerHdl, Timer *, void)
+{
+ ScSimpleRefDlgWrapper::SetAutoReOpen(true);
+ m_xAcceptChgCtr->ShowFilterPage();
+ RefHandle(nullptr);
+}
+
+IMPL_LINK_NOARG(ScAcceptChgDlg, UpdateSelectionHdl, Timer *, void)
+{
+ ScTabView* pTabView = pViewData->GetView();
+
+ bool bAcceptFlag = true;
+ bool bRejectFlag = true;
+
+ pTabView->DoneBlockMode(); // clears old marking
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ std::vector<const ScChangeAction*> aActions;
+ rTreeView.selected_foreach([&rTreeView, &bAcceptFlag, &bRejectFlag, &aActions](weld::TreeIter& rEntry){
+ ScRedlinData* pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rEntry));
+ if (pEntryData)
+ {
+ bRejectFlag &= pEntryData->bIsRejectable;
+ bAcceptFlag &= pEntryData->bIsAcceptable;
+
+ const ScChangeAction* pScChangeAction = static_cast<ScChangeAction*>(pEntryData->pData);
+ if( pScChangeAction && (pScChangeAction->GetType() != SC_CAT_DELETE_TABS) &&
+ (!pEntryData->bDisabled || pScChangeAction->IsVisible()) )
+ {
+ aActions.push_back(pScChangeAction);
+ }
+ }
+ else
+ {
+ bAcceptFlag = false;
+ bRejectFlag = false;
+ }
+ return false;
+ });
+
+ bool bContMark = false;
+ for (size_t i = 0, nCount = aActions.size(); i < nCount; ++i)
+ {
+ const ScBigRange& rBigRange = aActions[i]->GetBigRange();
+ if (rBigRange.IsValid(*pDoc) && m_xDialog->has_toplevel_focus())
+ {
+ bool bSetCursor = i == nCount - 1;
+ pTabView->MarkRange(rBigRange.MakeRange(*pDoc), bSetCursor, bContMark);
+ bContMark = true;
+ }
+ }
+
+ ScChangeTrack* pChanges = pDoc->GetChangeTrack();
+ bool bEnable = pDoc->IsDocEditable() && pChanges && !pChanges->IsProtected();
+ pTPView->EnableAccept( bAcceptFlag && bEnable );
+ pTPView->EnableReject( bRejectFlag && bEnable );
+}
+
+IMPL_LINK(ScAcceptChgDlg, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
+ return false;
+
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ bool bEntry = rTreeView.get_cursor(xEntry.get());
+ if (bEntry)
+ rTreeView.select(*xEntry);
+
+ int nSortedCol = rTreeView.get_sort_column();
+ for (sal_Int32 i = 0; i < 5; ++i)
+ m_xSortMenu->set_active("calcsort" + OString::number(i), i == nSortedCol);
+
+ m_xPopup->set_sensitive("calcedit", false);
+
+ if (pDoc->IsDocEditable() && bEntry)
+ {
+ ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry));
+ if (pEntryData)
+ {
+ ScChangeAction* pScChangeAction = static_cast<ScChangeAction*>(pEntryData->pData);
+ if (pScChangeAction && !rTreeView.get_iter_depth(*xEntry))
+ m_xPopup->set_sensitive("calcedit", true);
+ }
+ }
+
+ OString sCommand = m_xPopup->popup_at_rect(&rTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1)));
+
+ if (!sCommand.isEmpty())
+ {
+ if (sCommand == "calcedit")
+ {
+ if (bEntry)
+ {
+ ScRedlinData *pEntryData = weld::fromId<ScRedlinData*>(rTreeView.get_id(*xEntry));
+ if (pEntryData)
+ {
+ ScChangeAction* pScChangeAction = static_cast<ScChangeAction*>(pEntryData->pData);
+ pViewData->GetDocShell()->ExecuteChangeCommentDialog(pScChangeAction, m_xDialog.get(), false);
+ }
+ }
+ }
+ else
+ {
+ int nDialogCol = o3tl::toInt32(sCommand.subView(8));
+ pTheView->HeaderBarClick(nDialogCol);
+ }
+ }
+
+ return true;
+}
+
+namespace
+{
+ //at one point we were writing multiple AcceptChgDat strings,
+ //so strip all of them and keep the results of the last one
+ OUString lcl_StripAcceptChgDat(OUString &rExtraString)
+ {
+ OUString aStr;
+ while (true)
+ {
+ sal_Int32 nPos = rExtraString.indexOf("AcceptChgDat:");
+ if (nPos == -1)
+ break;
+ // Try to read the alignment string "ALIGN:(...)"; if it is missing
+ // we have an old version
+ sal_Int32 n1 = rExtraString.indexOf('(', nPos);
+ if ( n1 != -1 )
+ {
+ sal_Int32 n2 = rExtraString.indexOf(')', n1);
+ if ( n2 != -1 )
+ {
+ // cut out alignment string
+ aStr = rExtraString.copy(nPos, n2 - nPos + 1);
+ rExtraString = rExtraString.replaceAt(nPos, n2 - nPos + 1, u"");
+ aStr = aStr.copy( n1-nPos+1 );
+ }
+ }
+ }
+ return aStr;
+ }
+}
+
+void ScAcceptChgDlg::Initialize(SfxChildWinInfo* pInfo)
+{
+ OUString aStr;
+ if (pInfo && !pInfo->aExtraString.isEmpty())
+ aStr = lcl_StripAcceptChgDat(pInfo->aExtraString);
+
+ SfxModelessDialogController::Initialize(pInfo);
+
+ if (aStr.isEmpty())
+ return;
+
+ int nCount = aStr.toInt32();
+ if (nCount <= 2)
+ return;
+
+ std::vector<int> aEndPos;
+
+ for (int i = 0; i < nCount; ++i)
+ {
+ sal_Int32 n1 = aStr.indexOf(';');
+ aStr = aStr.copy( n1+1 );
+ aEndPos.push_back(aStr.toInt32());
+ }
+
+ std::vector<int> aWidths;
+ for (int i = 1; i < nCount; ++i)
+ aWidths.push_back(aEndPos[i] - aEndPos[i - 1]);
+
+ // turn column end points back to column widths, ignoring the small
+ // value used for the expander column
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ rTreeView.set_column_fixed_widths(aWidths);
+}
+
+void ScAcceptChgDlg::FillInfo(SfxChildWinInfo& rInfo) const
+{
+ SfxModelessDialogController::FillInfo(rInfo);
+ //remove any old one before adding a new one
+ lcl_StripAcceptChgDat(rInfo.aExtraString);
+ rInfo.aExtraString += "AcceptChgDat:(";
+
+ const int nTabCount = 5;
+
+ rInfo.aExtraString += OUString::number(nTabCount);
+ rInfo.aExtraString += ";";
+
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+ std::vector<int> aWidths;
+ // turn column widths back into column end points for compatibility
+ // with how they used to be stored, including a small value for the
+ // expander column
+ aWidths.push_back(rTreeView.get_checkbox_column_width());
+ for (int i = 0; i < nTabCount - 1; ++i)
+ aWidths.push_back(aWidths.back() + rTreeView.get_column_width(i));
+
+ for (auto a : aWidths)
+ {
+ rInfo.aExtraString += OUString::number(a);
+ rInfo.aExtraString += ";";
+ }
+ rInfo.aExtraString += ")";
+}
+
+#define CALC_DATE 3
+#define CALC_POS 1
+
+int ScAcceptChgDlg::ColCompareHdl(const weld::TreeIter& rLeft, const weld::TreeIter& rRight) const
+{
+ weld::TreeView& rTreeView = pTheView->GetWidget();
+
+ sal_Int32 nCompare = 0;
+ SCCOL nSortCol = rTreeView.get_sort_column();
+
+ if (CALC_DATE == nSortCol)
+ {
+ RedlinData *pLeftData = weld::fromId<RedlinData*>(rTreeView.get_id(rLeft));
+ RedlinData *pRightData = weld::fromId<RedlinData*>(rTreeView.get_id(rRight));
+ if (pLeftData && pRightData)
+ {
+ if(pLeftData->aDateTime < pRightData->aDateTime)
+ nCompare = -1;
+ else if(pLeftData->aDateTime > pRightData->aDateTime)
+ nCompare = 1;
+ return nCompare;
+ }
+ }
+ else if (CALC_POS == nSortCol)
+ {
+ ScRedlinData *pLeftData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rLeft));
+ ScRedlinData *pRightData = weld::fromId<ScRedlinData*>(rTreeView.get_id(rRight));
+ if (pLeftData && pRightData)
+ {
+ nCompare = 1;
+
+ if(pLeftData->nTable < pRightData->nTable)
+ nCompare = -1;
+ else if(pLeftData->nTable == pRightData->nTable)
+ {
+ if(pLeftData->nRow < pRightData->nRow)
+ nCompare = -1;
+ else if(pLeftData->nRow == pRightData->nRow)
+ {
+ if(pLeftData->nCol < pRightData->nCol)
+ nCompare = -1;
+ else if(pLeftData->nCol == pRightData->nCol)
+ nCompare = 0;
+ }
+ }
+
+ return nCompare;
+ }
+ }
+
+ return ScGlobal::GetCaseCollator().compareString(rTreeView.get_text(rLeft, nSortCol),
+ rTreeView.get_text(rRight, nSortCol));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/anyrefdg.cxx b/sc/source/ui/miscdlgs/anyrefdg.cxx
new file mode 100644
index 000000000..0ffad93cf
--- /dev/null
+++ b/sc/source/ui/miscdlgs/anyrefdg.cxx
@@ -0,0 +1,784 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rangelst.hxx>
+#include <comphelper/string.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+
+#include <anyrefdg.hxx>
+#include <sc.hrc>
+#include <inputhdl.hxx>
+#include <scmod.hxx>
+#include <inputwin.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <rfindlst.hxx>
+#include <compiler.hxx>
+#include <inputopt.hxx>
+#include <rangeutl.hxx>
+#include <tokenarray.hxx>
+#include <comphelper/lok.hxx>
+#include <output.hxx>
+
+#include <memory>
+
+ScFormulaReferenceHelper::ScFormulaReferenceHelper(IAnyRefDialog* _pDlg,SfxBindings* _pBindings)
+ : m_pDlg(_pDlg)
+ , m_pRefEdit (nullptr)
+ , m_pRefBtn (nullptr)
+ , m_pDialog(nullptr)
+ , m_pBindings(_pBindings)
+ , m_nRefTab(0)
+ , m_bHighlightRef(false)
+{
+ ScInputOptions aInputOption=SC_MOD()->GetInputOptions();
+ m_bEnableColorRef=aInputOption.GetRangeFinder();
+}
+
+ScFormulaReferenceHelper::~ScFormulaReferenceHelper() COVERITY_NOEXCEPT_FALSE
+{
+ dispose();
+}
+
+void ScFormulaReferenceHelper::dispose()
+{
+ // common cleanup for ScAnyRefDlg and ScFormulaDlg is done here
+ HideReference();
+ enableInput( true );
+
+ ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
+ if ( pInputHdl )
+ pInputHdl->ResetDelayTimer(); // stop the timer for disabling the input line
+
+ m_pDialog = nullptr;
+}
+
+void ScFormulaReferenceHelper::enableInput( bool bEnable )
+{
+ ScDocShell* pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(checkSfxObjectShell<ScDocShell>));
+ while( pDocShell )
+ {
+ SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell );
+ while( pFrame )
+ {
+ // enable everything except InPlace, including bean frames
+ if ( !pFrame->GetFrame().IsInPlace() )
+ {
+ SfxViewShell* p = pFrame->GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p );
+ if(pViewSh!=nullptr)
+ {
+ vcl::Window *pWin=pViewSh->GetWindow();
+ if(pWin)
+ {
+ vcl::Window *pParent=pWin->GetParent();
+ if(pParent)
+ {
+ pParent->EnableInput(bEnable);
+ pViewSh->EnableRefInput(bEnable);
+ }
+ }
+ }
+ }
+ pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell );
+ }
+
+ pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pDocShell, checkSfxObjectShell<ScDocShell>));
+ }
+}
+
+void ScFormulaReferenceHelper::ShowSimpleReference(std::u16string_view rStr)
+{
+ if (!m_bEnableColorRef)
+ return;
+
+ m_bHighlightRef = true;
+ ScViewData* pViewData=ScDocShell::GetViewData();
+ if ( !pViewData )
+ return;
+
+ ScDocument& rDoc = pViewData->GetDocument();
+ ScTabViewShell* pTabViewShell=pViewData->GetViewShell();
+
+ ScRangeList aRangeList;
+
+ pTabViewShell->DoneRefMode();
+ pTabViewShell->ClearHighlightRanges();
+
+ if( ParseWithNames( aRangeList, rStr, rDoc ) )
+ {
+ for ( size_t i = 0, nRanges = aRangeList.size(); i < nRanges; ++i )
+ {
+ ScRange const & rRangeEntry = aRangeList[ i ];
+ Color aColName = ScRangeFindList::GetColorName( i );
+ pTabViewShell->AddHighlightRange( rRangeEntry, aColName );
+ }
+ }
+}
+
+bool ScFormulaReferenceHelper::ParseWithNames( ScRangeList& rRanges, std::u16string_view rStr, const ScDocument& rDoc )
+{
+ rRanges.RemoveAll();
+
+ if (rStr.empty())
+ return true;
+
+ ScAddress::Details aDetails(rDoc.GetAddressConvention(), 0, 0);
+
+ bool bError = false;
+ sal_Int32 nIdx {0};
+ do
+ {
+ ScRange aRange;
+ OUString aRangeStr( o3tl::getToken(rStr, 0, ';', nIdx ) );
+
+ ScRefFlags nFlags = aRange.ParseAny( aRangeStr, rDoc, aDetails );
+ if ( nFlags & ScRefFlags::VALID )
+ {
+ if ( (nFlags & ScRefFlags::TAB_3D) == ScRefFlags::ZERO )
+ aRange.aStart.SetTab( m_nRefTab );
+ if ( (nFlags & ScRefFlags::TAB2_3D) == ScRefFlags::ZERO )
+ aRange.aEnd.SetTab( aRange.aStart.Tab() );
+ rRanges.push_back( aRange );
+ }
+ else if ( ScRangeUtil::MakeRangeFromName( aRangeStr, rDoc, m_nRefTab, aRange, RUTL_NAMES, aDetails ) )
+ rRanges.push_back( aRange );
+ else
+ bError = true;
+ }
+ while (nIdx>0);
+
+ return !bError;
+}
+
+void ScFormulaReferenceHelper::ShowFormulaReference(const OUString& rStr)
+{
+ if( !m_bEnableColorRef)
+ return;
+
+ m_bHighlightRef=true;
+ ScViewData* pViewData=ScDocShell::GetViewData();
+ if ( !(pViewData && m_pRefComp) )
+ return;
+
+ ScTabViewShell* pTabViewShell=pViewData->GetViewShell();
+ SCCOL nCol = pViewData->GetCurX();
+ SCROW nRow = pViewData->GetCurY();
+ SCTAB nTab = pViewData->GetTabNo();
+ ScAddress aPos( nCol, nRow, nTab );
+
+ std::unique_ptr<ScTokenArray> pScTokA(m_pRefComp->CompileString(rStr));
+
+ if (!(pTabViewShell && pScTokA))
+ return;
+
+ const ScViewData& rViewData = pTabViewShell->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ pTabViewShell->DoneRefMode();
+ pTabViewShell->ClearHighlightRanges();
+
+ formula::FormulaTokenArrayPlainIterator aIter(*pScTokA);
+ const formula::FormulaToken* pToken = aIter.GetNextReference();
+
+ sal_uInt16 nIndex=0;
+
+ while(pToken!=nullptr)
+ {
+ bool bDoubleRef=(pToken->GetType()==formula::svDoubleRef);
+
+ if(pToken->GetType()==formula::svSingleRef || bDoubleRef)
+ {
+ ScRange aRange;
+ if(bDoubleRef)
+ {
+ ScComplexRefData aRef( *pToken->GetDoubleRef() );
+ aRange = aRef.toAbs(rDoc, aPos);
+ }
+ else
+ {
+ ScSingleRefData aRef( *pToken->GetSingleRef() );
+ aRange.aStart = aRef.toAbs(rDoc, aPos);
+ aRange.aEnd = aRange.aStart;
+ }
+ Color aColName=ScRangeFindList::GetColorName(nIndex++);
+ pTabViewShell->AddHighlightRange(aRange, aColName);
+ }
+
+ pToken = aIter.GetNextReference();
+ }
+}
+
+void ScFormulaReferenceHelper::HideReference( bool bDoneRefMode )
+{
+ ScViewData* pViewData=ScDocShell::GetViewData();
+
+ if( !(pViewData && m_bHighlightRef && m_bEnableColorRef))
+ return;
+
+ ScTabViewShell* pTabViewShell=pViewData->GetViewShell();
+
+ if(pTabViewShell!=nullptr)
+ {
+ // bDoneRefMode is sal_False when called from before SetReference.
+ // In that case, RefMode was just started and must not be ended now.
+
+ if ( bDoneRefMode )
+ pTabViewShell->DoneRefMode();
+ pTabViewShell->ClearHighlightRanges();
+
+ if( comphelper::LibreOfficeKit::isActive() )
+ {
+ // Clear
+ std::vector<ReferenceMark> aReferenceMarks;
+ ScInputHandler::SendReferenceMarks( pTabViewShell, aReferenceMarks );
+ }
+ }
+ m_bHighlightRef=false;
+}
+
+void ScFormulaReferenceHelper::ShowReference(const OUString& rStr)
+{
+ if( !m_bEnableColorRef )
+ return;
+
+ if( rStr.indexOf('(') != -1 ||
+ rStr.indexOf('+') != -1 ||
+ rStr.indexOf('*') != -1 ||
+ rStr.indexOf('-') != -1 ||
+ rStr.indexOf('/') != -1 ||
+ rStr.indexOf('&') != -1 ||
+ rStr.indexOf('<') != -1 ||
+ rStr.indexOf('>') != -1 ||
+ rStr.indexOf('=') != -1 ||
+ rStr.indexOf('^') != -1 )
+ {
+ ShowFormulaReference(rStr);
+ }
+ else
+ {
+ ShowSimpleReference(rStr);
+ }
+}
+
+void ScFormulaReferenceHelper::ReleaseFocus( formula::RefEdit* pEdit )
+{
+ if( !m_pRefEdit && pEdit )
+ {
+ m_pDlg->RefInputStart( pEdit );
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if( !pViewShell )
+ return;
+
+ pViewShell->ActiveGrabFocus();
+ if( !m_pRefEdit )
+ return;
+
+ const ScViewData& rViewData = pViewShell->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScRangeList aRangeList;
+ if( !ParseWithNames( aRangeList, m_pRefEdit->GetText(), rDoc ) )
+ return;
+
+ if ( !aRangeList.empty() )
+ {
+ const ScRange & rRange = aRangeList.front();
+ pViewShell->SetTabNo( rRange.aStart.Tab() );
+ pViewShell->MoveCursorAbs( rRange.aStart.Col(),
+ rRange.aStart.Row(), SC_FOLLOW_JUMP, false, false );
+ pViewShell->MoveCursorAbs( rRange.aEnd.Col(),
+ rRange.aEnd.Row(), SC_FOLLOW_JUMP, true, false );
+ m_pDlg->SetReference( rRange, rDoc );
+ }
+}
+
+void ScFormulaReferenceHelper::Init()
+{
+ ScViewData* pViewData=ScDocShell::GetViewData(); //! use pScViewShell?
+ if ( !pViewData )
+ return;
+
+ ScDocument& rDoc = pViewData->GetDocument();
+ SCCOL nCol = pViewData->GetCurX();
+ SCROW nRow = pViewData->GetCurY();
+ SCTAB nTab = pViewData->GetTabNo();
+ ScAddress aCursorPos( nCol, nRow, nTab );
+
+ m_pRefComp.reset( new ScCompiler( rDoc, aCursorPos, rDoc.GetGrammar()) );
+ m_pRefComp->EnableJumpCommandReorder(false);
+ m_pRefComp->EnableStopOnError(false);
+
+ m_nRefTab = nTab;
+}
+
+IMPL_LINK_NOARG(ScFormulaReferenceHelper, ActivateHdl, weld::Widget&, bool)
+{
+ if (m_pRefEdit)
+ m_pRefEdit->GrabFocus();
+ m_pDlg->RefInputDone(true);
+ return true;
+}
+
+void ScFormulaReferenceHelper::RefInputDone( bool bForced )
+{
+ if ( !CanInputDone( bForced ) )
+ return;
+
+ if (!m_pDialog)
+ return;
+
+ // Adjust window title
+ m_pDialog->set_title(m_sOldDialogText);
+
+ if (m_pRefEdit)
+ m_pRefEdit->SetActivateHdl(Link<weld::Widget&, bool>());
+
+ // set button image
+ if (m_pRefBtn)
+ {
+ m_pRefBtn->SetActivateHdl(Link<weld::Widget&, bool>());
+ m_pRefBtn->SetStartImage();
+ }
+
+ m_pDialog->undo_collapse();
+
+ m_pRefEdit = nullptr;
+ m_pRefBtn = nullptr;
+}
+
+void ScFormulaReferenceHelper::RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton )
+{
+ if (m_pRefEdit)
+ return;
+
+ m_pRefEdit = pEdit;
+ m_pRefBtn = pButton;
+
+ // Save and adjust window title
+ m_sOldDialogText = m_pDialog->get_title();
+ if (weld::Label *pLabel = m_pRefEdit->GetLabelWidgetForShrinkMode())
+ {
+ const OUString sLabel = pLabel->get_label();
+ if (!sLabel.isEmpty())
+ {
+ const OUString sNewDialogText = m_sOldDialogText + ": " + comphelper::string::stripEnd(sLabel, ':');
+ m_pDialog->set_title(pLabel->strip_mnemonic(sNewDialogText));
+ }
+ }
+
+ m_pDialog->collapse(pEdit->GetWidget(), pButton ? pButton->GetWidget() : nullptr);
+
+ // set button image
+ if (pButton)
+ pButton->SetEndImage();
+
+ m_pRefEdit->SetActivateHdl(LINK(this, ScFormulaReferenceHelper, ActivateHdl));
+ if (m_pRefBtn)
+ m_pRefBtn->SetActivateHdl(LINK(this, ScFormulaReferenceHelper, ActivateHdl));
+}
+
+void ScFormulaReferenceHelper::ToggleCollapsed( formula::RefEdit* pEdit, formula::RefButton* pButton )
+{
+ if( !pEdit )
+ return;
+
+ if( m_pRefEdit == pEdit ) // is this the active ref edit field?
+ {
+ m_pRefEdit->GrabFocus(); // before RefInputDone()
+ m_pDlg->RefInputDone( true ); // finish ref input
+ }
+ else
+ {
+ m_pDlg->RefInputDone( true ); // another active ref edit?
+ m_pDlg->RefInputStart( pEdit, pButton ); // start ref input
+ // pRefEdit might differ from pEdit after RefInputStart() (i.e. ScFormulaDlg)
+ if( m_pRefEdit )
+ m_pRefEdit->GrabFocus();
+ }
+}
+
+void ScFormulaReferenceHelper::DoClose( sal_uInt16 nId )
+{
+ SfxApplication* pSfxApp = SfxGetpApp();
+
+ SetDispatcherLock( false ); //! here and in dtor ?
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if ( pViewFrm && pViewFrm->HasChildWindow(FID_INPUTLINE_STATUS) )
+ {
+ // The input row is disabled with ToolBox::Disable disabled, thus it must be
+ // reenabled with ToolBox::Enable (before the AppWindow is enabled)
+ // for the buttons to be drawn as enabled.
+ SfxChildWindow* pChild = pViewFrm->GetChildWindow(FID_INPUTLINE_STATUS);
+ if (pChild)
+ {
+ ScInputWindow* pWin = static_cast<ScInputWindow*>(pChild->GetWindow());
+ pWin->Enable();
+ }
+ }
+
+ // find parent view frame to close dialog
+ SfxViewFrame* pMyViewFrm = nullptr;
+ if ( m_pBindings )
+ {
+ SfxDispatcher* pMyDisp = m_pBindings->GetDispatcher();
+ if (pMyDisp)
+ pMyViewFrm = pMyDisp->GetFrame();
+ }
+ SC_MOD()->SetRefDialog( nId, false, pMyViewFrm );
+
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
+
+ ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( pScViewShell )
+ pScViewShell->UpdateInputHandler(true);
+}
+
+void ScFormulaReferenceHelper::SetDispatcherLock( bool bLock )
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ // lock / unlock only the dispatchers of Calc documents
+ ScDocShell* pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(checkSfxObjectShell<ScDocShell>));
+ while (pDocShell)
+ {
+ SfxViewFrame* pFrame = SfxViewFrame::GetFirst(pDocShell);
+ while (pFrame)
+ {
+ SfxDispatcher* pDisp = pFrame->GetDispatcher();
+ if (pDisp)
+ pDisp->Lock(bLock);
+ pFrame = SfxViewFrame::GetNext(*pFrame, pDocShell);
+ }
+ pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pDocShell, checkSfxObjectShell<ScDocShell>));
+ }
+ return;
+ // if a new view is created while the dialog is open,
+ // that view's dispatcher is locked when trying to create the dialog
+ // for that view (ScTabViewShell::CreateRefDialog)
+ }
+
+ // lock / unlock only the dispatcher of Calc document
+ SfxDispatcher* pDisp = nullptr;
+ if ( m_pBindings )
+ {
+ pDisp = m_pBindings->GetDispatcher();
+ }
+ else if(SfxViewFrame* pViewFrame = SfxViewFrame::Current())
+ {
+ if (dynamic_cast< ScTabViewShell* >(pViewFrame->GetViewShell()))
+ pDisp = pViewFrame->GetDispatcher();
+ }
+
+ if (pDisp)
+ pDisp->Lock(bLock);
+}
+
+void ScFormulaReferenceHelper::ViewShellChanged()
+{
+ enableInput( false );
+
+ EnableSpreadsheets();
+}
+void ScFormulaReferenceHelper::EnableSpreadsheets(bool bFlag)
+{
+ ScDocShell* pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(checkSfxObjectShell<ScDocShell>));
+ while( pDocShell )
+ {
+ SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell );
+ while( pFrame )
+ {
+ // enable everything except InPlace, including bean frames
+ if ( !pFrame->GetFrame().IsInPlace() )
+ {
+ SfxViewShell* p = pFrame->GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p );
+ if(pViewSh!=nullptr)
+ {
+ vcl::Window *pWin=pViewSh->GetWindow();
+ if(pWin)
+ {
+ vcl::Window *pParent=pWin->GetParent();
+ if(pParent)
+ {
+ pParent->EnableInput(bFlag,false);
+ pViewSh->EnableRefInput(bFlag);
+ }
+ }
+ }
+ }
+ pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell );
+ }
+
+ pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pDocShell, checkSfxObjectShell<ScDocShell>));
+ }
+}
+
+static void lcl_InvalidateWindows()
+{
+ ScDocShell* pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetFirst(checkSfxObjectShell<ScDocShell>));
+ while( pDocShell )
+ {
+ SfxViewFrame* pFrame = SfxViewFrame::GetFirst( pDocShell );
+ while( pFrame )
+ {
+ // enable everything except InPlace, including bean frames
+ if ( !pFrame->GetFrame().IsInPlace() )
+ {
+ SfxViewShell* p = pFrame->GetViewShell();
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( p );
+ if(pViewSh!=nullptr)
+ {
+ vcl::Window *pWin=pViewSh->GetWindow();
+ if(pWin)
+ {
+ vcl::Window *pParent=pWin->GetParent();
+ if(pParent)
+ pParent->Invalidate();
+ }
+ }
+ }
+ pFrame = SfxViewFrame::GetNext( *pFrame, pDocShell );
+ }
+
+ pDocShell = static_cast<ScDocShell*>(SfxObjectShell::GetNext(*pDocShell, checkSfxObjectShell<ScDocShell>));
+ }
+}
+
+static void lcl_HideAllReferences()
+{
+ SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
+ while ( pSh )
+ {
+ static_cast<ScTabViewShell*>(pSh)->ClearHighlightRanges();
+ pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
+ }
+}
+
+ScRefHandler::ScRefHandler(SfxDialogController& rController, SfxBindings* pB, bool bBindRef)
+ : m_pController(&rController)
+ , m_bInRefMode(false)
+ , m_aHelper(this, pB)
+ , m_pMyBindings(pB)
+{
+ m_aHelper.SetDialog(rController.getDialog());
+
+ if( bBindRef ) EnterRefMode();
+}
+
+bool ScRefHandler::EnterRefMode()
+{
+ if( m_bInRefMode ) return false;
+
+ SC_MOD()->InputEnterHandler();
+
+ ScTabViewShell* pScViewShell = nullptr;
+
+ // title has to be from the view that opened the dialog,
+ // even if it's not the current view
+
+ SfxObjectShell* pParentDoc = nullptr;
+ if ( m_pMyBindings )
+ {
+ SfxDispatcher* pMyDisp = m_pMyBindings->GetDispatcher();
+ if (pMyDisp)
+ {
+ SfxViewFrame* pMyViewFrm = pMyDisp->GetFrame();
+ if (pMyViewFrm)
+ {
+ pScViewShell = dynamic_cast<ScTabViewShell*>( pMyViewFrm->GetViewShell() );
+ if( pScViewShell )
+ pScViewShell->UpdateInputHandler(true);
+ pParentDoc = pMyViewFrm->GetObjectShell();
+ }
+ }
+ }
+ if ( !pParentDoc && pScViewShell ) // use current only if above fails
+ pParentDoc = pScViewShell->GetObjectShell();
+ if ( pParentDoc )
+ m_aDocName = pParentDoc->GetTitle();
+
+ ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl(pScViewShell);
+
+ OSL_ENSURE( pInputHdl, "Missing input handler :-/" );
+
+ if ( pInputHdl )
+ pInputHdl->NotifyChange( nullptr );
+
+ ScFormulaReferenceHelper::enableInput( false );
+
+ ScFormulaReferenceHelper::EnableSpreadsheets();
+
+ m_aHelper.Init();
+
+ m_aHelper.SetDispatcherLock( true );
+
+ m_bInRefMode = true;
+ return m_bInRefMode;
+}
+
+ScRefHandler::~ScRefHandler() COVERITY_NOEXCEPT_FALSE
+{
+ disposeRefHandler();
+}
+
+void ScRefHandler::disposeRefHandler()
+{
+ m_pController = nullptr;
+ LeaveRefMode();
+ m_aHelper.dispose();
+}
+
+bool ScRefHandler::LeaveRefMode()
+{
+ if( !m_bInRefMode ) return false;
+
+ lcl_HideAllReferences();
+
+ SetDispatcherLock( false ); //! here and in DoClose ?
+
+ ScTabViewShell* pScViewShell = ScTabViewShell::GetActiveViewShell();
+ if( pScViewShell )
+ pScViewShell->UpdateInputHandler(true);
+
+ lcl_InvalidateWindows();
+
+ m_bInRefMode = false;
+ return true;
+}
+
+void ScRefHandler::SwitchToDocument()
+{
+ ScTabViewShell* pCurrent = ScTabViewShell::GetActiveViewShell();
+ if (pCurrent)
+ {
+ SfxObjectShell* pObjSh = pCurrent->GetObjectShell();
+ if ( pObjSh && pObjSh->GetTitle() == m_aDocName )
+ {
+ // right document already visible -> nothing to do
+ return;
+ }
+ }
+
+ SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
+ while ( pSh )
+ {
+ SfxObjectShell* pObjSh = pSh->GetObjectShell();
+ if ( pObjSh && pObjSh->GetTitle() == m_aDocName )
+ {
+ // switch to first TabViewShell for document
+ static_cast<ScTabViewShell*>(pSh)->SetActive();
+ return;
+ }
+ pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
+ }
+}
+
+bool ScRefHandler::IsDocAllowed(SfxObjectShell* pDocSh) const // pDocSh may be 0
+{
+ // if aDocName isn't initialized, allow
+ if ( m_aDocName.isEmpty() )
+ return true;
+
+ if ( !pDocSh )
+ return false;
+
+ // default: allow only same document (overridden in function dialog)
+ return m_aDocName==pDocSh->GetTitle();
+}
+
+bool ScRefHandler::IsRefInputMode() const
+{
+ return m_pController->getDialog()->get_visible();
+}
+
+bool ScRefHandler::DoClose( sal_uInt16 nId )
+{
+ m_aHelper.DoClose(nId);
+ return true;
+}
+
+void ScRefHandler::SetDispatcherLock( bool bLock )
+{
+ m_aHelper.SetDispatcherLock( bLock );
+}
+
+void ScRefHandler::ViewShellChanged()
+{
+ ScFormulaReferenceHelper::ViewShellChanged();
+}
+
+void ScRefHandler::AddRefEntry()
+{
+ // override this for multi-references
+}
+
+bool ScRefHandler::IsTableLocked() const
+{
+ // the default is that the sheet can be switched during while the reference is edited
+
+ return false;
+}
+
+// RefInputStart/Done: Zoom-In (AutoHide) on single field
+// (using button or movement)
+
+void ScRefHandler::RefInputStart( formula::RefEdit* pEdit, formula::RefButton* pButton )
+{
+ m_aHelper.RefInputStart( pEdit, pButton );
+}
+
+void ScRefHandler::ToggleCollapsed( formula::RefEdit* pEdit, formula::RefButton* pButton )
+{
+ m_aHelper.ToggleCollapsed( pEdit, pButton );
+}
+
+bool ScRefHandler::ParseWithNames( ScRangeList& rRanges, std::u16string_view rStr, const ScDocument& rDoc )
+{
+ return m_aHelper.ParseWithNames( rRanges, rStr, rDoc );
+}
+
+void ScRefHandler::HideReference( bool bDoneRefMode )
+{
+ m_aHelper.HideReference( bDoneRefMode );
+}
+
+void ScRefHandler::ShowReference(const OUString& rStr)
+{
+ m_aHelper.ShowReference(rStr);
+}
+
+void ScRefHandler::ReleaseFocus( formula::RefEdit* pEdit )
+{
+ m_aHelper.ReleaseFocus( pEdit );
+}
+
+void ScRefHandler::RefInputDone( bool bForced )
+{
+ m_aHelper.RefInputDone( bForced );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/autofmt.cxx b/sc/source/ui/miscdlgs/autofmt.cxx
new file mode 100644
index 000000000..877c412a5
--- /dev/null
+++ b/sc/source/ui/miscdlgs/autofmt.cxx
@@ -0,0 +1,531 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <editeng/lineitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <osl/diagnose.h>
+#include <svl/numformat.hxx>
+#include <svtools/scriptedtext.hxx>
+#include <svx/framelink.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/virdev.hxx>
+#include <comphelper/processfactory.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+
+#include <strings.hrc>
+#include <zforauto.hxx>
+#include <global.hxx>
+#include <autoform.hxx>
+#include <autofmt.hxx>
+#include <scresid.hxx>
+#include <document.hxx>
+#include <viewdata.hxx>
+#include <svtools/colorcfg.hxx>
+#include <scmod.hxx>
+
+#define FRAME_OFFSET 4
+
+// ScAutoFmtPreview
+
+ScAutoFmtPreview::ScAutoFmtPreview()
+ : pCurData(nullptr)
+ , bFitWidth(false)
+ , mbRTL(false)
+ , aStrJan(ScResId(STR_JAN))
+ , aStrFeb(ScResId(STR_FEB))
+ , aStrMar(ScResId(STR_MAR))
+ , aStrNorth(ScResId(STR_NORTH))
+ , aStrMid(ScResId(STR_MID))
+ , aStrSouth(ScResId(STR_SOUTH))
+ , aStrSum(ScResId(STR_SUM))
+ , pNumFmt(new SvNumberFormatter(::comphelper::getProcessComponentContext(), ScGlobal::eLnge))
+{
+ Init();
+}
+
+void ScAutoFmtPreview::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ aVD.disposeAndReset(VclPtr<VirtualDevice>::Create(pDrawingArea->get_ref_device()));
+ CustomWidgetController::SetDrawingArea(pDrawingArea);
+}
+
+void ScAutoFmtPreview::Resize()
+{
+ Size aSize(GetOutputSizePixel());
+ aPrvSize = Size(aSize.Width() - 6, aSize.Height() - 30);
+ mnLabelColWidth = (aPrvSize.Width() - 4) / 4 - 12;
+ mnDataColWidth1 = (aPrvSize.Width() - 4 - 2 * mnLabelColWidth) / 3;
+ mnDataColWidth2 = (aPrvSize.Width() - 4 - 2 * mnLabelColWidth) / 4;
+ mnRowHeight = (aPrvSize.Height() - 4) / 5;
+ NotifyChange(pCurData);
+}
+
+ScAutoFmtPreview::~ScAutoFmtPreview()
+{
+}
+
+static void lcl_SetFontProperties(
+ vcl::Font& rFont,
+ const SvxFontItem& rFontItem,
+ const SvxWeightItem& rWeightItem,
+ const SvxPostureItem& rPostureItem )
+{
+ rFont.SetFamily ( rFontItem.GetFamily() );
+ rFont.SetFamilyName ( rFontItem.GetFamilyName() );
+ rFont.SetStyleName ( rFontItem.GetStyleName() );
+ rFont.SetCharSet ( rFontItem.GetCharSet() );
+ rFont.SetPitch ( rFontItem.GetPitch() );
+ rFont.SetWeight ( rWeightItem.GetValue() );
+ rFont.SetItalic ( rPostureItem.GetValue() );
+}
+
+void ScAutoFmtPreview::MakeFonts(vcl::RenderContext const& rRenderContext, sal_uInt16 nIndex, vcl::Font& rFont, vcl::Font& rCJKFont, vcl::Font& rCTLFont)
+{
+ if ( !pCurData )
+ return;
+
+ rFont = rCJKFont = rCTLFont = rRenderContext.GetFont();
+ Size aFontSize(rFont.GetFontSize().Width(), 10 * rRenderContext.GetDPIScaleFactor());
+
+ const SvxFontItem* pFontItem = pCurData->GetItem( nIndex, ATTR_FONT );
+ const SvxWeightItem* pWeightItem = pCurData->GetItem( nIndex, ATTR_FONT_WEIGHT );
+ const SvxPostureItem* pPostureItem = pCurData->GetItem( nIndex, ATTR_FONT_POSTURE );
+ const SvxFontItem* pCJKFontItem = pCurData->GetItem( nIndex, ATTR_CJK_FONT );
+ const SvxWeightItem* pCJKWeightItem = pCurData->GetItem( nIndex, ATTR_CJK_FONT_WEIGHT );
+ const SvxPostureItem* pCJKPostureItem = pCurData->GetItem( nIndex, ATTR_CJK_FONT_POSTURE );
+ const SvxFontItem* pCTLFontItem = pCurData->GetItem( nIndex, ATTR_CTL_FONT );
+ const SvxWeightItem* pCTLWeightItem = pCurData->GetItem( nIndex, ATTR_CTL_FONT_WEIGHT );
+ const SvxPostureItem* pCTLPostureItem = pCurData->GetItem( nIndex, ATTR_CTL_FONT_POSTURE );
+ const SvxUnderlineItem* pUnderlineItem = pCurData->GetItem( nIndex, ATTR_FONT_UNDERLINE );
+ const SvxOverlineItem* pOverlineItem = pCurData->GetItem( nIndex, ATTR_FONT_OVERLINE );
+ const SvxCrossedOutItem* pCrossedOutItem = pCurData->GetItem( nIndex, ATTR_FONT_CROSSEDOUT );
+ const SvxContourItem* pContourItem = pCurData->GetItem( nIndex, ATTR_FONT_CONTOUR );
+ const SvxShadowedItem* pShadowedItem = pCurData->GetItem( nIndex, ATTR_FONT_SHADOWED );
+ const SvxColorItem* pColorItem = pCurData->GetItem( nIndex, ATTR_FONT_COLOR );
+
+ lcl_SetFontProperties( rFont, *pFontItem, *pWeightItem, *pPostureItem );
+ lcl_SetFontProperties( rCJKFont, *pCJKFontItem, *pCJKWeightItem, *pCJKPostureItem );
+ lcl_SetFontProperties( rCTLFont, *pCTLFontItem, *pCTLWeightItem, *pCTLPostureItem );
+
+ Color aColor( pColorItem->GetValue() );
+ if( aColor == COL_TRANSPARENT )
+ aColor = Application::GetSettings().GetStyleSettings().GetWindowTextColor();
+
+#define SETONALLFONTS( MethodName, Value ) \
+rFont.MethodName( Value ); rCJKFont.MethodName( Value ); rCTLFont.MethodName( Value );
+
+ SETONALLFONTS( SetUnderline, pUnderlineItem->GetValue() )
+ SETONALLFONTS( SetOverline, pOverlineItem->GetValue() )
+ SETONALLFONTS( SetStrikeout, pCrossedOutItem->GetValue() )
+ SETONALLFONTS( SetOutline, pContourItem->GetValue() )
+ SETONALLFONTS( SetShadow, pShadowedItem->GetValue() )
+ SETONALLFONTS( SetColor, aColor )
+ SETONALLFONTS( SetFontSize, aFontSize )
+ SETONALLFONTS( SetTransparent, true )
+
+#undef SETONALLFONTS
+}
+
+sal_uInt16 ScAutoFmtPreview::GetFormatIndex( size_t nCol, size_t nRow ) const
+{
+ static const sal_uInt16 pnFmtMap[] =
+ {
+ 0, 1, 2, 1, 3,
+ 4, 5, 6, 5, 7,
+ 8, 9, 10, 9, 11,
+ 4, 5, 6, 5, 7,
+ 12, 13, 14, 13, 15
+ };
+ return pnFmtMap[ maArray.GetCellIndex( nCol, nRow, mbRTL ) ];
+}
+
+const SvxBoxItem& ScAutoFmtPreview::GetBoxItem( size_t nCol, size_t nRow ) const
+{
+ OSL_ENSURE( pCurData, "ScAutoFmtPreview::GetBoxItem - no format data found" );
+ return * pCurData->GetItem( GetFormatIndex( nCol, nRow ), ATTR_BORDER );
+}
+
+const SvxLineItem& ScAutoFmtPreview::GetDiagItem( size_t nCol, size_t nRow, bool bTLBR ) const
+{
+ OSL_ENSURE( pCurData, "ScAutoFmtPreview::GetDiagItem - no format data found" );
+ return * pCurData->GetItem( GetFormatIndex( nCol, nRow ), bTLBR ? ATTR_BORDER_TLBR : ATTR_BORDER_BLTR );
+}
+
+void ScAutoFmtPreview::DrawString(vcl::RenderContext& rRenderContext, size_t nCol, size_t nRow)
+{
+ if (!pCurData)
+ {
+ return;
+ }
+
+ // Emit the cell text
+
+ OUString cellString;
+ bool bNumFormat = pCurData->GetIncludeValueFormat();
+ sal_uInt32 nNum;
+ double nVal;
+ const Color* pDummy = nullptr;
+ sal_uInt16 nIndex = static_cast<sal_uInt16>(maArray.GetCellIndex(nCol, nRow, mbRTL));
+
+ switch (nIndex)
+ {
+ case 1: cellString = aStrJan; break;
+ case 2: cellString = aStrFeb; break;
+ case 3: cellString = aStrMar; break;
+ case 5: cellString = aStrNorth; break;
+ case 10: cellString = aStrMid; break;
+ case 15: cellString = aStrSouth; break;
+ case 4:
+ case 20: cellString = aStrSum; break;
+
+ case 6:
+ case 8:
+ case 16:
+ case 18: nVal = nIndex;
+ nNum = 5;
+ goto mknum;
+ case 17:
+ case 7: nVal = nIndex;
+ nNum = 6;
+ goto mknum;
+ case 11:
+ case 12:
+ case 13: nVal = nIndex;
+ nNum = 12 == nIndex ? 10 : 9;
+ goto mknum;
+
+ case 9: nVal = 21; nNum = 7; goto mknum;
+ case 14: nVal = 36; nNum = 11; goto mknum;
+ case 19: nVal = 51; nNum = 7; goto mknum;
+ case 21: nVal = 33; nNum = 13; goto mknum;
+ case 22: nVal = 36; nNum = 14; goto mknum;
+ case 23: nVal = 39; nNum = 13; goto mknum;
+ case 24: nVal = 108; nNum = 15;
+ mknum:
+ if (bNumFormat)
+ {
+ ScNumFormatAbbrev& rNumFormat = const_cast<ScNumFormatAbbrev&>(pCurData->GetNumFormat(sal_uInt16(nNum)));
+ nNum = rNumFormat.GetFormatIndex(*pNumFmt);
+ }
+ else
+ nNum = 0;
+ pNumFmt->GetOutputString(nVal, nNum, cellString, &pDummy);
+ break;
+ }
+
+ if (cellString.isEmpty())
+ return;
+
+ Size aStrSize;
+ sal_uInt16 nFmtIndex = GetFormatIndex( nCol, nRow );
+ const basegfx::B2DRange cellRange(maArray.GetCellRange( nCol, nRow ));
+ Point aPos(basegfx::fround(cellRange.getMinX()), basegfx::fround(cellRange.getMinY()));
+ sal_uInt16 nRightX = 0;
+ bool bJustify = pCurData->GetIncludeJustify();
+ SvxCellHorJustify eJustification;
+
+ SvtScriptedTextHelper aScriptedText(rRenderContext);
+
+ // Justification:
+
+ eJustification = mbRTL ? SvxCellHorJustify::Right : bJustify ?
+ pCurData->GetItem(nFmtIndex, ATTR_HOR_JUSTIFY)->GetValue() :
+ SvxCellHorJustify::Standard;
+
+ if (pCurData->GetIncludeFont())
+ {
+ vcl::Font aFont, aCJKFont, aCTLFont;
+ Size theMaxStrSize;
+
+ MakeFonts(rRenderContext, nFmtIndex, aFont, aCJKFont, aCTLFont);
+
+ theMaxStrSize = Size(basegfx::fround(cellRange.getWidth()), basegfx::fround(cellRange.getHeight()));
+ theMaxStrSize.AdjustWidth( -(FRAME_OFFSET) );
+ theMaxStrSize.AdjustHeight( -(FRAME_OFFSET) );
+
+ aScriptedText.SetFonts( &aFont, &aCJKFont, &aCTLFont );
+ aScriptedText.SetText(cellString, xBreakIter);
+ aStrSize = aScriptedText.GetTextSize();
+
+ if (theMaxStrSize.Height() < aStrSize.Height())
+ {
+ // if the string does not fit in the row using this font,
+ // the default font is used
+ aScriptedText.SetDefaultFont();
+ aStrSize = aScriptedText.GetTextSize();
+ }
+ while((theMaxStrSize.Width() <= aStrSize.Width()) && (cellString.getLength() > 1))
+ {
+ if( eJustification == SvxCellHorJustify::Right )
+ cellString = cellString.copy(1);
+ else
+ cellString = cellString.copy(0, cellString.getLength() - 1 );
+
+ aScriptedText.SetText( cellString, xBreakIter );
+ aStrSize = aScriptedText.GetTextSize();
+ }
+ }
+ else
+ {
+ aScriptedText.SetDefaultFont();
+ aScriptedText.SetText( cellString, xBreakIter );
+ aStrSize = aScriptedText.GetTextSize();
+ }
+
+ nRightX = sal_uInt16(basegfx::fround(cellRange.getWidth()) - aStrSize.Width() - FRAME_OFFSET);
+
+ // vertical (always center):
+
+ aPos.AdjustY((mnRowHeight - static_cast<sal_uInt16>(aStrSize.Height())) / 2 );
+
+ // horizontal
+
+ if (eJustification != SvxCellHorJustify::Standard)
+ {
+ sal_uInt16 nHorPos = sal_uInt16((basegfx::fround(cellRange.getWidth())-aStrSize.Width()) / 2);
+ //sal_uInt16 nHorPos = sal_uInt16((basegfx::fround(cellRange.getWidth())-aStrSize.Width()) / 2);
+
+ switch (eJustification)
+ {
+ case SvxCellHorJustify::Left:
+ aPos.AdjustX(FRAME_OFFSET );
+ break;
+ case SvxCellHorJustify::Right:
+ aPos.AdjustX(nRightX );
+ break;
+ case SvxCellHorJustify::Block:
+ case SvxCellHorJustify::Repeat:
+ case SvxCellHorJustify::Center:
+ aPos.AdjustX(nHorPos );
+ break;
+ // coverity[dead_error_line] - following conditions exist to avoid compiler warning
+ case SvxCellHorJustify::Standard:
+ default:
+ // Standard is not handled here
+ break;
+ }
+ }
+ else
+ {
+
+ // Standard justification
+
+ if (nCol == 0 || nRow == 0)
+ {
+ // Text label to the left or sum left adjusted
+ aPos.AdjustX(FRAME_OFFSET );
+ }
+ else
+ {
+ // Numbers/Dates right adjusted
+ aPos.AdjustX(nRightX );
+ }
+ }
+ aScriptedText.DrawText(aPos);
+}
+
+#undef FRAME_OFFSET
+
+void ScAutoFmtPreview::DrawBackground(vcl::RenderContext& rRenderContext)
+{
+ if (!pCurData)
+ return;
+
+ for(size_t nRow = 0; nRow < 5; ++nRow)
+ {
+ for(size_t nCol = 0; nCol < 5; ++nCol)
+ {
+ const SvxBrushItem* pItem =
+ pCurData->GetItem( GetFormatIndex( nCol, nRow ), ATTR_BACKGROUND );
+
+ rRenderContext.Push( vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR );
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor( pItem->GetColor() );
+
+ const basegfx::B2DRange aCellRange(maArray.GetCellRange( nCol, nRow ));
+ rRenderContext.DrawRect(
+ tools::Rectangle(
+ basegfx::fround(aCellRange.getMinX()), basegfx::fround(aCellRange.getMinY()),
+ basegfx::fround(aCellRange.getMaxX()), basegfx::fround(aCellRange.getMaxY())));
+
+ rRenderContext.Pop();
+ }
+ }
+}
+
+void ScAutoFmtPreview::PaintCells(vcl::RenderContext& rRenderContext)
+{
+ if (!pCurData)
+ return;
+
+ // 1) background
+ if (pCurData->GetIncludeBackground())
+ DrawBackground(rRenderContext);
+
+ // 2) values
+ for(size_t nRow = 0; nRow < 5; ++nRow)
+ for(size_t nCol = 0; nCol < 5; ++nCol)
+ DrawString(rRenderContext, nCol, nRow);
+
+ // 3) border
+ if (!pCurData->GetIncludeFrame())
+ return;
+
+ const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
+ drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
+ rRenderContext,
+ aNewViewInformation2D));
+
+ pProcessor2D->process(maArray.CreateB2DPrimitiveArray());
+ pProcessor2D.reset();
+}
+
+void ScAutoFmtPreview::Init()
+{
+ maArray.Initialize( 5, 5 );
+ mnLabelColWidth = 0;
+ mnDataColWidth1 = 0;
+ mnDataColWidth2 = 0;
+ mnRowHeight = 0;
+ CalcCellArray( false );
+ CalcLineMap();
+}
+
+void ScAutoFmtPreview::DetectRTL(const ScViewData& rViewData)
+{
+ SCTAB nCurrentTab = rViewData.GetTabNo();
+ ScDocument& rDoc = rViewData.GetDocument();
+ mbRTL = rDoc.IsLayoutRTL(nCurrentTab);
+ xBreakIter = rDoc.GetBreakIterator();
+}
+
+void ScAutoFmtPreview::CalcCellArray( bool bFitWidthP )
+{
+ maArray.SetXOffset( 2 );
+ maArray.SetAllColWidths( bFitWidthP ? mnDataColWidth2 : mnDataColWidth1 );
+ maArray.SetColWidth( 0, mnLabelColWidth );
+ maArray.SetColWidth( 4, mnLabelColWidth );
+
+ maArray.SetYOffset( 2 );
+ maArray.SetAllRowHeights( mnRowHeight );
+
+ aPrvSize.setWidth( maArray.GetWidth() + 4 );
+ aPrvSize.setHeight( maArray.GetHeight() + 4 );
+}
+
+static void lclSetStyleFromBorder( svx::frame::Style& rStyle, const ::editeng::SvxBorderLine* pBorder )
+{
+ rStyle.Set(pBorder, o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::pt), 5);
+}
+
+void ScAutoFmtPreview::CalcLineMap()
+{
+ if ( !pCurData )
+ return;
+
+ for( size_t nRow = 0; nRow < 5; ++nRow )
+ {
+ for( size_t nCol = 0; nCol < 5; ++nCol )
+ {
+ svx::frame::Style aStyle;
+
+ const SvxBoxItem& rItem = GetBoxItem( nCol, nRow );
+ lclSetStyleFromBorder( aStyle, rItem.GetLeft() );
+ maArray.SetCellStyleLeft( nCol, nRow, aStyle );
+ lclSetStyleFromBorder( aStyle, rItem.GetRight() );
+ maArray.SetCellStyleRight( nCol, nRow, aStyle );
+ lclSetStyleFromBorder( aStyle, rItem.GetTop() );
+ maArray.SetCellStyleTop( nCol, nRow, aStyle );
+ lclSetStyleFromBorder( aStyle, rItem.GetBottom() );
+ maArray.SetCellStyleBottom( nCol, nRow, aStyle );
+
+ lclSetStyleFromBorder( aStyle, GetDiagItem( nCol, nRow, true ).GetLine() );
+ maArray.SetCellStyleTLBR( nCol, nRow, aStyle );
+ lclSetStyleFromBorder( aStyle, GetDiagItem( nCol, nRow, false ).GetLine() );
+ maArray.SetCellStyleBLTR( nCol, nRow, aStyle );
+ }
+ }
+}
+
+void ScAutoFmtPreview::NotifyChange( ScAutoFormatData* pNewData )
+{
+ if (pNewData)
+ {
+ pCurData = pNewData;
+ bFitWidth = pNewData->GetIncludeWidthHeight();
+ }
+
+ CalcCellArray( bFitWidth );
+ CalcLineMap();
+
+ Invalidate();
+}
+
+void ScAutoFmtPreview::DoPaint(vcl::RenderContext& rRenderContext)
+{
+ rRenderContext.Push(vcl::PushFlags::ALL);
+ DrawModeFlags nOldDrawMode = aVD->GetDrawMode();
+
+ Size aWndSize(GetOutputSizePixel());
+ vcl::Font aFont(aVD->GetFont());
+ const Color& aBackCol = SC_MOD()->GetColorConfig().GetColorValue( ::svtools::DOCCOLOR ).nColor;
+ tools::Rectangle aRect(Point(), aWndSize);
+
+ aFont.SetTransparent( true );
+ aVD->SetFont(aFont);
+ aVD->SetLineColor();
+ aVD->SetFillColor(aBackCol);
+ aVD->SetOutputSize(aWndSize);
+ aVD->DrawRect(aRect);
+
+ PaintCells(*aVD);
+
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(aBackCol);
+ rRenderContext.DrawRect(aRect);
+
+ Point aPos((aWndSize.Width() - aPrvSize.Width()) / 2, (aWndSize.Height() - aPrvSize.Height()) / 2);
+ if (AllSettings::GetLayoutRTL())
+ aPos.setX( -aPos.X() );
+ rRenderContext.DrawOutDev(aPos, aWndSize, Point(), aWndSize, *aVD);
+ aVD->SetDrawMode(nOldDrawMode);
+ rRenderContext.Pop();
+}
+
+void ScAutoFmtPreview::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
+{
+ DoPaint(rRenderContext);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/conflictsdlg.cxx b/sc/source/ui/miscdlgs/conflictsdlg.cxx
new file mode 100644
index 000000000..3a48325aa
--- /dev/null
+++ b/sc/source/ui/miscdlgs/conflictsdlg.cxx
@@ -0,0 +1,643 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/string.hxx>
+#include <osl/diagnose.h>
+
+#include <conflictsdlg.hxx>
+#include <o3tl/safeint.hxx>
+#include <strings.hrc>
+#include <scresid.hxx>
+#include <viewdata.hxx>
+#include <dbfunc.hxx>
+#include <chgtrack.hxx>
+
+// struct ScConflictsListEntry
+
+bool ScConflictsListEntry::HasSharedAction( sal_uLong nSharedAction ) const
+{
+ auto aEnd = maSharedActions.cend();
+ auto aItr = std::find(maSharedActions.cbegin(), aEnd, nSharedAction);
+
+ return aItr != aEnd;
+}
+
+bool ScConflictsListEntry::HasOwnAction( sal_uLong nOwnAction ) const
+{
+ auto aEnd = maOwnActions.cend();
+ auto aItr = std::find(maOwnActions.cbegin(), aEnd, nOwnAction);
+
+ return aItr != aEnd;
+}
+
+
+bool ScConflictsListHelper::HasOwnAction( ScConflictsList& rConflictsList, sal_uLong nOwnAction )
+{
+ return std::any_of(rConflictsList.begin(), rConflictsList.end(),
+ [nOwnAction](ScConflictsListEntry& rConflict) { return rConflict.HasOwnAction( nOwnAction ); });
+}
+
+ScConflictsListEntry* ScConflictsListHelper::GetSharedActionEntry( ScConflictsList& rConflictsList, sal_uLong nSharedAction )
+{
+ auto aEnd = rConflictsList.end();
+ auto aItr = std::find_if(rConflictsList.begin(), aEnd,
+ [nSharedAction](ScConflictsListEntry& rConflict) { return rConflict.HasSharedAction( nSharedAction ); });
+
+ if (aItr != aEnd)
+ return &(*aItr);
+
+ return nullptr;
+}
+
+ScConflictsListEntry* ScConflictsListHelper::GetOwnActionEntry( ScConflictsList& rConflictsList, sal_uLong nOwnAction )
+{
+ auto aEnd = rConflictsList.end();
+ auto aItr = std::find_if(rConflictsList.begin(), aEnd,
+ [nOwnAction](ScConflictsListEntry& rConflict) { return rConflict.HasOwnAction( nOwnAction ); });
+
+ if (aItr != aEnd)
+ return &(*aItr);
+
+ return nullptr;
+}
+
+void ScConflictsListHelper::Transform_Impl( std::vector<sal_uLong>& rActionList, ScChangeActionMergeMap* pMergeMap )
+{
+ if ( !pMergeMap )
+ {
+ return;
+ }
+
+ for ( auto aItr = rActionList.begin(); aItr != rActionList.end(); )
+ {
+ ScChangeActionMergeMap::iterator aItrMap = pMergeMap->find( *aItr );
+ if ( aItrMap != pMergeMap->end() )
+ {
+ *aItr = aItrMap->second;
+ ++aItr;
+ }
+ else
+ {
+ aItr = rActionList.erase( aItr );
+ OSL_FAIL( "ScConflictsListHelper::Transform_Impl: erased action from conflicts list!" );
+ }
+ }
+}
+
+void ScConflictsListHelper::TransformConflictsList( ScConflictsList& rConflictsList,
+ ScChangeActionMergeMap* pSharedMap, ScChangeActionMergeMap* pOwnMap )
+{
+ for ( auto& rConflictEntry : rConflictsList )
+ {
+ if ( pSharedMap )
+ {
+ ScConflictsListHelper::Transform_Impl( rConflictEntry.maSharedActions, pSharedMap );
+ }
+
+ if ( pOwnMap )
+ {
+ ScConflictsListHelper::Transform_Impl( rConflictEntry.maOwnActions, pOwnMap );
+ }
+ }
+}
+
+
+ScConflictsFinder::ScConflictsFinder( ScChangeTrack* pTrack, sal_uLong nStartShared, sal_uLong nEndShared,
+ sal_uLong nStartOwn, sal_uLong nEndOwn, ScConflictsList& rConflictsList )
+ :mpTrack( pTrack )
+ ,mnStartShared( nStartShared )
+ ,mnEndShared( nEndShared )
+ ,mnStartOwn( nStartOwn )
+ ,mnEndOwn( nEndOwn )
+ ,mrConflictsList( rConflictsList )
+{
+}
+
+bool ScConflictsFinder::DoActionsIntersect( const ScChangeAction* pAction1, const ScChangeAction* pAction2 )
+{
+ return pAction1 && pAction2 && pAction1->GetBigRange().Intersects( pAction2->GetBigRange() );
+}
+
+ScConflictsListEntry* ScConflictsFinder::GetIntersectingEntry( const ScChangeAction* pAction ) const
+{
+ auto doActionsIntersect = [this, pAction](const sal_uLong& aAction) { return DoActionsIntersect( mpTrack->GetAction( aAction ), pAction ); };
+
+ for ( auto& rConflict : mrConflictsList )
+ {
+ if (std::any_of( rConflict.maSharedActions.cbegin(), rConflict.maSharedActions.cend(), doActionsIntersect ))
+ return &rConflict;
+
+ if (std::any_of( rConflict.maOwnActions.cbegin(), rConflict.maOwnActions.cend(), doActionsIntersect ))
+ return &rConflict;
+ }
+
+ return nullptr;
+}
+
+ScConflictsListEntry& ScConflictsFinder::GetEntry( sal_uLong nSharedAction, const std::vector<sal_uLong>& rOwnActions )
+{
+ // try to get a list entry which already contains the shared action
+ ScConflictsListEntry* pEntry = ScConflictsListHelper::GetSharedActionEntry( mrConflictsList, nSharedAction );
+ if ( pEntry )
+ {
+ return *pEntry;
+ }
+
+ // try to get a list entry for which the shared action intersects with any
+ // other action of this entry
+ pEntry = GetIntersectingEntry( mpTrack->GetAction( nSharedAction ) );
+ if ( pEntry )
+ {
+ pEntry->maSharedActions.push_back( nSharedAction );
+ return *pEntry;
+ }
+
+ // try to get a list entry for which any of the own actions intersects with
+ // any other action of this entry
+ for ( auto& rOwnAction : rOwnActions )
+ {
+ pEntry = GetIntersectingEntry( mpTrack->GetAction( rOwnAction ) );
+ if ( pEntry )
+ {
+ pEntry->maSharedActions.push_back( nSharedAction );
+ return *pEntry;
+ }
+ }
+
+ // if no entry was found, create a new one
+ ScConflictsListEntry aEntry;
+ aEntry.meConflictAction = SC_CONFLICT_ACTION_NONE;
+ aEntry.maSharedActions.push_back( nSharedAction );
+ mrConflictsList.push_back( aEntry );
+ return mrConflictsList.back();
+}
+
+bool ScConflictsFinder::Find()
+{
+ if ( !mpTrack )
+ {
+ return false;
+ }
+
+ bool bReturn = false;
+ ScChangeAction* pSharedAction = mpTrack->GetAction( mnStartShared );
+ while ( pSharedAction && pSharedAction->GetActionNumber() <= mnEndShared )
+ {
+ std::vector<sal_uLong> aOwnActions;
+ ScChangeAction* pOwnAction = mpTrack->GetAction( mnStartOwn );
+ while ( pOwnAction && pOwnAction->GetActionNumber() <= mnEndOwn )
+ {
+ if ( DoActionsIntersect( pSharedAction, pOwnAction ) )
+ {
+ aOwnActions.push_back( pOwnAction->GetActionNumber() );
+ }
+ pOwnAction = pOwnAction->GetNext();
+ }
+
+ if ( !aOwnActions.empty() )
+ {
+ ScConflictsListEntry& rEntry = GetEntry(pSharedAction->GetActionNumber(), aOwnActions);
+ for ( const auto& aOwnAction : aOwnActions )
+ {
+ if (!ScConflictsListHelper::HasOwnAction(mrConflictsList, aOwnAction))
+ {
+ rEntry.maOwnActions.push_back(aOwnAction);
+ }
+ }
+ bReturn = true;
+ }
+
+ pSharedAction = pSharedAction->GetNext();
+ }
+
+ return bReturn;
+}
+
+
+ScConflictsResolver::ScConflictsResolver( ScChangeTrack* pTrack, ScConflictsList& rConflictsList )
+ :mpTrack ( pTrack )
+ ,mrConflictsList ( rConflictsList )
+{
+ OSL_ENSURE( mpTrack, "ScConflictsResolver CTOR: mpTrack is null!" );
+}
+
+void ScConflictsResolver::HandleAction( ScChangeAction* pAction, bool bIsSharedAction,
+ bool bHandleContentAction, bool bHandleNonContentAction )
+{
+ if ( !mpTrack || !pAction )
+ {
+ return;
+ }
+
+ if ( bIsSharedAction )
+ {
+ ScConflictsListEntry* pConflictEntry = ScConflictsListHelper::GetSharedActionEntry(
+ mrConflictsList, pAction->GetActionNumber() );
+ if ( pConflictEntry )
+ {
+ ScConflictAction eConflictAction = pConflictEntry->meConflictAction;
+ if ( eConflictAction == SC_CONFLICT_ACTION_KEEP_MINE )
+ {
+ if ( pAction->GetType() == SC_CAT_CONTENT )
+ {
+ if ( bHandleContentAction )
+ {
+ mpTrack->Reject( pAction );
+ }
+ }
+ else
+ {
+ if ( bHandleNonContentAction )
+ {
+ mpTrack->Reject( pAction );
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ ScConflictsListEntry* pConflictEntry = ScConflictsListHelper::GetOwnActionEntry(
+ mrConflictsList, pAction->GetActionNumber() );
+ if ( pConflictEntry )
+ {
+ ScConflictAction eConflictAction = pConflictEntry->meConflictAction;
+ if ( eConflictAction == SC_CONFLICT_ACTION_KEEP_MINE )
+ {
+ if ( pAction->GetType() == SC_CAT_CONTENT )
+ {
+ if ( bHandleContentAction )
+ {
+ // do nothing
+ //mpTrack->SelectContent( pAction );
+ }
+ }
+ else
+ {
+ if ( bHandleNonContentAction )
+ {
+ // do nothing
+ //mpTrack->Accept( pAction );
+ }
+ }
+ }
+ else if ( eConflictAction == SC_CONFLICT_ACTION_KEEP_OTHER )
+ {
+ if ( pAction->GetType() == SC_CAT_CONTENT )
+ {
+ if ( bHandleContentAction )
+ {
+ mpTrack->Reject( pAction );
+ }
+ }
+ else
+ {
+ if ( bHandleNonContentAction )
+ {
+ mpTrack->Reject( pAction );
+ }
+ }
+ }
+ }
+ }
+}
+
+
+ScConflictsDlg::ScConflictsDlg(weld::Window* pParent, ScViewData* pViewData, ScDocument* pSharedDoc, ScConflictsList& rConflictsList)
+ : GenericDialogController(pParent, "modules/scalc/ui/conflictsdialog.ui", "ConflictsDialog")
+ , maStrUnknownUser ( ScResId( STR_UNKNOWN_USER_CONFLICT ) )
+ , mpViewData ( pViewData )
+ , mpOwnDoc ( nullptr )
+ , mpOwnTrack ( nullptr )
+ , mpSharedDoc ( pSharedDoc )
+ , mpSharedTrack ( nullptr )
+ , mrConflictsList ( rConflictsList )
+ , maSelectionIdle ( "ScConflictsDlg maSelectionIdle" )
+ , mbInSelectHdl ( false )
+ , m_xBtnKeepMine(m_xBuilder->weld_button("keepmine"))
+ , m_xBtnKeepOther(m_xBuilder->weld_button("keepother"))
+ , m_xBtnKeepAllMine(m_xBuilder->weld_button("keepallmine"))
+ , m_xBtnKeepAllOthers(m_xBuilder->weld_button("keepallothers"))
+ , m_xLbConflicts(new SvxRedlinTable(m_xBuilder->weld_tree_view("container"), nullptr))
+{
+ OSL_ENSURE( mpViewData, "ScConflictsDlg CTOR: mpViewData is null!" );
+ mpOwnDoc = ( mpViewData ? &mpViewData->GetDocument() : nullptr );
+ OSL_ENSURE( mpOwnDoc, "ScConflictsDlg CTOR: mpOwnDoc is null!" );
+ mpOwnTrack = ( mpOwnDoc ? mpOwnDoc->GetChangeTrack() : nullptr );
+ OSL_ENSURE( mpOwnTrack, "ScConflictsDlg CTOR: mpOwnTrack is null!" );
+ OSL_ENSURE( mpSharedDoc, "ScConflictsDlg CTOR: mpSharedDoc is null!" );
+ mpSharedTrack = ( mpSharedDoc ? mpSharedDoc->GetChangeTrack() : nullptr );
+ OSL_ENSURE( mpSharedTrack, "ScConflictsDlg CTOR: mpSharedTrack is null!" );
+
+ weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
+
+ auto nDigitWidth = rTreeView.get_approximate_digit_width();
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(nDigitWidth * 60),
+ o3tl::narrowing<int>(nDigitWidth * 20)
+ };
+ rTreeView.set_column_fixed_widths(aWidths);
+
+ rTreeView.set_selection_mode(SelectionMode::Multiple);
+ rTreeView.set_size_request(-1, rTreeView.get_height_rows(16));
+
+ maSelectionIdle.SetInvokeHandler( LINK( this, ScConflictsDlg, UpdateSelectionHdl ) );
+
+ rTreeView.connect_changed(LINK(this, ScConflictsDlg, SelectHandle));
+
+ m_xBtnKeepMine->connect_clicked( LINK( this, ScConflictsDlg, KeepMineHandle ) );
+ m_xBtnKeepOther->connect_clicked( LINK( this, ScConflictsDlg, KeepOtherHandle ) );
+ m_xBtnKeepAllMine->connect_clicked( LINK( this, ScConflictsDlg, KeepAllMineHandle ) );
+ m_xBtnKeepAllOthers->connect_clicked( LINK( this, ScConflictsDlg, KeepAllOthersHandle ) );
+
+ UpdateView();
+
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ if (rTreeView.get_iter_first(*xEntry))
+ rTreeView.select(*xEntry);
+}
+
+ScConflictsDlg::~ScConflictsDlg()
+{
+}
+
+OUString ScConflictsDlg::GetConflictString( const ScConflictsListEntry& rConflictEntry )
+{
+ OUString aString;
+ if ( mpOwnTrack )
+ {
+ const ScChangeAction* pAction = mpOwnTrack->GetAction( rConflictEntry.maOwnActions[ 0 ] );
+ if ( pAction && mpOwnDoc )
+ {
+ SCTAB nTab = pAction->GetBigRange().MakeRange( *mpOwnDoc ).aStart.Tab();
+ mpOwnDoc->GetName( nTab, aString );
+ }
+ }
+ return aString;
+}
+
+void ScConflictsDlg::SetActionString(const ScChangeAction* pAction, ScDocument* pDoc, const weld::TreeIter& rEntry)
+{
+ OSL_ENSURE( pAction, "ScConflictsDlg::GetActionString(): pAction is null!" );
+ OSL_ENSURE( pDoc, "ScConflictsDlg::GetActionString(): pDoc is null!" );
+ if (!pAction || !pDoc)
+ return;
+
+ weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
+ OUString aDesc = pAction->GetDescription(*pDoc, true, false);
+ rTreeView.set_text(rEntry, aDesc, 0);
+
+ OUString aUser = comphelper::string::strip(pAction->GetUser(), ' ');
+ if ( aUser.isEmpty() )
+ {
+ aUser = maStrUnknownUser;
+ }
+ rTreeView.set_text(rEntry, aUser, 1);
+
+ DateTime aDateTime = pAction->GetDateTime();
+ OUString aString = ScGlobal::getLocaleData().getDate( aDateTime ) + " " +
+ ScGlobal::getLocaleData().getTime( aDateTime, false );
+ rTreeView.set_text(rEntry, aString, 2);
+}
+
+void ScConflictsDlg::HandleListBoxSelection()
+{
+ weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ bool bSelEntry = rTreeView.get_cursor(xEntry.get());
+ if (!bSelEntry)
+ bSelEntry = rTreeView.get_selected(xEntry.get());
+ if (!bSelEntry)
+ return;
+
+ bool bSelectHandle = rTreeView.is_selected(*xEntry);
+
+ while (rTreeView.get_iter_depth(*xEntry))
+ rTreeView.iter_parent(*xEntry);
+
+ if (bSelectHandle)
+ rTreeView.unselect_all();
+ if (!rTreeView.is_selected(*xEntry))
+ rTreeView.select(*xEntry);
+ if (rTreeView.iter_children(*xEntry))
+ {
+ do
+ {
+ if (!rTreeView.is_selected(*xEntry))
+ rTreeView.select(*xEntry);
+ } while (rTreeView.iter_next_sibling(*xEntry));
+ }
+}
+
+IMPL_LINK_NOARG(ScConflictsDlg, SelectHandle, weld::TreeView&, void)
+{
+ if (mbInSelectHdl)
+ return;
+
+ mbInSelectHdl = true;
+ HandleListBoxSelection();
+ maSelectionIdle.Start();
+ mbInSelectHdl = false;
+}
+
+IMPL_LINK_NOARG(ScConflictsDlg, UpdateSelectionHdl, Timer *, void)
+{
+ if ( !mpViewData || !mpOwnDoc )
+ {
+ return;
+ }
+
+ ScTabView* pTabView = mpViewData->GetView();
+ pTabView->DoneBlockMode();
+
+ std::vector<const ScChangeAction*> aActions;
+
+ weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
+ rTreeView.selected_foreach([&rTreeView, &aActions](weld::TreeIter& rEntry){
+ if (rTreeView.get_iter_depth(rEntry))
+ {
+ RedlinData* pUserData = weld::fromId<RedlinData*>(rTreeView.get_id(rEntry));
+ if (pUserData)
+ {
+ ScChangeAction* pAction = static_cast< ScChangeAction* >( pUserData->pData );
+ if ( pAction && ( pAction->GetType() != SC_CAT_DELETE_TABS ) &&
+ ( pAction->IsClickable() || pAction->IsVisible() ) )
+ {
+ aActions.push_back(pAction);
+ }
+ }
+ }
+ return false;
+ });
+
+ bool bContMark = false;
+ for (size_t i = 0, nCount = aActions.size(); i < nCount; ++i)
+ {
+ const ScBigRange& rBigRange = aActions[i]->GetBigRange();
+ if (rBigRange.IsValid(*mpOwnDoc))
+ {
+ bool bSetCursor = i == nCount - 1;
+ pTabView->MarkRange(rBigRange.MakeRange( *mpOwnDoc ), bSetCursor, bContMark);
+ bContMark = true;
+ }
+ }
+}
+
+void ScConflictsDlg::SetConflictAction(const weld::TreeIter& rRootEntry, ScConflictAction eConflictAction)
+{
+ weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
+ RedlinData* pUserData = weld::fromId<RedlinData*>(rTreeView.get_id(rRootEntry));
+ ScConflictsListEntry* pConflictEntry = static_cast< ScConflictsListEntry* >( pUserData ? pUserData->pData : nullptr );
+ if ( pConflictEntry )
+ {
+ pConflictEntry->meConflictAction = eConflictAction;
+ }
+}
+
+void ScConflictsDlg::KeepHandler(bool bMine)
+{
+ weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ if (!rTreeView.get_selected(xEntry.get()))
+ return;
+
+ while (rTreeView.get_iter_depth(*xEntry))
+ rTreeView.iter_parent(*xEntry);
+
+ m_xDialog->set_busy_cursor(true);
+ ScConflictAction eConflictAction = ( bMine ? SC_CONFLICT_ACTION_KEEP_MINE : SC_CONFLICT_ACTION_KEEP_OTHER );
+ SetConflictAction(*xEntry, eConflictAction);
+ rTreeView.remove(*xEntry);
+ m_xDialog->set_busy_cursor(false);
+ if (rTreeView.n_children() == 0)
+ m_xDialog->response(RET_OK);
+}
+
+void ScConflictsDlg::KeepAllHandler( bool bMine )
+{
+ weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ if (!rTreeView.get_iter_first(*xEntry))
+ return;
+
+ while (rTreeView.get_iter_depth(*xEntry))
+ rTreeView.iter_parent(*xEntry);
+
+ m_xDialog->set_busy_cursor(true);
+
+ ScConflictAction eConflictAction = ( bMine ? SC_CONFLICT_ACTION_KEEP_MINE : SC_CONFLICT_ACTION_KEEP_OTHER );
+ do
+ {
+ SetConflictAction(*xEntry, eConflictAction);
+ } while (rTreeView.iter_next_sibling(*xEntry));
+
+ rTreeView.freeze();
+ rTreeView.clear();
+ rTreeView.thaw();
+
+ m_xDialog->set_busy_cursor(false);
+
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ScConflictsDlg, KeepMineHandle, weld::Button&, void)
+{
+ KeepHandler( true );
+}
+
+IMPL_LINK_NOARG(ScConflictsDlg, KeepOtherHandle, weld::Button&, void)
+{
+ KeepHandler( false );
+}
+
+IMPL_LINK_NOARG(ScConflictsDlg, KeepAllMineHandle, weld::Button&, void)
+{
+ KeepAllHandler( true );
+}
+
+IMPL_LINK_NOARG(ScConflictsDlg, KeepAllOthersHandle, weld::Button&, void)
+{
+ KeepAllHandler( false );
+}
+
+void ScConflictsDlg::UpdateView()
+{
+ weld::TreeView& rTreeView = m_xLbConflicts->GetWidget();
+ for ( ScConflictsListEntry& rConflictEntry : mrConflictsList )
+ {
+ if (rConflictEntry.meConflictAction == SC_CONFLICT_ACTION_NONE)
+ {
+ std::unique_ptr<RedlinData> pRootUserData(new RedlinData());
+ pRootUserData->pData = static_cast<void*>(&rConflictEntry);
+ OUString sString(GetConflictString(rConflictEntry));
+ OUString sId(weld::toId(pRootUserData.release()));
+ std::unique_ptr<weld::TreeIter> xRootEntry(rTreeView.make_iterator());
+ std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator());
+ rTreeView.insert(nullptr, -1, &sString, &sId, nullptr, nullptr, false, xRootEntry.get());
+
+ for ( const auto& aSharedAction : rConflictEntry.maSharedActions )
+ {
+ ScChangeAction* pAction = mpSharedTrack ? mpSharedTrack->GetAction(aSharedAction) : nullptr;
+ if ( pAction )
+ {
+ // only display shared top content entries
+ if ( pAction->GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionContent* pNextContent = dynamic_cast<ScChangeActionContent&>(*pAction).GetNextContent();
+ if ( pNextContent && rConflictEntry.HasSharedAction( pNextContent->GetActionNumber() ) )
+ {
+ continue;
+ }
+ }
+
+ rTreeView.insert(xRootEntry.get(), -1, nullptr, nullptr, nullptr, nullptr, false, xEntry.get());
+ SetActionString(pAction, mpSharedDoc, *xEntry);
+ }
+ }
+
+ for ( const auto& aOwnAction : rConflictEntry.maOwnActions )
+ {
+ ScChangeAction* pAction = mpOwnTrack ? mpOwnTrack->GetAction(aOwnAction) : nullptr;
+ if ( pAction )
+ {
+ // only display own top content entries
+ if ( pAction->GetType() == SC_CAT_CONTENT )
+ {
+ ScChangeActionContent* pNextContent = dynamic_cast<ScChangeActionContent&>(*pAction).GetNextContent();
+ if ( pNextContent && rConflictEntry.HasOwnAction( pNextContent->GetActionNumber() ) )
+ {
+ continue;
+ }
+ }
+
+ std::unique_ptr<RedlinData> pUserData(new RedlinData());
+ pUserData->pData = static_cast< void* >( pAction );
+ OUString aId(weld::toId(pUserData.release()));
+ rTreeView.insert(xRootEntry.get(), -1, nullptr, &aId, nullptr, nullptr, false, xEntry.get());
+ SetActionString(pAction, mpOwnDoc, *xEntry);
+ }
+ }
+
+ rTreeView.expand_row(*xRootEntry);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/crdlg.cxx b/sc/source/ui/miscdlgs/crdlg.cxx
new file mode 100644
index 000000000..9d778595e
--- /dev/null
+++ b/sc/source/ui/miscdlgs/crdlg.cxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <crdlg.hxx>
+#include <scui_def.hxx>
+
+ScColOrRowDlg::ScColOrRowDlg(weld::Window* pParent, const OUString& rStrTitle,
+ const OUString& rStrLabel)
+ : GenericDialogController(pParent, "modules/scalc/ui/colorrowdialog.ui", "ColOrRowDialog")
+ , m_xFrame(m_xBuilder->weld_frame("frame"))
+ , m_xBtnRows(m_xBuilder->weld_radio_button("rows"))
+ , m_xBtnCols(m_xBuilder->weld_radio_button("columns"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+{
+ m_xDialog->set_title(rStrTitle);
+ m_xFrame->set_label(rStrLabel);
+ m_xBtnOk->connect_clicked(LINK(this, ScColOrRowDlg, OkHdl));
+}
+
+ScColOrRowDlg::~ScColOrRowDlg() {}
+
+IMPL_LINK_NOARG(ScColOrRowDlg, OkHdl, weld::Button&, void)
+{
+ m_xDialog->response(m_xBtnCols->get_active() ? SCRET_COLS : SCRET_ROWS);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/crnrdlg.cxx b/sc/source/ui/miscdlgs/crnrdlg.cxx
new file mode 100644
index 000000000..38a0cfe66
--- /dev/null
+++ b/sc/source/ui/miscdlgs/crnrdlg.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 <reffact.hxx>
+#include <document.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <docsh.hxx>
+#include <crnrdlg.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <o3tl/string_view.hxx>
+#include <memory>
+
+namespace
+{
+ void ERRORBOX(weld::Window* pParent, const OUString& rString)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ rString));
+ xBox->run();
+ }
+
+ int QUERYBOX(weld::Window* pParent, const OUString& rString)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Question, VclButtonsType::YesNo,
+ rString));
+ xBox->set_default_response(RET_YES);
+ return xBox->run();
+ }
+
+}
+
+const sal_uLong nEntryDataCol = 0;
+const sal_uLong nEntryDataRow = 1;
+const sal_uLong nEntryDataDelim = 2;
+
+
+// note: some of the initialisation is done in Init
+ScColRowNameRangesDlg::ScColRowNameRangesDlg( SfxBindings* pB,
+ SfxChildWindow* pCW,
+ weld::Window* pParent,
+ ScViewData& rViewData )
+
+ : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/namerangesdialog.ui", "NameRangesDialog")
+ , m_rViewData(rViewData)
+ , rDoc(rViewData.GetDocument())
+ , bDlgLostFocus(false)
+ , m_pEdActive(nullptr)
+ , m_xLbRange(m_xBuilder->weld_tree_view("range"))
+ , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry("edassign")))
+ , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button("rbassign")))
+ , m_xBtnColHead(m_xBuilder->weld_radio_button("colhead"))
+ , m_xBtnRowHead(m_xBuilder->weld_radio_button("rowhead"))
+ , m_xEdAssign2(new formula::RefEdit(m_xBuilder->weld_entry("edassign2")))
+ , m_xRbAssign2(new formula::RefButton(m_xBuilder->weld_button("rbassign2")))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_xBtnAdd(m_xBuilder->weld_button("add"))
+ , m_xBtnRemove(m_xBuilder->weld_button("delete"))
+ , m_xRangeFrame(m_xBuilder->weld_frame("rangeframe"))
+ , m_xRangeFT(m_xRangeFrame->weld_label_widget())
+ , m_xDataFT(m_xBuilder->weld_label("datarange"))
+{
+ m_xRbAssign->SetReferences(this, m_xEdAssign.get());
+ m_xEdAssign->SetReferences(this, m_xRangeFT.get());
+ m_xRbAssign2->SetReferences(this, m_xEdAssign2.get());
+ m_xEdAssign2->SetReferences(this, m_xDataFT.get());
+
+ xColNameRanges = rDoc.GetColNameRanges()->Clone();
+ xRowNameRanges = rDoc.GetRowNameRanges()->Clone();
+ Init();
+}
+
+ScColRowNameRangesDlg::~ScColRowNameRangesDlg()
+{
+}
+
+// initialises event handlers and start parameters in the dialog
+void ScColRowNameRangesDlg::Init()
+{
+ m_xBtnOk->connect_clicked ( LINK( this, ScColRowNameRangesDlg, OkBtnHdl ) );
+ m_xBtnCancel->connect_clicked ( LINK( this, ScColRowNameRangesDlg, CancelBtnHdl ) );
+ m_xBtnAdd->connect_clicked ( LINK( this, ScColRowNameRangesDlg, AddBtnHdl ) );
+ m_xBtnRemove->connect_clicked ( LINK( this, ScColRowNameRangesDlg, RemoveBtnHdl ) );
+ m_xLbRange->connect_changed( LINK( this, ScColRowNameRangesDlg, Range1SelectHdl ) );
+ m_xEdAssign->SetModifyHdl ( LINK( this, ScColRowNameRangesDlg, Range1DataModifyHdl ) );
+ m_xBtnColHead->connect_toggled ( LINK( this, ScColRowNameRangesDlg, ColRowToggleHdl ) );
+ m_xEdAssign2->SetModifyHdl ( LINK( this, ScColRowNameRangesDlg, Range2DataModifyHdl ) );
+
+ Link<formula::RefEdit&,void> aEditLink = LINK( this, ScColRowNameRangesDlg, GetEditFocusHdl );
+ m_xEdAssign->SetGetFocusHdl( aEditLink );
+ m_xEdAssign2->SetGetFocusHdl( aEditLink );
+
+ Link<formula::RefButton&,void> aButtonLink = LINK( this, ScColRowNameRangesDlg, GetButtonFocusHdl );
+ m_xRbAssign->SetGetFocusHdl( aButtonLink );
+ m_xRbAssign2->SetGetFocusHdl( aButtonLink );
+
+ aEditLink = LINK( this, ScColRowNameRangesDlg, LoseEditFocusHdl );
+ m_xEdAssign->SetLoseFocusHdl( aEditLink );
+ m_xEdAssign2->SetLoseFocusHdl( aEditLink );
+
+ aButtonLink = LINK( this, ScColRowNameRangesDlg, LoseButtonFocusHdl );
+ m_xRbAssign2->SetLoseFocusHdl( aButtonLink );
+ m_xRbAssign->SetLoseFocusHdl( aButtonLink );
+
+ m_pEdActive = m_xEdAssign.get();
+
+ UpdateNames();
+
+ SCCOL nStartCol = 0;
+ SCROW nStartRow = 0;
+ SCTAB nStartTab = 0;
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ SCTAB nEndTab = 0;
+ m_rViewData.GetSimpleArea(nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab );
+ SetColRowData( ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab));
+
+ m_xBtnColHead->set_sensitive(true);
+ m_xBtnRowHead->set_sensitive(true);
+ m_xEdAssign->GetWidget()->set_sensitive(true);
+ m_xEdAssign->GrabFocus();
+ m_xRbAssign->GetWidget()->set_sensitive(true);
+
+ Range1SelectHdl( *m_xLbRange );
+}
+
+// set data range of a labeled range to default values and set the
+// form elements for the reference
+void ScColRowNameRangesDlg::SetColRowData( const ScRange& rLabelRange, bool bRef)
+{
+ theCurData = theCurArea = rLabelRange;
+ bool bValid = true;
+ SCCOL nCol1 = theCurArea.aStart.Col();
+ SCCOL nCol2 = theCurArea.aEnd.Col();
+ SCROW nRow1 = theCurArea.aStart.Row();
+ SCROW nRow2 = theCurArea.aEnd.Row();
+ if ( (static_cast<SCCOLROW>(nCol2 - nCol1) >= nRow2 - nRow1) || (nCol1 == 0 && nCol2 == rDoc.MaxCol()) )
+ { // Column headers and the limiting case of the whole sheet
+ m_xBtnColHead->set_active(true);
+ m_xBtnRowHead->set_active(false);
+ if ( nRow2 == rDoc.MaxRow() )
+ {
+ if ( nRow1 == 0 )
+ bValid = false; // limiting case of the whole sheet
+ else
+ { // Header at bottom, data above
+ theCurData.aStart.SetRow( 0 );
+ theCurData.aEnd.SetRow( nRow1 - 1 );
+ }
+ }
+ else
+ { // Header at top, data below
+ theCurData.aStart.SetRow( nRow2 + 1 );
+ theCurData.aEnd.SetRow( rDoc.MaxRow() );
+ }
+ }
+ else
+ { // Column headers
+ m_xBtnRowHead->set_active(true);
+ m_xBtnColHead->set_active(false);
+ if ( nCol2 == rDoc.MaxCol() )
+ { // Header at the right, data to the left
+ theCurData.aStart.SetCol( 0 );
+ theCurData.aEnd.SetCol( nCol2 - 1 );
+ }
+ else
+ { // Header at the left, data to the right
+ theCurData.aStart.SetCol( nCol2 + 1 );
+ theCurData.aEnd.SetCol( rDoc.MaxCol() );
+ }
+ }
+ if ( bValid )
+ {
+ const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
+ OUString aStr(theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, eConv));
+
+ if(bRef)
+ m_xEdAssign->SetRefString( aStr );
+ else
+ m_xEdAssign->SetText( aStr );
+
+ m_xEdAssign->SetCursorAtLast();
+ aStr = theCurData.Format(rDoc, ScRefFlags::RANGE_ABS_3D, eConv);
+
+ if(bRef)
+ m_xEdAssign2->SetRefString( aStr );
+ else
+ m_xEdAssign2->SetText( aStr );
+ }
+ else
+ {
+ theCurData = theCurArea = ScRange();
+
+ if(bRef)
+ {
+ m_xEdAssign->SetRefString( OUString() );
+ m_xEdAssign2->SetRefString( OUString() );
+ }
+ else
+ {
+ m_xEdAssign->SetText( OUString() );
+ m_xEdAssign2->SetText( OUString() );
+ }
+
+ m_xBtnColHead->set_sensitive(false);
+ m_xBtnRowHead->set_sensitive(false);
+ m_xEdAssign2->GetWidget()->set_sensitive(false);
+ m_xRbAssign2->GetWidget()->set_sensitive(false);
+ }
+}
+
+// adjust label range and set the data reference form element
+void ScColRowNameRangesDlg::AdjustColRowData( const ScRange& rDataRange, bool bRef)
+{
+ theCurData = rDataRange;
+ if ( m_xBtnColHead->get_active() )
+ { // Data range is the same columns as the header
+ theCurData.aStart.SetCol( theCurArea.aStart.Col() );
+ theCurData.aEnd.SetCol( theCurArea.aEnd.Col() );
+ if ( theCurData.Intersects( theCurArea ) )
+ {
+ SCROW nRow1 = theCurArea.aStart.Row();
+ SCROW nRow2 = theCurArea.aEnd.Row();
+ if ( nRow1 > 0
+ && (theCurData.aEnd.Row() < nRow2 || nRow2 == rDoc.MaxRow()) )
+ { // Data above header
+ theCurData.aEnd.SetRow( nRow1 - 1 );
+ if ( theCurData.aStart.Row() > theCurData.aEnd.Row() )
+ theCurData.aStart.SetRow( theCurData.aEnd.Row() );
+ }
+ else
+ { // Data below header
+ theCurData.aStart.SetRow( nRow2 + 1 );
+ if ( theCurData.aStart.Row() > theCurData.aEnd.Row() )
+ theCurData.aEnd.SetRow( theCurData.aStart.Row() );
+ }
+ }
+ }
+ else
+ { // Data range in the same rows as header
+ theCurData.aStart.SetRow( theCurArea.aStart.Row() );
+ theCurData.aEnd.SetRow( theCurArea.aEnd.Row() );
+ if ( theCurData.Intersects( theCurArea ) )
+ {
+ SCCOL nCol1 = theCurArea.aStart.Col();
+ SCCOL nCol2 = theCurArea.aEnd.Col();
+ if ( nCol1 > 0
+ && (theCurData.aEnd.Col() < nCol2 || nCol2 == rDoc.MaxCol()) )
+ { // Data left of header
+ theCurData.aEnd.SetCol( nCol1 - 1 );
+ if ( theCurData.aStart.Col() > theCurData.aEnd.Col() )
+ theCurData.aStart.SetCol( theCurData.aEnd.Col() );
+ }
+ else
+ { // Data right of header
+ theCurData.aStart.SetCol( nCol2 + 1 );
+ if ( theCurData.aStart.Col() > theCurData.aEnd.Col() )
+ theCurData.aEnd.SetCol( theCurData.aStart.Col() );
+ }
+ }
+ }
+ OUString aStr(theCurData.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()));
+
+ if(bRef)
+ m_xEdAssign2->SetRefString( aStr );
+ else
+ m_xEdAssign2->SetText( aStr );
+
+ m_xEdAssign2->SetCursorAtLast();
+}
+
+// Set the reference to a cell range selected with the mouse and update
+// the selection form element
+void ScColRowNameRangesDlg::SetReference( const ScRange& rRef, ScDocument& /* rDoc */ )
+{
+ if ( !m_pEdActive )
+ return;
+
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart( m_pEdActive );
+
+ if (m_pEdActive == m_xEdAssign.get())
+ SetColRowData( rRef, true );
+ else
+ AdjustColRowData( rRef, true );
+ m_xBtnColHead->set_sensitive(true);
+ m_xBtnRowHead->set_sensitive(true);
+ m_xBtnAdd->set_sensitive(true);
+ m_xBtnRemove->set_sensitive(false);
+}
+
+void ScColRowNameRangesDlg::Close()
+{
+ DoClose( ScColRowNameRangesDlgWrapper::GetChildWindowId() );
+}
+
+void ScColRowNameRangesDlg::SetActive()
+{
+ if ( bDlgLostFocus )
+ {
+ bDlgLostFocus = false;
+ if( m_pEdActive )
+ m_pEdActive->GrabFocus();
+ }
+ else
+ m_xDialog->grab_focus();
+
+ if( m_pEdActive == m_xEdAssign.get() )
+ Range1DataModifyHdl( *m_xEdAssign );
+ else if( m_pEdActive == m_xEdAssign2.get() )
+ Range2DataModifyHdl( *m_xEdAssign2 );
+
+ RefInputDone();
+}
+
+void ScColRowNameRangesDlg::UpdateNames()
+{
+ m_xLbRange->freeze();
+
+ m_xLbRange->clear();
+ aRangeMap.clear();
+ m_xEdAssign->SetText( OUString() );
+
+ size_t nCount, j;
+
+ SCCOL nCol1;
+ SCROW nRow1; //Extension for range names
+ SCTAB nTab1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ SCTAB nTab2;
+ OUString rString;
+ const ScAddress::Details aDetails(rDoc.GetAddressConvention());
+
+ OUString strDelim(" --- ");
+ OUString aString = strDelim + ScResId( STR_COLUMN ) + strDelim;
+ m_xLbRange->append(OUString::number(nEntryDataDelim), aString);
+ if ( xColNameRanges->size() > 0 )
+ {
+ std::vector<const ScRangePair*> aSortArray(xColNameRanges->CreateNameSortedArray(
+ rDoc ));
+ nCount = aSortArray.size();
+ for ( j=0; j < nCount; j++ )
+ {
+ const ScRange aRange(aSortArray[j]->GetRange(0));
+ aString = aRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, aDetails);
+
+ //@008 get range parameters from document
+ aSortArray[j]->GetRange(0).GetVars( nCol1, nRow1, nTab1,
+ nCol2, nRow2, nTab2 );
+ SCCOL q=nCol1+3;
+ if(q>nCol2) q=nCol2;
+ //@008 construct string
+ OUStringBuffer strShow = " [";
+ rString = rDoc.GetString(nCol1, nRow1, nTab1);
+ strShow.append(rString);
+ for(SCCOL i=nCol1+1;i<=q;i++)
+ {
+ strShow.append(", ");
+ rString = rDoc.GetString(i, nRow1, nTab1);
+ strShow.append(rString);
+ }
+ if(q<nCol2) // Too long? Add ",..."
+ {
+ strShow.append(", ...");
+ }
+ strShow.append("]");
+
+ //@008 Add string to listbox
+ OUString aInsStr = aString + strShow;
+ aRangeMap.emplace( aInsStr, aRange );
+ m_xLbRange->append(OUString::number(nEntryDataCol), aInsStr);
+ }
+ }
+ aString = strDelim + ScResId( STR_ROW ) + strDelim;
+ m_xLbRange->append(OUString::number(nEntryDataDelim), aString);
+ if ( xRowNameRanges->size() > 0 )
+ {
+ std::vector<const ScRangePair*> aSortArray(xRowNameRanges->CreateNameSortedArray(
+ rDoc ));
+ nCount = aSortArray.size();
+ for ( j=0; j < nCount; j++ )
+ {
+ const ScRange aRange(aSortArray[j]->GetRange(0));
+ aString = aRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, aDetails);
+
+ //@008 Build string for rows below
+ aSortArray[j]->GetRange(0).GetVars( nCol1, nRow1, nTab1,
+ nCol2, nRow2, nTab2 );
+ SCROW q=nRow1+3;
+ if(q>nRow2) q=nRow2;
+ OUStringBuffer strShow = " [";
+ rString = rDoc.GetString(nCol1, nRow1, nTab1);
+ strShow.append(rString);
+ for(SCROW i=nRow1+1;i<=q;i++)
+ {
+ strShow.append(", ");
+ rString = rDoc.GetString(nCol1, i, nTab1);
+ strShow.append(rString);
+ }
+ if(q<nRow2)
+ {
+ strShow.append(", ...");
+ }
+ strShow.append("]");
+
+ OUString aInsStr = aString + strShow;
+ aRangeMap.emplace( aInsStr, aRange );
+ m_xLbRange->append(OUString::number(nEntryDataRow), aInsStr);
+ }
+ }
+
+ m_xLbRange->thaw();
+}
+
+void ScColRowNameRangesDlg::UpdateRangeData( const ScRange& rRange, bool bColName )
+{
+ ScRangePair* pPair = nullptr;
+ bool bFound = false;
+ if ( bColName && (pPair = xColNameRanges->Find( rRange )) != nullptr )
+ bFound = true;
+ else if ( !bColName && (pPair = xRowNameRanges->Find( rRange )) != nullptr )
+ bFound = true;
+
+ if ( bFound )
+ {
+ const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
+ theCurArea = rRange;
+ OUString aStr(theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, eConv));
+ m_xEdAssign->SetText( aStr );
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(true);
+ m_xBtnColHead->set_active(bColName);
+ m_xBtnRowHead->set_active(!bColName);
+ theCurData = pPair->GetRange(1);
+ aStr = theCurData.Format(rDoc, ScRefFlags::RANGE_ABS_3D, eConv);
+ m_xEdAssign2->SetText( aStr );
+ }
+ else
+ {
+ m_xBtnAdd->set_sensitive(true);
+ m_xBtnRemove->set_sensitive(false);
+ }
+ m_xBtnColHead->set_sensitive(true);
+ m_xBtnRowHead->set_sensitive(true);
+ m_xEdAssign2->GetWidget()->set_sensitive(true);
+ m_xRbAssign2->GetWidget()->set_sensitive(true);
+}
+
+bool ScColRowNameRangesDlg::IsRefInputMode() const
+{
+ return (m_pEdActive != nullptr);
+}
+
+// Handler:
+
+// handler called when OK is clicked, calls the add button handler before
+// passing the range lists to the document
+IMPL_LINK_NOARG(ScColRowNameRangesDlg, OkBtnHdl, weld::Button&, void)
+{
+ AddBtnHdl(*m_xBtnAdd);
+
+ // assign RangeLists to the references in the document
+ rDoc.GetColNameRangesRef() = xColNameRanges;
+ rDoc.GetRowNameRangesRef() = xRowNameRanges;
+ // changed ranges need to take effect
+ rDoc.CompileColRowNameFormula();
+ ScDocShell* pDocShell = m_rViewData.GetDocShell();
+ pDocShell->PostPaint(ScRange(0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB), PaintPartFlags::Grid);
+ pDocShell->SetDocumentModified();
+
+ response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ScColRowNameRangesDlg, CancelBtnHdl, weld::Button&, void)
+{
+ response(RET_CANCEL);
+}
+
+// handler called when add button clicked: set ranges and add to listbox
+IMPL_LINK_NOARG(ScColRowNameRangesDlg, AddBtnHdl, weld::Button&, void)
+{
+ OUString aNewArea( m_xEdAssign->GetText() );
+ OUString aNewData( m_xEdAssign2->GetText() );
+
+ if (aNewArea.isEmpty() || aNewData.isEmpty())
+ return;
+
+ const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
+ ScRange aRange1, aRange2;
+ bool bOk1 = (aRange1.ParseAny( aNewArea, rDoc, eConv ) & ScRefFlags::VALID) == ScRefFlags::VALID;
+ if ( bOk1 && (aRange2.ParseAny( aNewData, rDoc, eConv ) & ScRefFlags::VALID) == ScRefFlags::VALID)
+ {
+ theCurArea = aRange1;
+ AdjustColRowData( aRange2 );
+ ScRangePair* pPair;
+ if ( ( pPair = xColNameRanges->Find( theCurArea ) ) != nullptr )
+ {
+ xColNameRanges->Remove( *pPair );
+ }
+ if ( ( pPair = xRowNameRanges->Find( theCurArea ) ) != nullptr )
+ {
+ xRowNameRanges->Remove( *pPair );
+ }
+ if ( m_xBtnColHead->get_active() )
+ xColNameRanges->Join( ScRangePair( theCurArea, theCurData ) );
+ else
+ xRowNameRanges->Join( ScRangePair( theCurArea, theCurData ) );
+
+ UpdateNames();
+
+ m_xEdAssign->GrabFocus();
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(false);
+ m_xEdAssign->SetText( OUString() );
+ m_xBtnColHead->set_active(true);
+ m_xBtnRowHead->set_active(false);
+ m_xEdAssign2->SetText( OUString() );
+ theCurArea = ScRange();
+ theCurData = theCurArea;
+ Range1SelectHdl( *m_xLbRange );
+ }
+ else
+ {
+ ERRORBOX(m_xDialog.get(), ScResId(STR_INVALIDTABNAME));
+ if ( !bOk1 )
+ m_xEdAssign->GrabFocus();
+ else
+ m_xEdAssign2->GrabFocus();
+ }
+}
+
+IMPL_LINK_NOARG(ScColRowNameRangesDlg, RemoveBtnHdl, weld::Button&, void)
+{
+ OUString aRangeStr = m_xLbRange->get_selected_text();
+ sal_Int32 nSelectPos = m_xLbRange->get_selected_index();
+ bool bColName = nSelectPos != -1 && m_xLbRange->get_id(nSelectPos).toInt32() == nEntryDataCol;
+ NameRangeMap::const_iterator itr = aRangeMap.find(aRangeStr);
+ if (itr == aRangeMap.end())
+ return;
+ const ScRange& rRange = itr->second;
+
+ ScRangePair* pPair = nullptr;
+ bool bFound = false;
+ if ( bColName && (pPair = xColNameRanges->Find( rRange )) != nullptr )
+ bFound = true;
+ else if ( !bColName && (pPair = xRowNameRanges->Find( rRange )) != nullptr )
+ bFound = true;
+ if ( !bFound )
+ return;
+
+ OUString aStrDelMsg = ScResId( STR_QUERY_DELENTRY );
+ OUString aMsg = o3tl::getToken(aStrDelMsg, 0, '#' )
+ + aRangeStr
+ + o3tl::getToken(aStrDelMsg, 1, '#' );
+
+ if (RET_YES != QUERYBOX(m_xDialog.get(), aMsg))
+ return;
+
+ if ( bColName )
+ xColNameRanges->Remove( *pPair );
+ else
+ xRowNameRanges->Remove( *pPair );
+
+ UpdateNames();
+ const sal_Int32 nCnt = m_xLbRange->n_children();
+ if ( nSelectPos >= nCnt )
+ {
+ if ( nCnt )
+ nSelectPos = nCnt - 1;
+ else
+ nSelectPos = 0;
+ }
+ m_xLbRange->select(nSelectPos);
+ if (nSelectPos && m_xLbRange->get_id(nSelectPos).toInt32() == nEntryDataDelim)
+ m_xLbRange->select( --nSelectPos ); // ---Row---
+
+ m_xLbRange->grab_focus();
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(false);
+ m_xEdAssign->SetText( OUString() );
+ theCurArea = theCurData = ScRange();
+ m_xBtnColHead->set_active(true);
+ m_xBtnRowHead->set_active(false);
+ m_xEdAssign2->SetText( OUString() );
+ Range1SelectHdl( *m_xLbRange );
+}
+
+// handler called when a row in the listbox is selected, updates form input fields
+IMPL_LINK_NOARG(ScColRowNameRangesDlg, Range1SelectHdl, weld::TreeView&, void)
+{
+ sal_Int32 nSelectPos = m_xLbRange->get_selected_index();
+ const sal_Int32 nCnt = m_xLbRange->n_children();
+ sal_uInt16 nMoves = 0;
+ while (nSelectPos != -1 && nSelectPos < nCnt && m_xLbRange->get_id(nSelectPos).toInt32() == nEntryDataDelim)
+ { // skip Delimiter
+ ++nMoves;
+ ++nSelectPos;
+ }
+ OUString aRangeStr = m_xLbRange->get_selected_text();
+ if ( nMoves )
+ {
+ if ( nSelectPos > 1 && nSelectPos >= nCnt )
+ { // if entries exist before the " --- Row --- " Delimiter then
+ // do not stop at the delimiter
+ nSelectPos = nCnt - 2;
+ m_xLbRange->select(nSelectPos);
+ aRangeStr = m_xLbRange->get_selected_text();
+ }
+ else if ( nSelectPos > 2 && nSelectPos < nCnt && !aRangeStr.isEmpty()
+ && aRangeStr == m_xEdAssign->GetText() )
+ { // move upwards instead of below to the previous position
+ nSelectPos -= 2;
+ m_xLbRange->select( nSelectPos );
+ aRangeStr = m_xLbRange->get_selected_text();
+ }
+ else
+ m_xLbRange->select(nSelectPos);
+ }
+ NameRangeMap::const_iterator itr = aRangeMap.find(aRangeStr);
+ if ( itr != aRangeMap.end() )
+ {
+ bool bColName = m_xLbRange->get_id(nSelectPos).toInt32() == nEntryDataCol;
+ UpdateRangeData( itr->second, bColName );
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(true);
+ }
+ else
+ {
+ if ( !m_xEdAssign->GetText().isEmpty() )
+ {
+ if ( !m_xEdAssign2->GetText().isEmpty() )
+ m_xBtnAdd->set_sensitive(true);
+ else
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnColHead->set_sensitive(true);
+ m_xBtnRowHead->set_sensitive(true);
+ m_xEdAssign2->GetWidget()->set_sensitive(true);
+ m_xRbAssign2->GetWidget()->set_sensitive(true);
+ }
+ else
+ {
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnColHead->set_sensitive(false);
+ m_xBtnRowHead->set_sensitive(false);
+ m_xEdAssign2->GetWidget()->set_sensitive(false);
+ m_xRbAssign2->GetWidget()->set_sensitive(false);
+ }
+ m_xBtnRemove->set_sensitive(false);
+ m_xEdAssign->GrabFocus();
+ }
+
+ m_xEdAssign->GetWidget()->set_sensitive(true);
+ m_xRbAssign->GetWidget()->set_sensitive(true);
+}
+
+// handler called when the label range has changed
+IMPL_LINK_NOARG(ScColRowNameRangesDlg, Range1DataModifyHdl, formula::RefEdit&, void)
+{
+ OUString aNewArea( m_xEdAssign->GetText() );
+ bool bValid = false;
+ if (!aNewArea.isEmpty())
+ {
+ ScRange aRange;
+ if ( (aRange.ParseAny(aNewArea, rDoc, rDoc.GetAddressConvention() ) & ScRefFlags::VALID) == ScRefFlags::VALID)
+ {
+ SetColRowData( aRange );
+ bValid = true;
+ }
+ }
+ if ( bValid )
+ {
+ m_xBtnAdd->set_sensitive(true);
+ m_xBtnColHead->set_sensitive(true);
+ m_xBtnRowHead->set_sensitive(true);
+ m_xEdAssign2->GetWidget()->set_sensitive(true);
+ m_xRbAssign2->GetWidget()->set_sensitive(true);
+ }
+ else
+ {
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnColHead->set_sensitive(false);
+ m_xBtnRowHead->set_sensitive(false);
+ m_xEdAssign2->GetWidget()->set_sensitive(false);
+ m_xRbAssign2->GetWidget()->set_sensitive(false);
+ }
+ m_xBtnRemove->set_sensitive(false);
+}
+
+// handler called when the data range has changed
+IMPL_LINK_NOARG(ScColRowNameRangesDlg, Range2DataModifyHdl, formula::RefEdit&, void)
+{
+ OUString aNewData( m_xEdAssign2->GetText() );
+ if ( !aNewData.isEmpty() )
+ {
+ ScRange aRange;
+ if ( (aRange.ParseAny(aNewData, rDoc, rDoc.GetAddressConvention() ) & ScRefFlags::VALID) == ScRefFlags::VALID)
+ {
+ AdjustColRowData( aRange );
+ m_xBtnAdd->set_sensitive(true);
+ }
+ else
+ m_xBtnAdd->set_sensitive(false);
+ }
+ else
+ {
+ m_xBtnAdd->set_sensitive(false);
+ }
+}
+
+IMPL_LINK_NOARG(ScColRowNameRangesDlg, ColRowToggleHdl, weld::Toggleable&, void)
+{
+ if (m_xBtnColHead->get_active())
+ {
+ // handler for the radio button for columns, adjust ranges
+ if ( theCurArea.aStart.Row() == 0 && theCurArea.aEnd.Row() == rDoc.MaxRow() )
+ {
+ theCurArea.aEnd.SetRow( rDoc.MaxRow() - 1 );
+ OUString aStr(theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()));
+ m_xEdAssign->SetText( aStr );
+ }
+ ScRange aRange( theCurData );
+ aRange.aStart.SetRow( std::min( static_cast<tools::Long>(theCurArea.aEnd.Row() + 1), static_cast<tools::Long>(rDoc.MaxRow()) ) );
+ aRange.aEnd.SetRow( rDoc.MaxRow() );
+ AdjustColRowData( aRange );
+ }
+ else if (m_xBtnRowHead->get_active())
+ {
+ // handler for the radio button for columns, adjust range
+ if ( theCurArea.aStart.Col() == 0 && theCurArea.aEnd.Col() == rDoc.MaxCol() )
+ {
+ theCurArea.aEnd.SetCol( rDoc.MaxCol() - 1 );
+ OUString aStr(theCurArea.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention()));
+ m_xEdAssign->SetText( aStr );
+ }
+ ScRange aRange( theCurData );
+ aRange.aStart.SetCol( static_cast<SCCOL>(std::min( static_cast<tools::Long>(theCurArea.aEnd.Col() + 1), static_cast<tools::Long>(rDoc.MaxCol()) )) );
+ aRange.aEnd.SetCol( rDoc.MaxCol() );
+ AdjustColRowData( aRange );
+ }
+}
+
+IMPL_LINK( ScColRowNameRangesDlg, GetEditFocusHdl, formula::RefEdit&, rCtrl, void )
+{
+ if (&rCtrl == m_xEdAssign.get())
+ m_pEdActive = m_xEdAssign.get();
+ else if (&rCtrl == m_xEdAssign2.get())
+ m_pEdActive = m_xEdAssign2.get();
+ else
+ m_pEdActive = nullptr;
+
+ if( m_pEdActive )
+ m_pEdActive->SelectAll();
+}
+
+IMPL_LINK( ScColRowNameRangesDlg, GetButtonFocusHdl, formula::RefButton&, rCtrl, void )
+{
+ if (&rCtrl == m_xRbAssign.get())
+ m_pEdActive = m_xEdAssign.get();
+ else if (&rCtrl == m_xRbAssign2.get())
+ m_pEdActive = m_xEdAssign2.get();
+ else
+ m_pEdActive = nullptr;
+
+ if( m_pEdActive )
+ m_pEdActive->SelectAll();
+}
+
+IMPL_LINK_NOARG(ScColRowNameRangesDlg, LoseEditFocusHdl, formula::RefEdit&, void)
+{
+ bDlgLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScColRowNameRangesDlg, LoseButtonFocusHdl, formula::RefButton&, void)
+{
+ bDlgLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/datafdlg.cxx b/sc/source/ui/miscdlgs/datafdlg.cxx
new file mode 100644
index 000000000..0ed421cba
--- /dev/null
+++ b/sc/source/ui/miscdlgs/datafdlg.cxx
@@ -0,0 +1,355 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <datafdlg.hxx>
+#include <viewdata.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+
+ScDataFormDlg::ScDataFormDlg(weld::Window* pParent, ScTabViewShell* pTabViewShellOri)
+ : GenericDialogController(pParent, "modules/scalc/ui/dataform.ui", "DataFormDialog")
+ , pTabViewShell(pTabViewShellOri)
+ , aColLength(0)
+ , nCurrentRow(0)
+ , nStartCol(0)
+ , nEndCol(0)
+ , nStartRow(0)
+ , nEndRow(0)
+ , nTab(0)
+ , m_xBtnNew(m_xBuilder->weld_button("new"))
+ , m_xBtnDelete(m_xBuilder->weld_button("delete"))
+ , m_xBtnRestore(m_xBuilder->weld_button("restore"))
+ , m_xBtnPrev(m_xBuilder->weld_button("prev"))
+ , m_xBtnNext(m_xBuilder->weld_button("next"))
+ , m_xBtnClose(m_xBuilder->weld_button("close"))
+ , m_xSlider(m_xBuilder->weld_scrolled_window("scrollbar", true))
+ , m_xGrid(m_xBuilder->weld_container("grid"))
+ , m_xFixedText(m_xBuilder->weld_label("label"))
+{
+ sNewRecord = m_xFixedText->get_label();
+
+ //read header from current document, and add new controls
+ OSL_ENSURE( pTabViewShell, "pTabViewShell is NULL! :-/" );
+ ScViewData& rViewData = pTabViewShell->GetViewData();
+
+ pDoc = &rViewData.GetDocument();
+
+ {
+ ScRange aRange;
+ rViewData.GetSimpleArea( aRange );
+ ScAddress aStart = aRange.aStart;
+ ScAddress aEnd = aRange.aEnd;
+
+ nStartCol = aStart.Col();
+ nEndCol = aEnd.Col();
+ nStartRow = aStart.Row();
+ nEndRow = aEnd.Row();
+
+ nTab = rViewData.GetTabNo();
+ bool bNoSelection(false);
+ //if there is no selection
+ if ((nStartCol == nEndCol) && (nStartRow == nEndRow))
+ bNoSelection = true;
+
+ if (bNoSelection)
+ {
+ //find last not blank cell in row
+ for (int i=1;i<=MAX_DATAFORM_COLS;i++)
+ {
+ nEndCol++;
+ OUString aColName = pDoc->GetString(nEndCol, nStartRow, nTab);
+ int nColWidth = pDoc->GetColWidth( nEndCol, nTab );
+ if (aColName.isEmpty() && nColWidth)
+ {
+ nEndCol--;
+ break;
+ }
+ }
+
+ //find first not blank cell in row
+ for (int i=1;i<=MAX_DATAFORM_COLS;i++)
+ {
+ if (nStartCol <= 0)
+ break;
+ nStartCol--;
+
+ OUString aColName = pDoc->GetString(nStartCol, nStartRow, nTab);
+ int nColWidth = pDoc->GetColWidth( nEndCol, nTab );
+ if (aColName.isEmpty() && nColWidth)
+ {
+ nStartCol++;
+ break;
+ }
+ }
+
+ //skip leading hide column
+ for (int i=1;i<=MAX_DATAFORM_COLS;i++)
+ {
+ int nColWidth = pDoc->GetColWidth( nStartCol, nTab );
+ if (nColWidth)
+ break;
+ nStartCol++;
+ }
+
+ if (nEndCol < nStartCol)
+ nEndCol = nStartCol;
+
+ //find last not blank cell in row
+ for (int i=1;i<=MAX_DATAFORM_ROWS;i++)
+ {
+ nEndRow++;
+ OUString aColName = pDoc->GetString(nStartCol, nEndRow, nTab);
+ if (aColName.isEmpty())
+ {
+ nEndRow--;
+ break;
+ }
+ }
+
+ //find first not blank cell in row
+ for (int i=1;i<=MAX_DATAFORM_ROWS;i++)
+ {
+ if (nStartRow <= 0)
+ break;
+ nStartRow--;
+
+ OUString aColName = pDoc->GetString(nStartCol, nStartRow, nTab);
+ if (aColName.isEmpty())
+ {
+ nStartRow++;
+ break;
+ }
+ }
+
+ if (nEndRow < nStartRow)
+ nEndRow = nStartRow;
+ }
+
+ nCurrentRow = nStartRow + 1;
+
+ aColLength = nEndCol - nStartCol + 1;
+
+ //new the controls
+ m_aEntries.reserve(aColLength);
+
+ sal_Int32 nGridRow = 0;
+ for(sal_uInt16 nIndex = 0; nIndex < aColLength; ++nIndex)
+ {
+ OUString aFieldName = pDoc->GetString(nIndex + nStartCol, nStartRow, nTab);
+ int nColWidth = pDoc->GetColWidth( nIndex + nStartCol, nTab );
+ if (nColWidth)
+ {
+ m_aEntries.emplace_back(new ScDataFormFragment(m_xGrid.get(), nGridRow));
+
+ ++nGridRow;
+
+ m_aEntries[nIndex]->m_xLabel->set_label(aFieldName);
+ m_aEntries[nIndex]->m_xLabel->show();
+ m_aEntries[nIndex]->m_xEdit->show();
+ }
+ else
+ {
+ m_aEntries.emplace_back(nullptr );
+ }
+ if (m_aEntries[nIndex] != nullptr)
+ {
+ m_aEntries[nIndex]->m_xEdit->connect_changed(LINK( this, ScDataFormDlg, Impl_DataModifyHdl));
+ m_aEntries[nIndex]->m_xEdit->save_value();
+ }
+ }
+ }
+
+ FillCtrls();
+
+ m_xSlider->vadjustment_configure(0, 0, nEndRow - nStartRow + 1, 1, 10, 1);
+
+ m_xBtnNew->connect_clicked(LINK( this, ScDataFormDlg, Impl_NewHdl));
+ m_xBtnPrev->connect_clicked(LINK( this, ScDataFormDlg, Impl_PrevHdl));
+ m_xBtnNext->connect_clicked(LINK( this, ScDataFormDlg, Impl_NextHdl));
+
+ m_xBtnRestore->connect_clicked(LINK( this, ScDataFormDlg, Impl_RestoreHdl));
+ m_xBtnDelete->connect_clicked(LINK( this, ScDataFormDlg, Impl_DeleteHdl));
+ m_xBtnClose->connect_clicked(LINK( this, ScDataFormDlg, Impl_CloseHdl));
+
+ m_xSlider->connect_vadjustment_changed(LINK( this, ScDataFormDlg, Impl_ScrollHdl));
+
+ SetButtonState();
+}
+
+ScDataFormDlg::~ScDataFormDlg()
+{
+}
+
+void ScDataFormDlg::FillCtrls()
+{
+ for (sal_uInt16 i = 0; i < aColLength; ++i)
+ {
+ if (m_aEntries[i])
+ {
+ if (nCurrentRow<=nEndRow && pDoc)
+ {
+ OUString aFieldName(pDoc->GetString(i + nStartCol, nCurrentRow, nTab));
+ m_aEntries[i]->m_xEdit->set_text(aFieldName);
+ }
+ else
+ m_aEntries[i]->m_xEdit->set_text(OUString());
+ }
+ }
+
+ if (nCurrentRow <= nEndRow)
+ {
+ OUString sLabel =
+ OUString::number(static_cast<sal_Int32>(nCurrentRow - nStartRow)) +
+ " / " +
+ OUString::number(static_cast<sal_Int32>(nEndRow - nStartRow));
+ m_xFixedText->set_label(sLabel);
+ }
+ else
+ m_xFixedText->set_label(sNewRecord);
+
+ m_xSlider->vadjustment_set_value(nCurrentRow-nStartRow-1);
+}
+
+IMPL_LINK( ScDataFormDlg, Impl_DataModifyHdl, weld::Entry&, rEdit, void)
+{
+ if (rEdit.get_value_changed_from_saved())
+ m_xBtnRestore->set_sensitive(true);
+}
+
+IMPL_LINK_NOARG(ScDataFormDlg, Impl_NewHdl, weld::Button&, void)
+{
+ ScViewData& rViewData = pTabViewShell->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ if ( !pDoc )
+ return;
+
+ bool bHasData = std::any_of(m_aEntries.begin(), m_aEntries.end(),
+ [](const std::unique_ptr<ScDataFormFragment>& rElem) { return (rElem != nullptr) && (!rElem->m_xEdit->get_text().isEmpty()); });
+
+ if ( !bHasData )
+ return;
+
+ pTabViewShell->DataFormPutData(nCurrentRow, nStartRow, nStartCol, nEndRow, nEndCol, m_aEntries, aColLength);
+ nCurrentRow++;
+ if (nCurrentRow >= nEndRow + 2)
+ {
+ nEndRow++;
+ m_xSlider->vadjustment_set_upper(nEndRow - nStartRow + 1);
+ }
+ SetButtonState();
+ FillCtrls();
+ pDocSh->SetDocumentModified();
+ pDocSh->PostPaintGridAll();
+}
+
+IMPL_LINK_NOARG(ScDataFormDlg, Impl_PrevHdl, weld::Button&, void)
+{
+ if (pDoc)
+ {
+ if ( nCurrentRow > nStartRow +1 )
+ nCurrentRow--;
+
+ SetButtonState();
+ FillCtrls();
+ }
+}
+
+IMPL_LINK_NOARG(ScDataFormDlg, Impl_NextHdl, weld::Button&, void)
+{
+ if (pDoc)
+ {
+ if ( nCurrentRow <= nEndRow)
+ nCurrentRow++;
+
+ SetButtonState();
+ FillCtrls();
+ }
+}
+
+IMPL_LINK_NOARG(ScDataFormDlg, Impl_RestoreHdl, weld::Button&, void)
+{
+ if (pDoc)
+ {
+ FillCtrls();
+ }
+}
+
+IMPL_LINK_NOARG(ScDataFormDlg, Impl_DeleteHdl, weld::Button&, void)
+{
+ ScViewData& rViewData = pTabViewShell->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ if (!pDoc)
+ return;
+
+ ScRange aRange(nStartCol, nCurrentRow, nTab, nEndCol, nCurrentRow, nTab);
+ pDoc->DeleteRow(aRange);
+ nEndRow--;
+
+ SetButtonState();
+ pDocSh->GetUndoManager()->Clear();
+
+ FillCtrls();
+ pDocSh->SetDocumentModified();
+ pDocSh->PostPaintGridAll();
+}
+
+IMPL_LINK_NOARG(ScDataFormDlg, Impl_CloseHdl, weld::Button&, void)
+{
+ m_xDialog->response(RET_CANCEL);
+}
+
+IMPL_LINK_NOARG(ScDataFormDlg, Impl_ScrollHdl, weld::ScrolledWindow&, void)
+{
+ auto nOffset = m_xSlider->vadjustment_get_value();
+ nCurrentRow = nStartRow + nOffset + 1;
+ SetButtonState();
+ FillCtrls();
+}
+
+void ScDataFormDlg::SetButtonState()
+{
+ if (nCurrentRow > nEndRow)
+ {
+ m_xBtnDelete->set_sensitive( false );
+ m_xBtnNext->set_sensitive( false );
+ }
+ else
+ {
+ m_xBtnDelete->set_sensitive(true);
+ m_xBtnNext->set_sensitive(true);
+ }
+
+ if (nCurrentRow == nStartRow + 1)
+ m_xBtnPrev->set_sensitive( false );
+ else
+ m_xBtnPrev->set_sensitive(true);
+
+ m_xBtnRestore->set_sensitive( false );
+ if (!m_aEntries.empty() && m_aEntries[0] != nullptr)
+ m_aEntries[0]->m_xEdit->grab_focus();
+}
+
+ScDataFormFragment::ScDataFormFragment(weld::Container* pGrid, int nLine)
+ : m_xBuilder(Application::CreateBuilder(pGrid, "modules/scalc/ui/dataformfragment.ui"))
+ , m_xLabel(m_xBuilder->weld_label("label"))
+ , m_xEdit(m_xBuilder->weld_entry("entry"))
+{
+ m_xLabel->set_grid_left_attach(0);
+ m_xLabel->set_grid_top_attach(nLine);
+
+ m_xEdit->set_grid_left_attach(1);
+ m_xEdit->set_grid_top_attach(nLine);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/dataproviderdlg.cxx b/sc/source/ui/miscdlgs/dataproviderdlg.cxx
new file mode 100644
index 000000000..f26e2ae7a
--- /dev/null
+++ b/sc/source/ui/miscdlgs/dataproviderdlg.cxx
@@ -0,0 +1,1125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <dataproviderdlg.hxx>
+
+#include <document.hxx>
+#include <dataprovider.hxx>
+#include <datatransformation.hxx>
+#include <datamapper.hxx>
+#include <dbdata.hxx>
+
+#include <comphelper/string.hxx>
+#include <sal/log.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <unotools/charclass.hxx>
+#include <vcl/svapp.hxx>
+
+#include <utility>
+
+class ScDataTransformationBaseControl
+{
+protected:
+ std::unique_ptr<weld::Builder> mxBuilder;
+ std::unique_ptr<weld::Container> mxGrid;
+ weld::Container* mpContainer;
+
+ sal_uInt32 mnIndex;
+
+public:
+ ScDataTransformationBaseControl(weld::Container* pParent, const OUString& rUIFile, sal_uInt32 nIndex);
+ virtual ~ScDataTransformationBaseControl();
+
+ void updateIndex(sal_uInt32 nIndex) { mnIndex = nIndex; }
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() = 0;
+
+ static SCROW getLastRow(const ScDocument& rDoc);
+ static SCCOL getLastCol(const ScDocument& rDoc);
+};
+
+SCROW ScDataTransformationBaseControl::getLastRow(const ScDocument& rDoc)
+{
+ SCROW nEndRow = rDoc.MaxRow();
+ return rDoc.GetLastDataRow(0, 0, 0, nEndRow);
+}
+
+SCCOL ScDataTransformationBaseControl::getLastCol(const ScDocument& rDoc)
+{
+ for (SCCOL nCol = 1; nCol <= rDoc.MaxCol(); ++nCol)
+ {
+ if (rDoc.GetCellType(nCol, 0, 0) == CELLTYPE_NONE)
+ {
+ return static_cast<SCCOL>(nCol - 1 );
+ }
+ }
+ return rDoc.MaxCol();
+}
+
+ScDataTransformationBaseControl::ScDataTransformationBaseControl(weld::Container* pParent, const OUString& rUIFile, sal_uInt32 nIndex)
+ : mxBuilder(Application::CreateBuilder(pParent, rUIFile))
+ , mxGrid(mxBuilder->weld_container("grid"))
+ , mpContainer(pParent)
+ , mnIndex(nIndex)
+{
+}
+
+ScDataTransformationBaseControl::~ScDataTransformationBaseControl()
+{
+ mpContainer->move(mxGrid.get(), nullptr);
+}
+
+namespace {
+
+struct MenuData
+{
+ const char* aTransformationName;
+ std::function<void(ScDataProviderDlg*)> maCallback;
+};
+
+MenuData aTransformationData[] = {
+ { "Delete Column", &ScDataProviderDlg::deleteColumn },
+ { "Delete Row", &ScDataProviderDlg::deleteRowTransformation},
+ { "Swap Rows", &ScDataProviderDlg::swapRowsTransformation},
+ { "Split Column", &ScDataProviderDlg::splitColumn },
+ { "Merge Columns", &ScDataProviderDlg::mergeColumns },
+ { "Text Transformation", &ScDataProviderDlg::textTransformation },
+ { "Sort Columns", &ScDataProviderDlg::sortTransformation },
+ { "Aggregate Functions", &ScDataProviderDlg::aggregateFunction},
+ { "Number Transformations", &ScDataProviderDlg::numberTransformation },
+ { "Replace Null Transformations", &ScDataProviderDlg::replaceNullTransformation },
+ { "Date & Time Transformations", &ScDataProviderDlg::dateTimeTransformation },
+ { "Find Replace Transformation", &ScDataProviderDlg::findReplaceTransformation}
+};
+
+class ScDeleteColumnTransformationControl : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::Entry> mxColumnNums;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument* mpDoc;
+
+public:
+ ScDeleteColumnTransformationControl(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 aIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScDeleteColumnTransformationControl::ScDeleteColumnTransformationControl(
+ const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/deletecolumnentry.ui", nIndex)
+ , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(std::move(aDeleteTransformation))
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this,ScDeleteColumnTransformationControl, DeleteHdl));
+}
+
+std::shared_ptr<sc::DataTransformation> ScDeleteColumnTransformationControl::getTransformation()
+{
+ OUString aColumnString = mxColumnNums->get_text();
+ std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
+ std::set<SCCOL> ColNums;
+ for (const auto& rColStr : aSplitColumns)
+ {
+ sal_Int32 nCol = rColStr.toInt32();
+ if (nCol <= 0)
+ continue;
+
+ if (nCol > mpDoc->MaxCol())
+ continue;
+
+ // translate from 1-based column notations to internal Calc one
+ ColNums.insert(nCol - 1);
+ }
+
+ return std::make_shared<sc::ColumnRemoveTransformation>(std::move(ColNums));
+}
+
+class ScSplitColumnTransformationControl : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::Entry> mxSeparator;
+ std::unique_ptr<weld::Entry> mxNumColumns;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument* mpDoc;
+
+public:
+ ScSplitColumnTransformationControl(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScSplitColumnTransformationControl::ScSplitColumnTransformationControl(
+ const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex,
+ std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/splitcolumnentry.ui", nIndex)
+ , mxSeparator(mxBuilder->weld_entry("ed_separator"))
+ , mxNumColumns(mxBuilder->weld_entry("num_cols"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(std::move(aDeleteTransformation))
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this,ScSplitColumnTransformationControl, DeleteHdl));
+}
+
+std::shared_ptr<sc::DataTransformation> ScSplitColumnTransformationControl::getTransformation()
+{
+ OUString aSeparator = mxSeparator->get_text();
+ sal_Unicode cSeparator = aSeparator.isEmpty() ? ',' : aSeparator[0];
+ OUString aColStr = mxNumColumns->get_text();
+ SCCOL mnCol = -1;
+ sal_Int32 nCol = aColStr.toInt32();
+ if (nCol > 0 && nCol <= mpDoc->MaxCol())
+ mnCol = nCol - 1;
+ return std::make_shared<sc::SplitColumnTransformation>(mnCol, cSeparator);
+}
+
+class ScMergeColumnTransformationControl : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::Entry> mxSeparator;
+ std::unique_ptr<weld::Entry> mxEdColumns;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument* mpDoc;
+
+public:
+ ScMergeColumnTransformationControl(const ScDocument *pDoc, weld::Container* pParent, SCCOL nStartCol, SCCOL nEndCol, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScMergeColumnTransformationControl::ScMergeColumnTransformationControl(
+ const ScDocument* pDoc, weld::Container* pParent, SCCOL nStartCol, SCCOL nEndCol, sal_uInt32 nIndex,
+ std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/mergecolumnentry.ui", nIndex)
+ , mxSeparator(mxBuilder->weld_entry("ed_separator"))
+ , mxEdColumns(mxBuilder->weld_entry("ed_columns"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(std::move(aDeleteTransformation))
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this,ScMergeColumnTransformationControl, DeleteHdl));
+
+ OUStringBuffer aBuffer;
+
+ // map from zero based to one based column numbers
+ aBuffer.append(static_cast<sal_Int32>(nStartCol + 1));
+ for ( SCCOL nCol = nStartCol + 1; nCol <= nEndCol; ++nCol)
+ {
+ aBuffer.append(";" + OUString::number(nCol + 1));
+ }
+
+ mxEdColumns->set_text(aBuffer.makeStringAndClear());
+}
+
+std::shared_ptr<sc::DataTransformation> ScMergeColumnTransformationControl::getTransformation()
+{
+ OUString aColumnString = mxEdColumns->get_text();
+ std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
+ std::set<SCCOL> aMergedColumns;
+ for (const auto& rColStr : aSplitColumns)
+ {
+ sal_Int32 nCol = rColStr.toInt32();
+ if (nCol <= 0)
+ continue;
+
+ if (nCol > mpDoc->MaxCol())
+ continue;
+
+ // translate from 1-based column notations to internal Calc one
+ aMergedColumns.insert(nCol - 1);
+ }
+ return std::make_shared<sc::MergeColumnTransformation>(std::move(aMergedColumns), mxSeparator->get_text());
+}
+
+class ScSortTransformationControl : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::ComboBox> mxType;
+ std::unique_ptr<weld::Entry> mxEdColumns;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument* mpDoc;
+
+public:
+ ScSortTransformationControl(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScSortTransformationControl::ScSortTransformationControl(
+ const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/sorttransformationentry.ui", nIndex)
+ , mxType(mxBuilder->weld_combo_box("ed_ascending"))
+ , mxEdColumns(mxBuilder->weld_entry("ed_columns"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(std::move(aDeleteTransformation))
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this,ScSortTransformationControl, DeleteHdl));
+}
+
+std::shared_ptr<sc::DataTransformation> ScSortTransformationControl::getTransformation()
+{
+ OUString aColStr = mxEdColumns->get_text();
+ bool aIsAscending = mxType->get_active();
+ SCCOL aColumn = 0;
+ sal_Int32 nCol = aColStr.toInt32();
+ if (nCol > 0 && nCol <= mpDoc->MaxCol())
+ aColumn = nCol - 1; // translate from 1-based column notations to internal Calc one
+
+ ScSortParam aSortParam;
+ aSortParam.nRow1=0;
+ aSortParam.nRow2=getLastRow(*mpDoc);
+ aSortParam.nCol1=0;
+ aSortParam.nCol2=getLastCol(*mpDoc);
+ aSortParam.maKeyState[0].bDoSort = true;
+ aSortParam.maKeyState[0].nField = aColumn;
+ aSortParam.maKeyState[0].bAscending = aIsAscending;
+ return std::make_shared<sc::SortTransformation>(aSortParam);
+}
+
+class ScColumnTextTransformation : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::Entry> mxColumnNums;
+ std::unique_ptr<weld::ComboBox> mxType;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument* mpDoc;
+
+public:
+ ScColumnTextTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScColumnTextTransformation::ScColumnTextTransformation(
+ const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/texttransformationentry.ui", nIndex)
+ , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
+ , mxType(mxBuilder->weld_combo_box("ed_lst"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(std::move(aDeleteTransformation))
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this,ScColumnTextTransformation, DeleteHdl));
+}
+
+std::shared_ptr<sc::DataTransformation> ScColumnTextTransformation::getTransformation()
+{
+ OUString aColumnString = mxColumnNums->get_text();
+ std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
+ std::set<SCCOL> aColumns;
+ for (const auto& rColStr : aSplitColumns)
+ {
+ sal_Int32 nCol = rColStr.toInt32();
+ if (nCol <= 0)
+ continue;
+
+ if (nCol > mpDoc->MaxCol())
+ continue;
+
+ // translate from 1-based column notations to internal Calc one
+ aColumns.insert(nCol - 1);
+ }
+
+ sal_Int32 nPos = mxType->get_active();
+ switch (nPos)
+ {
+ case 0:
+ return std::make_shared<sc::TextTransformation>(std::move(aColumns),sc::TEXT_TRANSFORM_TYPE::TO_LOWER);
+ case 1:
+ return std::make_shared<sc::TextTransformation>(std::move(aColumns),sc::TEXT_TRANSFORM_TYPE::TO_UPPER);
+ case 2:
+ return std::make_shared<sc::TextTransformation>(std::move(aColumns),sc::TEXT_TRANSFORM_TYPE::CAPITALIZE);
+ case 3:
+ return std::make_shared<sc::TextTransformation>(std::move(aColumns),sc::TEXT_TRANSFORM_TYPE::TRIM);
+ default:
+ assert(false);
+ }
+
+ return nullptr;
+}
+
+class ScAggregateFunction : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::Entry> mxColumnNums;
+ std::unique_ptr<weld::ComboBox> mxType;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument* mpDoc;
+
+public:
+ ScAggregateFunction(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScAggregateFunction::ScAggregateFunction(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex,
+ std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/aggregatefunctionentry.ui", nIndex)
+ , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
+ , mxType(mxBuilder->weld_combo_box("ed_lst"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(std::move(aDeleteTransformation))
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this,ScAggregateFunction, DeleteHdl));
+}
+
+std::shared_ptr<sc::DataTransformation> ScAggregateFunction::getTransformation()
+{
+ OUString aColumnString = mxColumnNums->get_text();
+ sal_Int32 nPos = mxType->get_active();
+ std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
+ std::set<SCCOL> aColumns;
+ for (const auto& rColStr : aSplitColumns)
+ {
+ sal_Int32 nCol = rColStr.toInt32();
+ if (nCol <= 0)
+ continue;
+
+ if (nCol > mpDoc->MaxCol())
+ continue;
+
+ // translate from 1-based column notations to internal Calc one
+ aColumns.insert(nCol - 1);
+ }
+ switch (nPos)
+ {
+ case 0:
+ return std::make_shared<sc::AggregateFunction>(std::move(aColumns),sc::AGGREGATE_FUNCTION::SUM);
+ case 1:
+ return std::make_shared<sc::AggregateFunction>(std::move(aColumns),sc::AGGREGATE_FUNCTION::AVERAGE);
+ case 2:
+ return std::make_shared<sc::AggregateFunction>(std::move(aColumns),sc::AGGREGATE_FUNCTION::MIN);
+ case 3:
+ return std::make_shared<sc::AggregateFunction>(std::move(aColumns),sc::AGGREGATE_FUNCTION::MAX);
+ default:
+ assert(false);
+ }
+
+ return nullptr;
+}
+
+class ScNumberTransformation : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::Entry> mxColumnNums;
+ std::unique_ptr<weld::ComboBox> mxType;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument* mpDoc;
+
+public:
+ ScNumberTransformation(const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScNumberTransformation::ScNumberTransformation(
+ const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/numbertransformationentry.ui", nIndex)
+ , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
+ , mxType(mxBuilder->weld_combo_box("ed_lst"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(std::move(aDeleteTransformation))
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this,ScNumberTransformation, DeleteHdl));
+}
+
+std::shared_ptr<sc::DataTransformation> ScNumberTransformation::getTransformation()
+{
+ OUString aColumnString = mxColumnNums->get_text();
+ sal_Int32 nPos = mxType->get_active();
+ std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
+ std::set<SCCOL> aColumns;
+ for (const auto& rColStr : aSplitColumns)
+ {
+ sal_Int32 nCol = rColStr.toInt32();
+ if (nCol <= 0)
+ continue;
+
+ if (nCol > mpDoc->MaxCol())
+ continue;
+
+ // translate from 1-based column notations to internal Calc one
+ aColumns.insert(nCol - 1);
+ }
+ switch (nPos)
+ {
+ case 0:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::SIGN);
+ case 1:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::ROUND);
+ case 2:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::ROUND_UP);
+ case 3:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::ROUND_DOWN);
+ case 4:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::ABSOLUTE);
+ case 5:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::LOG_E);
+ case 6:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::LOG_10);
+ case 7:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::CUBE);
+ case 8:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::SQUARE);
+ case 9:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::SQUARE_ROOT);
+ case 10:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::EXPONENT);
+ case 11:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::IS_EVEN);
+ case 12:
+ return std::make_shared<sc::NumberTransformation>(std::move(aColumns),sc::NUMBER_TRANSFORM_TYPE::IS_ODD);
+ default:
+ assert(false);
+ }
+
+ return nullptr;
+}
+
+class ScReplaceNullTransformation : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::Entry> mxColumnNums;
+ std::unique_ptr<weld::Entry> mxReplaceString;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument *mpDoc;
+
+public:
+
+ ScReplaceNullTransformation(const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScReplaceNullTransformation::ScReplaceNullTransformation(const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent,"modules/scalc/ui/replacenulltransformationentry.ui", nIndex)
+ , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
+ , mxReplaceString(mxBuilder->weld_entry("ed_str"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(aDeleteTransformation)
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this,ScReplaceNullTransformation, DeleteHdl));
+}
+
+
+std::shared_ptr<sc::DataTransformation> ScReplaceNullTransformation::getTransformation()
+{
+ OUString aColumnString = mxColumnNums->get_text();
+ OUString aReplaceWithString = mxReplaceString->get_text();
+ std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
+ std::set<SCCOL> aColumns;
+ for (const auto& rColStr : aSplitColumns)
+ {
+ sal_Int32 nCol = rColStr.toInt32();
+ if (nCol <= 0)
+ continue;
+
+ if (nCol > mpDoc->MaxCol())
+ continue;
+
+ // translate from 1-based column notations to internal Calc one
+ aColumns.insert(nCol - 1);
+ }
+
+ return std::make_shared<sc::ReplaceNullTransformation>(std::move(aColumns),aReplaceWithString);
+}
+
+class ScDateTimeTransformation : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::Entry> mxColumnNums;
+ std::unique_ptr<weld::ComboBox> mxType;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument* mpDoc;
+
+public:
+
+ ScDateTimeTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScDateTimeTransformation::ScDateTimeTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent,"modules/scalc/ui/datetimetransformationentry.ui", nIndex)
+ , mxColumnNums(mxBuilder->weld_entry("ed_columns"))
+ , mxType(mxBuilder->weld_combo_box("ed_lst"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(aDeleteTransformation)
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this,ScDateTimeTransformation, DeleteHdl));
+}
+
+std::shared_ptr<sc::DataTransformation> ScDateTimeTransformation::getTransformation()
+{
+ OUString aColumnString = mxColumnNums->get_text();
+ sal_Int32 nPos = mxType->get_active();
+ std::vector<OUString> aSplitColumns = comphelper::string::split(aColumnString, ';');
+ std::set<SCCOL> aColumns;
+ for (const auto& rColStr : aSplitColumns)
+ {
+ sal_Int32 nCol = rColStr.toInt32();
+ if (nCol <= 0)
+ continue;
+
+ if (nCol > mpDoc->MaxCol())
+ continue;
+
+ // translate from 1-based column notations to internal Calc one
+ aColumns.insert(nCol - 1);
+ }
+ switch (nPos)
+ {
+ case 0:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::DATE_STRING);
+ case 1:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::YEAR);
+ case 2:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::START_OF_YEAR);
+ case 3:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::END_OF_YEAR);
+ case 4:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::MONTH);
+ case 5:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::MONTH_NAME);
+ case 6:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::START_OF_MONTH);
+ case 7:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::END_OF_MONTH);
+ case 8:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::DAY);
+ case 9:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_WEEK);
+ case 10:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::DAY_OF_YEAR);
+ case 11:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::QUARTER);
+ case 12:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::START_OF_QUARTER);
+ case 13:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::END_OF_QUARTER);
+ case 14:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::HOUR);
+ case 15:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::MINUTE);
+ case 16:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::SECOND);
+ case 17:
+ return std::make_shared<sc::DateTimeTransformation>(std::move(aColumns),sc::DATETIME_TRANSFORMATION_TYPE::TIME);
+ default:
+ assert(false);
+ }
+
+ return nullptr;
+}
+
+class ScFindReplaceTransformation : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::Entry> mxFindString;
+ std::unique_ptr<weld::Entry> mxReplaceString;
+ std::unique_ptr<weld::Entry> mxEdColumns;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument* mpDoc;
+
+public:
+ ScFindReplaceTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScFindReplaceTransformation::ScFindReplaceTransformation(
+ const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex,
+ std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/findreplaceentry.ui", nIndex)
+ , mxFindString(mxBuilder->weld_entry("ed_find"))
+ , mxReplaceString(mxBuilder->weld_entry("ed_replace"))
+ , mxEdColumns(mxBuilder->weld_entry("ed_columns"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(std::move(aDeleteTransformation))
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this, ScFindReplaceTransformation, DeleteHdl));
+}
+
+std::shared_ptr<sc::DataTransformation> ScFindReplaceTransformation::getTransformation()
+{
+ OUString aColStr = mxEdColumns->get_text();
+ SCCOL aColumn = -1;
+ sal_Int32 nCol = aColStr.toInt32();
+ if (nCol > 0 && nCol <= mpDoc->MaxCol())
+ aColumn = nCol - 1;
+ return std::make_shared<sc::FindReplaceTransformation>(aColumn, mxFindString->get_text(), mxReplaceString->get_text());
+}
+
+class ScDeleteRowTransformation : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::Entry> mxFindString;
+ std::unique_ptr<weld::Entry> mxEdColumns;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument* mpDoc;
+
+public:
+ ScDeleteRowTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScDeleteRowTransformation::ScDeleteRowTransformation(
+ const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex,
+ std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/deleterowentry.ui", nIndex)
+ , mxFindString(mxBuilder->weld_entry("ed_find"))
+ , mxEdColumns(mxBuilder->weld_entry("ed_columns"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(std::move(aDeleteTransformation))
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this, ScDeleteRowTransformation, DeleteHdl));
+}
+
+std::shared_ptr<sc::DataTransformation> ScDeleteRowTransformation::getTransformation()
+{
+ OUString aColStr = mxEdColumns->get_text();
+ SCCOL aColumn = -1;
+ sal_Int32 nCol = aColStr.toInt32();
+ if (nCol > 0 && nCol <= mpDoc->MaxCol())
+ aColumn = nCol - 1;
+ return std::make_shared<sc::DeleteRowTransformation>(aColumn, mxFindString->get_text());
+}
+
+class ScSwapRowsTransformation : public ScDataTransformationBaseControl
+{
+private:
+ std::unique_ptr<weld::Entry> mxRow;
+ std::unique_ptr<weld::Entry> nxRow;
+ std::unique_ptr<weld::Button> mxDelete;
+ std::function<void(sal_uInt32&)> maDeleteTransformation;
+ const ScDocument* mpDoc;
+
+public:
+ ScSwapRowsTransformation(const ScDocument* pDoc, weld::Container* pParent, sal_uInt32 nIndex, std::function<void(sal_uInt32&)> aDeleteTransformation);
+
+ virtual std::shared_ptr<sc::DataTransformation> getTransformation() override;
+ DECL_LINK(DeleteHdl, weld::Button&, void);
+};
+
+ScSwapRowsTransformation::ScSwapRowsTransformation(
+ const ScDocument *pDoc, weld::Container* pParent, sal_uInt32 nIndex,
+ std::function<void(sal_uInt32&)> aDeleteTransformation)
+ : ScDataTransformationBaseControl(pParent, "modules/scalc/ui/swaprowsentry.ui", nIndex)
+ , mxRow(mxBuilder->weld_entry("ed_row1"))
+ , nxRow(mxBuilder->weld_entry("ed_row2"))
+ , mxDelete(mxBuilder->weld_button("ed_delete"))
+ , maDeleteTransformation(std::move(aDeleteTransformation))
+ , mpDoc(pDoc)
+{
+ mxDelete->connect_clicked(LINK(this, ScSwapRowsTransformation, DeleteHdl));
+}
+
+std::shared_ptr<sc::DataTransformation> ScSwapRowsTransformation::getTransformation()
+{
+ OUString aRowStr = mxRow->get_text();
+ OUString bRowStr = nxRow->get_text();
+ SCROW aRow = -1;
+ SCROW bRow = -1;
+ sal_Int32 mRow = aRowStr.toInt32();
+ sal_Int32 nRow = bRowStr.toInt32();
+ if (mRow > 0 && mRow <= mpDoc->MaxRow())
+ aRow = mRow - 1;
+ if (nRow > 0 && nRow <= mpDoc->MaxRow())
+ bRow = nRow - 1;
+ return std::make_shared<sc::SwapRowsTransformation>(aRow, bRow);
+}
+
+}
+
+ScDataProviderDlg::ScDataProviderDlg(weld::Window* pParent, std::shared_ptr<ScDocument> pDoc,
+ const ScDocument* pDocument)
+ : GenericDialogController(pParent, "modules/scalc/ui/dataproviderdlg.ui", "dataproviderdlg")
+ , mxDoc(std::move(pDoc))
+ , mxBox(m_xBuilder->weld_container("data_table"))
+ , m_xTableParent(mxBox->CreateChildFrame())
+ , mxTable(VclPtr<ScDataTableView>::Create(m_xTableParent, mxDoc))
+ , mxDBRanges(m_xBuilder->weld_combo_box("select_db_range"))
+ , mxOKBtn(m_xBuilder->weld_button("okay"))
+ , mxCancelBtn(m_xBuilder->weld_button("cancel"))
+ , mxAddTransformationBtn(m_xBuilder->weld_button("add_transformation"))
+ , mxScroll(m_xBuilder->weld_scrolled_window("scroll"))
+ , mxTransformationList(m_xBuilder->weld_container("transformation_ctrl"))
+ , mxTransformationBox(m_xBuilder->weld_combo_box("transformation_box"))
+ , mxProviderList(m_xBuilder->weld_combo_box("provider_lst"))
+ , mxEditURL(m_xBuilder->weld_entry("ed_url"))
+ , mxEditID(m_xBuilder->weld_entry("ed_id"))
+ , mxApplyBtn(m_xBuilder->weld_button("apply"))
+ , mxBrowseBtn(m_xBuilder->weld_button("browse"))
+ , maIdle("ScDataProviderDlg maIdle")
+ , mnIndex(0)
+{
+ Size aPrefSize = mxTable->GetOptimalSize();
+ mxBox->set_size_request(aPrefSize.Width(), aPrefSize.Height());
+ mxTable->Show();
+
+ ScDBCollection* pDBCollection = pDocument->GetDBCollection();
+ auto& rNamedDBs = pDBCollection->getNamedDBs();
+ for (auto& rNamedDB : rNamedDBs)
+ {
+ mxDBRanges->append_text(rNamedDB->GetName());
+ }
+
+ for (const auto& i : aTransformationData)
+ {
+ mxTransformationBox->append_text(OUString::createFromAscii(i.aTransformationName));
+ }
+
+ pDBData = new ScDBData("data", 0, 0, 0, mxDoc->MaxCol(), mxDoc->MaxRow());
+ bool bSuccess = mxDoc->GetDBCollection()->getNamedDBs().insert(std::unique_ptr<ScDBData>(pDBData));
+ SAL_WARN_IF(!bSuccess, "sc", "temporary warning");
+
+ auto aDataProvider = sc::DataProviderFactory::getDataProviders();
+ for (const auto& rDataProvider : aDataProvider)
+ {
+ mxProviderList->append_text(rDataProvider);
+ }
+
+ mxOKBtn->connect_clicked(LINK(this, ScDataProviderDlg, ApplyQuitHdl));
+ mxCancelBtn->connect_clicked(LINK(this, ScDataProviderDlg, CancelQuitHdl));
+ mxAddTransformationBtn->connect_clicked(LINK(this, ScDataProviderDlg, TransformationListHdl));
+ mxApplyBtn->connect_clicked(LINK(this, ScDataProviderDlg, ApplyBtnHdl));
+ mxBrowseBtn->connect_clicked(LINK(this, ScDataProviderDlg, BrowseBtnHdl));
+ mxTransformationBox->connect_changed(LINK(this, ScDataProviderDlg, TransformationSelectHdl));
+ mxProviderList->connect_changed(LINK(this, ScDataProviderDlg, ProviderSelectHdl));
+ mxEditID->connect_changed(LINK(this, ScDataProviderDlg, IDEditHdl));
+ mxEditURL->connect_changed(LINK(this, ScDataProviderDlg, URLEditHdl));
+
+ msApplyTooltip = mxApplyBtn->get_tooltip_text();
+ msAddTransformationToolTip = mxAddTransformationBtn->get_tooltip_text();
+ mxAddTransformationBtn->set_sensitive(false);
+ mxAddTransformationBtn->set_tooltip_text(OUString());
+ isValid();
+
+ maIdle.SetPriority( TaskPriority::LOWEST );
+ maIdle.SetInvokeHandler( LINK( this, ScDataProviderDlg, ScrollToEnd) );
+}
+
+ScDataProviderDlg::~ScDataProviderDlg()
+{
+ mxTable.disposeAndClear();
+ m_xTableParent->dispose();
+ m_xTableParent.clear();
+}
+
+IMPL_LINK_NOARG(ScDataProviderDlg, ScrollToEnd, Timer*, void)
+{
+ mxScroll->vadjustment_set_value(mxScroll->vadjustment_get_upper());
+}
+
+IMPL_LINK_NOARG(ScDataProviderDlg, ApplyQuitHdl, weld::Button&, void)
+{
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ScDataProviderDlg, CancelQuitHdl, weld::Button&, void)
+{
+ m_xDialog->response(RET_CANCEL);
+}
+
+IMPL_LINK_NOARG(ScDataProviderDlg, TransformationListHdl, weld::Button&, void)
+{
+ OUString transformation_string = mxTransformationBox->get_active_text();
+ for (auto& i: aTransformationData)
+ {
+ if (transformation_string == OUString::createFromAscii(i.aTransformationName))
+ {
+ i.maCallback(this);
+ maIdle.Start();
+ return;
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ScDataProviderDlg, ProviderSelectHdl, weld::ComboBox&, void)
+{
+ isValid();
+}
+
+IMPL_LINK_NOARG(ScDataProviderDlg, IDEditHdl, weld::Entry&, void)
+{
+ isValid();
+}
+
+IMPL_LINK_NOARG(ScDataProviderDlg, URLEditHdl, weld::Entry&, void)
+{
+ isValid();
+}
+
+IMPL_LINK_NOARG(ScDataProviderDlg, ApplyBtnHdl, weld::Button&, void)
+{
+ updateApplyBtn(true);
+ import(*mxDoc, true);
+}
+
+IMPL_LINK_NOARG(ScDataProviderDlg, BrowseBtnHdl, weld::Button&, void)
+{
+ sfx2::FileDialogHelper aFileDialog(0, FileDialogFlags::NONE, m_xDialog.get());
+ aFileDialog.SetContext(sfx2::FileDialogHelper::CalcDataProvider);
+ if (aFileDialog.Execute() != ERRCODE_NONE)
+ return;
+
+ mxEditURL->set_text(aFileDialog.GetPath());
+ isValid();
+}
+
+IMPL_LINK_NOARG(ScDataProviderDlg, TransformationSelectHdl, weld::ComboBox&, void)
+{
+ mxAddTransformationBtn->set_sensitive(true);
+ mxAddTransformationBtn->set_tooltip_text(msAddTransformationToolTip);
+}
+
+sc::ExternalDataSource ScDataProviderDlg::getDataSource(ScDocument* pDoc)
+{
+ OUString aURL = mxEditURL->get_text();
+ OUString aProvider = mxProviderList->get_active_text();
+ sc::ExternalDataSource aSource(aURL, aProvider, pDoc);
+
+ OUString aID = mxEditID->get_text();
+ aSource.setID(aID);
+ return aSource;
+}
+
+void ScDataProviderDlg::isValid()
+{
+ bool bValid = !mxProviderList->get_active_text().isEmpty();
+ bValid &= !mxEditURL->get_text().isEmpty();
+ updateApplyBtn(bValid);
+}
+
+void ScDataProviderDlg::updateApplyBtn(bool bValidConfig)
+{
+ if (!bValidConfig)
+ {
+ mxApplyBtn->set_sensitive(false);
+ mxApplyBtn->set_tooltip_text(OUString());
+ return;
+ }
+
+ mxApplyBtn->set_sensitive(true);
+ mxApplyBtn->set_tooltip_text(msApplyTooltip);
+}
+
+void ScDataProviderDlg::deleteColumn()
+{
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScDeleteColumnTransformationControl>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation));
+}
+
+void ScDataProviderDlg::splitColumn()
+{
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScSplitColumnTransformationControl>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation));
+}
+
+void ScDataProviderDlg::mergeColumns()
+{
+ SCCOL nStartCol = -1;
+ SCCOL nEndCol = -1;
+ mxTable->getColRange(nStartCol, nEndCol);
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScMergeColumnTransformationControl>(mxDoc.get(), mxTransformationList.get(), nStartCol, nEndCol, mnIndex++, adeleteTransformation));
+}
+
+void ScDataProviderDlg::textTransformation()
+{
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScColumnTextTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation));
+}
+
+void ScDataProviderDlg::sortTransformation()
+{
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScSortTransformationControl>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation));
+}
+
+void ScDataProviderDlg::aggregateFunction()
+{
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScAggregateFunction>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation));
+}
+
+void ScDataProviderDlg::numberTransformation()
+{
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScNumberTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation));
+}
+
+void ScDataProviderDlg::replaceNullTransformation()
+{
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScReplaceNullTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation));
+}
+
+void ScDataProviderDlg::dateTimeTransformation()
+{
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList,this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScDateTimeTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation));
+}
+
+void ScDataProviderDlg::findReplaceTransformation()
+{
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList, this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScFindReplaceTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation));
+}
+
+void ScDataProviderDlg::deleteRowTransformation()
+{
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList, this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScDeleteRowTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation));
+}
+
+void ScDataProviderDlg::swapRowsTransformation()
+{
+ std::function<void(sal_uInt32&)> adeleteTransformation = std::bind(&ScDataProviderDlg::deletefromList, this, std::placeholders::_1);
+ maControls.emplace_back(std::make_unique<ScSwapRowsTransformation>(mxDoc.get(), mxTransformationList.get(), mnIndex++, adeleteTransformation));
+}
+
+namespace {
+
+bool hasDBName(const OUString& rName, ScDBCollection* pDBCollection)
+{
+ if (pDBCollection->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rName)))
+ return true;
+
+ return false;
+}
+
+}
+
+void ScDataProviderDlg::import(ScDocument& rDoc, bool bInternal)
+{
+ sc::ExternalDataSource aSource = getDataSource(&rDoc);
+
+ for (size_t i = 0; i < maControls.size(); ++i)
+ {
+ ScDataTransformationBaseControl* pTransformationCtrl = maControls[i].get();
+ aSource.AddDataTransformation(pTransformationCtrl->getTransformation());
+ }
+ if (bInternal)
+ aSource.setDBData(pDBData->GetName());
+ else
+ {
+ aSource.setDBData(mxDBRanges->get_active_text());
+ if (!hasDBName(aSource.getDBName(), rDoc.GetDBCollection()))
+ return;
+ rDoc.GetExternalDataMapper().insertDataSource(aSource);
+ }
+ aSource.refresh(&rDoc, true);
+ mxTable->Invalidate();
+}
+
+void ScDataProviderDlg::deletefromList(sal_uInt32 nIndex)
+{
+ auto itr = maControls.erase(maControls.begin() + nIndex);
+ while (itr != maControls.end())
+ {
+ (*itr)->updateIndex(nIndex++);
+ ++itr;
+ }
+ --mnIndex;
+}
+
+IMPL_LINK_NOARG(ScDeleteColumnTransformationControl, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+
+IMPL_LINK_NOARG(ScSplitColumnTransformationControl, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+
+IMPL_LINK_NOARG(ScMergeColumnTransformationControl, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+
+IMPL_LINK_NOARG(ScNumberTransformation, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+
+IMPL_LINK_NOARG(ScAggregateFunction, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+
+IMPL_LINK_NOARG(ScSortTransformationControl, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+
+IMPL_LINK_NOARG(ScColumnTextTransformation, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+
+IMPL_LINK_NOARG(ScReplaceNullTransformation, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+
+IMPL_LINK_NOARG(ScDateTimeTransformation, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+
+IMPL_LINK_NOARG(ScFindReplaceTransformation, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+
+IMPL_LINK_NOARG(ScDeleteRowTransformation, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+
+IMPL_LINK_NOARG(ScSwapRowsTransformation, DeleteHdl, weld::Button&, void)
+{
+ maDeleteTransformation(mnIndex);
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/datastreamdlg.cxx b/sc/source/ui/miscdlgs/datastreamdlg.cxx
new file mode 100644
index 000000000..cd03a3e66
--- /dev/null
+++ b/sc/source/ui/miscdlgs/datastreamdlg.cxx
@@ -0,0 +1,178 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <datastreamdlg.hxx>
+
+#include <sfx2/filedlghelper.hxx>
+#include <svtools/inettbc.hxx>
+#include <address.hxx>
+#include <docsh.hxx>
+#include <datastream.hxx>
+
+namespace sc
+{
+DataStreamDlg::DataStreamDlg(ScDocShell* pDocShell, weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/datastreams.ui", "DataStreamDialog")
+ , m_pDocShell(pDocShell)
+ , m_xCbUrl(new SvtURLBox(m_xBuilder->weld_combo_box("url")))
+ , m_xBtnBrowse(m_xBuilder->weld_button("browse"))
+ , m_xRBValuesInLine(m_xBuilder->weld_radio_button("valuesinline"))
+ , m_xRBAddressValue(m_xBuilder->weld_radio_button("addressvalue"))
+ , m_xCBRefreshOnEmpty(m_xBuilder->weld_check_button("refresh_ui"))
+ , m_xRBDataDown(m_xBuilder->weld_radio_button("datadown"))
+ , m_xRBRangeDown(m_xBuilder->weld_radio_button("rangedown"))
+ , m_xRBNoMove(m_xBuilder->weld_radio_button("nomove"))
+ , m_xRBMaxLimit(m_xBuilder->weld_radio_button("maxlimit"))
+ , m_xRBUnlimited(m_xBuilder->weld_radio_button("unlimited"))
+ , m_xEdRange(m_xBuilder->weld_entry("range"))
+ , m_xEdLimit(m_xBuilder->weld_entry("limit"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xVclFrameLimit(m_xBuilder->weld_frame("framelimit"))
+ , m_xVclFrameMove(m_xBuilder->weld_frame("framemove"))
+{
+ m_xCbUrl->connect_changed(LINK(this, DataStreamDlg, UpdateComboBoxHdl));
+ m_xRBAddressValue->connect_toggled(LINK(this, DataStreamDlg, UpdateClickHdl));
+ m_xRBAddressValue->set_sensitive(false);
+ m_xRBNoMove->hide();
+ m_xRBValuesInLine->connect_toggled(LINK(this, DataStreamDlg, UpdateClickHdl));
+ m_xEdRange->connect_changed(LINK(this, DataStreamDlg, UpdateHdl));
+ m_xBtnBrowse->connect_clicked(LINK(this, DataStreamDlg, BrowseHdl));
+ UpdateEnable();
+}
+
+DataStreamDlg::~DataStreamDlg() {}
+
+IMPL_LINK_NOARG(DataStreamDlg, BrowseHdl, weld::Button&, void)
+{
+ sfx2::FileDialogHelper aFileDialog(0, FileDialogFlags::NONE, m_xDialog.get());
+ aFileDialog.SetContext(sfx2::FileDialogHelper::CalcDataStream);
+ if (aFileDialog.Execute() != ERRCODE_NONE)
+ return;
+
+ m_xCbUrl->set_entry_text(aFileDialog.GetPath());
+ UpdateEnable();
+}
+
+IMPL_LINK_NOARG(DataStreamDlg, UpdateClickHdl, weld::Toggleable&, void) { UpdateEnable(); }
+
+IMPL_LINK_NOARG(DataStreamDlg, UpdateComboBoxHdl, weld::ComboBox&, void) { UpdateEnable(); }
+
+IMPL_LINK_NOARG(DataStreamDlg, UpdateHdl, weld::Entry&, void) { UpdateEnable(); }
+
+void DataStreamDlg::UpdateEnable()
+{
+ bool bOk = !m_xCbUrl->GetURL().isEmpty();
+ if (m_xRBAddressValue->get_active())
+ {
+ m_xVclFrameLimit->set_sensitive(false);
+ m_xVclFrameMove->set_sensitive(false);
+ m_xEdRange->set_sensitive(false);
+ }
+ else
+ {
+ m_xVclFrameLimit->set_sensitive(true);
+ m_xVclFrameMove->set_sensitive(true);
+ m_xEdRange->set_sensitive(true);
+ if (bOk)
+ {
+ // Check the given range to make sure it's valid.
+ ScRange aTest = GetStartRange();
+ if (!aTest.IsValid())
+ bOk = false;
+ }
+ }
+ m_xBtnOk->set_sensitive(bOk);
+ // setOptimalLayoutSize();
+}
+
+ScRange DataStreamDlg::GetStartRange()
+{
+ OUString aStr = m_xEdRange->get_text();
+ ScDocument& rDoc = m_pDocShell->GetDocument();
+ ScRange aRange;
+ ScRefFlags nRes = aRange.Parse(aStr, rDoc, rDoc.GetAddressConvention());
+ if (((nRes & ScRefFlags::VALID) == ScRefFlags::ZERO) || !aRange.IsValid())
+ {
+ // Invalid range.
+ aRange.SetInvalid();
+ return aRange;
+ }
+
+ // Make sure it's only one row tall.
+ if (aRange.aStart.Row() != aRange.aEnd.Row())
+ aRange.SetInvalid();
+
+ return aRange;
+}
+
+void DataStreamDlg::Init(const DataStream& rStrm)
+{
+ m_xCbUrl->set_entry_text(rStrm.GetURL());
+ ScDocument& rDoc = m_pDocShell->GetDocument();
+
+ ScRange aRange = rStrm.GetRange();
+ ScRange aTopRange = aRange;
+ aTopRange.aEnd.SetRow(aTopRange.aStart.Row());
+ OUString aStr = aTopRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D, rDoc.GetAddressConvention());
+ m_xEdRange->set_text(aStr);
+ SCROW nRows = aRange.aEnd.Row() - aRange.aStart.Row() + 1;
+
+ if (aRange.aEnd.Row() == rDoc.MaxRow())
+ m_xRBUnlimited->set_active(true);
+ else
+ {
+ m_xRBMaxLimit->set_active(true);
+ m_xEdLimit->set_text(OUString::number(nRows));
+ }
+
+ DataStream::MoveType eMove = rStrm.GetMove();
+ switch (eMove)
+ {
+ case DataStream::MOVE_DOWN:
+ m_xRBDataDown->set_active(true);
+ break;
+ case DataStream::RANGE_DOWN:
+ m_xRBRangeDown->set_active(true);
+ break;
+ case DataStream::MOVE_UP:
+ case DataStream::NO_MOVE:
+ default:;
+ }
+
+ m_xCBRefreshOnEmpty->set_active(rStrm.IsRefreshOnEmptyLine());
+
+ UpdateEnable();
+}
+
+void DataStreamDlg::StartStream()
+{
+ ScRange aStartRange = GetStartRange();
+ if (!aStartRange.IsValid())
+ // Don't start the stream without a valid range.
+ return;
+
+ sal_Int32 nLimit = 0;
+ if (m_xRBMaxLimit->get_active())
+ nLimit = m_xEdLimit->get_text().toInt32();
+ OUString rURL = m_xCbUrl->get_active_text();
+ sal_uInt32 nSettings = 0;
+ if (m_xRBValuesInLine->get_active())
+ nSettings |= DataStream::VALUES_IN_LINE;
+
+ DataStream::MoveType eMove
+ = m_xRBRangeDown->get_active() ? DataStream::RANGE_DOWN : DataStream::MOVE_DOWN;
+
+ DataStream* pStream = DataStream::Set(m_pDocShell, rURL, aStartRange, nLimit, eMove, nSettings);
+ pStream->SetRefreshOnEmptyLine(m_xCBRefreshOnEmpty->get_active());
+ DataStream::MakeToolbarVisible();
+ pStream->StartImport();
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/datatableview.cxx b/sc/source/ui/miscdlgs/datatableview.cxx
new file mode 100644
index 000000000..d74df0e81
--- /dev/null
+++ b/sc/source/ui/miscdlgs/datatableview.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 <datatableview.hxx>
+
+#include <document.hxx>
+#include <utility>
+#include <viewdata.hxx>
+#include <output.hxx>
+#include <fillinfo.hxx>
+#include <table.hxx>
+
+#include <toolkit/helper/vclunohelper.hxx>
+#include <vcl/scrbar.hxx>
+#include <vcl/seleng.hxx>
+#include <sal/log.hxx>
+
+constexpr double nPPTX = 0.06666;
+constexpr double nPPTY = 0.06666;
+
+constexpr sal_uInt16 nRowHeaderWidth = 100;
+constexpr sal_uInt16 nColHeaderHeight = 20;
+constexpr sal_uInt16 nScrollBarSize = 10;
+
+ScDataTableColView::ScDataTableColView(vcl::Window* pParent, ScDocument* pDoc, SelectionEngine* pSelectionEngine):
+ ScHeaderControl(pParent, pSelectionEngine, pDoc->MaxCol()+1, false, nullptr),
+ mpDoc(pDoc),
+ mnCol(0)
+{
+}
+
+void ScDataTableColView::SetPos(SCCOLROW nCol)
+{
+ mnCol = nCol;
+}
+
+SCCOLROW ScDataTableColView::GetPos() const
+{
+ return mnCol;
+}
+
+sal_uInt16 ScDataTableColView::GetEntrySize(SCCOLROW nPos) const
+{
+ return ScViewData::ToPixel(mpDoc->GetColWidth(nPos, 0), nPPTX);
+}
+
+OUString ScDataTableColView::GetEntryText(SCCOLROW nPos) const
+{
+ return "Col: " + OUString::number(nPos + 1);
+}
+
+bool ScDataTableColView::IsLayoutRTL() const
+{
+ return false;
+}
+
+void ScDataTableColView::SetEntrySize(SCCOLROW nPos, sal_uInt16 nColWidth)
+{
+ mpDoc->SetColWidthOnly(nPos, 0, nColWidth/nPPTX);
+}
+
+void ScDataTableColView::HideEntries(SCCOLROW nPos, SCCOLROW nEndPos)
+{
+ for (SCCOLROW nCol = nPos; nCol <= nEndPos; ++nCol)
+ {
+ mpDoc->ShowCol(nCol, 0, false);
+ }
+}
+
+
+ScDataTableRowView::ScDataTableRowView(vcl::Window* pParent, ScDocument* pDoc, SelectionEngine* pSelectionEngine):
+ ScHeaderControl(pParent, pSelectionEngine, pDoc->MaxRow()+1, true, nullptr),
+ mpDoc(pDoc),
+ mnRow(0)
+{
+}
+
+void ScDataTableRowView::SetPos(SCCOLROW nRow)
+{
+ mnRow = nRow;
+}
+
+SCCOLROW ScDataTableRowView::GetPos() const
+{
+ return mnRow;
+}
+
+sal_uInt16 ScDataTableRowView::GetEntrySize(SCCOLROW nPos) const
+{
+ return ScViewData::ToPixel(mpDoc->GetRowHeight(nPos, SCTAB(0), true), nPPTX);
+}
+
+OUString ScDataTableRowView::GetEntryText(SCCOLROW nPos) const
+{
+ return OUString::number(nPos + 1);
+}
+
+bool ScDataTableRowView::IsLayoutRTL() const
+{
+ return false;
+}
+
+void ScDataTableRowView::SetEntrySize(SCCOLROW nPos, sal_uInt16 nColWidth)
+{
+ mpDoc->SetRowHeight(nPos, 0, nColWidth/nPPTX);
+}
+
+void ScDataTableRowView::HideEntries(SCCOLROW nPos, SCCOLROW nEndPos)
+{
+ for (SCCOLROW nCol = nPos; nCol <= nEndPos; ++nCol)
+ {
+ mpDoc->ShowRow(nCol, 0, false);
+ }
+}
+
+ScDataTableView::ScDataTableView(const css::uno::Reference<css::awt::XWindow> &rParent, std::shared_ptr<ScDocument> pDoc) :
+ Control(VCLUnoHelper::GetWindow(rParent)),
+ mpDoc(std::move(pDoc)),
+ mpSelectionEngine(new SelectionEngine(this)),
+ mpTopLeft(VclPtr<ScrollBarBox>::Create(this, WB_SIZEABLE)),
+ mpColView(VclPtr<ScDataTableColView>::Create(this, mpDoc.get(), mpSelectionEngine.get())),
+ mpRowView(VclPtr<ScDataTableRowView>::Create(this, mpDoc.get(), mpSelectionEngine.get())),
+ mpVScroll(VclPtr<ScrollBar>::Create(this, WinBits(WB_VSCROLL | WB_DRAG))),
+ mpHScroll(VclPtr<ScrollBar>::Create(this, WinBits(WB_HSCROLL | WB_DRAG))),
+ mnFirstVisibleRow(0),
+ mnFirstVisibleCol(0)
+{
+ mpTopLeft->setPosSizePixel(0, 0, nRowHeaderWidth, nColHeaderHeight);
+ mpColView->setPosSizePixel(nRowHeaderWidth, 0, nRowHeaderWidth, nColHeaderHeight);
+ mpRowView->setPosSizePixel(0, nColHeaderHeight, nRowHeaderWidth, nColHeaderHeight);
+
+ mpVScroll->SetRangeMin(0);
+ mpVScroll->SetRangeMax(100);
+ mpVScroll->SetEndScrollHdl(LINK(this, ScDataTableView, ScrollHdl));
+
+ mpHScroll->SetRangeMin(0);
+ mpHScroll->SetRangeMax(50);
+ mpHScroll->SetEndScrollHdl(LINK(this, ScDataTableView, ScrollHdl));
+
+ mpTopLeft->Show();
+ mpColView->Show();
+ mpRowView->Show();
+ mpVScroll->Show();
+ mpHScroll->Show();
+}
+
+ScDataTableView::~ScDataTableView()
+{
+ disposeOnce();
+}
+
+void ScDataTableView::dispose()
+{
+ mpTopLeft.disposeAndClear();
+ mpColView.disposeAndClear();
+ mpRowView.disposeAndClear();
+ mpVScroll.disposeAndClear();
+ mpHScroll.disposeAndClear();
+ Control::dispose();
+}
+
+void ScDataTableView::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ if (!rMEvt.IsLeft())
+ return;
+
+ mpMouseEvent.reset(new MouseEvent(rMEvt));
+}
+
+namespace {
+
+SCCOL findColFromPos(sal_uInt16 nPixelPos, const ScDocument* pDoc, SCCOL nStartCol = 0)
+{
+ nPixelPos -= nRowHeaderWidth;
+ sal_uInt32 nPixelLength = 0;
+ for (SCCOL nCol : pDoc->GetColumnsRange(0, nStartCol, pDoc->MaxCol()))
+ {
+ sal_uInt16 nColWidth = pDoc->GetColWidth(nCol, 0, true);
+ sal_uInt32 nPixel = ScViewData::ToPixel(nColWidth, nPPTX);
+ nPixelLength += nPixel;
+
+ if (nPixelLength >= nPixelPos)
+ {
+ return nCol;
+ }
+ }
+
+ SAL_WARN("sc", "Could not find the corresponding column");
+ return pDoc->MaxCol();
+}
+
+SCROW findRowFromPos(sal_uInt16 nPixelPos, const ScDocument* pDoc, SCROW nStartRow = 0)
+{
+ nPixelPos -= nColHeaderHeight;
+ sal_uInt32 nPixelLength = 0;
+ for (SCROW nRow = nStartRow; nRow <= pDoc->MaxRow(); ++nRow)
+ {
+ sal_uInt16 nColWidth = pDoc->GetRowHeight(nRow, SCTAB(0), true);
+ sal_uInt32 nPixel = ScViewData::ToPixel(nColWidth, nPPTX);
+ nPixelLength += nPixel;
+
+ if (nPixelLength >= nPixelPos)
+ {
+ return nRow;
+ }
+ }
+
+ SAL_WARN("sc", "Could not find the corresponding row");
+ return pDoc->MaxRow();
+}
+
+}
+
+void ScDataTableView::MouseButtonUp(const MouseEvent& rMEvt)
+{
+ if (!rMEvt.IsLeft())
+ return;
+ if (!mpMouseEvent) // tdf#120528 The event originated in another window, like context menu
+ return;
+
+ SCCOL nStartCol = findColFromPos(mpMouseEvent->GetPosPixel().getX(), mpDoc.get());
+ SCCOL nEndCol = findColFromPos(rMEvt.GetPosPixel().getX(), mpDoc.get());
+ SCROW nStartRow = findRowFromPos(mpMouseEvent->GetPosPixel().getY(), mpDoc.get());
+ SCROW nEndRow = findRowFromPos(rMEvt.GetPosPixel().getY(), mpDoc.get());
+ PutInOrder(nStartCol, nEndCol);
+ PutInOrder(nStartRow, nEndRow);
+ mpColView->SetMark(true, nStartCol, nEndCol);
+ mpRowView->SetMark(true, nStartRow, nEndRow);
+
+ mpMouseEvent.reset();
+}
+
+void ScDataTableView::Resize()
+{
+ Size aSize = GetSizePixel();
+ mpTopLeft->setPosSizePixel(0, 0, nRowHeaderWidth, nColHeaderHeight);
+ mpColView->setPosSizePixel(nRowHeaderWidth, 0, aSize.Width() - nScrollBarSize, nColHeaderHeight);
+ mpRowView->setPosSizePixel(0, nColHeaderHeight, nRowHeaderWidth, aSize.Height());
+
+ mpVScroll->setPosSizePixel(aSize.Width() - nScrollBarSize, nColHeaderHeight, nScrollBarSize, aSize.Height() - nColHeaderHeight - nScrollBarSize);
+ mpHScroll->setPosSizePixel(nRowHeaderWidth, aSize.Height() - nScrollBarSize, aSize.Width() - nRowHeaderWidth - nScrollBarSize, nScrollBarSize);
+}
+
+void ScDataTableView::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRectangle)
+{
+ Size aSize = GetSizePixel();
+ SCCOL nMaxVisibleCol = findColFromPos(aSize.Width() - nScrollBarSize, mpDoc.get(), mnFirstVisibleCol);
+ SCROW nMaxVisibleRow = findRowFromPos(aSize.Height(), mpDoc.get(), mnFirstVisibleRow);
+
+ ScTableInfo aTableInfo;
+ mpDoc->FillInfo(aTableInfo, mnFirstVisibleCol, mnFirstVisibleRow, nMaxVisibleCol, nMaxVisibleRow, 0, 0.06666, 0.06666, false, false);
+ ScOutputData aOutput(&rRenderContext, OUTTYPE_WINDOW, aTableInfo, mpDoc.get(), 0,
+ nRowHeaderWidth, nColHeaderHeight, mnFirstVisibleCol, mnFirstVisibleRow, nMaxVisibleCol, nMaxVisibleRow, nPPTX, nPPTY);
+
+ aOutput.SetGridColor(COL_BLACK);
+ aOutput.SetSolidBackground(true);
+ aOutput.DrawClear();
+ aOutput.DrawDocumentBackground();
+ aOutput.DrawGrid(rRenderContext, true, false);
+ aOutput.DrawStrings();
+ Control::Paint(rRenderContext, rRectangle);
+}
+
+Size ScDataTableView::GetOptimalSize() const
+{
+ return Size(450, 400);
+}
+
+void ScDataTableView::getColRange(SCCOL& rStartCol, SCCOL& rEndCol) const
+{
+ SCCOLROW aStart = 0;
+ SCCOLROW aEnd = 0;
+ mpColView->GetMarkRange(aStart, aEnd);
+ rStartCol = static_cast<SCCOL>(aStart);
+ rEndCol = static_cast<SCCOL>(aEnd);
+}
+
+void ScDataTableView::getRowRange(SCROW& rStartCol, SCROW& rEndCol) const
+{
+ SCCOLROW aStart = 0;
+ SCCOLROW aEnd = 0;
+ mpRowView->GetMarkRange(aStart, aEnd);
+ rStartCol = static_cast<SCROW>(aStart);
+ rEndCol = static_cast<SCROW>(aEnd);
+}
+
+IMPL_LINK(ScDataTableView, ScrollHdl, ScrollBar*, pScrollBar, void)
+{
+ if (pScrollBar == mpVScroll.get())
+ {
+ mnFirstVisibleRow = pScrollBar->GetThumbPos();
+ pScrollBar->SetRangeMax(std::min(mpDoc->MaxRow(), static_cast<SCROW>(mnFirstVisibleRow + 100)));
+ mpRowView->SetPos(mnFirstVisibleRow);
+ }
+ else
+ {
+ mnFirstVisibleCol = pScrollBar->GetThumbPos();
+ pScrollBar->SetRangeMax(std::min(mpDoc->MaxCol(), static_cast<SCCOL>(mnFirstVisibleCol + 50)));
+ mpColView->SetPos(mnFirstVisibleCol);
+ }
+ Invalidate();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/delcldlg.cxx b/sc/source/ui/miscdlgs/delcldlg.cxx
new file mode 100644
index 000000000..71ce6b99e
--- /dev/null
+++ b/sc/source/ui/miscdlgs/delcldlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <delcldlg.hxx>
+
+static sal_uInt8 nDelItemChecked = 0;
+
+ScDeleteCellDlg::ScDeleteCellDlg(weld::Window* pParent, bool bDisallowCellMove)
+ : GenericDialogController(pParent, "modules/scalc/ui/deletecells.ui", "DeleteCellsDialog")
+ , m_xBtnCellsUp(m_xBuilder->weld_radio_button("up"))
+ , m_xBtnCellsLeft(m_xBuilder->weld_radio_button("left"))
+ , m_xBtnDelRows(m_xBuilder->weld_radio_button("rows"))
+ , m_xBtnDelCols(m_xBuilder->weld_radio_button("cols"))
+{
+ if (bDisallowCellMove)
+ {
+ m_xBtnCellsUp->set_sensitive(false);
+ m_xBtnCellsLeft->set_sensitive(false);
+
+ switch (nDelItemChecked)
+ {
+ case 2:
+ m_xBtnDelRows->set_active(true);
+ break;
+ case 3:
+ m_xBtnDelCols->set_active(true);
+ break;
+ default:
+ m_xBtnDelRows->set_active(true);
+ break;
+ }
+ }
+ else
+ {
+ switch (nDelItemChecked)
+ {
+ case 0:
+ m_xBtnCellsUp->set_active(true);
+ break;
+ case 1:
+ m_xBtnCellsLeft->set_active(true);
+ break;
+ case 2:
+ m_xBtnDelRows->set_active(true);
+ break;
+ case 3:
+ m_xBtnDelCols->set_active(true);
+ break;
+ }
+ }
+}
+
+ScDeleteCellDlg::~ScDeleteCellDlg() {}
+
+DelCellCmd ScDeleteCellDlg::GetDelCellCmd() const
+{
+ DelCellCmd nReturn = DelCellCmd::NONE;
+
+ if (m_xBtnCellsUp->get_active())
+ {
+ nDelItemChecked = 0;
+ nReturn = DelCellCmd::CellsUp;
+ }
+ else if (m_xBtnCellsLeft->get_active())
+ {
+ nDelItemChecked = 1;
+ nReturn = DelCellCmd::CellsLeft;
+ }
+ else if (m_xBtnDelRows->get_active())
+ {
+ nDelItemChecked = 2;
+ nReturn = DelCellCmd::Rows;
+ }
+ else if (m_xBtnDelCols->get_active())
+ {
+ nDelItemChecked = 3;
+ nReturn = DelCellCmd::Cols;
+ }
+
+ return nReturn;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/delcodlg.cxx b/sc/source/ui/miscdlgs/delcodlg.cxx
new file mode 100644
index 000000000..9d804c252
--- /dev/null
+++ b/sc/source/ui/miscdlgs/delcodlg.cxx
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <delcodlg.hxx>
+
+bool ScDeleteContentsDlg::bPreviousAllCheck = false;
+InsertDeleteFlags ScDeleteContentsDlg::nPreviousChecks = InsertDeleteFlags::DATETIME | InsertDeleteFlags::STRING |
+ InsertDeleteFlags::NOTE | InsertDeleteFlags::FORMULA |
+ InsertDeleteFlags::VALUE;
+
+ScDeleteContentsDlg::ScDeleteContentsDlg(weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/deletecontents.ui", "DeleteContentsDialog")
+ , m_bObjectsDisabled(false)
+ , m_xBtnDelAll(m_xBuilder->weld_check_button("deleteall"))
+ , m_xBtnDelStrings(m_xBuilder->weld_check_button("text"))
+ , m_xBtnDelNumbers(m_xBuilder->weld_check_button("numbers"))
+ , m_xBtnDelDateTime(m_xBuilder->weld_check_button("datetime"))
+ , m_xBtnDelFormulas(m_xBuilder->weld_check_button("formulas"))
+ , m_xBtnDelNotes(m_xBuilder->weld_check_button("comments"))
+ , m_xBtnDelAttrs(m_xBuilder->weld_check_button("formats"))
+ , m_xBtnDelObjects(m_xBuilder->weld_check_button("objects"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+{
+ m_xBtnDelAll->set_active( ScDeleteContentsDlg::bPreviousAllCheck );
+ m_xBtnDelStrings->set_active( bool(InsertDeleteFlags::STRING & ScDeleteContentsDlg::nPreviousChecks) );
+ m_xBtnDelNumbers->set_active( bool(InsertDeleteFlags::VALUE & ScDeleteContentsDlg::nPreviousChecks) );
+ m_xBtnDelDateTime->set_active( bool(InsertDeleteFlags::DATETIME & ScDeleteContentsDlg::nPreviousChecks) );
+ m_xBtnDelFormulas->set_active( bool(InsertDeleteFlags::FORMULA & ScDeleteContentsDlg::nPreviousChecks) );
+ m_xBtnDelNotes->set_active( bool(InsertDeleteFlags::NOTE & ScDeleteContentsDlg::nPreviousChecks) );
+ m_xBtnDelAttrs->set_active( (InsertDeleteFlags::ATTRIB & ScDeleteContentsDlg::nPreviousChecks) == InsertDeleteFlags::ATTRIB );
+ m_xBtnDelObjects->set_active( bool(InsertDeleteFlags::OBJECTS & ScDeleteContentsDlg::nPreviousChecks) );
+
+ DisableChecks( m_xBtnDelAll->get_active() );
+
+ m_xBtnDelAll->connect_toggled( LINK( this, ScDeleteContentsDlg, DelAllHdl ) );
+}
+
+ScDeleteContentsDlg::~ScDeleteContentsDlg()
+{
+}
+
+InsertDeleteFlags ScDeleteContentsDlg::GetDelContentsCmdBits() const
+{
+ ScDeleteContentsDlg::nPreviousChecks = InsertDeleteFlags::NONE;
+
+ if ( m_xBtnDelStrings->get_active() )
+ ScDeleteContentsDlg::nPreviousChecks = InsertDeleteFlags::STRING;
+ if ( m_xBtnDelNumbers->get_active() )
+ ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::VALUE;
+ if ( m_xBtnDelDateTime->get_active())
+ ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::DATETIME;
+ if ( m_xBtnDelFormulas->get_active())
+ ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::FORMULA;
+ if ( m_xBtnDelNotes->get_active() )
+ ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::NOTE;
+ if ( m_xBtnDelAttrs->get_active() )
+ ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::ATTRIB;
+ if ( m_xBtnDelObjects->get_active() )
+ ScDeleteContentsDlg::nPreviousChecks |= InsertDeleteFlags::OBJECTS;
+
+ ScDeleteContentsDlg::bPreviousAllCheck = m_xBtnDelAll->get_active();
+
+ return ( ScDeleteContentsDlg::bPreviousAllCheck
+ ? InsertDeleteFlags::ALL
+ : ScDeleteContentsDlg::nPreviousChecks );
+}
+
+void ScDeleteContentsDlg::DisableChecks( bool bDelAllChecked )
+{
+ if ( bDelAllChecked )
+ {
+ m_xBtnDelStrings->set_sensitive(false);
+ m_xBtnDelNumbers->set_sensitive(false);
+ m_xBtnDelDateTime->set_sensitive(false);
+ m_xBtnDelFormulas->set_sensitive(false);
+ m_xBtnDelNotes->set_sensitive(false);
+ m_xBtnDelAttrs->set_sensitive(false);
+ m_xBtnDelObjects->set_sensitive(false);
+ }
+ else
+ {
+ m_xBtnDelStrings->set_sensitive(true);
+ m_xBtnDelNumbers->set_sensitive(true);
+ m_xBtnDelDateTime->set_sensitive(true);
+ m_xBtnDelFormulas->set_sensitive(true);
+ m_xBtnDelNotes->set_sensitive(true);
+ m_xBtnDelAttrs->set_sensitive(true);
+ if (m_bObjectsDisabled)
+ m_xBtnDelObjects->set_sensitive(false);
+ else
+ m_xBtnDelObjects->set_sensitive(true);
+ }
+}
+
+void ScDeleteContentsDlg::DisableObjects()
+{
+ m_bObjectsDisabled = true;
+ m_xBtnDelObjects->set_active(false);
+ m_xBtnDelObjects->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(ScDeleteContentsDlg, DelAllHdl, weld::Toggleable&, void)
+{
+ DisableChecks( m_xBtnDelAll->get_active() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/filldlg.cxx b/sc/source/ui/miscdlgs/filldlg.cxx
new file mode 100644
index 000000000..c72201d26
--- /dev/null
+++ b/sc/source/ui/miscdlgs/filldlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <svl/numformat.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <scresid.hxx>
+#include <document.hxx>
+#include <strings.hrc>
+#include <filldlg.hxx>
+#include <scui_def.hxx>
+
+
+ScFillSeriesDlg::ScFillSeriesDlg( weld::Window* pParent,
+ ScDocument& rDocument,
+ FillDir eFillDir,
+ FillCmd eFillCmd,
+ FillDateCmd eFillDateCmd,
+ const OUString& aStartStr,
+ double fStep,
+ double fMax,
+ const SCSIZE nSelectHeight,
+ const SCSIZE nSelectWidth,
+ sal_uInt16 nPossDir )
+ : GenericDialogController(pParent, "modules/scalc/ui/filldlg.ui", "FillSeriesDialog")
+ , aStartStrVal(aStartStr)
+ , aErrMsgInvalidVal(ScResId(SCSTR_VALERR))
+ , rDoc(rDocument)
+ , theFillDir(eFillDir)
+ , theFillCmd(eFillCmd)
+ , theFillDateCmd(eFillDateCmd)
+ , fIncrement(fStep)
+ , fEndVal(fMax)
+ , m_nSelectHeight(nSelectHeight)
+ , m_nSelectWidth(nSelectWidth)
+ , m_xFtStartVal(m_xBuilder->weld_label("startL"))
+ , m_xEdStartVal(m_xBuilder->weld_entry("startValue"))
+ , m_xFtEndVal(m_xBuilder->weld_label("endL"))
+ , m_xEdEndVal(m_xBuilder->weld_entry("endValue"))
+ , m_xFtIncrement(m_xBuilder->weld_label("incrementL"))
+ , m_xEdIncrement(m_xBuilder->weld_entry("increment"))
+ , m_xBtnDown(m_xBuilder->weld_radio_button("down"))
+ , m_xBtnRight(m_xBuilder->weld_radio_button("right"))
+ , m_xBtnUp(m_xBuilder->weld_radio_button("up"))
+ , m_xBtnLeft(m_xBuilder->weld_radio_button("left"))
+ , m_xBtnArithmetic(m_xBuilder->weld_radio_button("linear"))
+ , m_xBtnGeometric(m_xBuilder->weld_radio_button("growth"))
+ , m_xBtnDate(m_xBuilder->weld_radio_button("date"))
+ , m_xBtnAutoFill(m_xBuilder->weld_radio_button("autofill"))
+ , m_xFtTimeUnit(m_xBuilder->weld_label("tuL"))
+ , m_xBtnDay(m_xBuilder->weld_radio_button("day"))
+ , m_xBtnDayOfWeek(m_xBuilder->weld_radio_button("week"))
+ , m_xBtnMonth(m_xBuilder->weld_radio_button("month"))
+ , m_xBtnYear(m_xBuilder->weld_radio_button("year"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+{
+ Init(nPossDir);
+}
+
+ScFillSeriesDlg::~ScFillSeriesDlg()
+{
+}
+
+void ScFillSeriesDlg::SetEdStartValEnabled(bool bFlag)
+{
+ if(bFlag)
+ {
+ m_xFtStartVal->set_sensitive(true);
+ m_xEdStartVal->set_sensitive(true);
+ }
+ else
+ {
+ m_xFtStartVal->set_sensitive(false);
+ m_xEdStartVal->set_sensitive(false);
+ }
+}
+
+void ScFillSeriesDlg::Init( sal_uInt16 nPossDir )
+{
+ m_xBtnOk->connect_clicked ( LINK( this, ScFillSeriesDlg, OKHdl ) );
+ m_xBtnArithmetic->connect_toggled ( LINK( this, ScFillSeriesDlg, DisableHdl ) );
+ m_xBtnGeometric->connect_toggled ( LINK( this, ScFillSeriesDlg, DisableHdl ) );
+ m_xBtnDate->connect_toggled ( LINK( this, ScFillSeriesDlg, DisableHdl ) );
+ m_xBtnAutoFill->connect_toggled ( LINK( this, ScFillSeriesDlg, DisableHdl ) );
+
+ if( nPossDir == FDS_OPT_NONE )
+ {
+ m_xBtnLeft->set_sensitive(false);
+ m_xBtnRight->set_sensitive(false);
+ m_xBtnDown->set_sensitive(false);
+ m_xBtnUp->set_sensitive(false);
+ }
+
+ if( nPossDir == FDS_OPT_HORZ )
+ {
+ m_xBtnDown->set_sensitive(false);
+ m_xBtnUp->set_sensitive(false);
+ }
+
+ if( nPossDir == FDS_OPT_VERT )
+ {
+ m_xBtnLeft->set_sensitive(false);
+ m_xBtnRight->set_sensitive(false);
+ }
+
+ switch ( theFillDir )
+ {
+ case FILL_TO_LEFT: m_xBtnLeft->set_active(true); break;
+ case FILL_TO_RIGHT: m_xBtnRight->set_active(true); break;
+ case FILL_TO_BOTTOM: m_xBtnDown->set_active(true); break;
+ case FILL_TO_TOP: m_xBtnUp->set_active(true); break;
+ default:
+ break;
+ }
+
+ switch ( theFillCmd )
+ {
+ case FILL_LINEAR:
+ m_xBtnArithmetic->set_active(true);
+ DisableHdl(*m_xBtnArithmetic);
+ break;
+ case FILL_GROWTH:
+ m_xBtnGeometric->set_active(true);
+ DisableHdl(*m_xBtnGeometric );
+ break;
+ case FILL_DATE:
+ m_xBtnDate->set_active(true);
+ DisableHdl(*m_xBtnDate);
+ break;
+ case FILL_AUTO:
+ m_xBtnAutoFill->set_active(true);
+ DisableHdl(*m_xBtnAutoFill);
+ break;
+ default:
+ break;
+ }
+
+ switch ( theFillDateCmd )
+ {
+ case FILL_DAY: m_xBtnDay->set_active(true); break;
+ case FILL_WEEKDAY: m_xBtnDayOfWeek->set_active(true); break;
+ case FILL_MONTH: m_xBtnMonth->set_active(true); break;
+ case FILL_YEAR: m_xBtnYear->set_active(true); break;
+ default:
+ break;
+ }
+
+ fStartVal = MAXDOUBLE;
+
+ m_xEdStartVal->set_text( aStartStrVal);
+
+ OUString aIncrTxt;
+ rDoc.GetFormatTable()->GetInputLineString( fIncrement, 0, aIncrTxt );
+ m_xEdIncrement->set_text( aIncrTxt );
+
+ OUString aEndTxt;
+ if ( fEndVal != MAXDOUBLE )
+ rDoc.GetFormatTable()->GetInputLineString( fEndVal, 0, aEndTxt );
+ m_xEdEndVal->set_text( aEndTxt );
+}
+
+weld::Entry* ScFillSeriesDlg::CheckValues()
+{
+ OUString aStartStr = m_xEdStartVal->get_text();
+ OUString aIncStr = m_xEdIncrement->get_text();
+ OUString aEndStr = m_xEdEndVal->get_text();
+ sal_uInt32 nKey = 0;
+
+ // If entry is filled, capture value before handling special cases.
+ if ( !aStartStr.isEmpty()
+ && theFillCmd != FILL_AUTO
+ && !rDoc.GetFormatTable()->IsNumberFormat( aStartStr, nKey, fStartVal ) )
+ return m_xEdStartVal.get();
+ if ( !aIncStr.isEmpty()
+ && !rDoc.GetFormatTable()->IsNumberFormat( aIncStr, nKey, fIncrement ) )
+ return m_xEdIncrement.get();
+ if ( !aEndStr.isEmpty()
+ && !rDoc.GetFormatTable()->IsNumberFormat( aEndStr, nKey, fEndVal ) )
+ return m_xEdEndVal.get();
+
+ if ( theFillCmd == FILL_LINEAR && !aEndStr.isEmpty()
+ && aStartStr.isEmpty() != aIncStr.isEmpty()
+ && ( ( m_nSelectHeight == 1 ) != ( m_nSelectWidth == 1 ) ) )
+ {
+ SCSIZE nStepAmount = ( theFillDir == FILL_TO_BOTTOM || theFillDir == FILL_TO_TOP ) ?
+ m_nSelectHeight - 1 : m_nSelectWidth - 1 ;
+ if ( aStartStr.isEmpty() )
+ fStartVal = fEndVal - fIncrement * nStepAmount;
+ if ( aIncStr.isEmpty() && nStepAmount != 0 )
+ fIncrement = (fEndVal - fStartVal) / nStepAmount;
+ }
+ else
+ {
+ if ( aStartStr.isEmpty() || m_xBtnAutoFill->get_active() )
+ fStartVal = MAXDOUBLE;
+ if ( aIncStr.isEmpty() )
+ return m_xEdIncrement.get();
+ if ( aEndStr.isEmpty() )
+ fEndVal = ( fIncrement < 0 ) ? -MAXDOUBLE : MAXDOUBLE;
+ }
+ return nullptr;
+}
+
+// Handler:
+IMPL_LINK(ScFillSeriesDlg, DisableHdl, weld::Toggleable&, rBtn, void)
+{
+ if (&rBtn == m_xBtnDate.get())
+ {
+ m_xBtnDay->set_sensitive(true);
+ m_xBtnDayOfWeek->set_sensitive(true);
+ m_xBtnMonth->set_sensitive(true);
+ m_xBtnYear->set_sensitive(true);
+ m_xFtTimeUnit->set_sensitive(true);
+ }
+ else
+ {
+ m_xBtnDay->set_sensitive(false);
+ m_xBtnDayOfWeek->set_sensitive(false);
+ m_xBtnMonth->set_sensitive(false);
+ m_xBtnYear->set_sensitive(false);
+ m_xFtTimeUnit->set_sensitive(false);
+ }
+
+ if (&rBtn != m_xBtnAutoFill.get())
+ {
+ m_xFtIncrement->set_sensitive(true);
+ m_xEdIncrement->set_sensitive(true);
+ m_xFtEndVal->set_sensitive(true);
+ m_xEdEndVal->set_sensitive(true);
+ }
+ else
+ {
+ m_xFtIncrement->set_sensitive(false);
+ m_xEdIncrement->set_sensitive(false);
+ m_xFtEndVal->set_sensitive(false);
+ m_xEdEndVal->set_sensitive(false);
+ }
+}
+
+IMPL_LINK_NOARG(ScFillSeriesDlg, OKHdl, weld::Button&, void)
+{
+ if ( m_xBtnLeft->get_active() ) theFillDir = FILL_TO_LEFT;
+ else if ( m_xBtnRight->get_active() ) theFillDir = FILL_TO_RIGHT;
+ else if ( m_xBtnDown->get_active() ) theFillDir = FILL_TO_BOTTOM;
+ else if ( m_xBtnUp->get_active() ) theFillDir = FILL_TO_TOP;
+
+ if ( m_xBtnArithmetic->get_active() ) theFillCmd = FILL_LINEAR;
+ else if ( m_xBtnGeometric->get_active() ) theFillCmd = FILL_GROWTH;
+ else if ( m_xBtnDate->get_active() ) theFillCmd = FILL_DATE;
+ else if ( m_xBtnAutoFill->get_active() ) theFillCmd = FILL_AUTO;
+
+ if ( m_xBtnDay->get_active() ) theFillDateCmd = FILL_DAY;
+ else if ( m_xBtnDayOfWeek->get_active() ) theFillDateCmd = FILL_WEEKDAY;
+ else if ( m_xBtnMonth->get_active() ) theFillDateCmd = FILL_MONTH;
+ else if ( m_xBtnYear->get_active() ) theFillDateCmd = FILL_YEAR;
+
+ weld::Entry* pEdWrong = CheckValues();
+ if ( pEdWrong == nullptr )
+ {
+ m_xDialog->response(RET_OK);
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Warning,
+ VclButtonsType::Ok, aErrMsgInvalidVal));
+ xBox->run();
+ pEdWrong->grab_focus();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/gototabdlg.cxx b/sc/source/ui/miscdlgs/gototabdlg.cxx
new file mode 100644
index 000000000..e38e67100
--- /dev/null
+++ b/sc/source/ui/miscdlgs/gototabdlg.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/.
+ *
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <gototabdlg.hxx>
+
+ScGoToTabDlg::ScGoToTabDlg(weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/gotosheetdialog.ui", "GoToSheetDialog")
+ , m_xFrameMask(m_xBuilder->weld_frame("frame-mask"))
+ , m_xEnNameMask(m_xBuilder->weld_entry("entry-mask"))
+ , m_xFrameSheets(m_xBuilder->weld_frame("frame-sheets"))
+ , m_xLb(m_xBuilder->weld_tree_view("treeview"))
+{
+ m_xLb->set_selection_mode(SelectionMode::Single);
+ m_xLb->set_size_request(-1, m_xLb->get_height_rows(10));
+ m_xLb->connect_row_activated(LINK(this, ScGoToTabDlg, DblClkHdl));
+ m_xEnNameMask->connect_changed(LINK(this, ScGoToTabDlg, FindNameHdl));
+}
+
+ScGoToTabDlg::~ScGoToTabDlg() {}
+
+void ScGoToTabDlg::SetDescription(const OUString& rTitle, const OUString& rEntryLabel,
+ const OUString& rListLabel, const OString& rDlgHelpId,
+ const OString& rEnHelpId, const OString& rLbHelpId)
+{
+ m_xDialog->set_title(rTitle);
+ m_xFrameMask->set_label(rEntryLabel);
+ m_xFrameSheets->set_label(rListLabel);
+ m_xDialog->set_help_id(rDlgHelpId);
+ m_xEnNameMask->set_help_id(rEnHelpId);
+ m_xLb->set_help_id(rLbHelpId);
+}
+
+void ScGoToTabDlg::Insert(const OUString& rString, bool bSelected)
+{
+ maCacheSheetsNames.push_back(rString);
+ m_xLb->append_text(rString);
+ if (bSelected)
+ m_xLb->select(m_xLb->n_children() - 1);
+}
+
+OUString ScGoToTabDlg::GetSelectedEntry() const { return m_xLb->get_selected_text(); }
+
+IMPL_LINK_NOARG(ScGoToTabDlg, DblClkHdl, weld::TreeView&, bool)
+{
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+IMPL_LINK_NOARG(ScGoToTabDlg, FindNameHdl, weld::Entry&, void)
+{
+ const OUString aMask = m_xEnNameMask->get_text();
+ m_xLb->clear();
+ if (aMask.isEmpty())
+ {
+ for (const OUString& s : maCacheSheetsNames)
+ {
+ m_xLb->append_text(s);
+ }
+ }
+ else
+ {
+ for (const OUString& s : maCacheSheetsNames)
+ {
+ if (s.indexOf(aMask) >= 0)
+ {
+ m_xLb->append_text(s);
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/groupdlg.cxx b/sc/source/ui/miscdlgs/groupdlg.cxx
new file mode 100644
index 000000000..839cc4f74
--- /dev/null
+++ b/sc/source/ui/miscdlgs/groupdlg.cxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <groupdlg.hxx>
+
+ScGroupDlg::ScGroupDlg(weld::Window* pParent, bool bUngroup, bool bRows)
+ : GenericDialogController(pParent,
+ bUngroup ?
+ OUString("modules/scalc/ui/ungroupdialog.ui") :
+ OUString("modules/scalc/ui/groupdialog.ui")
+ ,
+ bUngroup ?
+ OString("UngroupDialog") :
+ OString("GroupDialog"))
+ , m_xBtnRows(m_xBuilder->weld_radio_button("rows"))
+ , m_xBtnCols(m_xBuilder->weld_radio_button("cols"))
+{
+ if (bRows)
+ m_xBtnRows->set_active(true);
+ else
+ m_xBtnCols->set_active(true);
+ m_xBtnRows->grab_focus();
+}
+
+ScGroupDlg::~ScGroupDlg()
+{
+}
+
+bool ScGroupDlg::GetColsChecked() const
+{
+ return m_xBtnCols->get_active();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/highred.cxx b/sc/source/ui/miscdlgs/highred.cxx
new file mode 100644
index 000000000..fa655f80e
--- /dev/null
+++ b/sc/source/ui/miscdlgs/highred.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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <reffact.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <chgtrack.hxx>
+
+#include <highred.hxx>
+
+
+ScHighlightChgDlg::ScHighlightChgDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScViewData& rViewData)
+ : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/showchangesdialog.ui", "ShowChangesDialog")
+ , m_rViewData(rViewData)
+ , rDoc(rViewData.GetDocument())
+ , m_xHighlightBox(m_xBuilder->weld_check_button("showchanges"))
+ , m_xCbAccept(m_xBuilder->weld_check_button("showaccepted"))
+ , m_xCbReject(m_xBuilder->weld_check_button("showrejected"))
+ , m_xOkButton(m_xBuilder->weld_button("ok"))
+ , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry("range")))
+ , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button("rangeref")))
+ , m_xBox(m_xBuilder->weld_container("box"))
+ , m_xFilterCtr(new SvxTPFilter(m_xBox.get()))
+{
+ m_xEdAssign->SetReferences(this, nullptr);
+ m_xRbAssign->SetReferences(this, m_xEdAssign.get());
+
+ m_xOkButton->connect_clicked(LINK( this, ScHighlightChgDlg, OKBtnHdl));
+ m_xHighlightBox->connect_toggled(LINK( this, ScHighlightChgDlg, HighlightHandle ));
+ m_xFilterCtr->SetRefHdl(LINK( this, ScHighlightChgDlg, RefHandle ));
+ m_xFilterCtr->HideRange(false);
+ m_xFilterCtr->Show();
+ SetDispatcherLock( true );
+
+ Init();
+}
+
+ScHighlightChgDlg::~ScHighlightChgDlg()
+{
+ SetDispatcherLock( false );
+}
+
+void ScHighlightChgDlg::Init()
+{
+ ScChangeTrack* pChanges = rDoc.GetChangeTrack();
+ if(pChanges!=nullptr)
+ {
+ aChangeViewSet.SetTheAuthorToShow(pChanges->GetUser());
+ m_xFilterCtr->ClearAuthors();
+ const std::set<OUString>& rUserColl = pChanges->GetUserCollection();
+ for (const auto& rItem : rUserColl)
+ m_xFilterCtr->InsertAuthor(rItem);
+ }
+
+ ScChangeViewSettings* pViewSettings = rDoc.GetChangeViewSettings();
+
+ if(pViewSettings!=nullptr)
+ aChangeViewSet=*pViewSettings;
+ m_xHighlightBox->set_active(aChangeViewSet.ShowChanges());
+ m_xFilterCtr->CheckDate(aChangeViewSet.HasDate());
+
+ DateTime aEmpty(DateTime::EMPTY);
+
+ DateTime aDateTime(aChangeViewSet.GetTheFirstDateTime());
+ if (aDateTime != aEmpty)
+ {
+ m_xFilterCtr->SetFirstDate(aDateTime);
+ m_xFilterCtr->SetFirstTime(aDateTime);
+ }
+ aDateTime = aChangeViewSet.GetTheLastDateTime();
+ if (aDateTime != aEmpty)
+ {
+ m_xFilterCtr->SetLastDate(aDateTime);
+ m_xFilterCtr->SetLastTime(aDateTime);
+ }
+
+ m_xFilterCtr->SetDateMode(static_cast<sal_uInt16>(aChangeViewSet.GetTheDateMode()));
+ m_xFilterCtr->CheckAuthor(aChangeViewSet.HasAuthor());
+ m_xFilterCtr->CheckComment(aChangeViewSet.HasComment());
+ m_xFilterCtr->SetComment(aChangeViewSet.GetTheComment());
+
+ m_xCbAccept->set_active(aChangeViewSet.IsShowAccepted());
+ m_xCbReject->set_active(aChangeViewSet.IsShowRejected());
+
+ OUString aString=aChangeViewSet.GetTheAuthorToShow();
+ if(!aString.isEmpty())
+ {
+ m_xFilterCtr->SelectAuthor(aString);
+ }
+ else
+ {
+ m_xFilterCtr->SelectedAuthorPos(0);
+ }
+
+ m_xFilterCtr->CheckRange(aChangeViewSet.HasRange());
+
+ if ( !aChangeViewSet.GetTheRangeList().empty() )
+ {
+ const ScRange & rRangeEntry = aChangeViewSet.GetTheRangeList().front();
+ OUString aRefStr(rRangeEntry.Format(rDoc, ScRefFlags::RANGE_ABS_3D));
+ m_xFilterCtr->SetRange(aRefStr);
+ }
+ m_xFilterCtr->Enable(true);
+ HighlightHandle(*m_xHighlightBox);
+}
+
+// Set the reference to a cell range selected with the mouse. This is then
+// shown as the new selection in the reference field.
+void ScHighlightChgDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
+{
+ if (m_xEdAssign->GetWidget()->get_visible())
+ {
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart(m_xEdAssign.get());
+ OUString aRefStr(rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D, rDocP.GetAddressConvention()));
+ m_xEdAssign->SetRefString( aRefStr );
+ m_xFilterCtr->SetRange(aRefStr);
+ }
+}
+
+void ScHighlightChgDlg::Close()
+{
+ DoClose( ScHighlightChgDlgWrapper::GetChildWindowId() );
+}
+
+void ScHighlightChgDlg::RefInputDone( bool bForced)
+{
+ ScAnyRefDlgController::RefInputDone(bForced);
+ if (bForced || !m_xRbAssign->GetWidget()->get_visible())
+ {
+ m_xFilterCtr->SetRange(m_xEdAssign->GetText());
+ m_xFilterCtr->SetFocusToRange();
+ m_xEdAssign->GetWidget()->hide();
+ m_xRbAssign->GetWidget()->hide();
+ }
+}
+
+void ScHighlightChgDlg::SetActive()
+{
+}
+
+bool ScHighlightChgDlg::IsRefInputMode() const
+{
+ return m_xEdAssign->GetWidget()->get_visible();
+}
+
+IMPL_LINK_NOARG(ScHighlightChgDlg, HighlightHandle, weld::Toggleable&, void)
+{
+ if (m_xHighlightBox->get_active())
+ {
+ m_xFilterCtr->Enable(true);
+ m_xCbAccept->set_sensitive(true);
+ m_xCbReject->set_sensitive(true);
+ }
+ else
+ {
+ m_xFilterCtr->Enable(false);
+ m_xCbAccept->set_sensitive(false);
+ m_xCbReject->set_sensitive(false);
+ }
+}
+
+IMPL_LINK( ScHighlightChgDlg, RefHandle, SvxTPFilter*, pRef, void )
+{
+ if(pRef!=nullptr)
+ {
+ SetDispatcherLock( true );
+ m_xEdAssign->GetWidget()->show();
+ m_xRbAssign->GetWidget()->show();
+ m_xEdAssign->SetText(m_xFilterCtr->GetRange());
+ m_xEdAssign->GrabFocus();
+ ScAnyRefDlgController::RefInputStart(m_xEdAssign.get(), m_xRbAssign.get());
+ }
+}
+
+IMPL_LINK_NOARG(ScHighlightChgDlg, OKBtnHdl, weld::Button&, void)
+{
+ aChangeViewSet.SetShowChanges(m_xHighlightBox->get_active());
+ aChangeViewSet.SetHasDate(m_xFilterCtr->IsDate());
+ SvxRedlinDateMode eMode = m_xFilterCtr->GetDateMode();
+ aChangeViewSet.SetTheDateMode( eMode );
+ Date aFirstDate( m_xFilterCtr->GetFirstDate() );
+ tools::Time aFirstTime( m_xFilterCtr->GetFirstTime() );
+ Date aLastDate( m_xFilterCtr->GetLastDate() );
+ tools::Time aLastTime( m_xFilterCtr->GetLastTime() );
+ aChangeViewSet.SetTheFirstDateTime( DateTime( aFirstDate, aFirstTime ) );
+ aChangeViewSet.SetTheLastDateTime( DateTime( aLastDate, aLastTime ) );
+ aChangeViewSet.SetHasAuthor(m_xFilterCtr->IsAuthor());
+ aChangeViewSet.SetTheAuthorToShow(m_xFilterCtr->GetSelectedAuthor());
+ aChangeViewSet.SetHasRange(m_xFilterCtr->IsRange());
+ aChangeViewSet.SetShowAccepted(m_xCbAccept->get_active());
+ aChangeViewSet.SetShowRejected(m_xCbReject->get_active());
+ aChangeViewSet.SetHasComment(m_xFilterCtr->IsComment());
+ aChangeViewSet.SetTheComment(m_xFilterCtr->GetComment());
+ ScRangeList aLocalRangeList;
+ aLocalRangeList.Parse(m_xFilterCtr->GetRange(), rDoc);
+ aChangeViewSet.SetTheRangeList(aLocalRangeList);
+ aChangeViewSet.AdjustDateMode( rDoc );
+ rDoc.SetChangeViewSettings(aChangeViewSet);
+ m_rViewData.GetDocShell()->PostPaintGridAll();
+ response(RET_OK);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/inscldlg.cxx b/sc/source/ui/miscdlgs/inscldlg.cxx
new file mode 100644
index 000000000..ac97c6ac3
--- /dev/null
+++ b/sc/source/ui/miscdlgs/inscldlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <inscldlg.hxx>
+#include <viewdata.hxx>
+#include <strings.hrc>
+#include <scresid.hxx>
+
+static sal_uInt8 nInsItemChecked = 0;
+
+ScInsertCellDlg::ScInsertCellDlg(weld::Window* pParent, bool bDisallowCellMove)
+ : GenericDialogController(pParent, "modules/scalc/ui/insertcells.ui", "InsertCellsDialog")
+ , m_xBtnCellsDown(m_xBuilder->weld_radio_button("down"))
+ , m_xBtnCellsRight(m_xBuilder->weld_radio_button("right"))
+ , m_xBtnInsRow(m_xBuilder->weld_radio_button("rows"))
+ , m_xBtnInsCol(m_xBuilder->weld_radio_button("cols"))
+ , m_xLbCellsRight(m_xBuilder->weld_label("right"))
+{
+ const ScViewData* pViewData = ScDocShell::GetViewData();
+ if (pViewData && pViewData->GetDocument().IsLayoutRTL(pViewData->GetTabNo()))
+ m_xLbCellsRight->set_label(ScResId(SCSTR_INSERT_RTL));
+
+ if (bDisallowCellMove)
+ {
+ m_xBtnCellsDown->set_sensitive(false);
+ m_xBtnCellsRight->set_sensitive(false);
+ m_xBtnInsRow->set_active(true);
+
+ switch (nInsItemChecked)
+ {
+ case 2:
+ m_xBtnInsRow->set_active(true);
+ break;
+ case 3:
+ m_xBtnInsCol->set_active(true);
+ break;
+ default:
+ m_xBtnInsRow->set_active(true);
+ break;
+ }
+ }
+ else
+ {
+ switch (nInsItemChecked)
+ {
+ case 0:
+ m_xBtnCellsDown->set_active(true);
+ break;
+ case 1:
+ m_xBtnCellsRight->set_active(true);
+ break;
+ case 2:
+ m_xBtnInsRow->set_active(true);
+ break;
+ case 3:
+ m_xBtnInsCol->set_active(true);
+ break;
+ }
+ }
+}
+
+ScInsertCellDlg::~ScInsertCellDlg() {}
+
+InsCellCmd ScInsertCellDlg::GetInsCellCmd() const
+{
+ InsCellCmd nReturn = INS_NONE;
+
+ if (m_xBtnCellsDown->get_active())
+ {
+ nInsItemChecked = 0;
+ nReturn = INS_CELLSDOWN;
+ }
+ else if (m_xBtnCellsRight->get_active())
+ {
+ nInsItemChecked = 1;
+ nReturn = INS_CELLSRIGHT;
+ }
+ else if (m_xBtnInsRow->get_active())
+ {
+ nInsItemChecked = 2;
+ nReturn = INS_INSROWS_BEFORE;
+ }
+ else if (m_xBtnInsCol->get_active())
+ {
+ nInsItemChecked = 3;
+ nReturn = INS_INSCOLS_BEFORE;
+ }
+
+ return nReturn;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/inscodlg.cxx b/sc/source/ui/miscdlgs/inscodlg.cxx
new file mode 100644
index 000000000..879ed2835
--- /dev/null
+++ b/sc/source/ui/miscdlgs/inscodlg.cxx
@@ -0,0 +1,367 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <inscodlg.hxx>
+
+InsertDeleteFlags ScInsertContentsDlg::nPreviousChecks = InsertDeleteFlags::VALUE | InsertDeleteFlags::DATETIME | InsertDeleteFlags::STRING;
+ScPasteFunc ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::NONE;
+InsertContentsFlags ScInsertContentsDlg::nPreviousChecks2 = InsertContentsFlags::NONE;
+InsCellCmd ScInsertContentsDlg::nPreviousMoveMode = InsCellCmd::INS_NONE;
+
+ScInsertContentsDlg::ScInsertContentsDlg(weld::Window* pParent,
+ const OUString* pStrTitle )
+ : GenericDialogController(pParent, "modules/scalc/ui/pastespecial.ui", "PasteSpecial")
+ , bOtherDoc(false)
+ , bFillMode(false)
+ , bChangeTrack(false)
+ , bMoveDownDisabled(false)
+ , bMoveRightDisabled(false)
+ , mxBtnInsAll(m_xBuilder->weld_check_button("paste_all"))
+ , mxBtnInsStrings(m_xBuilder->weld_check_button("text"))
+ , mxBtnInsNumbers(m_xBuilder->weld_check_button("numbers"))
+ , mxBtnInsDateTime(m_xBuilder->weld_check_button("datetime"))
+ , mxBtnInsFormulas(m_xBuilder->weld_check_button("formulas"))
+ , mxBtnInsNotes(m_xBuilder->weld_check_button("comments"))
+ , mxBtnInsAttrs(m_xBuilder->weld_check_button("formats"))
+ , mxBtnInsObjects(m_xBuilder->weld_check_button("objects"))
+ , mxBtnSkipEmptyCells(m_xBuilder->weld_check_button("skip_empty"))
+ , mxBtnTranspose(m_xBuilder->weld_check_button("transpose"))
+ , mxBtnLink(m_xBuilder->weld_check_button("link"))
+ , mxRbNoOp(m_xBuilder->weld_radio_button("none"))
+ , mxRbAdd(m_xBuilder->weld_radio_button("add"))
+ , mxRbSub(m_xBuilder->weld_radio_button("subtract"))
+ , mxRbMul(m_xBuilder->weld_radio_button("multiply"))
+ , mxRbDiv(m_xBuilder->weld_radio_button("divide"))
+ , mxRbMoveNone(m_xBuilder->weld_radio_button("no_shift"))
+ , mxRbMoveDown(m_xBuilder->weld_radio_button("move_down"))
+ , mxRbMoveRight(m_xBuilder->weld_radio_button("move_right"))
+ , mxBtnShortCutPasteValuesOnly(m_xBuilder->weld_button("paste_values_only"))
+ , mxBtnShortCutPasteValuesFormats(m_xBuilder->weld_button("paste_values_formats"))
+ , mxBtnShortCutPasteTranspose(m_xBuilder->weld_button("paste_transpose"))
+ , mxBtnShortCutPasteFormats(m_xBuilder->weld_button("paste_formats"))
+ , mxImmediately(m_xBuilder->weld_check_button("cbImmediately"))
+{
+ if (pStrTitle)
+ m_xDialog->set_title(*pStrTitle);
+
+ SetInsContentsCmdBits( ScInsertContentsDlg::nPreviousChecks );
+ SetFormulaCmdBits( ScInsertContentsDlg::nPreviousFormulaChecks );
+ SetCellCmdFlags( ScInsertContentsDlg::nPreviousMoveMode );
+ SetContentsFlags( ScInsertContentsDlg::nPreviousChecks2 );
+ DisableChecks( mxBtnInsAll->get_active() );
+
+ mxBtnInsAll->connect_toggled( LINK( this, ScInsertContentsDlg, InsAllHdl ) );
+ mxBtnLink->connect_toggled( LINK( this, ScInsertContentsDlg, LinkBtnHdl ) );
+ mxBtnShortCutPasteValuesOnly->connect_clicked( LINK( this, ScInsertContentsDlg, ShortCutHdl ) );
+ mxBtnShortCutPasteValuesFormats->connect_clicked( LINK( this, ScInsertContentsDlg, ShortCutHdl ) );
+ mxBtnShortCutPasteTranspose->connect_clicked( LINK( this, ScInsertContentsDlg, ShortCutHdl ) );
+ mxBtnShortCutPasteFormats->connect_clicked( LINK( this, ScInsertContentsDlg, ShortCutHdl ) );
+}
+
+InsertDeleteFlags ScInsertContentsDlg::GetInsContentsCmdBits() const
+{
+ ScInsertContentsDlg::nPreviousChecks = InsertDeleteFlags::NONE;
+
+ if ( mxBtnInsStrings->get_active() )
+ ScInsertContentsDlg::nPreviousChecks = InsertDeleteFlags::STRING;
+ if ( mxBtnInsNumbers->get_active() )
+ ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::VALUE;
+ if ( mxBtnInsDateTime->get_active())
+ ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::DATETIME;
+ if ( mxBtnInsFormulas->get_active())
+ ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::FORMULA;
+ if ( mxBtnInsNotes->get_active() )
+ ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::NOTE;
+ if ( mxBtnInsAttrs->get_active() )
+ ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::ATTRIB;
+ if ( mxBtnInsObjects->get_active() )
+ ScInsertContentsDlg::nPreviousChecks |= InsertDeleteFlags::OBJECTS;
+
+ return ( mxBtnInsAll->get_active()
+ ? InsertDeleteFlags::ALL
+ : ScInsertContentsDlg::nPreviousChecks );
+}
+
+void ScInsertContentsDlg::SetInsContentsCmdBits(const InsertDeleteFlags eFlags)
+{
+ mxBtnInsNumbers->set_active((InsertDeleteFlags::VALUE & eFlags) == InsertDeleteFlags::VALUE);
+ mxBtnInsDateTime->set_active((InsertDeleteFlags::DATETIME & eFlags) == InsertDeleteFlags::DATETIME);
+ mxBtnInsStrings->set_active((InsertDeleteFlags::STRING & eFlags) == InsertDeleteFlags::STRING);
+ mxBtnInsNotes->set_active((InsertDeleteFlags::NOTE & eFlags) == InsertDeleteFlags::NOTE);
+ mxBtnInsFormulas->set_active((InsertDeleteFlags::FORMULA & eFlags) == InsertDeleteFlags::FORMULA);
+ mxBtnInsAttrs->set_active((InsertDeleteFlags::ATTRIB & eFlags) == InsertDeleteFlags::ATTRIB);
+ mxBtnInsObjects->set_active((InsertDeleteFlags::OBJECTS & eFlags) == InsertDeleteFlags::OBJECTS);
+ mxBtnInsAll->set_active((InsertDeleteFlags::ALL & eFlags) == InsertDeleteFlags::ALL);
+ DisableChecks( mxBtnInsAll->get_active() );
+}
+
+void ScInsertContentsDlg::SetFormulaCmdBits(const ScPasteFunc eFlags)
+{
+ switch( eFlags )
+ {
+ case ScPasteFunc::NONE: mxRbNoOp->set_active(true); break;
+ case ScPasteFunc::ADD: mxRbAdd->set_active(true); break;
+ case ScPasteFunc::SUB: mxRbSub->set_active(true); break;
+ case ScPasteFunc::MUL: mxRbMul->set_active(true); break;
+ case ScPasteFunc::DIV: mxRbDiv->set_active(true); break;
+ }
+}
+
+void ScInsertContentsDlg::SetCellCmdFlags(const InsCellCmd eFlags)
+{
+ switch( eFlags )
+ {
+ case INS_NONE: mxRbMoveNone->set_active(true); break;
+ case INS_CELLSDOWN: mxRbMoveDown->set_active(true); break;
+ case INS_CELLSRIGHT: mxRbMoveRight->set_active(true); break;
+ case INS_INSROWS_BEFORE:
+ case INS_INSCOLS_BEFORE:
+ case INS_INSROWS_AFTER:
+ case INS_INSCOLS_AFTER: break;
+ }
+}
+
+void ScInsertContentsDlg::SetContentsFlags(const InsertContentsFlags eFlags)
+{
+ mxBtnSkipEmptyCells->set_active(bool(InsertContentsFlags::NoEmpty & eFlags));
+ mxBtnTranspose->set_active(bool(InsertContentsFlags::Trans & eFlags));
+ mxBtnLink->set_active(bool(InsertContentsFlags::Link & eFlags));
+}
+
+InsCellCmd ScInsertContentsDlg::GetMoveMode() const
+{
+ if ( mxRbMoveDown->get_active() )
+ return INS_CELLSDOWN;
+ if ( mxRbMoveRight->get_active() )
+ return INS_CELLSRIGHT;
+
+ return INS_NONE;
+}
+
+bool ScInsertContentsDlg::IsSkipEmptyCells() const
+{
+ return mxBtnSkipEmptyCells->get_active();
+}
+
+bool ScInsertContentsDlg::IsTranspose() const
+{
+ return mxBtnTranspose->get_active();
+}
+
+bool ScInsertContentsDlg::IsLink() const
+{
+ return mxBtnLink->get_active();
+}
+
+void ScInsertContentsDlg::DisableChecks( bool bInsAllChecked )
+{
+ if ( bInsAllChecked )
+ {
+ mxBtnInsStrings->set_sensitive(false);
+ mxBtnInsNumbers->set_sensitive(false);
+ mxBtnInsDateTime->set_sensitive(false);
+ mxBtnInsFormulas->set_sensitive(false);
+ mxBtnInsNotes->set_sensitive(false);
+ mxBtnInsAttrs->set_sensitive(false);
+ mxBtnInsObjects->set_sensitive(false);
+ }
+ else
+ {
+ mxBtnInsStrings->set_sensitive(true);
+ mxBtnInsNumbers->set_sensitive(true);
+ mxBtnInsDateTime->set_sensitive(true);
+ mxBtnInsFormulas->set_sensitive(true);
+ mxBtnInsNotes->set_sensitive(true);
+ mxBtnInsAttrs->set_sensitive(true);
+
+ // "Objects" is disabled for "Fill Tables"
+ if ( bFillMode )
+ mxBtnInsObjects->set_sensitive(false);
+ else
+ mxBtnInsObjects->set_sensitive(true);
+ }
+}
+
+// Link to other document -> everything else is disabled
+
+void ScInsertContentsDlg::TestModes()
+{
+ if ( bOtherDoc && mxBtnLink->get_active() )
+ {
+ mxBtnSkipEmptyCells->set_sensitive(false);
+ mxBtnTranspose->set_sensitive(false);
+ mxRbNoOp->set_sensitive(false);
+ mxRbAdd->set_sensitive(false);
+ mxRbSub->set_sensitive(false);
+ mxRbMul->set_sensitive(false);
+ mxRbDiv->set_sensitive(false);
+
+ mxRbMoveNone->set_sensitive(false);
+ mxRbMoveDown->set_sensitive(false);
+ mxRbMoveRight->set_sensitive(false);
+
+ mxBtnInsAll->set_sensitive(false);
+ DisableChecks(true);
+ }
+ else
+ {
+ mxBtnSkipEmptyCells->set_sensitive(true);
+ mxBtnTranspose->set_sensitive(!bFillMode);
+ mxRbNoOp->set_sensitive(true);
+ mxRbAdd->set_sensitive(true);
+ mxRbSub->set_sensitive(true);
+ mxRbMul->set_sensitive(true);
+ mxRbDiv->set_sensitive(true);
+
+ mxRbMoveNone->set_sensitive(!bFillMode && !bChangeTrack && !(bMoveDownDisabled && bMoveRightDisabled));
+ mxRbMoveDown->set_sensitive(!bFillMode && !bChangeTrack && !bMoveDownDisabled);
+ mxRbMoveRight->set_sensitive(!bFillMode && !bChangeTrack && !bMoveRightDisabled);
+
+ mxBtnInsAll->set_sensitive(true);
+ DisableChecks( mxBtnInsAll->get_active() );
+ }
+}
+
+void ScInsertContentsDlg::SetOtherDoc( bool bSet )
+{
+ if ( bSet != bOtherDoc )
+ {
+ bOtherDoc = bSet;
+ TestModes();
+ if ( bSet )
+ mxRbMoveNone->set_active(true);
+ }
+}
+
+void ScInsertContentsDlg::SetFillMode( bool bSet )
+{
+ if ( bSet != bFillMode )
+ {
+ bFillMode = bSet;
+ TestModes();
+ if ( bSet )
+ mxRbMoveNone->set_active(true);
+ }
+}
+
+void ScInsertContentsDlg::SetChangeTrack( bool bSet )
+{
+ if ( bSet != bChangeTrack )
+ {
+ bChangeTrack = bSet;
+ TestModes();
+ if ( bSet )
+ mxRbMoveNone->set_active(true);
+ }
+}
+
+void ScInsertContentsDlg::SetCellShiftDisabled( CellShiftDisabledFlags nDisable )
+{
+ bool bDown(nDisable & CellShiftDisabledFlags::Down);
+ bool bRight(nDisable & CellShiftDisabledFlags::Right);
+ if ( bDown != bMoveDownDisabled || bRight != bMoveRightDisabled )
+ {
+ bMoveDownDisabled = bDown;
+ bMoveRightDisabled = bRight;
+ TestModes();
+ if ( bMoveDownDisabled && mxRbMoveDown->get_active() )
+ mxRbMoveNone->set_active(true);
+ if ( bMoveRightDisabled && mxRbMoveRight->get_active() )
+ mxRbMoveNone->set_active(true);
+ }
+}
+
+IMPL_LINK(ScInsertContentsDlg, ShortCutHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == mxBtnShortCutPasteValuesOnly.get())
+ {
+ SetInsContentsCmdBits( InsertDeleteFlags::STRING | InsertDeleteFlags::VALUE | InsertDeleteFlags::DATETIME );
+ SetContentsFlags( InsertContentsFlags::NONE );
+ }
+ else if (&rBtn == mxBtnShortCutPasteValuesFormats.get())
+ {
+ SetInsContentsCmdBits( InsertDeleteFlags::STRING | InsertDeleteFlags::VALUE | InsertDeleteFlags::DATETIME | InsertDeleteFlags::ATTRIB );
+ SetContentsFlags( InsertContentsFlags::NONE );
+ }
+ else if (&rBtn == mxBtnShortCutPasteTranspose.get())
+ {
+ SetInsContentsCmdBits( InsertDeleteFlags::ALL );
+ SetContentsFlags( InsertContentsFlags::Trans );
+ }
+ else if (&rBtn == mxBtnShortCutPasteFormats.get())
+ {
+ SetInsContentsCmdBits( InsertDeleteFlags::ATTRIB );
+ SetContentsFlags( InsertContentsFlags::NONE );
+ }
+ else
+ return;
+
+ SetCellCmdFlags( InsCellCmd::INS_NONE );
+ SetFormulaCmdBits(ScPasteFunc::NONE);
+ if (mxImmediately->get_active()) m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ScInsertContentsDlg, InsAllHdl, weld::Toggleable&, void)
+{
+ DisableChecks( mxBtnInsAll->get_active() );
+}
+
+IMPL_LINK_NOARG(ScInsertContentsDlg, LinkBtnHdl, weld::Toggleable&, void)
+{
+ TestModes();
+}
+
+ScInsertContentsDlg::~ScInsertContentsDlg()
+{
+ ScInsertContentsDlg::nPreviousChecks2 = InsertContentsFlags::NONE;
+ if(mxBtnSkipEmptyCells->get_active())
+ ScInsertContentsDlg::nPreviousChecks2 |= InsertContentsFlags::NoEmpty;
+ if( mxBtnTranspose->get_active())
+ ScInsertContentsDlg::nPreviousChecks2 |= InsertContentsFlags::Trans;
+ if( mxBtnLink->get_active() )
+ ScInsertContentsDlg::nPreviousChecks2 |= InsertContentsFlags::Link;
+
+ if (!bFillMode) // in FillMode, None is checked and all three options are disabled
+ {
+ if ( mxRbMoveNone->get_active() )
+ ScInsertContentsDlg::nPreviousMoveMode = INS_NONE;
+ else if ( mxRbMoveDown->get_active() )
+ ScInsertContentsDlg::nPreviousMoveMode = INS_CELLSDOWN;
+ else if ( mxRbMoveRight->get_active() )
+ ScInsertContentsDlg::nPreviousMoveMode = INS_CELLSRIGHT;
+ }
+}
+
+ScPasteFunc ScInsertContentsDlg::GetFormulaCmdBits() const
+{
+ ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::NONE;
+ if(mxRbAdd->get_active())
+ ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::ADD;
+ else if(mxRbSub->get_active())
+ ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::SUB;
+ else if(mxRbMul->get_active())
+ ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::MUL;
+ else if(mxRbDiv->get_active())
+ ScInsertContentsDlg::nPreviousFormulaChecks = ScPasteFunc::DIV;
+ return ScInsertContentsDlg::nPreviousFormulaChecks;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/instbdlg.cxx b/sc/source/ui/miscdlgs/instbdlg.cxx
new file mode 100644
index 000000000..947b983ec
--- /dev/null
+++ b/sc/source/ui/miscdlgs/instbdlg.cxx
@@ -0,0 +1,356 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/docinsert.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <svtools/ehdl.hxx>
+#include <svtools/sfxecode.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <docsh.hxx>
+#include <viewdata.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <instbdlg.hxx>
+
+ScInsertTableDlg::ScInsertTableDlg(weld::Window* pParent, ScViewData& rData, SCTAB nTabCount, bool bFromFile)
+ : GenericDialogController(pParent, "modules/scalc/ui/insertsheet.ui", "InsertSheetDialog")
+ , aBrowseTimer("ScInsertTableDlg aBrowseTimer")
+ , rViewData(rData)
+ , rDoc(rData.GetDocument())
+ , pDocShTables(nullptr)
+ , bMustClose(false)
+ , nSelTabIndex(0)
+ , nTableCount(nTabCount)
+ , m_xBtnBefore(m_xBuilder->weld_radio_button("before"))
+ , m_xBtnBehind(m_xBuilder->weld_radio_button("after"))
+ , m_xBtnNew(m_xBuilder->weld_radio_button("new"))
+ , m_xBtnFromFile(m_xBuilder->weld_radio_button("fromfile"))
+ , m_xFtCount(m_xBuilder->weld_label("countft"))
+ , m_xNfCount(m_xBuilder->weld_spin_button("countnf"))
+ , m_xFtName(m_xBuilder->weld_label("nameft"))
+ , m_xEdName(m_xBuilder->weld_entry("nameed"))
+ , m_xLbTables(m_xBuilder->weld_tree_view("tables"))
+ , m_xFtPath(m_xBuilder->weld_label("path"))
+ , m_xBtnBrowse(m_xBuilder->weld_button("browse"))
+ , m_xBtnLink(m_xBuilder->weld_check_button("link"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+{
+ m_sSheetDotDotDot = m_xEdName->get_text();
+ m_xLbTables->set_size_request(-1, m_xLbTables->get_height_rows(8));
+ Init_Impl(bFromFile);
+}
+
+ScInsertTableDlg::~ScInsertTableDlg()
+{
+ if (pDocShTables)
+ pDocShTables->DoClose();
+ pDocInserter.reset();
+}
+
+void ScInsertTableDlg::Init_Impl( bool bFromFile )
+{
+ m_xLbTables->set_selection_mode(SelectionMode::Multiple);
+ m_xBtnBrowse->connect_clicked( LINK( this, ScInsertTableDlg, BrowseHdl_Impl ) );
+ m_xBtnNew->connect_toggled( LINK( this, ScInsertTableDlg, ChoiceHdl_Impl ) );
+ m_xBtnFromFile->connect_toggled( LINK( this, ScInsertTableDlg, ChoiceHdl_Impl ) );
+ m_xLbTables->connect_changed( LINK( this, ScInsertTableDlg, SelectHdl_Impl ) );
+ m_xNfCount->connect_value_changed( LINK( this, ScInsertTableDlg, CountHdl_Impl));
+ m_xBtnOk->connect_clicked( LINK( this, ScInsertTableDlg, DoEnterHdl ));
+ m_xBtnBefore->set_active(true);
+
+ m_xNfCount->set_max(MAXTAB - rDoc.GetTableCount() + 1);
+ m_xNfCount->set_value(nTableCount);
+
+ if(nTableCount==1)
+ {
+ OUString aName;
+ rDoc.CreateValidTabName( aName );
+ m_xEdName->set_text( aName );
+ }
+ else
+ {
+ m_xEdName->set_text(m_sSheetDotDotDot);
+ m_xFtName->set_sensitive(false);
+ m_xEdName->set_sensitive(false);
+ }
+
+ bool bShared = rViewData.GetDocShell() && rViewData.GetDocShell()->IsDocShared();
+
+ if ( !bFromFile || bShared )
+ {
+ m_xBtnNew->set_active(true);
+ SetNewTable_Impl();
+ if ( bShared )
+ {
+ m_xBtnFromFile->set_sensitive(false);
+ }
+ }
+ else
+ {
+ m_xBtnFromFile->set_active(true);
+ SetFromTo_Impl();
+
+ aBrowseTimer.SetInvokeHandler( LINK( this, ScInsertTableDlg, BrowseTimeoutHdl ) );
+ aBrowseTimer.SetTimeout( 200 );
+ }
+}
+
+short ScInsertTableDlg::run()
+{
+ if (m_xBtnFromFile->get_active())
+ aBrowseTimer.Start();
+
+ return GenericDialogController::run();
+}
+
+void ScInsertTableDlg::SetNewTable_Impl()
+{
+ if (!m_xBtnNew->get_active() )
+ return;
+
+ m_xNfCount->set_sensitive(true);
+ m_xFtCount->set_sensitive(true);
+ m_xLbTables->set_sensitive(false);
+ m_xFtPath->set_sensitive(false);
+ m_xBtnBrowse->set_sensitive(false);
+ m_xBtnLink->set_sensitive(false);
+
+ if(nTableCount==1)
+ {
+ m_xEdName->set_sensitive(true);
+ m_xFtName->set_sensitive(true);
+ }
+}
+
+void ScInsertTableDlg::SetFromTo_Impl()
+{
+ if (m_xBtnFromFile->get_active() )
+ {
+ m_xEdName->set_sensitive(false);
+ m_xFtName->set_sensitive(false);
+ m_xFtCount->set_sensitive(false);
+ m_xNfCount->set_sensitive(false);
+ m_xLbTables->set_sensitive(true);
+ m_xFtPath->set_sensitive(true);
+ m_xBtnBrowse->set_sensitive(true);
+ m_xBtnLink->set_sensitive(true);
+ }
+}
+
+void ScInsertTableDlg::FillTables_Impl( const ScDocument* pSrcDoc )
+{
+ m_xLbTables->freeze();
+ m_xLbTables->clear();
+
+ if ( pSrcDoc )
+ {
+ SCTAB nCount = pSrcDoc->GetTableCount();
+ OUString aName;
+
+ for (SCTAB i=0; i<nCount; ++i)
+ {
+ pSrcDoc->GetName( i, aName );
+ m_xLbTables->append_text(aName);
+ }
+ }
+
+ m_xLbTables->thaw();
+
+ if (m_xLbTables->n_children() == 1)
+ m_xLbTables->select(0);
+}
+
+const OUString* ScInsertTableDlg::GetFirstTable( sal_uInt16* pN )
+{
+ const OUString* pStr = nullptr;
+
+ if ( m_xBtnNew->get_active() )
+ {
+ aStrCurSelTable = m_xEdName->get_text();
+ pStr = &aStrCurSelTable;
+ }
+ else
+ {
+ std::vector<int> aRows(m_xLbTables->get_selected_rows());
+ if (nSelTabIndex < aRows.size())
+ {
+ aStrCurSelTable = m_xLbTables->get_text(aRows[0]);
+ pStr = &aStrCurSelTable;
+ if ( pN )
+ *pN = aRows[0];
+ nSelTabIndex = 1;
+ }
+ }
+
+ return pStr;
+}
+
+const OUString* ScInsertTableDlg::GetNextTable( sal_uInt16* pN )
+{
+ if (m_xBtnNew->get_active())
+ return nullptr;
+
+ std::vector<int> aRows(m_xLbTables->get_selected_rows());
+
+ const OUString* pStr = nullptr;
+ if (nSelTabIndex < aRows.size())
+ {
+ aStrCurSelTable = m_xLbTables->get_text(aRows[nSelTabIndex]);
+ pStr = &aStrCurSelTable;
+ if ( pN )
+ *pN = aRows[nSelTabIndex];
+ nSelTabIndex++;
+ }
+
+ return pStr;
+}
+
+// Handler:
+
+IMPL_LINK_NOARG(ScInsertTableDlg, CountHdl_Impl, weld::SpinButton&, void)
+{
+ nTableCount = static_cast<SCTAB>(m_xNfCount->get_value());
+ if ( nTableCount==1)
+ {
+ OUString aName;
+ rDoc.CreateValidTabName( aName );
+ m_xEdName->set_text( aName );
+ m_xFtName->set_sensitive(true);
+ m_xEdName->set_sensitive(true);
+ }
+ else
+ {
+ m_xEdName->set_text(m_sSheetDotDotDot);
+ m_xFtName->set_sensitive(false);
+ m_xEdName->set_sensitive(false);
+ }
+
+ DoEnable_Impl();
+}
+
+IMPL_LINK(ScInsertTableDlg, ChoiceHdl_Impl, weld::Toggleable&, rButton, void)
+{
+ if (!rButton.get_active())
+ return;
+
+ if ( m_xBtnNew->get_active() )
+ SetNewTable_Impl();
+ else
+ SetFromTo_Impl();
+
+ DoEnable_Impl();
+}
+
+IMPL_LINK_NOARG(ScInsertTableDlg, BrowseHdl_Impl, weld::Button&, void)
+{
+ pDocInserter.reset();
+ pDocInserter.reset( new ::sfx2::DocumentInserter(m_xDialog.get(), ScDocShell::Factory().GetFactoryName()) );
+ pDocInserter->StartExecuteModal( LINK( this, ScInsertTableDlg, DialogClosedHdl ) );
+}
+
+IMPL_LINK_NOARG(ScInsertTableDlg, SelectHdl_Impl, weld::TreeView&, void)
+{
+ DoEnable_Impl();
+}
+
+void ScInsertTableDlg::DoEnable_Impl()
+{
+ if ( m_xBtnNew->get_active() || ( pDocShTables && m_xLbTables->count_selected_rows() ) )
+ m_xBtnOk->set_sensitive(true);
+ else
+ m_xBtnOk->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(ScInsertTableDlg, DoEnterHdl, weld::Button&, void)
+{
+ if (nTableCount > 1 || ScDocument::ValidTabName(m_xEdName->get_text()))
+ {
+ m_xDialog->response(RET_OK);
+ }
+ else
+ {
+ OUString aErrMsg ( ScResId( STR_INVALIDTABNAME ) );
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(), VclMessageType::Warning,
+ VclButtonsType::Ok, aErrMsg));
+ xBox->run();
+ }
+}
+
+IMPL_LINK_NOARG(ScInsertTableDlg, BrowseTimeoutHdl, Timer *, void)
+{
+ bMustClose = true;
+ BrowseHdl_Impl(*m_xBtnBrowse);
+}
+
+IMPL_LINK( ScInsertTableDlg, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void )
+{
+ if ( ERRCODE_NONE == _pFileDlg->GetError() )
+ {
+ std::unique_ptr<SfxMedium> pMed = pDocInserter->CreateMedium();
+ if ( pMed )
+ {
+ // ERRCTX_SFX_OPENDOC -> "Error loading document"
+ SfxErrorContext aEc( ERRCTX_SFX_OPENDOC, pMed->GetName() );
+
+ if ( pDocShTables )
+ pDocShTables->DoClose(); // deletion is done when assigning to the reference
+
+ pMed->UseInteractionHandler( true ); // to enable the filter options dialog
+
+ pDocShTables = new ScDocShell;
+ aDocShTablesRef = pDocShTables;
+
+ {
+ weld::WaitObject aWait(m_xDialog.get());
+ pDocShTables->DoLoad(pMed.release());
+ }
+
+ ErrCode nErr = pDocShTables->GetErrorCode();
+ if ( nErr )
+ ErrorHandler::HandleError(nErr, m_xDialog.get()); // warnings, too
+
+ if ( !pDocShTables->GetError() ) // errors only
+ {
+ FillTables_Impl( &pDocShTables->GetDocument() );
+ m_xFtPath->set_label(pDocShTables->GetTitle(SFX_TITLE_FULLNAME));
+ }
+ else
+ {
+ pDocShTables->DoClose();
+ aDocShTablesRef.clear();
+ pDocShTables = nullptr;
+
+ FillTables_Impl( nullptr );
+ m_xFtPath->set_label(OUString());
+ }
+ }
+
+ DoEnable_Impl();
+ }
+ else if ( bMustClose )
+ // execute slot FID_INS_TABLE_EXT and cancel file dialog
+ m_xDialog->response(RET_CANCEL);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/lbseldlg.cxx b/sc/source/ui/miscdlgs/lbseldlg.cxx
new file mode 100644
index 000000000..4c0b592c7
--- /dev/null
+++ b/sc/source/ui/miscdlgs/lbseldlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <lbseldlg.hxx>
+
+ScSelEntryDlg::ScSelEntryDlg(weld::Window* pParent, const std::vector<OUString> &rEntryList)
+ : GenericDialogController(pParent, "modules/scalc/ui/selectrange.ui", "SelectRangeDialog")
+ , m_xLb(m_xBuilder->weld_tree_view("treeview"))
+{
+ m_xLb->set_size_request(m_xLb->get_approximate_digit_width() * 32,
+ m_xLb->get_height_rows(8));
+ m_xLb->connect_row_activated(LINK(this, ScSelEntryDlg, DblClkHdl));
+
+ for (const auto& rEntry : rEntryList)
+ m_xLb->append_text(rEntry);
+
+ if (m_xLb->n_children() > 0)
+ m_xLb->select(0);
+}
+
+ScSelEntryDlg::~ScSelEntryDlg()
+{
+}
+
+OUString ScSelEntryDlg::GetSelectedEntry() const
+{
+ return m_xLb->get_selected_text();
+}
+
+IMPL_LINK_NOARG(ScSelEntryDlg, DblClkHdl, weld::TreeView&, bool)
+{
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/linkarea.cxx b/sc/source/ui/miscdlgs/linkarea.cxx
new file mode 100644
index 000000000..09cfe6c3c
--- /dev/null
+++ b/sc/source/ui/miscdlgs/linkarea.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/docinsert.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <svtools/ehdl.hxx>
+#include <svtools/inettbc.hxx>
+#include <svtools/sfxecode.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <linkarea.hxx>
+#include <docsh.hxx>
+#include <tablink.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+ScLinkedAreaDlg::ScLinkedAreaDlg(weld::Widget* pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/externaldata.ui", "ExternalDataDialog")
+ , m_pSourceShell(nullptr)
+ , m_xCbUrl(new SvtURLBox(m_xBuilder->weld_combo_box("url")))
+ , m_xBtnBrowse(m_xBuilder->weld_button("browse"))
+ , m_xLbRanges(m_xBuilder->weld_tree_view("ranges"))
+ , m_xBtnReload(m_xBuilder->weld_check_button("reload"))
+ , m_xNfDelay(m_xBuilder->weld_spin_button("delay"))
+ , m_xFtSeconds(m_xBuilder->weld_label("secondsft"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+{
+ m_xLbRanges->set_selection_mode(SelectionMode::Multiple);
+
+ m_xCbUrl->connect_entry_activate(LINK(this, ScLinkedAreaDlg, FileHdl));
+ m_xBtnBrowse->connect_clicked(LINK( this, ScLinkedAreaDlg, BrowseHdl));
+ m_xLbRanges->connect_changed(LINK( this, ScLinkedAreaDlg, RangeHdl));
+ m_xLbRanges->set_size_request(m_xLbRanges->get_approximate_digit_width() * 54,
+ m_xLbRanges->get_height_rows(5));
+ m_xBtnReload->connect_toggled(LINK( this, ScLinkedAreaDlg, ReloadHdl));
+ UpdateEnable();
+}
+
+ScLinkedAreaDlg::~ScLinkedAreaDlg()
+{
+}
+
+constexpr OUStringLiteral FILTERNAME_HTML = u"HTML (StarCalc)";
+constexpr OUStringLiteral FILTERNAME_QUERY = u"calc_HTML_WebQuery";
+
+IMPL_LINK_NOARG(ScLinkedAreaDlg, BrowseHdl, weld::Button&, void)
+{
+ m_xDocInserter.reset( new sfx2::DocumentInserter(m_xDialog.get(), ScDocShell::Factory().GetFactoryName()) );
+ m_xDocInserter->StartExecuteModal( LINK( this, ScLinkedAreaDlg, DialogClosedHdl ) );
+}
+
+IMPL_LINK_NOARG(ScLinkedAreaDlg, FileHdl, weld::ComboBox&, bool)
+{
+ OUString aEntered = m_xCbUrl->GetURL();
+ if (m_pSourceShell)
+ {
+ SfxMedium* pMed = m_pSourceShell->GetMedium();
+ if ( aEntered == pMed->GetName() )
+ {
+ // already loaded - nothing to do
+ return true;
+ }
+ }
+
+ OUString aFilter;
+ OUString aOptions;
+ // get filter name by looking at the file content (bWithContent = true)
+ // Break operation if any error occurred inside.
+ if (!ScDocumentLoader::GetFilterName( aEntered, aFilter, aOptions, true, false ))
+ return true;
+
+ // #i53241# replace HTML filter with DataQuery filter
+ if (aFilter == FILTERNAME_HTML)
+ aFilter = FILTERNAME_QUERY;
+
+ LoadDocument( aEntered, aFilter, aOptions );
+
+ UpdateSourceRanges();
+ UpdateEnable();
+
+ return true;
+}
+
+void ScLinkedAreaDlg::LoadDocument( const OUString& rFile, const OUString& rFilter, const OUString& rOptions )
+{
+ if (m_pSourceShell)
+ {
+ // unload old document
+ m_pSourceShell->DoClose();
+ m_pSourceShell = nullptr;
+ aSourceRef.clear();
+ }
+
+ if ( rFile.isEmpty() )
+ return;
+
+ weld::WaitObject aWait(m_xDialog.get());
+
+ OUString aNewFilter = rFilter;
+ OUString aNewOptions = rOptions;
+
+ SfxErrorContext aEc( ERRCTX_SFX_OPENDOC, rFile );
+
+ ScDocumentLoader aLoader( rFile, aNewFilter, aNewOptions, 0, m_xDialog.get() ); // with interaction
+ m_pSourceShell = aLoader.GetDocShell();
+ if (m_pSourceShell)
+ {
+ ErrCode nErr = m_pSourceShell->GetErrorCode();
+ if (nErr)
+ ErrorHandler::HandleError( nErr ); // including warnings
+
+ aSourceRef = m_pSourceShell;
+ aLoader.ReleaseDocRef(); // don't call DoClose in DocLoader dtor
+ }
+}
+
+void ScLinkedAreaDlg::InitFromOldLink( const OUString& rFile, const OUString& rFilter,
+ const OUString& rOptions, std::u16string_view rSource,
+ sal_Int32 nRefreshDelaySeconds )
+{
+ LoadDocument( rFile, rFilter, rOptions );
+ if (m_pSourceShell)
+ {
+ SfxMedium* pMed = m_pSourceShell->GetMedium();
+ m_xCbUrl->set_entry_text(pMed->GetName());
+ }
+ else
+ m_xCbUrl->set_entry_text(OUString());
+
+ UpdateSourceRanges();
+
+ if (!rSource.empty())
+ {
+ sal_Int32 nIdx {0};
+ do
+ {
+ m_xLbRanges->select_text(OUString(o3tl::getToken(rSource, 0, ';', nIdx)));
+ }
+ while (nIdx>0);
+ }
+
+ bool bDoRefresh = (nRefreshDelaySeconds != 0);
+ m_xBtnReload->set_active(bDoRefresh);
+ if (bDoRefresh)
+ m_xNfDelay->set_value(nRefreshDelaySeconds);
+
+ UpdateEnable();
+}
+
+IMPL_LINK_NOARG(ScLinkedAreaDlg, RangeHdl, weld::TreeView&, void)
+{
+ UpdateEnable();
+}
+
+IMPL_LINK_NOARG(ScLinkedAreaDlg, ReloadHdl, weld::Toggleable&, void)
+{
+ UpdateEnable();
+}
+
+IMPL_LINK( ScLinkedAreaDlg, DialogClosedHdl, sfx2::FileDialogHelper*, _pFileDlg, void )
+{
+ if ( _pFileDlg->GetError() != ERRCODE_NONE )
+ return;
+
+ std::unique_ptr<SfxMedium> pMed = m_xDocInserter->CreateMedium();
+ if ( pMed )
+ {
+ weld::WaitObject aWait(m_xDialog.get());
+
+ // replace HTML filter with DataQuery filter
+ std::shared_ptr<const SfxFilter> pFilter = pMed->GetFilter();
+ if (pFilter && FILTERNAME_HTML == pFilter->GetFilterName())
+ {
+ std::shared_ptr<const SfxFilter> pNewFilter =
+ ScDocShell::Factory().GetFilterContainer()->GetFilter4FilterName( FILTERNAME_QUERY );
+ if( pNewFilter )
+ pMed->SetFilter( pNewFilter );
+ }
+
+ // ERRCTX_SFX_OPENDOC -> "Error loading document"
+ SfxErrorContext aEc( ERRCTX_SFX_OPENDOC, pMed->GetName() );
+
+ if (m_pSourceShell)
+ m_pSourceShell->DoClose(); // deleted when assigning aSourceRef
+
+ pMed->UseInteractionHandler( true ); // to enable the filter options dialog
+
+ m_pSourceShell = new ScDocShell;
+ aSourceRef = m_pSourceShell;
+ m_pSourceShell->DoLoad( pMed.get() );
+
+ ErrCode nErr = m_pSourceShell->GetErrorCode();
+ if (nErr)
+ ErrorHandler::HandleError( nErr ); // including warnings
+
+ if (!m_pSourceShell->GetError()) // only errors
+ {
+ m_xCbUrl->set_entry_text(pMed->GetName());
+ }
+ else
+ {
+ m_pSourceShell->DoClose();
+ m_pSourceShell = nullptr;
+ aSourceRef.clear();
+
+ m_xCbUrl->set_entry_text(OUString());
+ }
+ pMed.release(); // DoLoad takes ownership
+ }
+
+ UpdateSourceRanges();
+ UpdateEnable();
+}
+
+#undef FILTERNAME_HTML
+#undef FILTERNAME_QUERY
+
+void ScLinkedAreaDlg::UpdateSourceRanges()
+{
+ m_xLbRanges->freeze();
+
+ m_xLbRanges->clear();
+ if ( m_pSourceShell )
+ {
+ std::shared_ptr<const SfxFilter> pFilter = m_pSourceShell->GetMedium()->GetFilter();
+ if (pFilter && pFilter->GetFilterName() == SC_TEXT_CSV_FILTER_NAME)
+ {
+ // Insert dummy All range to have something selectable.
+ m_xLbRanges->append_text("CSV_all");
+ }
+
+ // tdf#142600 - list tables in order of their appearance in the document's source
+ const ScRangeName* pRangeName = m_pSourceShell->GetDocument().GetRangeName();
+ for (size_t i = 1; i <= pRangeName->index_size(); i++)
+ {
+ if (const ScRangeData* pRangeData = pRangeName->findByIndex(i))
+ {
+ m_xLbRanges->append_text(pRangeData->GetName());
+ }
+ }
+ }
+
+ m_xLbRanges->thaw();
+
+ if (m_xLbRanges->n_children() >= 1)
+ m_xLbRanges->select(0);
+ else
+ {
+ m_xLbRanges->append_text(ScResId(STR_NO_NAMED_RANGES_AVAILABLE));
+ m_xLbRanges->set_sensitive(false);
+ }
+}
+
+void ScLinkedAreaDlg::UpdateEnable()
+{
+ bool bEnable = ( m_pSourceShell && m_xLbRanges->count_selected_rows() );
+ m_xBtnOk->set_sensitive(bEnable);
+
+ bool bReload = m_xBtnReload->get_active();
+ m_xNfDelay->set_sensitive(bReload);
+ m_xFtSeconds->set_sensitive(bReload);
+}
+
+OUString ScLinkedAreaDlg::GetURL() const
+{
+ if (m_pSourceShell)
+ {
+ SfxMedium* pMed = m_pSourceShell->GetMedium();
+ return pMed->GetName();
+ }
+ return OUString();
+}
+
+OUString ScLinkedAreaDlg::GetFilter() const
+{
+ if (m_pSourceShell)
+ {
+ SfxMedium* pMed = m_pSourceShell->GetMedium();
+ return pMed->GetFilter()->GetFilterName();
+ }
+ return OUString();
+}
+
+OUString ScLinkedAreaDlg::GetOptions() const
+{
+ if (m_pSourceShell)
+ {
+ SfxMedium* pMed = m_pSourceShell->GetMedium();
+ return ScDocumentLoader::GetOptions( *pMed );
+ }
+ return OUString();
+}
+
+OUString ScLinkedAreaDlg::GetSource() const
+{
+ OUStringBuffer aBuf;
+ std::vector<OUString> aSelection = m_xLbRanges->get_selected_rows_text();
+ for (size_t i = 0; i < aSelection.size(); ++i)
+ {
+ if (i > 0)
+ aBuf.append(';');
+ aBuf.append(aSelection[i]);
+ }
+ return aBuf.makeStringAndClear();
+}
+
+sal_Int32 ScLinkedAreaDlg::GetRefreshDelaySeconds() const
+{
+ if (m_xBtnReload->get_active())
+ return m_xNfDelay->get_value();
+ else
+ return 0; // disabled
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/mergecellsdialog.cxx b/sc/source/ui/miscdlgs/mergecellsdialog.cxx
new file mode 100644
index 000000000..2bfcc5da3
--- /dev/null
+++ b/sc/source/ui/miscdlgs/mergecellsdialog.cxx
@@ -0,0 +1,36 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <mergecellsdialog.hxx>
+
+ScMergeCellsDialog::ScMergeCellsDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/mergecellsdialog.ui", "MergeCellsDialog")
+ , m_xRBMoveContent(m_xBuilder->weld_radio_button("move-cells-radio"))
+ , m_xRBKeepContent(m_xBuilder->weld_radio_button("keep-content-radio"))
+ , m_xRBEmptyContent(m_xBuilder->weld_radio_button("empty-cells-radio"))
+{
+ m_xRBKeepContent->set_active(true);
+}
+
+ScMergeCellsDialog::~ScMergeCellsDialog() {}
+
+ScMergeCellsOption ScMergeCellsDialog::GetMergeCellsOption() const
+{
+ if (m_xRBMoveContent->get_active())
+ return MoveContentHiddenCells;
+ if (m_xRBKeepContent->get_active())
+ return KeepContentHiddenCells;
+ if (m_xRBEmptyContent->get_active())
+ return EmptyContentHiddenCells;
+ assert(!"Unknown selection for merge cells.");
+ return KeepContentHiddenCells; // default value
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/mtrindlg.cxx b/sc/source/ui/miscdlgs/mtrindlg.cxx
new file mode 100644
index 000000000..7f234131f
--- /dev/null
+++ b/sc/source/ui/miscdlgs/mtrindlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <mtrindlg.hxx>
+
+ScMetricInputDlg::ScMetricInputDlg( weld::Window* pParent,
+ const OString& sDialogName,
+ tools::Long nCurrent,
+ tools::Long nDefault,
+ FieldUnit eFUnit,
+ sal_uInt16 nDecimals,
+ tools::Long nMaximum,
+ tools::Long nMinimum)
+
+ : GenericDialogController(pParent, "modules/scalc/ui/" + OStringToOUString(
+ sDialogName.toAsciiLowerCase(), RTL_TEXTENCODING_UTF8) + ".ui", sDialogName)
+ , m_xEdValue(m_xBuilder->weld_metric_spin_button("value", FieldUnit::CM))
+ , m_xBtnDefVal(m_xBuilder->weld_check_button("default"))
+{
+ m_xBtnDefVal->connect_toggled(LINK(this, ScMetricInputDlg, SetDefValHdl));
+ m_xEdValue->connect_value_changed(LINK( this, ScMetricInputDlg, ModifyHdl));
+
+ m_xEdValue->set_unit(eFUnit);
+ m_xEdValue->set_digits(nDecimals);
+ m_xEdValue->set_range(m_xEdValue->normalize(nMinimum),
+ m_xEdValue->normalize(nMaximum), FieldUnit::TWIP);
+
+ sal_Int64 nMin(0), nMax(0);
+ m_xEdValue->get_range(nMin, nMax, FieldUnit::TWIP);
+
+ auto nIncrement = m_xEdValue->normalize(1);
+ m_xEdValue->set_increments(nIncrement / 10, nIncrement, FieldUnit::NONE);
+ m_xEdValue->set_value(m_xEdValue->normalize(nDefault), FieldUnit::TWIP);
+ nDefaultValue = m_xEdValue->get_value(FieldUnit::NONE);
+ m_xEdValue->set_value(m_xEdValue->normalize(nCurrent), FieldUnit::TWIP);
+ nCurrentValue = m_xEdValue->get_value(FieldUnit::NONE);
+ m_xBtnDefVal->set_active(nCurrentValue == nDefaultValue);
+}
+
+ScMetricInputDlg::~ScMetricInputDlg()
+{
+}
+
+int ScMetricInputDlg::GetInputValue() const
+{
+/*
+ with decimal digits
+
+ double nVal = m_xEdValue->GetValue( eUnit );
+ sal_uInt16 nDecs = m_xEdValue->GetDecimalDigits();
+ double nFactor = 0.0;
+
+ // static long ImpPower10( sal_uInt16 nDecs )
+ {
+ nFactor = 1.0;
+
+ for ( sal_uInt16 i=0; i < nDecs; i++ )
+ nFactor *= 10.0;
+ }
+
+ return nVal / nFactor;
+*/
+ // first cut off the decimal digits - not that great...
+
+ return m_xEdValue->denormalize(m_xEdValue->get_value(FieldUnit::TWIP));
+}
+
+// Handler:
+
+IMPL_LINK_NOARG(ScMetricInputDlg, SetDefValHdl, weld::Toggleable&, void)
+{
+ if (m_xBtnDefVal->get_active())
+ {
+ nCurrentValue = m_xEdValue->get_value(FieldUnit::NONE);
+ m_xEdValue->set_value(nDefaultValue, FieldUnit::NONE);
+ }
+ else
+ m_xEdValue->set_value(nCurrentValue, FieldUnit::NONE);
+}
+
+IMPL_LINK_NOARG(ScMetricInputDlg, ModifyHdl, weld::MetricSpinButton&, void)
+{
+ m_xBtnDefVal->set_active(nDefaultValue == m_xEdValue->get_value(FieldUnit::NONE));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/mvtabdlg.cxx b/sc/source/ui/miscdlgs/mvtabdlg.cxx
new file mode 100644
index 000000000..80eeaeade
--- /dev/null
+++ b/sc/source/ui/miscdlgs/mvtabdlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <mvtabdlg.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <comphelper/lok.hxx>
+
+ScMoveTableDlg::ScMoveTableDlg(weld::Window* pParent, const OUString& rDefault)
+ : GenericDialogController(pParent, "modules/scalc/ui/movecopysheet.ui", "MoveCopySheetDialog")
+ , maDefaultName(rDefault)
+ , mnCurrentDocPos(0)
+ , nDocument(0)
+ , nTable(0)
+ , bCopyTable(false)
+ , bRenameTable(false)
+ , mbEverEdited(false)
+ , m_xBtnMove(m_xBuilder->weld_radio_button("move"))
+ , m_xBtnCopy(m_xBuilder->weld_radio_button("copy"))
+ , m_xFtDoc(m_xBuilder->weld_label("toDocumentLabel"))
+ , m_xLbDoc(m_xBuilder->weld_combo_box("toDocument"))
+ , m_xLbTable(m_xBuilder->weld_tree_view("insertBefore"))
+ , m_xEdTabName(m_xBuilder->weld_entry("newName"))
+ , m_xFtWarn(m_xBuilder->weld_label("newNameWarn"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xUnusedLabel(m_xBuilder->weld_label("warnunused"))
+ , m_xEmptyLabel(m_xBuilder->weld_label("warnempty"))
+ , m_xInvalidLabel(m_xBuilder->weld_label("warninvalid"))
+{
+ assert(m_xLbDoc->get_count() == 2);
+ msCurrentDoc = m_xLbDoc->get_text(0);
+ msNewDoc = m_xLbDoc->get_text(1);
+ m_xLbDoc->clear();
+ assert(m_xLbDoc->get_count() == 0);
+
+ m_xLbTable->set_size_request(-1, m_xLbTable->get_height_rows(8));
+
+ msStrTabNameUsed = m_xUnusedLabel->get_label();
+ msStrTabNameEmpty = m_xEmptyLabel->get_label();
+ msStrTabNameInvalid = m_xInvalidLabel->get_label();
+
+ Init();
+}
+
+ScMoveTableDlg::~ScMoveTableDlg() {}
+
+void ScMoveTableDlg::GetTabNameString(OUString& rString) const
+{
+ rString = m_xEdTabName->get_text();
+}
+
+void ScMoveTableDlg::SetForceCopyTable()
+{
+ m_xBtnCopy->set_active(true);
+ m_xBtnMove->set_sensitive(false);
+ m_xBtnCopy->set_sensitive(false);
+ SetOkBtnLabel();
+}
+
+void ScMoveTableDlg::EnableRenameTable(bool bFlag)
+{
+ bRenameTable = bFlag;
+ m_xEdTabName->set_sensitive(bFlag);
+ ResetRenameInput();
+}
+
+void ScMoveTableDlg::ResetRenameInput()
+{
+ if (mbEverEdited)
+ {
+ // Don't reset the name when the sheet name has ever been edited.
+ // But check the name, as this is also called for change of copy/move
+ // buttons and document listbox selection.
+ CheckNewTabName();
+ return;
+ }
+
+ if (!m_xEdTabName->get_sensitive())
+ {
+ m_xEdTabName->set_text(OUString());
+ return;
+ }
+
+ bool bVal = m_xBtnCopy->get_active();
+ if (bVal)
+ {
+ // copy
+ ScDocument* pDoc = GetSelectedDoc();
+ if (pDoc)
+ {
+ OUString aStr = maDefaultName;
+ pDoc->CreateValidTabName(aStr);
+ m_xEdTabName->set_text(aStr);
+ }
+ else
+ m_xEdTabName->set_text(maDefaultName);
+ }
+ else
+ {
+ // move
+ m_xEdTabName->set_text(maDefaultName);
+ }
+
+ CheckNewTabName();
+}
+
+void ScMoveTableDlg::CheckNewTabName()
+{
+ const OUString aNewName = m_xEdTabName->get_text();
+ if (aNewName.isEmpty())
+ {
+ // New sheet name is empty. This is not good.
+ m_xFtWarn->show();
+ //TODO m_xFtWarn->SetControlBackground(COL_YELLOW);
+ m_xFtWarn->set_label(msStrTabNameEmpty);
+ m_xBtnOk->set_sensitive(false);
+ return;
+ }
+
+ if (!ScDocument::ValidTabName(aNewName))
+ {
+ // New sheet name contains invalid characters.
+ m_xFtWarn->show();
+ //TODO m_xFtWarn->SetControlBackground(COL_YELLOW);
+ m_xFtWarn->set_label(msStrTabNameInvalid);
+ m_xBtnOk->set_sensitive(false);
+ return;
+ }
+
+ bool bMoveInCurrentDoc = m_xBtnMove->get_active() && m_xLbDoc->get_active() == mnCurrentDocPos;
+ bool bFound = false;
+ const int nLast = m_xLbTable->n_children();
+ for (int i = 0; i < nLast && !bFound; ++i)
+ {
+ if (aNewName == m_xLbTable->get_text(i))
+ {
+ // Only for move within same document the same name is allowed.
+ if (!bMoveInCurrentDoc || maDefaultName != m_xEdTabName->get_text())
+ bFound = true;
+ }
+ }
+
+ if (bFound)
+ {
+ m_xFtWarn->show();
+ //TODO m_xFtWarn->SetControlBackground(COL_YELLOW);
+ m_xFtWarn->set_label(msStrTabNameUsed);
+ m_xBtnOk->set_sensitive(false);
+ }
+ else
+ {
+ m_xFtWarn->hide();
+ //TODO m_xFtWarn->SetControlBackground();
+ m_xFtWarn->set_label(OUString());
+ m_xBtnOk->set_sensitive(true);
+ }
+}
+
+ScDocument* ScMoveTableDlg::GetSelectedDoc()
+{
+ return weld::fromId<ScDocument*>(m_xLbDoc->get_active_id());
+}
+
+void ScMoveTableDlg::Init()
+{
+ m_xBtnOk->connect_clicked(LINK(this, ScMoveTableDlg, OkHdl));
+ m_xLbDoc->connect_changed(LINK(this, ScMoveTableDlg, SelHdl));
+ m_xBtnCopy->connect_toggled(LINK(this, ScMoveTableDlg, CheckBtnHdl));
+ m_xBtnMove->connect_toggled(LINK(this, ScMoveTableDlg, CheckBtnHdl));
+ m_xEdTabName->connect_changed(LINK(this, ScMoveTableDlg, CheckNameHdl));
+ m_xBtnMove->set_active(true);
+ m_xBtnCopy->set_active(false);
+ m_xEdTabName->set_sensitive(false);
+ m_xFtWarn->hide();
+ InitDocListBox();
+ SelHdl(*m_xLbDoc);
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ m_xFtDoc->hide();
+ m_xLbDoc->hide();
+ }
+ SetOkBtnLabel();
+}
+
+void ScMoveTableDlg::InitDocListBox()
+{
+ SfxObjectShell* pSh = SfxObjectShell::GetFirst();
+ ScDocShell* pScSh = nullptr;
+ sal_uInt16 nSelPos = 0;
+ sal_uInt16 i = 0;
+
+ m_xLbDoc->clear();
+ m_xLbDoc->freeze();
+
+ while (pSh)
+ {
+ pScSh = dynamic_cast<ScDocShell*>(pSh);
+
+ if (pScSh)
+ {
+ OUString aEntryName = pScSh->GetTitle();
+
+ if (pScSh == SfxObjectShell::Current())
+ {
+ mnCurrentDocPos = nSelPos = i;
+ aEntryName += " " + msCurrentDoc;
+ }
+
+ OUString sId(weld::toId(&pScSh->GetDocument()));
+ m_xLbDoc->insert(i, aEntryName, &sId, nullptr, nullptr);
+
+ i++;
+ }
+ pSh = SfxObjectShell::GetNext(*pSh);
+ }
+
+ m_xLbDoc->thaw();
+ m_xLbDoc->append_text(msNewDoc);
+ m_xLbDoc->set_active(nSelPos);
+}
+
+void ScMoveTableDlg::SetOkBtnLabel()
+{
+ // tdf#139464 Write "Copy" or "Move" on OK button
+ m_xBtnOk->set_label(m_xBtnCopy->get_active() ? m_xBtnCopy->get_label()
+ : m_xBtnMove->get_label());
+}
+
+// Handler:
+
+IMPL_LINK(ScMoveTableDlg, CheckBtnHdl, weld::Toggleable&, rBtn, void)
+{
+ if (&rBtn == m_xBtnCopy.get())
+ ResetRenameInput();
+ SetOkBtnLabel();
+}
+
+IMPL_LINK_NOARG(ScMoveTableDlg, OkHdl, weld::Button&, void)
+{
+ const sal_Int32 nDocSel = m_xLbDoc->get_active();
+ const sal_Int32 nDocLast = m_xLbDoc->get_count() - 1;
+ const sal_Int32 nTabSel = m_xLbTable->get_selected_index();
+ const sal_Int32 nTabLast = m_xLbTable->n_children() - 1;
+
+ nDocument = (nDocSel != nDocLast) ? nDocSel : SC_DOC_NEW;
+ nTable = (nTabSel != nTabLast) ? static_cast<SCTAB>(nTabSel) : SC_TAB_APPEND;
+ bCopyTable = m_xBtnCopy->get_active();
+
+ if (bCopyTable)
+ {
+ // Return an empty string when the new name is the same as the
+ // automatic name assigned by the document.
+ OUString aCopyName = maDefaultName;
+ ScDocument* pDoc = GetSelectedDoc();
+ if (pDoc)
+ pDoc->CreateValidTabName(aCopyName);
+ if (aCopyName == m_xEdTabName->get_text())
+ m_xEdTabName->set_text(OUString());
+ }
+ else
+ {
+ // Return an empty string, when the new name is the same as the
+ // original name.
+ if (maDefaultName == m_xEdTabName->get_text())
+ m_xEdTabName->set_text(OUString());
+ }
+
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ScMoveTableDlg, SelHdl, weld::ComboBox&, void)
+{
+ ScDocument* pDoc = GetSelectedDoc();
+ OUString aName;
+
+ m_xLbTable->clear();
+ m_xLbTable->freeze();
+ if (pDoc)
+ {
+ SCTAB nLast = pDoc->GetTableCount() - 1;
+ for (SCTAB i = 0; i <= nLast; ++i)
+ {
+ pDoc->GetName(i, aName);
+ m_xLbTable->append_text(aName);
+ }
+ }
+ m_xLbTable->append_text(ScResId(STR_MOVE_TO_END));
+ m_xLbTable->thaw();
+ m_xLbTable->select(0);
+ ResetRenameInput();
+}
+
+IMPL_LINK_NOARG(ScMoveTableDlg, CheckNameHdl, weld::Entry&, void)
+{
+ mbEverEdited = true;
+ CheckNewTabName();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/namecrea.cxx b/sc/source/ui/miscdlgs/namecrea.cxx
new file mode 100644
index 000000000..334b89d8b
--- /dev/null
+++ b/sc/source/ui/miscdlgs/namecrea.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <namecrea.hxx>
+
+ScNameCreateDlg::ScNameCreateDlg(weld::Window* pParent, CreateNameFlags nFlags)
+ : GenericDialogController(pParent, "modules/scalc/ui/createnamesdialog.ui", "CreateNamesDialog")
+ , m_xTopBox(m_xBuilder->weld_check_button("top"))
+ , m_xLeftBox(m_xBuilder->weld_check_button("left"))
+ , m_xBottomBox(m_xBuilder->weld_check_button("bottom"))
+ , m_xRightBox(m_xBuilder->weld_check_button("right"))
+{
+ m_xTopBox->set_active(bool(nFlags & CreateNameFlags::Top));
+ m_xLeftBox->set_active(bool(nFlags & CreateNameFlags::Left));
+ m_xBottomBox->set_active(bool(nFlags & CreateNameFlags::Bottom));
+ m_xRightBox->set_active(bool(nFlags & CreateNameFlags::Right));
+}
+
+ScNameCreateDlg::~ScNameCreateDlg() {}
+
+CreateNameFlags ScNameCreateDlg::GetFlags() const
+{
+ CreateNameFlags nResult = CreateNameFlags::NONE;
+
+ if (m_xTopBox->get_active())
+ nResult |= CreateNameFlags::Top;
+ if (m_xLeftBox->get_active())
+ nResult |= CreateNameFlags::Left;
+ if (m_xBottomBox->get_active())
+ nResult |= CreateNameFlags::Bottom;
+ if (m_xRightBox->get_active())
+ nResult |= CreateNameFlags::Right;
+
+ return nResult;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/optsolver.cxx b/sc/source/ui/miscdlgs/optsolver.cxx
new file mode 100644
index 000000000..f0f5eb30c
--- /dev/null
+++ b/sc/source/ui/miscdlgs/optsolver.cxx
@@ -0,0 +1,1075 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rangelst.hxx>
+#include <sfx2/bindings.hxx>
+#include <svl/numformat.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/svapp.hxx>
+
+#include <reffact.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <rangeutl.hxx>
+#include <convuno.hxx>
+#include <unonames.hxx>
+#include <solveroptions.hxx>
+#include <solverutil.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <optsolver.hxx>
+
+#include <com/sun/star/sheet/SolverConstraint.hpp>
+#include <com/sun/star/sheet/SolverConstraintOperator.hpp>
+#include <com/sun/star/sheet/XSolverDescription.hpp>
+#include <com/sun/star/sheet/XSolver.hpp>
+
+using namespace com::sun::star;
+
+ScSolverProgressDialog::ScSolverProgressDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/solverprogressdialog.ui",
+ "SolverProgressDialog")
+ , m_xFtTime(m_xBuilder->weld_label("progress"))
+{
+}
+
+ScSolverProgressDialog::~ScSolverProgressDialog()
+{
+}
+
+void ScSolverProgressDialog::HideTimeLimit()
+{
+ m_xFtTime->hide();
+}
+
+void ScSolverProgressDialog::SetTimeLimit( sal_Int32 nSeconds )
+{
+ OUString aOld = m_xFtTime->get_label();
+ OUString aNew = aOld.replaceFirst("#", OUString::number(nSeconds));
+ m_xFtTime->set_label(aNew);
+}
+
+ScSolverNoSolutionDialog::ScSolverNoSolutionDialog(weld::Window* pParent, const OUString& rErrorText)
+ : GenericDialogController(pParent, "modules/scalc/ui/nosolutiondialog.ui", "NoSolutionDialog")
+ , m_xFtErrorText(m_xBuilder->weld_label("error"))
+{
+ m_xFtErrorText->set_label(rErrorText);
+}
+
+ScSolverNoSolutionDialog::~ScSolverNoSolutionDialog()
+{
+}
+
+ScSolverSuccessDialog::ScSolverSuccessDialog(weld::Window* pParent, std::u16string_view rSolution)
+ : GenericDialogController(pParent, "modules/scalc/ui/solversuccessdialog.ui", "SolverSuccessDialog")
+ , m_xFtResult(m_xBuilder->weld_label("result"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+{
+ m_xBtnOk->connect_clicked(LINK(this, ScSolverSuccessDialog, ClickHdl));
+ m_xBtnCancel->connect_clicked(LINK(this, ScSolverSuccessDialog, ClickHdl));
+ OUString aMessage = m_xFtResult->get_label() + " " + rSolution;
+ m_xFtResult->set_label(aMessage);
+}
+
+ScSolverSuccessDialog::~ScSolverSuccessDialog()
+{
+}
+
+IMPL_LINK(ScSolverSuccessDialog, ClickHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == m_xBtnOk.get())
+ m_xDialog->response(RET_OK);
+ else
+ m_xDialog->response(RET_CANCEL);
+}
+
+ScCursorRefEdit::ScCursorRefEdit(std::unique_ptr<weld::Entry> xControl)
+ : formula::RefEdit(std::move(xControl))
+{
+ xEntry->connect_key_press(Link<const KeyEvent&, bool>()); //acknowledge we first remove the old one
+ xEntry->connect_key_press(LINK(this, ScCursorRefEdit, KeyInputHdl));
+}
+
+void ScCursorRefEdit::SetCursorLinks( const Link<ScCursorRefEdit&,void>& rUp, const Link<ScCursorRefEdit&,void>& rDown )
+{
+ maCursorUpLink = rUp;
+ maCursorDownLink = rDown;
+}
+
+IMPL_LINK(ScCursorRefEdit, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+ bool bUp = (aCode.GetCode() == KEY_UP);
+ bool bDown = (aCode.GetCode() == KEY_DOWN);
+ if ( !aCode.IsShift() && !aCode.IsMod1() && !aCode.IsMod2() && ( bUp || bDown ) )
+ {
+ if ( bUp )
+ maCursorUpLink.Call( *this );
+ else
+ maCursorDownLink.Call( *this );
+ return true;
+ }
+ return formula::RefEdit::KeyInput(rKEvt);
+}
+
+ScOptSolverSave::ScOptSolverSave( const OUString& rObjective, bool bMax, bool bMin, bool bValue,
+ const OUString& rTarget, const OUString& rVariable,
+ std::vector<ScOptConditionRow>&& rConditions,
+ const OUString& rEngine,
+ const uno::Sequence<beans::PropertyValue>& rProperties ) :
+ maObjective( rObjective ),
+ mbMax( bMax ),
+ mbMin( bMin ),
+ mbValue( bValue ),
+ maTarget( rTarget ),
+ maVariable( rVariable ),
+ maConditions( std::move(rConditions) ),
+ maEngine( rEngine ),
+ maProperties( rProperties )
+{
+}
+
+ScOptSolverDlg::ScOptSolverDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScDocShell* pDocSh, const ScAddress& aCursorPos)
+ : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/solverdlg.ui", "SolverDialog")
+ , maInputError(ScResId(STR_INVALIDINPUT))
+ , maConditionError(ScResId(STR_INVALIDCONDITION))
+
+ , mpDocShell(pDocSh)
+ , mrDoc(pDocSh->GetDocument())
+ , mnCurTab(aCursorPos.Tab())
+ , mbDlgLostFocus(false)
+ , nScrollPos(0)
+ , mpEdActive(nullptr)
+ , m_xFtObjectiveCell(m_xBuilder->weld_label("targetlabel"))
+ , m_xEdObjectiveCell(new formula::RefEdit(m_xBuilder->weld_entry("targetedit")))
+ , m_xRBObjectiveCell(new formula::RefButton(m_xBuilder->weld_button("targetbutton")))
+ , m_xRbMax(m_xBuilder->weld_radio_button("max"))
+ , m_xRbMin(m_xBuilder->weld_radio_button("min"))
+ , m_xRbValue(m_xBuilder->weld_radio_button("value"))
+ , m_xEdTargetValue(new formula::RefEdit(m_xBuilder->weld_entry("valueedit")))
+ , m_xRBTargetValue(new formula::RefButton(m_xBuilder->weld_button("valuebutton")))
+ , m_xFtVariableCells(m_xBuilder->weld_label("changelabel"))
+ , m_xEdVariableCells(new formula::RefEdit(m_xBuilder->weld_entry("changeedit")))
+ , m_xRBVariableCells(new formula::RefButton(m_xBuilder->weld_button("changebutton")))
+ , m_xFtCellRef(m_xBuilder->weld_label("cellreflabel"))
+ , m_xEdLeft1(new ScCursorRefEdit(m_xBuilder->weld_entry("ref1edit")))
+ , m_xRBLeft1(new formula::RefButton(m_xBuilder->weld_button("ref1button")))
+ , m_xFtOperator(m_xBuilder->weld_label("oplabel"))
+ , m_xLbOp1(m_xBuilder->weld_combo_box("op1list"))
+ , m_xFtConstraint(m_xBuilder->weld_label("constraintlabel"))
+ , m_xEdRight1(new ScCursorRefEdit(m_xBuilder->weld_entry("val1edit")))
+ , m_xRBRight1(new formula::RefButton(m_xBuilder->weld_button("val1button")))
+ , m_xBtnDel1(m_xBuilder->weld_button("del1"))
+ , m_xEdLeft2(new ScCursorRefEdit(m_xBuilder->weld_entry("ref2edit")))
+ , m_xRBLeft2(new formula::RefButton(m_xBuilder->weld_button("ref2button")))
+ , m_xLbOp2(m_xBuilder->weld_combo_box("op2list"))
+ , m_xEdRight2(new ScCursorRefEdit(m_xBuilder->weld_entry("val2edit")))
+ , m_xRBRight2(new formula::RefButton(m_xBuilder->weld_button("val2button")))
+ , m_xBtnDel2(m_xBuilder->weld_button("del2"))
+ , m_xEdLeft3(new ScCursorRefEdit(m_xBuilder->weld_entry("ref3edit")))
+ , m_xRBLeft3(new formula::RefButton(m_xBuilder->weld_button("ref3button")))
+ , m_xLbOp3(m_xBuilder->weld_combo_box("op3list"))
+ , m_xEdRight3(new ScCursorRefEdit(m_xBuilder->weld_entry("val3edit")))
+ , m_xRBRight3(new formula::RefButton(m_xBuilder->weld_button("val3button")))
+ , m_xBtnDel3(m_xBuilder->weld_button("del3"))
+ , m_xEdLeft4(new ScCursorRefEdit(m_xBuilder->weld_entry("ref4edit")))
+ , m_xRBLeft4(new formula::RefButton(m_xBuilder->weld_button("ref4button")))
+ , m_xLbOp4(m_xBuilder->weld_combo_box("op4list"))
+ , m_xEdRight4(new ScCursorRefEdit(m_xBuilder->weld_entry("val4edit")))
+ , m_xRBRight4(new formula::RefButton(m_xBuilder->weld_button("val4button")))
+ , m_xBtnDel4(m_xBuilder->weld_button("del4"))
+ , m_xScrollBar(m_xBuilder->weld_scrolled_window("scrollbar", true))
+ , m_xBtnOpt(m_xBuilder->weld_button("options"))
+ , m_xBtnClose(m_xBuilder->weld_button("close"))
+ , m_xBtnSolve(m_xBuilder->weld_button("ok"))
+ , m_xBtnResetAll(m_xBuilder->weld_button("resetall"))
+ , m_xResultFT(m_xBuilder->weld_label("result"))
+ , m_xContents(m_xBuilder->weld_widget("grid"))
+{
+ m_xEdObjectiveCell->SetReferences(this, m_xFtObjectiveCell.get());
+ m_xRBObjectiveCell->SetReferences(this, m_xEdObjectiveCell.get());
+ m_xEdTargetValue->SetReferences(this, m_xResultFT.get());
+ m_xRBTargetValue->SetReferences(this, m_xEdTargetValue.get());
+ m_xEdVariableCells->SetReferences(this, m_xFtVariableCells.get());
+ m_xRBVariableCells->SetReferences(this, m_xEdVariableCells.get());
+ m_xEdLeft1->SetReferences(this, m_xFtCellRef.get());
+ m_xRBLeft1->SetReferences(this, m_xEdLeft1.get());
+ m_xEdRight1->SetReferences(this, m_xFtConstraint.get());
+ m_xRBRight1->SetReferences(this, m_xEdRight1.get());
+ m_xEdLeft2->SetReferences(this, m_xFtCellRef.get());
+ m_xRBLeft2->SetReferences(this, m_xEdLeft2.get());
+ m_xEdRight2->SetReferences(this, m_xFtConstraint.get());
+ m_xRBRight2->SetReferences(this, m_xEdRight2.get());
+ m_xEdLeft3->SetReferences(this, m_xFtCellRef.get());
+ m_xRBLeft3->SetReferences(this, m_xEdLeft3.get());
+ m_xEdRight3->SetReferences(this, m_xFtConstraint.get());
+ m_xRBRight3->SetReferences(this, m_xEdRight3.get());
+ m_xEdLeft4->SetReferences(this, m_xFtCellRef.get());
+ m_xRBLeft4->SetReferences(this, m_xEdLeft4.get());
+ m_xEdRight4->SetReferences(this, m_xFtConstraint.get());
+ m_xRBRight4->SetReferences(this, m_xEdRight4.get());
+
+ mpLeftEdit[0] = m_xEdLeft1.get();
+ mpLeftButton[0] = m_xRBLeft1.get();
+ mpRightEdit[0] = m_xEdRight1.get();
+ mpRightButton[0] = m_xRBRight1.get();
+ mpOperator[0] = m_xLbOp1.get();
+ mpDelButton[0] = m_xBtnDel1.get();
+
+ mpLeftEdit[1] = m_xEdLeft2.get();
+ mpLeftButton[1] = m_xRBLeft2.get();
+ mpRightEdit[1] = m_xEdRight2.get();
+ mpRightButton[1] = m_xRBRight2.get();
+ mpOperator[1] = m_xLbOp2.get();
+ mpDelButton[1] = m_xBtnDel2.get();
+
+ mpLeftEdit[2] = m_xEdLeft3.get();
+ mpLeftButton[2] = m_xRBLeft3.get();
+ mpRightEdit[2] = m_xEdRight3.get();
+ mpRightButton[2] = m_xRBRight3.get();
+ mpOperator[2] = m_xLbOp3.get();
+ mpDelButton[2] = m_xBtnDel3.get();
+
+ mpLeftEdit[3] = m_xEdLeft4.get();
+ mpLeftButton[3] = m_xRBLeft4.get();
+ mpRightEdit[3] = m_xEdRight4.get();
+ mpRightButton[3] = m_xRBRight4.get();
+ mpOperator[3] = m_xLbOp4.get();
+ mpDelButton[3] = m_xBtnDel4.get();
+
+ Init( aCursorPos );
+}
+
+ScOptSolverDlg::~ScOptSolverDlg()
+{
+}
+
+void ScOptSolverDlg::Init(const ScAddress& rCursorPos)
+{
+ uno::Reference<frame::XFrame> xFrame = GetBindings().GetActiveFrame();
+ auto xDelNm = vcl::CommandInfoProvider::GetXGraphicForCommand(".uno:DeleteRows", xFrame);
+ for (weld::Button* pButton : mpDelButton)
+ pButton->set_image(xDelNm);
+
+ m_xBtnOpt->connect_clicked( LINK( this, ScOptSolverDlg, BtnHdl ) );
+ m_xBtnClose->connect_clicked( LINK( this, ScOptSolverDlg, BtnHdl ) );
+ m_xBtnSolve->connect_clicked( LINK( this, ScOptSolverDlg, BtnHdl ) );
+ m_xBtnResetAll->connect_clicked( LINK( this, ScOptSolverDlg, BtnHdl ) );
+
+ Link<formula::RefEdit&,void> aEditLink = LINK( this, ScOptSolverDlg, GetEditFocusHdl );
+ Link<formula::RefButton&,void> aButtonLink = LINK( this, ScOptSolverDlg, GetButtonFocusHdl );
+ m_xEdObjectiveCell->SetGetFocusHdl( aEditLink );
+ m_xRBObjectiveCell->SetGetFocusHdl( aButtonLink );
+ m_xEdTargetValue->SetGetFocusHdl( aEditLink );
+ m_xRBTargetValue->SetGetFocusHdl( aButtonLink );
+ m_xEdVariableCells->SetGetFocusHdl( aEditLink );
+ m_xRBVariableCells->SetGetFocusHdl( aButtonLink );
+ Link<weld::Widget&,void> aLink = LINK(this, ScOptSolverDlg, GetFocusHdl);
+ m_xRbValue->connect_focus_in(aLink);
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ mpLeftEdit[nRow]->SetGetFocusHdl( aEditLink );
+ mpLeftButton[nRow]->SetGetFocusHdl( aButtonLink );
+ mpRightEdit[nRow]->SetGetFocusHdl( aEditLink );
+ mpRightButton[nRow]->SetGetFocusHdl( aButtonLink );
+ mpOperator[nRow]->connect_focus_in(aLink);
+ }
+
+ aEditLink = LINK( this, ScOptSolverDlg, LoseEditFocusHdl );
+ aButtonLink = LINK( this, ScOptSolverDlg, LoseButtonFocusHdl );
+ m_xEdObjectiveCell->SetLoseFocusHdl( aEditLink );
+ m_xRBObjectiveCell->SetLoseFocusHdl( aButtonLink );
+ m_xEdTargetValue->SetLoseFocusHdl( aEditLink );
+ m_xRBTargetValue-> SetLoseFocusHdl( aButtonLink );
+ m_xEdVariableCells->SetLoseFocusHdl( aEditLink );
+ m_xRBVariableCells->SetLoseFocusHdl( aButtonLink );
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ mpLeftEdit[nRow]->SetLoseFocusHdl( aEditLink );
+ mpLeftButton[nRow]->SetLoseFocusHdl( aButtonLink );
+ mpRightEdit[nRow]->SetLoseFocusHdl( aEditLink );
+ mpRightButton[nRow]->SetLoseFocusHdl( aButtonLink );
+ }
+
+ Link<ScCursorRefEdit&,void> aCursorUp = LINK( this, ScOptSolverDlg, CursorUpHdl );
+ Link<ScCursorRefEdit&,void> aCursorDown = LINK( this, ScOptSolverDlg, CursorDownHdl );
+ Link<formula::RefEdit&,void> aCondModify = LINK( this, ScOptSolverDlg, CondModifyHdl );
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ mpLeftEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown );
+ mpRightEdit[nRow]->SetCursorLinks( aCursorUp, aCursorDown );
+ mpLeftEdit[nRow]->SetModifyHdl( aCondModify );
+ mpRightEdit[nRow]->SetModifyHdl( aCondModify );
+ mpDelButton[nRow]->connect_clicked( LINK( this, ScOptSolverDlg, DelBtnHdl ) );
+ mpOperator[nRow]->connect_changed( LINK( this, ScOptSolverDlg, SelectHdl ) );
+ }
+ m_xEdTargetValue->SetModifyHdl( LINK( this, ScOptSolverDlg, TargetModifyHdl ) );
+
+ Size aSize(m_xContents->get_preferred_size());
+ m_xContents->set_size_request(aSize.Width(), aSize.Height());
+ m_xScrollBar->connect_vadjustment_changed( LINK( this, ScOptSolverDlg, ScrollHdl ) );
+
+ m_xScrollBar->vadjustment_set_page_increment( EDIT_ROW_COUNT );
+ m_xScrollBar->vadjustment_set_page_size( EDIT_ROW_COUNT );
+ // Range is set in ShowConditions
+
+ // get available solver implementations
+ //! sort by descriptions?
+ ScSolverUtil::GetImplementations( maImplNames, maDescriptions );
+ bool bImplHasElements = maImplNames.hasElements();
+
+ const ScOptSolverSave* pOldData = mpDocShell->GetSolverSaveData();
+ if ( pOldData )
+ {
+ m_xEdObjectiveCell->SetRefString( pOldData->GetObjective() );
+ m_xRbMax->set_active( pOldData->GetMax() );
+ m_xRbMin->set_active( pOldData->GetMin() );
+ m_xRbValue->set_active( pOldData->GetValue() );
+ m_xEdTargetValue->SetRefString( pOldData->GetTarget() );
+ m_xEdVariableCells->SetRefString( pOldData->GetVariable() );
+ maConditions = pOldData->GetConditions();
+ maEngine = pOldData->GetEngine();
+ maProperties = pOldData->GetProperties();
+ }
+ else
+ {
+ m_xRbMax->set_active(true);
+ OUString aCursorStr;
+ if ( !mrDoc.GetRangeAtBlock( ScRange(rCursorPos), aCursorStr ) )
+ aCursorStr = rCursorPos.Format(ScRefFlags::ADDR_ABS, nullptr, mrDoc.GetAddressConvention());
+ m_xEdObjectiveCell->SetRefString( aCursorStr );
+ if ( bImplHasElements )
+ maEngine = maImplNames[0]; // use first implementation
+ }
+ ShowConditions();
+
+ m_xEdObjectiveCell->GrabFocus();
+ mpEdActive = m_xEdObjectiveCell.get();
+}
+
+void ScOptSolverDlg::ReadConditions()
+{
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ ScOptConditionRow aRowEntry;
+ aRowEntry.aLeftStr = mpLeftEdit[nRow]->GetText();
+ aRowEntry.aRightStr = mpRightEdit[nRow]->GetText();
+ aRowEntry.nOperator = mpOperator[nRow]->get_active();
+
+ tools::Long nVecPos = nScrollPos + nRow;
+ if ( nVecPos >= static_cast<tools::Long>(maConditions.size()) && !aRowEntry.IsDefault() )
+ maConditions.resize( nVecPos + 1 );
+
+ if ( nVecPos < static_cast<tools::Long>(maConditions.size()) )
+ maConditions[nVecPos] = aRowEntry;
+
+ // remove default entries at the end
+ size_t nSize = maConditions.size();
+ while ( nSize > 0 && maConditions[ nSize-1 ].IsDefault() )
+ --nSize;
+ maConditions.resize( nSize );
+ }
+}
+
+void ScOptSolverDlg::ShowConditions()
+{
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ ScOptConditionRow aRowEntry;
+
+ tools::Long nVecPos = nScrollPos + nRow;
+ if ( nVecPos < static_cast<tools::Long>(maConditions.size()) )
+ aRowEntry = maConditions[nVecPos];
+
+ mpLeftEdit[nRow]->SetRefString( aRowEntry.aLeftStr );
+ mpRightEdit[nRow]->SetRefString( aRowEntry.aRightStr );
+ mpOperator[nRow]->set_active( aRowEntry.nOperator );
+ }
+
+ // allow to scroll one page behind the visible or stored rows
+ tools::Long nVisible = nScrollPos + EDIT_ROW_COUNT;
+ tools::Long nMax = std::max( nVisible, static_cast<tools::Long>(maConditions.size()) );
+ m_xScrollBar->vadjustment_configure(nScrollPos, 0, nMax + EDIT_ROW_COUNT, 1,
+ EDIT_ROW_COUNT - 1, EDIT_ROW_COUNT);
+
+ EnableButtons();
+}
+
+void ScOptSolverDlg::EnableButtons()
+{
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ tools::Long nVecPos = nScrollPos + nRow;
+ mpDelButton[nRow]->set_sensitive(nVecPos < static_cast<tools::Long>(maConditions.size()));
+ }
+}
+
+void ScOptSolverDlg::Close()
+{
+ if (m_xOptDlg)
+ m_xOptDlg->response(RET_CANCEL);
+ assert(!m_xOptDlg);
+ DoClose( ScOptSolverDlgWrapper::GetChildWindowId() );
+}
+
+void ScOptSolverDlg::SetActive()
+{
+ if ( mbDlgLostFocus )
+ {
+ mbDlgLostFocus = false;
+ if( mpEdActive )
+ mpEdActive->GrabFocus();
+ }
+ else
+ {
+ m_xDialog->grab_focus();
+ }
+ RefInputDone();
+}
+
+void ScOptSolverDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
+{
+ if( !mpEdActive )
+ return;
+
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart(mpEdActive);
+
+ // "target"/"value": single cell
+ bool bSingle = ( mpEdActive == m_xEdObjectiveCell.get() || mpEdActive == m_xEdTargetValue.get() );
+
+ OUString aStr;
+ ScAddress aAdr = rRef.aStart;
+ ScRange aNewRef( rRef );
+ if ( bSingle )
+ aNewRef.aEnd = aAdr;
+
+ OUString aName;
+ if ( rDocP.GetRangeAtBlock( aNewRef, aName ) ) // named range: show name
+ aStr = aName;
+ else // format cell/range reference
+ {
+ ScRefFlags nFmt = ( aAdr.Tab() == mnCurTab ) ? ScRefFlags::ADDR_ABS : ScRefFlags::ADDR_ABS_3D;
+ if ( bSingle )
+ aStr = aAdr.Format(nFmt, &rDocP, rDocP.GetAddressConvention());
+ else
+ aStr = rRef.Format(rDocP, nFmt | ScRefFlags::RANGE_ABS, rDocP.GetAddressConvention());
+ }
+
+ // variable cells can be several ranges, so only the selection is replaced
+ if ( mpEdActive == m_xEdVariableCells.get() )
+ {
+ OUString aVal = mpEdActive->GetText();
+ Selection aSel = mpEdActive->GetSelection();
+ aSel.Justify();
+ aVal = aVal.replaceAt( aSel.Min(), aSel.Len(), aStr );
+ Selection aNewSel( aSel.Min(), aSel.Min()+aStr.getLength() );
+ mpEdActive->SetRefString( aVal );
+ mpEdActive->SetSelection( aNewSel );
+ }
+ else
+ mpEdActive->SetRefString( aStr );
+
+ ReadConditions();
+ EnableButtons();
+
+ // select "Value of" if a ref is input into "target" edit
+ if ( mpEdActive == m_xEdTargetValue.get() )
+ m_xRbValue->set_active(true);
+}
+
+bool ScOptSolverDlg::IsRefInputMode() const
+{
+ return mpEdActive != nullptr;
+}
+
+// Handler:
+
+IMPL_LINK(ScOptSolverDlg, BtnHdl, weld::Button&, rBtn, void)
+{
+ auto xKeepAlive = shared_from_this();
+ if (&rBtn == m_xBtnSolve.get() || &rBtn == m_xBtnClose.get())
+ {
+ bool bSolve = ( &rBtn == m_xBtnSolve.get() );
+
+ SetDispatcherLock( false );
+ SwitchToDocument();
+
+ bool bClose = true;
+ if ( bSolve )
+ bClose = CallSolver();
+
+ if ( bClose )
+ {
+ // Close: write dialog settings to DocShell for subsequent calls
+ ReadConditions();
+ std::unique_ptr<ScOptSolverSave> pSave( new ScOptSolverSave(
+ m_xEdObjectiveCell->GetText(), m_xRbMax->get_active(), m_xRbMin->get_active(), m_xRbValue->get_active(),
+ m_xEdTargetValue->GetText(), m_xEdVariableCells->GetText(), std::vector(maConditions), maEngine, maProperties ) );
+ mpDocShell->SetSolverSaveData( std::move(pSave) );
+ response(RET_CLOSE);
+ }
+ else
+ {
+ // no solution -> dialog is kept open
+ SetDispatcherLock( true );
+ }
+ }
+ else if (&rBtn == m_xBtnOpt.get())
+ {
+ //! move options dialog to UI lib?
+ m_xOptDlg = std::make_shared<ScSolverOptionsDialog>(m_xDialog.get(), maImplNames, maDescriptions, maEngine, maProperties);
+ weld::DialogController::runAsync(m_xOptDlg, [this](sal_Int32 nResult){
+ if (nResult == RET_OK)
+ {
+ maEngine = m_xOptDlg->GetEngine();
+ maProperties = m_xOptDlg->GetProperties();
+ }
+ m_xOptDlg.reset();
+ });
+ }
+ else if (&rBtn == m_xBtnResetAll.get())
+ {
+ OUString sEmpty;
+ m_xEdObjectiveCell->SetText(sEmpty);
+ m_xEdTargetValue->SetText(sEmpty);
+ m_xEdVariableCells->SetText(sEmpty);
+
+ // Get default property values of solver implementations
+ maEngine = maImplNames[0];
+ maProperties = ScSolverUtil::GetDefaults( maEngine );
+
+ // Clear all conditions (Constraints)
+ maConditions.clear();
+ std::unique_ptr<ScOptSolverSave> pEmpty( new ScOptSolverSave(
+ sEmpty, true, false, false,
+ sEmpty, sEmpty, std::vector(maConditions), maEngine, maProperties ) );
+ mpDocShell->SetSolverSaveData( std::move(pEmpty) );
+ ShowConditions();
+
+ m_xRbMax->set_active(true);
+ m_xEdObjectiveCell->GrabFocus();
+ mpEdActive = m_xEdObjectiveCell.get();
+ }
+}
+
+IMPL_LINK( ScOptSolverDlg, GetEditFocusHdl, formula::RefEdit&, rCtrl, void )
+{
+ formula::RefEdit* pEdit = nullptr;
+ mpEdActive = nullptr;
+
+ if( &rCtrl == m_xEdObjectiveCell.get() )
+ pEdit = mpEdActive = m_xEdObjectiveCell.get();
+ else if( &rCtrl == m_xEdTargetValue.get() )
+ pEdit = mpEdActive = m_xEdTargetValue.get();
+ else if( &rCtrl == m_xEdVariableCells.get() )
+ pEdit = mpEdActive = m_xEdVariableCells.get();
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ if( &rCtrl == mpLeftEdit[nRow] )
+ pEdit = mpEdActive = mpLeftEdit[nRow];
+ else if( &rCtrl == mpRightEdit[nRow] )
+ pEdit = mpEdActive = mpRightEdit[nRow];
+ }
+
+ if( pEdit )
+ pEdit->SelectAll();
+}
+
+IMPL_LINK( ScOptSolverDlg, GetButtonFocusHdl, formula::RefButton&, rCtrl, void )
+{
+ formula::RefEdit* pEdit = nullptr;
+ mpEdActive = nullptr;
+
+ if( &rCtrl == m_xRBObjectiveCell.get() )
+ pEdit = mpEdActive = m_xEdObjectiveCell.get();
+ else if( &rCtrl == m_xRBTargetValue.get() )
+ pEdit = mpEdActive = m_xEdTargetValue.get();
+ else if( &rCtrl == m_xRBVariableCells.get() )
+ pEdit = mpEdActive = m_xEdVariableCells.get();
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ if( &rCtrl == mpLeftButton[nRow] )
+ pEdit = mpEdActive = mpLeftEdit[nRow];
+ else if( &rCtrl == mpRightButton[nRow] )
+ pEdit = mpEdActive = mpRightEdit[nRow];
+ }
+
+ if( pEdit )
+ pEdit->SelectAll();
+}
+
+
+IMPL_LINK(ScOptSolverDlg, GetFocusHdl, weld::Widget&, rCtrl, void)
+{
+ if( &rCtrl == m_xRbValue.get() ) // focus on "Value of" radio button
+ mpEdActive = m_xEdTargetValue.get(); // use value edit for ref input, but don't change selection
+ else
+ {
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ {
+ if( &rCtrl == mpOperator[nRow] ) // focus on "operator" list box
+ mpEdActive = mpRightEdit[nRow]; // use right edit for ref input, but don't change selection
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ScOptSolverDlg, LoseEditFocusHdl, formula::RefEdit&, void)
+{
+ mbDlgLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScOptSolverDlg, LoseButtonFocusHdl, formula::RefButton&, void)
+{
+ mbDlgLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK(ScOptSolverDlg, DelBtnHdl, weld::Button&, rBtn, void)
+{
+ for ( sal_uInt16 nRow = 0; nRow < EDIT_ROW_COUNT; ++nRow )
+ if (&rBtn == mpDelButton[nRow])
+ {
+ bool bHadFocus = rBtn.has_focus();
+
+ ReadConditions();
+ tools::Long nVecPos = nScrollPos + nRow;
+ if ( nVecPos < static_cast<tools::Long>(maConditions.size()) )
+ {
+ maConditions.erase( maConditions.begin() + nVecPos );
+ ShowConditions();
+
+ if ( bHadFocus && !rBtn.get_sensitive() )
+ {
+ // If the button is disabled, focus would normally move to the next control,
+ // (left edit of the next row). Move it to left edit of this row instead.
+
+ mpEdActive = mpLeftEdit[nRow];
+ mpEdActive->GrabFocus();
+ }
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ScOptSolverDlg, TargetModifyHdl, formula::RefEdit&, void)
+{
+ // modify handler for the target edit:
+ // select "Value of" if something is input into the edit
+ if ( !m_xEdTargetValue->GetText().isEmpty() )
+ m_xRbValue->set_active(true);
+}
+
+IMPL_LINK_NOARG(ScOptSolverDlg, CondModifyHdl, formula::RefEdit&, void)
+{
+ // modify handler for the condition edits, just to enable/disable "delete" buttons
+ ReadConditions();
+ EnableButtons();
+}
+
+IMPL_LINK_NOARG(ScOptSolverDlg, SelectHdl, weld::ComboBox&, void)
+{
+ // select handler for operator list boxes, just to enable/disable "delete" buttons
+ ReadConditions();
+ EnableButtons();
+}
+
+IMPL_LINK_NOARG(ScOptSolverDlg, ScrollHdl, weld::ScrolledWindow&, void)
+{
+ ReadConditions();
+ nScrollPos = m_xScrollBar->vadjustment_get_value();
+ ShowConditions();
+ if( mpEdActive )
+ mpEdActive->SelectAll();
+}
+
+IMPL_LINK( ScOptSolverDlg, CursorUpHdl, ScCursorRefEdit&, rEdit, void )
+{
+ if ( &rEdit == mpLeftEdit[0] || &rEdit == mpRightEdit[0] )
+ {
+ if ( nScrollPos > 0 )
+ {
+ ReadConditions();
+ --nScrollPos;
+ ShowConditions();
+ if( mpEdActive )
+ mpEdActive->SelectAll();
+ }
+ }
+ else
+ {
+ formula::RefEdit* pFocus = nullptr;
+ for ( sal_uInt16 nRow = 1; nRow < EDIT_ROW_COUNT; ++nRow ) // second row or below: move focus
+ {
+ if ( &rEdit == mpLeftEdit[nRow] )
+ pFocus = mpLeftEdit[nRow-1];
+ else if ( &rEdit == mpRightEdit[nRow] )
+ pFocus = mpRightEdit[nRow-1];
+ }
+ if (pFocus)
+ {
+ mpEdActive = pFocus;
+ pFocus->GrabFocus();
+ }
+ }
+}
+
+IMPL_LINK( ScOptSolverDlg, CursorDownHdl, ScCursorRefEdit&, rEdit, void )
+{
+ if ( &rEdit == mpLeftEdit[EDIT_ROW_COUNT-1] || &rEdit == mpRightEdit[EDIT_ROW_COUNT-1] )
+ {
+ //! limit scroll position?
+ ReadConditions();
+ ++nScrollPos;
+ ShowConditions();
+ if( mpEdActive )
+ mpEdActive->SelectAll();
+ }
+ else
+ {
+ formula::RefEdit* pFocus = nullptr;
+ for ( sal_uInt16 nRow = 0; nRow+1 < EDIT_ROW_COUNT; ++nRow ) // before last row: move focus
+ {
+ if ( &rEdit == mpLeftEdit[nRow] )
+ pFocus = mpLeftEdit[nRow+1];
+ else if ( &rEdit == mpRightEdit[nRow] )
+ pFocus = mpRightEdit[nRow+1];
+ }
+ if (pFocus)
+ {
+ mpEdActive = pFocus;
+ pFocus->GrabFocus();
+ }
+ }
+}
+
+void ScOptSolverDlg::ShowError( bool bCondition, formula::RefEdit* pFocus )
+{
+ OUString aMessage = bCondition ? maConditionError : maInputError;
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ aMessage));
+ xBox->run();
+ if (pFocus)
+ {
+ mpEdActive = pFocus;
+ pFocus->GrabFocus();
+ }
+}
+
+bool ScOptSolverDlg::ParseRef( ScRange& rRange, const OUString& rInput, bool bAllowRange )
+{
+ ScAddress::Details aDetails(mrDoc.GetAddressConvention(), 0, 0);
+ ScRefFlags nFlags = rRange.ParseAny( rInput, mrDoc, aDetails );
+ if ( nFlags & ScRefFlags::VALID )
+ {
+ if ( (nFlags & ScRefFlags::TAB_3D) == ScRefFlags::ZERO)
+ rRange.aStart.SetTab( mnCurTab );
+ if ( (nFlags & ScRefFlags::TAB2_3D) == ScRefFlags::ZERO)
+ rRange.aEnd.SetTab( rRange.aStart.Tab() );
+ return ( bAllowRange || rRange.aStart == rRange.aEnd );
+ }
+ else if ( ScRangeUtil::MakeRangeFromName( rInput, mrDoc, mnCurTab, rRange, RUTL_NAMES, aDetails ) )
+ return ( bAllowRange || rRange.aStart == rRange.aEnd );
+
+ return false; // not recognized
+}
+
+bool ScOptSolverDlg::FindTimeout( sal_Int32& rTimeout )
+{
+ bool bFound = false;
+
+ if ( !maProperties.hasElements() )
+ maProperties = ScSolverUtil::GetDefaults( maEngine ); // get property defaults from component
+
+ sal_Int32 nPropCount = maProperties.getLength();
+ for (sal_Int32 nProp=0; nProp<nPropCount && !bFound; ++nProp)
+ {
+ const beans::PropertyValue& rValue = maProperties[nProp];
+ if ( rValue.Name == SC_UNONAME_TIMEOUT )
+ bFound = ( rValue.Value >>= rTimeout );
+ }
+ return bFound;
+}
+
+bool ScOptSolverDlg::CallSolver() // return true -> close dialog after calling
+{
+ // show progress dialog
+
+ auto xProgress = std::make_shared<ScSolverProgressDialog>(m_xDialog.get());
+ sal_Int32 nTimeout = 0;
+ if ( FindTimeout( nTimeout ) )
+ xProgress->SetTimeLimit( nTimeout );
+ else
+ xProgress->HideTimeLimit();
+
+ weld::DialogController::runAsync(xProgress, [](sal_Int32 /*nResult*/){});
+
+ // try to make sure the progress dialog is painted before continuing
+ Application::Reschedule(true);
+
+ // collect solver parameters
+
+ ReadConditions();
+
+ uno::Reference<sheet::XSpreadsheetDocument> xDocument( mpDocShell->GetModel(), uno::UNO_QUERY );
+
+ ScRange aObjRange;
+ if ( !ParseRef( aObjRange, m_xEdObjectiveCell->GetText(), false ) )
+ {
+ ShowError( false, m_xEdObjectiveCell.get() );
+ return false;
+ }
+ table::CellAddress aObjective( aObjRange.aStart.Tab(), aObjRange.aStart.Col(), aObjRange.aStart.Row() );
+
+ // "changing cells" can be several ranges
+ ScRangeList aVarRanges;
+ if ( !ParseWithNames( aVarRanges, m_xEdVariableCells->GetText(), mrDoc ) )
+ {
+ ShowError( false, m_xEdVariableCells.get() );
+ return false;
+ }
+ uno::Sequence<table::CellAddress> aVariables;
+ sal_Int32 nVarPos = 0;
+
+ for ( size_t nRangePos=0, nRange = aVarRanges.size(); nRangePos < nRange; ++nRangePos )
+ {
+ ScRange aRange( aVarRanges[ nRangePos ] );
+ aRange.PutInOrder();
+ SCTAB nTab = aRange.aStart.Tab();
+
+ // resolve into single cells
+
+ sal_Int32 nAdd = ( aRange.aEnd.Col() - aRange.aStart.Col() + 1 ) *
+ ( aRange.aEnd.Row() - aRange.aStart.Row() + 1 );
+ aVariables.realloc( nVarPos + nAdd );
+ auto pVariables = aVariables.getArray();
+
+ for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
+ for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
+ pVariables[nVarPos++] = table::CellAddress( nTab, nCol, nRow );
+ }
+
+ uno::Sequence<sheet::SolverConstraint> aConstraints;
+ sal_Int32 nConstrPos = 0;
+ for ( const auto& rConstr : maConditions )
+ {
+ if ( !rConstr.aLeftStr.isEmpty() )
+ {
+ sheet::SolverConstraint aConstraint;
+ // order of list box entries must match enum values
+ aConstraint.Operator = static_cast<sheet::SolverConstraintOperator>(rConstr.nOperator);
+
+ ScRange aLeftRange;
+ if ( !ParseRef( aLeftRange, rConstr.aLeftStr, true ) )
+ {
+ ShowError( true, nullptr );
+ return false;
+ }
+
+ bool bIsRange = false;
+ ScRange aRightRange;
+ if ( ParseRef( aRightRange, rConstr.aRightStr, true ) )
+ {
+ if ( aRightRange.aStart == aRightRange.aEnd )
+ aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(),
+ aRightRange.aStart.Col(), aRightRange.aStart.Row() );
+ else if ( aRightRange.aEnd.Col()-aRightRange.aStart.Col() == aLeftRange.aEnd.Col()-aLeftRange.aStart.Col() &&
+ aRightRange.aEnd.Row()-aRightRange.aStart.Row() == aLeftRange.aEnd.Row()-aLeftRange.aStart.Row() )
+ bIsRange = true; // same size as "left" range, resolve into single cells
+ else
+ {
+ ShowError( true, nullptr );
+ return false;
+ }
+ }
+ else
+ {
+ sal_uInt32 nFormat = 0; //! explicit language?
+ double fValue = 0.0;
+ if ( mrDoc.GetFormatTable()->IsNumberFormat( rConstr.aRightStr, nFormat, fValue ) )
+ aConstraint.Right <<= fValue;
+ else if ( aConstraint.Operator != sheet::SolverConstraintOperator_INTEGER &&
+ aConstraint.Operator != sheet::SolverConstraintOperator_BINARY )
+ {
+ ShowError( true, nullptr );
+ return false;
+ }
+ }
+
+ // resolve into single cells
+
+ sal_Int32 nAdd = ( aLeftRange.aEnd.Col() - aLeftRange.aStart.Col() + 1 ) *
+ ( aLeftRange.aEnd.Row() - aLeftRange.aStart.Row() + 1 );
+ aConstraints.realloc( nConstrPos + nAdd );
+ auto pConstraints = aConstraints.getArray();
+
+ for (SCROW nRow = aLeftRange.aStart.Row(); nRow <= aLeftRange.aEnd.Row(); ++nRow)
+ for (SCCOL nCol = aLeftRange.aStart.Col(); nCol <= aLeftRange.aEnd.Col(); ++nCol)
+ {
+ aConstraint.Left = table::CellAddress( aLeftRange.aStart.Tab(), nCol, nRow );
+ if ( bIsRange )
+ aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(),
+ aRightRange.aStart.Col() + ( nCol - aLeftRange.aStart.Col() ),
+ aRightRange.aStart.Row() + ( nRow - aLeftRange.aStart.Row() ) );
+
+ pConstraints[nConstrPos++] = aConstraint;
+ }
+ }
+ }
+
+ bool bMaximize = m_xRbMax->get_active();
+ if ( m_xRbValue->get_active() )
+ {
+ // handle "value of" with an additional constraint (and then minimize)
+
+ sheet::SolverConstraint aConstraint;
+ aConstraint.Left = aObjective;
+ aConstraint.Operator = sheet::SolverConstraintOperator_EQUAL;
+
+ OUString aValStr = m_xEdTargetValue->GetText();
+ ScRange aRightRange;
+ if ( ParseRef( aRightRange, aValStr, false ) )
+ aConstraint.Right <<= table::CellAddress( aRightRange.aStart.Tab(),
+ aRightRange.aStart.Col(), aRightRange.aStart.Row() );
+ else
+ {
+ sal_uInt32 nFormat = 0; //! explicit language?
+ double fValue = 0.0;
+ if ( mrDoc.GetFormatTable()->IsNumberFormat( aValStr, nFormat, fValue ) )
+ aConstraint.Right <<= fValue;
+ else
+ {
+ ShowError( false, m_xEdTargetValue.get() );
+ return false;
+ }
+ }
+
+ aConstraints.realloc( nConstrPos + 1 );
+ aConstraints.getArray()[nConstrPos++] = aConstraint;
+ }
+
+ // copy old document values
+
+ sal_Int32 nVarCount = aVariables.getLength();
+ uno::Sequence<double> aOldValues( nVarCount );
+ std::transform(std::cbegin(aVariables), std::cend(aVariables), aOldValues.getArray(),
+ [this](const table::CellAddress& rVariable) -> double {
+ ScAddress aCellPos;
+ ScUnoConversion::FillScAddress( aCellPos, rVariable );
+ return mrDoc.GetValue( aCellPos );
+ });
+
+ // create and initialize solver
+
+ uno::Reference<sheet::XSolver> xSolver = ScSolverUtil::GetSolver( maEngine );
+ OSL_ENSURE( xSolver.is(), "can't get solver component" );
+ if ( !xSolver.is() )
+ return false;
+
+ xSolver->setDocument( xDocument );
+ xSolver->setObjective( aObjective );
+ xSolver->setVariables( aVariables );
+ xSolver->setConstraints( aConstraints );
+ xSolver->setMaximize( bMaximize );
+
+ // set options
+ uno::Reference<beans::XPropertySet> xOptProp(xSolver, uno::UNO_QUERY);
+ if ( xOptProp.is() )
+ {
+ for (const beans::PropertyValue& rValue : std::as_const(maProperties))
+ {
+ try
+ {
+ xOptProp->setPropertyValue( rValue.Name, rValue.Value );
+ }
+ catch ( uno::Exception & )
+ {
+ OSL_FAIL("Exception in solver option property");
+ }
+ }
+ }
+
+ xSolver->solve();
+ bool bSuccess = xSolver->getSuccess();
+
+ xProgress->response(RET_CLOSE);
+
+ bool bClose = false;
+ bool bRestore = true; // restore old values unless a solution is accepted
+ if ( bSuccess )
+ {
+ // put solution into document so it is visible when asking
+ uno::Sequence<double> aSolution = xSolver->getSolution();
+ if ( aSolution.getLength() == nVarCount )
+ {
+ mpDocShell->LockPaint();
+ ScDocFunc &rFunc = mpDocShell->GetDocFunc();
+ for (nVarPos=0; nVarPos<nVarCount; ++nVarPos)
+ {
+ ScAddress aCellPos;
+ ScUnoConversion::FillScAddress( aCellPos, std::as_const(aVariables)[nVarPos] );
+ rFunc.SetValueCell(aCellPos, aSolution[nVarPos], false);
+ }
+ mpDocShell->UnlockPaint();
+ }
+ //! else error?
+
+ // take formatted result from document (result value from component is ignored)
+ OUString aResultStr = mrDoc.GetString(
+ static_cast<SCCOL>(aObjective.Column), static_cast<SCROW>(aObjective.Row),
+ static_cast<SCTAB>(aObjective.Sheet));
+
+ ScSolverSuccessDialog aDialog(m_xDialog.get(), aResultStr);
+ if (aDialog.run() == RET_OK)
+ {
+ // keep results and close dialog
+ bRestore = false;
+ bClose = true;
+ }
+ }
+ else
+ {
+ OUString aError;
+ uno::Reference<sheet::XSolverDescription> xDesc( xSolver, uno::UNO_QUERY );
+ if ( xDesc.is() )
+ aError = xDesc->getStatusDescription(); // error description from component
+ ScSolverNoSolutionDialog aDialog(m_xDialog.get(), aError);
+ aDialog.run();
+ }
+
+ if ( bRestore ) // restore old values
+ {
+ mpDocShell->LockPaint();
+ ScDocFunc &rFunc = mpDocShell->GetDocFunc();
+ for (nVarPos=0; nVarPos<nVarCount; ++nVarPos)
+ {
+ ScAddress aCellPos;
+ ScUnoConversion::FillScAddress( aCellPos, aVariables[nVarPos] );
+ rFunc.SetValueCell(aCellPos, std::as_const(aOldValues)[nVarPos], false);
+ }
+ mpDocShell->UnlockPaint();
+ }
+
+ return bClose;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/protectiondlg.cxx b/sc/source/ui/miscdlgs/protectiondlg.cxx
new file mode 100644
index 000000000..920e7bfc4
--- /dev/null
+++ b/sc/source/ui/miscdlgs/protectiondlg.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 <protectiondlg.hxx>
+#include <tabprotection.hxx>
+
+#include <vector>
+
+namespace {
+
+// The order must match that of the list box.
+const std::vector<ScTableProtection::Option> aOptions = {
+ ScTableProtection::SELECT_LOCKED_CELLS,
+ ScTableProtection::SELECT_UNLOCKED_CELLS,
+ ScTableProtection::INSERT_COLUMNS,
+ ScTableProtection::INSERT_ROWS,
+ ScTableProtection::DELETE_COLUMNS,
+ ScTableProtection::DELETE_ROWS,
+};
+
+}
+
+ScTableProtectionDlg::ScTableProtectionDlg(weld::Window* pParent)
+ : weld::GenericDialogController(pParent, "modules/scalc/ui/protectsheetdlg.ui", "ProtectSheetDialog")
+ , m_xBtnProtect(m_xBuilder->weld_check_button("protect"))
+ , m_xPasswords(m_xBuilder->weld_container("passwords"))
+ , m_xOptions(m_xBuilder->weld_container("options"))
+ , m_xPassword1Edit(m_xBuilder->weld_entry("password1"))
+ , m_xPassword2Edit(m_xBuilder->weld_entry("password2"))
+ , m_xOptionsListBox(m_xBuilder->weld_tree_view("checklist"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xProtected(m_xBuilder->weld_label("protected"))
+ , m_xUnprotected(m_xBuilder->weld_label("unprotected"))
+ , m_xInsertColumns(m_xBuilder->weld_label("insert-columns"))
+ , m_xInsertRows(m_xBuilder->weld_label("insert-rows"))
+ , m_xDeleteColumns(m_xBuilder->weld_label("delete-columns"))
+ , m_xDeleteRows(m_xBuilder->weld_label("delete-rows"))
+{
+ m_aSelectLockedCells = m_xProtected->get_label();
+ m_aSelectUnlockedCells = m_xUnprotected->get_label();
+ m_aInsertColumns = m_xInsertColumns->get_label();
+ m_aInsertRows = m_xInsertRows->get_label();
+ m_aDeleteColumns = m_xDeleteColumns->get_label();
+ m_aDeleteRows = m_xDeleteRows->get_label();
+
+ m_xOptionsListBox->enable_toggle_buttons(weld::ColumnToggleType::Check);
+
+ Init();
+}
+
+ScTableProtectionDlg::~ScTableProtectionDlg()
+{
+}
+
+void ScTableProtectionDlg::SetDialogData(const ScTableProtection& rData)
+{
+ for (size_t i = 0; i < aOptions.size(); ++i)
+ m_xOptionsListBox->set_toggle(i, rData.isOptionEnabled(aOptions[i]) ? TRISTATE_TRUE : TRISTATE_FALSE);
+}
+
+void ScTableProtectionDlg::WriteData(ScTableProtection& rData) const
+{
+ rData.setProtected(m_xBtnProtect->get_active());
+
+ // We assume that the two password texts match.
+ rData.setPassword(m_xPassword1Edit->get_text());
+
+ for (size_t i = 0; i < aOptions.size(); ++i)
+ rData.setOption(aOptions[i], m_xOptionsListBox->get_toggle(i) == TRISTATE_TRUE);
+}
+
+void ScTableProtectionDlg::InsertEntry(const OUString& rTxt)
+{
+ m_xOptionsListBox->append();
+ const int nRow = m_xOptionsListBox->n_children() - 1;
+ m_xOptionsListBox->set_toggle(nRow, TRISTATE_FALSE);
+ m_xOptionsListBox->set_text(nRow, rTxt, 0);
+}
+
+void ScTableProtectionDlg::Init()
+{
+ m_xBtnProtect->connect_toggled(LINK(this, ScTableProtectionDlg, CheckBoxHdl));
+
+ m_xBtnOk->connect_clicked(LINK(this, ScTableProtectionDlg, OKHdl));
+
+ Link<weld::Entry&,void> aLink = LINK(this, ScTableProtectionDlg, PasswordModifyHdl);
+ m_xPassword1Edit->connect_changed(aLink);
+ m_xPassword2Edit->connect_changed(aLink);
+
+ m_xOptionsListBox->freeze();
+ m_xOptionsListBox->clear();
+
+ InsertEntry(m_aSelectLockedCells);
+ InsertEntry(m_aSelectUnlockedCells);
+ InsertEntry(m_aInsertColumns);
+ InsertEntry(m_aInsertRows);
+ InsertEntry(m_aDeleteColumns);
+ InsertEntry(m_aDeleteRows);
+
+ m_xOptionsListBox->set_toggle(0, TRISTATE_TRUE);
+ m_xOptionsListBox->set_toggle(1, TRISTATE_TRUE);
+
+ m_xOptionsListBox->thaw();
+
+ // Set the default state of the dialog.
+ m_xBtnProtect->set_active(true);
+ m_xPassword1Edit->grab_focus();
+}
+
+void ScTableProtectionDlg::EnableOptionalWidgets(bool bEnable)
+{
+ m_xPasswords->set_sensitive(bEnable);
+ m_xOptions->set_sensitive(bEnable);
+}
+
+IMPL_LINK(ScTableProtectionDlg, CheckBoxHdl, weld::Toggleable&, rBtn, void)
+{
+ if (&rBtn == m_xBtnProtect.get())
+ {
+ bool bChecked = m_xBtnProtect->get_active();
+ EnableOptionalWidgets(bChecked);
+ m_xBtnOk->set_sensitive(bChecked);
+ }
+}
+
+IMPL_LINK_NOARG(ScTableProtectionDlg, OKHdl, weld::Button&, void)
+{
+ m_xDialog->response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ScTableProtectionDlg, PasswordModifyHdl, weld::Entry&, void)
+{
+ OUString aPass1 = m_xPassword1Edit->get_text();
+ OUString aPass2 = m_xPassword2Edit->get_text();
+ m_xBtnOk->set_sensitive(aPass1 == aPass2);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/redcom.cxx b/sc/source/ui/miscdlgs/redcom.cxx
new file mode 100644
index 000000000..ef04bd57e
--- /dev/null
+++ b/sc/source/ui/miscdlgs/redcom.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 <unotools/localedatawrapper.hxx>
+
+#include <chgtrack.hxx>
+#include <redcom.hxx>
+#include <docsh.hxx>
+#include <dbfunc.hxx>
+#include <tabview.hxx>
+#include <viewutil.hxx>
+#include <svx/svxdlg.hxx>
+
+ScRedComDialog::ScRedComDialog( weld::Window* pParent, const SfxItemSet& rCoreSet,
+ ScDocShell *pShell, ScChangeAction *pAction, bool bPrevNext)
+ : pChangeAction(nullptr)
+ , pDocShell(nullptr)
+ , pDlg(nullptr)
+{
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ pDlg = pFact->CreateSvxPostItDialog( pParent, rCoreSet, bPrevNext );
+ pDocShell=pShell;
+ pDlg->DontChangeAuthor();
+ pDlg->HideAuthor();
+
+ pDlg->SetPrevHdl(LINK( this, ScRedComDialog, PrevHdl));
+ pDlg->SetNextHdl(LINK( this, ScRedComDialog, NextHdl));
+
+ ReInit(pAction);
+}
+
+ScRedComDialog::~ScRedComDialog()
+{
+ pDlg.disposeAndClear();
+}
+
+ScChangeAction *ScRedComDialog::FindPrev(ScChangeAction *pAction)
+{
+ if(pAction!=nullptr && pDocShell !=nullptr)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeViewSettings* pSettings = rDoc.GetChangeViewSettings();
+
+ pAction=pAction->GetPrev();
+
+ while(pAction!=nullptr)
+ {
+ if( pAction->GetState()==SC_CAS_VIRGIN &&
+ pAction->IsDialogRoot() &&
+ ScViewUtil::IsActionShown(*pAction,*pSettings,rDoc)) break;
+
+ pAction=pAction->GetPrev();
+ }
+ }
+ return pAction;
+}
+
+ScChangeAction *ScRedComDialog::FindNext(ScChangeAction *pAction)
+{
+ if(pAction!=nullptr && pDocShell !=nullptr)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeViewSettings* pSettings = rDoc.GetChangeViewSettings();
+
+ pAction=pAction->GetNext();
+
+ while(pAction!=nullptr)
+ {
+ if( pAction->GetState()==SC_CAS_VIRGIN &&
+ pAction->IsDialogRoot() &&
+ ScViewUtil::IsActionShown(*pAction,*pSettings,rDoc)) break;
+
+ pAction=pAction->GetNext();
+ }
+ }
+ return pAction;
+}
+
+void ScRedComDialog::ReInit(ScChangeAction *pAction)
+{
+ pChangeAction=pAction;
+ if(pChangeAction==nullptr || pDocShell ==nullptr)
+ return;
+
+ OUString aTitle = pChangeAction->GetDescription(pDocShell->GetDocument());
+ pDlg->SetText(aTitle);
+ aComment=pChangeAction->GetComment();
+
+ bool bNext=FindNext(pChangeAction)!=nullptr;
+ bool bPrev=FindPrev(pChangeAction)!=nullptr;
+ pDlg->EnableTravel(bNext,bPrev);
+
+ OUString aAuthor = pChangeAction->GetUser();
+
+ DateTime aDT = pChangeAction->GetDateTime();
+ OUString aDate = ScGlobal::getLocaleData().getDate( aDT ) + " " +
+ ScGlobal::getLocaleData().getTime( aDT, false );
+
+ pDlg->ShowLastAuthor(aAuthor, aDate);
+ pDlg->SetNote(aComment);
+}
+
+void ScRedComDialog::Execute()
+{
+ short nRet=pDlg->Execute();
+
+ if(nRet== RET_OK )
+ {
+ if ( pDocShell!=nullptr && pDlg->GetNote() != aComment )
+ pDocShell->SetChangeComment( pChangeAction, pDlg->GetNote());
+ }
+}
+
+void ScRedComDialog::SelectCell()
+{
+ if (!pChangeAction || !pDocShell)
+ return;
+
+ const ScChangeAction* pAction=pChangeAction;
+ const ScBigRange& rRange = pAction->GetBigRange();
+
+ if(rRange.IsValid(pDocShell->GetDocument()))
+ {
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ {
+ ScRange aRef = rRange.MakeRange(pDocShell->GetDocument());
+ ScTabView* pTabView = pViewData->GetView();
+ pTabView->MarkRange(aRef);
+ }
+ }
+}
+
+IMPL_LINK(ScRedComDialog, PrevHdl, AbstractSvxPostItDialog&, rDlgP, void )
+{
+ if (pDocShell!=nullptr && rDlgP.GetNote() != aComment )
+ pDocShell->SetChangeComment( pChangeAction, rDlgP.GetNote());
+
+ ReInit(FindPrev(pChangeAction));
+ SelectCell();
+}
+
+IMPL_LINK(ScRedComDialog, NextHdl, AbstractSvxPostItDialog&, rDlgP, void )
+{
+ if ( pDocShell!=nullptr && rDlgP.GetNote() != aComment )
+ pDocShell->SetChangeComment( pChangeAction, rDlgP.GetNote());
+
+ ReInit(FindNext(pChangeAction));
+ SelectCell();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/retypepassdlg.cxx b/sc/source/ui/miscdlgs/retypepassdlg.cxx
new file mode 100644
index 000000000..c7b9084a8
--- /dev/null
+++ b/sc/source/ui/miscdlgs/retypepassdlg.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 <vcl/svapp.hxx>
+#include <strings.hrc>
+#include <retypepassdlg.hxx>
+#include <scresid.hxx>
+#include <document.hxx>
+#include <tabprotection.hxx>
+
+ScRetypePassDlg::ScRetypePassDlg(weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/retypepassdialog.ui", "RetypePass")
+ , maTextNotProtected(ScResId(STR_NOT_PROTECTED))
+ , maTextNotPassProtected(ScResId(STR_NOT_PASS_PROTECTED))
+ , maTextHashBad(ScResId(STR_HASH_BAD))
+ , maTextHashGood(ScResId(STR_HASH_GOOD))
+ , meDesiredHash(PASSHASH_SHA1)
+ , mxBtnOk(m_xBuilder->weld_button("ok"))
+ , mxTextDocStatus(m_xBuilder->weld_label("docStatusLabel"))
+ , mxBtnRetypeDoc(m_xBuilder->weld_button("retypeDocButton"))
+ , mxScrolledWindow(m_xBuilder->weld_scrolled_window("scrolledwindow"))
+ , mxSheetsBox(m_xBuilder->weld_container("sheetsBox"))
+{
+ mxScrolledWindow->set_size_request(mxScrolledWindow->get_approximate_digit_width() * 46,
+ mxScrolledWindow->get_text_height() * 10);
+ Init();
+}
+
+ScRetypePassDlg::~ScRetypePassDlg() {}
+
+void ScRetypePassDlg::DeleteSheets() { maSheets.clear(); }
+
+short ScRetypePassDlg::run()
+{
+ PopulateDialog();
+ CheckHashStatus();
+ return GenericDialogController::run();
+}
+
+PassFragment::PassFragment(weld::Widget* pParent)
+ : m_xBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/passfragment.ui"))
+ , m_xSheetsBox(m_xBuilder->weld_container("PassEntry"))
+ , m_xName(m_xBuilder->weld_label("name"))
+ , m_xStatus(m_xBuilder->weld_label("status"))
+ , m_xButton(m_xBuilder->weld_button("button"))
+{
+ m_xButton->set_label(ScResId(STR_RETYPE));
+}
+
+void ScRetypePassDlg::SetDataFromDocument(const ScDocument& rDoc)
+{
+ DeleteSheets();
+ const ScDocProtection* pDocProtect = rDoc.GetDocProtection();
+ if (pDocProtect && pDocProtect->isProtected())
+ mpDocItem = std::make_shared<ScDocProtection>(*pDocProtect);
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ maTableItems.reserve(nTabCount);
+ maSheets.reserve(nTabCount);
+ for (SCTAB i = 0; i < nTabCount; ++i)
+ {
+ TableItem aTabItem;
+ rDoc.GetName(i, aTabItem.maName);
+
+ const ScTableProtection* pTabProtect = rDoc.GetTabProtection(i);
+ if (pTabProtect && pTabProtect->isProtected())
+ aTabItem.mpProtect = std::make_shared<ScTableProtection>(*pTabProtect);
+
+ maTableItems.push_back(aTabItem);
+ maSheets.emplace_back(new PassFragment(mxSheetsBox.get()));
+ maSheets.back()->m_xButton->connect_clicked(LINK(this, ScRetypePassDlg, RetypeBtnHdl));
+ }
+}
+
+void ScRetypePassDlg::SetDesiredHash(ScPasswordHash eHash) { meDesiredHash = eHash; }
+
+void ScRetypePassDlg::WriteNewDataToDocument(ScDocument& rDoc) const
+{
+ if (mpDocItem)
+ rDoc.SetDocProtection(mpDocItem.get());
+
+ size_t nTabCount = static_cast<size_t>(rDoc.GetTableCount());
+ size_t n = maTableItems.size();
+ for (size_t i = 0; i < n; ++i)
+ {
+ if (i >= nTabCount)
+ break;
+
+ ScTableProtection* pTabProtect = maTableItems[i].mpProtect.get();
+ if (pTabProtect)
+ rDoc.SetTabProtection(static_cast<SCTAB>(i), pTabProtect);
+ }
+}
+
+void ScRetypePassDlg::Init()
+{
+ Link<weld::Button&, void> aLink = LINK(this, ScRetypePassDlg, OKHdl);
+ mxBtnOk->connect_clicked(aLink);
+
+ aLink = LINK(this, ScRetypePassDlg, RetypeBtnHdl);
+ mxBtnRetypeDoc->connect_clicked(aLink);
+
+ mxTextDocStatus->set_label(maTextNotProtected);
+ mxBtnRetypeDoc->set_sensitive(false);
+}
+
+void ScRetypePassDlg::PopulateDialog()
+{
+ // Document protection first.
+ SetDocData();
+
+ // Sheet protection next.
+ for (size_t i = 0; i < maTableItems.size(); ++i)
+ SetTableData(i, static_cast<SCTAB>(i));
+}
+
+void ScRetypePassDlg::SetDocData()
+{
+ bool bBtnEnabled = false;
+ if (mpDocItem && mpDocItem->isProtected())
+ {
+ if (mpDocItem->isPasswordEmpty())
+ mxTextDocStatus->set_label(maTextNotPassProtected);
+ else if (mpDocItem->hasPasswordHash(meDesiredHash))
+ mxTextDocStatus->set_label(maTextHashGood);
+ else
+ {
+ // incompatible hash
+ mxTextDocStatus->set_label(maTextHashBad);
+ bBtnEnabled = true;
+ }
+ }
+ mxBtnRetypeDoc->set_sensitive(bBtnEnabled);
+}
+
+void ScRetypePassDlg::SetTableData(size_t nRowPos, SCTAB nTab)
+{
+ if (nRowPos >= maSheets.size())
+ return;
+
+ weld::Label& rName = *maSheets[nRowPos]->m_xName;
+ weld::Label& rStatus = *maSheets[nRowPos]->m_xStatus;
+ weld::Button& rBtn = *maSheets[nRowPos]->m_xButton;
+
+ bool bBtnEnabled = false;
+ rName.set_label(maTableItems[nTab].maName);
+ const ScTableProtection* pTabProtect = maTableItems[nTab].mpProtect.get();
+ if (pTabProtect && pTabProtect->isProtected())
+ {
+ if (pTabProtect->isPasswordEmpty())
+ rStatus.set_label(maTextNotPassProtected);
+ else if (pTabProtect->hasPasswordHash(meDesiredHash))
+ rStatus.set_label(maTextHashGood);
+ else
+ {
+ // incompatible hash
+ rStatus.set_label(maTextHashBad);
+ bBtnEnabled = true;
+ }
+ }
+ else
+ rStatus.set_label(maTextNotProtected);
+
+ rBtn.set_sensitive(bBtnEnabled);
+}
+
+static bool lcl_IsInGoodStatus(const ScPassHashProtectable* pProtected, ScPasswordHash eDesiredHash)
+{
+ if (!pProtected || !pProtected->isProtected())
+ // Not protected.
+ return true;
+
+ if (pProtected->isPasswordEmpty())
+ return true;
+
+ if (pProtected->hasPasswordHash(eDesiredHash))
+ return true;
+
+ return false;
+}
+
+void ScRetypePassDlg::CheckHashStatus()
+{
+ do
+ {
+ if (!lcl_IsInGoodStatus(mpDocItem.get(), meDesiredHash))
+ break;
+
+ bool bStatusGood = true;
+ size_t nTabCount = maTableItems.size();
+ for (size_t i = 0; i < nTabCount && bStatusGood; ++i)
+ {
+ if (!lcl_IsInGoodStatus(maTableItems[i].mpProtect.get(), meDesiredHash))
+ bStatusGood = false;
+ }
+ if (!bStatusGood)
+ break;
+
+ mxBtnOk->set_sensitive(true);
+ return;
+ } while (false);
+
+ mxBtnOk->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(ScRetypePassDlg, OKHdl, weld::Button&, void) { m_xDialog->response(RET_OK); }
+
+IMPL_LINK(ScRetypePassDlg, RetypeBtnHdl, weld::Button&, rBtn, void)
+{
+ ScPassHashProtectable* pProtected = nullptr;
+ if (&rBtn == mxBtnRetypeDoc.get())
+ {
+ // document protection.
+ pProtected = mpDocItem.get();
+ }
+ else
+ {
+ // sheet protection.
+ size_t aPos = 0;
+ while (aPos < maSheets.size() && &rBtn != maSheets[aPos]->m_xButton.get())
+ ++aPos;
+
+ pProtected = aPos < maSheets.size() ? maTableItems[aPos].mpProtect.get() : nullptr;
+ }
+
+ if (!pProtected)
+ // What the ... !?
+ return;
+
+ ScRetypePassInputDlg aDlg(m_xDialog.get(), pProtected);
+ if (aDlg.run() != RET_OK)
+ return;
+
+ // OK is pressed. Update the protected item.
+ if (aDlg.IsRemovePassword())
+ {
+ // Remove password from this item.
+ pProtected->setPassword(OUString());
+ }
+ else
+ {
+ // Set a new password.
+ OUString aNewPass = aDlg.GetNewPassword();
+ pProtected->setPassword(aNewPass);
+ }
+
+ SetDocData();
+ CheckHashStatus();
+}
+
+ScRetypePassInputDlg::ScRetypePassInputDlg(weld::Window* pParent, ScPassHashProtectable* pProtected)
+ : GenericDialogController(pParent, "modules/scalc/ui/retypepassworddialog.ui",
+ "RetypePasswordDialog")
+ , m_pProtected(pProtected)
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnRetypePassword(m_xBuilder->weld_radio_button("retypepassword"))
+ , m_xPasswordGrid(m_xBuilder->weld_widget("passwordgrid"))
+ , m_xPassword1Edit(m_xBuilder->weld_entry("newpassEntry"))
+ , m_xPassword2Edit(m_xBuilder->weld_entry("confirmpassEntry"))
+ , m_xBtnMatchOldPass(m_xBuilder->weld_check_button("mustmatch"))
+ , m_xBtnRemovePassword(m_xBuilder->weld_radio_button("removepassword"))
+{
+ Init();
+}
+
+ScRetypePassInputDlg::~ScRetypePassInputDlg() {}
+
+bool ScRetypePassInputDlg::IsRemovePassword() const { return m_xBtnRemovePassword->get_active(); }
+
+OUString ScRetypePassInputDlg::GetNewPassword() const { return m_xPassword1Edit->get_text(); }
+
+void ScRetypePassInputDlg::Init()
+{
+ m_xBtnOk->connect_clicked(LINK(this, ScRetypePassInputDlg, OKHdl));
+ m_xBtnRetypePassword->connect_toggled(LINK(this, ScRetypePassInputDlg, RadioBtnHdl));
+ m_xBtnRemovePassword->connect_toggled(LINK(this, ScRetypePassInputDlg, RadioBtnHdl));
+ m_xBtnMatchOldPass->connect_toggled(LINK(this, ScRetypePassInputDlg, CheckBoxHdl));
+ Link<weld::Entry&, void> aLink2 = LINK(this, ScRetypePassInputDlg, PasswordModifyHdl);
+ m_xPassword1Edit->connect_changed(aLink2);
+ m_xPassword2Edit->connect_changed(aLink2);
+
+ m_xBtnOk->set_sensitive(false);
+ m_xBtnRetypePassword->set_active(true);
+ m_xBtnMatchOldPass->set_active(true);
+ m_xPassword1Edit->grab_focus();
+}
+
+void ScRetypePassInputDlg::CheckPasswordInput()
+{
+ OUString aPass1 = m_xPassword1Edit->get_text();
+ OUString aPass2 = m_xPassword2Edit->get_text();
+
+ if (aPass1.isEmpty() || aPass2.isEmpty())
+ {
+ // Empty password is not allowed.
+ m_xBtnOk->set_sensitive(false);
+ return;
+ }
+
+ if (aPass1 != aPass2)
+ {
+ // The two passwords differ.
+ m_xBtnOk->set_sensitive(false);
+ return;
+ }
+
+ if (!m_xBtnMatchOldPass->get_active())
+ {
+ m_xBtnOk->set_sensitive(true);
+ return;
+ }
+
+ if (!m_pProtected)
+ {
+ // This should never happen!
+ m_xBtnOk->set_sensitive(false);
+ return;
+ }
+
+ bool bPassGood = m_pProtected->verifyPassword(aPass1);
+ m_xBtnOk->set_sensitive(bPassGood);
+}
+
+IMPL_LINK_NOARG(ScRetypePassInputDlg, OKHdl, weld::Button&, void) { m_xDialog->response(RET_OK); }
+
+IMPL_LINK_NOARG(ScRetypePassInputDlg, RadioBtnHdl, weld::Toggleable&, void)
+{
+ if (m_xBtnRetypePassword->get_active())
+ {
+ m_xPasswordGrid->set_sensitive(true);
+ CheckPasswordInput();
+ }
+ else
+ {
+ m_xPasswordGrid->set_sensitive(false);
+ m_xBtnOk->set_sensitive(true);
+ }
+}
+
+IMPL_LINK_NOARG(ScRetypePassInputDlg, CheckBoxHdl, weld::Toggleable&, void)
+{
+ CheckPasswordInput();
+}
+
+IMPL_LINK_NOARG(ScRetypePassInputDlg, PasswordModifyHdl, weld::Entry&, void)
+{
+ CheckPasswordInput();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/scuiautofmt.cxx b/sc/source/ui/miscdlgs/scuiautofmt.cxx
new file mode 100644
index 000000000..ecf446081
--- /dev/null
+++ b/sc/source/ui/miscdlgs/scuiautofmt.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/strings.hrc>
+#include <sfx2/sfxresid.hxx>
+#include <o3tl/string_view.hxx>
+#include <strings.hrc>
+#include <global.hxx>
+#include <globstr.hrc>
+#include <autoform.hxx>
+#include <strindlg.hxx>
+#include <scuiautofmt.hxx>
+#include <scresid.hxx>
+#include <helpids.h>
+
+// AutoFormat-Dialog:
+
+ScAutoFormatDlg::ScAutoFormatDlg(weld::Window* pParent,
+ ScAutoFormat* pAutoFormat,
+ const ScAutoFormatData* pSelFormatData,
+ const ScViewData& rViewData)
+ : GenericDialogController(pParent, "modules/scalc/ui/autoformattable.ui", "AutoFormatTableDialog")
+ , aStrTitle(ScResId(STR_ADD_AUTOFORMAT_TITLE))
+ , aStrLabel(ScResId(STR_ADD_AUTOFORMAT_LABEL))
+ , aStrClose(ScResId(STR_BTN_AUTOFORMAT_CLOSE))
+ , aStrDelMsg(ScResId(STR_DEL_AUTOFORMAT_MSG))
+ , aStrRename(ScResId(STR_RENAME_AUTOFORMAT_TITLE))
+ , pFormat(pAutoFormat)
+ , pSelFmtData(pSelFormatData)
+ , nIndex(0)
+ , bCoreDataChanged(false)
+ , bFmtInserted(false)
+ , m_xLbFormat(m_xBuilder->weld_tree_view("formatlb"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_xBtnAdd(m_xBuilder->weld_button("add"))
+ , m_xBtnRemove(m_xBuilder->weld_button("remove"))
+ , m_xBtnRename(m_xBuilder->weld_button("rename"))
+ , m_xBtnNumFormat(m_xBuilder->weld_check_button("numformatcb"))
+ , m_xBtnBorder(m_xBuilder->weld_check_button("bordercb"))
+ , m_xBtnFont(m_xBuilder->weld_check_button("fontcb"))
+ , m_xBtnPattern(m_xBuilder->weld_check_button("patterncb"))
+ , m_xBtnAlignment(m_xBuilder->weld_check_button("alignmentcb"))
+ , m_xBtnAdjust(m_xBuilder->weld_check_button("autofitcb"))
+ , m_xWndPreview(new weld::CustomWeld(*m_xBuilder, "preview", m_aWndPreview))
+{
+ m_aWndPreview.DetectRTL(rViewData);
+
+ const int nWidth = m_xLbFormat->get_approximate_digit_width() * 32;
+ const int nHeight = m_xLbFormat->get_height_rows(8);
+ m_xLbFormat->set_size_request(nWidth, nHeight);
+ m_xWndPreview->set_size_request(nWidth, nHeight);
+
+ Init();
+ ScAutoFormat::iterator it = pFormat->begin();
+ m_aWndPreview.NotifyChange(it->second.get());
+}
+
+ScAutoFormatDlg::~ScAutoFormatDlg()
+{
+}
+
+void ScAutoFormatDlg::Init()
+{
+ m_xLbFormat->connect_changed( LINK( this, ScAutoFormatDlg, SelFmtHdl ) );
+ m_xBtnNumFormat->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) );
+ m_xBtnBorder->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) );
+ m_xBtnFont->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) );
+ m_xBtnPattern->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) );
+ m_xBtnAlignment->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) );
+ m_xBtnAdjust->connect_toggled( LINK( this, ScAutoFormatDlg, CheckHdl ) );
+ m_xBtnAdd->connect_clicked ( LINK( this, ScAutoFormatDlg, AddHdl ) );
+ m_xBtnRemove->connect_clicked ( LINK( this, ScAutoFormatDlg, RemoveHdl ) );
+ m_xBtnOk->connect_clicked ( LINK( this, ScAutoFormatDlg, CloseHdl ) );
+ m_xBtnCancel->connect_clicked ( LINK( this, ScAutoFormatDlg, CloseHdl ) );
+ m_xBtnRename->connect_clicked ( LINK( this, ScAutoFormatDlg, RenameHdl ) );
+ m_xLbFormat->connect_row_activated( LINK( this, ScAutoFormatDlg, DblClkHdl ) );
+
+ for (const auto& rEntry : *pFormat)
+ m_xLbFormat->append_text(rEntry.second->GetName());
+
+ if (pFormat->size() == 1)
+ m_xBtnRemove->set_sensitive(false);
+
+ m_xLbFormat->select(0);
+ m_xBtnRename->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(false);
+
+ nIndex = 0;
+ UpdateChecks();
+
+ if ( !pSelFmtData )
+ {
+ m_xBtnAdd->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(false);
+ bFmtInserted = true;
+ }
+}
+
+void ScAutoFormatDlg::UpdateChecks()
+{
+ const ScAutoFormatData* pData = pFormat->findByIndex(nIndex);
+
+ m_xBtnNumFormat->set_active( pData->GetIncludeValueFormat() );
+ m_xBtnBorder->set_active( pData->GetIncludeFrame() );
+ m_xBtnFont->set_active( pData->GetIncludeFont() );
+ m_xBtnPattern->set_active( pData->GetIncludeBackground() );
+ m_xBtnAlignment->set_active( pData->GetIncludeJustify() );
+ m_xBtnAdjust->set_active( pData->GetIncludeWidthHeight() );
+}
+
+// Handler:
+
+IMPL_LINK(ScAutoFormatDlg, CloseHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == m_xBtnOk.get() || &rBtn == m_xBtnCancel.get())
+ {
+ if ( bCoreDataChanged )
+ ScGlobal::GetOrCreateAutoFormat()->Save();
+
+ m_xDialog->response( (&rBtn == m_xBtnOk.get()) ? RET_OK : RET_CANCEL );
+ }
+}
+
+IMPL_LINK_NOARG(ScAutoFormatDlg, DblClkHdl, weld::TreeView&, bool)
+{
+ if ( bCoreDataChanged )
+ ScGlobal::GetOrCreateAutoFormat()->Save();
+
+ m_xDialog->response( RET_OK );
+
+ return true;
+}
+
+IMPL_LINK(ScAutoFormatDlg, CheckHdl, weld::Toggleable&, rBtn, void)
+{
+ ScAutoFormatData* pData = pFormat->findByIndex(nIndex);
+ bool bCheck = rBtn.get_active();
+
+ if (&rBtn == m_xBtnNumFormat.get())
+ pData->SetIncludeValueFormat( bCheck );
+ else if (&rBtn == m_xBtnBorder.get())
+ pData->SetIncludeFrame( bCheck );
+ else if (&rBtn == m_xBtnFont.get())
+ pData->SetIncludeFont( bCheck );
+ else if (&rBtn == m_xBtnPattern.get())
+ pData->SetIncludeBackground( bCheck );
+ else if (&rBtn == m_xBtnAlignment.get())
+ pData->SetIncludeJustify( bCheck );
+ else if (&rBtn == m_xBtnAdjust.get())
+ pData->SetIncludeWidthHeight( bCheck );
+
+ if ( !bCoreDataChanged )
+ {
+ m_xBtnCancel->set_label(aStrClose);
+ bCoreDataChanged = true;
+ }
+
+ m_aWndPreview.NotifyChange( pData );
+}
+
+IMPL_LINK_NOARG(ScAutoFormatDlg, AddHdl, weld::Button&, void)
+{
+ if ( bFmtInserted || !pSelFmtData )
+ return;
+
+ OUString aStrStandard( SfxResId(STR_STANDARD) );
+ OUString aFormatName;
+ bool bOk = false;
+
+ while ( !bOk )
+ {
+ ScStringInputDlg aDlg(m_xDialog.get(), aStrTitle, aStrLabel, aFormatName,
+ HID_SC_ADD_AUTOFMT, HID_SC_AUTOFMT_NAME);
+
+ if (aDlg.run() == RET_OK)
+ {
+ aFormatName = aDlg.GetInputString();
+
+ if ( !aFormatName.isEmpty() && aFormatName != aStrStandard && pFormat->find(aFormatName) == pFormat->end() )
+ {
+ std::unique_ptr<ScAutoFormatData> pNewData(
+ new ScAutoFormatData( *pSelFmtData ));
+
+ pNewData->SetName( aFormatName );
+ ScAutoFormat::iterator it = pFormat->insert(std::move(pNewData));
+ bFmtInserted = it != pFormat->end();
+
+ if ( bFmtInserted )
+ {
+ size_t nPos = std::distance(pFormat->begin(), it);
+ m_xLbFormat->insert_text(nPos, aFormatName);
+ m_xLbFormat->select_text( aFormatName );
+ m_xBtnAdd->set_sensitive(false);
+
+ if ( !bCoreDataChanged )
+ {
+ m_xBtnCancel->set_label( aStrClose );
+ bCoreDataChanged = true;
+ }
+
+ SelFmtHdl( *m_xLbFormat );
+ bOk = true;
+ }
+ }
+
+ if ( !bFmtInserted )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Error, VclButtonsType::OkCancel,
+ ScResId(STR_INVALID_AFNAME)));
+
+ sal_uInt16 nRet = xBox->run();
+
+ bOk = ( nRet == RET_CANCEL );
+ }
+ }
+ else
+ bOk = true;
+ }
+}
+
+IMPL_LINK_NOARG(ScAutoFormatDlg, RemoveHdl, weld::Button&, void)
+{
+ if ( (nIndex > 0) && (m_xLbFormat->n_children() > 0) )
+ {
+ OUString aMsg = o3tl::getToken(aStrDelMsg, 0, '#' )
+ + m_xLbFormat->get_selected_text()
+ + o3tl::getToken(aStrDelMsg, 1, '#' );
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ aMsg));
+ xQueryBox->set_default_response(RET_YES);
+
+ if (RET_YES == xQueryBox->run())
+ {
+ m_xLbFormat->remove(nIndex);
+ m_xLbFormat->select(nIndex-1);
+
+ if ( nIndex-1 == 0 )
+ m_xBtnRemove->set_sensitive(false);
+
+ if ( !bCoreDataChanged )
+ {
+ m_xBtnCancel->set_label( aStrClose );
+ bCoreDataChanged = true;
+ }
+
+ ScAutoFormat::iterator it = pFormat->begin();
+ std::advance(it, nIndex);
+ pFormat->erase(it);
+ nIndex--;
+
+ SelFmtHdl( *m_xLbFormat );
+ }
+ }
+
+ SelFmtHdl( *m_xLbFormat );
+}
+
+IMPL_LINK_NOARG(ScAutoFormatDlg, RenameHdl, weld::Button&, void)
+{
+ bool bOk = false;
+ while( !bOk )
+ {
+
+ OUString aFormatName = m_xLbFormat->get_selected_text();
+ OUString aEntry;
+
+ ScStringInputDlg aDlg(m_xDialog.get(), aStrRename, aStrLabel, aFormatName,
+ HID_SC_REN_AFMT_DLG, HID_SC_REN_AFMT_NAME);
+ if (aDlg.run() == RET_OK)
+ {
+ bool bFmtRenamed = false;
+ aFormatName = aDlg.GetInputString();
+
+ if (!aFormatName.isEmpty())
+ {
+ ScAutoFormat::iterator it = pFormat->begin(), itEnd = pFormat->end();
+ for (; it != itEnd; ++it)
+ {
+ aEntry = it->second->GetName();
+ if (aFormatName == aEntry)
+ break;
+ }
+ if (it == itEnd)
+ {
+ // no format with this name yet, so we can rename
+
+ m_xLbFormat->remove(nIndex);
+ const ScAutoFormatData* p = pFormat->findByIndex(nIndex);
+ std::unique_ptr<ScAutoFormatData> pNewData(new ScAutoFormatData(*p));
+
+ it = pFormat->begin();
+ std::advance(it, nIndex);
+ pFormat->erase(it);
+
+ pNewData->SetName( aFormatName );
+
+ pFormat->insert(std::move(pNewData));
+
+ m_xLbFormat->freeze();
+ m_xLbFormat->clear();
+ for (it = pFormat->begin(); it != itEnd; ++it)
+ {
+ aEntry = it->second->GetName();
+ m_xLbFormat->append_text(aEntry);
+ }
+
+ m_xLbFormat->thaw();
+ m_xLbFormat->select_text(aFormatName);
+
+ if ( !bCoreDataChanged )
+ {
+ m_xBtnCancel->set_label( aStrClose );
+ bCoreDataChanged = true;
+ }
+
+ SelFmtHdl( *m_xLbFormat );
+ bOk = true;
+ bFmtRenamed = true;
+ }
+ }
+ if( !bFmtRenamed )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Error, VclButtonsType::OkCancel,
+ ScResId(STR_INVALID_AFNAME)));
+
+ bOk = RET_CANCEL == xBox->run();
+ }
+ }
+ else
+ bOk = true;
+ }
+}
+
+IMPL_LINK_NOARG(ScAutoFormatDlg, SelFmtHdl, weld::TreeView&, void)
+{
+ nIndex = m_xLbFormat->get_selected_index();
+ UpdateChecks();
+
+ if ( nIndex == 0 )
+ {
+ m_xBtnRename->set_sensitive(false);
+ m_xBtnRemove->set_sensitive(false);
+ }
+ else
+ {
+ m_xBtnRename->set_sensitive(true);
+ m_xBtnRemove->set_sensitive(true);
+ }
+
+ ScAutoFormatData* p = pFormat->findByIndex(nIndex);
+ m_aWndPreview.NotifyChange(p);
+}
+
+OUString ScAutoFormatDlg::GetCurrFormatName()
+{
+ const ScAutoFormatData* p = pFormat->findByIndex(nIndex);
+ return p ? p->GetName() : OUString();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/sharedocdlg.cxx b/sc/source/ui/miscdlgs/sharedocdlg.cxx
new file mode 100644
index 000000000..9abf05c6b
--- /dev/null
+++ b/sc/source/ui/miscdlgs/sharedocdlg.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 <o3tl/safeint.hxx>
+#include <osl/security.hxx>
+#include <osl/diagnose.h>
+#include <sfx2/dialoghelper.hxx>
+#include <svl/sharecontrolfile.hxx>
+#include <unotools/useroptions.hxx>
+#include <tools/diagnose_ex.h>
+#include <o3tl/string_view.hxx>
+
+#include <docsh.hxx>
+
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+
+#include <scresid.hxx>
+#include <sharedocdlg.hxx>
+#include <strings.hrc>
+#include <viewdata.hxx>
+
+using namespace ::com::sun::star;
+
+IMPL_LINK(ScShareDocumentDlg, SizeAllocated, const Size&, rSize, void)
+{
+ OUString sWidestAccessString = getWidestDateTime(ScGlobal::getLocaleData(), false);
+ const int nAccessWidth = m_xLbUsers->get_pixel_size(sWidestAccessString).Width() * 2;
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(rSize.Width() - nAccessWidth)
+ };
+ m_xLbUsers->set_column_fixed_widths(aWidths);
+}
+
+
+ScShareDocumentDlg::ScShareDocumentDlg(weld::Window* pParent, const ScViewData* pViewData)
+ : GenericDialogController(pParent, "modules/scalc/ui/sharedocumentdlg.ui",
+ "ShareDocumentDialog")
+ , m_aStrNoUserData(ScResId(STR_NO_USER_DATA_AVAILABLE))
+ , m_aStrUnknownUser(ScResId(STR_UNKNOWN_USER_CONFLICT))
+ , m_aStrExclusiveAccess(ScResId(STR_EXCLUSIVE_ACCESS))
+ , mpDocShell(nullptr)
+ , m_xCbShare(m_xBuilder->weld_check_button("share"))
+ , m_xFtWarning(m_xBuilder->weld_label("warning"))
+ , m_xLbUsers(m_xBuilder->weld_tree_view("users"))
+{
+
+ OSL_ENSURE( pViewData, "ScShareDocumentDlg CTOR: mpViewData is null!" );
+ mpDocShell = ( pViewData ? pViewData->GetDocShell() : nullptr );
+ OSL_ENSURE( mpDocShell, "ScShareDocumentDlg CTOR: mpDocShell is null!" );
+
+ std::vector<int> aWidths
+ {
+ o3tl::narrowing<int>(m_xLbUsers->get_approximate_digit_width() * 25)
+ };
+ m_xLbUsers->set_column_fixed_widths(aWidths);
+
+ m_xLbUsers->set_size_request(-1, m_xLbUsers->get_height_rows(9));
+ m_xLbUsers->connect_size_allocate(LINK(this, ScShareDocumentDlg, SizeAllocated));
+
+ bool bIsDocShared = mpDocShell && mpDocShell->IsDocShared();
+ m_xCbShare->set_active(bIsDocShared);
+ m_xCbShare->connect_toggled( LINK( this, ScShareDocumentDlg, ToggleHandle ) );
+ m_xFtWarning->set_sensitive(bIsDocShared);
+
+ m_xLbUsers->set_selection_mode(SelectionMode::NONE);
+
+ UpdateView();
+}
+
+ScShareDocumentDlg::~ScShareDocumentDlg()
+{
+}
+
+IMPL_LINK_NOARG(ScShareDocumentDlg, ToggleHandle, weld::Toggleable&, void)
+{
+ m_xFtWarning->set_sensitive(m_xCbShare->get_active());
+}
+
+bool ScShareDocumentDlg::IsShareDocumentChecked() const
+{
+ return m_xCbShare->get_active();
+}
+
+void ScShareDocumentDlg::UpdateView()
+{
+ if ( !mpDocShell )
+ {
+ return;
+ }
+
+ if ( mpDocShell->IsDocShared() )
+ {
+ try
+ {
+ ::svt::ShareControlFile aControlFile( mpDocShell->GetSharedFileURL() );
+ std::vector<LockFileEntry> aUsersData = aControlFile.GetUsersData();
+ sal_Int32 nLength = aUsersData.size();
+
+ if ( nLength > 0 )
+ {
+ sal_Int32 nUnknownUser = 1;
+
+ for ( sal_Int32 i = 0; i < nLength; ++i )
+ {
+ if ( !aUsersData[i][LockFileComponent::EDITTIME].isEmpty() )
+ {
+ OUString aUser;
+ if ( !aUsersData[i][LockFileComponent::OOOUSERNAME].isEmpty() )
+ {
+ aUser = aUsersData[i][LockFileComponent::OOOUSERNAME];
+ }
+ else if ( !aUsersData[i][LockFileComponent::SYSUSERNAME].isEmpty() )
+ {
+ aUser = aUsersData[i][LockFileComponent::SYSUSERNAME];
+ }
+ else
+ {
+ aUser = m_aStrUnknownUser + " " + OUString::number( nUnknownUser++ );
+ }
+
+ // parse the edit time string of the format "DD.MM.YYYY hh:mm"
+ OUString aDateTimeStr = aUsersData[i][LockFileComponent::EDITTIME];
+ sal_Int32 nIndex = 0;
+ std::u16string_view aDateStr = o3tl::getToken(aDateTimeStr, 0, ' ', nIndex );
+ std::u16string_view aTimeStr = o3tl::getToken(aDateTimeStr, 0, ' ', nIndex );
+ nIndex = 0;
+ sal_uInt16 nDay = sal::static_int_cast< sal_uInt16 >( o3tl::toInt32(o3tl::getToken(aDateStr, 0, '.', nIndex )) );
+ sal_uInt16 nMonth = sal::static_int_cast< sal_uInt16 >( o3tl::toInt32(o3tl::getToken(aDateStr, 0, '.', nIndex )) );
+ sal_uInt16 nYear = sal::static_int_cast< sal_uInt16 >( o3tl::toInt32(o3tl::getToken(aDateStr, 0, '.', nIndex )) );
+ nIndex = 0;
+ sal_uInt16 nHours = sal::static_int_cast< sal_uInt16 >( o3tl::toInt32(o3tl::getToken(aTimeStr, 0, ':', nIndex )) );
+ sal_uInt16 nMinutes = sal::static_int_cast< sal_uInt16 >( o3tl::toInt32(o3tl::getToken(aTimeStr, 0, ':', nIndex )) );
+ Date aDate( nDay, nMonth, nYear );
+ tools::Time aTime( nHours, nMinutes );
+ DateTime aDateTime( aDate, aTime );
+
+ OUString aString = formatDateTime(aDateTime, ScGlobal::getLocaleData(), false);
+
+ m_xLbUsers->append_text(aUser);
+ m_xLbUsers->set_text(m_xLbUsers->n_children() - 1, aString, 1);
+ }
+ }
+ }
+ else
+ {
+ m_xLbUsers->append_text(m_aStrNoUserData);
+ }
+ }
+ catch ( uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "ScShareDocumentDlg::UpdateView()" );
+ m_xLbUsers->clear();
+ m_xLbUsers->append_text(m_aStrNoUserData);
+ }
+ }
+ else
+ {
+ // get OOO user name
+ SvtUserOptions aUserOpt;
+ OUString aUser = aUserOpt.GetFirstName();
+ if ( !aUser.isEmpty() )
+ {
+ aUser += " ";
+ }
+ aUser += aUserOpt.GetLastName();
+ if ( aUser.isEmpty() )
+ {
+ // get sys user name
+ OUString aUserName;
+ ::osl::Security aSecurity;
+ aSecurity.getUserName( aUserName );
+ aUser = aUserName;
+ }
+ if ( aUser.isEmpty() )
+ {
+ // unknown user name
+ aUser = m_aStrUnknownUser;
+ }
+ aUser += " " + m_aStrExclusiveAccess;
+
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS(mpDocShell->GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
+
+ util::DateTime uDT(xDocProps->getModificationDate());
+ DateTime aDateTime(uDT);
+
+ OUString aString = formatDateTime(aDateTime, ScGlobal::getLocaleData(), false) + " " +
+ ScGlobal::getLocaleData().getTime( aDateTime, false );
+
+ m_xLbUsers->append_text(aUser);
+ m_xLbUsers->set_text(m_xLbUsers->n_children() - 1, aString, 1);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/shtabdlg.cxx b/sc/source/ui/miscdlgs/shtabdlg.cxx
new file mode 100644
index 000000000..cf0c10918
--- /dev/null
+++ b/sc/source/ui/miscdlgs/shtabdlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <shtabdlg.hxx>
+
+ScShowTabDlg::ScShowTabDlg(weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/showsheetdialog.ui", "ShowSheetDialog")
+ , m_xFrame(m_xBuilder->weld_frame("frame"))
+ , m_xLb(m_xBuilder->weld_tree_view("treeview"))
+{
+ m_xLb->set_selection_mode(SelectionMode::Multiple);
+ m_xLb->set_size_request(-1, m_xLb->get_height_rows(10));
+ m_xLb->connect_row_activated(LINK(this, ScShowTabDlg, DblClkHdl));
+}
+
+ScShowTabDlg::~ScShowTabDlg() {}
+
+void ScShowTabDlg::SetDescription(const OUString& rTitle, const OUString& rFixedText,
+ const OString& rDlgHelpId, const OString& sLbHelpId)
+{
+ m_xDialog->set_title(rTitle);
+ m_xFrame->set_label(rFixedText);
+ m_xDialog->set_help_id(rDlgHelpId);
+ m_xLb->set_help_id(sLbHelpId);
+}
+
+void ScShowTabDlg::Insert(const OUString& rString, bool bSelected)
+{
+ m_xLb->append_text(rString);
+ if (bSelected)
+ m_xLb->select(m_xLb->n_children() - 1);
+}
+
+std::vector<sal_Int32> ScShowTabDlg::GetSelectedRows() const
+{
+ auto aTmp = m_xLb->get_selected_rows();
+ return std::vector<sal_Int32>(aTmp.begin(), aTmp.end());
+}
+
+OUString ScShowTabDlg::GetEntry(sal_Int32 nIndex) const { return m_xLb->get_text(nIndex); }
+
+IMPL_LINK_NOARG(ScShowTabDlg, DblClkHdl, weld::TreeView&, bool)
+{
+ m_xDialog->response(RET_OK);
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/simpref.cxx b/sc/source/ui/miscdlgs/simpref.cxx
new file mode 100644
index 000000000..27e8e3bb6
--- /dev/null
+++ b/sc/source/ui/miscdlgs/simpref.cxx
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <reffact.hxx>
+#include <document.hxx>
+#include <simpref.hxx>
+
+ScSimpleRefDlg::ScSimpleRefDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent)
+ : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/simplerefdialog.ui", "SimpleRefDialog")
+ , bAutoReOpen(true)
+ , bCloseOnButtonUp(false)
+ , bSingleCell(false)
+ , bMultiSelection(false)
+ , m_xFtAssign(m_xBuilder->weld_label("area"))
+ , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry("assign")))
+ , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button("assignref")))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+{
+ m_xEdAssign->SetReferences(this, m_xFtAssign.get());
+ m_xRbAssign->SetReferences(this, m_xEdAssign.get());
+
+ // in order to keep the Strings with the FixedTexts in the resource:
+ Init();
+ SetDispatcherLock( true ); // activate modal mode
+}
+
+ScSimpleRefDlg::~ScSimpleRefDlg()
+{
+ SetDispatcherLock( false ); // deactivate modal mode
+}
+
+void ScSimpleRefDlg::FillInfo(SfxChildWinInfo& rWinInfo) const
+{
+ ScAnyRefDlgController::FillInfo(rWinInfo);
+ rWinInfo.bVisible = bAutoReOpen;
+}
+
+void ScSimpleRefDlg::SetRefString(const OUString &rStr)
+{
+ m_xEdAssign->SetText(rStr);
+}
+
+void ScSimpleRefDlg::Init()
+{
+ m_xBtnOk->connect_clicked( LINK( this, ScSimpleRefDlg, OkBtnHdl ) );
+ m_xBtnCancel->connect_clicked( LINK( this, ScSimpleRefDlg, CancelBtnHdl ) );
+ bCloseFlag=false;
+}
+
+// Set the reference to a cell range selected with the mouse. This is then
+// shown as the new selection in the reference field.
+void ScSimpleRefDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
+{
+ if (!m_xEdAssign->GetWidget()->get_sensitive())
+ return;
+
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart(m_xEdAssign.get());
+
+ theCurArea = rRef;
+ OUString aRefStr;
+ if ( bSingleCell )
+ {
+ ScAddress aAdr = rRef.aStart;
+ aRefStr = aAdr.Format(ScRefFlags::ADDR_ABS_3D, &rDocP, rDocP.GetAddressConvention());
+ }
+ else
+ aRefStr = theCurArea.Format(rDocP, ScRefFlags::RANGE_ABS_3D, rDocP.GetAddressConvention());
+
+ if ( bMultiSelection )
+ {
+ OUString aVal = m_xEdAssign->GetText();
+ Selection aSel = m_xEdAssign->GetSelection();
+ aSel.Justify();
+ aVal = aVal.replaceAt( aSel.Min(), aSel.Len(), aRefStr );
+ Selection aNewSel( aSel.Min(), aSel.Min()+aRefStr.getLength() );
+ m_xEdAssign->SetRefString( aVal );
+ m_xEdAssign->SetSelection( aNewSel );
+ }
+ else
+ m_xEdAssign->SetRefString( aRefStr );
+
+ aChangeHdl.Call( aRefStr );
+}
+
+void ScSimpleRefDlg::Close()
+{
+ CancelBtnHdl(*m_xBtnCancel);
+}
+
+void ScSimpleRefDlg::SetActive()
+{
+ m_xEdAssign->GrabFocus();
+
+ // no NameModifyHdl. Otherwise ranges could not be altered
+ // (after marking the reference, the old field content would be shown)
+ // (also, the selected DB name has also not been altered)
+
+ RefInputDone();
+}
+
+bool ScSimpleRefDlg::IsRefInputMode() const
+{
+ return true;
+}
+
+void ScSimpleRefDlg::SetCloseHdl( const Link<const OUString*,void>& rLink )
+{
+ aCloseHdl=rLink;
+}
+
+void ScSimpleRefDlg::SetUnoLinks( const Link<const OUString&,void>& rDone,
+ const Link<const OUString&,void>& rAbort,
+ const Link<const OUString&,void>& rChange )
+{
+ aDoneHdl = rDone;
+ aAbortedHdl = rAbort;
+ aChangeHdl = rChange;
+}
+
+void ScSimpleRefDlg::SetFlags( bool bSetCloseOnButtonUp, bool bSetSingleCell, bool bSetMultiSelection )
+{
+ bCloseOnButtonUp = bSetCloseOnButtonUp;
+ bSingleCell = bSetSingleCell;
+ bMultiSelection = bSetMultiSelection;
+}
+
+void ScSimpleRefDlg::StartRefInput()
+{
+ if ( bMultiSelection )
+ {
+ // initially select the whole string, so it gets replaced by default
+ m_xEdAssign->SelectAll();
+ }
+
+ m_xRbAssign->DoRef();
+ bCloseFlag = true;
+}
+
+void ScSimpleRefDlg::RefInputDone( bool bForced)
+{
+ ScAnyRefDlgController::RefInputDone(bForced);
+ if ( (bForced || bCloseOnButtonUp) && bCloseFlag )
+ OkBtnHdl(*m_xBtnOk);
+}
+
+// Handler:
+
+IMPL_LINK_NOARG(ScSimpleRefDlg, OkBtnHdl, weld::Button&, void)
+{
+ if (IsClosing())
+ return;
+ bAutoReOpen = false;
+ OUString aResult=m_xEdAssign->GetText();
+ aCloseHdl.Call(&aResult);
+ Link<const OUString&,void> aUnoLink = aDoneHdl; // stack var because this is deleted in DoClose
+ DoClose( ScSimpleRefDlgWrapper::GetChildWindowId() );
+ aUnoLink.Call( aResult );
+}
+
+IMPL_LINK_NOARG(ScSimpleRefDlg, CancelBtnHdl, weld::Button&, void)
+{
+ if (IsClosing())
+ return;
+ bAutoReOpen = false;
+ OUString aResult=m_xEdAssign->GetText();
+ aCloseHdl.Call(nullptr);
+ Link<const OUString&,void> aUnoLink = aAbortedHdl; // stack var because this is deleted in DoClose
+ DoClose( ScSimpleRefDlgWrapper::GetChildWindowId() );
+ aUnoLink.Call( aResult );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/solveroptions.cxx b/sc/source/ui/miscdlgs/solveroptions.cxx
new file mode 100644
index 000000000..41603b6d5
--- /dev/null
+++ b/sc/source/ui/miscdlgs/solveroptions.cxx
@@ -0,0 +1,415 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <solveroptions.hxx>
+#include <global.hxx>
+#include <miscuno.hxx>
+#include <solverutil.hxx>
+
+#include <rtl/math.hxx>
+#include <unotools/collatorwrapper.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <osl/diagnose.h>
+
+#include <algorithm>
+
+#include <com/sun/star/sheet/XSolver.hpp>
+#include <com/sun/star/sheet/XSolverDescription.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+using namespace com::sun::star;
+
+namespace {
+
+/// Helper for sorting properties
+struct ScSolverOptionsEntry
+{
+ sal_Int32 nPosition;
+ OUString aDescription;
+
+ ScSolverOptionsEntry() : nPosition(0) {}
+
+ bool operator< (const ScSolverOptionsEntry& rOther) const
+ {
+ return (ScGlobal::GetCollator().compareString( aDescription, rOther.aDescription ) < 0);
+ }
+};
+
+}
+
+ScSolverOptionsDialog::ScSolverOptionsDialog(weld::Window* pParent,
+ const uno::Sequence<OUString>& rImplNames,
+ const uno::Sequence<OUString>& rDescriptions,
+ const OUString& rEngine,
+ const uno::Sequence<beans::PropertyValue>& rProperties )
+ : GenericDialogController(pParent, "modules/scalc/ui/solveroptionsdialog.ui", "SolverOptionsDialog")
+ , maImplNames(rImplNames)
+ , maEngine(rEngine)
+ , maProperties(rProperties)
+ , m_xLbEngine(m_xBuilder->weld_combo_box("engine"))
+ , m_xLbSettings(m_xBuilder->weld_tree_view("settings"))
+ , m_xBtnEdit(m_xBuilder->weld_button("edit"))
+{
+ m_xLbSettings->set_size_request(m_xLbSettings->get_approximate_digit_width() * 32,
+ m_xLbSettings->get_height_rows(6));
+
+ m_xLbSettings->enable_toggle_buttons(weld::ColumnToggleType::Check);
+
+ m_xLbEngine->connect_changed( LINK( this, ScSolverOptionsDialog, EngineSelectHdl ) );
+
+ m_xBtnEdit->connect_clicked( LINK( this, ScSolverOptionsDialog, ButtonHdl ) );
+
+ m_xLbSettings->connect_changed( LINK( this, ScSolverOptionsDialog, SettingsSelHdl ) );
+ m_xLbSettings->connect_row_activated( LINK( this, ScSolverOptionsDialog, SettingsDoubleClickHdl ) );
+
+ sal_Int32 nSelect = -1;
+ sal_Int32 nImplCount = maImplNames.getLength();
+ for (sal_Int32 nImpl=0; nImpl<nImplCount; ++nImpl)
+ {
+ OUString aImplName( maImplNames[nImpl] );
+ OUString aDescription( rDescriptions[nImpl] ); // user-visible descriptions in list box
+ m_xLbEngine->append_text(aDescription);
+ if ( aImplName == maEngine )
+ nSelect = nImpl;
+ }
+ if ( nSelect < 0 ) // no (valid) engine given
+ {
+ if ( nImplCount > 0 )
+ {
+ maEngine = maImplNames[0]; // use first implementation
+ nSelect = 0;
+ }
+ else
+ maEngine.clear();
+ maProperties.realloc(0); // don't use options from different engine
+ }
+ if ( nSelect >= 0 ) // select in list box
+ m_xLbEngine->set_active(nSelect);
+
+ if ( !maProperties.hasElements() )
+ ReadFromComponent(); // fill maProperties from component (using maEngine)
+ FillListBox(); // using maProperties
+}
+
+ScSolverOptionsDialog::~ScSolverOptionsDialog()
+{
+ if (m_xIntDialog)
+ m_xIntDialog->response(RET_CANCEL);
+ assert(!m_xIntDialog);
+ if (m_xValDialog)
+ m_xValDialog->response(RET_CANCEL);
+ assert(!m_xValDialog);
+}
+
+const uno::Sequence<beans::PropertyValue>& ScSolverOptionsDialog::GetProperties()
+{
+ // update maProperties from list box content
+ // order of entries in list box and maProperties is the same
+ sal_Int32 nEntryCount = maProperties.getLength();
+ if (nEntryCount == m_xLbSettings->n_children())
+ {
+ auto maPropertiesRange = asNonConstRange(maProperties);
+ for (sal_Int32 nEntryPos=0; nEntryPos<nEntryCount; ++nEntryPos)
+ {
+ uno::Any& rValue = maPropertiesRange[nEntryPos].Value;
+ if (ScSolverOptionsString* pStringItem = weld::fromId<ScSolverOptionsString*>(m_xLbSettings->get_id(nEntryPos)))
+ {
+ if (pStringItem->IsDouble())
+ rValue <<= pStringItem->GetDoubleValue();
+ else
+ rValue <<= pStringItem->GetIntValue();
+ }
+ else
+ rValue <<= m_xLbSettings->get_toggle(nEntryPos) == TRISTATE_TRUE;
+ }
+ }
+ else
+ {
+ OSL_FAIL( "wrong count" );
+ }
+
+ return maProperties;
+}
+
+void ScSolverOptionsDialog::FillListBox()
+{
+ // get property descriptions, sort by them
+
+ uno::Reference<sheet::XSolverDescription> xDesc( ScSolverUtil::GetSolver( maEngine ), uno::UNO_QUERY );
+ sal_Int32 nCount = maProperties.getLength();
+ std::vector<ScSolverOptionsEntry> aDescriptions( nCount );
+ for (sal_Int32 nPos=0; nPos<nCount; nPos++)
+ {
+ OUString aPropName( maProperties[nPos].Name );
+ OUString aVisName;
+ if ( xDesc.is() )
+ aVisName = xDesc->getPropertyDescription( aPropName );
+ if ( aVisName.isEmpty() )
+ aVisName = aPropName;
+ aDescriptions[nPos].nPosition = nPos;
+ aDescriptions[nPos].aDescription = aVisName;
+ }
+ std::sort( aDescriptions.begin(), aDescriptions.end() );
+
+ // also update maProperties to the order of descriptions
+
+ uno::Sequence<beans::PropertyValue> aNewSeq;
+ aNewSeq.realloc( nCount );
+ std::transform(aDescriptions.begin(), aDescriptions.end(), aNewSeq.getArray(),
+ [this](const ScSolverOptionsEntry& rDescr) -> beans::PropertyValue { return maProperties[ rDescr.nPosition ]; });
+ maProperties = aNewSeq;
+
+ // fill the list box
+
+ m_xLbSettings->freeze();
+ m_xLbSettings->clear();
+
+ for (sal_Int32 nPos=0; nPos<nCount; nPos++)
+ {
+ OUString aVisName = aDescriptions[nPos].aDescription;
+
+ uno::Any aValue = maProperties[nPos].Value;
+ uno::TypeClass eClass = aValue.getValueTypeClass();
+
+ m_xLbSettings->append();
+
+ if ( eClass == uno::TypeClass_BOOLEAN )
+ {
+ // check box entry
+ m_xLbSettings->set_toggle(nPos, ScUnoHelpFunctions::GetBoolFromAny(aValue) ? TRISTATE_TRUE : TRISTATE_FALSE);
+ m_xLbSettings->set_text(nPos, aVisName, 0);
+ }
+ else
+ {
+ // value entry
+ m_xLbSettings->set_text(nPos, aVisName, 0);
+ m_aOptions.emplace_back(new ScSolverOptionsString(aVisName));
+ if (eClass == uno::TypeClass_DOUBLE)
+ {
+ double fDoubleValue = 0.0;
+ if (aValue >>= fDoubleValue)
+ m_aOptions.back()->SetDoubleValue(fDoubleValue);
+
+ OUString sTxt = aVisName + ": ";
+ sTxt += rtl::math::doubleToUString(fDoubleValue,
+ rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
+ ScGlobal::getLocaleData().getNumDecimalSep()[0], true );
+
+ m_xLbSettings->set_text(nPos, sTxt, 0);
+ }
+ else
+ {
+ sal_Int32 nIntValue = 0;
+ if (aValue >>= nIntValue)
+ m_aOptions.back()->SetIntValue(nIntValue);
+
+ OUString sTxt = aVisName + ": " + OUString::number(nIntValue);
+
+ m_xLbSettings->set_text(nPos, sTxt, 0);
+ }
+ m_xLbSettings->set_id(nPos, weld::toId(m_aOptions.back().get()));
+ }
+ }
+
+ m_xLbSettings->thaw();
+}
+
+void ScSolverOptionsDialog::ReadFromComponent()
+{
+ maProperties = ScSolverUtil::GetDefaults( maEngine );
+}
+
+void ScSolverOptionsDialog::EditOption()
+{
+ int nEntry = m_xLbSettings->get_selected_index();
+ if (nEntry == -1)
+ return;
+ ScSolverOptionsString* pStringItem = weld::fromId<ScSolverOptionsString*>(m_xLbSettings->get_id(nEntry));
+ if (!pStringItem)
+ return;
+
+ if (pStringItem->IsDouble())
+ {
+ m_xValDialog = std::make_shared<ScSolverValueDialog>(m_xDialog.get());
+ m_xValDialog->SetOptionName(pStringItem->GetText());
+ if (maProperties[nEntry].Name == "DECR")
+ m_xValDialog->SetMax(1.0);
+ else if (maProperties[nEntry].Name == "DEFactorMax")
+ m_xValDialog->SetMax(1.2);
+ else if (maProperties[nEntry].Name == "DEFactorMin")
+ m_xValDialog->SetMax(1.2);
+ else if (maProperties[nEntry].Name == "PSCL")
+ m_xValDialog->SetMax(0.005);
+ m_xValDialog->SetValue(pStringItem->GetDoubleValue());
+ weld::DialogController::runAsync(m_xValDialog, [nEntry, pStringItem, this](sal_Int32 nResult){
+ if (nResult == RET_OK)
+ {
+ pStringItem->SetDoubleValue(m_xValDialog->GetValue());
+
+ OUString sTxt(pStringItem->GetText() + ": ");
+ sTxt += rtl::math::doubleToUString(pStringItem->GetDoubleValue(),
+ rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
+ ScGlobal::getLocaleData().getNumDecimalSep()[0], true );
+
+ m_xLbSettings->set_text(nEntry, sTxt, 0);
+ }
+ m_xValDialog.reset();
+ });
+ }
+ else
+ {
+ m_xIntDialog = std::make_shared<ScSolverIntegerDialog>(m_xDialog.get());
+ m_xIntDialog->SetOptionName( pStringItem->GetText() );
+ if (maProperties[nEntry].Name == "EpsilonLevel")
+ m_xIntDialog->SetMax(3);
+ else if (maProperties[nEntry].Name == "Algorithm")
+ m_xIntDialog->SetMax(1);
+ m_xIntDialog->SetValue( pStringItem->GetIntValue() );
+ weld::DialogController::runAsync(m_xIntDialog, [nEntry, pStringItem, this](sal_Int32 nResult){
+ if (nResult == RET_OK)
+ {
+ pStringItem->SetIntValue(m_xIntDialog->GetValue());
+
+ OUString sTxt(
+ pStringItem->GetText() + ": " + OUString::number(pStringItem->GetIntValue()));
+
+ m_xLbSettings->set_text(nEntry, sTxt, 0);
+ }
+ m_xIntDialog.reset();
+ });
+ }
+}
+
+IMPL_LINK( ScSolverOptionsDialog, ButtonHdl, weld::Button&, rBtn, void )
+{
+ if (&rBtn == m_xBtnEdit.get())
+ EditOption();
+}
+
+IMPL_LINK_NOARG(ScSolverOptionsDialog, SettingsDoubleClickHdl, weld::TreeView&, bool)
+{
+ EditOption();
+ return true;
+}
+
+IMPL_LINK_NOARG(ScSolverOptionsDialog, EngineSelectHdl, weld::ComboBox&, void)
+{
+ const sal_Int32 nSelectPos = m_xLbEngine->get_active();
+ if ( nSelectPos < maImplNames.getLength() )
+ {
+ OUString aNewEngine( maImplNames[nSelectPos] );
+ if ( aNewEngine != maEngine )
+ {
+ maEngine = aNewEngine;
+ ReadFromComponent(); // fill maProperties from component (using maEngine)
+ FillListBox(); // using maProperties
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ScSolverOptionsDialog, SettingsSelHdl, weld::TreeView&, void)
+{
+ bool bCheckbox = false;
+
+ int nEntry = m_xLbSettings->get_selected_index();
+ if (nEntry != -1)
+ {
+ ScSolverOptionsString* pStringItem = weld::fromId<ScSolverOptionsString*>(m_xLbSettings->get_id(nEntry));
+ if (!pStringItem)
+ bCheckbox = true;
+ }
+
+ m_xBtnEdit->set_sensitive(!bCheckbox);
+}
+
+ScSolverIntegerDialog::ScSolverIntegerDialog(weld::Window * pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/integerdialog.ui", "IntegerDialog")
+ , m_xFrame(m_xBuilder->weld_frame("frame"))
+ , m_xNfValue(m_xBuilder->weld_spin_button("value"))
+{
+}
+
+ScSolverIntegerDialog::~ScSolverIntegerDialog()
+{
+}
+
+void ScSolverIntegerDialog::SetOptionName( const OUString& rName )
+{
+ m_xFrame->set_label(rName);
+}
+
+void ScSolverIntegerDialog::SetValue( sal_Int32 nValue )
+{
+ m_xNfValue->set_value( nValue );
+}
+
+void ScSolverIntegerDialog::SetMax( sal_Int32 nMax )
+{
+ m_xNfValue->set_range(0, nMax);
+}
+
+sal_Int32 ScSolverIntegerDialog::GetValue() const
+{
+ return m_xNfValue->get_value();
+}
+
+ScSolverValueDialog::ScSolverValueDialog(weld::Window* pParent)
+ : GenericDialogController(pParent, "modules/scalc/ui/doubledialog.ui", "DoubleDialog")
+ , m_xFrame(m_xBuilder->weld_frame("frame"))
+ , m_xEdValue(m_xBuilder->weld_entry("value"))
+ , m_fMaxValue(std::numeric_limits<double>::quiet_NaN())
+{
+}
+
+ScSolverValueDialog::~ScSolverValueDialog()
+{
+}
+
+void ScSolverValueDialog::SetOptionName( const OUString& rName )
+{
+ m_xFrame->set_label(rName);
+}
+
+void ScSolverValueDialog::SetValue( double fValue )
+{
+ m_xEdValue->set_text( rtl::math::doubleToUString( fValue,
+ rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
+ ScGlobal::getLocaleData().getNumDecimalSep()[0], true ) );
+}
+
+void ScSolverValueDialog::SetMax(double fMax)
+{
+ m_fMaxValue = fMax;
+}
+
+double ScSolverValueDialog::GetValue() const
+{
+ OUString aInput = m_xEdValue->get_text();
+
+ rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
+ sal_Int32 nParseEnd = 0;
+ double fValue = ScGlobal::getLocaleData().stringToDouble( aInput, true, &eStatus, &nParseEnd);
+ /* TODO: shouldn't there be some error checking? */
+ if (!std::isnan(m_fMaxValue) && fValue > m_fMaxValue)
+ fValue = m_fMaxValue;
+ return fValue;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/solverutil.cxx b/sc/source/ui/miscdlgs/solverutil.cxx
new file mode 100644
index 000000000..6ba270786
--- /dev/null
+++ b/sc/source/ui/miscdlgs/solverutil.cxx
@@ -0,0 +1,175 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <solverutil.hxx>
+
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XSingleComponentFactory.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sheet/XSolver.hpp>
+#include <com/sun/star/sheet/XSolverDescription.hpp>
+
+#include <osl/diagnose.h>
+#include <comphelper/processfactory.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace com::sun::star;
+
+constexpr OUStringLiteral SCSOLVER_SERVICE = u"com.sun.star.sheet.Solver";
+
+void ScSolverUtil::GetImplementations( uno::Sequence<OUString>& rImplNames,
+ uno::Sequence<OUString>& rDescriptions )
+{
+ rImplNames.realloc(0); // clear
+ rDescriptions.realloc(0);
+
+ uno::Reference<uno::XComponentContext> xCtx(
+ comphelper::getProcessComponentContext() );
+
+ uno::Reference<container::XContentEnumerationAccess> xEnAc(
+ xCtx->getServiceManager(), uno::UNO_QUERY );
+ if ( !xEnAc.is() )
+ return;
+
+ uno::Reference<container::XEnumeration> xEnum =
+ xEnAc->createContentEnumeration( SCSOLVER_SERVICE );
+ if ( !xEnum.is() )
+ return;
+
+ sal_Int32 nCount = 0;
+ while ( xEnum->hasMoreElements() )
+ {
+ uno::Any aAny = xEnum->nextElement();
+ uno::Reference<lang::XServiceInfo> xInfo;
+ aAny >>= xInfo;
+ if ( xInfo.is() )
+ {
+ uno::Reference<lang::XSingleComponentFactory> xCFac( xInfo, uno::UNO_QUERY );
+ if ( xCFac.is() )
+ {
+ OUString sName = xInfo->getImplementationName();
+
+ try
+ {
+ uno::Reference<sheet::XSolver> xSolver(
+ xCFac->createInstanceWithContext(xCtx), uno::UNO_QUERY );
+ uno::Reference<sheet::XSolverDescription> xDesc( xSolver, uno::UNO_QUERY );
+ OUString sDescription;
+ if ( xDesc.is() )
+ sDescription = xDesc->getComponentDescription();
+
+ if ( sDescription.isEmpty() )
+ sDescription = sName; // use implementation name if no description available
+
+ rImplNames.realloc( nCount+1 );
+ rImplNames.getArray()[nCount] = sName;
+ rDescriptions.realloc( nCount+1 );
+ rDescriptions.getArray()[nCount] = sDescription;
+ ++nCount;
+ }
+ catch (const css::uno::Exception&)
+ {
+ TOOLS_INFO_EXCEPTION("sc.ui", "ScSolverUtil::GetImplementations: cannot instantiate: " << sName);
+ }
+ }
+ }
+ }
+}
+
+uno::Reference<sheet::XSolver> ScSolverUtil::GetSolver( std::u16string_view rImplName )
+{
+ uno::Reference<sheet::XSolver> xSolver;
+
+ uno::Reference<uno::XComponentContext> xCtx(
+ comphelper::getProcessComponentContext() );
+
+ uno::Reference<container::XContentEnumerationAccess> xEnAc(
+ xCtx->getServiceManager(), uno::UNO_QUERY );
+ if ( xEnAc.is() )
+ {
+ uno::Reference<container::XEnumeration> xEnum =
+ xEnAc->createContentEnumeration( SCSOLVER_SERVICE );
+ if ( xEnum.is() )
+ {
+ while ( xEnum->hasMoreElements() && !xSolver.is() )
+ {
+ uno::Any aAny = xEnum->nextElement();
+ uno::Reference<lang::XServiceInfo> xInfo;
+ aAny >>= xInfo;
+ if ( xInfo.is() )
+ {
+ uno::Reference<lang::XSingleComponentFactory> xCFac( xInfo, uno::UNO_QUERY );
+ if ( xCFac.is() )
+ {
+ OUString sName = xInfo->getImplementationName();
+ if ( sName == rImplName )
+ xSolver.set( xCFac->createInstanceWithContext(xCtx), uno::UNO_QUERY );
+ }
+ }
+ }
+ }
+ }
+
+ SAL_WARN_IF( !xSolver.is(), "sc.ui", "can't get solver" );
+ return xSolver;
+}
+
+uno::Sequence<beans::PropertyValue> ScSolverUtil::GetDefaults( std::u16string_view rImplName )
+{
+ uno::Sequence<beans::PropertyValue> aDefaults;
+
+ uno::Reference<sheet::XSolver> xSolver = GetSolver( rImplName );
+ uno::Reference<beans::XPropertySet> xPropSet( xSolver, uno::UNO_QUERY );
+ if ( !xPropSet.is() )
+ {
+ // no XPropertySet - no options
+ return aDefaults;
+ }
+
+ // fill maProperties
+
+ uno::Reference<beans::XPropertySetInfo> xInfo = xPropSet->getPropertySetInfo();
+ OSL_ENSURE( xInfo.is(), "can't get property set info" );
+ if ( !xInfo.is() )
+ return aDefaults;
+
+ const uno::Sequence<beans::Property> aPropSeq = xInfo->getProperties();
+ const sal_Int32 nSize = aPropSeq.getLength();
+ aDefaults.realloc(nSize);
+ auto pDefaults = aDefaults.getArray();
+ sal_Int32 nValid = 0;
+ for (const beans::Property& rProp : aPropSeq)
+ {
+ uno::Any aValue = xPropSet->getPropertyValue( rProp.Name );
+ uno::TypeClass eClass = aValue.getValueTypeClass();
+ // only use properties of supported types
+ if ( eClass == uno::TypeClass_BOOLEAN || eClass == uno::TypeClass_LONG || eClass == uno::TypeClass_DOUBLE )
+ pDefaults[nValid++] = beans::PropertyValue( rProp.Name, -1, aValue, beans::PropertyState_DIRECT_VALUE );
+ }
+ aDefaults.realloc(nValid);
+
+ //! get user-visible names, sort by them
+
+ return aDefaults;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/solvrdlg.cxx b/sc/source/ui/miscdlgs/solvrdlg.cxx
new file mode 100644
index 000000000..f7cd8e27b
--- /dev/null
+++ b/sc/source/ui/miscdlgs/solvrdlg.cxx
@@ -0,0 +1,282 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svl/numformat.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <uiitems.hxx>
+#include <reffact.hxx>
+#include <document.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <sc.hrc>
+#include <solvrdlg.hxx>
+
+ScSolverDlg::ScSolverDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScDocument* pDocument,
+ const ScAddress& aCursorPos )
+
+ : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/goalseekdlg.ui", "GoalSeekDialog")
+ , theFormulaCell(aCursorPos)
+ , theVariableCell(aCursorPos)
+ , pDoc(pDocument)
+ , nCurTab(aCursorPos.Tab())
+ , bDlgLostFocus(false)
+ , errMsgInvalidVar(ScResId(STR_INVALIDVAR))
+ , errMsgInvalidForm(ScResId(STR_INVALIDFORM))
+ , errMsgNoFormula(ScResId(STR_NOFORMULA))
+ , errMsgInvalidVal(ScResId(STR_INVALIDVAL))
+ , m_pEdActive(nullptr)
+ , m_xFtFormulaCell(m_xBuilder->weld_label("formulatext"))
+ , m_xEdFormulaCell(new formula::RefEdit(m_xBuilder->weld_entry("formulaedit")))
+ , m_xRBFormulaCell(new formula::RefButton(m_xBuilder->weld_button("formulabutton")))
+ , m_xEdTargetVal(m_xBuilder->weld_entry("target"))
+ , m_xFtVariableCell(m_xBuilder->weld_label("vartext"))
+ , m_xEdVariableCell(new formula::RefEdit(m_xBuilder->weld_entry("varedit")))
+ , m_xRBVariableCell(new formula::RefButton(m_xBuilder->weld_button("varbutton")))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+{
+ m_xEdFormulaCell->SetReferences(this, m_xFtFormulaCell.get());
+ m_xRBFormulaCell->SetReferences(this, m_xEdFormulaCell.get());
+ m_xEdVariableCell->SetReferences(this, m_xFtVariableCell.get());
+ m_xRBVariableCell->SetReferences(this, m_xEdVariableCell.get());
+ Init();
+}
+
+ScSolverDlg::~ScSolverDlg()
+{
+ if (m_xMessageBox)
+ m_xMessageBox->response(RET_CANCEL);
+ assert(!m_xMessageBox);
+}
+
+void ScSolverDlg::Init()
+{
+ m_xBtnOk->connect_clicked( LINK( this, ScSolverDlg, BtnHdl ) );
+ m_xBtnCancel->connect_clicked( LINK( this, ScSolverDlg, BtnHdl ) );
+
+ Link<formula::RefEdit&,void> aEditLink = LINK( this, ScSolverDlg, GetEditFocusHdl );
+ m_xEdFormulaCell->SetGetFocusHdl( aEditLink );
+ m_xEdVariableCell->SetGetFocusHdl( aEditLink );
+
+ Link<formula::RefButton&,void> aButtonLink = LINK( this, ScSolverDlg, GetButtonFocusHdl );
+ m_xRBFormulaCell->SetGetFocusHdl( aButtonLink );
+ m_xRBVariableCell->SetGetFocusHdl( aButtonLink );
+
+ m_xEdTargetVal->connect_focus_in(LINK(this, ScSolverDlg, GetFocusHdl));
+
+ aEditLink = LINK( this, ScSolverDlg, LoseEditFocusHdl );
+ m_xEdFormulaCell->SetLoseFocusHdl ( aEditLink );
+ m_xEdVariableCell->SetLoseFocusHdl ( aEditLink );
+
+ aButtonLink = LINK( this, ScSolverDlg, LoseButtonFocusHdl );
+ m_xRBFormulaCell->SetLoseFocusHdl ( aButtonLink );
+ m_xRBVariableCell->SetLoseFocusHdl ( aButtonLink );
+
+ OUString aStr(theFormulaCell.Format(ScRefFlags::ADDR_ABS, nullptr, pDoc->GetAddressConvention()));
+
+ m_xEdFormulaCell->SetText( aStr );
+ m_xEdFormulaCell->GrabFocus();
+ m_pEdActive = m_xEdFormulaCell.get();
+}
+
+void ScSolverDlg::Close()
+{
+ DoClose( ScSolverDlgWrapper::GetChildWindowId() );
+}
+
+void ScSolverDlg::SetActive()
+{
+ if ( bDlgLostFocus )
+ {
+ bDlgLostFocus = false;
+ if( m_pEdActive )
+ m_pEdActive->GrabFocus();
+ }
+ else
+ {
+ m_xDialog->grab_focus();
+ }
+ RefInputDone();
+}
+
+void ScSolverDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
+{
+ if( !m_pEdActive )
+ return;
+
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart(m_pEdActive);
+
+ ScAddress aAdr = rRef.aStart;
+ ScRefFlags nFmt = ( aAdr.Tab() == nCurTab )
+ ? ScRefFlags::ADDR_ABS
+ : ScRefFlags::ADDR_ABS_3D;
+
+ OUString aStr(aAdr.Format(nFmt, &rDocP, rDocP.GetAddressConvention()));
+ m_pEdActive->SetRefString( aStr );
+
+ if (m_pEdActive == m_xEdFormulaCell.get())
+ theFormulaCell = aAdr;
+ else if (m_pEdActive == m_xEdVariableCell.get())
+ theVariableCell = aAdr;
+}
+
+void ScSolverDlg::RaiseError( ScSolverErr eError )
+{
+ OUString sMessage;
+
+ switch (eError)
+ {
+ case SOLVERR_NOFORMULA:
+ sMessage = errMsgNoFormula;
+ break;
+ case SOLVERR_INVALID_FORMULA:
+ sMessage = errMsgInvalidForm;
+ break;
+ case SOLVERR_INVALID_VARIABLE:
+ sMessage = errMsgInvalidVar;
+ break;
+ case SOLVERR_INVALID_TARGETVALUE:
+ sMessage = errMsgInvalidVal;
+ break;
+ }
+
+ m_xMessageBox.reset(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ sMessage));
+ m_xMessageBox->runAsync(m_xMessageBox, [this](sal_Int32 /*nResult*/) {
+ m_xEdTargetVal->grab_focus();
+ m_xMessageBox.reset();
+ });
+}
+
+bool ScSolverDlg::IsRefInputMode() const
+{
+ return m_pEdActive != nullptr;
+}
+
+bool ScSolverDlg::CheckTargetValue( const OUString& rStrVal )
+{
+ sal_uInt32 n1 = 0;
+ double n2;
+
+ return pDoc->GetFormatTable()->IsNumberFormat( rStrVal, n1, n2 );
+}
+
+// Handler:
+
+IMPL_LINK(ScSolverDlg, BtnHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == m_xBtnOk.get())
+ {
+ theTargetValStr = m_xEdTargetVal->get_text();
+
+ // The following code checks:
+ // 1. do the strings contain correct references / defined names?
+ // 2. does the formula coordinate refer to a cell containing a formula?
+ // 3. has a valid target value been entered?
+
+ const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
+ ScRefFlags nRes1 = theFormulaCell .Parse( m_xEdFormulaCell->GetText(), *pDoc, eConv );
+ ScRefFlags nRes2 = theVariableCell.Parse( m_xEdVariableCell->GetText(), *pDoc, eConv );
+
+ if ( (nRes1 & ScRefFlags::VALID) == ScRefFlags::VALID )
+ {
+ if ( (nRes2 & ScRefFlags::VALID) == ScRefFlags::VALID )
+ {
+ if ( CheckTargetValue( theTargetValStr ) )
+ {
+ CellType eType = pDoc->GetCellType( theFormulaCell.Col(),
+ theFormulaCell.Row(),
+ theFormulaCell.Tab());
+
+ if ( CELLTYPE_FORMULA == eType )
+ {
+ ScSolveParam aOutParam( theFormulaCell,
+ theVariableCell,
+ theTargetValStr );
+ ScSolveItem aOutItem( SCITEM_SOLVEDATA, &aOutParam );
+
+ SetDispatcherLock( false );
+
+ SwitchToDocument();
+ GetBindings().GetDispatcher()->ExecuteList(SID_SOLVE,
+ SfxCallMode::SLOT | SfxCallMode::RECORD,
+ { &aOutItem });
+ response(RET_OK);
+ }
+ else RaiseError( SOLVERR_NOFORMULA );
+ }
+ else RaiseError( SOLVERR_INVALID_TARGETVALUE );
+ }
+ else RaiseError( SOLVERR_INVALID_VARIABLE );
+ }
+ else RaiseError( SOLVERR_INVALID_FORMULA );
+ }
+ else if (&rBtn == m_xBtnCancel.get())
+ {
+ response(RET_CANCEL);
+ }
+}
+
+IMPL_LINK(ScSolverDlg, GetEditFocusHdl, formula::RefEdit&, rCtrl, void)
+{
+ if (&rCtrl == m_xEdFormulaCell.get())
+ m_pEdActive = m_xEdFormulaCell.get();
+ else if (&rCtrl == m_xEdVariableCell.get())
+ m_pEdActive = m_xEdVariableCell.get();
+
+ if (m_pEdActive)
+ m_pEdActive->SelectAll();
+}
+
+IMPL_LINK_NOARG(ScSolverDlg, GetFocusHdl, weld::Widget&, void)
+{
+ m_pEdActive = nullptr;
+ m_xEdTargetVal->select_region(0, -1);
+}
+
+IMPL_LINK(ScSolverDlg, GetButtonFocusHdl, formula::RefButton&, rCtrl, void)
+{
+ if (&rCtrl == m_xRBFormulaCell.get())
+ m_pEdActive = m_xEdFormulaCell.get();
+ else if (&rCtrl == m_xRBVariableCell.get())
+ m_pEdActive = m_xEdVariableCell.get();
+
+ if (m_pEdActive)
+ m_pEdActive->SelectAll();
+}
+
+IMPL_LINK_NOARG(ScSolverDlg, LoseEditFocusHdl, formula::RefEdit&, void)
+{
+ bDlgLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScSolverDlg, LoseButtonFocusHdl, formula::RefButton&, void)
+{
+ bDlgLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/strindlg.cxx b/sc/source/ui/miscdlgs/strindlg.cxx
new file mode 100644
index 000000000..61ba77534
--- /dev/null
+++ b/sc/source/ui/miscdlgs/strindlg.cxx
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <strindlg.hxx>
+
+ScStringInputDlg::ScStringInputDlg(weld::Window* pParent,
+ const OUString& rTitle,
+ const OUString& rEditTitle,
+ const OUString& rDefault,
+ const OString& rHelpId, const OString& rEditHelpId)
+ : GenericDialogController(pParent, "modules/scalc/ui/inputstringdialog.ui",
+ "InputStringDialog")
+ , m_xLabel(m_xBuilder->weld_label("description_label"))
+ , m_xEdInput(m_xBuilder->weld_entry("name_entry"))
+{
+ m_xLabel->set_label(rEditTitle);
+ m_xDialog->set_title(rTitle);
+ m_xDialog->set_help_id(rHelpId);
+ m_xEdInput->set_text(rDefault);
+ m_xEdInput->set_help_id(rEditHelpId);
+ m_xEdInput->select_region(0, -1);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/tabbgcolordlg.cxx b/sc/source/ui/miscdlgs/tabbgcolordlg.cxx
new file mode 100644
index 000000000..7a346a4e3
--- /dev/null
+++ b/sc/source/ui/miscdlgs/tabbgcolordlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <tabbgcolordlg.hxx>
+
+#include <tools/color.hxx>
+#include <vcl/event.hxx>
+
+#include <officecfg/Office/Common.hxx>
+
+ScTabBgColorDlg::ScTabBgColorDlg(weld::Window* pParent, const OUString& rTitle,
+ const OUString& rTabBgColorNoColorText, const Color& rDefaultColor)
+ : GenericDialogController(pParent, "modules/scalc/ui/tabcolordialog.ui", "TabColorDialog")
+ , m_aTabBgColor(rDefaultColor)
+ , m_xSelectPalette(m_xBuilder->weld_combo_box("paletteselector"))
+ , m_xTabBgColorSet(new ScTabBgColorValueSet(m_xBuilder->weld_scrolled_window("colorsetwin", true)))
+ , m_xTabBgColorSetWin(new weld::CustomWeld(*m_xBuilder, "colorset", *m_xTabBgColorSet))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+{
+ m_xTabBgColorSet->SetDialog(this);
+ m_xTabBgColorSet->SetColCount(SvxColorValueSet::getColumnCount());
+
+ m_xDialog->set_title(rTitle);
+
+ const WinBits nBits(m_xTabBgColorSet->GetStyle() | WB_NAMEFIELD | WB_ITEMBORDER | WB_NONEFIELD | WB_3DLOOK | WB_NO_DIRECTSELECT);
+ m_xTabBgColorSet->SetStyle(nBits);
+ m_xTabBgColorSet->SetText(rTabBgColorNoColorText);
+
+ const sal_uInt32 nColCount = SvxColorValueSet::getColumnCount();
+ const sal_uInt32 nRowCount(10);
+ const sal_uInt32 nLength = SvxColorValueSet::getEntryEdgeLength();
+ Size aSize(m_xTabBgColorSet->CalcWindowSizePixel(Size(nLength, nLength), nColCount, nRowCount));
+ m_xTabBgColorSetWin->set_size_request(aSize.Width() + 8, aSize.Height() + 8);
+
+ FillPaletteLB();
+
+ m_xSelectPalette->connect_changed(LINK(this, ScTabBgColorDlg, SelectPaletteLBHdl));
+ m_xTabBgColorSet->SetDoubleClickHdl(LINK(this, ScTabBgColorDlg, TabBgColorDblClickHdl_Impl));
+ m_xBtnOk->connect_clicked(LINK(this, ScTabBgColorDlg, TabBgColorOKHdl_Impl));
+}
+
+ScTabBgColorDlg::~ScTabBgColorDlg()
+{
+}
+
+void ScTabBgColorDlg::GetSelectedColor( Color& rColor ) const
+{
+ rColor = m_aTabBgColor;
+}
+
+void ScTabBgColorDlg::FillPaletteLB()
+{
+ m_xSelectPalette->clear();
+ std::vector<OUString> aPaletteList = m_aPaletteManager.GetPaletteList();
+ for (auto const& palette : aPaletteList)
+ {
+ m_xSelectPalette->append_text(palette);
+ }
+ OUString aPaletteName( officecfg::Office::Common::UserColors::PaletteName::get() );
+ m_xSelectPalette->set_active_text(aPaletteName);
+ if (m_xSelectPalette->get_active() != -1)
+ {
+ SelectPaletteLBHdl(*m_xSelectPalette);
+ }
+}
+
+IMPL_LINK_NOARG(ScTabBgColorDlg, SelectPaletteLBHdl, weld::ComboBox&, void)
+{
+ m_xTabBgColorSet->Clear();
+ sal_Int32 nPos = m_xSelectPalette->get_active();
+ m_aPaletteManager.SetPalette( nPos );
+ m_aPaletteManager.ReloadColorSet(*m_xTabBgColorSet);
+ m_xTabBgColorSet->Resize();
+ m_xTabBgColorSet->SelectItem(0);
+}
+
+// Handler, called when color selection is changed
+IMPL_LINK_NOARG(ScTabBgColorDlg, TabBgColorDblClickHdl_Impl, ValueSet*, void)
+{
+ sal_uInt16 nItemId = m_xTabBgColorSet->GetSelectedItemId();
+ Color aColor = nItemId ? ( m_xTabBgColorSet->GetItemColor( nItemId ) ) : COL_AUTO;
+ m_aTabBgColor = aColor;
+ m_xDialog->response(RET_OK);
+}
+
+// Handler, called when the OK button is pushed
+IMPL_LINK_NOARG(ScTabBgColorDlg, TabBgColorOKHdl_Impl, weld::Button&, void)
+{
+ sal_uInt16 nItemId = m_xTabBgColorSet->GetSelectedItemId();
+ Color aColor = nItemId ? ( m_xTabBgColorSet->GetItemColor( nItemId ) ) : COL_AUTO;
+ m_aTabBgColor = aColor;
+ m_xDialog->response(RET_OK);
+}
+
+ScTabBgColorDlg::ScTabBgColorValueSet::ScTabBgColorValueSet(std::unique_ptr<weld::ScrolledWindow> pWindow)
+ : SvxColorValueSet(std::move(pWindow))
+ , m_pTabBgColorDlg(nullptr)
+{
+}
+
+ScTabBgColorDlg::ScTabBgColorValueSet::~ScTabBgColorValueSet()
+{
+}
+
+bool ScTabBgColorDlg::ScTabBgColorValueSet::KeyInput( const KeyEvent& rKEvt )
+{
+ switch ( rKEvt.GetKeyCode().GetCode() )
+ {
+ case KEY_SPACE:
+ case KEY_RETURN:
+ {
+ sal_uInt16 nItemId = GetSelectedItemId();
+ const Color& aColor = nItemId ? ( GetItemColor( nItemId ) ) : COL_AUTO;
+ m_pTabBgColorDlg->m_aTabBgColor = aColor;
+ m_pTabBgColorDlg->response(RET_OK);
+ return true;
+ }
+ break;
+ }
+ return SvxColorValueSet::KeyInput(rKEvt);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/tabopdlg.cxx b/sc/source/ui/miscdlgs/tabopdlg.cxx
new file mode 100644
index 000000000..7e9be6ea8
--- /dev/null
+++ b/sc/source/ui/miscdlgs/tabopdlg.cxx
@@ -0,0 +1,345 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+
+#include <uiitems.hxx>
+#include <document.hxx>
+#include <scresid.hxx>
+#include <sc.hrc>
+#include <strings.hrc>
+#include <reffact.hxx>
+
+#include <tabopdlg.hxx>
+
+
+ScTabOpDlg::ScTabOpDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScDocument* pDocument,
+ const ScRefAddress& rCursorPos )
+ : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/multipleoperationsdialog.ui",
+ "MultipleOperationsDialog")
+ , theFormulaCell(rCursorPos)
+ , pDoc(pDocument)
+ , nCurTab(theFormulaCell.Tab())
+ , bDlgLostFocus(false)
+ , errMsgNoFormula(ScResId(STR_NOFORMULASPECIFIED))
+ , errMsgNoColRow(ScResId(STR_NOCOLROW))
+ , errMsgWrongFormula(ScResId(STR_WRONGFORMULA))
+ , errMsgWrongRowCol(ScResId(STR_WRONGROWCOL))
+ , errMsgNoColFormula(ScResId(STR_NOCOLFORMULA))
+ , errMsgNoRowFormula(ScResId(STR_NOROWFORMULA))
+ , m_pEdActive(nullptr)
+ , m_xFtFormulaRange(m_xBuilder->weld_label("formulasft"))
+ , m_xEdFormulaRange(new formula::RefEdit(m_xBuilder->weld_entry("formulas")))
+ , m_xRBFormulaRange(new formula::RefButton(m_xBuilder->weld_button("formulasref")))
+ , m_xFtRowCell(m_xBuilder->weld_label("rowft"))
+ , m_xEdRowCell(new formula::RefEdit(m_xBuilder->weld_entry("row")))
+ , m_xRBRowCell(new formula::RefButton(m_xBuilder->weld_button("rowref")))
+ , m_xFtColCell(m_xBuilder->weld_label("colft"))
+ , m_xEdColCell(new formula::RefEdit(m_xBuilder->weld_entry("col")))
+ , m_xRBColCell(new formula::RefButton(m_xBuilder->weld_button("colref")))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+{
+ m_xEdFormulaRange->SetReferences(this, m_xFtFormulaRange.get());
+ m_xRBFormulaRange->SetReferences(this, m_xEdFormulaRange.get());
+
+ m_xEdRowCell->SetReferences(this, m_xFtRowCell.get());
+ m_xRBRowCell->SetReferences(this, m_xEdRowCell.get());
+
+ m_xEdColCell->SetReferences(this, m_xFtColCell.get());
+ m_xRBColCell->SetReferences(this, m_xEdColCell.get());
+
+ Init();
+}
+
+ScTabOpDlg::~ScTabOpDlg()
+{
+}
+
+void ScTabOpDlg::Init()
+{
+ m_xBtnOk->connect_clicked( LINK( this, ScTabOpDlg, BtnHdl ) );
+ m_xBtnCancel->connect_clicked( LINK( this, ScTabOpDlg, BtnHdl ) );
+
+ Link<formula::RefEdit&,void> aEditLink = LINK( this, ScTabOpDlg, GetEditFocusHdl );
+ m_xEdFormulaRange->SetGetFocusHdl( aEditLink );
+ m_xEdRowCell->SetGetFocusHdl( aEditLink );
+ m_xEdColCell->SetGetFocusHdl( aEditLink );
+
+ Link<formula::RefButton&,void> aButtonLink = LINK( this, ScTabOpDlg, GetButtonFocusHdl );
+ m_xRBFormulaRange->SetGetFocusHdl( aButtonLink );
+ m_xRBRowCell->SetGetFocusHdl( aButtonLink );
+ m_xRBColCell->SetGetFocusHdl( aButtonLink );
+
+ aEditLink = LINK( this, ScTabOpDlg, LoseEditFocusHdl );
+ m_xEdFormulaRange->SetLoseFocusHdl( aEditLink );
+ m_xEdRowCell->SetLoseFocusHdl( aEditLink );
+ m_xEdColCell->SetLoseFocusHdl( aEditLink );
+
+ aButtonLink = LINK( this, ScTabOpDlg, LoseButtonFocusHdl );
+ m_xRBFormulaRange->SetLoseFocusHdl( aButtonLink );
+ m_xRBRowCell->SetLoseFocusHdl( aButtonLink );
+ m_xRBColCell->SetLoseFocusHdl( aButtonLink );
+
+ m_xEdFormulaRange->GrabFocus();
+ m_pEdActive = m_xEdFormulaRange.get();
+}
+
+void ScTabOpDlg::Close()
+{
+ DoClose( ScTabOpDlgWrapper::GetChildWindowId() );
+}
+
+void ScTabOpDlg::SetActive()
+{
+ if ( bDlgLostFocus )
+ {
+ bDlgLostFocus = false;
+ if (m_pEdActive)
+ m_pEdActive->GrabFocus();
+ }
+ else
+ m_xDialog->grab_focus();
+
+ RefInputDone();
+}
+
+void ScTabOpDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
+{
+ if (!m_pEdActive)
+ return;
+
+ ScAddress::Details aDetails(rDocP.GetAddressConvention(), 0, 0);
+
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart(m_pEdActive);
+
+ OUString aStr;
+ ScRefFlags nFmt = ( rRef.aStart.Tab() == nCurTab )
+ ? ScRefFlags::RANGE_ABS
+ : ScRefFlags::RANGE_ABS_3D;
+
+ if (m_pEdActive == m_xEdFormulaRange.get())
+ {
+ theFormulaCell.Set( rRef.aStart, false, false, false);
+ theFormulaEnd.Set( rRef.aEnd, false, false, false);
+ aStr = rRef.Format(rDocP, nFmt, aDetails);
+ }
+ else if (m_pEdActive == m_xEdRowCell.get())
+ {
+ theRowCell.Set( rRef.aStart, false, false, false);
+ aStr = rRef.aStart.Format(nFmt, &rDocP, aDetails);
+ }
+ else if (m_pEdActive == m_xEdColCell.get())
+ {
+ theColCell.Set( rRef.aStart, false, false, false);
+ aStr = rRef.aStart.Format(nFmt, &rDocP, aDetails);
+ }
+
+ m_pEdActive->SetRefString( aStr );
+}
+
+void ScTabOpDlg::RaiseError( ScTabOpErr eError )
+{
+ const OUString* pMsg = &errMsgNoFormula;
+ formula::RefEdit* pEd = m_xEdFormulaRange.get();
+
+ switch ( eError )
+ {
+ case TABOPERR_NOFORMULA:
+ pMsg = &errMsgNoFormula;
+ pEd = m_xEdFormulaRange.get();
+ break;
+
+ case TABOPERR_NOCOLROW:
+ pMsg = &errMsgNoColRow;
+ pEd = m_xEdRowCell.get();
+ break;
+
+ case TABOPERR_WRONGFORMULA:
+ pMsg = &errMsgWrongFormula;
+ pEd = m_xEdFormulaRange.get();
+ break;
+
+ case TABOPERR_WRONGROW:
+ pMsg = &errMsgWrongRowCol;
+ pEd = m_xEdRowCell.get();
+ break;
+
+ case TABOPERR_NOCOLFORMULA:
+ pMsg = &errMsgNoColFormula;
+ pEd = m_xEdFormulaRange.get();
+ break;
+
+ case TABOPERR_WRONGCOL:
+ pMsg = &errMsgWrongRowCol;
+ pEd = m_xEdColCell.get();
+ break;
+
+ case TABOPERR_NOROWFORMULA:
+ pMsg = &errMsgNoRowFormula;
+ pEd = m_xEdFormulaRange.get();
+ break;
+ }
+
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xDialog.get(),
+ VclMessageType::Error, VclButtonsType::OkCancel, *pMsg));
+ xBox->run();
+ pEd->GrabFocus();
+}
+
+static bool lcl_Parse( const OUString& rString, const ScDocument& rDoc, SCTAB nCurTab,
+ ScRefAddress& rStart, ScRefAddress& rEnd )
+{
+ bool bRet = false;
+ const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
+ if ( rString.indexOf(':') != -1 )
+ bRet = ConvertDoubleRef( rDoc, rString, nCurTab, rStart, rEnd, eConv );
+ else
+ {
+ bRet = ConvertSingleRef( rDoc, rString, nCurTab, rStart, eConv );
+ rEnd = rStart;
+ }
+ return bRet;
+}
+
+// Handler:
+
+IMPL_LINK(ScTabOpDlg, BtnHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == m_xBtnOk.get())
+ {
+ ScTabOpParam::Mode eMode = ScTabOpParam::Column;
+ sal_uInt16 nError = 0;
+
+ // The following code checks:
+ // 1. do the strings contain correct cell references / defined names?
+ // 2. is formula range row if row is empty or column if column is empty
+ // or single reference if both?
+ // 3. is at least one of row or column non-empty?
+
+ if (m_xEdFormulaRange->GetText().isEmpty())
+ nError = TABOPERR_NOFORMULA;
+ else if (m_xEdRowCell->GetText().isEmpty() &&
+ m_xEdColCell->GetText().isEmpty())
+ nError = TABOPERR_NOCOLROW;
+ else if ( !lcl_Parse( m_xEdFormulaRange->GetText(), *pDoc, nCurTab,
+ theFormulaCell, theFormulaEnd ) )
+ nError = TABOPERR_WRONGFORMULA;
+ else
+ {
+ const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
+ if (!m_xEdRowCell->GetText().isEmpty())
+ {
+ if (!ConvertSingleRef( *pDoc, m_xEdRowCell->GetText(), nCurTab,
+ theRowCell, eConv ))
+ nError = TABOPERR_WRONGROW;
+ else
+ {
+ if (m_xEdColCell->GetText().isEmpty() &&
+ theFormulaCell.Col() != theFormulaEnd.Col())
+ nError = TABOPERR_NOCOLFORMULA;
+ else
+ eMode = ScTabOpParam::Row;
+ }
+ }
+ if (!m_xEdColCell->GetText().isEmpty())
+ {
+ if (!ConvertSingleRef( *pDoc, m_xEdColCell->GetText(), nCurTab,
+ theColCell, eConv ))
+ nError = TABOPERR_WRONGCOL;
+ else
+ {
+ if (eMode == ScTabOpParam::Row) // both
+ {
+ eMode = ScTabOpParam::Both;
+ ConvertSingleRef( *pDoc, m_xEdFormulaRange->GetText(), nCurTab,
+ theFormulaCell, eConv );
+ }
+ else if (theFormulaCell.Row() != theFormulaEnd.Row())
+ nError = TABOPERR_NOROWFORMULA;
+ else
+ eMode = ScTabOpParam::Column;
+ }
+ }
+ }
+
+ if (nError)
+ RaiseError( static_cast<ScTabOpErr>(nError) );
+ else
+ {
+ ScTabOpParam aOutParam(theFormulaCell, theFormulaEnd, theRowCell, theColCell, eMode);
+ ScTabOpItem aOutItem( SID_TABOP, &aOutParam );
+
+ SetDispatcherLock( false );
+ SwitchToDocument();
+ GetBindings().GetDispatcher()->ExecuteList(SID_TABOP,
+ SfxCallMode::SLOT | SfxCallMode::RECORD,
+ { &aOutItem });
+ response(RET_OK);
+ }
+ }
+ else if (&rBtn == m_xBtnCancel.get())
+ response(RET_CANCEL);
+}
+
+IMPL_LINK( ScTabOpDlg, GetEditFocusHdl, formula::RefEdit&, rCtrl, void )
+{
+ if (&rCtrl == m_xEdFormulaRange.get())
+ m_pEdActive = m_xEdFormulaRange.get();
+ else if (&rCtrl == m_xEdRowCell.get())
+ m_pEdActive = m_xEdRowCell.get();
+ else if (&rCtrl == m_xEdColCell.get())
+ m_pEdActive = m_xEdColCell.get();
+ else
+ m_pEdActive = nullptr;
+
+ if( m_pEdActive )
+ m_pEdActive->SelectAll();
+}
+
+IMPL_LINK( ScTabOpDlg, GetButtonFocusHdl, formula::RefButton&, rCtrl, void )
+{
+ if (&rCtrl == m_xRBFormulaRange.get())
+ m_pEdActive = m_xEdFormulaRange.get();
+ else if (&rCtrl == m_xRBRowCell.get())
+ m_pEdActive = m_xEdRowCell.get();
+ else if (&rCtrl == m_xRBColCell.get())
+ m_pEdActive = m_xEdColCell.get();
+ else
+ m_pEdActive = nullptr;
+
+ if( m_pEdActive )
+ m_pEdActive->SelectAll();
+}
+
+IMPL_LINK_NOARG(ScTabOpDlg, LoseEditFocusHdl, formula::RefEdit&, void)
+{
+ bDlgLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+IMPL_LINK_NOARG(ScTabOpDlg, LoseButtonFocusHdl, formula::RefButton&, void)
+{
+ bDlgLostFocus = !m_xDialog->has_toplevel_focus();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/textdlgs.cxx b/sc/source/ui/miscdlgs/textdlgs.cxx
new file mode 100644
index 000000000..40a84a626
--- /dev/null
+++ b/sc/source/ui/miscdlgs/textdlgs.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <svx/svxids.hrc>
+#include <svx/dialogs.hrc>
+
+#include <editeng/flstitem.hxx>
+#include <sfx2/objsh.hxx>
+#include <svl/cjkoptions.hxx>
+
+#include <textdlgs.hxx>
+#include <svl/intitem.hxx>
+#include <svx/flagsdef.hxx>
+
+ScCharDlg::ScCharDlg(weld::Window* pParent, const SfxItemSet* pAttr, const SfxObjectShell* pDocShell, bool bDrawText)
+ : SfxTabDialogController(pParent, "modules/scalc/ui/chardialog.ui", "CharDialog", pAttr)
+ , rDocShell(*pDocShell)
+{
+ AddTabPage("font", RID_SVXPAGE_CHAR_NAME);
+ AddTabPage("fonteffects", RID_SVXPAGE_CHAR_EFFECTS);
+ AddTabPage("position", RID_SVXPAGE_CHAR_POSITION);
+
+ if (bDrawText)
+ AddTabPage("background", RID_SVXPAGE_BKG);
+ else
+ RemoveTabPage("background");
+}
+
+void ScCharDlg::PageCreated(const OString& rId, SfxTabPage &rPage)
+{
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ 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 == "fonteffects")
+ {
+ aSet.Put (SfxUInt16Item(SID_DISABLE_CTL,DISABLE_CASEMAP));
+ rPage.PageCreated(aSet);
+ }
+ else if (rId == "background")
+ {
+ aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, static_cast<sal_uInt32>(SvxBackgroundTabFlags::SHOW_CHAR_BKGCOLOR)));
+ rPage.PageCreated(aSet);
+ }
+}
+
+ScParagraphDlg::ScParagraphDlg(weld::Window* pParent, const SfxItemSet* pAttr)
+ : SfxTabDialogController(pParent, "modules/scalc/ui/paradialog.ui", "ParagraphDialog", pAttr)
+{
+ AddTabPage("labelTP_PARA_STD", RID_SVXPAGE_STD_PARAGRAPH);
+ AddTabPage("labelTP_PARA_ALIGN", RID_SVXPAGE_ALIGN_PARAGRAPH);
+ if (SvtCJKOptions::IsAsianTypographyEnabled() )
+ AddTabPage("labelTP_PARA_ASIAN", RID_SVXPAGE_PARA_ASIAN);
+ else
+ RemoveTabPage("labelTP_PARA_ASIAN");
+ AddTabPage("labelTP_TABULATOR", RID_SVXPAGE_TABULATOR);
+}
+
+void ScParagraphDlg::PageCreated(const OString& rId, SfxTabPage &rPage)
+{
+ if (rId == "labelTP_TABULATOR")
+ {
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ TabulatorDisableFlags const nFlags((TabulatorDisableFlags::TypeMask &~TabulatorDisableFlags::TypeLeft) |
+ (TabulatorDisableFlags::FillMask &~TabulatorDisableFlags::FillNone));
+ aSet.Put(SfxUInt16Item(SID_SVXTABULATORTABPAGE_DISABLEFLAGS, static_cast<sal_uInt16>(nFlags)));
+ rPage.PageCreated(aSet);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/miscdlgs/warnbox.cxx b/sc/source/ui/miscdlgs/warnbox.cxx
new file mode 100644
index 000000000..8bb0a37d1
--- /dev/null
+++ b/sc/source/ui/miscdlgs/warnbox.cxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <warnbox.hxx>
+
+#include <scmod.hxx>
+#include <inputopt.hxx>
+
+ScReplaceWarnBox::ScReplaceWarnBox(weld::Window* pParent)
+ : MessageDialogController(pParent, "modules/scalc/ui/checkwarningdialog.ui",
+ "CheckWarningDialog", "ask")
+ // By default, the check box is ON, and the user needs to un-check it to
+ // disable all future warnings.
+ , m_xWarningOnBox(m_xBuilder->weld_check_button("ask"))
+{
+ m_xDialog->set_default_response(RET_YES);
+}
+
+short ScReplaceWarnBox::run()
+{
+ short nRet = RET_YES;
+ if (SC_MOD()->GetInputOptions().GetReplaceCellsWarn())
+ {
+ nRet = MessageDialogController::run();
+ if (!m_xWarningOnBox->get_active())
+ {
+ ScModule* pScMod = SC_MOD();
+ ScInputOptions aInputOpt(pScMod->GetInputOptions());
+ aInputOpt.SetReplaceCellsWarn(false);
+ pScMod->SetInputOptions(aInputOpt);
+ }
+ }
+ return nRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/namedlg/namedefdlg.cxx b/sc/source/ui/namedlg/namedefdlg.cxx
new file mode 100644
index 000000000..97988e390
--- /dev/null
+++ b/sc/source/ui/namedlg/namedefdlg.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/.
+ */
+
+#include <namedefdlg.hxx>
+
+#include <formula/errorcodes.hxx>
+#include <sfx2/app.hxx>
+#include <unotools/charclass.hxx>
+
+#include <compiler.hxx>
+#include <document.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <globalnames.hxx>
+#include <rangenam.hxx>
+#include <reffact.hxx>
+#include <undorangename.hxx>
+#include <tabvwsh.hxx>
+#include <tokenarray.hxx>
+
+ScNameDefDlg::ScNameDefDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ const ScViewData& rViewData, std::map<OUString, ScRangeName*>&& aRangeMap,
+ const ScAddress& aCursorPos, const bool bUndo )
+ : ScAnyRefDlgController( pB, pCW, pParent, "modules/scalc/ui/definename.ui", "DefineNameDialog")
+ , mbUndo( bUndo )
+ , mrDoc(rViewData.GetDocument())
+ , mpDocShell ( rViewData.GetDocShell() )
+ , maCursorPos( aCursorPos )
+ , maGlobalNameStr ( ScResId(STR_GLOBAL_SCOPE) )
+ , maErrInvalidNameStr( ScResId(STR_ERR_NAME_INVALID))
+ , maErrInvalidNameCellRefStr( ScResId(STR_ERR_NAME_INVALID_CELL_REF))
+ , maErrNameInUse ( ScResId(STR_ERR_NAME_EXISTS))
+ , maRangeMap( std::move(aRangeMap) )
+ , m_xEdName(m_xBuilder->weld_entry("edit"))
+ , m_xEdRange(new formula::RefEdit(m_xBuilder->weld_entry("range")))
+ , m_xRbRange(new formula::RefButton(m_xBuilder->weld_button("refbutton")))
+ , m_xLbScope(m_xBuilder->weld_combo_box("scope"))
+ , m_xBtnRowHeader(m_xBuilder->weld_check_button("rowheader"))
+ , m_xBtnColHeader(m_xBuilder->weld_check_button("colheader"))
+ , m_xBtnPrintArea(m_xBuilder->weld_check_button("printarea"))
+ , m_xBtnCriteria(m_xBuilder->weld_check_button("filter"))
+ , m_xBtnAdd(m_xBuilder->weld_button("add"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_xFtInfo(m_xBuilder->weld_label("label"))
+ , m_xExpander(m_xBuilder->weld_expander("more"))
+ , m_xFtRange(m_xBuilder->weld_label("label3"))
+{
+ m_xEdRange->SetReferences(this, m_xFtRange.get());
+ m_xRbRange->SetReferences(this, m_xEdRange.get());
+ maStrInfoDefault = m_xFtInfo->get_label();
+
+ // Initialize scope list.
+ m_xLbScope->append_text(maGlobalNameStr);
+ m_xLbScope->set_active(0);
+ SCTAB n = mrDoc.GetTableCount();
+ for (SCTAB i = 0; i < n; ++i)
+ {
+ OUString aTabName;
+ mrDoc.GetName(i, aTabName);
+ m_xLbScope->append_text(aTabName);
+ }
+
+ m_xBtnCancel->connect_clicked( LINK( this, ScNameDefDlg, CancelBtnHdl));
+ m_xBtnAdd->connect_clicked( LINK( this, ScNameDefDlg, AddBtnHdl ));
+ m_xEdName->connect_changed( LINK( this, ScNameDefDlg, NameModifyHdl ));
+ m_xEdRange->SetGetFocusHdl( LINK( this, ScNameDefDlg, AssignGetFocusHdl ) );
+
+ m_xBtnAdd->set_sensitive(false); // empty name is invalid
+
+ ScRange aRange;
+
+ rViewData.GetSimpleArea( aRange );
+ OUString aAreaStr(aRange.Format(mrDoc, ScRefFlags::RANGE_ABS_3D,
+ ScAddress::Details(mrDoc.GetAddressConvention(), 0, 0)));
+
+ m_xEdRange->SetText( aAreaStr );
+
+ m_xEdName->grab_focus();
+ m_xEdName->select_region(0, -1);
+}
+
+ScNameDefDlg::~ScNameDefDlg()
+{
+}
+
+void ScNameDefDlg::CancelPushed()
+{
+ if (mbUndo)
+ response(RET_CANCEL);
+ else
+ {
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ pViewSh->SwitchBetweenRefDialogs(this);
+ }
+}
+
+bool ScNameDefDlg::IsFormulaValid()
+{
+ ScCompiler aComp(mrDoc, maCursorPos, mrDoc.GetGrammar());
+ std::unique_ptr<ScTokenArray> pCode = aComp.CompileString(m_xEdRange->GetText());
+ if (pCode->GetCodeError() != FormulaError::NONE)
+ {
+ //TODO: info message
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+bool ScNameDefDlg::IsNameValid()
+{
+ OUString aScope = m_xLbScope->get_active_text();
+ OUString aName = m_xEdName->get_text();
+
+ bool bIsNameValid = true;
+ OUString aHelpText = maStrInfoDefault;
+
+ ScRangeName* pRangeName = nullptr;
+ if(aScope == maGlobalNameStr)
+ {
+ pRangeName = maRangeMap.find(OUString(STR_GLOBAL_RANGE_NAME))->second;
+ }
+ else
+ {
+ pRangeName = maRangeMap.find(aScope)->second;
+ }
+
+ ScRangeData::IsNameValidType eType;
+ if ( aName.isEmpty() )
+ {
+ bIsNameValid = false;
+ }
+ else if ((eType = ScRangeData::IsNameValid(aName, mrDoc))
+ != ScRangeData::IsNameValidType::NAME_VALID)
+ {
+ if (eType == ScRangeData::IsNameValidType::NAME_INVALID_BAD_STRING)
+ {
+ aHelpText = maErrInvalidNameStr;
+ }
+ else if (eType == ScRangeData::IsNameValidType::NAME_INVALID_CELL_REF)
+ {
+ aHelpText = maErrInvalidNameCellRefStr;
+ }
+ bIsNameValid = false;
+ }
+ else if (pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(aName)))
+ {
+ aHelpText = maErrNameInUse;
+ bIsNameValid = false;
+ }
+
+ if (!IsFormulaValid())
+ {
+ bIsNameValid = false;
+ }
+
+ m_xEdName->set_tooltip_text(aHelpText);
+ m_xEdName->set_message_type(bIsNameValid || aName.isEmpty() ? weld::EntryMessageType::Normal
+ : weld::EntryMessageType::Error);
+ m_xBtnAdd->set_sensitive(bIsNameValid);
+ return bIsNameValid;
+}
+
+void ScNameDefDlg::AddPushed()
+{
+ OUString aScope = m_xLbScope->get_active_text();
+ OUString aName = m_xEdName->get_text();
+ OUString aExpression = m_xEdRange->GetText();
+
+ if (aName.isEmpty())
+ {
+ return;
+ }
+ if (aScope.isEmpty())
+ {
+ return;
+ }
+
+ ScRangeName* pRangeName = nullptr;
+ if(aScope == maGlobalNameStr)
+ {
+ pRangeName = maRangeMap.find(OUString(STR_GLOBAL_RANGE_NAME))->second;
+ }
+ else
+ {
+ pRangeName = maRangeMap.find(aScope)->second;
+ }
+ if (!pRangeName)
+ return;
+
+ if (!IsNameValid()) //should not happen, but make sure we don't break anything
+ return;
+ else
+ {
+ ScRangeData::Type nType = ScRangeData::Type::Name;
+
+ ScRangeData* pNewEntry = new ScRangeData( mrDoc,
+ aName,
+ aExpression,
+ maCursorPos,
+ nType );
+
+ if ( m_xBtnRowHeader->get_active() ) nType |= ScRangeData::Type::RowHeader;
+ if ( m_xBtnColHeader->get_active() ) nType |= ScRangeData::Type::ColHeader;
+ if ( m_xBtnPrintArea->get_active() ) nType |= ScRangeData::Type::PrintArea;
+ if ( m_xBtnCriteria->get_active() ) nType |= ScRangeData::Type::Criteria;
+
+ pNewEntry->AddType(nType);
+
+ // aExpression valid?
+ if ( FormulaError::NONE == pNewEntry->GetErrCode() )
+ {
+ if ( !pRangeName->insert( pNewEntry, false /*bReuseFreeIndex*/ ) )
+ pNewEntry = nullptr;
+
+ if (mbUndo)
+ {
+ // this means we called directly through the menu
+
+ SCTAB nTab;
+ // if no table with that name is found, assume global range name
+ if (!mrDoc.GetTable(aScope, nTab))
+ nTab = -1;
+
+ assert( pNewEntry); // undo of no insertion smells fishy
+ if (pNewEntry)
+ mpDocShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAddRangeData>( mpDocShell, pNewEntry, nTab) );
+
+ // set table stream invalid, otherwise RangeName won't be saved if no other
+ // call invalidates the stream
+ if (nTab != -1)
+ mrDoc.SetStreamValid(nTab, false);
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+ mpDocShell->SetDocumentModified();
+ Close();
+ }
+ else
+ {
+ maName = aName;
+ maScope = aScope;
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ pViewSh->SwitchBetweenRefDialogs(this);
+ }
+ }
+ else
+ {
+ delete pNewEntry;
+ m_xEdRange->GrabFocus();
+ m_xEdRange->SelectAll();
+ }
+ }
+}
+
+void ScNameDefDlg::GetNewData(OUString& rName, OUString& rScope)
+{
+ rName = maName;
+ rScope = maScope;
+}
+
+bool ScNameDefDlg::IsRefInputMode() const
+{
+ return m_xEdRange->GetWidget()->get_sensitive();
+}
+
+void ScNameDefDlg::RefInputDone( bool bForced)
+{
+ ScAnyRefDlgController::RefInputDone(bForced);
+ IsNameValid();
+}
+
+void ScNameDefDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
+{
+ if (m_xEdRange->GetWidget()->get_sensitive())
+ {
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart(m_xEdRange.get());
+ OUString aRefStr(rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D,
+ ScAddress::Details(rDocP.GetAddressConvention(), 0, 0)));
+ m_xEdRange->SetRefString( aRefStr );
+ }
+}
+
+void ScNameDefDlg::Close()
+{
+ DoClose( ScNameDefDlgWrapper::GetChildWindowId() );
+}
+
+void ScNameDefDlg::SetActive()
+{
+ m_xEdRange->GrabFocus();
+ RefInputDone();
+}
+
+IMPL_LINK_NOARG(ScNameDefDlg, CancelBtnHdl, weld::Button&, void)
+{
+ CancelPushed();
+}
+
+IMPL_LINK_NOARG(ScNameDefDlg, AddBtnHdl, weld::Button&, void)
+{
+ AddPushed();
+};
+
+IMPL_LINK_NOARG(ScNameDefDlg, NameModifyHdl, weld::Entry&, void)
+{
+ IsNameValid();
+}
+
+IMPL_LINK_NOARG(ScNameDefDlg, AssignGetFocusHdl, formula::RefEdit&, void)
+{
+ IsNameValid();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/namedlg/namedlg.cxx b/sc/source/ui/namedlg/namedlg.cxx
new file mode 100644
index 000000000..05094b810
--- /dev/null
+++ b/sc/source/ui/namedlg/namedlg.cxx
@@ -0,0 +1,505 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <global.hxx>
+#include <reffact.hxx>
+#include <compiler.hxx>
+#include <document.hxx>
+#include <docfunc.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <namedlg.hxx>
+#include <viewdata.hxx>
+#include <tabvwsh.hxx>
+
+#include <globalnames.hxx>
+#include <tokenarray.hxx>
+
+#include <vcl/svapp.hxx>
+#include <formula/errorcodes.hxx>
+#include <unotools/charclass.hxx>
+
+#include <map>
+
+//logic
+
+ScNameDlg::ScNameDlg( SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent,
+ ScViewData& rViewData,
+ const ScAddress& aCursorPos,
+ std::map<OUString, std::unique_ptr<ScRangeName>> *const pRangeMap)
+ : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/managenamesdialog.ui",
+ "ManageNamesDialog")
+
+ , maGlobalNameStr(ScResId(STR_GLOBAL_SCOPE))
+ , maErrInvalidNameStr(ScResId(STR_ERR_NAME_INVALID))
+ , maErrNameInUse(ScResId(STR_ERR_NAME_EXISTS))
+ , maStrMultiSelect(ScResId(STR_MULTI_SELECT))
+
+ , mrViewData(rViewData)
+ , mrDoc(rViewData.GetDocument())
+ , maCursorPos(aCursorPos)
+ , mbDataChanged(false)
+ , mbCloseWithoutUndo(false)
+
+ , m_xEdName(m_xBuilder->weld_entry("name"))
+ , m_xFtAssign(m_xBuilder->weld_label("label3"))
+ , m_xEdAssign(new formula::RefEdit(m_xBuilder->weld_entry("range")))
+ , m_xRbAssign(new formula::RefButton(m_xBuilder->weld_button("assign")))
+ , m_xLbScope(m_xBuilder->weld_combo_box("scope"))
+ , m_xBtnPrintArea(m_xBuilder->weld_check_button("printrange"))
+ , m_xBtnColHeader(m_xBuilder->weld_check_button("colheader"))
+ , m_xBtnCriteria(m_xBuilder->weld_check_button("filter"))
+ , m_xBtnRowHeader(m_xBuilder->weld_check_button("rowheader"))
+ , m_xBtnAdd(m_xBuilder->weld_button("add"))
+ , m_xBtnDelete(m_xBuilder->weld_button("delete"))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_xFtInfo(m_xBuilder->weld_label("info"))
+ , m_xExpander(m_xBuilder->weld_expander("more"))
+{
+ m_xEdAssign->SetReferences(this, m_xFtAssign.get());
+ m_xRbAssign->SetReferences(this, m_xEdAssign.get());
+ maStrInfoDefault = m_xFtInfo->get_label();
+
+ if (!pRangeMap)
+ {
+ std::map<OUString, ScRangeName*> aRangeMap;
+ mrDoc.GetRangeNameMap(aRangeMap);
+ for (const auto& [aTemp, pRangeName] : aRangeMap)
+ {
+ m_RangeMap.insert(std::make_pair(aTemp, std::make_unique<ScRangeName>(*pRangeName)));
+ }
+ }
+ else
+ {
+ m_RangeMap.swap(*pRangeMap);
+ }
+ Init();
+}
+
+ScNameDlg::~ScNameDlg()
+{
+}
+
+void ScNameDlg::Init()
+{
+ //init UI
+
+ std::unique_ptr<weld::TreeView> xTreeView(m_xBuilder->weld_tree_view("names"));
+ xTreeView->set_size_request(xTreeView->get_approximate_digit_width() * 75,
+ xTreeView->get_height_rows(10));
+ m_xRangeManagerTable.reset(new ScRangeManagerTable(std::move(xTreeView), m_RangeMap, maCursorPos));
+
+ m_xRangeManagerTable->connect_changed( LINK( this, ScNameDlg, SelectionChangedHdl_Impl ) );
+
+ m_xBtnOk->connect_clicked( LINK( this, ScNameDlg, OkBtnHdl ) );
+ m_xBtnCancel->connect_clicked( LINK( this, ScNameDlg, CancelBtnHdl ) );
+ m_xBtnAdd->connect_clicked( LINK( this, ScNameDlg, AddBtnHdl ) );
+ m_xEdAssign->SetGetFocusHdl( LINK( this, ScNameDlg, AssignGetFocusHdl ) );
+ m_xEdAssign->SetModifyHdl ( LINK( this, ScNameDlg, RefEdModifyHdl ) );
+ m_xEdName->connect_changed( LINK( this, ScNameDlg, EdModifyHdl ) );
+ m_xLbScope->connect_changed( LINK(this, ScNameDlg, ScopeChangedHdl) );
+ m_xBtnDelete->connect_clicked( LINK( this, ScNameDlg, RemoveBtnHdl ) );
+ m_xBtnPrintArea->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
+ m_xBtnCriteria->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
+ m_xBtnRowHeader->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
+ m_xBtnColHeader->connect_toggled( LINK(this, ScNameDlg, EdModifyCheckBoxHdl ) );
+
+ // Initialize scope list.
+ m_xLbScope->append_text(maGlobalNameStr);
+ m_xLbScope->set_active(0);
+ SCTAB n = mrDoc.GetTableCount();
+ for (SCTAB i = 0; i < n; ++i)
+ {
+ OUString aTabName;
+ mrDoc.GetName(i, aTabName);
+ m_xLbScope->append_text(aTabName);
+ }
+
+ CheckForEmptyTable();
+
+ if (m_xRangeManagerTable->n_children())
+ {
+ m_xRangeManagerTable->set_cursor(0);
+ m_xRangeManagerTable->CheckForFormulaString();
+ SelectionChanged();
+ }
+
+}
+
+bool ScNameDlg::IsRefInputMode() const
+{
+ return m_xEdAssign->GetWidget()->get_sensitive();
+}
+
+void ScNameDlg::RefInputDone( bool bForced)
+{
+ ScAnyRefDlgController::RefInputDone(bForced);
+ RefEdModifyHdl(*m_xEdAssign);
+}
+
+void ScNameDlg::SetReference( const ScRange& rRef, ScDocument& rDocP )
+{
+ if (m_xEdAssign->GetWidget()->get_sensitive())
+ {
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart(m_xEdAssign.get());
+ OUString aRefStr(rRef.Format(rDocP, ScRefFlags::RANGE_ABS_3D,
+ ScAddress::Details(rDocP.GetAddressConvention(), 0, 0)));
+ m_xEdAssign->SetRefString( aRefStr );
+ }
+}
+
+void ScNameDlg::Close()
+{
+ if (mbDataChanged && !mbCloseWithoutUndo)
+ mrViewData.GetDocFunc().ModifyAllRangeNames(m_RangeMap);
+ DoClose(ScNameDlgWrapper::GetChildWindowId());
+}
+
+void ScNameDlg::CheckForEmptyTable()
+{
+ if (!m_xRangeManagerTable->n_children())
+ {
+ m_xBtnDelete->set_sensitive(false);
+ m_xEdAssign->GetWidget()->set_sensitive(false);
+ m_xRbAssign->GetWidget()->set_sensitive(false);
+ m_xEdName->set_sensitive(false);
+ m_xLbScope->set_sensitive(false);
+
+ m_xBtnCriteria->set_sensitive(false);
+ m_xBtnPrintArea->set_sensitive(false);
+ m_xBtnColHeader->set_sensitive(false);
+ m_xBtnRowHeader->set_sensitive(false);
+ }
+ else
+ {
+ m_xBtnDelete->set_sensitive(true);
+ m_xEdAssign->GetWidget()->set_sensitive(true);
+ m_xRbAssign->GetWidget()->set_sensitive(true);
+ m_xEdName->set_sensitive(true);
+ m_xLbScope->set_sensitive(true);
+
+ m_xBtnCriteria->set_sensitive(true);
+ m_xBtnPrintArea->set_sensitive(true);
+ m_xBtnColHeader->set_sensitive(true);
+ m_xBtnRowHeader->set_sensitive(true);
+ }
+}
+
+void ScNameDlg::SetActive()
+{
+ m_xEdAssign->GrabFocus();
+ RefInputDone();
+}
+
+void ScNameDlg::UpdateChecks(const ScRangeData* pData)
+{
+ // remove handlers, we only want the handlers to process
+ // user input and not when we are syncing the controls with our internal
+ // model ( also UpdateChecks is called already from some other event
+ // handlers, triggering handlers while already processing a handler can
+ // ( and does in this case ) corrupt the internal data
+
+ m_xBtnCriteria->connect_toggled( Link<weld::Toggleable&,void>() );
+ m_xBtnPrintArea->connect_toggled( Link<weld::Toggleable&,void>() );
+ m_xBtnColHeader->connect_toggled( Link<weld::Toggleable&,void>() );
+ m_xBtnRowHeader->connect_toggled( Link<weld::Toggleable&,void>() );
+
+ m_xBtnCriteria->set_active( pData->HasType( ScRangeData::Type::Criteria ) );
+ m_xBtnPrintArea->set_active( pData->HasType( ScRangeData::Type::PrintArea ) );
+ m_xBtnColHeader->set_active( pData->HasType( ScRangeData::Type::ColHeader ) );
+ m_xBtnRowHeader->set_active( pData->HasType( ScRangeData::Type::RowHeader ) );
+
+ // Restore handlers so user input is processed again
+ Link<weld::Toggleable&,void> aToggleHandler = LINK( this, ScNameDlg, EdModifyCheckBoxHdl );
+ m_xBtnCriteria->connect_toggled( aToggleHandler );
+ m_xBtnPrintArea->connect_toggled( aToggleHandler );
+ m_xBtnColHeader->connect_toggled( aToggleHandler );
+ m_xBtnRowHeader->connect_toggled( aToggleHandler );
+}
+
+bool ScNameDlg::IsNameValid()
+{
+ OUString aScope = m_xLbScope->get_active_text();
+ OUString aName = m_xEdName->get_text();
+ aName = aName.trim();
+
+ if (aName.isEmpty())
+ return false;
+
+ ScRangeName* pRangeName = GetRangeName( aScope );
+
+ if (ScRangeData::IsNameValid(aName, mrDoc) != ScRangeData::IsNameValidType::NAME_VALID)
+ {
+ m_xFtInfo->set_label_type(weld::LabelType::Error);
+ m_xFtInfo->set_label(maErrInvalidNameStr);
+ return false;
+ }
+ else if (pRangeName && pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(aName)))
+ {
+ m_xFtInfo->set_label_type(weld::LabelType::Error);
+ m_xFtInfo->set_label(maErrNameInUse);
+ return false;
+ }
+ m_xFtInfo->set_label( maStrInfoDefault );
+ return true;
+}
+
+bool ScNameDlg::IsFormulaValid()
+{
+ ScCompiler aComp(mrDoc, maCursorPos, mrDoc.GetGrammar());
+ std::unique_ptr<ScTokenArray> pCode = aComp.CompileString(m_xEdAssign->GetText());
+ if (pCode->GetCodeError() != FormulaError::NONE)
+ {
+ m_xFtInfo->set_label_type(weld::LabelType::Error);
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+}
+
+ScRangeName* ScNameDlg::GetRangeName(const OUString& rScope)
+{
+ if (rScope == maGlobalNameStr)
+ return m_RangeMap.find(OUString(STR_GLOBAL_RANGE_NAME))->second.get();
+ else
+ return m_RangeMap.find(rScope)->second.get();
+}
+
+void ScNameDlg::ShowOptions(const ScRangeNameLine& rLine)
+{
+ ScRangeName* pRangeName = GetRangeName(rLine.aScope);
+ ScRangeData* pData = pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(rLine.aName));
+ if (pData)
+ {
+ UpdateChecks(pData);
+ }
+}
+
+void ScNameDlg::AddPushed()
+{
+ mbCloseWithoutUndo = true;
+ ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell();
+ pViewSh->SwitchBetweenRefDialogs(this);
+}
+
+void ScNameDlg::SetEntry(const OUString& rName, const OUString& rScope)
+{
+ if (!rName.isEmpty())
+ {
+ mbDataChanged = true;
+ ScRangeNameLine aLine;
+ aLine.aName = rName;
+ aLine.aScope = rScope;
+ m_xRangeManagerTable->SetEntry(aLine);
+ }
+}
+
+void ScNameDlg::RemovePushed()
+{
+ std::vector<ScRangeNameLine> aEntries = m_xRangeManagerTable->GetSelectedEntries();
+ m_xRangeManagerTable->DeleteSelectedEntries();
+ for (const auto& rEntry : aEntries)
+ {
+ ScRangeName* pRangeName = GetRangeName(rEntry.aScope);
+ ScRangeData* pData = pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(rEntry.aName));
+ OSL_ENSURE(pData, "table and model should be in sync");
+ // be safe and check for possible problems
+ if (pData)
+ pRangeName->erase(*pData);
+
+ mbDataChanged = true;
+ }
+ CheckForEmptyTable();
+}
+
+void ScNameDlg::NameModified()
+{
+ ScRangeNameLine aLine;
+ m_xRangeManagerTable->GetCurrentLine(aLine);
+ OUString aOldName = aLine.aName;
+ OUString aNewName = m_xEdName->get_text();
+ aNewName = aNewName.trim();
+ m_xFtInfo->set_label_type(weld::LabelType::Normal);
+ if (aNewName != aOldName)
+ {
+ if (!IsNameValid())
+ return;
+ }
+ else
+ {
+ m_xFtInfo->set_label( maStrInfoDefault );
+ }
+
+ if (!IsFormulaValid())
+ {
+ //TODO: implement an info text
+ return;
+ }
+
+ OUString aOldScope = aLine.aScope;
+ //empty table
+ if (aOldScope.isEmpty())
+ return;
+ OUString aExpr = m_xEdAssign->GetText();
+ OUString aNewScope = m_xLbScope->get_active_text();
+
+ ScRangeName* pOldRangeName = GetRangeName( aOldScope );
+ ScRangeData* pData = pOldRangeName->findByUpperName( ScGlobal::getCharClass().uppercase(aOldName) );
+ ScRangeName* pNewRangeName = GetRangeName( aNewScope );
+ OSL_ENSURE(pData, "model and table should be in sync");
+ // be safe and check for range data
+ if (!pData)
+ return;
+
+ // Assign new index (0) only if the scope is changed, else keep the
+ // existing index.
+ sal_uInt16 nIndex = (aNewScope != aOldScope ? 0 : pData->GetIndex());
+
+ pOldRangeName->erase(*pData);
+ m_xRangeManagerTable->BlockUpdate();
+ m_xRangeManagerTable->DeleteSelectedEntries();
+ ScRangeData::Type nType = ScRangeData::Type::Name;
+ if ( m_xBtnRowHeader->get_active() ) nType |= ScRangeData::Type::RowHeader;
+ if ( m_xBtnColHeader->get_active() ) nType |= ScRangeData::Type::ColHeader;
+ if ( m_xBtnPrintArea->get_active() ) nType |= ScRangeData::Type::PrintArea;
+ if ( m_xBtnCriteria->get_active() ) nType |= ScRangeData::Type::Criteria;
+
+ ScRangeData* pNewEntry = new ScRangeData( mrDoc, aNewName, aExpr,
+ maCursorPos, nType);
+ pNewEntry->SetIndex( nIndex);
+ pNewRangeName->insert(pNewEntry, false /*bReuseFreeIndex*/);
+ aLine.aName = aNewName;
+ aLine.aExpression = aExpr;
+ aLine.aScope = aNewScope;
+ m_xRangeManagerTable->addEntry(aLine, true);
+ // tdf#128137 process pending async row change events while UpdatesBlocked in place
+ Application::Reschedule(true);
+ m_xRangeManagerTable->UnblockUpdate();
+ mbDataChanged = true;
+}
+
+void ScNameDlg::SelectionChanged()
+{
+ //don't update if we have just modified due to user input
+ if (m_xRangeManagerTable->UpdatesBlocked())
+ {
+ return;
+ }
+
+ if (m_xRangeManagerTable->IsMultiSelection())
+ {
+ m_xEdName->set_text(maStrMultiSelect);
+ m_xEdAssign->SetText(maStrMultiSelect);
+
+ m_xEdName->set_sensitive(false);
+ m_xEdAssign->GetWidget()->set_sensitive(false);
+ m_xRbAssign->GetWidget()->set_sensitive(false);
+ m_xLbScope->set_sensitive(false);
+ m_xBtnRowHeader->set_sensitive(false);
+ m_xBtnColHeader->set_sensitive(false);
+ m_xBtnPrintArea->set_sensitive(false);
+ m_xBtnCriteria->set_sensitive(false);
+ }
+ else
+ {
+ ScRangeNameLine aLine;
+ m_xRangeManagerTable->GetCurrentLine(aLine);
+ m_xEdAssign->SetText(aLine.aExpression);
+ m_xEdName->set_text(aLine.aName);
+ m_xLbScope->set_active_text(aLine.aScope);
+ ShowOptions(aLine);
+ m_xBtnDelete->set_sensitive(true);
+ m_xEdName->set_sensitive(true);
+ m_xEdAssign->GetWidget()->set_sensitive(true);
+ m_xRbAssign->GetWidget()->set_sensitive(true);
+ m_xLbScope->set_sensitive(true);
+ m_xBtnRowHeader->set_sensitive(true);
+ m_xBtnColHeader->set_sensitive(true);
+ m_xBtnPrintArea->set_sensitive(true);
+ m_xBtnCriteria->set_sensitive(true);
+ }
+}
+
+void ScNameDlg::ScopeChanged()
+{
+ NameModified();
+}
+
+void ScNameDlg::GetRangeNames(std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap)
+{
+ m_RangeMap.swap(rRangeMap);
+}
+
+IMPL_LINK_NOARG(ScNameDlg, OkBtnHdl, weld::Button&, void)
+{
+ response(RET_OK);
+}
+
+IMPL_LINK_NOARG(ScNameDlg, CancelBtnHdl, weld::Button&, void)
+{
+ mbCloseWithoutUndo = true;
+ response(RET_CANCEL);
+}
+
+IMPL_LINK_NOARG(ScNameDlg, AddBtnHdl, weld::Button&, void)
+{
+ AddPushed();
+}
+
+IMPL_LINK_NOARG(ScNameDlg, RemoveBtnHdl, weld::Button&, void)
+{
+ RemovePushed();
+}
+
+IMPL_LINK_NOARG(ScNameDlg, EdModifyCheckBoxHdl, weld::Toggleable&, void)
+{
+ NameModified();
+}
+
+IMPL_LINK_NOARG(ScNameDlg, EdModifyHdl, weld::Entry&, void)
+{
+ NameModified();
+}
+
+IMPL_LINK_NOARG(ScNameDlg, RefEdModifyHdl, formula::RefEdit&, void)
+{
+ NameModified();
+}
+
+IMPL_LINK_NOARG(ScNameDlg, AssignGetFocusHdl, formula::RefEdit&, void)
+{
+ RefEdModifyHdl(*m_xEdAssign);
+}
+
+IMPL_LINK_NOARG(ScNameDlg, SelectionChangedHdl_Impl, weld::TreeView&, void)
+{
+ SelectionChanged();
+}
+
+IMPL_LINK_NOARG(ScNameDlg, ScopeChangedHdl, weld::ComboBox&, void)
+{
+ ScopeChanged();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/namedlg/namemgrtable.cxx b/sc/source/ui/namedlg/namemgrtable.cxx
new file mode 100644
index 000000000..0e5d98856
--- /dev/null
+++ b/sc/source/ui/namedlg/namemgrtable.cxx
@@ -0,0 +1,177 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+//ScRangeManagerTable
+#include <memory>
+#include <global.hxx>
+#include <globstr.hrc>
+#include <o3tl/safeint.hxx>
+#include <scresid.hxx>
+#include <globalnames.hxx>
+#include <namemgrtable.hxx>
+#include <rangenam.hxx>
+
+#include <unotools/charclass.hxx>
+#include <vcl/weld.hxx>
+#include <tools/link.hxx>
+
+void ScRangeManagerTable::GetCurrentLine(ScRangeNameLine& rLine)
+{
+ std::unique_ptr<weld::TreeIter> xCurrentEntry(m_xTreeView->make_iterator());
+ if (m_xTreeView->get_cursor(xCurrentEntry.get()))
+ GetLine(rLine, *xCurrentEntry);
+}
+
+void ScRangeManagerTable::DeleteSelectedEntries()
+{
+ std::vector<int> aRows = m_xTreeView->get_selected_rows();
+ std::sort(aRows.begin(), aRows.end());
+ for (auto it = aRows.rbegin(); it != aRows.rend(); ++it)
+ m_xTreeView->remove(*it);
+}
+
+bool ScRangeManagerTable::IsMultiSelection() const
+{
+ return m_xTreeView->count_selected_rows() > 1;
+}
+
+void ScRangeManagerTable::SetEntry(const ScRangeNameLine& rLine)
+{
+ for (int i = 0, nEntryCount = m_xTreeView->n_children(); i < nEntryCount; ++i)
+ {
+ if (rLine.aName == m_xTreeView->get_text(i, 0)
+ && rLine.aScope == m_xTreeView->get_text(i, 2))
+ {
+ m_xTreeView->set_cursor(i);
+ }
+ }
+}
+
+ScRangeManagerTable::ScRangeManagerTable(
+ std::unique_ptr<weld::TreeView> xTreeView,
+ const std::map<OUString, std::unique_ptr<ScRangeName>>& rRangeMap, const ScAddress& rPos)
+ : m_xTreeView(std::move(xTreeView))
+ , maGlobalString(ScResId(STR_GLOBAL_SCOPE))
+ , m_RangeMap(rRangeMap)
+ , maPos(rPos)
+ , m_nId(0)
+ , mbNeedUpdate(true)
+{
+ auto nColWidth = m_xTreeView->get_size_request().Width() / 7;
+ std::vector<int> aWidths{ o3tl::narrowing<int>(nColWidth * 2),
+ o3tl::narrowing<int>(nColWidth * 3) };
+ m_xTreeView->set_column_fixed_widths(aWidths);
+
+ Init();
+ m_xTreeView->set_selection_mode(SelectionMode::Multiple);
+ m_xTreeView->connect_size_allocate(LINK(this, ScRangeManagerTable, SizeAllocHdl));
+ m_xTreeView->connect_visible_range_changed(LINK(this, ScRangeManagerTable, VisRowsScrolledHdl));
+}
+
+IMPL_LINK_NOARG(ScRangeManagerTable, VisRowsScrolledHdl, weld::TreeView&, void)
+{
+ CheckForFormulaString();
+}
+
+const ScRangeData* ScRangeManagerTable::findRangeData(const ScRangeNameLine& rLine)
+{
+ const ScRangeName* pRangeName;
+ if (rLine.aScope == maGlobalString)
+ pRangeName = m_RangeMap.find(OUString(STR_GLOBAL_RANGE_NAME))->second.get();
+ else
+ pRangeName = m_RangeMap.find(rLine.aScope)->second.get();
+
+ return pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(rLine.aName));
+}
+
+void ScRangeManagerTable::CheckForFormulaString()
+{
+ if (UpdatesBlocked())
+ return;
+
+ auto lambda = [this](weld::TreeIter& rEntry) {
+ OUString sId(m_xTreeView->get_id(rEntry));
+ std::map<OUString, bool>::const_iterator itr = maCalculatedFormulaEntries.find(sId);
+ if (itr == maCalculatedFormulaEntries.end() || !itr->second)
+ {
+ ScRangeNameLine aLine;
+ GetLine(aLine, rEntry);
+ const ScRangeData* pData = findRangeData(aLine);
+ OUString aFormulaString = pData->GetSymbol(maPos);
+ m_xTreeView->set_text(rEntry, aFormulaString, 1);
+ maCalculatedFormulaEntries.insert(std::pair<OUString, bool>(sId, true));
+ }
+ return false;
+ };
+
+ // ensure all visible entries are up to date
+ m_xTreeView->visible_foreach(lambda);
+ // and ensure all selected entries are up to date
+ m_xTreeView->selected_foreach(lambda);
+}
+
+IMPL_LINK_NOARG(ScRangeManagerTable, SizeAllocHdl, const Size&, void) { CheckForFormulaString(); }
+
+void ScRangeManagerTable::addEntry(const ScRangeNameLine& rLine, bool bSetCurEntry)
+{
+ int nRow = m_xTreeView->n_children();
+ m_xTreeView->append();
+ m_xTreeView->set_text(nRow, rLine.aName, 0);
+ m_xTreeView->set_text(nRow, rLine.aExpression, 1);
+ m_xTreeView->set_text(nRow, rLine.aScope, 2);
+ // just unique to track which one has been cached by maCalculatedFormulaEntries
+ m_xTreeView->set_id(nRow, OUString::number(m_nId++));
+ if (bSetCurEntry)
+ m_xTreeView->set_cursor(nRow);
+}
+
+void ScRangeManagerTable::GetLine(ScRangeNameLine& rLine, const weld::TreeIter& rEntry)
+{
+ rLine.aName = m_xTreeView->get_text(rEntry, 0);
+ rLine.aExpression = m_xTreeView->get_text(rEntry, 1);
+ rLine.aScope = m_xTreeView->get_text(rEntry, 2);
+}
+
+void ScRangeManagerTable::Init()
+{
+ m_xTreeView->freeze();
+ m_xTreeView->clear();
+ for (auto const& itr : m_RangeMap)
+ {
+ const ScRangeName* const pLocalRangeName = itr.second.get();
+ ScRangeNameLine aLine;
+ if (itr.first == STR_GLOBAL_RANGE_NAME)
+ aLine.aScope = maGlobalString;
+ else
+ aLine.aScope = itr.first;
+ for (const auto& rEntry : *pLocalRangeName)
+ {
+ if (!rEntry.second->HasType(ScRangeData::Type::Database))
+ {
+ aLine.aName = rEntry.second->GetName();
+ addEntry(aLine, false);
+ }
+ }
+ }
+ m_xTreeView->thaw();
+}
+
+std::vector<ScRangeNameLine> ScRangeManagerTable::GetSelectedEntries()
+{
+ std::vector<ScRangeNameLine> aSelectedEntries;
+ m_xTreeView->selected_foreach([this, &aSelectedEntries](weld::TreeIter& rEntry) {
+ ScRangeNameLine aLine;
+ GetLine(aLine, rEntry);
+ aSelectedEntries.push_back(aLine);
+ return false;
+ });
+ return aSelectedEntries;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/namedlg/namepast.cxx b/sc/source/ui/namedlg/namepast.cxx
new file mode 100644
index 000000000..37984eb8b
--- /dev/null
+++ b/sc/source/ui/namedlg/namepast.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <namepast.hxx>
+#include <docsh.hxx>
+#include <rangenam.hxx>
+#include <viewdata.hxx>
+#include <scui_def.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <compiler.hxx>
+
+ScNamePasteDlg::ScNamePasteDlg(weld::Window* pParent, ScDocShell* pShell)
+ : GenericDialogController(pParent, "modules/scalc/ui/insertname.ui", "InsertNameDialog")
+ , m_xBtnPasteAll(m_xBuilder->weld_button("pasteall"))
+ , m_xBtnPaste(m_xBuilder->weld_button("paste"))
+ , m_xBtnClose(m_xBuilder->weld_button("close"))
+{
+ ScDocument& rDoc = pShell->GetDocument();
+ m_aSheetSep = OUString(rDoc.GetSheetSeparator());
+ std::map<OUString, ScRangeName*> aCopyMap;
+ rDoc.GetRangeNameMap(aCopyMap);
+ for (const auto & [ aTemp, pName ] : aCopyMap)
+ {
+ m_RangeMap.insert(std::make_pair(aTemp, std::make_unique<ScRangeName>(*pName)));
+ }
+
+ ScAddress aPos;
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ aPos = ScAddress(pViewData->GetCurX(), pViewData->GetCurY(), pViewData->GetTabNo());
+
+ std::unique_ptr<weld::TreeView> xTreeView(m_xBuilder->weld_tree_view("ctrl"));
+ xTreeView->set_size_request(xTreeView->get_approximate_digit_width() * 75,
+ xTreeView->get_height_rows(10));
+ m_xTable.reset(new ScRangeManagerTable(std::move(xTreeView), m_RangeMap, aPos));
+
+ m_xBtnPaste->connect_clicked(LINK(this, ScNamePasteDlg, ButtonHdl));
+ m_xBtnPasteAll->connect_clicked(LINK(this, ScNamePasteDlg, ButtonHdl));
+ m_xBtnClose->connect_clicked(LINK(this, ScNamePasteDlg, ButtonHdl));
+
+ if (!m_xTable->n_children())
+ {
+ m_xBtnPaste->set_sensitive(false);
+ m_xBtnPasteAll->set_sensitive(false);
+ }
+}
+
+ScNamePasteDlg::~ScNamePasteDlg() {}
+
+IMPL_LINK(ScNamePasteDlg, ButtonHdl, weld::Button&, rButton, void)
+{
+ if (&rButton == m_xBtnPasteAll.get())
+ {
+ m_xDialog->response(BTN_PASTE_LIST);
+ }
+ else if (&rButton == m_xBtnPaste.get())
+ {
+ const OUString aGlobalScope(ScResId(STR_GLOBAL_SCOPE));
+ std::vector<ScRangeNameLine> aSelectedLines = m_xTable->GetSelectedEntries();
+ for (const auto& rLine : aSelectedLines)
+ {
+ if (rLine.aScope == aGlobalScope)
+ maSelectedNames.push_back(rLine.aName);
+ else
+ {
+ OUString aSheet(rLine.aScope);
+ ScCompiler::CheckTabQuotes(aSheet);
+ maSelectedNames.push_back(aSheet + m_aSheetSep + rLine.aName);
+ }
+ }
+ m_xDialog->response(BTN_PASTE_NAME);
+ }
+ else if (&rButton == m_xBtnClose.get())
+ {
+ m_xDialog->response(BTN_PASTE_CLOSE);
+ }
+}
+
+const std::vector<OUString>& ScNamePasteDlg::GetSelectedNames() const { return maSelectedNames; }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/navipi/content.cxx b/sc/source/ui/navipi/content.cxx
new file mode 100644
index 000000000..2c8336fd3
--- /dev/null
+++ b/sc/source/ui/navipi/content.cxx
@@ -0,0 +1,1637 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include <svx/svditer.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdview.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+#include <tools/urlobj.hxx>
+#include <sal/log.hxx>
+#include <unotools/charclass.hxx>
+
+#include <content.hxx>
+#include <navipi.hxx>
+#include <global.hxx>
+#include <docsh.hxx>
+#include <scmod.hxx>
+#include <rangenam.hxx>
+#include <dbdata.hxx>
+#include <tablink.hxx>
+#include <drwlayer.hxx>
+#include <transobj.hxx>
+#include <drwtrans.hxx>
+#include <lnktrans.hxx>
+#include <strings.hrc>
+#include <scresid.hxx>
+#include <bitmaps.hlst>
+#include <arealink.hxx>
+#include <navicfg.hxx>
+#include <navsett.hxx>
+#include <postit.hxx>
+#include <tabvwsh.hxx>
+#include <drawview.hxx>
+#include <clipparam.hxx>
+#include <markdata.hxx>
+
+using namespace com::sun::star;
+
+// order of the categories in navigator -------------------------------------
+
+const ScContentId pTypeList[int(ScContentId::LAST) + 1] =
+{
+ ScContentId::ROOT, // ROOT (0) has to be at the front
+ ScContentId::TABLE,
+ ScContentId::RANGENAME,
+ ScContentId::DBAREA,
+ ScContentId::AREALINK,
+ ScContentId::GRAPHIC,
+ ScContentId::OLEOBJECT,
+ ScContentId::NOTE,
+ ScContentId::DRAWING
+};
+
+constexpr rtl::OUStringConstExpr aContentBmps[]=
+{
+ RID_BMP_CONTENT_TABLE,
+ RID_BMP_CONTENT_RANGENAME,
+ RID_BMP_CONTENT_DBAREA,
+ RID_BMP_CONTENT_GRAPHIC,
+ RID_BMP_CONTENT_OLEOBJECT,
+ RID_BMP_CONTENT_NOTE,
+ RID_BMP_CONTENT_AREALINK,
+ RID_BMP_CONTENT_DRAWING
+};
+
+ScDocShell* ScContentTree::GetManualOrCurrent()
+{
+ ScDocShell* pSh = nullptr;
+ if ( !aManualDoc.isEmpty() )
+ {
+ SfxObjectShell* pObjSh = SfxObjectShell::GetFirst( checkSfxObjectShell<ScDocShell> );
+ while ( pObjSh && !pSh )
+ {
+ if ( pObjSh->GetTitle() == aManualDoc )
+ pSh = dynamic_cast<ScDocShell*>( pObjSh );
+ pObjSh = SfxObjectShell::GetNext( *pObjSh, checkSfxObjectShell<ScDocShell> );
+ }
+ }
+ else
+ {
+ // only current when manual isn't set
+ // (so it's detected when the documents don't exists any longer)
+
+ SfxViewShell* pViewSh = SfxViewShell::Current();
+ if ( pViewSh )
+ {
+ SfxObjectShell* pObjSh = pViewSh->GetViewFrame()->GetObjectShell();
+ pSh = dynamic_cast<ScDocShell*>( pObjSh );
+ }
+ }
+
+ return pSh;
+}
+
+// ScContentTree
+
+ScContentTree::ScContentTree(std::unique_ptr<weld::TreeView> xTreeView, ScNavigatorDlg* pNavigatorDlg)
+ : m_xTreeView(std::move(xTreeView))
+ , m_xScratchIter(m_xTreeView->make_iterator())
+ , m_xTransferObj(new ScLinkTransferObj)
+ , pParentWindow(pNavigatorDlg)
+ , nRootType(ScContentId::ROOT)
+ , bHiddenDoc(false)
+ , pHiddenDocument(nullptr)
+ , bIsInNavigatorDlg(false)
+ , m_bFreeze(false)
+ , m_nAsyncMouseReleaseId(nullptr)
+{
+ for (sal_uInt16 i = 0; i <= int(ScContentId::LAST); ++i)
+ pPosList[pTypeList[i]] = i; // inverse for searching
+
+ m_aRootNodes[ScContentId::ROOT] = nullptr;
+ for (sal_uInt16 i = 1; i < int(ScContentId::LAST); ++i)
+ InitRoot(static_cast<ScContentId>(i));
+
+ m_xTreeView->connect_row_activated(LINK(this, ScContentTree, ContentDoubleClickHdl));
+ m_xTreeView->connect_mouse_release(LINK(this, ScContentTree, MouseReleaseHdl));
+ m_xTreeView->connect_key_press(LINK(this, ScContentTree, KeyInputHdl));
+ m_xTreeView->connect_popup_menu(LINK(this, ScContentTree, CommandHdl));
+ m_xTreeView->connect_query_tooltip(LINK(this, ScContentTree, QueryTooltipHdl));
+
+ rtl::Reference<TransferDataContainer> xHelper(m_xTransferObj);
+ m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
+
+ m_xTreeView->connect_drag_begin(LINK(this, ScContentTree, DragBeginHdl));
+
+ m_xTreeView->set_selection_mode( SelectionMode::Single );
+
+ m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 30,
+ m_xTreeView->get_text_height() * 13);
+}
+
+ScContentTree::~ScContentTree()
+{
+ if (m_nAsyncMouseReleaseId)
+ {
+ Application::RemoveUserEvent(m_nAsyncMouseReleaseId);
+ m_nAsyncMouseReleaseId = nullptr;
+ }
+}
+
+const TranslateId SCSTR_CONTENT_ARY[] =
+{
+ SCSTR_CONTENT_ROOT,
+ SCSTR_CONTENT_TABLE,
+ SCSTR_CONTENT_RANGENAME,
+ SCSTR_CONTENT_DBAREA,
+ SCSTR_CONTENT_GRAPHIC,
+ SCSTR_CONTENT_OLEOBJECT,
+ SCSTR_CONTENT_NOTE,
+ SCSTR_CONTENT_AREALINK,
+ SCSTR_CONTENT_DRAWING
+};
+
+void ScContentTree::InitRoot( ScContentId nType )
+{
+ if ( nType == ScContentId::ROOT )
+ return;
+
+ if ( nRootType != ScContentId::ROOT && nRootType != nType ) // hidden ?
+ {
+ m_aRootNodes[nType] = nullptr;
+ return;
+ }
+
+ auto const aImage(aContentBmps[static_cast<int>(nType) - 1]);
+ OUString aName(ScResId(SCSTR_CONTENT_ARY[static_cast<int>(nType)]));
+ // back to the correct position:
+ sal_uInt16 nPos = nRootType != ScContentId::ROOT ? 0 : pPosList[nType]-1;
+ m_aRootNodes[nType] = m_xTreeView->make_iterator();
+ m_xTreeView->insert(nullptr, nPos, &aName, nullptr, nullptr, nullptr, false, m_aRootNodes[nType].get());
+ m_xTreeView->set_image(*m_aRootNodes[nType], OUString(aImage));
+}
+
+void ScContentTree::ClearAll()
+{
+ //There are one method in Control::SetUpdateMode(), and one override method SvTreeListBox::SetUpdateMode(). Here although
+ //SvTreeListBox::SetUpdateMode() is called in refresh method, it only call SvTreeListBox::SetUpdateMode(), not Control::SetUpdateMode().
+ //In m_xTreeView->clear(), Broadcast( LISTACTION_CLEARED ) will be called and finally, it will be trapped into the event yield() loop. And
+ //the InitRoot() method won't be called. Then if a user click or press key to update the navigator tree, crash happens.
+ //So the solution is to disable the UpdateMode of Control, then call Clear(), then recover the update mode
+ bool bWasFrozen = m_bFreeze;
+ if (!bWasFrozen)
+ freeze();
+ m_xTreeView->clear();
+ if (!bWasFrozen)
+ thaw();
+ for (sal_uInt16 i=1; i<=int(ScContentId::LAST); i++)
+ InitRoot(static_cast<ScContentId>(i));
+}
+
+void ScContentTree::ClearType(ScContentId nType)
+{
+ if (nType == ScContentId::ROOT)
+ ClearAll();
+ else
+ {
+ weld::TreeIter* pParent = m_aRootNodes[nType].get();
+ if (!pParent || m_xTreeView->iter_has_child(*pParent)) // not if no children existing
+ {
+ if (pParent)
+ m_xTreeView->remove(*pParent); // with all children
+ InitRoot( nType ); // if needed insert anew
+ }
+ }
+}
+
+void ScContentTree::InsertContent( ScContentId nType, const OUString& rValue )
+{
+ weld::TreeIter* pParent = m_aRootNodes[nType].get();
+ if (pParent)
+ {
+ m_xTreeView->insert(pParent, -1, &rValue, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
+ m_xTreeView->set_sensitive(*m_xScratchIter, true);
+ }
+ else
+ {
+ OSL_FAIL("InsertContent without parent");
+ }
+}
+
+void ScContentTree::GetEntryIndexes(ScContentId& rnRootIndex, sal_uLong& rnChildIndex, const weld::TreeIter* pEntry) const
+{
+ rnRootIndex = ScContentId::ROOT;
+ rnChildIndex = SC_CONTENT_NOCHILD;
+
+ if( !pEntry )
+ return;
+
+ std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(pEntry));
+ if (!m_xTreeView->iter_parent(*xParent))
+ xParent.reset();
+ bool bFound = false;
+ for( int i = 1; !bFound && (i <= int(ScContentId::LAST)); ++i )
+ {
+ ScContentId nRoot = static_cast<ScContentId>(i);
+ if (!m_aRootNodes[nRoot])
+ continue;
+ if (m_xTreeView->iter_compare(*pEntry, *m_aRootNodes[nRoot]) == 0)
+ {
+ rnRootIndex = nRoot;
+ rnChildIndex = ~0UL;
+ bFound = true;
+ }
+ else if (xParent && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[nRoot]) == 0)
+ {
+ rnRootIndex = nRoot;
+
+ // search the entry in all child entries of the parent
+ sal_uLong nEntry = 0;
+ std::unique_ptr<weld::TreeIter> xIterEntry(m_xTreeView->make_iterator(xParent.get()));
+ bool bIterEntry = m_xTreeView->iter_children(*xIterEntry);
+ while (!bFound && bIterEntry)
+ {
+ if (m_xTreeView->iter_compare(*pEntry, *xIterEntry) == 0)
+ {
+ rnChildIndex = nEntry;
+ bFound = true; // exit the while loop
+ }
+ bIterEntry = m_xTreeView->iter_next_sibling(*xIterEntry);
+ ++nEntry;
+ }
+
+ bFound = true; // exit the for loop
+ }
+ }
+}
+
+sal_uLong ScContentTree::GetChildIndex(const weld::TreeIter* pEntry) const
+{
+ ScContentId nRoot;
+ sal_uLong nChild;
+ GetEntryIndexes(nRoot, nChild, pEntry);
+ return nChild;
+}
+
+static OUString lcl_GetDBAreaRange( const ScDocument* pDoc, const OUString& rDBName )
+{
+ OUString aRet;
+ if (pDoc)
+ {
+ ScDBCollection* pDbNames = pDoc->GetDBCollection();
+ const ScDBData* pData = pDbNames->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rDBName));
+ if (pData)
+ {
+ ScRange aRange;
+ pData->GetArea(aRange);
+ aRet = aRange.Format(*pDoc, ScRefFlags::RANGE_ABS_3D);
+ }
+ }
+ return aRet;
+}
+
+IMPL_LINK_NOARG(ScContentTree, ContentDoubleClickHdl, weld::TreeView&, bool)
+{
+ ScContentId nType;
+ sal_uLong nChild;
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_cursor(xEntry.get()))
+ xEntry.reset();
+ GetEntryIndexes(nType, nChild, xEntry.get());
+
+ if (xEntry && (nType != ScContentId::ROOT) && (nChild != SC_CONTENT_NOCHILD))
+ {
+ if ( bHiddenDoc )
+ return false; //! later...
+
+ OUString aText(m_xTreeView->get_text(*xEntry));
+
+ if ( !aManualDoc.isEmpty() )
+ pParentWindow->SetCurrentDoc( aManualDoc );
+
+ switch( nType )
+ {
+ case ScContentId::TABLE:
+ {
+ // tdf#133159 store current config before changing sheet
+ // plausible that this should be done for all cases, but this
+ // is the known case that needs it
+ StoreNavigatorSettings();
+ pParentWindow->SetCurrentTableStr( aText );
+ }
+ break;
+
+ case ScContentId::RANGENAME:
+ pParentWindow->SetCurrentCellStr( aText );
+ break;
+
+ case ScContentId::DBAREA:
+ {
+ // If the same names of area and DB exists, then
+ // SID_CURRENTCELL takes the area name.
+ // Therefore for DB areas access them directly via address.
+
+ OUString aRangeStr = lcl_GetDBAreaRange( GetSourceDocument(), aText );
+ if (!aRangeStr.isEmpty())
+ pParentWindow->SetCurrentCellStr( aRangeStr );
+ }
+ break;
+
+ case ScContentId::OLEOBJECT:
+ case ScContentId::GRAPHIC:
+ case ScContentId::DRAWING:
+ pParentWindow->SetCurrentObject( aText );
+ break;
+
+ case ScContentId::NOTE:
+ {
+ ScAddress aPos = GetNotePos( nChild );
+ pParentWindow->SetCurrentTable( aPos.Tab() );
+ pParentWindow->SetCurrentCell( aPos.Col(), aPos.Row() );
+ }
+ break;
+
+ case ScContentId::AREALINK:
+ {
+ const ScAreaLink* pLink = GetLink(nChild);
+ ScDocument* pSrcDoc = GetSourceDocument();
+ if (pLink && pSrcDoc)
+ {
+ const ScRange& aRange = pLink->GetDestArea();
+ OUString aRangeStr(aRange.Format(*pSrcDoc, ScRefFlags::RANGE_ABS_3D, pSrcDoc->GetAddressConvention()));
+ pParentWindow->SetCurrentCellStr( aRangeStr );
+ }
+ }
+ break;
+ default: break;
+ }
+
+ ScNavigatorDlg::ReleaseFocus(); // set focus into document
+ }
+
+ return false;
+}
+
+void ScContentTree::LaunchAsyncStoreNavigatorSettings()
+{
+ if (!m_nAsyncMouseReleaseId)
+ m_nAsyncMouseReleaseId = Application::PostUserEvent(LINK(this, ScContentTree, AsyncStoreNavigatorSettings));
+}
+
+IMPL_LINK_NOARG(ScContentTree, MouseReleaseHdl, const MouseEvent&, bool)
+{
+ LaunchAsyncStoreNavigatorSettings();
+ return false;
+}
+
+IMPL_LINK_NOARG(ScContentTree, AsyncStoreNavigatorSettings, void*, void)
+{
+ m_nAsyncMouseReleaseId = nullptr;
+ StoreNavigatorSettings();
+}
+
+IMPL_LINK(ScContentTree, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bUsed = false;
+
+ const vcl::KeyCode aCode = rKEvt.GetKeyCode();
+ if (aCode.GetCode() == KEY_RETURN)
+ {
+ switch (aCode.GetModifier())
+ {
+ case KEY_MOD1:
+ ToggleRoot(); // toggle root mode (as in Writer)
+ bUsed = true;
+ break;
+ case 0:
+ {
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_cursor(xEntry.get()))
+ xEntry.reset();
+ if (xEntry)
+ {
+ ScContentId nType;
+ sal_uLong nChild;
+ GetEntryIndexes(nType, nChild, xEntry.get());
+
+ if (nType != ScContentId::ROOT && nChild == SC_CONTENT_NOCHILD)
+ {
+ if (m_xTreeView->get_row_expanded(*xEntry))
+ m_xTreeView->collapse_row(*xEntry);
+ else
+ m_xTreeView->expand_row(*xEntry);
+ }
+ else
+ ContentDoubleClickHdl(*m_xTreeView); // select content as if double clicked
+ }
+
+ bUsed = true;
+ }
+ break;
+ }
+ }
+ //Make KEY_SPACE has same function as DoubleClick, and realize
+ //multi-selection.
+ if ( bIsInNavigatorDlg )
+ {
+ if(aCode.GetCode() == KEY_SPACE )
+ {
+ bUsed = true;
+ ScContentId nType;
+ sal_uLong nChild;
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_cursor(xEntry.get()))
+ xEntry.reset();
+ GetEntryIndexes(nType, nChild, xEntry.get());
+
+ if (xEntry && (nType != ScContentId::ROOT) && (nChild != SC_CONTENT_NOCHILD))
+ {
+ if ( bHiddenDoc )
+ return true; //! later...
+ OUString aText(m_xTreeView->get_text(*xEntry));
+ if (!aManualDoc.isEmpty())
+ pParentWindow->SetCurrentDoc( aManualDoc );
+ switch (nType)
+ {
+ case ScContentId::OLEOBJECT:
+ case ScContentId::GRAPHIC:
+ case ScContentId::DRAWING:
+ {
+ ScDrawView* pScDrawView = nullptr;
+ ScTabViewShell* pScTabViewShell = ScNavigatorDlg::GetTabViewShell();
+ if (pScTabViewShell)
+ pScDrawView = pScTabViewShell->GetViewData().GetScDrawView();
+ if (pScDrawView)
+ {
+ pScDrawView->SelectCurrentViewObject(aText);
+ bool bHasMakredObject = false;
+ weld::TreeIter* pParent = m_aRootNodes[nType].get();
+ std::unique_ptr<weld::TreeIter> xBeginEntry(m_xTreeView->make_iterator(pParent));
+ bool bBeginEntry = false;
+ if (pParent)
+ bBeginEntry = m_xTreeView->iter_children(*xBeginEntry);
+ while (bBeginEntry)
+ {
+ OUString aTempText(m_xTreeView->get_text(*xBeginEntry));
+ if( pScDrawView->GetObjectIsMarked( pScDrawView->GetObjectByName( aTempText ) ) )
+ {
+ bHasMakredObject = true;
+ break;
+ }
+ bBeginEntry = m_xTreeView->iter_next(*xBeginEntry);
+ }
+ if (!bHasMakredObject && pScTabViewShell)
+ pScTabViewShell->SetDrawShell(false);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (!bUsed)
+ {
+ if (aCode.GetCode() == KEY_F5)
+ StoreNavigatorSettings();
+ else
+ LaunchAsyncStoreNavigatorSettings();
+ }
+
+ return bUsed;
+}
+
+IMPL_LINK(ScContentTree, CommandHdl, const CommandEvent&, rCEvt, bool)
+{
+ bool bDone = false;
+
+ switch ( rCEvt.GetCommand() )
+ {
+ case CommandEventId::ContextMenu:
+ {
+ // drag-and-drop mode
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xTreeView.get(), "modules/scalc/ui/dropmenu.ui"));
+ std::unique_ptr<weld::Menu> xPop(xBuilder->weld_menu("contextmenu"));
+ std::unique_ptr<weld::Menu> xDropMenu(xBuilder->weld_menu("dragmodesubmenu"));
+
+ switch (pParentWindow->GetDropMode())
+ {
+ case 0:
+ xDropMenu->set_active("hyperlink", true);
+ break;
+ case 1:
+ xDropMenu->set_active("link", true);
+ break;
+ case 2:
+ xDropMenu->set_active("copy", true);
+ break;
+ }
+
+ // displayed document
+ std::unique_ptr<weld::Menu> xDocMenu(xBuilder->weld_menu("displaymenu"));
+ sal_uInt16 i=0;
+ OUString sActive;
+ OUString sId;
+ // loaded documents
+ ScDocShell* pCurrentSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ SfxObjectShell* pSh = SfxObjectShell::GetFirst();
+ while ( pSh )
+ {
+ if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
+ {
+ OUString aName = pSh->GetTitle();
+ OUString aEntry = aName;
+ if ( pSh == pCurrentSh )
+ aEntry += pParentWindow->aStrActive;
+ else
+ aEntry += pParentWindow->aStrNotActive;
+ ++i;
+ sId = "document" + OUString::number(i);
+ xDocMenu->append_radio(sId, aEntry);
+ if ( !bHiddenDoc && aName == aManualDoc )
+ sActive = sId;
+ }
+ pSh = SfxObjectShell::GetNext( *pSh );
+ }
+ // "active window"
+ ++i;
+ sId = "document" + OUString::number(i);
+ xDocMenu->append_radio(sId, pParentWindow->aStrActiveWin);
+ if (!bHiddenDoc && aManualDoc.isEmpty())
+ sActive = sId;
+ // hidden document
+ if ( !aHiddenTitle.isEmpty() )
+ {
+ OUString aEntry = aHiddenTitle + pParentWindow->aStrHidden;
+ ++i;
+ sId = "document" + OUString::number(i);
+ xDocMenu->append_radio(sId, aEntry);
+ if (bHiddenDoc)
+ sActive = sId;
+ }
+ xDocMenu->set_active(sActive.toUtf8(), true);
+
+ OString sIdent = xPop->popup_at_rect(m_xTreeView.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1)));
+ if (sIdent == "hyperlink")
+ pParentWindow->SetDropMode(0);
+ else if (sIdent == "link")
+ pParentWindow->SetDropMode(1);
+ else if (sIdent == "copy")
+ pParentWindow->SetDropMode(2);
+ else if (sIdent.startsWith("document"))
+ {
+ OUString aName = xDocMenu->get_label(sIdent);
+ SelectDoc(aName);
+ }
+ }
+ break;
+ default: break;
+ }
+
+ return bDone;
+}
+
+IMPL_LINK(ScContentTree, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
+{
+ OUString aHelpText;
+
+ std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(&rEntry));
+ if (!m_xTreeView->iter_parent(*xParent))
+ xParent.reset();
+
+ if (!xParent) // Top-Level ?
+ {
+ aHelpText = OUString::number(m_xTreeView->iter_n_children(rEntry)) +
+ " " + m_xTreeView->get_text(rEntry);
+ }
+ else if (m_aRootNodes[ScContentId::NOTE] && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[ScContentId::NOTE]) == 0)
+ {
+ aHelpText = m_xTreeView->get_text(rEntry); // notes as help text
+ }
+ else if (m_aRootNodes[ScContentId::AREALINK] && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[ScContentId::AREALINK]) == 0)
+ {
+ auto nIndex = GetChildIndex(&rEntry);
+ if (nIndex != SC_CONTENT_NOCHILD)
+ {
+ const ScAreaLink* pLink = GetLink(nIndex);
+ if (pLink)
+ {
+ aHelpText = pLink->GetFile(); // source file as help text
+ }
+ }
+ }
+
+ return aHelpText;
+}
+
+ScDocument* ScContentTree::GetSourceDocument()
+{
+ if (bHiddenDoc)
+ return pHiddenDocument;
+ else
+ {
+ ScDocShell* pSh = GetManualOrCurrent();
+ if (pSh)
+ return &pSh->GetDocument();
+
+ }
+ return nullptr;
+}
+
+void ScContentTree::Refresh( ScContentId nType )
+{
+ if ( bHiddenDoc && !pHiddenDocument )
+ return; // other document displayed
+
+ // if nothing has changed the cancel right away (against flicker)
+
+ if ( nType == ScContentId::NOTE )
+ if (!NoteStringsChanged())
+ return;
+ if ( nType == ScContentId::GRAPHIC )
+ if (!DrawNamesChanged(ScContentId::GRAPHIC))
+ return;
+ if ( nType == ScContentId::OLEOBJECT )
+ if (!DrawNamesChanged(ScContentId::OLEOBJECT))
+ return;
+ if ( nType == ScContentId::DRAWING )
+ if (!DrawNamesChanged(ScContentId::DRAWING))
+ return;
+
+ freeze();
+
+ ClearType( nType );
+
+ if ( nType == ScContentId::ROOT || nType == ScContentId::TABLE )
+ GetTableNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::RANGENAME )
+ GetAreaNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::DBAREA )
+ GetDbNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::GRAPHIC )
+ GetGraphicNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::OLEOBJECT )
+ GetOleNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::DRAWING )
+ GetDrawingNames();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::NOTE )
+ GetNoteStrings();
+ if ( nType == ScContentId::ROOT || nType == ScContentId::AREALINK )
+ GetLinkNames();
+
+ thaw();
+
+ ApplyNavigatorSettings();
+}
+
+void ScContentTree::GetTableNames()
+{
+ if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::TABLE ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ OUString aName;
+ SCTAB nCount = pDoc->GetTableCount();
+ for ( SCTAB i=0; i<nCount; i++ )
+ {
+ pDoc->GetName( i, aName );
+ InsertContent( ScContentId::TABLE, aName );
+ }
+}
+
+namespace {
+
+OUString createLocalRangeName(std::u16string_view rName, std::u16string_view rTableName)
+{
+ return OUString::Concat(rName) + " (" + rTableName + ")";
+}
+}
+
+void ScContentTree::GetAreaNames()
+{
+ if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::RANGENAME ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ ScRange aDummy;
+ std::set<OUString> aSet;
+ ScRangeName* pRangeNames = pDoc->GetRangeName();
+ for (const auto& rEntry : *pRangeNames)
+ {
+ if (rEntry.second->IsValidReference(aDummy))
+ aSet.insert(rEntry.second->GetName());
+ }
+ for (SCTAB i = 0; i < pDoc->GetTableCount(); ++i)
+ {
+ ScRangeName* pLocalRangeName = pDoc->GetRangeName(i);
+ if (pLocalRangeName && !pLocalRangeName->empty())
+ {
+ OUString aTableName;
+ pDoc->GetName(i, aTableName);
+ for (const auto& rEntry : *pLocalRangeName)
+ {
+ if (rEntry.second->IsValidReference(aDummy))
+ aSet.insert(createLocalRangeName(rEntry.second->GetName(), aTableName));
+ }
+ }
+ }
+
+ for (const auto& rItem : aSet)
+ {
+ InsertContent(ScContentId::RANGENAME, rItem);
+ }
+}
+
+void ScContentTree::GetDbNames()
+{
+ if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::DBAREA ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ ScDBCollection* pDbNames = pDoc->GetDBCollection();
+ const ScDBCollection::NamedDBs& rDBs = pDbNames->getNamedDBs();
+ for (const auto& rxDB : rDBs)
+ {
+ const OUString& aStrName = rxDB->GetName();
+ InsertContent(ScContentId::DBAREA, aStrName);
+ }
+}
+
+bool ScContentTree::IsPartOfType( ScContentId nContentType, SdrObjKind nObjIdentifier )
+{
+ bool bRet = false;
+ switch ( nContentType )
+ {
+ case ScContentId::GRAPHIC:
+ bRet = ( nObjIdentifier == SdrObjKind::Graphic );
+ break;
+ case ScContentId::OLEOBJECT:
+ bRet = ( nObjIdentifier == SdrObjKind::OLE2 );
+ break;
+ case ScContentId::DRAWING:
+ bRet = ( nObjIdentifier != SdrObjKind::Graphic && nObjIdentifier != SdrObjKind::OLE2 ); // everything else
+ break;
+ default:
+ OSL_FAIL("unknown content type");
+ }
+ return bRet;
+}
+
+constexpr int MAX_TREE_NODES = 1000;
+
+void ScContentTree::GetDrawNames( ScContentId nType )
+{
+ if (!bIsInNavigatorDlg)
+ return;
+
+ if ( nRootType != ScContentId::ROOT && nRootType != nType ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
+ if (!pDrawLayer)
+ return;
+
+ SfxObjectShell* pShell = pDoc->GetDocumentShell();
+ if (!pShell)
+ return;
+
+ // iterate in flat mode for groups
+ SdrIterMode eIter = ( nType == ScContentId::DRAWING ) ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups;
+
+ std::vector<OUString> aNames;
+ SCTAB nTabCount = pDoc->GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage,"Page ?");
+ if (!pPage)
+ continue;
+ SdrObjListIter aIter(pPage, eIter);
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if (IsPartOfType(nType, pObject->GetObjIdentifier()))
+ {
+ OUString aName = ScDrawLayer::GetVisibleName(pObject);
+ if (!aName.isEmpty())
+ aNames.push_back(aName);
+ if (aNames.size() > MAX_TREE_NODES)
+ {
+ SAL_WARN("sc", "too many tree nodes, ignoring the rest");
+ break;
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+
+ weld::TreeIter* pParent = m_aRootNodes[nType].get();
+ assert(pParent && "InsertContent without parent");
+ // insert all of these in one go under pParent
+ m_xTreeView->bulk_insert_for_each(aNames.size(), [this, &aNames](weld::TreeIter& rIter, int nIndex) {
+ m_xTreeView->set_text(rIter, aNames[nIndex], 0);
+ m_xTreeView->set_sensitive(rIter, true);
+ }, pParent);
+}
+
+void ScContentTree::GetGraphicNames()
+{
+ GetDrawNames( ScContentId::GRAPHIC );
+}
+
+void ScContentTree::GetOleNames()
+{
+ GetDrawNames( ScContentId::OLEOBJECT );
+}
+
+void ScContentTree::GetDrawingNames()
+{
+ GetDrawNames( ScContentId::DRAWING );
+}
+
+void ScContentTree::GetLinkNames()
+{
+ if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::AREALINK ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
+ OSL_ENSURE(pLinkManager, "no LinkManager on document?");
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.size();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if (auto pScAreaLink = dynamic_cast<const ScAreaLink*>( pBase))
+ InsertContent( ScContentId::AREALINK, pScAreaLink->GetSource() );
+
+ // insert in list the names of source areas
+ }
+}
+
+const ScAreaLink* ScContentTree::GetLink( sal_uLong nIndex )
+{
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return nullptr;
+
+ sal_uLong nFound = 0;
+ sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
+ OSL_ENSURE(pLinkManager, "no LinkManager on document?");
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = rLinks.size();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if (auto pAreaLink = dynamic_cast<const ScAreaLink*>( pBase))
+ {
+ if (nFound == nIndex)
+ return pAreaLink;
+ ++nFound;
+ }
+ }
+
+ OSL_FAIL("link not found");
+ return nullptr;
+}
+
+static OUString lcl_NoteString( const ScPostIt& rNote )
+{
+ OUString aText = rNote.GetText();
+ sal_Int32 nAt;
+ while ( (nAt = aText.indexOf( '\n' )) != -1 )
+ aText = aText.replaceAt( nAt, 1, u" " );
+ return aText;
+}
+
+void ScContentTree::GetNoteStrings()
+{
+ if ( nRootType != ScContentId::ROOT && nRootType != ScContentId::NOTE ) // hidden ?
+ return;
+
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return;
+
+ // loop over cell notes
+ std::vector<sc::NoteEntry> aEntries;
+ pDoc->GetAllNoteEntries(aEntries);
+ weld::TreeIter* pParent = m_aRootNodes[ScContentId::NOTE].get();
+ for (const auto& rEntry : aEntries)
+ {
+ OUString aValue = lcl_NoteString(*rEntry.mpNote);
+ m_xTreeView->insert(pParent, -1, &aValue, nullptr, nullptr, nullptr, false, m_xScratchIter.get());
+ m_xTreeView->set_sensitive(*m_xScratchIter, true);
+ }
+}
+
+ScAddress ScContentTree::GetNotePos( sal_uLong nIndex )
+{
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return ScAddress();
+
+ return pDoc->GetNotePosition(nIndex);
+}
+
+bool ScContentTree::NoteStringsChanged()
+{
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return false;
+
+ weld::TreeIter* pParent = m_aRootNodes[ScContentId::NOTE].get();
+ if (!pParent)
+ return false;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
+ bool bEntry = m_xTreeView->iter_children(*xEntry);
+
+ std::vector<sc::NoteEntry> aEntries;
+ pDoc->GetAllNoteEntries(aEntries);
+ for (const auto& rEntry : aEntries)
+ {
+ const ScPostIt* pNote = rEntry.mpNote;
+ if (!bEntry)
+ return true;
+
+ if (lcl_NoteString(*pNote) != m_xTreeView->get_text(*xEntry))
+ return true;
+
+ bEntry = m_xTreeView->iter_next_sibling(*xEntry);
+ }
+
+ return bEntry;
+}
+
+bool ScContentTree::DrawNamesChanged( ScContentId nType )
+{
+ ScDocument* pDoc = GetSourceDocument();
+ if (!pDoc)
+ return false;
+
+ weld::TreeIter* pParent = m_aRootNodes[nType].get();
+ if (!pParent)
+ return false;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
+ bool bEntry = m_xTreeView->iter_children(*xEntry);
+
+ // iterate in flat mode for groups
+ SdrIterMode eIter = ( nType == ScContentId::DRAWING ) ? SdrIterMode::Flat : SdrIterMode::DeepNoGroups;
+
+ bool bEqual = true;
+ ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
+ SfxObjectShell* pShell = pDoc->GetDocumentShell();
+ if (pDrawLayer && pShell)
+ {
+ SCTAB nTabCount = pDoc->GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount && bEqual; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, eIter );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && bEqual)
+ {
+ if ( IsPartOfType( nType, pObject->GetObjIdentifier() ) )
+ {
+ if ( !bEntry )
+ bEqual = false;
+ else
+ {
+ if (ScDrawLayer::GetVisibleName(pObject) != m_xTreeView->get_text(*xEntry))
+ bEqual = false;
+
+ bEntry = m_xTreeView->iter_next_sibling(*xEntry);
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+
+ if ( bEntry )
+ bEqual = false; // anything else
+
+ return !bEqual;
+}
+
+static bool lcl_GetRange( const ScDocument& rDoc, ScContentId nType, const OUString& rName, ScRange& rRange )
+{
+ bool bFound = false;
+
+ if ( nType == ScContentId::RANGENAME )
+ {
+ ScRangeName* pList = rDoc.GetRangeName();
+ if (pList)
+ {
+ const ScRangeData* p = pList->findByUpperName(ScGlobal::getCharClass().uppercase(rName));
+ if (p && p->IsValidReference(rRange))
+ bFound = true;
+ }
+ }
+ else if ( nType == ScContentId::DBAREA )
+ {
+ ScDBCollection* pList = rDoc.GetDBCollection();
+ if (pList)
+ {
+ const ScDBData* p = pList->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rName));
+ if (p)
+ {
+ SCTAB nTab;
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ p->GetArea(nTab, nCol1, nRow1, nCol2, nRow2);
+ rRange = ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab);
+ bFound = true;
+ }
+ }
+ }
+
+ return bFound;
+}
+
+static bool lcl_DoDragObject( ScDocShell* pSrcShell, std::u16string_view rName, ScContentId nType, weld::TreeView& rTreeView )
+{
+ bool bDisallow = true;
+
+ ScDocument& rSrcDoc = pSrcShell->GetDocument();
+ ScDrawLayer* pModel = rSrcDoc.GetDrawLayer();
+ if (pModel)
+ {
+ bool bOle = ( nType == ScContentId::OLEOBJECT );
+ bool bGraf = ( nType == ScContentId::GRAPHIC );
+ SdrObjKind nDrawId = bOle ? SdrObjKind::OLE2 : ( bGraf ? SdrObjKind::Graphic : SdrObjKind::Group );
+ SCTAB nTab = 0;
+ SdrObject* pObject = pModel->GetNamedObject( rName, nDrawId, nTab );
+ if (pObject)
+ {
+ SdrView aEditView(*pModel);
+ aEditView.ShowSdrPage(aEditView.GetModel()->GetPage(nTab));
+ SdrPageView* pPV = aEditView.GetSdrPageView();
+ aEditView.MarkObj(pObject, pPV);
+
+ // tdf125520 this is a D&D-start potentially with an OLE object. If
+ // so, we need to do similar as e.g. in ScDrawView::BeginDrag so that
+ // the temporary SdrModel for transfer does have a GetPersist() so
+ // that the EmbeddedObjectContainer gets copied. We need no CheckOle
+ // here, test is simpler.
+ ScDocShellRef aDragShellRef;
+ if(SdrObjKind::OLE2 == pObject->GetObjIdentifier())
+ {
+ aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately
+ aDragShellRef->DoInitNew();
+ }
+
+ ScDrawLayer::SetGlobalDrawPersist(aDragShellRef.get());
+ std::unique_ptr<SdrModel> pDragModel(aEditView.CreateMarkedObjModel());
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+
+ TransferableObjectDescriptor aObjDesc;
+ pSrcShell->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pSrcShell->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScDrawTransferObj ctor
+
+ rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pDragModel), pSrcShell, aObjDesc );
+
+ pTransferObj->SetDragSourceObj( *pObject, nTab );
+ pTransferObj->SetDragSourceFlags(ScDragSrc::Navigator);
+
+ SC_MOD()->SetDragObject( nullptr, pTransferObj.get() );
+
+ rtl::Reference<TransferDataContainer> xHelper(pTransferObj);
+ rTreeView.enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
+
+ bDisallow = false;
+ }
+ }
+
+ return bDisallow;
+}
+
+static bool lcl_DoDragCells( ScDocShell* pSrcShell, const ScRange& rRange, ScDragSrc nFlags, weld::TreeView& rTreeView )
+{
+ bool bDisallow = true;
+
+ ScDocument& rSrcDoc = pSrcShell->GetDocument();
+ ScMarkData aMark(rSrcDoc.GetSheetLimits());
+ aMark.SelectTable( rRange.aStart.Tab(), true );
+ aMark.SetMarkArea( rRange );
+
+ if ( !rSrcDoc.HasSelectedBlockMatrixFragment( rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(),
+ aMark ) )
+ {
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+ ScClipParam aClipParam(rRange, false);
+ rSrcDoc.CopyToClip(aClipParam, pClipDoc.get(), &aMark, false, false);
+ // pClipDoc->ExtendMerge( rRange, sal_True );
+
+ TransferableObjectDescriptor aObjDesc;
+ pSrcShell->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pSrcShell->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScTransferObj ctor
+
+ rtl::Reference<ScTransferObj> pTransferObj = new ScTransferObj( std::move(pClipDoc), aObjDesc );
+
+ pTransferObj->SetDragSource( pSrcShell, aMark );
+ pTransferObj->SetDragSourceFlags( nFlags );
+
+ SC_MOD()->SetDragObject( pTransferObj.get(), nullptr ); // for internal D&D
+
+ rtl::Reference<TransferDataContainer> xHelper(pTransferObj);
+ rTreeView.enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
+
+ bDisallow = false;
+ }
+
+ return bDisallow;
+}
+
+IMPL_LINK(ScContentTree, DragBeginHdl, bool&, rUnsetDragIcon, bool)
+{
+ rUnsetDragIcon = true;
+
+ StoreNavigatorSettings();
+
+ bool bDisallow = true;
+
+ std::unique_ptr<ScDocumentLoader> pDocLoader;
+
+ ScModule* pScMod = SC_MOD();
+
+ ScContentId nType;
+ sal_uLong nChild;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_cursor(xEntry.get()))
+ xEntry.reset();
+
+ GetEntryIndexes(nType, nChild, xEntry.get());
+
+ if( xEntry &&
+ (nChild != SC_CONTENT_NOCHILD) &&
+ (nType != ScContentId::ROOT) &&
+ (nType != ScContentId::NOTE) &&
+ (nType != ScContentId::AREALINK) )
+ {
+ OUString aText(m_xTreeView->get_text(*xEntry));
+
+ ScDocument* pLocalDoc = nullptr; // for URL drop
+ OUString aDocName;
+ if (bHiddenDoc)
+ aDocName = aHiddenName;
+ else
+ {
+ ScDocShell* pDocSh = GetManualOrCurrent();
+ if (pDocSh)
+ {
+ if (pDocSh->HasName())
+ aDocName = pDocSh->GetMedium()->GetName();
+ else
+ pLocalDoc = &pDocSh->GetDocument(); // drop only in this document
+ }
+ }
+
+ bool bDoLinkTrans = false; // use ScLinkTransferObj
+ OUString aLinkURL; // for ScLinkTransferObj
+ OUString aLinkText;
+
+ sal_uInt16 nDropMode = pParentWindow->GetDropMode();
+ switch ( nDropMode )
+ {
+ case SC_DROPMODE_URL:
+ {
+ OUString aUrl = aDocName + "#" + aText;
+
+ pScMod->SetDragJump( pLocalDoc, aUrl, aText );
+
+ if (!aDocName.isEmpty())
+ {
+ // provide URL to outside only if the document has a name
+ // (without name, only internal D&D via SetDragJump)
+
+ aLinkURL = aUrl;
+ aLinkText = aText;
+ }
+ bDoLinkTrans = true;
+ }
+ break;
+ case SC_DROPMODE_LINK:
+ {
+ if ( !aDocName.isEmpty() ) // link only to named documents
+ {
+ // for internal D&D, set flag to insert a link
+
+ switch ( nType )
+ {
+ case ScContentId::TABLE:
+ pScMod->SetDragLink( aDocName, aText, OUString() );
+ bDoLinkTrans = true;
+ break;
+ case ScContentId::RANGENAME:
+ case ScContentId::DBAREA:
+ pScMod->SetDragLink( aDocName, OUString(), aText );
+ bDoLinkTrans = true;
+ break;
+
+ // other types cannot be linked
+ default: break;
+ }
+ }
+ }
+ break;
+ case SC_DROPMODE_COPY:
+ {
+ ScDocShell* pSrcShell = nullptr;
+ if ( bHiddenDoc )
+ {
+ OUString aFilter, aOptions;
+ OUString aURL = aHiddenName;
+ pDocLoader.reset(new ScDocumentLoader( aURL, aFilter, aOptions ));
+ if (!pDocLoader->IsError())
+ pSrcShell = pDocLoader->GetDocShell();
+ }
+ else
+ pSrcShell = GetManualOrCurrent();
+
+ if ( pSrcShell )
+ {
+ ScDocument& rSrcDoc = pSrcShell->GetDocument();
+ if ( nType == ScContentId::RANGENAME || nType == ScContentId::DBAREA )
+ {
+ ScRange aRange;
+ if ( lcl_GetRange( rSrcDoc, nType, aText, aRange ) )
+ {
+ bDisallow = lcl_DoDragCells( pSrcShell, aRange, ScDragSrc::Navigator, *m_xTreeView );
+ }
+ }
+ else if ( nType == ScContentId::TABLE )
+ {
+ SCTAB nTab;
+ if ( rSrcDoc.GetTable( aText, nTab ) )
+ {
+ ScRange aRange(0, 0, nTab, rSrcDoc.MaxCol(), rSrcDoc.MaxRow(), nTab);
+ bDisallow = lcl_DoDragCells( pSrcShell, aRange, (ScDragSrc::Navigator | ScDragSrc::Table), *m_xTreeView );
+ }
+ }
+ else if ( nType == ScContentId::GRAPHIC || nType == ScContentId::OLEOBJECT ||
+ nType == ScContentId::DRAWING )
+ {
+ bDisallow = lcl_DoDragObject( pSrcShell, aText, nType, *m_xTreeView );
+
+ // during ExecuteDrag the navigator can be deleted
+ // -> don't access member anymore !!!
+ }
+ }
+ }
+ break;
+ }
+
+ if (bDoLinkTrans)
+ {
+ if (!aLinkURL.isEmpty())
+ m_xTransferObj->SetLinkURL(aLinkURL, aLinkText);
+
+ rtl::Reference<TransferDataContainer> xHelper(m_xTransferObj);
+ m_xTreeView->enable_drag_source(xHelper, DND_ACTION_COPY | DND_ACTION_LINK);
+
+ bDisallow = false;
+ }
+ }
+
+ return bDisallow;
+}
+
+void ScContentTree::LoadFile( const OUString& rUrl )
+{
+ OUString aDocName = rUrl;
+ sal_Int32 nPos = aDocName.indexOf('#');
+ if ( nPos != -1 )
+ aDocName = aDocName.copy(0, nPos); // only the name without #...
+
+ OUString aURL = aDocName;
+ OUString aFilter, aOptions;
+ ScDocumentLoader aLoader( aURL, aFilter, aOptions );
+ if ( aLoader.IsError() )
+ return;
+
+ bHiddenDoc = true;
+ aHiddenName = aDocName;
+ aHiddenTitle = aLoader.GetTitle();
+ pHiddenDocument = aLoader.GetDocument();
+
+ Refresh(); // get content from loaded document
+
+ pHiddenDocument = nullptr;
+
+ pParentWindow->GetDocNames( &aHiddenTitle ); // fill list
+
+ // document is closed again by ScDocumentLoader in dtor
+}
+
+void ScContentTree::SetRootType( ScContentId nNew )
+{
+ if ( nNew != nRootType )
+ {
+ nRootType = nNew;
+ Refresh();
+
+ ScNavipiCfg& rCfg = SC_MOD()->GetNavipiCfg();
+ rCfg.SetRootType( nRootType );
+ }
+}
+
+void ScContentTree::ToggleRoot() // after selection
+{
+ ScContentId nNew = ScContentId::ROOT;
+ if ( nRootType == ScContentId::ROOT )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator());
+ if (m_xTreeView->get_cursor(xEntry.get()))
+ {
+ std::unique_ptr<weld::TreeIter> xParent(m_xTreeView->make_iterator(xEntry.get()));
+ if (!m_xTreeView->iter_parent(*xParent))
+ xParent.reset();
+
+ for (sal_uInt16 i=1; i<=int(ScContentId::LAST); i++)
+ {
+ if (!m_aRootNodes[static_cast<ScContentId>(i)])
+ continue;
+ if ((m_xTreeView->iter_compare(*xEntry, *m_aRootNodes[static_cast<ScContentId>(i)]) == 0) ||
+ (xParent && m_xTreeView->iter_compare(*xParent, *m_aRootNodes[static_cast<ScContentId>(i)]) == 0))
+ {
+ nNew = static_cast<ScContentId>(i);
+ }
+ }
+ }
+ }
+
+ SetRootType( nNew );
+}
+
+void ScContentTree::ResetManualDoc()
+{
+ aManualDoc.clear();
+ bHiddenDoc = false;
+
+ ActiveDocChanged();
+}
+
+bool ScContentTree::ActiveDocChanged()
+{
+ bool bRefreshed = false;
+
+ if ( !bHiddenDoc && aManualDoc.isEmpty() )
+ {
+ Refresh(); // content only if automatic
+ bRefreshed = true;
+ }
+
+ // if flag active Listbox must be updated
+
+ OUString aCurrent;
+ if ( bHiddenDoc )
+ aCurrent = aHiddenTitle;
+ else
+ {
+ ScDocShell* pSh = GetManualOrCurrent();
+ if (pSh)
+ aCurrent = pSh->GetTitle();
+ else
+ {
+ // document is no longer available
+
+ aManualDoc.clear(); // again automatically
+ Refresh();
+ bRefreshed = true;
+ pSh = GetManualOrCurrent(); // should be active now
+ if (pSh)
+ aCurrent = pSh->GetTitle();
+ }
+ }
+ pParentWindow->GetDocNames( &aCurrent ); // select
+
+ return bRefreshed;
+}
+
+void ScContentTree::SetManualDoc(const OUString& rName)
+{
+ aManualDoc = rName;
+ if (!bHiddenDoc)
+ {
+ Refresh();
+ pParentWindow->GetDocNames( &aManualDoc ); // select
+ }
+}
+
+void ScContentTree::SelectDoc(const OUString& rName) // rName like shown in Menu/Listbox
+{
+ if ( rName == pParentWindow->aStrActiveWin )
+ {
+ ResetManualDoc();
+ return;
+ }
+
+ // omit "active" or "inactive"
+
+ OUString aRealName = rName;
+ sal_Int32 nLen = rName.getLength();
+ sal_Int32 nActiveStart = nLen - pParentWindow->aStrActive.getLength();
+ if ( rName.subView( nActiveStart ) == pParentWindow->aStrActive )
+ aRealName = rName.copy( 0, nActiveStart );
+ sal_Int32 nNotActiveStart = nLen - pParentWindow->aStrNotActive.getLength();
+ if ( rName.subView( nNotActiveStart ) == pParentWindow->aStrNotActive )
+ aRealName = rName.copy( 0, nNotActiveStart );
+
+ bool bLoaded = false;
+
+ // Is it a normally loaded document?
+
+ SfxObjectShell* pSh = SfxObjectShell::GetFirst();
+ while ( pSh && !bLoaded )
+ {
+ if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
+ if ( pSh->GetTitle() == aRealName )
+ bLoaded = true;
+ pSh = SfxObjectShell::GetNext( *pSh );
+ }
+
+ if (bLoaded)
+ {
+ bHiddenDoc = false;
+ SetManualDoc(aRealName);
+ }
+ else if (!aHiddenTitle.isEmpty()) // hidden selected
+ {
+ if (!bHiddenDoc)
+ LoadFile(aHiddenName);
+ }
+ else
+ {
+ OSL_FAIL("SelectDoc: not found");
+ }
+}
+
+void ScContentTree::SelectEntryByName(const ScContentId nRoot, std::u16string_view rName)
+{
+ weld::TreeIter* pParent = m_aRootNodes[nRoot].get();
+
+ if (pParent || !m_xTreeView->iter_has_child(*pParent))
+ return;
+
+ std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(pParent));
+ bool bEntry = m_xTreeView->iter_children(*xEntry);
+
+ while (bEntry)
+ {
+ if (m_xTreeView->get_text(*xEntry) == rName)
+ {
+ m_xTreeView->select(*xEntry);
+ m_xTreeView->set_cursor(*xEntry);
+
+ // Scroll to the selected item
+ m_xTreeView->scroll_to_row(*xEntry);
+
+ StoreNavigatorSettings();
+
+ return;
+ }
+ bEntry = m_xTreeView->iter_next(*xEntry);
+ }
+}
+
+void ScContentTree::ApplyNavigatorSettings()
+{
+ const ScNavigatorSettings* pSettings = ScNavigatorDlg::GetNavigatorSettings();
+ if( !pSettings )
+ return;
+
+ ScContentId nRootSel = pSettings->GetRootSelected();
+ auto nChildSel = pSettings->GetChildSelected();
+
+ // tdf#133079 ensure Sheet root is selected if nothing
+ // else would be
+ if (nRootSel == ScContentId::ROOT)
+ {
+ nRootSel = ScContentId::TABLE;
+ nChildSel = SC_CONTENT_NOCHILD;
+ }
+
+ for( int i = 1; i <= int(ScContentId::LAST); ++i )
+ {
+ ScContentId nEntry = static_cast<ScContentId>(i);
+ if( m_aRootNodes[ nEntry ] )
+ {
+ // gray or ungray
+ if (!m_xTreeView->iter_has_child(*m_aRootNodes[nEntry]))
+ m_xTreeView->set_sensitive(*m_aRootNodes[nEntry], false);
+ else
+ m_xTreeView->set_sensitive(*m_aRootNodes[nEntry], true);
+
+ // expand
+ bool bExp = pSettings->IsExpanded( nEntry );
+ if (bExp != m_xTreeView->get_row_expanded(*m_aRootNodes[nEntry]))
+ {
+ if( bExp )
+ m_xTreeView->expand_row(*m_aRootNodes[nEntry]);
+ else
+ m_xTreeView->collapse_row(*m_aRootNodes[nEntry]);
+ }
+
+ // select
+ if( nRootSel == nEntry )
+ {
+ std::unique_ptr<weld::TreeIter> xEntry;
+ if (bExp && (nChildSel != SC_CONTENT_NOCHILD))
+ {
+ xEntry = m_xTreeView->make_iterator(m_aRootNodes[nEntry].get());
+ if (!m_xTreeView->iter_children(*xEntry) || !m_xTreeView->iter_nth_sibling(*xEntry, nChildSel))
+ xEntry.reset();
+ }
+ m_xTreeView->select(xEntry ? *xEntry : *m_aRootNodes[nEntry]);
+ m_xTreeView->set_cursor(xEntry ? *xEntry : *m_aRootNodes[nEntry]);
+ }
+ }
+ }
+}
+
+void ScContentTree::StoreNavigatorSettings()
+{
+ if (m_nAsyncMouseReleaseId)
+ {
+ Application::RemoveUserEvent(m_nAsyncMouseReleaseId);
+ m_nAsyncMouseReleaseId = nullptr;
+ }
+
+ ScNavigatorSettings* pSettings = ScNavigatorDlg::GetNavigatorSettings();
+ if( !pSettings )
+ return;
+
+ for( int i = 1; i <= int(ScContentId::LAST); ++i )
+ {
+ ScContentId nEntry = static_cast<ScContentId>(i);
+ bool bExp = m_aRootNodes[nEntry] && m_xTreeView->get_row_expanded(*m_aRootNodes[nEntry]);
+ pSettings->SetExpanded( nEntry, bExp );
+ }
+
+ std::unique_ptr<weld::TreeIter> xCurEntry(m_xTreeView->make_iterator());
+ if (!m_xTreeView->get_cursor(xCurEntry.get()))
+ xCurEntry.reset();
+
+ ScContentId nRoot;
+ sal_uLong nChild;
+ GetEntryIndexes(nRoot, nChild, xCurEntry.get());
+
+ pSettings->SetRootSelected( nRoot );
+ pSettings->SetChildSelected( nChild );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/navipi/navcitem.cxx b/sc/source/ui/navipi/navcitem.cxx
new file mode 100644
index 000000000..871fbd445
--- /dev/null
+++ b/sc/source/ui/navipi/navcitem.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <osl/diagnose.h>
+
+#include <navcitem.hxx>
+#include <navipi.hxx>
+#include <viewdata.hxx>
+#include <sc.hrc>
+
+ScNavigatorControllerItem::ScNavigatorControllerItem( sal_uInt16 nIdP,
+ ScNavigatorDlg& rDlg,
+ SfxBindings& rBindings )
+ : SfxControllerItem ( nIdP, rBindings ),
+ rNavigatorDlg ( rDlg )
+{
+}
+
+void ScNavigatorControllerItem::StateChangedAtToolBoxControl( sal_uInt16 /* nSID */, SfxItemState /* eState */,
+ const SfxPoolItem* pItem )
+{
+ switch( GetId() )
+ {
+ case SID_CURRENTCELL:
+ if ( pItem )
+ {
+ ScViewData* pViewData = rNavigatorDlg.GetViewData();
+ const SfxStringItem* pCellPosItem = dynamic_cast<const SfxStringItem*>( pItem );
+
+ OSL_ENSURE( pCellPosItem, "SfxStringItem expected!" );
+
+ if (pCellPosItem && pViewData)
+ {
+ const OUString& aAddress( pCellPosItem->GetValue() );
+ ScAddress aScAddress;
+ aScAddress.Parse(aAddress, pViewData->GetDocument());
+
+ SCCOL nCol = aScAddress.Col()+1;
+ SCROW nRow = aScAddress.Row()+1;
+
+ rNavigatorDlg.UpdateColumn( &nCol );
+ rNavigatorDlg.UpdateRow ( &nRow );
+ }
+ }
+ break;
+
+ case SID_CURRENTTAB:
+ if ( pItem )
+ {
+ const SfxUInt16Item* pTabItem = dynamic_cast< const SfxUInt16Item *>( pItem );
+
+ OSL_ENSURE( pTabItem, "SfxUInt16Item expected!" );
+
+ // table for Basic is 1-based
+ if ( pTabItem && pTabItem->GetValue() )
+ {
+ SCTAB nTab = pTabItem->GetValue() - 1;
+
+ rNavigatorDlg.UpdateTable( &nTab );
+ rNavigatorDlg.UpdateColumn();
+ rNavigatorDlg.UpdateRow();
+ }
+ }
+ break;
+
+ case SID_CURRENTDOC:
+
+ // nothing is done via SfxHintId::DocChanged
+
+ break;
+
+ case SID_SELECT_SCENARIO:
+ rNavigatorDlg.m_xWndScenarios->NotifyState(pItem);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/navipi/navipi.cxx b/sc/source/ui/navipi/navipi.cxx
new file mode 100644
index 000000000..44ba8fee2
--- /dev/null
+++ b/sc/source/ui/navipi/navipi.cxx
@@ -0,0 +1,965 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/event.hxx>
+#include <sfx2/navigat.hxx>
+#include <svl/stritem.hxx>
+#include <unotools/charclass.hxx>
+
+#include <viewdata.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <rangeutl.hxx>
+#include <sc.hrc>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <scresid.hxx>
+#include <scmod.hxx>
+#include <navicfg.hxx>
+#include <navcitem.hxx>
+#include <navipi.hxx>
+#include <navsett.hxx>
+#include <markdata.hxx>
+
+#include <com/sun/star/uno/Reference.hxx>
+
+using namespace com::sun::star;
+
+// maximum values for UI
+static SCCOL SCNAV_MAXCOL(const ScSheetLimits& rLimits) { return rLimits.GetMaxColCount(); }
+static sal_Int32 SCNAV_COLDIGITS(const ScSheetLimits& rLimits)
+{
+ return static_cast<sal_Int32>( floor( log10( static_cast<double>(SCNAV_MAXCOL(rLimits)))) ) + 1; // 1...256...18278
+}
+static sal_Int32 SCNAV_COLLETTERS(const ScSheetLimits& rLimits)
+{
+ return ::ScColToAlpha(SCNAV_MAXCOL(rLimits)).getLength(); // A...IV...ZZZ
+}
+
+static SCROW SCNAV_MAXROW(const ScSheetLimits& rSheetLimits)
+{
+ return rSheetLimits.GetMaxRowCount();
+}
+
+void ScNavigatorDlg::ReleaseFocus()
+{
+ SfxViewShell* pCurSh = SfxViewShell::Current();
+
+ if ( pCurSh )
+ {
+ vcl::Window* pShellWnd = pCurSh->GetWindow();
+ if ( pShellWnd )
+ pShellWnd->GrabFocus();
+ }
+}
+
+namespace
+{
+ SCCOL NumToAlpha(const ScSheetLimits& rSheetLimits, SCCOL nColNo, OUString& rStr)
+ {
+ if ( nColNo > SCNAV_MAXCOL(rSheetLimits) )
+ nColNo = SCNAV_MAXCOL(rSheetLimits);
+ else if ( nColNo < 1 )
+ nColNo = 1;
+
+ ::ScColToAlpha( rStr, nColNo - 1);
+
+ return nColNo;
+ }
+
+ SCCOL AlphaToNum(const ScDocument& rDoc, OUString& rStr)
+ {
+ SCCOL nColumn = 0;
+
+ if ( CharClass::isAsciiAlpha( rStr) )
+ {
+ rStr = rStr.toAsciiUpperCase();
+
+ if (::AlphaToCol( rDoc, nColumn, rStr))
+ ++nColumn;
+
+ if ( (rStr.getLength() > SCNAV_COLLETTERS(rDoc.GetSheetLimits())) ||
+ (nColumn > SCNAV_MAXCOL(rDoc.GetSheetLimits())) )
+ {
+ nColumn = SCNAV_MAXCOL(rDoc.GetSheetLimits());
+ NumToAlpha( rDoc.GetSheetLimits(), nColumn, rStr );
+ }
+ }
+ else
+ rStr.clear();
+
+ return nColumn;
+ }
+
+ SCCOL NumStrToAlpha(const ScSheetLimits& rSheetLimits, OUString& rStr)
+ {
+ SCCOL nColumn = 0;
+
+ if ( CharClass::isAsciiNumeric(rStr) )
+ nColumn = NumToAlpha( rSheetLimits, static_cast<SCCOL>(rStr.toInt32()), rStr );
+ else
+ rStr.clear();
+
+ return nColumn;
+ }
+}
+
+IMPL_LINK(ScNavigatorDlg, ParseRowInputHdl, int*, result, bool)
+{
+ SCCOL nCol;
+
+ OUString aStrCol = m_xEdCol->get_text();
+
+ if (!aStrCol.isEmpty())
+ {
+ // nKeyGroup is no longer set at VCL, in cause of lack of keyinput
+
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ auto& rDoc = pViewSh->GetViewData().GetDocument();
+ if ( CharClass::isAsciiNumeric(aStrCol) )
+ nCol = NumStrToAlpha( rDoc.GetSheetLimits(), aStrCol );
+ else
+ nCol = AlphaToNum( rDoc, aStrCol );
+ }
+ else
+ nCol = 0;
+
+ *result = nCol;
+ return true;
+}
+
+IMPL_LINK_NOARG(ScNavigatorDlg, ExecuteColHdl, weld::Entry&, bool)
+{
+ ReleaseFocus();
+
+ SCROW nRow = m_xEdRow->get_value();
+ SCCOL nCol = m_xEdCol->get_value();
+
+ if ( (nCol > 0) && (nRow > 0) )
+ SetCurrentCell(nCol - 1, nRow - 1);
+
+ return true;
+}
+
+IMPL_LINK_NOARG(ScNavigatorDlg, FormatRowOutputHdl, weld::SpinButton&, void)
+{
+ OUString aStr;
+ ::ScColToAlpha(aStr, m_xEdCol->get_value() - 1);
+ m_xEdCol->set_text(aStr);
+}
+
+IMPL_LINK_NOARG(ScNavigatorDlg, ExecuteRowHdl, weld::Entry&, bool)
+{
+ ReleaseFocus();
+
+ SCCOL nCol = m_xEdCol->get_value();
+ SCROW nRow = m_xEdRow->get_value();
+
+ if ( (nCol > 0) && (nRow > 0) )
+ SetCurrentCell(nCol - 1, nRow - 1);
+
+ return true;
+}
+
+IMPL_LINK(ScNavigatorDlg, DocumentSelectHdl, weld::ComboBox&, rListBox, void)
+{
+ ScNavigatorDlg::ReleaseFocus();
+
+ OUString aDocName = rListBox.get_active_text();
+ m_xLbEntries->SelectDoc(aDocName);
+}
+
+IMPL_LINK(ScNavigatorDlg, ToolBoxSelectHdl, const OString&, rSelId, void)
+{
+ // Switch the mode?
+ if (rSelId == "contents" || rSelId == "scenarios")
+ {
+ NavListMode eOldMode = eListMode;
+ NavListMode eNewMode;
+
+ if (rSelId == "scenarios")
+ {
+ if (eOldMode == NAV_LMODE_SCENARIOS)
+ eNewMode = NAV_LMODE_AREAS;
+ else
+ eNewMode = NAV_LMODE_SCENARIOS;
+ }
+ else // on/off
+ {
+ if (eOldMode == NAV_LMODE_NONE)
+ eNewMode = NAV_LMODE_AREAS;
+ else
+ eNewMode = NAV_LMODE_NONE;
+ }
+ SetListMode(eNewMode);
+ UpdateButtons();
+ }
+ else if (rSelId == "dragmode")
+ m_xTbxCmd2->set_menu_item_active("dragmode", !m_xTbxCmd2->get_menu_item_active("dragmode"));
+ else
+ {
+ if (rSelId == "datarange")
+ MarkDataArea();
+ else if (rSelId == "start")
+ StartOfDataArea();
+ else if (rSelId == "end")
+ EndOfDataArea();
+ else if (rSelId == "toggle")
+ {
+ m_xLbEntries->ToggleRoot();
+ UpdateButtons();
+ }
+ }
+}
+
+IMPL_LINK(ScNavigatorDlg, ToolBoxDropdownClickHdl, const OString&, rCommand, void)
+{
+ if (!m_xTbxCmd2->get_menu_item_active(rCommand))
+ return;
+
+ // the popup menu of the drop mode has to be called in the
+ // click (button down) and not in the select (button up)
+ if (rCommand != "dragmode")
+ return;
+
+ switch (GetDropMode())
+ {
+ case 0:
+ m_xDragModeMenu->set_active("hyperlink", true);
+ break;
+ case 1:
+ m_xDragModeMenu->set_active("link", true);
+ break;
+ case 2:
+ m_xDragModeMenu->set_active("copy", true);
+ break;
+ }
+}
+
+IMPL_LINK(ScNavigatorDlg, MenuSelectHdl, const OString&, rIdent, void)
+{
+ if (rIdent == "hyperlink")
+ SetDropMode(0);
+ else if (rIdent == "link")
+ SetDropMode(1);
+ else if (rIdent == "copy")
+ SetDropMode(2);
+}
+
+void ScNavigatorDlg::UpdateButtons()
+{
+ NavListMode eMode = eListMode;
+ m_xTbxCmd2->set_item_active("scenarios", eMode == NAV_LMODE_SCENARIOS);
+ m_xTbxCmd1->set_item_active("contents", eMode != NAV_LMODE_NONE);
+
+ // the toggle button:
+ if (eMode == NAV_LMODE_SCENARIOS || eMode == NAV_LMODE_NONE)
+ {
+ m_xTbxCmd2->set_item_sensitive("toggle", false);
+ m_xTbxCmd2->set_item_active("toggle", false);
+ }
+ else
+ {
+ m_xTbxCmd2->set_item_sensitive("toggle", true);
+ bool bRootSet = m_xLbEntries->GetRootType() != ScContentId::ROOT;
+ m_xTbxCmd2->set_item_active("toggle", bRootSet);
+ }
+
+ OUString sImageId;
+ switch (nDropMode)
+ {
+ case SC_DROPMODE_URL:
+ sImageId = RID_BMP_DROP_URL;
+ break;
+ case SC_DROPMODE_LINK:
+ sImageId = RID_BMP_DROP_LINK;
+ break;
+ case SC_DROPMODE_COPY:
+ sImageId = RID_BMP_DROP_COPY;
+ break;
+ }
+ m_xTbxCmd2->set_item_icon_name("dragmode", sImageId);
+}
+
+ScNavigatorSettings::ScNavigatorSettings()
+ : mnRootSelected(ScContentId::ROOT)
+ , mnChildSelected(SC_CONTENT_NOCHILD)
+{
+ maExpandedVec.fill(false);
+}
+
+class ScNavigatorWin : public SfxNavigator
+{
+private:
+ std::unique_ptr<ScNavigatorDlg> m_xNavigator;
+public:
+ ScNavigatorWin(SfxBindings* _pBindings, SfxChildWindow* pMgr,
+ vcl::Window* pParent, SfxChildWinInfo* pInfo);
+ virtual void StateChanged(StateChangedType nStateChange) override;
+ virtual void dispose() override
+ {
+ m_xNavigator.reset();
+ SfxNavigator::dispose();
+ }
+ virtual ~ScNavigatorWin() override
+ {
+ disposeOnce();
+ }
+};
+
+ScNavigatorWin::ScNavigatorWin(SfxBindings* _pBindings, SfxChildWindow* _pMgr,
+ vcl::Window* _pParent, SfxChildWinInfo* pInfo)
+ : SfxNavigator(_pBindings, _pMgr, _pParent, pInfo)
+{
+ m_xNavigator = std::make_unique<ScNavigatorDlg>(_pBindings, m_xContainer.get(), this);
+ SetMinOutputSizePixel(GetOptimalSize());
+}
+
+ScNavigatorDlg::ScNavigatorDlg(SfxBindings* pB, weld::Widget* pParent, SfxNavigator* pNavigatorDlg)
+ : PanelLayout(pParent, "NavigatorPanel", "modules/scalc/ui/navigatorpanel.ui")
+ , rBindings(*pB)
+ , m_xEdCol(m_xBuilder->weld_spin_button("column"))
+ , m_xEdRow(m_xBuilder->weld_spin_button("row"))
+ , m_xTbxCmd1(m_xBuilder->weld_toolbar("toolbox1"))
+ , m_xTbxCmd2(m_xBuilder->weld_toolbar("toolbox2"))
+ , m_xLbEntries(new ScContentTree(m_xBuilder->weld_tree_view("contentbox"), this))
+ , m_xScenarioBox(m_xBuilder->weld_widget("scenariobox"))
+ , m_xWndScenarios(new ScScenarioWindow(*m_xBuilder,
+ ScResId(SCSTR_QHLP_SCEN_LISTBOX), ScResId(SCSTR_QHLP_SCEN_COMMENT)))
+ , m_xLbDocuments(m_xBuilder->weld_combo_box("documents"))
+ , m_xDragModeMenu(m_xBuilder->weld_menu("dragmodemenu"))
+ , m_xNavigatorDlg(pNavigatorDlg)
+ , aContentIdle("ScNavigatorDlg aContentIdle")
+ , aStrActiveWin(ScResId(SCSTR_ACTIVEWIN))
+ , pViewData(nullptr )
+ , eListMode(NAV_LMODE_NONE)
+ , nDropMode(SC_DROPMODE_URL)
+ , nCurCol(0)
+ , nCurRow(0)
+ , nCurTab(0)
+{
+ UpdateInitShow();
+
+ UpdateSheetLimits();
+ m_xEdRow->set_width_chars(5);
+ //max rows is 1,000,000, which is too long for typical use
+ m_xEdRow->connect_activate(LINK(this, ScNavigatorDlg, ExecuteRowHdl));
+
+ m_xEdCol->connect_activate(LINK(this, ScNavigatorDlg, ExecuteColHdl));
+ m_xEdCol->connect_output(LINK(this, ScNavigatorDlg, FormatRowOutputHdl));
+ m_xEdCol->connect_input(LINK(this, ScNavigatorDlg, ParseRowInputHdl));
+
+ m_xTbxCmd1->connect_clicked(LINK(this, ScNavigatorDlg, ToolBoxSelectHdl));
+ m_xTbxCmd2->connect_clicked(LINK(this, ScNavigatorDlg, ToolBoxSelectHdl));
+
+ m_xTbxCmd2->set_item_menu("dragmode", m_xDragModeMenu.get());
+ m_xDragModeMenu->connect_activate(LINK(this, ScNavigatorDlg, MenuSelectHdl));
+ m_xTbxCmd2->connect_menu_toggled(LINK(this, ScNavigatorDlg, ToolBoxDropdownClickHdl));
+
+ ScNavipiCfg& rCfg = SC_MOD()->GetNavipiCfg();
+ nDropMode = rCfg.GetDragMode();
+
+ m_xLbDocuments->set_size_request(42, -1); // set a nominal width so it takes width of surroundings
+ m_xLbDocuments->connect_changed(LINK(this, ScNavigatorDlg, DocumentSelectHdl));
+ aStrActive = " (" + ScResId(SCSTR_ACTIVE) + ")"; // " (active)"
+ aStrNotActive = " (" + ScResId(SCSTR_NOTACTIVE) + ")"; // " (not active)"
+ aStrHidden = " (" + ScResId(SCSTR_HIDDEN) + ")"; // " (hidden)"
+
+ rBindings.ENTERREGISTRATIONS();
+
+ mvBoundItems[0].reset(new ScNavigatorControllerItem(SID_CURRENTCELL,*this,rBindings));
+ mvBoundItems[1].reset(new ScNavigatorControllerItem(SID_CURRENTTAB,*this,rBindings));
+ mvBoundItems[2].reset(new ScNavigatorControllerItem(SID_CURRENTDOC,*this,rBindings));
+ mvBoundItems[3].reset(new ScNavigatorControllerItem(SID_SELECT_SCENARIO,*this,rBindings));
+
+ rBindings.LEAVEREGISTRATIONS();
+
+ StartListening( *(SfxGetpApp()) );
+ StartListening( rBindings );
+
+ // was a category chosen as root?
+ ScContentId nLastRoot = rCfg.GetRootType();
+ if ( nLastRoot != ScContentId::ROOT )
+ m_xLbEntries->SetRootType( nLastRoot );
+
+ GetDocNames(nullptr);
+
+ UpdateButtons();
+
+ UpdateColumn();
+ UpdateRow();
+ UpdateTable(nullptr);
+ m_xLbEntries->hide();
+ m_xScenarioBox->hide();
+
+ aContentIdle.SetInvokeHandler( LINK( this, ScNavigatorDlg, TimeHdl ) );
+ aContentIdle.SetPriority( TaskPriority::LOWEST );
+
+ m_xLbEntries->SetNavigatorDlgFlag(true);
+
+ // if scenario was active, switch on
+ NavListMode eNavMode = static_cast<NavListMode>(rCfg.GetListMode());
+ if (eNavMode == NAV_LMODE_SCENARIOS)
+ m_xTbxCmd2->set_item_active("scenarios", true);
+ else
+ eNavMode = NAV_LMODE_AREAS;
+ SetListMode(eNavMode);
+}
+
+weld::Window* ScNavigatorDlg::GetFrameWeld() const
+{
+ if (m_xNavigatorDlg)
+ return m_xNavigatorDlg->GetFrameWeld();
+ return PanelLayout::GetFrameWeld();
+}
+
+void ScNavigatorDlg::UpdateSheetLimits()
+{
+ if (ScViewData* pData = GetViewData())
+ {
+ ScDocument& rDoc = pData->GetDocument();
+ m_xEdRow->set_range(1, SCNAV_MAXROW(rDoc.GetSheetLimits()));
+ m_xEdCol->set_range(1, SCNAV_MAXCOL(rDoc.GetSheetLimits()));
+ m_xEdCol->set_width_chars(SCNAV_COLDIGITS(rDoc.GetSheetLimits())); // 1...256...18278 or A...IV...ZZZ
+ }
+}
+
+void ScNavigatorDlg::UpdateInitShow()
+{
+ // When the navigator is displayed in the sidebar, or is otherwise
+ // docked, it has the whole deck to fill. Therefore hide the button that
+ // hides all controls below the top two rows of buttons.
+ m_xTbxCmd1->set_item_visible("contents", ParentIsFloatingWindow(m_xNavigatorDlg));
+}
+
+void ScNavigatorWin::StateChanged(StateChangedType nStateChange)
+{
+ SfxNavigator::StateChanged(nStateChange);
+ if (nStateChange == StateChangedType::InitShow)
+ m_xNavigator->UpdateInitShow();
+}
+
+ScNavigatorDlg::~ScNavigatorDlg()
+{
+ aContentIdle.Stop();
+
+ for (auto & p : mvBoundItems)
+ p.reset();
+ pMarkArea.reset();
+
+ EndListening( *(SfxGetpApp()) );
+ EndListening( rBindings );
+
+ m_xEdCol.reset();
+ m_xEdRow.reset();
+ m_xTbxCmd1.reset();
+ m_xTbxCmd2.reset();
+ m_xDragModeMenu.reset();
+ m_xLbEntries.reset();
+ m_xWndScenarios.reset();
+ m_xScenarioBox.reset();
+ m_xLbDocuments.reset();
+}
+
+void ScNavigatorDlg::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if (const SfxEventHint* pHint = dynamic_cast<const SfxEventHint*>(&rHint))
+ {
+ if (pHint->GetEventId() == SfxEventHintId::ActivateDoc)
+ {
+ UpdateSheetLimits();
+ bool bRefreshed = m_xLbEntries->ActiveDocChanged();
+ // UpdateAll just possibly calls Refresh (and always
+ // ContentUpdated) so if ActiveDocChanged already called Refresh
+ // skip re-calling it
+ if (bRefreshed)
+ ContentUpdated();
+ else
+ UpdateAll();
+ }
+ }
+ else
+ {
+ const SfxHintId nHintId = rHint.GetId();
+
+ if (nHintId == SfxHintId::ScDocNameChanged)
+ {
+ m_xLbEntries->ActiveDocChanged();
+ }
+ else if (NAV_LMODE_NONE == eListMode)
+ {
+ // Table not any more
+ }
+ else
+ {
+ switch ( nHintId )
+ {
+ case SfxHintId::ScTablesChanged:
+ m_xLbEntries->Refresh( ScContentId::TABLE );
+ break;
+
+ case SfxHintId::ScDbAreasChanged:
+ m_xLbEntries->Refresh( ScContentId::DBAREA );
+ break;
+
+ case SfxHintId::ScAreasChanged:
+ m_xLbEntries->Refresh( ScContentId::RANGENAME );
+ break;
+
+ case SfxHintId::ScDrawChanged:
+ m_xLbEntries->Refresh( ScContentId::GRAPHIC );
+ m_xLbEntries->Refresh( ScContentId::OLEOBJECT );
+ m_xLbEntries->Refresh( ScContentId::DRAWING );
+ break;
+
+ case SfxHintId::ScAreaLinksChanged:
+ m_xLbEntries->Refresh( ScContentId::AREALINK );
+ break;
+
+ // SfxHintId::DocChanged not only at document change
+
+ case SfxHintId::ScNavigatorUpdateAll:
+ UpdateAll();
+ break;
+
+ case SfxHintId::ScDataChanged:
+ case SfxHintId::ScAnyDataChanged:
+ aContentIdle.Start(); // Do not search notes immediately
+ break;
+ case SfxHintId::ScSelectionChanged:
+ UpdateSelection();
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+IMPL_LINK( ScNavigatorDlg, TimeHdl, Timer*, pIdle, void )
+{
+ if ( pIdle != &aContentIdle )
+ return;
+
+ m_xLbEntries->Refresh( ScContentId::NOTE );
+}
+
+void ScNavigatorDlg::SetDropMode(sal_uInt16 nNew)
+{
+ nDropMode = nNew;
+ UpdateButtons();
+ ScNavipiCfg& rCfg = SC_MOD()->GetNavipiCfg();
+ rCfg.SetDragMode(nDropMode);
+}
+
+void ScNavigatorDlg::SetCurrentCell( SCCOL nColNo, SCROW nRowNo )
+{
+ if ((nColNo+1 == nCurCol) && (nRowNo+1 == nCurRow))
+ return;
+
+ // SID_CURRENTCELL == Item #0 clear cache, so it's possible
+ // setting the current cell even in combined areas
+ mvBoundItems[0]->ClearCache();
+
+ ScAddress aScAddress( nColNo, nRowNo, 0 );
+ OUString aAddr(aScAddress.Format(ScRefFlags::ADDR_ABS));
+
+ bool bUnmark = false;
+ if ( GetViewData() )
+ bUnmark = !pViewData->GetMarkData().IsCellMarked( nColNo, nRowNo );
+
+ SfxStringItem aPosItem( SID_CURRENTCELL, aAddr );
+ SfxBoolItem aUnmarkItem( FN_PARAM_1, bUnmark ); // cancel selection
+
+ rBindings.GetDispatcher()->ExecuteList(SID_CURRENTCELL,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aPosItem, &aUnmarkItem });
+}
+
+void ScNavigatorDlg::SetCurrentCellStr( const OUString& rName )
+{
+ mvBoundItems[0]->ClearCache();
+ SfxStringItem aNameItem( SID_CURRENTCELL, rName );
+
+ rBindings.GetDispatcher()->ExecuteList(SID_CURRENTCELL,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aNameItem });
+}
+
+void ScNavigatorDlg::SetCurrentTable( SCTAB nTabNo )
+{
+ if ( nTabNo != nCurTab )
+ {
+ // Table for basic is base-1
+ SfxUInt16Item aTabItem( SID_CURRENTTAB, static_cast<sal_uInt16>(nTabNo) + 1 );
+ rBindings.GetDispatcher()->ExecuteList(SID_CURRENTTAB,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aTabItem });
+ }
+}
+
+void ScNavigatorDlg::SetCurrentTableStr( std::u16string_view rName )
+{
+ if (!GetViewData()) return;
+
+ ScDocument& rDoc = pViewData->GetDocument();
+ SCTAB nCount = rDoc.GetTableCount();
+ OUString aTabName;
+ SCTAB nLastSheet = 0;
+
+ for (SCTAB i = 0; i<nCount; i++)
+ {
+ rDoc.GetName(i, aTabName);
+ if (aTabName == rName)
+ {
+ // Check if this is a Scenario sheet and if so select the sheet
+ // where it belongs to, which is the previous non-Scenario sheet.
+ if (rDoc.IsScenario(i))
+ {
+ SetCurrentTable(nLastSheet);
+ return;
+ }
+ else
+ {
+ SetCurrentTable(i);
+ return;
+ }
+ }
+ else
+ {
+ if (!rDoc.IsScenario(i))
+ nLastSheet = i;
+ }
+ }
+}
+
+void ScNavigatorDlg::SetCurrentObject( const OUString& rName )
+{
+ SfxStringItem aNameItem( SID_CURRENTOBJECT, rName );
+ rBindings.GetDispatcher()->ExecuteList( SID_CURRENTOBJECT,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aNameItem });
+}
+
+void ScNavigatorDlg::SetCurrentDoc( const OUString& rDocName ) // activate
+{
+ SfxStringItem aDocItem( SID_CURRENTDOC, rDocName );
+ rBindings.GetDispatcher()->ExecuteList( SID_CURRENTDOC,
+ SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aDocItem });
+}
+
+void ScNavigatorDlg::UpdateSelection()
+{
+ ScTabViewShell* pViewSh = GetTabViewShell();
+ if( !pViewSh )
+ return;
+
+ uno::Reference< drawing::XShapes > xShapes = pViewSh->getSelectedXShapes();
+ if( !xShapes )
+ return;
+
+ uno::Reference< container::XIndexAccess > xIndexAccess(
+ xShapes, uno::UNO_QUERY_THROW );
+ if( xIndexAccess->getCount() > 1 )
+ return;
+ uno::Reference< drawing::XShape > xShape;
+ if( xIndexAccess->getByIndex(0) >>= xShape )
+ {
+ uno::Reference< container::XNamed > xNamed( xShape, uno::UNO_QUERY_THROW );
+ OUString sName = xNamed->getName();
+ if (!sName.isEmpty())
+ {
+ m_xLbEntries->SelectEntryByName( ScContentId::DRAWING, sName );
+ }
+ }
+}
+
+ScTabViewShell* ScNavigatorDlg::GetTabViewShell()
+{
+ return dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+}
+
+ScNavigatorSettings* ScNavigatorDlg::GetNavigatorSettings()
+{
+ // Don't store the settings pointer here, because the settings belong to
+ // the view, and the view may be closed while the navigator is open (reload).
+ // If the pointer is cached here again later for performance reasons, it has to
+ // be forgotten when the view is closed.
+
+ ScTabViewShell* pViewSh = GetTabViewShell();
+ return pViewSh ? pViewSh->GetNavigatorSettings() : nullptr;
+}
+
+ScViewData* ScNavigatorDlg::GetViewData()
+{
+ ScTabViewShell* pViewSh = GetTabViewShell();
+ pViewData = pViewSh ? &pViewSh->GetViewData() : nullptr;
+ return pViewData;
+}
+
+void ScNavigatorDlg::UpdateColumn( const SCCOL* pCol )
+{
+ if ( pCol )
+ nCurCol = *pCol;
+ else if ( GetViewData() )
+ nCurCol = pViewData->GetCurX() + 1;
+
+ m_xEdCol->set_value(nCurCol);
+}
+
+void ScNavigatorDlg::UpdateRow( const SCROW* pRow )
+{
+ if ( pRow )
+ nCurRow = *pRow;
+ else if ( GetViewData() )
+ nCurRow = pViewData->GetCurY() + 1;
+
+ m_xEdRow->set_value(nCurRow);
+}
+
+void ScNavigatorDlg::UpdateTable( const SCTAB* pTab )
+{
+ if ( pTab )
+ nCurTab = *pTab;
+ else if ( GetViewData() )
+ nCurTab = pViewData->GetTabNo();
+}
+
+void ScNavigatorDlg::UpdateAll()
+{
+ switch (eListMode)
+ {
+ case NAV_LMODE_AREAS:
+ m_xLbEntries->Refresh();
+ break;
+ case NAV_LMODE_NONE:
+ //! ???
+ break;
+ default:
+ break;
+ }
+ ContentUpdated(); // not again
+}
+
+void ScNavigatorDlg::ContentUpdated()
+{
+ aContentIdle.Stop();
+}
+
+void ScNavigatorDlg::SetListMode(NavListMode eMode)
+{
+ if (eMode != eListMode)
+ {
+ bool bForceParentResize = ParentIsFloatingWindow(m_xNavigatorDlg) &&
+ (eMode == NAV_LMODE_NONE || eListMode == NAV_LMODE_NONE);
+ SfxNavigator* pNav = bForceParentResize ? m_xNavigatorDlg.get() : nullptr;
+ if (pNav && eMode == NAV_LMODE_NONE) //save last normal size on minimizing
+ aExpandedSize = pNav->GetSizePixel();
+
+ eListMode = eMode;
+
+ switch (eMode)
+ {
+ case NAV_LMODE_NONE:
+ ShowList(false);
+ break;
+ case NAV_LMODE_AREAS:
+ m_xLbEntries->Refresh();
+ ShowList(true);
+ break;
+ case NAV_LMODE_SCENARIOS:
+ ShowScenarios();
+ break;
+ }
+
+ UpdateButtons();
+
+ if (eMode != NAV_LMODE_NONE)
+ {
+ ScNavipiCfg& rCfg = SC_MOD()->GetNavipiCfg();
+ rCfg.SetListMode( static_cast<sal_uInt16>(eMode) );
+ }
+
+ if (pNav)
+ {
+ pNav->InvalidateChildSizeCache();
+ Size aOptimalSize(pNav->GetOptimalSize());
+ Size aNewSize(pNav->GetOutputSizePixel());
+ aNewSize.setHeight( eMode == NAV_LMODE_NONE ? aOptimalSize.Height() : aExpandedSize.Height() );
+ pNav->SetMinOutputSizePixel(aOptimalSize);
+ pNav->SetOutputSizePixel(aNewSize);
+ }
+ }
+
+ if (pMarkArea)
+ UnmarkDataArea();
+}
+
+void ScNavigatorDlg::ShowList(bool bShow)
+{
+ if (bShow)
+ {
+ m_xLbEntries->show();
+ m_xLbDocuments->show();
+ }
+ else
+ {
+ m_xLbEntries->hide();
+ m_xLbDocuments->hide();
+ }
+ m_xScenarioBox->hide();
+}
+
+void ScNavigatorDlg::ShowScenarios()
+{
+ rBindings.Invalidate( SID_SELECT_SCENARIO );
+ rBindings.Update( SID_SELECT_SCENARIO );
+
+ m_xScenarioBox->show();
+ m_xLbDocuments->show();
+ m_xLbEntries->hide();
+}
+
+// documents for Dropdown-Listbox
+void ScNavigatorDlg::GetDocNames( const OUString* pManualSel )
+{
+ m_xLbDocuments->clear();
+ m_xLbDocuments->freeze();
+
+ ScDocShell* pCurrentSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+
+ OUString aSelEntry;
+ SfxObjectShell* pSh = SfxObjectShell::GetFirst();
+ while ( pSh )
+ {
+ if ( dynamic_cast<const ScDocShell*>( pSh) != nullptr )
+ {
+ OUString aName = pSh->GetTitle();
+ OUString aEntry = aName;
+ if (pSh == pCurrentSh)
+ aEntry += aStrActive;
+ else
+ aEntry += aStrNotActive;
+ m_xLbDocuments->append_text(aEntry);
+
+ if ( pManualSel ? ( aName == *pManualSel )
+ : ( pSh == pCurrentSh ) )
+ aSelEntry = aEntry; // complete entry for selection
+ }
+
+ pSh = SfxObjectShell::GetNext( *pSh );
+ }
+
+ m_xLbDocuments->append_text(aStrActiveWin);
+
+ OUString aHidden = m_xLbEntries->GetHiddenTitle();
+ if (!aHidden.isEmpty())
+ {
+ OUString aEntry = aHidden + aStrHidden;
+ m_xLbDocuments->append_text(aEntry);
+
+ if ( pManualSel && aHidden == *pManualSel )
+ aSelEntry = aEntry;
+ }
+
+ m_xLbDocuments->thaw();
+
+ m_xLbDocuments->set_active_text(aSelEntry);
+}
+
+void ScNavigatorDlg::MarkDataArea()
+{
+ ScTabViewShell* pViewSh = GetTabViewShell();
+
+ if ( !pViewSh )
+ return;
+
+ if ( !pMarkArea )
+ pMarkArea.reset( new ScArea );
+
+ pViewSh->MarkDataArea();
+ const ScRange& aMarkRange = pViewSh->GetViewData().GetMarkData().GetMarkArea();
+ pMarkArea->nColStart = aMarkRange.aStart.Col();
+ pMarkArea->nRowStart = aMarkRange.aStart.Row();
+ pMarkArea->nColEnd = aMarkRange.aEnd.Col();
+ pMarkArea->nRowEnd = aMarkRange.aEnd.Row();
+ pMarkArea->nTab = aMarkRange.aStart.Tab();
+}
+
+void ScNavigatorDlg::UnmarkDataArea()
+{
+ ScTabViewShell* pViewSh = GetTabViewShell();
+
+ if ( pViewSh )
+ {
+ pViewSh->Unmark();
+ pMarkArea.reset();
+ }
+}
+
+void ScNavigatorDlg::StartOfDataArea()
+{
+ // pMarkArea evaluate ???
+
+ if ( GetViewData() )
+ {
+ ScMarkData& rMark = pViewData->GetMarkData();
+ const ScRange& aMarkRange = rMark.GetMarkArea();
+
+ SCCOL nCol = aMarkRange.aStart.Col();
+ SCROW nRow = aMarkRange.aStart.Row();
+
+ if ( (nCol+1 != m_xEdCol->get_value()) || (nRow+1 != m_xEdRow->get_value()) )
+ SetCurrentCell( nCol, nRow );
+ }
+}
+
+void ScNavigatorDlg::EndOfDataArea()
+{
+ // pMarkArea evaluate ???
+
+ if ( GetViewData() )
+ {
+ ScMarkData& rMark = pViewData->GetMarkData();
+ const ScRange& aMarkRange = rMark.GetMarkArea();
+
+ SCCOL nCol = aMarkRange.aEnd.Col();
+ SCROW nRow = aMarkRange.aEnd.Row();
+
+ if ( (nCol+1 != m_xEdCol->get_value()) || (nRow+1 != m_xEdRow->get_value()) )
+ SetCurrentCell( nCol, nRow );
+ }
+}
+
+SFX_IMPL_DOCKINGWINDOW(ScNavigatorWrapper, SID_NAVIGATOR);
+
+ScNavigatorWrapper::ScNavigatorWrapper(vcl::Window *_pParent, sal_uInt16 nId,
+ SfxBindings* pBindings, SfxChildWinInfo* pInfo)
+ : SfxNavigatorWrapper(_pParent, nId)
+{
+ SetWindow(VclPtr<ScNavigatorWin>::Create(pBindings, this, _pParent, pInfo));
+ Initialize();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/navipi/scenwnd.cxx b/sc/source/ui/navipi/scenwnd.cxx
new file mode 100644
index 000000000..3bbc6309c
--- /dev/null
+++ b/sc/source/ui/navipi/scenwnd.cxx
@@ -0,0 +1,242 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <sfx2/viewfrm.hxx>
+#include <svl/slstitm.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <navipi.hxx>
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <helpids.h>
+
+// class ScScenarioWindow ------------------------------------------------
+
+void ScScenarioWindow::UpdateEntries( const std::vector<OUString> &rNewEntryList )
+{
+ m_xLbScenario->clear();
+ m_aEntries.clear();
+
+ switch( rNewEntryList.size() )
+ {
+ case 0:
+ // no scenarios in current sheet
+ SetComment( OUString() );
+ break;
+
+ case 1:
+ // sheet is a scenario container, comment only
+ SetComment( rNewEntryList[0] );
+ break;
+
+ default:
+ {
+ // sheet contains scenarios
+ assert(rNewEntryList.size() % 3 == 0 && "ScScenarioListBox::UpdateEntries - wrong list size");
+ m_xLbScenario->freeze();
+
+ std::vector<OUString>::const_iterator iter;
+ for (iter = rNewEntryList.begin(); iter != rNewEntryList.end(); ++iter)
+ {
+ ScenarioEntry aEntry;
+
+ // first entry of a triple is the scenario name
+ aEntry.maName = *iter;
+
+ // second entry of a triple is the scenario comment
+ ++iter;
+ aEntry.maComment = *iter;
+
+ // third entry of a triple is the protection ("0" = not protected, "1" = protected)
+ ++iter;
+ aEntry.mbProtected = !(*iter).isEmpty() && (*iter)[0] != '0';
+
+ m_aEntries.push_back( aEntry );
+ m_xLbScenario->append_text(aEntry.maName);
+ }
+ m_xLbScenario->thaw();
+ m_xLbScenario->unselect_all();
+ SetComment(OUString());
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ScScenarioWindow, SelectHdl, weld::TreeView&, void)
+{
+ if (const ScenarioEntry* pEntry = GetSelectedScenarioEntry())
+ SetComment(pEntry->maComment);
+}
+
+IMPL_LINK_NOARG(ScScenarioWindow, DoubleClickHdl, weld::TreeView&, bool)
+{
+ SelectScenario();
+ return true;
+}
+
+IMPL_LINK(ScScenarioWindow, KeyInputHdl, const KeyEvent&, rKEvt, bool)
+{
+ bool bHandled = false;
+
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+ switch( aCode.GetCode() )
+ {
+ case KEY_RETURN:
+ SelectScenario();
+ bHandled = true;
+ break;
+ case KEY_DELETE:
+ DeleteScenario();
+ bHandled = true;
+ break;
+ }
+
+ return bHandled;
+}
+
+IMPL_LINK(ScScenarioWindow, ContextMenuHdl, const CommandEvent&, rCEvt, bool)
+{
+ bool bHandled = false;
+
+ if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
+ {
+ if (const ScenarioEntry* pEntry = GetSelectedScenarioEntry())
+ {
+ if (!pEntry->mbProtected)
+ {
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(m_xLbScenario.get(), "modules/scalc/ui/scenariomenu.ui"));
+ std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("menu"));
+ OString sIdent(xPopup->popup_at_rect(m_xLbScenario.get(), tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1,1))));
+ if (sIdent == "delete")
+ DeleteScenario();
+ else if (sIdent == "edit")
+ EditScenario();
+ }
+ }
+ bHandled = true;
+ }
+
+ return bHandled;
+}
+
+const ScScenarioWindow::ScenarioEntry* ScScenarioWindow::GetSelectedScenarioEntry() const
+{
+ size_t nPos = m_xLbScenario->get_selected_index();
+ return (nPos < m_aEntries.size()) ? &m_aEntries[ nPos ] : nullptr;
+}
+
+void ScScenarioWindow::ExecuteScenarioSlot(sal_uInt16 nSlotId)
+{
+ if( SfxViewFrame* pViewFrm = SfxViewFrame::Current() )
+ {
+ SfxStringItem aStringItem(nSlotId, m_xLbScenario->get_selected_text());
+ pViewFrm->GetDispatcher()->ExecuteList(nSlotId,
+ SfxCallMode::SLOT | SfxCallMode::RECORD, { &aStringItem } );
+ }
+}
+
+void ScScenarioWindow::SelectScenario()
+{
+ if (m_xLbScenario->get_selected_index() != -1)
+ ExecuteScenarioSlot(SID_SELECT_SCENARIO);
+}
+
+void ScScenarioWindow::EditScenario()
+{
+ if (m_xLbScenario->get_selected_index() != -1)
+ ExecuteScenarioSlot(SID_EDIT_SCENARIO);
+}
+
+void ScScenarioWindow::DeleteScenario()
+{
+ if (m_xLbScenario->get_selected_index() != -1)
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(m_xLbScenario.get(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_QUERY_DELSCENARIO)));
+ xQueryBox->set_default_response(RET_YES);
+ if (xQueryBox->run() == RET_YES)
+ ExecuteScenarioSlot(SID_DELETE_SCENARIO);
+ }
+}
+
+// class ScScenarioWindow ------------------------------------------------
+
+ScScenarioWindow::ScScenarioWindow(weld::Builder& rBuilder, const OUString& aQH_List,
+ const OUString& aQH_Comment)
+ : m_xLbScenario(rBuilder.weld_tree_view("scenariolist"))
+ , m_xEdComment(rBuilder.weld_text_view("scenariotext"))
+{
+ m_xLbScenario->set_help_id(HID_SC_SCENWIN_TOP);
+ m_xEdComment->set_help_id(HID_SC_SCENWIN_BOTTOM);
+
+ m_xLbScenario->set_tooltip_text(aQH_List);
+ m_xEdComment->set_tooltip_text(aQH_Comment);
+
+ m_xLbScenario->connect_changed(LINK(this, ScScenarioWindow, SelectHdl));
+ m_xLbScenario->connect_row_activated(LINK(this, ScScenarioWindow, DoubleClickHdl));
+ m_xLbScenario->connect_key_press(LINK(this, ScScenarioWindow, KeyInputHdl));
+ m_xLbScenario->connect_popup_menu(LINK(this, ScScenarioWindow, ContextMenuHdl));
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (pViewFrm)
+ {
+ SfxBindings& rBindings = pViewFrm->GetBindings();
+ rBindings.Invalidate( SID_SELECT_SCENARIO );
+ rBindings.Update( SID_SELECT_SCENARIO );
+ }
+}
+
+ScScenarioWindow::~ScScenarioWindow()
+{
+}
+
+void ScScenarioWindow::NotifyState( const SfxPoolItem* pState )
+{
+ if( pState )
+ {
+ m_xLbScenario->set_sensitive(true);
+
+ if ( auto pStringItem = dynamic_cast<const SfxStringItem*>( pState) )
+ {
+ const OUString& aNewEntry( pStringItem->GetValue() );
+
+ if (!aNewEntry.isEmpty())
+ m_xLbScenario->select_text(aNewEntry);
+ else
+ m_xLbScenario->unselect_all();
+ }
+ else if ( auto pStringListItem = dynamic_cast<const SfxStringListItem*>( pState) )
+ {
+ UpdateEntries(pStringListItem->GetList());
+ }
+ }
+ else
+ {
+ m_xLbScenario->set_sensitive(false);
+ m_xLbScenario->unselect_all();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/optdlg/calcoptionsdlg.cxx b/sc/source/ui/optdlg/calcoptionsdlg.cxx
new file mode 100644
index 000000000..ec65fb9d8
--- /dev/null
+++ b/sc/source/ui/optdlg/calcoptionsdlg.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/.
+ */
+
+#include <sal/config.h>
+
+#include <officecfg/Office/Calc.hxx>
+
+#include <calcconfig.hxx>
+#include "calcoptionsdlg.hxx"
+
+namespace {
+
+formula::FormulaGrammar::AddressConvention toAddressConvention(sal_Int32 nPos)
+{
+ switch (nPos)
+ {
+ case 1:
+ return formula::FormulaGrammar::CONV_OOO;
+ case 2:
+ return formula::FormulaGrammar::CONV_XL_A1;
+ case 3:
+ return formula::FormulaGrammar::CONV_XL_R1C1;
+ case 4:
+ return formula::FormulaGrammar::CONV_A1_XL_A1;
+ case 0:
+ default:
+ ;
+ }
+
+ return formula::FormulaGrammar::CONV_UNSPECIFIED;
+}
+
+sal_Int32 toSelectedItem( formula::FormulaGrammar::AddressConvention eConv )
+{
+ switch (eConv)
+ {
+ case formula::FormulaGrammar::CONV_OOO:
+ return 1;
+ case formula::FormulaGrammar::CONV_XL_A1:
+ return 2;
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ return 3;
+ case formula::FormulaGrammar::CONV_A1_XL_A1:
+ return 4;
+ default:
+ ;
+ }
+ return 0;
+}
+
+}
+
+ScCalcOptionsDialog::ScCalcOptionsDialog(weld::Window* pParent, const ScCalcConfig& rConfig, bool bWriteConfig)
+ : GenericDialogController(pParent, "modules/scalc/ui/formulacalculationoptions.ui", "FormulaCalculationOptions")
+ , maConfig(rConfig)
+ , mbSelectedEmptyStringAsZero(rConfig.mbEmptyStringAsZero)
+ , mbWriteConfig(bWriteConfig)
+ , mxEmptyAsZero(m_xBuilder->weld_check_button("checkEmptyAsZero"))
+ , mxConversion(m_xBuilder->weld_combo_box("comboConversion"))
+ , mxCurrentDocOnly(m_xBuilder->weld_check_button("current_doc"))
+ , mxSyntax(m_xBuilder->weld_combo_box("comboSyntaxRef"))
+{
+ mxConversion->set_active(static_cast<int>(rConfig.meStringConversion));
+ mxConversion->connect_changed(LINK(this, ScCalcOptionsDialog, ConversionModifiedHdl));
+ mxConversion->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::StringConversion::isReadOnly() );
+
+ mxEmptyAsZero->set_active(rConfig.mbEmptyStringAsZero);
+ mxEmptyAsZero->connect_toggled(LINK(this, ScCalcOptionsDialog, AsZeroModifiedHdl));
+ CoupleEmptyAsZeroToStringConversion();
+ mxEmptyAsZero->set_sensitive ( !officecfg::Office::Calc::Formula::Syntax::EmptyStringAsZero::isReadOnly() );
+
+ mxSyntax->set_active(toSelectedItem(rConfig.meStringRefAddressSyntax));
+ mxSyntax->connect_changed(LINK(this, ScCalcOptionsDialog, SyntaxModifiedHdl));
+ mxSyntax->set_sensitive ( !officecfg::Office::Calc::Formula::Syntax::StringRefAddressSyntax::isReadOnly() );
+
+ mxCurrentDocOnly->set_active(!mbWriteConfig);
+ mxCurrentDocOnly->connect_toggled(LINK(this, ScCalcOptionsDialog, CurrentDocOnlyHdl));
+}
+
+ScCalcOptionsDialog::~ScCalcOptionsDialog()
+{
+}
+
+void ScCalcOptionsDialog::CoupleEmptyAsZeroToStringConversion()
+{
+ switch (maConfig.meStringConversion)
+ {
+ case ScCalcConfig::StringConversion::ILLEGAL:
+ maConfig.mbEmptyStringAsZero = false;
+ mxEmptyAsZero->set_active(false);
+ mxEmptyAsZero->set_sensitive(false);
+ break;
+ case ScCalcConfig::StringConversion::ZERO:
+ maConfig.mbEmptyStringAsZero = true;
+ mxEmptyAsZero->set_active(true);
+ mxEmptyAsZero->set_sensitive(false);
+ break;
+ case ScCalcConfig::StringConversion::UNAMBIGUOUS:
+ case ScCalcConfig::StringConversion::LOCALE:
+ // Reset to the value the user selected before.
+ maConfig.mbEmptyStringAsZero = mbSelectedEmptyStringAsZero;
+ mxEmptyAsZero->set_sensitive(true);
+ mxEmptyAsZero->set_active(mbSelectedEmptyStringAsZero);
+ break;
+ }
+}
+
+IMPL_LINK(ScCalcOptionsDialog, AsZeroModifiedHdl, weld::Toggleable&, rCheckBox, void )
+{
+ maConfig.mbEmptyStringAsZero = mbSelectedEmptyStringAsZero = rCheckBox.get_active();
+}
+
+IMPL_LINK(ScCalcOptionsDialog, ConversionModifiedHdl, weld::ComboBox&, rConv, void)
+{
+ maConfig.meStringConversion = static_cast<ScCalcConfig::StringConversion>(rConv.get_active());
+ CoupleEmptyAsZeroToStringConversion();
+}
+
+IMPL_LINK(ScCalcOptionsDialog, SyntaxModifiedHdl, weld::ComboBox&, rSyntax, void)
+{
+ maConfig.SetStringRefSyntax(toAddressConvention(rSyntax.get_active()));
+}
+
+IMPL_LINK(ScCalcOptionsDialog, CurrentDocOnlyHdl, weld::Toggleable&, rCheckBox, void)
+{
+ mbWriteConfig = !rCheckBox.get_active();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/optdlg/calcoptionsdlg.hxx b/sc/source/ui/optdlg/calcoptionsdlg.hxx
new file mode 100644
index 000000000..97d7bb21c
--- /dev/null
+++ b/sc/source/ui/optdlg/calcoptionsdlg.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 <vcl/weld.hxx>
+#include <calcconfig.hxx>
+
+class ScCalcOptionsDialog : public weld::GenericDialogController
+{
+public:
+ ScCalcOptionsDialog(weld::Window* pParent, const ScCalcConfig& rConfig, bool bWriteConfig);
+ virtual ~ScCalcOptionsDialog() override;
+
+ DECL_LINK(AsZeroModifiedHdl, weld::Toggleable&, void);
+ DECL_LINK(ConversionModifiedHdl, weld::ComboBox&, void);
+ DECL_LINK(SyntaxModifiedHdl, weld::ComboBox&, void);
+ DECL_LINK(CurrentDocOnlyHdl, weld::Toggleable&, void);
+
+ const ScCalcConfig& GetConfig() const { return maConfig; }
+ bool GetWriteCalcConfig() const { return mbWriteConfig; }
+
+private:
+ void CoupleEmptyAsZeroToStringConversion();
+
+private:
+ ScCalcConfig maConfig;
+ bool mbSelectedEmptyStringAsZero;
+ bool mbWriteConfig;
+
+ std::unique_ptr<weld::CheckButton> mxEmptyAsZero;
+ std::unique_ptr<weld::ComboBox> mxConversion;
+ std::unique_ptr<weld::CheckButton> mxCurrentDocOnly;
+ std::unique_ptr<weld::ComboBox> mxSyntax;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/optdlg/opredlin.cxx b/sc/source/ui/optdlg/opredlin.cxx
new file mode 100644
index 000000000..963ea1bb3
--- /dev/null
+++ b/sc/source/ui/optdlg/opredlin.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <svx/colorbox.hxx>
+
+#include <appoptio.hxx>
+#include <scmod.hxx>
+#include <docsh.hxx>
+#include <svx/svxids.hrc>
+
+#include <opredlin.hxx>
+
+ScRedlineOptionsTabPage::ScRedlineOptionsTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/optchangespage.ui", "OptChangesPage", &rSet)
+ , m_xContentColorLB(new ColorListBox(m_xBuilder->weld_menu_button("changes"),
+ [this]{ return GetDialogController()->getDialog(); }))
+ , m_xRemoveColorLB(new ColorListBox(m_xBuilder->weld_menu_button("deletions"),
+ [this]{ return GetDialogController()->getDialog(); }))
+ , m_xInsertColorLB(new ColorListBox(m_xBuilder->weld_menu_button("entries"),
+ [this]{ return GetDialogController()->getDialog(); }))
+ , m_xMoveColorLB(new ColorListBox(m_xBuilder->weld_menu_button("insertions"),
+ [this]{ return GetDialogController()->getDialog(); }))
+{
+ m_xContentColorLB->SetSlotId(SID_AUTHOR_COLOR);
+ m_xRemoveColorLB->SetSlotId(SID_AUTHOR_COLOR);
+ m_xInsertColorLB->SetSlotId(SID_AUTHOR_COLOR);
+ m_xMoveColorLB->SetSlotId(SID_AUTHOR_COLOR);
+}
+
+ScRedlineOptionsTabPage::~ScRedlineOptionsTabPage()
+{
+ m_xContentColorLB.reset();
+ m_xRemoveColorLB.reset();
+ m_xInsertColorLB.reset();
+ m_xMoveColorLB.reset();
+}
+
+std::unique_ptr<SfxTabPage> ScRedlineOptionsTabPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rSet )
+{
+ return std::make_unique<ScRedlineOptionsTabPage>( pPage, pController, *rSet );
+}
+
+bool ScRedlineOptionsTabPage::FillItemSet( SfxItemSet* /* rSet */ )
+{
+ ScAppOptions aAppOptions=SC_MOD()->GetAppOptions();
+
+ Color nNew = m_xContentColorLB->GetSelectEntryColor();
+ aAppOptions.SetTrackContentColor(nNew);
+
+ nNew = m_xMoveColorLB->GetSelectEntryColor();
+ aAppOptions.SetTrackMoveColor(nNew);
+
+ nNew = m_xInsertColorLB->GetSelectEntryColor();
+ aAppOptions.SetTrackInsertColor(nNew);
+
+ nNew = m_xRemoveColorLB->GetSelectEntryColor();
+ aAppOptions.SetTrackDeleteColor(nNew);
+
+ SC_MOD()->SetAppOptions(aAppOptions);
+
+ // repaint (if everything would be done by Items (how it should be),
+ // this wouldn't be necessary)
+ ScDocShell* pDocSh = dynamic_cast<ScDocShell*>( SfxObjectShell::Current() );
+ if (pDocSh)
+ pDocSh->PostPaintGridAll();
+
+ return false;
+}
+
+void ScRedlineOptionsTabPage::Reset( const SfxItemSet* /* rSet */ )
+{
+ ScAppOptions aAppOptions=SC_MOD()->GetAppOptions();
+
+ Color nColor = aAppOptions.GetTrackContentColor();
+ m_xContentColorLB->SelectEntry(nColor);
+
+ nColor = aAppOptions.GetTrackMoveColor();
+ m_xMoveColorLB->SelectEntry(nColor);
+
+ nColor = aAppOptions.GetTrackInsertColor();
+ m_xInsertColorLB->SelectEntry(nColor);
+
+ nColor = aAppOptions.GetTrackDeleteColor();
+ m_xRemoveColorLB->SelectEntry(nColor);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/optdlg/tpcalc.cxx b/sc/source/ui/optdlg/tpcalc.cxx
new file mode 100644
index 000000000..ae767043f
--- /dev/null
+++ b/sc/source/ui/optdlg/tpcalc.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 .
+ */
+
+ #undef SC_DLLIMPLEMENTATION
+
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svl/numformat.hxx>
+
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <docoptio.hxx>
+#include <sc.hrc>
+#include <officecfg/Office/Calc.hxx>
+#include <svtools/restartdialog.hxx>
+
+#include <tpcalc.hxx>
+
+ScTpCalcOptions::ScTpCalcOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/optcalculatepage.ui", "OptCalculatePage", &rCoreAttrs)
+ , pOldOptions(new ScDocOptions(
+ rCoreAttrs.Get(SID_SCDOCOPTIONS).GetDocOptions()))
+ , pLocalOptions(new ScDocOptions)
+ , m_xBtnIterate(m_xBuilder->weld_check_button("iterate"))
+ , m_xFtSteps(m_xBuilder->weld_label("stepsft"))
+ , m_xEdSteps(m_xBuilder->weld_spin_button("steps"))
+ , m_xFtEps(m_xBuilder->weld_label("minchangeft"))
+ , m_xEdEps(new ScDoubleField(m_xBuilder->weld_entry("minchange")))
+ , m_xBtnDateStd(m_xBuilder->weld_radio_button("datestd"))
+ , m_xBtnDateSc10(m_xBuilder->weld_radio_button("datesc10"))
+ , m_xBtnDate1904(m_xBuilder->weld_radio_button("date1904"))
+ , m_xBtnCase(m_xBuilder->weld_check_button("case"))
+ , m_xBtnCalc(m_xBuilder->weld_check_button("calc"))
+ , m_xBtnMatch(m_xBuilder->weld_check_button("match"))
+ , m_xBtnWildcards(m_xBuilder->weld_radio_button("formulawildcards"))
+ , m_xBtnRegex(m_xBuilder->weld_radio_button("formularegex"))
+ , m_xBtnLiteral(m_xBuilder->weld_radio_button("formulaliteral"))
+ , m_xBtnLookUp(m_xBuilder->weld_check_button("lookup"))
+ , m_xBtnGeneralPrec(m_xBuilder->weld_check_button("generalprec"))
+ , m_xFtPrec(m_xBuilder->weld_label("precft"))
+ , m_xEdPrec(m_xBuilder->weld_spin_button("prec"))
+ , m_xBtnThread(m_xBuilder->weld_check_button("threadingenabled"))
+{
+ Init();
+ SetExchangeSupport();
+}
+
+ScTpCalcOptions::~ScTpCalcOptions()
+{
+}
+
+void ScTpCalcOptions::Init()
+{
+ m_xBtnIterate->connect_toggled( LINK( this, ScTpCalcOptions, CheckClickHdl ) );
+ m_xBtnGeneralPrec->connect_toggled( LINK(this, ScTpCalcOptions, CheckClickHdl) );
+ m_xBtnDateStd->connect_toggled( LINK( this, ScTpCalcOptions, RadioClickHdl ) );
+ m_xBtnDateSc10->connect_toggled( LINK( this, ScTpCalcOptions, RadioClickHdl ) );
+ m_xBtnDate1904->connect_toggled( LINK( this, ScTpCalcOptions, RadioClickHdl ) );
+ m_xBtnThread->connect_toggled( LINK( this, ScTpCalcOptions, CheckClickHdl ) );
+}
+
+std::unique_ptr<SfxTabPage> ScTpCalcOptions::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet )
+{
+ return std::make_unique<ScTpCalcOptions>( pPage, pController, *rAttrSet );
+}
+
+void ScTpCalcOptions::Reset(const SfxItemSet* rCoreAttrs)
+{
+ sal_uInt16 d,m;
+ sal_Int16 y;
+
+ pOldOptions.reset(new ScDocOptions(
+ rCoreAttrs->Get(SID_SCDOCOPTIONS).GetDocOptions()));
+
+ *pLocalOptions = *pOldOptions;
+
+ m_xBtnCase->set_active( !pLocalOptions->IsIgnoreCase() );
+ m_xBtnCase->set_sensitive( !officecfg::Office::Calc::Calculate::Other::CaseSensitive::isReadOnly() );
+ m_xBtnCalc->set_active( pLocalOptions->IsCalcAsShown() );
+ m_xBtnCalc->set_sensitive( !officecfg::Office::Calc::Calculate::Other::Precision::isReadOnly() );
+ m_xBtnMatch->set_active( pLocalOptions->IsMatchWholeCell() );
+ m_xBtnMatch->set_sensitive( !officecfg::Office::Calc::Calculate::Other::SearchCriteria::isReadOnly() );
+ bool bWildcards = pLocalOptions->IsFormulaWildcardsEnabled();
+ bool bRegex = pLocalOptions->IsFormulaRegexEnabled();
+ // If both, Wildcards and Regex, are set then Wildcards shall take
+ // precedence. This is also how other code calling Search handles it. Both
+ // simultaneously couldn't be set using UI but editing the configuration.
+ if (bWildcards && bRegex)
+ bRegex = false;
+ m_xBtnWildcards->set_active( bWildcards );
+ m_xBtnRegex->set_active( bRegex );
+ m_xBtnWildcards->set_sensitive( !officecfg::Office::Calc::Calculate::Other::Wildcards::isReadOnly() );
+ m_xBtnRegex->set_sensitive( !officecfg::Office::Calc::Calculate::Other::RegularExpressions::isReadOnly() );
+ m_xBtnLiteral->set_active( !bWildcards && !bRegex );
+ m_xBtnLiteral->set_sensitive( m_xBtnWildcards->get_sensitive() || m_xBtnRegex->get_sensitive() );
+ // if either regex or wildcards radio button is set and read-only, disable all three
+ if ( (!m_xBtnWildcards->get_sensitive() && bWildcards) || (!m_xBtnRegex->get_sensitive() && bRegex) )
+ {
+ m_xBtnWildcards->set_sensitive( false );
+ m_xBtnRegex->set_sensitive( false );
+ m_xBtnLiteral->set_sensitive( false );
+ }
+ m_xBtnLookUp->set_active( pLocalOptions->IsLookUpColRowNames() );
+ m_xBtnLookUp->set_sensitive( !officecfg::Office::Calc::Calculate::Other::FindLabel::isReadOnly() );
+ m_xBtnIterate->set_active( pLocalOptions->IsIter() );
+ m_xEdSteps->set_value( pLocalOptions->GetIterCount() );
+ m_xEdEps->SetValue( pLocalOptions->GetIterEps(), 6 );
+
+ pLocalOptions->GetDate( d, m, y );
+
+ switch ( y )
+ {
+ case 1899:
+ m_xBtnDateStd->set_active(true);
+ break;
+ case 1900:
+ m_xBtnDateSc10->set_active(true);
+ break;
+ case 1904:
+ m_xBtnDate1904->set_active(true);
+ break;
+ }
+
+ sal_uInt16 nPrec = pLocalOptions->GetStdPrecision();
+ if (nPrec == SvNumberFormatter::UNLIMITED_PRECISION)
+ {
+ m_xFtPrec->set_sensitive(false);
+ m_xEdPrec->set_sensitive(false);
+ m_xBtnGeneralPrec->set_active(false);
+ m_xEdPrec->set_value(0);
+ }
+ else
+ {
+ m_xBtnGeneralPrec->set_active(true);
+ m_xFtPrec->set_sensitive(true);
+ m_xEdPrec->set_sensitive(true);
+ m_xEdPrec->set_value(nPrec);
+ }
+
+ m_xBtnThread->set_sensitive( !officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::isReadOnly() );
+ m_xBtnThread->set_active( officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get() );
+
+ CheckClickHdl(*m_xBtnIterate);
+}
+
+bool ScTpCalcOptions::FillItemSet( SfxItemSet* rCoreAttrs )
+{
+ // every other options are updated in handlers
+ pLocalOptions->SetIterCount( static_cast<sal_uInt16>(m_xEdSteps->get_value()) );
+ pLocalOptions->SetIgnoreCase( !m_xBtnCase->get_active() );
+ pLocalOptions->SetCalcAsShown( m_xBtnCalc->get_active() );
+ pLocalOptions->SetMatchWholeCell( m_xBtnMatch->get_active() );
+ pLocalOptions->SetFormulaWildcardsEnabled( m_xBtnWildcards->get_active() );
+ pLocalOptions->SetFormulaRegexEnabled( m_xBtnRegex->get_active() );
+ pLocalOptions->SetLookUpColRowNames( m_xBtnLookUp->get_active() );
+
+ if (m_xBtnGeneralPrec->get_active())
+ pLocalOptions->SetStdPrecision(
+ static_cast<sal_uInt16>(m_xEdPrec->get_value()) );
+ else
+ pLocalOptions->SetStdPrecision( SvNumberFormatter::UNLIMITED_PRECISION );
+
+ bool bShouldEnableThreading = m_xBtnThread->get_active();
+ if (bShouldEnableThreading != officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::get())
+ {
+ std::shared_ptr<comphelper::ConfigurationChanges> xBatch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Calc::Formula::Calculation::UseThreadedCalculationForFormulaGroups::set(bShouldEnableThreading, xBatch);
+ xBatch->commit();
+ SolarMutexGuard aGuard;
+ if (svtools::executeRestartDialog(
+ comphelper::getProcessComponentContext(), GetFrameWeld(),
+ svtools::RESTART_REASON_THREADING))
+ GetDialogController()->response(RET_OK);
+ }
+ if ( *pLocalOptions != *pOldOptions )
+ {
+ rCoreAttrs->Put( ScTpCalcItem( SID_SCDOCOPTIONS, *pLocalOptions ) );
+ return true;
+ }
+ else
+ return false;
+}
+
+DeactivateRC ScTpCalcOptions::DeactivatePage( SfxItemSet* pSetP )
+{
+ DeactivateRC nReturn = DeactivateRC::KeepPage;
+
+ double fEps;
+ if( m_xEdEps->GetValue( fEps ) && (fEps > 0.0) )
+ {
+ pLocalOptions->SetIterEps( fEps );
+ nReturn = DeactivateRC::LeavePage;
+ }
+
+ if ( nReturn == DeactivateRC::KeepPage )
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(), VclMessageType::Warning,
+ VclButtonsType::Ok, ScResId(STR_INVALID_EPS)));
+ xBox->run();
+
+ m_xEdEps->grab_focus();
+ }
+ else if ( pSetP )
+ FillItemSet( pSetP );
+
+ return nReturn;
+}
+
+// Handler:
+
+IMPL_LINK( ScTpCalcOptions, RadioClickHdl, weld::Toggleable&, rBtn, void )
+{
+ if (!rBtn.get_active())
+ return;
+ if (m_xBtnDateStd->get_active())
+ {
+ pLocalOptions->SetDate( 30, 12, 1899 );
+ }
+ else if (m_xBtnDateSc10->get_active())
+ {
+ pLocalOptions->SetDate( 1, 1, 1900 );
+ }
+ else if (m_xBtnDate1904->get_active())
+ {
+ pLocalOptions->SetDate( 1, 1, 1904 );
+ }
+}
+
+IMPL_LINK(ScTpCalcOptions, CheckClickHdl, weld::Toggleable&, rBtn, void)
+{
+ if (&rBtn == m_xBtnGeneralPrec.get())
+ {
+ if (rBtn.get_active())
+ {
+ m_xEdPrec->set_sensitive(true);
+ m_xFtPrec->set_sensitive(true);
+ }
+ else
+ {
+ m_xEdPrec->set_sensitive(false);
+ m_xFtPrec->set_sensitive(false);
+ }
+ }
+ else if (&rBtn == m_xBtnIterate.get())
+ {
+ if (rBtn.get_active())
+ {
+ pLocalOptions->SetIter( true );
+ m_xFtSteps->set_sensitive(true); m_xEdSteps->set_sensitive(true);
+ m_xFtEps->set_sensitive(true); m_xEdEps->set_sensitive(true);
+ }
+ else
+ {
+ pLocalOptions->SetIter( false );
+ m_xFtSteps->set_sensitive(false); m_xEdSteps->set_sensitive(false);
+ m_xFtEps->set_sensitive(false); m_xEdEps->set_sensitive(false);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/optdlg/tpcompatibility.cxx b/sc/source/ui/optdlg/tpcompatibility.cxx
new file mode 100644
index 000000000..f468a68f6
--- /dev/null
+++ b/sc/source/ui/optdlg/tpcompatibility.cxx
@@ -0,0 +1,74 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <svl/intitem.hxx>
+
+#include <tpcompatibility.hxx>
+#include <sc.hrc>
+#include <optutil.hxx>
+
+ScTpCompatOptions::ScTpCompatOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rCoreAttrs)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/optcompatibilitypage.ui", "OptCompatibilityPage", &rCoreAttrs)
+ , m_xLbKeyBindings(m_xBuilder->weld_combo_box("keybindings"))
+{
+}
+
+ScTpCompatOptions::~ScTpCompatOptions()
+{
+}
+
+std::unique_ptr<SfxTabPage> ScTpCompatOptions::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rCoreAttrs)
+{
+ return std::make_unique<ScTpCompatOptions>(pPage, pController, *rCoreAttrs);
+}
+
+bool ScTpCompatOptions::FillItemSet(SfxItemSet *rCoreAttrs)
+{
+ bool bRet = false;
+ if (m_xLbKeyBindings->get_value_changed_from_saved())
+ {
+ rCoreAttrs->Put(
+ SfxUInt16Item(
+ SID_SC_OPT_KEY_BINDING_COMPAT, m_xLbKeyBindings->get_active()));
+ bRet = true;
+ }
+ return bRet;
+}
+
+void ScTpCompatOptions::Reset(const SfxItemSet *rCoreAttrs)
+{
+ if (const SfxUInt16Item* p16Item = rCoreAttrs->GetItemIfSet(SID_SC_OPT_KEY_BINDING_COMPAT))
+ {
+ ScOptionsUtil::KeyBindingType eKeyB =
+ static_cast<ScOptionsUtil::KeyBindingType>(p16Item->GetValue());
+
+ switch (eKeyB)
+ {
+ case ScOptionsUtil::KEY_DEFAULT:
+ m_xLbKeyBindings->set_active(0);
+ break;
+ case ScOptionsUtil::KEY_OOO_LEGACY:
+ m_xLbKeyBindings->set_active(1);
+ break;
+ default:
+ ;
+ }
+ }
+
+ m_xLbKeyBindings->save_value();
+}
+
+DeactivateRC ScTpCompatOptions::DeactivatePage(SfxItemSet* /*pSet*/)
+{
+ return DeactivateRC::KeepPage;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/optdlg/tpdefaults.cxx b/sc/source/ui/optdlg/tpdefaults.cxx
new file mode 100644
index 000000000..7a47f3dbc
--- /dev/null
+++ b/sc/source/ui/optdlg/tpdefaults.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/.
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <tpdefaults.hxx>
+#include <sc.hrc>
+#include <defaultsoptions.hxx>
+#include <document.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <config_features.h>
+
+ScTpDefaultsOptions::ScTpDefaultsOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rCoreSet)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/optdefaultpage.ui", "OptDefaultPage", &rCoreSet)
+ , m_xEdNSheets(m_xBuilder->weld_spin_button("sheetsnumber"))
+ , m_xEdSheetPrefix(m_xBuilder->weld_entry("sheetprefix"))
+ , m_xEdJumboSheets(m_xBuilder->weld_check_button("jumbo_sheets"))
+{
+ m_xEdNSheets->connect_changed( LINK(this, ScTpDefaultsOptions, NumModifiedHdl) );
+ m_xEdSheetPrefix->connect_changed( LINK(this, ScTpDefaultsOptions, PrefixModifiedHdl) );
+ m_xEdSheetPrefix->connect_focus_in( LINK(this, ScTpDefaultsOptions, PrefixEditOnFocusHdl) );
+#if HAVE_FEATURE_JUMBO_SHEETS
+ if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
+#endif
+ m_xEdJumboSheets->hide();
+}
+
+ScTpDefaultsOptions::~ScTpDefaultsOptions()
+{
+}
+
+std::unique_ptr<SfxTabPage> ScTpDefaultsOptions::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rCoreAttrs)
+{
+ return std::make_unique<ScTpDefaultsOptions>(pPage, pController, *rCoreAttrs);
+}
+
+bool ScTpDefaultsOptions::FillItemSet(SfxItemSet *rCoreSet)
+{
+ bool bRet = false;
+ ScDefaultsOptions aOpt;
+
+ SCTAB nTabCount = static_cast<SCTAB>(m_xEdNSheets->get_value());
+ OUString aSheetPrefix = m_xEdSheetPrefix->get_text();
+ bool bJumboSheets = m_xEdJumboSheets->get_state();
+
+ if ( m_xEdNSheets->get_value_changed_from_saved()
+ || m_xEdSheetPrefix->get_saved_value() != aSheetPrefix
+ || m_xEdJumboSheets->get_saved_state() != (bJumboSheets ? TRISTATE_TRUE : TRISTATE_FALSE) )
+ {
+ aOpt.SetInitTabCount( nTabCount );
+ aOpt.SetInitTabPrefix( aSheetPrefix );
+#if HAVE_FEATURE_JUMBO_SHEETS
+ aOpt.SetInitJumboSheets( bJumboSheets );
+#endif
+ rCoreSet->Put( ScTpDefaultsItem( aOpt ) );
+ bRet = true;
+ }
+ return bRet;
+}
+
+void ScTpDefaultsOptions::Reset(const SfxItemSet* rCoreSet)
+{
+ ScDefaultsOptions aOpt;
+
+ if(const ScTpDefaultsItem* pDefaultsItem = rCoreSet->GetItemIfSet(SID_SCDEFAULTSOPTIONS, false))
+ aOpt = pDefaultsItem->GetDefaultsOptions();
+
+ m_xEdNSheets->set_value(aOpt.GetInitTabCount());
+ m_xEdSheetPrefix->set_text( aOpt.GetInitTabPrefix() );
+ m_xEdJumboSheets->set_state( aOpt.GetInitJumboSheets() ? TRISTATE_TRUE : TRISTATE_FALSE );
+ m_xEdNSheets->save_value();
+ m_xEdSheetPrefix->save_value();
+ m_xEdJumboSheets->save_state();
+}
+
+DeactivateRC ScTpDefaultsOptions::DeactivatePage(SfxItemSet* /*pSet*/)
+{
+ return DeactivateRC::KeepPage;
+}
+
+void ScTpDefaultsOptions::CheckNumSheets()
+{
+ auto nVal = m_xEdNSheets->get_value();
+ if (nVal > MAXINITTAB)
+ m_xEdNSheets->set_value(MAXINITTAB);
+ if (nVal < MININITTAB)
+ m_xEdNSheets->set_value(MININITTAB);
+}
+
+void ScTpDefaultsOptions::CheckPrefix()
+{
+ OUString aSheetPrefix = m_xEdSheetPrefix->get_text();
+
+ if (!aSheetPrefix.isEmpty() && !ScDocument::ValidTabName(aSheetPrefix))
+ {
+ // Revert to last good Prefix and also select it to
+ // indicate something illegal was typed
+ m_xEdSheetPrefix->set_text(maOldPrefixValue);
+ m_xEdSheetPrefix->select_region(0, -1);
+ }
+ else
+ {
+ OnFocusPrefixInput();
+ }
+}
+
+void ScTpDefaultsOptions::OnFocusPrefixInput()
+{
+ // Store Prefix in case we need to revert
+ maOldPrefixValue = m_xEdSheetPrefix->get_text();
+}
+
+IMPL_LINK_NOARG(ScTpDefaultsOptions, NumModifiedHdl, weld::Entry&, void)
+{
+ CheckNumSheets();
+}
+
+IMPL_LINK_NOARG(ScTpDefaultsOptions, PrefixModifiedHdl, weld::Entry&, void)
+{
+ CheckPrefix();
+}
+
+IMPL_LINK_NOARG(ScTpDefaultsOptions, PrefixEditOnFocusHdl, weld::Widget&, void)
+{
+ OnFocusPrefixInput();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/optdlg/tpformula.cxx b/sc/source/ui/optdlg/tpformula.cxx
new file mode 100644
index 000000000..f4815d17c
--- /dev/null
+++ b/sc/source/ui/optdlg/tpformula.cxx
@@ -0,0 +1,411 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <global.hxx>
+#include <tpformula.hxx>
+#include <formulaopt.hxx>
+#include <sc.hrc>
+#include <strings.hrc>
+#include <scresid.hxx>
+#include <formula/grammar.hxx>
+#include <officecfg/Office/Calc.hxx>
+#include "calcoptionsdlg.hxx"
+
+#include <unotools/localedatawrapper.hxx>
+
+ScTpFormulaOptions::ScTpFormulaOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/optformula.ui", "OptFormula", &rCoreAttrs)
+ , mnDecSep(0)
+ , mxLbFormulaSyntax(m_xBuilder->weld_combo_box("formulasyntax"))
+ , mxCbEnglishFuncName(m_xBuilder->weld_check_button("englishfuncname"))
+ , mxBtnCustomCalcDefault(m_xBuilder->weld_radio_button("calcdefault"))
+ , mxBtnCustomCalcCustom(m_xBuilder->weld_radio_button("calccustom"))
+ , mxBtnCustomCalcDetails(m_xBuilder->weld_button("details"))
+ , mxEdSepFuncArg(m_xBuilder->weld_entry("function"))
+ , mxEdSepArrayCol(m_xBuilder->weld_entry("arraycolumn"))
+ , mxEdSepArrayRow(m_xBuilder->weld_entry("arrayrow"))
+ , mxBtnSepReset(m_xBuilder->weld_button("reset"))
+ , mxLbOOXMLRecalcOptions(m_xBuilder->weld_combo_box("ooxmlrecalc"))
+ , mxLbODFRecalcOptions(m_xBuilder->weld_combo_box("odfrecalc"))
+{
+ mxLbFormulaSyntax->append_text(ScResId(SCSTR_FORMULA_SYNTAX_CALC_A1));
+ mxLbFormulaSyntax->append_text(ScResId(SCSTR_FORMULA_SYNTAX_XL_A1));
+ mxLbFormulaSyntax->append_text(ScResId(SCSTR_FORMULA_SYNTAX_XL_R1C1));
+
+ Link<weld::Button&,void> aLink2 = LINK( this, ScTpFormulaOptions, ButtonHdl );
+ mxBtnSepReset->connect_clicked(aLink2);
+ mxBtnCustomCalcDetails->connect_clicked(aLink2);
+
+ Link<weld::Toggleable&,void> aToggleLink = LINK( this, ScTpFormulaOptions, ToggleHdl );
+ mxBtnCustomCalcDefault->connect_toggled(aToggleLink);
+ mxBtnCustomCalcCustom->connect_toggled(aToggleLink);
+
+ mxEdSepFuncArg->connect_insert_text(LINK( this, ScTpFormulaOptions, SepInsertTextHdl ));
+ mxEdSepArrayCol->connect_insert_text(LINK( this, ScTpFormulaOptions, ColSepInsertTextHdl ));
+ mxEdSepArrayRow->connect_insert_text(LINK( this, ScTpFormulaOptions, RowSepInsertTextHdl ));
+
+ Link<weld::Entry&,void> aLink = LINK( this, ScTpFormulaOptions, SepModifyHdl );
+ mxEdSepFuncArg->connect_changed(aLink);
+ mxEdSepArrayCol->connect_changed(aLink);
+ mxEdSepArrayRow->connect_changed(aLink);
+
+ Link<weld::Widget&,void> aLink3 = LINK( this, ScTpFormulaOptions, SepEditOnFocusHdl );
+ mxEdSepFuncArg->connect_focus_in(aLink3);
+ mxEdSepArrayCol->connect_focus_in(aLink3);
+ mxEdSepArrayRow->connect_focus_in(aLink3);
+
+ // Get the decimal separator for current locale.
+ OUString aSep = ScGlobal::getLocaleData().getNumDecimalSep();
+ mnDecSep = aSep.isEmpty() ? u'.' : aSep[0];
+
+ maSavedDocOptions = rCoreAttrs.Get(SID_SCDOCOPTIONS).GetDocOptions();
+}
+
+ScTpFormulaOptions::~ScTpFormulaOptions()
+{
+}
+
+void ScTpFormulaOptions::ResetSeparators()
+{
+ OUString aFuncArg, aArrayCol, aArrayRow;
+ ScFormulaOptions::GetDefaultFormulaSeparators(aFuncArg, aArrayCol, aArrayRow);
+ mxEdSepFuncArg->set_text(aFuncArg);
+ mxEdSepArrayCol->set_text(aArrayCol);
+ mxEdSepArrayRow->set_text(aArrayRow);
+}
+
+void ScTpFormulaOptions::OnFocusSeparatorInput(weld::Entry* pEdit)
+{
+ if (!pEdit)
+ return;
+
+ // Make sure the entire text is selected.
+ pEdit->select_region(0, -1);
+ OUString sSepValue = pEdit->get_text();
+ if (!sSepValue.isEmpty())
+ maOldSepValue = sSepValue;
+}
+
+void ScTpFormulaOptions::UpdateCustomCalcRadioButtons(bool bDefault)
+{
+ if (bDefault)
+ {
+ mxBtnCustomCalcDefault->set_active(true);
+ mxBtnCustomCalcCustom->set_active(false);
+ mxBtnCustomCalcDetails->set_sensitive(false);
+ }
+ else
+ {
+ mxBtnCustomCalcDefault->set_active(false);
+ mxBtnCustomCalcCustom->set_active(true);
+ mxBtnCustomCalcDetails->set_sensitive(true);
+ }
+}
+
+void ScTpFormulaOptions::LaunchCustomCalcSettings()
+{
+ ScCalcOptionsDialog aDlg(GetFrameWeld(), maCurrentConfig, maCurrentDocOptions.IsWriteCalcConfig());
+ if (aDlg.run() == RET_OK)
+ {
+ maCurrentConfig = aDlg.GetConfig();
+ maCurrentDocOptions.SetWriteCalcConfig(aDlg.GetWriteCalcConfig());
+ }
+}
+
+bool ScTpFormulaOptions::IsValidSeparator(const OUString& rSep, bool bArray) const
+{
+ if (rSep.getLength() != 1)
+ // Must be one-character long.
+ return false;
+
+ const sal_Unicode c = rSep[0];
+
+ if (c == mnDecSep)
+ // decimal separator is not allowed.
+ return false;
+
+ if (c <= 0x20 || c == 0x7f)
+ // Disallow non-printables including space and DEL.
+ return false;
+
+ if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9'))
+ // Disallow alphanumeric.
+ return false;
+
+ if (bArray)
+ {
+ switch (c)
+ {
+ case '+':
+ case '-':
+ case '{':
+ case '}':
+ case '"':
+ // All following just to prevent confusion, they are not
+ // evaluated in inline arrays and theoretically would be
+ // possible.
+ case '%':
+ case '/':
+ case '*':
+ case '=':
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '(':
+ case ')':
+ case '\'':
+ // Disallowed characters. Anything else we want to disallow ?
+ return false;
+ }
+ }
+ else if (c <= 0x7f)
+ {
+ switch (c)
+ {
+ default:
+ // Anything bad except the knowns.
+ return false;
+ case ';':
+ case ',':
+ ; // nothing
+ }
+ }
+ else
+ {
+ // Any Unicode character, would have to ask the compiler's localized
+ // symbol map whether it's a known symbol but not a separator
+ // (ocSep,ocArrayRowSep,ocArrayColSep), which we're about to set here.
+ // But really..
+ return false;
+ }
+
+ return true;
+}
+
+IMPL_LINK( ScTpFormulaOptions, ButtonHdl, weld::Button&, rBtn, void )
+{
+ if (&rBtn == mxBtnSepReset.get())
+ ResetSeparators();
+ else if (&rBtn == mxBtnCustomCalcDetails.get())
+ LaunchCustomCalcSettings();
+}
+
+IMPL_LINK( ScTpFormulaOptions, ToggleHdl, weld::Toggleable&, rBtn, void )
+{
+ if (!rBtn.get_active())
+ return;
+ if (mxBtnCustomCalcDefault->get_active())
+ UpdateCustomCalcRadioButtons(true);
+ else if (mxBtnCustomCalcCustom->get_active())
+ UpdateCustomCalcRadioButtons(false);
+}
+
+IMPL_LINK(ScTpFormulaOptions, SepInsertTextHdl, OUString&, rTest, bool)
+{
+ if (!IsValidSeparator(rTest, false) && !maOldSepValue.isEmpty())
+ // Invalid separator. Restore the old value.
+ rTest = maOldSepValue;
+ return true;
+}
+
+IMPL_LINK(ScTpFormulaOptions, RowSepInsertTextHdl, OUString&, rTest, bool)
+{
+ // Invalid separator or same as ColStr - Restore the old value.
+ if ((!IsValidSeparator(rTest, true) || rTest == mxEdSepArrayCol->get_text()) && !maOldSepValue.isEmpty())
+ rTest = maOldSepValue;
+ return true;
+}
+
+IMPL_LINK(ScTpFormulaOptions, ColSepInsertTextHdl, OUString&, rTest, bool)
+{
+ // Invalid separator or same as RowStr - Restore the old value.
+ if ((!IsValidSeparator(rTest, true) || rTest == mxEdSepArrayRow->get_text()) && !maOldSepValue.isEmpty())
+ rTest = maOldSepValue;
+ return true;
+}
+
+IMPL_LINK( ScTpFormulaOptions, SepModifyHdl, weld::Entry&, rEdit, void )
+{
+ OnFocusSeparatorInput(&rEdit);
+}
+
+IMPL_LINK( ScTpFormulaOptions, SepEditOnFocusHdl, weld::Widget&, rControl, void )
+{
+ OnFocusSeparatorInput(dynamic_cast<weld::Entry*>(&rControl));
+}
+
+std::unique_ptr<SfxTabPage> ScTpFormulaOptions::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet)
+{
+ return std::make_unique<ScTpFormulaOptions>(pPage, pController, *rCoreSet);
+}
+
+bool ScTpFormulaOptions::FillItemSet(SfxItemSet* rCoreSet)
+{
+ bool bRet = false;
+ ScFormulaOptions aOpt;
+ bool bEnglishFuncName = mxCbEnglishFuncName->get_active();
+ sal_Int16 aSyntaxPos = mxLbFormulaSyntax->get_active();
+ OUString aSep = mxEdSepFuncArg->get_text();
+ OUString aSepArrayCol = mxEdSepArrayCol->get_text();
+ OUString aSepArrayRow = mxEdSepArrayRow->get_text();
+ sal_Int16 nOOXMLRecalcMode = mxLbOOXMLRecalcOptions->get_active();
+ sal_Int16 nODFRecalcMode = mxLbODFRecalcOptions->get_active();
+
+ if (mxBtnCustomCalcDefault->get_active())
+ {
+ // When Default is selected, reset all the calc config settings to default.
+ maCurrentConfig.reset();
+ }
+
+ if ( mxLbFormulaSyntax->get_saved_value() != mxLbFormulaSyntax->get_text(aSyntaxPos)
+ || mxCbEnglishFuncName->get_saved_state() != (bEnglishFuncName ? 1 : 0)
+ || mxEdSepFuncArg->get_saved_value() != aSep
+ || mxEdSepArrayCol->get_saved_value() != aSepArrayCol
+ || mxEdSepArrayRow->get_saved_value() != aSepArrayRow
+ || mxLbOOXMLRecalcOptions->get_saved_value() != mxLbOOXMLRecalcOptions->get_text(nOOXMLRecalcMode)
+ || mxLbODFRecalcOptions->get_saved_value() != mxLbODFRecalcOptions->get_text(nODFRecalcMode)
+ || maSavedConfig != maCurrentConfig
+ || maSavedDocOptions != maCurrentDocOptions )
+ {
+ ::formula::FormulaGrammar::Grammar eGram = ::formula::FormulaGrammar::GRAM_DEFAULT;
+
+ switch (aSyntaxPos)
+ {
+ case 0:
+ eGram = ::formula::FormulaGrammar::GRAM_NATIVE;
+ break;
+ case 1:
+ eGram = ::formula::FormulaGrammar::GRAM_NATIVE_XL_A1;
+ break;
+ case 2:
+ eGram = ::formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1;
+ break;
+ }
+
+ ScRecalcOptions eOOXMLRecalc = static_cast<ScRecalcOptions>(nOOXMLRecalcMode);
+ ScRecalcOptions eODFRecalc = static_cast<ScRecalcOptions>(nODFRecalcMode);
+
+ aOpt.SetFormulaSyntax(eGram);
+ aOpt.SetUseEnglishFuncName(bEnglishFuncName);
+ aOpt.SetFormulaSepArg(aSep);
+ aOpt.SetFormulaSepArrayCol(aSepArrayCol);
+ aOpt.SetFormulaSepArrayRow(aSepArrayRow);
+ aOpt.SetCalcConfig(maCurrentConfig);
+ aOpt.SetOOXMLRecalcOptions(eOOXMLRecalc);
+ aOpt.SetODFRecalcOptions(eODFRecalc);
+ aOpt.SetWriteCalcConfig( maCurrentDocOptions.IsWriteCalcConfig());
+
+ rCoreSet->Put( ScTpFormulaItem( aOpt ) );
+ rCoreSet->Put( ScTpCalcItem( SID_SCDOCOPTIONS, maCurrentDocOptions ) );
+
+ bRet = true;
+ }
+ return bRet;
+}
+
+void ScTpFormulaOptions::Reset(const SfxItemSet* rCoreSet)
+{
+ ScFormulaOptions aOpt;
+ if(const ScTpFormulaItem* pItem = rCoreSet->GetItemIfSet(SID_SCFORMULAOPTIONS, false))
+ aOpt = pItem->GetFormulaOptions();
+
+ // formula grammar.
+ ::formula::FormulaGrammar::Grammar eGram = aOpt.GetFormulaSyntax();
+
+ switch (eGram)
+ {
+ case ::formula::FormulaGrammar::GRAM_NATIVE:
+ mxLbFormulaSyntax->set_active(0);
+ break;
+ case ::formula::FormulaGrammar::GRAM_NATIVE_XL_A1:
+ mxLbFormulaSyntax->set_active(1);
+ break;
+ case ::formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1:
+ mxLbFormulaSyntax->set_active(2);
+ break;
+ default:
+ mxLbFormulaSyntax->set_active(0);
+ }
+
+ mxLbFormulaSyntax->save_value();
+ mxLbFormulaSyntax->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::Grammar::isReadOnly() );
+
+ ScRecalcOptions eOOXMLRecalc = aOpt.GetOOXMLRecalcOptions();
+ mxLbOOXMLRecalcOptions->set_active(static_cast<sal_uInt16>(eOOXMLRecalc));
+ mxLbOOXMLRecalcOptions->save_value();
+ mxLbOOXMLRecalcOptions->set_sensitive( !officecfg::Office::Calc::Formula::Load::OOXMLRecalcMode::isReadOnly() );
+
+ ScRecalcOptions eODFRecalc = aOpt.GetODFRecalcOptions();
+ mxLbODFRecalcOptions->set_active(static_cast<sal_uInt16>(eODFRecalc));
+ mxLbODFRecalcOptions->save_value();
+ mxLbODFRecalcOptions->set_sensitive( !officecfg::Office::Calc::Formula::Load::ODFRecalcMode::isReadOnly() );
+
+ // english function name.
+ mxCbEnglishFuncName->set_active( aOpt.GetUseEnglishFuncName() );
+ mxCbEnglishFuncName->save_state();
+ mxCbEnglishFuncName->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::EnglishFunctionName::isReadOnly() );
+
+ // Separators
+ OUString aSep = aOpt.GetFormulaSepArg();
+ OUString aSepArrayRow = aOpt.GetFormulaSepArrayRow();
+ OUString aSepArrayCol = aOpt.GetFormulaSepArrayCol();
+
+ if (IsValidSeparator(aSep, false) && IsValidSeparator(aSepArrayRow, true) && IsValidSeparator(aSepArrayCol, true))
+ {
+ // Each and all separators must be valid.
+ mxEdSepFuncArg->set_text(aSep);
+ mxEdSepArrayCol->set_text(aSepArrayCol);
+ mxEdSepArrayRow->set_text(aSepArrayRow);
+
+ mxEdSepFuncArg->save_value();
+ mxEdSepArrayCol->save_value();
+ mxEdSepArrayRow->save_value();
+ }
+ else
+ ResetSeparators();
+
+ mxEdSepFuncArg->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::SeparatorArg::isReadOnly() );
+ mxEdSepArrayCol->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayCol::isReadOnly() );
+ mxEdSepArrayRow->set_sensitive( !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayRow::isReadOnly() );
+ mxBtnSepReset->set_sensitive ( !officecfg::Office::Calc::Formula::Syntax::SeparatorArg::isReadOnly() &&
+ !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayCol::isReadOnly() &&
+ !officecfg::Office::Calc::Formula::Syntax::SeparatorArrayRow::isReadOnly() );
+
+ // detailed calc settings.
+ ScFormulaOptions aDefaults;
+
+ maSavedConfig = aOpt.GetCalcConfig();
+ bool bDefault = aDefaults.GetCalcConfig() == maSavedConfig;
+ UpdateCustomCalcRadioButtons(bDefault);
+
+ maCurrentConfig = maSavedConfig;
+
+ maCurrentDocOptions = maSavedDocOptions;
+}
+
+DeactivateRC ScTpFormulaOptions::DeactivatePage(SfxItemSet* /*pSet*/)
+{
+ // What's this method for ?
+ return DeactivateRC::KeepPage;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/optdlg/tpprint.cxx b/sc/source/ui/optdlg/tpprint.cxx
new file mode 100644
index 000000000..c257f6f3d
--- /dev/null
+++ b/sc/source/ui/optdlg/tpprint.cxx
@@ -0,0 +1,111 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <svl/eitem.hxx>
+
+#include <tpprint.hxx>
+#include <printopt.hxx>
+#include <scmod.hxx>
+#include <sc.hrc>
+
+ScTpPrintOptions::ScTpPrintOptions( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet& rCoreAttrs )
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/optdlg.ui", "optCalcPrintPage", &rCoreAttrs )
+ , m_xSkipEmptyPagesCB(m_xBuilder->weld_check_button("suppressCB"))
+ , m_xSelectedSheetsCB(m_xBuilder->weld_check_button("printCB"))
+ , m_xForceBreaksCB(m_xBuilder->weld_check_button("forceBreaksCB"))
+{
+}
+
+ScTpPrintOptions::~ScTpPrintOptions()
+{
+}
+
+std::unique_ptr<SfxTabPage> ScTpPrintOptions::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet)
+{
+ return std::make_unique<ScTpPrintOptions>(pPage, pController, *rAttrSet);
+}
+
+DeactivateRC ScTpPrintOptions::DeactivatePage( SfxItemSet* pSetP )
+{
+ if ( pSetP )
+ FillItemSet( pSetP );
+
+ return DeactivateRC::LeavePage;
+}
+
+void ScTpPrintOptions::Reset( const SfxItemSet* rCoreSet )
+{
+ ScPrintOptions aOptions;
+
+ if(const ScTpPrintItem* pItem = rCoreSet->GetItemIfSet(SID_SCPRINTOPTIONS, false))
+ aOptions = pItem->GetPrintOptions();
+ else
+ {
+ // when called from print dialog and no options set, use configuration
+ aOptions = SC_MOD()->GetPrintOptions();
+ }
+
+ if ( const SfxBoolItem* pItem = rCoreSet->GetItemIfSet( SID_PRINT_SELECTEDSHEET, false))
+ {
+ bool bChecked = pItem->GetValue();
+ m_xSelectedSheetsCB->set_active( bChecked );
+ }
+ else
+ {
+ m_xSelectedSheetsCB->set_active( !aOptions.GetAllSheets() );
+ }
+
+ m_xSkipEmptyPagesCB->set_active( aOptions.GetSkipEmpty() );
+ m_xSkipEmptyPagesCB->save_state();
+ m_xSelectedSheetsCB->save_state();
+ m_xForceBreaksCB->set_active( aOptions.GetForceBreaks() );
+ m_xForceBreaksCB->save_state();
+}
+
+bool ScTpPrintOptions::FillItemSet( SfxItemSet* rCoreAttrs )
+{
+ rCoreAttrs->ClearItem( SID_PRINT_SELECTEDSHEET );
+
+ bool bSkipEmptyChanged = m_xSkipEmptyPagesCB->get_state_changed_from_saved();
+ bool bSelectedSheetsChanged = m_xSelectedSheetsCB->get_state_changed_from_saved();
+ bool bForceBreaksChanged = m_xForceBreaksCB->get_state_changed_from_saved();
+
+ if ( bSkipEmptyChanged || bSelectedSheetsChanged || bForceBreaksChanged )
+ {
+ ScPrintOptions aOpt;
+ aOpt.SetSkipEmpty( m_xSkipEmptyPagesCB->get_active() );
+ aOpt.SetAllSheets( !m_xSelectedSheetsCB->get_active() );
+ aOpt.SetForceBreaks( m_xForceBreaksCB->get_active() );
+ rCoreAttrs->Put( ScTpPrintItem( aOpt ) );
+ if ( bSelectedSheetsChanged )
+ {
+ rCoreAttrs->Put( SfxBoolItem( SID_PRINT_SELECTEDSHEET, m_xSelectedSheetsCB->get_active() ) );
+ }
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/optdlg/tpusrlst.cxx b/sc/source/ui/optdlg/tpusrlst.cxx
new file mode 100644
index 000000000..6553d64de
--- /dev/null
+++ b/sc/source/ui/optdlg/tpusrlst.cxx
@@ -0,0 +1,738 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <comphelper/string.hxx>
+#include <tools/lineend.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <osl/diagnose.h>
+#include <o3tl/string_view.hxx>
+
+#include <document.hxx>
+#include <tabvwsh.hxx>
+#include <viewdata.hxx>
+#include <uiitems.hxx>
+#include <userlist.hxx>
+#include <rangeutl.hxx>
+#include <crdlg.hxx>
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <tpusrlst.hxx>
+#include <scui_def.hxx>
+
+#define CR u'\x000D'
+#define LF u'\x000A'
+
+const sal_Unicode cDelimiter = ',';
+
+// Benutzerdefinierte Listen:
+
+ScTpUserLists::ScTpUserLists( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet& rCoreAttrs )
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/optsortlists.ui", "OptSortLists",
+ &rCoreAttrs )
+ , mxFtLists(m_xBuilder->weld_label("listslabel"))
+ , mxLbLists(m_xBuilder->weld_tree_view("lists"))
+ , mxFtEntries(m_xBuilder->weld_label("entrieslabel"))
+ , mxEdEntries(m_xBuilder->weld_text_view("entries"))
+ , mxFtCopyFrom(m_xBuilder->weld_label("copyfromlabel"))
+ , mxEdCopyFrom(m_xBuilder->weld_entry("copyfrom"))
+ , mxBtnNew(m_xBuilder->weld_button("new"))
+ , mxBtnDiscard(m_xBuilder->weld_button("discard"))
+ , mxBtnAdd(m_xBuilder->weld_button("add"))
+ , mxBtnModify(m_xBuilder->weld_button("modify"))
+ , mxBtnRemove(m_xBuilder->weld_button("delete"))
+ , mxBtnCopy(m_xBuilder->weld_button("copy"))
+ , aStrQueryRemove ( ScResId( STR_QUERYREMOVE ) )
+ , aStrCopyList ( ScResId( STR_COPYLIST ) )
+ , aStrCopyFrom ( ScResId( STR_COPYFROM ) )
+ , aStrCopyErr ( ScResId( STR_COPYERR ) )
+ , nWhichUserLists ( GetWhich( SID_SCUSERLISTS ) )
+ , pDoc ( nullptr )
+ , pViewData ( nullptr )
+ , bModifyMode ( false )
+ , bCancelMode ( false )
+ , bCopyDone ( false )
+ , nCancelPos ( 0 )
+{
+ SetExchangeSupport();
+ Init();
+ Reset(&rCoreAttrs);
+}
+
+ScTpUserLists::~ScTpUserLists()
+{
+}
+
+void ScTpUserLists::Init()
+{
+ SfxViewShell* pSh = SfxViewShell::Current();
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>( pSh );
+
+ mxLbLists->connect_changed ( LINK( this, ScTpUserLists, LbSelectHdl ) );
+ mxBtnNew->connect_clicked ( LINK( this, ScTpUserLists, BtnClickHdl ) );
+ mxBtnDiscard->connect_clicked ( LINK( this, ScTpUserLists, BtnClickHdl ) );
+ mxBtnAdd->connect_clicked ( LINK( this, ScTpUserLists, BtnClickHdl ) );
+ mxBtnModify->connect_clicked ( LINK( this, ScTpUserLists, BtnClickHdl ) );
+ mxBtnRemove->connect_clicked ( LINK( this, ScTpUserLists, BtnClickHdl ) );
+ mxEdEntries->connect_changed ( LINK( this, ScTpUserLists, EdEntriesModHdl ) );
+
+ if ( pViewSh )
+ {
+ SCTAB nStartTab = 0;
+ SCTAB nEndTab = 0;
+ SCCOL nStartCol = 0;
+ SCROW nStartRow = 0;
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+
+ pViewData = &pViewSh->GetViewData();
+ pDoc = &pViewData->GetDocument();
+
+ pViewData->GetSimpleArea( nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab );
+
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+
+ aStrSelectedArea = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab
+ ).Format(*pDoc, ScRefFlags::RANGE_ABS_3D);
+
+ mxBtnCopy->connect_clicked ( LINK( this, ScTpUserLists, BtnClickHdl ) );
+ mxBtnCopy->set_sensitive(true);
+ }
+ else
+ {
+ mxBtnCopy->set_sensitive(false);
+ mxFtCopyFrom->set_sensitive(false);
+ mxEdCopyFrom->set_sensitive(false);
+ }
+
+}
+
+std::unique_ptr<SfxTabPage> ScTpUserLists::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet )
+{
+ return std::make_unique<ScTpUserLists>(pPage, pController, *rAttrSet);
+}
+
+void ScTpUserLists::Reset( const SfxItemSet* rCoreAttrs )
+{
+ const ScUserListItem& rUserListItem = static_cast<const ScUserListItem&>(
+ rCoreAttrs->Get( nWhichUserLists ));
+ const ScUserList* pCoreList = rUserListItem.GetUserList();
+
+ OSL_ENSURE( pCoreList, "UserList not found :-/" );
+
+ if ( pCoreList )
+ {
+ if ( !pUserLists )
+ pUserLists.reset( new ScUserList( *pCoreList ) );
+ else
+ *pUserLists = *pCoreList;
+
+ if ( UpdateUserListBox() > 0 )
+ {
+ mxLbLists->select( 0 );
+ UpdateEntries( 0 );
+ }
+ }
+ else if ( !pUserLists )
+ pUserLists.reset( new ScUserList );
+
+ mxEdCopyFrom->set_text( aStrSelectedArea );
+
+ if ( mxLbLists->n_children() == 0 )
+ {
+ mxFtLists->set_sensitive(false);
+ mxLbLists->set_sensitive(false);
+ mxFtEntries->set_sensitive(false);
+ mxEdEntries->set_sensitive(false);
+ mxBtnRemove->set_sensitive(false);
+ }
+
+ mxBtnNew->show();
+ mxBtnDiscard->hide();
+ mxBtnAdd->show();
+ mxBtnModify->hide();
+ mxBtnAdd->set_sensitive(false);
+ mxBtnModify->set_sensitive(false);
+
+ if ( !bCopyDone && pViewData )
+ {
+ mxFtCopyFrom->set_sensitive(true);
+ mxEdCopyFrom->set_sensitive(true);
+ mxBtnCopy->set_sensitive(true);
+ }
+}
+
+bool ScTpUserLists::FillItemSet( SfxItemSet* rCoreAttrs )
+{
+ // Changes aren't saved?
+ // -> simulate click of Add-Button
+
+ if ( bModifyMode || bCancelMode )
+ BtnClickHdl(*mxBtnAdd);
+
+ const ScUserListItem& rUserListItem = static_cast<const ScUserListItem&>(
+ GetItemSet().Get( nWhichUserLists ));
+
+ ScUserList* pCoreList = rUserListItem.GetUserList();
+ bool bDataModified = false;
+
+ if ( (pUserLists == nullptr) && (pCoreList == nullptr) )
+ {
+ bDataModified = false;
+ }
+ else if ( pUserLists != nullptr )
+ {
+ if ( pCoreList != nullptr )
+ bDataModified = (*pUserLists != *pCoreList);
+ else
+ bDataModified = true;
+ }
+
+ if ( bDataModified )
+ {
+ ScUserListItem aULItem( nWhichUserLists );
+
+ if ( pUserLists )
+ aULItem.SetUserList( *pUserLists );
+
+ rCoreAttrs->Put( aULItem );
+ }
+
+ return bDataModified;
+}
+
+DeactivateRC ScTpUserLists::DeactivatePage( SfxItemSet* pSetP )
+{
+ if ( pSetP )
+ FillItemSet( pSetP );
+
+ return DeactivateRC::LeavePage;
+}
+
+size_t ScTpUserLists::UpdateUserListBox()
+{
+ mxLbLists->clear();
+
+ if ( !pUserLists ) return 0;
+
+ size_t nCount = pUserLists->size();
+ OUString aEntry;
+
+ for ( size_t i=0; i<nCount; ++i )
+ {
+ aEntry = (*pUserLists)[i].GetString();
+ OSL_ENSURE( !aEntry.isEmpty(), "Empty UserList-entry :-/" );
+ mxLbLists->append_text( aEntry );
+ }
+
+ return nCount;
+}
+
+void ScTpUserLists::UpdateEntries( size_t nList )
+{
+ if ( !pUserLists ) return;
+
+ if ( nList < pUserLists->size() )
+ {
+ const ScUserListData& rList = (*pUserLists)[nList];
+ std::size_t nSubCount = rList.GetSubCount();
+ OUStringBuffer aEntryListStr;
+
+ for ( size_t i=0; i<nSubCount; i++ )
+ {
+ if ( i!=0 )
+ aEntryListStr.append(CR);
+ aEntryListStr.append(rList.GetSubStr(i));
+ }
+
+ mxEdEntries->set_text(convertLineEnd(aEntryListStr.makeStringAndClear(), GetSystemLineEnd()));
+ }
+ else
+ {
+ OSL_FAIL( "Invalid ListIndex :-/" );
+ }
+}
+
+void ScTpUserLists::MakeListStr( OUString& rListStr )
+{
+ if (rListStr.isEmpty())
+ return;
+
+ OUStringBuffer aStr;
+
+ for(sal_Int32 nIdx=0; nIdx>=0;)
+ {
+ aStr.append(comphelper::string::strip(o3tl::getToken(rListStr, 0, LF, nIdx), ' '));
+ aStr.append(cDelimiter);
+ }
+
+ aStr.strip(cDelimiter);
+ sal_Int32 nLen = aStr.getLength();
+
+ rListStr.clear();
+
+ // delete all duplicates of cDelimiter
+ sal_Int32 c = 0;
+ while ( c < nLen )
+ {
+ rListStr += OUStringChar(aStr[c]);
+ ++c;
+
+ if ((c < nLen) && (aStr[c] == cDelimiter))
+ {
+ rListStr += OUStringChar(aStr[c]);
+
+ while ((c < nLen) && (aStr[c] == cDelimiter))
+ ++c;
+ }
+ }
+
+}
+
+void ScTpUserLists::AddNewList( const OUString& rEntriesStr )
+{
+ OUString theEntriesStr( rEntriesStr );
+
+ if ( !pUserLists )
+ pUserLists.reset( new ScUserList );
+
+ MakeListStr( theEntriesStr );
+
+ pUserLists->push_back(new ScUserListData(theEntriesStr));
+}
+
+void ScTpUserLists::CopyListFromArea( const ScRefAddress& rStartPos,
+ const ScRefAddress& rEndPos )
+{
+ if ( bCopyDone ) return;
+
+ SCTAB nTab = rStartPos.Tab();
+ SCCOL nStartCol = rStartPos.Col();
+ SCROW nStartRow = rStartPos.Row();
+ SCCOL nEndCol = rEndPos.Col();
+ SCROW nEndRow = rEndPos.Row();
+ sal_uInt16 nCellDir = SCRET_COLS;
+
+ if ( (nStartCol != nEndCol) && (nStartRow != nEndRow) )
+ {
+ ScColOrRowDlg aDialog(GetFrameWeld(), aStrCopyList, aStrCopyFrom);
+ nCellDir = aDialog.run();
+ }
+ else if ( nStartCol != nEndCol )
+ nCellDir = SCRET_ROWS;
+ else
+ nCellDir = SCRET_COLS;
+
+ if ( nCellDir != RET_CANCEL )
+ {
+ bool bValueIgnored = false;
+
+ if ( nCellDir == SCRET_COLS )
+ {
+ for ( SCCOL col=nStartCol; col<=nEndCol; col++ )
+ {
+ OUStringBuffer aStrList;
+ for ( SCROW row=nStartRow; row<=nEndRow; row++ )
+ {
+ if ( pDoc->HasStringData( col, row, nTab ) )
+ {
+ OUString aStrField = pDoc->GetString(col, row, nTab);
+
+ if ( !aStrField.isEmpty() )
+ {
+ aStrList.append(aStrField + "\n");
+ }
+ }
+ else
+ bValueIgnored = true;
+ }
+ if ( !aStrList.isEmpty() )
+ AddNewList( aStrList.makeStringAndClear() );
+ }
+ }
+ else
+ {
+ for ( SCROW row=nStartRow; row<=nEndRow; row++ )
+ {
+ OUStringBuffer aStrList;
+ for ( SCCOL col=nStartCol; col<=nEndCol; col++ )
+ {
+ if ( pDoc->HasStringData( col, row, nTab ) )
+ {
+ OUString aStrField = pDoc->GetString(col, row, nTab);
+
+ if ( !aStrField.isEmpty() )
+ {
+ aStrList.append(aStrField + "\n");
+ }
+ }
+ else
+ bValueIgnored = true;
+ }
+ if ( !aStrList.isEmpty() )
+ AddNewList( aStrList.makeStringAndClear() );
+ }
+ }
+
+ if ( bValueIgnored )
+ {
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ aStrCopyErr));
+ xInfoBox->run();
+ }
+ }
+
+ bCopyDone = true;
+
+}
+
+void ScTpUserLists::ModifyList( size_t nSelList,
+ const OUString& rEntriesStr )
+{
+ if ( !pUserLists ) return;
+
+ OUString theEntriesStr( rEntriesStr );
+
+ MakeListStr( theEntriesStr );
+
+ (*pUserLists)[nSelList].SetString( theEntriesStr );
+}
+
+void ScTpUserLists::RemoveList( size_t nList )
+{
+ if (pUserLists && nList < pUserLists->size())
+ {
+ ScUserList::iterator itr = pUserLists->begin();
+ ::std::advance(itr, nList);
+ pUserLists->erase(itr);
+ }
+}
+
+// Handler:
+
+IMPL_LINK( ScTpUserLists, LbSelectHdl, weld::TreeView&, rLb, void )
+{
+ if ( &rLb != mxLbLists.get() )
+ return;
+
+ sal_Int32 nSelPos = mxLbLists->get_selected_index();
+ if ( nSelPos == -1 )
+ return;
+
+ if ( !mxFtEntries->get_sensitive() ) mxFtEntries->set_sensitive(true);
+ if ( !mxEdEntries->get_sensitive() ) mxEdEntries->set_sensitive(true);
+ if ( !mxBtnRemove->get_sensitive() ) mxBtnRemove->set_sensitive(true);
+ if ( mxBtnAdd->get_sensitive() )
+ {
+ mxBtnAdd->set_sensitive(false);
+ mxBtnModify->set_sensitive(false);
+ }
+
+ UpdateEntries( nSelPos );
+}
+
+IMPL_LINK( ScTpUserLists, BtnClickHdl, weld::Button&, rBtn, void )
+{
+ if (&rBtn == mxBtnNew.get() || &rBtn == mxBtnDiscard.get())
+ {
+ if ( !bCancelMode )
+ {
+ nCancelPos = ( mxLbLists->n_children() > 0 )
+ ? mxLbLists->get_selected_index()
+ : 0;
+ mxLbLists->unselect_all();
+ mxFtLists->set_sensitive(false);
+ mxLbLists->set_sensitive(false);
+ mxFtEntries->set_sensitive(true);
+ mxEdEntries->set_sensitive(true);
+ mxEdEntries->set_text( OUString() );
+ mxEdEntries->grab_focus();
+ mxBtnAdd->set_sensitive(false);
+ mxBtnModify->set_sensitive(false);
+ mxBtnRemove->set_sensitive(false);
+
+ if ( mxBtnCopy->get_sensitive() )
+ {
+ mxBtnCopy->set_sensitive(false);
+ mxFtCopyFrom->set_sensitive(false);
+ mxEdCopyFrom->set_sensitive(false);
+ }
+ mxBtnNew->hide();
+ mxBtnDiscard->show();
+ bCancelMode = true;
+ }
+ else // if ( bCancelMode )
+ {
+ if ( mxLbLists->n_children() > 0 )
+ {
+ mxLbLists->select( nCancelPos );
+ LbSelectHdl( *mxLbLists );
+ mxFtLists->set_sensitive(true);
+ mxLbLists->set_sensitive(true);
+ }
+ else
+ {
+ mxFtEntries->set_sensitive(false);
+ mxEdEntries->set_sensitive(false);
+ mxEdEntries->set_text( OUString() );
+ mxBtnRemove->set_sensitive(false);
+ }
+ mxBtnAdd->set_sensitive(false);
+ mxBtnModify->set_sensitive(false);
+
+ if ( pViewData && !bCopyDone )
+ {
+ mxBtnCopy->set_sensitive(true);
+ mxFtCopyFrom->set_sensitive(true);
+ mxEdCopyFrom->set_sensitive(true);
+ }
+ mxBtnNew->show();
+ mxBtnDiscard->hide();
+ bCancelMode = false;
+ bModifyMode = false;
+ }
+ }
+ else if (&rBtn == mxBtnAdd.get() || &rBtn == mxBtnModify.get())
+ {
+ OUString theEntriesStr( mxEdEntries->get_text() );
+
+ if ( !bModifyMode )
+ {
+ if ( !theEntriesStr.isEmpty() )
+ {
+ AddNewList( theEntriesStr );
+ UpdateUserListBox();
+ mxLbLists->select( mxLbLists->n_children()-1 );
+ LbSelectHdl( *mxLbLists );
+ mxFtLists->set_sensitive(true);
+ mxLbLists->set_sensitive(true);
+ }
+ else
+ {
+ if ( mxLbLists->n_children() > 0 )
+ {
+ mxLbLists->select( nCancelPos );
+ LbSelectHdl( *mxLbLists );
+ mxLbLists->set_sensitive(true);
+ mxLbLists->set_sensitive(true);
+ }
+ }
+
+ mxBtnAdd->set_sensitive(false);
+ mxBtnModify->set_sensitive(false);
+ mxBtnRemove->set_sensitive(true);
+ mxBtnNew->show();
+ mxBtnDiscard->hide();
+ bCancelMode = false;
+ }
+ else // if ( bModifyMode )
+ {
+ sal_Int32 nSelList = mxLbLists->get_selected_index();
+
+ OSL_ENSURE( nSelList != -1 , "Modify without List :-/" );
+
+ if ( !theEntriesStr.isEmpty() )
+ {
+ ModifyList( nSelList, theEntriesStr );
+ UpdateUserListBox();
+ mxLbLists->select( nSelList );
+ }
+ else
+ {
+ mxLbLists->select( 0 );
+ LbSelectHdl( *mxLbLists );
+ }
+
+ mxBtnNew->show();
+ mxBtnDiscard->hide();
+ bCancelMode = false;
+ mxBtnAdd->show();
+ mxBtnModify->show();
+ mxBtnAdd->set_sensitive(false);
+ mxBtnModify->set_sensitive(false);
+ bModifyMode = false;
+ mxBtnRemove->set_sensitive(true);
+ mxFtLists->set_sensitive(true);
+ mxLbLists->set_sensitive(true);
+ }
+
+ if ( pViewData && !bCopyDone )
+ {
+ mxBtnCopy->set_sensitive(true);
+ mxFtCopyFrom->set_sensitive(true);
+ mxEdCopyFrom->set_sensitive(true);
+ }
+ }
+ else if ( &rBtn == mxBtnRemove.get() )
+ {
+ if ( mxLbLists->n_children() > 0 )
+ {
+ sal_Int32 nRemovePos = mxLbLists->get_selected_index();
+ OUString aMsg = o3tl::getToken(aStrQueryRemove, 0, '#' )
+ + mxLbLists->get_text( nRemovePos )
+ + o3tl::getToken(aStrQueryRemove, 1, '#' );
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ aMsg));
+ xQueryBox->set_default_response(RET_YES);
+
+ if (RET_YES == xQueryBox->run())
+ {
+ RemoveList( nRemovePos );
+ UpdateUserListBox();
+
+ if ( mxLbLists->n_children() > 0 )
+ {
+ mxLbLists->select(
+ ( nRemovePos >= mxLbLists->n_children() )
+ ? mxLbLists->n_children()-1
+ : nRemovePos );
+ LbSelectHdl( *mxLbLists );
+ }
+ else
+ {
+ mxFtLists->set_sensitive(false);
+ mxLbLists->set_sensitive(false);
+ mxFtEntries->set_sensitive(false);
+ mxEdEntries->set_sensitive(false);
+ mxEdEntries->set_text( OUString() );
+ mxBtnRemove->set_sensitive(false);
+ }
+ }
+
+ if ( pViewData && !bCopyDone && !mxBtnCopy->get_sensitive() )
+ {
+ mxBtnCopy->set_sensitive(true);
+ mxFtCopyFrom->set_sensitive(true);
+ mxEdCopyFrom->set_sensitive(true);
+ }
+ }
+ }
+ else if ( pViewData && (&rBtn == mxBtnCopy.get()) )
+ {
+ if ( bCopyDone )
+ return;
+
+ ScRefAddress theStartPos;
+ ScRefAddress theEndPos;
+ OUString theAreaStr( mxEdCopyFrom->get_text() );
+ bool bAreaOk = false;
+
+ if ( !theAreaStr.isEmpty() )
+ {
+ bAreaOk = ScRangeUtil::IsAbsArea( theAreaStr,
+ *pDoc,
+ pViewData->GetTabNo(),
+ &theAreaStr,
+ &theStartPos,
+ &theEndPos,
+ pDoc->GetAddressConvention() );
+ if ( !bAreaOk )
+ {
+ bAreaOk = ScRangeUtil::IsAbsPos( theAreaStr,
+ *pDoc,
+ pViewData->GetTabNo(),
+ &theAreaStr,
+ &theStartPos,
+ pDoc->GetAddressConvention() );
+ theEndPos = theStartPos;
+ }
+ }
+
+ if ( bAreaOk )
+ {
+ CopyListFromArea( theStartPos, theEndPos );
+ UpdateUserListBox();
+ mxLbLists->select( mxLbLists->n_children()-1 );
+ LbSelectHdl( *mxLbLists );
+ mxEdCopyFrom->set_text( theAreaStr );
+ mxEdCopyFrom->set_sensitive(false);
+ mxBtnCopy->set_sensitive(false);
+ mxFtCopyFrom->set_sensitive(false);
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(STR_INVALID_TABREF)));
+
+ xBox->run();
+ mxEdCopyFrom->grab_focus();
+ mxEdCopyFrom->select_region(0, -1);
+ }
+ }
+}
+
+IMPL_LINK( ScTpUserLists, EdEntriesModHdl, weld::TextView&, rEd, void )
+{
+ if ( &rEd != mxEdEntries.get() )
+ return;
+
+ if ( mxBtnCopy->get_sensitive() )
+ {
+ mxBtnCopy->set_sensitive(false);
+ mxFtCopyFrom->set_sensitive(false);
+ mxEdCopyFrom->set_sensitive(false);
+ }
+
+ if ( !mxEdEntries->get_text().isEmpty() )
+ {
+ if ( !bCancelMode && !bModifyMode )
+ {
+ mxBtnNew->hide();
+ mxBtnDiscard->show();
+ bCancelMode = true;
+ mxBtnAdd->hide();
+ mxBtnAdd->set_sensitive(true);
+ mxBtnModify->show();
+ mxBtnModify->set_sensitive(true);
+ bModifyMode = true;
+ mxBtnRemove->set_sensitive(false);
+ mxFtLists->set_sensitive(false);
+ mxLbLists->set_sensitive(false);
+ }
+ else // if ( bCancelMode || bModifyMode )
+ {
+ if ( !mxBtnAdd->get_sensitive() )
+ {
+ mxBtnAdd->set_sensitive(true);
+ mxBtnModify->set_sensitive(true);
+ }
+ }
+ }
+ else
+ {
+ if ( mxBtnAdd->get_sensitive() )
+ {
+ mxBtnAdd->set_sensitive(false);
+ mxBtnModify->set_sensitive(false);
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/optdlg/tpview.cxx b/sc/source/ui/optdlg/tpview.cxx
new file mode 100644
index 000000000..d7cd46303
--- /dev/null
+++ b/sc/source/ui/optdlg/tpview.cxx
@@ -0,0 +1,619 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <tpview.hxx>
+#include <global.hxx>
+#include <viewopti.hxx>
+#include <scresid.hxx>
+#include <docsh.hxx>
+#include <sc.hrc>
+#include <strings.hrc>
+#include <units.hrc>
+#include <appoptio.hxx>
+#include <scmod.hxx>
+#include <svl/eitem.hxx>
+#include <svx/colorbox.hxx>
+#include <svtools/unitconv.hxx>
+
+ScTpContentOptions::ScTpContentOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/tpviewpage.ui", "TpViewPage", &rArgSet)
+ , m_xGridLB(m_xBuilder->weld_combo_box("grid"))
+ , m_xColorFT(m_xBuilder->weld_label("color_label"))
+ , m_xColorLB(new ColorListBox(m_xBuilder->weld_menu_button("color"),
+ [this]{ return GetDialogController()->getDialog(); }))
+ , m_xBreakCB(m_xBuilder->weld_check_button("break"))
+ , m_xGuideLineCB(m_xBuilder->weld_check_button("guideline"))
+ , m_xFormulaCB(m_xBuilder->weld_check_button("formula"))
+ , m_xNilCB(m_xBuilder->weld_check_button("nil"))
+ , m_xAnnotCB(m_xBuilder->weld_check_button("annot"))
+ , m_xValueCB(m_xBuilder->weld_check_button("value"))
+ , m_xAnchorCB(m_xBuilder->weld_check_button("anchor"))
+ , m_xClipMarkCB(m_xBuilder->weld_check_button("clipmark"))
+ , m_xRangeFindCB(m_xBuilder->weld_check_button("rangefind"))
+ , m_xObjGrfLB(m_xBuilder->weld_combo_box("objgrf"))
+ , m_xDiagramLB(m_xBuilder->weld_combo_box("diagram"))
+ , m_xDrawLB(m_xBuilder->weld_combo_box("draw"))
+ , m_xSyncZoomCB(m_xBuilder->weld_check_button("synczoom"))
+ , m_xRowColHeaderCB(m_xBuilder->weld_check_button("rowcolheader"))
+ , m_xHScrollCB(m_xBuilder->weld_check_button("hscroll"))
+ , m_xVScrollCB(m_xBuilder->weld_check_button("vscroll"))
+ , m_xTblRegCB(m_xBuilder->weld_check_button("tblreg"))
+ , m_xOutlineCB(m_xBuilder->weld_check_button("outline"))
+ , m_xSummaryCB(m_xBuilder->weld_check_button("cbSummary"))
+ , m_xThemedCursorRB(m_xBuilder->weld_radio_button("rbThemedCursor"))
+ , m_xSystemCursorRB(m_xBuilder->weld_radio_button("rbSystemCursor"))
+{
+ SetExchangeSupport();
+ Link<weld::ComboBox&,void> aSelObjHdl(LINK( this, ScTpContentOptions, SelLbObjHdl ) );
+ m_xObjGrfLB->connect_changed(aSelObjHdl);
+ m_xDiagramLB->connect_changed(aSelObjHdl);
+ m_xDrawLB->connect_changed(aSelObjHdl);
+ m_xGridLB->connect_changed( LINK( this, ScTpContentOptions, GridHdl ) );
+
+ Link<weld::Toggleable&, void> aCBHdl(LINK( this, ScTpContentOptions, CBHdl ) );
+ m_xFormulaCB->connect_toggled(aCBHdl);
+ m_xNilCB->connect_toggled(aCBHdl);
+ m_xAnnotCB->connect_toggled(aCBHdl);
+ m_xAnnotCB->set_accessible_description(ScResId(STR_A11Y_DESC_ANNOT));
+ m_xValueCB->connect_toggled(aCBHdl);
+ m_xAnchorCB->connect_toggled(aCBHdl);
+ m_xClipMarkCB->connect_toggled(aCBHdl);
+
+ m_xVScrollCB->connect_toggled(aCBHdl);
+ m_xHScrollCB->connect_toggled(aCBHdl);
+ m_xTblRegCB->connect_toggled(aCBHdl);
+ m_xOutlineCB->connect_toggled(aCBHdl);
+ m_xBreakCB->connect_toggled(aCBHdl);
+ m_xGuideLineCB->connect_toggled(aCBHdl);
+ m_xRowColHeaderCB->connect_toggled(aCBHdl);
+ m_xSummaryCB->connect_toggled(aCBHdl);
+ m_xThemedCursorRB->connect_toggled(aCBHdl);
+
+ m_xColorLB->SetSlotId(SID_ATTR_CHAR_COLOR);
+ m_xColorLB->SetAutoDisplayColor(SC_STD_GRIDCOLOR);
+}
+
+ScTpContentOptions::~ScTpContentOptions()
+{
+ m_xColorLB.reset();
+}
+
+std::unique_ptr<SfxTabPage> ScTpContentOptions::Create( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rCoreSet )
+{
+ return std::make_unique<ScTpContentOptions>(pPage, pController, *rCoreSet);
+}
+
+bool ScTpContentOptions::FillItemSet( SfxItemSet* rCoreSet )
+{
+ bool bRet = false;
+ if( m_xFormulaCB->get_state_changed_from_saved() ||
+ m_xNilCB->get_state_changed_from_saved() ||
+ m_xAnnotCB->get_state_changed_from_saved() ||
+ m_xValueCB->get_state_changed_from_saved() ||
+ m_xAnchorCB->get_state_changed_from_saved() ||
+ m_xClipMarkCB->get_state_changed_from_saved() ||
+ m_xObjGrfLB->get_value_changed_from_saved() ||
+ m_xDiagramLB->get_value_changed_from_saved() ||
+ m_xDrawLB->get_value_changed_from_saved() ||
+ m_xGridLB->get_value_changed_from_saved() ||
+ m_xRowColHeaderCB->get_state_changed_from_saved() ||
+ m_xHScrollCB->get_state_changed_from_saved() ||
+ m_xVScrollCB->get_state_changed_from_saved() ||
+ m_xTblRegCB->get_state_changed_from_saved() ||
+ m_xOutlineCB->get_state_changed_from_saved() ||
+ m_xColorLB->IsValueChangedFromSaved() ||
+ m_xBreakCB->get_state_changed_from_saved() ||
+ m_xSummaryCB->get_state_changed_from_saved() ||
+ m_xThemedCursorRB->get_state_changed_from_saved() ||
+ m_xGuideLineCB->get_state_changed_from_saved())
+ {
+ NamedColor aNamedColor = m_xColorLB->GetSelectedEntry();
+ if (aNamedColor.first == COL_AUTO)
+ {
+ aNamedColor.first = SC_STD_GRIDCOLOR;
+ aNamedColor.second.clear();
+ }
+ m_xLocalOptions->SetGridColor(aNamedColor.first, aNamedColor.second);
+ rCoreSet->Put(ScTpViewItem(*m_xLocalOptions));
+ bRet = true;
+ }
+ if(m_xRangeFindCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put(SfxBoolItem(SID_SC_INPUT_RANGEFINDER, m_xRangeFindCB->get_active()));
+ bRet = true;
+ }
+ if(m_xSyncZoomCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put(SfxBoolItem(SID_SC_OPT_SYNCZOOM, m_xSyncZoomCB->get_active()));
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+void ScTpContentOptions::Reset( const SfxItemSet* rCoreSet )
+{
+ if(const ScTpViewItem* pViewItem = rCoreSet->GetItemIfSet(SID_SCVIEWOPTIONS, false))
+ m_xLocalOptions.reset( new ScViewOptions( pViewItem->GetViewOptions() ) );
+ else
+ m_xLocalOptions.reset( new ScViewOptions );
+ m_xFormulaCB ->set_active(m_xLocalOptions->GetOption(VOPT_FORMULAS));
+ m_xNilCB ->set_active(m_xLocalOptions->GetOption(VOPT_NULLVALS));
+ m_xAnnotCB ->set_active(m_xLocalOptions->GetOption(VOPT_NOTES));
+ m_xValueCB ->set_active(m_xLocalOptions->GetOption(VOPT_SYNTAX));
+ m_xAnchorCB ->set_active(m_xLocalOptions->GetOption(VOPT_ANCHOR));
+ m_xClipMarkCB->set_active(m_xLocalOptions->GetOption(VOPT_CLIPMARKS));
+
+ m_xObjGrfLB ->set_active( static_cast<sal_uInt16>(m_xLocalOptions->GetObjMode(VOBJ_TYPE_OLE)) );
+ m_xDiagramLB ->set_active( static_cast<sal_uInt16>(m_xLocalOptions->GetObjMode(VOBJ_TYPE_CHART)) );
+ m_xDrawLB ->set_active( static_cast<sal_uInt16>(m_xLocalOptions->GetObjMode(VOBJ_TYPE_DRAW)) );
+
+ m_xRowColHeaderCB->set_active( m_xLocalOptions->GetOption(VOPT_HEADER) );
+ m_xHScrollCB->set_active( m_xLocalOptions->GetOption(VOPT_HSCROLL) );
+ m_xVScrollCB->set_active( m_xLocalOptions->GetOption(VOPT_VSCROLL) );
+ m_xTblRegCB ->set_active( m_xLocalOptions->GetOption(VOPT_TABCONTROLS) );
+ m_xOutlineCB->set_active( m_xLocalOptions->GetOption(VOPT_OUTLINER) );
+ m_xSummaryCB->set_active( m_xLocalOptions->GetOption(VOPT_SUMMARY) );
+ if ( m_xLocalOptions->GetOption(VOPT_THEMEDCURSOR) )
+ m_xThemedCursorRB->set_active( true );
+ else
+ m_xSystemCursorRB->set_active( true );
+
+ InitGridOpt();
+
+ m_xBreakCB->set_active( m_xLocalOptions->GetOption(VOPT_PAGEBREAKS) );
+ m_xGuideLineCB->set_active( m_xLocalOptions->GetOption(VOPT_HELPLINES) );
+
+ if(const SfxBoolItem* pFinderItem = rCoreSet->GetItemIfSet(SID_SC_INPUT_RANGEFINDER, false))
+ m_xRangeFindCB->set_active(pFinderItem->GetValue());
+ if(const SfxBoolItem* pZoomItem = rCoreSet->GetItemIfSet(SID_SC_OPT_SYNCZOOM, false))
+ m_xSyncZoomCB->set_active(pZoomItem->GetValue());
+
+ m_xRangeFindCB->save_state();
+ m_xSyncZoomCB->save_state();
+
+ m_xFormulaCB->save_state();
+ m_xNilCB->save_state();
+ m_xAnnotCB->save_state();
+ m_xValueCB->save_state();
+ m_xAnchorCB->save_state();
+ m_xClipMarkCB->save_state();
+ m_xObjGrfLB->save_value();
+ m_xDiagramLB->save_value();
+ m_xDrawLB->save_value();
+ m_xRowColHeaderCB->save_state();
+ m_xHScrollCB->save_state();
+ m_xVScrollCB->save_state();
+ m_xTblRegCB->save_state();
+ m_xOutlineCB->save_state();
+ m_xGridLB->save_value();
+ m_xColorLB->SaveValue();
+ m_xBreakCB->save_state();
+ m_xGuideLineCB->save_state();
+ m_xSummaryCB->save_state();
+ m_xThemedCursorRB->save_state();
+}
+
+void ScTpContentOptions::ActivatePage( const SfxItemSet& rSet)
+{
+ if(const ScTpViewItem* pViewItem = rSet.GetItemIfSet(SID_SCVIEWOPTIONS, false))
+ *m_xLocalOptions = pViewItem->GetViewOptions();
+}
+
+DeactivateRC ScTpContentOptions::DeactivatePage( SfxItemSet* pSetP )
+{
+ if(pSetP)
+ FillItemSet(pSetP);
+ return DeactivateRC::LeavePage;
+}
+
+IMPL_LINK( ScTpContentOptions, SelLbObjHdl, weld::ComboBox&, rLb, void )
+{
+ const sal_Int32 nSelPos = rLb.get_active();
+ ScVObjMode eMode = ScVObjMode(nSelPos);
+ ScVObjType eType = VOBJ_TYPE_OLE;
+
+ if ( &rLb == m_xDiagramLB.get() )
+ eType = VOBJ_TYPE_CHART;
+ else if ( &rLb == m_xDrawLB.get() )
+ eType = VOBJ_TYPE_DRAW;
+
+ m_xLocalOptions->SetObjMode( eType, eMode );
+}
+
+IMPL_LINK( ScTpContentOptions, CBHdl, weld::Toggleable&, rBtn, void )
+{
+ ScViewOption eOption = VOPT_FORMULAS;
+ bool bChecked = rBtn.get_active();
+
+ if (m_xFormulaCB.get() == &rBtn ) eOption = VOPT_FORMULAS;
+ else if ( m_xNilCB.get() == &rBtn ) eOption = VOPT_NULLVALS;
+ else if ( m_xAnnotCB.get() == &rBtn ) eOption = VOPT_NOTES;
+ else if ( m_xValueCB.get() == &rBtn ) eOption = VOPT_SYNTAX;
+ else if ( m_xAnchorCB.get() == &rBtn ) eOption = VOPT_ANCHOR;
+ else if ( m_xClipMarkCB.get() == &rBtn ) eOption = VOPT_CLIPMARKS;
+ else if ( m_xVScrollCB.get() == &rBtn ) eOption = VOPT_VSCROLL;
+ else if ( m_xHScrollCB.get() == &rBtn ) eOption = VOPT_HSCROLL;
+ else if ( m_xTblRegCB.get() == &rBtn ) eOption = VOPT_TABCONTROLS;
+ else if ( m_xOutlineCB.get() == &rBtn ) eOption = VOPT_OUTLINER;
+ else if ( m_xBreakCB.get() == &rBtn ) eOption = VOPT_PAGEBREAKS;
+ else if ( m_xGuideLineCB.get() == &rBtn ) eOption = VOPT_HELPLINES;
+ else if ( m_xRowColHeaderCB.get() == &rBtn ) eOption = VOPT_HEADER;
+ else if ( m_xSummaryCB.get() == &rBtn ) eOption = VOPT_SUMMARY;
+ else if ( m_xThemedCursorRB.get() == &rBtn ) eOption = VOPT_THEMEDCURSOR;
+
+ m_xLocalOptions->SetOption( eOption, bChecked );
+}
+
+void ScTpContentOptions::InitGridOpt()
+{
+ bool bGrid = m_xLocalOptions->GetOption( VOPT_GRID );
+ bool bGridOnTop = m_xLocalOptions->GetOption( VOPT_GRID_ONTOP );
+ sal_Int32 nSelPos = 0;
+
+ if ( bGrid || bGridOnTop )
+ {
+ m_xColorFT->set_sensitive(true);
+ m_xColorLB->set_sensitive(true);
+ if ( !bGridOnTop )
+ nSelPos = 0;
+ else
+ nSelPos = 1;
+ }
+ else
+ {
+ m_xColorFT->set_sensitive(false);
+ m_xColorLB->set_sensitive(false);
+ nSelPos = 2;
+ }
+
+ m_xGridLB->set_active (nSelPos);
+
+ // select grid color entry
+ OUString aName;
+ Color aCol = m_xLocalOptions->GetGridColor( &aName );
+
+ if (aName.trim().isEmpty() && aCol == SC_STD_GRIDCOLOR)
+ aCol = COL_AUTO;
+
+ m_xColorLB->SelectEntry(std::make_pair(aCol, aName));
+}
+
+IMPL_LINK( ScTpContentOptions, GridHdl, weld::ComboBox&, rLb, void )
+{
+ sal_Int32 nSelPos = rLb.get_active();
+ bool bGrid = ( nSelPos <= 1 );
+ bool bGridOnTop = ( nSelPos == 1 );
+
+ m_xColorFT->set_sensitive(bGrid);
+ m_xColorLB->set_sensitive(bGrid);
+ m_xLocalOptions->SetOption( VOPT_GRID, bGrid );
+ m_xLocalOptions->SetOption( VOPT_GRID_ONTOP, bGridOnTop );
+}
+
+ScTpLayoutOptions::ScTpLayoutOptions(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rArgSet)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/scgeneralpage.ui", "ScGeneralPage", &rArgSet)
+ , pDoc(nullptr)
+ , m_xUnitLB(m_xBuilder->weld_combo_box("unitlb"))
+ , m_xTabMF(m_xBuilder->weld_metric_spin_button("tabmf", FieldUnit::CM))
+ , m_xAlwaysRB(m_xBuilder->weld_radio_button("alwaysrb"))
+ , m_xRequestRB(m_xBuilder->weld_radio_button("requestrb"))
+ , m_xNeverRB(m_xBuilder->weld_radio_button("neverrb"))
+ , m_xAlignCB(m_xBuilder->weld_check_button("aligncb"))
+ , m_xAlignLB(m_xBuilder->weld_combo_box("alignlb"))
+ , m_xEditModeCB(m_xBuilder->weld_check_button("editmodecb"))
+ , m_xFormatCB(m_xBuilder->weld_check_button("formatcb"))
+ , m_xExpRefCB(m_xBuilder->weld_check_button("exprefcb"))
+ , m_xSortRefUpdateCB(m_xBuilder->weld_check_button("sortrefupdatecb"))
+ , m_xMarkHdrCB(m_xBuilder->weld_check_button("markhdrcb"))
+ , m_xTextFmtCB(m_xBuilder->weld_check_button("textfmtcb"))
+ , m_xReplWarnCB(m_xBuilder->weld_check_button("replwarncb"))
+ , m_xLegacyCellSelectionCB(m_xBuilder->weld_check_button("legacy_cell_selection_cb"))
+ , m_xEnterPasteModeCB(m_xBuilder->weld_check_button("enter_paste_mode_cb"))
+{
+ SetExchangeSupport();
+
+ m_xUnitLB->connect_changed( LINK( this, ScTpLayoutOptions, MetricHdl ) );
+ m_xAlignCB->connect_toggled(LINK(this, ScTpLayoutOptions, AlignHdl));
+
+ for (size_t i = 0; i < SAL_N_ELEMENTS(SCSTR_UNIT); ++i)
+ {
+ OUString sMetric = ScResId(SCSTR_UNIT[i].first);
+ FieldUnit eFUnit = SCSTR_UNIT[i].second;
+
+ switch ( eFUnit )
+ {
+ case FieldUnit::MM:
+ case FieldUnit::CM:
+ case FieldUnit::POINT:
+ case FieldUnit::PICA:
+ case FieldUnit::INCH:
+ {
+ // only use these metrics
+ m_xUnitLB->append(OUString::number(static_cast<sal_uInt32>(eFUnit)), sMetric);
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+}
+
+ScTpLayoutOptions::~ScTpLayoutOptions()
+{
+}
+
+std::unique_ptr<SfxTabPage> ScTpLayoutOptions::Create( weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet* rCoreSet )
+{
+ auto xNew = std::make_unique<ScTpLayoutOptions>(pPage, pController, *rCoreSet);
+
+ ScDocShell* pDocSh = dynamic_cast< ScDocShell *>( SfxObjectShell::Current() );
+ if (pDocSh!=nullptr)
+ xNew->pDoc = &pDocSh->GetDocument();
+ return xNew;
+}
+
+bool ScTpLayoutOptions::FillItemSet( SfxItemSet* rCoreSet )
+{
+ bool bRet = true;
+ if (m_xUnitLB->get_value_changed_from_saved())
+ {
+ const sal_Int32 nMPos = m_xUnitLB->get_active();
+ sal_uInt16 nFieldUnit = m_xUnitLB->get_id(nMPos).toUInt32();
+ rCoreSet->Put( SfxUInt16Item( SID_ATTR_METRIC, nFieldUnit ) );
+ bRet = true;
+ }
+
+ if (m_xTabMF->get_value_changed_from_saved())
+ {
+ rCoreSet->Put(SfxUInt16Item(SID_ATTR_DEFTABSTOP,
+ sal::static_int_cast<sal_uInt16>( m_xTabMF->denormalize(m_xTabMF->get_value(FieldUnit::TWIP)) )));
+ bRet = true;
+ }
+
+ ScLkUpdMode nSet=LM_ALWAYS;
+
+ if (m_xRequestRB->get_active())
+ {
+ nSet=LM_ON_DEMAND;
+ }
+ else if (m_xNeverRB->get_active())
+ {
+ nSet=LM_NEVER;
+ }
+
+ if (m_xRequestRB->get_state_changed_from_saved() ||
+ m_xNeverRB->get_state_changed_from_saved() )
+ {
+ if(pDoc)
+ pDoc->SetLinkMode(nSet);
+ ScAppOptions aAppOptions=SC_MOD()->GetAppOptions();
+ aAppOptions.SetLinkMode(nSet );
+ SC_MOD()->SetAppOptions(aAppOptions);
+ bRet = true;
+ }
+ if (m_xAlignCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put(SfxBoolItem(SID_SC_INPUT_SELECTION, m_xAlignCB->get_active()));
+ bRet = true;
+ }
+
+ if (m_xAlignLB->get_value_changed_from_saved())
+ {
+ rCoreSet->Put(SfxUInt16Item(SID_SC_INPUT_SELECTIONPOS, m_xAlignLB->get_active()));
+ bRet = true;
+ }
+
+ if (m_xEditModeCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put(SfxBoolItem(SID_SC_INPUT_EDITMODE, m_xEditModeCB->get_active()));
+ bRet = true;
+ }
+
+ if (m_xFormatCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put(SfxBoolItem(SID_SC_INPUT_FMT_EXPAND, m_xFormatCB->get_active()));
+ bRet = true;
+ }
+
+ if (m_xExpRefCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put(SfxBoolItem(SID_SC_INPUT_REF_EXPAND, m_xExpRefCB->get_active()));
+ bRet = true;
+ }
+
+ if (m_xSortRefUpdateCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put(SfxBoolItem(SID_SC_OPT_SORT_REF_UPDATE, m_xSortRefUpdateCB->get_active()));
+ bRet = true;
+ }
+
+ if (m_xMarkHdrCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put(SfxBoolItem(SID_SC_INPUT_MARK_HEADER, m_xMarkHdrCB->get_active()));
+ bRet = true;
+ }
+
+ if (m_xTextFmtCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put(SfxBoolItem(SID_SC_INPUT_TEXTWYSIWYG, m_xTextFmtCB->get_active()));
+ bRet = true;
+ }
+
+ if (m_xReplWarnCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put( SfxBoolItem( SID_SC_INPUT_REPLCELLSWARN, m_xReplWarnCB->get_active() ) );
+ bRet = true;
+ }
+
+ if (m_xLegacyCellSelectionCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put( SfxBoolItem( SID_SC_INPUT_LEGACY_CELL_SELECTION, m_xLegacyCellSelectionCB->get_active() ) );
+ bRet = true;
+ }
+
+ if (m_xEnterPasteModeCB->get_state_changed_from_saved())
+ {
+ rCoreSet->Put( SfxBoolItem( SID_SC_INPUT_ENTER_PASTE_MODE, m_xEnterPasteModeCB->get_active() ) );
+ bRet = true;
+ }
+
+ return bRet;
+}
+
+void ScTpLayoutOptions::Reset( const SfxItemSet* rCoreSet )
+{
+ m_xUnitLB->set_active(-1);
+ if ( rCoreSet->GetItemState( SID_ATTR_METRIC ) >= SfxItemState::DEFAULT )
+ {
+ const SfxUInt16Item& rItem = rCoreSet->Get( SID_ATTR_METRIC );
+ FieldUnit eFieldUnit = static_cast<FieldUnit>(rItem.GetValue());
+
+ for (sal_Int32 i = 0, nEntryCount = m_xUnitLB->get_count(); i < nEntryCount; ++i)
+ {
+ if (m_xUnitLB->get_id(i).toUInt32() == static_cast<sal_uInt32>(eFieldUnit))
+ {
+ m_xUnitLB->set_active(i);
+ break;
+ }
+ }
+ ::SetFieldUnit(*m_xTabMF, eFieldUnit);
+ }
+ m_xUnitLB->save_value();
+
+ if(const SfxUInt16Item* pTabStopItem = rCoreSet->GetItemIfSet(SID_ATTR_DEFTABSTOP, false))
+ m_xTabMF->set_value(m_xTabMF->normalize(pTabStopItem->GetValue()), FieldUnit::TWIP);
+ m_xTabMF->save_value();
+
+ m_xUnitLB->save_value();
+ m_xTabMF->save_value();
+
+ ScLkUpdMode nSet=LM_UNKNOWN;
+
+ if(pDoc!=nullptr)
+ {
+ nSet=pDoc->GetLinkMode();
+ }
+
+ if(nSet==LM_UNKNOWN)
+ {
+ ScAppOptions aAppOptions=SC_MOD()->GetAppOptions();
+ nSet=aAppOptions.GetLinkMode();
+ }
+
+ switch(nSet)
+ {
+ case LM_ALWAYS: m_xAlwaysRB->set_active(true); break;
+ case LM_NEVER: m_xNeverRB->set_active(true); break;
+ case LM_ON_DEMAND: m_xRequestRB->set_active(true); break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ if(const SfxBoolItem* pSelectionItem = rCoreSet->GetItemIfSet(SID_SC_INPUT_SELECTION, false))
+ m_xAlignCB->set_active(pSelectionItem->GetValue());
+
+ if(const SfxUInt16Item* pPosItem = rCoreSet->GetItemIfSet(SID_SC_INPUT_SELECTIONPOS, false))
+ m_xAlignLB->set_active(pPosItem->GetValue());
+
+ if(const SfxBoolItem* pEditModeItem = rCoreSet->GetItemIfSet(SID_SC_INPUT_EDITMODE, false))
+ m_xEditModeCB->set_active(pEditModeItem->GetValue());
+
+ if(const SfxBoolItem* pExpandItem = rCoreSet->GetItemIfSet(SID_SC_INPUT_FMT_EXPAND, false))
+ m_xFormatCB->set_active(pExpandItem->GetValue());
+
+ if(const SfxBoolItem* pExpandItem = rCoreSet->GetItemIfSet(SID_SC_INPUT_REF_EXPAND, false))
+ m_xExpRefCB->set_active(pExpandItem->GetValue());
+
+ if (const SfxBoolItem* pUpdateItem = rCoreSet->GetItemIfSet(SID_SC_OPT_SORT_REF_UPDATE))
+ m_xSortRefUpdateCB->set_active(pUpdateItem->GetValue());
+
+ if(const SfxBoolItem* pHeaderItem = rCoreSet->GetItemIfSet(SID_SC_INPUT_MARK_HEADER, false))
+ m_xMarkHdrCB->set_active(pHeaderItem->GetValue());
+
+ if(const SfxBoolItem* pWysiItem = rCoreSet->GetItemIfSet(SID_SC_INPUT_TEXTWYSIWYG, false))
+ m_xTextFmtCB->set_active(pWysiItem->GetValue());
+
+ if( const SfxBoolItem* pWarnItem = rCoreSet->GetItemIfSet( SID_SC_INPUT_REPLCELLSWARN, false ) )
+ m_xReplWarnCB->set_active( pWarnItem->GetValue() );
+
+ if( const SfxBoolItem* pSelectionItem = rCoreSet->GetItemIfSet( SID_SC_INPUT_LEGACY_CELL_SELECTION, false ) )
+ m_xLegacyCellSelectionCB->set_active( pSelectionItem->GetValue() );
+
+ if( const SfxBoolItem* pPasteModeItem = rCoreSet->GetItemIfSet( SID_SC_INPUT_ENTER_PASTE_MODE, false ) )
+ m_xEnterPasteModeCB->set_active( pPasteModeItem->GetValue() );
+
+ m_xAlignCB->save_state();
+ m_xAlignLB->save_value();
+ m_xEditModeCB->save_state();
+ m_xFormatCB->save_state();
+
+ m_xExpRefCB->save_state();
+ m_xSortRefUpdateCB->save_state();
+ m_xMarkHdrCB->save_state();
+ m_xTextFmtCB->save_state();
+ m_xReplWarnCB->save_state();
+
+ m_xLegacyCellSelectionCB->save_state();
+ m_xEnterPasteModeCB->save_state();
+
+ AlignHdl(*m_xAlignCB);
+
+ m_xAlwaysRB->save_state();
+ m_xNeverRB->save_state();
+ m_xRequestRB->save_state();
+}
+
+void ScTpLayoutOptions::ActivatePage( const SfxItemSet& /* rCoreSet */ )
+{
+}
+
+DeactivateRC ScTpLayoutOptions::DeactivatePage( SfxItemSet* pSetP )
+{
+ if(pSetP)
+ FillItemSet(pSetP);
+ return DeactivateRC::LeavePage;
+}
+
+IMPL_LINK_NOARG(ScTpLayoutOptions, MetricHdl, weld::ComboBox&, void)
+{
+ const sal_Int32 nMPos = m_xUnitLB->get_active();
+ if (nMPos != -1)
+ {
+ FieldUnit eFieldUnit = static_cast<FieldUnit>(m_xUnitLB->get_id(nMPos).toUInt32());
+ sal_Int64 nVal =
+ m_xTabMF->denormalize( m_xTabMF->get_value( FieldUnit::TWIP ) );
+ ::SetFieldUnit( *m_xTabMF, eFieldUnit );
+ m_xTabMF->set_value( m_xTabMF->normalize( nVal ), FieldUnit::TWIP );
+ }
+}
+
+IMPL_LINK(ScTpLayoutOptions, AlignHdl, weld::Toggleable&, rBox, void)
+{
+ m_xAlignLB->set_sensitive(rBox.get_active());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/pagedlg/areasdlg.cxx b/sc/source/ui/pagedlg/areasdlg.cxx
new file mode 100644
index 000000000..51533dbf2
--- /dev/null
+++ b/sc/source/ui/pagedlg/areasdlg.cxx
@@ -0,0 +1,786 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rangelst.hxx>
+
+#include <sfx2/dispatch.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <unotools/charclass.hxx>
+
+#include <areasdlg.hxx>
+#include <rangenam.hxx>
+#include <reffact.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <compiler.hxx>
+#include <markdata.hxx>
+
+// List box positions for print range (PR)
+enum {
+ SC_AREASDLG_PR_ENTIRE = 1,
+ SC_AREASDLG_PR_USER = 2,
+ SC_AREASDLG_PR_SELECT = 3
+};
+
+// List box positions for repeat ranges (RR)
+enum {
+ SC_AREASDLG_RR_NONE = 0,
+ SC_AREASDLG_RR_USER = 1,
+ SC_AREASDLG_RR_OFFSET = 2
+};
+
+namespace
+{
+ void ERRORBOX(weld::Window* pParent, TranslateId rId)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(rId)));
+ xBox->run();
+ }
+}
+
+// global functions (->at the end of the file):
+
+static bool lcl_CheckRepeatString( const OUString& rStr, const ScDocument& rDoc, bool bIsRow, ScRange* pRange );
+static void lcl_GetRepeatRangeString( std::optional<ScRange> oRange, const ScDocument& rDoc, bool bIsRow, OUString& rStr );
+
+#if 0
+// this method is useful when debugging address flags.
+static void printAddressFlags(ScRefFlags nFlag)
+{
+ if ((nFlag & ScRefFlags::COL_ABS ) == ScRefFlags::COL_ABS ) printf("ScRefFlags::COL_ABS \n");
+ if ((nFlag & ScRefFlags::ROW_ABS ) == ScRefFlags::ROW_ABS ) printf("ScRefFlags::ROW_ABS \n");
+ if ((nFlag & ScRefFlags::TAB_ABS ) == ScRefFlags::TAB_ABS ) printf("ScRefFlags::TAB_ABS \n");
+ if ((nFlag & ScRefFlags::TAB_3D ) == ScRefFlags::TAB_3D ) printf("ScRefFlags::TAB_3D \n");
+ if ((nFlag & ScRefFlags::COL2_ABS ) == ScRefFlags::COL2_ABS ) printf("ScRefFlags::COL2_ABS \n");
+ if ((nFlag & ScRefFlags::ROW2_ABS ) == ScRefFlags::ROW2_ABS ) printf("ScRefFlags::ROW2_ABS \n");
+ if ((nFlag & ScRefFlags::TAB2_ABS ) == ScRefFlags::TAB2_ABS ) printf("ScRefFlags::TAB2_ABS \n");
+ if ((nFlag & ScRefFlags::TAB2_3D ) == ScRefFlags::TAB2_3D ) printf("ScRefFlags::TAB2_3D \n");
+ if ((nFlag & ScRefFlags::ROW_VALID ) == ScRefFlags::ROW_VALID ) printf("ScRefFlags::ROW_VALID \n");
+ if ((nFlag & ScRefFlags::COL_VALID ) == ScRefFlags::COL_VALID ) printf("ScRefFlags::COL_VALID \n");
+ if ((nFlag & ScRefFlags::TAB_VALID ) == ScRefFlags::TAB_VALID ) printf("ScRefFlags::TAB_VALID \n");
+ if ((nFlag & ScRefFlags::FORCE_DOC ) == ScRefFlags::FORCE_DOC ) printf("ScRefFlags::FORCE_DOC \n");
+ if ((nFlag & ScRefFlags::ROW2_VALID ) == ScRefFlags::ROW2_VALID ) printf("ScRefFlags::ROW2_VALID \n");
+ if ((nFlag & ScRefFlags::COL2_VALID ) == ScRefFlags::COL2_VALID ) printf("ScRefFlags::COL2_VALID \n");
+ if ((nFlag & ScRefFlags::TAB2_VALID ) == ScRefFlags::TAB2_VALID ) printf("ScRefFlags::TAB2_VALID \n");
+ if ((nFlag & ScRefFlags::VALID ) == ScRefFlags::VALID ) printf("ScRefFlags::VALID \n");
+ if ((nFlag & ScRefFlags::ADDR_ABS ) == ScRefFlags::ADDR_ABS ) printf("ScRefFlags::ADDR_ABS \n");
+ if ((nFlag & ScRefFlags::RANGE_ABS ) == ScRefFlags::RANGE_ABS ) printf("ScRefFlags::RANGE_ABS \n");
+ if ((nFlag & ScRefFlags::ADDR_ABS_3D ) == ScRefFlags::ADDR_ABS_3D ) printf("ScRefFlags::ADDR_ABS_3D \n");
+ if ((nFlag & ScRefFlags::RANGE_ABS_3D ) == ScRefFlags::RANGE_ABS_3D ) printf("ScRefFlags::RANGE_ABS_3D \n");
+}
+#endif
+
+
+ScPrintAreasDlg::ScPrintAreasDlg(SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent)
+ : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/printareasdialog.ui", "PrintAreasDialog")
+ , bDlgLostFocus(false)
+ , pDoc(nullptr)
+ , pViewData(nullptr)
+ , nCurTab(0)
+ , m_xLbPrintArea(m_xBuilder->weld_combo_box("lbprintarea"))
+ , m_xEdPrintArea(new formula::RefEdit(m_xBuilder->weld_entry("edprintarea")))
+ , m_xRbPrintArea(new formula::RefButton(m_xBuilder->weld_button("rbprintarea")))
+ , m_xLbRepeatRow(m_xBuilder->weld_combo_box("lbrepeatrow"))
+ , m_xEdRepeatRow(new formula::RefEdit(m_xBuilder->weld_entry("edrepeatrow")))
+ , m_xRbRepeatRow(new formula::RefButton(m_xBuilder->weld_button("rbrepeatrow")))
+ , m_xLbRepeatCol(m_xBuilder->weld_combo_box("lbrepeatcol"))
+ , m_xEdRepeatCol(new formula::RefEdit(m_xBuilder->weld_entry("edrepeatcol")))
+ , m_xRbRepeatCol(new formula::RefButton(m_xBuilder->weld_button("rbrepeatcol")))
+ , m_xBtnOk(m_xBuilder->weld_button("ok"))
+ , m_xBtnCancel(m_xBuilder->weld_button("cancel"))
+ , m_xPrintFrame(m_xBuilder->weld_frame("printframe"))
+ , m_xRowFrame(m_xBuilder->weld_frame("rowframe"))
+ , m_xColFrame(m_xBuilder->weld_frame("colframe"))
+ , m_xPrintFrameFT(m_xPrintFrame->weld_label_widget())
+ , m_xRowFrameFT(m_xRowFrame->weld_label_widget())
+ , m_xColFrameFT(m_xColFrame->weld_label_widget())
+{
+ m_xEdPrintArea->SetReferences(this, m_xPrintFrameFT.get());
+ m_pRefInputEdit = m_xEdPrintArea.get();
+ m_xRbPrintArea->SetReferences(this, m_xEdPrintArea.get());
+
+ m_xEdRepeatRow->SetReferences(this, m_xRowFrameFT.get());
+ m_xRbRepeatRow->SetReferences(this, m_xEdRepeatRow.get());
+
+ m_xEdRepeatCol->SetReferences(this, m_xColFrameFT.get());
+ m_xRbRepeatCol->SetReferences(this, m_xEdRepeatCol.get());
+
+ ScTabViewShell* pScViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ ScDocShell* pScDocSh = dynamic_cast<ScDocShell*>(SfxObjectShell::Current());
+ assert(pScDocSh && "Current DocumentShell not found :-(");
+
+ pDoc = &pScDocSh->GetDocument();
+
+ if ( pScViewSh )
+ {
+ pViewData = &pScViewSh->GetViewData();
+ nCurTab = pViewData->GetTabNo();
+ }
+
+ Impl_Reset();
+
+ //@BugID 54702 Enable/Disable only in base class
+ //SFX_APPWINDOW->Enable();
+}
+
+ScPrintAreasDlg::~ScPrintAreasDlg()
+{
+}
+
+void ScPrintAreasDlg::Close()
+{
+ DoClose( ScPrintAreasDlgWrapper::GetChildWindowId() );
+}
+
+bool ScPrintAreasDlg::IsTableLocked() const
+{
+ // Printing areas are per table, therefore it makes no sense,
+ // to switch the table during input
+
+ return true;
+}
+
+void ScPrintAreasDlg::SetReference( const ScRange& rRef, ScDocument& /* rDoc */ )
+{
+ if ( !m_pRefInputEdit )
+ return;
+
+ if ( rRef.aStart != rRef.aEnd )
+ RefInputStart( m_pRefInputEdit );
+
+ OUString aStr;
+ const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
+
+ if (m_xEdPrintArea.get() == m_pRefInputEdit)
+ {
+ aStr = rRef.Format(*pDoc, ScRefFlags::RANGE_ABS, eConv);
+ OUString aVal = m_xEdPrintArea->GetText();
+ Selection aSel = m_xEdPrintArea->GetSelection();
+ aSel.Justify();
+ aVal = aVal.replaceAt( aSel.Min(), aSel.Len(), aStr );
+ Selection aNewSel( aSel.Min(), aSel.Min()+aStr.getLength() );
+ m_xEdPrintArea->SetRefString( aVal );
+ m_xEdPrintArea->SetSelection( aNewSel );
+ }
+ else
+ {
+ bool bRow = ( m_xEdRepeatRow.get() == m_pRefInputEdit );
+ lcl_GetRepeatRangeString(rRef, *pDoc, bRow, aStr);
+ m_pRefInputEdit->SetRefString( aStr );
+ }
+ Impl_ModifyHdl( *m_pRefInputEdit );
+}
+
+void ScPrintAreasDlg::AddRefEntry()
+{
+ if (m_pRefInputEdit == m_xEdPrintArea.get())
+ {
+ const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
+ OUString aVal = m_xEdPrintArea->GetText() + OUStringChar(sep);
+ m_xEdPrintArea->SetText(aVal);
+
+ sal_Int32 nLen = aVal.getLength();
+ m_xEdPrintArea->SetSelection( Selection( nLen, nLen ) );
+
+ Impl_ModifyHdl( *m_xEdPrintArea );
+ }
+}
+
+void ScPrintAreasDlg::Deactivate()
+{
+ bDlgLostFocus = true;
+}
+
+void ScPrintAreasDlg::SetActive()
+{
+ if ( bDlgLostFocus )
+ {
+ bDlgLostFocus = false;
+
+ if ( m_pRefInputEdit )
+ {
+ m_pRefInputEdit->GrabFocus();
+ Impl_ModifyHdl( *m_pRefInputEdit );
+ }
+ }
+ else
+ m_xDialog->grab_focus();
+
+ RefInputDone();
+}
+
+void ScPrintAreasDlg::Impl_Reset()
+{
+ OUString aStrRange;
+ std::optional<ScRange> oRepeatColRange = pDoc->GetRepeatColRange( nCurTab );
+ std::optional<ScRange> oRepeatRowRange = pDoc->GetRepeatRowRange( nCurTab );
+
+ m_xEdPrintArea->SetModifyHdl (LINK( this, ScPrintAreasDlg, Impl_ModifyHdl));
+ m_xEdRepeatRow->SetModifyHdl (LINK( this, ScPrintAreasDlg, Impl_ModifyHdl));
+ m_xEdRepeatCol->SetModifyHdl (LINK( this, ScPrintAreasDlg, Impl_ModifyHdl));
+ m_xEdPrintArea->SetGetFocusHdl(LINK( this, ScPrintAreasDlg, Impl_GetEditFocusHdl));
+ m_xEdRepeatRow->SetGetFocusHdl(LINK( this, ScPrintAreasDlg, Impl_GetEditFocusHdl));
+ m_xEdRepeatCol->SetGetFocusHdl(LINK( this, ScPrintAreasDlg, Impl_GetEditFocusHdl));
+ m_xLbPrintArea->connect_focus_in(LINK( this, ScPrintAreasDlg, Impl_GetFocusHdl));
+ m_xLbRepeatRow->connect_focus_in(LINK( this, ScPrintAreasDlg, Impl_GetFocusHdl));
+ m_xLbRepeatCol->connect_focus_in(LINK( this, ScPrintAreasDlg, Impl_GetFocusHdl));
+ m_xLbPrintArea->connect_changed(LINK( this, ScPrintAreasDlg, Impl_SelectHdl));
+ m_xLbRepeatRow->connect_changed(LINK( this, ScPrintAreasDlg, Impl_SelectHdl));
+ m_xLbRepeatCol->connect_changed(LINK( this, ScPrintAreasDlg, Impl_SelectHdl));
+ m_xBtnOk->connect_clicked(LINK( this, ScPrintAreasDlg, Impl_BtnHdl));
+ m_xBtnCancel->connect_clicked(LINK( this, ScPrintAreasDlg, Impl_BtnHdl));
+
+ Impl_FillLists();
+
+ // printing area
+
+ aStrRange.clear();
+ const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
+ const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
+ sal_uInt16 nRangeCount = pDoc->GetPrintRangeCount( nCurTab );
+ for (sal_uInt16 i=0; i<nRangeCount; i++)
+ {
+ const ScRange* pPrintRange = pDoc->GetPrintRange( nCurTab, i );
+ if (pPrintRange)
+ {
+ if ( !aStrRange.isEmpty() )
+ aStrRange += OUStringChar(sep);
+ aStrRange += pPrintRange->Format(*pDoc, ScRefFlags::RANGE_ABS, eConv);
+ }
+ }
+ m_xEdPrintArea->SetText( aStrRange );
+
+ // repeat row
+
+ lcl_GetRepeatRangeString(oRepeatRowRange, *pDoc, true, aStrRange);
+ m_xEdRepeatRow->SetText( aStrRange );
+
+ // repeat column
+
+ lcl_GetRepeatRangeString(oRepeatColRange, *pDoc, false, aStrRange);
+ m_xEdRepeatCol->SetText( aStrRange );
+
+ Impl_ModifyHdl( *m_xEdPrintArea );
+ Impl_ModifyHdl( *m_xEdRepeatRow );
+ Impl_ModifyHdl( *m_xEdRepeatCol );
+ if( pDoc->IsPrintEntireSheet( nCurTab ) )
+ m_xLbPrintArea->set_active(SC_AREASDLG_PR_ENTIRE);
+
+ m_xEdPrintArea->SaveValue(); // save for FillItemSet():
+ m_xEdRepeatRow->SaveValue();
+ m_xEdRepeatCol->SaveValue();
+}
+
+bool ScPrintAreasDlg::Impl_GetItem( const formula::RefEdit* pEd, SfxStringItem& rItem )
+{
+ OUString aRangeStr = pEd->GetText();
+ bool bDataChanged = pEd->IsValueChangedFromSaved();
+
+ if ( !aRangeStr.isEmpty() && m_xEdPrintArea.get() != pEd )
+ {
+ ScRange aRange;
+ const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
+ lcl_CheckRepeatString(aRangeStr, *pDoc, m_xEdRepeatRow.get() == pEd, &aRange);
+ aRangeStr = aRange.Format(*pDoc, ScRefFlags::RANGE_ABS, eConv);
+ }
+
+ rItem.SetValue( aRangeStr );
+
+ return bDataChanged;
+}
+
+bool ScPrintAreasDlg::Impl_CheckRefStrings()
+{
+ bool bOk = false;
+ OUString aStrPrintArea = m_xEdPrintArea->GetText();
+ OUString aStrRepeatRow = m_xEdRepeatRow->GetText();
+ OUString aStrRepeatCol = m_xEdRepeatCol->GetText();
+
+ bool bPrintAreaOk = true;
+ if ( !aStrPrintArea.isEmpty() )
+ {
+ const ScRefFlags nValidAddr = ScRefFlags::VALID | ScRefFlags::ROW_VALID | ScRefFlags::COL_VALID;
+ const ScRefFlags nValidRange = nValidAddr | ScRefFlags::ROW2_VALID | ScRefFlags::COL2_VALID;
+ const formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
+ const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
+
+ ScAddress aAddr;
+ ScRange aRange;
+ for ( sal_Int32 nIdx = 0; nIdx >= 0; )
+ {
+ const OUString aOne = aStrPrintArea.getToken(0, sep, nIdx);
+ ScRefFlags nResult = aRange.Parse( aOne, *pDoc, eConv );
+ if ((nResult & nValidRange) != nValidRange)
+ {
+ ScRefFlags nAddrResult = aAddr.Parse( aOne, *pDoc, eConv );
+ if ((nAddrResult & nValidAddr) != nValidAddr)
+ {
+ bPrintAreaOk = false;
+ break;
+ }
+ }
+ }
+ }
+
+ bool bRepeatRowOk = aStrRepeatRow.isEmpty();
+ if ( !bRepeatRowOk )
+ bRepeatRowOk = lcl_CheckRepeatString(aStrRepeatRow, *pDoc, true, nullptr);
+
+ bool bRepeatColOk = aStrRepeatCol.isEmpty();
+ if ( !bRepeatColOk )
+ bRepeatColOk = lcl_CheckRepeatString(aStrRepeatCol, *pDoc, false, nullptr);
+
+ // error messages
+
+ bOk = (bPrintAreaOk && bRepeatRowOk && bRepeatColOk);
+
+ if ( !bOk )
+ {
+ formula::RefEdit* pEd = nullptr;
+
+ if ( !bPrintAreaOk ) pEd = m_xEdPrintArea.get();
+ else if ( !bRepeatRowOk ) pEd = m_xEdRepeatRow.get();
+ else if ( !bRepeatColOk ) pEd = m_xEdRepeatCol.get();
+
+ ERRORBOX(m_xDialog.get(), STR_INVALID_TABREF);
+
+ OSL_ASSERT(pEd);
+
+ if (pEd)
+ pEd->GrabFocus();
+ }
+
+ return bOk;
+}
+
+void ScPrintAreasDlg::Impl_FillLists()
+{
+
+ // Get selection and remember String in PrintArea-ListBox
+
+ ScRange aRange;
+ OUString aStrRange;
+ bool bSimple = true;
+
+ if ( pViewData )
+ bSimple = (pViewData->GetSimpleArea( aRange ) == SC_MARK_SIMPLE);
+
+ formula::FormulaGrammar::AddressConvention eConv = pDoc->GetAddressConvention();
+
+ if ( bSimple )
+ aStrRange = aRange.Format(*pDoc, ScRefFlags::RANGE_ABS, eConv);
+ else
+ {
+ ScRangeListRef aList( new ScRangeList );
+ pViewData->GetMarkData().FillRangeListWithMarks( aList.get(), false );
+ aList->Format(aStrRange, ScRefFlags::RANGE_ABS, *pDoc, eConv);
+ }
+
+ m_xLbPrintArea->set_id(SC_AREASDLG_PR_SELECT, aStrRange);
+
+ // Get ranges and remember in ListBoxen
+
+ ScRangeName* pRangeNames = pDoc->GetRangeName();
+
+ if (!pRangeNames || pRangeNames->empty())
+ // No range names to process.
+ return;
+
+ for (const auto& rEntry : *pRangeNames)
+ {
+ if (!rEntry.second->HasType(ScRangeData::Type::AbsArea )
+ && !rEntry.second->HasType(ScRangeData::Type::RefArea)
+ && !rEntry.second->HasType(ScRangeData::Type::AbsPos ))
+ continue;
+
+ OUString aName = rEntry.second->GetName();
+ OUString aSymbol = rEntry.second->GetSymbol();
+ if (aRange.ParseAny(aSymbol, *pDoc, eConv) & ScRefFlags::VALID)
+ {
+ if (rEntry.second->HasType(ScRangeData::Type::PrintArea))
+ {
+ aSymbol = aRange.Format(*pDoc, ScRefFlags::RANGE_ABS, eConv);
+ m_xLbPrintArea->append(aSymbol, aName);
+ }
+
+ if (rEntry.second->HasType(ScRangeData::Type::RowHeader))
+ {
+ lcl_GetRepeatRangeString(aRange, *pDoc, true, aSymbol);
+ m_xLbRepeatRow->append(aSymbol, aName);
+ }
+
+ if (rEntry.second->HasType(ScRangeData::Type::ColHeader))
+ {
+ lcl_GetRepeatRangeString(aRange, *pDoc, false, aSymbol);
+ m_xLbRepeatCol->append(aSymbol, aName);
+ }
+ }
+ }
+}
+
+// Handler:
+
+IMPL_LINK(ScPrintAreasDlg, Impl_BtnHdl, weld::Button&, rBtn, void)
+{
+ if (m_xBtnOk.get() == &rBtn)
+ {
+ if ( Impl_CheckRefStrings() )
+ {
+ SfxStringItem aPrintArea( SID_CHANGE_PRINTAREA, "" );
+ SfxStringItem aRepeatRow( FN_PARAM_2, "" );
+ SfxStringItem aRepeatCol( FN_PARAM_3, "" );
+
+ // Printing area changed?
+
+ // first try the list box, if "Entire sheet" is selected
+ bool bEntireSheet = (m_xLbPrintArea->get_active() == SC_AREASDLG_PR_ENTIRE);
+ SfxBoolItem aEntireSheet( FN_PARAM_4, bEntireSheet );
+
+ bool bDataChanged = bEntireSheet != pDoc->IsPrintEntireSheet( nCurTab );
+ if( !bEntireSheet )
+ {
+ // if new list box selection is not "Entire sheet", get the edit field contents
+ bDataChanged |= Impl_GetItem( m_xEdPrintArea.get(), aPrintArea );
+ }
+
+ // Repeat row changed?
+
+ bDataChanged |= Impl_GetItem( m_xEdRepeatRow.get(), aRepeatRow );
+
+ // Repeat column changed?
+
+ bDataChanged |= Impl_GetItem( m_xEdRepeatCol.get(), aRepeatCol );
+
+ if ( bDataChanged )
+ {
+ SetDispatcherLock( false );
+ SwitchToDocument();
+ GetBindings().GetDispatcher()->ExecuteList(SID_CHANGE_PRINTAREA,
+ SfxCallMode::SLOT | SfxCallMode::RECORD,
+ { &aPrintArea, &aRepeatRow, &aRepeatCol, &aEntireSheet });
+ }
+
+ response(RET_OK);
+ }
+ }
+ else if (m_xBtnCancel.get() == &rBtn)
+ response(RET_CANCEL);
+}
+
+IMPL_LINK(ScPrintAreasDlg, Impl_GetEditFocusHdl, formula::RefEdit&, rCtrl, void)
+{
+ m_pRefInputEdit = &rCtrl;
+}
+
+IMPL_LINK(ScPrintAreasDlg, Impl_GetFocusHdl, weld::Widget&, rCtrl, void)
+{
+ if (&rCtrl == m_xLbPrintArea.get())
+ m_pRefInputEdit = m_xEdPrintArea.get();
+ else if (&rCtrl == m_xLbRepeatRow.get())
+ m_pRefInputEdit = m_xEdRepeatRow.get();
+ else if (&rCtrl == m_xLbRepeatCol.get())
+ m_pRefInputEdit = m_xEdRepeatCol.get();
+}
+
+IMPL_LINK( ScPrintAreasDlg, Impl_SelectHdl, weld::ComboBox&, rLb, void )
+{
+ const sal_Int32 nSelPos = rLb.get_active();
+ formula::RefEdit* pEd = nullptr;
+
+ // list box positions of specific entries, default to "repeat row/column" list boxes
+ sal_Int32 nAllSheetPos = SC_AREASDLG_RR_NONE;
+ sal_Int32 nFirstCustomPos = SC_AREASDLG_RR_OFFSET;
+
+ // find edit field for list box, and list box positions
+ if (&rLb == m_xLbPrintArea.get())
+ {
+ pEd = m_xEdPrintArea.get();
+ nAllSheetPos = SC_AREASDLG_PR_ENTIRE;
+ nFirstCustomPos = SC_AREASDLG_PR_SELECT; // "Selection" and following
+ }
+ else if (&rLb == m_xLbRepeatCol.get())
+ pEd = m_xEdRepeatCol.get();
+ else if (&rLb == m_xLbRepeatRow.get())
+ pEd = m_xEdRepeatRow.get();
+ else
+ return;
+
+ // fill edit field according to list box selection
+ if( (nSelPos == 0) || (nSelPos == nAllSheetPos) )
+ pEd->SetText( OUString() );
+ else if( nSelPos >= nFirstCustomPos )
+ pEd->SetText(rLb.get_id(nSelPos));
+}
+
+IMPL_LINK( ScPrintAreasDlg, Impl_ModifyHdl, formula::RefEdit&, rEd, void )
+{
+ weld::ComboBox* pLb = nullptr;
+
+ // list box positions of specific entries, default to "repeat row/column" list boxes
+ sal_Int32 nUserDefPos = SC_AREASDLG_RR_USER;
+ sal_Int32 nFirstCustomPos = SC_AREASDLG_RR_OFFSET;
+
+ if( &rEd == m_xEdPrintArea.get() )
+ {
+ pLb = m_xLbPrintArea.get();
+ nUserDefPos = SC_AREASDLG_PR_USER;
+ nFirstCustomPos = SC_AREASDLG_PR_SELECT; // "Selection" and following
+ }
+ else if( &rEd == m_xEdRepeatCol.get() )
+ pLb = m_xLbRepeatCol.get();
+ else if( &rEd == m_xEdRepeatRow.get() )
+ pLb = m_xLbRepeatRow.get();
+ else
+ return;
+
+ // set list box selection according to edit field
+ const sal_Int32 nEntryCount = pLb->get_count();
+ OUString aStrEd( rEd.GetText() );
+ OUString aEdUpper = aStrEd.toAsciiUpperCase();
+
+ if ( (nEntryCount > nFirstCustomPos) && !aStrEd.isEmpty() )
+ {
+ bool bFound = false;
+ sal_Int32 i;
+
+ for ( i=nFirstCustomPos; i<nEntryCount && !bFound; i++ )
+ {
+ const OUString& rSymbol = pLb->get_id(i);
+ bFound = (rSymbol == aStrEd || rSymbol == aEdUpper);
+ }
+
+ pLb->set_active( bFound ? i-1 : nUserDefPos );
+ }
+ else
+ pLb->set_active( !aStrEd.isEmpty() ? nUserDefPos : 0 );
+}
+
+// global functions:
+
+// TODO: It might make sense to move these functions to address.?xx. -kohei
+
+static bool lcl_CheckOne_OOO( const ScDocument& rDoc, const OUString& rStr, bool bIsRow, SCCOLROW& rVal )
+{
+ // Allowed syntax for rStr:
+ // Row: [$]1-MAXTAB
+ // Col: [$]A-IV
+
+ OUString aStr = rStr;
+ sal_Int32 nLen = aStr.getLength();
+ SCCOLROW nNum = 0;
+ bool bStrOk = ( nLen > 0 ) && ( bIsRow ? ( nLen < 6 ) : ( nLen < 4 ) );
+
+ if ( bStrOk )
+ {
+ if ( '$' == aStr[0] )
+ aStr = aStr.copy( 1 );
+
+ if ( bIsRow )
+ {
+ bStrOk = CharClass::isAsciiNumeric(aStr);
+
+ if ( bStrOk )
+ {
+ sal_Int32 n = aStr.toInt32();
+
+ bStrOk = (n > 0) && ( n <= rDoc.GetSheetLimits().GetMaxRowCount() );
+ if ( bStrOk )
+ nNum = static_cast<SCCOLROW>(n - 1);
+ }
+ }
+ else
+ {
+ SCCOL nCol = 0;
+ bStrOk = ::AlphaToCol(rDoc, nCol, aStr);
+ nNum = nCol;
+ }
+ }
+
+ if ( bStrOk )
+ rVal = nNum;
+
+ return bStrOk;
+}
+
+static bool lcl_CheckOne_XL_A1( const ScDocument& rDoc, const OUString& rStr, bool bIsRow, SCCOLROW& rVal )
+{
+ // XL A1 style is identical to OOO one for print range formats.
+ return lcl_CheckOne_OOO(rDoc, rStr, bIsRow, rVal);
+}
+
+static bool lcl_CheckOne_XL_R1C1( const ScDocument& rDoc, const OUString& rStr, bool bIsRow, SCCOLROW& rVal )
+{
+ sal_Int32 nLen = rStr.getLength();
+ if (nLen <= 1)
+ // There must be at least two characters.
+ return false;
+
+ const sal_Unicode preUpper = bIsRow ? 'R' : 'C';
+ const sal_Unicode preLower = bIsRow ? 'r' : 'c';
+ if (rStr[0] != preUpper && rStr[0] != preLower)
+ return false;
+
+ OUString aNumStr = rStr.copy(1);
+ if (!CharClass::isAsciiNumeric(aNumStr))
+ return false;
+
+ sal_Int32 nNum = aNumStr.toInt32();
+
+ if (nNum <= 0)
+ return false;
+
+ if ((bIsRow && nNum > rDoc.GetSheetLimits().GetMaxRowCount()) ||
+ (!bIsRow && nNum > rDoc.GetSheetLimits().GetMaxColCount()))
+ return false;
+
+ rVal = static_cast<SCCOLROW>(nNum-1);
+ return true;
+}
+
+static bool lcl_CheckRepeatOne( const ScDocument& rDoc, const OUString& rStr, formula::FormulaGrammar::AddressConvention eConv, bool bIsRow, SCCOLROW& rVal )
+{
+ switch (eConv)
+ {
+ case formula::FormulaGrammar::CONV_OOO:
+ return lcl_CheckOne_OOO(rDoc, rStr, bIsRow, rVal);
+ case formula::FormulaGrammar::CONV_XL_A1:
+ return lcl_CheckOne_XL_A1(rDoc, rStr, bIsRow, rVal);
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ return lcl_CheckOne_XL_R1C1(rDoc, rStr, bIsRow, rVal);
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return false;
+}
+
+static bool lcl_CheckRepeatString( const OUString& rStr, const ScDocument& rDoc, bool bIsRow, ScRange* pRange )
+{
+ // Row: [valid row] rsep [valid row]
+ // Col: [valid col] rsep [valid col]
+
+ const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
+ const sal_Unicode rsep = ScCompiler::GetNativeSymbolChar(ocRange);
+
+ if (pRange)
+ {
+ // initialize the range value.
+ pRange->aStart.SetCol(0);
+ pRange->aStart.SetRow(0);
+ pRange->aEnd.SetCol(0);
+ pRange->aEnd.SetRow(0);
+ }
+
+ OUString aBuf;
+ SCCOLROW nVal = 0;
+ sal_Int32 nLen = rStr.getLength();
+ bool bEndPos = false;
+ for( sal_Int32 i = 0; i < nLen; ++i )
+ {
+ const sal_Unicode c = rStr[i];
+ if (c == rsep)
+ {
+ if (bEndPos)
+ // We aren't supposed to have more than one range separator.
+ return false;
+
+ // range separator
+ if (aBuf.isEmpty())
+ return false;
+
+ bool bRes = lcl_CheckRepeatOne(rDoc, aBuf, eConv, bIsRow, nVal);
+ if (!bRes)
+ return false;
+
+ if (pRange)
+ {
+ if (bIsRow)
+ {
+ pRange->aStart.SetRow(static_cast<SCROW>(nVal));
+ pRange->aEnd.SetRow(static_cast<SCROW>(nVal));
+ }
+ else
+ {
+ pRange->aStart.SetCol(static_cast<SCCOL>(nVal));
+ pRange->aEnd.SetCol(static_cast<SCCOL>(nVal));
+ }
+ }
+
+ aBuf.clear();
+ bEndPos = true;
+ }
+ else
+ aBuf += OUStringChar(c);
+ }
+
+ if (!aBuf.isEmpty())
+ {
+ bool bRes = lcl_CheckRepeatOne(rDoc, aBuf, eConv, bIsRow, nVal);
+ if (!bRes)
+ return false;
+
+ if (pRange)
+ {
+ if (bIsRow)
+ {
+ if (!bEndPos)
+ pRange->aStart.SetRow(static_cast<SCROW>(nVal));
+ pRange->aEnd.SetRow(static_cast<SCROW>(nVal));
+ }
+ else
+ {
+ if (!bEndPos)
+ pRange->aStart.SetCol(static_cast<SCCOL>(nVal));
+ pRange->aEnd.SetCol(static_cast<SCCOL>(nVal));
+ }
+ }
+ }
+
+ return true;
+}
+
+static void lcl_GetRepeatRangeString( std::optional<ScRange> oRange, const ScDocument& rDoc, bool bIsRow, OUString& rStr )
+{
+ rStr.clear();
+ if (!oRange)
+ return;
+
+ const formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
+ const ScAddress& rStart = oRange->aStart;
+ const ScAddress& rEnd = oRange->aEnd;
+
+ const ScRefFlags nFmt = bIsRow
+ ? (ScRefFlags::ROW_VALID | ScRefFlags::ROW_ABS)
+ : (ScRefFlags::COL_VALID | ScRefFlags::COL_ABS);
+ rStr += rStart.Format(nFmt, &rDoc, eConv);
+ if ((bIsRow && rStart.Row() != rEnd.Row()) || (!bIsRow && rStart.Col() != rEnd.Col()))
+ {
+ rStr += ScCompiler::GetNativeSymbol(ocRange);
+ rStr += rEnd.Format(nFmt, &rDoc, eConv);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/pagedlg/hfedtdlg.cxx b/sc/source/ui/pagedlg/hfedtdlg.cxx
new file mode 100644
index 000000000..b4e111b9c
--- /dev/null
+++ b/sc/source/ui/pagedlg/hfedtdlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <scitems.hxx>
+#include <svl/eitem.hxx>
+
+#include <hfedtdlg.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <scuitphfedit.hxx>
+#include <svx/svxids.hrc>
+#include <svx/pageitem.hxx>
+
+ScHFEditDlg::ScHFEditDlg(weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle,
+ const OUString& rUIXMLDescription,
+ const OString& rID)
+ : SfxTabDialogController(pParent, rUIXMLDescription, rID, &rCoreSet)
+{
+ eNumType = rCoreSet.Get(ATTR_PAGE).GetNumType();
+
+ OUString aTmp = m_xDialog->get_title() +
+ " (" + ScResId( STR_PAGESTYLE ) + ": " + rPageStyle + ")";
+
+ m_xDialog->set_title(aTmp);
+}
+
+ScHFEditHeaderDlg::ScHFEditHeaderDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/headerdialog.ui", "HeaderDialog")
+{
+ AddTabPage("headerfirst", ScFirstHeaderEditPage::Create, nullptr);
+ AddTabPage("headerright", ScRightHeaderEditPage::Create, nullptr);
+ AddTabPage("headerleft", ScLeftHeaderEditPage::Create, nullptr);
+}
+
+ScHFEditFooterDlg::ScHFEditFooterDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/footerdialog.ui", "FooterDialog" )
+{
+ AddTabPage("footerfirst", ScFirstFooterEditPage::Create, nullptr);
+ AddTabPage("footerright", ScRightFooterEditPage::Create, nullptr);
+ AddTabPage("footerleft", ScLeftFooterEditPage::Create, nullptr);
+}
+
+ScHFEditSharedFirstHeaderDlg::ScHFEditSharedFirstHeaderDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/sharedfirstheaderdialog.ui", "SharedFirstHeaderDialog" )
+{
+ AddTabPage("headerright", ScRightHeaderEditPage::Create, nullptr);
+ AddTabPage("headerleft", ScLeftHeaderEditPage::Create, nullptr);
+}
+
+ScHFEditSharedFirstFooterDlg::ScHFEditSharedFirstFooterDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/sharedfirstfooterdialog.ui", "SharedFirstFooterDialog" )
+{
+ AddTabPage("footerright", ScRightFooterEditPage::Create, nullptr);
+ AddTabPage("footerleft", ScLeftFooterEditPage::Create, nullptr);
+}
+
+ScHFEditSharedLeftHeaderDlg::ScHFEditSharedLeftHeaderDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/sharedleftheaderdialog.ui", "SharedLeftHeaderDialog" )
+{
+ AddTabPage("headerfirst", ScFirstHeaderEditPage::Create, nullptr);
+ AddTabPage("headerright", ScRightHeaderEditPage::Create, nullptr);
+}
+
+ScHFEditSharedLeftFooterDlg::ScHFEditSharedLeftFooterDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/sharedleftfooterdialog.ui", "SharedLeftFooterDialog" )
+{
+ AddTabPage("footerfirst", ScFirstFooterEditPage::Create, nullptr);
+ AddTabPage("footerright", ScRightFooterEditPage::Create, nullptr);
+}
+
+ScHFEditFirstHeaderDlg::ScHFEditFirstHeaderDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/firstheaderdialog.ui", "FirstHeaderDialog" )
+{
+ AddTabPage("headerfirst", ScFirstHeaderEditPage::Create, nullptr);
+}
+
+ScHFEditLeftHeaderDlg::ScHFEditLeftHeaderDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/leftheaderdialog.ui", "LeftHeaderDialog" )
+{
+ AddTabPage("headerleft", ScLeftHeaderEditPage::Create, nullptr);
+}
+
+ScHFEditRightHeaderDlg::ScHFEditRightHeaderDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/rightheaderdialog.ui", "RightHeaderDialog" )
+{
+ AddTabPage("headerright", ScRightHeaderEditPage::Create, nullptr);
+}
+
+ScHFEditFirstFooterDlg::ScHFEditFirstFooterDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/firstfooterdialog.ui", "FirstFooterDialog" )
+{
+ AddTabPage("footerfirst", ScFirstFooterEditPage::Create, nullptr);
+}
+
+ScHFEditLeftFooterDlg::ScHFEditLeftFooterDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/leftfooterdialog.ui", "LeftFooterDialog" )
+{
+ AddTabPage("footerleft", ScLeftFooterEditPage::Create, nullptr);
+}
+
+ScHFEditRightFooterDlg::ScHFEditRightFooterDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/rightfooterdialog.ui", "RightFooterDialog" )
+{
+ AddTabPage("footerright", ScRightFooterEditPage::Create, nullptr);
+}
+
+ScHFEditSharedHeaderDlg::ScHFEditSharedHeaderDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/sharedheaderdialog.ui", "SharedHeaderDialog" )
+{
+ AddTabPage("headerfirst", ScFirstHeaderEditPage::Create, nullptr);
+ AddTabPage("header", ScRightHeaderEditPage::Create, nullptr);
+ AddTabPage("footerfirst", ScFirstFooterEditPage::Create, nullptr);
+ AddTabPage("footerright", ScRightFooterEditPage::Create, nullptr);
+ AddTabPage("footerleft", ScLeftFooterEditPage::Create, nullptr);
+}
+
+ScHFEditSharedFooterDlg::ScHFEditSharedFooterDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/sharedfooterdialog.ui", "SharedFooterDialog" )
+{
+ AddTabPage("headerfirst", ScFirstFooterEditPage::Create, nullptr);
+ AddTabPage("headerright", ScRightHeaderEditPage::Create, nullptr);
+ AddTabPage("headerleft", ScLeftHeaderEditPage::Create, nullptr);
+ AddTabPage("footerfirst", ScFirstFooterEditPage::Create, nullptr);
+ AddTabPage("footer", ScRightFooterEditPage::Create, nullptr);
+}
+
+ScHFEditAllDlg::ScHFEditAllDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/allheaderfooterdialog.ui", "AllHeaderFooterDialog" )
+{
+ AddTabPage("headerfirst", ScFirstHeaderEditPage::Create, nullptr);
+ AddTabPage("headerright", ScRightHeaderEditPage::Create, nullptr);
+ AddTabPage("headerleft", ScLeftHeaderEditPage::Create, nullptr);
+ AddTabPage("footerfirst", ScFirstFooterEditPage::Create, nullptr);
+ AddTabPage("footerright", ScRightFooterEditPage::Create, nullptr);
+ AddTabPage("footerleft", ScLeftFooterEditPage::Create, nullptr);
+}
+
+ScHFEditActiveDlg::ScHFEditActiveDlg(
+ weld::Window* pParent,
+ const SfxItemSet& rCoreSet,
+ std::u16string_view rPageStyle)
+ : ScHFEditDlg( pParent, rCoreSet, rPageStyle,
+ "modules/scalc/ui/headerfooterdialog.ui", "HeaderFooterDialog" )
+{
+ const SvxPageItem& rPageItem =
+ rCoreSet.Get(
+ rCoreSet.GetPool()->GetWhich(SID_ATTR_PAGE) );
+
+ bool bRightPage = SvxPageUsage::Left != rPageItem.GetPageUsage();
+
+ if ( bRightPage )
+ {
+ AddTabPage("header", ScRightHeaderEditPage::Create, nullptr);
+ AddTabPage("footer", ScRightFooterEditPage::Create, nullptr);
+ }
+ else
+ {
+ // #69193a# respect "shared" setting
+
+ bool bShareHeader = rCoreSet.Get(ATTR_PAGE_HEADERSET).GetItemSet().
+ Get(ATTR_PAGE_SHARED).GetValue();
+ if ( bShareHeader )
+ AddTabPage("header", ScRightHeaderEditPage::Create, nullptr);
+ else
+ AddTabPage("header", ScLeftHeaderEditPage::Create, nullptr);
+
+ bool bShareFooter = rCoreSet.Get(ATTR_PAGE_FOOTERSET).GetItemSet().
+ Get(ATTR_PAGE_SHARED).GetValue();
+ if ( bShareFooter )
+ AddTabPage("footer", ScRightFooterEditPage::Create, nullptr);
+ else
+ AddTabPage("footer", ScLeftFooterEditPage::Create, nullptr);
+ }
+}
+
+void ScHFEditDlg::PageCreated(const OString& /* rId */, SfxTabPage& rPage)
+{
+ // Can only be a ScHFEditPage...
+
+ static_cast<ScHFEditPage&>(rPage).SetNumType(eNumType);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/pagedlg/scuitphfedit.cxx b/sc/source/ui/pagedlg/scuitphfedit.cxx
new file mode 100644
index 000000000..a4c7a1387
--- /dev/null
+++ b/sc/source/ui/pagedlg/scuitphfedit.cxx
@@ -0,0 +1,855 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <editeng/editobj.hxx>
+#include <editeng/flditem.hxx>
+#include <osl/time.h>
+#include <sfx2/tabdlg.hxx>
+#include <vcl/settings.hxx>
+
+#include <unotools/useroptions.hxx>
+
+#include <editutil.hxx>
+#include <attrib.hxx>
+#include <patattr.hxx>
+
+#include <scuitphfedit.hxx>
+#include <memory>
+
+
+ScHFEditPage::ScHFEditPage(weld::Container* pPage, weld::DialogController* pController,
+ const SfxItemSet& rCoreAttrs,
+ TypedWhichId<ScPageHFItem> nWhichId,
+ bool bHeader)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/headerfootercontent.ui", "HeaderFooterContent", &rCoreAttrs)
+ , nWhich( nWhichId )
+ , m_bDropDownActive(false)
+ , m_nTimeToggled(-1)
+ , m_xFtDefinedHF(m_xBuilder->weld_label(!bHeader ? "labelFT_F_DEFINED" : "labelFT_H_DEFINED"))
+ , m_xLbDefined(m_xBuilder->weld_combo_box("comboLB_DEFINED"))
+ , m_xFtCustomHF(m_xBuilder->weld_label(!bHeader ? "labelFT_F_CUSTOM" : "labelFT_H_CUSTOM"))
+ , m_xBtnText(m_xBuilder->weld_button("buttonBTN_TEXT"))
+ , m_xBtnFile(m_xBuilder->weld_menu_button("buttonBTN_FILE"))
+ , m_xBtnTable(m_xBuilder->weld_button("buttonBTN_TABLE"))
+ , m_xBtnPage(m_xBuilder->weld_button("buttonBTN_PAGE"))
+ , m_xBtnLastPage(m_xBuilder->weld_button("buttonBTN_PAGES"))
+ , m_xBtnDate(m_xBuilder->weld_button("buttonBTN_DATE"))
+ , m_xBtnTime(m_xBuilder->weld_button("buttonBTN_TIME"))
+ , m_xFtConfidential(m_xBuilder->weld_label("labelSTR_HF_CONFIDENTIAL"))
+ , m_xFtPage(m_xBuilder->weld_label("labelSTR_PAGE"))
+ , m_xFtOfQuestion(m_xBuilder->weld_label("labelSTR_HF_OF_QUESTION"))
+ , m_xFtOf(m_xBuilder->weld_label("labelSTR_HF_OF"))
+ , m_xFtNone(m_xBuilder->weld_label("labelSTR_HF_NONE_IN_BRACKETS"))
+ , m_xFtCreatedBy(m_xBuilder->weld_label("labelSTR_HF_CREATED_BY"))
+ , m_xFtCustomized(m_xBuilder->weld_label("labelSTR_HF_CUSTOMIZED"))
+ , m_xLeft(m_xBuilder->weld_widget("labelFT_LEFT"))
+ , m_xRight(m_xBuilder->weld_widget("labelFT_RIGHT"))
+ , m_xWndLeft(new ScEditWindow(Left, pController->getDialog()))
+ , m_xWndCenter(new ScEditWindow(Center, pController->getDialog()))
+ , m_xWndRight(new ScEditWindow(Right, pController->getDialog()))
+ , m_xWndLeftWnd(new weld::CustomWeld(*m_xBuilder, "textviewWND_LEFT", *m_xWndLeft))
+ , m_xWndCenterWnd(new weld::CustomWeld(*m_xBuilder, "textviewWND_CENTER", *m_xWndCenter))
+ , m_xWndRightWnd(new weld::CustomWeld(*m_xBuilder, "textviewWND_RIGHT", *m_xWndRight))
+ , m_pEditFocus(nullptr)
+{
+ // tdf#114695 override natural size with a small value
+ // we expect this to get stretched to some larger but
+ // limited size based on surrounding widgets
+ m_xLbDefined->set_size_request(m_xLbDefined->get_approximate_digit_width() * 20, -1);
+
+ //! use default style from current document?
+ //! if font color is used, header/footer background color must be set
+
+ ScPatternAttr aPatAttr( rCoreAttrs.GetPool() );
+
+ m_xLbDefined->connect_popup_toggled( LINK( this, ScHFEditPage, ListToggleHdl_Impl) );
+ m_xLbDefined->connect_changed( LINK( this, ScHFEditPage, ListHdl_Impl ) );
+ m_xBtnFile->connect_selected( LINK( this, ScHFEditPage, MenuHdl ) );
+ m_xBtnText->connect_clicked( LINK( this, ScHFEditPage, ClickHdl ) );
+ m_xBtnPage->connect_clicked( LINK( this, ScHFEditPage, ClickHdl ) );
+ m_xBtnLastPage->connect_clicked( LINK( this, ScHFEditPage, ClickHdl ) );
+ m_xBtnDate->connect_clicked( LINK( this, ScHFEditPage, ClickHdl ) );
+ m_xBtnTime->connect_clicked( LINK( this, ScHFEditPage, ClickHdl ) );
+ m_xBtnTable->connect_clicked( LINK( this, ScHFEditPage, ClickHdl ) );
+
+ m_xFtDefinedHF->show();
+ m_xFtCustomHF->show();
+
+ //swap left/right areas and their labels in RTL mode
+ if( AllSettings::GetLayoutRTL() )
+ {
+ sal_Int32 nOldLeftAttach = m_xLeft->get_grid_left_attach();
+ sal_Int32 nOldRightAttach = m_xRight->get_grid_left_attach();
+ m_xLeft->set_grid_left_attach(nOldRightAttach);
+ m_xRight->set_grid_left_attach(nOldLeftAttach);
+
+ nOldLeftAttach = m_xWndLeftWnd->get_grid_left_attach();
+ nOldRightAttach = m_xWndRightWnd->get_grid_left_attach();
+ m_xWndLeftWnd->set_grid_left_attach(nOldRightAttach);
+ m_xWndRightWnd->set_grid_left_attach(nOldLeftAttach);
+ }
+ m_xWndLeft->SetFont( aPatAttr );
+ m_xWndCenter->SetFont( aPatAttr );
+ m_xWndRight->SetFont( aPatAttr );
+
+ m_xWndLeft->SetObjectSelectHdl( LINK(this,ScHFEditPage,ObjectSelectHdl) );
+ m_xWndCenter->SetObjectSelectHdl( LINK(this,ScHFEditPage,ObjectSelectHdl) );
+ m_xWndRight->SetObjectSelectHdl( LINK(this,ScHFEditPage,ObjectSelectHdl) );
+ auto setEditFocus = [this](ScEditWindow & rEdit) { this->m_pEditFocus = &rEdit; };
+ m_xWndLeft->SetGetFocusHdl(setEditFocus);
+ m_xWndCenter->SetGetFocusHdl(setEditFocus);
+ m_xWndRight->SetGetFocusHdl(setEditFocus);
+
+ m_xWndLeft->GrabFocus();
+ m_pEditFocus = m_xWndLeft.get(); // there's no event from grab_focus()
+
+ InitPreDefinedList();
+
+}
+
+IMPL_LINK_NOARG( ScHFEditPage, ObjectSelectHdl, ScEditWindow&, void )
+{
+ m_xBtnText->grab_focus();
+}
+
+ScHFEditPage::~ScHFEditPage()
+{
+}
+
+void ScHFEditPage::SetNumType(SvxNumType eNumType)
+{
+ m_xWndLeft->SetNumType(eNumType);
+ m_xWndCenter->SetNumType(eNumType);
+ m_xWndRight->SetNumType(eNumType);
+}
+
+void ScHFEditPage::Reset( const SfxItemSet* rCoreSet )
+{
+ const ScPageHFItem* pItem = rCoreSet->GetItemIfSet(nWhich);
+ if ( !pItem )
+ return;
+
+ if( const EditTextObject* pLeft = pItem->GetLeftArea() )
+ m_xWndLeft->SetText( *pLeft );
+ if( const EditTextObject* pCenter = pItem->GetCenterArea() )
+ m_xWndCenter->SetText( *pCenter );
+ if( const EditTextObject* pRight = pItem->GetRightArea() )
+ m_xWndRight->SetText( *pRight );
+
+ SetSelectDefinedList();
+}
+
+bool ScHFEditPage::FillItemSet( SfxItemSet* rCoreSet )
+{
+ ScPageHFItem aItem( nWhich );
+ std::unique_ptr<EditTextObject> pLeft = m_xWndLeft->CreateTextObject();
+ std::unique_ptr<EditTextObject> pCenter = m_xWndCenter->CreateTextObject();
+ std::unique_ptr<EditTextObject> pRight = m_xWndRight->CreateTextObject();
+
+ aItem.SetLeftArea ( *pLeft );
+ aItem.SetCenterArea( *pCenter );
+ aItem.SetRightArea ( *pRight );
+
+ rCoreSet->Put( aItem );
+
+ return true;
+}
+
+void ScHFEditPage::InitPreDefinedList()
+{
+ SvtUserOptions aUserOpt;
+
+ std::optional<Color> pTxtColour;
+ std::optional<Color> pFldColour;
+
+ // Get the all field values at the outset.
+ OUString aPageFieldValue(m_xWndLeft->GetEditEngine()->CalcFieldValue(SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD), 0,0, pTxtColour, pFldColour));
+ OUString aSheetFieldValue(m_xWndLeft->GetEditEngine()->CalcFieldValue(SvxFieldItem(SvxTableField(), EE_FEATURE_FIELD), 0,0, pTxtColour, pFldColour));
+ OUString aFileFieldValue(m_xWndLeft->GetEditEngine()->CalcFieldValue(SvxFieldItem(SvxFileField(), EE_FEATURE_FIELD), 0,0, pTxtColour, pFldColour));
+ OUString aExtFileFieldValue(m_xWndLeft->GetEditEngine()->CalcFieldValue(SvxFieldItem(SvxExtFileField(), EE_FEATURE_FIELD), 0,0, pTxtColour, pFldColour));
+ OUString aDateFieldValue(m_xWndLeft->GetEditEngine()->CalcFieldValue(SvxFieldItem(SvxDateField(), EE_FEATURE_FIELD), 0,0, pTxtColour, pFldColour));
+
+ m_xLbDefined->clear();
+
+ m_xLbDefined->append_text(m_xFtNone->get_label());
+
+ OUString aPageEntry(m_xFtPage->get_label() + " " + aPageFieldValue);
+ m_xLbDefined->append_text(aPageEntry);
+
+ OUString aPageOfEntry(aPageEntry + " " + m_xFtOfQuestion->get_label());
+ m_xLbDefined->append_text( aPageOfEntry);
+
+ m_xLbDefined->append_text(aSheetFieldValue);
+
+ OUString aConfidentialEntry(aUserOpt.GetCompany() + " " + m_xFtConfidential->get_label() + ", " + aDateFieldValue + ", " + aPageEntry);
+ m_xLbDefined->append_text( aConfidentialEntry);
+
+ OUString aFileNamePageEntry(aFileFieldValue + ", " + aPageEntry);
+ m_xLbDefined->append_text( aFileNamePageEntry);
+
+ m_xLbDefined->append_text( aExtFileFieldValue);
+
+ OUString aPageSheetNameEntry(aPageEntry + ", " + aSheetFieldValue);
+ m_xLbDefined->append_text( aPageSheetNameEntry);
+
+ OUString aPageFileNameEntry(aPageEntry + ", " + aFileFieldValue);
+ m_xLbDefined->append_text( aPageFileNameEntry);
+
+ OUString aPagePathNameEntry(aPageEntry + ", " + aExtFileFieldValue);
+ m_xLbDefined->append_text( aPagePathNameEntry);
+
+ OUString aUserNameEntry(aUserOpt.GetFirstName() + " " + aUserOpt.GetLastName() + ", " + aPageEntry + ", " + aDateFieldValue);
+ m_xLbDefined->append_text( aUserNameEntry);
+
+ OUString aCreatedByEntry = m_xFtCreatedBy->get_label() + " " + aUserOpt.GetFirstName() + " " + aUserOpt.GetLastName() + ", " +
+ aDateFieldValue + ", " + aPageEntry;
+ m_xLbDefined->append_text( aCreatedByEntry);
+}
+
+void ScHFEditPage::InsertToDefinedList()
+{
+ const sal_Int32 nCount = m_xLbDefined->get_count();
+ if(nCount == eEntryCount)
+ {
+ m_xLbDefined->append_text( m_xFtCustomized->get_label() );
+ m_xLbDefined->set_active(eEntryCount);
+ }
+}
+
+void ScHFEditPage::RemoveFromDefinedList()
+{
+ const sal_Int32 nCount = m_xLbDefined->get_count();
+ if(nCount > eEntryCount )
+ m_xLbDefined->remove( nCount-1);
+}
+
+// determine if the header/footer exists in our predefined list and set select to it.
+void ScHFEditPage::SetSelectDefinedList()
+{
+ SvtUserOptions aUserOpt;
+
+ // default to customized
+ ScHFEntryId eSelectEntry = eEntryCount;
+
+ std::unique_ptr< EditTextObject > pLeftObj;
+ std::unique_ptr< EditTextObject > pCenterObj;
+ std::unique_ptr< EditTextObject > pRightObj;
+
+ OUString aLeftEntry;
+ OUString aCenterEntry;
+ OUString aRightEntry;
+
+ pLeftObj = m_xWndLeft->GetEditEngine()->CreateTextObject();
+ pCenterObj = m_xWndCenter->GetEditEngine()->CreateTextObject();
+ pRightObj = m_xWndRight->GetEditEngine()->CreateTextObject();
+
+ bool bFound = false;
+
+ const sal_Int32 nCount = m_xLbDefined->get_count();
+ for(sal_Int32 i = 0; i < nCount && !bFound; ++i)
+ {
+ switch(static_cast<ScHFEntryId>(i))
+ {
+ case eNoneEntry:
+ {
+ aLeftEntry = pLeftObj->GetText(0);
+ aCenterEntry = pCenterObj->GetText(0);
+ aRightEntry = pRightObj->GetText(0);
+ if(aLeftEntry.isEmpty() && aCenterEntry.isEmpty()
+ && aRightEntry.isEmpty())
+ {
+ eSelectEntry = eNoneEntry;
+ bFound = true;
+ }
+ }
+ break;
+
+ case ePageEntry:
+ {
+ aLeftEntry = pLeftObj->GetText(0);
+ aRightEntry = pRightObj->GetText(0);
+ if(aLeftEntry.isEmpty() && aRightEntry.isEmpty())
+ {
+ if(IsPageEntry(m_xWndCenter->GetEditEngine(), pCenterObj.get()))
+ {
+ eSelectEntry = ePageEntry;
+ bFound = true;
+ }
+ }
+ }
+ break;
+
+ //TODO
+ case ePagesEntry:
+ {
+ }
+ break;
+
+ case eSheetEntry:
+ {
+ aLeftEntry = pLeftObj->GetText(0);
+ aRightEntry = pRightObj->GetText(0);
+ if(aLeftEntry.isEmpty() && aRightEntry.isEmpty())
+ {
+ if(pCenterObj->IsFieldObject())
+ {
+ const SvxFieldItem* pFieldItem = pCenterObj->GetField();
+ if(pFieldItem)
+ {
+ const SvxFieldData* pField = pFieldItem->GetField();
+ if(dynamic_cast<const SvxTableField*>( pField))
+ {
+ eSelectEntry = eSheetEntry;
+ bFound = true;
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case eConfidentialEntry:
+ {
+ if(IsDateEntry(pCenterObj.get()) && IsPageEntry(m_xWndRight->GetEditEngine(), pRightObj.get()))
+ {
+ OUString aConfidentialEntry(aUserOpt.GetCompany() + " " + m_xFtConfidential->get_label());
+ if(aConfidentialEntry == m_xWndLeft->GetEditEngine()->GetText(0))
+ {
+ eSelectEntry = eConfidentialEntry;
+ bFound = true;
+ }
+ }
+ }
+ break;
+
+ //TODO
+ case eFileNamePageEntry:
+ {
+ }
+ break;
+
+ case eExtFileNameEntry:
+ {
+ aLeftEntry = pLeftObj->GetText(0);
+ aRightEntry = pRightObj->GetText(0);
+ if(IsExtFileNameEntry(pCenterObj.get()) && aLeftEntry.isEmpty()
+ && aRightEntry.isEmpty())
+ {
+ eSelectEntry = eExtFileNameEntry;
+ bFound = true;
+ }
+ }
+ break;
+
+ //TODO
+ case ePageSheetEntry:
+ {
+ }
+ break;
+
+ //TODO
+ case ePageFileNameEntry:
+ {
+ }
+ break;
+
+ case ePageExtFileNameEntry:
+ {
+ aLeftEntry = pLeftObj->GetText(0);
+ if(IsPageEntry(m_xWndCenter->GetEditEngine(), pCenterObj.get()) &&
+ IsExtFileNameEntry(pRightObj.get()) && aLeftEntry.isEmpty())
+ {
+ eSelectEntry = ePageExtFileNameEntry;
+ bFound = true;
+ }
+ }
+ break;
+
+ case eUserNameEntry:
+ {
+ if(IsDateEntry(pRightObj.get()) && IsPageEntry(m_xWndCenter->GetEditEngine(), pCenterObj.get()))
+ {
+ OUString aUserNameEntry(aUserOpt.GetFirstName() + " " + aUserOpt.GetLastName());
+
+ if(aUserNameEntry == m_xWndLeft->GetEditEngine()->GetText(0))
+ {
+ eSelectEntry = eUserNameEntry;
+ bFound = true;
+ }
+ }
+ }
+ break;
+
+ case eCreatedByEntry:
+ {
+ if(IsDateEntry(pCenterObj.get()) && IsPageEntry(m_xWndRight->GetEditEngine(), pRightObj.get()))
+ {
+ OUString aCreatedByEntry(m_xFtCreatedBy->get_label() + " " + aUserOpt.GetFirstName() + " " + aUserOpt.GetLastName());
+
+ if(aCreatedByEntry == m_xWndLeft->GetEditEngine()->GetText(0))
+ {
+ eSelectEntry = eCreatedByEntry;
+ bFound = true;
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+
+ if(eSelectEntry == eEntryCount)
+ InsertToDefinedList();
+
+ m_xLbDefined->set_active( sal::static_int_cast<sal_uInt16>( eSelectEntry ) );
+}
+
+bool ScHFEditPage::IsPageEntry(EditEngine*pEngine, const EditTextObject* pTextObj)
+{
+ if(!pEngine || !pTextObj)
+ return false;
+
+ bool bReturn = false;
+
+ if(!pTextObj->IsFieldObject())
+ {
+ std::vector<sal_Int32> aPosList;
+ pEngine->GetPortions(0,aPosList);
+ if(aPosList.size() == 2)
+ {
+ OUString aPageEntry(m_xFtPage->get_label() + " ");
+ ESelection aSel(0,0,0,0);
+ aSel.nEndPos = aPageEntry.getLength();
+ if(aPageEntry == pEngine->GetText(aSel))
+ {
+ aSel.nStartPos = aSel.nEndPos;
+ aSel.nEndPos++;
+ std::unique_ptr< EditTextObject > pPageObj = pEngine->CreateTextObject(aSel);
+ if(pPageObj && pPageObj->IsFieldObject() )
+ {
+ const SvxFieldItem* pFieldItem = pPageObj->GetField();
+ if(pFieldItem)
+ {
+ const SvxFieldData* pField = pFieldItem->GetField();
+ if(dynamic_cast<const SvxPageField*>( pField))
+ bReturn = true;
+ }
+ }
+ }
+ }
+ }
+ return bReturn;
+}
+
+bool ScHFEditPage::IsDateEntry(const EditTextObject* pTextObj)
+{
+ if(!pTextObj)
+ return false;
+
+ bool bReturn = false;
+ if(pTextObj->IsFieldObject())
+ {
+ const SvxFieldItem* pFieldItem = pTextObj->GetField();
+ if(pFieldItem)
+ {
+ const SvxFieldData* pField = pFieldItem->GetField();
+ if(dynamic_cast<const SvxDateField*>( pField))
+ bReturn = true;
+ }
+ }
+ return bReturn;
+}
+
+bool ScHFEditPage::IsExtFileNameEntry(const EditTextObject* pTextObj)
+{
+ if(!pTextObj)
+ return false;
+ bool bReturn = false;
+ if(pTextObj->IsFieldObject())
+ {
+ const SvxFieldItem* pFieldItem = pTextObj->GetField();
+ if(pFieldItem)
+ {
+ const SvxFieldData* pField = pFieldItem->GetField();
+ if(dynamic_cast<const SvxExtFileField*>( pField))
+ bReturn = true;
+ }
+ }
+ return bReturn;
+}
+
+void ScHFEditPage::ProcessDefinedListSel(ScHFEntryId eSel, bool bTravelling)
+{
+ SvtUserOptions aUserOpt;
+ std::unique_ptr< EditTextObject > pTextObj;
+
+ switch(eSel)
+ {
+ case eNoneEntry:
+ ClearTextAreas();
+ if(!bTravelling)
+ m_xWndLeft->GrabFocus();
+ break;
+
+ case ePageEntry:
+ {
+ ClearTextAreas();
+ OUString aPageEntry( m_xFtPage->get_label() + " " );
+ m_xWndCenter->GetEditEngine()->SetTextCurrentDefaults(aPageEntry);
+ m_xWndCenter->InsertField( SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD) );
+ if(!bTravelling)
+ m_xWndCenter->GrabFocus();
+ }
+ break;
+
+ case ePagesEntry:
+ {
+ ClearTextAreas();
+ ESelection aSel(0,0,0,0);
+ OUString aPageEntry( m_xFtPage->get_label() + " ");
+ m_xWndCenter->GetEditEngine()->SetTextCurrentDefaults(aPageEntry);
+ aSel.nEndPos = aPageEntry.getLength();
+ m_xWndCenter->GetEditEngine()->QuickInsertField(SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD), ESelection(aSel.nEndPara, aSel.nEndPos, aSel.nEndPara, aSel.nEndPos));
+ ++aSel.nEndPos;
+
+ OUString aPageOfEntry(" " + m_xFtOf->get_label() + " ");
+ m_xWndCenter->GetEditEngine()->QuickInsertText(aPageOfEntry,ESelection(aSel.nEndPara,aSel.nEndPos, aSel.nEndPara, aSel.nEndPos));
+ aSel.nEndPos = aSel.nEndPos + aPageOfEntry.getLength();
+ m_xWndCenter->GetEditEngine()->QuickInsertField(SvxFieldItem(SvxPagesField(), EE_FEATURE_FIELD), ESelection(aSel.nEndPara,aSel.nEndPos, aSel.nEndPara, aSel.nEndPos));
+ pTextObj = m_xWndCenter->GetEditEngine()->CreateTextObject();
+ m_xWndCenter->SetText(*pTextObj);
+ if(!bTravelling)
+ m_xWndCenter->GrabFocus();
+ }
+ break;
+
+ case eSheetEntry:
+ ClearTextAreas();
+ m_xWndCenter->InsertField( SvxFieldItem(SvxTableField(), EE_FEATURE_FIELD) );
+ if(!bTravelling)
+ m_xWndCenter->GrabFocus();
+ break;
+
+ case eConfidentialEntry:
+ {
+ ClearTextAreas();
+ OUString aConfidentialEntry(aUserOpt.GetCompany() + " " + m_xFtConfidential->get_label());
+ m_xWndLeft->GetEditEngine()->SetTextCurrentDefaults(aConfidentialEntry);
+ m_xWndCenter->InsertField( SvxFieldItem(SvxDateField(Date( Date::SYSTEM ),SvxDateType::Var), EE_FEATURE_FIELD) );
+
+ OUString aPageEntry( m_xFtPage->get_label() + " ");
+ m_xWndRight->GetEditEngine()->SetTextCurrentDefaults(aPageEntry);
+ m_xWndRight->InsertField( SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD) );
+ if(!bTravelling)
+ m_xWndRight->GrabFocus();
+ }
+ break;
+
+ case eFileNamePageEntry:
+ {
+ ClearTextAreas();
+ ESelection aSel(0,0,0,0);
+ m_xWndCenter->GetEditEngine()->QuickInsertField(SvxFieldItem( SvxFileField(), EE_FEATURE_FIELD ), aSel );
+ ++aSel.nEndPos;
+ OUString aPageEntry(", " + m_xFtPage->get_label() + " ");
+ m_xWndCenter->GetEditEngine()->QuickInsertText(aPageEntry, ESelection(aSel.nEndPara,aSel.nEndPos, aSel.nEndPara, aSel.nEndPos));
+ aSel.nStartPos = aSel.nEndPos;
+ aSel.nEndPos = aSel.nEndPos + aPageEntry.getLength();
+ m_xWndCenter->GetEditEngine()->QuickInsertField(SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD), ESelection(aSel.nEndPara,aSel.nEndPos, aSel.nEndPara, aSel.nEndPos));
+ pTextObj = m_xWndCenter->GetEditEngine()->CreateTextObject();
+ m_xWndCenter->SetText(*pTextObj);
+ if(!bTravelling)
+ m_xWndCenter->GrabFocus();
+ }
+ break;
+
+ case eExtFileNameEntry:
+ ClearTextAreas();
+ m_xWndCenter->InsertField( SvxFieldItem( SvxExtFileField(
+ OUString(), SvxFileType::Var, SvxFileFormat::PathFull ), EE_FEATURE_FIELD ) );
+ if(!bTravelling)
+ m_xWndCenter->GrabFocus();
+ break;
+
+ case ePageSheetEntry:
+ {
+ ClearTextAreas();
+ ESelection aSel(0,0,0,0);
+ OUString aPageEntry( m_xFtPage->get_label() + " " );
+ m_xWndCenter->GetEditEngine()->SetTextCurrentDefaults(aPageEntry);
+ aSel.nEndPos = aPageEntry.getLength();
+ m_xWndCenter->GetEditEngine()->QuickInsertField(SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD), ESelection(aSel.nEndPara, aSel.nEndPos, aSel.nEndPara, aSel.nEndPos));
+ ++aSel.nEndPos;
+
+ OUString aCommaSpace(", ");
+ m_xWndCenter->GetEditEngine()->QuickInsertText(aCommaSpace,ESelection(aSel.nEndPara, aSel.nEndPos, aSel.nEndPara, aSel.nEndPos));
+ aSel.nEndPos = aSel.nEndPos + aCommaSpace.getLength();
+ m_xWndCenter->GetEditEngine()->QuickInsertField( SvxFieldItem(SvxTableField(), EE_FEATURE_FIELD), ESelection(aSel.nEndPara, aSel.nEndPos, aSel.nEndPara, aSel.nEndPos));
+ pTextObj = m_xWndCenter->GetEditEngine()->CreateTextObject();
+ m_xWndCenter->SetText(*pTextObj);
+ if(!bTravelling)
+ m_xWndCenter->GrabFocus();
+ }
+ break;
+
+ case ePageFileNameEntry:
+ {
+ ClearTextAreas();
+ ESelection aSel(0,0,0,0);
+ OUString aPageEntry( m_xFtPage->get_label() + " " );
+ m_xWndCenter->GetEditEngine()->SetTextCurrentDefaults(aPageEntry);
+ aSel.nEndPos = aPageEntry.getLength();
+ m_xWndCenter->GetEditEngine()->QuickInsertField(SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD), ESelection(aSel.nEndPara, aSel.nEndPos, aSel.nEndPara, aSel.nEndPos));
+ ++aSel.nEndPos;
+ OUString aCommaSpace(", ");
+ m_xWndCenter->GetEditEngine()->QuickInsertText(aCommaSpace,ESelection(aSel.nEndPara, aSel.nEndPos, aSel.nEndPara, aSel.nEndPos));
+ aSel.nEndPos = aSel.nEndPos + aCommaSpace.getLength();
+ m_xWndCenter->GetEditEngine()->QuickInsertField( SvxFieldItem(SvxFileField(), EE_FEATURE_FIELD), ESelection(aSel.nEndPara, aSel.nEndPos, aSel.nEndPara, aSel.nEndPos));
+ pTextObj = m_xWndCenter->GetEditEngine()->CreateTextObject();
+ m_xWndCenter->SetText(*pTextObj);
+ if(!bTravelling)
+ m_xWndCenter->GrabFocus();
+ }
+ break;
+
+ case ePageExtFileNameEntry:
+ {
+ ClearTextAreas();
+ OUString aPageEntry( m_xFtPage->get_label() + " " );
+ m_xWndCenter->GetEditEngine()->SetTextCurrentDefaults(aPageEntry);
+ m_xWndCenter->InsertField( SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD) );
+ m_xWndRight->InsertField( SvxFieldItem( SvxExtFileField(
+ OUString(), SvxFileType::Var, SvxFileFormat::PathFull ), EE_FEATURE_FIELD ) );
+ if(!bTravelling)
+ m_xWndRight->GrabFocus();
+ }
+ break;
+
+ case eUserNameEntry:
+ {
+ ClearTextAreas();
+ OUString aUserNameEntry(aUserOpt.GetFirstName() + " " + aUserOpt.GetLastName());
+ m_xWndLeft->GetEditEngine()->SetTextCurrentDefaults(aUserNameEntry);
+ OUString aPageEntry( m_xFtPage->get_label() + " ");
+ //aPageEntry += " ";
+ m_xWndCenter->GetEditEngine()->SetTextCurrentDefaults(aPageEntry);
+ m_xWndCenter->InsertField( SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD) );
+ m_xWndRight->InsertField( SvxFieldItem(SvxDateField(Date( Date::SYSTEM ),SvxDateType::Var), EE_FEATURE_FIELD) );
+ if(!bTravelling)
+ m_xWndRight->GrabFocus();
+ }
+ break;
+
+ case eCreatedByEntry:
+ {
+ ClearTextAreas();
+ OUString aCreatedByEntry( m_xFtCreatedBy->get_label() + " " + aUserOpt.GetFirstName() + " " + aUserOpt.GetLastName());
+ m_xWndLeft->GetEditEngine()->SetTextCurrentDefaults(aCreatedByEntry);
+ m_xWndCenter->InsertField( SvxFieldItem(SvxDateField(Date( Date::SYSTEM ),SvxDateType::Var), EE_FEATURE_FIELD) );
+ OUString aPageEntry( m_xFtPage->get_label() + " " );
+ m_xWndRight->GetEditEngine()->SetTextCurrentDefaults(aPageEntry);
+ m_xWndRight->InsertField( SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD) );
+ if(!bTravelling)
+ m_xWndRight->GrabFocus();
+ }
+ break;
+
+ default :
+ break;
+ }
+}
+
+void ScHFEditPage::ClearTextAreas()
+{
+ m_xWndLeft->GetEditEngine()->SetTextCurrentDefaults(OUString());
+ m_xWndLeft->Invalidate();
+ m_xWndCenter->GetEditEngine()->SetTextCurrentDefaults(OUString());
+ m_xWndCenter->Invalidate();
+ m_xWndRight->GetEditEngine()->SetTextCurrentDefaults(OUString());
+ m_xWndRight->Invalidate();
+}
+
+// Handler:
+IMPL_LINK_NOARG(ScHFEditPage, ListToggleHdl_Impl, weld::ComboBox&, void)
+{
+ m_bDropDownActive = !m_bDropDownActive;
+ TimeValue aNow;
+ osl_getSystemTime(&aNow);
+ m_nTimeToggled = sal_Int64(aNow.Seconds) * 1000000000 + aNow.Nanosec;
+}
+
+IMPL_LINK_NOARG(ScHFEditPage, ListHdl_Impl, weld::ComboBox&, void)
+{
+ ScHFEntryId eSel = static_cast<ScHFEntryId>(m_xLbDefined->get_active());
+
+ TimeValue aNow;
+ osl_getSystemTime(&aNow);
+ sal_Int64 nNow = sal_Int64(aNow.Seconds) * 1000000000 + aNow.Nanosec;
+
+ // order of dropdown vs select not guaranteed
+ bool bDiscrepancy = m_xLbDefined->get_popup_shown() != m_bDropDownActive;
+ if (bDiscrepancy)
+ ListToggleHdl_Impl(*m_xLbDefined);
+
+ bool bFocusToTarget = !m_xLbDefined->get_popup_shown() && m_nTimeToggled != -1 && (nNow - m_nTimeToggled < 800000000);
+ ProcessDefinedListSel(eSel, !bFocusToTarget);
+ // check if we need to remove the customized entry.
+ if (!m_bDropDownActive && eSel < eEntryCount)
+ RemoveFromDefinedList();
+
+ // keep balanced
+ if (bDiscrepancy)
+ ListToggleHdl_Impl(*m_xLbDefined);
+}
+
+IMPL_LINK( ScHFEditPage, ClickHdl, weld::Button&, rBtn, void )
+{
+ if (!m_pEditFocus)
+ return;
+
+ if (&rBtn == m_xBtnText.get())
+ {
+ m_pEditFocus->SetCharAttributes();
+ }
+ else
+ {
+ if ( &rBtn == m_xBtnPage.get() )
+ m_pEditFocus->InsertField(SvxFieldItem(SvxPageField(), EE_FEATURE_FIELD));
+ else if ( &rBtn == m_xBtnLastPage.get() )
+ m_pEditFocus->InsertField(SvxFieldItem(SvxPagesField(), EE_FEATURE_FIELD));
+ else if ( &rBtn == m_xBtnDate.get() )
+ m_pEditFocus->InsertField(SvxFieldItem(SvxDateField(Date(Date::SYSTEM),SvxDateType::Var), EE_FEATURE_FIELD));
+ else if ( &rBtn == m_xBtnTime.get() )
+ m_pEditFocus->InsertField(SvxFieldItem(SvxTimeField(), EE_FEATURE_FIELD));
+ else if ( &rBtn == m_xBtnTable.get() )
+ m_pEditFocus->InsertField(SvxFieldItem(SvxTableField(), EE_FEATURE_FIELD));
+ }
+ InsertToDefinedList();
+ m_pEditFocus->GrabFocus();
+}
+
+IMPL_LINK(ScHFEditPage, MenuHdl, const OString&, rSelectedId, void)
+{
+ if (!m_pEditFocus)
+ return;
+
+ if (rSelectedId == "title")
+ {
+ m_pEditFocus->InsertField(SvxFieldItem(SvxFileField(), EE_FEATURE_FIELD));
+ }
+ else if (rSelectedId == "filename")
+ {
+ m_pEditFocus->InsertField( SvxFieldItem( SvxExtFileField(
+ OUString(), SvxFileType::Var, SvxFileFormat::NameAndExt ), EE_FEATURE_FIELD ) );
+ }
+ else if (rSelectedId == "pathname")
+ {
+ m_pEditFocus->InsertField( SvxFieldItem( SvxExtFileField(
+ OUString(), SvxFileType::Var, SvxFileFormat::PathFull ), EE_FEATURE_FIELD ) );
+ }
+}
+
+
+ScFirstHeaderEditPage::ScFirstHeaderEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet )
+ : ScHFEditPage( pPage, pController,
+ rCoreSet,
+ SID_SCATTR_PAGE_HEADERFIRST,
+ true )
+ {}
+
+std::unique_ptr<SfxTabPage> ScFirstHeaderEditPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet )
+{
+ return std::make_unique<ScFirstHeaderEditPage>( pPage, pController, *rCoreSet );
+}
+
+
+ScRightHeaderEditPage::ScRightHeaderEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet )
+ : ScHFEditPage( pPage, pController,
+ rCoreSet,
+ SID_SCATTR_PAGE_HEADERRIGHT,
+ true )
+ {}
+
+std::unique_ptr<SfxTabPage> ScRightHeaderEditPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet )
+{
+ return std::make_unique<ScRightHeaderEditPage>( pPage, pController, *rCoreSet );
+}
+
+
+ScLeftHeaderEditPage::ScLeftHeaderEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet )
+ : ScHFEditPage( pPage, pController,
+ rCoreSet,
+ SID_SCATTR_PAGE_HEADERLEFT,
+ true )
+ {}
+
+std::unique_ptr<SfxTabPage> ScLeftHeaderEditPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet )
+{
+ return std::make_unique<ScLeftHeaderEditPage>( pPage, pController, *rCoreSet );
+}
+
+
+ScFirstFooterEditPage::ScFirstFooterEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet )
+ : ScHFEditPage( pPage, pController,
+ rCoreSet,
+ SID_SCATTR_PAGE_FOOTERFIRST,
+ false )
+ {}
+
+std::unique_ptr<SfxTabPage> ScFirstFooterEditPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet )
+{
+ return std::make_unique<ScFirstFooterEditPage>( pPage, pController, *rCoreSet );
+}
+
+
+ScRightFooterEditPage::ScRightFooterEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet )
+ : ScHFEditPage( pPage, pController,
+ rCoreSet,
+ SID_SCATTR_PAGE_FOOTERRIGHT,
+ false )
+ {}
+
+std::unique_ptr<SfxTabPage> ScRightFooterEditPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet )
+{
+ return std::make_unique<ScRightFooterEditPage>( pPage, pController, *rCoreSet );
+}
+
+
+ScLeftFooterEditPage::ScLeftFooterEditPage( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet )
+ : ScHFEditPage( pPage, pController,
+ rCoreSet,
+ SID_SCATTR_PAGE_FOOTERLEFT,
+ false )
+ {}
+
+std::unique_ptr<SfxTabPage> ScLeftFooterEditPage::Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet )
+{
+ return std::make_unique<ScLeftFooterEditPage>( pPage, pController, *rCoreSet );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/pagedlg/tphf.cxx b/sc/source/ui/pagedlg/tphf.cxx
new file mode 100644
index 000000000..cdf4802af
--- /dev/null
+++ b/sc/source/ui/pagedlg/tphf.cxx
@@ -0,0 +1,262 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <scitems.hxx>
+#include <sfx2/basedlgs.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <svl/style.hxx>
+#include <svx/pageitem.hxx>
+
+#include <attrib.hxx>
+#include <tphf.hxx>
+#include <scres.hrc>
+#include <scabstdlg.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <tabvwsh.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <styledlg.hxx>
+#include <scuitphfedit.hxx>
+#include <memory>
+#include <helpids.h>
+
+
+ScHFPage::ScHFPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet, sal_uInt16 nSetId)
+ : SvxHFPage(pPage, pController, rSet, nSetId)
+ , aDataSet(*rSet.GetPool(), svl::Items<ATTR_PAGE, ATTR_PAGE, ATTR_PAGE_HEADERLEFT, ATTR_PAGE_FOOTERFIRST>)
+ , nPageUsage(SvxPageUsage::All)
+ , pStyleDlg(nullptr)
+ , m_xBtnEdit(m_xBuilder->weld_button("buttonEdit"))
+{
+ SetExchangeSupport();
+
+ SfxViewShell* pSh = SfxViewShell::Current();
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( pSh );
+ m_xBtnEdit->show();
+
+ aDataSet.Put( rSet );
+
+ if ( pViewSh )
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+
+ aStrPageStyle = rDoc.GetPageStyle( rViewData.GetTabNo() );
+ }
+
+ m_xBtnEdit->connect_clicked(LINK(this, ScHFPage, BtnHdl));
+ m_xTurnOnBox->connect_toggled(LINK(this, ScHFPage, TurnOnHdl));
+
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ m_xBtnEdit->set_help_id(HID_SC_HEADER_EDIT);
+ else
+ m_xBtnEdit->set_help_id(HID_SC_FOOTER_EDIT);
+}
+
+ScHFPage::~ScHFPage()
+{
+ pStyleDlg = nullptr;
+}
+
+void ScHFPage::Reset( const SfxItemSet* rSet )
+{
+ SvxHFPage::Reset( rSet );
+ TurnOnHdl(*m_xTurnOnBox);
+}
+
+bool ScHFPage::FillItemSet( SfxItemSet* rOutSet )
+{
+ bool bResult = SvxHFPage::FillItemSet( rOutSet );
+
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ {
+ rOutSet->Put( aDataSet.Get( ATTR_PAGE_HEADERLEFT ) );
+ rOutSet->Put( aDataSet.Get( ATTR_PAGE_HEADERRIGHT ) );
+ rOutSet->Put( aDataSet.Get( ATTR_PAGE_HEADERFIRST ) );
+ }
+ else
+ {
+ rOutSet->Put( aDataSet.Get( ATTR_PAGE_FOOTERLEFT ) );
+ rOutSet->Put( aDataSet.Get( ATTR_PAGE_FOOTERRIGHT ) );
+ rOutSet->Put( aDataSet.Get( ATTR_PAGE_FOOTERFIRST ) );
+ }
+
+ return bResult;
+}
+
+void ScHFPage::ActivatePage( const SfxItemSet& rSet )
+{
+ sal_uInt16 nPageWhich = GetWhich( SID_ATTR_PAGE );
+ const SvxPageItem& rPageItem = static_cast<const SvxPageItem&>(
+ rSet.Get(nPageWhich));
+
+ nPageUsage = rPageItem.GetPageUsage();
+
+ if ( pStyleDlg )
+ aStrPageStyle = pStyleDlg->GetStyleSheet().GetName();
+
+ aDataSet.Put( rSet.Get(ATTR_PAGE) );
+
+ SvxHFPage::ActivatePage( rSet );
+}
+
+DeactivateRC ScHFPage::DeactivatePage( SfxItemSet* pSetP )
+{
+ if ( DeactivateRC::LeavePage == SvxHFPage::DeactivatePage( pSetP ) )
+ if ( pSetP )
+ FillItemSet( pSetP );
+
+ return DeactivateRC::LeavePage;
+}
+
+// Handler:
+
+IMPL_LINK_NOARG(ScHFPage, TurnOnHdl, weld::Toggleable&, void)
+{
+ SvxHFPage::TurnOnHdl(*m_xTurnOnBox);
+
+ if (m_xTurnOnBox->get_active())
+ m_xBtnEdit->set_sensitive(true);
+ else
+ m_xBtnEdit->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(ScHFPage, BtnHdl, weld::Button&, void)
+{
+ SfxViewShell* pViewSh = SfxViewShell::Current();
+
+ if ( !pViewSh )
+ {
+ OSL_FAIL( "Current ViewShell not found." );
+ return;
+ }
+
+ if ( (m_xCntSharedBox->get_sensitive() && !m_xCntSharedBox->get_active()) ||
+ (m_xCntSharedFirstBox->get_sensitive() && !m_xCntSharedFirstBox->get_active()) )
+ {
+ sal_uInt16 nResId;
+
+ if ( m_xCntSharedBox->get_sensitive() && !m_xCntSharedBox->get_active() &&
+ m_xCntSharedFirstBox->get_sensitive() && !m_xCntSharedFirstBox->get_active() )
+ {
+ nResId = ( nId == SID_ATTR_PAGE_HEADERSET )
+ ? RID_SCDLG_HFED_HEADER
+ : RID_SCDLG_HFED_FOOTER;
+ }
+ else if (m_xCntSharedBox->get_sensitive() && !m_xCntSharedBox->get_active())
+ {
+ nResId = ( nId == SID_ATTR_PAGE_HEADERSET )
+ ? RID_SCDLG_HFEDIT_SHAREDFIRSTHEADER
+ : RID_SCDLG_HFEDIT_SHAREDFIRSTFOOTER;
+ }
+ else
+ {
+ OSL_ENSURE( m_xCntSharedFirstBox->get_sensitive() && !m_xCntSharedFirstBox->get_active(), "This should be logically impossible." );
+ nResId = ( nId == SID_ATTR_PAGE_HEADERSET )
+ ? RID_SCDLG_HFEDIT_SHAREDLEFTHEADER
+ : RID_SCDLG_HFEDIT_SHAREDLEFTFOOTER;
+ }
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ VclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateScHFEditDlg(
+ GetFrameWeld(), aDataSet, aStrPageStyle, nResId));
+ pDlg->StartExecuteAsync([this, pDlg](sal_Int32 nResult){
+ if ( nResult == RET_OK )
+ {
+ aDataSet.Put( *pDlg->GetOutputItemSet() );
+ }
+
+ pDlg->disposeOnce();
+ });
+ }
+ else
+ {
+ OUString aText;
+ SfxSingleTabDialogController aDlg(GetFrameWeld(), &aDataSet);
+ bool bRightPage = m_xCntSharedBox->get_active() || (SvxPageUsage::Left != nPageUsage);
+
+ if ( nId == SID_ATTR_PAGE_HEADERSET )
+ {
+ aText = ScResId( STR_PAGEHEADER );
+ if ( bRightPage )
+ aDlg.SetTabPage(ScRightHeaderEditPage::Create(aDlg.get_content_area(), &aDlg, &aDataSet));
+ else
+ aDlg.SetTabPage(ScLeftHeaderEditPage::Create(aDlg.get_content_area(), &aDlg, &aDataSet));
+ }
+ else
+ {
+ aText = ScResId( STR_PAGEFOOTER );
+ if ( bRightPage )
+ aDlg.SetTabPage(ScRightFooterEditPage::Create(aDlg.get_content_area(), &aDlg, &aDataSet));
+ else
+ aDlg.SetTabPage(ScLeftFooterEditPage::Create(aDlg.get_content_area(), &aDlg, &aDataSet));
+ }
+
+ SvxNumType eNumType = aDataSet.Get(ATTR_PAGE).GetNumType();
+ static_cast<ScHFEditPage*>(aDlg.GetTabPage())->SetNumType(eNumType);
+
+ aText += " (" + ScResId( STR_PAGESTYLE ) +
+ ": " + aStrPageStyle + ")";
+
+ aDlg.set_title(aText);
+
+ if (aDlg.run() == RET_OK)
+ {
+ aDataSet.Put(*aDlg.GetOutputItemSet());
+ }
+ }
+}
+
+
+ScHeaderPage::ScHeaderPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
+ : ScHFPage(pPage, pController, rSet, SID_ATTR_PAGE_HEADERSET)
+{
+}
+
+std::unique_ptr<SfxTabPage> ScHeaderPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet)
+{
+ return std::make_unique<ScHeaderPage>(pPage, pController, *rCoreSet);
+}
+
+WhichRangesContainer ScHeaderPage::GetRanges()
+{
+ return SvxHeaderPage::GetRanges();
+}
+
+
+ScFooterPage::ScFooterPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet)
+ : ScHFPage( pPage, pController, rSet, SID_ATTR_PAGE_FOOTERSET )
+{
+}
+
+std::unique_ptr<SfxTabPage> ScFooterPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet)
+{
+ return std::make_unique<ScFooterPage>(pPage, pController, *rCoreSet);
+}
+
+WhichRangesContainer ScFooterPage::GetRanges()
+{
+ return SvxHeaderPage::GetRanges();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/pagedlg/tphfedit.cxx b/sc/source/ui/pagedlg/tphfedit.cxx
new file mode 100644
index 000000000..fa5209850
--- /dev/null
+++ b/sc/source/ui/pagedlg/tphfedit.cxx
@@ -0,0 +1,258 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <editeng/editobj.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/sfxdlg.hxx>
+
+#include <tphfedit.hxx>
+#include <editutil.hxx>
+#include <global.hxx>
+#include <patattr.hxx>
+#include <scresid.hxx>
+#include <globstr.hrc>
+#include <strings.hrc>
+#include <tabvwsh.hxx>
+#include <prevwsh.hxx>
+#include <AccessibleEditObject.hxx>
+
+#include <scabstdlg.hxx>
+#include <memory>
+
+
+static void lcl_GetFieldData( ScHeaderFieldData& rData )
+{
+ SfxViewShell* pShell = SfxViewShell::Current();
+ if (pShell)
+ {
+ if (auto pTabViewShell = dynamic_cast<ScTabViewShell*>( pShell))
+ pTabViewShell->FillFieldData(rData);
+ else if (auto pPreviewShell = dynamic_cast<ScPreviewShell*>( pShell))
+ pPreviewShell->FillFieldData(rData);
+ }
+}
+
+
+ScEditWindow::ScEditWindow(ScEditWindowLocation eLoc, weld::Window* pDialog)
+ : eLocation(eLoc)
+ , mbRTL(ScGlobal::IsSystemRTL())
+ , mpDialog(pDialog)
+{
+}
+
+void ScEditWindow::makeEditEngine()
+{
+ m_xEditEngine.reset(new ScHeaderEditEngine(EditEngine::CreatePool().get()));
+}
+
+ScHeaderEditEngine* ScEditWindow::GetEditEngine() const
+{
+ return static_cast<ScHeaderEditEngine*>(m_xEditEngine.get());
+}
+
+void ScEditWindow::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ OutputDevice& rDevice = pDrawingArea->get_ref_device();
+ Size aSize = rDevice.LogicToPixel(Size(80, 120), MapMode(MapUnit::MapAppFont));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+
+ WeldEditView::SetDrawingArea(pDrawingArea);
+
+ ScHeaderFieldData aData;
+ lcl_GetFieldData(aData);
+ // fields
+ GetEditEngine()->SetData(aData);
+ if (mbRTL)
+ m_xEditEngine->SetDefaultHorizontalTextDirection(EEHorizontalTextDirection::R2L);
+
+ Color aBgColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+ rDevice.SetBackground(aBgColor);
+ m_xEditView->SetBackgroundColor(aBgColor);
+
+ auto tmpAcc = mxAcc.get();
+ if (!tmpAcc)
+ return;
+
+ OUString sName;
+ switch (eLocation)
+ {
+ case Left:
+ sName = ScResId(STR_ACC_LEFTAREA_NAME);
+ break;
+ case Center:
+ sName = ScResId(STR_ACC_CENTERAREA_NAME);
+ break;
+ case Right:
+ sName = ScResId(STR_ACC_RIGHTAREA_NAME);
+ break;
+ }
+
+ tmpAcc->InitAcc(nullptr, m_xEditView.get(),
+ sName, pDrawingArea->get_tooltip_text());
+}
+
+ScEditWindow::~ScEditWindow()
+{
+ // delete Accessible object before deleting EditEngine and EditView
+ if (auto tmp = mxAcc.get())
+ tmp->dispose();
+}
+
+void ScEditWindow::SetNumType(SvxNumType eNumType)
+{
+ ScHeaderEditEngine* pEditEngine = GetEditEngine();
+ pEditEngine->SetNumType(eNumType);
+ pEditEngine->UpdateFields();
+}
+
+std::unique_ptr<EditTextObject> ScEditWindow::CreateTextObject()
+{
+ // reset paragraph attributes
+ // (GetAttribs at creation of format dialog always returns the set items)
+
+ const SfxItemSet& rEmpty = m_xEditEngine->GetEmptyItemSet();
+ sal_Int32 nParCnt = m_xEditEngine->GetParagraphCount();
+ for (sal_Int32 i=0; i<nParCnt; i++)
+ m_xEditEngine->SetParaAttribs( i, rEmpty );
+
+ return m_xEditEngine->CreateTextObject();
+}
+
+void ScEditWindow::SetFont( const ScPatternAttr& rPattern )
+{
+ auto pSet = std::make_unique<SfxItemSet>( m_xEditEngine->GetEmptyItemSet() );
+ rPattern.FillEditItemSet( pSet.get() );
+ // FillEditItemSet adjusts font height to 1/100th mm,
+ // but for header/footer twips is needed, as in the PatternAttr:
+ pSet->Put( rPattern.GetItem(ATTR_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT) );
+ pSet->Put( rPattern.GetItem(ATTR_CJK_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CJK) );
+ pSet->Put( rPattern.GetItem(ATTR_CTL_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CTL) );
+ // font color used, suitable header/footer background color set in ScEditWindow::SetDrawingArea
+ Color aFgColor = svtools::ColorConfig().GetColorValue(svtools::FONTCOLOR, false).nColor;
+ if (aFgColor == COL_AUTO) {
+ Color aBgColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+ aFgColor = aBgColor.IsDark() ? COL_WHITE : COL_BLACK;
+ }
+ pSet->Put(SvxColorItem(aFgColor, EE_CHAR_COLOR));
+ if (mbRTL)
+ pSet->Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
+ GetEditEngine()->SetDefaults( std::move(pSet) );
+}
+
+void ScEditWindow::SetText( const EditTextObject& rTextObject )
+{
+ GetEditEngine()->SetTextCurrentDefaults(rTextObject);
+}
+
+void ScEditWindow::InsertField( const SvxFieldItem& rFld )
+{
+ m_xEditView->InsertField( rFld );
+}
+
+void ScEditWindow::SetCharAttributes()
+{
+ SfxObjectShell* pDocSh = SfxObjectShell::Current();
+
+ SfxViewShell* pViewSh = SfxViewShell::Current();
+
+ ScTabViewShell* pTabViewSh = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+
+ OSL_ENSURE( pDocSh, "Current DocShell not found" );
+ OSL_ENSURE( pViewSh, "Current ViewShell not found" );
+
+ if ( !(pDocSh && pViewSh) )
+ return;
+
+ if(pTabViewSh!=nullptr) pTabViewSh->SetInFormatDialog(true);
+
+ SfxItemSet aSet( m_xEditView->GetAttribs() );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateScCharDlg(
+ mpDialog, &aSet, pDocSh, false));
+ pDlg->SetText( ScResId( STR_TEXTATTRS ) );
+ if ( pDlg->Execute() == RET_OK )
+ {
+ aSet.ClearItem();
+ aSet.Put( *pDlg->GetOutputItemSet() );
+ m_xEditView->SetAttribs( aSet );
+ }
+
+ if(pTabViewSh!=nullptr) pTabViewSh->SetInFormatDialog(false);
+}
+
+bool ScEditWindow::KeyInput( const KeyEvent& rKEvt )
+{
+ if ( !rKEvt.GetKeyCode().IsMod1() && !rKEvt.GetKeyCode().IsShift() &&
+ rKEvt.GetKeyCode().IsMod2() && rKEvt.GetKeyCode().GetCode() == KEY_DOWN )
+ {
+ aObjectSelectLink.Call(*this);
+ return true;
+ }
+ return WeldEditView::KeyInput(rKEvt);
+}
+
+void ScEditWindow::GetFocus()
+{
+ assert(m_GetFocusLink);
+ m_GetFocusLink(*this);
+
+ if (auto tmp = mxAcc.get())
+ tmp->GotFocus();
+
+ WeldEditView::GetFocus();
+}
+
+void ScEditWindow::LoseFocus()
+{
+ if (auto xTemp = mxAcc.get())
+ xTemp->LostFocus();
+ else
+ mxAcc = nullptr;
+ WeldEditView::LoseFocus();
+}
+
+bool ScEditWindow::MouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bHadFocus = HasFocus();
+ bool bRet = WeldEditView::MouseButtonDown(rMEvt);
+ if (!bHadFocus)
+ {
+ assert(HasFocus());
+ GetFocus();
+ }
+ return bRet;
+}
+
+css::uno::Reference< css::accessibility::XAccessible > ScEditWindow::CreateAccessible()
+{
+ rtl::Reference<ScAccessibleEditControlObject> tmp = new ScAccessibleEditControlObject(this, ScAccessibleEditObject::EditControl);
+ mxAcc = tmp.get();
+ return css::uno::Reference<css::accessibility::XAccessible>(static_cast<cppu::OWeakObject*>(tmp.get()), css::uno::UNO_QUERY_THROW);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/pagedlg/tptable.cxx b/sc/source/ui/pagedlg/tptable.cxx
new file mode 100644
index 000000000..d5c50b930
--- /dev/null
+++ b/sc/source/ui/pagedlg/tptable.cxx
@@ -0,0 +1,522 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <scitems.hxx>
+
+#include <osl/diagnose.h>
+
+#include <tptable.hxx>
+#include <global.hxx>
+#include <attrib.hxx>
+#include <bitmaps.hlst>
+
+// Static Data
+
+const WhichRangesContainer ScTablePage::pPageTableRanges(
+ svl::Items<ATTR_PAGE_NOTES, ATTR_PAGE_FIRSTPAGENO>);
+
+static bool lcl_PutVObjModeItem(TypedWhichId<ScViewObjectModeItem> nWhich,
+ SfxItemSet& rCoreSet,
+ const SfxItemSet& rOldSet,
+ const weld::Toggleable& rBtn);
+
+static bool lcl_PutScaleItem( TypedWhichId<SfxUInt16Item> nWhich,
+ SfxItemSet& rCoreSet,
+ const SfxItemSet& rOldSet,
+ const weld::ComboBox& rListBox,
+ sal_uInt16 nLBEntry,
+ const weld::MetricSpinButton& rEd,
+ sal_uInt16 nValue );
+
+static bool lcl_PutScaleItem2( TypedWhichId<ScPageScaleToItem> nWhich,
+ SfxItemSet& rCoreSet,
+ const SfxItemSet& rOldSet,
+ const weld::ComboBox& rListBox,
+ sal_uInt16 nLBEntry,
+ const weld::SpinButton& rEd1,
+ sal_uInt16 nOrigScalePageWidth,
+ const weld::SpinButton& rEd2,
+ sal_uInt16 nOrigScalePageHeight );
+
+static bool lcl_PutScaleItem3( TypedWhichId<SfxUInt16Item> nWhich,
+ SfxItemSet& rCoreSet,
+ const SfxItemSet& rOldSet,
+ const weld::ComboBox& rListBox,
+ sal_uInt16 nLBEntry,
+ const weld::SpinButton& rEd,
+ sal_uInt16 nValue );
+
+static bool lcl_PutBoolItem( TypedWhichId<SfxBoolItem> nWhich,
+ SfxItemSet& rCoreSet,
+ const SfxItemSet& rOldSet,
+ bool bIsChecked,
+ bool bSavedValue );
+
+namespace {
+
+bool WAS_DEFAULT(sal_uInt16 w, SfxItemSet const & s)
+{ return SfxItemState::DEFAULT==s.GetItemState(w); }
+
+}
+
+// List box entries "Scaling mode"
+#define SC_TPTABLE_SCALE_PERCENT 0
+#define SC_TPTABLE_SCALE_TO 1
+#define SC_TPTABLE_SCALE_TO_PAGES 2
+
+ScTablePage::ScTablePage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreAttrs)
+ : SfxTabPage(pPage, pController, "modules/scalc/ui/sheetprintpage.ui", "SheetPrintPage", &rCoreAttrs)
+ , m_nOrigScalePageWidth(0)
+ , m_nOrigScalePageHeight(0)
+ , m_xBtnTopDown(m_xBuilder->weld_radio_button("radioBTN_TOPDOWN"))
+ , m_xBtnLeftRight(m_xBuilder->weld_radio_button("radioBTN_LEFTRIGHT"))
+ , m_xBmpPageDir(m_xBuilder->weld_image("imageBMP_PAGEDIR"))
+ , m_xBtnPageNo(m_xBuilder->weld_check_button("checkBTN_PAGENO"))
+ , m_xEdPageNo(m_xBuilder->weld_spin_button("spinED_PAGENO"))
+ , m_xBtnHeaders(m_xBuilder->weld_check_button("checkBTN_HEADER"))
+ , m_xBtnGrid(m_xBuilder->weld_check_button("checkBTN_GRID"))
+ , m_xBtnNotes(m_xBuilder->weld_check_button("checkBTN_NOTES"))
+ , m_xBtnObjects(m_xBuilder->weld_check_button("checkBTN_OBJECTS"))
+ , m_xBtnCharts(m_xBuilder->weld_check_button("checkBTN_CHARTS"))
+ , m_xBtnDrawings(m_xBuilder->weld_check_button("checkBTN_DRAWINGS"))
+ , m_xBtnFormulas(m_xBuilder->weld_check_button("checkBTN_FORMULAS"))
+ , m_xBtnNullVals(m_xBuilder->weld_check_button("checkBTN_NULLVALS"))
+ , m_xLbScaleMode(m_xBuilder->weld_combo_box("comboLB_SCALEMODE"))
+ , m_xBxScaleAll(m_xBuilder->weld_widget("boxSCALEALL"))
+ , m_xEdScaleAll(m_xBuilder->weld_metric_spin_button("spinED_SCALEALL", FieldUnit::PERCENT))
+ , m_xGrHeightWidth(m_xBuilder->weld_widget("gridWH"))
+ , m_xEdScalePageWidth(m_xBuilder->weld_spin_button("spinED_SCALEPAGEWIDTH"))
+ , m_xCbScalePageWidth(m_xBuilder->weld_check_button("labelWP"))
+ , m_xEdScalePageHeight(m_xBuilder->weld_spin_button("spinED_SCALEPAGEHEIGHT"))
+ , m_xCbScalePageHeight(m_xBuilder->weld_check_button("labelHP"))
+ , m_xBxScalePageNum(m_xBuilder->weld_widget("boxNP"))
+ , m_xEdScalePageNum(m_xBuilder->weld_spin_button("spinED_SCALEPAGENUM"))
+{
+ SetExchangeSupport();
+
+ m_xBtnPageNo->connect_toggled(LINK(this,ScTablePage,PageNoHdl));
+ m_xBtnTopDown->connect_toggled(LINK(this,ScTablePage,PageDirHdl));
+ m_xBtnLeftRight->connect_toggled(LINK(this,ScTablePage,PageDirHdl));
+ m_xLbScaleMode->connect_changed(LINK(this,ScTablePage,ScaleHdl));
+ m_xCbScalePageWidth->connect_toggled(LINK(this, ScTablePage, ToggleHdl));
+ m_xCbScalePageHeight->connect_toggled(LINK(this, ScTablePage, ToggleHdl));
+}
+
+void ScTablePage::ShowImage()
+{
+ OUString aImg(m_xBtnLeftRight->get_active() ? OUString(BMP_LEFTRIGHT) : OUString(BMP_TOPDOWN));
+ m_xBmpPageDir->set_from_icon_name(aImg);
+}
+
+ScTablePage::~ScTablePage()
+{
+}
+
+std::unique_ptr<SfxTabPage> ScTablePage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rCoreSet)
+{
+ return std::make_unique<ScTablePage>(pPage, pController, *rCoreSet);
+}
+
+void ScTablePage::Reset( const SfxItemSet* rCoreSet )
+{
+ bool bTopDown = rCoreSet->Get(SID_SCATTR_PAGE_TOPDOWN).GetValue();
+
+ // sal_Bool flags
+ m_xBtnNotes->set_active( rCoreSet->Get(SID_SCATTR_PAGE_NOTES).GetValue() );
+ m_xBtnGrid->set_active( rCoreSet->Get(SID_SCATTR_PAGE_GRID).GetValue() );
+ m_xBtnHeaders->set_active( rCoreSet->Get(SID_SCATTR_PAGE_HEADERS).GetValue() );
+ m_xBtnFormulas->set_active( rCoreSet->Get(SID_SCATTR_PAGE_FORMULAS).GetValue() );
+ m_xBtnNullVals->set_active( rCoreSet->Get(SID_SCATTR_PAGE_NULLVALS).GetValue() );
+ m_xBtnTopDown->set_active( bTopDown );
+ m_xBtnLeftRight->set_active( !bTopDown );
+
+ // first printed page:
+ sal_uInt16 nPage = rCoreSet->Get(SID_SCATTR_PAGE_FIRSTPAGENO).GetValue();
+ m_xBtnPageNo->set_active( nPage != 0 );
+ m_xEdPageNo->set_value( (nPage != 0) ? nPage : 1 );
+ PageNoHdl(nullptr);
+
+ // object representation:
+ m_xBtnCharts->set_active( rCoreSet->Get(SID_SCATTR_PAGE_CHARTS).GetValue() == VOBJ_MODE_SHOW );
+ m_xBtnObjects->set_active( rCoreSet->Get(SID_SCATTR_PAGE_OBJECTS).GetValue() == VOBJ_MODE_SHOW );
+ m_xBtnDrawings->set_active( rCoreSet->Get(SID_SCATTR_PAGE_DRAWINGS).GetValue() == VOBJ_MODE_SHOW );
+
+ // scaling:
+ constexpr auto nWhichPageScale = SID_SCATTR_PAGE_SCALE;
+ if ( rCoreSet->GetItemState( nWhichPageScale ) >= SfxItemState::DEFAULT )
+ {
+ sal_uInt16 nScale = rCoreSet->Get(nWhichPageScale).GetValue();
+ if( nScale > 0 )
+ m_xLbScaleMode->set_active(SC_TPTABLE_SCALE_PERCENT);
+ m_xEdScaleAll->set_value((nScale > 0) ? nScale : 100, FieldUnit::PERCENT);
+ }
+
+ constexpr auto nWhichScaleTo = SID_SCATTR_PAGE_SCALETO;
+ if ( rCoreSet->GetItemState( nWhichScaleTo ) >= SfxItemState::DEFAULT )
+ {
+ const ScPageScaleToItem& rItem = rCoreSet->Get( nWhichScaleTo );
+ sal_uInt16 nWidth = rItem.GetWidth();
+ sal_uInt16 nHeight = rItem.GetHeight();
+
+ /* width==0 and height==0 is invalid state, used as "not selected".
+ Dialog shows width=height=1 then. */
+ if (nWidth || nHeight)
+ m_xLbScaleMode->set_active(SC_TPTABLE_SCALE_TO);
+ else
+ nWidth = nHeight = 1;
+
+ if (nWidth)
+ m_xEdScalePageWidth->set_value(nWidth);
+ else
+ m_xEdScalePageWidth->set_text(OUString());
+
+ m_xEdScalePageWidth->set_sensitive(nWidth != 0);
+ m_xCbScalePageWidth->set_active(nWidth != 0);
+
+ if(nHeight)
+ m_xEdScalePageHeight->set_value(nHeight);
+ else
+ m_xEdScalePageHeight->set_text(OUString());
+
+ m_xEdScalePageHeight->set_sensitive(nHeight != 0);
+ m_xCbScalePageHeight->set_active(nHeight != 0);
+ }
+
+ constexpr auto nWhichScale = SID_SCATTR_PAGE_SCALETOPAGES;
+ if ( rCoreSet->GetItemState( nWhichScale ) >= SfxItemState::DEFAULT )
+ {
+ sal_uInt16 nPages = rCoreSet->Get(nWhichScale).GetValue();
+ if( nPages > 0 )
+ m_xLbScaleMode->set_active(SC_TPTABLE_SCALE_TO_PAGES);
+ m_xEdScalePageNum->set_value( (nPages > 0) ? nPages : 1 );
+ }
+
+ if (m_xLbScaleMode->get_active() == -1)
+ {
+ // fall back to 100%
+ OSL_FAIL( "ScTablePage::Reset - missing scaling item" );
+ m_xLbScaleMode->set_active(SC_TPTABLE_SCALE_PERCENT);
+ m_xEdScaleAll->set_value(100, FieldUnit::PERCENT);
+ }
+
+ PageDirHdl(*m_xBtnTopDown);
+ ScaleHdl(*m_xLbScaleMode);
+
+ // remember for FillItemSet
+ m_xBtnFormulas->save_state();
+ m_xBtnNullVals->save_state();
+ m_xBtnNotes->save_state();
+ m_xBtnGrid->save_state();
+ m_xBtnHeaders->save_state();
+ m_xBtnTopDown->save_state();
+ m_xBtnLeftRight->save_state();
+ m_xLbScaleMode->save_value();
+ m_xBtnCharts->save_state();
+ m_xBtnObjects->save_state();
+ m_xBtnDrawings->save_state();
+ m_xBtnPageNo->save_state();
+ m_xEdPageNo->save_value();
+ m_xEdScaleAll->save_value();
+ m_nOrigScalePageWidth = m_xEdScalePageWidth->get_sensitive() ? m_xEdScalePageWidth->get_value() : 0;
+ m_nOrigScalePageHeight = m_xEdScalePageHeight->get_sensitive() ? m_xEdScalePageHeight->get_value() : 0;
+ m_xEdScalePageNum->save_value();
+}
+
+bool ScTablePage::FillItemSet( SfxItemSet* rCoreSet )
+{
+ const SfxItemSet& rOldSet = GetItemSet();
+ constexpr sal_uInt16 nWhichPageNo = SID_SCATTR_PAGE_FIRSTPAGENO;
+ bool bDataChanged = false;
+
+ // sal_Bool flags
+ bDataChanged |= lcl_PutBoolItem( SID_SCATTR_PAGE_NOTES,
+ *rCoreSet, rOldSet,
+ m_xBtnNotes->get_active(),
+ m_xBtnNotes->get_saved_state() != TRISTATE_FALSE );
+
+ bDataChanged |= lcl_PutBoolItem( SID_SCATTR_PAGE_GRID,
+ *rCoreSet, rOldSet,
+ m_xBtnGrid->get_active(),
+ m_xBtnGrid->get_saved_state() != TRISTATE_FALSE );
+
+ bDataChanged |= lcl_PutBoolItem( SID_SCATTR_PAGE_HEADERS,
+ *rCoreSet, rOldSet,
+ m_xBtnHeaders->get_active(),
+ m_xBtnHeaders->get_saved_state() != TRISTATE_FALSE );
+
+ bDataChanged |= lcl_PutBoolItem( SID_SCATTR_PAGE_TOPDOWN,
+ *rCoreSet, rOldSet,
+ m_xBtnTopDown->get_active(),
+ m_xBtnTopDown->get_saved_state() != TRISTATE_FALSE );
+
+ bDataChanged |= lcl_PutBoolItem( SID_SCATTR_PAGE_FORMULAS,
+ *rCoreSet, rOldSet,
+ m_xBtnFormulas->get_active(),
+ m_xBtnFormulas->get_saved_state() != TRISTATE_FALSE );
+
+ bDataChanged |= lcl_PutBoolItem( SID_SCATTR_PAGE_NULLVALS,
+ *rCoreSet, rOldSet,
+ m_xBtnNullVals->get_active(),
+ m_xBtnNullVals->get_saved_state() != TRISTATE_FALSE );
+
+ // first printed page:
+ bool bUseValue = m_xBtnPageNo->get_active();
+
+ if ( WAS_DEFAULT(nWhichPageNo,rOldSet)
+ && ( (!bUseValue && 0 == m_xBtnPageNo->get_saved_state())
+ || ( bUseValue && 1 == m_xBtnPageNo->get_saved_state()
+ && ! m_xEdPageNo->get_value_changed_from_saved() ) ) )
+ {
+ rCoreSet->ClearItem( nWhichPageNo );
+ }
+ else
+ {
+ sal_uInt16 nPage = static_cast<sal_uInt16>( m_xBtnPageNo->get_active()
+ ? m_xEdPageNo->get_value()
+ : 0 );
+
+ rCoreSet->Put( SfxUInt16Item( nWhichPageNo, nPage ) );
+ bDataChanged = true;
+ }
+
+ // object representation:
+ bDataChanged |= lcl_PutVObjModeItem( SID_SCATTR_PAGE_CHARTS,
+ *rCoreSet, rOldSet, *m_xBtnCharts );
+
+ bDataChanged |= lcl_PutVObjModeItem( SID_SCATTR_PAGE_OBJECTS,
+ *rCoreSet, rOldSet, *m_xBtnObjects );
+
+ bDataChanged |= lcl_PutVObjModeItem( SID_SCATTR_PAGE_DRAWINGS,
+ *rCoreSet, rOldSet, *m_xBtnDrawings );
+
+ // scaling:
+ if( !m_xEdScalePageWidth->get_sensitive() && !m_xEdScalePageHeight->get_sensitive() )
+ {
+ m_xLbScaleMode->set_active(SC_TPTABLE_SCALE_PERCENT);
+ m_xEdScaleAll->set_value(100, FieldUnit::PERCENT);
+ }
+
+ bDataChanged |= lcl_PutScaleItem( SID_SCATTR_PAGE_SCALE,
+ *rCoreSet, rOldSet,
+ *m_xLbScaleMode, SC_TPTABLE_SCALE_PERCENT,
+ *m_xEdScaleAll, static_cast<sal_uInt16>(m_xEdScaleAll->get_value(FieldUnit::PERCENT)) );
+
+ bDataChanged |= lcl_PutScaleItem2( SID_SCATTR_PAGE_SCALETO,
+ *rCoreSet, rOldSet,
+ *m_xLbScaleMode, SC_TPTABLE_SCALE_TO,
+ *m_xEdScalePageWidth, m_nOrigScalePageWidth,
+ *m_xEdScalePageHeight, m_nOrigScalePageHeight );
+
+ bDataChanged |= lcl_PutScaleItem3( SID_SCATTR_PAGE_SCALETOPAGES,
+ *rCoreSet, rOldSet,
+ *m_xLbScaleMode, SC_TPTABLE_SCALE_TO_PAGES,
+ *m_xEdScalePageNum, static_cast<sal_uInt16>(m_xEdScalePageNum->get_value()) );
+
+ return bDataChanged;
+}
+
+DeactivateRC ScTablePage::DeactivatePage( SfxItemSet* pSetP )
+{
+ if ( pSetP )
+ FillItemSet( pSetP );
+
+ return DeactivateRC::LeavePage;
+}
+
+// Handler:
+
+IMPL_LINK_NOARG(ScTablePage, PageDirHdl, weld::Toggleable&, void)
+{
+ ShowImage();
+}
+
+IMPL_LINK(ScTablePage, PageNoHdl, weld::Toggleable&, rBtn, void)
+{
+ PageNoHdl(&rBtn);
+}
+
+void ScTablePage::PageNoHdl(const weld::Toggleable* pBtn)
+{
+ if (m_xBtnPageNo->get_active())
+ {
+ m_xEdPageNo->set_sensitive(true);
+ if (pBtn)
+ m_xEdPageNo->grab_focus();
+ }
+ else
+ m_xEdPageNo->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(ScTablePage, ScaleHdl, weld::ComboBox&, void)
+{
+ // controls for Box "Reduce/enlarge"
+ m_xBxScaleAll->set_visible(m_xLbScaleMode->get_active() == SC_TPTABLE_SCALE_PERCENT);
+
+ // controls for Grid "Scale to width/height"
+ m_xGrHeightWidth->set_visible(m_xLbScaleMode->get_active() == SC_TPTABLE_SCALE_TO);
+
+ // controls for Box "Scale to pages"
+ m_xBxScalePageNum->set_visible(m_xLbScaleMode->get_active() == SC_TPTABLE_SCALE_TO_PAGES);
+}
+
+IMPL_LINK(ScTablePage, ToggleHdl, weld::Toggleable&, rBox, void)
+{
+ if (&rBox == m_xCbScalePageWidth.get())
+ {
+ if (!rBox.get_active())
+ {
+ m_xEdScalePageWidth->set_text(OUString());
+ m_xEdScalePageWidth->set_sensitive(false);
+ }
+ else
+ {
+ m_xEdScalePageWidth->set_value(1);
+ m_xEdScalePageWidth->set_sensitive(true);
+ }
+ }
+ else
+ {
+ if (!rBox.get_active())
+ {
+ m_xEdScalePageHeight->set_text(OUString());
+ m_xEdScalePageHeight->set_sensitive(false);
+ }
+ else
+ {
+ m_xEdScalePageHeight->set_value(1);
+ m_xEdScalePageHeight->set_sensitive(true);
+ }
+ }
+}
+
+// Helper functions for FillItemSet:
+
+static bool lcl_PutBoolItem( TypedWhichId<SfxBoolItem> nWhich,
+ SfxItemSet& rCoreSet,
+ const SfxItemSet& rOldSet,
+ bool bIsChecked,
+ bool bSavedValue )
+{
+ bool bDataChanged = ( bSavedValue == bIsChecked
+ && WAS_DEFAULT(nWhich,rOldSet) );
+
+ if ( bDataChanged )
+ rCoreSet.ClearItem(nWhich);
+ else
+ rCoreSet.Put( SfxBoolItem( nWhich, bIsChecked ) );
+
+ return bDataChanged;
+}
+
+static bool lcl_PutVObjModeItem( TypedWhichId<ScViewObjectModeItem> nWhich,
+ SfxItemSet& rCoreSet,
+ const SfxItemSet& rOldSet,
+ const weld::Toggleable& rBtn )
+{
+ bool bIsChecked = rBtn.get_active();
+ bool bDataChanged = rBtn.get_saved_state() == (bIsChecked ? 1 : 0)
+ && WAS_DEFAULT(nWhich,rOldSet);
+
+ if ( bDataChanged )
+ rCoreSet.ClearItem( nWhich );
+
+ else
+ rCoreSet.Put( ScViewObjectModeItem( nWhich, bIsChecked
+ ? VOBJ_MODE_SHOW
+ : VOBJ_MODE_HIDE ) );
+ return bDataChanged;
+}
+
+static bool lcl_PutScaleItem( TypedWhichId<SfxUInt16Item> nWhich,
+ SfxItemSet& rCoreSet,
+ const SfxItemSet& rOldSet,
+ const weld::ComboBox& rListBox,
+ sal_uInt16 nLBEntry,
+ const weld::MetricSpinButton& rEd,
+ sal_uInt16 nValue )
+{
+ bool bIsSel = (rListBox.get_active() == nLBEntry);
+ bool bDataChanged = (rListBox.get_value_changed_from_saved()) ||
+ rEd.get_value_changed_from_saved() ||
+ !WAS_DEFAULT( nWhich, rOldSet );
+
+ if( bDataChanged )
+ rCoreSet.Put( SfxUInt16Item( nWhich, bIsSel ? nValue : 0 ) );
+ else
+ rCoreSet.ClearItem( nWhich );
+
+ return bDataChanged;
+}
+
+static bool lcl_PutScaleItem2( TypedWhichId<ScPageScaleToItem> nWhich,
+ SfxItemSet& rCoreSet,
+ const SfxItemSet& rOldSet,
+ const weld::ComboBox& rListBox,
+ sal_uInt16 nLBEntry,
+ const weld::SpinButton& rEd1,
+ sal_uInt16 nOrigScalePageWidth,
+ const weld::SpinButton& rEd2,
+ sal_uInt16 nOrigScalePageHeight )
+{
+ sal_uInt16 nValue1 = rEd1.get_sensitive() ? rEd1.get_value() : 0;
+ sal_uInt16 nValue2 = rEd2.get_sensitive() ? rEd2.get_value() : 0;
+ bool bIsSel = (rListBox.get_active() == nLBEntry);
+ bool bDataChanged = (rListBox.get_value_changed_from_saved()) ||
+ nValue1 != nOrigScalePageWidth ||
+ nValue1 != nOrigScalePageHeight ||
+ !WAS_DEFAULT( nWhich, rOldSet );
+
+ if( bDataChanged )
+ {
+ ScPageScaleToItem aItem;
+ if( bIsSel )
+ aItem.Set( nValue1, nValue2 );
+ rCoreSet.Put( aItem );
+ }
+ else
+ rCoreSet.ClearItem( nWhich );
+
+ return bDataChanged;
+}
+
+static bool lcl_PutScaleItem3( TypedWhichId<SfxUInt16Item> nWhich,
+ SfxItemSet& rCoreSet,
+ const SfxItemSet& rOldSet,
+ const weld::ComboBox& rListBox,
+ sal_uInt16 nLBEntry,
+ const weld::SpinButton& rEd,
+ sal_uInt16 nValue )
+{
+ bool bIsSel = (rListBox.get_active() == nLBEntry);
+ bool bDataChanged = (rListBox.get_value_changed_from_saved()) ||
+ rEd.get_value_changed_from_saved() ||
+ !WAS_DEFAULT( nWhich, rOldSet );
+
+ if( bDataChanged )
+ rCoreSet.Put( SfxUInt16Item( nWhich, bIsSel ? nValue : 0 ) );
+ else
+ rCoreSet.ClearItem( nWhich );
+
+ return bDataChanged;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/AlignmentPropertyPanel.cxx b/sc/source/ui/sidebar/AlignmentPropertyPanel.cxx
new file mode 100644
index 000000000..370b79157
--- /dev/null
+++ b/sc/source/ui/sidebar/AlignmentPropertyPanel.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 "AlignmentPropertyPanel.hxx"
+#include <editeng/justifyitem.hxx>
+#include <sc.hrc>
+#include <attrib.hxx>
+#include <scitems.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svl/intitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <svtools/unitconv.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+using namespace css;
+using namespace css::uno;
+
+// namespace open
+
+namespace sc::sidebar {
+
+AlignmentPropertyPanel::AlignmentPropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings)
+ : PanelLayout(pParent, "AlignmentPropertyPanel", "modules/scalc/ui/sidebaralignment.ui")
+ , mxFTLeftIndent(m_xBuilder->weld_label("leftindentlabel"))
+ , mxMFLeftIndent(m_xBuilder->weld_metric_spin_button("leftindent", FieldUnit::POINT))
+ , mxCBXWrapText(m_xBuilder->weld_check_button("wraptext"))
+ , mxCBXMergeCell(m_xBuilder->weld_check_button("mergecells"))
+ , mxFtRotate(m_xBuilder->weld_label("orientationlabel"))
+ , mxMtrAngle(m_xBuilder->weld_metric_spin_button("orientationdegrees", FieldUnit::DEGREE))
+ , mxRefEdgeBottom(m_xBuilder->weld_toggle_button("bottom"))
+ , mxRefEdgeTop(m_xBuilder->weld_toggle_button("top"))
+ , mxRefEdgeStd(m_xBuilder->weld_toggle_button("standard"))
+ , mxCBStacked(m_xBuilder->weld_check_button("stacked"))
+ , mxTextOrientBox(m_xBuilder->weld_widget("textorientbox"))
+ , mxHorizontalAlign(m_xBuilder->weld_toolbar("horizontalalignment"))
+ , mxHorizontalAlignDispatch(new ToolbarUnoDispatcher(*mxHorizontalAlign, *m_xBuilder, rxFrame))
+ , mxVertAlign(m_xBuilder->weld_toolbar("verticalalignment"))
+ , mxVertAlignDispatch(new ToolbarUnoDispatcher(*mxVertAlign, *m_xBuilder, rxFrame))
+ , mxWriteDirection(m_xBuilder->weld_toolbar("writedirection"))
+ , mxWriteDirectionDispatch(new ToolbarUnoDispatcher(*mxWriteDirection, *m_xBuilder, rxFrame))
+ , mxIndentButtons(m_xBuilder->weld_toolbar("indentbuttons"))
+ , mxIndentButtonsDispatch(new ToolbarUnoDispatcher(*mxIndentButtons, *m_xBuilder, rxFrame))
+ , maAlignHorControl(SID_H_ALIGNCELL, *pBindings, *this)
+ , maLeftIndentControl(SID_ATTR_ALIGN_INDENT, *pBindings, *this)
+ , maMergeCellControl(FID_MERGE_TOGGLE, *pBindings, *this)
+ , maWrapTextControl(SID_ATTR_ALIGN_LINEBREAK, *pBindings, *this)
+ , maAngleControl(SID_ATTR_ALIGN_DEGREES, *pBindings, *this)
+ , maVrtStackControl(SID_ATTR_ALIGN_STACKED, *pBindings, *this)
+ , maRefEdgeControl(SID_ATTR_ALIGN_LOCKPOS, *pBindings, *this)
+ , mbMultiDisable(false)
+ , mpBindings(pBindings)
+{
+ Initialize();
+}
+
+AlignmentPropertyPanel::~AlignmentPropertyPanel()
+{
+ mxIndentButtonsDispatch.reset();
+ mxIndentButtons.reset();
+ mxWriteDirectionDispatch.reset();
+ mxWriteDirection.reset();
+ mxVertAlignDispatch.reset();
+ mxVertAlign.reset();
+ mxHorizontalAlignDispatch.reset();
+ mxHorizontalAlign.reset();
+
+ mxFTLeftIndent.reset();
+ mxMFLeftIndent.reset();
+ mxCBXWrapText.reset();
+ mxCBXMergeCell.reset();
+ mxFtRotate.reset();
+ mxMtrAngle.reset();
+ mxCBStacked.reset();
+ mxRefEdgeBottom.reset();
+ mxRefEdgeTop.reset();
+ mxRefEdgeStd.reset();
+ mxTextOrientBox.reset();
+
+ maAlignHorControl.dispose();
+ maLeftIndentControl.dispose();
+ maMergeCellControl.dispose();
+ maWrapTextControl.dispose();
+ maAngleControl.dispose();
+ maVrtStackControl.dispose();
+ maRefEdgeControl.dispose();
+}
+
+void AlignmentPropertyPanel::Initialize()
+{
+ mxFTLeftIndent->set_sensitive(false);
+ mxMFLeftIndent->set_sensitive(false);
+ Link<weld::MetricSpinButton&,void> aLink = LINK(this, AlignmentPropertyPanel, MFLeftIndentMdyHdl);
+ mxMFLeftIndent->connect_value_changed( aLink );
+
+ mxCBXMergeCell->connect_toggled( LINK(this, AlignmentPropertyPanel, CBOXMergnCellClkHdl) );
+
+ mxCBXWrapText->connect_toggled( LINK(this, AlignmentPropertyPanel, CBOXWrapTextClkHdl) );
+
+ //rotation
+ mxMtrAngle->connect_value_changed(LINK( this, AlignmentPropertyPanel, AngleModifiedHdl));
+ mxCBStacked->connect_toggled(LINK(this, AlignmentPropertyPanel, ClickStackHdl));
+
+ Link<weld::Button&,void> aLink2 = LINK(this, AlignmentPropertyPanel, ReferenceEdgeHdl);
+ mxRefEdgeBottom->connect_clicked(aLink2);
+ mxRefEdgeTop->connect_clicked(aLink2);
+ mxRefEdgeStd->connect_clicked(aLink2);
+}
+
+IMPL_LINK(AlignmentPropertyPanel, ReferenceEdgeHdl, weld::Button&, rToggle, void)
+{
+ SvxRotateMode eMode;
+ if (&rToggle == mxRefEdgeBottom.get())
+ eMode = SVX_ROTATE_MODE_BOTTOM;
+ else if (&rToggle == mxRefEdgeTop.get())
+ eMode = SVX_ROTATE_MODE_TOP;
+ else /*if (&rToggle == mxRefEdgeStd.get())*/
+ eMode = SVX_ROTATE_MODE_STANDARD;
+
+ mxRefEdgeBottom->set_active(eMode == SVX_ROTATE_MODE_BOTTOM);
+ mxRefEdgeTop->set_active(eMode == SVX_ROTATE_MODE_TOP);
+ mxRefEdgeStd->set_active(eMode == SVX_ROTATE_MODE_STANDARD);
+
+ SvxRotateModeItem aItem(eMode, ATTR_ROTATE_MODE);
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_ALIGN_LOCKPOS,
+ SfxCallMode::RECORD, { &aItem });
+}
+
+IMPL_LINK_NOARG( AlignmentPropertyPanel, AngleModifiedHdl, weld::MetricSpinButton&, void )
+{
+ Degree100 nAngle(mxMtrAngle->get_value(FieldUnit::DEGREE) * 100);
+ ScRotateValueItem aAngleItem(nAngle);
+
+ GetBindings()->GetDispatcher()->ExecuteList(
+ SID_ATTR_ALIGN_DEGREES, SfxCallMode::RECORD, { &aAngleItem });
+}
+
+IMPL_LINK_NOARG( AlignmentPropertyPanel, ClickStackHdl, weld::Toggleable&, void )
+{
+ bool bVertical = mxCBStacked->get_active();
+ ScVerticalStackCell aStackItem(bVertical);
+ GetBindings()->GetDispatcher()->ExecuteList(
+ SID_ATTR_ALIGN_STACKED, SfxCallMode::RECORD, { &aStackItem });
+}
+
+IMPL_LINK_NOARG(AlignmentPropertyPanel, MFLeftIndentMdyHdl, weld::MetricSpinButton&, void)
+{
+ sal_uInt16 nVal = mxMFLeftIndent->get_value(FieldUnit::NONE);
+ ScIndentItem aItem(static_cast<sal_uInt16>(CalcToUnit(nVal, MapUnit::MapTwip)));
+
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_ALIGN_INDENT,
+ SfxCallMode::RECORD, { &aItem });
+}
+
+IMPL_LINK_NOARG(AlignmentPropertyPanel, CBOXMergnCellClkHdl, weld::Toggleable&, void)
+{
+ bool bState = mxCBXMergeCell->get_active();
+
+ if( bState)
+ GetBindings()->GetDispatcher()->Execute(FID_MERGE_ON, SfxCallMode::RECORD);
+ else
+ GetBindings()->GetDispatcher()->Execute(FID_MERGE_OFF, SfxCallMode::RECORD);
+ GetBindings()->Invalidate(FID_MERGE_TOGGLE,true);
+}
+
+IMPL_LINK_NOARG(AlignmentPropertyPanel, CBOXWrapTextClkHdl, weld::Toggleable&, void)
+{
+ bool bState = mxCBXWrapText->get_active();
+ ScLineBreakCell aItem(bState);
+ GetBindings()->GetDispatcher()->ExecuteList(SID_ATTR_ALIGN_LINEBREAK,
+ SfxCallMode::RECORD, { &aItem });
+}
+
+std::unique_ptr<PanelLayout> AlignmentPropertyPanel::Create (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to AlignmentPropertyPanel::Create", nullptr, 0);
+ if ( ! rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to AlignmentPropertyPanel::Create", nullptr, 1);
+ if (pBindings == nullptr)
+ throw lang::IllegalArgumentException("no SfxBindings given to AlignmentPropertyPanel::Create", nullptr, 2);
+
+ return std::make_unique<AlignmentPropertyPanel>(pParent, rxFrame, pBindings);
+}
+
+void AlignmentPropertyPanel::HandleContextChange(
+ const vcl::EnumContext& rContext)
+{
+ if (maContext == rContext)
+ {
+ // Nothing to do.
+ return;
+ }
+
+ maContext = rContext;
+}
+
+void AlignmentPropertyPanel::NotifyItemUpdate(
+ sal_uInt16 nSID,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ switch(nSID)
+ {
+ case SID_H_ALIGNCELL:
+ {
+ SvxCellHorJustify meHorAlignState = SvxCellHorJustify::Standard;
+ if(eState >= SfxItemState::DEFAULT)
+ if (auto pItem = dynamic_cast<const SvxHorJustifyItem*>( pState) )
+ meHorAlignState = pItem->GetValue();
+
+ if( meHorAlignState == SvxCellHorJustify::Repeat )
+ {
+ mxFtRotate->set_sensitive(false);
+ mxMtrAngle->set_sensitive(false);
+ }
+ else
+ {
+ mxFtRotate->set_sensitive(!mbMultiDisable);
+ mxMtrAngle->set_sensitive(!mbMultiDisable);
+ }
+
+ mxFTLeftIndent->set_sensitive( meHorAlignState == SvxCellHorJustify::Left );
+ mxMFLeftIndent->set_sensitive( meHorAlignState == SvxCellHorJustify::Left );
+ }
+ break;
+ case SID_ATTR_ALIGN_INDENT:
+ if(eState >= SfxItemState::DEFAULT && dynamic_cast<const SfxUInt16Item*>( pState) )
+ {
+ const SfxUInt16Item* pItem = static_cast<const SfxUInt16Item*>(pState);
+ sal_uInt16 nVal = pItem->GetValue();
+ mxMFLeftIndent->set_value( CalcToPoint(nVal, MapUnit::MapTwip, 1), FieldUnit::NONE );
+ }
+ else
+ {
+ mxMFLeftIndent->set_value(0, FieldUnit::NONE);
+ mxMFLeftIndent->set_text(OUString());
+ }
+ break;
+ case FID_MERGE_TOGGLE:
+ if(eState >= SfxItemState::DEFAULT && dynamic_cast<const SfxBoolItem*>( pState) )
+ {
+ mxCBXMergeCell->set_sensitive(true);
+ const SfxBoolItem* pItem = static_cast<const SfxBoolItem*>(pState);
+ mxCBXMergeCell->set_active(pItem->GetValue());
+ }
+ else
+ {
+ mxCBXMergeCell->set_active(false);
+ mxCBXMergeCell->set_sensitive(false);
+ }
+ break;
+
+ case SID_ATTR_ALIGN_LINEBREAK:
+ if(eState == SfxItemState::DISABLED)
+ {
+ mxCBXWrapText->set_active(false);
+ mxCBXWrapText->set_sensitive(false);
+ }
+ else
+ {
+ mxCBXWrapText->set_sensitive(true);
+ if(eState >= SfxItemState::DEFAULT && dynamic_cast<const ScLineBreakCell*>( pState) )
+ {
+ const ScLineBreakCell* pItem = static_cast<const ScLineBreakCell*>(pState);
+ mxCBXWrapText->set_active(pItem->GetValue());
+ }
+ else if(eState == SfxItemState::DONTCARE)
+ {
+ mxCBXWrapText->set_state(TRISTATE_INDET);
+ }
+ }
+ break;
+ case SID_ATTR_ALIGN_STACKED:
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ const SfxBoolItem* pStackItem = static_cast<const ScVerticalStackCell*>(pState);
+ mbMultiDisable = pStackItem->GetValue();
+ mxCBStacked->set_active(mbMultiDisable);
+ mxTextOrientBox->set_sensitive(!mbMultiDisable);
+ }
+ else
+ {
+ mbMultiDisable = true;
+ mxTextOrientBox->set_sensitive(false);
+ mxCBStacked->set_state(TRISTATE_INDET);
+ }
+ break;
+ case SID_ATTR_ALIGN_LOCKPOS:
+ if( eState >= SfxItemState::DEFAULT)
+ {
+ const SvxRotateModeItem* pItem = static_cast<const SvxRotateModeItem*>(pState);
+ SvxRotateMode eMode = pItem->GetValue();
+ mxRefEdgeBottom->set_active(eMode == SVX_ROTATE_MODE_BOTTOM);
+ mxRefEdgeTop->set_active(eMode == SVX_ROTATE_MODE_TOP);
+ mxRefEdgeStd->set_active(eMode == SVX_ROTATE_MODE_STANDARD);
+ }
+ break;
+ case SID_ATTR_ALIGN_DEGREES:
+ if (eState >= SfxItemState::DEFAULT)
+ {
+ Degree100 nTmp = static_cast<const ScRotateValueItem*>(pState)->GetValue();
+ mxMtrAngle->set_value(toDegrees(nTmp), FieldUnit::DEGREE);
+ }
+ else
+ {
+ mxMtrAngle->set_text( OUString() );
+ }
+ break;
+ }
+}
+
+// namespace close
+
+} // end of namespace ::sc::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/AlignmentPropertyPanel.hxx b/sc/source/ui/sidebar/AlignmentPropertyPanel.hxx
new file mode 100644
index 000000000..7de9cc633
--- /dev/null
+++ b/sc/source/ui/sidebar/AlignmentPropertyPanel.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 <sfx2/sidebar/ControllerItem.hxx>
+#include <sfx2/sidebar/IContextChangeReceiver.hxx>
+#include <sfx2/weldutils.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <vcl/EnumContext.hxx>
+
+namespace sc::sidebar {
+
+class AlignmentPropertyPanel
+: public PanelLayout,
+ public ::sfx2::sidebar::IContextChangeReceiver,
+ public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+public:
+ static std::unique_ptr<PanelLayout> Create(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings);
+
+ virtual void HandleContextChange(
+ const vcl::EnumContext& rContext) override;
+
+ virtual void NotifyItemUpdate(
+ const sal_uInt16 nSId,
+ const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void GetControlState(
+ const sal_uInt16 /*nSId*/,
+ boost::property_tree::ptree& /*rState*/) override {};
+
+ SfxBindings* GetBindings() { return mpBindings;}
+
+ // constructor/destructor
+ AlignmentPropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings);
+ virtual ~AlignmentPropertyPanel() override;
+
+private:
+ //ui controls
+ std::unique_ptr<weld::Label> mxFTLeftIndent;
+ std::unique_ptr<weld::MetricSpinButton> mxMFLeftIndent;
+ std::unique_ptr<weld::CheckButton> mxCBXWrapText;
+ std::unique_ptr<weld::CheckButton> mxCBXMergeCell;
+ std::unique_ptr<weld::Label> mxFtRotate;
+ std::unique_ptr<weld::MetricSpinButton> mxMtrAngle;
+ std::unique_ptr<weld::ToggleButton> mxRefEdgeBottom;
+ std::unique_ptr<weld::ToggleButton> mxRefEdgeTop;
+ std::unique_ptr<weld::ToggleButton> mxRefEdgeStd;
+ std::unique_ptr<weld::CheckButton> mxCBStacked;
+ std::unique_ptr<weld::Widget> mxTextOrientBox;
+
+ std::unique_ptr<weld::Toolbar> mxHorizontalAlign;
+ std::unique_ptr<ToolbarUnoDispatcher> mxHorizontalAlignDispatch;
+
+ std::unique_ptr<weld::Toolbar> mxVertAlign;
+ std::unique_ptr<ToolbarUnoDispatcher> mxVertAlignDispatch;
+
+ std::unique_ptr<weld::Toolbar> mxWriteDirection;
+ std::unique_ptr<ToolbarUnoDispatcher> mxWriteDirectionDispatch;
+
+ std::unique_ptr<weld::Toolbar> mxIndentButtons;
+ std::unique_ptr<ToolbarUnoDispatcher> mxIndentButtonsDispatch;
+
+ ::sfx2::sidebar::ControllerItem maAlignHorControl;
+ ::sfx2::sidebar::ControllerItem maLeftIndentControl;
+ ::sfx2::sidebar::ControllerItem maMergeCellControl;
+ ::sfx2::sidebar::ControllerItem maWrapTextControl;
+ ::sfx2::sidebar::ControllerItem maAngleControl;
+ ::sfx2::sidebar::ControllerItem maVrtStackControl;
+ ::sfx2::sidebar::ControllerItem maRefEdgeControl;
+
+ bool mbMultiDisable : 1;
+
+ vcl::EnumContext maContext;
+ SfxBindings* mpBindings;
+
+ DECL_LINK( MFLeftIndentMdyHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( CBOXMergnCellClkHdl, weld::Toggleable&, void );
+ DECL_LINK( CBOXWrapTextClkHdl, weld::Toggleable&, void );
+ DECL_LINK( AngleModifiedHdl, weld::MetricSpinButton&, void );
+ DECL_LINK( ClickStackHdl, weld::Toggleable&, void );
+ DECL_LINK( ReferenceEdgeHdl, weld::Button&, void );
+
+ void Initialize();
+};
+
+} // end of namespace ::sc::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/CellAppearancePropertyPanel.cxx b/sc/source/ui/sidebar/CellAppearancePropertyPanel.cxx
new file mode 100644
index 000000000..d09b8a5ca
--- /dev/null
+++ b/sc/source/ui/sidebar/CellAppearancePropertyPanel.cxx
@@ -0,0 +1,506 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "CellAppearancePropertyPanel.hxx"
+#include <sc.hrc>
+#include <bitmaps.hlst>
+#include <sfx2/bindings.hxx>
+#include <sfx2/weldutils.hxx>
+#include <svtools/toolbarmenu.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/lineitem.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include "CellLineStyleControl.hxx"
+#include "CellBorderStyleControl.hxx"
+
+using namespace css;
+using namespace css::uno;
+
+constexpr OStringLiteral SETBORDERSTYLE = "SetBorderStyle";
+constexpr OStringLiteral LINESTYLE = "LineStyle";
+
+// namespace open
+
+namespace sc::sidebar {
+
+CellAppearancePropertyPanel::CellAppearancePropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings)
+: PanelLayout(pParent, "CellAppearancePropertyPanel", "modules/scalc/ui/sidebarcellappearance.ui"),
+
+ mxTBCellBorder(m_xBuilder->weld_toolbar("cellbordertype")),
+ mxTBCellBackground(m_xBuilder->weld_toolbar("cellbackgroundcolor")),
+ mxBackColorDispatch(new ToolbarUnoDispatcher(*mxTBCellBackground, *m_xBuilder, rxFrame)),
+ mxTBLineStyle(m_xBuilder->weld_toolbar("borderlinestyle")),
+ mxTBLineColor(m_xBuilder->weld_toolbar("borderlinecolor")),
+ mxLineColorDispatch(new ToolbarUnoDispatcher(*mxTBLineColor, *m_xBuilder, rxFrame)),
+
+ mbCellBorderPopoverCreated(false),
+ mbLinePopoverCreated(false),
+
+ maLineStyleControl(SID_FRAME_LINESTYLE, *pBindings, *this),
+ maBorderOuterControl(SID_ATTR_BORDER_OUTER, *pBindings, *this),
+ maBorderInnerControl(SID_ATTR_BORDER_INNER, *pBindings, *this),
+ maGridShowControl(FID_TAB_TOGGLE_GRID, *pBindings, *this),
+ maBorderTLBRControl(SID_ATTR_BORDER_DIAG_TLBR, *pBindings, *this),
+ maBorderBLTRControl(SID_ATTR_BORDER_DIAG_BLTR, *pBindings, *this),
+
+ maIMGCellBorder(StockImage::Yes, RID_BMP_CELL_BORDER),
+ msIMGCellBorder(RID_BMP_CELL_BORDER),
+ msIMGLineStyle1(RID_BMP_LINE_STYLE1),
+ msIMGLineStyle2(RID_BMP_LINE_STYLE2),
+ msIMGLineStyle3(RID_BMP_LINE_STYLE3),
+ msIMGLineStyle4(RID_BMP_LINE_STYLE4),
+ msIMGLineStyle5(RID_BMP_LINE_STYLE5),
+ msIMGLineStyle6(RID_BMP_LINE_STYLE6),
+ msIMGLineStyle7(RID_BMP_LINE_STYLE7),
+ msIMGLineStyle8(RID_BMP_LINE_STYLE8),
+ msIMGLineStyle9(RID_BMP_LINE_STYLE9),
+
+ mnInWidth(0),
+ mnOutWidth(0),
+ mnDistance(0),
+ mnDiagTLBRInWidth(0),
+ mnDiagTLBROutWidth(0),
+ mnDiagTLBRDistance(0),
+ mnDiagBLTRInWidth(0),
+ mnDiagBLTROutWidth(0),
+ mnDiagBLTRDistance(0),
+ mbBorderStyleAvailable(true),
+ mbLeft(false),
+ mbRight(false),
+ mbTop(false),
+ mbBottom(false),
+ mbVer(false),
+ mbHor(false),
+ mbOuterBorder(false),
+ mbInnerBorder(false),
+ mbDiagTLBR(false),
+ mbDiagBLTR(false),
+ mpBindings(pBindings)
+{
+ Initialize();
+}
+
+CellAppearancePropertyPanel::~CellAppearancePropertyPanel()
+{
+ mxCellBorderPopoverContainer.reset();
+ mxTBCellBorder.reset();
+ mxBackColorDispatch.reset();
+ mxTBCellBackground.reset();
+ mxLinePopoverContainer.reset();
+ mxTBLineStyle.reset();
+ mxLineColorDispatch.reset();
+ mxTBLineColor.reset();
+
+ maLineStyleControl.dispose();
+ maBorderOuterControl.dispose();
+ maBorderInnerControl.dispose();
+ maGridShowControl.dispose();
+ maBorderTLBRControl.dispose();
+ maBorderBLTRControl.dispose();
+}
+
+void CellAppearancePropertyPanel::Initialize()
+{
+ mxTBCellBorder->set_item_icon_name(SETBORDERSTYLE, msIMGCellBorder);
+ mxCellBorderPopoverContainer.reset(new ToolbarPopupContainer(mxTBCellBorder.get()));
+ mxTBCellBorder->set_item_popover(SETBORDERSTYLE, mxCellBorderPopoverContainer->getTopLevel());
+ mxTBCellBorder->connect_clicked(LINK(this, CellAppearancePropertyPanel, TbxCellBorderSelectHdl));
+ mxTBCellBorder->connect_menu_toggled(LINK(this, CellAppearancePropertyPanel, TbxCellBorderMenuHdl));
+
+ mxTBLineStyle->set_item_icon_name(LINESTYLE, msIMGLineStyle1);
+ mxLinePopoverContainer.reset(new ToolbarPopupContainer(mxTBLineStyle.get()));
+ mxTBLineStyle->set_item_popover(LINESTYLE, mxLinePopoverContainer->getTopLevel());
+ mxTBLineStyle->connect_clicked(LINK(this, CellAppearancePropertyPanel, TbxLineStyleSelectHdl));
+ mxTBLineStyle->connect_menu_toggled(LINK(this, CellAppearancePropertyPanel, TbxLineStyleMenuHdl));
+ mxTBLineStyle->set_sensitive(false);
+
+ mxTBLineColor->set_sensitive(false);
+}
+
+IMPL_LINK_NOARG(CellAppearancePropertyPanel, TbxCellBorderSelectHdl, const OString&, void)
+{
+ mxTBCellBorder->set_menu_item_active(SETBORDERSTYLE, !mxTBCellBorder->get_menu_item_active(SETBORDERSTYLE));
+}
+
+IMPL_LINK_NOARG(CellAppearancePropertyPanel, TbxCellBorderMenuHdl, const OString&, void)
+{
+ if (!mxTBCellBorder->get_menu_item_active(SETBORDERSTYLE))
+ return;
+ if (!mbCellBorderPopoverCreated)
+ {
+ mxCellBorderPopoverContainer->setPopover(std::make_unique<CellBorderStylePopup>(mxTBCellBorder.get(), SETBORDERSTYLE, GetBindings()->GetDispatcher()));
+ mbCellBorderPopoverCreated = true;
+ }
+ mxCellBorderPopoverContainer->getPopover()->GrabFocus();
+}
+
+IMPL_LINK_NOARG(CellAppearancePropertyPanel, TbxLineStyleSelectHdl, const OString&, void)
+{
+ mxTBLineStyle->set_menu_item_active(LINESTYLE, !mxTBLineStyle->get_menu_item_active(LINESTYLE));
+}
+
+IMPL_LINK_NOARG(CellAppearancePropertyPanel, TbxLineStyleMenuHdl, const OString&, void)
+{
+ if (!mxTBLineStyle->get_menu_item_active(LINESTYLE))
+ return;
+ if (!mbLinePopoverCreated)
+ {
+ mxLinePopoverContainer->setPopover(std::make_unique<CellLineStylePopup>(mxTBLineStyle.get(), LINESTYLE, GetBindings()->GetDispatcher()));
+ mbLinePopoverCreated = true;
+ }
+ auto pPopup = static_cast<CellLineStylePopup*>(mxLinePopoverContainer->getPopover());
+ pPopup->SetLineStyleSelect(mnOutWidth, mnInWidth, mnDistance);
+ pPopup->GrabFocus();
+}
+
+std::unique_ptr<PanelLayout> CellAppearancePropertyPanel::Create (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to CellAppearancePropertyPanel::Create", nullptr, 0);
+ if ( ! rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to CellAppearancePropertyPanel::Create", nullptr, 1);
+ if (pBindings == nullptr)
+ throw lang::IllegalArgumentException("no SfxBindings given to CellAppearancePropertyPanel::Create", nullptr, 2);
+
+ return std::make_unique<CellAppearancePropertyPanel>(pParent, rxFrame, pBindings);
+}
+
+void CellAppearancePropertyPanel::HandleContextChange(const vcl::EnumContext& rContext)
+{
+ if (maContext == rContext)
+ {
+ // Nothing to do.
+ return;
+ }
+
+ maContext = rContext;
+}
+
+void CellAppearancePropertyPanel::NotifyItemUpdate(
+ sal_uInt16 nSID,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ switch(nSID)
+ {
+ case SID_FRAME_LINESTYLE:
+ mbBorderStyleAvailable = false;
+ if( eState == SfxItemState::DONTCARE )
+ {
+ mbBorderStyleAvailable = true;
+ mnInWidth = 0;
+ mnOutWidth = 0;
+ mnDistance = 0;
+ }
+ else if(eState >= SfxItemState::DEFAULT)
+ {
+ const SvxLineItem* pSvxLineItem = dynamic_cast< const SvxLineItem* >(pState);
+ if(pSvxLineItem)
+ {
+ const editeng::SvxBorderLine* pLineItem = pSvxLineItem->GetLine();
+ mnInWidth = pLineItem->GetInWidth();
+ mnOutWidth = pLineItem->GetOutWidth();
+ mnDistance = pLineItem->GetDistance();
+ mbBorderStyleAvailable = !(mnInWidth == 0 && mnOutWidth == 0 && mnDistance == 0);
+ }
+ }
+ SetStyleIcon();
+ break;
+ case SID_ATTR_BORDER_OUTER:
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ const SvxBoxItem* pBoxItem = dynamic_cast< const SvxBoxItem* >(pState);
+
+ if(pBoxItem)
+ {
+ mbLeft=false;
+ mbRight=false;
+ mbTop=false;
+ mbBottom=false;
+
+ if(pBoxItem->GetLeft())
+ mbLeft = true;
+
+ if(pBoxItem->GetRight())
+ mbRight = true;
+
+ if(pBoxItem->GetTop())
+ mbTop = true;
+
+ if(pBoxItem->GetBottom())
+ mbBottom = true;
+
+ if(!AllSettings::GetLayoutRTL())
+ UpdateCellBorder(mbTop, mbBottom, mbLeft, mbRight, mbVer, mbHor, mbDiagTLBR, mbDiagBLTR);
+ else
+ UpdateCellBorder(mbTop, mbBottom, mbRight, mbLeft, mbVer, mbHor, mbDiagTLBR, mbDiagBLTR);
+
+ if(mbLeft || mbRight || mbTop || mbBottom)
+ mbOuterBorder = true;
+ else
+ mbOuterBorder = false;
+
+ UpdateControlState();
+ }
+ }
+ break;
+ case SID_ATTR_BORDER_INNER:
+ if(eState >= SfxItemState::DEFAULT)
+ {
+ const SvxBoxInfoItem* pBoxInfoItem = dynamic_cast< const SvxBoxInfoItem* >(pState);
+ if(pBoxInfoItem)
+ {
+ bool bLeft(false), bRight(false), bTop(false), bBottom(false);
+
+ mbVer = false;
+ mbHor = false;
+
+ if(!pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::VERT ) || pBoxInfoItem->GetVert())
+ mbVer = true;
+
+ if(!pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::HORI ) || pBoxInfoItem->GetHori())
+ mbHor = true;
+
+ if(!pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::LEFT ) || mbLeft)
+ bLeft = true;
+
+ if(!pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::RIGHT ) || mbRight)
+ bRight = true;
+
+ if(!pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::TOP ) || mbTop)
+ bTop = true;
+
+ if(!pBoxInfoItem->IsValid( SvxBoxInfoItemValidFlags::BOTTOM ) || mbBottom)
+ bBottom = true;
+
+ if(!AllSettings::GetLayoutRTL())
+ UpdateCellBorder(bTop, bBottom, bLeft, bRight, mbVer, mbHor, mbDiagTLBR, mbDiagBLTR);
+ else
+ UpdateCellBorder(bTop, bBottom, bRight, bLeft, mbVer, mbHor, mbDiagTLBR, mbDiagBLTR);
+
+ if(mbVer || mbHor || bLeft || bRight || bTop || bBottom)
+ mbInnerBorder = true;
+ else
+ mbInnerBorder = false;
+
+ UpdateControlState();
+ }
+ }
+ break;
+ case SID_ATTR_BORDER_DIAG_TLBR:
+ mbDiagTLBR = false;
+ if( eState == SfxItemState::DONTCARE )
+ {
+ mbDiagTLBR = true;
+ mnDiagTLBRInWidth = mnDiagTLBROutWidth = mnDiagTLBRDistance = 0;
+ }
+ else if(eState >= SfxItemState::DEFAULT)
+ {
+ const SvxLineItem* pItem = dynamic_cast< const SvxLineItem* >(pState);
+ if(pItem)
+ {
+ const editeng::SvxBorderLine* aLine = pItem->GetLine();
+ if(aLine)
+ {
+ mnDiagTLBRInWidth = aLine->GetInWidth();
+ mnDiagTLBROutWidth = aLine->GetOutWidth();
+ mnDiagTLBRDistance = aLine->GetDistance();
+
+ mbDiagTLBR = !(mnDiagTLBRInWidth == 0 && mnDiagTLBROutWidth == 0 && mnDiagTLBRDistance == 0);
+ }
+ }
+ }
+ UpdateCellBorder(mbTop, mbBottom, mbLeft, mbRight, mbVer, mbHor, mbDiagTLBR, mbDiagBLTR);
+ UpdateControlState();
+ break;
+ case SID_ATTR_BORDER_DIAG_BLTR:
+ mbDiagBLTR = false;
+ if( eState == SfxItemState::DONTCARE )
+ {
+ mbDiagBLTR = true;
+ mnDiagBLTRInWidth = mnDiagBLTROutWidth = mnDiagBLTRDistance = 0;
+ }
+ else if(eState >= SfxItemState::DEFAULT)
+ {
+ const SvxLineItem* pItem = dynamic_cast< const SvxLineItem* >(pState);
+ if(pItem)
+ {
+ const editeng::SvxBorderLine* aLine = pItem->GetLine();
+
+ if(aLine)
+ {
+ mnDiagBLTRInWidth = aLine->GetInWidth();
+ mnDiagBLTROutWidth = aLine->GetOutWidth();
+ mnDiagBLTRDistance = aLine->GetDistance();
+
+ mbDiagBLTR = !(mnDiagBLTRInWidth == 0 && mnDiagBLTROutWidth == 0 && mnDiagBLTRDistance == 0);
+ }
+ }
+ }
+ UpdateCellBorder(mbTop, mbBottom, mbLeft, mbRight, mbVer, mbHor, mbDiagTLBR, mbDiagBLTR);
+ UpdateControlState();
+ break;
+ }
+}
+
+void CellAppearancePropertyPanel::SetStyleIcon()
+{
+ //FIXME: update for new line border possibilities
+ if(mnOutWidth == SvxBorderLineWidth::Hairline && mnInWidth == 0 && mnDistance == 0) //1
+ mxTBLineStyle->set_item_icon_name(LINESTYLE, msIMGLineStyle1);
+ else if(mnOutWidth == SvxBorderLineWidth::Medium && mnInWidth == 0 && mnDistance == 0) //2
+ mxTBLineStyle->set_item_icon_name(LINESTYLE, msIMGLineStyle2);
+ else if(mnOutWidth == SvxBorderLineWidth::Thick && mnInWidth == 0 && mnDistance == 0) //3
+ mxTBLineStyle->set_item_icon_name(LINESTYLE, msIMGLineStyle3);
+ else if(mnOutWidth == SvxBorderLineWidth::ExtraThick && mnInWidth == 0 && mnDistance == 0) //4
+ mxTBLineStyle->set_item_icon_name(LINESTYLE, msIMGLineStyle4);
+ else if(mnOutWidth == SvxBorderLineWidth::Hairline && mnInWidth == SvxBorderLineWidth::Hairline && mnDistance == SvxBorderLineWidth::Thin) //5
+ mxTBLineStyle->set_item_icon_name(LINESTYLE, msIMGLineStyle5);
+ else if(mnOutWidth == SvxBorderLineWidth::Hairline && mnInWidth == SvxBorderLineWidth::Hairline && mnDistance == SvxBorderLineWidth::Medium) //6
+ mxTBLineStyle->set_item_icon_name(LINESTYLE, msIMGLineStyle6);
+ else if(mnOutWidth == SvxBorderLineWidth::Thin && mnInWidth == SvxBorderLineWidth::Medium && mnDistance == SvxBorderLineWidth::Thin) //7
+ mxTBLineStyle->set_item_icon_name(LINESTYLE, msIMGLineStyle7);
+ else if(mnOutWidth == SvxBorderLineWidth::Medium && mnInWidth == SvxBorderLineWidth::Hairline && mnDistance == SvxBorderLineWidth::Medium) //8
+ mxTBLineStyle->set_item_icon_name(LINESTYLE, msIMGLineStyle8);
+ else if(mnOutWidth == SvxBorderLineWidth::Medium && mnInWidth == SvxBorderLineWidth::Medium && mnDistance == SvxBorderLineWidth::Medium) //9
+ mxTBLineStyle->set_item_icon_name(LINESTYLE, msIMGLineStyle9);
+ else
+ mxTBLineStyle->set_item_icon_name(LINESTYLE, msIMGLineStyle1);
+}
+
+void CellAppearancePropertyPanel::UpdateControlState()
+{
+ if(mbOuterBorder || mbInnerBorder || mbDiagTLBR || mbDiagBLTR)
+ {
+ mxTBLineColor->set_sensitive(true);
+ mxTBLineStyle->set_sensitive(true);
+
+ //set line style state
+ if( mbBorderStyleAvailable && !mbDiagTLBR && !mbDiagBLTR )
+ {
+ }
+ else if( !mbBorderStyleAvailable && mbDiagTLBR && !mbDiagBLTR )
+ {
+ mnInWidth = mnDiagTLBRInWidth;
+ mnOutWidth = mnDiagTLBROutWidth;
+ mnDistance = mnDiagTLBRDistance;
+ }
+ else if ( !mbBorderStyleAvailable && !mbDiagTLBR && mbDiagBLTR )
+ {
+ mnInWidth = mnDiagBLTRInWidth;
+ mnOutWidth = mnDiagBLTROutWidth;
+ mnDistance = mnDiagBLTRDistance;
+ }
+ else if( !mbBorderStyleAvailable && mbDiagTLBR && mbDiagBLTR)
+ {
+ if( mnDiagTLBRInWidth == mnDiagBLTRInWidth && mnDiagTLBROutWidth == mnDiagBLTROutWidth && mnDiagTLBRDistance == mnDiagBLTRDistance)
+ {
+ mnInWidth = mnDiagTLBRInWidth;
+ mnOutWidth = mnDiagTLBROutWidth;
+ mnDistance = mnDiagTLBRDistance;
+ }
+ else
+ {
+ mnInWidth = 0;
+ mnOutWidth = 0;
+ mnDistance = 0;
+ }
+ }
+ else if( mbBorderStyleAvailable && mbDiagTLBR && !mbDiagBLTR )
+ {
+ if( mnDiagTLBRInWidth != mnInWidth || mnDiagTLBROutWidth != mnOutWidth || mnDiagTLBRDistance != mnDistance)
+ {
+ mnInWidth = 0;
+ mnOutWidth = 0;
+ mnDistance = 0;
+ }
+ }
+ else if( mbBorderStyleAvailable && !mbDiagTLBR && mbDiagBLTR )
+ {
+ if( mnDiagBLTRInWidth != mnInWidth || mnDiagBLTROutWidth != mnOutWidth || mnDiagBLTRDistance != mnDistance )
+ {
+ mnInWidth = 0;
+ mnOutWidth = 0;
+ mnDistance = 0;
+ }
+ }
+ else
+ {
+ mnInWidth = 0;
+ mnOutWidth = 0;
+ mnDistance = 0;
+ }
+ SetStyleIcon();
+ }
+ else
+ {
+ mxTBLineColor->set_sensitive(false);
+ mxTBLineStyle->set_sensitive(false);
+ }
+}
+
+void CellAppearancePropertyPanel::UpdateCellBorder(bool bTop, bool bBot, bool bLeft, bool bRight,
+ bool bVer, bool bHor, bool bTLBR, bool bBLTR)
+{
+ const Size aBmpSize = maIMGCellBorder.GetBitmapEx().GetSizePixel();
+
+ if (aBmpSize.Width() == 43 && aBmpSize.Height() == 43)
+ {
+ ScopedVclPtr<VirtualDevice> pVirDev(mxTBCellBorder->create_virtual_device());
+ pVirDev->SetOutputSizePixel(aBmpSize);
+ pVirDev->SetLineColor( ::Application::GetSettings().GetStyleSettings().GetFieldTextColor() ) ;
+ pVirDev->SetFillColor(COL_BLACK);
+ pVirDev->DrawImage(Point(0, 0), maIMGCellBorder);
+ Point aTL(2, 1), aTR(42,1), aBL(2, 41), aBR(42, 41), aHL(2,21), aHR(42, 21), aVT(22,1), aVB(22, 41);
+ if(bLeft)
+ pVirDev->DrawLine( aTL,aBL );
+ if(bRight)
+ pVirDev->DrawLine( aTR,aBR );
+ if(bTop)
+ pVirDev->DrawLine( aTL,aTR );
+ if(bBot)
+ pVirDev->DrawLine( aBL,aBR );
+ if(bVer)
+ pVirDev->DrawLine( aVT,aVB );
+ if(bHor)
+ pVirDev->DrawLine( aHL,aHR );
+ if(bTLBR)
+ pVirDev->DrawLine( aTL,aBR );
+ if(bBLTR)
+ pVirDev->DrawLine( aBL,aTR );
+ mxTBCellBorder->set_item_image(SETBORDERSTYLE, pVirDev);
+ }
+ else
+ mxTBCellBorder->set_item_icon_name(SETBORDERSTYLE, msIMGCellBorder);
+}
+// namespace close
+
+} // end of namespace ::sc::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/CellAppearancePropertyPanel.hxx b/sc/source/ui/sidebar/CellAppearancePropertyPanel.hxx
new file mode 100644
index 000000000..412cd37e1
--- /dev/null
+++ b/sc/source/ui/sidebar/CellAppearancePropertyPanel.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 <sfx2/sidebar/ControllerItem.hxx>
+#include <sfx2/sidebar/IContextChangeReceiver.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <vcl/EnumContext.hxx>
+#include <vcl/image.hxx>
+#include <com/sun/star/frame/XFrame.hpp>
+
+class ToolbarUnoDispatcher;
+class ToolbarPopupContainer;
+
+namespace sc::sidebar {
+
+class CellAppearancePropertyPanel
+: public PanelLayout,
+ public ::sfx2::sidebar::IContextChangeReceiver,
+ public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+private:
+ friend class CellLineStylePopup;
+ friend class CellBorderStylePopup;
+
+public:
+ static std::unique_ptr<PanelLayout> Create(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings);
+
+ virtual void HandleContextChange(
+ const vcl::EnumContext& rContext) override;
+
+ virtual void NotifyItemUpdate(
+ const sal_uInt16 nSId,
+ const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void GetControlState(
+ const sal_uInt16 /*nSId*/,
+ boost::property_tree::ptree& /*rState*/) override {};
+
+ SfxBindings* GetBindings() { return mpBindings;}
+
+ // constructor/destructor
+ CellAppearancePropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings);
+ virtual ~CellAppearancePropertyPanel() override;
+
+private:
+ //ui controls
+
+ std::unique_ptr<ToolbarPopupContainer> mxCellBorderPopoverContainer;
+ std::unique_ptr<weld::Toolbar> mxTBCellBorder;
+ std::unique_ptr<weld::Toolbar> mxTBCellBackground;
+ std::unique_ptr<ToolbarUnoDispatcher> mxBackColorDispatch;
+ std::unique_ptr<ToolbarPopupContainer> mxLinePopoverContainer;
+ std::unique_ptr<weld::Toolbar> mxTBLineStyle;
+ std::unique_ptr<weld::Toolbar> mxTBLineColor;
+ std::unique_ptr<ToolbarUnoDispatcher> mxLineColorDispatch;
+
+ bool mbCellBorderPopoverCreated;
+ bool mbLinePopoverCreated;
+
+ ::sfx2::sidebar::ControllerItem maLineStyleControl;
+ ::sfx2::sidebar::ControllerItem maBorderOuterControl;
+ ::sfx2::sidebar::ControllerItem maBorderInnerControl;
+ ::sfx2::sidebar::ControllerItem maGridShowControl;
+ ::sfx2::sidebar::ControllerItem maBorderTLBRControl;
+ ::sfx2::sidebar::ControllerItem maBorderBLTRControl;
+
+ // images
+ Image maIMGCellBorder;
+ OUString msIMGCellBorder;
+ OUString msIMGLineStyle1;
+ OUString msIMGLineStyle2;
+ OUString msIMGLineStyle3;
+ OUString msIMGLineStyle4;
+ OUString msIMGLineStyle5;
+ OUString msIMGLineStyle6;
+ OUString msIMGLineStyle7;
+ OUString msIMGLineStyle8;
+ OUString msIMGLineStyle9;
+
+ // BorderStyle defines
+ sal_uInt16 mnInWidth;
+ sal_uInt16 mnOutWidth;
+ sal_uInt16 mnDistance;
+ sal_uInt16 mnDiagTLBRInWidth;
+ sal_uInt16 mnDiagTLBROutWidth;
+ sal_uInt16 mnDiagTLBRDistance;
+ sal_uInt16 mnDiagBLTRInWidth;
+ sal_uInt16 mnDiagBLTROutWidth;
+ sal_uInt16 mnDiagBLTRDistance;
+
+ bool mbBorderStyleAvailable : 1;
+
+ // CellBorder defines
+ bool mbLeft : 1;
+ bool mbRight : 1;
+ bool mbTop : 1;
+ bool mbBottom : 1;
+ bool mbVer : 1;
+ bool mbHor : 1;
+
+ bool mbOuterBorder : 1; // mbLeft || mbRight || mbTop || mbBottom
+ bool mbInnerBorder : 1; // mbVer || mbHor || bLeft || bRight || bTop || bBottom
+
+ bool mbDiagTLBR : 1;
+ bool mbDiagBLTR : 1;
+
+ vcl::EnumContext maContext;
+ SfxBindings* mpBindings;
+
+ DECL_LINK(TbxCellBorderSelectHdl, const OString&, void);
+ DECL_LINK(TbxCellBorderMenuHdl, const OString&, void);
+ DECL_LINK(TbxLineStyleSelectHdl, const OString&, void);
+ DECL_LINK(TbxLineStyleMenuHdl, const OString&, void);
+
+ void Initialize();
+ void SetStyleIcon();
+ void UpdateControlState();
+ void UpdateCellBorder(bool bTop, bool bBot, bool bLeft, bool bRight, bool bVer, bool bHor, bool bTLBR, bool bBLTR);
+};
+
+} // end of namespace ::sc::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/CellBorderStyleControl.cxx b/sc/source/ui/sidebar/CellBorderStyleControl.cxx
new file mode 100644
index 000000000..6749588b9
--- /dev/null
+++ b/sc/source/ui/sidebar/CellBorderStyleControl.cxx
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "CellBorderStyleControl.hxx"
+#include <editeng/boxitem.hxx>
+#include <editeng/borderline.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svxids.hrc>
+#include <vcl/settings.hxx>
+#include <editeng/lineitem.hxx>
+#include <memory>
+
+namespace sc::sidebar {
+
+#define FRM_VALID_LEFT 0x01
+#define FRM_VALID_RIGHT 0x02
+#define FRM_VALID_TOP 0x04
+#define FRM_VALID_BOTTOM 0x08
+#define FRM_VALID_HINNER 0x10
+#define FRM_VALID_VINNER 0x20
+#define FRM_VALID_OUTER 0x0f
+#define FRM_VALID_ALL 0xff
+
+CellBorderStylePopup::CellBorderStylePopup(weld::Toolbar* pParent, const OString& rId, SfxDispatcher* pDispatcher)
+ : WeldToolbarPopup(nullptr, pParent, "modules/scalc/ui/floatingborderstyle.ui", "FloatingBorderStyle")
+ , maToolButton(pParent, rId)
+ , mpDispatcher(pDispatcher)
+ , mxTBBorder1(m_xBuilder->weld_toolbar("border1"))
+ , mxTBBorder2(m_xBuilder->weld_toolbar("border2"))
+ , mxTBBorder3(m_xBuilder->weld_toolbar("border3"))
+ , mxTBBorder4(m_xBuilder->weld_toolbar("border4"))
+{
+ Initialize();
+}
+
+void CellBorderStylePopup::GrabFocus()
+{
+ mxTBBorder1->grab_focus();
+}
+
+CellBorderStylePopup::~CellBorderStylePopup()
+{
+}
+
+void CellBorderStylePopup::Initialize()
+{
+ mxTBBorder1->connect_clicked ( LINK(this, CellBorderStylePopup, TB1SelectHdl) );
+
+ mxTBBorder2->connect_clicked ( LINK(this, CellBorderStylePopup, TB2and3SelectHdl) );
+ mxTBBorder3->connect_clicked ( LINK(this, CellBorderStylePopup, TB2and3SelectHdl) );
+
+ mxTBBorder4->connect_clicked ( LINK(this, CellBorderStylePopup, TB4SelectHdl) );
+}
+
+IMPL_LINK(CellBorderStylePopup, TB1SelectHdl, const OString&, rId, void)
+{
+ SvxBoxItem aBorderOuter( SID_ATTR_BORDER_OUTER );
+ SvxBoxInfoItem aBorderInner( SID_ATTR_BORDER_INNER );
+ editeng::SvxBorderLine theDefLine(nullptr, SvxBorderLineWidth::Thin);
+ editeng::SvxBorderLine *pLeft = nullptr, *pRight = nullptr, *pTop = nullptr, *pBottom = nullptr;
+ sal_uInt8 nValidFlags = 0;
+
+ if (rId == "none")
+ {
+ nValidFlags |= FRM_VALID_ALL;
+ SvxLineItem aLineItem1( SID_ATTR_BORDER_DIAG_BLTR );
+ SvxLineItem aLineItem2( SID_ATTR_BORDER_DIAG_TLBR );
+ aLineItem1.SetLine( nullptr ); //modify
+ aLineItem2.SetLine( nullptr ); //modify
+ mpDispatcher->ExecuteList(
+ SID_ATTR_BORDER_DIAG_BLTR, SfxCallMode::RECORD, { &aLineItem1 });
+ mpDispatcher->ExecuteList(
+ SID_ATTR_BORDER_DIAG_TLBR, SfxCallMode::RECORD, { &aLineItem2 });
+ }
+ else if (rId == "all")
+ {
+ pLeft = pRight = pTop = pBottom = &theDefLine;
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::HORI );
+ aBorderInner.SetLine( &theDefLine, SvxBoxInfoItemLine::VERT );
+ nValidFlags |= FRM_VALID_ALL;
+ }
+ else if (rId == "outside")
+ {
+ pLeft = pRight = pTop = pBottom = &theDefLine;
+ nValidFlags |= FRM_VALID_OUTER;
+ }
+ else if (rId == "thickbox")
+ {
+ theDefLine.SetWidth(SvxBorderLineWidth::Thick);
+ pLeft = pRight = pTop = pBottom = &theDefLine;
+ nValidFlags |= FRM_VALID_OUTER;
+ }
+
+ aBorderOuter.SetLine( pLeft, SvxBoxItemLine::LEFT );
+ aBorderOuter.SetLine( pRight, SvxBoxItemLine::RIGHT );
+ aBorderOuter.SetLine( pTop, SvxBoxItemLine::TOP );
+ aBorderOuter.SetLine( pBottom, SvxBoxItemLine::BOTTOM );
+
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::TOP, 0 != (nValidFlags&FRM_VALID_TOP ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, 0 != (nValidFlags&FRM_VALID_BOTTOM ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, 0 != (nValidFlags&FRM_VALID_LEFT));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, 0 != (nValidFlags&FRM_VALID_RIGHT ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::HORI, 0 != (nValidFlags&FRM_VALID_HINNER ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::VERT, 0 != (nValidFlags&FRM_VALID_VINNER));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE );
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISABLE, false );
+
+ mpDispatcher->ExecuteList(
+ SID_ATTR_BORDER, SfxCallMode::RECORD, { &aBorderOuter, &aBorderInner });
+
+ maToolButton.set_inactive();
+}
+
+IMPL_LINK(CellBorderStylePopup, TB2and3SelectHdl, const OString&, rId, void)
+{
+ if (rId == "diagup")
+ {
+ editeng::SvxBorderLine aTmp( nullptr, SvxBorderLineWidth::Thin );
+ SvxLineItem aLineItem( SID_ATTR_BORDER_DIAG_BLTR );
+ aLineItem.SetLine( &aTmp );
+ mpDispatcher->ExecuteList(
+ SID_ATTR_BORDER_DIAG_BLTR, SfxCallMode::RECORD, { &aLineItem });
+ }
+ else if (rId == "diagdown")
+ {
+ editeng::SvxBorderLine aTmp( nullptr, SvxBorderLineWidth::Thin );
+ SvxLineItem aLineItem( SID_ATTR_BORDER_DIAG_TLBR );
+ aLineItem.SetLine( &aTmp );
+ mpDispatcher->ExecuteList(
+ SID_ATTR_BORDER_DIAG_TLBR, SfxCallMode::RECORD, { &aLineItem });
+ }
+ else
+ {
+ SvxBoxItem aBorderOuter( SID_ATTR_BORDER_OUTER );
+ SvxBoxInfoItem aBorderInner( SID_ATTR_BORDER_INNER );
+ editeng::SvxBorderLine theDefLine(nullptr, SvxBorderLineWidth::Thin);
+ editeng::SvxBorderLine *pLeft = nullptr,
+ *pRight = nullptr,
+ *pTop = nullptr,
+ *pBottom = nullptr;
+ sal_uInt8 nValidFlags = 0;
+ if (rId == "left")
+ {
+ pLeft = &theDefLine;
+ nValidFlags |= FRM_VALID_LEFT;
+ }
+ else if (rId == "right")
+ {
+ if(!AllSettings::GetLayoutRTL())
+ {
+ pRight = &theDefLine;
+ nValidFlags |= FRM_VALID_RIGHT;
+ }
+ else
+ {
+ pLeft = &theDefLine;
+ nValidFlags |= FRM_VALID_LEFT;
+ }
+ }
+ else if (rId == "top")
+ {
+ pTop = &theDefLine;
+ nValidFlags |= FRM_VALID_TOP;
+ }
+ else if (rId == "bottom")
+ {
+ pBottom = &theDefLine;
+ nValidFlags |= FRM_VALID_BOTTOM;
+ }
+ else if (rId == "topbottom")
+ {
+ pTop = pBottom = &theDefLine;
+ nValidFlags |= FRM_VALID_BOTTOM|FRM_VALID_TOP;
+ }
+ else if (rId == "leftright")
+ {
+ pLeft = pRight = &theDefLine;
+ nValidFlags |= FRM_VALID_RIGHT|FRM_VALID_LEFT;
+ }
+ aBorderOuter.SetLine( pLeft, SvxBoxItemLine::LEFT );
+ aBorderOuter.SetLine( pRight, SvxBoxItemLine::RIGHT );
+ aBorderOuter.SetLine( pTop, SvxBoxItemLine::TOP );
+ aBorderOuter.SetLine( pBottom, SvxBoxItemLine::BOTTOM );
+
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::TOP, 0 != (nValidFlags&FRM_VALID_TOP ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, 0 != (nValidFlags&FRM_VALID_BOTTOM ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, 0 != (nValidFlags&FRM_VALID_LEFT));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, 0 != (nValidFlags&FRM_VALID_RIGHT ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::HORI, 0 != (nValidFlags&FRM_VALID_HINNER ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::VERT, 0 != (nValidFlags&FRM_VALID_VINNER));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE );
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISABLE, false );
+
+ mpDispatcher->ExecuteList(
+ SID_ATTR_BORDER, SfxCallMode::RECORD, { &aBorderOuter, &aBorderInner});
+ }
+
+ maToolButton.set_inactive();
+}
+
+IMPL_LINK(CellBorderStylePopup, TB4SelectHdl, const OString&, rId, void)
+{
+ SvxBoxItem aBorderOuter( SID_ATTR_BORDER_OUTER );
+ SvxBoxInfoItem aBorderInner( SID_ATTR_BORDER_INNER );
+ std::unique_ptr<editeng::SvxBorderLine> pTop;
+ std::unique_ptr<editeng::SvxBorderLine> pBottom;
+ sal_uInt8 nValidFlags = 0;
+ using namespace ::com::sun::star::table::BorderLineStyle;
+
+ //FIXME: properly adapt to new line border model
+
+ if (rId == "thickbottom")
+ {
+ pBottom.reset(new editeng::SvxBorderLine(nullptr, SvxBorderLineWidth::Thick));
+ nValidFlags |= FRM_VALID_BOTTOM;
+ }
+ else if (rId == "doublebottom")
+ {
+ pBottom.reset(new editeng::SvxBorderLine(nullptr));
+ pBottom->GuessLinesWidths(SvxBorderLineStyle::DOUBLE, SvxBorderLineWidth::Hairline,
+ SvxBorderLineWidth::Hairline, SvxBorderLineWidth::Thin);
+ nValidFlags |= FRM_VALID_BOTTOM;
+ }
+ else if (rId == "topthickbottom")
+ {
+ pBottom.reset(new editeng::SvxBorderLine(nullptr, SvxBorderLineWidth::Thick));
+ pTop.reset(new editeng::SvxBorderLine(nullptr, SvxBorderLineWidth::Thin));
+ nValidFlags |= FRM_VALID_BOTTOM|FRM_VALID_TOP;
+ }
+ else if (rId == "topdoublebottom")
+ {
+ pBottom.reset(new editeng::SvxBorderLine(nullptr));
+ pBottom->GuessLinesWidths(SvxBorderLineStyle::DOUBLE, SvxBorderLineWidth::Hairline,
+ SvxBorderLineWidth::Hairline, SvxBorderLineWidth::Thin);
+ pTop.reset(new editeng::SvxBorderLine(nullptr, SvxBorderLineWidth::Thin));
+ nValidFlags |= FRM_VALID_BOTTOM|FRM_VALID_TOP;
+ }
+
+ aBorderOuter.SetLine( pTop.get(), SvxBoxItemLine::TOP );
+ aBorderOuter.SetLine( pBottom.get(), SvxBoxItemLine::BOTTOM );
+ aBorderOuter.SetLine( nullptr, SvxBoxItemLine::LEFT );
+ aBorderOuter.SetLine( nullptr, SvxBoxItemLine::RIGHT );
+
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::TOP, 0 != (nValidFlags&FRM_VALID_TOP ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, 0 != (nValidFlags&FRM_VALID_BOTTOM ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, 0 != (nValidFlags&FRM_VALID_LEFT ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, 0 != (nValidFlags&FRM_VALID_RIGHT ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::HORI, 0 != (nValidFlags&FRM_VALID_HINNER ));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::VERT, 0 != (nValidFlags&FRM_VALID_VINNER));
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE );
+ aBorderInner.SetValid( SvxBoxInfoItemValidFlags::DISABLE, false );
+
+ mpDispatcher->ExecuteList(
+ SID_ATTR_BORDER, SfxCallMode::RECORD, { &aBorderOuter, &aBorderInner });
+
+ pTop.reset();
+ pBottom.reset();
+
+ maToolButton.set_inactive();
+}
+
+} // end of namespace sc::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/CellBorderStyleControl.hxx b/sc/source/ui/sidebar/CellBorderStyleControl.hxx
new file mode 100644
index 000000000..f6ae6891b
--- /dev/null
+++ b/sc/source/ui/sidebar/CellBorderStyleControl.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 <svtools/toolbarmenu.hxx>
+#include <svx/colorwindow.hxx>
+
+class SfxDispatcher;
+
+namespace sc::sidebar
+{
+class CellBorderStylePopup : public WeldToolbarPopup
+{
+private:
+ MenuOrToolMenuButton maToolButton;
+ SfxDispatcher* mpDispatcher;
+ std::unique_ptr<weld::Toolbar> mxTBBorder1;
+ std::unique_ptr<weld::Toolbar> mxTBBorder2;
+ std::unique_ptr<weld::Toolbar> mxTBBorder3;
+ std::unique_ptr<weld::Toolbar> mxTBBorder4;
+
+ void Initialize();
+
+ DECL_LINK(TB1SelectHdl, const OString&, void);
+ DECL_LINK(TB2and3SelectHdl, const OString&, void);
+ DECL_LINK(TB4SelectHdl, const OString&, void);
+
+public:
+ CellBorderStylePopup(weld::Toolbar* pParent, const OString& rId, SfxDispatcher* pDispatcher);
+ virtual void GrabFocus() override;
+ virtual ~CellBorderStylePopup() override;
+};
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/CellLineStyleControl.cxx b/sc/source/ui/sidebar/CellLineStyleControl.cxx
new file mode 100644
index 000000000..5c27ee5a5
--- /dev/null
+++ b/sc/source/ui/sidebar/CellLineStyleControl.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 "CellLineStyleControl.hxx"
+#include "CellLineStyleValueSet.hxx"
+#include <vcl/i18nhelp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/lineitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svx/svxids.hrc>
+#include <scresid.hxx>
+#include <strings.hrc>
+
+namespace sc::sidebar {
+
+CellLineStylePopup::CellLineStylePopup(weld::Toolbar* pParent, const OString& rId, SfxDispatcher* pDispatcher)
+ : WeldToolbarPopup(nullptr, pParent, "modules/scalc/ui/floatinglinestyle.ui", "FloatingLineStyle")
+ , maToolButton(pParent, rId)
+ , mpDispatcher(pDispatcher)
+ , mxCellLineStyleValueSet(new sc::sidebar::CellLineStyleValueSet)
+ , mxCellLineStyleValueSetWin(new weld::CustomWeld(*m_xBuilder, "linestylevalueset", *mxCellLineStyleValueSet))
+ , mxPushButtonMoreOptions(m_xBuilder->weld_button("more"))
+{
+ Initialize();
+}
+
+CellLineStylePopup::~CellLineStylePopup()
+{
+}
+
+void CellLineStylePopup::Initialize()
+{
+ mxPushButtonMoreOptions->connect_clicked(LINK(this, CellLineStylePopup, PBClickHdl));
+
+ mxCellLineStyleValueSet->SetStyle(mxCellLineStyleValueSet->GetStyle()| WB_3DLOOK | WB_NO_DIRECTSELECT);
+
+ for(sal_uInt16 i = 1 ; i <= CELL_LINE_STYLE_ENTRIES ; i++)
+ {
+ mxCellLineStyleValueSet->InsertItem(i);
+ }
+
+ const vcl::I18nHelper& rI18nHelper = Application::GetSettings().GetLocaleI18nHelper();
+ maStr[0] = ScResId(STR_BORDER_HAIRLINE).replaceFirst("%s", rI18nHelper.GetNum(5, 2));
+ maStr[1] = ScResId(STR_BORDER_VERY_THIN).replaceFirst("%s", rI18nHelper.GetNum(50, 2));
+ maStr[2] = ScResId(STR_BORDER_THIN).replaceFirst("%s", rI18nHelper.GetNum(75, 2));
+ maStr[3] = ScResId(STR_BORDER_MEDIUM).replaceFirst("%s", rI18nHelper.GetNum(150, 2));
+ maStr[4] = ScResId(STR_BORDER_THICK).replaceFirst("%s", rI18nHelper.GetNum(225, 2));
+ maStr[5] = ScResId(STR_BORDER_EXTRA_THICK).replaceFirst("%s", rI18nHelper.GetNum(450, 2));
+
+ // Numbers in pt are the total width of the double line (inner + outer + distance)
+ maStr[6] = ScResId(STR_BORDER_DOUBLE_1).replaceFirst("%s", rI18nHelper.GetNum(110, 2));
+ maStr[7] = ScResId(STR_BORDER_DOUBLE_1).replaceFirst("%s", rI18nHelper.GetNum(235, 2));
+ maStr[8] = ScResId(STR_BORDER_DOUBLE_2).replaceFirst("%s", rI18nHelper.GetNum(300, 2));
+ maStr[9] = ScResId(STR_BORDER_DOUBLE_3).replaceFirst("%s", rI18nHelper.GetNum(305, 2));
+ maStr[10] = ScResId(STR_BORDER_DOUBLE_4).replaceFirst("%s", rI18nHelper.GetNum(450, 2));
+ mxCellLineStyleValueSet->SetUnit(&maStr[0]);
+
+ for (sal_uInt16 i = 1; i <= CELL_LINE_STYLE_ENTRIES; ++i)
+ {
+ mxCellLineStyleValueSet->SetItemText(i, maStr[i-1]);
+ }
+
+ SetAllNoSel();
+ mxCellLineStyleValueSet->SetSelectHdl(LINK(this, CellLineStylePopup, VSSelectHdl));
+}
+
+void CellLineStylePopup::GrabFocus()
+{
+ mxCellLineStyleValueSet->GrabFocus();
+}
+
+void CellLineStylePopup::SetAllNoSel()
+{
+ mxCellLineStyleValueSet->SelectItem(0);
+ mxCellLineStyleValueSet->SetNoSelection();
+ mxCellLineStyleValueSet->SetFormat();
+ mxCellLineStyleValueSet->Invalidate();
+}
+
+IMPL_LINK_NOARG(CellLineStylePopup, VSSelectHdl, ValueSet*, void)
+{
+ const sal_uInt16 iPos(mxCellLineStyleValueSet->GetSelectedItemId());
+ SvxLineItem aLineItem(SID_FRAME_LINESTYLE);
+ SvxBorderLineStyle nStyle = SvxBorderLineStyle::SOLID;
+ sal_uInt16 n1 = 0;
+ sal_uInt16 n2 = 0;
+ sal_uInt16 n3 = 0;
+
+ //FIXME: fully for new border line possibilities
+
+ switch(iPos)
+ {
+ case 1:
+ n1 = SvxBorderLineWidth::Hairline;
+ break;
+ case 2:
+ n1 = SvxBorderLineWidth::VeryThin;
+ break;
+ case 3:
+ n1 = SvxBorderLineWidth::Thin;
+ break;
+ case 4:
+ n1 = SvxBorderLineWidth::Medium;
+ break;
+ case 5:
+ n1 = SvxBorderLineWidth::Thick;
+ break;
+ case 6:
+ n1 = SvxBorderLineWidth::ExtraThick;
+ break;
+ case 7:
+ n1 = SvxBorderLineWidth::Hairline;
+ n2 = SvxBorderLineWidth::Hairline;
+ n3 = SvxBorderLineWidth::Medium;
+ nStyle = SvxBorderLineStyle::DOUBLE;
+ break;
+ case 8:
+ n1 = SvxBorderLineWidth::Hairline;
+ n2 = SvxBorderLineWidth::Hairline;
+ n3 = SvxBorderLineWidth::Thick;
+ nStyle = SvxBorderLineStyle::DOUBLE;
+ break;
+ case 9:
+ n1 = SvxBorderLineWidth::Thin;
+ n2 = SvxBorderLineWidth::Medium;
+ n3 = SvxBorderLineWidth::Thin;
+ nStyle = SvxBorderLineStyle::DOUBLE;
+ break;
+ case 10:
+ n1 = SvxBorderLineWidth::Medium;
+ n2 = SvxBorderLineWidth::Hairline;
+ n3 = SvxBorderLineWidth::Medium;
+ nStyle = SvxBorderLineStyle::DOUBLE;
+ break;
+ case 11:
+ n1 = SvxBorderLineWidth::Medium;
+ n2 = SvxBorderLineWidth::Medium;
+ n3 = SvxBorderLineWidth::Medium;
+ nStyle = SvxBorderLineStyle::DOUBLE;
+ break;
+ default:
+ break;
+ }
+
+ editeng::SvxBorderLine aTmp;
+ aTmp.GuessLinesWidths(nStyle, n1, n2, n3);
+ aLineItem.SetLine( &aTmp );
+ mpDispatcher->ExecuteList(
+ SID_FRAME_LINESTYLE, SfxCallMode::RECORD, { &aLineItem });
+ SetAllNoSel();
+
+ maToolButton.set_inactive();
+}
+
+IMPL_LINK_NOARG(CellLineStylePopup, PBClickHdl, weld::Button&, void)
+{
+ mpDispatcher->Execute(SID_CELL_FORMAT_BORDER, SfxCallMode::ASYNCHRON);
+ maToolButton.set_inactive();
+}
+
+void CellLineStylePopup::SetLineStyleSelect(sal_uInt16 out, sal_uInt16 in, sal_uInt16 dis)
+{
+ mxCellLineStyleValueSet->GrabFocus();
+ SetAllNoSel();
+
+ //FIXME: fully for new border line possibilities
+
+ if(out == SvxBorderLineWidth::Hairline && in == 0 && dis == 0) //1
+ {
+ mxCellLineStyleValueSet->SetSelItem(1);
+ }
+ else if(out == SvxBorderLineWidth::VeryThin && in == 0 && dis == 0) //2
+ {
+ mxCellLineStyleValueSet->SetSelItem(2);
+ }
+ else if(out == SvxBorderLineWidth::Thin && in == 0 && dis == 0) //3
+ {
+ mxCellLineStyleValueSet->SetSelItem(3);
+ }
+ else if(out == SvxBorderLineWidth::Medium && in == 0 && dis == 0) //4
+ {
+ mxCellLineStyleValueSet->SetSelItem(4);
+ }
+ else if(out == SvxBorderLineWidth::Thick && in == 0 && dis == 0) //5
+ {
+ mxCellLineStyleValueSet->SetSelItem(5);
+ }
+ else if(out == SvxBorderLineWidth::ExtraThick && in == 0 && dis == 0) //6
+ {
+ mxCellLineStyleValueSet->SetSelItem(6);
+ }
+ else if(out == SvxBorderLineWidth::Hairline && in == SvxBorderLineWidth::Hairline && dis == SvxBorderLineWidth::Thin) //7
+ {
+ mxCellLineStyleValueSet->SetSelItem(7);
+ }
+ else if(out == SvxBorderLineWidth::Hairline && in == SvxBorderLineWidth::Hairline && dis == SvxBorderLineWidth::Medium) //8
+ {
+ mxCellLineStyleValueSet->SetSelItem(8);
+ }
+ else if(out == SvxBorderLineWidth::Thin && in == SvxBorderLineWidth::Medium && dis == SvxBorderLineWidth::Thin) //9
+ {
+ mxCellLineStyleValueSet->SetSelItem(9);
+ }
+ else if(out == SvxBorderLineWidth::Medium && in == SvxBorderLineWidth::Hairline && dis == SvxBorderLineWidth::Medium) //10
+ {
+ mxCellLineStyleValueSet->SetSelItem(10);
+ }
+ else if(out == SvxBorderLineWidth::Medium && in == SvxBorderLineWidth::Medium && dis == SvxBorderLineWidth::Medium) //11
+ {
+ mxCellLineStyleValueSet->SetSelItem(11);
+ }
+
+ else
+ {
+ mxCellLineStyleValueSet->SetSelItem(0);
+ mxPushButtonMoreOptions->grab_focus();
+ }
+ mxCellLineStyleValueSet->SetFormat();
+ mxCellLineStyleValueSet->Invalidate();
+}
+
+} // end of namespace sc::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/CellLineStyleControl.hxx b/sc/source/ui/sidebar/CellLineStyleControl.hxx
new file mode 100644
index 000000000..8bb9ba89c
--- /dev/null
+++ b/sc/source/ui/sidebar/CellLineStyleControl.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 <svtools/toolbarmenu.hxx>
+#include <svx/colorwindow.hxx>
+#include "CellLineStyleValueSet.hxx"
+
+class SfxDispatcher;
+
+namespace sc::sidebar
+{
+class CellLineStylePopup : public WeldToolbarPopup
+{
+private:
+ MenuOrToolMenuButton maToolButton;
+ SfxDispatcher* mpDispatcher;
+ std::unique_ptr<CellLineStyleValueSet> mxCellLineStyleValueSet;
+ std::unique_ptr<weld::CustomWeld> mxCellLineStyleValueSetWin;
+ std::unique_ptr<weld::Button> mxPushButtonMoreOptions;
+ OUString maStr[CELL_LINE_STYLE_ENTRIES];
+
+ void Initialize();
+ void SetAllNoSel();
+
+ DECL_LINK(VSSelectHdl, ValueSet*, void);
+ DECL_LINK(PBClickHdl, weld::Button&, void);
+
+public:
+ CellLineStylePopup(weld::Toolbar* pParent, const OString& rId, SfxDispatcher* pDispatcher);
+ void SetLineStyleSelect(sal_uInt16 out, sal_uInt16 in, sal_uInt16 dis);
+ virtual void GrabFocus() override;
+ virtual ~CellLineStylePopup() override;
+};
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/CellLineStyleValueSet.cxx b/sc/source/ui/sidebar/CellLineStyleValueSet.cxx
new file mode 100644
index 000000000..d7c9e9b3c
--- /dev/null
+++ b/sc/source/ui/sidebar/CellLineStyleValueSet.cxx
@@ -0,0 +1,187 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "CellLineStyleValueSet.hxx"
+#include <i18nlangtag/mslangid.hxx>
+#include <vcl/event.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+
+namespace sc::sidebar {
+
+CellLineStyleValueSet::CellLineStyleValueSet()
+ : ValueSet(nullptr)
+ , mnMaxTextWidth(0)
+ , nSelItem(0)
+{
+}
+
+CellLineStyleValueSet::~CellLineStyleValueSet()
+{
+}
+
+void CellLineStyleValueSet::SetDrawingArea(weld::DrawingArea* pDrawingArea)
+{
+ ValueSet::SetDrawingArea(pDrawingArea);
+ Size aSize = pDrawingArea->get_ref_device().LogicToPixel(Size(120, 12 * CELL_LINE_STYLE_ENTRIES),
+ MapMode(MapUnit::MapAppFont));
+ pDrawingArea->set_size_request(aSize.Width(), aSize.Height());
+ SetOutputSizePixel(aSize);
+
+ SetColCount();
+ SetLineCount(CELL_LINE_STYLE_ENTRIES);
+}
+
+void CellLineStyleValueSet::SetUnit(const OUString* str)
+{
+ for (int i = 0; i < CELL_LINE_STYLE_ENTRIES; ++i)
+ {
+ maStrUnit[i] = str[i];
+ }
+}
+
+void CellLineStyleValueSet::SetSelItem(sal_uInt16 nSel)
+{
+ nSelItem = nSel;
+ if(nSel == 0)
+ {
+ SelectItem(1);
+ SetNoSelection();
+ }
+ else
+ {
+ SelectItem(nSelItem);
+ GrabFocus();
+ }
+}
+
+tools::Long CellLineStyleValueSet::GetMaxTextWidth(const vcl::RenderContext* pDev)
+{
+ if (mnMaxTextWidth > 0)
+ return mnMaxTextWidth;
+
+ for (int i = 0; i < CELL_LINE_STYLE_ENTRIES; ++i)
+ {
+ mnMaxTextWidth = std::max(pDev->GetTextWidth(maStrUnit[i]), mnMaxTextWidth);
+ }
+ return mnMaxTextWidth;
+}
+
+void CellLineStyleValueSet::UserDraw( const UserDrawEvent& rUDEvt )
+{
+ tools::Rectangle aRect = rUDEvt.GetRect();
+ vcl::RenderContext* pDev = rUDEvt.GetRenderContext();
+ sal_uInt16 nItemId = rUDEvt.GetItemId();
+
+ tools::Long nRectHeight = aRect.GetHeight();
+ tools::Long nRectWidth = aRect.GetWidth();
+ Point aBLPos = aRect.TopLeft();
+
+ vcl::Font aOldFont = pDev->GetFont();
+ Color aOldColor = pDev->GetLineColor();
+ Color aOldFillColor = pDev->GetFillColor();
+
+ vcl::Font aFont(OutputDevice::GetDefaultFont(DefaultFontType::UI_SANS, MsLangId::getConfiguredSystemLanguage(), GetDefaultFontFlags::OnlyOne));
+ Size aSize = aFont.GetFontSize();
+ aSize.setHeight( nRectHeight*3/5 );
+ aFont.SetFontSize( aSize );
+
+ if( nSelItem == nItemId )
+ {
+ tools::Rectangle aBackRect = aRect;
+ aBackRect.AdjustTop(3 );
+ aBackRect.AdjustBottom( -2 );
+ pDev->SetFillColor(Color(50,107,197));
+ pDev->DrawRect(aBackRect);
+ }
+ else
+ {
+ pDev->SetFillColor( COL_TRANSPARENT );
+ pDev->DrawRect(aRect);
+ }
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+
+ //draw text
+ if (nSelItem == nItemId )
+ aFont.SetColor(COL_WHITE);
+ else
+ aFont.SetColor(rStyleSettings.GetFieldTextColor()); //high contrast
+
+ pDev->SetFont(aFont);
+ tools::Long nTextWidth = GetMaxTextWidth(pDev);
+ tools::Long nTLX = aBLPos.X() + 5, nTLY = aBLPos.Y() + ( nRectHeight - nItemId )/2;
+ tools::Long nTRX = aBLPos.X() + nRectWidth - nTextWidth - 15, nTRY = aBLPos.Y() + ( nRectHeight - nItemId )/2;
+ Point aStart(aBLPos.X() + nRectWidth - nTextWidth - 5 , aBLPos.Y() + nRectHeight/6);
+ pDev->DrawText(aStart, maStrUnit[nItemId - 1]); //can't set DrawTextFlags::EndEllipsis here, or the text will disappear
+
+ //draw line
+ if( nSelItem == nItemId )
+ {
+ pDev->SetFillColor(COL_WHITE);
+ pDev->SetLineColor(COL_WHITE);
+ }
+ else
+ {
+ pDev->SetFillColor(rStyleSettings.GetFieldTextColor()); //high contrast
+ pDev->SetLineColor(rStyleSettings.GetFieldTextColor()); //high contrast
+ }
+
+ switch( nItemId )
+ {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ pDev->DrawRect(tools::Rectangle(nTLX, nTLY , nTRX, nTRY + nItemId * 2 - 1 ));
+ break;
+ case 7:
+ pDev->DrawRect(tools::Rectangle(nTLX, nTLY , nTRX, nTRY + 1 ));
+ pDev->DrawRect(tools::Rectangle(nTLX, nTLY + 3 , nTRX, nTRY + 4 ));
+ break;
+ case 8:
+ pDev->DrawRect(tools::Rectangle(nTLX, nTLY , nTRX, nTRY + 1 ));
+ pDev->DrawRect(tools::Rectangle(nTLX, nTLY + 5 , nTRX, nTRY + 6 ));
+ break;
+ case 9:
+ pDev->DrawRect(tools::Rectangle(nTLX, nTLY , nTRX, nTRY + 1 ));
+ pDev->DrawRect(tools::Rectangle(nTLX, nTLY + 3 , nTRX, nTRY + 6 ));
+ break;
+ case 10:
+ pDev->DrawRect(tools::Rectangle(nTLX, nTLY , nTRX, nTRY + 3 ));
+ pDev->DrawRect(tools::Rectangle(nTLX, nTLY + 5 , nTRX, nTRY + 6 ));
+ break;
+ case 11:
+ pDev->DrawRect(tools::Rectangle(nTLX, nTLY , nTRX, nTRY + 3 ));
+ pDev->DrawRect(tools::Rectangle(nTLX, nTLY + 5 , nTRX, nTRY + 8 ));
+ break;
+ }
+
+ Invalidate( aRect );
+ pDev->SetLineColor(aOldColor);
+ pDev->SetFillColor(aOldFillColor);
+ pDev->SetFont(aOldFont);
+
+}
+
+} // end of namespace sc::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/CellLineStyleValueSet.hxx b/sc/source/ui/sidebar/CellLineStyleValueSet.hxx
new file mode 100644
index 000000000..79dd08fb3
--- /dev/null
+++ b/sc/source/ui/sidebar/CellLineStyleValueSet.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 <svtools/valueset.hxx>
+#include <tools/long.hxx>
+
+#define CELL_LINE_STYLE_ENTRIES 11
+
+namespace sc::sidebar
+{
+class CellLineStyleValueSet : public ValueSet
+{
+private:
+ tools::Long mnMaxTextWidth;
+ sal_uInt16 nSelItem;
+ OUString maStrUnit[CELL_LINE_STYLE_ENTRIES];
+
+public:
+ CellLineStyleValueSet();
+ virtual ~CellLineStyleValueSet() override;
+
+ void SetUnit(const OUString* str);
+ void SetSelItem(sal_uInt16 nSel);
+ tools::Long GetMaxTextWidth(const vcl::RenderContext* pDev);
+ virtual void SetDrawingArea(weld::DrawingArea* pDrawingArea) override;
+ virtual void UserDraw(const UserDrawEvent& rUDEvt) override;
+};
+
+} // end of namespace svx::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/NumberFormatControl.cxx b/sc/source/ui/sidebar/NumberFormatControl.cxx
new file mode 100644
index 000000000..1060f0f5d
--- /dev/null
+++ b/sc/source/ui/sidebar/NumberFormatControl.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 <NumberFormatControl.hxx>
+#include <cbnumberformat.hxx>
+#include <svl/intitem.hxx>
+#include <vcl/toolbox.hxx>
+
+using namespace sc;
+
+SFX_IMPL_TOOLBOX_CONTROL(ScNumberFormatControl, SfxUInt16Item);
+
+ScNumberFormatControl::ScNumberFormatControl(sal_uInt16 nSlotId, ToolBoxItemId nId, ToolBox& rTbx)
+ : SfxToolBoxControl(nSlotId, nId, rTbx)
+{
+}
+
+ScNumberFormatControl::~ScNumberFormatControl()
+{
+}
+
+void ScNumberFormatControl::StateChangedAtToolBoxControl(sal_uInt16, SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ ToolBoxItemId nId = GetId();
+ ToolBox& rTbx = GetToolBox();
+ ScNumberFormat* pComboBox = static_cast<ScNumberFormat*>(rTbx.GetItemWindow(nId));
+
+ DBG_ASSERT( pComboBox, "Control not found!" );
+
+ if(SfxItemState::DISABLED == eState)
+ pComboBox->Disable();
+ else
+ pComboBox->Enable();
+
+ rTbx.EnableItem(nId, SfxItemState::DISABLED != eState);
+
+ switch(eState)
+ {
+ case SfxItemState::DEFAULT:
+ {
+ const SfxUInt16Item* pItem = static_cast<const SfxUInt16Item*>(pState);
+ sal_uInt16 nVal = pItem->GetValue();
+ pComboBox->set_active(nVal);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+VclPtr<InterimItemWindow> ScNumberFormatControl::CreateItemWindow( vcl::Window *pParent )
+{
+ VclPtr<ScNumberFormat> pControl = VclPtr<ScNumberFormat>::Create(pParent);
+ pControl->Show();
+
+ return pControl;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/NumberFormatPropertyPanel.cxx b/sc/source/ui/sidebar/NumberFormatPropertyPanel.cxx
new file mode 100644
index 000000000..c9910cc1d
--- /dev/null
+++ b/sc/source/ui/sidebar/NumberFormatPropertyPanel.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 "NumberFormatPropertyPanel.hxx"
+#include <sc.hrc>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <o3tl/string_view.hxx>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+
+using namespace css;
+using namespace css::uno;
+
+namespace sc::sidebar {
+
+NumberFormatPropertyPanel::NumberFormatPropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings)
+ : PanelLayout(pParent,"NumberFormatPropertyPanel", "modules/scalc/ui/sidebarnumberformat.ui")
+ , mxLbCategory(m_xBuilder->weld_combo_box("numberformatcombobox"))
+ , mxTBCategory(m_xBuilder->weld_toolbar("numberformat"))
+ , mxCategoryDispatch(new ToolbarUnoDispatcher(*mxTBCategory, *m_xBuilder, rxFrame))
+ , mxFtDecimals(m_xBuilder->weld_label("decimalplaceslabel"))
+ , mxEdDecimals(m_xBuilder->weld_spin_button("decimalplaces"))
+ , mxFtDenominator(m_xBuilder->weld_label("denominatorplaceslabel"))
+ , mxEdDenominator(m_xBuilder->weld_spin_button("denominatorplaces"))
+ , mxFtLeadZeroes(m_xBuilder->weld_label("leadingzeroeslabel"))
+ , mxEdLeadZeroes(m_xBuilder->weld_spin_button("leadingzeroes"))
+ , mxBtnNegRed(m_xBuilder->weld_check_button("negativenumbersred"))
+ , mxBtnThousand(m_xBuilder->weld_check_button("thousandseparator"))
+ , mxBtnEngineering(m_xBuilder->weld_check_button("engineeringnotation"))
+ , maNumFormatControl(SID_NUMBER_TYPE_FORMAT, *pBindings, *this)
+ , maFormatControl(SID_NUMBER_FORMAT, *pBindings, *this)
+ , mnCategorySelected(0)
+ , mpBindings(pBindings)
+{
+ Initialize();
+}
+
+NumberFormatPropertyPanel::~NumberFormatPropertyPanel()
+{
+ mxLbCategory.reset();
+ mxCategoryDispatch.reset();
+ mxTBCategory.reset();
+ mxFtDecimals.reset();
+ mxEdDecimals.reset();
+ mxFtDenominator.reset();
+ mxEdDenominator.reset();
+ mxFtLeadZeroes.reset();
+ mxEdLeadZeroes.reset();
+ mxBtnNegRed.reset();
+ mxBtnThousand.reset();
+ mxBtnEngineering.reset();
+
+ maNumFormatControl.dispose();
+ maFormatControl.dispose();
+}
+
+void NumberFormatPropertyPanel::Initialize()
+{
+ mxLbCategory->connect_changed( LINK(this, NumberFormatPropertyPanel, NumFormatSelectHdl) );
+ mxLbCategory->set_active(0);
+
+ Link<weld::SpinButton&,void> aLink = LINK(this, NumberFormatPropertyPanel, NumFormatValueHdl);
+
+ mxEdDecimals->connect_value_changed( aLink );
+ mxEdDenominator->connect_value_changed( aLink );
+ mxEdLeadZeroes->connect_value_changed( aLink );
+
+ mxBtnNegRed->connect_toggled( LINK(this, NumberFormatPropertyPanel, NumFormatValueClickHdl) );
+ mxBtnThousand->connect_toggled( LINK(this, NumberFormatPropertyPanel, NumFormatValueClickHdl) );
+ mxBtnEngineering->connect_toggled( LINK(this, NumberFormatPropertyPanel, NumFormatValueClickHdl) );
+}
+
+IMPL_LINK( NumberFormatPropertyPanel, NumFormatSelectHdl, weld::ComboBox&, rBox, void )
+{
+ const sal_Int32 nVal = rBox.get_active();
+ if( nVal != mnCategorySelected )
+ {
+ SfxUInt16Item aItem( SID_NUMBER_TYPE_FORMAT, nVal );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_NUMBER_TYPE_FORMAT,
+ SfxCallMode::RECORD, { &aItem });
+ mnCategorySelected = nVal;
+ }
+}
+
+IMPL_LINK_NOARG( NumberFormatPropertyPanel, NumFormatValueClickHdl, weld::Toggleable&, void )
+{
+ NumFormatValueHdl(*mxEdDecimals);
+}
+
+IMPL_LINK_NOARG( NumberFormatPropertyPanel, NumFormatValueHdl, weld::SpinButton&, void )
+{
+ OUString aFormat;
+ OUString sBreak = ",";
+ bool bThousand = ( mxBtnThousand->get_visible() && mxBtnThousand->get_sensitive() && mxBtnThousand->get_active() )
+ || ( mxBtnEngineering->get_visible() && mxBtnEngineering->get_sensitive() && mxBtnEngineering->get_active() );
+ bool bNegRed = mxBtnNegRed->get_sensitive() && mxBtnNegRed->get_active();
+ sal_uInt16 nPrecision = (mxEdDecimals->get_sensitive() && mxEdDecimals->get_visible())
+ ? static_cast<sal_uInt16>(mxEdDecimals->get_value())
+ : (mxEdDenominator->get_sensitive() && mxEdDenominator->get_visible())
+ ? static_cast<sal_uInt16>(mxEdDenominator->get_value())
+ : sal_uInt16(0);
+ sal_uInt16 nLeadZeroes = (mxEdLeadZeroes->get_sensitive())
+ ? static_cast<sal_uInt16>(mxEdLeadZeroes->get_value())
+ : sal_uInt16(0);
+
+ OUString sThousand = OUString::number(static_cast<sal_Int32>(bThousand));
+ OUString sNegRed = OUString::number(static_cast<sal_Int32>(bNegRed));
+ OUString sPrecision = OUString::number(nPrecision);
+ OUString sLeadZeroes = OUString::number(nLeadZeroes);
+
+ aFormat += sThousand +
+ sBreak +
+ sNegRed +
+ sBreak +
+ sPrecision +
+ sBreak +
+ sLeadZeroes +
+ sBreak;
+
+ SfxStringItem aItem( SID_NUMBER_FORMAT, aFormat );
+ GetBindings()->GetDispatcher()->ExecuteList(SID_NUMBER_FORMAT,
+ SfxCallMode::RECORD, { &aItem });
+}
+
+std::unique_ptr<PanelLayout> NumberFormatPropertyPanel::Create (
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings)
+{
+ if (pParent == nullptr)
+ throw lang::IllegalArgumentException("no parent Window given to NumberFormatPropertyPanel::Create", nullptr, 0);
+ if ( ! rxFrame.is())
+ throw lang::IllegalArgumentException("no XFrame given to NumberFormatPropertyPanel::Create", nullptr, 1);
+ if (pBindings == nullptr)
+ throw lang::IllegalArgumentException("no SfxBindings given to NumberFormatPropertyPanel::Create", nullptr, 2);
+
+ return std::make_unique<NumberFormatPropertyPanel>(pParent, rxFrame, pBindings);
+}
+
+void NumberFormatPropertyPanel::HandleContextChange(
+ const vcl::EnumContext& rContext)
+{
+ if(maContext == rContext)
+ {
+ // Nothing to do.
+ return;
+ }
+
+ maContext = rContext;
+}
+
+void NumberFormatPropertyPanel::NotifyItemUpdate(
+ sal_uInt16 nSID,
+ SfxItemState eState,
+ const SfxPoolItem* pState)
+{
+ switch(nSID)
+ {
+ case SID_NUMBER_TYPE_FORMAT:
+ {
+ if( eState >= SfxItemState::DEFAULT)
+ {
+ const SfxInt16Item* pItem = static_cast<const SfxInt16Item*>(pState);
+ sal_uInt16 nVal = pItem->GetValue();
+ mnCategorySelected = nVal;
+ mxLbCategory->set_active(nVal);
+ if (nVal < 8 && // General, Number, Percent, Currency, Time, Scientific, Fraction
+ nVal != 4 ) // not Date
+ {
+ bool bIsScientific ( nVal == 6 );// For scientific, Thousand separator is replaced by Engineering notation
+ bool bIsFraction ( nVal == 7 ); // For fraction, Decimal places is replaced by Denominator places
+ bool bIsTime ( nVal == 5 ); // For Time, Decimal places and NegRed available
+ mxBtnThousand->set_visible( !bIsScientific );
+ mxBtnThousand->set_sensitive( !bIsScientific && !bIsTime );
+ mxBtnThousand->set_active(false);
+ mxBtnEngineering->set_visible(bIsScientific);
+ mxBtnEngineering->set_sensitive(bIsScientific);
+ mxBtnEngineering->set_active(false);
+ mxBtnNegRed->set_sensitive(true);
+ mxFtDenominator->set_visible(bIsFraction);
+ mxEdDenominator->set_visible(bIsFraction);
+ mxFtDenominator->set_sensitive(bIsFraction);
+ mxEdDenominator->set_sensitive(bIsFraction);
+ mxFtDecimals->set_visible(!bIsFraction);
+ mxEdDecimals->set_visible(!bIsFraction);
+ mxFtDecimals->set_sensitive(!bIsFraction);
+ mxEdDecimals->set_sensitive(!bIsFraction);
+ mxFtLeadZeroes->set_sensitive( !bIsTime );
+ mxEdLeadZeroes->set_sensitive( !bIsTime );
+ }
+ else
+ DisableControls();
+ }
+ else
+ {
+ DisableControls();
+ mxLbCategory->set_active(-1);
+ mnCategorySelected = 0;
+ }
+ }
+ break;
+ case SID_NUMBER_FORMAT:
+ {
+ bool bThousand = false;
+ bool bNegRed = false;
+ sal_uInt16 nPrecision = 0;
+ sal_uInt16 nLeadZeroes = 0;
+ if( eState >= SfxItemState::DEFAULT)
+ {
+ const SfxStringItem* pItem = static_cast<const SfxStringItem*>(pState);
+ const OUString& aCode = pItem->GetValue();
+ sal_Int32 nIndex = 0;
+ sal_Int32 aFormat[4] = {0};
+ for (sal_Int32 & rn : aFormat)
+ {
+ rn = o3tl::toInt32(o3tl::getToken(aCode, 0, ',', nIndex));
+ if (nIndex<0)
+ break;
+ }
+ bThousand = static_cast<bool>(aFormat[0]);
+ bNegRed = static_cast<bool>(aFormat[1]);
+ nPrecision = static_cast<sal_uInt16>(aFormat[2]);
+ nLeadZeroes = static_cast<sal_uInt16>(aFormat[3]);
+ }
+ else
+ {
+ bThousand = false;
+ bNegRed = false;
+ nPrecision = 0;
+ nLeadZeroes = 1;
+ }
+ if ( mxBtnThousand->get_visible() )
+ mxBtnThousand->set_active(bThousand);
+ else if ( mxBtnEngineering->get_visible() )
+ mxBtnEngineering->set_active(bThousand);
+ mxBtnNegRed->set_active(bNegRed);
+ if ( mxLbCategory->get_active() == 0 )
+ mxEdDecimals->set_text(""); // tdf#44399
+ else if ( mxEdDecimals->get_visible() )
+ mxEdDecimals->set_value(nPrecision);
+ else if ( mxEdDenominator->get_visible() )
+ mxEdDenominator->set_value(nPrecision);
+ mxEdLeadZeroes->set_value(nLeadZeroes);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void NumberFormatPropertyPanel::DisableControls()
+{
+ mxBtnEngineering->hide();
+ mxBtnThousand->show();
+ mxBtnThousand->set_sensitive(false);
+ mxBtnNegRed->set_sensitive(false);
+ mxFtDenominator->hide();
+ mxEdDenominator->hide();
+ mxFtDecimals->show();
+ mxEdDecimals->show();
+ mxFtDecimals->set_sensitive(false);
+ mxEdDecimals->set_sensitive(false);
+ mxFtLeadZeroes->set_sensitive(false);
+ mxEdLeadZeroes->set_sensitive(false);
+}
+
+} // end of namespace ::sc::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/NumberFormatPropertyPanel.hxx b/sc/source/ui/sidebar/NumberFormatPropertyPanel.hxx
new file mode 100644
index 000000000..7f16dffb9
--- /dev/null
+++ b/sc/source/ui/sidebar/NumberFormatPropertyPanel.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/sidebar/ControllerItem.hxx>
+#include <sfx2/sidebar/IContextChangeReceiver.hxx>
+#include <sfx2/weldutils.hxx>
+#include <sfx2/sidebar/PanelLayout.hxx>
+#include <vcl/EnumContext.hxx>
+
+namespace sc::sidebar {
+
+class NumberFormatPropertyPanel
+: public PanelLayout,
+ public ::sfx2::sidebar::IContextChangeReceiver,
+ public ::sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface
+{
+public:
+public:
+ static std::unique_ptr<PanelLayout> Create(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings);
+
+ virtual void HandleContextChange(
+ const vcl::EnumContext& rContext) override;
+
+ virtual void NotifyItemUpdate(
+ const sal_uInt16 nSId,
+ const SfxItemState eState,
+ const SfxPoolItem* pState) override;
+
+ virtual void GetControlState(
+ const sal_uInt16 /*nSId*/,
+ boost::property_tree::ptree& /*rState*/) override {};
+
+ SfxBindings* GetBindings() { return mpBindings;}
+
+ // constructor/destructor
+ NumberFormatPropertyPanel(
+ weld::Widget* pParent,
+ const css::uno::Reference<css::frame::XFrame>& rxFrame,
+ SfxBindings* pBindings);
+ virtual ~NumberFormatPropertyPanel() override;
+private:
+ //ui controls
+ std::unique_ptr<weld::ComboBox> mxLbCategory;
+ std::unique_ptr<weld::Toolbar> mxTBCategory;
+ std::unique_ptr<ToolbarUnoDispatcher> mxCategoryDispatch;
+ std::unique_ptr<weld::Label> mxFtDecimals;
+ std::unique_ptr<weld::SpinButton> mxEdDecimals;
+ std::unique_ptr<weld::Label> mxFtDenominator;
+ std::unique_ptr<weld::SpinButton> mxEdDenominator;
+ std::unique_ptr<weld::Label> mxFtLeadZeroes;
+ std::unique_ptr<weld::SpinButton> mxEdLeadZeroes;
+ std::unique_ptr<weld::CheckButton> mxBtnNegRed;
+ std::unique_ptr<weld::CheckButton> mxBtnThousand;
+ std::unique_ptr<weld::CheckButton> mxBtnEngineering;
+
+ ::sfx2::sidebar::ControllerItem maNumFormatControl;
+ ::sfx2::sidebar::ControllerItem maFormatControl;
+
+ sal_Int32 mnCategorySelected;
+
+ vcl::EnumContext maContext;
+ SfxBindings* mpBindings;
+
+ DECL_LINK(NumFormatSelectHdl, weld::ComboBox&, void);
+ DECL_LINK(NumFormatValueHdl, weld::SpinButton&, void);
+ DECL_LINK(NumFormatValueClickHdl, weld::Toggleable&, void);
+
+ void Initialize();
+ void DisableControls();
+};
+
+} // end of namespace ::sc::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/ScPanelFactory.cxx b/sc/source/ui/sidebar/ScPanelFactory.cxx
new file mode 100644
index 000000000..bbcff315c
--- /dev/null
+++ b/sc/source/ui/sidebar/ScPanelFactory.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 "ScPanelFactory.hxx"
+
+#include "AlignmentPropertyPanel.hxx"
+#include "CellAppearancePropertyPanel.hxx"
+#include "NumberFormatPropertyPanel.hxx"
+#include <navipi.hxx>
+#include <dwfunctr.hxx>
+
+#include <sfx2/sidebar/SidebarPanelBase.hxx>
+#include <vcl/weldutils.hxx>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+namespace sc::sidebar {
+
+ScPanelFactory::ScPanelFactory()
+{
+}
+
+ScPanelFactory::~ScPanelFactory()
+{
+}
+
+Reference<ui::XUIElement> SAL_CALL ScPanelFactory::createUIElement (
+ const OUString& rsResourceURL,
+ const ::css::uno::Sequence<css::beans::PropertyValue>& rArguments)
+{
+ Reference<ui::XUIElement> xElement;
+
+ try
+ {
+ 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>()));
+ const sal_uInt64 nBindingsValue (aArguments.getOrDefault("SfxBindings", sal_uInt64(0)));
+ SfxBindings* pBindings = reinterpret_cast<SfxBindings*>(nBindingsValue);
+
+ weld::Widget* pParent(nullptr);
+ if (weld::TransportAsXWindow* pTunnel = dynamic_cast<weld::TransportAsXWindow*>(xParentWindow.get()))
+ pParent = pTunnel->getWidget();
+
+ if (!pParent)
+ throw RuntimeException(
+ "PanelFactory::createUIElement called without ParentWindow",
+ nullptr);
+ if ( ! xFrame.is())
+ throw RuntimeException(
+ "PanelFactory::createUIElement called without Frame",
+ nullptr);
+ if (pBindings == nullptr)
+ throw RuntimeException(
+ "PanelFactory::createUIElement called without SfxBindings",
+ nullptr);
+
+ sal_Int32 nMinimumSize = -1;
+ std::unique_ptr<PanelLayout> xPanel;
+ if (rsResourceURL.endsWith("/AlignmentPropertyPanel"))
+ xPanel = AlignmentPropertyPanel::Create( pParent, xFrame, pBindings );
+ else if (rsResourceURL.endsWith("/CellAppearancePropertyPanel"))
+ xPanel = CellAppearancePropertyPanel::Create( pParent, xFrame, pBindings );
+ else if (rsResourceURL.endsWith("/NumberFormatPropertyPanel"))
+ xPanel = NumberFormatPropertyPanel::Create( pParent, xFrame, pBindings );
+ else if (rsResourceURL.endsWith("/NavigatorPanel"))
+ {
+ xPanel = std::make_unique<ScNavigatorDlg>(pBindings, pParent, nullptr);
+ nMinimumSize = 0;
+ }
+ else if (rsResourceURL.endsWith("/FunctionsPanel"))
+ {
+ xPanel = std::make_unique<ScFunctionWin>(pParent);
+ nMinimumSize = 0;
+ }
+
+ if (xPanel)
+ xElement = sfx2::sidebar::SidebarPanelBase::Create(
+ rsResourceURL,
+ xFrame,
+ std::move(xPanel),
+ ui::LayoutSize(nMinimumSize,-1,-1));
+ }
+ catch (const uno::RuntimeException &)
+ {
+ throw;
+ }
+ catch (const uno::Exception&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw lang::WrappedTargetRuntimeException(
+ "ScPanelFactory::createUIElement exception",
+ nullptr, anyEx);
+ }
+
+ return xElement;
+}
+
+OUString ScPanelFactory::getImplementationName()
+{
+ return "org.apache.openoffice.comp.sc.sidebar.ScPanelFactory";
+}
+
+sal_Bool ScPanelFactory::supportsService(OUString const & ServiceName)
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence<OUString> ScPanelFactory::getSupportedServiceNames()
+{
+ return { "com.sun.star.ui.UIElementFactory" };
+}
+
+} // end of namespace sc::sidebar
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ScPanelFactory_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new sc::sidebar::ScPanelFactory());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sidebar/ScPanelFactory.hxx b/sc/source/ui/sidebar/ScPanelFactory.hxx
new file mode 100644
index 000000000..b2901e2ab
--- /dev/null
+++ b/sc/source/ui/sidebar/ScPanelFactory.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 <comphelper/compbase.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/ui/XUIElementFactory.hpp>
+
+namespace sc::sidebar {
+
+typedef comphelper::WeakComponentImplHelper <
+ css::ui::XUIElementFactory, css::lang::XServiceInfo
+ > PanelFactoryInterfaceBase;
+
+class ScPanelFactory final : public PanelFactoryInterfaceBase
+{
+public:
+ // noncopyable
+ ScPanelFactory(const ScPanelFactory&) = delete;
+ const ScPanelFactory& operator=(const ScPanelFactory&) = delete;
+
+ ScPanelFactory();
+ virtual ~ScPanelFactory() override;
+
+ // XUIElementFactory
+ css::uno::Reference<css::ui::XUIElement> SAL_CALL createUIElement(
+ const OUString& rsResourceURL,
+ const ::css::uno::Sequence<css::beans::PropertyValue>& rArguments) override;
+
+ OUString SAL_CALL getImplementationName() override;
+
+ sal_Bool SAL_CALL supportsService(OUString const & ServiceName) override;
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+};
+
+} // end of namespace sc::sidebar
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sparklines/SparklineAttributes.cxx b/sc/source/ui/sparklines/SparklineAttributes.cxx
new file mode 100644
index 000000000..20b8bf6fe
--- /dev/null
+++ b/sc/source/ui/sparklines/SparklineAttributes.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/.
+ *
+ */
+
+#include <SparklineAttributes.hxx>
+
+namespace sc
+{
+/** Holder of sparkline attributes */
+class SparklineAttributes::Implementation
+{
+public:
+ Color m_aColorSeries;
+ Color m_aColorNegative;
+ Color m_aColorAxis;
+ Color m_aColorMarkers;
+ Color m_aColorFirst;
+ Color m_aColorLast;
+ Color m_aColorHigh;
+ Color m_aColorLow;
+
+ AxisType m_eMinAxisType;
+ AxisType m_eMaxAxisType;
+
+ double m_fLineWeight; // In pt
+
+ SparklineType m_eType;
+
+ bool m_bDateAxis;
+
+ DisplayEmptyCellsAs m_eDisplayEmptyCellsAs; // span, gap, zero
+
+ bool m_bMarkers;
+ bool m_bHigh;
+ bool m_bLow;
+ bool m_bFirst;
+ bool m_bLast;
+ bool m_bNegative;
+ bool m_bDisplayXAxis;
+ bool m_bDisplayHidden;
+ bool m_bRightToLeft;
+
+ std::optional<double> m_aManualMax;
+ std::optional<double> m_aManualMin;
+
+ static constexpr ::Color COL_STANDARD_RED = 0xff0000;
+ static constexpr ::Color COL_STANDARD_BLUE = 0x2a6099;
+
+ Implementation()
+ : m_aColorSeries(COL_STANDARD_BLUE)
+ , m_aColorNegative(COL_STANDARD_RED)
+ , m_aColorAxis(COL_STANDARD_RED)
+ , m_aColorMarkers(COL_STANDARD_RED)
+ , m_aColorFirst(COL_STANDARD_RED)
+ , m_aColorLast(COL_STANDARD_RED)
+ , m_aColorHigh(COL_STANDARD_RED)
+ , m_aColorLow(COL_STANDARD_RED)
+ , m_eMinAxisType(AxisType::Individual)
+ , m_eMaxAxisType(AxisType::Individual)
+ , m_fLineWeight(0.75)
+ , m_eType(SparklineType::Line)
+ , m_bDateAxis(false)
+ , m_eDisplayEmptyCellsAs(DisplayEmptyCellsAs::Zero)
+ , m_bMarkers(false)
+ , m_bHigh(false)
+ , m_bLow(false)
+ , m_bFirst(false)
+ , m_bLast(false)
+ , m_bNegative(false)
+ , m_bDisplayXAxis(false)
+ , m_bDisplayHidden(false)
+ , m_bRightToLeft(false)
+ {
+ }
+
+ Implementation(Implementation const& pOther)
+ : m_aColorSeries(pOther.m_aColorSeries)
+ , m_aColorNegative(pOther.m_aColorNegative)
+ , m_aColorAxis(pOther.m_aColorAxis)
+ , m_aColorMarkers(pOther.m_aColorMarkers)
+ , m_aColorFirst(pOther.m_aColorFirst)
+ , m_aColorLast(pOther.m_aColorLast)
+ , m_aColorHigh(pOther.m_aColorHigh)
+ , m_aColorLow(pOther.m_aColorLow)
+ , m_eMinAxisType(pOther.m_eMinAxisType)
+ , m_eMaxAxisType(pOther.m_eMaxAxisType)
+ , m_fLineWeight(pOther.m_fLineWeight)
+ , m_eType(pOther.m_eType)
+ , m_bDateAxis(pOther.m_bDateAxis)
+ , m_eDisplayEmptyCellsAs(pOther.m_eDisplayEmptyCellsAs)
+ , m_bMarkers(pOther.m_bMarkers)
+ , m_bHigh(pOther.m_bHigh)
+ , m_bLow(pOther.m_bLow)
+ , m_bFirst(pOther.m_bFirst)
+ , m_bLast(pOther.m_bLast)
+ , m_bNegative(pOther.m_bNegative)
+ , m_bDisplayXAxis(pOther.m_bDisplayXAxis)
+ , m_bDisplayHidden(pOther.m_bDisplayHidden)
+ , m_bRightToLeft(pOther.m_bRightToLeft)
+ , m_aManualMax(pOther.m_aManualMax)
+ , m_aManualMin(pOther.m_aManualMin)
+ {
+ }
+
+ bool operator==(const Implementation& rImpl) const
+ {
+ return (m_aColorSeries == rImpl.m_aColorSeries)
+ && (m_aColorNegative == rImpl.m_aColorNegative)
+ && (m_aColorAxis == rImpl.m_aColorAxis) && (m_aColorMarkers == rImpl.m_aColorMarkers)
+ && (m_aColorFirst == rImpl.m_aColorFirst) && (m_aColorLast == rImpl.m_aColorLast)
+ && (m_aColorHigh == rImpl.m_aColorHigh) && (m_aColorLow == rImpl.m_aColorLow)
+ && (m_eMinAxisType == rImpl.m_eMinAxisType)
+ && (m_eMaxAxisType == rImpl.m_eMaxAxisType) && (m_fLineWeight == rImpl.m_fLineWeight)
+ && (m_eType == rImpl.m_eType) && (m_bDateAxis == rImpl.m_bDateAxis)
+ && (m_eDisplayEmptyCellsAs == rImpl.m_eDisplayEmptyCellsAs)
+ && (m_bMarkers == rImpl.m_bMarkers) && (m_bHigh == rImpl.m_bHigh)
+ && (m_bLow == rImpl.m_bLow) && (m_bFirst == rImpl.m_bFirst)
+ && (m_bLast == rImpl.m_bLast) && (m_bNegative == rImpl.m_bNegative)
+ && (m_bDisplayXAxis == rImpl.m_bDisplayXAxis)
+ && (m_bDisplayHidden == rImpl.m_bDisplayHidden)
+ && (m_bRightToLeft == rImpl.m_bRightToLeft) && (m_aManualMax == rImpl.m_aManualMax)
+ && (m_aManualMin == rImpl.m_aManualMin);
+ }
+};
+
+SparklineAttributes::SparklineAttributes() = default;
+
+SparklineAttributes::~SparklineAttributes() = default;
+
+SparklineAttributes::SparklineAttributes(SparklineAttributes const&) = default;
+
+SparklineAttributes::SparklineAttributes(SparklineAttributes&&) = default;
+
+SparklineAttributes& SparklineAttributes::operator=(SparklineAttributes const&) = default;
+
+SparklineAttributes& SparklineAttributes::operator=(SparklineAttributes&&) = default;
+
+bool SparklineAttributes::operator==(SparklineAttributes const& rOther) const
+{
+ return m_aImplementation == rOther.m_aImplementation;
+}
+
+Color SparklineAttributes::getColorSeries() const { return m_aImplementation->m_aColorSeries; }
+
+void SparklineAttributes::setColorSeries(Color aColor)
+{
+ m_aImplementation->m_aColorSeries = aColor;
+}
+
+Color SparklineAttributes::getColorNegative() const { return m_aImplementation->m_aColorNegative; }
+
+void SparklineAttributes::setColorNegative(Color aColor)
+{
+ m_aImplementation->m_aColorNegative = aColor;
+}
+
+Color SparklineAttributes::getColorAxis() const { return m_aImplementation->m_aColorAxis; }
+
+void SparklineAttributes::setColorAxis(Color aColor) { m_aImplementation->m_aColorAxis = aColor; }
+
+Color SparklineAttributes::getColorMarkers() const { return m_aImplementation->m_aColorMarkers; }
+void SparklineAttributes::setColorMarkers(Color aColor)
+{
+ m_aImplementation->m_aColorMarkers = aColor;
+}
+
+Color SparklineAttributes::getColorFirst() const { return m_aImplementation->m_aColorFirst; }
+void SparklineAttributes::setColorFirst(Color aColor) { m_aImplementation->m_aColorFirst = aColor; }
+
+Color SparklineAttributes::getColorLast() const { return m_aImplementation->m_aColorLast; }
+void SparklineAttributes::setColorLast(Color aColor) { m_aImplementation->m_aColorLast = aColor; }
+
+Color SparklineAttributes::getColorHigh() const { return m_aImplementation->m_aColorHigh; }
+void SparklineAttributes::setColorHigh(Color aColor) { m_aImplementation->m_aColorHigh = aColor; }
+
+Color SparklineAttributes::getColorLow() const { return m_aImplementation->m_aColorLow; }
+void SparklineAttributes::setColorLow(Color aColor) { m_aImplementation->m_aColorLow = aColor; }
+
+AxisType SparklineAttributes::getMinAxisType() const { return m_aImplementation->m_eMinAxisType; }
+void SparklineAttributes::setMinAxisType(AxisType eAxisType)
+{
+ m_aImplementation->m_eMinAxisType = eAxisType;
+}
+
+AxisType SparklineAttributes::getMaxAxisType() const { return m_aImplementation->m_eMaxAxisType; }
+void SparklineAttributes::setMaxAxisType(AxisType eAxisType)
+{
+ m_aImplementation->m_eMaxAxisType = eAxisType;
+}
+
+double SparklineAttributes::getLineWeight() const { return m_aImplementation->m_fLineWeight; }
+void SparklineAttributes::setLineWeight(double nWeight)
+{
+ m_aImplementation->m_fLineWeight = nWeight;
+}
+
+SparklineType SparklineAttributes::getType() const { return m_aImplementation->m_eType; }
+void SparklineAttributes::setType(SparklineType eType) { m_aImplementation->m_eType = eType; }
+
+bool SparklineAttributes::isDateAxis() const { return m_aImplementation->m_bDateAxis; }
+void SparklineAttributes::setDateAxis(bool bValue) { m_aImplementation->m_bDateAxis = bValue; }
+
+DisplayEmptyCellsAs SparklineAttributes::getDisplayEmptyCellsAs() const
+{
+ return m_aImplementation->m_eDisplayEmptyCellsAs;
+}
+void SparklineAttributes::setDisplayEmptyCellsAs(DisplayEmptyCellsAs eValue)
+{
+ m_aImplementation->m_eDisplayEmptyCellsAs = eValue;
+}
+
+bool SparklineAttributes::isMarkers() const { return m_aImplementation->m_bMarkers; }
+void SparklineAttributes::setMarkers(bool bValue) { m_aImplementation->m_bMarkers = bValue; }
+
+bool SparklineAttributes::isHigh() const { return m_aImplementation->m_bHigh; }
+void SparklineAttributes::setHigh(bool bValue) { m_aImplementation->m_bHigh = bValue; }
+
+bool SparklineAttributes::isLow() const { return m_aImplementation->m_bLow; }
+void SparklineAttributes::setLow(bool bValue) { m_aImplementation->m_bLow = bValue; }
+
+bool SparklineAttributes::isFirst() const { return m_aImplementation->m_bFirst; }
+void SparklineAttributes::setFirst(bool bValue) { m_aImplementation->m_bFirst = bValue; }
+
+bool SparklineAttributes::isLast() const { return m_aImplementation->m_bLast; }
+void SparklineAttributes::setLast(bool bValue) { m_aImplementation->m_bLast = bValue; }
+
+bool SparklineAttributes::isNegative() const { return m_aImplementation->m_bNegative; }
+void SparklineAttributes::setNegative(bool bValue) { m_aImplementation->m_bNegative = bValue; }
+
+bool SparklineAttributes::shouldDisplayXAxis() const { return m_aImplementation->m_bDisplayXAxis; }
+void SparklineAttributes::setDisplayXAxis(bool bValue)
+{
+ m_aImplementation->m_bDisplayXAxis = bValue;
+}
+
+bool SparklineAttributes::shouldDisplayHidden() const
+{
+ return m_aImplementation->m_bDisplayHidden;
+}
+void SparklineAttributes::setDisplayHidden(bool bValue)
+{
+ m_aImplementation->m_bDisplayHidden = bValue;
+}
+
+bool SparklineAttributes::isRightToLeft() const { return m_aImplementation->m_bRightToLeft; }
+void SparklineAttributes::setRightToLeft(bool bValue)
+{
+ m_aImplementation->m_bRightToLeft = bValue;
+}
+
+std::optional<double> SparklineAttributes::getManualMax() const
+{
+ return m_aImplementation->m_aManualMax;
+}
+void SparklineAttributes::setManualMax(std::optional<double> aValue)
+{
+ m_aImplementation->m_aManualMax = aValue;
+}
+
+std::optional<double> SparklineAttributes::getManualMin() const
+{
+ return m_aImplementation->m_aManualMin;
+}
+void SparklineAttributes::setManualMin(std::optional<double> aValue)
+{
+ m_aImplementation->m_aManualMin = aValue;
+}
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sparklines/SparklineData.cxx b/sc/source/ui/sparklines/SparklineData.cxx
new file mode 100644
index 000000000..a126acc10
--- /dev/null
+++ b/sc/source/ui/sparklines/SparklineData.cxx
@@ -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/.
+ *
+ */
+
+#include <SparklineData.hxx>
+
+namespace sc
+{
+RangeOrientation calculateOrientation(sal_Int32 nOutputSize, ScRange const& rInputRange)
+{
+ sal_Int32 nRowSize = rInputRange.aEnd.Row() - rInputRange.aStart.Row();
+ sal_Int32 nColSize = rInputRange.aEnd.Col() - rInputRange.aStart.Col();
+
+ auto eInputOrientation = RangeOrientation::Unknown;
+ if (nOutputSize == nRowSize)
+ eInputOrientation = RangeOrientation::Row;
+ else if (nOutputSize == nColSize)
+ eInputOrientation = RangeOrientation::Col;
+ return eInputOrientation;
+}
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sparklines/SparklineGroup.cxx b/sc/source/ui/sparklines/SparklineGroup.cxx
new file mode 100644
index 000000000..1ba235e75
--- /dev/null
+++ b/sc/source/ui/sparklines/SparklineGroup.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/.
+ *
+ */
+
+#include <SparklineGroup.hxx>
+
+namespace sc
+{
+SparklineGroup::SparklineGroup(SparklineAttributes const& rSparklineAttributes)
+ : m_aAttributes(rSparklineAttributes)
+ , m_aGUID(tools::Guid::Generate)
+{
+}
+
+SparklineGroup::SparklineGroup()
+ : m_aGUID(tools::Guid::Generate)
+{
+}
+
+SparklineGroup::SparklineGroup(SparklineGroup const& pOtherSparkline)
+ : m_aAttributes(pOtherSparkline.m_aAttributes)
+ , m_aGUID(pOtherSparkline.m_aGUID)
+{
+}
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/sparklines/SparklineList.cxx b/sc/source/ui/sparklines/SparklineList.cxx
new file mode 100644
index 000000000..1cae30896
--- /dev/null
+++ b/sc/source/ui/sparklines/SparklineList.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/.
+ *
+ */
+
+#include <SparklineList.hxx>
+
+namespace sc
+{
+SparklineList::SparklineList() = default;
+
+void SparklineList::addSparkline(std::shared_ptr<Sparkline> const& pSparkline)
+{
+ auto pWeakGroup = std::weak_ptr<SparklineGroup>(pSparkline->getSparklineGroup());
+
+ auto[iterator, bInserted]
+ = m_aSparklineGroupMap.try_emplace(pWeakGroup, std::vector<std::weak_ptr<Sparkline>>());
+ iterator->second.push_back(std::weak_ptr<Sparkline>(pSparkline));
+ if (bInserted)
+ m_aSparklineGroups.push_back(pWeakGroup);
+}
+
+void SparklineList::removeSparkline(std::shared_ptr<Sparkline> const& pSparkline)
+{
+ auto pWeakGroup = std::weak_ptr<SparklineGroup>(pSparkline->getSparklineGroup());
+ auto iteratorGroup = m_aSparklineGroupMap.find(pWeakGroup);
+ if (iteratorGroup != m_aSparklineGroupMap.end())
+ {
+ auto& rWeakSparklines = iteratorGroup->second;
+
+ for (auto iterator = rWeakSparklines.begin(); iterator != rWeakSparklines.end();)
+ {
+ auto pCurrentSparkline = iterator->lock();
+
+ if (pCurrentSparkline && pCurrentSparkline != pSparkline)
+ {
+ iterator++;
+ }
+ else
+ {
+ iterator = rWeakSparklines.erase(iterator);
+ }
+ }
+ }
+}
+
+std::vector<std::shared_ptr<SparklineGroup>> SparklineList::getSparklineGroups()
+{
+ std::vector<std::shared_ptr<SparklineGroup>> toReturn;
+
+ for (auto iterator = m_aSparklineGroups.begin(); iterator != m_aSparklineGroups.end();)
+ {
+ auto pWeakGroup = *iterator;
+ if (auto pSparklineGroup = pWeakGroup.lock())
+ {
+ toReturn.push_back(pSparklineGroup);
+ iterator++;
+ }
+ else
+ {
+ iterator = m_aSparklineGroups.erase(iterator);
+ }
+ }
+ return toReturn;
+}
+
+std::vector<std::shared_ptr<Sparkline>>
+SparklineList::getSparklinesFor(std::shared_ptr<SparklineGroup> const& pSparklineGroup)
+{
+ std::vector<std::shared_ptr<Sparkline>> toReturn;
+
+ std::weak_ptr<SparklineGroup> pWeakGroup(pSparklineGroup);
+ auto iteratorGroup = m_aSparklineGroupMap.find(pWeakGroup);
+
+ if (iteratorGroup == m_aSparklineGroupMap.end())
+ return toReturn;
+
+ auto& rWeakSparklines = iteratorGroup->second;
+
+ for (auto iterator = rWeakSparklines.begin(); iterator != rWeakSparklines.end();)
+ {
+ if (auto aSparkline = iterator->lock())
+ {
+ toReturn.push_back(aSparkline);
+ iterator++;
+ }
+ else
+ {
+ iterator = rWeakSparklines.erase(iterator);
+ }
+ }
+
+ return toReturn;
+}
+
+} // end sc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/styleui/styledlg.cxx b/sc/source/ui/styleui/styledlg.cxx
new file mode 100644
index 000000000..d814654e5
--- /dev/null
+++ b/sc/source/ui/styleui/styledlg.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 .
+ */
+
+#undef SC_DLLIMPLEMENTATION
+
+#include <svx/numinf.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <svl/style.hxx>
+#include <svl/cjkoptions.hxx>
+#include <osl/diagnose.h>
+
+#include <styledlg.hxx>
+#include <tabpages.hxx>
+#include <tphf.hxx>
+#include <tptable.hxx>
+#include <svx/svxids.hrc>
+#include <svx/dialogs.hrc>
+#include <svl/intitem.hxx>
+#include <editeng/flstitem.hxx>
+#include <svx/flagsdef.hxx>
+
+ScStyleDlg::ScStyleDlg(weld::Window* pParent,
+ SfxStyleSheetBase& rStyleBase,
+ bool bPage)
+ : SfxStyleDialogController(pParent,
+ bPage ?
+ OUString("modules/scalc/ui/pagetemplatedialog.ui") :
+ OUString("modules/scalc/ui/paratemplatedialog.ui"),
+ bPage ?
+ OString("PageTemplateDialog") :
+ OString("ParaTemplateDialog"),
+ rStyleBase )
+ , m_bPage(bPage)
+{
+ SfxAbstractDialogFactory* pFact = SfxAbstractDialogFactory::Create();
+ if (m_bPage) // page styles
+ {
+ AddTabPage("page", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_PAGE ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_PAGE ) );
+ AddTabPage("borders", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_BORDER ) );
+ AddTabPage("background", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BKG ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_BKG ) );
+ AddTabPage("header", &ScHeaderPage::Create, &ScHeaderPage::GetRanges );
+ AddTabPage("footer", &ScFooterPage::Create, &ScFooterPage::GetRanges );
+ AddTabPage("sheet", &ScTablePage::Create, &ScTablePage::GetRanges );
+ }
+ else // cell format styles
+ {
+ AddTabPage("numbers", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_NUMBERFORMAT ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_NUMBERFORMAT ));
+ AddTabPage("font", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_NAME ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_CHAR_NAME ));
+ AddTabPage("fonteffects", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_CHAR_EFFECTS ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_CHAR_EFFECTS ));
+ AddTabPage("alignment", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_ALIGNMENT ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_ALIGNMENT ));
+ if ( SvtCJKOptions::IsAsianTypographyEnabled() )
+ {
+ AddTabPage("asiantypo", pFact->GetTabPageCreatorFunc(RID_SVXPAGE_PARA_ASIAN), pFact->GetTabPageRangesFunc(RID_SVXPAGE_PARA_ASIAN));
+ }
+ else
+ RemoveTabPage("asiantypo");
+ AddTabPage("borders", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BORDER ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_BORDER ));
+ AddTabPage("background", pFact->GetTabPageCreatorFunc( RID_SVXPAGE_BKG ), pFact->GetTabPageRangesFunc( RID_SVXPAGE_BKG ));
+ AddTabPage("protection", &ScTabPageProtection::Create, &ScTabPageProtection::GetRanges);
+ }
+}
+
+void ScStyleDlg::PageCreated(const OString& rPageId, SfxTabPage& rTabPage)
+{
+ if (m_bPage)
+ {
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ if (rPageId == "page")
+ {
+ aSet.Put (SfxUInt16Item(sal_uInt16(SID_ENUM_PAGE_MODE), SVX_PAGE_MODE_CENTER));
+ rTabPage.PageCreated(aSet);
+ }
+ else if (rPageId == "header" || rPageId == "footer")
+ {
+ static_cast<ScHFPage&>(rTabPage).SetStyleDlg( this );
+ static_cast<ScHFPage&>(rTabPage).SetPageStyle( GetStyleSheet().GetName() );
+ static_cast<ScHFPage&>(rTabPage).DisableDeleteQueryBox();
+ }
+ else if (rPageId == "background")
+ {
+ aSet.Put (SfxUInt32Item(SID_FLAG_TYPE, static_cast<sal_uInt32>(SvxBackgroundTabFlags::SHOW_SELECTOR)));
+ rTabPage.PageCreated(aSet);
+ }
+ }
+ else if (SfxObjectShell* pDocSh = SfxObjectShell::Current())
+ {
+ SfxAllItemSet aSet(*(GetInputSetImpl()->GetPool()));
+ if (rPageId == "numbers")
+ {
+ const SfxPoolItem* pInfoItem
+ = pDocSh->GetItem( SID_ATTR_NUMBERFORMAT_INFO );
+
+ OSL_ENSURE( pInfoItem, "NumberInfoItem not found!" );
+
+ aSet.Put ( static_cast<const SvxNumberInfoItem&>(*pInfoItem) );
+ rTabPage.PageCreated(aSet);
+ }
+ else if (rPageId == "font")
+ {
+ const SfxPoolItem* pInfoItem
+ = pDocSh->GetItem( SID_ATTR_CHAR_FONTLIST );
+
+ OSL_ENSURE( pInfoItem, "FontListItem not found!" );
+
+ aSet.Put (SvxFontListItem(static_cast<const SvxFontListItem&>(*pInfoItem).GetFontList(), SID_ATTR_CHAR_FONTLIST));
+ rTabPage.PageCreated(aSet);
+ }
+ else if (rPageId == "background")
+ {
+ rTabPage.PageCreated(aSet);
+ }
+ }
+}
+
+void ScStyleDlg::RefreshInputSet()
+{
+ SfxItemSet* pItemSet = GetInputSetImpl();
+ pItemSet->ClearItem();
+ pItemSet->SetParent( GetStyleSheet().GetItemSet().GetParent() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/styleui/template.cur b/sc/source/ui/styleui/template.cur
new file mode 100644
index 000000000..0fb6a1f5d
--- /dev/null
+++ b/sc/source/ui/styleui/template.cur
Binary files differ
diff --git a/sc/source/ui/uitest/uiobject.cxx b/sc/source/ui/uitest/uiobject.cxx
new file mode 100644
index 000000000..58722b50e
--- /dev/null
+++ b/sc/source/ui/uitest/uiobject.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/.
+ */
+
+#include <memory>
+#include <uiobject.hxx>
+
+#include <rangeutl.hxx>
+#include <gridwin.hxx>
+
+#include <viewdata.hxx>
+#include <viewfunc.hxx>
+#include <dbfunc.hxx>
+#include <tabvwsh.hxx>
+#include <drwlayer.hxx>
+#include <sfx2/sidebar/Sidebar.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <appoptio.hxx>
+#include <scmod.hxx>
+#include <fudraw.hxx>
+#include <postit.hxx>
+
+#include <com/sun/star/embed/EmbedVerbs.hpp>
+
+#include <svx/svditer.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdoole2.hxx>
+#include <sal/log.hxx>
+
+namespace {
+
+ScAddress get_address_from_string(const ScDocument& rDoc, const OUString& rStr)
+{
+ ScAddress aAddr;
+ sal_Int32 nOffset = 0;
+ ScRangeStringConverter::GetAddressFromString(aAddr, rStr, rDoc, formula::FormulaGrammar::CONV_OOO, nOffset);
+ return aAddr;
+}
+
+ScRange get_range_from_string(const ScDocument& rDoc, const OUString& rStr)
+{
+ ScRange aRange;
+ sal_Int32 nOffset = 0;
+ ScRangeStringConverter::GetRangeFromString(aRange, rStr, rDoc, formula::FormulaGrammar::CONV_OOO, nOffset);
+
+ return aRange;
+}
+
+}
+
+ScGridWinUIObject::ScGridWinUIObject(const VclPtr<ScGridWindow>& xGridWin):
+ WindowUIObject(xGridWin),
+ mxGridWindow(xGridWin)
+{
+}
+
+StringMap ScGridWinUIObject::get_state()
+{
+ StringMap aMap = WindowUIObject::get_state();
+
+ aMap["SelectedTable"] = OUString::number(mxGridWindow->getViewData().GetTabNo());
+ aMap["CurrentColumn"] = OUString::number(mxGridWindow->getViewData().GetCurX());
+ aMap["CurrentRow"] = OUString::number(mxGridWindow->getViewData().GetCurY());
+
+ ScSplitPos eAlign = mxGridWindow->getViewData().GetActivePart();
+ ScHSplitPos eAlignX = WhichH(eAlign);
+ ScVSplitPos eAlignY = WhichV(eAlign);
+ aMap["TopVisibleRow"] = OUString::number(mxGridWindow->getViewData().GetPosY(eAlignY));
+ aMap["TopVisibleColumn"] = OUString::number(mxGridWindow->getViewData().GetPosX(eAlignX));
+
+ ScRangeList aMarkedArea = mxGridWindow->getViewData().GetMarkData().GetMarkedRanges();
+ OUString aMarkedAreaString;
+ ScRangeStringConverter::GetStringFromRangeList(aMarkedAreaString, &aMarkedArea, &mxGridWindow->getViewData().GetDocument(), formula::FormulaGrammar::CONV_OOO);
+
+ aMap["MarkedArea"] = aMarkedAreaString;
+
+ ScDocument& rDoc = mxGridWindow->getViewData().GetDocument();
+ ScAddress aPos( mxGridWindow->getViewData().GetCurX() , mxGridWindow->getViewData().GetCurY() , mxGridWindow->getViewData().GetTabNo() );
+ if ( rDoc.HasNote( aPos ) )
+ {
+ ScPostIt* pNote = rDoc.GetNote(aPos);
+ assert(pNote);
+ aMap["CurrentCellCommentText"] = pNote->GetText();
+ }
+
+ ScAppOptions aOpt = SC_MOD()->GetAppOptions();
+ aMap["Zoom"] = OUString::number( aOpt.GetZoom() );
+ return aMap;
+}
+
+ScDBFunc* ScGridWinUIObject::getDBFunc()
+{
+ ScViewData& rViewData = mxGridWindow->getViewData();
+ ScDBFunc* pFunc = rViewData.GetView();
+
+ return pFunc;
+}
+
+ScDrawView* ScGridWinUIObject::getDrawView()
+{
+ ScViewData& rViewData = mxGridWindow->getViewData();
+ ScDrawView* pDrawView = rViewData.GetScDrawView();
+
+ return pDrawView;
+}
+
+ScTabViewShell* ScGridWinUIObject::getViewShell()
+{
+ ScViewData& rViewData = mxGridWindow->getViewData();
+ ScTabViewShell* pViewShell = rViewData.GetViewShell();
+
+ return pViewShell;
+}
+
+ScViewFunc* ScGridWinUIObject::getViewFunc()
+{
+ ScViewData& rViewData = mxGridWindow->getViewData();
+ ScViewFunc* pViewFunc = rViewData.GetView();
+
+ return pViewFunc;
+}
+
+void ScGridWinUIObject::execute(const OUString& rAction,
+ const StringMap& rParameters)
+{
+ if (rAction == "SELECT")
+ {
+ bool bExtend = false;
+ if (rParameters.find("EXTEND") != rParameters.end())
+ {
+ auto itr = rParameters.find("EXTEND");
+ if (itr->second.equalsIgnoreAsciiCase("true") || itr->second == "1")
+ bExtend = true;
+ }
+
+ if (rParameters.find("CELL") != rParameters.end())
+ {
+ auto itr = rParameters.find("CELL");
+ const OUString& rStr = itr->second;
+ ScAddress aAddr = get_address_from_string(mxGridWindow->getViewData().GetDocument(), rStr);
+ ScDBFunc* pFunc = getDBFunc();
+ pFunc->MarkRange(ScRange(aAddr), true, bExtend);
+ mxGridWindow->CursorChanged();
+ }
+ else if (rParameters.find("RANGE") != rParameters.end())
+ {
+ auto itr = rParameters.find("RANGE");
+ const OUString rStr = itr->second;
+ ScRange aRange = get_range_from_string(mxGridWindow->getViewData().GetDocument(), rStr);
+ ScDBFunc* pFunc = getDBFunc();
+ pFunc->MarkRange(aRange, true, bExtend);
+ mxGridWindow->CursorChanged();
+ }
+ else if (rParameters.find("TABLE") != rParameters.end())
+ {
+ auto itr = rParameters.find("TABLE");
+ const OUString rStr = itr->second;
+ sal_Int32 nTab = rStr.toUInt32();
+ ScTabView* pTabView = mxGridWindow->getViewData().GetView();
+ if (pTabView)
+ {
+ ScDocument& rDoc = mxGridWindow->getViewData().GetDocument();
+ if( nTab < rDoc.GetTableCount() )
+ pTabView->SetTabNo(nTab);
+ else
+ {
+ SAL_WARN("sc.uitest", "incorrect table number");
+ }
+ }
+ }
+ else if (rParameters.find("OBJECT") != rParameters.end())
+ {
+ auto itr = rParameters.find("OBJECT");
+ const OUString rStr = itr->second;
+
+ ScDrawView* pDrawView = getDrawView();
+ pDrawView->SelectObject(rStr);
+ }
+ else
+ {
+ SAL_WARN("sc.uitest", "unknown selection method");
+ }
+ }
+ else if (rAction == "DESELECT")
+ {
+ if (rParameters.find("OBJECT") != rParameters.end())
+ {
+ ScDrawView* pDrawView = getDrawView();
+ pDrawView->UnmarkAll();
+
+ ScTabViewShell* pViewShell = getViewShell();
+ pViewShell->SetDrawShell(false);
+ }
+ }
+ else if (rAction == "ACTIVATE")
+ {
+ ScDrawView* pDrawView = getDrawView();
+ const SdrMarkList& rMarkList = pDrawView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+ SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
+ if (nSdrObjKind == SdrObjKind::OLE2)
+ {
+ ScTabViewShell* pViewShell = getViewShell();
+ pViewShell->ActivateObject(static_cast<SdrOle2Obj*>(pObj), css::embed::EmbedVerbs::MS_OLEVERB_PRIMARY);
+ }
+ else
+ {
+ SAL_WARN("sc.uitest", "can't activate non-ole objects");
+ }
+ }
+ else
+ SAL_WARN("sc.uitest", "can't activate the current selection");
+ }
+ else if (rAction == "LAUNCH")
+ {
+ if ( rParameters.find("AUTOFILTER") != rParameters.end())
+ {
+ auto itrCol = rParameters.find("COL");
+ if (itrCol == rParameters.end())
+ {
+ SAL_WARN("sc.uitest", "missing COL parameter");
+ return;
+ }
+
+ auto itrRow = rParameters.find("ROW");
+ if (itrRow == rParameters.end())
+ {
+ SAL_WARN("sc.uitest", "missing ROW parameter");
+ return;
+ }
+ SCROW nRow = itrRow->second.toUInt32();
+ SCCOL nCol = itrCol->second.toUInt32();
+ mxGridWindow->LaunchAutoFilterMenu(nCol, nRow);
+ }
+ else if ( rParameters.find("PIVOTTABLE") != rParameters.end())
+ {
+ auto itrCol = rParameters.find("COL");
+ if (itrCol == rParameters.end())
+ {
+ SAL_WARN("sc.uitest", "missing COL parameter");
+ return;
+ }
+
+ auto itrRow = rParameters.find("ROW");
+ if (itrRow == rParameters.end())
+ {
+ SAL_WARN("sc.uitest", "missing ROW parameter");
+ return;
+ }
+ SCROW nRow = itrRow->second.toUInt32();
+ SCCOL nCol = itrCol->second.toUInt32();
+ mxGridWindow->LaunchDPFieldMenu(nCol, nRow);
+ }
+ else if ( rParameters.find("SELECTMENU") != rParameters.end())
+ {
+ auto itrCol = rParameters.find("COL");
+ if (itrCol == rParameters.end())
+ {
+ SAL_WARN("sc.uitest", "missing COL parameter");
+ return;
+ }
+
+ auto itrRow = rParameters.find("ROW");
+ if (itrRow == rParameters.end())
+ {
+ SAL_WARN("sc.uitest", "missing ROW parameter");
+ return;
+ }
+ SCROW nRow = itrRow->second.toUInt32();
+ SCCOL nCol = itrCol->second.toUInt32();
+ mxGridWindow->LaunchDataSelectMenu(nCol, nRow);
+ }
+ }
+ else if (rAction == "COMMENT")
+ {
+ if ( rParameters.find("OPEN") != rParameters.end() )
+ {
+ ScViewFunc* pViewFunc = getViewFunc();
+ pViewFunc->EditNote();
+ }
+ else if ( rParameters.find("CLOSE") != rParameters.end() )
+ {
+ FuDraw* pDraw = dynamic_cast<FuDraw*>(getViewFunc()->GetDrawFuncPtr());
+ assert(pDraw);
+ ScViewData& rViewData = mxGridWindow->getViewData();
+ rViewData.GetDispatcher().Execute( pDraw->GetSlotID() , SfxCallMode::SLOT | SfxCallMode::RECORD );
+ }
+ else if ( rParameters.find("SETTEXT") != rParameters.end() )
+ {
+ auto itr = rParameters.find("SETTEXT");
+ const OUString rStr = itr->second;
+ ScDocument& rDoc = mxGridWindow->getViewData().GetDocument();
+ ScAddress aPos( mxGridWindow->getViewData().GetCurX() , mxGridWindow->getViewData().GetCurY() , mxGridWindow->getViewData().GetTabNo() );
+ rDoc.GetOrCreateNote( aPos )->SetText( aPos , rStr );
+ }
+ }
+ else if (rAction == "SIDEBAR")
+ {
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ DBG_ASSERT(pViewFrm, "ScGridWinUIObject::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 == "SET")
+ {
+ if (rParameters.find("ZOOM") != rParameters.end())
+ {
+ auto itr = rParameters.find("ZOOM");
+ OUString aVal = itr->second;
+ sal_Int32 nVal = aVal.toInt32();
+ ScTabViewShell* pViewShell = getViewShell();
+ ScModule* pScMod = SC_MOD();
+ if( nVal )
+ {
+ ScAppOptions aNewOpt = pScMod->GetAppOptions();
+ aNewOpt.SetZoom( nVal );
+ pScMod->SetAppOptions( aNewOpt );
+ Fraction aFract( nVal, 100 );
+ pViewShell->SetZoom( aFract, aFract, true );
+ pViewShell->PaintGrid();
+ pViewShell->PaintTop();
+ pViewShell->PaintLeft();
+ }
+ }
+ }
+ else
+ {
+ WindowUIObject::execute(rAction, rParameters);
+ }
+}
+
+namespace {
+
+ScDrawLayer* get_draw_layer(VclPtr<ScGridWindow> const & xGridWindow)
+{
+ return xGridWindow->getViewData().GetDocument().GetDrawLayer();
+}
+
+SdrPage* get_draw_page(VclPtr<ScGridWindow> const & xGridWindow, SCTAB nTab)
+{
+ ScDrawLayer* pDrawLayer = get_draw_layer(xGridWindow);
+
+ return pDrawLayer->GetPage(nTab);
+}
+
+std::set<OUString> collect_charts(VclPtr<ScGridWindow> const & xGridWindow)
+{
+ SCTAB nTab = xGridWindow->getViewData().GetTabNo();
+ SdrPage* pPage = get_draw_page(xGridWindow, nTab);
+
+ std::set<OUString> aRet;
+
+ if (!pPage)
+ return aRet;
+
+ SdrObjListIter aIter( pPage, SdrIterMode::Flat );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if (pObject->GetObjIdentifier() == SdrObjKind::OLE2)
+ {
+ aRet.insert(static_cast<SdrOle2Obj*>(pObject)->GetPersistName());
+ }
+ pObject = aIter.Next();
+ }
+
+ return aRet;
+}
+
+}
+
+std::set<OUString> ScGridWinUIObject::get_children() const
+{
+ std::set<OUString> aChildren = collect_charts(mxGridWindow);
+ return aChildren;
+}
+
+std::unique_ptr<UIObject> ScGridWinUIObject::get_child(const OUString& /*rID*/)
+{
+ return nullptr;
+}
+
+std::unique_ptr<UIObject> ScGridWinUIObject::create(vcl::Window* pWindow)
+{
+ ScGridWindow* pGridWin = dynamic_cast<ScGridWindow*>(pWindow);
+ assert(pGridWin);
+ return std::unique_ptr<UIObject>(new ScGridWinUIObject(pGridWin));
+}
+
+OUString ScGridWinUIObject::get_name() const
+{
+ return "ScGridWinUIObject";
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoDeleteSparkline.cxx b/sc/source/ui/undo/UndoDeleteSparkline.cxx
new file mode 100644
index 000000000..6c9df1809
--- /dev/null
+++ b/sc/source/ui/undo/UndoDeleteSparkline.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/.
+ *
+ */
+
+#include <undo/UndoDeleteSparkline.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+
+namespace sc
+{
+UndoDeleteSparkline::UndoDeleteSparkline(ScDocShell& rDocShell, ScAddress const& rSparklinePosition)
+ : ScSimpleUndo(&rDocShell)
+ , maSparklinePosition(rSparklinePosition)
+{
+}
+
+UndoDeleteSparkline::~UndoDeleteSparkline() {}
+
+void UndoDeleteSparkline::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ auto pSparkline = rDocument.GetSparkline(maSparklinePosition);
+ if (!pSparkline)
+ {
+ rDocument.CreateSparkline(maSparklinePosition, mpSparklineGroup);
+ }
+ else
+ {
+ SAL_WARN("sc", "Can't undo deletion if the sparkline at that address already exists.");
+ }
+
+ pDocShell->PostPaintCell(maSparklinePosition);
+
+ EndUndo();
+}
+
+void UndoDeleteSparkline::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ if (auto pSparkline = rDocument.GetSparkline(maSparklinePosition))
+ {
+ mpSparklineGroup = pSparkline->getSparklineGroup();
+ rDocument.DeleteSparkline(maSparklinePosition);
+ }
+ else
+ {
+ SAL_WARN("sc", "Can't delete a sparkline that donesn't exist.");
+ }
+
+ pDocShell->PostPaintCell(maSparklinePosition);
+
+ EndRedo();
+}
+
+void UndoDeleteSparkline::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoDeleteSparkline::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoDeleteSparkline::GetComment() const { return ScResId(STR_UNDO_DELETE_SPARKLINE); }
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoDeleteSparklineGroup.cxx b/sc/source/ui/undo/UndoDeleteSparklineGroup.cxx
new file mode 100644
index 000000000..9a8e4eb5d
--- /dev/null
+++ b/sc/source/ui/undo/UndoDeleteSparklineGroup.cxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <undo/UndoDeleteSparklineGroup.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <document.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineList.hxx>
+#include <SparklineGroup.hxx>
+
+namespace sc
+{
+UndoDeleteSparklineGroup::UndoDeleteSparklineGroup(
+ ScDocShell& rDocShell, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup, SCTAB nTab)
+ : ScSimpleUndo(&rDocShell)
+ , mpSparklineGroup(pSparklineGroup)
+ , mnTab(nTab)
+{
+}
+
+UndoDeleteSparklineGroup::~UndoDeleteSparklineGroup() {}
+
+void UndoDeleteSparklineGroup::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+
+ for (auto const& pSparkline : maSparklines)
+ {
+ ScAddress aAddress(pSparkline->getColumn(), pSparkline->getRow(), mnTab);
+ auto* pNewSparkline = rDocument.CreateSparkline(aAddress, mpSparklineGroup);
+ pNewSparkline->setInputRange(pSparkline->getInputRange());
+ }
+
+ pDocShell->PostPaintGridAll();
+
+ EndUndo();
+}
+
+void UndoDeleteSparklineGroup::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ auto* pList = rDocument.GetSparklineList(mnTab);
+ if (pList)
+ {
+ maSparklines = pList->getSparklinesFor(mpSparklineGroup);
+
+ for (auto const& pSparkline : maSparklines)
+ {
+ ScAddress aAddress(pSparkline->getColumn(), pSparkline->getRow(), mnTab);
+ rDocument.DeleteSparkline(aAddress);
+ }
+ }
+ pDocShell->PostPaintGridAll();
+
+ EndRedo();
+}
+
+void UndoDeleteSparklineGroup::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoDeleteSparklineGroup::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoDeleteSparklineGroup::GetComment() const
+{
+ return ScResId(STR_UNDO_DELETE_SPARKLINE_GROUP);
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoEditSparkline.cxx b/sc/source/ui/undo/UndoEditSparkline.cxx
new file mode 100644
index 000000000..b1f6f38f5
--- /dev/null
+++ b/sc/source/ui/undo/UndoEditSparkline.cxx
@@ -0,0 +1,63 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <undo/UndoEditSparkline.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+
+namespace sc
+{
+UndoEditSparkline::UndoEditSparkline(ScDocShell& rDocShell,
+ std::shared_ptr<sc::Sparkline> const& rpSparkline, SCTAB nTab,
+ ScRangeList const& rDataRange)
+ : ScSimpleUndo(&rDocShell)
+ , mpSparkline(rpSparkline)
+ , mnTab(nTab)
+ , maOldDataRange(mpSparkline->getInputRange())
+ , maNewDataRange(rDataRange)
+{
+}
+
+UndoEditSparkline::~UndoEditSparkline() = default;
+
+void UndoEditSparkline::Undo()
+{
+ BeginUndo();
+
+ mpSparkline->setInputRange(maOldDataRange);
+
+ pDocShell->PostPaintCell(ScAddress(mpSparkline->getColumn(), mpSparkline->getRow(), mnTab));
+
+ EndUndo();
+}
+
+void UndoEditSparkline::Redo()
+{
+ BeginRedo();
+
+ mpSparkline->setInputRange(maNewDataRange);
+
+ pDocShell->PostPaintCell(ScAddress(mpSparkline->getColumn(), mpSparkline->getRow(), mnTab));
+
+ EndRedo();
+}
+
+void UndoEditSparkline::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoEditSparkline::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoEditSparkline::GetComment() const { return ScResId(STR_UNDO_EDIT_SPARKLINE); }
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoEditSparklineGroup.cxx b/sc/source/ui/undo/UndoEditSparklineGroup.cxx
new file mode 100644
index 000000000..8136003d6
--- /dev/null
+++ b/sc/source/ui/undo/UndoEditSparklineGroup.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/.
+ *
+ */
+
+#include <undo/UndoEditSparklineGroup.hxx>
+
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
+namespace sc
+{
+UndoEditSparklneGroup::UndoEditSparklneGroup(
+ ScDocShell& rDocShell, std::shared_ptr<sc::SparklineGroup> const& pSparklineGroup,
+ sc::SparklineAttributes const& rAttributes)
+ : ScSimpleUndo(&rDocShell)
+ , m_pSparklineGroup(pSparklineGroup)
+ , m_aNewAttributes(rAttributes)
+ , m_aOriginalAttributes(pSparklineGroup->getAttributes())
+{
+}
+
+UndoEditSparklneGroup::~UndoEditSparklneGroup() = default;
+
+void UndoEditSparklneGroup::Undo()
+{
+ BeginUndo();
+
+ m_pSparklineGroup->setAttributes(m_aOriginalAttributes);
+ pDocShell->PostPaintGridAll();
+
+ EndUndo();
+}
+
+void UndoEditSparklneGroup::Redo()
+{
+ BeginRedo();
+
+ m_pSparklineGroup->setAttributes(m_aNewAttributes);
+ pDocShell->PostPaintGridAll();
+
+ EndRedo();
+}
+
+void UndoEditSparklneGroup::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoEditSparklneGroup::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoEditSparklneGroup::GetComment() const
+{
+ return ScResId(STR_UNDO_EDIT_SPARKLINE_GROUP);
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoGroupSparklines.cxx b/sc/source/ui/undo/UndoGroupSparklines.cxx
new file mode 100644
index 000000000..ac2182714
--- /dev/null
+++ b/sc/source/ui/undo/UndoGroupSparklines.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/.
+ *
+ */
+
+#include <undo/UndoGroupSparklines.hxx>
+
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
+namespace sc
+{
+UndoGroupSparklines::UndoGroupSparklines(
+ ScDocShell& rDocShell, ScRange const& rRange,
+ std::shared_ptr<sc::SparklineGroup> const& rpSparklineGroup)
+ : ScSimpleUndo(&rDocShell)
+ , m_aRange(rRange)
+ , m_pSparklineGroup(rpSparklineGroup)
+{
+}
+
+UndoGroupSparklines::~UndoGroupSparklines() = default;
+
+void UndoGroupSparklines::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+
+ for (auto& rUndoData : m_aUndoData)
+ {
+ rDocument.DeleteSparkline(rUndoData.m_aAddress);
+ auto* pCreated
+ = rDocument.CreateSparkline(rUndoData.m_aAddress, rUndoData.m_pSparklineGroup);
+ pCreated->setInputRange(rUndoData.m_aDataRangeList);
+ }
+
+ m_aUndoData.clear();
+
+ pDocShell->PostPaint(m_aRange, PaintPartFlags::All);
+
+ EndUndo();
+}
+
+void UndoGroupSparklines::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+
+ for (ScAddress aAddress = m_aRange.aStart; aAddress.Col() <= m_aRange.aEnd.Col();
+ aAddress.IncCol())
+ {
+ aAddress.SetRow(m_aRange.aStart.Row());
+ for (; aAddress.Row() <= m_aRange.aEnd.Row(); aAddress.IncRow())
+ {
+ if (auto pSparkline = rDocument.GetSparkline(aAddress))
+ {
+ m_aUndoData.emplace_back(aAddress, pSparkline->getInputRange(),
+ pSparkline->getSparklineGroup());
+
+ rDocument.DeleteSparkline(aAddress);
+ auto* pCreated = rDocument.CreateSparkline(aAddress, m_pSparklineGroup);
+ pCreated->setInputRange(pSparkline->getInputRange());
+ }
+ }
+ }
+
+ pDocShell->PostPaint(m_aRange, PaintPartFlags::All);
+
+ EndRedo();
+}
+
+void UndoGroupSparklines::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoGroupSparklines::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoGroupSparklines::GetComment() const { return ScResId(STR_UNDO_GROUP_SPARKLINES); }
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoInsertSparkline.cxx b/sc/source/ui/undo/UndoInsertSparkline.cxx
new file mode 100644
index 000000000..c35cc3f6d
--- /dev/null
+++ b/sc/source/ui/undo/UndoInsertSparkline.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/.
+ *
+ */
+
+#include <undo/UndoInsertSparkline.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineData.hxx>
+
+namespace sc
+{
+UndoInsertSparkline::UndoInsertSparkline(ScDocShell& rDocShell,
+ std::vector<SparklineData> const& rSparklineDataVector,
+ std::shared_ptr<sc::SparklineGroup> pSparklineGroup)
+ : ScSimpleUndo(&rDocShell)
+ , maSparklineDataVector(rSparklineDataVector)
+ , mpSparklineGroup(pSparklineGroup)
+{
+}
+
+UndoInsertSparkline::~UndoInsertSparkline() {}
+
+void UndoInsertSparkline::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ ScRangeList aRanges;
+ for (auto const& rSparklineData : maSparklineDataVector)
+ {
+ rDocument.DeleteSparkline(rSparklineData.maPosition);
+ aRanges.push_back(ScRange(rSparklineData.maPosition));
+ }
+
+ pDocShell->PostPaint(aRanges, PaintPartFlags::All);
+
+ EndUndo();
+}
+
+void UndoInsertSparkline::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ ScRangeList aRanges;
+ for (auto const& rSparklineData : maSparklineDataVector)
+ {
+ auto* pCreated = rDocument.CreateSparkline(rSparklineData.maPosition, mpSparklineGroup);
+ pCreated->setInputRange(rSparklineData.maData);
+ aRanges.push_back(ScRange(rSparklineData.maPosition));
+ }
+
+ pDocShell->PostPaint(aRanges, PaintPartFlags::All);
+
+ EndRedo();
+}
+
+void UndoInsertSparkline::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoInsertSparkline::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoInsertSparkline::GetComment() const
+{
+ return ScResId(STR_UNDO_INSERT_SPARKLINE_GROUP);
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/UndoUngroupSparklines.cxx b/sc/source/ui/undo/UndoUngroupSparklines.cxx
new file mode 100644
index 000000000..fe0201eb6
--- /dev/null
+++ b/sc/source/ui/undo/UndoUngroupSparklines.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/.
+ *
+ */
+
+#include <undo/UndoUngroupSparklines.hxx>
+
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+#include <SparklineAttributes.hxx>
+
+namespace sc
+{
+UndoUngroupSparklines::UndoUngroupSparklines(ScDocShell& rDocShell, ScRange const& rRange)
+ : ScSimpleUndo(&rDocShell)
+ , m_aRange(rRange)
+{
+}
+
+UndoUngroupSparklines::~UndoUngroupSparklines() = default;
+
+void UndoUngroupSparklines::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+
+ for (SparklineUndoData& rUndoData : m_aUndoData)
+ {
+ rDocument.DeleteSparkline(rUndoData.m_aAddress);
+ auto* pCreated
+ = rDocument.CreateSparkline(rUndoData.m_aAddress, rUndoData.m_pSparklineGroup);
+ pCreated->setInputRange(rUndoData.m_aDataRangeList);
+ }
+
+ m_aUndoData.clear();
+
+ pDocShell->PostPaint(m_aRange, PaintPartFlags::All);
+
+ EndUndo();
+}
+
+void UndoUngroupSparklines::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+
+ for (ScAddress aAddress = m_aRange.aStart; aAddress.Col() <= m_aRange.aEnd.Col();
+ aAddress.IncCol())
+ {
+ aAddress.SetRow(m_aRange.aStart.Row());
+ for (; aAddress.Row() <= m_aRange.aEnd.Row(); aAddress.IncRow())
+ {
+ if (auto pSparkline = rDocument.GetSparkline(aAddress))
+ {
+ auto const& rpGroup = pSparkline->getSparklineGroup();
+ m_aUndoData.emplace_back(aAddress, pSparkline->getInputRange(), rpGroup);
+ auto pSparklineGroupCopy
+ = std::make_shared<sc::SparklineGroup>(rpGroup->getAttributes());
+ rDocument.DeleteSparkline(aAddress);
+ auto* pCreated = rDocument.CreateSparkline(aAddress, pSparklineGroupCopy);
+ pCreated->setInputRange(pSparkline->getInputRange());
+ }
+ }
+ }
+
+ pDocShell->PostPaint(m_aRange, PaintPartFlags::All);
+
+ EndRedo();
+}
+
+void UndoUngroupSparklines::Repeat(SfxRepeatTarget& /*rTarget*/) {}
+
+bool UndoUngroupSparklines::CanRepeat(SfxRepeatTarget& /*rTarget*/) const { return false; }
+
+OUString UndoUngroupSparklines::GetComment() const { return ScResId(STR_UNDO_UNGROUP_SPARKLINES); }
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/areasave.cxx b/sc/source/ui/undo/areasave.cxx
new file mode 100644
index 000000000..f675c1abc
--- /dev/null
+++ b/sc/source/ui/undo/areasave.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 <sfx2/linkmgr.hxx>
+
+#include <areasave.hxx>
+#include <arealink.hxx>
+#include <document.hxx>
+#include <documentlinkmgr.hxx>
+
+ScAreaLinkSaver::ScAreaLinkSaver( const ScAreaLink& rSource ) :
+ aFileName ( rSource.GetFile() ),
+ aFilterName ( rSource.GetFilter() ),
+ aOptions ( rSource.GetOptions() ),
+ aSourceArea ( rSource.GetSource() ),
+ aDestArea ( rSource.GetDestArea() ),
+ nRefreshDelaySeconds ( rSource.GetRefreshDelaySeconds() ) // seconds
+{
+}
+
+bool ScAreaLinkSaver::IsEqualSource( const ScAreaLink& rCompare ) const
+{
+ return ( aFileName == rCompare.GetFile() &&
+ aFilterName == rCompare.GetFilter() &&
+ aOptions == rCompare.GetOptions() &&
+ aSourceArea == rCompare.GetSource() &&
+ nRefreshDelaySeconds == rCompare.GetRefreshDelaySeconds() );
+}
+
+bool ScAreaLinkSaver::IsEqual( const ScAreaLink& rCompare ) const
+{
+ return ( IsEqualSource( rCompare ) &&
+ aDestArea == rCompare.GetDestArea() );
+}
+
+void ScAreaLinkSaver::WriteToLink( ScAreaLink& rLink ) const
+{
+ rLink.SetDestArea( aDestArea );
+}
+
+void ScAreaLinkSaver::InsertNewLink( ScDocument* pDoc )
+{
+ // (see ScUndoRemoveAreaLink::Undo)
+
+ sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
+ SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
+
+ if ( pLinkManager && pObjSh )
+ {
+ ScAreaLink* pLink = new ScAreaLink( pObjSh, aFileName, aFilterName, aOptions,
+ aSourceArea, aDestArea.aStart, nRefreshDelaySeconds );
+ pLink->SetInCreate( true );
+ pLink->SetDestArea( aDestArea );
+ OUString aTmp1(aFilterName), aTmp2(aSourceArea);
+ pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aFileName, &aTmp1, &aTmp2 );
+ pLink->Update();
+ pLink->SetInCreate( false );
+ }
+}
+
+ScAreaLinkSaveCollection::ScAreaLinkSaveCollection() {}
+
+ScAreaLinkSaveCollection::~ScAreaLinkSaveCollection() {}
+
+bool ScAreaLinkSaveCollection::IsEqual( const ScDocument* pDoc ) const
+{
+ // IsEqual can be checked in sequence.
+ // Neither ref-update nor removing links will change the order.
+
+ const sfx2::LinkManager* pLinkManager = pDoc->GetLinkManager();
+ if (pLinkManager)
+ {
+ size_t nPos = 0;
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nLinkCount = rLinks.size();
+ for (sal_uInt16 i=0; i<nLinkCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if (auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase))
+ {
+ if ( nPos >= size() || !(*this)[nPos].IsEqual( *pAreaLink ) )
+ return false;
+
+ ++nPos;
+ }
+ }
+ if ( nPos < size() )
+ return false; // fewer links in the document than in the save collection
+ }
+
+ return true;
+}
+
+static ScAreaLink* lcl_FindLink( const ::sfx2::SvBaseLinks& rLinks, const ScAreaLinkSaver& rSaver )
+{
+ sal_uInt16 nLinkCount = rLinks.size();
+ for (sal_uInt16 i=0; i<nLinkCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if ( auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase) )
+ if ( rSaver.IsEqualSource( *pAreaLink ) )
+ return pAreaLink; // found
+ }
+ return nullptr; // not found
+}
+
+void ScAreaLinkSaveCollection::Restore( ScDocument* pDoc )
+{
+ // The save collection may contain additional entries that are not in the document.
+ // They must be inserted again.
+ // Entries from the save collection must be searched via source data, as the order
+ // of links changes if deleted entries are re-added to the link manager (always at the end).
+
+ sfx2::LinkManager* pLinkManager = pDoc->GetDocLinkManager().getLinkManager(false);
+ if (!pLinkManager)
+ return;
+
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ size_t nSaveCount = size();
+ for (size_t nPos=0; nPos<nSaveCount; ++nPos)
+ {
+ ScAreaLinkSaver& rSaver = (*this)[nPos];
+ ScAreaLink* pLink = lcl_FindLink( rLinks, rSaver );
+ if ( pLink )
+ rSaver.WriteToLink( *pLink ); // restore output position
+ else
+ rSaver.InsertNewLink( pDoc ); // re-insert deleted link
+ }
+}
+
+std::unique_ptr<ScAreaLinkSaveCollection> ScAreaLinkSaveCollection::CreateFromDoc( const ScDocument* pDoc )
+{
+ std::unique_ptr<ScAreaLinkSaveCollection> pColl;
+
+ sfx2::LinkManager* pLinkManager = const_cast<ScDocument*>(pDoc)->GetLinkManager();
+ if (pLinkManager)
+ {
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nLinkCount = rLinks.size();
+ for (sal_uInt16 i=0; i<nLinkCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if (auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase))
+ {
+ if (!pColl)
+ pColl.reset(new ScAreaLinkSaveCollection);
+
+ pColl->push_back( ScAreaLinkSaver( *pAreaLink ) );
+ }
+ }
+ }
+
+ return pColl;
+}
+
+ScAreaLinkSaver& ScAreaLinkSaveCollection::operator [](size_t nIndex)
+{
+ return maData[nIndex];
+}
+
+const ScAreaLinkSaver& ScAreaLinkSaveCollection::operator [](size_t nIndex) const
+{
+ return maData[nIndex];
+}
+
+size_t ScAreaLinkSaveCollection::size() const
+{
+ return maData.size();
+}
+
+void ScAreaLinkSaveCollection::push_back(const ScAreaLinkSaver& p)
+{
+ maData.push_back(p);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/refundo.cxx b/sc/source/ui/undo/refundo.cxx
new file mode 100644
index 000000000..d87098720
--- /dev/null
+++ b/sc/source/ui/undo/refundo.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 <refundo.hxx>
+#include <document.hxx>
+#include <dbdata.hxx>
+#include <rangenam.hxx>
+#include <detdata.hxx>
+#include <prnsave.hxx>
+#include <chartlis.hxx>
+#include <dpobject.hxx>
+#include <areasave.hxx>
+#include <unoreflist.hxx>
+#include <scopetools.hxx>
+#include <refupdatecontext.hxx>
+
+ScRefUndoData::ScRefUndoData( const ScDocument* pDoc ) :
+ pPrintRanges(pDoc->CreatePrintRangeSaver())
+{
+ const ScDBCollection* pOldDBColl = pDoc->GetDBCollection();
+ if (pOldDBColl && !pOldDBColl->empty())
+ pDBCollection.reset(new ScDBCollection(*pOldDBColl));
+
+ const ScRangeName* pOldRanges = pDoc->GetRangeName();
+ if (pOldRanges && !pOldRanges->empty())
+ pRangeName.reset(new ScRangeName(*pOldRanges));
+
+ // when handling Pivot solely keep the range?
+
+ const ScDPCollection* pOldDP = pDoc->GetDPCollection();
+ if (pOldDP && pOldDP->GetCount())
+ pDPCollection.reset(new ScDPCollection(*pOldDP));
+
+ const ScDetOpList* pOldDetOp = pDoc->GetDetOpList();
+ if (pOldDetOp && pOldDetOp->Count())
+ pDetOpList.reset(new ScDetOpList(*pOldDetOp));
+
+ const ScChartListenerCollection* pOldChartLisColl = pDoc->GetChartListenerCollection();
+ if (pOldChartLisColl)
+ pChartListenerCollection.reset(new ScChartListenerCollection(*pOldChartLisColl));
+
+ pAreaLinks = ScAreaLinkSaveCollection::CreateFromDoc(pDoc); // returns NULL if empty
+
+ const_cast<ScDocument*>(pDoc)->BeginUnoRefUndo();
+}
+
+ScRefUndoData::~ScRefUndoData()
+{
+ pDBCollection.reset();
+ pRangeName.reset();
+ pPrintRanges.reset();
+ pDPCollection.reset();
+ pDetOpList.reset();
+ pChartListenerCollection.reset();
+ pAreaLinks.reset();
+}
+
+void ScRefUndoData::DeleteUnchanged( const ScDocument* pDoc )
+{
+ if (pDBCollection)
+ {
+ ScDBCollection* pNewDBColl = pDoc->GetDBCollection();
+ if ( pNewDBColl && *pDBCollection == *pNewDBColl )
+ pDBCollection.reset();
+ }
+ if (pRangeName)
+ {
+ ScRangeName* pNewRanges = pDoc->GetRangeName();
+ if ( pNewRanges && *pRangeName == *pNewRanges )
+ pRangeName.reset();
+ }
+
+ if (pPrintRanges)
+ {
+ std::unique_ptr<ScPrintRangeSaver> pNewRanges = pDoc->CreatePrintRangeSaver();
+ if ( pNewRanges && *pPrintRanges == *pNewRanges )
+ pPrintRanges.reset();
+ }
+
+ if (pDPCollection)
+ {
+ ScDPCollection* pNewDP = const_cast<ScDocument*>(pDoc)->GetDPCollection(); //! const
+ if ( pNewDP && pDPCollection->RefsEqual(*pNewDP) )
+ pDPCollection.reset();
+ }
+
+ if (pDetOpList)
+ {
+ ScDetOpList* pNewDetOp = pDoc->GetDetOpList();
+ if ( pNewDetOp && *pDetOpList == *pNewDetOp )
+ pDetOpList.reset();
+ }
+
+ if ( pChartListenerCollection )
+ {
+ ScChartListenerCollection* pNewChartListenerCollection =
+ pDoc->GetChartListenerCollection();
+ if ( pNewChartListenerCollection &&
+ *pChartListenerCollection == *pNewChartListenerCollection )
+ pChartListenerCollection.reset();
+ }
+
+ if (pAreaLinks)
+ {
+ if ( pAreaLinks->IsEqual( pDoc ) )
+ pAreaLinks.reset();
+ }
+
+ if ( pDoc->HasUnoRefUndo() )
+ {
+ pUnoRefs = const_cast<ScDocument*>(pDoc)->EndUnoRefUndo();
+ if ( pUnoRefs && pUnoRefs->IsEmpty() )
+ {
+ pUnoRefs.reset();
+ }
+ }
+}
+
+void ScRefUndoData::DoUndo( ScDocument* pDoc, bool bUndoRefFirst )
+{
+ if (pDBCollection)
+ pDoc->SetDBCollection( std::unique_ptr<ScDBCollection>(new ScDBCollection(*pDBCollection)) );
+ if (pRangeName)
+ pDoc->SetRangeName( std::unique_ptr<ScRangeName>(new ScRangeName(*pRangeName)) );
+
+ if (pPrintRanges)
+ pDoc->RestorePrintRanges(*pPrintRanges);
+
+ if (pDPCollection)
+ {
+ ScDPCollection* pDocDP = pDoc->GetDPCollection();
+ if (pDocDP)
+ pDPCollection->WriteRefsTo( *pDocDP );
+ }
+
+ if (pDetOpList)
+ pDoc->SetDetOpList( std::unique_ptr<ScDetOpList>(new ScDetOpList(*pDetOpList)) );
+
+ // bUndoRefFirst is bSetChartRangeLists
+ if ( pChartListenerCollection )
+ pDoc->SetChartListenerCollection( std::make_unique<ScChartListenerCollection>(
+ *pChartListenerCollection ), bUndoRefFirst );
+
+ if (pDBCollection || pRangeName)
+ {
+ sc::AutoCalcSwitch aACSwitch(*pDoc, false);
+ pDoc->CompileAll();
+
+ sc::SetFormulaDirtyContext aCxt;
+ pDoc->SetAllFormulasDirty(aCxt);
+ }
+
+ if (pAreaLinks)
+ pAreaLinks->Restore( pDoc );
+
+ if ( pUnoRefs )
+ pUnoRefs->Undo( pDoc );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/target.cxx b/sc/source/ui/undo/target.cxx
new file mode 100644
index 000000000..ee220b633
--- /dev/null
+++ b/sc/source/ui/undo/target.cxx
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <target.hxx>
+
+ScTabViewTarget::~ScTabViewTarget() {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undobase.cxx b/sc/source/ui/undo/undobase.cxx
new file mode 100644
index 000000000..8ce8bc9e8
--- /dev/null
+++ b/sc/source/ui/undo/undobase.cxx
@@ -0,0 +1,616 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/virdev.hxx>
+#include <svx/svdundo.hxx>
+
+#include <undobase.hxx>
+#include <refundo.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <undoolk.hxx>
+#include <undodraw.hxx>
+#include <dbdata.hxx>
+#include <attrib.hxx>
+#include <queryparam.hxx>
+#include <subtotalparam.hxx>
+#include <rowheightcontext.hxx>
+#include <column.hxx>
+#include <sortparam.hxx>
+#include <columnspanset.hxx>
+
+
+ScSimpleUndo::ScSimpleUndo( ScDocShell* pDocSh ) :
+ pDocShell( pDocSh ),
+ mnViewShellId(-1)
+{
+ if (ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell())
+ mnViewShellId = pViewShell->GetViewShellId();
+}
+
+ViewShellId ScSimpleUndo::GetViewShellId() const
+{
+ return mnViewShellId;
+}
+
+bool ScSimpleUndo::SetViewMarkData( const ScMarkData& rMarkData )
+{
+ if ( IsPaintLocked() )
+ return false;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( !pViewShell )
+ return false;
+
+ pViewShell->SetMarkData( rMarkData );
+ return true;
+}
+
+bool ScSimpleUndo::Merge( SfxUndoAction *pNextAction )
+{
+ // A SdrUndoGroup for updating detective arrows can belong
+ // to each Undo-Action.
+ // DetectiveRefresh is always called next,
+ // the SdrUndoGroup is encapsulated in a ScUndoDraw action.
+ // AddUndoAction is only called with bTryMerg=sal_True
+ // for automatic update.
+
+ if ( !pDetectiveUndo && dynamic_cast<const ScUndoDraw*>( pNextAction) != nullptr )
+ {
+ // Take SdrUndoAction from ScUndoDraw Action,
+ // ScUndoDraw is later deleted by the UndoManager
+
+ ScUndoDraw* pCalcUndo = static_cast<ScUndoDraw*>(pNextAction);
+ pDetectiveUndo = pCalcUndo->ReleaseDrawUndo();
+ return true;
+ }
+
+ return false;
+}
+
+void ScSimpleUndo::BeginUndo()
+{
+ pDocShell->SetInUndo( true );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->HideAllCursors(); // for example due to merged cells
+
+ // detective updates happened last, must be undone first
+ if (pDetectiveUndo)
+ pDetectiveUndo->Undo();
+}
+
+namespace
+{
+ class DisableUndoGuard
+ {
+ private:
+ ScDocument& m_rDoc;
+ bool m_bUndoEnabled;
+ public:
+ explicit DisableUndoGuard(ScDocShell *pDocShell)
+ : m_rDoc(pDocShell->GetDocument())
+ , m_bUndoEnabled(m_rDoc.IsUndoEnabled())
+ {
+ m_rDoc.EnableUndo(false);
+ }
+
+ ~DisableUndoGuard()
+ {
+ m_rDoc.EnableUndo(m_bUndoEnabled);
+ }
+ };
+}
+
+void ScSimpleUndo::EndUndo()
+{
+ {
+ // rhbz#1352881 Temporarily turn off undo generation during
+ // SetDocumentModified
+ DisableUndoGuard aGuard(pDocShell);
+ pDocShell->SetDocumentModified();
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->UpdateAutoFillMark();
+ pViewShell->UpdateInputHandler();
+ pViewShell->ShowAllCursors();
+ }
+
+ pDocShell->SetInUndo( false );
+}
+
+void ScSimpleUndo::BeginRedo()
+{
+ pDocShell->SetInUndo( true ); //! own Flag for Redo?
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->HideAllCursors(); // for example due to merged cells
+}
+
+void ScSimpleUndo::EndRedo()
+{
+ if (pDetectiveUndo)
+ pDetectiveUndo->Redo();
+
+ {
+ // rhbz#1352881 Temporarily turn off undo generation during
+ // SetDocumentModified
+ DisableUndoGuard aGuard(pDocShell);
+ pDocShell->SetDocumentModified();
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->UpdateAutoFillMark();
+ pViewShell->UpdateInputHandler();
+ pViewShell->ShowAllCursors();
+ }
+
+ pDocShell->SetInUndo( false );
+}
+
+void ScSimpleUndo::BroadcastChanges( const ScRange& rRange )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.BroadcastCells(rRange, SfxHintId::ScDataChanged);
+}
+
+namespace {
+
+class SpanBroadcaster : public sc::ColumnSpanSet::ColumnAction
+{
+ ScDocument& mrDoc;
+ SCTAB mnCurTab;
+ SCCOL mnCurCol;
+
+public:
+ explicit SpanBroadcaster( ScDocument& rDoc ) : mrDoc(rDoc), mnCurTab(-1), mnCurCol(-1) {}
+
+ virtual void startColumn( ScColumn* pCol ) override
+ {
+ mnCurTab = pCol->GetTab();
+ mnCurCol = pCol->GetCol();
+ }
+
+ virtual void execute( SCROW nRow1, SCROW nRow2, bool bVal ) override
+ {
+ if (!bVal)
+ return;
+
+ ScRange aRange(mnCurCol, nRow1, mnCurTab, mnCurCol, nRow2, mnCurTab);
+ mrDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
+ };
+};
+
+}
+
+void ScSimpleUndo::BroadcastChanges( const DataSpansType& rSpans )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SpanBroadcaster aBroadcaster(rDoc);
+
+ for (const auto& rEntry : rSpans)
+ {
+ const sc::ColumnSpanSet& rSet = *rEntry.second;
+ rSet.executeColumnAction(rDoc, aBroadcaster);
+ }
+}
+
+void ScSimpleUndo::ShowTable( SCTAB nTab )
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo( nTab );
+}
+
+void ScSimpleUndo::ShowTable( const ScRange& rRange )
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ SCTAB nStart = rRange.aStart.Tab();
+ SCTAB nEnd = rRange.aEnd.Tab();
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ if ( nTab < nStart || nTab > nEnd ) // if not in range:
+ pViewShell->SetTabNo( nStart ); // at beginning of the range
+ }
+}
+
+ScBlockUndo::ScBlockUndo( ScDocShell* pDocSh, const ScRange& rRange,
+ ScBlockUndoMode eBlockMode ) :
+ ScSimpleUndo( pDocSh ),
+ aBlockRange( rRange ),
+ eMode( eBlockMode )
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScBlockUndo::~ScBlockUndo()
+{
+ pDrawUndo.reset();
+}
+
+void ScBlockUndo::BeginUndo()
+{
+ ScSimpleUndo::BeginUndo();
+ EnableDrawAdjust( &pDocShell->GetDocument(), false );
+}
+
+void ScBlockUndo::EndUndo()
+{
+ if (eMode == SC_UNDO_AUTOHEIGHT)
+ AdjustHeight();
+
+ EnableDrawAdjust( &pDocShell->GetDocument(), true );
+ DoSdrUndoAction( pDrawUndo.get(), &pDocShell->GetDocument() );
+
+ ShowBlock();
+ ScSimpleUndo::EndUndo();
+}
+
+void ScBlockUndo::EndRedo()
+{
+ if (eMode == SC_UNDO_AUTOHEIGHT)
+ AdjustHeight();
+
+ ShowBlock();
+ ScSimpleUndo::EndRedo();
+}
+
+bool ScBlockUndo::AdjustHeight()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ Fraction aZoomX( 1, 1 );
+ Fraction aZoomY = aZoomX;
+ double nPPTX, nPPTY;
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ ScViewData& rData = pViewShell->GetViewData();
+ nPPTX = rData.GetPPTX();
+ nPPTY = rData.GetPPTY();
+ aZoomX = rData.GetZoomX();
+ aZoomY = rData.GetZoomY();
+ }
+ else
+ {
+ // Leave zoom at 100
+ nPPTX = ScGlobal::nScreenPPTX;
+ nPPTY = ScGlobal::nScreenPPTY;
+ }
+
+ sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, aZoomX, aZoomY, pVirtDev);
+ bool bRet = rDoc.SetOptimalHeight(
+ aCxt, aBlockRange.aStart.Row(), aBlockRange.aEnd.Row(), aBlockRange.aStart.Tab(), true);
+
+ if (bRet)
+ {
+ // tdf#76183: recalculate objects' positions
+ rDoc.SetDrawPageSize(aBlockRange.aStart.Tab());
+
+ pDocShell->PostPaint( 0, aBlockRange.aStart.Row(), aBlockRange.aStart.Tab(),
+ rDoc.MaxCol(), rDoc.MaxRow(), aBlockRange.aEnd.Tab(),
+ PaintPartFlags::Grid | PaintPartFlags::Left );
+ }
+ return bRet;
+}
+
+void ScBlockUndo::ShowBlock()
+{
+ if ( IsPaintLocked() )
+ return;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (!pViewShell)
+ return;
+
+ ShowTable( aBlockRange ); // with multiple sheets in range each of them is good
+ pViewShell->MoveCursorAbs( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
+ SC_FOLLOW_JUMP, false, false );
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ ScRange aRange = aBlockRange;
+ aRange.aStart.SetTab( nTab );
+ aRange.aEnd.SetTab( nTab );
+ pViewShell->MarkRange( aRange );
+
+ // not through SetMarkArea to MarkData, due to possibly lacking paint
+}
+
+ScMultiBlockUndo::ScMultiBlockUndo(
+ ScDocShell* pDocSh, const ScRangeList& rRanges) :
+ ScSimpleUndo(pDocSh),
+ maBlockRanges(rRanges)
+{
+ mpDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScMultiBlockUndo::~ScMultiBlockUndo()
+{
+ mpDrawUndo.reset();
+}
+
+void ScMultiBlockUndo::BeginUndo()
+{
+ ScSimpleUndo::BeginUndo();
+ EnableDrawAdjust(&pDocShell->GetDocument(), false);
+}
+
+void ScMultiBlockUndo::EndUndo()
+{
+ EnableDrawAdjust(&pDocShell->GetDocument(), true);
+ DoSdrUndoAction(mpDrawUndo.get(), &pDocShell->GetDocument());
+
+ ShowBlock();
+ ScSimpleUndo::EndUndo();
+}
+
+void ScMultiBlockUndo::EndRedo()
+{
+ ShowBlock();
+ ScSimpleUndo::EndRedo();
+}
+
+void ScMultiBlockUndo::ShowBlock()
+{
+ if ( IsPaintLocked() )
+ return;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (!pViewShell)
+ return;
+
+ if (maBlockRanges.empty())
+ return;
+
+ // Move to the sheet of the first range.
+ ScRange aRange = maBlockRanges.front();
+ ShowTable(aRange);
+ pViewShell->MoveCursorAbs(
+ aRange.aStart.Col(), aRange.aStart.Row(), SC_FOLLOW_JUMP, false, false);
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ aRange.aStart.SetTab(nTab);
+ aRange.aEnd.SetTab(nTab);
+ pViewShell->MarkRange(aRange, false);
+
+ for (size_t i = 1, n = maBlockRanges.size(); i < n; ++i)
+ {
+ aRange = maBlockRanges[i];
+ aRange.aStart.SetTab(nTab);
+ aRange.aEnd.SetTab(nTab);
+ pViewShell->MarkRange(aRange, false, true);
+ }
+}
+
+ScMoveUndo::ScMoveUndo( ScDocShell* pDocSh, ScDocumentUniquePtr pRefDoc, std::unique_ptr<ScRefUndoData> pRefData ) :
+ ScSimpleUndo( pDocSh ),
+ pRefUndoDoc( std::move(pRefDoc) ),
+ pRefUndoData( std::move(pRefData) )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (pRefUndoData)
+ pRefUndoData->DeleteUnchanged(&rDoc);
+ pDrawUndo = GetSdrUndoAction( &rDoc );
+}
+
+ScMoveUndo::~ScMoveUndo()
+{
+ pRefUndoData.reset();
+ pRefUndoDoc.reset();
+ pDrawUndo.reset();
+}
+
+void ScMoveUndo::UndoRef()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRange aRange(0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),pRefUndoDoc->GetTableCount()-1);
+ pRefUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::FORMULA, false, rDoc, nullptr, false);
+ if (pRefUndoData)
+ pRefUndoData->DoUndo( &rDoc, false );
+}
+
+void ScMoveUndo::BeginUndo()
+{
+ ScSimpleUndo::BeginUndo();
+
+ EnableDrawAdjust( &pDocShell->GetDocument(), false );
+}
+
+void ScMoveUndo::EndUndo()
+{
+ DoSdrUndoAction( pDrawUndo.get(), &pDocShell->GetDocument() ); // must also be called when pointer is null
+
+ if (pRefUndoDoc)
+ UndoRef();
+
+ EnableDrawAdjust( &pDocShell->GetDocument(), true );
+
+ ScSimpleUndo::EndUndo();
+}
+
+ScDBFuncUndo::ScDBFuncUndo( ScDocShell* pDocSh, const ScRange& rOriginal ) :
+ ScSimpleUndo( pDocSh ),
+ aOriginalRange( rOriginal )
+{
+ pAutoDBRange = pDocSh->GetOldAutoDBRange();
+}
+
+ScDBFuncUndo::~ScDBFuncUndo()
+{
+ pAutoDBRange.reset();
+}
+
+void ScDBFuncUndo::BeginUndo()
+{
+ ScSimpleUndo::BeginUndo();
+ DoSdrUndoAction( nullptr, &pDocShell->GetDocument() );
+}
+
+void ScDBFuncUndo::EndUndo()
+{
+ ScSimpleUndo::EndUndo();
+
+ if ( !pAutoDBRange )
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab = rDoc.GetVisibleTab();
+ ScDBData* pNoNameData = rDoc.GetAnonymousDBData(nTab);
+ if (!pNoNameData )
+ return;
+
+ SCCOL nRangeX1;
+ SCROW nRangeY1;
+ SCCOL nRangeX2;
+ SCROW nRangeY2;
+ SCTAB nRangeTab;
+ pNoNameData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
+ pDocShell->DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2 );
+
+ *pNoNameData = *pAutoDBRange;
+
+ if ( pAutoDBRange->HasAutoFilter() )
+ {
+ // restore AutoFilter buttons
+ pAutoDBRange->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
+ rDoc.ApplyFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, ScMF::Auto );
+ pDocShell->PostPaint( nRangeX1, nRangeY1, nRangeTab, nRangeX2, nRangeY1, nRangeTab, PaintPartFlags::Grid );
+ }
+}
+
+void ScDBFuncUndo::BeginRedo()
+{
+ RedoSdrUndoAction( nullptr );
+ if ( pAutoDBRange )
+ {
+ // move the database range to this function's position again (see ScDocShell::GetDBData)
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDBData* pNoNameData = rDoc.GetAnonymousDBData(aOriginalRange.aStart.Tab());
+ if ( pNoNameData )
+ {
+
+ SCCOL nRangeX1;
+ SCROW nRangeY1;
+ SCCOL nRangeX2;
+ SCROW nRangeY2;
+ SCTAB nRangeTab;
+ pNoNameData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
+ pDocShell->DBAreaDeleted( nRangeTab, nRangeX1, nRangeY1, nRangeX2 );
+
+ pNoNameData->SetSortParam( ScSortParam() );
+ pNoNameData->SetQueryParam( ScQueryParam() );
+ pNoNameData->SetSubTotalParam( ScSubTotalParam() );
+
+ pNoNameData->SetArea( aOriginalRange.aStart.Tab(),
+ aOriginalRange.aStart.Col(), aOriginalRange.aStart.Row(),
+ aOriginalRange.aEnd.Col(), aOriginalRange.aEnd.Row() );
+
+ pNoNameData->SetByRow( true );
+ pNoNameData->SetAutoFilter( false );
+ // header is always set with the operation in redo
+ }
+ }
+
+ ScSimpleUndo::BeginRedo();
+}
+
+void ScDBFuncUndo::EndRedo()
+{
+ ScSimpleUndo::EndRedo();
+}
+
+ScUndoWrapper::ScUndoWrapper( std::unique_ptr<SfxUndoAction> pUndo ) :
+ pWrappedUndo( std::move(pUndo) ),
+ mnViewShellId( -1 )
+{
+ if (pWrappedUndo)
+ mnViewShellId = pWrappedUndo->GetViewShellId();
+}
+
+ScUndoWrapper::~ScUndoWrapper()
+{
+}
+
+void ScUndoWrapper::ForgetWrappedUndo()
+{
+ pWrappedUndo = nullptr; // don't delete in dtor - pointer must be stored outside
+}
+
+OUString ScUndoWrapper::GetComment() const
+{
+ if (pWrappedUndo)
+ return pWrappedUndo->GetComment();
+ return OUString();
+}
+
+ViewShellId ScUndoWrapper::GetViewShellId() const
+{
+ return mnViewShellId;
+}
+
+OUString ScUndoWrapper::GetRepeatComment(SfxRepeatTarget& rTarget) const
+{
+ if (pWrappedUndo)
+ return pWrappedUndo->GetRepeatComment(rTarget);
+ return OUString();
+}
+
+bool ScUndoWrapper::Merge( SfxUndoAction* pNextAction )
+{
+ if (pWrappedUndo)
+ return pWrappedUndo->Merge(pNextAction);
+ else
+ return false;
+}
+
+void ScUndoWrapper::Undo()
+{
+ if (pWrappedUndo)
+ pWrappedUndo->Undo();
+}
+
+void ScUndoWrapper::Redo()
+{
+ if (pWrappedUndo)
+ pWrappedUndo->Redo();
+}
+
+void ScUndoWrapper::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (pWrappedUndo)
+ pWrappedUndo->Repeat(rTarget);
+}
+
+bool ScUndoWrapper::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ if (pWrappedUndo)
+ return pWrappedUndo->CanRepeat(rTarget);
+ else
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undoblk.cxx b/sc/source/ui/undo/undoblk.cxx
new file mode 100644
index 000000000..e3b10f78b
--- /dev/null
+++ b/sc/source/ui/undo/undoblk.cxx
@@ -0,0 +1,2437 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <vcl/virdev.hxx>
+#include <editeng/boxitem.hxx>
+#include <sfx2/app.hxx>
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+
+#include <undoblk.hxx>
+#include <undoutil.hxx>
+#include <document.hxx>
+#include <patattr.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <rangenam.hxx>
+#include <rangeutl.hxx>
+#include <stlpool.hxx>
+#include <stlsheet.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <target.hxx>
+#include <docpool.hxx>
+#include <docfunc.hxx>
+#include <attrib.hxx>
+#include <chgtrack.hxx>
+#include <transobj.hxx>
+#include <refundo.hxx>
+#include <undoolk.hxx>
+#include <clipparam.hxx>
+#include <rowheightcontext.hxx>
+#include <refupdatecontext.hxx>
+#include <validat.hxx>
+#include <gridwin.hxx>
+#include <columnspanset.hxx>
+
+#include <memory>
+#include <set>
+
+// TODO:
+/*A*/ // SetOptimalHeight on Document, if no View
+/*B*/ // linked sheets
+/*C*/ // ScArea
+//? // check later
+
+ScUndoInsertCells::ScUndoInsertCells( ScDocShell* pNewDocShell,
+ const ScRange& rRange,
+ SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
+ InsCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData,
+ bool bNewPartOfPaste ) :
+ ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
+ aEffRange( rRange ),
+ nCount( nNewCount ),
+ pTabs( std::move(pNewTabs) ),
+ pScenarios( std::move(pNewScenarios) ),
+ eCmd( eNewCmd ),
+ bPartOfPaste( bNewPartOfPaste )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER) // whole row?
+ {
+ aEffRange.aStart.SetCol(0);
+ aEffRange.aEnd.SetCol(rDoc.MaxCol());
+ }
+
+ if (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER) // whole column?
+ {
+ aEffRange.aStart.SetRow(0);
+ aEffRange.aEnd.SetRow(rDoc.MaxRow());
+ }
+
+ SetChangeTrack();
+}
+
+ScUndoInsertCells::~ScUndoInsertCells()
+{
+}
+
+OUString ScUndoInsertCells::GetComment() const
+{
+ return ScResId( pPasteUndo ? STR_UNDO_PASTE : STR_UNDO_INSERTCELLS );
+}
+
+bool ScUndoInsertCells::Merge( SfxUndoAction* pNextAction )
+{
+ // If a paste undo action has already been added, append (detective) action there.
+ if ( pPasteUndo )
+ return pPasteUndo->Merge( pNextAction );
+
+ if ( bPartOfPaste )
+ if ( auto pWrapper = dynamic_cast<ScUndoWrapper*>( pNextAction) )
+ {
+ SfxUndoAction* pWrappedAction = pWrapper->GetWrappedUndo();
+ if ( dynamic_cast<const ScUndoPaste*>( pWrappedAction) )
+ {
+ // Store paste action if this is part of paste with inserting cells.
+ // A list action isn't used because Repeat wouldn't work (insert wrong cells).
+
+ pPasteUndo.reset( pWrappedAction );
+ pWrapper->ForgetWrappedUndo(); // pWrapper is deleted by UndoManager
+ return true;
+ }
+ }
+
+ // Call base class for detective handling
+ return ScMoveUndo::Merge( pNextAction );
+}
+
+void ScUndoInsertCells::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ pChangeTrack->AppendInsert( aEffRange );
+ nEndChangeAction = pChangeTrack->GetActionMax();
+ }
+ else
+ nEndChangeAction = 0;
+}
+
+void ScUndoInsertCells::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB i;
+
+ if ( bUndo )
+ {
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
+ }
+ else
+ SetChangeTrack();
+
+ // refresh of merged cells has to be after inserting/deleting
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ switch (eCmd)
+ {
+ case INS_INSROWS_BEFORE:
+ case INS_INSROWS_AFTER:
+ case INS_CELLSDOWN:
+ for( i=0; i<nCount; i++ )
+ {
+
+ if (bUndo)
+ rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+ else
+ rDoc.InsertRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+
+ if (pViewShell)
+ {
+ const tools::Long nSign = bUndo ? -1 : 1;
+ pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+ }
+ }
+ break;
+ case INS_INSCOLS_BEFORE:
+ case INS_INSCOLS_AFTER:
+ case INS_CELLSRIGHT:
+ for( i=0; i<nCount; i++ )
+ {
+ if (bUndo)
+ rDoc.DeleteCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+ else
+ rDoc.InsertCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+
+ if (pViewShell)
+ {
+ const tools::Long nSign = bUndo ? -1 : 1;
+ pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ ScRange aWorkRange( aEffRange );
+ if ( eCmd == INS_CELLSRIGHT ) // only "shift right" requires refresh of the moved area
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+ for( i=0; i<nCount; i++ )
+ {
+ if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
+ aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged ) )
+ {
+ SCCOL nEndCol = aWorkRange.aEnd.Col();
+ SCROW nEndRow = aWorkRange.aEnd.Row();
+ rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true );
+ }
+ }
+
+ // Undo for displaced attributes?
+
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+
+ switch (eCmd)
+ {
+ case INS_INSROWS_BEFORE:
+ case INS_INSROWS_AFTER:
+ nPaint |= PaintPartFlags::Left;
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ break;
+ case INS_CELLSDOWN:
+ for( i=0; i<nCount; i++ )
+ {
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ))
+ {
+ aWorkRange.aStart.SetCol(0);
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+ nPaint |= PaintPartFlags::Left;
+ }
+ }
+ break;
+ case INS_INSCOLS_BEFORE:
+ case INS_INSCOLS_AFTER:
+ nPaint |= PaintPartFlags::Top; // top bar
+ [[fallthrough]];
+ case INS_CELLSRIGHT:
+ for( i=0; i<nCount; i++ )
+ {
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol()); // to the far right
+ if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i]) )
+ { // AdjustDraw does not paint PaintPartFlags::Top,
+ aWorkRange.aStart.SetCol(0); // thus solved like this
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Left;
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ for( i=0; i<nCount; i++ )
+ {
+ pDocShell->PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
+ aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint );
+ }
+ pDocShell->PostDataChanged();
+ if (!pViewShell)
+ return;
+
+ pViewShell->CellContentChanged();
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ bool bColsAffected = (eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER || eCmd == INS_CELLSRIGHT);
+ bool bRowsAffected = (eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER || eCmd == INS_CELLSDOWN);
+
+ if (bColsAffected)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab);
+
+ if (bRowsAffected)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ bColsAffected, bRowsAffected,
+ true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+}
+
+void ScUndoInsertCells::Undo()
+{
+ if ( pPasteUndo )
+ pPasteUndo->Undo(); // undo paste first
+
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas in UpdateReference
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (SCTAB i = 0; i < nCount; ++i)
+ rDoc.SetDrawPageSize(pTabs[i]);
+}
+
+void ScUndoInsertCells::Redo()
+{
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important due to TrackFormulas in UpdateReference
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+
+ if ( pPasteUndo )
+ pPasteUndo->Redo(); // redo paste last
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (SCTAB i = 0; i < nCount; ++i)
+ rDoc.SetDrawPageSize(pTabs[i]);
+}
+
+void ScUndoInsertCells::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr)
+ {
+ if ( pPasteUndo )
+ {
+ // Repeat for paste with inserting cells is handled completely
+ // by the Paste undo action
+
+ pPasteUndo->Repeat( rTarget );
+ }
+ else
+ static_cast<ScTabViewTarget&>(rTarget).GetViewShell()->InsertCells( eCmd );
+ }
+}
+
+bool ScUndoInsertCells::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoDeleteCells::ScUndoDeleteCells( ScDocShell* pNewDocShell,
+ const ScRange& rRange,
+ SCTAB nNewCount, std::unique_ptr<SCTAB[]> pNewTabs, std::unique_ptr<SCTAB[]> pNewScenarios,
+ DelCellCmd eNewCmd, ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
+ ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
+ aEffRange( rRange ),
+ nCount( nNewCount ),
+ pTabs( std::move(pNewTabs) ),
+ pScenarios( std::move(pNewScenarios) ),
+ eCmd( eNewCmd )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (eCmd == DelCellCmd::Rows) // whole row?
+ {
+ aEffRange.aStart.SetCol(0);
+ aEffRange.aEnd.SetCol(rDoc.MaxCol());
+ }
+
+ if (eCmd == DelCellCmd::Cols) // whole column?
+ {
+ aEffRange.aStart.SetRow(0);
+ aEffRange.aEnd.SetRow(rDoc.MaxRow());
+ }
+
+ SetChangeTrack();
+}
+
+ScUndoDeleteCells::~ScUndoDeleteCells()
+{
+}
+
+OUString ScUndoDeleteCells::GetComment() const
+{
+ return ScResId( STR_UNDO_DELETECELLS ); // "Delete"
+}
+
+void ScUndoDeleteCells::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->AppendDeleteRange( aEffRange, pRefUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoDeleteCells::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB i;
+
+ if ( bUndo )
+ {
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+ }
+ else
+ SetChangeTrack();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ switch (eCmd)
+ {
+ case DelCellCmd::Rows:
+ case DelCellCmd::CellsUp:
+ for( i=0; i<nCount; i++ )
+ {
+ if (bUndo)
+ rDoc.InsertRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+ else
+ rDoc.DeleteRow( aEffRange.aStart.Col(), pTabs[i], aEffRange.aEnd.Col(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Row(), static_cast<SCSIZE>(aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+
+ if (pViewShell)
+ {
+ const tools::Long nSign = bUndo ? 1 : -1;
+ pViewShell->OnLOKInsertDeleteRow(aEffRange.aStart.Row(), nSign * (aEffRange.aEnd.Row()-aEffRange.aStart.Row()+1));
+ }
+ }
+ break;
+ case DelCellCmd::Cols:
+ case DelCellCmd::CellsLeft:
+ for( i=0; i<nCount; i++ )
+ {
+ if (bUndo)
+ rDoc.InsertCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+ else
+ rDoc.DeleteCol( aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
+ aEffRange.aStart.Col(), static_cast<SCSIZE>(aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+
+ if (pViewShell)
+ {
+ const tools::Long nSign = bUndo ? 1 : -1;
+ pViewShell->OnLOKInsertDeleteColumn(aEffRange.aStart.Col(), nSign * (aEffRange.aEnd.Col()-aEffRange.aStart.Col()+1));
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ // if Undo, restore references
+ for( i=0; i<nCount && bUndo; i++ )
+ {
+ pRefUndoDoc->CopyToDocument(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i],
+ InsertDeleteFlags::ALL | InsertDeleteFlags::NOCAPTIONS, false, rDoc);
+ }
+
+ ScRange aWorkRange( aEffRange );
+ if ( eCmd == DelCellCmd::CellsLeft ) // only "shift left" requires refresh of the moved area
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+
+ for( i=0; i<nCount; i++ )
+ {
+ if ( rDoc.HasAttrib( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
+ aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i], HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
+ {
+ // #i51445# old merge flag attributes must be deleted also for single cells,
+ // not only for whole columns/rows
+
+ if ( !bUndo )
+ {
+ if ( eCmd==DelCellCmd::Cols || eCmd==DelCellCmd::CellsLeft )
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+ if ( eCmd==DelCellCmd::Rows || eCmd==DelCellCmd::CellsUp )
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+ aMarkData.SelectOneTable( aWorkRange.aStart.Tab() );
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( ScMergeFlagAttr() );
+ rDoc.ApplyPatternArea( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(),
+ aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(),
+ aMarkData, aPattern );
+ }
+
+ SCCOL nEndCol = aWorkRange.aEnd.Col();
+ SCROW nEndRow = aWorkRange.aEnd.Row();
+ rDoc.ExtendMerge( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), nEndCol, nEndRow, pTabs[i], true );
+ }
+ }
+
+ // paint
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+ switch (eCmd)
+ {
+ case DelCellCmd::Rows:
+ nPaint |= PaintPartFlags::Left;
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ break;
+ case DelCellCmd::CellsUp:
+ for( i=0; i<nCount; i++ )
+ {
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ))
+ {
+ aWorkRange.aStart.SetCol(0);
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+ nPaint |= PaintPartFlags::Left;
+ }
+ }
+ break;
+ case DelCellCmd::Cols:
+ nPaint |= PaintPartFlags::Top; // top bar
+ [[fallthrough]];
+ case DelCellCmd::CellsLeft:
+ for( i=0; i<nCount; i++ )
+ {
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol()); // to the far right
+ if ( pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), pTabs[i] ) )
+ {
+ aWorkRange.aStart.SetCol(0);
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Left;
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ for( i=0; i<nCount; i++ )
+ {
+ pDocShell->PostPaint( aWorkRange.aStart.Col(), aWorkRange.aStart.Row(), pTabs[i],
+ aWorkRange.aEnd.Col(), aWorkRange.aEnd.Row(), pTabs[i]+pScenarios[i], nPaint, SC_PF_LINES );
+ }
+ // Selection not until EndUndo
+
+ pDocShell->PostDataChanged();
+ // CellContentChanged comes with the selection
+
+ if (!pViewShell)
+ return;
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ bool bColsAffected = (eCmd == DelCellCmd::Cols || eCmd == DelCellCmd::CellsLeft);
+ bool bRowsAffected = (eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::CellsUp);
+
+ if (bColsAffected)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, COLUMN_HEADER, nTab);
+
+ if (bRowsAffected)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ bColsAffected, bRowsAffected,
+ true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+
+}
+
+void ScUndoDeleteCells::Undo()
+{
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // Now that DBData have been restored in ScMoveUndo::EndUndo() via its
+ // pRefUndoDoc we can apply the AutoFilter buttons.
+ // Add one row for cases undoing deletion right above a cut AutoFilter
+ // range so the buttons are removed.
+ SCROW nRefreshEndRow = std::min<SCROW>( aEffRange.aEnd.Row() + 1, rDoc.MaxRow());
+ for (SCTAB i=0; i < nCount; ++i)
+ {
+ rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(),
+ aEffRange.aEnd.Col(), nRefreshEndRow, pTabs[i]);
+ }
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+
+ // Selection not until EndUndo
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ for( SCTAB i=0; i<nCount; i++ )
+ {
+ pViewShell->MarkRange( ScRange(aEffRange.aStart.Col(), aEffRange.aStart.Row(), pTabs[i], aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]+pScenarios[i]) );
+ }
+ }
+
+ for (SCTAB i = 0; i < nCount; ++i)
+ rDoc.SetDrawPageSize(pTabs[i]);
+}
+
+void ScUndoDeleteCells::Redo()
+{
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
+ BeginRedo();
+ DoChange( false);
+ EndRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ for (SCTAB i=0; i < nCount; ++i)
+ {
+ rDoc.RefreshAutoFilter( aEffRange.aStart.Col(), aEffRange.aStart.Row(),
+ aEffRange.aEnd.Col(), aEffRange.aEnd.Row(), pTabs[i]);
+ }
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->DoneBlockMode(); // current way
+
+ for (SCTAB i = 0; i < nCount; ++i)
+ rDoc.SetDrawPageSize(pTabs[i]);
+}
+
+void ScUndoDeleteCells::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget) )
+ pViewTarget->GetViewShell()->DeleteCells( eCmd );
+}
+
+bool ScUndoDeleteCells::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+// delete cells in multiselection
+ScUndoDeleteMulti::ScUndoDeleteMulti(
+ ScDocShell* pNewDocShell,
+ bool bNewRows, bool bNeedsRefresh, SCTAB nNewTab,
+ std::vector<sc::ColRowSpan>&& rSpans,
+ ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
+ ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) ),
+ mbRows(bNewRows),
+ mbRefresh(bNeedsRefresh),
+ nTab( nNewTab ),
+ maSpans(std::move(rSpans))
+{
+ SetChangeTrack();
+}
+
+ScUndoDeleteMulti::~ScUndoDeleteMulti()
+{
+}
+
+OUString ScUndoDeleteMulti::GetComment() const
+{
+ return ScResId( STR_UNDO_DELETECELLS ); // like DeleteCells
+}
+
+void ScUndoDeleteMulti::DoChange() const
+{
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ PaintPartFlags nPaint;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (mbRows)
+ {
+ nStartCol = 0;
+ nStartRow = static_cast<SCROW>(maSpans[0].mnStart);
+ nPaint = PaintPartFlags::Grid | PaintPartFlags::Left;
+ }
+ else
+ {
+ nStartCol = static_cast<SCCOL>(maSpans[0].mnStart);
+ nStartRow = 0;
+ nPaint = PaintPartFlags::Grid | PaintPartFlags::Top;
+ }
+
+ if (mbRefresh)
+ {
+ SCCOL nEndCol = rDoc.MaxCol();
+ SCROW nEndRow = rDoc.MaxRow();
+ rDoc.RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver );
+ rDoc.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, true );
+ }
+
+ pDocShell->PostPaint( nStartCol, nStartRow, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, nPaint );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ ShowTable( nTab );
+}
+
+void ScUndoDeleteMulti::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ nStartChangeAction = pChangeTrack->GetActionMax() + 1;
+ ScRange aRange( 0, 0, nTab, 0, 0, nTab );
+ if (mbRows)
+ aRange.aEnd.SetCol( rDoc.MaxCol() );
+ else
+ aRange.aEnd.SetRow( rDoc.MaxRow() );
+ // delete in reverse
+ std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend();
+ for (; ri != riEnd; ++ri)
+ {
+ SCCOLROW nEnd = ri->mnEnd;
+ SCCOLROW nStart = ri->mnStart;
+ if (mbRows)
+ {
+ aRange.aStart.SetRow( nStart );
+ aRange.aEnd.SetRow( nEnd );
+ }
+ else
+ {
+ aRange.aStart.SetCol( static_cast<SCCOL>(nStart) );
+ aRange.aEnd.SetCol( static_cast<SCCOL>(nEnd) );
+ }
+ sal_uLong nDummyStart;
+ pChangeTrack->AppendDeleteRange( aRange, pRefUndoDoc.get(),
+ nDummyStart, nEndChangeAction );
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoDeleteMulti::Undo()
+{
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // reverse delete -> forward insert
+ for (const auto& rSpan : maSpans)
+ {
+ SCCOLROW nStart = rSpan.mnStart;
+ SCCOLROW nEnd = rSpan.mnEnd;
+ if (mbRows)
+ rDoc.InsertRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) );
+ else
+ rDoc.InsertCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
+ }
+
+ for (const auto& rSpan : maSpans)
+ {
+ SCCOLROW nStart = rSpan.mnStart;
+ SCCOLROW nEnd = rSpan.mnEnd;
+ if (mbRows)
+ pRefUndoDoc->CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::ALL, false, rDoc);
+ else
+ pRefUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart),0,nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL, false, rDoc);
+ }
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ DoChange();
+
+ //! redrawing the selection is not possible at the moment
+ //! since no data for selection exist
+
+ EndUndo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoDeleteMulti::Redo()
+{
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() ); // important because of TrackFormulas in UpdateReference
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // reverse delete
+ std::vector<sc::ColRowSpan>::const_reverse_iterator ri = maSpans.rbegin(), riEnd = maSpans.rend();
+ for (; ri != riEnd; ++ri)
+ {
+ SCCOLROW nEnd = ri->mnEnd;
+ SCCOLROW nStart = ri->mnStart;
+ if (mbRows)
+ rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, nStart,static_cast<SCSIZE>(nEnd-nStart+1) );
+ else
+ rDoc.DeleteCol( 0,nTab, rDoc.MaxRow(),nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd-nStart+1) );
+ }
+
+ SetChangeTrack();
+
+ DoChange();
+
+ EndRedo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoDeleteMulti::Repeat(SfxRepeatTarget& rTarget)
+{
+ // if single selection
+ if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pTabViewTarget->GetViewShell()->DeleteCells( DelCellCmd::Rows );
+}
+
+bool ScUndoDeleteMulti::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoCut::ScUndoCut(ScDocShell* pNewDocShell, const ScRange& aRange, const ScAddress& aOldEnd,
+ const ScMarkData& rMark, ScDocumentUniquePtr pNewUndoDoc)
+ : ScBlockUndo(pNewDocShell, ScRange(aRange.aStart, aOldEnd), SC_UNDO_AUTOHEIGHT)
+ , aMarkData(rMark)
+ , pUndoDoc(std::move(pNewUndoDoc))
+ , aExtendedRange(aRange)
+{
+ SetChangeTrack();
+}
+
+ScUndoCut::~ScUndoCut()
+{
+}
+
+OUString ScUndoCut::GetComment() const
+{
+ return ScResId( STR_UNDO_CUT ); // "cut"
+}
+
+void ScUndoCut::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->AppendContentRange( aBlockRange, pUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction, SC_CACM_CUT );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoCut::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_uInt16 nExtFlags = 0;
+
+ // do not undo/redo objects and note captions, they are handled via drawing undo
+ InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
+
+ if (bUndo) // only for Undo
+ {
+ // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
+ SCTAB nTabCount = rDoc.GetTableCount();
+ ScRange aCopyRange = aExtendedRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, nUndoFlags, false, rDoc);
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ BroadcastChanges(aCopyRange);
+ }
+ else // only for Redo
+ {
+ pDocShell->UpdatePaintExt( nExtFlags, aExtendedRange );
+ rDoc.DeleteArea( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
+ aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(), aMarkData, nUndoFlags );
+ SetChangeTrack();
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
+/*A*/ pDocShell->PostPaint( aExtendedRange, PaintPartFlags::Grid, nExtFlags );
+
+ if ( !bUndo ) // draw redo after updating row heights
+ RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo?
+
+ pDocShell->PostDataChanged();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoCut::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoCut::Redo()
+{
+ BeginRedo();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
+ DoChange( false );
+ EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
+ EndRedo();
+}
+
+void ScUndoCut::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->CutToClip();
+}
+
+bool ScUndoCut::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoPaste::ScUndoPaste( ScDocShell* pNewDocShell, const ScRangeList& rRanges,
+ const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
+ InsertDeleteFlags nNewFlags,
+ std::unique_ptr<ScRefUndoData> pRefData,
+ bool bRedoIsFilled, const ScUndoPasteOptions* pOptions ) :
+ ScMultiBlockUndo( pNewDocShell, rRanges ),
+ aMarkData( rMark ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ pRedoDoc( std::move(pNewRedoDoc) ),
+ nFlags( nNewFlags ),
+ pRefUndoData( std::move(pRefData) ),
+ bRedoFilled( bRedoIsFilled )
+{
+ if ( pRefUndoData )
+ pRefUndoData->DeleteUnchanged( &pDocShell->GetDocument() );
+
+ if ( pOptions )
+ aPasteOptions = *pOptions; // used only for Repeat
+
+ SetChangeTrack();
+}
+
+ScUndoPaste::~ScUndoPaste()
+{
+ pUndoDoc.reset();
+ pRedoDoc.reset();
+ pRefUndoData.reset();
+ pRefRedoData.reset();
+}
+
+OUString ScUndoPaste::GetComment() const
+{
+ return ScResId( STR_UNDO_PASTE ); // "paste"
+}
+
+void ScUndoPaste::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack && (nFlags & InsertDeleteFlags::CONTENTS) )
+ {
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ {
+ pChangeTrack->AppendContentRange(maBlockRanges[i], pUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction, SC_CACM_PASTE );
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoPaste::DoChange(bool bUndo)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // RefUndoData for redo is created before first undo
+ // (with DeleteUnchanged after the DoUndo call)
+ bool bCreateRedoData = ( bUndo && pRefUndoData && !pRefRedoData );
+ if ( bCreateRedoData )
+ pRefRedoData.reset( new ScRefUndoData( &rDoc ) );
+
+ ScRefUndoData* pWorkRefData = bUndo ? pRefUndoData.get() : pRefRedoData.get();
+
+ // Always back-up either all or none of the content for Undo
+ InsertDeleteFlags nUndoFlags = InsertDeleteFlags::NONE;
+ if (nFlags & InsertDeleteFlags::CONTENTS)
+ nUndoFlags |= InsertDeleteFlags::CONTENTS;
+ if (nFlags & InsertDeleteFlags::ATTRIB)
+ nUndoFlags |= InsertDeleteFlags::ATTRIB;
+
+ // do not undo/redo objects and note captions, they are handled via drawing undo
+ nUndoFlags &= ~InsertDeleteFlags::OBJECTS;
+ nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
+
+ bool bPaintAll = false;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ if ( bUndo && !bRedoFilled )
+ {
+ if (!pRedoDoc)
+ {
+ bool bColInfo = true;
+ bool bRowInfo = true;
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ {
+ const ScRange& r = maBlockRanges[i];
+ bColInfo &= (r.aStart.Row() == 0 && r.aEnd.Row() == rDoc.MaxRow());
+ bRowInfo &= (r.aStart.Col() == 0 && r.aEnd.Col() == rDoc.MaxCol());
+ if (!bColInfo && !bRowInfo)
+ break;
+ }
+
+ pRedoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
+ pRedoDoc->InitUndoSelected( rDoc, aMarkData, bColInfo, bRowInfo );
+ }
+ // read "redo" data from the document in the first undo
+ // all sheets - CopyToDocument skips those that don't exist in pRedoDoc
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ {
+ ScRange aCopyRange = maBlockRanges[i];
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument(aCopyRange, nUndoFlags, false, *pRedoDoc);
+ bRedoFilled = true;
+ }
+ }
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt(nExtFlags, maBlockRanges.Combine());
+
+ rDoc.ForgetNoteCaptions(maBlockRanges, false);
+ aMarkData.MarkToMulti();
+ rDoc.DeleteSelection(nUndoFlags, aMarkData, false); // no broadcasting here
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ rDoc.BroadcastCells(maBlockRanges[i], SfxHintId::ScDataChanged);
+
+ aMarkData.MarkToSimple();
+
+ SCTAB nFirstSelected = aMarkData.GetFirstSelected();
+
+ if ( !bUndo && pRedoDoc ) // Redo: UndoToDocument before handling RefData
+ {
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ {
+ ScRange aRange = maBlockRanges[i];
+ aRange.aStart.SetTab(nFirstSelected);
+ aRange.aEnd.SetTab(nFirstSelected);
+ pRedoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc);
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (rTab == nFirstSelected)
+ continue;
+
+ aRange.aStart.SetTab(rTab);
+ aRange.aEnd.SetTab(rTab);
+ pRedoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc);
+ }
+ }
+ }
+
+ if (pWorkRefData)
+ {
+ pWorkRefData->DoUndo( &rDoc, true ); // true = bSetChartRangeLists for SetChartListenerCollection
+ if (!maBlockRanges.empty() &&
+ rDoc.RefreshAutoFilter(0, 0, rDoc.MaxCol(), rDoc.MaxRow(), maBlockRanges[0].aStart.Tab()))
+ bPaintAll = true;
+ }
+
+ if ( bCreateRedoData && pRefRedoData )
+ pRefRedoData->DeleteUnchanged( &rDoc );
+
+ if (bUndo) // Undo: UndoToDocument after handling RefData
+ {
+ for (size_t i = 0, n = maBlockRanges.size(); i < n; ++i)
+ {
+ ScRange aRange = maBlockRanges[i];
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+ aRange.aStart.SetTab(rTab);
+ aRange.aEnd.SetTab(rTab);
+ pUndoDoc->UndoToDocument(aRange, nUndoFlags, false, rDoc);
+ }
+ }
+ }
+
+ if ( bUndo )
+ {
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+ }
+ else
+ SetChangeTrack();
+
+ ScRangeList aDrawRanges(maBlockRanges);
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+
+ // For sheet geometry invalidation.
+ bool bColsAffected = false;
+ bool bRowsAffected = false;
+
+ for (size_t i = 0, n = aDrawRanges.size(); i < n; ++i)
+ {
+ ScRange& rDrawRange = aDrawRanges[i];
+ rDoc.ExtendMerge(rDrawRange, true); // only needed for single sheet (text/rtf etc.)
+ ScRangeList aRangeList(rDrawRange);
+ ScMarkData aData(rDoc.GetSheetLimits(), aRangeList);
+ if (bPaintAll)
+ {
+ rDrawRange.aStart.SetCol(0);
+ rDrawRange.aStart.SetRow(0);
+ rDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ rDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Top | PaintPartFlags::Left;
+ if (pViewShell)
+ pViewShell->AdjustBlockHeight(false, &aData);
+ }
+ else
+ {
+ if (maBlockRanges[i].aStart.Row() == 0 && maBlockRanges[i].aEnd.Row() == rDoc.MaxRow()) // whole column
+ {
+ nPaint |= PaintPartFlags::Top;
+ rDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ bColsAffected = true;
+ }
+ if (maBlockRanges[i].aStart.Col() == 0 && maBlockRanges[i].aEnd.Col() == rDoc.MaxCol()) // whole row
+ {
+ nPaint |= PaintPartFlags::Left;
+ rDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ bRowsAffected = true;
+ }
+ if (pViewShell && pViewShell->AdjustBlockHeight(false, &aData))
+ {
+ rDrawRange.aStart.SetCol(0);
+ rDrawRange.aStart.SetRow(0);
+ rDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ rDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Left;
+ }
+ pDocShell->UpdatePaintExt(nExtFlags, rDrawRange);
+ }
+ }
+
+ if ( !bUndo ) // draw redo after updating row heights
+ RedoSdrUndoAction(mpDrawUndo.get());
+
+ pDocShell->PostPaint(aDrawRanges, nPaint, nExtFlags);
+
+ pDocShell->PostDataChanged();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ if (bColsAffected || bRowsAffected)
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ bColsAffected, bRowsAffected,
+ true /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, aDrawRanges[0].aStart.Tab());
+}
+
+void ScUndoPaste::Undo()
+{
+ BeginUndo();
+ DoChange(true);
+ if (!maBlockRanges.empty())
+ ShowTable(maBlockRanges.front());
+ EndUndo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoPaste::Redo()
+{
+ BeginRedo();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
+ DoChange( false );
+ EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
+ EndRedo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoPaste::Repeat(SfxRepeatTarget& rTarget)
+{
+ auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget);
+ if (!pViewTarget)
+ return;
+
+ ScTabViewShell* pViewSh = pViewTarget->GetViewShell();
+ // keep a reference in case the clipboard is changed during PasteFromClip
+ const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pViewSh->GetViewData().GetActiveWin()));
+ if (pOwnClip)
+ {
+ pViewSh->PasteFromClip( nFlags, pOwnClip->GetDocument(),
+ aPasteOptions.nFunction, aPasteOptions.bSkipEmptyCells, aPasteOptions.bTranspose,
+ aPasteOptions.bAsLink, aPasteOptions.eMoveMode, InsertDeleteFlags::NONE,
+ true ); // allow warning dialog
+ }
+}
+
+bool ScUndoPaste::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoDragDrop::ScUndoDragDrop( ScDocShell* pNewDocShell,
+ const ScRange& rRange, const ScAddress& aNewDestPos, bool bNewCut,
+ ScDocumentUniquePtr pUndoDocument, bool bScenario ) :
+ ScMoveUndo( pNewDocShell, std::move(pUndoDocument), nullptr ),
+ mnPaintExtFlags( 0 ),
+ aSrcRange( rRange ),
+ bCut( bNewCut ),
+ bKeepScenarioFlags( bScenario )
+{
+ ScAddress aDestEnd(aNewDestPos);
+ aDestEnd.IncRow(aSrcRange.aEnd.Row() - aSrcRange.aStart.Row());
+ aDestEnd.IncCol(aSrcRange.aEnd.Col() - aSrcRange.aStart.Col());
+ aDestEnd.IncTab(aSrcRange.aEnd.Tab() - aSrcRange.aStart.Tab());
+
+ bool bIncludeFiltered = bCut;
+ if ( !bIncludeFiltered )
+ {
+ // find number of non-filtered rows
+ SCROW nPastedCount = pDocShell->GetDocument().CountNonFilteredRows(
+ aSrcRange.aStart.Row(), aSrcRange.aEnd.Row(), aSrcRange.aStart.Tab());
+
+ if ( nPastedCount == 0 )
+ nPastedCount = 1;
+ aDestEnd.SetRow( aNewDestPos.Row() + nPastedCount - 1 );
+ }
+
+ aDestRange.aStart = aNewDestPos;
+ aDestRange.aEnd = aDestEnd;
+
+ SetChangeTrack();
+}
+
+ScUndoDragDrop::~ScUndoDragDrop()
+{
+}
+
+OUString ScUndoDragDrop::GetComment() const
+{ // "Move" : "Copy"
+ return bCut ?
+ ScResId( STR_UNDO_MOVE ) :
+ ScResId( STR_UNDO_COPY );
+}
+
+void ScUndoDragDrop::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ if ( bCut )
+ {
+ nStartChangeAction = pChangeTrack->GetActionMax() + 1;
+ pChangeTrack->AppendMove( aSrcRange, aDestRange, pRefUndoDoc.get() );
+ nEndChangeAction = pChangeTrack->GetActionMax();
+ }
+ else
+ pChangeTrack->AppendContentRange( aDestRange, pRefUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction );
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoDragDrop::PaintArea( ScRange aRange, sal_uInt16 nExtFlags ) const
+{
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ if (pViewShell)
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ ScViewData& rViewData = pViewShell->GetViewData();
+ sc::RowHeightContext aCxt(
+ rDoc.MaxRow(), rViewData.GetPPTX(), rViewData.GetPPTY(), rViewData.GetZoomX(), rViewData.GetZoomY(),
+ pVirtDev);
+
+ if (rDoc.SetOptimalHeight(aCxt, aRange.aStart.Row(), aRange.aEnd.Row(), aRange.aStart.Tab(), true))
+ {
+ // tdf#76183: recalculate objects' positions
+ rDoc.SetDrawPageSize(aRange.aStart.Tab());
+ aRange.aStart.SetCol(0);
+ aRange.aEnd.SetCol(rDoc.MaxCol());
+ aRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Left;
+ }
+ }
+
+ if ( bKeepScenarioFlags )
+ {
+ // Copy scenario -> also paint scenario boarder
+ aRange.aStart.SetCol(0);
+ aRange.aStart.SetRow(0);
+ aRange.aEnd.SetCol(rDoc.MaxCol());
+ aRange.aEnd.SetRow(rDoc.MaxRow());
+ }
+
+ // column/row info (width/height) included if whole columns/rows were copied
+ if ( aSrcRange.aStart.Col() == 0 && aSrcRange.aEnd.Col() == rDoc.MaxCol() )
+ {
+ nPaint |= PaintPartFlags::Left;
+ aRange.aEnd.SetRow(rDoc.MaxRow());
+ }
+ if ( aSrcRange.aStart.Row() == 0 && aSrcRange.aEnd.Row() == rDoc.MaxRow() )
+ {
+ nPaint |= PaintPartFlags::Top;
+ aRange.aEnd.SetCol(rDoc.MaxCol());
+ }
+
+ pDocShell->PostPaint( aRange, nPaint, nExtFlags );
+}
+
+void ScUndoDragDrop::DoUndo( ScRange aRange )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ // Database range before data, so that the Autofilter button match up in ExtendMerge
+
+ ScRange aPaintRange = aRange;
+ rDoc.ExtendMerge( aPaintRange ); // before deleting
+
+ pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange);
+
+ // do not undo objects and note captions, they are handled via drawing undo
+ InsertDeleteFlags nUndoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
+
+ // Additionally discard/forget caption ownership during deletion, as
+ // Drag&Drop is a special case in that the Undo holds captions of the
+ // transferred target range, which would get deleted and
+ // SdrGroupUndo::Undo() would attempt to access invalidated captions and
+ // crash, tdf#92995
+ InsertDeleteFlags nDelFlags = nUndoFlags | InsertDeleteFlags::FORGETCAPTIONS;
+
+ rDoc.DeleteAreaTab( aRange, nDelFlags );
+ pRefUndoDoc->CopyToDocument(aRange, nUndoFlags, false, rDoc);
+ if ( rDoc.HasAttrib( aRange, HasAttrFlags::Merged ) )
+ rDoc.ExtendMerge( aRange, true );
+
+ aPaintRange.aEnd.SetCol( std::max( aPaintRange.aEnd.Col(), aRange.aEnd.Col() ) );
+ aPaintRange.aEnd.SetRow( std::max( aPaintRange.aEnd.Row(), aRange.aEnd.Row() ) );
+
+ pDocShell->UpdatePaintExt(mnPaintExtFlags, aPaintRange);
+ maPaintRanges.Join(aPaintRange);
+}
+
+void ScUndoDragDrop::Undo()
+{
+ mnPaintExtFlags = 0;
+ maPaintRanges.RemoveAll();
+
+ BeginUndo();
+
+ if (bCut)
+ {
+ // During undo, we move cells from aDestRange to aSrcRange.
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCCOL nColDelta = aSrcRange.aStart.Col() - aDestRange.aStart.Col();
+ SCROW nRowDelta = aSrcRange.aStart.Row() - aDestRange.aStart.Row();
+ SCTAB nTabDelta = aSrcRange.aStart.Tab() - aDestRange.aStart.Tab();
+
+ sc::RefUpdateContext aCxt(rDoc);
+ aCxt.meMode = URM_MOVE;
+ aCxt.maRange = aSrcRange;
+ aCxt.mnColDelta = nColDelta;
+ aCxt.mnRowDelta = nRowDelta;
+ aCxt.mnTabDelta = nTabDelta;
+
+ // Global range names.
+ ScRangeName* pName = rDoc.GetRangeName();
+ if (pName)
+ pName->UpdateReference(aCxt);
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
+ {
+ // Sheet-local range names.
+ pName = rDoc.GetRangeName(nTab);
+ if (pName)
+ pName->UpdateReference(aCxt, nTab);
+ }
+
+ ScValidationDataList* pValidList = rDoc.GetValidationList();
+ if (pValidList)
+ {
+ // Update the references of validation entries.
+ pValidList->UpdateReference(aCxt);
+ }
+
+ DoUndo(aDestRange);
+ DoUndo(aSrcRange);
+
+ rDoc.BroadcastCells(aSrcRange, SfxHintId::ScDataChanged, false);
+ }
+ else
+ DoUndo(aDestRange);
+
+ for (size_t i = 0; i < maPaintRanges.size(); ++i)
+ {
+ const ScRange& r = maPaintRanges[i];
+ PaintArea(r, mnPaintExtFlags);
+ }
+
+ EndUndo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoDragDrop::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+
+ EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
+
+ // do not undo/redo objects and note captions, they are handled via drawing undo
+ constexpr InsertDeleteFlags nRedoFlags = (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
+
+ /* TODO: Redoing note captions is quite tricky due to the fact that a
+ helper clip document is used. While (re-)pasting the contents to the
+ destination area, the original pointers to the captions created while
+ dropping have to be restored. A simple CopyFromClip() would create new
+ caption objects that are not tracked by drawing undo, and the captions
+ restored by drawing redo would live without cell note objects pointing
+ to them. So, first, CopyToClip() and CopyFromClip() are called without
+ cloning the caption objects. This leads to cell notes pointing to the
+ wrong captions from source area that will be removed by drawing redo
+ later. Second, the pointers to the new captions have to be restored.
+ Sadly, currently these pointers are not stored anywhere but in the list
+ of drawing undo actions. */
+
+ SCTAB nTab;
+ ScMarkData aSourceMark(rDoc.GetSheetLimits());
+ for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++)
+ aSourceMark.SelectTable( nTab, true );
+
+ // do not clone objects and note captions into clipdoc (see above)
+ // but at least copy notes
+ ScClipParam aClipParam(aSrcRange, bCut);
+ rDoc.CopyToClip(aClipParam, pClipDoc.get(), &aSourceMark, bKeepScenarioFlags, false);
+
+ if (bCut)
+ {
+ ScRange aSrcPaintRange = aSrcRange;
+ rDoc.ExtendMerge( aSrcPaintRange ); // before deleting
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aSrcPaintRange );
+ rDoc.DeleteAreaTab( aSrcRange, nRedoFlags );
+ PaintArea( aSrcPaintRange, nExtFlags );
+ }
+
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++)
+ aDestMark.SelectTable( nTab, true );
+
+ bool bIncludeFiltered = bCut;
+ // TODO: restore old note captions instead of cloning new captions...
+ rDoc.CopyFromClip( aDestRange, aDestMark, InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS, nullptr, pClipDoc.get(), true, false, bIncludeFiltered );
+
+ if (bCut)
+ for (nTab=aSrcRange.aStart.Tab(); nTab<=aSrcRange.aEnd.Tab(); nTab++)
+ rDoc.RefreshAutoFilter( aSrcRange.aStart.Col(), aSrcRange.aStart.Row(),
+ aSrcRange.aEnd.Col(), aSrcRange.aEnd.Row(), nTab );
+
+ // skipped rows and merged cells don't mix
+ if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
+ pDocShell->GetDocFunc().UnmergeCells( aDestRange, false, nullptr );
+
+ for (nTab=aDestRange.aStart.Tab(); nTab<=aDestRange.aEnd.Tab(); nTab++)
+ {
+ SCCOL nEndCol = aDestRange.aEnd.Col();
+ SCROW nEndRow = aDestRange.aEnd.Row();
+ rDoc.ExtendMerge( aDestRange.aStart.Col(), aDestRange.aStart.Row(),
+ nEndCol, nEndRow, nTab, true );
+ PaintArea( ScRange( aDestRange.aStart.Col(), aDestRange.aStart.Row(), nTab,
+ nEndCol, nEndRow, nTab ), 0 );
+ }
+
+ SetChangeTrack();
+
+ pClipDoc.reset();
+ ShowTable( aDestRange.aStart.Tab() );
+
+ RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo?
+ EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
+
+ EndRedo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoDragDrop::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoDragDrop::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // not possible
+}
+
+// Insert list containing range names
+// (Insert|Name|Insert =>[List])
+ScUndoListNames::ScUndoListNames(ScDocShell* pNewDocShell, const ScRange& rRange,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc)
+ : ScBlockUndo(pNewDocShell, rRange, SC_UNDO_AUTOHEIGHT)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xRedoDoc(std::move(pNewRedoDoc))
+{
+}
+
+OUString ScUndoListNames::GetComment() const
+{
+ return ScResId( STR_UNDO_LISTNAMES );
+}
+
+void ScUndoListNames::DoChange( ScDocument* pSrcDoc ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL );
+ pSrcDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL, false, rDoc);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoListNames::Undo()
+{
+ BeginUndo();
+ DoChange(xUndoDoc.get());
+ EndUndo();
+}
+
+void ScUndoListNames::Redo()
+{
+ BeginRedo();
+ DoChange(xRedoDoc.get());
+ EndRedo();
+}
+
+void ScUndoListNames::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget))
+ pTabViewTarget->GetViewShell()->InsertNameList();
+}
+
+bool ScUndoListNames::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoConditionalFormat::ScUndoConditionalFormat(ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pUndoDoc, ScDocumentUniquePtr pRedoDoc, const ScRange& rRange):
+ ScSimpleUndo( pNewDocShell ),
+ mpUndoDoc(std::move(pUndoDoc)),
+ mpRedoDoc(std::move(pRedoDoc)),
+ maRange(rRange)
+{
+}
+
+ScUndoConditionalFormat::~ScUndoConditionalFormat()
+{
+}
+
+OUString ScUndoConditionalFormat::GetComment() const
+{
+ return ScResId( STR_UNDO_CONDFORMAT );
+}
+
+void ScUndoConditionalFormat::Undo()
+{
+ DoChange(mpUndoDoc.get());
+}
+
+void ScUndoConditionalFormat::Redo()
+{
+ DoChange(mpRedoDoc.get());
+}
+
+void ScUndoConditionalFormat::DoChange(ScDocument* pSrcDoc)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.DeleteAreaTab( maRange, InsertDeleteFlags::ALL );
+ pSrcDoc->CopyToDocument(maRange, InsertDeleteFlags::ALL, false, rDoc);
+ pDocShell->PostPaint( maRange, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoConditionalFormat::Repeat(SfxRepeatTarget& )
+{
+}
+
+bool ScUndoConditionalFormat::CanRepeat(SfxRepeatTarget& ) const
+{
+ return false;
+}
+
+ScUndoConditionalFormatList::ScUndoConditionalFormatList(ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pUndoDoc, ScDocumentUniquePtr pRedoDoc, SCTAB nTab):
+ ScSimpleUndo( pNewDocShell ),
+ mpUndoDoc(std::move(pUndoDoc)),
+ mpRedoDoc(std::move(pRedoDoc)),
+ mnTab(nTab)
+{
+}
+
+ScUndoConditionalFormatList::~ScUndoConditionalFormatList()
+{
+}
+
+OUString ScUndoConditionalFormatList::GetComment() const
+{
+ return ScResId( STR_UNDO_CONDFORMAT_LIST );
+}
+
+void ScUndoConditionalFormatList::Undo()
+{
+ DoChange(mpUndoDoc.get());
+}
+
+void ScUndoConditionalFormatList::Redo()
+{
+ DoChange(mpRedoDoc.get());
+}
+
+void ScUndoConditionalFormatList::DoChange(const ScDocument* pSrcDoc)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ if (pSrcDoc == mpUndoDoc.get())
+ {
+ mpRedoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc);
+ mpUndoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc);
+ }
+ else
+ {
+ mpUndoDoc->GetCondFormList(mnTab)->RemoveFromDocument(rDoc);
+ mpRedoDoc->GetCondFormList(mnTab)->AddToDocument(rDoc);
+ }
+ rDoc.SetCondFormList(new ScConditionalFormatList(rDoc, *pSrcDoc->GetCondFormList(mnTab)), mnTab);
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoConditionalFormatList::Repeat(SfxRepeatTarget& )
+{
+}
+
+bool ScUndoConditionalFormatList::CanRepeat(SfxRepeatTarget& ) const
+{
+ return false;
+}
+
+ScUndoUseScenario::ScUndoUseScenario( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+/*C*/ const ScArea& rDestArea,
+ ScDocumentUniquePtr pNewUndoDoc,
+ const OUString& rNewName ) :
+ ScSimpleUndo( pNewDocShell ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ aMarkData( rMark ),
+ aName( rNewName )
+{
+ aRange.aStart.SetCol(rDestArea.nColStart);
+ aRange.aStart.SetRow(rDestArea.nRowStart);
+ aRange.aStart.SetTab(rDestArea.nTab);
+ aRange.aEnd.SetCol(rDestArea.nColEnd);
+ aRange.aEnd.SetRow(rDestArea.nRowEnd);
+ aRange.aEnd.SetTab(rDestArea.nTab);
+}
+
+ScUndoUseScenario::~ScUndoUseScenario()
+{
+}
+
+OUString ScUndoUseScenario::GetComment() const
+{
+ return ScResId( STR_UNDO_USESCENARIO );
+}
+
+void ScUndoUseScenario::Undo()
+{
+ BeginUndo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->DoneBlockMode();
+ pViewShell->InitOwnBlockMode( aRange );
+ }
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.DeleteSelection( InsertDeleteFlags::ALL, aMarkData );
+ pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL, true, rDoc, &aMarkData);
+
+ // scenario table
+ bool bFrame = false;
+ SCTAB nTab = aRange.aStart.Tab();
+ SCTAB nEndTab = nTab;
+ while ( pUndoDoc->HasTable(nEndTab+1) && pUndoDoc->IsScenario(nEndTab+1) )
+ ++nEndTab;
+ for (SCTAB i = nTab+1; i<=nEndTab; i++)
+ {
+ // Flags always
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ pUndoDoc->GetScenarioData( i, aComment, aColor, nScenFlags );
+ rDoc.SetScenarioData( i, aComment, aColor, nScenFlags );
+ bool bActive = pUndoDoc->IsActiveScenario( i );
+ rDoc.SetActiveScenario( i, bActive );
+ // For copy-back scenario also consider content
+ if ( nScenFlags & ScScenarioFlags::TwoWay )
+ {
+ rDoc.DeleteAreaTab( 0,0, rDoc.MaxCol(),rDoc.MaxRow(), i, InsertDeleteFlags::ALL );
+ pUndoDoc->CopyToDocument(0,0,i, rDoc.MaxCol(),rDoc.MaxRow(),i, InsertDeleteFlags::ALL,false, rDoc);
+ }
+ if ( nScenFlags & ScScenarioFlags::ShowFrame )
+ bFrame = true;
+ }
+
+ // if visible borders, then paint all
+ if (bFrame)
+ pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid | PaintPartFlags::Extras );
+ else
+ pDocShell->PostPaint( aRange, PaintPartFlags::Grid | PaintPartFlags::Extras );
+ pDocShell->PostDataChanged();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ ShowTable( aRange.aStart.Tab() );
+
+ EndUndo();
+}
+
+void ScUndoUseScenario::Redo()
+{
+ SCTAB nTab = aRange.aStart.Tab();
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->SetTabNo( nTab );
+ pViewShell->DoneBlockMode();
+ pViewShell->InitOwnBlockMode( aRange );
+ }
+
+ pDocShell->UseScenario( nTab, aName, false );
+
+ EndRedo();
+}
+
+void ScUndoUseScenario::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ OUString aTemp = aName;
+ pViewTarget->GetViewShell()->UseScenario(aTemp);
+ }
+}
+
+bool ScUndoUseScenario::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScViewData& rViewData = pViewTarget->GetViewShell()->GetViewData();
+ return !rViewData.GetDocument().IsScenario( rViewData.GetTabNo() );
+ }
+ return false;
+}
+
+ScUndoSelectionStyle::ScUndoSelectionStyle( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ const ScRange& rRange,
+ const OUString& rName,
+ ScDocumentUniquePtr pNewUndoDoc ) :
+ ScSimpleUndo( pNewDocShell ),
+ aMarkData( rMark ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ aStyleName( rName ),
+ aRange( rRange )
+{
+ aMarkData.MarkToMulti();
+}
+
+ScUndoSelectionStyle::~ScUndoSelectionStyle()
+{
+}
+
+OUString ScUndoSelectionStyle::GetComment() const
+{
+ return ScResId( STR_UNDO_APPLYCELLSTYLE );
+}
+
+void ScUndoSelectionStyle::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SetViewMarkData( aMarkData );
+
+ ScRange aWorkRange( aRange );
+ if ( rDoc.HasAttrib( aWorkRange, HasAttrFlags::Merged ) ) // Merged cells?
+ rDoc.ExtendMerge( aWorkRange, true );
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aWorkRange );
+
+ if (bUndo) // if Undo then push back all old data again
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ ScRange aCopyRange = aWorkRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
+ }
+ else // if Redo, then reapply style
+ {
+ ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
+ ScStyleSheet* pStyleSheet =
+ static_cast<ScStyleSheet*>( pStlPool->Find( aStyleName, SfxStyleFamily::Para ) );
+ if (!pStyleSheet)
+ {
+ OSL_FAIL("StyleSheet not found");
+ return;
+ }
+ rDoc.ApplySelectionStyle( *pStyleSheet, aMarkData );
+ }
+
+ pDocShell->UpdatePaintExt( nExtFlags, aWorkRange );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
+/*A*/ pDocShell->PostPaint( aWorkRange, PaintPartFlags::Grid | PaintPartFlags::Extras, nExtFlags );
+
+ ShowTable( aWorkRange.aStart.Tab() );
+}
+
+void ScUndoSelectionStyle::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoSelectionStyle::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoSelectionStyle::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (dynamic_cast<const ScTabViewTarget*>( &rTarget) == nullptr)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
+ ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>( pStlPool->
+ Find( aStyleName, SfxStyleFamily::Para ));
+ if (!pStyleSheet)
+ {
+ OSL_FAIL("StyleSheet not found");
+ return;
+ }
+
+ ScTabViewShell& rViewShell = *static_cast<ScTabViewTarget&>(rTarget).GetViewShell();
+ rViewShell.SetStyleSheetToMarked( pStyleSheet );
+}
+
+bool ScUndoSelectionStyle::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoEnterMatrix::ScUndoEnterMatrix( ScDocShell* pNewDocShell, const ScRange& rArea,
+ ScDocumentUniquePtr pNewUndoDoc, const OUString& rForm ) :
+ ScBlockUndo( pNewDocShell, rArea, SC_UNDO_SIMPLE ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ aFormula( rForm )
+{
+ SetChangeTrack();
+}
+
+ScUndoEnterMatrix::~ScUndoEnterMatrix()
+{
+}
+
+OUString ScUndoEnterMatrix::GetComment() const
+{
+ return ScResId( STR_UNDO_ENTERMATRIX );
+}
+
+void ScUndoEnterMatrix::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->AppendContentRange( aBlockRange, pUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoEnterMatrix::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.DeleteAreaTab( aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ EndUndo();
+}
+
+void ScUndoEnterMatrix::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ aDestMark.SelectOneTable( aBlockRange.aStart.Tab() );
+ aDestMark.SetMarkArea( aBlockRange );
+
+ rDoc.InsertMatrixFormula( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
+ aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(),
+ aDestMark, aFormula );
+
+ SetChangeTrack();
+
+ EndRedo();
+}
+
+void ScUndoEnterMatrix::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pTabViewTarget = dynamic_cast<ScTabViewTarget*>(&rTarget))
+ {
+ OUString aTemp = aFormula;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pTabViewTarget->GetViewShell()->EnterMatrix(aTemp, rDoc.GetGrammar());
+ }
+}
+
+bool ScUndoEnterMatrix::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+static ScRange lcl_GetMultiMarkRange( const ScMarkData& rMark )
+{
+ OSL_ENSURE( rMark.IsMultiMarked(), "wrong mark type" );
+ return rMark.GetMultiMarkArea();
+}
+
+ScUndoIndent::ScUndoIndent( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, bool bIncrement ) :
+ ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
+ aMarkData( rMark ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ bIsIncrement( bIncrement )
+{
+}
+
+ScUndoIndent::~ScUndoIndent()
+{
+}
+
+OUString ScUndoIndent::GetComment() const
+{
+ TranslateId pId = bIsIncrement ? STR_UNDO_INC_INDENT : STR_UNDO_DEC_INDENT;
+ return ScResId(pId);
+}
+
+void ScUndoIndent::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ ScRange aCopyRange = aBlockRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndUndo();
+}
+
+void ScUndoIndent::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.ChangeSelectionIndent( bIsIncrement, aMarkData );
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndRedo();
+}
+
+void ScUndoIndent::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->ChangeIndent( bIsIncrement );
+}
+
+bool ScUndoIndent::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoTransliterate::ScUndoTransliterate( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, TransliterationFlags nType ) :
+ ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
+ aMarkData( rMark ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ nTransliterationType( nType )
+{
+}
+
+ScUndoTransliterate::~ScUndoTransliterate()
+{
+}
+
+OUString ScUndoTransliterate::GetComment() const
+{
+ return ScResId( STR_UNDO_TRANSLITERATE );
+}
+
+void ScUndoTransliterate::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ ScRange aCopyRange = aBlockRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::CONTENTS, true, rDoc, &aMarkData);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndUndo();
+}
+
+void ScUndoTransliterate::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.TransliterateText( aMarkData, nTransliterationType );
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndRedo();
+}
+
+void ScUndoTransliterate::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->TransliterateText( nTransliterationType );
+}
+
+bool ScUndoTransliterate::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoClearItems::ScUndoClearItems( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, const sal_uInt16* pW ) :
+ ScBlockUndo( pNewDocShell, lcl_GetMultiMarkRange(rMark), SC_UNDO_AUTOHEIGHT ),
+ aMarkData( rMark ),
+ pUndoDoc( std::move(pNewUndoDoc) )
+{
+ OSL_ENSURE( pW, "ScUndoClearItems: Which-Pointer is Null" );
+
+ sal_uInt16 nCount = 0;
+ while ( pW[nCount] )
+ ++nCount;
+ pWhich.reset( new sal_uInt16[nCount+1] );
+ for (sal_uInt16 i=0; i<=nCount; i++)
+ pWhich[i] = pW[i];
+}
+
+ScUndoClearItems::~ScUndoClearItems()
+{
+}
+
+OUString ScUndoClearItems::GetComment() const
+{
+ return ScResId( STR_UNDO_DELETECONTENTS );
+}
+
+void ScUndoClearItems::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndUndo();
+}
+
+void ScUndoClearItems::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.ClearSelectionItems( pWhich.get(), aMarkData );
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndRedo();
+}
+
+void ScUndoClearItems::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScViewData& rViewData = pViewTarget->GetViewShell()->GetViewData();
+ rViewData.GetDocFunc().ClearItems( rViewData.GetMarkData(), pWhich.get(), false );
+ }
+}
+
+bool ScUndoClearItems::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+// remove all line breaks of a table
+ScUndoRemoveBreaks::ScUndoRemoveBreaks( ScDocShell* pNewDocShell,
+ SCTAB nNewTab, ScDocumentUniquePtr pNewUndoDoc ) :
+ ScSimpleUndo( pNewDocShell ),
+ nTab( nNewTab ),
+ pUndoDoc( std::move(pNewUndoDoc) )
+{
+}
+
+ScUndoRemoveBreaks::~ScUndoRemoveBreaks()
+{
+}
+
+OUString ScUndoRemoveBreaks::GetComment() const
+{
+ return ScResId( STR_UNDO_REMOVEBREAKS );
+}
+
+void ScUndoRemoveBreaks::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ pUndoDoc->CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::NONE, false, rDoc);
+ if (pViewShell)
+ pViewShell->UpdatePageBreakData( true );
+ pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
+
+ EndUndo();
+}
+
+void ScUndoRemoveBreaks::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ rDoc.RemoveManualBreaks(nTab);
+ rDoc.UpdatePageBreaks(nTab);
+ if (pViewShell)
+ pViewShell->UpdatePageBreakData( true );
+ pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
+
+ EndRedo();
+}
+
+void ScUndoRemoveBreaks::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+ rViewShell.RemoveManualBreaks();
+ }
+}
+
+bool ScUndoRemoveBreaks::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell* pNewDocShell,
+ const ScCellMergeOption& rOption, ScDocumentUniquePtr pNewUndoDoc ) :
+ ScBlockUndo( pNewDocShell, rOption.getFirstSingleRange(), SC_UNDO_SIMPLE ),
+ pUndoDoc( std::move(pNewUndoDoc) )
+{
+ maOptions.push_back( rOption);
+}
+
+ScUndoRemoveMerge::ScUndoRemoveMerge( ScDocShell* pNewDocShell,
+ const ScRange& rRange, ScDocumentUniquePtr pNewUndoDoc ) :
+ ScBlockUndo( pNewDocShell, rRange, SC_UNDO_SIMPLE ),
+ pUndoDoc( std::move(pNewUndoDoc) )
+{
+}
+
+ScUndoRemoveMerge::~ScUndoRemoveMerge()
+{
+}
+
+OUString ScUndoRemoveMerge::GetComment() const
+{
+ return ScResId( STR_UNDO_REMERGE ); // "remove merge"
+}
+
+ScDocument* ScUndoRemoveMerge::GetUndoDoc()
+{
+ return pUndoDoc.get();
+}
+
+void ScUndoRemoveMerge::AddCellMergeOption( const ScCellMergeOption& rOption )
+{
+ maOptions.push_back( rOption);
+}
+
+void ScUndoRemoveMerge::Undo()
+{
+ using ::std::set;
+
+ SetCurTab();
+ BeginUndo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (const auto & rOption : maOptions)
+ {
+ for (const auto& rTab : rOption.maTabs)
+ {
+ OSL_ENSURE(pUndoDoc, "NULL pUndoDoc!");
+ if (!pUndoDoc)
+ continue;
+ // There is no need to extend merge area because it's already been extended.
+ ScRange aRange = rOption.getSingleRange(rTab);
+ rDoc.DeleteAreaTab(aRange, InsertDeleteFlags::ATTRIB);
+ pUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ATTRIB, false, rDoc);
+
+ bool bDidPaint = false;
+ if ( pViewShell )
+ {
+ pViewShell->SetTabNo(rTab);
+ bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true);
+ }
+ if (!bDidPaint)
+ ScUndoUtil::PaintMore(pDocShell, aRange);
+ }
+ }
+
+ EndUndo();
+}
+
+void ScUndoRemoveMerge::Redo()
+{
+ using ::std::set;
+
+ SetCurTab();
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ for (const auto & rOption : maOptions)
+ {
+ for (const SCTAB nTab : rOption.maTabs)
+ {
+ // There is no need to extend merge area because it's already been extended.
+ ScRange aRange = rOption.getSingleRange(nTab);
+
+ const SfxPoolItem& rDefAttr = rDoc.GetPool()->GetDefaultItem( ATTR_MERGE );
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( rDefAttr );
+ rDoc.ApplyPatternAreaTab( rOption.mnStartCol, rOption.mnStartRow,
+ rOption.mnEndCol, rOption.mnEndRow, nTab,
+ aPattern );
+
+ rDoc.RemoveFlagsTab( rOption.mnStartCol, rOption.mnStartRow,
+ rOption.mnEndCol, rOption.mnEndRow, nTab,
+ ScMF::Hor | ScMF::Ver );
+
+ rDoc.ExtendMerge(aRange, true);
+
+ // Paint
+
+ bool bDidPaint = false;
+ if ( pViewShell )
+ {
+ pViewShell->SetTabNo(nTab);
+ bDidPaint = pViewShell->AdjustRowHeight(rOption.mnStartRow, rOption.mnEndRow, true);
+ }
+ if (!bDidPaint)
+ ScUndoUtil::PaintMore(pDocShell, aRange);
+ }
+ }
+
+ EndRedo();
+}
+
+void ScUndoRemoveMerge::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->RemoveMerge();
+}
+
+bool ScUndoRemoveMerge::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+void ScUndoRemoveMerge::SetCurTab()
+{
+ SCTAB nCurTab = ScDocShell::GetCurTab();
+ aBlockRange.aStart.SetTab(nCurTab);
+ aBlockRange.aEnd.SetTab(nCurTab);
+}
+
+/** set only border, for ScRangeList (StarOne) */
+static ScRange lcl_TotalRange( const ScRangeList& rRanges )
+{
+ ScRange aTotal;
+ if ( !rRanges.empty() )
+ {
+ aTotal = rRanges[ 0 ];
+ for ( size_t i = 1, nCount = rRanges.size(); i < nCount; ++i )
+ {
+ ScRange const & rRange = rRanges[ i ];
+ if (rRange.aStart.Col() < aTotal.aStart.Col()) aTotal.aStart.SetCol(rRange.aStart.Col());
+ if (rRange.aStart.Row() < aTotal.aStart.Row()) aTotal.aStart.SetRow(rRange.aStart.Row());
+ if (rRange.aStart.Tab() < aTotal.aStart.Tab()) aTotal.aStart.SetTab(rRange.aStart.Tab());
+ if (rRange.aEnd.Col() > aTotal.aEnd.Col() ) aTotal.aEnd.SetCol( rRange.aEnd.Col() );
+ if (rRange.aEnd.Row() > aTotal.aEnd.Row() ) aTotal.aEnd.SetRow( rRange.aEnd.Row() );
+ if (rRange.aEnd.Tab() > aTotal.aEnd.Tab() ) aTotal.aEnd.SetTab(rRange.aEnd.Tab() );
+ }
+ }
+ return aTotal;
+}
+
+ScUndoBorder::ScUndoBorder(ScDocShell* pNewDocShell,
+ const ScRangeList& rRangeList, ScDocumentUniquePtr pNewUndoDoc,
+ const SvxBoxItem& rNewOuter, const SvxBoxInfoItem& rNewInner)
+ : ScBlockUndo(pNewDocShell, lcl_TotalRange(rRangeList), SC_UNDO_SIMPLE)
+ , xUndoDoc(std::move(pNewUndoDoc))
+{
+ xRanges.reset(new ScRangeList(rRangeList));
+ xOuter.reset(new SvxBoxItem(rNewOuter));
+ xInner.reset(new SvxBoxInfoItem(rNewInner));
+}
+
+OUString ScUndoBorder::GetComment() const
+{
+ return ScResId( STR_UNDO_SELATTRLINES ); //! own string?
+}
+
+void ScUndoBorder::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+ aMarkData.MarkFromRangeList(*xRanges, false);
+ xUndoDoc->CopyToDocument(aBlockRange, InsertDeleteFlags::ATTRIB, true, rDoc, &aMarkData);
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndUndo();
+}
+
+void ScUndoBorder::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument(); // call function at docfunc
+ size_t nCount = xRanges->size();
+ for (size_t i = 0; i < nCount; ++i )
+ {
+ ScRange const & rRange = (*xRanges)[i];
+ SCTAB nTab = rRange.aStart.Tab();
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SetMarkArea( rRange );
+ aMark.SelectTable( nTab, true );
+
+ rDoc.ApplySelectionFrame(aMark, *xOuter, xInner.get());
+ }
+ for (size_t i = 0; i < nCount; ++i)
+ pDocShell->PostPaint( (*xRanges)[i], PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ EndRedo();
+}
+
+void ScUndoBorder::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ //TODO later (when the function has moved from cellsuno to docfunc)
+}
+
+bool ScUndoBorder::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // See above
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undoblk2.cxx b/sc/source/ui/undo/undoblk2.cxx
new file mode 100644
index 000000000..52ee421cc
--- /dev/null
+++ b/sc/source/ui/undo/undoblk2.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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <undoblk.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <olinetab.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <target.hxx>
+#include <columnspanset.hxx>
+
+#include <undoolk.hxx>
+
+#include <svx/svdundo.hxx>
+
+/** Change column widths or row heights */
+ScUndoWidthOrHeight::ScUndoWidthOrHeight( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ SCCOLROW nNewStart, SCTAB nNewStartTab, SCCOLROW nNewEnd, SCTAB nNewEndTab,
+ ScDocumentUniquePtr pNewUndoDoc, std::vector<sc::ColRowSpan>&& rRanges,
+ std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ ScSizeMode eNewMode, sal_uInt16 nNewSizeTwips, bool bNewWidth ) :
+ ScSimpleUndo( pNewDocShell ),
+ aMarkData( rMark ),
+ nStart( nNewStart ),
+ nEnd( nNewEnd ),
+ nStartTab( nNewStartTab ),
+ nEndTab( nNewEndTab ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ pUndoTab( std::move(pNewUndoTab) ),
+ maRanges( std::move(rRanges) ),
+ nNewSize( nNewSizeTwips ),
+ bWidth( bNewWidth ),
+ eMode( eNewMode )
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScUndoWidthOrHeight::~ScUndoWidthOrHeight()
+{
+ pUndoDoc.reset();
+ pUndoTab.reset();
+ pDrawUndo.reset();
+}
+
+OUString ScUndoWidthOrHeight::GetComment() const
+{
+ // [ "optimal " ] "Column width" | "row height"
+ return ( bWidth ?
+ ( ( eMode == SC_SIZE_OPTIMAL )?
+ ScResId( STR_UNDO_OPTCOLWIDTH ) :
+ ScResId( STR_UNDO_COLWIDTH )
+ ) :
+ ( ( eMode == SC_SIZE_OPTIMAL )?
+ ScResId( STR_UNDO_OPTROWHEIGHT ) :
+ ScResId( STR_UNDO_ROWHEIGHT )
+ ) );
+}
+
+void ScUndoWidthOrHeight::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCCOLROW nPaintStart = nStart > 0 ? nStart-1 : static_cast<SCCOLROW>(0);
+
+ if (eMode==SC_SIZE_OPTIMAL)
+ {
+ if ( SetViewMarkData( aMarkData ) )
+ nPaintStart = 0; // paint all, because of changed selection
+ }
+
+ //! outlines from all tables?
+ if (pUndoTab) // Outlines are included when saving ?
+ rDoc.SetOutlineTable( nStartTab, pUndoTab.get() );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+
+ if (pViewShell)
+ pViewShell->OnLOKSetWidthOrHeight(nStart, bWidth);
+
+ if (bWidth) // Width
+ {
+ pUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart), 0, rTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), rTab, InsertDeleteFlags::NONE,
+ false, rDoc);
+ rDoc.UpdatePageBreaks( rTab );
+ pDocShell->PostPaint( static_cast<SCCOL>(nPaintStart), 0, rTab,
+ rDoc.MaxCol(), rDoc.MaxRow(), rTab, PaintPartFlags::Grid | PaintPartFlags::Top );
+ }
+ else // Height
+ {
+ pUndoDoc->CopyToDocument(0, nStart, rTab, rDoc.MaxCol(), nEnd, rTab, InsertDeleteFlags::NONE, false, rDoc);
+ rDoc.UpdatePageBreaks( rTab );
+ pDocShell->PostPaint( 0, nPaintStart, rTab, rDoc.MaxCol(), rDoc.MaxRow(), rTab, PaintPartFlags::Grid | PaintPartFlags::Left );
+ }
+ }
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc );
+
+ if (pViewShell)
+ {
+ SCTAB nCurrentTab = pViewShell->GetViewData().GetTabNo();
+ bool bAffectsVisibility = (eMode != SC_SIZE_ORIGINAL && eMode != SC_SIZE_VISOPT);
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell, bWidth /* bColumns */, !bWidth /* bRows */,
+ true /* bSizes*/, bAffectsVisibility /* bHidden */, bAffectsVisibility /* bFiltered */,
+ false /* bGroups */, nCurrentTab);
+ pViewShell->UpdateScrollBars(bWidth ? COLUMN_HEADER : ROW_HEADER);
+
+ if ( nCurrentTab < nStartTab || nCurrentTab > nEndTab )
+ pViewShell->SetTabNo( nStartTab );
+ }
+
+ EndUndo();
+}
+
+void ScUndoWidthOrHeight::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ bool bPaintAll = false;
+ if (eMode==SC_SIZE_OPTIMAL)
+ {
+ if ( SetViewMarkData( aMarkData ) )
+ bPaintAll = true; // paint all, because of changed selection
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ if ( nTab < nStartTab || nTab > nEndTab )
+ pViewShell->SetTabNo( nStartTab );
+
+ // SetWidthOrHeight changes current sheet!
+ pViewShell->SetWidthOrHeight(
+ bWidth, maRanges, eMode, nNewSize, false, &aMarkData);
+ }
+
+ // paint grid if selection was changed directly at the MarkData
+ if (bPaintAll)
+ pDocShell->PostPaint( 0, 0, nStartTab, rDoc.MaxCol(), rDoc.MaxRow(), nEndTab, PaintPartFlags::Grid );
+
+ EndRedo();
+}
+
+void ScUndoWidthOrHeight::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->SetMarkedWidthOrHeight( bWidth, eMode, nNewSize );
+}
+
+bool ScUndoWidthOrHeight::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undoblk3.cxx b/sc/source/ui/undo/undoblk3.cxx
new file mode 100644
index 000000000..0e8782211
--- /dev/null
+++ b/sc/source/ui/undo/undoblk3.cxx
@@ -0,0 +1,1743 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <scitems.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <svl/srchitem.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <vcl/virdev.hxx>
+#include <sfx2/app.hxx>
+#include <svx/svdundo.hxx>
+#include <osl/diagnose.h>
+
+#include <undoblk.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <arealink.hxx>
+#include <patattr.hxx>
+#include <target.hxx>
+#include <document.hxx>
+#include <docpool.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <undoolk.hxx>
+#include <undoutil.hxx>
+#include <chgtrack.hxx>
+#include <paramisc.hxx>
+#include <postit.hxx>
+#include <progress.hxx>
+#include <editutil.hxx>
+#include <editdataarray.hxx>
+#include <rowheightcontext.hxx>
+
+// TODO:
+/*A*/ // SetOptimalHeight on Document, when no View
+
+ScUndoDeleteContents::ScUndoDeleteContents(
+ ScDocShell* pNewDocShell,
+ const ScMarkData& rMark, const ScRange& rRange,
+ ScDocumentUniquePtr&& pNewUndoDoc, bool bNewMulti,
+ InsertDeleteFlags nNewFlags, bool bObjects )
+ : ScSimpleUndo( pNewDocShell ),
+ aRange ( rRange ),
+ aMarkData ( rMark ),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ nFlags ( nNewFlags ),
+ bMulti ( bNewMulti ) // unnecessary
+{
+ if (bObjects)
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+
+ if ( !(aMarkData.IsMarked() || aMarkData.IsMultiMarked()) ) // if no cell is selected:
+ aMarkData.SetMarkArea( aRange ); // select cell under cursor
+
+ SetChangeTrack();
+}
+
+ScUndoDeleteContents::~ScUndoDeleteContents()
+{
+ pUndoDoc.reset();
+ pDrawUndo.reset();
+}
+
+OUString ScUndoDeleteContents::GetComment() const
+{
+ return ScResId( STR_UNDO_DELETECONTENTS ); // "Delete"
+}
+
+void ScUndoDeleteContents::SetDataSpans( const std::shared_ptr<DataSpansType>& pSpans )
+{
+ mpDataSpans = pSpans;
+}
+
+void ScUndoDeleteContents::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack && (nFlags & InsertDeleteFlags::CONTENTS) )
+ pChangeTrack->AppendContentRange( aRange, pUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoDeleteContents::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SetViewMarkData( aMarkData );
+
+ sal_uInt16 nExtFlags = 0;
+
+ if (bUndo) // only Undo
+ {
+ InsertDeleteFlags nUndoFlags = InsertDeleteFlags::NONE; // copy either all or none of the content
+ if (nFlags & InsertDeleteFlags::CONTENTS) // (Only the correct ones have been copied into UndoDoc)
+ nUndoFlags |= InsertDeleteFlags::CONTENTS;
+ if (nFlags & InsertDeleteFlags::ATTRIB)
+ nUndoFlags |= InsertDeleteFlags::ATTRIB;
+ if (nFlags & InsertDeleteFlags::EDITATTR) // Edit-Engine attribute
+ nUndoFlags |= InsertDeleteFlags::STRING; // -> Cells will be changed
+ if (nFlags & InsertDeleteFlags::SPARKLINES)
+ nUndoFlags |= InsertDeleteFlags::SPARKLINES;
+ // do not create clones of note captions, they will be restored via drawing undo
+ nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
+
+ ScRange aCopyRange = aRange;
+ SCTAB nTabCount = rDoc.GetTableCount();
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+
+ pUndoDoc->CopyToDocument(aCopyRange, nUndoFlags, bMulti, rDoc, &aMarkData);
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc );
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ pDocShell->UpdatePaintExt( nExtFlags, aRange ); // content after the change
+ }
+ else // only Redo
+ {
+ pDocShell->UpdatePaintExt( nExtFlags, aRange ); // content before the change
+
+ aMarkData.MarkToMulti();
+ RedoSdrUndoAction( pDrawUndo.get() );
+ // do not delete objects and note captions, they have been removed via drawing undo
+ InsertDeleteFlags nRedoFlags = (nFlags & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS;
+ rDoc.DeleteSelection( nRedoFlags, aMarkData );
+ aMarkData.MarkToSimple();
+
+ SetChangeTrack();
+ }
+
+ if (nFlags & InsertDeleteFlags::CONTENTS)
+ {
+ // Broadcast only when the content changes. fdo#74687
+ if (mpDataSpans)
+ BroadcastChanges(*mpDataSpans);
+ else
+ BroadcastChanges(aRange);
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( !( pViewShell && pViewShell->AdjustRowHeight(
+ aRange.aStart.Row(), aRange.aEnd.Row(), true ) ) )
+/*A*/ pDocShell->PostPaint( aRange, PaintPartFlags::Grid | PaintPartFlags::Extras, nExtFlags );
+
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ ShowTable( aRange );
+}
+
+void ScUndoDeleteContents::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocShell, aRange);
+}
+
+void ScUndoDeleteContents::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocShell, aRange);
+}
+
+void ScUndoDeleteContents::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->DeleteContents( nFlags );
+}
+
+bool ScUndoDeleteContents::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoFillTable::ScUndoFillTable( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, bool bNewMulti, SCTAB nSrc,
+ InsertDeleteFlags nFlg, ScPasteFunc nFunc, bool bSkip, bool bLink )
+ : ScSimpleUndo( pNewDocShell ),
+ aRange ( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ ),
+ aMarkData ( rMark ),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ nFlags ( nFlg ),
+ nFunction ( nFunc ),
+ nSrcTab ( nSrc ),
+ bMulti ( bNewMulti ),
+ bSkipEmpty ( bSkip ),
+ bAsLink ( bLink )
+{
+ SetChangeTrack();
+}
+
+ScUndoFillTable::~ScUndoFillTable()
+{
+}
+
+OUString ScUndoFillTable::GetComment() const
+{
+ return ScResId( STR_FILL_TAB );
+}
+
+void ScUndoFillTable::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ SCTAB nTabCount = pDocShell->GetDocument().GetTableCount();
+ ScRange aWorkRange(aRange);
+ nStartChangeAction = 0;
+ sal_uLong nTmpAction;
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+ if (rTab != nSrcTab)
+ {
+ aWorkRange.aStart.SetTab(rTab);
+ aWorkRange.aEnd.SetTab(rTab);
+ pChangeTrack->AppendContentRange( aWorkRange, pUndoDoc.get(),
+ nTmpAction, nEndChangeAction );
+ if ( !nStartChangeAction )
+ nStartChangeAction = nTmpAction;
+ }
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoFillTable::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SetViewMarkData( aMarkData );
+
+ if (bUndo) // only Undo
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ ScRange aWorkRange(aRange);
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+ if (rTab != nSrcTab)
+ {
+ aWorkRange.aStart.SetTab(rTab);
+ aWorkRange.aEnd.SetTab(rTab);
+ if (bMulti)
+ rDoc.DeleteSelectionTab( rTab, InsertDeleteFlags::ALL, aMarkData );
+ else
+ rDoc.DeleteAreaTab( aWorkRange, InsertDeleteFlags::ALL );
+ pUndoDoc->CopyToDocument(aWorkRange, InsertDeleteFlags::ALL, bMulti, rDoc, &aMarkData);
+ }
+ }
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+ }
+ else // only Redo
+ {
+ aMarkData.MarkToMulti();
+ rDoc.FillTabMarked( nSrcTab, aMarkData, nFlags, nFunction, bSkipEmpty, bAsLink );
+ aMarkData.MarkToSimple();
+ SetChangeTrack();
+ }
+
+ pDocShell->PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Extras);
+ pDocShell->PostDataChanged();
+
+ // CellContentChanged comes with the selection
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ SCTAB nTab = pViewShell->GetViewData().GetTabNo();
+ if ( !aMarkData.GetTableSelect(nTab) )
+ pViewShell->SetTabNo( nSrcTab );
+
+ pViewShell->DoneBlockMode(); // causes problems otherwise since selection is on the wrong sheet.
+ }
+}
+
+void ScUndoFillTable::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoFillTable::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoFillTable::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->FillTab( nFlags, nFunction, bSkipEmpty, bAsLink );
+}
+
+bool ScUndoFillTable::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoSelectionAttr::ScUndoSelectionAttr( ScDocShell* pNewDocShell,
+ const ScMarkData& rMark,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, bool bNewMulti,
+ const ScPatternAttr* pNewApply,
+ const SvxBoxItem* pNewOuter, const SvxBoxInfoItem* pNewInner,
+ const ScRange* pRangeCover )
+ : ScSimpleUndo( pNewDocShell ),
+ aMarkData ( rMark ),
+ aRange ( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ ),
+ mpDataArray(new ScEditDataArray),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ bMulti ( bNewMulti )
+{
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ pApplyPattern = const_cast<ScPatternAttr*>(&pPool->Put( *pNewApply ));
+ pLineOuter = pNewOuter ? const_cast<SvxBoxItem*>( &pPool->Put( *pNewOuter ) ) : nullptr;
+ pLineInner = pNewInner ? const_cast<SvxBoxInfoItem*>( &pPool->Put( *pNewInner ) ) : nullptr;
+ aRangeCover = pRangeCover ? *pRangeCover : aRange;
+}
+
+ScUndoSelectionAttr::~ScUndoSelectionAttr()
+{
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ pPool->Remove(*pApplyPattern);
+ if (pLineOuter)
+ pPool->Remove(*pLineOuter);
+ if (pLineInner)
+ pPool->Remove(*pLineInner);
+
+ pUndoDoc.reset();
+}
+
+OUString ScUndoSelectionAttr::GetComment() const
+{
+ //"Attribute" "/Lines"
+ return ScResId( pLineOuter ? STR_UNDO_SELATTRLINES : STR_UNDO_SELATTR );
+}
+
+ScEditDataArray* ScUndoSelectionAttr::GetDataArray()
+{
+ return mpDataArray.get();
+}
+
+void ScUndoSelectionAttr::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SetViewMarkData( aMarkData );
+
+ ScRange aEffRange( aRangeCover );
+ if ( rDoc.HasAttrib( aEffRange, HasAttrFlags::Merged ) ) // merged cells?
+ rDoc.ExtendMerge( aEffRange );
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aEffRange );
+
+ ChangeEditData(bUndo);
+
+ if (bUndo) // only for Undo
+ {
+ ScRange aCopyRange = aRangeCover;
+ SCTAB nTabCount = rDoc.GetTableCount();
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, bMulti, rDoc, &aMarkData);
+ }
+ else // only for Redo
+ {
+ aMarkData.MarkToMulti();
+ rDoc.ApplySelectionPattern( *pApplyPattern, aMarkData );
+ aMarkData.MarkToSimple();
+
+ if (pLineOuter)
+ rDoc.ApplySelectionFrame(aMarkData, *pLineOuter, pLineInner);
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( !( pViewShell && pViewShell->AdjustBlockHeight() ) )
+/*A*/ pDocShell->PostPaint( aEffRange, PaintPartFlags::Grid | PaintPartFlags::Extras, nExtFlags );
+
+ ShowTable( aRange );
+}
+
+void ScUndoSelectionAttr::ChangeEditData( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (const ScEditDataArray::Item* pItem = mpDataArray->First(); pItem; pItem = mpDataArray->Next())
+ {
+ ScAddress aPos(pItem->GetCol(), pItem->GetRow(), pItem->GetTab());
+ if (rDoc.GetCellType(aPos) != CELLTYPE_EDIT)
+ continue;
+
+ if (bUndo)
+ {
+ if (pItem->GetOldData())
+ rDoc.SetEditText(aPos, *pItem->GetOldData(), nullptr);
+ else
+ rDoc.SetEmptyCell(aPos);
+ }
+ else
+ {
+ if (pItem->GetNewData())
+ rDoc.SetEditText(aPos, *pItem->GetNewData(), nullptr);
+ else
+ rDoc.SetEmptyCell(aPos);
+ }
+ }
+}
+
+void ScUndoSelectionAttr::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoSelectionAttr::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoSelectionAttr::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+ if (pLineOuter)
+ rViewShell.ApplyPatternLines(*pApplyPattern, *pLineOuter, pLineInner);
+ else
+ rViewShell.ApplySelectionPattern( *pApplyPattern );
+ }
+}
+
+bool ScUndoSelectionAttr::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoAutoFill::ScUndoAutoFill( ScDocShell* pNewDocShell,
+ const ScRange& rRange, const ScRange& rSourceArea,
+ ScDocumentUniquePtr pNewUndoDoc, const ScMarkData& rMark,
+ FillDir eNewFillDir, FillCmd eNewFillCmd, FillDateCmd eNewFillDateCmd,
+ double fNewStartValue, double fNewStepValue, double fNewMaxValue )
+ : ScBlockUndo( pNewDocShell, rRange, SC_UNDO_AUTOHEIGHT ),
+ aSource ( rSourceArea ),
+ aMarkData ( rMark ),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ eFillDir ( eNewFillDir ),
+ eFillCmd ( eNewFillCmd ),
+ eFillDateCmd ( eNewFillDateCmd ),
+ fStartValue ( fNewStartValue ),
+ fStepValue ( fNewStepValue ),
+ fMaxValue ( fNewMaxValue )
+{
+ SetChangeTrack();
+}
+
+ScUndoAutoFill::~ScUndoAutoFill()
+{
+}
+
+OUString ScUndoAutoFill::GetComment() const
+{
+ return ScResId( STR_UNDO_AUTOFILL ); //"Fill"
+}
+
+void ScUndoAutoFill::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->AppendContentRange( aBlockRange, pUndoDoc.get(),
+ nStartChangeAction, nEndChangeAction );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoAutoFill::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (const auto& rTab : aMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+ ScRange aWorkRange = aBlockRange;
+ aWorkRange.aStart.SetTab(rTab);
+ aWorkRange.aEnd.SetTab(rTab);
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aWorkRange );
+ rDoc.DeleteAreaTab( aWorkRange, InsertDeleteFlags::AUTOFILL );
+ pUndoDoc->CopyToDocument(aWorkRange, InsertDeleteFlags::AUTOFILL, false, rDoc);
+
+ // Actually we'd only need to broadcast the cells inserted during
+ // CopyToDocument(), as DeleteAreaTab() broadcasts deleted cells. For
+ // this we'd need to either record the span sets or let
+ // CopyToDocument() broadcast.
+ BroadcastChanges( aWorkRange);
+
+ rDoc.ExtendMerge( aWorkRange, true );
+ pDocShell->PostPaint( aWorkRange, PaintPartFlags::Grid, nExtFlags );
+ }
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ EndUndo();
+}
+
+void ScUndoAutoFill::Redo()
+{
+ BeginRedo();
+
+//! Select sheet
+
+ SCCOLROW nCount = 0;
+ switch (eFillDir)
+ {
+ case FILL_TO_BOTTOM:
+ nCount = aBlockRange.aEnd.Row() - aSource.aEnd.Row();
+ break;
+ case FILL_TO_RIGHT:
+ nCount = aBlockRange.aEnd.Col() - aSource.aEnd.Col();
+ break;
+ case FILL_TO_TOP:
+ nCount = aSource.aStart.Row() - aBlockRange.aStart.Row();
+ break;
+ case FILL_TO_LEFT:
+ nCount = aSource.aStart.Col() - aBlockRange.aStart.Col();
+ break;
+ }
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( fStartValue != MAXDOUBLE )
+ {
+ SCCOL nValX = (eFillDir == FILL_TO_LEFT) ? aSource.aEnd.Col() : aSource.aStart.Col();
+ SCROW nValY = (eFillDir == FILL_TO_TOP ) ? aSource.aEnd.Row() : aSource.aStart.Row();
+ SCTAB nTab = aSource.aStart.Tab();
+ rDoc.SetValue( nValX, nValY, nTab, fStartValue );
+ }
+ sal_uLong nProgCount;
+ if (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP)
+ nProgCount = aSource.aEnd.Col() - aSource.aStart.Col() + 1;
+ else
+ nProgCount = aSource.aEnd.Row() - aSource.aStart.Row() + 1;
+ nProgCount *= nCount;
+ ScProgress aProgress( rDoc.GetDocumentShell(),
+ ScResId(STR_FILL_SERIES_PROGRESS), nProgCount, true );
+
+ rDoc.Fill( aSource.aStart.Col(), aSource.aStart.Row(),
+ aSource.aEnd.Col(), aSource.aEnd.Row(), &aProgress,
+ aMarkData, nCount,
+ eFillDir, eFillCmd, eFillDateCmd,
+ fStepValue, fMaxValue );
+
+ SetChangeTrack();
+
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ EndRedo();
+}
+
+void ScUndoAutoFill::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+ if (eFillCmd==FILL_SIMPLE)
+ rViewShell.FillSimple( eFillDir );
+ else
+ rViewShell.FillSeries( eFillDir, eFillCmd, eFillDateCmd,
+ fStartValue, fStepValue, fMaxValue );
+ }
+}
+
+bool ScUndoAutoFill::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoMerge::ScUndoMerge(ScDocShell* pNewDocShell, const ScCellMergeOption& rOption,
+ bool bMergeContents, ScDocumentUniquePtr pUndoDoc, std::unique_ptr<SdrUndoAction> pDrawUndo)
+ : ScSimpleUndo(pNewDocShell)
+ , maOption(rOption)
+ , mbMergeContents(bMergeContents)
+ , mxUndoDoc(std::move(pUndoDoc))
+ , mpDrawUndo(std::move(pDrawUndo))
+{
+}
+
+ScUndoMerge::~ScUndoMerge()
+{
+ mpDrawUndo.reset();
+}
+
+OUString ScUndoMerge::GetComment() const
+{
+ return ScResId( STR_UNDO_MERGE );
+}
+
+void ScUndoMerge::DoChange( bool bUndo ) const
+{
+ using ::std::set;
+
+ if (maOption.maTabs.empty())
+ // Nothing to do.
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScRange aCurRange = maOption.getSingleRange(ScDocShell::GetCurTab());
+ ScUndoUtil::MarkSimpleBlock(pDocShell, aCurRange);
+
+ for (const SCTAB nTab : maOption.maTabs)
+ {
+ ScRange aRange = maOption.getSingleRange(nTab);
+
+ if (bUndo)
+ // remove merge (contents are copied back below from undo document)
+ rDoc.RemoveMerge( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aStart.Tab() );
+ else
+ {
+ // repeat merge, but do not remove note captions (will be done by drawing redo below)
+ rDoc.DoMerge( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(),
+ aRange.aStart.Tab(), false );
+
+ if (maOption.mbCenter)
+ {
+ rDoc.ApplyAttr( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab(),
+ SvxHorJustifyItem( SvxCellHorJustify::Center, ATTR_HOR_JUSTIFY ) );
+ rDoc.ApplyAttr( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab(),
+ SvxVerJustifyItem( SvxCellVerJustify::Center, ATTR_VER_JUSTIFY ) );
+ }
+ }
+
+ // undo -> copy back deleted contents
+ if (bUndo && mxUndoDoc)
+ {
+ // If there are note captions to be deleted during Undo they were
+ // kept or moved during the merge and copied to the Undo document
+ // without cloning the caption. Forget the target area's caption
+ // pointer that is identical to the one in the Undo document
+ // instead of deleting it.
+ rDoc.DeleteAreaTab( aRange,
+ InsertDeleteFlags::CONTENTS | InsertDeleteFlags::NOCAPTIONS | InsertDeleteFlags::FORGETCAPTIONS );
+ mxUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL|InsertDeleteFlags::NOCAPTIONS, false, rDoc);
+ }
+
+ // redo -> merge contents again
+ else if (!bUndo && mbMergeContents)
+ {
+ rDoc.DoMergeContents( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(),
+ aRange.aStart.Tab() );
+ }
+
+ if (bUndo)
+ DoSdrUndoAction( mpDrawUndo.get(), &rDoc );
+ else
+ RedoSdrUndoAction( mpDrawUndo.get() );
+
+ bool bDidPaint = false;
+ if ( pViewShell )
+ {
+ pViewShell->SetTabNo(nTab);
+ bDidPaint = pViewShell->AdjustRowHeight(maOption.mnStartRow, maOption.mnEndRow, true);
+ }
+
+ if (!bDidPaint)
+ ScUndoUtil::PaintMore(pDocShell, aRange);
+
+ rDoc.BroadcastCells(aRange, SfxHintId::ScDataChanged);
+ }
+
+ ShowTable(aCurRange);
+}
+
+void ScUndoMerge::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoMerge::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoMerge::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+ bool bCont = false;
+ rViewShell.MergeCells( false, bCont, false );
+ }
+}
+
+bool ScUndoMerge::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoAutoFormat::ScUndoAutoFormat( ScDocShell* pNewDocShell,
+ const ScRange& rRange, ScDocumentUniquePtr pNewUndoDoc,
+ const ScMarkData& rMark, bool bNewSize, sal_uInt16 nNewFormatNo )
+ : ScBlockUndo( pNewDocShell, rRange, bNewSize ? SC_UNDO_MANUALHEIGHT : SC_UNDO_AUTOHEIGHT ),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ aMarkData ( rMark ),
+ bSize ( bNewSize ),
+ nFormatNo ( nNewFormatNo )
+{
+}
+
+ScUndoAutoFormat::~ScUndoAutoFormat()
+{
+}
+
+OUString ScUndoAutoFormat::GetComment() const
+{
+ return ScResId( STR_UNDO_AUTOFORMAT ); //"Auto-Format"
+}
+
+void ScUndoAutoFormat::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ rDoc.DeleteArea( aBlockRange.aStart.Col(), aBlockRange.aStart.Row(),
+ aBlockRange.aEnd.Col(), aBlockRange.aEnd.Row(),
+ aMarkData, InsertDeleteFlags::ATTRIB );
+ ScRange aCopyRange = aBlockRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ATTRIB, false, rDoc, &aMarkData);
+
+ // cell heights and widths (InsertDeleteFlags::NONE)
+ if (bSize)
+ {
+ SCCOL nStartX = aBlockRange.aStart.Col();
+ SCROW nStartY = aBlockRange.aStart.Row();
+ SCTAB nStartZ = aBlockRange.aStart.Tab();
+ SCCOL nEndX = aBlockRange.aEnd.Col();
+ SCROW nEndY = aBlockRange.aEnd.Row();
+ SCTAB nEndZ = aBlockRange.aEnd.Tab();
+
+ pUndoDoc->CopyToDocument( nStartX, 0, 0, nEndX, rDoc.MaxRow(), nTabCount-1,
+ InsertDeleteFlags::NONE, false, rDoc, &aMarkData );
+ pUndoDoc->CopyToDocument( 0, nStartY, 0, rDoc.MaxCol(), nEndY, nTabCount-1,
+ InsertDeleteFlags::NONE, false, rDoc, &aMarkData );
+ pDocShell->PostPaint( 0, 0, nStartZ, rDoc.MaxCol(), rDoc.MaxRow(), nEndZ,
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top, SC_PF_LINES );
+ }
+ else
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES );
+
+ EndUndo();
+}
+
+void ScUndoAutoFormat::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCCOL nStartX = aBlockRange.aStart.Col();
+ SCROW nStartY = aBlockRange.aStart.Row();
+ SCTAB nStartZ = aBlockRange.aStart.Tab();
+ SCCOL nEndX = aBlockRange.aEnd.Col();
+ SCROW nEndY = aBlockRange.aEnd.Row();
+ SCTAB nEndZ = aBlockRange.aEnd.Tab();
+
+ rDoc.AutoFormat( nStartX, nStartY, nEndX, nEndY, nFormatNo, aMarkData );
+
+ if (bSize)
+ {
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ Fraction aZoomX(1,1);
+ Fraction aZoomY = aZoomX;
+ double nPPTX,nPPTY;
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ ScViewData& rData = pViewShell->GetViewData();
+ nPPTX = rData.GetPPTX();
+ nPPTY = rData.GetPPTY();
+ aZoomX = rData.GetZoomX();
+ aZoomY = rData.GetZoomY();
+ }
+ else
+ {
+ // Keep zoom at 100
+ nPPTX = ScGlobal::nScreenPPTX;
+ nPPTY = ScGlobal::nScreenPPTY;
+ }
+
+ sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, aZoomX, aZoomY, pVirtDev);
+ for (SCTAB nTab=nStartZ; nTab<=nEndZ; nTab++)
+ {
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ aDestMark.SelectOneTable( nTab );
+ aDestMark.SetMarkArea( ScRange( nStartX, nStartY, nTab, nEndX, nEndY, nTab ) );
+ aDestMark.MarkToMulti();
+
+ // as SC_SIZE_VISOPT
+ for (SCROW nRow=nStartY; nRow<=nEndY; nRow++)
+ {
+ CRFlags nOld = rDoc.GetRowFlags(nRow,nTab);
+ bool bHidden = rDoc.RowHidden(nRow, nTab);
+ if ( !bHidden && ( nOld & CRFlags::ManualSize ) )
+ rDoc.SetRowFlags( nRow, nTab, nOld & ~CRFlags::ManualSize );
+ }
+
+ bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartY, nEndY, nTab, true);
+
+ for (SCCOL nCol=nStartX; nCol<=nEndX; nCol++)
+ if (!rDoc.ColHidden(nCol, nTab))
+ {
+ sal_uInt16 nThisSize = STD_EXTRA_WIDTH + rDoc.GetOptimalColWidth( nCol, nTab,
+ pVirtDev, nPPTX, nPPTY, aZoomX, aZoomY, false/*bFormula*/,
+ &aDestMark );
+ rDoc.SetColWidth( nCol, nTab, nThisSize );
+ rDoc.ShowCol( nCol, nTab, true );
+ }
+
+ // tdf#76183: recalculate objects' positions
+ if (bChanged)
+ rDoc.SetDrawPageSize(nTab);
+ }
+
+ pDocShell->PostPaint( 0, 0, nStartZ,
+ rDoc.MaxCol(), rDoc.MaxRow(), nEndZ,
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top, SC_PF_LINES);
+ }
+ else
+ pDocShell->PostPaint( aBlockRange, PaintPartFlags::Grid, SC_PF_LINES );
+
+ EndRedo();
+}
+
+void ScUndoAutoFormat::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->AutoFormat( nFormatNo );
+}
+
+bool ScUndoAutoFormat::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoReplace::ScUndoReplace( ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
+ const OUString& rNewUndoStr, ScDocumentUniquePtr pNewUndoDoc,
+ const SvxSearchItem* pItem )
+ : ScSimpleUndo( pNewDocShell ),
+ aCursorPos ( nCurX, nCurY, nCurZ ),
+ aMarkData ( rMark ),
+ aUndoStr ( rNewUndoStr ),
+ pUndoDoc ( std::move(pNewUndoDoc) )
+{
+ pSearchItem.reset( new SvxSearchItem( *pItem ) );
+ SetChangeTrack();
+}
+
+ScUndoReplace::~ScUndoReplace()
+{
+ pUndoDoc.reset();
+ pSearchItem.reset();
+}
+
+void ScUndoReplace::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ if ( pUndoDoc )
+ { //! UndoDoc includes only the changed cells,
+ // that is why an Iterator can be used
+ pChangeTrack->AppendContentsIfInRefDoc( *pUndoDoc,
+ nStartChangeAction, nEndChangeAction );
+ }
+ else
+ {
+ nStartChangeAction = pChangeTrack->GetActionMax() + 1;
+ ScChangeActionContent* pContent = new ScChangeActionContent(
+ ScRange( aCursorPos) );
+ ScCellValue aCell;
+ aCell.assign(rDoc, aCursorPos);
+ pContent->SetOldValue( aUndoStr, &rDoc );
+ pContent->SetNewValue(aCell, &rDoc);
+ pChangeTrack->Append( pContent );
+ nEndChangeAction = pChangeTrack->GetActionMax();
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+OUString ScUndoReplace::GetComment() const
+{
+ return ScResId( STR_UNDO_REPLACE ); // "Replace"
+}
+
+void ScUndoReplace::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ShowTable( aCursorPos.Tab() );
+
+ if (pUndoDoc) // only for ReplaceAll !!
+ {
+ OSL_ENSURE(pSearchItem->GetCommand() == SvxSearchCmd::REPLACE_ALL,
+ "ScUndoReplace:: Wrong Mode");
+
+ SetViewMarkData( aMarkData );
+
+//! selected sheet
+//! select range ?
+
+ // Undo document has no row/column information, thus copy with
+ // bColRowFlags = FALSE to not destroy Outline groups
+
+ InsertDeleteFlags nUndoFlags = (pSearchItem->GetPattern()) ? InsertDeleteFlags::ATTRIB : InsertDeleteFlags::CONTENTS;
+ pUndoDoc->CopyToDocument( 0, 0, 0,
+ rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB,
+ nUndoFlags, false, rDoc, nullptr, false ); // without row flags
+ pDocShell->PostPaintGridAll();
+ }
+ else if (pSearchItem->GetPattern() &&
+ pSearchItem->GetCommand() == SvxSearchCmd::REPLACE)
+ {
+ OUString aTempStr = pSearchItem->GetSearchString(); // toggle
+ pSearchItem->SetSearchString(pSearchItem->GetReplaceString());
+ pSearchItem->SetReplaceString(aTempStr);
+ rDoc.ReplaceStyle( *pSearchItem,
+ aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(),
+ aMarkData);
+ pSearchItem->SetReplaceString(pSearchItem->GetSearchString());
+ pSearchItem->SetSearchString(aTempStr);
+ if (pViewShell)
+ pViewShell->MoveCursorAbs( aCursorPos.Col(), aCursorPos.Row(),
+ SC_FOLLOW_JUMP, false, false );
+ pDocShell->PostPaintGridAll();
+ }
+ else if (pSearchItem->GetCellType() == SvxSearchCellType::NOTE)
+ {
+ ScPostIt* pNote = rDoc.GetNote(aCursorPos);
+ OSL_ENSURE( pNote, "ScUndoReplace::Undo - cell does not contain a note" );
+ if (pNote)
+ pNote->SetText( aCursorPos, aUndoStr );
+ if (pViewShell)
+ pViewShell->MoveCursorAbs( aCursorPos.Col(), aCursorPos.Row(),
+ SC_FOLLOW_JUMP, false, false );
+ }
+ else
+ {
+ // aUndoStr may contain line breaks
+ if ( aUndoStr.indexOf('\n') != -1 )
+ {
+ ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
+ rEngine.SetTextCurrentDefaults(aUndoStr);
+ rDoc.SetEditText(aCursorPos, rEngine.CreateTextObject());
+ }
+ else
+ rDoc.SetString( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(), aUndoStr );
+ if (pViewShell)
+ pViewShell->MoveCursorAbs( aCursorPos.Col(), aCursorPos.Row(),
+ SC_FOLLOW_JUMP, false, false );
+ pDocShell->PostPaintGridAll();
+ }
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ EndUndo();
+}
+
+void ScUndoReplace::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ if (pViewShell)
+ pViewShell->MoveCursorAbs( aCursorPos.Col(), aCursorPos.Row(),
+ SC_FOLLOW_JUMP, false, false );
+ if (pUndoDoc)
+ {
+ if (pViewShell)
+ {
+ SetViewMarkData( aMarkData );
+
+ pViewShell->SearchAndReplace( pSearchItem.get(), false, true );
+ }
+ }
+ else if (pSearchItem->GetPattern() &&
+ pSearchItem->GetCommand() == SvxSearchCmd::REPLACE)
+ {
+ rDoc.ReplaceStyle( *pSearchItem,
+ aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(),
+ aMarkData);
+ pDocShell->PostPaintGridAll();
+ }
+ else
+ if (pViewShell)
+ pViewShell->SearchAndReplace( pSearchItem.get(), false, true );
+
+ SetChangeTrack();
+
+ EndRedo();
+}
+
+void ScUndoReplace::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->SearchAndReplace( pSearchItem.get(), true, false );
+}
+
+bool ScUndoReplace::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+// multi-operation (only simple blocks)
+ScUndoTabOp::ScUndoTabOp( ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ, ScDocumentUniquePtr pNewUndoDoc,
+ const ScRefAddress& rFormulaCell,
+ const ScRefAddress& rFormulaEnd,
+ const ScRefAddress& rRowCell,
+ const ScRefAddress& rColCell,
+ ScTabOpParam::Mode eMode )
+ : ScSimpleUndo( pNewDocShell ),
+ aRange ( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ ),
+ pUndoDoc ( std::move(pNewUndoDoc) ),
+ theFormulaCell ( rFormulaCell ),
+ theFormulaEnd ( rFormulaEnd ),
+ theRowCell ( rRowCell ),
+ theColCell ( rColCell ),
+ meMode(eMode)
+{
+}
+
+ScUndoTabOp::~ScUndoTabOp()
+{
+}
+
+OUString ScUndoTabOp::GetComment() const
+{
+ return ScResId( STR_UNDO_TABOP ); // "Multiple operation"
+}
+
+void ScUndoTabOp::Undo()
+{
+ BeginUndo();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aRange );
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aRange );
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.DeleteAreaTab( aRange,InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ pUndoDoc->CopyToDocument( aRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc );
+ pDocShell->PostPaint( aRange, PaintPartFlags::Grid, nExtFlags );
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+
+ EndUndo();
+}
+
+void ScUndoTabOp::Redo()
+{
+ BeginRedo();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aRange );
+
+ ScTabOpParam aParam(theFormulaCell, theFormulaEnd, theRowCell, theColCell, meMode);
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->TabOp( aParam, false);
+
+ EndRedo();
+}
+
+void ScUndoTabOp::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoTabOp::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoConversion::ScUndoConversion(
+ ScDocShell* pNewDocShell, const ScMarkData& rMark,
+ SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, ScDocumentUniquePtr pNewUndoDoc,
+ SCCOL nNewX, SCROW nNewY, SCTAB nNewZ, ScDocumentUniquePtr pNewRedoDoc,
+ const ScConversionParam& rConvParam ) :
+ ScSimpleUndo( pNewDocShell ),
+ aMarkData( rMark ),
+ aCursorPos( nCurX, nCurY, nCurZ ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ aNewCursorPos( nNewX, nNewY, nNewZ ),
+ pRedoDoc( std::move(pNewRedoDoc) ),
+ maConvParam( rConvParam )
+{
+ SetChangeTrack();
+}
+
+ScUndoConversion::~ScUndoConversion()
+{
+ pUndoDoc.reset();
+ pRedoDoc.reset();
+}
+
+void ScUndoConversion::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ if ( pUndoDoc )
+ pChangeTrack->AppendContentsIfInRefDoc( *pUndoDoc,
+ nStartChangeAction, nEndChangeAction );
+ else
+ {
+ OSL_FAIL( "ScUndoConversion::SetChangeTrack: no UndoDoc" );
+ nStartChangeAction = nEndChangeAction = 0;
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+OUString ScUndoConversion::GetComment() const
+{
+ OUString aText;
+ switch( maConvParam.GetType() )
+ {
+ case SC_CONVERSION_SPELLCHECK: aText = ScResId( STR_UNDO_SPELLING ); break;
+ case SC_CONVERSION_HANGULHANJA: aText = ScResId( STR_UNDO_HANGULHANJA ); break;
+ case SC_CONVERSION_CHINESE_TRANSL: aText = ScResId( STR_UNDO_CHINESE_TRANSLATION ); break;
+ default: OSL_FAIL( "ScUndoConversion::GetComment - unknown conversion type" );
+ }
+ return aText;
+}
+
+void ScUndoConversion::DoChange( ScDocument* pRefDoc, const ScAddress& rCursorPos )
+{
+ if (pRefDoc)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ShowTable( rCursorPos.Tab() );
+
+ SetViewMarkData( aMarkData );
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ // Undo/Redo-doc has only selected tables
+
+ bool bMulti = aMarkData.IsMultiMarked();
+ pRefDoc->CopyToDocument( 0, 0, 0,
+ rDoc.MaxCol(), rDoc.MaxRow(), nTabCount-1,
+ InsertDeleteFlags::CONTENTS, bMulti, rDoc, &aMarkData );
+
+ // Reset the spell checking results to re-check on paint, otherwise
+ // we show the previous spelling markers (or lack thereof on misspellings).
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ pViewData->GetActiveWin()->ResetAutoSpell();
+ pDocShell->PostPaintGridAll();
+ }
+ else
+ {
+ OSL_FAIL("no Un-/RedoDoc for Un-/RedoSpelling");
+ }
+}
+
+void ScUndoConversion::Undo()
+{
+ BeginUndo();
+ DoChange( pUndoDoc.get(), aCursorPos );
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+ EndUndo();
+}
+
+void ScUndoConversion::Redo()
+{
+ BeginRedo();
+ DoChange( pRedoDoc.get(), aNewCursorPos );
+ SetChangeTrack();
+ EndRedo();
+}
+
+void ScUndoConversion::Repeat( SfxRepeatTarget& rTarget )
+{
+ if( auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget) )
+ pViewTarget->GetViewShell()->DoSheetConversion( maConvParam );
+}
+
+bool ScUndoConversion::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRefConversion::ScUndoRefConversion( ScDocShell* pNewDocShell,
+ const ScRange& aMarkRange, const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc, bool bNewMulti) :
+ScSimpleUndo( pNewDocShell ),
+aMarkData ( rMark ),
+pUndoDoc ( std::move(pNewUndoDoc) ),
+pRedoDoc ( std::move(pNewRedoDoc) ),
+aRange ( aMarkRange ),
+bMulti ( bNewMulti )
+{
+ assert(pUndoDoc && pRedoDoc);
+ SetChangeTrack();
+}
+
+ScUndoRefConversion::~ScUndoRefConversion()
+{
+ pUndoDoc.reset();
+ pRedoDoc.reset();
+}
+
+OUString ScUndoRefConversion::GetComment() const
+{
+ return ScResId( STR_UNDO_ENTERDATA ); // "Input"
+}
+
+void ScUndoRefConversion::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->AppendContentsIfInRefDoc( *pUndoDoc,
+ nStartChangeAction, nEndChangeAction );
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoRefConversion::DoChange( ScDocument* pRefDoc)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ShowTable(aRange);
+
+ SetViewMarkData( aMarkData );
+
+ ScRange aCopyRange = aRange;
+ SCTAB nTabCount = rDoc.GetTableCount();
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ pRefDoc->CopyToDocument( aCopyRange, InsertDeleteFlags::ALL, bMulti, rDoc, &aMarkData );
+ pDocShell->PostPaint( aRange, PaintPartFlags::Grid);
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoRefConversion::Undo()
+{
+ BeginUndo();
+ if (pUndoDoc)
+ DoChange(pUndoDoc.get());
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+ EndUndo();
+}
+
+void ScUndoRefConversion::Redo()
+{
+ BeginRedo();
+ if (pRedoDoc)
+ DoChange(pRedoDoc.get());
+ SetChangeTrack();
+ EndRedo();
+}
+
+void ScUndoRefConversion::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->DoRefConversion();
+}
+
+bool ScUndoRefConversion::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRefreshLink::ScUndoRefreshLink(ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pNewUndoDoc)
+ : ScSimpleUndo(pNewDocShell)
+ , xUndoDoc(std::move(pNewUndoDoc))
+{
+}
+
+OUString ScUndoRefreshLink::GetComment() const
+{
+ return ScResId( STR_UNDO_UPDATELINK );
+}
+
+void ScUndoRefreshLink::Undo()
+{
+ BeginUndo();
+
+ bool bMakeRedo = !xRedoDoc;
+ if (bMakeRedo)
+ xRedoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+
+ bool bFirst = true;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nCount; nTab++)
+ if (xUndoDoc->HasTable(nTab))
+ {
+ ScRange aRange(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab);
+ if (bMakeRedo)
+ {
+ if (bFirst)
+ xRedoDoc->InitUndo(rDoc, nTab, nTab, true, true);
+ else
+ xRedoDoc->AddUndoTab(nTab, nTab, true, true);
+ bFirst = false;
+ rDoc.CopyToDocument(aRange, InsertDeleteFlags::ALL, false, *xRedoDoc);
+ xRedoDoc->SetLink(nTab,
+ rDoc.GetLinkMode(nTab),
+ rDoc.GetLinkDoc(nTab),
+ rDoc.GetLinkFlt(nTab),
+ rDoc.GetLinkOpt(nTab),
+ rDoc.GetLinkTab(nTab),
+ rDoc.GetLinkRefreshDelay(nTab));
+ xRedoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) );
+ }
+
+ rDoc.DeleteAreaTab( aRange,InsertDeleteFlags::ALL );
+ xUndoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL, false, rDoc);
+ rDoc.SetLink(nTab, xUndoDoc->GetLinkMode(nTab), xUndoDoc->GetLinkDoc(nTab),
+ xUndoDoc->GetLinkFlt(nTab), xUndoDoc->GetLinkOpt(nTab),
+ xUndoDoc->GetLinkTab(nTab),
+ xUndoDoc->GetLinkRefreshDelay(nTab) );
+ rDoc.SetTabBgColor(nTab, xUndoDoc->GetTabBgColor(nTab));
+ }
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostPaintExtras();
+
+ EndUndo();
+}
+
+void ScUndoRefreshLink::Redo()
+{
+ OSL_ENSURE(xRedoDoc, "No RedoDoc for ScUndoRefreshLink::Redo");
+
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nCount; nTab++)
+ if (xRedoDoc->HasTable(nTab))
+ {
+ ScRange aRange(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab);
+
+ rDoc.DeleteAreaTab( aRange, InsertDeleteFlags::ALL );
+ xRedoDoc->CopyToDocument(aRange, InsertDeleteFlags::ALL, false, rDoc);
+ rDoc.SetLink(nTab,
+ xRedoDoc->GetLinkMode(nTab),
+ xRedoDoc->GetLinkDoc(nTab),
+ xRedoDoc->GetLinkFlt(nTab),
+ xRedoDoc->GetLinkOpt(nTab),
+ xRedoDoc->GetLinkTab(nTab),
+ xRedoDoc->GetLinkRefreshDelay(nTab) );
+ rDoc.SetTabBgColor(nTab, xRedoDoc->GetTabBgColor(nTab));
+ }
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostPaintExtras();
+
+ EndUndo();
+}
+
+void ScUndoRefreshLink::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoRefreshLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+static ScAreaLink* lcl_FindAreaLink( const sfx2::LinkManager* pLinkManager, std::u16string_view rDoc,
+ std::u16string_view rFlt, std::u16string_view rOpt,
+ std::u16string_view rSrc, const ScRange& rDest )
+{
+ const ::sfx2::SvBaseLinks& rLinks = pLinkManager->GetLinks();
+ sal_uInt16 nCount = pLinkManager->GetLinks().size();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = rLinks[i].get();
+ if (auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase))
+ if ( pAreaLink->IsEqual( rDoc, rFlt, rOpt, rSrc, rDest ) )
+ return pAreaLink;
+ }
+
+ OSL_FAIL("ScAreaLink not found");
+ return nullptr;
+}
+
+ScUndoInsertAreaLink::ScUndoInsertAreaLink( ScDocShell* pShell,
+ const OUString& rDoc,
+ const OUString& rFlt, const OUString& rOpt,
+ const OUString& rArea, const ScRange& rDestRange,
+ sal_uLong nRefresh )
+ : ScSimpleUndo ( pShell ),
+ aDocName ( rDoc ),
+ aFltName ( rFlt ),
+ aOptions ( rOpt ),
+ aAreaName ( rArea ),
+ aRange ( rDestRange ),
+ nRefreshDelay ( nRefresh )
+{
+}
+
+ScUndoInsertAreaLink::~ScUndoInsertAreaLink()
+{
+}
+
+OUString ScUndoInsertAreaLink::GetComment() const
+{
+ return ScResId( STR_UNDO_INSERTAREALINK );
+}
+
+void ScUndoInsertAreaLink::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+
+ ScAreaLink* pLink = lcl_FindAreaLink( pLinkManager, aDocName, aFltName, aOptions,
+ aAreaName, aRange );
+ if (pLink)
+ pLinkManager->Remove( pLink );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); // Navigator
+}
+
+void ScUndoInsertAreaLink::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+
+ ScAreaLink* pLink = new ScAreaLink( pDocShell, aDocName, aFltName, aOptions,
+ aAreaName, aRange.aStart, nRefreshDelay );
+ pLink->SetInCreate( true );
+ pLink->SetDestArea( aRange );
+ pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aDocName, &aFltName, &aAreaName );
+ pLink->Update();
+ pLink->SetInCreate( false );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); // Navigator
+}
+
+void ScUndoInsertAreaLink::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoInsertAreaLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoRemoveAreaLink::ScUndoRemoveAreaLink( ScDocShell* pShell,
+ const OUString& rDoc, const OUString& rFlt, const OUString& rOpt,
+ const OUString& rArea, const ScRange& rDestRange,
+ sal_uLong nRefresh )
+ : ScSimpleUndo ( pShell ),
+ aDocName ( rDoc ),
+ aFltName ( rFlt ),
+ aOptions ( rOpt ),
+ aAreaName ( rArea ),
+ aRange ( rDestRange ),
+ nRefreshDelay ( nRefresh )
+{
+}
+
+ScUndoRemoveAreaLink::~ScUndoRemoveAreaLink()
+{
+}
+
+OUString ScUndoRemoveAreaLink::GetComment() const
+{
+ return ScResId( STR_UNDO_REMOVELINK ); //! own text ??
+}
+
+void ScUndoRemoveAreaLink::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+
+ ScAreaLink* pLink = new ScAreaLink( pDocShell, aDocName, aFltName, aOptions,
+ aAreaName, aRange.aStart, nRefreshDelay );
+ pLink->SetInCreate( true );
+ pLink->SetDestArea( aRange );
+ pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aDocName, &aFltName, &aAreaName );
+ pLink->Update();
+ pLink->SetInCreate( false );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); // Navigator
+}
+
+void ScUndoRemoveAreaLink::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+
+ ScAreaLink* pLink = lcl_FindAreaLink( pLinkManager, aDocName, aFltName, aOptions,
+ aAreaName, aRange );
+ if (pLink)
+ pLinkManager->Remove( pLink );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); // Navigator
+}
+
+void ScUndoRemoveAreaLink::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoRemoveAreaLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoUpdateAreaLink::ScUndoUpdateAreaLink( ScDocShell* pShell,
+ const OUString& rOldD, const OUString& rOldF, const OUString& rOldO,
+ const OUString& rOldA, const ScRange& rOldR, sal_uLong nOldRD,
+ const OUString& rNewD, const OUString& rNewF, const OUString& rNewO,
+ const OUString& rNewA, const ScRange& rNewR, sal_uLong nNewRD,
+ ScDocumentUniquePtr pUndo, ScDocumentUniquePtr pRedo, bool bDoInsert )
+ : ScSimpleUndo( pShell ),
+ aOldDoc ( rOldD ),
+ aOldFlt ( rOldF ),
+ aOldOpt ( rOldO ),
+ aOldArea ( rOldA ),
+ aOldRange ( rOldR ),
+ aNewDoc ( rNewD ),
+ aNewFlt ( rNewF ),
+ aNewOpt ( rNewO ),
+ aNewArea ( rNewA ),
+ aNewRange ( rNewR ),
+ xUndoDoc ( std::move(pUndo) ),
+ xRedoDoc ( std::move(pRedo) ),
+ nOldRefresh ( nOldRD ),
+ nNewRefresh ( nNewRD ),
+ bWithInsert ( bDoInsert )
+{
+ OSL_ENSURE( aOldRange.aStart == aNewRange.aStart, "AreaLink moved ?" );
+}
+
+OUString ScUndoUpdateAreaLink::GetComment() const
+{
+ return ScResId( STR_UNDO_UPDATELINK ); //! own text ??
+}
+
+void ScUndoUpdateAreaLink::DoChange( const bool bUndo ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SCCOL nEndX = std::max( aOldRange.aEnd.Col(), aNewRange.aEnd.Col() );
+ SCROW nEndY = std::max( aOldRange.aEnd.Row(), aNewRange.aEnd.Row() );
+ SCTAB nEndZ = std::max( aOldRange.aEnd.Tab(), aNewRange.aEnd.Tab() ); //?
+
+ if ( bUndo )
+ {
+ if ( bWithInsert )
+ {
+ rDoc.FitBlock( aNewRange, aOldRange );
+ rDoc.DeleteAreaTab( aOldRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ xUndoDoc->UndoToDocument(aOldRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ }
+ else
+ {
+ ScRange aCopyRange( aOldRange.aStart, ScAddress(nEndX,nEndY,nEndZ) );
+ rDoc.DeleteAreaTab( aCopyRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ xUndoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ }
+ }
+ else
+ {
+ if ( bWithInsert )
+ {
+ rDoc.FitBlock( aOldRange, aNewRange );
+ rDoc.DeleteAreaTab( aNewRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ xRedoDoc->CopyToDocument(aNewRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ }
+ else
+ {
+ ScRange aCopyRange( aOldRange.aStart, ScAddress(nEndX,nEndY,nEndZ) );
+ rDoc.DeleteAreaTab( aCopyRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ xRedoDoc->CopyToDocument(aCopyRange, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ }
+ }
+
+ ScRange aWorkRange( aNewRange.aStart, ScAddress( nEndX, nEndY, nEndZ ) );
+ rDoc.ExtendMerge( aWorkRange, true );
+
+ // Paint
+
+ if ( aNewRange.aEnd.Col() != aOldRange.aEnd.Col() )
+ aWorkRange.aEnd.SetCol(rDoc.MaxCol());
+ if ( aNewRange.aEnd.Row() != aOldRange.aEnd.Row() )
+ aWorkRange.aEnd.SetRow(rDoc.MaxRow());
+
+ if ( !pDocShell->AdjustRowHeight( aWorkRange.aStart.Row(), aWorkRange.aEnd.Row(), aWorkRange.aStart.Tab() ) )
+ pDocShell->PostPaint( aWorkRange, PaintPartFlags::Grid );
+
+ pDocShell->PostDataChanged();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+void ScUndoUpdateAreaLink::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+ ScAreaLink* pLink = lcl_FindAreaLink( pLinkManager, aNewDoc, aNewFlt, aNewOpt,
+ aNewArea, aNewRange );
+ if (pLink)
+ {
+ pLink->SetSource( aOldDoc, aOldFlt, aOldOpt, aOldArea ); // old data in Link
+ pLink->SetDestArea( aOldRange );
+ pLink->SetRefreshDelay( nOldRefresh );
+ }
+
+ DoChange(true);
+}
+
+void ScUndoUpdateAreaLink::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+ ScAreaLink* pLink = lcl_FindAreaLink( pLinkManager, aOldDoc, aOldFlt, aOldOpt,
+ aOldArea, aOldRange );
+ if (pLink)
+ {
+ pLink->SetSource( aNewDoc, aNewFlt, aNewOpt, aNewArea ); // new values in link
+ pLink->SetDestArea( aNewRange );
+ pLink->SetRefreshDelay( nNewRefresh );
+ }
+
+ DoChange(false);
+}
+
+void ScUndoUpdateAreaLink::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoUpdateAreaLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undocell.cxx b/sc/source/ui/undo/undocell.cxx
new file mode 100644
index 000000000..8323cd824
--- /dev/null
+++ b/sc/source/ui/undo/undocell.cxx
@@ -0,0 +1,1048 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <undocell.hxx>
+
+#include <scitems.hxx>
+#include <editeng/editobj.hxx>
+#include <sfx2/app.hxx>
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+
+#include <document.hxx>
+#include <docpool.hxx>
+#include <patattr.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <formulacell.hxx>
+#include <target.hxx>
+#include <undoolk.hxx>
+#include <detdata.hxx>
+#include <stlpool.hxx>
+#include <printfun.hxx>
+#include <rangenam.hxx>
+#include <chgtrack.hxx>
+#include <stringutil.hxx>
+
+namespace HelperNotifyChanges
+{
+ static void NotifyIfChangesListeners(const ScDocShell& rDocShell, const ScAddress &rPos,
+ const ScUndoEnterData::ValuesType &rOldValues)
+ {
+ if (ScModelObj* pModelObj = getMustPropagateChangesModel(rDocShell))
+ {
+ ScRangeList aChangeRanges;
+
+ for (const auto & rOldValue : rOldValues)
+ {
+ aChangeRanges.push_back( ScRange(rPos.Col(), rPos.Row(), rOldValue.mnTab));
+ }
+
+ Notify(*pModelObj, aChangeRanges, "cell-change");
+ }
+ }
+}
+
+
+ScUndoCursorAttr::ScUndoCursorAttr( ScDocShell* pNewDocShell,
+ SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
+ const ScPatternAttr* pOldPat, const ScPatternAttr* pNewPat,
+ const ScPatternAttr* pApplyPat ) :
+ ScSimpleUndo( pNewDocShell ),
+ nCol( nNewCol ),
+ nRow( nNewRow ),
+ nTab( nNewTab ),
+ pOldEditData( static_cast<EditTextObject*>(nullptr) ),
+ pNewEditData( static_cast<EditTextObject*>(nullptr) )
+{
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ pNewPattern = const_cast<ScPatternAttr*>( &pPool->Put( *pNewPat ) );
+ pOldPattern = const_cast<ScPatternAttr*>( &pPool->Put( *pOldPat ) );
+ pApplyPattern = const_cast<ScPatternAttr*>( &pPool->Put( *pApplyPat ) );
+}
+
+ScUndoCursorAttr::~ScUndoCursorAttr()
+{
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ pPool->Remove(*pNewPattern);
+ pPool->Remove(*pOldPattern);
+ pPool->Remove(*pApplyPattern);
+}
+
+OUString ScUndoCursorAttr::GetComment() const
+{
+ //! own text for automatic attribution
+ return ScResId( STR_UNDO_CURSORATTR ); // "Attribute"
+}
+
+void ScUndoCursorAttr::SetEditData( std::unique_ptr<EditTextObject> pOld, std::unique_ptr<EditTextObject> pNew )
+{
+ pOldEditData = std::move(pOld);
+ pNewEditData = std::move(pNew);
+}
+
+void ScUndoCursorAttr::DoChange( const ScPatternAttr* pWhichPattern, const std::unique_ptr<EditTextObject>& pEditData ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScAddress aPos(nCol, nRow, nTab);
+ rDoc.SetPattern( nCol, nRow, nTab, *pWhichPattern );
+
+ if (rDoc.GetCellType(aPos) == CELLTYPE_EDIT && pEditData)
+ rDoc.SetEditText(aPos, *pEditData, nullptr);
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->SetTabNo( nTab );
+ pViewShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_JUMP, false, false );
+ pViewShell->AdjustBlockHeight();
+ }
+
+ const SfxItemSet& rApplySet = pApplyPattern->GetItemSet();
+ bool bPaintExt = ( rApplySet.GetItemState( ATTR_SHADOW ) != SfxItemState::DEFAULT ||
+ rApplySet.GetItemState( ATTR_CONDITIONAL ) != SfxItemState::DEFAULT );
+ bool bPaintRows = ( rApplySet.GetItemState( ATTR_HOR_JUSTIFY ) != SfxItemState::DEFAULT );
+
+ sal_uInt16 nFlags = SC_PF_TESTMERGE;
+ if (bPaintExt)
+ nFlags |= SC_PF_LINES;
+ if (bPaintRows)
+ nFlags |= SC_PF_WHOLEROWS;
+ pDocShell->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid, nFlags );
+}
+
+void ScUndoCursorAttr::Undo()
+{
+ BeginUndo();
+ DoChange(pOldPattern, pOldEditData);
+ EndUndo();
+}
+
+void ScUndoCursorAttr::Redo()
+{
+ BeginRedo();
+ DoChange(pNewPattern, pNewEditData);
+ EndRedo();
+}
+
+void ScUndoCursorAttr::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->ApplySelectionPattern( *pApplyPattern );
+}
+
+bool ScUndoCursorAttr::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoEnterData::Value::Value() : mnTab(-1), mbHasFormat(false), mnFormat(0) {}
+
+ScUndoEnterData::ScUndoEnterData(
+ ScDocShell* pNewDocShell, const ScAddress& rPos, ValuesType& rOldValues,
+ const OUString& rNewStr, std::unique_ptr<EditTextObject> pObj ) :
+ ScSimpleUndo( pNewDocShell ),
+ maNewString(rNewStr),
+ mpNewEditData(std::move(pObj)),
+ mnEndChangeAction(0),
+ maPos(rPos)
+{
+ maOldValues.swap(rOldValues);
+
+ SetChangeTrack();
+}
+
+OUString ScUndoEnterData::GetComment() const
+{
+ return ScResId( STR_UNDO_ENTERDATA ); // "Input"
+}
+
+void ScUndoEnterData::DoChange() const
+{
+ // only when needed (old or new Edit cell, or Attribute)?
+ bool bHeightChanged = false;
+ for (const auto & i : maOldValues)
+ {
+ if (pDocShell->AdjustRowHeight(maPos.Row(), maPos.Row(), i.mnTab))
+ bHeightChanged = true;
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ if (comphelper::LibreOfficeKit::isActive() && bHeightChanged)
+ {
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, maPos.Tab());
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell, false /* bColumns */, true /* bRows */, true /* bSizes*/,
+ false /* bHidden */, false /* bFiltered */, false /* bGroups */, maPos.Tab());
+ }
+ pViewShell->SetTabNo(maPos.Tab());
+ pViewShell->MoveCursorAbs(maPos.Col(), maPos.Row(), SC_FOLLOW_JUMP, false, false);
+ }
+
+ pDocShell->PostDataChanged();
+}
+
+void ScUndoEnterData::SetChangeTrack()
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ mnEndChangeAction = pChangeTrack->GetActionMax() + 1;
+ ScAddress aPos(maPos);
+ for (const Value & rOldValue : maOldValues)
+ {
+ aPos.SetTab(rOldValue.mnTab);
+ sal_uLong nFormat = 0;
+ if (rOldValue.mbHasFormat)
+ nFormat = rOldValue.mnFormat;
+ pChangeTrack->AppendContent(aPos, rOldValue.maCell, nFormat);
+ }
+ if ( mnEndChangeAction > pChangeTrack->GetActionMax() )
+ mnEndChangeAction = 0; // nothing is appended
+ }
+ else
+ mnEndChangeAction = 0;
+}
+
+void ScUndoEnterData::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (const Value & rVal : maOldValues)
+ {
+ ScCellValue aNewCell;
+ aNewCell.assign(rVal.maCell, rDoc, ScCloneFlags::StartListening);
+ ScAddress aPos = maPos;
+ aPos.SetTab(rVal.mnTab);
+ aNewCell.release(rDoc, aPos);
+
+ if (rVal.mbHasFormat)
+ rDoc.ApplyAttr(maPos.Col(), maPos.Row(), rVal.mnTab,
+ SfxUInt32Item(ATTR_VALUE_FORMAT, rVal.mnFormat));
+ else
+ {
+ auto pPattern = std::make_unique<ScPatternAttr>(*rDoc.GetPattern(maPos.Col(), maPos.Row(), rVal.mnTab));
+ pPattern->GetItemSet().ClearItem( ATTR_VALUE_FORMAT );
+ rDoc.SetPattern(maPos.Col(), maPos.Row(), rVal.mnTab, std::move(pPattern));
+ }
+ pDocShell->PostPaintCell(maPos.Col(), maPos.Row(), rVal.mnTab);
+ }
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ size_t nCount = maOldValues.size();
+ if ( pChangeTrack && mnEndChangeAction >= sal::static_int_cast<sal_uLong>(nCount) )
+ pChangeTrack->Undo( mnEndChangeAction - nCount + 1, mnEndChangeAction );
+
+ DoChange();
+ EndUndo();
+
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocShell, maPos, maOldValues);
+}
+
+void ScUndoEnterData::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (const Value & rOldValue : maOldValues)
+ {
+ SCTAB nTab = rOldValue.mnTab;
+ if (mpNewEditData)
+ {
+ ScAddress aPos = maPos;
+ aPos.SetTab(nTab);
+ // edit text will be cloned.
+ rDoc.SetEditText(aPos, *mpNewEditData, nullptr);
+ }
+ else
+ rDoc.SetString(maPos.Col(), maPos.Row(), nTab, maNewString);
+
+ pDocShell->PostPaintCell(maPos.Col(), maPos.Row(), nTab);
+ }
+
+ SetChangeTrack();
+
+ DoChange();
+ EndRedo();
+
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocShell, maPos, maOldValues);
+}
+
+void ScUndoEnterData::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ OUString aTemp = maNewString;
+ pViewTarget->GetViewShell()->EnterDataAtCursor( aTemp );
+ }
+}
+
+bool ScUndoEnterData::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoEnterValue::ScUndoEnterValue(
+ ScDocShell* pNewDocShell, const ScAddress& rNewPos,
+ const ScCellValue& rUndoCell, double nVal ) :
+ ScSimpleUndo( pNewDocShell ),
+ aPos ( rNewPos ),
+ maOldCell(rUndoCell),
+ nValue ( nVal )
+{
+ SetChangeTrack();
+}
+
+ScUndoEnterValue::~ScUndoEnterValue()
+{
+}
+
+OUString ScUndoEnterValue::GetComment() const
+{
+ return ScResId( STR_UNDO_ENTERDATA ); // "Input"
+}
+
+void ScUndoEnterValue::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ nEndChangeAction = pChangeTrack->GetActionMax() + 1;
+ pChangeTrack->AppendContent(aPos, maOldCell);
+ if ( nEndChangeAction > pChangeTrack->GetActionMax() )
+ nEndChangeAction = 0; // nothing is appended
+ }
+ else
+ nEndChangeAction = 0;
+}
+
+void ScUndoEnterValue::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScCellValue aNewCell;
+ aNewCell.assign(maOldCell, rDoc, ScCloneFlags::StartListening);
+ aNewCell.release(rDoc, aPos);
+
+ pDocShell->PostPaintCell( aPos );
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
+
+ EndUndo();
+}
+
+void ScUndoEnterValue::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.SetValue( aPos.Col(), aPos.Row(), aPos.Tab(), nValue );
+ pDocShell->PostPaintCell( aPos );
+
+ SetChangeTrack();
+
+ EndRedo();
+}
+
+void ScUndoEnterValue::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoEnterValue::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoSetCell::ScUndoSetCell( ScDocShell* pDocSh, const ScAddress& rPos, const ScCellValue& rOldVal, const ScCellValue& rNewVal ) :
+ ScSimpleUndo(pDocSh), maPos(rPos), maOldValue(rOldVal), maNewValue(rNewVal), mnEndChangeAction(0)
+{
+ SetChangeTrack();
+}
+
+ScUndoSetCell::~ScUndoSetCell() {}
+
+void ScUndoSetCell::Undo()
+{
+ BeginUndo();
+ SetValue(maOldValue);
+ MoveCursorToCell();
+ pDocShell->PostPaintCell(maPos);
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if (pChangeTrack)
+ pChangeTrack->Undo(mnEndChangeAction, mnEndChangeAction);
+
+ EndUndo();
+}
+
+void ScUndoSetCell::Redo()
+{
+ BeginRedo();
+ SetValue(maNewValue);
+ MoveCursorToCell();
+ pDocShell->PostPaintCell(maPos);
+ SetChangeTrack();
+ EndRedo();
+}
+
+void ScUndoSetCell::Repeat( SfxRepeatTarget& /*rTarget*/ )
+{
+ // Makes no sense.
+}
+
+bool ScUndoSetCell::CanRepeat( SfxRepeatTarget& /*rTarget*/ ) const
+{
+ return false;
+}
+
+OUString ScUndoSetCell::GetComment() const
+{
+ return ScResId(STR_UNDO_ENTERDATA); // "Input"
+}
+
+void ScUndoSetCell::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if (pChangeTrack)
+ {
+ mnEndChangeAction = pChangeTrack->GetActionMax() + 1;
+
+ pChangeTrack->AppendContent(maPos, maOldValue);
+
+ if (mnEndChangeAction > pChangeTrack->GetActionMax())
+ mnEndChangeAction = 0; // Nothing is appended
+ }
+ else
+ mnEndChangeAction = 0;
+}
+
+void ScUndoSetCell::SetValue( const ScCellValue& rVal )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ switch (rVal.meType)
+ {
+ case CELLTYPE_NONE:
+ // empty cell
+ rDoc.SetEmptyCell(maPos);
+ break;
+ case CELLTYPE_VALUE:
+ rDoc.SetValue(maPos, rVal.mfValue);
+ break;
+ case CELLTYPE_STRING:
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ // Undo only cell content, without setting any number format.
+ aParam.meSetTextNumFormat = ScSetStringParam::Keep;
+ rDoc.SetString(maPos, rVal.mpString->getString(), &aParam);
+ }
+ break;
+ case CELLTYPE_EDIT:
+ rDoc.SetEditText(maPos, rVal.mpEditText->Clone());
+ break;
+ case CELLTYPE_FORMULA:
+ rDoc.SetFormulaCell(maPos, rVal.mpFormula->Clone());
+ break;
+ default:
+ ;
+ }
+}
+
+void ScUndoSetCell::MoveCursorToCell()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if ( pViewShell )
+ {
+ pViewShell->SetTabNo( maPos.Tab() );
+ pViewShell->MoveCursorAbs( maPos.Col(), maPos.Row(), SC_FOLLOW_JUMP, false, false );
+ }
+}
+
+ScUndoPageBreak::ScUndoPageBreak( ScDocShell* pNewDocShell,
+ SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
+ bool bNewColumn, bool bNewInsert ) :
+ ScSimpleUndo( pNewDocShell ),
+ nCol( nNewCol ),
+ nRow( nNewRow ),
+ nTab( nNewTab ),
+ bColumn( bNewColumn ),
+ bInsert( bNewInsert )
+{
+}
+
+ScUndoPageBreak::~ScUndoPageBreak()
+{
+}
+
+OUString ScUndoPageBreak::GetComment() const
+{
+ //"Column break" | "Row break" "insert" | "delete"
+ return bColumn ?
+ ( bInsert ?
+ ScResId( STR_UNDO_INSCOLBREAK ) :
+ ScResId( STR_UNDO_DELCOLBREAK )
+ ) :
+ ( bInsert ?
+ ScResId( STR_UNDO_INSROWBREAK ) :
+ ScResId( STR_UNDO_DELROWBREAK )
+ );
+}
+
+void ScUndoPageBreak::DoChange( bool bInsertP ) const
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ if (pViewShell)
+ {
+ pViewShell->SetTabNo( nTab );
+ pViewShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_JUMP, false, false );
+
+ if (bInsertP)
+ pViewShell->InsertPageBreak(bColumn, false);
+ else
+ pViewShell->DeletePageBreak(bColumn, false);
+
+ pDocShell->GetDocument().InvalidatePageBreaks(nTab);
+ }
+}
+
+void ScUndoPageBreak::Undo()
+{
+ BeginUndo();
+ DoChange(!bInsert);
+ EndUndo();
+}
+
+void ScUndoPageBreak::Redo()
+{
+ BeginRedo();
+ DoChange(bInsert);
+ EndRedo();
+}
+
+void ScUndoPageBreak::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+
+ if (bInsert)
+ rViewShell.InsertPageBreak(bColumn);
+ else
+ rViewShell.DeletePageBreak(bColumn);
+ }
+}
+
+bool ScUndoPageBreak::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoPrintZoom::ScUndoPrintZoom( ScDocShell* pNewDocShell,
+ SCTAB nT, sal_uInt16 nOS, sal_uInt16 nOP, sal_uInt16 nNS, sal_uInt16 nNP ) :
+ ScSimpleUndo( pNewDocShell ),
+ nTab( nT ),
+ nOldScale( nOS ),
+ nOldPages( nOP ),
+ nNewScale( nNS ),
+ nNewPages( nNP )
+{
+}
+
+ScUndoPrintZoom::~ScUndoPrintZoom()
+{
+}
+
+OUString ScUndoPrintZoom::GetComment() const
+{
+ return ScResId( STR_UNDO_PRINTSCALE );
+}
+
+void ScUndoPrintZoom::DoChange( bool bUndo )
+{
+ sal_uInt16 nScale = bUndo ? nOldScale : nNewScale;
+ sal_uInt16 nPages = bUndo ? nOldPages : nNewPages;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OUString aStyleName = rDoc.GetPageStyle( nTab );
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName, SfxStyleFamily::Page );
+ OSL_ENSURE( pStyleSheet, "PageStyle not found" );
+ if ( pStyleSheet )
+ {
+ SfxItemSet& rSet = pStyleSheet->GetItemSet();
+ rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALE, nScale ) );
+ rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALETOPAGES, nPages ) );
+
+ ScPrintFunc aPrintFunc( pDocShell, pDocShell->GetPrinter(), nTab );
+ aPrintFunc.UpdatePages();
+ }
+}
+
+void ScUndoPrintZoom::Undo()
+{
+ BeginUndo();
+ DoChange(true);
+ EndUndo();
+}
+
+void ScUndoPrintZoom::Redo()
+{
+ BeginRedo();
+ DoChange(false);
+ EndRedo();
+}
+
+void ScUndoPrintZoom::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+ ScViewData& rViewData = rViewShell.GetViewData();
+ rViewData.GetDocShell()->SetPrintZoom( rViewData.GetTabNo(), nNewScale, nNewPages );
+ }
+}
+
+bool ScUndoPrintZoom::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoThesaurus::ScUndoThesaurus(
+ ScDocShell* pNewDocShell, SCCOL nNewCol, SCROW nNewRow, SCTAB nNewTab,
+ const ScCellValue& rOldText, const ScCellValue& rNewText ) :
+ ScSimpleUndo( pNewDocShell ),
+ nCol( nNewCol ),
+ nRow( nNewRow ),
+ nTab( nNewTab ),
+ maOldText(rOldText),
+ maNewText(rNewText)
+{
+ SetChangeTrack(maOldText);
+}
+
+ScUndoThesaurus::~ScUndoThesaurus() {}
+
+OUString ScUndoThesaurus::GetComment() const
+{
+ return ScResId( STR_UNDO_THESAURUS ); // "Thesaurus"
+}
+
+void ScUndoThesaurus::SetChangeTrack( const ScCellValue& rOldCell )
+{
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ nEndChangeAction = pChangeTrack->GetActionMax() + 1;
+ pChangeTrack->AppendContent(ScAddress(nCol, nRow, nTab), rOldCell);
+ if ( nEndChangeAction > pChangeTrack->GetActionMax() )
+ nEndChangeAction = 0; // nothing is appended
+ }
+ else
+ nEndChangeAction = 0;
+}
+
+void ScUndoThesaurus::DoChange( bool bUndo, const ScCellValue& rText )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->SetTabNo( nTab );
+ pViewShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_JUMP, false, false );
+ }
+
+ ScAddress aPos(nCol, nRow, nTab);
+ rText.commit(rDoc, aPos);
+ if (!bUndo)
+ SetChangeTrack(maOldText);
+
+ pDocShell->PostPaintCell( nCol, nRow, nTab );
+}
+
+void ScUndoThesaurus::Undo()
+{
+ BeginUndo();
+ DoChange(true, maOldText);
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
+ EndUndo();
+}
+
+void ScUndoThesaurus::Redo()
+{
+ BeginRedo();
+ DoChange(false, maNewText);
+ EndRedo();
+}
+
+void ScUndoThesaurus::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->DoThesaurus();
+}
+
+bool ScUndoThesaurus::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+
+ScUndoReplaceNote::ScUndoReplaceNote( ScDocShell& rDocShell, const ScAddress& rPos,
+ const ScNoteData& rNoteData, bool bInsert, std::unique_ptr<SdrUndoAction> pDrawUndo ) :
+ ScSimpleUndo( &rDocShell ),
+ maPos( rPos ),
+ mpDrawUndo( std::move(pDrawUndo) )
+{
+ OSL_ENSURE( rNoteData.mxCaption, "ScUndoReplaceNote::ScUndoReplaceNote - missing note caption" );
+ if (bInsert)
+ {
+ maNewData = rNoteData;
+ maNewData.mxCaption.setNotOwner();
+ }
+ else
+ {
+ maOldData = rNoteData;
+ maOldData.mxCaption.setNotOwner();
+ }
+}
+
+ScUndoReplaceNote::ScUndoReplaceNote( ScDocShell& rDocShell, const ScAddress& rPos,
+ const ScNoteData& rOldData, const ScNoteData& rNewData, std::unique_ptr<SdrUndoAction> pDrawUndo ) :
+ ScSimpleUndo( &rDocShell ),
+ maPos( rPos ),
+ maOldData( rOldData ),
+ maNewData( rNewData ),
+ mpDrawUndo( std::move(pDrawUndo) )
+{
+ OSL_ENSURE( maOldData.mxCaption || maNewData.mxCaption, "ScUndoReplaceNote::ScUndoReplaceNote - missing note captions" );
+ OSL_ENSURE( !maOldData.mxInitData && !maNewData.mxInitData, "ScUndoReplaceNote::ScUndoReplaceNote - unexpected uninitialized note" );
+ maOldData.mxCaption.setNotOwner();
+ maNewData.mxCaption.setNotOwner();
+}
+
+ScUndoReplaceNote::~ScUndoReplaceNote()
+{
+ mpDrawUndo.reset();
+}
+
+void ScUndoReplaceNote::Undo()
+{
+ BeginUndo();
+ DoSdrUndoAction( mpDrawUndo.get(), &pDocShell->GetDocument() );
+ /* Undo insert -> remove new note.
+ Undo remove -> insert old note.
+ Undo replace -> remove new note, insert old note. */
+ DoRemoveNote( maNewData );
+ DoInsertNote( maOldData );
+ pDocShell->PostPaintCell( maPos );
+ EndUndo();
+}
+
+void ScUndoReplaceNote::Redo()
+{
+ BeginRedo();
+ RedoSdrUndoAction( mpDrawUndo.get() );
+ /* Redo insert -> insert new note.
+ Redo remove -> remove old note.
+ Redo replace -> remove old note, insert new note. */
+ DoRemoveNote( maOldData );
+ DoInsertNote( maNewData );
+ pDocShell->PostPaintCell( maPos );
+ EndRedo();
+}
+
+void ScUndoReplaceNote::Repeat( SfxRepeatTarget& /*rTarget*/ )
+{
+}
+
+bool ScUndoReplaceNote::CanRepeat( SfxRepeatTarget& /*rTarget*/ ) const
+{
+ return false;
+}
+
+OUString ScUndoReplaceNote::GetComment() const
+{
+ return ScResId( maNewData.mxCaption ?
+ (maOldData.mxCaption ? STR_UNDO_EDITNOTE : STR_UNDO_INSERTNOTE) : STR_UNDO_DELETENOTE );
+}
+
+void ScUndoReplaceNote::DoInsertNote( const ScNoteData& rNoteData )
+{
+ if( rNoteData.mxCaption )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OSL_ENSURE( !rDoc.GetNote(maPos), "ScUndoReplaceNote::DoInsertNote - unexpected cell note" );
+ ScPostIt* pNote = new ScPostIt( rDoc, maPos, rNoteData, false );
+ rDoc.SetNote( maPos, std::unique_ptr<ScPostIt>(pNote) );
+ ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Add, &rDoc, maPos, pNote);
+ }
+}
+
+void ScUndoReplaceNote::DoRemoveNote( const ScNoteData& rNoteData )
+{
+ if( !rNoteData.mxCaption )
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OSL_ENSURE( rDoc.GetNote(maPos), "ScUndoReplaceNote::DoRemoveNote - missing cell note" );
+ if( std::unique_ptr<ScPostIt> pNote = rDoc.ReleaseNote( maPos ) )
+ {
+ /* Forget pointer to caption object to suppress removing the
+ caption object from the drawing layer while deleting pNote
+ (removing the caption is done by a drawing undo action). */
+ pNote->ForgetCaption();
+ ScDocShell::LOKCommentNotify(LOKCommentNotificationType::Remove, &rDoc, maPos, pNote.get());
+ }
+}
+
+ScUndoShowHideNote::ScUndoShowHideNote( ScDocShell& rDocShell, const ScAddress& rPos, bool bShow ) :
+ ScSimpleUndo( &rDocShell ),
+ maPos( rPos ),
+ mbShown( bShow )
+{
+}
+
+ScUndoShowHideNote::~ScUndoShowHideNote()
+{
+}
+
+void ScUndoShowHideNote::Undo()
+{
+ BeginUndo();
+ if( ScPostIt* pNote = pDocShell->GetDocument().GetNote(maPos) )
+ pNote->ShowCaption( maPos, !mbShown );
+ EndUndo();
+}
+
+void ScUndoShowHideNote::Redo()
+{
+ BeginRedo();
+ if( ScPostIt* pNote = pDocShell->GetDocument().GetNote(maPos) )
+ pNote->ShowCaption( maPos, mbShown );
+ EndRedo();
+}
+
+void ScUndoShowHideNote::Repeat( SfxRepeatTarget& /*rTarget*/ )
+{
+}
+
+bool ScUndoShowHideNote::CanRepeat( SfxRepeatTarget& /*rTarget*/ ) const
+{
+ return false;
+}
+
+OUString ScUndoShowHideNote::GetComment() const
+{
+ return ScResId( mbShown ? STR_UNDO_SHOWNOTE : STR_UNDO_HIDENOTE );
+}
+
+ScUndoDetective::ScUndoDetective( ScDocShell* pNewDocShell,
+ std::unique_ptr<SdrUndoAction> pDraw, const ScDetOpData* pOperation,
+ std::unique_ptr<ScDetOpList> pUndoList ) :
+ ScSimpleUndo( pNewDocShell ),
+ pOldList ( std::move(pUndoList) ),
+ nAction ( 0 ),
+ pDrawUndo ( std::move(pDraw) )
+{
+ bIsDelete = ( pOperation == nullptr );
+ if (!bIsDelete)
+ {
+ nAction = static_cast<sal_uInt16>(pOperation->GetOperation());
+ aPos = pOperation->GetPos();
+ }
+}
+
+ScUndoDetective::~ScUndoDetective()
+{
+ pDrawUndo.reset();
+ pOldList.reset();
+}
+
+OUString ScUndoDetective::GetComment() const
+{
+ TranslateId pId = STR_UNDO_DETDELALL;
+ if ( !bIsDelete )
+ switch ( static_cast<ScDetOpType>(nAction) )
+ {
+ case SCDETOP_ADDSUCC: pId = STR_UNDO_DETADDSUCC; break;
+ case SCDETOP_DELSUCC: pId = STR_UNDO_DETDELSUCC; break;
+ case SCDETOP_ADDPRED: pId = STR_UNDO_DETADDPRED; break;
+ case SCDETOP_DELPRED: pId = STR_UNDO_DETDELPRED; break;
+ case SCDETOP_ADDERROR: pId = STR_UNDO_DETADDERROR; break;
+ }
+
+ return ScResId(pId);
+}
+
+void ScUndoDetective::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ DoSdrUndoAction(pDrawUndo.get(), &rDoc);
+
+ if (bIsDelete)
+ {
+ if ( pOldList )
+ rDoc.SetDetOpList( std::unique_ptr<ScDetOpList>(new ScDetOpList(*pOldList)) );
+ }
+ else
+ {
+ // Remove entry from list
+
+ ScDetOpList* pList = rDoc.GetDetOpList();
+ if (pList && pList->Count())
+ {
+ ScDetOpDataVector& rVec = pList->GetDataVector();
+ ScDetOpDataVector::iterator it = rVec.begin() + rVec.size() - 1;
+ if ( it->GetOperation() == static_cast<ScDetOpType>(nAction) && it->GetPos() == aPos )
+ rVec.erase( it);
+ else
+ {
+ OSL_FAIL("Detective entry could not be found in list");
+ }
+ }
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->RecalcPPT(); //! use broadcast instead?
+
+ EndUndo();
+}
+
+void ScUndoDetective::Redo()
+{
+ BeginRedo();
+
+ RedoSdrUndoAction(pDrawUndo.get());
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ if (bIsDelete)
+ rDoc.ClearDetectiveOperations();
+ else
+ rDoc.AddDetectiveOperation( ScDetOpData( aPos, static_cast<ScDetOpType>(nAction) ) );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->RecalcPPT(); //! use broadcast instead?
+
+ EndRedo();
+}
+
+void ScUndoDetective::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoDetective::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoRangeNames::ScUndoRangeNames( ScDocShell* pNewDocShell,
+ std::unique_ptr<ScRangeName> pOld, std::unique_ptr<ScRangeName> pNew, SCTAB nTab ) :
+ ScSimpleUndo( pNewDocShell ),
+ pOldRanges ( std::move(pOld) ),
+ pNewRanges ( std::move(pNew) ),
+ mnTab ( nTab )
+{
+}
+
+ScUndoRangeNames::~ScUndoRangeNames()
+{
+ pOldRanges.reset();
+ pNewRanges.reset();
+}
+
+OUString ScUndoRangeNames::GetComment() const
+{
+ return ScResId( STR_UNDO_RANGENAMES );
+}
+
+void ScUndoRangeNames::DoChange( bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.PreprocessRangeNameUpdate();
+
+ if ( bUndo )
+ {
+ auto p = std::make_unique<ScRangeName>(*pOldRanges);
+ if (mnTab >= 0)
+ rDoc.SetRangeName( mnTab, std::move(p) );
+ else
+ rDoc.SetRangeName( std::move(p) );
+ }
+ else
+ {
+ auto p = std::make_unique<ScRangeName>(*pNewRanges);
+ if (mnTab >= 0)
+ rDoc.SetRangeName( mnTab, std::move(p) );
+ else
+ rDoc.SetRangeName( std::move(p) );
+ }
+
+ rDoc.CompileHybridFormula();
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+}
+
+void ScUndoRangeNames::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoRangeNames::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoRangeNames::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoRangeNames::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undocell2.cxx b/sc/source/ui/undo/undocell2.cxx
new file mode 100644
index 000000000..2222afa42
--- /dev/null
+++ b/sc/source/ui/undo/undocell2.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/.
+ */
+
+#include <undocell.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <cellvalues.hxx>
+#include <formulacell.hxx>
+
+namespace sc {
+
+UndoSetCells::UndoSetCells( ScDocShell* pDocSh, const ScAddress& rTopPos ) :
+ ScSimpleUndo(pDocSh), maTopPos(rTopPos) {}
+
+UndoSetCells::~UndoSetCells() {}
+
+void UndoSetCells::DoChange( const CellValues& rValues )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.CopyCellValuesFrom(maTopPos, rValues);
+
+ ScRange aRange(maTopPos);
+ aRange.aEnd.IncRow(rValues.size());
+ BroadcastChanges(aRange);
+ pDocShell->PostPaintGridAll();
+}
+
+void UndoSetCells::Undo()
+{
+ BeginUndo();
+ DoChange(maOldValues);
+ EndUndo();
+}
+
+void UndoSetCells::Redo()
+{
+ BeginRedo();
+ DoChange(maNewValues);
+ EndRedo();
+}
+
+bool UndoSetCells::CanRepeat( SfxRepeatTarget& ) const
+{
+ return false;
+}
+
+OUString UndoSetCells::GetComment() const
+{
+ // "Input"
+ return ScResId(STR_UNDO_ENTERDATA);
+}
+
+void UndoSetCells::SetNewValues( const std::vector<double>& rVals )
+{
+ maNewValues.assign(rVals);
+}
+
+void UndoSetCells::SetNewValues( const std::vector<ScFormulaCell*>& rVals )
+{
+ maNewValues.assign(rVals);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undoconvert.cxx b/sc/source/ui/undo/undoconvert.cxx
new file mode 100644
index 000000000..ea9facfc2
--- /dev/null
+++ b/sc/source/ui/undo/undoconvert.cxx
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <undoconvert.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <undoutil.hxx>
+
+namespace sc {
+
+UndoFormulaToValue::UndoFormulaToValue( ScDocShell* pDocSh, TableValues& rUndoValues ) :
+ ScSimpleUndo(pDocSh)
+{
+ maUndoValues.swap(rUndoValues);
+}
+
+OUString UndoFormulaToValue::GetComment() const
+{
+ return ScResId(STR_UNDO_FORMULA_TO_VALUE);
+}
+
+void UndoFormulaToValue::Undo()
+{
+ Execute();
+}
+
+void UndoFormulaToValue::Redo()
+{
+ Execute();
+}
+
+void UndoFormulaToValue::Execute()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.SwapNonEmpty(maUndoValues);
+
+ ScUndoUtil::MarkSimpleBlock(pDocShell, maUndoValues.getRange());
+
+ pDocShell->PostPaint(maUndoValues.getRange(), PaintPartFlags::Grid);
+ pDocShell->PostDataChanged();
+ rDoc.BroadcastCells(maUndoValues.getRange(), SfxHintId::ScDataChanged);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undodat.cxx b/sc/source/ui/undo/undodat.cxx
new file mode 100644
index 000000000..1ab89a8b5
--- /dev/null
+++ b/sc/source/ui/undo/undodat.cxx
@@ -0,0 +1,1925 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/app.hxx>
+#include <svx/svdundo.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/diagnose.h>
+
+#include <undodat.hxx>
+#include <undoutil.hxx>
+#include <undoolk.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <olinetab.hxx>
+#include <dbdata.hxx>
+#include <rangenam.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <globalnames.hxx>
+#include <target.hxx>
+#include <dbdocfun.hxx>
+#include <olinefun.hxx>
+#include <dpobject.hxx>
+#include <attrib.hxx>
+#include <hints.hxx>
+#include <chgtrack.hxx>
+#include <refundo.hxx>
+#include <markdata.hxx>
+
+// Show or hide outline groups
+
+ScUndoDoOutline::ScUndoDoOutline( ScDocShell* pNewDocShell,
+ SCCOLROW nNewStart, SCCOLROW nNewEnd, SCTAB nNewTab,
+ ScDocumentUniquePtr pNewUndoDoc, bool bNewColumns,
+ sal_uInt16 nNewLevel, sal_uInt16 nNewEntry, bool bNewShow ) :
+ ScSimpleUndo( pNewDocShell ),
+ nStart( nNewStart ),
+ nEnd( nNewEnd ),
+ nTab( nNewTab ),
+ pUndoDoc( std::move(pNewUndoDoc) ),
+ bColumns( bNewColumns ),
+ nLevel( nNewLevel ),
+ nEntry( nNewEntry ),
+ bShow( bNewShow )
+{
+}
+
+ScUndoDoOutline::~ScUndoDoOutline()
+{
+}
+
+OUString ScUndoDoOutline::GetComment() const
+{ // Show outline" "Hide outline"
+ return bShow ?
+ ScResId( STR_UNDO_DOOUTLINE ) :
+ ScResId( STR_UNDO_REDOOUTLINE );
+}
+
+void ScUndoDoOutline::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ // sheet has to be switched over (#46952#)!
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ // perform the inverse function
+
+ if (bShow)
+ pViewShell->HideOutline( bColumns, nLevel, nEntry, false, false );
+ else
+ pViewShell->ShowOutline( bColumns, nLevel, nEntry, false, false );
+
+ // Original column/row status
+ if (bColumns)
+ pUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart), 0, nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, rDoc);
+ else
+ pUndoDoc->CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pViewShell, bColumns, !bColumns,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+ pViewShell->UpdateScrollBars();
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top);
+
+ EndUndo();
+}
+
+void ScUndoDoOutline::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ // sheet has to be switched over (#46952#)!
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ if (bShow)
+ pViewShell->ShowOutline( bColumns, nLevel, nEntry, false );
+ else
+ pViewShell->HideOutline( bColumns, nLevel, nEntry, false );
+
+ EndRedo();
+}
+
+void ScUndoDoOutline::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoDoOutline::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // is not possible
+}
+
+/** Make or delete outline groups */
+ScUndoMakeOutline::ScUndoMakeOutline( ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ std::unique_ptr<ScOutlineTable> pNewUndoTab, bool bNewColumns, bool bNewMake ) :
+ ScSimpleUndo( pNewDocShell ),
+ aBlockStart( nStartX, nStartY, nStartZ ),
+ aBlockEnd( nEndX, nEndY, nEndZ ),
+ pUndoTable( std::move(pNewUndoTab) ),
+ bColumns( bNewColumns ),
+ bMake( bNewMake )
+{
+}
+
+ScUndoMakeOutline::~ScUndoMakeOutline()
+{
+}
+
+OUString ScUndoMakeOutline::GetComment() const
+{ // "Grouping" "Undo grouping"
+ return bMake ?
+ ScResId( STR_UNDO_MAKEOUTLINE ) :
+ ScResId( STR_UNDO_REMAKEOUTLINE );
+}
+
+void ScUndoMakeOutline::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aBlockStart, aBlockEnd );
+
+ rDoc.SetOutlineTable( nTab, pUndoTable.get() );
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);
+
+ ScTabViewShell::notifyAllViewsHeaderInvalidation( pViewShell, bColumns ? COLUMN_HEADER : ROW_HEADER, nTab );
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ bColumns /* bColumns */, !bColumns /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+
+ EndUndo();
+}
+
+void ScUndoMakeOutline::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aBlockStart, aBlockEnd );
+
+ if (bMake)
+ pViewShell->MakeOutline( bColumns, false );
+ else
+ pViewShell->RemoveOutline( bColumns, false );
+
+ pDocShell->PostPaint(0,0,aBlockStart.Tab(),rDoc.MaxCol(),rDoc.MaxRow(),aBlockEnd.Tab(),PaintPartFlags::Grid);
+
+ EndRedo();
+}
+
+void ScUndoMakeOutline::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+
+ if (bMake)
+ rViewShell.MakeOutline( bColumns );
+ else
+ rViewShell.RemoveOutline( bColumns );
+ }
+}
+
+bool ScUndoMakeOutline::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoOutlineLevel::ScUndoOutlineLevel( ScDocShell* pNewDocShell,
+ SCCOLROW nNewStart, SCCOLROW nNewEnd, SCTAB nNewTab,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ bool bNewColumns, sal_uInt16 nNewLevel )
+ : ScSimpleUndo(pNewDocShell)
+ , nStart(nNewStart)
+ , nEnd(nNewEnd)
+ , nTab(nNewTab)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xUndoTable(std::move(pNewUndoTab))
+ , bColumns(bNewColumns)
+ , nLevel(nNewLevel)
+{
+}
+
+OUString ScUndoOutlineLevel::GetComment() const
+{ // "Select outline level"
+ return ScResId( STR_UNDO_OUTLINELEVEL );
+}
+
+void ScUndoOutlineLevel::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ // Original Outline table
+
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+
+ if (bColumns)
+ xUndoDoc->CopyToDocument(static_cast<SCCOL>(nStart), 0, nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, rDoc);
+ else
+ xUndoDoc->CopyToDocument(0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ rDoc.UpdatePageBreaks( nTab );
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pViewShell, bColumns, !bColumns,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+ pViewShell->UpdateScrollBars();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top);
+
+ EndUndo();
+}
+
+void ScUndoOutlineLevel::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ // sheet has to be switched on or off before this (#46952#) !!!
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pViewShell->SelectLevel( bColumns, nLevel, false );
+
+ EndRedo();
+}
+
+void ScUndoOutlineLevel::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->SelectLevel( bColumns, nLevel );
+}
+
+bool ScUndoOutlineLevel::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+/** show/hide outline over block marks */
+ScUndoOutlineBlock::ScUndoOutlineBlock( ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab, bool bNewShow ) :
+ ScSimpleUndo( pNewDocShell ),
+ aBlockStart( nStartX, nStartY, nStartZ ),
+ aBlockEnd( nEndX, nEndY, nEndZ ),
+ xUndoDoc(std::move(pNewUndoDoc)),
+ xUndoTable(std::move(pNewUndoTab)),
+ bShow( bNewShow )
+{
+}
+
+OUString ScUndoOutlineBlock::GetComment() const
+{ // "Show outline" "Hide outline"
+ return bShow ?
+ ScResId( STR_UNDO_DOOUTLINEBLK ) :
+ ScResId( STR_UNDO_REDOOUTLINEBLK );
+}
+
+void ScUndoOutlineBlock::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ // Original Outline table
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+ SCCOLROW nStartCol = aBlockStart.Col();
+ SCCOLROW nEndCol = aBlockEnd.Col();
+ SCCOLROW nStartRow = aBlockStart.Row();
+ SCCOLROW nEndRow = aBlockEnd.Row();
+
+ if (!bShow)
+ { // Size of the hidden blocks
+ size_t nLevel;
+ xUndoTable->GetColArray().FindTouchedLevel(nStartCol, nEndCol, nLevel);
+ xUndoTable->GetColArray().ExtendBlock(nLevel, nStartCol, nEndCol);
+ xUndoTable->GetRowArray().FindTouchedLevel(nStartRow, nEndRow, nLevel);
+ xUndoTable->GetRowArray().ExtendBlock(nLevel, nStartRow, nEndRow);
+ }
+
+ xUndoDoc->CopyToDocument(static_cast<SCCOL>(nStartCol), 0, nTab,
+ static_cast<SCCOL>(nEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, rDoc);
+ xUndoDoc->CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ rDoc.UpdatePageBreaks( nTab );
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pViewShell, true /* bColumns */, true /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+ pViewShell->UpdateScrollBars();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top);
+
+
+ pViewShell->OnLOKShowHideColRow(/*columns: */ true, nStartCol - 1);
+ pViewShell->OnLOKShowHideColRow(/*columns: */ false, nStartRow - 1);
+
+ EndUndo();
+}
+
+void ScUndoOutlineBlock::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aBlockStart, aBlockEnd );
+ if (bShow)
+ pViewShell->ShowMarkedOutlines( false );
+ else
+ pViewShell->HideMarkedOutlines( false );
+
+ EndRedo();
+}
+
+void ScUndoOutlineBlock::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+
+ if (bShow)
+ rViewShell.ShowMarkedOutlines();
+ else
+ rViewShell.HideMarkedOutlines();
+ }
+}
+
+bool ScUndoOutlineBlock::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRemoveAllOutlines::ScUndoRemoveAllOutlines(ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab)
+ : ScSimpleUndo(pNewDocShell)
+ , aBlockStart(nStartX, nStartY, nStartZ)
+ , aBlockEnd(nEndX, nEndY, nEndZ)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xUndoTable(std::move(pNewUndoTab))
+{
+}
+
+OUString ScUndoRemoveAllOutlines::GetComment() const
+{ // "Remove outlines"
+ return ScResId( STR_UNDO_REMOVEALLOTLNS );
+}
+
+void ScUndoRemoveAllOutlines::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ // Original Outline table
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+ SCCOL nStartCol = aBlockStart.Col();
+ SCCOL nEndCol = aBlockEnd.Col();
+ SCROW nStartRow = aBlockStart.Row();
+ SCROW nEndRow = aBlockEnd.Row();
+
+ xUndoDoc->CopyToDocument(nStartCol, 0, nTab, nEndCol, rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, rDoc);
+ xUndoDoc->CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ rDoc.UpdatePageBreaks( nTab );
+
+ pViewShell->UpdateScrollBars();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);
+
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, BOTH_HEADERS, nTab);
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ true /* bColumns */, true /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+
+ EndUndo();
+}
+
+void ScUndoRemoveAllOutlines::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ // sheet has to be switched over (#46952#)!
+
+ SCTAB nTab = aBlockStart.Tab();
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pViewShell->RemoveAllOutlines( false );
+
+ EndRedo();
+}
+
+void ScUndoRemoveAllOutlines::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->RemoveAllOutlines();
+}
+
+bool ScUndoRemoveAllOutlines::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoAutoOutline::ScUndoAutoOutline(ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab)
+ : ScSimpleUndo(pNewDocShell)
+ , aBlockStart(nStartX, nStartY, nStartZ)
+ , aBlockEnd(nEndX, nEndY, nEndZ)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xUndoTable(std::move(pNewUndoTab))
+{
+}
+
+OUString ScUndoAutoOutline::GetComment() const
+{
+ return ScResId( STR_UNDO_AUTOOUTLINE );
+}
+
+void ScUndoAutoOutline::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ // Original outline table
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+ if (xUndoDoc && xUndoTable)
+ {
+ SCCOLROW nStartCol;
+ SCCOLROW nStartRow;
+ SCCOLROW nEndCol;
+ SCCOLROW nEndRow;
+ xUndoTable->GetColArray().GetRange(nStartCol, nEndCol);
+ xUndoTable->GetRowArray().GetRange(nStartRow, nEndRow);
+
+ xUndoDoc->CopyToDocument(static_cast<SCCOL>(nStartCol), 0, nTab,
+ static_cast<SCCOL>(nEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false,
+ rDoc);
+ xUndoDoc->CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ pViewShell->UpdateScrollBars();
+ }
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);
+
+ EndUndo();
+}
+
+void ScUndoAutoOutline::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nTab = aBlockStart.Tab();
+ if (pViewShell)
+ {
+ // sheet has to be switched on or off before this (#46952#) !!!
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+ }
+
+ ScRange aRange( aBlockStart.Col(), aBlockStart.Row(), nTab,
+ aBlockEnd.Col(), aBlockEnd.Row(), nTab );
+ ScOutlineDocFunc aFunc( *pDocShell );
+ aFunc.AutoOutline( aRange, false );
+
+ // Select in View
+ // If it was called with a multi selection,
+ // then this is now the enclosing range...
+
+ if (pViewShell)
+ pViewShell->MarkRange( aRange );
+
+ EndRedo();
+}
+
+void ScUndoAutoOutline::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->AutoOutline();
+}
+
+bool ScUndoAutoOutline::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoSubTotals::ScUndoSubTotals(ScDocShell* pNewDocShell, SCTAB nNewTab,
+ const ScSubTotalParam& rNewParam, SCROW nNewEndY,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ std::unique_ptr<ScRangeName> pNewUndoRange, std::unique_ptr<ScDBCollection> pNewUndoDB)
+ : ScDBFuncUndo(pNewDocShell, ScRange(rNewParam.nCol1, rNewParam.nRow1, nNewTab,
+ rNewParam.nCol2, rNewParam.nRow2, nNewTab))
+ , nTab(nNewTab)
+ , aParam(rNewParam)
+ , nNewEndRow(nNewEndY)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xUndoTable(std::move(pNewUndoTab))
+ , xUndoRange(std::move(pNewUndoRange))
+ , xUndoDB(std::move(pNewUndoDB))
+{
+}
+
+OUString ScUndoSubTotals::GetComment() const
+{ // "Subtotals"
+ return ScResId( STR_UNDO_SUBTOTALS );
+}
+
+void ScUndoSubTotals::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ if (nNewEndRow > aParam.nRow2)
+ {
+ rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, aParam.nRow2+1, static_cast<SCSIZE>(nNewEndRow-aParam.nRow2) );
+ }
+ else if (nNewEndRow < aParam.nRow2)
+ {
+ rDoc.InsertRow( 0,nTab, rDoc.MaxCol(),nTab, nNewEndRow+1, static_cast<SCSIZE>(aParam.nRow2-nNewEndRow) );
+ }
+
+ // Original Outline table
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+ if (xUndoTable)
+ {
+ SCCOLROW nStartCol;
+ SCCOLROW nStartRow;
+ SCCOLROW nEndCol;
+ SCCOLROW nEndRow;
+ xUndoTable->GetColArray().GetRange(nStartCol, nEndCol);
+ xUndoTable->GetRowArray().GetRange(nStartRow, nEndRow);
+
+ xUndoDoc->CopyToDocument(static_cast<SCCOL>(nStartCol), 0, nTab,
+ static_cast<SCCOL>(nEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false,
+ rDoc);
+ xUndoDoc->CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ pViewShell->UpdateScrollBars();
+ }
+
+ // Original data and references
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, 0, aParam.nRow1+1, nTab,
+ rDoc.MaxCol(), aParam.nRow2, nTab );
+
+ rDoc.DeleteAreaTab( 0,aParam.nRow1+1, rDoc.MaxCol(),aParam.nRow2, nTab, InsertDeleteFlags::ALL );
+
+ xUndoDoc->CopyToDocument(0, aParam.nRow1+1, nTab, rDoc.MaxCol(), aParam.nRow2, nTab,
+ InsertDeleteFlags::NONE, false, rDoc); // Flags
+ xUndoDoc->UndoToDocument(0, aParam.nRow1+1, nTab, rDoc.MaxCol(), aParam.nRow2, nTab,
+ InsertDeleteFlags::ALL, false, rDoc);
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aParam.nCol1,aParam.nRow1,nTab,
+ aParam.nCol2,aParam.nRow2,nTab );
+
+ if (xUndoRange)
+ rDoc.SetRangeName(std::unique_ptr<ScRangeName>(new ScRangeName(*xUndoRange)));
+ if (xUndoDB)
+ rDoc.SetDBCollection(std::unique_ptr<ScDBCollection>(new ScDBCollection(*xUndoDB)), true);
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);
+ pDocShell->PostDataChanged();
+
+ EndUndo();
+}
+
+void ScUndoSubTotals::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aParam.nCol1,aParam.nRow1,nTab,
+ aParam.nCol2,aParam.nRow2,nTab );
+ pViewShell->DoSubTotals( aParam, false );
+
+ EndRedo();
+}
+
+void ScUndoSubTotals::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoSubTotals::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // is not possible due to column numbers
+}
+
+ScUndoQuery::ScUndoQuery( ScDocShell* pNewDocShell, SCTAB nNewTab, const ScQueryParam& rParam,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScDBCollection> pNewUndoDB,
+ const ScRange* pOld, bool bSize, const ScRange* pAdvSrc ) :
+ ScDBFuncUndo( pNewDocShell, ScRange( rParam.nCol1, rParam.nRow1, nNewTab,
+ rParam.nCol2, rParam.nRow2, nNewTab ) ),
+ nTab( nNewTab ),
+ aQueryParam( rParam ),
+ xUndoDoc( std::move(pNewUndoDoc) ),
+ xUndoDB( std::move(pNewUndoDB) ),
+ bIsAdvanced( false ),
+ bDestArea( false ),
+ bDoSize( bSize )
+{
+ if ( pOld )
+ {
+ bDestArea = true;
+ aOldDest = *pOld;
+ }
+ if ( pAdvSrc )
+ {
+ bIsAdvanced = true;
+ aAdvSource = *pAdvSrc;
+ }
+
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScUndoQuery::~ScUndoQuery()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoQuery::GetComment() const
+{ // "Filter";
+ return ScResId( STR_UNDO_QUERY );
+}
+
+void ScUndoQuery::Undo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (ScTabViewShell::isAnyEditViewInRange(pViewShell, /*bColumns*/ false, aQueryParam.nRow1, aQueryParam.nRow2))
+ return;
+
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ bool bCopy = !aQueryParam.bInplace;
+ SCCOL nDestEndCol = 0;
+ SCROW nDestEndRow = 0;
+ if (bCopy)
+ {
+ nDestEndCol = aQueryParam.nDestCol + ( aQueryParam.nCol2-aQueryParam.nCol1 );
+ nDestEndRow = aQueryParam.nDestRow + ( aQueryParam.nRow2-aQueryParam.nRow1 );
+
+ ScDBData* pData = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
+ aQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
+ if (pData)
+ {
+ ScRange aNewDest;
+ pData->GetArea( aNewDest );
+ nDestEndCol = aNewDest.aEnd.Col();
+ nDestEndRow = aNewDest.aEnd.Row();
+ }
+
+ if ( bDoSize && bDestArea )
+ {
+ // aDestRange is the old range
+ rDoc.FitBlock( ScRange(
+ aQueryParam.nDestCol, aQueryParam.nDestRow, aQueryParam.nDestTab,
+ nDestEndCol, nDestEndRow, aQueryParam.nDestTab ),
+ aOldDest );
+ }
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell,
+ aQueryParam.nDestCol, aQueryParam.nDestRow, aQueryParam.nDestTab,
+ nDestEndCol, nDestEndRow, aQueryParam.nDestTab );
+ rDoc.DeleteAreaTab( aQueryParam.nDestCol, aQueryParam.nDestRow,
+ nDestEndCol, nDestEndRow, aQueryParam.nDestTab, InsertDeleteFlags::ALL );
+
+ pViewShell->DoneBlockMode();
+
+ xUndoDoc->CopyToDocument(aQueryParam.nDestCol, aQueryParam.nDestRow, aQueryParam.nDestTab,
+ nDestEndCol, nDestEndRow, aQueryParam.nDestTab,
+ InsertDeleteFlags::ALL, false, rDoc);
+ // Attributes are always copied (#49287#)
+
+ // rest of the old range
+ if ( bDestArea && !bDoSize )
+ {
+ rDoc.DeleteAreaTab( aOldDest, InsertDeleteFlags::ALL );
+ xUndoDoc->CopyToDocument(aOldDest, InsertDeleteFlags::ALL, false, rDoc);
+ }
+ }
+ else
+ xUndoDoc->CopyToDocument(0, aQueryParam.nRow1, nTab, rDoc.MaxCol(), aQueryParam.nRow2, nTab,
+ InsertDeleteFlags::NONE, false, rDoc);
+
+ if (xUndoDB)
+ rDoc.SetDBCollection(std::unique_ptr<ScDBCollection>(new ScDBCollection(*xUndoDB )), true);
+
+ if (!bCopy)
+ {
+ rDoc.InvalidatePageBreaks(nTab);
+ rDoc.UpdatePageBreaks( nTab );
+ }
+
+ ScRange aDirtyRange( 0 , aQueryParam.nRow1, nTab,
+ rDoc.MaxCol(), aQueryParam.nRow2, nTab );
+ rDoc.SetDirty( aDirtyRange, true );
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc );
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+
+ // invalidate cache positions and update cursor and selection
+ pViewShell->OnLOKShowHideColRow(/*bColumns*/ false, aQueryParam.nRow1 - 1);
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(pViewShell, ROW_HEADER, nTab);
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pViewShell,
+ false /* bColumns */, true /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ false /* bGroups */, nTab);
+
+ // Paint
+
+ if (bCopy)
+ {
+ SCCOL nEndX = nDestEndCol;
+ SCROW nEndY = nDestEndRow;
+ if (bDestArea)
+ {
+ if ( aOldDest.aEnd.Col() > nEndX )
+ nEndX = aOldDest.aEnd.Col();
+ if ( aOldDest.aEnd.Row() > nEndY )
+ nEndY = aOldDest.aEnd.Row();
+ }
+ if (bDoSize)
+ nEndY = rDoc.MaxRow();
+ pDocShell->PostPaint( aQueryParam.nDestCol, aQueryParam.nDestRow, aQueryParam.nDestTab,
+ nEndX, nEndY, aQueryParam.nDestTab, PaintPartFlags::Grid );
+ }
+ else
+ pDocShell->PostPaint( 0, aQueryParam.nRow1, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab,
+ PaintPartFlags::Grid | PaintPartFlags::Left );
+ pDocShell->PostDataChanged();
+
+ EndUndo();
+}
+
+void ScUndoQuery::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ if ( bIsAdvanced )
+ pViewShell->Query( aQueryParam, &aAdvSource, false );
+ else
+ pViewShell->Query( aQueryParam, nullptr, false );
+
+ EndRedo();
+}
+
+void ScUndoQuery::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoQuery::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // does not work due to column numbers
+}
+
+// Show or hide AutoFilter buttons (doesn't include filter settings)
+
+ScUndoAutoFilter::ScUndoAutoFilter( ScDocShell* pNewDocShell, const ScRange& rRange,
+ const OUString& rName, bool bSet ) :
+ ScDBFuncUndo( pNewDocShell, rRange ),
+ aDBName( rName ),
+ bFilterSet( bSet )
+{
+}
+
+ScUndoAutoFilter::~ScUndoAutoFilter()
+{
+}
+
+OUString ScUndoAutoFilter::GetComment() const
+{
+ return ScResId( STR_UNDO_QUERY ); // same as ScUndoQuery
+}
+
+void ScUndoAutoFilter::DoChange( bool bUndo )
+{
+ bool bNewFilter = bUndo ? !bFilterSet : bFilterSet;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDBData* pDBData=nullptr;
+ if (aDBName == STR_DB_LOCAL_NONAME)
+ {
+ SCTAB nTab = aOriginalRange.aStart.Tab();
+ pDBData = rDoc.GetAnonymousDBData(nTab);
+ }
+ else
+ {
+ ScDBCollection* pColl = rDoc.GetDBCollection();
+ pDBData = pColl->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(aDBName));
+ }
+
+ if ( !pDBData )
+ return;
+
+ pDBData->SetAutoFilter( bNewFilter );
+
+ SCCOL nRangeX1;
+ SCROW nRangeY1;
+ SCCOL nRangeX2;
+ SCROW nRangeY2;
+ SCTAB nRangeTab;
+ pDBData->GetArea( nRangeTab, nRangeX1, nRangeY1, nRangeX2, nRangeY2 );
+
+ if ( bNewFilter )
+ rDoc.ApplyFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, ScMF::Auto );
+ else
+ rDoc.RemoveFlagsTab( nRangeX1, nRangeY1, nRangeX2, nRangeY1, nRangeTab, ScMF::Auto );
+
+ pDocShell->PostPaint( nRangeX1, nRangeY1, nRangeTab, nRangeX2, nRangeY1, nRangeTab, PaintPartFlags::Grid );
+}
+
+void ScUndoAutoFilter::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoAutoFilter::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoAutoFilter::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoAutoFilter::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+// change database sections (dialog)
+ScUndoDBData::ScUndoDBData( ScDocShell* pNewDocShell,
+ std::unique_ptr<ScDBCollection> pNewUndoColl,
+ std::unique_ptr<ScDBCollection> pNewRedoColl ) :
+ ScSimpleUndo( pNewDocShell ),
+ pUndoColl( std::move(pNewUndoColl) ),
+ pRedoColl( std::move(pNewRedoColl) )
+{
+}
+
+ScUndoDBData::~ScUndoDBData()
+{
+}
+
+OUString ScUndoDBData::GetComment() const
+{ // "Change database range";
+ return ScResId( STR_UNDO_DBDATA );
+}
+
+void ScUndoDBData::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ bool bOldAutoCalc = rDoc.GetAutoCalc();
+ rDoc.SetAutoCalc( false ); // Avoid unnecessary calculations
+ rDoc.PreprocessDBDataUpdate();
+ rDoc.SetDBCollection( std::unique_ptr<ScDBCollection>(new ScDBCollection(*pUndoColl)), true );
+ rDoc.CompileHybridFormula();
+ rDoc.SetAutoCalc( bOldAutoCalc );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+
+ EndUndo();
+}
+
+void ScUndoDBData::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ bool bOldAutoCalc = rDoc.GetAutoCalc();
+ rDoc.SetAutoCalc( false ); // Avoid unnecessary calculations
+ rDoc.PreprocessDBDataUpdate();
+ rDoc.SetDBCollection( std::unique_ptr<ScDBCollection>(new ScDBCollection(*pRedoColl)), true );
+ rDoc.CompileHybridFormula();
+ rDoc.SetAutoCalc( bOldAutoCalc );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+
+ EndRedo();
+}
+
+void ScUndoDBData::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoDBData::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // is not possible
+}
+
+ScUndoImportData::ScUndoImportData( ScDocShell* pNewDocShell, SCTAB nNewTab,
+ const ScImportParam& rParam, SCCOL nNewEndX, SCROW nNewEndY,
+ SCCOL nNewFormula,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
+ std::unique_ptr<ScDBData> pNewUndoData, std::unique_ptr<ScDBData> pNewRedoData ) :
+ ScSimpleUndo( pNewDocShell ),
+ nTab( nNewTab ),
+ aImportParam( rParam ),
+ nEndCol( nNewEndX ),
+ nEndRow( nNewEndY ),
+ xUndoDoc(std::move(pNewUndoDoc)),
+ xRedoDoc(std::move(pNewRedoDoc)),
+ xUndoDBData(std::move(pNewUndoData)),
+ xRedoDBData(std::move(pNewRedoData)),
+ nFormulaCols( nNewFormula ),
+ bRedoFilled( false )
+{
+ // redo doc doesn't contain imported data (but everything else)
+}
+
+OUString ScUndoImportData::GetComment() const
+{
+ return ScResId( STR_UNDO_IMPORTDATA );
+}
+
+void ScUndoImportData::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol,nEndRow,nTab );
+
+ SCTAB nTable;
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ ScDBData* pCurrentData = nullptr;
+ if (xUndoDBData && xRedoDBData)
+ {
+ xRedoDBData->GetArea( nTable, nCol1, nRow1, nCol2, nRow2 );
+ pCurrentData = ScUndoUtil::GetOldDBData(xRedoDBData.get(), &rDoc, nTab,
+ nCol1, nRow1, nCol2, nRow2);
+
+ if ( !bRedoFilled )
+ {
+ // read redo data from document at first undo
+ // imported data is deleted later anyway,
+ // so now delete each column after copying to save memory (#41216#)
+
+ bool bOldAutoCalc = rDoc.GetAutoCalc();
+ rDoc.SetAutoCalc( false ); // outside of the loop
+ for (SCCOL nCopyCol = nCol1; nCopyCol <= nCol2; nCopyCol++)
+ {
+ rDoc.CopyToDocument(nCopyCol,nRow1,nTab, nCopyCol,nRow2,nTab,
+ InsertDeleteFlags::CONTENTS & ~InsertDeleteFlags::NOTE, false, *xRedoDoc);
+ rDoc.DeleteAreaTab(nCopyCol, nRow1, nCopyCol, nRow2, nTab, InsertDeleteFlags::CONTENTS & ~InsertDeleteFlags::NOTE);
+ }
+ rDoc.SetAutoCalc( bOldAutoCalc );
+ bRedoFilled = true;
+ }
+ }
+ bool bMoveCells = xUndoDBData && xRedoDBData &&
+ xRedoDBData->IsDoSize(); // the same in old and new
+ if (bMoveCells)
+ {
+ // Undo: first delete the new data, then FitBlock backwards
+
+ ScRange aOld, aNew;
+ xUndoDBData->GetArea(aOld);
+ xRedoDBData->GetArea(aNew);
+
+ rDoc.DeleteAreaTab( aNew.aStart.Col(), aNew.aStart.Row(),
+ aNew.aEnd.Col(), aNew.aEnd.Row(), nTab, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+
+ aOld.aEnd.SetCol( aOld.aEnd.Col() + nFormulaCols ); // FitBlock also for formulas
+ aNew.aEnd.SetCol( aNew.aEnd.Col() + nFormulaCols );
+ rDoc.FitBlock( aNew, aOld, false ); // backwards
+ }
+ else
+ rDoc.DeleteAreaTab( aImportParam.nCol1,aImportParam.nRow1,
+ nEndCol,nEndRow, nTab, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+
+ xUndoDoc->CopyToDocument(aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol+nFormulaCols,nEndRow,nTab,
+ InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+
+ if (pCurrentData)
+ {
+ *pCurrentData = *xUndoDBData;
+
+ xUndoDBData->GetArea(nTable, nCol1, nRow1, nCol2, nRow2);
+ ScUndoUtil::MarkSimpleBlock( pDocShell, nCol1, nRow1, nTable, nCol2, nRow2, nTable );
+ }
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ if (bMoveCells)
+ pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
+ else
+ pDocShell->PostPaint( aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol,nEndRow,nTab, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+
+ EndUndo();
+}
+
+void ScUndoImportData::Redo()
+{
+ BeginRedo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol,nEndRow,nTab );
+
+ SCTAB nTable;
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ ScDBData* pCurrentData = nullptr;
+ if (xUndoDBData && xRedoDBData)
+ {
+ xUndoDBData->GetArea( nTable, nCol1, nRow1, nCol2, nRow2 );
+ pCurrentData = ScUndoUtil::GetOldDBData(xUndoDBData.get(), &rDoc, nTab,
+ nCol1, nRow1, nCol2, nRow2);
+ }
+ bool bMoveCells = xUndoDBData && xRedoDBData &&
+ xRedoDBData->IsDoSize(); // the same in old and new
+ if (bMoveCells)
+ {
+ // Redo: FitBlock, then delete data (needed for CopyToDocument)
+
+ ScRange aOld, aNew;
+ xUndoDBData->GetArea(aOld);
+ xRedoDBData->GetArea(aNew);
+
+ aOld.aEnd.SetCol( aOld.aEnd.Col() + nFormulaCols ); // FitBlock also for formulas
+ aNew.aEnd.SetCol( aNew.aEnd.Col() + nFormulaCols );
+ rDoc.FitBlock( aOld, aNew );
+
+ rDoc.DeleteAreaTab( aNew.aStart.Col(), aNew.aStart.Row(),
+ aNew.aEnd.Col(), aNew.aEnd.Row(), nTab, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+
+ xRedoDoc->CopyToDocument(aNew, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc); // including formulas
+ }
+ else
+ {
+ rDoc.DeleteAreaTab( aImportParam.nCol1,aImportParam.nRow1,
+ nEndCol,nEndRow, nTab, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE );
+ xRedoDoc->CopyToDocument(aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol,nEndRow,nTab, InsertDeleteFlags::ALL & ~InsertDeleteFlags::NOTE, false, rDoc);
+ }
+
+ if (pCurrentData)
+ {
+ *pCurrentData = *xRedoDBData;
+
+ xRedoDBData->GetArea(nTable, nCol1, nRow1, nCol2, nRow2);
+ ScUndoUtil::MarkSimpleBlock( pDocShell, nCol1, nRow1, nTable, nCol2, nRow2, nTable );
+ }
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ if (bMoveCells)
+ pDocShell->PostPaint( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid );
+ else
+ pDocShell->PostPaint( aImportParam.nCol1,aImportParam.nRow1,nTab,
+ nEndCol,nEndRow,nTab, PaintPartFlags::Grid );
+ pDocShell->PostDataChanged();
+
+ EndRedo();
+}
+
+void ScUndoImportData::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell& rViewShell = *pViewTarget->GetViewShell();
+
+ SCTAB nDummy;
+ ScImportParam aNewParam(aImportParam);
+ ScDBData* pDBData = rViewShell.GetDBData();
+ pDBData->GetArea( nDummy, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
+
+ rViewShell.ImportData( aNewParam );
+ }
+}
+
+bool ScUndoImportData::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ // Repeat only for import using a database range, then xUndoDBData is set
+
+ if (xUndoDBData)
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+ else
+ return false; // Address book
+}
+
+ScUndoRepeatDB::ScUndoRepeatDB( ScDocShell* pNewDocShell, SCTAB nNewTab,
+ SCCOL nStartX, SCROW nStartY, SCCOL nEndX, SCROW nEndY,
+ SCROW nResultEndRow, SCCOL nCurX, SCROW nCurY,
+ ScDocumentUniquePtr pNewUndoDoc, std::unique_ptr<ScOutlineTable> pNewUndoTab,
+ std::unique_ptr<ScRangeName> pNewUndoRange, std::unique_ptr<ScDBCollection> pNewUndoDB,
+ const ScRange* pOldQ, const ScRange* pNewQ ) :
+ ScSimpleUndo( pNewDocShell ),
+ aBlockStart( nStartX,nStartY,nNewTab ),
+ aBlockEnd( nEndX,nEndY,nNewTab ),
+ nNewEndRow( nResultEndRow ),
+ aCursorPos( nCurX,nCurY,nNewTab ),
+ xUndoDoc(std::move(pNewUndoDoc)),
+ xUndoTable(std::move(pNewUndoTab)),
+ xUndoRange(std::move(pNewUndoRange)),
+ xUndoDB(std::move(pNewUndoDB)),
+ bQuerySize( false )
+{
+ if ( pOldQ && pNewQ )
+ {
+ aOldQuery = *pOldQ;
+ aNewQuery = *pNewQ;
+ bQuerySize = true;
+ }
+}
+
+OUString ScUndoRepeatDB::GetComment() const
+{
+ return ScResId( STR_UNDO_REPEATDB );
+}
+
+void ScUndoRepeatDB::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ if (bQuerySize)
+ {
+ rDoc.FitBlock( aNewQuery, aOldQuery, false );
+
+ if ( aNewQuery.aEnd.Col() == aOldQuery.aEnd.Col() )
+ {
+ SCCOL nFormulaCols = 0;
+ SCCOL nCol = aOldQuery.aEnd.Col() + 1;
+ SCROW nRow = aOldQuery.aStart.Row() + 1; // test the header
+ while ( nCol <= rDoc.MaxCol() &&
+ rDoc.GetCellType(ScAddress( nCol, nRow, nTab )) == CELLTYPE_FORMULA )
+ {
+ ++nCol;
+ ++nFormulaCols;
+ }
+
+ if ( nFormulaCols > 0 )
+ {
+ ScRange aOldForm = aOldQuery;
+ aOldForm.aStart.SetCol( aOldQuery.aEnd.Col() + 1 );
+ aOldForm.aEnd.SetCol( aOldQuery.aEnd.Col() + nFormulaCols );
+ ScRange aNewForm = aOldForm;
+ aNewForm.aEnd.SetRow( aNewQuery.aEnd.Row() );
+ rDoc.FitBlock( aNewForm, aOldForm, false );
+ }
+ }
+ }
+
+ // TODO Data from Filter in other range are still missing!
+
+ if (nNewEndRow > aBlockEnd.Row())
+ {
+ rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, aBlockEnd.Row()+1, static_cast<SCSIZE>(nNewEndRow-aBlockEnd.Row()) );
+ }
+ else if (nNewEndRow < aBlockEnd.Row())
+ {
+ rDoc.InsertRow( 0,nTab, rDoc.MaxCol(),nTab, nNewEndRow+1, static_cast<SCSIZE>(nNewEndRow-aBlockEnd.Row()) );
+ }
+
+ // Original Outline table
+ rDoc.SetOutlineTable(nTab, xUndoTable.get());
+
+ // Original column/row status
+ if (xUndoTable)
+ {
+ SCCOLROW nStartCol;
+ SCCOLROW nStartRow;
+ SCCOLROW nEndCol;
+ SCCOLROW nEndRow;
+ xUndoTable->GetColArray().GetRange(nStartCol, nEndCol);
+ xUndoTable->GetRowArray().GetRange(nStartRow, nEndRow);
+
+ xUndoDoc->CopyToDocument(static_cast<SCCOL>(nStartCol), 0, nTab,
+ static_cast<SCCOL>(nEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false,
+ rDoc);
+ xUndoDoc->CopyToDocument(0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ pViewShell->UpdateScrollBars();
+ }
+
+ // Original data and references
+ ScUndoUtil::MarkSimpleBlock( pDocShell, 0, aBlockStart.Row(), nTab,
+ rDoc.MaxCol(), aBlockEnd.Row(), nTab );
+ rDoc.DeleteAreaTab( 0, aBlockStart.Row(),
+ rDoc.MaxCol(), aBlockEnd.Row(), nTab, InsertDeleteFlags::ALL );
+
+ xUndoDoc->CopyToDocument(0, aBlockStart.Row(), nTab, rDoc.MaxCol(), aBlockEnd.Row(), nTab,
+ InsertDeleteFlags::NONE, false, rDoc); // Flags
+ xUndoDoc->UndoToDocument(0, aBlockStart.Row(), nTab, rDoc.MaxCol(), aBlockEnd.Row(), nTab,
+ InsertDeleteFlags::ALL, false, rDoc);
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aBlockStart.Col(),aBlockStart.Row(),nTab,
+ aBlockEnd.Col(),aBlockEnd.Row(),nTab );
+
+ if (xUndoRange)
+ rDoc.SetRangeName(std::unique_ptr<ScRangeName>(new ScRangeName(*xUndoRange)));
+ if (xUndoDB)
+ rDoc.SetDBCollection(std::unique_ptr<ScDBCollection>(new ScDBCollection(*xUndoDB)), true);
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pViewShell, false /* bColumns */, true /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ false /* bGroups */, nTab);
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab,PaintPartFlags::Grid|PaintPartFlags::Left|PaintPartFlags::Top|PaintPartFlags::Size);
+ pDocShell->PostDataChanged();
+
+ EndUndo();
+}
+
+void ScUndoRepeatDB::Redo()
+{
+ BeginRedo();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ SCTAB nTab = aBlockStart.Tab();
+
+ SCTAB nVisTab = pViewShell->GetViewData().GetTabNo();
+ if ( nVisTab != nTab )
+ pViewShell->SetTabNo( nTab );
+
+ ScUndoUtil::MarkSimpleBlock( pDocShell, aBlockStart.Col(),aBlockStart.Row(),nTab,
+ aBlockEnd.Col(),aBlockEnd.Row(),nTab );
+ pViewShell->SetCursor( aCursorPos.Col(), aCursorPos.Row() );
+
+ pViewShell->RepeatDB( false );
+
+ EndRedo();
+}
+
+void ScUndoRepeatDB::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->RepeatDB();
+}
+
+bool ScUndoRepeatDB::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoDataPilot::ScUndoDataPilot( ScDocShell* pNewDocShell,
+ ScDocumentUniquePtr pOldDoc, ScDocumentUniquePtr pNewDoc,
+ const ScDPObject* pOldObj, const ScDPObject* pNewObj, bool bMove )
+ : ScSimpleUndo(pNewDocShell)
+ , xOldUndoDoc(std::move(pOldDoc))
+ , xNewUndoDoc(std::move(pNewDoc))
+ , bAllowMove( bMove)
+{
+ if (pOldObj)
+ xOldDPObject.reset(new ScDPObject(*pOldObj));
+ if (pNewObj)
+ xNewDPObject.reset(new ScDPObject(*pNewObj));
+}
+
+OUString ScUndoDataPilot::GetComment() const
+{
+ TranslateId pResId;
+ if (xOldUndoDoc && xNewUndoDoc)
+ pResId = STR_UNDO_PIVOT_MODIFY;
+ else if (xNewUndoDoc)
+ pResId = STR_UNDO_PIVOT_NEW;
+ else
+ pResId = STR_UNDO_PIVOT_DELETE;
+
+ return ScResId(pResId);
+}
+
+void ScUndoDataPilot::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScRange aOldRange;
+ ScRange aNewRange;
+
+ if (xNewDPObject && xNewUndoDoc)
+ {
+ aNewRange = xNewDPObject->GetOutRange();
+ rDoc.DeleteAreaTab( aNewRange, InsertDeleteFlags::ALL );
+ xNewUndoDoc->CopyToDocument(aNewRange, InsertDeleteFlags::ALL, false, rDoc);
+ }
+ if (xOldDPObject && xOldUndoDoc)
+ {
+ aOldRange = xOldDPObject->GetOutRange();
+ rDoc.DeleteAreaTab(aOldRange, InsertDeleteFlags::ALL);
+ xOldUndoDoc->CopyToDocument(aOldRange, InsertDeleteFlags::ALL, false, rDoc);
+ }
+
+ // update objects in collection
+ if (xNewDPObject)
+ {
+ // find updated object
+ //! find by name!
+
+ ScDPObject* pDocObj = rDoc.GetDPAtCursor(
+ aNewRange.aStart.Col(), aNewRange.aStart.Row(), aNewRange.aStart.Tab() );
+ OSL_ENSURE(pDocObj, "DPObject not found");
+ if (pDocObj)
+ {
+ if (xOldDPObject)
+ {
+ // restore old settings
+ xOldDPObject->WriteSourceDataTo( *pDocObj );
+ ScDPSaveData* pData = xOldDPObject->GetSaveData();
+ if (pData)
+ pDocObj->SetSaveData(*pData);
+ pDocObj->SetOutRange(xOldDPObject->GetOutRange());
+ xOldDPObject->WriteTempDataTo( *pDocObj );
+ }
+ else
+ {
+ // delete inserted object
+ rDoc.GetDPCollection()->FreeTable(pDocObj);
+ }
+ }
+ }
+ else if (xOldDPObject)
+ {
+ // re-insert deleted object
+ rDoc.GetDPCollection()->InsertNewTable(std::make_unique<ScDPObject>(*xOldDPObject));
+ }
+
+ if (xNewUndoDoc)
+ pDocShell->PostPaint(aNewRange, PaintPartFlags::Grid, SC_PF_LINES);
+ if (xOldUndoDoc)
+ pDocShell->PostPaint(aOldRange, PaintPartFlags::Grid, SC_PF_LINES);
+ pDocShell->PostDataChanged();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ //! set current sheet
+ }
+
+ if (xNewDPObject)
+ {
+ // notify API objects
+ rDoc.BroadcastUno(ScDataPilotModifiedHint(xNewDPObject->GetName()));
+ }
+
+ EndUndo();
+}
+
+void ScUndoDataPilot::Redo()
+{
+ BeginRedo();
+
+ //! copy output data instead of repeating the change,
+ //! in case external data have changed!
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScDPObject* pSourceObj = nullptr;
+ if (xOldDPObject)
+ {
+ // find object to modify
+ //! find by name!
+
+ ScRange aOldRange = xOldDPObject->GetOutRange();
+ pSourceObj = rDoc.GetDPAtCursor(
+ aOldRange.aStart.Col(), aOldRange.aStart.Row(), aOldRange.aStart.Tab() );
+ OSL_ENSURE(pSourceObj, "DPObject not found");
+ }
+
+ ScDBDocFunc aFunc( *pDocShell );
+ aFunc.DataPilotUpdate(pSourceObj, xNewDPObject.get(), false, false, bAllowMove); // no new undo action
+
+ EndRedo();
+}
+
+void ScUndoDataPilot::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ //! allow deletion
+}
+
+bool ScUndoDataPilot::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ //! allow deletion
+ return false;
+}
+
+ScUndoConsolidate::ScUndoConsolidate( ScDocShell* pNewDocShell, const ScArea& rArea,
+ const ScConsolidateParam& rPar, ScDocumentUniquePtr pNewUndoDoc,
+ bool bReference, SCROW nInsCount, std::unique_ptr<ScOutlineTable> pTab,
+ std::unique_ptr<ScDBData> pData )
+ : ScSimpleUndo(pNewDocShell)
+ , aDestArea(rArea)
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , aParam(rPar)
+ , bInsRef(bReference)
+ , nInsertCount(nInsCount)
+ , xUndoTab(std::move(pTab))
+ , xUndoData(std::move(pData))
+{
+}
+
+OUString ScUndoConsolidate::GetComment() const
+{
+ return ScResId( STR_UNDO_CONSOLIDATE );
+}
+
+void ScUndoConsolidate::Undo()
+{
+ BeginUndo();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab = aDestArea.nTab;
+
+ ScRange aOldRange;
+ if (xUndoData)
+ xUndoData->GetArea(aOldRange);
+
+ if (bInsRef)
+ {
+ rDoc.DeleteRow( 0,nTab, rDoc.MaxCol(),nTab, aDestArea.nRowStart, nInsertCount );
+ rDoc.SetOutlineTable(nTab, xUndoTab.get());
+
+ // Row status
+ xUndoDoc->CopyToDocument(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, rDoc);
+
+ // Data and references
+ rDoc.DeleteAreaTab( 0,aDestArea.nRowStart, rDoc.MaxCol(),aDestArea.nRowEnd, nTab, InsertDeleteFlags::ALL );
+ xUndoDoc->UndoToDocument(0, aDestArea.nRowStart, nTab,
+ rDoc.MaxCol(), aDestArea.nRowEnd, nTab,
+ InsertDeleteFlags::ALL, false, rDoc);
+
+ // Original range
+ if (xUndoData)
+ {
+ rDoc.DeleteAreaTab(aOldRange, InsertDeleteFlags::ALL);
+ xUndoDoc->CopyToDocument(aOldRange, InsertDeleteFlags::ALL, false, rDoc);
+ }
+
+ pDocShell->PostPaint( 0,aDestArea.nRowStart,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab,
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Size );
+ }
+ else
+ {
+ rDoc.DeleteAreaTab( aDestArea.nColStart,aDestArea.nRowStart,
+ aDestArea.nColEnd,aDestArea.nRowEnd, nTab, InsertDeleteFlags::ALL );
+ xUndoDoc->CopyToDocument(aDestArea.nColStart, aDestArea.nRowStart, nTab,
+ aDestArea.nColEnd, aDestArea.nRowEnd, nTab,
+ InsertDeleteFlags::ALL, false, rDoc);
+
+ // Original range
+ if (xUndoData)
+ {
+ rDoc.DeleteAreaTab(aOldRange, InsertDeleteFlags::ALL);
+ xUndoDoc->CopyToDocument(aOldRange, InsertDeleteFlags::ALL, false, rDoc);
+ }
+
+ SCCOL nEndX = aDestArea.nColEnd;
+ SCROW nEndY = aDestArea.nRowEnd;
+ if (xUndoData)
+ {
+ if ( aOldRange.aEnd.Col() > nEndX )
+ nEndX = aOldRange.aEnd.Col();
+ if ( aOldRange.aEnd.Row() > nEndY )
+ nEndY = aOldRange.aEnd.Row();
+ }
+ pDocShell->PostPaint( aDestArea.nColStart, aDestArea.nRowStart, nTab,
+ nEndX, nEndY, nTab, PaintPartFlags::Grid );
+ }
+
+ // Adjust Database range again
+ if (xUndoData)
+ {
+ ScDBCollection* pColl = rDoc.GetDBCollection();
+ if (pColl)
+ {
+ ScDBData* pDocData = pColl->getNamedDBs().findByUpperName(xUndoData->GetUpperName());
+ if (pDocData)
+ *pDocData = *xUndoData;
+ }
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ SCTAB nViewTab = pViewShell->GetViewData().GetTabNo();
+ if ( nViewTab != nTab )
+ pViewShell->SetTabNo( nTab );
+ }
+
+ EndUndo();
+}
+
+void ScUndoConsolidate::Redo()
+{
+ BeginRedo();
+
+ pDocShell->DoConsolidate( aParam, false );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ SCTAB nViewTab = pViewShell->GetViewData().GetTabNo();
+ if ( nViewTab != aParam.nTab )
+ pViewShell->SetTabNo( aParam.nTab );
+ }
+
+ EndRedo();
+}
+
+void ScUndoConsolidate::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoConsolidate::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+// Change source data of Chart
+void ScUndoChartData::Init()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ aOldRangeListRef = new ScRangeList;
+ rDoc.GetOldChartParameters( aChartName, *aOldRangeListRef, bOldColHeaders, bOldRowHeaders );
+}
+
+ScUndoChartData::ScUndoChartData( ScDocShell* pNewDocShell, const OUString& rName,
+ const ScRange& rNew, bool bColHdr, bool bRowHdr,
+ bool bAdd ) :
+ ScSimpleUndo( pNewDocShell ),
+ aChartName( rName ),
+ bOldColHeaders(false),
+ bOldRowHeaders(false),
+ bNewColHeaders( bColHdr ),
+ bNewRowHeaders( bRowHdr ),
+ bAddRange( bAdd )
+{
+ aNewRangeListRef = new ScRangeList;
+ aNewRangeListRef->push_back( rNew );
+
+ Init();
+}
+
+ScUndoChartData::ScUndoChartData( ScDocShell* pNewDocShell, const OUString& rName,
+ const ScRangeListRef& rNew, bool bColHdr, bool bRowHdr,
+ bool bAdd ) :
+ ScSimpleUndo( pNewDocShell ),
+ aChartName( rName ),
+ bOldColHeaders(false),
+ bOldRowHeaders(false),
+ aNewRangeListRef( rNew ),
+ bNewColHeaders( bColHdr ),
+ bNewRowHeaders( bRowHdr ),
+ bAddRange( bAdd )
+{
+ Init();
+}
+
+ScUndoChartData::~ScUndoChartData()
+{
+}
+
+OUString ScUndoChartData::GetComment() const
+{
+ return ScResId( STR_UNDO_CHARTDATA );
+}
+
+void ScUndoChartData::Undo()
+{
+ BeginUndo();
+
+ pDocShell->GetDocument().UpdateChartArea( aChartName, aOldRangeListRef,
+ bOldColHeaders, bOldRowHeaders, false );
+
+ EndUndo();
+}
+
+void ScUndoChartData::Redo()
+{
+ BeginRedo();
+
+ pDocShell->GetDocument().UpdateChartArea( aChartName, aNewRangeListRef,
+ bNewColHeaders, bNewRowHeaders, bAddRange );
+
+ EndRedo();
+}
+
+void ScUndoChartData::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoChartData::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoDataForm::ScUndoDataForm( ScDocShell* pNewDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ,
+ const ScMarkData& rMark,
+ ScDocumentUniquePtr pNewUndoDoc, ScDocumentUniquePtr pNewRedoDoc,
+ std::unique_ptr<ScRefUndoData> pRefData )
+ : ScBlockUndo(pNewDocShell, ScRange( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ ), SC_UNDO_SIMPLE)
+ , mxMarkData(new ScMarkData(rMark))
+ , xUndoDoc(std::move(pNewUndoDoc))
+ , xRedoDoc(std::move(pNewRedoDoc))
+ , xRefUndoData(std::move(pRefData))
+ , bRedoFilled(false)
+{
+ // pFill1,pFill2,pFill3 are there so the ctor calls for simple paste (without cutting)
+ // don't have to be changed and branched for 641.
+ // They can be removed later.
+
+ if (!mxMarkData->IsMarked()) // no cell marked:
+ mxMarkData->SetMarkArea(aBlockRange); // mark paste block
+
+ if (xRefUndoData)
+ xRefUndoData->DeleteUnchanged(&pDocShell->GetDocument());
+}
+
+OUString ScUndoDataForm::GetComment() const
+{
+ return ScResId( STR_UNDO_PASTE );
+}
+
+void ScUndoDataForm::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ ShowTable( aBlockRange );
+ EndUndo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoDataForm::Redo()
+{
+ BeginRedo();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ EnableDrawAdjust( &rDoc, false ); //! include in ScBlockUndo?
+ DoChange( false );
+ EnableDrawAdjust( &rDoc, true ); //! include in ScBlockUndo?
+ EndRedo();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+void ScUndoDataForm::Repeat(SfxRepeatTarget& /*rTarget*/)
+{
+}
+
+bool ScUndoDataForm::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return (dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr);
+}
+
+void ScUndoDataForm::DoChange( const bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // RefUndoData for redo is created before first undo
+ // (with DeleteUnchanged after the DoUndo call)
+ bool bCreateRedoData = (bUndo && xRefUndoData && !xRefRedoData);
+ if (bCreateRedoData)
+ xRefRedoData.reset(new ScRefUndoData(&rDoc));
+
+ ScRefUndoData* pWorkRefData = bUndo ? xRefUndoData.get() : xRefRedoData.get();
+
+ bool bPaintAll = false;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ if ( bUndo && !bRedoFilled )
+ {
+ if (!xRedoDoc)
+ {
+ bool bColInfo = ( aBlockRange.aStart.Row()==0 && aBlockRange.aEnd.Row()==rDoc.MaxRow() );
+ bool bRowInfo = ( aBlockRange.aStart.Col()==0 && aBlockRange.aEnd.Col()==rDoc.MaxCol() );
+
+ xRedoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ xRedoDoc->InitUndoSelected(rDoc, *mxMarkData, bColInfo, bRowInfo);
+ }
+ // read "redo" data from the document in the first undo
+ // all sheets - CopyToDocument skips those that don't exist in pRedoDoc
+ ScRange aCopyRange = aBlockRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument(aCopyRange, InsertDeleteFlags::VALUE, false, *xRedoDoc);
+ bRedoFilled = true;
+ }
+
+ sal_uInt16 nExtFlags = 0;
+ pDocShell->UpdatePaintExt( nExtFlags, aBlockRange );
+
+ for ( sal_uInt16 i=0; i <= ( aBlockRange.aEnd.Col() - aBlockRange.aStart.Col() ); i++ )
+ {
+ OUString aOldString = xUndoDoc->GetString(
+ aBlockRange.aStart.Col()+i, aBlockRange.aStart.Row(), aBlockRange.aStart.Tab());
+ rDoc.SetString( aBlockRange.aStart.Col()+i , aBlockRange.aStart.Row() , aBlockRange.aStart.Tab() , aOldString );
+ }
+
+ if (pWorkRefData)
+ {
+ pWorkRefData->DoUndo( &rDoc, true ); // TRUE = bSetChartRangeLists for SetChartListenerCollection
+ if ( rDoc.RefreshAutoFilter( 0,0, rDoc.MaxCol(),rDoc.MaxRow(), aBlockRange.aStart.Tab() ) )
+ bPaintAll = true;
+ }
+
+ if (bCreateRedoData && xRefRedoData)
+ xRefRedoData->DeleteUnchanged(&rDoc);
+
+ if ( bUndo )
+ {
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( 0, 0 );
+ }
+
+ ScRange aDrawRange( aBlockRange );
+ rDoc.ExtendMerge( aDrawRange, true ); // only needed for single sheet (text/rtf etc.)
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+ if (bPaintAll)
+ {
+ aDrawRange.aStart.SetCol(0);
+ aDrawRange.aStart.SetRow(0);
+ aDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ aDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Top | PaintPartFlags::Left;
+/*A*/ if (pViewShell)
+ pViewShell->AdjustBlockHeight(false);
+ }
+ else
+ {
+ if ( aBlockRange.aStart.Row() == 0 && aBlockRange.aEnd.Row() == rDoc.MaxRow() ) // whole column
+ {
+ nPaint |= PaintPartFlags::Top;
+ aDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ }
+ if ( aBlockRange.aStart.Col() == 0 && aBlockRange.aEnd.Col() == rDoc.MaxCol() ) // whole row
+ {
+ nPaint |= PaintPartFlags::Left;
+ aDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ }
+/*A*/ if (pViewShell && pViewShell->AdjustBlockHeight(false))
+ {
+ aDrawRange.aStart.SetCol(0);
+ aDrawRange.aStart.SetRow(0);
+ aDrawRange.aEnd.SetCol(rDoc.MaxCol());
+ aDrawRange.aEnd.SetRow(rDoc.MaxRow());
+ nPaint |= PaintPartFlags::Left;
+ }
+ pDocShell->UpdatePaintExt( nExtFlags, aDrawRange );
+ }
+
+ if ( !bUndo ) // draw redo after updating row heights
+ RedoSdrUndoAction( pDrawUndo.get() ); //! include in ScBlockUndo?
+
+ pDocShell->PostPaint( aDrawRange, nPaint, nExtFlags );
+
+ pDocShell->PostDataChanged();
+ if (pViewShell)
+ pViewShell->CellContentChanged();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undodraw.cxx b/sc/source/ui/undo/undodraw.cxx
new file mode 100644
index 000000000..7204f1643
--- /dev/null
+++ b/sc/source/ui/undo/undodraw.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 <undodraw.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+
+
+ScUndoDraw::ScUndoDraw( std::unique_ptr<SfxUndoAction> pUndo, ScDocShell* pDocSh ) :
+ pDrawUndo( std::move(pUndo) ),
+ pDocShell( pDocSh ),
+ mnViewShellId( -1 )
+{
+ if (ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell())
+ mnViewShellId = pViewShell->GetViewShellId();
+}
+
+ScUndoDraw::~ScUndoDraw()
+{
+}
+
+OUString ScUndoDraw::GetComment() const
+{
+ if (pDrawUndo)
+ return pDrawUndo->GetComment();
+ return OUString();
+}
+
+ViewShellId ScUndoDraw::GetViewShellId() const
+{
+ return mnViewShellId;
+}
+
+OUString ScUndoDraw::GetRepeatComment(SfxRepeatTarget& rTarget) const
+{
+ if (pDrawUndo)
+ return pDrawUndo->GetRepeatComment(rTarget);
+ return OUString();
+}
+
+bool ScUndoDraw::Merge( SfxUndoAction* pNextAction )
+{
+ if (pDrawUndo)
+ return pDrawUndo->Merge(pNextAction);
+ else
+ return false;
+}
+
+void ScUndoDraw::UpdateSubShell()
+{
+ // #i26822# remove the draw shell if the selected object has been removed
+ ScTabViewShell* pViewShell = pDocShell->GetBestViewShell();
+ if (pViewShell)
+ pViewShell->UpdateDrawShell();
+}
+
+void ScUndoDraw::Undo()
+{
+ if (pDrawUndo)
+ {
+ pDrawUndo->Undo();
+ pDocShell->SetDrawModified();
+ UpdateSubShell();
+ }
+}
+
+void ScUndoDraw::Redo()
+{
+ if (pDrawUndo)
+ {
+ pDrawUndo->Redo();
+ pDocShell->SetDrawModified();
+ UpdateSubShell();
+ }
+}
+
+void ScUndoDraw::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (pDrawUndo)
+ pDrawUndo->Repeat(rTarget);
+}
+
+bool ScUndoDraw::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ if (pDrawUndo)
+ return pDrawUndo->CanRepeat(rTarget);
+ else
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undoolk.cxx b/sc/source/ui/undo/undoolk.cxx
new file mode 100644
index 000000000..519ae20a7
--- /dev/null
+++ b/sc/source/ui/undo/undoolk.cxx
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdundo.hxx>
+
+#include <document.hxx>
+#include <drwlayer.hxx>
+#include <undoolk.hxx>
+
+std::unique_ptr<SdrUndoAction> GetSdrUndoAction(ScDocument* pDoc)
+{
+ ScDrawLayer* pLayer = pDoc->GetDrawLayer();
+ if (pLayer)
+ return pLayer->GetCalcUndo(); // must exist
+ else
+ return nullptr;
+}
+
+void DoSdrUndoAction(SdrUndoAction* pUndoAction, ScDocument* pDoc)
+{
+ if (pUndoAction)
+ pUndoAction->Undo();
+ else
+ {
+ // if no drawing layer existed when the action was created,
+ // but it was created after that, there is no draw undo action,
+ // and after undo there might be a drawing layer with a wrong page count.
+ // The drawing layer must have been empty in that case, so any missing
+ // pages can just be created now.
+
+ ScDrawLayer* pDrawLayer = pDoc->GetDrawLayer();
+ if (pDrawLayer)
+ {
+ SCTAB nTabCount = pDoc->GetTableCount();
+ SCTAB nPages = static_cast<SCTAB>(pDrawLayer->GetPageCount());
+ while (nPages < nTabCount)
+ {
+ pDrawLayer->ScAddPage(nPages);
+ ++nPages;
+ }
+ }
+ }
+}
+
+void RedoSdrUndoAction(SdrUndoAction* pUndoAction)
+{
+ // DoSdrUndoAction/RedoSdrUndoAction is called even if the pointer is null
+ if (pUndoAction)
+ pUndoAction->Redo();
+}
+
+void EnableDrawAdjust(ScDocument* pDoc, bool bEnable)
+{
+ ScDrawLayer* pLayer = pDoc->GetDrawLayer();
+ if (pLayer)
+ pLayer->EnableAdjust(bEnable);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undorangename.cxx b/sc/source/ui/undo/undorangename.cxx
new file mode 100644
index 000000000..1b9efafae
--- /dev/null
+++ b/sc/source/ui/undo/undorangename.cxx
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <undorangename.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <sfx2/app.hxx>
+
+#include <memory>
+#include <utility>
+
+using ::std::unique_ptr;
+
+ScUndoAllRangeNames::ScUndoAllRangeNames(
+ ScDocShell* pDocSh,
+ const std::map<OUString, ScRangeName*>& rOldNames,
+ const std::map<OUString, std::unique_ptr<ScRangeName>>& rNewNames)
+ : ScSimpleUndo(pDocSh)
+{
+ for (const auto& [rName, pRangeName] : rOldNames)
+ {
+ m_OldNames.insert(std::make_pair(rName, std::make_unique<ScRangeName>(*pRangeName)));
+ }
+
+ for (auto const& it : rNewNames)
+ {
+ m_NewNames.insert(std::make_pair(it.first, std::make_unique<ScRangeName>(*it.second)));
+ }
+}
+
+ScUndoAllRangeNames::~ScUndoAllRangeNames()
+{
+}
+
+void ScUndoAllRangeNames::Undo()
+{
+ DoChange(m_OldNames);
+}
+
+void ScUndoAllRangeNames::Redo()
+{
+ DoChange(m_NewNames);
+}
+
+void ScUndoAllRangeNames::Repeat(SfxRepeatTarget& /*rTarget*/)
+{
+}
+
+bool ScUndoAllRangeNames::CanRepeat(SfxRepeatTarget& /*rTarget*/) const
+{
+ return false;
+}
+
+OUString ScUndoAllRangeNames::GetComment() const
+{
+ return ScResId(STR_UNDO_RANGENAMES);
+}
+
+void ScUndoAllRangeNames::DoChange(const std::map<OUString, std::unique_ptr<ScRangeName>>& rNames)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.PreprocessAllRangeNamesUpdate(rNames);
+ rDoc.SetAllRangeNames(rNames);
+ rDoc.CompileHybridFormula();
+
+ SfxGetpApp()->Broadcast(SfxHint(SfxHintId::ScAreasChanged));
+}
+
+ScUndoAddRangeData::ScUndoAddRangeData(ScDocShell* pDocSh, const ScRangeData* pRangeData, SCTAB nTab) :
+ ScSimpleUndo(pDocSh),
+ mpRangeData(new ScRangeData(*pRangeData)),
+ mnTab(nTab)
+{
+
+}
+
+ScUndoAddRangeData::~ScUndoAddRangeData()
+{
+}
+
+void ScUndoAddRangeData::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangeName* pRangeName = nullptr;
+ if (mnTab == -1)
+ {
+ pRangeName = rDoc.GetRangeName();
+ }
+ else
+ {
+ pRangeName = rDoc.GetRangeName( mnTab );
+ }
+ pRangeName->erase(*mpRangeData);
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+
+}
+
+void ScUndoAddRangeData::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangeName* pRangeName = nullptr;
+ if (mnTab == -1)
+ {
+ pRangeName = rDoc.GetRangeName();
+ }
+ else
+ {
+ pRangeName = rDoc.GetRangeName( mnTab );
+ }
+ pRangeName->insert(new ScRangeData(*mpRangeData));
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+}
+
+void ScUndoAddRangeData::Repeat(SfxRepeatTarget& /*rTarget*/)
+{
+}
+
+bool ScUndoAddRangeData::CanRepeat(SfxRepeatTarget& /*rTarget*/) const
+{
+ return false;
+}
+
+OUString ScUndoAddRangeData::GetComment() const
+{
+ return ScResId(STR_UNDO_RANGENAMES);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undosort.cxx b/sc/source/ui/undo/undosort.cxx
new file mode 100644
index 000000000..ed65c760e
--- /dev/null
+++ b/sc/source/ui/undo/undosort.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/.
+ */
+
+#include <undosort.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <undoutil.hxx>
+
+namespace sc {
+
+UndoSort::UndoSort( ScDocShell* pDocSh, const ReorderParam& rParam ) :
+ ScSimpleUndo(pDocSh), maParam(rParam) {}
+
+OUString UndoSort::GetComment() const
+{
+ return ScResId(STR_UNDO_SORT);
+}
+
+void UndoSort::Undo()
+{
+ BeginUndo();
+ Execute(true);
+ EndUndo();
+}
+
+void UndoSort::Redo()
+{
+ BeginRedo();
+ Execute(false);
+ EndRedo();
+}
+
+void UndoSort::Execute( bool bUndo )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sc::ReorderParam aParam = maParam;
+ if (bUndo)
+ aParam.reverse();
+ rDoc.Reorder(aParam);
+
+ ScRange aOverallRange( maParam.maSortRange);
+ if (maParam.maDataAreaExtras.anyExtrasWanted())
+ {
+ aOverallRange.aStart.SetCol( maParam.maDataAreaExtras.mnStartCol);
+ aOverallRange.aStart.SetRow( maParam.maDataAreaExtras.mnStartRow);
+ aOverallRange.aEnd.SetCol( maParam.maDataAreaExtras.mnEndCol);
+ aOverallRange.aEnd.SetRow( maParam.maDataAreaExtras.mnEndRow);
+ }
+
+ if (maParam.mbHasHeaders)
+ {
+ ScRange aMarkRange( aOverallRange);
+ if (maParam.mbByRow)
+ {
+ if (aMarkRange.aStart.Row() > 0)
+ aMarkRange.aStart.IncRow(-1);
+ }
+ else
+ {
+ if (aMarkRange.aStart.Col() > 0)
+ aMarkRange.aStart.IncCol(-1);
+ }
+ ScUndoUtil::MarkSimpleBlock(pDocShell, aMarkRange);
+ }
+ else
+ {
+ ScUndoUtil::MarkSimpleBlock(pDocShell, aOverallRange);
+ }
+
+ rDoc.SetDirty(maParam.maSortRange, true);
+ if (!aParam.mbUpdateRefs)
+ rDoc.BroadcastCells(aParam.maSortRange, SfxHintId::ScDataChanged);
+
+ pDocShell->PostPaint(aOverallRange, PaintPartFlags::Grid);
+ pDocShell->PostDataChanged();
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undostyl.cxx b/sc/source/ui/undo/undostyl.cxx
new file mode 100644
index 000000000..b0c17277a
--- /dev/null
+++ b/sc/source/ui/undo/undostyl.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 <svl/itemset.hxx>
+#include <vcl/virdev.hxx>
+#include <osl/diagnose.h>
+
+#include <undostyl.hxx>
+#include <docsh.hxx>
+#include <docpool.hxx>
+#include <stlpool.hxx>
+#include <printfun.hxx>
+#include <scmod.hxx>
+#include <inputhdl.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+// modify style (cell or page style)
+
+ScStyleSaveData::ScStyleSaveData()
+{
+}
+
+ScStyleSaveData::ScStyleSaveData( const ScStyleSaveData& rOther ) :
+ aName( rOther.aName ),
+ aParent( rOther.aParent )
+{
+ if (rOther.moItems)
+ moItems.emplace(*rOther.moItems);
+}
+
+ScStyleSaveData& ScStyleSaveData::operator=( const ScStyleSaveData& rOther )
+{
+ if (this != &rOther)
+ {
+ aName = rOther.aName;
+ aParent = rOther.aParent;
+ if (rOther.moItems)
+ moItems.emplace(*rOther.moItems);
+ else
+ moItems.reset();
+ }
+ return *this;
+}
+
+void ScStyleSaveData::InitFromStyle( const SfxStyleSheetBase* pSource )
+{
+ if ( pSource )
+ {
+ aName = pSource->GetName();
+ aParent = pSource->GetParent();
+ moItems.emplace(const_cast<SfxStyleSheetBase*>(pSource)->GetItemSet());
+ }
+ else
+ {
+ aName.clear();
+ aParent.clear();
+ moItems.reset();
+ }
+}
+
+ScUndoModifyStyle::ScUndoModifyStyle( ScDocShell* pDocSh, SfxStyleFamily eFam,
+ const ScStyleSaveData& rOld, const ScStyleSaveData& rNew ) :
+ ScSimpleUndo( pDocSh ),
+ eFamily( eFam ),
+ aOldData( rOld ),
+ aNewData( rNew )
+{
+}
+
+ScUndoModifyStyle::~ScUndoModifyStyle()
+{
+}
+
+OUString ScUndoModifyStyle::GetComment() const
+{
+ TranslateId pId = (eFamily == SfxStyleFamily::Para) ?
+ STR_UNDO_EDITCELLSTYLE :
+ STR_UNDO_EDITPAGESTYLE;
+ return ScResId(pId);
+}
+
+static void lcl_DocStyleChanged( ScDocument* pDoc, const SfxStyleSheetBase* pStyle, bool bRemoved )
+{
+ //! move to document or docshell
+
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Point aLogic = pVDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
+ double nPPTX = aLogic.X() / 1000.0;
+ double nPPTY = aLogic.Y() / 1000.0;
+ Fraction aZoom(1,1);
+ pDoc->StyleSheetChanged( pStyle, bRemoved, pVDev, nPPTX, nPPTY, aZoom, aZoom );
+
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if (pHdl)
+ pHdl->ForgetLastPattern();
+}
+
+void ScUndoModifyStyle::DoChange( ScDocShell* pDocSh, const OUString& rName,
+ SfxStyleFamily eStyleFamily, const ScStyleSaveData& rData )
+{
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScStyleSheetPool* pStlPool = rDoc.GetStyleSheetPool();
+ const OUString& aNewName = rData.GetName();
+ bool bDelete = aNewName.isEmpty(); // no new name -> delete style
+ bool bNew = ( rName.isEmpty() && !bDelete ); // creating new style
+
+ SfxStyleSheetBase* pStyle = nullptr;
+ if ( !rName.isEmpty() )
+ {
+ // find old style to modify
+ pStyle = pStlPool->Find( rName, eStyleFamily );
+ OSL_ENSURE( pStyle, "style not found" );
+
+ if ( pStyle && !bDelete )
+ {
+ // set new name
+ pStyle->SetName( aNewName );
+ }
+ }
+ else if ( !bDelete )
+ {
+ // create style (with new name)
+ pStyle = &pStlPool->Make( aNewName, eStyleFamily, SfxStyleSearchBits::UserDefined );
+
+ if ( eStyleFamily == SfxStyleFamily::Para )
+ rDoc.GetPool()->CellStyleCreated( aNewName, rDoc );
+ }
+
+ if ( pStyle )
+ {
+ if ( bDelete )
+ {
+ if ( eStyleFamily == SfxStyleFamily::Para )
+ lcl_DocStyleChanged( &rDoc, pStyle, true ); // TRUE: remove usage of style
+ else
+ rDoc.RemovePageStyleInUse( rName );
+
+ // delete style
+ pStlPool->Remove( pStyle );
+ }
+ else
+ {
+ // modify style
+
+ const OUString& aNewParent = rData.GetParent();
+ if ( aNewParent != pStyle->GetParent() )
+ pStyle->SetParent( aNewParent );
+
+ SfxItemSet& rStyleSet = pStyle->GetItemSet();
+ const std::optional<SfxItemSet>& pNewSet = rData.GetItems();
+ OSL_ENSURE( pNewSet, "no ItemSet for style" );
+ if (pNewSet)
+ rStyleSet.Set( *pNewSet, false );
+
+ if ( eStyleFamily == SfxStyleFamily::Para )
+ {
+ lcl_DocStyleChanged( &rDoc, pStyle, false ); // cell styles: row heights
+ }
+ else
+ {
+ // page styles
+
+ if ( bNew && aNewName != rName )
+ rDoc.RenamePageStyleInUse( rName, aNewName );
+
+ if (pNewSet)
+ rDoc.ModifyStyleSheet( *pStyle, *pNewSet );
+
+ pDocSh->PageStyleModified( aNewName, true );
+ }
+ }
+ }
+
+ pDocSh->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+
+ //! undo/redo document modifications for deleted styles
+ //! undo/redo modifications of number formatter
+}
+
+void ScUndoModifyStyle::Undo()
+{
+ BeginUndo();
+ DoChange( pDocShell, aNewData.GetName(), eFamily, aOldData );
+ EndUndo();
+}
+
+void ScUndoModifyStyle::Redo()
+{
+ BeginRedo();
+ DoChange( pDocShell, aOldData.GetName(), eFamily, aNewData );
+ EndRedo();
+}
+
+void ScUndoModifyStyle::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoModifyStyle::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // no repeat possible
+}
+
+// apply page style
+
+ScUndoApplyPageStyle::ApplyStyleEntry::ApplyStyleEntry( SCTAB nTab, const OUString& rOldStyle ) :
+ mnTab( nTab ),
+ maOldStyle( rOldStyle )
+{
+}
+
+ScUndoApplyPageStyle::ScUndoApplyPageStyle( ScDocShell* pDocSh, const OUString& rNewStyle ) :
+ ScSimpleUndo( pDocSh ),
+ maNewStyle( rNewStyle )
+{
+}
+
+ScUndoApplyPageStyle::~ScUndoApplyPageStyle()
+{
+}
+
+void ScUndoApplyPageStyle::AddSheetAction( SCTAB nTab, const OUString& rOldStyle )
+{
+ maEntries.emplace_back( nTab, rOldStyle );
+}
+
+OUString ScUndoApplyPageStyle::GetComment() const
+{
+ return ScResId( STR_UNDO_APPLYPAGESTYLE );
+}
+
+void ScUndoApplyPageStyle::Undo()
+{
+ BeginUndo();
+ for( const auto& rEntry : maEntries )
+ {
+ pDocShell->GetDocument().SetPageStyle( rEntry.mnTab, rEntry.maOldStyle );
+ ScPrintFunc( pDocShell, pDocShell->GetPrinter(), rEntry.mnTab ).UpdatePages();
+ }
+ EndUndo();
+}
+
+void ScUndoApplyPageStyle::Redo()
+{
+ BeginRedo();
+ for( const auto& rEntry : maEntries )
+ {
+ pDocShell->GetDocument().SetPageStyle( rEntry.mnTab, maNewStyle );
+ ScPrintFunc( pDocShell, pDocShell->GetPrinter(), rEntry.mnTab ).UpdatePages();
+ }
+ EndRedo();
+}
+
+void ScUndoApplyPageStyle::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ //! set same page style to current tab
+}
+
+bool ScUndoApplyPageStyle::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undotab.cxx b/sc/source/ui/undo/undotab.cxx
new file mode 100644
index 000000000..bf9379e78
--- /dev/null
+++ b/sc/source/ui/undo/undotab.cxx
@@ -0,0 +1,1570 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svl/hint.hxx>
+#include <osl/diagnose.h>
+
+#include <undotab.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <globstr.hrc>
+#include <global.hxx>
+#include <sc.hrc>
+#include <strings.hrc>
+#include <undoolk.hxx>
+#include <target.hxx>
+#include <uiitems.hxx>
+#include <prnsave.hxx>
+#include <printfun.hxx>
+#include <chgtrack.hxx>
+#include <tabprotection.hxx>
+#include <viewdata.hxx>
+#include <progress.hxx>
+#include <markdata.hxx>
+#include <refundo.hxx>
+
+// for ScUndoRenameObject - might me moved to another file later
+#include <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <drwlayer.hxx>
+#include <scresid.hxx>
+#include <sheetevents.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <tools/json_writer.hxx>
+
+#include <memory>
+#include <utility>
+#include <vector>
+
+using namespace com::sun::star;
+using ::std::unique_ptr;
+using ::std::vector;
+
+
+ScUndoInsertTab::ScUndoInsertTab( ScDocShell* pNewDocShell,
+ SCTAB nTabNum,
+ bool bApp,
+ const OUString& rNewName) :
+ ScSimpleUndo( pNewDocShell ),
+ sNewName( rNewName ),
+ nTab( nTabNum ),
+ bAppend( bApp )
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+ SetChangeTrack();
+}
+
+ScUndoInsertTab::~ScUndoInsertTab()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoInsertTab::GetComment() const
+{
+ if (bAppend)
+ return ScResId( STR_UNDO_APPEND_TAB );
+ else
+ return ScResId( STR_UNDO_INSERT_TAB );
+}
+
+void ScUndoInsertTab::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ ScRange aRange( 0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab );
+ pChangeTrack->AppendInsert( aRange );
+ nEndChangeAction = pChangeTrack->GetActionMax();
+ }
+ else
+ nEndChangeAction = 0;
+}
+
+void ScUndoInsertTab::Undo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ pViewShell->SetTabNo(nTab);
+
+ pDocShell->SetInUndo( true ); //! BeginUndo
+ bDrawIsInUndo = true;
+ pViewShell->DeleteTable( nTab, false );
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false ); //! EndUndo
+
+ DoSdrUndoAction( pDrawUndo.get(), &pDocShell->GetDocument() );
+
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nEndChangeAction, nEndChangeAction );
+
+ // SetTabNo(...,sal_True) for all views to sync with drawing layer pages
+ pDocShell->Broadcast( SfxHint( SfxHintId::ScForceSetTab ) );
+}
+
+void ScUndoInsertTab::Redo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // Draw Redo first
+
+ pDocShell->SetInUndo( true ); //! BeginRedo
+ bDrawIsInUndo = true;
+ if (bAppend)
+ pViewShell->AppendTable( sNewName, false );
+ else
+ {
+ pViewShell->SetTabNo(nTab);
+ pViewShell->InsertTable( sNewName, nTab, false );
+ }
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false ); //! EndRedo
+
+ SetChangeTrack();
+}
+
+void ScUndoInsertTab::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->GetViewData().GetDispatcher().
+ Execute(FID_INS_TABLE, SfxCallMode::SLOT | SfxCallMode::RECORD);
+}
+
+bool ScUndoInsertTab::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoInsertTables::ScUndoInsertTables( ScDocShell* pNewDocShell,
+ SCTAB nTabNum,
+ std::vector<OUString>&& newNameList) :
+ ScSimpleUndo( pNewDocShell ),
+ aNameList( std::move(newNameList) ),
+ nTab( nTabNum )
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+
+ SetChangeTrack();
+}
+
+ScUndoInsertTables::~ScUndoInsertTables()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoInsertTables::GetComment() const
+{
+ return ScResId( STR_UNDO_INSERT_TAB );
+}
+
+void ScUndoInsertTables::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ nStartChangeAction = pChangeTrack->GetActionMax() + 1;
+ nEndChangeAction = 0;
+ ScRange aRange( 0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab );
+ for( size_t i = 0; i < aNameList.size(); i++ )
+ {
+ aRange.aStart.SetTab( sal::static_int_cast<SCTAB>( nTab + i ) );
+ aRange.aEnd.SetTab( sal::static_int_cast<SCTAB>( nTab + i ) );
+ pChangeTrack->AppendInsert( aRange );
+ nEndChangeAction = pChangeTrack->GetActionMax();
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+void ScUndoInsertTables::Undo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ pViewShell->SetTabNo(nTab);
+
+ pDocShell->SetInUndo( true ); //! BeginUndo
+ bDrawIsInUndo = true;
+
+ pViewShell->DeleteTables( nTab, static_cast<SCTAB>(aNameList.size()) );
+
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false ); //! EndUndo
+
+ DoSdrUndoAction( pDrawUndo.get(), &pDocShell->GetDocument() );
+
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ // SetTabNo(...,sal_True) for all views to sync with drawing layer pages
+ pDocShell->Broadcast( SfxHint( SfxHintId::ScForceSetTab ) );
+}
+
+void ScUndoInsertTables::Redo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // Draw Redo first
+
+ pDocShell->SetInUndo( true ); //! BeginRedo
+ bDrawIsInUndo = true;
+ pViewShell->InsertTables( aNameList, nTab, static_cast<SCTAB>(aNameList.size()),false );
+
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false ); //! EndRedo
+
+ SetChangeTrack();
+}
+
+void ScUndoInsertTables::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->GetViewData().GetDispatcher().
+ Execute(FID_INS_TABLE, SfxCallMode::SLOT | SfxCallMode::RECORD);
+}
+
+bool ScUndoInsertTables::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoDeleteTab::ScUndoDeleteTab( ScDocShell* pNewDocShell, const vector<SCTAB> &aTab,
+ ScDocumentUniquePtr pUndoDocument, std::unique_ptr<ScRefUndoData> pRefData ) :
+ ScMoveUndo( pNewDocShell, std::move(pUndoDocument), std::move(pRefData) )
+{
+ theTabs.insert(theTabs.end(), aTab.begin(), aTab.end() );
+ SetChangeTrack();
+}
+
+ScUndoDeleteTab::~ScUndoDeleteTab()
+{
+ theTabs.clear();
+}
+
+OUString ScUndoDeleteTab::GetComment() const
+{
+ return ScResId( STR_UNDO_DELETE_TAB );
+}
+
+void ScUndoDeleteTab::SetChangeTrack()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ {
+ sal_uLong nTmpChangeAction;
+ nStartChangeAction = pChangeTrack->GetActionMax() + 1;
+ nEndChangeAction = 0;
+ ScRange aRange( 0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), 0 );
+ for ( size_t i = 0; i < theTabs.size(); ++i )
+ {
+ aRange.aStart.SetTab( theTabs[i] );
+ aRange.aEnd.SetTab( theTabs[i] );
+ pChangeTrack->AppendDeleteRange( aRange, pRefUndoDoc.get(),
+ nTmpChangeAction, nEndChangeAction, static_cast<short>(i) );
+ }
+ }
+ else
+ nStartChangeAction = nEndChangeAction = 0;
+}
+
+static SCTAB lcl_GetVisibleTabBefore( const ScDocument& rDoc, SCTAB nTab )
+{
+ while ( nTab > 0 && !rDoc.IsVisible( nTab ) )
+ --nTab;
+
+ return nTab;
+}
+
+void ScUndoDeleteTab::Undo()
+{
+ BeginUndo();
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ bool bLink = false;
+ OUString aName;
+
+ for(SCTAB nTab: theTabs)
+ {
+ pRefUndoDoc->GetName( nTab, aName );
+
+ bDrawIsInUndo = true;
+ bool bOk = rDoc.InsertTab(nTab, aName, false, true);
+ bDrawIsInUndo = false;
+ if (bOk)
+ {
+ pRefUndoDoc->CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::ALL,false, rDoc);
+
+ OUString aOldName;
+ pRefUndoDoc->GetName( nTab, aOldName );
+ rDoc.RenameTab( nTab, aOldName );
+ if (pRefUndoDoc->IsLinked(nTab))
+ {
+ rDoc.SetLink( nTab, pRefUndoDoc->GetLinkMode(nTab), pRefUndoDoc->GetLinkDoc(nTab),
+ pRefUndoDoc->GetLinkFlt(nTab), pRefUndoDoc->GetLinkOpt(nTab),
+ pRefUndoDoc->GetLinkTab(nTab), pRefUndoDoc->GetLinkRefreshDelay(nTab) );
+ bLink = true;
+ }
+
+ if ( pRefUndoDoc->IsScenario(nTab) )
+ {
+ rDoc.SetScenario( nTab, true );
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ pRefUndoDoc->GetScenarioData( nTab, aComment, aColor, nScenFlags );
+ rDoc.SetScenarioData( nTab, aComment, aColor, nScenFlags );
+ bool bActive = pRefUndoDoc->IsActiveScenario( nTab );
+ rDoc.SetActiveScenario( nTab, bActive );
+ }
+ rDoc.SetVisible( nTab, pRefUndoDoc->IsVisible( nTab ) );
+ rDoc.SetTabBgColor( nTab, pRefUndoDoc->GetTabBgColor(nTab) );
+ auto pSheetEvents = pRefUndoDoc->GetSheetEvents( nTab );
+ rDoc.SetSheetEvents( nTab, std::unique_ptr<ScSheetEvents>(pSheetEvents ? new ScSheetEvents(*pSheetEvents) : nullptr) );
+ rDoc.SetLayoutRTL( nTab, pRefUndoDoc->IsLayoutRTL( nTab ) );
+
+ if ( pRefUndoDoc->IsTabProtected( nTab ) )
+ rDoc.SetTabProtection(nTab, pRefUndoDoc->GetTabProtection(nTab));
+ }
+ }
+ if (bLink)
+ {
+ pDocShell->UpdateLinks(); // update Link Manager
+ }
+
+ EndUndo(); // Draw-Undo has to be called before Broadcast!
+
+ ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->Undo( nStartChangeAction, nEndChangeAction );
+
+ for(SCTAB nTab: theTabs)
+ {
+ pDocShell->Broadcast( ScTablesHint( SC_TAB_INSERTED, nTab) );
+ }
+ SfxApplication* pSfxApp = SfxGetpApp(); // Navigator
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+
+ pDocShell->PostPaint(0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::All ); // incl. extras
+
+ // not ShowTable due to SetTabNo(..., sal_True):
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo( lcl_GetVisibleTabBefore( rDoc, theTabs[0] ), true );
+}
+
+void ScUndoDeleteTab::Redo()
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ pViewShell->SetTabNo( lcl_GetVisibleTabBefore( pDocShell->GetDocument(), theTabs.front() ) );
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // Draw Redo first
+
+ pDocShell->SetInUndo( true ); //! BeginRedo
+ bDrawIsInUndo = true;
+ pViewShell->DeleteTables( theTabs, false );
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( true ); //! EndRedo
+
+ SetChangeTrack();
+
+ // SetTabNo(...,sal_True) for all views to sync with drawing layer pages
+ pDocShell->Broadcast( SfxHint( SfxHintId::ScForceSetTab ) );
+}
+
+void ScUndoDeleteTab::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ ScTabViewShell* pViewShell = pViewTarget->GetViewShell();
+ pViewShell->DeleteTable( pViewShell->GetViewData().GetTabNo() );
+ }
+}
+
+bool ScUndoDeleteTab::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRenameTab::ScUndoRenameTab( ScDocShell* pNewDocShell,
+ SCTAB nT,
+ const OUString& rOldName,
+ const OUString& rNewName) :
+ ScSimpleUndo( pNewDocShell ),
+ nTab ( nT )
+{
+ sOldName = rOldName;
+ sNewName = rNewName;
+}
+
+ScUndoRenameTab::~ScUndoRenameTab()
+{
+}
+
+OUString ScUndoRenameTab::GetComment() const
+{
+ return ScResId( STR_UNDO_RENAME_TAB );
+}
+
+void ScUndoRenameTab::DoChange( SCTAB nTabP, const OUString& rName ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.RenameTab( nTabP, rName );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); // Navigator
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) ); // Also Name Box
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostPaintExtras();
+ pDocShell->PostDataChanged();
+
+ // The sheet name might be used in a formula ...
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->UpdateInputHandler();
+}
+
+void ScUndoRenameTab::Undo()
+{
+ DoChange(nTab, sOldName);
+}
+
+void ScUndoRenameTab::Redo()
+{
+ DoChange(nTab, sNewName);
+}
+
+void ScUndoRenameTab::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoRenameTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoMoveTab::ScUndoMoveTab(
+ ScDocShell* pNewDocShell, std::unique_ptr<vector<SCTAB>> pOldTabs, std::unique_ptr<vector<SCTAB>> pNewTabs,
+ std::unique_ptr<vector<OUString>> pOldNames, std::unique_ptr<vector<OUString>> pNewNames) :
+ ScSimpleUndo( pNewDocShell ),
+ mpOldTabs(std::move(pOldTabs)), mpNewTabs(std::move(pNewTabs)),
+ mpOldNames(std::move(pOldNames)), mpNewNames(std::move(pNewNames))
+{
+ // The sizes differ. Something is wrong.
+ assert(!mpOldNames || mpOldTabs->size() == mpOldNames->size());
+ // The sizes differ. Something is wrong.
+ assert(!mpNewNames || mpNewTabs->size() == mpNewNames->size());
+}
+
+ScUndoMoveTab::~ScUndoMoveTab()
+{
+}
+
+OUString ScUndoMoveTab::GetComment() const
+{
+ return ScResId( STR_UNDO_MOVE_TAB );
+}
+
+void ScUndoMoveTab::DoChange( bool bUndo ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ if (bUndo) // UnDo
+ {
+ size_t i = mpNewTabs->size();
+ ScProgress aProgress(pDocShell, ScResId(STR_UNDO_MOVE_TAB),
+ i * rDoc.GetCodeCount(), true);
+ for (; i > 0; --i)
+ {
+ SCTAB nDestTab = (*mpNewTabs)[i-1];
+ SCTAB nOldTab = (*mpOldTabs)[i-1];
+ if (nDestTab > MAXTAB) // appended ?
+ nDestTab = rDoc.GetTableCount() - 1;
+
+ rDoc.MoveTab( nDestTab, nOldTab, &aProgress );
+ pViewShell->GetViewData().MoveTab( nDestTab, nOldTab );
+ pViewShell->SetTabNo( nOldTab, true );
+ if (mpOldNames)
+ {
+ const OUString& rOldName = (*mpOldNames)[i-1];
+ rDoc.RenameTab(nOldTab, rOldName);
+ }
+ }
+ }
+ else
+ {
+ size_t n = mpNewTabs->size();
+ ScProgress aProgress(pDocShell, ScResId(STR_UNDO_MOVE_TAB),
+ n * rDoc.GetCodeCount(), true);
+ for (size_t i = 0; i < n; ++i)
+ {
+ SCTAB nDestTab = (*mpNewTabs)[i];
+ SCTAB nNewTab = nDestTab;
+ SCTAB nOldTab = (*mpOldTabs)[i];
+ if (nDestTab > MAXTAB) // appended ?
+ nDestTab = rDoc.GetTableCount() - 1;
+
+ rDoc.MoveTab( nOldTab, nNewTab, &aProgress );
+ pViewShell->GetViewData().MoveTab( nOldTab, nNewTab );
+ pViewShell->SetTabNo( nDestTab, true );
+ if (mpNewNames)
+ {
+ const OUString& rNewName = (*mpNewNames)[i];
+ rDoc.RenameTab(nNewTab, rNewName);
+ }
+ }
+ }
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); // Navigator
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostPaintExtras();
+ pDocShell->PostDataChanged();
+}
+
+void ScUndoMoveTab::Undo()
+{
+ DoChange( true );
+}
+
+void ScUndoMoveTab::Redo()
+{
+ DoChange( false );
+}
+
+void ScUndoMoveTab::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // No Repeat ! ? !
+}
+
+bool ScUndoMoveTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoCopyTab::ScUndoCopyTab(
+ ScDocShell* pNewDocShell,
+ std::unique_ptr<vector<SCTAB>> pOldTabs, std::unique_ptr<vector<SCTAB>> pNewTabs,
+ std::unique_ptr<vector<OUString>> pNewNames) :
+ ScSimpleUndo( pNewDocShell ),
+ mpOldTabs(std::move(pOldTabs)),
+ mpNewTabs(std::move(pNewTabs)),
+ mpNewNames(std::move(pNewNames))
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+
+ // The sizes differ. Something is wrong.
+ assert(!mpNewNames || mpNewTabs->size() == mpNewNames->size());
+}
+
+ScUndoCopyTab::~ScUndoCopyTab()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoCopyTab::GetComment() const
+{
+ return ScResId( STR_UNDO_COPY_TAB );
+}
+
+void ScUndoCopyTab::DoChange() const
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ if (pViewShell)
+ pViewShell->SetTabNo((*mpOldTabs)[0],true);
+
+ SfxApplication* pSfxApp = SfxGetpApp(); // Navigator
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->PostPaintExtras();
+ pDocShell->PostDataChanged();
+}
+
+void ScUndoCopyTab::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc ); // before the sheets are deleted
+
+ vector<SCTAB>::const_reverse_iterator itr, itrEnd = mpNewTabs->rend();
+ for (itr = mpNewTabs->rbegin(); itr != itrEnd; ++itr)
+ {
+ SCTAB nDestTab = *itr;
+ if (nDestTab > MAXTAB) // append?
+ nDestTab = rDoc.GetTableCount() - 1;
+
+ bDrawIsInUndo = true;
+ rDoc.DeleteTab(nDestTab);
+ bDrawIsInUndo = false;
+ }
+
+ // ScTablesHint broadcasts after all sheets have been deleted,
+ // so sheets and draw pages are in sync!
+
+ for (itr = mpNewTabs->rbegin(); itr != itrEnd; ++itr)
+ {
+ SCTAB nDestTab = *itr;
+ if (nDestTab > MAXTAB) // append?
+ nDestTab = rDoc.GetTableCount() - 1;
+
+ pDocShell->Broadcast( ScTablesHint( SC_TAB_DELETED, nDestTab ) );
+ }
+
+ DoChange();
+}
+
+void ScUndoCopyTab::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ SCTAB nDestTab = 0;
+ for (size_t i = 0, n = mpNewTabs->size(); i < n; ++i)
+ {
+ nDestTab = (*mpNewTabs)[i];
+ SCTAB nNewTab = nDestTab;
+ SCTAB nOldTab = (*mpOldTabs)[i];
+ if (nDestTab > MAXTAB) // appended ?
+ nDestTab = rDoc.GetTableCount() - 1;
+
+ bDrawIsInUndo = true;
+ rDoc.CopyTab( nOldTab, nNewTab );
+ bDrawIsInUndo = false;
+
+ pViewShell->GetViewData().MoveTab( nOldTab, nNewTab );
+
+ SCTAB nAdjSource = nOldTab;
+ if ( nNewTab <= nOldTab )
+ ++nAdjSource; // new position of source table after CopyTab
+
+ if ( rDoc.IsScenario(nAdjSource) )
+ {
+ rDoc.SetScenario(nNewTab, true );
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ rDoc.GetScenarioData(nAdjSource, aComment, aColor, nScenFlags );
+ rDoc.SetScenarioData(nNewTab, aComment, aColor, nScenFlags );
+ bool bActive = rDoc.IsActiveScenario(nAdjSource);
+ rDoc.SetActiveScenario(nNewTab, bActive );
+ bool bVisible = rDoc.IsVisible(nAdjSource);
+ rDoc.SetVisible(nNewTab,bVisible );
+ }
+
+ if ( rDoc.IsTabProtected( nAdjSource ) )
+ rDoc.CopyTabProtection(nAdjSource, nNewTab);
+
+ if (mpNewNames)
+ {
+ const OUString& rName = (*mpNewNames)[i];
+ rDoc.RenameTab(nNewTab, rName);
+ }
+ }
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // after the sheets are inserted
+
+ pViewShell->SetTabNo( nDestTab, true ); // after draw-undo
+
+ DoChange();
+
+}
+
+void ScUndoCopyTab::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // no Repeat ! ? !
+}
+
+bool ScUndoCopyTab::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoTabColor::ScUndoTabColor(
+ ScDocShell* pNewDocShell, SCTAB nT, const Color& aOTabBgColor, const Color& aNTabBgColor) :
+ ScSimpleUndo( pNewDocShell )
+{
+ ScUndoTabColorInfo aInfo(nT);
+ aInfo.maOldTabBgColor = aOTabBgColor;
+ aInfo.maNewTabBgColor = aNTabBgColor;
+ aTabColorList.push_back(aInfo);
+}
+
+ScUndoTabColor::ScUndoTabColor(
+ ScDocShell* pNewDocShell,
+ ScUndoTabColorInfo::List&& rUndoTabColorList) :
+ ScSimpleUndo(pNewDocShell),
+ aTabColorList(std::move(rUndoTabColorList))
+{
+}
+
+ScUndoTabColor::~ScUndoTabColor()
+{
+}
+
+OUString ScUndoTabColor::GetComment() const
+{
+ if (aTabColorList.size() > 1)
+ return ScResId(STR_UNDO_SET_MULTI_TAB_BG_COLOR);
+ return ScResId(STR_UNDO_SET_TAB_BG_COLOR);
+}
+
+void ScUndoTabColor::DoChange(bool bUndoType) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ size_t nTabColorCount = aTabColorList.size();
+ for (size_t i = 0; i < nTabColorCount; ++i)
+ {
+ const ScUndoTabColorInfo& rTabColor = aTabColorList[i];
+ rDoc.SetTabBgColor(rTabColor.mnTabId,
+ bUndoType ? rTabColor.maOldTabBgColor : rTabColor.maNewTabBgColor);
+ }
+
+ pDocShell->PostPaintExtras();
+ ScDocShellModificator aModificator( *pDocShell );
+ aModificator.SetDocumentModified();
+}
+
+void ScUndoTabColor::Undo()
+{
+ DoChange(true);
+}
+
+void ScUndoTabColor::Redo()
+{
+ DoChange(false);
+}
+
+void ScUndoTabColor::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoTabColor::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoMakeScenario::ScUndoMakeScenario( ScDocShell* pNewDocShell,
+ SCTAB nSrc, SCTAB nDest,
+ const OUString& rN, const OUString& rC,
+ const Color& rCol, ScScenarioFlags nF,
+ const ScMarkData& rMark ) :
+ ScSimpleUndo( pNewDocShell ),
+ mpMarkData(new ScMarkData(rMark)),
+ nSrcTab( nSrc ),
+ nDestTab( nDest ),
+ aName( rN ),
+ aComment( rC ),
+ aColor( rCol ),
+ nFlags( nF )
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScUndoMakeScenario::~ScUndoMakeScenario()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoMakeScenario::GetComment() const
+{
+ return ScResId( STR_UNDO_MAKESCENARIO );
+}
+
+void ScUndoMakeScenario::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ pDocShell->SetInUndo( true );
+ bDrawIsInUndo = true;
+ rDoc.DeleteTab( nDestTab );
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false );
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc );
+
+ pDocShell->PostPaint(0,0,nDestTab,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::All);
+ pDocShell->PostDataChanged();
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo( nSrcTab, true );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+
+ // SetTabNo(...,sal_True) for all views to sync with drawing layer pages
+ pDocShell->Broadcast( SfxHint( SfxHintId::ScForceSetTab ) );
+}
+
+void ScUndoMakeScenario::Redo()
+{
+ SetViewMarkData(*mpMarkData);
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // Draw Redo first
+
+ pDocShell->SetInUndo( true );
+ bDrawIsInUndo = true;
+
+ pDocShell->MakeScenario( nSrcTab, aName, aComment, aColor, nFlags, *mpMarkData, false );
+
+ bDrawIsInUndo = false;
+ pDocShell->SetInUndo( false );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo( nDestTab, true );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+}
+
+void ScUndoMakeScenario::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ {
+ pViewTarget->GetViewShell()->MakeScenario( aName, aComment, aColor, nFlags );
+ }
+}
+
+bool ScUndoMakeScenario::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoImportTab::ScUndoImportTab(ScDocShell* pShell,
+ SCTAB nNewTab, SCTAB nNewCount)
+ : ScSimpleUndo(pShell)
+ , nTab(nNewTab)
+ , nCount(nNewCount)
+{
+ pDrawUndo = GetSdrUndoAction( &pDocShell->GetDocument() );
+}
+
+ScUndoImportTab::~ScUndoImportTab()
+{
+ pDrawUndo.reset();
+}
+
+OUString ScUndoImportTab::GetComment() const
+{
+ return ScResId( STR_UNDO_INSERT_TAB );
+}
+
+void ScUndoImportTab::DoChange() const
+{
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ if (pViewShell)
+ {
+ if(nTab<nTabCount)
+ {
+ pViewShell->SetTabNo(nTab,true);
+ }
+ else
+ {
+ pViewShell->SetTabNo(nTab-1,true);
+ }
+ }
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) ); // Navigator
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB,
+ PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left | PaintPartFlags::Extras );
+}
+
+void ScUndoImportTab::Undo()
+{
+ // Inserted range names, etc.
+
+ SCTAB i;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bMakeRedo = !xRedoDoc;
+ if (bMakeRedo)
+ {
+ xRedoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ xRedoDoc->InitUndo(rDoc, nTab,nTab+nCount-1, true, true);
+
+ OUString aOldName;
+ for (i=0; i<nCount; i++)
+ {
+ SCTAB nTabPos=nTab+i;
+
+ rDoc.CopyToDocument(0,0,nTabPos, rDoc.MaxCol(),rDoc.MaxRow(),nTabPos, InsertDeleteFlags::ALL,false, *xRedoDoc);
+ rDoc.GetName( nTabPos, aOldName );
+ xRedoDoc->RenameTab(nTabPos, aOldName);
+ xRedoDoc->SetTabBgColor(nTabPos, rDoc.GetTabBgColor(nTabPos));
+
+ if ( rDoc.IsScenario(nTabPos) )
+ {
+ xRedoDoc->SetScenario(nTabPos, true);
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ rDoc.GetScenarioData(nTabPos, aComment, aColor, nScenFlags );
+ xRedoDoc->SetScenarioData(nTabPos, aComment, aColor, nScenFlags);
+ bool bActive = rDoc.IsActiveScenario(nTabPos);
+ xRedoDoc->SetActiveScenario(nTabPos, bActive);
+ bool bVisible = rDoc.IsVisible(nTabPos);
+ xRedoDoc->SetVisible(nTabPos, bVisible);
+ }
+
+ if ( rDoc.IsTabProtected( nTabPos ) )
+ xRedoDoc->SetTabProtection(nTabPos, rDoc.GetTabProtection(nTabPos));
+ }
+
+ }
+
+ DoSdrUndoAction( pDrawUndo.get(), &rDoc ); // before the sheets are deleted
+
+ bDrawIsInUndo = true;
+ for (i=0; i<nCount; i++)
+ rDoc.DeleteTab( nTab );
+ bDrawIsInUndo = false;
+
+ DoChange();
+}
+
+void ScUndoImportTab::Redo()
+{
+ if (!xRedoDoc)
+ {
+ OSL_FAIL("Where is my Redo Document?");
+ return;
+ }
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OUString aName;
+ SCTAB i;
+ for (i=0; i<nCount; i++) // first insert all sheets (#63304#)
+ {
+ SCTAB nTabPos=nTab+i;
+ xRedoDoc->GetName(nTabPos, aName);
+ bDrawIsInUndo = true;
+ rDoc.InsertTab(nTabPos,aName);
+ bDrawIsInUndo = false;
+ }
+ for (i=0; i<nCount; i++) // then copy into inserted sheets
+ {
+ SCTAB nTabPos=nTab+i;
+ xRedoDoc->CopyToDocument(0,0,nTabPos, rDoc.MaxCol(),rDoc.MaxRow(),nTabPos, InsertDeleteFlags::ALL,false, rDoc);
+ rDoc.SetTabBgColor(nTabPos, xRedoDoc->GetTabBgColor(nTabPos));
+
+ if (xRedoDoc->IsScenario(nTabPos))
+ {
+ rDoc.SetScenario(nTabPos, true );
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ xRedoDoc->GetScenarioData(nTabPos, aComment, aColor, nScenFlags );
+ rDoc.SetScenarioData(nTabPos, aComment, aColor, nScenFlags );
+ bool bActive = xRedoDoc->IsActiveScenario(nTabPos);
+ rDoc.SetActiveScenario(nTabPos, bActive );
+ bool bVisible = xRedoDoc->IsVisible(nTabPos);
+ rDoc.SetVisible(nTabPos,bVisible );
+ }
+
+ if (xRedoDoc->IsTabProtected(nTabPos))
+ rDoc.SetTabProtection(nTabPos, xRedoDoc->GetTabProtection(nTabPos));
+ }
+
+ RedoSdrUndoAction( pDrawUndo.get() ); // after the sheets are inserted
+
+ DoChange();
+}
+
+void ScUndoImportTab::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->GetViewData().GetDispatcher().
+ Execute(FID_INS_TABLE, SfxCallMode::SLOT | SfxCallMode::RECORD);
+}
+
+bool ScUndoImportTab::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+ScUndoRemoveLink::ScUndoRemoveLink( ScDocShell* pShell, const OUString& rDocName ) :
+ ScSimpleUndo( pShell ),
+ aDocName( rDocName ),
+ nRefreshDelay( 0 ),
+ nCount( 0 )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ pTabs.reset( new SCTAB[nTabCount] );
+ pModes.reset( new ScLinkMode[nTabCount] );
+ pTabNames.reset( new OUString[nTabCount] );
+
+ for (SCTAB i=0; i<nTabCount; i++)
+ {
+ ScLinkMode nMode = rDoc.GetLinkMode(i);
+ if (nMode != ScLinkMode::NONE)
+ if (rDoc.GetLinkDoc(i) == aDocName)
+ {
+ if (!nCount)
+ {
+ aFltName = rDoc.GetLinkFlt(i);
+ aOptions = rDoc.GetLinkOpt(i);
+ nRefreshDelay = rDoc.GetLinkRefreshDelay(i);
+ }
+ else
+ {
+ OSL_ENSURE(aFltName == rDoc.GetLinkFlt(i) &&
+ aOptions == rDoc.GetLinkOpt(i),
+ "different Filter for a Document?");
+ }
+ pTabs[nCount] = i;
+ pModes[nCount] = nMode;
+ pTabNames[nCount] = rDoc.GetLinkTab(i);
+ ++nCount;
+ }
+ }
+}
+
+ScUndoRemoveLink::~ScUndoRemoveLink()
+{
+}
+
+OUString ScUndoRemoveLink::GetComment() const
+{
+ return ScResId( STR_UNDO_REMOVELINK );
+}
+
+void ScUndoRemoveLink::DoChange( bool bLink ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if (bLink) // establish link
+ rDoc.SetLink( pTabs[i], pModes[i], aDocName, aFltName, aOptions, pTabNames[i], nRefreshDelay );
+ else // remove link
+ rDoc.SetLink( pTabs[i], ScLinkMode::NONE, "", "", "", "", 0 );
+ pDocShell->UpdateLinks();
+}
+
+void ScUndoRemoveLink::Undo()
+{
+ DoChange( true );
+}
+
+void ScUndoRemoveLink::Redo()
+{
+ DoChange( false );
+}
+
+void ScUndoRemoveLink::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoRemoveLink::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoShowHideTab::ScUndoShowHideTab( ScDocShell* pShell, std::vector<SCTAB>&& newUndoTabs, bool bNewShow ) :
+ ScSimpleUndo( pShell ),
+ undoTabs( std::move(newUndoTabs) ),
+ bShow( bNewShow )
+{
+}
+
+ScUndoShowHideTab::~ScUndoShowHideTab()
+{
+}
+
+void ScUndoShowHideTab::DoChange( bool bShowP ) const
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+
+ for(const SCTAB& nTab : undoTabs)
+ {
+ rDoc.SetVisible( nTab, bShowP );
+ if (pViewShell)
+ pViewShell->SetTabNo(nTab,true);
+ }
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ pDocShell->SetDocumentModified();
+}
+
+void ScUndoShowHideTab::Undo()
+{
+ DoChange(!bShow);
+}
+
+void ScUndoShowHideTab::Redo()
+{
+ DoChange(bShow);
+}
+
+void ScUndoShowHideTab::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->GetViewData().GetDispatcher().
+ Execute( bShow ? FID_TABLE_SHOW : FID_TABLE_HIDE,
+ SfxCallMode::SLOT | SfxCallMode::RECORD);
+}
+
+bool ScUndoShowHideTab::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+OUString ScUndoShowHideTab::GetComment() const
+{
+ TranslateId pId;
+ if (undoTabs.size() > 1)
+ {
+ pId = bShow ? STR_UNDO_SHOWTABS : STR_UNDO_HIDETABS;
+ }
+ else
+ {
+ pId = bShow ? STR_UNDO_SHOWTAB : STR_UNDO_HIDETAB;
+ }
+
+ return ScResId(pId);
+}
+
+ScUndoDocProtect::ScUndoDocProtect(ScDocShell* pShell, unique_ptr<ScDocProtection> && pProtectSettings) :
+ ScSimpleUndo(pShell),
+ mpProtectSettings(std::move(pProtectSettings))
+{
+}
+
+ScUndoDocProtect::~ScUndoDocProtect()
+{
+}
+
+void ScUndoDocProtect::DoProtect(bool bProtect)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ if (bProtect)
+ {
+ // set protection.
+ unique_ptr<ScDocProtection> pCopy(new ScDocProtection(*mpProtectSettings));
+ pCopy->setProtected(true);
+ rDoc.SetDocProtection(pCopy.get());
+ }
+ else
+ {
+ // remove protection.
+ rDoc.SetDocProtection(nullptr);
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ pViewShell->UpdateLayerLocks();
+ pViewShell->UpdateInputHandler(true); // so that input can be immediately entered again
+ }
+
+ pDocShell->PostPaintGridAll();
+}
+
+void ScUndoDocProtect::Undo()
+{
+ BeginUndo();
+ DoProtect(!mpProtectSettings->isProtected());
+ EndUndo();
+}
+
+void ScUndoDocProtect::Redo()
+{
+ BeginRedo();
+ DoProtect(mpProtectSettings->isProtected());
+ EndRedo();
+}
+
+void ScUndoDocProtect::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoDocProtect::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // makes no sense
+}
+
+OUString ScUndoDocProtect::GetComment() const
+{
+ TranslateId pId = mpProtectSettings->isProtected() ? STR_UNDO_PROTECT_DOC : STR_UNDO_UNPROTECT_DOC;
+ return ScResId(pId);
+}
+
+ScUndoTabProtect::ScUndoTabProtect(ScDocShell* pShell, SCTAB nTab, unique_ptr<ScTableProtection> && pProtectSettings) :
+ ScSimpleUndo(pShell),
+ mnTab(nTab),
+ mpProtectSettings(std::move(pProtectSettings))
+{
+}
+
+ScUndoTabProtect::~ScUndoTabProtect()
+{
+}
+
+void ScUndoTabProtect::DoProtect(bool bProtect)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ if (bProtect)
+ {
+ // set protection.
+ unique_ptr<ScTableProtection> pCopy(new ScTableProtection(*mpProtectSettings));
+ pCopy->setProtected(true);
+ rDoc.SetTabProtection(mnTab, pCopy.get());
+ }
+ else
+ {
+ // remove protection.
+ rDoc.SetTabProtection(mnTab, nullptr);
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ {
+ if (ScTabView* pTabView = pViewShell->GetViewData().GetView())
+ pTabView->SetTabProtectionSymbol( mnTab, bProtect);
+ pViewShell->UpdateLayerLocks();
+ pViewShell->UpdateInputHandler(true); // so that input can be immediately entered again
+ }
+
+ pDocShell->PostPaintGridAll();
+}
+
+void ScUndoTabProtect::Undo()
+{
+ BeginUndo();
+ DoProtect(!mpProtectSettings->isProtected());
+ EndUndo();
+}
+
+void ScUndoTabProtect::Redo()
+{
+ BeginRedo();
+ DoProtect(mpProtectSettings->isProtected());
+ EndRedo();
+}
+
+void ScUndoTabProtect::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoTabProtect::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // makes no sense
+}
+
+OUString ScUndoTabProtect::GetComment() const
+{
+ TranslateId pId = mpProtectSettings->isProtected() ? STR_UNDO_PROTECT_TAB : STR_UNDO_UNPROTECT_TAB;
+ return ScResId(pId);
+}
+
+ScUndoPrintRange::ScUndoPrintRange( ScDocShell* pShell, SCTAB nNewTab,
+ std::unique_ptr<ScPrintRangeSaver> pOld, std::unique_ptr<ScPrintRangeSaver> pNew ) :
+ ScSimpleUndo( pShell ),
+ nTab( nNewTab ),
+ pOldRanges( std::move(pOld) ),
+ pNewRanges( std::move(pNew) )
+{
+}
+
+ScUndoPrintRange::~ScUndoPrintRange()
+{
+ pOldRanges.reset();
+ pNewRanges.reset();
+}
+
+void ScUndoPrintRange::DoChange(bool bUndo)
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (bUndo)
+ rDoc.RestorePrintRanges( *pOldRanges );
+ else
+ rDoc.RestorePrintRanges( *pNewRanges );
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo( nTab );
+
+ ScPrintFunc( pDocShell, pDocShell->GetPrinter(), nTab ).UpdatePages();
+
+ if (pViewShell && comphelper::LibreOfficeKit::isActive())
+ {
+ tools::JsonWriter aJsonWriter;
+ if (bUndo)
+ pOldRanges->GetPrintRangesInfo(aJsonWriter);
+ else
+ pNewRanges->GetPrintRangesInfo(aJsonWriter);
+
+ const std::string message = aJsonWriter.extractAsStdString();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_PRINT_RANGES, message.c_str());
+ }
+
+ pDocShell->PostPaint( ScRange(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab), PaintPartFlags::Grid );
+}
+
+void ScUndoPrintRange::Undo()
+{
+ BeginUndo();
+ DoChange( true );
+ EndUndo();
+}
+
+void ScUndoPrintRange::Redo()
+{
+ BeginRedo();
+ DoChange( false );
+ EndRedo();
+}
+
+void ScUndoPrintRange::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // makes no sense
+}
+
+bool ScUndoPrintRange::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false; // makes no sense
+}
+
+OUString ScUndoPrintRange::GetComment() const
+{
+ return ScResId( STR_UNDO_PRINTRANGES );
+}
+
+ScUndoScenarioFlags::ScUndoScenarioFlags(ScDocShell* pNewDocShell, SCTAB nT,
+ const OUString& rON, const OUString& rNN, const OUString& rOC, const OUString& rNC,
+ const Color& rOCol, const Color& rNCol, ScScenarioFlags nOF, ScScenarioFlags nNF) :
+ ScSimpleUndo( pNewDocShell ),
+ nTab ( nT ),
+ aOldName ( rON ),
+ aNewName ( rNN ),
+ aOldComment ( rOC ),
+ aNewComment ( rNC ),
+ aOldColor ( rOCol ),
+ aNewColor ( rNCol ),
+ nOldFlags (nOF),
+ nNewFlags (nNF)
+{
+}
+
+ScUndoScenarioFlags::~ScUndoScenarioFlags()
+{
+}
+
+OUString ScUndoScenarioFlags::GetComment() const
+{
+ return ScResId( STR_UNDO_EDITSCENARIO );
+}
+
+void ScUndoScenarioFlags::Undo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.RenameTab( nTab, aOldName );
+ rDoc.SetScenarioData( nTab, aOldComment, aOldColor, nOldFlags );
+
+ pDocShell->PostPaintGridAll();
+ // The sheet name might be used in a formula ...
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->UpdateInputHandler();
+
+ if ( aOldName != aNewName )
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+}
+
+void ScUndoScenarioFlags::Redo()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.RenameTab( nTab, aNewName );
+ rDoc.SetScenarioData( nTab, aNewComment, aNewColor, nNewFlags );
+
+ pDocShell->PostPaintGridAll();
+ // The sheet name might be used in a formula ...
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->UpdateInputHandler();
+
+ if ( aOldName != aNewName )
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+}
+
+void ScUndoScenarioFlags::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+ // Repeat makes no sense
+}
+
+bool ScUndoScenarioFlags::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+// (move to different file?)
+ScUndoRenameObject::ScUndoRenameObject( ScDocShell* pNewDocShell, const OUString& rPN,
+ const OUString& rON, const OUString& rNN ) :
+ ScSimpleUndo( pNewDocShell ),
+ aPersistName( rPN ),
+ aOldName ( rON ),
+ aNewName ( rNN )
+{
+}
+
+ScUndoRenameObject::~ScUndoRenameObject()
+{
+}
+
+OUString ScUndoRenameObject::GetComment() const
+{
+ // string resource shared with title for dialog
+ return ScResId(SCSTR_RENAMEOBJECT);
+}
+
+SdrObject* ScUndoRenameObject::GetObject()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if ( pDrawLayer )
+ {
+ sal_uInt16 nCount = pDrawLayer->GetPageCount();
+ for (sal_uInt16 nTab=0; nTab<nCount; nTab++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(nTab);
+ assert(pPage && "Page ?");
+
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 &&
+ static_cast<SdrOle2Obj*>(pObject)->GetPersistName() == aPersistName )
+ {
+ return pObject;
+ }
+
+ pObject = aIter.Next();
+ }
+ }
+ }
+ OSL_FAIL("Object not found");
+ return nullptr;
+}
+
+void ScUndoRenameObject::Undo()
+{
+ BeginUndo();
+ SdrObject* pObj = GetObject();
+ if ( pObj )
+ pObj->SetName( aOldName );
+ EndUndo();
+}
+
+void ScUndoRenameObject::Redo()
+{
+ BeginRedo();
+ SdrObject* pObj = GetObject();
+ if ( pObj )
+ pObj->SetName( aNewName );
+ EndRedo();
+}
+
+void ScUndoRenameObject::Repeat(SfxRepeatTarget& /* rTarget */)
+{
+}
+
+bool ScUndoRenameObject::CanRepeat(SfxRepeatTarget& /* rTarget */) const
+{
+ return false;
+}
+
+ScUndoLayoutRTL::ScUndoLayoutRTL( ScDocShell* pShell, SCTAB nNewTab, bool bNewRTL ) :
+ ScSimpleUndo( pShell ),
+ nTab( nNewTab ),
+ bRTL( bNewRTL )
+{
+}
+
+ScUndoLayoutRTL::~ScUndoLayoutRTL()
+{
+}
+
+void ScUndoLayoutRTL::DoChange( bool bNew )
+{
+ pDocShell->SetInUndo( true );
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.SetLayoutRTL(nTab, bNew, ScObjectHandling::MirrorRTLMode);
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->SetTabNo(nTab,true);
+
+ pDocShell->SetDocumentModified();
+
+ pDocShell->SetInUndo( false );
+}
+
+void ScUndoLayoutRTL::Undo()
+{
+ DoChange(!bRTL);
+}
+
+void ScUndoLayoutRTL::Redo()
+{
+ DoChange(bRTL);
+}
+
+void ScUndoLayoutRTL::Repeat(SfxRepeatTarget& rTarget)
+{
+ if (auto pViewTarget = dynamic_cast<ScTabViewTarget*>( &rTarget))
+ pViewTarget->GetViewShell()->GetViewData().GetDispatcher().
+ Execute( FID_TAB_RTL, SfxCallMode::SLOT | SfxCallMode::RECORD);
+}
+
+bool ScUndoLayoutRTL::CanRepeat(SfxRepeatTarget& rTarget) const
+{
+ return dynamic_cast<const ScTabViewTarget*>( &rTarget) != nullptr;
+}
+
+OUString ScUndoLayoutRTL::GetComment() const
+{
+ return ScResId( STR_UNDO_TAB_RTL );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/undo/undoutil.cxx b/sc/source/ui/undo/undoutil.cxx
new file mode 100644
index 000000000..de9a50ef8
--- /dev/null
+++ b/sc/source/ui/undo/undoutil.cxx
@@ -0,0 +1,114 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <undoutil.hxx>
+
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <dbdata.hxx>
+#include <globalnames.hxx>
+#include <global.hxx>
+#include <markdata.hxx>
+#include <osl/diagnose.h>
+
+void ScUndoUtil::MarkSimpleBlock( const ScDocShell* pDocShell,
+ SCCOL nStartX, SCROW nStartY, SCTAB nStartZ,
+ SCCOL nEndX, SCROW nEndY, SCTAB nEndZ )
+{
+ if ( pDocShell->IsPaintLocked() )
+ return;
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (!pViewShell)
+ return;
+
+ SCTAB nViewTab = pViewShell->GetViewData().GetTabNo();
+ if ( nViewTab < nStartZ || nViewTab > nEndZ )
+ pViewShell->SetTabNo( nStartZ );
+
+ const ScRange aMarkRange( nStartX, nStartY, nStartZ, nEndX, nEndY, nEndZ);
+ pViewShell->DoneBlockMode();
+ pViewShell->MoveCursorAbs( nStartX, nStartY, SC_FOLLOW_JUMP, false, false );
+ pViewShell->InitOwnBlockMode( aMarkRange );
+ pViewShell->GetViewData().GetMarkData().SetMarkArea( aMarkRange );
+ pViewShell->MarkDataChanged();
+}
+
+void ScUndoUtil::MarkSimpleBlock( const ScDocShell* pDocShell,
+ const ScAddress& rBlockStart,
+ const ScAddress& rBlockEnd )
+{
+ MarkSimpleBlock( pDocShell, rBlockStart.Col(), rBlockStart.Row(), rBlockStart.Tab(),
+ rBlockEnd.Col(), rBlockEnd.Row(), rBlockEnd.Tab() );
+}
+
+void ScUndoUtil::MarkSimpleBlock( const ScDocShell* pDocShell,
+ const ScRange& rRange )
+{
+ MarkSimpleBlock( pDocShell, rRange.aStart.Col(), rRange.aStart.Row(), rRange.aStart.Tab(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aEnd.Tab() );
+}
+
+ScDBData* ScUndoUtil::GetOldDBData( const ScDBData* pUndoData, ScDocument* pDoc, SCTAB nTab,
+ SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ ScDBData* pRet = pDoc->GetDBAtArea( nTab, nCol1, nRow1, nCol2, nRow2 );
+
+ if (!pRet)
+ {
+ bool bWasTemp = false;
+ if ( pUndoData )
+ {
+ const OUString& aName = pUndoData->GetName();
+ if ( aName == STR_DB_LOCAL_NONAME )
+ bWasTemp = true;
+ }
+ OSL_ENSURE(bWasTemp, "Undo: didn't find database range");
+ pRet = pDoc->GetAnonymousDBData(nTab);
+ if (!pRet)
+ {
+ pRet = new ScDBData( STR_DB_LOCAL_NONAME, nTab,
+ nCol1,nRow1, nCol2,nRow2, true,
+ pDoc->HasColHeader( nCol1,nRow1,nCol2,nRow2,nTab ) );
+ pDoc->SetAnonymousDBData(nTab, std::unique_ptr<ScDBData>(pRet));
+ }
+ }
+
+ return pRet;
+}
+
+void ScUndoUtil::PaintMore( ScDocShell* pDocShell,
+ const ScRange& rRange )
+{
+ SCCOL nCol1 = rRange.aStart.Col();
+ SCROW nRow1 = rRange.aStart.Row();
+ SCCOL nCol2 = rRange.aEnd.Col();
+ SCROW nRow2 = rRange.aEnd.Row();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (nCol1 > 0) --nCol1;
+ if (nRow1 > 0) --nRow1;
+ if (nCol2<rDoc.MaxCol()) ++nCol2;
+ if (nRow2<rDoc.MaxRow()) ++nRow2;
+
+ pDocShell->PostPaint( nCol1,nRow1,rRange.aStart.Tab(),
+ nCol2,nRow2,rRange.aEnd.Tab(), PaintPartFlags::Grid );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/ChartRangeSelectionListener.cxx b/sc/source/ui/unoobj/ChartRangeSelectionListener.cxx
new file mode 100644
index 000000000..eae58aee6
--- /dev/null
+++ b/sc/source/ui/unoobj/ChartRangeSelectionListener.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 <ChartRangeSelectionListener.hxx>
+
+#include <com/sun/star/chart2/data/XRangeHighlighter.hpp>
+
+#include <tabvwsh.hxx>
+#include <unonames.hxx>
+#include <miscuno.hxx>
+
+using namespace ::com::sun::star;
+
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+
+SC_SIMPLE_SERVICE_INFO( ScChartRangeSelectionListener, "ScChartRangeSelectionListener",
+ SC_SERVICENAME_CHRANGEHILIGHT )
+
+ScChartRangeSelectionListener::ScChartRangeSelectionListener( ScTabViewShell * pViewShell ) :
+ m_pViewShell( pViewShell )
+{}
+
+ScChartRangeSelectionListener::~ScChartRangeSelectionListener()
+{}
+
+// ____ XModifyListener ____
+void SAL_CALL ScChartRangeSelectionListener::selectionChanged( const lang::EventObject& aEvent )
+{
+ Reference< chart2::data::XRangeHighlighter > xRangeHighlighter( aEvent.Source, uno::UNO_QUERY );
+ if( xRangeHighlighter.is())
+ {
+ Sequence< chart2::data::HighlightedRange > aRanges( xRangeHighlighter->getSelectedRanges());
+
+ // search the view on which the chart is active
+
+ if( m_pViewShell )
+ {
+ m_pViewShell->DoChartSelection( aRanges );
+ }
+ }
+}
+
+// ____ XEventListener ____
+void SAL_CALL ScChartRangeSelectionListener::disposing( const lang::EventObject& /*Source*/ )
+{
+}
+
+// ____ WeakComponentImplHelperBase ____
+void ScChartRangeSelectionListener::disposing(std::unique_lock<std::mutex>&)
+{
+ m_pViewShell = nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/ChartTools.cxx b/sc/source/ui/unoobj/ChartTools.cxx
new file mode 100644
index 000000000..6ce72bd9e
--- /dev/null
+++ b/sc/source/ui/unoobj/ChartTools.cxx
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ */
+
+#include <ChartTools.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+
+#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+
+using namespace css;
+
+namespace sc::tools {
+
+namespace {
+
+uno::Reference<chart2::data::XPivotTableDataProvider>
+getPivotTableDataProvider(const SdrOle2Obj* pOleObject)
+{
+ uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider;
+
+ const uno::Reference<embed::XEmbeddedObject>& xObject = pOleObject->GetObjRef();
+ if (xObject.is())
+ {
+ uno::Reference<chart2::XChartDocument> xChartDoc(xObject->getComponent(), uno::UNO_QUERY);
+ if (xChartDoc.is())
+ {
+ xPivotTableDataProvider.set(uno::Reference<chart2::data::XPivotTableDataProvider>(
+ xChartDoc->getDataProvider(), uno::UNO_QUERY));
+ }
+ }
+ return xPivotTableDataProvider;
+}
+
+OUString getAssociatedPivotTableName(const SdrOle2Obj* pOleObject)
+{
+ OUString aPivotTableName;
+ uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider;
+ xPivotTableDataProvider.set(getPivotTableDataProvider(pOleObject));
+ if (xPivotTableDataProvider.is())
+ aPivotTableName = xPivotTableDataProvider->getPivotTableName();
+ return aPivotTableName;
+}
+
+} // end anonymous namespace
+
+ChartIterator::ChartIterator(ScDocShell* pDocShell, SCTAB nTab, ChartSourceType eChartSourceType)
+ : m_eChartSourceType(eChartSourceType)
+{
+ if (!pDocShell)
+ return;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if (!pDrawLayer)
+ return;
+ SdrPage* pPage = pDrawLayer->GetPage(sal_uInt16(nTab));
+ if (!pPage)
+ return;
+ m_pIterator.reset(new SdrObjListIter(pPage, SdrIterMode::DeepNoGroups));
+}
+
+SdrOle2Obj* ChartIterator::next()
+{
+ if (!m_pIterator)
+ return nullptr;
+
+ SdrObject* pObject = m_pIterator->Next();
+ while (pObject)
+ {
+ if (pObject->GetObjIdentifier() == SdrObjKind::OLE2 && ScDocument::IsChart(pObject))
+ {
+ SdrOle2Obj* pOleObject = static_cast<SdrOle2Obj*>(pObject);
+
+ uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider;
+ xPivotTableDataProvider.set(getPivotTableDataProvider(pOleObject));
+
+ if (xPivotTableDataProvider.is() && m_eChartSourceType == ChartSourceType::PIVOT_TABLE)
+ return pOleObject;
+ else if (!xPivotTableDataProvider.is() && m_eChartSourceType == ChartSourceType::CELL_RANGE)
+ return pOleObject;
+ }
+ pObject = m_pIterator->Next();
+ }
+ return nullptr;
+}
+
+SdrOle2Obj* findChartsByName(ScDocShell* pDocShell, SCTAB nTab, std::u16string_view rName, ChartSourceType eChartSourceType)
+{
+ if (!pDocShell)
+ return nullptr;
+
+ ChartIterator aIterator(pDocShell, nTab, eChartSourceType);
+
+ SdrOle2Obj* pObject = aIterator.next();
+ while (pObject)
+ {
+ uno::Reference<embed::XEmbeddedObject> xObject = pObject->GetObjRef();
+ if (xObject.is())
+ {
+ OUString aObjectName = pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName(xObject);
+ if (aObjectName == rName)
+ return pObject;
+ }
+ pObject = aIterator.next();
+ }
+ return nullptr;
+}
+
+SdrOle2Obj* getChartByIndex(ScDocShell* pDocShell, SCTAB nTab, ::tools::Long nIndex, ChartSourceType eChartSourceType)
+{
+ if (!pDocShell)
+ return nullptr;
+
+ ChartIterator aIterator(pDocShell, nTab, eChartSourceType);
+
+ SdrOle2Obj* pObject = aIterator.next();
+ ::tools::Long i = 0;
+ while (pObject)
+ {
+ if (i == nIndex)
+ {
+ return pObject;
+ }
+
+ i++;
+ pObject = aIterator.next();
+ }
+ return nullptr;
+}
+
+std::vector<SdrOle2Obj*> getAllPivotChartsConnectedTo(std::u16string_view sPivotTableName, ScDocShell* pDocShell)
+{
+ std::vector<SdrOle2Obj*> aObjects;
+
+ ScDocument& rDocument = pDocShell->GetDocument();
+ ScDrawLayer* pModel = rDocument.GetDrawLayer();
+ if (!pModel)
+ return aObjects;
+
+ sal_uInt16 nPageCount = pModel->GetPageCount();
+ for (sal_uInt16 nPageNo = 0; nPageNo < nPageCount; nPageNo++)
+ {
+ SdrPage* pPage = pModel->GetPage(nPageNo);
+ if (!pPage)
+ continue;
+
+ sc::tools::ChartIterator aIterator(pDocShell, nPageNo, ChartSourceType::PIVOT_TABLE);
+ SdrOle2Obj* pObject = aIterator.next();
+ while (pObject)
+ {
+ if (sPivotTableName == getAssociatedPivotTableName(pObject))
+ {
+ aObjects.push_back(pObject);
+ }
+ pObject = aIterator.next();
+ }
+ }
+ return aObjects;
+}
+
+} // end sc::tools
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/PivotTableDataProvider.cxx b/sc/source/ui/unoobj/PivotTableDataProvider.cxx
new file mode 100644
index 000000000..f0a9cdb8e
--- /dev/null
+++ b/sc/source/ui/unoobj/PivotTableDataProvider.cxx
@@ -0,0 +1,904 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <limits>
+#include <memory>
+#include <sal/config.h>
+
+#include <PivotTableDataProvider.hxx>
+#include <PivotTableDataSource.hxx>
+#include <PivotTableDataSequence.hxx>
+
+#include <miscuno.hxx>
+#include <document.hxx>
+#include <unonames.hxx>
+#include <scresid.hxx>
+#include <globstr.hrc>
+#include <strings.hrc>
+#include <dpobject.hxx>
+#include <hints.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/objsh.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/processfactory.hxx>
+
+#include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+
+#include <com/sun/star/sheet/XDataPilotResults.hpp>
+#include <com/sun/star/sheet/DataResultFlags.hpp>
+
+#include <com/sun/star/sheet/XDimensionsSupplier.hpp>
+#include <com/sun/star/sheet/XHierarchiesSupplier.hpp>
+#include <com/sun/star/sheet/XLevelsSupplier.hpp>
+#include <com/sun/star/sheet/XDataPilotMemberResults.hpp>
+#include <com/sun/star/sheet/MemberResultFlags.hpp>
+#include <com/sun/star/sheet/XMembersSupplier.hpp>
+
+#include <com/sun/star/chart/ChartDataChangeEvent.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+
+#include <unordered_map>
+
+using namespace css;
+
+namespace sc
+{
+namespace
+{
+constexpr OUStringLiteral constIdCategories(u"categories");
+constexpr OUStringLiteral constIdLabel(u"label");
+constexpr OUStringLiteral constIdData(u"data");
+
+const SfxItemPropertyMapEntry* lcl_GetDataProviderPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_INCLUDEHIDDENCELLS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_USE_INTERNAL_DATA_PROVIDER, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aDataProviderPropertyMap_Impl;
+}
+
+uno::Reference<frame::XModel> lcl_GetXModel(const ScDocument * pDoc)
+{
+ uno::Reference<frame::XModel> xModel;
+ SfxObjectShell* pObjSh(pDoc ? pDoc->GetDocumentShell() : nullptr);
+ if (pObjSh)
+ xModel.set(pObjSh->GetModel());
+ return xModel;
+}
+
+OUString lcl_identifierForData(sal_Int32 index)
+{
+ return "PT@" + constIdData + " " + OUString::number(index);
+}
+
+OUString lcl_identifierForLabel(sal_Int32 index)
+{
+ return "PT@" + constIdLabel + " " + OUString::number(index);
+}
+
+OUString lcl_identifierForCategories()
+{
+ return "PT@" + constIdCategories;
+}
+
+std::vector<OUString> lcl_getVisiblePageMembers(const uno::Reference<uno::XInterface> & xLevel)
+{
+ std::vector<OUString> aResult;
+ if (!xLevel.is())
+ return aResult;
+
+ uno::Reference<sheet::XMembersSupplier> xMembersSupplier(xLevel, uno::UNO_QUERY);
+ if (!xMembersSupplier.is())
+ return aResult;
+
+ uno::Reference<sheet::XMembersAccess> xMembersAccess = xMembersSupplier->getMembers();
+ if (!xMembersAccess.is())
+ return aResult;
+
+ const css::uno::Sequence<OUString> aMembersNames = xMembersAccess->getElementNames();
+ for (OUString const & rMemberNames : aMembersNames)
+ {
+ uno::Reference<beans::XPropertySet> xProperties(xMembersAccess->getByName(rMemberNames), uno::UNO_QUERY);
+ if (!xProperties.is())
+ continue;
+
+ OUString aCaption = ScUnoHelpFunctions::GetStringProperty(xProperties, SC_UNO_DP_LAYOUTNAME, OUString());
+ if (aCaption.isEmpty())
+ aCaption = rMemberNames;
+
+ bool bVisible = ScUnoHelpFunctions::GetBoolProperty(xProperties, SC_UNO_DP_ISVISIBLE);
+
+ if (bVisible)
+ aResult.push_back(aCaption);
+ }
+
+ return aResult;
+}
+
+} // end anonymous namespace
+
+SC_SIMPLE_SERVICE_INFO(PivotTableDataProvider, "PivotTableDataProvider", SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER)
+
+// DataProvider ==============================================================
+
+PivotTableDataProvider::PivotTableDataProvider(ScDocument& rDoc)
+ : m_pDocument(&rDoc)
+ , m_aPropSet(lcl_GetDataProviderPropertyMap())
+ , m_bIncludeHiddenCells(true)
+ , m_bNeedsUpdate(true)
+ , m_xContext(comphelper::getProcessComponentContext())
+{
+ rDoc.AddUnoObject(*this);
+}
+
+PivotTableDataProvider::~PivotTableDataProvider()
+{
+ SolarMutexGuard g;
+
+ if (m_pDocument)
+ m_pDocument->RemoveUnoObject( *this);
+}
+
+void PivotTableDataProvider::Notify(SfxBroadcaster& /*rBroadcaster*/, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ m_pDocument = nullptr;
+ }
+ else if (m_pDocument)
+ {
+ if (auto pDataPilotHint = dynamic_cast<const ScDataPilotModifiedHint*>(&rHint))
+ {
+ if (pDataPilotHint->GetName() == m_sPivotTableName)
+ {
+ m_bNeedsUpdate = true;
+ for (uno::Reference<util::XModifyListener> const & xListener : m_aValueListeners)
+ {
+ css::chart::ChartDataChangeEvent aEvent(static_cast<cppu::OWeakObject*>(this),
+ css::chart::ChartDataChangeType_ALL,
+ 0, 0, 0, 0);
+ xListener->modified(aEvent);
+ }
+ }
+ }
+ }
+}
+
+sal_Bool SAL_CALL PivotTableDataProvider::createDataSourcePossible(const uno::Sequence<beans::PropertyValue>& /*aArguments*/)
+{
+ SolarMutexGuard aGuard;
+ if (!m_pDocument)
+ return false;
+
+ if (m_sPivotTableName.isEmpty())
+ return false;
+
+ ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
+ return bool(pDPCollection->GetByName(m_sPivotTableName));
+}
+
+uno::Reference<chart2::data::XDataSource> SAL_CALL
+ PivotTableDataProvider::createDataSource(const uno::Sequence<beans::PropertyValue>& aArguments)
+{
+ SolarMutexGuard aGuard;
+
+ if (!m_pDocument)
+ throw uno::RuntimeException();
+
+ bool bOrientCol = true;
+ OUString aRangeRepresentation;
+
+ for (beans::PropertyValue const & rProperty : aArguments)
+ {
+ if (rProperty.Name == "DataRowSource")
+ {
+ chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
+ if (!(rProperty.Value >>= eSource))
+ {
+ sal_Int32 nSource(0);
+ if (rProperty.Value >>= nSource)
+ eSource = chart::ChartDataRowSource(nSource);
+ }
+ bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
+ }
+ else if (rProperty.Name == "CellRangeRepresentation")
+ rProperty.Value >>= aRangeRepresentation;
+ }
+
+ uno::Reference<chart2::data::XDataSource> xResult;
+
+ if (aRangeRepresentation == lcl_identifierForCategories())
+ xResult = createCategoriesDataSource(bOrientCol);
+ else
+ xResult = createValuesDataSource();
+
+ return xResult;
+}
+
+uno::Reference<chart2::data::XLabeledDataSequence>
+ PivotTableDataProvider::newLabeledDataSequence()
+{
+ uno::Reference<chart2::data::XLabeledDataSequence> xResult;
+ if (!m_xContext.is())
+ return xResult;
+ xResult.set(chart2::data::LabeledDataSequence::create(m_xContext), uno::UNO_QUERY_THROW);
+ return xResult;
+}
+
+uno::Reference<chart2::data::XDataSource>
+PivotTableDataProvider::createCategoriesDataSource(bool bOrientationIsColumn)
+{
+ if (m_bNeedsUpdate)
+ collectPivotTableData();
+
+ uno::Reference<chart2::data::XDataSource> xDataSource;
+ std::vector<uno::Reference<chart2::data::XLabeledDataSequence>> aLabeledSequences;
+
+ std::vector<std::vector<ValueAndFormat>> const & rCategoriesVector = bOrientationIsColumn ? m_aCategoriesColumnOrientation
+ : m_aCategoriesRowOrientation;
+
+ for (std::vector<ValueAndFormat> const & rCategories : rCategoriesVector)
+ {
+ uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
+ rtl::Reference<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument,
+ lcl_identifierForCategories(), std::vector(rCategories)));
+ pSequence->setRole("categories");
+ xResult->setValues(uno::Reference<chart2::data::XDataSequence>(pSequence));
+
+ aLabeledSequences.push_back(xResult);
+ }
+
+ xDataSource.set(new PivotTableDataSource(std::move(aLabeledSequences)));
+ return xDataSource;
+}
+
+void PivotTableDataProvider::collectPivotTableData()
+{
+ ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
+ ScDPObject* pDPObject = pDPCollection->GetByName(m_sPivotTableName);
+ if (!pDPObject)
+ return;
+
+ m_aCategoriesColumnOrientation.clear();
+ m_aCategoriesRowOrientation.clear();
+ m_aLabels.clear();
+ m_aDataRowVector.clear();
+ m_aColumnFields.clear();
+ m_aRowFields.clear();
+ m_aPageFields.clear();
+ m_aDataFields.clear();
+ m_aFieldOutputDescriptionMap.clear();
+
+ uno::Reference<sheet::XDataPilotResults> xDPResults(pDPObject->GetSource(), uno::UNO_QUERY);
+ if (!xDPResults.is())
+ return;
+ const uno::Sequence<uno::Sequence<sheet::DataResult>> xDataResultsSequence = xDPResults->getResults();
+
+ std::unordered_set<size_t> aValidRowIndex;
+
+ size_t nRowIndex = 0;
+ for (uno::Sequence<sheet::DataResult> const & xDataResults : xDataResultsSequence)
+ {
+ std::vector<ValueAndFormat> aRow;
+ bool bRowEmpty = true;
+ // First pass - collect a row of valid data and track if the row is empty
+ for (sheet::DataResult const & rDataResult : xDataResults)
+ {
+ if (rDataResult.Flags & css::sheet::DataResultFlags::SUBTOTAL)
+ continue;
+ if (rDataResult.Flags == 0 || rDataResult.Flags & css::sheet::DataResultFlags::HASDATA)
+ {
+ aRow.emplace_back(rDataResult.Flags ? rDataResult.Value
+ : std::numeric_limits<double>::quiet_NaN(), 0);
+ if (rDataResult.Flags != 0) // set as valid only if we have data
+ {
+ bRowEmpty = false;
+ // We need to remember all valid (non-empty) row indices
+ aValidRowIndex.insert(nRowIndex);
+ }
+ }
+ }
+ // Second pass: add to collection only non-empty rows
+ if (!bRowEmpty)
+ {
+ size_t nColumnIndex = 0;
+ for (ValueAndFormat const & aValue : aRow)
+ {
+ if (nColumnIndex >= m_aDataRowVector.size())
+ m_aDataRowVector.resize(nColumnIndex + 1);
+ m_aDataRowVector[nColumnIndex].push_back(aValue);
+ nColumnIndex++;
+ }
+ }
+ nRowIndex++;
+ }
+
+ uno::Reference<sheet::XDimensionsSupplier> xDimensionsSupplier(pDPObject->GetSource());
+ uno::Reference<container::XIndexAccess> xDims = new ScNameToIndexAccess(xDimensionsSupplier->getDimensions());
+
+ std::unordered_map<OUString, sal_Int32> aDataFieldNumberFormatMap;
+ std::vector<OUString> aDataFieldNamesVectors;
+
+ std::unordered_map<OUString, OUString> aDataFieldCaptionNames;
+
+ sheet::DataPilotFieldOrientation eDataFieldOrientation = sheet::DataPilotFieldOrientation_HIDDEN;
+
+ for (sal_Int32 nDim = 0; nDim < xDims->getCount(); nDim++)
+ {
+ uno::Reference<uno::XInterface> xDim(xDims->getByIndex(nDim), uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xDimProp(xDim, uno::UNO_QUERY);
+ uno::Reference<sheet::XHierarchiesSupplier> xDimSupp(xDim, uno::UNO_QUERY);
+
+ if (!xDimProp.is() || !xDimSupp.is())
+ continue;
+
+ sheet::DataPilotFieldOrientation eDimOrient =
+ ScUnoHelpFunctions::GetEnumProperty(xDimProp, SC_UNO_DP_ORIENTATION,
+ sheet::DataPilotFieldOrientation_HIDDEN);
+
+ if (eDimOrient == sheet::DataPilotFieldOrientation_HIDDEN)
+ continue;
+
+ uno::Reference<container::XIndexAccess> xHierarchies = new ScNameToIndexAccess(xDimSupp->getHierarchies());
+ sal_Int32 nHierarchy = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_USEDHIERARCHY);
+ if (nHierarchy >= xHierarchies->getCount())
+ nHierarchy = 0;
+
+ uno::Reference<sheet::XLevelsSupplier> xLevelsSupplier(xHierarchies->getByIndex(nHierarchy),
+ uno::UNO_QUERY);
+
+ if (!xLevelsSupplier.is())
+ continue;
+
+ uno::Reference<container::XIndexAccess> xLevels = new ScNameToIndexAccess(xLevelsSupplier->getLevels());
+
+ for (tools::Long nLevel = 0; nLevel < xLevels->getCount(); nLevel++)
+ {
+ uno::Reference<uno::XInterface> xLevel(xLevels->getByIndex(nLevel), uno::UNO_QUERY);
+ uno::Reference<container::XNamed> xLevelName(xLevel, uno::UNO_QUERY);
+ uno::Reference<sheet::XDataPilotMemberResults> xLevelResult(xLevel, uno::UNO_QUERY );
+
+ if (xLevelName.is() && xLevelResult.is())
+ {
+ bool bIsDataLayout = ScUnoHelpFunctions::GetBoolProperty(xDimProp, SC_UNO_DP_ISDATALAYOUT);
+ sal_Int32 nDimPos = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_POSITION);
+ sal_Int32 nNumberFormat = ScUnoHelpFunctions::GetLongProperty(xDimProp, SC_UNO_DP_NUMBERFO);
+ bool bHasHiddenMember = ScUnoHelpFunctions::GetBoolProperty(xDimProp, SC_UNO_DP_HAS_HIDDEN_MEMBER);
+
+ switch (eDimOrient)
+ {
+ case sheet::DataPilotFieldOrientation_COLUMN:
+ {
+ m_aColumnFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
+
+ const uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
+ size_t i = 0;
+ OUString sCaption;
+ OUString sName;
+ for (sheet::MemberResult const & rMember : aSequence)
+ {
+ // Skip grandtotals and subtotals
+ if (rMember.Flags & sheet::MemberResultFlags::SUBTOTAL ||
+ rMember.Flags & sheet::MemberResultFlags::GRANDTOTAL)
+ continue;
+ if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER ||
+ rMember.Flags & sheet::MemberResultFlags::CONTINUE)
+ {
+ if (!(rMember.Flags & sheet::MemberResultFlags::CONTINUE))
+ {
+ sCaption = rMember.Caption;
+ sName = rMember.Name;
+ }
+
+ if (i >= m_aLabels.size())
+ m_aLabels.resize(i + 1);
+
+ if (o3tl::make_unsigned(nDimPos) >= m_aLabels[i].size())
+ m_aLabels[i].resize(nDimPos + 1);
+ m_aLabels[i][nDimPos] = ValueAndFormat(sCaption);
+
+ if (bIsDataLayout)
+ {
+ // Remember data fields to determine the number format of data
+ aDataFieldNamesVectors.push_back(sName);
+ eDataFieldOrientation = sheet::DataPilotFieldOrientation_COLUMN;
+ // Remember the caption name
+ aDataFieldCaptionNames[rMember.Name] = rMember.Caption;
+ }
+ i++;
+ }
+ }
+ }
+ break;
+
+ case sheet::DataPilotFieldOrientation_ROW:
+ {
+ m_aRowFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
+
+ const uno::Sequence<sheet::MemberResult> aSequence = xLevelResult->getResults();
+
+ size_t i = 0;
+ size_t nEachIndex = 0;
+ std::unique_ptr<ValueAndFormat> pItem;
+
+ for (sheet::MemberResult const & rMember : aSequence)
+ {
+ bool bFound = aValidRowIndex.find(nEachIndex) != aValidRowIndex.end();
+
+ nEachIndex++;
+
+ bool bHasContinueFlag = rMember.Flags & sheet::MemberResultFlags::CONTINUE;
+
+ if (rMember.Flags & sheet::MemberResultFlags::HASMEMBER || bHasContinueFlag)
+ {
+ if (!bHasContinueFlag)
+ {
+ // Chart2 does not use number format for labels, so use the display string.
+ pItem.reset(new ValueAndFormat(rMember.Caption));
+ }
+
+ if (bFound)
+ {
+ if (i >= m_aCategoriesRowOrientation.size())
+ m_aCategoriesRowOrientation.resize(i + 1);
+
+ if (o3tl::make_unsigned(nDimPos) >= m_aCategoriesColumnOrientation.size())
+ m_aCategoriesColumnOrientation.resize(nDimPos + 1);
+ m_aCategoriesColumnOrientation[nDimPos].push_back(*pItem);
+
+ if (o3tl::make_unsigned(nDimPos) >= m_aCategoriesRowOrientation[i].size())
+ m_aCategoriesRowOrientation[i].resize(nDimPos + 1);
+ m_aCategoriesRowOrientation[i][nDimPos] = *pItem;
+
+ if (bIsDataLayout)
+ {
+ // Remember data fields to determine the number format of data
+ aDataFieldNamesVectors.push_back(rMember.Name);
+ eDataFieldOrientation = sheet::DataPilotFieldOrientation_ROW;
+
+ // Remember the caption name
+ aDataFieldCaptionNames[rMember.Name] = rMember.Caption;
+ }
+
+ // Set to empty so the sub categories are set to empty when they continue
+ pItem.reset(new ValueAndFormat);
+ i++;
+ }
+ }
+ }
+ }
+ break;
+
+ case sheet::DataPilotFieldOrientation_PAGE:
+ {
+ m_aPageFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
+
+ // Resolve filtering
+ OUString aFieldOutputDescription;
+ if (bHasHiddenMember)
+ {
+ std::vector<OUString> aMembers = lcl_getVisiblePageMembers(xLevel);
+
+ if (aMembers.size() == 1)
+ aFieldOutputDescription = aMembers[0];
+ else
+ aFieldOutputDescription = ScResId(SCSTR_MULTIPLE);
+ }
+ else
+ {
+ aFieldOutputDescription = ScResId(SCSTR_ALL);
+ }
+ m_aFieldOutputDescriptionMap[nDim] = aFieldOutputDescription;
+ }
+ break;
+
+ case sheet::DataPilotFieldOrientation_DATA:
+ {
+ aDataFieldNumberFormatMap[xLevelName->getName()] = nNumberFormat;
+ m_aDataFields.emplace_back(xLevelName->getName(), nDim, nDimPos, bHasHiddenMember);
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // Transform the name of data fields
+ for (chart2::data::PivotTableFieldEntry& rDataFields : m_aDataFields)
+ {
+ rDataFields.Name = aDataFieldCaptionNames[rDataFields.Name];
+ }
+
+ // Apply number format to the data
+ if (eDataFieldOrientation == sheet::DataPilotFieldOrientation_ROW)
+ {
+ for (std::vector<ValueAndFormat> & rDataRow : m_aDataRowVector)
+ {
+ size_t i = 0;
+ for (ValueAndFormat & rItem : rDataRow)
+ {
+ OUString sName = aDataFieldNamesVectors[i];
+ sal_Int32 nNumberFormat = aDataFieldNumberFormatMap[sName];
+ rItem.m_nNumberFormat = nNumberFormat;
+ i++;
+ }
+ }
+ }
+ else if (eDataFieldOrientation == sheet::DataPilotFieldOrientation_COLUMN)
+ {
+ size_t i = 0;
+ for (std::vector<ValueAndFormat> & rDataRow : m_aDataRowVector)
+ {
+ OUString sName = aDataFieldNamesVectors[i];
+ sal_Int32 nNumberFormat = aDataFieldNumberFormatMap[sName];
+ for (ValueAndFormat & rItem : rDataRow)
+ {
+ rItem.m_nNumberFormat = nNumberFormat;
+ }
+ i++;
+ }
+ }
+
+ // Sort fields so it respects the order of how it is represented in the pivot table
+
+ auto funcDimensionPositionSortCompare = [] (chart2::data::PivotTableFieldEntry const & entry1,
+ chart2::data::PivotTableFieldEntry const & entry2)
+ {
+ return entry1.DimensionPositionIndex < entry2.DimensionPositionIndex;
+ };
+
+ std::sort(m_aColumnFields.begin(), m_aColumnFields.end(), funcDimensionPositionSortCompare);
+ std::sort(m_aRowFields.begin(), m_aRowFields.end(), funcDimensionPositionSortCompare);
+ std::sort(m_aPageFields.begin(), m_aPageFields.end(), funcDimensionPositionSortCompare);
+ std::sort(m_aDataFields.begin(), m_aDataFields.end(), funcDimensionPositionSortCompare);
+
+ // Mark that we updated the data
+ m_bNeedsUpdate = false;
+}
+
+uno::Reference<chart2::data::XDataSequence>
+PivotTableDataProvider::assignValuesToDataSequence(size_t nIndex)
+{
+ uno::Reference<chart2::data::XDataSequence> xDataSequence;
+ if (nIndex >= m_aDataRowVector.size())
+ return xDataSequence;
+
+ OUString sDataID = lcl_identifierForData(nIndex);
+
+ std::vector<ValueAndFormat> const & rRowOfData = m_aDataRowVector[nIndex];
+ rtl::Reference<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument, sDataID, std::vector(rRowOfData)));
+ pSequence->setRole("values-y");
+ xDataSequence = pSequence;
+ return xDataSequence;
+}
+
+uno::Reference<chart2::data::XDataSequence>
+PivotTableDataProvider::assignLabelsToDataSequence(size_t nIndex)
+{
+ uno::Reference<chart2::data::XDataSequence> xDataSequence;
+
+ OUString sLabelID = lcl_identifierForLabel(nIndex);
+
+ OUStringBuffer aLabel;
+ bool bFirst = true;
+
+ if (m_aLabels.empty())
+ {
+ aLabel = ScResId(STR_PIVOT_TOTAL);
+ }
+ else if (nIndex < m_aLabels.size())
+ {
+ for (ValueAndFormat const & rItem : m_aLabels[nIndex])
+ {
+ if (bFirst)
+ {
+ aLabel.append(rItem.m_aString);
+ bFirst = false;
+ }
+ else
+ {
+ aLabel.append(" - " + rItem.m_aString);
+ }
+ }
+ }
+
+ std::vector<ValueAndFormat> aLabelVector { ValueAndFormat(aLabel.makeStringAndClear()) };
+
+ rtl::Reference<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument,
+ sLabelID, std::move(aLabelVector)));
+ pSequence->setRole("values-y");
+ xDataSequence = pSequence;
+ return xDataSequence;
+}
+
+css::uno::Reference<css::chart2::data::XDataSequence>
+ PivotTableDataProvider::assignFirstCategoriesToDataSequence()
+{
+ uno::Reference<chart2::data::XDataSequence> xDataSequence;
+
+ if (m_aCategoriesColumnOrientation.empty())
+ return xDataSequence;
+
+ std::vector<ValueAndFormat> const & rCategories = m_aCategoriesColumnOrientation.back();
+
+ rtl::Reference<PivotTableDataSequence> pSequence(new PivotTableDataSequence(m_pDocument,
+ lcl_identifierForCategories(), std::vector(rCategories)));
+ pSequence->setRole("categories");
+ xDataSequence = pSequence;
+
+ return xDataSequence;
+}
+
+uno::Reference<chart2::data::XDataSource>
+ PivotTableDataProvider::createValuesDataSource()
+{
+ if (m_bNeedsUpdate)
+ collectPivotTableData();
+
+ uno::Reference<chart2::data::XDataSource> xDataSource;
+ std::vector<uno::Reference<chart2::data::XLabeledDataSequence>> aLabeledSequences;
+
+ // Fill first sequence of categories
+ {
+ uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
+ xResult->setValues(assignFirstCategoriesToDataSequence());
+ aLabeledSequences.push_back(xResult);
+ }
+
+ // Fill values and labels
+ {
+ for (size_t i = 0; i < m_aDataRowVector.size(); ++i)
+ {
+ uno::Reference<chart2::data::XLabeledDataSequence> xResult = newLabeledDataSequence();
+ xResult->setValues(assignValuesToDataSequence(i));
+ xResult->setLabel(assignLabelsToDataSequence(i));
+ aLabeledSequences.push_back(xResult);
+ }
+ }
+
+ xDataSource.set(new PivotTableDataSource(std::move(aLabeledSequences)));
+ return xDataSource;
+}
+
+
+uno::Sequence<beans::PropertyValue> SAL_CALL PivotTableDataProvider::detectArguments(
+ const uno::Reference<chart2::data::XDataSource> & xDataSource)
+{
+ if (!m_pDocument ||!xDataSource.is())
+ return uno::Sequence<beans::PropertyValue>();
+
+ return comphelper::InitPropertySequence({
+ { "CellRangeRepresentation", uno::Any(OUString("PivotChart")) },
+ { "DataRowSource", uno::Any(chart::ChartDataRowSource_COLUMNS) },
+ { "FirstCellAsLabel", uno::Any(false) },
+ { "HasCategories", uno::Any(true) }
+ });
+}
+
+sal_Bool SAL_CALL PivotTableDataProvider::createDataSequenceByRangeRepresentationPossible(const OUString& /*aRangeRepresentation*/)
+{
+ return false;
+}
+
+uno::Reference<chart2::data::XDataSequence> SAL_CALL
+ PivotTableDataProvider::createDataSequenceByRangeRepresentation(const OUString& /*rRangeRepresentation*/)
+{
+ uno::Reference<chart2::data::XDataSequence> xDataSequence;
+ return xDataSequence;
+}
+
+uno::Reference<chart2::data::XDataSequence> SAL_CALL
+ PivotTableDataProvider::createDataSequenceByValueArray(const OUString& /*aRole*/,
+ const OUString& /*aRangeRepresentation*/,
+ const OUString& /*aRoleQualifier*/)
+{
+ return uno::Reference<chart2::data::XDataSequence>();
+}
+
+uno::Reference<sheet::XRangeSelection> SAL_CALL PivotTableDataProvider::getRangeSelection()
+{
+ uno::Reference<sheet::XRangeSelection> xResult;
+
+ uno::Reference<frame::XModel> xModel(lcl_GetXModel(m_pDocument));
+ if (xModel.is())
+ xResult.set(xModel->getCurrentController(), uno::UNO_QUERY);
+
+ return xResult;
+}
+
+// XPivotTableDataProvider ========================================================
+
+uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getColumnFields()
+{
+ return comphelper::containerToSequence(m_aColumnFields);
+}
+
+uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getRowFields()
+{
+ return comphelper::containerToSequence(m_aRowFields);
+}
+
+uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getPageFields()
+{
+ return comphelper::containerToSequence(m_aPageFields);
+}
+
+uno::Sequence<chart2::data::PivotTableFieldEntry> PivotTableDataProvider::getDataFields()
+{
+ return comphelper::containerToSequence(m_aDataFields);
+}
+
+OUString PivotTableDataProvider::getPivotTableName()
+{
+ return m_sPivotTableName;
+}
+
+void PivotTableDataProvider::setPivotTableName(const OUString& sPivotTableName)
+{
+ ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
+ ScDPObject* pDPObject = pDPCollection->GetByName(sPivotTableName);
+ if (pDPObject)
+ m_sPivotTableName = sPivotTableName;
+}
+
+sal_Bool PivotTableDataProvider::hasPivotTable()
+{
+ if (m_sPivotTableName.isEmpty())
+ return false;
+
+ ScDPCollection* pDPCollection = m_pDocument->GetDPCollection();
+ ScDPObject* pDPObject = pDPCollection->GetByName(m_sPivotTableName);
+
+ if (pDPObject)
+ return true;
+
+ return false;
+}
+
+uno::Reference<chart2::data::XDataSequence>
+ PivotTableDataProvider::createDataSequenceOfValuesByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+
+ if (m_bNeedsUpdate)
+ collectPivotTableData();
+
+ return assignValuesToDataSequence(size_t(nIndex));
+}
+
+uno::Reference<css::chart2::data::XDataSequence>
+ PivotTableDataProvider::createDataSequenceOfLabelsByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+
+ if (m_bNeedsUpdate)
+ collectPivotTableData();
+
+ return assignLabelsToDataSequence(size_t(nIndex));
+}
+
+uno::Reference<css::chart2::data::XDataSequence>
+ PivotTableDataProvider::createDataSequenceOfCategories()
+{
+ SolarMutexGuard aGuard;
+
+ if (m_bNeedsUpdate)
+ collectPivotTableData();
+
+ return assignFirstCategoriesToDataSequence();
+}
+
+OUString PivotTableDataProvider::getFieldOutputDescription(sal_Int32 nDimensionIndex)
+{
+ if (nDimensionIndex < 0)
+ return OUString();
+ return m_aFieldOutputDescriptionMap[size_t(nDimensionIndex)];
+}
+
+// XModifyBroadcaster ========================================================
+
+void SAL_CALL PivotTableDataProvider::addModifyListener(const uno::Reference< util::XModifyListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ m_aValueListeners.emplace_back(aListener);
+}
+
+void SAL_CALL PivotTableDataProvider::removeModifyListener(const uno::Reference<util::XModifyListener>& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ sal_uInt16 nCount = m_aValueListeners.size();
+ for (sal_uInt16 n = nCount; n--;)
+ {
+ uno::Reference<util::XModifyListener>& rObject = m_aValueListeners[n];
+ if (rObject == aListener)
+ {
+ m_aValueListeners.erase(m_aValueListeners.begin() + n);
+ }
+ }
+}
+
+// DataProvider XPropertySet ========================================================
+
+uno::Reference< beans::XPropertySetInfo> SAL_CALL
+ PivotTableDataProvider::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL PivotTableDataProvider::setPropertyValue(const OUString& rPropertyName, const uno::Any& rValue)
+{
+ if (rPropertyName != SC_UNONAME_INCLUDEHIDDENCELLS)
+ throw beans::UnknownPropertyException(rPropertyName);
+
+ if (!(rValue >>= m_bIncludeHiddenCells))
+ throw lang::IllegalArgumentException();
+}
+
+uno::Any SAL_CALL PivotTableDataProvider::getPropertyValue(const OUString& rPropertyName)
+{
+ uno::Any aRet;
+ if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS)
+ aRet <<= m_bIncludeHiddenCells;
+ else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
+ {
+ // This is a read-only property.
+ aRet <<= m_pDocument->PastingDrawFromOtherDoc();
+ }
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+ return aRet;
+}
+
+void SAL_CALL PivotTableDataProvider::addPropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference<beans::XPropertyChangeListener>& /*xListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataProvider::removePropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference<beans::XPropertyChangeListener>& /*rListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataProvider::addVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataProvider::removeVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference<beans::XVetoableChangeListener>& /*rListener*/ )
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/PivotTableDataSequence.cxx b/sc/source/ui/unoobj/PivotTableDataSequence.cxx
new file mode 100644
index 000000000..03626dc84
--- /dev/null
+++ b/sc/source/ui/unoobj/PivotTableDataSequence.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/.
+ */
+
+#include <memory>
+#include <PivotTableDataSequence.hxx>
+
+#include <sal/config.h>
+#include <sal/log.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+
+#include <miscuno.hxx>
+#include <document.hxx>
+#include <unonames.hxx>
+
+using namespace css;
+
+namespace sc
+{
+
+SC_SIMPLE_SERVICE_INFO( PivotTableDataSequence, "PivotTableDataSequence", "com.sun.star.chart2.data.DataSequence")
+
+static const SfxItemPropertyMapEntry* lcl_GetDataSequencePropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDataSequencePropertyMap_Impl[] =
+ {
+ { SC_UNONAME_HIDDENVALUES, 0, cppu::UnoType<uno::Sequence<sal_Int32>>::get(), 0, 0 },
+ { SC_UNONAME_ROLE, 0, cppu::UnoType<css::chart2::data::DataSequenceRole>::get(), 0, 0 },
+ { SC_UNONAME_INCLUDEHIDDENCELLS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aDataSequencePropertyMap_Impl;
+}
+
+PivotTableDataSequence::PivotTableDataSequence(ScDocument* pDocument, OUString const & sID,
+ std::vector<ValueAndFormat>&& rData)
+ : m_pDocument(pDocument)
+ , m_aID(sID)
+ , m_aData(std::move(rData))
+ , m_aPropSet(lcl_GetDataSequencePropertyMap())
+{
+ if (m_pDocument)
+ m_pDocument->AddUnoObject(*this);
+}
+
+PivotTableDataSequence::~PivotTableDataSequence()
+{
+ SolarMutexGuard g;
+
+ if (m_pDocument)
+ m_pDocument->RemoveUnoObject(*this);
+}
+
+void PivotTableDataSequence::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ m_pDocument = nullptr;
+ }
+}
+
+uno::Sequence<uno::Any> SAL_CALL PivotTableDataSequence::getData()
+{
+ SolarMutexGuard aGuard;
+
+ if (!m_pDocument)
+ throw uno::RuntimeException();
+
+ uno::Sequence<uno::Any> aSeq(m_aData.size());
+ auto pSeq = aSeq.getArray();
+
+ size_t i = 0;
+ for (ValueAndFormat const & rItem : m_aData)
+ {
+ if (rItem.m_eType == ValueType::Numeric)
+ pSeq[i] <<= double(rItem.m_fValue);
+ else if (rItem.m_eType == ValueType::String)
+ pSeq[i] <<= rItem.m_aString;
+
+ i++;
+ }
+ return aSeq;
+}
+
+// XNumericalDataSequence --------------------------------------------------
+
+uno::Sequence<double> SAL_CALL PivotTableDataSequence::getNumericalData()
+{
+ SolarMutexGuard aGuard;
+ if (!m_pDocument)
+ throw uno::RuntimeException();
+
+ uno::Sequence<double> aSeq(m_aData.size());
+ auto pSeq = aSeq.getArray();
+
+ size_t i = 0;
+ for (ValueAndFormat const & rItem : m_aData)
+ {
+ pSeq[i] = rItem.m_fValue;
+ i++;
+ }
+ return aSeq;
+}
+
+// XTextualDataSequence --------------------------------------------------
+
+uno::Sequence<OUString> SAL_CALL PivotTableDataSequence::getTextualData()
+{
+ SolarMutexGuard aGuard;
+ if (!m_pDocument)
+ throw uno::RuntimeException();
+
+ uno::Sequence<OUString> aSeq(m_aData.size());
+ auto pSeq = aSeq.getArray();
+
+ size_t i = 0;
+ for (ValueAndFormat const & rItem : m_aData)
+ {
+ if (rItem.m_eType == ValueType::String)
+ pSeq[i] = rItem.m_aString;
+ i++;
+ }
+ return aSeq;
+}
+
+OUString SAL_CALL PivotTableDataSequence::getSourceRangeRepresentation()
+{
+ SolarMutexGuard aGuard;
+
+ return m_aID;
+}
+
+uno::Sequence<OUString> SAL_CALL PivotTableDataSequence::generateLabel(chart2::data::LabelOrigin /*eOrigin*/)
+{
+ SolarMutexGuard aGuard;
+ if (!m_pDocument)
+ throw uno::RuntimeException();
+
+ uno::Sequence<OUString> aSeq;
+ return aSeq;
+}
+
+sal_Int32 SAL_CALL PivotTableDataSequence::getNumberFormatKeyByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ if (nIndex == -1 && !m_aData.empty())
+ {
+ return m_aData[0].m_nNumberFormat;
+ }
+ else if (nIndex < 0 && o3tl::make_unsigned(nIndex) >= m_aData.size())
+ {
+ SAL_WARN("sc.ui", "Passed invalid index to getNumberFormatKeyByIndex(). Will return default value '0'.");
+ return 0;
+ }
+ return m_aData[size_t(nIndex)].m_nNumberFormat;
+}
+
+// XCloneable ================================================================
+
+uno::Reference<util::XCloneable> SAL_CALL PivotTableDataSequence::createClone()
+{
+ SolarMutexGuard aGuard;
+
+ rtl::Reference<PivotTableDataSequence> pClone(new PivotTableDataSequence(m_pDocument, m_aID, std::vector(m_aData)));
+ pClone->setRole(m_aRole);
+
+ return pClone;
+}
+
+// XModifyBroadcaster ========================================================
+
+void SAL_CALL PivotTableDataSequence::addModifyListener(const uno::Reference<util::XModifyListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+ m_aValueListeners.emplace_back(aListener);
+}
+
+void SAL_CALL PivotTableDataSequence::removeModifyListener(const uno::Reference<util::XModifyListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ sal_uInt16 nCount = m_aValueListeners.size();
+ for (sal_uInt16 n = nCount; n--; )
+ {
+ uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
+ if (rObj == aListener)
+ {
+ m_aValueListeners.erase(m_aValueListeners.begin() + n);
+ }
+ }
+}
+
+// DataSequence XPropertySet -------------------------------------------------
+
+uno::Reference< beans::XPropertySetInfo> SAL_CALL PivotTableDataSequence::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef = new SfxItemPropertySetInfo(m_aPropSet.getPropertyMap());
+ return aRef;
+}
+
+void SAL_CALL PivotTableDataSequence::setPropertyValue(const OUString& rPropertyName, const uno::Any& rValue)
+{
+ if (rPropertyName == SC_UNONAME_ROLE)
+ {
+ if (!(rValue >>= m_aRole))
+ throw lang::IllegalArgumentException();
+ }
+ else if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS
+ || rPropertyName == SC_UNONAME_HIDDENVALUES
+ || rPropertyName == SC_UNONAME_TIME_BASED
+ || rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
+ {}
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+}
+
+uno::Any SAL_CALL PivotTableDataSequence::getPropertyValue(const OUString& rPropertyName)
+{
+ uno::Any aReturn;
+ if (rPropertyName == SC_UNONAME_ROLE)
+ aReturn <<= m_aRole;
+ else if (rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS)
+ aReturn <<= false;
+ else if (rPropertyName == SC_UNONAME_HIDDENVALUES)
+ {
+ css::uno::Sequence<sal_Int32> aHiddenValues;
+ aReturn <<= aHiddenValues;
+ }
+ else if (rPropertyName == SC_UNONAME_TIME_BASED)
+ {
+ aReturn <<= false;
+ }
+ else if (rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
+ {
+ aReturn <<= false;
+ }
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+ return aReturn;
+}
+
+void SAL_CALL PivotTableDataSequence::addPropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataSequence::removePropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataSequence::addVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+void SAL_CALL PivotTableDataSequence::removeVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
+{
+ OSL_FAIL("Not yet implemented");
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/PivotTableDataSource.cxx b/sc/source/ui/unoobj/PivotTableDataSource.cxx
new file mode 100644
index 000000000..5c47f0d12
--- /dev/null
+++ b/sc/source/ui/unoobj/PivotTableDataSource.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 <PivotTableDataSource.hxx>
+
+#include <sal/config.h>
+
+#include <miscuno.hxx>
+
+#include <comphelper/sequence.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace css;
+
+namespace sc
+{
+
+SC_SIMPLE_SERVICE_INFO(PivotTableDataSource, "PivotTableDataSource", "com.sun.star.chart2.data.DataSource")
+
+PivotTableDataSource::PivotTableDataSource(std::vector<css::uno::Reference<css::chart2::data::XLabeledDataSequence>>&& xLabeledSequence)
+ : m_xLabeledSequence(std::move(xLabeledSequence))
+{
+}
+
+PivotTableDataSource::~PivotTableDataSource()
+{
+}
+
+void PivotTableDataSource::Notify(SfxBroadcaster& /*rBroadcaster*/, const SfxHint& /*rHint*/)
+{
+}
+
+uno::Sequence<uno::Reference<chart2::data::XLabeledDataSequence>> SAL_CALL
+ PivotTableDataSource::getDataSequences()
+{
+ SolarMutexGuard aGuard;
+
+ return comphelper::containerToSequence(m_xLabeledSequence);
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/TablePivotChart.cxx b/sc/source/ui/unoobj/TablePivotChart.cxx
new file mode 100644
index 000000000..ecc158002
--- /dev/null
+++ b/sc/source/ui/unoobj/TablePivotChart.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/.
+ */
+
+#include <com/sun/star/chart2/data/XPivotTableDataProvider.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <svx/svdoole2.hxx>
+#include <svtools/embedhlp.hxx>
+#include <vcl/svapp.hxx>
+
+#include <miscuno.hxx>
+#include <docsh.hxx>
+
+#include <TablePivotChart.hxx>
+#include <ChartTools.hxx>
+
+using namespace css;
+
+namespace sc
+{
+
+SC_SIMPLE_SERVICE_INFO(TablePivotChart, "TablePivotChart", "com.sun.star.table.TablePivotChart")
+
+TablePivotChart::TablePivotChart(ScDocShell* pDocShell, SCTAB nTab, const OUString& rName)
+ : m_pDocShell(pDocShell)
+ , m_nTab(nTab)
+ , m_aChartName(rName)
+{
+ if (m_pDocShell)
+ m_pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+TablePivotChart::~TablePivotChart()
+{
+ SolarMutexGuard aGuard;
+
+ if (m_pDocShell)
+ m_pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void TablePivotChart::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ m_pDocShell = nullptr;
+}
+
+// XEmbeddedObjectSupplier
+
+uno::Reference<lang::XComponent> SAL_CALL TablePivotChart::getEmbeddedObject()
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* pObject = sc::tools::findChartsByName(m_pDocShell, m_nTab, m_aChartName, sc::tools::ChartSourceType::PIVOT_TABLE);
+ if (pObject && svt::EmbeddedObjectRef::TryRunningState(pObject->GetObjRef()))
+ return uno::Reference<lang::XComponent>(pObject->GetObjRef()->getComponent(), uno::UNO_QUERY);
+ return nullptr;
+}
+
+// XNamed
+
+OUString SAL_CALL TablePivotChart::getName()
+{
+ return m_aChartName;
+}
+
+void SAL_CALL TablePivotChart::setName(OUString const & /* aName */)
+{
+ throw uno::RuntimeException(); // name cannot be changed
+}
+
+// XTablePivotChart
+
+OUString SAL_CALL TablePivotChart::getPivotTableName()
+{
+ SolarMutexGuard aGuard;
+
+ SdrOle2Obj* pObject = sc::tools::findChartsByName(m_pDocShell, m_nTab, m_aChartName, sc::tools::ChartSourceType::PIVOT_TABLE);
+ if (!pObject)
+ return OUString();
+
+ uno::Reference<embed::XEmbeddedObject> xObject = pObject->GetObjRef();
+ if (!xObject.is())
+ return OUString();
+
+ uno::Reference<chart2::XChartDocument> xChartDoc(xObject->getComponent(), uno::UNO_QUERY);
+ if (!xChartDoc.is())
+ return OUString();
+
+ uno::Reference<chart2::data::XPivotTableDataProvider> xPivotTableDataProvider(xChartDoc->getDataProvider(), uno::UNO_QUERY);
+ if (!xPivotTableDataProvider.is())
+ return OUString();
+
+ return xPivotTableDataProvider->getPivotTableName();
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/TablePivotCharts.cxx b/sc/source/ui/unoobj/TablePivotCharts.cxx
new file mode 100644
index 000000000..b3a32cd45
--- /dev/null
+++ b/sc/source/ui/unoobj/TablePivotCharts.cxx
@@ -0,0 +1,279 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/chart2/data/XDataReceiver.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+
+#include <tools/gen.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdundo.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/classids.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/globname.hxx>
+#include <svtools/embedhlp.hxx>
+#include <comphelper/sequence.hxx>
+#include <vcl/svapp.hxx>
+
+#include <TablePivotChart.hxx>
+#include <TablePivotCharts.hxx>
+#include <PivotTableDataProvider.hxx>
+#include <ChartTools.hxx>
+
+#include <miscuno.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+
+using namespace css;
+
+namespace sc
+{
+
+SC_SIMPLE_SERVICE_INFO(TablePivotCharts, "TablePivotCharts", "com.sun.star.table.TablePivotCharts")
+
+TablePivotCharts::TablePivotCharts(ScDocShell* pDocShell, SCTAB nTab)
+ : m_pDocShell(pDocShell)
+ , m_nTab(nTab)
+{
+ m_pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+TablePivotCharts::~TablePivotCharts()
+{
+ SolarMutexGuard aGuard;
+
+ if (m_pDocShell)
+ m_pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void TablePivotCharts::Notify(SfxBroadcaster& /*rBroadcaster*/, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ m_pDocShell = nullptr;
+}
+
+// XTablePivotCharts
+void SAL_CALL TablePivotCharts::addNewByName(OUString const & rName,
+ const awt::Rectangle& aRect,
+ OUString const & rDataPilotName)
+{
+ SolarMutexGuard aGuard;
+
+ if (!m_pDocShell)
+ return;
+
+ ScDocument& rDoc = m_pDocShell->GetDocument();
+ ScDrawLayer* pModel = m_pDocShell->MakeDrawLayer();
+ SdrPage* pPage = pModel->GetPage(sal_uInt16(m_nTab));
+ if (!pPage)
+ return;
+
+ // chart can't be inserted if any ole object with that name exists on any table
+ // (empty string: generate valid name)
+
+ OUString aName = rName;
+ SCTAB nDummy;
+ if (!aName.isEmpty() && pModel->GetNamedObject(aName, SdrObjKind::OLE2, nDummy))
+ {
+ // object exists - only RuntimeException is specified
+ throw uno::RuntimeException();
+ }
+
+ uno::Reference<embed::XEmbeddedObject> xObject;
+
+ if (SvtModuleOptions().IsChart())
+ xObject = m_pDocShell->GetEmbeddedObjectContainer().CreateEmbeddedObject(SvGlobalName(SO3_SCH_CLASSID).GetByteSequence(), aName);
+
+ if (!xObject.is())
+ return;
+
+ Point aRectPos(aRect.X, aRect.Y);
+ bool bLayoutRTL = rDoc.IsLayoutRTL(m_nTab);
+ if ((aRectPos.X() < 0 && !bLayoutRTL) || (aRectPos.X() > 0 && bLayoutRTL))
+ aRectPos.setX( 0 );
+
+ if (aRectPos.Y() < 0)
+ aRectPos.setY( 0 );
+
+ Size aRectSize(aRect.Width, aRect.Height);
+ if (aRectSize.Width() <= 0)
+ aRectSize.setWidth( 5000 ); // default size
+
+ if (aRectSize.Height() <= 0)
+ aRectSize.setHeight( 5000 );
+
+ ::tools::Rectangle aInsRect(aRectPos, aRectSize);
+
+ sal_Int64 nAspect(embed::Aspects::MSOLE_CONTENT);
+ MapUnit aMapUnit(VCLUnoHelper::UnoEmbed2VCLMapUnit(xObject->getMapUnit(nAspect)));
+ Size aSize(aInsRect.GetSize());
+ aSize = OutputDevice::LogicToLogic(aSize, MapMode(MapUnit::Map100thMM), MapMode(aMapUnit));
+ awt::Size aAwtSize;
+ aAwtSize.Width = aSize.Width();
+ aAwtSize.Height = aSize.Height();
+
+ rtl::Reference<sc::PivotTableDataProvider> pPivotTableDataProvider(new sc::PivotTableDataProvider(rDoc));
+ pPivotTableDataProvider->setPivotTableName(rDataPilotName);
+
+ uno::Reference<chart2::data::XDataProvider> xDataProvider(pPivotTableDataProvider);
+
+ uno::Reference<chart2::data::XDataReceiver> xReceiver;
+
+ if (xObject.is())
+ xReceiver.set(xObject->getComponent(), uno::UNO_QUERY);
+
+ if (xReceiver.is())
+ {
+ xReceiver->attachDataProvider(xDataProvider);
+
+ uno::Reference<util::XNumberFormatsSupplier> xNumberFormatsSupplier(m_pDocShell->GetModel(), uno::UNO_QUERY);
+ xReceiver->attachNumberFormatsSupplier(xNumberFormatsSupplier);
+
+ uno::Sequence<beans::PropertyValue> aArgs( comphelper::InitPropertySequence({
+ { "CellRangeRepresentation", uno::Any(rDataPilotName) },
+ { "HasCategories", uno::Any(true) },
+ { "DataRowSource", uno::Any(chart::ChartDataRowSource_COLUMNS) }
+ }));
+ xReceiver->setArguments(aArgs);
+ }
+
+ SdrOle2Obj* pObject = new SdrOle2Obj(
+ *pModel,
+ svt::EmbeddedObjectRef(xObject, embed::Aspects::MSOLE_CONTENT),
+ aName,
+ aInsRect);
+
+ if (xObject.is())
+ xObject->setVisualAreaSize(nAspect, aAwtSize);
+
+ pPage->InsertObject(pObject);
+ pModel->AddUndo(std::make_unique<SdrUndoInsertObj>(*pObject));
+}
+
+void SAL_CALL TablePivotCharts::removeByName(const OUString& rName)
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* pObject = sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE);
+ if (pObject)
+ {
+ ScDocument& rDoc = m_pDocShell->GetDocument();
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ SdrPage* pPage = pModel->GetPage(sal_uInt16(m_nTab));
+ pModel->AddUndo(std::make_unique<SdrUndoDelObj>(*pObject));
+ pPage->RemoveObject(pObject->GetOrdNum());
+ }
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL TablePivotCharts::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nCount = 0;
+
+ if (!m_pDocShell)
+ return nCount;
+
+ sc::tools::ChartIterator aIterator(m_pDocShell, m_nTab, sc::tools::ChartSourceType::PIVOT_TABLE);
+
+ SdrOle2Obj* pOleObject = aIterator.next();
+ while (pOleObject)
+ {
+ if (pOleObject->GetObjRef().is())
+ nCount++;
+ pOleObject = aIterator.next();
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL TablePivotCharts::getByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* pObject = sc::tools::getChartByIndex(m_pDocShell, m_nTab, nIndex,
+ sc::tools::ChartSourceType::PIVOT_TABLE);
+ if (!pObject)
+ throw lang::IndexOutOfBoundsException();
+
+ OUString aName;
+ uno::Reference<embed::XEmbeddedObject> xObject = pObject->GetObjRef();
+ if (xObject.is())
+ aName = m_pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName(xObject);
+
+ if (aName.isEmpty())
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Reference<table::XTablePivotChart> xChart(new TablePivotChart(m_pDocShell, m_nTab, aName));
+ if (!xChart.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xChart);
+}
+
+uno::Type SAL_CALL TablePivotCharts::getElementType()
+{
+ return cppu::UnoType<table::XTablePivotChart>::get();
+}
+
+sal_Bool SAL_CALL TablePivotCharts::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return getCount() != 0;
+}
+
+uno::Any SAL_CALL TablePivotCharts::getByName(OUString const & rName)
+{
+ SolarMutexGuard aGuard;
+
+ if (!sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE))
+ throw container::NoSuchElementException();
+
+ uno::Reference<table::XTablePivotChart> xChart(new TablePivotChart(m_pDocShell, m_nTab, rName));
+ if (!xChart.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xChart);
+}
+
+uno::Sequence<OUString> SAL_CALL TablePivotCharts::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ std::vector<OUString> aElements;
+ sc::tools::ChartIterator aIterator(m_pDocShell, m_nTab, sc::tools::ChartSourceType::PIVOT_TABLE);
+
+ SdrOle2Obj* pOleObject = aIterator.next();
+ while (pOleObject)
+ {
+ uno::Reference<embed::XEmbeddedObject> xObject = pOleObject->GetObjRef();
+ if (xObject.is())
+ {
+ OUString aName = m_pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName(xObject);
+ aElements.push_back(aName);
+ }
+ pOleObject = aIterator.next();
+ }
+ return comphelper::containerToSequence(aElements);
+}
+
+sal_Bool SAL_CALL TablePivotCharts::hasByName(OUString const & rName)
+{
+ SolarMutexGuard aGuard;
+
+ return sc::tools::findChartsByName(m_pDocShell, m_nTab, rName, sc::tools::ChartSourceType::PIVOT_TABLE) != nullptr;
+}
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/addruno.cxx b/sc/source/ui/unoobj/addruno.cxx
new file mode 100644
index 000000000..177fa119c
--- /dev/null
+++ b/sc/source/ui/unoobj/addruno.cxx
@@ -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 .
+ */
+
+#include <com/sun/star/table/CellAddress.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <svl/itemprop.hxx>
+#include <vcl/svapp.hxx>
+
+#include <docsh.hxx>
+#include <unonames.hxx>
+#include <miscuno.hxx>
+#include <convuno.hxx>
+#include <addruno.hxx>
+
+using namespace com::sun::star;
+
+ScAddressConversionObj::ScAddressConversionObj(ScDocShell* pDocSh, bool _bIsRange) :
+ pDocShell( pDocSh ),
+ nRefSheet( 0 ),
+ bIsRange( _bIsRange )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScAddressConversionObj::~ScAddressConversionObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScAddressConversionObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // invalid
+ }
+}
+
+bool ScAddressConversionObj::ParseUIString( const OUString& rUIString, ::formula::FormulaGrammar::AddressConvention eConv )
+{
+ if (!pDocShell)
+ return false;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bSuccess = false;
+ if ( bIsRange )
+ {
+ ScRefFlags nResult = aRange.ParseAny( rUIString, rDoc, eConv );
+ if ( nResult & ScRefFlags::VALID )
+ {
+ if ( ( nResult & ScRefFlags::TAB_3D ) == ScRefFlags::ZERO )
+ aRange.aStart.SetTab( static_cast<SCTAB>(nRefSheet) );
+ if ( ( nResult & ScRefFlags::TAB2_3D ) == ScRefFlags::ZERO )
+ aRange.aEnd.SetTab( aRange.aStart.Tab() );
+ // different sheets are not supported in CellRangeAddress
+ if ( aRange.aStart.Tab() == aRange.aEnd.Tab() )
+ bSuccess = true;
+ }
+ }
+ else
+ {
+ ScRefFlags nResult = aRange.aStart.Parse( rUIString, rDoc, eConv );
+ if ( nResult & ScRefFlags::VALID )
+ {
+ if ( ( nResult & ScRefFlags::TAB_3D ) == ScRefFlags::ZERO )
+ aRange.aStart.SetTab( static_cast<SCTAB>(nRefSheet) );
+ bSuccess = true;
+ }
+ }
+ return bSuccess;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAddressConversionObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+
+ if ( bIsRange )
+ {
+ static const SfxItemPropertyMapEntry aPropertyMap[] =
+ {
+ { SC_UNONAME_ADDRESS, 0, cppu::UnoType<table::CellRangeAddress>::get(), 0, 0 },
+ { SC_UNONAME_PERSREPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_XLA1REPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_REFSHEET, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_UIREPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_XLA1REPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static uno::Reference<beans::XPropertySetInfo> aRef(new SfxItemPropertySetInfo( aPropertyMap ));
+ return aRef;
+ }
+ else
+ {
+ static const SfxItemPropertyMapEntry aPropertyMap[] =
+ {
+ { SC_UNONAME_ADDRESS, 0, cppu::UnoType<table::CellAddress>::get(), 0, 0 },
+ { SC_UNONAME_PERSREPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_XLA1REPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_REFSHEET, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_UIREPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_XLA1REPR, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static uno::Reference<beans::XPropertySetInfo> aRef(new SfxItemPropertySetInfo( aPropertyMap ));
+ return aRef;
+ }
+}
+
+void SAL_CALL ScAddressConversionObj::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
+{
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ bool bSuccess = false;
+ if ( aPropertyName == SC_UNONAME_ADDRESS )
+ {
+ // read the cell/range address from API struct
+ if ( bIsRange )
+ {
+ table::CellRangeAddress aRangeAddress;
+ if ( aValue >>= aRangeAddress )
+ {
+ ScUnoConversion::FillScRange( aRange, aRangeAddress );
+ bSuccess = true;
+ }
+ }
+ else
+ {
+ table::CellAddress aCellAddress;
+ if ( aValue >>= aCellAddress )
+ {
+ ScUnoConversion::FillScAddress( aRange.aStart, aCellAddress );
+ bSuccess = true;
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_REFSHEET )
+ {
+ // set the reference sheet
+ sal_Int32 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ {
+ nRefSheet = nIntVal;
+ bSuccess = true;
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_UIREPR )
+ {
+ // parse the UI representation string
+ OUString sRepresentation;
+ if (aValue >>= sRepresentation)
+ {
+ bSuccess = ParseUIString( sRepresentation );
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_PERSREPR || aPropertyName == SC_UNONAME_XLA1REPR )
+ {
+ ::formula::FormulaGrammar::AddressConvention eConv = aPropertyName == SC_UNONAME_XLA1REPR ?
+ ::formula::FormulaGrammar::CONV_XL_A1 : ::formula::FormulaGrammar::CONV_OOO;
+
+ // parse the file format string
+ OUString sRepresentation;
+ if (aValue >>= sRepresentation)
+ {
+ OUString aUIString(sRepresentation);
+
+ // cell or range: strip a single "." at the start
+ if ( aUIString[0]== '.' )
+ aUIString = aUIString.copy( 1 );
+
+ if ( bIsRange )
+ {
+ // range: also strip a "." after the last colon
+ sal_Int32 nColon = aUIString.lastIndexOf( ':' );
+ if ( nColon >= 0 && nColon < aUIString.getLength() - 1 &&
+ aUIString[nColon+1] == '.' )
+ aUIString = aUIString.replaceAt( nColon+1, 1, u"" );
+ }
+
+ // parse the rest like a UI string
+ bSuccess = ParseUIString( aUIString, eConv );
+ }
+ }
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ if ( !bSuccess )
+ throw lang::IllegalArgumentException();
+}
+
+uno::Any SAL_CALL ScAddressConversionObj::getPropertyValue( const OUString& aPropertyName )
+{
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ uno::Any aRet;
+
+ if ( aPropertyName == SC_UNONAME_ADDRESS )
+ {
+ if ( bIsRange )
+ {
+ table::CellRangeAddress aRangeAddress;
+ ScUnoConversion::FillApiRange( aRangeAddress, aRange );
+ aRet <<= aRangeAddress;
+ }
+ else
+ {
+ table::CellAddress aCellAddress;
+ ScUnoConversion::FillApiAddress( aCellAddress, aRange.aStart );
+ aRet <<= aCellAddress;
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_REFSHEET )
+ {
+ aRet <<= nRefSheet;
+ }
+ else if ( aPropertyName == SC_UNONAME_UIREPR )
+ {
+ // generate UI representation string - include sheet only if different from ref sheet
+ OUString aFormatStr;
+ ScRefFlags nFlags = ScRefFlags::VALID;
+ if ( aRange.aStart.Tab() != nRefSheet )
+ nFlags |= ScRefFlags::TAB_3D;
+ if ( bIsRange )
+ aFormatStr = aRange.Format(rDoc, nFlags);
+ else
+ aFormatStr = aRange.aStart.Format(nFlags, &rDoc);
+ aRet <<= aFormatStr;
+ }
+ else if ( aPropertyName == SC_UNONAME_PERSREPR || aPropertyName == SC_UNONAME_XLA1REPR )
+ {
+ ::formula::FormulaGrammar::AddressConvention eConv = aPropertyName == SC_UNONAME_XLA1REPR ?
+ ::formula::FormulaGrammar::CONV_XL_A1 : ::formula::FormulaGrammar::CONV_OOO;
+
+ // generate file format string - always include sheet
+ OUString aFormatStr(aRange.aStart.Format(ScRefFlags::VALID | ScRefFlags::TAB_3D, &rDoc, eConv));
+ if ( bIsRange )
+ {
+ // manually concatenate range so both parts always have the sheet name
+ aFormatStr += ":";
+ ScRefFlags nFlags = ScRefFlags::VALID;
+ if( eConv != ::formula::FormulaGrammar::CONV_XL_A1 )
+ nFlags |= ScRefFlags::TAB_3D;
+ OUString aSecond(aRange.aEnd.Format(nFlags, &rDoc, eConv));
+ aFormatStr += aSecond ;
+ }
+ aRet <<= aFormatStr;
+ }
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAddressConversionObj )
+
+// lang::XServiceInfo
+
+OUString SAL_CALL ScAddressConversionObj::getImplementationName()
+{
+ return "ScAddressConversionObj";
+}
+
+sal_Bool SAL_CALL ScAddressConversionObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScAddressConversionObj::getSupportedServiceNames()
+{
+ if (bIsRange)
+ return {SC_SERVICENAME_RANGEADDRESS};
+ else
+ return {SC_SERVICENAME_CELLADDRESS};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/afmtuno.cxx b/sc/source/ui/unoobj/afmtuno.cxx
new file mode 100644
index 000000000..ce0300628
--- /dev/null
+++ b/sc/source/ui/unoobj/afmtuno.cxx
@@ -0,0 +1,724 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/memberids.h>
+#include <osl/diagnose.h>
+#include <svl/poolitem.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <svx/unomid.hxx>
+#include <unowids.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/table/CellHoriJustify.hpp>
+#include <com/sun/star/table/CellOrientation.hpp>
+#include <com/sun/star/table/TableBorder2.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+
+#include <attrib.hxx>
+#include <afmtuno.hxx>
+#include <miscuno.hxx>
+#include <autoform.hxx>
+#include <scdll.hxx>
+#include <unonames.hxx>
+#include <cellsuno.hxx>
+
+using namespace ::com::sun::star;
+
+// an AutoFormat has always 16 entries
+#define SC_AF_FIELD_COUNT 16
+
+// AutoFormat map only for PropertySetInfo without Which-IDs
+
+static const SfxItemPropertyMapEntry* lcl_GetAutoFormatMap()
+{
+ static const SfxItemPropertyMapEntry aAutoFormatMap_Impl[] =
+ {
+ { SC_UNONAME_INCBACK, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_INCBORD, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_INCFONT, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_INCJUST, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_INCNUM, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_INCWIDTH, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aAutoFormatMap_Impl;
+}
+
+//! number format (String/Language) ??? (in XNumberFormat only ReadOnly)
+//! table::TableBorder ??!?
+
+static const SfxItemPropertyMapEntry* lcl_GetAutoFieldMap()
+{
+ static const SfxItemPropertyMapEntry aAutoFieldMap_Impl[] =
+ {
+ { SC_UNONAME_CELLBACK, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ { SC_UNONAME_CCOLOR, ATTR_FONT_COLOR, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT, cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CFONT, ATTR_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, ::cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, ::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT, ::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT, ::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, ::cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, ::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE, ::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE, ::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, ::cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, ::cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE, ::cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, ::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT, ::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT, ::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, ::cppu::UnoType<table::CellHoriJustify>::get(), 0, 0 },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, ::cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aAutoFieldMap_Impl;
+}
+
+constexpr OUStringLiteral SCAUTOFORMATSOBJ_SERVICE = u"com.sun.star.sheet.TableAutoFormats";
+
+SC_SIMPLE_SERVICE_INFO( ScAutoFormatFieldObj, "ScAutoFormatFieldObj", "com.sun.star.sheet.TableAutoFormatField" )
+SC_SIMPLE_SERVICE_INFO( ScAutoFormatObj, "ScAutoFormatObj", "com.sun.star.sheet.TableAutoFormat" )
+SC_SIMPLE_SERVICE_INFO( ScAutoFormatsObj, "stardiv.StarCalc.ScAutoFormatsObj", SCAUTOFORMATSOBJ_SERVICE )
+
+static bool lcl_FindAutoFormatIndex( const ScAutoFormat& rFormats, std::u16string_view rName, sal_uInt16& rOutIndex )
+{
+ ScAutoFormat::const_iterator itBeg = rFormats.begin(), itEnd = rFormats.end();
+ for (ScAutoFormat::const_iterator it = itBeg; it != itEnd; ++it)
+ {
+ const ScAutoFormatData *const pEntry = it->second.get();
+ const OUString& aEntryName = pEntry->GetName();
+ if ( aEntryName == rName )
+ {
+ size_t nPos = std::distance(itBeg, it);
+ rOutIndex = nPos;
+ return true;
+ }
+ }
+ return false;
+}
+
+ScAutoFormatsObj::ScAutoFormatsObj()
+{
+ //! This object should only exist once and it must be known to Auto-Format-Data,
+ //! so that changes can be broadcasted
+}
+
+ScAutoFormatsObj::~ScAutoFormatsObj()
+{
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ScAutoFormatsObj_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScAutoFormatsObj);
+}
+
+// XTableAutoFormats
+
+rtl::Reference<ScAutoFormatObj> ScAutoFormatsObj::GetObjectByIndex_Impl(sal_uInt16 nIndex)
+{
+ if (nIndex < ScGlobal::GetOrCreateAutoFormat()->size())
+ return new ScAutoFormatObj(nIndex);
+
+ return nullptr; // wrong index
+}
+
+rtl::Reference<ScAutoFormatObj> ScAutoFormatsObj::GetObjectByName_Impl(std::u16string_view aName)
+{
+ sal_uInt16 nIndex;
+ if (lcl_FindAutoFormatIndex(
+ *ScGlobal::GetOrCreateAutoFormat(), aName, nIndex ))
+ return GetObjectByIndex_Impl(nIndex);
+ return nullptr;
+}
+
+// container::XNameContainer
+
+void SAL_CALL ScAutoFormatsObj::insertByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ // Reflection need not be uno::XInterface, can be any interface...
+ uno::Reference< uno::XInterface > xInterface(aElement, uno::UNO_QUERY);
+ if ( xInterface.is() )
+ {
+ ScAutoFormatObj* pFormatObj = comphelper::getFromUnoTunnel<ScAutoFormatObj>( xInterface );
+ if ( pFormatObj && !pFormatObj->IsInserted() )
+ {
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+
+ sal_uInt16 nDummy;
+ if (lcl_FindAutoFormatIndex( *pFormats, aName, nDummy ))
+ {
+ throw container::ElementExistException();
+ }
+
+ std::unique_ptr<ScAutoFormatData> pNew(new ScAutoFormatData());
+ pNew->SetName( aName );
+
+ if (pFormats->insert(std::move(pNew)) != pFormats->end())
+ {
+ //! notify to other objects
+ pFormats->Save();
+
+ sal_uInt16 nNewIndex;
+ if (lcl_FindAutoFormatIndex( *pFormats, aName, nNewIndex ))
+ {
+ pFormatObj->InitFormat( nNewIndex ); // can be used now
+ bDone = true;
+ }
+ }
+ else
+ {
+ OSL_FAIL("AutoFormat could not be inserted");
+ throw uno::RuntimeException();
+ }
+ }
+ }
+
+ if (!bDone)
+ {
+ // other errors are handled above
+ throw lang::IllegalArgumentException();
+ }
+}
+
+void SAL_CALL ScAutoFormatsObj::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ //! combine?
+ removeByName( aName );
+ insertByName( aName, aElement );
+}
+
+void SAL_CALL ScAutoFormatsObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+
+ ScAutoFormat::iterator it = pFormats->find(aName);
+ if (it == pFormats->end())
+ {
+ throw container::NoSuchElementException();
+ }
+ pFormats->erase(it);
+
+ //! notify to other objects
+ pFormats->Save(); // save immediately
+
+}
+
+// container::XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScAutoFormatsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.TableAutoFormatEnumeration");
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScAutoFormatsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return ScGlobal::GetOrCreateAutoFormat()->size();
+}
+
+uno::Any SAL_CALL ScAutoFormatsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XNamed > xFormat(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if (!xFormat.is())
+ throw lang::IndexOutOfBoundsException();
+ return uno::Any(xFormat);
+}
+
+uno::Type SAL_CALL ScAutoFormatsObj::getElementType()
+{
+ return cppu::UnoType<container::XNamed>::get(); // must match getByIndex
+}
+
+sal_Bool SAL_CALL ScAutoFormatsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// container::XNameAccess
+
+uno::Any SAL_CALL ScAutoFormatsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XNamed > xFormat(GetObjectByName_Impl(aName));
+ if (!xFormat.is())
+ throw container::NoSuchElementException();
+ return uno::Any(xFormat);
+}
+
+uno::Sequence<OUString> SAL_CALL ScAutoFormatsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ uno::Sequence<OUString> aSeq(pFormats->size());
+ OUString* pAry = aSeq.getArray();
+ size_t i = 0;
+ for (const auto& rEntry : *pFormats)
+ {
+ pAry[i] = rEntry.second->GetName();
+ ++i;
+ }
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScAutoFormatsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nDummy;
+ return lcl_FindAutoFormatIndex(
+ *ScGlobal::GetOrCreateAutoFormat(), aName, nDummy );
+}
+
+ScAutoFormatObj::ScAutoFormatObj(sal_uInt16 nIndex) :
+ aPropSet( lcl_GetAutoFormatMap() ),
+ nFormatIndex( nIndex )
+{
+}
+
+ScAutoFormatObj::~ScAutoFormatObj()
+{
+ // If an AutoFormat object is released, then eventually changes are saved
+ // so that they become visible in e.g Writer
+
+ if (IsInserted())
+ {
+ ScAutoFormat* pFormats = ScGlobal::GetAutoFormat();
+ if ( pFormats && pFormats->IsSaveLater() )
+ pFormats->Save();
+
+ // Save() resets flag SaveLater
+ }
+}
+
+void ScAutoFormatObj::InitFormat( sal_uInt16 nNewIndex )
+{
+ OSL_ENSURE( nFormatIndex == SC_AFMTOBJ_INVALID, "ScAutoFormatObj::InitFormat is multiple" );
+ nFormatIndex = nNewIndex;
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION_IMPL(ScAutoFormatObj);
+
+// XTableAutoFormat
+
+rtl::Reference<ScAutoFormatFieldObj> ScAutoFormatObj::GetObjectByIndex_Impl(sal_uInt16 nIndex)
+{
+ if ( IsInserted() && nIndex < SC_AF_FIELD_COUNT )
+ return new ScAutoFormatFieldObj( nFormatIndex, nIndex );
+
+ return nullptr;
+}
+
+// container::XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScAutoFormatObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.TableAutoFormatEnumeration");
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScAutoFormatObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if (IsInserted())
+ return SC_AF_FIELD_COUNT; // always 16 elements
+ else
+ return 0;
+}
+
+uno::Any SAL_CALL ScAutoFormatObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+
+ if ( nIndex < 0 || nIndex >= getCount() )
+ throw lang::IndexOutOfBoundsException();
+
+ if (IsInserted())
+ return uno::Any(uno::Reference< beans::XPropertySet >(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex))));
+ return uno::Any();
+}
+
+uno::Type SAL_CALL ScAutoFormatObj::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get(); // must match getByIndex
+}
+
+sal_Bool SAL_CALL ScAutoFormatObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// container::XNamed
+
+OUString SAL_CALL ScAutoFormatObj::getName()
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ if (IsInserted() && nFormatIndex < pFormats->size())
+ return pFormats->findByIndex(nFormatIndex)->GetName();
+
+ return OUString();
+}
+
+void SAL_CALL ScAutoFormatObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+
+ sal_uInt16 nDummy;
+ if (!IsInserted() || nFormatIndex >= pFormats->size() ||
+ lcl_FindAutoFormatIndex( *pFormats, aNewName, nDummy ))
+ {
+ // not inserted or name exists
+ throw uno::RuntimeException();
+ }
+
+ ScAutoFormat::iterator it = pFormats->begin();
+ std::advance(it, nFormatIndex);
+ ScAutoFormatData *const pData = it->second.get();
+ OSL_ENSURE(pData,"AutoFormat data not available");
+
+ std::unique_ptr<ScAutoFormatData> pNew(new ScAutoFormatData(*pData));
+ pNew->SetName( aNewName );
+
+ pFormats->erase(it);
+ it = pFormats->insert(std::move(pNew));
+ if (it != pFormats->end())
+ {
+ ScAutoFormat::iterator itBeg = pFormats->begin();
+ nFormatIndex = std::distance(itBeg, it);
+
+ //! notify to other objects
+ pFormats->SetSaveLater(true);
+ }
+ else
+ {
+ OSL_FAIL("AutoFormat could not be inserted");
+ nFormatIndex = 0; //! old index invalid
+ }
+}
+
+// beans::XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAutoFormatObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScAutoFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ if (!(IsInserted() && nFormatIndex < pFormats->size()))
+ return;
+
+ ScAutoFormatData* pData = pFormats->findByIndex(nFormatIndex);
+ OSL_ENSURE(pData,"AutoFormat data not available");
+
+ bool bBool;
+ if (aPropertyName == SC_UNONAME_INCBACK && (aValue >>= bBool))
+ pData->SetIncludeBackground( bBool );
+ else if (aPropertyName == SC_UNONAME_INCBORD && (aValue >>= bBool))
+ pData->SetIncludeFrame( bBool );
+ else if (aPropertyName == SC_UNONAME_INCFONT && (aValue >>= bBool))
+ pData->SetIncludeFont( bBool );
+ else if (aPropertyName == SC_UNONAME_INCJUST && (aValue >>= bBool))
+ pData->SetIncludeJustify( bBool );
+ else if (aPropertyName == SC_UNONAME_INCNUM && (aValue >>= bBool))
+ pData->SetIncludeValueFormat( bBool );
+ else if (aPropertyName == SC_UNONAME_INCWIDTH && (aValue >>= bBool))
+ pData->SetIncludeWidthHeight( bBool );
+
+ // else error
+
+ //! notify to other objects
+ pFormats->SetSaveLater(true);
+}
+
+uno::Any SAL_CALL ScAutoFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aAny;
+
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ if (IsInserted() && nFormatIndex < pFormats->size())
+ {
+ ScAutoFormatData* pData = pFormats->findByIndex(nFormatIndex);
+ OSL_ENSURE(pData,"AutoFormat data not available");
+
+ bool bValue;
+ bool bError = false;
+
+ if (aPropertyName == SC_UNONAME_INCBACK)
+ bValue = pData->GetIncludeBackground();
+ else if (aPropertyName == SC_UNONAME_INCBORD)
+ bValue = pData->GetIncludeFrame();
+ else if (aPropertyName == SC_UNONAME_INCFONT)
+ bValue = pData->GetIncludeFont();
+ else if (aPropertyName == SC_UNONAME_INCJUST)
+ bValue = pData->GetIncludeJustify();
+ else if (aPropertyName == SC_UNONAME_INCNUM)
+ bValue = pData->GetIncludeValueFormat();
+ else if (aPropertyName == SC_UNONAME_INCWIDTH)
+ bValue = pData->GetIncludeWidthHeight();
+ else
+ bError = true; // unknown property
+
+ if (!bError)
+ aAny <<= bValue;
+ }
+
+ return aAny;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAutoFormatObj )
+
+ScAutoFormatFieldObj::ScAutoFormatFieldObj(sal_uInt16 nFormat, sal_uInt16 nField) :
+ aPropSet( lcl_GetAutoFieldMap() ),
+ nFormatIndex( nFormat ),
+ nFieldIndex( nField )
+{
+}
+
+ScAutoFormatFieldObj::~ScAutoFormatFieldObj()
+{
+}
+
+// beans::XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAutoFormatFieldObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScAutoFormatFieldObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ const SfxItemPropertyMapEntry* pEntry =
+ aPropSet.getPropertyMap().getByName( aPropertyName );
+
+ if ( !(pEntry && pEntry->nWID && nFormatIndex < pFormats->size()) )
+ return;
+
+ ScAutoFormatData* pData = pFormats->findByIndex(nFormatIndex);
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ if( const SfxPoolItem* pItem = pData->GetItem( nFieldIndex, pEntry->nWID ) )
+ {
+ bool bDone = false;
+
+ switch( pEntry->nWID )
+ {
+ case ATTR_STACKED:
+ {
+ table::CellOrientation eOrient;
+ if( aValue >>= eOrient )
+ {
+ switch( eOrient )
+ {
+ case table::CellOrientation_STANDARD:
+ pData->PutItem( nFieldIndex, ScVerticalStackCell( false ) );
+ break;
+ case table::CellOrientation_TOPBOTTOM:
+ pData->PutItem( nFieldIndex, ScVerticalStackCell( false ) );
+ pData->PutItem( nFieldIndex, ScRotateValueItem( 27000_deg100 ) );
+ break;
+ case table::CellOrientation_BOTTOMTOP:
+ pData->PutItem( nFieldIndex, ScVerticalStackCell( false ) );
+ pData->PutItem( nFieldIndex, ScRotateValueItem( 9000_deg100 ) );
+ break;
+ case table::CellOrientation_STACKED:
+ pData->PutItem( nFieldIndex, ScVerticalStackCell( true ) );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ bDone = true;
+ }
+ }
+ break;
+ default:
+ std::unique_ptr<SfxPoolItem> pNewItem(pItem->Clone());
+ bDone = pNewItem->PutValue( aValue, pEntry->nMemberId );
+ if (bDone)
+ pData->PutItem( nFieldIndex, *pNewItem );
+ }
+
+ if (bDone)
+ //! Notify to other objects?
+ pFormats->SetSaveLater(true);
+ }
+ }
+ else
+ {
+ switch (pEntry->nWID)
+ {
+ case SC_WID_UNO_TBLBORD:
+ {
+ table::TableBorder aBorder;
+ if ( aValue >>= aBorder ) // empty = nothing to do
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder );
+ pData->PutItem( nFieldIndex, aOuter );
+
+ //! Notify for other objects?
+ pFormats->SetSaveLater(true);
+ }
+ }
+ break;
+ case SC_WID_UNO_TBLBORD2:
+ {
+ table::TableBorder2 aBorder2;
+ if ( aValue >>= aBorder2 ) // empty = nothing to do
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder2 );
+ pData->PutItem( nFieldIndex, aOuter );
+
+ //! Notify for other objects?
+ pFormats->SetSaveLater(true);
+ }
+ }
+ break;
+ }
+ }
+}
+
+uno::Any SAL_CALL ScAutoFormatFieldObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aVal;
+
+ ScAutoFormat* pFormats = ScGlobal::GetOrCreateAutoFormat();
+ const SfxItemPropertyMapEntry* pEntry =
+ aPropSet.getPropertyMap().getByName( aPropertyName );
+
+ if ( pEntry && pEntry->nWID && nFormatIndex < pFormats->size() )
+ {
+ const ScAutoFormatData* pData = pFormats->findByIndex(nFormatIndex);
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ if( const SfxPoolItem* pItem = pData->GetItem( nFieldIndex, pEntry->nWID ) )
+ {
+ switch( pEntry->nWID )
+ {
+ case ATTR_STACKED:
+ {
+ const ScRotateValueItem* pRotItem = pData->GetItem( nFieldIndex, ATTR_ROTATE_VALUE );
+ Degree100 nRot = pRotItem ? pRotItem->GetValue() : 0_deg100;
+ bool bStacked = static_cast<const ScVerticalStackCell*>(pItem)->GetValue();
+ SvxOrientationItem( nRot, bStacked, TypedWhichId<SvxOrientationItem>(0) ).QueryValue( aVal );
+ }
+ break;
+ default:
+ pItem->QueryValue( aVal, pEntry->nMemberId );
+ }
+ }
+ }
+ else
+ {
+ switch (pEntry->nWID)
+ {
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ {
+ const SfxPoolItem* pItem = pData->GetItem(nFieldIndex, ATTR_BORDER);
+ if (pItem)
+ {
+ SvxBoxItem aOuter(*static_cast<const SvxBoxItem*>(pItem));
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+
+ if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
+ ScHelperFunctions::AssignTableBorder2ToAny( aVal, aOuter, aInner);
+ else
+ ScHelperFunctions::AssignTableBorderToAny( aVal, aOuter, aInner);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return aVal;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAutoFormatFieldObj )
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/appluno.cxx b/sc/source/ui/unoobj/appluno.cxx
new file mode 100644
index 000000000..998d7ef50
--- /dev/null
+++ b/sc/source/ui/unoobj/appluno.cxx
@@ -0,0 +1,621 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <appluno.hxx>
+#include <sal/types.h>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <formula/funcvarargs.h>
+
+#include <vcl/svapp.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/sfxmodelfactory.hxx>
+#include <miscuno.hxx>
+#include <scmod.hxx>
+#include <appoptio.hxx>
+#include <inputopt.hxx>
+#include <printopt.hxx>
+#include <userlist.hxx>
+#include <scdll.hxx>
+#include <unonames.hxx>
+#include <funcdesc.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/sheet/FunctionArgument.hpp>
+#include <memory>
+
+using namespace com::sun::star;
+
+// Special value for zoom
+//! somewhere central
+#define SC_ZOOMVAL_OPTIMAL (-1)
+#define SC_ZOOMVAL_WHOLEPAGE (-2)
+#define SC_ZOOMVAL_PAGEWIDTH (-3)
+
+// Number of PropertyValues in a function description
+#define SC_FUNCDESC_PROPCOUNT 5
+
+// everything without Which-ID, map only for PropertySetInfo
+
+static const SfxItemPropertyMapEntry* lcl_GetSettingsPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aSettingsPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_DOAUTOCP, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ENTERED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_EXPREF, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_EXTFMT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_LINKUPD, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_MARKHDR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_METRIC, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_MOVEDIR, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_MOVESEL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_PRALLSH, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_PREMPTY, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_RANGEFIN, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_SCALE, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_STBFUNC, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_ULISTS, 0, cppu::UnoType<uno::Sequence<OUString>>::get(), 0, 0},
+ { SC_UNONAME_PRMETRICS,0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_USETABCOL,0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_REPLWARN, 0, cppu::UnoType<bool>::get(), 0, 0},
+ {u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aSettingsPropertyMap_Impl;
+}
+
+constexpr OUStringLiteral SCFUNCTIONLISTOBJ_SERVICE = u"com.sun.star.sheet.FunctionDescriptions";
+constexpr OUStringLiteral SCRECENTFUNCTIONSOBJ_SERVICE = u"com.sun.star.sheet.RecentFunctions";
+constexpr OUStringLiteral SCSPREADSHEETSETTINGS_SERVICE = u"com.sun.star.sheet.GlobalSheetSettings";
+
+SC_SIMPLE_SERVICE_INFO( ScFunctionListObj, "stardiv.StarCalc.ScFunctionListObj", SCFUNCTIONLISTOBJ_SERVICE )
+SC_SIMPLE_SERVICE_INFO( ScRecentFunctionsObj, "stardiv.StarCalc.ScRecentFunctionsObj", SCRECENTFUNCTIONSOBJ_SERVICE )
+SC_SIMPLE_SERVICE_INFO( ScSpreadsheetSettings, "stardiv.StarCalc.ScSpreadsheetSettings", SCSPREADSHEETSETTINGS_SERVICE )
+
+
+ScSpreadsheetSettings::ScSpreadsheetSettings() :
+ aPropSet( lcl_GetSettingsPropertyMap() )
+{
+}
+
+ScSpreadsheetSettings::~ScSpreadsheetSettings()
+{
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_ScSpreadsheetSettings_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScSpreadsheetSettings());
+}
+
+
+bool ScSpreadsheetSettings::getPropertyBool(const OUString& aPropertyName)
+{
+ uno::Any any = getPropertyValue(aPropertyName);
+ bool b = false;
+ any >>= b;
+ return b;
+}
+
+sal_Int16 ScSpreadsheetSettings::getPropertyInt16(const OUString& aPropertyName)
+{
+ uno::Any any = getPropertyValue(aPropertyName);
+ sal_Int16 b = 0;
+ any >>= b;
+ return b;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSpreadsheetSettings::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScSpreadsheetSettings::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ ScModule* pScMod = SC_MOD();
+ ScAppOptions aAppOpt(pScMod->GetAppOptions());
+ ScInputOptions aInpOpt(pScMod->GetInputOptions());
+ bool bSaveApp = false;
+ bool bSaveInp = false;
+ // print options aren't loaded until needed
+
+ if (aPropertyName == SC_UNONAME_DOAUTOCP)
+ {
+ aAppOpt.SetAutoComplete( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveApp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_ENTERED)
+ {
+ aInpOpt.SetEnterEdit( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_EXPREF)
+ {
+ aInpOpt.SetExpandRefs( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_EXTFMT)
+ {
+ aInpOpt.SetExtendFormat( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_LINKUPD)
+ {
+ // XXX NOTE: this is not css::document::Settings property
+ // LinkUpdateMode but css::sheet::XGlobalSheetSettings attribute
+ // LinkUpdateMode.
+ sal_Int16 n;
+ if (!(aValue >>= n) || n < 0 || n >= ScLkUpdMode::LM_UNKNOWN)
+ {
+ throw css::lang::IllegalArgumentException(
+ ("LinkUpdateMode property value must be a SHORT with a value in the range of 0--2"
+ " as documented for css::sheet::XGlobalSheetSettings attribute LinkUpdateMode"),
+ css::uno::Reference<css::uno::XInterface>(), -1);
+ }
+ aAppOpt.SetLinkMode( static_cast<ScLkUpdMode>(n) );
+ bSaveApp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_MARKHDR)
+ {
+ aInpOpt.SetMarkHeader( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_MOVESEL)
+ {
+ aInpOpt.SetMoveSelection( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_RANGEFIN)
+ {
+ aInpOpt.SetRangeFinder( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_USETABCOL)
+ {
+ aInpOpt.SetUseTabCol( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_PRMETRICS)
+ {
+ aInpOpt.SetTextWysiwyg( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_REPLWARN)
+ {
+ aInpOpt.SetReplaceCellsWarn( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_METRIC)
+ {
+ aAppOpt.SetAppMetric( static_cast<FieldUnit>(ScUnoHelpFunctions::GetInt16FromAny( aValue )) );
+ bSaveApp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_MOVEDIR)
+ {
+ aInpOpt.SetMoveDir( ScUnoHelpFunctions::GetInt16FromAny( aValue ) );
+ bSaveInp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_SCALE)
+ {
+ short nVal = ScUnoHelpFunctions::GetInt16FromAny( aValue );
+ if ( nVal < 0 )
+ {
+ SvxZoomType eType = SvxZoomType::PERCENT;
+ switch (nVal)
+ {
+ case SC_ZOOMVAL_OPTIMAL: eType = SvxZoomType::OPTIMAL; break;
+ case SC_ZOOMVAL_WHOLEPAGE: eType = SvxZoomType::WHOLEPAGE; break;
+ case SC_ZOOMVAL_PAGEWIDTH: eType = SvxZoomType::PAGEWIDTH; break;
+ }
+ aAppOpt.SetZoomType( eType );
+ }
+ else if ( nVal >= MINZOOM && nVal <= MAXZOOM )
+ {
+ aAppOpt.SetZoom( nVal );
+ aAppOpt.SetZoomType( SvxZoomType::PERCENT );
+ }
+ bSaveApp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_STBFUNC)
+ {
+ aAppOpt.SetStatusFunc( ScUnoHelpFunctions::GetInt16FromAny( aValue ) );
+ bSaveApp = true;
+ }
+ else if (aPropertyName == SC_UNONAME_ULISTS)
+ {
+ ScUserList* pUserList = ScGlobal::GetUserList();
+ uno::Sequence<OUString> aSeq;
+ if ( pUserList && ( aValue >>= aSeq ) )
+ {
+ // directly change the active list
+ // ScGlobal::SetUseTabCol does not do much else
+
+ pUserList->clear();
+ for (const OUString& aEntry : std::as_const(aSeq))
+ {
+ ScUserListData* pData = new ScUserListData(aEntry);
+ pUserList->push_back(pData);
+ }
+ bSaveApp = true; // List with App-Options are saved
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_PRALLSH)
+ {
+ ScPrintOptions aPrintOpt(pScMod->GetPrintOptions());
+ aPrintOpt.SetAllSheets( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ pScMod->SetPrintOptions( aPrintOpt );
+ }
+ else if (aPropertyName == SC_UNONAME_PREMPTY)
+ {
+ ScPrintOptions aPrintOpt(pScMod->GetPrintOptions());
+ aPrintOpt.SetSkipEmpty( !ScUnoHelpFunctions::GetBoolFromAny( aValue ) ); // reversed
+ pScMod->SetPrintOptions( aPrintOpt );
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScPrintOptions ) ); // update previews
+ }
+
+ if ( bSaveApp )
+ pScMod->SetAppOptions( aAppOpt );
+ if ( bSaveInp )
+ pScMod->SetInputOptions( aInpOpt );
+}
+
+uno::Any SAL_CALL ScSpreadsheetSettings::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ ScModule* pScMod = SC_MOD();
+ ScAppOptions aAppOpt = pScMod->GetAppOptions();
+ const ScInputOptions& aInpOpt = pScMod->GetInputOptions();
+ // print options aren't loaded until needed
+
+ if (aPropertyName == SC_UNONAME_DOAUTOCP) aRet <<= aAppOpt.GetAutoComplete();
+ else if (aPropertyName == SC_UNONAME_ENTERED ) aRet <<= aInpOpt.GetEnterEdit();
+ else if (aPropertyName == SC_UNONAME_EXPREF ) aRet <<= aInpOpt.GetExpandRefs();
+ else if (aPropertyName == SC_UNONAME_EXTFMT ) aRet <<= aInpOpt.GetExtendFormat();
+ else if (aPropertyName == SC_UNONAME_LINKUPD ) aRet <<= static_cast<sal_Int16>(aAppOpt.GetLinkMode());
+ else if (aPropertyName == SC_UNONAME_MARKHDR ) aRet <<= aInpOpt.GetMarkHeader();
+ else if (aPropertyName == SC_UNONAME_MOVESEL ) aRet <<= aInpOpt.GetMoveSelection();
+ else if (aPropertyName == SC_UNONAME_RANGEFIN ) aRet <<= aInpOpt.GetRangeFinder();
+ else if (aPropertyName == SC_UNONAME_USETABCOL ) aRet <<= aInpOpt.GetUseTabCol();
+ else if (aPropertyName == SC_UNONAME_PRMETRICS ) aRet <<= aInpOpt.GetTextWysiwyg();
+ else if (aPropertyName == SC_UNONAME_REPLWARN ) aRet <<= aInpOpt.GetReplaceCellsWarn();
+ else if (aPropertyName == SC_UNONAME_METRIC ) aRet <<= static_cast<sal_Int16>(aAppOpt.GetAppMetric());
+ else if (aPropertyName == SC_UNONAME_MOVEDIR ) aRet <<= static_cast<sal_Int16>(aInpOpt.GetMoveDir());
+ else if (aPropertyName == SC_UNONAME_STBFUNC ) aRet <<= static_cast<sal_Int16>(aAppOpt.GetStatusFunc());
+ else if (aPropertyName == SC_UNONAME_SCALE )
+ {
+ sal_Int16 nZoomVal = 0;
+ switch ( aAppOpt.GetZoomType() )
+ {
+ case SvxZoomType::PERCENT: nZoomVal = aAppOpt.GetZoom(); break;
+ case SvxZoomType::OPTIMAL: nZoomVal = SC_ZOOMVAL_OPTIMAL; break;
+ case SvxZoomType::WHOLEPAGE: nZoomVal = SC_ZOOMVAL_WHOLEPAGE; break;
+ case SvxZoomType::PAGEWIDTH: nZoomVal = SC_ZOOMVAL_PAGEWIDTH; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ aRet <<= nZoomVal;
+ }
+ else if (aPropertyName == SC_UNONAME_ULISTS )
+ {
+ ScUserList* pUserList = ScGlobal::GetUserList();
+ if (pUserList)
+ {
+ size_t nCount = pUserList->size();
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ OUString aEntry((*pUserList)[i].GetString());
+ pAry[i] = aEntry;
+ }
+ aRet <<= aSeq;
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_PRALLSH )
+ aRet <<= pScMod->GetPrintOptions().GetAllSheets();
+ else if (aPropertyName == SC_UNONAME_PREMPTY )
+ aRet <<= !pScMod->GetPrintOptions().GetSkipEmpty(); // reversed
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSpreadsheetSettings )
+
+ScRecentFunctionsObj::ScRecentFunctionsObj()
+{
+}
+
+ScRecentFunctionsObj::~ScRecentFunctionsObj()
+{
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ScRecentFunctionsObj_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScRecentFunctionsObj());
+}
+
+// XRecentFunctions
+
+uno::Sequence<sal_Int32> SAL_CALL ScRecentFunctionsObj::getRecentFunctionIds()
+{
+ SolarMutexGuard aGuard;
+ const ScAppOptions& rOpt = SC_MOD()->GetAppOptions();
+ sal_uInt16 nCount = rOpt.GetLRUFuncListCount();
+ const sal_uInt16* pFuncs = rOpt.GetLRUFuncList();
+ if (pFuncs)
+ {
+ uno::Sequence<sal_Int32> aSeq(nCount);
+ sal_Int32* pAry = aSeq.getArray();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ pAry[i] = pFuncs[i];
+ return aSeq;
+ }
+ return {};
+}
+
+void SAL_CALL ScRecentFunctionsObj::setRecentFunctionIds(
+ const uno::Sequence<sal_Int32>& aRecentFunctionIds )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = static_cast<sal_uInt16>(std::min( aRecentFunctionIds.getLength(), sal_Int32(LRU_MAX) ));
+ const sal_Int32* pAry = aRecentFunctionIds.getConstArray();
+
+ std::unique_ptr<sal_uInt16[]> pFuncs(nCount ? new sal_uInt16[nCount] : nullptr);
+ for (sal_uInt16 i=0; i<nCount; i++)
+ pFuncs[i] = static_cast<sal_uInt16>(pAry[i]); //! check for valid values?
+
+ ScModule* pScMod = SC_MOD();
+ ScAppOptions aNewOpts(pScMod->GetAppOptions());
+ aNewOpts.SetLRUFuncList(pFuncs.get(), nCount);
+ pScMod->SetAppOptions(aNewOpts);
+}
+
+sal_Int32 SAL_CALL ScRecentFunctionsObj::getMaxRecentFunctions()
+{
+ return LRU_MAX;
+}
+
+ScFunctionListObj::ScFunctionListObj()
+{
+}
+
+ScFunctionListObj::~ScFunctionListObj()
+{
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ScFunctionListObj_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScFunctionListObj());
+}
+
+static void lcl_FillSequence( uno::Sequence<beans::PropertyValue>& rSequence, const ScFuncDesc& rDesc )
+{
+ rDesc.initArgumentInfo(); // full argument info is needed
+
+ OSL_ENSURE( rSequence.getLength() == SC_FUNCDESC_PROPCOUNT, "Wrong count" );
+
+ beans::PropertyValue* pArray = rSequence.getArray();
+
+ pArray[0].Name = SC_UNONAME_ID;
+ pArray[0].Value <<= static_cast<sal_Int32>(rDesc.nFIndex);
+
+ pArray[1].Name = SC_UNONAME_CATEGORY;
+ pArray[1].Value <<= static_cast<sal_Int32>(rDesc.nCategory);
+
+ pArray[2].Name = SC_UNONAME_NAME;
+ if (rDesc.mxFuncName)
+ pArray[2].Value <<= *rDesc.mxFuncName;
+
+ pArray[3].Name = SC_UNONAME_DESCRIPTION;
+ if (rDesc.mxFuncDesc)
+ pArray[3].Value <<= *rDesc.mxFuncDesc;
+
+ pArray[4].Name = SC_UNONAME_ARGUMENTS;
+ if (rDesc.maDefArgNames.empty() || rDesc.maDefArgDescs.empty() || !rDesc.pDefArgFlags)
+ return;
+
+ sal_uInt16 nCount = rDesc.nArgCount;
+ if (nCount >= PAIRED_VAR_ARGS)
+ nCount -= PAIRED_VAR_ARGS - 2;
+ else if (nCount >= VAR_ARGS)
+ nCount -= VAR_ARGS - 1;
+ sal_uInt16 nSeqCount = rDesc.GetSuppressedArgCount();
+ if (nSeqCount >= PAIRED_VAR_ARGS)
+ nSeqCount -= PAIRED_VAR_ARGS - 2;
+ else if (nSeqCount >= VAR_ARGS)
+ nSeqCount -= VAR_ARGS - 1;
+
+ if (!nSeqCount)
+ return;
+
+ uno::Sequence<sheet::FunctionArgument> aArgSeq(nSeqCount);
+ sheet::FunctionArgument* pArgAry = aArgSeq.getArray();
+ for (sal_uInt16 i=0, j=0; i<nCount; i++)
+ {
+ sheet::FunctionArgument aArgument;
+ aArgument.Name = rDesc.maDefArgNames[i];
+ aArgument.Description = rDesc.maDefArgDescs[i];
+ aArgument.IsOptional = rDesc.pDefArgFlags[i].bOptional;
+ pArgAry[j++] = aArgument;
+ }
+ pArray[4].Value <<= aArgSeq;
+}
+
+// XFunctionDescriptions
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScFunctionListObj::getById( sal_Int32 nId )
+{
+ SolarMutexGuard aGuard;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( !pFuncList )
+ throw uno::RuntimeException(); // should not happen
+
+ sal_uInt16 nCount = static_cast<sal_uInt16>(pFuncList->GetCount());
+ for (sal_uInt16 nIndex=0; nIndex<nCount; nIndex++)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(nIndex);
+ if ( pDesc && pDesc->nFIndex == nId )
+ {
+ uno::Sequence<beans::PropertyValue> aSeq( SC_FUNCDESC_PROPCOUNT );
+ lcl_FillSequence( aSeq, *pDesc );
+ return aSeq;
+ }
+ }
+
+ throw lang::IllegalArgumentException(); // not found
+}
+
+// XNameAccess
+
+uno::Any SAL_CALL ScFunctionListObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( !pFuncList )
+ throw uno::RuntimeException(); // should not happen
+
+ sal_uInt16 nCount = static_cast<sal_uInt16>(pFuncList->GetCount());
+ for (sal_uInt16 nIndex=0; nIndex<nCount; nIndex++)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(nIndex);
+ //! Case-insensitive???
+ if ( pDesc && pDesc->mxFuncName && aName == *pDesc->mxFuncName )
+ {
+ uno::Sequence<beans::PropertyValue> aSeq( SC_FUNCDESC_PROPCOUNT );
+ lcl_FillSequence( aSeq, *pDesc );
+ return uno::Any(aSeq);
+ }
+ }
+
+ throw container::NoSuchElementException(); // not found
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScFunctionListObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nCount = 0;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( pFuncList )
+ nCount = static_cast<sal_Int32>(pFuncList->GetCount());
+ return nCount;
+}
+
+uno::Any SAL_CALL ScFunctionListObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( !pFuncList )
+ throw uno::RuntimeException(); // should not happen
+
+ if ( nIndex >= 0 && o3tl::make_unsigned(nIndex) < pFuncList->GetCount() )
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(nIndex);
+ if ( pDesc )
+ {
+ uno::Sequence<beans::PropertyValue> aSeq( SC_FUNCDESC_PROPCOUNT );
+ lcl_FillSequence( aSeq, *pDesc );
+ return uno::Any(aSeq);
+ }
+ }
+
+ throw lang::IndexOutOfBoundsException(); // illegal index
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScFunctionListObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.FunctionDescriptionEnumeration");
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScFunctionListObj::getElementType()
+{
+ return cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get();
+}
+
+sal_Bool SAL_CALL ScFunctionListObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() > 0 );
+}
+
+uno::Sequence<OUString> SAL_CALL ScFunctionListObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( pFuncList )
+ {
+ sal_uInt32 nCount = pFuncList->GetCount();
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(nIndex);
+ if ( pDesc && pDesc->mxFuncName )
+ pAry[nIndex] = *pDesc->mxFuncName;
+ }
+ return aSeq;
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScFunctionListObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( pFuncList )
+ {
+ sal_uInt32 nCount = pFuncList->GetCount();
+ for (sal_uInt32 nIndex=0; nIndex<nCount; ++nIndex)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction(nIndex);
+ //! Case-insensitive???
+ if ( pDesc && pDesc->mxFuncName && aName == *pDesc->mxFuncName )
+ return true;
+ }
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/celllistsource.cxx b/sc/source/ui/unoobj/celllistsource.cxx
new file mode 100644
index 000000000..37704a503
--- /dev/null
+++ b/sc/source/ui/unoobj/celllistsource.cxx
@@ -0,0 +1,433 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "celllistsource.hxx"
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/NotInitializedException.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/FormulaResult.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace calc
+{
+
+#define PROP_HANDLE_RANGE_ADDRESS 1
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::table;
+ using namespace ::com::sun::star::text;
+ using namespace ::com::sun::star::sheet;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::form::binding;
+
+ OCellListSource::OCellListSource( const Reference< XSpreadsheetDocument >& _rxDocument )
+ :OCellListSource_Base( m_aMutex )
+ ,OCellListSource_PBase( OCellListSource_Base::rBHelper )
+ ,m_xDocument( _rxDocument )
+ ,m_aListEntryListeners( m_aMutex )
+ ,m_bInitialized( false )
+ {
+ OSL_PRECOND( m_xDocument.is(), "OCellListSource::OCellListSource: invalid document!" );
+
+ // register our property at the base class
+ registerPropertyNoMember(
+ "CellRange",
+ PROP_HANDLE_RANGE_ADDRESS,
+ PropertyAttribute::BOUND | PropertyAttribute::READONLY,
+ cppu::UnoType<CellRangeAddress>::get(),
+ css::uno::Any(CellRangeAddress())
+ );
+ }
+
+ OCellListSource::~OCellListSource( )
+ {
+ if ( !OCellListSource_Base::rBHelper.bDisposed )
+ {
+ acquire(); // prevent duplicate dtor
+ dispose();
+ }
+ }
+
+ IMPLEMENT_FORWARD_XINTERFACE2( OCellListSource, OCellListSource_Base, OCellListSource_PBase )
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCellListSource, OCellListSource_Base, OCellListSource_PBase )
+
+ void SAL_CALL OCellListSource::disposing()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ Reference<XModifyBroadcaster> xBroadcaster( m_xRange, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->removeModifyListener( this );
+ }
+
+ EventObject aDisposeEvent( *this );
+ m_aListEntryListeners.disposeAndClear( aDisposeEvent );
+
+ WeakAggComponentImplHelperBase::disposing();
+
+ // TODO: clean up here whatever you need to clean up (e.g. revoking listeners etc.)
+ }
+
+ Reference< XPropertySetInfo > SAL_CALL OCellListSource::getPropertySetInfo( )
+ {
+ return createPropertySetInfo( getInfoHelper() ) ;
+ }
+
+ ::cppu::IPropertyArrayHelper& SAL_CALL OCellListSource::getInfoHelper()
+ {
+ return *OCellListSource_PABase::getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* OCellListSource::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper(aProps);
+ }
+
+ void SAL_CALL OCellListSource::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
+ {
+ OSL_ENSURE( _nHandle == PROP_HANDLE_RANGE_ADDRESS, "OCellListSource::getFastPropertyValue: invalid handle!" );
+ // we only have this one property...
+
+ _rValue <<= getRangeAddress( );
+ }
+
+ void OCellListSource::checkDisposed( ) const
+ {
+ if ( OCellListSource_Base::rBHelper.bInDispose || OCellListSource_Base::rBHelper.bDisposed )
+ throw DisposedException();
+ // TODO: is it worth having an error message here?
+ }
+
+ void OCellListSource::checkInitialized()
+ {
+ if ( !m_bInitialized )
+ throw NotInitializedException("CellListSource is not initialized", static_cast<cppu::OWeakObject*>(this));
+ }
+
+ OUString SAL_CALL OCellListSource::getImplementationName( )
+ {
+ return "com.sun.star.comp.sheet.OCellListSource";
+ }
+
+ sal_Bool SAL_CALL OCellListSource::supportsService( const OUString& _rServiceName )
+ {
+ return cppu::supportsService(this, _rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL OCellListSource::getSupportedServiceNames( )
+ {
+ return {"com.sun.star.table.CellRangeListSource",
+ "com.sun.star.form.binding.ListEntrySource"};
+ }
+
+ CellRangeAddress OCellListSource::getRangeAddress( ) const
+ {
+ OSL_PRECOND( m_xRange.is(), "OCellListSource::getRangeAddress: invalid range!" );
+
+ CellRangeAddress aAddress;
+ Reference< XCellRangeAddressable > xRangeAddress( m_xRange, UNO_QUERY );
+ if ( xRangeAddress.is() )
+ aAddress = xRangeAddress->getRangeAddress( );
+ return aAddress;
+ }
+
+ OUString OCellListSource::getCellTextContent_noCheck( sal_Int32 _nRangeRelativeRow, css::uno::Any* pAny )
+ {
+ OUString sText;
+
+ OSL_PRECOND( m_xRange.is(), "OCellListSource::getRangeAddress: invalid range!" );
+
+ if (!m_xRange.is())
+ return sText;
+
+ Reference< XCell > xCell( m_xRange->getCellByPosition( 0, _nRangeRelativeRow ));
+ if (!xCell.is())
+ {
+ if (pAny)
+ *pAny <<= sText;
+ return sText;
+ }
+
+ Reference< XTextRange > xCellText;
+ xCellText.set( xCell, UNO_QUERY);
+
+ if (xCellText.is())
+ sText = xCellText->getString(); // formatted output string
+
+ if (pAny)
+ {
+ switch (xCell->getType())
+ {
+ case CellContentType_VALUE:
+ *pAny <<= xCell->getValue();
+ break;
+ case CellContentType_TEXT:
+ *pAny <<= sText;
+ break;
+ case CellContentType_FORMULA:
+ if (xCell->getError())
+ *pAny <<= sText; // Err:... or #...!
+ else
+ {
+ Reference< XPropertySet > xProp( xCell, UNO_QUERY);
+ if (xProp.is())
+ {
+ sal_Int32 nResultType;
+ if ((xProp->getPropertyValue("FormulaResultType2") >>= nResultType) &&
+ nResultType == FormulaResult::VALUE)
+ *pAny <<= xCell->getValue();
+ else
+ *pAny <<= sText;
+ }
+ }
+ break;
+ case CellContentType_EMPTY:
+ *pAny <<= OUString();
+ break;
+ default:
+ ; // nothing, if actually occurred it would result in #N/A being displayed if selected
+ }
+ }
+
+ return sText;
+ }
+
+ sal_Int32 SAL_CALL OCellListSource::getListEntryCount( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ CellRangeAddress aAddress( getRangeAddress( ) );
+ return aAddress.EndRow - aAddress.StartRow + 1;
+ }
+
+ OUString SAL_CALL OCellListSource::getListEntry( sal_Int32 _nPosition )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ if ( _nPosition >= getListEntryCount() )
+ throw IndexOutOfBoundsException();
+
+ return getCellTextContent_noCheck( _nPosition, nullptr );
+ }
+
+ Sequence< OUString > SAL_CALL OCellListSource::getAllListEntries( )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ Sequence< OUString > aAllEntries( getListEntryCount() );
+ OUString* pAllEntries = aAllEntries.getArray();
+ for ( sal_Int32 i = 0; i < aAllEntries.getLength(); ++i )
+ {
+ *pAllEntries++ = getCellTextContent_noCheck( i, nullptr );
+ }
+
+ return aAllEntries;
+ }
+
+ Sequence< OUString > SAL_CALL OCellListSource::getAllListEntriesTyped( Sequence< Any >& rDataValues )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ const sal_Int32 nCount = getListEntryCount();
+ Sequence< OUString > aAllEntries( nCount );
+ rDataValues = Sequence< Any >( nCount );
+ OUString* pAllEntries = aAllEntries.getArray();
+ Any* pDataValues = rDataValues.getArray();
+ for ( sal_Int32 i = 0; i < nCount; ++i )
+ {
+ *pAllEntries++ = getCellTextContent_noCheck( i, pDataValues++ );
+ }
+
+ return aAllEntries;
+ }
+
+ void SAL_CALL OCellListSource::addListEntryListener( const Reference< XListEntryListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ if ( !_rxListener.is() )
+ throw NullPointerException();
+
+ m_aListEntryListeners.addInterface( _rxListener );
+ }
+
+ void SAL_CALL OCellListSource::removeListEntryListener( const Reference< XListEntryListener >& _rxListener )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed();
+ checkInitialized();
+
+ if ( !_rxListener.is() )
+ throw NullPointerException();
+
+ m_aListEntryListeners.removeInterface( _rxListener );
+ }
+
+ void SAL_CALL OCellListSource::modified( const EventObject& /* aEvent */ )
+ {
+ notifyModified();
+ }
+
+ void OCellListSource::notifyModified()
+ {
+ EventObject aEvent;
+ aEvent.Source.set(*this);
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter( m_aListEntryListeners );
+ while ( aIter.hasMoreElements() )
+ {
+ try
+ {
+ aIter.next()->allEntriesChanged( aEvent );
+ }
+ catch( const RuntimeException& )
+ {
+ // silent this
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "OCellListSource::notifyModified: caught a (non-runtime) exception!" );
+ }
+ }
+
+ }
+
+ void SAL_CALL OCellListSource::disposing( const EventObject& aEvent )
+ {
+ Reference<XInterface> xRangeInt( m_xRange, UNO_QUERY );
+ if ( xRangeInt == aEvent.Source )
+ {
+ // release references to range object
+ m_xRange.clear();
+ }
+ }
+
+ void SAL_CALL OCellListSource::initialize( const Sequence< Any >& _rArguments )
+ {
+ if ( m_bInitialized )
+ throw RuntimeException("CellListSource is already initialized", static_cast<cppu::OWeakObject*>(this));
+
+ // get the cell address
+ CellRangeAddress aRangeAddress;
+ bool bFoundAddress = false;
+
+ for ( const Any& rArg : _rArguments )
+ {
+ NamedValue aValue;
+ if ( rArg >>= aValue )
+ {
+ if ( aValue.Name == "CellRange" )
+ {
+ if ( aValue.Value >>= aRangeAddress )
+ {
+ bFoundAddress = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !bFoundAddress )
+ throw RuntimeException("Cell not found", static_cast<cppu::OWeakObject*>(this));
+
+ // determine the range we're bound to
+ try
+ {
+ if ( m_xDocument.is() )
+ {
+ // first the sheets collection
+ Reference< XIndexAccess > xSheets(m_xDocument->getSheets( ), UNO_QUERY);
+ OSL_ENSURE( xSheets.is(), "OCellListSource::initialize: could not retrieve the sheets!" );
+
+ if ( xSheets.is() )
+ {
+ // the concrete sheet
+ Reference< XCellRange > xSheet(xSheets->getByIndex( aRangeAddress.Sheet ), UNO_QUERY);
+ OSL_ENSURE( xSheet.is(), "OCellListSource::initialize: NULL sheet, but no exception!" );
+
+ // the concrete cell
+ if ( xSheet.is() )
+ {
+ m_xRange.set(xSheet->getCellRangeByPosition(
+ aRangeAddress.StartColumn, aRangeAddress.StartRow,
+ aRangeAddress.EndColumn, aRangeAddress.EndRow));
+ OSL_ENSURE( Reference< XCellRangeAddressable >( m_xRange, UNO_QUERY ).is(), "OCellListSource::initialize: either NULL range, or cell without address access!" );
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "OCellListSource::initialize: caught an exception while retrieving the cell object!" );
+ }
+
+ if ( !m_xRange.is() )
+ throw RuntimeException("Failed to retrieve cell range", static_cast<cppu::OWeakObject*>(this));
+
+ Reference<XModifyBroadcaster> xBroadcaster( m_xRange, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->addModifyListener( this );
+ }
+
+ // TODO: add as XEventListener to the cell range, so we get notified when it dies,
+ // and can dispose ourself then
+
+ // TODO: somehow add as listener so we get notified when the address of the cell range changes
+ // We need to forward this as change in our CellRange property to our property change listeners
+
+ // TODO: somehow add as listener to the cells in the range, so that we get notified
+ // when their content changes. We need to forward this to our list entry listeners then
+
+ // TODO: somehow add as listener so that we get notified of insertions and removals of rows in our
+ // range. In this case, we need to fire a change in our CellRange property, and additionally
+ // notify our XListEntryListeners
+
+ m_bInitialized = true;
+ }
+
+} // namespace calc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/celllistsource.hxx b/sc/source/ui/unoobj/celllistsource.hxx
new file mode 100644
index 000000000..7a5f72c02
--- /dev/null
+++ b/sc/source/ui/unoobj/celllistsource.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 <com/sun/star/form/binding/XListEntryTypedSource.hpp>
+#include <cppuhelper/compbase4.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/util/XModifyListener.hpp>
+
+namespace com::sun::star::sheet { class XSpreadsheetDocument; }
+namespace com::sun::star::table { class XCellRange; }
+
+namespace calc
+{
+
+ //= OCellListSource
+
+ class OCellListSource;
+ // the base for our interfaces
+ typedef ::cppu::WeakAggComponentImplHelper4 < css::form::binding::XListEntryTypedSource
+ , css::util::XModifyListener
+ , css::lang::XServiceInfo
+ , css::lang::XInitialization
+ > OCellListSource_Base;
+ // the base for the property handling
+ typedef ::comphelper::OPropertyContainer OCellListSource_PBase;
+ // the second base for property handling
+ typedef ::comphelper::OPropertyArrayUsageHelper< OCellListSource >
+ OCellListSource_PABase;
+
+ class OCellListSource :public ::cppu::BaseMutex
+ ,public OCellListSource_Base // order matters! before OCellListSource_PBase, so rBHelper gets initialized
+ ,public OCellListSource_PBase
+ ,public OCellListSource_PABase
+ {
+ private:
+ css::uno::Reference< css::sheet::XSpreadsheetDocument >
+ m_xDocument; /// the document where our cell lives
+ css::uno::Reference< css::table::XCellRange >
+ m_xRange; /// the range of cells we're bound to
+ ::comphelper::OInterfaceContainerHelper3<css::form::binding::XListEntryListener>
+ m_aListEntryListeners; /// our listeners
+ bool m_bInitialized; /// has XInitialization::initialize been called?
+
+ public:
+ explicit OCellListSource(
+ const css::uno::Reference< css::sheet::XSpreadsheetDocument >& _rxDocument
+ );
+
+ using OCellListSource_PBase::getFastPropertyValue;
+
+ protected:
+ virtual ~OCellListSource( ) override;
+
+ protected:
+ // XInterface
+ DECLARE_XINTERFACE()
+
+ // XTypeProvider
+ DECLARE_XTYPEPROVIDER()
+
+ // XListEntrySource
+ virtual sal_Int32 SAL_CALL getListEntryCount( ) override;
+ virtual OUString SAL_CALL getListEntry( sal_Int32 Position ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getAllListEntries( ) override;
+ virtual void SAL_CALL addListEntryListener( const css::uno::Reference< css::form::binding::XListEntryListener >& Listener ) override;
+ virtual void SAL_CALL removeListEntryListener( const css::uno::Reference< css::form::binding::XListEntryListener >& Listener ) override;
+
+ // XListEntryTypedSource
+ virtual css::uno::Sequence< OUString > SAL_CALL getAllListEntriesTyped( css::uno::Sequence< css::uno::Any >& rDataValues ) override;
+
+ // OComponentHelper/XComponent
+ virtual void SAL_CALL disposing() 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;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& _rValue, sal_Int32 _nHandle ) const override;
+
+ // ::comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // XModifyListener
+ virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ private:
+ void checkDisposed( ) const;
+ void checkInitialized();
+
+ /** retrieves the actual address of our cell range
+ @precond
+ our m_xRange is not <NULL/>
+ */
+ css::table::CellRangeAddress
+ getRangeAddress( ) const;
+
+ /** retrieves the text of a cell within our range
+ @param _nRangeRelativeRow
+ the relative row index of the cell within our range
+ @param pAny
+ if not <NULL/> then the underlying data value is returned in the Any
+ @precond
+ our m_xRange is not <NULL/>
+ */
+ OUString
+ getCellTextContent_noCheck(
+ sal_Int32 _nRangeRelativeRow,
+ css::uno::Any* pAny
+ );
+
+ void notifyModified();
+
+ private:
+ OCellListSource( const OCellListSource& ) = delete;
+ OCellListSource& operator=( const OCellListSource& ) = delete;
+ };
+
+} // namespace calc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx
new file mode 100644
index 000000000..b2117cefc
--- /dev/null
+++ b/sc/source/ui/unoobj/cellsuno.cxx
@@ -0,0 +1,9302 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+#include <o3tl/safeint.hxx>
+#include <svx/svdpool.hxx>
+
+#include <vcl/svapp.hxx>
+#include <svx/algitem.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/unoipset.hxx>
+#include <editeng/langitem.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <svl/numformat.hxx>
+#include <svl/srchitem.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <svx/unomid.hxx>
+#include <editeng/unoprnms.hxx>
+#include <editeng/unotext.hxx>
+#include <svx/svdpage.hxx>
+#include <sfx2/bindings.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <float.h>
+#include <tools/diagnose_ex.h>
+#include <tools/UnitConversion.hxx>
+
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/util/CellProtection.hpp>
+#include <com/sun/star/table/CellHoriJustify.hpp>
+#include <com/sun/star/table/CellOrientation.hpp>
+#include <com/sun/star/table/ShadowFormat.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/table/TableBorder2.hpp>
+#include <com/sun/star/sheet/CellFlags.hpp>
+#include <com/sun/star/sheet/FormulaResult.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/beans/TolerantPropertySetResultType.hpp>
+#include <com/sun/star/beans/SetPropertyTolerantFailed.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
+#include <com/sun/star/text/textfield/Type.hpp>
+#include <com/sun/star/sheet/XConditionalFormats.hpp>
+
+#include <autoform.hxx>
+#include <cellvalue.hxx>
+#include <cellmergeoption.hxx>
+#include <cellsuno.hxx>
+#include <cursuno.hxx>
+#include <textuno.hxx>
+#include <editsrc.hxx>
+#include <notesuno.hxx>
+#include <fielduno.hxx>
+#include <docuno.hxx>
+#include <datauno.hxx>
+#include <dapiuno.hxx>
+#include <chartuno.hxx>
+#include <fmtuno.hxx>
+#include <miscuno.hxx>
+#include <convuno.hxx>
+#include <srchuno.hxx>
+#include <nameuno.hxx>
+#include <targuno.hxx>
+#include <tokenuno.hxx>
+#include <eventuno.hxx>
+#include <docsh.hxx>
+#include <markdata.hxx>
+#include <patattr.hxx>
+#include <docpool.hxx>
+#include <docfunc.hxx>
+#include <dbdocfun.hxx>
+#include <olinefun.hxx>
+#include <hints.hxx>
+#include <formulacell.hxx>
+#include <undotab.hxx>
+#include <undoblk.hxx>
+#include <stlsheet.hxx>
+#include <dbdata.hxx>
+#include <attrib.hxx>
+#include <chartarr.hxx>
+#include <chartlis.hxx>
+#include <drwlayer.hxx>
+#include <printfun.hxx>
+#include <prnsave.hxx>
+#include <tablink.hxx>
+#include <dociter.hxx>
+#include <rangeutl.hxx>
+#include <conditio.hxx>
+#include <validat.hxx>
+#include <sc.hrc>
+#include <cellform.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <unonames.hxx>
+#include <styleuno.hxx>
+#include <rangeseq.hxx>
+#include <unowids.hxx>
+#include <paramisc.hxx>
+#include <queryentry.hxx>
+#include <formula/errorcodes.hxx>
+#include <unoreflist.hxx>
+#include <formula/grammar.hxx>
+#include <editeng/escapementitem.hxx>
+#include <stringutil.hxx>
+#include <formulaiter.hxx>
+#include <tokenarray.hxx>
+#include <stylehelper.hxx>
+#include <dputil.hxx>
+#include <sortparam.hxx>
+#include <condformatuno.hxx>
+#include <TablePivotCharts.hxx>
+#include <table.hxx>
+#include <refundo.hxx>
+#include <columnspanset.hxx>
+
+#include <memory>
+
+using namespace com::sun::star;
+
+// The names in the maps must be sorted according to strcmp!
+//! Instead of Which-ID 0 use special IDs and do not compare via names!
+
+// Left/Right/Top/BottomBorder are mapped directly to the core items,
+// not collected/applied to the borders of a range -> ATTR_BORDER can be used directly
+
+static const SfxItemPropertySet* lcl_GetCellsPropertySet()
+{
+ static const SfxItemPropertyMapEntry aCellsPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_BOTTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_BOTTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_CELLBACK, ATTR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_CCOLOR, ATTR_FONT_COLOR, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_LEFTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_LEFTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_RIGHTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_RIGHTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TOPBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_TOPBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_HYPERLINK, ATTR_HYPERLINK, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_FORMATID, SC_WID_UNO_FORMATID, cppu::UnoType<sal_uInt64>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aCellsPropertySet( aCellsPropertyMap_Impl );
+ return &aCellsPropertySet;
+}
+
+// CellRange contains all entries from Cells, plus its own entries
+// with Which-ID 0 (those are needed only for getPropertySetInfo).
+
+static const SfxItemPropertySet* lcl_GetRangePropertySet()
+{
+ static const SfxItemPropertyMapEntry aRangePropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_BOTTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_BOTTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_CELLBACK, ATTR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_CCOLOR, ATTR_FONT_COLOR, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_LEFTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_LEFTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_RIGHTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_RIGHTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TOPBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_TOPBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_FORMATID, SC_WID_UNO_FORMATID, cppu::UnoType<sal_uInt64>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aRangePropertySet( aRangePropertyMap_Impl );
+ return &aRangePropertySet;
+}
+
+// Cell contains entries from CellRange, plus its own entries
+// with Which-ID 0 (those are needed only for getPropertySetInfo).
+
+static const SfxItemPropertySet* lcl_GetCellPropertySet()
+{
+ static const SfxItemPropertyMapEntry aCellPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_BOTTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_BOTTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_CELLBACK, ATTR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_CCOLOR, ATTR_FONT_COLOR, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_FORMLOC, SC_WID_UNO_FORMLOC, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_FORMRT, SC_WID_UNO_FORMRT, cppu::UnoType<table::CellContentType>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_CELLCONTENTTYPE, SC_WID_UNO_CELLCONTENTTYPE, cppu::UnoType<table::CellContentType>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_FORMRT2, SC_WID_UNO_FORMRT2, cppu::UnoType<sal_Int32>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_LEFTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_LEFTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_RIGHTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_RIGHTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TOPBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_TOPBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { UNO_NAME_EDIT_CHAR_ESCAPEMENT, EE_CHAR_ESCAPEMENT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_HYPERLINK, ATTR_HYPERLINK, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_FORMATID, SC_WID_UNO_FORMATID, cppu::UnoType<sal_uInt64>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aCellPropertySet( aCellPropertyMap_Impl );
+ return &aCellPropertySet;
+}
+
+// Column and Row contain all entries from CellRange, plus its own entries
+// with Which-ID 0 (those are needed only for getPropertySetInfo).
+
+static const SfxItemPropertySet* lcl_GetColumnPropertySet()
+{
+ static const SfxItemPropertyMapEntry aColumnPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_BOTTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_BOTTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_CELLBACK, ATTR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_CCOLOR, ATTR_FONT_COLOR, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_MANPAGE, SC_WID_UNO_MANPAGE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NEWPAGE, SC_WID_UNO_NEWPAGE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLVIS, SC_WID_UNO_CELLVIS, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_LEFTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_LEFTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_OWIDTH, SC_WID_UNO_OWIDTH, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_RIGHTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_RIGHTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TOPBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_TOPBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLWID, SC_WID_UNO_CELLWID, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aColumnPropertySet( aColumnPropertyMap_Impl );
+ return &aColumnPropertySet;
+}
+
+static const SfxItemPropertySet* lcl_GetRowPropertySet()
+{
+ static const SfxItemPropertyMapEntry aRowPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_BOTTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_BOTTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_CELLBACK, ATTR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_CCOLOR, ATTR_FONT_COLOR, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CELLHGT, SC_WID_UNO_CELLHGT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_CELLFILT, SC_WID_UNO_CELLFILT,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_MANPAGE, SC_WID_UNO_MANPAGE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NEWPAGE, SC_WID_UNO_NEWPAGE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLVIS, SC_WID_UNO_CELLVIS, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_LEFTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_LEFTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_OHEIGHT, SC_WID_UNO_OHEIGHT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_RIGHTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_RIGHTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TOPBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_TOPBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aRowPropertySet( aRowPropertyMap_Impl );
+ return &aRowPropertySet;
+}
+
+static const SfxItemPropertySet* lcl_GetSheetPropertySet()
+{
+ static const SfxItemPropertyMapEntry aSheetPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ABSNAME, SC_WID_UNO_ABSNAME, cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_AUTOPRINT,SC_WID_UNO_AUTOPRINT,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_BORDCOL, SC_WID_UNO_BORDCOL, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_BOTTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_BOTTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_CELLBACK, ATTR_BACKGROUND, cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ { SC_UNONAME_CELLPRO, ATTR_PROTECTION, cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ { SC_UNONAME_CELLSTYL, SC_WID_UNO_CELLSTYL,cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_CCOLOR, ATTR_FONT_COLOR, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ { SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ { SC_UNONAME_CFONT, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_COVER, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CPOST, ATTR_FONT_POSTURE, cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ { SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ { SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ { SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ { SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ { SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ { SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ { SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHCOLHDR, SC_WID_UNO_CHCOLHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CHROWHDR, SC_WID_UNO_CHROWHDR,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CONDFMT, SC_WID_UNO_CONDFMT, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDLOC, SC_WID_UNO_CONDLOC, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_CONDXML, SC_WID_UNO_CONDXML, cppu::UnoType<sheet::XSheetConditionalEntries>::get(), 0, 0 },
+ { SC_UNONAME_COPYBACK, SC_WID_UNO_COPYBACK,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_COPYFORM, SC_WID_UNO_COPYFORM,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_COPYSTYL, SC_WID_UNO_COPYSTYL,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ { SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ISACTIVE, SC_WID_UNO_ISACTIVE,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLVIS, SC_WID_UNO_CELLVIS, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_LEFTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_LEFTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ { SC_UNO_LINKDISPBIT, SC_WID_UNO_LINKDISPBIT,cppu::UnoType<awt::XBitmap>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_LINKDISPNAME, SC_WID_UNO_LINKDISPNAME,cppu::UnoType<OUString>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ { SC_UNONAME_CELLORI, ATTR_STACKED, cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ { SC_UNONAME_PAGESTL, SC_WID_UNO_PAGESTL, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PBMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PINDENT, ATTR_INDENT, cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ { SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ { SC_UNONAME_PLMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PRMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_PTMARGIN, ATTR_MARGIN, cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ { SC_UNONAME_POS, SC_WID_UNO_POS, cppu::UnoType<awt::Point>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_PRINTBORD,SC_WID_UNO_PRINTBORD,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_PROTECT, SC_WID_UNO_PROTECT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_RIGHTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_RIGHTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHADOW, ATTR_SHADOW, cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_SHOWBORD, SC_WID_UNO_SHOWBORD,cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SIZE, SC_WID_UNO_SIZE, cppu::UnoType<awt::Size>::get(), 0 | beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TBLBORD2, SC_WID_UNO_TBLBORD2, cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ { SC_UNONAME_TABLAYOUT,SC_WID_UNO_TABLAYOUT,cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_CONDFORMAT, SC_WID_UNO_CONDFORMAT, cppu::UnoType<sheet::XConditionalFormats>::get(), 0, 0},
+ { SC_UNONAME_TOPBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_TOPBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ { SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ { SC_UNONAME_VALIDAT, SC_WID_UNO_VALIDAT, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALILOC, SC_WID_UNO_VALILOC, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_VALIXML, SC_WID_UNO_VALIXML, cppu::UnoType<beans::XPropertySet>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_TABCOLOR, SC_WID_UNO_TABCOLOR, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNO_CODENAME, SC_WID_UNO_CODENAME, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNO_NAMEDRANGES, SC_WID_UNO_NAMES, cppu::UnoType<sheet::XNamedRanges>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aSheetPropertySet( aSheetPropertyMap_Impl );
+ return &aSheetPropertySet;
+}
+
+static const SfxItemPropertyMapEntry* lcl_GetEditPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aEditPropertyMap_Impl[] =
+ {
+ SVX_UNOEDIT_CHAR_PROPERTIES,
+ SVX_UNOEDIT_FONT_PROPERTIES,
+ SVX_UNOEDIT_PARA_PROPERTIES,
+ SVX_UNOEDIT_NUMBERING_PROPERTY, // for completeness of service ParagraphProperties
+ { SC_UNONAME_TEXTUSER, EE_CHAR_XMLATTRIBS, cppu::UnoType<container::XNameContainer>::get(), 0, 0},
+ { SC_UNONAME_USERDEF, EE_PARA_XMLATTRIBS, cppu::UnoType<container::XNameContainer>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aEditPropertyMap_Impl;
+}
+static const SvxItemPropertySet* lcl_GetEditPropertySet()
+{
+ static SvxItemPropertySet aEditPropertySet( lcl_GetEditPropertyMap(), SdrObject::GetGlobalDrawObjectItemPool() );
+ return &aEditPropertySet;
+}
+
+constexpr OUStringLiteral SCCHARPROPERTIES_SERVICE = u"com.sun.star.style.CharacterProperties";
+constexpr OUStringLiteral SCPARAPROPERTIES_SERVICE = u"com.sun.star.style.ParagraphProperties";
+constexpr OUStringLiteral SCCELLPROPERTIES_SERVICE = u"com.sun.star.table.CellProperties";
+constexpr OUStringLiteral SCCELLRANGE_SERVICE = u"com.sun.star.table.CellRange";
+constexpr OUStringLiteral SCCELL_SERVICE = u"com.sun.star.table.Cell";
+constexpr OUStringLiteral SCSHEETCELLRANGES_SERVICE = u"com.sun.star.sheet.SheetCellRanges";
+constexpr OUStringLiteral SCSHEETCELLRANGE_SERVICE = u"com.sun.star.sheet.SheetCellRange";
+constexpr OUStringLiteral SCSPREADSHEET_SERVICE = u"com.sun.star.sheet.Spreadsheet";
+constexpr OUStringLiteral SCSHEETCELL_SERVICE = u"com.sun.star.sheet.SheetCell";
+
+SC_SIMPLE_SERVICE_INFO( ScCellFormatsEnumeration, "ScCellFormatsEnumeration", "com.sun.star.sheet.CellFormatRangesEnumeration" )
+SC_SIMPLE_SERVICE_INFO( ScCellFormatsObj, "ScCellFormatsObj", "com.sun.star.sheet.CellFormatRanges" )
+SC_SIMPLE_SERVICE_INFO( ScUniqueCellFormatsEnumeration, "ScUniqueCellFormatsEnumeration", "com.sun.star.sheet.UniqueCellFormatRangesEnumeration" )
+SC_SIMPLE_SERVICE_INFO( ScUniqueCellFormatsObj, "ScUniqueCellFormatsObj", "com.sun.star.sheet.UniqueCellFormatRanges" )
+SC_SIMPLE_SERVICE_INFO( ScCellRangesBase, "ScCellRangesBase", "stardiv.unknown" )
+SC_SIMPLE_SERVICE_INFO( ScCellsEnumeration, "ScCellsEnumeration", "com.sun.star.sheet.CellsEnumeration" )
+SC_SIMPLE_SERVICE_INFO( ScCellsObj, "ScCellsObj", "com.sun.star.sheet.Cells" )
+SC_SIMPLE_SERVICE_INFO( ScTableColumnObj, "ScTableColumnObj", "com.sun.star.table.TableColumn" )
+SC_SIMPLE_SERVICE_INFO( ScTableRowObj, "ScTableRowObj", "com.sun.star.table.TableRow" )
+
+//! move ScLinkListener into another file !!!
+
+ScLinkListener::~ScLinkListener()
+{
+}
+
+void ScLinkListener::Notify( const SfxHint& rHint )
+{
+ aLink.Call( rHint );
+}
+
+static void lcl_CopyProperties( beans::XPropertySet& rDest, beans::XPropertySet& rSource )
+{
+ uno::Reference<beans::XPropertySetInfo> xInfo(rSource.getPropertySetInfo());
+ if (xInfo.is())
+ {
+ const uno::Sequence<beans::Property> aSeq(xInfo->getProperties());
+ for (const beans::Property& rProp : aSeq)
+ {
+ OUString aName(rProp.Name);
+ rDest.setPropertyValue( aName, rSource.getPropertyValue( aName ) );
+ }
+ }
+}
+
+static SCTAB lcl_FirstTab( const ScRangeList& rRanges )
+{
+ if (rRanges.empty())
+ throw std::out_of_range("empty range");
+ const ScRange & rFirst = rRanges[0];
+ return rFirst.aStart.Tab();
+}
+
+static bool lcl_WholeSheet( const ScDocument& rDoc, const ScRangeList& rRanges )
+{
+ if ( rRanges.size() == 1 )
+ {
+ const ScRange & rRange = rRanges[0];
+ if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
+ rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
+ return true;
+ }
+ return false;
+}
+
+namespace {
+template<typename BorderLineType>
+const ::editeng::SvxBorderLine* lcl_getBorderLine(
+ ::editeng::SvxBorderLine& rLine, const BorderLineType& rStruct )
+{
+ // Convert from 1/100mm to Twips.
+ if (!SvxBoxItem::LineToSvxLine( rStruct, rLine, true))
+ return nullptr;
+
+ if ( rLine.GetOutWidth() || rLine.GetInWidth() || rLine.GetDistance() )
+ return &rLine;
+ else
+ return nullptr;
+}
+}
+
+const ::editeng::SvxBorderLine* ScHelperFunctions::GetBorderLine(
+ ::editeng::SvxBorderLine& rLine, const table::BorderLine& rStruct )
+{
+ return lcl_getBorderLine( rLine, rStruct);
+}
+
+const ::editeng::SvxBorderLine* ScHelperFunctions::GetBorderLine(
+ ::editeng::SvxBorderLine& rLine, const table::BorderLine2& rStruct )
+{
+ return lcl_getBorderLine( rLine, rStruct);
+}
+
+namespace {
+template<typename TableBorderType>
+void lcl_fillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const TableBorderType& rBorder )
+{
+ ::editeng::SvxBorderLine aLine;
+ rOuter.SetAllDistances(o3tl::toTwips(rBorder.Distance, o3tl::Length::mm100));
+ rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.TopLine ), SvxBoxItemLine::TOP );
+ rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.BottomLine ), SvxBoxItemLine::BOTTOM );
+ rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.LeftLine ), SvxBoxItemLine::LEFT );
+ rOuter.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.RightLine ), SvxBoxItemLine::RIGHT );
+ rInner.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.HorizontalLine ), SvxBoxInfoItemLine::HORI );
+ rInner.SetLine( ScHelperFunctions::GetBorderLine( aLine, rBorder.VerticalLine ), SvxBoxInfoItemLine::VERT );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::TOP, rBorder.IsTopLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::BOTTOM, rBorder.IsBottomLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::LEFT, rBorder.IsLeftLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::RIGHT, rBorder.IsRightLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::HORI, rBorder.IsHorizontalLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::VERT, rBorder.IsVerticalLineValid );
+ rInner.SetValid( SvxBoxInfoItemValidFlags::DISTANCE, rBorder.IsDistanceValid );
+ rInner.SetTable( true );
+}
+}
+
+void ScHelperFunctions::FillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const table::TableBorder& rBorder )
+{
+ lcl_fillBoxItems( rOuter, rInner, rBorder);
+}
+
+void ScHelperFunctions::FillBoxItems( SvxBoxItem& rOuter, SvxBoxInfoItem& rInner, const table::TableBorder2& rBorder )
+{
+ lcl_fillBoxItems( rOuter, rInner, rBorder);
+}
+
+void ScHelperFunctions::FillBorderLine( table::BorderLine& rStruct, const ::editeng::SvxBorderLine* pLine )
+{
+ // Convert from Twips to 1/100mm.
+ rStruct = SvxBoxItem::SvxLineToLine( pLine, true);
+}
+
+void ScHelperFunctions::FillBorderLine( table::BorderLine2& rStruct, const ::editeng::SvxBorderLine* pLine )
+{
+ rStruct = SvxBoxItem::SvxLineToLine( pLine, true);
+}
+
+namespace {
+template<typename TableBorderItem>
+void lcl_fillTableBorder( TableBorderItem& rBorder, const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner,
+ bool bInvalidateHorVerDist )
+{
+ ScHelperFunctions::FillBorderLine( rBorder.TopLine, rOuter.GetTop() );
+ ScHelperFunctions::FillBorderLine( rBorder.BottomLine, rOuter.GetBottom() );
+ ScHelperFunctions::FillBorderLine( rBorder.LeftLine, rOuter.GetLeft() );
+ ScHelperFunctions::FillBorderLine( rBorder.RightLine, rOuter.GetRight() );
+ ScHelperFunctions::FillBorderLine( rBorder.HorizontalLine, rInner.GetHori() );
+ ScHelperFunctions::FillBorderLine( rBorder.VerticalLine, rInner.GetVert() );
+
+ rBorder.Distance = rOuter.GetSmallestDistance();
+ rBorder.IsTopLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::TOP);
+ rBorder.IsBottomLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::BOTTOM);
+ rBorder.IsLeftLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::LEFT);
+ rBorder.IsRightLineValid = rInner.IsValid(SvxBoxInfoItemValidFlags::RIGHT);
+ rBorder.IsHorizontalLineValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::HORI);
+ rBorder.IsVerticalLineValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::VERT);
+ rBorder.IsDistanceValid = !bInvalidateHorVerDist && rInner.IsValid(SvxBoxInfoItemValidFlags::DISTANCE);
+}
+}
+
+void ScHelperFunctions::AssignTableBorderToAny( uno::Any& rAny,
+ const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner, bool bInvalidateHorVerDist )
+{
+ table::TableBorder aBorder;
+ lcl_fillTableBorder( aBorder, rOuter, rInner, bInvalidateHorVerDist);
+ rAny <<= aBorder;
+}
+
+void ScHelperFunctions::AssignTableBorder2ToAny( uno::Any& rAny,
+ const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner, bool bInvalidateHorVerDist )
+{
+ table::TableBorder2 aBorder;
+ lcl_fillTableBorder( aBorder, rOuter, rInner, bInvalidateHorVerDist);
+ rAny <<= aBorder;
+}
+
+//! move lcl_ApplyBorder to docfunc !
+
+void ScHelperFunctions::ApplyBorder( ScDocShell* pDocShell, const ScRangeList& rRanges,
+ const SvxBoxItem& rOuter, const SvxBoxInfoItem& rInner )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+ ScDocumentUniquePtr pUndoDoc;
+ if (bUndo)
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ size_t nCount = rRanges.size();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ ScRange const & rRange = rRanges[ i ];
+ SCTAB nTab = rRange.aStart.Tab();
+
+ if (bUndo)
+ {
+ if ( i==0 )
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ else
+ pUndoDoc->AddUndoTab( nTab, nTab );
+ rDoc.CopyToDocument(rRange, InsertDeleteFlags::ATTRIB, false, *pUndoDoc);
+ }
+
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SetMarkArea( rRange );
+ aMark.SelectTable( nTab, true );
+
+ rDoc.ApplySelectionFrame(aMark, rOuter, &rInner);
+ // don't need RowHeight if there is only a border
+ }
+
+ if (bUndo)
+ {
+ pDocShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoBorder>( pDocShell, rRanges, std::move(pUndoDoc), rOuter, rInner ) );
+ }
+
+ for (size_t i = 0; i < nCount; ++i )
+ pDocShell->PostPaint( rRanges[ i ], PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ pDocShell->SetDocumentModified();
+}
+
+//! move lcl_PutDataArray to docfunc?
+//! merge loop with ScFunctionAccess::callFunction
+
+static bool lcl_PutDataArray( ScDocShell& rDocShell, const ScRange& rRange,
+ const uno::Sequence< uno::Sequence<uno::Any> >& aData )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
+ SCTAB nTab = rRange.aStart.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ if ( !rDoc.IsBlockEditable( nTab, nStartCol,nStartRow, nEndCol,nEndRow ) )
+ {
+ //! error message
+ return false;
+ }
+
+ sal_Int32 nCols = 0;
+ sal_Int32 nRows = aData.getLength();
+ if ( nRows )
+ nCols = aData[0].getLength();
+
+ if ( nCols != nEndCol-nStartCol+1 || nRows != nEndRow-nStartRow+1 )
+ {
+ //! error message?
+ return false;
+ }
+
+ ScDocumentUniquePtr pUndoDoc;
+ if ( bUndo )
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ rDoc.CopyToDocument(rRange, InsertDeleteFlags::CONTENTS|InsertDeleteFlags::NOCAPTIONS, false, *pUndoDoc);
+ }
+
+ rDoc.DeleteAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS );
+
+ bool bError = false;
+ SCROW nDocRow = nStartRow;
+ for (const uno::Sequence<uno::Any>& rColSeq : aData)
+ {
+ if ( rColSeq.getLength() == nCols )
+ {
+ SCCOL nDocCol = nStartCol;
+ for (const uno::Any& rElement : rColSeq)
+ {
+ ScAddress aPos(nDocCol, nDocRow, nTab);
+
+ switch( rElement.getValueTypeClass() )
+ {
+ case uno::TypeClass_VOID:
+ {
+ // void = "no value"
+ rDoc.SetError( nDocCol, nDocRow, nTab, FormulaError::NotAvailable );
+ }
+ break;
+
+ // #87871# accept integer types because Basic passes a floating point
+ // variable as byte, short or long if it's an integer number.
+ case uno::TypeClass_BYTE:
+ case uno::TypeClass_SHORT:
+ case uno::TypeClass_UNSIGNED_SHORT:
+ case uno::TypeClass_LONG:
+ case uno::TypeClass_UNSIGNED_LONG:
+ case uno::TypeClass_FLOAT:
+ case uno::TypeClass_DOUBLE:
+ {
+ double fVal(0.0);
+ rElement >>= fVal;
+ rDoc.SetValue(aPos, fVal);
+ }
+ break;
+
+ case uno::TypeClass_STRING:
+ {
+ OUString aUStr;
+ rElement >>= aUStr;
+ if ( !aUStr.isEmpty() )
+ {
+ // tdf#146454 - check for a multiline string since setting an edit
+ // or string cell is in magnitudes slower than setting a plain string
+ if (ScStringUtil::isMultiline(aUStr))
+ {
+ rEngine.SetTextCurrentDefaults(aUStr);
+ rDoc.SetEditText(aPos, rEngine.CreateTextObject());
+ }
+ else
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(aPos, aUStr, &aParam);
+ }
+ }
+ }
+ break;
+
+ // accept Sequence<FormulaToken> for formula cells
+ case uno::TypeClass_SEQUENCE:
+ {
+ uno::Sequence< sheet::FormulaToken > aTokens;
+ if ( rElement >>= aTokens )
+ {
+ ScTokenArray aTokenArray(rDoc);
+ ScTokenConversion::ConvertToTokenArray( rDoc, aTokenArray, aTokens );
+ rDoc.SetFormula(aPos, aTokenArray);
+ }
+ else
+ bError = true;
+ }
+ break;
+
+ default:
+ bError = true; // invalid type
+ }
+ ++nDocCol;
+ }
+ }
+ else
+ bError = true; // wrong size
+
+ ++nDocRow;
+ }
+
+ bool bHeight = rDocShell.AdjustRowHeight( nStartRow, nEndRow, nTab );
+
+ if ( pUndoDoc )
+ {
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ aDestMark.SelectOneTable( nTab );
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoPaste>(
+ &rDocShell, ScRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab),
+ aDestMark, std::move(pUndoDoc), nullptr, InsertDeleteFlags::CONTENTS, nullptr, false));
+ }
+
+ if (!bHeight)
+ rDocShell.PostPaint( rRange, PaintPartFlags::Grid ); // AdjustRowHeight may have painted already
+
+ rDocShell.SetDocumentModified();
+
+ return !bError;
+}
+
+static bool lcl_PutFormulaArray( ScDocShell& rDocShell, const ScRange& rRange,
+ const uno::Sequence< uno::Sequence<OUString> >& aData,
+ const formula::FormulaGrammar::Grammar eGrammar )
+{
+ ScDocument& rDoc = rDocShell.GetDocument();
+ SCTAB nTab = rRange.aStart.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ if ( !rDoc.IsBlockEditable( nTab, nStartCol,nStartRow, nEndCol,nEndRow ) )
+ {
+ //! error message
+ return false;
+ }
+
+ sal_Int32 nCols = 0;
+ sal_Int32 nRows = aData.getLength();
+ if ( nRows )
+ nCols = aData[0].getLength();
+
+ if ( nCols != nEndCol-nStartCol+1 || nRows != nEndRow-nStartRow+1 )
+ {
+ //! error message?
+ return false;
+ }
+
+ ScDocumentUniquePtr pUndoDoc;
+ if ( bUndo )
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ rDoc.CopyToDocument(rRange, InsertDeleteFlags::CONTENTS, false, *pUndoDoc);
+ }
+
+ rDoc.DeleteAreaTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, InsertDeleteFlags::CONTENTS );
+
+ bool bError = false;
+ SCROW nDocRow = nStartRow;
+ for (const uno::Sequence<OUString>& rColSeq : aData)
+ {
+ if ( rColSeq.getLength() == nCols )
+ {
+ SCCOL nDocCol = nStartCol;
+ for (const OUString& aText : rColSeq)
+ {
+ ScAddress aPos( nDocCol, nDocRow, nTab );
+
+ ScInputStringType aRes =
+ ScStringUtil::parseInputString(
+ *rDoc.GetFormatTable(), aText, LANGUAGE_ENGLISH_US);
+ switch (aRes.meType)
+ {
+ case ScInputStringType::Formula:
+ rDoc.SetFormula(aPos, aRes.maText, eGrammar);
+ break;
+ case ScInputStringType::Number:
+ rDoc.SetValue(aPos, aRes.mfValue);
+ break;
+ case ScInputStringType::Text:
+ rDoc.SetTextCell(aPos, aRes.maText);
+ break;
+ default:
+ ;
+ }
+
+ ++nDocCol;
+ }
+ }
+ else
+ bError = true; // wrong size
+
+ ++nDocRow;
+ }
+
+ bool bHeight = rDocShell.AdjustRowHeight( nStartRow, nEndRow, nTab );
+
+ if ( pUndoDoc )
+ {
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ aDestMark.SelectOneTable( nTab );
+ rDocShell.GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoPaste>( &rDocShell,
+ ScRange(nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab), aDestMark,
+ std::move(pUndoDoc), nullptr, InsertDeleteFlags::CONTENTS, nullptr, false));
+ }
+
+ if (!bHeight)
+ rDocShell.PostPaint( rRange, PaintPartFlags::Grid ); // AdjustRowHeight may have painted already
+
+ rDocShell.SetDocumentModified();
+
+ return !bError;
+}
+
+// used in ScCellRangeObj::getFormulaArray and ScCellObj::GetInputString_Impl
+static OUString lcl_GetInputString( ScDocument& rDoc, const ScAddress& rPos, bool bEnglish )
+{
+ ScRefCellValue aCell(rDoc, rPos);
+ if (aCell.isEmpty())
+ return OUString();
+
+ OUString aVal;
+
+ CellType eType = aCell.meType;
+ if (eType == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pForm = aCell.mpFormula;
+ return pForm->GetFormula( formula::FormulaGrammar::mapAPItoGrammar( bEnglish, false));
+ }
+
+ SvNumberFormatter* pFormatter = bEnglish ? ScGlobal::GetEnglishFormatter() :
+ rDoc.GetFormatTable();
+ // Since the English formatter was constructed with
+ // LANGUAGE_ENGLISH_US the "General" format has index key 0,
+ // we don't have to query.
+ sal_uInt32 nNumFmt = bEnglish ? 0 : rDoc.GetNumberFormat(rPos);
+
+ if (eType == CELLTYPE_EDIT)
+ {
+ // GetString on EditCell turns breaks into spaces,
+ // but we need the breaks here
+ const EditTextObject* pData = aCell.mpEditText;
+ if (pData)
+ {
+ EditEngine& rEngine = rDoc.GetEditEngine();
+ rEngine.SetText(*pData);
+ aVal = rEngine.GetText();
+ }
+ }
+ else
+ aVal = ScCellFormat::GetInputString(aCell, nNumFmt, *pFormatter, rDoc);
+
+ // if applicable, prepend ' like in ScTabViewShell::UpdateInputHandler
+ if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
+ {
+ double fDummy;
+ OUString aTempString = aVal;
+ bool bIsNumberFormat(pFormatter->IsNumberFormat(aTempString, nNumFmt, fDummy));
+ if ( bIsNumberFormat )
+ aTempString = "'" + aTempString;
+ else if ( aTempString.startsWith("'") )
+ {
+ // if the string starts with a "'", add another one because setFormula
+ // strips one (like text input, except for "text" number formats)
+ if ( bEnglish || ( pFormatter->GetType(nNumFmt) != SvNumFormatType::TEXT ) )
+ aTempString = "'" + aTempString;
+ }
+ aVal = aTempString;
+ }
+ return aVal;
+}
+
+ScCellRangesBase::ScCellRangesBase(ScDocShell* pDocSh, const ScRange& rR) :
+ pPropSet(lcl_GetCellsPropertySet()),
+ pDocShell( pDocSh ),
+ nObjectId( 0 ),
+ bChartColAsHdr( false ),
+ bChartRowAsHdr( false ),
+ bCursorOnly( false ),
+ bGotDataChangedHint( false ),
+ aValueListeners( 0 )
+{
+ ScRange aCellRange(rR);
+ aCellRange.PutInOrder();
+ aRanges.push_back( aCellRange );
+
+ if (pDocShell) // Null if created with createInstance
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.AddUnoObject(*this);
+ nObjectId = rDoc.GetNewUnoId();
+ }
+}
+
+ScCellRangesBase::ScCellRangesBase(ScDocShell* pDocSh, const ScRangeList& rR) :
+ pPropSet(lcl_GetCellsPropertySet()),
+ pDocShell( pDocSh ),
+ aRanges( rR ),
+ nObjectId( 0 ),
+ bChartColAsHdr( false ),
+ bChartRowAsHdr( false ),
+ bCursorOnly( false ),
+ bGotDataChangedHint( false ),
+ aValueListeners( 0 )
+{
+ if (pDocShell) // Null if created with createInstance
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.AddUnoObject(*this);
+ nObjectId = rDoc.GetNewUnoId();
+ }
+}
+
+ScCellRangesBase::~ScCellRangesBase()
+{
+ SolarMutexGuard g;
+
+ // call RemoveUnoObject first, so no notification can happen
+ // during ForgetCurrentAttrs
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+
+ ForgetCurrentAttrs();
+ ForgetMarkData();
+
+ pValueListener.reset();
+
+ //! unregister XChartDataChangeEventListener ??
+ //! (ChartCollection will then hold this object as well!)
+}
+
+void ScCellRangesBase::ForgetCurrentAttrs()
+{
+ pCurrentFlat.reset();
+ pCurrentDeep.reset();
+ moCurrentDataSet.reset();
+ moNoDfltCurrentDataSet.reset();
+
+ // #i62483# pMarkData can remain unchanged, is deleted only if the range changes (RefChanged)
+}
+
+void ScCellRangesBase::ForgetMarkData()
+{
+ pMarkData.reset();
+}
+
+const ScPatternAttr* ScCellRangesBase::GetCurrentAttrsFlat()
+{
+ // get and cache direct cell attributes for this object's range
+
+ if ( !pCurrentFlat && pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pCurrentFlat = rDoc.CreateSelectionPattern( *GetMarkData(), false );
+ }
+ return pCurrentFlat.get();
+}
+
+const ScPatternAttr* ScCellRangesBase::GetCurrentAttrsDeep()
+{
+ // get and cache cell attributes (incl. styles) for this object's range
+
+ if ( !pCurrentDeep && pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pCurrentDeep = rDoc.CreateSelectionPattern( *GetMarkData() );
+ }
+ return pCurrentDeep.get();
+}
+
+SfxItemSet* ScCellRangesBase::GetCurrentDataSet(bool bNoDflt)
+{
+ if(!moCurrentDataSet)
+ {
+ const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
+ if ( pPattern )
+ {
+ // replace Dontcare with Default, so that we always have a reflection
+ moCurrentDataSet.emplace( pPattern->GetItemSet() );
+ moNoDfltCurrentDataSet.emplace( pPattern->GetItemSet() );
+ moCurrentDataSet->ClearInvalidItems();
+ }
+ }
+ if (bNoDflt)
+ {
+ if (moNoDfltCurrentDataSet)
+ return &*moNoDfltCurrentDataSet;
+ }
+ else
+ {
+ if (moCurrentDataSet)
+ return &*moCurrentDataSet;
+ }
+ return nullptr;
+}
+
+const ScMarkData* ScCellRangesBase::GetMarkData()
+{
+ if (!pMarkData)
+ {
+ pMarkData.reset( new ScMarkData(GetDocument()->GetSheetLimits(), aRanges) );
+ }
+ return pMarkData.get();
+}
+
+void ScCellRangesBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::Dying )
+ {
+ // if the document dies, must reset to avoid crash in dtor!
+ ForgetCurrentAttrs();
+ pDocShell = nullptr; // invalid
+
+ // fdo#72695: if UNO object is already dead, don't revive it with event
+ if ( m_refCount > 0 && !aValueListeners.empty() )
+ {
+ // dispose listeners
+
+ lang::EventObject aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ for (uno::Reference<util::XModifyListener> & xValueListener : aValueListeners)
+ xValueListener->disposing( aEvent );
+
+ aValueListeners.clear();
+
+ // The listeners can't have the last ref to this, as it's still held
+ // by the DocShell.
+ }
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ // document content changed -> forget cached attributes
+ ForgetCurrentAttrs();
+
+ if ( bGotDataChangedHint && pDocShell )
+ {
+ // This object was notified of content changes, so one call
+ // for each listener is generated now.
+ // The calls can't be executed directly because the document's
+ // UNO broadcaster list must not be modified.
+ // Instead, add to the document's list of listener calls,
+ // which will be executed directly after the broadcast of
+ // SfxHintId::DataChanged.
+
+ lang::EventObject aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+
+ // the EventObject holds a Ref to this object until after the listener calls
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for (const uno::Reference<util::XModifyListener> & xValueListener : aValueListeners)
+ rDoc.AddUnoListenerCall( xValueListener, aEvent );
+
+ bGotDataChangedHint = false;
+ }
+ }
+ else if ( nId == SfxHintId::ScCalcAll )
+ {
+ // broadcast from DoHardRecalc - set bGotDataChangedHint
+ // (SfxHintId::DataChanged follows separately)
+
+ if ( !aValueListeners.empty() )
+ bGotDataChangedHint = true;
+ }
+ else if ( auto pRefHint = dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::unique_ptr<ScRangeList> pUndoRanges;
+ if ( rDoc.HasUnoRefUndo() )
+ pUndoRanges.reset(new ScRangeList( aRanges ));
+
+ if ( aRanges.UpdateReference( pRefHint->GetMode(), &rDoc, pRefHint->GetRange(),
+ pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() ) )
+ {
+ if ( pRefHint->GetMode() == URM_INSDEL
+ && aRanges.size() == 1
+ && dynamic_cast<ScTableSheetObj*>(this)
+ )
+ {
+ // #101755#; the range size of a sheet does not change
+ ScRange & rR = aRanges.front();
+ rR.aStart.SetCol(0);
+ rR.aStart.SetRow(0);
+ rR.aEnd.SetCol(rDoc.MaxCol());
+ rR.aEnd.SetRow(rDoc.MaxRow());
+ }
+ RefChanged();
+
+ // any change of the range address is broadcast to value (modify) listeners
+ if ( !aValueListeners.empty() )
+ bGotDataChangedHint = true;
+
+ if ( pUndoRanges )
+ rDoc.AddUnoRefChange( nObjectId, *pUndoRanges );
+ }
+ }
+ else if ( auto pUndoHint = dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
+ {
+ if ( pUndoHint->GetObjectId() == nObjectId )
+ {
+ // restore ranges from hint
+
+ aRanges = pUndoHint->GetRanges();
+
+ RefChanged();
+ if ( !aValueListeners.empty() )
+ bGotDataChangedHint = true; // need to broadcast the undo, too
+ }
+ }
+}
+
+void ScCellRangesBase::RefChanged()
+{
+ //! adjust XChartDataChangeEventListener
+
+ if ( pValueListener && !aValueListeners.empty() )
+ {
+ pValueListener->EndListeningAll();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
+ rDoc.StartListeningArea( aRanges[ i ], false, pValueListener.get() );
+ }
+
+ ForgetCurrentAttrs();
+ ForgetMarkData();
+}
+
+ScDocument* ScCellRangesBase::GetDocument() const
+{
+ if (pDocShell)
+ return &pDocShell->GetDocument();
+ else
+ return nullptr;
+}
+
+void ScCellRangesBase::InitInsertRange(ScDocShell* pDocSh, const ScRange& rR)
+{
+ if ( pDocShell || !pDocSh )
+ return;
+
+ pDocShell = pDocSh;
+
+ ScRange aCellRange(rR);
+ aCellRange.PutInOrder();
+ aRanges.RemoveAll();
+ aRanges.push_back( aCellRange );
+
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ RefChanged(); // adjust range in range object
+}
+
+void ScCellRangesBase::AddRange(const ScRange& rRange, const bool bMergeRanges)
+{
+ if (bMergeRanges)
+ aRanges.Join(rRange);
+ else
+ aRanges.push_back(rRange);
+ RefChanged();
+}
+
+void ScCellRangesBase::SetNewRange(const ScRange& rNew)
+{
+ ScRange aCellRange(rNew);
+ aCellRange.PutInOrder();
+
+ aRanges.RemoveAll();
+ aRanges.push_back( aCellRange );
+ RefChanged();
+}
+
+void ScCellRangesBase::SetNewRanges(const ScRangeList& rNew)
+{
+ aRanges = rNew;
+ RefChanged();
+}
+
+void ScCellRangesBase::SetCursorOnly( bool bSet )
+{
+ // set for a selection object that is created from the cursor position
+ // without anything selected (may contain several sheets)
+
+ bCursorOnly = bSet;
+}
+
+void ScCellRangesBase::PaintGridRanges_Impl( )
+{
+ for (size_t i = 0, nCount = aRanges.size(); i < nCount; ++i)
+ pDocShell->PostPaint( aRanges[ i ], PaintPartFlags::Grid );
+}
+
+// XSheetOperation
+
+double SAL_CALL ScCellRangesBase::computeFunction( sheet::GeneralFunction nFunction )
+{
+ SolarMutexGuard aGuard;
+ ScMarkData aMark(*GetMarkData());
+ aMark.MarkToSimple();
+ if (!aMark.IsMarked())
+ aMark.SetMarkNegative(true); // so we can enter dummy position
+
+ ScAddress aDummy; // if not marked, ignored if it is negative
+ double fVal;
+ ScSubTotalFunc eFunc = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(nFunction));
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( !rDoc.GetSelectionFunction( eFunc, aDummy, aMark, fVal ) )
+ {
+ throw uno::RuntimeException(); //! own exception?
+ }
+
+ return fVal;
+}
+
+void SAL_CALL ScCellRangesBase::clearContents( sal_Int32 nContentFlags )
+{
+ SolarMutexGuard aGuard;
+ if ( !aRanges.empty() )
+ {
+ // only for clearContents: EDITATTR is only used if no contents are deleted
+ InsertDeleteFlags nDelFlags = static_cast<InsertDeleteFlags>(nContentFlags) & InsertDeleteFlags::ALL;
+ if ( ( nDelFlags & InsertDeleteFlags::EDITATTR ) && ( nDelFlags & InsertDeleteFlags::CONTENTS ) == InsertDeleteFlags::NONE )
+ nDelFlags |= InsertDeleteFlags::EDITATTR;
+
+ pDocShell->GetDocFunc().DeleteContents( *GetMarkData(), nDelFlags, true, true );
+ }
+ // otherwise nothing to do
+}
+
+// XPropertyState
+
+const SfxItemPropertyMap& ScCellRangesBase::GetItemPropertyMap()
+{
+ return pPropSet->getPropertyMap();
+}
+
+static void lcl_GetPropertyWhich( const SfxItemPropertyMapEntry* pEntry,
+ sal_uInt16& rItemWhich )
+{
+ // Which-ID of the affected items also when the item can't handle
+ // the property by itself
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ rItemWhich = pEntry->nWID;
+ else
+ switch ( pEntry->nWID )
+ {
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ rItemWhich = ATTR_BORDER;
+ break;
+ case SC_WID_UNO_CONDFMT:
+ case SC_WID_UNO_CONDLOC:
+ case SC_WID_UNO_CONDXML:
+ rItemWhich = ATTR_CONDITIONAL;
+ break;
+ case SC_WID_UNO_VALIDAT:
+ case SC_WID_UNO_VALILOC:
+ case SC_WID_UNO_VALIXML:
+ rItemWhich = ATTR_VALIDDATA;
+ break;
+ }
+
+}
+
+beans::PropertyState ScCellRangesBase::GetOnePropertyState( sal_uInt16 nItemWhich, const SfxItemPropertyMapEntry* pEntry )
+{
+ beans::PropertyState eRet = beans::PropertyState_DIRECT_VALUE;
+ if ( nItemWhich ) // item wid (from map or special case)
+ {
+ // For items that contain several properties (like background),
+ // "ambiguous" is returned too often here
+
+ // for PropertyState, don't look at styles
+ const ScPatternAttr* pPattern = GetCurrentAttrsFlat();
+ if ( pPattern )
+ {
+ SfxItemState eState = pPattern->GetItemSet().GetItemState( nItemWhich, false );
+
+ if ( nItemWhich == ATTR_VALUE_FORMAT && eState == SfxItemState::DEFAULT )
+ eState = pPattern->GetItemSet().GetItemState( ATTR_LANGUAGE_FORMAT, false );
+
+ if ( eState == SfxItemState::SET )
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ else if ( eState == SfxItemState::DEFAULT )
+ eRet = beans::PropertyState_DEFAULT_VALUE;
+ else if ( eState == SfxItemState::DONTCARE )
+ eRet = beans::PropertyState_AMBIGUOUS_VALUE;
+ else
+ {
+ OSL_FAIL("unknown ItemState");
+ }
+ }
+ }
+ else if ( pEntry )
+ {
+ if ( pEntry->nWID == SC_WID_UNO_CHCOLHDR || pEntry->nWID == SC_WID_UNO_CHROWHDR || pEntry->nWID == SC_WID_UNO_ABSNAME )
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ else if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
+ {
+ // a style is always set, there's no default state
+ const ScStyleSheet* pStyle = pDocShell->GetDocument().GetSelectionStyle(*GetMarkData());
+ if (pStyle)
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ else
+ eRet = beans::PropertyState_AMBIGUOUS_VALUE;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_NUMRULES )
+ eRet = beans::PropertyState_DEFAULT_VALUE; // numbering rules are always default
+ }
+ return eRet;
+}
+
+beans::PropertyState SAL_CALL ScCellRangesBase::getPropertyState( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ if ( aRanges.empty() )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMap& rMap = GetItemPropertyMap(); // from derived class
+ sal_uInt16 nItemWhich = 0;
+ const SfxItemPropertyMapEntry* pEntry = rMap.getByName( aPropertyName );
+ lcl_GetPropertyWhich( pEntry, nItemWhich );
+ return GetOnePropertyState( nItemWhich, pEntry );
+}
+
+uno::Sequence<beans::PropertyState> SAL_CALL ScCellRangesBase::getPropertyStates(
+ const uno::Sequence<OUString>& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+
+ uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength());
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.getArray(),
+ [this, &rPropertyMap](const auto& rName) -> beans::PropertyState {
+ sal_uInt16 nItemWhich = 0;
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( rName );
+ lcl_GetPropertyWhich( pEntry, nItemWhich );
+ return GetOnePropertyState(nItemWhich, pEntry);
+ });
+ return aRet;
+}
+
+void SAL_CALL ScCellRangesBase::setPropertyToDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ if ( !pDocShell )
+ return;
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ sal_uInt16 nItemWhich = 0;
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ lcl_GetPropertyWhich( pEntry, nItemWhich );
+ if ( nItemWhich ) // item wid (from map or special case)
+ {
+ if ( !aRanges.empty() ) // empty = nothing to do
+ {
+ //! for items that have multiple properties (e.g. background)
+ //! too much will be reset
+ //! for ATTR_ROTATE_VALUE, reset ATTR_ORIENTATION as well?
+
+ sal_uInt16 aWIDs[3];
+ aWIDs[0] = nItemWhich;
+ if ( nItemWhich == ATTR_VALUE_FORMAT )
+ {
+ aWIDs[1] = ATTR_LANGUAGE_FORMAT; // language for number formats
+ aWIDs[2] = 0;
+ }
+ else
+ aWIDs[1] = 0;
+ pDocShell->GetDocFunc().ClearItems( *GetMarkData(), aWIDs, true );
+ }
+ }
+ else if ( pEntry )
+ {
+ if ( pEntry->nWID == SC_WID_UNO_CHCOLHDR )
+ bChartColAsHdr = false;
+ else if ( pEntry->nWID == SC_WID_UNO_CHROWHDR )
+ bChartRowAsHdr = false;
+ else if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
+ {
+ OUString aStyleName( ScResId( STR_STYLENAME_STANDARD ) );
+ pDocShell->GetDocFunc().ApplyStyle( *GetMarkData(), aStyleName, true );
+ }
+ }
+}
+
+uno::Any SAL_CALL ScCellRangesBase::getPropertyDefault( const OUString& aPropertyName )
+{
+ //! bundle with getPropertyValue
+
+ SolarMutexGuard aGuard;
+ uno::Any aAny;
+
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( pEntry )
+ {
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ const ScPatternAttr* pPattern = rDoc.GetDefPattern();
+ if ( pPattern )
+ {
+ const SfxItemSet& rSet = pPattern->GetItemSet();
+
+ switch ( pEntry->nWID ) // for item-specific handling
+ {
+ case ATTR_VALUE_FORMAT:
+ // default has no language set
+ aAny <<= static_cast<sal_Int32>( static_cast<const SfxUInt32Item&>(rSet.Get(pEntry->nWID)).GetValue() );
+ break;
+ case ATTR_INDENT:
+ aAny <<= static_cast<sal_Int16>( convertTwipToMm100(static_cast<const ScIndentItem&>(
+ rSet.Get(pEntry->nWID)).GetValue()) );
+ break;
+ default:
+ pPropSet->getPropertyValue(aPropertyName, rSet, aAny);
+ }
+ }
+ }
+ else
+ switch ( pEntry->nWID )
+ {
+ case SC_WID_UNO_CHCOLHDR:
+ case SC_WID_UNO_CHROWHDR:
+ aAny <<= false;
+ break;
+ case SC_WID_UNO_CELLSTYL:
+ aAny <<= ScStyleNameConversion::DisplayToProgrammaticName(
+ ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Para );
+ break;
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ {
+ const ScPatternAttr* pPattern = rDoc.GetDefPattern();
+ if ( pPattern )
+ {
+ if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
+ ScHelperFunctions::AssignTableBorder2ToAny( aAny,
+ pPattern->GetItem(ATTR_BORDER),
+ pPattern->GetItem(ATTR_BORDER_INNER) );
+ else
+ ScHelperFunctions::AssignTableBorderToAny( aAny,
+ pPattern->GetItem(ATTR_BORDER),
+ pPattern->GetItem(ATTR_BORDER_INNER) );
+ }
+ }
+ break;
+ case SC_WID_UNO_CONDFMT:
+ case SC_WID_UNO_CONDLOC:
+ case SC_WID_UNO_CONDXML:
+ {
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ rDoc.GetStorageGrammar() :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+
+ aAny <<= uno::Reference<sheet::XSheetConditionalEntries>(
+ new ScTableConditionalFormat( &rDoc, 0, aRanges[0].aStart.Tab(), eGrammar ));
+ }
+ break;
+ case SC_WID_UNO_VALIDAT:
+ case SC_WID_UNO_VALILOC:
+ case SC_WID_UNO_VALIXML:
+ {
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ rDoc.GetStorageGrammar() :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+
+ aAny <<= uno::Reference<beans::XPropertySet>(
+ new ScTableValidationObj( rDoc, 0, eGrammar ));
+ }
+ break;
+ case SC_WID_UNO_NUMRULES:
+ {
+ aAny <<= ScStyleObj::CreateEmptyNumberingRules();
+ }
+ break;
+ }
+ }
+ }
+
+ return aAny;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCellRangesBase::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pPropSet->getPropertyMap() ));
+ return aRef;
+}
+
+static void lcl_SetCellProperty( const SfxItemPropertyMapEntry& rEntry, const uno::Any& rValue,
+ ScPatternAttr& rPattern, const ScDocument &rDoc,
+ sal_uInt16& rFirstItemId, sal_uInt16& rSecondItemId )
+{
+ rFirstItemId = rEntry.nWID;
+ rSecondItemId = 0;
+
+ SfxItemSet& rSet = rPattern.GetItemSet();
+ switch ( rEntry.nWID )
+ {
+ case ATTR_VALUE_FORMAT:
+ {
+ // language for number formats
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ sal_uLong nOldFormat = rSet.Get( ATTR_VALUE_FORMAT ).GetValue();
+ LanguageType eOldLang = rSet.Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
+ nOldFormat = pFormatter->GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
+
+ sal_Int32 nIntVal = 0;
+ if ( !(rValue >>= nIntVal) )
+ throw lang::IllegalArgumentException();
+
+ sal_uLong nNewFormat = static_cast<sal_uLong>(nIntVal);
+ rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
+
+ const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
+ LanguageType eNewLang =
+ pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
+ if ( eNewLang != eOldLang && eNewLang != LANGUAGE_DONTKNOW )
+ {
+ rSet.Put( SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
+
+ // if only language is changed,
+ // don't touch number format attribute
+ sal_uLong nNewMod = nNewFormat % SV_COUNTRY_LANGUAGE_OFFSET;
+ if ( nNewMod == ( nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET ) &&
+ nNewMod <= SV_MAX_COUNT_STANDARD_FORMATS )
+ {
+ rFirstItemId = 0; // don't use ATTR_VALUE_FORMAT value
+ }
+
+ rSecondItemId = ATTR_LANGUAGE_FORMAT;
+ }
+
+ }
+ break;
+ case ATTR_INDENT:
+ {
+ sal_Int16 nIntVal = 0;
+ if ( !(rValue >>= nIntVal) )
+ throw lang::IllegalArgumentException();
+
+ rSet.Put(ScIndentItem(o3tl::toTwips(nIntVal, o3tl::Length::mm100)));
+
+ }
+ break;
+ case ATTR_ROTATE_VALUE:
+ {
+ sal_Int32 nRotVal = 0;
+ if ( !(rValue >>= nRotVal) )
+ throw lang::IllegalArgumentException();
+
+ // stored value is always between 0 and 360 deg.
+ nRotVal %= 36000;
+ if ( nRotVal < 0 )
+ nRotVal += 36000;
+
+ rSet.Put( ScRotateValueItem( Degree100(nRotVal) ) );
+
+ }
+ break;
+ case ATTR_STACKED:
+ {
+ table::CellOrientation eOrient;
+ if( rValue >>= eOrient )
+ {
+ switch( eOrient )
+ {
+ case table::CellOrientation_STANDARD:
+ rSet.Put( ScVerticalStackCell( false ) );
+ break;
+ case table::CellOrientation_TOPBOTTOM:
+ rSet.Put( ScVerticalStackCell( false ) );
+ rSet.Put( ScRotateValueItem( 27000_deg100 ) );
+ rSecondItemId = ATTR_ROTATE_VALUE;
+ break;
+ case table::CellOrientation_BOTTOMTOP:
+ rSet.Put( ScVerticalStackCell( false ) );
+ rSet.Put( ScRotateValueItem( 9000_deg100 ) );
+ rSecondItemId = ATTR_ROTATE_VALUE;
+ break;
+ case table::CellOrientation_STACKED:
+ rSet.Put( ScVerticalStackCell( true ) );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ break;
+ default:
+ {
+ lcl_GetCellsPropertySet()->setPropertyValue(rEntry, rValue, rSet);
+ }
+ }
+}
+
+void SAL_CALL ScCellRangesBase::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell || aRanges.empty() )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ SetOnePropertyValue( pEntry, aValue );
+}
+
+void ScCellRangesBase::SetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue )
+{
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ if ( !aRanges.empty() ) // empty = nothing to do
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ // For parts of compound items with multiple properties (e.g. background)
+ // the old item has to be first fetched from the document.
+ //! But we can't recognize this case here
+ //! -> an extra flag in PropertyMap entry, or something like that???
+ //! fetch the item directly from its position in the range?
+ // ClearInvalidItems, so that in any case we have an item with the correct type
+
+ ScPatternAttr aPattern( *GetCurrentAttrsDeep() );
+ SfxItemSet& rSet = aPattern.GetItemSet();
+ rSet.ClearInvalidItems();
+
+ sal_uInt16 nFirstItem, nSecondItem;
+ lcl_SetCellProperty( *pEntry, aValue, aPattern, rDoc, nFirstItem, nSecondItem );
+
+ for (sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; nWhich++)
+ if ( nWhich != nFirstItem && nWhich != nSecondItem )
+ rSet.ClearItem(nWhich);
+
+ pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), aPattern, true );
+ }
+ }
+ else // implemented here
+ switch ( pEntry->nWID )
+ {
+ case EE_CHAR_ESCAPEMENT: // Specifically for xlsx import
+ {
+ sal_Int32 nValue = 0;
+ aValue >>= nValue;
+ if (nValue)
+ {
+ for (size_t i = 0, n = aRanges.size(); i < n; ++i)
+ {
+ ScRange const & rRange = aRanges[i];
+
+ /* TODO: Iterate through the range */
+ ScAddress aAddr = rRange.aStart;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRefCellValue aCell(rDoc, aAddr);
+
+ OUString aStr = aCell.getString(&rDoc);
+ EditEngine aEngine( rDoc.GetEnginePool() );
+ aEngine.SetEditTextObjectPool(rDoc.GetEditPool());
+
+ /* EE_CHAR_ESCAPEMENT seems to be set on the cell _only_ when
+ * there are no other attribs for the cell.
+ * So, it is safe to overwrite the complete attribute set.
+ * If there is a need - getting CellType and processing
+ * the attributes could be considered.
+ */
+ SfxItemSet aAttr = aEngine.GetEmptyItemSet();
+ aEngine.SetText(aStr);
+ if( nValue < 0 ) // Subscript
+ aAttr.Put( SvxEscapementItem( SvxEscapement::Subscript, EE_CHAR_ESCAPEMENT ) );
+ else // Superscript
+ aAttr.Put( SvxEscapementItem( SvxEscapement::Superscript, EE_CHAR_ESCAPEMENT ) );
+ aEngine.QuickSetAttribs(aAttr, ESelection(0, 0, 0, aStr.getLength()));
+
+ // The cell will own the text object instance.
+ rDoc.SetEditText(aRanges[0].aStart, aEngine.CreateTextObject());
+ }
+ }
+ }
+ break;
+ case SC_WID_UNO_CHCOLHDR:
+ // chart header flags are set for this object, not stored with document
+ bChartColAsHdr = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ break;
+ case SC_WID_UNO_CHROWHDR:
+ bChartRowAsHdr = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ break;
+ case SC_WID_UNO_CELLSTYL:
+ {
+ OUString aStrVal;
+ aValue >>= aStrVal;
+ OUString aString(ScStyleNameConversion::ProgrammaticToDisplayName(
+ aStrVal, SfxStyleFamily::Para ));
+ pDocShell->GetDocFunc().ApplyStyle( *GetMarkData(), aString, true );
+ }
+ break;
+ case SC_WID_UNO_TBLBORD:
+ {
+ table::TableBorder aBorder;
+ if ( !aRanges.empty() && ( aValue >>= aBorder ) ) // empty = nothing to do
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder );
+
+ ScHelperFunctions::ApplyBorder( pDocShell, aRanges, aOuter, aInner ); //! docfunc
+ }
+ }
+ break;
+ case SC_WID_UNO_TBLBORD2:
+ {
+ table::TableBorder2 aBorder2;
+ if ( !aRanges.empty() && ( aValue >>= aBorder2 ) ) // empty = nothing to do
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems( aOuter, aInner, aBorder2 );
+
+ ScHelperFunctions::ApplyBorder( pDocShell, aRanges, aOuter, aInner ); //! docfunc
+ }
+ }
+ break;
+ case SC_WID_UNO_CONDFMT:
+ case SC_WID_UNO_CONDLOC:
+ case SC_WID_UNO_CONDXML:
+ {
+ uno::Reference<sheet::XSheetConditionalEntries> xInterface(aValue, uno::UNO_QUERY);
+ if ( !aRanges.empty() && xInterface.is() ) // empty = nothing to do
+ {
+ ScTableConditionalFormat* pFormat =
+ comphelper::getFromUnoTunnel<ScTableConditionalFormat>( xInterface );
+ if (pFormat)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ formula::FormulaGrammar::GRAM_UNSPECIFIED :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+
+ SCTAB nTab = aRanges.front().aStart.Tab();
+ // To remove conditional formats for all cells in aRanges we need to:
+ // Remove conditional format data from cells' attributes
+ rDoc.RemoveCondFormatData( aRanges, nTab, 0 );
+ // And also remove ranges from conditional formats list
+ for (size_t i = 0; i < aRanges.size(); ++i)
+ {
+ rDoc.GetCondFormList( aRanges[i].aStart.Tab() )->DeleteArea(
+ aRanges[i].aStart.Col(), aRanges[i].aStart.Row(),
+ aRanges[i].aEnd.Col(), aRanges[i].aEnd.Row() );
+ }
+
+ // Then we can apply new conditional format if there is one
+ if (pFormat->getCount())
+ {
+ auto pNew = std::make_unique<ScConditionalFormat>( 0, &rDoc ); // Index will be set on inserting
+ pFormat->FillFormat( *pNew, rDoc, eGrammar );
+ pNew->SetRange( aRanges );
+ pDocShell->GetDocFunc().ReplaceConditionalFormat( 0, std::move(pNew), nTab, aRanges );
+ }
+
+ // and repaint
+ for (size_t i = 0; i < aRanges.size(); ++i)
+ pDocShell->PostPaint(aRanges[i], PaintPartFlags::Grid);
+ pDocShell->SetDocumentModified();
+ }
+ }
+ }
+ break;
+ case SC_WID_UNO_VALIDAT:
+ case SC_WID_UNO_VALILOC:
+ case SC_WID_UNO_VALIXML:
+ {
+ uno::Reference<beans::XPropertySet> xInterface(aValue, uno::UNO_QUERY);
+ if ( !aRanges.empty() && xInterface.is() ) // empty = nothing to do
+ {
+ ScTableValidationObj* pValidObj =
+ comphelper::getFromUnoTunnel<ScTableValidationObj>( xInterface );
+ if (pValidObj)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ formula::FormulaGrammar::GRAM_UNSPECIFIED :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+
+ std::unique_ptr<ScValidationData> pNewData(
+ pValidObj->CreateValidationData( rDoc, eGrammar ));
+ sal_uLong nIndex = rDoc.AddValidationEntry( *pNewData );
+ pNewData.reset();
+
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nIndex ) );
+ pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), aPattern, true );
+ }
+ }
+ }
+ break;
+ // SC_WID_UNO_NUMRULES is ignored...
+ }
+}
+
+uno::Any SAL_CALL ScCellRangesBase::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell || aRanges.empty() )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+ GetOnePropertyValue( pEntry, aAny );
+ return aAny;
+}
+
+void ScCellRangesBase::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ SfxItemSet* pDataSet = GetCurrentDataSet();
+ if ( pDataSet )
+ {
+ switch ( pEntry->nWID ) // for special handling of items
+ {
+ case ATTR_VALUE_FORMAT:
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ sal_uLong nOldFormat =
+ pDataSet->Get( ATTR_VALUE_FORMAT ).GetValue();
+ LanguageType eOldLang =
+ pDataSet->Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
+ nOldFormat = rDoc.GetFormatTable()->
+ GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
+ rAny <<= static_cast<sal_Int32>(nOldFormat);
+ }
+ break;
+ case ATTR_INDENT:
+ rAny <<= static_cast<sal_Int16>( convertTwipToMm100(static_cast<const ScIndentItem&>(
+ pDataSet->Get(pEntry->nWID)).GetValue()) );
+ break;
+ case ATTR_STACKED:
+ {
+ Degree100 nRot = pDataSet->Get(ATTR_ROTATE_VALUE).GetValue();
+ bool bStacked = static_cast<const ScVerticalStackCell&>(pDataSet->Get(pEntry->nWID)).GetValue();
+ SvxOrientationItem( nRot, bStacked, TypedWhichId<SvxOrientationItem>(0) ).QueryValue( rAny );
+ }
+ break;
+ default:
+ pPropSet->getPropertyValue(*pEntry, *pDataSet, rAny);
+ }
+ }
+ }
+ else // implemented here
+ switch ( pEntry->nWID )
+ {
+ case SC_WID_UNO_CHCOLHDR:
+ rAny <<= bChartColAsHdr;
+ break;
+ case SC_WID_UNO_CHROWHDR:
+ rAny <<= bChartRowAsHdr;
+ break;
+ case SC_WID_UNO_CELLSTYL:
+ {
+ OUString aStyleName;
+ const ScStyleSheet* pStyle = pDocShell->GetDocument().GetSelectionStyle(*GetMarkData());
+ if (pStyle)
+ aStyleName = pStyle->GetName();
+ rAny <<= ScStyleNameConversion::DisplayToProgrammaticName(
+ aStyleName, SfxStyleFamily::Para );
+ }
+ break;
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ {
+ //! loop through all ranges
+ if ( !aRanges.empty() )
+ {
+ const ScRange & rFirst = aRanges[ 0 ];
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SetMarkArea( rFirst );
+ aMark.SelectTable( rFirst.aStart.Tab(), true );
+ rDoc.GetSelectionFrame( aMark, aOuter, aInner );
+
+ if (pEntry->nWID == SC_WID_UNO_TBLBORD2)
+ ScHelperFunctions::AssignTableBorder2ToAny( rAny, aOuter, aInner);
+ else
+ ScHelperFunctions::AssignTableBorderToAny( rAny, aOuter, aInner);
+ }
+ }
+ break;
+ case SC_WID_UNO_CONDFMT:
+ case SC_WID_UNO_CONDLOC:
+ case SC_WID_UNO_CONDXML:
+ {
+ const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
+ if ( pPattern )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_CONDLOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_CONDXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ rDoc.GetStorageGrammar() :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+ const ScCondFormatIndexes& rIndex =
+ pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
+ sal_uLong nIndex = 0;
+ if(!rIndex.empty())
+ nIndex = rIndex[0];
+ rAny <<= uno::Reference<sheet::XSheetConditionalEntries>(
+ new ScTableConditionalFormat( &rDoc, nIndex, aRanges.front().aStart.Tab(), eGrammar ));
+ }
+ }
+ break;
+ case SC_WID_UNO_VALIDAT:
+ case SC_WID_UNO_VALILOC:
+ case SC_WID_UNO_VALIXML:
+ {
+ const ScPatternAttr* pPattern = GetCurrentAttrsDeep();
+ if ( pPattern )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bEnglish = ( pEntry->nWID != SC_WID_UNO_VALILOC );
+ bool bXML = ( pEntry->nWID == SC_WID_UNO_VALIXML );
+ formula::FormulaGrammar::Grammar eGrammar = (bXML ?
+ rDoc.GetStorageGrammar() :
+ formula::FormulaGrammar::mapAPItoGrammar( bEnglish, bXML));
+ sal_uLong nIndex =
+ pPattern->GetItem(ATTR_VALIDDATA).GetValue();
+ rAny <<= uno::Reference<beans::XPropertySet>(
+ new ScTableValidationObj( rDoc, nIndex, eGrammar ));
+ }
+ }
+ break;
+ case SC_WID_UNO_NUMRULES:
+ {
+ // always return empty numbering rules object
+ rAny <<= ScStyleObj::CreateEmptyNumberingRules();
+ }
+ break;
+ case SC_WID_UNO_ABSNAME:
+ {
+ OUString sRet;
+ aRanges.Format(sRet, ScRefFlags::RANGE_ABS_3D, pDocShell->GetDocument());
+ rAny <<= sRet;
+ }
+ break;
+ case SC_WID_UNO_FORMATID:
+ {
+ const ScPatternAttr* pPattern = GetCurrentAttrsFlat();
+ rAny <<= pPattern->GetKey();
+ }
+ break;
+ }
+}
+
+void SAL_CALL ScCellRangesBase::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SolarMutexGuard aGuard;
+ if ( aRanges.empty() )
+ throw uno::RuntimeException();
+
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellRangesBase::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SolarMutexGuard aGuard;
+ if ( aRanges.empty() )
+ throw uno::RuntimeException();
+
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellRangesBase::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellRangesBase::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ OSL_FAIL("not implemented");
+}
+
+// XMultiPropertySet
+
+void SAL_CALL ScCellRangesBase::setPropertyValues( const uno::Sequence< OUString >& aPropertyNames,
+ const uno::Sequence< uno::Any >& aValues )
+{
+ SolarMutexGuard aGuard;
+
+ sal_Int32 nCount(aPropertyNames.getLength());
+ sal_Int32 nValues(aValues.getLength());
+ if (nCount != nValues)
+ throw lang::IllegalArgumentException();
+
+ if ( !(pDocShell && nCount) )
+ return;
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ const OUString* pNames = aPropertyNames.getConstArray();
+ const uno::Any* pValues = aValues.getConstArray();
+
+ std::unique_ptr<const SfxItemPropertyMapEntry*[]> pEntryArray(new const SfxItemPropertyMapEntry*[nCount]);
+
+ sal_Int32 i;
+ for(i = 0; i < nCount; i++)
+ {
+ // first loop: find all properties in map, but handle only CellStyle
+ // (CellStyle must be set before any other cell properties)
+
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( pNames[i] );
+ pEntryArray[i] = pEntry;
+ if (pEntry)
+ {
+ if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
+ {
+ try
+ {
+ SetOnePropertyValue( pEntry, pValues[i] );
+ }
+ catch ( lang::IllegalArgumentException& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "exception when setting cell style"); // not supposed to happen
+ }
+ }
+ }
+ }
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::unique_ptr<ScPatternAttr> pOldPattern;
+ std::unique_ptr<ScPatternAttr> pNewPattern;
+
+ for(i = 0; i < nCount; i++)
+ {
+ // second loop: handle other properties
+
+ const SfxItemPropertyMapEntry* pEntry = pEntryArray[i];
+ if ( pEntry )
+ {
+ if ( IsScItemWid( pEntry->nWID ) ) // can be handled by SfxItemPropertySet
+ {
+ if ( !pOldPattern )
+ {
+ pOldPattern.reset(new ScPatternAttr( *GetCurrentAttrsDeep() ));
+ pOldPattern->GetItemSet().ClearInvalidItems();
+ pNewPattern.reset(new ScPatternAttr( rDoc.GetPool() ));
+ }
+
+ // collect items in pNewPattern, apply with one call after the loop
+
+ sal_uInt16 nFirstItem, nSecondItem;
+ lcl_SetCellProperty( *pEntry, pValues[i], *pOldPattern, rDoc, nFirstItem, nSecondItem );
+
+ // put only affected items into new set
+ if ( nFirstItem )
+ pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nFirstItem ) );
+ if ( nSecondItem )
+ pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nSecondItem ) );
+ }
+ else if ( pEntry->nWID != SC_WID_UNO_CELLSTYL ) // CellStyle is handled above
+ {
+ // call virtual method to set a single property
+ SetOnePropertyValue( pEntry, pValues[i] );
+ }
+ }
+ }
+
+ if ( pNewPattern && !aRanges.empty() )
+ pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), *pNewPattern, true );
+}
+
+uno::Sequence<uno::Any> SAL_CALL ScCellRangesBase::getPropertyValues(
+ const uno::Sequence< OUString >& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+
+ uno::Sequence<uno::Any> aRet(aPropertyNames.getLength());
+ uno::Any* pProperties = aRet.getArray();
+ for(sal_Int32 i = 0; i < aPropertyNames.getLength(); i++)
+ {
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
+ GetOnePropertyValue( pEntry, pProperties[i] );
+ }
+ return aRet;
+}
+
+void SAL_CALL ScCellRangesBase::addPropertiesChangeListener( const uno::Sequence< OUString >& /* aPropertyNames */,
+ const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellRangesBase::removePropertiesChangeListener( const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellRangesBase::firePropertiesChangeEvent( const uno::Sequence< OUString >& /* aPropertyNames */,
+ const uno::Reference< beans::XPropertiesChangeListener >& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+IMPL_LINK( ScCellRangesBase, ValueListenerHdl, const SfxHint&, rHint, void )
+{
+ if ( pDocShell && (rHint.GetId() == SfxHintId::ScDataChanged))
+ {
+ // This may be called several times for a single change, if several formulas
+ // in the range are notified. So only a flag is set that is checked when
+ // SfxHintId::DataChanged is received.
+
+ bGotDataChangedHint = true;
+ }
+}
+
+// XTolerantMultiPropertySet
+uno::Sequence< beans::SetPropertyTolerantFailed > SAL_CALL ScCellRangesBase::setPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames,
+ const uno::Sequence< uno::Any >& aValues )
+{
+ SolarMutexGuard aGuard;
+
+ sal_Int32 nCount(aPropertyNames.getLength());
+ sal_Int32 nValues(aValues.getLength());
+ if (nCount != nValues)
+ throw lang::IllegalArgumentException();
+
+ if ( pDocShell && nCount )
+ {
+ uno::Sequence < beans::SetPropertyTolerantFailed > aReturns(nCount);
+ beans::SetPropertyTolerantFailed* pReturns = aReturns.getArray();
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+ const OUString* pNames = aPropertyNames.getConstArray();
+ const uno::Any* pValues = aValues.getConstArray();
+
+ std::unique_ptr<const SfxItemPropertyMapEntry*[]> pMapArray(new const SfxItemPropertyMapEntry*[nCount]);
+
+ sal_Int32 i;
+ for(i = 0; i < nCount; i++)
+ {
+ // first loop: find all properties in map, but handle only CellStyle
+ // (CellStyle must be set before any other cell properties)
+
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( pNames[i] );
+ pMapArray[i] = pEntry;
+ if (pEntry)
+ {
+ if ( pEntry->nWID == SC_WID_UNO_CELLSTYL )
+ {
+ try
+ {
+ SetOnePropertyValue( pEntry, pValues[i] );
+ }
+ catch ( lang::IllegalArgumentException& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "exception when setting cell style"); // not supposed to happen
+ }
+ }
+ }
+ }
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::unique_ptr<ScPatternAttr> pOldPattern;
+ std::unique_ptr<ScPatternAttr> pNewPattern;
+
+ sal_Int32 nFailed(0);
+ for(i = 0; i < nCount; i++)
+ {
+ // second loop: handle other properties
+
+ const SfxItemPropertyMapEntry* pEntry = pMapArray[i];
+ if ( pEntry && ((pEntry->nFlags & beans::PropertyAttribute::READONLY) == 0))
+ {
+ if ( IsScItemWid( pEntry->nWID ) ) // can be handled by SfxItemPropertySet
+ {
+ if ( !pOldPattern )
+ {
+ pOldPattern.reset(new ScPatternAttr( *GetCurrentAttrsDeep() ));
+ pOldPattern->GetItemSet().ClearInvalidItems();
+ pNewPattern.reset(new ScPatternAttr( rDoc.GetPool() ));
+ }
+
+ // collect items in pNewPattern, apply with one call after the loop
+ try
+ {
+ sal_uInt16 nFirstItem, nSecondItem;
+ lcl_SetCellProperty( *pEntry, pValues[i], *pOldPattern, rDoc, nFirstItem, nSecondItem );
+
+ // put only affected items into new set
+ if ( nFirstItem )
+ pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nFirstItem ) );
+ if ( nSecondItem )
+ pNewPattern->GetItemSet().Put( pOldPattern->GetItemSet().Get( nSecondItem ) );
+ }
+ catch ( lang::IllegalArgumentException& )
+ {
+ pReturns[nFailed].Name = pNames[i];
+ pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT;
+ }
+ }
+ else if ( pEntry->nWID != SC_WID_UNO_CELLSTYL ) // CellStyle is handled above
+ {
+ // call virtual method to set a single property
+ try
+ {
+ SetOnePropertyValue( pEntry, pValues[i] );
+ }
+ catch ( lang::IllegalArgumentException& )
+ {
+ pReturns[nFailed].Name = pNames[i];
+ pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::ILLEGAL_ARGUMENT;
+ }
+ }
+ }
+ else
+ {
+ pReturns[nFailed].Name = pNames[i];
+ if (pEntry)
+ pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::PROPERTY_VETO;
+ else
+ pReturns[nFailed++].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
+ }
+ }
+
+ if ( pNewPattern && !aRanges.empty() )
+ pDocShell->GetDocFunc().ApplyAttributes( *GetMarkData(), *pNewPattern, true );
+
+ aReturns.realloc(nFailed);
+
+ return aReturns;
+ }
+ return uno::Sequence < beans::SetPropertyTolerantFailed >();
+}
+
+uno::Sequence< beans::GetPropertyTolerantResult > SAL_CALL ScCellRangesBase::getPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+
+ sal_Int32 nCount(aPropertyNames.getLength());
+ uno::Sequence < beans::GetPropertyTolerantResult > aReturns(nCount);
+ beans::GetPropertyTolerantResult* pReturns = aReturns.getArray();
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+
+ for(sal_Int32 i = 0; i < nCount; i++)
+ {
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
+ if (!pEntry)
+ {
+ pReturns[i].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
+ }
+ else
+ {
+ sal_uInt16 nItemWhich = 0;
+ lcl_GetPropertyWhich( pEntry, nItemWhich );
+ pReturns[i].State = GetOnePropertyState( nItemWhich, pEntry );
+ GetOnePropertyValue( pEntry, pReturns[i].Value );
+ pReturns[i].Result = beans::TolerantPropertySetResultType::SUCCESS;
+ }
+ }
+ return aReturns;
+}
+
+uno::Sequence< beans::GetDirectPropertyTolerantResult > SAL_CALL ScCellRangesBase::getDirectPropertyValuesTolerant( const uno::Sequence< OUString >& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+
+ sal_Int32 nCount(aPropertyNames.getLength());
+ uno::Sequence < beans::GetDirectPropertyTolerantResult > aReturns(nCount);
+ beans::GetDirectPropertyTolerantResult* pReturns = aReturns.getArray();
+
+ const SfxItemPropertyMap& rPropertyMap = GetItemPropertyMap(); // from derived class
+
+ sal_Int32 j = 0;
+ for(sal_Int32 i = 0; i < nCount; i++)
+ {
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyNames[i] );
+ if (!pEntry)
+ {
+ pReturns[i].Result = beans::TolerantPropertySetResultType::UNKNOWN_PROPERTY;
+ }
+ else
+ {
+ sal_uInt16 nItemWhich = 0;
+ lcl_GetPropertyWhich( pEntry, nItemWhich );
+ pReturns[j].State = GetOnePropertyState( nItemWhich, pEntry );
+ if (pReturns[j].State == beans::PropertyState_DIRECT_VALUE)
+ {
+ GetOnePropertyValue( pEntry, pReturns[j].Value );
+ pReturns[j].Result = beans::TolerantPropertySetResultType::SUCCESS;
+ pReturns[j].Name = aPropertyNames[i];
+ ++j;
+ }
+ }
+ }
+ if (j < nCount)
+ aReturns.realloc(j);
+ return aReturns;
+}
+
+// XIndent
+
+void SAL_CALL ScCellRangesBase::decrementIndent()
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell && !aRanges.empty() )
+ {
+ //#97041#; put only MultiMarked ScMarkData in ChangeIndent
+ ScMarkData aMarkData(*GetMarkData());
+ aMarkData.MarkToMulti();
+ pDocShell->GetDocFunc().ChangeIndent( aMarkData, false, true );
+ }
+}
+
+void SAL_CALL ScCellRangesBase::incrementIndent()
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell && !aRanges.empty() )
+ {
+ //#97041#; put only MultiMarked ScMarkData in ChangeIndent
+ ScMarkData aMarkData(*GetMarkData());
+ aMarkData.MarkToMulti();
+ pDocShell->GetDocFunc().ChangeIndent( aMarkData, true, true );
+ }
+}
+
+// XChartData
+
+std::unique_ptr<ScMemChart> ScCellRangesBase::CreateMemChart_Impl() const
+{
+ if ( pDocShell && !aRanges.empty() )
+ {
+ ScRangeListRef xChartRanges;
+ if ( aRanges.size() == 1 )
+ {
+ // set useful table limit (only occupied data area)
+ // (only here - Listeners are registered for the whole area)
+ //! check immediately if a ScTableSheetObj?
+
+ const ScDocument & rDoc = pDocShell->GetDocument();
+ const ScRange & rRange = aRanges[0];
+ if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
+ rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
+ {
+ SCTAB nTab = rRange.aStart.Tab();
+
+ SCCOL nStartX;
+ SCROW nStartY; // Get start
+ if (!pDocShell->GetDocument().GetDataStart( nTab, nStartX, nStartY ))
+ {
+ nStartX = 0;
+ nStartY = 0;
+ }
+
+ SCCOL nEndX;
+ SCROW nEndY; // Get end
+ if (!pDocShell->GetDocument().GetTableArea( nTab, nEndX, nEndY ))
+ {
+ nEndX = 0;
+ nEndY = 0;
+ }
+
+ xChartRanges = new ScRangeList( ScRange( nStartX, nStartY, nTab, nEndX, nEndY, nTab ) );
+ }
+ }
+ if (!xChartRanges.is()) // otherwise take Ranges directly
+ xChartRanges = new ScRangeList(aRanges);
+ ScChartArray aArr( pDocShell->GetDocument(), xChartRanges );
+
+ // RowAsHdr = ColHeaders and vice versa
+ aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr );
+
+ return aArr.CreateMemChart();
+ }
+ return nullptr;
+}
+
+uno::Sequence< uno::Sequence<double> > SAL_CALL ScCellRangesBase::getData()
+{
+ SolarMutexGuard aGuard;
+ std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
+ if ( pMemChart )
+ {
+ sal_Int32 nColCount = pMemChart->GetColCount();
+ sal_Int32 nRowCount = static_cast<sal_Int32>(pMemChart->GetRowCount());
+
+ uno::Sequence< uno::Sequence<double> > aRowSeq( nRowCount );
+ uno::Sequence<double>* pRowAry = aRowSeq.getArray();
+ for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
+ {
+ uno::Sequence<double> aColSeq( nColCount );
+ double* pColAry = aColSeq.getArray();
+ for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
+ pColAry[nCol] = pMemChart->GetData( nCol, nRow );
+
+ pRowAry[nRow] = aColSeq;
+ }
+
+ return aRowSeq;
+ }
+
+ return {};
+}
+
+ScRangeListRef ScCellRangesBase::GetLimitedChartRanges_Impl( sal_Int32 nDataColumns, sal_Int32 nDataRows ) const
+{
+ if ( aRanges.size() == 1 )
+ {
+ const ScDocument & rDoc = pDocShell->GetDocument();
+ const ScRange & rRange = aRanges[0];
+ if ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() &&
+ rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() )
+ {
+ // if aRanges is a complete sheet, limit to given size
+
+ SCTAB nTab = rRange.aStart.Tab();
+
+ sal_Int32 nEndColumn = nDataColumns - 1 + ( bChartColAsHdr ? 1 : 0 );
+ if ( nEndColumn < 0 )
+ nEndColumn = 0;
+ if ( nEndColumn > rDoc.MaxCol() )
+ nEndColumn = rDoc.MaxCol();
+
+ sal_Int32 nEndRow = nDataRows - 1 + ( bChartRowAsHdr ? 1 : 0 );
+ if ( nEndRow < 0 )
+ nEndRow = 0;
+ if ( nEndRow > rDoc.MaxRow() )
+ nEndRow = rDoc.MaxRow();
+
+ ScRangeListRef xChartRanges = new ScRangeList( ScRange( 0, 0, nTab, static_cast<SCCOL>(nEndColumn), static_cast<SCROW>(nEndRow), nTab ) );
+ return xChartRanges;
+ }
+ }
+
+ return new ScRangeList(aRanges); // as-is
+}
+
+void SAL_CALL ScCellRangesBase::setData( const uno::Sequence< uno::Sequence<double> >& aData )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ sal_Int32 nRowCount = aData.getLength();
+ sal_Int32 nColCount = nRowCount ? aData[0].getLength() : 0;
+ ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( nColCount, nRowCount );
+ if ( pDocShell && xChartRanges.is() )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChartArray aArr( rDoc, xChartRanges );
+ aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
+ const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
+ if (pPosMap)
+ {
+ if ( pPosMap->GetColCount() == static_cast<SCCOL>(nColCount) &&
+ pPosMap->GetRowCount() == static_cast<SCROW>(nRowCount) )
+ {
+ for (sal_Int32 nRow=0; nRow<nRowCount; nRow++)
+ {
+ const uno::Sequence<double>& rRowSeq = aData[nRow];
+ const double* pArray = rRowSeq.getConstArray();
+ nColCount = rRowSeq.getLength();
+ for (sal_Int32 nCol=0; nCol<nColCount; nCol++)
+ {
+ const ScAddress* pPos = pPosMap->GetPosition(
+ sal::static_int_cast<SCCOL>(nCol),
+ sal::static_int_cast<SCROW>(nRow) );
+ if (pPos)
+ {
+ double fVal = pArray[nCol];
+ if ( fVal == DBL_MIN )
+ rDoc.SetEmptyCell(*pPos);
+ else
+ rDoc.SetValue(*pPos, pArray[nCol]);
+ }
+ }
+ }
+
+ //! undo
+ PaintGridRanges_Impl();
+ pDocShell->SetDocumentModified();
+ ForceChartListener_Impl(); // call listeners for this object synchronously
+ bDone = true;
+ }
+ }
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException();
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellRangesBase::getRowDescriptions()
+{
+ SolarMutexGuard aGuard;
+ std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
+ if ( pMemChart )
+ {
+ sal_Int32 nRowCount = static_cast<sal_Int32>(pMemChart->GetRowCount());
+ uno::Sequence<OUString> aSeq( nRowCount );
+ OUString* pAry = aSeq.getArray();
+ for (sal_Int32 nRow = 0; nRow < nRowCount; nRow++)
+ pAry[nRow] = pMemChart->GetRowText(nRow);
+
+ return aSeq;
+ }
+ return {};
+}
+
+void SAL_CALL ScCellRangesBase::setRowDescriptions(
+ const uno::Sequence<OUString>& aRowDescriptions )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if ( bChartColAsHdr )
+ {
+ sal_Int32 nRowCount = aRowDescriptions.getLength();
+ ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( 1, nRowCount );
+ if ( pDocShell && xChartRanges.is() )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChartArray aArr( rDoc, xChartRanges );
+ aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
+ const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
+ if (pPosMap)
+ {
+ if ( pPosMap->GetRowCount() == static_cast<SCROW>(nRowCount) )
+ {
+ const OUString* pArray = aRowDescriptions.getConstArray();
+ for (sal_Int32 nRow=0; nRow<nRowCount; nRow++)
+ {
+ const ScAddress* pPos = pPosMap->GetRowHeaderPosition(
+ static_cast<SCSIZE>(nRow) );
+ if (pPos)
+ {
+ const OUString& aStr = pArray[nRow];
+ if (aStr.isEmpty())
+ rDoc.SetEmptyCell(*pPos);
+ else
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(*pPos, aStr, &aParam);
+ }
+ }
+ }
+
+ //! undo
+ PaintGridRanges_Impl();
+ pDocShell->SetDocumentModified();
+ ForceChartListener_Impl(); // call listeners for this object synchronously
+ bDone = true;
+ }
+ }
+ }
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException();
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellRangesBase::getColumnDescriptions()
+{
+ SolarMutexGuard aGuard;
+ std::unique_ptr<ScMemChart> pMemChart(CreateMemChart_Impl());
+ if ( pMemChart )
+ {
+ sal_Int32 nColCount = pMemChart->GetColCount();
+ uno::Sequence<OUString> aSeq( nColCount );
+ OUString* pAry = aSeq.getArray();
+ for (sal_Int32 nCol = 0; nCol < nColCount; nCol++)
+ pAry[nCol] = pMemChart->GetColText(nCol);
+
+ return aSeq;
+ }
+ return {};
+}
+
+void SAL_CALL ScCellRangesBase::setColumnDescriptions(
+ const uno::Sequence<OUString>& aColumnDescriptions )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if ( bChartRowAsHdr )
+ {
+ sal_Int32 nColCount = aColumnDescriptions.getLength();
+ ScRangeListRef xChartRanges = GetLimitedChartRanges_Impl( nColCount, 1 );
+ if ( pDocShell && xChartRanges.is() )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChartArray aArr( rDoc, xChartRanges );
+ aArr.SetHeaders( bChartRowAsHdr, bChartColAsHdr ); // RowAsHdr = ColHeaders
+ const ScChartPositionMap* pPosMap = aArr.GetPositionMap();
+ if (pPosMap)
+ {
+ if ( pPosMap->GetColCount() == static_cast<SCCOL>(nColCount) )
+ {
+ const OUString* pArray = aColumnDescriptions.getConstArray();
+ for (sal_Int32 nCol=0; nCol<nColCount; nCol++)
+ {
+ const ScAddress* pPos = pPosMap->GetColHeaderPosition(
+ sal::static_int_cast<SCCOL>(nCol) );
+ if (pPos)
+ {
+ const OUString& aStr = pArray[nCol];
+ if (aStr.isEmpty())
+ rDoc.SetEmptyCell(*pPos);
+ else
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ rDoc.SetString(*pPos, aStr, &aParam);
+ }
+ }
+ }
+
+ //! undo
+ PaintGridRanges_Impl();
+ pDocShell->SetDocumentModified();
+ ForceChartListener_Impl(); // call listeners for this object synchronously
+ bDone = true;
+ }
+ }
+ }
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException();
+}
+
+void ScCellRangesBase::ForceChartListener_Impl()
+{
+ // call Update immediately so the caller to setData etc. can
+ // recognize the listener call
+
+ if (!pDocShell)
+ return;
+
+ ScChartListenerCollection* pColl = pDocShell->GetDocument().GetChartListenerCollection();
+ if (!pColl)
+ return;
+
+ ScChartListenerCollection::ListenersType& rListeners = pColl->getListeners();
+ for (auto const& it : rListeners)
+ {
+ ScChartListener *const p = it.second.get();
+ assert(p);
+ if (p->GetUnoSource() == static_cast<chart::XChartData*>(this) && p->IsDirty())
+ p->Update();
+ }
+}
+
+void SAL_CALL ScCellRangesBase::addChartDataChangeEventListener( const uno::Reference<
+ chart::XChartDataChangeEventListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+ if ( !pDocShell || aRanges.empty() )
+ return;
+
+ //! test for duplicates ?
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangeListRef aRangesRef( new ScRangeList(aRanges) );
+ ScChartListenerCollection* pColl = rDoc.GetChartListenerCollection();
+ OUString aName = pColl->getUniqueName(u"__Uno");
+ if (aName.isEmpty())
+ // failed to create unique name.
+ return;
+
+ ScChartListener* pListener = new ScChartListener( aName, rDoc, aRangesRef );
+ pListener->SetUno( aListener, this );
+ pColl->insert( pListener );
+ pListener->StartListeningTo();
+}
+
+void SAL_CALL ScCellRangesBase::removeChartDataChangeEventListener( const uno::Reference<
+ chart::XChartDataChangeEventListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell && !aRanges.empty() )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScChartListenerCollection* pColl = rDoc.GetChartListenerCollection();
+ pColl->FreeUno( aListener, this );
+ }
+}
+
+double SAL_CALL ScCellRangesBase::getNotANumber()
+{
+ // use DBL_MIN in ScChartArray, because Chart wants it so
+ return DBL_MIN;
+}
+
+sal_Bool SAL_CALL ScCellRangesBase::isNotANumber( double nNumber )
+{
+ // use DBL_MIN in ScChartArray, because Chart wants it so
+ return (nNumber == DBL_MIN);
+}
+
+// XModifyBroadcaster
+
+void SAL_CALL ScCellRangesBase::addModifyListener(const uno::Reference<util::XModifyListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+ if ( aRanges.empty() )
+ throw uno::RuntimeException();
+
+ aValueListeners.emplace_back( aListener );
+
+ if ( aValueListeners.size() == 1 )
+ {
+ if (!pValueListener)
+ pValueListener.reset( new ScLinkListener( LINK( this, ScCellRangesBase, ValueListenerHdl ) ) );
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ for ( size_t i = 0, nCount = aRanges.size(); i < nCount; i++)
+ rDoc.StartListeningArea( aRanges[ i ], false, pValueListener.get() );
+
+ acquire(); // don't lose this object (one ref for all listeners)
+ }
+}
+
+void SAL_CALL ScCellRangesBase::removeModifyListener( const uno::Reference<util::XModifyListener>& aListener )
+{
+
+ SolarMutexGuard aGuard;
+ if ( aRanges.empty() )
+ throw uno::RuntimeException();
+
+ rtl::Reference<ScCellRangesBase> xSelfHold(this); // in case the listeners have the last ref
+
+ sal_uInt16 nCount = aValueListeners.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ {
+ uno::Reference<util::XModifyListener>& rObj = aValueListeners[n];
+ if ( rObj == aListener )
+ {
+ aValueListeners.erase( aValueListeners.begin() + n );
+
+ if ( aValueListeners.empty() )
+ {
+ if (pValueListener)
+ pValueListener->EndListeningAll();
+
+ release(); // release the ref for the listeners
+ }
+
+ break;
+ }
+ }
+}
+
+// XCellRangesQuery
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryVisibleCells()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ //! Separate for all tables, if markings separated per table
+ SCTAB nTab = lcl_FirstTab(aRanges);
+
+ ScMarkData aMarkData(*GetMarkData());
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCCOL nCol = 0, nLastCol;
+ while (nCol <= rDoc.MaxCol())
+ {
+ if (rDoc.ColHidden(nCol, nTab, nullptr, &nLastCol))
+ // hidden columns. Deselect them.
+ aMarkData.SetMultiMarkArea(ScRange(nCol, 0, nTab, nLastCol, rDoc.MaxRow(), nTab), false);
+
+ nCol = nLastCol + 1;
+ }
+
+ SCROW nRow = 0, nLastRow;
+ while (nRow <= rDoc.MaxRow())
+ {
+ if (rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow))
+ // These rows are hidden. Deselect them.
+ aMarkData.SetMultiMarkArea(ScRange(0, nRow, nTab, rDoc.MaxCol(), nLastRow, nTab), false);
+
+ nRow = nLastRow + 1;
+ }
+
+ ScRangeList aNewRanges;
+ aMarkData.FillRangeListWithMarks( &aNewRanges, false );
+ return new ScCellRangesObj( pDocShell, aNewRanges );
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryEmptyCells()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScMarkData aMarkData(*GetMarkData());
+
+ // mark occupied cells
+ for (size_t i = 0, nCount = aRanges.size(); i < nCount; ++i)
+ {
+ ScRange const & rRange = aRanges[ i ];
+
+ ScCellIterator aIter(rDoc, rRange);
+ for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
+ {
+ // notes count as non-empty
+ if (!aIter.isEmpty())
+ aMarkData.SetMultiMarkArea(aIter.GetPos(), false);
+ }
+ }
+
+ ScRangeList aNewRanges;
+ // IsMultiMarked is not enough (will not be reset during deselecting)
+ //if (aMarkData.HasAnyMultiMarks()) // #i20044# should be set for all empty range
+ aMarkData.FillRangeListWithMarks( &aNewRanges, false );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryContentCells(
+ sal_Int16 nContentFlags )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+
+ // select matching cells
+ for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
+ {
+ ScRange const & rRange = aRanges[ i ];
+
+ ScCellIterator aIter(rDoc, rRange);
+ for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
+ {
+ bool bAdd = false;
+ switch (aIter.getType())
+ {
+ case CELLTYPE_STRING:
+ if ( nContentFlags & sheet::CellFlags::STRING )
+ bAdd = true;
+ break;
+ case CELLTYPE_EDIT:
+ if ( (nContentFlags & sheet::CellFlags::STRING) || (nContentFlags & sheet::CellFlags::FORMATTED) )
+ bAdd = true;
+ break;
+ case CELLTYPE_FORMULA:
+ if ( nContentFlags & sheet::CellFlags::FORMULA )
+ bAdd = true;
+ break;
+ case CELLTYPE_VALUE:
+ if ( (nContentFlags & (sheet::CellFlags::VALUE|sheet::CellFlags::DATETIME))
+ == (sheet::CellFlags::VALUE|sheet::CellFlags::DATETIME) )
+ bAdd = true;
+ else
+ {
+ // date/time identification
+
+ sal_uLong nIndex = static_cast<sal_uLong>(rDoc.GetAttr(
+ aIter.GetPos(), ATTR_VALUE_FORMAT)->GetValue());
+ SvNumFormatType nTyp = rDoc.GetFormatTable()->GetType(nIndex);
+ if ((nTyp == SvNumFormatType::DATE) || (nTyp == SvNumFormatType::TIME) ||
+ (nTyp == SvNumFormatType::DATETIME))
+ {
+ if ( nContentFlags & sheet::CellFlags::DATETIME )
+ bAdd = true;
+ }
+ else
+ {
+ if ( nContentFlags & sheet::CellFlags::VALUE )
+ bAdd = true;
+ }
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (bAdd)
+ aMarkData.SetMultiMarkArea(aIter.GetPos());
+ }
+ }
+
+ if (nContentFlags & sheet::CellFlags::ANNOTATION)
+ {
+ std::vector<sc::NoteEntry> aNotes;
+ rDoc.GetNotesInRange(aRanges, aNotes);
+
+ for (const auto& i : aNotes)
+ {
+ aMarkData.SetMultiMarkArea(i.maPos);
+ }
+ }
+
+ ScRangeList aNewRanges;
+ if (aMarkData.IsMultiMarked())
+ aMarkData.FillRangeListWithMarks( &aNewRanges, false );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryFormulaCells(
+ sal_Int32 nResultFlags )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+
+ // select matching cells
+ for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
+ {
+ ScRange const & rRange = aRanges[ i ];
+
+ ScCellIterator aIter(rDoc, rRange);
+ for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
+ {
+ if (aIter.getType() == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = aIter.getFormulaCell();
+ bool bAdd = false;
+ if (pFCell->GetErrCode() != FormulaError::NONE)
+ {
+ if ( nResultFlags & sheet::FormulaResult::ERROR )
+ bAdd = true;
+ }
+ else if (pFCell->IsValue())
+ {
+ if ( nResultFlags & sheet::FormulaResult::VALUE )
+ bAdd = true;
+ }
+ else // String
+ {
+ if ( nResultFlags & sheet::FormulaResult::STRING )
+ bAdd = true;
+ }
+
+ if (bAdd)
+ aMarkData.SetMultiMarkArea(aIter.GetPos());
+ }
+ }
+ }
+
+ ScRangeList aNewRanges;
+ if (aMarkData.IsMultiMarked())
+ aMarkData.FillRangeListWithMarks( &aNewRanges, false );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges> ScCellRangesBase::QueryDifferences_Impl(
+ const table::CellAddress& aCompare, bool bColumnDiff)
+{
+ if (pDocShell)
+ {
+ size_t nRangeCount = aRanges.size();
+ size_t i;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+
+ SCCOLROW nCmpPos = bColumnDiff ? static_cast<SCCOLROW>(aCompare.Row) : static_cast<SCCOLROW>(aCompare.Column);
+
+ // first select everything, where at all something is in the comparison column
+ // (in the second step the selection is cancelled for equal cells)
+
+ SCTAB nTab = lcl_FirstTab(aRanges); //! for all tables, if markings per table
+ ScRange aCmpRange, aCellRange;
+ if (bColumnDiff)
+ aCmpRange = ScRange( 0,nCmpPos,nTab, rDoc.MaxCol(),nCmpPos,nTab );
+ else
+ aCmpRange = ScRange( static_cast<SCCOL>(nCmpPos),0,nTab, static_cast<SCCOL>(nCmpPos),rDoc.MaxRow(),nTab );
+ ScCellIterator aCmpIter(rDoc, aCmpRange);
+ for (bool bHasCell = aCmpIter.first(); bHasCell; bHasCell = aCmpIter.next())
+ {
+ SCCOLROW nCellPos = bColumnDiff ? static_cast<SCCOLROW>(aCmpIter.GetPos().Col()) : static_cast<SCCOLROW>(aCmpIter.GetPos().Row());
+ if (bColumnDiff)
+ aCellRange = ScRange( static_cast<SCCOL>(nCellPos),0,nTab,
+ static_cast<SCCOL>(nCellPos),rDoc.MaxRow(),nTab );
+ else
+ aCellRange = ScRange( 0,nCellPos,nTab, rDoc.MaxCol(),nCellPos,nTab );
+
+ for (i=0; i<nRangeCount; i++)
+ {
+ ScRange aRange( aRanges[ i ] );
+ if ( aRange.Intersects( aCellRange ) )
+ {
+ if (bColumnDiff)
+ {
+ aRange.aStart.SetCol(static_cast<SCCOL>(nCellPos));
+ aRange.aEnd.SetCol(static_cast<SCCOL>(nCellPos));
+ }
+ else
+ {
+ aRange.aStart.SetRow(nCellPos);
+ aRange.aEnd.SetRow(nCellPos);
+ }
+ aMarkData.SetMultiMarkArea( aRange );
+ }
+ }
+ }
+
+ // compare all not empty cells with the comparison column and accordingly
+ // select or cancel
+
+ ScAddress aCmpAddr;
+ for (i=0; i<nRangeCount; i++)
+ {
+ ScRange const & rRange = aRanges[ i ];
+
+ ScCellIterator aIter( rDoc, rRange );
+ for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
+ {
+ if (bColumnDiff)
+ aCmpAddr = ScAddress( aIter.GetPos().Col(), nCmpPos, aIter.GetPos().Tab() );
+ else
+ aCmpAddr = ScAddress( static_cast<SCCOL>(nCmpPos), aIter.GetPos().Row(), aIter.GetPos().Tab() );
+
+ ScRange aOneRange(aIter.GetPos());
+ if (!aIter.equalsWithoutFormat(aCmpAddr))
+ aMarkData.SetMultiMarkArea( aOneRange );
+ else
+ aMarkData.SetMultiMarkArea( aOneRange, false ); // deselect
+ }
+ }
+
+ ScRangeList aNewRanges;
+ if (aMarkData.IsMultiMarked())
+ aMarkData.FillRangeListWithMarks( &aNewRanges, false );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges ); // aNewRanges can be empty
+ }
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges > SAL_CALL ScCellRangesBase::queryColumnDifferences(
+ const table::CellAddress& aCompare )
+{
+ SolarMutexGuard aGuard;
+ return QueryDifferences_Impl( aCompare, true );
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryRowDifferences(
+ const table::CellAddress& aCompare )
+{
+ SolarMutexGuard aGuard;
+ return QueryDifferences_Impl( aCompare, false );
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryIntersection(
+ const table::CellRangeAddress& aRange )
+{
+ SolarMutexGuard aGuard;
+ ScRange aMask( static_cast<SCCOL>(aRange.StartColumn), static_cast<SCROW>(aRange.StartRow), aRange.Sheet,
+ static_cast<SCCOL>(aRange.EndColumn), static_cast<SCROW>(aRange.EndRow), aRange.Sheet );
+
+ ScRangeList aNew;
+ for ( size_t i = 0, nCount = aRanges.size(); i < nCount; ++i )
+ {
+ ScRange aTemp( aRanges[ i ] );
+ if ( aTemp.Intersects( aMask ) )
+ aNew.Join( ScRange( std::max( aTemp.aStart.Col(), aMask.aStart.Col() ),
+ std::max( aTemp.aStart.Row(), aMask.aStart.Row() ),
+ std::max( aTemp.aStart.Tab(), aMask.aStart.Tab() ),
+ std::min( aTemp.aEnd.Col(), aMask.aEnd.Col() ),
+ std::min( aTemp.aEnd.Row(), aMask.aEnd.Row() ),
+ std::min( aTemp.aEnd.Tab(), aMask.aEnd.Tab() ) ) );
+ }
+
+ return new ScCellRangesObj( pDocShell, aNew ); // can be empty
+}
+
+// XFormulaQuery
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryPrecedents(
+ sal_Bool bRecursive )
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScRangeList aNewRanges(aRanges);
+ bool bFound;
+ do
+ {
+ bFound = false;
+
+ // aMarkData uses aNewRanges, not aRanges, so GetMarkData can't be used
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+ aMarkData.MarkFromRangeList( aNewRanges, false );
+
+ for (size_t nR = 0, nCount = aNewRanges.size(); nR<nCount; ++nR)
+ {
+ ScRange const & rRange = aNewRanges[ nR];
+ ScCellIterator aIter(rDoc, rRange);
+ for (bool bHasCell = aIter.first(); bHasCell; bHasCell = aIter.next())
+ {
+ if (aIter.getType() != CELLTYPE_FORMULA)
+ continue;
+
+ ScDetectiveRefIter aRefIter(rDoc, aIter.getFormulaCell());
+ ScRange aRefRange;
+ while ( aRefIter.GetNextRef( aRefRange) )
+ {
+ if ( bRecursive && !bFound && !aMarkData.IsAllMarked( aRefRange ) )
+ bFound = true;
+ aMarkData.SetMultiMarkArea(aRefRange);
+ }
+ }
+ }
+
+ aMarkData.FillRangeListWithMarks( &aNewRanges, true );
+ }
+ while ( bRecursive && bFound );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges );
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellRanges> SAL_CALL ScCellRangesBase::queryDependents(
+ sal_Bool bRecursive )
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScRangeList aNewRanges(aRanges);
+ bool bFound;
+ do
+ {
+ bFound = false;
+
+ // aMarkData uses aNewRanges, not aRanges, so GetMarkData can't be used
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+ aMarkData.MarkFromRangeList( aNewRanges, false );
+
+ SCTAB nTab = lcl_FirstTab(aNewRanges); //! all tables
+
+ ScCellIterator aCellIter( rDoc, ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab) );
+ for (bool bHasCell = aCellIter.first(); bHasCell; bHasCell = aCellIter.next())
+ {
+ if (aCellIter.getType() != CELLTYPE_FORMULA)
+ continue;
+
+ bool bMark = false;
+ ScDetectiveRefIter aIter(rDoc, aCellIter.getFormulaCell());
+ ScRange aRefRange;
+ while ( aIter.GetNextRef( aRefRange) && !bMark )
+ {
+ size_t nRangesCount = aNewRanges.size();
+ for (size_t nR = 0; nR < nRangesCount; ++nR)
+ {
+ ScRange const & rRange = aNewRanges[ nR ];
+ if (rRange.Intersects(aRefRange))
+ {
+ bMark = true; // depending on part of Range
+ break;
+ }
+ }
+ }
+ if (bMark)
+ {
+ ScRange aCellRange(aCellIter.GetPos());
+ if ( bRecursive && !bFound && !aMarkData.IsAllMarked( aCellRange ) )
+ bFound = true;
+ aMarkData.SetMultiMarkArea(aCellRange);
+ }
+ }
+
+ aMarkData.FillRangeListWithMarks( &aNewRanges, true );
+ }
+ while ( bRecursive && bFound );
+
+ return new ScCellRangesObj( pDocShell, aNewRanges );
+ }
+
+ return nullptr;
+}
+
+// XSearchable
+
+uno::Reference<util::XSearchDescriptor> SAL_CALL ScCellRangesBase::createSearchDescriptor()
+{
+ return new ScCellSearchObj;
+}
+
+uno::Reference<container::XIndexAccess> SAL_CALL ScCellRangesBase::findAll(
+ const uno::Reference<util::XSearchDescriptor>& xDesc )
+{
+ SolarMutexGuard aGuard;
+ // should we return Null if nothing is found(?)
+ uno::Reference<container::XIndexAccess> xRet;
+ if ( pDocShell && xDesc.is() )
+ {
+ ScCellSearchObj* pSearch = comphelper::getFromUnoTunnel<ScCellSearchObj>( xDesc );
+ if (pSearch)
+ {
+ SvxSearchItem* pSearchItem = pSearch->GetSearchItem();
+ if (pSearchItem)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pSearchItem->SetCommand( SvxSearchCmd::FIND_ALL );
+ // always only within this object
+ pSearchItem->SetSelection( !lcl_WholeSheet(rDoc, aRanges) );
+
+ ScMarkData aMark(*GetMarkData());
+
+ OUString aDummyUndo;
+ ScRangeList aMatchedRanges;
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+ SCTAB nTab = 0;
+ bool bFound = rDoc.SearchAndReplace(
+ *pSearchItem, nCol, nRow, nTab, aMark, aMatchedRanges, aDummyUndo);
+ if (bFound)
+ {
+ // on findAll always CellRanges no matter how much has been found
+ xRet.set(new ScCellRangesObj( pDocShell, aMatchedRanges ));
+ }
+ }
+ }
+ }
+ return xRet;
+}
+
+uno::Reference<uno::XInterface> ScCellRangesBase::Find_Impl(
+ const uno::Reference<util::XSearchDescriptor>& xDesc,
+ const ScAddress* pLastPos )
+{
+ uno::Reference<uno::XInterface> xRet;
+ if ( pDocShell && xDesc.is() )
+ {
+ ScCellSearchObj* pSearch = comphelper::getFromUnoTunnel<ScCellSearchObj>( xDesc );
+ if (pSearch)
+ {
+ SvxSearchItem* pSearchItem = pSearch->GetSearchItem();
+ if (pSearchItem)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pSearchItem->SetCommand( SvxSearchCmd::FIND );
+ // only always in this object
+ pSearchItem->SetSelection( !lcl_WholeSheet(rDoc, aRanges) );
+
+ ScMarkData aMark(*GetMarkData());
+
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ if (pLastPos)
+ pLastPos->GetVars( nCol, nRow, nTab );
+ else
+ {
+ nTab = lcl_FirstTab(aRanges); //! multiple sheets?
+ rDoc.GetSearchAndReplaceStart( *pSearchItem, nCol, nRow );
+ }
+
+ OUString aDummyUndo;
+ ScRangeList aMatchedRanges;
+ bool bFound = rDoc.SearchAndReplace(
+ *pSearchItem, nCol, nRow, nTab, aMark, aMatchedRanges, aDummyUndo);
+ if (bFound)
+ {
+ ScAddress aFoundPos( nCol, nRow, nTab );
+ xRet.set(static_cast<cppu::OWeakObject*>(new ScCellObj( pDocShell, aFoundPos )));
+ }
+ }
+ }
+ }
+ return xRet;
+}
+
+uno::Reference<uno::XInterface> SAL_CALL ScCellRangesBase::findFirst(
+ const uno::Reference<util::XSearchDescriptor>& xDesc )
+{
+ SolarMutexGuard aGuard;
+ return Find_Impl( xDesc, nullptr );
+}
+
+uno::Reference<uno::XInterface> SAL_CALL ScCellRangesBase::findNext(
+ const uno::Reference<uno::XInterface>& xStartAt,
+ const uno::Reference<util::XSearchDescriptor >& xDesc )
+{
+ SolarMutexGuard aGuard;
+ if ( xStartAt.is() )
+ {
+ ScCellRangesBase* pRangesImp = comphelper::getFromUnoTunnel<ScCellRangesBase>( xStartAt );
+ if ( pRangesImp && pRangesImp->GetDocShell() == pDocShell )
+ {
+ const ScRangeList& rStartRanges = pRangesImp->GetRangeList();
+ if ( rStartRanges.size() == 1 )
+ {
+ ScAddress aStartPos = rStartRanges[ 0 ].aStart;
+ return Find_Impl( xDesc, &aStartPos );
+ }
+ }
+ }
+ return nullptr;
+}
+
+// XReplaceable
+
+uno::Reference<util::XReplaceDescriptor> SAL_CALL ScCellRangesBase::createReplaceDescriptor()
+{
+ return new ScCellSearchObj;
+}
+
+sal_Int32 SAL_CALL ScCellRangesBase::replaceAll( const uno::Reference<util::XSearchDescriptor>& xDesc )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt64 nReplaced = 0;
+ if ( pDocShell && xDesc.is() )
+ {
+ ScCellSearchObj* pSearch = comphelper::getFromUnoTunnel<ScCellSearchObj>( xDesc );
+ if (pSearch)
+ {
+ SvxSearchItem* pSearchItem = pSearch->GetSearchItem();
+ if (pSearchItem)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+ pSearchItem->SetCommand( SvxSearchCmd::REPLACE_ALL );
+ // only always in this object
+ pSearchItem->SetSelection( !lcl_WholeSheet(rDoc, aRanges) );
+
+ ScMarkData aMark(*GetMarkData());
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ bool bProtected = !pDocShell->IsEditable();
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+ if ( rDoc.IsTabProtected(rTab) )
+ bProtected = true;
+ }
+ if (bProtected)
+ {
+ //! Exception, or what?
+ }
+ else
+ {
+ SCTAB nTab = aMark.GetFirstSelected(); // do not use if SearchAndReplace
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+
+ OUString aUndoStr;
+ ScDocumentUniquePtr pUndoDoc;
+ if (bUndo)
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ }
+ for (const auto& rTab : aMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+ if (rTab != nTab && bUndo)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ }
+ std::unique_ptr<ScMarkData> pUndoMark;
+ if (bUndo)
+ pUndoMark.reset(new ScMarkData(aMark));
+
+ bool bFound = false;
+ if (bUndo)
+ {
+ ScRangeList aMatchedRanges;
+ bFound = rDoc.SearchAndReplace(
+ *pSearchItem, nCol, nRow, nTab, aMark, aMatchedRanges, aUndoStr, pUndoDoc.get() );
+ }
+ if (bFound)
+ {
+ nReplaced = pUndoDoc->GetCellCount();
+
+ pDocShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoReplace>( pDocShell, *pUndoMark, nCol, nRow, nTab,
+ aUndoStr, std::move(pUndoDoc), pSearchItem ) );
+
+ pDocShell->PostPaintGridAll();
+ pDocShell->SetDocumentModified();
+ }
+ }
+ }
+ }
+ }
+ return nReplaced;
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION_IMPL(ScCellRangesBase);
+
+ScCellRangesObj::ScCellRangesObj(ScDocShell* pDocSh, const ScRangeList& rR)
+ : ScCellRangesBase(pDocSh, rR)
+{
+}
+
+ScCellRangesObj::~ScCellRangesObj()
+{
+}
+
+void ScCellRangesObj::RefChanged()
+{
+ ScCellRangesBase::RefChanged();
+}
+
+uno::Any SAL_CALL ScCellRangesObj::queryInterface( const uno::Type& rType )
+{
+ SC_QUERYINTERFACE( sheet::XSheetCellRangeContainer )
+ SC_QUERYINTERFACE( sheet::XSheetCellRanges )
+ SC_QUERYINTERFACE( container::XIndexAccess )
+ SC_QUERY_MULTIPLE( container::XElementAccess, container::XIndexAccess )
+ SC_QUERYINTERFACE( container::XEnumerationAccess )
+ SC_QUERYINTERFACE( container::XNameContainer )
+ SC_QUERYINTERFACE( container::XNameReplace )
+ SC_QUERYINTERFACE( container::XNameAccess )
+
+ return ScCellRangesBase::queryInterface( rType );
+}
+
+void SAL_CALL ScCellRangesObj::acquire() noexcept
+{
+ ScCellRangesBase::acquire();
+}
+
+void SAL_CALL ScCellRangesObj::release() noexcept
+{
+ ScCellRangesBase::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScCellRangesObj::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes = comphelper::concatSequences(
+ ScCellRangesBase::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XSheetCellRangeContainer>::get(),
+ cppu::UnoType<container::XNameContainer>::get(),
+ cppu::UnoType<container::XEnumerationAccess>::get()
+ } );
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScCellRangesObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XCellRanges
+
+rtl::Reference<ScCellRangeObj> ScCellRangesObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
+{
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ if ( pDocSh && nIndex >= 0 && nIndex < sal::static_int_cast<sal_Int32>(rRanges.size()) )
+ {
+ ScRange const & rRange = rRanges[ nIndex ];
+ if ( rRange.aStart == rRange.aEnd )
+ return new ScCellObj( pDocSh, rRange.aStart );
+ else
+ return new ScCellRangeObj( pDocSh, rRange );
+ }
+
+ return nullptr; // no DocShell or wrong index
+}
+
+uno::Sequence<table::CellRangeAddress> SAL_CALL ScCellRangesObj::getRangeAddresses()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ size_t nCount = rRanges.size();
+ if ( pDocSh && nCount )
+ {
+ table::CellRangeAddress aRangeAddress;
+ uno::Sequence<table::CellRangeAddress> aSeq(nCount);
+ table::CellRangeAddress* pAry = aSeq.getArray();
+ for ( size_t i=0; i < nCount; i++)
+ {
+ ScUnoConversion::FillApiRange( aRangeAddress, rRanges[ i ] );
+ pAry[i] = aRangeAddress;
+ }
+ return aSeq;
+ }
+
+ return {}; // can be empty
+}
+
+uno::Reference<container::XEnumerationAccess> SAL_CALL ScCellRangesObj::getCells()
+{
+ SolarMutexGuard aGuard;
+
+ // getCells with empty range list is possible (no exception),
+ // the resulting enumeration just has no elements
+ // (same behaviour as a valid range with no cells)
+ // This is handled in ScCellsEnumeration ctor.
+
+ const ScRangeList& rRanges = GetRangeList();
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ return new ScCellsObj( pDocSh, rRanges );
+ return nullptr;
+}
+
+OUString SAL_CALL ScCellRangesObj::getRangeAddressesAsString()
+{
+ SolarMutexGuard aGuard;
+ OUString aString;
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ if (pDocSh)
+ rRanges.Format( aString, ScRefFlags::VALID | ScRefFlags::TAB_3D, pDocSh->GetDocument() );
+ return aString;
+}
+
+// XSheetCellRangeContainer
+
+void SAL_CALL ScCellRangesObj::addRangeAddress( const table::CellRangeAddress& rRange,
+ sal_Bool bMergeRanges )
+{
+ SolarMutexGuard aGuard;
+ ScRange aRange(static_cast<SCCOL>(rRange.StartColumn),
+ static_cast<SCROW>(rRange.StartRow),
+ static_cast<SCTAB>(rRange.Sheet),
+ static_cast<SCCOL>(rRange.EndColumn),
+ static_cast<SCROW>(rRange.EndRow),
+ static_cast<SCTAB>(rRange.Sheet));
+ AddRange(aRange, bMergeRanges);
+}
+
+static void lcl_RemoveNamedEntry( std::vector<ScCellRangesObj::ScNamedEntry>& rNamedEntries, const ScRange& rRange )
+{
+ sal_uInt16 nCount = rNamedEntries.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ if ( rNamedEntries[n].GetRange() == rRange )
+ rNamedEntries.erase( rNamedEntries.begin() + n );
+}
+
+void SAL_CALL ScCellRangesObj::removeRangeAddress( const table::CellRangeAddress& rRange )
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+
+ ScRangeList aSheetRanges;
+ ScRangeList aNotSheetRanges;
+ for (size_t i = 0; i < rRanges.size(); ++i)
+ {
+ if (rRanges[ i].aStart.Tab() == rRange.Sheet)
+ {
+ aSheetRanges.push_back( rRanges[ i ] );
+ }
+ else
+ {
+ aNotSheetRanges.push_back( rRanges[ i ] );
+ }
+ }
+ ScMarkData aMarkData(GetDocument()->GetSheetLimits());
+ aMarkData.MarkFromRangeList( aSheetRanges, false );
+ ScRange aRange(static_cast<SCCOL>(rRange.StartColumn),
+ static_cast<SCROW>(rRange.StartRow),
+ static_cast<SCTAB>(rRange.Sheet),
+ static_cast<SCCOL>(rRange.EndColumn),
+ static_cast<SCROW>(rRange.EndRow),
+ static_cast<SCTAB>(rRange.Sheet));
+ if (aMarkData.GetTableSelect( aRange.aStart.Tab() ))
+ {
+ aMarkData.MarkToMulti();
+ if (!aMarkData.IsAllMarked( aRange ) )
+ throw container::NoSuchElementException();
+
+ aMarkData.SetMultiMarkArea( aRange, false );
+ lcl_RemoveNamedEntry(m_aNamedEntries, aRange);
+
+ }
+ SetNewRanges(aNotSheetRanges);
+ ScRangeList aNew;
+ aMarkData.FillRangeListWithMarks( &aNew, false );
+ for ( size_t j = 0; j < aNew.size(); ++j)
+ {
+ AddRange(aNew[ j ], false);
+ }
+}
+
+void SAL_CALL ScCellRangesObj::addRangeAddresses( const uno::Sequence<table::CellRangeAddress >& rRanges,
+ sal_Bool bMergeRanges )
+{
+ SolarMutexGuard aGuard;
+ for (const table::CellRangeAddress& rRange : rRanges)
+ {
+ ScRange aRange(static_cast<SCCOL>(rRange.StartColumn),
+ static_cast<SCROW>(rRange.StartRow),
+ static_cast<SCTAB>(rRange.Sheet),
+ static_cast<SCCOL>(rRange.EndColumn),
+ static_cast<SCROW>(rRange.EndRow),
+ static_cast<SCTAB>(rRange.Sheet));
+ AddRange(aRange, bMergeRanges);
+ }
+}
+
+void SAL_CALL ScCellRangesObj::removeRangeAddresses( const uno::Sequence<table::CellRangeAddress >& rRangeSeq )
+{
+ // use sometimes a better/faster implementation
+ for (const table::CellRangeAddress& rRange : rRangeSeq)
+ {
+ removeRangeAddress(rRange);
+ }
+}
+
+// XNameContainer
+
+static void lcl_RemoveNamedEntry( std::vector<ScCellRangesObj::ScNamedEntry>& rNamedEntries, std::u16string_view rName )
+{
+ sal_uInt16 nCount = rNamedEntries.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ if ( rNamedEntries[n].GetName() == rName )
+ rNamedEntries.erase( rNamedEntries.begin() + n );
+}
+
+void SAL_CALL ScCellRangesObj::insertByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ bool bDone = false;
+
+ //! Type of aElement can be some specific interface instead of XInterface
+
+ uno::Reference<uno::XInterface> xInterface(aElement, uno::UNO_QUERY);
+ if ( pDocSh && xInterface.is() )
+ {
+ ScCellRangesBase* pRangesImp = comphelper::getFromUnoTunnel<ScCellRangesBase>( xInterface );
+ if ( pRangesImp && pRangesImp->GetDocShell() == pDocSh )
+ {
+ // if explicit name is given and already existing, throw exception
+
+ if ( !aName.isEmpty() )
+ {
+ size_t nNamedCount = m_aNamedEntries.size();
+ for (size_t n = 0; n < nNamedCount; n++)
+ {
+ if (m_aNamedEntries[n].GetName() == aName)
+ throw container::ElementExistException();
+ }
+ }
+
+ ScRangeList aNew(GetRangeList());
+ const ScRangeList& rAddRanges = pRangesImp->GetRangeList();
+ size_t nAddCount = rAddRanges.size();
+ for ( size_t i = 0; i < nAddCount; i++ )
+ aNew.Join( rAddRanges[ i ] );
+ SetNewRanges(aNew);
+ bDone = true;
+
+ if ( !aName.isEmpty() && nAddCount == 1 )
+ {
+ // if a name is given, also insert into list of named entries
+ // (only possible for a single range)
+ // name is not in m_aNamedEntries (tested above)
+ m_aNamedEntries.emplace_back( ScNamedEntry{aName, rAddRanges[ 0 ]} );
+ }
+ }
+ }
+
+ if (!bDone)
+ {
+ // invalid element - double names are handled above
+ throw lang::IllegalArgumentException();
+ }
+}
+
+static bool lcl_FindRangeByName( const ScRangeList& rRanges, ScDocShell* pDocSh,
+ std::u16string_view rName, size_t& rIndex )
+{
+ if (pDocSh)
+ {
+ OUString aRangeStr;
+ ScDocument& rDoc = pDocSh->GetDocument();
+ for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
+ {
+ aRangeStr = rRanges[ i ].Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_3D);
+ if ( aRangeStr == rName )
+ {
+ rIndex = i;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static bool lcl_FindRangeOrEntry( const std::vector<ScCellRangesObj::ScNamedEntry>& rNamedEntries,
+ const ScRangeList& rRanges, ScDocShell* pDocSh,
+ const OUString& rName, ScRange& rFound )
+{
+ // exact range in list?
+
+ size_t nIndex = 0;
+ if ( lcl_FindRangeByName( rRanges, pDocSh, rName, nIndex ) )
+ {
+ rFound = rRanges[ nIndex ];
+ return true;
+ }
+
+ // range contained in selection? (sheet must be specified)
+
+ ScRange aCellRange;
+ ScRefFlags nParse = aCellRange.ParseAny( rName, pDocSh->GetDocument() );
+ if ( (nParse & ( ScRefFlags::VALID | ScRefFlags::TAB_3D ))
+ == ( ScRefFlags::VALID | ScRefFlags::TAB_3D ))
+ {
+ ScMarkData aMarkData(pDocSh->GetDocument().GetSheetLimits());
+ aMarkData.MarkFromRangeList( rRanges, false );
+ if ( aMarkData.IsAllMarked( aCellRange ) )
+ {
+ rFound = aCellRange;
+ return true;
+ }
+ }
+
+ // named entry in this object?
+
+ for (const auto & rNamedEntry : rNamedEntries)
+ if ( rNamedEntry.GetName() == rName )
+ {
+ // test if named entry is contained in rRanges
+
+ const ScRange& rComp = rNamedEntry.GetRange();
+ ScMarkData aMarkData(pDocSh->GetDocument().GetSheetLimits());
+ aMarkData.MarkFromRangeList( rRanges, false );
+ if ( aMarkData.IsAllMarked( rComp ) )
+ {
+ rFound = rComp;
+ return true;
+ }
+ }
+
+ return false; // not found
+}
+
+void SAL_CALL ScCellRangesObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ size_t nIndex = 0;
+ if ( lcl_FindRangeByName( rRanges, pDocSh, aName, nIndex ) )
+ {
+ // skip a single range
+ ScRangeList aNew;
+ for ( size_t i = 0, nCount = rRanges.size(); i < nCount; i++ )
+ if (i != nIndex)
+ aNew.push_back( rRanges[ i ] );
+ SetNewRanges(aNew);
+ bDone = true;
+ }
+ else if (pDocSh)
+ {
+ // deselect any ranges (parsed or named entry)
+ ScRangeList aDiff;
+ bool bValid = ( aDiff.Parse( aName, pDocSh->GetDocument() ) & ScRefFlags::VALID )
+ == ScRefFlags::VALID;
+ if (!bValid)
+ {
+ sal_uInt16 nCount = m_aNamedEntries.size();
+ for (sal_uInt16 n=0; n<nCount && !bValid; n++)
+ if (m_aNamedEntries[n].GetName() == aName)
+ {
+ aDiff.RemoveAll();
+ aDiff.push_back(m_aNamedEntries[n].GetRange());
+ bValid = true;
+ }
+ }
+ if ( bValid )
+ {
+ ScMarkData aMarkData(GetDocument()->GetSheetLimits());
+ aMarkData.MarkFromRangeList( rRanges, false );
+
+ for ( size_t i = 0, nDiffCount = aDiff.size(); i < nDiffCount; i++ )
+ {
+ ScRange const & rDiffRange = aDiff[ i ];
+ if (aMarkData.GetTableSelect( rDiffRange.aStart.Tab() ))
+ aMarkData.SetMultiMarkArea( rDiffRange, false );
+ }
+
+ ScRangeList aNew;
+ aMarkData.FillRangeListWithMarks( &aNew, false );
+ SetNewRanges(aNew);
+
+ bDone = true; //! error if range was not selected before?
+ }
+ }
+
+ if (!m_aNamedEntries.empty())
+ lcl_RemoveNamedEntry(m_aNamedEntries, aName);
+
+ if (!bDone)
+ throw container::NoSuchElementException(); // not found
+}
+
+// XNameReplace
+
+void SAL_CALL ScCellRangesObj::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ //! combine?
+ removeByName( aName );
+ insertByName( aName, aElement );
+}
+
+// XNameAccess
+
+uno::Any SAL_CALL ScCellRangesObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ ScRange aRange;
+ if (!lcl_FindRangeOrEntry(m_aNamedEntries, rRanges,
+ pDocSh, aName, aRange))
+ throw container::NoSuchElementException();
+
+ uno::Reference<table::XCellRange> xRange;
+ if ( aRange.aStart == aRange.aEnd )
+ xRange.set(new ScCellObj( pDocSh, aRange.aStart ));
+ else
+ xRange.set(new ScCellRangeObj( pDocSh, aRange ));
+ aRet <<= xRange;
+
+ return aRet;
+}
+
+static bool lcl_FindEntryName( const std::vector<ScCellRangesObj::ScNamedEntry>& rNamedEntries,
+ const ScRange& rRange, OUString& rName )
+{
+ sal_uInt16 nCount = rNamedEntries.size();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if (rNamedEntries[i].GetRange() == rRange)
+ {
+ rName = rNamedEntries[i].GetName();
+ return true;
+ }
+ return false;
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellRangesObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ if (pDocSh)
+ {
+ OUString aRangeStr;
+ ScDocument& rDoc = pDocSh->GetDocument();
+ size_t nCount = rRanges.size();
+
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ for (size_t i=0; i < nCount; i++)
+ {
+ // use given name if for exactly this range, otherwise just format
+ ScRange const & rRange = rRanges[ i ];
+ if (m_aNamedEntries.empty() ||
+ !lcl_FindEntryName(m_aNamedEntries, rRange, aRangeStr))
+ {
+ aRangeStr = rRange.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_3D);
+ }
+ pAry[i] = aRangeStr;
+ }
+ return aSeq;
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScCellRangesObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ const ScRangeList& rRanges = GetRangeList();
+ ScRange aRange;
+ return lcl_FindRangeOrEntry(m_aNamedEntries, rRanges, pDocSh,
+ aName, aRange);
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScCellRangesObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.SheetCellRangesEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScCellRangesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ return rRanges.size();
+}
+
+uno::Any SAL_CALL ScCellRangesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XCellRange> xRange(GetObjectByIndex_Impl(nIndex));
+ if (!xRange.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRange);
+
+}
+
+uno::Type SAL_CALL ScCellRangesObj::getElementType()
+{
+ return cppu::UnoType<table::XCellRange>::get();
+}
+
+sal_Bool SAL_CALL ScCellRangesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ return !rRanges.empty();
+}
+
+// XServiceInfo
+OUString SAL_CALL ScCellRangesObj::getImplementationName()
+{
+ return "ScCellRangesObj";
+}
+
+sal_Bool SAL_CALL ScCellRangesObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellRangesObj::getSupportedServiceNames()
+{
+ return {SCSHEETCELLRANGES_SERVICE,
+ SCCELLPROPERTIES_SERVICE,
+ SCCHARPROPERTIES_SERVICE,
+ SCPARAPROPERTIES_SERVICE};
+}
+
+uno::Reference<table::XCellRange> ScCellRangeObj::CreateRangeFromDoc( const ScDocument& rDoc, const ScRange& rR )
+{
+ SfxObjectShell* pObjSh = rDoc.GetDocumentShell();
+ if ( auto pDocShell = dynamic_cast<ScDocShell*>( pObjSh) )
+ return new ScCellRangeObj( pDocShell, rR );
+ return nullptr;
+}
+
+ScCellRangeObj::ScCellRangeObj(ScDocShell* pDocSh, const ScRange& rR) :
+ ScCellRangesBase( pDocSh, rR ),
+ pRangePropSet( lcl_GetRangePropertySet() ),
+ aRange( rR )
+{
+ aRange.PutInOrder(); // beginning / end correct
+}
+
+ScCellRangeObj::~ScCellRangeObj()
+{
+}
+
+void ScCellRangeObj::RefChanged()
+{
+ ScCellRangesBase::RefChanged();
+
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE(rRanges.size() == 1, "What ranges ?!?!");
+ if ( !rRanges.empty() )
+ {
+ const ScRange & rFirst = rRanges[0];
+ aRange = rFirst;
+ aRange.PutInOrder();
+ }
+}
+
+uno::Any SAL_CALL ScCellRangeObj::queryInterface( const uno::Type& rType )
+{
+ SC_QUERYINTERFACE( sheet::XCellRangeAddressable )
+ SC_QUERYINTERFACE( table::XCellRange )
+ SC_QUERYINTERFACE( sheet::XSheetCellRange )
+ SC_QUERYINTERFACE( sheet::XArrayFormulaRange )
+ SC_QUERYINTERFACE( sheet::XArrayFormulaTokens )
+ SC_QUERYINTERFACE( sheet::XCellRangeData )
+ SC_QUERYINTERFACE( sheet::XCellRangeFormula )
+ SC_QUERYINTERFACE( sheet::XMultipleOperation )
+ SC_QUERYINTERFACE( util::XMergeable )
+ SC_QUERYINTERFACE( sheet::XCellSeries )
+ SC_QUERYINTERFACE( table::XAutoFormattable )
+ SC_QUERYINTERFACE( util::XSortable )
+ SC_QUERYINTERFACE( sheet::XSheetFilterableEx )
+ SC_QUERYINTERFACE( sheet::XSheetFilterable )
+ SC_QUERYINTERFACE( sheet::XSubTotalCalculatable )
+ SC_QUERYINTERFACE( table::XColumnRowRange )
+ SC_QUERYINTERFACE( util::XImportable )
+ SC_QUERYINTERFACE( sheet::XCellFormatRangesSupplier )
+ SC_QUERYINTERFACE( sheet::XUniqueCellFormatRangesSupplier )
+
+ return ScCellRangesBase::queryInterface( rType );
+}
+
+void SAL_CALL ScCellRangeObj::acquire() noexcept
+{
+ ScCellRangesBase::acquire();
+}
+
+void SAL_CALL ScCellRangeObj::release() noexcept
+{
+ ScCellRangesBase::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScCellRangeObj::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes = comphelper::concatSequences(
+ ScCellRangesBase::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XCellRangeAddressable>::get(),
+ cppu::UnoType<sheet::XSheetCellRange>::get(),
+ cppu::UnoType<sheet::XArrayFormulaRange>::get(),
+ cppu::UnoType<sheet::XArrayFormulaTokens>::get(),
+ cppu::UnoType<sheet::XCellRangeData>::get(),
+ cppu::UnoType<sheet::XCellRangeFormula>::get(),
+ cppu::UnoType<sheet::XMultipleOperation>::get(),
+ cppu::UnoType<util::XMergeable>::get(),
+ cppu::UnoType<sheet::XCellSeries>::get(),
+ cppu::UnoType<table::XAutoFormattable>::get(),
+ cppu::UnoType<util::XSortable>::get(),
+ cppu::UnoType<sheet::XSheetFilterableEx>::get(),
+ cppu::UnoType<sheet::XSubTotalCalculatable>::get(),
+ cppu::UnoType<table::XColumnRowRange>::get(),
+ cppu::UnoType<util::XImportable>::get(),
+ cppu::UnoType<sheet::XCellFormatRangesSupplier>::get(),
+ cppu::UnoType<sheet::XUniqueCellFormatRangesSupplier>::get()
+ } );
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScCellRangeObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XCellRange
+
+// ColumnCount / RowCount vanished
+//! are used in Writer for tables ???
+
+uno::Reference<table::XCell> ScCellRangeObj::GetCellByPosition_Impl(
+ sal_Int32 nColumn, sal_Int32 nRow )
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ throw uno::RuntimeException();
+
+ if ( nColumn >= 0 && nRow >= 0 )
+ {
+ sal_Int32 nPosX = aRange.aStart.Col() + nColumn;
+ sal_Int32 nPosY = aRange.aStart.Row() + nRow;
+
+ if ( nPosX <= aRange.aEnd.Col() && nPosY <= aRange.aEnd.Row() )
+ {
+ ScAddress aNew( static_cast<SCCOL>(nPosX), static_cast<SCROW>(nPosY), aRange.aStart.Tab() );
+ return new ScCellObj( pDocSh, aNew );
+ }
+ }
+
+ throw lang::IndexOutOfBoundsException();
+}
+
+uno::Reference<table::XCell> SAL_CALL ScCellRangeObj::getCellByPosition(
+ sal_Int32 nColumn, sal_Int32 nRow )
+{
+ SolarMutexGuard aGuard;
+
+ return GetCellByPosition_Impl(nColumn, nRow);
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScCellRangeObj::getCellRangeByPosition(
+ sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+{
+ SolarMutexGuard aGuard;
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ throw uno::RuntimeException();
+
+ if ( nLeft >= 0 && nTop >= 0 && nRight >= 0 && nBottom >= 0 )
+ {
+ sal_Int32 nStartX = aRange.aStart.Col() + nLeft;
+ sal_Int32 nStartY = aRange.aStart.Row() + nTop;
+ sal_Int32 nEndX = aRange.aStart.Col() + nRight;
+ sal_Int32 nEndY = aRange.aStart.Row() + nBottom;
+
+ if ( nStartX <= nEndX && nEndX <= aRange.aEnd.Col() &&
+ nStartY <= nEndY && nEndY <= aRange.aEnd.Row() )
+ {
+ ScRange aNew( static_cast<SCCOL>(nStartX), static_cast<SCROW>(nStartY), aRange.aStart.Tab(),
+ static_cast<SCCOL>(nEndX), static_cast<SCROW>(nEndY), aRange.aEnd.Tab() );
+ return new ScCellRangeObj( pDocSh, aNew );
+ }
+ }
+
+ throw lang::IndexOutOfBoundsException();
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScCellRangeObj::getCellRangeByName(
+ const OUString& aName )
+{
+ return getCellRangeByName( aName, ScAddress::detailsOOOa1 );
+}
+
+uno::Reference<table::XCellRange> ScCellRangeObj::getCellRangeByName(
+ const OUString& aName, const ScAddress::Details& rDetails )
+{
+ // name refers to the whole document (with the range's table as default),
+ // valid only if the range is within this range
+
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = aRange.aStart.Tab();
+
+ ScRange aCellRange;
+ bool bFound = false;
+ ScRefFlags nParse = aCellRange.ParseAny( aName, rDoc, rDetails );
+ if ( nParse & ScRefFlags::VALID )
+ {
+ if ( !(nParse & ScRefFlags::TAB_3D) ) // no sheet specified -> this sheet
+ {
+ aCellRange.aStart.SetTab(nTab);
+ aCellRange.aEnd.SetTab(nTab);
+ }
+ bFound = true;
+ }
+ else
+ {
+ if ( ScRangeUtil::MakeRangeFromName( aName, rDoc, nTab, aCellRange, RUTL_NAMES, rDetails) ||
+ ScRangeUtil::MakeRangeFromName( aName, rDoc, nTab, aCellRange, RUTL_DBASE, rDetails))
+ bFound = true;
+ }
+
+ if (bFound) // valid only if within this object's range
+ {
+ if (!aRange.Contains(aCellRange))
+ bFound = false;
+ }
+
+ if (bFound)
+ {
+ if ( aCellRange.aStart == aCellRange.aEnd )
+ return new ScCellObj( pDocSh, aCellRange.aStart );
+ else
+ return new ScCellRangeObj( pDocSh, aCellRange );
+ }
+ }
+
+ throw uno::RuntimeException();
+}
+
+// XColumnRowRange
+
+uno::Reference<table::XTableColumns> SAL_CALL ScCellRangeObj::getColumns()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ return new ScTableColumnsObj( pDocSh, aRange.aStart.Tab(),
+ aRange.aStart.Col(), aRange.aEnd.Col() );
+
+ OSL_FAIL("Document invalid");
+ return nullptr;
+}
+
+uno::Reference<table::XTableRows> SAL_CALL ScCellRangeObj::getRows()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ return new ScTableRowsObj( pDocSh, aRange.aStart.Tab(),
+ aRange.aStart.Row(), aRange.aEnd.Row() );
+
+ OSL_FAIL("Document invalid");
+ return nullptr;
+}
+
+// XAddressableCellRange
+
+table::CellRangeAddress SAL_CALL ScCellRangeObj::getRangeAddress()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScUnoConversion::FillApiRange( aRet, aRange );
+ return aRet;
+}
+
+// XSheetCellRange
+
+uno::Reference<sheet::XSpreadsheet> SAL_CALL ScCellRangeObj::getSpreadsheet()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ return new ScTableSheetObj( pDocSh, aRange.aStart.Tab() );
+
+ OSL_FAIL("Document invalid");
+ return nullptr;
+}
+
+// XArrayFormulaRange
+
+OUString SAL_CALL ScCellRangeObj::getArrayFormula()
+{
+ SolarMutexGuard aGuard;
+
+ // Matrix formula if clearly part of a matrix (so when start and end of
+ // the block belong to the same matrix) else empty string.
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return OUString();
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScRefCellValue aCell1(rDoc, aRange.aStart);
+ ScRefCellValue aCell2(rDoc, aRange.aEnd);
+ if (aCell1.meType == CELLTYPE_FORMULA && aCell2.meType == CELLTYPE_FORMULA)
+ {
+ const ScFormulaCell* pFCell1 = aCell1.mpFormula;
+ const ScFormulaCell* pFCell2 = aCell2.mpFormula;
+ ScAddress aStart1;
+ ScAddress aStart2;
+ if (pFCell1->GetMatrixOrigin(rDoc, aStart1) && pFCell2->GetMatrixOrigin(rDoc, aStart2))
+ {
+ if (aStart1 == aStart2) // both the same matrix
+ return pFCell1->GetFormula(); // it doesn't matter from which cell
+ }
+ }
+ return OUString();
+}
+
+void ScCellRangeObj::SetArrayFormula_Impl(const OUString& rFormula,
+ const formula::FormulaGrammar::Grammar eGrammar)
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ if ( !rFormula.isEmpty() )
+ {
+ if ( comphelper::getFromUnoTunnel<ScTableSheetObj>( static_cast<cppu::OWeakObject*>(this) ) )
+ {
+ // don't set array formula for sheet object
+ throw uno::RuntimeException();
+ }
+
+ pDocSh->GetDocFunc().EnterMatrix( aRange, nullptr, nullptr, rFormula, true, true, OUString()/*rFormulaNmsp*/, eGrammar );
+ }
+ else
+ {
+ // empty string -> erase array formula
+ ScMarkData aMark(GetDocument()->GetSheetLimits());
+ aMark.SetMarkArea( aRange );
+ aMark.SelectTable( aRange.aStart.Tab(), true );
+ pDocSh->GetDocFunc().DeleteContents( aMark, InsertDeleteFlags::CONTENTS, true, true );
+ }
+}
+
+void SAL_CALL ScCellRangeObj::setArrayFormula( const OUString& aFormula )
+{
+ SolarMutexGuard aGuard;
+ // GRAM_API for API compatibility.
+ SetArrayFormula_Impl( aFormula, formula::FormulaGrammar::GRAM_API);
+}
+
+// XArrayFormulaTokens
+uno::Sequence<sheet::FormulaToken> SAL_CALL ScCellRangeObj::getArrayTokens()
+{
+ SolarMutexGuard aGuard;
+
+ // same cell logic as in getArrayFormula
+
+ uno::Sequence<sheet::FormulaToken> aSequence;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return aSequence;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScRefCellValue aCell1(rDoc, aRange.aStart);
+ ScRefCellValue aCell2(rDoc, aRange.aEnd);
+ if (aCell1.meType == CELLTYPE_FORMULA && aCell2.meType == CELLTYPE_FORMULA)
+ {
+ const ScFormulaCell* pFCell1 = aCell1.mpFormula;
+ const ScFormulaCell* pFCell2 = aCell2.mpFormula;
+ ScAddress aStart1;
+ ScAddress aStart2;
+ if (pFCell1->GetMatrixOrigin(rDoc, aStart1) && pFCell2->GetMatrixOrigin(rDoc, aStart2))
+ {
+ if (aStart1 == aStart2)
+ {
+ const ScTokenArray* pTokenArray = pFCell1->GetCode();
+ if (pTokenArray)
+ ScTokenConversion::ConvertToTokenSequence(rDoc, aSequence, *pTokenArray);
+ }
+ }
+ }
+
+ return aSequence;
+}
+
+void SAL_CALL ScCellRangeObj::setArrayTokens( const uno::Sequence<sheet::FormulaToken>& rTokens )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ if ( rTokens.hasElements() )
+ {
+ if ( comphelper::getFromUnoTunnel<ScTableSheetObj>( static_cast<cppu::OWeakObject*>(this) ) )
+ {
+ throw uno::RuntimeException();
+ }
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScTokenArray aTokenArray(rDoc);
+ (void)ScTokenConversion::ConvertToTokenArray( rDoc, aTokenArray, rTokens );
+
+ // Actually GRAM_API is a don't-care here because of the token
+ // array being set, it fits with other API compatibility grammars
+ // though.
+ pDocSh->GetDocFunc().EnterMatrix( aRange, nullptr, &aTokenArray, OUString(), true, true, OUString(), formula::FormulaGrammar::GRAM_API );
+ }
+ else
+ {
+ // empty sequence -> erase array formula
+ ScMarkData aMark(pDocSh->GetDocument().GetSheetLimits());
+ aMark.SetMarkArea( aRange );
+ aMark.SelectTable( aRange.aStart.Tab(), true );
+ pDocSh->GetDocFunc().DeleteContents( aMark, InsertDeleteFlags::CONTENTS, true, true );
+ }
+}
+
+// XCellRangeData
+
+uno::Sequence< uno::Sequence<uno::Any> > SAL_CALL ScCellRangeObj::getDataArray()
+{
+ SolarMutexGuard aGuard;
+
+ if ( comphelper::getFromUnoTunnel<ScTableSheetObj>( static_cast<cppu::OWeakObject*>(this) ) )
+ {
+ // don't create a data array for the sheet
+ throw uno::RuntimeException();
+ }
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ uno::Any aAny;
+ // bAllowNV = TRUE: errors as void
+ if ( ScRangeToSequence::FillMixedArray( aAny, pDocSh->GetDocument(), aRange, true ) )
+ {
+ uno::Sequence< uno::Sequence<uno::Any> > aSeq;
+ if ( aAny >>= aSeq )
+ return aSeq; // success
+ }
+ }
+
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScCellRangeObj::setDataArray(
+ const uno::Sequence< uno::Sequence<uno::Any> >& aArray )
+{
+ SolarMutexGuard aGuard;
+
+ bool bDone = false;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ //! move lcl_PutDataArray to docfunc?
+ bDone = lcl_PutDataArray( *pDocSh, aRange, aArray );
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// XCellRangeFormula
+
+uno::Sequence< uno::Sequence<OUString> > SAL_CALL ScCellRangeObj::getFormulaArray()
+{
+ SolarMutexGuard aGuard;
+
+ if ( comphelper::getFromUnoTunnel<ScTableSheetObj>( static_cast<cppu::OWeakObject*>(this) ) )
+ {
+ // don't create a data array for the sheet
+ throw uno::RuntimeException();
+ }
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ SCCOL nStartCol = aRange.aStart.Col();
+ SCROW nStartRow = aRange.aStart.Row();
+ SCCOL nEndCol = aRange.aEnd.Col();
+ SCROW nEndRow = aRange.aEnd.Row();
+ SCCOL nColCount = nEndCol + 1 - nStartCol;
+ SCROW nRowCount = nEndRow + 1 - nStartRow;
+ SCTAB nTab = aRange.aStart.Tab();
+
+ uno::Sequence< uno::Sequence<OUString> > aRowSeq( nRowCount );
+ uno::Sequence<OUString>* pRowAry = aRowSeq.getArray();
+ for (SCROW nRowIndex = 0; nRowIndex < nRowCount; nRowIndex++)
+ {
+ uno::Sequence<OUString> aColSeq( nColCount );
+ OUString* pColAry = aColSeq.getArray();
+ for (SCCOL nColIndex = 0; nColIndex < nColCount; nColIndex++)
+ pColAry[nColIndex] = lcl_GetInputString( pDocSh->GetDocument(),
+ ScAddress( nStartCol+nColIndex, nStartRow+nRowIndex, nTab ), true );
+
+ pRowAry[nRowIndex] = aColSeq;
+ }
+
+ return aRowSeq;
+ }
+
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScCellRangeObj::setFormulaArray(
+ const uno::Sequence< uno::Sequence<OUString> >& aArray )
+{
+ SolarMutexGuard aGuard;
+
+ bool bDone = false;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ ScExternalRefManager::ApiGuard aExtRefGuard(pDocSh->GetDocument());
+
+ // GRAM_API for API compatibility.
+ bDone = lcl_PutFormulaArray( *pDocSh, aRange, aArray, formula::FormulaGrammar::GRAM_API );
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// XMultipleOperation
+
+void SAL_CALL ScCellRangeObj::setTableOperation( const table::CellRangeAddress& aFormulaRange,
+ sheet::TableOperationMode nMode,
+ const table::CellAddress& aColumnCell,
+ const table::CellAddress& aRowCell )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ bool bError = false;
+ ScTabOpParam aParam;
+ aParam.aRefFormulaCell = ScRefAddress( static_cast<SCCOL>(aFormulaRange.StartColumn),
+ static_cast<SCROW>(aFormulaRange.StartRow), aFormulaRange.Sheet );
+ aParam.aRefFormulaEnd = ScRefAddress( static_cast<SCCOL>(aFormulaRange.EndColumn),
+ static_cast<SCROW>(aFormulaRange.EndRow), aFormulaRange.Sheet );
+ aParam.aRefRowCell = ScRefAddress( static_cast<SCCOL>(aRowCell.Column),
+ static_cast<SCROW>(aRowCell.Row), aRowCell.Sheet );
+ aParam.aRefColCell = ScRefAddress( static_cast<SCCOL>(aColumnCell.Column),
+ static_cast<SCROW>(aColumnCell.Row), aColumnCell.Sheet );
+
+ switch (nMode)
+ {
+ case sheet::TableOperationMode_COLUMN:
+ aParam.meMode = ScTabOpParam::Column;
+ break;
+ case sheet::TableOperationMode_ROW:
+ aParam.meMode = ScTabOpParam::Row;
+ break;
+ case sheet::TableOperationMode_BOTH:
+ aParam.meMode = ScTabOpParam::Both;
+ break;
+ default:
+ bError = true;
+ }
+
+ if (!bError)
+ pDocSh->GetDocFunc().TabOp( aRange, nullptr, aParam, true, true );
+}
+
+// XMergeable
+
+void SAL_CALL ScCellRangeObj::merge( sal_Bool bMerge )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScCellMergeOption aMergeOption(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), false);
+ aMergeOption.maTabs.insert(aRange.aStart.Tab());
+ if ( bMerge )
+ pDocSh->GetDocFunc().MergeCells( aMergeOption, false, true, true );
+ else
+ pDocSh->GetDocFunc().UnmergeCells( aMergeOption, true, nullptr );
+
+ //! Catch error?
+}
+
+sal_Bool SAL_CALL ScCellRangeObj::getIsMerged()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ return pDocSh && pDocSh->GetDocument().HasAttrib( aRange, HasAttrFlags::Merged );
+}
+
+// XCellSeries
+
+void SAL_CALL ScCellRangeObj::fillSeries( sheet::FillDirection nFillDirection,
+ sheet::FillMode nFillMode, sheet::FillDateMode nFillDateMode,
+ double fStep, double fEndValue )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ bool bError = false;
+
+ FillDir eDir = FILL_TO_BOTTOM;
+ switch (nFillDirection)
+ {
+ case sheet::FillDirection_TO_BOTTOM:
+ eDir = FILL_TO_BOTTOM;
+ break;
+ case sheet::FillDirection_TO_RIGHT:
+ eDir = FILL_TO_RIGHT;
+ break;
+ case sheet::FillDirection_TO_TOP:
+ eDir = FILL_TO_TOP;
+ break;
+ case sheet::FillDirection_TO_LEFT:
+ eDir = FILL_TO_LEFT;
+ break;
+ default:
+ bError = true;
+ }
+
+ FillCmd eCmd = FILL_SIMPLE;
+ switch ( nFillMode )
+ {
+ case sheet::FillMode_SIMPLE:
+ eCmd = FILL_SIMPLE;
+ break;
+ case sheet::FillMode_LINEAR:
+ eCmd = FILL_LINEAR;
+ break;
+ case sheet::FillMode_GROWTH:
+ eCmd = FILL_GROWTH;
+ break;
+ case sheet::FillMode_DATE:
+ eCmd = FILL_DATE;
+ break;
+ case sheet::FillMode_AUTO:
+ eCmd = FILL_AUTO;
+ break;
+ default:
+ bError = true;
+ }
+
+ FillDateCmd eDateCmd = FILL_DAY;
+ switch ( nFillDateMode )
+ {
+ case sheet::FillDateMode_FILL_DATE_DAY:
+ eDateCmd = FILL_DAY;
+ break;
+ case sheet::FillDateMode_FILL_DATE_WEEKDAY:
+ eDateCmd = FILL_WEEKDAY;
+ break;
+ case sheet::FillDateMode_FILL_DATE_MONTH:
+ eDateCmd = FILL_MONTH;
+ break;
+ case sheet::FillDateMode_FILL_DATE_YEAR:
+ eDateCmd = FILL_YEAR;
+ break;
+ default:
+ bError = true;
+ }
+
+ if (!bError)
+ pDocSh->GetDocFunc().FillSeries( aRange, nullptr, eDir, eCmd, eDateCmd,
+ MAXDOUBLE, fStep, fEndValue, true );
+}
+
+void SAL_CALL ScCellRangeObj::fillAuto( sheet::FillDirection nFillDirection,
+ sal_Int32 nSourceCount )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !(pDocSh && nSourceCount) )
+ return;
+
+ ScRange aSourceRange(aRange);
+ SCCOLROW nCount = 0; // "Dest-Count"
+ FillDir eDir = FILL_TO_BOTTOM;
+ bool bError = false;
+ switch (nFillDirection)
+ {
+ case sheet::FillDirection_TO_BOTTOM:
+ aSourceRange.aEnd.SetRow( static_cast<SCROW>( aSourceRange.aStart.Row() + nSourceCount - 1 ) );
+ nCount = aRange.aEnd.Row() - aSourceRange.aEnd.Row();
+ eDir = FILL_TO_BOTTOM;
+ break;
+ case sheet::FillDirection_TO_RIGHT:
+ aSourceRange.aEnd.SetCol( static_cast<SCCOL>( aSourceRange.aStart.Col() + nSourceCount - 1 ) );
+ nCount = aRange.aEnd.Col() - aSourceRange.aEnd.Col();
+ eDir = FILL_TO_RIGHT;
+ break;
+ case sheet::FillDirection_TO_TOP:
+ aSourceRange.aStart.SetRow( static_cast<SCROW>( aSourceRange.aEnd.Row() - nSourceCount + 1 ) );
+ nCount = aSourceRange.aStart.Row() - aRange.aStart.Row();
+ eDir = FILL_TO_TOP;
+ break;
+ case sheet::FillDirection_TO_LEFT:
+ aSourceRange.aStart.SetCol( static_cast<SCCOL>( aSourceRange.aEnd.Col() - nSourceCount + 1 ) );
+ nCount = aSourceRange.aStart.Col() - aRange.aStart.Col();
+ eDir = FILL_TO_LEFT;
+ break;
+ default:
+ bError = true;
+ }
+ const ScDocument& rDoc = pDocSh->GetDocument();
+ if (nCount < 0 || nCount > rDoc.MaxRow()) // overflow
+ bError = true;
+
+ if (!bError)
+ pDocSh->GetDocFunc().FillAuto( aSourceRange, nullptr, eDir, nCount, true );
+}
+
+// XAutoFormattable
+
+void SAL_CALL ScCellRangeObj::autoFormat( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScAutoFormat* pAutoFormat = ScGlobal::GetOrCreateAutoFormat();
+ ScAutoFormat::const_iterator it = pAutoFormat->find(aName);
+ if (it == pAutoFormat->end())
+ throw lang::IllegalArgumentException();
+
+ ScAutoFormat::const_iterator itBeg = pAutoFormat->begin();
+ size_t nIndex = std::distance(itBeg, it);
+ pDocSh->GetDocFunc().AutoFormat(aRange, nullptr, nIndex, true);
+
+ }
+}
+
+// XSortable
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScCellRangeObj::createSortDescriptor()
+{
+ SolarMutexGuard aGuard;
+ ScSortParam aParam;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ // create DB-Area only during execution; API always the exact area
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, ScGetDBSelection::ForceMark );
+ if (pData)
+ {
+ pData->GetSortParam(aParam);
+
+ // SortDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOLROW nFieldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aDBRange.aStart.Col()) :
+ static_cast<SCCOLROW>(aDBRange.aStart.Row());
+ for (sal_uInt16 i=0; i<aParam.GetSortKeyCount(); i++)
+ if ( aParam.maKeyState[i].bDoSort && aParam.maKeyState[i].nField >= nFieldStart )
+ aParam.maKeyState[i].nField -= nFieldStart;
+ }
+ }
+
+ uno::Sequence<beans::PropertyValue> aSeq( ScSortDescriptor::GetPropertyCount() );
+ ScSortDescriptor::FillProperties( aSeq, aParam );
+ return aSeq;
+}
+
+void SAL_CALL ScCellRangeObj::sort( const uno::Sequence<beans::PropertyValue>& aDescriptor )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ sal_uInt16 i;
+ ScSortParam aParam;
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+ if (pData)
+ {
+ // get old settings if not everything is set anew
+ pData->GetSortParam(aParam);
+ SCCOLROW nOldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aRange.aStart.Col()) :
+ static_cast<SCCOLROW>(aRange.aStart.Row());
+ for (i=0; i<aParam.GetSortKeyCount(); i++)
+ if ( aParam.maKeyState[i].bDoSort && aParam.maKeyState[i].nField >= nOldStart )
+ aParam.maKeyState[i].nField -= nOldStart;
+ }
+
+ ScSortDescriptor::FillSortParam( aParam, aDescriptor );
+
+ // SortDescriptor contains the counted fields inside the area
+ // ByRow can be changed during execution of FillSortParam
+ SCCOLROW nFieldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aRange.aStart.Col()) :
+ static_cast<SCCOLROW>(aRange.aStart.Row());
+ SCCOLROW nFieldEnd = aParam.bByRow ?
+ static_cast<SCCOLROW>(aRange.aEnd.Col()) :
+ static_cast<SCCOLROW>(aRange.aEnd.Row());
+ for (i=0; i<aParam.GetSortKeyCount(); i++)
+ {
+ aParam.maKeyState[i].nField += nFieldStart;
+ // tdf#103632 - sanity check poorly behaved macros.
+ if (aParam.maKeyState[i].nField > nFieldEnd)
+ aParam.maKeyState[i].nField = nFieldEnd;
+ }
+
+ SCTAB nTab = aRange.aStart.Tab();
+ aParam.nCol1 = aRange.aStart.Col();
+ aParam.nRow1 = aRange.aStart.Row();
+ aParam.nCol2 = aRange.aEnd.Col();
+ aParam.nRow2 = aRange.aEnd.Row();
+
+ pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+
+ ScDBDocFunc aFunc(*pDocSh); // area must be created
+ (void)aFunc.Sort( nTab, aParam, true, true, true );
+}
+
+// XFilterable
+
+uno::Reference<sheet::XSheetFilterDescriptor> SAL_CALL ScCellRangeObj::createFilterDescriptor(
+ sal_Bool bEmpty )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ rtl::Reference<ScFilterDescriptor> pNew = new ScFilterDescriptor(pDocSh);
+ if ( !bEmpty && pDocSh )
+ {
+ // create DB-Area only during execution; API always the exact area
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, ScGetDBSelection::ForceMark );
+ if (pData)
+ {
+ ScQueryParam aParam;
+ pData->GetQueryParam(aParam);
+ // FilterDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOLROW nFieldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aDBRange.aStart.Col()) :
+ static_cast<SCCOLROW>(aDBRange.aStart.Row());
+ SCSIZE nCount = aParam.GetEntryCount();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if (rEntry.bDoQuery && rEntry.nField >= nFieldStart)
+ rEntry.nField -= nFieldStart;
+ }
+ pNew->SetParam(aParam);
+ }
+ }
+ return pNew;
+}
+
+void SAL_CALL ScCellRangeObj::filter( const uno::Reference<sheet::XSheetFilterDescriptor>& xDescriptor )
+{
+ SolarMutexGuard aGuard;
+
+ if (!xDescriptor.is()) return;
+
+ // This could be theoretically an unknown object, so only use the
+ // public XSheetFilterDescriptor interface to copy the data into a
+ // ScFilterDescriptor object:
+ //! if it already a ScFilterDescriptor is, direct via getImplementation?
+
+ ScDocShell* pDocSh = GetDocShell();
+ rtl::Reference<ScFilterDescriptor> xImpl(new ScFilterDescriptor(pDocSh));
+ uno::Reference< sheet::XSheetFilterDescriptor2 > xDescriptor2( xDescriptor, uno::UNO_QUERY );
+ if ( xDescriptor2.is() )
+ {
+ xImpl->setFilterFields2( xDescriptor2->getFilterFields2() );
+ }
+ else
+ {
+ xImpl->setFilterFields( xDescriptor->getFilterFields() );
+ }
+ // the rest are now properties...
+
+ uno::Reference<beans::XPropertySet> xPropSet( xDescriptor, uno::UNO_QUERY );
+ if (xPropSet.is())
+ lcl_CopyProperties(*xImpl, *xPropSet);
+
+ if (!pDocSh)
+ return;
+
+ ScQueryParam aParam = xImpl->GetParam();
+ // FilterDescriptor contains the counted fields inside the area
+ SCCOLROW nFieldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aRange.aStart.Col()) :
+ static_cast<SCCOLROW>(aRange.aStart.Row());
+ SCSIZE nCount = aParam.GetEntryCount();
+ svl::SharedStringPool& rPool = pDocSh->GetDocument().GetSharedStringPool();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if (rEntry.bDoQuery)
+ {
+ rEntry.nField += nFieldStart;
+ // dialog always shows the string -> must match the value
+ ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ rItems.resize(1);
+ ScQueryEntry::Item& rItem = rItems.front();
+ if (rItem.meType != ScQueryEntry::ByString)
+ {
+ OUString aStr;
+ pDocSh->GetDocument().GetFormatTable()->GetInputLineString(rItem.mfVal, 0, aStr);
+ rItem.maString = rPool.intern(aStr);
+ }
+ }
+ }
+
+ SCTAB nTab = aRange.aStart.Tab();
+ aParam.nCol1 = aRange.aStart.Col();
+ aParam.nRow1 = aRange.aStart.Row();
+ aParam.nCol2 = aRange.aEnd.Col();
+ aParam.nRow2 = aRange.aEnd.Row();
+
+ pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+
+ //! keep source range in filter descriptor
+ //! if created by createFilterDescriptorByObject ???
+
+ ScDBDocFunc aFunc(*pDocSh);
+ aFunc.Query( nTab, aParam, nullptr, true, true ); // area must be created
+}
+
+//! get/setAutoFilter as properties!!!
+
+// XAdvancedFilterSource
+
+uno::Reference<sheet::XSheetFilterDescriptor> SAL_CALL ScCellRangeObj::createFilterDescriptorByObject(
+ const uno::Reference<sheet::XSheetFilterable>& xObject )
+{
+ SolarMutexGuard aGuard;
+
+ // this here is not the area, which will be filtered, instead the area
+ // with the query
+
+ uno::Reference<sheet::XCellRangeAddressable> xAddr( xObject, uno::UNO_QUERY );
+
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh || !xAddr.is() )
+ {
+ OSL_FAIL("no document or no area");
+ return nullptr;
+ }
+
+ //! check if xObject is in the same document
+
+ rtl::Reference<ScFilterDescriptor> pNew(new ScFilterDescriptor(pDocSh)); //! instead from object?
+
+ ScQueryParam aParam = pNew->GetParam();
+ aParam.bHasHeader = true;
+
+ table::CellRangeAddress aDataAddress(xAddr->getRangeAddress());
+ aParam.nCol1 = static_cast<SCCOL>(aDataAddress.StartColumn);
+ aParam.nRow1 = static_cast<SCROW>(aDataAddress.StartRow);
+ aParam.nCol2 = static_cast<SCCOL>(aDataAddress.EndColumn);
+ aParam.nRow2 = static_cast<SCROW>(aDataAddress.EndRow);
+ aParam.nTab = aDataAddress.Sheet;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ if (!rDoc.CreateQueryParam(aRange, aParam))
+ return nullptr;
+
+ // FilterDescriptor contains the counted fields inside the area
+ SCCOLROW nFieldStart = aParam.bByRow ?
+ static_cast<SCCOLROW>(aDataAddress.StartColumn) :
+ static_cast<SCCOLROW>(aDataAddress.StartRow);
+ SCSIZE nCount = aParam.GetEntryCount();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if (rEntry.bDoQuery && rEntry.nField >= nFieldStart)
+ rEntry.nField -= nFieldStart;
+ }
+
+ pNew->SetParam( aParam );
+ return pNew;
+}
+
+// XSubTotalSource
+
+uno::Reference<sheet::XSubTotalDescriptor> SAL_CALL ScCellRangeObj::createSubTotalDescriptor(
+ sal_Bool bEmpty )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<ScSubTotalDescriptor> pNew = new ScSubTotalDescriptor;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !bEmpty && pDocSh )
+ {
+ // create DB-Area only during execution; API always the exact area
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, ScGetDBSelection::ForceMark );
+ if (pData)
+ {
+ ScSubTotalParam aParam;
+ pData->GetSubTotalParam(aParam);
+ // SubTotalDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOL nFieldStart = aDBRange.aStart.Col();
+ for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
+ {
+ if ( aParam.bGroupActive[i] )
+ {
+ if ( aParam.nField[i] >= nFieldStart )
+ aParam.nField[i] = sal::static_int_cast<SCCOL>( aParam.nField[i] - nFieldStart );
+ for (SCCOL j=0; j<aParam.nSubTotals[i]; j++)
+ if ( aParam.pSubTotals[i][j] >= nFieldStart )
+ aParam.pSubTotals[i][j] = sal::static_int_cast<SCCOL>( aParam.pSubTotals[i][j] - nFieldStart );
+ }
+ }
+ pNew->SetParam(aParam);
+ }
+ }
+ return pNew;
+}
+
+void SAL_CALL ScCellRangeObj::applySubTotals(
+ const uno::Reference<sheet::XSubTotalDescriptor>& xDescriptor,
+ sal_Bool bReplace)
+{
+ SolarMutexGuard aGuard;
+
+ if (!xDescriptor.is()) return;
+
+ ScDocShell* pDocSh = GetDocShell();
+ ScSubTotalDescriptorBase* pImp =
+ comphelper::getFromUnoTunnel<ScSubTotalDescriptorBase>( xDescriptor );
+
+ if (!(pDocSh && pImp))
+ return;
+
+ ScSubTotalParam aParam;
+ pImp->GetData(aParam); // virtual method of base class
+
+ // SubTotalDescriptor contains the counted fields inside the area
+ SCCOL nFieldStart = aRange.aStart.Col();
+ for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
+ {
+ if ( aParam.bGroupActive[i] )
+ {
+ aParam.nField[i] = sal::static_int_cast<SCCOL>( aParam.nField[i] + nFieldStart );
+ for (SCCOL j=0; j<aParam.nSubTotals[i]; j++)
+ aParam.pSubTotals[i][j] = sal::static_int_cast<SCCOL>( aParam.pSubTotals[i][j] + nFieldStart );
+ }
+ }
+
+ aParam.bReplace = bReplace;
+
+ SCTAB nTab = aRange.aStart.Tab();
+ aParam.nCol1 = aRange.aStart.Col();
+ aParam.nRow1 = aRange.aStart.Row();
+ aParam.nCol2 = aRange.aEnd.Col();
+ aParam.nRow2 = aRange.aEnd.Row();
+
+ pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+
+ ScDBDocFunc aFunc(*pDocSh);
+ aFunc.DoSubTotals( nTab, aParam, true, true ); // area must be created
+}
+
+void SAL_CALL ScCellRangeObj::removeSubTotals()
+{
+ SolarMutexGuard aGuard;
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ ScSubTotalParam aParam;
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, ScGetDBSelection::ForceMark );
+ if (pData)
+ pData->GetSubTotalParam(aParam); // also keep field entries during remove
+
+ aParam.bRemoveOnly = true;
+
+ SCTAB nTab = aRange.aStart.Tab();
+ aParam.nCol1 = aRange.aStart.Col();
+ aParam.nRow1 = aRange.aStart.Row();
+ aParam.nCol2 = aRange.aEnd.Col();
+ aParam.nRow2 = aRange.aEnd.Row();
+
+ pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+
+ ScDBDocFunc aFunc(*pDocSh);
+ aFunc.DoSubTotals( nTab, aParam, true, true ); // are must be created
+}
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScCellRangeObj::createImportDescriptor( sal_Bool bEmpty )
+{
+ SolarMutexGuard aGuard;
+ ScImportParam aParam;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !bEmpty && pDocSh )
+ {
+ // create DB-Area only during execution; API always the exact area
+ ScDBData* pData = pDocSh->GetDBData( aRange, SC_DB_OLD, ScGetDBSelection::ForceMark );
+ if (pData)
+ pData->GetImportParam(aParam);
+ }
+
+ uno::Sequence<beans::PropertyValue> aSeq( ScImportDescriptor::GetPropertyCount() );
+ ScImportDescriptor::FillProperties( aSeq, aParam );
+ return aSeq;
+}
+
+void SAL_CALL ScCellRangeObj::doImport( const uno::Sequence<beans::PropertyValue>& aDescriptor )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ ScImportParam aParam;
+ ScImportDescriptor::FillImportParam( aParam, aDescriptor );
+
+ SCTAB nTab = aRange.aStart.Tab();
+ aParam.nCol1 = aRange.aStart.Col();
+ aParam.nRow1 = aRange.aStart.Row();
+ aParam.nCol2 = aRange.aEnd.Col();
+ aParam.nRow2 = aRange.aEnd.Row();
+
+ //! TODO: could we get passed a valid result set by any means?
+
+ pDocSh->GetDBData( aRange, SC_DB_MAKE, ScGetDBSelection::ForceMark ); // if needed create area
+
+ ScDBDocFunc aFunc(*pDocSh); // are must be created
+ aFunc.DoImport( nTab, aParam, nullptr ); //! Api-Flag as parameter
+}
+
+// XCellFormatRangesSupplier
+
+uno::Reference<container::XIndexAccess> SAL_CALL ScCellRangeObj::getCellFormatRanges()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScCellFormatsObj( pDocSh, aRange );
+ return nullptr;
+}
+
+// XUniqueCellFormatRangesSupplier
+
+uno::Reference<container::XIndexAccess> SAL_CALL ScCellRangeObj::getUniqueCellFormatRanges()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScUniqueCellFormatsObj( pDocSh, aRange );
+ return nullptr;
+}
+
+// XPropertySet extended for Range-Properties
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCellRangeObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pRangePropSet->getPropertyMap() ));
+ return aRef;
+}
+
+void ScCellRangeObj::SetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue )
+{
+ // Range has only Position and Size in addition to ScCellRangesBase, both are ReadOnly
+ // -> nothing to do here
+
+ ScCellRangesBase::SetOnePropertyValue( pEntry, aValue );
+}
+
+void ScCellRangeObj::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ if ( pEntry->nWID == SC_WID_UNO_POS )
+ {
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ // GetMMRect converts using HMM_PER_TWIPS, like the DrawingLayer
+ tools::Rectangle aMMRect(pDocSh->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab() ));
+ awt::Point aPos( aMMRect.Left(), aMMRect.Top() );
+ rAny <<= aPos;
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_SIZE )
+ {
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ // GetMMRect converts using HMM_PER_TWIPS, like the DrawingLayer
+ tools::Rectangle aMMRect = pDocSh->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab() );
+ Size aSize(aMMRect.GetSize());
+ awt::Size aAwtSize( aSize.Width(), aSize.Height() );
+ rAny <<= aAwtSize;
+ }
+ }
+ else
+ ScCellRangesBase::GetOnePropertyValue( pEntry, rAny );
+}
+
+const SfxItemPropertyMap& ScCellRangeObj::GetItemPropertyMap()
+{
+ return pRangePropSet->getPropertyMap();
+}
+
+// XServiceInfo
+
+OUString SAL_CALL ScCellRangeObj::getImplementationName()
+{
+ return "ScCellRangeObj";
+}
+
+sal_Bool SAL_CALL ScCellRangeObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellRangeObj::getSupportedServiceNames()
+{
+ return {SCSHEETCELLRANGE_SERVICE,
+ SCCELLRANGE_SERVICE,
+ SCCELLPROPERTIES_SERVICE,
+ SCCHARPROPERTIES_SERVICE,
+ SCPARAPROPERTIES_SERVICE};
+}
+
+const SvxItemPropertySet* ScCellObj::GetEditPropertySet()
+{
+ return lcl_GetEditPropertySet();
+}
+
+const SfxItemPropertyMap& ScCellObj::GetCellPropertyMap()
+{
+ return lcl_GetCellPropertySet()->getPropertyMap();
+}
+
+ScCellObj::ScCellObj(ScDocShell* pDocSh, const ScAddress& rP) :
+ ScCellRangeObj( pDocSh, ScRange(rP,rP) ),
+ pCellPropSet( lcl_GetCellPropertySet() ),
+ aCellPos( rP ),
+ nActionLockCount( 0 )
+{
+ // pUnoText is allocated on demand (GetUnoText)
+ // can't be aggregated because getString/setString is handled here
+}
+
+SvxUnoText& ScCellObj::GetUnoText()
+{
+ if (!mxUnoText.is())
+ {
+ mxUnoText.set(new ScCellTextObj(GetDocShell(), aCellPos));
+ if (nActionLockCount)
+ {
+ ScCellEditSource* pEditSource =
+ static_cast<ScCellEditSource*> (mxUnoText->GetEditSource());
+ if (pEditSource)
+ pEditSource->SetDoUpdateData(false);
+ }
+ }
+ return *mxUnoText;
+}
+
+ScCellObj::~ScCellObj()
+{
+}
+
+void ScCellObj::RefChanged()
+{
+ ScCellRangeObj::RefChanged();
+
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE(rRanges.size() == 1, "What ranges ?!?!");
+ if ( !rRanges.empty() )
+ {
+ aCellPos = rRanges[ 0 ].aStart;
+ }
+}
+
+uno::Any SAL_CALL ScCellObj::queryInterface( const uno::Type& rType )
+{
+ SC_QUERYINTERFACE( table::XCell )
+ SC_QUERYINTERFACE( table::XCell2 )
+ SC_QUERYINTERFACE( sheet::XFormulaTokens )
+ SC_QUERYINTERFACE( sheet::XCellAddressable )
+ SC_QUERYINTERFACE( text::XText )
+ SC_QUERYINTERFACE( text::XSimpleText )
+ SC_QUERYINTERFACE( text::XTextRange )
+ SC_QUERYINTERFACE( container::XEnumerationAccess )
+ SC_QUERYINTERFACE( container::XElementAccess )
+ SC_QUERYINTERFACE( sheet::XSheetAnnotationAnchor )
+ SC_QUERYINTERFACE( text::XTextFieldsSupplier )
+ SC_QUERYINTERFACE( document::XActionLockable )
+
+ return ScCellRangeObj::queryInterface( rType );
+}
+
+void SAL_CALL ScCellObj::acquire() noexcept
+{
+ ScCellRangeObj::acquire();
+}
+
+void SAL_CALL ScCellObj::release() noexcept
+{
+ ScCellRangeObj::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScCellObj::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes = comphelper::concatSequences(
+ ScCellRangeObj::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<table::XCell>::get(),
+ cppu::UnoType<sheet::XCellAddressable>::get(),
+ cppu::UnoType<text::XText>::get(),
+ cppu::UnoType<container::XEnumerationAccess>::get(),
+ cppu::UnoType<sheet::XSheetAnnotationAnchor>::get(),
+ cppu::UnoType<text::XTextFieldsSupplier>::get(),
+ cppu::UnoType<document::XActionLockable>::get(),
+ cppu::UnoType<sheet::XFormulaTokens>::get(),
+ cppu::UnoType<table::XCell2>::get()
+ } );
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScCellObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// helper methods
+
+OUString ScCellObj::GetInputString_Impl(bool bEnglish) const // for getFormula / FormulaLocal
+{
+ if (GetDocShell())
+ return lcl_GetInputString( GetDocShell()->GetDocument(), aCellPos, bEnglish );
+ return OUString();
+}
+
+OUString ScCellObj::GetOutputString_Impl() const
+{
+ ScDocShell* pDocSh = GetDocShell();
+ OUString aVal;
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScRefCellValue aCell(rDoc, aCellPos);
+
+ aVal = ScCellFormat::GetOutputString(rDoc, aCellPos, aCell);
+ }
+ return aVal;
+}
+
+void ScCellObj::SetString_Impl(const OUString& rString, bool bInterpret, bool bEnglish)
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ // GRAM_API for API compatibility.
+ (void)pDocSh->GetDocFunc().SetCellText(
+ aCellPos, rString, bInterpret, bEnglish, true, formula::FormulaGrammar::GRAM_API );
+ }
+}
+
+double ScCellObj::GetValue_Impl() const
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return pDocSh->GetDocument().GetValue( aCellPos );
+
+ return 0.0;
+}
+
+void ScCellObj::SetValue_Impl(double fValue)
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ pDocSh->GetDocFunc().SetValueCell(aCellPos, fValue, false);
+}
+
+// only for XML import
+
+void ScCellObj::InputEnglishString( const OUString& rText )
+{
+ // This is like a mixture of setFormula and property FormulaLocal:
+ // The cell's number format is checked for "text", a new cell format may be set,
+ // but all parsing is in English.
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ sal_uInt32 nOldFormat = rDoc.GetNumberFormat( aCellPos );
+ if (pFormatter->GetType(nOldFormat) == SvNumFormatType::TEXT)
+ {
+ SetString_Impl(rText, false, false); // text cell
+ return;
+ }
+
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+
+ ScInputStringType aRes =
+ ScStringUtil::parseInputString(*pFormatter, rText, LANGUAGE_ENGLISH_US);
+
+ if (aRes.meType != ScInputStringType::Unknown)
+ {
+ if ((nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && aRes.mnFormatType != SvNumFormatType::ALL)
+ {
+ // apply a format for the recognized type and the old format's language
+ sal_uInt32 nNewFormat = ScGlobal::GetStandardFormat(*pFormatter, nOldFormat, aRes.mnFormatType);
+ if (nNewFormat != nOldFormat)
+ {
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
+ // ATTR_LANGUAGE_FORMAT remains unchanged
+ rFunc.ApplyAttributes( *GetMarkData(), aPattern, true );
+ }
+ }
+ }
+ switch (aRes.meType)
+ {
+ case ScInputStringType::Formula:
+ rFunc.SetFormulaCell(
+ aCellPos,
+ new ScFormulaCell(rDoc, aCellPos, aRes.maText, formula::FormulaGrammar::GRAM_API),
+ false);
+ break;
+ case ScInputStringType::Number:
+ rFunc.SetValueCell(aCellPos, aRes.mfValue, false);
+ break;
+ case ScInputStringType::Text:
+ rFunc.SetStringOrEditCell(aCellPos, aRes.maText, false);
+ break;
+ default:
+ SetString_Impl(rText, false, false); // probably empty string
+ }
+}
+
+// XText
+
+uno::Reference<text::XTextCursor> SAL_CALL ScCellObj::createTextCursor()
+{
+ SolarMutexGuard aGuard;
+ return new ScCellTextCursor( *this );
+}
+
+uno::Reference<text::XTextCursor> SAL_CALL ScCellObj::createTextCursorByRange(
+ const uno::Reference<text::XTextRange>& aTextPosition )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<SvxUnoTextCursor> pCursor = new ScCellTextCursor( *this );
+
+ SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( aTextPosition );
+ if(pRange)
+ pCursor->SetSelection( pRange->GetSelection() );
+ else
+ {
+ ScCellTextCursor* pOther = comphelper::getFromUnoTunnel<ScCellTextCursor>( aTextPosition );
+ if(!pOther)
+ throw uno::RuntimeException();
+
+ pCursor->SetSelection( pOther->GetSelection() );
+
+ }
+
+ return pCursor;
+}
+
+OUString SAL_CALL ScCellObj::getString()
+{
+ SolarMutexGuard aGuard;
+ return GetOutputString_Impl();
+}
+
+void SAL_CALL ScCellObj::setString( const OUString& aText )
+{
+ SolarMutexGuard aGuard;
+ SetString_Impl(aText, false, false); // always text
+
+ // don't create pUnoText here if not there
+ if (mxUnoText.is())
+ mxUnoText->SetSelection(ESelection( 0,0, 0,aText.getLength() ));
+}
+
+void SAL_CALL ScCellObj::insertString( const uno::Reference<text::XTextRange>& xRange,
+ const OUString& aString, sal_Bool bAbsorb )
+{
+ // special handling for ScCellTextCursor is no longer needed,
+ // SvxUnoText::insertString checks for SvxUnoTextRangeBase instead of SvxUnoTextRange
+
+ SolarMutexGuard aGuard;
+ GetUnoText().insertString(xRange, aString, bAbsorb);
+}
+
+void SAL_CALL ScCellObj::insertControlCharacter( const uno::Reference<text::XTextRange>& xRange,
+ sal_Int16 nControlCharacter, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ GetUnoText().insertControlCharacter(xRange, nControlCharacter, bAbsorb);
+}
+
+void SAL_CALL ScCellObj::insertTextContent( const uno::Reference<text::XTextRange >& xRange,
+ const uno::Reference<text::XTextContent >& xContent,
+ sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh && xContent.is() )
+ {
+ ScEditFieldObj* pCellField = comphelper::getFromUnoTunnel<ScEditFieldObj>(xContent);
+ SvxUnoTextRangeBase* pTextRange = comphelper::getFromUnoTunnel<ScCellTextCursor>( xRange );
+
+ if ( pCellField && !pCellField->IsInserted() && pTextRange )
+ {
+ SvxEditSource* pEditSource = pTextRange->GetEditSource();
+ ESelection aSelection(pTextRange->GetSelection());
+
+ if (!bAbsorb)
+ {
+ // do not replace -> append
+ aSelection.Adjust();
+ aSelection.nStartPara = aSelection.nEndPara;
+ aSelection.nStartPos = aSelection.nEndPos;
+ }
+
+ if (pCellField->GetFieldType() == text::textfield::Type::TABLE)
+ pCellField->setPropertyValue(SC_UNONAME_TABLEPOS, uno::Any(sal_Int32(aCellPos.Tab())));
+
+ SvxFieldItem aItem = pCellField->CreateFieldItem();
+ SvxTextForwarder* pForwarder = pEditSource->GetTextForwarder();
+ pForwarder->QuickInsertField( aItem, aSelection );
+ pEditSource->UpdateData();
+
+ // new selection: a digit
+ aSelection.Adjust();
+ aSelection.nEndPara = aSelection.nStartPara;
+ aSelection.nEndPos = aSelection.nStartPos + 1;
+ uno::Reference<text::XTextRange> xParent(this);
+ pCellField->InitDoc(
+ xParent, std::make_unique<ScCellEditSource>(pDocSh, aCellPos), aSelection);
+
+ // for bAbsorb=FALSE, the new selection must be behind the inserted content
+ // (the xml filter relies on this)
+ if (!bAbsorb)
+ aSelection.nStartPos = aSelection.nEndPos;
+
+ pTextRange->SetSelection( aSelection );
+
+ return;
+ }
+ }
+ GetUnoText().insertTextContent(xRange, xContent, bAbsorb);
+}
+
+void SAL_CALL ScCellObj::removeTextContent( const uno::Reference<text::XTextContent>& xContent )
+{
+ SolarMutexGuard aGuard;
+ if ( xContent.is() )
+ {
+ ScEditFieldObj* pCellField = comphelper::getFromUnoTunnel<ScEditFieldObj>(xContent);
+ if ( pCellField && pCellField->IsInserted() )
+ {
+ //! Check if field is in this cell
+ pCellField->DeleteField();
+ return;
+ }
+ }
+ GetUnoText().removeTextContent(xContent);
+}
+
+uno::Reference<text::XText> SAL_CALL ScCellObj::getText()
+{
+ return this;
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScCellObj::getStart()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getStart();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScCellObj::getEnd()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getEnd();
+}
+
+uno::Reference<container::XEnumeration> SAL_CALL ScCellObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().createEnumeration();
+}
+
+uno::Type SAL_CALL ScCellObj::getElementType()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getElementType();
+}
+
+sal_Bool SAL_CALL ScCellObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().hasElements();
+}
+
+// XCell
+
+OUString SAL_CALL ScCellObj::getFormula()
+{
+ SolarMutexGuard aGuard;
+ return GetInputString_Impl( true /* English */ );
+}
+
+void SAL_CALL ScCellObj::setFormula( const OUString& aFormula )
+{
+ SolarMutexGuard aGuard;
+ SetString_Impl(aFormula, true, true); // Interpret as English
+}
+
+double SAL_CALL ScCellObj::getValue()
+{
+ SolarMutexGuard aGuard;
+ return GetValue_Impl();
+}
+
+void SAL_CALL ScCellObj::setValue( double nValue )
+{
+ SolarMutexGuard aGuard;
+ SetValue_Impl(nValue);
+}
+
+void SAL_CALL ScCellObj::setFormulaString( const OUString& aFormula)
+{
+ SolarMutexGuard aGuard;
+ ScDocShell *pDocSh = GetDocShell();
+ if( pDocSh )
+ {
+ ScFormulaCell* pCell = new ScFormulaCell( pDocSh->GetDocument(), aCellPos );
+ pCell->SetHybridFormula( aFormula, formula::FormulaGrammar::GRAM_NATIVE );
+ pDocSh->GetDocFunc().SetFormulaCell(aCellPos, pCell, false);
+ }
+}
+void SAL_CALL ScCellObj::setFormulaResult( double nValue )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ ScRefCellValue aCell(pDocSh->GetDocument(), aCellPos);
+ if (aCell.meType == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pCell = aCell.mpFormula;
+ pCell->SetHybridDouble( nValue );
+ pCell->ResetDirty();
+ pCell->SetChanged(false);
+ }
+ }
+}
+
+table::CellContentType SAL_CALL ScCellObj::getType()
+{
+ SolarMutexGuard aGuard;
+ table::CellContentType eRet = table::CellContentType_EMPTY;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ CellType eCalcType = pDocSh->GetDocument().GetCellType( aCellPos );
+ switch (eCalcType)
+ {
+ case CELLTYPE_VALUE:
+ eRet = table::CellContentType_VALUE;
+ break;
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ eRet = table::CellContentType_TEXT;
+ break;
+ case CELLTYPE_FORMULA:
+ eRet = table::CellContentType_FORMULA;
+ break;
+ default:
+ eRet = table::CellContentType_EMPTY;
+ }
+ }
+ else
+ {
+ OSL_FAIL("no DocShell"); //! Exception or so?
+ }
+
+ return eRet;
+}
+
+sal_Int32 ScCellObj::GetResultType_Impl() const
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 eRet = sheet::FormulaResult::STRING;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ {
+ if (pDocSh->GetDocument().GetCellType(aCellPos) == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = pDocSh->GetDocument().GetFormulaCell(aCellPos);
+ if (!pFCell)
+ {
+ // should throw instead of default string?
+ }
+ else if (pFCell->GetErrCode() != FormulaError::NONE )
+ {
+ eRet = sheet::FormulaResult::ERROR;
+ }
+ else if (pFCell->IsValue())
+ {
+ eRet = sheet::FormulaResult::VALUE;
+ }
+ else
+ {
+ eRet = sheet::FormulaResult::STRING;
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("no DocShell");
+ }
+
+ return eRet;
+}
+
+table::CellContentType ScCellObj::GetContentType_Impl()
+{
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScRefCellValue aCell(pDocSh->GetDocument(), aCellPos);
+ if (aCell.meType == CELLTYPE_FORMULA)
+ {
+ bool bValue = aCell.mpFormula->IsValue();
+ return bValue ? table::CellContentType_VALUE : table::CellContentType_TEXT;
+ }
+ }
+ return getType();
+}
+
+sal_Int32 SAL_CALL ScCellObj::getError()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ {
+ OSL_FAIL("no DocShell"); //! Exception or so?
+ return 0;
+ }
+
+ FormulaError nError = FormulaError::NONE;
+ ScRefCellValue aCell(pDocSh->GetDocument(), aCellPos);
+ if (aCell.meType == CELLTYPE_FORMULA)
+ nError = aCell.mpFormula->GetErrCode();
+
+ return static_cast<sal_Int32>(nError);
+}
+
+// XFormulaTokens
+
+uno::Sequence<sheet::FormulaToken> SAL_CALL ScCellObj::getTokens()
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence<sheet::FormulaToken> aSequence;
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return aSequence;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScRefCellValue aCell(rDoc, aCellPos);
+ if (aCell.meType == CELLTYPE_FORMULA)
+ {
+ ScTokenArray* pTokenArray = aCell.mpFormula->GetCode();
+ if (pTokenArray)
+ ScTokenConversion::ConvertToTokenSequence(rDoc, aSequence, *pTokenArray);
+ }
+ return aSequence;
+}
+
+void SAL_CALL ScCellObj::setTokens( const uno::Sequence<sheet::FormulaToken>& rTokens )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScTokenArray aTokenArray(rDoc);
+ (void)ScTokenConversion::ConvertToTokenArray( rDoc, aTokenArray, rTokens );
+
+ ScFormulaCell* pNewCell = new ScFormulaCell(rDoc, aCellPos, aTokenArray);
+ (void)pDocSh->GetDocFunc().SetFormulaCell(aCellPos, pNewCell, false);
+ }
+}
+
+// XCellAddressable
+
+table::CellAddress SAL_CALL ScCellObj::getCellAddress()
+{
+ SolarMutexGuard aGuard;
+ table::CellAddress aAdr;
+ aAdr.Sheet = aCellPos.Tab();
+ aAdr.Column = aCellPos.Col();
+ aAdr.Row = aCellPos.Row();
+ return aAdr;
+}
+
+// XSheetAnnotationAnchor
+
+uno::Reference<sheet::XSheetAnnotation> SAL_CALL ScCellObj::getAnnotation()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScAnnotationObj( pDocSh, aCellPos );
+
+ OSL_FAIL("getAnnotation without DocShell");
+ return nullptr;
+}
+
+// XFieldTypesSupplier
+
+uno::Reference<container::XEnumerationAccess> SAL_CALL ScCellObj::getTextFields()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ uno::Reference<text::XTextRange> xContent(this);
+ return new ScCellFieldsObj(xContent, pDocSh, aCellPos);
+ }
+
+ return nullptr;
+}
+
+uno::Reference<container::XNameAccess> SAL_CALL ScCellObj::getTextFieldMasters()
+{
+ // there is no such thing in Calc (?)
+ return nullptr;
+}
+
+// XPropertySet extended for Cell-Properties
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCellObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pCellPropSet->getPropertyMap() ));
+ return aRef;
+}
+
+void ScCellObj::SetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue )
+{
+ if ( !pEntry )
+ return;
+
+ if ( pEntry->nWID == SC_WID_UNO_FORMLOC )
+ {
+ OUString aStrVal;
+ aValue >>= aStrVal;
+ SetString_Impl(aStrVal, true, false); // interpret locally
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_FORMRT || pEntry->nWID == SC_WID_UNO_FORMRT2
+ || pEntry->nWID == SC_WID_UNO_CELLCONTENTTYPE )
+ {
+ // Read-Only
+ //! Exception or so...
+ }
+ else
+ ScCellRangeObj::SetOnePropertyValue( pEntry, aValue );
+}
+
+void ScCellObj::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ if ( pEntry->nWID == SC_WID_UNO_FORMLOC )
+ {
+ // sal_False = local
+ rAny <<= GetInputString_Impl(false);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_FORMRT2 )
+ {
+ sal_Int32 eType = GetResultType_Impl();
+ rAny <<= eType;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLCONTENTTYPE || pEntry->nWID == SC_WID_UNO_FORMRT )
+ {
+ table::CellContentType eType = GetContentType_Impl();
+ rAny <<= eType;
+ }
+ else
+ ScCellRangeObj::GetOnePropertyValue(pEntry, rAny);
+}
+
+const SfxItemPropertyMap& ScCellObj::GetItemPropertyMap()
+{
+ return pCellPropSet->getPropertyMap();
+}
+
+// XServiceInfo
+
+OUString SAL_CALL ScCellObj::getImplementationName()
+{
+ return "ScCellObj";
+}
+
+sal_Bool SAL_CALL ScCellObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellObj::getSupportedServiceNames()
+{
+ return {SCSHEETCELL_SERVICE,
+ SCCELL_SERVICE,
+ SCCELLPROPERTIES_SERVICE,
+ SCCHARPROPERTIES_SERVICE,
+ SCPARAPROPERTIES_SERVICE,
+ SCSHEETCELLRANGE_SERVICE,
+ SCCELLRANGE_SERVICE};
+}
+
+// XActionLockable
+
+sal_Bool SAL_CALL ScCellObj::isActionLocked()
+{
+ SolarMutexGuard aGuard;
+ return nActionLockCount != 0;
+}
+
+void SAL_CALL ScCellObj::addActionLock()
+{
+ SolarMutexGuard aGuard;
+ if (!nActionLockCount)
+ {
+ if (mxUnoText.is())
+ {
+ ScCellEditSource* pEditSource =
+ static_cast<ScCellEditSource*> (mxUnoText->GetEditSource());
+ if (pEditSource)
+ pEditSource->SetDoUpdateData(false);
+ }
+ }
+ nActionLockCount++;
+}
+
+void SAL_CALL ScCellObj::removeActionLock()
+{
+ SolarMutexGuard aGuard;
+ if (nActionLockCount <= 0)
+ return;
+
+ nActionLockCount--;
+ if (nActionLockCount)
+ return;
+
+ if (mxUnoText.is())
+ {
+ ScCellEditSource* pEditSource =
+ static_cast<ScCellEditSource*> (mxUnoText->GetEditSource());
+ if (pEditSource)
+ {
+ pEditSource->SetDoUpdateData(true);
+ if (pEditSource->IsDirty())
+ pEditSource->UpdateData();
+ }
+ }
+}
+
+void SAL_CALL ScCellObj::setActionLocks( sal_Int16 nLock )
+{
+ SolarMutexGuard aGuard;
+ if (mxUnoText.is())
+ {
+ ScCellEditSource* pEditSource =
+ static_cast<ScCellEditSource*> (mxUnoText->GetEditSource());
+ if (pEditSource)
+ {
+ pEditSource->SetDoUpdateData(nLock == 0);
+ if ((nActionLockCount > 0) && (nLock == 0) && pEditSource->IsDirty())
+ pEditSource->UpdateData();
+ }
+ }
+ nActionLockCount = nLock;
+}
+
+sal_Int16 SAL_CALL ScCellObj::resetActionLocks()
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nRet(nActionLockCount);
+ if (mxUnoText.is())
+ {
+ ScCellEditSource* pEditSource =
+ static_cast<ScCellEditSource*> (mxUnoText->GetEditSource());
+ if (pEditSource)
+ {
+ pEditSource->SetDoUpdateData(true);
+ if (pEditSource->IsDirty())
+ pEditSource->UpdateData();
+ }
+ }
+ nActionLockCount = 0;
+ return nRet;
+}
+
+static ScRange MaxDocRange(ScDocShell* pDocSh, SCTAB nTab)
+{
+ const SCCOL nMaxcol = pDocSh ? pDocSh->GetDocument().MaxCol() : MAXCOL;
+ const SCROW nMaxRow = pDocSh ? pDocSh->GetDocument().MaxRow() : MAXROW;
+ return ScRange(0, 0, nTab, nMaxcol, nMaxRow, nTab);
+}
+
+ScTableSheetObj::ScTableSheetObj( ScDocShell* pDocSh, SCTAB nTab ) :
+ ScCellRangeObj( pDocSh, MaxDocRange(pDocSh, nTab) ),
+ pSheetPropSet(lcl_GetSheetPropertySet())
+{
+}
+
+ScTableSheetObj::~ScTableSheetObj()
+{
+}
+
+void ScTableSheetObj::InitInsertSheet(ScDocShell* pDocSh, SCTAB nTab)
+{
+ ScDocument& rDoc = pDocSh->GetDocument();
+ InitInsertRange( pDocSh, ScRange(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab) );
+}
+
+uno::Any SAL_CALL ScTableSheetObj::queryInterface( const uno::Type& rType )
+{
+ SC_QUERYINTERFACE( sheet::XSpreadsheet )
+ SC_QUERYINTERFACE( container::XNamed )
+ SC_QUERYINTERFACE( sheet::XSheetPageBreak )
+ SC_QUERYINTERFACE( sheet::XCellRangeMovement )
+ SC_QUERYINTERFACE( table::XTableChartsSupplier )
+ SC_QUERYINTERFACE( sheet::XDataPilotTablesSupplier )
+ SC_QUERYINTERFACE( sheet::XScenariosSupplier )
+ SC_QUERYINTERFACE( sheet::XSheetAnnotationsSupplier )
+ SC_QUERYINTERFACE( drawing::XDrawPageSupplier )
+ SC_QUERYINTERFACE( sheet::XPrintAreas )
+ SC_QUERYINTERFACE( sheet::XSheetAuditing )
+ SC_QUERYINTERFACE( sheet::XSheetOutline )
+ SC_QUERYINTERFACE( util::XProtectable )
+ SC_QUERYINTERFACE( sheet::XScenario )
+ SC_QUERYINTERFACE( sheet::XScenarioEnhanced )
+ SC_QUERYINTERFACE( sheet::XSheetLinkable )
+ SC_QUERYINTERFACE( sheet::XExternalSheetName )
+ SC_QUERYINTERFACE( document::XEventsSupplier )
+ SC_QUERYINTERFACE( table::XTablePivotChartsSupplier )
+
+ return ScCellRangeObj::queryInterface( rType );
+}
+
+void SAL_CALL ScTableSheetObj::acquire() noexcept
+{
+ ScCellRangeObj::acquire();
+}
+
+void SAL_CALL ScTableSheetObj::release() noexcept
+{
+ ScCellRangeObj::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScTableSheetObj::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes = comphelper::concatSequences(
+ ScCellRangeObj::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XSpreadsheet>::get(),
+ cppu::UnoType<container::XNamed>::get(),
+ cppu::UnoType<sheet::XSheetPageBreak>::get(),
+ cppu::UnoType<sheet::XCellRangeMovement>::get(),
+ cppu::UnoType<table::XTableChartsSupplier>::get(),
+ cppu::UnoType<sheet::XDataPilotTablesSupplier>::get(),
+ cppu::UnoType<sheet::XScenariosSupplier>::get(),
+ cppu::UnoType<sheet::XSheetAnnotationsSupplier>::get(),
+ cppu::UnoType<drawing::XDrawPageSupplier>::get(),
+ cppu::UnoType<sheet::XPrintAreas>::get(),
+ cppu::UnoType<sheet::XSheetAuditing>::get(),
+ cppu::UnoType<sheet::XSheetOutline>::get(),
+ cppu::UnoType<util::XProtectable>::get(),
+ cppu::UnoType<sheet::XScenario>::get(),
+ cppu::UnoType<sheet::XScenarioEnhanced>::get(),
+ cppu::UnoType<sheet::XSheetLinkable>::get(),
+ cppu::UnoType<sheet::XExternalSheetName>::get(),
+ cppu::UnoType<document::XEventsSupplier>::get(),
+ cppu::UnoType<table::XTablePivotChartsSupplier>::get()
+ } );
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScTableSheetObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// Helper functions
+
+SCTAB ScTableSheetObj::GetTab_Impl() const
+{
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE(rRanges.size() == 1, "What ranges ?!?!");
+ if ( !rRanges.empty() )
+ {
+ return rRanges[ 0 ].aStart.Tab();
+ }
+ return 0;
+}
+
+// former XSheet
+
+uno::Reference<table::XTableCharts> SAL_CALL ScTableSheetObj::getCharts()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScChartsObj( pDocSh, GetTab_Impl() );
+
+ OSL_FAIL("no document");
+ return nullptr;
+}
+
+uno::Reference<table::XTablePivotCharts> SAL_CALL ScTableSheetObj::getPivotCharts()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if (pDocSh)
+ return new sc::TablePivotCharts(pDocSh, GetTab_Impl());
+
+ OSL_FAIL("no document");
+ return nullptr;
+}
+
+uno::Reference<sheet::XDataPilotTables> SAL_CALL ScTableSheetObj::getDataPilotTables()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScDataPilotTablesObj(*pDocSh, GetTab_Impl());
+
+ OSL_FAIL("no document");
+ return nullptr;
+}
+
+uno::Reference<sheet::XScenarios> SAL_CALL ScTableSheetObj::getScenarios()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+
+ if ( pDocSh )
+ return new ScScenariosObj( pDocSh, GetTab_Impl() );
+
+ OSL_FAIL("no document");
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetAnnotations> SAL_CALL ScTableSheetObj::getAnnotations()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+
+ if ( pDocSh )
+ return new ScAnnotationsObj( pDocSh, GetTab_Impl() );
+
+ OSL_FAIL("no document");
+ return nullptr;
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScTableSheetObj::getCellRangeByName(
+ const OUString& rRange )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getCellRangeByName( rRange );
+}
+
+uno::Reference<sheet::XSheetCellCursor> SAL_CALL ScTableSheetObj::createCursor()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ //! single cell or whole table??????
+ const ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ return new ScCellCursorObj( pDocSh, ScRange( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab ) );
+ }
+ return nullptr;
+}
+
+uno::Reference<sheet::XSheetCellCursor> SAL_CALL ScTableSheetObj::createCursorByRange(
+ const uno::Reference<sheet::XSheetCellRange>& xCellRange )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh && xCellRange.is() )
+ {
+ ScCellRangesBase* pRangesImp = comphelper::getFromUnoTunnel<ScCellRangesBase>( xCellRange );
+ if (pRangesImp)
+ {
+ const ScRangeList& rRanges = pRangesImp->GetRangeList();
+ SAL_WARN_IF( rRanges.size() != 1, "sc", "ScTableSheetObj::createCursorByRange: Range? Ranges?");
+ if (rRanges.empty())
+ return nullptr;
+ return new ScCellCursorObj( pDocSh, rRanges[ 0 ] );
+ }
+ }
+ return nullptr;
+}
+
+// XSheetCellRange
+
+uno::Reference<sheet::XSpreadsheet> SAL_CALL ScTableSheetObj::getSpreadsheet()
+{
+ return this; //!???
+}
+
+// XCellRange
+
+uno::Reference<table::XCell> SAL_CALL ScTableSheetObj::getCellByPosition(
+ sal_Int32 nColumn, sal_Int32 nRow )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::GetCellByPosition_Impl(nColumn, nRow);
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScTableSheetObj::getCellRangeByPosition(
+ sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getCellRangeByPosition(nLeft,nTop,nRight,nBottom);
+}
+
+uno::Sequence<sheet::TablePageBreakData> SAL_CALL ScTableSheetObj::getColumnPageBreaks()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ Size aSize(rDoc.GetPageSize( nTab ));
+ if (aSize.Width() && aSize.Height()) // effective size already set?
+ rDoc.UpdatePageBreaks( nTab );
+ else
+ {
+ // update breaks like in ScDocShell::PageStyleModified:
+ ScPrintFunc aPrintFunc( pDocSh, pDocSh->GetPrinter(), nTab );
+ aPrintFunc.UpdatePages();
+ }
+
+ SCCOL nCount = 0;
+ for (SCCOL nCol : rDoc.GetColumnsRange(nTab, 0, rDoc.MaxCol()))
+ if (rDoc.HasColBreak(nCol, nTab) != ScBreakType::NONE)
+ ++nCount;
+
+ sheet::TablePageBreakData aData;
+ uno::Sequence<sheet::TablePageBreakData> aSeq(nCount);
+ sheet::TablePageBreakData* pAry = aSeq.getArray();
+ sal_uInt16 nPos = 0;
+ for (SCCOL nCol : rDoc.GetColumnsRange(nTab, 0, rDoc.MaxCol()))
+ {
+ ScBreakType nBreak = rDoc.HasColBreak(nCol, nTab);
+ if (nBreak != ScBreakType::NONE)
+ {
+ aData.Position = nCol;
+ aData.ManualBreak = bool(nBreak & ScBreakType::Manual);
+ pAry[nPos] = aData;
+ ++nPos;
+ }
+ }
+ return aSeq;
+ }
+ return {};
+}
+
+uno::Sequence<sheet::TablePageBreakData> SAL_CALL ScTableSheetObj::getRowPageBreaks()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ Size aSize(rDoc.GetPageSize( nTab ));
+ if (aSize.Width() && aSize.Height()) // effective size already set?
+ rDoc.UpdatePageBreaks( nTab );
+ else
+ {
+ // update breaks like in ScDocShell::PageStyleModified:
+ ScPrintFunc aPrintFunc( pDocSh, pDocSh->GetPrinter(), nTab );
+ aPrintFunc.UpdatePages();
+ }
+ return rDoc.GetRowBreakData(nTab);
+ }
+ return {};
+}
+
+void SAL_CALL ScTableSheetObj::removeAllManualPageBreaks()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ //! DocFunc function, also for ScViewFunc::RemoveManualBreaks
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bool bUndo (rDoc.IsUndoEnabled());
+ SCTAB nTab = GetTab_Impl();
+
+ if (bUndo)
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ rDoc.CopyToDocument(0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab, InsertDeleteFlags::NONE, false, *pUndoDoc);
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRemoveBreaks>( pDocSh, nTab, std::move(pUndoDoc) ) );
+ }
+
+ rDoc.RemoveManualBreaks(nTab);
+ rDoc.UpdatePageBreaks(nTab);
+
+ //? UpdatePageBreakData( sal_True );
+ pDocSh->SetDocumentModified();
+ pDocSh->PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab), PaintPartFlags::Grid);
+}
+
+// XNamed
+
+OUString SAL_CALL ScTableSheetObj::getName()
+{
+ SolarMutexGuard aGuard;
+ OUString aName;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ pDocSh->GetDocument().GetName( GetTab_Impl(), aName );
+ return aName;
+}
+
+void SAL_CALL ScTableSheetObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ pDocSh->GetDocFunc().RenameTable( GetTab_Impl(), aNewName, true, true );
+ }
+}
+
+// XDrawPageSupplier
+
+uno::Reference<drawing::XDrawPage> SAL_CALL ScTableSheetObj::getDrawPage()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDrawLayer* pDrawLayer = pDocSh->MakeDrawLayer();
+ OSL_ENSURE(pDrawLayer,"Cannot create Draw-Layer");
+
+ SCTAB nTab = GetTab_Impl();
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage,"Draw-Page not found");
+ if (pPage)
+ return uno::Reference<drawing::XDrawPage> (pPage->getUnoPage(), uno::UNO_QUERY);
+
+ // The DrawPage object will register itself as a Listener at SdrModel
+ // and should receive all action from there
+ }
+ return nullptr;
+}
+
+// XCellMovement
+
+void SAL_CALL ScTableSheetObj::insertCells( const table::CellRangeAddress& rRangeAddress,
+ sheet::CellInsertMode nMode )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ bool bDo = true;
+ InsCellCmd eCmd = INS_NONE;
+ switch (nMode)
+ {
+ case sheet::CellInsertMode_NONE: bDo = false; break;
+ case sheet::CellInsertMode_DOWN: eCmd = INS_CELLSDOWN; break;
+ case sheet::CellInsertMode_RIGHT: eCmd = INS_CELLSRIGHT; break;
+ case sheet::CellInsertMode_ROWS: eCmd = INS_INSROWS_BEFORE; break;
+ case sheet::CellInsertMode_COLUMNS: eCmd = INS_INSCOLS_BEFORE; break;
+ default:
+ OSL_FAIL("insertCells: wrong mode");
+ bDo = false;
+ }
+
+ if (bDo)
+ {
+ OSL_ENSURE( rRangeAddress.Sheet == GetTab_Impl(), "wrong table in CellRangeAddress" );
+ ScRange aScRange;
+ ScUnoConversion::FillScRange( aScRange, rRangeAddress );
+ (void)pDocSh->GetDocFunc().InsertCells( aScRange, nullptr, eCmd, true, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::removeRange( const table::CellRangeAddress& rRangeAddress,
+ sheet::CellDeleteMode nMode )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ bool bDo = true;
+ DelCellCmd eCmd = DelCellCmd::NONE;
+ switch (nMode)
+ {
+ case sheet::CellDeleteMode_NONE: bDo = false; break;
+ case sheet::CellDeleteMode_UP: eCmd = DelCellCmd::CellsUp; break;
+ case sheet::CellDeleteMode_LEFT: eCmd = DelCellCmd::CellsLeft; break;
+ case sheet::CellDeleteMode_ROWS: eCmd = DelCellCmd::Rows; break;
+ case sheet::CellDeleteMode_COLUMNS: eCmd = DelCellCmd::Cols; break;
+ default:
+ OSL_FAIL("deleteCells: wrong mode");
+ bDo = false;
+ }
+
+ if (bDo)
+ {
+ OSL_ENSURE( rRangeAddress.Sheet == GetTab_Impl(), "wrong table in CellRangeAddress" );
+ ScRange aScRange;
+ ScUnoConversion::FillScRange( aScRange, rRangeAddress );
+ (void)pDocSh->GetDocFunc().DeleteCells( aScRange, nullptr, eCmd, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::moveRange( const table::CellAddress& aDestination,
+ const table::CellRangeAddress& aSource )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ OSL_ENSURE( aSource.Sheet == GetTab_Impl(), "wrong table in CellRangeAddress" );
+ ScRange aSourceRange;
+ ScUnoConversion::FillScRange( aSourceRange, aSource );
+ ScAddress aDestPos( static_cast<SCCOL>(aDestination.Column), static_cast<SCROW>(aDestination.Row), aDestination.Sheet );
+ (void)pDocSh->GetDocFunc().MoveBlock( aSourceRange, aDestPos, true, true, true, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::copyRange( const table::CellAddress& aDestination,
+ const table::CellRangeAddress& aSource )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ OSL_ENSURE( aSource.Sheet == GetTab_Impl(), "wrong table in CellRangeAddress" );
+ ScRange aSourceRange;
+ ScUnoConversion::FillScRange( aSourceRange, aSource );
+ ScAddress aDestPos( static_cast<SCCOL>(aDestination.Column), static_cast<SCROW>(aDestination.Row), aDestination.Sheet );
+ (void)pDocSh->GetDocFunc().MoveBlock( aSourceRange, aDestPos, false, true, true, true );
+ }
+}
+
+// XPrintAreas
+
+void ScTableSheetObj::PrintAreaUndo_Impl( std::unique_ptr<ScPrintRangeSaver> pOldRanges )
+{
+ // page break and undo
+ ScDocShell* pDocSh = GetDocShell();
+
+ if(!pDocSh)
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const bool bUndo(rDoc.IsUndoEnabled());
+ const SCTAB nTab(GetTab_Impl());
+
+ if(bUndo)
+ {
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoPrintRange>(
+ pDocSh,
+ nTab,
+ std::move(pOldRanges),
+ rDoc.CreatePrintRangeSaver())); // create new ranges
+ }
+
+ ScPrintFunc(pDocSh, pDocSh->GetPrinter(), nTab).UpdatePages();
+ SfxBindings* pBindings = pDocSh->GetViewBindings();
+
+ if(pBindings)
+ {
+ pBindings->Invalidate(SID_DELETE_PRINTAREA);
+ }
+
+ pDocSh->SetDocumentModified();
+}
+
+uno::Sequence<table::CellRangeAddress> SAL_CALL ScTableSheetObj::getPrintAreas()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ sal_uInt16 nCount = rDoc.GetPrintRangeCount( nTab );
+
+ table::CellRangeAddress aRangeAddress;
+ uno::Sequence<table::CellRangeAddress> aSeq(nCount);
+ table::CellRangeAddress* pAry = aSeq.getArray();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ const ScRange* pRange = rDoc.GetPrintRange( nTab, i );
+ OSL_ENSURE(pRange,"where is the printing area");
+ if (pRange)
+ {
+ ScUnoConversion::FillApiRange( aRangeAddress, *pRange );
+ aRangeAddress.Sheet = nTab; // core does not care about sheet index
+ pAry[i] = aRangeAddress;
+ }
+ }
+ return aSeq;
+ }
+ return uno::Sequence<table::CellRangeAddress>();
+}
+
+void SAL_CALL ScTableSheetObj::setPrintAreas(
+ const uno::Sequence<table::CellRangeAddress>& aPrintAreas )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges;
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ if ( rDoc.IsUndoEnabled() )
+ pOldRanges = rDoc.CreatePrintRangeSaver();
+
+ sal_uInt16 nCount = static_cast<sal_uInt16>(aPrintAreas.getLength());
+ rDoc.ClearPrintRanges( nTab );
+ if (nCount)
+ {
+ ScRange aPrintRange;
+ for (const table::CellRangeAddress& rPrintArea : aPrintAreas)
+ {
+ ScUnoConversion::FillScRange( aPrintRange, rPrintArea );
+ rDoc.AddPrintRange( nTab, aPrintRange );
+ }
+ }
+
+ if ( rDoc.IsUndoEnabled() )
+ PrintAreaUndo_Impl( std::move(pOldRanges) ); // Undo, Page Breaks, Modified etc.
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::getPrintTitleColumns()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ return rDoc.GetRepeatColRange(nTab).has_value();
+ }
+ return false;
+}
+
+void SAL_CALL ScTableSheetObj::setPrintTitleColumns( sal_Bool bPrintTitleColumns )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges = rDoc.CreatePrintRangeSaver();
+
+ if ( bPrintTitleColumns )
+ {
+ if ( !rDoc.GetRepeatColRange( nTab ) ) // do not change existing area
+ {
+ rDoc.SetRepeatColRange( nTab, ScRange( 0, 0, nTab, 0, 0, nTab ) ); // enable
+ }
+ }
+ else
+ rDoc.SetRepeatColRange( nTab, std::nullopt ); // disable
+
+ PrintAreaUndo_Impl( std::move(pOldRanges) ); // undo, page break, modified etc.
+
+ //! save last set area during switch off and recreate during switch on ???
+}
+
+table::CellRangeAddress SAL_CALL ScTableSheetObj::getTitleColumns()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ std::optional<ScRange> oRange = rDoc.GetRepeatColRange(nTab);
+ if (oRange)
+ {
+ ScUnoConversion::FillApiRange( aRet, *oRange );
+ aRet.Sheet = nTab; // core does not care about sheet index
+ }
+ }
+ return aRet;
+}
+
+void SAL_CALL ScTableSheetObj::setTitleColumns( const table::CellRangeAddress& aTitleColumns )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges = rDoc.CreatePrintRangeSaver();
+
+ ScRange aNew;
+ ScUnoConversion::FillScRange( aNew, aTitleColumns );
+ rDoc.SetRepeatColRange( nTab, std::move(aNew) ); // also always enable
+
+ PrintAreaUndo_Impl( std::move(pOldRanges) ); // undo, page breaks, modified etc.
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::getPrintTitleRows()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ return rDoc.GetRepeatRowRange(nTab).has_value();
+ }
+ return false;
+}
+
+void SAL_CALL ScTableSheetObj::setPrintTitleRows( sal_Bool bPrintTitleRows )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges = rDoc.CreatePrintRangeSaver();
+
+ if ( bPrintTitleRows )
+ {
+ if ( !rDoc.GetRepeatRowRange( nTab ) ) // do not change existing area
+ {
+ rDoc.SetRepeatRowRange( nTab, ScRange(0, 0, nTab, 0, 0, nTab) ); // enable
+ }
+ }
+ else
+ rDoc.SetRepeatRowRange( nTab, std::nullopt ); // disable
+
+ PrintAreaUndo_Impl( std::move(pOldRanges) ); // undo, page breaks, modified etc.
+
+ //! save last set area during switch off and recreate during switch on ???
+}
+
+table::CellRangeAddress SAL_CALL ScTableSheetObj::getTitleRows()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ std::optional<ScRange> oRange = rDoc.GetRepeatRowRange(nTab);
+ if (oRange)
+ {
+ ScUnoConversion::FillApiRange( aRet, *oRange );
+ aRet.Sheet = nTab; // core does not care about sheet index
+ }
+ }
+ return aRet;
+}
+
+void SAL_CALL ScTableSheetObj::setTitleRows( const table::CellRangeAddress& aTitleRows )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges = rDoc.CreatePrintRangeSaver();
+
+ ScRange aNew;
+ ScUnoConversion::FillScRange( aNew, aTitleRows );
+ rDoc.SetRepeatRowRange( nTab, std::move(aNew) ); // also always enable
+
+ PrintAreaUndo_Impl( std::move(pOldRanges) ); // Undo, page breaks, modified etc.
+}
+
+// XSheetLinkable
+
+sheet::SheetLinkMode SAL_CALL ScTableSheetObj::getLinkMode()
+{
+ SolarMutexGuard aGuard;
+ sheet::SheetLinkMode eRet = sheet::SheetLinkMode_NONE;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScLinkMode nMode = pDocSh->GetDocument().GetLinkMode( GetTab_Impl() );
+ if ( nMode == ScLinkMode::NORMAL )
+ eRet = sheet::SheetLinkMode_NORMAL;
+ else if ( nMode == ScLinkMode::VALUE )
+ eRet = sheet::SheetLinkMode_VALUE;
+ }
+ return eRet;
+}
+
+void SAL_CALL ScTableSheetObj::setLinkMode( sheet::SheetLinkMode nLinkMode )
+{
+ SolarMutexGuard aGuard;
+
+ //! search for filter and options in old link
+
+ OUString aUrl(getLinkUrl());
+ OUString aSheet(getLinkSheetName());
+
+ link( aUrl, aSheet, "", "", nLinkMode );
+}
+
+OUString SAL_CALL ScTableSheetObj::getLinkUrl()
+{
+ SolarMutexGuard aGuard;
+ OUString aFile;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ aFile = pDocSh->GetDocument().GetLinkDoc( GetTab_Impl() );
+ return aFile;
+}
+
+void SAL_CALL ScTableSheetObj::setLinkUrl( const OUString& aLinkUrl )
+{
+ SolarMutexGuard aGuard;
+
+ //! search for filter and options in old link
+
+ sheet::SheetLinkMode eMode = getLinkMode();
+ OUString aSheet(getLinkSheetName());
+
+ link( aLinkUrl, aSheet, "", "", eMode );
+}
+
+OUString SAL_CALL ScTableSheetObj::getLinkSheetName()
+{
+ SolarMutexGuard aGuard;
+ OUString aSheet;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ aSheet = pDocSh->GetDocument().GetLinkTab( GetTab_Impl() );
+ return aSheet;
+}
+
+void SAL_CALL ScTableSheetObj::setLinkSheetName( const OUString& aLinkSheetName )
+{
+ SolarMutexGuard aGuard;
+
+ //! search for filter and options in old link
+
+ sheet::SheetLinkMode eMode = getLinkMode();
+ OUString aUrl(getLinkUrl());
+
+ link( aUrl, aLinkSheetName, "", "", eMode );
+}
+
+void SAL_CALL ScTableSheetObj::link( const OUString& aUrl, const OUString& aSheetName,
+ const OUString& aFilterName, const OUString& aFilterOptions,
+ sheet::SheetLinkMode nMode )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ OUString aFileString = aUrl;
+ OUString aFilterString = aFilterName;
+ OUString aOptString = aFilterOptions;
+
+ aFileString = ScGlobal::GetAbsDocName( aFileString, pDocSh );
+ if (aFilterString.isEmpty())
+ ScDocumentLoader::GetFilterName( aFileString, aFilterString, aOptString, true, false );
+
+ // remove application prefix from filter name here, so the filter options
+ // aren't reset when the filter name is changed in ScTableLink::DataChanged
+ ScDocumentLoader::RemoveAppPrefix( aFilterString );
+
+ ScLinkMode nLinkMode = ScLinkMode::NONE;
+ if ( nMode == sheet::SheetLinkMode_NORMAL )
+ nLinkMode = ScLinkMode::NORMAL;
+ else if ( nMode == sheet::SheetLinkMode_VALUE )
+ nLinkMode = ScLinkMode::VALUE;
+
+ rDoc.SetLink( nTab, nLinkMode, aFileString, aFilterString, aOptString, aSheetName, 0/*nRefresh*/ );
+
+ pDocSh->UpdateLinks(); // if needed add or delete link
+ SfxBindings* pBindings = pDocSh->GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate(SID_LINKS);
+
+ //! undo of link data on the table
+
+ if ( !(nLinkMode != ScLinkMode::NONE && rDoc.IsExecuteLinkEnabled()) ) // update link
+ return;
+
+ // Always update link also if already exists
+ //! update only on the affected table???
+
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+ sal_uInt16 nCount = pLinkManager->GetLinks().size();
+ for ( sal_uInt16 i=0; i<nCount; i++ )
+ {
+ ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
+ if (auto pTabLink = dynamic_cast<ScTableLink*>( pBase))
+ {
+ if ( aFileString == pTabLink->GetFileName() )
+ pTabLink->Update(); // include Paint&Undo
+
+ //! The file name should only exists once (?)
+ }
+ }
+
+ //! notify ScSheetLinkObj objects!!!
+}
+
+// XSheetAuditing
+
+sal_Bool SAL_CALL ScTableSheetObj::hideDependents( const table::CellAddress& aPosition )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ OSL_ENSURE( aPosition.Sheet == nTab, "wrong table in CellAddress" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ return pDocSh->GetDocFunc().DetectiveDelSucc( aPos );
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::hidePrecedents( const table::CellAddress& aPosition )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ OSL_ENSURE( aPosition.Sheet == nTab, "wrong table in CellAddress" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ return pDocSh->GetDocFunc().DetectiveDelPred( aPos );
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::showDependents( const table::CellAddress& aPosition )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ OSL_ENSURE( aPosition.Sheet == nTab, "wrong table in CellAddress" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ return pDocSh->GetDocFunc().DetectiveAddSucc( aPos );
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::showPrecedents( const table::CellAddress& aPosition )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ OSL_ENSURE( aPosition.Sheet == nTab, "wrong table in CellAddress" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ return pDocSh->GetDocFunc().DetectiveAddPred( aPos );
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::showErrors( const table::CellAddress& aPosition )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ OSL_ENSURE( aPosition.Sheet == nTab, "wrong table in CellAddress" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ return pDocSh->GetDocFunc().DetectiveAddError( aPos );
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::showInvalid()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return pDocSh->GetDocFunc().DetectiveMarkInvalid( GetTab_Impl() );
+ return false;
+}
+
+void SAL_CALL ScTableSheetObj::clearArrows()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ pDocSh->GetDocFunc().DetectiveDelAll( GetTab_Impl() );
+}
+
+// XSheetOutline
+
+void SAL_CALL ScTableSheetObj::group( const table::CellRangeAddress& rGroupRange,
+ table::TableOrientation nOrientation )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ bool bColumns = ( nOrientation == table::TableOrientation_COLUMNS );
+ ScRange aGroupRange;
+ ScUnoConversion::FillScRange( aGroupRange, rGroupRange );
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.MakeOutline( aGroupRange, bColumns, true, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::ungroup( const table::CellRangeAddress& rGroupRange,
+ table::TableOrientation nOrientation )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ bool bColumns = ( nOrientation == table::TableOrientation_COLUMNS );
+ ScRange aGroupRange;
+ ScUnoConversion::FillScRange( aGroupRange, rGroupRange );
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.RemoveOutline( aGroupRange, bColumns, true, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::autoOutline( const table::CellRangeAddress& rCellRange )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScRange aFormulaRange;
+ ScUnoConversion::FillScRange( aFormulaRange, rCellRange );
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.AutoOutline( aFormulaRange, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::clearOutline()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ SCTAB nTab = GetTab_Impl();
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.RemoveAllOutlines( nTab, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::hideDetail( const table::CellRangeAddress& rCellRange )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScRange aMarkRange;
+ ScUnoConversion::FillScRange( aMarkRange, rCellRange );
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.HideMarkedOutlines( aMarkRange, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::showDetail( const table::CellRangeAddress& rCellRange )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScRange aMarkRange;
+ ScUnoConversion::FillScRange( aMarkRange, rCellRange );
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.ShowMarkedOutlines( aMarkRange, true );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::showLevel( sal_Int16 nLevel, table::TableOrientation nOrientation )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ bool bColumns = ( nOrientation == table::TableOrientation_COLUMNS );
+ SCTAB nTab = GetTab_Impl();
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.SelectLevel( nTab, bColumns, nLevel, true, true );
+ }
+}
+
+// XProtectable
+
+void SAL_CALL ScTableSheetObj::protect( const OUString& aPassword )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ // #i108245# if already protected, don't change anything
+ if ( pDocSh && !pDocSh->GetDocument().IsTabProtected( GetTab_Impl() ) )
+ {
+ pDocSh->GetDocFunc().Protect( GetTab_Impl(), aPassword );
+ }
+}
+
+void SAL_CALL ScTableSheetObj::unprotect( const OUString& aPassword )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ bool bDone = pDocSh->GetDocFunc().Unprotect( GetTab_Impl(), aPassword, true );
+ if (!bDone)
+ throw lang::IllegalArgumentException();
+ }
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::isProtected()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return pDocSh->GetDocument().IsTabProtected( GetTab_Impl() );
+
+ OSL_FAIL("no DocShell"); //! Exception or so?
+ return false;
+}
+
+// XScenario
+
+sal_Bool SAL_CALL ScTableSheetObj::getIsScenario()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return pDocSh->GetDocument().IsScenario( GetTab_Impl() );
+
+ return false;
+}
+
+OUString SAL_CALL ScTableSheetObj::getScenarioComment()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ pDocSh->GetDocument().GetScenarioData( GetTab_Impl(), aComment, aColor, nFlags );
+ return aComment;
+ }
+ return OUString();
+}
+
+void SAL_CALL ScTableSheetObj::setScenarioComment( const OUString& aScenarioComment )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+
+ aComment = aScenarioComment;
+
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+}
+
+void SAL_CALL ScTableSheetObj::addRanges( const uno::Sequence<table::CellRangeAddress>& rScenRanges )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ if (!rDoc.IsScenario(nTab))
+ return;
+
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+ aMarkData.SelectTable( nTab, true );
+
+ for (const table::CellRangeAddress& rRange : rScenRanges)
+ {
+ OSL_ENSURE( rRange.Sheet == nTab, "addRanges with wrong Tab" );
+ ScRange aOneRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), nTab,
+ static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), nTab );
+
+ aMarkData.SetMultiMarkArea( aOneRange );
+ }
+
+ // Scenario ranges are tagged with attribute
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( ScMergeFlagAttr( ScMF::Scenario ) );
+ aPattern.GetItemSet().Put( ScProtectionAttr( true ) );
+ pDocSh->GetDocFunc().ApplyAttributes( aMarkData, aPattern, true );
+}
+
+void SAL_CALL ScTableSheetObj::apply()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ OUString aName;
+ rDoc.GetName( nTab, aName ); // scenario name
+
+ SCTAB nDestTab = nTab;
+ while ( nDestTab > 0 && rDoc.IsScenario(nDestTab) )
+ --nDestTab;
+
+ if ( !rDoc.IsScenario(nDestTab) )
+ pDocSh->UseScenario( nDestTab, aName );
+
+ //! otherwise error or so
+}
+
+// XScenarioEnhanced
+
+uno::Sequence< table::CellRangeAddress > SAL_CALL ScTableSheetObj::getRanges( )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ const ScRangeList* pRangeList = rDoc.GetScenarioRanges(nTab);
+ if (pRangeList)
+ {
+ size_t nCount = pRangeList->size();
+ uno::Sequence< table::CellRangeAddress > aRetRanges( nCount );
+ table::CellRangeAddress* pAry = aRetRanges.getArray();
+ for( size_t nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ const ScRange & rRange = (*pRangeList)[nIndex];
+ pAry->StartColumn = rRange.aStart.Col();
+ pAry->StartRow = rRange.aStart.Row();
+ pAry->EndColumn = rRange.aEnd.Col();
+ pAry->EndRow = rRange.aEnd.Row();
+ pAry->Sheet = rRange.aStart.Tab();
+ ++pAry;
+ }
+ return aRetRanges;
+ }
+ }
+ return uno::Sequence< table::CellRangeAddress > ();
+}
+
+// XExternalSheetName
+
+void ScTableSheetObj::setExternalName( const OUString& aUrl, const OUString& aSheetName )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const SCTAB nTab = GetTab_Impl();
+ const OUString aAbsDocName( ScGlobal::GetAbsDocName( aUrl, pDocSh ) );
+ const OUString aDocTabName( ScGlobal::GetDocTabName( aAbsDocName, aSheetName ) );
+ if ( !rDoc.RenameTab( nTab, aDocTabName, true /*bExternalDocument*/ ) )
+ {
+ throw container::ElementExistException( OUString(), *this );
+ }
+ }
+}
+
+// XEventsSupplier
+
+uno::Reference<container::XNameReplace> SAL_CALL ScTableSheetObj::getEvents()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ return new ScSheetEventsObj( pDocSh, GetTab_Impl() );
+
+ return nullptr;
+}
+
+// XPropertySet extended for Sheet-Properties
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableSheetObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pSheetPropSet->getPropertyMap() ));
+ return aRef;
+}
+
+void ScTableSheetObj::SetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue )
+{
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ // for Item WIDs, call ScCellRangesBase directly
+ ScCellRangesBase::SetOnePropertyValue(pEntry, aValue);
+ return;
+ }
+
+ // own properties
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return; //! Exception or so?
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+
+ if ( pEntry->nWID == SC_WID_UNO_PAGESTL )
+ {
+ OUString aStrVal;
+ aValue >>= aStrVal;
+ OUString aNewStr(ScStyleNameConversion::ProgrammaticToDisplayName(
+ aStrVal, SfxStyleFamily::Page ));
+
+ //! Undo? (also if SID_STYLE_APPLY on View)
+
+ if ( rDoc.GetPageStyle( nTab ) != aNewStr )
+ {
+ rDoc.SetPageStyle( nTab, aNewStr );
+ if (!rDoc.IsImportingXML())
+ {
+ ScPrintFunc( pDocSh, pDocSh->GetPrinter(), nTab ).UpdatePages();
+
+ SfxBindings* pBindings = pDocSh->GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( SID_STYLE_FAMILY4 );
+ pBindings->Invalidate( SID_STATUS_PAGESTYLE );
+ pBindings->Invalidate( FID_RESET_PRINTZOOM );
+ pBindings->Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ pBindings->Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT );
+ }
+ }
+ pDocSh->SetDocumentModified();
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLVIS )
+ {
+ bool bVis = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ rFunc.SetTableVisible( nTab, bVis, true );
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_ISACTIVE )
+ {
+ if (rDoc.IsScenario(nTab))
+ rDoc.SetActiveScenario( nTab, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_BORDCOL )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ Color aColor;
+ if (aValue >>= aColor)
+ {
+ OUString aName;
+ OUString aComment;
+ ScScenarioFlags nFlags;
+ Color aTmp;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aTmp, nFlags );
+
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_PROTECT )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (!(nFlags & ScScenarioFlags::Protected))
+ {
+ nFlags |= ScScenarioFlags::Protected;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (nFlags & ScScenarioFlags::Protected)
+ {
+ nFlags &= ~ScScenarioFlags::Protected;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_SHOWBORD )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (!(nFlags & ScScenarioFlags::ShowFrame))
+ {
+ nFlags |= ScScenarioFlags::ShowFrame;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (nFlags & ScScenarioFlags::ShowFrame)
+ {
+ nFlags &= ~ScScenarioFlags::ShowFrame;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_PRINTBORD )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (!(nFlags & ScScenarioFlags::PrintFrame))
+ {
+ nFlags |= ScScenarioFlags::PrintFrame;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (nFlags & ScScenarioFlags::PrintFrame)
+ {
+ nFlags &= ~ScScenarioFlags::PrintFrame;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYBACK )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (!(nFlags & ScScenarioFlags::TwoWay))
+ {
+ nFlags |= ScScenarioFlags::TwoWay;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (nFlags & ScScenarioFlags::TwoWay)
+ {
+ nFlags &= ~ScScenarioFlags::TwoWay;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYSTYL )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (!(nFlags & ScScenarioFlags::Attrib))
+ {
+ nFlags |= ScScenarioFlags::Attrib;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (nFlags & ScScenarioFlags::Attrib)
+ {
+ nFlags &= ~ScScenarioFlags::Attrib;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYFORM )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aName;
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetName( nTab, aName );
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+ bool bModify(false);
+
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ if (nFlags & ScScenarioFlags::Value)
+ {
+ nFlags &= ~ScScenarioFlags::Value;
+ bModify = true;
+ }
+ }
+ else
+ {
+ if (!(nFlags & ScScenarioFlags::Value))
+ {
+ nFlags |= ScScenarioFlags::Value;
+ bModify = true;
+ }
+ }
+
+ if (bModify)
+ pDocSh->ModifyScenario( nTab, aName, aComment, aColor, nFlags );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_TABLAYOUT )
+ {
+ sal_Int16 nValue = 0;
+ if (aValue >>= nValue)
+ {
+ if (nValue == css::text::WritingMode2::RL_TB)
+ rFunc.SetLayoutRTL(nTab, true);
+ else
+ rFunc.SetLayoutRTL(nTab, false);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_AUTOPRINT )
+ {
+ bool bAutoPrint = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bAutoPrint)
+ rDoc.SetPrintEntireSheet( nTab ); // clears all print ranges
+ else
+ {
+ if (rDoc.IsPrintEntireSheet( nTab ))
+ rDoc.ClearPrintRanges( nTab ); // if this flag is true, there are no PrintRanges, so Clear clears only the flag.
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_TABCOLOR )
+ {
+ Color aColor = COL_AUTO;
+ if ( aValue >>= aColor )
+ {
+ if ( rDoc.GetTabBgColor( nTab ) != aColor )
+ rFunc.SetTabBgColor( nTab, aColor, true, true );
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CODENAME )
+ {
+ OUString aCodeName;
+ if (aValue >>= aCodeName)
+ {
+ pDocSh->GetDocument().SetCodeName( GetTab_Impl(), aCodeName );
+ }
+ }
+ else if (pEntry->nWID == SC_WID_UNO_CONDFORMAT)
+ {
+ uno::Reference<sheet::XConditionalFormats> xCondFormat;
+ if (aValue >>= xCondFormat)
+ {
+ // how to set the format correctly
+ }
+ }
+ else
+ ScCellRangeObj::SetOnePropertyValue(pEntry, aValue); // base class, no Item WID
+}
+
+void ScTableSheetObj::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry,
+ uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ throw uno::RuntimeException();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetTab_Impl();
+
+ if ( pEntry->nWID == SC_WID_UNO_NAMES )
+ {
+ rAny <<= uno::Reference<sheet::XNamedRanges>(new ScLocalNamedRangesObj(pDocSh, this));
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_PAGESTL )
+ {
+ rAny <<= ScStyleNameConversion::DisplayToProgrammaticName(
+ rDoc.GetPageStyle( nTab ), SfxStyleFamily::Page );
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLVIS )
+ {
+ bool bVis = rDoc.IsVisible( nTab );
+ rAny <<= bVis;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_LINKDISPBIT )
+ {
+ // no target bitmaps for individual entries (would be all equal)
+ // ScLinkTargetTypeObj::SetLinkTargetBitmap( aAny, SC_LINKTARGETTYPE_SHEET );
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_LINKDISPNAME )
+ {
+ // LinkDisplayName for hyperlink dialog
+ rAny <<= getName(); // sheet name
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_ISACTIVE )
+ {
+ if (rDoc.IsScenario(nTab))
+ rAny <<= rDoc.IsActiveScenario( nTab );
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_BORDCOL )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioData( nTab, aComment, aColor, nFlags );
+
+ rAny <<= aColor;
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_PROTECT )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= ((nFlags & ScScenarioFlags::Protected) != ScScenarioFlags::NONE);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_SHOWBORD )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= ((nFlags & ScScenarioFlags::ShowFrame) != ScScenarioFlags::NONE);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_PRINTBORD )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= ((nFlags & ScScenarioFlags::PrintFrame) != ScScenarioFlags::NONE);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYBACK )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= ((nFlags & ScScenarioFlags::TwoWay) != ScScenarioFlags::NONE);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYSTYL )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= ((nFlags & ScScenarioFlags::Attrib) != ScScenarioFlags::NONE);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_COPYFORM )
+ {
+ if (rDoc.IsScenario(nTab))
+ {
+ ScScenarioFlags nFlags;
+ rDoc.GetScenarioFlags(nTab, nFlags);
+
+ rAny <<= !(nFlags & ScScenarioFlags::Value);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_TABLAYOUT )
+ {
+ if (rDoc.IsLayoutRTL(nTab))
+ rAny <<= sal_Int16(css::text::WritingMode2::RL_TB);
+ else
+ rAny <<= sal_Int16(css::text::WritingMode2::LR_TB);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_AUTOPRINT )
+ {
+ bool bAutoPrint = rDoc.IsPrintEntireSheet( nTab );
+ rAny <<= bAutoPrint;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_TABCOLOR )
+ {
+ rAny <<= rDoc.GetTabBgColor(nTab);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CODENAME )
+ {
+ OUString aCodeName;
+ pDocSh->GetDocument().GetCodeName(GetTab_Impl(), aCodeName);
+ rAny <<= aCodeName;
+ }
+ else if (pEntry->nWID == SC_WID_UNO_CONDFORMAT)
+ {
+ rAny <<= uno::Reference<sheet::XConditionalFormats>(new ScCondFormatsObj(pDocSh, nTab));
+ }
+ else
+ ScCellRangeObj::GetOnePropertyValue(pEntry, rAny);
+}
+
+const SfxItemPropertyMap& ScTableSheetObj::GetItemPropertyMap()
+{
+ return pSheetPropSet->getPropertyMap();
+}
+
+// XServiceInfo
+
+OUString SAL_CALL ScTableSheetObj::getImplementationName()
+{
+ return "ScTableSheetObj";
+}
+
+sal_Bool SAL_CALL ScTableSheetObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScTableSheetObj::getSupportedServiceNames()
+{
+ return {SCSPREADSHEET_SERVICE,
+ SCSHEETCELLRANGE_SERVICE,
+ SCCELLRANGE_SERVICE,
+ SCCELLPROPERTIES_SERVICE,
+ SCCHARPROPERTIES_SERVICE,
+ SCPARAPROPERTIES_SERVICE,
+ SCLINKTARGET_SERVICE};
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION2_IMPL(ScTableSheetObj, ScCellRangeObj);
+
+ScTableColumnObj::ScTableColumnObj( ScDocShell* pDocSh, SCCOL nCol, SCTAB nTab ) :
+ ScCellRangeObj( pDocSh, ScRange(nCol,0,nTab, nCol, pDocSh->GetDocument().MaxRow(),nTab) ),
+ pColPropSet(lcl_GetColumnPropertySet())
+{
+}
+
+ScTableColumnObj::~ScTableColumnObj()
+{
+}
+
+uno::Any SAL_CALL ScTableColumnObj::queryInterface( const uno::Type& rType )
+{
+ SC_QUERYINTERFACE( container::XNamed )
+
+ return ScCellRangeObj::queryInterface( rType );
+}
+
+void SAL_CALL ScTableColumnObj::acquire() noexcept
+{
+ ScCellRangeObj::acquire();
+}
+
+void SAL_CALL ScTableColumnObj::release() noexcept
+{
+ ScCellRangeObj::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScTableColumnObj::getTypes()
+{
+ return comphelper::concatSequences(
+ ScCellRangeObj::getTypes(),
+ uno::Sequence<uno::Type> { cppu::UnoType<container::XNamed>::get() } );
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScTableColumnObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XNamed
+
+OUString SAL_CALL ScTableColumnObj::getName()
+{
+ SolarMutexGuard aGuard;
+
+ const ScRange& rRange = GetRange();
+ OSL_ENSURE(rRange.aStart.Col() == rRange.aEnd.Col(), "too many columns");
+ SCCOL nCol = rRange.aStart.Col();
+
+ return ScColToAlpha( nCol ); // from global.hxx
+}
+
+void SAL_CALL ScTableColumnObj::setName( const OUString& /* aNewName */ )
+{
+ throw uno::RuntimeException(); // read-only
+}
+
+// XPropertySet extended for Column-Properties
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableColumnObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pColPropSet->getPropertyMap() ));
+ return aRef;
+}
+
+void ScTableColumnObj::SetOnePropertyValue(const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue)
+{
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ // for Item WIDs, call ScCellRangesBase directly
+ ScCellRangesBase::SetOnePropertyValue(pEntry, aValue);
+ return;
+ }
+
+ // own properties
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return; //! Exception or so?
+ const ScRange& rRange = GetRange();
+ OSL_ENSURE(rRange.aStart.Col() == rRange.aEnd.Col(), "Too many columns");
+ SCCOL nCol = rRange.aStart.Col();
+ SCTAB nTab = rRange.aStart.Tab();
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+
+ std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(nCol,nCol));
+
+ if ( pEntry->nWID == SC_WID_UNO_CELLWID )
+ {
+ sal_Int32 nNewWidth = 0;
+ if ( aValue >>= nNewWidth )
+ {
+ // property is 1/100mm, column width is twips
+ nNewWidth = o3tl::toTwips(nNewWidth, o3tl::Length::mm100);
+ rFunc.SetWidthOrHeight(
+ true, aColArr, nTab, SC_SIZE_ORIGINAL, nNewWidth, true, true);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLVIS )
+ {
+ bool bVis = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ ScSizeMode eMode = bVis ? SC_SIZE_SHOW : SC_SIZE_DIRECT;
+ rFunc.SetWidthOrHeight(true, aColArr, nTab, eMode, 0, true, true);
+ // SC_SIZE_DIRECT with size 0 will hide
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_OWIDTH )
+ {
+ bool bOpt = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bOpt)
+ rFunc.SetWidthOrHeight(
+ true, aColArr, nTab, SC_SIZE_OPTIMAL, STD_EXTRA_WIDTH, true, true);
+ // sal_False on columns currently without effect
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_NEWPAGE || pEntry->nWID == SC_WID_UNO_MANPAGE )
+ {
+ bool bSet = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bSet)
+ rFunc.InsertPageBreak( true, rRange.aStart, true, true );
+ else
+ rFunc.RemovePageBreak( true, rRange.aStart, true, true );
+ }
+ else
+ ScCellRangeObj::SetOnePropertyValue(pEntry, aValue); // base class, no Item WID
+}
+
+void ScTableColumnObj::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const ScRange& rRange = GetRange();
+ OSL_ENSURE(rRange.aStart.Col() == rRange.aEnd.Col(), "too many columns");
+ SCCOL nCol = rRange.aStart.Col();
+ SCTAB nTab = rRange.aStart.Tab();
+
+ if ( pEntry->nWID == SC_WID_UNO_CELLWID )
+ {
+ // for hidden column, return original height
+ sal_uInt16 nWidth = rDoc.GetOriginalWidth( nCol, nTab );
+ // property is 1/100mm, column width is twips
+ nWidth = static_cast<sal_uInt16>(convertTwipToMm100(nWidth));
+ rAny <<= static_cast<sal_Int32>(nWidth);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLVIS )
+ {
+ bool bHidden = rDoc.ColHidden(nCol, nTab);
+ rAny <<= !bHidden;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_OWIDTH )
+ {
+ //! at the moment always set ??!?!
+ bool bOpt = !(rDoc.GetColFlags( nCol, nTab ) & CRFlags::ManualSize);
+ rAny <<= bOpt;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_NEWPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasColBreak(nCol, nTab);
+ rAny <<= nBreak != ScBreakType::NONE;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_MANPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasColBreak(nCol, nTab);
+ rAny <<= bool(nBreak & ScBreakType::Manual);
+ }
+ else
+ ScCellRangeObj::GetOnePropertyValue(pEntry, rAny);
+}
+
+const SfxItemPropertyMap& ScTableColumnObj::GetItemPropertyMap()
+{
+ return pColPropSet->getPropertyMap();
+}
+
+ScTableRowObj::ScTableRowObj(ScDocShell* pDocSh, SCROW nRow, SCTAB nTab) :
+ ScCellRangeObj( pDocSh, ScRange(0,nRow,nTab, pDocSh->GetDocument().MaxCol(),nRow,nTab) ),
+ pRowPropSet(lcl_GetRowPropertySet())
+{
+}
+
+ScTableRowObj::~ScTableRowObj()
+{
+}
+
+// XPropertySet extended for Row-Properties
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableRowObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( pRowPropSet->getPropertyMap() ));
+ return aRef;
+}
+
+void ScTableRowObj::SetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, const uno::Any& aValue )
+{
+ if ( !pEntry )
+ return;
+
+ if ( IsScItemWid( pEntry->nWID ) )
+ {
+ // for Item WIDs, call ScCellRangesBase directly
+ ScCellRangesBase::SetOnePropertyValue(pEntry, aValue);
+ return;
+ }
+
+ // own properties
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ return; //! Exception or so?
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const ScRange& rRange = GetRange();
+ OSL_ENSURE(rRange.aStart.Row() == rRange.aEnd.Row(), "too many rows");
+ SCROW nRow = rRange.aStart.Row();
+ SCTAB nTab = rRange.aStart.Tab();
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+
+ std::vector<sc::ColRowSpan> aRowArr(1, sc::ColRowSpan(nRow,nRow));
+
+ if ( pEntry->nWID == SC_WID_UNO_CELLHGT )
+ {
+ sal_Int32 nNewHeight = 0;
+ if ( aValue >>= nNewHeight )
+ {
+ // property is 1/100mm, row height is twips
+ nNewHeight = o3tl::toTwips(nNewHeight, o3tl::Length::mm100);
+ rFunc.SetWidthOrHeight(
+ false, aRowArr, nTab, SC_SIZE_ORIGINAL, nNewHeight, true, true);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLVIS )
+ {
+ bool bVis = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ ScSizeMode eMode = bVis ? SC_SIZE_SHOW : SC_SIZE_DIRECT;
+ rFunc.SetWidthOrHeight(false, aRowArr, nTab, eMode, 0, true, true);
+ // SC_SIZE_DIRECT with size zero will hide
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLFILT )
+ {
+ bool bFil = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ // SC_SIZE_DIRECT with size zero will hide
+ rDoc.SetRowFiltered(nRow, nRow, nTab, bFil);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_OHEIGHT )
+ {
+ bool bOpt = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bOpt)
+ rFunc.SetWidthOrHeight(false, aRowArr, nTab, SC_SIZE_OPTIMAL, 0, true, true);
+ else
+ {
+ // set current height again manually
+ sal_uInt16 nHeight = rDoc.GetOriginalHeight( nRow, nTab );
+ rFunc.SetWidthOrHeight(false, aRowArr, nTab, SC_SIZE_ORIGINAL, nHeight, true, true);
+ }
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_NEWPAGE || pEntry->nWID == SC_WID_UNO_MANPAGE )
+ {
+ bool bSet = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bSet)
+ rFunc.InsertPageBreak( false, rRange.aStart, true, true );
+ else
+ rFunc.RemovePageBreak( false, rRange.aStart, true, true );
+ }
+ else
+ ScCellRangeObj::SetOnePropertyValue(pEntry, aValue); // base class, no Item WID
+}
+
+void ScTableRowObj::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntry, uno::Any& rAny )
+{
+ if ( !pEntry )
+ return;
+
+ ScDocShell* pDocSh = GetDocShell();
+ if (!pDocSh)
+ throw uno::RuntimeException();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const ScRange& rRange = GetRange();
+ OSL_ENSURE(rRange.aStart.Row() == rRange.aEnd.Row(), "too many rows");
+ SCROW nRow = rRange.aStart.Row();
+ SCTAB nTab = rRange.aStart.Tab();
+
+ if ( pEntry->nWID == SC_WID_UNO_CELLHGT )
+ {
+ // for hidden row, return original height
+ sal_uInt16 nHeight = rDoc.GetOriginalHeight( nRow, nTab );
+ // property is 1/100mm, row height is twips
+ nHeight = static_cast<sal_uInt16>(convertTwipToMm100(nHeight));
+ rAny <<= static_cast<sal_Int32>(nHeight);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLVIS )
+ {
+ bool bHidden = rDoc.RowHidden(nRow, nTab);
+ rAny <<= !bHidden;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_CELLFILT )
+ {
+ bool bVis = rDoc.RowFiltered(nRow, nTab);
+ rAny <<= bVis;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_OHEIGHT )
+ {
+ bool bOpt = !(rDoc.GetRowFlags( nRow, nTab ) & CRFlags::ManualSize);
+ rAny <<= bOpt;
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_NEWPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasRowBreak(nRow, nTab);
+ rAny <<= (nBreak != ScBreakType::NONE);
+ }
+ else if ( pEntry->nWID == SC_WID_UNO_MANPAGE )
+ {
+ bool bBreak(rDoc.HasRowBreak(nRow, nTab) & ScBreakType::Manual);
+ rAny <<= bBreak;
+ }
+ else
+ ScCellRangeObj::GetOnePropertyValue(pEntry, rAny);
+}
+
+const SfxItemPropertyMap& ScTableRowObj::GetItemPropertyMap()
+{
+ return pRowPropSet->getPropertyMap();
+}
+
+ScCellsObj::ScCellsObj(ScDocShell* pDocSh, const ScRangeList& rR) :
+ pDocShell( pDocSh ),
+ aRanges( rR )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScCellsObj::~ScCellsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScCellsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( auto pRefHint = dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ aRanges.UpdateReference( pRefHint->GetMode(), &pDocShell->GetDocument(), pRefHint->GetRange(),
+ pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() );
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScCellsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScCellsEnumeration( pDocShell, aRanges );
+ return nullptr;
+}
+
+uno::Type SAL_CALL ScCellsObj::getElementType()
+{
+ return cppu::UnoType<table::XCell>::get();
+}
+
+sal_Bool SAL_CALL ScCellsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ bool bHas = false;
+ if ( pDocShell )
+ {
+ //! faster if test ourself?
+
+ uno::Reference<container::XEnumeration> xEnum(new ScCellsEnumeration( pDocShell, aRanges ));
+ bHas = xEnum->hasMoreElements();
+ }
+ return bHas;
+}
+
+ScCellsEnumeration::ScCellsEnumeration(ScDocShell* pDocSh, const ScRangeList& rR) :
+ pDocShell( pDocSh ),
+ aRanges( rR ),
+ bAtEnd( false )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.AddUnoObject(*this);
+
+ if ( aRanges.empty() )
+ bAtEnd = true;
+ else
+ {
+ SCTAB nTab = aRanges[ 0 ].aStart.Tab();
+ aPos = ScAddress(0,0,nTab);
+ CheckPos_Impl(); // set aPos on first matching cell
+ }
+}
+
+void ScCellsEnumeration::CheckPos_Impl()
+{
+ if (!pDocShell)
+ return;
+
+ bool bFound = false;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRefCellValue aCell(rDoc, aPos);
+ if (!aCell.isEmpty())
+ {
+ if (!pMark)
+ {
+ pMark.reset( new ScMarkData(rDoc.GetSheetLimits()) );
+ pMark->MarkFromRangeList(aRanges, false);
+ pMark->MarkToMulti(); // needed for GetNextMarkedCell
+ }
+ bFound = pMark->IsCellMarked(aPos.Col(), aPos.Row());
+ }
+ if (!bFound)
+ Advance_Impl();
+}
+
+ScCellsEnumeration::~ScCellsEnumeration()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+ pMark.reset();
+}
+
+void ScCellsEnumeration::Advance_Impl()
+{
+ OSL_ENSURE(!bAtEnd,"too much Advance_Impl");
+ if (!pMark)
+ {
+ pMark.reset( new ScMarkData(pDocShell->GetDocument().GetSheetLimits()) );
+ pMark->MarkFromRangeList( aRanges, false );
+ pMark->MarkToMulti(); // needed for GetNextMarkedCell
+ }
+
+ SCCOL nCol = aPos.Col();
+ SCROW nRow = aPos.Row();
+ SCTAB nTab = aPos.Tab();
+ bool bFound = pDocShell->GetDocument().GetNextMarkedCell( nCol, nRow, nTab, *pMark );
+ if (bFound)
+ aPos.Set( nCol, nRow, nTab );
+ else
+ bAtEnd = true; // nothing will follow
+}
+
+void ScCellsEnumeration::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const ScUpdateRefHint* pRefHint = dynamic_cast<const ScUpdateRefHint*>(&rHint);
+ if ( pRefHint )
+ {
+ if (pDocShell)
+ {
+ aRanges.UpdateReference( pRefHint->GetMode(), &pDocShell->GetDocument(), pRefHint->GetRange(),
+ pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() );
+
+ pMark.reset(); // recreate from moved area
+
+ if (!bAtEnd) // adjust aPos
+ {
+ ScRangeList aNew { ScRange(aPos) };
+ aNew.UpdateReference( pRefHint->GetMode(), &pDocShell->GetDocument(), pRefHint->GetRange(),
+ pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() );
+ if (aNew.size()==1)
+ {
+ aPos = aNew[ 0 ].aStart;
+ CheckPos_Impl();
+ }
+ }
+ }
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XEnumeration
+
+sal_Bool SAL_CALL ScCellsEnumeration::hasMoreElements()
+{
+ SolarMutexGuard aGuard;
+ return !bAtEnd;
+}
+
+uno::Any SAL_CALL ScCellsEnumeration::nextElement()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell && !bAtEnd)
+ {
+ // interface must match ScCellsObj::getElementType
+
+ ScAddress aTempPos(aPos);
+ Advance_Impl();
+ return uno::Any(uno::Reference<table::XCell>(new ScCellObj( pDocShell, aTempPos )));
+ }
+
+ throw container::NoSuchElementException(); // no more elements
+}
+
+ScCellFormatsObj::ScCellFormatsObj(ScDocShell* pDocSh, const ScRange& rRange) :
+ pDocShell( pDocSh ),
+ aTotalRange( rRange )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.AddUnoObject(*this);
+
+ OSL_ENSURE( aTotalRange.aStart.Tab() == aTotalRange.aEnd.Tab(), "different tables" );
+}
+
+ScCellFormatsObj::~ScCellFormatsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScCellFormatsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! aTotalRange...
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+rtl::Reference<ScCellRangeObj> ScCellFormatsObj::GetObjectByIndex_Impl(tools::Long nIndex) const
+{
+ //! access the AttrArrays directly !!!!
+
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ tools::Long nPos = 0;
+ ScAttrRectIterator aIter( rDoc, aTotalRange.aStart.Tab(),
+ aTotalRange.aStart.Col(), aTotalRange.aStart.Row(),
+ aTotalRange.aEnd.Col(), aTotalRange.aEnd.Row() );
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ while ( aIter.GetNext( nCol1, nCol2, nRow1, nRow2 ) )
+ {
+ if ( nPos == nIndex )
+ {
+ SCTAB nTab = aTotalRange.aStart.Tab();
+ ScRange aNext( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
+
+ if ( aNext.aStart == aNext.aEnd )
+ return new ScCellObj( pDocShell, aNext.aStart );
+ else
+ return new ScCellRangeObj( pDocShell, aNext );
+ }
+ ++nPos;
+ }
+ }
+ return {};
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScCellFormatsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ //! access the AttrArrays directly !!!!
+
+ tools::Long nCount = 0;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScAttrRectIterator aIter( rDoc, aTotalRange.aStart.Tab(),
+ aTotalRange.aStart.Col(), aTotalRange.aStart.Row(),
+ aTotalRange.aEnd.Col(), aTotalRange.aEnd.Row() );
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ while ( aIter.GetNext( nCol1, nCol2, nRow1, nRow2 ) )
+ ++nCount;
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL ScCellFormatsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<table::XCellRange> xRange(GetObjectByIndex_Impl(nIndex));
+ if (!xRange.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRange);
+
+}
+
+uno::Type SAL_CALL ScCellFormatsObj::getElementType()
+{
+ return cppu::UnoType<table::XCellRange>::get();
+}
+
+sal_Bool SAL_CALL ScCellFormatsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 ); //! always greater then zero ??
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScCellFormatsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScCellFormatsEnumeration( pDocShell, aTotalRange );
+ return nullptr;
+}
+
+ScCellFormatsEnumeration::ScCellFormatsEnumeration(ScDocShell* pDocSh, const ScRange& rRange) :
+ pDocShell( pDocSh ),
+ nTab( rRange.aStart.Tab() ),
+ bAtEnd( false ),
+ bDirty( false )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.AddUnoObject(*this);
+
+ OSL_ENSURE( rRange.aStart.Tab() == rRange.aEnd.Tab(),
+ "CellFormatsEnumeration: different tables" );
+
+ pIter.reset( new ScAttrRectIterator( rDoc, nTab,
+ rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row() ) );
+ Advance_Impl();
+}
+
+ScCellFormatsEnumeration::~ScCellFormatsEnumeration()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScCellFormatsEnumeration::Advance_Impl()
+{
+ OSL_ENSURE(!bAtEnd,"too many Advance_Impl");
+
+ if ( pIter )
+ {
+ if ( bDirty )
+ {
+ pIter->DataChanged(); // new search for AttrArray-Index
+ bDirty = false;
+ }
+
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ if ( pIter->GetNext( nCol1, nCol2, nRow1, nRow2 ) )
+ aNext = ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
+ else
+ bAtEnd = true;
+ }
+ else
+ bAtEnd = true; // document vanished or so
+}
+
+rtl::Reference<ScCellRangeObj> ScCellFormatsEnumeration::NextObject_Impl()
+{
+ rtl::Reference<ScCellRangeObj> pRet;
+ if (pDocShell && !bAtEnd)
+ {
+ if ( aNext.aStart == aNext.aEnd )
+ pRet = new ScCellObj( pDocShell, aNext.aStart );
+ else
+ pRet = new ScCellRangeObj( pDocShell, aNext );
+ Advance_Impl();
+ }
+ return pRet;
+}
+
+void ScCellFormatsEnumeration::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! and now???
+ }
+ else
+ {
+ const SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ pIter.reset();
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ bDirty = true; // AttrArray-Index possibly invalid
+ }
+ }
+}
+
+// XEnumeration
+
+sal_Bool SAL_CALL ScCellFormatsEnumeration::hasMoreElements()
+{
+ SolarMutexGuard aGuard;
+ return !bAtEnd;
+}
+
+uno::Any SAL_CALL ScCellFormatsEnumeration::nextElement()
+{
+ SolarMutexGuard aGuard;
+
+ if ( bAtEnd || !pDocShell )
+ throw container::NoSuchElementException(); // no more elements
+
+ // interface must match ScCellFormatsObj::getElementType
+
+ return uno::Any(uno::Reference<table::XCellRange> (NextObject_Impl()));
+}
+
+ScUniqueCellFormatsObj::~ScUniqueCellFormatsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScUniqueCellFormatsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! aTotalRange...
+ }
+ else
+ {
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr;
+ }
+}
+
+// Fill the list of formats from the document
+
+namespace {
+
+// hash code to access the range lists by ScPatternAttr pointer
+struct ScPatternHashCode
+{
+ size_t operator()( const ScPatternAttr* pPattern ) const
+ {
+ return reinterpret_cast<size_t>(pPattern);
+ }
+};
+
+}
+
+// Hash map to find a range by its start row
+typedef std::unordered_map< SCROW, ScRange > ScRowRangeHashMap;
+
+namespace {
+
+// Hash map entry.
+// The Join method depends on the column-wise order of ScAttrRectIterator
+class ScUniqueFormatsEntry
+{
+ enum EntryState { STATE_EMPTY, STATE_SINGLE, STATE_COMPLEX };
+
+ EntryState eState;
+ ScRange aSingleRange;
+ ScRowRangeHashMap aJoinedRanges; // "active" ranges to be merged
+ std::vector<ScRange> aCompletedRanges; // ranges that will no longer be touched
+ ScRangeListRef aReturnRanges; // result as ScRangeList for further use
+
+public:
+ ScUniqueFormatsEntry() : eState( STATE_EMPTY ) {}
+
+ void Join( const ScRange& rNewRange );
+ const ScRangeList& GetRanges();
+ void Clear() { aReturnRanges.clear(); } // aJoinedRanges and aCompletedRanges are cleared in GetRanges
+};
+
+}
+
+void ScUniqueFormatsEntry::Join( const ScRange& rNewRange )
+{
+ // Special-case handling for single range
+
+ if ( eState == STATE_EMPTY )
+ {
+ aSingleRange = rNewRange;
+ eState = STATE_SINGLE;
+ return;
+ }
+ if ( eState == STATE_SINGLE )
+ {
+ if ( aSingleRange.aStart.Row() == rNewRange.aStart.Row() &&
+ aSingleRange.aEnd.Row() == rNewRange.aEnd.Row() &&
+ aSingleRange.aEnd.Col() + 1 == rNewRange.aStart.Col() )
+ {
+ aSingleRange.aEnd.SetCol( rNewRange.aEnd.Col() );
+ return; // still a single range
+ }
+
+ SCROW nSingleRow = aSingleRange.aStart.Row();
+ aJoinedRanges.emplace( nSingleRow, aSingleRange );
+ eState = STATE_COMPLEX;
+ // continue normally
+ }
+
+ // This is called in the order of ScAttrRectIterator results.
+ // rNewRange can only be joined with an existing entry if it's the same rows, starting in the next column.
+ // If the old entry for the start row extends to a different end row, or ends in a different column, it
+ // can be moved to aCompletedRanges because it can't be joined with following iterator results.
+ // Everything happens within one sheet, so Tab can be ignored.
+
+ SCROW nStartRow = rNewRange.aStart.Row();
+ ScRowRangeHashMap::iterator aIter( aJoinedRanges.find( nStartRow ) ); // find the active entry for the start row
+ if ( aIter != aJoinedRanges.end() )
+ {
+ ScRange& rOldRange = aIter->second;
+ if ( rOldRange.aEnd.Row() == rNewRange.aEnd.Row() &&
+ rOldRange.aEnd.Col() + 1 == rNewRange.aStart.Col() )
+ {
+ // extend existing range
+ rOldRange.aEnd.SetCol( rNewRange.aEnd.Col() );
+ }
+ else
+ {
+ // move old range to aCompletedRanges, keep rNewRange for joining
+ aCompletedRanges.push_back( rOldRange );
+ rOldRange = rNewRange; // replace in hash map
+ }
+ }
+ else
+ {
+ // keep rNewRange for joining
+ aJoinedRanges.emplace( nStartRow, rNewRange );
+ }
+}
+
+const ScRangeList& ScUniqueFormatsEntry::GetRanges()
+{
+ if ( eState == STATE_SINGLE )
+ {
+ aReturnRanges = new ScRangeList( aSingleRange );
+ return *aReturnRanges;
+ }
+
+ // move remaining entries from aJoinedRanges to aCompletedRanges
+
+ for ( const auto& rEntry : aJoinedRanges )
+ aCompletedRanges.push_back( rEntry.second );
+ aJoinedRanges.clear();
+
+ // sort all ranges for a predictable API result
+
+ std::sort( aCompletedRanges.begin(), aCompletedRanges.end() );
+
+ // fill and return ScRangeList
+
+ aReturnRanges = new ScRangeList;
+ aReturnRanges->insert( aReturnRanges->end(), aCompletedRanges.begin(), aCompletedRanges.end() );
+ aCompletedRanges.clear();
+
+ return *aReturnRanges;
+}
+
+namespace {
+
+// function object to sort the range lists by start of first range
+struct ScUniqueFormatsOrder
+{
+ bool operator()( const ScRangeList& rList1, const ScRangeList& rList2 ) const
+ {
+ // all range lists have at least one entry
+ OSL_ENSURE( !rList1.empty() && !rList2.empty(), "ScUniqueFormatsOrder: empty list" );
+
+ // compare start positions using ScAddress comparison operator
+ return ( rList1[ 0 ].aStart < rList2[ 0 ].aStart );
+ }
+};
+
+}
+
+ScUniqueCellFormatsObj::ScUniqueCellFormatsObj(ScDocShell* pDocSh, const ScRange& rTotalRange) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ OSL_ENSURE( rTotalRange.aStart.Tab() == rTotalRange.aEnd.Tab(), "different tables" );
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab = rTotalRange.aStart.Tab();
+ ScAttrRectIterator aIter( rDoc, nTab,
+ rTotalRange.aStart.Col(), rTotalRange.aStart.Row(),
+ rTotalRange.aEnd.Col(), rTotalRange.aEnd.Row() );
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+
+ // Collect the ranges for each format in a hash map, to avoid nested loops
+
+ std::unordered_map< const ScPatternAttr*, ScUniqueFormatsEntry, ScPatternHashCode > aHashMap;
+ while (aIter.GetNext( nCol1, nCol2, nRow1, nRow2 ) )
+ {
+ ScRange aRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
+ const ScPatternAttr* pPattern = rDoc.GetPattern(nCol1, nRow1, nTab);
+ aHashMap[pPattern].Join( aRange );
+ }
+
+ // Fill the vector aRangeLists with the range lists from the hash map
+
+ aRangeLists.reserve( aHashMap.size() );
+ for ( auto& rMapEntry : aHashMap )
+ {
+ ScUniqueFormatsEntry& rEntry = rMapEntry.second;
+ const ScRangeList& rRanges = rEntry.GetRanges();
+ aRangeLists.push_back( rRanges ); // copy ScRangeList
+ rEntry.Clear(); // free memory, don't hold both copies of all ranges
+ }
+
+ // Sort the vector by first range's start position, to avoid random shuffling
+ // due to using the ScPatterAttr pointers
+
+ ::std::sort( aRangeLists.begin(), aRangeLists.end(), ScUniqueFormatsOrder() );
+}
+
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScUniqueCellFormatsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ return aRangeLists.size();
+}
+
+uno::Any SAL_CALL ScUniqueCellFormatsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+
+ if(o3tl::make_unsigned(nIndex) >= aRangeLists.size())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(uno::Reference<sheet::XSheetCellRangeContainer>(new ScCellRangesObj(pDocShell, aRangeLists[nIndex])));
+
+}
+
+uno::Type SAL_CALL ScUniqueCellFormatsObj::getElementType()
+{
+ return cppu::UnoType<sheet::XSheetCellRangeContainer>::get();
+}
+
+sal_Bool SAL_CALL ScUniqueCellFormatsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( !aRangeLists.empty() );
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScUniqueCellFormatsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScUniqueCellFormatsEnumeration( pDocShell, std::vector(aRangeLists) );
+ return nullptr;
+}
+
+ScUniqueCellFormatsEnumeration::ScUniqueCellFormatsEnumeration(ScDocShell* pDocSh, std::vector<ScRangeList>&& rRangeLists) :
+ aRangeLists(std::move(rRangeLists)),
+ pDocShell( pDocSh ),
+ nCurrentPosition(0)
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScUniqueCellFormatsEnumeration::~ScUniqueCellFormatsEnumeration()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScUniqueCellFormatsEnumeration::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! and now ???
+ }
+ else
+ {
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr;
+ }
+}
+
+// XEnumeration
+
+sal_Bool SAL_CALL ScUniqueCellFormatsEnumeration::hasMoreElements()
+{
+ SolarMutexGuard aGuard;
+ return o3tl::make_unsigned(nCurrentPosition) < aRangeLists.size();
+}
+
+uno::Any SAL_CALL ScUniqueCellFormatsEnumeration::nextElement()
+{
+ SolarMutexGuard aGuard;
+
+ if ( !hasMoreElements() || !pDocShell )
+ throw container::NoSuchElementException(); // no more elements
+
+ // interface type must match ScCellFormatsObj::getElementType
+
+ return uno::Any(uno::Reference<sheet::XSheetCellRangeContainer>(new ScCellRangesObj(pDocShell, aRangeLists[nCurrentPosition++])));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/cellvaluebinding.cxx b/sc/source/ui/unoobj/cellvaluebinding.cxx
new file mode 100644
index 000000000..6bf868cf3
--- /dev/null
+++ b/sc/source/ui/unoobj/cellvaluebinding.cxx
@@ -0,0 +1,576 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "cellvaluebinding.hxx"
+#include <rtl/math.hxx>
+#include <com/sun/star/form/binding/IncompatibleTypesException.hpp>
+#include <com/sun/star/lang/NotInitializedException.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/sheet/FormulaResult.hpp>
+#include <com/sun/star/sheet/XCellAddressable.hpp>
+#include <com/sun/star/sheet/XCellRangeData.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/types.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace calc
+{
+
+#define PROP_HANDLE_BOUND_CELL 1
+
+ namespace lang = ::com::sun::star::lang;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::table;
+ using namespace ::com::sun::star::text;
+ using namespace ::com::sun::star::sheet;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::form::binding;
+
+ OCellValueBinding::OCellValueBinding( const Reference< XSpreadsheetDocument >& _rxDocument, bool _bListPos )
+ :OCellValueBinding_Base( m_aMutex )
+ ,OCellValueBinding_PBase( OCellValueBinding_Base::rBHelper )
+ ,m_xDocument( _rxDocument )
+ ,m_aModifyListeners( m_aMutex )
+ ,m_bInitialized( false )
+ ,m_bListPos( _bListPos )
+ {
+ // register our property at the base class
+ registerPropertyNoMember(
+ "BoundCell",
+ PROP_HANDLE_BOUND_CELL,
+ PropertyAttribute::BOUND | PropertyAttribute::READONLY,
+ cppu::UnoType<CellAddress>::get(),
+ css::uno::Any(CellAddress())
+ );
+
+ // TODO: implement a ReadOnly property as required by the service,
+ // which probably maps to the cell being locked
+ }
+
+ OCellValueBinding::~OCellValueBinding( )
+ {
+ if ( !OCellValueBinding_Base::rBHelper.bDisposed )
+ {
+ acquire(); // prevent duplicate dtor
+ dispose();
+ }
+ }
+
+ IMPLEMENT_FORWARD_XINTERFACE2( OCellValueBinding, OCellValueBinding_Base, OCellValueBinding_PBase )
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( OCellValueBinding, OCellValueBinding_Base, OCellValueBinding_PBase )
+
+ void SAL_CALL OCellValueBinding::disposing()
+ {
+ Reference<XModifyBroadcaster> xBroadcaster( m_xCell, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->removeModifyListener( this );
+ }
+
+ WeakAggComponentImplHelperBase::disposing();
+
+ // TODO: clean up here whatever you need to clean up (e.g. deregister as XEventListener
+ // for the cell)
+ }
+
+ Reference< XPropertySetInfo > SAL_CALL OCellValueBinding::getPropertySetInfo( )
+ {
+ return createPropertySetInfo( getInfoHelper() ) ;
+ }
+
+ ::cppu::IPropertyArrayHelper& SAL_CALL OCellValueBinding::getInfoHelper()
+ {
+ return *OCellValueBinding_PABase::getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* OCellValueBinding::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper(aProps);
+ }
+
+ void SAL_CALL OCellValueBinding::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
+ {
+ OSL_ENSURE( _nHandle == PROP_HANDLE_BOUND_CELL, "OCellValueBinding::getFastPropertyValue: invalid handle!" );
+ // we only have this one property...
+
+ _rValue.clear();
+ Reference< XCellAddressable > xCellAddress( m_xCell, UNO_QUERY );
+ if ( xCellAddress.is() )
+ _rValue <<= xCellAddress->getCellAddress( );
+ }
+
+ Sequence< Type > SAL_CALL OCellValueBinding::getSupportedValueTypes( )
+ {
+ checkDisposed( );
+ checkInitialized( );
+
+ sal_Int32 nCount = m_xCellText.is() ? 3 : m_xCell.is() ? 1 : 0;
+ if ( m_bListPos )
+ ++nCount;
+
+ Sequence< Type > aTypes( nCount );
+ if ( m_xCell.is() )
+ {
+ auto pTypes = aTypes.getArray();
+
+ // an XCell can be used to set/get "double" values
+ pTypes[0] = ::cppu::UnoType<double>::get();
+ if ( m_xCellText.is() )
+ {
+ // an XTextRange can be used to set/get "string" values
+ pTypes[1] = ::cppu::UnoType<OUString>::get();
+ // and additionally, we use it to handle booleans
+ pTypes[2] = ::cppu::UnoType<sal_Bool>::get();
+ }
+
+ // add sal_Int32 only if constructed as ListPositionCellBinding
+ if ( m_bListPos )
+ pTypes[nCount-1] = cppu::UnoType<sal_Int32>::get();
+ }
+
+ return aTypes;
+ }
+
+ sal_Bool SAL_CALL OCellValueBinding::supportsType( const Type& aType )
+ {
+ checkDisposed( );
+ checkInitialized( );
+
+ // look up in our sequence
+ const Sequence< Type > aSupportedTypes( getSupportedValueTypes() );
+ for ( auto const & i : aSupportedTypes )
+ if ( aType == i )
+ return true;
+
+ return false;
+ }
+
+ Any SAL_CALL OCellValueBinding::getValue( const Type& aType )
+ {
+ checkDisposed( );
+ checkInitialized( );
+ checkValueType( aType );
+
+ Any aReturn;
+ switch ( aType.getTypeClass() )
+ {
+ case TypeClass_STRING:
+ OSL_ENSURE( m_xCellText.is(), "OCellValueBinding::getValue: don't have a text!" );
+ if ( m_xCellText.is() )
+ aReturn <<= m_xCellText->getString();
+ else
+ aReturn <<= OUString();
+ break;
+
+ case TypeClass_BOOLEAN:
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" );
+ if ( m_xCell.is() )
+ {
+ // check if the cell has a numeric value (this might go into a helper function):
+
+ bool bHasValue = false;
+ CellContentType eCellType = m_xCell->getType();
+ if ( eCellType == CellContentType_VALUE )
+ bHasValue = true;
+ else if ( eCellType == CellContentType_FORMULA )
+ {
+ // check if the formula result is a value
+ if ( m_xCell->getError() == 0 )
+ {
+ Reference<XPropertySet> xProp( m_xCell, UNO_QUERY );
+ if ( xProp.is() )
+ {
+ sal_Int32 nResultType;
+ if ( (xProp->getPropertyValue("FormulaResultType2") >>= nResultType)
+ && nResultType == FormulaResult::VALUE )
+ bHasValue = true;
+ }
+ }
+ }
+
+ if ( bHasValue )
+ {
+ // 0 is "unchecked", any other value is "checked", regardless of number format
+ double nCellValue = m_xCell->getValue();
+ bool bBoolValue = ( nCellValue != 0.0 );
+ aReturn <<= bBoolValue;
+ }
+ // empty cells, text cells and text or error formula results: leave return value empty
+ }
+ break;
+
+ case TypeClass_DOUBLE:
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" );
+ if ( m_xCell.is() )
+ aReturn <<= m_xCell->getValue();
+ else
+ aReturn <<= double(0);
+ break;
+
+ case TypeClass_LONG:
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::getValue: don't have a double value supplier!" );
+ if ( m_xCell.is() )
+ {
+ // The list position value in the cell is 1-based.
+ // We subtract 1 from any cell value (no special handling for 0 or negative values).
+
+ sal_Int32 nValue = static_cast<sal_Int32>(rtl::math::approxFloor( m_xCell->getValue() ));
+ --nValue;
+
+ aReturn <<= nValue;
+ }
+ else
+ aReturn <<= sal_Int32(0);
+ break;
+
+ default:
+ OSL_FAIL( "OCellValueBinding::getValue: unreachable code!" );
+ // a type other than double and string should never have survived the checkValueType
+ // above
+ }
+ return aReturn;
+ }
+
+ void SAL_CALL OCellValueBinding::setValue( const Any& aValue )
+ {
+ checkDisposed( );
+ checkInitialized( );
+ if ( aValue.hasValue() )
+ checkValueType( aValue.getValueType() );
+
+ switch ( aValue.getValueType().getTypeClass() )
+ {
+ case TypeClass_STRING:
+ {
+ OSL_ENSURE( m_xCellText.is(), "OCellValueBinding::setValue: don't have a text!" );
+
+ OUString sText;
+ aValue >>= sText;
+ if ( m_xCellText.is() )
+ m_xCellText->setString( sText );
+ }
+ break;
+
+ case TypeClass_BOOLEAN:
+ {
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" );
+
+ // boolean is stored as values 0 or 1
+ // TODO: set the number format to boolean if no format is set?
+
+ bool bValue( false );
+ aValue >>= bValue;
+ double nCellValue = bValue ? 1.0 : 0.0;
+
+ if ( m_xCell.is() )
+ m_xCell->setValue( nCellValue );
+
+ setBooleanFormat();
+ }
+ break;
+
+ case TypeClass_DOUBLE:
+ {
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" );
+
+ double nValue = 0;
+ aValue >>= nValue;
+ if ( m_xCell.is() )
+ m_xCell->setValue( nValue );
+ }
+ break;
+
+ case TypeClass_LONG:
+ {
+ OSL_ENSURE( m_xCell.is(), "OCellValueBinding::setValue: don't have a double value supplier!" );
+
+ sal_Int32 nValue = 0;
+ aValue >>= nValue; // list index from control layer (0-based)
+ ++nValue; // the list position value in the cell is 1-based
+ if ( m_xCell.is() )
+ m_xCell->setValue( nValue );
+ }
+ break;
+
+ case TypeClass_VOID:
+ {
+ // #N/A error value can only be set using XCellRangeData
+
+ Reference<XCellRangeData> xData( m_xCell, UNO_QUERY );
+ OSL_ENSURE( xData.is(), "OCellValueBinding::setValue: don't have XCellRangeData!" );
+ if ( xData.is() )
+ {
+ Sequence<Any> aInner(1); // one empty element
+ Sequence< Sequence<Any> > aOuter( &aInner, 1 ); // one row
+ xData->setDataArray( aOuter );
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL( "OCellValueBinding::setValue: unreachable code!" );
+ // a type other than double and string should never have survived the checkValueType
+ // above
+ }
+ }
+
+ void OCellValueBinding::setBooleanFormat()
+ {
+ // set boolean number format if not already set
+
+ OUString sPropName( "NumberFormat" );
+ Reference<XPropertySet> xCellProp( m_xCell, UNO_QUERY );
+ Reference<XNumberFormatsSupplier> xSupplier( m_xDocument, UNO_QUERY );
+ if ( !(xSupplier.is() && xCellProp.is()) )
+ return;
+
+ Reference<XNumberFormats> xFormats(xSupplier->getNumberFormats());
+ Reference<XNumberFormatTypes> xTypes( xFormats, UNO_QUERY );
+ if ( !xTypes.is() )
+ return;
+
+ lang::Locale aLocale;
+ bool bWasBoolean = false;
+
+ sal_Int32 nOldIndex = ::comphelper::getINT32( xCellProp->getPropertyValue( sPropName ) );
+ Reference<XPropertySet> xOldFormat;
+ try
+ {
+ xOldFormat.set(xFormats->getByKey( nOldIndex ));
+ }
+ catch ( Exception& )
+ {
+ // non-existing format - can happen, use defaults
+ }
+ if ( xOldFormat.is() )
+ {
+ // use the locale of the existing format
+ xOldFormat->getPropertyValue("Locale") >>= aLocale;
+
+ sal_Int16 nOldType = ::comphelper::getINT16(
+ xOldFormat->getPropertyValue("Type") );
+ if ( nOldType & NumberFormat::LOGICAL )
+ bWasBoolean = true;
+ }
+
+ if ( !bWasBoolean )
+ {
+ sal_Int32 nNewIndex = xTypes->getStandardFormat( NumberFormat::LOGICAL, aLocale );
+ xCellProp->setPropertyValue( sPropName, Any( nNewIndex ) );
+ }
+ }
+
+ void OCellValueBinding::checkDisposed( ) const
+ {
+ if ( OCellValueBinding_Base::rBHelper.bInDispose || OCellValueBinding_Base::rBHelper.bDisposed )
+ throw DisposedException();
+ // TODO: is it worth having an error message here?
+ }
+
+ void OCellValueBinding::checkInitialized()
+ {
+ if ( !m_bInitialized )
+ throw NotInitializedException("CellValueBinding is not initialized", static_cast<cppu::OWeakObject*>(this));
+ }
+
+ void OCellValueBinding::checkValueType( const Type& _rType ) const
+ {
+ OCellValueBinding* pNonConstThis = const_cast< OCellValueBinding* >( this );
+ if ( !pNonConstThis->supportsType( _rType ) )
+ {
+ OUString sMessage = "The given type (" +
+ _rType.getTypeName() +
+ ") is not supported by this binding.";
+ // TODO: localize this error message
+
+ throw IncompatibleTypesException( sMessage, *pNonConstThis );
+ // TODO: alternatively use a type converter service for this?
+ }
+ }
+
+ OUString SAL_CALL OCellValueBinding::getImplementationName( )
+ {
+ return "com.sun.star.comp.sheet.OCellValueBinding";
+ }
+
+ sal_Bool SAL_CALL OCellValueBinding::supportsService( const OUString& _rServiceName )
+ {
+ return cppu::supportsService(this, _rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL OCellValueBinding::getSupportedServiceNames( )
+ {
+ Sequence< OUString > aServices( m_bListPos ? 3 : 2 );
+ auto pServices = aServices.getArray();
+ pServices[ 0 ] = "com.sun.star.table.CellValueBinding";
+ pServices[ 1 ] = "com.sun.star.form.binding.ValueBinding";
+ if ( m_bListPos )
+ pServices[ 2 ] = "com.sun.star.table.ListPositionCellBinding";
+ return aServices;
+ }
+
+ void SAL_CALL OCellValueBinding::addModifyListener( const Reference< XModifyListener >& _rxListener )
+ {
+ if ( _rxListener.is() )
+ m_aModifyListeners.addInterface( _rxListener );
+ }
+
+ void SAL_CALL OCellValueBinding::removeModifyListener( const Reference< XModifyListener >& _rxListener )
+ {
+ if ( _rxListener.is() )
+ m_aModifyListeners.removeInterface( _rxListener );
+ }
+
+ void OCellValueBinding::notifyModified()
+ {
+ EventObject aEvent;
+ aEvent.Source.set(*this);
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter( m_aModifyListeners );
+ while ( aIter.hasMoreElements() )
+ {
+ try
+ {
+ aIter.next()->modified( aEvent );
+ }
+ catch( const RuntimeException& )
+ {
+ // silent this
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "OCellValueBinding::notifyModified: caught a (non-runtime) exception!" );
+ }
+ }
+ }
+
+ void SAL_CALL OCellValueBinding::modified( const EventObject& /* aEvent */ )
+ {
+ notifyModified();
+ }
+
+ void SAL_CALL OCellValueBinding::disposing( const EventObject& aEvent )
+ {
+ Reference<XInterface> xCellInt( m_xCell, UNO_QUERY );
+ if ( xCellInt == aEvent.Source )
+ {
+ // release references to cell object
+ m_xCell.clear();
+ m_xCellText.clear();
+ }
+ }
+
+ void SAL_CALL OCellValueBinding::initialize( const Sequence< Any >& _rArguments )
+ {
+ if ( m_bInitialized )
+ throw RuntimeException("CellValueBinding is already initialized", static_cast<cppu::OWeakObject*>(this));
+
+ // get the cell address
+ CellAddress aAddress;
+ bool bFoundAddress = false;
+
+ for ( const Any& rArg : _rArguments )
+ {
+ NamedValue aValue;
+ if ( rArg >>= aValue )
+ {
+ if ( aValue.Name == "BoundCell" )
+ {
+ if ( aValue.Value >>= aAddress )
+ {
+ bFoundAddress = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( !bFoundAddress )
+ throw RuntimeException("Cell not found", static_cast<cppu::OWeakObject*>(this));
+
+ // get the cell object
+ try
+ {
+ // first the sheets collection
+ Reference< XIndexAccess > xSheets;
+ if ( m_xDocument.is() )
+ xSheets.set(m_xDocument->getSheets( ), css::uno::UNO_QUERY);
+ OSL_ENSURE( xSheets.is(), "OCellValueBinding::initialize: could not retrieve the sheets!" );
+
+ if ( xSheets.is() )
+ {
+ // the concrete sheet
+ Reference< XCellRange > xSheet(xSheets->getByIndex( aAddress.Sheet ), UNO_QUERY);
+ OSL_ENSURE( xSheet.is(), "OCellValueBinding::initialize: NULL sheet, but no exception!" );
+
+ // the concrete cell
+ if ( xSheet.is() )
+ {
+ m_xCell.set(xSheet->getCellByPosition( aAddress.Column, aAddress.Row ));
+ Reference< XCellAddressable > xAddressAccess( m_xCell, UNO_QUERY );
+ OSL_ENSURE( xAddressAccess.is(), "OCellValueBinding::initialize: either NULL cell, or cell without address access!" );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "OCellValueBinding::initialize: caught an exception while retrieving the cell object!" );
+ }
+
+ if ( !m_xCell.is() )
+ throw RuntimeException("Failed to retrieve cell object", static_cast<cppu::OWeakObject*>(this));
+
+ m_xCellText.set(m_xCell, css::uno::UNO_QUERY);
+
+ Reference<XModifyBroadcaster> xBroadcaster( m_xCell, UNO_QUERY );
+ if ( xBroadcaster.is() )
+ {
+ xBroadcaster->addModifyListener( this );
+ }
+
+ // TODO: add as XEventListener to the cell, so we get notified when it dies,
+ // and can dispose ourself then
+
+ // TODO: somehow add as listener so we get notified when the address of the cell changes
+ // We need to forward this as change in our BoundCell property to our property change listeners
+
+ // TODO: be an XModifyBroadcaster, so that changes in our cell can be notified
+ // to the BindableValue which is/will be bound to this instance.
+
+ m_bInitialized = true;
+ // TODO: place your code here
+ }
+
+} // namespace calc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/cellvaluebinding.hxx b/sc/source/ui/unoobj/cellvaluebinding.hxx
new file mode 100644
index 000000000..048e7d504
--- /dev/null
+++ b/sc/source/ui/unoobj/cellvaluebinding.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/form/binding/XValueBinding.hpp>
+#include <com/sun/star/util/XModifyBroadcaster.hpp>
+#include <cppuhelper/compbase5.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+
+namespace com::sun::star::table { class XCell; }
+namespace com::sun::star::sheet { class XSpreadsheetDocument; }
+namespace com::sun::star::text { class XTextRange; }
+
+namespace calc
+{
+
+ //= OCellValueBinding
+
+ class OCellValueBinding;
+ // the base for our interfaces
+ typedef ::cppu::WeakAggComponentImplHelper5 < css::form::binding::XValueBinding
+ , css::lang::XServiceInfo
+ , css::util::XModifyBroadcaster
+ , css::util::XModifyListener
+ , css::lang::XInitialization
+ > OCellValueBinding_Base;
+ // the base for the property handling
+ typedef ::comphelper::OPropertyContainer OCellValueBinding_PBase;
+ // the second base for property handling
+ typedef ::comphelper::OPropertyArrayUsageHelper< OCellValueBinding >
+ OCellValueBinding_PABase;
+
+ class OCellValueBinding :public ::cppu::BaseMutex
+ ,public OCellValueBinding_Base // order matters! before OCellValueBinding_PBase, so rBHelper gets initialized
+ ,public OCellValueBinding_PBase
+ ,public OCellValueBinding_PABase
+ {
+ private:
+ css::uno::Reference< css::sheet::XSpreadsheetDocument >
+ m_xDocument; /// the document where our cell lives
+ css::uno::Reference< css::table::XCell >
+ m_xCell; /// the cell we're bound to, for double value access
+ css::uno::Reference< css::text::XTextRange >
+ m_xCellText; /// the cell we're bound to, for text access
+ ::comphelper::OInterfaceContainerHelper3<css::util::XModifyListener>
+ m_aModifyListeners; /// our modify listeners
+ bool m_bInitialized; /// has XInitialization::initialize been called?
+ bool m_bListPos; /// constructed as ListPositionCellBinding?
+
+ public:
+ OCellValueBinding(
+ const css::uno::Reference< css::sheet::XSpreadsheetDocument >& _rxDocument,
+ bool _bListPos
+ );
+
+ using OCellValueBinding_PBase::getFastPropertyValue;
+
+ protected:
+ virtual ~OCellValueBinding( ) override;
+
+ protected:
+ // XInterface
+ DECLARE_XINTERFACE()
+
+ // XTypeProvider
+ DECLARE_XTYPEPROVIDER()
+
+ // XValueBinding
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getSupportedValueTypes( ) override;
+ virtual sal_Bool SAL_CALL supportsType( const css::uno::Type& aType ) override;
+ virtual css::uno::Any SAL_CALL getValue( const css::uno::Type& aType ) override;
+ virtual void SAL_CALL setValue( const css::uno::Any& aValue ) override;
+
+ // OComponentHelper/XComponent
+ virtual void SAL_CALL disposing() 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;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& _rValue, sal_Int32 _nHandle ) const override;
+
+ // ::comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+
+ // XModifyListener
+ virtual void SAL_CALL modified( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ private:
+ void checkDisposed( ) const;
+ void checkValueType( const css::uno::Type& _rType ) const;
+ void checkInitialized();
+
+ /** notifies our modify listeners
+ @precond
+ our mutex is <em>not</em> locked
+ */
+ void notifyModified();
+
+ void setBooleanFormat();
+
+ private:
+ OCellValueBinding( const OCellValueBinding& ) = delete;
+ OCellValueBinding& operator=( const OCellValueBinding& ) = delete;
+ };
+
+} // namespace calc
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/chart2uno.cxx b/sc/source/ui/unoobj/chart2uno.cxx
new file mode 100644
index 000000000..8de29306e
--- /dev/null
+++ b/sc/source/ui/unoobj/chart2uno.cxx
@@ -0,0 +1,3490 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <algorithm>
+#include <utility>
+
+#include <chart2uno.hxx>
+#include <miscuno.hxx>
+#include <document.hxx>
+#include <formulacell.hxx>
+#include <unonames.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <rangeutl.hxx>
+#include <hints.hxx>
+#include <unoreflist.hxx>
+#include <compiler.hxx>
+#include <reftokenhelper.hxx>
+#include <chartlis.hxx>
+#include <tokenuno.hxx>
+#include <cellvalue.hxx>
+#include <tokenarray.hxx>
+#include <scmatrix.hxx>
+#include <brdcst.hxx>
+#include <mtvelements.hxx>
+
+#include <formula/opcode.hxx>
+#include <o3tl/safeint.hxx>
+#include <svl/numformat.hxx>
+#include <svl/sharedstring.hxx>
+
+#include <sfx2/objsh.hxx>
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/beans/UnknownPropertyException.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/chart2/data/LabeledDataSequence.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <comphelper/extract.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <limits>
+
+SC_SIMPLE_SERVICE_INFO( ScChart2DataProvider, "ScChart2DataProvider",
+ "com.sun.star.chart2.data.DataProvider")
+SC_SIMPLE_SERVICE_INFO( ScChart2DataSource, "ScChart2DataSource",
+ "com.sun.star.chart2.data.DataSource")
+SC_SIMPLE_SERVICE_INFO( ScChart2DataSequence, "ScChart2DataSequence",
+ "com.sun.star.chart2.data.DataSequence")
+
+using namespace ::com::sun::star;
+using namespace ::formula;
+using ::com::sun::star::uno::Sequence;
+using ::std::unique_ptr;
+using ::std::vector;
+using ::std::distance;
+using ::std::shared_ptr;
+
+namespace
+{
+const SfxItemPropertyMapEntry* lcl_GetDataProviderPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDataProviderPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_INCLUDEHIDDENCELLS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_USE_INTERNAL_DATA_PROVIDER, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aDataProviderPropertyMap_Impl;
+}
+
+const SfxItemPropertyMapEntry* lcl_GetDataSequencePropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDataSequencePropertyMap_Impl[] =
+ {
+ { SC_UNONAME_HIDDENVALUES, 0, cppu::UnoType<uno::Sequence<sal_Int32>>::get(), 0, 0 },
+ { SC_UNONAME_ROLE, 0, cppu::UnoType<css::chart2::data::DataSequenceRole>::get(), 0, 0 },
+ { SC_UNONAME_INCLUDEHIDDENCELLS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aDataSequencePropertyMap_Impl;
+}
+
+struct lcl_appendTableNumber
+{
+ explicit lcl_appendTableNumber( OUStringBuffer & rBuffer ) :
+ m_rBuffer( rBuffer )
+ {}
+ void operator() ( SCTAB nTab )
+ {
+ // there is no append with SCTAB or sal_Int16
+ m_rBuffer.append( static_cast< sal_Int32 >( nTab ));
+ m_rBuffer.append( ' ' );
+ }
+private:
+ OUStringBuffer & m_rBuffer;
+};
+
+OUString lcl_createTableNumberList( const ::std::vector< SCTAB > & rTableVector )
+{
+ OUStringBuffer aBuffer;
+ ::std::for_each( rTableVector.begin(), rTableVector.end(), lcl_appendTableNumber( aBuffer ));
+ // remove last trailing ' '
+ if( !aBuffer.isEmpty() )
+ aBuffer.setLength( aBuffer.getLength() - 1 );
+ return aBuffer.makeStringAndClear();
+}
+
+uno::Reference< frame::XModel > lcl_GetXModel( const ScDocument * pDoc )
+{
+ uno::Reference< frame::XModel > xModel;
+ SfxObjectShell * pObjSh( pDoc ? pDoc->GetDocumentShell() : nullptr );
+ if( pObjSh )
+ xModel.set( pObjSh->GetModel());
+ return xModel;
+}
+
+struct TokenTable
+{
+ SCROW mnRowCount;
+ SCCOL mnColCount;
+ vector<std::unique_ptr<FormulaToken>> maTokens;
+
+ // noncopyable
+ TokenTable(const TokenTable&) = delete;
+ const TokenTable& operator=(const TokenTable&) = delete;
+
+ TokenTable()
+ : mnRowCount(0)
+ , mnColCount(0)
+ {
+ }
+
+ void init( SCCOL nColCount, SCROW nRowCount )
+ {
+ mnColCount = nColCount;
+ mnRowCount = nRowCount;
+ maTokens.reserve(mnColCount*mnRowCount);
+ }
+ void clear()
+ {
+ for (auto & rToken : maTokens)
+ rToken.reset();
+ }
+
+ void push_back( std::unique_ptr<FormulaToken> pToken )
+ {
+ maTokens.push_back( std::move(pToken) );
+ OSL_ENSURE( maTokens.size()<= o3tl::make_unsigned( mnColCount*mnRowCount ), "too many tokens" );
+ }
+
+ sal_uInt32 getIndex(SCCOL nCol, SCROW nRow) const
+ {
+ OSL_ENSURE( nCol<mnColCount, "wrong column index" );
+ OSL_ENSURE( nRow<mnRowCount, "wrong row index" );
+ sal_uInt32 nRet = static_cast<sal_uInt32>(nCol*mnRowCount + nRow);
+ OSL_ENSURE( maTokens.size()>= o3tl::make_unsigned( mnColCount*mnRowCount ), "too few tokens" );
+ return nRet;
+ }
+
+ vector<ScTokenRef> getColRanges(const ScDocument* pDoc, SCCOL nCol) const;
+ vector<ScTokenRef> getRowRanges(const ScDocument* pDoc, SCROW nRow) const;
+ vector<ScTokenRef> getAllRanges(const ScDocument* pDoc) const;
+};
+
+vector<ScTokenRef> TokenTable::getColRanges(const ScDocument* pDoc, SCCOL nCol) const
+{
+ if (nCol >= mnColCount)
+ return vector<ScTokenRef>();
+ if( mnRowCount<=0 )
+ return vector<ScTokenRef>();
+
+ vector<ScTokenRef> aTokens;
+ sal_uInt32 nLast = getIndex(nCol, mnRowCount-1);
+ for (sal_uInt32 i = getIndex(nCol, 0); i <= nLast; ++i)
+ {
+ FormulaToken* p = maTokens[i].get();
+ if (!p)
+ continue;
+
+ ScTokenRef pCopy(p->Clone());
+ ScRefTokenHelper::join(pDoc, aTokens, pCopy, ScAddress());
+ }
+ return aTokens;
+}
+
+vector<ScTokenRef> TokenTable::getRowRanges(const ScDocument* pDoc, SCROW nRow) const
+{
+ if (nRow >= mnRowCount)
+ return vector<ScTokenRef>();
+ if( mnColCount<=0 )
+ return vector<ScTokenRef>();
+
+ vector<ScTokenRef> aTokens;
+ sal_uInt32 nLast = getIndex(mnColCount-1, nRow);
+ for (sal_uInt32 i = getIndex(0, nRow); i <= nLast; i += mnRowCount)
+ {
+ FormulaToken* p = maTokens[i].get();
+ if (!p)
+ continue;
+
+ ScTokenRef p2(p->Clone());
+ ScRefTokenHelper::join(pDoc, aTokens, p2, ScAddress());
+ }
+ return aTokens;
+}
+
+vector<ScTokenRef> TokenTable::getAllRanges(const ScDocument* pDoc) const
+{
+ vector<ScTokenRef> aTokens;
+ sal_uInt32 nStop = mnColCount*mnRowCount;
+ for (sal_uInt32 i = 0; i < nStop; i++)
+ {
+ FormulaToken* p = maTokens[i].get();
+ if (!p)
+ continue;
+
+ ScTokenRef p2(p->Clone());
+ ScRefTokenHelper::join(pDoc, aTokens, p2, ScAddress());
+ }
+ return aTokens;
+}
+
+typedef std::map<SCROW, std::unique_ptr<FormulaToken>> FormulaTokenMap;
+typedef std::map<sal_uInt32, FormulaTokenMap> FormulaTokenMapMap;
+
+class Chart2PositionMap
+{
+public:
+ Chart2PositionMap(SCCOL nColCount, SCROW nRowCount,
+ bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols,
+ ScDocument* pDoc );
+ ~Chart2PositionMap();
+
+ SCCOL getDataColCount() const { return mnDataColCount; }
+ SCROW getDataRowCount() const { return mnDataRowCount; }
+
+ vector<ScTokenRef> getLeftUpperCornerRanges() const;
+ vector<ScTokenRef> getAllColHeaderRanges() const;
+ vector<ScTokenRef> getAllRowHeaderRanges() const;
+
+ vector<ScTokenRef> getColHeaderRanges(SCCOL nChartCol) const;
+ vector<ScTokenRef> getRowHeaderRanges(SCROW nChartRow) const;
+
+ vector<ScTokenRef> getDataColRanges(SCCOL nCol) const;
+ vector<ScTokenRef> getDataRowRanges(SCROW nRow) const;
+
+private:
+ const ScDocument* mpDoc;
+ SCCOL mnDataColCount;
+ SCROW mnDataRowCount;
+
+ TokenTable maLeftUpperCorner; //nHeaderColCount*nHeaderRowCount
+ TokenTable maColHeaders; //mnDataColCount*nHeaderRowCount
+ TokenTable maRowHeaders; //nHeaderColCount*mnDataRowCount
+ TokenTable maData;//mnDataColCount*mnDataRowCount
+};
+
+Chart2PositionMap::Chart2PositionMap(SCCOL nAllColCount, SCROW nAllRowCount,
+ bool bFillRowHeader, bool bFillColumnHeader, FormulaTokenMapMap& rCols, ScDocument* pDoc)
+{
+ mpDoc = pDoc;
+ // if bFillRowHeader is true, at least the first column serves as a row header.
+ // If more than one column is pure text all the first pure text columns are used as header.
+ // Likewise, if bFillColumnHeader is true, at least the first row serves as a column header.
+ // If more than one row is pure text all the first pure text rows are used as header.
+
+ SCROW nHeaderRowCount = (bFillColumnHeader && nAllColCount && nAllRowCount) ? 1 : 0;
+ SCCOL nHeaderColCount = (bFillRowHeader && nAllColCount && nAllRowCount) ? 1 : 0;
+
+ if( pDoc && (nHeaderColCount || nHeaderRowCount ) )
+ {
+ //check whether there is more than one text column or row that should be added to the headers
+ SCROW nMaxHeaderRow = nAllRowCount;
+ SCCOL nCol = 0;
+ for (auto it = rCols.begin(); it != rCols.end(); ++it, ++nCol)
+ {
+ // Skip header columns
+ if (nCol < nHeaderColCount)
+ continue;
+
+ const auto& rCol = *it;
+
+ bool bFoundValuesInCol = false;
+ bool bFoundAnythingInCol = false;
+ SCROW nRow = 0;
+ for (auto it2 = rCol.second.begin(); it2 != rCol.second.end(); ++it2, ++nRow)
+ {
+ const auto& rCell = *it2;
+
+ // Skip header rows
+ if (nRow < nHeaderRowCount || !rCell.second)
+ continue;
+
+ ScRange aRange;
+ bool bExternal = false;
+ StackVar eType = rCell.second->GetType();
+ if( eType==svExternal || eType==svExternalSingleRef || eType==svExternalDoubleRef || eType==svExternalName )
+ bExternal = true;//lllll todo correct?
+ ScTokenRef pSharedToken(rCell.second->Clone());
+ ScRefTokenHelper::getRangeFromToken(pDoc, aRange, pSharedToken, ScAddress(), bExternal);
+ SCCOL nCol1=0, nCol2=0;
+ SCROW nRow1=0, nRow2=0;
+ SCTAB nTab1=0, nTab2=0;
+ aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
+ if ( pDoc->HasValueData( nCol1, nRow1, nTab1 ) )
+ {
+ // Found some numeric data
+ bFoundValuesInCol = true;
+ nMaxHeaderRow = std::min(nMaxHeaderRow, nRow);
+ break;
+ }
+ if ( pDoc->HasData( nCol1, nRow1, nTab1 ) )
+ {
+ // Found some other data (non-numeric)
+ bFoundAnythingInCol = true;
+ }
+ else
+ {
+ // If cell is empty, it belongs to data
+ nMaxHeaderRow = std::min(nMaxHeaderRow, nRow);
+ }
+ }
+
+ if (nHeaderColCount && !bFoundValuesInCol && bFoundAnythingInCol && nCol == nHeaderColCount)
+ {
+ // There is no values in row, but some data. And this column is next to header
+ // So lets put it to header
+ nHeaderColCount++;
+ }
+ }
+
+ if (nHeaderRowCount)
+ {
+ nHeaderRowCount = nMaxHeaderRow;
+ }
+ }
+
+ mnDataColCount = nAllColCount - nHeaderColCount;
+ mnDataRowCount = nAllRowCount - nHeaderRowCount;
+
+ maLeftUpperCorner.init(nHeaderColCount,nHeaderRowCount);
+ maColHeaders.init(mnDataColCount,nHeaderRowCount);
+ maRowHeaders.init(nHeaderColCount,mnDataRowCount);
+ maData.init(mnDataColCount,mnDataRowCount);
+
+ FormulaTokenMapMap::iterator it1 = rCols.begin();
+ for (SCCOL nCol = 0; nCol < nAllColCount; ++nCol)
+ {
+ if (it1 != rCols.end())
+ {
+ FormulaTokenMap& rCol = it1->second;
+ FormulaTokenMap::iterator it2 = rCol.begin();
+ for (SCROW nRow = 0; nRow < nAllRowCount; ++nRow)
+ {
+ std::unique_ptr<FormulaToken> pToken;
+ if (it2 != rCol.end())
+ {
+ pToken = std::move(it2->second);
+ ++it2;
+ }
+
+ if( nCol < nHeaderColCount )
+ {
+ if( nRow < nHeaderRowCount )
+ maLeftUpperCorner.push_back(std::move(pToken));
+ else
+ maRowHeaders.push_back(std::move(pToken));
+ }
+ else if( nRow < nHeaderRowCount )
+ maColHeaders.push_back(std::move(pToken));
+ else
+ maData.push_back(std::move(pToken));
+ }
+ ++it1;
+ }
+ }
+}
+
+Chart2PositionMap::~Chart2PositionMap()
+{
+ maLeftUpperCorner.clear();
+ maColHeaders.clear();
+ maRowHeaders.clear();
+ maData.clear();
+}
+
+vector<ScTokenRef> Chart2PositionMap::getLeftUpperCornerRanges() const
+{
+ return maLeftUpperCorner.getAllRanges(mpDoc);
+}
+vector<ScTokenRef> Chart2PositionMap::getAllColHeaderRanges() const
+{
+ return maColHeaders.getAllRanges(mpDoc);
+}
+vector<ScTokenRef> Chart2PositionMap::getAllRowHeaderRanges() const
+{
+ return maRowHeaders.getAllRanges(mpDoc);
+}
+vector<ScTokenRef> Chart2PositionMap::getColHeaderRanges(SCCOL nCol) const
+{
+ return maColHeaders.getColRanges(mpDoc, nCol);
+}
+vector<ScTokenRef> Chart2PositionMap::getRowHeaderRanges(SCROW nRow) const
+{
+ return maRowHeaders.getRowRanges(mpDoc, nRow);
+}
+
+vector<ScTokenRef> Chart2PositionMap::getDataColRanges(SCCOL nCol) const
+{
+ return maData.getColRanges(mpDoc, nCol);
+}
+
+vector<ScTokenRef> Chart2PositionMap::getDataRowRanges(SCROW nRow) const
+{
+ return maData.getRowRanges(mpDoc, nRow);
+}
+
+/**
+ * Designed to be a drop-in replacement for ScChartPositioner, in order to
+ * handle external references.
+ */
+class Chart2Positioner
+{
+ enum GlueType
+ {
+ GLUETYPE_NA,
+ GLUETYPE_NONE,
+ GLUETYPE_COLS,
+ GLUETYPE_ROWS,
+ GLUETYPE_BOTH
+ };
+
+public:
+ Chart2Positioner(const Chart2Positioner&) = delete;
+ const Chart2Positioner& operator=(const Chart2Positioner&) = delete;
+
+ Chart2Positioner(ScDocument* pDoc, const vector<ScTokenRef>& rRefTokens) :
+ mrRefTokens(rRefTokens),
+ meGlue(GLUETYPE_NA),
+ mnStartCol(0),
+ mnStartRow(0),
+ mpDoc(pDoc),
+ mbColHeaders(false),
+ mbRowHeaders(false),
+ mbDummyUpperLeft(false)
+ {
+ }
+
+ void setHeaders(bool bColHeaders, bool bRowHeaders)
+ {
+ mbColHeaders = bColHeaders;
+ mbRowHeaders = bRowHeaders;
+ }
+
+ Chart2PositionMap* getPositionMap()
+ {
+ createPositionMap();
+ return mpPositionMap.get();
+ }
+
+private:
+ void invalidateGlue();
+ void glueState();
+ void calcGlueState(SCCOL nCols, SCROW nRows);
+ void createPositionMap();
+
+private:
+ const vector<ScTokenRef>& mrRefTokens;
+ std::unique_ptr<Chart2PositionMap> mpPositionMap;
+ GlueType meGlue;
+ SCCOL mnStartCol;
+ SCROW mnStartRow;
+ ScDocument* mpDoc;
+ bool mbColHeaders:1;
+ bool mbRowHeaders:1;
+ bool mbDummyUpperLeft:1;
+};
+
+void Chart2Positioner::invalidateGlue()
+{
+ meGlue = GLUETYPE_NA;
+ mpPositionMap.reset();
+}
+
+void Chart2Positioner::glueState()
+{
+ if (meGlue != GLUETYPE_NA)
+ return;
+
+ mbDummyUpperLeft = false;
+ if (mrRefTokens.size() <= 1)
+ {
+ // Source data consists of only one data range.
+ const ScTokenRef& p = mrRefTokens.front();
+ ScComplexRefData aData;
+ if (ScRefTokenHelper::getDoubleRefDataFromToken(aData, p))
+ {
+ if (aData.Ref1.Tab() == aData.Ref2.Tab())
+ meGlue = GLUETYPE_NONE;
+ else
+ meGlue = GLUETYPE_COLS;
+ mnStartCol = aData.Ref1.Col();
+ mnStartRow = aData.Ref1.Row();
+ }
+ else
+ {
+ invalidateGlue();
+ mnStartCol = 0;
+ mnStartRow = 0;
+ }
+ return;
+ }
+
+ ScComplexRefData aData;
+ if (!ScRefTokenHelper::getDoubleRefDataFromToken(aData, mrRefTokens.front()))
+ {
+ SAL_WARN("sc", "Chart2Positioner::glueState getDoubleRefDataFromToken failed");
+ invalidateGlue();
+ mnStartCol = 0;
+ mnStartRow = 0;
+ return;
+ }
+ mnStartCol = aData.Ref1.Col();
+ mnStartRow = aData.Ref1.Row();
+
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ for (const auto& rxToken : mrRefTokens)
+ {
+ ScRefTokenHelper::getDoubleRefDataFromToken(aData, rxToken);
+ SCCOLROW n1 = aData.Ref1.Col();
+ SCCOLROW n2 = aData.Ref2.Col();
+ if (n1 > mpDoc->MaxCol())
+ n1 = mpDoc->MaxCol();
+ if (n2 > mpDoc->MaxCol())
+ n2 = mpDoc->MaxCol();
+ if (n1 < mnStartCol)
+ mnStartCol = static_cast<SCCOL>(n1);
+ if (n2 > nEndCol)
+ nEndCol = static_cast<SCCOL>(n2);
+
+ n1 = aData.Ref1.Row();
+ n2 = aData.Ref2.Row();
+ if (n1 > mpDoc->MaxRow())
+ n1 = mpDoc->MaxRow();
+ if (n2 > mpDoc->MaxRow())
+ n2 = mpDoc->MaxRow();
+
+ if (n1 < mnStartRow)
+ mnStartRow = static_cast<SCROW>(n1);
+ if (n2 > nEndRow)
+ nEndRow = static_cast<SCROW>(n2);
+ }
+
+ if (mnStartCol == nEndCol)
+ {
+ // All source data is in a single column.
+ meGlue = GLUETYPE_ROWS;
+ return;
+ }
+
+ if (mnStartRow == nEndRow)
+ {
+ // All source data is in a single row.
+ meGlue = GLUETYPE_COLS;
+ return;
+ }
+
+ // total column size
+ SCCOL nC = nEndCol - mnStartCol + 1;
+
+ // total row size
+ SCROW nR = nEndRow - mnStartRow + 1;
+
+ // #i103540# prevent invalid vector size
+ if ((nC <= 0) || (nR <= 0))
+ {
+ invalidateGlue();
+ mnStartCol = 0;
+ mnStartRow = 0;
+ return;
+ }
+
+ calcGlueState(nC, nR);
+}
+
+enum State { Hole = 0, Occupied = 1, Free = 2, Glue = 3 };
+
+void Chart2Positioner::calcGlueState(SCCOL nColSize, SCROW nRowSize)
+{
+ // TODO: This code can use some space optimization. Using an array to
+ // store individual cell's states is terribly inefficient esp for large
+ // data ranges; let's use flat_segment_tree to reduce memory usage here.
+
+ sal_uInt32 nCR = static_cast<sal_uInt32>(nColSize*nRowSize);
+
+ vector<State> aCellStates(nCR, Hole);
+
+ // Mark all referenced cells "occupied".
+ for (const auto& rxToken : mrRefTokens)
+ {
+ ScComplexRefData aData;
+ ScRefTokenHelper::getDoubleRefDataFromToken(aData, rxToken);
+ SCCOL nCol1 = aData.Ref1.Col() - mnStartCol;
+ SCCOL nCol2 = aData.Ref2.Col() - mnStartCol;
+ SCROW nRow1 = aData.Ref1.Row() - mnStartRow;
+ SCROW nRow2 = aData.Ref2.Row() - mnStartRow;
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+ {
+ size_t i = nCol*nRowSize + nRow;
+ aCellStates[i] = Occupied;
+ }
+ }
+
+ // If at least one cell in either the first column or first row is empty,
+ // we don't glue at all unless the whole column or row is empty; we expect
+ // all cells in the first column / row to be fully populated. If we have
+ // empty column or row, then we do glue by the column or row,
+ // respectively.
+
+ bool bGlue = true;
+ bool bGlueCols = false;
+ for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol)
+ {
+ for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
+ {
+ size_t i = nCol*nRowSize + nRow;
+ if (aCellStates[i] == Occupied)
+ {
+ if (nCol == 0 || nRow == 0)
+ break;
+
+ bGlue = false;
+ }
+ else
+ aCellStates[i] = Free;
+ }
+ size_t nLast = (nCol+1)*nRowSize - 1; // index for the last cell in the column.
+ if (bGlue && aCellStates[nLast] == Free)
+ {
+ // Whole column is empty.
+ aCellStates[nLast] = Glue;
+ bGlueCols = true;
+ }
+ }
+
+ bool bGlueRows = false;
+ for (SCROW nRow = 0; bGlue && nRow < nRowSize; ++nRow)
+ {
+ size_t i = nRow;
+ for (SCCOL nCol = 0; bGlue && nCol < nColSize; ++nCol, i += nRowSize)
+ {
+ if (aCellStates[i] == Occupied)
+ {
+ if (nCol == 0 || nRow == 0)
+ break;
+
+ bGlue = false;
+ }
+ else
+ aCellStates[i] = Free;
+ }
+ i = (nColSize-1)*nRowSize + nRow; // index for the row position in the last column.
+ if (bGlue && aCellStates[i] == Free)
+ {
+ // Whole row is empty.
+ aCellStates[i] = Glue;
+ bGlueRows = true;
+ }
+ }
+
+ size_t i = 1;
+ for (sal_uInt32 n = 1; bGlue && n < nCR; ++n, ++i)
+ if (aCellStates[i] == Hole)
+ bGlue = false;
+
+ if (bGlue)
+ {
+ if (bGlueCols && bGlueRows)
+ meGlue = GLUETYPE_BOTH;
+ else if (bGlueRows)
+ meGlue = GLUETYPE_ROWS;
+ else
+ meGlue = GLUETYPE_COLS;
+ if (aCellStates.front() != Occupied)
+ mbDummyUpperLeft = true;
+ }
+ else
+ meGlue = GLUETYPE_NONE;
+}
+
+void Chart2Positioner::createPositionMap()
+{
+ if (meGlue == GLUETYPE_NA && mpPositionMap)
+ mpPositionMap.reset();
+
+ if (mpPositionMap)
+ return;
+
+ glueState();
+
+ bool bNoGlue = (meGlue == GLUETYPE_NONE);
+ FormulaTokenMapMap aCols;
+ SCROW nNoGlueRow = 0;
+ for (const ScTokenRef& pToken : mrRefTokens)
+ {
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
+ svl::SharedString aTabName = svl::SharedString::getEmptyString();
+ if (bExternal)
+ aTabName = pToken->GetString();
+
+ ScComplexRefData aData;
+ if( !ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken) )
+ break;
+ const ScSingleRefData& s = aData.Ref1;
+ const ScSingleRefData& e = aData.Ref2;
+ SCCOL nCol1 = s.Col(), nCol2 = e.Col();
+ SCROW nRow1 = s.Row(), nRow2 = e.Row();
+ SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
+
+ for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
+ {
+ // columns on secondary sheets are appended; we treat them as if
+ // all columns are on the same sheet. TODO: We can't assume that
+ // the column range is 16-bit; remove that restriction.
+ sal_uInt32 nInsCol = (static_cast<sal_uInt32>(nTab) << 16) |
+ (bNoGlue ? 0 : static_cast<sal_uInt32>(nCol1));
+
+ for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol, ++nInsCol)
+ {
+ FormulaTokenMap& rCol = aCols[nInsCol];
+
+ auto nInsRow = bNoGlue ? nNoGlueRow : nRow1;
+ for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow, ++nInsRow)
+ {
+ ScSingleRefData aCellData;
+ aCellData.InitFlags();
+ aCellData.SetFlag3D(true);
+ aCellData.SetColRel(false);
+ aCellData.SetRowRel(false);
+ aCellData.SetTabRel(false);
+ aCellData.SetAbsCol(nCol);
+ aCellData.SetAbsRow(nRow);
+ aCellData.SetAbsTab(nTab);
+
+ auto& rCell = rCol[nInsRow];
+ if (!rCell)
+ {
+ if (bExternal)
+ rCell.reset(new ScExternalSingleRefToken(nFileId, aTabName, aCellData));
+ else
+ rCell.reset(new ScSingleRefToken(mpDoc->GetSheetLimits(), aCellData));
+ }
+ }
+ }
+ }
+ nNoGlueRow += nRow2 - nRow1 + 1;
+ }
+
+ bool bFillRowHeader = mbRowHeaders;
+ bool bFillColumnHeader = mbColHeaders;
+
+ SCSIZE nAllColCount = static_cast<SCSIZE>(aCols.size());
+ SCSIZE nAllRowCount = 0;
+ if (!aCols.empty())
+ {
+ FormulaTokenMap& rCol = aCols.begin()->second;
+ if (mbDummyUpperLeft)
+ rCol.try_emplace( 0, nullptr ); // dummy for labeling
+ nAllRowCount = static_cast<SCSIZE>(rCol.size());
+ }
+
+ if( nAllColCount!=0 && nAllRowCount!=0 )
+ {
+ if (bNoGlue)
+ {
+ FormulaTokenMap& rFirstCol = aCols.begin()->second;
+ for (const auto& rFirstColEntry : rFirstCol)
+ {
+ SCROW nKey = rFirstColEntry.first;
+ for (auto& rEntry : aCols)
+ {
+ FormulaTokenMap& rCol = rEntry.second;
+ rCol.try_emplace( nKey, nullptr );
+ }
+ }
+ }
+ }
+ mpPositionMap.reset(
+ new Chart2PositionMap(
+ static_cast<SCCOL>(nAllColCount), static_cast<SCROW>(nAllRowCount),
+ bFillRowHeader, bFillColumnHeader, aCols, mpDoc));
+}
+
+/**
+ * Function object to create a range string from a token list.
+ */
+class Tokens2RangeString
+{
+public:
+ Tokens2RangeString(ScDocument& rDoc, FormulaGrammar::Grammar eGram, sal_Unicode cRangeSep) :
+ mpRangeStr(std::make_shared<OUStringBuffer>()),
+ mpDoc(&rDoc),
+ meGrammar(eGram),
+ mcRangeSep(cRangeSep),
+ mbFirst(true)
+ {
+ }
+
+ void operator() (const ScTokenRef& rToken)
+ {
+ ScCompiler aCompiler(*mpDoc, ScAddress(0,0,0), meGrammar);
+ OUString aStr;
+ aCompiler.CreateStringFromToken(aStr, rToken.get());
+ if (mbFirst)
+ mbFirst = false;
+ else
+ mpRangeStr->append(mcRangeSep);
+ mpRangeStr->append(aStr);
+ }
+
+ void getString(OUString& rStr)
+ {
+ rStr = mpRangeStr->makeStringAndClear();
+ }
+
+private:
+ shared_ptr<OUStringBuffer> mpRangeStr;
+ ScDocument* mpDoc;
+ FormulaGrammar::Grammar meGrammar;
+ sal_Unicode mcRangeSep;
+ bool mbFirst;
+};
+
+/**
+ * Function object to convert a list of tokens into a string form suitable
+ * for ODF export. In ODF, a range is expressed as
+ *
+ * (start cell address):(end cell address)
+ *
+ * and each address doesn't include any '$' symbols.
+ */
+class Tokens2RangeStringXML
+{
+public:
+ explicit Tokens2RangeStringXML(ScDocument& rDoc) :
+ mpRangeStr(std::make_shared<OUStringBuffer>()),
+ mpDoc(&rDoc),
+ mbFirst(true)
+ {
+ }
+
+ void operator() (const ScTokenRef& rToken)
+ {
+ if (mbFirst)
+ mbFirst = false;
+ else
+ mpRangeStr->append(mcRangeSep);
+
+ ScTokenRef aStart, aEnd;
+ bool bValidToken = splitRangeToken(*mpDoc, rToken, aStart, aEnd);
+ // Check there is a valid reference in named range
+ if (!bValidToken && rToken->GetType() == svIndex && rToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = mpDoc->FindRangeNameBySheetAndIndex(rToken->GetSheet(), rToken->GetIndex());
+ if (pNameRange->HasReferences())
+ {
+ const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
+ bValidToken = splitRangeToken(*mpDoc, aTempToken, aStart, aEnd);
+ }
+ }
+
+ OSL_ENSURE(bValidToken, "invalid token");
+ if (!bValidToken)
+ return;
+
+ ScCompiler aCompiler(*mpDoc, ScAddress(0,0,0), FormulaGrammar::GRAM_ENGLISH);
+ {
+ OUString aStr;
+ aCompiler.CreateStringFromToken(aStr, aStart.get());
+ mpRangeStr->append(aStr);
+ }
+ mpRangeStr->append(mcAddrSep);
+ {
+ OUString aStr;
+ aCompiler.CreateStringFromToken(aStr, aEnd.get());
+ mpRangeStr->append(aStr);
+ }
+ }
+
+ void getString(OUString& rStr)
+ {
+ rStr = mpRangeStr->makeStringAndClear();
+ }
+
+private:
+ static bool splitRangeToken(const ScDocument& rDoc, const ScTokenRef& pToken, ScTokenRef& rStart, ScTokenRef& rEnd)
+ {
+ ScComplexRefData aData;
+ bool bIsRefToken = ScRefTokenHelper::getDoubleRefDataFromToken(aData, pToken);
+ OSL_ENSURE(bIsRefToken, "invalid token");
+ if (!bIsRefToken)
+ return false;
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ sal_uInt16 nFileId = bExternal ? pToken->GetIndex() : 0;
+ svl::SharedString aTabName = svl::SharedString::getEmptyString();
+ if (bExternal)
+ aTabName = pToken->GetString();
+
+ // In saving to XML, we don't prepend address with '$'.
+ setRelative(aData.Ref1);
+ setRelative(aData.Ref2);
+
+ // In XML, the range must explicitly specify sheet name.
+ aData.Ref1.SetFlag3D(true);
+ aData.Ref2.SetFlag3D(true);
+
+ if (bExternal)
+ rStart.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref1));
+ else
+ rStart.reset(new ScSingleRefToken(rDoc.GetSheetLimits(), aData.Ref1));
+
+ if (bExternal)
+ rEnd.reset(new ScExternalSingleRefToken(nFileId, aTabName, aData.Ref2));
+ else
+ rEnd.reset(new ScSingleRefToken(rDoc.GetSheetLimits(), aData.Ref2));
+ return true;
+ }
+
+ static void setRelative(ScSingleRefData& rData)
+ {
+ rData.SetColRel(true);
+ rData.SetRowRel(true);
+ rData.SetTabRel(true);
+ }
+
+private:
+ shared_ptr<OUStringBuffer> mpRangeStr;
+ ScDocument* mpDoc;
+ static const sal_Unicode mcRangeSep = ' ';
+ static const sal_Unicode mcAddrSep = ':';
+ bool mbFirst;
+};
+
+void lcl_convertTokensToString(OUString& rStr, const vector<ScTokenRef>& rTokens, ScDocument& rDoc)
+{
+ const sal_Unicode cRangeSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ FormulaGrammar::Grammar eGrammar = rDoc.GetGrammar();
+ Tokens2RangeString func(rDoc, eGrammar, cRangeSep);
+ func = ::std::for_each(rTokens.begin(), rTokens.end(), func);
+ func.getString(rStr);
+}
+
+} // anonymous namespace
+
+// DataProvider ==============================================================
+
+ScChart2DataProvider::ScChart2DataProvider( ScDocument* pDoc )
+ : m_pDocument( pDoc)
+ , m_aPropSet(lcl_GetDataProviderPropertyMap())
+ , m_bIncludeHiddenCells( true)
+{
+ if ( m_pDocument )
+ m_pDocument->AddUnoObject( *this);
+}
+
+ScChart2DataProvider::~ScChart2DataProvider()
+{
+ SolarMutexGuard g;
+
+ if ( m_pDocument )
+ m_pDocument->RemoveUnoObject( *this);
+}
+
+void ScChart2DataProvider::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ m_pDocument = nullptr;
+ }
+}
+
+sal_Bool SAL_CALL ScChart2DataProvider::createDataSourcePossible( const uno::Sequence< beans::PropertyValue >& aArguments )
+{
+ SolarMutexGuard aGuard;
+ if( ! m_pDocument )
+ return false;
+
+ OUString aRangeRepresentation;
+ for(const auto& rArgument : aArguments)
+ {
+ if ( rArgument.Name == "CellRangeRepresentation" )
+ {
+ rArgument.Value >>= aRangeRepresentation;
+ }
+ }
+
+ vector<ScTokenRef> aTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ return !aTokens.empty();
+}
+
+namespace
+{
+
+uno::Reference< chart2::data::XLabeledDataSequence > lcl_createLabeledDataSequenceFromTokens(
+ vector< ScTokenRef > && aValueTokens, vector< ScTokenRef > && aLabelTokens,
+ ScDocument* pDoc, bool bIncludeHiddenCells )
+{
+ uno::Reference< chart2::data::XLabeledDataSequence > xResult;
+ bool bHasValues = !aValueTokens.empty();
+ bool bHasLabel = !aLabelTokens.empty();
+ if( bHasValues || bHasLabel )
+ {
+ try
+ {
+ uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+ if ( xContext.is() )
+ {
+ xResult.set( chart2::data::LabeledDataSequence::create(xContext), uno::UNO_QUERY_THROW );
+ }
+ if ( bHasValues )
+ {
+ uno::Reference< chart2::data::XDataSequence > xSeq( new ScChart2DataSequence( pDoc, std::move(aValueTokens), bIncludeHiddenCells ) );
+ xResult->setValues( xSeq );
+ }
+ if ( bHasLabel )
+ {
+ //Labels should always include hidden cells, regardless of the bIncludeHiddenCells setting
+ uno::Reference< chart2::data::XDataSequence > xLabelSeq( new ScChart2DataSequence( pDoc, std::move(aLabelTokens), true ) );
+ xResult->setLabel( xLabelSeq );
+ }
+ }
+ catch( const uno::Exception& )
+ {
+ }
+ }
+ return xResult;
+}
+
+/**
+ * Check the current list of reference tokens, and add the upper left
+ * corner of the minimum range that encloses all ranges if certain
+ * conditions are met.
+ *
+ * @param rRefTokens list of reference tokens
+ *
+ * @return true if the corner was added, false otherwise.
+ */
+bool lcl_addUpperLeftCornerIfMissing(const ScDocument* pDoc, vector<ScTokenRef>& rRefTokens,
+ SCROW nCornerRowCount, SCCOL nCornerColumnCount)
+{
+ using ::std::max;
+ using ::std::min;
+
+ if (rRefTokens.empty())
+ return false;
+
+ SCCOL nMinCol = pDoc->GetSheetLimits().GetMaxColCount();
+ SCROW nMinRow = pDoc->GetSheetLimits().GetMaxRowCount();
+ SCCOL nMaxCol = 0;
+ SCROW nMaxRow = 0;
+ SCTAB nTab = 0;
+
+ sal_uInt16 nFileId = 0;
+ svl::SharedString aExtTabName;
+ bool bExternal = false;
+
+ vector<ScTokenRef>::const_iterator itr = rRefTokens.begin(), itrEnd = rRefTokens.end();
+
+ // Get the first ref token.
+ ScTokenRef pToken = *itr;
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ {
+ const ScSingleRefData& rData = *pToken->GetSingleRef();
+ nMinCol = rData.Col();
+ nMinRow = rData.Row();
+ nMaxCol = rData.Col();
+ nMaxRow = rData.Row();
+ nTab = rData.Tab();
+ }
+ break;
+ case svDoubleRef:
+ {
+ const ScComplexRefData& rData = *pToken->GetDoubleRef();
+ nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
+ nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
+ nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
+ nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
+ nTab = rData.Ref1.Tab();
+ }
+ break;
+ case svExternalSingleRef:
+ {
+ const ScSingleRefData& rData = *pToken->GetSingleRef();
+ nMinCol = rData.Col();
+ nMinRow = rData.Row();
+ nMaxCol = rData.Col();
+ nMaxRow = rData.Row();
+ nTab = rData.Tab();
+ nFileId = pToken->GetIndex();
+ aExtTabName = pToken->GetString();
+ bExternal = true;
+ }
+ break;
+ case svExternalDoubleRef:
+ {
+ const ScComplexRefData& rData = *pToken->GetDoubleRef();
+ nMinCol = min(rData.Ref1.Col(), rData.Ref2.Col());
+ nMinRow = min(rData.Ref1.Row(), rData.Ref2.Row());
+ nMaxCol = max(rData.Ref1.Col(), rData.Ref2.Col());
+ nMaxRow = max(rData.Ref1.Row(), rData.Ref2.Row());
+ nTab = rData.Ref1.Tab();
+ nFileId = pToken->GetIndex();
+ aExtTabName = pToken->GetString();
+ bExternal = true;
+ }
+ break;
+ default:
+ ;
+ }
+
+ // Determine the minimum range enclosing all data ranges. Also make sure
+ // that they are all on the same table.
+
+ for (++itr; itr != itrEnd; ++itr)
+ {
+ pToken = *itr;
+ switch (pToken->GetType())
+ {
+ case svSingleRef:
+ {
+ const ScSingleRefData& rData = *pToken->GetSingleRef();
+
+ nMinCol = min(nMinCol, rData.Col());
+ nMinRow = min(nMinRow, rData.Row());
+ nMaxCol = max(nMaxCol, rData.Col());
+ nMaxRow = max(nMaxRow, rData.Row());
+ if (nTab != rData.Tab() || bExternal)
+ return false;
+ }
+ break;
+ case svDoubleRef:
+ {
+ const ScComplexRefData& rData = *pToken->GetDoubleRef();
+
+ nMinCol = min(nMinCol, rData.Ref1.Col());
+ nMinCol = min(nMinCol, rData.Ref2.Col());
+ nMinRow = min(nMinRow, rData.Ref1.Row());
+ nMinRow = min(nMinRow, rData.Ref2.Row());
+
+ nMaxCol = max(nMaxCol, rData.Ref1.Col());
+ nMaxCol = max(nMaxCol, rData.Ref2.Col());
+ nMaxRow = max(nMaxRow, rData.Ref1.Row());
+ nMaxRow = max(nMaxRow, rData.Ref2.Row());
+
+ if (nTab != rData.Ref1.Tab() || bExternal)
+ return false;
+ }
+ break;
+ case svExternalSingleRef:
+ {
+ if (!bExternal)
+ return false;
+
+ if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
+ return false;
+
+ const ScSingleRefData& rData = *pToken->GetSingleRef();
+
+ nMinCol = min(nMinCol, rData.Col());
+ nMinRow = min(nMinRow, rData.Row());
+ nMaxCol = max(nMaxCol, rData.Col());
+ nMaxRow = max(nMaxRow, rData.Row());
+ }
+ break;
+ case svExternalDoubleRef:
+ {
+ if (!bExternal)
+ return false;
+
+ if (nFileId != pToken->GetIndex() || aExtTabName != pToken->GetString())
+ return false;
+
+ const ScComplexRefData& rData = *pToken->GetDoubleRef();
+
+ nMinCol = min(nMinCol, rData.Ref1.Col());
+ nMinCol = min(nMinCol, rData.Ref2.Col());
+ nMinRow = min(nMinRow, rData.Ref1.Row());
+ nMinRow = min(nMinRow, rData.Ref2.Row());
+
+ nMaxCol = max(nMaxCol, rData.Ref1.Col());
+ nMaxCol = max(nMaxCol, rData.Ref2.Col());
+ nMaxRow = max(nMaxRow, rData.Ref1.Row());
+ nMaxRow = max(nMaxRow, rData.Ref2.Row());
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+ const auto & rSheetLimits = pDoc->GetSheetLimits();
+ if (nMinRow >= nMaxRow || nMinCol >= nMaxCol ||
+ nMinRow >= rSheetLimits.GetMaxRowCount() || nMinCol >= rSheetLimits.GetMaxColCount() ||
+ nMaxRow >= rSheetLimits.GetMaxRowCount() || nMaxCol >= rSheetLimits.GetMaxColCount())
+ {
+ // Invalid range. Bail out.
+ return false;
+ }
+
+ // Check if the following conditions are met:
+
+ // 1) The upper-left corner cell is not included.
+ // 2) The three adjacent cells of that corner cell are included.
+
+ bool bRight = false, bBottom = false, bDiagonal = false;
+ for (const auto& rxToken : rRefTokens)
+ {
+ switch (rxToken->GetType())
+ {
+ case svSingleRef:
+ case svExternalSingleRef:
+ {
+ const ScSingleRefData& rData = *rxToken->GetSingleRef();
+ if (rData.Col() == nMinCol && rData.Row() == nMinRow)
+ // The corner cell is contained.
+ return false;
+
+ if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow)
+ bRight = true;
+
+ if (rData.Col() == nMinCol && rData.Row() == nMinRow+nCornerRowCount)
+ bBottom = true;
+
+ if (rData.Col() == nMinCol+nCornerColumnCount && rData.Row() == nMinRow+nCornerRowCount)
+ bDiagonal = true;
+ }
+ break;
+ case svDoubleRef:
+ case svExternalDoubleRef:
+ {
+ const ScComplexRefData& rData = *rxToken->GetDoubleRef();
+ const ScSingleRefData& r1 = rData.Ref1;
+ const ScSingleRefData& r2 = rData.Ref2;
+ if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
+ r1.Row() <= nMinRow && nMinRow <= r2.Row())
+ // The corner cell is contained.
+ return false;
+
+ if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
+ r1.Row() <= nMinRow && nMinRow <= r2.Row())
+ bRight = true;
+
+ if (r1.Col() <= nMinCol && nMinCol <= r2.Col() &&
+ r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
+ bBottom = true;
+
+ if (r1.Col() <= nMinCol+nCornerColumnCount && nMinCol+nCornerColumnCount <= r2.Col() &&
+ r1.Row() <= nMinRow+nCornerRowCount && nMinRow+nCornerRowCount <= r2.Row())
+ bDiagonal = true;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+ if (!bRight || !bBottom || !bDiagonal)
+ // Not all the adjacent cells are included. Bail out.
+ return false;
+
+ ScSingleRefData aData;
+ aData.InitFlags();
+ aData.SetFlag3D(true);
+ aData.SetAbsCol(nMinCol);
+ aData.SetAbsRow(nMinRow);
+ aData.SetAbsTab(nTab);
+
+ if( nCornerRowCount==1 && nCornerColumnCount==1 )
+ {
+ if (bExternal)
+ {
+ ScTokenRef pCorner(
+ new ScExternalSingleRefToken(nFileId, aExtTabName, aData));
+ ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
+ }
+ else
+ {
+ ScTokenRef pCorner(new ScSingleRefToken(pDoc->GetSheetLimits(), aData));
+ ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
+ }
+ }
+ else
+ {
+ ScSingleRefData aDataEnd(aData);
+ aDataEnd.IncCol(nCornerColumnCount-1);
+ aDataEnd.IncRow(nCornerRowCount-1);
+ ScComplexRefData r;
+ r.Ref1=aData;
+ r.Ref2=aDataEnd;
+ if (bExternal)
+ {
+ ScTokenRef pCorner(
+ new ScExternalDoubleRefToken(nFileId, aExtTabName, r));
+ ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
+ }
+ else
+ {
+ ScTokenRef pCorner(new ScDoubleRefToken(pDoc->GetSheetLimits(), r));
+ ScRefTokenHelper::join(pDoc, rRefTokens, pCorner, ScAddress());
+ }
+ }
+
+ return true;
+}
+
+#define SHRINK_RANGE_THRESHOLD 10000
+
+class ShrinkRefTokenToDataRange
+{
+ ScDocument* mpDoc;
+public:
+ explicit ShrinkRefTokenToDataRange(ScDocument* pDoc) : mpDoc(pDoc) {}
+ void operator() (const ScTokenRef& rRef)
+ {
+ if (ScRefTokenHelper::isExternalRef(rRef))
+ return;
+
+ // Don't assume an ScDoubleRefToken if it isn't. It can be at least an
+ // ScSingleRefToken, then there isn't anything to shrink.
+ if (rRef->GetType() != svDoubleRef)
+ return;
+
+ ScComplexRefData& rData = *rRef->GetDoubleRef();
+ ScSingleRefData& s = rData.Ref1;
+ ScSingleRefData& e = rData.Ref2;
+
+ if(abs((e.Col()-s.Col())*(e.Row()-s.Row())) < SHRINK_RANGE_THRESHOLD)
+ return;
+
+ SCCOL nMinCol = mpDoc->MaxCol(), nMaxCol = 0;
+ SCROW nMinRow = mpDoc->MaxRow(), nMaxRow = 0;
+
+ // Determine the smallest range that encompasses the data ranges of all sheets.
+ SCTAB nTab1 = s.Tab(), nTab2 = e.Tab();
+ for (SCTAB nTab = nTab1; nTab <= nTab2; ++nTab)
+ {
+ SCCOL nCol1 = 0, nCol2 = mpDoc->MaxCol();
+ SCROW nRow1 = 0, nRow2 = mpDoc->MaxRow();
+ mpDoc->ShrinkToDataArea(nTab, nCol1, nRow1, nCol2, nRow2);
+ nMinCol = std::min(nMinCol, nCol1);
+ nMinRow = std::min(nMinRow, nRow1);
+ nMaxCol = std::max(nMaxCol, nCol2);
+ nMaxRow = std::max(nMaxRow, nRow2);
+ }
+
+ // Shrink range to the data range if applicable.
+ if (s.Col() < nMinCol)
+ s.SetAbsCol(nMinCol);
+ if (s.Row() < nMinRow)
+ s.SetAbsRow(nMinRow);
+ if (e.Col() > nMaxCol)
+ e.SetAbsCol(nMaxCol);
+ if (e.Row() > nMaxRow)
+ e.SetAbsRow(nMaxRow);
+ }
+};
+
+void shrinkToDataRange(ScDocument* pDoc, vector<ScTokenRef>& rRefTokens)
+{
+ std::for_each(rRefTokens.begin(), rRefTokens.end(), ShrinkRefTokenToDataRange(pDoc));
+}
+
+}
+
+uno::Reference< chart2::data::XDataSource> SAL_CALL
+ScChart2DataProvider::createDataSource(
+ const uno::Sequence< beans::PropertyValue >& aArguments )
+{
+ SolarMutexGuard aGuard;
+ if ( ! m_pDocument )
+ throw uno::RuntimeException();
+
+ uno::Reference< chart2::data::XDataSource> xResult;
+ bool bLabel = true;
+ bool bCategories = false;
+ bool bOrientCol = true;
+ OUString aRangeRepresentation;
+ uno::Sequence< sal_Int32 > aSequenceMapping;
+ bool bTimeBased = false;
+ for(const auto& rArgument : aArguments)
+ {
+ if ( rArgument.Name == "DataRowSource" )
+ {
+ chart::ChartDataRowSource eSource = chart::ChartDataRowSource_COLUMNS;
+ if( ! (rArgument.Value >>= eSource))
+ {
+ sal_Int32 nSource(0);
+ if( rArgument.Value >>= nSource )
+ eSource = static_cast< chart::ChartDataRowSource >( nSource );
+ }
+ bOrientCol = (eSource == chart::ChartDataRowSource_COLUMNS);
+ }
+ else if ( rArgument.Name == "FirstCellAsLabel" )
+ {
+ bLabel = ::cppu::any2bool(rArgument.Value);
+ }
+ else if ( rArgument.Name == "HasCategories" )
+ {
+ bCategories = ::cppu::any2bool(rArgument.Value);
+ }
+ else if ( rArgument.Name == "CellRangeRepresentation" )
+ {
+ rArgument.Value >>= aRangeRepresentation;
+ }
+ else if ( rArgument.Name == "SequenceMapping" )
+ {
+ rArgument.Value >>= aSequenceMapping;
+ }
+ else if ( rArgument.Name == "TimeBased" )
+ {
+ rArgument.Value >>= bTimeBased;
+ }
+ }
+
+ vector<ScTokenRef> aRefTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ if (aRefTokens.empty())
+ // Invalid range representation. Bail out.
+ throw lang::IllegalArgumentException();
+
+ SCTAB nTimeBasedStart = MAXTAB;
+ SCTAB nTimeBasedEnd = 0;
+ if(bTimeBased)
+ {
+ // limit to first sheet
+ for(const auto& rxToken : aRefTokens)
+ {
+ if (rxToken->GetType() != svDoubleRef)
+ continue;
+
+ ScComplexRefData& rData = *rxToken->GetDoubleRef();
+ ScSingleRefData& s = rData.Ref1;
+ ScSingleRefData& e = rData.Ref2;
+
+ nTimeBasedStart = std::min(nTimeBasedStart, s.Tab());
+ nTimeBasedEnd = std::min(nTimeBasedEnd, e.Tab());
+
+ if(s.Tab() != e.Tab())
+ e.SetAbsTab(s.Tab());
+ }
+ }
+
+ if(!bTimeBased)
+ shrinkToDataRange(m_pDocument, aRefTokens);
+
+ if (bLabel)
+ lcl_addUpperLeftCornerIfMissing(m_pDocument, aRefTokens, 1, 1); //#i90669#
+
+ bool bColHeaders = (bOrientCol ? bLabel : bCategories );
+ bool bRowHeaders = (bOrientCol ? bCategories : bLabel );
+
+ Chart2Positioner aChPositioner(m_pDocument, aRefTokens);
+ aChPositioner.setHeaders(bColHeaders, bRowHeaders);
+
+ const Chart2PositionMap* pChartMap = aChPositioner.getPositionMap();
+ if (!pChartMap)
+ // No chart position map instance. Bail out.
+ return xResult;
+
+ rtl::Reference<ScChart2DataSource> pDS;
+ ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqs;
+
+ // Fill Categories
+ if( bCategories )
+ {
+ vector<ScTokenRef> aValueTokens;
+ if (bOrientCol)
+ aValueTokens = pChartMap->getAllRowHeaderRanges();
+ else
+ aValueTokens = pChartMap->getAllColHeaderRanges();
+
+ vector<ScTokenRef> aLabelTokens(
+ pChartMap->getLeftUpperCornerRanges());
+
+ uno::Reference< chart2::data::XLabeledDataSequence > xCategories = lcl_createLabeledDataSequenceFromTokens(
+ std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
+ if ( xCategories.is() )
+ {
+ aSeqs.push_back( xCategories );
+ }
+ }
+
+ // Fill Series (values and label)
+ sal_Int32 nCount = bOrientCol ? pChartMap->getDataColCount() : pChartMap->getDataRowCount();
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ vector<ScTokenRef> aValueTokens;
+ vector<ScTokenRef> aLabelTokens;
+ if (bOrientCol)
+ {
+ aValueTokens = pChartMap->getDataColRanges(static_cast<SCCOL>(i));
+ aLabelTokens = pChartMap->getColHeaderRanges(static_cast<SCCOL>(i));
+ }
+ else
+ {
+ aValueTokens = pChartMap->getDataRowRanges(static_cast<SCROW>(i));
+ aLabelTokens = pChartMap->getRowHeaderRanges(static_cast<SCROW>(i));
+ }
+ uno::Reference< chart2::data::XLabeledDataSequence > xChartSeries = lcl_createLabeledDataSequenceFromTokens(
+ std::move(aValueTokens), std::move(aLabelTokens), m_pDocument, m_bIncludeHiddenCells ); //ownership of pointers is transferred!
+ if ( xChartSeries.is() && xChartSeries->getValues().is() && xChartSeries->getValues()->getData().hasElements() )
+ {
+ aSeqs.push_back( xChartSeries );
+ }
+ }
+
+ pDS = new ScChart2DataSource(m_pDocument);
+
+ //reorder labeled sequences according to aSequenceMapping
+ ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > > aSeqVector;
+ aSeqVector.reserve(aSeqs.size());
+ for (auto const& aSeq : aSeqs)
+ {
+ aSeqVector.push_back(aSeq);
+ }
+
+ for( const sal_Int32 nNewIndex : std::as_const(aSequenceMapping) )
+ {
+ // note: assuming that the values in the sequence mapping are always non-negative
+ ::std::vector< uno::Reference< chart2::data::XLabeledDataSequence > >::size_type nOldIndex( static_cast< sal_uInt32 >( nNewIndex ) );
+ if( nOldIndex < aSeqVector.size() )
+ {
+ pDS->AddLabeledSequence( aSeqVector[nOldIndex] );
+ aSeqVector[nOldIndex] = nullptr;
+ }
+ }
+
+ for(const uno::Reference< chart2::data::XLabeledDataSequence >& xSeq : aSeqVector)
+ {
+ if ( xSeq.is() )
+ {
+ pDS->AddLabeledSequence( xSeq );
+ }
+ }
+
+ xResult.set( pDS );
+ return xResult;
+}
+
+namespace
+{
+
+/**
+ * Function object to create a list of table numbers from a token list.
+ */
+class InsertTabNumber
+{
+public:
+ InsertTabNumber() :
+ mpTabNumVector(std::make_shared<vector<SCTAB>>())
+ {
+ }
+
+ void operator() (const ScTokenRef& pToken) const
+ {
+ if (!ScRefTokenHelper::isRef(pToken))
+ return;
+
+ const ScSingleRefData& r = *pToken->GetSingleRef();
+ mpTabNumVector->push_back(r.Tab());
+ }
+
+ void getVector(vector<SCTAB>& rVector)
+ {
+ mpTabNumVector->swap(rVector);
+ }
+private:
+ shared_ptr< vector<SCTAB> > mpTabNumVector;
+};
+
+class RangeAnalyzer
+{
+public:
+ RangeAnalyzer();
+ void initRangeAnalyzer( const ScDocument* pDoc, const vector<ScTokenRef>& rTokens );
+ void analyzeRange( sal_Int32& rnDataInRows, sal_Int32& rnDataInCols,
+ bool& rbRowSourceAmbiguous ) const;
+ bool inSameSingleRow( const RangeAnalyzer& rOther );
+ bool inSameSingleColumn( const RangeAnalyzer& rOther );
+ SCROW getRowCount() const { return mnRowCount; }
+ SCCOL getColumnCount() const { return mnColumnCount; }
+
+private:
+ bool mbEmpty;
+ bool mbAmbiguous;
+ SCROW mnRowCount;
+ SCCOL mnColumnCount;
+
+ SCCOL mnStartColumn;
+ SCROW mnStartRow;
+};
+
+RangeAnalyzer::RangeAnalyzer()
+ : mbEmpty(true)
+ , mbAmbiguous(false)
+ , mnRowCount(0)
+ , mnColumnCount(0)
+ , mnStartColumn(-1)
+ , mnStartRow(-1)
+{
+}
+
+void RangeAnalyzer::initRangeAnalyzer( const ScDocument* pDoc, const vector<ScTokenRef>& rTokens )
+{
+ mnRowCount=0;
+ mnColumnCount=0;
+ mnStartColumn = -1;
+ mnStartRow = -1;
+ mbAmbiguous=false;
+ if( rTokens.empty() )
+ {
+ mbEmpty=true;
+ return;
+ }
+ mbEmpty=false;
+
+ for (const ScTokenRef& aRefToken : rTokens)
+ {
+ StackVar eVar = aRefToken->GetType();
+ if (eVar == svDoubleRef || eVar == svExternalDoubleRef)
+ {
+ const ScComplexRefData& r = *aRefToken->GetDoubleRef();
+ if (r.Ref1.Tab() == r.Ref2.Tab())
+ {
+ mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(r.Ref2.Col() - r.Ref1.Col())+1));
+ mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(r.Ref2.Row() - r.Ref1.Row())+1));
+ if( mnStartColumn == -1 )
+ {
+ mnStartColumn = r.Ref1.Col();
+ mnStartRow = r.Ref1.Row();
+ }
+ else
+ {
+ if (mnStartColumn != r.Ref1.Col() && mnStartRow != r.Ref1.Row())
+ mbAmbiguous=true;
+ }
+ }
+ else
+ mbAmbiguous=true;
+ }
+ else if (eVar == svSingleRef || eVar == svExternalSingleRef)
+ {
+ const ScSingleRefData& r = *aRefToken->GetSingleRef();
+ mnColumnCount = std::max<SCCOL>( mnColumnCount, 1);
+ mnRowCount = std::max<SCROW>( mnRowCount, 1);
+ if( mnStartColumn == -1 )
+ {
+ mnStartColumn = r.Col();
+ mnStartRow = r.Row();
+ }
+ else
+ {
+ if (mnStartColumn != r.Col() && mnStartRow != r.Row())
+ mbAmbiguous=true;
+ }
+ }
+ else if (eVar == svIndex && aRefToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = pDoc->FindRangeNameBySheetAndIndex(aRefToken->GetSheet(), aRefToken->GetIndex());
+ ScRange aRange;
+ if (pNameRange->IsReference(aRange))
+ {
+ mnColumnCount = std::max<SCCOL>(mnColumnCount, static_cast<SCCOL>(abs(aRange.aEnd.Col() - aRange.aStart.Col()) + 1));
+ mnRowCount = std::max<SCROW>(mnRowCount, static_cast<SCROW>(abs(aRange.aEnd.Row() - aRange.aStart.Row()) + 1));
+ if (mnStartColumn == -1)
+ {
+ mnStartColumn = aRange.aStart.Col();
+ mnStartRow = aRange.aStart.Row();
+ }
+ else
+ {
+ if (mnStartColumn != aRange.aStart.Col() && mnStartRow != aRange.aStart.Row())
+ mbAmbiguous = true;
+ }
+ }
+ else
+ mbAmbiguous = true;
+ }
+ else
+ mbAmbiguous=true;
+ }
+}
+
+void RangeAnalyzer::analyzeRange( sal_Int32& rnDataInRows,
+ sal_Int32& rnDataInCols,
+ bool& rbRowSourceAmbiguous ) const
+{
+ if(!mbEmpty && !mbAmbiguous)
+ {
+ if( mnRowCount==1 && mnColumnCount>1 )
+ ++rnDataInRows;
+ else if( mnColumnCount==1 && mnRowCount>1 )
+ ++rnDataInCols;
+ else if( mnRowCount>1 && mnColumnCount>1 )
+ rbRowSourceAmbiguous = true;
+ }
+ else if( !mbEmpty )
+ rbRowSourceAmbiguous = true;
+}
+
+bool RangeAnalyzer::inSameSingleRow( const RangeAnalyzer& rOther )
+{
+ return mnStartRow==rOther.mnStartRow &&
+ mnRowCount==1 && rOther.mnRowCount==1;
+}
+
+bool RangeAnalyzer::inSameSingleColumn( const RangeAnalyzer& rOther )
+{
+ return mnStartColumn==rOther.mnStartColumn &&
+ mnColumnCount==1 && rOther.mnColumnCount==1;
+}
+
+std::pair<OUString, OUString> constructKey(const uno::Reference< chart2::data::XLabeledDataSequence>& xNew)
+{
+ std::pair<OUString, OUString> aKey;
+ if( xNew->getLabel().is() )
+ aKey.first = xNew->getLabel()->getSourceRangeRepresentation();
+ if( xNew->getValues().is() )
+ aKey.second = xNew->getValues()->getSourceRangeRepresentation();
+ return aKey;
+}
+
+
+} //end anonymous namespace
+
+uno::Sequence< beans::PropertyValue > SAL_CALL ScChart2DataProvider::detectArguments(
+ const uno::Reference< chart2::data::XDataSource >& xDataSource )
+{
+ ::std::vector< beans::PropertyValue > aResult;
+ bool bRowSourceDetected = false;
+ bool bFirstCellAsLabel = false;
+ bool bHasCategories = false;
+ OUString sRangeRep;
+
+ bool bHasCategoriesLabels = false;
+ vector<ScTokenRef> aAllCategoriesValuesTokens;
+ vector<ScTokenRef> aAllSeriesLabelTokens;
+
+ chart::ChartDataRowSource eRowSource = chart::ChartDataRowSource_COLUMNS;
+
+ vector<ScTokenRef> aAllTokens;
+
+ // parse given data source and collect infos
+ {
+ SolarMutexGuard aGuard;
+ OSL_ENSURE( m_pDocument, "No Document -> no detectArguments" );
+ if(!m_pDocument ||!xDataSource.is())
+ return comphelper::containerToSequence( aResult );
+
+ sal_Int32 nDataInRows = 0;
+ sal_Int32 nDataInCols = 0;
+ bool bRowSourceAmbiguous = false;
+
+ const Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences( xDataSource->getDataSequences());
+ const sal_Int32 nCount( aSequences.getLength());
+ RangeAnalyzer aPrevLabel,aPrevValues;
+ for( const uno::Reference< chart2::data::XLabeledDataSequence >& xLS : aSequences )
+ {
+ if( xLS.is() )
+ {
+ bool bThisIsCategories = false;
+ if(!bHasCategories)
+ {
+ uno::Reference< beans::XPropertySet > xSeqProp( xLS->getValues(), uno::UNO_QUERY );
+ OUString aRole;
+ if( xSeqProp.is() && (xSeqProp->getPropertyValue("Role") >>= aRole) &&
+ aRole == "categories" )
+ bThisIsCategories = bHasCategories = true;
+ }
+
+ RangeAnalyzer aLabel,aValues;
+ // label
+ uno::Reference< chart2::data::XDataSequence > xLabel( xLS->getLabel());
+ if( xLabel.is())
+ {
+ bFirstCellAsLabel = true;
+ vector<ScTokenRef> aTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aTokens, xLabel->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ aLabel.initRangeAnalyzer(m_pDocument, aTokens);
+ for (const auto& rxToken : aTokens)
+ {
+ if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
+ if (pNameRange->HasReferences())
+ {
+ const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ if(!bThisIsCategories)
+ ScRefTokenHelper::join(m_pDocument, aAllSeriesLabelTokens, rxToken, ScAddress());
+ }
+ if(bThisIsCategories)
+ bHasCategoriesLabels=true;
+ }
+ // values
+ uno::Reference< chart2::data::XDataSequence > xValues( xLS->getValues());
+ if( xValues.is())
+ {
+ vector<ScTokenRef> aTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aTokens, xValues->getSourceRangeRepresentation(), *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ aValues.initRangeAnalyzer(m_pDocument, aTokens);
+ for (const auto& rxToken : aTokens)
+ {
+ if (rxToken->GetType() == svIndex && rxToken->GetOpCode() == ocName)
+ {
+ ScRangeData* pNameRange = m_pDocument->FindRangeNameBySheetAndIndex(rxToken->GetSheet(), rxToken->GetIndex());
+ if (pNameRange->HasReferences())
+ {
+ const ScTokenRef aTempToken = pNameRange->GetCode()->FirstToken();
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, aTempToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ }
+ else
+ ScRefTokenHelper::join(m_pDocument, aAllTokens, rxToken, ScAddress());
+ if(bThisIsCategories)
+ ScRefTokenHelper::join(m_pDocument, aAllCategoriesValuesTokens, rxToken, ScAddress());
+ }
+ }
+ //detect row source
+ if(!bThisIsCategories || nCount==1) //categories might span multiple rows *and* columns, so they should be used for detection only if nothing else is available
+ {
+ if (!bRowSourceAmbiguous)
+ {
+ aValues.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
+ aLabel.analyzeRange(nDataInRows,nDataInCols,bRowSourceAmbiguous);
+ if (nDataInRows > 1 && nDataInCols > 1)
+ bRowSourceAmbiguous = true;
+ else if( !bRowSourceAmbiguous && !nDataInRows && !nDataInCols )
+ {
+ if( aValues.inSameSingleColumn( aLabel ) )
+ nDataInCols++;
+ else if( aValues.inSameSingleRow( aLabel ) )
+ nDataInRows++;
+ else
+ {
+ //#i86188# also detect a single column split into rows correctly
+ if( aValues.inSameSingleColumn( aPrevValues ) )
+ nDataInRows++;
+ else if( aValues.inSameSingleRow( aPrevValues ) )
+ nDataInCols++;
+ else if( aLabel.inSameSingleColumn( aPrevLabel ) )
+ nDataInRows++;
+ else if( aLabel.inSameSingleRow( aPrevLabel ) )
+ nDataInCols++;
+ }
+ }
+ }
+ }
+ aPrevValues=aValues;
+ aPrevLabel=aLabel;
+ }
+ }
+
+ if (!bRowSourceAmbiguous)
+ {
+ bRowSourceDetected = true;
+ eRowSource = ( nDataInCols > 0
+ ? chart::ChartDataRowSource_COLUMNS
+ : chart::ChartDataRowSource_ROWS );
+ }
+ else
+ {
+ // set DataRowSource to the better of the two ambiguities
+ eRowSource = ( nDataInRows > nDataInCols
+ ? chart::ChartDataRowSource_ROWS
+ : chart::ChartDataRowSource_COLUMNS );
+ }
+
+ }
+
+ // TableNumberList
+ {
+ vector<SCTAB> aTableNumVector;
+ InsertTabNumber func;
+ func = ::std::for_each(aAllTokens.begin(), aAllTokens.end(), func);
+ func.getVector(aTableNumVector);
+ aResult.emplace_back( "TableNumberList", -1,
+ uno::Any( lcl_createTableNumberList( aTableNumVector ) ),
+ beans::PropertyState_DIRECT_VALUE );
+ }
+
+ if( bRowSourceDetected )
+ {
+ // DataRowSource (calculated before)
+ aResult.emplace_back( "DataRowSource", -1,
+ uno::Any( eRowSource ), beans::PropertyState_DIRECT_VALUE );
+ // HasCategories
+ aResult.emplace_back( "HasCategories", -1,
+ uno::Any( bHasCategories ), beans::PropertyState_DIRECT_VALUE );
+ // FirstCellAsLabel
+ aResult.emplace_back( "FirstCellAsLabel", -1,
+ uno::Any( bFirstCellAsLabel ), beans::PropertyState_DIRECT_VALUE );
+ }
+
+ // Add the left upper corner to the range if it is missing.
+ if (bRowSourceDetected && bFirstCellAsLabel && bHasCategories && !bHasCategoriesLabels )
+ {
+ RangeAnalyzer aTop,aLeft;
+ if( eRowSource==chart::ChartDataRowSource_COLUMNS )
+ {
+ aTop.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
+ aLeft.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
+ }
+ else
+ {
+ aTop.initRangeAnalyzer(m_pDocument, aAllCategoriesValuesTokens);
+ aLeft.initRangeAnalyzer(m_pDocument, aAllSeriesLabelTokens);
+ }
+ lcl_addUpperLeftCornerIfMissing(m_pDocument, aAllTokens, aTop.getRowCount(), aLeft.getColumnCount());//e.g. #i91212#
+ }
+
+ // Get range string.
+ lcl_convertTokensToString(sRangeRep, aAllTokens, *m_pDocument);
+
+ // add cell range property
+ aResult.emplace_back( "CellRangeRepresentation", -1,
+ uno::Any( sRangeRep ), beans::PropertyState_DIRECT_VALUE );
+
+ //Sequence Mapping
+ bool const bSequencesReordered = true;//todo detect this above or detect this sequence mapping cheaper ...
+ if( bSequencesReordered && bRowSourceDetected )
+ {
+ bool bDifferentIndexes = false;
+
+ std::vector< sal_Int32 > aSequenceMappingVector;
+
+ uno::Reference< chart2::data::XDataSource > xCompareDataSource;
+ try
+ {
+ xCompareDataSource.set( createDataSource( comphelper::containerToSequence( aResult ) ) );
+ }
+ catch( const lang::IllegalArgumentException & )
+ {
+ // creation of data source to compare didn't work, so we cannot
+ // create a sequence mapping
+ }
+
+ if( xDataSource.is() && xCompareDataSource.is() )
+ {
+ const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aOldSequences =
+ xCompareDataSource->getDataSequences();
+ const uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> >& aNewSequences =
+ xDataSource->getDataSequences();
+
+ std::map<std::pair<OUString, OUString>,sal_Int32> aOldEntryToIndex;
+ for( sal_Int32 nIndex = 0, n = aOldSequences.getLength(); nIndex < n; nIndex++ )
+ {
+ const uno::Reference< chart2::data::XLabeledDataSequence>& xOld( aOldSequences[nIndex] );
+ if( xOld.is() )
+ {
+ std::pair<OUString, OUString> aKey = constructKey(xOld);
+ aOldEntryToIndex[aKey] = nIndex;
+ }
+ }
+
+ for( sal_Int32 nNewIndex = 0, n = aNewSequences.getLength(); nNewIndex < n; nNewIndex++ )
+ {
+ const uno::Reference< chart2::data::XLabeledDataSequence>& xNew( aNewSequences[nNewIndex] );
+ if( !xNew.is() )
+ continue;
+
+ std::pair<OUString, OUString> aKey = constructKey(xNew);
+ if (aOldEntryToIndex.find(aKey) == aOldEntryToIndex.end())
+ continue;
+
+ sal_Int32 nOldIndex = aOldEntryToIndex[aKey];
+ if( nOldIndex != nNewIndex )
+ bDifferentIndexes = true;
+
+ aSequenceMappingVector.push_back(nOldIndex);
+ }
+ }
+
+ if( bDifferentIndexes && !aSequenceMappingVector.empty() )
+ {
+ aResult.emplace_back( "SequenceMapping", -1,
+ uno::Any( comphelper::containerToSequence(aSequenceMappingVector) )
+ , beans::PropertyState_DIRECT_VALUE );
+ }
+ }
+
+ return comphelper::containerToSequence( aResult );
+}
+
+sal_Bool SAL_CALL ScChart2DataProvider::createDataSequenceByRangeRepresentationPossible( const OUString& aRangeRepresentation )
+{
+ SolarMutexGuard aGuard;
+ if( ! m_pDocument )
+ return false;
+
+ vector<ScTokenRef> aTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ return !aTokens.empty();
+}
+
+uno::Reference< chart2::data::XDataSequence > SAL_CALL
+ ScChart2DataProvider::createDataSequenceByRangeRepresentation(
+ const OUString& aRangeRepresentation )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< chart2::data::XDataSequence > xResult;
+
+ OSL_ENSURE( m_pDocument, "No Document -> no createDataSequenceByRangeRepresentation" );
+ if(!m_pDocument || aRangeRepresentation.isEmpty())
+ return xResult;
+
+ vector<ScTokenRef> aRefTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aRefTokens, aRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ if (aRefTokens.empty())
+ return xResult;
+
+ shrinkToDataRange(m_pDocument, aRefTokens);
+
+ xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
+
+ return xResult;
+}
+
+uno::Reference<chart2::data::XDataSequence> SAL_CALL
+ScChart2DataProvider::createDataSequenceByValueArray(
+ const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/,
+ const OUString& /*aRoleQualifier*/ )
+{
+ return uno::Reference<chart2::data::XDataSequence>();
+}
+
+uno::Reference< sheet::XRangeSelection > SAL_CALL ScChart2DataProvider::getRangeSelection()
+{
+ uno::Reference< sheet::XRangeSelection > xResult;
+
+ uno::Reference< frame::XModel > xModel( lcl_GetXModel( m_pDocument ));
+ if( xModel.is())
+ xResult.set( xModel->getCurrentController(), uno::UNO_QUERY );
+
+ return xResult;
+}
+
+sal_Bool SAL_CALL ScChart2DataProvider::createDataSequenceByFormulaTokensPossible(
+ const Sequence<sheet::FormulaToken>& aTokens )
+{
+ if (!aTokens.hasElements())
+ return false;
+
+ ScTokenArray aCode(*m_pDocument);
+ if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
+ return false;
+
+ sal_uInt16 n = aCode.GetLen();
+ if (!n)
+ return false;
+
+ formula::FormulaTokenArrayPlainIterator aIter(aCode);
+ const formula::FormulaToken* pFirst = aIter.First();
+ const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
+ for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
+ {
+ switch (p->GetType())
+ {
+ case svSep:
+ {
+ switch (p->GetOpCode())
+ {
+ case ocSep:
+ // separators are allowed.
+ break;
+ case ocOpen:
+ if (p != pFirst)
+ // open paran is allowed only as the first token.
+ return false;
+ break;
+ case ocClose:
+ if (p != pLast)
+ // close paren is allowed only as the last token.
+ return false;
+ break;
+ default:
+ return false;
+ }
+ }
+ break;
+ case svSingleRef:
+ case svDoubleRef:
+ case svExternalSingleRef:
+ case svExternalDoubleRef:
+ break;
+ default:
+ return false;
+ }
+ }
+
+ return true;
+}
+
+uno::Reference<chart2::data::XDataSequence> SAL_CALL
+ScChart2DataProvider::createDataSequenceByFormulaTokens(
+ const Sequence<sheet::FormulaToken>& aTokens )
+{
+ uno::Reference<chart2::data::XDataSequence> xResult;
+ if (!aTokens.hasElements())
+ return xResult;
+
+ ScTokenArray aCode(*m_pDocument);
+ if (!ScTokenConversion::ConvertToTokenArray(*m_pDocument, aCode, aTokens))
+ return xResult;
+
+ sal_uInt16 n = aCode.GetLen();
+ if (!n)
+ return xResult;
+
+ vector<ScTokenRef> aRefTokens;
+ formula::FormulaTokenArrayPlainIterator aIter(aCode);
+ const formula::FormulaToken* pFirst = aIter.First();
+ const formula::FormulaToken* pLast = aCode.GetArray()[n-1];
+ for (const formula::FormulaToken* p = aIter.First(); p; p = aIter.Next())
+ {
+ switch (p->GetType())
+ {
+ case svSep:
+ {
+ switch (p->GetOpCode())
+ {
+ case ocSep:
+ // separators are allowed.
+ break;
+ case ocOpen:
+ if (p != pFirst)
+ // open paran is allowed only as the first token.
+ throw lang::IllegalArgumentException();
+ break;
+ case ocClose:
+ if (p != pLast)
+ // close paren is allowed only as the last token.
+ throw lang::IllegalArgumentException();
+ break;
+ default:
+ throw lang::IllegalArgumentException();
+ }
+ }
+ break;
+ case svIndex:
+ case svString:
+ case svSingleRef:
+ case svDoubleRef:
+ case svExternalSingleRef:
+ case svExternalDoubleRef:
+ {
+ ScTokenRef pNew(p->Clone());
+ aRefTokens.push_back(pNew);
+ }
+ break;
+ default:
+ throw lang::IllegalArgumentException();
+ }
+ }
+
+ if (aRefTokens.empty())
+ return xResult;
+
+ shrinkToDataRange(m_pDocument, aRefTokens);
+
+ xResult.set(new ScChart2DataSequence(m_pDocument, std::move(aRefTokens), m_bIncludeHiddenCells));
+ return xResult;
+}
+
+// XRangeXMLConversion ---------------------------------------------------
+
+OUString SAL_CALL ScChart2DataProvider::convertRangeToXML( const OUString& sRangeRepresentation )
+{
+ OUString aRet;
+ if (!m_pDocument)
+ return aRet;
+
+ if (sRangeRepresentation.isEmpty())
+ // Empty data range is allowed.
+ return aRet;
+
+ vector<ScTokenRef> aRefTokens;
+ const sal_Unicode cSep = ScCompiler::GetNativeSymbolChar(ocSep);
+ ScRefTokenHelper::compileRangeRepresentation(
+ aRefTokens, sRangeRepresentation, *m_pDocument, cSep, m_pDocument->GetGrammar(), true);
+ if (aRefTokens.empty())
+ {
+ SAL_WARN("sc", "convertRangeToXML throw IllegalArgumentException from input of: " << sRangeRepresentation);
+ throw lang::IllegalArgumentException();
+ }
+
+ Tokens2RangeStringXML converter(*m_pDocument);
+ converter = ::std::for_each(aRefTokens.begin(), aRefTokens.end(), converter);
+ converter.getString(aRet);
+
+ return aRet;
+}
+
+OUString SAL_CALL ScChart2DataProvider::convertRangeFromXML( const OUString& sXMLRange )
+{
+ if (!m_pDocument)
+ {
+ // #i74062# When loading flat XML, this is called before the referenced sheets are in the document,
+ // so the conversion has to take place directly with the strings, without looking up the sheets.
+
+ OUStringBuffer sRet;
+ sal_Int32 nOffset = 0;
+ while( nOffset >= 0 )
+ {
+ OUString sToken;
+ ScRangeStringConverter::GetTokenByOffset( sToken, sXMLRange, nOffset );
+ if( nOffset >= 0 )
+ {
+ // convert one address (remove dots)
+
+ OUString aUIString(sToken);
+
+ sal_Int32 nIndex = ScRangeStringConverter::IndexOf( sToken, ':', 0 );
+ if ( nIndex >= 0 && nIndex < aUIString.getLength() - 1 &&
+ aUIString[nIndex + 1] == '.' )
+ aUIString = aUIString.replaceAt( nIndex + 1, 1, u"" );
+
+ if ( aUIString[0] == '.' )
+ aUIString = aUIString.copy( 1 );
+
+ if( !sRet.isEmpty() )
+ sRet.append( ';' );
+ sRet.append( aUIString );
+ }
+ }
+
+ return sRet.makeStringAndClear();
+ }
+
+ OUString aRet;
+ ScRangeStringConverter::GetStringFromXMLRangeString(aRet, sXMLRange, *m_pDocument);
+ return aRet;
+}
+
+// DataProvider XPropertySet -------------------------------------------------
+
+uno::Reference< beans::XPropertySetInfo> SAL_CALL
+ScChart2DataProvider::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL ScChart2DataProvider::setPropertyValue(
+ const OUString& rPropertyName, const uno::Any& rValue)
+{
+ if ( rPropertyName != SC_UNONAME_INCLUDEHIDDENCELLS )
+ throw beans::UnknownPropertyException(rPropertyName);
+
+ if ( !(rValue >>= m_bIncludeHiddenCells))
+ throw lang::IllegalArgumentException();
+
+}
+
+uno::Any SAL_CALL ScChart2DataProvider::getPropertyValue(
+ const OUString& rPropertyName)
+{
+ uno::Any aRet;
+ if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
+ aRet <<= m_bIncludeHiddenCells;
+ else if (rPropertyName == SC_UNONAME_USE_INTERNAL_DATA_PROVIDER)
+ {
+ // This is a read-only property.
+ aRet <<= m_pDocument->PastingDrawFromOtherDoc();
+ }
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+ return aRet;
+}
+
+void SAL_CALL ScChart2DataProvider::addPropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
+{
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataProvider::removePropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
+{
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataProvider::addVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
+{
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataProvider::removeVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/ )
+{
+ OSL_FAIL( "Not yet implemented" );
+}
+
+// DataSource ================================================================
+
+ScChart2DataSource::ScChart2DataSource( ScDocument* pDoc)
+ : m_pDocument( pDoc)
+{
+ if ( m_pDocument )
+ m_pDocument->AddUnoObject( *this);
+}
+
+ScChart2DataSource::~ScChart2DataSource()
+{
+ SolarMutexGuard g;
+
+ if ( m_pDocument )
+ m_pDocument->RemoveUnoObject( *this);
+}
+
+void ScChart2DataSource::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ m_pDocument = nullptr;
+ }
+}
+
+uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence> > SAL_CALL
+ScChart2DataSource::getDataSequences()
+{
+ SolarMutexGuard aGuard;
+ return comphelper::containerToSequence(m_aLabeledSequences);
+}
+
+void ScChart2DataSource::AddLabeledSequence(const uno::Reference < chart2::data::XLabeledDataSequence >& xNew)
+{
+ m_aLabeledSequences.push_back(xNew);
+}
+
+// DataSequence ==============================================================
+
+ScChart2DataSequence::Item::Item()
+ : mfValue(std::numeric_limits<double>::quiet_NaN())
+ , mbIsValue(false)
+{
+}
+
+ScChart2DataSequence::HiddenRangeListener::HiddenRangeListener(ScChart2DataSequence& rParent) :
+ mrParent(rParent)
+{
+}
+
+ScChart2DataSequence::HiddenRangeListener::~HiddenRangeListener()
+{
+}
+
+void ScChart2DataSequence::HiddenRangeListener::notify()
+{
+ mrParent.setDataChangedHint(true);
+}
+
+ScChart2DataSequence::ScChart2DataSequence( ScDocument* pDoc,
+ vector<ScTokenRef>&& rTokens,
+ bool bIncludeHiddenCells )
+ : m_bIncludeHiddenCells( bIncludeHiddenCells)
+ , m_nObjectId( 0 )
+ , m_pDocument( pDoc)
+ , m_aTokens(std::move(rTokens))
+ , m_aPropSet(lcl_GetDataSequencePropertyMap())
+ , m_bGotDataChangedHint(false)
+ , m_bExtDataRebuildQueued(false)
+ , mbTimeBased(false)
+ , mnTimeBasedStart(0)
+ , mnTimeBasedEnd(0)
+ , mnCurrentTab(0)
+{
+ if ( m_pDocument )
+ {
+ m_pDocument->AddUnoObject( *this);
+ m_nObjectId = m_pDocument->GetNewUnoId();
+ }
+ // FIXME: real implementation of identifier and it's mapping to ranges.
+ // Reuse ScChartListener?
+
+ // BM: don't use names of named ranges but the UI range strings
+// String aStr;
+// rRangeList->Format( aStr, ScRefFlags::RANGE_ABS_3D, m_pDocument );
+// m_aIdentifier = aStr;
+
+// m_aIdentifier = "ID_";
+// static sal_Int32 nID = 0;
+// m_aIdentifier += OUString::valueOf( ++nID);
+}
+
+ScChart2DataSequence::~ScChart2DataSequence()
+{
+ SolarMutexGuard g;
+
+ if ( m_pDocument )
+ {
+ m_pDocument->RemoveUnoObject( *this);
+ if (m_pHiddenListener)
+ {
+ ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
+ if (pCLC)
+ pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
+ }
+ StopListeningToAllExternalRefs();
+ }
+
+ m_pValueListener.reset();
+}
+
+void ScChart2DataSequence::RefChanged()
+{
+ if( !m_pValueListener || m_aValueListeners.empty() )
+ return;
+
+ m_pValueListener->EndListeningAll();
+
+ if( !m_pDocument )
+ return;
+
+ ScChartListenerCollection* pCLC = nullptr;
+ if (m_pHiddenListener)
+ {
+ pCLC = m_pDocument->GetChartListenerCollection();
+ if (pCLC)
+ pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
+ }
+
+ for (const auto& rxToken : m_aTokens)
+ {
+ ScRange aRange;
+ if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
+ continue;
+
+ m_pDocument->StartListeningArea(aRange, false, m_pValueListener.get());
+ if (pCLC)
+ pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
+ }
+}
+
+void ScChart2DataSequence::BuildDataCache()
+{
+ m_bExtDataRebuildQueued = false;
+
+ if (!m_aDataArray.empty())
+ return;
+
+ StopListeningToAllExternalRefs();
+
+ ::std::vector<sal_Int32> aHiddenValues;
+ sal_Int32 nDataCount = 0;
+
+ for (const auto& rxToken : m_aTokens)
+ {
+ if (ScRefTokenHelper::isExternalRef(rxToken))
+ {
+ nDataCount += FillCacheFromExternalRef(rxToken);
+ }
+ else
+ {
+ ScRange aRange;
+ if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
+ continue;
+
+ SCCOL nLastCol = -1;
+ SCROW nLastRow = -1;
+ for (SCTAB nTab = aRange.aStart.Tab(); nTab <= aRange.aEnd.Tab(); ++nTab)
+ {
+ for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
+ {
+ sc::ColumnBlockPosition hint;
+ m_pDocument->InitColumnBlockPosition( hint, nTab, nCol );
+ for (SCROW nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
+ {
+ bool bColHidden = m_pDocument->ColHidden(nCol, nTab, nullptr, &nLastCol);
+ bool bRowHidden = m_pDocument->RowHidden(nRow, nTab, nullptr, &nLastRow);
+
+ if (bColHidden || bRowHidden)
+ {
+ // hidden cell
+ aHiddenValues.push_back(nDataCount-1);
+
+ if( !m_bIncludeHiddenCells )
+ continue;
+ }
+
+ Item aItem;
+
+ ScAddress aAdr(nCol, nRow, nTab);
+ aItem.maString = m_pDocument->GetString(aAdr);
+
+ ScRefCellValue aCell(*m_pDocument, aAdr, hint);
+ switch (aCell.meType)
+ {
+ case CELLTYPE_VALUE:
+ aItem.mfValue = aCell.getValue();
+ aItem.mbIsValue = true;
+ break;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFCell = aCell.mpFormula;
+ FormulaError nErr = pFCell->GetErrCode();
+ if (nErr != FormulaError::NONE)
+ break;
+
+ if (pFCell->IsValue())
+ {
+ aItem.mfValue = pFCell->GetValue();
+ aItem.mbIsValue = true;
+ }
+ }
+ break;
+ case CELLTYPE_EDIT:
+ case CELLTYPE_NONE:
+ case CELLTYPE_STRING:
+ default:
+ ; // do nothing
+ }
+
+ aItem.mAddress = ScAddress(nCol, nRow, nTab);
+
+ m_aDataArray.push_back(std::move(aItem));
+ ++nDataCount;
+ }
+ }
+ }
+ }
+ }
+
+ // convert the hidden cell list to sequence.
+ m_aHiddenValues.realloc(aHiddenValues.size());
+ std::copy(
+ aHiddenValues.begin(), aHiddenValues.end(), m_aHiddenValues.getArray());
+
+ // Clear the data series cache when the array is re-built.
+ m_aMixedDataCache.realloc(0);
+}
+
+void ScChart2DataSequence::RebuildDataCache()
+{
+ if (!m_bExtDataRebuildQueued)
+ {
+ m_aDataArray.clear();
+ m_pDocument->BroadcastUno(ScHint(SfxHintId::ScDataChanged, ScAddress()));
+ m_bExtDataRebuildQueued = true;
+ m_bGotDataChangedHint = true;
+ }
+}
+
+sal_Int32 ScChart2DataSequence::FillCacheFromExternalRef(const ScTokenRef& pToken)
+{
+ ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
+ ScRange aRange;
+ if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, pToken, ScAddress(), true))
+ return 0;
+
+ sal_uInt16 nFileId = pToken->GetIndex();
+ OUString aTabName = pToken->GetString().getString();
+ ScExternalRefCache::TokenArrayRef pArray = pRefMgr->getDoubleRefTokens(nFileId, aTabName, aRange, nullptr);
+ if (!pArray)
+ // no external data exists for this range.
+ return 0;
+
+ // Start listening for this external document.
+ ExternalRefListener* pExtRefListener = GetExtRefListener();
+ pRefMgr->addLinkListener(nFileId, pExtRefListener);
+ pExtRefListener->addFileId(nFileId);
+
+ ScExternalRefCache::TableTypeRef pTable = pRefMgr->getCacheTable(nFileId, aTabName, false);
+ sal_Int32 nDataCount = 0;
+ FormulaTokenArrayPlainIterator aIter(*pArray);
+ for (FormulaToken* p = aIter.First(); p; p = aIter.Next())
+ {
+ // Cached external range is always represented as a single
+ // matrix token, although that might change in the future when
+ // we introduce a new token type to store multi-table range
+ // data.
+
+ if (p->GetType() != svMatrix)
+ {
+ OSL_FAIL("Cached array is not a matrix token.");
+ continue;
+ }
+
+ const ScMatrix* pMat = p->GetMatrix();
+ SCSIZE nCSize, nRSize;
+ pMat->GetDimensions(nCSize, nRSize);
+ for (SCSIZE nC = 0; nC < nCSize; ++nC)
+ {
+ for (SCSIZE nR = 0; nR < nRSize; ++nR)
+ {
+ if (pMat->IsValue(nC, nR) || pMat->IsBoolean(nC, nR))
+ {
+ Item aItem;
+
+ aItem.mbIsValue = true;
+ aItem.mfValue = pMat->GetDouble(nC, nR);
+
+ SvNumberFormatter* pFormatter = m_pDocument->GetFormatTable();
+ if (pFormatter)
+ {
+ const double fVal = aItem.mfValue;
+ const Color* pColor = nullptr;
+ sal_uInt32 nFmt = 0;
+ if (pTable)
+ {
+ // Get the correct format index from the cache.
+ SCCOL nCol = aRange.aStart.Col() + static_cast<SCCOL>(nC);
+ SCROW nRow = aRange.aStart.Row() + static_cast<SCROW>(nR);
+ pTable->getCell(nCol, nRow, &nFmt);
+ }
+ pFormatter->GetOutputString(fVal, nFmt, aItem.maString, &pColor);
+ }
+
+ m_aDataArray.push_back(aItem);
+ ++nDataCount;
+ }
+ else if (pMat->IsStringOrEmpty(nC, nR))
+ {
+ Item aItem;
+
+ aItem.mbIsValue = false;
+ aItem.maString = pMat->GetString(nC, nR).getString();
+
+ m_aDataArray.emplace_back(aItem);
+ ++nDataCount;
+ }
+ }
+ }
+ }
+ return nDataCount;
+}
+
+void ScChart2DataSequence::UpdateTokensFromRanges(const ScRangeList& rRanges)
+{
+ if (!m_oRangeIndices)
+ return;
+
+ for ( size_t i = 0, nCount = rRanges.size(); i < nCount; ++i )
+ {
+ ScTokenRef pToken;
+ const ScRange & rRange = rRanges[i];
+
+ ScRefTokenHelper::getTokenFromRange(m_pDocument, pToken, rRange);
+ sal_uInt32 nOrigPos = (*m_oRangeIndices)[i];
+ m_aTokens[nOrigPos] = pToken;
+ }
+
+ RefChanged();
+
+ // any change of the range address is broadcast to value (modify) listeners
+ if ( !m_aValueListeners.empty() )
+ m_bGotDataChangedHint = true;
+}
+
+ScChart2DataSequence::ExternalRefListener* ScChart2DataSequence::GetExtRefListener()
+{
+ if (!m_pExtRefListener)
+ m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
+
+ return m_pExtRefListener.get();
+}
+
+void ScChart2DataSequence::StopListeningToAllExternalRefs()
+{
+ if (!m_pExtRefListener)
+ return;
+
+ const std::unordered_set<sal_uInt16>& rFileIds = m_pExtRefListener->getAllFileIds();
+ ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
+ for (const auto& rFileId : rFileIds)
+ pRefMgr->removeLinkListener(rFileId, m_pExtRefListener.get());
+
+ m_pExtRefListener.reset();
+}
+
+void ScChart2DataSequence::CopyData(const ScChart2DataSequence& r)
+{
+ if (!m_pDocument)
+ {
+ OSL_FAIL("document instance is nullptr!?");
+ return;
+ }
+
+ std::vector<Item> aDataArray(r.m_aDataArray);
+ m_aDataArray.swap(aDataArray);
+
+ m_aHiddenValues = r.m_aHiddenValues;
+ m_aRole = r.m_aRole;
+
+ if (r.m_oRangeIndices)
+ m_oRangeIndices = *r.m_oRangeIndices;
+
+ if (!r.m_pExtRefListener)
+ return;
+
+ // Re-register all external files that the old instance was
+ // listening to.
+
+ ScExternalRefManager* pRefMgr = m_pDocument->GetExternalRefManager();
+ m_pExtRefListener.reset(new ExternalRefListener(*this, m_pDocument));
+ const std::unordered_set<sal_uInt16>& rFileIds = r.m_pExtRefListener->getAllFileIds();
+ for (const auto& rFileId : rFileIds)
+ {
+ pRefMgr->addLinkListener(rFileId, m_pExtRefListener.get());
+ m_pExtRefListener->addFileId(rFileId);
+ }
+}
+
+void ScChart2DataSequence::Notify( SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ // Create a range list from the token list, have the range list
+ // updated, and bring the change back to the token list.
+
+ ScRangeList aRanges;
+ m_oRangeIndices.emplace();
+ vector<ScTokenRef>::const_iterator itrBeg = m_aTokens.begin(), itrEnd = m_aTokens.end();
+ for (vector<ScTokenRef>::const_iterator itr = itrBeg ;itr != itrEnd; ++itr)
+ {
+ if (!ScRefTokenHelper::isExternalRef(*itr))
+ {
+ ScRange aRange;
+ ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, *itr, ScAddress());
+ aRanges.push_back(aRange);
+ sal_uInt32 nPos = distance(itrBeg, itr);
+ m_oRangeIndices->push_back(nPos);
+ }
+ }
+
+ assert(m_oRangeIndices->size() == aRanges.size() &&
+ "range list and range index list have different sizes.");
+
+ unique_ptr<ScRangeList> pUndoRanges;
+ if ( m_pDocument->HasUnoRefUndo() )
+ pUndoRanges.reset(new ScRangeList(aRanges));
+
+ const ScUpdateRefHint& rRef = static_cast<const ScUpdateRefHint&>(rHint);
+ bool bChanged = aRanges.UpdateReference(
+ rRef.GetMode(), m_pDocument, rRef.GetRange(), rRef.GetDx(), rRef.GetDy(), rRef.GetDz());
+
+ if (bChanged)
+ {
+ // TODO: This should be an assert, but tdf#144537 triggers it.
+ SAL_WARN_IF(m_oRangeIndices->size() == aRanges.size(),
+ "sc.ui", "range list and range index list have different sizes after the reference update.");
+
+ // Bring the change back from the range list to the token list.
+ UpdateTokensFromRanges(aRanges);
+
+ if (pUndoRanges)
+ m_pDocument->AddUnoRefChange(m_nObjectId, *pUndoRanges);
+ }
+ }
+ else if ( auto pUndoHint = dynamic_cast<const ScUnoRefUndoHint*>(&rHint) )
+ {
+ do
+ {
+ if (pUndoHint->GetObjectId() != m_nObjectId)
+ break;
+
+ // The hint object provides the old ranges. Restore the old state
+ // from these ranges.
+
+ if (!m_oRangeIndices || m_oRangeIndices->empty())
+ {
+ assert(false && " faulty range indices");
+ break;
+ }
+
+ const ScRangeList& rRanges = pUndoHint->GetRanges();
+
+ size_t nCount = rRanges.size();
+ if (nCount != m_oRangeIndices->size())
+ {
+ assert(false && "range count and range index count differ.");
+ break;
+ }
+
+ UpdateTokensFromRanges(rRanges);
+ }
+ while (false);
+ }
+ else
+ {
+ const SfxHintId nId = rHint.GetId();
+ if ( nId ==SfxHintId::Dying )
+ {
+ m_pDocument = nullptr;
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ // delayed broadcast as in ScCellRangesBase
+
+ if ( m_bGotDataChangedHint && m_pDocument )
+ {
+ m_aDataArray.clear();
+ lang::EventObject aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+
+ if( m_pDocument )
+ {
+ for (const uno::Reference<util::XModifyListener> & xListener: m_aValueListeners)
+ m_pDocument->AddUnoListenerCall( xListener, aEvent );
+ }
+
+ m_bGotDataChangedHint = false;
+ }
+ }
+ else if ( nId == SfxHintId::ScCalcAll )
+ {
+ // broadcast from DoHardRecalc - set m_bGotDataChangedHint
+ // (SfxHintId::DataChanged follows separately)
+
+ if ( !m_aValueListeners.empty() )
+ m_bGotDataChangedHint = true;
+ }
+ else if (nId == SfxHintId::ScClearCache)
+ {
+ // necessary after import
+ m_aDataArray.clear();
+ }
+ }
+}
+
+IMPL_LINK( ScChart2DataSequence, ValueListenerHdl, const SfxHint&, rHint, void )
+{
+ if ( m_pDocument && (rHint.GetId() == SfxHintId::ScDataChanged) )
+ {
+ // This may be called several times for a single change, if several formulas
+ // in the range are notified. So only a flag is set that is checked when
+ // SfxHintId::DataChanged is received.
+
+ setDataChangedHint(true);
+ }
+}
+
+ScChart2DataSequence::ExternalRefListener::ExternalRefListener(
+ ScChart2DataSequence& rParent, ScDocument* pDoc) :
+ mrParent(rParent),
+ mpDoc(pDoc)
+{
+}
+
+ScChart2DataSequence::ExternalRefListener::~ExternalRefListener()
+{
+ if (!mpDoc || mpDoc->IsInDtorClear())
+ // The document is being destroyed. Do nothing.
+ return;
+
+ // Make sure to remove all pointers to this object.
+ mpDoc->GetExternalRefManager()->removeLinkListener(this);
+}
+
+void ScChart2DataSequence::ExternalRefListener::notify(sal_uInt16 nFileId, ScExternalRefManager::LinkUpdateType eType)
+{
+ switch (eType)
+ {
+ case ScExternalRefManager::LINK_MODIFIED:
+ {
+ if (maFileIds.count(nFileId))
+ // We are listening to this external document.
+ mrParent.RebuildDataCache();
+ }
+ break;
+ case ScExternalRefManager::LINK_BROKEN:
+ maFileIds.erase(nFileId);
+ break;
+ case ScExternalRefManager::OH_NO_WE_ARE_GOING_TO_DIE:
+ mpDoc = nullptr;
+ break;
+ }
+}
+
+void ScChart2DataSequence::ExternalRefListener::addFileId(sal_uInt16 nFileId)
+{
+ maFileIds.insert(nFileId);
+}
+
+uno::Sequence< uno::Any> SAL_CALL ScChart2DataSequence::getData()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pDocument)
+ throw uno::RuntimeException();
+
+ BuildDataCache();
+
+ if (!m_aMixedDataCache.hasElements())
+ {
+ // Build a cache for the 1st time...
+
+ sal_Int32 nCount = m_aDataArray.size();
+ m_aMixedDataCache.realloc(nCount);
+ uno::Any* pArr = m_aMixedDataCache.getArray();
+ for (const Item &rItem : m_aDataArray)
+ {
+ if (rItem.mbIsValue)
+ *pArr <<= rItem.mfValue;
+ else if (rItem.maString.isEmpty())
+ {
+ ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
+ if (aCell.isEmpty())
+ *pArr = uno::Any();
+ else
+ *pArr <<= rItem.maString;
+ }
+ else
+ *pArr <<= rItem.maString;
+ ++pArr;
+ }
+ }
+ return m_aMixedDataCache;
+}
+
+// XNumericalDataSequence --------------------------------------------------
+
+uno::Sequence< double > SAL_CALL ScChart2DataSequence::getNumericalData()
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pDocument)
+ throw uno::RuntimeException();
+
+ BuildDataCache();
+
+ sal_Int32 nCount = m_aDataArray.size();
+ uno::Sequence<double> aSeq(nCount);
+ double* pArr = aSeq.getArray();
+ for (const Item& rItem : m_aDataArray)
+ {
+ *pArr = rItem.mbIsValue ? rItem.mfValue : std::numeric_limits<double>::quiet_NaN();
+ ++pArr;
+ }
+
+ return aSeq;
+}
+
+// XTextualDataSequence --------------------------------------------------
+
+uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::getTextualData()
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence<OUString> aSeq;
+ if ( !m_pDocument )
+ throw uno::RuntimeException();
+
+ BuildDataCache();
+
+ sal_Int32 nCount = m_aDataArray.size();
+ if ( nCount > 0 )
+ {
+ aSeq = uno::Sequence<OUString>(nCount);
+ OUString* pArr = aSeq.getArray();
+ for (const Item& rItem : m_aDataArray)
+ {
+ *pArr = rItem.maString;
+ ++pArr;
+ }
+ }
+ else if ( m_aTokens.front() )
+ {
+ if( m_aTokens.front()->GetType() == svString )
+ {
+ aSeq = uno::Sequence<OUString> { m_aTokens.front()->GetString().getString() };
+ }
+ }
+
+ return aSeq;
+}
+
+OUString SAL_CALL ScChart2DataSequence::getSourceRangeRepresentation()
+{
+ SolarMutexGuard aGuard;
+ OUString aStr;
+ OSL_ENSURE( m_pDocument, "No Document -> no SourceRangeRepresentation" );
+ if (m_pDocument)
+ lcl_convertTokensToString(aStr, m_aTokens, *m_pDocument);
+
+ return aStr;
+}
+
+namespace {
+
+/**
+ * This function object is used to accumulatively count the numbers of
+ * columns and rows in all reference tokens.
+ */
+class AccumulateRangeSize
+{
+public:
+ AccumulateRangeSize(const ScDocument* pDoc) :
+ mpDoc(pDoc), mnCols(0), mnRows(0) {}
+
+ void operator() (const ScTokenRef& pToken)
+ {
+ ScRange r;
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ ScRefTokenHelper::getRangeFromToken(mpDoc, r, pToken, ScAddress(), bExternal);
+ r.PutInOrder();
+ mnCols += r.aEnd.Col() - r.aStart.Col() + 1;
+ mnRows += r.aEnd.Row() - r.aStart.Row() + 1;
+ }
+
+ SCCOL getCols() const { return mnCols; }
+ SCROW getRows() const { return mnRows; }
+private:
+ const ScDocument* mpDoc;
+ SCCOL mnCols;
+ SCROW mnRows;
+};
+
+/**
+ * This function object is used to generate label strings from a list of
+ * reference tokens.
+ */
+class GenerateLabelStrings
+{
+public:
+ GenerateLabelStrings(const ScDocument* pDoc, sal_Int32 nSize, chart2::data::LabelOrigin eOrigin, bool bColumn) :
+ mpDoc(pDoc),
+ mpLabels(std::make_shared<Sequence<OUString>>(nSize)),
+ meOrigin(eOrigin),
+ mnCount(0),
+ mbColumn(bColumn) {}
+
+ void operator() (const ScTokenRef& pToken)
+ {
+ bool bExternal = ScRefTokenHelper::isExternalRef(pToken);
+ ScRange aRange;
+ ScRefTokenHelper::getRangeFromToken(mpDoc, aRange, pToken, ScAddress(), bExternal);
+ OUString* pArr = mpLabels->getArray();
+ if (mbColumn)
+ {
+ for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
+ {
+ if ( meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
+ {
+ OUString aString = ScResId(STR_COLUMN) + " ";
+ ScAddress aPos( nCol, 0, 0 );
+ OUString aColStr(aPos.Format(ScRefFlags::COL_VALID));
+ aString += aColStr;
+ pArr[mnCount] = aString;
+ }
+ else //only indices for categories
+ pArr[mnCount] = OUString::number( mnCount+1 );
+ ++mnCount;
+ }
+ }
+ else
+ {
+ for (sal_Int32 nRow = aRange.aStart.Row(); nRow <= aRange.aEnd.Row(); ++nRow)
+ {
+ if (meOrigin != chart2::data::LabelOrigin_LONG_SIDE)
+ {
+ OUString aString = ScResId(STR_ROW) +
+ " " + OUString::number( nRow+1 );
+ pArr[mnCount] = aString;
+ }
+ else //only indices for categories
+ pArr[mnCount] = OUString::number( mnCount+1 );
+ ++mnCount;
+ }
+ }
+ }
+
+ const Sequence<OUString>& getLabels() const { return *mpLabels; }
+
+private:
+ const ScDocument* mpDoc;
+ shared_ptr< Sequence<OUString> > mpLabels;
+ chart2::data::LabelOrigin meOrigin;
+ sal_Int32 mnCount;
+ bool mbColumn;
+};
+
+}
+
+uno::Sequence< OUString > SAL_CALL ScChart2DataSequence::generateLabel(chart2::data::LabelOrigin eOrigin)
+{
+ SolarMutexGuard aGuard;
+ if ( !m_pDocument)
+ throw uno::RuntimeException();
+
+ // Determine the total size of all ranges.
+ AccumulateRangeSize func(m_pDocument);
+ func = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), func);
+ SCCOL nCols = func.getCols();
+ SCROW nRows = func.getRows();
+
+ // Determine whether this is column-major or row-major.
+ bool bColumn = true;
+ if ((eOrigin == chart2::data::LabelOrigin_SHORT_SIDE) ||
+ (eOrigin == chart2::data::LabelOrigin_LONG_SIDE))
+ {
+ if (nRows > nCols)
+ {
+ bColumn = eOrigin == chart2::data::LabelOrigin_SHORT_SIDE;
+ }
+ else if (nCols > nRows)
+ {
+ bColumn = eOrigin != chart2::data::LabelOrigin_SHORT_SIDE;
+ }
+ else
+ return Sequence<OUString>();
+ }
+
+ // Generate label strings based on the info so far.
+ sal_Int32 nCount = bColumn ? nCols : nRows;
+ GenerateLabelStrings genLabels(m_pDocument, nCount, eOrigin, bColumn);
+ genLabels = ::std::for_each(m_aTokens.begin(), m_aTokens.end(), genLabels);
+ Sequence<OUString> aSeq = genLabels.getLabels();
+
+ return aSeq;
+}
+
+namespace {
+
+sal_uInt32 getDisplayNumberFormat(const ScDocument* pDoc, const ScAddress& rPos)
+{
+ sal_uInt32 nFormat = pDoc->GetNumberFormat(rPos); // original format from cell.
+ return nFormat;
+}
+
+}
+
+::sal_Int32 SAL_CALL ScChart2DataSequence::getNumberFormatKeyByIndex( ::sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ BuildDataCache();
+
+ if (nIndex == -1)
+ {
+ // return format of first non-empty cell
+ // TODO: use nicer heuristic
+ for (const Item& rItem : m_aDataArray)
+ {
+ ScRefCellValue aCell(*m_pDocument, rItem.mAddress);
+ if (!aCell.isEmpty() && aCell.hasNumeric())
+ {
+ return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, rItem.mAddress));
+ }
+ }
+
+ // we could not find a non-empty cell
+ return 0;
+ }
+
+ if (nIndex < 0 || o3tl::make_unsigned(nIndex) >= m_aDataArray.size())
+ {
+ SAL_WARN("sc.ui", "Passed invalid index to getNumberFormatKeyByIndex(). Will return default value '0'.");
+ return 0;
+ }
+
+ return static_cast<sal_Int32>(getDisplayNumberFormat(m_pDocument, m_aDataArray.at(nIndex).mAddress));
+}
+
+// XCloneable ================================================================
+
+uno::Reference< util::XCloneable > SAL_CALL ScChart2DataSequence::createClone()
+{
+ SolarMutexGuard aGuard;
+
+ // Clone tokens.
+ vector<ScTokenRef> aTokensNew;
+ aTokensNew.reserve(m_aTokens.size());
+ for (const auto& rxToken : m_aTokens)
+ {
+ ScTokenRef p(rxToken->Clone());
+ aTokensNew.push_back(p);
+ }
+
+ rtl::Reference<ScChart2DataSequence> p(new ScChart2DataSequence(m_pDocument, std::move(aTokensNew), m_bIncludeHiddenCells));
+ p->CopyData(*this);
+ return p;
+}
+
+// XModifyBroadcaster ========================================================
+
+void SAL_CALL ScChart2DataSequence::addModifyListener( const uno::Reference< util::XModifyListener >& aListener )
+{
+ // like ScCellRangesBase::addModifyListener
+ SolarMutexGuard aGuard;
+ if (m_aTokens.empty())
+ return;
+
+ ScRangeList aRanges;
+ ScRefTokenHelper::getRangeListFromTokens(m_pDocument, aRanges, m_aTokens, ScAddress());
+ m_aValueListeners.emplace_back( aListener );
+
+ if ( m_aValueListeners.size() != 1 )
+ return;
+
+ if (!m_pValueListener)
+ m_pValueListener.reset(new ScLinkListener( LINK( this, ScChart2DataSequence, ValueListenerHdl ) ));
+
+ if (!m_pHiddenListener)
+ m_pHiddenListener.reset(new HiddenRangeListener(*this));
+
+ if( m_pDocument )
+ {
+ ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
+ for (const auto& rxToken : m_aTokens)
+ {
+ ScRange aRange;
+ if (!ScRefTokenHelper::getRangeFromToken(m_pDocument, aRange, rxToken, ScAddress()))
+ continue;
+
+ m_pDocument->StartListeningArea( aRange, false, m_pValueListener.get() );
+ if (pCLC)
+ pCLC->StartListeningHiddenRange(aRange, m_pHiddenListener.get());
+ }
+ }
+
+ acquire(); // don't lose this object (one ref for all listeners)
+}
+
+void SAL_CALL ScChart2DataSequence::removeModifyListener( const uno::Reference< util::XModifyListener >& aListener )
+{
+ // like ScCellRangesBase::removeModifyListener
+
+ SolarMutexGuard aGuard;
+ if (m_aTokens.empty())
+ return;
+
+ rtl::Reference<ScChart2DataSequence> xSelfHold(this); // in case the listeners have the last ref
+
+ sal_uInt16 nCount = m_aValueListeners.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ {
+ uno::Reference<util::XModifyListener>& rObj = m_aValueListeners[n];
+ if ( rObj == aListener )
+ {
+ m_aValueListeners.erase( m_aValueListeners.begin() + n );
+
+ if ( m_aValueListeners.empty() )
+ {
+ if (m_pValueListener)
+ m_pValueListener->EndListeningAll();
+
+ if (m_pHiddenListener && m_pDocument)
+ {
+ ScChartListenerCollection* pCLC = m_pDocument->GetChartListenerCollection();
+ if (pCLC)
+ pCLC->EndListeningHiddenRange(m_pHiddenListener.get());
+ }
+
+ release(); // release the ref for the listeners
+ }
+
+ break;
+ }
+ }
+}
+
+// DataSequence XPropertySet -------------------------------------------------
+
+uno::Reference< beans::XPropertySetInfo> SAL_CALL
+ScChart2DataSequence::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( m_aPropSet.getPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL ScChart2DataSequence::setPropertyValue(
+ const OUString& rPropertyName, const uno::Any& rValue)
+{
+ if ( rPropertyName == SC_UNONAME_ROLE )
+ {
+ if ( !(rValue >>= m_aRole))
+ throw lang::IllegalArgumentException();
+ }
+ else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
+ {
+ bool bOldValue = m_bIncludeHiddenCells;
+ if ( !(rValue >>= m_bIncludeHiddenCells))
+ throw lang::IllegalArgumentException();
+ if( bOldValue != m_bIncludeHiddenCells )
+ m_aDataArray.clear();//data array is dirty now
+ }
+ else if( rPropertyName == "TimeBased" )
+ {
+ bool bTimeBased = mbTimeBased;
+ rValue>>= bTimeBased;
+ mbTimeBased = bTimeBased;
+ }
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+ // TODO: support optional properties
+}
+
+uno::Any SAL_CALL ScChart2DataSequence::getPropertyValue(const OUString& rPropertyName)
+{
+ uno::Any aRet;
+ if ( rPropertyName == SC_UNONAME_ROLE )
+ aRet <<= m_aRole;
+ else if ( rPropertyName == SC_UNONAME_INCLUDEHIDDENCELLS )
+ aRet <<= m_bIncludeHiddenCells;
+ else if ( rPropertyName == SC_UNONAME_HIDDENVALUES )
+ {
+ // This property is read-only thus cannot be set externally via
+ // setPropertyValue(...).
+ BuildDataCache();
+ aRet <<= m_aHiddenValues;
+ }
+ else if (rPropertyName == SC_UNONAME_TIME_BASED)
+ {
+ aRet <<= mbTimeBased;
+ }
+ else if (rPropertyName == SC_UNONAME_HAS_STRING_LABEL)
+ {
+ // Read-only property. It returns whether or not the label value is a
+ // direct user input, rather than an indirect reference.
+ bool bHasStringLabel = false;
+ if (m_aTokens.size() == 1)
+ {
+ const formula::FormulaToken& rToken = *m_aTokens[0];
+ bHasStringLabel = rToken.GetType() == formula::svString;
+ }
+ aRet <<= bHasStringLabel;
+ }
+ else
+ throw beans::UnknownPropertyException(rPropertyName);
+ // TODO: support optional properties
+ return aRet;
+}
+
+void SAL_CALL ScChart2DataSequence::addPropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*xListener*/)
+{
+ // FIXME: real implementation
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataSequence::removePropertyChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XPropertyChangeListener>& /*rListener*/)
+{
+ // FIXME: real implementation
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataSequence::addVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
+{
+ // FIXME: real implementation
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void SAL_CALL ScChart2DataSequence::removeVetoableChangeListener(
+ const OUString& /*rPropertyName*/,
+ const uno::Reference< beans::XVetoableChangeListener>& /*rListener*/)
+{
+ // FIXME: real implementation
+ OSL_FAIL( "Not yet implemented" );
+}
+
+void ScChart2DataSequence::setDataChangedHint(bool b)
+{
+ m_bGotDataChangedHint = b;
+}
+
+sal_Bool ScChart2DataSequence::switchToNext(sal_Bool bWrap)
+{
+ if(!mbTimeBased)
+ return true;
+
+ if(mnCurrentTab >= mnTimeBasedEnd)
+ {
+ if(bWrap)
+ setToPointInTime(0);
+ return false;
+ }
+
+ for(const auto& rxToken : m_aTokens)
+ {
+ if (rxToken->GetType() != svDoubleRef)
+ continue;
+
+ ScComplexRefData& rData = *rxToken->GetDoubleRef();
+ ScSingleRefData& s = rData.Ref1;
+ ScSingleRefData& e = rData.Ref2;
+
+ s.IncTab(1);
+ e.IncTab(1);
+ }
+
+ ++mnCurrentTab;
+
+ RebuildDataCache();
+
+ return true;
+}
+
+void ScChart2DataSequence::setRange(sal_Int32 nStart, sal_Int32 nEnd)
+{
+ mnTimeBasedStart = nStart;
+ mnTimeBasedEnd = nEnd;
+ mnCurrentTab = mnTimeBasedStart;
+}
+
+sal_Bool ScChart2DataSequence::setToPointInTime(sal_Int32 nPoint)
+{
+ if(nPoint > mnTimeBasedEnd - mnTimeBasedStart)
+ return false;
+
+ SCTAB nTab = mnTimeBasedStart + nPoint;
+ for(const auto& rxToken : m_aTokens)
+ {
+ if (rxToken->GetType() != svDoubleRef)
+ continue;
+
+ ScComplexRefData& rData = *rxToken->GetDoubleRef();
+ ScSingleRefData& s = rData.Ref1;
+ ScSingleRefData& e = rData.Ref2;
+
+ s.SetAbsTab(nTab);
+ e.SetAbsTab(nTab);
+ }
+
+ mnCurrentTab = nTab;
+
+ RebuildDataCache();
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/chartuno.cxx b/sc/source/ui/unoobj/chartuno.cxx
new file mode 100644
index 000000000..a4c9777a2
--- /dev/null
+++ b/sc/source/ui/unoobj/chartuno.cxx
@@ -0,0 +1,738 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/Aspects.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/chart2/data/XDataReceiver.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+
+#include <osl/diagnose.h>
+#include <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdundo.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <comphelper/classids.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <tools/globname.hxx>
+#include <svtools/embedhlp.hxx>
+#include <vcl/svapp.hxx>
+
+#include <ChartTools.hxx>
+#include <chartuno.hxx>
+#include <miscuno.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <undodat.hxx>
+#include <chartlis.hxx>
+#include <chart2uno.hxx>
+#include <convuno.hxx>
+
+using namespace css;
+
+#define PROP_HANDLE_RELATED_CELLRANGES 1
+
+SC_SIMPLE_SERVICE_INFO( ScChartObj, "ScChartObj", "com.sun.star.table.TableChart" )
+SC_SIMPLE_SERVICE_INFO( ScChartsObj, "ScChartsObj", "com.sun.star.table.TableCharts" )
+
+ScChartsObj::ScChartsObj(ScDocShell* pDocSh, SCTAB nT) :
+ pDocShell( pDocSh ),
+ nTab( nT )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScChartsObj::~ScChartsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScChartsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! update reference
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+rtl::Reference<ScChartObj> ScChartsObj::GetObjectByIndex_Impl(tools::Long nIndex) const
+{
+ if ( pDocShell )
+ {
+ OUString aName;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if (pDrawLayer)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage, "Page not found");
+ if (pPage)
+ {
+ tools::Long nPos = 0;
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 && ScDocument::IsChart(pObject) )
+ {
+ if ( nPos == nIndex )
+ {
+ uno::Reference < embed::XEmbeddedObject > xObj = static_cast<SdrOle2Obj*>(pObject)->GetObjRef();
+ if ( xObj.is() )
+ aName = pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName( xObj );
+ break; // stop searching
+ }
+ ++nPos;
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+
+ if (!aName.isEmpty())
+ return new ScChartObj( pDocShell, nTab, aName );
+ }
+
+ return nullptr;
+}
+
+rtl::Reference<ScChartObj> ScChartsObj::GetObjectByName_Impl(const OUString& aName) const
+{
+ if (sc::tools::findChartsByName(pDocShell, nTab, aName, sc::tools::ChartSourceType::CELL_RANGE))
+ return new ScChartObj( pDocShell, nTab, aName );
+ if (sc::tools::findChartsByName(pDocShell, nTab, aName, sc::tools::ChartSourceType::PIVOT_TABLE))
+ return new ScChartObj( pDocShell, nTab, aName );
+ return nullptr;
+}
+
+// XTableCharts
+
+void SAL_CALL ScChartsObj::addNewByName( const OUString& rName,
+ const awt::Rectangle& aRect,
+ const uno::Sequence<table::CellRangeAddress>& aRanges,
+ sal_Bool bColumnHeaders, sal_Bool bRowHeaders )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDrawLayer* pModel = pDocShell->MakeDrawLayer();
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage,"addChart: no Page");
+ if (!pPage)
+ return;
+
+ // chart can't be inserted if any ole object with that name exists on any table
+ // (empty string: generate valid name)
+
+ OUString aName = rName;
+ SCTAB nDummy;
+ if ( !aName.isEmpty() && pModel->GetNamedObject( aName, SdrObjKind::OLE2, nDummy ) )
+ {
+ // object exists - only RuntimeException is specified
+ throw uno::RuntimeException();
+ }
+
+ ScRangeList* pList = new ScRangeList;
+ for (const table::CellRangeAddress& rRange : aRanges)
+ {
+ ScRange aRange( static_cast<SCCOL>(rRange.StartColumn), rRange.StartRow, rRange.Sheet,
+ static_cast<SCCOL>(rRange.EndColumn), rRange.EndRow, rRange.Sheet );
+ pList->push_back( aRange );
+ }
+ ScRangeListRef xNewRanges( pList );
+
+ uno::Reference < embed::XEmbeddedObject > xObj;
+ if ( SvtModuleOptions().IsChart() )
+ xObj = pDocShell->GetEmbeddedObjectContainer().CreateEmbeddedObject( SvGlobalName( SO3_SCH_CLASSID ).GetByteSequence(), aName );
+ if ( !xObj.is() )
+ return;
+
+ // adjust rectangle
+ //! error/exception, if empty/invalid ???
+ Point aRectPos( aRect.X, aRect.Y );
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ if ( ( aRectPos.X() < 0 && !bLayoutRTL ) || ( aRectPos.X() > 0 && bLayoutRTL ) )
+ aRectPos.setX( 0 );
+
+ if (aRectPos.Y() < 0)
+ aRectPos.setY( 0 );
+
+ Size aRectSize( aRect.Width, aRect.Height );
+ if (aRectSize.Width() <= 0)
+ aRectSize.setWidth( 5000 ); // default size
+
+ if (aRectSize.Height() <= 0)
+ aRectSize.setHeight( 5000 );
+ tools::Rectangle aInsRect( aRectPos, aRectSize );
+
+ sal_Int64 nAspect(embed::Aspects::MSOLE_CONTENT);
+ MapUnit aMapUnit(VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) ));
+ Size aSize(aInsRect.GetSize());
+ aSize = OutputDevice::LogicToLogic( aSize, MapMode( MapUnit::Map100thMM ), MapMode( aMapUnit ) );
+ awt::Size aSz;
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+
+ // Calc -> DataProvider
+ uno::Reference< chart2::data::XDataProvider > xDataProvider = new
+ ScChart2DataProvider( &rDoc );
+ // Chart -> DataReceiver
+ uno::Reference< chart2::data::XDataReceiver > xReceiver;
+ if( xObj.is())
+ xReceiver.set( xObj->getComponent(), uno::UNO_QUERY );
+ if( xReceiver.is())
+ {
+ // Range in UI representation.
+ OUString sRangeStr;
+ xNewRanges->Format(sRangeStr, ScRefFlags::RANGE_ABS_3D, rDoc, rDoc.GetAddressConvention());
+
+ // connect
+ if( !sRangeStr.isEmpty() )
+ xReceiver->attachDataProvider( xDataProvider );
+ else
+ sRangeStr = "all";
+
+ uno::Reference< util::XNumberFormatsSupplier > xNumberFormatsSupplier( pDocShell->GetModel(), uno::UNO_QUERY );
+ xReceiver->attachNumberFormatsSupplier( xNumberFormatsSupplier );
+
+ // set arguments
+ uno::Sequence< beans::PropertyValue > aArgs{
+ beans::PropertyValue(
+ "CellRangeRepresentation", -1,
+ uno::Any( sRangeStr ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "HasCategories", -1,
+ uno::Any( bRowHeaders ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "FirstCellAsLabel", -1,
+ uno::Any( bColumnHeaders ), beans::PropertyState_DIRECT_VALUE ),
+ beans::PropertyValue(
+ "DataRowSource", -1,
+ uno::Any( chart::ChartDataRowSource_COLUMNS ), beans::PropertyState_DIRECT_VALUE )
+ };
+ xReceiver->setArguments( aArgs );
+ }
+
+ ScChartListener* pChartListener =
+ new ScChartListener( aName, rDoc, xNewRanges );
+ rDoc.GetChartListenerCollection()->insert( pChartListener );
+ pChartListener->StartListeningTo();
+
+ SdrOle2Obj* pObj = new SdrOle2Obj(
+ *pModel,
+ ::svt::EmbeddedObjectRef(xObj, embed::Aspects::MSOLE_CONTENT),
+ aName,
+ aInsRect);
+
+ // set VisArea
+ if( xObj.is())
+ xObj->setVisualAreaSize( nAspect, aSz );
+
+ // #i121334# This call will change the chart's default background fill from white to transparent.
+ // Add here again if this is wanted (see task description for details)
+ // ChartHelper::AdaptDefaultsForChart( xObj );
+
+ pPage->InsertObject( pObj );
+ pModel->AddUndo( std::make_unique<SdrUndoInsertObj>( *pObj ) );
+}
+
+void SAL_CALL ScChartsObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* pObj = sc::tools::findChartsByName(pDocShell, nTab, aName, sc::tools::ChartSourceType::CELL_RANGE);
+ if (pObj)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.GetChartListenerCollection()->removeByName(aName);
+ ScDrawLayer* pModel = rDoc.GetDrawLayer(); // is not zero
+ SdrPage* pPage = pModel->GetPage(static_cast<sal_uInt16>(nTab)); // is not zero
+
+ pModel->AddUndo( std::make_unique<SdrUndoDelObj>( *pObj ) );
+ pPage->RemoveObject( pObj->GetOrdNum() );
+
+ //! Notify etc.???
+ }
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScChartsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.table.TableChartsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScChartsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nCount = 0;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if (pDrawLayer)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage, "Page not found");
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 && ScDocument::IsChart(pObject) )
+ ++nCount;
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL ScChartsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XTableChart> xChart(GetObjectByIndex_Impl(nIndex));
+ if (!xChart.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xChart);
+}
+
+uno::Type SAL_CALL ScChartsObj::getElementType()
+{
+ return cppu::UnoType<table::XTableChart>::get();
+}
+
+sal_Bool SAL_CALL ScChartsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return getCount() != 0;
+}
+
+uno::Any SAL_CALL ScChartsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XTableChart> xChart(GetObjectByName_Impl(aName));
+ if (!xChart.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xChart);
+}
+
+uno::Sequence<OUString> SAL_CALL ScChartsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ tools::Long nCount = getCount();
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+
+ tools::Long nPos = 0;
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if (pDrawLayer)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+ OSL_ENSURE(pPage, "Page not found");
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( pObject->GetObjIdentifier() == SdrObjKind::OLE2 && ScDocument::IsChart(pObject) )
+ {
+ OUString aName;
+ uno::Reference < embed::XEmbeddedObject > xObj = static_cast<SdrOle2Obj*>(pObject)->GetObjRef();
+ if ( xObj.is() )
+ aName = pDocShell->GetEmbeddedObjectContainer().GetEmbeddedObjectName( xObj );
+
+ OSL_ENSURE(nPos<nCount, "oops, miscounted?");
+ pAry[nPos++] = aName;
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ OSL_ENSURE(nPos==nCount, "hey, miscounted?");
+
+ return aSeq;
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScChartsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* aOle2Obj = sc::tools::findChartsByName(pDocShell, nTab, aName,
+ sc::tools::ChartSourceType::CELL_RANGE);
+ return aOle2Obj != nullptr;
+}
+
+ScChartObj::ScChartObj(ScDocShell* pDocSh, SCTAB nT, const OUString& rN)
+ :ScChartObj_Base( m_aMutex )
+ ,ScChartObj_PBase( ScChartObj_Base::rBHelper )
+ ,pDocShell( pDocSh )
+ ,nTab( nT )
+ ,aChartName( rN )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ registerPropertyNoMember( "RelatedCellRanges",
+ PROP_HANDLE_RELATED_CELLRANGES, beans::PropertyAttribute::MAYBEVOID,
+ cppu::UnoType<uno::Sequence<table::CellRangeAddress>>::get(),
+ css::uno::Any(uno::Sequence<table::CellRangeAddress>()) );
+}
+
+ScChartObj::~ScChartObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScChartObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! update reference
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+void ScChartObj::GetData_Impl( ScRangeListRef& rRanges, bool& rColHeaders, bool& rRowHeaders ) const
+{
+ bool bFound = false;
+
+ if( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ uno::Reference< chart2::XChartDocument > xChartDoc( rDoc.GetChartByName( aChartName ) );
+ if( xChartDoc.is() )
+ {
+ uno::Reference< chart2::data::XDataReceiver > xReceiver( xChartDoc, uno::UNO_QUERY );
+ uno::Reference< chart2::data::XDataProvider > xProvider = xChartDoc->getDataProvider();
+ if( xReceiver.is() && xProvider.is() )
+ {
+ const uno::Sequence< beans::PropertyValue > aArgs( xProvider->detectArguments( xReceiver->getUsedData() ) );
+
+ OUString aRanges;
+ chart::ChartDataRowSource eDataRowSource = chart::ChartDataRowSource_COLUMNS;
+ bool bHasCategories=false;
+ bool bFirstCellAsLabel=false;
+ for (const beans::PropertyValue& rProp : aArgs)
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == "CellRangeRepresentation")
+ rProp.Value >>= aRanges;
+ else if (aPropName == "DataRowSource")
+ eDataRowSource = static_cast<chart::ChartDataRowSource>(ScUnoHelpFunctions::GetEnumFromAny( rProp.Value ));
+ else if (aPropName == "HasCategories")
+ bHasCategories = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == "FirstCellAsLabel")
+ bFirstCellAsLabel = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ }
+
+ if( chart::ChartDataRowSource_COLUMNS == eDataRowSource )
+ {
+ rColHeaders=bFirstCellAsLabel;
+ rRowHeaders=bHasCategories;
+ }
+ else
+ {
+ rColHeaders=bHasCategories;
+ rRowHeaders=bFirstCellAsLabel;
+ }
+ // Range in UI representation.
+ rRanges->Parse( aRanges, rDoc, rDoc.GetAddressConvention());
+ }
+ bFound = true;
+ }
+ }
+ if( !bFound )
+ {
+ rRanges = nullptr;
+ rColHeaders = false;
+ rRowHeaders = false;
+ }
+}
+
+void ScChartObj::Update_Impl( const ScRangeListRef& rRanges, bool bColHeaders, bool bRowHeaders )
+{
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ if (bUndo)
+ {
+ pDocShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoChartData>( pDocShell, aChartName, rRanges, bColHeaders, bRowHeaders, false ) );
+ }
+ rDoc.UpdateChartArea( aChartName, rRanges, bColHeaders, bRowHeaders, false );
+ }
+}
+
+// ::comphelper::OPropertySetHelper
+
+::cppu::IPropertyArrayHelper& ScChartObj::getInfoHelper()
+{
+ return *ScChartObj_PABase::getArrayHelper();
+}
+
+void ScChartObj::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const uno::Any& rValue )
+{
+ switch ( nHandle )
+ {
+ case PROP_HANDLE_RELATED_CELLRANGES:
+ {
+ uno::Sequence< table::CellRangeAddress > aCellRanges;
+ if ( rValue >>= aCellRanges )
+ {
+ ScRangeListRef rRangeList = new ScRangeList();
+ for ( table::CellRangeAddress const & aCellRange : std::as_const(aCellRanges) )
+ {
+ ScRange aRange;
+ ScUnoConversion::FillScRange( aRange, aCellRange );
+ rRangeList->push_back( aRange );
+ }
+ if ( pDocShell )
+ {
+ ScChartListenerCollection* pCollection = pDocShell->GetDocument().GetChartListenerCollection();
+ if ( pCollection )
+ {
+ pCollection->ChangeListening( aChartName, rRangeList );
+ }
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void ScChartObj::getFastPropertyValue( uno::Any& rValue, sal_Int32 nHandle ) const
+{
+ switch ( nHandle )
+ {
+ case PROP_HANDLE_RELATED_CELLRANGES:
+ {
+ if (!pDocShell)
+ break;
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScChartListenerCollection* pCollection = rDoc.GetChartListenerCollection();
+ if (!pCollection)
+ break;
+
+ ScChartListener* pListener = pCollection->findByName(aChartName);
+ if (!pListener)
+ break;
+
+ const ScRangeListRef& rRangeList = pListener->GetRangeList();
+ if (!rRangeList.is())
+ break;
+
+ size_t nCount = rRangeList->size();
+ uno::Sequence<table::CellRangeAddress> aCellRanges(nCount);
+ table::CellRangeAddress* pCellRanges = aCellRanges.getArray();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ ScRange const & rRange = (*rRangeList)[i];
+ table::CellRangeAddress aCellRange;
+ ScUnoConversion::FillApiRange(aCellRange, rRange);
+ pCellRanges[i] = aCellRange;
+ }
+ rValue <<= aCellRanges;
+ }
+ break;
+ default:
+ ;
+ }
+}
+
+// ::comphelper::OPropertyArrayUsageHelper
+
+::cppu::IPropertyArrayHelper* ScChartObj::createArrayHelper() const
+{
+ uno::Sequence< beans::Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+}
+
+// XInterface
+
+IMPLEMENT_FORWARD_XINTERFACE2( ScChartObj, ScChartObj_Base, ScChartObj_PBase )
+
+// XTypeProvider
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( ScChartObj, ScChartObj_Base, ScChartObj_PBase )
+
+// XTableChart
+
+sal_Bool SAL_CALL ScChartObj::getHasColumnHeaders()
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xRanges = new ScRangeList;
+ bool bColHeaders, bRowHeaders;
+ GetData_Impl( xRanges, bColHeaders, bRowHeaders );
+ return bColHeaders;
+}
+
+void SAL_CALL ScChartObj::setHasColumnHeaders( sal_Bool bHasColumnHeaders )
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xRanges = new ScRangeList;
+ bool bOldColHeaders, bOldRowHeaders;
+ GetData_Impl( xRanges, bOldColHeaders, bOldRowHeaders );
+ if ( bOldColHeaders != bool(bHasColumnHeaders) )
+ Update_Impl( xRanges, bHasColumnHeaders, bOldRowHeaders );
+}
+
+sal_Bool SAL_CALL ScChartObj::getHasRowHeaders()
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xRanges = new ScRangeList;
+ bool bColHeaders, bRowHeaders;
+ GetData_Impl( xRanges, bColHeaders, bRowHeaders );
+ return bRowHeaders;
+}
+
+void SAL_CALL ScChartObj::setHasRowHeaders( sal_Bool bHasRowHeaders )
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xRanges = new ScRangeList;
+ bool bOldColHeaders, bOldRowHeaders;
+ GetData_Impl( xRanges, bOldColHeaders, bOldRowHeaders );
+ if ( bOldRowHeaders != bool(bHasRowHeaders) )
+ Update_Impl( xRanges, bOldColHeaders, bHasRowHeaders );
+}
+
+uno::Sequence<table::CellRangeAddress> SAL_CALL ScChartObj::getRanges()
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xRanges = new ScRangeList;
+ bool bColHeaders, bRowHeaders;
+ GetData_Impl( xRanges, bColHeaders, bRowHeaders );
+ if ( xRanges.is() )
+ {
+ size_t nCount = xRanges->size();
+
+ table::CellRangeAddress aRangeAddress;
+ uno::Sequence<table::CellRangeAddress> aSeq(nCount);
+ table::CellRangeAddress* pAry = aSeq.getArray();
+ for (size_t i = 0; i < nCount; i++)
+ {
+ ScRange const & rRange = (*xRanges)[i];
+
+ aRangeAddress.Sheet = rRange.aStart.Tab();
+ aRangeAddress.StartColumn = rRange.aStart.Col();
+ aRangeAddress.StartRow = rRange.aStart.Row();
+ aRangeAddress.EndColumn = rRange.aEnd.Col();
+ aRangeAddress.EndRow = rRange.aEnd.Row();
+
+ pAry[i] = aRangeAddress;
+ }
+ return aSeq;
+ }
+
+ OSL_FAIL("ScChartObj::getRanges: no Ranges");
+ return uno::Sequence<table::CellRangeAddress>();
+}
+
+void SAL_CALL ScChartObj::setRanges( const uno::Sequence<table::CellRangeAddress>& aRanges )
+{
+ SolarMutexGuard aGuard;
+ ScRangeListRef xOldRanges = new ScRangeList;
+ bool bColHeaders, bRowHeaders;
+ GetData_Impl( xOldRanges, bColHeaders, bRowHeaders );
+
+ ScRangeList* pList = new ScRangeList;
+ for (const table::CellRangeAddress& rRange : aRanges)
+ {
+ ScRange aRange( static_cast<SCCOL>(rRange.StartColumn), rRange.StartRow, rRange.Sheet,
+ static_cast<SCCOL>(rRange.EndColumn), rRange.EndRow, rRange.Sheet );
+ pList->push_back( aRange );
+ }
+ ScRangeListRef xNewRanges( pList );
+
+ if ( !xOldRanges.is() || *xOldRanges != *xNewRanges )
+ Update_Impl( xNewRanges, bColHeaders, bRowHeaders );
+}
+
+// XEmbeddedObjectSupplier
+
+uno::Reference<lang::XComponent> SAL_CALL ScChartObj::getEmbeddedObject()
+{
+ SolarMutexGuard aGuard;
+ SdrOle2Obj* pObject = sc::tools::findChartsByName(pDocShell, nTab, aChartName,
+ sc::tools::ChartSourceType::CELL_RANGE);
+ if ( pObject && svt::EmbeddedObjectRef::TryRunningState( pObject->GetObjRef() ) )
+ {
+ //TODO/LATER: is it OK that something is returned for *all* objects, not only own objects?
+ return uno::Reference < lang::XComponent > ( pObject->GetObjRef()->getComponent(), uno::UNO_QUERY );
+ }
+
+ return nullptr;
+}
+
+// XNamed
+
+OUString SAL_CALL ScChartObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return aChartName;
+}
+
+void SAL_CALL ScChartObj::setName( const OUString& /* aName */ )
+{
+ throw uno::RuntimeException(); // name cannot be changed
+}
+
+// XPropertySet
+
+uno::Reference< beans::XPropertySetInfo > ScChartObj::getPropertySetInfo()
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/condformatuno.cxx b/sc/source/ui/unoobj/condformatuno.cxx
new file mode 100644
index 000000000..4654efa6c
--- /dev/null
+++ b/sc/source/ui/unoobj/condformatuno.cxx
@@ -0,0 +1,1904 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <sal/config.h>
+
+#include <algorithm>
+#include <memory>
+#include <condformatuno.hxx>
+
+#include <document.hxx>
+#include <conditio.hxx>
+#include <colorscale.hxx>
+#include <docsh.hxx>
+#include <compiler.hxx>
+#include <tokenarray.hxx>
+
+#include <cellsuno.hxx>
+#include <convuno.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <vcl/svapp.hxx>
+#include <rtl/ustring.hxx>
+#include <sal/log.hxx>
+
+#include <com/sun/star/sheet/DataBarAxis.hpp>
+#include <com/sun/star/sheet/IconSetType.hpp>
+#include <com/sun/star/sheet/ConditionFormatOperator.hpp>
+#include <com/sun/star/sheet/DataBarEntryType.hpp>
+#include <com/sun/star/sheet/ColorScaleEntryType.hpp>
+#include <com/sun/star/sheet/IconSetFormatEntry.hpp>
+#include <com/sun/star/sheet/ConditionEntryType.hpp>
+#include <com/sun/star/sheet/DateType.hpp>
+
+namespace {
+
+enum CondFormatProperties
+{
+ ID,
+ CondFormat_Range
+};
+
+const SfxItemPropertyMapEntry* getCondFormatPropset()
+{
+ static const SfxItemPropertyMapEntry aCondFormatPropertyMap_Impl[] =
+ {
+ {u"ID", ID, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ {u"Range", CondFormat_Range, cppu::UnoType<sheet::XSheetCellRanges>::get(), 0, 0},
+ {u"", 0, css::uno::Type(), 0, 0}
+ };
+ return aCondFormatPropertyMap_Impl;
+}
+
+enum ConditionEntryProperties
+{
+ StyleName,
+ Formula1,
+ Formula2,
+ Operator
+};
+
+const SfxItemPropertyMapEntry* getConditionEntryrPropSet()
+{
+ static const SfxItemPropertyMapEntry aConditionEntryPropertyMap_Impl[] =
+ {
+ {u"StyleName", StyleName, cppu::UnoType<OUString>::get(), 0, 0},
+ {u"Formula1", Formula1, cppu::UnoType<OUString>::get(), 0, 0},
+ {u"Formula2", Formula2, cppu::UnoType<OUString>::get(), 0, 0},
+ {u"Operator", Operator, cppu::UnoType<decltype(sheet::ConditionFormatOperator::EQUAL)>::get(), 0, 0 },
+ {u"", 0, css::uno::Type(), 0, 0}
+ };
+ return aConditionEntryPropertyMap_Impl;
+}
+
+struct ConditionEntryApiMap
+{
+ ScConditionMode eMode;
+ sal_Int32 nApiMode;
+};
+
+ConditionEntryApiMap const aConditionEntryMap[] =
+{
+ {ScConditionMode::Equal, sheet::ConditionFormatOperator::EQUAL},
+ {ScConditionMode::Less, sheet::ConditionFormatOperator::LESS},
+ {ScConditionMode::Greater, sheet::ConditionFormatOperator::GREATER},
+ {ScConditionMode::EqLess, sheet::ConditionFormatOperator::LESS_EQUAL},
+ {ScConditionMode::EqGreater, sheet::ConditionFormatOperator::GREATER_EQUAL},
+ {ScConditionMode::NotEqual, sheet::ConditionFormatOperator::NOT_EQUAL},
+ {ScConditionMode::Between, sheet::ConditionFormatOperator::BETWEEN},
+ {ScConditionMode::NotBetween, sheet::ConditionFormatOperator::NOT_BETWEEN},
+ {ScConditionMode::Duplicate, sheet::ConditionFormatOperator::DUPLICATE},
+ {ScConditionMode::NotDuplicate, sheet::ConditionFormatOperator::UNIQUE},
+ {ScConditionMode::Direct, sheet::ConditionFormatOperator::EXPRESSION},
+ {ScConditionMode::Top10, sheet::ConditionFormatOperator::TOP_N_ELEMENTS},
+ {ScConditionMode::Bottom10, sheet::ConditionFormatOperator::BOTTOM_N_ELEMENTS},
+ {ScConditionMode::TopPercent, sheet::ConditionFormatOperator::TOP_N_PERCENT},
+ {ScConditionMode::BottomPercent, sheet::ConditionFormatOperator::BOTTOM_N_PERCENT},
+ {ScConditionMode::AboveAverage, sheet::ConditionFormatOperator::ABOVE_AVERAGE},
+ {ScConditionMode::BelowAverage, sheet::ConditionFormatOperator::BELOW_AVERAGE},
+ {ScConditionMode::AboveEqualAverage, sheet::ConditionFormatOperator::ABOVE_EQUAL_AVERAGE},
+ {ScConditionMode::BelowEqualAverage, sheet::ConditionFormatOperator::BELOW_EQUAL_AVERAGE},
+ {ScConditionMode::Error, sheet::ConditionFormatOperator::ERROR},
+ {ScConditionMode::NoError, sheet::ConditionFormatOperator::NO_ERROR},
+ {ScConditionMode::BeginsWith, sheet::ConditionFormatOperator::BEGINS_WITH},
+ {ScConditionMode::EndsWith, sheet::ConditionFormatOperator::ENDS_WITH},
+ {ScConditionMode::ContainsText, sheet::ConditionFormatOperator::CONTAINS},
+ {ScConditionMode::NotContainsText, sheet::ConditionFormatOperator::NOT_CONTAINS},
+ {ScConditionMode::NONE, sheet::ConditionFormatOperator::EQUAL},
+};
+
+enum ColorScaleProperties
+{
+ ColorScaleEntries
+};
+
+const SfxItemPropertyMapEntry* getColorScalePropSet()
+{
+ static const SfxItemPropertyMapEntry aColorScalePropertyMap_Impl[] =
+ {
+ {u"ColorScaleEntries", ColorScaleEntries, cppu::UnoType<uno::Sequence< sheet::XColorScaleEntry >>::get(), 0, 0 },
+ {u"", 0, css::uno::Type(), 0, 0}
+ };
+ return aColorScalePropertyMap_Impl;
+}
+
+struct ColorScaleEntryTypeApiMap
+{
+ ScColorScaleEntryType eType;
+ sal_Int32 nApiType;
+};
+
+ColorScaleEntryTypeApiMap const aColorScaleEntryTypeMap[] =
+{
+ { COLORSCALE_MIN, sheet::ColorScaleEntryType::COLORSCALE_MIN },
+ { COLORSCALE_MAX, sheet::ColorScaleEntryType::COLORSCALE_MAX },
+ { COLORSCALE_VALUE, sheet::ColorScaleEntryType::COLORSCALE_VALUE },
+ { COLORSCALE_FORMULA, sheet::ColorScaleEntryType::COLORSCALE_FORMULA },
+ { COLORSCALE_PERCENT, sheet::ColorScaleEntryType::COLORSCALE_PERCENT },
+ { COLORSCALE_PERCENTILE, sheet::ColorScaleEntryType::COLORSCALE_PERCENTILE }
+};
+
+enum DataBarProperties
+{
+ AxisPosition,
+ UseGradient,
+ UseNegativeColor,
+ DataBar_ShowValue,
+ DataBar_Color,
+ AxisColor,
+ NegativeColor,
+ DataBarEntries,
+ MinimumLength,
+ MaximumLength
+};
+
+const SfxItemPropertyMapEntry* getDataBarPropSet()
+{
+ static const SfxItemPropertyMapEntry aDataBarPropertyMap_Impl[] =
+ {
+ {u"AxisPosition", AxisPosition, cppu::UnoType<decltype(sheet::DataBarAxis::AXIS_AUTOMATIC)>::get(), 0, 0 },
+ {u"UseGradient", UseGradient, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"UseNegativeColor", UseNegativeColor, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"ShowValue", DataBar_ShowValue, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"Color", DataBar_Color, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ {u"AxisColor", AxisColor, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ {u"NegativeColor", NegativeColor, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ {u"DataBarEntries", DataBarEntries, cppu::UnoType<uno::Sequence< sheet::XDataBarEntry >>::get(), 0, 0 },
+ {u"MinimumLength", MinimumLength, cppu::UnoType<double>::get(), 0, 0 },
+ {u"MaximumLength", MaximumLength, cppu::UnoType<double>::get(), 0, 0 },
+ {u"", 0, css::uno::Type(), 0, 0}
+ };
+ return aDataBarPropertyMap_Impl;
+}
+
+struct DataBarAxisApiMap
+{
+ databar::ScAxisPosition ePos;
+ sal_Int32 nApiPos;
+};
+
+DataBarAxisApiMap const aDataBarAxisMap[] =
+{
+ { databar::NONE, sheet::DataBarAxis::AXIS_NONE },
+ { databar::AUTOMATIC, sheet::DataBarAxis::AXIS_AUTOMATIC },
+ { databar::MIDDLE, sheet::DataBarAxis::AXIS_MIDDLE }
+};
+
+struct DataBarEntryTypeApiMap
+{
+ ScColorScaleEntryType eType;
+ sal_Int32 nApiType;
+};
+
+DataBarEntryTypeApiMap const aDataBarEntryTypeMap[] =
+{
+ { COLORSCALE_AUTO, sheet::DataBarEntryType::DATABAR_AUTO },
+ { COLORSCALE_MIN, sheet::DataBarEntryType::DATABAR_MIN },
+ { COLORSCALE_MAX, sheet::DataBarEntryType::DATABAR_MAX },
+ { COLORSCALE_VALUE, sheet::DataBarEntryType::DATABAR_VALUE },
+ { COLORSCALE_FORMULA, sheet::DataBarEntryType::DATABAR_FORMULA },
+ { COLORSCALE_PERCENT, sheet::DataBarEntryType::DATABAR_PERCENT },
+ { COLORSCALE_PERCENTILE, sheet::DataBarEntryType::DATABAR_PERCENTILE }
+};
+
+enum IconSetProperties
+{
+ Icons,
+ Reverse,
+ ShowValue,
+ IconSetEntries
+};
+
+const SfxItemPropertyMapEntry* getIconSetPropSet()
+{
+ static const SfxItemPropertyMapEntry aIconSetPropertyMap_Impl[] =
+ {
+ {u"Icons", Icons, cppu::UnoType<decltype(sheet::IconSetType::ICONSET_3SYMBOLS)>::get(), 0, 0 },
+ {u"Reverse", Reverse, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"ShowValue", ShowValue, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"IconSetEntries", IconSetEntries, cppu::UnoType<uno::Sequence< sheet::XIconSetEntry >>::get(), 0, 0 },
+ {u"", 0, css::uno::Type(), 0, 0}
+ };
+ return aIconSetPropertyMap_Impl;
+}
+
+struct IconSetTypeApiMap
+{
+ ScIconSetType eType;
+ sal_Int32 nApiType;
+};
+
+const IconSetTypeApiMap aIconSetApiMap[] =
+{
+ { IconSet_3Arrows, sheet::IconSetType::ICONSET_3ARROWS },
+ { IconSet_3ArrowsGray, sheet::IconSetType::ICONSET_3ARROWS_GRAY },
+ { IconSet_3Flags, sheet::IconSetType::ICONSET_3FLAGS },
+ { IconSet_3TrafficLights1, sheet::IconSetType::ICONSET_3TRAFFICLIGHTS1 },
+ { IconSet_3TrafficLights2, sheet::IconSetType::ICONSET_3TRAFFICLIGHTS2 },
+ { IconSet_3Signs, sheet::IconSetType::ICONSET_3SIGNS },
+ { IconSet_3Symbols, sheet::IconSetType::ICONSET_3SYMBOLS },
+ { IconSet_3Symbols2, sheet::IconSetType::ICONSET_3SYMBOLS2 },
+ { IconSet_3Smilies, sheet::IconSetType::ICONSET_3SMILIES },
+ { IconSet_3ColorSmilies, sheet::IconSetType::ICONSET_3COLOR_SIMILIES },
+ { IconSet_4Arrows, sheet::IconSetType::ICONSET_4ARROWS },
+ { IconSet_4ArrowsGray, sheet::IconSetType::ICONSET_4ARROWS_GRAY },
+ { IconSet_4Rating, sheet::IconSetType::ICONSET_4RATING },
+ { IconSet_4RedToBlack, sheet::IconSetType::ICONSET_4RED_TO_BLACK },
+ { IconSet_4TrafficLights, sheet::IconSetType::ICONSET_4TRAFFICLIGHTS },
+ { IconSet_5Arrows, sheet::IconSetType::ICONSET_5ARROWS },
+ { IconSet_5ArrowsGray, sheet::IconSetType::ICONSET_4ARROWS_GRAY },
+ { IconSet_5Ratings, sheet::IconSetType::ICONSET_5RATINGS },
+ { IconSet_5Quarters, sheet::IconSetType::ICONSET_5QUARTERS },
+};
+
+struct IconSetEntryTypeApiMap
+{
+ ScColorScaleEntryType eType;
+ sal_Int32 nApiType;
+};
+
+IconSetEntryTypeApiMap const aIconSetEntryTypeMap[] =
+{
+ { COLORSCALE_MIN, sheet::IconSetFormatEntry::ICONSET_MIN },
+ { COLORSCALE_VALUE, sheet::IconSetFormatEntry::ICONSET_VALUE },
+ { COLORSCALE_FORMULA, sheet::IconSetFormatEntry::ICONSET_FORMULA },
+ { COLORSCALE_PERCENT, sheet::IconSetFormatEntry::ICONSET_PERCENT },
+ { COLORSCALE_PERCENTILE, sheet::IconSetFormatEntry::ICONSET_PERCENTILE }
+};
+
+enum DateProperties
+{
+ Date_StyleName,
+ DateType
+};
+
+const SfxItemPropertyMapEntry* getCondDatePropSet()
+{
+ static const SfxItemPropertyMapEntry aCondDatePropertyMap_Impl[] =
+ {
+ {u"StyleName", StyleName, cppu::UnoType<OUString>::get(), 0, 0},
+ {u"DateType", Icons, cppu::UnoType<decltype(sheet::DateType::TODAY)>::get(), 0, 0 },
+ {u"", 0, css::uno::Type(), 0, 0}
+ };
+ return aCondDatePropertyMap_Impl;
+}
+
+struct DateTypeApiMap
+{
+ condformat::ScCondFormatDateType eType;
+ sal_Int32 nApiType;
+};
+
+DateTypeApiMap const aDateTypeApiMap[] =
+{
+ { condformat::TODAY, sheet::DateType::TODAY },
+ { condformat::YESTERDAY, sheet::DateType::YESTERDAY },
+ { condformat::TOMORROW, sheet::DateType::TOMORROW },
+ { condformat::LAST7DAYS, sheet::DateType::LAST7DAYS },
+ { condformat::THISWEEK, sheet::DateType::THISWEEK },
+ { condformat::LASTWEEK, sheet::DateType::LASTWEEK },
+ { condformat::NEXTWEEK, sheet::DateType::NEXTWEEK },
+ { condformat::THISMONTH, sheet::DateType::THISMONTH },
+ { condformat::LASTMONTH, sheet::DateType::LASTMONTH },
+ { condformat::NEXTMONTH, sheet::DateType::NEXTMONTH },
+ { condformat::THISYEAR, sheet::DateType::THISYEAR },
+ { condformat::LASTYEAR, sheet::DateType::LASTYEAR },
+ { condformat::NEXTYEAR, sheet::DateType::NEXTYEAR }
+};
+
+}
+
+ScCondFormatsObj::ScCondFormatsObj(ScDocShell* pDocShell, SCTAB nTab):
+ mnTab(nTab),
+ mpDocShell(pDocShell)
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScCondFormatsObj::~ScCondFormatsObj()
+{
+ if (mpDocShell)
+ mpDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScCondFormatsObj::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ mpDocShell = nullptr;
+ }
+}
+
+sal_Int32 ScCondFormatsObj::createByRange(const uno::Reference< sheet::XSheetCellRanges >& xRanges)
+{
+ SolarMutexGuard aGuard;
+ if (!mpDocShell)
+ throw lang::IllegalArgumentException();
+
+ if (!xRanges.is())
+ throw lang::IllegalArgumentException();
+
+ const uno::Sequence<table::CellRangeAddress> aRanges =
+ xRanges->getRangeAddresses();
+
+ ScRangeList aCoreRange;
+ for (const auto& rRange : aRanges)
+ {
+ ScRange aRange;
+ ScUnoConversion::FillScRange(aRange, rRange);
+ aCoreRange.Join(aRange);
+ }
+
+ if (aCoreRange.empty())
+ throw lang::IllegalArgumentException();
+
+ SCTAB nTab = aCoreRange[0].aStart.Tab();
+
+ auto pNewFormat = std::make_unique<ScConditionalFormat>(0, &mpDocShell->GetDocument());
+ pNewFormat->SetRange(aCoreRange);
+ return mpDocShell->GetDocument().AddCondFormat(std::move(pNewFormat), nTab);
+}
+
+void ScCondFormatsObj::removeByID(const sal_Int32 nID)
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormatList* pFormatList = getCoreObject();
+ pFormatList->erase(nID);
+}
+
+uno::Sequence<uno::Reference<sheet::XConditionalFormat> > ScCondFormatsObj::getConditionalFormats()
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormatList* pFormatList = getCoreObject();
+ size_t n = pFormatList->size();
+ uno::Sequence<uno::Reference<sheet::XConditionalFormat> > aCondFormats(n);
+ std::transform(pFormatList->begin(), pFormatList->end(), aCondFormats.getArray(),
+ [this](const auto& rFormat)
+ { return uno::Reference(new ScCondFormatObj(mpDocShell, this, rFormat->GetKey())); });
+
+ return aCondFormats;
+}
+
+sal_Int32 ScCondFormatsObj::getLength()
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormatList* pFormatList = getCoreObject();
+ return pFormatList->size();
+}
+
+ScConditionalFormatList* ScCondFormatsObj::getCoreObject()
+{
+ if (!mpDocShell)
+ throw uno::RuntimeException();
+
+ ScConditionalFormatList* pList = mpDocShell->GetDocument().GetCondFormList(mnTab);
+ if (!pList)
+ throw uno::RuntimeException();
+
+ return pList;
+}
+
+namespace {
+
+uno::Reference<beans::XPropertySet> createConditionEntry(const ScFormatEntry* pEntry,
+ rtl::Reference<ScCondFormatObj> const & xParent)
+{
+ switch (pEntry->GetType())
+ {
+ case ScFormatEntry::Type::Condition:
+ case ScFormatEntry::Type::ExtCondition:
+ return new ScConditionEntryObj(xParent,
+ static_cast<const ScCondFormatEntry*>(pEntry));
+ break;
+ case ScFormatEntry::Type::Colorscale:
+ return new ScColorScaleFormatObj(xParent,
+ static_cast<const ScColorScaleFormat*>(pEntry));
+ break;
+ case ScFormatEntry::Type::Databar:
+ return new ScDataBarFormatObj(xParent,
+ static_cast<const ScDataBarFormat*>(pEntry));
+ break;
+ case ScFormatEntry::Type::Iconset:
+ return new ScIconSetFormatObj(xParent,
+ static_cast<const ScIconSetFormat*>(pEntry));
+ break;
+ case ScFormatEntry::Type::Date:
+ return new ScCondDateFormatObj(xParent,
+ static_cast<const ScCondDateFormatEntry*>(pEntry));
+ break;
+ default:
+ break;
+ }
+ return uno::Reference<beans::XPropertySet>();
+}
+
+}
+
+ScCondFormatObj::ScCondFormatObj(ScDocShell* pDocShell, rtl::Reference<ScCondFormatsObj> const & xCondFormats,
+ sal_Int32 nKey):
+ mxCondFormatList(xCondFormats),
+ mpDocShell(pDocShell),
+ maPropSet(getCondFormatPropset()),
+ mnKey(nKey)
+{
+}
+
+ScCondFormatObj::~ScCondFormatObj()
+{
+}
+
+ScConditionalFormat* ScCondFormatObj::getCoreObject()
+{
+ ScConditionalFormatList* pList = mxCondFormatList->getCoreObject();
+ ScConditionalFormat* pFormat = pList->GetFormat(mnKey);
+ if (!pFormat)
+ throw uno::RuntimeException();
+
+ return pFormat;
+}
+
+ScDocShell* ScCondFormatObj::getDocShell()
+{
+ return mpDocShell;
+}
+
+void ScCondFormatObj::createEntry(const sal_Int32 nType, const sal_Int32 nPos)
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormat* pFormat = getCoreObject();
+ if (nPos > sal_Int32(pFormat->size()))
+ throw lang::IllegalArgumentException();
+
+ ScFormatEntry* pNewEntry = nullptr;
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ switch (nType)
+ {
+ case sheet::ConditionEntryType::CONDITION:
+ pNewEntry = new ScCondFormatEntry(ScConditionMode::Equal, "", "",
+ rDoc, pFormat->GetRange().GetTopLeftCorner(), "");
+ break;
+ case sheet::ConditionEntryType::COLORSCALE:
+ pNewEntry = new ScColorScaleFormat(&rDoc);
+ static_cast<ScColorScaleFormat*>(pNewEntry)->EnsureSize();
+ break;
+ case sheet::ConditionEntryType::DATABAR:
+ pNewEntry = new ScDataBarFormat(&rDoc);
+ static_cast<ScDataBarFormat*>(pNewEntry)->EnsureSize();
+ break;
+ case sheet::ConditionEntryType::ICONSET:
+ pNewEntry = new ScIconSetFormat(&rDoc);
+ static_cast<ScIconSetFormat*>(pNewEntry)->EnsureSize();
+ break;
+ case sheet::ConditionEntryType::DATE:
+ pNewEntry = new ScCondDateFormatEntry(&rDoc);
+ break;
+ default:
+ SAL_WARN("sc", "unknown conditional format type");
+ throw lang::IllegalArgumentException();
+ }
+
+ pFormat->AddEntry(pNewEntry);
+}
+
+void ScCondFormatObj::removeByIndex(const sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ if (getCoreObject()->size() >= o3tl::make_unsigned(nIndex))
+ throw lang::IllegalArgumentException();
+
+ getCoreObject()->RemoveEntry(nIndex);
+}
+
+uno::Type ScCondFormatObj::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get();
+}
+
+sal_Bool ScCondFormatObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormat* pFormat = getCoreObject();
+ return !pFormat->IsEmpty();
+}
+
+sal_Int32 ScCondFormatObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ ScConditionalFormat* pFormat = getCoreObject();
+
+ return pFormat->size();
+}
+
+uno::Any ScCondFormatObj::getByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ if (getCoreObject()->size() <= o3tl::make_unsigned(nIndex))
+ throw lang::IllegalArgumentException();
+
+ const ScFormatEntry* pEntry = getCoreObject()->GetEntry(nIndex);
+ uno::Reference<beans::XPropertySet> xCondEntry =
+ createConditionEntry(pEntry, this);
+ return uno::Any(xCondEntry);
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCondFormatObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap()));
+ return aRef;
+}
+
+void SAL_CALL ScCondFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case ID:
+ throw lang::IllegalArgumentException();
+ break;
+ case CondFormat_Range:
+ {
+ uno::Reference<sheet::XSheetCellRanges> xRange;
+ if (aValue >>= xRange)
+ {
+ ScConditionalFormat* pFormat = getCoreObject();
+ const uno::Sequence<table::CellRangeAddress> aRanges =
+ xRange->getRangeAddresses();
+ ScRangeList aTargetRange;
+ for (const auto& rRange : aRanges)
+ {
+ ScRange aRange;
+ ScUnoConversion::FillScRange(aRange, rRange);
+ aTargetRange.Join(aRange);
+ }
+ pFormat->SetRange(aTargetRange);
+ }
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+}
+
+uno::Any SAL_CALL ScCondFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+ switch(pEntry->nWID)
+ {
+ case ID:
+ aAny <<= sal_Int32(getCoreObject()->GetKey());
+ break;
+ case CondFormat_Range:
+ {
+ const ScRangeList& rRange = getCoreObject()->GetRange();
+ uno::Reference<sheet::XSheetCellRanges> xRange;
+ xRange.set(new ScCellRangesObj(mpDocShell, rRange));
+ aAny <<= xRange;
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+ return aAny;
+}
+
+void SAL_CALL ScCondFormatObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondFormatObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondFormatObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondFormatObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+namespace {
+
+bool isObjectStillAlive(const ScConditionalFormat* pFormat, const ScFormatEntry* pEntry)
+{
+ for(size_t i = 0, n= pFormat->size(); i < n; ++i)
+ {
+ if (pFormat->GetEntry(i) == pEntry)
+ return true;
+ }
+ return false;
+}
+
+}
+
+ScConditionEntryObj::ScConditionEntryObj(rtl::Reference<ScCondFormatObj> const & xParent,
+ const ScCondFormatEntry* pFormat):
+ mpDocShell(xParent->getDocShell()),
+ mxParent(xParent),
+ maPropSet(getConditionEntryrPropSet()),
+ mpFormat(pFormat)
+{
+}
+
+ScConditionEntryObj::~ScConditionEntryObj()
+{
+}
+
+ScCondFormatEntry* ScConditionEntryObj::getCoreObject()
+{
+ ScConditionalFormat* pFormat = mxParent->getCoreObject();
+ if (isObjectStillAlive(pFormat, mpFormat))
+ return const_cast<ScCondFormatEntry*>(mpFormat);
+
+ throw lang::IllegalArgumentException();
+}
+
+sal_Int32 ScConditionEntryObj::getType()
+{
+ return sheet::ConditionEntryType::CONDITION;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScConditionEntryObj::getPropertySetInfo()
+{
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScConditionEntryObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case StyleName:
+ {
+ OUString aStyleName;
+ if ((aValue >>= aStyleName) && !aStyleName.isEmpty())
+ getCoreObject()->UpdateStyleName(aStyleName);
+ }
+ break;
+ case Formula1:
+ {
+ OUString aFormula;
+ if ((aValue >>= aFormula) && !aFormula.isEmpty())
+ {
+ ScCompiler aComp(mpDocShell->GetDocument(), getCoreObject()->GetSrcPos());
+ aComp.SetGrammar(mpDocShell->GetDocument().GetGrammar());
+ std::unique_ptr<ScTokenArray> pArr(aComp.CompileString(aFormula));
+ getCoreObject()->SetFormula1(*pArr);
+ }
+ }
+ break;
+ case Formula2:
+ {
+ OUString aFormula;
+ if ((aValue >>= aFormula) && !aFormula.isEmpty())
+ {
+ ScCompiler aComp(mpDocShell->GetDocument(), getCoreObject()->GetSrcPos());
+ aComp.SetGrammar(mpDocShell->GetDocument().GetGrammar());
+ std::unique_ptr<ScTokenArray> pArr(aComp.CompileString(aFormula));
+ getCoreObject()->SetFormula2(*pArr);
+ }
+ }
+ break;
+ case Operator:
+ {
+ sal_Int32 nVal;
+ if (aValue >>= nVal)
+ {
+ for (ConditionEntryApiMap const & rEntry : aConditionEntryMap)
+ {
+ if (rEntry.nApiMode == nVal)
+ {
+ getCoreObject()->SetOperation(rEntry.eMode);
+ break;
+ }
+ }
+ }
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unsupported property");
+ }
+}
+
+uno::Any SAL_CALL ScConditionEntryObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+ switch(pEntry->nWID)
+ {
+ case StyleName:
+ aAny <<= getCoreObject()->GetStyle();
+ break;
+ case Formula1:
+ {
+ ScAddress aCursor = getCoreObject()->GetSrcPos();
+ OUString aFormula = getCoreObject()->GetExpression(aCursor, 0);
+ aAny <<= aFormula;
+ }
+ break;
+ case Formula2:
+ {
+ ScAddress aCursor = getCoreObject()->GetSrcPos();
+ OUString aFormula = getCoreObject()->GetExpression(aCursor, 1);
+ aAny <<= aFormula;
+ }
+ break;
+ case Operator:
+ {
+ ScConditionMode eMode = getCoreObject()->GetOperation();
+ for (ConditionEntryApiMap const & rEntry : aConditionEntryMap)
+ {
+ if (rEntry.eMode == eMode)
+ {
+ aAny <<= rEntry.nApiMode;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unsupported property");
+ }
+ return aAny;
+}
+
+void SAL_CALL ScConditionEntryObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScConditionEntryObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScConditionEntryObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScConditionEntryObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+ScColorScaleFormatObj::ScColorScaleFormatObj(rtl::Reference<ScCondFormatObj> const & xParent,
+ const ScColorScaleFormat* pFormat):
+ mxParent(xParent),
+ maPropSet(getColorScalePropSet()),
+ mpFormat(pFormat)
+{
+}
+
+ScColorScaleFormatObj::~ScColorScaleFormatObj()
+{
+}
+
+ScColorScaleFormat* ScColorScaleFormatObj::getCoreObject()
+{
+ ScConditionalFormat* pFormat = mxParent->getCoreObject();
+ if (isObjectStillAlive(pFormat, mpFormat))
+ return const_cast<ScColorScaleFormat*>(mpFormat);
+
+ throw lang::IllegalArgumentException();
+}
+
+sal_Int32 ScColorScaleFormatObj::getType()
+{
+ return sheet::ConditionEntryType::COLORSCALE;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScColorScaleFormatObj::getPropertySetInfo()
+{
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+namespace {
+
+void setColorScaleEntry(ScColorScaleEntry* pEntry, uno::Reference<sheet::XColorScaleEntry> const & xEntry)
+{
+ ScColorScaleEntryType eType = ScColorScaleEntryType();
+ sal_Int32 nApiType = xEntry->getType();
+ bool bFound = false;
+ for (ColorScaleEntryTypeApiMap const & rEntry : aColorScaleEntryTypeMap)
+ {
+ if (rEntry.nApiType == nApiType)
+ {
+ eType = rEntry.eType;
+ bFound = true;
+ break;
+ }
+ }
+
+ if (!bFound)
+ throw lang::IllegalArgumentException();
+
+ pEntry->SetType(eType);
+ pEntry->SetColor(Color(ColorTransparency, xEntry->getColor()));
+ switch (eType)
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ {
+ double nVal = xEntry->getFormula().toDouble();
+ pEntry->SetValue(nVal);
+ }
+ break;
+ }
+}
+
+}
+
+void SAL_CALL ScColorScaleFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case ColorScaleEntries:
+ {
+ uno::Sequence<uno::Reference<sheet::XColorScaleEntry> > aEntries;
+ if (!(aValue >>= aEntries))
+ throw lang::IllegalArgumentException();
+
+ if (aEntries.getLength() < 2)
+ throw lang::IllegalArgumentException();
+
+ // TODO: we need to make sure that there are enough entries
+ size_t n = size_t(aEntries.getLength());
+ for (size_t i = 0; i < n; ++i)
+ {
+ setColorScaleEntry(getCoreObject()->GetEntry(i), aEntries[i]);
+ }
+
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+}
+
+uno::Any SAL_CALL ScColorScaleFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+
+ switch(pEntry->nWID)
+ {
+ case ColorScaleEntries:
+ {
+ uno::Sequence<uno::Reference<sheet::XColorScaleEntry> > aEntries(getCoreObject()->size());
+ auto aEntriesRange = asNonConstRange(aEntries);
+ for (size_t i = 0; i < getCoreObject()->size(); ++i)
+ {
+ aEntriesRange[i] = new ScColorScaleEntryObj(this, i);
+ }
+ aAny <<= aEntries;
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+
+ return aAny;
+}
+
+void SAL_CALL ScColorScaleFormatObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScColorScaleFormatObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScColorScaleFormatObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScColorScaleFormatObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+ScColorScaleEntryObj::ScColorScaleEntryObj(rtl::Reference<ScColorScaleFormatObj> const & xParent,
+ size_t nPos):
+ mxParent(xParent),
+ mnPos(nPos)
+{
+}
+
+ScColorScaleEntryObj::~ScColorScaleEntryObj()
+{
+}
+
+ScColorScaleEntry* ScColorScaleEntryObj::getCoreObject()
+{
+ ScColorScaleFormat* pFormat = mxParent->getCoreObject();
+ if (pFormat->size() <= mnPos)
+ throw lang::IllegalArgumentException();
+
+ return pFormat->GetEntry(mnPos);
+}
+
+sal_Int32 ScColorScaleEntryObj::getColor()
+{
+ Color aColor = getCoreObject()->GetColor();
+ return sal_Int32(aColor);
+}
+
+void ScColorScaleEntryObj::setColor(sal_Int32 aColor)
+{
+ getCoreObject()->SetColor(Color(ColorTransparency, aColor));
+}
+
+sal_Int32 ScColorScaleEntryObj::getType()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ for (ColorScaleEntryTypeApiMap const & rEntry : aColorScaleEntryTypeMap)
+ {
+ if (rEntry.eType == pEntry->GetType())
+ {
+ return rEntry.nApiType;
+ }
+ }
+
+ throw lang::IllegalArgumentException();
+}
+
+void ScColorScaleEntryObj::setType(sal_Int32 nType)
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ for (ColorScaleEntryTypeApiMap const & rEntry : aColorScaleEntryTypeMap)
+ {
+ if (rEntry.nApiType == nType)
+ {
+ pEntry->SetType(rEntry.eType);
+ return;
+ }
+ }
+ throw lang::IllegalArgumentException();
+}
+
+OUString ScColorScaleEntryObj::getFormula()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ return OUString::number(pEntry->GetValue());
+ }
+
+ return OUString();
+}
+
+void ScColorScaleEntryObj::setFormula(const OUString& rFormula)
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ // pEntry->SetFormula(rFormula);
+ break;
+ default:
+ pEntry->SetValue(rFormula.toDouble());
+ break;
+ }
+}
+
+
+ScDataBarFormatObj::ScDataBarFormatObj(rtl::Reference<ScCondFormatObj> const & xParent,
+ const ScDataBarFormat* pFormat):
+ mxParent(xParent),
+ maPropSet(getDataBarPropSet()),
+ mpFormat(pFormat)
+{
+}
+
+ScDataBarFormatObj::~ScDataBarFormatObj()
+{
+}
+
+ScDataBarFormat* ScDataBarFormatObj::getCoreObject()
+{
+ ScConditionalFormat* pFormat = mxParent->getCoreObject();
+ if (isObjectStillAlive(pFormat, mpFormat))
+ return const_cast<ScDataBarFormat*>(mpFormat);
+
+ throw lang::IllegalArgumentException();
+}
+
+sal_Int32 ScDataBarFormatObj::getType()
+{
+ return sheet::ConditionEntryType::DATABAR;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDataBarFormatObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+namespace {
+
+void setDataBarEntry(ScColorScaleEntry* pEntry, uno::Reference<sheet::XDataBarEntry> const & xEntry)
+{
+ ScColorScaleEntryType eType = ScColorScaleEntryType();
+ sal_Int32 nApiType = xEntry->getType();
+ bool bFound = false;
+ for (DataBarEntryTypeApiMap const & rEntry : aDataBarEntryTypeMap)
+ {
+ if (rEntry.nApiType == nApiType)
+ {
+ eType = rEntry.eType;
+ bFound = true;
+ break;
+ }
+ }
+
+ if (!bFound)
+ throw lang::IllegalArgumentException();
+
+ pEntry->SetType(eType);
+ switch (eType)
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ {
+ double nVal = xEntry->getFormula().toDouble();
+ pEntry->SetValue(nVal);
+ }
+ break;
+ }
+}
+
+}
+
+void SAL_CALL ScDataBarFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case AxisPosition:
+ {
+ sal_Int32 nVal;
+ if (aValue >>= nVal)
+ {
+ for (DataBarAxisApiMap const & rEntry : aDataBarAxisMap)
+ {
+ if (rEntry.nApiPos == nVal)
+ {
+ getCoreObject()->GetDataBarData()->meAxisPosition =
+ rEntry.ePos;
+ break;
+ }
+ }
+ }
+ }
+ break;
+ case UseGradient:
+ {
+ bool bUseGradient = true;
+ if (aValue >>= bUseGradient)
+ {
+ getCoreObject()->GetDataBarData()->mbGradient = bUseGradient;
+ }
+ }
+ break;
+ case UseNegativeColor:
+ {
+ bool bUseNegativeColor = false;
+ if (aValue >>= bUseNegativeColor)
+ {
+ getCoreObject()->GetDataBarData()->mbNeg = bUseNegativeColor;
+ if (bUseNegativeColor && !getCoreObject()->GetDataBarData()->mxNegativeColor)
+ {
+ getCoreObject()->GetDataBarData()->mxNegativeColor = COL_AUTO;
+ }
+ }
+ }
+ break;
+ case DataBar_ShowValue:
+ {
+ bool bShowValue = true;
+ if (aValue >>= bShowValue)
+ {
+ getCoreObject()->GetDataBarData()->mbOnlyBar = !bShowValue;
+ }
+ }
+ break;
+ case DataBar_Color:
+ {
+ Color nColor = COL_AUTO;
+ if (aValue >>= nColor)
+ {
+ getCoreObject()->GetDataBarData()->maPositiveColor = nColor;
+ }
+ }
+ break;
+ case AxisColor:
+ {
+ Color nAxisColor = COL_AUTO;
+ if (aValue >>= nAxisColor)
+ {
+ getCoreObject()->GetDataBarData()->maAxisColor = nAxisColor;
+ }
+ }
+ break;
+ case NegativeColor:
+ {
+ Color nNegativeColor = COL_AUTO;
+ if (!(aValue >>= nNegativeColor) || !getCoreObject()->GetDataBarData()->mbNeg)
+ throw lang::IllegalArgumentException();
+
+ getCoreObject()->GetDataBarData()->mxNegativeColor = nNegativeColor;
+
+ }
+ break;
+ case DataBarEntries:
+ {
+ uno::Sequence<uno::Reference<sheet::XDataBarEntry> > aEntries;
+ if (!(aValue >>= aEntries))
+ throw lang::IllegalArgumentException();
+
+ if (aEntries.getLength() != 2)
+ throw lang::IllegalArgumentException();
+
+ setDataBarEntry(getCoreObject()->GetDataBarData()->mpLowerLimit.get(),
+ aEntries[0]);
+ setDataBarEntry(getCoreObject()->GetDataBarData()->mpUpperLimit.get(),
+ aEntries[1]);
+
+ }
+ break;
+ case MinimumLength:
+ {
+ double nLength = 0;
+ if (!(aValue >>= nLength) || nLength >= 100 || nLength < 0)
+ throw lang::IllegalArgumentException();
+ getCoreObject()->GetDataBarData()->mnMinLength = nLength;
+
+ }
+ break;
+ case MaximumLength:
+ {
+ double nLength = 0;
+ if (!(aValue >>= nLength) || nLength > 100 || nLength <= 0)
+ throw lang::IllegalArgumentException();
+ getCoreObject()->GetDataBarData()->mnMaxLength = nLength;
+
+ }
+ break;
+ }
+}
+
+uno::Any SAL_CALL ScDataBarFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+ switch(pEntry->nWID)
+ {
+ case AxisPosition:
+ {
+ databar::ScAxisPosition ePos = getCoreObject()->GetDataBarData()->meAxisPosition;
+ sal_Int32 nApiPos = sheet::DataBarAxis::AXIS_NONE;
+ for (DataBarAxisApiMap const & rEntry : aDataBarAxisMap)
+ {
+ if (rEntry.ePos == ePos)
+ {
+ nApiPos = rEntry.nApiPos;
+ }
+ }
+
+ aAny <<= nApiPos;
+ }
+ break;
+ case UseGradient:
+ {
+ aAny <<= getCoreObject()->GetDataBarData()->mbGradient;
+ }
+ break;
+ case UseNegativeColor:
+ {
+ aAny <<= getCoreObject()->GetDataBarData()->mbNeg;
+ }
+ break;
+ case DataBar_ShowValue:
+ {
+ aAny <<= !getCoreObject()->GetDataBarData()->mbOnlyBar;
+ }
+ break;
+ case DataBar_Color:
+ {
+ aAny <<= getCoreObject()->GetDataBarData()->maPositiveColor;
+ }
+ break;
+ case AxisColor:
+ {
+ aAny <<= getCoreObject()->GetDataBarData()->maAxisColor;
+ }
+ break;
+ case NegativeColor:
+ {
+ if (getCoreObject()->GetDataBarData()->mbNeg && getCoreObject()->GetDataBarData()->mxNegativeColor)
+ {
+ aAny <<= *getCoreObject()->GetDataBarData()->mxNegativeColor;
+ }
+ }
+ break;
+ case DataBarEntries:
+ {
+ uno::Sequence<uno::Reference<sheet::XDataBarEntry> > aEntries
+ {
+ new ScDataBarEntryObj(this, 0),
+ new ScDataBarEntryObj(this, 1)
+ };
+ aAny <<= aEntries;
+ }
+ break;
+ }
+ return aAny;
+}
+
+void SAL_CALL ScDataBarFormatObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScDataBarFormatObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScDataBarFormatObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScDataBarFormatObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+ScDataBarEntryObj::ScDataBarEntryObj(rtl::Reference<ScDataBarFormatObj> const & xParent,
+ size_t nPos):
+ mxParent(xParent),
+ mnPos(nPos)
+{
+}
+
+ScDataBarEntryObj::~ScDataBarEntryObj()
+{
+}
+
+ScColorScaleEntry* ScDataBarEntryObj::getCoreObject()
+{
+ ScDataBarFormat* pFormat = mxParent->getCoreObject();
+ ScColorScaleEntry* pEntry;
+ if (mnPos == 0)
+ pEntry = pFormat->GetDataBarData()->mpLowerLimit.get();
+ else
+ pEntry = pFormat->GetDataBarData()->mpUpperLimit.get();
+
+ return pEntry;
+}
+
+sal_Int32 ScDataBarEntryObj::getType()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ for (DataBarEntryTypeApiMap const & rEntry : aDataBarEntryTypeMap)
+ {
+ if (rEntry.eType == pEntry->GetType())
+ {
+ return rEntry.nApiType;
+ }
+ }
+
+ throw lang::IllegalArgumentException();
+}
+
+void ScDataBarEntryObj::setType(sal_Int32 nType)
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ for (DataBarEntryTypeApiMap const & rEntry : aDataBarEntryTypeMap)
+ {
+ if (rEntry.nApiType == nType)
+ {
+ pEntry->SetType(rEntry.eType);
+ return;
+ }
+ }
+ throw lang::IllegalArgumentException();
+}
+
+OUString ScDataBarEntryObj::getFormula()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ return OUString::number(pEntry->GetValue());
+ }
+
+ return OUString();
+}
+
+void ScDataBarEntryObj::setFormula(const OUString& rFormula)
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ // pEntry->SetFormula(rFormula);
+ break;
+ default:
+ pEntry->SetValue(rFormula.toDouble());
+ break;
+ }
+}
+
+
+ScIconSetFormatObj::ScIconSetFormatObj(rtl::Reference<ScCondFormatObj> const & xParent,
+ const ScIconSetFormat* pFormat):
+ mxParent(xParent),
+ maPropSet(getIconSetPropSet()),
+ mpFormat(pFormat)
+{
+}
+
+ScIconSetFormatObj::~ScIconSetFormatObj()
+{
+}
+
+ScIconSetFormat* ScIconSetFormatObj::getCoreObject()
+{
+ ScConditionalFormat* pFormat = mxParent->getCoreObject();
+ if (isObjectStillAlive(pFormat, mpFormat))
+ return const_cast<ScIconSetFormat*>(mpFormat);
+
+ throw lang::IllegalArgumentException();
+}
+
+sal_Int32 ScIconSetFormatObj::getType()
+{
+ return sheet::ConditionEntryType::ICONSET;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScIconSetFormatObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+namespace {
+
+void setIconSetEntry(ScIconSetFormat* pFormat, uno::Reference<sheet::XIconSetEntry> const & xEntry, size_t nPos)
+{
+ ScIconSetFormatData* pData = pFormat->GetIconSetData();
+ ScColorScaleEntryType eType = ScColorScaleEntryType();
+ sal_Int32 nApiType = xEntry->getType();
+ bool bFound = false;
+ for (IconSetEntryTypeApiMap const & rEntry : aIconSetEntryTypeMap)
+ {
+ if (rEntry.nApiType == nApiType)
+ {
+ eType = rEntry.eType;
+ bFound = true;
+ break;
+ }
+ }
+
+ if (!bFound)
+ throw lang::IllegalArgumentException();
+
+ pData->m_Entries[nPos]->SetType(eType);
+ switch (eType)
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ {
+ double nVal = xEntry->getFormula().toDouble();
+ pData->m_Entries[nPos]->SetValue(nVal);
+ }
+ break;
+ }
+}
+
+}
+
+void SAL_CALL ScIconSetFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case ShowValue:
+ {
+ bool bShowValue = true;
+ aValue >>= bShowValue;
+ getCoreObject()->GetIconSetData()->mbShowValue = bShowValue;
+ }
+ break;
+ case Reverse:
+ {
+ bool bReverse = false;
+ aValue >>= bReverse;
+ getCoreObject()->GetIconSetData()->mbReverse = bReverse;
+ }
+ break;
+ case Icons:
+ {
+ sal_Int32 nApiType = -1;
+ aValue >>= nApiType;
+ ScIconSetType eType = IconSet_3Arrows;
+ bool bFound = false;
+ for (const IconSetTypeApiMap & rEntry : aIconSetApiMap)
+ {
+ if (rEntry.nApiType == nApiType)
+ {
+ eType = rEntry.eType;
+ bFound = true;
+ break;
+ }
+ }
+
+ if (!bFound)
+ {
+ throw lang::IllegalArgumentException();
+ }
+
+ // TODO: we need to make sure that there are enough entries
+ getCoreObject()->GetIconSetData()->eIconSetType = eType;
+ }
+ break;
+ case IconSetEntries:
+ {
+ uno::Sequence<uno::Reference<sheet::XIconSetEntry> > aEntries;
+ if (!(aValue >>= aEntries))
+ throw lang::IllegalArgumentException();
+
+ // TODO: we need to check that the number of entries
+ // corresponds to the icon type
+ sal_Int32 nLength = aEntries.getLength();
+ for (size_t i = 0; i < o3tl::make_unsigned(nLength); ++i)
+ {
+ setIconSetEntry(getCoreObject(), aEntries[i], i);
+ }
+
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+uno::Any SAL_CALL ScIconSetFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+
+ switch(pEntry->nWID)
+ {
+ case ShowValue:
+ aAny <<= getCoreObject()->GetIconSetData()->mbShowValue;
+ break;
+ case Reverse:
+ aAny <<= getCoreObject()->GetIconSetData()->mbReverse;
+ break;
+ case Icons:
+ {
+ ScIconSetType eType = getCoreObject()->GetIconSetData()->eIconSetType;
+ for (const IconSetTypeApiMap & rEntry : aIconSetApiMap)
+ {
+ if (rEntry.eType == eType)
+ {
+ aAny <<= rEntry.nApiType;
+ break;
+ }
+ }
+ }
+ break;
+ case IconSetEntries:
+ {
+ size_t nSize = getCoreObject()->size();
+ uno::Sequence<uno::Reference<sheet::XIconSetEntry> > aEntries(nSize);
+ auto aEntriesRange = asNonConstRange(aEntries);
+ for (size_t i = 0; i < nSize; ++i)
+ {
+ aEntriesRange[i] = new ScIconSetEntryObj(this, i);
+ }
+ aAny <<= aEntries;
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+ return aAny;
+}
+
+void SAL_CALL ScIconSetFormatObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScIconSetFormatObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScIconSetFormatObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScIconSetFormatObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+ScIconSetEntryObj::ScIconSetEntryObj(rtl::Reference<ScIconSetFormatObj> const & xParent,
+ size_t nPos):
+ mxParent(xParent),
+ mnPos(nPos)
+{
+}
+
+ScIconSetEntryObj::~ScIconSetEntryObj()
+{
+}
+
+ScColorScaleEntry* ScIconSetEntryObj::getCoreObject()
+{
+ ScIconSetFormat* pFormat = mxParent->getCoreObject();
+ if (pFormat->GetIconSetData()->m_Entries.size() <= mnPos)
+ throw lang::IllegalArgumentException();
+
+ return pFormat->GetIconSetData()->m_Entries[mnPos].get();
+}
+
+sal_Int32 ScIconSetEntryObj::getType()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ // the first entry always is minimum
+ if (mnPos == 0)
+ return sheet::IconSetFormatEntry::ICONSET_MIN;
+
+ for (IconSetEntryTypeApiMap const & rEntry : aIconSetEntryTypeMap)
+ {
+ if (rEntry.eType == pEntry->GetType())
+ {
+ return rEntry.nApiType;
+ }
+ }
+
+ throw lang::IllegalArgumentException();
+}
+
+void ScIconSetEntryObj::setType(sal_Int32 nType)
+{
+ // first entry is always MIN
+ if (mnPos == 0)
+ return;
+
+ ScColorScaleEntry* pEntry = getCoreObject();
+ for (IconSetEntryTypeApiMap const & rEntry : aIconSetEntryTypeMap)
+ {
+ if (rEntry.nApiType == nType)
+ {
+ pEntry->SetType(rEntry.eType);
+ return;
+ }
+ }
+ throw lang::IllegalArgumentException();
+}
+
+OUString ScIconSetEntryObj::getFormula()
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ break;
+ default:
+ return OUString::number(pEntry->GetValue());
+ }
+
+ return OUString();
+}
+
+void ScIconSetEntryObj::setFormula(const OUString& rFormula)
+{
+ ScColorScaleEntry* pEntry = getCoreObject();
+ switch (pEntry->GetType())
+ {
+ case COLORSCALE_FORMULA:
+ // TODO: Implement
+ // pEntry->SetFormula(rFormula);
+ break;
+ default:
+ pEntry->SetValue(rFormula.toDouble());
+ break;
+ }
+}
+
+ScCondDateFormatObj::ScCondDateFormatObj(rtl::Reference<ScCondFormatObj> const & xParent,
+ const ScCondDateFormatEntry* pFormat):
+ mxParent(xParent),
+ maPropSet(getCondDatePropSet()),
+ mpFormat(pFormat)
+{
+}
+
+ScCondDateFormatObj::~ScCondDateFormatObj()
+{
+}
+
+ScCondDateFormatEntry* ScCondDateFormatObj::getCoreObject()
+{
+ ScConditionalFormat* pFormat = mxParent->getCoreObject();
+ if (isObjectStillAlive(pFormat, mpFormat))
+ return const_cast<ScCondDateFormatEntry*>(mpFormat);
+
+ throw lang::IllegalArgumentException();
+}
+
+sal_Int32 ScCondDateFormatObj::getType()
+{
+ return sheet::ConditionEntryType::DATE;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCondDateFormatObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScCondDateFormatObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ switch(pEntry->nWID)
+ {
+ case Date_StyleName:
+ {
+ OUString aStyleName;
+ if (!(aValue >>= aStyleName))
+ throw lang::IllegalArgumentException();
+
+ getCoreObject()->SetStyleName(aStyleName);
+
+ }
+ break;
+ case DateType:
+ {
+ sal_Int32 nApiType = -1;
+ if (!(aValue >>= nApiType))
+ throw lang::IllegalArgumentException();
+
+ for (DateTypeApiMap const & rEntry : aDateTypeApiMap)
+ {
+ if (rEntry.nApiType == nApiType)
+ {
+ getCoreObject()->SetDateType(rEntry.eType);
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+uno::Any SAL_CALL ScCondDateFormatObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ const SfxItemPropertyMap& rPropertyMap = maPropSet.getPropertyMap(); // from derived class
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aAny;
+
+ switch(pEntry->nWID)
+ {
+ case Date_StyleName:
+ {
+ OUString aStyleName = getCoreObject()->GetStyleName();
+ aAny <<= aStyleName;
+ }
+ break;
+ case DateType:
+ {
+ condformat::ScCondFormatDateType eType = getCoreObject()->GetDateType();
+ for (DateTypeApiMap const & rEntry : aDateTypeApiMap)
+ {
+ if (rEntry.eType == eType)
+ {
+ aAny <<= rEntry.nApiType;
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ SAL_WARN("sc", "unknown property");
+ }
+ return aAny;
+}
+
+void SAL_CALL ScCondDateFormatObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondDateFormatObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener>& /* aListener */)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondDateFormatObj::addVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+void SAL_CALL ScCondDateFormatObj::removeVetoableChangeListener( const OUString&,
+ const uno::Reference<beans::XVetoableChangeListener>&)
+{
+ SAL_WARN("sc", "not implemented");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/confuno.cxx b/sc/source/ui/unoobj/confuno.cxx
new file mode 100644
index 000000000..c71f2f28f
--- /dev/null
+++ b/sc/source/ui/unoobj/confuno.cxx
@@ -0,0 +1,657 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <config_features.h>
+
+#include <confuno.hxx>
+#include <unonames.hxx>
+#include <docsh.hxx>
+#include <miscuno.hxx>
+#include <forbiuno.hxx>
+#include <appoptio.hxx>
+#include <viewopti.hxx>
+#include <docpool.hxx>
+#include <sc.hrc>
+#include <scmod.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/document/LinkUpdateModes.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <formula/grammar.hxx>
+#include <sfx2/printer.hxx>
+#include <svl/itemset.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/stream.hxx>
+
+using namespace com::sun::star;
+
+constexpr OUStringLiteral SCSAVEVERSION = u"SaveVersionOnClose";
+
+static const SfxItemPropertyMapEntry* lcl_GetConfigPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aConfigPropertyMap_Impl[] =
+ {
+ { SC_UNO_SHOWZERO, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWNOTES, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWGRID, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_GRIDCOLOR, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_SHOWPAGEBR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_LINKUPD, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_COLROWHDR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHEETTABS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_OUTLSYMB, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SNAPTORASTER, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_RASTERVIS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_RASTERRESX, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_RASTERRESY, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_RASTERSUBX, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_RASTERSUBY, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_RASTERSYNC, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_AUTOCALC, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_PRINTERNAME, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNO_PRINTERSETUP, 0, cppu::UnoType<uno::Sequence<sal_Int8>>::get(), 0, 0},
+ { SC_UNO_PRINTERPAPER, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_APPLYDOCINF, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_SAVE_THUMBNAIL, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_FORBIDDEN, 0, cppu::UnoType<i18n::XForbiddenCharacters>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_CHARCOMP, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_ASIANKERN, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SCSAVEVERSION, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_UPDTEMPL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ /*Stampit enable/disable print cancel */
+ { SC_UNO_ALLOWPRINTJOBCANCEL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_LOADREADONLY, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHAREDOC, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_MODIFYPASSWORDINFO, 0, cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get(), 0, 0},
+ { SC_UNO_MODIFYPASSWORDHASH, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_EMBED_FONTS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_EMBED_ONLY_USED_FONTS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_EMBED_FONT_SCRIPT_LATIN, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_EMBED_FONT_SCRIPT_ASIAN, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_EMBED_FONT_SCRIPT_COMPLEX, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_IMAGE_PREFERRED_DPI, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_SYNTAXSTRINGREF, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aConfigPropertyMap_Impl;
+}
+
+ScDocumentConfiguration::ScDocumentConfiguration(ScDocShell* pDocSh)
+ : pDocShell(pDocSh) ,
+ aPropSet ( lcl_GetConfigPropertyMap() )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDocumentConfiguration::~ScDocumentConfiguration()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDocumentConfiguration::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDocumentConfiguration::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScDocumentConfiguration::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if(!pDocShell)
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bUpdateHeights = false;
+
+ ScViewOptions aViewOpt(rDoc.GetViewOptions());
+
+ /*Stampit enable/disable print cancel */
+ if ( aPropertyName == SC_UNO_ALLOWPRINTJOBCANCEL )
+ pDocShell->Stamp_SetPrintCancelState( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ /*Stampit enable/disable print cancel */
+
+ else if ( aPropertyName == SC_UNO_SHOWZERO )
+ aViewOpt.SetOption(VOPT_NULLVALS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWNOTES )
+ aViewOpt.SetOption(VOPT_NOTES, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWGRID )
+ aViewOpt.SetOption(VOPT_GRID, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_GRIDCOLOR )
+ {
+ Color aColor;
+ if (aValue >>= aColor)
+ aViewOpt.SetGridColor(aColor, OUString());
+ }
+ else if ( aPropertyName == SC_UNO_SHOWPAGEBR )
+ aViewOpt.SetOption(VOPT_PAGEBREAKS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNONAME_LINKUPD )
+ {
+ // XXX NOTE: this is the css::document::Settings property
+ // LinkUpdateMode, not the css::sheet::XGlobalSheetSettings
+ // attribute LinkUpdateMode.
+ sal_Int16 n;
+ if (!(aValue >>= n) || n < css::document::LinkUpdateModes::NEVER ||
+ n > css::document::LinkUpdateModes::GLOBAL_SETTING)
+ {
+ throw css::lang::IllegalArgumentException(
+ ("LinkUpdateMode property value must be a SHORT with a value in"
+ " the range of the css::document::LinkUpdateModes constants"),
+ css::uno::Reference<css::uno::XInterface>(), -1);
+ }
+ ScLkUpdMode eMode;
+ switch (n)
+ {
+ case css::document::LinkUpdateModes::NEVER:
+ eMode = LM_NEVER;
+ break;
+ case css::document::LinkUpdateModes::MANUAL:
+ eMode = LM_ON_DEMAND;
+ break;
+ case css::document::LinkUpdateModes::AUTO:
+ eMode = LM_ALWAYS;
+ break;
+ case css::document::LinkUpdateModes::GLOBAL_SETTING:
+ default:
+ eMode = SC_MOD()->GetAppOptions().GetLinkMode();
+ break;
+ }
+ rDoc.SetLinkMode( eMode );
+ }
+ else if ( aPropertyName == SC_UNO_COLROWHDR )
+ aViewOpt.SetOption(VOPT_HEADER, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHEETTABS )
+ aViewOpt.SetOption(VOPT_TABCONTROLS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_OUTLSYMB )
+ aViewOpt.SetOption(VOPT_OUTLINER, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_AUTOCALC )
+ rDoc.SetAutoCalc( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_PRINTERNAME )
+ {
+ OUString sPrinterName;
+ if ( !(aValue >>= sPrinterName) )
+ throw lang::IllegalArgumentException();
+
+ // #i75610# if the name is empty, do nothing (don't create any printer)
+ if ( !sPrinterName.isEmpty() && pDocShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
+ {
+ SfxPrinter* pPrinter = pDocShell->GetPrinter();
+ if (!pPrinter)
+ throw uno::RuntimeException();
+
+ if (pPrinter->GetName() != sPrinterName)
+ {
+ VclPtrInstance<SfxPrinter> pNewPrinter( pPrinter->GetOptions().Clone(), sPrinterName );
+ if (pNewPrinter->IsKnown())
+ pDocShell->SetPrinter( pNewPrinter, SfxPrinterChangeFlags::PRINTER );
+ else
+ pNewPrinter.disposeAndClear();
+ }
+
+ }
+
+ }
+ else if ( aPropertyName == SC_UNO_PRINTERSETUP )
+ {
+ uno::Sequence<sal_Int8> aSequence;
+ if ( aValue >>= aSequence )
+ {
+ sal_uInt32 nSize = aSequence.getLength();
+ // #i75610# if the sequence is empty, do nothing (don't create any printer)
+ if ( nSize != 0 )
+ {
+ SvMemoryStream aStream (aSequence.getArray(), nSize, StreamMode::READ );
+ aStream.Seek ( STREAM_SEEK_TO_BEGIN );
+ auto pSet = std::make_unique<SfxItemSetFixed
+ <SID_PRINTER_NOTFOUND_WARN, SID_PRINTER_NOTFOUND_WARN,
+ SID_PRINTER_CHANGESTODOC, SID_PRINTER_CHANGESTODOC,
+ SID_PRINT_SELECTEDSHEET, SID_PRINT_SELECTEDSHEET,
+ SID_SCPRINTOPTIONS, SID_SCPRINTOPTIONS>>( *rDoc.GetPool());
+
+ SfxPrinter* pPrinter = pDocShell->GetPrinter();
+ bool bPreferPrinterPapersize = false;
+ if ( pPrinter )
+ bPreferPrinterPapersize = pPrinter->GetPrinterSettingsPreferred();
+
+ VclPtr<SfxPrinter> pTempPrinter = SfxPrinter::Create( aStream, std::move(pSet) );
+ pTempPrinter->SetPrinterSettingsPreferred( bPreferPrinterPapersize );
+ pDocShell->SetPrinter( pTempPrinter );
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNO_PRINTERPAPER )
+ {
+ bool bPreferPrinterPapersize;
+ if( aValue >>= bPreferPrinterPapersize )
+ {
+ if( pDocShell->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
+ {
+ SfxPrinter *pTempPrinter = pDocShell->GetPrinter( true );
+ if (pTempPrinter)
+ pTempPrinter->SetPrinterSettingsPreferred( bPreferPrinterPapersize );
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNO_APPLYDOCINF )
+ {
+ bool bTmp=true;
+ if ( aValue >>= bTmp )
+ pDocShell->SetUseUserData( bTmp );
+ }
+ else if ( aPropertyName == SC_UNO_SAVE_THUMBNAIL)
+ {
+ bool bTmp = true;
+ if (aValue >>= bTmp)
+ pDocShell->SetUseThumbnailSave( bTmp );
+ }
+ else if ( aPropertyName == SC_UNO_FORBIDDEN )
+ {
+ // read-only - should not be set
+ }
+ else if ( aPropertyName == SC_UNO_CHARCOMP )
+ {
+ // Int16 contains CharacterCompressionType values
+ sal_Int16 nUno = ScUnoHelpFunctions::GetInt16FromAny( aValue );
+ rDoc.SetAsianCompression( static_cast<CharCompressType>(nUno) );
+ bUpdateHeights = true;
+ }
+ else if ( aPropertyName == SC_UNO_ASIANKERN )
+ {
+ rDoc.SetAsianKerning( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ bUpdateHeights = true;
+ }
+ else if ( aPropertyName == SCSAVEVERSION )
+ {
+ bool bTmp=false;
+ if ( aValue >>= bTmp )
+ pDocShell->SetSaveVersionOnClose( bTmp );
+ }
+ else if ( aPropertyName == SC_UNO_UPDTEMPL )
+ {
+ bool bTmp=true;
+ if ( aValue >>= bTmp )
+ pDocShell->SetQueryLoadTemplate( bTmp );
+ }
+ else if ( aPropertyName == SC_UNO_LOADREADONLY )
+ {
+ bool bTmp=false;
+ if ( aValue >>= bTmp )
+ pDocShell->SetLoadReadonly( bTmp );
+ }
+ else if ( aPropertyName == SC_UNO_SHAREDOC )
+ {
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+ bool bDocShared = false;
+ if ( aValue >>= bDocShared )
+ {
+ pDocShell->SetSharedXMLFlag( bDocShared );
+ }
+#endif
+ }
+ else if ( aPropertyName == SC_UNO_MODIFYPASSWORDINFO )
+ {
+ uno::Sequence< beans::PropertyValue > aInfo;
+ if ( !( aValue >>= aInfo ) )
+ throw lang::IllegalArgumentException(
+ "Value of type Sequence<PropertyValue> expected!",
+ uno::Reference< uno::XInterface >(),
+ 2 );
+
+ if ( !pDocShell->SetModifyPasswordInfo( aInfo ) )
+ throw beans::PropertyVetoException(
+ "The hash is not allowed to be changed now!" );
+ }
+ else if (aPropertyName == SC_UNO_MODIFYPASSWORDHASH)
+ {
+ sal_Int32 nHash;
+ if (!(aValue >>= nHash))
+ throw lang::IllegalArgumentException("Value of type sal_Int32 expected!",
+ uno::Reference<uno::XInterface>(), 2);
+
+ if (!pDocShell->SetModifyPasswordHash(nHash))
+ throw beans::PropertyVetoException("The hash is not allowed to be changed now!");
+ }
+ else if (aPropertyName == SC_UNO_EMBED_FONTS)
+ {
+ bool bVal = aValue.has<bool>() && aValue.get<bool>();
+ rDoc.SetEmbedFonts(bVal);
+ }
+ else if (aPropertyName == SC_UNO_EMBED_ONLY_USED_FONTS)
+ {
+ bool bVal = aValue.has<bool>() && aValue.get<bool>();
+ rDoc.SetEmbedUsedFontsOnly(bVal);
+ }
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_LATIN)
+ {
+ bool bVal = aValue.has<bool>() && aValue.get<bool>();
+ rDoc.SetEmbedFontScriptLatin(bVal);
+ }
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_ASIAN)
+ {
+ bool bVal = aValue.has<bool>() && aValue.get<bool>();
+ rDoc.SetEmbedFontScriptAsian(bVal);
+ }
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_COMPLEX)
+ {
+ bool bVal = aValue.has<bool>() && aValue.get<bool>();
+ rDoc.SetEmbedFontScriptComplex(bVal);
+ }
+ else if ( aPropertyName == SC_UNO_SYNTAXSTRINGREF )
+ {
+ ScCalcConfig aCalcConfig = rDoc.GetCalcConfig();
+ sal_Int16 nUno = 0;
+
+ if( aValue >>= nUno )
+ {
+ switch (nUno)
+ {
+ case 0: // CONV_OOO
+ case 2: // CONV_XL_A1
+ case 3: // CONV_XL_R1C1
+ case 7: // CONV_A1_XL_A1
+ aCalcConfig.SetStringRefSyntax( static_cast<formula::FormulaGrammar::AddressConvention>( nUno ) );
+ break;
+ default:
+ aCalcConfig.SetStringRefSyntax( formula::FormulaGrammar::CONV_UNSPECIFIED );
+ break;
+
+ }
+ rDoc.SetCalcConfig( aCalcConfig );
+ }
+ }
+ else if (aPropertyName == SC_UNO_IMAGE_PREFERRED_DPI)
+ {
+ if (aValue.has<sal_Int32>())
+ {
+ rDoc.SetImagePreferredDPI(aValue.get<sal_Int32>());
+ }
+ }
+ else
+ {
+ ScGridOptions aGridOpt(aViewOpt.GetGridOptions());
+ if ( aPropertyName == SC_UNO_SNAPTORASTER )
+ aGridOpt.SetUseGridSnap( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_RASTERVIS )
+ aGridOpt.SetGridVisible( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_RASTERRESX )
+ aGridOpt.SetFieldDrawX( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( aValue ) ) );
+ else if ( aPropertyName == SC_UNO_RASTERRESY )
+ aGridOpt.SetFieldDrawY( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( aValue ) ) );
+ else if ( aPropertyName == SC_UNO_RASTERSUBX )
+ aGridOpt.SetFieldDivisionX( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( aValue ) ) );
+ else if ( aPropertyName == SC_UNO_RASTERSUBY )
+ aGridOpt.SetFieldDivisionY( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( aValue ) ) );
+ else if ( aPropertyName == SC_UNO_RASTERSYNC )
+ aGridOpt.SetSynchronize( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+ aViewOpt.SetGridOptions(aGridOpt);
+ }
+ rDoc.SetViewOptions(aViewOpt);
+
+ if ( bUpdateHeights && !rDoc.IsImportingXML() )
+ {
+ // update automatic row heights and repaint
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ if ( !pDocShell->AdjustRowHeight( 0, rDoc.MaxRow(), nTab ) )
+ pDocShell->PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab), PaintPartFlags::Grid);
+ pDocShell->SetDocumentModified();
+ }
+
+}
+
+uno::Any SAL_CALL ScDocumentConfiguration::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if(!pDocShell)
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScViewOptions& aViewOpt = rDoc.GetViewOptions();
+
+ /*Stampit enable/disable print cancel */
+ if ( aPropertyName == SC_UNO_ALLOWPRINTJOBCANCEL )
+ aRet <<= pDocShell->Stamp_GetPrintCancelState();
+ /*Stampit enable/disable print cancel */
+
+ else if ( aPropertyName == SC_UNO_SHOWZERO )
+ aRet <<= aViewOpt.GetOption( VOPT_NULLVALS );
+ else if ( aPropertyName == SC_UNO_SHOWNOTES )
+ aRet <<= aViewOpt.GetOption( VOPT_NOTES );
+ else if ( aPropertyName == SC_UNO_SHOWGRID )
+ aRet <<= aViewOpt.GetOption( VOPT_GRID );
+ else if ( aPropertyName == SC_UNO_GRIDCOLOR )
+ {
+ OUString aColorName;
+ Color aColor = aViewOpt.GetGridColor(&aColorName);
+ aRet <<= aColor;
+ }
+ else if ( aPropertyName == SC_UNO_SHOWPAGEBR )
+ aRet <<= aViewOpt.GetOption( VOPT_PAGEBREAKS );
+ else if ( aPropertyName == SC_UNONAME_LINKUPD )
+ {
+ sal_Int16 nLUM;
+ switch (rDoc.GetLinkMode())
+ {
+ case LM_ALWAYS:
+ nLUM = css::document::LinkUpdateModes::AUTO;
+ break;
+ case LM_NEVER:
+ nLUM = css::document::LinkUpdateModes::NEVER;
+ break;
+ case LM_ON_DEMAND:
+ nLUM = css::document::LinkUpdateModes::MANUAL;
+ break;
+ case LM_UNKNOWN:
+ default:
+ nLUM = css::document::LinkUpdateModes::GLOBAL_SETTING;
+ break;
+ }
+ aRet <<= nLUM;
+ }
+ else if ( aPropertyName == SC_UNO_COLROWHDR )
+ aRet <<= aViewOpt.GetOption( VOPT_HEADER );
+ else if ( aPropertyName == SC_UNO_SHEETTABS )
+ aRet <<= aViewOpt.GetOption( VOPT_TABCONTROLS );
+ else if ( aPropertyName == SC_UNO_OUTLSYMB )
+ aRet <<= aViewOpt.GetOption( VOPT_OUTLINER );
+ else if ( aPropertyName == SC_UNO_AUTOCALC )
+ aRet <<= rDoc.GetAutoCalc();
+ else if ( aPropertyName == SC_UNO_PRINTERNAME )
+ {
+ // #i75610# don't create the printer, return empty string if no printer created yet
+ // (as in SwXDocumentSettings)
+ SfxPrinter* pPrinter = rDoc.GetPrinter( false );
+ if (pPrinter)
+ aRet <<= pPrinter->GetName();
+ else
+ aRet <<= OUString();
+ }
+ else if ( aPropertyName == SC_UNO_PRINTERSETUP )
+ {
+ // #i75610# don't create the printer, return empty sequence if no printer created yet
+ // (as in SwXDocumentSettings)
+ SfxPrinter* pPrinter = rDoc.GetPrinter( false );
+ if (pPrinter)
+ {
+ SvMemoryStream aStream;
+ pPrinter->Store( aStream );
+ aRet <<= uno::Sequence< sal_Int8 >( static_cast< const sal_Int8* >( aStream.GetData() ),
+ aStream.TellEnd() );
+ }
+ else
+ aRet <<= uno::Sequence<sal_Int8>();
+ }
+ else if ( aPropertyName == SC_UNO_PRINTERPAPER)
+ {
+ SfxPrinter *pTempPrinter = pDocShell->GetPrinter( false );
+ aRet <<= pTempPrinter && pTempPrinter->GetPrinterSettingsPreferred();
+
+ }
+ else if ( aPropertyName == SC_UNO_APPLYDOCINF )
+ aRet <<= pDocShell->IsUseUserData();
+ else if ( aPropertyName == SC_UNO_SAVE_THUMBNAIL )
+ aRet <<= pDocShell->IsUseThumbnailSave();
+ else if ( aPropertyName == SC_UNO_FORBIDDEN )
+ {
+ aRet <<= uno::Reference<i18n::XForbiddenCharacters>(new ScForbiddenCharsObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_CHARCOMP )
+ aRet <<= static_cast<sal_Int16> ( rDoc.GetAsianCompression() );
+ else if ( aPropertyName == SC_UNO_ASIANKERN )
+ aRet <<= rDoc.GetAsianKerning();
+ else if ( aPropertyName == SCSAVEVERSION )
+ aRet <<= pDocShell->IsSaveVersionOnClose();
+ else if ( aPropertyName == SC_UNO_UPDTEMPL )
+ aRet <<= pDocShell->IsQueryLoadTemplate();
+ else if ( aPropertyName == SC_UNO_LOADREADONLY )
+ aRet <<= pDocShell->IsLoadReadonly();
+ else if ( aPropertyName == SC_UNO_SHAREDOC )
+ {
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+ aRet <<= pDocShell->HasSharedXMLFlagSet();
+#endif
+ }
+ else if ( aPropertyName == SC_UNO_MODIFYPASSWORDINFO )
+ aRet <<= pDocShell->GetModifyPasswordInfo();
+ else if (aPropertyName == SC_UNO_MODIFYPASSWORDHASH)
+ aRet <<= pDocShell->GetModifyPasswordHash();
+ else if (aPropertyName == SC_UNO_EMBED_FONTS)
+ aRet <<= rDoc.IsEmbedFonts();
+ else if (aPropertyName == SC_UNO_EMBED_ONLY_USED_FONTS)
+ aRet <<= rDoc.IsEmbedUsedFontsOnly();
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_LATIN)
+ aRet <<= rDoc.IsEmbedFontScriptLatin();
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_ASIAN)
+ aRet <<= rDoc.IsEmbedFontScriptAsian();
+ else if (aPropertyName == SC_UNO_EMBED_FONT_SCRIPT_COMPLEX)
+ aRet <<= rDoc.IsEmbedFontScriptComplex();
+ else if ( aPropertyName == SC_UNO_SYNTAXSTRINGREF )
+ {
+ ScCalcConfig aCalcConfig = rDoc.GetCalcConfig();
+ formula::FormulaGrammar::AddressConvention eConv = aCalcConfig.meStringRefAddressSyntax;
+
+ // don't save "unspecified" string ref syntax ... query formula grammar
+ // and save that instead
+ if( eConv == formula::FormulaGrammar::CONV_UNSPECIFIED)
+ {
+ eConv = rDoc.GetAddressConvention();
+ }
+
+ // write if it has been read|imported or explicitly changed
+ // or if ref syntax isn't what would be native for our file format
+ // i.e. CalcA1 in this case
+ if ( aCalcConfig.mbHasStringRefSyntax ||
+ (eConv != formula::FormulaGrammar::CONV_OOO) )
+ {
+ switch (eConv)
+ {
+ case formula::FormulaGrammar::CONV_OOO:
+ case formula::FormulaGrammar::CONV_XL_A1:
+ case formula::FormulaGrammar::CONV_XL_R1C1:
+ case formula::FormulaGrammar::CONV_A1_XL_A1:
+ aRet <<= static_cast<sal_Int16>( eConv );
+ break;
+
+ case formula::FormulaGrammar::CONV_UNSPECIFIED:
+ case formula::FormulaGrammar::CONV_ODF:
+ case formula::FormulaGrammar::CONV_XL_OOX:
+ case formula::FormulaGrammar::CONV_LOTUS_A1:
+ case formula::FormulaGrammar::CONV_LAST:
+ {
+ aRet <<= sal_Int16(9999);
+ break;
+ }
+ }
+ }
+ }
+ else if (aPropertyName == SC_UNO_IMAGE_PREFERRED_DPI)
+ {
+ aRet <<= rDoc.GetImagePreferredDPI();
+ }
+ else
+ {
+ const ScGridOptions& aGridOpt = aViewOpt.GetGridOptions();
+ if ( aPropertyName == SC_UNO_SNAPTORASTER )
+ aRet <<= aGridOpt.GetUseGridSnap();
+ else if ( aPropertyName == SC_UNO_RASTERVIS )
+ aRet <<= aGridOpt.GetGridVisible();
+ else if ( aPropertyName == SC_UNO_RASTERRESX )
+ aRet <<= static_cast<sal_Int32> ( aGridOpt.GetFieldDrawX() );
+ else if ( aPropertyName == SC_UNO_RASTERRESY )
+ aRet <<= static_cast<sal_Int32> ( aGridOpt.GetFieldDrawY() );
+ else if ( aPropertyName == SC_UNO_RASTERSUBX )
+ aRet <<= static_cast<sal_Int32> ( aGridOpt.GetFieldDivisionX() );
+ else if ( aPropertyName == SC_UNO_RASTERSUBY )
+ aRet <<= static_cast<sal_Int32> ( aGridOpt.GetFieldDivisionY() );
+ else if ( aPropertyName == SC_UNO_RASTERSYNC )
+ aRet <<= aGridOpt.GetSynchronize();
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+ }
+
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDocumentConfiguration )
+
+// XServiceInfo
+OUString SAL_CALL ScDocumentConfiguration::getImplementationName()
+{
+ return "ScDocumentConfiguration";
+}
+
+sal_Bool SAL_CALL ScDocumentConfiguration::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScDocumentConfiguration::getSupportedServiceNames()
+{
+ return {"com.sun.star.comp.SpreadsheetSettings",
+ "com.sun.star.document.Settings"};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/convuno.cxx b/sc/source/ui/unoobj/convuno.cxx
new file mode 100644
index 000000000..d6ce8d9e1
--- /dev/null
+++ b/sc/source/ui/unoobj/convuno.cxx
@@ -0,0 +1,46 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <convuno.hxx>
+
+using namespace com::sun::star;
+
+// everything is static...
+
+LanguageType ScUnoConversion::GetLanguage(const lang::Locale& rLocale)
+{
+ // empty language -> LANGUAGE_SYSTEM
+ if (rLocale.Language.isEmpty())
+ return LANGUAGE_SYSTEM;
+
+ LanguageType eRet = LanguageTag::convertToLanguageType(rLocale, false);
+ if (eRet == LANGUAGE_NONE)
+ eRet = LANGUAGE_SYSTEM; //! or throw an exception?
+
+ return eRet;
+}
+
+void ScUnoConversion::FillLocale(lang::Locale& rLocale, LanguageType eLang)
+{
+ rLocale = LanguageTag::convertToLocale(eLang);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/cursuno.cxx b/sc/source/ui/unoobj/cursuno.cxx
new file mode 100644
index 000000000..800b4be82
--- /dev/null
+++ b/sc/source/ui/unoobj/cursuno.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 <vcl/svapp.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <cursuno.hxx>
+#include <cellsuno.hxx>
+#include <docsh.hxx>
+#include <markdata.hxx>
+#include <miscuno.hxx>
+
+using namespace com::sun::star;
+
+constexpr OUStringLiteral SCSHEETCELLCURSOR_SERVICE = u"com.sun.star.sheet.SheetCellCursor";
+constexpr OUStringLiteral SCCELLCURSOR_SERVICE = u"com.sun.star.table.CellCursor";
+
+ScCellCursorObj::ScCellCursorObj(ScDocShell* pDocSh, const ScRange& rR) :
+ ScCellRangeObj( pDocSh, rR )
+{
+}
+
+ScCellCursorObj::~ScCellCursorObj()
+{
+}
+
+uno::Any SAL_CALL ScCellCursorObj::queryInterface( const uno::Type& rType )
+{
+ SC_QUERYINTERFACE( sheet::XSheetCellCursor )
+ SC_QUERYINTERFACE( sheet::XUsedAreaCursor )
+ SC_QUERYINTERFACE( table::XCellCursor )
+
+ return ScCellRangeObj::queryInterface( rType );
+}
+
+void SAL_CALL ScCellCursorObj::acquire() noexcept
+{
+ ScCellRangeObj::acquire();
+}
+
+void SAL_CALL ScCellCursorObj::release() noexcept
+{
+ ScCellRangeObj::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScCellCursorObj::getTypes()
+{
+ return comphelper::concatSequences(
+ ScCellRangeObj::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XSheetCellCursor>::get(),
+ cppu::UnoType<sheet::XUsedAreaCursor>::get(),
+ cppu::UnoType<table::XCellCursor>::get()
+ } );
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScCellCursorObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XSheetCellCursor
+
+void SAL_CALL ScCellCursorObj::collapseToCurrentRegion()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+
+ aOneRange.PutInOrder();
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ SCCOL nStartCol = aOneRange.aStart.Col();
+ SCROW nStartRow = aOneRange.aStart.Row();
+ SCCOL nEndCol = aOneRange.aEnd.Col();
+ SCROW nEndRow = aOneRange.aEnd.Row();
+ SCTAB nTab = aOneRange.aStart.Tab();
+
+ pDocSh->GetDocument().GetDataArea(
+ nTab, nStartCol, nStartRow, nEndCol, nEndRow, true, false );
+
+ ScRange aNew( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
+ SetNewRange( aNew );
+}
+
+void SAL_CALL ScCellCursorObj::collapseToCurrentArray()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+
+ aOneRange.PutInOrder();
+ ScAddress aCursor(aOneRange.aStart); // use the start address of the range
+
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScRange aMatrix;
+
+ // finding the matrix range is now in GetMatrixFormulaRange in the document
+ if ( rDoc.GetMatrixFormulaRange( aCursor, aMatrix ) )
+ {
+ SetNewRange( aMatrix );
+ }
+ }
+ // that's a Bug, that this assertion comes; the API Reference says, that
+ // if there is no Matrix, the Range is left unchanged; they say nothing
+ // about an exception
+ /*if (!bFound)
+ {
+ OSL_FAIL("no matrix");
+ //! Exception, or what?
+ }*/
+}
+
+void SAL_CALL ScCellCursorObj::collapseToMergedArea()
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ {
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[ 0 ] );
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ rDoc.ExtendOverlapped( aNewRange );
+ rDoc.ExtendMerge( aNewRange ); // after ExtendOverlapped!
+
+ SetNewRange( aNewRange );
+ }
+}
+
+void SAL_CALL ScCellCursorObj::expandToEntireColumns()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[ 0 ] );
+
+ aNewRange.aStart.SetRow( 0 );
+ aNewRange.aEnd.SetRow( GetDocShell()->GetDocument().MaxRow() );
+
+ SetNewRange( aNewRange );
+}
+
+void SAL_CALL ScCellCursorObj::expandToEntireRows()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[ 0 ] );
+
+ aNewRange.aStart.SetCol( 0 );
+ aNewRange.aEnd.SetCol( GetDocShell()->GetDocument().MaxCol() );
+
+ SetNewRange( aNewRange );
+}
+
+void SAL_CALL ScCellCursorObj::collapseToSize( sal_Int32 nColumns, sal_Int32 nRows )
+{
+ SolarMutexGuard aGuard;
+ if ( nColumns <= 0 || nRows <= 0 )
+ {
+ OSL_FAIL("Empty range not allowed");
+ //! and then?
+ }
+ else
+ {
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[ 0 ] );
+
+ aNewRange.PutInOrder(); //! really?
+
+ const auto & rDoc = GetDocShell()->GetDocument();
+ tools::Long nEndX = aNewRange.aStart.Col() + nColumns - 1;
+ tools::Long nEndY = aNewRange.aStart.Row() + nRows - 1;
+ if ( nEndX < 0 ) nEndX = 0;
+ if ( nEndX > rDoc.MaxCol() ) nEndX = rDoc.MaxCol();
+ if ( nEndY < 0 ) nEndY = 0;
+ if ( nEndY > rDoc.MaxRow() ) nEndY = rDoc.MaxRow();
+ //! error/exception or so, if too big/small
+
+ aNewRange.aEnd.SetCol(static_cast<SCCOL>(nEndX));
+ aNewRange.aEnd.SetRow(static_cast<SCROW>(nEndY));
+
+ aNewRange.PutInOrder(); //! really?
+
+ SetNewRange( aNewRange );
+ }
+}
+
+// XUsedAreaCursor
+
+void SAL_CALL ScCellCursorObj::gotoStartOfUsedArea(sal_Bool bExpand)
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[0] );
+ SCTAB nTab = aNewRange.aStart.Tab();
+
+ SCCOL nUsedX = 0; // fetch the beginning
+ SCROW nUsedY = 0;
+ if (!pDocSh->GetDocument().GetDataStart( nTab, nUsedX, nUsedY ))
+ {
+ nUsedX = 0;
+ nUsedY = 0;
+ }
+
+ aNewRange.aStart.SetCol( nUsedX );
+ aNewRange.aStart.SetRow( nUsedY );
+ if (!bExpand)
+ aNewRange.aEnd = aNewRange.aStart;
+ SetNewRange( aNewRange );
+}
+
+void SAL_CALL ScCellCursorObj::gotoEndOfUsedArea( sal_Bool bExpand )
+{
+ SolarMutexGuard aGuard;
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aNewRange( rRanges[ 0 ]);
+ SCTAB nTab = aNewRange.aStart.Tab();
+
+ SCCOL nUsedX = 0; // fetch the end
+ SCROW nUsedY = 0;
+ if (!pDocSh->GetDocument().GetTableArea( nTab, nUsedX, nUsedY, true ))
+ {
+ nUsedX = 0;
+ nUsedY = 0;
+ }
+
+ aNewRange.aEnd.SetCol( nUsedX );
+ aNewRange.aEnd.SetRow( nUsedY );
+ if (!bExpand)
+ aNewRange.aStart = aNewRange.aEnd;
+ SetNewRange( aNewRange );
+}
+
+// XCellCursor
+
+void SAL_CALL ScCellCursorObj::gotoStart()
+{
+ // this is similar to collapseToCurrentRegion
+ //! something like gotoEdge with 4 possible directions is needed
+
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ]);
+
+ aOneRange.PutInOrder();
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ SCCOL nStartCol = aOneRange.aStart.Col();
+ SCROW nStartRow = aOneRange.aStart.Row();
+ SCCOL nEndCol = aOneRange.aEnd.Col();
+ SCROW nEndRow = aOneRange.aEnd.Row();
+ SCTAB nTab = aOneRange.aStart.Tab();
+
+ pDocSh->GetDocument().GetDataArea(
+ nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, false );
+
+ ScRange aNew( nStartCol, nStartRow, nTab );
+ SetNewRange( aNew );
+}
+
+void SAL_CALL ScCellCursorObj::gotoEnd()
+{
+ // this is similar to collapseToCurrentRegion
+ //! something like gotoEdge with 4 possible directions is needed
+
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+
+ aOneRange.PutInOrder();
+ ScDocShell* pDocSh = GetDocShell();
+ if ( !pDocSh )
+ return;
+
+ SCCOL nStartCol = aOneRange.aStart.Col();
+ SCROW nStartRow = aOneRange.aStart.Row();
+ SCCOL nEndCol = aOneRange.aEnd.Col();
+ SCROW nEndRow = aOneRange.aEnd.Row();
+ SCTAB nTab = aOneRange.aStart.Tab();
+
+ pDocSh->GetDocument().GetDataArea(
+ nTab, nStartCol, nStartRow, nEndCol, nEndRow, false, false );
+
+ ScRange aNew( nEndCol, nEndRow, nTab );
+ SetNewRange( aNew );
+}
+
+void SAL_CALL ScCellCursorObj::gotoNext()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+
+ aOneRange.PutInOrder();
+ ScAddress aCursor(aOneRange.aStart); // always use start of block
+
+ ScMarkData aMark(GetDocument()->GetSheetLimits()); // not used with bMarked=FALSE
+ SCCOL nNewX = aCursor.Col();
+ SCROW nNewY = aCursor.Row();
+ SCTAB nTab = aCursor.Tab();
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ pDocSh->GetDocument().GetNextPos( nNewX,nNewY, nTab, 1,0, false,true, aMark );
+ //! otherwise exception or so
+
+ SetNewRange( ScRange( nNewX, nNewY, nTab ) );
+}
+
+void SAL_CALL ScCellCursorObj::gotoPrevious()
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+
+ aOneRange.PutInOrder();
+ ScAddress aCursor(aOneRange.aStart); // always use start of block
+
+ ScMarkData aMark(GetDocument()->GetSheetLimits()); // not used with bMarked=FALSE
+ SCCOL nNewX = aCursor.Col();
+ SCROW nNewY = aCursor.Row();
+ SCTAB nTab = aCursor.Tab();
+ ScDocShell* pDocSh = GetDocShell();
+ if ( pDocSh )
+ pDocSh->GetDocument().GetNextPos( nNewX,nNewY, nTab, -1,0, false,true, aMark );
+ //! otherwise exception or so
+
+ SetNewRange( ScRange( nNewX, nNewY, nTab ) );
+}
+
+void SAL_CALL ScCellCursorObj::gotoOffset( sal_Int32 nColumnOffset, sal_Int32 nRowOffset )
+{
+ SolarMutexGuard aGuard;
+ const ScRangeList& rRanges = GetRangeList();
+ OSL_ENSURE( rRanges.size() == 1, "Range? Ranges?" );
+ ScRange aOneRange( rRanges[ 0 ] );
+ aOneRange.PutInOrder();
+
+ const auto & rDoc = GetDocShell()->GetDocument();
+ if ( aOneRange.aStart.Col() + nColumnOffset >= 0 &&
+ aOneRange.aEnd.Col() + nColumnOffset <= rDoc.MaxCol() &&
+ aOneRange.aStart.Row() + nRowOffset >= 0 &&
+ aOneRange.aEnd.Row() + nRowOffset <= rDoc.MaxRow() )
+ {
+ ScRange aNew( static_cast<SCCOL>(aOneRange.aStart.Col() + nColumnOffset),
+ static_cast<SCROW>(aOneRange.aStart.Row() + nRowOffset),
+ aOneRange.aStart.Tab(),
+ static_cast<SCCOL>(aOneRange.aEnd.Col() + nColumnOffset),
+ static_cast<SCROW>(aOneRange.aEnd.Row() + nRowOffset),
+ aOneRange.aEnd.Tab() );
+ SetNewRange( aNew );
+ }
+}
+
+// XSheetCellRange
+
+uno::Reference<sheet::XSpreadsheet> SAL_CALL ScCellCursorObj::getSpreadsheet()
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getSpreadsheet();
+}
+
+// XCellRange
+
+uno::Reference<table::XCell> SAL_CALL ScCellCursorObj::getCellByPosition(
+ sal_Int32 nColumn, sal_Int32 nRow )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getCellByPosition(nColumn,nRow);
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByPosition(
+ sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getCellRangeByPosition(nLeft,nTop,nRight,nBottom);
+}
+
+uno::Reference<table::XCellRange> SAL_CALL ScCellCursorObj::getCellRangeByName(
+ const OUString& rRange )
+{
+ SolarMutexGuard aGuard;
+ return ScCellRangeObj::getCellRangeByName(rRange);
+}
+
+// XServiceInfo
+
+OUString SAL_CALL ScCellCursorObj::getImplementationName()
+{
+ return "ScCellCursorObj";
+}
+
+sal_Bool SAL_CALL ScCellCursorObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellCursorObj::getSupportedServiceNames()
+{
+ // SheetCellCursor should be first (?)
+ return comphelper::concatSequences<OUString>(
+ { SCSHEETCELLCURSOR_SERVICE, SCCELLCURSOR_SERVICE },
+ ScCellRangeObj::getSupportedServiceNames());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/dapiuno.cxx b/sc/source/ui/unoobj/dapiuno.cxx
new file mode 100644
index 000000000..64111c1c3
--- /dev/null
+++ b/sc/source/ui/unoobj/dapiuno.cxx
@@ -0,0 +1,3356 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <cmath>
+
+#include <o3tl/safeint.hxx>
+#include <svl/hint.hxx>
+#include <vcl/svapp.hxx>
+#include <sal/log.hxx>
+
+#include <dapiuno.hxx>
+#include <datauno.hxx>
+#include <miscuno.hxx>
+#include <convuno.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <rangeutl.hxx>
+#include <dpobject.hxx>
+#include <dpshttab.hxx>
+#include <dpsdbtab.hxx>
+#include <dpsave.hxx>
+#include <dbdocfun.hxx>
+#include <unonames.hxx>
+#include <dpdimsave.hxx>
+#include <hints.hxx>
+#include <dputil.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <generalfunction.hxx>
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/NullPointerException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sheet/XDimensionsSupplier.hpp>
+#include <com/sun/star/sheet/XLevelsSupplier.hpp>
+#include <com/sun/star/sheet/XMembersAccess.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sheet/DataImportMode.hpp>
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+#include <com/sun/star/sheet/DataPilotOutputRangeType.hpp>
+#include <com/sun/star/sheet/DataPilotTablePositionData.hpp>
+#include <com/sun/star/sheet/GeneralFunction2.hpp>
+
+#include <comphelper/extract.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+using namespace com::sun::star;
+using namespace com::sun::star::sheet;
+
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Exception;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::RuntimeException;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+
+using ::com::sun::star::container::ElementExistException;
+using ::com::sun::star::container::NoSuchElementException;
+using ::com::sun::star::container::XEnumeration;
+using ::com::sun::star::container::XIndexAccess;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::container::XNamed;
+
+using ::com::sun::star::beans::UnknownPropertyException;
+using ::com::sun::star::beans::XPropertyChangeListener;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::beans::XPropertySetInfo;
+using ::com::sun::star::beans::XVetoableChangeListener;
+
+using ::com::sun::star::lang::IllegalArgumentException;
+using ::com::sun::star::lang::IndexOutOfBoundsException;
+using ::com::sun::star::lang::NullPointerException;
+
+using ::com::sun::star::table::CellAddress;
+using ::com::sun::star::table::CellRangeAddress;
+
+namespace {
+
+const SfxItemPropertyMapEntry* lcl_GetDataPilotDescriptorBaseMap()
+{
+ static const SfxItemPropertyMapEntry aDataPilotDescriptorBaseMap_Impl[] =
+ {
+ { SC_UNO_DP_COLGRAND, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_DRILLDOWN, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_GRANDTOTAL_NAME,0,cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0 },
+ { SC_UNO_DP_IGNORE_EMPTYROWS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_IMPORTDESC, 0, cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get(), 0, 0 },
+ { SC_UNO_DP_REPEATEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_ROWGRAND, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_SERVICEARG, 0, cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get(), 0, 0 },
+ { SC_UNO_DP_SHOWFILTER, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_DP_SOURCESERVICE, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aDataPilotDescriptorBaseMap_Impl;
+}
+
+const SfxItemPropertyMapEntry* lcl_GetDataPilotFieldMap()
+{
+ using namespace ::com::sun::star::beans::PropertyAttribute;
+ static const SfxItemPropertyMapEntry aDataPilotFieldMap_Impl[] =
+ {
+ { SC_UNONAME_AUTOSHOW, 0, cppu::UnoType<DataPilotFieldAutoShowInfo>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_FUNCTION, 0, cppu::UnoType<GeneralFunction>::get(), 0, 0 },
+ { SC_UNONAME_FUNCTION2, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_GROUPINFO, 0, cppu::UnoType<DataPilotFieldGroupInfo>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_HASAUTOSHOW, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_HASLAYOUTINFO,0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_HASREFERENCE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_HASSORTINFO, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_ISGROUP, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_LAYOUTINFO, 0, cppu::UnoType<DataPilotFieldLayoutInfo>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_ORIENT, 0, cppu::UnoType<DataPilotFieldOrientation>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_REFERENCE, 0, cppu::UnoType<DataPilotFieldReference>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_SELPAGE, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_SHOWEMPTY, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_REPEATITEMLABELS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_SORTINFO, 0, cppu::UnoType<DataPilotFieldSortInfo>::get(), MAYBEVOID, 0 },
+ { SC_UNONAME_SUBTOTALS, 0, cppu::UnoType<Sequence<GeneralFunction>>::get(), 0, 0 },
+ { SC_UNONAME_SUBTOTALS2, 0, cppu::UnoType<Sequence<sal_Int16>>::get(), 0, 0 },
+ { SC_UNONAME_USESELPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aDataPilotFieldMap_Impl;
+}
+
+const SfxItemPropertyMapEntry* lcl_GetDataPilotItemMap()
+{
+ static const SfxItemPropertyMapEntry aDataPilotItemMap_Impl[] =
+ {
+ { SC_UNONAME_ISHIDDEN, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_POS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_SHOWDETAIL, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aDataPilotItemMap_Impl;
+}
+
+bool lclCheckValidDouble( double fValue, bool bAuto )
+{
+ return bAuto || std::isfinite( fValue );
+}
+
+bool lclCheckMinMaxStep( const DataPilotFieldGroupInfo& rInfo )
+{
+ return
+ lclCheckValidDouble( rInfo.Start, rInfo.HasAutoStart ) &&
+ lclCheckValidDouble( rInfo.End, rInfo.HasAutoEnd ) &&
+ (rInfo.HasAutoStart || rInfo.HasAutoEnd || (rInfo.Start <= rInfo.End)) &&
+ lclCheckValidDouble( rInfo.Step, false ) &&
+ (0.0 <= rInfo.Step);
+}
+
+} // namespace
+
+SC_SIMPLE_SERVICE_INFO( ScDataPilotDescriptor, "ScDataPilotDescriptor", "stardiv::one::sheet::DataPilotDescriptor" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldObj, "ScDataPilotFieldObj", "com.sun.star.sheet.DataPilotField" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldsObj, "ScDataPilotFieldsObj", "com.sun.star.sheet.DataPilotFields" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotTableObj, "ScDataPilotTableObj", "com.sun.star.sheet.DataPilotTable" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotTablesObj, "ScDataPilotTablesObj", "com.sun.star.sheet.DataPilotTables" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotItemsObj, "ScDataPilotItemsObj", "com.sun.star.sheet.DataPilotItems" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotItemObj, "ScDataPilotItemObj", "com.sun.star.sheet.DataPilotItem" )
+
+SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupsObj, "ScDataPilotFieldGroupsObj", "com.sun.star.sheet.DataPilotFieldGroups" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupObj, "ScDataPilotFieldGroupObj", "com.sun.star.sheet.DataPilotFieldGroup" )
+SC_SIMPLE_SERVICE_INFO( ScDataPilotFieldGroupItemObj, "ScDataPilotFieldGroupItemObj", "com.sun.star.sheet.DataPilotFieldGroupItem" )
+
+// name that is used in the API for the data layout field
+constexpr OUStringLiteral SC_DATALAYOUT_NAME = u"Data";
+
+ScGeneralFunction ScDataPilotConversion::FirstFunc( PivotFunc nBits )
+{
+ if ( nBits & PivotFunc::Sum ) return ScGeneralFunction::SUM;
+ if ( nBits & PivotFunc::Count ) return ScGeneralFunction::COUNT;
+ if ( nBits & PivotFunc::Average ) return ScGeneralFunction::AVERAGE;
+ if ( nBits & PivotFunc::Median ) return ScGeneralFunction::MEDIAN;
+ if ( nBits & PivotFunc::Max ) return ScGeneralFunction::MAX;
+ if ( nBits & PivotFunc::Min ) return ScGeneralFunction::MIN;
+ if ( nBits & PivotFunc::Product ) return ScGeneralFunction::PRODUCT;
+ if ( nBits & PivotFunc::CountNum ) return ScGeneralFunction::COUNTNUMS;
+ if ( nBits & PivotFunc::StdDev ) return ScGeneralFunction::STDEV;
+ if ( nBits & PivotFunc::StdDevP ) return ScGeneralFunction::STDEVP;
+ if ( nBits & PivotFunc::StdVar ) return ScGeneralFunction::VAR;
+ if ( nBits & PivotFunc::StdVarP ) return ScGeneralFunction::VARP;
+ if ( nBits & PivotFunc::Auto ) return ScGeneralFunction::AUTO;
+ return ScGeneralFunction::NONE;
+}
+
+PivotFunc ScDataPilotConversion::FunctionBit( sal_Int16 eFunc )
+{
+ PivotFunc nRet = PivotFunc::NONE; // 0
+ switch (eFunc)
+ {
+ case GeneralFunction2::SUM: nRet = PivotFunc::Sum; break;
+ case GeneralFunction2::COUNT: nRet = PivotFunc::Count; break;
+ case GeneralFunction2::AVERAGE: nRet = PivotFunc::Average; break;
+ case GeneralFunction2::MEDIAN: nRet = PivotFunc::Median; break;
+ case GeneralFunction2::MAX: nRet = PivotFunc::Max; break;
+ case GeneralFunction2::MIN: nRet = PivotFunc::Min; break;
+ case GeneralFunction2::PRODUCT: nRet = PivotFunc::Product; break;
+ case GeneralFunction2::COUNTNUMS: nRet = PivotFunc::CountNum; break;
+ case GeneralFunction2::STDEV: nRet = PivotFunc::StdDev; break;
+ case GeneralFunction2::STDEVP: nRet = PivotFunc::StdDevP; break;
+ case GeneralFunction2::VAR: nRet = PivotFunc::StdVar; break;
+ case GeneralFunction2::VARP: nRet = PivotFunc::StdVarP; break;
+ case GeneralFunction2::AUTO: nRet = PivotFunc::Auto; break;
+ default:
+ {
+ assert(false);
+ }
+ }
+ return nRet;
+}
+
+void ScDataPilotConversion::FillGroupInfo( DataPilotFieldGroupInfo& rInfo, const ScDPNumGroupInfo& rGroupInfo )
+{
+ rInfo.HasDateValues = rGroupInfo.mbDateValues;
+ rInfo.HasAutoStart = rGroupInfo.mbAutoStart;
+ rInfo.Start = rGroupInfo.mfStart;
+ rInfo.HasAutoEnd = rGroupInfo.mbAutoEnd;
+ rInfo.End = rGroupInfo.mfEnd;
+ rInfo.Step = rGroupInfo.mfStep;
+}
+
+static ScDPObject* lcl_GetDPObject( ScDocShell* pDocShell, SCTAB nTab, std::u16string_view rName )
+{
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ {
+ size_t nCount = pColl->GetCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab &&
+ rDPObj.GetName() == rName )
+ return &rDPObj;
+ }
+ }
+ }
+ return nullptr; // not found
+}
+
+static OUString lcl_CreatePivotName( ScDocShell* pDocShell )
+{
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ return pColl->CreateNewName();
+ }
+ return OUString(); // shouldn't happen
+}
+
+static sal_Int32 lcl_GetObjectIndex( ScDPObject* pDPObj, const ScFieldIdentifier& rFieldId )
+{
+ // used for items - nRepeat in identifier can be ignored
+ if ( pDPObj )
+ {
+ sal_Int32 nCount = pDPObj->GetDimCount();
+ for ( sal_Int32 nDim = 0; nDim < nCount; ++nDim )
+ {
+ bool bIsDataLayout = false;
+ OUString aDimName( pDPObj->GetDimName( nDim, bIsDataLayout ) );
+ if ( rFieldId.mbDataLayout ? bIsDataLayout : (aDimName == rFieldId.maFieldName) )
+ return nDim;
+ }
+ }
+ return -1; // none
+}
+
+ScDataPilotTablesObj::ScDataPilotTablesObj(ScDocShell& rDocSh, SCTAB nT) :
+ pDocShell( &rDocSh ),
+ nTab( nT )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDataPilotTablesObj::~ScDataPilotTablesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDataPilotTablesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! update of references
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XDataPilotTables
+
+rtl::Reference<ScDataPilotTableObj> ScDataPilotTablesObj::GetObjectByIndex_Impl( sal_Int32 nIndex )
+{
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ {
+ // count tables on this sheet
+ sal_Int32 nFound = 0;
+ size_t nCount = pColl->GetCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
+ {
+ if ( nFound == nIndex )
+ {
+ return new ScDataPilotTableObj(*pDocShell, nTab, rDPObj.GetName());
+ }
+ ++nFound;
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+rtl::Reference<ScDataPilotTableObj> ScDataPilotTablesObj::GetObjectByName_Impl(const OUString& rName)
+{
+ if (hasByName(rName))
+ return new ScDataPilotTableObj(*pDocShell, nTab, rName);
+ return nullptr;
+}
+
+Reference<XDataPilotDescriptor> SAL_CALL ScDataPilotTablesObj::createDataPilotDescriptor()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScDataPilotDescriptor(*pDocShell);
+ return nullptr;
+}
+
+static bool lcl_IsDuplicated(const Reference<XPropertySet>& rDimProps)
+{
+ try
+ {
+ Any aAny = rDimProps->getPropertyValue( SC_UNO_DP_ORIGINAL );
+ Reference< XNamed > xOriginal( aAny, UNO_QUERY );
+ return xOriginal.is();
+ }
+ catch( Exception& )
+ {
+ }
+ return false;
+}
+
+static OUString lcl_GetOriginalName(const Reference< XNamed >& rDim)
+{
+ Reference< XNamed > xOriginal;
+
+ Reference< XPropertySet > xDimProps(rDim, UNO_QUERY);
+ if ( xDimProps.is() )
+ {
+ try
+ {
+ Any aAny = xDimProps->getPropertyValue(SC_UNO_DP_ORIGINAL);
+ aAny >>= xOriginal;
+ }
+ catch( Exception& )
+ {
+ }
+ }
+
+ if ( !xOriginal.is() )
+ xOriginal = rDim;
+
+ return xOriginal->getName();
+}
+
+void SAL_CALL ScDataPilotTablesObj::insertNewByName( const OUString& aNewName,
+ const CellAddress& aOutputAddress,
+ const Reference<XDataPilotDescriptor>& xDescriptor )
+{
+ SolarMutexGuard aGuard;
+ if (!xDescriptor.is()) return;
+
+ if ( !aNewName.isEmpty() && hasByName( aNewName ) )
+ throw IllegalArgumentException("Name \"" + aNewName + "\" already exists", static_cast<cppu::OWeakObject*>(this), 0);
+
+ if (!pDocShell)
+ throw RuntimeException("DocShell is null", static_cast<cppu::OWeakObject*>(this));
+
+ auto pImp = comphelper::getFromUnoTunnel<ScDataPilotDescriptorBase>( xDescriptor );
+ if (!pImp)
+ throw RuntimeException("Failed to get ScDataPilotDescriptor", static_cast<cppu::OWeakObject*>(this));
+
+ ScDPObject* pNewObj = pImp->GetDPObject();
+ if (!pNewObj)
+ throw RuntimeException("Failed to get DPObject", static_cast<cppu::OWeakObject*>(this));
+
+ ScRange aOutputRange(static_cast<SCCOL>(aOutputAddress.Column), static_cast<SCROW>(aOutputAddress.Row), static_cast<SCTAB>(aOutputAddress.Sheet),
+ static_cast<SCCOL>(aOutputAddress.Column), static_cast<SCROW>(aOutputAddress.Row), static_cast<SCTAB>(aOutputAddress.Sheet));
+ pNewObj->SetOutRange(aOutputRange);
+ OUString aName = aNewName;
+ if (aName.isEmpty())
+ aName = lcl_CreatePivotName( pDocShell );
+ pNewObj->SetName(aName);
+ OUString aTag = xDescriptor->getTag();
+ pNewObj->SetTag(aTag);
+
+ // todo: handle double fields (for more information see ScDPObject)
+
+ ScDBDocFunc aFunc(*pDocShell);
+ if (!aFunc.CreatePivotTable(*pNewObj, true, true))
+ throw RuntimeException("Failed to create pivot table", static_cast<cppu::OWeakObject*>(this));
+}
+
+void SAL_CALL ScDataPilotTablesObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject( pDocShell, nTab, aName );
+ if (!pDPObj || !pDocShell)
+ throw RuntimeException(); // no other exceptions specified
+
+ ScDBDocFunc aFunc(*pDocShell);
+ aFunc.RemovePivotTable(*pDPObj, true, true); // remove - incl. undo etc.
+
+}
+
+// XEnumerationAccess
+
+Reference< XEnumeration > SAL_CALL ScDataPilotTablesObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.DataPilotTablesEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDataPilotTablesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ {
+ // count tables on this sheet
+
+ sal_uInt16 nFound = 0;
+ size_t nCount = pColl->GetCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
+ ++nFound;
+ }
+ return nFound;
+ }
+ }
+
+ return 0;
+}
+
+Any SAL_CALL ScDataPilotTablesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ Reference<XDataPilotTable2> xTable(GetObjectByIndex_Impl(nIndex));
+ if (!xTable.is())
+ throw IndexOutOfBoundsException();
+ return Any( xTable );
+}
+
+uno::Type SAL_CALL ScDataPilotTablesObj::getElementType()
+{
+ return cppu::UnoType<XDataPilotTable2>::get();
+}
+
+sal_Bool SAL_CALL ScDataPilotTablesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XNameAccess
+
+Any SAL_CALL ScDataPilotTablesObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ Reference<XDataPilotTable2> xTable(GetObjectByName_Impl(aName));
+ if (!xTable.is())
+ throw NoSuchElementException();
+ return Any( xTable );
+}
+
+Sequence<OUString> SAL_CALL ScDataPilotTablesObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ {
+ // count tables on this sheet
+
+ sal_uInt16 nFound = 0;
+ size_t nCount = pColl->GetCount();
+ size_t i;
+ for (i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
+ ++nFound;
+ }
+
+ sal_uInt16 nPos = 0;
+ Sequence<OUString> aSeq(nFound);
+ OUString* pAry = aSeq.getArray();
+ for (i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab )
+ pAry[nPos++] = rDPObj.GetName();
+ }
+
+ return aSeq;
+ }
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScDataPilotTablesObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDPCollection* pColl = rDoc.GetDPCollection();
+ if ( pColl )
+ {
+ size_t nCount = pColl->GetCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ ScDPObject& rDPObj = (*pColl)[i];
+ if ( rDPObj.GetOutRange().aStart.Tab() == nTab &&
+ rDPObj.GetName() == aName )
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+ScDataPilotDescriptorBase::ScDataPilotDescriptorBase(ScDocShell& rDocSh) :
+ maPropSet( lcl_GetDataPilotDescriptorBaseMap() ),
+ pDocShell( &rDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDataPilotDescriptorBase::~ScDataPilotDescriptorBase()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDataPilotDescriptorBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! update of references ?
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XDataPilotDescriptor
+
+CellRangeAddress SAL_CALL ScDataPilotDescriptorBase::getSourceRange()
+{
+ SolarMutexGuard aGuard;
+
+ ScDPObject* pDPObject(GetDPObject());
+ if (!pDPObject)
+ throw RuntimeException("Failed to get DPObject", static_cast<cppu::OWeakObject*>(this));
+
+ CellRangeAddress aRet;
+ if (pDPObject->IsSheetData())
+ ScUnoConversion::FillApiRange( aRet, pDPObject->GetSheetDesc()->GetSourceRange() );
+ return aRet;
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::setSourceRange( const CellRangeAddress& aSourceRange )
+{
+ SolarMutexGuard aGuard;
+
+ ScDPObject* pDPObject = GetDPObject();
+ if (!pDPObject)
+ throw RuntimeException("Failed to get DPObject", static_cast<cppu::OWeakObject*>(this));
+
+ ScSheetSourceDesc aSheetDesc(&pDocShell->GetDocument());
+ if (pDPObject->IsSheetData())
+ aSheetDesc = *pDPObject->GetSheetDesc();
+
+ ScRange aRange;
+ ScUnoConversion::FillScRange(aRange, aSourceRange);
+ aSheetDesc.SetSourceRange(aRange);
+ pDPObject->SetSheetDesc( aSheetDesc );
+ SetDPObject( pDPObject );
+}
+
+Reference<XSheetFilterDescriptor> SAL_CALL ScDataPilotDescriptorBase::getFilterDescriptor()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFilterDescriptor( pDocShell, this );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getDataPilotFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getColumnFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_COLUMN );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getRowFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_ROW );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getPageFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_PAGE );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getDataFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_DATA );
+}
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotDescriptorBase::getHiddenFields()
+{
+ SolarMutexGuard aGuard;
+ return new ScDataPilotFieldsObj( *this, DataPilotFieldOrientation_HIDDEN );
+}
+
+// XPropertySet
+Reference< XPropertySetInfo > SAL_CALL ScDataPilotDescriptorBase::getPropertySetInfo( )
+{
+ SolarMutexGuard aGuard;
+ static Reference<XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObject = GetDPObject();
+ if (!pDPObject)
+ return;
+
+ ScDPSaveData* pOldData = pDPObject->GetSaveData();
+ OSL_ENSURE(pOldData, "Here should be a SaveData");
+ if ( pOldData )
+ {
+ ScDPSaveData aNewData( *pOldData );
+
+ if ( aPropertyName == SC_UNO_DP_COLGRAND )
+ {
+ aNewData.SetColumnGrand(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_IGNORE_EMPTYROWS )
+ {
+ aNewData.SetIgnoreEmptyRows(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_REPEATEMPTY )
+ {
+ aNewData.SetRepeatIfEmpty(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_ROWGRAND )
+ {
+ aNewData.SetRowGrand(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_SHOWFILTER )
+ {
+ aNewData.SetFilterButton(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_DRILLDOWN )
+ {
+ aNewData.SetDrillDown(::cppu::any2bool( aValue ));
+ }
+ else if ( aPropertyName == SC_UNO_DP_GRANDTOTAL_NAME )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aNewData.SetGrandTotalName(aStrVal);
+ }
+ else if ( aPropertyName == SC_UNO_DP_IMPORTDESC )
+ {
+ uno::Sequence<beans::PropertyValue> aArgSeq;
+ if ( aValue >>= aArgSeq )
+ {
+ ScImportSourceDesc aImportDesc(&pDocShell->GetDocument());
+
+ const ScImportSourceDesc* pOldDesc = pDPObject->GetImportSourceDesc();
+ if (pOldDesc)
+ aImportDesc = *pOldDesc;
+
+ ScImportParam aParam;
+ ScImportDescriptor::FillImportParam( aParam, aArgSeq );
+
+ sheet::DataImportMode nNewType = sheet::DataImportMode_NONE;
+ if ( aParam.bImport )
+ {
+ if ( aParam.bSql )
+ nNewType = sheet::DataImportMode_SQL;
+ else if ( aParam.nType == ScDbQuery )
+ nNewType = sheet::DataImportMode_QUERY;
+ else
+ nNewType = sheet::DataImportMode_TABLE;
+ }
+ aImportDesc.nType = nNewType;
+ aImportDesc.aDBName = aParam.aDBName;
+ aImportDesc.aObject = aParam.aStatement;
+ aImportDesc.bNative = aParam.bNative;
+
+ pDPObject->SetImportDesc( aImportDesc );
+ }
+ }
+ else if ( aPropertyName == SC_UNO_DP_SOURCESERVICE )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ {
+ ScDPServiceDesc aServiceDesc("", "", "", "", "");
+
+ const ScDPServiceDesc* pOldDesc = pDPObject->GetDPServiceDesc();
+ if (pOldDesc)
+ aServiceDesc = *pOldDesc;
+
+ aServiceDesc.aServiceName = aStrVal;
+
+ pDPObject->SetServiceData( aServiceDesc );
+ }
+ }
+ else if ( aPropertyName == SC_UNO_DP_SERVICEARG )
+ {
+ uno::Sequence<beans::PropertyValue> aArgSeq;
+ if ( aValue >>= aArgSeq )
+ {
+ ScDPServiceDesc aServiceDesc("", "", "", "", "");
+
+ const ScDPServiceDesc* pOldDesc = pDPObject->GetDPServiceDesc();
+ if (pOldDesc)
+ aServiceDesc = *pOldDesc;
+
+ OUString aStrVal;
+ for (const beans::PropertyValue& rProp : std::as_const(aArgSeq))
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == SC_UNO_DP_SOURCENAME)
+ {
+ if ( rProp.Value >>= aStrVal )
+ aServiceDesc.aParSource = aStrVal;
+ }
+ else if (aPropName == SC_UNO_DP_OBJECTNAME)
+ {
+ if ( rProp.Value >>= aStrVal )
+ aServiceDesc.aParName = aStrVal;
+ }
+ else if (aPropName == SC_UNO_DP_USERNAME)
+ {
+ if ( rProp.Value >>= aStrVal )
+ aServiceDesc.aParUser = aStrVal;
+ }
+ else if (aPropName == SC_UNO_DP_PASSWORD)
+ {
+ if ( rProp.Value >>= aStrVal )
+ aServiceDesc.aParPass = aStrVal;
+ }
+ }
+
+ pDPObject->SetServiceData( aServiceDesc );
+ }
+ }
+ else
+ throw UnknownPropertyException(aPropertyName);
+
+ pDPObject->SetSaveData( aNewData );
+ }
+
+ SetDPObject(pDPObject);
+}
+
+Any SAL_CALL ScDataPilotDescriptorBase::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ Any aRet;
+
+ ScDPObject* pDPObject(GetDPObject());
+ if (pDPObject)
+ {
+ ScDPSaveData* pOldData = pDPObject->GetSaveData();
+ OSL_ENSURE(pOldData, "Here should be a SaveData");
+ if ( pOldData )
+ {
+ ScDPSaveData aNewData( *pOldData );
+
+ if ( aPropertyName == SC_UNO_DP_COLGRAND )
+ {
+ aRet <<= aNewData.GetColumnGrand();
+ }
+ else if ( aPropertyName == SC_UNO_DP_IGNORE_EMPTYROWS )
+ {
+ aRet <<= aNewData.GetIgnoreEmptyRows();
+ }
+ else if ( aPropertyName == SC_UNO_DP_REPEATEMPTY )
+ {
+ aRet <<= aNewData.GetRepeatIfEmpty();
+ }
+ else if ( aPropertyName == SC_UNO_DP_ROWGRAND )
+ {
+ aRet <<= aNewData.GetRowGrand();
+ }
+ else if ( aPropertyName == SC_UNO_DP_SHOWFILTER )
+ {
+ aRet <<= aNewData.GetFilterButton();
+ }
+ else if ( aPropertyName == SC_UNO_DP_DRILLDOWN )
+ {
+ aRet <<= aNewData.GetDrillDown();
+ }
+ else if ( aPropertyName == SC_UNO_DP_GRANDTOTAL_NAME )
+ {
+ const std::optional<OUString> & pGrandTotalName = aNewData.GetGrandTotalName();
+ if (pGrandTotalName)
+ aRet <<= *pGrandTotalName; // same behavior as in ScDPSource
+ }
+ else if ( aPropertyName == SC_UNO_DP_IMPORTDESC )
+ {
+ const ScImportSourceDesc* pImportDesc = pDPObject->GetImportSourceDesc();
+ if ( pImportDesc )
+ {
+ // fill ScImportParam so ScImportDescriptor::FillProperties can be used
+ ScImportParam aParam;
+ aParam.bImport = ( pImportDesc->nType != sheet::DataImportMode_NONE );
+ aParam.aDBName = pImportDesc->aDBName;
+ aParam.aStatement = pImportDesc->aObject;
+ aParam.bNative = pImportDesc->bNative;
+ aParam.bSql = ( pImportDesc->nType == sheet::DataImportMode_SQL );
+ aParam.nType = static_cast<sal_uInt8>(( pImportDesc->nType == sheet::DataImportMode_QUERY ) ? ScDbQuery : ScDbTable);
+
+ uno::Sequence<beans::PropertyValue> aSeq( ScImportDescriptor::GetPropertyCount() );
+ ScImportDescriptor::FillProperties( aSeq, aParam );
+ aRet <<= aSeq;
+ }
+ else
+ {
+ // empty sequence
+ uno::Sequence<beans::PropertyValue> aEmpty(0);
+ aRet <<= aEmpty;
+ }
+ }
+ else if ( aPropertyName == SC_UNO_DP_SOURCESERVICE )
+ {
+ OUString aServiceName;
+ const ScDPServiceDesc* pServiceDesc = pDPObject->GetDPServiceDesc();
+ if (pServiceDesc)
+ aServiceName = pServiceDesc->aServiceName;
+ aRet <<= aServiceName; // empty string if no ServiceDesc set
+ }
+ else if ( aPropertyName == SC_UNO_DP_SERVICEARG )
+ {
+ const ScDPServiceDesc* pServiceDesc = pDPObject->GetDPServiceDesc();
+ if (pServiceDesc)
+ {
+ uno::Sequence<beans::PropertyValue> aSeq( comphelper::InitPropertySequence({
+ { SC_UNO_DP_SOURCENAME, Any(pServiceDesc->aParSource) },
+ { SC_UNO_DP_OBJECTNAME, Any(pServiceDesc->aParName) },
+ { SC_UNO_DP_USERNAME, Any(pServiceDesc->aParUser) },
+ { SC_UNO_DP_PASSWORD, Any(pServiceDesc->aParPass) }
+ }));
+ aRet <<= aSeq;
+ }
+ else
+ {
+ // empty sequence
+ uno::Sequence<beans::PropertyValue> aEmpty;
+ aRet <<= aEmpty;
+ }
+ }
+ else
+ throw UnknownPropertyException(aPropertyName);
+ }
+ }
+
+ return aRet;
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::addPropertyChangeListener(
+ const OUString& /* aPropertyName */, const Reference<XPropertyChangeListener >& /* xListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::removePropertyChangeListener(
+ const OUString& /* aPropertyName */, const Reference<XPropertyChangeListener >& /* aListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::addVetoableChangeListener(
+ const OUString& /* PropertyName */, const Reference<XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotDescriptorBase::removeVetoableChangeListener(
+ const OUString& /* PropertyName */, const Reference<XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+// XDataPilotDataLayoutFieldSupplier
+
+Reference< XDataPilotField > SAL_CALL ScDataPilotDescriptorBase::getDataLayoutField()
+{
+ SolarMutexGuard aGuard;
+ if( ScDPObject* pDPObject = GetDPObject() )
+ {
+ if( ScDPSaveData* pSaveData = pDPObject->GetSaveData() )
+ {
+ if( pSaveData->GetDataLayoutDimension() )
+ {
+ ScFieldIdentifier aFieldId( SC_DATALAYOUT_NAME, true );
+ return new ScDataPilotFieldObj( *this, aFieldId );
+ }
+ }
+ }
+ return nullptr;
+}
+
+// XUnoTunnel
+
+sal_Int64 SAL_CALL ScDataPilotDescriptorBase::getSomething(
+ const Sequence<sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+const Sequence<sal_Int8>& ScDataPilotDescriptorBase::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theScDataPilotDescriptorBaseUnoTunnelId;
+ return theScDataPilotDescriptorBaseUnoTunnelId.getSeq();
+}
+
+ScDataPilotTableObj::ScDataPilotTableObj(ScDocShell& rDocSh, SCTAB nT, const OUString& rN) :
+ ScDataPilotDescriptorBase( rDocSh ),
+ nTab( nT ),
+ aName( rN ),
+ aModifyListeners( 0 )
+{
+}
+
+ScDataPilotTableObj::~ScDataPilotTableObj()
+{
+}
+
+Any SAL_CALL ScDataPilotTableObj::queryInterface( const uno::Type& rType )
+{
+ // since we manually do resolve the query for XDataPilotTable2
+ // we also need to do the same for XDataPilotTable
+ SC_QUERYINTERFACE( XDataPilotTable )
+ SC_QUERYINTERFACE( XDataPilotTable2 )
+ SC_QUERYINTERFACE( XModifyBroadcaster )
+
+ return ScDataPilotDescriptorBase::queryInterface( rType );
+}
+
+void SAL_CALL ScDataPilotTableObj::acquire() noexcept
+{
+ ScDataPilotDescriptorBase::acquire();
+}
+
+void SAL_CALL ScDataPilotTableObj::release() noexcept
+{
+ ScDataPilotDescriptorBase::release();
+}
+
+Sequence< uno::Type > SAL_CALL ScDataPilotTableObj::getTypes()
+{
+ return comphelper::concatSequences(
+ ScDataPilotDescriptorBase::getTypes(),
+ Sequence< uno::Type >
+ {
+ cppu::UnoType<XDataPilotTable2>::get(),
+ cppu::UnoType<XModifyBroadcaster>::get()
+ } );
+}
+
+Sequence<sal_Int8> SAL_CALL ScDataPilotTableObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+ScDPObject* ScDataPilotTableObj::GetDPObject() const
+{
+ return lcl_GetDPObject(GetDocShell(), nTab, aName);
+}
+
+void ScDataPilotTableObj::SetDPObject( ScDPObject* pDPObject )
+{
+ ScDocShell* pDocSh = GetDocShell();
+ ScDPObject* pDPObj = lcl_GetDPObject(pDocSh, nTab, aName);
+ if ( pDPObj && pDocSh )
+ {
+ ScDBDocFunc aFunc(*pDocSh);
+ aFunc.DataPilotUpdate( pDPObj, pDPObject, true, true );
+ }
+}
+
+// "rest of XDataPilotDescriptor"
+
+OUString SAL_CALL ScDataPilotTableObj::getName()
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ return pDPObj->GetName();
+ return OUString();
+}
+
+void SAL_CALL ScDataPilotTableObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ {
+ //! test for existing names !!!
+
+ pDPObj->SetName( aNewName ); //! Undo - DBDocFunc ???
+ aName = aNewName;
+
+ // DataPilotUpdate would do too much (output table is not changed)
+ GetDocShell()->SetDocumentModified();
+ }
+}
+
+OUString SAL_CALL ScDataPilotTableObj::getTag()
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ return pDPObj->GetTag();
+ return OUString();
+}
+
+void SAL_CALL ScDataPilotTableObj::setTag( const OUString& aNewTag )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ {
+ pDPObj->SetTag( aNewTag ); //! Undo - DBDocFunc ???
+
+ // DataPilotUpdate would do too much (output table is not changed)
+ GetDocShell()->SetDocumentModified();
+ }
+}
+
+// XDataPilotTable
+
+CellRangeAddress SAL_CALL ScDataPilotTableObj::getOutputRange()
+{
+ SolarMutexGuard aGuard;
+ CellRangeAddress aRet;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ {
+ ScRange aRange(pDPObj->GetOutRange());
+ aRet.Sheet = aRange.aStart.Tab();
+ aRet.StartColumn = aRange.aStart.Col();
+ aRet.StartRow = aRange.aStart.Row();
+ aRet.EndColumn = aRange.aEnd.Col();
+ aRet.EndRow = aRange.aEnd.Row();
+ }
+ return aRet;
+}
+
+void SAL_CALL ScDataPilotTableObj::refresh()
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName);
+ if (pDPObj)
+ {
+ ScDBDocFunc aFunc(*GetDocShell());
+ aFunc.RefreshPivotTables(pDPObj, true);
+ }
+}
+
+Sequence< Sequence<Any> > SAL_CALL ScDataPilotTableObj::getDrillDownData(const CellAddress& aAddr)
+{
+ SolarMutexGuard aGuard;
+ Sequence< Sequence<Any> > aTabData;
+ ScAddress aAddr2(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet);
+ ScDPObject* pObj = GetDPObject();
+ if (!pObj)
+ throw RuntimeException("Failed to get DPObject", static_cast<cppu::OWeakObject*>(this));
+
+ pObj->GetDrillDownData(aAddr2, aTabData);
+ return aTabData;
+}
+
+DataPilotTablePositionData SAL_CALL ScDataPilotTableObj::getPositionData(const CellAddress& aAddr)
+{
+ SolarMutexGuard aGuard;
+ DataPilotTablePositionData aPosData;
+ ScAddress aAddr2(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet);
+ ScDPObject* pObj = GetDPObject();
+ if (!pObj)
+ throw RuntimeException("Failed to get DPObject", static_cast<cppu::OWeakObject*>(this));
+
+ pObj->GetPositionData(aAddr2, aPosData);
+ return aPosData;
+}
+
+void SAL_CALL ScDataPilotTableObj::insertDrillDownSheet(const CellAddress& aAddr)
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = GetDPObject();
+ if (!pDPObj)
+ throw RuntimeException("Failed to get DPObject", static_cast<cppu::OWeakObject*>(this));
+ ScTabViewShell* pViewSh = GetDocShell()->GetBestViewShell();
+ if (!pViewSh)
+ throw RuntimeException("Failed to get ViewShell", static_cast<cppu::OWeakObject*>(this));
+
+ Sequence<DataPilotFieldFilter> aFilters;
+ pDPObj->GetDataFieldPositionData(
+ ScAddress(static_cast<SCCOL>(aAddr.Column), static_cast<SCROW>(aAddr.Row), aAddr.Sheet), aFilters);
+ pViewSh->ShowDataPilotSourceData(*pDPObj, aFilters);
+}
+
+CellRangeAddress SAL_CALL ScDataPilotTableObj::getOutputRangeByType( sal_Int32 nType )
+{
+ SolarMutexGuard aGuard;
+ if (nType < 0 || nType > DataPilotOutputRangeType::RESULT)
+ throw IllegalArgumentException("nType must be between 0 and " +
+ OUString::number(DataPilotOutputRangeType::RESULT) + ", got " + OUString::number(nType),
+ static_cast<cppu::OWeakObject*>(this), 0);
+
+ CellRangeAddress aRet;
+ if (ScDPObject* pDPObj = lcl_GetDPObject(GetDocShell(), nTab, aName))
+ ScUnoConversion::FillApiRange( aRet, pDPObj->GetOutputRangeByType( nType ) );
+ return aRet;
+}
+
+void SAL_CALL ScDataPilotTableObj::addModifyListener( const uno::Reference<util::XModifyListener>& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ aModifyListeners.emplace_back( aListener );
+
+ if ( aModifyListeners.size() == 1 )
+ {
+ acquire(); // don't lose this object (one ref for all listeners)
+ }
+}
+
+void SAL_CALL ScDataPilotTableObj::removeModifyListener( const uno::Reference<util::XModifyListener>& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ rtl::Reference<ScDataPilotTableObj> xSelfHold(this); // in case the listeners have the last ref
+
+ sal_uInt16 nCount = aModifyListeners.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ {
+ uno::Reference<util::XModifyListener>& rObj = aModifyListeners[n];
+ if ( rObj == aListener )
+ {
+ aModifyListeners.erase( aModifyListeners.begin() + n );
+
+ if ( aModifyListeners.empty() )
+ {
+ release(); // release the ref for the listeners
+ }
+
+ break;
+ }
+ }
+}
+
+void ScDataPilotTableObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if ( auto pDataPilotHint = dynamic_cast<const ScDataPilotModifiedHint*>(&rHint) )
+ {
+ if (pDataPilotHint->GetName() == aName)
+ Refreshed_Impl();
+ }
+ else if ( auto pRefHint = dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ ScRange aRange( 0, 0, nTab );
+ ScRangeList aRanges( aRange );
+ if ( aRanges.UpdateReference( pRefHint->GetMode(), &GetDocShell()->GetDocument(), pRefHint->GetRange(),
+ pRefHint->GetDx(), pRefHint->GetDy(), pRefHint->GetDz() ) &&
+ aRanges.size() == 1 )
+ {
+ nTab = aRanges.front().aStart.Tab();
+ }
+ }
+
+ ScDataPilotDescriptorBase::Notify( rBC, rHint );
+}
+
+void ScDataPilotTableObj::Refreshed_Impl()
+{
+ lang::EventObject aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+
+ // the EventObject holds a Ref to this object until after the listener calls
+
+ ScDocument& rDoc = GetDocShell()->GetDocument();
+ for (const uno::Reference<util::XModifyListener> & xModifyListener : aModifyListeners)
+ rDoc.AddUnoListenerCall( xModifyListener, aEvent );
+}
+
+ScDataPilotDescriptor::ScDataPilotDescriptor(ScDocShell& rDocSh) :
+ ScDataPilotDescriptorBase( rDocSh ),
+ mpDPObject(new ScDPObject(&rDocSh.GetDocument()))
+{
+ ScDPSaveData aSaveData;
+ // set defaults like in ScPivotParam constructor
+ aSaveData.SetColumnGrand( true );
+ aSaveData.SetRowGrand( true );
+ aSaveData.SetIgnoreEmptyRows( false );
+ aSaveData.SetRepeatIfEmpty( false );
+ mpDPObject->SetSaveData(aSaveData);
+ ScSheetSourceDesc aSheetDesc(&rDocSh.GetDocument());
+ mpDPObject->SetSheetDesc(aSheetDesc);
+}
+
+ScDataPilotDescriptor::~ScDataPilotDescriptor()
+{
+}
+
+ScDPObject* ScDataPilotDescriptor::GetDPObject() const
+{
+ return mpDPObject.get();
+}
+
+void ScDataPilotDescriptor::SetDPObject( ScDPObject* pDPObject )
+{
+ if (mpDPObject.get() != pDPObject)
+ {
+ mpDPObject.reset( pDPObject );
+ OSL_FAIL("replace DPObject should not happen");
+ }
+}
+
+// "rest of XDataPilotDescriptor"
+
+OUString SAL_CALL ScDataPilotDescriptor::getName()
+{
+ SolarMutexGuard aGuard;
+ return mpDPObject->GetName();
+}
+
+void SAL_CALL ScDataPilotDescriptor::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ mpDPObject->SetName( aNewName );
+}
+
+OUString SAL_CALL ScDataPilotDescriptor::getTag()
+{
+ SolarMutexGuard aGuard;
+ return mpDPObject->GetTag();
+}
+
+void SAL_CALL ScDataPilotDescriptor::setTag( const OUString& aNewTag )
+{
+ SolarMutexGuard aGuard;
+ mpDPObject->SetTag( aNewTag );
+}
+
+ScDataPilotChildObjBase::ScDataPilotChildObjBase( ScDataPilotDescriptorBase& rParent ) :
+ mxParent( &rParent )
+{
+}
+
+ScDataPilotChildObjBase::ScDataPilotChildObjBase( ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId ) :
+ mxParent( &rParent ),
+ maFieldId( rFieldId )
+{
+}
+
+ScDataPilotChildObjBase::~ScDataPilotChildObjBase()
+{
+}
+
+ScDPObject* ScDataPilotChildObjBase::GetDPObject() const
+{
+ return mxParent->GetDPObject();
+}
+
+void ScDataPilotChildObjBase::SetDPObject( ScDPObject* pDPObject )
+{
+ mxParent->SetDPObject( pDPObject );
+}
+
+ScDPSaveDimension* ScDataPilotChildObjBase::GetDPDimension( ScDPObject** ppDPObject ) const
+{
+ if( ScDPObject* pDPObj = GetDPObject() )
+ {
+ if( ppDPObject ) *ppDPObject = pDPObj;
+ if( ScDPSaveData* pSaveData = pDPObj->GetSaveData() )
+ {
+ if( maFieldId.mbDataLayout )
+ return pSaveData->GetDataLayoutDimension();
+
+ if( maFieldId.mnFieldIdx == 0 )
+ return pSaveData->GetDimensionByName( maFieldId.maFieldName );
+
+ // find dimension with specified index (search in duplicated dimensions)
+ const ScDPSaveData::DimsType& rDims = pSaveData->GetDimensions();
+
+ sal_Int32 nFoundIdx = 0;
+ for (auto const& it : rDims)
+ {
+ if (it->IsDataLayout())
+ continue;
+
+ OUString aSrcName = ScDPUtil::getSourceDimensionName(it->GetName());
+ if (aSrcName == maFieldId.maFieldName)
+ {
+ if( nFoundIdx == maFieldId.mnFieldIdx )
+ return it.get();
+ ++nFoundIdx;
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+sal_Int32 ScDataPilotChildObjBase::GetMemberCount() const
+{
+ sal_Int32 nRet = 0;
+ Reference<XNameAccess> xMembersNA = GetMembers();
+ if (xMembersNA.is())
+ {
+ Reference< XIndexAccess > xMembersIA( new ScNameToIndexAccess( xMembersNA ) );
+ nRet = xMembersIA->getCount();
+ }
+ return nRet;
+}
+
+Reference< XMembersAccess > ScDataPilotChildObjBase::GetMembers() const
+{
+ Reference< XMembersAccess > xMembersNA;
+ if( ScDPObject* pDPObj = GetDPObject() )
+ pDPObj->GetMembersNA( lcl_GetObjectIndex( pDPObj, maFieldId ), xMembersNA );
+ return xMembersNA;
+}
+
+ScDocShell* ScDataPilotChildObjBase::GetDocShell() const
+{
+ return mxParent->GetDocShell();
+}
+
+ScDataPilotFieldsObj::ScDataPilotFieldsObj( ScDataPilotDescriptorBase& rParent ) :
+ ScDataPilotChildObjBase( rParent )
+{
+}
+
+ScDataPilotFieldsObj::ScDataPilotFieldsObj( ScDataPilotDescriptorBase& rParent, DataPilotFieldOrientation eOrient ) :
+ ScDataPilotChildObjBase( rParent ),
+ maOrient( eOrient )
+{
+}
+
+ScDataPilotFieldsObj::~ScDataPilotFieldsObj()
+{
+}
+
+static sal_Int32 lcl_GetFieldCount( const Reference<XDimensionsSupplier>& rSource, const Any& rOrient )
+{
+ if (!rSource.is())
+ throw NullPointerException();
+
+ sal_Int32 nRet = 0;
+
+ Reference<XNameAccess> xDimsName(rSource->getDimensions());
+ Reference<XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
+ sal_Int32 nIntCount = xIntDims->getCount();
+ for (sal_Int32 i = 0; i < nIntCount; ++i)
+ {
+ Reference<XPropertySet> xDim(xIntDims->getByIndex(i), UNO_QUERY);
+ const bool bMatch = xDim
+ && (rOrient.hasValue()
+ // all fields of the specified orientation, including duplicated
+ ? (xDim->getPropertyValue(SC_UNO_DP_ORIENTATION) == rOrient)
+ // count all non-duplicated fields
+ : !lcl_IsDuplicated(xDim));
+ if (bMatch)
+ ++nRet;
+ }
+
+ return nRet;
+}
+
+static bool lcl_GetFieldDataByIndex( const Reference<XDimensionsSupplier>& rSource,
+ const Any& rOrient, SCSIZE nIndex, ScFieldIdentifier& rFieldId )
+{
+ if (!rSource.is())
+ throw NullPointerException();
+
+ bool bOk = false;
+ SCSIZE nPos = 0;
+ sal_Int32 nDimIndex = 0;
+
+ Reference<XNameAccess> xDimsName(rSource->getDimensions());
+ Reference<XIndexAccess> xIntDims(new ScNameToIndexAccess( xDimsName ));
+ sal_Int32 nIntCount = xIntDims->getCount();
+ Reference<XPropertySet> xDim;
+ for (sal_Int32 i = 0; i < nIntCount; ++i)
+ {
+ xDim.set(xIntDims->getByIndex(i), UNO_QUERY);
+ const bool bMatch = xDim
+ && (rOrient.hasValue()
+ ? (xDim->getPropertyValue(SC_UNO_DP_ORIENTATION) == rOrient)
+ : !lcl_IsDuplicated(xDim));
+ if (bMatch)
+ {
+ if (nPos == nIndex)
+ {
+ bOk = true;
+ nDimIndex = i;
+ break;
+ }
+ else
+ ++nPos;
+ }
+ }
+
+ if ( bOk )
+ {
+ xDim.set( xIntDims->getByIndex(nDimIndex), UNO_QUERY );
+ Reference<XNamed> xDimName( xDim, UNO_QUERY );
+ if ( xDimName.is() )
+ {
+ OUString sOriginalName( lcl_GetOriginalName( xDimName ) );
+ rFieldId.maFieldName = sOriginalName;
+ rFieldId.mbDataLayout = ScUnoHelpFunctions::GetBoolProperty( xDim,
+ SC_UNO_DP_ISDATALAYOUT );
+
+ sal_Int32 nRepeat = 0;
+ if ( rOrient.hasValue() && lcl_IsDuplicated( xDim ) )
+ {
+ // find the repeat count
+ // (this relies on the original dimension always being before the duplicates)
+
+ Reference<XNamed> xPrevName;
+ for (sal_Int32 i = 0; i < nDimIndex; ++i)
+ {
+ xPrevName.set( xIntDims->getByIndex(i), UNO_QUERY );
+ if ( xPrevName.is() && lcl_GetOriginalName( xPrevName ) == sOriginalName )
+ ++nRepeat;
+ }
+ }
+ rFieldId.mnFieldIdx = nRepeat;
+ }
+ else
+ bOk = false;
+ }
+
+ return bOk;
+}
+
+static bool lcl_GetFieldDataByName( ScDPObject* pDPObj, const OUString& rFieldName, ScFieldIdentifier& rFieldId )
+{
+ // "By name" is always the first match.
+ // The name "Data" always refers to the data layout field.
+ rFieldId.maFieldName = rFieldName;
+ rFieldId.mnFieldIdx = 0;
+ rFieldId.mbDataLayout = rFieldName == SC_DATALAYOUT_NAME;
+
+ pDPObj->GetSource(); // IsDimNameInUse doesn't update source data
+
+ // check if the named field exists (not for data layout)
+ return rFieldId.mbDataLayout || pDPObj->IsDimNameInUse( rFieldName );
+}
+
+// XDataPilotFields
+
+rtl::Reference<ScDataPilotFieldObj> ScDataPilotFieldsObj::GetObjectByIndex_Impl( sal_Int32 nIndex ) const
+{
+ if (ScDPObject* pObj = GetDPObject())
+ {
+ ScFieldIdentifier aFieldId;
+ if (lcl_GetFieldDataByIndex( pObj->GetSource(), maOrient, nIndex, aFieldId ))
+ return new ScDataPilotFieldObj( *mxParent, aFieldId, maOrient );
+ }
+ return nullptr;
+}
+
+rtl::Reference<ScDataPilotFieldObj> ScDataPilotFieldsObj::GetObjectByName_Impl(const OUString& aName) const
+{
+ if (ScDPObject* pDPObj = GetDPObject())
+ {
+ ScFieldIdentifier aFieldId;
+ if (lcl_GetFieldDataByName( pDPObj, aName, aFieldId ))
+ return new ScDataPilotFieldObj( *mxParent, aFieldId, maOrient );
+ }
+ return nullptr;
+}
+
+// XEnumerationAccess
+
+Reference<XEnumeration> SAL_CALL ScDataPilotFieldsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.DataPilotFieldsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDataPilotFieldsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = GetDPObject();
+ return pDPObj ? lcl_GetFieldCount( pDPObj->GetSource(), maOrient ) : 0;
+}
+
+Any SAL_CALL ScDataPilotFieldsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ Reference< XPropertySet > xField( GetObjectByIndex_Impl( nIndex ) );
+ if (!xField.is())
+ throw IndexOutOfBoundsException();
+ return Any( xField );
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScDataPilotFieldsObj::getElementType()
+{
+ return cppu::UnoType<XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XNameAccess
+
+Any SAL_CALL ScDataPilotFieldsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ Reference<XPropertySet> xField(GetObjectByName_Impl(aName));
+ if (!xField.is())
+ throw NoSuchElementException();
+ return Any( xField );
+}
+
+Sequence<OUString> SAL_CALL ScDataPilotFieldsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (ScDPObject* pDPObj = GetDPObject())
+ {
+ Sequence< OUString > aSeq( lcl_GetFieldCount( pDPObj->GetSource(), maOrient ) );
+ OUString* pAry = aSeq.getArray();
+
+ const ScDPSaveData::DimsType& rDimensions = pDPObj->GetSaveData()->GetDimensions();
+ for (auto const& it : rDimensions)
+ {
+ if(maOrient.hasValue() && (it->GetOrientation() == maOrient.get< DataPilotFieldOrientation >()))
+ {
+ *pAry = it->GetName();
+ ++pAry;
+ }
+ }
+ return aSeq;
+ }
+ return Sequence<OUString>();
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ return GetObjectByName_Impl(aName) != nullptr;
+}
+
+ScDataPilotFieldObj::ScDataPilotFieldObj(
+ ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId ) :
+ ScDataPilotChildObjBase( rParent, rFieldId ),
+ maPropSet( lcl_GetDataPilotFieldMap() )
+{
+}
+
+ScDataPilotFieldObj::ScDataPilotFieldObj( ScDataPilotDescriptorBase& rParent,
+ const ScFieldIdentifier& rFieldId, const Any& rOrient ) :
+ ScDataPilotChildObjBase( rParent, rFieldId ),
+ maPropSet( lcl_GetDataPilotFieldMap() ),
+ maOrient( rOrient )
+{
+}
+
+ScDataPilotFieldObj::~ScDataPilotFieldObj()
+{
+}
+
+// XNamed
+
+OUString SAL_CALL ScDataPilotFieldObj::getName()
+{
+ SolarMutexGuard aGuard;
+ OUString aName;
+ if( ScDPSaveDimension* pDim = GetDPDimension() )
+ {
+ if( pDim->IsDataLayout() )
+ aName = SC_DATALAYOUT_NAME;
+ else
+ {
+ const std::optional<OUString> & pLayoutName = pDim->GetLayoutName();
+ if (pLayoutName)
+ aName = *pLayoutName;
+ else
+ aName = pDim->GetName();
+ }
+ }
+ return aName;
+}
+
+void SAL_CALL ScDataPilotFieldObj::setName(const OUString& rName)
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if( pDim && !pDim->IsDataLayout() )
+ {
+ pDim->SetLayoutName(rName);
+ SetDPObject( pDPObj );
+ }
+}
+
+// XPropertySet
+
+Reference<XPropertySetInfo> SAL_CALL ScDataPilotFieldObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static Reference<XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScDataPilotFieldObj::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ if ( aPropertyName == SC_UNONAME_FUNCTION )
+ {
+ // #i109350# use GetEnumFromAny because it also allows sal_Int32
+ ScGeneralFunction eFunction = static_cast<ScGeneralFunction>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
+ setFunction( eFunction );
+ }
+ else if ( aPropertyName == SC_UNONAME_FUNCTION2 )
+ {
+ ScGeneralFunction eFunction = static_cast<ScGeneralFunction>(ScUnoHelpFunctions::GetInt16FromAny( aValue ));
+ setFunction( eFunction );
+ }
+ else if ( aPropertyName == SC_UNONAME_SUBTOTALS )
+ {
+ uno::Sequence<sheet::GeneralFunction> aSeq;
+ if( aValue >>= aSeq)
+ {
+ std::vector< ScGeneralFunction > aSubTotals(aSeq.getLength());
+ std::transform(std::cbegin(aSeq), std::cend(aSeq), aSubTotals.begin(),
+ [](const sheet::GeneralFunction& rValue) -> ScGeneralFunction {
+ const int nValAsInt = static_cast<int>(rValue);
+ return static_cast<ScGeneralFunction>(nValAsInt);
+ });
+ setSubtotals( aSubTotals );
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_SUBTOTALS2 )
+ {
+ Sequence< sal_Int16 > aSeq;
+ if( aValue >>= aSeq )
+ {
+ std::vector< ScGeneralFunction > aSubTotals(aSeq.getLength());
+ std::transform(std::cbegin(aSeq), std::cend(aSeq), aSubTotals.begin(),
+ [](sal_Int16 nValue) -> ScGeneralFunction { return static_cast<ScGeneralFunction>(nValue); });
+ setSubtotals( aSubTotals );
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_ORIENT )
+ {
+ //! test for correct enum type?
+ DataPilotFieldOrientation eOrient = static_cast<DataPilotFieldOrientation>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
+ setOrientation( eOrient );
+ }
+ else if ( aPropertyName == SC_UNONAME_SELPAGE )
+ {
+ OUString sCurrentPage;
+ if (aValue >>= sCurrentPage)
+ setCurrentPage(sCurrentPage);
+ }
+ else if ( aPropertyName == SC_UNONAME_USESELPAGE )
+ {
+ setUseCurrentPage(cppu::any2bool(aValue));
+ }
+ else if ( aPropertyName == SC_UNONAME_HASAUTOSHOW )
+ {
+ if (!cppu::any2bool(aValue))
+ setAutoShowInfo(nullptr);
+ }
+ else if ( aPropertyName == SC_UNONAME_AUTOSHOW )
+ {
+ DataPilotFieldAutoShowInfo aInfo;
+ if (aValue >>= aInfo)
+ setAutoShowInfo(&aInfo);
+ }
+ else if ( aPropertyName == SC_UNONAME_HASLAYOUTINFO )
+ {
+ if (!cppu::any2bool(aValue))
+ setLayoutInfo(nullptr);
+ }
+ else if ( aPropertyName == SC_UNONAME_LAYOUTINFO )
+ {
+ DataPilotFieldLayoutInfo aInfo;
+ if (aValue >>= aInfo)
+ setLayoutInfo(&aInfo);
+ }
+ else if ( aPropertyName == SC_UNONAME_HASREFERENCE )
+ {
+ if (!cppu::any2bool(aValue))
+ setReference(nullptr);
+ }
+ else if ( aPropertyName == SC_UNONAME_REFERENCE )
+ {
+ DataPilotFieldReference aRef;
+ if (aValue >>= aRef)
+ setReference(&aRef);
+ }
+ else if ( aPropertyName == SC_UNONAME_HASSORTINFO )
+ {
+ if (!cppu::any2bool(aValue))
+ setSortInfo(nullptr);
+ }
+ else if ( aPropertyName == SC_UNONAME_SORTINFO )
+ {
+ DataPilotFieldSortInfo aInfo;
+ if (aValue >>= aInfo)
+ setSortInfo(&aInfo);
+ }
+ else if ( aPropertyName == SC_UNONAME_ISGROUP )
+ {
+ if (!cppu::any2bool(aValue))
+ setGroupInfo(nullptr);
+ }
+ else if ( aPropertyName == SC_UNONAME_GROUPINFO )
+ {
+ DataPilotFieldGroupInfo aInfo;
+ if (aValue >>= aInfo)
+ setGroupInfo(&aInfo);
+ }
+ else if ( aPropertyName == SC_UNONAME_SHOWEMPTY )
+ {
+ setShowEmpty(cppu::any2bool(aValue));
+ }
+ else if ( aPropertyName == SC_UNONAME_REPEATITEMLABELS )
+ {
+ setRepeatItemLabels(cppu::any2bool(aValue));
+ }
+ else if (aPropertyName == SC_UNONAME_NAME)
+ {
+ OUString sName;
+ if (aValue >>= sName)
+ setName(sName);
+ }
+}
+
+Any SAL_CALL ScDataPilotFieldObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ Any aRet;
+
+ if ( aPropertyName == SC_UNONAME_FUNCTION )
+ {
+ sheet::GeneralFunction eVal;
+ sal_Int16 nFunction = getFunction();
+ if (nFunction == sheet::GeneralFunction2::MEDIAN)
+ {
+ eVal = sheet::GeneralFunction_NONE;
+ }
+ else
+ {
+ eVal = static_cast<sheet::GeneralFunction>(nFunction);
+ }
+ aRet <<= eVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_FUNCTION2 )
+ aRet <<= getFunction();
+ else if ( aPropertyName == SC_UNONAME_SUBTOTALS )
+ {
+ const uno::Sequence<sal_Int16> aSeq = getSubtotals();
+ uno::Sequence<sheet::GeneralFunction> aNewSeq(aSeq.getLength());
+ std::transform(aSeq.begin(), aSeq.end(), aNewSeq.getArray(),
+ [](sal_Int16 nFunc) -> sheet::GeneralFunction {
+ if (nFunc == sheet::GeneralFunction2::MEDIAN)
+ return sheet::GeneralFunction_NONE;
+ return static_cast<sheet::GeneralFunction>(nFunc);
+ });
+ aRet <<= aNewSeq;
+ }
+ else if ( aPropertyName == SC_UNONAME_SUBTOTALS2 )
+ {
+ aRet <<= getSubtotals();
+ }
+ else if ( aPropertyName == SC_UNONAME_ORIENT )
+ aRet <<= getOrientation();
+ else if ( aPropertyName == SC_UNONAME_SELPAGE )
+ aRet <<= OUString();
+ else if ( aPropertyName == SC_UNONAME_USESELPAGE )
+ aRet <<= false;
+ else if ( aPropertyName == SC_UNONAME_HASAUTOSHOW )
+ aRet <<= (getAutoShowInfo() != nullptr);
+ else if ( aPropertyName == SC_UNONAME_AUTOSHOW )
+ {
+ const DataPilotFieldAutoShowInfo* pInfo = getAutoShowInfo();
+ if (pInfo)
+ aRet <<= *pInfo;
+ }
+ else if ( aPropertyName == SC_UNONAME_HASLAYOUTINFO )
+ aRet <<= (getLayoutInfo() != nullptr);
+ else if ( aPropertyName == SC_UNONAME_LAYOUTINFO )
+ {
+ const DataPilotFieldLayoutInfo* pInfo = getLayoutInfo();
+ if (pInfo)
+ aRet <<= *pInfo;
+ }
+ else if ( aPropertyName == SC_UNONAME_HASREFERENCE )
+ aRet <<= (getReference() != nullptr);
+ else if ( aPropertyName == SC_UNONAME_REFERENCE )
+ {
+ const DataPilotFieldReference* pRef = getReference();
+ if (pRef)
+ aRet <<= *pRef;
+ }
+ else if ( aPropertyName == SC_UNONAME_HASSORTINFO )
+ aRet <<= (getSortInfo() != nullptr);
+ else if ( aPropertyName == SC_UNONAME_SORTINFO )
+ {
+ const DataPilotFieldSortInfo* pInfo = getSortInfo();
+ if (pInfo)
+ aRet <<= *pInfo;
+ }
+ else if ( aPropertyName == SC_UNONAME_ISGROUP )
+ aRet <<= hasGroupInfo();
+ else if ( aPropertyName == SC_UNONAME_GROUPINFO )
+ {
+ aRet <<= getGroupInfo();
+ }
+ else if ( aPropertyName == SC_UNONAME_SHOWEMPTY )
+ aRet <<= getShowEmpty();
+ else if ( aPropertyName == SC_UNONAME_REPEATITEMLABELS )
+ aRet <<= getRepeatItemLabels();
+ else if (aPropertyName == SC_UNONAME_NAME)
+ aRet <<= getName();
+
+ return aRet;
+}
+
+// XDatePilotField
+
+Reference<XIndexAccess> SAL_CALL ScDataPilotFieldObj::getItems()
+{
+ SolarMutexGuard aGuard;
+ if (!mxItems.is())
+ mxItems.set( new ScDataPilotItemsObj( *mxParent, maFieldId ) );
+ return mxItems;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDataPilotFieldObj )
+
+DataPilotFieldOrientation ScDataPilotFieldObj::getOrientation() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim ? pDim->GetOrientation() : DataPilotFieldOrientation_HIDDEN;
+}
+
+void ScDataPilotFieldObj::setOrientation(DataPilotFieldOrientation eNew)
+{
+ SolarMutexGuard aGuard;
+ if (maOrient.hasValue() && (eNew == maOrient.get< DataPilotFieldOrientation >()))
+ return;
+
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if(!pDim)
+ return;
+
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+
+ /* If the field was taken from getDataPilotFields(), don't reset the
+ orientation for an existing use, but create a duplicated field
+ instead (for "Data" orientation only). */
+ if ( !maOrient.hasValue() && !maFieldId.mbDataLayout &&
+ (pDim->GetOrientation() != DataPilotFieldOrientation_HIDDEN) &&
+ (eNew == DataPilotFieldOrientation_DATA) )
+ {
+
+ ScDPSaveDimension* pNewDim = nullptr;
+
+ // look for existing duplicate with orientation "hidden"
+
+ sal_Int32 nFound = 0;
+ const ScDPSaveData::DimsType& rDimensions = pSaveData->GetDimensions();
+ for (auto const& it : rDimensions)
+ {
+ if ( !it->IsDataLayout() && (it->GetName() == maFieldId.maFieldName) )
+ {
+ if ( it->GetOrientation() == DataPilotFieldOrientation_HIDDEN )
+ {
+ pNewDim = it.get(); // use this one
+ break;
+ }
+ else
+ ++nFound; // count existing non-hidden occurrences
+ }
+ }
+
+ if ( !pNewDim ) // if none found, create a new duplicated dimension
+ pNewDim = &pSaveData->DuplicateDimension( *pDim );
+
+ maFieldId.mnFieldIdx = nFound; // keep accessing the new one
+ pDim = pNewDim;
+ }
+
+ pDim->SetOrientation(eNew);
+
+ // move changed field behind all other fields (make it the last field in dimension)
+ pSaveData->SetPosition( pDim, pSaveData->GetDimensions().size() );
+
+ SetDPObject( pDPObj );
+
+ maOrient <<= eNew; // modifying the same object's orientation again doesn't create another duplicate
+}
+
+sal_Int16 ScDataPilotFieldObj::getFunction() const
+{
+ SolarMutexGuard aGuard;
+ sal_Int16 eRet = GeneralFunction2::NONE;
+ if( ScDPSaveDimension* pDim = GetDPDimension() )
+ {
+ if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
+ {
+ // for non-data fields, property Function is the subtotals
+ tools::Long nSubCount = pDim->GetSubTotalsCount();
+ if ( nSubCount > 0 )
+ eRet = static_cast<sal_Int16>(pDim->GetSubTotalFunc(0)); // always use the first one
+ // else keep NONE
+ }
+ else
+ eRet = static_cast<sal_Int16>(pDim->GetFunction());
+ }
+ return eRet;
+}
+
+void ScDataPilotFieldObj::setFunction(ScGeneralFunction eNewFunc)
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if(!pDim)
+ return;
+
+ if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
+ {
+ // for non-data fields, property Function is the subtotals
+ std::vector<ScGeneralFunction> nSubTotalFuncs;
+ if ( eNewFunc != ScGeneralFunction::NONE )
+ {
+ nSubTotalFuncs.push_back( eNewFunc );
+ }
+ pDim->SetSubTotals( std::move(nSubTotalFuncs) );
+ }
+ else
+ pDim->SetFunction( eNewFunc );
+ SetDPObject( pDPObj );
+}
+
+Sequence< sal_Int16 > ScDataPilotFieldObj::getSubtotals() const
+{
+ SolarMutexGuard aGuard;
+ Sequence< sal_Int16 > aRet;
+ if( ScDPSaveDimension* pDim = GetDPDimension() )
+ {
+ if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
+ {
+ // for non-data fields, property Functions is the sequence of subtotals
+ sal_Int32 nCount = static_cast< sal_Int32 >( pDim->GetSubTotalsCount() );
+ if ( nCount > 0 )
+ {
+ aRet.realloc( nCount );
+ auto pRet = aRet.getArray();
+ for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
+ pRet[ nIdx ] = static_cast<sal_Int16>(pDim->GetSubTotalFunc( nIdx ));
+ }
+ }
+ }
+ return aRet;
+}
+
+void ScDataPilotFieldObj::setSubtotals( const std::vector< ScGeneralFunction >& rSubtotals )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if(!pDim)
+ return;
+
+ if( pDim->GetOrientation() != DataPilotFieldOrientation_DATA )
+ {
+ sal_Int32 nCount = rSubtotals.size();
+ if( nCount == 1 )
+ {
+ // count 1: all values are allowed (including NONE and AUTO)
+ std::vector<ScGeneralFunction> nTmpFuncs;
+ if( rSubtotals[ 0 ] != ScGeneralFunction::NONE )
+ {
+ nTmpFuncs.push_back( rSubtotals[ 0 ] );
+ }
+ pDim->SetSubTotals( std::move(nTmpFuncs) );
+ }
+ else if( nCount > 1 )
+ {
+ // set multiple functions, ignore NONE and AUTO in this case
+ ::std::vector< ScGeneralFunction > aSubt;
+ for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
+ {
+ ScGeneralFunction eFunc = rSubtotals[ nIdx ];
+ if( (eFunc != ScGeneralFunction::NONE) && (eFunc != ScGeneralFunction::AUTO) )
+ {
+ // do not insert functions twice
+ if( ::std::find( aSubt.begin(), aSubt.end(), eFunc ) == aSubt.end() )
+ aSubt.push_back( eFunc );
+ }
+ }
+ // set values from vector to ScDPSaveDimension
+ pDim->SetSubTotals( std::move(aSubt) );
+ }
+ }
+ SetDPObject( pDPObj );
+}
+
+void ScDataPilotFieldObj::setCurrentPage( const OUString& rPage )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetCurrentPage( &rPage );
+ SetDPObject( pDPObj );
+ }
+}
+
+void ScDataPilotFieldObj::setUseCurrentPage( bool bUse )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if(!pDim)
+ return;
+
+ if( bUse )
+ {
+ /* It is somehow useless to set the property "HasSelectedPage" to
+ true, because it is still needed to set an explicit page name. */
+ const OUString aPage;
+ pDim->SetCurrentPage( &aPage );
+ }
+ else
+ pDim->SetCurrentPage( nullptr );
+ SetDPObject( pDPObj );
+}
+
+const DataPilotFieldAutoShowInfo* ScDataPilotFieldObj::getAutoShowInfo() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim ? pDim->GetAutoShowInfo() : nullptr;
+}
+
+void ScDataPilotFieldObj::setAutoShowInfo( const DataPilotFieldAutoShowInfo* pInfo )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetAutoShowInfo( pInfo );
+ SetDPObject( pDPObj );
+ }
+}
+
+const DataPilotFieldLayoutInfo* ScDataPilotFieldObj::getLayoutInfo() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim ? pDim->GetLayoutInfo() : nullptr;
+}
+
+void ScDataPilotFieldObj::setLayoutInfo( const DataPilotFieldLayoutInfo* pInfo )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetLayoutInfo( pInfo );
+ SetDPObject( pDPObj );
+ }
+}
+
+const DataPilotFieldReference* ScDataPilotFieldObj::getReference() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim ? pDim->GetReferenceValue() : nullptr;
+}
+
+void ScDataPilotFieldObj::setReference( const DataPilotFieldReference* pInfo )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetReferenceValue( pInfo );
+ SetDPObject( pDPObj );
+ }
+}
+
+const DataPilotFieldSortInfo* ScDataPilotFieldObj::getSortInfo() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim ? pDim->GetSortInfo() : nullptr;
+}
+
+void ScDataPilotFieldObj::setSortInfo( const DataPilotFieldSortInfo* pInfo )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetSortInfo( pInfo );
+ SetDPObject( pDPObj );
+ }
+}
+
+bool ScDataPilotFieldObj::getShowEmpty() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim && pDim->GetShowEmpty();
+}
+
+void ScDataPilotFieldObj::setShowEmpty( bool bShow )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetShowEmpty( bShow );
+ SetDPObject( pDPObj );
+ }
+}
+
+bool ScDataPilotFieldObj::getRepeatItemLabels() const
+{
+ SolarMutexGuard aGuard;
+ ScDPSaveDimension* pDim = GetDPDimension();
+ return pDim && pDim->GetRepeatItemLabels();
+}
+
+void ScDataPilotFieldObj::setRepeatItemLabels( bool bShow )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ pDim->SetRepeatItemLabels( bShow );
+ SetDPObject( pDPObj );
+ }
+}
+
+bool ScDataPilotFieldObj::hasGroupInfo() const
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ if( const ScDPDimensionSaveData* pDimData = pDPObj->GetSaveData()->GetExistingDimensionData() )
+ return pDimData->GetNamedGroupDim( pDim->GetName() ) || pDimData->GetNumGroupDim( pDim->GetName() );
+ return false;
+}
+
+DataPilotFieldGroupInfo ScDataPilotFieldObj::getGroupInfo()
+{
+ SolarMutexGuard aGuard;
+ DataPilotFieldGroupInfo aInfo;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ if( const ScDPDimensionSaveData* pDimData = pDPObj->GetSaveData()->GetExistingDimensionData() )
+ {
+ if( const ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDim( pDim->GetName() ) )
+ {
+ // grouped by ...
+ aInfo.GroupBy = pGroupDim->GetDatePart();
+
+ // find source field
+ try
+ {
+ Reference< XNameAccess > xFields( mxParent->getDataPilotFields(), UNO_QUERY_THROW );
+ aInfo.SourceField.set( xFields->getByName( pGroupDim->GetSourceDimName() ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ }
+
+ ScDataPilotConversion::FillGroupInfo( aInfo, pGroupDim->GetDateInfo() );
+ if( pGroupDim->GetDatePart() == 0 )
+ {
+ // fill vector of group and group member information
+ ScFieldGroups aGroups;
+ for( sal_Int32 nIdx = 0, nCount = pGroupDim->GetGroupCount(); nIdx < nCount; ++nIdx )
+ {
+ const ScDPSaveGroupItem& rGroup = pGroupDim->GetGroupByIndex( nIdx );
+ ScFieldGroup aGroup;
+ aGroup.maName = rGroup.GetGroupName();
+ for( sal_Int32 nMemIdx = 0, nMemCount = rGroup.GetElementCount(); nMemIdx < nMemCount; ++nMemIdx )
+ if (const OUString* pMem = rGroup.GetElementByIndex(nMemIdx))
+ aGroup.maMembers.push_back( *pMem );
+ aGroups.push_back( aGroup );
+ }
+ aInfo.Groups = new ScDataPilotFieldGroupsObj( std::move(aGroups) );
+ }
+ }
+ else if( const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( pDim->GetName() ) )
+ {
+ if (pNumGroupDim->GetDatePart())
+ {
+ ScDataPilotConversion::FillGroupInfo( aInfo, pNumGroupDim->GetDateInfo() );
+ aInfo.GroupBy = pNumGroupDim->GetDatePart();
+ }
+ else
+ {
+ ScDataPilotConversion::FillGroupInfo( aInfo, pNumGroupDim->GetInfo() );
+ }
+ }
+ }
+ }
+ return aInfo;
+}
+
+void ScDataPilotFieldObj::setGroupInfo( const DataPilotFieldGroupInfo* pInfo )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ if( /*ScDPSaveDimension* pDim =*/ !GetDPDimension( &pDPObj ) )
+ return;
+
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ if( pInfo && lclCheckMinMaxStep( *pInfo ) )
+ {
+ ScDPNumGroupInfo aInfo;
+ aInfo.mbEnable = true;
+ aInfo.mbDateValues = pInfo->HasDateValues;
+ aInfo.mbAutoStart = pInfo->HasAutoStart;
+ aInfo.mbAutoEnd = pInfo->HasAutoEnd;
+ aInfo.mfStart = pInfo->Start;
+ aInfo.mfEnd = pInfo->End;
+ aInfo.mfStep = pInfo->Step;
+ Reference< XNamed > xNamed( pInfo->SourceField, UNO_QUERY );
+ if( xNamed.is() )
+ {
+ ScDPSaveGroupDimension aGroupDim( xNamed->getName(), getName() );
+ if( pInfo->GroupBy )
+ aGroupDim.SetDateInfo(aInfo, pInfo->GroupBy);
+ else
+ {
+ Reference<XIndexAccess> xIndex(pInfo->Groups, UNO_QUERY);
+ if (xIndex.is())
+ {
+ sal_Int32 nCount(xIndex->getCount());
+ for(sal_Int32 i = 0; i < nCount; i++)
+ {
+ Reference<XNamed> xGroupNamed(xIndex->getByIndex(i), UNO_QUERY);
+ if (xGroupNamed.is())
+ {
+ ScDPSaveGroupItem aItem(xGroupNamed->getName());
+ Reference<XIndexAccess> xGroupIndex(xGroupNamed, UNO_QUERY);
+ if (xGroupIndex.is())
+ {
+ sal_Int32 nItemCount(xGroupIndex->getCount());
+ for (sal_Int32 j = 0; j < nItemCount; ++j)
+ {
+ Reference<XNamed> xItemNamed(xGroupIndex->getByIndex(j), UNO_QUERY);
+ if (xItemNamed.is())
+ aItem.AddElement(xItemNamed->getName());
+ }
+ }
+ aGroupDim.AddGroupItem(aItem);
+ }
+ }
+ }
+ }
+
+ // get dimension savedata or create new if none
+ ScDPDimensionSaveData& rDimSaveData = *pSaveData->GetDimensionData();
+ rDimSaveData.ReplaceGroupDimension( aGroupDim );
+ }
+ else // no source field in group info -> numeric group
+ {
+ ScDPDimensionSaveData* pDimData = pSaveData->GetDimensionData(); // created if not there
+
+ ScDPSaveNumGroupDimension* pExisting = pDimData->GetNumGroupDimAcc( getName() );
+ if ( pExisting )
+ {
+ if (pInfo->GroupBy)
+ pExisting->SetDateInfo(aInfo, pInfo->GroupBy);
+ // modify existing group dimension
+ pExisting->SetGroupInfo( aInfo );
+ }
+ else if (pInfo->GroupBy)
+ {
+ // create new group dimension
+ ScDPSaveNumGroupDimension aNumGroupDim( getName(), aInfo, pInfo->GroupBy );
+ pDimData->AddNumGroupDimension( aNumGroupDim );
+ }
+ else
+ {
+ // create new group dimension
+ ScDPSaveNumGroupDimension aNumGroupDim( getName(), aInfo );
+ pDimData->AddNumGroupDimension( aNumGroupDim );
+ }
+ }
+ }
+ else // null passed as argument
+ {
+ pSaveData->SetDimensionData( nullptr );
+ }
+
+ pDPObj->SetSaveData( *pSaveData );
+ SetDPObject( pDPObj );
+}
+
+// XDataPilotFieldGrouping
+Reference< XDataPilotField > SAL_CALL ScDataPilotFieldObj::createNameGroup( const Sequence< OUString >& rItems )
+{
+ SolarMutexGuard aGuard;
+
+ if( !rItems.hasElements() )
+ throw IllegalArgumentException("rItems is empty", static_cast<cppu::OWeakObject*>(this), 0);
+
+ Reference< XMembersAccess > xMembers = GetMembers();
+ if (!xMembers.is())
+ {
+ SAL_WARN("sc.ui", "Cannot access members of the field object.");
+ throw RuntimeException("Cannot access members of the field object", static_cast<cppu::OWeakObject*>(this));
+ }
+
+ for (const OUString& aEntryName : rItems)
+ {
+ if (!xMembers->hasByName(aEntryName))
+ {
+ SAL_WARN("sc.ui", "There is no member with that name: " + aEntryName + ".");
+ throw IllegalArgumentException("There is no member with name \"" + aEntryName + "\"", static_cast<cppu::OWeakObject*>(this), 0);
+ }
+ }
+
+ Reference< XDataPilotField > xRet;
+ OUString sNewDim;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ const OUString& aDimName = pDim->GetName();
+
+ ScDPSaveData aSaveData = *pDPObj->GetSaveData();
+ ScDPDimensionSaveData* pDimData = aSaveData.GetDimensionData(); // created if not there
+
+ // find original base
+ OUString aBaseDimName( aDimName );
+ const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName );
+ if ( pBaseGroupDim )
+ {
+ // any entry's SourceDimName is the original base
+ aBaseDimName = pBaseGroupDim->GetSourceDimName();
+ }
+
+ // find existing group dimension
+ // (using the selected dim, can be intermediate group dim)
+ ScDPSaveGroupDimension* pGroupDimension = pDimData->GetGroupDimAccForBase( aDimName );
+
+ // remove the selected items from their groups
+ // (empty groups are removed, too)
+ if ( pGroupDimension )
+ {
+ for (const OUString& aEntryName : rItems)
+ {
+ if ( pBaseGroupDim )
+ {
+ // for each selected (intermediate) group, remove all its items
+ // (same logic as for adding, below)
+ const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
+ if ( pBaseGroup )
+ pBaseGroup->RemoveElementsFromGroups( *pGroupDimension ); // remove all elements
+ else
+ pGroupDimension->RemoveFromGroups( aEntryName );
+ }
+ else
+ pGroupDimension->RemoveFromGroups( aEntryName );
+ }
+ }
+
+ std::unique_ptr<ScDPSaveGroupDimension> pNewGroupDim;
+ if ( !pGroupDimension )
+ {
+ // create a new group dimension
+ sNewDim = pDimData->CreateGroupDimName( aBaseDimName, *pDPObj, false, nullptr );
+ pNewGroupDim.reset(new ScDPSaveGroupDimension( aBaseDimName, sNewDim ));
+
+ pGroupDimension = pNewGroupDim.get(); // make changes to the new dim if none existed
+
+ if ( pBaseGroupDim )
+ {
+ // If it's a higher-order group dimension, pre-allocate groups for all
+ // non-selected original groups, so the individual base members aren't
+ // used for automatic groups (this would make the original groups hard
+ // to find).
+ //! Also do this when removing groups?
+ //! Handle this case dynamically with automatic groups?
+
+ tools::Long nGroupCount = pBaseGroupDim->GetGroupCount();
+ for ( tools::Long nGroup = 0; nGroup < nGroupCount; nGroup++ )
+ {
+ const ScDPSaveGroupItem& rBaseGroup = pBaseGroupDim->GetGroupByIndex( nGroup );
+
+ if (comphelper::findValue(rItems, rBaseGroup.GetGroupName()) == -1) //! ignore case?
+ {
+ // add an additional group for each item that is not in the selection
+ ScDPSaveGroupItem aGroup( rBaseGroup.GetGroupName() );
+ aGroup.AddElementsFromGroup( rBaseGroup );
+ pGroupDimension->AddGroupItem( aGroup );
+ }
+ }
+ }
+ }
+ OUString aGroupDimName = pGroupDimension->GetGroupDimName();
+
+ OUString aGroupName = pGroupDimension->CreateGroupName( ScResId(STR_PIVOT_GROUP) );
+ ScDPSaveGroupItem aGroup( aGroupName );
+ for (const OUString& aEntryName : rItems)
+ {
+ if ( pBaseGroupDim )
+ {
+ // for each selected (intermediate) group, add all its items
+ const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
+ if ( pBaseGroup )
+ aGroup.AddElementsFromGroup( *pBaseGroup );
+ else
+ aGroup.AddElement( aEntryName ); // no group found -> automatic group, add the item itself
+ }
+ else
+ aGroup.AddElement( aEntryName ); // no group dimension, add all items directly
+ }
+
+ pGroupDimension->AddGroupItem( aGroup );
+
+ if ( pNewGroupDim )
+ {
+ pDimData->AddGroupDimension( *pNewGroupDim );
+ pNewGroupDim.reset(); // AddGroupDimension copies the object
+ // don't access pGroupDimension after here
+ }
+ pGroupDimension = nullptr;
+
+ // set orientation
+ ScDPSaveDimension* pSaveDimension = aSaveData.GetDimensionByName( aGroupDimName );
+ if ( pSaveDimension->GetOrientation() == DataPilotFieldOrientation_HIDDEN )
+ {
+ ScDPSaveDimension* pOldDimension = aSaveData.GetDimensionByName( aDimName );
+ pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
+ aSaveData.SetPosition( pSaveDimension, 0 ); //! before (immediate) base
+ }
+
+ // apply changes
+ pDPObj->SetSaveData( aSaveData );
+ ScDBDocFunc(*GetDocShell()).RefreshPivotTableGroups(pDPObj);
+ }
+
+ // if new grouping field has been created (on first group), return it
+ if( !sNewDim.isEmpty() )
+ {
+ Reference< XNameAccess > xFields(mxParent->getDataPilotFields(), UNO_QUERY);
+ if (xFields.is())
+ {
+ try
+ {
+ xRet.set(xFields->getByName(sNewDim), UNO_QUERY);
+ SAL_WARN_IF(!xRet.is(), "sc.ui", "there is a name, so there should be also a field");
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ SAL_WARN("sc.ui", "Cannot find field with that name: " + sNewDim + ".");
+ // Avoid throwing exception that's not specified in the method signature.
+ throw css::lang::WrappedTargetRuntimeException(
+ "Cannot find field with name \"" + sNewDim + "\"",
+ static_cast<cppu::OWeakObject*>(this), anyEx );
+ }
+ }
+ }
+ return xRet;
+}
+
+Reference < XDataPilotField > SAL_CALL ScDataPilotFieldObj::createDateGroup( const DataPilotFieldGroupInfo& rInfo )
+{
+ SolarMutexGuard aGuard;
+ using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
+
+ if( !rInfo.HasDateValues )
+ throw IllegalArgumentException("HasDateValues is not set", static_cast<cppu::OWeakObject*>(this), 0);
+ if( !lclCheckMinMaxStep( rInfo ) )
+ throw IllegalArgumentException("min/max/step", static_cast<cppu::OWeakObject*>(this), 0);
+
+ // only a single date flag is allowed
+ if( (rInfo.GroupBy == 0) || (rInfo.GroupBy > YEARS) || ((rInfo.GroupBy & (rInfo.GroupBy - 1)) != 0) )
+ throw IllegalArgumentException("Invalid GroupBy value: " + OUString::number(rInfo.GroupBy), static_cast<cppu::OWeakObject*>(this), 0);
+
+ // step must be zero, if something else than DAYS is specified
+ if( rInfo.Step >= ((rInfo.GroupBy == DAYS) ? 32768.0 : 1.0) )
+ throw IllegalArgumentException("Invalid step value: " + OUString::number(rInfo.Step), static_cast<cppu::OWeakObject*>(this), 0);
+
+ OUString aGroupDimName;
+ ScDPObject* pDPObj = nullptr;
+ if( ScDPSaveDimension* pDim = GetDPDimension( &pDPObj ) )
+ {
+ ScDPNumGroupInfo aInfo;
+ aInfo.mbEnable = true;
+ aInfo.mbDateValues = (rInfo.GroupBy == DAYS) && (rInfo.Step >= 1.0);
+ aInfo.mbAutoStart = rInfo.HasAutoStart;
+ aInfo.mbAutoEnd = rInfo.HasAutoEnd;
+ aInfo.mfStart = rInfo.Start;
+ aInfo.mfEnd = rInfo.End;
+ aInfo.mfStep = std::trunc( rInfo.Step );
+
+ // create a local copy of the entire save data (will be written back below)
+ ScDPSaveData aSaveData = *pDPObj->GetSaveData();
+ // get or create dimension save data
+ ScDPDimensionSaveData& rDimData = *aSaveData.GetDimensionData();
+
+ // find source dimension name
+ const OUString& rDimName = pDim->GetName();
+ const ScDPSaveGroupDimension* pGroupDim = rDimData.GetNamedGroupDim( rDimName );
+ OUString aSrcDimName = pGroupDim ? pGroupDim->GetSourceDimName() : rDimName;
+
+ // find a group dimension for the base field, or get numeric grouping
+ pGroupDim = rDimData.GetFirstNamedGroupDim( aSrcDimName );
+ const ScDPSaveNumGroupDimension* pNumGroupDim = rDimData.GetNumGroupDim( aSrcDimName );
+
+ // do not group by dates, if named groups or numeric grouping is present
+ bool bHasNamedGrouping = pGroupDim && !pGroupDim->GetDateInfo().mbEnable;
+ bool bHasNumGrouping = pNumGroupDim && pNumGroupDim->GetInfo().mbEnable && !pNumGroupDim->GetInfo().mbDateValues && !pNumGroupDim->GetDateInfo().mbEnable;
+ if( bHasNamedGrouping || bHasNumGrouping )
+ throw IllegalArgumentException();
+
+ if( aInfo.mbDateValues ) // create day ranges grouping
+ {
+ // first remove all named group dimensions
+ while( pGroupDim )
+ {
+ OUString aGroupDimName2 = pGroupDim->GetGroupDimName();
+ // find next group dimension before deleting this group
+ pGroupDim = rDimData.GetNextNamedGroupDim( aGroupDimName2 );
+ // remove from dimension save data
+ rDimData.RemoveGroupDimension( aGroupDimName2 );
+ // also remove save data settings for the dimension that no longer exists
+ aSaveData.RemoveDimensionByName( aGroupDimName2 );
+ }
+ // create or replace the number grouping dimension
+ ScDPSaveNumGroupDimension aNumGroupDim( aSrcDimName, aInfo );
+ rDimData.ReplaceNumGroupDimension( aNumGroupDim );
+ }
+ else // create date grouping
+ {
+ // collect all existing date flags
+ sal_Int32 nDateParts = rDimData.CollectDateParts( aSrcDimName );
+ if( nDateParts == 0 )
+ {
+ // insert numeric group dimension, if no date groups exist yet (or replace day range grouping)
+ ScDPSaveNumGroupDimension aNumGroupDim( aSrcDimName, aInfo, rInfo.GroupBy );
+ rDimData.ReplaceNumGroupDimension( aNumGroupDim );
+ }
+ else if( (nDateParts & rInfo.GroupBy) == 0 ) // do nothing if date field exists already
+ {
+ // create new named group dimension for additional date groups
+ aGroupDimName = rDimData.CreateDateGroupDimName( rInfo.GroupBy, *pDPObj, true, nullptr );
+ ScDPSaveGroupDimension aGroupDim( aSrcDimName, aGroupDimName, aInfo, rInfo.GroupBy );
+ rDimData.AddGroupDimension( aGroupDim );
+
+ // set orientation of new named group dimension
+ ScDPSaveDimension& rSaveDim = *aSaveData.GetDimensionByName( aGroupDimName );
+ if( rSaveDim.GetOrientation() == DataPilotFieldOrientation_HIDDEN )
+ {
+ ScDPSaveDimension& rOldDim = *aSaveData.GetDimensionByName( aSrcDimName );
+ rSaveDim.SetOrientation( rOldDim.GetOrientation() );
+ aSaveData.SetPosition( &rSaveDim, 0 ); //! before (immediate) base
+ }
+ }
+ }
+
+ // apply changes
+ pDPObj->SetSaveData( aSaveData );
+ ScDBDocFunc(*GetDocShell()).RefreshPivotTableGroups(pDPObj);
+ }
+
+ // return the UNO object of the new dimension, after writing back saved data
+ Reference< XDataPilotField > xRet;
+ if( !aGroupDimName.isEmpty() )
+ try
+ {
+ Reference< XNameAccess > xFields( mxParent->getDataPilotFields(), UNO_QUERY_THROW );
+ xRet.set( xFields->getByName( aGroupDimName ), UNO_QUERY );
+ }
+ catch( Exception& )
+ {
+ }
+ return xRet;
+}
+
+namespace {
+
+bool lclExtractGroupMembers( ScFieldGroupMembers& rMembers, const Any& rElement )
+{
+ // allow empty value to create a new group
+ if( !rElement.hasValue() )
+ return true;
+
+ // try to extract a simple sequence of strings
+ Sequence< OUString > aSeq;
+ if( rElement >>= aSeq )
+ {
+ if( aSeq.hasElements() )
+ rMembers.insert( rMembers.end(), std::cbegin(aSeq), std::cend(aSeq) );
+ return true;
+ }
+
+ // try to use XIndexAccess providing objects that support XNamed
+ Reference< XIndexAccess > xItemsIA( rElement, UNO_QUERY );
+ if( xItemsIA.is() )
+ {
+ for( sal_Int32 nIdx = 0, nCount = xItemsIA->getCount(); nIdx < nCount; ++nIdx )
+ {
+ try // getByIndex() should not throw, but we cannot be sure
+ {
+ Reference< XNamed > xItemName( xItemsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
+ rMembers.push_back( xItemName->getName() );
+ }
+ catch( Exception& )
+ {
+ // ignore exceptions, go ahead with next element in the array
+ }
+ }
+ return true;
+ }
+
+ // nothing valid inside the Any -> return false
+ return false;
+}
+
+} // namespace
+
+ScDataPilotFieldGroupsObj::ScDataPilotFieldGroupsObj( ScFieldGroups&& rGroups ) :
+ maGroups( std::move(rGroups) )
+{
+}
+
+ScDataPilotFieldGroupsObj::~ScDataPilotFieldGroupsObj()
+{
+}
+
+// XNameAccess
+
+Any SAL_CALL ScDataPilotFieldGroupsObj::getByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ if( implFindByName( rName ) == maGroups.end() )
+ throw NoSuchElementException();
+ return Any( Reference< XNameAccess >( new ScDataPilotFieldGroupObj( *this, rName ) ) );
+}
+
+Sequence< OUString > SAL_CALL ScDataPilotFieldGroupsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ Sequence< OUString > aSeq;
+ if( !maGroups.empty() )
+ {
+ aSeq.realloc( static_cast< sal_Int32 >( maGroups.size() ) );
+ OUString* pName = aSeq.getArray();
+ for( const auto& rGroup : maGroups )
+ {
+ *pName = rGroup.maName;
+ ++pName;
+ }
+ }
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldGroupsObj::hasByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ return implFindByName( rName ) != maGroups.end();
+}
+
+// XNameReplace
+
+void SAL_CALL ScDataPilotFieldGroupsObj::replaceByName( const OUString& rName, const Any& rElement )
+{
+ SolarMutexGuard aGuard;
+
+ if( rName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", static_cast<cppu::OWeakObject*>(this), 0);
+
+ ScFieldGroups::iterator aIt = implFindByName( rName );
+ if( aIt == maGroups.end() )
+ throw NoSuchElementException("Name \"" + rName + "\" not found", static_cast<cppu::OWeakObject*>(this));
+
+ // read all item names provided by the passed object
+ ScFieldGroupMembers aMembers;
+ if( !lclExtractGroupMembers( aMembers, rElement ) )
+ throw IllegalArgumentException("Invalid element object", static_cast<cppu::OWeakObject*>(this), 0);
+
+ // copy and forget, faster than vector assignment
+ aIt->maMembers.swap( aMembers );
+}
+
+// XNameContainer
+
+void SAL_CALL ScDataPilotFieldGroupsObj::insertByName( const OUString& rName, const Any& rElement )
+{
+ SolarMutexGuard aGuard;
+
+ if( rName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", static_cast<cppu::OWeakObject*>(this), 0);
+
+ ScFieldGroups::iterator aIt = implFindByName( rName );
+ if( aIt != maGroups.end() )
+ throw ElementExistException("Name \"" + rName + "\" already exists", static_cast<cppu::OWeakObject*>(this));
+
+ // read all item names provided by the passed object
+ ScFieldGroupMembers aMembers;
+ if( !lclExtractGroupMembers( aMembers, rElement ) )
+ throw IllegalArgumentException("Invalid element object", static_cast<cppu::OWeakObject*>(this), 0);
+
+ // create the new entry if no error has been occurred
+ maGroups.emplace_back();
+ ScFieldGroup& rGroup = maGroups.back();
+ rGroup.maName = rName;
+ rGroup.maMembers.swap( aMembers );
+}
+
+void SAL_CALL ScDataPilotFieldGroupsObj::removeByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+
+ if( rName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", static_cast<cppu::OWeakObject*>(this), 0);
+
+ ScFieldGroups::iterator aIt = implFindByName( rName );
+ if( aIt == maGroups.end() )
+ throw NoSuchElementException("Name \"" + rName + "\" not found", static_cast<cppu::OWeakObject*>(this));
+
+ maGroups.erase( aIt );
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDataPilotFieldGroupsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return static_cast< sal_Int32 >( maGroups.size() );
+}
+
+Any SAL_CALL ScDataPilotFieldGroupsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ if ((nIndex < 0) || (o3tl::make_unsigned(nIndex) >= maGroups.size()))
+ throw IndexOutOfBoundsException();
+ return Any( Reference< XNameAccess >( new ScDataPilotFieldGroupObj( *this, maGroups[ nIndex ].maName ) ) );
+}
+
+// XEnumerationAccess
+
+Reference<XEnumeration> SAL_CALL ScDataPilotFieldGroupsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration( this, "com.sun.star.sheet.DataPilotFieldGroupsEnumeration" );
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScDataPilotFieldGroupsObj::getElementType()
+{
+ return cppu::UnoType<XNameAccess>::get();
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldGroupsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return !maGroups.empty();
+}
+
+// implementation
+
+ScFieldGroup& ScDataPilotFieldGroupsObj::getFieldGroup( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ ScFieldGroups::iterator aIt = implFindByName( rName );
+ if( aIt == maGroups.end() )
+ throw RuntimeException("Field Group with name \"" + rName + "\" not found", static_cast<cppu::OWeakObject*>(this));
+ return *aIt;
+}
+
+void ScDataPilotFieldGroupsObj::renameFieldGroup( const OUString& rOldName, const OUString& rNewName )
+{
+ SolarMutexGuard aGuard;
+ ScFieldGroups::iterator aOldIt = implFindByName( rOldName );
+ ScFieldGroups::iterator aNewIt = implFindByName( rNewName );
+ if( aOldIt == maGroups.end() )
+ throw RuntimeException("Field Group with name \"" + rOldName + "\" not found", static_cast<cppu::OWeakObject*>(this));
+ // new name must not exist yet
+ if( (aNewIt != maGroups.end()) && (aNewIt != aOldIt) )
+ throw RuntimeException("Field Group with name \"" + rOldName + "\" already exists", static_cast<cppu::OWeakObject*>(this));
+ aOldIt->maName = rNewName;
+}
+
+ScFieldGroups::iterator ScDataPilotFieldGroupsObj::implFindByName( const OUString& rName )
+{
+ return std::find_if(maGroups.begin(), maGroups.end(),
+ [&rName](const ScFieldGroup& rGroup) { return rGroup.maName == rName; });
+}
+
+namespace {
+
+OUString lclExtractMember( const Any& rElement )
+{
+ if( rElement.has< OUString >() )
+ return rElement.get< OUString >();
+
+ Reference< XNamed > xNamed( rElement, UNO_QUERY );
+ if( xNamed.is() )
+ return xNamed->getName();
+
+ return OUString();
+}
+
+} // namespace
+
+ScDataPilotFieldGroupObj::ScDataPilotFieldGroupObj( ScDataPilotFieldGroupsObj& rParent, const OUString& rGroupName ) :
+ mxParent( &rParent ),
+ maGroupName( rGroupName )
+{
+}
+
+ScDataPilotFieldGroupObj::~ScDataPilotFieldGroupObj()
+{
+}
+
+// XNameAccess
+
+Any SAL_CALL ScDataPilotFieldGroupObj::getByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
+ if( aIt == rMembers.end() )
+ throw NoSuchElementException("Name \"" + rName + "\" not found", static_cast<cppu::OWeakObject*>(this));
+ return Any( Reference< XNamed >( new ScDataPilotFieldGroupItemObj( *this, *aIt ) ) );
+}
+
+Sequence< OUString > SAL_CALL ScDataPilotFieldGroupObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ return ::comphelper::containerToSequence( mxParent->getFieldGroup( maGroupName ).maMembers );
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldGroupObj::hasByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ return ::std::find( rMembers.begin(), rMembers.end(), rName ) != rMembers.end();
+}
+
+// XNameReplace
+
+void SAL_CALL ScDataPilotFieldGroupObj::replaceByName( const OUString& rName, const Any& rElement )
+{
+ SolarMutexGuard aGuard;
+
+ // it should be possible to quickly rename an item -> accept string or XNamed
+ OUString aNewName = lclExtractMember( rElement );
+ if( rName.isEmpty() || aNewName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", static_cast<cppu::OWeakObject*>(this), 0);
+ if( rName == aNewName )
+ return;
+
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ ScFieldGroupMembers::iterator aOldIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
+ ScFieldGroupMembers::iterator aNewIt = ::std::find( rMembers.begin(), rMembers.end(), aNewName );
+ if( aOldIt == rMembers.end() )
+ throw NoSuchElementException("Name \"" + rName + "\" not found", static_cast<cppu::OWeakObject*>(this));
+ if( aNewIt != rMembers.end() )
+ throw IllegalArgumentException("Name \"" + rName + "\" already exists", static_cast<cppu::OWeakObject*>(this), 0);
+ *aOldIt = aNewName;
+}
+
+// XNameContainer
+
+void SAL_CALL ScDataPilotFieldGroupObj::insertByName( const OUString& rName, const Any& /*rElement*/ )
+{
+ SolarMutexGuard aGuard;
+
+ // we will ignore the passed element and just try to insert the name
+ if( rName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", static_cast<cppu::OWeakObject*>(this), 0);
+
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
+ if( aIt != rMembers.end() )
+ throw IllegalArgumentException("Name \"" + rName + "\" already exists", static_cast<cppu::OWeakObject*>(this), 0);
+ rMembers.push_back( rName );
+}
+
+void SAL_CALL ScDataPilotFieldGroupObj::removeByName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+
+ if( rName.isEmpty() )
+ throw IllegalArgumentException("Name is empty", static_cast<cppu::OWeakObject*>(this), 0);
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ ScFieldGroupMembers::iterator aIt = ::std::find( rMembers.begin(), rMembers.end(), rName );
+ if( aIt == rMembers.end() )
+ throw NoSuchElementException("Name \"" + rName + "\" not found", static_cast<cppu::OWeakObject*>(this));
+ rMembers.erase( aIt );
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDataPilotFieldGroupObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return static_cast< sal_Int32 >( mxParent->getFieldGroup( maGroupName ).maMembers.size() );
+}
+
+Any SAL_CALL ScDataPilotFieldGroupObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ScFieldGroupMembers& rMembers = mxParent->getFieldGroup( maGroupName ).maMembers;
+ if ((nIndex < 0) || (o3tl::make_unsigned(nIndex) >= rMembers.size()))
+ throw IndexOutOfBoundsException();
+ return Any( Reference< XNamed >( new ScDataPilotFieldGroupItemObj( *this, rMembers[ nIndex ] ) ) );
+}
+
+// XEnumerationAccess
+
+Reference< XEnumeration > SAL_CALL ScDataPilotFieldGroupObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration( this, "com.sun.star.sheet.DataPilotFieldGroupEnumeration" );
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScDataPilotFieldGroupObj::getElementType()
+{
+ return cppu::UnoType<XNamed>::get();
+}
+
+sal_Bool SAL_CALL ScDataPilotFieldGroupObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return !mxParent->getFieldGroup( maGroupName ).maMembers.empty();
+}
+
+// XNamed
+
+OUString SAL_CALL ScDataPilotFieldGroupObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return maGroupName;
+}
+
+void SAL_CALL ScDataPilotFieldGroupObj::setName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ mxParent->renameFieldGroup( maGroupName, rName );
+ // if call to renameFieldGroup() did not throw, remember the new name
+ maGroupName = rName;
+}
+
+ScDataPilotFieldGroupItemObj::ScDataPilotFieldGroupItemObj( ScDataPilotFieldGroupObj& rParent, const OUString& rName ) :
+ mxParent( &rParent ),
+ maName( rName )
+{
+}
+
+ScDataPilotFieldGroupItemObj::~ScDataPilotFieldGroupItemObj()
+{
+}
+
+// XNamed
+
+OUString SAL_CALL ScDataPilotFieldGroupItemObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return maName;
+}
+
+void SAL_CALL ScDataPilotFieldGroupItemObj::setName( const OUString& rName )
+{
+ SolarMutexGuard aGuard;
+ mxParent->replaceByName( maName, Any( rName ) );
+ // if call to replaceByName() did not throw, remember the new name
+ maName = rName;
+}
+
+ScDataPilotItemsObj::ScDataPilotItemsObj( ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId ) :
+ ScDataPilotChildObjBase( rParent, rFieldId )
+{
+}
+
+ScDataPilotItemsObj::~ScDataPilotItemsObj()
+{
+}
+
+// XDataPilotItems
+
+ScDataPilotItemObj* ScDataPilotItemsObj::GetObjectByIndex_Impl( sal_Int32 nIndex ) const
+{
+ return ((0 <= nIndex) && (nIndex < GetMemberCount())) ?
+ new ScDataPilotItemObj( *mxParent, maFieldId, nIndex ) : nullptr;
+}
+
+// XNameAccess
+
+Any SAL_CALL ScDataPilotItemsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ Reference<XNameAccess> xMembers = GetMembers();
+ if (xMembers.is())
+ {
+ Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
+ sal_Int32 nCount = xMembersIndex->getCount();
+ sal_Int32 nItem = 0;
+ while (nItem < nCount)
+ {
+ Reference<XNamed> xMember(xMembersIndex->getByIndex(nItem), UNO_QUERY);
+ if (xMember.is() && (aName == xMember->getName()))
+ {
+ return Any( Reference< XPropertySet >( GetObjectByIndex_Impl( nItem ) ) );
+ }
+ ++nItem;
+ }
+ throw NoSuchElementException("Name \"" + aName + "\" not found", static_cast<cppu::OWeakObject*>(this));
+ }
+ return Any();
+}
+
+Sequence<OUString> SAL_CALL ScDataPilotItemsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ Sequence< OUString > aSeq;
+ if( ScDPObject* pDPObj = GetDPObject() )
+ pDPObj->GetMemberNames( lcl_GetObjectIndex( pDPObj, maFieldId ), aSeq );
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScDataPilotItemsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bFound = false;
+ Reference<XNameAccess> xMembers = GetMembers();
+ if (xMembers.is())
+ {
+ Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
+ sal_Int32 nCount = xMembersIndex->getCount();
+ sal_Int32 nItem = 0;
+ while (nItem < nCount && !bFound )
+ {
+ Reference<XNamed> xMember(xMembersIndex->getByIndex(nItem), UNO_QUERY);
+ if (xMember.is() && aName == xMember->getName())
+ bFound = true;
+ else
+ nItem++;
+ }
+ }
+ return bFound;
+}
+
+// XEnumerationAccess
+
+Reference<XEnumeration> SAL_CALL ScDataPilotItemsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.DataPilotItemsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDataPilotItemsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return GetMemberCount();
+}
+
+Any SAL_CALL ScDataPilotItemsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ Reference< XPropertySet > xItem( GetObjectByIndex_Impl( nIndex ) );
+ if (!xItem.is())
+ throw IndexOutOfBoundsException();
+ return Any( xItem );
+}
+
+uno::Type SAL_CALL ScDataPilotItemsObj::getElementType()
+{
+ return cppu::UnoType<XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL ScDataPilotItemsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+ScDataPilotItemObj::ScDataPilotItemObj( ScDataPilotDescriptorBase& rParent, const ScFieldIdentifier& rFieldId, sal_Int32 nIndex ) :
+ ScDataPilotChildObjBase( rParent, rFieldId ),
+ maPropSet( lcl_GetDataPilotItemMap() ),
+ mnIndex( nIndex )
+{
+}
+
+ScDataPilotItemObj::~ScDataPilotItemObj()
+{
+}
+
+ // XNamed
+OUString SAL_CALL ScDataPilotItemObj::getName()
+{
+ SolarMutexGuard aGuard;
+ OUString sRet;
+ Reference<XNameAccess> xMembers = GetMembers();
+ if (xMembers.is())
+ {
+ Reference<XIndexAccess> xMembersIndex(new ScNameToIndexAccess( xMembers ));
+ sal_Int32 nCount = xMembersIndex->getCount();
+ if (mnIndex < nCount)
+ {
+ Reference<XNamed> xMember(xMembersIndex->getByIndex(mnIndex), UNO_QUERY);
+ sRet = xMember->getName();
+ }
+ }
+ return sRet;
+}
+
+void SAL_CALL ScDataPilotItemObj::setName( const OUString& /* aName */ )
+{
+}
+
+ // XPropertySet
+Reference< XPropertySetInfo >
+ SAL_CALL ScDataPilotItemObj::getPropertySetInfo( )
+{
+ SolarMutexGuard aGuard;
+ static Reference<XPropertySetInfo> aRef =
+ new SfxItemPropertySetInfo( maPropSet.getPropertyMap() );
+ return aRef;
+}
+
+void SAL_CALL ScDataPilotItemObj::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScDPObject* pDPObj = nullptr;
+ ScDPSaveDimension* pDim = GetDPDimension( &pDPObj );
+ if(!pDim)
+ return;
+
+ Reference<XNameAccess> xMembers = GetMembers();
+ if( !xMembers.is() )
+ return;
+
+ Reference<XIndexAccess> xMembersIndex( new ScNameToIndexAccess( xMembers ) );
+ sal_Int32 nCount = xMembersIndex->getCount();
+ if( mnIndex >= nCount )
+ return;
+
+ Reference<XNamed> xMember(xMembersIndex->getByIndex(mnIndex), UNO_QUERY);
+ OUString sName(xMember->getName());
+ ScDPSaveMember* pMember = pDim->GetMemberByName(sName);
+ if (!pMember)
+ return;
+
+ bool bGetNewIndex = false;
+ if ( aPropertyName == SC_UNONAME_SHOWDETAIL )
+ pMember->SetShowDetails(cppu::any2bool(aValue));
+ else if ( aPropertyName == SC_UNONAME_ISHIDDEN )
+ pMember->SetIsVisible(!cppu::any2bool(aValue));
+ else if ( aPropertyName == SC_UNONAME_POS )
+ {
+ sal_Int32 nNewPos = 0;
+ if ( !( aValue >>= nNewPos ) || nNewPos < 0 || nNewPos >= nCount )
+ throw IllegalArgumentException();
+
+ pDim->SetMemberPosition( sName, nNewPos );
+ // get new effective index (depends on sorting mode, which isn't modified)
+ bGetNewIndex = true;
+
+ }
+ SetDPObject( pDPObj );
+
+ if ( bGetNewIndex ) // after SetDPObject, get the new index
+ {
+ Sequence< OUString > aItemNames = xMembers->getElementNames();
+ sal_Int32 nItemCount = aItemNames.getLength();
+ for (sal_Int32 nItem=0; nItem<nItemCount; ++nItem)
+ if (aItemNames[nItem] == sName)
+ mnIndex = nItem;
+ }
+}
+
+Any SAL_CALL ScDataPilotItemObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ Any aRet;
+ if( ScDPSaveDimension* pDim = GetDPDimension() )
+ {
+ Reference< XNameAccess > xMembers = GetMembers();
+ if( xMembers.is() )
+ {
+ Reference< XIndexAccess > xMembersIndex( new ScNameToIndexAccess( xMembers ) );
+ sal_Int32 nCount = xMembersIndex->getCount();
+ if( mnIndex < nCount )
+ {
+ Reference< XNamed > xMember( xMembersIndex->getByIndex( mnIndex ), UNO_QUERY );
+ OUString sName( xMember->getName() );
+ ScDPSaveMember* pMember = pDim->GetExistingMemberByName( sName );
+ if ( aPropertyName == SC_UNONAME_SHOWDETAIL )
+ {
+ if (pMember && pMember->HasShowDetails())
+ {
+ aRet <<= pMember->GetShowDetails();
+ }
+ else
+ {
+ Reference< XPropertySet > xMemberProps( xMember, UNO_QUERY );
+ if( xMemberProps.is() )
+ aRet = xMemberProps->getPropertyValue( SC_UNO_DP_SHOWDETAILS );
+ else
+ aRet <<= true;
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_ISHIDDEN )
+ {
+ if (pMember && pMember->HasIsVisible())
+ {
+ aRet <<= !pMember->GetIsVisible();
+ }
+ else
+ {
+ Reference< XPropertySet > xMemberProps( xMember, UNO_QUERY );
+ if( xMemberProps.is() )
+ aRet <<= !cppu::any2bool( xMemberProps->getPropertyValue( SC_UNO_DP_ISVISIBLE ) );
+ else
+ aRet <<= false;
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_POS )
+ {
+ aRet <<= mnIndex;
+ }
+ }
+ }
+ }
+ return aRet;
+}
+
+void SAL_CALL ScDataPilotItemObj::addPropertyChangeListener(
+ const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* xListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotItemObj::removePropertyChangeListener(
+ const OUString& /* aPropertyName */, const Reference< XPropertyChangeListener >& /* aListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotItemObj::addVetoableChangeListener(
+ const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+void SAL_CALL ScDataPilotItemObj::removeVetoableChangeListener(
+ const OUString& /* PropertyName */, const Reference< XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/datauno.cxx b/sc/source/ui/unoobj/datauno.cxx
new file mode 100644
index 000000000..effa5ed50
--- /dev/null
+++ b/sc/source/ui/unoobj/datauno.cxx
@@ -0,0 +1,2390 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <datauno.hxx>
+
+#include <svl/hint.hxx>
+#include <svl/numformat.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <vcl/svapp.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/util/SortField.hpp>
+#include <com/sun/star/table/TableSortField.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/table/TableOrientation.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <com/sun/star/sheet/DataImportMode.hpp>
+#include <com/sun/star/sheet/FilterFieldType.hpp>
+#include <com/sun/star/sheet/FilterOperator2.hpp>
+#include <com/sun/star/sheet/TableFilterField2.hpp>
+
+#include <dapiuno.hxx>
+#include <cellsuno.hxx>
+#include <miscuno.hxx>
+#include <targuno.hxx>
+#include <rangeutl.hxx>
+#include <dbdata.hxx>
+#include <docsh.hxx>
+#include <dbdocfun.hxx>
+#include <unonames.hxx>
+#include <globalnames.hxx>
+#include <convuno.hxx>
+#include <hints.hxx>
+#include <attrib.hxx>
+#include <dpshttab.hxx>
+#include <queryentry.hxx>
+#include <dputil.hxx>
+#include <sortparam.hxx>
+#include <dpobject.hxx>
+#include <filterentries.hxx>
+
+#include <comphelper/extract.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+
+#include <memory>
+
+using namespace com::sun::star;
+using namespace css::sheet;
+
+// everything without Which-ID, map only for PropertySetInfo
+
+static const SfxItemPropertyMapEntry* lcl_GetSubTotalPropertyMap()
+{
+ // some old property names are for 5.2 compatibility
+
+ static const SfxItemPropertyMapEntry aSubTotalPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_BINDFMT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_CASE, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ENABSORT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ENUSLIST, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_FORMATS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_INSBRK, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ISCASE, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_MAXFLD, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNONAME_SORTASC, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ULIST, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_UINDEX, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNONAME_USINDEX, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aSubTotalPropertyMap_Impl;
+}
+
+static const SfxItemPropertyMapEntry* lcl_GetFilterPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aFilterPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_CONTHDR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_COPYOUT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ISCASE, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_MAXFLD, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNONAME_ORIENT, 0, cppu::UnoType<table::TableOrientation>::get(), 0, 0},
+ { SC_UNONAME_OUTPOS, 0, cppu::UnoType<table::CellAddress>::get(), 0, 0},
+ { SC_UNONAME_SAVEOUT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_SKIPDUP, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_USEREGEX, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aFilterPropertyMap_Impl;
+}
+
+static const SfxItemPropertyMapEntry* lcl_GetDBRangePropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDBRangePropertyMap_Impl[] =
+ {
+ { SC_UNONAME_AUTOFLT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_FLTCRT, 0, cppu::UnoType<table::CellRangeAddress>::get(), 0, 0},
+ { SC_UNONAME_FROMSELECT,0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_ISUSER, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_KEEPFORM, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_LINKDISPBIT, 0, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_LINKDISPNAME, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_MOVCELLS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_REFPERIOD, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNONAME_STRIPDAT, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_TOKENINDEX,0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_USEFLTCRT,0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_TOTALSROW,0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_CONTHDR ,0, cppu::UnoType<bool>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aDBRangePropertyMap_Impl;
+}
+
+SC_SIMPLE_SERVICE_INFO( ScConsolidationDescriptor, "ScConsolidationDescriptor", "com.sun.star.sheet.ConsolidationDescriptor" )
+SC_SIMPLE_SERVICE_INFO( ScDatabaseRangesObj, "ScDatabaseRangesObj", "com.sun.star.sheet.DatabaseRanges" )
+SC_SIMPLE_SERVICE_INFO( ScFilterDescriptorBase, "ScFilterDescriptorBase", "com.sun.star.sheet.SheetFilterDescriptor" )
+SC_SIMPLE_SERVICE_INFO( ScSubTotalDescriptorBase, "ScSubTotalDescriptorBase", "com.sun.star.sheet.SubTotalDescriptor" )
+SC_SIMPLE_SERVICE_INFO( ScSubTotalFieldObj, "ScSubTotalFieldObj", "com.sun.star.sheet.SubTotalField" )
+
+sheet::GeneralFunction ScDataUnoConversion::SubTotalToGeneral( ScSubTotalFunc eSubTotal )
+{
+ sheet::GeneralFunction eGeneral;
+ switch (eSubTotal)
+ {
+ case SUBTOTAL_FUNC_NONE: eGeneral = sheet::GeneralFunction_NONE; break;
+ case SUBTOTAL_FUNC_AVE: eGeneral = sheet::GeneralFunction_AVERAGE; break;
+ case SUBTOTAL_FUNC_CNT: eGeneral = sheet::GeneralFunction_COUNTNUMS; break;
+ case SUBTOTAL_FUNC_CNT2: eGeneral = sheet::GeneralFunction_COUNT; break;
+ case SUBTOTAL_FUNC_MAX: eGeneral = sheet::GeneralFunction_MAX; break;
+ case SUBTOTAL_FUNC_MIN: eGeneral = sheet::GeneralFunction_MIN; break;
+ case SUBTOTAL_FUNC_PROD: eGeneral = sheet::GeneralFunction_PRODUCT; break;
+ case SUBTOTAL_FUNC_STD: eGeneral = sheet::GeneralFunction_STDEV; break;
+ case SUBTOTAL_FUNC_STDP: eGeneral = sheet::GeneralFunction_STDEVP; break;
+ case SUBTOTAL_FUNC_SUM: eGeneral = sheet::GeneralFunction_SUM; break;
+ case SUBTOTAL_FUNC_VAR: eGeneral = sheet::GeneralFunction_VAR; break;
+ case SUBTOTAL_FUNC_VARP: eGeneral = sheet::GeneralFunction_VARP; break;
+ default:
+ OSL_FAIL("SubTotalToGeneral: wrong enum");
+ eGeneral = sheet::GeneralFunction_NONE;
+ break;
+ }
+ return eGeneral;
+}
+
+void ScImportDescriptor::FillProperties( uno::Sequence<beans::PropertyValue>& rSeq, const ScImportParam& rParam )
+{
+ OSL_ENSURE( rSeq.getLength() == GetPropertyCount(), "wrong Count" );
+
+ beans::PropertyValue* pArray = rSeq.getArray();
+
+ sheet::DataImportMode eMode = sheet::DataImportMode_NONE;
+ if ( rParam.bImport )
+ {
+ if ( rParam.bSql )
+ eMode = sheet::DataImportMode_SQL;
+ else if ( rParam.nType == ScDbQuery )
+ eMode = sheet::DataImportMode_QUERY;
+ else
+ eMode = sheet::DataImportMode_TABLE; // type always ScDbQuery or ScDbTable
+ }
+
+ svx::ODataAccessDescriptor aDescriptor;
+ aDescriptor.setDataSource(rParam.aDBName);
+ if (aDescriptor.has( svx::DataAccessDescriptorProperty::DataSource ))
+ {
+ pArray[0].Name = SC_UNONAME_DBNAME;
+ pArray[0].Value <<= rParam.aDBName;
+ }
+ else if (aDescriptor.has( svx::DataAccessDescriptorProperty::ConnectionResource ))
+ {
+ pArray[0].Name = SC_UNONAME_CONRES;
+ pArray[0].Value <<= rParam.aDBName;
+ }
+
+ pArray[1].Name = SC_UNONAME_SRCTYPE;
+ pArray[1].Value <<= eMode;
+
+ pArray[2].Name = SC_UNONAME_SRCOBJ;
+ pArray[2].Value <<= rParam.aStatement;
+
+ pArray[3].Name = SC_UNONAME_ISNATIVE;
+ pArray[3].Value <<= rParam.bNative;
+}
+
+void ScImportDescriptor::FillImportParam( ScImportParam& rParam, const uno::Sequence<beans::PropertyValue>& rSeq )
+{
+ OUString aStrVal;
+ for (const beans::PropertyValue& rProp : rSeq)
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == SC_UNONAME_ISNATIVE)
+ rParam.bNative = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_DBNAME)
+ {
+ if ( rProp.Value >>= aStrVal )
+ rParam.aDBName = aStrVal;
+ }
+ else if (aPropName == SC_UNONAME_CONRES)
+ {
+ if ( rProp.Value >>= aStrVal )
+ rParam.aDBName = aStrVal;
+ }
+ else if (aPropName == SC_UNONAME_SRCOBJ)
+ {
+ if ( rProp.Value >>= aStrVal )
+ rParam.aStatement = aStrVal;
+ }
+ else if (aPropName == SC_UNONAME_SRCTYPE)
+ {
+ //! test for correct enum type?
+ sheet::DataImportMode eMode = static_cast<sheet::DataImportMode>(ScUnoHelpFunctions::GetEnumFromAny( rProp.Value ));
+ switch (eMode)
+ {
+ case sheet::DataImportMode_NONE:
+ rParam.bImport = false;
+ break;
+ case sheet::DataImportMode_SQL:
+ rParam.bImport = true;
+ rParam.bSql = true;
+ break;
+ case sheet::DataImportMode_TABLE:
+ rParam.bImport = true;
+ rParam.bSql = false;
+ rParam.nType = ScDbTable;
+ break;
+ case sheet::DataImportMode_QUERY:
+ rParam.bImport = true;
+ rParam.bSql = false;
+ rParam.nType = ScDbQuery;
+ break;
+ default:
+ OSL_FAIL("wrong mode");
+ rParam.bImport = false;
+ }
+ }
+ }
+}
+
+void ScSortDescriptor::FillProperties( uno::Sequence<beans::PropertyValue>& rSeq, const ScSortParam& rParam )
+{
+ OSL_ENSURE( rSeq.getLength() == GetPropertyCount(), "wrong count" );
+
+ beans::PropertyValue* pArray = rSeq.getArray();
+
+ // gather Uno values together
+
+ table::CellAddress aOutPos;
+ aOutPos.Sheet = rParam.nDestTab;
+ aOutPos.Column = rParam.nDestCol;
+ aOutPos.Row = rParam.nDestRow;
+
+ sal_uInt16 nSortCount = 0;
+ while ( nSortCount < rParam.GetSortKeyCount() && rParam.maKeyState[nSortCount].bDoSort )
+ ++nSortCount;
+
+ uno::Sequence<table::TableSortField> aFields(nSortCount);
+ if (nSortCount)
+ {
+ table::TableSortField* pFieldArray = aFields.getArray();
+ for (sal_uInt16 i=0; i<nSortCount; i++)
+ {
+ pFieldArray[i].Field = rParam.maKeyState[i].nField;
+ pFieldArray[i].IsAscending = rParam.maKeyState[i].bAscending;
+ pFieldArray[i].FieldType = table::TableSortFieldType_AUTOMATIC; // always automatic
+ pFieldArray[i].IsCaseSensitive = rParam.bCaseSens;
+ pFieldArray[i].CollatorLocale = rParam.aCollatorLocale;
+ pFieldArray[i].CollatorAlgorithm = rParam.aCollatorAlgorithm;
+ }
+ }
+
+ // fill the sequence
+
+ pArray[0].Name = SC_UNONAME_ISSORTCOLUMNS;
+ pArray[0].Value <<= !rParam.bByRow;
+
+ pArray[1].Name = SC_UNONAME_CONTHDR;
+ pArray[1].Value <<= rParam.bHasHeader;
+
+ pArray[2].Name = SC_UNONAME_MAXFLD;
+ pArray[2].Value <<= static_cast<sal_Int32>( rParam.GetSortKeyCount() );
+
+ pArray[3].Name = SC_UNONAME_SORTFLD;
+ pArray[3].Value <<= aFields;
+
+ pArray[4].Name = SC_UNONAME_BINDFMT;
+ pArray[4].Value <<= rParam.aDataAreaExtras.mbCellFormats;
+
+ pArray[5].Name = SC_UNONAME_COPYOUT;
+ pArray[5].Value <<= !rParam.bInplace;
+
+ pArray[6].Name = SC_UNONAME_OUTPOS;
+ pArray[6].Value <<= aOutPos;
+
+ pArray[7].Name = SC_UNONAME_ISULIST;
+ pArray[7].Value <<= rParam.bUserDef;
+
+ pArray[8].Name = SC_UNONAME_UINDEX;
+ pArray[8].Value <<= static_cast<sal_Int32>( rParam.nUserIndex );
+}
+
+void ScSortDescriptor::FillSortParam( ScSortParam& rParam, const uno::Sequence<beans::PropertyValue>& rSeq )
+{
+ sal_Int32 nSortSize = static_cast<sal_Int32>(rParam.GetSortKeyCount());
+
+ for (const beans::PropertyValue& rProp : rSeq)
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == SC_UNONAME_ORIENT)
+ {
+ //! test for correct enum type?
+ table::TableOrientation eOrient = static_cast<table::TableOrientation>(ScUnoHelpFunctions::GetEnumFromAny( rProp.Value ));
+ rParam.bByRow = ( eOrient != table::TableOrientation_COLUMNS );
+ }
+ else if (aPropName == SC_UNONAME_ISSORTCOLUMNS)
+ {
+ rParam.bByRow = !::cppu::any2bool(rProp.Value);
+ }
+ else if (aPropName == SC_UNONAME_CONTHDR)
+ rParam.bHasHeader = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_MAXFLD)
+ {
+ sal_Int32 nVal;
+ if ( (rProp.Value >>= nVal) && nVal > nSortSize )
+ {
+ //! specify exceptions
+ //! throw lang::IllegalArgumentException();
+ }
+ }
+ else if (aPropName == SC_UNONAME_SORTFLD)
+ {
+ uno::Sequence<util::SortField> aSeq;
+ uno::Sequence<table::TableSortField> aNewSeq;
+ if ( rProp.Value >>= aSeq )
+ {
+ sal_Int32 nCount = aSeq.getLength();
+ sal_Int32 i;
+ if ( nCount > static_cast<sal_Int32>( rParam.GetSortKeyCount() ) )
+ {
+ // tdf#105301 - increase the size of the sorting keys
+ nSortSize = nCount;
+ rParam.maKeyState.resize(nCount);
+ }
+ const util::SortField* pFieldArray = aSeq.getConstArray();
+ for (i=0; i<nCount; i++)
+ {
+ rParam.maKeyState[i].nField = static_cast<SCCOLROW>( pFieldArray[i].Field );
+ rParam.maKeyState[i].bAscending = pFieldArray[i].SortAscending;
+
+ // FieldType is ignored
+ rParam.maKeyState[i].bDoSort = true;
+ }
+ for (i=nCount; i<nSortSize; i++)
+ rParam.maKeyState[i].bDoSort = false;
+ }
+ else if ( rProp.Value >>= aNewSeq )
+ {
+ sal_Int32 nCount = aNewSeq.getLength();
+ sal_Int32 i;
+ if ( nCount > nSortSize )
+ {
+ nCount = nSortSize;
+ rParam.maKeyState.resize(nCount);
+ }
+ const table::TableSortField* pFieldArray = aNewSeq.getConstArray();
+ for (i=0; i<nCount; i++)
+ {
+ rParam.maKeyState[i].nField = static_cast<SCCOLROW>( pFieldArray[i].Field );
+ rParam.maKeyState[i].bAscending = pFieldArray[i].IsAscending;
+
+ // only one is possible, sometime we should make it possible to have different for every entry
+ rParam.bCaseSens = pFieldArray[i].IsCaseSensitive;
+ rParam.aCollatorLocale = pFieldArray[i].CollatorLocale;
+ rParam.aCollatorAlgorithm = pFieldArray[i].CollatorAlgorithm;
+
+ // FieldType is ignored
+ rParam.maKeyState[i].bDoSort = true;
+ }
+ for (i=nCount; i<nSortSize; i++)
+ rParam.maKeyState[i].bDoSort = false;
+ }
+ }
+ else if (aPropName == SC_UNONAME_ISCASE)
+ {
+ rParam.bCaseSens = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ }
+ else if (aPropName == SC_UNONAME_BINDFMT)
+ rParam.aDataAreaExtras.mbCellFormats = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_COPYOUT)
+ rParam.bInplace = !ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_OUTPOS)
+ {
+ table::CellAddress aAddress;
+ if ( rProp.Value >>= aAddress )
+ {
+ rParam.nDestTab = aAddress.Sheet;
+ rParam.nDestCol = static_cast<SCCOL>(aAddress.Column);
+ rParam.nDestRow = static_cast<SCROW>(aAddress.Row);
+ }
+ }
+ else if (aPropName == SC_UNONAME_ISULIST)
+ rParam.bUserDef = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_UINDEX)
+ {
+ sal_Int32 nVal = 0;
+ if ( rProp.Value >>= nVal )
+ rParam.nUserIndex = static_cast<sal_uInt16>(nVal);
+ }
+ else if (aPropName == SC_UNONAME_COLLLOC)
+ {
+ rProp.Value >>= rParam.aCollatorLocale;
+ }
+ else if (aPropName == SC_UNONAME_COLLALG)
+ {
+ OUString sStr;
+ if ( rProp.Value >>= sStr )
+ rParam.aCollatorAlgorithm = sStr;
+ }
+ }
+}
+
+ScSubTotalFieldObj::ScSubTotalFieldObj( ScSubTotalDescriptorBase* pDesc, sal_uInt16 nP ) :
+ xParent( pDesc ),
+ nPos( nP )
+{
+ OSL_ENSURE(pDesc, "ScSubTotalFieldObj: Parent is 0");
+}
+
+ScSubTotalFieldObj::~ScSubTotalFieldObj()
+{
+}
+
+// XSubTotalField
+
+sal_Int32 SAL_CALL ScSubTotalFieldObj::getGroupColumn()
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ xParent->GetData(aParam);
+
+ return aParam.nField[nPos];
+}
+
+void SAL_CALL ScSubTotalFieldObj::setGroupColumn( sal_Int32 nGroupColumn )
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ xParent->GetData(aParam);
+
+ aParam.nField[nPos] = static_cast<SCCOL>(nGroupColumn);
+
+ xParent->PutData(aParam);
+}
+
+uno::Sequence<sheet::SubTotalColumn> SAL_CALL ScSubTotalFieldObj::getSubTotalColumns()
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ xParent->GetData(aParam);
+
+ SCCOL nCount = aParam.nSubTotals[nPos];
+ uno::Sequence<sheet::SubTotalColumn> aSeq(nCount);
+ sheet::SubTotalColumn* pAry = aSeq.getArray();
+ for (SCCOL i=0; i<nCount; i++)
+ {
+ pAry[i].Column = aParam.pSubTotals[nPos][i];
+ pAry[i].Function = ScDataUnoConversion::SubTotalToGeneral(
+ aParam.pFunctions[nPos][i] );
+ }
+ return aSeq;
+}
+
+void SAL_CALL ScSubTotalFieldObj::setSubTotalColumns(
+ const uno::Sequence<sheet::SubTotalColumn>& aSubTotalColumns )
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ xParent->GetData(aParam);
+
+ sal_uInt32 nColCount = aSubTotalColumns.getLength();
+ if ( nColCount <= sal::static_int_cast<sal_uInt32>(SCCOL_MAX) )
+ {
+ SCCOL nCount = static_cast<SCCOL>(nColCount);
+ aParam.nSubTotals[nPos] = nCount;
+ if (nCount != 0)
+ {
+ aParam.pSubTotals[nPos].reset(new SCCOL[nCount]);
+ aParam.pFunctions[nPos].reset(new ScSubTotalFunc[nCount]);
+
+ const sheet::SubTotalColumn* pAry = aSubTotalColumns.getConstArray();
+ for (SCCOL i=0; i<nCount; i++)
+ {
+ aParam.pSubTotals[nPos][i] = static_cast<SCCOL>(pAry[i].Column);
+ aParam.pFunctions[nPos][i] = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(pAry[i].Function));
+ }
+ }
+ else
+ {
+ aParam.pSubTotals[nPos].reset();
+ aParam.pFunctions[nPos].reset();
+ }
+ }
+ //! otherwise exception or so? (too many columns)
+
+ xParent->PutData(aParam);
+}
+
+ScSubTotalDescriptorBase::ScSubTotalDescriptorBase() :
+ aPropSet( lcl_GetSubTotalPropertyMap() )
+{
+}
+
+ScSubTotalDescriptorBase::~ScSubTotalDescriptorBase()
+{
+}
+
+// XSubTotalDescriptor
+
+rtl::Reference<ScSubTotalFieldObj> ScSubTotalDescriptorBase::GetObjectByIndex_Impl(sal_uInt16 nIndex)
+{
+ if ( nIndex < getCount() )
+ return new ScSubTotalFieldObj( this, nIndex );
+ return nullptr;
+}
+
+void SAL_CALL ScSubTotalDescriptorBase::clear()
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ GetData(aParam);
+
+ for (bool & rn : aParam.bGroupActive)
+ rn = false;
+
+ //! notify the field objects???
+
+ PutData(aParam);
+}
+
+void SAL_CALL ScSubTotalDescriptorBase::addNew(
+ const uno::Sequence<sheet::SubTotalColumn>& aSubTotalColumns,
+ sal_Int32 nGroupColumn )
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ GetData(aParam);
+
+ sal_uInt16 nPos = 0;
+ while ( nPos < MAXSUBTOTAL && aParam.bGroupActive[nPos] )
+ ++nPos;
+
+ sal_uInt32 nColCount = aSubTotalColumns.getLength();
+
+ if ( nPos >= MAXSUBTOTAL || nColCount > sal::static_int_cast<sal_uInt32>(SCCOL_MAX) )
+ // too many fields / columns
+ throw uno::RuntimeException(); // no other exceptions specified
+
+ aParam.bGroupActive[nPos] = true;
+ aParam.nField[nPos] = static_cast<SCCOL>(nGroupColumn);
+
+ aParam.pSubTotals[nPos].reset();
+ aParam.pFunctions[nPos].reset();
+
+ SCCOL nCount = static_cast<SCCOL>(nColCount);
+ aParam.nSubTotals[nPos] = nCount;
+ if (nCount != 0)
+ {
+ aParam.pSubTotals[nPos].reset(new SCCOL[nCount]);
+ aParam.pFunctions[nPos].reset(new ScSubTotalFunc[nCount]);
+
+ const sheet::SubTotalColumn* pAry = aSubTotalColumns.getConstArray();
+ for (SCCOL i=0; i<nCount; i++)
+ {
+ aParam.pSubTotals[nPos][i] = static_cast<SCCOL>(pAry[i].Column);
+ aParam.pFunctions[nPos][i] = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(pAry[i].Function));
+ }
+ }
+ else
+ {
+ aParam.pSubTotals[nPos].reset();
+ aParam.pFunctions[nPos].reset();
+ }
+
+ PutData(aParam);
+}
+
+// flags/settings as properties
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScSubTotalDescriptorBase::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.SubTotalFieldsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScSubTotalDescriptorBase::getCount()
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ GetData(aParam);
+
+ sal_uInt16 nCount = 0;
+ while ( nCount < MAXSUBTOTAL && aParam.bGroupActive[nCount] )
+ ++nCount;
+ return nCount;
+}
+
+uno::Any SAL_CALL ScSubTotalDescriptorBase::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XSubTotalField> xField(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if (!xField.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xField);
+}
+
+uno::Type SAL_CALL ScSubTotalDescriptorBase::getElementType()
+{
+ return cppu::UnoType<sheet::XSubTotalField>::get();
+}
+
+sal_Bool SAL_CALL ScSubTotalDescriptorBase::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSubTotalDescriptorBase::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScSubTotalDescriptorBase::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ GetData(aParam);
+
+ // some old property names are for 5.2 compatibility
+
+ if (aPropertyName == SC_UNONAME_CASE || aPropertyName == SC_UNONAME_ISCASE )
+ aParam.bCaseSens = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_FORMATS || aPropertyName == SC_UNONAME_BINDFMT )
+ aParam.bIncludePattern = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_ENABSORT )
+ aParam.bDoSort = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_SORTASC )
+ aParam.bAscending = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_INSBRK )
+ aParam.bPagebreak = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_ULIST || aPropertyName == SC_UNONAME_ENUSLIST )
+ aParam.bUserDef = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_UINDEX || aPropertyName == SC_UNONAME_USINDEX )
+ {
+ sal_Int32 nVal = 0;
+ if ( aValue >>= nVal )
+ aParam.nUserIndex = static_cast<sal_uInt16>(nVal);
+ }
+ else if (aPropertyName == SC_UNONAME_MAXFLD )
+ {
+ sal_Int32 nVal = 0;
+ if ( (aValue >>= nVal) && nVal > sal::static_int_cast<sal_Int32>(MAXSUBTOTAL) )
+ {
+ throw lang::IllegalArgumentException();
+ }
+ }
+
+ PutData(aParam);
+}
+
+uno::Any SAL_CALL ScSubTotalDescriptorBase::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ ScSubTotalParam aParam;
+ GetData(aParam);
+
+ uno::Any aRet;
+
+ // some old property names are for 5.2 compatibility
+
+ if (aPropertyName == SC_UNONAME_CASE || aPropertyName == SC_UNONAME_ISCASE )
+ aRet <<= aParam.bCaseSens;
+ else if (aPropertyName == SC_UNONAME_FORMATS || aPropertyName == SC_UNONAME_BINDFMT )
+ aRet <<= aParam.bIncludePattern;
+ else if (aPropertyName == SC_UNONAME_ENABSORT )
+ aRet <<= aParam.bDoSort;
+ else if (aPropertyName == SC_UNONAME_SORTASC )
+ aRet <<= aParam.bAscending;
+ else if (aPropertyName == SC_UNONAME_INSBRK )
+ aRet <<= aParam.bPagebreak;
+ else if (aPropertyName == SC_UNONAME_ULIST || aPropertyName == SC_UNONAME_ENUSLIST )
+ aRet <<= aParam.bUserDef;
+ else if (aPropertyName == SC_UNONAME_UINDEX || aPropertyName == SC_UNONAME_USINDEX )
+ aRet <<= static_cast<sal_Int32>(aParam.nUserIndex);
+ else if (aPropertyName == SC_UNONAME_MAXFLD )
+ aRet <<= sal_Int32(MAXSUBTOTAL);
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSubTotalDescriptorBase )
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION_IMPL(ScSubTotalDescriptorBase);
+
+ScSubTotalDescriptor::ScSubTotalDescriptor()
+{
+}
+
+ScSubTotalDescriptor::~ScSubTotalDescriptor()
+{
+}
+
+void ScSubTotalDescriptor::GetData( ScSubTotalParam& rParam ) const
+{
+ rParam = aStoredParam; // query for interface
+}
+
+void ScSubTotalDescriptor::PutData( const ScSubTotalParam& rParam )
+{
+ aStoredParam = rParam; // set by the interface
+}
+
+void ScSubTotalDescriptor::SetParam( const ScSubTotalParam& rNew )
+{
+ aStoredParam = rNew; // set from outside
+}
+
+ScRangeSubTotalDescriptor::ScRangeSubTotalDescriptor(ScDatabaseRangeObj* pPar) :
+ mxParent(pPar)
+{
+}
+
+ScRangeSubTotalDescriptor::~ScRangeSubTotalDescriptor()
+{
+}
+
+void ScRangeSubTotalDescriptor::GetData( ScSubTotalParam& rParam ) const
+{
+ if (mxParent.is())
+ mxParent->GetSubTotalParam( rParam );
+}
+
+void ScRangeSubTotalDescriptor::PutData( const ScSubTotalParam& rParam )
+{
+ if (mxParent.is())
+ mxParent->SetSubTotalParam( rParam );
+}
+
+ScConsolidationDescriptor::ScConsolidationDescriptor()
+{
+}
+
+ScConsolidationDescriptor::~ScConsolidationDescriptor()
+{
+}
+
+void ScConsolidationDescriptor::SetParam( const ScConsolidateParam& rNew )
+{
+ aParam = rNew;
+}
+
+// XConsolidationDescriptor
+
+sheet::GeneralFunction SAL_CALL ScConsolidationDescriptor::getFunction()
+{
+ SolarMutexGuard aGuard;
+ return ScDataUnoConversion::SubTotalToGeneral(aParam.eFunction);
+}
+
+void SAL_CALL ScConsolidationDescriptor::setFunction( sheet::GeneralFunction nFunction )
+{
+ SolarMutexGuard aGuard;
+ aParam.eFunction = ScDPUtil::toSubTotalFunc(static_cast<ScGeneralFunction>(nFunction));
+}
+
+uno::Sequence<table::CellRangeAddress> SAL_CALL ScConsolidationDescriptor::getSources()
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = aParam.nDataAreaCount;
+ if (!aParam.pDataAreas)
+ nCount = 0;
+ table::CellRangeAddress aRange;
+ uno::Sequence<table::CellRangeAddress> aSeq(nCount);
+ table::CellRangeAddress* pAry = aSeq.getArray();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ScArea const & rArea = aParam.pDataAreas[i];
+ aRange.Sheet = rArea.nTab;
+ aRange.StartColumn = rArea.nColStart;
+ aRange.StartRow = rArea.nRowStart;
+ aRange.EndColumn = rArea.nColEnd;
+ aRange.EndRow = rArea.nRowEnd;
+ pAry[i] = aRange;
+ }
+ return aSeq;
+}
+
+void SAL_CALL ScConsolidationDescriptor::setSources(
+ const uno::Sequence<table::CellRangeAddress>& aSources )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = static_cast<sal_uInt16>(aSources.getLength());
+ if (nCount)
+ {
+ const table::CellRangeAddress* pAry = aSources.getConstArray();
+ std::unique_ptr<ScArea[]> pNew(new ScArea[nCount]);
+ sal_uInt16 i;
+ for (i=0; i<nCount; i++)
+ pNew[i] = ScArea( pAry[i].Sheet,
+ static_cast<SCCOL>(pAry[i].StartColumn), pAry[i].StartRow,
+ static_cast<SCCOL>(pAry[i].EndColumn), pAry[i].EndRow );
+
+ aParam.SetAreas( std::move(pNew), nCount ); // copy everything
+ }
+ else
+ aParam.ClearDataAreas();
+}
+
+table::CellAddress SAL_CALL ScConsolidationDescriptor::getStartOutputPosition()
+{
+ SolarMutexGuard aGuard;
+ table::CellAddress aPos;
+ aPos.Column = aParam.nCol;
+ aPos.Row = aParam.nRow;
+ aPos.Sheet = aParam.nTab;
+ return aPos;
+}
+
+void SAL_CALL ScConsolidationDescriptor::setStartOutputPosition(
+ const table::CellAddress& aStartOutputPosition )
+{
+ SolarMutexGuard aGuard;
+ aParam.nCol = static_cast<SCCOL>(aStartOutputPosition.Column);
+ aParam.nRow = static_cast<SCROW>(aStartOutputPosition.Row);
+ aParam.nTab = aStartOutputPosition.Sheet;
+}
+
+sal_Bool SAL_CALL ScConsolidationDescriptor::getUseColumnHeaders()
+{
+ SolarMutexGuard aGuard;
+ return aParam.bByCol;
+}
+
+void SAL_CALL ScConsolidationDescriptor::setUseColumnHeaders( sal_Bool bUseColumnHeaders )
+{
+ SolarMutexGuard aGuard;
+ aParam.bByCol = bUseColumnHeaders;
+}
+
+sal_Bool SAL_CALL ScConsolidationDescriptor::getUseRowHeaders()
+{
+ SolarMutexGuard aGuard;
+ return aParam.bByRow;
+}
+
+void SAL_CALL ScConsolidationDescriptor::setUseRowHeaders( sal_Bool bUseRowHeaders )
+{
+ SolarMutexGuard aGuard;
+ aParam.bByRow = bUseRowHeaders;
+}
+
+sal_Bool SAL_CALL ScConsolidationDescriptor::getInsertLinks()
+{
+ SolarMutexGuard aGuard;
+ return aParam.bReferenceData;
+}
+
+void SAL_CALL ScConsolidationDescriptor::setInsertLinks( sal_Bool bInsertLinks )
+{
+ SolarMutexGuard aGuard;
+ aParam.bReferenceData = bInsertLinks;
+}
+
+ScFilterDescriptorBase::ScFilterDescriptorBase(ScDocShell* pDocShell) :
+ aPropSet( lcl_GetFilterPropertyMap() ),
+ pDocSh(pDocShell)
+{
+ if (pDocSh)
+ pDocSh->GetDocument().AddUnoObject(*this);
+}
+
+ScFilterDescriptorBase::~ScFilterDescriptorBase()
+{
+ SolarMutexGuard g;
+
+ if (pDocSh)
+ pDocSh->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScFilterDescriptorBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocSh = nullptr; // invalid
+ }
+}
+
+// XSheetFilterDescriptor and XSheetFilterDescriptor2
+
+uno::Sequence<sheet::TableFilterField> SAL_CALL ScFilterDescriptorBase::getFilterFields()
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ SCSIZE nEntries = aParam.GetEntryCount(); // allocated entries in Param
+ SCSIZE nCount = 0; // active
+ while ( nCount < nEntries &&
+ aParam.GetEntry(nCount).bDoQuery )
+ ++nCount;
+
+ sheet::TableFilterField aField;
+ uno::Sequence<sheet::TableFilterField> aSeq(static_cast<sal_Int32>(nCount));
+ sheet::TableFilterField* pAry = aSeq.getArray();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ const ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if (rEntry.GetQueryItems().empty())
+ continue;
+
+ const ScQueryEntry::Item& rItem = rEntry.GetQueryItems().front();
+
+ aField.Connection = (rEntry.eConnect == SC_AND) ? sheet::FilterConnection_AND :
+ sheet::FilterConnection_OR;
+ aField.Field = rEntry.nField;
+ aField.IsNumeric = rItem.meType != ScQueryEntry::ByString;
+ aField.StringValue = rItem.maString.getString();
+ aField.NumericValue = rItem.mfVal;
+
+ switch (rEntry.eOp) // ScQueryOp
+ {
+ case SC_EQUAL:
+ {
+ aField.Operator = sheet::FilterOperator_EQUAL;
+ if (rEntry.IsQueryByEmpty())
+ {
+ aField.Operator = sheet::FilterOperator_EMPTY;
+ aField.NumericValue = 0;
+ }
+ else if (rEntry.IsQueryByNonEmpty())
+ {
+ aField.Operator = sheet::FilterOperator_NOT_EMPTY;
+ aField.NumericValue = 0;
+ }
+ }
+ break;
+ case SC_LESS: aField.Operator = sheet::FilterOperator_LESS; break;
+ case SC_GREATER: aField.Operator = sheet::FilterOperator_GREATER; break;
+ case SC_LESS_EQUAL: aField.Operator = sheet::FilterOperator_LESS_EQUAL; break;
+ case SC_GREATER_EQUAL: aField.Operator = sheet::FilterOperator_GREATER_EQUAL; break;
+ case SC_NOT_EQUAL: aField.Operator = sheet::FilterOperator_NOT_EQUAL; break;
+ case SC_TOPVAL: aField.Operator = sheet::FilterOperator_TOP_VALUES; break;
+ case SC_BOTVAL: aField.Operator = sheet::FilterOperator_BOTTOM_VALUES; break;
+ case SC_TOPPERC: aField.Operator = sheet::FilterOperator_TOP_PERCENT; break;
+ case SC_BOTPERC: aField.Operator = sheet::FilterOperator_BOTTOM_PERCENT; break;
+ default:
+ OSL_FAIL("wrong filter enum");
+ aField.Operator = sheet::FilterOperator_EMPTY;
+ }
+ pAry[i] = aField;
+ }
+ return aSeq;
+}
+
+namespace {
+
+template<typename T>
+void convertQueryEntryToUno(const ScQueryEntry& rEntry, T& rField)
+{
+ rField.Connection = (rEntry.eConnect == SC_AND) ? sheet::FilterConnection_AND : sheet::FilterConnection_OR;
+ rField.Field = rEntry.nField;
+
+ switch (rEntry.eOp) // ScQueryOp
+ {
+ case SC_EQUAL: rField.Operator = sheet::FilterOperator2::EQUAL; break;
+ case SC_LESS: rField.Operator = sheet::FilterOperator2::LESS; break;
+ case SC_GREATER: rField.Operator = sheet::FilterOperator2::GREATER; break;
+ case SC_LESS_EQUAL: rField.Operator = sheet::FilterOperator2::LESS_EQUAL; break;
+ case SC_GREATER_EQUAL: rField.Operator = sheet::FilterOperator2::GREATER_EQUAL; break;
+ case SC_NOT_EQUAL: rField.Operator = sheet::FilterOperator2::NOT_EQUAL; break;
+ case SC_TOPVAL: rField.Operator = sheet::FilterOperator2::TOP_VALUES; break;
+ case SC_BOTVAL: rField.Operator = sheet::FilterOperator2::BOTTOM_VALUES; break;
+ case SC_TOPPERC: rField.Operator = sheet::FilterOperator2::TOP_PERCENT; break;
+ case SC_BOTPERC: rField.Operator = sheet::FilterOperator2::BOTTOM_PERCENT; break;
+ case SC_CONTAINS: rField.Operator = sheet::FilterOperator2::CONTAINS; break;
+ case SC_DOES_NOT_CONTAIN: rField.Operator = sheet::FilterOperator2::DOES_NOT_CONTAIN; break;
+ case SC_BEGINS_WITH: rField.Operator = sheet::FilterOperator2::BEGINS_WITH; break;
+ case SC_DOES_NOT_BEGIN_WITH: rField.Operator = sheet::FilterOperator2::DOES_NOT_BEGIN_WITH; break;
+ case SC_ENDS_WITH: rField.Operator = sheet::FilterOperator2::ENDS_WITH; break;
+ case SC_DOES_NOT_END_WITH: rField.Operator = sheet::FilterOperator2::DOES_NOT_END_WITH; break;
+ default:
+ OSL_FAIL("Unknown filter operator value.");
+ rField.Operator = sheet::FilterOperator2::EMPTY;
+ }
+}
+
+template<typename T>
+void convertUnoToQueryEntry(const T& rField, ScQueryEntry& rEntry)
+{
+ rEntry.bDoQuery = true;
+ rEntry.eConnect = (rField.Connection == sheet::FilterConnection_AND) ? SC_AND : SC_OR;
+ rEntry.nField = rField.Field;
+
+ switch (rField.Operator) // FilterOperator
+ {
+ case sheet::FilterOperator2::EQUAL: rEntry.eOp = SC_EQUAL; break;
+ case sheet::FilterOperator2::LESS: rEntry.eOp = SC_LESS; break;
+ case sheet::FilterOperator2::GREATER: rEntry.eOp = SC_GREATER; break;
+ case sheet::FilterOperator2::LESS_EQUAL: rEntry.eOp = SC_LESS_EQUAL; break;
+ case sheet::FilterOperator2::GREATER_EQUAL: rEntry.eOp = SC_GREATER_EQUAL; break;
+ case sheet::FilterOperator2::NOT_EQUAL: rEntry.eOp = SC_NOT_EQUAL; break;
+ case sheet::FilterOperator2::TOP_VALUES: rEntry.eOp = SC_TOPVAL; break;
+ case sheet::FilterOperator2::BOTTOM_VALUES: rEntry.eOp = SC_BOTVAL; break;
+ case sheet::FilterOperator2::TOP_PERCENT: rEntry.eOp = SC_TOPPERC; break;
+ case sheet::FilterOperator2::BOTTOM_PERCENT: rEntry.eOp = SC_BOTPERC; break;
+ case sheet::FilterOperator2::CONTAINS: rEntry.eOp = SC_CONTAINS; break;
+ case sheet::FilterOperator2::DOES_NOT_CONTAIN: rEntry.eOp = SC_DOES_NOT_CONTAIN; break;
+ case sheet::FilterOperator2::BEGINS_WITH: rEntry.eOp = SC_BEGINS_WITH; break;
+ case sheet::FilterOperator2::DOES_NOT_BEGIN_WITH: rEntry.eOp = SC_DOES_NOT_BEGIN_WITH;break;
+ case sheet::FilterOperator2::ENDS_WITH: rEntry.eOp = SC_ENDS_WITH; break;
+ case sheet::FilterOperator2::DOES_NOT_END_WITH: rEntry.eOp = SC_DOES_NOT_END_WITH; break;
+ case sheet::FilterOperator2::EMPTY:
+ rEntry.SetQueryByEmpty();
+ break;
+ case sheet::FilterOperator2::NOT_EMPTY:
+ rEntry.SetQueryByNonEmpty();
+ break;
+ default:
+ OSL_FAIL("Unknown filter operator type.");
+ rEntry.eOp = SC_EQUAL;
+ }
+}
+
+void fillQueryParam(
+ ScQueryParam& rParam, ScDocument* pDoc,
+ const uno::Sequence<sheet::TableFilterField2>& aFilterFields)
+{
+ size_t nCount = static_cast<size_t>(aFilterFields.getLength());
+ rParam.Resize(nCount);
+
+ const sheet::TableFilterField2* pAry = aFilterFields.getConstArray();
+ svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ ScQueryEntry& rEntry = rParam.GetEntry(i);
+ convertUnoToQueryEntry(pAry[i], rEntry);
+
+ if (pAry[i].Operator != sheet::FilterOperator2::EMPTY && pAry[i].Operator != sheet::FilterOperator2::NOT_EMPTY)
+ {
+ ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ rItems.resize(1);
+ ScQueryEntry::Item& rItem = rItems.front();
+ rItem.meType = pAry[i].IsNumeric ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
+ rItem.mfVal = pAry[i].NumericValue;
+ rItem.maString = rPool.intern(pAry[i].StringValue);
+
+ if (rItem.meType == ScQueryEntry::ByValue)
+ {
+ OUString aStr;
+ pDoc->GetFormatTable()->GetInputLineString(rItem.mfVal, 0, aStr);
+ rItem.maString = rPool.intern(aStr);
+ }
+ }
+ }
+
+ size_t nParamCount = rParam.GetEntryCount(); // if below eight Param isn't resized
+ for (size_t i = nCount; i < nParamCount; ++i)
+ rParam.GetEntry(i).bDoQuery = false; // reset surplus fields
+}
+
+void fillQueryParam(
+ ScQueryParam& rParam, ScDocument* pDoc,
+ const uno::Sequence<sheet::TableFilterField3>& aFilterFields)
+{
+ size_t nCount = static_cast<size_t>(aFilterFields.getLength());
+ rParam.Resize(nCount);
+
+ svl::SharedStringPool& rPool = pDoc->GetSharedStringPool();
+ const sheet::TableFilterField3* pAry = aFilterFields.getConstArray();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ ScQueryEntry& rEntry = rParam.GetEntry(i);
+ convertUnoToQueryEntry(pAry[i], rEntry);
+
+ if (pAry[i].Operator != sheet::FilterOperator2::EMPTY && pAry[i].Operator != sheet::FilterOperator2::NOT_EMPTY)
+ {
+ ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ rItems.clear();
+ const uno::Sequence<sheet::FilterFieldValue>& rVals = pAry[i].Values;
+ for (const auto& rVal : rVals)
+ {
+ ScQueryEntry::Item aItem;
+ switch (rVal.FilterType)
+ {
+ case FilterFieldType::NUMERIC:
+ aItem.meType = ScQueryEntry::ByValue;
+ break;
+ case FilterFieldType::STRING:
+ aItem.meType = ScQueryEntry::ByString;
+ break;
+ case FilterFieldType::DATE:
+ aItem.meType = ScQueryEntry::ByDate;
+ break;
+ case FilterFieldType::TEXT_COLOR:
+ aItem.meType = ScQueryEntry::ByTextColor;
+ break;
+ case FilterFieldType::BACKGROUND_COLOR:
+ aItem.meType = ScQueryEntry::ByBackgroundColor;
+ break;
+ }
+ aItem.mfVal = rVal.NumericValue;
+ aItem.maString = rPool.intern(rVal.StringValue);
+
+ if (aItem.meType == ScQueryEntry::ByValue)
+ {
+ OUString aStr;
+ pDoc->GetFormatTable()->GetInputLineString(aItem.mfVal, 0, aStr);
+ aItem.maString = rPool.intern(aStr);
+ }
+ else if (aItem.meType == ScQueryEntry::ByTextColor
+ || aItem.meType == ScQueryEntry::ByBackgroundColor)
+ {
+ aItem.maColor = Color(ColorTransparency, rVal.ColorValue);
+ }
+
+ // filter all dates starting with the given date filter YYYY or YYYY-MM and filter all datetimes
+ // starting with the given datetime filter YYYY-MM-DD, YYYY-MM-DD HH, or YYYY-MM-DD HH:MM
+ if( aItem.meType == ScQueryEntry::ByDate && aItem.maString.getLength() < 19 )
+ {
+ ScFilterEntries aFilterEntries;
+ pDoc->GetFilterEntries(rEntry.nField, rParam.nRow1, rParam.nTab, aFilterEntries);
+ for( const auto& rFilter : aFilterEntries )
+ {
+ if( rFilter.GetString().startsWith(rVal.StringValue) )
+ {
+ aItem.maString = rPool.intern(rFilter.GetString());
+ rItems.push_back(aItem);
+ }
+ }
+ }
+ else
+ {
+ rItems.push_back(aItem);
+ }
+ }
+ }
+ }
+
+ size_t nParamCount = rParam.GetEntryCount(); // if below eight Param isn't resized
+ for (size_t i = nCount; i < nParamCount; ++i)
+ rParam.GetEntry(i).bDoQuery = false; // reset surplus fields
+}
+
+}
+
+uno::Sequence<sheet::TableFilterField2> SAL_CALL ScFilterDescriptorBase::getFilterFields2()
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ SCSIZE nEntries = aParam.GetEntryCount(); // allocated entries in Param
+ SCSIZE nCount = 0; // active
+ while ( nCount < nEntries &&
+ aParam.GetEntry(nCount).bDoQuery )
+ ++nCount;
+
+ sheet::TableFilterField2 aField;
+ uno::Sequence<sheet::TableFilterField2> aSeq(static_cast<sal_Int32>(nCount));
+ sheet::TableFilterField2* pAry = aSeq.getArray();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ const ScQueryEntry& rEntry = aParam.GetEntry(i);
+ convertQueryEntryToUno(rEntry, aField);
+
+ bool bByEmpty = false;
+ if (aField.Operator == sheet::FilterOperator2::EQUAL)
+ {
+ if (rEntry.IsQueryByEmpty())
+ {
+ aField.Operator = sheet::FilterOperator2::EMPTY;
+ aField.NumericValue = 0;
+ bByEmpty = true;
+ }
+ else if (rEntry.IsQueryByNonEmpty())
+ {
+ aField.Operator = sheet::FilterOperator2::NOT_EMPTY;
+ aField.NumericValue = 0;
+ bByEmpty = true;
+ }
+ }
+
+ if (!bByEmpty && !rEntry.GetQueryItems().empty())
+ {
+ const ScQueryEntry::Item& rItem = rEntry.GetQueryItems().front();
+ aField.IsNumeric = rItem.meType != ScQueryEntry::ByString;
+ aField.StringValue = rItem.maString.getString();
+ aField.NumericValue = rItem.mfVal;
+ }
+
+ pAry[i] = aField;
+ }
+ return aSeq;
+}
+
+uno::Sequence<sheet::TableFilterField3> SAL_CALL ScFilterDescriptorBase::getFilterFields3()
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ SCSIZE nEntries = aParam.GetEntryCount(); // allocated entries in Param
+ SCSIZE nCount = 0; // active
+ while ( nCount < nEntries &&
+ aParam.GetEntry(nCount).bDoQuery )
+ ++nCount;
+
+ sheet::TableFilterField3 aField;
+ uno::Sequence<sheet::TableFilterField3> aSeq(static_cast<sal_Int32>(nCount));
+ sheet::TableFilterField3* pAry = aSeq.getArray();
+ for (SCSIZE i = 0; i < nCount; ++i)
+ {
+ const ScQueryEntry& rEntry = aParam.GetEntry(i);
+ convertQueryEntryToUno(rEntry, aField);
+
+ bool bByEmpty = false;
+ if (aField.Operator == sheet::FilterOperator2::EQUAL)
+ {
+ if (rEntry.IsQueryByEmpty())
+ {
+ aField.Operator = sheet::FilterOperator2::EMPTY;
+ aField.Values.realloc(1);
+ aField.Values.getArray()[0].NumericValue = 0;
+ bByEmpty = true;
+ }
+ else if (rEntry.IsQueryByNonEmpty())
+ {
+ aField.Operator = sheet::FilterOperator2::NOT_EMPTY;
+ aField.Values.realloc(1);
+ aField.Values.getArray()[0].NumericValue = 0;
+ bByEmpty = true;
+ }
+ }
+
+ if (!bByEmpty)
+ {
+ const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ size_t nItemCount = rItems.size();
+ aField.Values.realloc(nItemCount);
+ auto pValues = aField.Values.getArray();
+ size_t j = 0;
+ for (const auto& rItem : rItems)
+ {
+ pValues[j].IsNumeric = rItem.meType != ScQueryEntry::ByString;
+ pValues[j].StringValue = rItem.maString.getString();
+ pValues[j].NumericValue = rItem.mfVal;
+ ++j;
+ }
+ }
+
+ pAry[i] = aField;
+ }
+ return aSeq;
+}
+
+void SAL_CALL ScFilterDescriptorBase::setFilterFields(
+ const uno::Sequence<sheet::TableFilterField>& aFilterFields )
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ SCSIZE nCount = static_cast<SCSIZE>(aFilterFields.getLength());
+ aParam.Resize( nCount );
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
+ const sheet::TableFilterField* pAry = aFilterFields.getConstArray();
+ SCSIZE i;
+ for (i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
+ rItems.resize(1);
+ ScQueryEntry::Item& rItem = rItems.front();
+ rEntry.bDoQuery = true;
+ rEntry.eConnect = (pAry[i].Connection == sheet::FilterConnection_AND) ? SC_AND : SC_OR;
+ rEntry.nField = pAry[i].Field;
+ rItem.meType = pAry[i].IsNumeric ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
+ rItem.mfVal = pAry[i].NumericValue;
+ rItem.maString = rPool.intern(pAry[i].StringValue);
+
+ if (rItem.meType != ScQueryEntry::ByString)
+ {
+ OUString aStr;
+ rDoc.GetFormatTable()->GetInputLineString(rItem.mfVal, 0, aStr);
+ rItem.maString = rPool.intern(aStr);
+ }
+
+ switch (pAry[i].Operator) // FilterOperator
+ {
+ case sheet::FilterOperator_EQUAL: rEntry.eOp = SC_EQUAL; break;
+ case sheet::FilterOperator_LESS: rEntry.eOp = SC_LESS; break;
+ case sheet::FilterOperator_GREATER: rEntry.eOp = SC_GREATER; break;
+ case sheet::FilterOperator_LESS_EQUAL: rEntry.eOp = SC_LESS_EQUAL; break;
+ case sheet::FilterOperator_GREATER_EQUAL: rEntry.eOp = SC_GREATER_EQUAL; break;
+ case sheet::FilterOperator_NOT_EQUAL: rEntry.eOp = SC_NOT_EQUAL; break;
+ case sheet::FilterOperator_TOP_VALUES: rEntry.eOp = SC_TOPVAL; break;
+ case sheet::FilterOperator_BOTTOM_VALUES: rEntry.eOp = SC_BOTVAL; break;
+ case sheet::FilterOperator_TOP_PERCENT: rEntry.eOp = SC_TOPPERC; break;
+ case sheet::FilterOperator_BOTTOM_PERCENT: rEntry.eOp = SC_BOTPERC; break;
+ case sheet::FilterOperator_EMPTY:
+ rEntry.SetQueryByEmpty();
+ break;
+ case sheet::FilterOperator_NOT_EMPTY:
+ rEntry.SetQueryByNonEmpty();
+ break;
+ default:
+ OSL_FAIL("Wrong query enum");
+ rEntry.eOp = SC_EQUAL;
+ }
+ }
+
+ SCSIZE nParamCount = aParam.GetEntryCount(); // if below eight Param isn't resized
+ for (i=nCount; i<nParamCount; i++)
+ aParam.GetEntry(i).bDoQuery = false; // reset surplus fields
+
+ PutData(aParam);
+}
+
+void SAL_CALL ScFilterDescriptorBase::setFilterFields2(
+ const uno::Sequence<sheet::TableFilterField2>& aFilterFields )
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+ fillQueryParam(aParam, &pDocSh->GetDocument(), aFilterFields);
+ PutData(aParam);
+}
+
+void SAL_CALL ScFilterDescriptorBase::setFilterFields3(
+ const uno::Sequence<sheet::TableFilterField3>& aFilterFields )
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+ fillQueryParam(aParam, &pDocSh->GetDocument(), aFilterFields);
+ PutData(aParam);
+}
+
+// Rest sind Properties
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFilterDescriptorBase::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScFilterDescriptorBase::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ if (aPropertyName == SC_UNONAME_CONTHDR)
+ aParam.bHasHeader = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_COPYOUT)
+ aParam.bInplace = !(ScUnoHelpFunctions::GetBoolFromAny( aValue ));
+ else if (aPropertyName == SC_UNONAME_ISCASE)
+ aParam.bCaseSens = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_MAXFLD)
+ {
+ // silently ignored
+ }
+ else if (aPropertyName == SC_UNONAME_ORIENT)
+ {
+ //! test for correct enum type?
+ table::TableOrientation eOrient = static_cast<table::TableOrientation>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
+ aParam.bByRow = ( eOrient != table::TableOrientation_COLUMNS );
+ }
+ else if (aPropertyName == SC_UNONAME_OUTPOS)
+ {
+ table::CellAddress aAddress;
+ if ( aValue >>= aAddress )
+ {
+ aParam.nDestTab = aAddress.Sheet;
+ aParam.nDestCol = static_cast<SCCOL>(aAddress.Column);
+ aParam.nDestRow = static_cast<SCROW>(aAddress.Row);
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_SAVEOUT)
+ aParam.bDestPers = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if (aPropertyName == SC_UNONAME_SKIPDUP)
+ aParam.bDuplicate = !(ScUnoHelpFunctions::GetBoolFromAny( aValue ));
+ else if (aPropertyName == SC_UNONAME_USEREGEX)
+ aParam.eSearchType = ScUnoHelpFunctions::GetBoolFromAny( aValue ) ? utl::SearchParam::SearchType::Regexp :
+ utl::SearchParam::SearchType::Normal;
+
+ PutData(aParam);
+}
+
+uno::Any SAL_CALL ScFilterDescriptorBase::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ ScQueryParam aParam;
+ GetData(aParam);
+
+ uno::Any aRet;
+
+ if (aPropertyName == SC_UNONAME_CONTHDR )
+ aRet <<= aParam.bHasHeader;
+ else if (aPropertyName == SC_UNONAME_COPYOUT )
+ aRet <<= !(aParam.bInplace);
+ else if (aPropertyName == SC_UNONAME_ISCASE )
+ aRet <<= aParam.bCaseSens;
+ else if (aPropertyName == SC_UNONAME_MAXFLD )
+ aRet <<= static_cast<sal_Int32>(aParam.GetEntryCount());
+ else if (aPropertyName == SC_UNONAME_ORIENT )
+ {
+ table::TableOrientation eOrient = aParam.bByRow ? table::TableOrientation_ROWS :
+ table::TableOrientation_COLUMNS;
+ aRet <<= eOrient;
+ }
+ else if (aPropertyName == SC_UNONAME_OUTPOS )
+ {
+ table::CellAddress aOutPos;
+ aOutPos.Sheet = aParam.nDestTab;
+ aOutPos.Column = aParam.nDestCol;
+ aOutPos.Row = aParam.nDestRow;
+ aRet <<= aOutPos;
+ }
+ else if (aPropertyName == SC_UNONAME_SAVEOUT )
+ aRet <<= aParam.bDestPers;
+ else if (aPropertyName == SC_UNONAME_SKIPDUP )
+ aRet <<= !(aParam.bDuplicate);
+ else if (aPropertyName == SC_UNONAME_USEREGEX )
+ aRet <<= (aParam.eSearchType == utl::SearchParam::SearchType::Regexp);
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFilterDescriptorBase )
+
+ScFilterDescriptor::ScFilterDescriptor(ScDocShell* pDocShell)
+ :
+ ScFilterDescriptorBase(pDocShell)
+{
+}
+
+ScFilterDescriptor::~ScFilterDescriptor()
+{
+}
+
+void ScFilterDescriptor::GetData( ScQueryParam& rParam ) const
+{
+ rParam = aStoredParam; // query for interface
+}
+
+void ScFilterDescriptor::PutData( const ScQueryParam& rParam )
+{
+ aStoredParam = rParam; // set by the interface
+}
+
+void ScFilterDescriptor::SetParam( const ScQueryParam& rNew )
+{
+ aStoredParam = rNew; // set from outside
+}
+
+ScRangeFilterDescriptor::ScRangeFilterDescriptor(ScDocShell* pDocShell, ScDatabaseRangeObj* pPar) :
+ ScFilterDescriptorBase(pDocShell),
+ mxParent(pPar)
+{
+}
+
+ScRangeFilterDescriptor::~ScRangeFilterDescriptor()
+{
+}
+
+void ScRangeFilterDescriptor::GetData( ScQueryParam& rParam ) const
+{
+ if (mxParent.is())
+ mxParent->GetQueryParam( rParam );
+}
+
+void ScRangeFilterDescriptor::PutData( const ScQueryParam& rParam )
+{
+ if (mxParent.is())
+ mxParent->SetQueryParam( rParam );
+}
+
+ScDataPilotFilterDescriptor::ScDataPilotFilterDescriptor(ScDocShell* pDocShell, ScDataPilotDescriptorBase* pPar) :
+ ScFilterDescriptorBase(pDocShell),
+ mxParent(pPar)
+{
+}
+
+ScDataPilotFilterDescriptor::~ScDataPilotFilterDescriptor()
+{
+}
+
+void ScDataPilotFilterDescriptor::GetData( ScQueryParam& rParam ) const
+{
+ if (mxParent.is())
+ {
+ ScDPObject* pDPObj = mxParent->GetDPObject();
+ if (pDPObj && pDPObj->IsSheetData())
+ rParam = pDPObj->GetSheetDesc()->GetQueryParam();
+ }
+}
+
+void ScDataPilotFilterDescriptor::PutData( const ScQueryParam& rParam )
+{
+ if (!mxParent.is())
+ return;
+
+ ScDPObject* pDPObj = mxParent->GetDPObject();
+ if (pDPObj)
+ {
+ ScSheetSourceDesc aSheetDesc(&mxParent->GetDocShell()->GetDocument());
+ if (pDPObj->IsSheetData())
+ aSheetDesc = *pDPObj->GetSheetDesc();
+ aSheetDesc.SetQueryParam(rParam);
+ pDPObj->SetSheetDesc(aSheetDesc);
+ mxParent->SetDPObject(pDPObj);
+ }
+}
+
+ScDatabaseRangeObj::ScDatabaseRangeObj(ScDocShell* pDocSh, const OUString& rNm) :
+ pDocShell( pDocSh ),
+ aName( rNm ),
+ aPropSet( lcl_GetDBRangePropertyMap() ),
+ bIsUnnamed(false),
+ aTab( 0 )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDatabaseRangeObj::ScDatabaseRangeObj(ScDocShell* pDocSh, const SCTAB nTab) :
+ pDocShell( pDocSh ),
+ aName(STR_DB_LOCAL_NONAME),
+ aPropSet( lcl_GetDBRangePropertyMap() ),
+ bIsUnnamed(true),
+ aTab( nTab )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDatabaseRangeObj::~ScDatabaseRangeObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDatabaseRangeObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr;
+ else if ( auto pRefreshHint = dynamic_cast<const ScDBRangeRefreshedHint*>(&rHint) )
+ {
+ ScDBData* pDBData = GetDBData_Impl();
+ ScImportParam aParam;
+ pDBData->GetImportParam(aParam);
+ if (aParam == pRefreshHint->GetImportParam())
+ Refreshed_Impl();
+ }
+}
+
+// Help functions
+
+ScDBData* ScDatabaseRangeObj::GetDBData_Impl() const
+{
+ ScDBData* pRet = nullptr;
+ if (pDocShell)
+ {
+ if (bIsUnnamed)
+ {
+ pRet = pDocShell->GetDocument().GetAnonymousDBData(aTab);
+ }
+ else
+ {
+ ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection();
+ if (pNames)
+ {
+ ScDBData* p = pNames->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(aName));
+ if (p)
+ pRet = p;
+ }
+ }
+ }
+ return pRet;
+}
+
+// XNamed
+
+OUString SAL_CALL ScDatabaseRangeObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return aName;
+}
+
+void SAL_CALL ScDatabaseRangeObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDBDocFunc aFunc(*pDocShell);
+ bool bOk = aFunc.RenameDBRange( aName, aNewName );
+ if (bOk)
+ aName = aNewName;
+ }
+}
+
+// XDatabaseRange
+
+table::CellRangeAddress SAL_CALL ScDatabaseRangeObj::getDataArea()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aAddress;
+ ScDBData* pData = GetDBData_Impl();
+ if (pData)
+ {
+ ScRange aRange;
+ pData->GetArea(aRange);
+ aAddress.Sheet = aRange.aStart.Tab();
+ aAddress.StartColumn = aRange.aStart.Col();
+ aAddress.StartRow = aRange.aStart.Row();
+ aAddress.EndColumn = aRange.aEnd.Col();
+ aAddress.EndRow = aRange.aEnd.Row();
+ }
+ return aAddress;
+}
+
+void SAL_CALL ScDatabaseRangeObj::setDataArea( const table::CellRangeAddress& aDataArea )
+{
+ SolarMutexGuard aGuard;
+ ScDBData* pData = GetDBData_Impl();
+ if ( pDocShell && pData )
+ {
+ ScDBData aNewData( *pData );
+ //! MoveTo ???
+ aNewData.SetArea( aDataArea.Sheet, static_cast<SCCOL>(aDataArea.StartColumn), static_cast<SCROW>(aDataArea.StartRow),
+ static_cast<SCCOL>(aDataArea.EndColumn), static_cast<SCROW>(aDataArea.EndRow) );
+ ScDBDocFunc aFunc(*pDocShell);
+ aFunc.ModifyDBData(aNewData);
+ }
+}
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScDatabaseRangeObj::getSortDescriptor()
+{
+ SolarMutexGuard aGuard;
+ ScSortParam aParam;
+ const ScDBData* pData = GetDBData_Impl();
+ if (pData)
+ {
+ pData->GetSortParam(aParam);
+
+ // SortDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOLROW nFieldStart = aParam.bByRow ? static_cast<SCCOLROW>(aDBRange.aStart.Col()) : static_cast<SCCOLROW>(aDBRange.aStart.Row());
+ for (sal_uInt16 i=0; i<aParam.GetSortKeyCount(); i++)
+ if ( aParam.maKeyState[i].bDoSort && aParam.maKeyState[i].nField >= nFieldStart )
+ aParam.maKeyState[i].nField -= nFieldStart;
+ }
+
+ uno::Sequence<beans::PropertyValue> aSeq( ScSortDescriptor::GetPropertyCount() );
+ ScSortDescriptor::FillProperties( aSeq, aParam );
+ return aSeq;
+}
+
+void ScDatabaseRangeObj::GetQueryParam(ScQueryParam& rQueryParam) const
+{
+ const ScDBData* pData = GetDBData_Impl();
+ if (!pData)
+ return;
+
+ pData->GetQueryParam(rQueryParam);
+
+ // FilterDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOLROW nFieldStart = rQueryParam.bByRow ? static_cast<SCCOLROW>(aDBRange.aStart.Col()) : static_cast<SCCOLROW>(aDBRange.aStart.Row());
+ SCSIZE nCount = rQueryParam.GetEntryCount();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = rQueryParam.GetEntry(i);
+ if (rEntry.bDoQuery && rEntry.nField >= nFieldStart)
+ rEntry.nField -= nFieldStart;
+ }
+}
+
+void ScDatabaseRangeObj::SetQueryParam(const ScQueryParam& rQueryParam)
+{
+ const ScDBData* pData = GetDBData_Impl();
+ if (!pData)
+ return;
+
+ // FilterDescriptor contains the counted fields inside the area
+ ScQueryParam aParam(rQueryParam);
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOLROW nFieldStart = aParam.bByRow ? static_cast<SCCOLROW>(aDBRange.aStart.Col()) : static_cast<SCCOLROW>(aDBRange.aStart.Row());
+
+ SCSIZE nCount = aParam.GetEntryCount();
+ for (SCSIZE i=0; i<nCount; i++)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if (rEntry.bDoQuery)
+ rEntry.nField += nFieldStart;
+ }
+
+ ScDBData aNewData( *pData );
+ aNewData.SetQueryParam(aParam);
+ aNewData.SetHeader(aParam.bHasHeader); // not in ScDBData::SetQueryParam
+ ScDBDocFunc aFunc(*pDocShell);
+ aFunc.ModifyDBData(aNewData);
+}
+
+uno::Reference<sheet::XSheetFilterDescriptor> SAL_CALL ScDatabaseRangeObj::getFilterDescriptor()
+{
+ SolarMutexGuard aGuard;
+ return new ScRangeFilterDescriptor(pDocShell, this);
+}
+
+void ScDatabaseRangeObj::GetSubTotalParam(ScSubTotalParam& rSubTotalParam) const
+{
+ const ScDBData* pData = GetDBData_Impl();
+ if (!pData)
+ return;
+
+ pData->GetSubTotalParam(rSubTotalParam);
+
+ // FilterDescriptor contains the counted fields inside the area
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOL nFieldStart = aDBRange.aStart.Col();
+ for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
+ {
+ if ( rSubTotalParam.bGroupActive[i] )
+ {
+ if ( rSubTotalParam.nField[i] >= nFieldStart )
+ rSubTotalParam.nField[i] = sal::static_int_cast<SCCOL>( rSubTotalParam.nField[i] - nFieldStart );
+ for (SCCOL j=0; j<rSubTotalParam.nSubTotals[i]; j++)
+ if ( rSubTotalParam.pSubTotals[i][j] >= nFieldStart )
+ rSubTotalParam.pSubTotals[i][j] =
+ sal::static_int_cast<SCCOL>( rSubTotalParam.pSubTotals[i][j] - nFieldStart );
+ }
+ }
+}
+
+void ScDatabaseRangeObj::SetSubTotalParam(const ScSubTotalParam& rSubTotalParam)
+{
+ const ScDBData* pData = GetDBData_Impl();
+ if (!pData)
+ return;
+
+ // FilterDescriptor contains the counted fields inside the area
+ ScSubTotalParam aParam(rSubTotalParam);
+ ScRange aDBRange;
+ pData->GetArea(aDBRange);
+ SCCOL nFieldStart = aDBRange.aStart.Col();
+ for (sal_uInt16 i=0; i<MAXSUBTOTAL; i++)
+ {
+ if ( aParam.bGroupActive[i] )
+ {
+ aParam.nField[i] = sal::static_int_cast<SCCOL>( aParam.nField[i] + nFieldStart );
+ for (SCCOL j=0; j<aParam.nSubTotals[i]; j++)
+ aParam.pSubTotals[i][j] = sal::static_int_cast<SCCOL>( aParam.pSubTotals[i][j] + nFieldStart );
+ }
+ }
+
+ ScDBData aNewData( *pData );
+ aNewData.SetSubTotalParam(aParam);
+ ScDBDocFunc aFunc(*pDocShell);
+ aFunc.ModifyDBData(aNewData);
+}
+
+uno::Reference<sheet::XSubTotalDescriptor> SAL_CALL ScDatabaseRangeObj::getSubTotalDescriptor()
+{
+ SolarMutexGuard aGuard;
+ return new ScRangeSubTotalDescriptor(this);
+}
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScDatabaseRangeObj::getImportDescriptor()
+{
+ SolarMutexGuard aGuard;
+ ScImportParam aParam;
+ const ScDBData* pData = GetDBData_Impl();
+ if (pData)
+ pData->GetImportParam(aParam);
+
+ uno::Sequence<beans::PropertyValue> aSeq( ScImportDescriptor::GetPropertyCount() );
+ ScImportDescriptor::FillProperties( aSeq, aParam );
+ return aSeq;
+}
+
+// XRefreshable
+
+void SAL_CALL ScDatabaseRangeObj::refresh()
+{
+ SolarMutexGuard aGuard;
+ ScDBData* pData = GetDBData_Impl();
+ if ( !(pDocShell && pData) )
+ return;
+
+ ScDBDocFunc aFunc(*pDocShell);
+
+ // repeat import?
+ bool bContinue = true;
+ ScImportParam aImportParam;
+ pData->GetImportParam( aImportParam );
+ if (aImportParam.bImport && !pData->HasImportSelection())
+ {
+ SCTAB nTab;
+ SCCOL nDummyCol;
+ SCROW nDummyRow;
+ pData->GetArea( nTab, nDummyCol,nDummyRow,nDummyCol,nDummyRow );
+ bContinue = aFunc.DoImport( nTab, aImportParam, nullptr ); //! Api-Flag as parameter
+ }
+
+ // if no error then internal operations (sort, query, subtotal)
+ if (bContinue)
+ aFunc.RepeatDB( pData->GetName(), true, bIsUnnamed, aTab );
+}
+
+void SAL_CALL ScDatabaseRangeObj::addRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRefreshListeners.emplace_back( xListener );
+
+ // hold one additional ref to keep this object alive as long as there are listeners
+ if ( aRefreshListeners.size() == 1 )
+ acquire();
+}
+
+void SAL_CALL ScDatabaseRangeObj::removeRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = aRefreshListeners.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ {
+ uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n];
+ if ( rObj == xListener )
+ {
+ aRefreshListeners.erase( aRefreshListeners.begin() + n );
+ if ( aRefreshListeners.empty() )
+ release(); // release ref for listeners
+ break;
+ }
+ }
+}
+
+void ScDatabaseRangeObj::Refreshed_Impl()
+{
+ lang::EventObject aEvent;
+ aEvent.Source = static_cast<cppu::OWeakObject*>(this);
+ for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners)
+ xRefreshListener->refreshed( aEvent );
+}
+
+// XCellRangeSource
+
+uno::Reference<table::XCellRange> SAL_CALL ScDatabaseRangeObj::getReferredCells()
+{
+ SolarMutexGuard aGuard;
+ ScDBData* pData = GetDBData_Impl();
+ if ( pData )
+ {
+ //! static function to create ScCellObj/ScCellRange on ScCellRangeObj ???
+ ScRange aRange;
+
+ pData->GetArea(aRange);
+ if ( aRange.aStart == aRange.aEnd )
+ return new ScCellObj( pDocShell, aRange.aStart );
+ else
+ return new ScCellRangeObj( pDocShell, aRange );
+ }
+ return nullptr;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDatabaseRangeObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScDatabaseRangeObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ ScDBData* pData = GetDBData_Impl();
+ if ( !(pDocShell && pData) )
+ return;
+
+ ScDBData aNewData( *pData );
+ bool bDo = true;
+
+ if ( aPropertyName == SC_UNONAME_KEEPFORM )
+ aNewData.SetKeepFmt( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNONAME_MOVCELLS )
+ aNewData.SetDoSize( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNONAME_STRIPDAT )
+ aNewData.SetStripData( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNONAME_AUTOFLT )
+ {
+ bool bAutoFilter(ScUnoHelpFunctions::GetBoolFromAny( aValue ));
+ aNewData.SetAutoFilter(bAutoFilter);
+ ScRange aRange;
+ aNewData.GetArea(aRange);
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (bAutoFilter)
+ rDoc.ApplyFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab(), ScMF::Auto );
+ else if (!bAutoFilter)
+ rDoc.RemoveFlagsTab(aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab(), ScMF::Auto );
+ ScRange aPaintRange(aRange.aStart, aRange.aEnd);
+ aPaintRange.aEnd.SetRow(aPaintRange.aStart.Row());
+ pDocShell->PostPaint(aPaintRange, PaintPartFlags::Grid);
+ }
+ else if (aPropertyName == SC_UNONAME_USEFLTCRT )
+ {
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ {
+ // only here to set bIsAdvanced in ScDBData
+ ScRange aRange;
+ (void)aNewData.GetAdvancedQuerySource(aRange);
+ aNewData.SetAdvancedQuerySource(&aRange);
+ }
+ else
+ aNewData.SetAdvancedQuerySource(nullptr);
+ }
+ else if (aPropertyName == SC_UNONAME_FLTCRT )
+ {
+ table::CellRangeAddress aRange;
+ if (aValue >>= aRange)
+ {
+ ScRange aCoreRange;
+ ScUnoConversion::FillScRange(aCoreRange, aRange);
+
+ aNewData.SetAdvancedQuerySource(&aCoreRange);
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_FROMSELECT )
+ {
+ aNewData.SetImportSelection(::cppu::any2bool(aValue));
+ }
+ else if (aPropertyName == SC_UNONAME_REFPERIOD )
+ {
+ sal_Int32 nRefresh = 0;
+ if (aValue >>= nRefresh)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ aNewData.SetRefreshDelay(nRefresh);
+ if (rDoc.GetDBCollection())
+ {
+ aNewData.SetRefreshHandler( rDoc.GetDBCollection()->GetRefreshHandler() );
+ aNewData.SetRefreshControl( &rDoc.GetRefreshTimerControlAddress() );
+ }
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_CONRES )
+ {
+ }
+ else if ( aPropertyName == SC_UNONAME_TOTALSROW )
+ aNewData.SetTotals( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNONAME_CONTHDR )
+ aNewData.SetHeader( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else
+ bDo = false;
+
+ if (bDo)
+ {
+ ScDBDocFunc aFunc(*pDocShell);
+ aFunc.ModifyDBData(aNewData);
+ }
+}
+
+uno::Any SAL_CALL ScDatabaseRangeObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ ScDBData* pData = GetDBData_Impl();
+ if ( pData )
+ {
+ if ( aPropertyName == SC_UNONAME_KEEPFORM )
+ aRet <<= pData->IsKeepFmt();
+ else if ( aPropertyName == SC_UNONAME_MOVCELLS )
+ aRet <<= pData->IsDoSize();
+ else if ( aPropertyName == SC_UNONAME_STRIPDAT )
+ aRet <<= pData->IsStripData();
+ else if ( aPropertyName == SC_UNONAME_ISUSER )
+ {
+ // all database ranges except "unnamed" are user defined
+ aRet <<= (pData->GetName() != STR_DB_LOCAL_NONAME);
+ }
+ else if ( aPropertyName == SC_UNO_LINKDISPBIT )
+ {
+ // no target bitmaps for individual entries (would be all equal)
+ // ScLinkTargetTypeObj::SetLinkTargetBitmap( aRet, SC_LINKTARGETTYPE_DBAREA );
+ }
+ else if ( aPropertyName == SC_UNO_LINKDISPNAME )
+ aRet <<= aName;
+ else if (aPropertyName == SC_UNONAME_AUTOFLT )
+ {
+ bool bAutoFilter(GetDBData_Impl()->HasAutoFilter());
+
+ aRet <<= bAutoFilter;
+ }
+ else if (aPropertyName == SC_UNONAME_USEFLTCRT )
+ {
+ ScRange aRange;
+ bool bIsAdvancedSource(GetDBData_Impl()->GetAdvancedQuerySource(aRange));
+
+ aRet <<= bIsAdvancedSource;
+ }
+ else if (aPropertyName == SC_UNONAME_FLTCRT )
+ {
+ table::CellRangeAddress aRange;
+ ScRange aCoreRange;
+ if (GetDBData_Impl()->GetAdvancedQuerySource(aCoreRange))
+ ScUnoConversion::FillApiRange(aRange, aCoreRange);
+
+ aRet <<= aRange;
+ }
+ else if (aPropertyName == SC_UNONAME_FROMSELECT )
+ {
+ aRet <<= GetDBData_Impl()->HasImportSelection();
+ }
+ else if (aPropertyName == SC_UNONAME_REFPERIOD )
+ {
+ sal_Int32 nRefresh(GetDBData_Impl()->GetRefreshDelaySeconds());
+ aRet <<= nRefresh;
+ }
+ else if (aPropertyName == SC_UNONAME_CONRES )
+ {
+ }
+ else if (aPropertyName == SC_UNONAME_TOKENINDEX )
+ {
+ // get index for use in formula tokens (read-only)
+ aRet <<= static_cast<sal_Int32>(GetDBData_Impl()->GetIndex());
+ }
+ else if (aPropertyName == SC_UNONAME_TOTALSROW )
+ {
+ bool bTotals(GetDBData_Impl()->HasTotals());
+
+ aRet <<= bTotals;
+ }
+ else if (aPropertyName == SC_UNONAME_CONTHDR )
+ {
+ bool bHeader(GetDBData_Impl()->HasHeader());
+
+ aRet <<= bHeader;
+ }
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDatabaseRangeObj )
+
+// XServiceInfo
+OUString SAL_CALL ScDatabaseRangeObj::getImplementationName()
+{
+ return "ScDatabaseRangeObj";
+}
+
+sal_Bool SAL_CALL ScDatabaseRangeObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScDatabaseRangeObj::getSupportedServiceNames()
+{
+ return {"com.sun.star.sheet.DatabaseRange",
+ SCLINKTARGET_SERVICE};
+}
+
+ScDatabaseRangesObj::ScDatabaseRangesObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDatabaseRangesObj::~ScDatabaseRangesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDatabaseRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XDatabaseRanges
+
+rtl::Reference<ScDatabaseRangeObj> ScDatabaseRangesObj::GetObjectByIndex_Impl(size_t nIndex)
+{
+ if (!pDocShell)
+ return nullptr;
+
+ ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection();
+ if (!pNames)
+ return nullptr;
+
+ const ScDBCollection::NamedDBs& rDBs = pNames->getNamedDBs();
+ if (rDBs.empty() || nIndex >= rDBs.size())
+ return nullptr;
+
+ ScDBCollection::NamedDBs::const_iterator itr = rDBs.begin();
+ ::std::advance(itr, nIndex); // boundary check is done above.
+ return new ScDatabaseRangeObj(pDocShell, (*itr)->GetName());
+}
+
+rtl::Reference<ScDatabaseRangeObj> ScDatabaseRangesObj::GetObjectByName_Impl(const OUString& aName)
+{
+ if ( pDocShell && hasByName(aName) )
+ {
+ return new ScDatabaseRangeObj( pDocShell, aName );
+ }
+ return nullptr;
+}
+
+void SAL_CALL ScDatabaseRangesObj::addNewByName( const OUString& aName,
+ const table::CellRangeAddress& aRange )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ ScDBDocFunc aFunc(*pDocShell);
+
+ ScRange aNameRange( static_cast<SCCOL>(aRange.StartColumn), static_cast<SCROW>(aRange.StartRow), aRange.Sheet,
+ static_cast<SCCOL>(aRange.EndColumn), static_cast<SCROW>(aRange.EndRow), aRange.Sheet );
+ bDone = aFunc.AddDBRange( aName, aNameRange );
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScDatabaseRangesObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ ScDBDocFunc aFunc(*pDocShell);
+ bDone = aFunc.DeleteDBRange( aName );
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScDatabaseRangesObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.DatabaseRangesEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDatabaseRangesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ //! need to omit "unnamed"?
+
+ if (pDocShell)
+ {
+ ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection();
+ if (pNames)
+ return static_cast<sal_Int32>(pNames->getNamedDBs().size());
+ }
+ return 0;
+}
+
+uno::Any SAL_CALL ScDatabaseRangesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ if (nIndex < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Reference<sheet::XDatabaseRange> xRange(GetObjectByIndex_Impl(static_cast<size_t>(nIndex)));
+ if (!xRange.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRange);
+}
+
+uno::Type SAL_CALL ScDatabaseRangesObj::getElementType()
+{
+ return cppu::UnoType<sheet::XDatabaseRange>::get();
+}
+
+sal_Bool SAL_CALL ScDatabaseRangesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XNameAccess
+
+uno::Any SAL_CALL ScDatabaseRangesObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XDatabaseRange> xRange(GetObjectByName_Impl(aName));
+ if (!xRange.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xRange);
+}
+
+uno::Sequence<OUString> SAL_CALL ScDatabaseRangesObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ //! need to omit "unnamed"?
+
+ if (pDocShell)
+ {
+ ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection();
+ if (pNames)
+ {
+ const ScDBCollection::NamedDBs& rDBs = pNames->getNamedDBs();
+ uno::Sequence<OUString> aSeq(rDBs.size());
+ auto aSeqRange = asNonConstRange(aSeq);
+ size_t i = 0;
+ for (const auto& rDB : rDBs)
+ {
+ aSeqRange[i] = rDB->GetName();
+ ++i;
+ }
+
+ return aSeq;
+ }
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScDatabaseRangesObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ //! need to omit "unnamed"?
+
+ if (pDocShell)
+ {
+ ScDBCollection* pNames = pDocShell->GetDocument().GetDBCollection();
+ if (pNames)
+ return pNames->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(aName)) != nullptr;
+ }
+ return false;
+}
+
+ScUnnamedDatabaseRangesObj::ScUnnamedDatabaseRangesObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScUnnamedDatabaseRangesObj::~ScUnnamedDatabaseRangesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScUnnamedDatabaseRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XUnnamedDatabaseRanges
+
+void ScUnnamedDatabaseRangesObj::setByTable( const table::CellRangeAddress& aRange )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ if ( pDocShell->GetDocument().GetTableCount() <= aRange.Sheet )
+ throw lang::IndexOutOfBoundsException();
+
+ ScDBDocFunc aFunc(*pDocShell);
+ ScRange aUnnamedRange( static_cast<SCCOL>(aRange.StartColumn), static_cast<SCROW>(aRange.StartRow), aRange.Sheet,
+ static_cast<SCCOL>(aRange.EndColumn), static_cast<SCROW>(aRange.EndRow), aRange.Sheet );
+ bDone = aFunc.AddDBRange( STR_DB_LOCAL_NONAME, aUnnamedRange );
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+uno::Any ScUnnamedDatabaseRangesObj::getByTable( sal_Int32 nTab )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ throw uno::RuntimeException();
+
+ if ( pDocShell->GetDocument().GetTableCount() <= nTab )
+ throw lang::IndexOutOfBoundsException();
+ uno::Reference<sheet::XDatabaseRange> xRange(
+ new ScDatabaseRangeObj(pDocShell, static_cast<SCTAB>(nTab)));
+ if (!xRange.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xRange);
+}
+
+sal_Bool ScUnnamedDatabaseRangesObj::hasByTable( sal_Int32 nTab )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ if (pDocShell->GetDocument().GetTableCount() <= nTab)
+ throw lang::IndexOutOfBoundsException();
+ if (pDocShell->GetDocument().GetAnonymousDBData(static_cast<SCTAB>(nTab)))
+ return true;
+ return false;
+ }
+ else
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/defltuno.cxx b/sc/source/ui/unoobj/defltuno.cxx
new file mode 100644
index 000000000..e19324cc3
--- /dev/null
+++ b/sc/source/ui/unoobj/defltuno.cxx
@@ -0,0 +1,335 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <editeng/memberids.h>
+#include <svl/hint.hxx>
+#include <svl/itemprop.hxx>
+#include <vcl/svapp.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+#include <scitems.hxx>
+#include <defltuno.hxx>
+#include <miscuno.hxx>
+#include <docsh.hxx>
+#include <docpool.hxx>
+#include <unonames.hxx>
+#include <docoptio.hxx>
+
+#include <limits>
+
+class SvxFontItem;
+using namespace ::com::sun::star;
+
+static const SfxItemPropertyMapEntry* lcl_GetDocDefaultsMap()
+{
+ static const SfxItemPropertyMapEntry aDocDefaultsMap_Impl[] =
+ {
+ { SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ { SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ { SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ { SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ { SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ { SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE, cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ { SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT, cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ { SC_UNO_STANDARDDEC, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNO_TABSTOPDIS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aDocDefaultsMap_Impl;
+}
+
+using sc::TwipsToEvenHMM;
+
+SC_SIMPLE_SERVICE_INFO( ScDocDefaultsObj, "ScDocDefaultsObj", "com.sun.star.sheet.Defaults" )
+
+ScDocDefaultsObj::ScDocDefaultsObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh ),
+ aPropertyMap(lcl_GetDocDefaultsMap())
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDocDefaultsObj::~ScDocDefaultsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDocDefaultsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // document gone
+ }
+}
+
+void ScDocDefaultsObj::ItemsChanged()
+{
+ if (pDocShell)
+ {
+ //! if not in XML import, adjust row heights
+ const auto & rDoc = pDocShell->GetDocument();
+ pDocShell->PostPaint(ScRange(0, 0, 0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB), PaintPartFlags::Grid);
+ }
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScDocDefaultsObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef = new SfxItemPropertySetInfo(
+ aPropertyMap );
+ return aRef;
+}
+
+void SAL_CALL ScDocDefaultsObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMapEntry* pEntry = aPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+ if(!pEntry->nWID)
+ {
+ if(aPropertyName ==SC_UNO_STANDARDDEC)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDocOptions aDocOpt(rDoc.GetDocOptions());
+ sal_Int16 nValue = 0;
+ if (aValue >>= nValue)
+ {
+ aDocOpt.SetStdPrecision(static_cast<sal_uInt16> (nValue));
+ rDoc.SetDocOptions(aDocOpt);
+ }
+ }
+ else if (aPropertyName == SC_UNO_TABSTOPDIS)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDocOptions aDocOpt(rDoc.GetDocOptions());
+ sal_Int32 nValue = 0;
+ if (aValue >>= nValue)
+ {
+ aDocOpt.SetTabDistance(o3tl::toTwips(nValue, o3tl::Length::mm100));
+ rDoc.SetDocOptions(aDocOpt);
+ }
+ }
+ }
+ else if ( pEntry->nWID == ATTR_FONT_LANGUAGE ||
+ pEntry->nWID == ATTR_CJK_FONT_LANGUAGE ||
+ pEntry->nWID == ATTR_CTL_FONT_LANGUAGE )
+ {
+ // for getPropertyValue the PoolDefaults are sufficient,
+ // but setPropertyValue has to be handled differently
+
+ lang::Locale aLocale;
+ if ( aValue >>= aLocale )
+ {
+ LanguageType eNew;
+ if (!aLocale.Language.isEmpty() || !aLocale.Country.isEmpty())
+ eNew = LanguageTag::convertToLanguageType( aLocale, false);
+ else
+ eNew = LANGUAGE_NONE;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+
+ if ( pEntry->nWID == ATTR_CJK_FONT_LANGUAGE )
+ eCjk = eNew;
+ else if ( pEntry->nWID == ATTR_CTL_FONT_LANGUAGE )
+ eCtl = eNew;
+ else
+ eLatin = eNew;
+
+ rDoc.SetLanguage( eLatin, eCjk, eCtl );
+ }
+ }
+ else
+ {
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ std::unique_ptr<SfxPoolItem> pNewItem(pPool->GetDefaultItem(pEntry->nWID).Clone());
+
+ if( !pNewItem->PutValue( aValue, pEntry->nMemberId ) )
+ throw lang::IllegalArgumentException();
+
+ pPool->SetPoolDefaultItem( *pNewItem );
+
+ ItemsChanged();
+ }
+}
+
+uno::Any SAL_CALL ScDocDefaultsObj::getPropertyValue( const OUString& aPropertyName )
+{
+ // use pool default if set
+
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ uno::Any aRet;
+ const SfxItemPropertyMapEntry* pEntry = aPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ if (!pEntry->nWID)
+ {
+ if(aPropertyName == SC_UNO_STANDARDDEC)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScDocOptions& aDocOpt = rDoc.GetDocOptions();
+ sal_uInt16 nPrec = aDocOpt.GetStdPrecision();
+ // the max value of unsigned 16-bit integer is used as the flag
+ // value for unlimited precision, c.f.
+ // SvNumberFormatter::UNLIMITED_PRECISION.
+ if (nPrec <= ::std::numeric_limits<sal_Int16>::max())
+ aRet <<= static_cast<sal_Int16> (nPrec);
+ }
+ else if (aPropertyName == SC_UNO_TABSTOPDIS)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScDocOptions& aDocOpt = rDoc.GetDocOptions();
+ sal_Int32 nValue (TwipsToEvenHMM(aDocOpt.GetTabDistance()));
+ aRet <<= nValue;
+ }
+ }
+ else
+ {
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ const SfxPoolItem& rItem = pPool->GetDefaultItem( pEntry->nWID );
+ rItem.QueryValue( aRet, pEntry->nMemberId );
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScDocDefaultsObj )
+
+// XPropertyState
+
+beans::PropertyState SAL_CALL ScDocDefaultsObj::getPropertyState( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMapEntry* pEntry = aPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ beans::PropertyState eRet = beans::PropertyState_DEFAULT_VALUE;
+
+ sal_uInt16 nWID = pEntry->nWID;
+ if ( nWID == ATTR_FONT || nWID == ATTR_CJK_FONT || nWID == ATTR_CTL_FONT || !nWID )
+ {
+ // static default for font is system-dependent,
+ // so font default is always treated as "direct value".
+
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ }
+ else
+ {
+ // check if pool default is set
+
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ if ( pPool->GetPoolDefaultItem( nWID ) != nullptr )
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ }
+
+ return eRet;
+}
+
+uno::Sequence<beans::PropertyState> SAL_CALL ScDocDefaultsObj::getPropertyStates(
+ const uno::Sequence<OUString>& aPropertyNames )
+{
+ // the simple way: call getPropertyState
+
+ SolarMutexGuard aGuard;
+ uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength());
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.getArray(),
+ [this](const OUString& rName) -> beans::PropertyState { return getPropertyState(rName); });
+ return aRet;
+}
+
+void SAL_CALL ScDocDefaultsObj::setPropertyToDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMapEntry* pEntry = aPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ if (pEntry->nWID)
+ {
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ pPool->ResetPoolDefaultItem( pEntry->nWID );
+
+ ItemsChanged();
+ }
+}
+
+uno::Any SAL_CALL ScDocDefaultsObj::getPropertyDefault( const OUString& aPropertyName )
+{
+ // always use static default
+
+ SolarMutexGuard aGuard;
+
+ if ( !pDocShell )
+ throw uno::RuntimeException();
+
+ const SfxItemPropertyMapEntry* pEntry = aPropertyMap.getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ uno::Any aRet;
+ if (pEntry->nWID)
+ {
+ ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
+ const SfxPoolItem* pItem = pPool->GetItem2Default( pEntry->nWID );
+ if (pItem)
+ pItem->QueryValue( aRet, pEntry->nMemberId );
+ }
+ return aRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/dispuno.cxx b/sc/source/ui/unoobj/dispuno.cxx
new file mode 100644
index 000000000..93ea182a0
--- /dev/null
+++ b/sc/source/ui/unoobj/dispuno.cxx
@@ -0,0 +1,369 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/viewfrm.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <svl/hint.hxx>
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/frame/XDispatchProviderInterception.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+
+#include <dispuno.hxx>
+#include <tabvwsh.hxx>
+#include <dbdocfun.hxx>
+#include <dbdata.hxx>
+
+using namespace com::sun::star;
+
+const char cURLInsertColumns[] = ".uno:DataSourceBrowser/InsertColumns"; //data into text
+constexpr OUStringLiteral cURLDocDataSource = u".uno:DataSourceBrowser/DocumentDataSource";
+
+static uno::Reference<view::XSelectionSupplier> lcl_GetSelectionSupplier( const SfxViewShell* pViewShell )
+{
+ if ( pViewShell )
+ {
+ SfxViewFrame* pViewFrame = pViewShell->GetViewFrame();
+ if (pViewFrame)
+ {
+ return uno::Reference<view::XSelectionSupplier>( pViewFrame->GetFrame().GetController(), uno::UNO_QUERY );
+ }
+ }
+ return uno::Reference<view::XSelectionSupplier>();
+}
+
+ScDispatchProviderInterceptor::ScDispatchProviderInterceptor(ScTabViewShell* pViewSh) :
+ pViewShell( pViewSh )
+{
+ if ( !pViewShell )
+ return;
+
+ m_xIntercepted.set(uno::Reference<frame::XDispatchProviderInterception>(pViewShell->GetViewFrame()->GetFrame().GetFrameInterface(), uno::UNO_QUERY));
+ if (m_xIntercepted.is())
+ {
+ osl_atomic_increment( &m_refCount );
+
+ m_xIntercepted->registerDispatchProviderInterceptor(
+ static_cast<frame::XDispatchProviderInterceptor*>(this));
+ // this should make us the top-level dispatch-provider for the component, via a call to our
+ // setDispatchProvider we should have got a fallback for requests we (i.e. our master) cannot fulfill
+ uno::Reference<lang::XComponent> xInterceptedComponent(m_xIntercepted, uno::UNO_QUERY);
+ if (xInterceptedComponent.is())
+ xInterceptedComponent->addEventListener(static_cast<lang::XEventListener*>(this));
+
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ StartListening(*pViewShell);
+}
+
+ScDispatchProviderInterceptor::~ScDispatchProviderInterceptor()
+{
+ if (pViewShell)
+ EndListening(*pViewShell);
+}
+
+void ScDispatchProviderInterceptor::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pViewShell = nullptr;
+}
+
+// XDispatchProvider
+
+uno::Reference<frame::XDispatch> SAL_CALL ScDispatchProviderInterceptor::queryDispatch(
+ const util::URL& aURL, const OUString& aTargetFrameName,
+ sal_Int32 nSearchFlags )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<frame::XDispatch> xResult;
+ // create some dispatch ...
+ if ( pViewShell && (
+ aURL.Complete == cURLInsertColumns ||
+ aURL.Complete == cURLDocDataSource ) )
+ {
+ if (!m_xMyDispatch.is())
+ m_xMyDispatch = new ScDispatch( pViewShell );
+ xResult = m_xMyDispatch;
+ }
+
+ // ask our slave provider
+ if (!xResult.is() && m_xSlaveDispatcher.is())
+ xResult = m_xSlaveDispatcher->queryDispatch(aURL, aTargetFrameName, nSearchFlags);
+
+ return xResult;
+}
+
+uno::Sequence< uno::Reference<frame::XDispatch> > SAL_CALL
+ ScDispatchProviderInterceptor::queryDispatches(
+ const uno::Sequence<frame::DispatchDescriptor>& aDescripts )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Sequence< uno::Reference< frame::XDispatch> > aReturn(aDescripts.getLength());
+ std::transform(aDescripts.begin(), aDescripts.end(), aReturn.getArray(),
+ [this](const frame::DispatchDescriptor& rDescr) -> uno::Reference<frame::XDispatch> {
+ return queryDispatch(rDescr.FeatureURL, rDescr.FrameName, rDescr.SearchFlags); });
+ return aReturn;
+}
+
+// XDispatchProviderInterceptor
+
+uno::Reference<frame::XDispatchProvider> SAL_CALL
+ ScDispatchProviderInterceptor::getSlaveDispatchProvider()
+{
+ SolarMutexGuard aGuard;
+ return m_xSlaveDispatcher;
+}
+
+void SAL_CALL ScDispatchProviderInterceptor::setSlaveDispatchProvider(
+ const uno::Reference<frame::XDispatchProvider>& xNewDispatchProvider )
+{
+ SolarMutexGuard aGuard;
+ m_xSlaveDispatcher.set(xNewDispatchProvider);
+}
+
+uno::Reference<frame::XDispatchProvider> SAL_CALL
+ ScDispatchProviderInterceptor::getMasterDispatchProvider()
+{
+ SolarMutexGuard aGuard;
+ return m_xMasterDispatcher;
+}
+
+void SAL_CALL ScDispatchProviderInterceptor::setMasterDispatchProvider(
+ const uno::Reference<frame::XDispatchProvider>& xNewSupplier )
+{
+ SolarMutexGuard aGuard;
+ m_xMasterDispatcher.set(xNewSupplier);
+}
+
+// XEventListener
+
+void SAL_CALL ScDispatchProviderInterceptor::disposing( const lang::EventObject& /* Source */ )
+{
+ SolarMutexGuard aGuard;
+
+ if (m_xIntercepted.is())
+ {
+ m_xIntercepted->releaseDispatchProviderInterceptor(
+ static_cast<frame::XDispatchProviderInterceptor*>(this));
+ uno::Reference<lang::XComponent> xInterceptedComponent(m_xIntercepted, uno::UNO_QUERY);
+ if (xInterceptedComponent.is())
+ xInterceptedComponent->removeEventListener(static_cast<lang::XEventListener*>(this));
+
+ m_xMyDispatch = nullptr;
+ }
+ m_xIntercepted = nullptr;
+}
+
+ScDispatch::ScDispatch(ScTabViewShell* pViewSh) :
+ pViewShell( pViewSh ),
+ bListeningToView( false )
+{
+ if (pViewShell)
+ StartListening(*pViewShell);
+}
+
+ScDispatch::~ScDispatch()
+{
+ if (pViewShell)
+ EndListening(*pViewShell);
+
+ if (bListeningToView && pViewShell)
+ {
+ uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell ));
+ if ( xSupplier.is() )
+ xSupplier->removeSelectionChangeListener(this);
+ }
+}
+
+void ScDispatch::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pViewShell = nullptr;
+}
+
+// XDispatch
+
+void SAL_CALL ScDispatch::dispatch( const util::URL& aURL,
+ const uno::Sequence<beans::PropertyValue>& aArgs )
+{
+ SolarMutexGuard aGuard;
+
+ bool bDone = false;
+ if ( pViewShell && aURL.Complete == cURLInsertColumns )
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScAddress aPos( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
+
+ ScDBDocFunc aFunc( *rViewData.GetDocShell() );
+ aFunc.DoImportUno( aPos, aArgs );
+ bDone = true;
+ }
+ // cURLDocDataSource is never dispatched
+
+ if (!bDone)
+ throw uno::RuntimeException();
+}
+
+static void lcl_FillDataSource( frame::FeatureStateEvent& rEvent, const ScImportParam& rParam )
+{
+ rEvent.IsEnabled = rParam.bImport;
+
+ svx::ODataAccessDescriptor aDescriptor;
+ if ( rParam.bImport )
+ {
+ sal_Int32 nType = rParam.bSql ? sdb::CommandType::COMMAND :
+ ( (rParam.nType == ScDbQuery) ? sdb::CommandType::QUERY :
+ sdb::CommandType::TABLE );
+
+ aDescriptor.setDataSource(rParam.aDBName);
+ aDescriptor[svx::DataAccessDescriptorProperty::Command] <<= rParam.aStatement;
+ aDescriptor[svx::DataAccessDescriptorProperty::CommandType] <<= nType;
+ }
+ else
+ {
+ // descriptor has to be complete anyway
+
+ aDescriptor[svx::DataAccessDescriptorProperty::DataSource] <<= OUString();
+ aDescriptor[svx::DataAccessDescriptorProperty::Command] <<= OUString();
+ aDescriptor[svx::DataAccessDescriptorProperty::CommandType] <<= sal_Int32(sdb::CommandType::TABLE);
+ }
+ rEvent.State <<= aDescriptor.createPropertyValueSequence();
+}
+
+void SAL_CALL ScDispatch::addStatusListener(
+ const uno::Reference<frame::XStatusListener>& xListener,
+ const util::URL& aURL)
+{
+ SolarMutexGuard aGuard;
+
+ if (!pViewShell)
+ throw uno::RuntimeException();
+
+ // initial state
+ frame::FeatureStateEvent aEvent;
+ aEvent.IsEnabled = true;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ aEvent.FeatureURL = aURL;
+
+ if ( aURL.Complete == cURLDocDataSource )
+ {
+ aDataSourceListeners.emplace_back( xListener );
+
+ if (!bListeningToView)
+ {
+ uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell ));
+ if ( xSupplier.is() )
+ xSupplier->addSelectionChangeListener(this);
+ bListeningToView = true;
+ }
+
+ ScDBData* pDBData = pViewShell->GetDBData(false,SC_DB_OLD);
+ if ( pDBData )
+ pDBData->GetImportParam( aLastImport );
+ lcl_FillDataSource( aEvent, aLastImport ); // modifies State, IsEnabled
+ }
+ //! else add to listener for "enabled" changes?
+
+ xListener->statusChanged( aEvent );
+}
+
+void SAL_CALL ScDispatch::removeStatusListener(
+ const uno::Reference<frame::XStatusListener>& xListener,
+ const util::URL& aURL )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aURL.Complete != cURLDocDataSource )
+ return;
+
+ sal_uInt16 nCount = aDataSourceListeners.size();
+ for ( sal_uInt16 n=nCount; n--; )
+ {
+ uno::Reference<frame::XStatusListener>& rObj = aDataSourceListeners[n];
+ if ( rObj == xListener )
+ {
+ aDataSourceListeners.erase( aDataSourceListeners.begin() + n );
+ break;
+ }
+ }
+
+ if ( aDataSourceListeners.empty() && pViewShell )
+ {
+ uno::Reference<view::XSelectionSupplier> xSupplier(lcl_GetSelectionSupplier( pViewShell ));
+ if ( xSupplier.is() )
+ xSupplier->removeSelectionChangeListener(this);
+ bListeningToView = false;
+ }
+}
+
+// XSelectionChangeListener
+
+void SAL_CALL ScDispatch::selectionChanged( const css::lang::EventObject& /* aEvent */ )
+{
+ // currently only called for URL cURLDocDataSource
+
+ if ( !pViewShell )
+ return;
+
+ ScImportParam aNewImport;
+ ScDBData* pDBData = pViewShell->GetDBData(false,SC_DB_OLD);
+ if ( pDBData )
+ pDBData->GetImportParam( aNewImport );
+
+ // notify listeners only if data source has changed
+ if ( !(aNewImport.bImport != aLastImport.bImport ||
+ aNewImport.aDBName != aLastImport.aDBName ||
+ aNewImport.aStatement != aLastImport.aStatement ||
+ aNewImport.bSql != aLastImport.bSql ||
+ aNewImport.nType != aLastImport.nType) )
+ return;
+
+ frame::FeatureStateEvent aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ aEvent.FeatureURL.Complete = cURLDocDataSource;
+
+ lcl_FillDataSource( aEvent, aNewImport ); // modifies State, IsEnabled
+
+ for (uno::Reference<frame::XStatusListener> & xDataSourceListener : aDataSourceListeners)
+ xDataSourceListener->statusChanged( aEvent );
+
+ aLastImport = aNewImport;
+}
+
+// XEventListener
+
+void SAL_CALL ScDispatch::disposing( const css::lang::EventObject& rSource )
+{
+ uno::Reference<view::XSelectionSupplier> xSupplier(rSource.Source, uno::UNO_QUERY);
+ xSupplier->removeSelectionChangeListener(this);
+ bListeningToView = false;
+
+ lang::EventObject aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ for (uno::Reference<frame::XStatusListener> & xDataSourceListener : aDataSourceListeners)
+ xDataSourceListener->disposing( aEvent );
+
+ pViewShell = nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/docuno.cxx b/sc/source/ui/unoobj/docuno.cxx
new file mode 100644
index 000000000..caae533a3
--- /dev/null
+++ b/sc/source/ui/unoobj/docuno.cxx
@@ -0,0 +1,4866 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_feature_opencl.h>
+
+#include <scitems.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/memberids.h>
+#include <editeng/outliner.hxx>
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <svx/fmview.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svxids.hrc>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/propertysequence.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <officecfg/Office/Calc.hxx>
+#include <svl/numuno.hxx>
+#include <svl/hint.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/unopage.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
+#include <vcl/print.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/json_writer.hxx>
+#include <tools/multisel.hxx>
+#include <tools/UnitConversion.hxx>
+#include <toolkit/awt/vclxdevice.hxx>
+
+#include <float.h>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/util/Date.hpp>
+#include <com/sun/star/sheet/XNamedRanges.hpp>
+#include <com/sun/star/sheet/XLabelRanges.hpp>
+#include <com/sun/star/sheet/XSelectedSheetsSupplier.hpp>
+#include <com/sun/star/sheet/XUnnamedDatabaseRanges.hpp>
+#include <com/sun/star/i18n/XForbiddenCharacters.hpp>
+#include <com/sun/star/script/XLibraryContainer.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <com/sun/star/script/XInvocation.hpp>
+#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
+#include <com/sun/star/beans/XFastPropertySet.hpp>
+#include <comphelper/indexedpropertyvalues.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/profilezone.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/string.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#if HAVE_FEATURE_OPENCL
+#include <opencl/platforminfo.hxx>
+#endif
+#include <sfx2/lokhelper.hxx>
+#include <sfx2/lokcomponenthelpers.hxx>
+#include <sfx2/LokControlHandler.hxx>
+
+#include <cellsuno.hxx>
+#include <columnspanset.hxx>
+#include <convuno.hxx>
+#include <datauno.hxx>
+#include <docfunc.hxx>
+#include <docoptio.hxx>
+#include <docsh.hxx>
+#include <docuno.hxx>
+#include <drwlayer.hxx>
+#include <forbiuno.hxx>
+#include <formulagroup.hxx>
+#include <gridwin.hxx>
+#include <hints.hxx>
+#include <inputhdl.hxx>
+#include <inputopt.hxx>
+#include <interpre.hxx>
+#include <linkuno.hxx>
+#include <markdata.hxx>
+#include <miscuno.hxx>
+#include <nameuno.hxx>
+#include <notesuno.hxx>
+#include <optuno.hxx>
+#include <pfuncache.hxx>
+#include <postit.hxx>
+#include <printfun.hxx>
+#include <rangeutl.hxx>
+#include <scmod.hxx>
+#include <scresid.hxx>
+#include <servuno.hxx>
+#include <shapeuno.hxx>
+#include <sheetevents.hxx>
+#include <styleuno.hxx>
+#include <tabvwsh.hxx>
+#include <targuno.hxx>
+#include <unonames.hxx>
+#include <ViewSettingsSequenceDefines.hxx>
+#include <editsh.hxx>
+#include <drawsh.hxx>
+#include <drtxtob.hxx>
+#include <transobj.hxx>
+#include <chgtrack.hxx>
+#include <table.hxx>
+#include <appoptio.hxx>
+#include <formulaopt.hxx>
+
+#include <strings.hrc>
+
+using namespace com::sun::star;
+
+// #i111553# provides the name of the VBA constant for this document type (e.g. 'ThisExcelDoc' for Calc)
+constexpr OUStringLiteral SC_UNO_VBAGLOBNAME = u"VBAGlobalConstantName";
+
+// no Which-ID here, map only for PropertySetInfo
+
+//! rename this, those are no longer only options
+static const SfxItemPropertyMapEntry* lcl_GetDocOptPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aDocOptPropertyMap_Impl[] =
+ {
+ { SC_UNO_APPLYFMDES, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_AREALINKS, 0, cppu::UnoType<sheet::XAreaLinks>::get(), 0, 0},
+ { SC_UNO_AUTOCONTFOC, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_BASICLIBRARIES, 0, cppu::UnoType<script::XLibraryContainer>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_DIALOGLIBRARIES, 0, cppu::UnoType<script::XLibraryContainer>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_VBAGLOBNAME, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_CALCASSHOWN, PROP_UNO_CALCASSHOWN, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_CLOCAL, 0, cppu::UnoType<lang::Locale>::get(), 0, 0},
+ { SC_UNO_CJK_CLOCAL, 0, cppu::UnoType<lang::Locale>::get(), 0, 0},
+ { SC_UNO_CTL_CLOCAL, 0, cppu::UnoType<lang::Locale>::get(), 0, 0},
+ { SC_UNO_COLLABELRNG, 0, cppu::UnoType<sheet::XLabelRanges>::get(), 0, 0},
+ { SC_UNO_DDELINKS, 0, cppu::UnoType<container::XNameAccess>::get(), 0, 0},
+ { SC_UNO_DEFTABSTOP, PROP_UNO_DEFTABSTOP, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_EXTERNALDOCLINKS, 0, cppu::UnoType<sheet::XExternalDocLinks>::get(), 0, 0},
+ { SC_UNO_FORBIDDEN, 0, cppu::UnoType<i18n::XForbiddenCharacters>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_HASDRAWPAGES, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_IGNORECASE, PROP_UNO_IGNORECASE, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ITERENABLED, PROP_UNO_ITERENABLED, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ITERCOUNT, PROP_UNO_ITERCOUNT, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_ITEREPSILON, PROP_UNO_ITEREPSILON, cppu::UnoType<double>::get(), 0, 0},
+ { SC_UNO_LOOKUPLABELS, PROP_UNO_LOOKUPLABELS, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_MATCHWHOLE, PROP_UNO_MATCHWHOLE, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_NAMEDRANGES, 0, cppu::UnoType<sheet::XNamedRanges>::get(), 0, 0},
+ { SC_UNO_DATABASERNG, 0, cppu::UnoType<sheet::XDatabaseRanges>::get(), 0, 0},
+ { SC_UNO_NULLDATE, PROP_UNO_NULLDATE, cppu::UnoType<util::Date>::get(), 0, 0},
+ { SC_UNO_ROWLABELRNG, 0, cppu::UnoType<sheet::XLabelRanges>::get(), 0, 0},
+ { SC_UNO_SHEETLINKS, 0, cppu::UnoType<container::XNameAccess>::get(), 0, 0},
+ { SC_UNO_SPELLONLINE, PROP_UNO_SPELLONLINE, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_STANDARDDEC, PROP_UNO_STANDARDDEC, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_REGEXENABLED, PROP_UNO_REGEXENABLED, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_WILDCARDSENABLED, PROP_UNO_WILDCARDSENABLED, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_RUNTIMEUID, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_HASVALIDSIGNATURES, 0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_ISLOADED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ISUNDOENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_RECORDCHANGES, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ISRECORDCHANGESPROTECTED,0, cppu::UnoType<bool>::get(), beans::PropertyAttribute::READONLY, 0},
+ { SC_UNO_ISADJUSTHEIGHTENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ISEXECUTELINKENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ISCHANGEREADONLYENABLED, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_REFERENCEDEVICE, 0, cppu::UnoType<awt::XDevice>::get(), beans::PropertyAttribute::READONLY, 0},
+ {u"BuildId", 0, ::cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNO_CODENAME, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNO_INTEROPGRABBAG, 0, cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aDocOptPropertyMap_Impl;
+}
+
+//! StandardDecimals as property and from NumberFormatter ????????
+
+static const SfxItemPropertyMapEntry* lcl_GetColumnsPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aColumnsPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_MANPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NEWPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLVIS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_OWIDTH, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLWID, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aColumnsPropertyMap_Impl;
+}
+
+static const SfxItemPropertyMapEntry* lcl_GetRowsPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aRowsPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_CELLHGT, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_CELLFILT, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_OHEIGHT, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_MANPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NEWPAGE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLVIS, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_CELLBACK, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ { SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ // not sorted, not used with SfxItemPropertyMapEntry::GetByName
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aRowsPropertyMap_Impl;
+}
+
+constexpr OUStringLiteral SCMODELOBJ_SERVICE = u"com.sun.star.sheet.SpreadsheetDocument";
+constexpr OUStringLiteral SCDOCSETTINGS_SERVICE = u"com.sun.star.sheet.SpreadsheetDocumentSettings";
+constexpr OUStringLiteral SCDOC_SERVICE = u"com.sun.star.document.OfficeDocument";
+
+SC_SIMPLE_SERVICE_INFO( ScAnnotationsObj, "ScAnnotationsObj", "com.sun.star.sheet.CellAnnotations" )
+SC_SIMPLE_SERVICE_INFO( ScDrawPagesObj, "ScDrawPagesObj", "com.sun.star.drawing.DrawPages" )
+SC_SIMPLE_SERVICE_INFO( ScScenariosObj, "ScScenariosObj", "com.sun.star.sheet.Scenarios" )
+SC_SIMPLE_SERVICE_INFO( ScSpreadsheetSettingsObj, "ScSpreadsheetSettingsObj", "com.sun.star.sheet.SpreadsheetDocumentSettings" )
+SC_SIMPLE_SERVICE_INFO( ScTableColumnsObj, "ScTableColumnsObj", "com.sun.star.table.TableColumns" )
+SC_SIMPLE_SERVICE_INFO( ScTableRowsObj, "ScTableRowsObj", "com.sun.star.table.TableRows" )
+SC_SIMPLE_SERVICE_INFO( ScTableSheetsObj, "ScTableSheetsObj", "com.sun.star.sheet.Spreadsheets" )
+
+class ScPrintUIOptions : public vcl::PrinterOptionsHelper
+{
+public:
+ ScPrintUIOptions();
+ void SetDefaults();
+};
+
+ScPrintUIOptions::ScPrintUIOptions()
+{
+ const ScPrintOptions& rPrintOpt = SC_MOD()->GetPrintOptions();
+ sal_Int32 nContent = rPrintOpt.GetAllSheets() ? 0 : 1;
+ bool bSuppress = rPrintOpt.GetSkipEmpty();
+
+ sal_Int32 nNumProps= 10, nIdx = 0;
+
+ m_aUIProperties.resize(nNumProps);
+
+ // load the writer PrinterOptions into the custom tab
+ m_aUIProperties[nIdx].Name = "OptionsUIFile";
+ m_aUIProperties[nIdx++].Value <<= OUString("modules/scalc/ui/printeroptions.ui");
+
+ // create Section for spreadsheet (results in an extra tab page in dialog)
+ SvtModuleOptions aOpt;
+ OUString aAppGroupname( ScResId( SCSTR_PRINTOPT_PRODNAME ) );
+ aAppGroupname = aAppGroupname.replaceFirst( "%s", aOpt.GetModuleName( SvtModuleOptions::EModule::CALC ) );
+ m_aUIProperties[nIdx++].Value = setGroupControlOpt("tabcontrol-page2", aAppGroupname, OUString());
+
+ // show subgroup for pages
+ m_aUIProperties[nIdx++].Value = setSubgroupControlOpt("pages", ScResId( SCSTR_PRINTOPT_PAGES ), OUString());
+
+ // create a bool option for empty pages
+ m_aUIProperties[nIdx++].Value = setBoolControlOpt("suppressemptypages", ScResId( SCSTR_PRINTOPT_SUPPRESSEMPTY ),
+ ".HelpID:vcl:PrintDialog:IsSuppressEmptyPages:CheckBox",
+ "IsSuppressEmptyPages",
+ bSuppress);
+ // show Subgroup for print content
+ vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt;
+ aPrintRangeOpt.maGroupHint = "PrintRange";
+ m_aUIProperties[nIdx++].Value = setSubgroupControlOpt("printrange", ScResId( SCSTR_PRINTOPT_PAGES ),
+ OUString(),
+ aPrintRangeOpt);
+
+ // create a choice for the content to create
+ uno::Sequence< OUString > aChoices{
+ ScResId( SCSTR_PRINTOPT_ALLSHEETS ),
+ ScResId( SCSTR_PRINTOPT_SELECTEDSHEETS ),
+ ScResId( SCSTR_PRINTOPT_SELECTEDCELLS )};
+ uno::Sequence< OUString > aHelpIds{
+ ".HelpID:vcl:PrintDialog:PrintContent:ListBox"};
+ m_aUIProperties[nIdx++].Value = setChoiceListControlOpt( "printextrabox", OUString(),
+ aHelpIds, "PrintContent",
+ aChoices, nContent );
+
+ // show Subgroup for print range
+ aPrintRangeOpt.mbInternalOnly = true;
+ m_aUIProperties[nIdx++].Value = setSubgroupControlOpt("fromwhich", ScResId( SCSTR_PRINTOPT_FROMWHICH ),
+ OUString(),
+ aPrintRangeOpt);
+
+ // create a choice for the range to print
+ OUString aPrintRangeName( "PrintRange" );
+ aChoices = { ScResId( SCSTR_PRINTOPT_PRINTALLPAGES ), ScResId( SCSTR_PRINTOPT_PRINTPAGES ) };
+ aHelpIds = { ".HelpID:vcl:PrintDialog:PrintRange:RadioButton:0",
+ ".HelpID:vcl:PrintDialog:PrintRange:RadioButton:1" };
+ uno::Sequence< OUString > aWidgetIds{ "rbAllPages", "rbRangePages" };
+ m_aUIProperties[nIdx++].Value = setChoiceRadiosControlOpt(aWidgetIds, OUString(),
+ aHelpIds,
+ aPrintRangeName,
+ aChoices,
+ 0 );
+
+ // create an Edit dependent on "Pages" selected
+ vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt( aPrintRangeName, 1, true );
+ m_aUIProperties[nIdx++].Value = setEditControlOpt("pagerange", OUString(),
+ ".HelpID:vcl:PrintDialog:PageRange:Edit",
+ "PageRange", OUString(), aPageRangeOpt);
+
+ vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintRangeName, 0, true);
+ m_aUIProperties[ nIdx++ ].Value = setChoiceListControlOpt("evenoddbox",
+ OUString(),
+ uno::Sequence<OUString>(),
+ "EvenOdd",
+ uno::Sequence<OUString>(),
+ 0,
+ uno::Sequence< sal_Bool >(),
+ aEvenOddOpt);
+
+ assert(nIdx == nNumProps);
+}
+
+void ScPrintUIOptions::SetDefaults()
+{
+ // re-initialize the default values from print options
+
+ const ScPrintOptions& rPrintOpt = SC_MOD()->GetPrintOptions();
+ sal_Int32 nContent = rPrintOpt.GetAllSheets() ? 0 : 1;
+ bool bSuppress = rPrintOpt.GetSkipEmpty();
+
+ for (beans::PropertyValue & rPropValue : m_aUIProperties)
+ {
+ uno::Sequence<beans::PropertyValue> aUIProp;
+ if ( rPropValue.Value >>= aUIProp )
+ {
+ for (auto& rProp : asNonConstRange(aUIProp))
+ {
+ OUString aName = rProp.Name;
+ if ( aName == "Property" )
+ {
+ beans::PropertyValue aPropertyValue;
+ if ( rProp.Value >>= aPropertyValue )
+ {
+ if ( aPropertyValue.Name == "PrintContent" )
+ {
+ aPropertyValue.Value <<= nContent;
+ rProp.Value <<= aPropertyValue;
+ }
+ else if ( aPropertyValue.Name == "IsSuppressEmptyPages" )
+ {
+ aPropertyValue.Value <<= bSuppress;
+ rProp.Value <<= aPropertyValue;
+ }
+ }
+ }
+ }
+ rPropValue.Value <<= aUIProp;
+ }
+ }
+}
+
+void ScModelObj::CreateAndSet(ScDocShell* pDocSh)
+{
+ if (pDocSh)
+ pDocSh->SetBaseModel( new ScModelObj(pDocSh) );
+}
+
+SdrModel& ScModelObj::getSdrModelFromUnoModel() const
+{
+ ScDocument& rDoc(pDocShell->GetDocument());
+
+ if(!rDoc.GetDrawLayer())
+ {
+ rDoc.InitDrawLayer();
+ }
+
+ return *rDoc.GetDrawLayer(); // TTTT should be reference
+}
+
+ScModelObj::ScModelObj( ScDocShell* pDocSh ) :
+ SfxBaseModel( pDocSh ),
+ aPropSet( lcl_GetDocOptPropertyMap() ),
+ pDocShell( pDocSh ),
+ maChangesListeners( m_aMutex )
+{
+ // pDocShell may be NULL if this is the base of a ScDocOptionsObj
+ if ( pDocShell )
+ {
+ pDocShell->GetDocument().AddUnoObject(*this); // SfxModel is derived from SfxListener
+ }
+}
+
+ScModelObj::~ScModelObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+
+ if (xNumberAgg.is())
+ xNumberAgg->setDelegator(uno::Reference<uno::XInterface>());
+
+ pPrintFuncCache.reset();
+ pPrinterOptions.reset();
+}
+
+uno::Reference< uno::XAggregation> const & ScModelObj::GetFormatter()
+{
+ // pDocShell may be NULL if this is the base of a ScDocOptionsObj
+ if ( !xNumberAgg.is() && pDocShell )
+ {
+ // setDelegator changes RefCount, so we'd better hold the reference ourselves
+ // (directly in m_refCount, so we don't delete ourselves with release())
+ osl_atomic_increment( &m_refCount );
+ // we need a reference to SvNumberFormatsSupplierObj during queryInterface,
+ // otherwise it'll be deleted
+ uno::Reference<util::XNumberFormatsSupplier> xFormatter(
+ new SvNumberFormatsSupplierObj(pDocShell->GetDocument().GetThreadedContext().GetFormatTable() ));
+ {
+ xNumberAgg.set(uno::Reference<uno::XAggregation>( xFormatter, uno::UNO_QUERY ));
+ // extra block to force deletion of the temporary before setDelegator
+ }
+
+ // during setDelegator no additional reference should exist
+ xFormatter = nullptr;
+
+ if (xNumberAgg.is())
+ xNumberAgg->setDelegator( static_cast<cppu::OWeakObject*>(this) );
+ osl_atomic_decrement( &m_refCount );
+ } // if ( !xNumberAgg.is() )
+ return xNumberAgg;
+}
+
+ScDocument* ScModelObj::GetDocument() const
+{
+ if (pDocShell)
+ return &pDocShell->GetDocument();
+ return nullptr;
+}
+
+SfxObjectShell* ScModelObj::GetEmbeddedObject() const
+{
+ return pDocShell;
+}
+
+void ScModelObj::UpdateAllRowHeights()
+{
+ if (pDocShell)
+ pDocShell->UpdateAllRowHeights();
+}
+
+void ScModelObj::BeforeXMLLoading()
+{
+ if (pDocShell)
+ pDocShell->BeforeXMLLoading();
+}
+
+void ScModelObj::AfterXMLLoading()
+{
+ if (pDocShell)
+ pDocShell->AfterXMLLoading(true);
+}
+
+ScSheetSaveData* ScModelObj::GetSheetSaveData()
+{
+ if (pDocShell)
+ return pDocShell->GetSheetSaveData();
+ return nullptr;
+}
+
+ScFormatSaveData* ScModelObj::GetFormatSaveData()
+{
+ if (pDocShell)
+ return pDocShell->GetFormatSaveData();
+ return nullptr;
+}
+
+void ScModelObj::RepaintRange( const ScRange& rRange )
+{
+ if (pDocShell)
+ pDocShell->PostPaint( rRange, PaintPartFlags::Grid );
+}
+
+void ScModelObj::RepaintRange( const ScRangeList& rRange )
+{
+ if (pDocShell)
+ pDocShell->PostPaint( rRange, PaintPartFlags::Grid );
+}
+
+static ScViewData* lcl_getViewMatchingDocZoomTab(const Fraction& rZoomX,
+ const Fraction& rZoomY,
+ const SCTAB nTab,
+ const ViewShellDocId& rDocId)
+{
+ constexpr size_t nMaxIter = 5;
+ size_t nIter = 0;
+ for (SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ pViewShell && nIter < nMaxIter;
+ (pViewShell = SfxViewShell::GetNext(*pViewShell)), ++nIter)
+ {
+ if (pViewShell->GetDocId() != rDocId)
+ continue;
+
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (!pTabViewShell)
+ continue;
+
+ ScViewData& rData = pTabViewShell->GetViewData();
+ if (rData.GetTabNo() == nTab && rData.GetZoomX() == rZoomX && rData.GetZoomY() == rZoomY)
+ return &rData;
+ }
+
+ return nullptr;
+}
+
+void ScModelObj::paintTile( VirtualDevice& rDevice,
+ int nOutputWidth, int nOutputHeight,
+ int nTilePosX, int nTilePosY,
+ tools::Long nTileWidth, tools::Long nTileHeight )
+{
+ ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
+
+ // FIXME: Can this happen? What should we do?
+ if (!pViewShell)
+ return;
+
+ ScViewData* pActiveViewData = &pViewShell->GetViewData();
+ Fraction aFracX(o3tl::toTwips(nOutputWidth, o3tl::Length::px), nTileWidth);
+ Fraction aFracY(o3tl::toTwips(nOutputHeight, o3tl::Length::px), nTileHeight);
+
+ // Try to find a view that matches the tile-zoom requested by iterating over
+ // first few shells. This is to avoid switching of zooms in ScGridWindow::PaintTile
+ // and hence avoid grid-offset recomputation on all shapes which is not cheap.
+ ScViewData* pViewData = lcl_getViewMatchingDocZoomTab(aFracX, aFracY,
+ pActiveViewData->GetTabNo(), pViewShell->GetDocId());
+ if (!pViewData)
+ pViewData = pActiveViewData;
+
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+
+ // update the size of the area we are painting
+ // FIXME we want to use only the minimal necessary size, like the
+ // following; but for the moment there is too many problems with that and
+ // interaction with editeng used for the cell editing
+ //Size aTileSize(nOutputWidth, nOutputHeight);
+ //if (pGridWindow->GetOutputSizePixel() != aTileSize)
+ // pGridWindow->SetOutputSizePixel(Size(nOutputWidth, nOutputHeight));
+ // so instead for now, set the viewport size to document size
+ Size aDocSize = getDocumentSize();
+ pGridWindow->SetOutputSizePixel(Size(aDocSize.Width() * pViewData->GetPPTX(), aDocSize.Height() * pViewData->GetPPTY()));
+
+ pGridWindow->PaintTile( rDevice, nOutputWidth, nOutputHeight,
+ nTilePosX, nTilePosY, nTileWidth, nTileHeight );
+
+ // Draw Form controls
+ ScDrawLayer* pDrawLayer = pDocShell->GetDocument().GetDrawLayer();
+ SdrPage* pPage = pDrawLayer->GetPage(sal_uInt16(pViewData->GetTabNo()));
+ SdrView* pDrawView = pViewData->GetViewShell()->GetScDrawView();
+ tools::Rectangle aTileRect(Point(nTilePosX, nTilePosY), Size(nTileWidth, nTileHeight));
+ Size aOutputSize(nOutputWidth, nOutputHeight);
+ LokControlHandler::paintControlTile(pPage, pDrawView, *pGridWindow, rDevice, aOutputSize, aTileRect);
+}
+
+void ScModelObj::setPart( int nPart, bool /*bAllowChangeFocus*/ )
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScTabView* pTabView = pViewData->GetView();
+ if (!pTabView)
+ return;
+
+ if (SdrView* pDrawView = pViewData->GetViewShell()->GetScDrawView())
+ pDrawView->SetNegativeX(comphelper::LibreOfficeKit::isActive() &&
+ pViewData->GetDocument().IsLayoutRTL(nPart));
+
+ pTabView->SelectTabPage(nPart + 1);
+}
+
+int ScModelObj::getParts()
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ return rDoc.GetTableCount();
+}
+
+int ScModelObj::getPart()
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ return pViewData ? pViewData->GetViewShell()->getPart() : 0;
+}
+
+OUString ScModelObj::getPartInfo( int nPart )
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return OUString();
+
+ const bool bIsVisible = pViewData->GetDocument().IsVisible(nPart);
+ //FIXME: Implement IsSelected().
+ const bool bIsSelected = false; //pViewData->GetDocument()->IsSelected(nPart);
+ const bool bIsRTLLayout = pViewData->GetDocument().IsLayoutRTL(nPart);
+
+ OUString aPartInfo = "{ \"visible\": \"" +
+ OUString::number(static_cast<unsigned int>(bIsVisible)) +
+ "\", \"selected\": \"" +
+ OUString::number(static_cast<unsigned int>(bIsSelected)) +
+ "\", \"rtllayout\": \"" +
+ OUString::number(static_cast<unsigned int>(bIsRTLLayout)) +
+ "\" }";
+ return aPartInfo;
+}
+
+OUString ScModelObj::getPartName( int nPart )
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return OUString();
+
+ OUString sTabName;
+ pViewData->GetDocument().GetName(nPart, sTabName);
+ return sTabName;
+}
+
+OUString ScModelObj::getPartHash( int nPart )
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return OUString();
+
+ sal_Int64 nHashCode;
+ return (pViewData->GetDocument().GetHashCode(nPart, nHashCode) ? OUString::number(nHashCode) : OUString());
+}
+
+VclPtr<vcl::Window> ScModelObj::getDocWindow()
+{
+ SolarMutexGuard aGuard;
+
+ ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
+
+ // FIXME: Can this happen? What should we do?
+ if (!pViewShell)
+ return VclPtr<vcl::Window>();
+
+ ScViewData* pViewData = &pViewShell->GetViewData();
+
+ VclPtr<vcl::Window> pWindow;
+ if (pViewData)
+ {
+ pWindow = pViewData->GetActiveWin();
+
+ LokChartHelper aChartHelper(pViewData->GetViewShell());
+ vcl::Window* pChartWindow = aChartHelper.GetWindow();
+ if (pChartWindow)
+ pWindow = pChartWindow;
+ }
+
+ return pWindow;
+}
+
+Size ScModelObj::getDocumentSize()
+{
+ Size aSize(10, 10); // minimum size
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return aSize;
+
+ SCTAB nTab = pViewData->GetTabNo();
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ const ScDocument& rDoc = pDocShell->GetDocument();
+
+ rDoc.GetTiledRenderingArea(nTab, nEndCol, nEndRow);
+
+ const ScDocument* pThisDoc = &rDoc;
+ const double fPPTX = pViewData->GetPPTX();
+ const double fPPTY = pViewData->GetPPTY();
+
+ auto GetColWidthPx = [pThisDoc, fPPTX, nTab](SCCOL nCol) {
+ const sal_uInt16 nSize = pThisDoc->GetColWidth(nCol, nTab);
+ return ScViewData::ToPixel(nSize, fPPTX);
+ };
+
+ tools::Long nDocWidthPixel = pViewData->GetLOKWidthHelper().computePosition(nEndCol, GetColWidthPx);
+ tools::Long nDocHeightPixel = pThisDoc->GetScaledRowHeight(0, nEndRow, nTab, fPPTY);
+
+ if (nDocWidthPixel > 0 && nDocHeightPixel > 0)
+ {
+ // convert to twips
+ aSize.setWidth(nDocWidthPixel / fPPTX);
+ aSize.setHeight(nDocHeightPixel / fPPTY);
+ }
+ else
+ {
+ // convert to twips
+ aSize.setWidth(rDoc.GetColWidth(0, nEndCol, nTab));
+ aSize.setHeight(rDoc.GetRowHeight(0, nEndRow, nTab));
+ }
+
+ return aSize;
+}
+
+
+void ScModelObj::postKeyEvent(int nType, int nCharCode, int nKeyCode)
+{
+ SolarMutexGuard aGuard;
+ SfxLokHelper::postKeyEventAsync(getDocWindow(), nType, nCharCode, nKeyCode);
+}
+
+void ScModelObj::postMouseEvent(int nType, int nX, int nY, int nCount, int nButtons, int nModifier)
+{
+ SolarMutexGuard aGuard;
+
+ ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
+
+ // FIXME: Can this happen? What should we do?
+ if (!pViewShell)
+ return;
+
+ ScViewData* pViewData = &pViewShell->GetViewData();
+
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+
+ if (!pGridWindow)
+ return;
+
+ // check if user hit a chart which is being edited by him
+ ScTabViewShell * pTabViewShell = pViewData->GetViewShell();
+ SCTAB nTab = pViewData->GetTabNo();
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ // In LOK RTL mode draw/svx operates in negative X coordinates
+ // But the coordinates from client is always positive, so negate nX for draw.
+ bool bDrawNegativeX = rDoc.IsNegativePage(nTab);
+ LokChartHelper aChartHelper(pTabViewShell, bDrawNegativeX);
+ int nDrawX = bDrawNegativeX ? -nX : nX;
+ if (aChartHelper.postMouseEvent(nType, nDrawX, nY,
+ nCount, nButtons, nModifier,
+ pViewData->GetPPTX(), pViewData->GetPPTY()))
+ {
+ return;
+ }
+
+ Point aPointTwip(nX, nY);
+ Point aPointTwipDraw(nDrawX, nY);
+
+ // 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(aPointTwipDraw, bDrawNegativeX))
+ return;
+ }
+
+ // Check if a control is hit
+ Point aPointHMM = o3tl::convert(aPointTwip, o3tl::Length::twip, o3tl::Length::mm100);
+ Point aPointHMMDraw(bDrawNegativeX ? -aPointHMM.X() : aPointHMM.X(), aPointHMM.Y());
+ ScDrawLayer* pDrawLayer = pDocShell->GetDocument().GetDrawLayer();
+ SdrPage* pPage = pDrawLayer->GetPage(sal_uInt16(nTab));
+ SdrView* pDrawView = pViewData->GetViewShell()->GetScDrawView();
+ if (LokControlHandler::postMouseEvent(pPage, pDrawView, *pGridWindow, nType, aPointHMMDraw, nCount, nButtons, nModifier))
+ return;
+
+ if (!pGridWindow->HasChildPathFocus(true))
+ pGridWindow->GrabFocus();
+
+ // Calc operates in pixels...
+ const Point aPosition(nX * pViewData->GetPPTX() + pGridWindow->GetOutOffXPixel(),
+ nY * pViewData->GetPPTY() + pGridWindow->GetOutOffYPixel());
+
+ VclEventId aEvent = VclEventId::NONE;
+ MouseEvent aData(aPosition, nCount, MouseEventModifiers::SIMPLECLICK, nButtons, nModifier);
+ aData.setLogicPosition(aPointHMM);
+ switch (nType)
+ {
+ case LOK_MOUSEEVENT_MOUSEBUTTONDOWN:
+ aEvent = VclEventId::WindowMouseButtonDown;
+ break;
+ case LOK_MOUSEEVENT_MOUSEBUTTONUP:
+ aEvent = VclEventId::WindowMouseButtonUp;
+ break;
+ case LOK_MOUSEEVENT_MOUSEMOVE:
+ aEvent = VclEventId::WindowMouseMove;
+ break;
+ default:
+ break;
+ }
+
+ Application::LOKHandleMouseEvent(aEvent, pGridWindow, &aData);
+}
+
+void ScModelObj::setTextSelection(int nType, int nX, int nY)
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScTabViewShell* pViewShell = pViewData->GetViewShell();
+
+ LokChartHelper aChartHelper(pViewShell);
+ if (aChartHelper.setTextSelection(nType, nX, nY))
+ return;
+
+ ScInputHandler* pInputHandler = SC_MOD()->GetInputHdl(pViewShell);
+ ScDrawView* pDrawView = pViewData->GetScDrawView();
+
+ bool bHandled = false;
+
+ if (pInputHandler && pInputHandler->IsInputMode())
+ {
+ // forwarding to editeng - we are editing the cell content
+ EditView* pTableView = pInputHandler->GetTableView();
+ assert(pTableView);
+
+ Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
+
+ if (pTableView->GetOutputArea().Contains(aPoint))
+ {
+ switch (nType)
+ {
+ case LOK_SETTEXTSELECTION_START:
+ pTableView->SetCursorLogicPosition(aPoint, /*bPoint=*/false, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_END:
+ pTableView->SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_RESET:
+ pTableView->SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/true);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ bHandled = true;
+ }
+ }
+ else if (pDrawView && pDrawView->IsTextEdit())
+ {
+ // forwarding to editeng - we are editing the text in shape
+ OutlinerView* pOutlinerView = pDrawView->GetTextEditOutlinerView();
+ EditView& rEditView = pOutlinerView->GetEditView();
+
+ Point aPoint(convertTwipToMm100(nX), convertTwipToMm100(nY));
+ switch (nType)
+ {
+ case LOK_SETTEXTSELECTION_START:
+ rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/false, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_END:
+ rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/false);
+ break;
+ case LOK_SETTEXTSELECTION_RESET:
+ rEditView.SetCursorLogicPosition(aPoint, /*bPoint=*/true, /*bClearMark=*/true);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ bHandled = true;
+ }
+
+ if (!bHandled)
+ {
+ // just update the cell selection
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+ if (!pGridWindow)
+ return;
+
+ // move the cell selection handles
+ pGridWindow->SetCellSelectionPixel(nType, nX * pViewData->GetPPTX(), nY * pViewData->GetPPTY());
+ }
+}
+
+uno::Reference<datatransfer::XTransferable> ScModelObj::getSelection()
+{
+ SolarMutexGuard aGuard;
+
+ TransferableDataHelper aDataHelper;
+ uno::Reference<datatransfer::XTransferable> xTransferable;
+
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ {
+ if ( ScEditShell * pShell = dynamic_cast<ScEditShell*>( pViewData->GetViewShell()->GetViewFrame()->GetDispatcher()->GetShell(0) ) )
+ xTransferable = pShell->GetEditView()->GetTransferable();
+ else if ( nullptr != dynamic_cast<ScDrawTextObjectBar*>( pViewData->GetViewShell()->GetViewFrame()->GetDispatcher()->GetShell(0) ))
+ {
+ ScDrawView* pView = pViewData->GetScDrawView();
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+ if (pOutView)
+ xTransferable = pOutView->GetEditView().GetTransferable();
+ }
+ else if ( ScDrawShell * pDrawShell = dynamic_cast<ScDrawShell*>( pViewData->GetViewShell()->GetViewFrame()->GetDispatcher()->GetShell(0) ) )
+ xTransferable = pDrawShell->GetDrawView()->CopyToTransferable();
+ else
+ xTransferable = pViewData->GetViewShell()->CopyToTransferable();
+ }
+
+ if (!xTransferable.is())
+ xTransferable.set( aDataHelper.GetTransferable() );
+
+ return xTransferable;
+}
+
+void ScModelObj::setGraphicSelection(int nType, int nX, int nY)
+{
+ SolarMutexGuard aGuard;
+
+ ScTabViewShell* pViewShell = pDocShell->GetBestViewShell(false);
+
+ // FIXME: Can this happen? What should we do?
+ if (!pViewShell)
+ return;
+
+ ScViewData* pViewData = &pViewShell->GetViewData();
+
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+
+ double fPPTX = pViewData->GetPPTX();
+ double fPPTY = pViewData->GetPPTY();
+
+ pViewShell = pViewData->GetViewShell();
+ LokChartHelper aChartHelper(pViewShell);
+ if (aChartHelper.setGraphicSelection(nType, nX, nY, fPPTX, fPPTY))
+ return;
+
+ int nPixelX = nX * fPPTX;
+ int nPixelY = nY * fPPTY;
+
+ switch (nType)
+ {
+ case LOK_SETGRAPHICSELECTION_START:
+ {
+ MouseEvent aClickEvent(Point(nPixelX, nPixelY), 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
+ pGridWindow->MouseButtonDown(aClickEvent);
+ MouseEvent aMoveEvent(Point(nPixelX, nPixelY), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
+ pGridWindow->MouseMove(aMoveEvent);
+ }
+ break;
+ case LOK_SETGRAPHICSELECTION_END:
+ {
+ MouseEvent aMoveEvent(Point(nPixelX, nPixelY), 0, MouseEventModifiers::SIMPLEMOVE, MOUSE_LEFT);
+ pGridWindow->MouseMove(aMoveEvent);
+ MouseEvent aClickEvent(Point(nPixelX, nPixelY), 1, MouseEventModifiers::SIMPLECLICK, MOUSE_LEFT);
+ pGridWindow->MouseButtonUp(aClickEvent);
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+void ScModelObj::resetSelection()
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScTabViewShell* pViewShell = pViewData->GetViewShell();
+
+ // deselect the shapes & texts
+ ScDrawView* pDrawView = pViewShell->GetScDrawView();
+ if (pDrawView)
+ {
+ pDrawView->ScEndTextEdit();
+ pDrawView->UnmarkAll();
+ }
+ else
+ pViewShell->Unmark();
+
+ // and hide the cell and text selection
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, "");
+ SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "");
+}
+
+void ScModelObj::setClipboard(const uno::Reference<datatransfer::clipboard::XClipboard>& xClipboard)
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ pViewData->GetActiveWin()->SetClipboard(xClipboard);
+}
+
+bool ScModelObj::isMimeTypeSupported()
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return false;
+
+
+ TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromSystemClipboard(pViewData->GetActiveWin()));
+ return EditEngine::HasValidData(aDataHelper.GetTransferable());
+}
+
+static void lcl_sendLOKDocumentBackground(const ScViewData* pViewData)
+{
+ ScDocShell* pDocSh = pViewData->GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ const ScPatternAttr *pAttr = rDoc.GetDefPattern();
+ const SfxPoolItem& rItem = pAttr->GetItem(ATTR_BACKGROUND);
+ const SvxBrushItem& rBackground = static_cast<const SvxBrushItem&>(rItem);
+ const Color& rColor = rBackground.GetColor();
+
+ ScTabViewShell* pViewShell = pViewData->GetViewShell();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_DOCUMENT_BACKGROUND_COLOR, rColor.AsRGBHexString().toUtf8().getStr());
+}
+
+void ScModelObj::setClientZoom(int nTilePixelWidth_, int nTilePixelHeight_, int nTileTwipWidth_, int nTileTwipHeight_)
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ // Currently in LOK clients the doc background cannot be changed, so send this sparingly as possible but for every view.
+ // FIXME: Find a better place to trigger this callback where it would be called just once per view creation.
+ // Doing this in ScTabViewShell init code does not work because callbacks do not work at that point for the first view.
+ lcl_sendLOKDocumentBackground(pViewData);
+
+ const Fraction newZoomX(o3tl::toTwips(nTilePixelWidth_, o3tl::Length::px), nTileTwipWidth_);
+ const Fraction newZoomY(o3tl::toTwips(nTilePixelHeight_, o3tl::Length::px), nTileTwipHeight_);
+
+ double fDeltaPPTX = std::abs(ScGlobal::nScreenPPTX * static_cast<double>(newZoomX) - pViewData->GetPPTX());
+ double fDeltaPPTY = std::abs(ScGlobal::nScreenPPTY * static_cast<double>(newZoomY) - pViewData->GetPPTY());
+ constexpr double fEps = 1E-08;
+
+ if (pViewData->GetZoomX() == newZoomX && pViewData->GetZoomY() == newZoomY && fDeltaPPTX < fEps && fDeltaPPTY < fEps)
+ return;
+
+ pViewData->SetZoom(newZoomX, newZoomY, true);
+
+ // refresh our view's take on other view's cursors & selections
+ pViewData->GetActiveWin()->updateKitOtherCursors();
+ pViewData->GetActiveWin()->updateOtherKitSelections();
+
+ if (ScDrawView* pDrawView = pViewData->GetScDrawView())
+ pDrawView->resetGridOffsetsForAllSdrPageViews();
+}
+
+void ScModelObj::getRowColumnHeaders(const tools::Rectangle& rRectangle, tools::JsonWriter& rJsonWriter)
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScTabView* pTabView = pViewData->GetView();
+ if (!pTabView)
+ return;
+
+ pTabView->getRowColumnHeaders(rRectangle, rJsonWriter);
+}
+
+OString ScModelObj::getSheetGeometryData(bool bColumns, bool bRows, bool bSizes, bool bHidden,
+ bool bFiltered, bool bGroups)
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return "";
+
+ ScTabView* pTabView = pViewData->GetView();
+ if (!pTabView)
+ return "";
+
+ return pTabView->getSheetGeometryData(bColumns, bRows, bSizes, bHidden, bFiltered, bGroups);
+}
+
+void ScModelObj::getCellCursor(tools::JsonWriter& rJsonWriter)
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+ if (!pGridWindow)
+ return;
+
+ rJsonWriter.put("commandName", ".uno:CellCursor");
+ rJsonWriter.put("commandValues", pGridWindow->getCellCursor());
+}
+
+PointerStyle ScModelObj::getPointer()
+{
+ SolarMutexGuard aGuard;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return PointerStyle::Arrow;
+
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+ if (!pGridWindow)
+ return PointerStyle::Arrow;
+
+ return pGridWindow->GetPointer();
+}
+
+void ScModelObj::getTrackedChanges(tools::JsonWriter& rJson)
+{
+ if (pDocShell)
+ {
+ if (ScChangeTrack* pChangeTrack = pDocShell->GetDocument().GetChangeTrack())
+ pChangeTrack->GetChangeTrackInfo(rJson);
+ }
+}
+
+void ScModelObj::setClientVisibleArea(const tools::Rectangle& rRectangle)
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ // set the PgUp/PgDown offset
+ pViewData->ForcePageUpDownOffset(rRectangle.GetHeight());
+
+ // Store the visible area so that we can use at places like shape insertion
+ pViewData->setLOKVisibleArea(rRectangle);
+
+ if (comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ {
+ ScTabView* pTabView = pViewData->GetView();
+ if (pTabView)
+ pTabView->extendTiledAreaIfNeeded();
+ }
+}
+
+void ScModelObj::setOutlineState(bool bColumn, int nLevel, int nIndex, bool bHidden)
+{
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if (!pViewData)
+ return;
+
+ ScDBFunc* pFunc = pViewData->GetView();
+
+ if (pFunc)
+ pFunc->SetOutlineState(bColumn, nLevel, nIndex, bHidden);
+}
+
+void ScModelObj::getPostIts(tools::JsonWriter& rJsonWriter)
+{
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::vector<sc::NoteEntry> aNotes;
+ rDoc.GetAllNoteEntries(aNotes);
+
+ auto commentsNode = rJsonWriter.startArray("comments");
+ for (const sc::NoteEntry& aNote : aNotes)
+ {
+ auto commentNode = rJsonWriter.startStruct();
+
+ rJsonWriter.put("id", aNote.mpNote->GetId());
+ rJsonWriter.put("tab", aNote.maPos.Tab());
+ rJsonWriter.put("author", aNote.mpNote->GetAuthor());
+ rJsonWriter.put("dateTime", aNote.mpNote->GetDate());
+ rJsonWriter.put("text", aNote.mpNote->GetText());
+
+ // Calculating the cell cursor position
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ {
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+ if (pGridWindow)
+ {
+ SCCOL nX = aNote.maPos.Col();
+ SCROW nY = aNote.maPos.Row();
+ Point aScrPos = pViewData->GetScrPos(nX, nY, pViewData->GetActivePart(), true);
+ tools::Long nSizeXPix;
+ tools::Long nSizeYPix;
+ pViewData->GetMergeSizePixel(nX, nY, nSizeXPix, nSizeYPix);
+
+ double fPPTX = pViewData->GetPPTX();
+ double fPPTY = pViewData->GetPPTY();
+ tools::Rectangle aRect(Point(aScrPos.getX() / fPPTX, aScrPos.getY() / fPPTY),
+ Size(nSizeXPix / fPPTX, nSizeYPix / fPPTY));
+
+ rJsonWriter.put("cellPos", aRect.toString());
+ }
+ }
+ }
+}
+
+void ScModelObj::getPostItsPos(tools::JsonWriter& rJsonWriter)
+{
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::vector<sc::NoteEntry> aNotes;
+ rDoc.GetAllNoteEntries(aNotes);
+
+ auto commentsNode = rJsonWriter.startArray("commentsPos");
+ for (const sc::NoteEntry& aNote : aNotes)
+ {
+ auto commentNode = rJsonWriter.startStruct();
+
+ rJsonWriter.put("id", aNote.mpNote->GetId());
+ rJsonWriter.put("tab", aNote.maPos.Tab());
+
+ // Calculating the cell cursor position
+ if (ScViewData* pViewData = ScDocShell::GetViewData())
+ {
+ ScGridWindow* pGridWindow = pViewData->GetActiveWin();
+ if (pGridWindow)
+ {
+ SCCOL nX = aNote.maPos.Col();
+ SCROW nY = aNote.maPos.Row();
+ Point aScrPos = pViewData->GetScrPos(nX, nY, pViewData->GetActivePart(), true);
+ tools::Long nSizeXPix;
+ tools::Long nSizeYPix;
+ pViewData->GetMergeSizePixel(nX, nY, nSizeXPix, nSizeYPix);
+
+ double fPPTX = pViewData->GetPPTX();
+ double fPPTY = pViewData->GetPPTY();
+ tools::Rectangle aRect(Point(aScrPos.getX() / fPPTX, aScrPos.getY() / fPPTY),
+ Size(nSizeXPix / fPPTX, nSizeYPix / fPPTY));
+
+ rJsonWriter.put("cellPos", aRect.toString());
+ }
+ }
+ }
+}
+
+void ScModelObj::completeFunction(const OUString& rFunctionName)
+{
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if (pHdl)
+ {
+ assert(!rFunctionName.isEmpty());
+ pHdl->LOKPasteFunctionData(rFunctionName);
+ }
+}
+
+void ScModelObj::initializeForTiledRendering(const css::uno::Sequence<css::beans::PropertyValue>& rArguments)
+{
+ SolarMutexGuard aGuard;
+
+ // enable word autocompletion
+ ScAppOptions aAppOptions(SC_MOD()->GetAppOptions());
+ aAppOptions.SetAutoComplete(true);
+ SC_MOD()->SetAppOptions(aAppOptions);
+
+ for (const beans::PropertyValue& rValue : rArguments)
+ {
+ if (rValue.Name == ".uno:SpellOnline" && rValue.Value.has<bool>())
+ {
+ ScDocOptions options = GetDocument()->GetDocOptions();
+ options.SetAutoSpell(rValue.Value.get<bool>());
+ GetDocument()->SetDocOptions(options);
+ }
+ }
+
+ // show us the text exactly
+ ScInputOptions aInputOptions(SC_MOD()->GetInputOptions());
+ aInputOptions.SetTextWysiwyg(true);
+ aInputOptions.SetReplaceCellsWarn(false);
+ SC_MOD()->SetInputOptions(aInputOptions);
+ pDocShell->CalcOutputFactor();
+
+ // 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();
+}
+
+uno::Any SAL_CALL ScModelObj::queryInterface( const uno::Type& rType )
+{
+ SC_QUERYINTERFACE( sheet::XSpreadsheetDocument )
+ SC_QUERYINTERFACE( document::XActionLockable )
+ SC_QUERYINTERFACE( sheet::XCalculatable )
+ SC_QUERYINTERFACE( util::XProtectable )
+ SC_QUERYINTERFACE( drawing::XDrawPagesSupplier )
+ SC_QUERYINTERFACE( sheet::XGoalSeek )
+ SC_QUERYINTERFACE( sheet::XConsolidatable )
+ SC_QUERYINTERFACE( sheet::XDocumentAuditing )
+ SC_QUERYINTERFACE( style::XStyleFamiliesSupplier )
+ SC_QUERYINTERFACE( view::XRenderable )
+ SC_QUERYINTERFACE( document::XLinkTargetSupplier )
+ SC_QUERYINTERFACE( beans::XPropertySet )
+ SC_QUERYINTERFACE( lang::XMultiServiceFactory )
+ SC_QUERYINTERFACE( lang::XServiceInfo )
+ SC_QUERYINTERFACE( util::XChangesNotifier )
+ SC_QUERYINTERFACE( sheet::opencl::XOpenCLSelection )
+ SC_QUERYINTERFACE( chart2::XDataProviderAccess )
+
+ uno::Any aRet(SfxBaseModel::queryInterface( rType ));
+ if ( !aRet.hasValue()
+ && rType != cppu::UnoType<css::document::XDocumentEventBroadcaster>::get()
+ && rType != cppu::UnoType<css::frame::XController>::get()
+ && rType != cppu::UnoType<css::frame::XFrame>::get()
+ && rType != cppu::UnoType<css::script::XInvocation>::get()
+ && rType != cppu::UnoType<css::beans::XFastPropertySet>::get()
+ && rType != cppu::UnoType<css::awt::XWindow>::get())
+ {
+ GetFormatter();
+ if ( xNumberAgg.is() )
+ aRet = xNumberAgg->queryAggregation( rType );
+ }
+
+ return aRet;
+}
+
+void SAL_CALL ScModelObj::acquire() noexcept
+{
+ SfxBaseModel::acquire();
+}
+
+void SAL_CALL ScModelObj::release() noexcept
+{
+ SfxBaseModel::release();
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScModelObj::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes = [&]()
+ {
+ uno::Sequence<uno::Type> aAggTypes;
+ if ( GetFormatter().is() )
+ {
+ const uno::Type& rProvType = cppu::UnoType<lang::XTypeProvider>::get();
+ uno::Any aNumProv(xNumberAgg->queryAggregation(rProvType));
+ if(auto xNumProv
+ = o3tl::tryAccess<uno::Reference<lang::XTypeProvider>>(aNumProv))
+ {
+ aAggTypes = (*xNumProv)->getTypes();
+ }
+ }
+ return comphelper::concatSequences(
+ SfxBaseModel::getTypes(),
+ aAggTypes,
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XSpreadsheetDocument>::get(),
+ cppu::UnoType<document::XActionLockable>::get(),
+ cppu::UnoType<sheet::XCalculatable>::get(),
+ cppu::UnoType<util::XProtectable>::get(),
+ cppu::UnoType<drawing::XDrawPagesSupplier>::get(),
+ cppu::UnoType<sheet::XGoalSeek>::get(),
+ cppu::UnoType<sheet::XConsolidatable>::get(),
+ cppu::UnoType<sheet::XDocumentAuditing>::get(),
+ cppu::UnoType<style::XStyleFamiliesSupplier>::get(),
+ cppu::UnoType<view::XRenderable>::get(),
+ cppu::UnoType<document::XLinkTargetSupplier>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<lang::XMultiServiceFactory>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<util::XChangesNotifier>::get(),
+ cppu::UnoType<sheet::opencl::XOpenCLSelection>::get(),
+ } );
+ }();
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScModelObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void ScModelObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ // Not interested in reference update hints here
+
+ const SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // has become invalid
+ if (xNumberAgg.is())
+ {
+ SvNumberFormatsSupplierObj* pNumFmt =
+ comphelper::getFromUnoTunnel<SvNumberFormatsSupplierObj>(
+ uno::Reference<util::XNumberFormatsSupplier>(xNumberAgg, uno::UNO_QUERY) );
+ if ( pNumFmt )
+ pNumFmt->SetNumberFormatter( nullptr );
+ }
+
+ pPrintFuncCache.reset(); // must be deleted because it has a pointer to the DocShell
+ m_pPrintState.reset();
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ // cached data for rendering become invalid when contents change
+ // (if a broadcast is added to SetDrawModified, is has to be tested here, too)
+
+ pPrintFuncCache.reset();
+ m_pPrintState.reset();
+
+ // handle "OnCalculate" sheet events (search also for VBA event handlers)
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( rDoc.GetVbaEventProcessor().is() )
+ {
+ // If the VBA event processor is set, HasAnyCalcNotification is much faster than HasAnySheetEventScript
+ if ( rDoc.HasAnyCalcNotification() && rDoc.HasAnySheetEventScript( ScSheetEventId::CALCULATE, true ) )
+ HandleCalculateEvents();
+ }
+ else
+ {
+ if ( rDoc.HasAnySheetEventScript( ScSheetEventId::CALCULATE ) )
+ HandleCalculateEvents();
+ }
+ }
+ }
+
+ // always call parent - SfxBaseModel might need to handle the same hints again
+ SfxBaseModel::Notify( rBC, rHint ); // SfxBaseModel is derived from SfxListener
+}
+
+// XSpreadsheetDocument
+
+uno::Reference<sheet::XSpreadsheets> SAL_CALL ScModelObj::getSheets()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScTableSheetsObj(pDocShell);
+ return nullptr;
+}
+
+css::uno::Reference< ::css::chart2::data::XDataProvider > SAL_CALL ScModelObj::createDataProvider()
+{
+ if (pDocShell)
+ {
+ return css::uno::Reference< ::css::chart2::data::XDataProvider > (
+ ScServiceProvider::MakeInstance(ScServiceProvider::Type::CHDATAPROV, pDocShell), uno::UNO_QUERY);
+ }
+ return nullptr;
+}
+
+// XStyleFamiliesSupplier
+
+uno::Reference<container::XNameAccess> SAL_CALL ScModelObj::getStyleFamilies()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScStyleFamiliesObj(pDocShell);
+ return nullptr;
+}
+
+// XRenderable
+
+static OutputDevice* lcl_GetRenderDevice( const uno::Sequence<beans::PropertyValue>& rOptions )
+{
+ OutputDevice* pRet = nullptr;
+ for (const beans::PropertyValue& rProp : rOptions)
+ {
+ const OUString & rPropName = rProp.Name;
+
+ if (rPropName == SC_UNONAME_RENDERDEV)
+ {
+ uno::Reference<awt::XDevice> xRenderDevice(rProp.Value, uno::UNO_QUERY);
+ if ( xRenderDevice.is() )
+ {
+ VCLXDevice* pDevice = comphelper::getFromUnoTunnel<VCLXDevice>( xRenderDevice );
+ if ( pDevice )
+ {
+ pRet = pDevice->GetOutputDevice().get();
+ pRet->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
+ }
+ }
+ }
+ }
+ return pRet;
+}
+
+static bool lcl_ParseTarget( const OUString& rTarget, ScRange& rTargetRange, tools::Rectangle& rTargetRect,
+ bool& rIsSheet, ScDocument& rDoc, SCTAB nSourceTab )
+{
+ // test in same order as in SID_CURRENTCELL execute
+
+ ScAddress aAddress;
+ SCTAB nNameTab;
+ sal_Int32 nNumeric = 0;
+
+ bool bRangeValid = false;
+ bool bRectValid = false;
+
+ if ( rTargetRange.Parse( rTarget, rDoc ) & ScRefFlags::VALID )
+ {
+ bRangeValid = true; // range reference
+ }
+ else if ( aAddress.Parse( rTarget, rDoc ) & ScRefFlags::VALID )
+ {
+ rTargetRange = aAddress;
+ bRangeValid = true; // cell reference
+ }
+ else if ( ScRangeUtil::MakeRangeFromName( rTarget, rDoc, nSourceTab, rTargetRange ) ||
+ ScRangeUtil::MakeRangeFromName( rTarget, rDoc, nSourceTab, rTargetRange, RUTL_DBASE ) )
+ {
+ bRangeValid = true; // named range or database range
+ }
+ else if ( comphelper::string::isdigitAsciiString(rTarget) &&
+ ( nNumeric = rTarget.toInt32() ) > 0 && nNumeric <= rDoc.MaxRow()+1 )
+ {
+ // row number is always mapped to cell A(row) on the same sheet
+ rTargetRange = ScAddress( 0, static_cast<SCROW>(nNumeric-1), nSourceTab ); // target row number is 1-based
+ bRangeValid = true; // row number
+ }
+ else if ( rDoc.GetTable( rTarget, nNameTab ) )
+ {
+ rTargetRange = ScAddress(0,0,nNameTab);
+ bRangeValid = true; // sheet name
+ rIsSheet = true; // needs special handling (first page of the sheet)
+ }
+ else
+ {
+ // look for named drawing object
+
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if ( pDrawLayer )
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB i=0; i<nTabCount && !bRangeValid; i++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(i));
+ OSL_ENSURE(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bRangeValid)
+ {
+ if ( ScDrawLayer::GetVisibleName( pObject ) == rTarget )
+ {
+ rTargetRect = pObject->GetLogicRect(); // 1/100th mm
+ rTargetRange = rDoc.GetRange( i, rTargetRect ); // underlying cells
+ bRangeValid = bRectValid = true; // rectangle is valid
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+ }
+ if ( bRangeValid && !bRectValid )
+ {
+ // get rectangle for cell range
+ rTargetRect = rDoc.GetMMRect( rTargetRange.aStart.Col(), rTargetRange.aStart.Row(),
+ rTargetRange.aEnd.Col(), rTargetRange.aEnd.Row(),
+ rTargetRange.aStart.Tab() );
+ }
+
+ return bRangeValid;
+}
+
+bool ScModelObj::FillRenderMarkData( const uno::Any& aSelection,
+ const uno::Sequence< beans::PropertyValue >& rOptions,
+ ScMarkData& rMark,
+ ScPrintSelectionStatus& rStatus, OUString& rPagesStr,
+ bool& rbRenderToGraphic ) const
+{
+ OSL_ENSURE( !rMark.IsMarked() && !rMark.IsMultiMarked(), "FillRenderMarkData: MarkData must be empty" );
+ OSL_ENSURE( pDocShell, "FillRenderMarkData: DocShell must be set" );
+
+ bool bDone = false;
+
+ uno::Reference<frame::XController> xView;
+
+ // defaults when no options are passed: all sheets, include empty pages
+ bool bSelectedSheetsOnly = false;
+ bool bSuppressEmptyPages = true;
+
+ bool bHasPrintContent = false;
+ sal_Int32 nPrintContent = 0; // all sheets / selected sheets / selected cells
+ sal_Int32 nPrintRange = 0; // all pages / pages
+ sal_Int32 nEOContent = 0; // even pages / odd pages
+ OUString aPageRange; // "pages" edit value
+
+ for( const auto& rOption : rOptions )
+ {
+ if ( rOption.Name == "IsOnlySelectedSheets" )
+ {
+ rOption.Value >>= bSelectedSheetsOnly;
+ }
+ else if ( rOption.Name == "IsSuppressEmptyPages" )
+ {
+ rOption.Value >>= bSuppressEmptyPages;
+ }
+ else if ( rOption.Name == "PageRange" )
+ {
+ rOption.Value >>= aPageRange;
+ }
+ else if ( rOption.Name == "PrintRange" )
+ {
+ rOption.Value >>= nPrintRange;
+ }
+ else if ( rOption.Name == "EvenOdd" )
+ {
+ rOption.Value >>= nEOContent;
+ }
+ else if ( rOption.Name == "PrintContent" )
+ {
+ bHasPrintContent = true;
+ rOption.Value >>= nPrintContent;
+ }
+ else if ( rOption.Name == "View" )
+ {
+ rOption.Value >>= xView;
+ }
+ else if ( rOption.Name == "RenderToGraphic" )
+ {
+ rOption.Value >>= rbRenderToGraphic;
+ }
+ }
+
+ // "Print Content" selection wins over "Selected Sheets" option
+ if ( bHasPrintContent )
+ bSelectedSheetsOnly = ( nPrintContent != 0 );
+
+ uno::Reference<uno::XInterface> xInterface(aSelection, uno::UNO_QUERY);
+ if ( xInterface.is() )
+ {
+ ScCellRangesBase* pSelObj = comphelper::getFromUnoTunnel<ScCellRangesBase>( xInterface );
+ uno::Reference< drawing::XShapes > xShapes( xInterface, uno::UNO_QUERY );
+ if ( pSelObj && pSelObj->GetDocShell() == pDocShell )
+ {
+ bool bSheet = ( comphelper::getFromUnoTunnel<ScTableSheetObj>( xInterface ) != nullptr );
+ bool bCursor = pSelObj->IsCursorOnly();
+ const ScRangeList& rRanges = pSelObj->GetRangeList();
+
+ rMark.MarkFromRangeList( rRanges, false );
+ rMark.MarkToSimple();
+
+ if ( rMark.IsMultiMarked() )
+ {
+ // #i115266# copy behavior of old printing:
+ // treat multiple selection like a single selection with the enclosing range
+ const ScRange& aMultiMarkArea = rMark.GetMultiMarkArea();
+ rMark.ResetMark();
+ rMark.SetMarkArea( aMultiMarkArea );
+ }
+
+ if ( rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ // a sheet object is treated like an empty selection: print the used area of the sheet
+
+ if ( bCursor || bSheet ) // nothing selected -> use whole tables
+ {
+ rMark.ResetMark(); // doesn't change table selection
+ rStatus.SetMode( ScPrintSelectionMode::Cursor );
+ }
+ else
+ rStatus.SetMode( ScPrintSelectionMode::Range );
+
+ rStatus.SetRanges( rRanges );
+ bDone = true;
+ }
+ // multi selection isn't supported
+ }
+ else if( xShapes.is() )
+ {
+ //print a selected ole object
+ // multi selection isn't supported yet
+ uno::Reference< drawing::XShape > xShape( xShapes->getByIndex(0), uno::UNO_QUERY );
+ SdrObject* pSdrObj = SdrObject::getSdrObjectFromXShape( xShape );
+ if( pSdrObj && pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ tools::Rectangle aObjRect = pSdrObj->GetCurrentBoundRect();
+ SCTAB nCurrentTab = ScDocShell::GetCurTab();
+ ScRange aRange = rDoc.GetRange( nCurrentTab, aObjRect );
+ rMark.SetMarkArea( aRange );
+
+ if( rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ rStatus.SetMode( ScPrintSelectionMode::RangeExclusivelyOleAndDrawObjects );
+ bDone = true;
+ }
+ }
+ }
+ else if ( comphelper::getFromUnoTunnel<ScModelObj>( xInterface ) == this )
+ {
+ // render the whole document
+ // -> no selection, all sheets
+
+ SCTAB nTabCount = pDocShell->GetDocument().GetTableCount();
+ for (SCTAB nTab = 0; nTab < nTabCount; nTab++)
+ rMark.SelectTable( nTab, true );
+ rStatus.SetMode( ScPrintSelectionMode::Document );
+ bDone = true;
+ }
+ // other selection types aren't supported
+ }
+
+ // restrict to selected sheets if a view is available
+ uno::Reference<sheet::XSelectedSheetsSupplier> xSelectedSheets(xView, uno::UNO_QUERY);
+ if (bSelectedSheetsOnly && pDocShell && xSelectedSheets.is())
+ {
+ const uno::Sequence<sal_Int32> aSelected = xSelectedSheets->getSelectedSheets();
+ ScMarkData::MarkedTabsType aSelectedTabs;
+ SCTAB nMaxTab = pDocShell->GetDocument().GetTableCount() -1;
+ for (const auto& rSelected : aSelected)
+ {
+ SCTAB nSelected = static_cast<SCTAB>(rSelected);
+ if (ValidTab(nSelected, nMaxTab))
+ aSelectedTabs.insert(nSelected);
+ }
+ rMark.SetSelectedTabs(aSelectedTabs);
+ }
+
+ ScPrintOptions aNewOptions;
+ aNewOptions.SetSkipEmpty( bSuppressEmptyPages );
+ aNewOptions.SetAllSheets( !bSelectedSheetsOnly );
+ rStatus.SetOptions( aNewOptions );
+
+ // "PrintRange" enables (1) or disables (0) the "PageRange" edit
+ if ( nPrintRange == 1 )
+ rPagesStr = aPageRange;
+ else
+ rPagesStr.clear();
+
+ return bDone;
+}
+
+sal_Int32 SAL_CALL ScModelObj::getRendererCount(const uno::Any& aSelection,
+ const uno::Sequence<beans::PropertyValue>& rOptions)
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ {
+ throw lang::DisposedException( OUString(),
+ static_cast< sheet::XSpreadsheetDocument* >(this) );
+ }
+
+ ScMarkData aMark(GetDocument()->GetSheetLimits());
+ ScPrintSelectionStatus aStatus;
+ OUString aPagesStr;
+ bool bRenderToGraphic = false;
+ if ( !FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr, bRenderToGraphic ) )
+ return 0;
+
+ // The same ScPrintFuncCache object in pPrintFuncCache is used as long as
+ // the same selection is used (aStatus) and the document isn't changed
+ // (pPrintFuncCache is cleared in Notify handler)
+
+ if ( !pPrintFuncCache || !pPrintFuncCache->IsSameSelection( aStatus ) )
+ {
+ pPrintFuncCache.reset(new ScPrintFuncCache( pDocShell, aMark, aStatus ));
+ }
+ sal_Int32 nPages = pPrintFuncCache->GetPageCount();
+
+ m_pPrintState.reset();
+ maValidPages.clear();
+
+ sal_Int32 nContent = 0;
+ sal_Int32 nEOContent = 0;
+ bool bSinglePageSheets = false;
+ for ( const auto& rValue : rOptions)
+ {
+ if ( rValue.Name == "PrintRange" )
+ {
+ rValue.Value >>= nContent;
+ }
+ else if ( rValue.Name == "SinglePageSheets" )
+ {
+ rValue.Value >>= bSinglePageSheets;
+ }
+ else if ( rValue.Name == "EvenOdd" )
+ {
+ rValue.Value >>= nEOContent;
+ }
+ }
+
+ if (bSinglePageSheets)
+ {
+ return pDocShell->GetDocument().GetTableCount();
+ }
+
+ bool bIsPrintEvenPages = (nEOContent != 1 && nContent == 0) || nContent != 0;
+ bool bIsPrintOddPages = (nEOContent != 2 && nContent == 0) || nContent != 0;
+
+ for ( sal_Int32 nPage = 1; nPage <= nPages; nPage++ )
+ {
+ if ( (bIsPrintEvenPages && IsOnEvenPage( nPage )) || (bIsPrintOddPages && !IsOnEvenPage( nPage )) )
+ maValidPages.push_back( nPage );
+ }
+
+ sal_Int32 nSelectCount = static_cast<sal_Int32>( maValidPages.size() );
+
+ if ( nEOContent == 1 || nEOContent == 2 ) // even pages / odd pages
+ return nSelectCount;
+
+ if ( !aPagesStr.isEmpty() )
+ {
+ StringRangeEnumerator aRangeEnum( aPagesStr, 0, nPages-1 );
+ nSelectCount = aRangeEnum.size();
+ }
+ return (nSelectCount > 0) ? nSelectCount : 1;
+}
+
+static sal_Int32 lcl_GetRendererNum( sal_Int32 nSelRenderer, std::u16string_view rPagesStr, sal_Int32 nTotalPages )
+{
+ if ( rPagesStr.empty() )
+ return nSelRenderer;
+
+ StringRangeEnumerator aRangeEnum( rPagesStr, 0, nTotalPages-1 );
+ StringRangeEnumerator::Iterator aIter = aRangeEnum.begin();
+ StringRangeEnumerator::Iterator aEnd = aRangeEnum.end();
+ for ( ; nSelRenderer > 0 && aIter != aEnd; --nSelRenderer )
+ ++aIter;
+
+ return *aIter; // returns -1 if reached the end
+}
+
+static bool lcl_renderSelectionToGraphic( bool bRenderToGraphic, const ScPrintSelectionStatus& rStatus )
+{
+ return bRenderToGraphic && rStatus.GetMode() == ScPrintSelectionMode::Range;
+}
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScModelObj::getRenderer( sal_Int32 nSelRenderer,
+ const uno::Any& aSelection, const uno::Sequence<beans::PropertyValue>& rOptions )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ {
+ throw lang::DisposedException( OUString(),
+ static_cast< sheet::XSpreadsheetDocument* >(this) );
+ }
+
+ ScMarkData aMark(pDocShell->GetDocument().GetSheetLimits());
+ ScPrintSelectionStatus aStatus;
+ OUString aPagesStr;
+ // #i115266# if FillRenderMarkData fails, keep nTotalPages at 0, but still handle getRenderer(0) below
+ tools::Long nTotalPages = 0;
+ bool bRenderToGraphic = false;
+ bool bSinglePageSheets = false;
+ if ( FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr, bRenderToGraphic ) )
+ {
+ if ( !pPrintFuncCache || !pPrintFuncCache->IsSameSelection( aStatus ) )
+ {
+ pPrintFuncCache.reset(new ScPrintFuncCache( pDocShell, aMark, aStatus ));
+ }
+ nTotalPages = pPrintFuncCache->GetPageCount();
+ }
+
+ for ( const auto& rValue : rOptions)
+ {
+ if ( rValue.Name == "SinglePageSheets" )
+ {
+ rValue.Value >>= bSinglePageSheets;
+ break;
+ }
+ }
+
+ if (bSinglePageSheets)
+ nTotalPages = pDocShell->GetDocument().GetTableCount();
+
+ sal_Int32 nRenderer = lcl_GetRendererNum( nSelRenderer, aPagesStr, nTotalPages );
+
+ if ( nRenderer < 0 )
+ {
+ if ( nSelRenderer != 0 )
+ throw lang::IllegalArgumentException();
+
+ // getRenderer(0) is used to query the settings, so it must always return something
+
+ awt::Size aPageSize;
+ if (lcl_renderSelectionToGraphic( bRenderToGraphic, aStatus))
+ {
+ assert( aMark.IsMarked());
+ const ScRange& aRange = aMark.GetMarkArea();
+ tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
+ aPageSize.Width = aMMRect.GetWidth();
+ aPageSize.Height = aMMRect.GetHeight();
+ }
+ else
+ {
+ SCTAB const nCurTab = 0; //! use current sheet from view?
+ ScPrintFunc aDefaultFunc( pDocShell, pDocShell->GetPrinter(), nCurTab );
+ Size aTwips = aDefaultFunc.GetPageSize();
+ aPageSize.Width = convertTwipToMm100(aTwips.Width());
+ aPageSize.Height = convertTwipToMm100(aTwips.Height());
+ }
+
+ uno::Sequence<beans::PropertyValue> aSequence( comphelper::InitPropertySequence({
+ { SC_UNONAME_PAGESIZE, uno::Any(aPageSize) }
+ }));
+
+ if( ! pPrinterOptions )
+ pPrinterOptions.reset(new ScPrintUIOptions);
+ else
+ pPrinterOptions->SetDefaults();
+ pPrinterOptions->appendPrintUIOptions( aSequence );
+ return aSequence;
+
+ }
+
+ // printer is used as device (just for page layout), draw view is not needed
+
+ SCTAB nTab;
+ if (bSinglePageSheets)
+ nTab = nSelRenderer;
+ else if ( !maValidPages.empty() )
+ nTab = pPrintFuncCache->GetTabForPage( maValidPages.at( nRenderer )-1 );
+ else
+ nTab = pPrintFuncCache->GetTabForPage( nRenderer );
+
+
+ ScRange aRange;
+ const ScRange* pSelRange = nullptr;
+ if ( bSinglePageSheets )
+ {
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ const ScDocument* pDocument = &pDocShell->GetDocument();
+ pDocument->GetDataStart( nTab, nStartCol, nStartRow );
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ pDocument->GetPrintArea( nTab, nEndCol, nEndRow );
+
+ aRange.aStart = ScAddress(nStartCol, nStartRow, nTab);
+ aRange.aEnd = ScAddress(nEndCol, nEndRow, nTab);
+
+ table::CellRangeAddress aRangeAddress( nTab,
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row() );
+ tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
+
+ const awt::Size aPageSize(aMMRect.GetWidth(), aMMRect.GetHeight());
+ const awt::Point aCalcPagePos(aMMRect.Left(), aMMRect.Top());
+
+ uno::Sequence<beans::PropertyValue> aSequence
+ {
+ comphelper::makePropertyValue(SC_UNONAME_PAGESIZE, aPageSize),
+ // #i111158# all positions are relative to the whole page, including non-printable area
+ comphelper::makePropertyValue(SC_UNONAME_INC_NP_AREA, true),
+ comphelper::makePropertyValue(SC_UNONAME_SOURCERANGE, aRangeAddress),
+ comphelper::makePropertyValue(SC_UNONAME_CALCPAGESIZE, aPageSize), // TODO aPageSize too ?
+ comphelper::makePropertyValue(SC_UNONAME_CALCPAGEPOS, aCalcPagePos)
+ };
+
+ if( ! pPrinterOptions )
+ pPrinterOptions.reset(new ScPrintUIOptions);
+ else
+ pPrinterOptions->SetDefaults();
+ pPrinterOptions->appendPrintUIOptions( aSequence );
+ return aSequence;
+ }
+ else if ( aMark.IsMarked() )
+ {
+ aRange = aMark.GetMarkArea();
+ pSelRange = &aRange;
+ }
+
+ awt::Size aPageSize;
+ bool bWasCellRange = false;
+ ScRange aCellRange;
+ if (lcl_renderSelectionToGraphic( bRenderToGraphic, aStatus))
+ {
+ bWasCellRange = true;
+ aCellRange = aRange;
+ tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
+ aPageSize.Width = aMMRect.GetWidth();
+ aPageSize.Height = aMMRect.GetHeight();
+ }
+ else
+ {
+ std::unique_ptr<ScPrintFunc, o3tl::default_delete<ScPrintFunc>> pPrintFunc;
+ if (m_pPrintState && m_pPrintState->nPrintTab == nTab)
+ pPrintFunc.reset(new ScPrintFunc(pDocShell, pDocShell->GetPrinter(), *m_pPrintState, &aStatus.GetOptions()));
+ else
+ pPrintFunc.reset(new ScPrintFunc(pDocShell, pDocShell->GetPrinter(), nTab,
+ pPrintFuncCache->GetFirstAttr(nTab), nTotalPages, pSelRange, &aStatus.GetOptions()));
+ pPrintFunc->SetRenderFlag( true );
+
+ sal_Int32 nContent = 0;
+ sal_Int32 nEOContent = 0;
+ for ( const auto& rValue : rOptions)
+ {
+ if ( rValue.Name == "PrintRange" )
+ {
+ rValue.Value >>= nContent;
+ }
+ else if ( rValue.Name == "EvenOdd" )
+ {
+ rValue.Value >>= nEOContent;
+ }
+ }
+
+ MultiSelection aPage;
+ aPage.SetTotalRange( Range(0,RANGE_MAX) );
+
+ bool bOddOrEven = (nContent == 0 && nEOContent == 1) || (nContent == 1 && nEOContent == 2); // even pages or odd pages
+ // tdf#127682 when odd/even allow nRenderer of 0 even when maValidPages is empty
+ // to allow PrinterController::abortJob to spool an empty page as part of
+ // its abort procedure
+ if (bOddOrEven && !maValidPages.empty())
+ aPage.Select( maValidPages.at(nRenderer) );
+ else
+ aPage.Select( nRenderer+1 );
+
+ tools::Long nDisplayStart = pPrintFuncCache->GetDisplayStart( nTab );
+ tools::Long nTabStart = pPrintFuncCache->GetTabStart( nTab );
+
+ (void)pPrintFunc->DoPrint( aPage, nTabStart, nDisplayStart, false, nullptr );
+
+ bWasCellRange = pPrintFunc->GetLastSourceRange( aCellRange );
+ Size aTwips = pPrintFunc->GetPageSize();
+
+ if (!m_pPrintState)
+ {
+ m_pPrintState.reset(new ScPrintState());
+ pPrintFunc->GetPrintState(*m_pPrintState, true);
+ }
+
+ aPageSize.Width = convertTwipToMm100(aTwips.Width());
+ aPageSize.Height = convertTwipToMm100(aTwips.Height());
+ }
+
+ tools::Long nPropCount = bWasCellRange ? 5 : 4;
+ uno::Sequence<beans::PropertyValue> aSequence(nPropCount);
+ beans::PropertyValue* pArray = aSequence.getArray();
+ pArray[0].Name = SC_UNONAME_PAGESIZE;
+ pArray[0].Value <<= aPageSize;
+ // #i111158# all positions are relative to the whole page, including non-printable area
+ pArray[1].Name = SC_UNONAME_INC_NP_AREA;
+ pArray[1].Value <<= true;
+ if ( bWasCellRange )
+ {
+ table::CellRangeAddress aRangeAddress( nTab,
+ aCellRange.aStart.Col(), aCellRange.aStart.Row(),
+ aCellRange.aEnd.Col(), aCellRange.aEnd.Row() );
+ tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
+ aCellRange.aStart.Col(), aCellRange.aStart.Row(),
+ aCellRange.aEnd.Col(), aCellRange.aEnd.Row(), aCellRange.aStart.Tab()));
+
+ const awt::Size aCalcPageSize(aMMRect.GetWidth(), aMMRect.GetHeight());
+ const awt::Point aCalcPagePos(aMMRect.Left(), aMMRect.Top());
+
+ pArray[2].Name = SC_UNONAME_SOURCERANGE;
+ pArray[2].Value <<= aRangeAddress;
+ pArray[3].Name = SC_UNONAME_CALCPAGESIZE;
+ pArray[3].Value <<= aCalcPageSize;
+ pArray[4].Name = SC_UNONAME_CALCPAGEPOS;
+ pArray[4].Value <<= aCalcPagePos;
+ }
+
+ if( ! pPrinterOptions )
+ pPrinterOptions.reset(new ScPrintUIOptions);
+ else
+ pPrinterOptions->SetDefaults();
+ pPrinterOptions->appendPrintUIOptions( aSequence );
+ return aSequence;
+}
+
+void SAL_CALL ScModelObj::render( sal_Int32 nSelRenderer, const uno::Any& aSelection,
+ const uno::Sequence<beans::PropertyValue>& rOptions )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ {
+ throw lang::DisposedException( OUString(),
+ static_cast< sheet::XSpreadsheetDocument* >(this) );
+ }
+
+ ScMarkData aMark(pDocShell->GetDocument().GetSheetLimits());
+ ScPrintSelectionStatus aStatus;
+ OUString aPagesStr;
+ bool bRenderToGraphic = false;
+ bool bSinglePageSheets = false;
+ if ( !FillRenderMarkData( aSelection, rOptions, aMark, aStatus, aPagesStr, bRenderToGraphic ) )
+ throw lang::IllegalArgumentException();
+
+ if ( !pPrintFuncCache || !pPrintFuncCache->IsSameSelection( aStatus ) )
+ {
+ pPrintFuncCache.reset(new ScPrintFuncCache( pDocShell, aMark, aStatus ));
+ }
+ tools::Long nTotalPages = pPrintFuncCache->GetPageCount();
+
+ for ( const auto& rValue : rOptions)
+ {
+ if ( rValue.Name == "SinglePageSheets" )
+ {
+ rValue.Value >>= bSinglePageSheets;
+ break;
+ }
+ }
+
+ if (bSinglePageSheets)
+ nTotalPages = pDocShell->GetDocument().GetTableCount();
+
+ sal_Int32 nRenderer = lcl_GetRendererNum( nSelRenderer, aPagesStr, nTotalPages );
+ if ( nRenderer < 0 )
+ throw lang::IllegalArgumentException();
+
+ OutputDevice* pDev = lcl_GetRenderDevice( rOptions );
+ if ( !pDev )
+ throw lang::IllegalArgumentException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ ScRange aRange;
+ const ScRange* pSelRange = nullptr;
+ if ( bSinglePageSheets )
+ {
+ awt::Size aPageSize;
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ rDoc.GetDataStart( nSelRenderer, nStartCol, nStartRow );
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ rDoc.GetPrintArea( nSelRenderer, nEndCol, nEndRow );
+
+ aRange.aStart = ScAddress(nStartCol, nStartRow, nSelRenderer);
+ aRange.aEnd = ScAddress(nEndCol, nEndRow, nSelRenderer);
+
+ tools::Rectangle aMMRect( pDocShell->GetDocument().GetMMRect(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab()));
+
+ aPageSize.Width = aMMRect.GetWidth();
+ aPageSize.Height = aMMRect.GetHeight();
+
+ //Set visible tab
+ SCTAB nVisTab = rDoc.GetVisibleTab();
+ if (nVisTab != nSelRenderer)
+ {
+ nVisTab = nSelRenderer;
+ rDoc.SetVisibleTab(nVisTab);
+ }
+
+ pDocShell->DoDraw(pDev, Point(0,0), Size(aPageSize.Width, aPageSize.Height), JobSetup());
+
+ return;
+ }
+ else if ( aMark.IsMarked() )
+ {
+ aRange = aMark.GetMarkArea();
+ pSelRange = &aRange;
+ }
+
+ if (lcl_renderSelectionToGraphic( bRenderToGraphic, aStatus))
+ {
+ // Similar to as in and when calling ScTransferObj::PaintToDev()
+
+ tools::Rectangle aBound( Point(), pDev->GetOutputSize());
+
+ ScViewData aViewData(rDoc);
+
+ aViewData.SetTabNo( aRange.aStart.Tab() );
+ aViewData.SetScreen( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row() );
+
+ const double nPrintFactor = 1.0; /* XXX: currently (2017-08-28) is not evaluated */
+ // The bMetaFile argument maybe could be
+ // pDev->GetConnectMetaFile() != nullptr
+ // but for some yet unknown reason does not draw cell content if true.
+ ScPrintFunc::DrawToDev( rDoc, pDev, nPrintFactor, aBound, &aViewData, false /*bMetaFile*/ );
+
+ return;
+ }
+
+ struct DrawViewKeeper
+ {
+ std::unique_ptr<FmFormView> mpDrawView;
+ DrawViewKeeper() {}
+ ~DrawViewKeeper()
+ {
+ if (mpDrawView)
+ {
+ mpDrawView->HideSdrPage();
+ mpDrawView.reset();
+ }
+ }
+ } aDrawViewKeeper;
+
+ SCTAB nTab;
+ if ( !maValidPages.empty() )
+ nTab = pPrintFuncCache->GetTabForPage( maValidPages.at( nRenderer )-1 );
+ else
+ nTab = pPrintFuncCache->GetTabForPage( nRenderer );
+
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+
+ if( pModel )
+ {
+ aDrawViewKeeper.mpDrawView.reset( new FmFormView(
+ *pModel,
+ pDev) );
+ aDrawViewKeeper.mpDrawView->ShowSdrPage(aDrawViewKeeper.mpDrawView->GetModel()->GetPage(nTab));
+ aDrawViewKeeper.mpDrawView->SetPrintPreview();
+ }
+
+ // to increase performance, ScPrintState might be used here for subsequent
+ // pages of the same sheet
+
+
+ std::unique_ptr<ScPrintFunc, o3tl::default_delete<ScPrintFunc>> pPrintFunc;
+ if (m_pPrintState && m_pPrintState->nPrintTab == nTab
+ && ! pSelRange) // tdf#120161 use selection to set required printed area
+ pPrintFunc.reset(new ScPrintFunc(pDev, pDocShell, *m_pPrintState, &aStatus.GetOptions()));
+ else
+ pPrintFunc.reset(new ScPrintFunc(pDev, pDocShell, nTab, pPrintFuncCache->GetFirstAttr(nTab), nTotalPages, pSelRange, &aStatus.GetOptions()));
+
+ pPrintFunc->SetDrawView( aDrawViewKeeper.mpDrawView.get() );
+ pPrintFunc->SetRenderFlag( true );
+ if( aStatus.GetMode() == ScPrintSelectionMode::RangeExclusivelyOleAndDrawObjects )
+ pPrintFunc->SetExclusivelyDrawOleAndDrawObjects();
+
+ sal_Int32 nContent = 0;
+ sal_Int32 nEOContent = 0;
+ for ( const auto& rValue : rOptions)
+ {
+ if ( rValue.Name == "PrintRange" )
+ {
+ rValue.Value >>= nContent;
+ }
+ else if ( rValue.Name == "EvenOdd" )
+ {
+ rValue.Value >>= nEOContent;
+ }
+ }
+
+ MultiSelection aPage;
+ aPage.SetTotalRange( Range(0,RANGE_MAX) );
+
+ bool bOddOrEven = (nContent == 0 && nEOContent == 1) || (nContent == 0 && nEOContent == 2); // even pages or odd pages
+ // tdf#127682 when odd/even allow nRenderer of 0 even when maValidPages is empty
+ // to allow PrinterController::abortJob to spool an empty page as part of
+ // its abort procedure
+ if (bOddOrEven && !maValidPages.empty())
+ aPage.Select( maValidPages.at( nRenderer ) );
+ else
+ aPage.Select( nRenderer+1 );
+
+ tools::Long nDisplayStart = pPrintFuncCache->GetDisplayStart( nTab );
+ tools::Long nTabStart = pPrintFuncCache->GetTabStart( nTab );
+
+ vcl::PDFExtOutDevData* pPDFData = dynamic_cast< vcl::PDFExtOutDevData* >(pDev->GetExtOutDevData() );
+ if ( nRenderer == nTabStart )
+ {
+ if (pPDFData)
+ {
+ css::lang::Locale const docLocale(LanguageTag(ScGlobal::GetEditDefaultLanguage()).getLocale());
+ pPDFData->SetDocumentLocale(docLocale);
+ }
+
+ // first page of a sheet: add outline item for the sheet name
+
+ if ( pPDFData && pPDFData->GetIsExportBookmarks() )
+ {
+ // the sheet starts at the top of the page
+ tools::Rectangle aArea( pDev->PixelToLogic( tools::Rectangle( 0,0,0,0 ) ) );
+ sal_Int32 nDestID = pPDFData->CreateDest( aArea );
+ OUString aTabName;
+ rDoc.GetName( nTab, aTabName );
+ // top-level
+ pPDFData->CreateOutlineItem( -1/*nParent*/, aTabName, nDestID );
+ }
+ // #i56629# add the named destination stuff
+ if( pPDFData && pPDFData->GetIsExportNamedDestinations() )
+ {
+ tools::Rectangle aArea( pDev->PixelToLogic( tools::Rectangle( 0,0,0,0 ) ) );
+ OUString aTabName;
+ rDoc.GetName( nTab, aTabName );
+ //need the PDF page number here
+ pPDFData->CreateNamedDest( aTabName, aArea );
+ }
+ }
+
+ (void)pPrintFunc->DoPrint( aPage, nTabStart, nDisplayStart, true, nullptr );
+
+ if (!m_pPrintState)
+ {
+ m_pPrintState.reset(new ScPrintState());
+ pPrintFunc->GetPrintState(*m_pPrintState, true);
+ }
+
+ // resolve the hyperlinks for PDF export
+
+ if ( !pPDFData || pPDFData->GetBookmarks().empty() )
+ return;
+
+ // iterate over the hyperlinks that were output for this page
+
+ std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFData->GetBookmarks();
+ for ( const auto& rBookmark : rBookmarks )
+ {
+ OUString aBookmark = rBookmark.aBookmark;
+ if ( aBookmark.toChar() == '#' )
+ {
+ // try to resolve internal link
+
+ OUString aTarget( aBookmark.copy( 1 ) );
+
+ ScRange aTargetRange;
+ tools::Rectangle aTargetRect; // 1/100th mm
+ bool bIsSheet = false;
+ bool bValid = lcl_ParseTarget( aTarget, aTargetRange, aTargetRect, bIsSheet, rDoc, nTab );
+
+ if ( bValid )
+ {
+ sal_Int32 nPage = -1;
+ tools::Rectangle aArea;
+ if ( bIsSheet )
+ {
+ // Get first page for sheet (if nothing from that sheet is printed,
+ // this page can show a different sheet)
+ nPage = pPrintFuncCache->GetTabStart( aTargetRange.aStart.Tab() );
+ aArea = pDev->PixelToLogic( tools::Rectangle( 0,0,0,0 ) );
+ }
+ else
+ {
+ pPrintFuncCache->InitLocations( aMark, pDev ); // does nothing if already initialized
+
+ ScPrintPageLocation aLocation;
+ if ( pPrintFuncCache->FindLocation( aTargetRange.aStart, aLocation ) )
+ {
+ nPage = aLocation.nPage;
+
+ // get the rectangle of the page's cell range in 1/100th mm
+ ScRange aLocRange = aLocation.aCellRange;
+ tools::Rectangle aLocationMM = rDoc.GetMMRect(
+ aLocRange.aStart.Col(), aLocRange.aStart.Row(),
+ aLocRange.aEnd.Col(), aLocRange.aEnd.Row(),
+ aLocRange.aStart.Tab() );
+ tools::Rectangle aLocationPixel = aLocation.aRectangle;
+
+ // Scale and move the target rectangle from aLocationMM to aLocationPixel,
+ // to get the target rectangle in pixels.
+ assert(aLocationPixel.GetWidth() != 0 && aLocationPixel.GetHeight() != 0);
+
+ Fraction aScaleX( aLocationPixel.GetWidth(), aLocationMM.GetWidth() );
+ Fraction aScaleY( aLocationPixel.GetHeight(), aLocationMM.GetHeight() );
+
+ tools::Long nX1 = aLocationPixel.Left() + static_cast<tools::Long>( Fraction( aTargetRect.Left() - aLocationMM.Left(), 1 ) * aScaleX );
+ tools::Long nX2 = aLocationPixel.Left() + static_cast<tools::Long>( Fraction( aTargetRect.Right() - aLocationMM.Left(), 1 ) * aScaleX );
+ tools::Long nY1 = aLocationPixel.Top() + static_cast<tools::Long>( Fraction( aTargetRect.Top() - aLocationMM.Top(), 1 ) * aScaleY );
+ tools::Long nY2 = aLocationPixel.Top() + static_cast<tools::Long>( Fraction( aTargetRect.Bottom() - aLocationMM.Top(), 1 ) * aScaleY );
+
+ if ( nX1 > aLocationPixel.Right() ) nX1 = aLocationPixel.Right();
+ if ( nX2 > aLocationPixel.Right() ) nX2 = aLocationPixel.Right();
+ if ( nY1 > aLocationPixel.Bottom() ) nY1 = aLocationPixel.Bottom();
+ if ( nY2 > aLocationPixel.Bottom() ) nY2 = aLocationPixel.Bottom();
+
+ // The link target area is interpreted using the device's MapMode at
+ // the time of the CreateDest call, so PixelToLogic can be used here,
+ // regardless of the MapMode that is actually selected.
+ aArea = pDev->PixelToLogic( tools::Rectangle( nX1, nY1, nX2, nY2 ) );
+ }
+ }
+
+ if ( nPage >= 0 )
+ pPDFData->SetLinkDest( rBookmark.nLinkId, pPDFData->CreateDest( aArea, nPage ) );
+ }
+ }
+ else
+ {
+ // external link, use as-is
+ pPDFData->SetLinkURL( rBookmark.nLinkId, aBookmark );
+ }
+ }
+ rBookmarks.clear();
+}
+
+// XLinkTargetSupplier
+
+uno::Reference<container::XNameAccess> SAL_CALL ScModelObj::getLinks()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScLinkTargetTypesObj(pDocShell);
+ return nullptr;
+}
+
+// XActionLockable
+
+sal_Bool SAL_CALL ScModelObj::isActionLocked()
+{
+ SolarMutexGuard aGuard;
+ bool bLocked = false;
+ if (pDocShell)
+ bLocked = ( pDocShell->GetLockCount() != 0 );
+ return bLocked;
+}
+
+void SAL_CALL ScModelObj::addActionLock()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ pDocShell->LockDocument();
+}
+
+void SAL_CALL ScModelObj::removeActionLock()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ pDocShell->UnlockDocument();
+}
+
+void SAL_CALL ScModelObj::setActionLocks( sal_Int16 nLock )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ pDocShell->SetLockCount(nLock);
+}
+
+sal_Int16 SAL_CALL ScModelObj::resetActionLocks()
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nRet = 0;
+ if (pDocShell)
+ {
+ nRet = pDocShell->GetLockCount();
+ pDocShell->SetLockCount(0);
+ }
+ return nRet;
+}
+
+void SAL_CALL ScModelObj::lockControllers()
+{
+ SolarMutexGuard aGuard;
+ SfxBaseModel::lockControllers();
+ if (pDocShell)
+ pDocShell->LockPaint();
+}
+
+void SAL_CALL ScModelObj::unlockControllers()
+{
+ SolarMutexGuard aGuard;
+ if (hasControllersLocked())
+ {
+ SfxBaseModel::unlockControllers();
+ if (pDocShell)
+ pDocShell->UnlockPaint();
+ }
+}
+
+// XCalculate
+
+void SAL_CALL ScModelObj::calculate()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ comphelper::ProfileZone aZone("calculate");
+ pDocShell->DoRecalc(true);
+ }
+ else
+ {
+ OSL_FAIL("no DocShell"); //! throw exception?
+ }
+}
+
+void SAL_CALL ScModelObj::calculateAll()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ comphelper::ProfileZone aZone("calculateAll");
+ pDocShell->DoHardRecalc();
+ }
+ else
+ {
+ OSL_FAIL("no DocShell"); //! throw exception?
+ }
+}
+
+sal_Bool SAL_CALL ScModelObj::isAutomaticCalculationEnabled()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return pDocShell->GetDocument().GetAutoCalc();
+
+ OSL_FAIL("no DocShell"); //! throw exception?
+ return false;
+}
+
+void SAL_CALL ScModelObj::enableAutomaticCalculation( sal_Bool bEnabledIn )
+{
+ bool bEnabled(bEnabledIn);
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( rDoc.GetAutoCalc() != bEnabled )
+ {
+ rDoc.SetAutoCalc( bEnabled );
+ pDocShell->SetDocumentModified();
+ }
+ }
+ else
+ {
+ OSL_FAIL("no DocShell"); //! throw exception?
+ }
+}
+
+// XProtectable
+
+void SAL_CALL ScModelObj::protect( const OUString& aPassword )
+{
+ SolarMutexGuard aGuard;
+ // #i108245# if already protected, don't change anything
+ if ( pDocShell && !pDocShell->GetDocument().IsDocProtected() )
+ {
+ pDocShell->GetDocFunc().Protect( TABLEID_DOC, aPassword );
+ }
+}
+
+void SAL_CALL ScModelObj::unprotect( const OUString& aPassword )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ bool bDone = pDocShell->GetDocFunc().Unprotect( TABLEID_DOC, aPassword, true );
+ if (!bDone)
+ throw lang::IllegalArgumentException();
+ }
+}
+
+sal_Bool SAL_CALL ScModelObj::isProtected()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return pDocShell->GetDocument().IsDocProtected();
+
+ OSL_FAIL("no DocShell"); //! throw exception?
+ return false;
+}
+
+// XDrawPagesSupplier
+
+uno::Reference<drawing::XDrawPages> SAL_CALL ScModelObj::getDrawPages()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return new ScDrawPagesObj(pDocShell);
+
+ OSL_FAIL("no DocShell"); //! throw exception?
+ return nullptr;
+}
+
+// XGoalSeek
+
+sheet::GoalResult SAL_CALL ScModelObj::seekGoal(
+ const table::CellAddress& aFormulaPosition,
+ const table::CellAddress& aVariablePosition,
+ const OUString& aGoalValue )
+{
+ SolarMutexGuard aGuard;
+ sheet::GoalResult aResult;
+ aResult.Divergence = DBL_MAX; // not found
+ if (pDocShell)
+ {
+ weld::WaitObject aWait( ScDocShell::GetActiveDialogParent() );
+ ScDocument& rDoc = pDocShell->GetDocument();
+ double fValue = 0.0;
+ bool bFound = rDoc.Solver(
+ static_cast<SCCOL>(aFormulaPosition.Column), static_cast<SCROW>(aFormulaPosition.Row), aFormulaPosition.Sheet,
+ static_cast<SCCOL>(aVariablePosition.Column), static_cast<SCROW>(aVariablePosition.Row), aVariablePosition.Sheet,
+ aGoalValue, fValue );
+ aResult.Result = fValue;
+ if (bFound)
+ aResult.Divergence = 0.0; //! this is a lie
+ }
+ return aResult;
+}
+
+// XConsolidatable
+
+uno::Reference<sheet::XConsolidationDescriptor> SAL_CALL ScModelObj::createConsolidationDescriptor(
+ sal_Bool bEmpty )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<ScConsolidationDescriptor> pNew = new ScConsolidationDescriptor;
+ if ( pDocShell && !bEmpty )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScConsolidateParam* pParam = rDoc.GetConsolidateDlgData();
+ if (pParam)
+ pNew->SetParam( *pParam );
+ }
+ return pNew;
+}
+
+void SAL_CALL ScModelObj::consolidate(
+ const uno::Reference<sheet::XConsolidationDescriptor>& xDescriptor )
+{
+ SolarMutexGuard aGuard;
+ // in theory, this could also be a different object, so use only
+ // public XConsolidationDescriptor interface to copy the data into
+ // ScConsolidationDescriptor object
+ //! but if this already is ScConsolidationDescriptor, do it directly via getImplementation?
+
+ rtl::Reference< ScConsolidationDescriptor > xImpl(new ScConsolidationDescriptor);
+ xImpl->setFunction( xDescriptor->getFunction() );
+ xImpl->setSources( xDescriptor->getSources() );
+ xImpl->setStartOutputPosition( xDescriptor->getStartOutputPosition() );
+ xImpl->setUseColumnHeaders( xDescriptor->getUseColumnHeaders() );
+ xImpl->setUseRowHeaders( xDescriptor->getUseRowHeaders() );
+ xImpl->setInsertLinks( xDescriptor->getInsertLinks() );
+
+ if (pDocShell)
+ {
+ const ScConsolidateParam& rParam = xImpl->GetParam();
+ pDocShell->DoConsolidate( rParam );
+ pDocShell->GetDocument().SetConsolidateDlgData( std::unique_ptr<ScConsolidateParam>(new ScConsolidateParam(rParam)) );
+ }
+}
+
+// XDocumentAuditing
+
+void SAL_CALL ScModelObj::refreshArrows()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ pDocShell->GetDocFunc().DetectiveRefresh();
+}
+
+// XViewDataSupplier
+uno::Reference< container::XIndexAccess > SAL_CALL ScModelObj::getViewData( )
+{
+ uno::Reference < container::XIndexAccess > xRet( SfxBaseModel::getViewData() );
+
+ if( !xRet.is() )
+ {
+ SolarMutexGuard aGuard;
+ if (pDocShell && pDocShell->GetCreateMode() == SfxObjectCreateMode::EMBEDDED)
+ {
+ rtl::Reference< comphelper::IndexedPropertyValuesContainer > xCont = new comphelper::IndexedPropertyValuesContainer();
+ xRet = xCont;
+
+ OUString sName;
+ pDocShell->GetDocument().GetName( pDocShell->GetDocument().GetVisibleTab(), sName );
+ SCCOL nPosLeft = pDocShell->GetDocument().GetPosLeft();
+ SCROW nPosTop = pDocShell->GetDocument().GetPosTop();
+ uno::Sequence< beans::PropertyValue > aSeq{
+ comphelper::makePropertyValue(SC_ACTIVETABLE, sName),
+ comphelper::makePropertyValue(SC_POSITIONLEFT, nPosLeft),
+ comphelper::makePropertyValue(SC_POSITIONTOP, nPosTop)
+ };
+ xCont->insertByIndex( 0, uno::Any( aSeq ) );
+ }
+ }
+
+ return xRet;
+}
+
+// XPropertySet (Doc-Options)
+//! provide them also to the application?
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScModelObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScModelObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScDocOptions& rOldOpt = rDoc.GetDocOptions();
+ ScDocOptions aNewOpt = rOldOpt;
+ // Don't recalculate while loading XML, when the formula text is stored
+ // Recalculation after loading is handled separately.
+ bool bHardRecalc = !rDoc.IsImportingXML();
+
+ bool bOpt = ScDocOptionsHelper::setPropertyValue( aNewOpt, aPropSet.getPropertyMap(), aPropertyName, aValue );
+ if (bOpt)
+ {
+ // done...
+ if ( aPropertyName == SC_UNO_IGNORECASE ||
+ aPropertyName == SC_UNONAME_REGEXP ||
+ aPropertyName == SC_UNONAME_WILDCARDS ||
+ aPropertyName == SC_UNO_LOOKUPLABELS )
+ bHardRecalc = false;
+ }
+ else if ( aPropertyName == SC_UNONAME_CLOCAL )
+ {
+ lang::Locale aLocale;
+ if ( aValue >>= aLocale )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+ eLatin = ScUnoConversion::GetLanguage(aLocale);
+ rDoc.SetLanguage( eLatin, eCjk, eCtl );
+ }
+ }
+ else if ( aPropertyName == SC_UNO_CODENAME )
+ {
+ OUString sCodeName;
+ if ( aValue >>= sCodeName )
+ rDoc.SetCodeName( sCodeName );
+ }
+ else if ( aPropertyName == SC_UNO_CJK_CLOCAL )
+ {
+ lang::Locale aLocale;
+ if ( aValue >>= aLocale )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+ eCjk = ScUnoConversion::GetLanguage(aLocale);
+ rDoc.SetLanguage( eLatin, eCjk, eCtl );
+ }
+ }
+ else if ( aPropertyName == SC_UNO_CTL_CLOCAL )
+ {
+ lang::Locale aLocale;
+ if ( aValue >>= aLocale )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+ eCtl = ScUnoConversion::GetLanguage(aLocale);
+ rDoc.SetLanguage( eLatin, eCjk, eCtl );
+ }
+ }
+ else if ( aPropertyName == SC_UNO_APPLYFMDES )
+ {
+ // model is created if not there
+ ScDrawLayer* pModel = pDocShell->MakeDrawLayer();
+ pModel->SetOpenInDesignMode( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+
+ SfxBindings* pBindings = pDocShell->GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_FM_OPEN_READONLY );
+ }
+ else if ( aPropertyName == SC_UNO_AUTOCONTFOC )
+ {
+ // model is created if not there
+ ScDrawLayer* pModel = pDocShell->MakeDrawLayer();
+ pModel->SetAutoControlFocus( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+
+ SfxBindings* pBindings = pDocShell->GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_FM_AUTOCONTROLFOCUS );
+ }
+ else if ( aPropertyName == SC_UNO_ISLOADED )
+ {
+ pDocShell->SetEmpty( !ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ }
+ else if ( aPropertyName == SC_UNO_ISUNDOENABLED )
+ {
+ bool bUndoEnabled = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ rDoc.EnableUndo( bUndoEnabled );
+ pDocShell->GetUndoManager()->SetMaxUndoActionCount(
+ bUndoEnabled
+ ? officecfg::Office::Common::Undo::Steps::get() : 0);
+ }
+ else if ( aPropertyName == SC_UNO_RECORDCHANGES )
+ {
+ bool bRecordChangesEnabled = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+
+ bool bChangeAllowed = true;
+ if (!bRecordChangesEnabled)
+ bChangeAllowed = !pDocShell->HasChangeRecordProtection();
+
+ if (bChangeAllowed)
+ pDocShell->SetChangeRecording(bRecordChangesEnabled);
+ }
+ else if ( aPropertyName == SC_UNO_ISADJUSTHEIGHTENABLED )
+ {
+ if( ScUnoHelpFunctions::GetBoolFromAny( aValue ) )
+ rDoc.UnlockAdjustHeight();
+ else
+ rDoc.LockAdjustHeight();
+ }
+ else if ( aPropertyName == SC_UNO_ISEXECUTELINKENABLED )
+ {
+ rDoc.EnableExecuteLink( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ }
+ else if ( aPropertyName == SC_UNO_ISCHANGEREADONLYENABLED )
+ {
+ rDoc.EnableChangeReadOnly( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ }
+ else if ( aPropertyName == "BuildId" )
+ {
+ aValue >>= maBuildId;
+ }
+ else if ( aPropertyName == "SavedObject" ) // set from chart after saving
+ {
+ OUString aObjName;
+ aValue >>= aObjName;
+ if ( !aObjName.isEmpty() )
+ rDoc.RestoreChartListener( aObjName );
+ }
+ else if ( aPropertyName == SC_UNO_INTEROPGRABBAG )
+ {
+ setGrabBagItem(aValue);
+ }
+
+ if ( aNewOpt != rOldOpt )
+ {
+ rDoc.SetDocOptions( aNewOpt );
+ //! Recalc only for options that need it?
+ if ( bHardRecalc )
+ pDocShell->DoHardRecalc();
+ pDocShell->SetDocumentModified();
+ }
+}
+
+uno::Any SAL_CALL ScModelObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ const ScDocOptions& rOpt = rDoc.GetDocOptions();
+ aRet = ScDocOptionsHelper::getPropertyValue( rOpt, aPropSet.getPropertyMap(), aPropertyName );
+ if ( aRet.hasValue() )
+ {
+ // done...
+ }
+ else if ( aPropertyName == SC_UNONAME_CLOCAL )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+
+ lang::Locale aLocale;
+ ScUnoConversion::FillLocale( aLocale, eLatin );
+ aRet <<= aLocale;
+ }
+ else if ( aPropertyName == SC_UNO_CODENAME )
+ {
+ aRet <<= rDoc.GetCodeName();
+ }
+
+ else if ( aPropertyName == SC_UNO_CJK_CLOCAL )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+
+ lang::Locale aLocale;
+ ScUnoConversion::FillLocale( aLocale, eCjk );
+ aRet <<= aLocale;
+ }
+ else if ( aPropertyName == SC_UNO_CTL_CLOCAL )
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+
+ lang::Locale aLocale;
+ ScUnoConversion::FillLocale( aLocale, eCtl );
+ aRet <<= aLocale;
+ }
+ else if ( aPropertyName == SC_UNO_NAMEDRANGES )
+ {
+ aRet <<= uno::Reference<sheet::XNamedRanges>(new ScGlobalNamedRangesObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_DATABASERNG )
+ {
+ aRet <<= uno::Reference<sheet::XDatabaseRanges>(new ScDatabaseRangesObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_UNNAMEDDBRNG )
+ {
+ aRet <<= uno::Reference<sheet::XUnnamedDatabaseRanges>(new ScUnnamedDatabaseRangesObj(pDocShell));
+ }
+ else if ( aPropertyName == SC_UNO_COLLABELRNG )
+ {
+ aRet <<= uno::Reference<sheet::XLabelRanges>(new ScLabelRangesObj( pDocShell, true ));
+ }
+ else if ( aPropertyName == SC_UNO_ROWLABELRNG )
+ {
+ aRet <<= uno::Reference<sheet::XLabelRanges>(new ScLabelRangesObj( pDocShell, false ));
+ }
+ else if ( aPropertyName == SC_UNO_AREALINKS )
+ {
+ aRet <<= uno::Reference<sheet::XAreaLinks>(new ScAreaLinksObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_DDELINKS )
+ {
+ aRet <<= uno::Reference<container::XNameAccess>(new ScDDELinksObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_EXTERNALDOCLINKS )
+ {
+ aRet <<= uno::Reference<sheet::XExternalDocLinks>(new ScExternalDocLinksObj(pDocShell));
+ }
+ else if ( aPropertyName == SC_UNO_SHEETLINKS )
+ {
+ aRet <<= uno::Reference<container::XNameAccess>(new ScSheetLinksObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_APPLYFMDES )
+ {
+ // default for no model is TRUE
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ bool bOpenInDesign = pModel == nullptr || pModel->GetOpenInDesignMode();
+ aRet <<= bOpenInDesign;
+ }
+ else if ( aPropertyName == SC_UNO_AUTOCONTFOC )
+ {
+ // default for no model is FALSE
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ bool bAutoControlFocus = pModel && pModel->GetAutoControlFocus();
+ aRet <<= bAutoControlFocus;
+ }
+ else if ( aPropertyName == SC_UNO_FORBIDDEN )
+ {
+ aRet <<= uno::Reference<i18n::XForbiddenCharacters>(new ScForbiddenCharsObj( pDocShell ));
+ }
+ else if ( aPropertyName == SC_UNO_HASDRAWPAGES )
+ {
+ aRet <<= (pDocShell->GetDocument().GetDrawLayer() != nullptr);
+ }
+ else if ( aPropertyName == SC_UNO_BASICLIBRARIES )
+ {
+ aRet <<= pDocShell->GetBasicContainer();
+ }
+ else if ( aPropertyName == SC_UNO_DIALOGLIBRARIES )
+ {
+ aRet <<= pDocShell->GetDialogContainer();
+ }
+ else if ( aPropertyName == SC_UNO_VBAGLOBNAME )
+ {
+ /* #i111553# This property provides the name of the constant that
+ will be used to store this model in the global Basic manager.
+ That constant will be equivalent to 'ThisComponent' but for
+ each application, so e.g. a 'ThisExcelDoc' and a 'ThisWordDoc'
+ constant can co-exist, as required by VBA. */
+ aRet <<= OUString( "ThisExcelDoc" );
+ }
+ else if ( aPropertyName == SC_UNO_RUNTIMEUID )
+ {
+ aRet <<= getRuntimeUID();
+ }
+ else if ( aPropertyName == SC_UNO_HASVALIDSIGNATURES )
+ {
+ aRet <<= hasValidSignatures();
+ }
+ else if ( aPropertyName == SC_UNO_ISLOADED )
+ {
+ aRet <<= !pDocShell->IsEmpty();
+ }
+ else if ( aPropertyName == SC_UNO_ISUNDOENABLED )
+ {
+ aRet <<= rDoc.IsUndoEnabled();
+ }
+ else if ( aPropertyName == SC_UNO_RECORDCHANGES )
+ {
+ aRet <<= pDocShell->IsChangeRecording();
+ }
+ else if ( aPropertyName == SC_UNO_ISRECORDCHANGESPROTECTED )
+ {
+ aRet <<= pDocShell->HasChangeRecordProtection();
+ }
+ else if ( aPropertyName == SC_UNO_ISADJUSTHEIGHTENABLED )
+ {
+ aRet <<= !( rDoc.IsAdjustHeightLocked() );
+ }
+ else if ( aPropertyName == SC_UNO_ISEXECUTELINKENABLED )
+ {
+ aRet <<= rDoc.IsExecuteLinkEnabled();
+ }
+ else if ( aPropertyName == SC_UNO_ISCHANGEREADONLYENABLED )
+ {
+ aRet <<= rDoc.IsChangeReadOnlyEnabled();
+ }
+ else if ( aPropertyName == SC_UNO_REFERENCEDEVICE )
+ {
+ rtl::Reference<VCLXDevice> pXDev = new VCLXDevice();
+ pXDev->SetOutputDevice( rDoc.GetRefDevice() );
+ aRet <<= uno::Reference< awt::XDevice >( pXDev );
+ }
+ else if ( aPropertyName == "BuildId" )
+ {
+ aRet <<= maBuildId;
+ }
+ else if ( aPropertyName == "InternalDocument" )
+ {
+ aRet <<= (pDocShell->GetCreateMode() == SfxObjectCreateMode::INTERNAL);
+ }
+ else if ( aPropertyName == SC_UNO_INTEROPGRABBAG )
+ {
+ getGrabBagItem(aRet);
+ }
+ }
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScModelObj )
+
+// XMultiServiceFactory
+
+css::uno::Reference<css::uno::XInterface> ScModelObj::create(
+ OUString const & aServiceSpecifier,
+ css::uno::Sequence<css::uno::Any> const * arguments)
+{
+ using ServiceType = ScServiceProvider::Type;
+
+ uno::Reference<uno::XInterface> xRet;
+ ServiceType nType = ScServiceProvider::GetProviderType(aServiceSpecifier);
+ if ( nType != ServiceType::INVALID )
+ {
+ // drawing layer tables must be kept as long as the model is alive
+ // return stored instance if already set
+ switch ( nType )
+ {
+ case ServiceType::GRADTAB: xRet.set(xDrawGradTab); break;
+ case ServiceType::HATCHTAB: xRet.set(xDrawHatchTab); break;
+ case ServiceType::BITMAPTAB: xRet.set(xDrawBitmapTab); break;
+ case ServiceType::TRGRADTAB: xRet.set(xDrawTrGradTab); break;
+ case ServiceType::MARKERTAB: xRet.set(xDrawMarkerTab); break;
+ case ServiceType::DASHTAB: xRet.set(xDrawDashTab); break;
+ case ServiceType::CHDATAPROV: xRet.set(xChartDataProv); break;
+ case ServiceType::VBAOBJECTPROVIDER: xRet.set(xObjProvider); break;
+ default: break;
+ }
+
+ // #i64497# If a chart is in a temporary document during clipboard paste,
+ // there should be no data provider, so that own data is used
+ bool bCreate =
+ ( nType != ServiceType::CHDATAPROV ||
+ ( pDocShell->GetCreateMode() != SfxObjectCreateMode::INTERNAL ));
+ // this should never happen, i.e. the temporary document should never be
+ // loaded, because this unlinks the data
+ assert(bCreate);
+
+ if ( !xRet.is() && bCreate )
+ {
+ xRet.set(ScServiceProvider::MakeInstance( nType, pDocShell ));
+
+ // store created instance
+ switch ( nType )
+ {
+ case ServiceType::GRADTAB: xDrawGradTab.set(xRet); break;
+ case ServiceType::HATCHTAB: xDrawHatchTab.set(xRet); break;
+ case ServiceType::BITMAPTAB: xDrawBitmapTab.set(xRet); break;
+ case ServiceType::TRGRADTAB: xDrawTrGradTab.set(xRet); break;
+ case ServiceType::MARKERTAB: xDrawMarkerTab.set(xRet); break;
+ case ServiceType::DASHTAB: xDrawDashTab.set(xRet); break;
+ case ServiceType::CHDATAPROV: xChartDataProv.set(xRet); break;
+ case ServiceType::VBAOBJECTPROVIDER: xObjProvider.set(xRet); break;
+ default: break;
+ }
+ }
+ }
+ else
+ {
+ // we offload everything we don't know to SvxFmMSFactory,
+ // it'll throw exception if this isn't okay ...
+
+ try
+ {
+ xRet = arguments == nullptr
+ ? SvxFmMSFactory::createInstance(aServiceSpecifier)
+ : SvxFmMSFactory::createInstanceWithArguments(
+ aServiceSpecifier, *arguments);
+ // extra block to force deletion of the temporary before ScShapeObj ctor (setDelegator)
+ }
+ catch ( lang::ServiceNotRegisteredException & )
+ {
+ }
+
+ // if the drawing factory created a shape, a ScShapeObj has to be used
+ // to support own properties like ImageMap:
+
+ uno::Reference<drawing::XShape> xShape( xRet, uno::UNO_QUERY );
+ if ( xShape.is() )
+ {
+ xRet.clear(); // for aggregation, xShape must be the object's only ref
+ new ScShapeObj( xShape ); // aggregates object and modifies xShape
+ xRet.set(xShape);
+ }
+ }
+ return xRet;
+}
+
+uno::Reference<uno::XInterface> SAL_CALL ScModelObj::createInstance(
+ const OUString& aServiceSpecifier )
+{
+ SolarMutexGuard aGuard;
+ return create(aServiceSpecifier, nullptr);
+}
+
+uno::Reference<uno::XInterface> SAL_CALL ScModelObj::createInstanceWithArguments(
+ const OUString& ServiceSpecifier,
+ const uno::Sequence<uno::Any>& aArgs )
+{
+ //! distinguish between own services and those of drawing layer?
+
+ SolarMutexGuard aGuard;
+ uno::Reference<uno::XInterface> xInt(create(ServiceSpecifier, &aArgs));
+
+ if ( aArgs.hasElements() )
+ {
+ // used only for cell value binding so far - it can be initialized after creating
+
+ uno::Reference<lang::XInitialization> xInit( xInt, uno::UNO_QUERY );
+ if ( xInit.is() )
+ xInit->initialize( aArgs );
+ }
+
+ return xInt;
+}
+
+uno::Sequence<OUString> SAL_CALL ScModelObj::getAvailableServiceNames()
+{
+ SolarMutexGuard aGuard;
+
+ return comphelper::concatSequences( ScServiceProvider::GetAllServiceNames(),
+ SvxFmMSFactory::getAvailableServiceNames() );
+}
+
+// XServiceInfo
+OUString SAL_CALL ScModelObj::getImplementationName()
+{
+ return "ScModelObj";
+ /* // Matching the .component information:
+ return OUString( "com.sun.star.comp.Calc.SpreadsheetDocument" );
+ */
+}
+
+sal_Bool SAL_CALL ScModelObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScModelObj::getSupportedServiceNames()
+{
+ return {SCMODELOBJ_SERVICE, SCDOCSETTINGS_SERVICE, SCDOC_SERVICE};
+}
+
+// XUnoTunnel
+
+sal_Int64 SAL_CALL ScModelObj::getSomething(
+ const uno::Sequence<sal_Int8 >& rId )
+{
+ if ( comphelper::isUnoTunnelId<ScModelObj>(rId) )
+ {
+ return comphelper::getSomething_cast(this);
+ }
+
+ if ( comphelper::isUnoTunnelId<SfxObjectShell>(rId) )
+ {
+ return comphelper::getSomething_cast(pDocShell);
+ }
+
+ // aggregated number formats supplier has XUnoTunnel, too
+ // interface from aggregated object must be obtained via queryAggregation
+
+ sal_Int64 nRet = SfxBaseModel::getSomething( rId );
+ if ( nRet )
+ return nRet;
+
+ if ( GetFormatter().is() )
+ {
+ const uno::Type& rTunnelType = cppu::UnoType<lang::XUnoTunnel>::get();
+ uno::Any aNumTunnel(xNumberAgg->queryAggregation(rTunnelType));
+ if(auto xTunnelAgg = o3tl::tryAccess<uno::Reference<lang::XUnoTunnel>>(
+ aNumTunnel))
+ {
+ return (*xTunnelAgg)->getSomething( rId );
+ }
+ }
+
+ return 0;
+}
+
+const uno::Sequence<sal_Int8>& ScModelObj::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theScModelObjUnoTunnelId;
+ return theScModelObjUnoTunnelId.getSeq();
+}
+
+// XChangesNotifier
+
+void ScModelObj::addChangesListener( const uno::Reference< util::XChangesListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+ maChangesListeners.addInterface( aListener );
+}
+
+void ScModelObj::removeChangesListener( const uno::Reference< util::XChangesListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+ maChangesListeners.removeInterface( aListener );
+}
+
+bool ScModelObj::HasChangesListeners() const
+{
+ if ( maChangesListeners.getLength() > 0 )
+ return true;
+
+ // "change" event set in any sheet?
+ return pDocShell && pDocShell->GetDocument().HasAnySheetEventScript(ScSheetEventId::CHANGE);
+}
+
+void ScModelObj::NotifyChanges( const OUString& rOperation, const ScRangeList& rRanges,
+ const uno::Sequence< beans::PropertyValue >& rProperties )
+{
+ if ( pDocShell && HasChangesListeners() )
+ {
+ util::ChangesEvent aEvent;
+ aEvent.Source.set( static_cast< cppu::OWeakObject* >( this ) );
+ aEvent.Base <<= aEvent.Source;
+
+ size_t nRangeCount = rRanges.size();
+ aEvent.Changes.realloc( static_cast< sal_Int32 >( nRangeCount ) );
+ auto pChanges = aEvent.Changes.getArray();
+ for ( size_t nIndex = 0; nIndex < nRangeCount; ++nIndex )
+ {
+ uno::Reference< table::XCellRange > xRangeObj;
+
+ ScRange const & rRange = rRanges[ nIndex ];
+ if ( rRange.aStart == rRange.aEnd )
+ {
+ xRangeObj.set( new ScCellObj( pDocShell, rRange.aStart ) );
+ }
+ else
+ {
+ xRangeObj.set( new ScCellRangeObj( pDocShell, rRange ) );
+ }
+
+ util::ElementChange& rChange = pChanges[ static_cast< sal_Int32 >( nIndex ) ];
+ rChange.Accessor <<= rOperation;
+ rChange.Element <<= rProperties;
+ rChange.ReplacedElement <<= xRangeObj;
+ }
+
+ ::comphelper::OInterfaceIteratorHelper3 aIter( maChangesListeners );
+ while ( aIter.hasMoreElements() )
+ {
+ try
+ {
+ aIter.next()->changesOccurred( aEvent );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ }
+
+ // handle sheet events
+ //! separate method with ScMarkData? Then change HasChangesListeners back.
+ if ( !(rOperation == "cell-change" && pDocShell) )
+ return;
+
+ ScMarkData aMarkData(pDocShell->GetDocument().GetSheetLimits());
+ aMarkData.MarkFromRangeList( rRanges, false );
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (const SCTAB& nTab : aMarkData)
+ {
+ if (nTab >= nTabCount)
+ break;
+ const ScSheetEvents* pEvents = rDoc.GetSheetEvents(nTab);
+ if (pEvents)
+ {
+ const OUString* pScript = pEvents->GetScript(ScSheetEventId::CHANGE);
+ if (pScript)
+ {
+ ScRangeList aTabRanges; // collect ranges on this sheet
+ size_t nRangeCount = rRanges.size();
+ for ( size_t nIndex = 0; nIndex < nRangeCount; ++nIndex )
+ {
+ ScRange const & rRange = rRanges[ nIndex ];
+ if ( rRange.aStart.Tab() == nTab )
+ aTabRanges.push_back( rRange );
+ }
+ size_t nTabRangeCount = aTabRanges.size();
+ if ( nTabRangeCount > 0 )
+ {
+ uno::Reference<uno::XInterface> xTarget;
+ if ( nTabRangeCount == 1 )
+ {
+ ScRange const & rRange = aTabRanges[ 0 ];
+ if ( rRange.aStart == rRange.aEnd )
+ xTarget.set( static_cast<cppu::OWeakObject*>( new ScCellObj( pDocShell, rRange.aStart ) ) );
+ else
+ xTarget.set( static_cast<cppu::OWeakObject*>( new ScCellRangeObj( pDocShell, rRange ) ) );
+ }
+ else
+ xTarget.set( static_cast<cppu::OWeakObject*>( new ScCellRangesObj( pDocShell, aTabRanges ) ) );
+
+ uno::Sequence<uno::Any> aParams{ uno::Any(xTarget) };
+
+ uno::Any aRet;
+ uno::Sequence<sal_Int16> aOutArgsIndex;
+ uno::Sequence<uno::Any> aOutArgs;
+
+ /*ErrCode eRet =*/ pDocShell->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
+ }
+ }
+ }
+ }
+}
+
+void ScModelObj::HandleCalculateEvents()
+{
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ // don't call events before the document is visible
+ // (might also set a flag on SfxEventHintId::LoadFinished and only disable while loading)
+ if ( rDoc.IsDocVisible() )
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab = 0; nTab < nTabCount; nTab++)
+ {
+ if (rDoc.HasCalcNotification(nTab))
+ {
+ if (const ScSheetEvents* pEvents = rDoc.GetSheetEvents( nTab ))
+ {
+ if (const OUString* pScript = pEvents->GetScript(ScSheetEventId::CALCULATE))
+ {
+ uno::Any aRet;
+ uno::Sequence<uno::Any> aParams;
+ uno::Sequence<sal_Int16> aOutArgsIndex;
+ uno::Sequence<uno::Any> aOutArgs;
+ pDocShell->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
+ }
+ }
+
+ try
+ {
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( rDoc.GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ uno::Sequence< uno::Any > aArgs{ uno::Any(nTab) };
+ xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( ScSheetEventId::CALCULATE ), aArgs );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ }
+ }
+ rDoc.ResetCalcNotifications();
+}
+
+// XOpenCLSelection
+
+sal_Bool ScModelObj::isOpenCLEnabled()
+{
+ return ScCalcConfig::isOpenCLEnabled();
+}
+
+void ScModelObj::enableOpenCL(sal_Bool bEnable)
+{
+ if (ScCalcConfig::isOpenCLEnabled() == static_cast<bool>(bEnable))
+ return;
+ if (ScCalcConfig::getForceCalculationType() != ForceCalculationNone)
+ return;
+
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Misc::UseOpenCL::set(bEnable, batch);
+ batch->commit();
+
+ ScCalcConfig aConfig = ScInterpreter::GetGlobalConfig();
+ if (bEnable)
+ aConfig.setOpenCLConfigToDefault();
+ ScInterpreter::SetGlobalConfig(aConfig);
+
+#if HAVE_FEATURE_OPENCL
+ sc::FormulaGroupInterpreter::switchOpenCLDevice(OUString(), true);
+#endif
+
+ ScDocument* pDoc = GetDocument();
+ pDoc->CheckVectorizationState();
+
+}
+
+void ScModelObj::enableAutomaticDeviceSelection(sal_Bool bForce)
+{
+ ScCalcConfig aConfig = ScInterpreter::GetGlobalConfig();
+ aConfig.mbOpenCLAutoSelect = true;
+ ScInterpreter::SetGlobalConfig(aConfig);
+ ScFormulaOptions aOptions = SC_MOD()->GetFormulaOptions();
+ aOptions.SetCalcConfig(aConfig);
+ SC_MOD()->SetFormulaOptions(aOptions);
+#if !HAVE_FEATURE_OPENCL
+ (void) bForce;
+#else
+ sc::FormulaGroupInterpreter::switchOpenCLDevice(OUString(), true, bForce);
+#endif
+}
+
+void ScModelObj::disableAutomaticDeviceSelection()
+{
+ ScCalcConfig aConfig = ScInterpreter::GetGlobalConfig();
+ aConfig.mbOpenCLAutoSelect = false;
+ ScInterpreter::SetGlobalConfig(aConfig);
+ ScFormulaOptions aOptions = SC_MOD()->GetFormulaOptions();
+ aOptions.SetCalcConfig(aConfig);
+ SC_MOD()->SetFormulaOptions(aOptions);
+}
+
+void ScModelObj::selectOpenCLDevice( sal_Int32 nPlatform, sal_Int32 nDevice )
+{
+ if(nPlatform < 0 || nDevice < 0)
+ throw uno::RuntimeException();
+
+#if !HAVE_FEATURE_OPENCL
+ throw uno::RuntimeException();
+#else
+ std::vector<OpenCLPlatformInfo> aPlatformInfo;
+ sc::FormulaGroupInterpreter::fillOpenCLInfo(aPlatformInfo);
+ if(o3tl::make_unsigned(nPlatform) >= aPlatformInfo.size())
+ throw uno::RuntimeException();
+
+ if(o3tl::make_unsigned(nDevice) >= aPlatformInfo[nPlatform].maDevices.size())
+ throw uno::RuntimeException();
+
+ OUString aDeviceString = aPlatformInfo[nPlatform].maVendor + " " + aPlatformInfo[nPlatform].maDevices[nDevice].maName;
+ sc::FormulaGroupInterpreter::switchOpenCLDevice(aDeviceString, false);
+#endif
+}
+
+sal_Int32 ScModelObj::getPlatformID()
+{
+#if !HAVE_FEATURE_OPENCL
+ return -1;
+#else
+ sal_Int32 nPlatformId;
+ sal_Int32 nDeviceId;
+ sc::FormulaGroupInterpreter::getOpenCLDeviceInfo(nDeviceId, nPlatformId);
+ return nPlatformId;
+#endif
+}
+
+sal_Int32 ScModelObj::getDeviceID()
+{
+#if !HAVE_FEATURE_OPENCL
+ return -1;
+#else
+ sal_Int32 nPlatformId;
+ sal_Int32 nDeviceId;
+ sc::FormulaGroupInterpreter::getOpenCLDeviceInfo(nDeviceId, nPlatformId);
+ return nDeviceId;
+#endif
+}
+
+uno::Sequence< sheet::opencl::OpenCLPlatform > ScModelObj::getOpenCLPlatforms()
+{
+#if !HAVE_FEATURE_OPENCL
+ return uno::Sequence<sheet::opencl::OpenCLPlatform>();
+#else
+ std::vector<OpenCLPlatformInfo> aPlatformInfo;
+ sc::FormulaGroupInterpreter::fillOpenCLInfo(aPlatformInfo);
+
+ uno::Sequence<sheet::opencl::OpenCLPlatform> aRet(aPlatformInfo.size());
+ auto aRetRange = asNonConstRange(aRet);
+ for(size_t i = 0; i < aPlatformInfo.size(); ++i)
+ {
+ aRetRange[i].Name = aPlatformInfo[i].maName;
+ aRetRange[i].Vendor = aPlatformInfo[i].maVendor;
+
+ aRetRange[i].Devices.realloc(aPlatformInfo[i].maDevices.size());
+ auto pDevices = aRetRange[i].Devices.getArray();
+ for(size_t j = 0; j < aPlatformInfo[i].maDevices.size(); ++j)
+ {
+ const OpenCLDeviceInfo& rDevice = aPlatformInfo[i].maDevices[j];
+ pDevices[j].Name = rDevice.maName;
+ pDevices[j].Vendor = rDevice.maVendor;
+ pDevices[j].Driver = rDevice.maDriver;
+ }
+ }
+
+ return aRet;
+#endif
+}
+
+namespace {
+
+/// @throws css::uno::RuntimeException
+void setOpcodeSubsetTest(bool bFlag)
+{
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Calc::Formula::Calculation::OpenCLSubsetOnly::set(bFlag, batch);
+ batch->commit();
+}
+
+}
+
+void ScModelObj::enableOpcodeSubsetTest()
+{
+ setOpcodeSubsetTest(true);
+}
+
+void ScModelObj::disableOpcodeSubsetTest()
+{
+ setOpcodeSubsetTest(false);
+}
+
+sal_Bool ScModelObj::isOpcodeSubsetTested()
+{
+ return officecfg::Office::Calc::Formula::Calculation::OpenCLSubsetOnly::get();
+}
+
+void ScModelObj::setFormulaCellNumberLimit( sal_Int32 number )
+{
+ std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
+ officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::set(number, batch);
+ batch->commit();
+}
+
+sal_Int32 ScModelObj::getFormulaCellNumberLimit()
+{
+ return officecfg::Office::Calc::Formula::Calculation::OpenCLMinimumDataSize::get();
+}
+
+ScDrawPagesObj::ScDrawPagesObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDrawPagesObj::~ScDrawPagesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDrawPagesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // we don't care about update of references here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+uno::Reference<drawing::XDrawPage> ScDrawPagesObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
+{
+ if (pDocShell)
+ {
+ ScDrawLayer* pDrawLayer = pDocShell->MakeDrawLayer();
+ OSL_ENSURE(pDrawLayer,"Cannot create Draw-Layer");
+ if ( pDrawLayer && nIndex >= 0 && nIndex < pDocShell->GetDocument().GetTableCount() )
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nIndex));
+ OSL_ENSURE(pPage,"Draw-Page not found");
+ if (pPage)
+ {
+ return uno::Reference<drawing::XDrawPage> (pPage->getUnoPage(), uno::UNO_QUERY);
+ }
+ }
+ }
+ return nullptr;
+}
+
+// XDrawPages
+
+uno::Reference<drawing::XDrawPage> SAL_CALL ScDrawPagesObj::insertNewByIndex( sal_Int32 nPos )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<drawing::XDrawPage> xRet;
+ if (pDocShell)
+ {
+ OUString aNewName;
+ pDocShell->GetDocument().CreateValidTabName(aNewName);
+ if ( pDocShell->GetDocFunc().InsertTable( static_cast<SCTAB>(nPos),
+ aNewName, true, true ) )
+ xRet.set(GetObjectByIndex_Impl( nPos ));
+ }
+ return xRet;
+}
+
+void SAL_CALL ScDrawPagesObj::remove( const uno::Reference<drawing::XDrawPage>& xPage )
+{
+ SolarMutexGuard aGuard;
+ SvxDrawPage* pImp = comphelper::getFromUnoTunnel<SvxDrawPage>( xPage );
+ if ( pDocShell && pImp )
+ {
+ SdrPage* pPage = pImp->GetSdrPage();
+ if (pPage)
+ {
+ SCTAB nPageNum = static_cast<SCTAB>(pPage->GetPageNum());
+ pDocShell->GetDocFunc().DeleteTable( nPageNum, true );
+ }
+ }
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDrawPagesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return pDocShell->GetDocument().GetTableCount();
+ return 0;
+}
+
+uno::Any SAL_CALL ScDrawPagesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<drawing::XDrawPage> xPage(GetObjectByIndex_Impl(nIndex));
+ if (!xPage.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xPage);
+}
+
+uno::Type SAL_CALL ScDrawPagesObj::getElementType()
+{
+ return cppu::UnoType<drawing::XDrawPage>::get();
+}
+
+sal_Bool SAL_CALL ScDrawPagesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+ScTableSheetsObj::ScTableSheetsObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScTableSheetsObj::~ScTableSheetsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScTableSheetsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // we don't care about update of references here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XSpreadsheets
+
+rtl::Reference<ScTableSheetObj> ScTableSheetsObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
+{
+ if ( pDocShell && nIndex >= 0 && nIndex < pDocShell->GetDocument().GetTableCount() )
+ return new ScTableSheetObj( pDocShell, static_cast<SCTAB>(nIndex) );
+
+ return nullptr;
+}
+
+rtl::Reference<ScTableSheetObj> ScTableSheetsObj::GetObjectByName_Impl(const OUString& aName) const
+{
+ if (pDocShell)
+ {
+ SCTAB nIndex;
+ if ( pDocShell->GetDocument().GetTable( aName, nIndex ) )
+ return new ScTableSheetObj( pDocShell, nIndex );
+ }
+ return nullptr;
+}
+
+void SAL_CALL ScTableSheetsObj::insertNewByName( const OUString& aName, sal_Int16 nPosition )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ bDone = pDocShell->GetDocFunc().InsertTable( nPosition, aName, true, true );
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScTableSheetsObj::moveByName( const OUString& aName, sal_Int16 nDestination )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ SCTAB nSource;
+ if ( pDocShell->GetDocument().GetTable( aName, nSource ) )
+ bDone = pDocShell->MoveTable( nSource, nDestination, false, true );
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScTableSheetsObj::copyByName( const OUString& aName,
+ const OUString& aCopy, sal_Int16 nDestination )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ SCTAB nSource;
+ if ( pDocShell->GetDocument().GetTable( aName, nSource ) )
+ {
+ bDone = pDocShell->MoveTable( nSource, nDestination, true, true );
+ if (bDone)
+ {
+ // #i92477# any index past the last sheet means "append" in MoveTable
+ SCTAB nResultTab = static_cast<SCTAB>(nDestination);
+ SCTAB nTabCount = pDocShell->GetDocument().GetTableCount(); // count after copying
+ if (nResultTab >= nTabCount)
+ nResultTab = nTabCount - 1;
+
+ bDone = pDocShell->GetDocFunc().RenameTable( nResultTab, aCopy,
+ true, true );
+ }
+ }
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScTableSheetsObj::insertByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ bool bIllArg = false;
+
+ //! Type of aElement can be some specific interface instead of XInterface
+
+ if ( pDocShell )
+ {
+ uno::Reference<uno::XInterface> xInterface(aElement, uno::UNO_QUERY);
+ if ( xInterface.is() )
+ {
+ ScTableSheetObj* pSheetObj = comphelper::getFromUnoTunnel<ScTableSheetObj>( xInterface );
+ if ( pSheetObj && !pSheetObj->GetDocShell() ) // not inserted yet?
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nDummy;
+ if ( rDoc.GetTable( aName, nDummy ) )
+ {
+ // name already exists
+ throw container::ElementExistException();
+ }
+ SCTAB nPosition = rDoc.GetTableCount();
+ bDone = pDocShell->GetDocFunc().InsertTable( nPosition, aName,
+ true, true );
+ if (bDone)
+ pSheetObj->InitInsertSheet( pDocShell, nPosition );
+ // set document and new range in the object
+ }
+ else
+ bIllArg = true;
+ }
+ else
+ bIllArg = true;
+ }
+
+ if (!bDone)
+ {
+ if (bIllArg)
+ throw lang::IllegalArgumentException();
+ else
+ throw uno::RuntimeException(); // ElementExistException is handled above
+ }
+}
+
+void SAL_CALL ScTableSheetsObj::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ bool bIllArg = false;
+
+ //! Type of aElement can be some specific interface instead of XInterface
+
+ if ( pDocShell )
+ {
+ uno::Reference<uno::XInterface> xInterface(aElement, uno::UNO_QUERY);
+ if ( xInterface.is() )
+ {
+ ScTableSheetObj* pSheetObj = comphelper::getFromUnoTunnel<ScTableSheetObj>( xInterface );
+ if ( pSheetObj && !pSheetObj->GetDocShell() ) // not inserted yet?
+ {
+ SCTAB nPosition;
+ if ( !pDocShell->GetDocument().GetTable( aName, nPosition ) )
+ {
+ // not found
+ throw container::NoSuchElementException();
+ }
+
+ if ( pDocShell->GetDocFunc().DeleteTable( nPosition, true ) )
+ {
+ // InsertTable can't really go wrong now
+ bDone = pDocShell->GetDocFunc().InsertTable( nPosition, aName, true, true );
+ if (bDone)
+ pSheetObj->InitInsertSheet( pDocShell, nPosition );
+ }
+
+ }
+ else
+ bIllArg = true;
+ }
+ else
+ bIllArg = true;
+ }
+
+ if (!bDone)
+ {
+ if (bIllArg)
+ throw lang::IllegalArgumentException();
+ else
+ throw uno::RuntimeException(); // NoSuchElementException is handled above
+ }
+}
+
+void SAL_CALL ScTableSheetsObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ SCTAB nIndex;
+ if ( !pDocShell->GetDocument().GetTable( aName, nIndex ) )
+ throw container::NoSuchElementException(); // not found
+ bDone = pDocShell->GetDocFunc().DeleteTable( nIndex, true );
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException(); // NoSuchElementException is handled above
+}
+
+sal_Int32 ScTableSheetsObj::importSheet(
+ const uno::Reference < sheet::XSpreadsheetDocument > & xDocSrc,
+ const OUString& srcName, const sal_Int32 nDestPosition )
+{
+ //pDocShell is the destination
+ ScDocument& rDocDest = pDocShell->GetDocument();
+
+ // Source document docShell
+ if ( !xDocSrc.is() )
+ throw uno::RuntimeException();
+ ScModelObj* pObj = comphelper::getFromUnoTunnel<ScModelObj>(xDocSrc);
+ ScDocShell* pDocShellSrc = static_cast<ScDocShell*>(pObj->GetEmbeddedObject());
+
+ // SourceSheet Position and does srcName exists ?
+ SCTAB nIndexSrc;
+ if ( !pDocShellSrc->GetDocument().GetTable( srcName, nIndexSrc ) )
+ throw lang::IllegalArgumentException();
+
+ // Check the validity of destination index.
+ SCTAB nCount = rDocDest.GetTableCount();
+ SCTAB nIndexDest = static_cast<SCTAB>(nDestPosition);
+ if (nIndexDest > nCount || nIndexDest < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ // Transfer Tab
+ pDocShell->TransferTab(
+ *pDocShellSrc, nIndexSrc, nIndexDest, true/*bInsertNew*/, true/*bNotifyAndPaint*/ );
+
+ return nIndexDest;
+}
+
+// XCellRangesAccess
+
+uno::Reference< table::XCell > SAL_CALL ScTableSheetsObj::getCellByPosition( sal_Int32 nColumn, sal_Int32 nRow, sal_Int32 nSheet )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<ScTableSheetObj> xSheet = GetObjectByIndex_Impl(static_cast<sal_uInt16>(nSheet));
+ if (! xSheet.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return xSheet->getCellByPosition(nColumn, nRow);
+}
+
+uno::Reference< table::XCellRange > SAL_CALL ScTableSheetsObj::getCellRangeByPosition( sal_Int32 nLeft, sal_Int32 nTop, sal_Int32 nRight, sal_Int32 nBottom, sal_Int32 nSheet )
+{
+ SolarMutexGuard aGuard;
+ rtl::Reference<ScTableSheetObj> xSheet = GetObjectByIndex_Impl(static_cast<sal_uInt16>(nSheet));
+ if (! xSheet.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return xSheet->getCellRangeByPosition(nLeft, nTop, nRight, nBottom);
+}
+
+uno::Sequence < uno::Reference< table::XCellRange > > SAL_CALL ScTableSheetsObj::getCellRangesByName( const OUString& aRange )
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence < uno::Reference < table::XCellRange > > xRet;
+
+ ScRangeList aRangeList;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (!ScRangeStringConverter::GetRangeListFromString( aRangeList, aRange, rDoc, ::formula::FormulaGrammar::CONV_OOO, ';' ))
+ throw lang::IllegalArgumentException();
+
+ size_t nCount = aRangeList.size();
+ if (!nCount)
+ throw lang::IllegalArgumentException();
+
+ xRet.realloc(nCount);
+ auto pRet = xRet.getArray();
+ for( size_t nIndex = 0; nIndex < nCount; nIndex++ )
+ {
+ const ScRange & rRange = aRangeList[ nIndex ];
+ pRet[nIndex] = new ScCellRangeObj(pDocShell, rRange);
+ }
+
+ return xRet;
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScTableSheetsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.SpreadsheetsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScTableSheetsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ return pDocShell->GetDocument().GetTableCount();
+ return 0;
+}
+
+uno::Any SAL_CALL ScTableSheetsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XSpreadsheet> xSheet(GetObjectByIndex_Impl(nIndex));
+ if (!xSheet.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xSheet);
+
+// return uno::Any();
+}
+
+uno::Type SAL_CALL ScTableSheetsObj::getElementType()
+{
+ return cppu::UnoType<sheet::XSpreadsheet>::get();
+}
+
+sal_Bool SAL_CALL ScTableSheetsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XNameAccess
+
+uno::Any SAL_CALL ScTableSheetsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XSpreadsheet> xSheet(GetObjectByName_Impl(aName));
+ if (!xSheet.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xSheet);
+}
+
+uno::Sequence<OUString> SAL_CALL ScTableSheetsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nCount = rDoc.GetTableCount();
+ OUString aName;
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ for (SCTAB i=0; i<nCount; i++)
+ {
+ rDoc.GetName( i, aName );
+ pAry[i] = aName;
+ }
+ return aSeq;
+ }
+ return uno::Sequence<OUString>();
+}
+
+sal_Bool SAL_CALL ScTableSheetsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ SCTAB nIndex;
+ if ( pDocShell->GetDocument().GetTable( aName, nIndex ) )
+ return true;
+ }
+ return false;
+}
+
+ScTableColumnsObj::ScTableColumnsObj(ScDocShell* pDocSh, SCTAB nT, SCCOL nSC, SCCOL nEC) :
+ pDocShell( pDocSh ),
+ nTab ( nT ),
+ nStartCol( nSC ),
+ nEndCol ( nEC )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScTableColumnsObj::~ScTableColumnsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScTableColumnsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! update of references for sheet and its start/end
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XTableColumns
+
+rtl::Reference<ScTableColumnObj> ScTableColumnsObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
+{
+ SCCOL nCol = static_cast<SCCOL>(nIndex) + nStartCol;
+ if ( pDocShell && nCol <= nEndCol )
+ return new ScTableColumnObj( pDocShell, nCol, nTab );
+
+ return nullptr; // wrong index
+}
+
+rtl::Reference<ScTableColumnObj> ScTableColumnsObj::GetObjectByName_Impl(const OUString& aName) const
+{
+ SCCOL nCol = 0;
+ if (pDocShell && ::AlphaToCol(pDocShell->GetDocument(), nCol, aName))
+ if (nCol >= nStartCol && nCol <= nEndCol)
+ return new ScTableColumnObj( pDocShell, nCol, nTab );
+
+ return nullptr;
+}
+
+void SAL_CALL ScTableColumnsObj::insertByIndex( sal_Int32 nPosition, sal_Int32 nCount )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if ( pDocShell )
+ {
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ if ( nCount > 0 && nPosition >= 0 && nStartCol+nPosition <= nEndCol &&
+ nStartCol+nPosition+nCount-1 <= rDoc.MaxCol() )
+ {
+ ScRange aRange( static_cast<SCCOL>(nStartCol+nPosition), 0, nTab,
+ static_cast<SCCOL>(nStartCol+nPosition+nCount-1), rDoc.MaxRow(), nTab );
+ bDone = pDocShell->GetDocFunc().InsertCells( aRange, nullptr, INS_INSCOLS_BEFORE, true, true );
+ }
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScTableColumnsObj::removeByIndex( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ // the range to be deleted has to lie within the object
+ if ( pDocShell )
+ {
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ if ( nCount > 0 && nIndex >= 0 && nStartCol+nIndex+nCount-1 <= nEndCol )
+ {
+ ScRange aRange( static_cast<SCCOL>(nStartCol+nIndex), 0, nTab,
+ static_cast<SCCOL>(nStartCol+nIndex+nCount-1), rDoc.MaxRow(), nTab );
+ bDone = pDocShell->GetDocFunc().DeleteCells( aRange, nullptr, DelCellCmd::Cols, true );
+ }
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScTableColumnsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.table.TableColumnsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScTableColumnsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return nEndCol - nStartCol + 1;
+}
+
+uno::Any SAL_CALL ScTableColumnsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XCellRange> xColumn(GetObjectByIndex_Impl(nIndex));
+ if (!xColumn.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xColumn);
+
+}
+
+uno::Type SAL_CALL ScTableColumnsObj::getElementType()
+{
+ return cppu::UnoType<table::XCellRange>::get();
+}
+
+sal_Bool SAL_CALL ScTableColumnsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Any SAL_CALL ScTableColumnsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XCellRange> xColumn(GetObjectByName_Impl(aName));
+ if (!xColumn.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xColumn);
+}
+
+uno::Sequence<OUString> SAL_CALL ScTableColumnsObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ SCCOL nCount = nEndCol - nStartCol + 1;
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ for (SCCOL i=0; i<nCount; i++)
+ pAry[i] = ::ScColToAlpha( nStartCol + i );
+
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScTableColumnsObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ SCCOL nCol = 0;
+ if (pDocShell && ::AlphaToCol(pDocShell->GetDocument(), nCol, aName))
+ if (nCol >= nStartCol && nCol <= nEndCol)
+ return true;
+
+ return false; // not found
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableColumnsObj::getPropertySetInfo()
+{
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( lcl_GetColumnsPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScTableColumnsObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ throw uno::RuntimeException();
+
+ std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(nStartCol,nEndCol));
+ ScDocFunc& rFunc = pDocShell->GetDocFunc();
+
+ if ( aPropertyName == SC_UNONAME_CELLWID )
+ {
+ sal_Int32 nNewWidth = 0;
+ if ( aValue >>= nNewWidth )
+ rFunc.SetWidthOrHeight(
+ true, aColArr, nTab, SC_SIZE_ORIGINAL, o3tl::toTwips(nNewWidth, o3tl::Length::mm100), true, true);
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLVIS )
+ {
+ bool bVis = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ ScSizeMode eMode = bVis ? SC_SIZE_SHOW : SC_SIZE_DIRECT;
+ rFunc.SetWidthOrHeight(true, aColArr, nTab, eMode, 0, true, true);
+ // SC_SIZE_DIRECT with size 0: hide
+ }
+ else if ( aPropertyName == SC_UNONAME_OWIDTH )
+ {
+ bool bOpt = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bOpt)
+ rFunc.SetWidthOrHeight(
+ true, aColArr, nTab, SC_SIZE_OPTIMAL, STD_EXTRA_WIDTH, true, true);
+ // sal_False for columns currently has no effect
+ }
+ else if ( aPropertyName == SC_UNONAME_NEWPAGE || aPropertyName == SC_UNONAME_MANPAGE )
+ {
+ //! single function to set/remove all breaks?
+ bool bSet = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
+ if (bSet)
+ rFunc.InsertPageBreak( true, ScAddress(nCol,0,nTab), true, true );
+ else
+ rFunc.RemovePageBreak( true, ScAddress(nCol,0,nTab), true, true );
+ }
+}
+
+uno::Any SAL_CALL ScTableColumnsObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ uno::Any aAny;
+
+ //! loop over all columns for current state?
+
+ if ( aPropertyName == SC_UNONAME_CELLWID )
+ {
+ // for hidden column, return original height
+ sal_uInt16 nWidth = rDoc.GetOriginalWidth( nStartCol, nTab );
+ aAny <<= static_cast<sal_Int32>(convertTwipToMm100(nWidth));
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLVIS )
+ {
+ bool bVis = !rDoc.ColHidden(nStartCol, nTab);
+ aAny <<= bVis;
+ }
+ else if ( aPropertyName == SC_UNONAME_OWIDTH )
+ {
+ bool bOpt = !(rDoc.GetColFlags( nStartCol, nTab ) & CRFlags::ManualSize);
+ aAny <<= bOpt;
+ }
+ else if ( aPropertyName == SC_UNONAME_NEWPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasColBreak(nStartCol, nTab);
+ aAny <<= (nBreak != ScBreakType::NONE);
+ }
+ else if ( aPropertyName == SC_UNONAME_MANPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasColBreak(nStartCol, nTab);
+ aAny <<= bool(nBreak & ScBreakType::Manual);
+ }
+
+ return aAny;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScTableColumnsObj )
+
+ScTableRowsObj::ScTableRowsObj(ScDocShell* pDocSh, SCTAB nT, SCROW nSR, SCROW nER) :
+ pDocShell( pDocSh ),
+ nTab ( nT ),
+ nStartRow( nSR ),
+ nEndRow ( nER )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScTableRowsObj::~ScTableRowsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScTableRowsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! update of references for sheet and its start/end
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XTableRows
+
+rtl::Reference<ScTableRowObj> ScTableRowsObj::GetObjectByIndex_Impl(sal_Int32 nIndex) const
+{
+ SCROW nRow = static_cast<SCROW>(nIndex) + nStartRow;
+ if ( pDocShell && nRow <= nEndRow )
+ return new ScTableRowObj( pDocShell, nRow, nTab );
+
+ return nullptr; // wrong index
+}
+
+void SAL_CALL ScTableRowsObj::insertByIndex( sal_Int32 nPosition, sal_Int32 nCount )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if ( pDocShell )
+ {
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ if ( nCount > 0 && nPosition >= 0 && nStartRow+nPosition <= nEndRow &&
+ nStartRow+nPosition+nCount-1 <= rDoc.MaxRow() )
+ {
+ ScRange aRange( 0, static_cast<SCROW>(nStartRow+nPosition), nTab,
+ rDoc.MaxCol(), static_cast<SCROW>(nStartRow+nPosition+nCount-1), nTab );
+ bDone = pDocShell->GetDocFunc().InsertCells( aRange, nullptr, INS_INSROWS_BEFORE, true, true );
+ }
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScTableRowsObj::removeByIndex( sal_Int32 nIndex, sal_Int32 nCount )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ // the range to be deleted has to lie within the object
+ if ( pDocShell && nCount > 0 && nIndex >= 0 && nStartRow+nIndex+nCount-1 <= nEndRow )
+ {
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ ScRange aRange( 0, static_cast<SCROW>(nStartRow+nIndex), nTab,
+ rDoc.MaxCol(), static_cast<SCROW>(nStartRow+nIndex+nCount-1), nTab );
+ bDone = pDocShell->GetDocFunc().DeleteCells( aRange, nullptr, DelCellCmd::Rows, true );
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScTableRowsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.table.TableRowsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScTableRowsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return nEndRow - nStartRow + 1;
+}
+
+uno::Any SAL_CALL ScTableRowsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<table::XCellRange> xRow(GetObjectByIndex_Impl(nIndex));
+ if (!xRow.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRow);
+}
+
+uno::Type SAL_CALL ScTableRowsObj::getElementType()
+{
+ return cppu::UnoType<table::XCellRange>::get();
+}
+
+sal_Bool SAL_CALL ScTableRowsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableRowsObj::getPropertySetInfo()
+{
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( lcl_GetRowsPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScTableRowsObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ throw uno::RuntimeException();
+
+ ScDocFunc& rFunc = pDocShell->GetDocFunc();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ std::vector<sc::ColRowSpan> aRowArr(1, sc::ColRowSpan(nStartRow,nEndRow));
+
+ if ( aPropertyName == SC_UNONAME_OHEIGHT )
+ {
+ sal_Int32 nNewHeight = 0;
+ if ( rDoc.IsImportingXML() && ( aValue >>= nNewHeight ) )
+ {
+ // used to set the stored row height for rows with optimal height when loading.
+
+ // TODO: It's probably cleaner to use a different property name
+ // for this.
+ rDoc.SetRowHeightOnly( nStartRow, nEndRow, nTab, o3tl::toTwips(nNewHeight, o3tl::Length::mm100) );
+ }
+ else
+ {
+ bool bOpt = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ if (bOpt)
+ rFunc.SetWidthOrHeight(false, aRowArr, nTab, SC_SIZE_OPTIMAL, 0, true, true);
+ else
+ {
+ //! manually set old heights again?
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLHGT )
+ {
+ sal_Int32 nNewHeight = 0;
+ if ( aValue >>= nNewHeight )
+ {
+ if (rDoc.IsImportingXML())
+ {
+ // TODO: This is a band-aid fix. Eventually we need to
+ // re-work ods' style import to get it to set styles to
+ // ScDocument directly.
+ rDoc.SetRowHeightOnly( nStartRow, nEndRow, nTab, o3tl::toTwips(nNewHeight, o3tl::Length::mm100) );
+ rDoc.SetManualHeight( nStartRow, nEndRow, nTab, true );
+ }
+ else
+ rFunc.SetWidthOrHeight(
+ false, aRowArr, nTab, SC_SIZE_ORIGINAL, o3tl::toTwips(nNewHeight, o3tl::Length::mm100), true, true);
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLVIS )
+ {
+ bool bVis = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ ScSizeMode eMode = bVis ? SC_SIZE_SHOW : SC_SIZE_DIRECT;
+ rFunc.SetWidthOrHeight(false, aRowArr, nTab, eMode, 0, true, true);
+ // SC_SIZE_DIRECT with size 0: hide
+ }
+ else if ( aPropertyName == SC_UNONAME_VISFLAG )
+ {
+ // #i116460# Shortcut to only set the flag, without drawing layer update etc.
+ // Should only be used from import filters.
+ rDoc.SetRowHidden(nStartRow, nEndRow, nTab, !ScUnoHelpFunctions::GetBoolFromAny( aValue ));
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLFILT )
+ {
+ //! undo etc.
+ if (ScUnoHelpFunctions::GetBoolFromAny( aValue ))
+ rDoc.SetRowFiltered(nStartRow, nEndRow, nTab, true);
+ else
+ rDoc.SetRowFiltered(nStartRow, nEndRow, nTab, false);
+ }
+ else if ( aPropertyName == SC_UNONAME_NEWPAGE || aPropertyName == SC_UNONAME_MANPAGE )
+ {
+ //! single function to set/remove all breaks?
+ bool bSet = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
+ if (bSet)
+ rFunc.InsertPageBreak( false, ScAddress(0,nRow,nTab), true, true );
+ else
+ rFunc.RemovePageBreak( false, ScAddress(0,nRow,nTab), true, true );
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLBACK || aPropertyName == SC_UNONAME_CELLTRAN )
+ {
+ // #i57867# Background color is specified for row styles in the file format,
+ // so it has to be supported along with the row properties (import only).
+
+ // Use ScCellRangeObj to set the property for all cells in the rows
+ // (this means, the "row attribute" must be set before individual cell attributes).
+
+ ScRange aRange( 0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab );
+ uno::Reference<beans::XPropertySet> xRangeObj = new ScCellRangeObj( pDocShell, aRange );
+ xRangeObj->setPropertyValue( aPropertyName, aValue );
+ }
+}
+
+uno::Any SAL_CALL ScTableRowsObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ throw uno::RuntimeException();
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ uno::Any aAny;
+
+ //! loop over all rows for current state?
+
+ if ( aPropertyName == SC_UNONAME_CELLHGT )
+ {
+ // for hidden row, return original height
+ sal_uInt16 nHeight = rDoc.GetOriginalHeight( nStartRow, nTab );
+ aAny <<= static_cast<sal_Int32>(convertTwipToMm100(nHeight));
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLVIS )
+ {
+ SCROW nLastRow;
+ bool bVis = !rDoc.RowHidden(nStartRow, nTab, nullptr, &nLastRow);
+ aAny <<= bVis;
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLFILT )
+ {
+ bool bVis = rDoc.RowFiltered(nStartRow, nTab);
+ aAny <<= bVis;
+ }
+ else if ( aPropertyName == SC_UNONAME_OHEIGHT )
+ {
+ bool bOpt = !(rDoc.GetRowFlags( nStartRow, nTab ) & CRFlags::ManualSize);
+ aAny <<= bOpt;
+ }
+ else if ( aPropertyName == SC_UNONAME_NEWPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasRowBreak(nStartRow, nTab);
+ aAny <<= (nBreak != ScBreakType::NONE);
+ }
+ else if ( aPropertyName == SC_UNONAME_MANPAGE )
+ {
+ ScBreakType nBreak = rDoc.HasRowBreak(nStartRow, nTab);
+ aAny <<= bool(nBreak & ScBreakType::Manual);
+ }
+ else if ( aPropertyName == SC_UNONAME_CELLBACK || aPropertyName == SC_UNONAME_CELLTRAN )
+ {
+ // Use ScCellRangeObj to get the property from the cell range
+ // (for completeness only, this is not used by the XML filter).
+
+ ScRange aRange( 0, nStartRow, nTab, rDoc.MaxCol(), nEndRow, nTab );
+ uno::Reference<beans::XPropertySet> xRangeObj = new ScCellRangeObj( pDocShell, aRange );
+ aAny = xRangeObj->getPropertyValue( aPropertyName );
+ }
+
+ return aAny;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScTableRowsObj )
+
+ScSpreadsheetSettingsObj::~ScSpreadsheetSettingsObj()
+{
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSpreadsheetSettingsObj::getPropertySetInfo()
+{
+ return nullptr;
+}
+
+void SAL_CALL ScSpreadsheetSettingsObj::setPropertyValue(
+ const OUString& /* aPropertyName */, const uno::Any& /* aValue */ )
+{
+}
+
+uno::Any SAL_CALL ScSpreadsheetSettingsObj::getPropertyValue( const OUString& /* aPropertyName */ )
+{
+ return uno::Any();
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSpreadsheetSettingsObj )
+
+ScAnnotationsObj::ScAnnotationsObj(ScDocShell* pDocSh, SCTAB nT) :
+ pDocShell( pDocSh ),
+ nTab( nT )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScAnnotationsObj::~ScAnnotationsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScAnnotationsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! adjust nTab when updating references!!!
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+bool ScAnnotationsObj::GetAddressByIndex_Impl( sal_Int32 nIndex, ScAddress& rPos ) const
+{
+ if (!pDocShell)
+ return false;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rPos = rDoc.GetNotePosition(nIndex, nTab);
+ return rPos.IsValid();
+}
+
+rtl::Reference<ScAnnotationObj> ScAnnotationsObj::GetObjectByIndex_Impl( sal_Int32 nIndex ) const
+{
+ if (pDocShell)
+ {
+ ScAddress aPos;
+ if ( GetAddressByIndex_Impl( nIndex, aPos ) )
+ return new ScAnnotationObj( pDocShell, aPos );
+ }
+ return nullptr;
+}
+
+// XSheetAnnotations
+
+void SAL_CALL ScAnnotationsObj::insertNew(
+ const table::CellAddress& aPosition, const OUString& rText )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ OSL_ENSURE( aPosition.Sheet == nTab, "addAnnotation with a wrong Sheet" );
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), nTab );
+ pDocShell->GetDocFunc().ReplaceNote( aPos, rText, nullptr, nullptr, true );
+ }
+}
+
+void SAL_CALL ScAnnotationsObj::removeByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScAddress aPos;
+ if ( GetAddressByIndex_Impl( nIndex, aPos ) )
+ {
+ ScMarkData aMarkData(pDocShell->GetDocument().GetSheetLimits());
+ aMarkData.SelectTable( aPos.Tab(), true );
+ aMarkData.SetMultiMarkArea( ScRange(aPos) );
+
+ pDocShell->GetDocFunc().DeleteContents( aMarkData, InsertDeleteFlags::NOTE, true, true );
+ }
+ }
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScAnnotationsObj::createEnumeration()
+{
+ //! iterate directly (more efficiently)?
+
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.CellAnnotationsEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScAnnotationsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nCount = 0;
+ if (pDocShell)
+ {
+ const ScDocument& rDoc = pDocShell->GetDocument();
+ for (SCCOL nCol : rDoc.GetAllocatedColumnsRange(nTab, 0, rDoc.MaxCol()))
+ nCount += rDoc.GetNoteCount(nTab, nCol);
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL ScAnnotationsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XSheetAnnotation> xAnnotation(GetObjectByIndex_Impl(nIndex));
+ if (!xAnnotation.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xAnnotation);
+}
+
+uno::Type SAL_CALL ScAnnotationsObj::getElementType()
+{
+ return cppu::UnoType<sheet::XSheetAnnotation>::get();
+}
+
+sal_Bool SAL_CALL ScAnnotationsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+ScScenariosObj::ScScenariosObj(ScDocShell* pDocSh, SCTAB nT) :
+ pDocShell( pDocSh ),
+ nTab ( nT )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScScenariosObj::~ScScenariosObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScScenariosObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! update of references for sheet and its start/end
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XScenarios
+
+bool ScScenariosObj::GetScenarioIndex_Impl( std::u16string_view rName, SCTAB& rIndex )
+{
+ //! Case-insensitive ????
+
+ if ( pDocShell )
+ {
+ OUString aTabName;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nCount = static_cast<SCTAB>(getCount());
+ for (SCTAB i=0; i<nCount; i++)
+ if (rDoc.GetName( nTab+i+1, aTabName ))
+ if (aTabName == rName)
+ {
+ rIndex = i;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+rtl::Reference<ScTableSheetObj> ScScenariosObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
+{
+ sal_uInt16 nCount = static_cast<sal_uInt16>(getCount());
+ if ( pDocShell && nIndex >= 0 && nIndex < nCount )
+ return new ScTableSheetObj( pDocShell, nTab+static_cast<SCTAB>(nIndex)+1 );
+
+ return nullptr; // no document or wrong index
+}
+
+rtl::Reference<ScTableSheetObj> ScScenariosObj::GetObjectByName_Impl(std::u16string_view aName)
+{
+ SCTAB nIndex;
+ if ( pDocShell && GetScenarioIndex_Impl( aName, nIndex ) )
+ return new ScTableSheetObj( pDocShell, nTab+nIndex+1 );
+
+ return nullptr; // not found
+}
+
+void SAL_CALL ScScenariosObj::addNewByName( const OUString& aName,
+ const uno::Sequence<table::CellRangeAddress>& aRanges,
+ const OUString& aComment )
+{
+ SolarMutexGuard aGuard;
+ if ( !pDocShell )
+ return;
+
+ ScMarkData aMarkData(pDocShell->GetDocument().GetSheetLimits());
+ aMarkData.SelectTable( nTab, true );
+
+ for (const table::CellRangeAddress& rRange : aRanges)
+ {
+ OSL_ENSURE( rRange.Sheet == nTab, "addScenario with a wrong Tab" );
+ ScRange aRange( static_cast<SCCOL>(rRange.StartColumn), static_cast<SCROW>(rRange.StartRow), nTab,
+ static_cast<SCCOL>(rRange.EndColumn), static_cast<SCROW>(rRange.EndRow), nTab );
+
+ aMarkData.SetMultiMarkArea( aRange );
+ }
+
+ ScScenarioFlags const nFlags = ScScenarioFlags::ShowFrame | ScScenarioFlags::PrintFrame
+ | ScScenarioFlags::TwoWay | ScScenarioFlags::Protected;
+
+ pDocShell->MakeScenario( nTab, aName, aComment, COL_LIGHTGRAY, nFlags, aMarkData );
+}
+
+void SAL_CALL ScScenariosObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ SCTAB nIndex;
+ if ( pDocShell && GetScenarioIndex_Impl( aName, nIndex ) )
+ pDocShell->GetDocFunc().DeleteTable( nTab+nIndex+1, true );
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScScenariosObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.ScenariosEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScScenariosObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ SCTAB nCount = 0;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if (!rDoc.IsScenario(nTab))
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCTAB nNext = nTab + 1;
+ while (nNext < nTabCount && rDoc.IsScenario(nNext))
+ {
+ ++nCount;
+ ++nNext;
+ }
+ }
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL ScScenariosObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XScenario> xScen(GetObjectByIndex_Impl(nIndex));
+ if (!xScen.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xScen);
+}
+
+uno::Type SAL_CALL ScScenariosObj::getElementType()
+{
+ return cppu::UnoType<sheet::XScenario>::get();
+}
+
+sal_Bool SAL_CALL ScScenariosObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Any SAL_CALL ScScenariosObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XScenario> xScen(GetObjectByName_Impl(aName));
+ if (!xScen.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xScen);
+}
+
+uno::Sequence<OUString> SAL_CALL ScScenariosObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ SCTAB nCount = static_cast<SCTAB>(getCount());
+ uno::Sequence<OUString> aSeq(nCount);
+
+ if ( pDocShell ) // otherwise Count = 0
+ {
+ OUString aTabName;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OUString* pAry = aSeq.getArray();
+ for (SCTAB i=0; i<nCount; i++)
+ if (rDoc.GetName( nTab+i+1, aTabName ))
+ pAry[i] = aTabName;
+ }
+
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScScenariosObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ SCTAB nIndex;
+ return GetScenarioIndex_Impl( aName, nIndex );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/drdefuno.cxx b/sc/source/ui/unoobj/drdefuno.cxx
new file mode 100644
index 000000000..7ad5dc28e
--- /dev/null
+++ b/sc/source/ui/unoobj/drdefuno.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 <drdefuno.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+
+ScDrawDefaultsObj::ScDrawDefaultsObj(ScDocShell* pDocSh) :
+ SvxUnoDrawPool( nullptr ),
+ pDocShell( pDocSh )
+{
+ // SvxUnoDrawPool is initialized without model,
+ // draw layer is created on demand in getModelPool
+
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDrawDefaultsObj::~ScDrawDefaultsObj() noexcept
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDrawDefaultsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // document gone
+ }
+}
+
+SfxItemPool* ScDrawDefaultsObj::getModelPool( bool bReadOnly ) noexcept
+{
+ SfxItemPool* pRet = nullptr;
+
+ try
+ {
+ if ( pDocShell )
+ {
+ ScDrawLayer* pModel = bReadOnly ?
+ pDocShell->GetDocument().GetDrawLayer() :
+ pDocShell->MakeDrawLayer();
+ if ( pModel )
+ pRet = &pModel->GetItemPool();
+ }
+ }
+ catch (...)
+ {
+ }
+
+ if ( !pRet )
+ pRet = SvxUnoDrawPool::getModelPool( bReadOnly ); // uses default pool
+
+ return pRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/editsrc.cxx b/sc/source/ui/unoobj/editsrc.cxx
new file mode 100644
index 000000000..f96f9c020
--- /dev/null
+++ b/sc/source/ui/unoobj/editsrc.cxx
@@ -0,0 +1,272 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <editsrc.hxx>
+
+#include <editeng/unofored.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/svdocapt.hxx>
+#include <editeng/outlobj.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/outliner.hxx>
+#include <textuno.hxx>
+#include <editutil.hxx>
+#include <docsh.hxx>
+#include <hints.hxx>
+#include <postit.hxx>
+#include <AccessibleText.hxx>
+
+ScHeaderFooterEditSource::ScHeaderFooterEditSource(ScHeaderFooterTextData& rData) :
+ mrTextData(rData) {}
+
+ScHeaderFooterEditSource::~ScHeaderFooterEditSource() {}
+
+ScEditEngineDefaulter* ScHeaderFooterEditSource::GetEditEngine()
+{
+ return mrTextData.GetEditEngine();
+}
+
+std::unique_ptr<SvxEditSource> ScHeaderFooterEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new ScHeaderFooterEditSource(mrTextData));
+}
+
+SvxTextForwarder* ScHeaderFooterEditSource::GetTextForwarder()
+{
+ return mrTextData.GetTextForwarder();
+}
+
+void ScHeaderFooterEditSource::UpdateData()
+{
+ mrTextData.UpdateData();
+}
+
+ScCellEditSource::ScCellEditSource(ScDocShell* pDocSh, const ScAddress& rP) :
+ pCellTextData(new ScCellTextData(pDocSh, rP)) {}
+
+ScCellEditSource::~ScCellEditSource()
+{
+}
+
+std::unique_ptr<SvxEditSource> ScCellEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new ScCellEditSource(pCellTextData->GetDocShell(), pCellTextData->GetCellPos()));
+}
+
+SvxTextForwarder* ScCellEditSource::GetTextForwarder()
+{
+ return pCellTextData->GetTextForwarder();
+}
+
+void ScCellEditSource::UpdateData()
+{
+ pCellTextData->UpdateData();
+}
+
+void ScCellEditSource::SetDoUpdateData(bool bValue)
+{
+ pCellTextData->SetDoUpdate(bValue);
+}
+
+bool ScCellEditSource::IsDirty() const
+{
+ return pCellTextData->IsDirty();
+}
+
+ScEditEngineDefaulter* ScCellEditSource::GetEditEngine()
+{
+ return pCellTextData->GetEditEngine();
+}
+
+ScAnnotationEditSource::ScAnnotationEditSource(ScDocShell* pDocSh, const ScAddress& rP) :
+ pDocShell( pDocSh ),
+ aCellPos( rP ),
+ bDataValid( false )
+{
+ if (pDocShell)
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScAnnotationEditSource::~ScAnnotationEditSource()
+{
+ SolarMutexGuard aGuard; // needed for EditEngine dtor
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+
+ pForwarder.reset();
+ pEditEngine.reset();
+}
+
+std::unique_ptr<SvxEditSource> ScAnnotationEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new ScAnnotationEditSource( pDocShell, aCellPos ));
+}
+
+SdrObject* ScAnnotationEditSource::GetCaptionObj()
+{
+ ScPostIt* pNote = pDocShell->GetDocument().GetNote(aCellPos);
+ return pNote ? pNote->GetOrCreateCaption( aCellPos ) : nullptr;
+}
+
+SvxTextForwarder* ScAnnotationEditSource::GetTextForwarder()
+{
+ if (!pEditEngine)
+ {
+ // notes don't have fields
+ if ( pDocShell )
+ {
+ pEditEngine.reset( new ScNoteEditEngine( pDocShell->GetDocument().GetNoteEngine() ) );
+ }
+ else
+ {
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->FreezeIdRanges();
+ pEditEngine.reset( new ScEditEngineDefaulter( pEnginePool.get(), true ) );
+ }
+ pForwarder.reset( new SvxEditEngineForwarder(*pEditEngine) );
+ }
+
+ if (bDataValid)
+ return pForwarder.get();
+
+ if ( pDocShell )
+ if ( ScPostIt* pNote = pDocShell->GetDocument().GetNote(aCellPos) )
+ if ( const EditTextObject* pEditObj = pNote->GetEditTextObject() )
+ pEditEngine->SetTextCurrentDefaults( *pEditObj ); // incl. breaks (line, etc.)
+
+ bDataValid = true;
+ return pForwarder.get();
+}
+
+void ScAnnotationEditSource::UpdateData()
+{
+ if ( !(pDocShell && pEditEngine) )
+ return;
+
+ ScDocShellModificator aModificator( *pDocShell );
+
+ if( SdrObject* pObj = GetCaptionObj() )
+ {
+ OutlinerParaObject aOPO( pEditEngine->CreateTextObject() );
+ aOPO.SetOutlinerMode( OutlinerMode::TextObject );
+ pObj->NbcSetOutlinerParaObject( std::move(aOPO) );
+ pObj->ActionChanged();
+ }
+
+ //! Undo !!!
+
+ aModificator.SetDocumentModified();
+
+ // SetDocumentModified will reset bDataValid
+}
+
+void ScAnnotationEditSource::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! reference update
+ }
+ else
+ {
+ const SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+
+ pForwarder.reset();
+ pEditEngine.reset(); // EditEngine uses document's pool
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ bDataValid = false; // text must be retrieved again
+ }
+}
+
+ScSimpleEditSource::ScSimpleEditSource( SvxTextForwarder* pForw ) :
+ pForwarder( pForw )
+{
+ // The same forwarder (and EditEngine) is shared by all children of the same Text object.
+ // Text range and cursor keep a reference to their parent text, so the text object is
+ // always alive and the forwarder is valid as long as there are children.
+}
+
+ScSimpleEditSource::~ScSimpleEditSource()
+{
+}
+
+std::unique_ptr<SvxEditSource> ScSimpleEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new ScSimpleEditSource( pForwarder ));
+}
+
+SvxTextForwarder* ScSimpleEditSource::GetTextForwarder()
+{
+ return pForwarder;
+}
+
+void ScSimpleEditSource::UpdateData()
+{
+ // nothing
+}
+
+ScAccessibilityEditSource::ScAccessibilityEditSource( ::std::unique_ptr < ScAccessibleTextData > && pAccessibleCellTextData )
+ : mpAccessibleTextData(std::move(pAccessibleCellTextData))
+{
+}
+
+ScAccessibilityEditSource::~ScAccessibilityEditSource()
+{
+}
+
+std::unique_ptr<SvxEditSource> ScAccessibilityEditSource::Clone() const
+{
+ return std::unique_ptr<SvxEditSource>(new ScAccessibilityEditSource(::std::unique_ptr < ScAccessibleTextData > (mpAccessibleTextData->Clone())));
+}
+
+SvxTextForwarder* ScAccessibilityEditSource::GetTextForwarder()
+{
+ return mpAccessibleTextData->GetTextForwarder();
+}
+
+SvxViewForwarder* ScAccessibilityEditSource::GetViewForwarder()
+{
+ return mpAccessibleTextData->GetViewForwarder();
+}
+
+SvxEditViewForwarder* ScAccessibilityEditSource::GetEditViewForwarder( bool bCreate )
+{
+ return mpAccessibleTextData->GetEditViewForwarder(bCreate);
+}
+
+void ScAccessibilityEditSource::UpdateData()
+{
+ mpAccessibleTextData->UpdateData();
+}
+
+SfxBroadcaster& ScAccessibilityEditSource::GetBroadcaster() const
+{
+ return mpAccessibleTextData->GetBroadcaster();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/eventuno.cxx b/sc/source/ui/unoobj/eventuno.cxx
new file mode 100644
index 000000000..88a387637
--- /dev/null
+++ b/sc/source/ui/unoobj/eventuno.cxx
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <eventuno.hxx>
+#include <miscuno.hxx>
+#include <docsh.hxx>
+#include <sheetevents.hxx>
+#include <unonames.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <vcl/svapp.hxx>
+
+using namespace ::com::sun::star;
+
+SC_SIMPLE_SERVICE_INFO( ScSheetEventsObj, "ScSheetEventsObj", "com.sun.star.document.Events" )
+
+ScSheetEventsObj::ScSheetEventsObj(ScDocShell* pDocSh, SCTAB nT) :
+ mpDocShell( pDocSh ),
+ mnTab( nT )
+{
+ mpDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScSheetEventsObj::~ScSheetEventsObj()
+{
+ SolarMutexGuard g;
+
+ if (mpDocShell)
+ mpDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScSheetEventsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! reference update
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ mpDocShell = nullptr;
+ }
+}
+
+static ScSheetEventId lcl_GetEventFromName( std::u16string_view aName )
+{
+ for (sal_Int32 nEvent=0; nEvent<static_cast<sal_Int32>(ScSheetEventId::COUNT); ++nEvent)
+ if ( aName == ScSheetEvents::GetEventName(static_cast<ScSheetEventId>(nEvent)) )
+ return static_cast<ScSheetEventId>(nEvent);
+
+ return ScSheetEventId::NOTFOUND; // not found
+}
+
+// XNameReplace
+
+void SAL_CALL ScSheetEventsObj::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ if (!mpDocShell)
+ throw uno::RuntimeException();
+
+ ScSheetEventId nEvent = lcl_GetEventFromName(aName);
+ if (nEvent == ScSheetEventId::NOTFOUND)
+ throw container::NoSuchElementException();
+
+ std::unique_ptr<ScSheetEvents> pNewEvents(new ScSheetEvents);
+ const ScSheetEvents* pOldEvents = mpDocShell->GetDocument().GetSheetEvents(mnTab);
+ if (pOldEvents)
+ *pNewEvents = *pOldEvents;
+
+ OUString aScript;
+ if ( aElement.hasValue() ) // empty Any -> reset event
+ {
+ uno::Sequence<beans::PropertyValue> aPropSeq;
+ if ( aElement >>= aPropSeq )
+ {
+ for (const beans::PropertyValue& rProp : std::as_const(aPropSeq))
+ {
+ if ( rProp.Name == SC_UNO_EVENTTYPE )
+ {
+ OUString aEventType;
+ if ( rProp.Value >>= aEventType )
+ {
+ // only "Script" is supported
+ if ( aEventType != SC_UNO_SCRIPT )
+ throw lang::IllegalArgumentException();
+ }
+ }
+ else if ( rProp.Name == SC_UNO_SCRIPT )
+ rProp.Value >>= aScript;
+ }
+ }
+ }
+ if (!aScript.isEmpty())
+ pNewEvents->SetScript( nEvent, &aScript );
+ else
+ pNewEvents->SetScript( nEvent, nullptr ); // reset
+
+ mpDocShell->GetDocument().SetSheetEvents( mnTab, std::move(pNewEvents) );
+ mpDocShell->SetDocumentModified();
+}
+
+// XNameAccess
+
+uno::Any SAL_CALL ScSheetEventsObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ ScSheetEventId nEvent = lcl_GetEventFromName(aName);
+ if (nEvent == ScSheetEventId::NOTFOUND)
+ throw container::NoSuchElementException();
+
+ const OUString* pScript = nullptr;
+ if (mpDocShell)
+ {
+ const ScSheetEvents* pEvents = mpDocShell->GetDocument().GetSheetEvents(mnTab);
+ if (pEvents)
+ pScript = pEvents->GetScript(nEvent);
+ }
+
+ uno::Any aRet;
+ if (pScript)
+ {
+ uno::Sequence<beans::PropertyValue> aPropSeq( comphelper::InitPropertySequence({
+ { "EventType", uno::Any( OUString("Script") ) },
+ { "Script", uno::Any( *pScript ) }
+ }));
+ aRet <<= aPropSeq;
+ }
+ // empty Any if nothing was set
+ return aRet;
+}
+
+uno::Sequence<OUString> SAL_CALL ScSheetEventsObj::getElementNames()
+{
+ auto aNames = uno::Sequence<OUString>(int(ScSheetEventId::COUNT));
+ auto pNames = aNames.getArray();
+ for (sal_Int32 nEvent=0; nEvent<int(ScSheetEventId::COUNT); ++nEvent)
+ pNames[nEvent] = ScSheetEvents::GetEventName(static_cast<ScSheetEventId>(nEvent));
+ return aNames;
+}
+
+sal_Bool SAL_CALL ScSheetEventsObj::hasByName( const OUString& aName )
+{
+ ScSheetEventId nEvent = lcl_GetEventFromName(aName);
+ return (nEvent != ScSheetEventId::NOTFOUND);
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScSheetEventsObj::getElementType()
+{
+ return cppu::UnoType<uno::Sequence<beans::PropertyValue>>::get();
+}
+
+sal_Bool SAL_CALL ScSheetEventsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ if (mpDocShell)
+ return true;
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/exceldetect.cxx b/sc/source/ui/unoobj/exceldetect.cxx
new file mode 100644
index 000000000..75694bbc9
--- /dev/null
+++ b/sc/source/ui/unoobj/exceldetect.cxx
@@ -0,0 +1,198 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "exceldetect.hxx"
+
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <sfx2/docfile.hxx>
+#include <unotools/mediadescriptor.hxx>
+#include <sot/storage.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace com::sun::star;
+using utl::MediaDescriptor;
+
+ScExcelBiffDetect::ScExcelBiffDetect() {}
+ScExcelBiffDetect::~ScExcelBiffDetect() {}
+
+OUString ScExcelBiffDetect::getImplementationName()
+{
+ return "com.sun.star.comp.calc.ExcelBiffFormatDetector";
+}
+
+sal_Bool ScExcelBiffDetect::supportsService( const OUString& aName )
+{
+ return cppu::supportsService(this, aName);
+}
+
+uno::Sequence<OUString> ScExcelBiffDetect::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ExtendedTypeDetection" };
+}
+
+namespace {
+
+bool hasStream(const uno::Reference<io::XInputStream>& xInStream, const OUString& rName)
+{
+ SfxMedium aMedium;
+ aMedium.UseInteractionHandler(false);
+ aMedium.setStreamToLoadFrom(xInStream, true);
+ SvStream* pStream = aMedium.GetInStream();
+ if (!pStream)
+ return false;
+
+ sal_uInt64 const nSize = pStream->TellEnd();
+ pStream->Seek(0);
+
+ if (!nSize)
+ {
+ // 0-size stream. Failed.
+ return false;
+ }
+
+ try
+ {
+ tools::SvRef<SotStorage> xStorage = new SotStorage(pStream, false);
+ if (!xStorage.is() || xStorage->GetError())
+ return false;
+ return xStorage->IsStream(rName);
+ }
+ catch (const css::ucb::ContentCreationException &)
+ {
+ TOOLS_WARN_EXCEPTION("sc", "hasStream");
+ }
+
+ return false;
+}
+
+/**
+ * We detect BIFF 2, 3 and 4 file types together since the only thing that
+ * set them apart is the BOF ID.
+ */
+bool isExcel40(const uno::Reference<io::XInputStream>& xInStream)
+{
+ SfxMedium aMedium;
+ aMedium.UseInteractionHandler(false);
+ aMedium.setStreamToLoadFrom(xInStream, true);
+ SvStream* pStream = aMedium.GetInStream();
+ if (!pStream)
+ return false;
+
+ sal_uInt64 const nSize = pStream->TellEnd();
+ pStream->Seek(0);
+
+ if (nSize < 4)
+ return false;
+
+ sal_uInt16 nBofId, nBofSize;
+ pStream->ReadUInt16( nBofId ).ReadUInt16( nBofSize );
+
+ switch (nBofId)
+ {
+ case 0x0009: // Excel 2.1 worksheet (BIFF 2)
+ case 0x0209: // Excel 3.0 worksheet (BIFF 3)
+ case 0x0409: // Excel 4.0 worksheet (BIFF 4)
+ case 0x0809: // Excel 5.0 worksheet (BIFF 5), some apps create such files (fdo#70100)
+ break;
+ default:
+ return false;
+ }
+
+ if (nBofSize < 4 || 16 < nBofSize)
+ // BOF record must be sized between 4 and 16 for BIFF 2, 3 and 4.
+ return false;
+
+ sal_uInt64 const nPos = pStream->Tell();
+ if (nSize - nPos < nBofSize)
+ // BOF record doesn't have required bytes.
+ return false;
+
+ return true;
+}
+
+bool isTemplate(std::u16string_view rType)
+{
+ return rType.find(u"_VorlageTemplate") != std::u16string_view::npos;
+}
+
+}
+
+OUString ScExcelBiffDetect::detect( uno::Sequence<beans::PropertyValue>& lDescriptor )
+{
+ MediaDescriptor aMediaDesc(lDescriptor);
+ OUString aType;
+ aMediaDesc[MediaDescriptor::PROP_TYPENAME] >>= aType;
+ if (aType.isEmpty())
+ // Type is not given. We can't proceed.
+ return OUString();
+
+ aMediaDesc.addInputStream();
+ uno::Reference<io::XInputStream> xInStream(aMediaDesc[MediaDescriptor::PROP_INPUTSTREAM], uno::UNO_QUERY);
+ if (!xInStream.is())
+ // No input stream.
+ return OUString();
+
+ if (aType == "calc_MS_Excel_97" || aType == "calc_MS_Excel_97_VorlageTemplate")
+ {
+ // See if this stream is an Excel 97/XP/2003 (BIFF8) stream.
+ if (!hasStream(xInStream, "Workbook"))
+ // BIFF8 is expected to contain a stream named "Workbook".
+ return OUString();
+
+ aMediaDesc[MediaDescriptor::PROP_FILTERNAME] <<= isTemplate(aType) ? OUString("MS Excel 97 Vorlage/Template") : OUString("MS Excel 97");
+ }
+
+ else if (aType == "calc_MS_Excel_95" || aType == "calc_MS_Excel_95_VorlageTemplate")
+ {
+ // See if this stream is an Excel 95 (BIFF5) stream.
+ if (!hasStream(xInStream, "Book"))
+ return OUString();
+
+ aMediaDesc[MediaDescriptor::PROP_FILTERNAME] <<= isTemplate(aType) ? OUString("MS Excel 95 Vorlage/Template") : OUString("MS Excel 95");
+ }
+
+ else if (aType == "calc_MS_Excel_5095" || aType == "calc_MS_Excel_5095_VorlageTemplate")
+ {
+ // See if this stream is an Excel 5.0/95 stream.
+ if (!hasStream(xInStream, "Book"))
+ return OUString();
+
+ aMediaDesc[MediaDescriptor::PROP_FILTERNAME] <<= isTemplate(aType) ? OUString("MS Excel 5.0/95 Vorlage/Template") : OUString("MS Excel 5.0/95");
+ }
+
+ else if (aType == "calc_MS_Excel_40" || aType == "calc_MS_Excel_40_VorlageTemplate")
+ {
+ // See if this stream is an Excel 4.0 stream.
+ if (!isExcel40(xInStream))
+ return OUString();
+
+ aMediaDesc[MediaDescriptor::PROP_FILTERNAME] <<= isTemplate(aType) ? OUString("MS Excel 4.0 Vorlage/Template") : OUString("MS Excel 4.0");
+ }
+
+ else
+ // Nothing to detect.
+ return OUString();
+
+ aMediaDesc >> lDescriptor;
+ return aType;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_calc_ExcelBiffFormatDetector_get_implementation(css::uno::XComponentContext* /*context*/,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ScExcelBiffDetect);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/exceldetect.hxx b/sc/source/ui/unoobj/exceldetect.hxx
new file mode 100644
index 000000000..718963752
--- /dev/null
+++ b/sc/source/ui/unoobj/exceldetect.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/document/XExtendedFilterDetection.hpp>
+
+class ScExcelBiffDetect
+ : public cppu::WeakImplHelper<css::document::XExtendedFilterDetection, css::lang::XServiceInfo>
+{
+public:
+ explicit ScExcelBiffDetect();
+ virtual ~ScExcelBiffDetect() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName() override;
+ virtual sal_Bool SAL_CALL supportsService(const OUString& aName) override;
+ virtual css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+ // XExtendedFilterDetection
+ virtual OUString SAL_CALL
+ detect(css::uno::Sequence<css::beans::PropertyValue>& lDescriptor) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/fielduno.cxx b/sc/source/ui/unoobj/fielduno.cxx
new file mode 100644
index 000000000..d79526279
--- /dev/null
+++ b/sc/source/ui/unoobj/fielduno.cxx
@@ -0,0 +1,1302 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <fielduno.hxx>
+#include <textuno.hxx>
+#include <miscuno.hxx>
+#include <docsh.hxx>
+#include <hints.hxx>
+#include <editsrc.hxx>
+#include <unonames.hxx>
+#include <editutil.hxx>
+
+#include <svl/hint.hxx>
+#include <vcl/svapp.hxx>
+
+#include <editeng/eeitem.hxx>
+
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/flditem.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
+#include <com/sun/star/text/WrapTextMode.hpp>
+#include <com/sun/star/text/FilenameDisplayFormat.hpp>
+#include <com/sun/star/text/textfield/Type.hpp>
+
+using namespace com::sun::star;
+
+namespace {
+
+// no Which-ID here, map only for PropertySetInfo
+
+const SfxItemPropertySet* getDateTimePropertySet()
+{
+ static const SfxItemPropertyMapEntry aMapContent[] =
+ {
+ { SC_UNONAME_DATETIME, 0, cppu::UnoType<util::DateTime>::get(), 0, 0 },
+ { SC_UNONAME_ISFIXED, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_ISDATE, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNONAME_NUMFMT, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aMap(aMapContent);
+ return &aMap;
+}
+
+const SfxItemPropertySet* getEmptyPropertySet()
+{
+ static const SfxItemPropertyMapEntry aMapContent[] =
+ {
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aMap(aMapContent);
+ return &aMap;
+}
+
+const SfxItemPropertySet* lcl_GetURLPropertySet()
+{
+ static const SfxItemPropertyMapEntry aURLPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ANCTYPE, 0, cppu::UnoType<text::TextContentAnchorType>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ANCTYPES, 0, cppu::UnoType<uno::Sequence<text::TextContentAnchorType>>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_REPR, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_TARGET, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_TEXTWRAP, 0, cppu::UnoType<text::WrapTextMode>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_URL, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aURLPropertySet_Impl( aURLPropertyMap_Impl );
+ return &aURLPropertySet_Impl;
+}
+
+const SfxItemPropertySet* lcl_GetHeaderFieldPropertySet()
+{
+ static const SfxItemPropertyMapEntry aHeaderFieldPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ANCTYPE, 0, cppu::UnoType<text::TextContentAnchorType>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ANCTYPES, 0, cppu::UnoType<uno::Sequence<text::TextContentAnchorType>>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TEXTWRAP, 0, cppu::UnoType<text::WrapTextMode>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aHeaderFieldPropertySet_Impl( aHeaderFieldPropertyMap_Impl );
+ return &aHeaderFieldPropertySet_Impl;
+}
+
+const SfxItemPropertySet* lcl_GetFileFieldPropertySet()
+{
+ static const SfxItemPropertyMapEntry aFileFieldPropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ANCTYPE, 0, cppu::UnoType<text::TextContentAnchorType>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ANCTYPES, 0, cppu::UnoType<uno::Sequence<text::TextContentAnchorType>>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_FILEFORM, 0, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ { SC_UNONAME_TEXTWRAP, 0, cppu::UnoType<text::WrapTextMode>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aFileFieldPropertySet_Impl( aFileFieldPropertyMap_Impl );
+ return &aFileFieldPropertySet_Impl;
+}
+
+SvxFileFormat lcl_UnoToSvxFileFormat( sal_Int16 nUnoValue )
+{
+ switch( nUnoValue )
+ {
+ case text::FilenameDisplayFormat::FULL: return SvxFileFormat::PathFull;
+ case text::FilenameDisplayFormat::PATH: return SvxFileFormat::PathOnly;
+ case text::FilenameDisplayFormat::NAME: return SvxFileFormat::NameOnly;
+ default:
+ return SvxFileFormat::NameAndExt;
+ }
+}
+
+sal_Int16 lcl_SvxToUnoFileFormat( SvxFileFormat nSvxValue )
+{
+ switch( nSvxValue )
+ {
+ case SvxFileFormat::NameAndExt: return text::FilenameDisplayFormat::NAME_AND_EXT;
+ case SvxFileFormat::PathFull: return text::FilenameDisplayFormat::FULL;
+ case SvxFileFormat::PathOnly: return text::FilenameDisplayFormat::PATH;
+ default:
+ return text::FilenameDisplayFormat::NAME;
+ }
+}
+
+}
+
+SC_SIMPLE_SERVICE_INFO( ScCellFieldsObj, "ScCellFieldsObj", "com.sun.star.text.TextFields" )
+SC_SIMPLE_SERVICE_INFO( ScHeaderFieldsObj, "ScHeaderFieldsObj", "com.sun.star.text.TextFields" )
+
+namespace {
+
+enum ScUnoCollectMode
+{
+ SC_UNO_COLLECT_NONE,
+ SC_UNO_COLLECT_COUNT,
+ SC_UNO_COLLECT_FINDINDEX,
+ SC_UNO_COLLECT_FINDPOS
+};
+
+/**
+ * This class exists solely to allow searching through field items. TODO:
+ * Look into providing the same functionality directly in EditEngine, to
+ * avoid having this class altogether.
+ */
+class ScUnoEditEngine : public ScEditEngineDefaulter
+{
+ ScUnoCollectMode eMode;
+ sal_uInt16 nFieldCount;
+ sal_Int32 mnFieldType;
+ std::unique_ptr<SvxFieldData>
+ pFound; // local copy
+ sal_Int32 nFieldPar;
+ sal_Int32 nFieldPos;
+ sal_uInt16 nFieldIndex;
+
+public:
+ explicit ScUnoEditEngine(ScEditEngineDefaulter* pSource);
+
+ virtual OUString CalcFieldValue( const SvxFieldItem& rField, sal_Int32 nPara, sal_Int32 nPos,
+ std::optional<Color>& rTxtColor, std::optional<Color>& rFldColor ) override;
+
+ sal_uInt16 CountFields();
+ SvxFieldData* FindByIndex(sal_uInt16 nIndex);
+ SvxFieldData* FindByPos(sal_Int32 nPar, sal_Int32 nPos, sal_Int32 nType);
+
+ sal_Int32 GetFieldPar() const { return nFieldPar; }
+ sal_Int32 GetFieldPos() const { return nFieldPos; }
+};
+
+}
+
+ScUnoEditEngine::ScUnoEditEngine(ScEditEngineDefaulter* pSource)
+ : ScEditEngineDefaulter(*pSource)
+ , eMode(SC_UNO_COLLECT_NONE)
+ , nFieldCount(0)
+ , mnFieldType(text::textfield::Type::UNSPECIFIED)
+ , nFieldPar(0)
+ , nFieldPos(0)
+ , nFieldIndex(0)
+{
+ std::unique_ptr<EditTextObject> pData = pSource->CreateTextObject();
+ SetTextCurrentDefaults( *pData );
+}
+
+OUString ScUnoEditEngine::CalcFieldValue( const SvxFieldItem& rField,
+ sal_Int32 nPara, sal_Int32 nPos, std::optional<Color>& rTxtColor, std::optional<Color>& rFldColor )
+{
+ OUString aRet(EditEngine::CalcFieldValue( rField, nPara, nPos, rTxtColor, rFldColor ));
+ if (eMode != SC_UNO_COLLECT_NONE)
+ {
+ const SvxFieldData* pFieldData = rField.GetField();
+ if ( pFieldData )
+ {
+ if (mnFieldType == text::textfield::Type::UNSPECIFIED || pFieldData->GetClassId() == mnFieldType)
+ {
+ if ( eMode == SC_UNO_COLLECT_FINDINDEX && !pFound && nFieldCount == nFieldIndex )
+ {
+ pFound = pFieldData->Clone();
+ nFieldPar = nPara;
+ nFieldPos = nPos;
+ }
+ if ( eMode == SC_UNO_COLLECT_FINDPOS && !pFound &&
+ nPara == nFieldPar && nPos == nFieldPos )
+ {
+ pFound = pFieldData->Clone();
+ nFieldIndex = nFieldCount;
+ }
+ ++nFieldCount;
+ }
+ }
+ }
+ return aRet;
+}
+
+sal_uInt16 ScUnoEditEngine::CountFields()
+{
+ eMode = SC_UNO_COLLECT_COUNT;
+ mnFieldType = text::textfield::Type::UNSPECIFIED;
+ nFieldCount = 0;
+ UpdateFields();
+ eMode = SC_UNO_COLLECT_NONE;
+
+ return nFieldCount;
+}
+
+SvxFieldData* ScUnoEditEngine::FindByIndex(sal_uInt16 nIndex)
+{
+ eMode = SC_UNO_COLLECT_FINDINDEX;
+ nFieldIndex = nIndex;
+ mnFieldType = text::textfield::Type::UNSPECIFIED;
+ nFieldCount = 0;
+ UpdateFields();
+ eMode = SC_UNO_COLLECT_NONE;
+
+ return pFound.get();
+}
+
+SvxFieldData* ScUnoEditEngine::FindByPos(sal_Int32 nPar, sal_Int32 nPos, sal_Int32 nType)
+{
+ eMode = SC_UNO_COLLECT_FINDPOS;
+ nFieldPar = nPar;
+ nFieldPos = nPos;
+ mnFieldType = nType;
+ nFieldCount = 0;
+ UpdateFields();
+ mnFieldType = text::textfield::Type::UNSPECIFIED;
+ eMode = SC_UNO_COLLECT_NONE;
+
+ return pFound.get();
+}
+
+ScCellFieldsObj::ScCellFieldsObj(
+ const uno::Reference<text::XTextRange>& xContent,
+ ScDocShell* pDocSh, const ScAddress& rPos) :
+ mxContent(xContent),
+ pDocShell( pDocSh ),
+ aCellPos( rPos )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ mpEditSource.reset( new ScCellEditSource( pDocShell, aCellPos ) );
+}
+
+ScCellFieldsObj::~ScCellFieldsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+
+ mpEditSource.reset();
+
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+
+ if (mpRefreshListeners)
+ {
+ lang::EventObject aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ mpRefreshListeners->disposeAndClear(aEvent);
+ mpRefreshListeners.reset();
+ }
+}
+
+void ScCellFieldsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( dynamic_cast<const ScUpdateRefHint*>(&rHint) )
+ {
+ //! update of references
+ }
+ else if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+
+ // EditSource registered itself as a listener
+}
+
+// XIndexAccess (via XTextFields)
+
+uno::Reference<text::XTextField> ScCellFieldsObj::GetObjectByIndex_Impl(sal_Int32 Index) const
+{
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ SvxFieldData* pData = aTempEngine.FindByIndex(static_cast<sal_uInt16>(Index));
+ if (!pData)
+ return uno::Reference<text::XTextField>();
+
+ sal_Int32 nPar = aTempEngine.GetFieldPar();
+ sal_Int32 nPos = aTempEngine.GetFieldPos();
+ ESelection aSelection( nPar, nPos, nPar, nPos+1 ); // Field size is 1 character
+
+ sal_Int32 eType = pData->GetClassId();
+ uno::Reference<text::XTextField> xRet(
+ new ScEditFieldObj(mxContent, std::make_unique<ScCellEditSource>(pDocShell, aCellPos), eType, aSelection));
+ return xRet;
+}
+
+sal_Int32 SAL_CALL ScCellFieldsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ return aTempEngine.CountFields(); // count the fields, we don't care about their type in the cell
+}
+
+uno::Any SAL_CALL ScCellFieldsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<text::XTextField> xField(GetObjectByIndex_Impl(nIndex));
+ if (!xField.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xField);
+}
+
+uno::Type SAL_CALL ScCellFieldsObj::getElementType()
+{
+ return cppu::UnoType<text::XTextField>::get();
+}
+
+sal_Bool SAL_CALL ScCellFieldsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Reference<container::XEnumeration> SAL_CALL ScCellFieldsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.text.TextFieldEnumeration");
+}
+
+void SAL_CALL ScCellFieldsObj::addContainerListener(
+ const uno::Reference<container::XContainerListener>& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScCellFieldsObj::removeContainerListener(
+ const uno::Reference<container::XContainerListener>& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+// XRefreshable
+void SAL_CALL ScCellFieldsObj::refresh( )
+{
+ if (mpRefreshListeners)
+ {
+ // Call all listeners.
+ lang::EventObject aEvent;
+ aEvent.Source.set(uno::Reference< util::XRefreshable >(this));
+ mpRefreshListeners->notifyEach( &util::XRefreshListener::refreshed, aEvent );
+ }
+}
+
+void SAL_CALL ScCellFieldsObj::addRefreshListener( const uno::Reference< util::XRefreshListener >& xListener )
+{
+ if (xListener.is())
+ {
+ SolarMutexGuard aGuard;
+ if (!mpRefreshListeners)
+ mpRefreshListeners.reset( new comphelper::OInterfaceContainerHelper3<util::XRefreshListener>(aMutex) );
+ mpRefreshListeners->addInterface(xListener);
+ }
+}
+
+void SAL_CALL ScCellFieldsObj::removeRefreshListener( const uno::Reference<util::XRefreshListener >& xListener )
+{
+ if (xListener.is())
+ {
+ SolarMutexGuard aGuard;
+ if (mpRefreshListeners)
+ mpRefreshListeners->removeInterface(xListener);
+ }
+}
+
+ScHeaderFieldsObj::ScHeaderFieldsObj(ScHeaderFooterTextData& rData) :
+ mrData(rData)
+{
+ mpEditSource.reset( new ScHeaderFooterEditSource(rData) );
+}
+
+ScHeaderFieldsObj::~ScHeaderFieldsObj()
+{
+ mpEditSource.reset();
+
+ // increment refcount to prevent double call off dtor
+ osl_atomic_increment( &m_refCount );
+
+ if (mpRefreshListeners)
+ {
+ lang::EventObject aEvent;
+ aEvent.Source = static_cast<cppu::OWeakObject*>(this);
+ mpRefreshListeners->disposeAndClear(aEvent);
+ mpRefreshListeners.reset();
+ }
+}
+
+// XIndexAccess (via XTextFields)
+
+uno::Reference<text::XTextField> ScHeaderFieldsObj::GetObjectByIndex_Impl(sal_Int32 Index) const
+{
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ SvxFieldData* pData = aTempEngine.FindByIndex(static_cast<sal_uInt16>(Index));
+ if (!pData)
+ return nullptr;
+
+ // Get the parent text range instance.
+ uno::Reference<text::XTextRange> xTextRange;
+ uno::Reference<sheet::XHeaderFooterContent> xContentObj = mrData.GetContentObj();
+ if (!xContentObj.is())
+ throw uno::RuntimeException("");
+
+ rtl::Reference<ScHeaderFooterContentObj> pContentObj = ScHeaderFooterContentObj::getImplementation(xContentObj);
+ uno::Reference<text::XText> xText;
+
+ switch ( mrData.GetPart() )
+ {
+ case ScHeaderFooterPart::LEFT:
+ xText = pContentObj->getLeftText();
+ break;
+ case ScHeaderFooterPart::CENTER:
+ xText = pContentObj->getCenterText();
+ break;
+ case ScHeaderFooterPart::RIGHT:
+ xText = pContentObj->getRightText();
+ break;
+ }
+
+ xTextRange = xText;
+
+ sal_Int32 nPar = aTempEngine.GetFieldPar();
+ sal_Int32 nPos = aTempEngine.GetFieldPos();
+ ESelection aSelection( nPar, nPos, nPar, nPos+1 ); // Field size is 1 character
+
+ sal_Int32 eRealType = pData->GetClassId();
+ uno::Reference<text::XTextField> xRet(
+ new ScEditFieldObj(xTextRange, std::make_unique<ScHeaderFooterEditSource>(mrData), eRealType, aSelection));
+ return xRet;
+}
+
+sal_Int32 SAL_CALL ScHeaderFieldsObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ return aTempEngine.CountFields();
+}
+
+uno::Any SAL_CALL ScHeaderFieldsObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<text::XTextField> xField(GetObjectByIndex_Impl(nIndex));
+ if (!xField.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xField);
+}
+
+uno::Type SAL_CALL ScHeaderFieldsObj::getElementType()
+{
+ return cppu::UnoType<text::XTextField>::get();
+}
+
+sal_Bool SAL_CALL ScHeaderFieldsObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Reference<container::XEnumeration> SAL_CALL ScHeaderFieldsObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.text.TextFieldEnumeration");
+}
+
+void SAL_CALL ScHeaderFieldsObj::addContainerListener(
+ const uno::Reference<container::XContainerListener>& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+void SAL_CALL ScHeaderFieldsObj::removeContainerListener(
+ const uno::Reference<container::XContainerListener>& /* xListener */ )
+{
+ OSL_FAIL("not implemented");
+}
+
+// XRefreshable
+void SAL_CALL ScHeaderFieldsObj::refresh( )
+{
+ if (mpRefreshListeners)
+ {
+ // Call all listeners.
+ lang::EventObject aEvent;
+ aEvent.Source.set(uno::Reference< util::XRefreshable >(this));
+ mpRefreshListeners->notifyEach( &util::XRefreshListener::refreshed, aEvent);
+ }
+}
+
+void SAL_CALL ScHeaderFieldsObj::addRefreshListener( const uno::Reference< util::XRefreshListener >& xListener )
+{
+ if (xListener.is())
+ {
+ SolarMutexGuard aGuard;
+ if (!mpRefreshListeners)
+ mpRefreshListeners.reset(new comphelper::OInterfaceContainerHelper3<util::XRefreshListener>(aMutex));
+ mpRefreshListeners->addInterface(xListener);
+ }
+}
+
+void SAL_CALL ScHeaderFieldsObj::removeRefreshListener( const uno::Reference<util::XRefreshListener >& xListener )
+{
+ if (xListener.is())
+ {
+ SolarMutexGuard aGuard;
+ if (mpRefreshListeners)
+ mpRefreshListeners->removeInterface(xListener);
+ }
+}
+
+SvxFieldData& ScEditFieldObj::getData()
+{
+ if (!mpData)
+ {
+ switch (meType)
+ {
+ case text::textfield::Type::DATE:
+ mpData.reset(new SvxDateField);
+ break;
+ case text::textfield::Type::EXTENDED_FILE:
+ mpData.reset(
+ new SvxExtFileField(OUString(), SvxFileType::Var, SvxFileFormat::NameAndExt));
+ break;
+ case text::textfield::Type::PAGE:
+ mpData.reset(new SvxPageField);
+ break;
+ case text::textfield::Type::PAGES:
+ mpData.reset(new SvxPagesField);
+ break;
+ case text::textfield::Type::TABLE:
+ mpData.reset(new SvxTableField);
+ break;
+ case text::textfield::Type::TIME:
+ mpData.reset(new SvxTimeField);
+ break;
+ case text::textfield::Type::EXTENDED_TIME:
+ {
+ if (mbIsDate)
+ mpData.reset(new SvxDateField);
+ else
+ mpData.reset(new SvxExtTimeField);
+ }
+ break;
+ case text::textfield::Type::DOCINFO_TITLE:
+ mpData.reset(new SvxFileField);
+ break;
+ case text::textfield::Type::URL:
+ mpData.reset(
+ new SvxURLField(OUString(), OUString(), SvxURLFormat::AppDefault));
+ break;
+ default:
+ mpData.reset(new SvxFieldData);
+ }
+ }
+ return *mpData;
+}
+
+void ScEditFieldObj::setPropertyValueURL(const OUString& rName, const css::uno::Any& rVal)
+{
+ OUString aStrVal;
+ if (mpEditSource)
+ {
+ // Edit engine instance already exists for this field item. Use it.
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ // don't care about the type (only URLs can be found in the cells)
+ SvxFieldData* pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::UNSPECIFIED);
+ OSL_ENSURE(pField,"setPropertyValue: Field not found");
+ if (!pField)
+ return;
+
+ if (pField->GetClassId() != text::textfield::Type::URL)
+ // Make sure this is indeed a URL field.
+ return;
+
+ SvxURLField* pURL = static_cast<SvxURLField*>(pField);
+
+ if (rName == SC_UNONAME_URL)
+ {
+ if (rVal >>= aStrVal)
+ pURL->SetURL(aStrVal);
+ }
+ else if (rName == SC_UNONAME_REPR)
+ {
+ if (rVal >>= aStrVal)
+ pURL->SetRepresentation(aStrVal);
+ }
+ else if (rName == SC_UNONAME_TARGET)
+ {
+ if (rVal >>= aStrVal)
+ pURL->SetTargetFrame(aStrVal);
+ }
+ else
+ throw beans::UnknownPropertyException(rName);
+
+ pEditEngine->QuickInsertField( SvxFieldItem(*pField, EE_FEATURE_FIELD), aSelection );
+ mpEditSource->UpdateData();
+ return;
+ }
+
+ // Edit engine instance not yet present. Store the item data for later use.
+ SvxURLField& rData = static_cast<SvxURLField&>(getData());
+ if (rName == SC_UNONAME_URL)
+ {
+ if (rVal >>= aStrVal)
+ rData.SetURL(aStrVal);
+ }
+ else if (rName == SC_UNONAME_REPR)
+ {
+ if (rVal >>= aStrVal)
+ rData.SetRepresentation(aStrVal);
+ }
+ else if (rName == SC_UNONAME_TARGET)
+ {
+ if (rVal >>= aStrVal)
+ rData.SetTargetFrame(aStrVal);
+ }
+ else
+ throw beans::UnknownPropertyException(rName);
+}
+
+uno::Any ScEditFieldObj::getPropertyValueURL(const OUString& rName)
+{
+ uno::Any aRet;
+
+ // anchor type is always "as character", text wrap always "none"
+
+ if (mpEditSource)
+ {
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ // don't care about the type (only URLs can be found in the cells)
+ const SvxFieldData* pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::UNSPECIFIED);
+ OSL_ENSURE(pField,"getPropertyValue: Field not found");
+ if (!pField)
+ throw uno::RuntimeException();
+
+ if (pField->GetClassId() != text::textfield::Type::URL)
+ throw uno::RuntimeException();
+
+ const SvxURLField* pURL = static_cast<const SvxURLField*>(pField);
+
+ if (rName == SC_UNONAME_URL)
+ aRet <<= pURL->GetURL();
+ else if (rName == SC_UNONAME_REPR)
+ aRet <<= pURL->GetRepresentation();
+ else if (rName == SC_UNONAME_TARGET)
+ aRet <<= pURL->GetTargetFrame();
+ else
+ throw beans::UnknownPropertyException(rName);
+ }
+ else // not inserted yet
+ {
+ const SvxURLField& rURL = static_cast<const SvxURLField&>(getData());
+
+ if (rName == SC_UNONAME_URL)
+ aRet <<= rURL.GetURL();
+ else if (rName == SC_UNONAME_REPR)
+ aRet <<= rURL.GetRepresentation();
+ else if (rName == SC_UNONAME_TARGET)
+ aRet <<= rURL.GetTargetFrame();
+ else
+ throw beans::UnknownPropertyException(rName);
+ }
+ return aRet;
+}
+
+void ScEditFieldObj::setPropertyValueFile(const OUString& rName, const uno::Any& rVal)
+{
+ if (rName != SC_UNONAME_FILEFORM)
+ throw beans::UnknownPropertyException(rName);
+
+ sal_Int16 nIntVal = 0;
+ if (!(rVal >>= nIntVal))
+ return;
+
+ SvxFileFormat eFormat = lcl_UnoToSvxFileFormat(nIntVal);
+ if (mpEditSource)
+ {
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ SvxFieldData* pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::EXTENDED_FILE);
+ OSL_ENSURE(pField, "setPropertyValueFile: Field not found");
+ if (pField)
+ {
+ SvxExtFileField* pExtFile = static_cast<SvxExtFileField*>(pField); // local to the ScUnoEditEngine
+ pExtFile->SetFormat(eFormat);
+ pEditEngine->QuickInsertField(SvxFieldItem(*pField, EE_FEATURE_FIELD), aSelection);
+ mpEditSource->UpdateData();
+ }
+ }
+ else
+ {
+ SvxExtFileField& rExtFile = static_cast<SvxExtFileField&>(getData());
+ rExtFile.SetFormat(eFormat);
+ }
+
+}
+
+uno::Any ScEditFieldObj::getPropertyValueFile(const OUString& rName)
+{
+ uno::Any aRet;
+ if (rName != SC_UNONAME_FILEFORM)
+ throw beans::UnknownPropertyException(rName);
+
+ SvxFileFormat eFormat = SvxFileFormat::NameAndExt;
+ const SvxFieldData* pField = nullptr;
+ if (mpEditSource)
+ {
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::EXTENDED_FILE);
+ }
+ else
+ pField = &getData();
+
+ OSL_ENSURE(pField, "setPropertyValueFile: Field not found");
+ if (!pField)
+ throw uno::RuntimeException();
+
+ const SvxExtFileField* pExtFile = static_cast<const SvxExtFileField*>(pField);
+ eFormat = pExtFile->GetFormat();
+ sal_Int16 nIntVal = lcl_SvxToUnoFileFormat(eFormat);
+ aRet <<= nIntVal;
+
+ return aRet;
+}
+
+void ScEditFieldObj::setPropertyValueDateTime(const OUString& rName, const uno::Any& rVal)
+{
+ if (mpEditSource)
+ {
+ // Field already inserted.
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ SvxFieldData* pField = aTempEngine.FindByPos(aSelection.nStartPara, aSelection.nStartPos, meType);
+ if (!pField)
+ return;
+
+ switch (meType)
+ {
+ case text::textfield::Type::DATE:
+ {
+ SvxDateField* p = static_cast<SvxDateField*>(pField);
+ if (rName == SC_UNONAME_ISDATE)
+ {
+ // Do nothing for now.
+ }
+ else if (rName == SC_UNONAME_ISFIXED)
+ {
+ SvxDateType eType = rVal.get<bool>() ? SvxDateType::Fix : SvxDateType::Var;
+ p->SetType(eType);
+ }
+ else if (rName == SC_UNONAME_DATETIME)
+ {
+ maDateTime = rVal.get<util::DateTime>();
+ Date aDate(maDateTime.Day, maDateTime.Month, maDateTime.Year);
+ p->SetFixDate(aDate);
+ }
+ else if (rName == SC_UNONAME_NUMFMT)
+ {
+ mnNumFormat = rVal.get<sal_Int32>();
+ p->SetFormat(static_cast<SvxDateFormat>(mnNumFormat));
+ }
+ else
+ throw beans::UnknownPropertyException(rName);
+ }
+ break;
+ case text::textfield::Type::TIME:
+ {
+ // SvxTimeField doesn't have any attributes.
+ if (rName != SC_UNONAME_ISDATE && rName != SC_UNONAME_ISFIXED &&
+ rName != SC_UNONAME_DATETIME && rName != SC_UNONAME_NUMFMT)
+ throw beans::UnknownPropertyException(rName);
+ }
+ break;
+ case text::textfield::Type::EXTENDED_TIME:
+ {
+ SvxExtTimeField* p = static_cast<SvxExtTimeField*>(pField);
+ if (rName == SC_UNONAME_ISDATE)
+ {
+ // Do nothing for now.
+ }
+ else if (rName == SC_UNONAME_ISFIXED)
+ {
+ SvxTimeType eType = rVal.get<bool>() ? SvxTimeType::Fix : SvxTimeType::Var;
+ p->SetType(eType);
+ }
+ else if (rName == SC_UNONAME_DATETIME)
+ {
+ maDateTime = rVal.get<util::DateTime>();
+ tools::Time aTime(maDateTime);
+ p->SetFixTime(aTime);
+ }
+ else if (rName == SC_UNONAME_NUMFMT)
+ {
+ mnNumFormat = rVal.get<sal_Int32>();
+ p->SetFormat(static_cast<SvxTimeFormat>(mnNumFormat));
+ }
+ else
+ throw beans::UnknownPropertyException(rName);
+ }
+ break;
+ default:
+ throw beans::UnknownPropertyException(rName);
+ }
+ }
+ else
+ {
+ if (rName == SC_UNONAME_ISDATE)
+ mbIsDate = rVal.get<bool>();
+ else if (rName == SC_UNONAME_ISFIXED)
+ mbIsFixed = rVal.get<bool>();
+ else if (rName == SC_UNONAME_DATETIME)
+ maDateTime = rVal.get<util::DateTime>();
+ else if (rName == SC_UNONAME_NUMFMT)
+ mnNumFormat = rVal.get<sal_Int32>();
+ else
+ throw beans::UnknownPropertyException(rName);
+ }
+}
+
+uno::Any ScEditFieldObj::getPropertyValueDateTime(const OUString& rName)
+{
+ if (mpEditSource)
+ {
+ // Field already inserted.
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+ SvxFieldData* pField = aTempEngine.FindByPos(aSelection.nStartPara, aSelection.nStartPos, meType);
+ if (!pField)
+ throw uno::RuntimeException();
+
+ switch (meType)
+ {
+ case text::textfield::Type::DATE:
+ {
+ SvxDateField* p = static_cast<SvxDateField*>(pField);
+ if (rName == SC_UNONAME_ISDATE)
+ return uno::Any(true);
+
+ if (rName == SC_UNONAME_ISFIXED)
+ return uno::Any(p->GetType() == SvxDateType::Fix);
+
+ if (rName == SC_UNONAME_DATETIME)
+ {
+ Date aD(p->GetFixDate());
+ maDateTime.Year = aD.GetYear();
+ maDateTime.Month = aD.GetMonth();
+ maDateTime.Day = aD.GetDay();
+ maDateTime.Hours = 0;
+ maDateTime.Minutes = 0;
+ maDateTime.Seconds = 0;
+ maDateTime.NanoSeconds = 0;
+ return uno::Any(maDateTime);
+ }
+
+ if (rName == SC_UNONAME_NUMFMT)
+ return uno::Any(static_cast<sal_Int32>(p->GetFormat()));
+ }
+ break;
+ case text::textfield::Type::TIME:
+ {
+ // SvxTimeField doesn't have any attributes.
+ if (rName == SC_UNONAME_ISDATE)
+ return uno::Any(false);
+
+ if (rName == SC_UNONAME_ISFIXED)
+ return uno::Any(false);
+
+ if (rName == SC_UNONAME_DATETIME)
+ // This is the best we can do.
+ return uno::Any(maDateTime);
+
+ if (rName == SC_UNONAME_NUMFMT)
+ // Same as above.
+ return uno::Any(sal_Int32(0));
+ }
+ break;
+ case text::textfield::Type::EXTENDED_TIME:
+ {
+ SvxExtTimeField* p = static_cast<SvxExtTimeField*>(pField);
+ if (rName == SC_UNONAME_ISDATE)
+ return uno::Any(false);
+
+ if (rName == SC_UNONAME_ISFIXED)
+ return uno::Any(p->GetType() == SvxTimeType::Fix);
+
+ if (rName == SC_UNONAME_DATETIME)
+ {
+ tools::Time aT(p->GetFixTime());
+ maDateTime.Year = 0;
+ maDateTime.Month = 0;
+ maDateTime.Day = 0;
+ maDateTime.Hours = aT.GetHour();
+ maDateTime.Minutes = aT.GetMin();
+ maDateTime.Seconds = aT.GetSec();
+ maDateTime.NanoSeconds = aT.GetNanoSec();
+ return uno::Any(maDateTime);
+ }
+
+ if (rName == SC_UNONAME_NUMFMT)
+ return uno::Any(static_cast<sal_Int32>(p->GetFormat()));
+ }
+ break;
+ default:
+ ;
+ }
+ }
+ else
+ {
+ if (rName == SC_UNONAME_ISDATE)
+ return uno::Any(mbIsDate);
+
+ if (rName == SC_UNONAME_ISFIXED)
+ return uno::Any(mbIsFixed);
+
+ if (rName == SC_UNONAME_DATETIME)
+ return uno::Any(maDateTime);
+
+ if (rName == SC_UNONAME_NUMFMT)
+ return uno::Any(mnNumFormat);
+ }
+
+ throw beans::UnknownPropertyException(rName);
+}
+
+void ScEditFieldObj::setPropertyValueSheet(const OUString& rName, const uno::Any& rVal)
+{
+ if (mpEditSource)
+ {
+ // Edit engine instance already exists for this field item. Use it.
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ // don't care about the type (only URLs can be found in the cells)
+ SvxFieldData* pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::UNSPECIFIED);
+ OSL_ENSURE(pField,"setPropertyValue: Field not found");
+ if (!pField)
+ return;
+
+ if (pField->GetClassId() != text::textfield::Type::TABLE)
+ // Make sure this is indeed a URL field.
+ return;
+
+ SvxTableField* p = static_cast<SvxTableField*>(pField);
+
+ if (rName != SC_UNONAME_TABLEPOS)
+ throw beans::UnknownPropertyException(rName);
+
+ sal_Int32 nTab = rVal.get<sal_Int32>();
+ p->SetTab(nTab);
+
+
+ pEditEngine->QuickInsertField(SvxFieldItem(*pField, EE_FEATURE_FIELD), aSelection);
+ mpEditSource->UpdateData();
+ return;
+ }
+
+ // Edit engine instance not yet present. Store the item data for later use.
+ SvxTableField& r = static_cast<SvxTableField&>(getData());
+ if (rName != SC_UNONAME_TABLEPOS)
+ throw beans::UnknownPropertyException(rName);
+
+ sal_Int32 nTab = rVal.get<sal_Int32>();
+ r.SetTab(nTab);
+}
+
+ScEditFieldObj::ScEditFieldObj(
+ const uno::Reference<text::XTextRange>& rContent,
+ std::unique_ptr<ScEditSource> pEditSrc, sal_Int32 eType, const ESelection& rSel) :
+ pPropSet(nullptr),
+ mpEditSource(std::move(pEditSrc)),
+ aSelection(rSel),
+ meType(eType), mpContent(rContent), mnNumFormat(0), mbIsDate(false), mbIsFixed(false)
+{
+ switch (meType)
+ {
+ case text::textfield::Type::DOCINFO_TITLE:
+ pPropSet = getEmptyPropertySet();
+ break;
+ case text::textfield::Type::EXTENDED_FILE:
+ pPropSet = lcl_GetFileFieldPropertySet();
+ break;
+ case text::textfield::Type::URL:
+ pPropSet = lcl_GetURLPropertySet();
+ break;
+ case text::textfield::Type::DATE:
+ case text::textfield::Type::TIME:
+ case text::textfield::Type::EXTENDED_TIME:
+ pPropSet = getDateTimePropertySet();
+ break;
+ default:
+ pPropSet = lcl_GetHeaderFieldPropertySet();
+ }
+
+ if (meType == text::textfield::Type::DATE)
+ mbIsDate = true;
+}
+
+void ScEditFieldObj::InitDoc(
+ const uno::Reference<text::XTextRange>& rContent, std::unique_ptr<ScEditSource> pEditSrc, const ESelection& rSel)
+{
+ if (!mpEditSource)
+ {
+ mpContent = rContent;
+ mpData.reset();
+
+ aSelection = rSel;
+ mpEditSource = std::move( pEditSrc );
+ }
+}
+
+ScEditFieldObj::~ScEditFieldObj()
+{
+}
+
+SvxFieldItem ScEditFieldObj::CreateFieldItem()
+{
+ OSL_ENSURE( !mpEditSource, "CreateFieldItem with inserted field" );
+ return SvxFieldItem(getData(), EE_FEATURE_FIELD);
+}
+
+void ScEditFieldObj::DeleteField()
+{
+ if (mpEditSource)
+ {
+ SvxTextForwarder* pForwarder = mpEditSource->GetTextForwarder();
+ pForwarder->QuickInsertText( OUString(), aSelection );
+ mpEditSource->UpdateData();
+
+ aSelection.nEndPara = aSelection.nStartPara;
+ aSelection.nEndPos = aSelection.nStartPos;
+
+ //! Broadcast in order to adjust selection in other objects
+ //! (also for other actions)
+ }
+}
+
+bool ScEditFieldObj::IsInserted() const
+{
+ return mpEditSource != nullptr;
+}
+
+// XTextField
+
+OUString SAL_CALL ScEditFieldObj::getPresentation( sal_Bool bShowCommand )
+{
+ SolarMutexGuard aGuard;
+
+ if (!mpEditSource)
+ return OUString();
+
+ //! Field functions have to be passed to the forwarder !!!
+ ScEditEngineDefaulter* pEditEngine = mpEditSource->GetEditEngine();
+ ScUnoEditEngine aTempEngine(pEditEngine);
+
+ // don't care about the type (only URLs can be found in the cells)
+ const SvxFieldData* pField = aTempEngine.FindByPos(
+ aSelection.nStartPara, aSelection.nStartPos, text::textfield::Type::UNSPECIFIED);
+ OSL_ENSURE(pField,"getPresentation: Field not found");
+ if (!pField)
+ return OUString();
+
+ switch (meType)
+ {
+ case text::textfield::Type::URL:
+ {
+ if (pField->GetClassId() != text::textfield::Type::URL)
+ // Not a URL field, but URL is expected.
+ throw uno::RuntimeException();
+
+ const SvxURLField* pURL = static_cast<const SvxURLField*>(pField);
+ return bShowCommand ? pURL->GetURL() : pURL->GetRepresentation();
+ }
+ break;
+ default:
+ ;
+ }
+ return OUString();
+}
+
+// XTextContent
+
+void SAL_CALL ScEditFieldObj::attach( const uno::Reference<text::XTextRange>& xTextRange )
+{
+ SolarMutexGuard aGuard;
+ if (xTextRange.is())
+ {
+ uno::Reference<text::XText> xText(xTextRange->getText());
+ if (xText.is())
+ {
+ xText->insertTextContent( xTextRange, this, true );
+ }
+ }
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScEditFieldObj::getAnchor()
+{
+ SolarMutexGuard aGuard;
+ return mpContent;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScEditFieldObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<beans::XPropertySetInfo> aRef = pPropSet->getPropertySetInfo();
+ return aRef;
+}
+
+void SAL_CALL ScEditFieldObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ if (aPropertyName == SC_UNONAME_ANCHOR)
+ {
+ aValue >>= mpContent;
+ return;
+ }
+
+ switch (meType)
+ {
+ case text::textfield::Type::URL:
+ setPropertyValueURL(aPropertyName, aValue);
+ break;
+ case text::textfield::Type::EXTENDED_FILE:
+ setPropertyValueFile(aPropertyName, aValue);
+ break;
+ case text::textfield::Type::DATE:
+ case text::textfield::Type::TIME:
+ case text::textfield::Type::EXTENDED_TIME:
+ setPropertyValueDateTime(aPropertyName, aValue);
+ break;
+ case text::textfield::Type::TABLE:
+ setPropertyValueSheet(aPropertyName, aValue);
+ break;
+ case text::textfield::Type::DOCINFO_TITLE:
+ default:
+ throw beans::UnknownPropertyException(OUString::number(meType));
+ }
+}
+
+uno::Any SAL_CALL ScEditFieldObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ if (aPropertyName == SC_UNONAME_TEXTFIELD_TYPE)
+ return uno::Any(meType);
+
+ if (aPropertyName == SC_UNONAME_ANCHOR)
+ return uno::Any(mpContent);
+
+ if (aPropertyName == SC_UNONAME_ANCTYPE)
+ {
+ uno::Any aRet;
+ aRet <<= text::TextContentAnchorType_AS_CHARACTER;
+ return aRet;
+ }
+ if (aPropertyName == SC_UNONAME_ANCTYPES)
+ {
+ uno::Any aRet;
+ uno::Sequence<text::TextContentAnchorType> aSeq { text::TextContentAnchorType_AS_CHARACTER };
+ aRet <<= aSeq;
+ return aRet;
+ }
+ if (aPropertyName == SC_UNONAME_TEXTWRAP)
+ {
+ uno::Any aRet;
+ aRet <<= text::WrapTextMode_NONE;
+ return aRet;
+ }
+
+ switch (meType)
+ {
+ case text::textfield::Type::URL:
+ return getPropertyValueURL(aPropertyName);
+ case text::textfield::Type::EXTENDED_FILE:
+ return getPropertyValueFile(aPropertyName);
+ case text::textfield::Type::DATE:
+ case text::textfield::Type::TIME:
+ case text::textfield::Type::EXTENDED_TIME:
+ return getPropertyValueDateTime(aPropertyName);
+ case text::textfield::Type::DOCINFO_TITLE:
+ default:
+ throw beans::UnknownPropertyException(OUString::number(meType));
+ }
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScEditFieldObj )
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION_IMPL(ScEditFieldObj);
+
+// XServiceInfo
+
+OUString SAL_CALL ScEditFieldObj::getImplementationName()
+{
+ return "ScEditFieldObj";
+}
+
+sal_Bool SAL_CALL ScEditFieldObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScEditFieldObj::getSupportedServiceNames()
+{
+ return {"com.sun.star.text.TextField",
+ "com.sun.star.text.TextContent"};
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScEditFieldObj::getTypes()
+{
+ return comphelper::concatSequences(
+ ScEditFieldObj_Base::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<text::XTextField>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get()
+ } );
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScEditFieldObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/filtuno.cxx b/sc/source/ui/unoobj/filtuno.cxx
new file mode 100644
index 000000000..a2b4d0f7e
--- /dev/null
+++ b/sc/source/ui/unoobj/filtuno.cxx
@@ -0,0 +1,363 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/dialogs/ExecutableDialogResults.hpp>
+#include <tools/urlobj.hxx>
+#include <vcl/svapp.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+#include <connectivity/dbtools.hxx>
+#include <osl/diagnose.h>
+
+#include <filtuno.hxx>
+#include <miscuno.hxx>
+#include <scdll.hxx>
+#include <imoptdlg.hxx>
+#include <asciiopt.hxx>
+#include <docsh.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <scabstdlg.hxx>
+#include <i18nlangtag/lang.h>
+
+#include <optutil.hxx>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+using namespace com::sun::star::uno;
+using namespace connectivity::dbase;
+
+constexpr OUStringLiteral SCFILTEROPTIONSOBJ_SERVICE = u"com.sun.star.ui.dialogs.FilterOptionsDialog";
+constexpr OUStringLiteral SCFILTEROPTIONSOBJ_IMPLNAME = u"com.sun.star.comp.Calc.FilterOptionsDialog";
+
+SC_SIMPLE_SERVICE_INFO( ScFilterOptionsObj, SCFILTEROPTIONSOBJ_IMPLNAME, SCFILTEROPTIONSOBJ_SERVICE )
+
+constexpr OUStringLiteral SC_UNONAME_FILENAME = u"URL";
+constexpr OUStringLiteral SC_UNONAME_FILTERNAME = u"FilterName";
+constexpr OUStringLiteral SC_UNONAME_FILTEROPTIONS = u"FilterOptions";
+constexpr OUStringLiteral SC_UNONAME_INPUTSTREAM = u"InputStream";
+
+constexpr OUStringLiteral DBF_CHAR_SET = u"CharSet";
+constexpr OUStringLiteral DBF_SEP_PATH_IMPORT = u"Office.Calc/Dialogs/DBFImport";
+constexpr OUStringLiteral DBF_SEP_PATH_EXPORT = u"Office.Calc/Dialogs/DBFExport";
+
+namespace
+{
+
+ enum class charsetSource
+ {
+ charset_from_file,
+ charset_from_user_setting,
+ charset_default
+ };
+
+ charsetSource load_CharSet(rtl_TextEncoding &nCharSet, bool bExport, SvStream* dbf_Stream)
+ {
+ if (dbf_Stream && dbfReadCharset(nCharSet, dbf_Stream))
+ {
+ return charsetSource::charset_from_file;
+ }
+
+ Sequence<Any> aValues;
+ const Any *pProperties;
+ Sequence<OUString> aNames { DBF_CHAR_SET };
+ ScLinkConfigItem aItem( bExport ? DBF_SEP_PATH_EXPORT : DBF_SEP_PATH_IMPORT );
+
+ aValues = aItem.GetProperties( aNames );
+ pProperties = aValues.getConstArray();
+
+ if( pProperties[0].hasValue() )
+ {
+ sal_Int32 nChar = 0;
+ pProperties[0] >>= nChar;
+ if( nChar >= 0)
+ {
+ nCharSet = static_cast<rtl_TextEncoding>(nChar);
+ return charsetSource::charset_from_user_setting;
+ }
+ }
+
+ // Default choice
+ nCharSet = RTL_TEXTENCODING_IBM_850;
+ return charsetSource::charset_default;
+ }
+
+ void save_CharSet( rtl_TextEncoding nCharSet, bool bExport )
+ {
+ Sequence<Any> aValues;
+ Any *pProperties;
+ Sequence<OUString> aNames { DBF_CHAR_SET };
+ ScLinkConfigItem aItem( bExport ? DBF_SEP_PATH_EXPORT : DBF_SEP_PATH_IMPORT );
+
+ aValues = aItem.GetProperties( aNames );
+ pProperties = aValues.getArray();
+ pProperties[0] <<= static_cast<sal_Int32>(nCharSet);
+
+ aItem.PutProperties(aNames, aValues);
+ }
+}
+
+ScFilterOptionsObj::ScFilterOptionsObj() :
+ bExport( false )
+{
+}
+
+ScFilterOptionsObj::~ScFilterOptionsObj()
+{
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_FilterOptionsDialog_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScFilterOptionsObj);
+}
+
+// XPropertyAccess
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScFilterOptionsObj::getPropertyValues()
+{
+ return comphelper::InitPropertySequence({
+ { SC_UNONAME_FILTEROPTIONS, Any(aFilterOptions) }
+ });
+}
+
+void SAL_CALL ScFilterOptionsObj::setPropertyValues( const uno::Sequence<beans::PropertyValue>& aProps )
+{
+ for (const beans::PropertyValue& rProp : aProps)
+ {
+ OUString aPropName(rProp.Name);
+
+ if ( aPropName == SC_UNONAME_FILENAME )
+ rProp.Value >>= aFileName;
+ else if ( aPropName == SC_UNONAME_FILTERNAME )
+ rProp.Value >>= aFilterName;
+ else if ( aPropName == SC_UNONAME_FILTEROPTIONS )
+ rProp.Value >>= aFilterOptions;
+ else if ( aPropName == SC_UNONAME_INPUTSTREAM )
+ rProp.Value >>= xInputStream;
+ }
+}
+
+// XExecutableDialog
+
+void SAL_CALL ScFilterOptionsObj::setTitle( const OUString& /* aTitle */ )
+{
+ // not used
+}
+
+sal_Int16 SAL_CALL ScFilterOptionsObj::execute()
+{
+ sal_Int16 nRet = ui::dialogs::ExecutableDialogResults::CANCEL;
+
+ OUString aFilterString( aFilterName );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ if ( !bExport && aFilterString == ScDocShell::GetAsciiFilterName() )
+ {
+ // ascii import is special...
+
+ INetURLObject aURL( aFileName );
+ // tdf#132421 - don't URL encode filename for the import ASCII dialog title
+ OUString aPrivDatName(aURL.GetLastName(INetURLObject::DecodeMechanism::Unambiguous));
+ std::unique_ptr<SvStream> pInStream;
+ if ( xInputStream.is() )
+ pInStream = utl::UcbStreamHelper::CreateStream( xInputStream );
+
+ ScopedVclPtr<AbstractScImportAsciiDlg> pDlg(pFact->CreateScImportAsciiDlg(Application::GetFrameWeld(xDialogParent), aPrivDatName,
+ pInStream.get(), SC_IMPORTFILE));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ ScAsciiOptions aOptions;
+ pDlg->GetOptions( aOptions );
+ pDlg->SaveParameters();
+ aFilterOptions = aOptions.WriteToString();
+ nRet = ui::dialogs::ExecutableDialogResults::OK;
+ }
+ }
+ else if ( aFilterString == ScDocShell::GetWebQueryFilterName() || aFilterString == ScDocShell::GetHtmlFilterName() )
+ {
+ if (bExport)
+ nRet = ui::dialogs::ExecutableDialogResults::OK; // export HTML without dialog
+ else
+ {
+ // HTML import.
+ ScopedVclPtr<AbstractScTextImportOptionsDlg> pDlg(
+ pFact->CreateScTextImportOptionsDlg(Application::GetFrameWeld(xDialogParent)));
+
+ if (pDlg->Execute() == RET_OK)
+ {
+ LanguageType eLang = pDlg->GetLanguageType();
+ OUStringBuffer aBuf;
+
+ aBuf.append(static_cast<sal_Int32>(static_cast<sal_uInt16>(eLang)));
+ aBuf.append(' ');
+ aBuf.append(pDlg->IsDateConversionSet() ? u'1' : u'0');
+ aFilterOptions = aBuf.makeStringAndClear();
+ nRet = ui::dialogs::ExecutableDialogResults::OK;
+ }
+ }
+ }
+ else
+ {
+ bool bDBEnc = false;
+ bool bAscii = false;
+ bool skipDialog = false;
+
+ sal_Unicode const cStrDel = '"';
+ sal_Unicode cAsciiDel = ';';
+ rtl_TextEncoding eEncoding = RTL_TEXTENCODING_DONTKNOW;
+
+ OUString aTitle;
+
+ if ( aFilterString == ScDocShell::GetAsciiFilterName() )
+ {
+ // ascii export (import is handled above)
+
+ INetURLObject aURL( aFileName );
+ OUString aExt(aURL.getExtension());
+ if (aExt.equalsIgnoreAsciiCase("CSV"))
+ cAsciiDel = ',';
+ else
+ cAsciiDel = '\t';
+
+ aTitle = ScResId( STR_EXPORT_ASCII );
+ bAscii = true;
+ }
+ else if ( aFilterString == ScDocShell::GetLotusFilterName() )
+ {
+ // lotus is only imported
+ OSL_ENSURE( !bExport, "Filter Options for Lotus Export is not implemented" );
+
+ aTitle = ScResId( STR_IMPORT_LOTUS );
+ eEncoding = RTL_TEXTENCODING_IBM_437;
+ }
+ else if ( aFilterString == ScDocShell::GetDBaseFilterName() )
+ {
+ if ( bExport )
+ {
+ // dBase export
+ aTitle = ScResId( STR_EXPORT_DBF );
+ }
+ else
+ {
+ // dBase import
+ aTitle = ScResId( STR_IMPORT_DBF );
+ }
+
+ std::unique_ptr<SvStream> pInStream;
+ if ( xInputStream.is() )
+ pInStream = utl::UcbStreamHelper::CreateStream( xInputStream );
+ switch(load_CharSet( eEncoding, bExport, pInStream.get()))
+ {
+ case charsetSource::charset_from_file:
+ skipDialog = true;
+ break;
+ case charsetSource::charset_from_user_setting:
+ case charsetSource::charset_default:
+ break;
+ }
+ bDBEnc = true;
+ // pInStream goes out of scope, the stream is automatically closed
+ }
+ else if ( aFilterString == ScDocShell::GetDifFilterName() )
+ {
+ if ( bExport )
+ {
+ // DIF export
+ aTitle = ScResId( STR_EXPORT_DIF );
+ }
+ else
+ {
+ // DIF import
+ aTitle = ScResId( STR_IMPORT_DIF );
+ }
+ // common for DIF import/export
+ eEncoding = RTL_TEXTENCODING_MS_1252;
+ }
+
+ ScImportOptions aOptions( cAsciiDel, cStrDel, eEncoding);
+ if(skipDialog)
+ {
+ // TODO: check we are not missing some of the stuff that ScImportOptionsDlg::GetImportOptions
+ // (file sc/source/ui/dbgui/scuiimoptdlg.cxx) does
+ // that is, if the dialog sets options that are not selected by the user (!)
+ // then we are missing them here.
+ // Then we may need to rip them out of the dialog.
+ // Or we actually change the dialog to not display if skipDialog==true
+ // in that case, add an argument skipDialog to CreateScImportOptionsDlg
+ nRet = ui::dialogs::ExecutableDialogResults::OK;
+ }
+ else
+ {
+ ScopedVclPtr<AbstractScImportOptionsDlg> pDlg(pFact->CreateScImportOptionsDlg(Application::GetFrameWeld(xDialogParent),
+ bAscii, &aOptions, &aTitle,
+ bDBEnc, !bExport));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ pDlg->SaveImportOptions();
+ pDlg->GetImportOptions( aOptions );
+ save_CharSet( aOptions.eCharSet, bExport );
+ nRet = ui::dialogs::ExecutableDialogResults::OK;
+ }
+ }
+ if (nRet == ui::dialogs::ExecutableDialogResults::OK)
+ {
+ if ( bAscii )
+ aFilterOptions = aOptions.BuildString();
+ else
+ aFilterOptions = aOptions.aStrFont;
+ }
+ }
+
+ xInputStream.clear(); // don't hold the stream longer than necessary
+
+ return nRet;
+}
+
+// XImporter
+
+void SAL_CALL ScFilterOptionsObj::setTargetDocument( const uno::Reference<lang::XComponent>& /* xDoc */ )
+{
+ bExport = false;
+}
+
+// XExporter
+
+void SAL_CALL ScFilterOptionsObj::setSourceDocument( const uno::Reference<lang::XComponent>& /* xDoc */ )
+{
+ bExport = true;
+}
+
+// XInitialization
+
+void SAL_CALL ScFilterOptionsObj::initialize(const uno::Sequence<uno::Any>& rArguments)
+{
+ ::comphelper::NamedValueCollection aProperties(rArguments);
+ if (aProperties.has("ParentWindow"))
+ aProperties.get("ParentWindow") >>= xDialogParent;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/fmtuno.cxx b/sc/source/ui/unoobj/fmtuno.cxx
new file mode 100644
index 000000000..64ff28419
--- /dev/null
+++ b/sc/source/ui/unoobj/fmtuno.cxx
@@ -0,0 +1,921 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <osl/diagnose.h>
+#include <svl/style.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/sheet/ConditionOperator2.hpp>
+#include <com/sun/star/sheet/ValidationAlertStyle.hpp>
+#include <com/sun/star/sheet/ValidationType.hpp>
+#include <com/sun/star/sheet/TableValidationVisibility.hpp>
+
+#include <fmtuno.hxx>
+#include <miscuno.hxx>
+#include <validat.hxx>
+#include <document.hxx>
+#include <unonames.hxx>
+#include <tokenarray.hxx>
+#include <tokenuno.hxx>
+#include <stylehelper.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::formula;
+
+// map only for PropertySetInfo
+
+static const SfxItemPropertyMapEntry* lcl_GetValidatePropertyMap()
+{
+ static const SfxItemPropertyMapEntry aValidatePropertyMap_Impl[] =
+ {
+ { SC_UNONAME_ERRALSTY, 0, cppu::UnoType<sheet::ValidationAlertStyle>::get(), 0, 0},
+ { SC_UNONAME_ERRMESS, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_ERRTITLE, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_IGNOREBL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_INPMESS, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_INPTITLE, 0, cppu::UnoType<OUString>::get(), 0, 0},
+ { SC_UNONAME_SHOWERR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_SHOWINP, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNONAME_SHOWLIST, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNONAME_TYPE, 0, cppu::UnoType<sheet::ValidationType>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aValidatePropertyMap_Impl;
+}
+
+SC_SIMPLE_SERVICE_INFO( ScTableConditionalEntry, "ScTableConditionalEntry", "com.sun.star.sheet.TableConditionalEntry" )
+SC_SIMPLE_SERVICE_INFO( ScTableConditionalFormat, "ScTableConditionalFormat", "com.sun.star.sheet.TableConditionalFormat" )
+SC_SIMPLE_SERVICE_INFO( ScTableValidationObj, "ScTableValidationObj", "com.sun.star.sheet.TableValidation" )
+
+static sal_Int32 lcl_ConditionModeToOperatorNew( ScConditionMode eMode )
+{
+ sal_Int32 eOper = sheet::ConditionOperator2::NONE;
+ switch (eMode)
+ {
+ case ScConditionMode::Equal: eOper = sheet::ConditionOperator2::EQUAL; break;
+ case ScConditionMode::Less: eOper = sheet::ConditionOperator2::LESS; break;
+ case ScConditionMode::Greater: eOper = sheet::ConditionOperator2::GREATER; break;
+ case ScConditionMode::EqLess: eOper = sheet::ConditionOperator2::LESS_EQUAL; break;
+ case ScConditionMode::EqGreater: eOper = sheet::ConditionOperator2::GREATER_EQUAL; break;
+ case ScConditionMode::NotEqual: eOper = sheet::ConditionOperator2::NOT_EQUAL; break;
+ case ScConditionMode::Between: eOper = sheet::ConditionOperator2::BETWEEN; break;
+ case ScConditionMode::NotBetween: eOper = sheet::ConditionOperator2::NOT_BETWEEN; break;
+ case ScConditionMode::Direct: eOper = sheet::ConditionOperator2::FORMULA; break;
+ case ScConditionMode::Duplicate: eOper = sheet::ConditionOperator2::DUPLICATE; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return eOper;
+}
+
+static sheet::ConditionOperator lcl_ConditionModeToOperator( ScConditionMode eMode )
+{
+ sheet::ConditionOperator eOper = sheet::ConditionOperator_NONE;
+ switch (eMode)
+ {
+ case ScConditionMode::Equal: eOper = sheet::ConditionOperator_EQUAL; break;
+ case ScConditionMode::Less: eOper = sheet::ConditionOperator_LESS; break;
+ case ScConditionMode::Greater: eOper = sheet::ConditionOperator_GREATER; break;
+ case ScConditionMode::EqLess: eOper = sheet::ConditionOperator_LESS_EQUAL; break;
+ case ScConditionMode::EqGreater: eOper = sheet::ConditionOperator_GREATER_EQUAL; break;
+ case ScConditionMode::NotEqual: eOper = sheet::ConditionOperator_NOT_EQUAL; break;
+ case ScConditionMode::Between: eOper = sheet::ConditionOperator_BETWEEN; break;
+ case ScConditionMode::NotBetween: eOper = sheet::ConditionOperator_NOT_BETWEEN; break;
+ case ScConditionMode::Direct: eOper = sheet::ConditionOperator_FORMULA; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return eOper;
+}
+
+static ScConditionMode lcl_ConditionOperatorToMode( sheet::ConditionOperator eOper )
+{
+ ScConditionMode eMode = ScConditionMode::NONE;
+ switch (eOper)
+ {
+ case sheet::ConditionOperator_EQUAL: eMode = ScConditionMode::Equal; break;
+ case sheet::ConditionOperator_LESS: eMode = ScConditionMode::Less; break;
+ case sheet::ConditionOperator_GREATER: eMode = ScConditionMode::Greater; break;
+ case sheet::ConditionOperator_LESS_EQUAL: eMode = ScConditionMode::EqLess; break;
+ case sheet::ConditionOperator_GREATER_EQUAL: eMode = ScConditionMode::EqGreater; break;
+ case sheet::ConditionOperator_NOT_EQUAL: eMode = ScConditionMode::NotEqual; break;
+ case sheet::ConditionOperator_BETWEEN: eMode = ScConditionMode::Between; break;
+ case sheet::ConditionOperator_NOT_BETWEEN: eMode = ScConditionMode::NotBetween; break;
+ case sheet::ConditionOperator_FORMULA: eMode = ScConditionMode::Direct; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return eMode;
+}
+
+ScCondFormatEntryItem::ScCondFormatEntryItem() :
+ meGrammar1( FormulaGrammar::GRAM_UNSPECIFIED ),
+ meGrammar2( FormulaGrammar::GRAM_UNSPECIFIED ),
+ meMode( ScConditionMode::NONE )
+{
+}
+
+ScTableConditionalFormat::ScTableConditionalFormat(
+ const ScDocument* pDoc, sal_uLong nKey, SCTAB nTab, FormulaGrammar::Grammar eGrammar)
+{
+ // read the entry from the document...
+
+ if ( !(pDoc && nKey) )
+ return;
+
+ ScConditionalFormatList* pList = pDoc->GetCondFormList(nTab);
+ if (!pList)
+ return;
+
+ const ScConditionalFormat* pFormat = pList->GetFormat( nKey );
+ if (!pFormat)
+ return;
+
+ // During save to XML.
+ if (pDoc->IsInExternalReferenceMarking())
+ pFormat->MarkUsedExternalReferences();
+
+ size_t nEntryCount = pFormat->size();
+ for (size_t i=0; i<nEntryCount; i++)
+ {
+ ScCondFormatEntryItem aItem;
+ const ScFormatEntry* pFrmtEntry = pFormat->GetEntry(i);
+ if(pFrmtEntry->GetType() != ScFormatEntry::Type::Condition &&
+ pFrmtEntry->GetType() != ScFormatEntry::Type::ExtCondition)
+ continue;
+
+ const ScCondFormatEntry* pFormatEntry = static_cast<const ScCondFormatEntry*>(pFrmtEntry);
+ aItem.meMode = pFormatEntry->GetOperation();
+ aItem.maPos = pFormatEntry->GetValidSrcPos();
+ aItem.maExpr1 = pFormatEntry->GetExpression(aItem.maPos, 0, 0, eGrammar);
+ aItem.maExpr2 = pFormatEntry->GetExpression(aItem.maPos, 1, 0, eGrammar);
+ aItem.meGrammar1 = aItem.meGrammar2 = eGrammar;
+ aItem.maStyle = pFormatEntry->GetStyle();
+
+ AddEntry_Impl(aItem);
+ }
+}
+
+namespace {
+
+FormulaGrammar::Grammar lclResolveGrammar( FormulaGrammar::Grammar eExtGrammar, FormulaGrammar::Grammar eIntGrammar )
+{
+ if( eExtGrammar != FormulaGrammar::GRAM_UNSPECIFIED )
+ return eExtGrammar;
+ OSL_ENSURE( eIntGrammar != FormulaGrammar::GRAM_UNSPECIFIED, "lclResolveGrammar - unspecified grammar, using GRAM_API" );
+ return (eIntGrammar == FormulaGrammar::GRAM_UNSPECIFIED) ? FormulaGrammar::GRAM_API : eIntGrammar;
+}
+
+} // namespace
+
+void ScTableConditionalFormat::FillFormat( ScConditionalFormat& rFormat,
+ ScDocument& rDoc, FormulaGrammar::Grammar eGrammar) const
+{
+ // ScConditionalFormat = Core-Struktur, has to be empty
+
+ OSL_ENSURE( rFormat.IsEmpty(), "FillFormat: format not empty" );
+
+ for (const auto & i : maEntries)
+ {
+ ScCondFormatEntryItem aData;
+ i->GetData(aData);
+
+ FormulaGrammar::Grammar eGrammar1 = lclResolveGrammar( eGrammar, aData.meGrammar1 );
+ FormulaGrammar::Grammar eGrammar2 = lclResolveGrammar( eGrammar, aData.meGrammar2 );
+
+ ScCondFormatEntry* pCoreEntry = new ScCondFormatEntry( aData.meMode, aData.maExpr1, aData.maExpr2,
+ rDoc, aData.maPos, aData.maStyle, aData.maExprNmsp1, aData.maExprNmsp2, eGrammar1, eGrammar2 );
+
+ if ( !aData.maPosStr.isEmpty() )
+ pCoreEntry->SetSrcString( aData.maPosStr );
+
+ if ( aData.maTokens1.hasElements() )
+ {
+ ScTokenArray aTokenArray(rDoc);
+ if ( ScTokenConversion::ConvertToTokenArray(rDoc, aTokenArray, aData.maTokens1) )
+ pCoreEntry->SetFormula1(aTokenArray);
+ }
+
+ if ( aData.maTokens2.hasElements() )
+ {
+ ScTokenArray aTokenArray(rDoc);
+ if ( ScTokenConversion::ConvertToTokenArray(rDoc, aTokenArray, aData.maTokens2) )
+ pCoreEntry->SetFormula2(aTokenArray);
+ }
+ rFormat.AddEntry( pCoreEntry );
+ }
+}
+
+ScTableConditionalFormat::~ScTableConditionalFormat()
+{
+}
+
+void ScTableConditionalFormat::AddEntry_Impl(const ScCondFormatEntryItem& aEntry)
+{
+ rtl::Reference<ScTableConditionalEntry> pNew = new ScTableConditionalEntry(aEntry);
+ maEntries.emplace_back(pNew);
+}
+
+// XSheetConditionalFormat
+
+ScTableConditionalEntry* ScTableConditionalFormat::GetObjectByIndex_Impl(sal_uInt16 nIndex) const
+{
+ return nIndex < maEntries.size() ? maEntries[nIndex].get() : nullptr;
+}
+
+void SAL_CALL ScTableConditionalFormat::addNew(
+ const uno::Sequence<beans::PropertyValue >& aConditionalEntry )
+{
+ SolarMutexGuard aGuard;
+ ScCondFormatEntryItem aEntry;
+ aEntry.meMode = ScConditionMode::NONE;
+
+ for (const beans::PropertyValue& rProp : aConditionalEntry)
+ {
+ if ( rProp.Name == SC_UNONAME_OPERATOR )
+ {
+ sal_Int32 eOper = ScUnoHelpFunctions::GetEnumFromAny( rProp.Value );
+ aEntry.meMode = ScConditionEntry::GetModeFromApi( static_cast<sheet::ConditionOperator>(eOper) );
+ }
+ else if ( rProp.Name == SC_UNONAME_FORMULA1 )
+ {
+ OUString aStrVal;
+ uno::Sequence<sheet::FormulaToken> aTokens;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maExpr1 = aStrVal;
+ else if ( rProp.Value >>= aTokens )
+ {
+ aEntry.maExpr1.clear();
+ aEntry.maTokens1 = aTokens;
+ }
+ }
+ else if ( rProp.Name == SC_UNONAME_FORMULA2 )
+ {
+ OUString aStrVal;
+ uno::Sequence<sheet::FormulaToken> aTokens;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maExpr2 = aStrVal;
+ else if ( rProp.Value >>= aTokens )
+ {
+ aEntry.maExpr2.clear();
+ aEntry.maTokens2 = aTokens;
+ }
+ }
+ else if ( rProp.Name == SC_UNONAME_SOURCEPOS )
+ {
+ table::CellAddress aAddress;
+ if ( rProp.Value >>= aAddress )
+ aEntry.maPos = ScAddress( static_cast<SCCOL>(aAddress.Column), static_cast<SCROW>(aAddress.Row), aAddress.Sheet );
+ }
+ else if ( rProp.Name == SC_UNONAME_SOURCESTR )
+ {
+ OUString aStrVal;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maPosStr = aStrVal;
+ }
+ else if ( rProp.Name == SC_UNONAME_STYLENAME )
+ {
+ OUString aStrVal;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maStyle = ScStyleNameConversion::ProgrammaticToDisplayName(
+ aStrVal, SfxStyleFamily::Para );
+ }
+ else if ( rProp.Name == SC_UNONAME_FORMULANMSP1 )
+ {
+ OUString aStrVal;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maExprNmsp1 = aStrVal;
+ }
+ else if ( rProp.Name == SC_UNONAME_FORMULANMSP2 )
+ {
+ OUString aStrVal;
+ if ( rProp.Value >>= aStrVal )
+ aEntry.maExprNmsp2 = aStrVal;
+ }
+ else if ( rProp.Name == SC_UNONAME_GRAMMAR1 )
+ {
+ sal_Int32 nVal = 0;
+ if ( rProp.Value >>= nVal )
+ aEntry.meGrammar1 = static_cast< FormulaGrammar::Grammar >( nVal );
+ }
+ else if ( rProp.Name == SC_UNONAME_GRAMMAR2 )
+ {
+ sal_Int32 nVal = 0;
+ if ( rProp.Value >>= nVal )
+ aEntry.meGrammar2 = static_cast< FormulaGrammar::Grammar >( nVal );
+ }
+ else
+ {
+ OSL_FAIL("wrong property");
+ //! Exception...
+ }
+ }
+
+ AddEntry_Impl(aEntry);
+}
+
+void SAL_CALL ScTableConditionalFormat::removeByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+
+ if (nIndex >= 0 && o3tl::make_unsigned(nIndex) < maEntries.size())
+ {
+ maEntries.erase(maEntries.begin()+nIndex);
+ }
+}
+
+void SAL_CALL ScTableConditionalFormat::clear()
+{
+ SolarMutexGuard aGuard;
+ maEntries.clear();
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScTableConditionalFormat::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.TableConditionalEntryEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScTableConditionalFormat::getCount()
+{
+ SolarMutexGuard aGuard;
+ return maEntries.size();
+}
+
+uno::Any SAL_CALL ScTableConditionalFormat::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XSheetConditionalEntry> xEntry(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if (!xEntry.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xEntry);
+}
+
+uno::Type SAL_CALL ScTableConditionalFormat::getElementType()
+{
+ return cppu::UnoType<sheet::XSheetConditionalEntry>::get();
+}
+
+sal_Bool SAL_CALL ScTableConditionalFormat::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// conditional format entries have no real names
+// -> generate name from index
+
+static OUString lcl_GetEntryNameFromIndex( sal_Int32 nIndex )
+{
+ OUString aRet = "Entry" + OUString::number( nIndex );
+ return aRet;
+}
+
+uno::Any SAL_CALL ScTableConditionalFormat::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<sheet::XSheetConditionalEntry> xEntry;
+ tools::Long nCount = maEntries.size();
+ for (tools::Long i=0; i<nCount; i++)
+ if ( aName == lcl_GetEntryNameFromIndex(i) )
+ {
+ xEntry.set(GetObjectByIndex_Impl(static_cast<sal_uInt16>(i)));
+ break;
+ }
+
+ if (!xEntry.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xEntry);
+}
+
+uno::Sequence<OUString> SAL_CALL ScTableConditionalFormat::getElementNames()
+{
+ SolarMutexGuard aGuard;
+
+ tools::Long nCount = maEntries.size();
+ uno::Sequence<OUString> aNames(nCount);
+ OUString* pArray = aNames.getArray();
+ for (tools::Long i=0; i<nCount; i++)
+ pArray[i] = lcl_GetEntryNameFromIndex(i);
+
+ return aNames;
+}
+
+sal_Bool SAL_CALL ScTableConditionalFormat::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+
+ tools::Long nCount = maEntries.size();
+ for (tools::Long i=0; i<nCount; i++)
+ if ( aName == lcl_GetEntryNameFromIndex(i) )
+ return true;
+
+ return false;
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION_IMPL(ScTableConditionalFormat);
+
+ScTableConditionalEntry::ScTableConditionalEntry(const ScCondFormatEntryItem& aItem) :
+ aData( aItem )
+{
+ // #i113668# only store the settings, keep no reference to parent object
+}
+
+ScTableConditionalEntry::~ScTableConditionalEntry()
+{
+}
+
+void ScTableConditionalEntry::GetData(ScCondFormatEntryItem& rData) const
+{
+ rData = aData;
+}
+
+// XSheetCondition
+
+sheet::ConditionOperator SAL_CALL ScTableConditionalEntry::getOperator()
+{
+ SolarMutexGuard aGuard;
+ return lcl_ConditionModeToOperator( aData.meMode );
+}
+
+void SAL_CALL ScTableConditionalEntry::setOperator( sheet::ConditionOperator nOperator )
+{
+ SolarMutexGuard aGuard;
+ aData.meMode = lcl_ConditionOperatorToMode( nOperator );
+}
+
+sal_Int32 SAL_CALL ScTableConditionalEntry::getConditionOperator()
+{
+ SolarMutexGuard aGuard;
+ return lcl_ConditionModeToOperatorNew( aData.meMode );
+}
+
+void SAL_CALL ScTableConditionalEntry::setConditionOperator( sal_Int32 nOperator )
+{
+ SolarMutexGuard aGuard;
+ aData.meMode = ScConditionEntry::GetModeFromApi( static_cast<sheet::ConditionOperator>(nOperator) );
+}
+
+OUString SAL_CALL ScTableConditionalEntry::getFormula1()
+{
+ SolarMutexGuard aGuard;
+ return aData.maExpr1;
+}
+
+void SAL_CALL ScTableConditionalEntry::setFormula1( const OUString& aFormula1 )
+{
+ SolarMutexGuard aGuard;
+ aData.maExpr1 = aFormula1;
+}
+
+OUString SAL_CALL ScTableConditionalEntry::getFormula2()
+{
+ SolarMutexGuard aGuard;
+ return aData.maExpr2;
+}
+
+void SAL_CALL ScTableConditionalEntry::setFormula2( const OUString& aFormula2 )
+{
+ SolarMutexGuard aGuard;
+ aData.maExpr2 = aFormula2;
+}
+
+table::CellAddress SAL_CALL ScTableConditionalEntry::getSourcePosition()
+{
+ SolarMutexGuard aGuard;
+ table::CellAddress aRet;
+ aRet.Column = aData.maPos.Col();
+ aRet.Row = aData.maPos.Row();
+ aRet.Sheet = aData.maPos.Tab();
+ return aRet;
+}
+
+void SAL_CALL ScTableConditionalEntry::setSourcePosition( const table::CellAddress& aSourcePosition )
+{
+ SolarMutexGuard aGuard;
+ aData.maPos.Set( static_cast<SCCOL>(aSourcePosition.Column), static_cast<SCROW>(aSourcePosition.Row), aSourcePosition.Sheet );
+}
+
+// XSheetConditionalEntry
+
+OUString SAL_CALL ScTableConditionalEntry::getStyleName()
+{
+ SolarMutexGuard aGuard;
+ return ScStyleNameConversion::DisplayToProgrammaticName( aData.maStyle, SfxStyleFamily::Para );
+}
+
+void SAL_CALL ScTableConditionalEntry::setStyleName( const OUString& aStyleName )
+{
+ SolarMutexGuard aGuard;
+ aData.maStyle = ScStyleNameConversion::ProgrammaticToDisplayName( aStyleName, SfxStyleFamily::Para );
+}
+
+ScTableValidationObj::ScTableValidationObj(const ScDocument& rDoc, sal_uLong nKey,
+ const formula::FormulaGrammar::Grammar eGrammar) :
+ aPropSet( lcl_GetValidatePropertyMap() )
+{
+ // read the entry from the document...
+
+ bool bFound = false;
+ if (nKey)
+ {
+ const ScValidationData* pData = rDoc.GetValidationEntry( nKey );
+ if (pData)
+ {
+ nMode = pData->GetOperation();
+ aSrcPos = pData->GetValidSrcPos(); // valid pos for expressions
+ aExpr1 = pData->GetExpression( aSrcPos, 0, 0, eGrammar );
+ aExpr2 = pData->GetExpression( aSrcPos, 1, 0, eGrammar );
+ meGrammar1 = meGrammar2 = eGrammar;
+ nValMode = sal::static_int_cast<sal_uInt16>( pData->GetDataMode() );
+ bIgnoreBlank = pData->IsIgnoreBlank();
+ nShowList = pData->GetListType();
+ bShowInput = pData->GetInput( aInputTitle, aInputMessage );
+ ScValidErrorStyle eStyle;
+ bShowError = pData->GetErrMsg( aErrorTitle, aErrorMessage, eStyle );
+ nErrorStyle = sal::static_int_cast<sal_uInt16>( eStyle );
+
+ // During save to XML, sheet::ValidationType_ANY formulas are not
+ // saved, even if in the list, see
+ // ScMyValidationsContainer::GetCondition(), so shall not mark
+ // anything in use.
+ if (nValMode != SC_VALID_ANY && rDoc.IsInExternalReferenceMarking())
+ pData->MarkUsedExternalReferences();
+
+ bFound = true;
+ }
+ }
+ if (!bFound)
+ ClearData_Impl(); // Defaults
+}
+
+ScValidationData* ScTableValidationObj::CreateValidationData( ScDocument& rDoc,
+ formula::FormulaGrammar::Grammar eGrammar ) const
+{
+ // ScValidationData = Core-Struktur
+
+ FormulaGrammar::Grammar eGrammar1 = lclResolveGrammar( eGrammar, meGrammar1 );
+ FormulaGrammar::Grammar eGrammar2 = lclResolveGrammar( eGrammar, meGrammar2 );
+
+ ScValidationData* pRet = new ScValidationData( static_cast<ScValidationMode>(nValMode),
+ nMode,
+ aExpr1, aExpr2, rDoc, aSrcPos,
+ maExprNmsp1, maExprNmsp2,
+ eGrammar1, eGrammar2 );
+ pRet->SetIgnoreBlank(bIgnoreBlank);
+ pRet->SetListType(nShowList);
+
+ if ( aTokens1.hasElements() )
+ {
+ ScTokenArray aTokenArray(rDoc);
+ if ( ScTokenConversion::ConvertToTokenArray(rDoc, aTokenArray, aTokens1) )
+ pRet->SetFormula1(aTokenArray);
+ }
+
+ if ( aTokens2.hasElements() )
+ {
+ ScTokenArray aTokenArray(rDoc);
+ if ( ScTokenConversion::ConvertToTokenArray(rDoc, aTokenArray, aTokens2) )
+ pRet->SetFormula2(aTokenArray);
+ }
+
+ // set strings for error / input even if disabled (and disable afterwards)
+ pRet->SetInput( aInputTitle, aInputMessage );
+ if (!bShowInput)
+ pRet->ResetInput();
+ pRet->SetError( aErrorTitle, aErrorMessage, static_cast<ScValidErrorStyle>(nErrorStyle) );
+ if (!bShowError)
+ pRet->ResetError();
+
+ if ( !aPosString.isEmpty() )
+ pRet->SetSrcString( aPosString );
+
+ return pRet;
+}
+
+void ScTableValidationObj::ClearData_Impl()
+{
+ nMode = ScConditionMode::NONE;
+ nValMode = SC_VALID_ANY;
+ bIgnoreBlank = true;
+ nShowList = sheet::TableValidationVisibility::UNSORTED;
+ bShowInput = false;
+ bShowError = false;
+ nErrorStyle = SC_VALERR_STOP;
+ aSrcPos.Set(0,0,0);
+ aExpr1.clear();
+ aExpr2.clear();
+ maExprNmsp1.clear();
+ maExprNmsp2.clear();
+ meGrammar1 = meGrammar2 = FormulaGrammar::GRAM_UNSPECIFIED; // will be overridden when needed
+ aInputTitle.clear();
+ aInputMessage.clear();
+ aErrorTitle.clear();
+ aErrorMessage.clear();
+}
+
+ScTableValidationObj::~ScTableValidationObj()
+{
+}
+
+// XSheetCondition
+
+sheet::ConditionOperator SAL_CALL ScTableValidationObj::getOperator()
+{
+ SolarMutexGuard aGuard;
+ return lcl_ConditionModeToOperator( nMode );
+}
+
+void SAL_CALL ScTableValidationObj::setOperator( sheet::ConditionOperator nOperator )
+{
+ SolarMutexGuard aGuard;
+ nMode = lcl_ConditionOperatorToMode( nOperator );
+}
+
+sal_Int32 SAL_CALL ScTableValidationObj::getConditionOperator()
+{
+ SolarMutexGuard aGuard;
+ return lcl_ConditionModeToOperatorNew( nMode );
+}
+
+void SAL_CALL ScTableValidationObj::setConditionOperator( sal_Int32 nOperator )
+{
+ SolarMutexGuard aGuard;
+ nMode = ScConditionEntry::GetModeFromApi( static_cast<css::sheet::ConditionOperator>(nOperator) );
+}
+
+OUString SAL_CALL ScTableValidationObj::getFormula1()
+{
+ SolarMutexGuard aGuard;
+ return aExpr1;
+}
+
+void SAL_CALL ScTableValidationObj::setFormula1( const OUString& aFormula1 )
+{
+ SolarMutexGuard aGuard;
+ aExpr1 = aFormula1;
+}
+
+OUString SAL_CALL ScTableValidationObj::getFormula2()
+{
+ SolarMutexGuard aGuard;
+ return aExpr2;
+}
+
+void SAL_CALL ScTableValidationObj::setFormula2( const OUString& aFormula2 )
+{
+ SolarMutexGuard aGuard;
+ aExpr2 = aFormula2;
+}
+
+table::CellAddress SAL_CALL ScTableValidationObj::getSourcePosition()
+{
+ SolarMutexGuard aGuard;
+ table::CellAddress aRet;
+ aRet.Column = aSrcPos.Col();
+ aRet.Row = aSrcPos.Row();
+ aRet.Sheet = aSrcPos.Tab();
+ return aRet;
+}
+
+void SAL_CALL ScTableValidationObj::setSourcePosition( const table::CellAddress& aSourcePosition )
+{
+ SolarMutexGuard aGuard;
+ aSrcPos.Set( static_cast<SCCOL>(aSourcePosition.Column), static_cast<SCROW>(aSourcePosition.Row), aSourcePosition.Sheet );
+}
+
+uno::Sequence<sheet::FormulaToken> SAL_CALL ScTableValidationObj::getTokens( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ if (nIndex >= 2 || nIndex < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ return nIndex == 0 ? aTokens1 : aTokens2;
+}
+
+void SAL_CALL ScTableValidationObj::setTokens( sal_Int32 nIndex, const uno::Sequence<sheet::FormulaToken>& aTokens )
+{
+ SolarMutexGuard aGuard;
+ if (nIndex >= 2 || nIndex < 0)
+ throw lang::IndexOutOfBoundsException();
+
+ if (nIndex == 0)
+ {
+ aTokens1 = aTokens;
+ aExpr1.clear();
+ }
+ else if (nIndex == 1)
+ {
+ aTokens2 = aTokens;
+ aExpr2.clear();
+ }
+}
+
+sal_Int32 SAL_CALL ScTableValidationObj::getCount()
+{
+ return 2;
+}
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTableValidationObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScTableValidationObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == SC_UNONAME_SHOWINP ) bShowInput = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if ( aPropertyName == SC_UNONAME_SHOWERR ) bShowError = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if ( aPropertyName == SC_UNONAME_IGNOREBL ) bIgnoreBlank = ScUnoHelpFunctions::GetBoolFromAny( aValue );
+ else if ( aPropertyName == SC_UNONAME_SHOWLIST ) aValue >>= nShowList;
+ else if ( aPropertyName == SC_UNONAME_INPTITLE )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aInputTitle = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_INPMESS )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aInputMessage = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_ERRTITLE )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aErrorTitle = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_ERRMESS )
+ {
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aErrorMessage = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_TYPE )
+ {
+ sheet::ValidationType eType = static_cast<sheet::ValidationType>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
+ switch (eType)
+ {
+ case sheet::ValidationType_ANY: nValMode = SC_VALID_ANY; break;
+ case sheet::ValidationType_WHOLE: nValMode = SC_VALID_WHOLE; break;
+ case sheet::ValidationType_DECIMAL: nValMode = SC_VALID_DECIMAL; break;
+ case sheet::ValidationType_DATE: nValMode = SC_VALID_DATE; break;
+ case sheet::ValidationType_TIME: nValMode = SC_VALID_TIME; break;
+ case sheet::ValidationType_TEXT_LEN: nValMode = SC_VALID_TEXTLEN; break;
+ case sheet::ValidationType_LIST: nValMode = SC_VALID_LIST; break;
+ case sheet::ValidationType_CUSTOM: nValMode = SC_VALID_CUSTOM; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_ERRALSTY )
+ {
+ sheet::ValidationAlertStyle eStyle = static_cast<sheet::ValidationAlertStyle>(ScUnoHelpFunctions::GetEnumFromAny( aValue ));
+ switch (eStyle)
+ {
+ case sheet::ValidationAlertStyle_STOP: nErrorStyle = SC_VALERR_STOP; break;
+ case sheet::ValidationAlertStyle_WARNING: nErrorStyle = SC_VALERR_WARNING; break;
+ case sheet::ValidationAlertStyle_INFO: nErrorStyle = SC_VALERR_INFO; break;
+ case sheet::ValidationAlertStyle_MACRO: nErrorStyle = SC_VALERR_MACRO; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_SOURCESTR )
+ {
+ // internal - only for XML filter, not in PropertySetInfo, only set
+
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ aPosString = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_FORMULANMSP1 )
+ {
+ // internal - only for XML filter, not in PropertySetInfo, only set
+
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ maExprNmsp1 = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_FORMULANMSP2 )
+ {
+ // internal - only for XML filter, not in PropertySetInfo, only set
+
+ OUString aStrVal;
+ if ( aValue >>= aStrVal )
+ maExprNmsp2 = aStrVal;
+ }
+ else if ( aPropertyName == SC_UNONAME_GRAMMAR1 )
+ {
+ // internal - only for XML filter, not in PropertySetInfo, only set
+
+ sal_Int32 nVal = 0;
+ if ( aValue >>= nVal )
+ meGrammar1 = static_cast< FormulaGrammar::Grammar >(nVal);
+ }
+ else if ( aPropertyName == SC_UNONAME_GRAMMAR2 )
+ {
+ // internal - only for XML filter, not in PropertySetInfo, only set
+
+ sal_Int32 nVal = 0;
+ if ( aValue >>= nVal )
+ meGrammar2 = static_cast< FormulaGrammar::Grammar >(nVal);
+ }
+}
+
+uno::Any SAL_CALL ScTableValidationObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if ( aPropertyName == SC_UNONAME_SHOWINP ) aRet <<= bShowInput;
+ else if ( aPropertyName == SC_UNONAME_SHOWERR ) aRet <<= bShowError;
+ else if ( aPropertyName == SC_UNONAME_IGNOREBL ) aRet <<= bIgnoreBlank;
+ else if ( aPropertyName == SC_UNONAME_SHOWLIST ) aRet <<= nShowList;
+ else if ( aPropertyName == SC_UNONAME_INPTITLE ) aRet <<= aInputTitle;
+ else if ( aPropertyName == SC_UNONAME_INPMESS ) aRet <<= aInputMessage;
+ else if ( aPropertyName == SC_UNONAME_ERRTITLE ) aRet <<= aErrorTitle;
+ else if ( aPropertyName == SC_UNONAME_ERRMESS ) aRet <<= aErrorMessage;
+ else if ( aPropertyName == SC_UNONAME_TYPE )
+ {
+ sheet::ValidationType eType = sheet::ValidationType_ANY;
+ switch (nValMode)
+ {
+ case SC_VALID_ANY: eType = sheet::ValidationType_ANY; break;
+ case SC_VALID_WHOLE: eType = sheet::ValidationType_WHOLE; break;
+ case SC_VALID_DECIMAL: eType = sheet::ValidationType_DECIMAL; break;
+ case SC_VALID_DATE: eType = sheet::ValidationType_DATE; break;
+ case SC_VALID_TIME: eType = sheet::ValidationType_TIME; break;
+ case SC_VALID_TEXTLEN: eType = sheet::ValidationType_TEXT_LEN; break;
+ case SC_VALID_LIST: eType = sheet::ValidationType_LIST; break;
+ case SC_VALID_CUSTOM: eType = sheet::ValidationType_CUSTOM; break;
+ }
+ aRet <<= eType;
+ }
+ else if ( aPropertyName == SC_UNONAME_ERRALSTY )
+ {
+ sheet::ValidationAlertStyle eStyle = sheet::ValidationAlertStyle_STOP;
+ switch (nErrorStyle)
+ {
+ case SC_VALERR_STOP: eStyle = sheet::ValidationAlertStyle_STOP; break;
+ case SC_VALERR_WARNING: eStyle = sheet::ValidationAlertStyle_WARNING; break;
+ case SC_VALERR_INFO: eStyle = sheet::ValidationAlertStyle_INFO; break;
+ case SC_VALERR_MACRO: eStyle = sheet::ValidationAlertStyle_MACRO; break;
+ }
+ aRet <<= eStyle;
+ }
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScTableValidationObj )
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION_IMPL(ScTableValidationObj);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/forbiuno.cxx b/sc/source/ui/unoobj/forbiuno.cxx
new file mode 100644
index 000000000..0928170c5
--- /dev/null
+++ b/sc/source/ui/unoobj/forbiuno.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 <editeng/forbiddencharacterstable.hxx>
+#include <comphelper/processfactory.hxx>
+#include <vcl/svapp.hxx>
+
+#include <forbiuno.hxx>
+#include <docsh.hxx>
+
+using namespace ::com::sun::star;
+
+static std::shared_ptr<SvxForbiddenCharactersTable> lcl_GetForbidden( ScDocShell* pDocSh )
+{
+ std::shared_ptr<SvxForbiddenCharactersTable> xRet;
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ xRet = rDoc.GetForbiddenCharacters();
+ if (!xRet)
+ {
+ // create an empty SvxForbiddenCharactersTable for SvxUnoForbiddenCharsTable,
+ // so changes can be stored.
+ xRet = SvxForbiddenCharactersTable::makeForbiddenCharactersTable(comphelper::getProcessComponentContext());
+ rDoc.SetForbiddenCharacters( xRet );
+ }
+ }
+ return xRet;
+}
+
+ScForbiddenCharsObj::ScForbiddenCharsObj( ScDocShell* pDocSh ) :
+ SvxUnoForbiddenCharsTable( lcl_GetForbidden( pDocSh ) ),
+ pDocShell( pDocSh )
+{
+ if (pDocShell)
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScForbiddenCharsObj::~ScForbiddenCharsObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScForbiddenCharsObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // document gone
+ }
+}
+
+void ScForbiddenCharsObj::onChange()
+{
+ if (pDocShell)
+ {
+ pDocShell->GetDocument().SetForbiddenCharacters( mxForbiddenChars );
+ pDocShell->PostPaintGridAll();
+ pDocShell->SetDocumentModified();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/funcuno.cxx b/sc/source/ui/unoobj/funcuno.cxx
new file mode 100644
index 000000000..e0d18a7a2
--- /dev/null
+++ b/sc/source/ui/unoobj/funcuno.cxx
@@ -0,0 +1,653 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cppuhelper/supportsservice.hxx>
+#include <sfx2/app.hxx>
+#include <svl/itemprop.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/diagnose.h>
+#include <vcl/svapp.hxx>
+
+#include <funcuno.hxx>
+#include <miscuno.hxx>
+#include <cellsuno.hxx>
+#include <scdll.hxx>
+#include <document.hxx>
+#include <compiler.hxx>
+#include <formula/errorcodes.hxx>
+#include <callform.hxx>
+#include <addincol.hxx>
+#include <rangeseq.hxx>
+#include <formulacell.hxx>
+#include <docoptio.hxx>
+#include <optuno.hxx>
+#include <markdata.hxx>
+#include <patattr.hxx>
+#include <docpool.hxx>
+#include <attrib.hxx>
+#include <clipparam.hxx>
+#include <stringutil.hxx>
+#include <tokenarray.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+
+// registered as implementation for service FunctionAccess,
+// also supports service SpreadsheetDocumentSettings (to set null date etc.)
+
+constexpr OUStringLiteral SCFUNCTIONACCESS_SERVICE = u"com.sun.star.sheet.FunctionAccess";
+constexpr OUStringLiteral SCDOCSETTINGS_SERVICE = u"com.sun.star.sheet.SpreadsheetDocumentSettings";
+
+// helper to use cached document if not in use, temporary document otherwise
+
+namespace {
+
+class ScTempDocSource
+{
+private:
+ ScTempDocCache& rCache;
+ ScDocumentUniquePtr pTempDoc;
+
+ static ScDocument* CreateDocument(); // create and initialize doc
+
+public:
+ explicit ScTempDocSource( ScTempDocCache& rDocCache );
+ ~ScTempDocSource() COVERITY_NOEXCEPT_FALSE;
+
+ ScDocument* GetDocument();
+};
+
+}
+
+ScDocument* ScTempDocSource::CreateDocument()
+{
+ ScDocument* pDoc = new ScDocument( SCDOCMODE_FUNCTIONACCESS );
+ pDoc->MakeTable( 0 );
+ return pDoc;
+}
+
+ScTempDocSource::ScTempDocSource( ScTempDocCache& rDocCache ) :
+ rCache( rDocCache )
+{
+ if ( rCache.IsInUse() )
+ pTempDoc.reset(CreateDocument());
+ else
+ {
+ rCache.SetInUse( true );
+ if ( !rCache.GetDocument() )
+ rCache.SetDocument( CreateDocument() );
+ }
+}
+
+ScTempDocSource::~ScTempDocSource() COVERITY_NOEXCEPT_FALSE
+{
+ if ( !pTempDoc )
+ rCache.SetInUse( false );
+}
+
+ScDocument* ScTempDocSource::GetDocument()
+{
+ if ( pTempDoc )
+ return pTempDoc.get();
+ else
+ return rCache.GetDocument();
+}
+
+ScTempDocCache::ScTempDocCache()
+ : bInUse(false)
+{
+}
+
+void ScTempDocCache::SetDocument( ScDocument* pNew )
+{
+ OSL_ENSURE(!xDoc, "ScTempDocCache::SetDocument: already set");
+ xDoc.reset(pNew);
+}
+
+void ScTempDocCache::Clear()
+{
+ OSL_ENSURE( !bInUse, "ScTempDocCache::Clear: bInUse" );
+ xDoc.reset();
+}
+
+// copy results from one document into another
+//! merge this with ScAreaLink::Refresh
+//! copy directly without a clipboard document?
+
+static bool lcl_CopyData( ScDocument* pSrcDoc, const ScRange& rSrcRange,
+ ScDocument* pDestDoc, const ScAddress& rDestPos )
+{
+ SCTAB nSrcTab = rSrcRange.aStart.Tab();
+ SCTAB nDestTab = rDestPos.Tab();
+
+ ScRange aNewRange( rDestPos, ScAddress(
+ rSrcRange.aEnd.Col() - rSrcRange.aStart.Col() + rDestPos.Col(),
+ rSrcRange.aEnd.Row() - rSrcRange.aStart.Row() + rDestPos.Row(),
+ nDestTab ) );
+
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+ ScMarkData aSourceMark(pSrcDoc->GetSheetLimits());
+ aSourceMark.SelectOneTable( nSrcTab ); // for CopyToClip
+ aSourceMark.SetMarkArea( rSrcRange );
+ ScClipParam aClipParam(rSrcRange, false);
+ pSrcDoc->CopyToClip(aClipParam, pClipDoc.get(), &aSourceMark, false, false);
+
+ if ( pClipDoc->HasAttrib( 0,0,nSrcTab, pClipDoc->MaxCol(), pClipDoc->MaxRow(),nSrcTab,
+ HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
+ {
+ ScPatternAttr aPattern( pSrcDoc->GetPool() );
+ aPattern.GetItemSet().Put( ScMergeAttr() ); // Defaults
+ aPattern.GetItemSet().Put( ScMergeFlagAttr() );
+ pClipDoc->ApplyPatternAreaTab( 0,0, pClipDoc->MaxCol(), pClipDoc->MaxRow(), nSrcTab, aPattern );
+ }
+
+ ScMarkData aDestMark(pDestDoc->GetSheetLimits());
+ aDestMark.SelectOneTable( nDestTab );
+ aDestMark.SetMarkArea( aNewRange );
+ pDestDoc->CopyFromClip( aNewRange, aDestMark, InsertDeleteFlags::ALL & ~InsertDeleteFlags::FORMULA, nullptr, pClipDoc.get(), false );
+
+ return true;
+}
+
+ScFunctionAccess::ScFunctionAccess() :
+ aPropertyMap( ScDocOptionsHelper::GetPropertyMap() ),
+ mbArray( true ), // default according to behaviour of older Office versions
+ mbValid( true )
+{
+ StartListening( *SfxGetpApp() ); // for SfxHintId::Deinitializing
+}
+
+ScFunctionAccess::~ScFunctionAccess()
+{
+ pOptions.reset();
+ {
+ // SfxBroadcaster::RemoveListener checks DBG_TESTSOLARMUTEX():
+ SolarMutexGuard g;
+ EndListeningAll();
+ }
+}
+
+void ScFunctionAccess::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Deinitializing )
+ {
+ // document must not be used anymore
+ aDocCache.Clear();
+ mbValid = false;
+ }
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+ScFunctionAccess_get_implementation(css::uno::XComponentContext*, css::uno::Sequence<css::uno::Any> const &)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ return cppu::acquire(new ScFunctionAccess);
+}
+
+// XServiceInfo
+OUString SAL_CALL ScFunctionAccess::getImplementationName()
+{
+ return "stardiv.StarCalc.ScFunctionAccess";
+}
+
+sal_Bool SAL_CALL ScFunctionAccess::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScFunctionAccess::getSupportedServiceNames()
+{
+ return {SCFUNCTIONACCESS_SERVICE, SCDOCSETTINGS_SERVICE};
+}
+
+// XPropertySet (document settings)
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFunctionAccess::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropertyMap ));
+ return aRef;
+}
+
+void SAL_CALL ScFunctionAccess::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == "IsArrayFunction" )
+ {
+ if( !(aValue >>= mbArray) )
+ throw lang::IllegalArgumentException();
+ }
+ else
+ {
+ if ( !pOptions )
+ pOptions.reset( new ScDocOptions() );
+
+ // options aren't initialized from configuration - always get the same default behaviour
+
+ bool bDone = ScDocOptionsHelper::setPropertyValue( *pOptions, aPropertyMap, aPropertyName, aValue );
+ if (!bDone)
+ throw beans::UnknownPropertyException(aPropertyName);
+ }
+}
+
+uno::Any SAL_CALL ScFunctionAccess::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == "IsArrayFunction" )
+ return uno::Any( mbArray );
+
+ if ( !pOptions )
+ pOptions.reset( new ScDocOptions() );
+
+ // options aren't initialized from configuration - always get the same default behaviour
+
+ return ScDocOptionsHelper::getPropertyValue( *pOptions, aPropertyMap, aPropertyName );
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFunctionAccess )
+
+// XFunctionAccess
+
+static bool lcl_AddFunctionToken( ScTokenArray& rArray, const OUString& rName,const ScCompiler& rCompiler )
+{
+ // function names are always case-insensitive
+ OUString aUpper = ScGlobal::getCharClass().uppercase(rName);
+
+ // same options as in ScCompiler::IsOpCode:
+ // 1. built-in function name
+
+ OpCode eOp = rCompiler.GetEnglishOpCode( aUpper );
+ if ( eOp != ocNone )
+ {
+ rArray.AddOpCode( eOp );
+ return true;
+ }
+
+ // 2. old add in functions
+
+ if (ScGlobal::GetLegacyFuncCollection()->findByName(aUpper))
+ {
+ rArray.AddExternal(aUpper.getStr());
+ return true;
+ }
+
+ // 3. new (uno) add in functions
+
+ OUString aIntName =
+ ScGlobal::GetAddInCollection()->FindFunction(aUpper, false);
+ if (!aIntName.isEmpty())
+ {
+ rArray.AddExternal(aIntName.getStr()); // international name
+ return true;
+ }
+
+ return false; // no valid function name
+}
+
+static void lcl_AddRef( ScTokenArray& rArray, sal_Int32 nStartRow, sal_Int32 nColCount, sal_Int32 nRowCount )
+{
+ ScComplexRefData aRef;
+ aRef.InitRange(ScRange(0,nStartRow,0,nColCount-1,nStartRow+nRowCount-1,0));
+ rArray.AddDoubleReference(aRef);
+}
+
+namespace {
+
+class SimpleVisitor
+{
+protected:
+ bool mbArgError;
+ ScDocument* mpDoc;
+public:
+ explicit SimpleVisitor( ScDocument* pDoc ) : mbArgError( false ), mpDoc( pDoc ) {}
+ // could possibly just get away with JUST the following overload
+ // 1) virtual void visitElem( long& nCol, long& nRow, const double& elem )
+ // 2) virtual void visitElem( long& nCol, long& nRow, const OUString& elem )
+ // 3) virtual void visitElem( long& nCol, long& nRow, const uno::Any& elem )
+ // the other types methods are here just to reflect the orig code and for
+ // completeness.
+
+ void visitElem( sal_Int32 nCol, sal_Int32 nRow, sal_Int16 elem )
+ {
+ mpDoc->SetValue( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), 0, elem );
+ }
+ void visitElem( sal_Int32 nCol, sal_Int32 nRow, sal_Int32 elem )
+ {
+ mpDoc->SetValue( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), 0, elem );
+ }
+ void visitElem( sal_Int32 nCol, sal_Int32 nRow, const double& elem )
+ {
+ mpDoc->SetValue( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), 0, elem );
+ }
+ void visitElem( sal_Int32 nCol, sal_Int32 nRow, const OUString& elem )
+ {
+ if (!elem.isEmpty())
+ {
+ ScSetStringParam aParam;
+ aParam.setTextInput();
+ mpDoc->SetString(ScAddress(nCol,nRow,0), elem, &aParam);
+ }
+ }
+ void visitElem( sal_Int32 nCol, sal_Int32 nRow, const uno::Any& rElement )
+ {
+ uno::TypeClass eElemClass = rElement.getValueTypeClass();
+ if ( eElemClass == uno::TypeClass_VOID )
+ {
+ // leave empty
+ }
+ else if ( eElemClass == uno::TypeClass_BYTE ||
+ eElemClass == uno::TypeClass_SHORT ||
+ eElemClass == uno::TypeClass_UNSIGNED_SHORT ||
+ eElemClass == uno::TypeClass_LONG ||
+ eElemClass == uno::TypeClass_UNSIGNED_LONG ||
+ eElemClass == uno::TypeClass_FLOAT ||
+ eElemClass == uno::TypeClass_DOUBLE )
+ {
+ // accept integer types because Basic passes a floating point
+ // variable as byte, short or long if it's an integer number.
+ double fVal(0.0);
+ rElement >>= fVal;
+ visitElem( nCol, nRow, fVal );
+ }
+ else if ( eElemClass == uno::TypeClass_STRING )
+ {
+ OUString aUStr;
+ rElement >>= aUStr;
+ visitElem( nCol, nRow, aUStr );
+ }
+ else
+ mbArgError = true;
+ }
+ bool hasArgError() const { return mbArgError; }
+};
+
+template< class seq >
+class SequencesContainer
+{
+ uno::Sequence< uno::Sequence< seq > > maSeq;
+
+ sal_Int32& mrDocRow;
+ bool mbOverflow;
+ bool mbArgError;
+ ScDocument* mpDoc;
+ ScTokenArray& mrTokenArr;
+
+public:
+ SequencesContainer( const uno::Any& rArg, ScTokenArray& rTokenArr, sal_Int32& rDocRow, ScDocument* pDoc ) :
+ mrDocRow( rDocRow ), mbOverflow(false), mbArgError(false), mpDoc( pDoc ), mrTokenArr( rTokenArr )
+ {
+ rArg >>= maSeq;
+ }
+
+ void process()
+ {
+ SimpleVisitor aVisitor(mpDoc);
+ sal_Int32 nStartRow = mrDocRow;
+ sal_Int32 nRowCount = maSeq.getLength();
+ sal_Int32 nMaxColCount = 0;
+ for ( const uno::Sequence< seq >& rRow : std::as_const(maSeq) )
+ {
+ sal_Int32 nColCount = rRow.getLength();
+ if ( nColCount > nMaxColCount )
+ nMaxColCount = nColCount;
+ for (sal_Int32 nCol=0; nCol<nColCount; nCol++)
+ if ( nCol <= mpDoc->MaxCol() && mrDocRow <= mpDoc->MaxRow() )
+ aVisitor.visitElem( nCol, mrDocRow, rRow[ nCol ] );
+ else
+ mbOverflow=true;
+ mrDocRow++;
+ }
+ mbArgError = aVisitor.hasArgError();
+ if (!mbOverflow)
+ {
+ if (nRowCount && nMaxColCount)
+ lcl_AddRef( mrTokenArr, nStartRow, nMaxColCount, nRowCount );
+ else if (nRowCount == 1 && !nMaxColCount)
+ // Empty Sequence<Sequence<Any>> is omitted argument.
+ mrTokenArr.AddOpCode( ocMissing);
+ }
+ }
+ bool getOverflow() const { return mbOverflow; }
+ bool getArgError() const { return mbArgError; }
+};
+
+template <class T>
+class ArrayOfArrayProc
+{
+public:
+static void processSequences( ScDocument* pDoc, const uno::Any& rArg, ScTokenArray& rTokenArr,
+ sal_Int32& rDocRow, bool& rArgErr, bool& rOverflow )
+{
+ SequencesContainer< T > aContainer( rArg, rTokenArr, rDocRow, pDoc );
+ aContainer.process();
+ rArgErr = aContainer.getArgError();
+ rOverflow = aContainer.getOverflow();
+}
+};
+
+}
+
+uno::Any SAL_CALL ScFunctionAccess::callFunction( const OUString& aName,
+ const uno::Sequence<uno::Any>& aArguments )
+{
+ SolarMutexGuard aGuard;
+
+ if (!mbValid)
+ throw uno::RuntimeException();
+
+ // use cached document if not in use, temporary document otherwise
+ // (deleted in ScTempDocSource dtor)
+ ScTempDocSource aSource( aDocCache );
+ ScDocument* pDoc = aSource.GetDocument();
+ const static SCTAB nTempSheet = 1;
+ // Create an extra tab to contain the Function Cell
+ // this will allow full rows to be used.
+ if ( !pDoc->HasTable( nTempSheet ) )
+ pDoc->MakeTable( nTempSheet );
+
+ /// TODO: check
+ ScAddress aAdr;
+ ScCompiler aCompiler(*pDoc, aAdr, pDoc->GetGrammar());
+
+ // find function
+
+ ScTokenArray aTokenArr(*pDoc);
+ if ( !lcl_AddFunctionToken( aTokenArr, aName,aCompiler ) )
+ {
+ // function not found
+ throw container::NoSuchElementException();
+ }
+
+ // set options (null date, etc.)
+
+ if ( pOptions )
+ pDoc->SetDocOptions( *pOptions );
+
+ // add arguments to token array
+
+ bool bArgErr = false;
+ bool bOverflow = false;
+ sal_Int32 nDocRow = 0;
+ tools::Long nArgCount = aArguments.getLength();
+ const uno::Any* pArgArr = aArguments.getConstArray();
+
+ svl::SharedStringPool& rSPool = pDoc->GetSharedStringPool();
+ aTokenArr.AddOpCode(ocOpen);
+ for (tools::Long nPos=0; nPos<nArgCount; nPos++)
+ {
+ if ( nPos > 0 )
+ aTokenArr.AddOpCode(ocSep);
+
+ const uno::Any& rArg = pArgArr[nPos];
+
+ uno::TypeClass eClass = rArg.getValueTypeClass();
+ const uno::Type& aType = rArg.getValueType();
+ if ( eClass == uno::TypeClass_BYTE ||
+ eClass == uno::TypeClass_BOOLEAN ||
+ eClass == uno::TypeClass_SHORT ||
+ eClass == uno::TypeClass_UNSIGNED_SHORT ||
+ eClass == uno::TypeClass_LONG ||
+ eClass == uno::TypeClass_UNSIGNED_LONG ||
+ eClass == uno::TypeClass_FLOAT ||
+ eClass == uno::TypeClass_DOUBLE )
+ {
+ // accept integer types because Basic passes a floating point
+ // variable as byte, short or long if it's an integer number.
+ double fVal = 0;
+ rArg >>= fVal;
+ aTokenArr.AddDouble( fVal );
+ }
+ else if ( eClass == uno::TypeClass_STRING )
+ {
+ OUString aUStr;
+ rArg >>= aUStr;
+ aTokenArr.AddString(rSPool.intern(aUStr));
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int16> >>::get() ) )
+ {
+ ArrayOfArrayProc<sal_Int16>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<sal_Int32> >>::get() ) )
+ {
+ ArrayOfArrayProc<sal_Int32>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<double> >>::get() ) )
+ {
+ ArrayOfArrayProc<double>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<OUString> >>::get() ) )
+ {
+ ArrayOfArrayProc<OUString>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence< uno::Sequence<uno::Any> >>::get() ) )
+ {
+ ArrayOfArrayProc<uno::Any>::processSequences( pDoc, rArg, aTokenArr, nDocRow, bArgErr, bOverflow );
+ }
+ else if ( aType.equals( cppu::UnoType<table::XCellRange>::get()) )
+ {
+ // currently, only our own cell ranges are supported
+
+ uno::Reference<table::XCellRange> xRange(rArg, uno::UNO_QUERY);
+ ScCellRangesBase* pImpl = comphelper::getFromUnoTunnel<ScCellRangesBase>( xRange );
+ if ( pImpl )
+ {
+ ScDocument* pSrcDoc = pImpl->GetDocument();
+ const ScRangeList& rRanges = pImpl->GetRangeList();
+ if ( pSrcDoc && rRanges.size() == 1 )
+ {
+ ScRange const & rSrcRange = rRanges[ 0 ];
+
+ sal_Int32 nStartRow = nDocRow;
+ sal_Int32 nColCount = rSrcRange.aEnd.Col() - rSrcRange.aStart.Col() + 1;
+ sal_Int32 nRowCount = rSrcRange.aEnd.Row() - rSrcRange.aStart.Row() + 1;
+
+ if ( nStartRow + nRowCount > pDoc->GetSheetLimits().GetMaxRowCount() )
+ bOverflow = true;
+ else
+ {
+ // copy data
+ if ( !lcl_CopyData( pSrcDoc, rSrcRange, pDoc, ScAddress( 0, static_cast<SCROW>(nDocRow), 0 ) ) )
+ bOverflow = true;
+ }
+
+ nDocRow += nRowCount;
+ if ( !bOverflow )
+ lcl_AddRef( aTokenArr, nStartRow, nColCount, nRowCount );
+ }
+ else
+ bArgErr = true;
+ }
+ else
+ bArgErr = true;
+ }
+ else
+ bArgErr = true; // invalid type
+ }
+ aTokenArr.AddOpCode(ocClose);
+ aTokenArr.AddOpCode(ocStop);
+
+ // execute formula
+
+ uno::Any aRet;
+ if ( !bArgErr && !bOverflow && nDocRow <= pDoc->GetSheetLimits().GetMaxRowCount() )
+ {
+ ScAddress aFormulaPos( 0, 0, nTempSheet );
+ // GRAM_API doesn't really matter for the token array but fits with
+ // other API compatibility grammars.
+ ScFormulaCell* pFormula = new ScFormulaCell(
+ *pDoc, aFormulaPos, aTokenArr, formula::FormulaGrammar::GRAM_API,
+ mbArray ? ScMatrixMode::Formula : ScMatrixMode::NONE );
+ pFormula = pDoc->SetFormulaCell(aFormulaPos, pFormula);
+ if (mbArray && pFormula)
+ pFormula->SetMatColsRows(1,1); // the cell dimensions (only one cell)
+
+ // call GetMatrix before GetErrCode because GetMatrix always recalculates
+ // if there is no matrix result
+
+ const ScMatrix* pMat = (mbArray && pFormula) ? pFormula->GetMatrix() : nullptr;
+ FormulaError nErrCode = pFormula ? pFormula->GetErrCode() : FormulaError::IllegalArgument;
+ if ( nErrCode == FormulaError::NONE )
+ {
+ if ( pMat )
+ {
+ // array result
+ ScRangeToSequence::FillMixedArray( aRet, pMat );
+ }
+ else if ( pFormula->IsValue() )
+ {
+ // numeric value
+ aRet <<= pFormula->GetValue();
+ }
+ else
+ {
+ // string result
+ OUString aStrVal = pFormula->GetString().getString();
+ aRet <<= aStrVal;
+ }
+ }
+ else if ( nErrCode == FormulaError::NotAvailable )
+ {
+ // #N/A: leave result empty, no exception
+ }
+ else
+ {
+ // any other error: IllegalArgumentException
+ bArgErr = true;
+ }
+
+ pDoc->DeleteAreaTab( 0, 0, pDoc->MaxCol(), pDoc->MaxRow(), 0, InsertDeleteFlags::ALL );
+ pDoc->DeleteAreaTab( 0, 0, 0, 0, nTempSheet, InsertDeleteFlags::ALL );
+ }
+
+ if (bOverflow)
+ throw uno::RuntimeException();
+
+ if (bArgErr)
+ throw lang::IllegalArgumentException();
+
+ return aRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/linkuno.cxx b/sc/source/ui/unoobj/linkuno.cxx
new file mode 100644
index 000000000..c63468cdf
--- /dev/null
+++ b/sc/source/ui/unoobj/linkuno.cxx
@@ -0,0 +1,1691 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <comphelper/sequence.hxx>
+#include <formula/token.hxx>
+#include <svl/hint.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/sharedstringpool.hxx>
+
+#include <linkuno.hxx>
+#include <miscuno.hxx>
+#include <convuno.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <tablink.hxx>
+#include <arealink.hxx>
+#include <hints.hxx>
+#include <unonames.hxx>
+#include <rangeseq.hxx>
+#include <scmatrix.hxx>
+#include <documentlinkmgr.hxx>
+
+#include <string_view>
+#include <vector>
+
+using namespace com::sun::star;
+using namespace formula;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::lang::IllegalArgumentException;
+using ::com::sun::star::uno::RuntimeException;
+using ::std::vector;
+
+// used for sheet- and area link:
+static const SfxItemPropertyMapEntry* lcl_GetSheetLinkMap()
+{
+ static const SfxItemPropertyMapEntry aSheetLinkMap_Impl[] =
+ {
+ { SC_UNONAME_FILTER, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_FILTOPT, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_LINKURL, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_REFDELAY, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_REFPERIOD, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aSheetLinkMap_Impl;
+}
+
+SC_SIMPLE_SERVICE_INFO( ScAreaLinkObj, "ScAreaLinkObj", "com.sun.star.sheet.CellAreaLink" )
+SC_SIMPLE_SERVICE_INFO( ScAreaLinksObj, "ScAreaLinksObj", "com.sun.star.sheet.CellAreaLinks" )
+SC_SIMPLE_SERVICE_INFO( ScDDELinkObj, "ScDDELinkObj", "com.sun.star.sheet.DDELink" )
+SC_SIMPLE_SERVICE_INFO( ScDDELinksObj, "ScDDELinksObj", "com.sun.star.sheet.DDELinks" )
+SC_SIMPLE_SERVICE_INFO( ScSheetLinkObj, "ScSheetLinkObj", "com.sun.star.sheet.SheetLink" )
+SC_SIMPLE_SERVICE_INFO( ScSheetLinksObj, "ScSheetLinksObj", "com.sun.star.sheet.SheetLinks" )
+
+ScSheetLinkObj::ScSheetLinkObj(ScDocShell* pDocSh, const OUString& rName) :
+ aPropSet( lcl_GetSheetLinkMap() ),
+ pDocShell( pDocSh ),
+ aFileName( rName )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScSheetLinkObj::~ScSheetLinkObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScSheetLinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! notify if links in document are changed
+ // UpdateRef is not needed here
+
+ if ( auto pRefreshHint = dynamic_cast<const ScLinkRefreshedHint*>(&rHint) )
+ {
+ if ( pRefreshHint->GetLinkType() == ScLinkRefType::SHEET && pRefreshHint->GetUrl() == aFileName )
+ Refreshed_Impl();
+ }
+ else
+ {
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // pointer is invalid
+ }
+}
+
+ScTableLink* ScSheetLinkObj::GetLink_Impl() const
+{
+ if (pDocShell)
+ {
+ sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
+ size_t nCount = pLinkManager->GetLinks().size();
+ for (size_t i=0; i<nCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
+ if (auto pTabLink = dynamic_cast<ScTableLink*>( pBase))
+ {
+ if ( pTabLink->GetFileName() == aFileName )
+ return pTabLink;
+ }
+ }
+ }
+ return nullptr; // not found
+}
+
+// XNamed
+
+OUString SAL_CALL ScSheetLinkObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return getFileName(); // Name is the same as filename (URL)
+}
+
+void SAL_CALL ScSheetLinkObj::setName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ setFileName(aName); // Name is the same as filename (URL)
+}
+
+// XRefreshable
+
+void SAL_CALL ScSheetLinkObj::refresh()
+{
+ SolarMutexGuard aGuard;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ pLink->Refresh( pLink->GetFileName(), pLink->GetFilterName(), nullptr, pLink->GetRefreshDelaySeconds() );
+}
+
+void SAL_CALL ScSheetLinkObj::addRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRefreshListeners.push_back( xListener );
+
+ // hold one additional ref to keep this object alive as long as there are listeners
+ if ( aRefreshListeners.size() == 1 )
+ acquire();
+}
+
+void SAL_CALL ScSheetLinkObj::removeRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ size_t nCount = aRefreshListeners.size();
+ for ( size_t n=nCount; n--; )
+ {
+ uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n];
+ if ( rObj == xListener )
+ {
+ aRefreshListeners.erase( aRefreshListeners.begin() + n );
+ if ( aRefreshListeners.empty() )
+ release(); // release ref for listeners
+ break;
+ }
+ }
+}
+
+void ScSheetLinkObj::Refreshed_Impl()
+{
+ lang::EventObject aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners)
+ xRefreshListener->refreshed( aEvent );
+}
+
+void ScSheetLinkObj::ModifyRefreshDelay_Impl( sal_Int32 nRefresh )
+{
+ ScTableLink* pLink = GetLink_Impl();
+ if( pLink )
+ pLink->SetRefreshDelay( static_cast<sal_uLong>(nRefresh) );
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScSheetLinkObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScSheetLinkObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ OUString aValStr;
+ if ( aPropertyName == SC_UNONAME_LINKURL )
+ {
+ if ( aValue >>= aValStr )
+ setFileName( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_FILTER )
+ {
+ if ( aValue >>= aValStr )
+ setFilter( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_FILTOPT )
+ {
+ if ( aValue >>= aValStr )
+ setFilterOptions( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_REFPERIOD )
+ {
+ sal_Int32 nRefresh = 0;
+ if ( aValue >>= nRefresh )
+ setRefreshDelay( nRefresh );
+ }
+ else if ( aPropertyName == SC_UNONAME_REFDELAY )
+ {
+ sal_Int32 nRefresh = 0;
+ if ( aValue >>= nRefresh )
+ setRefreshDelay( nRefresh );
+ }
+}
+
+uno::Any SAL_CALL ScSheetLinkObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ if ( aPropertyName == SC_UNONAME_LINKURL )
+ aRet <<= getFileName();
+ else if ( aPropertyName == SC_UNONAME_FILTER )
+ aRet <<= getFilter();
+ else if ( aPropertyName == SC_UNONAME_FILTOPT )
+ aRet <<= getFilterOptions();
+ else if ( aPropertyName == SC_UNONAME_REFPERIOD )
+ aRet <<= getRefreshDelay();
+ else if ( aPropertyName == SC_UNONAME_REFDELAY )
+ aRet <<= getRefreshDelay();
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScSheetLinkObj )
+
+// internal:
+
+OUString ScSheetLinkObj::getFileName() const
+{
+ SolarMutexGuard aGuard;
+ return aFileName;
+}
+
+void ScSheetLinkObj::setFileName(const OUString& rNewName)
+{
+ SolarMutexGuard aGuard;
+ ScTableLink* pLink = GetLink_Impl();
+ if (!pLink)
+ return;
+
+ // pLink->Refresh with a new file name confuses sfx2::LinkManager
+ // therefore we transplant the sheets manually and create new links with UpdateLinks
+
+ OUString aNewStr(ScGlobal::GetAbsDocName( rNewName, pDocShell ));
+
+ // first transplant the sheets
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ if ( rDoc.IsLinked(nTab) && rDoc.GetLinkDoc(nTab) == aFileName ) // old file
+ rDoc.SetLink( nTab, rDoc.GetLinkMode(nTab), aNewStr,
+ rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab),
+ rDoc.GetLinkTab(nTab),
+ rDoc.GetLinkRefreshDelay(nTab) ); // only change the file
+
+ // update links
+ //! Undo !!!
+
+ pDocShell->UpdateLinks(); // remove old links, possibly set up new ones
+
+ // copy data
+
+ aFileName = aNewStr;
+ pLink = GetLink_Impl(); // new link with new name
+ if (pLink)
+ pLink->Update(); // incl. paint & undo for data
+}
+
+OUString ScSheetLinkObj::getFilter() const
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ aRet = pLink->GetFilterName();
+ return aRet;
+}
+
+void ScSheetLinkObj::setFilter(const OUString& rFilter)
+{
+ SolarMutexGuard aGuard;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ {
+ pLink->Refresh( aFileName, rFilter, nullptr, pLink->GetRefreshDelaySeconds() );
+ }
+}
+
+OUString ScSheetLinkObj::getFilterOptions() const
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ aRet = pLink->GetOptions();
+ return aRet;
+}
+
+void ScSheetLinkObj::setFilterOptions(const OUString& FilterOptions)
+{
+ SolarMutexGuard aGuard;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ {
+ OUString aOptStr(FilterOptions);
+ pLink->Refresh( aFileName, pLink->GetFilterName(), &aOptStr, pLink->GetRefreshDelaySeconds() );
+ }
+}
+
+sal_Int32 ScSheetLinkObj::getRefreshDelay() const
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nRet = 0;
+ ScTableLink* pLink = GetLink_Impl();
+ if (pLink)
+ nRet = pLink->GetRefreshDelaySeconds();
+ return nRet;
+}
+
+void ScSheetLinkObj::setRefreshDelay(sal_Int32 nRefreshDelay)
+{
+ SolarMutexGuard aGuard;
+ ModifyRefreshDelay_Impl( nRefreshDelay );
+}
+
+ScSheetLinksObj::ScSheetLinksObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScSheetLinksObj::~ScSheetLinksObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScSheetLinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // we don't care about update of references here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XSheetLinks
+
+rtl::Reference<ScSheetLinkObj> ScSheetLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
+{
+ if (!pDocShell)
+ return nullptr;
+
+ typedef std::unordered_set<OUString> StrSetType;
+ StrSetType aNames;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ sal_Int32 nCount = 0;
+ for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
+ {
+ if (!rDoc.IsLinked(nTab))
+ continue;
+
+ OUString aLinkDoc = rDoc.GetLinkDoc(nTab);
+ if (aNames.insert(aLinkDoc).second)
+ {
+ // unique document name.
+ if (nCount == nIndex)
+ return new ScSheetLinkObj( pDocShell, aLinkDoc );
+ ++nCount;
+ }
+ }
+
+ return nullptr; // no document or index too large
+}
+
+rtl::Reference<ScSheetLinkObj> ScSheetLinksObj::GetObjectByName_Impl(const OUString& aName)
+{
+ // Name is the same as file name
+
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ if (rDoc.IsLinked(nTab))
+ {
+ //! case-insensitive ???
+ OUString aLinkDoc = rDoc.GetLinkDoc( nTab );
+ if ( aLinkDoc == aName )
+ return new ScSheetLinkObj( pDocShell, aName );
+ }
+ }
+
+ return nullptr;
+}
+
+// XEnumerationAccess
+uno::Reference<container::XEnumeration> SAL_CALL ScSheetLinksObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.SheetLinksEnumeration");
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL ScSheetLinksObj::getCount()
+{
+ typedef std::unordered_set<OUString> StrSetType;
+
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ return 0;
+
+ sal_Int32 nCount = 0;
+
+ StrSetType aNames;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
+ {
+ if (!rDoc.IsLinked(nTab))
+ continue;
+
+ OUString aLinkDoc = rDoc.GetLinkDoc(nTab);
+ if (aNames.insert(aLinkDoc).second)
+ ++nCount;
+ }
+ return nCount;
+}
+
+uno::Any SAL_CALL ScSheetLinksObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<beans::XPropertySet> xLink(GetObjectByIndex_Impl(nIndex));
+ if (!xLink.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xLink);
+}
+
+uno::Type SAL_CALL ScSheetLinksObj::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL ScSheetLinksObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Any SAL_CALL ScSheetLinksObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<beans::XPropertySet> xLink(GetObjectByName_Impl(aName));
+ if (!xLink.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xLink);
+}
+
+sal_Bool SAL_CALL ScSheetLinksObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ // Name is the same as file name
+
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ if (rDoc.IsLinked(nTab))
+ {
+ //! case-insensitive ???
+ OUString aLinkDoc(rDoc.GetLinkDoc( nTab ));
+ if ( aLinkDoc == aName )
+ return true;
+ }
+ }
+ return false;
+}
+
+uno::Sequence<OUString> SAL_CALL ScSheetLinksObj::getElementNames()
+{
+ typedef std::unordered_set<OUString> StrSetType;
+
+ SolarMutexGuard aGuard;
+ // Name is the same as file name
+
+ if (!pDocShell)
+ return uno::Sequence<OUString>();
+
+ StrSetType aNames;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+
+ sal_Int32 nLinkCount = getCount();
+ uno::Sequence<OUString> aSeq(nLinkCount);
+ OUString* pAry = aSeq.getArray();
+ size_t nPos = 0;
+ for (SCTAB nTab = 0; nTab < nTabCount; ++nTab)
+ {
+ if (!rDoc.IsLinked(nTab))
+ continue;
+
+ OUString aLinkDoc = rDoc.GetLinkDoc(nTab);
+ if (aNames.insert(aLinkDoc).second)
+ pAry[nPos++] = aLinkDoc;
+ }
+ OSL_ENSURE( nPos==static_cast<size_t>(nLinkCount), "verzaehlt" );
+ return aSeq;
+}
+
+static ScAreaLink* lcl_GetAreaLink( ScDocShell* pDocShell, size_t nPos )
+{
+ if (pDocShell)
+ {
+ sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
+ size_t nTotalCount = pLinkManager->GetLinks().size();
+ size_t nAreaCount = 0;
+ for (size_t i=0; i<nTotalCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
+ if (auto pAreaLink = dynamic_cast<ScAreaLink*>( pBase))
+ {
+ if ( nAreaCount == nPos )
+ return pAreaLink;
+ ++nAreaCount;
+ }
+ }
+ }
+ return nullptr; // not found
+}
+
+ScAreaLinkObj::ScAreaLinkObj(ScDocShell* pDocSh, size_t nP) :
+ aPropSet( lcl_GetSheetLinkMap() ),
+ pDocShell( pDocSh ),
+ nPos( nP )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScAreaLinkObj::~ScAreaLinkObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScAreaLinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! notify if links in document are changed
+ // UpdateRef is not needed here
+
+ if ( auto pRefreshedHint = dynamic_cast<const ScLinkRefreshedHint*>(&rHint) )
+ {
+ if ( pRefreshedHint->GetLinkType() == ScLinkRefType::AREA )
+ {
+ // get this link to compare dest position
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if ( pLink && pLink->GetDestArea().aStart == pRefreshedHint->GetDestPos() )
+ Refreshed_Impl();
+ }
+ }
+ else
+ {
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // pointer is invalid
+ }
+}
+
+// XFileLink
+
+void ScAreaLinkObj::Modify_Impl( const OUString* pNewFile, const OUString* pNewFilter,
+ const OUString* pNewOptions, const OUString* pNewSource,
+ const table::CellRangeAddress* pNewDest )
+{
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (!pLink)
+ return;
+
+ OUString aFile (pLink->GetFile());
+ OUString aFilter (pLink->GetFilter());
+ OUString aOptions (pLink->GetOptions());
+ OUString aSource (pLink->GetSource());
+ ScRange aDest (pLink->GetDestArea());
+ sal_Int32 nRefreshDelaySeconds = pLink->GetRefreshDelaySeconds();
+
+ //! Undo delete
+ //! Undo merge
+
+ sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
+ pLinkManager->Remove( pLink );
+ pLink = nullptr; // deleted along with remove
+
+ bool bFitBlock = true; // move, if the size changes with update
+ if (pNewFile)
+ {
+ aFile = ScGlobal::GetAbsDocName( *pNewFile, pDocShell ); //! in InsertAreaLink?
+ }
+ if (pNewFilter)
+ aFilter = *pNewFilter;
+ if (pNewOptions)
+ aOptions = *pNewOptions;
+ if (pNewSource)
+ aSource = *pNewSource;
+ if (pNewDest)
+ {
+ ScUnoConversion::FillScRange( aDest, *pNewDest );
+ bFitBlock = false; // new range was specified -> do not move the content
+ }
+ pDocShell->GetDocFunc().InsertAreaLink( aFile, aFilter, aOptions, aSource,
+ aDest, nRefreshDelaySeconds, bFitBlock, true );
+}
+
+void ScAreaLinkObj::ModifyRefreshDelay_Impl( sal_Int32 nRefreshDelaySeconds )
+{
+ ScAreaLink* pLink = lcl_GetAreaLink( pDocShell, nPos );
+ if( pLink )
+ pLink->SetRefreshDelay( nRefreshDelaySeconds );
+}
+
+// XRefreshable
+
+void SAL_CALL ScAreaLinkObj::refresh()
+{
+ SolarMutexGuard aGuard;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ pLink->Refresh( pLink->GetFile(), pLink->GetFilter(), pLink->GetSource(), pLink->GetRefreshDelaySeconds() );
+}
+
+void SAL_CALL ScAreaLinkObj::addRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRefreshListeners.push_back( xListener );
+
+ // hold one additional ref to keep this object alive as long as there are listeners
+ if ( aRefreshListeners.size() == 1 )
+ acquire();
+}
+
+void SAL_CALL ScAreaLinkObj::removeRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ size_t nCount = aRefreshListeners.size();
+ for ( size_t n=nCount; n--; )
+ {
+ uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n];
+ if ( rObj == xListener )
+ {
+ aRefreshListeners.erase( aRefreshListeners.begin() + n );
+ if ( aRefreshListeners.empty() )
+ release(); // release ref for listeners
+ break;
+ }
+
+ if(n == 0)
+ break;
+ }
+}
+
+void ScAreaLinkObj::Refreshed_Impl()
+{
+ lang::EventObject aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners)
+ xRefreshListener->refreshed( aEvent );
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScAreaLinkObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScAreaLinkObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ OUString aValStr;
+ if ( aPropertyName == SC_UNONAME_LINKURL )
+ {
+ if ( aValue >>= aValStr )
+ setFileName( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_FILTER )
+ {
+ if ( aValue >>= aValStr )
+ setFilter( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_FILTOPT )
+ {
+ if ( aValue >>= aValStr )
+ setFilterOptions( aValStr );
+ }
+ else if ( aPropertyName == SC_UNONAME_REFPERIOD )
+ {
+ sal_Int32 nRefresh = 0;
+ if ( aValue >>= nRefresh )
+ setRefreshDelay( nRefresh );
+ }
+ else if ( aPropertyName == SC_UNONAME_REFDELAY )
+ {
+ sal_Int32 nRefresh = 0;
+ if ( aValue >>= nRefresh )
+ setRefreshDelay( nRefresh );
+ }
+}
+
+uno::Any SAL_CALL ScAreaLinkObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ if ( aPropertyName == SC_UNONAME_LINKURL )
+ aRet <<= getFileName();
+ else if ( aPropertyName == SC_UNONAME_FILTER )
+ aRet <<= getFilter();
+ else if ( aPropertyName == SC_UNONAME_FILTOPT )
+ aRet <<= getFilterOptions();
+ else if ( aPropertyName == SC_UNONAME_REFPERIOD )
+ aRet <<= getRefreshDelay();
+ else if ( aPropertyName == SC_UNONAME_REFDELAY )
+ aRet <<= getRefreshDelay();
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScAreaLinkObj )
+
+// internal:
+
+OUString ScAreaLinkObj::getFileName() const
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ aRet = pLink->GetFile();
+ return aRet;
+}
+
+void ScAreaLinkObj::setFileName(const OUString& rNewName)
+{
+ SolarMutexGuard aGuard;
+ Modify_Impl( &rNewName, nullptr, nullptr, nullptr, nullptr );
+}
+
+OUString ScAreaLinkObj::getFilter() const
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ aRet = pLink->GetFilter();
+ return aRet;
+}
+
+void ScAreaLinkObj::setFilter(const OUString& Filter)
+{
+ SolarMutexGuard aGuard;
+ Modify_Impl( nullptr, &Filter, nullptr, nullptr, nullptr );
+}
+
+OUString ScAreaLinkObj::getFilterOptions() const
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ aRet = pLink->GetOptions();
+ return aRet;
+}
+
+void ScAreaLinkObj::setFilterOptions(const OUString& FilterOptions)
+{
+ SolarMutexGuard aGuard;
+ Modify_Impl( nullptr, nullptr, &FilterOptions, nullptr, nullptr );
+}
+
+sal_Int32 ScAreaLinkObj::getRefreshDelay() const
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nRet = 0;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ nRet = pLink->GetRefreshDelaySeconds();
+ return nRet;
+}
+
+void ScAreaLinkObj::setRefreshDelay(sal_Int32 nRefreshDelay)
+{
+ SolarMutexGuard aGuard;
+ ModifyRefreshDelay_Impl( nRefreshDelay );
+}
+
+// XAreaLink
+
+OUString SAL_CALL ScAreaLinkObj::getSourceArea()
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ aRet = pLink->GetSource();
+ return aRet;
+}
+
+void SAL_CALL ScAreaLinkObj::setSourceArea( const OUString& aSourceArea )
+{
+ SolarMutexGuard aGuard;
+ Modify_Impl( nullptr, nullptr, nullptr, &aSourceArea, nullptr );
+}
+
+table::CellRangeAddress SAL_CALL ScAreaLinkObj::getDestArea()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, nPos);
+ if (pLink)
+ ScUnoConversion::FillApiRange( aRet, pLink->GetDestArea() );
+ return aRet;
+}
+
+void SAL_CALL ScAreaLinkObj::setDestArea( const table::CellRangeAddress& aDestArea )
+{
+ SolarMutexGuard aGuard;
+ Modify_Impl( nullptr, nullptr, nullptr, nullptr, &aDestArea );
+}
+
+ScAreaLinksObj::ScAreaLinksObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScAreaLinksObj::~ScAreaLinksObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScAreaLinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // we don't care about update of references here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XAreaLinks
+
+rtl::Reference<ScAreaLinkObj> ScAreaLinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
+{
+ if ( pDocShell && nIndex >= 0 && nIndex < getCount() )
+ return new ScAreaLinkObj( pDocShell, static_cast<size_t>(nIndex) );
+
+ return nullptr; // not found
+}
+
+void SAL_CALL ScAreaLinksObj::insertAtPosition( const table::CellAddress& aDestPos,
+ const OUString& aFileName,
+ const OUString& aSourceArea,
+ const OUString& aFilter,
+ const OUString& aFilterOptions )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ OUString aFileStr (aFileName);
+ ScAddress aDestAddr( static_cast<SCCOL>(aDestPos.Column), static_cast<SCROW>(aDestPos.Row), aDestPos.Sheet );
+
+ aFileStr = ScGlobal::GetAbsDocName( aFileStr, pDocShell ); //! in InsertAreaLink ???
+ pDocShell->GetDocFunc().InsertAreaLink( aFileStr, aFilter, aFilterOptions,
+ aSourceArea, ScRange(aDestAddr),
+ /*nRefreshDelaySeconds*/0, false, true ); // don't move contents
+ }
+}
+
+void SAL_CALL ScAreaLinksObj::removeByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ ScAreaLink* pLink = lcl_GetAreaLink(pDocShell, static_cast<size_t>(nIndex));
+ if (pLink)
+ {
+ //! SetAddUndo or what
+
+ sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
+ pLinkManager->Remove( pLink );
+ }
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScAreaLinksObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.CellAreaLinksEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScAreaLinksObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nAreaCount = 0;
+ if (pDocShell)
+ {
+ sfx2::LinkManager* pLinkManager = pDocShell->GetDocument().GetLinkManager();
+ size_t nTotalCount = pLinkManager->GetLinks().size();
+ for (size_t i=0; i<nTotalCount; i++)
+ {
+ ::sfx2::SvBaseLink* pBase = pLinkManager->GetLinks()[i].get();
+ if (dynamic_cast<const ScAreaLink*>( pBase) != nullptr)
+ ++nAreaCount;
+ }
+ }
+ return nAreaCount;
+}
+
+uno::Any SAL_CALL ScAreaLinksObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XAreaLink> xLink(GetObjectByIndex_Impl(nIndex));
+ if (!xLink.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xLink);
+
+}
+
+uno::Type SAL_CALL ScAreaLinksObj::getElementType()
+{
+ return cppu::UnoType<sheet::XAreaLink>::get();
+}
+
+sal_Bool SAL_CALL ScAreaLinksObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+ScDDELinkObj::ScDDELinkObj(ScDocShell* pDocSh, const OUString& rA,
+ const OUString& rT, const OUString& rI) :
+ pDocShell( pDocSh ),
+ aAppl( rA ),
+ aTopic( rT ),
+ aItem( rI )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDDELinkObj::~ScDDELinkObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDDELinkObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! notify if links in document are changed
+ // UpdateRef is not needed here
+
+ if ( auto pRefreshedHint = dynamic_cast<const ScLinkRefreshedHint*>(&rHint) )
+ {
+ if ( pRefreshedHint->GetLinkType() == ScLinkRefType::DDE &&
+ pRefreshedHint->GetDdeAppl() == aAppl &&
+ pRefreshedHint->GetDdeTopic() == aTopic &&
+ pRefreshedHint->GetDdeItem() == aItem ) //! mode is ignored
+ Refreshed_Impl();
+ }
+ else
+ {
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // pointer is invalid
+ }
+}
+
+// XNamed
+
+static OUString lcl_BuildDDEName( std::u16string_view rAppl, std::u16string_view rTopic, std::u16string_view rItem )
+{
+ // Appl|Topic!Item (like Excel)
+ OUString aRet = OUString::Concat(rAppl) + "|" + rTopic + "!" + rItem;
+ return aRet;
+}
+
+OUString SAL_CALL ScDDELinkObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return lcl_BuildDDEName( aAppl, aTopic, aItem );
+}
+
+void SAL_CALL ScDDELinkObj::setName( const OUString& /* aName */ )
+{
+ // name can't be changed (formulas wouldn't find the link)
+ throw uno::RuntimeException();
+}
+
+// XDDELink
+
+OUString SAL_CALL ScDDELinkObj::getApplication()
+{
+ SolarMutexGuard aGuard;
+ //! Test if the link is still in the document?
+
+ return aAppl;
+}
+
+OUString SAL_CALL ScDDELinkObj::getTopic()
+{
+ SolarMutexGuard aGuard;
+ //! Test if the link is still in the document?
+
+ return aTopic;
+}
+
+OUString SAL_CALL ScDDELinkObj::getItem()
+{
+ SolarMutexGuard aGuard;
+ //! Test if the link is still in the document?
+
+ return aItem;
+}
+
+// XRefreshable
+
+void SAL_CALL ScDDELinkObj::refresh()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ sc::DocumentLinkManager& rMgr = pDocShell->GetDocument().GetDocLinkManager();
+ rMgr.updateDdeLink(aAppl, aTopic, aItem);
+ }
+}
+
+void SAL_CALL ScDDELinkObj::addRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRefreshListeners.push_back( xListener );
+
+ // hold one additional ref to keep this object alive as long as there are listeners
+ if ( aRefreshListeners.size() == 1 )
+ acquire();
+}
+
+void SAL_CALL ScDDELinkObj::removeRefreshListener(
+ const uno::Reference<util::XRefreshListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ size_t nCount = aRefreshListeners.size();
+ for ( size_t n=nCount; n--; )
+ {
+ uno::Reference<util::XRefreshListener>& rObj = aRefreshListeners[n];
+ if ( rObj == xListener )
+ {
+ aRefreshListeners.erase( aRefreshListeners.begin() + n );
+ if ( aRefreshListeners.empty() )
+ release(); // release ref for listeners
+ break;
+ }
+ }
+}
+
+// XDDELinkResults
+
+uno::Sequence< uno::Sequence< uno::Any > > ScDDELinkObj::getResults( )
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence< uno::Sequence< uno::Any > > aReturn;
+ bool bSuccess = false;
+
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ size_t nPos = 0;
+ if ( rDoc.FindDdeLink( aAppl, aTopic, aItem, SC_DDE_IGNOREMODE, nPos ) )
+ {
+ const ScMatrix* pMatrix = rDoc.GetDdeLinkResultMatrix( nPos );
+ if ( pMatrix )
+ {
+ uno::Any aAny;
+ if ( ScRangeToSequence::FillMixedArray( aAny, pMatrix, true ) )
+ {
+ aAny >>= aReturn;
+ }
+ }
+ bSuccess = true;
+ }
+ }
+
+ if ( !bSuccess )
+ {
+ throw uno::RuntimeException(
+ "ScDDELinkObj::getResults: failed to get results!" );
+ }
+
+ return aReturn;
+}
+
+void ScDDELinkObj::setResults( const uno::Sequence< uno::Sequence< uno::Any > >& aResults )
+{
+ SolarMutexGuard aGuard;
+ bool bSuccess = false;
+
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ size_t nPos = 0;
+ if ( rDoc.FindDdeLink( aAppl, aTopic, aItem, SC_DDE_IGNOREMODE, nPos ) )
+ {
+ ScMatrixRef xMatrix = ScSequenceToMatrix::CreateMixedMatrix( Any(aResults) );
+ bSuccess = rDoc.SetDdeLinkResultMatrix( nPos, xMatrix );
+ }
+ }
+
+ if ( !bSuccess )
+ {
+ throw uno::RuntimeException(
+ "ScDDELinkObj::setResults: failed to set results!" );
+ }
+}
+
+void ScDDELinkObj::Refreshed_Impl()
+{
+ lang::EventObject aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ for (uno::Reference<util::XRefreshListener> & xRefreshListener : aRefreshListeners)
+ xRefreshListener->refreshed( aEvent );
+}
+
+ScDDELinksObj::ScDDELinksObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScDDELinksObj::~ScDDELinksObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScDDELinksObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // we don't care about update of references here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XDDELinks
+
+rtl::Reference<ScDDELinkObj> ScDDELinksObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
+{
+ if (pDocShell)
+ {
+ OUString aAppl, aTopic, aItem;
+ if ( pDocShell->GetDocument().GetDdeLinkData( static_cast<size_t>(nIndex), aAppl, aTopic, aItem ) )
+ return new ScDDELinkObj( pDocShell, aAppl, aTopic, aItem );
+ }
+ return nullptr;
+}
+
+rtl::Reference<ScDDELinkObj> ScDDELinksObj::GetObjectByName_Impl(std::u16string_view aName)
+{
+ if (pDocShell)
+ {
+ OUString aAppl, aTopic, aItem;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ size_t nCount = rDoc.GetDocLinkManager().getDdeLinkCount();
+ for (size_t i=0; i<nCount; i++)
+ {
+ rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem );
+ if ( lcl_BuildDDEName(aAppl, aTopic, aItem) == aName )
+ return new ScDDELinkObj( pDocShell, aAppl, aTopic, aItem );
+ }
+ }
+ return nullptr;
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScDDELinksObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.DDELinksEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScDDELinksObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nAreaCount = 0;
+ if (pDocShell)
+ nAreaCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount();
+ return nAreaCount;
+}
+
+uno::Any SAL_CALL ScDDELinksObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XDDELink> xLink(GetObjectByIndex_Impl(nIndex));
+ if (!xLink.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xLink);
+}
+
+uno::Type SAL_CALL ScDDELinksObj::getElementType()
+{
+ return cppu::UnoType<sheet::XDDELink>::get();
+}
+
+sal_Bool SAL_CALL ScDDELinksObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+uno::Any SAL_CALL ScDDELinksObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XDDELink> xLink(GetObjectByName_Impl(aName));
+ if (!xLink.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xLink);
+}
+
+uno::Sequence<OUString> SAL_CALL ScDDELinksObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ OUString aAppl, aTopic, aItem;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ size_t nCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount();
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+
+ for (size_t i=0; i<nCount; i++)
+ {
+ rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem );
+ pAry[i] = lcl_BuildDDEName(aAppl, aTopic, aItem);
+ }
+ return aSeq;
+ }
+ return uno::Sequence<OUString>();
+}
+
+sal_Bool SAL_CALL ScDDELinksObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ OUString aAppl, aTopic, aItem;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ size_t nCount = pDocShell->GetDocument().GetDocLinkManager().getDdeLinkCount();
+ for (size_t i=0; i<nCount; i++)
+ {
+ rDoc.GetDdeLinkData( i, aAppl, aTopic, aItem );
+ if ( lcl_BuildDDEName(aAppl, aTopic, aItem) == aName )
+ return true;
+ }
+ }
+ return false;
+}
+
+// XDDELinks
+
+uno::Reference< sheet::XDDELink > ScDDELinksObj::addDDELink(
+ const OUString& aApplication, const OUString& aTopic,
+ const OUString& aItem, css::sheet::DDELinkMode nMode )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< sheet::XDDELink > xLink;
+
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_uInt8 nMod = SC_DDE_DEFAULT;
+ switch ( nMode )
+ {
+ case sheet::DDELinkMode_DEFAULT:
+ {
+ nMod = SC_DDE_DEFAULT;
+ }
+ break;
+ case sheet::DDELinkMode_ENGLISH:
+ {
+ nMod = SC_DDE_ENGLISH;
+ }
+ break;
+ case sheet::DDELinkMode_TEXT:
+ {
+ nMod = SC_DDE_TEXT;
+ }
+ break;
+ default:
+ {
+ }
+ break;
+ }
+
+ if ( rDoc.CreateDdeLink( aApplication, aTopic, aItem, nMod, ScMatrixRef() ) )
+ {
+ const OUString aName( lcl_BuildDDEName( aApplication, aTopic, aItem ) );
+ xLink.set( GetObjectByName_Impl( aName ) );
+ }
+ }
+
+ if ( !xLink.is() )
+ {
+ throw uno::RuntimeException(
+ "ScDDELinksObj::addDDELink: cannot add DDE link!" );
+ }
+
+ return xLink;
+}
+
+ScExternalSheetCacheObj::ScExternalSheetCacheObj(ScDocShell* pDocShell, ScExternalRefCache::TableTypeRef const & pTable, size_t nIndex) :
+ mpDocShell(pDocShell),
+ mpTable(pTable),
+ mnIndex(nIndex)
+{
+}
+
+ScExternalSheetCacheObj::~ScExternalSheetCacheObj()
+{
+}
+
+void SAL_CALL ScExternalSheetCacheObj::setCellValue(sal_Int32 nCol, sal_Int32 nRow, const Any& rValue)
+{
+ SolarMutexGuard aGuard;
+ if (nRow < 0 || nCol < 0)
+ throw IllegalArgumentException();
+
+ ScExternalRefCache::TokenRef pToken;
+ double fVal = 0.0;
+ OUString aVal;
+ if (rValue >>= fVal)
+ pToken.reset(new FormulaDoubleToken(fVal));
+ else if (rValue >>= aVal)
+ {
+ svl::SharedStringPool& rPool = mpDocShell->GetDocument().GetSharedStringPool();
+ svl::SharedString aSS = rPool.intern(aVal);
+ pToken.reset(new FormulaStringToken(aSS));
+ }
+ else
+ // unidentified value type.
+ return;
+
+ mpTable->setCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), pToken);
+}
+
+Any SAL_CALL ScExternalSheetCacheObj::getCellValue(sal_Int32 nCol, sal_Int32 nRow)
+{
+ SolarMutexGuard aGuard;
+ if (nRow < 0 || nCol < 0)
+ throw IllegalArgumentException();
+
+ FormulaToken* pToken = mpTable->getCell(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow)).get();
+ if (!pToken)
+ throw IllegalArgumentException();
+
+ Any aValue;
+ switch (pToken->GetType())
+ {
+ case svDouble:
+ {
+ double fVal = pToken->GetDouble();
+ aValue <<= fVal;
+ }
+ break;
+ case svString:
+ {
+ OUString aVal = pToken->GetString().getString();
+ aValue <<= aVal;
+ }
+ break;
+ default:
+ throw IllegalArgumentException();
+ }
+ return aValue;
+}
+
+Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllRows()
+{
+ SolarMutexGuard aGuard;
+ vector<SCROW> aRows;
+ mpTable->getAllRows(aRows);
+ size_t nSize = aRows.size();
+ Sequence<sal_Int32> aRowsSeq(nSize);
+ auto aRowsSeqRange = asNonConstRange(aRowsSeq);
+ for (size_t i = 0; i < nSize; ++i)
+ aRowsSeqRange[i] = aRows[i];
+
+ return aRowsSeq;
+}
+
+Sequence< sal_Int32 > SAL_CALL ScExternalSheetCacheObj::getAllColumns(sal_Int32 nRow)
+{
+ SolarMutexGuard aGuard;
+ if (nRow < 0)
+ throw IllegalArgumentException();
+
+ vector<SCCOL> aCols;
+ mpTable->getAllCols(static_cast<SCROW>(nRow), aCols);
+ size_t nSize = aCols.size();
+ Sequence<sal_Int32> aColsSeq(nSize);
+ auto aColsSeqRange = asNonConstRange(aColsSeq);
+ for (size_t i = 0; i < nSize; ++i)
+ aColsSeqRange[i] = aCols[i];
+
+ return aColsSeq;
+}
+
+sal_Int32 SAL_CALL ScExternalSheetCacheObj::getTokenIndex()
+{
+ return static_cast< sal_Int32 >( mnIndex );
+}
+
+ScExternalDocLinkObj::ScExternalDocLinkObj(ScDocShell* pDocShell, ScExternalRefManager* pRefMgr, sal_uInt16 nFileId) :
+ mpDocShell(pDocShell), mpRefMgr(pRefMgr), mnFileId(nFileId)
+{
+}
+
+ScExternalDocLinkObj::~ScExternalDocLinkObj()
+{
+}
+
+uno::Reference< sheet::XExternalSheetCache > SAL_CALL ScExternalDocLinkObj::addSheetCache(
+ const OUString& aSheetName, sal_Bool bDynamicCache )
+{
+ SolarMutexGuard aGuard;
+ size_t nIndex = 0;
+ ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aSheetName, true, &nIndex);
+ if (!bDynamicCache)
+ // Set the whole table cached to prevent access to the source document.
+ pTable->setWholeTableCached();
+
+ uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(mpDocShell, pTable, nIndex));
+ return aSheetCache;
+}
+
+Any SAL_CALL ScExternalDocLinkObj::getByName(const OUString &aName)
+{
+ SolarMutexGuard aGuard;
+ size_t nIndex = 0;
+ ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aName, false, &nIndex);
+ if (!pTable)
+ throw container::NoSuchElementException();
+
+ uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(mpDocShell, pTable, nIndex));
+
+ return Any(aSheetCache);
+}
+
+Sequence< OUString > SAL_CALL ScExternalDocLinkObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ vector<OUString> aTabNames;
+ mpRefMgr->getAllCachedTableNames(mnFileId, aTabNames);
+
+ // #i116940# be consistent with getByName: include only table names which have a cache already
+ vector<OUString> aValidNames;
+ std::copy_if(aTabNames.begin(), aTabNames.end(), std::back_inserter(aValidNames),
+ [&](const OUString& rTabName) { return mpRefMgr->getCacheTable(mnFileId, rTabName, false); });
+
+ Sequence<OUString> aSeq(comphelper::containerToSequence(aValidNames));
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScExternalDocLinkObj::hasByName(const OUString &aName)
+{
+ SolarMutexGuard aGuard;
+
+ // #i116940# be consistent with getByName: allow only table names which have a cache already
+ ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aName, false);
+ return bool(pTable);
+}
+
+sal_Int32 SAL_CALL ScExternalDocLinkObj::getCount()
+{
+ SolarMutexGuard aGuard;
+
+ // #i116940# be consistent with getByName: count only table names which have a cache already
+ return getElementNames().getLength();
+}
+
+Any SAL_CALL ScExternalDocLinkObj::getByIndex(sal_Int32 nApiIndex)
+{
+ SolarMutexGuard aGuard;
+
+ // #i116940# Can't use nApiIndex as index for the ref manager, because the API counts only
+ // the entries which have a cache already. Quick solution: Use getElementNames.
+ Sequence< OUString > aNames( getElementNames() );
+ if (nApiIndex < 0 || nApiIndex >= aNames.getLength())
+ throw lang::IndexOutOfBoundsException();
+
+ size_t nIndex = 0;
+ ScExternalRefCache::TableTypeRef pTable = mpRefMgr->getCacheTable(mnFileId, aNames[nApiIndex], false, &nIndex);
+ if (!pTable)
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Reference< sheet::XExternalSheetCache > aSheetCache(new ScExternalSheetCacheObj(mpDocShell, pTable, nIndex));
+
+ return Any(aSheetCache);
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL ScExternalDocLinkObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XEnumeration > aRef(
+ new ScIndexEnumeration(this, "com.sun.star.sheet.ExternalDocLink"));
+ return aRef;
+}
+
+uno::Type SAL_CALL ScExternalDocLinkObj::getElementType()
+{
+ return cppu::UnoType<sheet::XExternalDocLink>::get();
+}
+
+sal_Bool SAL_CALL ScExternalDocLinkObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+
+ // #i116940# be consistent with getByName: count only table names which have a cache already
+ return getElementNames().hasElements();
+}
+
+sal_Int32 SAL_CALL ScExternalDocLinkObj::getTokenIndex()
+{
+ return static_cast<sal_Int32>(mnFileId);
+}
+
+ScExternalDocLinksObj::ScExternalDocLinksObj(ScDocShell* pDocShell) :
+ mpDocShell(pDocShell),
+ mpRefMgr(pDocShell->GetDocument().GetExternalRefManager())
+{
+}
+
+ScExternalDocLinksObj::~ScExternalDocLinksObj()
+{
+}
+
+uno::Reference< sheet::XExternalDocLink > SAL_CALL ScExternalDocLinksObj::addDocLink(
+ const OUString& aDocName )
+{
+ SolarMutexGuard aGuard;
+ OUString aDocUrl( ScGlobal::GetAbsDocName( aDocName, mpDocShell));
+ sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aDocUrl);
+ uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId));
+ return aDocLink;
+}
+
+Any SAL_CALL ScExternalDocLinksObj::getByName(const OUString &aName)
+{
+ SolarMutexGuard aGuard;
+ OUString aDocUrl( ScGlobal::GetAbsDocName( aName, mpDocShell));
+ if (!mpRefMgr->hasExternalFile(aDocUrl))
+ throw container::NoSuchElementException();
+
+ sal_uInt16 nFileId = mpRefMgr->getExternalFileId(aDocUrl);
+ uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId));
+
+ return Any(aDocLink);
+}
+
+Sequence< OUString > SAL_CALL ScExternalDocLinksObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 n = mpRefMgr->getExternalFileCount();
+ Sequence<OUString> aSeq(n);
+ auto aSeqRange = asNonConstRange(aSeq);
+ for (sal_uInt16 i = 0; i < n; ++i)
+ {
+ const OUString* pName = mpRefMgr->getExternalFileName(i);
+ aSeqRange[i] = pName ? *pName : OUString();
+ }
+
+ return aSeq;
+}
+
+sal_Bool SAL_CALL ScExternalDocLinksObj::hasByName(const OUString &aName)
+{
+ SolarMutexGuard aGuard;
+ return mpRefMgr->hasExternalFile(aName);
+}
+
+sal_Int32 SAL_CALL ScExternalDocLinksObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ return mpRefMgr->getExternalFileCount();
+}
+
+Any SAL_CALL ScExternalDocLinksObj::getByIndex(sal_Int32 nIndex)
+{
+ SolarMutexGuard aGuard;
+ if (nIndex > ::std::numeric_limits<sal_uInt16>::max() || nIndex < ::std::numeric_limits<sal_uInt16>::min())
+ throw lang::IndexOutOfBoundsException();
+
+ sal_uInt16 nFileId = static_cast<sal_uInt16>(nIndex);
+
+ if (!mpRefMgr->hasExternalFile(nFileId))
+ throw lang::IndexOutOfBoundsException();
+
+ uno::Reference< sheet::XExternalDocLink > aDocLink(new ScExternalDocLinkObj(mpDocShell, mpRefMgr, nFileId));
+ return Any(aDocLink);
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL ScExternalDocLinksObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XEnumeration > aRef(
+ new ScIndexEnumeration(this, "com.sun.star.sheet.ExternalDocLinks"));
+ return aRef;
+}
+
+uno::Type SAL_CALL ScExternalDocLinksObj::getElementType()
+{
+ return cppu::UnoType<sheet::XExternalDocLinks>::get();
+}
+
+sal_Bool SAL_CALL ScExternalDocLinksObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return mpRefMgr->getExternalFileCount() > 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/listenercalls.cxx b/sc/source/ui/unoobj/listenercalls.cxx
new file mode 100644
index 000000000..7ff7c7df0
--- /dev/null
+++ b/sc/source/ui/unoobj/listenercalls.cxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/util/XModifyListener.hpp>
+#include <osl/diagnose.h>
+
+#include <listenercalls.hxx>
+
+using namespace com::sun::star;
+
+ScUnoListenerCalls::ScUnoListenerCalls() {}
+
+ScUnoListenerCalls::~ScUnoListenerCalls()
+{
+ OSL_ENSURE(aEntries.empty(), "unhandled listener calls remaining");
+}
+
+void ScUnoListenerCalls::Add(const uno::Reference<util::XModifyListener>& rListener,
+ const lang::EventObject& rEvent)
+{
+ if (rListener.is())
+ aEntries.emplace_back(rListener, rEvent);
+}
+
+void ScUnoListenerCalls::ExecuteAndClear()
+{
+ // Execute all stored calls and remove them from the list.
+ // During each modified() call, Add may be called again.
+ // These new calls are executed here, too.
+
+ std::list<ScUnoListenerEntry>::iterator aItr(aEntries.begin());
+ while (aItr != aEntries.end())
+ {
+ ScUnoListenerEntry aEntry = *aItr;
+ try
+ {
+ aEntry.xListener->modified(aEntry.aEvent);
+ }
+ catch (const uno::RuntimeException&)
+ {
+ // the listener is an external object and may throw a RuntimeException
+ // for reasons we don't know
+ }
+
+ // New calls that are added during the modified() call are appended to the end
+ // of aEntries, so the loop will catch them, too (as long as erase happens
+ // after modified).
+
+ aItr = aEntries.erase(aItr);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/miscuno.cxx b/sc/source/ui/unoobj/miscuno.cxx
new file mode 100644
index 000000000..d2e098d00
--- /dev/null
+++ b/sc/source/ui/unoobj/miscuno.cxx
@@ -0,0 +1,284 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <o3tl/any.hxx>
+#include <vcl/svapp.hxx>
+
+#include <miscuno.hxx>
+
+using namespace com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Any;
+
+SC_SIMPLE_SERVICE_INFO( ScNameToIndexAccess, "ScNameToIndexAccess", "stardiv.unknown" )
+
+bool ScUnoHelpFunctions::GetBoolProperty( const uno::Reference<beans::XPropertySet>& xProp,
+ const OUString& rName, bool bDefault )
+{
+ bool bRet = bDefault;
+ if ( xProp.is() )
+ {
+ try
+ {
+ xProp->getPropertyValue( rName ) >>= bRet;
+ }
+ catch(uno::Exception&)
+ {
+ // keep default
+ }
+ }
+ return bRet;
+}
+
+sal_Int16 ScUnoHelpFunctions::GetShortProperty( const css::uno::Reference< css::beans::XPropertySet>& xProp,
+ const OUString& rName, sal_Int16 nDefault )
+{
+ sal_Int16 nRet = nDefault;
+ if ( xProp.is() )
+ {
+ try
+ {
+ xProp->getPropertyValue( rName ) >>= nRet;
+ }
+ catch(uno::Exception&)
+ {
+ // keep default
+ }
+ }
+ return nRet;
+}
+
+sal_Int32 ScUnoHelpFunctions::GetLongProperty( const uno::Reference<beans::XPropertySet>& xProp,
+ const OUString& rName )
+{
+ sal_Int32 nRet = 0;
+ if ( xProp.is() )
+ {
+ try
+ {
+ //! type conversion???
+ xProp->getPropertyValue( rName ) >>= nRet;
+ }
+ catch(uno::Exception&)
+ {
+ // keep default
+ }
+ }
+ return nRet;
+}
+
+sal_Int32 ScUnoHelpFunctions::GetEnumPropertyImpl( const uno::Reference<beans::XPropertySet>& xProp,
+ const OUString& rName, sal_Int32 nDefault )
+{
+ sal_Int32 nRet = nDefault;
+ if ( xProp.is() )
+ {
+ try
+ {
+ uno::Any aAny(xProp->getPropertyValue( rName ));
+
+ if ( aAny.getValueTypeClass() == uno::TypeClass_ENUM )
+ {
+ //! get enum value from any???
+ nRet = *static_cast<sal_Int32 const *>(aAny.getValue());
+ }
+ else
+ {
+ //! type conversion???
+ aAny >>= nRet;
+ }
+ }
+ catch(uno::Exception&)
+ {
+ // keep default
+ }
+ }
+ return nRet;
+}
+
+OUString ScUnoHelpFunctions::GetStringProperty(
+ const Reference<beans::XPropertySet>& xProp, const OUString& rName, const OUString& rDefault )
+{
+ OUString aRet = rDefault;
+ if (!xProp.is())
+ return aRet;
+
+ try
+ {
+ Any any = xProp->getPropertyValue(rName);
+ any >>= aRet;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ return aRet;
+}
+
+bool ScUnoHelpFunctions::GetBoolFromAny( const uno::Any& aAny )
+{
+ auto b = o3tl::tryAccess<bool>(aAny);
+ return b && *b;
+}
+
+sal_Int16 ScUnoHelpFunctions::GetInt16FromAny( const uno::Any& aAny )
+{
+ sal_Int16 nRet = 0;
+ if ( aAny >>= nRet )
+ return nRet;
+ return 0;
+}
+
+sal_Int32 ScUnoHelpFunctions::GetInt32FromAny( const uno::Any& aAny )
+{
+ sal_Int32 nRet = 0;
+ if ( aAny >>= nRet )
+ return nRet;
+ return 0;
+}
+
+sal_Int32 ScUnoHelpFunctions::GetEnumFromAny( const uno::Any& aAny )
+{
+ sal_Int32 nRet = 0;
+ if ( aAny.getValueTypeClass() == uno::TypeClass_ENUM )
+ nRet = *static_cast<sal_Int32 const *>(aAny.getValue());
+ else
+ aAny >>= nRet;
+ return nRet;
+}
+
+void ScUnoHelpFunctions::SetOptionalPropertyValue(
+ const Reference<beans::XPropertySet>& rPropSet, const char* pPropName, const Any& rVal )
+{
+ SetOptionalPropertyValue(rPropSet, OUString::createFromAscii(pPropName), rVal);
+}
+
+void ScUnoHelpFunctions::SetOptionalPropertyValue(
+ const Reference<beans::XPropertySet>& rPropSet, const OUString& sPropName, const Any& rVal )
+{
+ try
+ {
+ rPropSet->setPropertyValue(sPropName, rVal);
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ // ignored - not supported.
+ }
+}
+
+ScIndexEnumeration::ScIndexEnumeration(const uno::Reference<container::XIndexAccess>& rInd,
+ const OUString& rServiceName) :
+ xIndex( rInd ),
+ sServiceName(rServiceName),
+ nPos( 0 )
+{
+}
+
+ScIndexEnumeration::~ScIndexEnumeration()
+{
+}
+
+// XEnumeration
+
+sal_Bool SAL_CALL ScIndexEnumeration::hasMoreElements()
+{
+ SolarMutexGuard aGuard;
+ return ( nPos < xIndex->getCount() );
+}
+
+uno::Any SAL_CALL ScIndexEnumeration::nextElement()
+{
+ SolarMutexGuard aGuard;
+ uno::Any aReturn;
+ try
+ {
+ aReturn = xIndex->getByIndex(nPos++);
+ }
+ catch (lang::IndexOutOfBoundsException&)
+ {
+ throw container::NoSuchElementException();
+ }
+ return aReturn;
+}
+
+OUString SAL_CALL ScIndexEnumeration::getImplementationName()
+{
+ return "ScIndexEnumeration";
+}
+
+sal_Bool SAL_CALL ScIndexEnumeration::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+css::uno::Sequence< OUString >
+ SAL_CALL ScIndexEnumeration::getSupportedServiceNames()
+{
+ return { sServiceName };
+}
+
+ScNameToIndexAccess::ScNameToIndexAccess( const css::uno::Reference<
+ css::container::XNameAccess>& rNameObj ) :
+ xNameAccess( rNameObj )
+{
+ //! test for XIndexAccess interface at rNameObj, use that instead!
+
+ if ( xNameAccess.is() )
+ aNames = xNameAccess->getElementNames();
+}
+
+ScNameToIndexAccess::~ScNameToIndexAccess()
+{
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScNameToIndexAccess::getCount( )
+{
+ return aNames.getLength();
+}
+
+css::uno::Any SAL_CALL ScNameToIndexAccess::getByIndex( sal_Int32 nIndex )
+{
+ if ( xNameAccess.is() && nIndex >= 0 && nIndex < aNames.getLength() )
+ return xNameAccess->getByName( aNames.getConstArray()[nIndex] );
+
+ throw lang::IndexOutOfBoundsException();
+}
+
+// XElementAccess
+
+css::uno::Type SAL_CALL ScNameToIndexAccess::getElementType( )
+{
+ if ( xNameAccess.is() )
+ return xNameAccess->getElementType();
+ else
+ return uno::Type();
+}
+
+sal_Bool SAL_CALL ScNameToIndexAccess::hasElements( )
+{
+ return getCount() > 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/nameuno.cxx b/sc/source/ui/unoobj/nameuno.cxx
new file mode 100644
index 000000000..1a1184c00
--- /dev/null
+++ b/sc/source/ui/unoobj/nameuno.cxx
@@ -0,0 +1,1158 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <o3tl/safeint.hxx>
+#include <svl/hint.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/sheet/NamedRangeFlag.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <unotools/charclass.hxx>
+
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Any;
+
+#include <nameuno.hxx>
+#include <miscuno.hxx>
+#include <cellsuno.hxx>
+#include <convuno.hxx>
+#include <targuno.hxx>
+#include <tokenuno.hxx>
+#include <tokenarray.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <rangenam.hxx>
+#include <unonames.hxx>
+
+#include <scui_def.hxx>
+
+static const SfxItemPropertyMapEntry* lcl_GetNamedRangeMap()
+{
+ static const SfxItemPropertyMapEntry aNamedRangeMap_Impl[] =
+ {
+ { SC_UNO_LINKDISPBIT, 0, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_LINKDISPNAME, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_TOKENINDEX, 0, cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNONAME_ISSHAREDFMLA, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aNamedRangeMap_Impl;
+}
+
+static const SfxItemPropertyMapEntry* lcl_GetNamedRangesMap()
+{
+ static const SfxItemPropertyMapEntry aNamedRangesMap_Impl[] =
+ {
+ { SC_UNO_MODIFY_BROADCAST, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aNamedRangesMap_Impl;
+}
+
+constexpr OUStringLiteral SCNAMEDRANGEOBJ_SERVICE = u"com.sun.star.sheet.NamedRange";
+
+SC_SIMPLE_SERVICE_INFO( ScLabelRangeObj, "ScLabelRangeObj", "com.sun.star.sheet.LabelRange" )
+SC_SIMPLE_SERVICE_INFO( ScLabelRangesObj, "ScLabelRangesObj", "com.sun.star.sheet.LabelRanges" )
+SC_SIMPLE_SERVICE_INFO( ScNamedRangesObj, "ScNamedRangesObj", "com.sun.star.sheet.NamedRanges" )
+
+static bool lcl_UserVisibleName(const ScRangeData& rData)
+{
+ //! as method to ScRangeData
+
+ return !rData.HasType(ScRangeData::Type::Database);
+}
+
+ScNamedRangeObj::ScNamedRangeObj( rtl::Reference< ScNamedRangesObj > const & xParent, ScDocShell* pDocSh, const OUString& rNm, Reference<container::XNamed> const & xSheet):
+ mxParent(xParent),
+ pDocShell( pDocSh ),
+ aName( rNm ),
+ mxSheet( xSheet )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScNamedRangeObj::~ScNamedRangeObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScNamedRangeObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update is of no interest
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // became invalid
+}
+
+// Helper functions
+
+ScRangeData* ScNamedRangeObj::GetRangeData_Impl()
+{
+ ScRangeData* pRet = nullptr;
+ if (pDocShell)
+ {
+ ScRangeName* pNames;
+ SCTAB nTab = GetTab_Impl();
+ if (nTab >= 0)
+ pNames = pDocShell->GetDocument().GetRangeName(nTab);
+ else
+ pNames = pDocShell->GetDocument().GetRangeName();
+ if (pNames)
+ {
+ pRet = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
+ if (pRet)
+ pRet->ValidateTabRefs(); // adjust relative tab refs to valid tables
+ }
+ }
+ return pRet;
+}
+
+SCTAB ScNamedRangeObj::GetTab_Impl()
+{
+ if (mxSheet.is())
+ {
+ if (!pDocShell)
+ return -2;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab;
+ OUString sName = mxSheet->getName();
+ bool bFound = rDoc.GetTable(sName, nTab);
+ assert(bFound); (void)bFound; // fouled up?
+ return nTab;
+ }
+ else
+ return -1;//global range name
+}
+
+// sheet::XNamedRange
+
+void ScNamedRangeObj::Modify_Impl( const OUString* pNewName, const ScTokenArray* pNewTokens, const OUString* pNewContent,
+ const ScAddress* pNewPos, const ScRangeData::Type* pNewType,
+ const formula::FormulaGrammar::Grammar eGrammar )
+{
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangeName* pNames;
+ SCTAB nTab = GetTab_Impl();
+ if (nTab >= 0)
+ pNames = rDoc.GetRangeName(nTab);
+ else
+ pNames = rDoc.GetRangeName();
+ if (!pNames)
+ return;
+
+ const ScRangeData* pOld = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
+ if (!pOld)
+ return;
+
+ std::unique_ptr<ScRangeName> pNewRanges(new ScRangeName(*pNames));
+
+ OUString aInsName = pOld->GetName();
+ if (pNewName)
+ aInsName = *pNewName;
+
+ // Content string based => no problems with changed positions and such.
+ OUString aContent = pOld->GetSymbol(eGrammar);
+ if (pNewContent)
+ aContent = *pNewContent;
+
+ ScAddress aPos = pOld->GetPos();
+ if (pNewPos)
+ aPos = *pNewPos;
+
+ ScRangeData::Type nType = pOld->GetType();
+ if (pNewType)
+ nType = *pNewType;
+
+ ScRangeData* pNew = nullptr;
+ if (pNewTokens)
+ pNew = new ScRangeData( rDoc, aInsName, *pNewTokens, aPos, nType );
+ else
+ pNew = new ScRangeData( rDoc, aInsName, aContent, aPos, nType, eGrammar );
+
+ pNew->SetIndex( pOld->GetIndex() );
+
+ pNewRanges->erase(*pOld);
+ if (pNewRanges->insert(pNew))
+ {
+ pDocShell->GetDocFunc().SetNewRangeNames(std::move(pNewRanges), mxParent->IsModifyAndBroadcast(), nTab);
+
+ aName = aInsName; //! broadcast?
+ }
+ else
+ {
+ pNew = nullptr; //! uno::Exception/Error or something
+ }
+}
+
+OUString SAL_CALL ScNamedRangeObj::getName()
+{
+ SolarMutexGuard aGuard;
+ return aName;
+}
+
+void SAL_CALL ScNamedRangeObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ //! adapt formulas ?????
+
+ OUString aNewStr(aNewName);
+ // GRAM_API for API compatibility.
+ Modify_Impl( &aNewStr, nullptr, nullptr, nullptr, nullptr,formula::FormulaGrammar::GRAM_API );
+
+ if ( aName != aNewStr ) // some error occurred...
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+OUString SAL_CALL ScNamedRangeObj::getContent()
+{
+ SolarMutexGuard aGuard;
+ OUString aContent;
+ ScRangeData* pData = GetRangeData_Impl();
+ if (pData)
+ // GRAM_API for API compatibility.
+ aContent = pData->GetSymbol(formula::FormulaGrammar::GRAM_API);
+ return aContent;
+}
+
+void SAL_CALL ScNamedRangeObj::setContent( const OUString& aContent )
+{
+ SolarMutexGuard aGuard;
+ OUString aContStr(aContent);
+ // GRAM_API for API compatibility.
+ Modify_Impl( nullptr, nullptr, &aContStr, nullptr, nullptr,formula::FormulaGrammar::GRAM_API );
+}
+
+table::CellAddress SAL_CALL ScNamedRangeObj::getReferencePosition()
+{
+ SolarMutexGuard aGuard;
+ ScAddress aPos;
+ ScRangeData* pData = GetRangeData_Impl();
+ if (pData)
+ aPos = pData->GetPos();
+ table::CellAddress aAddress;
+ aAddress.Column = aPos.Col();
+ aAddress.Row = aPos.Row();
+ aAddress.Sheet = aPos.Tab();
+ if (pDocShell)
+ {
+ SCTAB nDocTabs = pDocShell->GetDocument().GetTableCount();
+ if ( aAddress.Sheet >= nDocTabs && nDocTabs > 0 )
+ {
+ // Even after ValidateTabRefs, the position can be invalid if
+ // the content points to preceding tables. The resulting string
+ // is invalid in any case, so the position is just shifted.
+ aAddress.Sheet = nDocTabs - 1;
+ }
+ }
+ return aAddress;
+}
+
+void SAL_CALL ScNamedRangeObj::setReferencePosition( const table::CellAddress& aReferencePosition )
+{
+ SolarMutexGuard aGuard;
+ ScAddress aPos( static_cast<SCCOL>(aReferencePosition.Column), static_cast<SCROW>(aReferencePosition.Row), aReferencePosition.Sheet );
+ // GRAM_API for API compatibility.
+ Modify_Impl( nullptr, nullptr, nullptr, &aPos, nullptr,formula::FormulaGrammar::GRAM_API );
+}
+
+sal_Int32 SAL_CALL ScNamedRangeObj::getType()
+{
+ SolarMutexGuard aGuard;
+ sal_Int32 nType=0;
+ ScRangeData* pData = GetRangeData_Impl();
+ if (pData)
+ {
+ // do not return internal ScRangeData::Type flags
+ if ( pData->HasType(ScRangeData::Type::Criteria) ) nType |= sheet::NamedRangeFlag::FILTER_CRITERIA;
+ if ( pData->HasType(ScRangeData::Type::PrintArea) ) nType |= sheet::NamedRangeFlag::PRINT_AREA;
+ if ( pData->HasType(ScRangeData::Type::ColHeader) ) nType |= sheet::NamedRangeFlag::COLUMN_HEADER;
+ if ( pData->HasType(ScRangeData::Type::RowHeader) ) nType |= sheet::NamedRangeFlag::ROW_HEADER;
+ }
+ return nType;
+}
+
+void SAL_CALL ScNamedRangeObj::setType( sal_Int32 nUnoType )
+{
+ SolarMutexGuard aGuard;
+ ScRangeData::Type nNewType = ScRangeData::Type::Name;
+ if ( nUnoType & sheet::NamedRangeFlag::FILTER_CRITERIA ) nNewType |= ScRangeData::Type::Criteria;
+ if ( nUnoType & sheet::NamedRangeFlag::PRINT_AREA ) nNewType |= ScRangeData::Type::PrintArea;
+ if ( nUnoType & sheet::NamedRangeFlag::COLUMN_HEADER ) nNewType |= ScRangeData::Type::ColHeader;
+ if ( nUnoType & sheet::NamedRangeFlag::ROW_HEADER ) nNewType |= ScRangeData::Type::RowHeader;
+
+ // GRAM_API for API compatibility.
+ Modify_Impl( nullptr, nullptr, nullptr, nullptr, &nNewType,formula::FormulaGrammar::GRAM_API );
+}
+
+// XFormulaTokens
+
+uno::Sequence<sheet::FormulaToken> SAL_CALL ScNamedRangeObj::getTokens()
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence<sheet::FormulaToken> aSequence;
+ ScRangeData* pData = GetRangeData_Impl();
+ if (pData && pDocShell)
+ {
+ ScTokenArray* pTokenArray = pData->GetCode();
+ if ( pTokenArray )
+ ScTokenConversion::ConvertToTokenSequence( pDocShell->GetDocument(), aSequence, *pTokenArray );
+ }
+ return aSequence;
+}
+
+void SAL_CALL ScNamedRangeObj::setTokens( const uno::Sequence<sheet::FormulaToken>& rTokens )
+{
+ SolarMutexGuard aGuard;
+ if( pDocShell )
+ {
+ ScTokenArray aTokenArray(pDocShell->GetDocument());
+ (void)ScTokenConversion::ConvertToTokenArray( pDocShell->GetDocument(), aTokenArray, rTokens );
+ // GRAM_API for API compatibility.
+ Modify_Impl( nullptr, &aTokenArray, nullptr, nullptr, nullptr, formula::FormulaGrammar::GRAM_API );
+ }
+}
+
+// XCellRangeSource
+
+uno::Reference<table::XCellRange> SAL_CALL ScNamedRangeObj::getReferredCells()
+{
+ SolarMutexGuard aGuard;
+ ScRange aRange;
+ ScRangeData* pData = GetRangeData_Impl();
+ if ( pData && pData->IsValidReference( aRange ) )
+ {
+ //! static function to create ScCellObj/ScCellRangeObj at ScCellRangeObj ???
+
+ if ( aRange.aStart == aRange.aEnd )
+ return new ScCellObj( pDocShell, aRange.aStart );
+ else
+ return new ScCellRangeObj( pDocShell, aRange );
+ }
+ return nullptr;
+}
+
+// beans::XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScNamedRangeObj::getPropertySetInfo()
+{
+ static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetNamedRangeMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScNamedRangeObj::setPropertyValue(
+ const OUString& rPropertyName, const uno::Any& /*aValue*/ )
+{
+ if ( rPropertyName == SC_UNONAME_ISSHAREDFMLA )
+ {
+ // Ignore this.
+ }
+}
+
+uno::Any SAL_CALL ScNamedRangeObj::getPropertyValue( const OUString& rPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ if ( rPropertyName == SC_UNO_LINKDISPBIT )
+ {
+ // no target bitmaps for individual entries (would be all equal)
+ // ScLinkTargetTypeObj::SetLinkTargetBitmap( aRet, SC_LINKTARGETTYPE_RANGENAME );
+ }
+ else if ( rPropertyName == SC_UNO_LINKDISPNAME )
+ aRet <<= aName;
+ else if ( rPropertyName == SC_UNONAME_TOKENINDEX )
+ {
+ // get index for use in formula tokens (read-only)
+ ScRangeData* pData = GetRangeData_Impl();
+ if (pData)
+ aRet <<= static_cast<sal_Int32>(pData->GetIndex());
+ }
+ else if ( rPropertyName == SC_UNONAME_ISSHAREDFMLA )
+ {
+ if (GetRangeData_Impl())
+ aRet <<= false;
+ }
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScNamedRangeObj )
+
+// lang::XServiceInfo
+
+OUString SAL_CALL ScNamedRangeObj::getImplementationName()
+{
+ return "ScNamedRangeObj";
+}
+
+sal_Bool SAL_CALL ScNamedRangeObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScNamedRangeObj::getSupportedServiceNames()
+{
+ return {SCNAMEDRANGEOBJ_SERVICE, SCLINKTARGET_SERVICE};
+}
+
+// XUnoTunnel
+
+sal_Int64 SAL_CALL ScNamedRangeObj::getSomething(
+ const uno::Sequence<sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+const uno::Sequence<sal_Int8>& ScNamedRangeObj::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theScNamedRangeObjUnoTunnelId;
+ return theScNamedRangeObjUnoTunnelId.getSeq();
+}
+
+ScNamedRangesObj::ScNamedRangesObj(ScDocShell* pDocSh) :
+ mbModifyAndBroadcast(true),
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScNamedRangesObj::~ScNamedRangesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScNamedRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update is of no interest
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// sheet::XNamedRanges
+
+void SAL_CALL ScNamedRangesObj::addNewByName( const OUString& aName,
+ const OUString& aContent, const table::CellAddress& aPosition,
+ sal_Int32 nUnoType )
+{
+ SolarMutexGuard aGuard;
+ ScAddress aPos( static_cast<SCCOL>(aPosition.Column), static_cast<SCROW>(aPosition.Row), aPosition.Sheet );
+
+ ScRangeData::Type nNewType = ScRangeData::Type::Name;
+ if ( nUnoType & sheet::NamedRangeFlag::FILTER_CRITERIA ) nNewType |= ScRangeData::Type::Criteria;
+ if ( nUnoType & sheet::NamedRangeFlag::PRINT_AREA ) nNewType |= ScRangeData::Type::PrintArea;
+ if ( nUnoType & sheet::NamedRangeFlag::COLUMN_HEADER ) nNewType |= ScRangeData::Type::ColHeader;
+ if ( nUnoType & sheet::NamedRangeFlag::ROW_HEADER ) nNewType |= ScRangeData::Type::RowHeader;
+
+ bool bDone = false;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ // tdf#119457 - check for a valid range name and cell reference
+ switch (ScRangeData::IsNameValid(aName, rDoc))
+ {
+ case ScRangeData::IsNameValidType::NAME_INVALID_CELL_REF:
+ throw uno::RuntimeException(
+ "Invalid name. Reference to a cell, or a range of cells not allowed",
+ uno::Reference<uno::XInterface>(static_cast<::cppu::OWeakObject*>(this)));
+ break;
+ case ScRangeData::IsNameValidType::NAME_INVALID_BAD_STRING:
+ throw uno::RuntimeException(
+ "Invalid name. Start with a letter, use only letters, numbers and underscore",
+ uno::Reference<uno::XInterface>(static_cast<::cppu::OWeakObject*>(this)));
+ break;
+ case ScRangeData::IsNameValidType::NAME_VALID:
+ if (ScRangeName* pNames = GetRangeName_Impl();
+ pNames
+ && !pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName)))
+ {
+ std::unique_ptr<ScRangeName> pNewRanges(new ScRangeName( *pNames ));
+ // GRAM_API for API compatibility.
+ ScRangeData* pNew = new ScRangeData( rDoc, aName, aContent,
+ aPos, nNewType,formula::FormulaGrammar::GRAM_API );
+ if ( pNewRanges->insert(pNew) )
+ {
+ pDocShell->GetDocFunc().SetNewRangeNames(std::move(pNewRanges), mbModifyAndBroadcast, GetTab_Impl());
+ bDone = true;
+ }
+ else
+ {
+ pNew = nullptr;
+ }
+ }
+ }
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScNamedRangesObj::addNewFromTitles( const table::CellRangeAddress& aSource,
+ sheet::Border aBorder )
+{
+ SolarMutexGuard aGuard;
+ //! this cannot be an enum, because multiple bits can be set !!!
+
+ bool bTop = ( aBorder == sheet::Border_TOP );
+ bool bLeft = ( aBorder == sheet::Border_LEFT );
+ bool bBottom = ( aBorder == sheet::Border_BOTTOM );
+ bool bRight = ( aBorder == sheet::Border_RIGHT );
+
+ ScRange aRange;
+ ScUnoConversion::FillScRange( aRange, aSource );
+
+ CreateNameFlags nFlags = CreateNameFlags::NONE;
+ if (bTop) nFlags |= CreateNameFlags::Top;
+ if (bLeft) nFlags |= CreateNameFlags::Left;
+ if (bBottom) nFlags |= CreateNameFlags::Bottom;
+ if (bRight) nFlags |= CreateNameFlags::Right;
+
+ if (nFlags != CreateNameFlags::NONE)
+ pDocShell->GetDocFunc().CreateNames( aRange, nFlags, true, GetTab_Impl() );
+}
+
+void SAL_CALL ScNamedRangesObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ ScRangeName* pNames = GetRangeName_Impl();
+ if (pNames)
+ {
+ const ScRangeData* pData = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
+ if (pData && lcl_UserVisibleName(*pData))
+ {
+ std::unique_ptr<ScRangeName> pNewRanges(new ScRangeName(*pNames));
+ pNewRanges->erase(*pData);
+ pDocShell->GetDocFunc().SetNewRangeNames( std::move(pNewRanges), mbModifyAndBroadcast, GetTab_Impl());
+ bDone = true;
+ }
+ }
+ }
+
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+void SAL_CALL ScNamedRangesObj::outputList( const table::CellAddress& aOutputPosition )
+{
+ SolarMutexGuard aGuard;
+ ScAddress aPos( static_cast<SCCOL>(aOutputPosition.Column), static_cast<SCROW>(aOutputPosition.Row), aOutputPosition.Sheet );
+ if (pDocShell)
+ pDocShell->GetDocFunc().InsertNameList( aPos, true );
+}
+
+// container::XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScNamedRangesObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.NamedRangesEnumeration");
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScNamedRangesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ tools::Long nRet = 0;
+ if (pDocShell)
+ {
+ ScRangeName* pNames = GetRangeName_Impl();
+ if (pNames)
+ {
+ for (const auto& rName : *pNames)
+ if (lcl_UserVisibleName(*rName.second))
+ ++nRet;
+ }
+ }
+ return nRet;
+}
+
+uno::Any SAL_CALL ScNamedRangesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< sheet::XNamedRange > xRange(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if ( !xRange.is() )
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRange);
+}
+
+uno::Type SAL_CALL ScNamedRangesObj::getElementType()
+{
+ return cppu::UnoType<sheet::XNamedRange>::get(); // must be suitable for getByIndex
+}
+
+sal_Bool SAL_CALL ScNamedRangesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+Reference<beans::XPropertySetInfo> SAL_CALL ScNamedRangesObj::getPropertySetInfo()
+{
+ static Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo(lcl_GetNamedRangesMap()));
+ return aRef;
+}
+
+void SAL_CALL ScNamedRangesObj::setPropertyValue(
+ const OUString& rPropertyName, const uno::Any& aValue )
+{
+ if ( rPropertyName == SC_UNO_MODIFY_BROADCAST )
+ {
+ aValue >>= mbModifyAndBroadcast;
+ }
+}
+
+Any SAL_CALL ScNamedRangesObj::getPropertyValue( const OUString& rPropertyName )
+{
+ Any aRet;
+ if ( rPropertyName == SC_UNO_MODIFY_BROADCAST )
+ {
+ aRet <<= mbModifyAndBroadcast;
+ }
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScNamedRangesObj )
+
+uno::Any SAL_CALL ScNamedRangesObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< sheet::XNamedRange > xRange(GetObjectByName_Impl(aName));
+ if ( !xRange.is() )
+ throw container::NoSuchElementException();
+
+ return uno::Any(xRange);
+}
+
+uno::Sequence<OUString> SAL_CALL ScNamedRangesObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScRangeName* pNames = GetRangeName_Impl();
+ if (pNames)
+ {
+ tools::Long nVisCount = getCount(); // names with lcl_UserVisibleName
+ uno::Sequence<OUString> aSeq(nVisCount);
+ OUString* pAry = aSeq.getArray();
+ sal_uInt16 nVisPos = 0;
+ for (const auto& rName : *pNames)
+ {
+ if (lcl_UserVisibleName(*rName.second))
+ pAry[nVisPos++] = rName.second->GetName();
+ }
+ return aSeq;
+ }
+ }
+ return {};
+}
+
+sal_Bool SAL_CALL ScNamedRangesObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScRangeName* pNames = GetRangeName_Impl();
+ if (pNames)
+ {
+ const ScRangeData* pData = pNames->findByUpperName(ScGlobal::getCharClass().uppercase(aName));
+ if (pData && lcl_UserVisibleName(*pData))
+ return true;
+ }
+ }
+ return false;
+}
+
+/** called from the XActionLockable interface methods on initial locking */
+void ScNamedRangesObj::lock()
+{
+ pDocShell->GetDocument().PreprocessRangeNameUpdate();
+}
+
+/** called from the XActionLockable interface methods on final unlock */
+void ScNamedRangesObj::unlock()
+{
+ pDocShell->GetDocument().CompileHybridFormula();
+}
+
+// document::XActionLockable
+
+sal_Bool ScNamedRangesObj::isActionLocked()
+{
+ SolarMutexGuard aGuard;
+ return pDocShell->GetDocument().GetNamedRangesLockCount() != 0;
+}
+
+void ScNamedRangesObj::addActionLock()
+{
+ SolarMutexGuard aGuard;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
+ ++nLockCount;
+ if ( nLockCount == 1 )
+ {
+ lock();
+ }
+ rDoc.SetNamedRangesLockCount( nLockCount );
+}
+
+void ScNamedRangesObj::removeActionLock()
+{
+ SolarMutexGuard aGuard;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
+ if ( nLockCount > 0 )
+ {
+ --nLockCount;
+ if ( nLockCount == 0 )
+ {
+ unlock();
+ }
+ rDoc.SetNamedRangesLockCount( nLockCount );
+ }
+}
+
+void ScNamedRangesObj::setActionLocks( sal_Int16 nLock )
+{
+ SolarMutexGuard aGuard;
+ if ( nLock < 0 )
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
+ if ( nLock == 0 && nLockCount > 0 )
+ {
+ unlock();
+ }
+ if ( nLock > 0 && nLockCount == 0 )
+ {
+ lock();
+ }
+ rDoc.SetNamedRangesLockCount( nLock );
+}
+
+sal_Int16 ScNamedRangesObj::resetActionLocks()
+{
+ SolarMutexGuard aGuard;
+ ScDocument& rDoc = pDocShell->GetDocument();
+ sal_Int16 nLockCount = rDoc.GetNamedRangesLockCount();
+ if ( nLockCount > 0 )
+ {
+ unlock();
+ }
+ rDoc.SetNamedRangesLockCount( 0 );
+ return nLockCount;
+}
+
+ScGlobalNamedRangesObj::ScGlobalNamedRangesObj(ScDocShell* pDocSh)
+ : ScNamedRangesObj(pDocSh)
+{
+
+}
+
+ScGlobalNamedRangesObj::~ScGlobalNamedRangesObj()
+{
+
+}
+
+rtl::Reference<ScNamedRangeObj> ScGlobalNamedRangesObj::GetObjectByIndex_Impl(sal_uInt16 nIndex)
+{
+ if (!pDocShell)
+ return nullptr;
+
+ ScRangeName* pNames = pDocShell->GetDocument().GetRangeName();
+ if (!pNames)
+ return nullptr;
+
+ sal_uInt16 nPos = 0;
+ for (const auto& rName : *pNames)
+ {
+ if (lcl_UserVisibleName(*rName.second))
+ {
+ if (nPos == nIndex)
+ return new ScNamedRangeObj(this, pDocShell, rName.second->GetName());
+ }
+ ++nPos;
+ }
+ return nullptr;
+}
+
+rtl::Reference<ScNamedRangeObj> ScGlobalNamedRangesObj::GetObjectByName_Impl(const OUString& aName)
+{
+ if ( pDocShell && hasByName(aName) )
+ return new ScNamedRangeObj(this, pDocShell, aName);
+ return nullptr;
+}
+
+ScRangeName* ScGlobalNamedRangesObj::GetRangeName_Impl()
+{
+ return pDocShell->GetDocument().GetRangeName();
+}
+
+SCTAB ScGlobalNamedRangesObj::GetTab_Impl()
+{
+ return -1;
+}
+
+ScLocalNamedRangesObj::ScLocalNamedRangesObj( ScDocShell* pDocSh, uno::Reference<container::XNamed> const & xSheet )
+ : ScNamedRangesObj(pDocSh),
+ mxSheet(xSheet)
+{
+
+}
+
+ScLocalNamedRangesObj::~ScLocalNamedRangesObj()
+{
+
+}
+
+rtl::Reference<ScNamedRangeObj> ScLocalNamedRangesObj::GetObjectByName_Impl(const OUString& aName)
+{
+ if ( pDocShell && hasByName( aName ) )
+ return new ScNamedRangeObj( this, pDocShell, aName, mxSheet);
+ return nullptr;
+
+}
+
+rtl::Reference<ScNamedRangeObj> ScLocalNamedRangesObj::GetObjectByIndex_Impl( sal_uInt16 nIndex )
+{
+ if (!pDocShell)
+ return nullptr;
+
+ OUString aName = mxSheet->getName();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab;
+ if (!rDoc.GetTable(aName, nTab))
+ return nullptr;
+
+ ScRangeName* pNames = rDoc.GetRangeName( nTab );
+ if (!pNames)
+ return nullptr;
+
+ sal_uInt16 nPos = 0;
+ for (const auto& rName : *pNames)
+ {
+ if (lcl_UserVisibleName(*rName.second))
+ {
+ if (nPos == nIndex)
+ return new ScNamedRangeObj(this, pDocShell, rName.second->GetName(), mxSheet);
+ }
+ ++nPos;
+ }
+ return nullptr;
+}
+
+ScRangeName* ScLocalNamedRangesObj::GetRangeName_Impl()
+{
+ SCTAB nTab = GetTab_Impl();
+ return pDocShell->GetDocument().GetRangeName( nTab );
+}
+
+SCTAB ScLocalNamedRangesObj::GetTab_Impl()
+{
+ SCTAB nTab;
+ (void)pDocShell->GetDocument().GetTable(mxSheet->getName(), nTab);
+ return nTab;
+}
+
+ScLabelRangeObj::ScLabelRangeObj(ScDocShell* pDocSh, bool bCol, const ScRange& rR) :
+ pDocShell( pDocSh ),
+ bColumn( bCol ),
+ aRange( rR )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScLabelRangeObj::~ScLabelRangeObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScLabelRangeObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ //! Ref-Update !!!
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // became invalid
+}
+
+// Helper functions
+
+ScRangePair* ScLabelRangeObj::GetData_Impl()
+{
+ ScRangePair* pRet = nullptr;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+ if (pList)
+ pRet = pList->Find( aRange );
+ }
+ return pRet;
+}
+
+void ScLabelRangeObj::Modify_Impl( const ScRange* pLabel, const ScRange* pData )
+{
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pOldList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+ if (!pOldList)
+ return;
+
+ ScRangePairListRef xNewList(pOldList->Clone());
+ ScRangePair* pEntry = xNewList->Find( aRange );
+ if (!pEntry)
+ return;
+
+ if ( pLabel )
+ pEntry->GetRange(0) = *pLabel;
+ if ( pData )
+ pEntry->GetRange(1) = *pData;
+
+ xNewList->Join( *pEntry, true );
+
+ if (bColumn)
+ rDoc.GetColNameRangesRef() = xNewList;
+ else
+ rDoc.GetRowNameRangesRef() = xNewList;
+
+ rDoc.CompileColRowNameFormula();
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid );
+ pDocShell->SetDocumentModified();
+
+ //! Undo ?!?! (here and from dialog)
+
+ if ( pLabel )
+ aRange = *pLabel; // adapt object to find range again
+}
+
+// sheet::XLabelRange
+
+table::CellRangeAddress SAL_CALL ScLabelRangeObj::getLabelArea()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScRangePair* pData = GetData_Impl();
+ if (pData)
+ ScUnoConversion::FillApiRange( aRet, pData->GetRange(0) );
+ return aRet;
+}
+
+void SAL_CALL ScLabelRangeObj::setLabelArea( const table::CellRangeAddress& aLabelArea )
+{
+ SolarMutexGuard aGuard;
+ ScRange aLabelRange;
+ ScUnoConversion::FillScRange( aLabelRange, aLabelArea );
+ Modify_Impl( &aLabelRange, nullptr );
+}
+
+table::CellRangeAddress SAL_CALL ScLabelRangeObj::getDataArea()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aRet;
+ ScRangePair* pData = GetData_Impl();
+ if (pData)
+ ScUnoConversion::FillApiRange( aRet, pData->GetRange(1) );
+ return aRet;
+}
+
+void SAL_CALL ScLabelRangeObj::setDataArea( const table::CellRangeAddress& aDataArea )
+{
+ SolarMutexGuard aGuard;
+ ScRange aDataRange;
+ ScUnoConversion::FillScRange( aDataRange, aDataArea );
+ Modify_Impl( nullptr, &aDataRange );
+}
+
+ScLabelRangesObj::ScLabelRangesObj(ScDocShell* pDocSh, bool bCol) :
+ pDocShell( pDocSh ),
+ bColumn( bCol )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScLabelRangesObj::~ScLabelRangesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScLabelRangesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update is of no interest
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// sheet::XLabelRanges
+
+rtl::Reference<ScLabelRangeObj> ScLabelRangesObj::GetObjectByIndex_Impl(size_t nIndex)
+{
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+ if ( pList && nIndex < pList->size() )
+ {
+ ScRangePair & rData = (*pList)[nIndex];
+ return new ScLabelRangeObj( pDocShell, bColumn, rData.GetRange(0) );
+ }
+ }
+ return nullptr;
+}
+
+void SAL_CALL ScLabelRangesObj::addNew( const table::CellRangeAddress& aLabelArea,
+ const table::CellRangeAddress& aDataArea )
+{
+ SolarMutexGuard aGuard;
+ if (!pDocShell)
+ return;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pOldList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+ if (!pOldList)
+ return;
+
+ ScRangePairListRef xNewList(pOldList->Clone());
+
+ ScRange aLabelRange;
+ ScRange aDataRange;
+ ScUnoConversion::FillScRange( aLabelRange, aLabelArea );
+ ScUnoConversion::FillScRange( aDataRange, aDataArea );
+ xNewList->Join( ScRangePair( aLabelRange, aDataRange ) );
+
+ if (bColumn)
+ rDoc.GetColNameRangesRef() = xNewList;
+ else
+ rDoc.GetRowNameRangesRef() = xNewList;
+
+ rDoc.CompileColRowNameFormula();
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid );
+ pDocShell->SetDocumentModified();
+
+ //! Undo ?!?! (here and from dialog)
+}
+
+void SAL_CALL ScLabelRangesObj::removeByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pOldList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+
+ if ( pOldList && nIndex >= 0 && o3tl::make_unsigned(nIndex) < pOldList->size() )
+ {
+ ScRangePairListRef xNewList(pOldList->Clone());
+
+ xNewList->Remove( nIndex );
+
+ if (bColumn)
+ rDoc.GetColNameRangesRef() = xNewList;
+ else
+ rDoc.GetRowNameRangesRef() = xNewList;
+
+ rDoc.CompileColRowNameFormula();
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid );
+ pDocShell->SetDocumentModified();
+ bDone = true;
+
+ //! Undo ?!?! (here and from dialog)
+ }
+ }
+ if (!bDone)
+ throw uno::RuntimeException(); // no other exceptions specified
+}
+
+// container::XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScLabelRangesObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.LabelRangesEnumeration");
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScLabelRangesObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScRangePairList* pList = bColumn ? rDoc.GetColNameRanges() : rDoc.GetRowNameRanges();
+ if (pList)
+ return pList->size();
+ }
+ return 0;
+}
+
+uno::Any SAL_CALL ScLabelRangesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< sheet::XLabelRange > xRange(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if ( !xRange.is() )
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xRange);
+}
+
+uno::Type SAL_CALL ScLabelRangesObj::getElementType()
+{
+ return cppu::UnoType<sheet::XLabelRange>::get(); // must be suitable for getByIndex
+}
+
+sal_Bool SAL_CALL ScLabelRangesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/notesuno.cxx b/sc/source/ui/unoobj/notesuno.cxx
new file mode 100644
index 000000000..f745de7dd
--- /dev/null
+++ b/sc/source/ui/unoobj/notesuno.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 <notesuno.hxx>
+
+#include <vcl/svapp.hxx>
+#include <svl/hint.hxx>
+#include <editeng/unoipset.hxx>
+#include <editeng/unotext.hxx>
+#include <editeng/unoprnms.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdocapt.hxx>
+
+#include <postit.hxx>
+#include <cellsuno.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <editsrc.hxx>
+#include <miscuno.hxx>
+
+using namespace com::sun::star;
+
+static const SvxItemPropertySet* lcl_GetAnnotationPropertySet()
+{
+ static const SfxItemPropertyMapEntry aAnnotationPropertyMap_Impl[] =
+ {
+ SVX_UNOEDIT_CHAR_PROPERTIES,
+ SVX_UNOEDIT_FONT_PROPERTIES,
+ SVX_UNOEDIT_PARA_PROPERTIES,
+ SVX_UNOEDIT_NUMBERING_PROPERTY, // for completeness of service ParagraphProperties
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SvxItemPropertySet aAnnotationPropertySet_Impl( aAnnotationPropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool() );
+ return &aAnnotationPropertySet_Impl;
+}
+
+SC_SIMPLE_SERVICE_INFO( ScAnnotationObj, "ScAnnotationObj", "com.sun.star.sheet.CellAnnotation" )
+//SC_SIMPLE_SERVICE_INFO( ScAnnotationShapeObj, "ScAnnotationShapeObj", "com.sun.star.sheet.CellAnnotationShape" )
+
+ScAnnotationObj::ScAnnotationObj(ScDocShell* pDocSh, const ScAddress& rPos) :
+ pDocShell( pDocSh ),
+ aCellPos( rPos )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ // pUnoText is allocated on demand (GetUnoText)
+ // can't be aggregated because getString/setString is handled here
+}
+
+ScAnnotationObj::~ScAnnotationObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScAnnotationObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // became invalid
+ }
+}
+
+// XChild
+
+uno::Reference<uno::XInterface> SAL_CALL ScAnnotationObj::getParent()
+{
+ SolarMutexGuard aGuard;
+
+ // parent of note is the related cell
+ //! find and reset existing object ???
+
+ if (pDocShell)
+ return static_cast<cppu::OWeakObject*>(new ScCellObj( pDocShell, aCellPos ));
+
+ return nullptr;
+}
+
+void SAL_CALL ScAnnotationObj::setParent( const uno::Reference<uno::XInterface>& /* Parent */ )
+{
+ // ain't there
+ //! exception or what ??!
+}
+
+// XSimpleText
+
+uno::Reference<text::XTextCursor> SAL_CALL ScAnnotationObj::createTextCursor()
+{
+ SolarMutexGuard aGuard;
+ // notes does not need special treatment
+ return GetUnoText().createTextCursor();
+}
+
+uno::Reference<text::XTextCursor> SAL_CALL ScAnnotationObj::createTextCursorByRange(
+ const uno::Reference<text::XTextRange>& aTextPosition )
+{
+ SolarMutexGuard aGuard;
+ // notes does not need special treatment
+ return GetUnoText().createTextCursorByRange(aTextPosition);
+}
+
+OUString SAL_CALL ScAnnotationObj::getString()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getString();
+}
+
+void SAL_CALL ScAnnotationObj::setString( const OUString& aText )
+{
+ SolarMutexGuard aGuard;
+ GetUnoText().setString(aText);
+}
+
+void SAL_CALL ScAnnotationObj::insertString( const uno::Reference<text::XTextRange>& xRange,
+ const OUString& aString, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ GetUnoText().insertString( xRange, aString, bAbsorb );
+}
+
+void SAL_CALL ScAnnotationObj::insertControlCharacter( const uno::Reference<text::XTextRange>& xRange,
+ sal_Int16 nControlCharacter, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ GetUnoText().insertControlCharacter( xRange, nControlCharacter, bAbsorb );
+}
+
+uno::Reference<text::XText> SAL_CALL ScAnnotationObj::getText()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getText();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScAnnotationObj::getStart()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getStart();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScAnnotationObj::getEnd()
+{
+ SolarMutexGuard aGuard;
+ return GetUnoText().getEnd();
+}
+
+// XSheetAnnotation
+
+table::CellAddress SAL_CALL ScAnnotationObj::getPosition()
+{
+ SolarMutexGuard aGuard;
+ table::CellAddress aAdr;
+ aAdr.Sheet = aCellPos.Tab();
+ aAdr.Column = aCellPos.Col();
+ aAdr.Row = aCellPos.Row();
+ return aAdr;
+}
+
+OUString SAL_CALL ScAnnotationObj::getAuthor()
+{
+ SolarMutexGuard aGuard;
+ const ScPostIt* pNote = ImplGetNote();
+ return pNote ? pNote->GetAuthor() : OUString();
+}
+
+OUString SAL_CALL ScAnnotationObj::getDate()
+{
+ SolarMutexGuard aGuard;
+ const ScPostIt* pNote = ImplGetNote();
+ return pNote ? pNote->GetDate() : OUString();
+}
+
+sal_Bool SAL_CALL ScAnnotationObj::getIsVisible()
+{
+ SolarMutexGuard aGuard;
+ const ScPostIt* pNote = ImplGetNote();
+ return pNote && pNote->IsCaptionShown();
+}
+
+void SAL_CALL ScAnnotationObj::setIsVisible( sal_Bool bIsVisible )
+{
+ SolarMutexGuard aGuard;
+ // show/hide note with undo action
+ if( pDocShell )
+ pDocShell->GetDocFunc().ShowNote( aCellPos, bIsVisible );
+}
+
+// XSheetAnnotationShapeSupplier
+uno::Reference < drawing::XShape > SAL_CALL ScAnnotationObj::getAnnotationShape()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference < drawing::XShape > xShape;
+ if( const ScPostIt* pNote = ImplGetNote() )
+ if( SdrObject* pCaption = pNote->GetOrCreateCaption( aCellPos ) )
+ xShape.set( pCaption->getUnoShape(), uno::UNO_QUERY );
+ return xShape;
+}
+
+SvxUnoText& ScAnnotationObj::GetUnoText()
+{
+ if (!pUnoText.is())
+ {
+ ScAnnotationEditSource aEditSource( pDocShell, aCellPos );
+ pUnoText = new SvxUnoText( &aEditSource, lcl_GetAnnotationPropertySet(),
+ uno::Reference<text::XText>() );
+ }
+ return *pUnoText;
+}
+
+const ScPostIt* ScAnnotationObj::ImplGetNote() const
+{
+ return pDocShell ? pDocShell->GetDocument().GetNote(aCellPos) : nullptr;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/optuno.cxx b/sc/source/ui/unoobj/optuno.cxx
new file mode 100644
index 000000000..d652082d3
--- /dev/null
+++ b/sc/source/ui/unoobj/optuno.cxx
@@ -0,0 +1,222 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svl/itemprop.hxx>
+#include <vcl/svapp.hxx>
+
+#include <com/sun/star/util/Date.hpp>
+
+#include <optuno.hxx>
+#include <miscuno.hxx>
+#include <unonames.hxx>
+#include <docoptio.hxx>
+
+using namespace com::sun::star;
+
+const SfxItemPropertyMapEntry* ScDocOptionsHelper::GetPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aMap[] =
+ {
+ { SC_UNO_CALCASSHOWN, PROP_UNO_CALCASSHOWN , cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_DEFTABSTOP, PROP_UNO_DEFTABSTOP , cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_IGNORECASE, PROP_UNO_IGNORECASE , cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ITERENABLED, PROP_UNO_ITERENABLED , cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_ITERCOUNT, PROP_UNO_ITERCOUNT , cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_ITEREPSILON, PROP_UNO_ITEREPSILON , cppu::UnoType<double>::get(), 0, 0},
+ { SC_UNO_LOOKUPLABELS, PROP_UNO_LOOKUPLABELS, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_MATCHWHOLE, PROP_UNO_MATCHWHOLE , cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_NULLDATE, PROP_UNO_NULLDATE , cppu::UnoType<util::Date>::get(), 0, 0},
+ { SC_UNO_SPELLONLINE, PROP_UNO_SPELLONLINE , cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_STANDARDDEC, PROP_UNO_STANDARDDEC , cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_REGEXENABLED, PROP_UNO_REGEXENABLED, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_WILDCARDSENABLED, PROP_UNO_WILDCARDSENABLED, cppu::UnoType<bool>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aMap;
+}
+
+bool ScDocOptionsHelper::setPropertyValue( ScDocOptions& rOptions,
+ const SfxItemPropertyMap& rPropMap,
+ std::u16string_view aPropertyName, const uno::Any& aValue )
+{
+ //! use map (with new identifiers)
+
+ const SfxItemPropertyMapEntry* pEntry = rPropMap.getByName(aPropertyName );
+ if( !pEntry || !pEntry->nWID )
+ return false;
+ switch( pEntry->nWID )
+ {
+ case PROP_UNO_CALCASSHOWN :
+ rOptions.SetCalcAsShown( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_DEFTABSTOP :
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ rOptions.SetTabDistance( nIntVal );
+ }
+ break;
+ case PROP_UNO_IGNORECASE :
+ rOptions.SetIgnoreCase( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_ITERENABLED:
+ rOptions.SetIter( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_ITERCOUNT :
+ {
+ sal_Int32 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ rOptions.SetIterCount( static_cast<sal_uInt16>(nIntVal) );
+ }
+ break;
+ case PROP_UNO_ITEREPSILON :
+ {
+ double fDoubleVal = 0;
+ if ( aValue >>= fDoubleVal )
+ rOptions.SetIterEps( fDoubleVal );
+ }
+ break;
+ case PROP_UNO_LOOKUPLABELS :
+ rOptions.SetLookUpColRowNames( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_MATCHWHOLE :
+ rOptions.SetMatchWholeCell( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_NULLDATE:
+ {
+ util::Date aDate;
+ if ( aValue >>= aDate )
+ rOptions.SetDate( aDate.Day, aDate.Month, aDate.Year );
+ }
+ break;
+ case PROP_UNO_SPELLONLINE:
+ rOptions.SetAutoSpell( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_STANDARDDEC:
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ rOptions.SetStdPrecision( nIntVal );
+ }
+ break;
+ case PROP_UNO_REGEXENABLED:
+ rOptions.SetFormulaRegexEnabled( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ case PROP_UNO_WILDCARDSENABLED:
+ rOptions.SetFormulaWildcardsEnabled( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ break;
+ default:;
+ }
+ return true;
+}
+
+uno::Any ScDocOptionsHelper::getPropertyValue(
+ const ScDocOptions& rOptions,
+ const SfxItemPropertyMap& rPropMap,
+ std::u16string_view aPropertyName )
+{
+ uno::Any aRet;
+ const SfxItemPropertyMapEntry* pEntry = rPropMap.getByName( aPropertyName );
+ if( !pEntry || !pEntry->nWID )
+ return aRet;
+ switch( pEntry->nWID )
+ {
+ case PROP_UNO_CALCASSHOWN :
+ aRet <<= rOptions.IsCalcAsShown();
+ break;
+ case PROP_UNO_DEFTABSTOP :
+ aRet <<= static_cast<sal_Int16>( rOptions.GetTabDistance() );
+ break;
+ case PROP_UNO_IGNORECASE :
+ aRet <<= rOptions.IsIgnoreCase();
+ break;
+ case PROP_UNO_ITERENABLED:
+ aRet <<= rOptions.IsIter();
+ break;
+ case PROP_UNO_ITERCOUNT:
+ aRet <<= static_cast<sal_Int32>( rOptions.GetIterCount() );
+ break;
+ case PROP_UNO_ITEREPSILON:
+ aRet <<= rOptions.GetIterEps();
+ break;
+ case PROP_UNO_LOOKUPLABELS:
+ aRet <<= rOptions.IsLookUpColRowNames();
+ break;
+ case PROP_UNO_MATCHWHOLE:
+ aRet <<= rOptions.IsMatchWholeCell();
+ break;
+ case PROP_UNO_NULLDATE:
+ {
+ sal_uInt16 nD, nM;
+ sal_Int16 nY;
+ rOptions.GetDate( nD, nM, nY );
+ util::Date aDate( nD, nM, nY );
+ aRet <<= aDate;
+ }
+ break;
+ case PROP_UNO_SPELLONLINE:
+ aRet <<= rOptions.IsAutoSpell();
+ break;
+ case PROP_UNO_STANDARDDEC :
+ aRet <<= static_cast<sal_Int16>( rOptions.GetStdPrecision() );
+ break;
+ case PROP_UNO_REGEXENABLED:
+ aRet <<= rOptions.IsFormulaRegexEnabled();
+ break;
+ case PROP_UNO_WILDCARDSENABLED:
+ aRet <<= rOptions.IsFormulaWildcardsEnabled();
+ break;
+ default:;
+ }
+ return aRet;
+}
+
+ScDocOptionsObj::ScDocOptionsObj( const ScDocOptions& rOpt ) :
+ ScModelObj( nullptr ),
+ aOptions( rOpt )
+{
+}
+
+ScDocOptionsObj::~ScDocOptionsObj()
+{
+}
+
+void SAL_CALL ScDocOptionsObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ bool bDone = ScDocOptionsHelper::setPropertyValue( aOptions, GetPropertySet().getPropertyMap(), aPropertyName, aValue );
+
+ if (!bDone)
+ ScModelObj::setPropertyValue( aPropertyName, aValue );
+}
+
+uno::Any SAL_CALL ScDocOptionsObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aRet(ScDocOptionsHelper::getPropertyValue( aOptions, GetPropertySet().getPropertyMap(), aPropertyName ));
+ if ( !aRet.hasValue() )
+ aRet = ScModelObj::getPropertyValue( aPropertyName );
+
+ return aRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/pageuno.cxx b/sc/source/ui/unoobj/pageuno.cxx
new file mode 100644
index 000000000..796d16e12
--- /dev/null
+++ b/sc/source/ui/unoobj/pageuno.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <cppuhelper/supportsservice.hxx>
+#include <rtl/ustring.hxx>
+#include <pageuno.hxx>
+#include <shapeuno.hxx>
+
+using namespace ::com::sun::star;
+
+ScPageObj::ScPageObj( SdrPage* pPage ) :
+ SvxFmDrawPage( pPage )
+{
+}
+
+ScPageObj::~ScPageObj() noexcept
+{
+}
+
+uno::Reference<drawing::XShape > ScPageObj::CreateShape( SdrObject *pObj ) const
+{
+ uno::Reference<drawing::XShape> xShape(SvxFmDrawPage::CreateShape( pObj ));
+
+ new ScShapeObj( xShape ); // aggregates object and modifies xShape
+
+ return xShape;
+}
+
+OUString SAL_CALL ScPageObj::getImplementationName()
+{
+ return "ScPageObj";
+}
+
+sal_Bool SAL_CALL ScPageObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScPageObj::getSupportedServiceNames()
+{
+ return { "com.sun.star.sheet.SpreadsheetDrawPage" };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/scdetect.cxx b/sc/source/ui/unoobj/scdetect.cxx
new file mode 100644
index 000000000..e5fc5848e
--- /dev/null
+++ b/sc/source/ui/unoobj/scdetect.cxx
@@ -0,0 +1,353 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "scdetect.hxx"
+
+#include <sal/macros.h>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <unotools/mediadescriptor.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/fcontnr.hxx>
+
+using namespace ::com::sun::star;
+using utl::MediaDescriptor;
+
+namespace {
+
+// table with search pattern
+// meaning of the sequences
+// 0x00??: the exact byte 0x?? must be at that place
+// 0x0100: read over a byte (don't care)
+// 0x02nn: a byte of 0xnn variations follows
+// 0x8000: recognition finished
+
+#define M_DC 0x0100
+#define M_ALT(CNT) (0x0200+(CNT))
+#define M_END 0x8000
+
+const sal_uInt16 pLotus[] = // Lotus 1/1A/2
+ { 0x0000, 0x0000, 0x0002, 0x0000,
+ M_ALT(2), 0x0004, 0x0006,
+ 0x0004, M_END };
+
+const sal_uInt16 pLotusNew[] = // Lotus >= 9.7
+ { 0x0000, 0x0000, M_DC, 0x0000, // Rec# + Len (0x1a)
+ M_ALT(3), 0x0003, 0x0004, 0x0005, // File Revision Code 97->ME
+ 0x0010, 0x0004, 0x0000, 0x0000,
+ M_END };
+
+const sal_uInt16 pLotus2[] = // Lotus >3
+ { 0x0000, 0x0000, 0x001A, 0x0000, // Rec# + Len (26)
+ M_ALT(2), 0x0000, 0x0002, // File Revision Code
+ 0x0010,
+ 0x0004, 0x0000, // File Revision Subcode
+ M_END };
+
+const sal_uInt16 pQPro[] =
+ { 0x0000, 0x0000, 0x0002, 0x0000,
+ M_ALT(4), 0x0001, 0x0002, // WB1, WB2
+ 0x0006, 0x0007, // QPro 6/7 (?)
+ 0x0010,
+ M_END };
+
+const sal_uInt16 pDIF1[] = // DIF with CR-LF
+ {
+ 'T', 'A', 'B', 'L', 'E',
+ M_DC, M_DC,
+ '0', ',', '1',
+ M_DC, M_DC,
+ '\"',
+ M_END };
+
+const sal_uInt16 pDIF2[] = // DIF with CR or LF
+ {
+ 'T', 'A', 'B', 'L', 'E',
+ M_DC,
+ '0', ',', '1',
+ M_DC,
+ '\"',
+ M_END };
+
+const sal_uInt16 pSylk[] = // Sylk
+ {
+ 'I', 'D', ';',
+ M_ALT(3), 'P', 'N', 'E', // 'P' plus undocumented Excel extensions 'N' and 'E'
+ M_END };
+
+bool detectThisFormat(SvStream& rStr, const sal_uInt16* pSearch)
+{
+ sal_uInt8 nByte;
+ rStr.Seek( 0 ); // in the beginning everything was bad...
+ rStr.ReadUChar( nByte );
+ bool bSync = true;
+ while( !rStr.eof() && bSync )
+ {
+ sal_uInt16 nMuster = *pSearch;
+
+ if( nMuster < 0x0100 )
+ { // compare bytes
+ if( static_cast<sal_uInt8>(nMuster) != nByte )
+ bSync = false;
+ }
+ else if( nMuster & M_DC )
+ { // don't care
+ }
+ else if( nMuster & M_ALT(0) )
+ { // alternative Bytes
+ sal_uInt8 nCntAlt = static_cast<sal_uInt8>(nMuster);
+ bSync = false; // first unsynchron
+ while( nCntAlt > 0 )
+ {
+ pSearch++;
+ if( static_cast<sal_uInt8>(*pSearch) == nByte )
+ bSync = true; // only now synchronization
+ nCntAlt--;
+ }
+ }
+ else if( nMuster & M_END )
+ { // Format detected
+ return true;
+ }
+
+ pSearch++;
+ rStr.ReadUChar( nByte );
+ }
+
+ return false;
+}
+
+}
+
+ScFilterDetect::ScFilterDetect()
+{
+}
+
+ScFilterDetect::~ScFilterDetect()
+{
+}
+
+#if 0
+// This method is no longer used, but I do want to keep this for now to see
+// if we could transfer this check to the now centralized ascii detection
+// code in the filter module.
+static sal_Bool lcl_MayBeAscii( SvStream& rStream )
+{
+ // ASCII/CSV is considered possible if there are no null bytes, or a Byte
+ // Order Mark is present, or if, for Unicode UCS2/UTF-16, all null bytes
+ // are on either even or uneven byte positions.
+
+ rStream.Seek(STREAM_SEEK_TO_BEGIN);
+
+ const size_t nBufSize = 2048;
+ sal_uInt16 aBuffer[ nBufSize ];
+ sal_uInt8* pByte = reinterpret_cast<sal_uInt8*>(aBuffer);
+ sal_uLong nBytesRead = rStream.Read( pByte, nBufSize*2);
+
+ if ( nBytesRead >= 2 && (aBuffer[0] == 0xfffe || aBuffer[0] == 0xfeff) )
+ {
+ // Unicode BOM file may contain null bytes.
+ return sal_True;
+ }
+
+ const sal_uInt16* p = aBuffer;
+ sal_uInt16 nMask = 0xffff;
+ nBytesRead /= 2;
+ while( nBytesRead-- && nMask )
+ {
+ sal_uInt16 nVal = *p++ & nMask;
+ if (!(nVal & 0x00ff))
+ nMask &= 0xff00;
+ if (!(nVal & 0xff00))
+ nMask &= 0x00ff;
+ }
+
+ return nMask != 0;
+}
+#endif
+
+static bool lcl_MayBeDBase( SvStream& rStream )
+{
+ // Look for dbf marker, see connectivity/source/inc/dbase/DTable.hxx
+ // DBFType for values.
+ const sal_uInt8 nValidMarks[] = {
+ 0x03, 0x04, 0x05, 0x30, 0x31, 0x43, 0xB3, 0x83, 0x8b, 0x8e, 0xf5 };
+ sal_uInt8 nMark;
+ rStream.Seek(STREAM_SEEK_TO_BEGIN);
+ rStream.ReadUChar( nMark );
+ bool bValidMark = false;
+ for (size_t i=0; i < SAL_N_ELEMENTS(nValidMarks) && !bValidMark; ++i)
+ {
+ if (nValidMarks[i] == nMark)
+ bValidMark = true;
+ }
+ if ( !bValidMark )
+ return false;
+
+ const size_t nHeaderBlockSize = 32;
+ // Empty dbf is >= 32*2+1 bytes in size.
+ const size_t nEmptyDbf = nHeaderBlockSize * 2 + 1;
+
+ sal_uInt64 nSize = rStream.TellEnd();
+ if ( nSize < nEmptyDbf )
+ return false;
+
+ // count of records at 4
+ rStream.Seek(4);
+ sal_uInt32 nRecords(0);
+ rStream.ReadUInt32(nRecords);
+
+ // length of header starts at 8
+ rStream.Seek(8);
+ sal_uInt16 nHeaderLen;
+ rStream.ReadUInt16( nHeaderLen );
+
+ // size of record at 10
+ sal_uInt16 nRecordSize(0);
+ rStream.ReadUInt16(nRecordSize);
+
+ if ( nHeaderLen < nEmptyDbf || nSize < nHeaderLen )
+ return false;
+
+ // see DTable.cxx ODbaseTable::readHeader()
+ if (0 == nRecordSize)
+ return false;
+
+ // see DTable.cxx ODbaseTable::construct() line 546
+ if (0 == nRecords)
+ {
+ nRecords = (nSize - nHeaderLen) / nRecordSize;
+ }
+
+ // tdf#84834 sanity check of size
+ // tdf#106423: a dbf file can have 0 record, so no need to check nRecords
+ if (nSize < nHeaderLen + nRecords * sal_uInt64(nRecordSize))
+ return false;
+
+ // Last byte of header must be 0x0d, this is how it's specified.
+ // #i9581#,#i26407# but some applications don't follow the specification
+ // and pad the header with one byte 0x00 to reach an
+ // even boundary. Some (#i88577# ) even pad more or pad using a 0x1a ^Z
+ // control character (#i8857#). This results in:
+ // Last byte of header must be 0x0d on 32 bytes boundary.
+ sal_uInt16 nBlocks = (nHeaderLen - 1) / nHeaderBlockSize;
+ sal_uInt8 nEndFlag = 0;
+ while ( nBlocks > 1 && nEndFlag != 0x0d ) {
+ rStream.Seek( nBlocks-- * nHeaderBlockSize );
+ rStream.ReadUChar( nEndFlag );
+ }
+
+ return ( 0x0d == nEndFlag );
+}
+
+OUString SAL_CALL ScFilterDetect::detect( uno::Sequence<beans::PropertyValue>& lDescriptor )
+{
+ MediaDescriptor aMediaDesc( lDescriptor );
+ OUString aTypeName = aMediaDesc.getUnpackedValueOrDefault( MediaDescriptor::PROP_TYPENAME, OUString() );
+ uno::Reference< io::XInputStream > xStream ( aMediaDesc[MediaDescriptor::PROP_INPUTSTREAM], uno::UNO_QUERY );
+ if ( !xStream.is() )
+ return OUString();
+
+ SfxMedium aMedium;
+ aMedium.UseInteractionHandler( false );
+ aMedium.setStreamToLoadFrom( xStream, true );
+
+ SvStream* pStream = aMedium.GetInStream();
+ if ( !pStream || pStream->GetError() )
+ // No stream, no detection.
+ return OUString();
+
+ const char* pSearchFilterName = nullptr;
+ if (aTypeName == "calc_Lotus")
+ {
+ if (!detectThisFormat(*pStream, pLotus) && !detectThisFormat(*pStream, pLotusNew) && !detectThisFormat(*pStream, pLotus2))
+ return OUString();
+
+ pSearchFilterName = "Lotus";
+ }
+ else if (aTypeName == "calc_QPro")
+ {
+ if (!detectThisFormat(*pStream, pQPro))
+ return OUString();
+
+ pSearchFilterName = "Quattro Pro 6.0";
+ }
+ else if (aTypeName == "calc_SYLK")
+ {
+ if (!detectThisFormat(*pStream, pSylk))
+ return OUString();
+
+ pSearchFilterName = "SYLK";
+ }
+ else if (aTypeName == "calc_DIF")
+ {
+ if (!detectThisFormat(*pStream, pDIF1) && !detectThisFormat(*pStream, pDIF2))
+ return OUString();
+
+ pSearchFilterName = "DIF";
+ }
+ else if (aTypeName == "calc_dBase")
+ {
+ if (!lcl_MayBeDBase(*pStream))
+ return OUString();
+
+ pSearchFilterName = "dBase";
+ }
+ else
+ return OUString();
+
+ SfxFilterMatcher aMatcher("scalc");
+ std::shared_ptr<const SfxFilter> pFilter = aMatcher.GetFilter4FilterName(OUString::createFromAscii(pSearchFilterName));
+
+ if (!pFilter)
+ return OUString();
+
+ aMediaDesc[MediaDescriptor::PROP_FILTERNAME] <<= pFilter->GetName();
+ aMediaDesc >> lDescriptor;
+ return aTypeName;
+}
+
+OUString SAL_CALL ScFilterDetect::getImplementationName()
+{
+ return "com.sun.star.comp.calc.FormatDetector";
+}
+
+sal_Bool ScFilterDetect::supportsService( const OUString& sServiceName )
+{
+ return cppu::supportsService(this, sServiceName);
+}
+
+css::uno::Sequence<OUString> ScFilterDetect::getSupportedServiceNames()
+{
+ return { "com.sun.star.frame.ExtendedTypeDetection" };
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_calc_FormatDetector_get_implementation(css::uno::XComponentContext* /*context*/,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ScFilterDetect);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/scdetect.hxx b/sc/source/ui/unoobj/scdetect.hxx
new file mode 100644
index 000000000..697bd8d58
--- /dev/null
+++ b/sc/source/ui/unoobj/scdetect.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 <com/sun/star/document/XExtendedFilterDetection.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <rtl/ustring.hxx>
+
+namespace com::sun::star {
+ namespace beans { struct PropertyValue; }
+}
+
+class ScFilterDetect : public ::cppu::WeakImplHelper< css::document::XExtendedFilterDetection, css::lang::XServiceInfo >
+{
+public:
+ explicit ScFilterDetect();
+ virtual ~ScFilterDetect() 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/sc/source/ui/unoobj/servuno.cxx b/sc/source/ui/unoobj/servuno.cxx
new file mode 100644
index 000000000..f2713d26b
--- /dev/null
+++ b/sc/source/ui/unoobj/servuno.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 <memory>
+#include <config_features.h>
+
+#include <sal/macros.h>
+#include <svtools/unoimap.hxx>
+#include <svx/unofill.hxx>
+#include <vcl/svapp.hxx>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/text/textfield/Type.hpp>
+
+#include <editsrc.hxx>
+#include <servuno.hxx>
+#include <unonames.hxx>
+#include <appluno.hxx>
+#include <cellsuno.hxx>
+#include <fielduno.hxx>
+#include <styleuno.hxx>
+#include <afmtuno.hxx>
+#include <defltuno.hxx>
+#include <drdefuno.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <confuno.hxx>
+#include <shapeuno.hxx>
+#include "cellvaluebinding.hxx"
+#include "celllistsource.hxx"
+#include <addruno.hxx>
+#include <chart2uno.hxx>
+#include <tokenuno.hxx>
+#include <PivotTableDataProvider.hxx>
+
+// Support creation of GraphicStorageHandler and EmbeddedObjectResolver
+#include <svx/xmleohlp.hxx>
+#include <svx/xmlgrhlp.hxx>
+#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
+#include <com/sun/star/document/XCodeNameQuery.hpp>
+#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <svx/unomod.hxx>
+#include <vbahelper/vbaaccesshelper.hxx>
+
+#include <comphelper/processfactory.hxx>
+#include <basic/basmgr.hxx>
+#include <sfx2/app.hxx>
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/script/vba/XVBACompatibility.hpp>
+
+using namespace ::com::sun::star;
+
+#if HAVE_FEATURE_SCRIPTING
+
+static bool isInVBAMode( ScDocShell& rDocSh )
+{
+ uno::Reference<script::XLibraryContainer> xLibContainer = rDocSh.GetBasicContainer();
+ uno::Reference<script::vba::XVBACompatibility> xVBACompat( xLibContainer, uno::UNO_QUERY );
+ if ( xVBACompat.is() )
+ return xVBACompat->getVBACompatibilityMode();
+ return false;
+}
+
+#endif
+
+namespace {
+
+#if HAVE_FEATURE_SCRIPTING
+class ScVbaObjectForCodeNameProvider : public ::cppu::WeakImplHelper< container::XNameAccess >
+{
+ uno::Any maWorkbook;
+ uno::Any maCachedObject;
+ ScDocShell* mpDocShell;
+public:
+ explicit ScVbaObjectForCodeNameProvider( ScDocShell* pDocShell ) : mpDocShell( pDocShell )
+ {
+ uno::Sequence< uno::Any > aArgs{
+ // access the application object ( parent for workbook )
+ uno::Any(ooo::vba::createVBAUnoAPIServiceWithArgs( mpDocShell, "ooo.vba.Application", {} )),
+ uno::Any(mpDocShell->GetModel())
+ };
+ maWorkbook <<= ooo::vba::createVBAUnoAPIServiceWithArgs( mpDocShell, "ooo.vba.excel.Workbook", aArgs );
+ }
+
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
+ {
+ SolarMutexGuard aGuard;
+ maCachedObject = uno::Any(); // clear cached object
+
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ // aName is generated from the stream name which can be different ( case-wise )
+ // from the code name
+ if( aName.equalsIgnoreAsciiCase( rDoc.GetCodeName() ) )
+ maCachedObject = maWorkbook;
+ else
+ {
+ OUString sCodeName;
+ SCTAB nCount = rDoc.GetTableCount();
+ for( SCTAB i = 0; i < nCount; i++ )
+ {
+ rDoc.GetCodeName( i, sCodeName );
+ // aName is generated from the stream name which can be different ( case-wise )
+ // from the code name
+ if( sCodeName.equalsIgnoreAsciiCase( aName ) )
+ {
+ OUString sSheetName;
+ if( rDoc.GetName( i, sSheetName ) )
+ {
+ uno::Reference< frame::XModel > xModel( mpDocShell->GetModel() );
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( xModel, uno::UNO_QUERY_THROW );
+ uno::Reference<sheet::XSpreadsheets > xSheets( xSpreadDoc->getSheets(), uno::UNO_SET_THROW );
+ uno::Reference< container::XIndexAccess > xIndexAccess( xSheets, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheet > xSheet( xIndexAccess->getByIndex( i ), uno::UNO_QUERY_THROW );
+ uno::Sequence< uno::Any > aArgs{ maWorkbook, uno::Any(xModel), uno::Any(sSheetName) };
+ // use the convenience function
+ maCachedObject <<= ooo::vba::createVBAUnoAPIServiceWithArgs( mpDocShell, "ooo.vba.excel.Worksheet", aArgs );
+ break;
+ }
+ }
+ }
+ }
+ return maCachedObject.hasValue();
+
+ }
+ css::uno::Any SAL_CALL getByName( const OUString& aName ) override
+ {
+ SolarMutexGuard aGuard;
+ if ( !hasByName( aName ) )
+ throw css::container::NoSuchElementException();
+ return maCachedObject;
+ }
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override
+ {
+ SolarMutexGuard aGuard;
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ SCTAB nCount = rDoc.GetTableCount();
+ uno::Sequence< OUString > aNames( nCount + 1 );
+ auto pNames = aNames.getArray();
+ SCTAB index = 0;
+ OUString sCodeName;
+ for( ; index < nCount; ++index )
+ {
+ rDoc.GetCodeName( index, sCodeName );
+ pNames[ index ] = sCodeName;
+ }
+ pNames[ index ] = rDoc.GetCodeName();
+ return aNames;
+ }
+ // XElemenAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override { return uno::Type(); }
+ virtual sal_Bool SAL_CALL hasElements( ) override { return true; }
+
+};
+
+class ScVbaCodeNameProvider : public ::cppu::WeakImplHelper< document::XCodeNameQuery >
+{
+ ScDocShell& mrDocShell;
+public:
+ explicit ScVbaCodeNameProvider( ScDocShell& rDocShell ) : mrDocShell(rDocShell) {}
+ // XCodeNameQuery
+ OUString SAL_CALL getCodeNameForObject( const uno::Reference< uno::XInterface >& xIf ) override
+ {
+ SolarMutexGuard aGuard;
+ OUString sCodeName;
+
+ // need to find the page ( and index ) for this control
+ uno::Reference< drawing::XDrawPagesSupplier > xSupplier( mrDocShell.GetModel(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xIndex( xSupplier->getDrawPages(), uno::UNO_QUERY_THROW );
+ sal_Int32 nLen = xIndex->getCount();
+ bool bMatched = false;
+ for ( sal_Int32 index = 0; index < nLen; ++index )
+ {
+ try
+ {
+ uno::Reference< form::XFormsSupplier > xFormSupplier( xIndex->getByIndex( index ), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xFormIndex( xFormSupplier->getForms(), uno::UNO_QUERY_THROW );
+ // get the www-standard container
+ uno::Reference< container::XIndexAccess > xFormControls( xFormIndex->getByIndex(0), uno::UNO_QUERY_THROW );
+ sal_Int32 nCntrls = xFormControls->getCount();
+ for( sal_Int32 cIndex = 0; cIndex < nCntrls; ++cIndex )
+ {
+ uno::Reference< uno::XInterface > xControl( xFormControls->getByIndex( cIndex ), uno::UNO_QUERY_THROW );
+ bMatched = ( xControl == xIf );
+ if ( bMatched )
+ {
+ OUString sName;
+ mrDocShell.GetDocument().GetCodeName( static_cast<SCTAB>( index ), sName );
+ sCodeName = sName;
+ }
+ }
+ }
+ catch( uno::Exception& ) {}
+ if ( bMatched )
+ break;
+ }
+ // Probably should throw here ( if !bMatched )
+ return sCodeName;
+ }
+
+ OUString SAL_CALL getCodeNameForContainer( const uno::Reference<uno::XInterface>& xContainer ) override
+ {
+ SolarMutexGuard aGuard;
+ uno::Reference<drawing::XDrawPagesSupplier> xSupplier(mrDocShell.GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xIndex(xSupplier->getDrawPages(), uno::UNO_QUERY_THROW);
+
+ for (sal_Int32 i = 0, n = xIndex->getCount(); i < n; ++i)
+ {
+ try
+ {
+ uno::Reference<form::XFormsSupplier> xFormSupplier(xIndex->getByIndex(i), uno::UNO_QUERY_THROW);
+ uno::Reference<container::XIndexAccess> xFormIndex(xFormSupplier->getForms(), uno::UNO_QUERY_THROW);
+ // get the www-standard container
+ uno::Reference<container::XIndexAccess> xFormControls(xFormIndex->getByIndex(0), uno::UNO_QUERY_THROW);
+ if (xFormControls == xContainer)
+ {
+ OUString aName;
+ if (mrDocShell.GetDocument().GetCodeName(static_cast<SCTAB>(i), aName))
+ return aName;
+ }
+ }
+ catch( uno::Exception& ) {}
+ }
+ return OUString();
+ }
+};
+
+#endif
+
+using Type = ScServiceProvider::Type;
+
+struct ProvNamesId_Type
+{
+ OUString pName;
+ ScServiceProvider::Type nType;
+};
+
+const ProvNamesId_Type aProvNamesId[] =
+{
+ { "com.sun.star.sheet.Spreadsheet", Type::SHEET },
+ { "com.sun.star.text.TextField.URL", Type::URLFIELD },
+ { "com.sun.star.text.TextField.PageNumber", Type::PAGEFIELD },
+ { "com.sun.star.text.TextField.PageCount", Type::PAGESFIELD },
+ { "com.sun.star.text.TextField.Date", Type::DATEFIELD },
+ { "com.sun.star.text.TextField.Time", Type::TIMEFIELD },
+ { "com.sun.star.text.TextField.DateTime", Type::EXT_TIMEFIELD },
+ { "com.sun.star.text.TextField.DocInfo.Title", Type::TITLEFIELD },
+ { "com.sun.star.text.TextField.FileName", Type::FILEFIELD },
+ { "com.sun.star.text.TextField.SheetName", Type::SHEETFIELD },
+ { "com.sun.star.style.CellStyle", Type::CELLSTYLE },
+ { "com.sun.star.style.PageStyle", Type::PAGESTYLE },
+ { "com.sun.star.sheet.TableAutoFormat", Type::AUTOFORMAT },
+ { "com.sun.star.sheet.TableAutoFormats", Type::AUTOFORMATS },
+ { "com.sun.star.sheet.SheetCellRanges", Type::CELLRANGES },
+ { "com.sun.star.sheet.FunctionDescriptions", Type::FUNCTIONDESCRIPTIONS },
+ { "com.sun.star.sheet.GlobalSheetSettings", Type::GLOBALSHEETSETTINGS },
+ { "com.sun.star.sheet.RecentFunctions", Type::RECENTFUNCTIONS },
+ { "com.sun.star.drawing.GradientTable", Type::GRADTAB },
+ { "com.sun.star.drawing.HatchTable", Type::HATCHTAB },
+ { "com.sun.star.drawing.BitmapTable", Type::BITMAPTAB },
+ { "com.sun.star.drawing.TransparencyGradientTable", Type::TRGRADTAB },
+ { "com.sun.star.drawing.MarkerTable", Type::MARKERTAB },
+ { "com.sun.star.drawing.DashTable", Type::DASHTAB },
+ { "com.sun.star.text.NumberingRules", Type::NUMRULES },
+ { "com.sun.star.sheet.Defaults", Type::DOCDEFLTS },
+ { "com.sun.star.drawing.Defaults", Type::DRAWDEFLTS },
+ { "com.sun.star.comp.SpreadsheetSettings", Type::DOCSPRSETT },
+ { "com.sun.star.document.Settings", Type::DOCCONF },
+ { "com.sun.star.image.ImageMapRectangleObject", Type::IMAP_RECT },
+ { "com.sun.star.image.ImageMapCircleObject", Type::IMAP_CIRC },
+ { "com.sun.star.image.ImageMapPolygonObject", Type::IMAP_POLY },
+
+ // Support creation of GraphicStorageHandler and EmbeddedObjectResolver
+ { "com.sun.star.document.ExportGraphicStorageHandler", Type::EXPORT_GRAPHIC_STORAGE_HANDLER },
+ { "com.sun.star.document.ImportGraphicStorageHandler", Type::IMPORT_GRAPHIC_STORAGE_HANDLER },
+ { "com.sun.star.document.ExportEmbeddedObjectResolver", Type::EXPORT_EOR },
+ { "com.sun.star.document.ImportEmbeddedObjectResolver", Type::IMPORT_EOR },
+
+ { SC_SERVICENAME_VALBIND, Type::VALBIND },
+ { SC_SERVICENAME_LISTCELLBIND, Type::LISTCELLBIND },
+ { SC_SERVICENAME_LISTSOURCE, Type::LISTSOURCE },
+ { SC_SERVICENAME_CELLADDRESS, Type::CELLADDRESS },
+ { SC_SERVICENAME_RANGEADDRESS, Type::RANGEADDRESS },
+
+ { "com.sun.star.sheet.DocumentSettings",Type::SHEETDOCSET },
+
+ { SC_SERVICENAME_CHDATAPROV, Type::CHDATAPROV },
+ { SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER, Type::CHART_PIVOTTABLE_DATAPROVIDER },
+ { SC_SERVICENAME_FORMULAPARS, Type::FORMULAPARS },
+ { SC_SERVICENAME_OPCODEMAPPER, Type::OPCODEMAPPER },
+ { "ooo.vba.VBAObjectModuleObjectProvider", Type::VBAOBJECTPROVIDER },
+ { "ooo.vba.VBACodeNameProvider", Type::VBACODENAMEPROVIDER },
+ { "ooo.vba.VBAGlobals", Type::VBAGLOBALS },
+
+ // case-correct versions of the service names (#i102468#)
+ { "com.sun.star.text.textfield.URL", Type::URLFIELD },
+ { "com.sun.star.text.textfield.PageNumber", Type::PAGEFIELD },
+ { "com.sun.star.text.textfield.PageCount", Type::PAGESFIELD },
+ { "com.sun.star.text.textfield.Date", Type::DATEFIELD },
+ { "com.sun.star.text.textfield.Time", Type::TIMEFIELD },
+ { "com.sun.star.text.textfield.DateTime", Type::EXT_TIMEFIELD },
+ { "com.sun.star.text.textfield.docinfo.Title", Type::TITLEFIELD },
+ { "com.sun.star.text.textfield.FileName", Type::FILEFIELD },
+ { "com.sun.star.text.textfield.SheetName", Type::SHEETFIELD },
+ { "ooo.vba.VBAGlobals", Type::VBAGLOBALS },
+};
+
+// old service names that were in 567 still work in createInstance,
+// in case some macro is still using them
+const ProvNamesId_Type aOldNames[] =
+{
+ { "stardiv.one.text.TextField.URL", Type::URLFIELD },
+ { "stardiv.one.text.TextField.PageNumber", Type::PAGEFIELD },
+ { "stardiv.one.text.TextField.PageCount", Type::PAGESFIELD },
+ { "stardiv.one.text.TextField.Date", Type::DATEFIELD },
+ { "stardiv.one.text.TextField.Time", Type::TIMEFIELD },
+ { "stardiv.one.text.TextField.DocumentTitle", Type::TITLEFIELD },
+ { "stardiv.one.text.TextField.FileName", Type::FILEFIELD },
+ { "stardiv.one.text.TextField.SheetName", Type::SHEETFIELD },
+ { "stardiv.one.style.CellStyle", Type::CELLSTYLE },
+ { "stardiv.one.style.PageStyle", Type::PAGESTYLE },
+};
+
+sal_Int32 getFieldType(ScServiceProvider::Type nOldType)
+{
+ switch (nOldType)
+ {
+ case Type::URLFIELD:
+ return text::textfield::Type::URL;
+ case Type::PAGEFIELD:
+ return text::textfield::Type::PAGE;
+ case Type::PAGESFIELD:
+ return text::textfield::Type::PAGES;
+ case Type::DATEFIELD:
+ return text::textfield::Type::DATE;
+ case Type::TIMEFIELD:
+ return text::textfield::Type::TIME;
+ case Type::EXT_TIMEFIELD:
+ return text::textfield::Type::EXTENDED_TIME;
+ case Type::TITLEFIELD:
+ return text::textfield::Type::DOCINFO_TITLE;
+ case Type::FILEFIELD:
+ return text::textfield::Type::EXTENDED_FILE;
+ case Type::SHEETFIELD:
+ return text::textfield::Type::TABLE;
+ default:
+ ;
+ }
+
+ return text::textfield::Type::URL; // default to URL for no reason whatsoever.
+}
+
+} // namespace
+
+
+ScServiceProvider::Type ScServiceProvider::GetProviderType(std::u16string_view rServiceName)
+{
+ if (!rServiceName.empty())
+ {
+ for (const ProvNamesId_Type & i : aProvNamesId)
+ {
+ if (rServiceName == i.pName)
+ {
+ return i.nType;
+ }
+ }
+
+ for (const ProvNamesId_Type & rOldName : aOldNames)
+ {
+ if (rServiceName == rOldName.pName)
+ {
+ OSL_FAIL("old service name used");
+ return rOldName.nType;
+ }
+ }
+ }
+ return Type::INVALID;
+}
+
+uno::Reference<uno::XInterface> ScServiceProvider::MakeInstance(
+ Type nType, ScDocShell* pDocShell )
+{
+ uno::Reference<uno::XInterface> xRet;
+
+ switch (nType)
+ {
+ case Type::SHEET:
+ // not inserted yet - DocShell=Null
+ xRet.set(static_cast<sheet::XSpreadsheet*>(new ScTableSheetObj(nullptr,0)));
+ break;
+ case Type::URLFIELD:
+ case Type::PAGEFIELD:
+ case Type::PAGESFIELD:
+ case Type::DATEFIELD:
+ case Type::TIMEFIELD:
+ case Type::EXT_TIMEFIELD:
+ case Type::TITLEFIELD:
+ case Type::FILEFIELD:
+ case Type::SHEETFIELD:
+ {
+ uno::Reference<text::XTextRange> xNullContent;
+ xRet.set(static_cast<text::XTextField*>(
+ new ScEditFieldObj(xNullContent, nullptr, getFieldType(nType), ESelection())));
+ } break;
+ case Type::CELLSTYLE:
+ xRet.set(static_cast<style::XStyle*>(new ScStyleObj( nullptr, SfxStyleFamily::Para, OUString() )));
+ break;
+ case Type::PAGESTYLE:
+ xRet.set(static_cast<style::XStyle*>(new ScStyleObj( nullptr, SfxStyleFamily::Page, OUString() )));
+ break;
+ case Type::AUTOFORMAT:
+ xRet.set(static_cast<container::XIndexAccess*>(new ScAutoFormatObj( SC_AFMTOBJ_INVALID )));
+ break;
+ case Type::AUTOFORMATS:
+ xRet.set(static_cast<container::XIndexAccess*>(new ScAutoFormatsObj()));
+ break;
+ case Type::CELLRANGES:
+ // isn't inserted, rather filled
+ // -> DocShell must be set, but empty ranges
+ if (pDocShell)
+ xRet.set(static_cast<sheet::XSheetCellRanges*>(new ScCellRangesObj( pDocShell, ScRangeList() )));
+ break;
+ case Type::FUNCTIONDESCRIPTIONS:
+ xRet.set(static_cast<sheet::XFunctionDescriptions*>(new ScFunctionListObj()));
+ break;
+ case Type::GLOBALSHEETSETTINGS:
+ xRet.set(static_cast<sheet::XGlobalSheetSettings*>(new ScSpreadsheetSettings()));
+ break;
+ case Type::RECENTFUNCTIONS:
+ xRet.set(static_cast<sheet::XRecentFunctions*>(new ScRecentFunctionsObj()));
+ break;
+ case Type::DOCDEFLTS:
+ if (pDocShell)
+ xRet.set(static_cast<beans::XPropertySet*>(new ScDocDefaultsObj( pDocShell )));
+ break;
+ case Type::DRAWDEFLTS:
+ if (pDocShell)
+ xRet.set(static_cast<beans::XPropertySet*>(new ScDrawDefaultsObj( pDocShell )));
+ break;
+
+ // Drawing layer tables are not in SvxUnoDrawMSFactory,
+ // because SvxUnoDrawMSFactory doesn't have a SdrModel pointer.
+ // Drawing layer is always allocated if not there (MakeDrawLayer).
+
+ case Type::GRADTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoGradientTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::HATCHTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoHatchTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::BITMAPTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoBitmapTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::TRGRADTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoTransGradientTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::MARKERTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoMarkerTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::DASHTAB:
+ if (pDocShell)
+ xRet.set(SvxUnoDashTable_createInstance( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::NUMRULES:
+ if (pDocShell)
+ xRet.set(SvxCreateNumRule( pDocShell->MakeDrawLayer() ));
+ break;
+ case Type::DOCSPRSETT:
+ case Type::SHEETDOCSET:
+ case Type::DOCCONF:
+ if (pDocShell)
+ xRet.set(static_cast<beans::XPropertySet*>(new ScDocumentConfiguration(pDocShell)));
+ break;
+ case Type::IMAP_RECT:
+ xRet.set(SvUnoImageMapRectangleObject_createInstance( ScShapeObj::GetSupportedMacroItems() ));
+ break;
+ case Type::IMAP_CIRC:
+ xRet.set(SvUnoImageMapCircleObject_createInstance( ScShapeObj::GetSupportedMacroItems() ));
+ break;
+ case Type::IMAP_POLY:
+ xRet.set(SvUnoImageMapPolygonObject_createInstance( ScShapeObj::GetSupportedMacroItems() ));
+ break;
+
+ // Support creation of GraphicStorageHandler and EmbeddedObjectResolver
+ case Type::EXPORT_GRAPHIC_STORAGE_HANDLER:
+ xRet.set(static_cast<cppu::OWeakObject *>(new SvXMLGraphicHelper( SvXMLGraphicHelperMode::Write )));
+ break;
+ case Type::IMPORT_GRAPHIC_STORAGE_HANDLER:
+ xRet.set(static_cast<cppu::OWeakObject *>(new SvXMLGraphicHelper( SvXMLGraphicHelperMode::Read )));
+ break;
+ case Type::EXPORT_EOR:
+ if (pDocShell)
+ xRet.set(static_cast<cppu::OWeakObject *>(new SvXMLEmbeddedObjectHelper( *pDocShell, SvXMLEmbeddedObjectHelperMode::Write )));
+ break;
+ case Type::IMPORT_EOR:
+ if (pDocShell)
+ xRet.set(static_cast<cppu::OWeakObject *>(new SvXMLEmbeddedObjectHelper( *pDocShell, SvXMLEmbeddedObjectHelperMode::Read )));
+ break;
+ case Type::VALBIND:
+ case Type::LISTCELLBIND:
+ if (pDocShell)
+ {
+ bool bListPos = ( nType == Type::LISTCELLBIND );
+ uno::Reference<sheet::XSpreadsheetDocument> xDoc( pDocShell->GetBaseModel(), uno::UNO_QUERY );
+ xRet.set(*new calc::OCellValueBinding( xDoc, bListPos ));
+ }
+ break;
+ case Type::LISTSOURCE:
+ if (pDocShell)
+ {
+ uno::Reference<sheet::XSpreadsheetDocument> xDoc( pDocShell->GetBaseModel(), uno::UNO_QUERY );
+ xRet.set(*new calc::OCellListSource( xDoc ));
+ }
+ break;
+ case Type::CELLADDRESS:
+ case Type::RANGEADDRESS:
+ if (pDocShell)
+ {
+ bool bIsRange = ( nType == Type::RANGEADDRESS );
+ xRet.set(*new ScAddressConversionObj( pDocShell, bIsRange ));
+ }
+ break;
+ case Type::CHDATAPROV:
+ if (pDocShell)
+ xRet = *new ScChart2DataProvider( &pDocShell->GetDocument() );
+ break;
+ case Type::CHART_PIVOTTABLE_DATAPROVIDER:
+ if (pDocShell)
+ xRet = *new sc::PivotTableDataProvider(pDocShell->GetDocument());
+ break;
+ case Type::FORMULAPARS:
+ if (pDocShell)
+ xRet.set(static_cast<sheet::XFormulaParser*>(new ScFormulaParserObj( pDocShell )));
+ break;
+ case Type::OPCODEMAPPER:
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScAddress aAddress;
+ ScCompiler* pComp = new ScCompiler(rDoc, aAddress, rDoc.GetGrammar());
+ xRet.set(static_cast<sheet::XFormulaOpCodeMapper*>(new ScFormulaOpCodeMapperObj(::std::unique_ptr<formula::FormulaCompiler> (pComp))));
+ break;
+ }
+ break;
+#if HAVE_FEATURE_SCRIPTING
+ case Type::VBAOBJECTPROVIDER:
+ if (pDocShell && pDocShell->GetDocument().IsInVBAMode())
+ {
+ xRet.set(static_cast<container::XNameAccess*>(new ScVbaObjectForCodeNameProvider( pDocShell )));
+ }
+ break;
+ case Type::VBACODENAMEPROVIDER:
+ if ( pDocShell && isInVBAMode( *pDocShell ) )
+ {
+ xRet.set(static_cast<document::XCodeNameQuery*>(new ScVbaCodeNameProvider(*pDocShell)));
+ }
+ break;
+ case Type::VBAGLOBALS:
+ if (pDocShell)
+ {
+ uno::Any aGlobs;
+ if ( !pDocShell->GetBasicManager()->GetGlobalUNOConstant( "VBAGlobals", aGlobs ) )
+ {
+ uno::Sequence< uno::Any > aArgs{ uno::Any(pDocShell->GetModel()) };
+ xRet = ::comphelper::getProcessServiceFactory()->createInstanceWithArguments( "ooo.vba.excel.Globals", aArgs );
+ pDocShell->GetBasicManager()->SetGlobalUNOConstant( "VBAGlobals", uno::Any( xRet ) );
+ BasicManager* pAppMgr = SfxApplication::GetBasicManager();
+ if ( pAppMgr )
+ pAppMgr->SetGlobalUNOConstant( "ThisExcelDoc", aArgs[ 0 ] );
+
+ // create the VBA document event processor
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents(
+ ::ooo::vba::createVBAUnoAPIServiceWithArgs( pDocShell, "com.sun.star.script.vba.VBASpreadsheetEventProcessor", aArgs ), uno::UNO_QUERY );
+ pDocShell->GetDocument().SetVbaEventProcessor( xVbaEvents );
+ }
+ }
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return xRet;
+}
+
+uno::Sequence<OUString> ScServiceProvider::GetAllServiceNames()
+{
+ const sal_uInt16 nEntries = SAL_N_ELEMENTS(aProvNamesId);
+ uno::Sequence<OUString> aRet(nEntries);
+ OUString* pArray = aRet.getArray();
+ for (sal_uInt16 i = 0; i < nEntries; i++)
+ {
+ pArray[i] = aProvNamesId[i].pName;
+ }
+ return aRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/shapeuno.cxx b/sc/source/ui/unoobj/shapeuno.cxx
new file mode 100644
index 000000000..e8914d859
--- /dev/null
+++ b/sc/source/ui/unoobj/shapeuno.cxx
@@ -0,0 +1,1443 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <comphelper/sequence.hxx>
+#include <svtools/unoevent.hxx>
+#include <svtools/unoimap.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/event.hxx>
+#include <editeng/unofield.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+
+#include <shapeuno.hxx>
+#include <cellsuno.hxx>
+#include <textuno.hxx>
+#include <fielduno.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <userdat.hxx>
+#include <unonames.hxx>
+
+using namespace ::com::sun::star;
+
+static const SfxItemPropertyMapEntry* lcl_GetShapeMap()
+{
+ static const SfxItemPropertyMapEntry aShapeMap_Impl[] =
+ {
+ { SC_UNONAME_ANCHOR, 0, cppu::UnoType<uno::XInterface>::get(), 0, 0 },
+ { SC_UNONAME_RESIZE_WITH_CELL, 0, cppu::UnoType<sal_Bool>::get(), 0, 0 },
+ { SC_UNONAME_HORIPOS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_IMAGEMAP, 0, cppu::UnoType<container::XIndexContainer>::get(), 0, 0 },
+ { SC_UNONAME_VERTPOS, 0, cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ { SC_UNONAME_MOVEPROTECT, 0, cppu::UnoType<sal_Bool>::get(), 0, 0 },
+ { SC_UNONAME_HYPERLINK, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { SC_UNONAME_URL, 0, cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aShapeMap_Impl;
+}
+
+const SvEventDescription* ScShapeObj::GetSupportedMacroItems()
+{
+ static const SvEventDescription aMacroDescriptionsImpl[] =
+ {
+ { SvMacroItemId::NONE, nullptr }
+ };
+ return aMacroDescriptionsImpl;
+}
+ScMacroInfo* ScShapeObj_getShapeHyperMacroInfo( const ScShapeObj* pShape, bool bCreate = false )
+{
+ if( pShape )
+ if( SdrObject* pObj = pShape->GetSdrObject() )
+ return ScDrawLayer::GetMacroInfo( pObj, bCreate );
+ return nullptr;
+}
+
+ScShapeObj::ScShapeObj( uno::Reference<drawing::XShape>& xShape ) :
+ pShapePropertySet(nullptr),
+ pShapePropertyState(nullptr),
+ bIsTextShape(false),
+ bIsNoteCaption(false)
+{
+ osl_atomic_increment( &m_refCount );
+
+ {
+ mxShapeAgg.set( xShape, uno::UNO_QUERY );
+ // extra block to force deletion of the temporary before setDelegator
+ }
+
+ if (mxShapeAgg.is())
+ {
+ xShape = nullptr; // during setDelegator, mxShapeAgg must be the only ref
+
+ mxShapeAgg->setDelegator( static_cast<cppu::OWeakObject*>(this) );
+
+ xShape.set(uno::Reference<drawing::XShape>( mxShapeAgg, uno::UNO_QUERY ));
+
+ bIsTextShape = ( comphelper::getFromUnoTunnel<SvxUnoTextBase>( mxShapeAgg ) != nullptr );
+ }
+
+ {
+ SdrObject* pObj = GetSdrObject();
+ if ( pObj )
+ {
+ bIsNoteCaption = ScDrawLayer::IsNoteCaption( pObj );
+ }
+ }
+
+ osl_atomic_decrement( &m_refCount );
+}
+
+ScShapeObj::~ScShapeObj()
+{
+// if (mxShapeAgg.is())
+// mxShapeAgg->setDelegator(uno::Reference<uno::XInterface>());
+}
+
+// XInterface
+
+uno::Any SAL_CALL ScShapeObj::queryInterface( const uno::Type& rType )
+{
+ uno::Any aRet = ScShapeObj_Base::queryInterface( rType );
+
+ if ( !aRet.hasValue() && bIsTextShape )
+ aRet = ScShapeObj_TextBase::queryInterface( rType );
+
+ if ( !aRet.hasValue() && bIsNoteCaption )
+ aRet = ScShapeObj_ChildBase::queryInterface( rType );
+
+ if ( !aRet.hasValue() && mxShapeAgg.is() )
+ aRet = mxShapeAgg->queryAggregation( rType );
+
+ return aRet;
+}
+
+void SAL_CALL ScShapeObj::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL ScShapeObj::release() noexcept
+{
+ OWeakObject::release();
+}
+
+void ScShapeObj::GetShapePropertySet()
+{
+ // #i61908# Store the result of queryAggregation in a member.
+ // The reference in mxShapeAgg is kept for this object's lifetime, so the pointer is always valid.
+
+ if (!pShapePropertySet)
+ {
+ uno::Reference<beans::XPropertySet> xProp;
+ if ( mxShapeAgg.is() )
+ mxShapeAgg->queryAggregation( cppu::UnoType<beans::XPropertySet>::get()) >>= xProp;
+ pShapePropertySet = xProp.get();
+ }
+}
+
+void ScShapeObj::GetShapePropertyState()
+{
+ // #i61908# Store the result of queryAggregation in a member.
+ // The reference in mxShapeAgg is kept for this object's lifetime, so the pointer is always valid.
+
+ if (!pShapePropertyState)
+ {
+ uno::Reference<beans::XPropertyState> xState;
+ if ( mxShapeAgg.is() )
+ mxShapeAgg->queryAggregation( cppu::UnoType<beans::XPropertyState>::get()) >>= xState;
+ pShapePropertyState = xState.get();
+ }
+}
+
+static uno::Reference<lang::XComponent> lcl_GetComponent( const uno::Reference<uno::XAggregation>& xAgg )
+{
+ uno::Reference<lang::XComponent> xRet;
+ if ( xAgg.is() )
+ xAgg->queryAggregation( cppu::UnoType<lang::XComponent>::get()) >>= xRet;
+ return xRet;
+}
+
+static uno::Reference<text::XText> lcl_GetText( const uno::Reference<uno::XAggregation>& xAgg )
+{
+ uno::Reference<text::XText> xRet;
+ if ( xAgg.is() )
+ xAgg->queryAggregation( cppu::UnoType<text::XText>::get()) >>= xRet;
+ return xRet;
+}
+
+static uno::Reference<text::XSimpleText> lcl_GetSimpleText( const uno::Reference<uno::XAggregation>& xAgg )
+{
+ uno::Reference<text::XSimpleText> xRet;
+ if ( xAgg.is() )
+ xAgg->queryAggregation( cppu::UnoType<text::XSimpleText>::get()) >>= xRet;
+ return xRet;
+}
+
+static uno::Reference<text::XTextRange> lcl_GetTextRange( const uno::Reference<uno::XAggregation>& xAgg )
+{
+ uno::Reference<text::XTextRange> xRet;
+ if ( xAgg.is() )
+ xAgg->queryAggregation( cppu::UnoType<text::XTextRange>::get()) >>= xRet;
+ return xRet;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScShapeObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+
+ // #i61527# cache property set info for this object
+ if ( !mxPropSetInfo.is() )
+ {
+ // mix own and aggregated properties:
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ {
+ uno::Reference<beans::XPropertySetInfo> xAggInfo(pShapePropertySet->getPropertySetInfo());
+ const uno::Sequence<beans::Property> aPropSeq(xAggInfo->getProperties());
+ mxPropSetInfo.set(new SfxExtItemPropertySetInfo( lcl_GetShapeMap(), aPropSeq ));
+ }
+ }
+ return mxPropSetInfo;
+}
+
+static bool lcl_GetPageNum( const SdrPage* pPage, SdrModel& rModel, SCTAB& rNum )
+{
+ sal_uInt16 nCount = rModel.GetPageCount();
+ for (sal_uInt16 i=0; i<nCount; i++)
+ if ( rModel.GetPage(i) == pPage )
+ {
+ rNum = static_cast<SCTAB>(i);
+ return true;
+ }
+
+ return false;
+}
+
+static bool lcl_GetCaptionPoint( const uno::Reference< drawing::XShape >& xShape, awt::Point& rCaptionPoint )
+{
+ bool bReturn = false;
+ OUString sType(xShape->getShapeType());
+ bool bCaptionShape( sType == "com.sun.star.drawing.CaptionShape" );
+ if (bCaptionShape)
+ {
+ uno::Reference < beans::XPropertySet > xShapeProp (xShape, uno::UNO_QUERY);
+ if (xShapeProp.is())
+ {
+ xShapeProp->getPropertyValue("CaptionPoint") >>= rCaptionPoint;
+ bReturn = true;
+ }
+ }
+ return bReturn;
+}
+
+static ScRange lcl_GetAnchorCell( const uno::Reference< drawing::XShape >& xShape, const ScDocument* pDoc, SCTAB nTab,
+ awt::Point& rUnoPoint, awt::Size& rUnoSize, awt::Point& rCaptionPoint )
+{
+ ScRange aReturn;
+ rUnoPoint = xShape->getPosition();
+ bool bCaptionShape(lcl_GetCaptionPoint(xShape, rCaptionPoint));
+ if (pDoc->IsNegativePage(nTab))
+ {
+ rUnoSize = xShape->getSize();
+ rUnoPoint.X += rUnoSize.Width; // the right top point is base
+ if (bCaptionShape)
+ {
+ if (rCaptionPoint.X > 0 && rCaptionPoint.X > rUnoSize.Width)
+ rUnoPoint.X += rCaptionPoint.X - rUnoSize.Width;
+ if (rCaptionPoint.Y < 0)
+ rUnoPoint.Y += rCaptionPoint.Y;
+ }
+ aReturn = pDoc->GetRange( nTab, tools::Rectangle( VCLPoint(rUnoPoint), VCLPoint(rUnoPoint) ));
+ }
+ else
+ {
+ if (bCaptionShape)
+ {
+ if (rCaptionPoint.X < 0)
+ rUnoPoint.X += rCaptionPoint.X;
+ if (rCaptionPoint.Y < 0)
+ rUnoPoint.Y += rCaptionPoint.Y;
+ }
+ aReturn = pDoc->GetRange( nTab, tools::Rectangle( VCLPoint(rUnoPoint), VCLPoint(rUnoPoint) ));
+ }
+
+ return aReturn;
+}
+
+static awt::Point lcl_GetRelativePos( const uno::Reference< drawing::XShape >& xShape, const ScDocument* pDoc, SCTAB nTab, ScRange& rRange,
+ awt::Size& rUnoSize, awt::Point& rCaptionPoint)
+{
+ awt::Point aUnoPoint;
+ rRange = lcl_GetAnchorCell(xShape, pDoc, nTab, aUnoPoint, rUnoSize, rCaptionPoint);
+ tools::Rectangle aRect(pDoc->GetMMRect( rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aStart.Tab() ));
+ Point aPoint = pDoc->IsNegativePage(nTab) ? aRect.TopRight() : aRect.TopLeft();
+ aUnoPoint.X -= aPoint.X();
+ aUnoPoint.Y -= aPoint.Y();
+ return aUnoPoint;
+}
+
+void SAL_CALL ScShapeObj::setPropertyValue(const OUString& aPropertyName, const uno::Any& aValue)
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == SC_UNONAME_ANCHOR )
+ {
+ uno::Reference<sheet::XCellRangeAddressable> xRangeAdd(aValue, uno::UNO_QUERY);
+ if (!xRangeAdd.is())
+ throw lang::IllegalArgumentException("only XCell or XSpreadsheet objects allowed", static_cast<cppu::OWeakObject*>(this), 0);
+
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ ScDocument* pDoc(rModel.GetDocument());
+
+ if ( pDoc )
+ {
+ SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
+ if ( auto pDocSh = dynamic_cast<ScDocShell*>( pObjSh) )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ table::CellRangeAddress aAddress = xRangeAdd->getRangeAddress();
+ if (nTab == aAddress.Sheet)
+ {
+ tools::Rectangle aRect(pDoc->GetMMRect( static_cast<SCCOL>(aAddress.StartColumn), static_cast<SCROW>(aAddress.StartRow),
+ static_cast<SCCOL>(aAddress.EndColumn), static_cast<SCROW>(aAddress.EndRow), aAddress.Sheet ));
+ awt::Point aRelPoint;
+ uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
+ if (xShape.is())
+ {
+ Point aPoint;
+ Point aEndPoint;
+ if (pDoc->IsNegativePage(nTab))
+ {
+ aPoint = aRect.TopRight();
+ aEndPoint = aRect.BottomLeft();
+ }
+ else
+ {
+ aPoint = aRect.TopLeft();
+ aEndPoint = aRect.BottomRight();
+ }
+ awt::Size aUnoSize;
+ awt::Point aCaptionPoint;
+ ScRange aRange;
+ aRelPoint = lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint );
+ awt::Point aUnoPoint(aRelPoint);
+
+ aUnoPoint.X += aPoint.X();
+ aUnoPoint.Y += aPoint.Y();
+
+ if ( aUnoPoint.Y > aEndPoint.Y() )
+ aUnoPoint.Y = aEndPoint.Y() - 2;
+ if (pDoc->IsNegativePage(nTab))
+ {
+ if ( aUnoPoint.X < aEndPoint.X() )
+ aUnoPoint.X = aEndPoint.X() + 2;
+ aUnoPoint.X -= aUnoSize.Width;
+ // remove difference to caption point
+ if (aCaptionPoint.X > 0 && aCaptionPoint.X > aUnoSize.Width)
+ aUnoPoint.X -= aCaptionPoint.X - aUnoSize.Width;
+ }
+ else
+ {
+ if ( aUnoPoint.X > aEndPoint.X() )
+ aUnoPoint.X = aEndPoint.X() - 2;
+ if (aCaptionPoint.X < 0)
+ aUnoPoint.X -= aCaptionPoint.X;
+ }
+ if (aCaptionPoint.Y < 0)
+ aUnoPoint.Y -= aCaptionPoint.Y;
+
+ xShape->setPosition(aUnoPoint);
+ pDocSh->SetModified();
+ }
+
+ if (aAddress.StartRow != aAddress.EndRow) //should be a Spreadsheet
+ {
+ OSL_ENSURE(aAddress.StartRow == 0 && aAddress.EndRow == pDoc->MaxRow() &&
+ aAddress.StartColumn == 0 && aAddress.EndColumn == pDoc->MaxCol(), "here should be a XSpreadsheet");
+ ScDrawLayer::SetPageAnchored(*pObj);
+ }
+ else
+ {
+ OSL_ENSURE(aAddress.StartRow == aAddress.EndRow &&
+ aAddress.StartColumn == aAddress.EndColumn, "here should be a XCell");
+ ScDrawObjData aAnchor;
+ aAnchor.maStart = ScAddress(aAddress.StartColumn, aAddress.StartRow, aAddress.Sheet);
+ aAnchor.maStartOffset = Point(aRelPoint.X, aRelPoint.Y);
+ ScDrawObjData* pDrawObjData = ScDrawLayer::GetObjData(pObj);
+ if (pDrawObjData)
+ aAnchor.mbResizeWithCell = pDrawObjData->mbResizeWithCell;
+ //Uno sets the Anchor in terms of the unrotated shape, not much we can do
+ //about that since uno also displays the shape geometry in terms of the unrotated
+ //shape. #TODO think about changing the anchoring behaviour here too
+ //Currently we've only got a start anchor, not an end-anchor, so generate that now
+ ScDrawLayer::UpdateCellAnchorFromPositionEnd(*pObj, aAnchor, *pDoc, aAddress.Sheet);
+ ScDrawLayer::SetCellAnchored(*pObj, aAnchor);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+ else if ( aPropertyName == SC_UNONAME_RESIZE_WITH_CELL )
+ {
+ SdrObject* pObj = GetSdrObject();
+ if (!pObj)
+ return;
+ ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObj);
+
+ // Nothing to do if anchored to page
+ if (aAnchorType == SCA_PAGE)
+ return;
+
+ ScDrawObjData* pDrawObjData = ScDrawLayer::GetObjData(pObj);
+ if (!pDrawObjData)
+ return;
+
+ aValue >>= pDrawObjData->mbResizeWithCell;
+ ScDrawLayer::SetCellAnchored(*pObj, *pDrawObjData);
+ }
+ else if ( aPropertyName == SC_UNONAME_IMAGEMAP )
+ {
+ SdrObject* pObj = GetSdrObject();
+ if ( pObj )
+ {
+ ImageMap aImageMap;
+ uno::Reference< uno::XInterface > xImageMapInt(aValue, uno::UNO_QUERY);
+
+ if( !xImageMapInt.is() || !SvUnoImageMap_fillImageMap( xImageMapInt, 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) ));
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_HORIPOS )
+ {
+ sal_Int32 nPos = 0;
+ if (aValue >>= nPos)
+ {
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ ScDocument* pDoc = rModel.GetDocument();
+ if ( pDoc )
+ {
+ SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
+ if ( auto pDocSh = dynamic_cast<ScDocShell*>( pObjSh) )
+ {
+ uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
+ if (xShape.is())
+ {
+ if (ScDrawLayer::GetAnchorType(*pObj) == SCA_PAGE)
+ {
+ awt::Point aPoint(xShape->getPosition());
+ awt::Size aSize(xShape->getSize());
+ awt::Point aCaptionPoint;
+ if (pDoc->IsNegativePage(nTab))
+ {
+ nPos *= -1;
+ nPos -= aSize.Width;
+ }
+ if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
+ {
+ if (pDoc->IsNegativePage(nTab))
+ {
+ if (aCaptionPoint.X > 0 && aCaptionPoint.X > aSize.Width)
+ nPos -= aCaptionPoint.X - aSize.Width;
+ }
+ else
+ {
+ if (aCaptionPoint.X < 0)
+ nPos -= aCaptionPoint.X;
+ }
+ }
+ aPoint.X = nPos;
+ xShape->setPosition(aPoint);
+ pDocSh->SetModified();
+ }
+ else if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL
+ || ScDrawLayer::GetAnchorType(*pObj)
+ == SCA_CELL_RESIZE)
+ {
+ awt::Size aUnoSize;
+ awt::Point aCaptionPoint;
+ ScRange aRange;
+ awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
+ tools::Rectangle aRect(pDoc->GetMMRect( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab() ));
+ if (pDoc->IsNegativePage(nTab))
+ {
+ aUnoPoint.X = -nPos;
+ Point aPoint(aRect.TopRight());
+ Point aEndPoint(aRect.BottomLeft());
+ aUnoPoint.X += aPoint.X();
+ if (aUnoPoint.X < aEndPoint.X())
+ aUnoPoint.X = aEndPoint.X() + 2;
+ aUnoPoint.X -= aUnoSize.Width;
+ if (aCaptionPoint.X > 0 && aCaptionPoint.X > aUnoSize.Width)
+ aUnoPoint.X -= aCaptionPoint.X - aUnoSize.Width;
+ }
+ else
+ {
+ aUnoPoint.X = nPos;
+ Point aPoint(aRect.TopLeft());
+ Point aEndPoint(aRect.BottomRight());
+ aUnoPoint.X += aPoint.X();
+ if (aUnoPoint.X > aEndPoint.X())
+ aUnoPoint.X = aEndPoint.X() - 2;
+ if (aCaptionPoint.X < 0)
+ aUnoPoint.X -= aCaptionPoint.X;
+ }
+ aUnoPoint.Y = xShape->getPosition().Y;
+ xShape->setPosition(aUnoPoint);
+ pDocSh->SetModified();
+ }
+ else
+ {
+ OSL_FAIL("unknown anchor type");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_VERTPOS )
+ {
+ sal_Int32 nPos = 0;
+ if (aValue >>= nPos)
+ {
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ ScDocument* pDoc = rModel.GetDocument();
+ if ( pDoc )
+ {
+ SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
+ if ( auto pDocSh = dynamic_cast<ScDocShell*>( pObjSh) )
+ {
+ uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
+ if (xShape.is())
+ {
+ if (ScDrawLayer::GetAnchorType(*pObj) == SCA_PAGE)
+ {
+ awt::Point aPoint = xShape->getPosition();
+ awt::Point aCaptionPoint;
+ if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
+ {
+ if (aCaptionPoint.Y < 0)
+ nPos -= aCaptionPoint.Y;
+ }
+ aPoint.Y = nPos;
+ xShape->setPosition(aPoint);
+ pDocSh->SetModified();
+ }
+ else if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL
+ || ScDrawLayer::GetAnchorType(*pObj)
+ == SCA_CELL_RESIZE)
+ {
+ awt::Size aUnoSize;
+ awt::Point aCaptionPoint;
+ ScRange aRange;
+ awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
+ tools::Rectangle aRect(pDoc->GetMMRect( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), aRange.aStart.Tab() ));
+ Point aPoint(aRect.TopRight());
+ Point aEndPoint(aRect.BottomLeft());
+ aUnoPoint.Y = nPos;
+ aUnoPoint.Y += aPoint.Y();
+ if (aUnoPoint.Y > aEndPoint.Y())
+ aUnoPoint.Y = aEndPoint.Y() - 2;
+ if (aCaptionPoint.Y < 0)
+ aUnoPoint.Y -= aCaptionPoint.Y;
+ aUnoPoint.X = xShape->getPosition().X;
+ xShape->setPosition(aUnoPoint);
+ pDocSh->SetModified();
+ }
+ else
+ {
+ OSL_FAIL("unknown anchor type");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_HYPERLINK ||
+ aPropertyName == SC_UNONAME_URL )
+ {
+ OUString sHyperlink;
+ SdrObject* pObj = GetSdrObject();
+ if (pObj && (aValue >>= sHyperlink))
+ pObj->setHyperlink(sHyperlink);
+ }
+ else if ( aPropertyName == SC_UNONAME_MOVEPROTECT )
+ {
+ if( SdrObject* pObj = GetSdrObject() )
+ {
+ bool aProt = false;
+ if( aValue >>= aProt )
+ pObj->SetMoveProtect( aProt );
+ }
+ }
+ else
+ {
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ pShapePropertySet->setPropertyValue( aPropertyName, aValue );
+ }
+}
+
+uno::Any SAL_CALL ScShapeObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aAny;
+ if ( aPropertyName == SC_UNONAME_ANCHOR )
+ {
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ ScDocument* pDoc = rModel.GetDocument();
+ if ( pDoc )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
+ if ( auto pDocSh = dynamic_cast<ScDocShell*>( pObjSh) )
+ {
+ uno::Reference< uno::XInterface > xAnchor;
+ if (ScDrawObjData *pAnchor = ScDrawLayer::GetObjDataTab(pObj, nTab))
+ xAnchor.set(static_cast<cppu::OWeakObject*>(new ScCellObj( pDocSh, pAnchor->maStart)));
+ else
+ xAnchor.set(static_cast<cppu::OWeakObject*>(new ScTableSheetObj( pDocSh, nTab )));
+ aAny <<= xAnchor;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (aPropertyName == SC_UNONAME_RESIZE_WITH_CELL)
+ {
+ bool bIsResizeWithCell = false;
+ SdrObject* pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScAnchorType anchorType = ScDrawLayer::GetAnchorType(*pObj);
+ bIsResizeWithCell = (anchorType == SCA_CELL_RESIZE);
+ }
+ aAny <<= bIsResizeWithCell;
+ }
+ else if ( aPropertyName == SC_UNONAME_IMAGEMAP )
+ {
+ uno::Reference< uno::XInterface > xImageMap;
+ SdrObject* pObj = GetSdrObject();
+ if ( pObj )
+ {
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo(GetSdrObject());
+ if( pIMapInfo )
+ {
+ const ImageMap& rIMap = pIMapInfo->GetImageMap();
+ xImageMap.set(SvUnoImageMap_createInstance( rIMap, GetSupportedMacroItems() ));
+ }
+ else
+ xImageMap = SvUnoImageMap_createInstance();
+ }
+ aAny <<= uno::Reference< container::XIndexContainer >::query( xImageMap );
+ }
+ else if ( aPropertyName == SC_UNONAME_HORIPOS )
+ {
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ ScDocument* pDoc = rModel.GetDocument();
+ if ( pDoc )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
+ if (xShape.is())
+ {
+ if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL
+ || ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL_RESIZE)
+ {
+ awt::Size aUnoSize;
+ awt::Point aCaptionPoint;
+ ScRange aRange;
+ awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
+ if (pDoc->IsNegativePage(nTab))
+ aUnoPoint.X *= -1;
+ aAny <<= aUnoPoint.X;
+ }
+ else
+ {
+ awt::Point aCaptionPoint;
+ awt::Point aUnoPoint(xShape->getPosition());
+ awt::Size aUnoSize(xShape->getSize());
+ if (pDoc->IsNegativePage(nTab))
+ {
+ aUnoPoint.X *= -1;
+ aUnoPoint.X -= aUnoSize.Width;
+ }
+ if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
+ {
+ if (pDoc->IsNegativePage(nTab))
+ {
+ if (aCaptionPoint.X > 0 && aCaptionPoint.X > aUnoSize.Width)
+ aUnoPoint.X -= aCaptionPoint.X - aUnoSize.Width;
+ }
+ else
+ {
+ if (aCaptionPoint.X < 0)
+ aUnoPoint.X += aCaptionPoint.X;
+ }
+ }
+ aAny <<= aUnoPoint.X;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_VERTPOS )
+ {
+ SdrObject *pObj = GetSdrObject();
+ if (pObj)
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+
+ if ( pPage )
+ {
+ ScDocument* pDoc = rModel.GetDocument();
+ if ( pDoc )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ uno::Reference<drawing::XShape> xShape( mxShapeAgg, uno::UNO_QUERY );
+ if (xShape.is())
+ {
+ if (ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL
+ || ScDrawLayer::GetAnchorType(*pObj) == SCA_CELL_RESIZE)
+ {
+ awt::Size aUnoSize;
+ awt::Point aCaptionPoint;
+ ScRange aRange;
+ awt::Point aUnoPoint(lcl_GetRelativePos( xShape, pDoc, nTab, aRange, aUnoSize, aCaptionPoint ));
+
+ aAny <<= aUnoPoint.Y;
+ }
+ else
+ {
+ awt::Point aUnoPoint(xShape->getPosition());
+ awt::Point aCaptionPoint;
+ if (lcl_GetCaptionPoint(xShape, aCaptionPoint))
+ {
+ if (aCaptionPoint.Y < 0)
+ aUnoPoint.Y += aCaptionPoint.Y;
+ }
+ aAny <<= aUnoPoint.Y;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ else if ( aPropertyName == SC_UNONAME_HYPERLINK ||
+ aPropertyName == SC_UNONAME_URL )
+ {
+ OUString sHlink;
+ if (SdrObject* pObj = GetSdrObject())
+ sHlink = pObj->getHyperlink();
+ aAny <<= sHlink;
+ }
+ else if ( aPropertyName == SC_UNONAME_MOVEPROTECT )
+ {
+ bool aProt = false;
+ if ( SdrObject* pObj = GetSdrObject() )
+ aProt = pObj->IsMoveProtect();
+ aAny <<= aProt;
+ }
+ else
+ {
+ if(!pShapePropertySet) //performance consideration
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ aAny = pShapePropertySet->getPropertyValue( aPropertyName );
+ }
+
+ return aAny;
+}
+
+void SAL_CALL ScShapeObj::addPropertyChangeListener( const OUString& aPropertyName,
+ const uno::Reference<beans::XPropertyChangeListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ pShapePropertySet->addPropertyChangeListener( aPropertyName, aListener );
+}
+
+void SAL_CALL ScShapeObj::removePropertyChangeListener( const OUString& aPropertyName,
+ const uno::Reference<beans::XPropertyChangeListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ pShapePropertySet->removePropertyChangeListener( aPropertyName, aListener );
+}
+
+void SAL_CALL ScShapeObj::addVetoableChangeListener( const OUString& aPropertyName,
+ const uno::Reference<beans::XVetoableChangeListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ pShapePropertySet->addVetoableChangeListener( aPropertyName, aListener );
+}
+
+void SAL_CALL ScShapeObj::removeVetoableChangeListener( const OUString& aPropertyName,
+ const uno::Reference<beans::XVetoableChangeListener>& aListener)
+{
+ SolarMutexGuard aGuard;
+
+ GetShapePropertySet();
+ if (pShapePropertySet)
+ pShapePropertySet->removeVetoableChangeListener( aPropertyName, aListener );
+}
+
+// XPropertyState
+
+beans::PropertyState SAL_CALL ScShapeObj::getPropertyState( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ beans::PropertyState eRet = beans::PropertyState_DIRECT_VALUE;
+ if ( aPropertyName == SC_UNONAME_IMAGEMAP )
+ {
+ // ImageMap is always "direct"
+ }
+ else if ( aPropertyName == SC_UNONAME_ANCHOR )
+ {
+ // Anchor is always "direct"
+ }
+ else if ( aPropertyName == SC_UNONAME_HORIPOS )
+ {
+ // HoriPos is always "direct"
+ }
+ else if ( aPropertyName == SC_UNONAME_VERTPOS )
+ {
+ // VertPos is always "direct"
+ }
+ else
+ {
+ GetShapePropertyState();
+ if (pShapePropertyState)
+ eRet = pShapePropertyState->getPropertyState( aPropertyName );
+ }
+
+ return eRet;
+}
+
+uno::Sequence<beans::PropertyState> SAL_CALL ScShapeObj::getPropertyStates(
+ const uno::Sequence<OUString>& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+
+ // simple loop to get own and aggregated states
+
+ uno::Sequence<beans::PropertyState> aRet(aPropertyNames.getLength());
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.getArray(),
+ [this](const OUString& rName) -> beans::PropertyState { return getPropertyState(rName); });
+ return aRet;
+}
+
+void SAL_CALL ScShapeObj::setPropertyToDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == SC_UNONAME_IMAGEMAP )
+ {
+ SdrObject* pObj = GetSdrObject();
+ if ( pObj )
+ {
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo(pObj);
+ if( pIMapInfo )
+ {
+ ImageMap aEmpty;
+ pIMapInfo->SetImageMap( aEmpty ); // replace with empty image map
+ }
+ else
+ {
+ // nothing to do (no need to insert user data for an empty map)
+ }
+ }
+ }
+ else
+ {
+ GetShapePropertyState();
+ if (pShapePropertyState)
+ pShapePropertyState->setPropertyToDefault( aPropertyName );
+ }
+}
+
+uno::Any SAL_CALL ScShapeObj::getPropertyDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Any aAny;
+ if ( aPropertyName == SC_UNONAME_IMAGEMAP )
+ {
+ // default: empty ImageMap
+ uno::Reference< uno::XInterface > xImageMap(SvUnoImageMap_createInstance());
+ aAny <<= uno::Reference< container::XIndexContainer >::query( xImageMap );
+ }
+ else
+ {
+ GetShapePropertyState();
+ if (pShapePropertyState)
+ aAny = pShapePropertyState->getPropertyDefault( aPropertyName );
+ }
+
+ return aAny;
+}
+
+// XTextContent
+
+void SAL_CALL ScShapeObj::attach( const uno::Reference<text::XTextRange>& /* xTextRange */ )
+{
+ throw lang::IllegalArgumentException(); // anchor cannot be changed
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getAnchor()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextRange> xRet;
+
+ SdrObject* pObj = GetSdrObject();
+ if( pObj )
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+ ScDocument* pDoc = rModel.GetDocument();
+
+ if ( pPage && pDoc )
+ {
+ SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
+ if ( auto pDocSh = dynamic_cast<ScDocShell*>( pObjSh) )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ Point aPos(pObj->GetCurrentBoundRect().TopLeft());
+ ScRange aRange(pDoc->GetRange( nTab, tools::Rectangle( aPos, aPos ) ));
+
+ // anchor is always the cell
+
+ xRet.set(new ScCellObj( pDocSh, aRange.aStart ));
+ }
+ }
+ }
+ }
+
+ return xRet;
+}
+
+// XComponent
+
+void SAL_CALL ScShapeObj::dispose()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<lang::XComponent> xAggComp(lcl_GetComponent(mxShapeAgg));
+ if ( xAggComp.is() )
+ xAggComp->dispose();
+}
+
+void SAL_CALL ScShapeObj::addEventListener(
+ const uno::Reference<lang::XEventListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<lang::XComponent> xAggComp(lcl_GetComponent(mxShapeAgg));
+ if ( xAggComp.is() )
+ xAggComp->addEventListener(xListener);
+}
+
+void SAL_CALL ScShapeObj::removeEventListener(
+ const uno::Reference<lang::XEventListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<lang::XComponent> xAggComp(lcl_GetComponent(mxShapeAgg));
+ if ( xAggComp.is() )
+ xAggComp->removeEventListener(xListener);
+}
+
+// XText
+// (special handling for ScCellFieldObj)
+
+static void lcl_CopyOneProperty( beans::XPropertySet& rDest, beans::XPropertySet& rSource, const OUString& aNameStr )
+{
+ try
+ {
+ rDest.setPropertyValue( aNameStr, rSource.getPropertyValue( aNameStr ) );
+ }
+ catch (uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "Exception in text field");
+ }
+}
+
+void SAL_CALL ScShapeObj::insertTextContent( const uno::Reference<text::XTextRange>& xRange,
+ const uno::Reference<text::XTextContent>& xContent,
+ sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextContent> xEffContent;
+
+ ScEditFieldObj* pCellField = comphelper::getFromUnoTunnel<ScEditFieldObj>( xContent );
+ if ( pCellField )
+ {
+ // createInstance("TextField.URL") from the document creates a ScCellFieldObj.
+ // To insert it into drawing text, a SvxUnoTextField is needed instead.
+ // The ScCellFieldObj object is left in non-inserted state.
+
+ rtl::Reference<SvxUnoTextField> pDrawField = new SvxUnoTextField( text::textfield::Type::URL );
+ xEffContent.set(pDrawField);
+ lcl_CopyOneProperty( *pDrawField, *pCellField, SC_UNONAME_URL );
+ lcl_CopyOneProperty( *pDrawField, *pCellField, SC_UNONAME_REPR );
+ lcl_CopyOneProperty( *pDrawField, *pCellField, SC_UNONAME_TARGET );
+ }
+ else
+ xEffContent.set(xContent);
+
+ uno::Reference<text::XText> xAggText(lcl_GetText(mxShapeAgg));
+ if ( xAggText.is() )
+ xAggText->insertTextContent( xRange, xEffContent, bAbsorb );
+}
+
+void SAL_CALL ScShapeObj::removeTextContent( const uno::Reference<text::XTextContent>& xContent )
+{
+ SolarMutexGuard aGuard;
+
+ // ScCellFieldObj can't be used here.
+
+ uno::Reference<text::XText> xAggText(lcl_GetText(mxShapeAgg));
+ if ( xAggText.is() )
+ xAggText->removeTextContent( xContent );
+}
+
+// XSimpleText (parent of XText)
+// Use own SvxUnoTextCursor subclass - everything is just passed to aggregated object
+
+uno::Reference<text::XTextCursor> SAL_CALL ScShapeObj::createTextCursor()
+{
+ SolarMutexGuard aGuard;
+
+ if ( mxShapeAgg.is() )
+ {
+ // ScDrawTextCursor must be used to ensure the ScShapeObj is returned by getText
+
+ SvxUnoTextBase* pText = comphelper::getFromUnoTunnel<SvxUnoTextBase>( mxShapeAgg );
+ if (pText)
+ return new ScDrawTextCursor( this, *pText );
+ }
+
+ return uno::Reference<text::XTextCursor>();
+}
+
+uno::Reference<text::XTextCursor> SAL_CALL ScShapeObj::createTextCursorByRange(
+ const uno::Reference<text::XTextRange>& aTextPosition )
+{
+ SolarMutexGuard aGuard;
+
+ if ( mxShapeAgg.is() && aTextPosition.is() )
+ {
+ // ScDrawTextCursor must be used to ensure the ScShapeObj is returned by getText
+
+ SvxUnoTextBase* pText = comphelper::getFromUnoTunnel<SvxUnoTextBase>( mxShapeAgg );
+ SvxUnoTextRangeBase* pRange = comphelper::getFromUnoTunnel<SvxUnoTextRangeBase>( aTextPosition );
+ if ( pText && pRange )
+ {
+ rtl::Reference<SvxUnoTextCursor> pCursor = new ScDrawTextCursor( this, *pText );
+ pCursor->SetSelection( pRange->GetSelection() );
+ return pCursor;
+ }
+ }
+
+ return uno::Reference<text::XTextCursor>();
+}
+
+void SAL_CALL ScShapeObj::insertString( const uno::Reference<text::XTextRange>& xRange,
+ const OUString& aString, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XSimpleText> xAggSimpleText(lcl_GetSimpleText(mxShapeAgg));
+ if ( !xAggSimpleText.is() )
+ throw uno::RuntimeException();
+
+ xAggSimpleText->insertString( xRange, aString, bAbsorb );
+}
+
+void SAL_CALL ScShapeObj::insertControlCharacter( const uno::Reference<text::XTextRange>& xRange,
+ sal_Int16 nControlCharacter, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XSimpleText> xAggSimpleText(lcl_GetSimpleText(mxShapeAgg));
+ if ( !xAggSimpleText.is() )
+ throw uno::RuntimeException();
+
+ xAggSimpleText->insertControlCharacter( xRange, nControlCharacter, bAbsorb );
+}
+
+// XTextRange
+// (parent of XSimpleText)
+
+uno::Reference<text::XText> SAL_CALL ScShapeObj::getText()
+{
+ return this;
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getStart()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
+ if ( !xAggTextRange.is() )
+ throw uno::RuntimeException();
+
+ return xAggTextRange->getStart();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScShapeObj::getEnd()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
+ if ( !xAggTextRange.is() )
+ throw uno::RuntimeException();
+
+ return xAggTextRange->getEnd();
+}
+
+OUString SAL_CALL ScShapeObj::getString()
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
+ if ( !xAggTextRange.is() )
+ throw uno::RuntimeException();
+
+ return xAggTextRange->getString();
+}
+
+void SAL_CALL ScShapeObj::setString( const OUString& aText )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<text::XTextRange> xAggTextRange(lcl_GetTextRange(mxShapeAgg));
+ if ( !xAggTextRange.is() )
+ throw uno::RuntimeException();
+
+ xAggTextRange->setString( aText );
+}
+
+// XChild
+
+uno::Reference< uno::XInterface > SAL_CALL ScShapeObj::getParent()
+{
+ SolarMutexGuard aGuard;
+
+ // receive cell position from caption object (parent of a note caption is the note cell)
+ SdrObject* pObj = GetSdrObject();
+ if( pObj )
+ {
+ ScDrawLayer& rModel(static_cast< ScDrawLayer& >(pObj->getSdrModelFromSdrObject()));
+ SdrPage* pPage(pObj->getSdrPageFromSdrObject());
+ ScDocument* pDoc = rModel.GetDocument();
+
+ if ( pPage && pDoc )
+ {
+ SfxObjectShell* pObjSh = pDoc->GetDocumentShell();
+ if ( auto pDocSh = dynamic_cast<ScDocShell*>( pObjSh) )
+ {
+ SCTAB nTab = 0;
+ if ( lcl_GetPageNum( pPage, rModel, nTab ) )
+ {
+ const ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( pObj, nTab );
+ if( pCaptData )
+ return static_cast< ::cppu::OWeakObject* >( new ScCellObj( pDocSh, pCaptData->maStart ) );
+ }
+ }
+ }
+ }
+
+ return nullptr;
+}
+
+void SAL_CALL ScShapeObj::setParent( const uno::Reference< uno::XInterface >& )
+{
+ throw lang::NoSupportException();
+}
+
+// XTypeProvider
+
+uno::Sequence<uno::Type> SAL_CALL ScShapeObj::getTypes()
+{
+ uno::Sequence< uno::Type > aBaseTypes( ScShapeObj_Base::getTypes() );
+
+ uno::Sequence< uno::Type > aTextTypes;
+ if ( bIsTextShape )
+ aTextTypes = ScShapeObj_TextBase::getTypes();
+
+ uno::Reference<lang::XTypeProvider> xBaseProvider;
+ if ( mxShapeAgg.is() )
+ mxShapeAgg->queryAggregation( cppu::UnoType<lang::XTypeProvider>::get()) >>= xBaseProvider;
+ OSL_ENSURE( xBaseProvider.is(), "ScShapeObj: No XTypeProvider from aggregated shape!" );
+
+ uno::Sequence< uno::Type > aAggTypes;
+ if( xBaseProvider.is() )
+ aAggTypes = xBaseProvider->getTypes();
+
+ return ::comphelper::concatSequences( aBaseTypes, aTextTypes, aAggTypes );
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScShapeObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+SdrObject* ScShapeObj::GetSdrObject() const noexcept
+{
+ if(mxShapeAgg.is())
+ return SdrObject::getSdrObjectFromXShape( mxShapeAgg );
+ return nullptr;
+}
+
+constexpr OUStringLiteral SC_EVENTACC_ONCLICK = u"OnClick";
+constexpr OUStringLiteral SC_EVENTACC_SCRIPT = u"Script";
+constexpr OUStringLiteral SC_EVENTACC_EVENTTYPE = u"EventType";
+
+class ShapeUnoEventAccessImpl : public ::cppu::WeakImplHelper< container::XNameReplace >
+{
+private:
+ ScShapeObj* mpShape;
+
+ ScMacroInfo* getInfo( bool bCreate )
+ {
+ return ScShapeObj_getShapeHyperMacroInfo( mpShape, bCreate );
+ }
+
+public:
+ explicit ShapeUnoEventAccessImpl( ScShapeObj* pShape ): mpShape( pShape )
+ {
+ }
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const uno::Any& aElement ) override
+ {
+ if ( !hasByName( aName ) )
+ throw container::NoSuchElementException();
+ uno::Sequence< beans::PropertyValue > aProperties;
+ aElement >>= aProperties;
+ bool isEventType = false;
+ for( const beans::PropertyValue& rProperty : std::as_const(aProperties) )
+ {
+ if ( rProperty.Name == SC_EVENTACC_EVENTTYPE )
+ {
+ isEventType = true;
+ continue;
+ }
+ if ( isEventType && (rProperty.Name == SC_EVENTACC_SCRIPT) )
+ {
+ OUString sValue;
+ if ( rProperty.Value >>= sValue )
+ {
+ ScMacroInfo* pInfo = getInfo( true );
+ OSL_ENSURE( pInfo, "shape macro info could not be created!" );
+ if ( !pInfo )
+ break;
+ pInfo->SetMacro( sValue );
+ }
+ }
+ }
+ }
+
+ // XNameAccess
+ virtual uno::Any SAL_CALL getByName( const OUString& aName ) override
+ {
+ uno::Sequence< beans::PropertyValue > aProperties;
+ ScMacroInfo* pInfo = getInfo(false);
+
+ if ( aName != SC_EVENTACC_ONCLICK )
+ {
+ throw container::NoSuchElementException();
+ }
+
+ if ( pInfo && !pInfo->GetMacro().isEmpty() )
+ {
+ aProperties = { comphelper::makePropertyValue(SC_EVENTACC_EVENTTYPE,
+ OUString(SC_EVENTACC_SCRIPT)),
+ comphelper::makePropertyValue(SC_EVENTACC_SCRIPT, pInfo->GetMacro()) };
+ }
+
+ return uno::Any( aProperties );
+ }
+
+ virtual uno::Sequence< OUString > SAL_CALL getElementNames() override
+ {
+ uno::Sequence<OUString> aSeq { SC_EVENTACC_ONCLICK };
+ return aSeq;
+ }
+
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
+ {
+ return aName == SC_EVENTACC_ONCLICK;
+ }
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override
+ {
+ return cppu::UnoType<uno::Sequence< beans::PropertyValue >>::get();
+ }
+
+ virtual sal_Bool SAL_CALL hasElements() override
+ {
+ // elements are always present (but contained property sequences may be empty)
+ return true;
+ }
+};
+
+::uno::Reference< container::XNameReplace > SAL_CALL
+ScShapeObj::getEvents( )
+{
+ return new ShapeUnoEventAccessImpl( this );
+}
+
+OUString SAL_CALL ScShapeObj::getImplementationName( )
+{
+ return "com.sun.star.comp.sc.ScShapeObj";
+}
+
+sal_Bool SAL_CALL ScShapeObj::supportsService( const OUString& ServiceName )
+{
+ return cppu::supportsService(this, ServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL ScShapeObj::getSupportedServiceNames( )
+{
+ uno::Reference<lang::XServiceInfo> xSI;
+ if ( mxShapeAgg.is() )
+ mxShapeAgg->queryAggregation( cppu::UnoType<lang::XServiceInfo>::get() ) >>= xSI;
+
+ uno::Sequence< OUString > aSupported;
+ if ( xSI.is() )
+ aSupported = xSI->getSupportedServiceNames();
+
+ aSupported.realloc( aSupported.getLength() + 1 );
+ aSupported.getArray()[ aSupported.getLength() - 1 ] = "com.sun.star.sheet.Shape";
+
+ if( bIsNoteCaption )
+ {
+ aSupported.realloc( aSupported.getLength() + 1 );
+ aSupported.getArray()[ aSupported.getLength() - 1 ] = "com.sun.star.sheet.CellAnnotationShape";
+ }
+
+ return aSupported;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/srchuno.cxx b/sc/source/ui/unoobj/srchuno.cxx
new file mode 100644
index 000000000..6d765a5d4
--- /dev/null
+++ b/sc/source/ui/unoobj/srchuno.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 <scitems.hxx>
+#include <svl/srchitem.hxx>
+#include <vcl/svapp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <srchuno.hxx>
+#include <miscuno.hxx>
+#include <unonames.hxx>
+
+using namespace com::sun::star;
+
+//! SearchWords searches in whole cells - rename it ???
+
+// SfxItemPropertyMapEntry only for GetPropertySetInfo
+
+static const SfxItemPropertyMapEntry* lcl_GetSearchPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aSearchPropertyMap_Impl[] =
+ {
+ { SC_UNO_SRCHBACK, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHBYROW, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHCASE, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHREGEXP, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHWILDCARD, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHSIM, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHSIMADD, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SRCHSIMEX, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SRCHSIMREL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHSIMREM, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SRCHSTYLES, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SRCHTYPE, 0, cppu::UnoType<sal_Int16>::get(), 0, 0}, // enum TableSearch is gone
+ { SC_UNO_SRCHWORDS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aSearchPropertyMap_Impl;
+}
+
+constexpr OUStringLiteral SCSEARCHDESCRIPTOR_SERVICE = u"com.sun.star.util.SearchDescriptor";
+constexpr OUStringLiteral SCREPLACEDESCRIPTOR_SERVICE = u"com.sun.star.util.ReplaceDescriptor";
+
+ScCellSearchObj::ScCellSearchObj() :
+ aPropSet(lcl_GetSearchPropertyMap()),
+ pSearchItem( new SvxSearchItem( SCITEM_SEARCHDATA ) )
+{
+ // Defaults:
+ pSearchItem->SetWordOnly(false);
+ pSearchItem->SetExact(false);
+ pSearchItem->SetMatchFullHalfWidthForms(false);
+ pSearchItem->SetUseAsianOptions(false); // or all asian bits would have to be handled
+ pSearchItem->SetBackward(false);
+ pSearchItem->SetSelection(false);
+ pSearchItem->SetRegExp(false);
+ pSearchItem->SetWildcard(false);
+ pSearchItem->SetPattern(false);
+ pSearchItem->SetLevenshtein(false);
+ pSearchItem->SetLEVRelaxed(false);
+ pSearchItem->SetLEVOther(2);
+ pSearchItem->SetLEVShorter(2);
+ pSearchItem->SetLEVLonger(2);
+ // Calc-Flags
+ pSearchItem->SetRowDirection(false);
+ pSearchItem->SetCellType(SvxSearchCellType::FORMULA);
+
+ // Selection-Flag will be set when this is called
+}
+
+ScCellSearchObj::~ScCellSearchObj()
+{
+}
+
+// XSearchDescriptor
+
+OUString SAL_CALL ScCellSearchObj::getSearchString()
+{
+ SolarMutexGuard aGuard;
+ return pSearchItem->GetSearchString();
+}
+
+void SAL_CALL ScCellSearchObj::setSearchString( const OUString& aString )
+{
+ SolarMutexGuard aGuard;
+ pSearchItem->SetSearchString( aString );
+}
+
+// XReplaceDescriptor
+
+OUString SAL_CALL ScCellSearchObj::getReplaceString()
+{
+ SolarMutexGuard aGuard;
+ return pSearchItem->GetReplaceString();
+}
+
+void SAL_CALL ScCellSearchObj::setReplaceString( const OUString& aReplaceString )
+{
+ SolarMutexGuard aGuard;
+ pSearchItem->SetReplaceString( aReplaceString );
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScCellSearchObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScCellSearchObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if (aPropertyName == SC_UNO_SRCHBACK) pSearchItem->SetBackward( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHBYROW) pSearchItem->SetRowDirection( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHCASE) pSearchItem->SetExact( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHREGEXP) pSearchItem->SetRegExp( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHWILDCARD) pSearchItem->SetWildcard( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSIM) pSearchItem->SetLevenshtein( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSIMREL) pSearchItem->SetLEVRelaxed( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSTYLES) pSearchItem->SetPattern( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHWORDS) pSearchItem->SetWordOnly( ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSIMADD) pSearchItem->SetLEVLonger( ScUnoHelpFunctions::GetInt16FromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSIMEX) pSearchItem->SetLEVOther( ScUnoHelpFunctions::GetInt16FromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHSIMREM) pSearchItem->SetLEVShorter( ScUnoHelpFunctions::GetInt16FromAny( aValue ) );
+ else if (aPropertyName == SC_UNO_SRCHTYPE) pSearchItem->SetCellType( static_cast<SvxSearchCellType>(ScUnoHelpFunctions::GetInt16FromAny( aValue )) );
+ else if (aPropertyName == SC_UNO_SRCHFILTERED) pSearchItem->SetSearchFiltered( ScUnoHelpFunctions::GetBoolFromAny(aValue) );
+ else if (aPropertyName == SC_UNO_SRCHFORMATTED) pSearchItem->SetSearchFormatted( ScUnoHelpFunctions::GetBoolFromAny(aValue) );
+}
+
+uno::Any SAL_CALL ScCellSearchObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if (aPropertyName == SC_UNO_SRCHBACK) aRet <<= pSearchItem->GetBackward();
+ else if (aPropertyName == SC_UNO_SRCHBYROW) aRet <<= pSearchItem->GetRowDirection();
+ else if (aPropertyName == SC_UNO_SRCHCASE) aRet <<= pSearchItem->GetExact();
+ else if (aPropertyName == SC_UNO_SRCHREGEXP) aRet <<= pSearchItem->GetRegExp();
+ else if (aPropertyName == SC_UNO_SRCHWILDCARD) aRet <<= pSearchItem->GetWildcard();
+ else if (aPropertyName == SC_UNO_SRCHSIM) aRet <<= pSearchItem->IsLevenshtein();
+ else if (aPropertyName == SC_UNO_SRCHSIMREL) aRet <<= pSearchItem->IsLEVRelaxed();
+ else if (aPropertyName == SC_UNO_SRCHSTYLES) aRet <<= pSearchItem->GetPattern();
+ else if (aPropertyName == SC_UNO_SRCHWORDS) aRet <<= pSearchItem->GetWordOnly();
+ else if (aPropertyName == SC_UNO_SRCHSIMADD) aRet <<= static_cast<sal_Int16>(pSearchItem->GetLEVLonger());
+ else if (aPropertyName == SC_UNO_SRCHSIMEX) aRet <<= static_cast<sal_Int16>(pSearchItem->GetLEVOther());
+ else if (aPropertyName == SC_UNO_SRCHSIMREM) aRet <<= static_cast<sal_Int16>(pSearchItem->GetLEVShorter());
+ else if (aPropertyName == SC_UNO_SRCHTYPE) aRet <<= static_cast<sal_Int16>(pSearchItem->GetCellType());
+ else if (aPropertyName == SC_UNO_SRCHFILTERED) aRet <<= pSearchItem->IsSearchFiltered();
+ else if (aPropertyName == SC_UNO_SRCHFORMATTED) aRet <<= pSearchItem->IsSearchFormatted();
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScCellSearchObj )
+
+// XServiceInfo
+
+OUString SAL_CALL ScCellSearchObj::getImplementationName()
+{
+ return "ScCellSearchObj";
+}
+
+sal_Bool SAL_CALL ScCellSearchObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScCellSearchObj::getSupportedServiceNames()
+{
+ return {SCSEARCHDESCRIPTOR_SERVICE, SCREPLACEDESCRIPTOR_SERVICE};
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION_IMPL(ScCellSearchObj);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/styleuno.cxx b/sc/source/ui/unoobj/styleuno.cxx
new file mode 100644
index 000000000..f97129a07
--- /dev/null
+++ b/sc/source/ui/unoobj/styleuno.cxx
@@ -0,0 +1,1936 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/memberids.h>
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/numitem.hxx>
+#include <svx/pageitem.hxx>
+#include <editeng/pbinitem.hxx>
+#include <svx/unomid.hxx>
+#include <editeng/unonrule.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/sfxsids.hrc>
+#include <vcl/virdev.hxx>
+#include <vcl/svapp.hxx>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <svl/numformat.hxx>
+#include <svl/intitem.hxx>
+#include <svl/zformat.hxx>
+#include <tools/fract.hxx>
+#include <tools/UnitConversion.hxx>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/table/BorderLine.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/table/TableBorder2.hpp>
+#include <com/sun/star/table/ShadowFormat.hpp>
+#include <com/sun/star/table/CellHoriJustify.hpp>
+#include <com/sun/star/table/CellOrientation.hpp>
+#include <com/sun/star/style/PageStyleLayout.hpp>
+#include <com/sun/star/style/GraphicLocation.hpp>
+#include <com/sun/star/sheet/XHeaderFooterContent.hpp>
+#include <com/sun/star/util/CellProtection.hpp>
+#include <com/sun/star/awt/FontSlant.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/Locale.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <comphelper/propertysequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+#include <styleuno.hxx>
+#include <docsh.hxx>
+#include <attrib.hxx>
+#include <stlpool.hxx>
+#include <docpool.hxx>
+#include <miscuno.hxx>
+#include <tablink.hxx>
+#include <unonames.hxx>
+#include <unowids.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <cellsuno.hxx>
+#include <stylehelper.hxx>
+
+using namespace ::com::sun::star;
+
+static const SfxItemPropertySet* lcl_GetCellStyleSet()
+{
+ static const SfxItemPropertyMapEntry aCellStyleMap_Impl[] =
+ {
+ {u"" SC_UNONAME_ASIANVERT,ATTR_VERTICAL_ASIAN,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_BOTTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNONAME_BOTTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNONAME_CELLBACK, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {u"" SC_UNONAME_CELLPRO, ATTR_PROTECTION, ::cppu::UnoType<util::CellProtection>::get(), 0, 0 },
+ {u"" SC_UNONAME_CCOLOR, ATTR_FONT_COLOR, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNONAME_COUTL, ATTR_FONT_CONTOUR, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_CCROSS, ATTR_FONT_CROSSEDOUT,cppu::UnoType<bool>::get(), 0, MID_CROSSED_OUT },
+ {u"" SC_UNONAME_CEMPHAS, ATTR_FONT_EMPHASISMARK,cppu::UnoType<sal_Int16>::get(), 0, MID_EMPHASIS },
+ {u"" SC_UNONAME_CFONT, ATTR_FONT, ::cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ {u"" SC_UNONAME_CFCHARS, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ {u"" SC_UNO_CJK_CFCHARS, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ {u"" SC_UNO_CTL_CFCHARS, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_CHAR_SET },
+ {u"" SC_UNONAME_CFFAMIL, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ {u"" SC_UNO_CJK_CFFAMIL, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ {u"" SC_UNO_CTL_CFFAMIL, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_FAMILY },
+ {u"" SC_UNONAME_CFNAME, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ {u"" SC_UNO_CJK_CFNAME, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ {u"" SC_UNO_CTL_CFNAME, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_FAMILY_NAME },
+ {u"" SC_UNONAME_CFPITCH, ATTR_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ {u"" SC_UNO_CJK_CFPITCH, ATTR_CJK_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ {u"" SC_UNO_CTL_CFPITCH, ATTR_CTL_FONT, cppu::UnoType<sal_Int16>::get(), 0, MID_FONT_PITCH },
+ {u"" SC_UNONAME_CFSTYLE, ATTR_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ {u"" SC_UNO_CJK_CFSTYLE, ATTR_CJK_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ {u"" SC_UNO_CTL_CFSTYLE, ATTR_CTL_FONT, cppu::UnoType<OUString>::get(), 0, MID_FONT_STYLE_NAME },
+ {u"" SC_UNONAME_CHEIGHT, ATTR_FONT_HEIGHT, ::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ {u"" SC_UNO_CJK_CHEIGHT, ATTR_CJK_FONT_HEIGHT,::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ {u"" SC_UNO_CTL_CHEIGHT, ATTR_CTL_FONT_HEIGHT,::cppu::UnoType<float>::get(), 0, MID_FONTHEIGHT | CONVERT_TWIPS },
+ {u"" SC_UNONAME_CLOCAL, ATTR_FONT_LANGUAGE, ::cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ {u"" SC_UNO_CJK_CLOCAL, ATTR_CJK_FONT_LANGUAGE,::cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ {u"" SC_UNO_CTL_CLOCAL, ATTR_CTL_FONT_LANGUAGE,::cppu::UnoType<lang::Locale>::get(), 0, MID_LANG_LOCALE },
+ {u"" SC_UNONAME_COVER, ATTR_FONT_OVERLINE, ::cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ {u"" SC_UNONAME_COVRLCOL, ATTR_FONT_OVERLINE, cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ {u"" SC_UNONAME_COVRLHAS, ATTR_FONT_OVERLINE, cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ {u"" SC_UNONAME_CPOST, ATTR_FONT_POSTURE, ::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ {u"" SC_UNO_CJK_CPOST, ATTR_CJK_FONT_POSTURE,::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ {u"" SC_UNO_CTL_CPOST, ATTR_CTL_FONT_POSTURE,::cppu::UnoType<awt::FontSlant>::get(), 0, MID_POSTURE },
+ {u"" SC_UNONAME_CRELIEF, ATTR_FONT_RELIEF, cppu::UnoType<sal_Int16>::get(), 0, MID_RELIEF },
+ {u"" SC_UNONAME_CSHADD, ATTR_FONT_SHADOWED, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_CSTRIKE, ATTR_FONT_CROSSEDOUT,cppu::UnoType<sal_Int16>::get(), 0, MID_CROSS_OUT },
+ {u"" SC_UNONAME_CUNDER, ATTR_FONT_UNDERLINE,::cppu::UnoType<sal_Int16>::get(), 0, MID_TL_STYLE },
+ {u"" SC_UNONAME_CUNDLCOL, ATTR_FONT_UNDERLINE,cppu::UnoType<sal_Int32>::get(), 0, MID_TL_COLOR },
+ {u"" SC_UNONAME_CUNDLHAS, ATTR_FONT_UNDERLINE,cppu::UnoType<bool>::get(), 0, MID_TL_HASCOLOR },
+ {u"" SC_UNONAME_CWEIGHT, ATTR_FONT_WEIGHT, ::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ {u"" SC_UNO_CJK_CWEIGHT, ATTR_CJK_FONT_WEIGHT,::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ {u"" SC_UNO_CTL_CWEIGHT, ATTR_CTL_FONT_WEIGHT,::cppu::UnoType<float>::get(), 0, MID_WEIGHT },
+ {u"" SC_UNONAME_CWORDMOD, ATTR_FONT_WORDLINE, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_DIAGONAL_BLTR, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ {u"" SC_UNONAME_DIAGONAL_BLTR2, ATTR_BORDER_BLTR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ {u"" SC_UNONAME_DIAGONAL_TLBR, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine>::get(), 0, 0 | CONVERT_TWIPS },
+ {u"" SC_UNONAME_DIAGONAL_TLBR2, ATTR_BORDER_TLBR, ::cppu::UnoType<table::BorderLine2>::get(), 0, 0 | CONVERT_TWIPS },
+ {u"" SC_UNONAME_DISPNAME, SC_WID_UNO_DISPNAME,::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ {u"" SC_UNONAME_CELLHJUS, ATTR_HOR_JUSTIFY, ::cppu::UnoType<table::CellHoriJustify>::get(), 0, MID_HORJUST_HORJUST },
+ {u"" SC_UNONAME_CELLHJUS_METHOD, ATTR_HOR_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNONAME_CELLTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ {u"" SC_UNONAME_WRAP, ATTR_LINEBREAK, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_LEFTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNONAME_LEFTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNONAME_NUMFMT, ATTR_VALUE_FORMAT, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+// {SC_UNONAME_NUMRULES, SC_WID_UNO_NUMRULES,cppu::UnoType<container::XIndexReplace>::get(), 0, 0 },
+ {u"" SC_UNONAME_CELLORI, ATTR_STACKED, ::cppu::UnoType<table::CellOrientation>::get(), 0, 0 },
+ {u"" SC_UNONAME_PADJUST, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ {u"" SC_UNONAME_PBMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_LO_MARGIN | CONVERT_TWIPS },
+ {u"" SC_UNONAME_PINDENT, ATTR_INDENT, ::cppu::UnoType<sal_Int16>::get(), 0, 0 }, //! CONVERT_TWIPS
+ {u"" SC_UNONAME_PISCHDIST,ATTR_SCRIPTSPACE, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_PISFORBID,ATTR_FORBIDDEN_RULES,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_PISHANG, ATTR_HANGPUNCTUATION,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_PISHYPHEN,ATTR_HYPHENATE, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_PLASTADJ, ATTR_HOR_JUSTIFY, ::cppu::UnoType<sal_Int16>::get(), 0, MID_HORJUST_ADJUST },
+ {u"" SC_UNONAME_PLMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_L_MARGIN | CONVERT_TWIPS },
+ {u"" SC_UNONAME_PRMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_R_MARGIN | CONVERT_TWIPS },
+ {u"" SC_UNONAME_PTMARGIN, ATTR_MARGIN, ::cppu::UnoType<sal_Int32>::get(), 0, MID_MARGIN_UP_MARGIN | CONVERT_TWIPS },
+ {u"" SC_UNONAME_RIGHTBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNONAME_RIGHTBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNONAME_ROTANG, ATTR_ROTATE_VALUE, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNONAME_ROTREF, ATTR_ROTATE_MODE, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNONAME_SHADOW, ATTR_SHADOW, ::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ {u"" SC_UNONAME_SHRINK_TO_FIT, ATTR_SHRINKTOFIT, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD, ::cppu::UnoType<table::TableBorder>::get(), 0, 0 | CONVERT_TWIPS },
+ {u"" SC_UNONAME_TBLBORD, SC_WID_UNO_TBLBORD2, ::cppu::UnoType<table::TableBorder2>::get(), 0, 0 | CONVERT_TWIPS },
+ {u"" SC_UNONAME_TOPBORDER,ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNONAME_TOPBORDER2,ATTR_BORDER, ::cppu::UnoType<table::BorderLine2>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ {u"" SC_UNONAME_CELLVJUS, ATTR_VER_JUSTIFY, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNONAME_CELLVJUS_METHOD, ATTR_VER_JUSTIFY_METHOD, ::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {u"" SC_UNONAME_HIDDEN, ATTR_HIDDEN, cppu::UnoType<sal_Bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_HYPERLINK, ATTR_HYPERLINK, cppu::UnoType<OUString>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aCellStyleSet_Impl( aCellStyleMap_Impl );
+ return &aCellStyleSet_Impl;
+}
+
+// map with all site attributes including header and footer attributes
+
+static const SfxItemPropertySet * lcl_GetPageStyleSet()
+{
+ static const SfxItemPropertyMapEntry aPageStyleMap_Impl[] =
+ {
+ {u"" SC_UNO_PAGE_BACKCOLOR, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {u"" SC_UNO_PAGE_GRAPHICFILT, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_FILTER },
+ {u"" SC_UNO_PAGE_GRAPHICLOC, ATTR_BACKGROUND, ::cppu::UnoType<style::GraphicLocation>::get(), 0, MID_GRAPHIC_POSITION },
+ {u"" SC_UNO_PAGE_GRAPHICURL, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_URL },
+ {u"" SC_UNO_PAGE_GRAPHIC, ATTR_BACKGROUND, ::cppu::UnoType<graphic::XGraphic>::get(), 0, MID_GRAPHIC },
+ {u"" SC_UNO_PAGE_BACKTRANS, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ {u"" OLD_UNO_PAGE_BACKCOLOR, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {u"" SC_UNO_PAGE_BORDERDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_BOTTBORDER, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_BOTTBRDDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_BOTTMARGIN, ATTR_ULSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_LO_MARGIN | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_CENTERHOR, ATTR_PAGE_HORCENTER,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_CENTERVER, ATTR_PAGE_VERCENTER,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_DISPNAME, SC_WID_UNO_DISPNAME,::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ {u"" SC_UNO_PAGE_FIRSTPAGE, ATTR_PAGE_FIRSTPAGENO,::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FIRSTFTRSHARED, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FIRSTHDRSHARED, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FIRSTFTRCONT, ATTR_PAGE_FOOTERFIRST,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FIRSTHDRCONT, ATTR_PAGE_HEADERFIRST,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+
+ {u"" SC_UNO_PAGE_FTRBACKCOL, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRGRFFILT, SC_WID_UNO_FOOTERSET,::cppu::UnoType<OUString>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRGRFLOC, SC_WID_UNO_FOOTERSET,::cppu::UnoType<style::GraphicLocation>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRGRFURL, SC_WID_UNO_FOOTERSET,::cppu::UnoType<OUString>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRGRF, SC_WID_UNO_FOOTERSET,::cppu::UnoType<graphic::XGraphic>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRBACKTRAN, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" OLD_UNO_PAGE_FTRBACKCOL, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRBODYDIST, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRBRDDIST, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRBOTTBOR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRBOTTBDIS, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" OLD_UNO_PAGE_FTRDYNAMIC, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRHEIGHT, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRDYNAMIC, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRON, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRSHARED, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRLEFTBOR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRLEFTBDIS, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRLEFTMAR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" OLD_UNO_PAGE_FTRON, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRRIGHTBOR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRRIGHTBDIS,SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRRIGHTMAR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRSHADOW, SC_WID_UNO_FOOTERSET,::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 },
+ {u"" OLD_UNO_PAGE_FTRSHARED, SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRTOPBOR, SC_WID_UNO_FOOTERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRTOPBDIS, SC_WID_UNO_FOOTERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+
+ {u"" SC_UNO_PAGE_HDRBACKCOL, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRGRFFILT, SC_WID_UNO_HEADERSET,::cppu::UnoType<OUString>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRGRFLOC, SC_WID_UNO_HEADERSET,::cppu::UnoType<style::GraphicLocation>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRGRFURL, SC_WID_UNO_HEADERSET,::cppu::UnoType<OUString>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRGRF, SC_WID_UNO_HEADERSET,::cppu::UnoType<graphic::XGraphic>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRBACKTRAN, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" OLD_UNO_PAGE_HDRBACKCOL, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRBODYDIST, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRBRDDIST, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRBOTTBOR, SC_WID_UNO_HEADERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRBOTTBDIS, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" OLD_UNO_PAGE_HDRDYNAMIC, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRHEIGHT, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRDYNAMIC, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRON, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRSHARED, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRLEFTBOR, SC_WID_UNO_HEADERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRLEFTBDIS, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRLEFTMAR, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" OLD_UNO_PAGE_HDRON, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRRIGHTBOR, SC_WID_UNO_HEADERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRRIGHTBDIS,SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRRIGHTMAR, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRSHADOW, SC_WID_UNO_HEADERSET,::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 },
+ {u"" OLD_UNO_PAGE_HDRSHARED, SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRTOPBOR, SC_WID_UNO_HEADERSET,::cppu::UnoType<table::BorderLine>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRTOPBDIS, SC_WID_UNO_HEADERSET,::cppu::UnoType<sal_Int32>::get(), 0, 0 },
+
+ {u"" SC_UNO_PAGE_HEIGHT, ATTR_PAGE_SIZE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_SIZE_HEIGHT | CONVERT_TWIPS },
+ {u"" OLD_UNO_PAGE_BACKTRANS, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ {u"" SC_UNO_PAGE_LANDSCAPE, ATTR_PAGE, cppu::UnoType<bool>::get(), 0, MID_PAGE_ORIENTATION },
+ {u"" SC_UNO_PAGE_LEFTBORDER, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_LEFTBRDDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_LEFTMARGIN, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_L_MARGIN | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_LEFTFTRCONT, ATTR_PAGE_FOOTERLEFT,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_LEFTHDRCONT, ATTR_PAGE_HEADERLEFT,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_NUMBERTYPE, ATTR_PAGE, ::cppu::UnoType<sal_Int16>::get(), 0, MID_PAGE_NUMTYPE },
+ {u"" SC_UNO_PAGE_SCALEVAL, ATTR_PAGE_SCALE, ::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_SYTLELAYOUT, ATTR_PAGE, ::cppu::UnoType<style::PageStyleLayout>::get(), 0, MID_PAGE_LAYOUT },
+ {u"" SC_UNO_PAGE_PRINTANNOT, ATTR_PAGE_NOTES, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_PRINTCHARTS, ATTR_PAGE_CHARTS, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_PRINTDOWN, ATTR_PAGE_TOPDOWN, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_PRINTDRAW, ATTR_PAGE_DRAWINGS, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_PRINTFORMUL, ATTR_PAGE_FORMULAS, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_PRINTGRID, ATTR_PAGE_GRID, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_PRINTHEADER, ATTR_PAGE_HEADERS, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_PRINTOBJS, ATTR_PAGE_OBJECTS, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_PRINTZERO, ATTR_PAGE_NULLVALS, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_PAPERTRAY, ATTR_PAGE_PAPERBIN, ::cppu::UnoType<OUString>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_RIGHTBORDER, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_RIGHTBRDDIST,ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_RIGHTMARGIN, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_R_MARGIN | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_RIGHTFTRCON, ATTR_PAGE_FOOTERRIGHT,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_RIGHTHDRCON, ATTR_PAGE_HEADERRIGHT,cppu::UnoType<sheet::XHeaderFooterContent>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_SCALETOPAG, ATTR_PAGE_SCALETOPAGES,::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_SCALETOX, ATTR_PAGE_SCALETO, ::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_SCALETOY, ATTR_PAGE_SCALETO, ::cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_SHADOWFORM, ATTR_SHADOW, ::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_SIZE, ATTR_PAGE_SIZE, ::cppu::UnoType<awt::Size>::get(), 0, MID_SIZE_SIZE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_TOPBORDER, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_TOPBRDDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_TOPMARGIN, ATTR_ULSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_UP_MARGIN | CONVERT_TWIPS },
+ {u"" OLD_UNO_PAGE_FTRBACKTRAN,SC_WID_UNO_FOOTERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" OLD_UNO_PAGE_HDRBACKTRAN,SC_WID_UNO_HEADERSET,cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNONAME_USERDEF, ATTR_USERDEF, cppu::UnoType<container::XNameContainer>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_WIDTH, ATTR_PAGE_SIZE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_SIZE_WIDTH | CONVERT_TWIPS },
+ {u"" SC_UNONAME_WRITING, ATTR_WRITINGDIR, cppu::UnoType<sal_Int16>::get(), 0, 0 },
+ {u"" SC_UNONAME_HIDDEN, ATTR_HIDDEN, cppu::UnoType<sal_Bool>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertySet aPageStyleSet_Impl( aPageStyleMap_Impl );
+ return &aPageStyleSet_Impl;
+}
+
+// map with content of the Header-Item-Sets
+
+static const SfxItemPropertyMap* lcl_GetHeaderStyleMap()
+{
+ static const SfxItemPropertyMapEntry aHeaderStyleMap_Impl[] =
+ {
+ {u"" SC_UNO_PAGE_HDRBACKCOL, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {u"" SC_UNO_PAGE_HDRGRFFILT, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_FILTER },
+ {u"" SC_UNO_PAGE_HDRGRFLOC, ATTR_BACKGROUND, ::cppu::UnoType<style::GraphicLocation>::get(), 0, MID_GRAPHIC_POSITION },
+ {u"" SC_UNO_PAGE_HDRGRFURL, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_URL },
+ {u"" SC_UNO_PAGE_HDRGRF, ATTR_BACKGROUND, ::cppu::UnoType<graphic::XGraphic>::get(), 0, MID_GRAPHIC },
+ {u"" SC_UNO_PAGE_HDRBACKTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ {u"" OLD_UNO_PAGE_HDRBACKCOL, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {u"" SC_UNO_PAGE_HDRBODYDIST, ATTR_ULSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_LO_MARGIN | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_HDRBRDDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_HDRBOTTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_HDRBOTTBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" OLD_UNO_PAGE_HDRDYNAMIC, ATTR_PAGE_DYNAMIC, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRHEIGHT, ATTR_PAGE_SIZE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_SIZE_HEIGHT | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_HDRDYNAMIC, ATTR_PAGE_DYNAMIC, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRON, ATTR_PAGE_ON, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRSHARED, ATTR_PAGE_SHARED, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FIRSTHDRSHARED, ATTR_PAGE_SHARED_FIRST, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRLEFTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_HDRLEFTBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_HDRLEFTMAR, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_L_MARGIN | CONVERT_TWIPS },
+ {u"" OLD_UNO_PAGE_HDRON, ATTR_PAGE_ON, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRRIGHTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_HDRRIGHTBDIS,ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_HDRRIGHTMAR, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_R_MARGIN | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_HDRSHADOW, ATTR_SHADOW, ::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ {u"" OLD_UNO_PAGE_HDRSHARED, ATTR_PAGE_SHARED, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_HDRTOPBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_HDRTOPBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" OLD_UNO_PAGE_HDRBACKTRAN,ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertyMap aHeaderStyleMap( aHeaderStyleMap_Impl );
+ return &aHeaderStyleMap;
+}
+
+// map with content of the Footer-Item-Sets
+
+static const SfxItemPropertyMap* lcl_GetFooterStyleMap()
+{
+ static const SfxItemPropertyMapEntry aFooterStyleMap_Impl[] =
+ {
+ {u"" SC_UNO_PAGE_FTRBACKCOL, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {u"" SC_UNO_PAGE_FTRGRFFILT, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_FILTER },
+ {u"" SC_UNO_PAGE_FTRGRFLOC, ATTR_BACKGROUND, ::cppu::UnoType<style::GraphicLocation>::get(), 0, MID_GRAPHIC_POSITION },
+ {u"" SC_UNO_PAGE_FTRGRFURL, ATTR_BACKGROUND, ::cppu::UnoType<OUString>::get(), 0, MID_GRAPHIC_URL },
+ {u"" SC_UNO_PAGE_FTRGRF, ATTR_BACKGROUND, ::cppu::UnoType<graphic::XGraphic>::get(), 0, MID_GRAPHIC },
+ {u"" SC_UNO_PAGE_FTRBACKTRAN, ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ {u"" OLD_UNO_PAGE_FTRBACKCOL, ATTR_BACKGROUND, ::cppu::UnoType<sal_Int32>::get(), 0, MID_BACK_COLOR },
+ {u"" SC_UNO_PAGE_FTRBODYDIST, ATTR_ULSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_UP_MARGIN | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_FTRBRDDIST, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_FTRBOTTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, BOTTOM_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_FTRBOTTBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, BOTTOM_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" OLD_UNO_PAGE_FTRDYNAMIC, ATTR_PAGE_DYNAMIC, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRHEIGHT, ATTR_PAGE_SIZE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_SIZE_HEIGHT | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_FTRDYNAMIC, ATTR_PAGE_DYNAMIC, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRON, ATTR_PAGE_ON, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRSHARED, ATTR_PAGE_SHARED, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FIRSTFTRSHARED, ATTR_PAGE_SHARED_FIRST, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRLEFTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, LEFT_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_FTRLEFTBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, LEFT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_FTRLEFTMAR, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_L_MARGIN | CONVERT_TWIPS },
+ {u"" OLD_UNO_PAGE_FTRON, ATTR_PAGE_ON, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRRIGHTBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, RIGHT_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_FTRRIGHTBDIS,ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, RIGHT_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_FTRRIGHTMAR, ATTR_LRSPACE, ::cppu::UnoType<sal_Int32>::get(), 0, MID_R_MARGIN | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_FTRSHADOW, ATTR_SHADOW, ::cppu::UnoType<table::ShadowFormat>::get(), 0, 0 | CONVERT_TWIPS },
+ {u"" OLD_UNO_PAGE_FTRSHARED, ATTR_PAGE_SHARED, cppu::UnoType<bool>::get(), 0, 0 },
+ {u"" SC_UNO_PAGE_FTRTOPBOR, ATTR_BORDER, ::cppu::UnoType<table::BorderLine>::get(), 0, TOP_BORDER | CONVERT_TWIPS },
+ {u"" SC_UNO_PAGE_FTRTOPBDIS, ATTR_BORDER, ::cppu::UnoType<sal_Int32>::get(), 0, TOP_BORDER_DISTANCE | CONVERT_TWIPS },
+ {u"" OLD_UNO_PAGE_FTRBACKTRAN,ATTR_BACKGROUND, cppu::UnoType<bool>::get(), 0, MID_GRAPHIC_TRANSPARENT },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ static SfxItemPropertyMap aFooterStyleMap( aFooterStyleMap_Impl );
+ return &aFooterStyleMap;
+}
+
+// access index on the style types: 0 = Cell, 1 = Page
+
+#define SC_STYLE_FAMILY_COUNT 2
+
+constexpr OUStringLiteral SC_FAMILYNAME_CELL = u"CellStyles";
+constexpr OUStringLiteral SC_FAMILYNAME_PAGE = u"PageStyles";
+
+const SfxStyleFamily aStyleFamilyTypes[SC_STYLE_FAMILY_COUNT] = { SfxStyleFamily::Para, SfxStyleFamily::Page };
+
+constexpr OUStringLiteral SCSTYLE_SERVICE = u"com.sun.star.style.Style";
+constexpr OUStringLiteral SCCELLSTYLE_SERVICE = u"com.sun.star.style.CellStyle";
+constexpr OUStringLiteral SCPAGESTYLE_SERVICE = u"com.sun.star.style.PageStyle";
+
+SC_SIMPLE_SERVICE_INFO( ScStyleFamiliesObj, "ScStyleFamiliesObj", "com.sun.star.style.StyleFamilies" )
+SC_SIMPLE_SERVICE_INFO( ScStyleFamilyObj, "ScStyleFamilyObj", "com.sun.star.style.StyleFamily" )
+
+constexpr OUStringLiteral SC_PAPERBIN_DEFAULTNAME = u"[From printer settings]";
+
+static bool lcl_AnyTabProtected( const ScDocument& rDoc )
+{
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB i=0; i<nTabCount; i++)
+ if (rDoc.IsTabProtected(i))
+ return true;
+ return false;
+}
+
+ScStyleFamiliesObj::ScStyleFamiliesObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScStyleFamiliesObj::~ScStyleFamiliesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScStyleFamiliesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr;
+ }
+}
+
+// XStyleFamilies
+
+rtl::Reference<ScStyleFamilyObj> ScStyleFamiliesObj::GetObjectByType_Impl(SfxStyleFamily nType) const
+{
+ if ( pDocShell )
+ {
+ if ( nType == SfxStyleFamily::Para )
+ return new ScStyleFamilyObj( pDocShell, SfxStyleFamily::Para );
+ else if ( nType == SfxStyleFamily::Page )
+ return new ScStyleFamilyObj( pDocShell, SfxStyleFamily::Page );
+ }
+ OSL_FAIL("getStyleFamilyByType: no DocShell or wrong SfxStyleFamily");
+ return nullptr;
+}
+
+rtl::Reference<ScStyleFamilyObj> ScStyleFamiliesObj::GetObjectByIndex_Impl(sal_uInt32 nIndex) const
+{
+ if ( nIndex < SC_STYLE_FAMILY_COUNT )
+ return GetObjectByType_Impl(aStyleFamilyTypes[nIndex]);
+
+ return nullptr; // invalid index
+}
+
+rtl::Reference<ScStyleFamilyObj> ScStyleFamiliesObj::GetObjectByName_Impl(std::u16string_view aName) const
+{
+ if ( pDocShell )
+ {
+ if ( aName == SC_FAMILYNAME_CELL )
+ return new ScStyleFamilyObj( pDocShell, SfxStyleFamily::Para );
+ else if ( aName == SC_FAMILYNAME_PAGE )
+ return new ScStyleFamilyObj( pDocShell, SfxStyleFamily::Page );
+ }
+ // no assertion - called directly from getByName
+ return nullptr;
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScStyleFamiliesObj::getCount()
+{
+ return SC_STYLE_FAMILY_COUNT;
+}
+
+uno::Any SAL_CALL ScStyleFamiliesObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XNameContainer > xFamily(GetObjectByIndex_Impl(nIndex));
+ if (!xFamily.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xFamily);
+}
+
+uno::Type SAL_CALL ScStyleFamiliesObj::getElementType()
+{
+ return cppu::UnoType<container::XNameContainer>::get(); // has to fit to getByIndex
+}
+
+sal_Bool SAL_CALL ScStyleFamiliesObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// container::XNameAccess
+
+uno::Any SAL_CALL ScStyleFamiliesObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< container::XNameContainer > xFamily(GetObjectByName_Impl(aName));
+ if (!xFamily.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xFamily);
+}
+
+uno::Sequence<OUString> SAL_CALL ScStyleFamiliesObj::getElementNames()
+{
+ return {SC_FAMILYNAME_CELL, SC_FAMILYNAME_PAGE};
+}
+
+sal_Bool SAL_CALL ScStyleFamiliesObj::hasByName( const OUString& aName )
+{
+ return aName == SC_FAMILYNAME_CELL || aName == SC_FAMILYNAME_PAGE;
+}
+
+// style::XStyleLoader
+
+void SAL_CALL ScStyleFamiliesObj::loadStylesFromURL( const OUString& aURL,
+ const uno::Sequence<beans::PropertyValue>& aOptions )
+{
+ //! use aOptions (like Writer)
+ //! set flag to disable filter option dialogs when importing
+
+ OUString aFilter; // empty - detect
+ OUString aFiltOpt;
+ uno::Reference<io::XInputStream> xInputStream;
+ if (aURL == "private:stream")
+ {
+ for (const auto& rProp : aOptions)
+ {
+ if (rProp.Name == "InputStream")
+ {
+ rProp.Value >>= xInputStream;
+ if (!xInputStream.is())
+ {
+ throw lang::IllegalArgumentException(
+ "Parameter 'InputStream' could not be converted "
+ "to type 'com::sun::star::io::XInputStream'",
+ nullptr, 0);
+ }
+ break;
+ }
+ }
+ }
+
+ ScDocumentLoader aLoader( aURL, aFilter, aFiltOpt, 0, nullptr, xInputStream );
+
+ ScDocShell* pSource = aLoader.GetDocShell();
+
+ loadStylesFromDocShell(pSource, aOptions);
+}
+
+uno::Sequence<beans::PropertyValue> SAL_CALL ScStyleFamiliesObj::getStyleLoaderOptions()
+{
+ // return defaults for options (?)
+ return comphelper::InitPropertySequence({
+ { SC_UNONAME_OVERWSTL, uno::Any(true) },
+ { SC_UNONAME_LOADCELL, uno::Any(true) },
+ { SC_UNONAME_LOADPAGE, uno::Any(true) }
+ });
+}
+
+// style::XStyleLoader2
+
+void SAL_CALL ScStyleFamiliesObj::loadStylesFromDocument( const uno::Reference < lang::XComponent > & aSourceComponent,
+ const uno::Sequence<beans::PropertyValue>& aOptions )
+{
+ // Source document docShell
+ if ( !aSourceComponent.is() )
+ throw uno::RuntimeException();
+
+ ScDocShell* pDocShellSrc = dynamic_cast<ScDocShell*> (SfxObjectShell::GetShellFromComponent(aSourceComponent));
+
+ loadStylesFromDocShell(pDocShellSrc, aOptions);
+}
+
+// private
+
+void ScStyleFamiliesObj::loadStylesFromDocShell( ScDocShell* pSource,
+ const uno::Sequence<beans::PropertyValue>& aOptions )
+{
+
+ if ( !(pSource && pDocShell) )
+ return;
+
+ // collect options
+
+ bool bLoadReplace = true; // defaults
+ bool bLoadCellStyles = true;
+ bool bLoadPageStyles = true;
+
+ for (const beans::PropertyValue& rProp : aOptions)
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == SC_UNONAME_OVERWSTL)
+ bLoadReplace = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_LOADCELL)
+ bLoadCellStyles = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_LOADPAGE)
+ bLoadPageStyles = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ }
+
+ pDocShell->LoadStylesArgs( *pSource, bLoadReplace, bLoadCellStyles, bLoadPageStyles );
+ pDocShell->SetDocumentModified(); // paint is inside LoadStyles
+}
+
+ScStyleFamilyObj::ScStyleFamilyObj(ScDocShell* pDocSh, SfxStyleFamily eFam) :
+ pDocShell( pDocSh ),
+ eFamily( eFam )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScStyleFamilyObj::~ScStyleFamilyObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScStyleFamilyObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // has become invalid
+ }
+}
+
+// XStyleFamily
+
+rtl::Reference<ScStyleObj> ScStyleFamilyObj::GetObjectByIndex_Impl(sal_Int32 nIndex)
+{
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+
+ SfxStyleSheetIterator aIter( pStylePool, eFamily );
+ if ( nIndex < aIter.Count() )
+ {
+ SfxStyleSheetBase* pStyle = aIter[nIndex];
+ if ( pStyle )
+ {
+ return new ScStyleObj( pDocShell, eFamily, pStyle->GetName() );
+ }
+ }
+ }
+ return nullptr;
+}
+
+rtl::Reference<ScStyleObj> ScStyleFamilyObj::GetObjectByName_Impl(const OUString& aName)
+{
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ if ( pStylePool->Find( aName, eFamily ) )
+ return new ScStyleObj( pDocShell, eFamily, aName );
+ }
+ return nullptr;
+}
+
+void SAL_CALL ScStyleFamilyObj::insertByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ bool bDone = false;
+ // reflection does not need to be uno::XInterface, can be any interface...
+ uno::Reference< uno::XInterface > xInterface(aElement, uno::UNO_QUERY);
+ if ( xInterface.is() )
+ {
+ ScStyleObj* pStyleObj = comphelper::getFromUnoTunnel<ScStyleObj>( xInterface );
+ if ( pStyleObj && pStyleObj->GetFamily() == eFamily &&
+ !pStyleObj->IsInserted() ) // not yet inserted?
+ {
+ OUString aNameStr(ScStyleNameConversion::ProgrammaticToDisplayName( aName, eFamily ));
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+
+ //! DocFunc function ???
+ //! Undo ?????????????
+
+ if ( pStylePool->Find( aNameStr, eFamily ) ) // not available yet
+ throw container::ElementExistException();
+
+ (void)pStylePool->Make( aNameStr, eFamily, SfxStyleSearchBits::UserDefined );
+
+ if ( eFamily == SfxStyleFamily::Para && !rDoc.IsImportingXML() )
+ rDoc.GetPool()->CellStyleCreated( aNameStr, rDoc );
+
+ pStyleObj->InitDoc( pDocShell, aNameStr ); // object can be used
+
+ if (!rDoc.IsImportingXML())
+ pDocShell->SetDocumentModified(); // new style not used yet
+ bDone = true;
+
+ }
+ }
+
+ if (!bDone)
+ {
+ // other errors are handled above
+ throw lang::IllegalArgumentException();
+ }
+}
+
+void SAL_CALL ScStyleFamilyObj::replaceByName( const OUString& aName, const uno::Any& aElement )
+{
+ SolarMutexGuard aGuard;
+ //! combine?
+ removeByName( aName );
+ insertByName( aName, aElement );
+}
+
+void SAL_CALL ScStyleFamilyObj::removeByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ bool bFound = false;
+ if ( pDocShell )
+ {
+ OUString aString(ScStyleNameConversion::ProgrammaticToDisplayName( aName, eFamily ));
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+
+ //! DocFunc function??
+ //! Undo ?????????????
+
+ SfxStyleSheetBase* pStyle = pStylePool->Find( aString, eFamily );
+ if (pStyle)
+ {
+ bFound = true;
+ if ( eFamily == SfxStyleFamily::Para )
+ {
+ // like ScViewFunc::RemoveStyleSheetInUse
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Point aLogic = pVDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
+ double nPPTX = aLogic.X() / 1000.0;
+ double nPPTY = aLogic.Y() / 1000.0;
+ Fraction aZoom(1,1);
+ rDoc.StyleSheetChanged( pStyle, false, pVDev, nPPTX, nPPTY, aZoom, aZoom );
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+ pDocShell->SetDocumentModified();
+
+ pStylePool->Remove( pStyle );
+
+ //! InvalidateAttribs(); // Bindings-Invalidate
+ }
+ else
+ {
+ if ( rDoc.RemovePageStyleInUse( aString ) )
+ pDocShell->PageStyleModified( ScResId(STR_STYLENAME_STANDARD), true );
+
+ pStylePool->Remove( pStyle );
+
+ SfxBindings* pBindings = pDocShell->GetViewBindings();
+ if (pBindings)
+ pBindings->Invalidate( SID_STYLE_FAMILY4 );
+ pDocShell->SetDocumentModified();
+ }
+ }
+ }
+
+ if (!bFound)
+ throw container::NoSuchElementException();
+}
+
+// container::XIndexAccess
+
+sal_Int32 SAL_CALL ScStyleFamilyObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+
+ SfxStyleSheetIterator aIter( pStylePool, eFamily );
+ return aIter.Count();
+ }
+ return 0;
+}
+
+uno::Any SAL_CALL ScStyleFamilyObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< style::XStyle > xObj(GetObjectByIndex_Impl(nIndex));
+ if (!xObj.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xObj);
+}
+
+uno::Type SAL_CALL ScStyleFamilyObj::getElementType()
+{
+ return cppu::UnoType<style::XStyle>::get(); // has to fit to getByIndex
+}
+
+sal_Bool SAL_CALL ScStyleFamilyObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// container::XNameAccess
+
+uno::Any SAL_CALL ScStyleFamilyObj::getByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference< style::XStyle > xObj(
+ GetObjectByName_Impl( ScStyleNameConversion::ProgrammaticToDisplayName( aName, eFamily ) ));
+ if (!xObj.is())
+ throw container::NoSuchElementException();
+
+ return uno::Any(xObj);
+}
+
+uno::Sequence<OUString> SAL_CALL ScStyleFamilyObj::getElementNames()
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+
+ SfxStyleSheetIterator aIter( pStylePool, eFamily );
+ sal_uInt16 nCount = aIter.Count();
+
+ uno::Sequence<OUString> aSeq(nCount);
+ OUString* pAry = aSeq.getArray();
+ SfxStyleSheetBase* pStyle = aIter.First();
+ sal_uInt16 nPos = 0;
+ while (pStyle)
+ {
+ OSL_ENSURE( nPos < nCount, "Count is wrong" );
+ if (nPos < nCount)
+ pAry[nPos++] = ScStyleNameConversion::DisplayToProgrammaticName(
+ pStyle->GetName(), eFamily );
+ pStyle = aIter.Next();
+ }
+ return aSeq;
+ }
+ return uno::Sequence<OUString>();
+}
+
+sal_Bool SAL_CALL ScStyleFamilyObj::hasByName( const OUString& aName )
+{
+ SolarMutexGuard aGuard;
+ if ( pDocShell )
+ {
+ OUString aString(ScStyleNameConversion::ProgrammaticToDisplayName( aName, eFamily ));
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ if ( pStylePool->Find( aString, eFamily ) )
+ return true;
+ }
+ return false;
+}
+
+// XPropertySet
+
+uno::Reference< beans::XPropertySetInfo > SAL_CALL ScStyleFamilyObj::getPropertySetInfo( )
+{
+ OSL_FAIL( "###unexpected!" );
+ return uno::Reference< beans::XPropertySetInfo >();
+}
+
+void SAL_CALL ScStyleFamilyObj::setPropertyValue( const OUString&, const uno::Any& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+uno::Any SAL_CALL ScStyleFamilyObj::getPropertyValue( const OUString& sPropertyName )
+{
+ uno::Any aRet;
+
+ if ( sPropertyName != "DisplayName" )
+ {
+ throw beans::UnknownPropertyException( "unknown property: " + sPropertyName, static_cast<OWeakObject *>(this) );
+ }
+
+ SolarMutexGuard aGuard;
+ TranslateId pResId;
+ switch ( eFamily )
+ {
+ case SfxStyleFamily::Para:
+ pResId = STR_STYLE_FAMILY_CELL; break;
+ case SfxStyleFamily::Page:
+ pResId = STR_STYLE_FAMILY_PAGE; break;
+ default:
+ OSL_FAIL( "ScStyleFamilyObj::getPropertyValue(): invalid family" );
+ }
+ if (pResId)
+ {
+ OUString sDisplayName(ScResId(pResId));
+ aRet <<= sDisplayName;
+ }
+
+ return aRet;
+}
+
+void SAL_CALL ScStyleFamilyObj::addPropertyChangeListener( const OUString&, const uno::Reference< beans::XPropertyChangeListener >& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+void SAL_CALL ScStyleFamilyObj::removePropertyChangeListener( const OUString&, const uno::Reference< beans::XPropertyChangeListener >& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+void SAL_CALL ScStyleFamilyObj::addVetoableChangeListener( const OUString&, const uno::Reference< beans::XVetoableChangeListener >& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+void SAL_CALL ScStyleFamilyObj::removeVetoableChangeListener( const OUString&, const uno::Reference< beans::XVetoableChangeListener >& )
+{
+ OSL_FAIL( "###unexpected!" );
+}
+
+// default ctor is needed for reflection
+
+ScStyleObj::ScStyleObj(ScDocShell* pDocSh, SfxStyleFamily eFam, const OUString& rName)
+ : pPropSet( (eFam == SfxStyleFamily::Para) ? lcl_GetCellStyleSet() : lcl_GetPageStyleSet() )
+ , pDocShell(pDocSh)
+ , eFamily(eFam)
+ , aStyleName(rName)
+ , pStyle_cached(nullptr)
+{
+ // if create by ServiceProvider then pDocShell is NULL
+
+ if (pDocShell)
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+void ScStyleObj::InitDoc( ScDocShell* pNewDocSh, const OUString& rNewName )
+{
+ if ( pNewDocSh && !pDocShell )
+ {
+ aStyleName = rNewName;
+ pDocShell = pNewDocSh;
+ pDocShell->GetDocument().AddUnoObject(*this);
+ }
+}
+
+ScStyleObj::~ScStyleObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION_IMPL(ScStyleObj);
+
+void ScStyleObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ // reference update does not matter here
+
+ if ( rHint.GetId() == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // has become invalid
+ }
+}
+
+SfxStyleSheetBase* ScStyleObj::GetStyle_Impl( bool bUseCachedValue )
+{
+ if ( bUseCachedValue )
+ return pStyle_cached;
+
+ pStyle_cached = nullptr;
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ pStyle_cached = pStylePool->Find( aStyleName, eFamily );
+ }
+ return pStyle_cached;
+}
+
+// style::XStyle
+
+sal_Bool SAL_CALL ScStyleObj::isUserDefined()
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (pStyle)
+ return pStyle->IsUserDefined();
+ return false;
+}
+
+sal_Bool SAL_CALL ScStyleObj::isInUse()
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (pStyle)
+ return pStyle->IsUsed();
+ return false;
+}
+
+OUString SAL_CALL ScStyleObj::getParentStyle()
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (pStyle)
+ return ScStyleNameConversion::DisplayToProgrammaticName( pStyle->GetParent(), eFamily );
+ return OUString();
+}
+
+void SAL_CALL ScStyleObj::setParentStyle( const OUString& rParentStyle )
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (!pStyle)
+ return;
+
+ // cell styles cannot be modified if any sheet is protected
+ if ( eFamily == SfxStyleFamily::Para && lcl_AnyTabProtected( pDocShell->GetDocument() ) )
+ return; //! exception?
+
+ //! DocFunc function??
+ //! Undo ?????????????
+
+ OUString aString(ScStyleNameConversion::ProgrammaticToDisplayName( rParentStyle, eFamily ));
+ bool bOk = pStyle->SetParent( aString );
+ if (!bOk)
+ return;
+
+ // as by setPropertyValue
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( eFamily == SfxStyleFamily::Para )
+ {
+ // update line height
+
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Point aLogic = pVDev->LogicToPixel( Point(1000,1000), MapMode(MapUnit::MapTwip));
+ double nPPTX = aLogic.X() / 1000.0;
+ double nPPTY = aLogic.Y() / 1000.0;
+ Fraction aZoom(1,1);
+ rDoc.StyleSheetChanged( pStyle, false, pVDev, nPPTX, nPPTY, aZoom, aZoom );
+
+ if (!rDoc.IsImportingXML())
+ {
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+ pDocShell->SetDocumentModified();
+ }
+ }
+ else
+ {
+ //! ModifyStyleSheet on document (save old values)
+
+ pDocShell->PageStyleModified( aStyleName, true );
+ }
+}
+
+// container::XNamed
+
+OUString SAL_CALL ScStyleObj::getName()
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (pStyle)
+ return ScStyleNameConversion::DisplayToProgrammaticName( pStyle->GetName(), eFamily );
+ return OUString();
+}
+
+void SAL_CALL ScStyleObj::setName( const OUString& aNewName )
+{
+ SolarMutexGuard aGuard;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if (!pStyle)
+ return;
+
+ // cell styles cannot be renamed if any sheet is protected
+ if ( eFamily == SfxStyleFamily::Para && lcl_AnyTabProtected( pDocShell->GetDocument() ) )
+ return; //! exception?
+
+ //! DocFunc function??
+ //! Undo ?????????????
+
+ bool bOk = pStyle->SetName( aNewName );
+ if (!bOk)
+ return;
+
+ aStyleName = aNewName; //! notify other objects for this style?
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( eFamily == SfxStyleFamily::Para && !rDoc.IsImportingXML() )
+ rDoc.GetPool()->CellStyleCreated( aNewName, rDoc );
+
+ // cell styles = 2, page styles = 4
+ sal_uInt16 nId = ( eFamily == SfxStyleFamily::Para ) ?
+ SID_STYLE_FAMILY2 : SID_STYLE_FAMILY4;
+ SfxBindings* pBindings = pDocShell->GetViewBindings();
+ if (pBindings)
+ {
+ pBindings->Invalidate( nId );
+ pBindings->Invalidate( SID_STYLE_APPLY );
+ }
+}
+
+uno::Reference<container::XIndexReplace> ScStyleObj::CreateEmptyNumberingRules()
+{
+ SvxNumRule aRule( SvxNumRuleFlags::NONE, 0, true ); // nothing supported
+ return SvxCreateNumRule( aRule );
+}
+
+// beans::XPropertyState
+
+const SfxItemSet* ScStyleObj::GetStyleItemSet_Impl( std::u16string_view rPropName,
+ const SfxItemPropertyMapEntry*& rpResultEntry )
+{
+ SfxStyleSheetBase* pStyle = GetStyle_Impl( true );
+ if ( pStyle )
+ {
+ const SfxItemPropertyMapEntry* pEntry = nullptr;
+ if ( eFamily == SfxStyleFamily::Page )
+ {
+ pEntry = lcl_GetHeaderStyleMap()->getByName( rPropName );
+ if ( pEntry ) // only item-WIDs in header/footer map
+ {
+ rpResultEntry = pEntry;
+ return &pStyle->GetItemSet().Get(ATTR_PAGE_HEADERSET).GetItemSet();
+ }
+ pEntry = lcl_GetFooterStyleMap()->getByName( rPropName );
+ if ( pEntry ) // only item-WIDs in header/footer map
+ {
+ rpResultEntry = pEntry;
+ return &pStyle->GetItemSet().Get(ATTR_PAGE_FOOTERSET).GetItemSet();
+ }
+ }
+ pEntry = pPropSet->getPropertyMap().getByName( rPropName );
+ if ( pEntry )
+ {
+ rpResultEntry = pEntry;
+ return &pStyle->GetItemSet();
+ }
+ }
+
+ rpResultEntry = nullptr;
+ return nullptr;
+}
+
+beans::PropertyState ScStyleObj::getPropertyState_Impl( std::u16string_view aPropertyName )
+{
+ beans::PropertyState eRet = beans::PropertyState_DIRECT_VALUE;
+
+ const SfxItemPropertyMapEntry* pResultEntry = nullptr;
+ const SfxItemSet* pItemSet = GetStyleItemSet_Impl( aPropertyName, pResultEntry );
+
+ if ( pItemSet && pResultEntry )
+ {
+ sal_uInt16 nWhich = pResultEntry->nWID;
+ if ( nWhich == SC_WID_UNO_TBLBORD || nWhich == SC_WID_UNO_TBLBORD2 )
+ {
+ nWhich = ATTR_BORDER;
+ }
+ if ( IsScItemWid( nWhich ) )
+ {
+ SfxItemState eState = pItemSet->GetItemState( nWhich, false );
+
+// // if no rotate value is set, look at orientation
+// //! also for a fixed value of 0 (in case orientation is ambiguous)?
+// if ( nWhich == ATTR_ROTATE_VALUE && eState == SfxItemState::DEFAULT )
+// eState = pItemSet->GetItemState( ATTR_ORIENTATION, sal_False );
+
+ if ( eState == SfxItemState::SET )
+ eRet = beans::PropertyState_DIRECT_VALUE;
+ else if ( eState == SfxItemState::DEFAULT )
+ eRet = beans::PropertyState_DEFAULT_VALUE;
+ else if ( eState == SfxItemState::DONTCARE )
+ eRet = beans::PropertyState_AMBIGUOUS_VALUE; // should not happen
+ else
+ {
+ OSL_FAIL("unknown ItemState");
+ }
+ }
+ }
+ return eRet;
+}
+
+beans::PropertyState SAL_CALL ScStyleObj::getPropertyState( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ return getPropertyState_Impl( aPropertyName );
+}
+
+uno::Sequence<beans::PropertyState> SAL_CALL ScStyleObj::getPropertyStates( const uno::Sequence<OUString>& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ uno::Sequence<beans::PropertyState> aRet( aPropertyNames.getLength() );
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aRet.getArray(),
+ [this](const OUString& rName) -> beans::PropertyState { return getPropertyState_Impl(rName); });
+ return aRet;
+}
+
+void SAL_CALL ScStyleObj::setPropertyToDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ const SfxItemPropertyMapEntry* pEntry = pPropSet->getPropertyMap().getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ setPropertyValue_Impl( aPropertyName, pEntry, nullptr );
+}
+
+uno::Any ScStyleObj::getPropertyDefault_Impl( std::u16string_view aPropertyName )
+{
+ uno::Any aAny;
+
+ const SfxItemPropertyMapEntry* pResultEntry = nullptr;
+ const SfxItemSet* pStyleSet = GetStyleItemSet_Impl( aPropertyName, pResultEntry );
+
+ if ( pStyleSet && pResultEntry )
+ {
+ sal_uInt16 nWhich = pResultEntry->nWID;
+
+ if ( IsScItemWid( nWhich ) )
+ {
+ // Default is default from ItemPool, not from Standard-Style,
+ // so it is the same as in setPropertyToDefault
+ SfxItemSet aEmptySet( *pStyleSet->GetPool(), pStyleSet->GetRanges() );
+ // default items with wrong Slot-ID are not functional in SfxItemPropertySet3
+ //! change Slot-IDs...
+ if ( aEmptySet.GetPool()->GetSlotId(nWhich) == nWhich &&
+ aEmptySet.GetItemState(nWhich, false) == SfxItemState::DEFAULT )
+ {
+ aEmptySet.Put( aEmptySet.Get( nWhich ) );
+ }
+ const SfxItemSet* pItemSet = &aEmptySet;
+
+ switch ( nWhich ) // special item handling
+ {
+ case ATTR_VALUE_FORMAT:
+ // default has no language set
+ aAny <<= sal_Int32( static_cast<const SfxUInt32Item&>(pItemSet->Get(nWhich)).GetValue() );
+ break;
+ case ATTR_INDENT:
+ aAny <<= sal_Int16( convertTwipToMm100(static_cast<const ScIndentItem&>(
+ pItemSet->Get(nWhich)).GetValue()) );
+ break;
+ case ATTR_PAGE_SCALE:
+ case ATTR_PAGE_SCALETOPAGES:
+ case ATTR_PAGE_FIRSTPAGENO:
+ aAny <<= sal_Int16( static_cast<const SfxUInt16Item&>(pItemSet->Get(nWhich)).GetValue() );
+ break;
+ case ATTR_PAGE_CHARTS:
+ case ATTR_PAGE_OBJECTS:
+ case ATTR_PAGE_DRAWINGS:
+ //! define sal_Bool-MID for ScViewObjectModeItem?
+ aAny <<= static_cast<const ScViewObjectModeItem&>(pItemSet->Get(nWhich)).GetValue() == VOBJ_MODE_SHOW;
+ break;
+ case ATTR_PAGE_SCALETO:
+ {
+ const ScPageScaleToItem aItem(static_cast<const ScPageScaleToItem&>(pItemSet->Get(nWhich)));
+ if ( aPropertyName == u"" SC_UNO_PAGE_SCALETOX )
+ aAny <<= static_cast<sal_Int16>(aItem.GetWidth());
+ else
+ aAny <<= static_cast<sal_Int16>(aItem.GetHeight());
+ }
+ break;
+ default:
+ pPropSet->getPropertyValue( *pResultEntry, *pItemSet, aAny );
+ }
+ }
+ else if ( IsScUnoWid( nWhich ) )
+ {
+ SfxItemSet aEmptySet( *pStyleSet->GetPool(), pStyleSet->GetRanges() );
+ const SfxItemSet* pItemSet = &aEmptySet;
+ switch ( nWhich )
+ {
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ {
+ const SfxPoolItem& rItem = pItemSet->Get(ATTR_BORDER);
+ SvxBoxItem aOuter(static_cast<const SvxBoxItem&>(rItem));
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ if (nWhich == SC_WID_UNO_TBLBORD2)
+ ScHelperFunctions::AssignTableBorder2ToAny(aAny, aOuter, aInner, true);
+ else
+ ScHelperFunctions::AssignTableBorderToAny(aAny, aOuter, aInner, true);
+ }
+ break;
+ }
+ }
+ }
+ return aAny;
+}
+
+uno::Any SAL_CALL ScStyleObj::getPropertyDefault( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ return getPropertyDefault_Impl( aPropertyName );
+}
+
+uno::Sequence<uno::Any> SAL_CALL ScStyleObj::getPropertyDefaults( const uno::Sequence<OUString>& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ uno::Sequence<uno::Any> aSequence( aPropertyNames.getLength() );
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aSequence.getArray(),
+ [this](const OUString& rName) -> uno::Any { return getPropertyDefault_Impl(rName); });
+ return aSequence;
+}
+
+// XMultiPropertySet
+
+void SAL_CALL ScStyleObj::setPropertyValues( const uno::Sequence< OUString >& aPropertyNames,
+ const uno::Sequence< uno::Any >& aValues )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ if ( aValues.getLength() != aPropertyNames.getLength() )
+ throw lang::IllegalArgumentException();
+
+ const OUString* pNames = aPropertyNames.getConstArray();
+ const uno::Any* pValues = aValues.getConstArray();
+ const SfxItemPropertyMap& rPropertyMap = pPropSet->getPropertyMap();
+ for ( sal_Int32 i = 0; i < aPropertyNames.getLength(); i++ )
+ {
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( pNames[i] );
+ setPropertyValue_Impl( pNames[i], pEntry, &pValues[i] );
+ }
+}
+
+uno::Sequence<uno::Any> SAL_CALL ScStyleObj::getPropertyValues( const uno::Sequence< OUString >& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ uno::Sequence<uno::Any> aSequence( aPropertyNames.getLength() );
+ std::transform(aPropertyNames.begin(), aPropertyNames.end(), aSequence.getArray(),
+ [this](const OUString& rName) -> uno::Any { return getPropertyValue_Impl(rName); });
+ return aSequence;
+}
+
+void SAL_CALL ScStyleObj::addPropertiesChangeListener( const uno::Sequence<OUString>& /* aPropertyNames */,
+ const uno::Reference<beans::XPropertiesChangeListener>& /* xListener */ )
+{
+ // no bound properties
+}
+
+void SAL_CALL ScStyleObj::removePropertiesChangeListener(
+ const uno::Reference<beans::XPropertiesChangeListener>& /* xListener */ )
+{
+ // no bound properties
+}
+
+void SAL_CALL ScStyleObj::firePropertiesChangeEvent( const uno::Sequence<OUString>& /* aPropertyNames */,
+ const uno::Reference<beans::XPropertiesChangeListener>& /* xListener */ )
+{
+ // no bound properties
+}
+
+// XMultiPropertyStates
+// getPropertyStates already defined for XPropertyState
+
+void SAL_CALL ScStyleObj::setAllPropertiesToDefault()
+{
+ SolarMutexGuard aGuard;
+
+ SfxStyleSheetBase* pStyle = GetStyle_Impl();
+ if ( !pStyle )
+ return;
+
+ // cell styles cannot be modified if any sheet is protected
+ if ( eFamily == SfxStyleFamily::Para && lcl_AnyTabProtected( pDocShell->GetDocument() ) )
+ throw uno::RuntimeException();
+
+ SfxItemSet& rSet = pStyle->GetItemSet();
+ rSet.ClearItem(); // set all items to default
+
+ //! merge with SetOneProperty
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ if ( eFamily == SfxStyleFamily::Para )
+ {
+ // row heights
+
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Point aLogic = pVDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
+ double nPPTX = aLogic.X() / 1000.0;
+ double nPPTY = aLogic.Y() / 1000.0;
+ Fraction aZoom(1,1);
+ rDoc.StyleSheetChanged( pStyle, false, pVDev, nPPTX, nPPTY, aZoom, aZoom );
+
+ if (!rDoc.IsImportingXML())
+ {
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+ pDocShell->SetDocumentModified();
+ }
+ }
+ else
+ {
+ // #i22448# apply the default BoxInfoItem for page styles again
+ // (same content as in ScStyleSheet::GetItemSet, to control the dialog)
+ SvxBoxInfoItem aBoxInfoItem( ATTR_BORDER_INNER );
+ aBoxInfoItem.SetTable( false );
+ aBoxInfoItem.SetDist( true );
+ aBoxInfoItem.SetValid( SvxBoxInfoItemValidFlags::DISTANCE );
+ rSet.Put( aBoxInfoItem );
+
+ pDocShell->PageStyleModified( aStyleName, true );
+ }
+}
+
+void SAL_CALL ScStyleObj::setPropertiesToDefault( const uno::Sequence<OUString>& aPropertyNames )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ const SfxItemPropertyMap& rPropertyMap = pPropSet->getPropertyMap();
+ for ( const OUString& rName : aPropertyNames )
+ {
+ const SfxItemPropertyMapEntry* pEntry = rPropertyMap.getByName( rName );
+ setPropertyValue_Impl( rName, pEntry, nullptr );
+ }
+}
+
+// beans::XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScStyleObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ return pPropSet->getPropertySetInfo();
+}
+
+void SAL_CALL ScStyleObj::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ const SfxItemPropertyMapEntry* pEntry = pPropSet->getPropertyMap().getByName( aPropertyName );
+ if ( !pEntry )
+ throw beans::UnknownPropertyException(aPropertyName);
+
+ setPropertyValue_Impl( aPropertyName, pEntry, &aValue );
+}
+
+void ScStyleObj::setPropertyValue_Impl( std::u16string_view rPropertyName, const SfxItemPropertyMapEntry* pEntry, const uno::Any* pValue )
+{
+ SfxStyleSheetBase* pStyle = GetStyle_Impl( true );
+ if ( !(pStyle && pEntry) )
+ return;
+
+ // cell styles cannot be modified if any sheet is protected
+ if ( eFamily == SfxStyleFamily::Para && lcl_AnyTabProtected( pDocShell->GetDocument() ) )
+ throw uno::RuntimeException();
+
+ SfxItemSet& rSet = pStyle->GetItemSet(); // change directly in active Style
+ bool bDone = false;
+ if ( eFamily == SfxStyleFamily::Page )
+ {
+ if(pEntry->nWID == SC_WID_UNO_HEADERSET)
+ {
+ const SfxItemPropertyMapEntry* pHeaderEntry = lcl_GetHeaderStyleMap()->getByName( rPropertyName );
+ if ( pHeaderEntry ) // only item-WIDs in header/footer map
+ {
+ SvxSetItem aNewHeader( rSet.Get(ATTR_PAGE_HEADERSET) );
+ if (pValue)
+ pPropSet->setPropertyValue( *pHeaderEntry, *pValue, aNewHeader.GetItemSet() );
+ else
+ aNewHeader.GetItemSet().ClearItem( pHeaderEntry->nWID );
+ rSet.Put( aNewHeader );
+ bDone = true;
+ }
+ }
+ else if(pEntry->nWID == SC_WID_UNO_FOOTERSET)
+ {
+ const SfxItemPropertyMapEntry* pFooterEntry = lcl_GetFooterStyleMap()->getByName( rPropertyName );
+ if ( pFooterEntry ) // only item-WIDs in header/footer map
+ {
+ SvxSetItem aNewFooter( rSet.Get(ATTR_PAGE_FOOTERSET) );
+ if (pValue)
+ pPropSet->setPropertyValue( *pFooterEntry, *pValue, aNewFooter.GetItemSet() );
+ else
+ aNewFooter.GetItemSet().ClearItem( pFooterEntry->nWID );
+ rSet.Put( aNewFooter );
+ bDone = true;
+ }
+ }
+ }
+ if (!bDone)
+ {
+ if (IsScItemWid(pEntry->nWID))
+ {
+ if (pValue)
+ {
+ switch (pEntry->nWID) // special item handling
+ {
+ case ATTR_VALUE_FORMAT:
+ {
+ // language for number formats
+ SvNumberFormatter* pFormatter
+ = pDocShell->GetDocument().GetFormatTable();
+ sal_uInt32 nOldFormat = rSet.Get(ATTR_VALUE_FORMAT).GetValue();
+ LanguageType eOldLang
+ = rSet.Get(ATTR_LANGUAGE_FORMAT).GetLanguage();
+ pFormatter->GetFormatForLanguageIfBuiltIn(nOldFormat, eOldLang);
+
+ sal_uInt32 nNewFormat = 0;
+ *pValue >>= nNewFormat;
+ rSet.Put(SfxUInt32Item(ATTR_VALUE_FORMAT, nNewFormat));
+
+ const SvNumberformat* pNewEntry = pFormatter->GetEntry(nNewFormat);
+ LanguageType eNewLang
+ = pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
+ if (eNewLang != eOldLang && eNewLang != LANGUAGE_DONTKNOW)
+ rSet.Put(SvxLanguageItem(eNewLang, ATTR_LANGUAGE_FORMAT));
+
+ //! keep default state of number format if only language changed?
+ }
+ break;
+ case ATTR_INDENT:
+ {
+ sal_Int16 nVal = 0;
+ *pValue >>= nVal;
+ rSet.Put(ScIndentItem(o3tl::toTwips(nVal, o3tl::Length::mm100)));
+ }
+ break;
+ case ATTR_ROTATE_VALUE:
+ {
+ sal_Int32 nRotVal = 0;
+ if (*pValue >>= nRotVal)
+ {
+ // stored value is always between 0 and 360 deg.
+ nRotVal %= 36000;
+ if (nRotVal < 0)
+ nRotVal += 36000;
+ rSet.Put(ScRotateValueItem(Degree100(nRotVal)));
+ }
+ }
+ break;
+ case ATTR_STACKED:
+ {
+ table::CellOrientation eOrient;
+ if (*pValue >>= eOrient)
+ {
+ switch (eOrient)
+ {
+ case table::CellOrientation_STANDARD:
+ rSet.Put(ScVerticalStackCell(false));
+ break;
+ case table::CellOrientation_TOPBOTTOM:
+ rSet.Put(ScVerticalStackCell(false));
+ rSet.Put(ScRotateValueItem(27000_deg100));
+ break;
+ case table::CellOrientation_BOTTOMTOP:
+ rSet.Put(ScVerticalStackCell(false));
+ rSet.Put(ScRotateValueItem(9000_deg100));
+ break;
+ case table::CellOrientation_STACKED:
+ rSet.Put(ScVerticalStackCell(true));
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ break;
+ case ATTR_PAGE_SCALE:
+ case ATTR_PAGE_SCALETOPAGES:
+ {
+ rSet.ClearItem(ATTR_PAGE_SCALETOPAGES);
+ rSet.ClearItem(ATTR_PAGE_SCALE);
+ rSet.ClearItem(ATTR_PAGE_SCALETO);
+ sal_Int16 nVal = 0;
+ *pValue >>= nVal;
+ rSet.Put(SfxUInt16Item(pEntry->nWID, nVal));
+ }
+ break;
+ case ATTR_PAGE_FIRSTPAGENO:
+ {
+ sal_Int16 nVal = 0;
+ *pValue >>= nVal;
+ rSet.Put(SfxUInt16Item(ATTR_PAGE_FIRSTPAGENO, nVal));
+ }
+ break;
+ case ATTR_PAGE_CHARTS:
+ case ATTR_PAGE_OBJECTS:
+ case ATTR_PAGE_DRAWINGS:
+ {
+ bool bBool = false;
+ *pValue >>= bBool;
+ //! need to define sal_Bool-MID for ScViewObjectModeItem?
+ rSet.Put(ScViewObjectModeItem(
+ pEntry->nWID, bBool ? VOBJ_MODE_SHOW : VOBJ_MODE_HIDE));
+ }
+ break;
+ case ATTR_PAGE_PAPERBIN:
+ {
+ sal_uInt8 nTray = PAPERBIN_PRINTER_SETTINGS;
+ bool bFound = false;
+
+ OUString aName;
+ if (*pValue >>= aName)
+ {
+ if (aName == SC_PAPERBIN_DEFAULTNAME)
+ bFound = true;
+ else
+ {
+ Printer* pPrinter = pDocShell->GetPrinter();
+ if (pPrinter)
+ {
+ const sal_uInt16 nCount = pPrinter->GetPaperBinCount();
+ for (sal_uInt16 i = 0; i < nCount; i++)
+ if (aName == pPrinter->GetPaperBinName(i))
+ {
+ nTray = static_cast<sal_uInt8>(i);
+ bFound = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!bFound)
+ throw lang::IllegalArgumentException();
+
+ rSet.Put(SvxPaperBinItem(ATTR_PAGE_PAPERBIN, nTray));
+
+ }
+ break;
+ case ATTR_PAGE_SCALETO:
+ {
+ sal_Int16 nPages = 0;
+ if (*pValue >>= nPages)
+ {
+ ScPageScaleToItem aItem = rSet.Get(ATTR_PAGE_SCALETO);
+ if (rPropertyName == u"" SC_UNO_PAGE_SCALETOX)
+ aItem.SetWidth(static_cast<sal_uInt16>(nPages));
+ else
+ aItem.SetHeight(static_cast<sal_uInt16>(nPages));
+ rSet.Put(aItem);
+ rSet.ClearItem(ATTR_PAGE_SCALETOPAGES);
+ rSet.ClearItem(ATTR_PAGE_SCALE);
+ }
+ }
+ break;
+ case ATTR_HIDDEN:
+ {
+ bool bHidden = false;
+ if (*pValue >>= bHidden)
+ pStyle->SetHidden(bHidden);
+ }
+ break;
+ default:
+ // default items with wrong Slot-ID are not working in SfxItemPropertySet3
+ //! change Slot-IDs...
+ if (rSet.GetPool()->GetSlotId(pEntry->nWID) == pEntry->nWID
+ && rSet.GetItemState(pEntry->nWID, false) == SfxItemState::DEFAULT)
+ {
+ rSet.Put(rSet.Get(pEntry->nWID));
+ }
+ pPropSet->setPropertyValue(*pEntry, *pValue, rSet);
+ }
+ }
+ else
+ {
+ rSet.ClearItem(pEntry->nWID);
+ // language for number formats
+ if (pEntry->nWID == ATTR_VALUE_FORMAT)
+ rSet.ClearItem(ATTR_LANGUAGE_FORMAT);
+
+ //! for ATTR_ROTATE_VALUE, also reset ATTR_ORIENTATION?
+ }
+ }
+ else if (IsScUnoWid(pEntry->nWID))
+ {
+ switch (pEntry->nWID)
+ {
+ case SC_WID_UNO_TBLBORD:
+ {
+ if (pValue)
+ {
+ table::TableBorder aBorder;
+ if (*pValue >>= aBorder)
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems(aOuter, aInner, aBorder);
+ rSet.Put(aOuter);
+ }
+ }
+ else
+ {
+ rSet.ClearItem(ATTR_BORDER);
+ }
+ }
+ break;
+ case SC_WID_UNO_TBLBORD2:
+ {
+ if (pValue)
+ {
+ table::TableBorder2 aBorder2;
+ if (*pValue >>= aBorder2)
+ {
+ SvxBoxItem aOuter(ATTR_BORDER);
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ ScHelperFunctions::FillBoxItems(aOuter, aInner, aBorder2);
+ rSet.Put(aOuter);
+ }
+ }
+ else
+ {
+ rSet.ClearItem(ATTR_BORDER);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ //! DocFunc-??
+ //! Undo ??
+
+ if ( eFamily == SfxStyleFamily::Para )
+ {
+ // If we are loading, we can delay line height calculation, because we are going to re-calc all of those
+ // after load.
+ if (pDocShell && !pDocShell->IsLoading())
+ {
+ // update line height
+ ScopedVclPtrInstance< VirtualDevice > pVDev;
+ Point aLogic = pVDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
+ double nPPTX = aLogic.X() / 1000.0;
+ double nPPTY = aLogic.Y() / 1000.0;
+ Fraction aZoom(1,1);
+ ScDocument& rDoc = pDocShell->GetDocument();
+ rDoc.StyleSheetChanged( pStyle, false, pVDev, nPPTX, nPPTY, aZoom, aZoom );
+
+ if (!rDoc.IsImportingXML())
+ {
+ pDocShell->PostPaint( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+ pDocShell->SetDocumentModified();
+ }
+ }
+ }
+ else
+ {
+ //! ModifyStyleSheet on document (save old values)
+
+ pDocShell->PageStyleModified( aStyleName, true );
+ }
+}
+
+uno::Any ScStyleObj::getPropertyValue_Impl( std::u16string_view aPropertyName )
+{
+ uno::Any aAny;
+ SfxStyleSheetBase* pStyle = GetStyle_Impl( true );
+
+ if ( aPropertyName == u"" SC_UNONAME_DISPNAME ) // read-only
+ {
+ // core always has the display name
+ if ( pStyle )
+ aAny <<= pStyle->GetName();
+ }
+ else
+ {
+ const SfxItemPropertyMapEntry* pResultEntry = nullptr;
+ const SfxItemSet* pItemSet = GetStyleItemSet_Impl( aPropertyName, pResultEntry );
+
+ if ( pItemSet && pResultEntry )
+ {
+ sal_uInt16 nWhich = pResultEntry->nWID;
+
+ if ( IsScItemWid( nWhich ) )
+ {
+ switch ( nWhich ) // for special item handling
+ {
+ case ATTR_VALUE_FORMAT:
+ if ( pDocShell )
+ {
+ sal_uInt32 nOldFormat =
+ pItemSet->Get( ATTR_VALUE_FORMAT ).GetValue();
+ LanguageType eOldLang =
+ pItemSet->Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
+ nOldFormat = pDocShell->GetDocument().GetFormatTable()->
+ GetFormatForLanguageIfBuiltIn( nOldFormat, eOldLang );
+ aAny <<= nOldFormat;
+ }
+ break;
+ case ATTR_INDENT:
+ aAny <<= sal_Int16( convertTwipToMm100(static_cast<const ScIndentItem&>(
+ pItemSet->Get(nWhich)).GetValue()) );
+ break;
+ case ATTR_STACKED:
+ {
+ Degree100 nRot = pItemSet->Get(ATTR_ROTATE_VALUE).GetValue();
+ bool bStacked = static_cast<const ScVerticalStackCell&>(pItemSet->Get(nWhich)).GetValue();
+ SvxOrientationItem( nRot, bStacked, TypedWhichId<SvxOrientationItem>(0) ).QueryValue( aAny );
+ }
+ break;
+ case ATTR_PAGE_SCALE:
+ case ATTR_PAGE_SCALETOPAGES:
+ case ATTR_PAGE_FIRSTPAGENO:
+ aAny <<= sal_Int16( static_cast<const SfxUInt16Item&>(pItemSet->Get(nWhich)).GetValue() );
+ break;
+ case ATTR_PAGE_CHARTS:
+ case ATTR_PAGE_OBJECTS:
+ case ATTR_PAGE_DRAWINGS:
+ //! define sal_Bool-MID for ScViewObjectModeItem?
+ aAny <<= static_cast<const ScViewObjectModeItem&>(pItemSet->Get(nWhich)).GetValue() == VOBJ_MODE_SHOW;
+ break;
+ case ATTR_PAGE_PAPERBIN:
+ {
+ // property PrinterPaperTray is the name of the tray
+
+ sal_uInt8 nValue = static_cast<const SvxPaperBinItem&>(pItemSet->Get(nWhich)).GetValue();
+ OUString aName;
+ if ( nValue == PAPERBIN_PRINTER_SETTINGS )
+ aName = SC_PAPERBIN_DEFAULTNAME;
+ else
+ {
+ Printer* pPrinter = pDocShell->GetPrinter();
+ if (pPrinter)
+ aName = pPrinter->GetPaperBinName( nValue );
+ }
+ aAny <<= aName;
+ }
+ break;
+ case ATTR_PAGE_SCALETO:
+ {
+ const ScPageScaleToItem& aItem(pItemSet->Get(ATTR_PAGE_SCALETO));
+ if ( aPropertyName == u"" SC_UNO_PAGE_SCALETOX )
+ aAny <<= static_cast<sal_Int16>(aItem.GetWidth());
+ else
+ aAny <<= static_cast<sal_Int16>(aItem.GetHeight());
+ }
+ break;
+ case ATTR_HIDDEN:
+ {
+ bool bHidden = pStyle && pStyle->IsHidden();
+ aAny <<= bHidden;
+ }
+ break;
+ default:
+ // Default-Items with wrong Slot-ID don't work in SfxItemPropertySet3
+ //! change Slot-IDs...
+ if ( pItemSet->GetPool()->GetSlotId(nWhich) == nWhich &&
+ pItemSet->GetItemState(nWhich, false) == SfxItemState::DEFAULT )
+ {
+ SfxItemSet aNoEmptySet( *pItemSet );
+ aNoEmptySet.Put( aNoEmptySet.Get( nWhich ) );
+ pPropSet->getPropertyValue( *pResultEntry, aNoEmptySet, aAny );
+ }
+ else
+ pPropSet->getPropertyValue( *pResultEntry, *pItemSet, aAny );
+ }
+ }
+ else if ( IsScUnoWid( nWhich ) )
+ {
+ switch ( nWhich )
+ {
+ case SC_WID_UNO_TBLBORD:
+ case SC_WID_UNO_TBLBORD2:
+ {
+ const SfxPoolItem& rItem = pItemSet->Get(ATTR_BORDER);
+ SvxBoxItem aOuter(static_cast<const SvxBoxItem&>(rItem));
+ SvxBoxInfoItem aInner(ATTR_BORDER_INNER);
+ if (nWhich == SC_WID_UNO_TBLBORD2)
+ ScHelperFunctions::AssignTableBorder2ToAny(aAny, aOuter, aInner,
+ true);
+ else
+ ScHelperFunctions::AssignTableBorderToAny(aAny, aOuter, aInner,
+ true);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ return aAny;
+}
+
+uno::Any SAL_CALL ScStyleObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ GetStyle_Impl();
+
+ return getPropertyValue_Impl( aPropertyName );
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScStyleObj )
+
+// lang::XServiceInfo
+
+OUString SAL_CALL ScStyleObj::getImplementationName()
+{
+ return "ScStyleObj";
+}
+
+sal_Bool SAL_CALL ScStyleObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScStyleObj::getSupportedServiceNames()
+{
+ const bool bPage = ( eFamily == SfxStyleFamily::Page );
+
+ return {SCSTYLE_SERVICE,
+ (bPage ? OUString(SCPAGESTYLE_SERVICE)
+ : OUString(SCCELLSTYLE_SERVICE))};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/targuno.cxx b/sc/source/ui/unoobj/targuno.cxx
new file mode 100644
index 000000000..8af19b58e
--- /dev/null
+++ b/sc/source/ui/unoobj/targuno.cxx
@@ -0,0 +1,293 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <toolkit/helper/vclunohelper.hxx>
+#include <svl/itemprop.hxx>
+#include <svl/hint.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include <targuno.hxx>
+#include <miscuno.hxx>
+#include <docuno.hxx>
+#include <datauno.hxx>
+#include <nameuno.hxx>
+#include <docsh.hxx>
+#include <content.hxx>
+#include <scresid.hxx>
+#include <strings.hrc>
+#include <bitmaps.hlst>
+#include <unonames.hxx>
+
+using namespace ::com::sun::star;
+
+const TranslateId aTypeResIds[SC_LINKTARGETTYPE_COUNT] =
+{
+ SCSTR_CONTENT_TABLE, // SC_LINKTARGETTYPE_SHEET
+ SCSTR_CONTENT_RANGENAME, // SC_LINKTARGETTYPE_RANGENAME
+ SCSTR_CONTENT_DBAREA // SC_LINKTARGETTYPE_DBAREA
+};
+
+static const SfxItemPropertyMapEntry* lcl_GetLinkTargetMap()
+{
+ static const SfxItemPropertyMapEntry aLinkTargetMap_Impl[] =
+ {
+ { SC_UNO_LINKDISPBIT, 0, cppu::UnoType<awt::XBitmap>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { SC_UNO_LINKDISPNAME, 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::READONLY, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aLinkTargetMap_Impl;
+}
+
+// service for ScLinkTargetTypeObj is not defined
+// must not support document::LinkTarget because the target type cannot be used as a target
+
+SC_SIMPLE_SERVICE_INFO( ScLinkTargetTypesObj, "ScLinkTargetTypesObj", "com.sun.star.document.LinkTargets" )
+SC_SIMPLE_SERVICE_INFO( ScLinkTargetTypeObj, "ScLinkTargetTypeObj", "com.sun.star.document.LinkTargetSupplier" )
+SC_SIMPLE_SERVICE_INFO( ScLinkTargetsObj, "ScLinkTargetsObj", "com.sun.star.document.LinkTargets" )
+
+ScLinkTargetTypesObj::ScLinkTargetTypesObj(ScDocShell* pDocSh) :
+ pDocShell( pDocSh )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+
+ for (sal_uInt16 i=0; i<SC_LINKTARGETTYPE_COUNT; i++)
+ aNames[i] = ScResId(aTypeResIds[i]);
+}
+
+ScLinkTargetTypesObj::~ScLinkTargetTypesObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScLinkTargetTypesObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // document gone
+}
+
+// container::XNameAccess
+
+uno::Any SAL_CALL ScLinkTargetTypesObj::getByName(const OUString& aName)
+{
+ if (pDocShell)
+ {
+ for (sal_uInt16 i=0; i<SC_LINKTARGETTYPE_COUNT; i++)
+ if ( aNames[i] == aName )
+ return uno::Any(uno::Reference< beans::XPropertySet >(new ScLinkTargetTypeObj( pDocShell, i )));
+ }
+
+ throw container::NoSuchElementException();
+}
+
+uno::Sequence<OUString> SAL_CALL ScLinkTargetTypesObj::getElementNames()
+{
+ uno::Sequence<OUString> aRet(SC_LINKTARGETTYPE_COUNT);
+ OUString* pArray = aRet.getArray();
+ for (sal_uInt16 i=0; i<SC_LINKTARGETTYPE_COUNT; i++)
+ pArray[i] = aNames[i];
+ return aRet;
+}
+
+sal_Bool SAL_CALL ScLinkTargetTypesObj::hasByName(const OUString& aName)
+{
+ for (const auto & i : aNames)
+ if ( i == aName )
+ return true;
+ return false;
+}
+
+// container::XElementAccess
+
+uno::Type SAL_CALL ScLinkTargetTypesObj::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL ScLinkTargetTypesObj::hasElements()
+{
+ return true;
+}
+
+ScLinkTargetTypeObj::ScLinkTargetTypeObj(ScDocShell* pDocSh, sal_uInt16 nT) :
+ pDocShell( pDocSh ),
+ nType( nT )
+{
+ pDocShell->GetDocument().AddUnoObject(*this);
+ aName = ScResId(aTypeResIds[nType]); //! on demand?
+}
+
+ScLinkTargetTypeObj::~ScLinkTargetTypeObj()
+{
+ SolarMutexGuard g;
+
+ if (pDocShell)
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScLinkTargetTypeObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pDocShell = nullptr; // document gone
+}
+
+// document::XLinkTargetSupplier
+
+uno::Reference< container::XNameAccess > SAL_CALL ScLinkTargetTypeObj::getLinks()
+{
+ uno::Reference< container::XNameAccess > xCollection;
+
+ if ( pDocShell )
+ {
+ switch ( nType )
+ {
+ case SC_LINKTARGETTYPE_SHEET:
+ xCollection.set(new ScTableSheetsObj(pDocShell));
+ break;
+ case SC_LINKTARGETTYPE_RANGENAME:
+ xCollection.set(new ScGlobalNamedRangesObj(pDocShell));
+ break;
+ case SC_LINKTARGETTYPE_DBAREA:
+ xCollection.set(new ScDatabaseRangesObj(pDocShell));
+ break;
+ default:
+ OSL_FAIL("invalid type");
+ }
+ }
+
+ // wrap collection in ScLinkTargetsObj because service document::LinkTargets requires
+ // beans::XPropertySet as ElementType in container::XNameAccess.
+ if ( xCollection.is() )
+ return new ScLinkTargetsObj( xCollection );
+ return nullptr;
+}
+
+// beans::XPropertySet
+
+uno::Reference< beans::XPropertySetInfo > SAL_CALL ScLinkTargetTypeObj::getPropertySetInfo()
+{
+ static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetLinkTargetMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScLinkTargetTypeObj::setPropertyValue(const OUString& /* aPropertyName */,
+ const uno::Any& /* aValue */)
+{
+ // everything is read-only
+ //! exception?
+}
+
+constexpr rtl::OUStringConstExpr aContentBmps[]=
+{
+ RID_BMP_CONTENT_TABLE,
+ RID_BMP_CONTENT_RANGENAME,
+ RID_BMP_CONTENT_DBAREA,
+ RID_BMP_CONTENT_GRAPHIC,
+ RID_BMP_CONTENT_OLEOBJECT,
+ RID_BMP_CONTENT_NOTE,
+ RID_BMP_CONTENT_AREALINK,
+ RID_BMP_CONTENT_DRAWING
+};
+
+void ScLinkTargetTypeObj::SetLinkTargetBitmap( uno::Any& rRet, sal_uInt16 nType )
+{
+ ScContentId nImgId = ScContentId::ROOT;
+ switch ( nType )
+ {
+ case SC_LINKTARGETTYPE_SHEET:
+ nImgId = ScContentId::TABLE;
+ break;
+ case SC_LINKTARGETTYPE_RANGENAME:
+ nImgId = ScContentId::RANGENAME;
+ break;
+ case SC_LINKTARGETTYPE_DBAREA:
+ nImgId = ScContentId::DBAREA;
+ break;
+ }
+ if (nImgId != ScContentId::ROOT)
+ {
+ BitmapEx aBitmapEx { OUString(aContentBmps[static_cast<int>(nImgId) -1 ]) };
+ rRet <<= VCLUnoHelper::CreateBitmap(aBitmapEx);
+ }
+}
+
+uno::Any SAL_CALL ScLinkTargetTypeObj::getPropertyValue(const OUString& PropertyName)
+{
+ uno::Any aRet;
+ if ( PropertyName == SC_UNO_LINKDISPBIT )
+ SetLinkTargetBitmap( aRet, nType );
+ else if ( PropertyName == SC_UNO_LINKDISPNAME )
+ aRet <<= aName;
+
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScLinkTargetTypeObj )
+
+ScLinkTargetsObj::ScLinkTargetsObj( const uno::Reference< container::XNameAccess > & rColl ) :
+ xCollection( rColl )
+{
+ OSL_ENSURE( xCollection.is(), "ScLinkTargetsObj: NULL" );
+}
+
+ScLinkTargetsObj::~ScLinkTargetsObj()
+{
+}
+
+// container::XNameAccess
+
+uno::Any SAL_CALL ScLinkTargetsObj::getByName(const OUString& aName)
+{
+ uno::Reference<beans::XPropertySet> xProp(xCollection->getByName(aName), uno::UNO_QUERY);
+ if (xProp.is())
+ return uno::Any(xProp);
+
+ throw container::NoSuchElementException();
+}
+
+uno::Sequence<OUString> SAL_CALL ScLinkTargetsObj::getElementNames()
+{
+ return xCollection->getElementNames();
+}
+
+sal_Bool SAL_CALL ScLinkTargetsObj::hasByName(const OUString& aName)
+{
+ return xCollection->hasByName(aName);
+}
+
+// container::XElementAccess
+
+uno::Type SAL_CALL ScLinkTargetsObj::getElementType()
+{
+ return cppu::UnoType<beans::XPropertySet>::get();
+}
+
+sal_Bool SAL_CALL ScLinkTargetsObj::hasElements()
+{
+ return xCollection->hasElements();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/textuno.cxx b/sc/source/ui/unoobj/textuno.cxx
new file mode 100644
index 000000000..46ec6dbf2
--- /dev/null
+++ b/sc/source/ui/unoobj/textuno.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 <memory>
+#include <sal/config.h>
+#include <sal/log.hxx>
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+#include <svx/svdpool.hxx>
+#include <svx/svdobj.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/unoprnms.hxx>
+#include <editeng/unofored.hxx>
+#include <vcl/svapp.hxx>
+
+#include <editeng/unoipset.hxx>
+#include <textuno.hxx>
+#include <fielduno.hxx>
+#include <editsrc.hxx>
+#include <docsh.hxx>
+#include <editutil.hxx>
+#include <miscuno.hxx>
+#include <cellsuno.hxx>
+#include <cellvalue.hxx>
+#include <cellform.hxx>
+#include <patattr.hxx>
+#include <docfunc.hxx>
+#include <scmod.hxx>
+
+using namespace com::sun::star;
+
+static const SvxItemPropertySet * lcl_GetHdFtPropertySet()
+{
+ static const SvxItemPropertySet aHdFtPropertySet_Impl = [] {
+ static SfxItemPropertyMapEntry aHdFtPropertyMap_Impl[] =
+ {
+ SVX_UNOEDIT_CHAR_PROPERTIES,
+ SVX_UNOEDIT_FONT_PROPERTIES,
+ SVX_UNOEDIT_PARA_PROPERTIES,
+ SVX_UNOEDIT_NUMBERING_PROPERTY, // for completeness of service ParagraphProperties
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+
+ // modify PropertyMap to include CONVERT_TWIPS flag for font height
+ // (headers/footers are in twips)
+
+ SfxItemPropertyMapEntry* pEntry = aHdFtPropertyMap_Impl;
+ while (!pEntry->aName.isEmpty())
+ {
+ if ( ( pEntry->nWID == EE_CHAR_FONTHEIGHT ||
+ pEntry->nWID == EE_CHAR_FONTHEIGHT_CJK ||
+ pEntry->nWID == EE_CHAR_FONTHEIGHT_CTL ) &&
+ pEntry->nMemberId == MID_FONTHEIGHT )
+ {
+ pEntry->nMemberId |= CONVERT_TWIPS;
+ }
+
+ ++pEntry;
+ }
+
+ return SvxItemPropertySet(aHdFtPropertyMap_Impl, SdrObject::GetGlobalDrawObjectItemPool());
+ }();
+ return &aHdFtPropertySet_Impl;
+}
+
+SC_SIMPLE_SERVICE_INFO( ScHeaderFooterContentObj, "ScHeaderFooterContentObj", "com.sun.star.sheet.HeaderFooterContent" )
+SC_SIMPLE_SERVICE_INFO( ScHeaderFooterTextObj, "ScHeaderFooterTextObj", "stardiv.one.Text.Text" )
+
+ScHeaderFooterContentObj::ScHeaderFooterContentObj()
+{
+}
+
+ScHeaderFooterContentObj::~ScHeaderFooterContentObj() {}
+
+const EditTextObject* ScHeaderFooterContentObj::GetLeftEditObject() const
+{
+ return mxLeftText->GetTextObject();
+}
+
+const EditTextObject* ScHeaderFooterContentObj::GetCenterEditObject() const
+{
+ return mxCenterText->GetTextObject();
+}
+
+const EditTextObject* ScHeaderFooterContentObj::GetRightEditObject() const
+{
+ return mxRightText->GetTextObject();
+}
+
+// XHeaderFooterContent
+
+uno::Reference<text::XText> SAL_CALL ScHeaderFooterContentObj::getLeftText()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<text::XText> xInt(*mxLeftText, uno::UNO_QUERY);
+ return xInt;
+}
+
+uno::Reference<text::XText> SAL_CALL ScHeaderFooterContentObj::getCenterText()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<text::XText> xInt(*mxCenterText, uno::UNO_QUERY);
+ return xInt;
+}
+
+uno::Reference<text::XText> SAL_CALL ScHeaderFooterContentObj::getRightText()
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<text::XText> xInt(*mxRightText, uno::UNO_QUERY);
+ return xInt;
+}
+
+// XUnoTunnel
+
+sal_Int64 SAL_CALL ScHeaderFooterContentObj::getSomething(
+ const uno::Sequence<sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+const uno::Sequence<sal_Int8>& ScHeaderFooterContentObj::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theScHeaderFooterContentObjUnoTunnelId;
+ return theScHeaderFooterContentObjUnoTunnelId.getSeq();
+}
+
+rtl::Reference<ScHeaderFooterContentObj> ScHeaderFooterContentObj::getImplementation(
+ const uno::Reference<sheet::XHeaderFooterContent>& rObj)
+{
+ return comphelper::getFromUnoTunnel<ScHeaderFooterContentObj>(rObj);
+}
+
+void ScHeaderFooterContentObj::Init( const EditTextObject* pLeft,
+ const EditTextObject* pCenter,
+ const EditTextObject* pRight )
+{
+ uno::Reference<css::sheet::XHeaderFooterContent> xThis(this);
+ mxLeftText = rtl::Reference<ScHeaderFooterTextObj>(new ScHeaderFooterTextObj(xThis, ScHeaderFooterPart::LEFT, pLeft));
+ mxCenterText = rtl::Reference<ScHeaderFooterTextObj>(new ScHeaderFooterTextObj(xThis, ScHeaderFooterPart::CENTER, pCenter));
+ mxRightText = rtl::Reference<ScHeaderFooterTextObj>(new ScHeaderFooterTextObj(xThis, ScHeaderFooterPart::RIGHT, pRight));
+}
+
+ScHeaderFooterTextData::ScHeaderFooterTextData(
+ uno::WeakReference<sheet::XHeaderFooterContent> const & xContent, ScHeaderFooterPart nP, const EditTextObject* pTextObj) :
+ mpTextObj(pTextObj ? pTextObj->Clone() : nullptr),
+ xContentObj( xContent ),
+ nPart( nP ),
+ bDataValid(false)
+{
+}
+
+ScHeaderFooterTextData::~ScHeaderFooterTextData()
+{
+ SolarMutexGuard aGuard; // needed for EditEngine dtor
+
+ pForwarder.reset();
+ pEditEngine.reset();
+}
+
+SvxTextForwarder* ScHeaderFooterTextData::GetTextForwarder()
+{
+ if (!pEditEngine)
+ {
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->FreezeIdRanges();
+ std::unique_ptr<ScHeaderEditEngine> pHdrEngine(new ScHeaderEditEngine( pEnginePool.get() ));
+
+ pHdrEngine->EnableUndo( false );
+ pHdrEngine->SetRefMapMode(MapMode(MapUnit::MapTwip));
+
+ // default font must be set, independently of document
+ // -> use global pool from module
+
+ SfxItemSet aDefaults( pHdrEngine->GetEmptyItemSet() );
+ const ScPatternAttr& rPattern = SC_MOD()->GetPool().GetDefaultItem(ATTR_PATTERN);
+ rPattern.FillEditItemSet( &aDefaults );
+ // FillEditItemSet adjusts font height to 1/100th mm,
+ // but for header/footer twips is needed, as in the PatternAttr:
+ aDefaults.Put( rPattern.GetItem(ATTR_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT) );
+ aDefaults.Put( rPattern.GetItem(ATTR_CJK_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CJK) ) ;
+ aDefaults.Put( rPattern.GetItem(ATTR_CTL_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CTL) );
+ pHdrEngine->SetDefaults( aDefaults );
+
+ ScHeaderFieldData aData;
+ ScHeaderFooterTextObj::FillDummyFieldData( aData );
+ pHdrEngine->SetData( aData );
+
+ pEditEngine = std::move(pHdrEngine);
+ pForwarder.reset( new SvxEditEngineForwarder(*pEditEngine) );
+ }
+
+ if (bDataValid)
+ return pForwarder.get();
+
+ if (mpTextObj)
+ pEditEngine->SetTextCurrentDefaults(*mpTextObj);
+
+ bDataValid = true;
+ return pForwarder.get();
+}
+
+void ScHeaderFooterTextData::UpdateData()
+{
+ if (pEditEngine)
+ {
+ mpTextObj = pEditEngine->CreateTextObject();
+ }
+}
+
+void ScHeaderFooterTextData::UpdateData(EditEngine& rEditEngine)
+{
+ mpTextObj = rEditEngine.CreateTextObject();
+ bDataValid = false;
+}
+
+ScHeaderFooterTextObj::ScHeaderFooterTextObj(
+ const uno::WeakReference<sheet::XHeaderFooterContent>& xContent, ScHeaderFooterPart nP, const EditTextObject* pTextObj) :
+ aTextData(xContent, nP, pTextObj)
+{
+ // ScHeaderFooterTextData acquires rContent
+ // pUnoText is created on demand (getString/setString work without it)
+}
+
+void ScHeaderFooterTextObj::CreateUnoText_Impl()
+{
+ if (!mxUnoText.is())
+ {
+ // can't be aggregated because getString/setString is handled here
+ ScHeaderFooterEditSource aEditSrc(aTextData);
+ mxUnoText.set(new SvxUnoText(&aEditSrc, lcl_GetHdFtPropertySet(), uno::Reference<text::XText>()));
+ }
+}
+
+ScHeaderFooterTextObj::~ScHeaderFooterTextObj() {}
+
+const EditTextObject* ScHeaderFooterTextObj::GetTextObject() const
+{
+ return aTextData.GetTextObject();
+}
+
+const SvxUnoText& ScHeaderFooterTextObj::GetUnoText()
+{
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return *mxUnoText;
+}
+
+// XText
+
+uno::Reference<text::XTextCursor> SAL_CALL ScHeaderFooterTextObj::createTextCursor()
+{
+ SolarMutexGuard aGuard;
+ return new ScHeaderFooterTextCursor( this );
+}
+
+uno::Reference<text::XTextCursor> SAL_CALL ScHeaderFooterTextObj::createTextCursorByRange(
+ const uno::Reference<text::XTextRange>& aTextPosition )
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->createTextCursorByRange(aTextPosition);
+ //! like ScCellObj::createTextCursorByRange, if SvxUnoTextRange_getReflection available
+}
+
+void ScHeaderFooterTextObj::FillDummyFieldData( ScHeaderFieldData& rData )
+{
+ OUString aDummy("???");
+ rData.aTitle = aDummy;
+ rData.aLongDocName = aDummy;
+ rData.aShortDocName = aDummy;
+ rData.aTabName = aDummy;
+ rData.nPageNo = 1;
+ rData.nTotalPages = 99;
+}
+
+OUString SAL_CALL ScHeaderFooterTextObj::getString()
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+ const EditTextObject* pData;
+
+ uno::Reference<css::sheet::XHeaderFooterContent> xContentObj = aTextData.GetContentObj();
+ if (!xContentObj.is())
+ throw css::uno::RuntimeException(
+ "ScHeaderFooterTextObj::getString: no ContentObj");
+
+ rtl::Reference<ScHeaderFooterContentObj> pObj = ScHeaderFooterContentObj::getImplementation(xContentObj);
+
+ switch ( aTextData.GetPart() )
+ {
+ case ScHeaderFooterPart::LEFT:
+ pData = pObj->GetLeftEditObject();
+ break;
+ case ScHeaderFooterPart::CENTER:
+ pData = pObj->GetCenterEditObject();
+ break;
+ case ScHeaderFooterPart::RIGHT:
+ pData = pObj->GetRightEditObject();
+ break;
+ default:
+ SAL_WARN("sc.ui","unexpected enum value of ScHeaderFooterPart");
+ pData = nullptr;
+ }
+
+ if (pData)
+ {
+ // for pure text, no font info is needed in pool defaults
+ ScHeaderEditEngine aEditEngine( EditEngine::CreatePool().get() );
+
+ ScHeaderFieldData aData;
+ FillDummyFieldData( aData );
+ aEditEngine.SetData( aData );
+
+ aEditEngine.SetTextCurrentDefaults(*pData);
+ aRet = ScEditUtil::GetSpaceDelimitedString( aEditEngine );
+ }
+ return aRet;
+}
+
+void SAL_CALL ScHeaderFooterTextObj::setString( const OUString& aText )
+{
+ SolarMutexGuard aGuard;
+
+ // for pure text, no font info is needed in pool defaults
+ ScHeaderEditEngine aEditEngine(EditEngine::CreatePool().get());
+ aEditEngine.SetTextCurrentDefaults( aText );
+ aTextData.UpdateData(aEditEngine);
+}
+
+void SAL_CALL ScHeaderFooterTextObj::insertString( const uno::Reference<text::XTextRange>& xRange,
+ const OUString& aString, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ mxUnoText->insertString( xRange, aString, bAbsorb );
+}
+
+void SAL_CALL ScHeaderFooterTextObj::insertControlCharacter(
+ const uno::Reference<text::XTextRange>& xRange,
+ sal_Int16 nControlCharacter, sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ mxUnoText->insertControlCharacter( xRange, nControlCharacter, bAbsorb );
+}
+
+void SAL_CALL ScHeaderFooterTextObj::insertTextContent(
+ const uno::Reference<text::XTextRange >& xRange,
+ const uno::Reference<text::XTextContent >& xContent,
+ sal_Bool bAbsorb )
+{
+ SolarMutexGuard aGuard;
+ if ( xContent.is() && xRange.is() )
+ {
+ ScEditFieldObj* pHeaderField = comphelper::getFromUnoTunnel<ScEditFieldObj>( xContent );
+
+ SvxUnoTextRangeBase* pTextRange =
+ comphelper::getFromUnoTunnel<ScHeaderFooterTextCursor>( xRange );
+
+ if ( pHeaderField && !pHeaderField->IsInserted() && pTextRange )
+ {
+ SvxEditSource* pEditSource = pTextRange->GetEditSource();
+ ESelection aSelection(pTextRange->GetSelection());
+
+ if (!bAbsorb)
+ {
+ // don't replace -> append at end
+ aSelection.Adjust();
+ aSelection.nStartPara = aSelection.nEndPara;
+ aSelection.nStartPos = aSelection.nEndPos;
+ }
+
+ SvxFieldItem aItem(pHeaderField->CreateFieldItem());
+
+ SvxTextForwarder* pForwarder = pEditSource->GetTextForwarder();
+ pForwarder->QuickInsertField( aItem, aSelection );
+ pEditSource->UpdateData();
+
+ // new selection: a digit
+ aSelection.Adjust();
+ aSelection.nEndPara = aSelection.nStartPara;
+ aSelection.nEndPos = aSelection.nStartPos + 1;
+
+ uno::Reference<text::XTextRange> xTextRange;
+ switch ( aTextData.GetPart() )
+ {
+ case ScHeaderFooterPart::LEFT:
+ xTextRange = aTextData.GetContentObj()->getLeftText();
+ break;
+ case ScHeaderFooterPart::CENTER:
+ xTextRange = aTextData.GetContentObj()->getCenterText();
+ break;
+ case ScHeaderFooterPart::RIGHT:
+ xTextRange = aTextData.GetContentObj()->getRightText();
+ break;
+ }
+
+ pHeaderField->InitDoc(xTextRange, std::make_unique<ScHeaderFooterEditSource>(aTextData), aSelection);
+
+ // for bAbsorb=FALSE, the new selection must be behind the inserted content
+ // (the xml filter relies on this)
+ if (!bAbsorb)
+ aSelection.nStartPos = aSelection.nEndPos;
+
+ pTextRange->SetSelection( aSelection );
+
+ return;
+ }
+ }
+
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ mxUnoText->insertTextContent( xRange, xContent, bAbsorb );
+}
+
+void SAL_CALL ScHeaderFooterTextObj::removeTextContent(
+ const uno::Reference<text::XTextContent>& xContent )
+{
+ SolarMutexGuard aGuard;
+ if ( xContent.is() )
+ {
+ ScEditFieldObj* pHeaderField = comphelper::getFromUnoTunnel<ScEditFieldObj>(xContent);
+ if ( pHeaderField && pHeaderField->IsInserted() )
+ {
+ //! check if the field is in this cell
+ pHeaderField->DeleteField();
+ return;
+ }
+ }
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ mxUnoText->removeTextContent( xContent );
+}
+
+uno::Reference<text::XText> SAL_CALL ScHeaderFooterTextObj::getText()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->getText();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScHeaderFooterTextObj::getStart()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->getStart();
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScHeaderFooterTextObj::getEnd()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->getEnd();
+}
+
+// XTextFieldsSupplier
+
+uno::Reference<container::XEnumerationAccess> SAL_CALL ScHeaderFooterTextObj::getTextFields()
+{
+ SolarMutexGuard aGuard;
+ // all fields
+ return new ScHeaderFieldsObj(aTextData);
+}
+
+uno::Reference<container::XNameAccess> SAL_CALL ScHeaderFooterTextObj::getTextFieldMasters()
+{
+ // this does not exists in Calc (?)
+ return nullptr;
+}
+
+// XTextRangeMover
+
+void SAL_CALL ScHeaderFooterTextObj::moveTextRange(
+ const uno::Reference<text::XTextRange>& xRange,
+ sal_Int16 nParagraphs )
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ mxUnoText->moveTextRange( xRange, nParagraphs );
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScHeaderFooterTextObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->createEnumeration();
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScHeaderFooterTextObj::getElementType()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->getElementType();
+}
+
+sal_Bool SAL_CALL ScHeaderFooterTextObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ if (!mxUnoText.is())
+ CreateUnoText_Impl();
+ return mxUnoText->hasElements();
+}
+
+ScCellTextCursor::ScCellTextCursor(ScCellObj& rText) :
+ SvxUnoTextCursor( rText.GetUnoText() ),
+ mxTextObj( &rText )
+{
+}
+
+ScCellTextCursor::~ScCellTextCursor() noexcept
+{
+}
+
+// SvxUnoTextCursor methods reimplemented here to return the right objects:
+
+uno::Reference<text::XText> SAL_CALL ScCellTextCursor::getText()
+{
+ return mxTextObj;
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScCellTextCursor::getStart()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScCellTextCursor> pNew = new ScCellTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nEndPara = aNewSel.nStartPara;
+ aNewSel.nEndPos = aNewSel.nStartPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScCellTextCursor::getEnd()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScCellTextCursor> pNew = new ScCellTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nStartPara = aNewSel.nEndPara;
+ aNewSel.nStartPos = aNewSel.nEndPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION2_IMPL(ScCellTextCursor, SvxUnoTextCursor);
+
+ScHeaderFooterTextCursor::ScHeaderFooterTextCursor(rtl::Reference<ScHeaderFooterTextObj> const & rText) :
+ SvxUnoTextCursor( rText->GetUnoText() ),
+ rTextObj( rText )
+{}
+
+ScHeaderFooterTextCursor::~ScHeaderFooterTextCursor() noexcept {};
+
+// SvxUnoTextCursor methods reimplemented here to return the right objects:
+
+uno::Reference<text::XText> SAL_CALL ScHeaderFooterTextCursor::getText()
+{
+ SolarMutexGuard aGuard;
+ return rTextObj;
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScHeaderFooterTextCursor::getStart()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScHeaderFooterTextCursor> pNew = new ScHeaderFooterTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nEndPara = aNewSel.nStartPara;
+ aNewSel.nEndPos = aNewSel.nStartPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScHeaderFooterTextCursor::getEnd()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScHeaderFooterTextCursor> pNew = new ScHeaderFooterTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nStartPara = aNewSel.nEndPara;
+ aNewSel.nStartPos = aNewSel.nEndPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION2_IMPL(ScHeaderFooterTextCursor, SvxUnoTextCursor);
+
+ScDrawTextCursor::ScDrawTextCursor( const uno::Reference<text::XText>& xParent,
+ const SvxUnoTextBase& rText ) :
+ SvxUnoTextCursor( rText ),
+ xParentText( xParent )
+
+{
+}
+
+ScDrawTextCursor::~ScDrawTextCursor() noexcept
+{
+}
+
+// SvxUnoTextCursor methods reimplemented here to return the right objects:
+
+uno::Reference<text::XText> SAL_CALL ScDrawTextCursor::getText()
+{
+ SolarMutexGuard aGuard;
+ return xParentText;
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScDrawTextCursor::getStart()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScDrawTextCursor> pNew = new ScDrawTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nEndPara = aNewSel.nStartPara;
+ aNewSel.nEndPos = aNewSel.nStartPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+uno::Reference<text::XTextRange> SAL_CALL ScDrawTextCursor::getEnd()
+{
+ SolarMutexGuard aGuard;
+
+ //! use other object for range than cursor?
+
+ rtl::Reference<ScDrawTextCursor> pNew = new ScDrawTextCursor( *this );
+
+ ESelection aNewSel(GetSelection());
+ aNewSel.nStartPara = aNewSel.nEndPara;
+ aNewSel.nStartPos = aNewSel.nEndPos;
+ pNew->SetSelection( aNewSel );
+
+ return static_cast<SvxUnoTextRangeBase*>(pNew.get());
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION2_IMPL(ScDrawTextCursor, SvxUnoTextCursor);
+
+ScSimpleEditSourceHelper::ScSimpleEditSourceHelper()
+{
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->SetDefaultMetric( MapUnit::Map100thMM );
+ pEnginePool->FreezeIdRanges();
+
+ pEditEngine.reset( new ScFieldEditEngine(nullptr, pEnginePool.get(), nullptr, true) ); // TRUE: become owner of pool
+ pForwarder.reset( new SvxEditEngineForwarder( *pEditEngine ) );
+ pOriginalSource.reset( new ScSimpleEditSource( pForwarder.get() ) );
+}
+
+ScSimpleEditSourceHelper::~ScSimpleEditSourceHelper()
+{
+ SolarMutexGuard aGuard; // needed for EditEngine dtor
+
+ pOriginalSource.reset();
+ pForwarder.reset();
+ pEditEngine.reset();
+}
+
+ScEditEngineTextObj::ScEditEngineTextObj() :
+ SvxUnoText( GetOriginalSource(), ScCellObj::GetEditPropertySet(), uno::Reference<text::XText>() )
+{
+}
+
+ScEditEngineTextObj::~ScEditEngineTextObj() noexcept
+{
+}
+
+void ScEditEngineTextObj::SetText( const EditTextObject& rTextObject )
+{
+ GetEditEngine()->SetTextCurrentDefaults( rTextObject );
+
+ ESelection aSel;
+ ::GetSelection( aSel, GetEditSource()->GetTextForwarder() );
+ SetSelection( aSel );
+}
+
+std::unique_ptr<EditTextObject> ScEditEngineTextObj::CreateTextObject()
+{
+ return GetEditEngine()->CreateTextObject();
+}
+
+ScCellTextData::ScCellTextData(ScDocShell* pDocSh, const ScAddress& rP) :
+ pDocShell( pDocSh ),
+ aCellPos( rP ),
+ bDataValid( false ),
+ bInUpdate( false ),
+ bDirty( false ),
+ bDoUpdate( true )
+{
+ if (pDocShell)
+ pDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScCellTextData::~ScCellTextData()
+{
+ SolarMutexGuard aGuard; // needed for EditEngine dtor
+
+ if (pDocShell)
+ {
+ pDocShell->GetDocument().RemoveUnoObject(*this);
+ pDocShell->GetDocument().DisposeFieldEditEngine(pEditEngine);
+ }
+ else
+ pEditEngine.reset();
+
+ pForwarder.reset();
+
+ pOriginalSource.reset();
+}
+
+ScCellEditSource* ScCellTextData::GetOriginalSource()
+{
+ if (!pOriginalSource)
+ pOriginalSource.reset( new ScCellEditSource(pDocShell, aCellPos) );
+ return pOriginalSource.get();
+}
+
+SvxTextForwarder* ScCellTextData::GetTextForwarder()
+{
+ if (!pEditEngine)
+ {
+ if ( pDocShell )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ pEditEngine = rDoc.CreateFieldEditEngine();
+ }
+ else
+ {
+ rtl::Reference<SfxItemPool> pEnginePool = EditEngine::CreatePool();
+ pEnginePool->FreezeIdRanges();
+ pEditEngine.reset( new ScFieldEditEngine(nullptr, pEnginePool.get(), nullptr, true) );
+ }
+ // currently, GetPortions doesn't work if UpdateMode is sal_False,
+ // this will be fixed (in EditEngine) by src600
+// pEditEngine->SetUpdateMode( sal_False );
+ pEditEngine->EnableUndo( false );
+ if (pDocShell)
+ pEditEngine->SetRefDevice(pDocShell->GetRefDevice());
+ else
+ pEditEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
+ pForwarder.reset( new SvxEditEngineForwarder(*pEditEngine) );
+ }
+
+ if (bDataValid)
+ return pForwarder.get();
+
+ if (pDocShell)
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ SfxItemSet aDefaults( pEditEngine->GetEmptyItemSet() );
+ if( const ScPatternAttr* pPattern =
+ rDoc.GetPattern( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab() ) )
+ {
+ pPattern->FillEditItemSet( &aDefaults );
+ pPattern->FillEditParaItems( &aDefaults ); // including alignment etc. (for reading)
+ }
+
+ ScRefCellValue aCell(rDoc, aCellPos);
+ if (aCell.meType == CELLTYPE_EDIT)
+ {
+ const EditTextObject* pObj = aCell.mpEditText;
+ pEditEngine->SetTextNewDefaults(*pObj, aDefaults);
+ }
+ else
+ {
+ sal_uInt32 nFormat = rDoc.GetNumberFormat(aCellPos);
+ OUString aText = ScCellFormat::GetInputString(aCell, nFormat, *rDoc.GetFormatTable(), rDoc);
+ if (!aText.isEmpty())
+ pEditEngine->SetTextNewDefaults(aText, aDefaults);
+ else
+ pEditEngine->SetDefaults(aDefaults);
+ }
+ }
+
+ bDataValid = true;
+ return pForwarder.get();
+}
+
+void ScCellTextData::UpdateData()
+{
+ if ( bDoUpdate )
+ {
+ OSL_ENSURE(pEditEngine != nullptr, "no EditEngine for UpdateData()");
+ if ( pDocShell && pEditEngine )
+ {
+ // during the own UpdateData call, bDataValid must not be reset,
+ // or things like attributes after the text would be lost
+ // (are not stored in the cell)
+ bInUpdate = true; // prevents bDataValid from being reset
+ pDocShell->GetDocFunc().PutData(aCellPos, *pEditEngine, true); // always as text
+
+ bInUpdate = false;
+ bDirty = false;
+ }
+ }
+ else
+ bDirty = true;
+}
+
+void ScCellTextData::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ const SfxHintId nId = rHint.GetId();
+ if ( nId == SfxHintId::Dying )
+ {
+ pDocShell = nullptr; // invalid now
+
+ pForwarder.reset();
+ pEditEngine.reset(); // EditEngine uses document's pool
+ }
+ else if ( nId == SfxHintId::DataChanged )
+ {
+ if (!bInUpdate) // not for own UpdateData calls
+ bDataValid = false; // text has to be read from the cell again
+ }
+}
+
+ScCellTextObj::ScCellTextObj(ScDocShell* pDocSh, const ScAddress& rP) :
+ ScCellTextData( pDocSh, rP ),
+ SvxUnoText( GetOriginalSource(), ScCellObj::GetEditPropertySet(), uno::Reference<text::XText>() )
+{
+}
+
+ScCellTextObj::~ScCellTextObj() COVERITY_NOEXCEPT_FALSE
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/tokenuno.cxx b/sc/source/ui/unoobj/tokenuno.cxx
new file mode 100644
index 000000000..40cb3a613
--- /dev/null
+++ b/sc/source/ui/unoobj/tokenuno.cxx
@@ -0,0 +1,521 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <tokenuno.hxx>
+
+#include <sal/macros.h>
+#include <sal/log.hxx>
+
+#include <com/sun/star/sheet/ComplexReference.hpp>
+#include <com/sun/star/sheet/ExternalReference.hpp>
+#include <com/sun/star/sheet/ReferenceFlags.hpp>
+#include <com/sun/star/sheet/AddressConvention.hpp>
+#include <com/sun/star/sheet/NameToken.hpp>
+#include <com/sun/star/table/CellAddress.hpp>
+
+#include <svl/itemprop.hxx>
+#include <vcl/svapp.hxx>
+#include <comphelper/string.hxx>
+
+#include <miscuno.hxx>
+#include <convuno.hxx>
+#include <unonames.hxx>
+#include <compiler.hxx>
+#include <tokenarray.hxx>
+#include <docsh.hxx>
+#include <rangeseq.hxx>
+#include <externalrefmgr.hxx>
+
+using namespace ::formula;
+using namespace ::com::sun::star;
+
+static const SfxItemPropertyMapEntry* lcl_GetFormulaParserMap()
+{
+ static const SfxItemPropertyMapEntry aFormulaParserMap_Impl[] =
+ {
+ { SC_UNO_COMPILEFAP, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_COMPILEENGLISH, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_IGNORELEADING, 0, cppu::UnoType<bool>::get(), 0, 0 },
+ { SC_UNO_FORMULACONVENTION, 0, cppu::UnoType<decltype(sheet::AddressConvention::UNSPECIFIED)>::get(), 0, 0 },
+ { SC_UNO_OPCODEMAP, 0, cppu::UnoType<uno::Sequence< sheet::FormulaOpCodeMapEntry >>::get(), 0, 0 },
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aFormulaParserMap_Impl;
+}
+
+const formula::FormulaGrammar::AddressConvention aConvMap[] = {
+ formula::FormulaGrammar::CONV_OOO, // <- AddressConvention::OOO
+ formula::FormulaGrammar::CONV_XL_A1, // <- AddressConvention::XL_A1
+ formula::FormulaGrammar::CONV_XL_R1C1, // <- AddressConvention::XL_R1C1
+ formula::FormulaGrammar::CONV_XL_OOX, // <- AddressConvention::XL_OOX
+ formula::FormulaGrammar::CONV_LOTUS_A1 // <- AddressConvention::LOTUS_A1
+};
+// sal_Int16 because of comparison of integer expressions below.
+constexpr sal_Int16 nConvMapCount = SAL_N_ELEMENTS(aConvMap);
+
+
+SC_SIMPLE_SERVICE_INFO( ScFormulaParserObj, "ScFormulaParserObj", SC_SERVICENAME_FORMULAPARS )
+
+ScFormulaParserObj::ScFormulaParserObj(ScDocShell* pDocSh) :
+ mpDocShell( pDocSh ),
+ mnConv( sheet::AddressConvention::UNSPECIFIED ),
+ mbEnglish( false ),
+ mbIgnoreSpaces( true ),
+ mbCompileFAP( false ),
+ mbRefConventionChartOOXML( false )
+{
+ mpDocShell->GetDocument().AddUnoObject(*this);
+}
+
+ScFormulaParserObj::~ScFormulaParserObj()
+{
+ SolarMutexGuard g;
+
+ if (mpDocShell)
+ mpDocShell->GetDocument().RemoveUnoObject(*this);
+}
+
+void ScFormulaParserObj::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ mpDocShell = nullptr;
+}
+
+// XFormulaParser
+
+void ScFormulaParserObj::SetCompilerFlags( ScCompiler& rCompiler ) const
+{
+ formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_UNSPECIFIED;
+ if (mnConv >= 0 && mnConv < nConvMapCount)
+ eConv = aConvMap[mnConv];
+
+ // If mxOpCodeMap is not empty it overrides mbEnglish, and vice versa. We
+ // don't need to initialize things twice.
+ if (mxOpCodeMap)
+ rCompiler.SetFormulaLanguage( mxOpCodeMap );
+ else
+ {
+ const sal_Int32 nFormulaLanguage = (eConv == formula::FormulaGrammar::CONV_XL_OOX ?
+ sheet::FormulaLanguage::OOXML :
+ (mbEnglish ? sheet::FormulaLanguage::ENGLISH : sheet::FormulaLanguage::NATIVE));
+ ScCompiler::OpCodeMapPtr xMap = rCompiler.GetOpCodeMap( nFormulaLanguage);
+ rCompiler.SetFormulaLanguage( xMap);
+ }
+
+ rCompiler.SetRefConvention( eConv );
+ rCompiler.EnableJumpCommandReorder(!mbCompileFAP);
+ rCompiler.EnableStopOnError(!mbCompileFAP);
+
+ rCompiler.SetExternalLinks(maExternalLinks);
+ rCompiler.SetRefConventionChartOOXML(mbRefConventionChartOOXML);
+}
+
+uno::Sequence<sheet::FormulaToken> SAL_CALL ScFormulaParserObj::parseFormula(
+ const OUString& aFormula, const table::CellAddress& rReferencePos )
+{
+ SolarMutexGuard aGuard;
+ uno::Sequence<sheet::FormulaToken> aRet;
+
+ if (mpDocShell)
+ {
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ ScExternalRefManager::ApiGuard aExtRefGuard(rDoc);
+
+ ScAddress aRefPos( ScAddress::UNINITIALIZED );
+ ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
+ ScCompiler aCompiler( rDoc, aRefPos, rDoc.GetGrammar());
+ SetCompilerFlags( aCompiler );
+
+ std::unique_ptr<ScTokenArray> pCode = aCompiler.CompileString( aFormula );
+ ScTokenConversion::ConvertToTokenSequence( rDoc, aRet, *pCode );
+ }
+
+ return aRet;
+}
+
+OUString SAL_CALL ScFormulaParserObj::printFormula(
+ const uno::Sequence<sheet::FormulaToken>& aTokens, const table::CellAddress& rReferencePos )
+{
+ SolarMutexGuard aGuard;
+ OUString aRet;
+
+ if (mpDocShell)
+ {
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ ScTokenArray aCode(rDoc);
+ (void)ScTokenConversion::ConvertToTokenArray( rDoc, aCode, aTokens );
+ ScAddress aRefPos( ScAddress::UNINITIALIZED );
+ ScUnoConversion::FillScAddress( aRefPos, rReferencePos );
+ ScCompiler aCompiler(rDoc, aRefPos, aCode, rDoc.GetGrammar());
+ SetCompilerFlags( aCompiler );
+
+ OUStringBuffer aBuffer;
+ aCompiler.CreateStringFromTokenArray( aBuffer );
+ aRet = aBuffer.makeStringAndClear();
+ }
+
+ return aRet;
+}
+
+// XPropertySet
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScFormulaParserObj::getPropertySetInfo()
+{
+ static uno::Reference< beans::XPropertySetInfo > aRef(new SfxItemPropertySetInfo( lcl_GetFormulaParserMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScFormulaParserObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+ if ( aPropertyName == SC_UNO_COMPILEFAP )
+ {
+ aValue >>= mbCompileFAP;
+ }
+ else if ( aPropertyName == SC_UNO_COMPILEENGLISH )
+ {
+ bool bOldEnglish = mbEnglish;
+ if (!(aValue >>= mbEnglish))
+ throw lang::IllegalArgumentException();
+
+ // Need to recreate the symbol map to change English property
+ // because the map is const. So for performance reasons set
+ // CompileEnglish _before_ OpCodeMap!
+ if (mxOpCodeMap && mbEnglish != bOldEnglish)
+ {
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ ScCompiler aCompiler( rDoc, ScAddress(), rDoc.GetGrammar());
+ mxOpCodeMap = formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping, mbEnglish);
+ }
+
+ }
+ else if ( aPropertyName == SC_UNO_FORMULACONVENTION )
+ {
+ aValue >>= mnConv;
+
+ bool bOldEnglish = mbEnglish;
+ if (mnConv >= 0 && mnConv < nConvMapCount
+ && aConvMap[mnConv] == formula::FormulaGrammar::CONV_XL_OOX)
+ mbEnglish = true;
+
+ // Same as for SC_UNO_COMPILEENGLISH, though an OpCodeMap should not
+ // had been set for CONV_XL_OOX.
+ if (mxOpCodeMap && mbEnglish != bOldEnglish)
+ {
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ ScCompiler aCompiler( rDoc, ScAddress(), rDoc.GetGrammar());
+ mxOpCodeMap = formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping, mbEnglish);
+ }
+ }
+ else if ( aPropertyName == SC_UNO_IGNORELEADING )
+ {
+ aValue >>= mbIgnoreSpaces;
+ }
+ else if ( aPropertyName == SC_UNO_OPCODEMAP )
+ {
+ if (!(aValue >>= maOpCodeMapping))
+ throw lang::IllegalArgumentException();
+
+ ScDocument& rDoc = mpDocShell->GetDocument();
+ ScCompiler aCompiler(rDoc, ScAddress(), rDoc.GetGrammar());
+ mxOpCodeMap = formula::FormulaCompiler::CreateOpCodeMap( maOpCodeMapping, mbEnglish);
+
+ }
+ else if ( aPropertyName == SC_UNO_EXTERNALLINKS )
+ {
+ if (!(aValue >>= maExternalLinks))
+ throw lang::IllegalArgumentException();
+ }
+ else if ( aPropertyName == SC_UNO_REF_CONV_CHARTOOXML )
+ {
+ if (!(aValue >>= mbRefConventionChartOOXML))
+ throw lang::IllegalArgumentException();
+ }
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+}
+
+uno::Any SAL_CALL ScFormulaParserObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+ if ( aPropertyName == SC_UNO_COMPILEFAP )
+ {
+ aRet <<= mbCompileFAP;
+ }
+ else if ( aPropertyName == SC_UNO_COMPILEENGLISH )
+ {
+ aRet <<= mbEnglish;
+ }
+ else if ( aPropertyName == SC_UNO_FORMULACONVENTION )
+ {
+ aRet <<= mnConv;
+ }
+ else if ( aPropertyName == SC_UNO_IGNORELEADING )
+ {
+ aRet <<= mbIgnoreSpaces;
+ }
+ else if ( aPropertyName == SC_UNO_OPCODEMAP )
+ {
+ aRet <<= maOpCodeMapping;
+ }
+ else if ( aPropertyName == SC_UNO_EXTERNALLINKS )
+ {
+ aRet <<= maExternalLinks;
+ }
+ else if ( aPropertyName == SC_UNO_REF_CONV_CHARTOOXML )
+ {
+ aRet <<= mbRefConventionChartOOXML;
+ }
+ else
+ throw beans::UnknownPropertyException(aPropertyName);
+ return aRet;
+}
+
+SC_IMPL_DUMMY_PROPERTY_LISTENER( ScFormulaParserObj )
+
+static void lcl_ExternalRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
+{
+ rAPI.Column = 0;
+ rAPI.Row = 0;
+ rAPI.Sheet = 0;
+ rAPI.RelativeColumn = 0;
+ rAPI.RelativeRow = 0;
+ rAPI.RelativeSheet = 0;
+
+ sal_Int32 nFlags = 0;
+ if ( rRef.IsColRel() )
+ {
+ nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
+ rAPI.RelativeColumn = rRef.Col();
+ }
+ else
+ rAPI.Column = rRef.Col();
+
+ if ( rRef.IsRowRel() )
+ {
+ nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
+ rAPI.RelativeRow = rRef.Row();
+ }
+ else
+ rAPI.Row = rRef.Row();
+
+ if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
+ if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
+ if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
+ if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
+ rAPI.Flags = nFlags;
+}
+
+static void lcl_SingleRefToApi( sheet::SingleReference& rAPI, const ScSingleRefData& rRef )
+{
+ sal_Int32 nFlags = 0;
+ if ( rRef.IsColRel() )
+ {
+ nFlags |= sheet::ReferenceFlags::COLUMN_RELATIVE;
+ rAPI.RelativeColumn = rRef.Col();
+ rAPI.Column = 0;
+ }
+ else
+ {
+ rAPI.RelativeColumn = 0;
+ rAPI.Column = rRef.Col();
+ }
+
+ if ( rRef.IsRowRel() )
+ {
+ nFlags |= sheet::ReferenceFlags::ROW_RELATIVE;
+ rAPI.RelativeRow = rRef.Row();
+ rAPI.Row = 0;
+ }
+ else
+ {
+ rAPI.RelativeRow = 0;
+ rAPI.Row = rRef.Row();
+ }
+
+ if ( rRef.IsTabRel() )
+ {
+ nFlags |= sheet::ReferenceFlags::SHEET_RELATIVE;
+ rAPI.RelativeSheet = rRef.Tab();
+ rAPI.Sheet = 0;
+ }
+ else
+ {
+ rAPI.RelativeSheet = 0;
+ rAPI.Sheet = rRef.Tab();
+ }
+
+ if ( rRef.IsColDeleted() ) nFlags |= sheet::ReferenceFlags::COLUMN_DELETED;
+ if ( rRef.IsRowDeleted() ) nFlags |= sheet::ReferenceFlags::ROW_DELETED;
+ if ( rRef.IsTabDeleted() ) nFlags |= sheet::ReferenceFlags::SHEET_DELETED;
+ if ( rRef.IsFlag3D() ) nFlags |= sheet::ReferenceFlags::SHEET_3D;
+ if ( rRef.IsRelName() ) nFlags |= sheet::ReferenceFlags::RELATIVE_NAME;
+ rAPI.Flags = nFlags;
+}
+
+bool ScTokenConversion::ConvertToTokenArray( ScDocument& rDoc,
+ ScTokenArray& rTokenArray, const uno::Sequence<sheet::FormulaToken>& rSequence )
+{
+ return !rTokenArray.Fill(rSequence, rDoc.GetSharedStringPool(), rDoc.GetExternalRefManager());
+}
+
+void ScTokenConversion::ConvertToTokenSequence( const ScDocument& rDoc,
+ uno::Sequence<sheet::FormulaToken>& rSequence, const ScTokenArray& rTokenArray )
+{
+ sal_Int32 nLen = static_cast<sal_Int32>(rTokenArray.GetLen());
+ formula::FormulaToken** pTokens = rTokenArray.GetArray();
+ if ( pTokens )
+ {
+ rSequence.realloc(nLen);
+ auto pSequence = rSequence.getArray();
+ for (sal_Int32 nPos=0; nPos<nLen; nPos++)
+ {
+ const formula::FormulaToken& rToken = *pTokens[nPos];
+ sheet::FormulaToken& rAPI = pSequence[nPos];
+
+ OpCode eOpCode = rToken.GetOpCode();
+ // eOpCode may be changed in the following switch/case
+ switch ( rToken.GetType() )
+ {
+ case svByte:
+ // Only the count of spaces is stored as "long". Parameter count is ignored.
+ if ( eOpCode == ocSpaces )
+ rAPI.Data <<= static_cast<sal_Int32>(rToken.GetByte());
+ else if (eOpCode == ocWhitespace)
+ {
+ // Convention is one character repeated.
+ if (rToken.GetByte() == 1)
+ rAPI.Data <<= OUString( rToken.GetChar());
+ else
+ {
+ OUStringBuffer aBuf( rToken.GetByte());
+ comphelper::string::padToLength( aBuf, rToken.GetByte(), rToken.GetChar());
+ rAPI.Data <<= aBuf.makeStringAndClear();
+ }
+ }
+ else
+ rAPI.Data.clear(); // no data
+ break;
+ case formula::svDouble:
+ rAPI.Data <<= rToken.GetDouble();
+ break;
+ case formula::svString:
+ rAPI.Data <<= rToken.GetString().getString();
+ break;
+ case svExternal:
+ // Function name is stored as string.
+ // Byte (parameter count) is ignored.
+ rAPI.Data <<= rToken.GetExternal();
+ break;
+ case svSingleRef:
+ {
+ sheet::SingleReference aSingleRef;
+ lcl_SingleRefToApi( aSingleRef, *rToken.GetSingleRef() );
+ rAPI.Data <<= aSingleRef;
+ }
+ break;
+ case formula::svDoubleRef:
+ {
+ sheet::ComplexReference aCompRef;
+ lcl_SingleRefToApi( aCompRef.Reference1, *rToken.GetSingleRef() );
+ lcl_SingleRefToApi( aCompRef.Reference2, *rToken.GetSingleRef2() );
+ rAPI.Data <<= aCompRef;
+ }
+ break;
+ case svIndex:
+ {
+ sheet::NameToken aNameToken;
+ aNameToken.Index = static_cast<sal_Int32>( rToken.GetIndex() );
+ aNameToken.Sheet = rToken.GetSheet();
+ rAPI.Data <<= aNameToken;
+ }
+ break;
+ case svMatrix:
+ if (!ScRangeToSequence::FillMixedArray( rAPI.Data, rToken.GetMatrix(), true))
+ rAPI.Data.clear();
+ break;
+ case svExternalSingleRef:
+ {
+ sheet::SingleReference aSingleRef;
+ lcl_ExternalRefToApi( aSingleRef, *rToken.GetSingleRef() );
+ size_t nCacheId;
+ rDoc.GetExternalRefManager()->getCacheTable(
+ rToken.GetIndex(), rToken.GetString().getString(), false, &nCacheId);
+ aSingleRef.Sheet = static_cast< sal_Int32 >( nCacheId );
+ sheet::ExternalReference aExtRef;
+ aExtRef.Index = rToken.GetIndex();
+ aExtRef.Reference <<= aSingleRef;
+ rAPI.Data <<= aExtRef;
+ eOpCode = ocPush;
+ }
+ break;
+ case svExternalDoubleRef:
+ {
+ sheet::ComplexReference aComplRef;
+ lcl_ExternalRefToApi( aComplRef.Reference1, *rToken.GetSingleRef() );
+ lcl_ExternalRefToApi( aComplRef.Reference2, *rToken.GetSingleRef2() );
+ size_t nCacheId;
+ rDoc.GetExternalRefManager()->getCacheTable(
+ rToken.GetIndex(), rToken.GetString().getString(), false, &nCacheId);
+ aComplRef.Reference1.Sheet = static_cast< sal_Int32 >( nCacheId );
+ // NOTE: This assumes that cached sheets are in consecutive order!
+ aComplRef.Reference2.Sheet =
+ aComplRef.Reference1.Sheet +
+ (rToken.GetSingleRef2()->Tab() - rToken.GetSingleRef()->Tab());
+ sheet::ExternalReference aExtRef;
+ aExtRef.Index = rToken.GetIndex();
+ aExtRef.Reference <<= aComplRef;
+ rAPI.Data <<= aExtRef;
+ eOpCode = ocPush;
+ }
+ break;
+ case svExternalName:
+ {
+ sheet::ExternalReference aExtRef;
+ aExtRef.Index = rToken.GetIndex();
+ aExtRef.Reference <<= rToken.GetString().getString();
+ rAPI.Data <<= aExtRef;
+ eOpCode = ocPush;
+ }
+ break;
+ default:
+ SAL_WARN("sc", "ScTokenConversion::ConvertToTokenSequence: unhandled token type " << StackVarEnumToString(rToken.GetType()));
+ [[fallthrough]];
+ case svJump: // occurs with ocIf, ocChoose
+ case svError: // seems to be fairly common, and probably not exceptional and not worth a warning?
+ case svMissing: // occurs with ocMissing
+ case svSep: // occurs with ocSep, ocOpen, ocClose, ocArray*
+ rAPI.Data.clear(); // no data
+ }
+ rAPI.OpCode = static_cast<sal_Int32>(eOpCode); //! assuming equal values for the moment
+ }
+ }
+ else
+ rSequence.realloc(0);
+}
+
+ScFormulaOpCodeMapperObj::ScFormulaOpCodeMapperObj(::std::unique_ptr<formula::FormulaCompiler> && _pCompiler)
+: formula::FormulaOpCodeMapperObj(std::move(_pCompiler))
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/unodoc.cxx b/sc/source/ui/unoobj/unodoc.cxx
new file mode 100644
index 000000000..bed297df7
--- /dev/null
+++ b/sc/source/ui/unoobj/unodoc.cxx
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/sfxmodelfactory.hxx>
+
+#include <scdll.hxx>
+#include <vcl/svapp.hxx>
+
+#include <docsh.hxx>
+
+using namespace ::com::sun::star;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_SpreadsheetDocument_get_implementation(
+ css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const& args)
+{
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ css::uno::Reference<css::uno::XInterface> xInterface = sfx2::createSfxModelInstance(args,
+ [](SfxModelFlags _nCreationFlags)
+ {
+ SfxObjectShell* pShell = new ScDocShell( _nCreationFlags );
+ return uno::Reference< uno::XInterface >( pShell->GetModel() );
+ });
+ xInterface->acquire();
+ return xInterface.get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/unoreflist.cxx b/sc/source/ui/unoobj/unoreflist.cxx
new file mode 100644
index 000000000..b2c1fb5f0
--- /dev/null
+++ b/sc/source/ui/unoobj/unoreflist.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 <unoreflist.hxx>
+#include <document.hxx>
+
+ScUnoRefList::ScUnoRefList()
+{
+}
+
+ScUnoRefList::~ScUnoRefList()
+{
+}
+
+void ScUnoRefList::Add( sal_Int64 nId, const ScRangeList& rOldRanges )
+{
+ aEntries.emplace_back( nId, rOldRanges );
+}
+
+void ScUnoRefList::Undo( ScDocument* pDoc )
+{
+ for (const auto & entry: aEntries)
+ {
+ ScUnoRefUndoHint aHint(entry);
+ pDoc->BroadcastUno( aHint );
+ }
+}
+
+ScUnoRefUndoHint::ScUnoRefUndoHint( const ScUnoRefEntry& rRefEntry ) :
+ aEntry( rRefEntry )
+{
+}
+
+ScUnoRefUndoHint::~ScUnoRefUndoHint()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/viewuno.cxx b/sc/source/ui/unoobj/viewuno.cxx
new file mode 100644
index 000000000..d50a833cf
--- /dev/null
+++ b/sc/source/ui/unoobj/viewuno.cxx
@@ -0,0 +1,2204 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/MouseButton.hpp>
+#include <com/sun/star/drawing/ShapeCollection.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
+#include <com/sun/star/util/VetoException.hpp>
+#include <com/sun/star/view/DocumentZoomType.hpp>
+
+#include <editeng/outliner.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <svx/unoshape.hxx>
+#include <svx/fmshell.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <comphelper/profilezone.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <toolkit/helper/convert.hxx>
+#include <vcl/svapp.hxx>
+
+#include <drawsh.hxx>
+#include <drtxtob.hxx>
+#include <transobj.hxx>
+#include <editsh.hxx>
+#include <viewuno.hxx>
+#include <cellsuno.hxx>
+#include <miscuno.hxx>
+#include <tabvwsh.hxx>
+#include <prevwsh.hxx>
+#include <docsh.hxx>
+#include <drwlayer.hxx>
+#include <drawview.hxx>
+#include <fupoor.hxx>
+#include <sc.hrc>
+#include <unonames.hxx>
+#include <scmod.hxx>
+#include <appoptio.hxx>
+#include <gridwin.hxx>
+#include <sheetevents.hxx>
+#include <markdata.hxx>
+#include <scextopt.hxx>
+#include <preview.hxx>
+#include <inputhdl.hxx>
+#include <inputwin.hxx>
+#include <svx/sdrhittesthelper.hxx>
+#include <formatsh.hxx>
+#include <sfx2/app.hxx>
+
+using namespace com::sun::star;
+
+//! Clipping Marks
+
+// no Which-ID here, Map only for PropertySetInfo
+
+static const SfxItemPropertyMapEntry* lcl_GetViewOptPropertyMap()
+{
+ static const SfxItemPropertyMapEntry aViewOptPropertyMap_Impl[] =
+ {
+ { OLD_UNO_COLROWHDR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_GRIDCOLOR, 0, cppu::UnoType<sal_Int32>::get(), 0, 0},
+ { SC_UNO_COLROWHDR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_HORSCROLL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHEETTABS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_VERTSCROLL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_HIDESPELL, 0, cppu::UnoType<bool>::get(), 0, 0}, /* deprecated #i91949 */
+ { OLD_UNO_HORSCROLL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_OUTLSYMB, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_VALUEHIGH, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { OLD_UNO_OUTLSYMB, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { OLD_UNO_SHEETTABS, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWANCHOR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWCHARTS, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SHOWDRAW, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SHOWFORM, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWGRID, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWHELP, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWNOTES, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWOBJ, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_SHOWPAGEBR, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_SHOWZERO, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { OLD_UNO_VALUEHIGH, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { OLD_UNO_VERTSCROLL, 0, cppu::UnoType<bool>::get(), 0, 0},
+ { SC_UNO_VISAREA, 0, cppu::UnoType<awt::Rectangle>::get(), 0, 0},
+ { SC_UNO_ZOOMTYPE, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_ZOOMVALUE, 0, cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { SC_UNO_VISAREASCREEN,0, cppu::UnoType<awt::Rectangle>::get(), 0, 0},
+ { SC_UNO_FORMULABARHEIGHT,0,cppu::UnoType<sal_Int16>::get(), 0, 0},
+ { u"", 0, css::uno::Type(), 0, 0 }
+ };
+ return aViewOptPropertyMap_Impl;
+}
+
+constexpr OUStringLiteral SCTABVIEWOBJ_SERVICE = u"com.sun.star.sheet.SpreadsheetView";
+constexpr OUStringLiteral SCVIEWSETTINGS_SERVICE = u"com.sun.star.sheet.SpreadsheetViewSettings";
+
+SC_SIMPLE_SERVICE_INFO( ScViewPaneBase, "ScViewPaneObj", "com.sun.star.sheet.SpreadsheetViewPane" )
+
+ScViewPaneBase::ScViewPaneBase(ScTabViewShell* pViewSh, sal_uInt16 nP) :
+ pViewShell( pViewSh ),
+ nPane( nP )
+{
+ if (pViewShell)
+ StartListening(*pViewShell);
+}
+
+ScViewPaneBase::~ScViewPaneBase()
+{
+ SolarMutexGuard g;
+
+ if (pViewShell)
+ EndListening(*pViewShell);
+}
+
+void ScViewPaneBase::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ if ( rHint.GetId() == SfxHintId::Dying )
+ pViewShell = nullptr;
+}
+
+uno::Any SAL_CALL ScViewPaneBase::queryInterface( const uno::Type& rType )
+{
+ SC_QUERYINTERFACE( sheet::XViewPane )
+ SC_QUERYINTERFACE( sheet::XCellRangeReferrer )
+ SC_QUERYINTERFACE( view::XFormLayerAccess )
+ SC_QUERYINTERFACE( view::XControlAccess )
+ SC_QUERYINTERFACE( lang::XServiceInfo )
+ SC_QUERYINTERFACE( lang::XTypeProvider )
+
+ return uno::Any(); // OWeakObject is in derived objects
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScViewPaneBase::getTypes()
+{
+ static const uno::Sequence<uno::Type> aTypes
+ {
+ cppu::UnoType<sheet::XViewPane>::get(),
+ cppu::UnoType<sheet::XCellRangeReferrer>::get(),
+ cppu::UnoType<view::XFormLayerAccess>::get(),
+ cppu::UnoType<lang::XServiceInfo>::get(),
+ cppu::UnoType<lang::XTypeProvider>::get(),
+ };
+ return aTypes;
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScViewPaneBase::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XViewPane
+
+sal_Int32 SAL_CALL ScViewPaneBase::getFirstVisibleColumn()
+{
+ SolarMutexGuard aGuard;
+ if (pViewShell)
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScHSplitPos eWhichH = WhichH( eWhich );
+
+ return rViewData.GetPosX( eWhichH );
+ }
+ OSL_FAIL("no View ?!?"); //! Exception?
+ return 0;
+}
+
+void SAL_CALL ScViewPaneBase::setFirstVisibleColumn(sal_Int32 nFirstVisibleColumn)
+{
+ SolarMutexGuard aGuard;
+ if (pViewShell)
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScHSplitPos eWhichH = WhichH( eWhich );
+
+ tools::Long nDeltaX = static_cast<tools::Long>(nFirstVisibleColumn) - rViewData.GetPosX( eWhichH );
+ pViewShell->ScrollX( nDeltaX, eWhichH );
+ }
+}
+
+sal_Int32 SAL_CALL ScViewPaneBase::getFirstVisibleRow()
+{
+ SolarMutexGuard aGuard;
+ if (pViewShell)
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScVSplitPos eWhichV = WhichV( eWhich );
+
+ return rViewData.GetPosY( eWhichV );
+ }
+ OSL_FAIL("no View ?!?"); //! Exception?
+ return 0;
+}
+
+void SAL_CALL ScViewPaneBase::setFirstVisibleRow( sal_Int32 nFirstVisibleRow )
+{
+ SolarMutexGuard aGuard;
+ if (pViewShell)
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScVSplitPos eWhichV = WhichV( eWhich );
+
+ tools::Long nDeltaY = static_cast<tools::Long>(nFirstVisibleRow) - rViewData.GetPosY( eWhichV );
+ pViewShell->ScrollY( nDeltaY, eWhichV );
+ }
+}
+
+table::CellRangeAddress SAL_CALL ScViewPaneBase::getVisibleRange()
+{
+ SolarMutexGuard aGuard;
+ table::CellRangeAddress aAdr;
+ if (pViewShell)
+ {
+ ScViewData& rViewData = pViewShell->GetViewData();
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScHSplitPos eWhichH = WhichH( eWhich );
+ ScVSplitPos eWhichV = WhichV( eWhich );
+
+ // VisibleCellsX returns only completely visible cells
+ // VisibleRange in Excel also partially visible ones
+ //! do the same ???
+
+ SCCOL nVisX = rViewData.VisibleCellsX( eWhichH );
+ SCROW nVisY = rViewData.VisibleCellsY( eWhichV );
+ if (!nVisX) nVisX = 1; // there has to be something in the range
+ if (!nVisY) nVisY = 1;
+ aAdr.Sheet = rViewData.GetTabNo();
+ aAdr.StartColumn = rViewData.GetPosX( eWhichH );
+ aAdr.StartRow = rViewData.GetPosY( eWhichV );
+ aAdr.EndColumn = aAdr.StartColumn + nVisX - 1;
+ aAdr.EndRow = aAdr.StartRow + nVisY - 1;
+ }
+ return aAdr;
+}
+
+// XCellRangeSource
+
+uno::Reference<table::XCellRange> SAL_CALL ScViewPaneBase::getReferredCells()
+{
+ SolarMutexGuard aGuard;
+ if (pViewShell)
+ {
+ ScDocShell* pDocSh = pViewShell->GetViewData().GetDocShell();
+
+ table::CellRangeAddress aAdr(getVisibleRange()); //! helper function with ScRange?
+ ScRange aRange( static_cast<SCCOL>(aAdr.StartColumn), static_cast<SCROW>(aAdr.StartRow), aAdr.Sheet,
+ static_cast<SCCOL>(aAdr.EndColumn), static_cast<SCROW>(aAdr.EndRow), aAdr.Sheet );
+ if ( aRange.aStart == aRange.aEnd )
+ return new ScCellObj( pDocSh, aRange.aStart );
+ else
+ return new ScCellRangeObj( pDocSh, aRange );
+ }
+
+ return nullptr;
+}
+
+namespace
+{
+ bool lcl_prepareFormShellCall( ScTabViewShell* _pViewShell, sal_uInt16 _nPane, FmFormShell*& _rpFormShell, vcl::Window*& _rpWindow, SdrView*& _rpSdrView )
+ {
+ if ( !_pViewShell )
+ return false;
+
+ ScViewData& rViewData = _pViewShell->GetViewData();
+ ScSplitPos eWhich = ( _nPane == SC_VIEWPANE_ACTIVE ) ?
+ rViewData.GetActivePart() :
+ static_cast<ScSplitPos>(_nPane);
+ _rpWindow = _pViewShell->GetWindowByPos( eWhich );
+ _rpSdrView = _pViewShell->GetScDrawView();
+ _rpFormShell = _pViewShell->GetFormShell();
+ return ( _rpFormShell != nullptr ) && ( _rpSdrView != nullptr )&& ( _rpWindow != nullptr );
+ }
+}
+
+// XFormLayerAccess
+uno::Reference< form::runtime::XFormController > SAL_CALL ScViewPaneBase::getFormController( const uno::Reference< form::XForm >& Form )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference< form::runtime::XFormController > xController;
+
+ vcl::Window* pWindow( nullptr );
+ SdrView* pSdrView( nullptr );
+ FmFormShell* pFormShell( nullptr );
+ if ( lcl_prepareFormShellCall( pViewShell, nPane, pFormShell, pWindow, pSdrView ) )
+ xController = FmFormShell::GetFormController( Form, *pSdrView, *pWindow->GetOutDev() );
+
+ return xController;
+}
+
+sal_Bool SAL_CALL ScViewPaneBase::isFormDesignMode( )
+{
+ SolarMutexGuard aGuard;
+
+ bool bIsFormDesignMode( true );
+
+ FmFormShell* pFormShell( pViewShell ? pViewShell->GetFormShell() : nullptr );
+ if ( pFormShell )
+ bIsFormDesignMode = pFormShell->IsDesignMode();
+
+ return bIsFormDesignMode;
+}
+
+void SAL_CALL ScViewPaneBase::setFormDesignMode( sal_Bool DesignMode )
+{
+ SolarMutexGuard aGuard;
+
+ vcl::Window* pWindow( nullptr );
+ SdrView* pSdrView( nullptr );
+ FmFormShell* pFormShell( nullptr );
+ if ( lcl_prepareFormShellCall( pViewShell, nPane, pFormShell, pWindow, pSdrView ) )
+ pFormShell->SetDesignMode( DesignMode );
+}
+
+// XControlAccess
+
+uno::Reference<awt::XControl> SAL_CALL ScViewPaneBase::getControl(
+ const uno::Reference<awt::XControlModel>& xModel )
+{
+ SolarMutexGuard aGuard;
+
+ uno::Reference<awt::XControl> xRet;
+
+ vcl::Window* pWindow( nullptr );
+ SdrView* pSdrView( nullptr );
+ FmFormShell* pFormShell( nullptr );
+ if ( lcl_prepareFormShellCall( pViewShell, nPane, pFormShell, pWindow, pSdrView ) )
+ pFormShell->GetFormControl( xModel, *pSdrView, *pWindow->GetOutDev(), xRet );
+
+ if ( !xRet.is() )
+ throw container::NoSuchElementException(); // no control found
+
+ return xRet;
+}
+
+awt::Rectangle ScViewPaneBase::GetVisArea() const
+{
+ awt::Rectangle aVisArea;
+ if (pViewShell)
+ {
+ ScSplitPos eWhich = ( nPane == SC_VIEWPANE_ACTIVE ) ?
+ pViewShell->GetViewData().GetActivePart() :
+ static_cast<ScSplitPos>(nPane);
+ ScGridWindow* pWindow = static_cast<ScGridWindow*>(pViewShell->GetWindowByPos(eWhich));
+ ScDocument& rDoc = pViewShell->GetViewData().GetDocument();
+ if (pWindow)
+ {
+ ScHSplitPos eWhichH = ((eWhich == SC_SPLIT_TOPLEFT) || (eWhich == SC_SPLIT_BOTTOMLEFT)) ?
+ SC_SPLIT_LEFT : SC_SPLIT_RIGHT;
+ ScVSplitPos eWhichV = ((eWhich == SC_SPLIT_TOPLEFT) || (eWhich == SC_SPLIT_TOPRIGHT)) ?
+ SC_SPLIT_TOP : SC_SPLIT_BOTTOM;
+ ScAddress aCell(pViewShell->GetViewData().GetPosX(eWhichH),
+ pViewShell->GetViewData().GetPosY(eWhichV),
+ pViewShell->GetViewData().GetTabNo());
+ tools::Rectangle aCellRect( rDoc.GetMMRect( aCell.Col(), aCell.Row(), aCell.Col(), aCell.Row(), aCell.Tab() ) );
+ Size aVisSize( pWindow->PixelToLogic( pWindow->GetSizePixel(), pWindow->GetDrawMapMode( true ) ) );
+ Point aVisPos( aCellRect.TopLeft() );
+ if ( rDoc.IsLayoutRTL( aCell.Tab() ) )
+ {
+ aVisPos = aCellRect.TopRight();
+ aVisPos.AdjustX( -(aVisSize.Width()) );
+ }
+ tools::Rectangle aVisRect( aVisPos, aVisSize );
+ aVisArea = AWTRectangle(aVisRect);
+ }
+ }
+ return aVisArea;
+}
+
+ScViewPaneObj::ScViewPaneObj(ScTabViewShell* pViewSh, sal_uInt16 nP) :
+ ScViewPaneBase( pViewSh, nP )
+{
+}
+
+ScViewPaneObj::~ScViewPaneObj()
+{
+}
+
+uno::Any SAL_CALL ScViewPaneObj::queryInterface( const uno::Type& rType )
+{
+ // ScViewPaneBase has everything except OWeakObject
+
+ uno::Any aRet(ScViewPaneBase::queryInterface( rType ));
+ if (!aRet.hasValue())
+ aRet = OWeakObject::queryInterface( rType );
+ return aRet;
+}
+
+void SAL_CALL ScViewPaneObj::acquire() noexcept
+{
+ OWeakObject::acquire();
+}
+
+void SAL_CALL ScViewPaneObj::release() noexcept
+{
+ OWeakObject::release();
+}
+
+// We need default ctor for SMART_REFLECTION_IMPLEMENTATION
+
+ScTabViewObj::ScTabViewObj( ScTabViewShell* pViewSh ) :
+ ScViewPaneBase( pViewSh, SC_VIEWPANE_ACTIVE ),
+ SfxBaseController( pViewSh ),
+ aPropSet( lcl_GetViewOptPropertyMap() ),
+ aMouseClickHandlers( 0 ),
+ aActivationListeners( 0 ),
+ nPreviousTab( 0 ),
+ bDrawSelModeSet(false),
+ bFilteredRangeSelection(false),
+ mbLeftMousePressed(false)
+{
+ if (pViewSh)
+ nPreviousTab = pViewSh->GetViewData().GetTabNo();
+}
+
+ScTabViewObj::~ScTabViewObj()
+{
+ //! Listening or something along that line
+ if (!aMouseClickHandlers.empty())
+ {
+ acquire();
+ EndMouseListening();
+ }
+ if (!aActivationListeners.empty())
+ {
+ acquire();
+ EndActivationListening();
+ }
+}
+
+uno::Any SAL_CALL ScTabViewObj::queryInterface( const uno::Type& rType )
+{
+ SC_QUERYINTERFACE( sheet::XSpreadsheetView )
+ SC_QUERYINTERFACE( sheet::XEnhancedMouseClickBroadcaster )
+ SC_QUERYINTERFACE( sheet::XActivationBroadcaster )
+ SC_QUERYINTERFACE( container::XEnumerationAccess )
+ SC_QUERYINTERFACE( container::XIndexAccess )
+ SC_QUERY_MULTIPLE( container::XElementAccess, container::XIndexAccess )
+ SC_QUERYINTERFACE( view::XSelectionSupplier )
+ SC_QUERYINTERFACE( beans::XPropertySet )
+ SC_QUERYINTERFACE( sheet::XViewSplitable )
+ SC_QUERYINTERFACE( sheet::XViewFreezable )
+ SC_QUERYINTERFACE( sheet::XRangeSelection )
+ SC_QUERYINTERFACE( lang::XUnoTunnel )
+ SC_QUERYINTERFACE( datatransfer::XTransferableSupplier )
+ SC_QUERYINTERFACE( sheet::XSelectedSheetsSupplier )
+
+ uno::Any aRet(ScViewPaneBase::queryInterface( rType ));
+ if (!aRet.hasValue())
+ aRet = SfxBaseController::queryInterface( rType );
+ return aRet;
+}
+
+void SAL_CALL ScTabViewObj::acquire() noexcept
+{
+ SfxBaseController::acquire();
+}
+
+void SAL_CALL ScTabViewObj::release() noexcept
+{
+ SfxBaseController::release();
+}
+
+static void lcl_CallActivate( ScDocShell* pDocSh, SCTAB nTab, ScSheetEventId nEvent )
+{
+ ScDocument& rDoc = pDocSh->GetDocument();
+ // when deleting a sheet, nPreviousTab can be invalid
+ // (could be handled with reference updates)
+ if (!rDoc.HasTable(nTab))
+ return;
+
+ const ScSheetEvents* pEvents = rDoc.GetSheetEvents(nTab);
+ if (pEvents)
+ {
+ const OUString* pScript = pEvents->GetScript(nEvent);
+ if (pScript)
+ {
+ uno::Any aRet;
+ uno::Sequence<uno::Any> aParams;
+ uno::Sequence<sal_Int16> aOutArgsIndex;
+ uno::Sequence<uno::Any> aOutArgs;
+ /*ErrCode eRet =*/ pDocSh->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
+ }
+ }
+
+ // execute VBA event handlers
+ try
+ {
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( rDoc.GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ // the parameter is the clicked object, as in the mousePressed call above
+ uno::Sequence< uno::Any > aArgs{ uno::Any(nTab) };
+ xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+void ScTabViewObj::SheetChanged( bool bSameTabButMoved )
+{
+ if ( !GetViewShell() )
+ return;
+
+ ScViewData& rViewData = GetViewShell()->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ if (!aActivationListeners.empty())
+ {
+ sheet::ActivationEvent aEvent;
+ uno::Reference< sheet::XSpreadsheetView > xView(this);
+ uno::Reference< uno::XInterface > xSource(xView, uno::UNO_QUERY);
+ aEvent.Source = xSource;
+ aEvent.ActiveSheet = new ScTableSheetObj(pDocSh, rViewData.GetTabNo());
+ // Listener's handler may remove it from the listeners list
+ for (size_t i = aActivationListeners.size(); i > 0; --i)
+ {
+ try
+ {
+ aActivationListeners[i - 1]->activeSpreadsheetChanged( aEvent );
+ }
+ catch( uno::Exception& )
+ {
+ aActivationListeners.erase(aActivationListeners.begin() + (i - 1));
+ }
+ }
+ }
+
+ /* Handle sheet events, but do not trigger event handlers, if the old
+ active sheet gets re-activated after inserting/deleting/moving a sheet. */
+ SCTAB nNewTab = rViewData.GetTabNo();
+ if ( !bSameTabButMoved && (nNewTab != nPreviousTab) )
+ {
+ lcl_CallActivate( pDocSh, nPreviousTab, ScSheetEventId::UNFOCUS );
+ lcl_CallActivate( pDocSh, nNewTab, ScSheetEventId::FOCUS );
+ }
+ nPreviousTab = nNewTab;
+}
+
+uno::Sequence<uno::Type> SAL_CALL ScTabViewObj::getTypes()
+{
+ return comphelper::concatSequences(
+ ScViewPaneBase::getTypes(),
+ SfxBaseController::getTypes(),
+ uno::Sequence<uno::Type>
+ {
+ cppu::UnoType<sheet::XSpreadsheetView>::get(),
+ cppu::UnoType<container::XEnumerationAccess>::get(),
+ cppu::UnoType<container::XIndexAccess>::get(),
+ cppu::UnoType<view::XSelectionSupplier>::get(),
+ cppu::UnoType<beans::XPropertySet>::get(),
+ cppu::UnoType<sheet::XViewSplitable>::get(),
+ cppu::UnoType<sheet::XViewFreezable>::get(),
+ cppu::UnoType<sheet::XRangeSelection>::get(),
+ cppu::UnoType<lang::XUnoTunnel>::get(),
+ cppu::UnoType<sheet::XEnhancedMouseClickBroadcaster>::get(),
+ cppu::UnoType<sheet::XActivationBroadcaster>::get(),
+ cppu::UnoType<datatransfer::XTransferableSupplier>::get()
+ } );
+}
+
+uno::Sequence<sal_Int8> SAL_CALL ScTabViewObj::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XDocumentView
+
+static bool lcl_TabInRanges( SCTAB nTab, const ScRangeList& rRanges )
+{
+ for (size_t i = 0, nCount = rRanges.size(); i < nCount; ++i)
+ {
+ const ScRange & rRange = rRanges[ i ];
+ if ( nTab >= rRange.aStart.Tab() && nTab <= rRange.aEnd.Tab() )
+ return true;
+ }
+ return false;
+}
+
+static void lcl_ShowObject( ScTabViewShell& rViewSh, const ScDrawView& rDrawView, const SdrObject* pSelObj )
+{
+ bool bFound = false;
+ SCTAB nObjectTab = 0;
+
+ SdrModel* pModel = rDrawView.GetModel();
+ sal_uInt16 nPageCount = pModel->GetPageCount();
+ for (sal_uInt16 i=0; i<nPageCount && !bFound; i++)
+ {
+ SdrPage* pPage = pModel->GetPage(i);
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !bFound)
+ {
+ if ( pObject == pSelObj )
+ {
+ bFound = true;
+ nObjectTab = static_cast<SCTAB>(i);
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+
+ if (bFound)
+ {
+ rViewSh.SetTabNo( nObjectTab );
+ rViewSh.ScrollToObject( pSelObj );
+ }
+}
+
+sal_Bool SAL_CALL ScTabViewObj::select( const uno::Any& aSelection )
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+
+ if ( !pViewSh )
+ return false;
+
+ //! Type of aSelection can be some specific interface instead of XInterface
+
+ bool bRet = false;
+ uno::Reference<uno::XInterface> xInterface(aSelection, uno::UNO_QUERY);
+ if ( !xInterface.is() ) //clear all selections
+ {
+ ScDrawView* pDrawView = pViewSh->GetScDrawView();
+ if (pDrawView)
+ {
+ pDrawView->ScEndTextEdit();
+ pDrawView->UnmarkAll();
+ }
+ else //#102232#; if there is no DrawView remove range selection
+ pViewSh->Unmark();
+ bRet = true;
+ }
+
+ if (bDrawSelModeSet) // remove DrawSelMode if set by API; if necessary it will be set again later
+ {
+ pViewSh->SetDrawSelMode(false);
+ pViewSh->UpdateLayerLocks();
+ bDrawSelModeSet = false;
+ }
+
+ if (bRet)
+ return bRet;
+
+ ScCellRangesBase* pRangesImp = comphelper::getFromUnoTunnel<ScCellRangesBase>( xInterface );
+ uno::Reference<drawing::XShapes> xShapeColl( xInterface, uno::UNO_QUERY );
+ uno::Reference<drawing::XShape> xShapeSel( xInterface, uno::UNO_QUERY );
+ SvxShape* pShapeImp = comphelper::getFromUnoTunnel<SvxShape>( xShapeSel );
+
+ if (pRangesImp) // Cell ranges
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetDocShell() == pRangesImp->GetDocShell() )
+ {
+ // perhaps remove drawing selection first
+ // (MarkListHasChanged removes sheet selection)
+
+ ScDrawView* pDrawView = pViewSh->GetScDrawView();
+ if (pDrawView)
+ {
+ pDrawView->ScEndTextEdit();
+ pDrawView->UnmarkAll();
+ }
+ FuPoor* pFunc = pViewSh->GetDrawFuncPtr();
+ if ( pFunc && pFunc->GetSlotID() != SID_OBJECT_SELECT )
+ {
+ // execute the slot of drawing function again -> switch off
+ SfxDispatcher* pDisp = pViewSh->GetDispatcher();
+ if (pDisp)
+ pDisp->Execute( pFunc->GetSlotID(), SfxCallMode::SYNCHRON );
+ }
+ pViewSh->SetDrawShell(false);
+ pViewSh->SetDrawSelMode(false); // after Dispatcher-Execute
+
+ // select ranges
+
+ const ScRangeList& rRanges = pRangesImp->GetRangeList();
+ size_t nRangeCount = rRanges.size();
+ // for empty range list, remove selection (cursor remains where it was)
+ if ( nRangeCount == 0 )
+ pViewSh->Unmark();
+ else if ( nRangeCount == 1 )
+ pViewSh->MarkRange( rRanges[ 0 ] );
+ else
+ {
+ // multiselection
+
+ const ScRange & rFirst = rRanges[ 0 ];
+ if ( !lcl_TabInRanges( rViewData.GetTabNo(), rRanges ) )
+ pViewSh->SetTabNo( rFirst.aStart.Tab() );
+ pViewSh->DoneBlockMode();
+ pViewSh->InitOwnBlockMode( rFirst ); /* TODO: or even the overall range? */
+ rViewData.GetMarkData().MarkFromRangeList( rRanges, true );
+ pViewSh->MarkDataChanged();
+ rViewData.GetDocShell()->PostPaintGridAll(); // Marks (old&new)
+ pViewSh->AlignToCursor( rFirst.aStart.Col(), rFirst.aStart.Row(),
+ SC_FOLLOW_JUMP );
+ pViewSh->SetCursor( rFirst.aStart.Col(), rFirst.aStart.Row() );
+
+ //! method of the view to select RangeList
+ }
+ bRet = true;
+ }
+ }
+ else if ( pShapeImp || xShapeColl.is() ) // Drawing-Layer
+ {
+ ScDrawView* pDrawView = pViewSh->GetScDrawView();
+ if (pDrawView)
+ {
+ pDrawView->ScEndTextEdit();
+ pDrawView->UnmarkAll();
+
+ if (pShapeImp) // single shape
+ {
+ SdrObject *pObj = pShapeImp->GetSdrObject();
+ if (pObj)
+ {
+ lcl_ShowObject( *pViewSh, *pDrawView, pObj );
+ SdrPageView* pPV = pDrawView->GetSdrPageView();
+ if ( pPV && pObj->getSdrPageFromSdrObject() == pPV->GetPage() )
+ {
+ pDrawView->MarkObj( pObj, pPV );
+ bRet = true;
+ }
+ }
+ }
+ else // Shape-Collection (xShapeColl is not 0)
+ {
+ // We'll switch to the sheet where the first object is
+ // and select all objects on that sheet
+ //!?throw exception when objects are on different sheets?
+
+ tools::Long nCount = xShapeColl->getCount();
+ if (nCount)
+ {
+ SdrPageView* pPV = nullptr;
+ bool bAllMarked(true);
+ for ( tools::Long i = 0; i < nCount; i++ )
+ {
+ uno::Reference<drawing::XShape> xShapeInt(xShapeColl->getByIndex(i), uno::UNO_QUERY);
+ if (xShapeInt.is())
+ {
+ SdrObject* pObj = SdrObject::getSdrObjectFromXShape( xShapeInt );
+ if (pObj)
+ {
+ if (!bDrawSelModeSet && (pObj->GetLayer() == SC_LAYER_BACK))
+ {
+ pViewSh->SetDrawSelMode(true);
+ pViewSh->UpdateLayerLocks();
+ bDrawSelModeSet = true;
+ }
+ if (!pPV) // first object
+ {
+ lcl_ShowObject( *pViewSh, *pDrawView, pObj );
+ pPV = pDrawView->GetSdrPageView();
+ }
+ if ( pPV && pObj->getSdrPageFromSdrObject() == pPV->GetPage() )
+ {
+ if (pDrawView->IsObjMarkable( pObj, pPV ))
+ pDrawView->MarkObj( pObj, pPV );
+ else
+ bAllMarked = false;
+ }
+ }
+ }
+ }
+ if (bAllMarked)
+ bRet = true;
+ }
+ else
+ bRet = true; // empty XShapes (all shapes are deselected)
+ }
+
+ if (bRet)
+ pViewSh->SetDrawShell(true);
+ }
+ }
+
+ if (!bRet)
+ throw lang::IllegalArgumentException();
+
+ return bRet;
+}
+
+uno::Reference<drawing::XShapes> ScTabViewShell::getSelectedXShapes()
+{
+ uno::Reference<drawing::XShapes> xShapes;
+ SdrView* pSdrView = GetScDrawView();
+ if (pSdrView)
+ {
+ const SdrMarkList& rMarkList = pSdrView->GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+ if (nMarkCount)
+ {
+ // generate ShapeCollection (like in SdXImpressView::getSelection in Draw)
+ // XInterfaceRef will be returned and it has to be UsrObject-XInterface
+ xShapes = drawing::ShapeCollection::create(comphelper::getProcessComponentContext());
+
+ for (size_t i = 0; i < nMarkCount; ++i)
+ {
+ SdrObject* pDrawObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if (pDrawObj)
+ {
+ uno::Reference<drawing::XShape> xShape( pDrawObj->getUnoShape(), uno::UNO_QUERY );
+ if (xShape.is())
+ xShapes->add(xShape);
+ }
+ }
+ }
+ }
+ return xShapes;
+}
+
+uno::Any SAL_CALL ScTabViewObj::getSelection()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ rtl::Reference<ScCellRangesBase> pObj;
+ if (pViewSh)
+ {
+ // is something selected in drawing layer?
+ uno::Reference<uno::XInterface> xRet(pViewSh->getSelectedXShapes());
+ if (xRet.is())
+ return uno::Any(xRet);
+
+ // otherwise sheet (cell) selection
+
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+
+ const ScMarkData& rMark = rViewData.GetMarkData();
+ SCTAB nTabs = rMark.GetSelectCount();
+
+ ScRange aRange;
+ ScMarkType eMarkType = rViewData.GetSimpleArea(aRange);
+ if ( nTabs == 1 && (eMarkType == SC_MARK_SIMPLE) )
+ {
+ if (aRange.aStart == aRange.aEnd)
+ pObj = new ScCellObj( pDocSh, aRange.aStart );
+ else
+ pObj = new ScCellRangeObj( pDocSh, aRange );
+ }
+ else if ( nTabs == 1 && (eMarkType == SC_MARK_SIMPLE_FILTERED) )
+ {
+ ScMarkData aFilteredMark( rMark );
+ ScViewUtil::UnmarkFiltered( aFilteredMark, pDocSh->GetDocument());
+ ScRangeList aRangeList;
+ aFilteredMark.FillRangeListWithMarks( &aRangeList, false);
+ // Theoretically a selection may start and end on a filtered row.
+ switch ( aRangeList.size() )
+ {
+ case 0:
+ // No unfiltered row, we have to return some object, so
+ // here is one with no ranges.
+ pObj = new ScCellRangesObj( pDocSh, aRangeList );
+ break;
+ case 1:
+ {
+ const ScRange& rRange = aRangeList[ 0 ];
+ if (rRange.aStart == rRange.aEnd)
+ pObj = new ScCellObj( pDocSh, rRange.aStart );
+ else
+ pObj = new ScCellRangeObj( pDocSh, rRange );
+ }
+ break;
+ default:
+ pObj = new ScCellRangesObj( pDocSh, aRangeList );
+ }
+ }
+ else // multiselection
+ {
+ ScRangeListRef xRanges;
+ rViewData.GetMultiArea( xRanges );
+
+ // if there are more sheets, copy ranges
+ //! should this happen in ScMarkData::FillRangeListWithMarks already?
+ if ( nTabs > 1 )
+ rMark.ExtendRangeListTables( xRanges.get() );
+
+ pObj = new ScCellRangesObj( pDocSh, *xRanges );
+ }
+
+ if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ // remember if the selection was from the cursor position without anything selected
+ // (used when rendering the selection)
+
+ pObj->SetCursorOnly( true );
+ }
+ }
+
+ return uno::Any(uno::Reference<uno::XInterface>(static_cast<cppu::OWeakObject*>(pObj.get())));
+}
+
+// XEnumerationAccess
+
+uno::Reference<container::XEnumeration> SAL_CALL ScTabViewObj::createEnumeration()
+{
+ SolarMutexGuard aGuard;
+ return new ScIndexEnumeration(this, "com.sun.star.sheet.SpreadsheetViewPanesEnumeration");
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScTabViewObj::getCount()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ sal_uInt16 nPanes = 0;
+ if (pViewSh)
+ {
+ nPanes = 1;
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ nPanes *= 2;
+ if ( rViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ nPanes *= 2;
+ }
+ return nPanes;
+}
+
+uno::Any SAL_CALL ScTabViewObj::getByIndex( sal_Int32 nIndex )
+{
+ SolarMutexGuard aGuard;
+ uno::Reference<sheet::XViewPane> xPane(GetObjectByIndex_Impl(static_cast<sal_uInt16>(nIndex)));
+ if (!xPane.is())
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any(xPane);
+}
+
+uno::Type SAL_CALL ScTabViewObj::getElementType()
+{
+ return cppu::UnoType<sheet::XViewPane>::get();
+}
+
+sal_Bool SAL_CALL ScTabViewObj::hasElements()
+{
+ SolarMutexGuard aGuard;
+ return ( getCount() != 0 );
+}
+
+// XSpreadsheetView
+
+rtl::Reference<ScViewPaneObj> ScTabViewObj::GetObjectByIndex_Impl(sal_uInt16 nIndex) const
+{
+ static const ScSplitPos ePosHV[4] =
+ { SC_SPLIT_TOPLEFT, SC_SPLIT_BOTTOMLEFT, SC_SPLIT_TOPRIGHT, SC_SPLIT_BOTTOMRIGHT };
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScSplitPos eWhich = SC_SPLIT_BOTTOMLEFT; // default position
+ bool bError = false;
+ ScViewData& rViewData = pViewSh->GetViewData();
+ bool bHor = ( rViewData.GetHSplitMode() != SC_SPLIT_NONE );
+ bool bVer = ( rViewData.GetVSplitMode() != SC_SPLIT_NONE );
+ if ( bHor && bVer )
+ {
+ // bottom left, bottom right, top left, top right - like in Excel
+ if ( nIndex < 4 )
+ eWhich = ePosHV[nIndex];
+ else
+ bError = true;
+ }
+ else if ( bHor )
+ {
+ if ( nIndex > 1 )
+ bError = true;
+ else if ( nIndex == 1 )
+ eWhich = SC_SPLIT_BOTTOMRIGHT;
+ // otherwise SC_SPLIT_BOTTOMLEFT
+ }
+ else if ( bVer )
+ {
+ if ( nIndex > 1 )
+ bError = true;
+ else if ( nIndex == 0 )
+ eWhich = SC_SPLIT_TOPLEFT;
+ // otherwise SC_SPLIT_BOTTOMLEFT
+ }
+ else if ( nIndex > 0 )
+ bError = true; // not split: only 0 is valid
+
+ if (!bError)
+ return new ScViewPaneObj( pViewSh, sal::static_int_cast<sal_uInt16>(eWhich) );
+ }
+
+ return nullptr;
+}
+
+uno::Reference<sheet::XSpreadsheet> SAL_CALL ScTabViewObj::getActiveSheet()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ SCTAB nTab = rViewData.GetTabNo();
+ return new ScTableSheetObj( rViewData.GetDocShell(), nTab );
+ }
+ return nullptr;
+}
+
+// support expand (but not replace) the active sheet
+void SAL_CALL ScTabViewObj::setActiveSheet( const uno::Reference<sheet::XSpreadsheet>& xActiveSheet )
+{
+ SolarMutexGuard aGuard;
+ comphelper::ProfileZone aZone("setActiveSheet");
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if ( !(pViewSh && xActiveSheet.is()) )
+ return;
+
+ // XSpreadsheet and ScCellRangesBase -> has to be the same sheet
+
+ ScCellRangesBase* pRangesImp = comphelper::getFromUnoTunnel<ScCellRangesBase>( xActiveSheet );
+ if ( pRangesImp && pViewSh->GetViewData().GetDocShell() == pRangesImp->GetDocShell() )
+ {
+ const ScRangeList& rRanges = pRangesImp->GetRangeList();
+ if ( rRanges.size() == 1 )
+ {
+ SCTAB nNewTab = rRanges[ 0 ].aStart.Tab();
+ if ( pViewSh->GetViewData().GetDocument().HasTable(nNewTab) )
+ pViewSh->SetTabNo( nNewTab );
+ }
+ }
+}
+
+uno::Reference< uno::XInterface > ScTabViewObj::GetClickedObject(const Point& rPoint) const
+{
+ uno::Reference< uno::XInterface > xTarget;
+ if (GetViewShell())
+ {
+ SCCOL nX;
+ SCROW nY;
+ ScViewData& rData = GetViewShell()->GetViewData();
+ ScSplitPos eSplitMode = rData.GetActivePart();
+ SCTAB nTab(rData.GetTabNo());
+ rData.GetPosFromPixel( rPoint.X(), rPoint.Y(), eSplitMode, nX, nY);
+
+ ScAddress aCellPos (nX, nY, nTab);
+ rtl::Reference<ScCellObj> pCellObj = new ScCellObj(rData.GetDocShell(), aCellPos);
+
+ xTarget.set(uno::Reference<table::XCell>(pCellObj), uno::UNO_QUERY);
+
+ ScDocument& rDoc = rData.GetDocument();
+ if (ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer())
+ {
+ SdrPage* pDrawPage = nullptr;
+ if (pDrawLayer->HasObjects() && (pDrawLayer->GetPageCount() > nTab))
+ pDrawPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(nTab));
+
+ SdrView* pDrawView = GetViewShell()->GetScDrawView();
+
+ if (pDrawPage && pDrawView && pDrawView->GetSdrPageView())
+ {
+ vcl::Window* pActiveWin = rData.GetActiveWin();
+ Point aPos = pActiveWin->PixelToLogic(rPoint);
+
+ sal_uInt16 nHitLog = static_cast<sal_uInt16>(pActiveWin->PixelToLogic(
+ Size(pDrawView->GetHitTolerancePixel(),0)).Width());
+
+ const size_t nCount(pDrawPage->GetObjCount());
+ bool bFound(false);
+ for (size_t i = 0; i < nCount && !bFound; ++i)
+ {
+ SdrObject* pObj = pDrawPage->GetObj(i);
+ if (pObj && SdrObjectPrimitiveHit(*pObj, aPos, nHitLog, *pDrawView->GetSdrPageView(), nullptr, false))
+ {
+ xTarget.set(pObj->getUnoShape(), uno::UNO_QUERY);
+ bFound = true;
+ }
+ }
+ }
+ }
+ }
+ return xTarget;
+}
+
+bool ScTabViewObj::IsMouseListening() const
+{
+ if ( !aMouseClickHandlers.empty() )
+ return true;
+
+ // also include sheet events, because MousePressed must be called for them
+ ScViewData& rViewData = GetViewShell()->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ return
+ rDoc.HasSheetEventScript( nTab, ScSheetEventId::RIGHTCLICK, true ) ||
+ rDoc.HasSheetEventScript( nTab, ScSheetEventId::DOUBLECLICK, true ) ||
+ rDoc.HasSheetEventScript( nTab, ScSheetEventId::SELECT, true );
+
+}
+
+bool ScTabViewObj::MousePressed( const awt::MouseEvent& e )
+{
+ bool bReturn(false);
+ if ( e.Buttons == css::awt::MouseButton::LEFT )
+ mbLeftMousePressed = true;
+
+ uno::Reference< uno::XInterface > xTarget = GetClickedObject(Point(e.X, e.Y));
+ if (!aMouseClickHandlers.empty() && xTarget.is())
+ {
+ awt::EnhancedMouseEvent aMouseEvent;
+
+ aMouseEvent.Buttons = e.Buttons;
+ aMouseEvent.X = e.X;
+ aMouseEvent.Y = e.Y;
+ aMouseEvent.ClickCount = e.ClickCount;
+ aMouseEvent.PopupTrigger = e.PopupTrigger;
+ aMouseEvent.Target = xTarget;
+ aMouseEvent.Modifiers = e.Modifiers;
+
+ // Listener's handler may remove it from the listeners list
+ for (size_t i = aMouseClickHandlers.size(); i > 0; --i)
+ {
+ try
+ {
+ if (!aMouseClickHandlers[i - 1]->mousePressed(aMouseEvent))
+ bReturn = true;
+ }
+ catch ( uno::Exception& )
+ {
+ aMouseClickHandlers.erase(aMouseClickHandlers.begin() + (i - 1));
+ }
+ }
+ }
+
+ // handle sheet events
+ bool bDoubleClick = ( e.Buttons == awt::MouseButton::LEFT && e.ClickCount == 2 );
+ bool bRightClick = ( e.Buttons == awt::MouseButton::RIGHT && e.ClickCount == 1 );
+ if ( ( bDoubleClick || bRightClick ) && !bReturn && xTarget.is())
+ {
+ ScSheetEventId nEvent = bDoubleClick ? ScSheetEventId::DOUBLECLICK : ScSheetEventId::RIGHTCLICK;
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ const ScSheetEvents* pEvents = rDoc.GetSheetEvents(nTab);
+ if (pEvents)
+ {
+ const OUString* pScript = pEvents->GetScript(nEvent);
+ if (pScript)
+ {
+ // the macro parameter is the clicked object, as in the mousePressed call above
+ uno::Sequence<uno::Any> aParams{ uno::Any(xTarget) };
+
+ uno::Any aRet;
+ uno::Sequence<sal_Int16> aOutArgsIndex;
+ uno::Sequence<uno::Any> aOutArgs;
+
+ /*ErrCode eRet =*/ pDocSh->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
+
+ // look for a boolean return value of true
+ bool bRetValue = false;
+ if ((aRet >>= bRetValue) && bRetValue)
+ bReturn = true;
+ }
+ }
+
+ // execute VBA event handler
+ if (!bReturn && xTarget.is()) try
+ {
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( rDoc.GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ // the parameter is the clicked object, as in the mousePressed call above
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xTarget) };
+ xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( nEvent ), aArgs );
+ }
+ catch( util::VetoException& )
+ {
+ bReturn = true;
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+
+ return bReturn;
+}
+
+bool ScTabViewObj::MouseReleased( const awt::MouseEvent& e )
+{
+ if ( e.Buttons == css::awt::MouseButton::LEFT )
+ {
+ try
+ {
+ ScTabViewShell* pViewSh = GetViewShell();
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( rDoc.GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ uno::Sequence< uno::Any > aArgs{ getSelection() };
+ xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( ScSheetEventId::SELECT ), aArgs );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ mbLeftMousePressed = false;
+ }
+
+ bool bReturn(false);
+
+ if (!aMouseClickHandlers.empty())
+ {
+ uno::Reference< uno::XInterface > xTarget = GetClickedObject(Point(e.X, e.Y));
+
+ if (xTarget.is())
+ {
+ awt::EnhancedMouseEvent aMouseEvent;
+
+ aMouseEvent.Buttons = e.Buttons;
+ aMouseEvent.X = e.X;
+ aMouseEvent.Y = e.Y;
+ aMouseEvent.ClickCount = e.ClickCount;
+ aMouseEvent.PopupTrigger = e.PopupTrigger;
+ aMouseEvent.Target = xTarget;
+ aMouseEvent.Modifiers = e.Modifiers;
+
+ // Listener's handler may remove it from the listeners list
+ for (size_t i = aMouseClickHandlers.size(); i > 0; --i)
+ {
+ try
+ {
+ if (!aMouseClickHandlers[i - 1]->mouseReleased( aMouseEvent ))
+ bReturn = true;
+ }
+ catch ( uno::Exception& )
+ {
+ aMouseClickHandlers.erase(aMouseClickHandlers.begin() + (i - 1));
+ }
+ }
+ }
+ }
+ return bReturn;
+}
+
+// XEnhancedMouseClickBroadcaster
+
+void ScTabViewObj::EndMouseListening()
+{
+ lang::EventObject aEvent;
+ aEvent.Source = static_cast<cppu::OWeakObject*>(this);
+ for (const auto& rListener : aMouseClickHandlers)
+ {
+ try
+ {
+ rListener->disposing(aEvent);
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ aMouseClickHandlers.clear();
+}
+
+void ScTabViewObj::EndActivationListening()
+{
+ lang::EventObject aEvent;
+ aEvent.Source = static_cast<cppu::OWeakObject*>(this);
+ for (const auto& rListener : aActivationListeners)
+ {
+ try
+ {
+ rListener->disposing(aEvent);
+ }
+ catch ( uno::Exception& )
+ {
+ }
+ }
+ aActivationListeners.clear();
+}
+
+void SAL_CALL ScTabViewObj::addEnhancedMouseClickHandler( const uno::Reference< awt::XEnhancedMouseClickHandler >& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ if (aListener.is())
+ {
+ aMouseClickHandlers.push_back( aListener );
+ }
+}
+
+void SAL_CALL ScTabViewObj::removeEnhancedMouseClickHandler( const uno::Reference< awt::XEnhancedMouseClickHandler >& aListener )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = aMouseClickHandlers.size();
+ aMouseClickHandlers.erase(
+ std::remove(aMouseClickHandlers.begin(), aMouseClickHandlers.end(), aListener),
+ aMouseClickHandlers.end());
+ if (aMouseClickHandlers.empty() && (nCount > 0)) // only if last listener removed
+ EndMouseListening();
+}
+
+// XActivationBroadcaster
+
+void SAL_CALL ScTabViewObj::addActivationEventListener( const uno::Reference< sheet::XActivationEventListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+
+ if (aListener.is())
+ {
+ aActivationListeners.push_back( aListener );
+ }
+}
+
+void SAL_CALL ScTabViewObj::removeActivationEventListener( const uno::Reference< sheet::XActivationEventListener >& aListener )
+{
+ SolarMutexGuard aGuard;
+ sal_uInt16 nCount = aActivationListeners.size();
+ aActivationListeners.erase(
+ std::remove(aActivationListeners.begin(), aActivationListeners.end(), aListener),
+ aActivationListeners.end());
+ if (aActivationListeners.empty() && (nCount > 0)) // only if last listener removed
+ EndActivationListening();
+}
+
+sal_Int16 ScTabViewObj::GetZoom() const
+{
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ const Fraction& rZoomY = pViewSh->GetViewData().GetZoomY(); // Y will be shown
+ return static_cast<sal_Int16>(tools::Long( rZoomY * 100 ));
+ }
+ return 0;
+}
+
+void ScTabViewObj::SetZoom(sal_Int16 nZoom)
+{
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ if ( nZoom != GetZoom() && nZoom != 0 )
+ {
+ if (!pViewSh->GetViewData().IsPagebreakMode())
+ {
+ ScModule* pScMod = SC_MOD();
+ ScAppOptions aNewOpt(pScMod->GetAppOptions());
+ aNewOpt.SetZoom( nZoom );
+ aNewOpt.SetZoomType( pViewSh->GetViewData().GetView()->GetZoomType() );
+ pScMod->SetAppOptions( aNewOpt );
+ }
+ }
+ Fraction aFract( nZoom, 100 );
+ pViewSh->SetZoom( aFract, aFract, true );
+ pViewSh->PaintGrid();
+ pViewSh->PaintTop();
+ pViewSh->PaintLeft();
+ pViewSh->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM );
+ pViewSh->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
+ pViewSh->GetViewFrame()->GetBindings().Invalidate(SID_ZOOM_IN);
+ pViewSh->GetViewFrame()->GetBindings().Invalidate(SID_ZOOM_OUT);
+}
+
+sal_Int16 ScTabViewObj::GetZoomType() const
+{
+ sal_Int16 aZoomType = view::DocumentZoomType::OPTIMAL;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ SvxZoomType eZoomType = pViewSh->GetViewData().GetView()->GetZoomType();
+ switch (eZoomType)
+ {
+ case SvxZoomType::PERCENT:
+ aZoomType = view::DocumentZoomType::BY_VALUE;
+ break;
+ case SvxZoomType::OPTIMAL:
+ aZoomType = view::DocumentZoomType::OPTIMAL;
+ break;
+ case SvxZoomType::WHOLEPAGE:
+ aZoomType = view::DocumentZoomType::ENTIRE_PAGE;
+ break;
+ case SvxZoomType::PAGEWIDTH:
+ aZoomType = view::DocumentZoomType::PAGE_WIDTH;
+ break;
+ case SvxZoomType::PAGEWIDTH_NOBORDER:
+ aZoomType = view::DocumentZoomType::PAGE_WIDTH_EXACT;
+ break;
+ }
+ }
+ return aZoomType;
+}
+
+void ScTabViewObj::SetZoomType(sal_Int16 aZoomType)
+{
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ ScDBFunc* pView = pViewSh->GetViewData().GetView();
+ if (!pView)
+ return;
+
+ SvxZoomType eZoomType;
+ switch (aZoomType)
+ {
+ case view::DocumentZoomType::BY_VALUE:
+ eZoomType = SvxZoomType::PERCENT;
+ break;
+ case view::DocumentZoomType::OPTIMAL:
+ eZoomType = SvxZoomType::OPTIMAL;
+ break;
+ case view::DocumentZoomType::ENTIRE_PAGE:
+ eZoomType = SvxZoomType::WHOLEPAGE;
+ break;
+ case view::DocumentZoomType::PAGE_WIDTH:
+ eZoomType = SvxZoomType::PAGEWIDTH;
+ break;
+ case view::DocumentZoomType::PAGE_WIDTH_EXACT:
+ eZoomType = SvxZoomType::PAGEWIDTH_NOBORDER;
+ break;
+ default:
+ eZoomType = SvxZoomType::OPTIMAL;
+ }
+ sal_Int16 nZoom(GetZoom());
+ sal_Int16 nOldZoom(nZoom);
+ if ( eZoomType == SvxZoomType::PERCENT )
+ {
+ if ( nZoom < MINZOOM ) nZoom = MINZOOM;
+ if ( nZoom > MAXZOOM ) nZoom = MAXZOOM;
+ }
+ else
+ nZoom = pView->CalcZoom( eZoomType, nOldZoom );
+
+ switch ( eZoomType )
+ {
+ case SvxZoomType::WHOLEPAGE:
+ case SvxZoomType::PAGEWIDTH:
+ pView->SetZoomType( eZoomType, true );
+ break;
+
+ default:
+ pView->SetZoomType( SvxZoomType::PERCENT, true );
+ }
+ SetZoom( nZoom );
+}
+
+sal_Bool SAL_CALL ScTabViewObj::getIsWindowSplit()
+{
+ SolarMutexGuard aGuard;
+ // what menu slot SID_WINDOW_SPLIT does
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ return ( rViewData.GetHSplitMode() == SC_SPLIT_NORMAL ||
+ rViewData.GetVSplitMode() == SC_SPLIT_NORMAL );
+ }
+
+ return false;
+}
+
+sal_Bool SAL_CALL ScTabViewObj::hasFrozenPanes()
+{
+ SolarMutexGuard aGuard;
+ // what menu slot SID_WINDOW_FIX does
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ return ( rViewData.GetHSplitMode() == SC_SPLIT_FIX ||
+ rViewData.GetVSplitMode() == SC_SPLIT_FIX );
+ }
+
+ return false;
+}
+
+sal_Int32 SAL_CALL ScTabViewObj::getSplitHorizontal()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ return rViewData.GetHSplitPos();
+ }
+ return 0;
+}
+
+sal_Int32 SAL_CALL ScTabViewObj::getSplitVertical()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ return rViewData.GetVSplitPos();
+ }
+ return 0;
+}
+
+sal_Int32 SAL_CALL ScTabViewObj::getSplitColumn()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ {
+ tools::Long nSplit = rViewData.GetHSplitPos();
+
+ ScSplitPos ePos = SC_SPLIT_BOTTOMLEFT;
+ if ( rViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ ePos = SC_SPLIT_TOPLEFT;
+
+ SCCOL nCol;
+ SCROW nRow;
+ rViewData.GetPosFromPixel( nSplit, 0, ePos, nCol, nRow, false );
+ if ( nCol > 0 )
+ return nCol;
+ }
+ }
+ return 0;
+}
+
+sal_Int32 SAL_CALL ScTabViewObj::getSplitRow()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ if ( rViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ {
+ tools::Long nSplit = rViewData.GetVSplitPos();
+
+ // split vertically
+ SCCOL nCol;
+ SCROW nRow;
+ rViewData.GetPosFromPixel( 0, nSplit, SC_SPLIT_TOPLEFT, nCol, nRow, false );
+ if ( nRow > 0 )
+ return nRow;
+ }
+ }
+ return 0;
+}
+
+void SAL_CALL ScTabViewObj::splitAtPosition( sal_Int32 nPixelX, sal_Int32 nPixelY )
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ pViewSh->SplitAtPixel( Point( nPixelX, nPixelY ) );
+ pViewSh->FreezeSplitters( false );
+ pViewSh->InvalidateSplit();
+ }
+}
+
+void SAL_CALL ScTabViewObj::freezeAtPosition( sal_Int32 nColumns, sal_Int32 nRows )
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ // first, remove them all -> no stress with scrolling in the meantime
+
+ pViewSh->RemoveSplit();
+
+ Point aWinStart;
+ vcl::Window* pWin = pViewSh->GetWindowByPos( SC_SPLIT_BOTTOMLEFT );
+ if (pWin)
+ aWinStart = pWin->GetPosPixel();
+
+ ScViewData& rViewData = pViewSh->GetViewData();
+ Point aSplit(rViewData.GetScrPos( static_cast<SCCOL>(nColumns), static_cast<SCROW>(nRows), SC_SPLIT_BOTTOMLEFT, true ));
+ aSplit += aWinStart;
+
+ pViewSh->SplitAtPixel( aSplit );
+ pViewSh->FreezeSplitters( true );
+ pViewSh->InvalidateSplit();
+}
+
+void SAL_CALL ScTabViewObj::addSelectionChangeListener(
+ const uno::Reference<view::XSelectionChangeListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+ aSelectionChgListeners.push_back( xListener );
+}
+
+void SAL_CALL ScTabViewObj::removeSelectionChangeListener(
+ const uno::Reference< view::XSelectionChangeListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ auto it = std::find(aSelectionChgListeners.begin(), aSelectionChgListeners.end(), xListener); //! why the hassle with queryInterface?
+ if (it != aSelectionChgListeners.end())
+ aSelectionChgListeners.erase(it);
+}
+
+void ScTabViewObj::SelectionChanged()
+{
+ // Selection changed so end any style preview
+ // Note: executing this slot through the dispatcher
+ // will cause the style dialog to be raised so we go
+ // direct here
+ ScFormatShell aShell( GetViewShell()->GetViewData() );
+ SfxAllItemSet reqList( SfxGetpApp()->GetPool() );
+ SfxRequest aReq( SID_STYLE_END_PREVIEW, SfxCallMode::SLOT, reqList );
+ aShell.ExecuteStyle( aReq );
+ lang::EventObject aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ for (const auto& rListener : aSelectionChgListeners)
+ rListener->selectionChanged( aEvent );
+
+ // handle sheet events
+ ScTabViewShell* pViewSh = GetViewShell();
+ ScViewData& rViewData = pViewSh->GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ const ScSheetEvents* pEvents = rDoc.GetSheetEvents(nTab);
+ if (pEvents)
+ {
+ const OUString* pScript = pEvents->GetScript(ScSheetEventId::SELECT);
+ if (pScript)
+ {
+ // the macro parameter is the selection as returned by getSelection
+ uno::Sequence<uno::Any> aParams{ getSelection() };
+ uno::Any aRet;
+ uno::Sequence<sal_Int16> aOutArgsIndex;
+ uno::Sequence<uno::Any> aOutArgs;
+ /*ErrCode eRet =*/ pDocSh->CallXScript( *pScript, aParams, aRet, aOutArgsIndex, aOutArgs );
+ }
+ }
+
+ SfxApplication::Get()->Broadcast( SfxHint( SfxHintId::ScSelectionChanged ) );
+
+ if ( mbLeftMousePressed ) // selection still in progress
+ return;
+
+ try
+ {
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( rDoc.GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ uno::Sequence< uno::Any > aArgs{ getSelection() };
+ xVbaEvents->processVbaEvent( ScSheetEvents::GetVbaSheetEventId( ScSheetEventId::SELECT ), aArgs );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+// XPropertySet (view options)
+//! provide those also in application?
+
+uno::Reference<beans::XPropertySetInfo> SAL_CALL ScTabViewObj::getPropertySetInfo()
+{
+ SolarMutexGuard aGuard;
+ static uno::Reference<beans::XPropertySetInfo> aRef(
+ new SfxItemPropertySetInfo( aPropSet.getPropertyMap() ));
+ return aRef;
+}
+
+void SAL_CALL ScTabViewObj::setPropertyValue(
+ const OUString& aPropertyName, const uno::Any& aValue )
+{
+ SolarMutexGuard aGuard;
+
+ if ( aPropertyName == SC_UNO_FILTERED_RANGE_SELECTION )
+ {
+ bFilteredRangeSelection = ScUnoHelpFunctions::GetBoolFromAny(aValue);
+ return;
+ }
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ ScViewData& rViewData = pViewSh->GetViewData();
+ const ScViewOptions& rOldOpt = pViewSh->GetViewData().GetOptions();
+ ScViewOptions aNewOpt(rOldOpt);
+
+ if ( aPropertyName == SC_UNO_COLROWHDR || aPropertyName == OLD_UNO_COLROWHDR )
+ aNewOpt.SetOption( VOPT_HEADER, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_HORSCROLL || aPropertyName == OLD_UNO_HORSCROLL )
+ aNewOpt.SetOption( VOPT_HSCROLL, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_OUTLSYMB || aPropertyName == OLD_UNO_OUTLSYMB )
+ aNewOpt.SetOption( VOPT_OUTLINER, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHEETTABS || aPropertyName == OLD_UNO_SHEETTABS )
+ aNewOpt.SetOption( VOPT_TABCONTROLS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWANCHOR )
+ aNewOpt.SetOption( VOPT_ANCHOR, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWFORM )
+ aNewOpt.SetOption( VOPT_FORMULAS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWGRID )
+ aNewOpt.SetOption( VOPT_GRID, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWHELP )
+ aNewOpt.SetOption( VOPT_HELPLINES, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWNOTES )
+ aNewOpt.SetOption( VOPT_NOTES, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWPAGEBR )
+ aNewOpt.SetOption( VOPT_PAGEBREAKS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWZERO )
+ aNewOpt.SetOption( VOPT_NULLVALS, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_VALUEHIGH || aPropertyName == OLD_UNO_VALUEHIGH )
+ aNewOpt.SetOption( VOPT_SYNTAX, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_VERTSCROLL || aPropertyName == OLD_UNO_VERTSCROLL )
+ aNewOpt.SetOption( VOPT_VSCROLL, ScUnoHelpFunctions::GetBoolFromAny( aValue ) );
+ else if ( aPropertyName == SC_UNO_SHOWOBJ )
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ {
+ //#i80528# adapt to new range eventually
+ if(sal_Int16(VOBJ_MODE_HIDE) < nIntVal) nIntVal = sal_Int16(VOBJ_MODE_SHOW);
+
+ aNewOpt.SetObjMode( VOBJ_TYPE_OLE, static_cast<ScVObjMode>(nIntVal));
+ }
+ }
+ else if ( aPropertyName == SC_UNO_SHOWCHARTS )
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ {
+ //#i80528# adapt to new range eventually
+ if(sal_Int16(VOBJ_MODE_HIDE) < nIntVal) nIntVal = sal_Int16(VOBJ_MODE_SHOW);
+
+ aNewOpt.SetObjMode( VOBJ_TYPE_CHART, static_cast<ScVObjMode>(nIntVal));
+ }
+ }
+ else if ( aPropertyName == SC_UNO_SHOWDRAW )
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ {
+ //#i80528# adapt to new range eventually
+ if(sal_Int16(VOBJ_MODE_HIDE) < nIntVal) nIntVal = sal_Int16(VOBJ_MODE_SHOW);
+
+ aNewOpt.SetObjMode( VOBJ_TYPE_DRAW, static_cast<ScVObjMode>(nIntVal));
+ }
+ }
+ else if ( aPropertyName == SC_UNO_GRIDCOLOR )
+ {
+ Color nIntVal;
+ if ( aValue >>= nIntVal )
+ aNewOpt.SetGridColor( nIntVal, OUString() );
+ }
+ else if ( aPropertyName == SC_UNO_ZOOMTYPE )
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ SetZoomType(nIntVal);
+ }
+ else if ( aPropertyName == SC_UNO_ZOOMVALUE )
+ {
+ sal_Int16 nIntVal = 0;
+ if ( aValue >>= nIntVal )
+ SetZoom(nIntVal);
+ }
+ else if ( aPropertyName == SC_UNO_FORMULABARHEIGHT )
+ {
+ sal_Int16 nIntVal = ScUnoHelpFunctions::GetInt16FromAny(aValue);
+ if (nIntVal > 0)
+ {
+ rViewData.SetFormulaBarLines(nIntVal);
+ // Notify formula bar about changed lines
+ ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
+ if (pInputHdl)
+ {
+ ScInputWindow* pInputWin = pInputHdl->GetInputWindow();
+ if (pInputWin)
+ pInputWin->NumLinesChanged();
+ }
+ }
+ }
+
+ // Options are set on the view and document (for new views),
+ // so that they remain during saving.
+ //! In the app (module) we need an extra options to tune that
+ //! (for new documents)
+
+ if ( aNewOpt == rOldOpt )
+ return;
+
+ rViewData.SetOptions( aNewOpt );
+ rViewData.GetDocument().SetViewOptions( aNewOpt );
+ rViewData.GetDocShell()->SetDocumentModified(); //! really?
+
+ pViewSh->UpdateFixPos();
+ pViewSh->PaintGrid();
+ pViewSh->PaintTop();
+ pViewSh->PaintLeft();
+ pViewSh->PaintExtras();
+ pViewSh->InvalidateBorder();
+
+ SfxBindings& rBindings = pViewSh->GetViewFrame()->GetBindings();
+ rBindings.Invalidate( FID_TOGGLEHEADERS ); // -> check in menu
+ rBindings.Invalidate( FID_TOGGLESYNTAX );
+}
+
+uno::Any SAL_CALL ScTabViewObj::getPropertyValue( const OUString& aPropertyName )
+{
+ SolarMutexGuard aGuard;
+ uno::Any aRet;
+
+ if ( aPropertyName == SC_UNO_FILTERED_RANGE_SELECTION )
+ {
+ aRet <<= bFilteredRangeSelection;
+ return aRet;
+ }
+
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ {
+ ScViewData& rViewData = pViewSh->GetViewData();
+ const ScViewOptions& rOpt = rViewData.GetOptions();
+
+ if ( aPropertyName == SC_UNO_COLROWHDR || aPropertyName == OLD_UNO_COLROWHDR )
+ aRet <<= rOpt.GetOption( VOPT_HEADER );
+ else if ( aPropertyName == SC_UNO_HORSCROLL || aPropertyName == OLD_UNO_HORSCROLL )
+ aRet <<= rOpt.GetOption( VOPT_HSCROLL );
+ else if ( aPropertyName == SC_UNO_OUTLSYMB || aPropertyName == OLD_UNO_OUTLSYMB )
+ aRet <<= rOpt.GetOption( VOPT_OUTLINER );
+ else if ( aPropertyName == SC_UNO_SHEETTABS || aPropertyName == OLD_UNO_SHEETTABS )
+ aRet <<= rOpt.GetOption( VOPT_TABCONTROLS );
+ else if ( aPropertyName == SC_UNO_SHOWANCHOR ) aRet <<= rOpt.GetOption( VOPT_ANCHOR );
+ else if ( aPropertyName == SC_UNO_SHOWFORM ) aRet <<= rOpt.GetOption( VOPT_FORMULAS );
+ else if ( aPropertyName == SC_UNO_SHOWGRID ) aRet <<= rOpt.GetOption( VOPT_GRID );
+ else if ( aPropertyName == SC_UNO_SHOWHELP ) aRet <<= rOpt.GetOption( VOPT_HELPLINES );
+ else if ( aPropertyName == SC_UNO_SHOWNOTES ) aRet <<= rOpt.GetOption( VOPT_NOTES );
+ else if ( aPropertyName == SC_UNO_SHOWPAGEBR ) aRet <<= rOpt.GetOption( VOPT_PAGEBREAKS );
+ else if ( aPropertyName == SC_UNO_SHOWZERO ) aRet <<= rOpt.GetOption( VOPT_NULLVALS );
+ else if ( aPropertyName == SC_UNO_VALUEHIGH || aPropertyName == OLD_UNO_VALUEHIGH )
+ aRet <<= rOpt.GetOption( VOPT_SYNTAX );
+ else if ( aPropertyName == SC_UNO_VERTSCROLL || aPropertyName == OLD_UNO_VERTSCROLL )
+ aRet <<= rOpt.GetOption( VOPT_VSCROLL );
+ else if ( aPropertyName == SC_UNO_SHOWOBJ ) aRet <<= static_cast<sal_Int16>( rOpt.GetObjMode( VOBJ_TYPE_OLE ) );
+ else if ( aPropertyName == SC_UNO_SHOWCHARTS ) aRet <<= static_cast<sal_Int16>( rOpt.GetObjMode( VOBJ_TYPE_CHART ) );
+ else if ( aPropertyName == SC_UNO_SHOWDRAW ) aRet <<= static_cast<sal_Int16>( rOpt.GetObjMode( VOBJ_TYPE_DRAW ) );
+ else if ( aPropertyName == SC_UNO_GRIDCOLOR ) aRet <<= rOpt.GetGridColor();
+ else if ( aPropertyName == SC_UNO_VISAREA ) aRet <<= GetVisArea();
+ else if ( aPropertyName == SC_UNO_ZOOMTYPE ) aRet <<= GetZoomType();
+ else if ( aPropertyName == SC_UNO_ZOOMVALUE ) aRet <<= GetZoom();
+ else if ( aPropertyName == SC_UNO_FORMULABARHEIGHT ) aRet <<= rViewData.GetFormulaBarLines();
+ else if ( aPropertyName == SC_UNO_VISAREASCREEN )
+ {
+ vcl::Window* pActiveWin = rViewData.GetActiveWin();
+ if ( pActiveWin )
+ {
+ tools::Rectangle aRect = pActiveWin->GetWindowExtentsRelative( nullptr );
+ aRet <<= AWTRectangle( aRect );
+ }
+ }
+ }
+
+ return aRet;
+}
+
+void SAL_CALL ScTabViewObj::addPropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ aPropertyChgListeners.push_back( xListener );
+}
+
+void SAL_CALL ScTabViewObj::removePropertyChangeListener( const OUString& /* aPropertyName */,
+ const uno::Reference<beans::XPropertyChangeListener >& xListener )
+{
+ SolarMutexGuard aGuard;
+ auto it = std::find(aPropertyChgListeners.begin(), aPropertyChgListeners.end(), xListener); //! Why the nonsense with queryInterface?
+ if (it != aPropertyChgListeners.end())
+ aPropertyChgListeners.erase(it);
+}
+
+void SAL_CALL ScTabViewObj::addVetoableChangeListener( const OUString& /* PropertyName */,
+ const uno::Reference<beans::XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+void SAL_CALL ScTabViewObj::removeVetoableChangeListener( const OUString& /* PropertyName */,
+ const uno::Reference<beans::XVetoableChangeListener >& /* aListener */ )
+{
+}
+
+void ScTabViewObj::VisAreaChanged()
+{
+ beans::PropertyChangeEvent aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ for (const auto& rListener : aPropertyChgListeners)
+ rListener->propertyChange( aEvent );
+}
+
+// XRangeSelection
+
+void SAL_CALL ScTabViewObj::startRangeSelection(
+ const uno::Sequence<beans::PropertyValue>& aArguments )
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return;
+
+ OUString aInitVal, aTitle;
+ bool bCloseOnButtonUp = false;
+ bool bSingleCell = false;
+ bool bMultiSelection = false;
+
+ OUString aStrVal;
+ for (const beans::PropertyValue& rProp : aArguments)
+ {
+ OUString aPropName(rProp.Name);
+
+ if (aPropName == SC_UNONAME_CLOSEONUP )
+ bCloseOnButtonUp = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_TITLE )
+ {
+ if ( rProp.Value >>= aStrVal )
+ aTitle = aStrVal;
+ }
+ else if (aPropName == SC_UNONAME_INITVAL )
+ {
+ if ( rProp.Value >>= aStrVal )
+ aInitVal = aStrVal;
+ }
+ else if (aPropName == SC_UNONAME_SINGLECELL )
+ bSingleCell = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ else if (aPropName == SC_UNONAME_MULTISEL )
+ bMultiSelection = ScUnoHelpFunctions::GetBoolFromAny( rProp.Value );
+ }
+
+ pViewSh->StartSimpleRefDialog( aTitle, aInitVal, bCloseOnButtonUp, bSingleCell, bMultiSelection );
+}
+
+void SAL_CALL ScTabViewObj::abortRangeSelection()
+{
+ SolarMutexGuard aGuard;
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (pViewSh)
+ pViewSh->StopSimpleRefDialog();
+}
+
+void SAL_CALL ScTabViewObj::addRangeSelectionListener(
+ const uno::Reference<sheet::XRangeSelectionListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRangeSelListeners.push_back( xListener );
+}
+
+void SAL_CALL ScTabViewObj::removeRangeSelectionListener(
+ const uno::Reference<sheet::XRangeSelectionListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+ auto it = std::find(aRangeSelListeners.begin(), aRangeSelListeners.end(), xListener);
+ if (it != aRangeSelListeners.end())
+ aRangeSelListeners.erase(it);
+}
+
+void SAL_CALL ScTabViewObj::addRangeSelectionChangeListener(
+ const uno::Reference<sheet::XRangeSelectionChangeListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+ aRangeChgListeners.push_back( xListener );
+}
+
+void SAL_CALL ScTabViewObj::removeRangeSelectionChangeListener(
+ const uno::Reference<sheet::XRangeSelectionChangeListener>& xListener )
+{
+ SolarMutexGuard aGuard;
+ auto it = std::find(aRangeChgListeners.begin(), aRangeChgListeners.end(), xListener);
+ if (it != aRangeChgListeners.end())
+ aRangeChgListeners.erase(it);
+}
+
+void ScTabViewObj::RangeSelDone( const OUString& rText )
+{
+ sheet::RangeSelectionEvent aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ aEvent.RangeDescriptor = rText;
+
+ // copy on the stack because listener could remove itself
+ auto const listeners(aRangeSelListeners);
+
+ for (const auto& rListener : listeners)
+ rListener->done( aEvent );
+}
+
+void ScTabViewObj::RangeSelAborted( const OUString& rText )
+{
+ sheet::RangeSelectionEvent aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ aEvent.RangeDescriptor = rText;
+
+ // copy on the stack because listener could remove itself
+ auto const listeners(aRangeSelListeners);
+
+ for (const auto& rListener : listeners)
+ rListener->aborted( aEvent );
+}
+
+void ScTabViewObj::RangeSelChanged( const OUString& rText )
+{
+ sheet::RangeSelectionEvent aEvent;
+ aEvent.Source.set(static_cast<cppu::OWeakObject*>(this));
+ aEvent.RangeDescriptor = rText;
+
+ // copy on the stack because listener could remove itself
+ auto const listener(aRangeChgListeners);
+
+ for (const auto& rListener : listener)
+ rListener->descriptorChanged( aEvent );
+}
+
+// XServiceInfo
+OUString SAL_CALL ScTabViewObj::getImplementationName()
+{
+ return "ScTabViewObj";
+}
+
+sal_Bool SAL_CALL ScTabViewObj::supportsService( const OUString& rServiceName )
+{
+ return cppu::supportsService(this, rServiceName);
+}
+
+uno::Sequence<OUString> SAL_CALL ScTabViewObj::getSupportedServiceNames()
+{
+ return {SCTABVIEWOBJ_SERVICE, SCVIEWSETTINGS_SERVICE};
+}
+
+// XUnoTunnel
+
+UNO3_GETIMPLEMENTATION_IMPL(ScTabViewObj);
+
+css::uno::Reference< css::datatransfer::XTransferable > SAL_CALL ScTabViewObj::getTransferable()
+{
+ SolarMutexGuard aGuard;
+ ScEditShell* pShell = dynamic_cast<ScEditShell*>( GetViewShell()->GetViewFrame()->GetDispatcher()->GetShell(0) );
+ if (pShell)
+ return pShell->GetEditView()->GetTransferable();
+
+ ScDrawTextObjectBar* pTextShell = dynamic_cast<ScDrawTextObjectBar*>( GetViewShell()->GetViewFrame()->GetDispatcher()->GetShell(0) );
+ if (pTextShell)
+ {
+ ScViewData& rViewData = GetViewShell()->GetViewData();
+ ScDrawView* pView = rViewData.GetScDrawView();
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+ if (pOutView)
+ return pOutView->GetEditView().GetTransferable();
+ }
+
+ ScDrawShell* pDrawShell = dynamic_cast<ScDrawShell*>( GetViewShell()->GetViewFrame()->GetDispatcher()->GetShell(0) );
+ if (pDrawShell)
+ return pDrawShell->GetDrawView()->CopyToTransferable();
+
+ return GetViewShell()->CopyToTransferable();
+}
+
+void SAL_CALL ScTabViewObj::insertTransferable( const css::uno::Reference< css::datatransfer::XTransferable >& xTrans )
+{
+ SolarMutexGuard aGuard;
+ ScEditShell* pShell = dynamic_cast<ScEditShell*>( GetViewShell()->GetViewFrame()->GetDispatcher()->GetShell(0) );
+ if (pShell)
+ pShell->GetEditView()->InsertText( xTrans, OUString(), false );
+ else
+ {
+ ScDrawTextObjectBar* pTextShell = dynamic_cast<ScDrawTextObjectBar*>( GetViewShell()->GetViewFrame()->GetDispatcher()->GetShell(0) );
+ if (pTextShell)
+ {
+ ScViewData& rViewData = GetViewShell()->GetViewData();
+ ScDrawView* pView = rViewData.GetScDrawView();
+ OutlinerView* pOutView = pView->GetTextEditOutlinerView();
+ if ( pOutView )
+ {
+ pOutView->GetEditView().InsertText( xTrans, OUString(), false );
+ return;
+ }
+ }
+
+ GetViewShell()->PasteFromTransferable( xTrans );
+ }
+}
+
+namespace {
+
+uno::Sequence<sal_Int32> toSequence(const ScMarkData::MarkedTabsType& rSelected)
+{
+ uno::Sequence<sal_Int32> aRet(rSelected.size());
+ auto aRetRange = asNonConstRange(aRet);
+ size_t i = 0;
+ for (const auto& rTab : rSelected)
+ {
+ aRetRange[i] = static_cast<sal_Int32>(rTab);
+ ++i;
+ }
+
+ return aRet;
+}
+
+}
+
+uno::Sequence<sal_Int32> ScTabViewObj::getSelectedSheets()
+{
+ ScTabViewShell* pViewSh = GetViewShell();
+ if (!pViewSh)
+ return uno::Sequence<sal_Int32>();
+
+ ScViewData& rViewData = pViewSh->GetViewData();
+
+ // #i95280# when printing from the shell, the view is never activated,
+ // so Excel view settings must also be evaluated here.
+ ScExtDocOptions* pExtOpt = rViewData.GetDocument().GetExtDocOptions();
+ if (pExtOpt && pExtOpt->IsChanged())
+ {
+ pViewSh->GetViewData().ReadExtOptions(*pExtOpt); // Excel view settings
+ pViewSh->SetTabNo(pViewSh->GetViewData().GetTabNo(), true);
+ pExtOpt->SetChanged(false);
+ }
+
+ return toSequence(rViewData.GetMarkData().GetSelectedTabs());
+}
+
+ScPreviewObj::ScPreviewObj(ScPreviewShell* pViewSh) :
+ SfxBaseController(pViewSh),
+ mpViewShell(pViewSh)
+{
+ if (mpViewShell)
+ StartListening(*mpViewShell);
+}
+
+ScPreviewObj::~ScPreviewObj()
+{
+ if (mpViewShell)
+ EndListening(*mpViewShell);
+}
+
+uno::Any ScPreviewObj::queryInterface(const uno::Type& rType)
+{
+ SC_QUERYINTERFACE(sheet::XSelectedSheetsSupplier)
+ return SfxBaseController::queryInterface(rType);
+}
+
+void ScPreviewObj::acquire() noexcept
+{
+ SfxBaseController::acquire();
+}
+
+void ScPreviewObj::release() noexcept
+{
+ SfxBaseController::release();
+}
+
+void ScPreviewObj::Notify(SfxBroadcaster&, const SfxHint& rHint)
+{
+ if (rHint.GetId() == SfxHintId::Dying)
+ mpViewShell = nullptr;
+}
+
+uno::Sequence<sal_Int32> ScPreviewObj::getSelectedSheets()
+{
+ ScPreview* p = mpViewShell ? mpViewShell->GetPreview() : nullptr;
+ if (!p)
+ return uno::Sequence<sal_Int32>();
+
+ return toSequence(p->GetSelectedTabs());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/unoobj/warnpassword.cxx b/sc/source/ui/unoobj/warnpassword.cxx
new file mode 100644
index 000000000..b8ccbffa2
--- /dev/null
+++ b/sc/source/ui/unoobj/warnpassword.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 <warnpassword.hxx>
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <sfx2/docfile.hxx>
+#include <ucbhelper/simpleinteractionrequest.hxx>
+#include <com/sun/star/task/InteractionClassification.hpp>
+#include <com/sun/star/ucb/InteractiveAppException.hpp>
+#include <svx/svxerr.hxx>
+#include <rtl/ref.hxx>
+
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::XInterface;
+using ::com::sun::star::task::InteractionClassification_QUERY;
+using ::com::sun::star::task::XInteractionHandler;
+using ::com::sun::star::ucb::InteractiveAppException;
+
+bool ScWarnPassword::WarningOnPassword( SfxMedium& rMedium )
+{
+ bool bReturn = true;
+ Reference< XInteractionHandler > xHandler( rMedium.GetInteractionHandler());
+ if( xHandler.is() )
+ {
+ Any aException( InteractiveAppException("",
+ Reference <XInterface> (),
+ InteractionClassification_QUERY,
+ sal_uInt32(ERRCODE_SVX_EXPORT_FILTER_CRYPT)));
+
+ rtl::Reference< ucbhelper::SimpleInteractionRequest > xRequest
+ = new ucbhelper::SimpleInteractionRequest(
+ aException,
+ ContinuationFlags::Approve | ContinuationFlags::Disapprove );
+
+ xHandler->handle( xRequest );
+
+ const ContinuationFlags nResp = xRequest->getResponse();
+
+ if ( nResp == ContinuationFlags::Disapprove )
+ bReturn = false;
+ }
+ return bReturn;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/excelvbahelper.cxx b/sc/source/ui/vba/excelvbahelper.cxx
new file mode 100644
index 000000000..317b06454
--- /dev/null
+++ b/sc/source/ui/vba/excelvbahelper.cxx
@@ -0,0 +1,399 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "excelvbahelper.hxx"
+
+#include <basic/basmgr.hxx>
+#include <comphelper/processfactory.hxx>
+#include <vbahelper/vbahelper.hxx>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/sheet/XSheetCellRange.hpp>
+#include <com/sun/star/sheet/GlobalSheetSettings.hpp>
+#include <com/sun/star/sheet/XUnnamedDatabaseRanges.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XDatabaseRange.hpp>
+
+#include <document.hxx>
+#include <docuno.hxx>
+#include <tabvwsh.hxx>
+#include <transobj.hxx>
+#include <cellsuno.hxx>
+#include <gridwin.hxx>
+
+#include <com/sun/star/script/vba/VBAEventId.hpp>
+#include <com/sun/star/script/vba/XVBACompatibility.hpp>
+#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
+#include <com/sun/star/script/vba/XVBAModuleInfo.hpp>
+#include <com/sun/star/script/ModuleInfo.hpp>
+#include <com/sun/star/script/ModuleType.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+namespace ooo::vba::excel {
+
+uno::Reference< sheet::XUnnamedDatabaseRanges >
+GetUnnamedDataBaseRanges( const ScDocShell* pShell )
+{
+ uno::Reference< frame::XModel > xModel;
+ if ( pShell )
+ xModel.set( pShell->GetModel(), uno::UNO_SET_THROW );
+ uno::Reference< beans::XPropertySet > xModelProps( xModel, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XUnnamedDatabaseRanges > xUnnamedDBRanges( xModelProps->getPropertyValue("UnnamedDatabaseRanges"), uno::UNO_QUERY_THROW );
+ return xUnnamedDBRanges;
+}
+
+// returns the XDatabaseRange for the autofilter on sheet (nSheet)
+// also populates sName with the name of range
+uno::Reference< sheet::XDatabaseRange >
+GetAutoFiltRange( const ScDocShell* pShell, sal_Int16 nSheet )
+{
+ uno::Reference< sheet::XUnnamedDatabaseRanges > xUnnamedDBRanges( GetUnnamedDataBaseRanges( pShell ), uno::UNO_SET_THROW );
+ uno::Reference< sheet::XDatabaseRange > xDataBaseRange;
+ if (xUnnamedDBRanges->hasByTable( nSheet ) )
+ {
+ uno::Reference< sheet::XDatabaseRange > xDBRange( xUnnamedDBRanges->getByTable( nSheet ) , uno::UNO_QUERY_THROW );
+ bool bHasAuto = false;
+ uno::Reference< beans::XPropertySet > xProps( xDBRange, uno::UNO_QUERY_THROW );
+ xProps->getPropertyValue("AutoFilter") >>= bHasAuto;
+ if ( bHasAuto )
+ {
+ xDataBaseRange=xDBRange;
+ }
+ }
+ return xDataBaseRange;
+}
+
+ScDocShell* GetDocShellFromRange( const uno::Reference< uno::XInterface >& xRange )
+{
+ ScCellRangesBase* pScCellRangesBase = comphelper::getFromUnoTunnel<ScCellRangesBase>( xRange );
+ if ( !pScCellRangesBase )
+ {
+ throw uno::RuntimeException("Failed to access underlying doc shell uno range object" );
+ }
+ return pScCellRangesBase->GetDocShell();
+}
+
+uno::Reference< XHelperInterface >
+getUnoSheetModuleObj( const uno::Reference< table::XCellRange >& xRange )
+{
+ uno::Reference< sheet::XSheetCellRange > xSheetRange( xRange, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheet > xSheet( xSheetRange->getSpreadsheet(), uno::UNO_SET_THROW );
+ return getUnoSheetModuleObj( xSheet );
+}
+
+void implSetZoom( const uno::Reference< frame::XModel >& xModel, sal_Int16 nZoom, std::vector< SCTAB >& nTabs )
+{
+ ScTabViewShell* pViewSh = excel::getBestViewShell( xModel );
+ Fraction aFract( nZoom, 100 );
+ pViewSh->GetViewData().SetZoom( aFract, aFract, nTabs );
+ pViewSh->RefreshZoom();
+}
+
+namespace {
+
+class PasteCellsWarningReseter
+{
+private:
+ bool bInitialWarningState;
+ /// @throws uno::RuntimeException
+ static uno::Reference< sheet::XGlobalSheetSettings > const & getGlobalSheetSettings()
+ {
+ static uno::Reference< sheet::XGlobalSheetSettings > xProps = sheet::GlobalSheetSettings::create( comphelper::getProcessComponentContext() );
+ return xProps;
+ }
+
+ /// @throws uno::RuntimeException
+ static bool getReplaceCellsWarning()
+ {
+ return getGlobalSheetSettings()->getReplaceCellsWarning();
+ }
+
+ /// @throws uno::RuntimeException
+ static void setReplaceCellsWarning( bool bState )
+ {
+ getGlobalSheetSettings()->setReplaceCellsWarning( bState );
+ }
+public:
+ /// @throws uno::RuntimeException
+ PasteCellsWarningReseter()
+ {
+ bInitialWarningState = getReplaceCellsWarning();
+ if ( bInitialWarningState )
+ setReplaceCellsWarning( false );
+ }
+ ~PasteCellsWarningReseter()
+ {
+ if ( bInitialWarningState )
+ {
+ // don't allow dtor to throw
+ try
+ {
+ setReplaceCellsWarning( true );
+ }
+ catch ( uno::Exception& /*e*/ ){}
+ }
+ }
+};
+
+}
+
+void
+implnPaste( const uno::Reference< frame::XModel>& xModel )
+{
+ PasteCellsWarningReseter resetWarningBox;
+ ScTabViewShell* pViewShell = getBestViewShell( xModel );
+ if ( pViewShell )
+ {
+ pViewShell->PasteFromSystem();
+ pViewShell->CellContentChanged();
+ }
+}
+
+void
+implnCopy( const uno::Reference< frame::XModel>& xModel )
+{
+ ScTabViewShell* pViewShell = getBestViewShell( xModel );
+ ScDocShell* pDocShell = getDocShell( xModel );
+ if ( !(pViewShell && pDocShell) )
+ return;
+
+ pViewShell->CopyToClip(nullptr,false,false,true);
+
+ // mark the copied transfer object so it is used in ScVbaRange::Insert
+ uno::Reference<datatransfer::XTransferable2> xTransferable(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin()));
+ ScTransferObj* pClipObj = ScTransferObj::GetOwnClipboard(xTransferable);
+ if (pClipObj)
+ {
+ pClipObj->SetUseInApi( true );
+ pDocShell->SetClipData(xTransferable);
+ }
+}
+
+void
+implnCut( const uno::Reference< frame::XModel>& xModel )
+{
+ ScTabViewShell* pViewShell = getBestViewShell( xModel );
+ ScDocShell* pDocShell = getDocShell( xModel );
+ if ( !(pViewShell && pDocShell) )
+ return;
+
+ pViewShell->CutToClip();
+
+ // mark the copied transfer object so it is used in ScVbaRange::Insert
+ uno::Reference<datatransfer::XTransferable2> xTransferable(ScTabViewShell::GetClipData(pViewShell->GetViewData().GetActiveWin()));
+ ScTransferObj* pClipObj = ScTransferObj::GetOwnClipboard(xTransferable);
+ if (pClipObj)
+ {
+ pClipObj->SetUseInApi( true );
+ pDocShell->SetClipData(xTransferable);
+ }
+}
+
+void implnPasteSpecial( const uno::Reference< frame::XModel>& xModel, InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bTranspose)
+{
+ PasteCellsWarningReseter resetWarningBox;
+
+ ScTabViewShell* pTabViewShell = getBestViewShell(xModel);
+ if (!pTabViewShell)
+ return;
+
+ ScDocShell* pDocShell = getDocShell(xModel);
+ if (!pDocShell)
+ return;
+
+ ScViewData& rView = pTabViewShell->GetViewData();
+ vcl::Window* pWin = rView.GetActiveWin();
+ if (!pWin)
+ return;
+
+ const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pWin));
+ if (pOwnClip)
+ {
+ pTabViewShell->PasteFromClip(nFlags, pOwnClip->GetDocument(),
+ nFunction, bSkipEmpty, bTranspose, false,
+ INS_NONE, InsertDeleteFlags::NONE, true);
+
+ pTabViewShell->CellContentChanged();
+ }
+}
+
+ScDocShell*
+getDocShell( const css::uno::Reference< css::frame::XModel>& xModel )
+{
+ uno::Reference< uno::XInterface > xIf( xModel, uno::UNO_QUERY_THROW );
+ ScModelObj* pModel = dynamic_cast< ScModelObj* >( xIf.get() );
+ ScDocShell* pDocShell = nullptr;
+ if ( pModel )
+ pDocShell = static_cast<ScDocShell*>(pModel->GetEmbeddedObject());
+ return pDocShell;
+
+}
+
+ScTabViewShell*
+getBestViewShell( const css::uno::Reference< css::frame::XModel>& xModel )
+{
+ ScDocShell* pDocShell = getDocShell( xModel );
+ if ( pDocShell )
+ return pDocShell->GetBestViewShell();
+ return nullptr;
+}
+
+ScTabViewShell*
+getCurrentBestViewShell( const uno::Reference< uno::XComponentContext >& xContext )
+{
+ uno::Reference< frame::XModel > xModel = getCurrentExcelDoc( xContext );
+ return getBestViewShell( xModel );
+}
+
+SfxViewFrame*
+getViewFrame( const uno::Reference< frame::XModel >& xModel )
+{
+ ScTabViewShell* pViewShell = getBestViewShell( xModel );
+ if ( pViewShell )
+ return pViewShell->GetViewFrame();
+ return nullptr;
+}
+
+uno::Reference< XHelperInterface >
+getUnoSheetModuleObj( const uno::Reference< sheet::XSpreadsheet >& xSheet )
+{
+ uno::Reference< beans::XPropertySet > xProps( xSheet, uno::UNO_QUERY_THROW );
+ OUString sCodeName;
+ xProps->getPropertyValue("CodeName") >>= sCodeName;
+ // #TODO #FIXME ideally we should 'throw' here if we don't get a valid parent, but... it is possible
+ // to create a module ( and use 'Option VBASupport 1' ) for a calc document, in this scenario there
+ // are *NO* special document module objects ( of course being able to switch between vba/non vba mode at
+ // the document in the future could fix this, especially IF the switching of the vba mode takes care to
+ // create the special document module objects if they don't exist.
+ return getUnoDocModule( sCodeName, GetDocShellFromRange( xSheet ) );
+}
+
+uno::Reference< XHelperInterface >
+getUnoSheetModuleObj( const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges )
+{
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( xRanges, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
+ uno::Reference< table::XCellRange > xRange( xEnum->nextElement(), uno::UNO_QUERY_THROW );
+ return getUnoSheetModuleObj( xRange );
+}
+
+uno::Reference< XHelperInterface >
+getUnoSheetModuleObj( const uno::Reference< table::XCell >& xCell )
+{
+ uno::Reference< sheet::XSheetCellRange > xSheetRange( xCell, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheet > xSheet( xSheetRange->getSpreadsheet(), uno::UNO_SET_THROW );
+ return getUnoSheetModuleObj( xSheet );
+}
+
+uno::Reference< XHelperInterface >
+getUnoSheetModuleObj( const uno::Reference< frame::XModel >& xModel, SCTAB nTab )
+{
+ uno::Reference< sheet::XSpreadsheetDocument > xDoc( xModel, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xSheets( xDoc->getSheets(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheet > xSheet( xSheets->getByIndex( nTab ), uno::UNO_QUERY_THROW );
+ return getUnoSheetModuleObj( xSheet );
+}
+
+void setUpDocumentModules( const uno::Reference< sheet::XSpreadsheetDocument >& xDoc )
+{
+ uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY );
+ ScDocShell* pShell = excel::getDocShell( xModel );
+ if ( !pShell )
+ return;
+
+ OUString aPrjName( "Standard" );
+ pShell->GetBasicManager()->SetName( aPrjName );
+
+ /* Set library container to VBA compatibility mode. This will create
+ the VBA Globals object and store it in the Basic manager of the
+ document. */
+ uno::Reference<script::XLibraryContainer> xLibContainer = pShell->GetBasicContainer();
+ uno::Reference<script::vba::XVBACompatibility> xVBACompat( xLibContainer, uno::UNO_QUERY_THROW );
+ xVBACompat->setVBACompatibilityMode( true );
+
+ if( xLibContainer.is() )
+ {
+ if( !xLibContainer->hasByName( aPrjName ) )
+ xLibContainer->createLibrary( aPrjName );
+ uno::Any aLibAny = xLibContainer->getByName( aPrjName );
+ uno::Reference< container::XNameContainer > xLib;
+ aLibAny >>= xLib;
+ if( xLib.is() )
+ {
+ uno::Reference< script::vba::XVBAModuleInfo > xVBAModuleInfo( xLib, uno::UNO_QUERY_THROW );
+ uno::Reference< lang::XMultiServiceFactory> xSF( pShell->GetModel(), uno::UNO_QUERY_THROW);
+ uno::Reference< container::XNameAccess > xVBACodeNamedObjectAccess( xSF->createInstance("ooo.vba.VBAObjectModuleObjectProvider"), uno::UNO_QUERY_THROW );
+ // set up the module info for the workbook and sheets in the newly created
+ // spreadsheet
+ ScDocument& rDoc = pShell->GetDocument();
+ OUString sCodeName = rDoc.GetCodeName();
+ if ( sCodeName.isEmpty() )
+ {
+ sCodeName = "ThisWorkbook";
+ rDoc.SetCodeName( sCodeName );
+ }
+
+ std::vector< OUString > sDocModuleNames { sCodeName };
+
+ for ( SCTAB index = 0; index < rDoc.GetTableCount(); index++)
+ {
+ OUString aName;
+ rDoc.GetCodeName( index, aName );
+ sDocModuleNames.push_back( aName );
+ }
+
+ for ( const auto& rName : sDocModuleNames )
+ {
+ script::ModuleInfo sModuleInfo;
+
+ uno::Any aName= xVBACodeNamedObjectAccess->getByName( rName );
+ sModuleInfo.ModuleObject.set( aName, uno::UNO_QUERY );
+ sModuleInfo.ModuleType = script::ModuleType::DOCUMENT;
+ xVBAModuleInfo->insertModuleInfo( rName, sModuleInfo );
+ if( xLib->hasByName( rName ) )
+ xLib->replaceByName( rName, uno::Any( OUString( "Option VBASupport 1\n") ) );
+ else
+ xLib->insertByName( rName, uno::Any( OUString( "Option VBASupport 1\n" ) ) );
+ }
+ }
+ }
+
+ /* Trigger the Workbook_Open event, event processor will register
+ itself as listener for specific events. */
+ try
+ {
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents( pShell->GetDocument().GetVbaEventProcessor(), uno::UNO_SET_THROW );
+ uno::Sequence< uno::Any > aArgs;
+ xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKBOOK_OPEN, aArgs );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+SfxItemSet*
+ScVbaCellRangeAccess::GetDataSet( ScCellRangesBase* pRangeObj )
+{
+ return pRangeObj ? pRangeObj->GetCurrentDataSet( true ) : nullptr;
+}
+
+} // namespace ooo::vba::excel
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/excelvbahelper.hxx b/sc/source/ui/vba/excelvbahelper.hxx
new file mode 100644
index 000000000..0b72481e3
--- /dev/null
+++ b/sc/source/ui/vba/excelvbahelper.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 <sal/config.h>
+
+#include <comphelper/servicehelper.hxx>
+
+#include <vector>
+#include <global.hxx>
+
+namespace com::sun::star::frame { class XModel; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace com::sun::star::sheet { class XDatabaseRange; }
+namespace com::sun::star::sheet { class XUnnamedDatabaseRanges; }
+namespace com::sun::star::table { class XCell; }
+namespace com::sun::star::table { class XCellRange; }
+namespace com::sun::star::sheet { class XSheetCellRangeContainer; }
+namespace com::sun::star::sheet { class XSpreadsheet; }
+namespace com::sun::star::sheet { class XSpreadsheetDocument; }
+namespace ooo::vba { class XHelperInterface; }
+
+class ScCellRangesBase;
+class ScTabViewShell;
+class SfxViewFrame;
+
+namespace ooo::vba::excel {
+
+// nTabs empty means apply zoom to all sheets
+void implSetZoom( const css::uno::Reference< css::frame::XModel >& xModel, sal_Int16 nZoom, std::vector< SCTAB >& nTabs );
+void implnCopy( const css::uno::Reference< css::frame::XModel>& xModel );
+void implnPaste ( const css::uno::Reference< css::frame::XModel>& xModel );
+void implnCut( const css::uno::Reference< css::frame::XModel>& xModel );
+void implnPasteSpecial( const css::uno::Reference< css::frame::XModel>& xModel, InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bTranspose);
+ScTabViewShell* getBestViewShell( const css::uno::Reference< css::frame::XModel>& xModel ) ;
+ScDocShell* getDocShell( const css::uno::Reference< css::frame::XModel>& xModel ) ;
+ScTabViewShell* getCurrentBestViewShell( const css::uno::Reference< css::uno::XComponentContext >& xContext );
+SfxViewFrame* getViewFrame( const css::uno::Reference< css::frame::XModel >& xModel );
+
+/// @throws css::uno::RuntimeException
+css::uno::Reference< css::sheet::XUnnamedDatabaseRanges > GetUnnamedDataBaseRanges( const ScDocShell* pShell );
+
+/// @throws css::uno::RuntimeException
+css::uno::Reference< css::sheet::XDatabaseRange > GetAutoFiltRange( const ScDocShell* pShell, sal_Int16 nSheet );
+/// @throws css::uno::RuntimeException
+css::uno::Reference< ooo::vba::XHelperInterface > getUnoSheetModuleObj( const css::uno::Reference< css::sheet::XSpreadsheet >& xSheet );
+/// @throws css::uno::RuntimeException
+css::uno::Reference< ooo::vba::XHelperInterface > getUnoSheetModuleObj( const css::uno::Reference< css::sheet::XSheetCellRangeContainer >& xRanges );
+/// @throws css::uno::RuntimeException
+css::uno::Reference< ooo::vba::XHelperInterface > getUnoSheetModuleObj( const css::uno::Reference< css::table::XCellRange >& xRange );
+/// @throws css::uno::RuntimeException
+css::uno::Reference< ooo::vba::XHelperInterface > getUnoSheetModuleObj( const css::uno::Reference< css::table::XCell >& xCell );
+/// @throws css::uno::RuntimeException
+css::uno::Reference< ooo::vba::XHelperInterface > getUnoSheetModuleObj( const css::uno::Reference< css::frame::XModel >& xModel, SCTAB nTab );
+
+/// @throws css::uno::RuntimeException
+ScDocShell* GetDocShellFromRange( const css::uno::Reference< css::uno::XInterface >& xRange );
+void setUpDocumentModules( const css::uno::Reference< css::sheet::XSpreadsheetDocument >& xDoc );
+
+class ScVbaCellRangeAccess
+{
+public:
+ static SfxItemSet* GetDataSet( ScCellRangesBase* pRangeObj );
+};
+
+// Extracts an implementation object (via XUnoTunnel) from a UNO object.
+// Will throw if unsuccessful.
+/// @throws css::uno::RuntimeException
+template < typename ImplObject >
+ ImplObject* getImplFromDocModuleWrapper( const css::uno::Reference< css::uno::XInterface >& rxWrapperIf )
+ {
+ ImplObject* pObj = comphelper::getFromUnoTunnel<ImplObject>(rxWrapperIf);
+ if ( !pObj )
+ throw css::uno::RuntimeException("Internal error, can't extract implementation object", rxWrapperIf );
+ return pObj;
+ }
+
+} // namespace ooo::vba::excel
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/helperdecl.hxx b/sc/source/ui/vba/helperdecl.hxx
new file mode 100644
index 000000000..b1163047e
--- /dev/null
+++ b/sc/source/ui/vba/helperdecl.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 <comphelper/servicedecl.hxx>
+
+namespace comphelper::service_decl {
+template <typename ImplT_, typename WithArgsT = with_args<false> >
+struct vba_service_class_ : public serviceimpl_base< detail::OwnServiceImpl<ImplT_>, WithArgsT >
+{
+ typedef serviceimpl_base< detail::OwnServiceImpl<ImplT_>, WithArgsT > baseT;
+ /** Default ctor. Implementation class without args, expecting
+ component context as single argument.
+ */
+ vba_service_class_() : baseT() {}
+ template <typename PostProcessFuncT>
+ /** Ctor to pass a post processing function/functor.
+
+ @tpl PostProcessDefaultT let your compiler deduce this
+ @param postProcessFunc function/functor that gets the yet unacquired
+ ImplT_ pointer returning a
+ uno::Reference<uno::XInterface>
+ */
+ explicit vba_service_class_( PostProcessFuncT const& postProcessFunc ) : baseT( postProcessFunc ) {}
+};
+
+} // namespace service_decl
+} // namespace comphelper
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaapplication.cxx b/sc/source/ui/vba/vbaapplication.cxx
new file mode 100644
index 000000000..2fda7fa86
--- /dev/null
+++ b/sc/source/ui/vba/vbaapplication.cxx
@@ -0,0 +1,1566 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/XDesktop.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/BasicErrorException.hpp>
+#include <com/sun/star/sheet/XCalculatable.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XNamedRanges.hpp>
+#include <com/sun/star/sheet/XSpreadsheetView.hpp>
+#include <com/sun/star/task/XStatusIndicatorSupplier.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/util/PathSettings.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <ooo/vba/XCommandBars.hpp>
+#include <ooo/vba/excel/XApplicationOutgoing.hpp>
+#include <ooo/vba/excel/XlCalculation.hpp>
+#include <ooo/vba/excel/XlMousePointer.hpp>
+#include <ooo/vba/office/MsoShapeType.hpp>
+#include <ooo/vba/office/MsoAutoShapeType.hpp>
+#include <ooo/vba/office/MsoFileDialogType.hpp>
+
+#include "vbaapplication.hxx"
+#include "vbaworkbooks.hxx"
+#include "vbaworkbook.hxx"
+#include "vbarange.hxx"
+#include "vbawsfunction.hxx"
+#include "vbadialogs.hxx"
+#include "vbawindow.hxx"
+#include "vbawindows.hxx"
+#include "vbamenubars.hxx"
+#include <tabvwsh.hxx>
+#include <gridwin.hxx>
+#include "vbanames.hxx"
+#include <vbahelper/vbashape.hxx>
+#include "vbatextboxshape.hxx"
+#include "vbaovalshape.hxx"
+#include "vbalineshape.hxx"
+#include "vbaassistant.hxx"
+#include <sc.hrc>
+#include <macromgr.hxx>
+#include "vbafiledialog.hxx"
+#include "vbafiledialogitems.hxx"
+
+#include <osl/file.hxx>
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/app.hxx>
+#include <vcl/svapp.hxx>
+
+#include <tools/diagnose_ex.h>
+
+#include <basic/sbx.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/sbuno.hxx>
+#include <basic/sbmeth.hxx>
+#include <basic/sberrors.hxx>
+#include <comphelper/sequence.hxx>
+
+#include <convuno.hxx>
+#include <cellsuno.hxx>
+#include <unonames.hxx>
+#include <docsh.hxx>
+#include "excelvbahelper.hxx"
+#include <basic/sbxobj.hxx>
+
+#include <viewutil.hxx>
+#include <docoptio.hxx>
+#include <scmod.hxx>
+#include <scdll.hxx>
+
+#include <list>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY_THROW;
+using ::com::sun::star::uno::UNO_QUERY;
+
+/** Global application settings shared by all open workbooks. */
+struct ScVbaAppSettings
+{
+ bool mbDisplayAlerts;
+ bool mbEnableEvents;
+ bool mbExcel4Menus;
+ bool mbDisplayNoteIndicator;
+ bool mbShowWindowsInTaskbar;
+ bool mbEnableCancelKey;
+ explicit ScVbaAppSettings();
+};
+
+ScVbaAppSettings::ScVbaAppSettings() :
+ mbDisplayAlerts( true ),
+ mbEnableEvents( true ),
+ mbExcel4Menus( false ),
+ mbDisplayNoteIndicator( true ),
+ mbShowWindowsInTaskbar( true ),
+ mbEnableCancelKey( false )
+{
+}
+
+namespace {
+
+ScVbaAppSettings& ScVbaStaticAppSettings()
+{
+ static ScVbaAppSettings SINGLETON;
+ return SINGLETON;
+}
+
+class ScVbaApplicationOutgoingConnectionPoint : public cppu::WeakImplHelper<XConnectionPoint>
+{
+private:
+ ScVbaApplication* mpApp;
+
+public:
+ ScVbaApplicationOutgoingConnectionPoint( ScVbaApplication* pApp );
+
+ // XConnectionPoint
+ sal_uInt32 SAL_CALL Advise(const uno::Reference< XSink >& Sink ) override;
+ void SAL_CALL Unadvise( sal_uInt32 Cookie ) override;
+};
+
+}
+
+sal_uInt32
+ScVbaApplication::AddSink( const uno::Reference< XSink >& xSink )
+{
+ {
+ SolarMutexGuard aGuard;
+ ScDLL::Init();
+ }
+ // No harm in potentially calling this several times
+ SC_MOD()->RegisterAutomationApplicationEventsCaller( uno::Reference< XSinkCaller >(this) );
+ mvSinks.push_back(xSink);
+ return mvSinks.size();
+}
+
+void
+ScVbaApplication::RemoveSink( sal_uInt32 nNumber )
+{
+ if (nNumber < 1 || nNumber > mvSinks.size())
+ return;
+
+ mvSinks[nNumber-1] = uno::Reference< XSink >();
+}
+
+ScVbaApplication::ScVbaApplication( const uno::Reference<uno::XComponentContext >& xContext ) :
+ ScVbaApplication_BASE( xContext ),
+ mrAppSettings( ScVbaStaticAppSettings() ),
+ m_nDialogType(0)
+{
+}
+
+ScVbaApplication::~ScVbaApplication()
+{
+}
+
+/*static*/ bool ScVbaApplication::getDocumentEventsEnabled()
+{
+ return ScVbaStaticAppSettings().mbEnableEvents;
+}
+
+OUString SAL_CALL
+ScVbaApplication::getExactName( const OUString& aApproximateName )
+{
+ uno::Reference< beans::XExactName > xWSF( new ScVbaWSFunction( this, mxContext ) );
+ return xWSF->getExactName( aApproximateName );
+}
+
+uno::Reference< beans::XIntrospectionAccess > SAL_CALL
+ScVbaApplication::getIntrospection()
+{
+ uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
+ return xWSF->getIntrospection();
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::invoke( const OUString& FunctionName, const uno::Sequence< uno::Any >& Params, uno::Sequence< sal_Int16 >& OutParamIndex, uno::Sequence< uno::Any >& OutParam)
+{
+ /* When calling the functions directly at the Application object, no runtime
+ errors are thrown, but the error is inserted into the return value. */
+ uno::Any aAny;
+ try
+ {
+ uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
+ aAny = xWSF->invoke( FunctionName, Params, OutParamIndex, OutParam );
+ }
+ catch (const uno::Exception&)
+ {
+ aAny <<= script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), 1000, OUString() );
+ }
+ return aAny;
+}
+
+void SAL_CALL
+ScVbaApplication::setValue( const OUString& PropertyName, const uno::Any& Value )
+{
+ uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
+ xWSF->setValue( PropertyName, Value );
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::getValue( const OUString& PropertyName )
+{
+ uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
+ return xWSF->getValue( PropertyName );
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::hasMethod( const OUString& Name )
+{
+ uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
+ return xWSF->hasMethod( Name );
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::hasProperty( const OUString& Name )
+{
+ uno::Reference< script::XInvocation > xWSF( new ScVbaWSFunction( this, mxContext ) );
+ return xWSF->hasProperty( Name );
+}
+
+uno::Reference< excel::XWorkbook >
+ScVbaApplication::getActiveWorkbook()
+{
+ uno::Reference< frame::XModel > xModel( getCurrentExcelDoc( mxContext ), uno::UNO_SET_THROW );
+ uno::Reference< excel::XWorkbook > xWorkbook( getVBADocument( xModel ), uno::UNO_QUERY );
+ if( xWorkbook.is() ) return xWorkbook;
+ // #i116936# getVBADocument() may return null in documents without global VBA mode enabled
+ return new ScVbaWorkbook( this, mxContext, xModel );
+}
+
+uno::Reference< excel::XWorkbook > SAL_CALL
+ScVbaApplication::getThisWorkbook()
+{
+ uno::Reference< frame::XModel > xModel( getThisExcelDoc( mxContext ), uno::UNO_SET_THROW );
+ uno::Reference< excel::XWorkbook > xWorkbook( getVBADocument( xModel ), uno::UNO_QUERY );
+ if( xWorkbook.is() ) return xWorkbook;
+ // #i116936# getVBADocument() may return null in documents without global VBA mode enabled
+ return new ScVbaWorkbook( this, mxContext, xModel );
+}
+
+uno::Reference< XAssistant > SAL_CALL
+ScVbaApplication::getAssistant()
+{
+ return uno::Reference< XAssistant >( new ScVbaAssistant( this, mxContext ) );
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::getSelection()
+{
+ uno::Reference< frame::XModel > xModel( getCurrentDocument() );
+
+ Reference< view::XSelectionSupplier > xSelSupp( xModel->getCurrentController(), UNO_QUERY_THROW );
+ Reference< beans::XPropertySet > xPropSet( xSelSupp, UNO_QUERY_THROW );
+ OUString aPropName( SC_UNO_FILTERED_RANGE_SELECTION );
+ uno::Any aOldVal = xPropSet->getPropertyValue( aPropName );
+ uno::Any any;
+ any <<= false;
+ xPropSet->setPropertyValue( aPropName, any );
+ uno::Reference<uno::XInterface> aSelection(xSelSupp->getSelection(), uno::UNO_QUERY);
+ xPropSet->setPropertyValue( aPropName, aOldVal );
+
+ if (!aSelection.is())
+ {
+ throw uno::RuntimeException( "failed to obtain current selection" );
+ }
+
+ uno::Reference< lang::XServiceInfo > xServiceInfo( aSelection, uno::UNO_QUERY_THROW );
+ OUString sImplementationName = xServiceInfo->getImplementationName();
+
+ if( sImplementationName.equalsIgnoreAsciiCase("com.sun.star.drawing.SvxShapeCollection") )
+ {
+ uno::Reference< drawing::XShapes > xShapes( aSelection, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xIndexAccess( xShapes, uno::UNO_QUERY_THROW );
+ uno::Reference< drawing::XShape > xShape( xIndexAccess->getByIndex(0), uno::UNO_QUERY_THROW );
+ // if ScVbaShape::getType( xShape ) == office::MsoShapeType::msoAutoShape
+ // and the uno object implements the com.sun.star.drawing.Text service
+ // return a textboxshape object
+ sal_Int32 nType = ScVbaShape::getType( xShape );
+ if ( nType == office::MsoShapeType::msoAutoShape )
+ {
+ // TODO Oval with text box
+ if( ScVbaShape::getAutoShapeType( xShape ) == office::MsoAutoShapeType::msoShapeOval )
+ {
+ return uno::Any( uno::Reference< msforms::XOval >(new ScVbaOvalShape( mxContext, xShape, xShapes, xModel ) ) );
+ }
+
+
+ uno::Reference< lang::XServiceInfo > xShapeServiceInfo( xShape, uno::UNO_QUERY_THROW );
+ if ( xShapeServiceInfo->supportsService("com.sun.star.drawing.Text") )
+ {
+ return uno::Any( uno::Reference< msforms::XTextBoxShape >(
+ new ScVbaTextBoxShape( mxContext, xShape, xShapes, xModel ) ) );
+ }
+ }
+ else if ( nType == office::MsoShapeType::msoLine )
+ {
+ return uno::Any( uno::Reference< msforms::XLine >( new ScVbaLineShape(
+ mxContext, xShape, xShapes, xModel ) ) );
+ }
+ return uno::Any( uno::Reference< msforms::XShape >(new ScVbaShape( this, mxContext, xShape, xShapes, xModel, ScVbaShape::getType( xShape ) ) ) );
+ }
+ else if( xServiceInfo->supportsService("com.sun.star.sheet.SheetCellRange") ||
+ xServiceInfo->supportsService("com.sun.star.sheet.SheetCellRanges") )
+ {
+ uno::Reference< table::XCellRange > xRange( aSelection, ::uno::UNO_QUERY);
+ if ( !xRange.is() )
+ {
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges( aSelection, ::uno::UNO_QUERY);
+ if ( xRanges.is() )
+ return uno::Any( uno::Reference< excel::XRange >( new ScVbaRange( excel::getUnoSheetModuleObj( xRanges ), mxContext, xRanges ) ) );
+
+ }
+ return uno::Any( uno::Reference< excel::XRange >(new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), mxContext, xRange ) ) );
+ }
+ else
+ {
+ throw uno::RuntimeException( sImplementationName + " not supported" );
+ }
+}
+
+uno::Reference< excel::XRange >
+ScVbaApplication::getActiveCell()
+{
+ uno::Reference< sheet::XSpreadsheetView > xView( getCurrentDocument()->getCurrentController(), uno::UNO_QUERY_THROW );
+ uno::Reference< table::XCellRange > xRange( xView->getActiveSheet(), ::uno::UNO_QUERY_THROW);
+ ScTabViewShell* pViewShell = excel::getCurrentBestViewShell(mxContext);
+ if ( !pViewShell )
+ throw uno::RuntimeException("No ViewShell available" );
+ ScViewData& rTabView = pViewShell->GetViewData();
+
+ sal_Int32 nCursorX = rTabView.GetCurX();
+ sal_Int32 nCursorY = rTabView.GetCurY();
+
+ // #i117392# excel::getUnoSheetModuleObj() may return null in documents without global VBA mode enabled
+ return new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), mxContext, xRange->getCellRangeByPosition( nCursorX, nCursorY, nCursorX, nCursorY ) );
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::GetOpenFilename(const uno::Any& /*aFileFilter*/, const uno::Any& /*aFilterIndex*/, const uno::Any& aTitle, const uno::Any& /*aButtonText*/, const uno::Any& aMultiSelect)
+{
+ // TODO - take all parameters into account
+ uno::Reference<excel::XFileDialog> xDialog(new ScVbaFileDialog(this, mxContext, office::MsoFileDialogType::msoFileDialogFilePicker));
+ xDialog->setTitle(aTitle);
+ xDialog->setAllowMultiSelect(aMultiSelect);
+
+ bool bMultiSelect = false;
+ aMultiSelect >>= bMultiSelect;
+
+ if (xDialog->Show() == 0)
+ {
+ // return FALSE when canceled
+ return uno::Any(false);
+ }
+
+ uno::Reference<excel::XFileDialogSelectedItems> xItems = xDialog->getSelectedItems();
+ auto* pItems = dynamic_cast<ScVbaFileDialogSelectedItems*>(xItems.get());
+
+ // Check, if the implementation of XFileDialogSelectedItems is what we expect
+ if (!pItems)
+ throw uno::RuntimeException("Unexpected XFileDialogSelectedItems implementation");
+
+ auto const & rItemVector = pItems->getItems();
+
+ if (!bMultiSelect) // only 1 selection allowed - return path
+ {
+ OUString aPath;
+ if (!rItemVector.empty())
+ aPath = rItemVector.at(0);
+ return uno::Any(aPath);
+ }
+ else
+ {
+ // convert to sequence
+ return uno::Any(comphelper::containerToSequence(rItemVector));
+ }
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::International( sal_Int32 /*Index*/ )
+{
+ // complete stub for now
+ // #TODO flesh out some of the Indices we could handle
+ uno::Any aRet;
+ return aRet;
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::FileDialog( const uno::Any& DialogType )
+{
+ sal_Int32 nType = 0;
+ DialogType >>= nType;
+
+ if( !m_xFileDialog || nType != m_nDialogType )
+ {
+ m_nDialogType = nType;
+ m_xFileDialog = uno::Reference<excel::XFileDialog> ( new ScVbaFileDialog( this, mxContext, nType ));
+ }
+ return uno::Any( m_xFileDialog );
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::Workbooks( const uno::Any& aIndex )
+{
+ uno::Reference< XCollection > xWorkBooks( new ScVbaWorkbooks( this, mxContext ) );
+ if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID )
+ {
+ // void then somebody did Workbooks.something in vba
+ return uno::Any( xWorkBooks );
+ }
+
+ return xWorkBooks->Item( aIndex, uno::Any() );
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::Worksheets( const uno::Any& aIndex )
+{
+ uno::Reference< excel::XWorkbook > xWorkbook( getActiveWorkbook(), uno::UNO_SET_THROW );
+ return xWorkbook->Worksheets( aIndex );
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::WorksheetFunction( )
+{
+ return uno::Any( uno::Reference< script::XInvocation >( new ScVbaWSFunction( this, mxContext ) ) );
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::Evaluate( const OUString& Name )
+{
+ // #TODO Evaluate allows other things to be evaluated, e.g. functions
+ // I think ( like SIN(3) etc. ) need to investigate that
+ // named Ranges also? e.g. [MyRange] if so need a list of named ranges
+ uno::Any aVoid;
+ return uno::Any( getActiveWorkbook()->getActiveSheet()->Range( uno::Any( Name ), aVoid ) );
+}
+
+uno::Any
+ScVbaApplication::Dialogs( const uno::Any &aIndex )
+{
+ uno::Reference< excel::XDialogs > xDialogs( new ScVbaDialogs( uno::Reference< XHelperInterface >( this ), mxContext, getCurrentDocument() ) );
+ if( !aIndex.hasValue() )
+ return uno::Any( xDialogs );
+ return xDialogs->Item( aIndex );
+}
+
+uno::Reference< excel::XWindow > SAL_CALL
+ScVbaApplication::getActiveWindow()
+{
+ uno::Reference< frame::XModel > xModel = getCurrentDocument();
+ uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW );
+ uno::Reference< XHelperInterface > xParent( getActiveWorkbook(), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XWindow > xWin( new ScVbaWindow( xParent, mxContext, xModel, xController ) );
+ return xWin;
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::getCutCopyMode()
+{
+ //# FIXME TODO, implementation
+ uno::Any result;
+ result <<= false;
+ return result;
+}
+
+void SAL_CALL
+ScVbaApplication::setCutCopyMode( const uno::Any& /* _cutcopymode */ )
+{
+ //# FIXME TODO, implementation
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::getStatusBar()
+{
+ return uno::Any( !getDisplayStatusBar() );
+}
+
+css::uno::Any SAL_CALL ScVbaApplication::getWindowState()
+{
+ return getActiveWindow()->getWindowState();
+}
+
+void SAL_CALL ScVbaApplication::setWindowState(const css::uno::Any& rWindowState)
+{
+ getActiveWindow()->setWindowState(rWindowState);
+}
+
+void SAL_CALL
+ScVbaApplication::setStatusBar( const uno::Any& _statusbar )
+{
+ OUString sText;
+ bool bDefault = false;
+ uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW );
+ uno::Reference< task::XStatusIndicatorSupplier > xStatusIndicatorSupplier( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
+ uno::Reference< task::XStatusIndicator > xStatusIndicator( xStatusIndicatorSupplier->getStatusIndicator(), uno::UNO_SET_THROW );
+ if( _statusbar >>= sText )
+ {
+ setDisplayStatusBar( true );
+ if ( !sText.isEmpty() )
+ xStatusIndicator->start( sText, 100 );
+ else
+ xStatusIndicator->end(); // restore normal state for empty text
+ }
+ else if( _statusbar >>= bDefault )
+ {
+ if( !bDefault )
+ {
+ xStatusIndicator->end();
+ setDisplayStatusBar( true );
+ }
+ }
+ else
+ throw uno::RuntimeException("Invalid parameter. It should be a string or False" );
+}
+
+::sal_Int32 SAL_CALL
+ScVbaApplication::getCalculation()
+{
+ // TODO: in Excel, this is an application-wide setting
+ uno::Reference<sheet::XCalculatable> xCalc(getCurrentDocument(), uno::UNO_QUERY_THROW);
+ if(xCalc->isAutomaticCalculationEnabled())
+ return excel::XlCalculation::xlCalculationAutomatic;
+ else
+ return excel::XlCalculation::xlCalculationManual;
+}
+
+void SAL_CALL
+ScVbaApplication::setCalculation( ::sal_Int32 _calculation )
+{
+ // TODO: in Excel, this is an application-wide setting
+ uno::Reference< sheet::XCalculatable > xCalc(getCurrentDocument(), uno::UNO_QUERY_THROW);
+ switch(_calculation)
+ {
+ case excel::XlCalculation::xlCalculationManual:
+ xCalc->enableAutomaticCalculation(false);
+ break;
+ case excel::XlCalculation::xlCalculationAutomatic:
+ case excel::XlCalculation::xlCalculationSemiautomatic:
+ xCalc->enableAutomaticCalculation(true);
+ break;
+ }
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::Windows( const uno::Any& aIndex )
+{
+ uno::Reference< excel::XWindows > xWindows( new ScVbaWindows( this, mxContext ) );
+ if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID )
+ return uno::Any( xWindows );
+ return xWindows->Item( aIndex, uno::Any() );
+}
+void SAL_CALL
+ScVbaApplication::wait( double time )
+{
+ StarBASIC* pBasic = SfxApplication::GetBasic();
+ SbxArrayRef aArgs = new SbxArray;
+ SbxVariableRef aRef = new SbxVariable;
+ aRef->PutDouble( time );
+ aArgs->Put(aRef.get(), 1);
+ SbMethod* pMeth = static_cast<SbMethod*>(pBasic->GetRtl()->Find( "WaitUntil", SbxClassType::Method ));
+
+ if ( pMeth )
+ {
+ pMeth->SetParameters( aArgs.get() );
+ SbxVariableRef refTemp = pMeth;
+ // forces a broadcast
+ SbxVariableRef pNew = new SbxMethod( *static_cast<SbxMethod*>(pMeth));
+ }
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::Range( const uno::Any& Cell1, const uno::Any& Cell2 )
+{
+ uno::Reference< excel::XRange > xVbRange = ScVbaRange::ApplicationRange( mxContext, Cell1, Cell2 );
+ return uno::Any( xVbRange );
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::Names( const css::uno::Any& aIndex )
+{
+ uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW );
+ uno::Reference< beans::XPropertySet > xPropertySet( xModel, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XNamedRanges > xNamedRanges( xPropertySet->getPropertyValue(
+ "NamedRanges" ), uno::UNO_QUERY_THROW );
+
+ css::uno::Reference< excel::XNames > xNames ( new ScVbaNames( this , mxContext , xNamedRanges , xModel ) );
+ if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID )
+ {
+ return uno::Any( xNames );
+ }
+ return xNames->Item( aIndex, uno::Any() );
+}
+
+uno::Reference< excel::XWorksheet > SAL_CALL
+ScVbaApplication::getActiveSheet()
+{
+ uno::Reference< excel::XWorksheet > result;
+ uno::Reference< excel::XWorkbook > xWorkbook = getActiveWorkbook();
+ if ( xWorkbook.is() )
+ {
+ uno::Reference< excel::XWorksheet > xWorksheet =
+ xWorkbook->getActiveSheet();
+ if ( xWorksheet.is() )
+ {
+ result = xWorksheet;
+ }
+ }
+
+ if ( !result.is() )
+ {
+ // Fixme - check if this is reasonable/desired behavior
+ throw uno::RuntimeException("No activeSheet available" );
+ }
+ return result;
+
+}
+
+/*******************************************************************************
+ * In msdn:
+ * Reference Optional Variant. The destination. Can be a Range
+ * object, a string that contains a cell reference in R1C1-style notation,
+ * or a string that contains a Visual Basic procedure name.
+ * Scroll Optional Variant. True to scroll, False to not scroll through
+ * the window. The default is False.
+ * Parser is split to three parts, Range, R1C1 string and procedure name.
+ * by test excel, it seems Scroll no effect. ???
+*******************************************************************************/
+void SAL_CALL
+ScVbaApplication::GoTo( const uno::Any& Reference, const uno::Any& Scroll )
+{
+ //test Scroll is a boolean
+ bool bScroll = false;
+ //R1C1-style string or a string of procedure name.
+
+ if( Scroll.hasValue() )
+ {
+ bool aScroll = false;
+ if( !(Scroll >>= aScroll) )
+ throw uno::RuntimeException("second parameter should be boolean" );
+
+ bScroll = aScroll;
+
+ }
+
+ OUString sRangeName;
+ if( Reference >>= sRangeName )
+ {
+ uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW );
+ uno::Reference< sheet::XSpreadsheetView > xSpreadsheet(
+ xModel->getCurrentController(), uno::UNO_QUERY_THROW );
+
+ ScTabViewShell* pShell = excel::getCurrentBestViewShell( mxContext );
+ ScGridWindow* gridWindow = static_cast<ScGridWindow*>(pShell->GetWindow());
+ try
+ {
+ uno::Reference< excel::XRange > xVbaSheetRange = ScVbaRange::getRangeObjectForName(
+ mxContext, sRangeName, excel::getDocShell( xModel ), formula::FormulaGrammar::CONV_XL_R1C1 );
+
+ if( bScroll )
+ {
+ xVbaSheetRange->Select();
+ uno::Reference< excel::XWindow > xWindow = getActiveWindow();
+ ScSplitPos eWhich = pShell->GetViewData().GetActivePart();
+ sal_Int32 nValueX = pShell->GetViewData().GetPosX(WhichH(eWhich));
+ sal_Int32 nValueY = pShell->GetViewData().GetPosY(WhichV(eWhich));
+ xWindow->SmallScroll( uno::Any( static_cast<sal_Int16>(xVbaSheetRange->getRow() - 1) ),
+ uno::Any( static_cast<sal_Int16>(nValueY) ),
+ uno::Any( static_cast<sal_Int16>(xVbaSheetRange->getColumn() - 1) ),
+ uno::Any( static_cast<sal_Int16>(nValueX) ) );
+ gridWindow->GrabFocus();
+ }
+ else
+ {
+ xVbaSheetRange->Select();
+ gridWindow->GrabFocus();
+ }
+ }
+ catch (const uno::RuntimeException&)
+ {
+ //maybe this should be a procedure name
+ //TODO for procedure name
+ //browse::XBrowseNodeFactory is a singleton. OUString( "/singletons/com.sun.star.script.browse.theBrowseNodeFactory")
+ //and the createView( browse::BrowseNodeFactoryViewTypes::MACROSELECTOR ) to get a root browse::XBrowseNode.
+ //for query XInvocation interface.
+ //but how to directly get the XInvocation?
+ throw uno::RuntimeException("invalid reference for range name, it should be procedure name" );
+ }
+ return;
+ }
+ uno::Reference< excel::XRange > xRange;
+ if( Reference >>= xRange )
+ {
+ uno::Reference< excel::XRange > xVbaRange( Reference, uno::UNO_QUERY );
+ ScTabViewShell* pShell = excel::getCurrentBestViewShell( mxContext );
+ ScGridWindow* gridWindow = static_cast<ScGridWindow*>(pShell->GetWindow());
+ if ( xVbaRange.is() )
+ {
+ //TODO bScroll should be used. At this time, it does not have effect
+ if( bScroll )
+ {
+ xVbaRange->Select();
+ uno::Reference< excel::XWindow > xWindow = getActiveWindow();
+ ScSplitPos eWhich = pShell->GetViewData().GetActivePart();
+ sal_Int32 nValueX = pShell->GetViewData().GetPosX(WhichH(eWhich));
+ sal_Int32 nValueY = pShell->GetViewData().GetPosY(WhichV(eWhich));
+ xWindow->SmallScroll( uno::Any( static_cast<sal_Int16>(xVbaRange->getRow() - 1) ),
+ uno::Any( static_cast<sal_Int16>(nValueY) ),
+ uno::Any( static_cast<sal_Int16>(xVbaRange->getColumn() - 1) ),
+ uno::Any( static_cast<sal_Int16>(nValueX) ) );
+ gridWindow->GrabFocus();
+ }
+ else
+ {
+ xVbaRange->Select();
+ gridWindow->GrabFocus();
+ }
+ }
+ return;
+ }
+ throw uno::RuntimeException("invalid reference or name" );
+}
+
+sal_Int32 SAL_CALL
+ScVbaApplication::getCursor()
+{
+ PointerStyle nPointerStyle = getPointerStyle(getCurrentDocument());
+
+ switch( nPointerStyle )
+ {
+ case PointerStyle::Arrow:
+ return excel::XlMousePointer::xlNorthwestArrow;
+ case PointerStyle::Null:
+ return excel::XlMousePointer::xlDefault;
+ case PointerStyle::Wait:
+ return excel::XlMousePointer::xlWait;
+ case PointerStyle::Text:
+ return excel::XlMousePointer::xlIBeam;
+ default:
+ return excel::XlMousePointer::xlDefault;
+ }
+}
+
+void SAL_CALL
+ScVbaApplication::setCursor( sal_Int32 _cursor )
+{
+ try
+ {
+ uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW );
+ switch( _cursor )
+ {
+ case excel::XlMousePointer::xlNorthwestArrow:
+ {
+ setCursorHelper( xModel, PointerStyle::Arrow, false );
+ break;
+ }
+ case excel::XlMousePointer::xlWait:
+ case excel::XlMousePointer::xlIBeam:
+ {
+ PointerStyle nPointer( static_cast< PointerStyle >( _cursor ) );
+ //It will set the edit window, toobar and statusbar's mouse pointer.
+ setCursorHelper( xModel, nPointer, true );
+ break;
+ }
+ case excel::XlMousePointer::xlDefault:
+ {
+ setCursorHelper( xModel, PointerStyle::Null, false );
+ break;
+ }
+ default:
+ throw uno::RuntimeException("Unknown value for Cursor pointer" );
+ // TODO: isn't this a flaw in the API? It should be allowed to throw an
+ // IllegalArgumentException, or so
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sc.ui");
+ }
+}
+
+// #TODO perhaps we should switch the return type depending of the filter
+// type, e.g. return Calc for Calc and Excel if it's an imported doc
+OUString SAL_CALL
+ScVbaApplication::getName()
+{
+ return "Microsoft Excel";
+}
+
+// #TODO #FIXME get/setDisplayAlerts are just stub impl
+// here just the status of the switch is set
+// the function that throws an error message needs to
+// evaluate this switch in order to know whether it has to disable the
+// error message thrown by OpenOffice
+
+void SAL_CALL
+ScVbaApplication::setDisplayAlerts(sal_Bool displayAlerts)
+{
+ mrAppSettings.mbDisplayAlerts = displayAlerts;
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::getDisplayAlerts()
+{
+ return mrAppSettings.mbDisplayAlerts;
+}
+
+void SAL_CALL
+ScVbaApplication::setEnableEvents(sal_Bool bEnable)
+{
+ mrAppSettings.mbEnableEvents = bEnable;
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::getEnableEvents()
+{
+ return mrAppSettings.mbEnableEvents;
+}
+
+void SAL_CALL
+ScVbaApplication::setEnableCancelKey(sal_Bool bEnable)
+{
+ // Stub, does nothing
+ mrAppSettings.mbEnableCancelKey = bEnable;
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::getEnableCancelKey()
+{
+ return mrAppSettings.mbEnableCancelKey;
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::getDisplayFullScreen()
+{
+ SfxViewShell* pShell = excel::getCurrentBestViewShell( mxContext );
+ if ( pShell )
+ return ScViewUtil::IsFullScreen( *pShell );
+ return false;
+}
+
+void SAL_CALL
+ScVbaApplication::setDisplayFullScreen( sal_Bool bSet )
+{
+ // #FIXME calling ScViewUtil::SetFullScreen( *pShell, bSet );
+ // directly results in a strange crash, using dispatch instead
+ if ( bSet != getDisplayFullScreen() )
+ dispatchRequests( getCurrentDocument(), ".uno:FullScreen" );
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::getDisplayScrollBars()
+{
+ ScTabViewShell* pShell = excel::getCurrentBestViewShell( mxContext );
+ if ( pShell )
+ {
+ return ( pShell->GetViewData().IsHScrollMode() && pShell->GetViewData().IsVScrollMode() );
+ }
+ return true;
+}
+
+void SAL_CALL
+ScVbaApplication::setDisplayScrollBars( sal_Bool bSet )
+{
+ // use uno here as it does all he repainting etc. magic
+ uno::Reference< sheet::XSpreadsheetView > xView( getCurrentDocument()->getCurrentController(), uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xProps( xView, uno::UNO_QUERY );
+ xProps->setPropertyValue("HasVerticalScrollBar", uno::Any( bSet ) );
+ xProps->setPropertyValue("HasHorizontalScrollBar", uno::Any( bSet ) );
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::getDisplayExcel4Menus()
+{
+ return mrAppSettings.mbExcel4Menus;
+}
+
+void SAL_CALL
+ScVbaApplication::setDisplayExcel4Menus( sal_Bool bSet )
+{
+ mrAppSettings.mbExcel4Menus = bSet;
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::getDisplayNoteIndicator()
+{
+ return mrAppSettings.mbDisplayNoteIndicator;
+}
+
+void SAL_CALL
+ScVbaApplication::setDisplayNoteIndicator( sal_Bool bSet )
+{
+ mrAppSettings.mbDisplayNoteIndicator = bSet;
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::getShowWindowsInTaskbar()
+{
+ return mrAppSettings.mbShowWindowsInTaskbar;
+}
+
+void SAL_CALL
+ScVbaApplication::setShowWindowsInTaskbar( sal_Bool bSet )
+{
+ mrAppSettings.mbShowWindowsInTaskbar = bSet;
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::getIteration()
+{
+ return SC_MOD()->GetDocOptions().IsIter();
+}
+
+void SAL_CALL
+ScVbaApplication::setIteration( sal_Bool bSet )
+{
+ uno::Reference< lang::XMultiComponentFactory > xSMgr(
+ mxContext->getServiceManager(), uno::UNO_SET_THROW );
+
+ uno::Reference< frame::XDesktop > xDesktop
+ (xSMgr->createInstanceWithContext( "com.sun.star.frame.Desktop" , mxContext), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XEnumeration > xComponents = xDesktop->getComponents()->createEnumeration();
+ while ( xComponents->hasMoreElements() )
+ {
+ uno::Reference< lang::XServiceInfo > xServiceInfo( xComponents->nextElement(), uno::UNO_QUERY );
+ if ( xServiceInfo.is() && xServiceInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) )
+ {
+ uno::Reference< beans::XPropertySet > xProps( xServiceInfo, uno::UNO_QUERY );
+ if ( xProps.is() )
+ xProps->setPropertyValue( SC_UNO_ITERENABLED, uno::Any( bSet ) );
+ }
+ }
+ ScDocOptions aOpts( SC_MOD()->GetDocOptions() );
+ aOpts.SetIter( bSet );
+ SC_MOD()->SetDocOptions( aOpts );
+}
+
+void SAL_CALL
+ScVbaApplication::Calculate()
+{
+ uno::Reference< frame::XModel > xModel( getCurrentDocument(), uno::UNO_SET_THROW );
+ uno::Reference< sheet::XCalculatable > xCalculatable( getCurrentDocument(), uno::UNO_QUERY_THROW );
+ xCalculatable->calculateAll();
+}
+
+/// @throws uno::RuntimeException
+static uno::Reference< util::XPathSettings > const & lcl_getPathSettingsService( const uno::Reference< uno::XComponentContext >& xContext )
+{
+ static uno::Reference< util::XPathSettings > xPathSettings( util::PathSettings::create( xContext ) );
+ return xPathSettings;
+}
+
+OUString ScVbaApplication::getOfficePath( const OUString& _sPathType )
+{
+ OUString sRetPath;
+ const uno::Reference< util::XPathSettings >& xProps = lcl_getPathSettingsService( mxContext );
+ try
+ {
+ OUString sUrl;
+ xProps->getPropertyValue( _sPathType ) >>= sUrl;
+
+ // if it's a list of paths then use the last one
+ sal_Int32 nIndex = sUrl.lastIndexOf( ';' ) ;
+ if ( nIndex > 0 )
+ sUrl = sUrl.copy( nIndex + 1 );
+ ::osl::File::getSystemPathFromFileURL( sUrl, sRetPath );
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::runtimeexception(ERRCODE_BASIC_METHOD_FAILED);
+ }
+ return sRetPath;
+}
+
+void SAL_CALL
+ScVbaApplication::setDefaultFilePath( const OUString& DefaultFilePath )
+{
+ const uno::Reference< util::XPathSettings >& xProps = lcl_getPathSettingsService( mxContext );
+ OUString aURL;
+ osl::FileBase::getFileURLFromSystemPath( DefaultFilePath, aURL );
+ xProps->setWork( aURL );
+}
+
+OUString SAL_CALL
+ScVbaApplication::getDefaultFilePath()
+{
+ return getOfficePath( "Work");
+}
+
+OUString SAL_CALL
+ScVbaApplication::getLibraryPath()
+{
+ return getOfficePath( "Basic");
+}
+
+OUString SAL_CALL
+ScVbaApplication::getTemplatesPath()
+{
+ return getOfficePath( "Template");
+}
+
+OUString SAL_CALL
+ScVbaApplication::getPathSeparator()
+{
+ return OUString( sal_Unicode(SAL_PATHDELIMITER) );
+}
+
+OUString SAL_CALL
+ScVbaApplication::getOperatingSystem()
+{
+ // TODO Solution should contain the version number of the operating system
+ // too.
+#if defined(_WIN32)
+ return "Windows";
+#elif defined(MACOSX)
+ return "Macintosh";
+#elif defined(UNX)
+ // M. Office is not available on Unix systems, so it is not documented.
+ return "Unix";
+#else
+ return OUString("Unknown");
+#endif
+}
+
+// Helpers for Intersect and Union
+
+namespace {
+
+typedef ::std::list< ScRange > ListOfScRange;
+
+/** Appends all ranges of a VBA Range object in the passed Any to the list of ranges.
+
+ @throws script::BasicErrorException
+ @throws uno::RuntimeException
+*/
+void lclAddToListOfScRange( ListOfScRange& rList, const uno::Any& rArg )
+{
+ if( !rArg.hasValue() )
+ return;
+
+ uno::Reference< excel::XRange > xRange( rArg, uno::UNO_QUERY_THROW );
+ uno::Reference< XCollection > xCol( xRange->Areas( uno::Any() ), uno::UNO_QUERY_THROW );
+ for( sal_Int32 nIdx = 1, nCount = xCol->getCount(); nIdx <= nCount; ++nIdx )
+ {
+ uno::Reference< excel::XRange > xAreaRange( xCol->Item( uno::Any( nIdx ), uno::Any() ), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XCellRangeAddressable > xAddressable( xAreaRange->getCellRange(), uno::UNO_QUERY_THROW );
+ ScRange aScRange;
+ ScUnoConversion::FillScRange( aScRange, xAddressable->getRangeAddress() );
+ rList.push_back( aScRange );
+ }
+}
+
+/** Returns true, if the passed ranges can be expressed by a single range. The
+ new range will be contained in r1 then, the range r2 can be removed. */
+bool lclTryJoin( ScRange& r1, const ScRange& r2 )
+{
+ // 1) r2 is completely inside r1
+ if( r1.Contains( r2 ) )
+ return true;
+
+ // 2) r1 is completely inside r2
+ if( r2.Contains( r1 ) )
+ {
+ r1 = r2;
+ return true;
+ }
+
+ SCCOL n1L = r1.aStart.Col();
+ SCCOL n1R = r1.aEnd.Col();
+ SCROW n1T = r1.aStart.Row();
+ SCROW n1B = r1.aEnd.Row();
+ SCCOL n2L = r2.aStart.Col();
+ SCCOL n2R = r2.aEnd.Col();
+ SCROW n2T = r2.aStart.Row();
+ SCROW n2B = r2.aEnd.Row();
+
+ // 3) r1 and r2 have equal upper and lower border
+ if( (n1T == n2T) && (n1B == n2B) )
+ {
+ // check that r1 overlaps or touches r2
+ if( ((n1L < n2L) && (n2L - 1 <= n1R)) || ((n2L < n1L) && (n1L - 1 <= n2R)) )
+ {
+ r1.aStart.SetCol( ::std::min( n1L, n2L ) );
+ r1.aEnd.SetCol( ::std::max( n1R, n2R ) );
+ return true;
+ }
+ return false;
+ }
+
+ // 4) r1 and r2 have equal left and right border
+ if( (n1L == n2L) && (n1R == n2R) )
+ {
+ // check that r1 overlaps or touches r2
+ if( ((n1T < n2T) && (n2T + 1 <= n1B)) || ((n2T < n1T) && (n1T + 1 <= n2B)) )
+ {
+ r1.aStart.SetRow( ::std::min( n1T, n2T ) );
+ r1.aEnd.SetRow( ::std::max( n1B, n2B ) );
+ return true;
+ }
+ return false;
+ }
+
+ // 5) cannot join these ranges
+ return false;
+}
+
+/** Strips out ranges that are contained by other ranges, joins ranges that can be joined
+ together (aligned borders, e.g. A4:D10 and B4:E10 would be combined to A4:E10. */
+void lclJoinRanges( ListOfScRange& rList )
+{
+ ListOfScRange::iterator aOuterIt = rList.begin();
+ while( aOuterIt != rList.end() )
+ {
+ bool bAnyErased = false; // true = any range erased from rList
+ ListOfScRange::iterator aInnerIt = rList.begin();
+ while( aInnerIt != rList.end() )
+ {
+ bool bInnerErased = false; // true = aInnerIt erased from rList
+ // do not compare a range with itself
+ if( (aOuterIt != aInnerIt) && lclTryJoin( *aOuterIt, *aInnerIt ) )
+ {
+ // aOuterIt points to joined range, aInnerIt will be removed
+ aInnerIt = rList.erase( aInnerIt );
+ bInnerErased = bAnyErased = true;
+ }
+ /* If aInnerIt has been erased from rList, it already points to
+ the next element (return value of list::erase()). */
+ if( !bInnerErased )
+ ++aInnerIt;
+ }
+ // if any range has been erased, repeat outer loop with the same range
+ if( !bAnyErased )
+ ++aOuterIt;
+ }
+}
+
+/** Intersects the passed list with all ranges of a VBA Range object in the passed Any.
+
+ @throws script::BasicErrorException
+ @throws uno::RuntimeException
+*/
+void lclIntersectRanges( ListOfScRange& rList, const uno::Any& rArg )
+{
+ // extract the ranges from the passed argument, will throw on invalid data
+ ListOfScRange aList2;
+ lclAddToListOfScRange( aList2, rArg );
+ // do nothing, if the passed list is already empty
+ if( rList.empty() || aList2.empty() )
+ return;
+
+ // save original list in a local
+ ListOfScRange aList1;
+ aList1.swap( rList );
+ // join ranges from passed argument
+ lclJoinRanges( aList2 );
+ // calculate intersection of the ranges in both lists
+ for( const auto& rOuterItem : aList1 )
+ {
+ for( const auto& rInnerItem : aList2 )
+ {
+ if( rOuterItem.Intersects( rInnerItem ) )
+ {
+ ScRange aIsectRange(
+ std::max( rOuterItem.aStart.Col(), rInnerItem.aStart.Col() ),
+ std::max( rOuterItem.aStart.Row(), rInnerItem.aStart.Row() ),
+ std::max( rOuterItem.aStart.Tab(), rInnerItem.aStart.Tab() ),
+ std::min( rOuterItem.aEnd.Col(), rInnerItem.aEnd.Col() ),
+ std::min( rOuterItem.aEnd.Row(), rInnerItem.aEnd.Row() ),
+ std::min( rOuterItem.aEnd.Tab(), rInnerItem.aEnd.Tab() ) );
+ rList.push_back( aIsectRange );
+ }
+ }
+ }
+ // again, join the result ranges
+ lclJoinRanges( rList );
+}
+
+/** Creates a VBA Range object from the passed list of ranges.
+
+ @throws uno::RuntimeException
+*/
+uno::Reference< excel::XRange > lclCreateVbaRange(
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< frame::XModel >& rxModel,
+ const ListOfScRange& rList )
+{
+ ScDocShell* pDocShell = excel::getDocShell( rxModel );
+ if( !pDocShell ) throw uno::RuntimeException();
+
+ ScRangeList aCellRanges;
+ for( const auto& rItem : rList )
+ aCellRanges.push_back( rItem );
+
+ if( aCellRanges.size() == 1 )
+ {
+ uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pDocShell, aCellRanges.front() ) );
+ return new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), rxContext, xRange );
+ }
+ if( aCellRanges.size() > 1 )
+ {
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDocShell, aCellRanges ) );
+ return new ScVbaRange( excel::getUnoSheetModuleObj( xRanges ), rxContext, xRanges );
+ }
+ return nullptr;
+}
+
+} // namespace
+
+uno::Reference< excel::XRange > SAL_CALL ScVbaApplication::Intersect(
+ const uno::Reference< excel::XRange >& rArg1, const uno::Reference< excel::XRange >& rArg2,
+ const uno::Any& rArg3, const uno::Any& rArg4, const uno::Any& rArg5, const uno::Any& rArg6,
+ const uno::Any& rArg7, const uno::Any& rArg8, const uno::Any& rArg9, const uno::Any& rArg10,
+ const uno::Any& rArg11, const uno::Any& rArg12, const uno::Any& rArg13, const uno::Any& rArg14,
+ const uno::Any& rArg15, const uno::Any& rArg16, const uno::Any& rArg17, const uno::Any& rArg18,
+ const uno::Any& rArg19, const uno::Any& rArg20, const uno::Any& rArg21, const uno::Any& rArg22,
+ const uno::Any& rArg23, const uno::Any& rArg24, const uno::Any& rArg25, const uno::Any& rArg26,
+ const uno::Any& rArg27, const uno::Any& rArg28, const uno::Any& rArg29, const uno::Any& rArg30 )
+{
+ if( !rArg1.is() || !rArg2.is() )
+ DebugHelper::basicexception( ERRCODE_BASIC_BAD_PARAMETER, {} );
+
+ // initialize the result list with 1st parameter, join its ranges together
+ ListOfScRange aList;
+ lclAddToListOfScRange( aList, uno::Any( rArg1 ) );
+ lclJoinRanges( aList );
+
+ // process all other parameters, this updates the list with intersection
+ lclIntersectRanges( aList, uno::Any( rArg2 ) );
+ lclIntersectRanges( aList, rArg3 );
+ lclIntersectRanges( aList, rArg4 );
+ lclIntersectRanges( aList, rArg5 );
+ lclIntersectRanges( aList, rArg6 );
+ lclIntersectRanges( aList, rArg7 );
+ lclIntersectRanges( aList, rArg8 );
+ lclIntersectRanges( aList, rArg9 );
+ lclIntersectRanges( aList, rArg10 );
+ lclIntersectRanges( aList, rArg11 );
+ lclIntersectRanges( aList, rArg12 );
+ lclIntersectRanges( aList, rArg13 );
+ lclIntersectRanges( aList, rArg14 );
+ lclIntersectRanges( aList, rArg15 );
+ lclIntersectRanges( aList, rArg16 );
+ lclIntersectRanges( aList, rArg17 );
+ lclIntersectRanges( aList, rArg18 );
+ lclIntersectRanges( aList, rArg19 );
+ lclIntersectRanges( aList, rArg20 );
+ lclIntersectRanges( aList, rArg21 );
+ lclIntersectRanges( aList, rArg22 );
+ lclIntersectRanges( aList, rArg23 );
+ lclIntersectRanges( aList, rArg24 );
+ lclIntersectRanges( aList, rArg25 );
+ lclIntersectRanges( aList, rArg26 );
+ lclIntersectRanges( aList, rArg27 );
+ lclIntersectRanges( aList, rArg28 );
+ lclIntersectRanges( aList, rArg29 );
+ lclIntersectRanges( aList, rArg30 );
+
+ // create the VBA Range object
+ return lclCreateVbaRange( mxContext, getCurrentDocument(), aList );
+}
+
+uno::Reference< excel::XRange > SAL_CALL ScVbaApplication::Union(
+ const uno::Reference< excel::XRange >& rArg1, const uno::Reference< excel::XRange >& rArg2,
+ const uno::Any& rArg3, const uno::Any& rArg4, const uno::Any& rArg5, const uno::Any& rArg6,
+ const uno::Any& rArg7, const uno::Any& rArg8, const uno::Any& rArg9, const uno::Any& rArg10,
+ const uno::Any& rArg11, const uno::Any& rArg12, const uno::Any& rArg13, const uno::Any& rArg14,
+ const uno::Any& rArg15, const uno::Any& rArg16, const uno::Any& rArg17, const uno::Any& rArg18,
+ const uno::Any& rArg19, const uno::Any& rArg20, const uno::Any& rArg21, const uno::Any& rArg22,
+ const uno::Any& rArg23, const uno::Any& rArg24, const uno::Any& rArg25, const uno::Any& rArg26,
+ const uno::Any& rArg27, const uno::Any& rArg28, const uno::Any& rArg29, const uno::Any& rArg30 )
+{
+ if( !rArg1.is() || !rArg2.is() )
+ DebugHelper::basicexception( ERRCODE_BASIC_BAD_PARAMETER, {} );
+
+ ListOfScRange aList;
+ lclAddToListOfScRange( aList, uno::Any( rArg1 ) );
+ lclAddToListOfScRange( aList, uno::Any( rArg2 ) );
+ lclAddToListOfScRange( aList, rArg3 );
+ lclAddToListOfScRange( aList, rArg4 );
+ lclAddToListOfScRange( aList, rArg5 );
+ lclAddToListOfScRange( aList, rArg6 );
+ lclAddToListOfScRange( aList, rArg7 );
+ lclAddToListOfScRange( aList, rArg8 );
+ lclAddToListOfScRange( aList, rArg9 );
+ lclAddToListOfScRange( aList, rArg10 );
+ lclAddToListOfScRange( aList, rArg11 );
+ lclAddToListOfScRange( aList, rArg12 );
+ lclAddToListOfScRange( aList, rArg13 );
+ lclAddToListOfScRange( aList, rArg14 );
+ lclAddToListOfScRange( aList, rArg15 );
+ lclAddToListOfScRange( aList, rArg16 );
+ lclAddToListOfScRange( aList, rArg17 );
+ lclAddToListOfScRange( aList, rArg18 );
+ lclAddToListOfScRange( aList, rArg19 );
+ lclAddToListOfScRange( aList, rArg20 );
+ lclAddToListOfScRange( aList, rArg21 );
+ lclAddToListOfScRange( aList, rArg22 );
+ lclAddToListOfScRange( aList, rArg23 );
+ lclAddToListOfScRange( aList, rArg24 );
+ lclAddToListOfScRange( aList, rArg25 );
+ lclAddToListOfScRange( aList, rArg26 );
+ lclAddToListOfScRange( aList, rArg27 );
+ lclAddToListOfScRange( aList, rArg28 );
+ lclAddToListOfScRange( aList, rArg29 );
+ lclAddToListOfScRange( aList, rArg30 );
+
+ // simply join together all ranges as much as possible, strip out covered ranges etc.
+ lclJoinRanges( aList );
+
+ // create the VBA Range object
+ return lclCreateVbaRange( mxContext, getCurrentDocument(), aList );
+}
+
+double
+ScVbaApplication::InchesToPoints( double Inches )
+{
+ double result = Inches * 72.0;
+ return result;
+}
+
+void
+ScVbaApplication::Volatile( const uno::Any& aVolatile )
+{
+ bool bVolatile = true;
+ aVolatile >>= bVolatile;
+ SbMethod* pMeth = StarBASIC::GetActiveMethod();
+ if ( pMeth )
+ {
+ uno::Reference< frame::XModel > xModel( getCurrentDocument() );
+ ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument();
+ rDoc.GetMacroManager()->SetUserFuncVolatile( pMeth->GetName(), bVolatile);
+ }
+
+// this is bound to break when loading the document
+}
+
+sal_Bool SAL_CALL
+ScVbaApplication::getDisplayFormulaBar()
+{
+ bool bRes = false;
+ ScTabViewShell* pViewShell = excel::getCurrentBestViewShell( mxContext );
+ if ( pViewShell )
+ {
+ SfxBoolItem sfxFormBar( FID_TOGGLEINPUTLINE);
+ SfxAllItemSet reqList( SfxGetpApp()->GetPool() );
+ reqList.Put( sfxFormBar );
+
+ pViewShell->GetState( reqList );
+ if ( const SfxBoolItem *pItem = reqList.GetItemIfSet( FID_TOGGLEINPUTLINE, false ) )
+ bRes = pItem->GetValue();
+ }
+ return bRes;
+}
+
+void SAL_CALL
+ScVbaApplication::setDisplayFormulaBar( sal_Bool _displayformulabar )
+{
+ ScTabViewShell* pViewShell = excel::getCurrentBestViewShell( mxContext );
+ if ( pViewShell && ( _displayformulabar != getDisplayFormulaBar() ) )
+ {
+ SfxAllItemSet reqList( SfxGetpApp()->GetPool() );
+ SfxRequest aReq( FID_TOGGLEINPUTLINE, SfxCallMode::SLOT, reqList );
+ pViewShell->Execute( aReq );
+ }
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::Caller( const uno::Any& /*aIndex*/ )
+{
+ StarBASIC* pBasic = SfxApplication::GetBasic();
+ SbMethod* pMeth = static_cast<SbMethod*>(pBasic->GetRtl()->Find( "FuncCaller", SbxClassType::Method ));
+ uno::Any aRet;
+ if ( pMeth )
+ {
+ SbxVariableRef refTemp = pMeth;
+ // forces a broadcast
+ SbxVariableRef pNew = new SbxMethod( *static_cast<SbxMethod*>(pMeth));
+ aRet = sbxToUnoValue( pNew.get() );
+ }
+ return aRet;
+}
+
+uno::Reference< frame::XModel >
+ScVbaApplication::getCurrentDocument()
+{
+ return getCurrentExcelDoc(mxContext);
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::MenuBars( const uno::Any& aIndex )
+{
+ uno::Reference< XCommandBars > xCommandBars( CommandBars( uno::Any() ), uno::UNO_QUERY_THROW );
+ uno::Reference< XCollection > xMenuBars( new ScVbaMenuBars( this, mxContext, xCommandBars ) );
+ if ( aIndex.hasValue() )
+ {
+ return xMenuBars->Item( aIndex, uno::Any() );
+ }
+
+ return uno::Any( xMenuBars );
+}
+
+uno::Any SAL_CALL
+ScVbaApplication::Rows( const uno::Any& aIndex )
+{
+ uno::Reference< excel::XWorksheet > xWorksheet = getActiveSheet();
+ if ( xWorksheet.is() )
+ return uno::Any( xWorksheet->Rows( aIndex ) );
+ return uno::Any();
+}
+
+void SAL_CALL ScVbaApplication::OnKey( const OUString& Key, const uno::Any& Procedure )
+{
+ try
+ {
+ // Perhaps we can catch some excel specific
+ // related behaviour here
+ VbaApplicationBase::OnKey( Key, Procedure );
+ }
+ catch( container::NoSuchElementException& )
+ {
+ // #TODO special handling for unhandled
+ // bindings
+ }
+}
+
+void SAL_CALL ScVbaApplication::setScreenUpdating(sal_Bool bUpdate)
+{
+ VbaApplicationBase::setScreenUpdating( bUpdate );
+
+ uno::Reference< frame::XModel > xModel( getCurrentExcelDoc( mxContext ), uno::UNO_SET_THROW );
+ ScDocShell* pDocShell = excel::getDocShell( xModel );
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ if( bUpdate )
+ {
+ // Since setting ScreenUpdating from user code might be unpaired, avoid calling function,
+ // that asserts correct lock/unlock order and number, when not locked.
+ if(rDoc.IsAdjustHeightLocked())
+ rDoc.UnlockAdjustHeight();
+ if( !rDoc.IsAdjustHeightLocked() )
+ pDocShell->UpdateAllRowHeights();
+ }
+ else
+ {
+ rDoc.LockAdjustHeight();
+ }
+}
+
+void SAL_CALL ScVbaApplication::Undo()
+{
+ uno::Reference< frame::XModel > xModel( getThisExcelDoc( mxContext ), uno::UNO_SET_THROW );
+
+ ScTabViewShell* pViewShell = excel::getBestViewShell( xModel );
+ if ( pViewShell )
+ dispatchExecute( pViewShell, SID_UNDO );
+}
+
+// XInterfaceWithIID
+
+OUString SAL_CALL
+ScVbaApplication::getIID()
+{
+ return "{82154425-0FBF-11d4-8313-005004526AB4}";
+}
+
+// XConnectable
+
+OUString SAL_CALL
+ScVbaApplication::GetIIDForClassItselfNotCoclass()
+{
+ return "{82154426-0FBF-11D4-8313-005004526AB4}";
+}
+
+TypeAndIID SAL_CALL
+ScVbaApplication::GetConnectionPoint()
+{
+ TypeAndIID aResult =
+ { excel::XApplicationOutgoing::static_type(),
+ "{82154427-0FBF-11D4-8313-005004526AB4}"
+ };
+
+ return aResult;
+}
+
+uno::Reference<XConnectionPoint> SAL_CALL
+ScVbaApplication::FindConnectionPoint()
+{
+ uno::Reference<XConnectionPoint> xCP(new ScVbaApplicationOutgoingConnectionPoint(this));
+ return xCP;
+}
+
+// XSinkCaller
+
+void SAL_CALL
+ScVbaApplication::CallSinks( const OUString& Method, uno::Sequence< uno::Any >& Arguments )
+{
+ for (auto& i : mvSinks)
+ {
+ if (i.is())
+ i->Call(Method, Arguments);
+ }
+}
+
+OUString
+ScVbaApplication::getServiceImplName()
+{
+ return "ScVbaApplication";
+}
+
+uno::Sequence< OUString >
+ScVbaApplication::getServiceNames()
+{
+ static uno::Sequence< OUString > aServiceNames
+ {
+ "ooo.vba.excel.Application"
+ };
+ return aServiceNames;
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_ScVbaApplication_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new ScVbaApplication(context));
+}
+
+
+// ScVbaApplicationOutgoingConnectionPoint
+
+ScVbaApplicationOutgoingConnectionPoint::ScVbaApplicationOutgoingConnectionPoint( ScVbaApplication* pApp ) :
+ mpApp(pApp)
+{
+}
+
+// XConnectionPoint
+sal_uInt32 SAL_CALL
+ScVbaApplicationOutgoingConnectionPoint::Advise( const uno::Reference< XSink >& Sink )
+{
+ return mpApp->AddSink(Sink);
+}
+
+void SAL_CALL
+ScVbaApplicationOutgoingConnectionPoint::Unadvise( sal_uInt32 Cookie )
+{
+ mpApp->RemoveSink( Cookie );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaapplication.hxx b/sc/source/ui/vba/vbaapplication.hxx
new file mode 100644
index 000000000..db9c91cdd
--- /dev/null
+++ b/sc/source/ui/vba/vbaapplication.hxx
@@ -0,0 +1,168 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <vector>
+
+#include <ooo/vba/XSinkCaller.hpp>
+#include <ooo/vba/excel/XApplication.hpp>
+
+#include <vbahelper/vbaapplicationbase.hxx>
+#include <cppuhelper/implbase.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace ooo::vba { class XSink; }
+namespace ooo::vba::excel { class XFileDialog; }
+
+typedef cppu::ImplInheritanceHelper< VbaApplicationBase, ov::excel::XApplication, ov::XSinkCaller > ScVbaApplication_BASE;
+
+struct ScVbaAppSettings;
+
+class ScVbaApplication : public ScVbaApplication_BASE
+{
+private:
+ // note: member variables moved to struct "ScVbaAppSettings", see cxx file, to be shared by all application instances
+ ScVbaAppSettings& mrAppSettings;
+
+ // must be stored in order to get result paths from the same instance
+ css::uno::Reference< ov::excel::XFileDialog > m_xFileDialog;
+ sal_Int32 m_nDialogType;
+
+ /// @throws css::uno::RuntimeException
+ OUString getOfficePath( const OUString& sPath );
+
+ std::vector<css::uno::Reference< ooo::vba::XSink >> mvSinks;
+
+protected:
+ virtual css::uno::Reference< css::frame::XModel > getCurrentDocument() override;
+
+public:
+ explicit ScVbaApplication( const css::uno::Reference< css::uno::XComponentContext >& m_xContext );
+ virtual ~ScVbaApplication() override;
+
+ /** Returns true, if VBA document events are enabled. */
+ static bool getDocumentEventsEnabled();
+
+ sal_uInt32 AddSink( const css::uno::Reference< ooo::vba::XSink >& xSink );
+ void RemoveSink( sal_uInt32 nNumber );
+
+ // XExactName
+ virtual OUString SAL_CALL getExactName( const OUString& aApproximateName ) override;
+
+ // XInvocation
+ virtual css::uno::Reference< css::beans::XIntrospectionAccess > SAL_CALL getIntrospection() override;
+ virtual css::uno::Any SAL_CALL invoke(const OUString& FunctionName, const css::uno::Sequence< css::uno::Any >& Params, css::uno::Sequence< sal_Int16 >& OutParamIndex, css::uno::Sequence< css::uno::Any >& OutParam) override;
+ virtual void SAL_CALL setValue(const OUString& PropertyName, const css::uno::Any& Value) override;
+ virtual css::uno::Any SAL_CALL getValue(const OUString& PropertyName) override;
+ virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override;
+ virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override;
+
+ // XApplication
+ virtual void SAL_CALL setDefaultFilePath( const OUString& DefaultFilePath ) override;
+ virtual OUString SAL_CALL getDefaultFilePath() override;
+ virtual OUString SAL_CALL getPathSeparator() override;
+ virtual OUString SAL_CALL getLibraryPath() override;
+ virtual OUString SAL_CALL getTemplatesPath() override;
+ virtual OUString SAL_CALL getOperatingSystem() override;
+
+ virtual OUString SAL_CALL getName() override;
+ virtual sal_Bool SAL_CALL getDisplayAlerts() override;
+ virtual void SAL_CALL setDisplayAlerts( sal_Bool displayAlerts ) override;
+ virtual ::sal_Int32 SAL_CALL getCalculation() override;
+ virtual void SAL_CALL setCalculation( ::sal_Int32 _calculation ) override;
+ virtual css::uno::Any SAL_CALL getSelection() override;
+ virtual css::uno::Reference< ov::excel::XWorkbook > SAL_CALL getActiveWorkbook() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getActiveCell() override;
+ virtual css::uno::Reference< ov::excel::XWindow > SAL_CALL getActiveWindow() override;
+ virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getActiveSheet() override;
+ virtual sal_Bool SAL_CALL getDisplayFormulaBar() override;
+ virtual void SAL_CALL setDisplayFormulaBar(sal_Bool _displayformulabar) override;
+
+ virtual css::uno::Reference< ov::XAssistant > SAL_CALL getAssistant() override;
+ virtual css::uno::Reference< ov::excel::XWorkbook > SAL_CALL getThisWorkbook() override;
+
+ virtual css::uno::Any SAL_CALL GetOpenFilename(const css::uno::Any& FileFilter, const css::uno::Any& FilterIndex, const css::uno::Any& Title, const css::uno::Any& ButtonText, const css::uno::Any& MultiSelect) override;
+ virtual css::uno::Any SAL_CALL International( sal_Int32 Index ) override;
+ virtual css::uno::Any SAL_CALL FileDialog( const css::uno::Any& DialogType ) override;
+ virtual css::uno::Any SAL_CALL Workbooks( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL Worksheets( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL WorksheetFunction( ) override;
+ virtual css::uno::Any SAL_CALL Evaluate( const OUString& Name ) override;
+ virtual css::uno::Any SAL_CALL Dialogs( const css::uno::Any& DialogIndex ) override;
+ virtual css::uno::Any SAL_CALL getCutCopyMode() override;
+ virtual void SAL_CALL setCutCopyMode( const css::uno::Any& _cutcopymode ) override;
+ virtual css::uno::Any SAL_CALL getStatusBar() override;
+ virtual void SAL_CALL setStatusBar( const css::uno::Any& _statusbar ) override;
+ virtual css::uno::Any SAL_CALL getWindowState() override;
+ virtual void SAL_CALL setWindowState(const css::uno::Any& rWindowState) override;
+ virtual ::sal_Int32 SAL_CALL getCursor() override;
+ virtual void SAL_CALL setCursor( ::sal_Int32 _cursor ) override;
+ virtual void SAL_CALL OnKey( const OUString& Key, const css::uno::Any& Procedure ) override;
+ virtual void SAL_CALL setScreenUpdating( sal_Bool bUpdate ) override;
+ virtual sal_Bool SAL_CALL getEnableEvents() override;
+ virtual void SAL_CALL setEnableEvents( sal_Bool bEnable ) override;
+ virtual sal_Bool SAL_CALL getEnableCancelKey() override;
+ virtual void SAL_CALL setEnableCancelKey( sal_Bool bEnable ) override;
+
+ virtual sal_Bool SAL_CALL getDisplayFullScreen() override;
+ virtual void SAL_CALL setDisplayFullScreen( sal_Bool bSet ) override;
+ virtual sal_Bool SAL_CALL getDisplayScrollBars() override;
+ virtual void SAL_CALL setDisplayScrollBars( sal_Bool bSet ) override;
+ virtual sal_Bool SAL_CALL getDisplayExcel4Menus() override;
+ virtual void SAL_CALL setDisplayExcel4Menus( sal_Bool bSet ) override;
+
+ virtual sal_Bool SAL_CALL getDisplayNoteIndicator() override;
+ virtual void SAL_CALL setDisplayNoteIndicator( sal_Bool bSet ) override;
+ virtual sal_Bool SAL_CALL getShowWindowsInTaskbar() override;
+ virtual void SAL_CALL setShowWindowsInTaskbar( sal_Bool bSet ) override;
+ virtual sal_Bool SAL_CALL getIteration() override;
+ virtual void SAL_CALL setIteration( sal_Bool bSet ) override;
+
+ virtual css::uno::Any SAL_CALL Windows( const css::uno::Any& aIndex ) override;
+ virtual void SAL_CALL wait( double time ) override;
+ virtual css::uno::Any SAL_CALL Range( const css::uno::Any& Cell1, const css::uno::Any& Cell2 ) override;
+ virtual css::uno::Any SAL_CALL Names( const css::uno::Any& aIndex ) override;
+ virtual void SAL_CALL GoTo( const css::uno::Any& Reference, const css::uno::Any& Scroll ) override;
+ virtual void SAL_CALL Calculate() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Intersect( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Union( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 ) override;
+ virtual double SAL_CALL InchesToPoints( double InchesToPoints ) override;
+ virtual void SAL_CALL Volatile( const css::uno::Any& Volatile ) override;
+ virtual css::uno::Any SAL_CALL MenuBars( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL Rows( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL Caller( const css::uno::Any& aIndex ) override;
+ virtual void SAL_CALL Undo() override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+ // XInterfaceWithIID
+ virtual OUString SAL_CALL getIID() override;
+
+ // XConnectable
+ virtual OUString SAL_CALL GetIIDForClassItselfNotCoclass() override;
+ virtual ov::TypeAndIID SAL_CALL GetConnectionPoint() override;
+ virtual css::uno::Reference<ov::XConnectionPoint> SAL_CALL FindConnectionPoint() override;
+
+ // XSinkCaller
+ virtual void SAL_CALL CallSinks( const OUString& Method, css::uno::Sequence< css::uno::Any >& Arguments ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaassistant.cxx b/sc/source/ui/vba/vbaassistant.cxx
new file mode 100644
index 000000000..ea13fbcd6
--- /dev/null
+++ b/sc/source/ui/vba/vbaassistant.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 <ooo/vba/office/MsoAnimationType.hpp>
+
+#include"vbaassistant.hxx"
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+using namespace ooo::vba::office::MsoAnimationType;
+
+constexpr OUStringLiteral g_sName = u"Clippit";
+
+ScVbaAssistant::ScVbaAssistant( const uno::Reference< XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext ): ScVbaAssistantImpl_BASE(rParent, rContext)
+{
+ m_bIsVisible = false;
+ m_nPointsLeft = 795;
+ m_nPointsTop = 248;
+ m_nAnimation = msoAnimationIdle;
+}
+
+ScVbaAssistant::~ScVbaAssistant()
+{
+}
+
+sal_Bool SAL_CALL ScVbaAssistant::getVisible()
+{
+ return m_bIsVisible;
+}
+
+void SAL_CALL ScVbaAssistant::setVisible( sal_Bool bVisible )
+{
+ m_bIsVisible = bVisible;
+}
+
+sal_Bool SAL_CALL ScVbaAssistant::getOn()
+{
+ return false;
+}
+
+void SAL_CALL ScVbaAssistant::setOn( sal_Bool bOn )
+{
+ setVisible( bOn );
+}
+
+::sal_Int32 SAL_CALL
+ScVbaAssistant::getTop()
+{
+ return m_nPointsTop;
+}
+void SAL_CALL
+ScVbaAssistant::setTop( ::sal_Int32 _top )
+{
+ m_nPointsTop = _top;
+}
+::sal_Int32 SAL_CALL
+ScVbaAssistant::getLeft()
+{
+ return m_nPointsLeft;
+}
+void SAL_CALL
+ScVbaAssistant::setLeft( ::sal_Int32 _left )
+{
+ m_nPointsLeft = _left;
+}
+::sal_Int32 SAL_CALL
+ScVbaAssistant::getAnimation()
+{
+ return m_nAnimation;
+}
+void SAL_CALL
+ScVbaAssistant::setAnimation( ::sal_Int32 _animation )
+{
+ m_nAnimation = _animation;
+}
+
+OUString SAL_CALL
+ScVbaAssistant::Name( )
+{
+ return g_sName;
+}
+
+OUString
+ScVbaAssistant::getServiceImplName()
+{
+ return "ScVbaAssistant";
+}
+
+uno::Sequence< OUString >
+ScVbaAssistant::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.Assistant"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaassistant.hxx b/sc/source/ui/vba/vbaassistant.hxx
new file mode 100644
index 000000000..674e64445
--- /dev/null
+++ b/sc/source/ui/vba/vbaassistant.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 <cppuhelper/implbase.hxx>
+#include <ooo/vba/XAssistant.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+typedef ::cppu::WeakImplHelper< ov::XAssistant > Assistant;
+typedef InheritedHelperInterfaceImpl< Assistant > ScVbaAssistantImpl_BASE;
+
+class ScVbaAssistant : public ScVbaAssistantImpl_BASE
+{
+private:
+ bool m_bIsVisible;
+ sal_Int32 m_nPointsLeft;
+ sal_Int32 m_nPointsTop;
+ sal_Int32 m_nAnimation;
+public:
+ ScVbaAssistant( const css::uno::Reference< ov::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext );
+ virtual ~ScVbaAssistant() override;
+ // XAssistant
+ virtual sal_Bool SAL_CALL getOn() override;
+ virtual void SAL_CALL setOn( sal_Bool _on ) override;
+ virtual sal_Bool SAL_CALL getVisible() override;
+ virtual void SAL_CALL setVisible( sal_Bool _visible ) override;
+ virtual ::sal_Int32 SAL_CALL getTop() override;
+ virtual void SAL_CALL setTop( ::sal_Int32 _top ) override;
+ virtual ::sal_Int32 SAL_CALL getLeft() override;
+ virtual void SAL_CALL setLeft( ::sal_Int32 _left ) override;
+ virtual ::sal_Int32 SAL_CALL getAnimation() override;
+ virtual void SAL_CALL setAnimation( ::sal_Int32 _animation ) override;
+
+ virtual OUString SAL_CALL Name( ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaaxes.cxx b/sc/source/ui/vba/vbaaxes.cxx
new file mode 100644
index 000000000..c295158b7
--- /dev/null
+++ b/sc/source/ui/vba/vbaaxes.cxx
@@ -0,0 +1,211 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "vbaaxes.hxx"
+#include "vbaaxis.hxx"
+#include "vbachart.hxx"
+#include <basic/sberrors.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/script/BasicErrorException.hpp>
+#include <ooo/vba/excel/XlAxisType.hpp>
+#include <ooo/vba/excel/XlAxisGroup.hpp>
+#include <ooo/vba/excel/XAxis.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+using namespace ::ooo::vba::excel::XlAxisType;
+using namespace ::ooo::vba::excel::XlAxisGroup;
+
+// each 'Item' in the Axes collection is indexed via 2 indexes, group and type.
+// We need to 'flatten' this into a single index in order to be able to wrap
+// iteration over the set of Axis(s) in a XIndexAccess implementation
+
+typedef ::std::pair<sal_Int32, sal_Int32 > AxesCoordinate; // type and group combination
+
+namespace {
+
+class EnumWrapper : public EnumerationHelper_BASE
+{
+ uno::Reference<container::XIndexAccess > m_xIndexAccess;
+ sal_Int32 nIndex;
+public:
+ explicit EnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess ) : m_xIndexAccess( xIndexAccess ), nIndex( 0 ) {}
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override
+ {
+ return ( nIndex < m_xIndexAccess->getCount() );
+ }
+
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ if ( nIndex < m_xIndexAccess->getCount() )
+ return m_xIndexAccess->getByIndex( nIndex++ );
+ throw container::NoSuchElementException();
+ }
+};
+
+}
+
+uno::Reference< excel::XAxis >
+ScVbaAxes::createAxis( const uno::Reference< excel::XChart >& xChart, const uno::Reference< uno::XComponentContext >& xContext, sal_Int32 nType, sal_Int32 nAxisGroup )
+{
+ ScVbaChart* pChart = static_cast< ScVbaChart* >( xChart.get() );
+ if ( !pChart )
+ throw uno::RuntimeException("Object failure, can't access chart implementation" );
+
+ uno::Reference< beans::XPropertySet > xAxisPropertySet;
+ if ((nType == xlCategory) || (nType == xlSeriesAxis) || (nType == xlValue))
+ {
+ if ((nAxisGroup != xlPrimary) && (nAxisGroup != xlSecondary))
+ DebugHelper::runtimeexception(ERRCODE_BASIC_METHOD_FAILED);
+ xAxisPropertySet.set( pChart->getAxisPropertySet(nType, nAxisGroup), uno::UNO_SET_THROW );
+ }
+ else
+ DebugHelper::runtimeexception(ERRCODE_BASIC_METHOD_FAILED);
+ uno::Reference< XHelperInterface > xParent( xChart, uno::UNO_QUERY_THROW );
+ return new ScVbaAxis( xParent, xContext, xAxisPropertySet, nType, nAxisGroup);
+}
+
+namespace {
+
+class AxisIndexWrapper : public ::cppu::WeakImplHelper< container::XIndexAccess >
+{
+ // if necessary for better performance we could change this into a map and cache the
+ // indices -> Axis, currently we create a new Axis object
+ // on each getByIndex
+ uno::Reference< uno::XComponentContext > mxContext;
+ std::vector< AxesCoordinate > mCoordinates;
+ uno::Reference< excel::XChart > mxChart;
+public:
+ AxisIndexWrapper( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< excel::XChart >& xChart ) : mxContext( xContext ), mxChart( xChart )
+ {
+ if ( !mxChart.is() )
+ return;
+
+ ScVbaChart* pChart = static_cast< ScVbaChart* >( mxChart.get() );
+ // primary
+ bool bBool = false;
+ uno::Reference< beans::XPropertySet > xDiagramPropertySet( pChart->xDiagramPropertySet() );
+ if ( ( xDiagramPropertySet->getPropertyValue("HasXAxis") >>= bBool ) && bBool )
+ mCoordinates.emplace_back( xlPrimary, xlCategory );
+ if ( ( xDiagramPropertySet->getPropertyValue("HasYAxis") >>= bBool ) && bBool )
+ mCoordinates.emplace_back( xlPrimary, xlSeriesAxis );
+
+ if ( pChart->is3D() )
+ mCoordinates.emplace_back( xlPrimary, xlValue );
+
+ // secondary
+ if ( ( xDiagramPropertySet->getPropertyValue("HasSecondaryXAxis") >>= bBool ) && bBool )
+ mCoordinates.emplace_back( xlSecondary, xlCategory );
+ if ( ( xDiagramPropertySet->getPropertyValue("HasSecondaryYAxis") >>= bBool ) && bBool )
+ mCoordinates.emplace_back( xlSecondary, xlSeriesAxis );
+
+ }
+ virtual ::sal_Int32 SAL_CALL getCount() override { return mCoordinates.size(); }
+ virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
+ {
+ try
+ {
+ AxesCoordinate dIndexes = mCoordinates[ Index ];
+ return uno::Any( ScVbaAxes::createAxis( mxChart, mxContext, dIndexes.second, dIndexes.first ) );
+ }
+ catch (const css::script::BasicErrorException&)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetException(
+ "Error Getting Index!",
+ static_cast < OWeakObject * > ( this ),
+ anyEx );
+ }
+ }
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override
+ {
+ return cppu::UnoType<excel::XAxis>::get();
+ }
+ virtual sal_Bool SAL_CALL hasElements( ) override
+ {
+ return ( !mCoordinates.empty() );
+ }
+};
+
+uno::Reference< container::XIndexAccess > createIndexWrapper( const uno::Reference< excel::XChart >& xChart, const uno::Reference< uno::XComponentContext >& xContext )
+{
+ return new AxisIndexWrapper( xContext, xChart );
+}
+
+}
+
+// #FIXME The collection semantics will never work as this object is not yet initialised correctly
+ScVbaAxes::ScVbaAxes( const uno::Reference< XHelperInterface >& xParent,const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< excel::XChart >& xChart ) : ScVbaAxes_BASE( xParent, xContext, createIndexWrapper( xChart, xContext )), moChartParent( xChart )
+{
+}
+
+uno::Type SAL_CALL
+ScVbaAxes::getElementType()
+{
+ return cppu::UnoType<excel::XAxes>::get();
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL
+ScVbaAxes::createEnumeration()
+{
+ return new EnumWrapper( m_xIndexAccess );
+}
+
+uno::Any SAL_CALL
+ScVbaAxes::Item( const css::uno::Any& _nType, const css::uno::Any& _oAxisGroup)
+{
+ // #TODO map the possible index combinations to a container::XIndexAccess wrapper impl
+ // using a vector of valid std::pair maybe?
+ // body helper api port bits
+ sal_Int32 nAxisGroup = xlPrimary;
+ sal_Int32 nType = -1;
+ if ( !_nType.hasValue() || !( _nType >>= nType ) )
+ throw uno::RuntimeException("Axes::Item Failed to extract type" );
+
+ if ( _oAxisGroup.hasValue() )
+ _oAxisGroup >>= nAxisGroup ;
+
+ return uno::Any( createAxis( moChartParent, mxContext, nType, nAxisGroup ) );
+}
+
+uno::Any
+ScVbaAxes::createCollectionObject(const css::uno::Any& aSource)
+{
+ return aSource; // pass through ( it's already an XAxis object
+}
+
+OUString
+ScVbaAxes::getServiceImplName()
+{
+ return "ScVbaAxes";
+}
+
+uno::Sequence< OUString >
+ScVbaAxes::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Axes"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaaxes.hxx b/sc/source/ui/vba/vbaaxes.hxx
new file mode 100644
index 000000000..cb7c48a7f
--- /dev/null
+++ b/sc/source/ui/vba/vbaaxes.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 <ooo/vba/excel/XAxes.hpp>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace ooo::vba::excel { class XAxis; }
+namespace ooo::vba::excel { class XChart; }
+
+typedef CollTestImplHelper< ov::excel::XAxes > ScVbaAxes_BASE;
+class ScVbaAxes : public ScVbaAxes_BASE
+{
+ css::uno::Reference< ov::excel::XChart > moChartParent; // not the true parent I guess
+public:
+ ScVbaAxes( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< ov::excel::XChart >& xChart );
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+ // XCollection
+ virtual css::uno::Any SAL_CALL Item( const css::uno::Any& aIndex, const css::uno::Any& aIndex2 ) override;
+ virtual css::uno::Any createCollectionObject(const css::uno::Any&) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+ /// @throws css::uno::RuntimeException
+ /// @throws css::script::BasicErrorException
+ static css::uno::Reference< ov::excel::XAxis > createAxis( const css::uno::Reference< ov::excel::XChart >& xChart, const css::uno::Reference< css::uno::XComponentContext >& xContext, sal_Int32 nType, sal_Int32 nAxisGroup );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaaxis.cxx b/sc/source/ui/vba/vbaaxis.cxx
new file mode 100644
index 000000000..c34649fa5
--- /dev/null
+++ b/sc/source/ui/vba/vbaaxis.cxx
@@ -0,0 +1,656 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "vbaaxis.hxx"
+#include <ooo/vba/excel/XlAxisCrosses.hpp>
+#include <ooo/vba/excel/XlAxisType.hpp>
+#include <ooo/vba/excel/XlScaleType.hpp>
+#include "vbaaxistitle.hxx"
+#include "vbachart.hxx"
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+using namespace ::ooo::vba::excel::XlAxisCrosses;
+using namespace ::ooo::vba::excel::XlAxisType;
+using namespace ::ooo::vba::excel::XlScaleType;
+
+constexpr OUStringLiteral ORIGIN(u"Origin");
+constexpr OUStringLiteral AUTOORIGIN(u"AutoOrigin");
+constexpr OUStringLiteral VBA_MIN(u"Max");
+constexpr OUStringLiteral VBA_MAX(u"Min");
+ScVbaChart*
+ScVbaAxis::getChartPtr()
+{
+ ScVbaChart* pChart = static_cast< ScVbaChart* >( moChartParent.get() );
+ if ( !pChart )
+ throw uno::RuntimeException("Can't access parent chart impl" );
+ return pChart;
+}
+
+bool
+ScVbaAxis::isValueAxis()
+{
+ if ( getType() == xlCategory )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return true;
+}
+
+ScVbaAxis::ScVbaAxis( const uno::Reference< XHelperInterface >& xParent,const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< beans::XPropertySet >& _xPropertySet, sal_Int32 _nType, sal_Int32 _nGroup ) : ScVbaAxis_BASE( xParent, xContext ), mxPropertySet( _xPropertySet ), mnType( _nType ), mnGroup( _nGroup ), bCrossesAreCustomized( false )
+{
+ oShapeHelper.reset( new ShapeHelper( uno::Reference< drawing::XShape >( mxPropertySet, uno::UNO_QUERY ) ) );
+ moChartParent.set( xParent, uno::UNO_QUERY_THROW );
+ setType(_nType);
+ setCrosses(xlAxisCrossesAutomatic);
+}
+
+void SAL_CALL
+ScVbaAxis::Delete( )
+{
+ uno::Reference< lang::XComponent > xComponent( mxPropertySet, uno::UNO_QUERY_THROW );
+ xComponent->dispose();
+}
+
+ uno::Reference< ::ooo::vba::excel::XAxisTitle > SAL_CALL
+ScVbaAxis::getAxisTitle( )
+{
+ uno::Reference< excel::XAxisTitle > xAxisTitle;
+ try
+ {
+ ScVbaChart* pChart = getChartPtr();
+
+ if (getHasTitle() )
+ {
+ int nType = getType();
+ switch(nType)
+ {
+ case xlCategory:
+ xAxisTitle = new ScVbaAxisTitle(this, mxContext, pChart->xAxisXSupplier->getXAxisTitle());
+ break;
+ case xlSeriesAxis:
+ xAxisTitle = new ScVbaAxisTitle(this, mxContext, pChart->xAxisZSupplier->getZAxisTitle());
+ break;
+ default: // xlValue:
+ xAxisTitle = new ScVbaAxisTitle(this, mxContext, pChart->xAxisYSupplier->getYAxisTitle());
+ break;
+ }
+ }
+ }
+ catch (const uno::Exception& e)
+ {
+ DebugHelper::basicexception(e);
+ }
+ return xAxisTitle;
+
+}
+
+void SAL_CALL
+ScVbaAxis::setDisplayUnit( ::sal_Int32 /*DisplayUnit*/ )
+{
+ DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {});
+}
+
+::sal_Int32 SAL_CALL
+ScVbaAxis::getDisplayUnit( )
+{
+ DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {});
+ return -1;
+}
+
+void SAL_CALL
+ScVbaAxis::setCrosses( ::sal_Int32 _nCrosses )
+{
+ try
+ {
+ double fNum = 0.0;
+ switch (_nCrosses)
+ {
+ case xlAxisCrossesAutomatic: //Microsoft Excel sets the axis crossing point.
+ mxPropertySet->setPropertyValue(AUTOORIGIN, uno::Any( true ) );
+ bCrossesAreCustomized = false;
+ return;
+ case xlAxisCrossesMinimum: // The axis crosses at the minimum value.
+ mxPropertySet->getPropertyValue(VBA_MIN) >>= fNum;
+ setCrossesAt( fNum );
+ bCrossesAreCustomized = false;
+ break;
+ case xlAxisCrossesMaximum: // The axis crosses at the maximum value.
+ mxPropertySet->getPropertyValue(VBA_MAX) >>= fNum;
+ setCrossesAt(fNum);
+ bCrossesAreCustomized = false;
+ break;
+ default: //xlAxisCrossesCustom
+ bCrossesAreCustomized = true;
+ break;
+ }
+ mxPropertySet->setPropertyValue(AUTOORIGIN, uno::Any(false) );
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+::sal_Int32 SAL_CALL
+ScVbaAxis::getCrosses( )
+{
+ sal_Int32 nCrosses = xlAxisCrossesCustom;
+ try
+ {
+ bool bisAutoOrigin = false;
+ mxPropertySet->getPropertyValue(AUTOORIGIN) >>= bisAutoOrigin;
+ if (bisAutoOrigin)
+ nCrosses = xlAxisCrossesAutomatic;
+ else
+ {
+ if (bCrossesAreCustomized)
+ nCrosses = xlAxisCrossesCustom;
+ else
+ {
+ double forigin = 0.0;
+ mxPropertySet->getPropertyValue(ORIGIN) >>= forigin;
+ double fmin = 0.0;
+ mxPropertySet->getPropertyValue(VBA_MIN) >>= fmin;
+ if (forigin == fmin)
+ nCrosses = xlAxisCrossesMinimum;
+ else
+ nCrosses = xlAxisCrossesMaximum;
+ }
+ }
+ }
+ catch (uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+ return nCrosses;
+}
+
+ void SAL_CALL
+ScVbaAxis::setCrossesAt( double _fCrossesAt )
+{
+ try
+ {
+ setMaximumScaleIsAuto( false );
+ setMinimumScaleIsAuto( false );
+ mxPropertySet->setPropertyValue(ORIGIN, uno::Any(_fCrossesAt));
+ }
+ catch (const uno::Exception& e)
+ {
+ DebugHelper::basicexception(e);
+ }
+}
+
+ double SAL_CALL
+ScVbaAxis::getCrossesAt( )
+{
+ double fCrosses = 0.0;
+ try
+ {
+ mxPropertySet->getPropertyValue(ORIGIN) >>= fCrosses;
+ }
+ catch (uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return fCrosses;
+}
+
+void SAL_CALL
+ScVbaAxis::setType( ::sal_Int32 _nType )
+{
+ mnType = _nType;
+}
+
+::sal_Int32 SAL_CALL
+ScVbaAxis::getType( )
+{
+ return mnType;
+}
+
+void SAL_CALL
+ScVbaAxis::setHasTitle( sal_Bool _bHasTitle )
+{
+ try
+ {
+ ScVbaChart* pChart = getChartPtr();
+ sal_Int32 nType = getType();
+ switch(nType)
+ {
+ case xlCategory:
+ pChart->mxDiagramPropertySet->setPropertyValue("HasXAxisTitle", uno::Any(_bHasTitle));
+ break;
+ case xlSeriesAxis:
+ pChart->mxDiagramPropertySet->setPropertyValue("HasZAxisTitle", uno::Any(_bHasTitle));
+ break;
+ default: // xlValue:
+ pChart->mxDiagramPropertySet->setPropertyValue("HasYAxisTitle", uno::Any(_bHasTitle));
+ }
+
+ }
+ catch (const uno::Exception& e)
+ {
+ DebugHelper::basicexception(e);
+ }
+}
+
+ sal_Bool SAL_CALL
+ScVbaAxis::getHasTitle( )
+{
+ bool bHasTitle = false;
+ try
+ {
+ ScVbaChart* pChart = getChartPtr();
+ int nType = getType();
+ switch(nType)
+ {
+ case xlCategory:
+ pChart->mxDiagramPropertySet->getPropertyValue("HasXAxisTitle") >>= bHasTitle;
+ break;
+ case xlSeriesAxis:
+ pChart->mxDiagramPropertySet->getPropertyValue("HasZAxisTitle") >>= bHasTitle;
+ break;
+ default: // xlValue:
+ pChart->mxDiagramPropertySet->getPropertyValue("HasYAxisTitle") >>= bHasTitle;
+ }
+ }
+ catch (const uno::Exception& e)
+ {
+ DebugHelper::basicexception(e);
+ }
+ return bHasTitle;
+}
+
+void SAL_CALL
+ScVbaAxis::setMinorUnit( double _fMinorUnit )
+{
+ try
+ {
+ if (isValueAxis())
+ mxPropertySet->setPropertyValue("StepHelp", uno::Any(_fMinorUnit));
+ }
+ catch (uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+double SAL_CALL
+ScVbaAxis::getMinorUnit( )
+{
+ double fMinor = 1.0;
+ try
+ {
+ if (isValueAxis())
+ mxPropertySet->getPropertyValue("StepHelp") >>= fMinor;
+ }
+ catch (uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return fMinor;
+}
+
+void SAL_CALL
+ScVbaAxis::setMinorUnitIsAuto( sal_Bool _bMinorUnitIsAuto )
+{
+ try
+ {
+ if (isValueAxis())
+ mxPropertySet->setPropertyValue("AutoStepHelp", uno::Any(_bMinorUnitIsAuto));
+ }
+ catch (uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+}
+
+ sal_Bool SAL_CALL
+ScVbaAxis::getMinorUnitIsAuto( )
+{
+ bool bIsAuto = false;
+ try
+ {
+ if (isValueAxis())
+ {
+ mxPropertySet->getPropertyValue("AutoStepHelp") >>= bIsAuto;
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return bIsAuto;
+}
+
+void SAL_CALL
+ScVbaAxis::setReversePlotOrder( sal_Bool /*ReversePlotOrder*/ )
+{
+ DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {});
+}
+
+sal_Bool SAL_CALL
+ScVbaAxis::getReversePlotOrder( )
+{
+ DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {});
+ return false;
+}
+
+void SAL_CALL
+ScVbaAxis::setMajorUnit( double _fMajorUnit )
+{
+ try
+ {
+ if (isValueAxis())
+ {
+ mxPropertySet->setPropertyValue("StepMain", uno::Any(_fMajorUnit));
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+double SAL_CALL
+ScVbaAxis::getMajorUnit( )
+{
+ double fMax = 1.0;
+ try
+ {
+ if (isValueAxis())
+ mxPropertySet->getPropertyValue("StepMain") >>= fMax;
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+ return fMax;
+}
+
+void SAL_CALL
+ScVbaAxis::setMajorUnitIsAuto( sal_Bool _bMajorUnitIsAuto )
+{
+ try
+ {
+ if (isValueAxis())
+ {
+ mxPropertySet->setPropertyValue("AutoStepMain", uno::Any( _bMajorUnitIsAuto ));
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+sal_Bool SAL_CALL
+ScVbaAxis::getMajorUnitIsAuto( )
+{
+ bool bIsAuto = false;
+ try
+ {
+ if (isValueAxis())
+ {
+ mxPropertySet->getPropertyValue("AutoStepMain") >>= bIsAuto;
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return bIsAuto;
+}
+
+void SAL_CALL
+ScVbaAxis::setMaximumScale( double _fMaximumScale )
+{
+ try
+ {
+ if ( isValueAxis() )
+ {
+ mxPropertySet->setPropertyValue("Max", uno::Any(_fMaximumScale));
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+double SAL_CALL
+ScVbaAxis::getMaximumScale( )
+{
+ double fMax = 1.0;
+ try
+ {
+ if (isValueAxis())
+ {
+ mxPropertySet->getPropertyValue("Max") >>= fMax;
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return fMax;
+
+}
+
+void SAL_CALL
+ScVbaAxis::setMaximumScaleIsAuto( sal_Bool _bMaximumScaleIsAuto )
+{
+ try
+ {
+ if ( isValueAxis() )
+ mxPropertySet->setPropertyValue("AutoMax", uno::Any( _bMaximumScaleIsAuto ));
+
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+sal_Bool SAL_CALL
+ScVbaAxis::getMaximumScaleIsAuto( )
+{
+ bool bIsAuto = false;
+ try
+ {
+ if (isValueAxis())
+ mxPropertySet->getPropertyValue("AutoMax") >>= bIsAuto;
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception( ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+ return bIsAuto;
+}
+
+void SAL_CALL
+ScVbaAxis::setMinimumScale( double _fMinimumScale )
+{
+ try
+ {
+ if (isValueAxis())
+ mxPropertySet->setPropertyValue("Min", uno::Any( _fMinimumScale ) );
+ }
+ catch ( uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+}
+
+double SAL_CALL
+ScVbaAxis::getMinimumScale( )
+{
+ double fMin = 0.0;
+ try
+ {
+ if (isValueAxis())
+ mxPropertySet->getPropertyValue("Min") >>= fMin;
+ }
+ catch (const uno::Exception& e)
+ {
+ DebugHelper::basicexception(e);
+ }
+ return fMin;
+}
+
+void SAL_CALL
+ScVbaAxis::setMinimumScaleIsAuto( sal_Bool _bMinimumScaleIsAuto )
+{
+ try
+ {
+ if (isValueAxis())
+ {
+ mxPropertySet->setPropertyValue("AutoMin", uno::Any(_bMinimumScaleIsAuto));
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+sal_Bool SAL_CALL
+ScVbaAxis::getMinimumScaleIsAuto( )
+{
+ bool bIsAuto = false;
+ try
+ {
+ if (isValueAxis())
+ {
+ mxPropertySet->getPropertyValue("AutoMin") >>= bIsAuto;
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return bIsAuto;
+}
+
+::sal_Int32 SAL_CALL
+ScVbaAxis::getAxisGroup( )
+{
+ return mnGroup;
+}
+
+void SAL_CALL
+ScVbaAxis::setScaleType( ::sal_Int32 _nScaleType )
+{
+ try
+ {
+ if (isValueAxis())
+ {
+ switch (_nScaleType)
+ {
+ case xlScaleLinear:
+ mxPropertySet->setPropertyValue("Logarithmic", uno::Any( false ) );
+ break;
+ case xlScaleLogarithmic:
+ mxPropertySet->setPropertyValue("Logarithmic", uno::Any( true ) );
+ break;
+ default:
+ // According to MS the parameter is ignored and no Error is thrown
+ break;
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+::sal_Int32 SAL_CALL
+ScVbaAxis::getScaleType( )
+{
+ sal_Int32 nScaleType = xlScaleLinear;
+ try
+ {
+ if (isValueAxis())
+ {
+ bool bisLogarithmic = false;
+ mxPropertySet->getPropertyValue( "Logarithmic" ) >>= bisLogarithmic;
+ if (bisLogarithmic)
+ nScaleType = xlScaleLogarithmic;
+ else
+ nScaleType = xlScaleLinear;
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return nScaleType;
+}
+
+double SAL_CALL
+ScVbaAxis::getHeight( )
+{
+ return oShapeHelper->getHeight();
+}
+
+void SAL_CALL ScVbaAxis::setHeight( double height )
+{
+ oShapeHelper->setHeight( height );
+}
+double SAL_CALL ScVbaAxis::getWidth( )
+{
+ return oShapeHelper->getWidth( );
+}
+void SAL_CALL ScVbaAxis::setWidth( double width )
+{
+ oShapeHelper->setWidth( width );
+}
+double SAL_CALL ScVbaAxis::getTop( )
+{
+ return oShapeHelper->getTop( );
+}
+void SAL_CALL ScVbaAxis::setTop( double top )
+{
+ oShapeHelper->setTop( top );
+}
+double SAL_CALL ScVbaAxis::getLeft( )
+{
+ return oShapeHelper->getLeft( );
+}
+void SAL_CALL ScVbaAxis::setLeft( double left )
+{
+ oShapeHelper->setLeft( left );
+}
+
+OUString
+ScVbaAxis::getServiceImplName()
+{
+ return "ScVbaAxis";
+}
+
+uno::Sequence< OUString >
+ScVbaAxis::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Axis"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaaxis.hxx b/sc/source/ui/vba/vbaaxis.hxx
new file mode 100644
index 000000000..6636fb617
--- /dev/null
+++ b/sc/source/ui/vba/vbaaxis.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/beans/XPropertySet.hpp>
+#include <ooo/vba/excel/XAxis.hpp>
+#include <ooo/vba/excel/XChart.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+#include <memory>
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XAxis > ScVbaAxis_BASE;
+class ScVbaChart;
+class ScVbaAxis : public ScVbaAxis_BASE
+{
+ css::uno::Reference< ov::excel::XChart > moChartParent;
+ css::uno::Reference< css::beans::XPropertySet > mxPropertySet;
+ sal_Int32 mnType;
+ sal_Int32 mnGroup;
+ bool bCrossesAreCustomized;
+ /// @throws css::uno::RuntimeException
+ ScVbaChart* getChartPtr();
+ /// @throws css::script::BasicErrorException
+ bool isValueAxis();
+ std::unique_ptr<ov::ShapeHelper> oShapeHelper;
+
+public:
+ ScVbaAxis( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::beans::XPropertySet >& _xPropertySet, sal_Int32 _nType, sal_Int32 _nGroup );
+ // Methods
+ virtual void SAL_CALL Delete( ) override;
+ virtual css::uno::Reference< ::ooo::vba::excel::XAxisTitle > SAL_CALL getAxisTitle( ) override;
+ virtual void SAL_CALL setDisplayUnit( ::sal_Int32 DisplayUnit ) override;
+ virtual ::sal_Int32 SAL_CALL getDisplayUnit( ) override;
+ virtual void SAL_CALL setCrosses( ::sal_Int32 Crosses ) override;
+ virtual ::sal_Int32 SAL_CALL getCrosses( ) override;
+ virtual void SAL_CALL setCrossesAt( double CrossesAt ) override;
+ virtual double SAL_CALL getCrossesAt( ) override;
+ virtual void SAL_CALL setType( ::sal_Int32 Type ) override;
+ virtual ::sal_Int32 SAL_CALL getType( ) override;
+ virtual void SAL_CALL setHasTitle( sal_Bool HasTitle ) override;
+ virtual sal_Bool SAL_CALL getHasTitle( ) override;
+ virtual void SAL_CALL setMinorUnit( double MinorUnit ) override;
+ virtual double SAL_CALL getMinorUnit( ) override;
+ virtual void SAL_CALL setMinorUnitIsAuto( sal_Bool MinorUnitIsAuto ) override;
+ virtual sal_Bool SAL_CALL getMinorUnitIsAuto( ) override;
+ virtual void SAL_CALL setReversePlotOrder( sal_Bool ReversePlotOrder ) override;
+ virtual sal_Bool SAL_CALL getReversePlotOrder( ) override;
+ virtual void SAL_CALL setMajorUnit( double MajorUnit ) override;
+ virtual double SAL_CALL getMajorUnit( ) override;
+ virtual void SAL_CALL setMajorUnitIsAuto( sal_Bool MajorUnitIsAuto ) override;
+ virtual sal_Bool SAL_CALL getMajorUnitIsAuto( ) override;
+ virtual void SAL_CALL setMaximumScale( double MaximumScale ) override;
+ virtual double SAL_CALL getMaximumScale( ) override;
+ virtual void SAL_CALL setMaximumScaleIsAuto( sal_Bool MaximumScaleIsAuto ) override;
+ virtual sal_Bool SAL_CALL getMaximumScaleIsAuto( ) override;
+ virtual void SAL_CALL setMinimumScale( double MinimumScale ) override;
+ virtual double SAL_CALL getMinimumScale( ) override;
+ virtual void SAL_CALL setMinimumScaleIsAuto( sal_Bool MinimumScaleIsAuto ) override;
+ virtual sal_Bool SAL_CALL getMinimumScaleIsAuto( ) override;
+ virtual ::sal_Int32 SAL_CALL getAxisGroup( ) override;
+ virtual void SAL_CALL setScaleType( ::sal_Int32 ScaleType ) override;
+ virtual ::sal_Int32 SAL_CALL getScaleType( ) override;
+ virtual double SAL_CALL getHeight( ) override;
+ virtual void SAL_CALL setHeight( double height ) override;
+ virtual double SAL_CALL getWidth( ) override;
+ virtual void SAL_CALL setWidth( double width ) override;
+ virtual double SAL_CALL getTop( ) override;
+ virtual void SAL_CALL setTop( double top ) override;
+ virtual double SAL_CALL getLeft( ) override;
+ virtual void SAL_CALL setLeft( double left ) override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaaxistitle.cxx b/sc/source/ui/vba/vbaaxistitle.cxx
new file mode 100644
index 000000000..5336ef7a7
--- /dev/null
+++ b/sc/source/ui/vba/vbaaxistitle.cxx
@@ -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 .
+ */
+#include "vbaaxistitle.hxx"
+#include <comphelper/sequence.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+ScVbaAxisTitle::ScVbaAxisTitle( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< drawing::XShape >& _xTitleShape ) : AxisTitleBase( xParent, xContext, _xTitleShape )
+{
+}
+
+OUString
+ScVbaAxisTitle::getServiceImplName()
+{
+ return "ScVbaAxisTitle";
+}
+
+uno::Sequence< OUString >
+ScVbaAxisTitle::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames = comphelper::concatSequences(
+ AxisTitleBase::getServiceNames(),
+ uno::Sequence<OUString> { "ooo.vba.excel.AxisTitle" } );
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaaxistitle.hxx b/sc/source/ui/vba/vbaaxistitle.hxx
new file mode 100644
index 000000000..9226a58a3
--- /dev/null
+++ b/sc/source/ui/vba/vbaaxistitle.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 "vbatitle.hxx"
+#include <cppuhelper/implbase.hxx>
+#include <ooo/vba/excel/XAxisTitle.hpp>
+
+typedef TitleImpl< cppu::WeakImplHelper< ov::excel::XAxisTitle > > AxisTitleBase;
+
+class ScVbaAxisTitle : public AxisTitleBase
+{
+public:
+ ScVbaAxisTitle( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::drawing::XShape >& _xTitleShape );
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaborders.cxx b/sc/source/ui/vba/vbaborders.cxx
new file mode 100644
index 000000000..22434f971
--- /dev/null
+++ b/sc/source/ui/vba/vbaborders.cxx
@@ -0,0 +1,591 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "vbaborders.hxx"
+
+#include <sal/macros.h>
+#include <cppuhelper/implbase.hxx>
+#include <ooo/vba/excel/XlBordersIndex.hpp>
+#include <ooo/vba/excel/XlBorderWeight.hpp>
+#include <ooo/vba/excel/XlLineStyle.hpp>
+#include <ooo/vba/excel/XlColorIndex.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/table/TableBorder.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/table/XColumnRowRange.hpp>
+
+#include "vbapalette.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+using namespace ::ooo::vba::excel;
+
+typedef ::cppu::WeakImplHelper<container::XIndexAccess > RangeBorders_Base;
+typedef InheritedHelperInterfaceWeakImpl<excel::XBorder > ScVbaBorder_Base;
+
+// #TODO sort these indexes to match the order in which Excel iterates over the
+// borders, the enumeration will match the order in this list
+const sal_Int16 supportedIndexTable[] = { XlBordersIndex::xlEdgeLeft, XlBordersIndex::xlEdgeTop, XlBordersIndex::xlEdgeBottom, XlBordersIndex::xlEdgeRight, XlBordersIndex::xlDiagonalDown, XlBordersIndex::xlDiagonalUp, XlBordersIndex::xlInsideVertical, XlBordersIndex::xlInsideHorizontal };
+
+constexpr OUStringLiteral sTableBorder = u"TableBorder";
+
+// Equiv widths in 1/100 mm
+const sal_Int32 OOLineThin = 26;
+const sal_Int32 OOLineMedium = 88;
+const sal_Int32 OOLineThick = 141;
+const sal_Int32 OOLineHairline = 2;
+
+namespace {
+
+class ScVbaBorder : public ScVbaBorder_Base
+{
+private:
+ uno::Reference< beans::XPropertySet > m_xProps;
+ sal_Int32 m_LineType;
+ ScVbaPalette m_Palette;
+ void setBorderLine( const table::BorderLine& rBorderLine )
+ {
+ table::TableBorder aTableBorder;
+ m_xProps->getPropertyValue( sTableBorder ) >>= aTableBorder;
+
+ switch ( m_LineType )
+ {
+ case XlBordersIndex::xlEdgeLeft:
+ aTableBorder.IsLeftLineValid = true;
+ aTableBorder.LeftLine= rBorderLine;
+ break;
+ case XlBordersIndex::xlEdgeTop:
+ aTableBorder.IsTopLineValid = true;
+ aTableBorder.TopLine = rBorderLine;
+ break;
+
+ case XlBordersIndex::xlEdgeBottom:
+ aTableBorder.IsBottomLineValid = true;
+ aTableBorder.BottomLine = rBorderLine;
+ break;
+ case XlBordersIndex::xlEdgeRight:
+ aTableBorder.IsRightLineValid = true;
+ aTableBorder.RightLine = rBorderLine;
+ break;
+ case XlBordersIndex::xlInsideVertical:
+ aTableBorder.IsVerticalLineValid = true;
+ aTableBorder.VerticalLine = rBorderLine;
+ break;
+ case XlBordersIndex::xlInsideHorizontal:
+ aTableBorder.IsHorizontalLineValid = true;
+ aTableBorder.HorizontalLine = rBorderLine;
+ break;
+ case XlBordersIndex::xlDiagonalDown:
+ case XlBordersIndex::xlDiagonalUp:
+ // #TODO have to ignore at the moment, would be
+ // nice to investigate what we can do here
+ break;
+ default:
+ return;
+ }
+ m_xProps->setPropertyValue( sTableBorder, uno::Any(aTableBorder) );
+ }
+
+ bool getBorderLine( table::BorderLine& rBorderLine )
+ {
+ table::TableBorder aTableBorder;
+ m_xProps->getPropertyValue( sTableBorder ) >>= aTableBorder;
+ switch ( m_LineType )
+ {
+ case XlBordersIndex::xlEdgeLeft:
+ if ( aTableBorder.IsLeftLineValid )
+ rBorderLine = aTableBorder.LeftLine;
+ break;
+ case XlBordersIndex::xlEdgeTop:
+ if ( aTableBorder.IsTopLineValid )
+ rBorderLine = aTableBorder.TopLine;
+ break;
+
+ case XlBordersIndex::xlEdgeBottom:
+ if ( aTableBorder.IsBottomLineValid )
+ rBorderLine = aTableBorder.BottomLine;
+ break;
+ case XlBordersIndex::xlEdgeRight:
+ if ( aTableBorder.IsRightLineValid )
+ rBorderLine = aTableBorder.RightLine;
+ break;
+ case XlBordersIndex::xlInsideVertical:
+ if ( aTableBorder.IsVerticalLineValid )
+ rBorderLine = aTableBorder.VerticalLine;
+ break;
+ case XlBordersIndex::xlInsideHorizontal:
+ if ( aTableBorder.IsHorizontalLineValid )
+ rBorderLine = aTableBorder.HorizontalLine;
+ break;
+
+ case XlBordersIndex::xlDiagonalDown:
+ case XlBordersIndex::xlDiagonalUp:
+ // #TODO have to ignore at the moment, would be
+ // nice to investigate what we can do here
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
+
+protected:
+ virtual OUString getServiceImplName() override
+ {
+ return "ScVbaBorder";
+ }
+ virtual css::uno::Sequence<OUString> getServiceNames() override
+ {
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Border"
+ };
+ return aServiceNames;
+ }
+public:
+ ScVbaBorder( const uno::Reference< beans::XPropertySet > & xProps, const uno::Reference< uno::XComponentContext >& xContext, sal_Int32 lineType, const ScVbaPalette& rPalette) : ScVbaBorder_Base( uno::Reference< XHelperInterface >( xProps, uno::UNO_QUERY ), xContext ), m_xProps( xProps ), m_LineType( lineType ), m_Palette( rPalette ) {}
+
+ // XBorder
+ uno::Any SAL_CALL getColor() override
+ {
+ table::BorderLine aBorderLine;
+ if ( getBorderLine( aBorderLine ) )
+ return uno::Any( OORGBToXLRGB( Color(ColorTransparency, aBorderLine.Color) ) );
+ throw uno::RuntimeException("No Implementation available" );
+ }
+ void SAL_CALL setColor( const uno::Any& _color ) override
+ {
+ sal_Int32 nColor = 0;
+ _color >>= nColor;
+ table::BorderLine aBorderLine;
+ if ( !getBorderLine( aBorderLine ) )
+ throw uno::RuntimeException("No Implementation available" );
+
+ aBorderLine.Color = XLRGBToOORGB( nColor );
+ setBorderLine( aBorderLine );
+
+ }
+
+ uno::Any SAL_CALL getColorIndex() override
+ {
+ sal_Int32 nColor = 0;
+ XLRGBToOORGB( getColor() ) >>= nColor;
+ uno::Reference< container::XIndexAccess > xIndex = m_Palette.getPalette();
+ sal_Int32 nElems = xIndex->getCount();
+ sal_Int32 nIndex = -1;
+ for ( sal_Int32 count=0; count<nElems; ++count )
+ {
+ sal_Int32 nPaletteColor = 0;
+ xIndex->getByIndex( count ) >>= nPaletteColor;
+ if ( nPaletteColor == nColor )
+ {
+ nIndex = count + 1;
+ break;
+ }
+ }
+ return uno::Any(nIndex);
+ }
+
+ void SAL_CALL setColorIndex( const uno::Any& _colorindex ) override
+ {
+ sal_Int32 nColor = 0;
+ _colorindex >>= nColor;
+ if ( !nColor || nColor == XlColorIndex::xlColorIndexAutomatic )
+ nColor = 1;
+ setColor( OORGBToXLRGB( m_Palette.getPalette()->getByIndex( --nColor ) ) );
+ }
+ uno::Any SAL_CALL getWeight() override
+ {
+ table::BorderLine aBorderLine;
+ if ( getBorderLine( aBorderLine ) )
+ {
+ switch ( aBorderLine.OuterLineWidth )
+ {
+ case 0: // Thin = default OO thickness
+ case OOLineThin:
+ return uno::Any( XlBorderWeight::xlThin );
+ case OOLineMedium:
+ return uno::Any( XlBorderWeight::xlMedium );
+ case OOLineThick:
+ return uno::Any( XlBorderWeight::xlThick );
+ case OOLineHairline:
+ return uno::Any( XlBorderWeight::xlHairline );
+ default:
+ break;
+ }
+ }
+ throw uno::RuntimeException("Method failed" );
+ }
+ void SAL_CALL setWeight( const uno::Any& _weight ) override
+ {
+ sal_Int32 nWeight = 0;
+ _weight >>= nWeight;
+ table::BorderLine aBorderLine;
+ if ( !getBorderLine( aBorderLine ) )
+ throw uno::RuntimeException("Method failed" );
+
+ switch ( nWeight )
+ {
+ case XlBorderWeight::xlThin:
+ aBorderLine.OuterLineWidth = OOLineThin;
+ break;
+ case XlBorderWeight::xlMedium:
+ aBorderLine.OuterLineWidth = OOLineMedium;
+ break;
+ case XlBorderWeight::xlThick:
+ aBorderLine.OuterLineWidth = OOLineThick;
+ break;
+ case XlBorderWeight::xlHairline:
+ aBorderLine.OuterLineWidth = OOLineHairline;
+ break;
+ default:
+ throw uno::RuntimeException("Bad param" );
+ }
+ setBorderLine( aBorderLine );
+
+ }
+
+ void SAL_CALL setTintAndShade( const uno::Any& /*rAny*/ ) override
+ {
+ // TODO implement
+ }
+ uno::Any SAL_CALL getTintAndShade() override
+ {
+ // TODO implement
+ return uno::Any(static_cast<double>(0));
+ }
+
+ uno::Any SAL_CALL getLineStyle() override
+ {
+ // always return xlContinuous;
+ return uno::Any( XlLineStyle::xlContinuous );
+ }
+ void SAL_CALL setLineStyle( const uno::Any& _linestyle ) override
+ {
+ // Urk no choice but to silently ignore we don't support this attribute
+ // #TODO would be nice to support the excel line styles
+ sal_Int32 nLineStyle = 0;
+ _linestyle >>= nLineStyle;
+ table::BorderLine aBorderLine;
+ if ( !getBorderLine( aBorderLine ) )
+ throw uno::RuntimeException("Method failed" );
+
+ switch ( nLineStyle )
+ {
+ case XlLineStyle::xlContinuous:
+ case XlLineStyle::xlDash:
+ case XlLineStyle::xlDashDot:
+ case XlLineStyle::xlDashDotDot:
+ case XlLineStyle::xlDot:
+ case XlLineStyle::xlDouble:
+ case XlLineStyle::xlLineStyleNone:
+ case XlLineStyle::xlSlantDashDot:
+ break;
+ default:
+ throw uno::RuntimeException("Bad param" );
+ }
+ setBorderLine( aBorderLine );
+
+ }
+};
+
+class RangeBorders : public RangeBorders_Base
+{
+private:
+ uno::Reference< table::XCellRange > m_xRange;
+ uno::Reference< uno::XComponentContext > m_xContext;
+ ScVbaPalette m_Palette;
+ sal_Int32 getTableIndex( sal_Int32 nConst )
+ {
+ // okay return position of the index in the table
+ sal_Int32 nIndexes = getCount();
+ sal_Int32 realIndex = 0;
+ const sal_Int16* pTableEntry = supportedIndexTable;
+ for ( ; realIndex < nIndexes; ++realIndex, ++pTableEntry )
+ {
+ if ( *pTableEntry == nConst )
+ return realIndex;
+ }
+ return getCount(); // error condition
+ }
+public:
+ RangeBorders( const uno::Reference< table::XCellRange >& xRange, const uno::Reference< uno::XComponentContext > & xContext, const ScVbaPalette& rPalette ) : m_xRange( xRange ), m_xContext( xContext ), m_Palette( rPalette )
+ {
+ }
+ // XIndexAccess
+ virtual ::sal_Int32 SAL_CALL getCount( ) override
+ {
+ return SAL_N_ELEMENTS( supportedIndexTable );
+ }
+ virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
+ {
+
+ sal_Int32 nIndex = getTableIndex( Index );
+ if ( nIndex >= 0 && nIndex < getCount() )
+ {
+ uno::Reference< beans::XPropertySet > xProps( m_xRange, uno::UNO_QUERY_THROW );
+ return uno::Any( uno::Reference< excel::XBorder >( new ScVbaBorder( xProps, m_xContext, supportedIndexTable[ nIndex ], m_Palette )) );
+ }
+ throw lang::IndexOutOfBoundsException();
+ }
+ virtual uno::Type SAL_CALL getElementType( ) override
+ {
+ return cppu::UnoType<excel::XBorder>::get();
+ }
+ virtual sal_Bool SAL_CALL hasElements( ) override
+ {
+ return true;
+ }
+};
+
+}
+
+static uno::Reference< container::XIndexAccess >
+rangeToBorderIndexAccess( const uno::Reference< table::XCellRange >& xRange, const uno::Reference< uno::XComponentContext > & xContext, const ScVbaPalette& rPalette )
+{
+ return new RangeBorders( xRange, xContext, rPalette );
+}
+
+namespace {
+
+class RangeBorderEnumWrapper : public EnumerationHelper_BASE
+{
+ uno::Reference<container::XIndexAccess > m_xIndexAccess;
+ sal_Int32 nIndex;
+public:
+ explicit RangeBorderEnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess ) : m_xIndexAccess( xIndexAccess ), nIndex( 0 ) {}
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override
+ {
+ return ( nIndex < m_xIndexAccess->getCount() );
+ }
+
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ if ( nIndex < m_xIndexAccess->getCount() )
+ return m_xIndexAccess->getByIndex( nIndex++ );
+ throw container::NoSuchElementException();
+ }
+};
+
+}
+
+ScVbaBorders::ScVbaBorders( const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext > & xContext,
+ const uno::Reference< table::XCellRange >& xRange,
+ const ScVbaPalette& rPalette )
+ : ScVbaBorders_BASE( xParent, xContext, rangeToBorderIndexAccess( xRange ,xContext, rPalette ) ), bRangeIsSingleCell( false )
+{
+ uno::Reference< table::XColumnRowRange > xColumnRowRange(xRange, uno::UNO_QUERY_THROW );
+ if ( xColumnRowRange->getRows()->getCount() == 1 && xColumnRowRange->getColumns()->getCount() == 1 )
+ bRangeIsSingleCell = true;
+ m_xProps.set( xRange, uno::UNO_QUERY_THROW );
+}
+
+uno::Reference< container::XEnumeration >
+ScVbaBorders::createEnumeration()
+{
+ return new RangeBorderEnumWrapper( m_xIndexAccess );
+}
+
+uno::Any
+ScVbaBorders::createCollectionObject( const css::uno::Any& aSource )
+{
+ return aSource; // it's already a Border object
+}
+
+uno::Type
+ScVbaBorders::getElementType()
+{
+ return cppu::UnoType<excel::XBorders>::get();
+}
+
+uno::Any
+ScVbaBorders::getItemByIntIndex( const sal_Int32 nIndex )
+{
+ return createCollectionObject( m_xIndexAccess->getByIndex( nIndex ) );
+}
+
+uno::Any SAL_CALL ScVbaBorders::getColor()
+{
+ sal_Int32 count = getCount();
+ uno::Any color;
+ for( sal_Int32 i = 0; i < count ; i++ )
+ {
+ if( XlBordersIndex::xlDiagonalDown != supportedIndexTable[i] && XlBordersIndex::xlDiagonalUp != supportedIndexTable[i] )
+ {
+ uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW );
+ if( color.hasValue() )
+ {
+ if( color != xBorder->getColor() )
+ return uno::Any( uno::Reference< uno::XInterface >() );
+ }
+ else
+ color = xBorder->getColor();
+ }
+ }
+ return color;
+}
+void SAL_CALL ScVbaBorders::setColor( const uno::Any& _color )
+{
+ sal_Int32 count = getCount();
+ for( sal_Int32 i = 0; i < count ; i++ )
+ {
+ uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW );
+ xBorder->setColor( _color );
+ }
+}
+uno::Any SAL_CALL ScVbaBorders::getColorIndex()
+{
+ sal_Int32 count = getCount();
+ uno::Any nColorIndex;
+ for( sal_Int32 i = 0; i < count ; i++ )
+ {
+ if( XlBordersIndex::xlDiagonalDown != supportedIndexTable[i] && XlBordersIndex::xlDiagonalUp != supportedIndexTable[i] )
+ {
+ uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW );
+ if( nColorIndex.hasValue() )
+ {
+ if( nColorIndex != xBorder->getColorIndex() )
+ return uno::Any( uno::Reference< uno::XInterface >() );
+ }
+ else
+ nColorIndex = xBorder->getColorIndex();
+ }
+ }
+ return nColorIndex;
+}
+void SAL_CALL ScVbaBorders::setColorIndex( const uno::Any& _colorindex )
+{
+ sal_Int32 count = getCount();
+ for( sal_Int32 i = 0; i < count ; i++ )
+ {
+ uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW );
+ xBorder->setColorIndex( _colorindex );
+ }
+}
+
+static bool
+lcl_areAllLineWidthsSame( const table::TableBorder& maTableBorder, bool bIsCell )
+{
+
+ bool bRes = false;
+ if (bIsCell)
+ {
+ bRes = ((maTableBorder.TopLine.OuterLineWidth == maTableBorder.BottomLine.OuterLineWidth) &&
+(maTableBorder.TopLine.OuterLineWidth == maTableBorder.LeftLine.OuterLineWidth) &&
+(maTableBorder.TopLine.OuterLineWidth == maTableBorder.RightLine.OuterLineWidth));
+ }
+ else
+ {
+ bRes = ((maTableBorder.TopLine.OuterLineWidth == maTableBorder.BottomLine.OuterLineWidth) &&
+(maTableBorder.TopLine.OuterLineWidth == maTableBorder.LeftLine.OuterLineWidth) &&
+(maTableBorder.TopLine.OuterLineWidth == maTableBorder.HorizontalLine.OuterLineWidth) &&
+(maTableBorder.TopLine.OuterLineWidth == maTableBorder.VerticalLine.OuterLineWidth) &&
+(maTableBorder.TopLine.OuterLineWidth == maTableBorder.RightLine.OuterLineWidth));
+ }
+ return bRes;
+}
+
+uno::Any SAL_CALL ScVbaBorders::getLineStyle()
+{
+ table::TableBorder aTableBorder;
+ m_xProps->getPropertyValue( sTableBorder ) >>= aTableBorder;
+
+ sal_Int32 aLinestyle = XlLineStyle::xlLineStyleNone;
+
+ if ( lcl_areAllLineWidthsSame( aTableBorder, bRangeIsSingleCell ))
+ {
+ if (aTableBorder.TopLine.LineDistance != 0)
+ {
+ aLinestyle = XlLineStyle::xlDouble;
+ }
+ else if ( aTableBorder.TopLine.OuterLineWidth != 0 )
+ {
+ aLinestyle = XlLineStyle::xlContinuous;
+ }
+ }
+ return uno::Any( aLinestyle );
+}
+void SAL_CALL ScVbaBorders::setLineStyle( const uno::Any& _linestyle )
+{
+ sal_Int32 count = getCount();
+ for( sal_Int32 i = 0; i < count ; i++ )
+ {
+ uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW );
+ xBorder->setLineStyle( _linestyle );
+ }
+}
+uno::Any SAL_CALL ScVbaBorders::getWeight()
+{
+ sal_Int32 count = getCount();
+ uno::Any weight;
+ for( sal_Int32 i = 0; i < count ; i++ )
+ {
+ if( XlBordersIndex::xlDiagonalDown != supportedIndexTable[i] && XlBordersIndex::xlDiagonalUp != supportedIndexTable[i] )
+ {
+ uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW );
+ if( weight.hasValue() )
+ {
+ if( weight != xBorder->getWeight() )
+ return uno::Any( uno::Reference< uno::XInterface >() );
+ }
+ else
+ weight = xBorder->getWeight();
+ }
+ }
+ return weight;
+}
+
+uno::Any SAL_CALL ScVbaBorders::getTintAndShade()
+{
+ // TODO implement
+ return uno::Any(static_cast<double>(0));
+}
+
+void SAL_CALL ScVbaBorders::setTintAndShade(const uno::Any& /*rAny*/)
+{
+ // TODO implement
+}
+
+void SAL_CALL ScVbaBorders::setWeight( const uno::Any& _weight )
+{
+ sal_Int32 count = getCount();
+ for( sal_Int32 i = 0; i < count ; i++ )
+ {
+ uno::Reference< XBorder > xBorder( getItemByIntIndex( supportedIndexTable[i] ), uno::UNO_QUERY_THROW );
+ xBorder->setWeight( _weight );
+ }
+}
+
+OUString
+ScVbaBorders::getServiceImplName()
+{
+ return "ScVbaBorders";
+}
+
+uno::Sequence< OUString >
+ScVbaBorders::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Borders"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaborders.hxx b/sc/source/ui/vba/vbaborders.hxx
new file mode 100644
index 000000000..6d3621101
--- /dev/null
+++ b/sc/source/ui/vba/vbaborders.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 <ooo/vba/excel/XBorders.hpp>
+
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::table { class XCellRange; }
+
+typedef CollTestImplHelper< ov::excel::XBorders > ScVbaBorders_BASE;
+class ScVbaPalette;
+class ScVbaBorders : public ScVbaBorders_BASE
+{
+ // XEnumerationAccess
+ virtual css::uno::Any getItemByIntIndex( const sal_Int32 nIndex ) override;
+ bool bRangeIsSingleCell;
+ css::uno::Reference< css::beans::XPropertySet > m_xProps;
+public:
+ ScVbaBorders( const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext > & xContext,
+ const css::uno::Reference< css::table::XCellRange >& xRange,
+ const ScVbaPalette& rPalette );
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+
+ // XBorders
+
+ // ScVbaCollectionBaseImpl
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+
+ virtual css::uno::Any SAL_CALL getColor() override;
+ virtual void SAL_CALL setColor( const css::uno::Any& _color ) override;
+ virtual css::uno::Any SAL_CALL getColorIndex() override;
+ virtual void SAL_CALL setColorIndex( const css::uno::Any& _colorindex ) override;
+ virtual css::uno::Any SAL_CALL getLineStyle() override;
+ virtual void SAL_CALL setLineStyle( const css::uno::Any& _linestyle ) override;
+ virtual css::uno::Any SAL_CALL getWeight() override;
+ virtual void SAL_CALL setWeight( const css::uno::Any& ) override;
+ virtual css::uno::Any SAL_CALL getTintAndShade() override;
+ virtual void SAL_CALL setTintAndShade( const css::uno::Any& ) override;
+ // xxxxBASE
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbacharacters.cxx b/sc/source/ui/vba/vbacharacters.cxx
new file mode 100644
index 000000000..3fd00b207
--- /dev/null
+++ b/sc/source/ui/vba/vbacharacters.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 "vbacharacters.hxx"
+
+#include "vbafont.hxx"
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+ScVbaCharacters::ScVbaCharacters( const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const ScVbaPalette& dPalette,
+ const uno::Reference< text::XSimpleText>& xRange,
+ const css::uno::Any& Start,
+ const css::uno::Any& Length,
+ bool Replace )
+ : ScVbaCharacters_BASE( xParent, xContext ),
+ m_xSimpleText(xRange), m_aPalette( dPalette), bReplace( Replace )
+{
+ sal_Int16 nLength(-1);
+ sal_Int16 nStart(1);
+ Start >>= nStart;
+ if ( nStart < 1 )
+ nStart = 1; // silently correct user error ( as ms )
+ nStart--; // OOo is 0 based
+ Length >>=nLength;
+ uno::Reference< text::XTextCursor > xTextCursor( m_xSimpleText->createTextCursor(), uno::UNO_SET_THROW );
+ xTextCursor->collapseToStart();
+ if ( nStart )
+ {
+ if ( ( nStart + 1 ) > m_xSimpleText->getString().getLength() )
+ //nStart = m_xSimpleText->getString().getLength();
+ xTextCursor->gotoEnd( false );
+ xTextCursor->goRight( nStart, false );
+ }
+ if ( nLength < 0 ) // expand to end
+ xTextCursor->gotoEnd( true );
+ else
+ xTextCursor->goRight( nLength, true );
+ m_xTextRange.set( xTextCursor, uno::UNO_QUERY_THROW );
+
+}
+
+OUString SAL_CALL
+ScVbaCharacters::getCaption()
+{
+ return m_xTextRange->getString();
+}
+void SAL_CALL
+ScVbaCharacters::setCaption( const OUString& _caption )
+{
+ m_xTextRange->setString( _caption );
+
+}
+
+::sal_Int32 SAL_CALL
+ScVbaCharacters::getCount()
+{
+ return getCaption().getLength();
+}
+
+OUString SAL_CALL
+ScVbaCharacters::getText()
+{
+ return getCaption();
+}
+void SAL_CALL
+ScVbaCharacters::setText( const OUString& _text )
+{
+ setCaption( _text );
+}
+uno::Reference< excel::XFont > SAL_CALL
+ScVbaCharacters::getFont()
+{
+ uno::Reference< beans::XPropertySet > xProps( m_xTextRange, uno::UNO_QUERY_THROW );
+ return uno::Reference< excel::XFont >( new ScVbaFont( this, mxContext, m_aPalette, xProps ) );
+}
+void SAL_CALL
+ScVbaCharacters::setFont( const uno::Reference< excel::XFont >& /*_font*/ )
+{
+ // #TODO #FIXME needs implementation, or can't be done?
+ throw uno::RuntimeException("Not Implemented" );
+}
+
+// Methods
+void SAL_CALL
+ScVbaCharacters::Insert( const OUString& rString )
+{
+ m_xSimpleText->insertString( m_xTextRange, rString, bReplace );
+}
+
+void SAL_CALL
+ScVbaCharacters::Delete( )
+{
+ // #FIXME #TODO is this a bit suspect? I wonder should the contents
+ // of the cell be deleted from the parent ( range )
+ m_xSimpleText->setString(OUString());
+}
+
+OUString
+ScVbaCharacters::getServiceImplName()
+{
+ return "ScVbaCharacters";
+}
+
+uno::Sequence< OUString >
+ScVbaCharacters::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Characters"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbacharacters.hxx b/sc/source/ui/vba/vbacharacters.hxx
new file mode 100644
index 000000000..1d9c3c82f
--- /dev/null
+++ b/sc/source/ui/vba/vbacharacters.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 <ooo/vba/excel/XCharacters.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+#include "vbapalette.hxx"
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XCharacters > ScVbaCharacters_BASE;
+
+class ScVbaCharacters : public ScVbaCharacters_BASE
+{
+private:
+ css::uno::Reference< css::text::XTextRange > m_xTextRange;
+ css::uno::Reference< css::text::XSimpleText > m_xSimpleText;
+ ScVbaPalette m_aPalette;
+ // Add because of MSO has different behavior.
+ bool bReplace;
+public:
+ /// @throws css::lang::IllegalArgumentException
+ /// @throws css::uno::RuntimeException
+ ScVbaCharacters( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const ScVbaPalette& dPalette, const css::uno::Reference< css::text::XSimpleText >& xRange, const css::uno::Any& Start, const css::uno::Any& Length, bool bReplace = false );
+
+ // Attributes
+ virtual OUString SAL_CALL getCaption() override;
+ virtual void SAL_CALL setCaption( const OUString& _caption ) override;
+ virtual ::sal_Int32 SAL_CALL getCount() override;
+ virtual OUString SAL_CALL getText() override;
+ virtual void SAL_CALL setText( const OUString& _text ) override;
+ virtual css::uno::Reference< ov::excel::XFont > SAL_CALL getFont() override;
+ virtual void SAL_CALL setFont( const css::uno::Reference< ov::excel::XFont >& _font ) override;
+
+ // Methods
+ virtual void SAL_CALL Insert( const OUString& String ) override;
+ virtual void SAL_CALL Delete( ) override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbachart.cxx b/sc/source/ui/vba/vbachart.cxx
new file mode 100644
index 000000000..5d9cd56a8
--- /dev/null
+++ b/sc/source/ui/vba/vbachart.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 "vbachart.hxx"
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/chart/XAxisXSupplier.hpp>
+#include <com/sun/star/chart/XAxisYSupplier.hpp>
+#include <com/sun/star/chart/XAxisZSupplier.hpp>
+#include <com/sun/star/chart/XTwoAxisXSupplier.hpp>
+#include <com/sun/star/chart/XTwoAxisYSupplier.hpp>
+#include <com/sun/star/chart/XChartDataArray.hpp>
+#include <com/sun/star/chart/ChartSymbolType.hpp>
+#include <com/sun/star/chart/ChartSolidType.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <ooo/vba/excel/XlChartType.hpp>
+#include <ooo/vba/excel/XlRowCol.hpp>
+#include <ooo/vba/excel/XlAxisType.hpp>
+#include <ooo/vba/excel/XlAxisGroup.hpp>
+
+#include <basic/sberrors.hxx>
+#include "vbachartobject.hxx"
+#include "vbarange.hxx"
+#include "vbacharttitle.hxx"
+#include "vbaaxes.hxx"
+#include <document.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+using namespace ::ooo::vba::excel::XlChartType;
+using namespace ::ooo::vba::excel::XlRowCol;
+using namespace ::ooo::vba::excel::XlAxisType;
+using namespace ::ooo::vba::excel::XlAxisGroup;
+
+constexpr OUStringLiteral CHART_NAME(u"Name");
+// #TODO move this constant to vbaseries.[ch]xx ( when it exists )
+constexpr OUStringLiteral DEFAULTSERIESPREFIX(u"Series");
+constexpr OUStringLiteral DATAROWSOURCE(u"DataRowSource");
+constexpr OUStringLiteral UPDOWN(u"UpDown");
+constexpr OUStringLiteral VOLUME(u"Volume");
+constexpr OUStringLiteral LINES(u"Lines");
+constexpr OUStringLiteral SPLINETYPE(u"SplineType");
+constexpr OUStringLiteral SYMBOLTYPE(u"SymbolType");
+constexpr OUStringLiteral DEEP(u"Deep");
+constexpr OUStringLiteral SOLIDTYPE(u"SolidType");
+constexpr OUStringLiteral VERTICAL(u"Vertical");
+constexpr OUStringLiteral PERCENT(u"Percent");
+constexpr OUStringLiteral STACKED(u"Stacked");
+constexpr OUStringLiteral DIM3D(u"Dim3D");
+constexpr OUStringLiteral HASMAINTITLE(u"HasMainTitle");
+constexpr OUStringLiteral HASLEGEND(u"HasLegend");
+
+ScVbaChart::ScVbaChart( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::lang::XComponent >& _xChartComponent, const css::uno::Reference< css::table::XTableChart >& _xTableChart ) : ChartImpl_BASE( _xParent, _xContext ), mxTableChart( _xTableChart )
+{
+ mxChartDocument.set( _xChartComponent, uno::UNO_QUERY_THROW ) ;
+ // #TODO is it possible that the XPropertySet interface is not set
+ // code in setPlotBy seems to indicate that this is possible? but
+ // additionally there is no check in most of the places where it is used
+ // ( and therefore could possibly be NULL )
+ // I'm going to let it throw for the moment ( npower )
+ mxDiagramPropertySet.set( mxChartDocument->getDiagram(), uno::UNO_QUERY_THROW );
+ mxChartPropertySet.set( _xChartComponent, uno::UNO_QUERY_THROW ) ;
+}
+
+OUString SAL_CALL
+ScVbaChart::getName()
+{
+ OUString sName;
+ uno::Reference< beans::XPropertySet > xProps( mxChartDocument, uno::UNO_QUERY_THROW );
+ try
+ {
+ xProps->getPropertyValue( CHART_NAME ) >>= sName;
+ }
+ catch( const uno::Exception & ) // swallow exceptions
+ {
+ }
+ return sName;
+}
+
+uno::Any SAL_CALL
+ScVbaChart::SeriesCollection(const uno::Any&)
+{
+ return uno::Any();
+}
+
+::sal_Int32 SAL_CALL
+ScVbaChart::getChartType()
+{
+ sal_Int32 nChartType = -1;
+ try
+ {
+ OUString sDiagramType = mxChartDocument->getDiagram()->getDiagramType();
+ if ( sDiagramType == "com.sun.star.chart.AreaDiagram" )
+ {
+ if (is3D())
+ {
+ nChartType = getStackedType(xl3DAreaStacked, xl3DAreaStacked100, xl3DArea);
+ }
+ else
+ {
+ nChartType = getStackedType(xlAreaStacked, xlAreaStacked100, xlArea);
+ }
+ }
+ else if ( sDiagramType == "com.sun.star.chart.PieDiagram" )
+ {
+ if (is3D())
+ nChartType = xl3DPie;
+ else
+ nChartType = xlPie; /*TODO XlChartType xlPieExploded, XlChartType xlPieOfPie */
+ }
+ else if ( sDiagramType == "com.sun.star.chart.BarDiagram" )
+ {
+ sal_Int32 nSolidType = chart::ChartSolidType::RECTANGULAR_SOLID;
+ if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(SOLIDTYPE))
+ { //in 2D diagrams 'SolidType' may not be set
+ if (is3D())
+ mxDiagramPropertySet->getPropertyValue(SOLIDTYPE) >>= nSolidType;
+ }
+ switch (nSolidType)
+ {
+ case chart::ChartSolidType::CONE:
+ nChartType = getSolidType(xlConeCol, xlConeColStacked, xlConeColStacked100, xlConeColClustered, xlConeBarStacked, xlConeBarStacked100, xlConeBarClustered);
+ break;
+ case chart::ChartSolidType::CYLINDER:
+ nChartType = getSolidType(xlCylinderCol, xlCylinderColStacked, xlCylinderColStacked100, xlCylinderColClustered, xlCylinderBarStacked, xlCylinderBarStacked100, xlCylinderBarClustered);
+ break;
+ case chart::ChartSolidType::PYRAMID:
+ nChartType = getSolidType(xlPyramidCol, xlPyramidColStacked, xlPyramidColStacked100, xlPyramidColClustered, xlPyramidBarStacked, xlPyramidBarStacked100, xlPyramidBarClustered);
+ break;
+ default: // RECTANGULAR_SOLID
+ if (is3D())
+ {
+ nChartType = getSolidType(xl3DColumn, xl3DColumnStacked, xl3DColumnStacked100, xl3DColumnClustered, xl3DBarStacked, xl3DBarStacked100, xl3DBarClustered);
+ }
+ else
+ {
+ nChartType = getSolidType(xlColumnClustered, xlColumnStacked, xlColumnStacked100, xlColumnClustered, xlBarStacked, xlBarStacked100, xlBarClustered);
+ }
+ break;
+ }
+ }
+ else if ( sDiagramType == "com.sun.star.chart.StockDiagram" )
+ {
+ bool bVolume = false;
+ mxDiagramPropertySet->getPropertyValue(VOLUME) >>= bVolume;
+ if (bVolume)
+ {
+ nChartType = getStockUpDownValue(xlStockVOHLC, xlStockVHLC);
+ }
+ else
+ {
+ nChartType = getStockUpDownValue(xlStockOHLC, xlStockHLC);
+ }
+ }
+ else if ( sDiagramType == "com.sun.star.chart.XYDiagram" )
+ {
+ bool bHasLines = false;
+ mxDiagramPropertySet->getPropertyValue(LINES) >>= bHasLines;
+ sal_Int32 nSplineType = 0;
+ mxDiagramPropertySet->getPropertyValue(SPLINETYPE) >>= nSplineType;
+ if (nSplineType == 1)
+ {
+ nChartType = getMarkerType(xlXYScatterSmooth, xlXYScatterSmoothNoMarkers);
+ }
+ else if (bHasLines)
+ {
+ nChartType = getMarkerType(xlXYScatterLines, xlXYScatterLinesNoMarkers);
+ }
+ else
+ {
+ nChartType = xlXYScatter;
+ }
+ }
+ else if ( sDiagramType == "com.sun.star.chart.LineDiagram" )
+ {
+ if (is3D())
+ {
+ nChartType = xl3DLine;
+ }
+ else if (hasMarkers())
+ {
+ nChartType = getStackedType(xlLineMarkersStacked, xlLineMarkersStacked100, xlLineMarkers);
+ }
+ else
+ {
+ nChartType = getStackedType(xlLineStacked, xlLineStacked100, xlLine);
+ }
+ }
+ else if ( sDiagramType == "com.sun.star.chart.DonutDiagram" )
+ {
+ nChartType = xlDoughnut; // TODO DoughnutExploded ??
+ }
+ else if ( sDiagramType == "com.sun.star.chart.NetDiagram" )
+ {
+ nChartType = getMarkerType(xlRadarMarkers, xlRadar);
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+ return nChartType;
+}
+
+void SAL_CALL
+ScVbaChart::setChartType( ::sal_Int32 _nChartType )
+{
+ try
+ {
+ switch (_nChartType)
+ {
+ case xlColumnClustered:
+ case xlColumnStacked:
+ case xlColumnStacked100:
+ case xl3DColumnClustered:
+ case xl3DColumnStacked:
+ case xl3DColumnStacked100:
+ case xl3DColumn:
+ case xlBarClustered:
+ case xlBarStacked:
+ case xlBarStacked100:
+ case xl3DBarClustered:
+ case xl3DBarStacked:
+ case xl3DBarStacked100:
+ case xlConeColClustered:
+ case xlConeColStacked:
+ case xlConeColStacked100:
+ case xlConeBarClustered:
+ case xlConeBarStacked:
+ case xlConeBarStacked100:
+ case xlConeCol:
+ case xlPyramidColClustered:
+ case xlPyramidColStacked:
+ case xlPyramidColStacked100:
+ case xlPyramidBarClustered:
+ case xlPyramidBarStacked:
+ case xlPyramidBarStacked100:
+ case xlPyramidCol:
+ case xlCylinderColClustered:
+ case xlCylinderColStacked:
+ case xlCylinderColStacked100:
+ case xlCylinderBarClustered:
+ case xlCylinderBarStacked:
+ case xlCylinderBarStacked100:
+ case xlCylinderCol:
+ case xlSurface: // not possible
+ case xlSurfaceWireframe:
+ case xlSurfaceTopView:
+ case xlSurfaceTopViewWireframe:
+ setDiagram( "com.sun.star.chart.BarDiagram");
+ break;
+ case xlLine:
+ case xl3DLine:
+ case xlLineStacked:
+ case xlLineStacked100:
+ case xlLineMarkers:
+ case xlLineMarkersStacked:
+ case xlLineMarkersStacked100:
+ setDiagram( "com.sun.star.chart.LineDiagram");
+ break;
+ case xl3DArea:
+ case xlArea:
+ case xlAreaStacked:
+ case xlAreaStacked100:
+ case xl3DAreaStacked:
+ case xl3DAreaStacked100:
+ setDiagram( "com.sun.star.chart.AreaDiagram" );
+ break;
+ case xlDoughnut:
+ case xlDoughnutExploded:
+ setDiagram( "com.sun.star.chart.DonutDiagram" );
+ break;
+ case xlStockHLC:
+ case xlStockOHLC:
+ case xlStockVHLC:
+ case xlStockVOHLC:
+ setDiagram( "com.sun.star.chart.StockDiagram");
+ mxDiagramPropertySet->setPropertyValue( UPDOWN, uno::Any((_nChartType == xlStockOHLC) || (_nChartType == xlStockVOHLC)));
+ mxDiagramPropertySet->setPropertyValue( VOLUME, uno::Any((_nChartType == xlStockVHLC) || (_nChartType == xlStockVOHLC)));
+ break;
+
+ case xlPieOfPie: // not possible
+ case xlPieExploded: // SegmentOffset on ChartDataPointProperties -> get from XDiagram //How does Excel do this?
+ case xl3DPieExploded:
+ case xl3DPie:
+ case xlPie:
+ case xlBarOfPie: // not possible (Zoom pie)
+ setDiagram( "com.sun.star.chart.PieDiagram");
+ break;
+
+ case xlRadar:
+ case xlRadarMarkers:
+ case xlRadarFilled:
+ setDiagram( "com.sun.star.chart.NetDiagram");
+ break;
+ case xlXYScatter:
+ case xlBubble: // not possible
+ case xlBubble3DEffect: // not possible
+ case xlXYScatterLines:
+ case xlXYScatterLinesNoMarkers:
+ case xlXYScatterSmooth:
+ case xlXYScatterSmoothNoMarkers:
+ setDiagram( "com.sun.star.chart.XYDiagram");
+ switch(_nChartType)
+ {
+ case xlXYScatter:
+ case xlBubble: // not possible
+ case xlBubble3DEffect: // not possible
+ mxDiagramPropertySet->setPropertyValue(LINES, uno::Any( false ));
+ break;
+ case xlXYScatterLines:
+ case xlXYScatterLinesNoMarkers:
+ mxDiagramPropertySet->setPropertyValue(LINES, uno::Any( true ));
+ break;
+ case xlXYScatterSmooth:
+ case xlXYScatterSmoothNoMarkers:
+ mxDiagramPropertySet->setPropertyValue(SPLINETYPE, uno::Any( sal_Int32(1)));
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_CONVERSION), OUString() );
+ }
+
+ switch (_nChartType)
+ {
+ case xlLineMarkers:
+ case xlLineMarkersStacked:
+ case xlLineMarkersStacked100:
+ case xlRadarMarkers:
+ case xlXYScatterLines:
+ case xlXYScatterSmooth:
+ case xlXYScatter:
+ case xlBubble: // not possible
+ case xlBubble3DEffect: // not possible
+ mxDiagramPropertySet->setPropertyValue(SYMBOLTYPE, uno::Any( chart::ChartSymbolType::AUTO));
+ break;
+ default:
+ if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(SYMBOLTYPE))
+ {
+ mxDiagramPropertySet->setPropertyValue(SYMBOLTYPE, uno::Any(chart::ChartSymbolType::NONE));
+ }
+ break;
+ }
+
+ switch (_nChartType)
+ {
+ case xlConeCol:
+ case xlPyramidCol:
+ case xlCylinderCol:
+ case xl3DColumn:
+ case xlSurface: // not possible
+ case xlSurfaceWireframe:
+ case xlSurfaceTopView:
+ case xlSurfaceTopViewWireframe:
+ mxDiagramPropertySet->setPropertyValue(DEEP,uno::Any( true ));
+ break;
+ default:
+ if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(DEEP))
+ {
+ mxDiagramPropertySet->setPropertyValue(DEEP, uno::Any( false));
+ }
+ break;
+ }
+
+ switch (_nChartType)
+ {
+ case xlConeColClustered:
+ case xlConeColStacked:
+ case xlConeColStacked100:
+ case xlConeBarClustered:
+ case xlConeBarStacked:
+ case xlConeBarStacked100:
+ case xlConeCol:
+ mxDiagramPropertySet->setPropertyValue(SOLIDTYPE, uno::Any(chart::ChartSolidType::CONE));
+ break;
+ case xlPyramidColClustered:
+ case xlPyramidColStacked:
+ case xlPyramidColStacked100:
+ case xlPyramidBarClustered:
+ case xlPyramidBarStacked:
+ case xlPyramidBarStacked100:
+ case xlPyramidCol:
+ mxDiagramPropertySet->setPropertyValue(SOLIDTYPE, uno::Any(chart::ChartSolidType::PYRAMID));
+ break;
+ case xlCylinderColClustered:
+ case xlCylinderColStacked:
+ case xlCylinderColStacked100:
+ case xlCylinderBarClustered:
+ case xlCylinderBarStacked:
+ case xlCylinderBarStacked100:
+ case xlCylinderCol:
+ mxDiagramPropertySet->setPropertyValue(SOLIDTYPE, uno::Any(chart::ChartSolidType::CYLINDER));
+ break;
+ default:
+ if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(SOLIDTYPE))
+ {
+ mxDiagramPropertySet->setPropertyValue(SOLIDTYPE, uno::Any(chart::ChartSolidType::RECTANGULAR_SOLID));
+ }
+ break;
+ }
+
+ switch ( _nChartType)
+ {
+ case xlConeCol:
+ case xlConeColClustered:
+ case xlConeColStacked:
+ case xlConeColStacked100:
+ case xlPyramidColClustered:
+ case xlPyramidColStacked:
+ case xlPyramidColStacked100:
+ case xlCylinderColClustered:
+ case xlCylinderColStacked:
+ case xlCylinderColStacked100:
+ case xlColumnClustered:
+ case xlColumnStacked:
+ case xlColumnStacked100:
+ case xl3DColumnClustered:
+ case xl3DColumnStacked:
+ case xl3DColumnStacked100:
+ case xlSurface: // not possible
+ case xlSurfaceWireframe:
+ case xlSurfaceTopView:
+ case xlSurfaceTopViewWireframe:
+ mxDiagramPropertySet->setPropertyValue(VERTICAL, uno::Any( true));
+ break;
+ default:
+ if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(VERTICAL))
+ {
+ mxDiagramPropertySet->setPropertyValue(VERTICAL, uno::Any(false));
+ }
+ break;
+ }
+
+ switch (_nChartType)
+ {
+ case xlColumnStacked:
+ case xl3DColumnStacked:
+ case xlBarStacked:
+ case xl3DBarStacked:
+ case xlLineStacked:
+ case xlLineMarkersStacked:
+ case xlAreaStacked:
+ case xl3DAreaStacked:
+ case xlCylinderColStacked:
+ case xlCylinderBarStacked:
+ case xlConeColStacked:
+ case xlConeBarStacked:
+ case xlPyramidColStacked:
+ case xlPyramidBarStacked:
+ mxDiagramPropertySet->setPropertyValue(PERCENT, uno::Any( false ));
+ mxDiagramPropertySet->setPropertyValue(STACKED, uno::Any( true ));
+ break;
+ case xlPyramidColStacked100:
+ case xlPyramidBarStacked100:
+ case xlConeColStacked100:
+ case xlConeBarStacked100:
+ case xlCylinderBarStacked100:
+ case xlCylinderColStacked100:
+ case xl3DAreaStacked100:
+ case xlLineMarkersStacked100:
+ case xlAreaStacked100:
+ case xlLineStacked100:
+ case xl3DBarStacked100:
+ case xlBarStacked100:
+ case xl3DColumnStacked100:
+ case xlColumnStacked100:
+ mxDiagramPropertySet->setPropertyValue(STACKED, uno::Any( true));
+ mxDiagramPropertySet->setPropertyValue(PERCENT, uno::Any( true ));
+ break;
+ default:
+ mxDiagramPropertySet->setPropertyValue(PERCENT, uno::Any( false));
+ mxDiagramPropertySet->setPropertyValue(STACKED, uno::Any( false));
+ break;
+ }
+ switch (_nChartType)
+ {
+ case xl3DArea:
+ case xl3DAreaStacked:
+ case xl3DAreaStacked100:
+ case xl3DBarClustered:
+ case xl3DBarStacked:
+ case xl3DBarStacked100:
+ case xl3DColumn:
+ case xl3DColumnClustered:
+ case xl3DColumnStacked:
+ case xl3DColumnStacked100:
+ case xl3DLine:
+ case xl3DPie:
+ case xl3DPieExploded:
+ case xlConeColClustered:
+ case xlConeColStacked:
+ case xlConeColStacked100:
+ case xlConeBarClustered:
+ case xlConeBarStacked:
+ case xlConeBarStacked100:
+ case xlConeCol:
+ case xlPyramidColClustered:
+ case xlPyramidColStacked:
+ case xlPyramidColStacked100:
+ case xlPyramidBarClustered:
+ case xlPyramidBarStacked:
+ case xlPyramidBarStacked100:
+ case xlPyramidCol:
+ case xlCylinderColClustered:
+ case xlCylinderColStacked:
+ case xlCylinderColStacked100:
+ case xlCylinderBarClustered:
+ case xlCylinderBarStacked:
+ case xlCylinderBarStacked100:
+ case xlCylinderCol:
+ mxDiagramPropertySet->setPropertyValue(DIM3D, uno::Any( true));
+ break;
+ default:
+ if (mxDiagramPropertySet->getPropertySetInfo()->hasPropertyByName(DIM3D))
+ {
+ mxDiagramPropertySet->setPropertyValue(DIM3D, uno::Any( false));
+ }
+ break;
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+}
+
+void SAL_CALL
+ScVbaChart::Activate()
+{
+ // #TODO how are Chart sheets handled ( I know we don't even consider
+ // them in the worksheets/sheets collections ), but...???
+ // note: in vba for excel the parent of a Chart sheet is a workbook,
+ // e.g. 'ThisWorkbook'
+ uno::Reference< XHelperInterface > xParent( getParent() );
+ ScVbaChartObject* pChartObj = static_cast< ScVbaChartObject* >( xParent.get() );
+ if ( !pChartObj )
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), "no ChartObject as parent" );
+
+ pChartObj->Activate();
+
+}
+
+void SAL_CALL
+ScVbaChart::setSourceData( const css::uno::Reference< ::ooo::vba::excel::XRange >& _xCalcRange, const css::uno::Any& _aPlotBy )
+{
+ try
+ {
+ table::CellRangeAddress aSingleRangeAddress;
+
+ uno::Reference< sheet::XCellRangeAddressable > xAddressable( _xCalcRange->getCellRange(), uno::UNO_QUERY_THROW );
+ aSingleRangeAddress = xAddressable->getRangeAddress();
+
+ mxTableChart->setRanges({ aSingleRangeAddress } );
+
+ bool bsetRowHeaders = false;
+ bool bsetColumnHeaders = false;
+
+ ScVbaRange* pRange = static_cast< ScVbaRange* >( _xCalcRange.get() );
+ if ( pRange )
+ {
+ ScDocument& rDoc = pRange->getScDocument();
+ bsetRowHeaders = rDoc.HasRowHeader( static_cast< SCCOL >( aSingleRangeAddress.StartColumn ), static_cast< SCROW >( aSingleRangeAddress.StartRow ), static_cast< SCCOL >( aSingleRangeAddress.EndColumn ), static_cast< SCROW >( aSingleRangeAddress.EndRow ), static_cast< SCTAB >( aSingleRangeAddress.Sheet ) );
+ bsetColumnHeaders = rDoc.HasColHeader( static_cast< SCCOL >( aSingleRangeAddress.StartColumn ), static_cast< SCROW >( aSingleRangeAddress.StartRow ), static_cast< SCCOL >( aSingleRangeAddress.EndColumn ), static_cast< SCROW >( aSingleRangeAddress.EndRow ), static_cast< SCTAB >( aSingleRangeAddress.Sheet ));
+ }
+ mxTableChart->setHasRowHeaders(bsetRowHeaders);
+ mxTableChart->setHasColumnHeaders(bsetColumnHeaders);
+
+ if ((!bsetColumnHeaders) || (!bsetRowHeaders))
+ {
+ uno::Reference< chart::XChartDataArray > xChartDataArray( mxChartDocument->getData(), uno::UNO_QUERY_THROW );
+ if (!bsetColumnHeaders)
+ {
+ xChartDataArray->setColumnDescriptions( getDefaultSeriesDescriptions(xChartDataArray->getColumnDescriptions().getLength() ));
+ }
+ if (!bsetRowHeaders)
+ {
+ xChartDataArray->setRowDescriptions(getDefaultSeriesDescriptions(xChartDataArray->getRowDescriptions().getLength() ));
+ }
+ }
+
+ if ( _aPlotBy.hasValue() )
+ {
+ sal_Int32 nVal = 0;
+ _aPlotBy >>= nVal;
+ setPlotBy( nVal );
+ }
+ else
+ {
+ sal_Int32 nRows = aSingleRangeAddress.EndRow - aSingleRangeAddress.StartRow;
+ sal_Int32 nCols = aSingleRangeAddress.EndColumn - aSingleRangeAddress.StartColumn;
+ // AutoDetect emulation
+ if ( nRows > nCols )
+ setPlotBy( xlColumns );
+ else if ( nRows <= nCols )
+ setPlotBy( xlRows );
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+}
+
+uno::Sequence< OUString >
+ScVbaChart::getDefaultSeriesDescriptions( sal_Int32 _nCount )
+{
+ uno::Sequence< OUString > sDescriptions ( _nCount );
+ std::generate_n(sDescriptions.getArray(), _nCount,
+ [i = 1]() mutable -> OUString { return DEFAULTSERIESPREFIX + OUString::number(i++); });
+ return sDescriptions;
+}
+
+void
+ScVbaChart::setDefaultChartType()
+{
+ setChartType( xlColumnClustered );
+}
+
+void
+ScVbaChart::setPlotBy( ::sal_Int32 _nPlotBy )
+{
+ try
+ {
+ if ( !mxDiagramPropertySet.is() )
+ setDefaultChartType();
+ switch (_nPlotBy)
+ {
+ case xlRows:
+ mxDiagramPropertySet->setPropertyValue( DATAROWSOURCE, uno::Any( chart::ChartDataRowSource_ROWS ) );
+ break;
+ case xlColumns:
+ mxDiagramPropertySet->setPropertyValue( DATAROWSOURCE, uno::Any( chart::ChartDataRowSource_COLUMNS) );
+ break;
+ default:
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+}
+
+::sal_Int32 SAL_CALL
+ScVbaChart::getPlotBy( )
+{
+ try
+ {
+ chart::ChartDataRowSource aChartDataRowSource;
+ mxDiagramPropertySet->getPropertyValue(DATAROWSOURCE) >>= aChartDataRowSource;
+ if (aChartDataRowSource == chart::ChartDataRowSource_COLUMNS)
+ {
+ return xlColumns;
+ }
+ else
+ {
+ return xlRows;
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+}
+
+void
+ScVbaChart::setDiagram( const OUString& _sDiagramType )
+{
+ try
+ {
+ uno::Reference< lang::XMultiServiceFactory > xMSF( mxChartDocument, uno::UNO_QUERY_THROW );
+ uno::Reference< chart::XDiagram > xDiagram( xMSF->createInstance( _sDiagramType ), uno::UNO_QUERY_THROW );
+ mxChartDocument->setDiagram( xDiagram );
+ mxDiagramPropertySet.set( xDiagram, uno::UNO_QUERY_THROW );
+ }
+ catch ( const uno::Exception& )
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+}
+
+// #TODO find out why we have Location/getLocation? there is afaik no
+// Location property, just a Location function for the Chart object
+sal_Int32 SAL_CALL
+ScVbaChart::Location()
+{
+ return getLocation();
+}
+
+sal_Int32 SAL_CALL
+ScVbaChart::getLocation()
+{
+ return -1;
+}
+
+void SAL_CALL
+ScVbaChart::setLocation( ::sal_Int32 /*where*/, const css::uno::Any& /*Name*/ )
+{
+ // Helper api just stubs out the code <shrug>
+ // #TODO come back and make sense out of this
+// String sheetName = null;
+//
+// if ((name != null) && name instanceof String) {
+// sheetName = (String) name;
+// }
+// XSpreadsheetDocument xShDoc = (XSpreadsheetDocument) UnoRuntime.queryInterface( XSpreadsheetDocument.class,getXModel() );
+// com.sun.star.sheet.XSpreadsheets xSheets = xShDoc.Sheets();
+//
+// switch (where) {
+// case ClLocationType.clLocationAsObject_value: //{
+//
+// if (sheetName == null) {
+// DebugHelper.writeInfo("Can't embed in Chart without knowing SheetName");
+// return;
+// }
+//
+// try {
+// Any any = (Any) xSheets.getByName(sheetName);
+// chartSheet = (XSpreadsheet) any.getObject();
+//
+// // chartSheet = (XSpreadsheet) xSheets.getByName( sheetName );
+// } catch (NoSuchElementException e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+//
+// return;
+// } catch (WrappedTargetException e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+//
+// return;
+// } catch (java.lang.Exception e) {
+// e.printStackTrace();
+// }
+//
+// XTableChartsSupplier xTCS = (XTableChartsSupplier) UnoRuntime.queryInterface( XTableChartsSupplier.class, chartSheet);
+// XTableCharts xTableCharts = xTCS.getCharts();
+// XIndexAccess xIA = (XIndexAccess) UnoRuntime.queryInterface( XIndexAccess.class, xTableCharts);
+// int numCharts = xIA.getCount();
+// chartName = "Chart " + (numCharts + 1);
+//
+// //}
+// break;
+//
+// case ClLocationType.clLocationAsNewSheet_value:
+// case ClLocationType.clLocationAutomatic_value:default: //{
+// chartName = "Chart 1"; // Since it's a new sheet, it's the first on it...
+//
+// XIndexAccess xSheetIA = (XIndexAccess) UnoRuntime.queryInterface( XIndexAccess.class, xSheets);
+//
+// short newSheetNum = (short) (xSheetIA.getCount() + 1);
+//
+// if (sheetName == null){
+// sheetName = "ChartSheet " + newSheetNum; // Why not?
+// }
+// // DPK TODO : Probably should use Sheets to create this!
+// xSheets.insertNewByName(sheetName, newSheetNum);
+//
+// try {
+// chartSheet =
+// (XSpreadsheet) xSheets.getByName(sheetName);
+// } catch (NoSuchElementException e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+//
+// return;
+// } catch (WrappedTargetException e) {
+// // TODO Auto-generated catch block
+// e.printStackTrace();
+//
+// return;
+// }
+//
+// //}
+// break;
+// }
+//
+// // Last thing should be a call to createChartForReal(), one of them
+// // should succeed.
+// createChartForReal();
+
+}
+
+sal_Bool SAL_CALL
+ScVbaChart::getHasTitle( )
+{
+ bool bHasTitle = false;
+ try
+ {
+ mxChartPropertySet->getPropertyValue(HASMAINTITLE) >>= bHasTitle;
+ }
+ catch (const uno::Exception&)
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+ return bHasTitle;
+}
+
+void SAL_CALL
+ScVbaChart::setHasTitle( sal_Bool bTitle )
+{
+ try
+ {
+ mxChartPropertySet->setPropertyValue(HASMAINTITLE, uno::Any( bTitle ));
+ }
+ catch (const uno::Exception&)
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+
+}
+
+sal_Bool SAL_CALL
+ScVbaChart::getHasLegend( )
+{
+ bool bHasLegend = false;
+ try
+ {
+ mxChartPropertySet->getPropertyValue(HASLEGEND) >>= bHasLegend;
+ }
+ catch (const uno::Exception&)
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+ return bHasLegend;
+}
+
+void SAL_CALL
+ScVbaChart::setHasLegend( sal_Bool bLegend )
+{
+ try
+ {
+ mxChartPropertySet->setPropertyValue(HASLEGEND, uno::Any(bLegend));
+ }
+ catch (const uno::Exception&)
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+}
+
+uno::Reference< excel::XChartTitle > SAL_CALL
+ScVbaChart::getChartTitle( )
+{
+ uno::Reference< drawing::XShape > xTitleShape = mxChartDocument->getTitle();
+ // #TODO check parent
+ return new ScVbaChartTitle(this, mxContext, xTitleShape);
+}
+
+uno::Any SAL_CALL
+ScVbaChart::Axes( const uno::Any& Type, const uno::Any& AxisGroup )
+{
+ // mmm chart probably is the parent, #TODO check parent
+ uno::Reference< excel::XAxes > xAxes = new ScVbaAxes( this, mxContext, this );
+ if ( !Type.hasValue() )
+ return uno::Any( xAxes );
+ return xAxes->Item( Type, AxisGroup );
+}
+bool
+ScVbaChart::is3D()
+{
+ // #TODO perhaps provide limited Debughelper functionality
+ bool is3d = false;
+ mxDiagramPropertySet->getPropertyValue(DIM3D) >>= is3d;
+ return is3d;
+}
+
+sal_Int32
+ScVbaChart::getStackedType( sal_Int32 _nStacked, sal_Int32 _n100PercentStacked, sal_Int32 _nUnStacked )
+{
+ // #TODO perhaps provide limited Debughelper functionality
+ if (isStacked())
+ {
+ if (is100PercentStacked())
+ return _n100PercentStacked;
+ else
+ return _nStacked;
+ }
+ else
+ return _nUnStacked;
+}
+
+bool
+ScVbaChart::isStacked()
+{
+ // #TODO perhaps provide limited Debughelper functionality
+ bool bStacked = false;
+ mxDiagramPropertySet->getPropertyValue(STACKED) >>= bStacked;
+ return bStacked;
+}
+
+bool
+ScVbaChart::is100PercentStacked()
+{
+ // #TODO perhaps provide limited Debughelper functionality
+ bool b100Percent = false;
+ mxDiagramPropertySet->getPropertyValue(PERCENT) >>= b100Percent;
+ return b100Percent;
+}
+
+sal_Int32
+ScVbaChart::getSolidType(sal_Int32 _nDeep, sal_Int32 _nVertiStacked, sal_Int32 _nVerti100PercentStacked, sal_Int32 _nVertiUnStacked, sal_Int32 _nHoriStacked, sal_Int32 _nHori100PercentStacked, sal_Int32 _nHoriUnStacked)
+{
+ try
+ {
+ bool bIsVertical = true;
+ mxDiagramPropertySet->getPropertyValue(VERTICAL) >>= bIsVertical;
+ bool bIsDeep = false;
+ mxDiagramPropertySet->getPropertyValue(DEEP) >>= bIsDeep;
+
+ if (bIsDeep)
+ {
+ return _nDeep;
+ }
+ else
+ {
+ if (bIsVertical)
+ {
+ return getStackedType(_nVertiStacked, _nVerti100PercentStacked, _nVertiUnStacked);
+ }
+ else
+ {
+ return getStackedType(_nHoriStacked, _nHori100PercentStacked, _nHoriUnStacked);
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+}
+
+sal_Int32
+ScVbaChart::getStockUpDownValue(sal_Int32 _nUpDown, sal_Int32 _nNotUpDown)
+{
+ try
+ {
+ bool bUpDown = false;
+ mxDiagramPropertySet->getPropertyValue(UPDOWN) >>= bUpDown;
+ if (bUpDown)
+ {
+ return _nUpDown;
+ }
+ else
+ {
+ return _nNotUpDown;
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+}
+
+bool
+ScVbaChart::hasMarkers()
+{
+ bool bHasMarkers = false;
+ try
+ {
+ sal_Int32 nSymbol=0;
+ mxDiagramPropertySet->getPropertyValue(SYMBOLTYPE) >>= nSymbol;
+ bHasMarkers = nSymbol != chart::ChartSymbolType::NONE;
+ }
+ catch (const uno::Exception&)
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+ return bHasMarkers;
+}
+
+sal_Int32
+ScVbaChart::getMarkerType(sal_Int32 _nWithMarkers, sal_Int32 _nWithoutMarkers)
+{
+ if (hasMarkers())
+ return _nWithMarkers;
+ return _nWithoutMarkers;
+}
+
+void
+ScVbaChart::assignDiagramAttributes()
+{
+ xAxisXSupplier.set( mxDiagramPropertySet, uno::UNO_QUERY_THROW );
+ xAxisYSupplier.set( mxDiagramPropertySet, uno::UNO_QUERY_THROW );
+ xAxisZSupplier.set( mxDiagramPropertySet, uno::UNO_QUERY_THROW );
+ xTwoAxisXSupplier.set( mxDiagramPropertySet, uno::UNO_QUERY_THROW );
+ xTwoAxisYSupplier.set( mxDiagramPropertySet, uno::UNO_QUERY_THROW );
+}
+
+uno::Reference< beans::XPropertySet >
+ScVbaChart::getAxisPropertySet(sal_Int32 _nAxisType, sal_Int32 _nAxisGroup)
+{
+ assignDiagramAttributes();
+ uno::Reference< beans::XPropertySet > xAxisProps;
+ switch(_nAxisType)
+ {
+ case xlCategory:
+ if (_nAxisGroup == xlPrimary)
+ {
+ xAxisProps = xAxisXSupplier->getXAxis();
+ }
+ else if (_nAxisGroup == xlSecondary)
+ {
+ xAxisProps = xTwoAxisXSupplier->getSecondaryXAxis();
+ }
+ break;
+ case xlSeriesAxis:
+ xAxisProps = xAxisZSupplier->getZAxis();
+ break;
+ case xlValue:
+ if (_nAxisGroup == xlPrimary)
+ xAxisProps = xAxisYSupplier->getYAxis();
+ else if (_nAxisGroup == xlSecondary)
+ xAxisProps = xTwoAxisYSupplier->getSecondaryYAxis();
+ break;
+ default:
+ return xAxisProps;
+ }
+ return xAxisProps;
+}
+
+OUString
+ScVbaChart::getServiceImplName()
+{
+ return "ScVbaChart";
+}
+
+uno::Sequence< OUString >
+ScVbaChart::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Chart"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbachart.hxx b/sc/source/ui/vba/vbachart.hxx
new file mode 100644
index 000000000..eedf13b9f
--- /dev/null
+++ b/sc/source/ui/vba/vbachart.hxx
@@ -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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/table/XTableChart.hpp>
+#include <com/sun/star/chart/XChartDocument.hpp>
+#include <com/sun/star/chart/XAxisXSupplier.hpp>
+#include <com/sun/star/chart/XAxisYSupplier.hpp>
+#include <com/sun/star/chart/XAxisZSupplier.hpp>
+#include <com/sun/star/chart/XTwoAxisXSupplier.hpp>
+#include <com/sun/star/chart/XTwoAxisYSupplier.hpp>
+#include <ooo/vba/excel/XChart.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl<ov::excel::XChart > ChartImpl_BASE;
+
+class ScVbaChart : public ChartImpl_BASE
+{
+friend class ScVbaAxis;
+
+ css::uno::Reference< css::chart::XChartDocument > mxChartDocument;
+ css::uno::Reference< css::table::XTableChart > mxTableChart;
+ css::uno::Reference< css::beans::XPropertySet > mxDiagramPropertySet;
+ css::uno::Reference< css::beans::XPropertySet > mxChartPropertySet;
+ css::uno::Reference< css::chart::XAxisXSupplier > xAxisXSupplier;
+ css::uno::Reference< css::chart::XAxisYSupplier> xAxisYSupplier;
+ css::uno::Reference< css::chart::XAxisZSupplier > xAxisZSupplier;
+ css::uno::Reference< css::chart::XTwoAxisXSupplier > xTwoAxisXSupplier;
+ css::uno::Reference< css::chart::XTwoAxisYSupplier > xTwoAxisYSupplier;
+
+ static css::uno::Sequence< OUString > getDefaultSeriesDescriptions( sal_Int32 nCount );
+ /// @throws css::script::BasicErrorException
+ void setDefaultChartType() ;
+ /// @throws css::script::BasicErrorException
+ void setDiagram( const OUString& _sDiagramType);
+ /// @throws css::uno::RuntimeException
+ bool isStacked();
+ /// @throws css::uno::RuntimeException
+ bool is100PercentStacked();
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getStackedType( sal_Int32 _nStacked, sal_Int32 _n100PercentStacked, sal_Int32 _nUnStacked );
+ /// @throws css::script::BasicErrorException
+ sal_Int32 getSolidType(sal_Int32 _nDeep, sal_Int32 _nVertiStacked, sal_Int32 _nVerti100PercentStacked, sal_Int32 _nVertiUnStacked, sal_Int32 _nHoriStacked, sal_Int32 _nHori100PercentStacked, sal_Int32 _nHoriUnStacked);
+ /// @throws css::script::BasicErrorException
+ sal_Int32 getStockUpDownValue(sal_Int32 _nUpDown, sal_Int32 _nNotUpDown);
+ /// @throws css::script::BasicErrorException
+ bool hasMarkers();
+ /// @throws css::script::BasicErrorException
+ sal_Int32 getMarkerType(sal_Int32 _nWithMarkers, sal_Int32 _nWithoutMarkers);
+ void assignDiagramAttributes();
+public:
+ ScVbaChart( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::lang::XComponent >& _xChartComponent, const css::uno::Reference< css::table::XTableChart >& _xTableChart );
+
+ // Non-interface
+ const css::uno::Reference< css::beans::XPropertySet >& xDiagramPropertySet() const { return mxDiagramPropertySet; }
+ /// @throws css::uno::RuntimeException
+ bool is3D();
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::beans::XPropertySet > getAxisPropertySet(sal_Int32 _nAxisType, sal_Int32 _nAxisGroup);
+ // Methods
+ virtual OUString SAL_CALL getName() override;
+ virtual css::uno::Any SAL_CALL SeriesCollection(const css::uno::Any&) override;
+ virtual ::sal_Int32 SAL_CALL getChartType() override;
+ virtual void SAL_CALL setChartType( ::sal_Int32 _charttype ) override;
+ virtual void SAL_CALL Activate( ) override;
+ virtual void SAL_CALL setSourceData( const css::uno::Reference< ::ooo::vba::excel::XRange >& range, const css::uno::Any& PlotBy ) override;
+ virtual ::sal_Int32 SAL_CALL Location( ) override;
+ virtual ::sal_Int32 SAL_CALL getLocation( ) override;
+ virtual void SAL_CALL setLocation( ::sal_Int32 where, const css::uno::Any& Name ) override;
+ virtual sal_Bool SAL_CALL getHasTitle( ) override;
+ virtual void SAL_CALL setHasTitle( sal_Bool bTitle ) override;
+ virtual sal_Bool SAL_CALL getHasLegend( ) override;
+ virtual void SAL_CALL setHasLegend( sal_Bool bLegend ) override;
+ virtual void SAL_CALL setPlotBy( ::sal_Int32 xlRowCol ) override;
+ virtual ::sal_Int32 SAL_CALL getPlotBy( ) override;
+ virtual css::uno::Reference< ov::excel::XChartTitle > SAL_CALL getChartTitle( ) override;
+ virtual css::uno::Any SAL_CALL Axes( const css::uno::Any& Type, const css::uno::Any& AxisGroup ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbachartobject.cxx b/sc/source/ui/vba/vbachartobject.cxx
new file mode 100644
index 000000000..5246a9040
--- /dev/null
+++ b/sc/source/ui/vba/vbachartobject.cxx
@@ -0,0 +1,147 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "vbachart.hxx"
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/script/BasicErrorException.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <basic/sberrors.hxx>
+#include "vbachartobject.hxx"
+#include "vbachartobjects.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+constexpr OUStringLiteral PERSIST_NAME(u"PersistName");
+
+ScVbaChartObject::ScVbaChartObject( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::table::XTableChart >& _xTableChart, const css::uno::Reference< css::drawing::XDrawPageSupplier >& _xDrawPageSupplier ) : ChartObjectImpl_BASE( _xParent, _xContext ), xTableChart( _xTableChart ), xDrawPageSupplier( _xDrawPageSupplier )
+{
+ xDrawPage = xDrawPageSupplier->getDrawPage();
+ xEmbeddedObjectSupplier.set( xTableChart, uno::UNO_QUERY_THROW );
+ xNamed.set( xTableChart, uno::UNO_QUERY_THROW );
+ sPersistName = getPersistName();
+ xShape = setShape();
+ setName(sPersistName);
+ oShapeHelper.reset(new ShapeHelper(xShape));
+}
+
+OUString const & ScVbaChartObject::getPersistName()
+{
+ if ( sPersistName.isEmpty() )
+ sPersistName = xNamed->getName();
+ return sPersistName;
+}
+
+uno::Reference< drawing::XShape >
+ScVbaChartObject::setShape()
+{
+ try
+ {
+ sal_Int32 nItems = xDrawPage->getCount();
+ for (int i = 0; i < nItems; i++)
+ {
+ xShape.set( xDrawPage->getByIndex(i), uno::UNO_QUERY_THROW );
+ if (xShape->getShapeType() == "com.sun.star.drawing.OLE2Shape")
+ {
+ uno::Reference< beans::XPropertySet > xShapePropertySet(xShape, uno::UNO_QUERY_THROW );
+ OUString sName;
+ xShapePropertySet->getPropertyValue(PERSIST_NAME ) >>=sName;
+ if ( sName == sPersistName )
+ {
+ xNamedShape.set( xShape, uno::UNO_QUERY_THROW );
+ return xShape;
+ }
+ }
+ }
+ }
+ catch (uno::Exception& )
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+ return nullptr;
+}
+
+void SAL_CALL
+ScVbaChartObject::setName( const OUString& sName )
+{
+ xNamedShape->setName(sName);
+}
+
+OUString SAL_CALL
+ScVbaChartObject::getName()
+{
+ return xNamedShape->getName();
+}
+
+void SAL_CALL
+ScVbaChartObject::Delete()
+{
+ // parent of this object is sheet
+ uno::Reference< excel::XWorksheet > xParent( getParent(), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XChartObjects > xColl( xParent->ChartObjects( uno::Any() ), uno::UNO_QUERY_THROW );
+ ScVbaChartObjects* pChartObjectsImpl = static_cast< ScVbaChartObjects* >( xColl.get() );
+ if (!pChartObjectsImpl)
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), "Parent is not ChartObjects" );
+
+ pChartObjectsImpl->removeByName( getPersistName() );
+
+}
+
+void
+ScVbaChartObject::Activate()
+{
+ try
+ {
+ // #TODO #FIXME should be ThisWorkbook or equivalent, or in
+ // fact probably the chart object should be created with
+ // the XModel owner
+ //uno::Reference< view::XSelectionSupplier > xSelectionSupplier( getXModel().getCurrentController());
+ uno::Reference< view::XSelectionSupplier > xSelectionSupplier( getCurrentExcelDoc(mxContext)->getCurrentController(), uno::UNO_QUERY_THROW );
+ xSelectionSupplier->select(uno::Any(xShape));
+ }
+ catch (uno::Exception& )
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), "ChartObject Activate internal error" );
+ }
+}
+
+uno::Reference< excel::XChart > SAL_CALL
+ScVbaChartObject::getChart()
+{
+ return new ScVbaChart( this, mxContext, xEmbeddedObjectSupplier->getEmbeddedObject(), xTableChart );
+}
+
+OUString
+ScVbaChartObject::getServiceImplName()
+{
+ return "ScVbaChartObject";
+}
+
+uno::Sequence< OUString >
+ScVbaChartObject::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.ChartObject"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbachartobject.hxx b/sc/source/ui/vba/vbachartobject.hxx
new file mode 100644
index 000000000..85a014052
--- /dev/null
+++ b/sc/source/ui/vba/vbachartobject.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 <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/table/XTableChart.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/document/XEmbeddedObjectSupplier.hpp>
+#include <ooo/vba/excel/XChartObject.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+#include <memory>
+
+typedef InheritedHelperInterfaceWeakImpl<ov::excel::XChartObject > ChartObjectImpl_BASE;
+
+class ScVbaChartObject : public ChartObjectImpl_BASE
+{
+
+ css::uno::Reference< css::table::XTableChart > xTableChart;
+ css::uno::Reference< css::document::XEmbeddedObjectSupplier > xEmbeddedObjectSupplier;
+ css::uno::Reference< css::drawing::XDrawPageSupplier > xDrawPageSupplier;
+ css::uno::Reference< css::drawing::XDrawPage > xDrawPage;
+ css::uno::Reference< css::drawing::XShape > xShape;
+ css::uno::Reference< css::container::XNamed > xNamed;
+ OUString sPersistName;
+ std::unique_ptr<ov::ShapeHelper> oShapeHelper;
+ css::uno::Reference< css::container::XNamed > xNamedShape;
+ OUString const & getPersistName();
+ /// @throws css::script::BasicErrorException
+ css::uno::Reference< css::drawing::XShape > setShape();
+public:
+ ScVbaChartObject( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::table::XTableChart >& _xTableChart, const css::uno::Reference< css::drawing::XDrawPageSupplier >& _xDrawPageSupplier );
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName( const OUString& sName ) override;
+ virtual css::uno::Reference< ov::excel::XChart > SAL_CALL getChart() override;
+ virtual void SAL_CALL Delete() override;
+ /// @throws css::script::BasicErrorException
+ void Activate();
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbachartobjects.cxx b/sc/source/ui/vba/vbachartobjects.cxx
new file mode 100644
index 000000000..674c92511
--- /dev/null
+++ b/sc/source/ui/vba/vbachartobjects.cxx
@@ -0,0 +1,206 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/table/XTableChartsSupplier.hpp>
+#include <com/sun/star/table/XTableChart.hpp>
+#include <com/sun/star/script/BasicErrorException.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <ooo/vba/excel/XlChartType.hpp>
+
+#include "vbachartobjects.hxx"
+#include "vbachartobject.hxx"
+#include <docsh.hxx>
+#include <cellsuno.hxx>
+
+#include <string_view>
+#include <vector>
+#include <basic/sberrors.hxx>
+#include <comphelper/sequence.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+namespace {
+
+class ChartObjectEnumerationImpl : public EnumerationHelperImpl
+{
+ uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier;
+
+public:
+ /// @throws uno::RuntimeException
+ ChartObjectEnumerationImpl( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, const uno::Reference< drawing::XDrawPageSupplier >& _xDrawPageSupplier, const uno::Reference< XHelperInterface >& _xParent ) : EnumerationHelperImpl( _xParent, xContext, xEnumeration ), xDrawPageSupplier( _xDrawPageSupplier ) {}
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ uno::Any ret;
+
+ try
+ {
+ uno::Reference< table::XTableChart > xTableChart( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW );
+ // parent Object is sheet
+ ret <<= uno::Reference< excel::XChartObject > ( new ScVbaChartObject( m_xParent, m_xContext, xTableChart, xDrawPageSupplier ) );
+ }
+ catch (const lang::WrappedTargetException&)
+ {
+ throw;
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ throw;
+ }
+ catch (const uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception&)
+ {
+ css::uno::Any anyEx(cppu::getCaughtException());
+ throw lang::WrappedTargetException(
+ "Error creating ScVbaChartObject!",
+ static_cast < OWeakObject * > ( this ),
+ anyEx );
+ }
+ return ret;
+ }
+};
+
+}
+
+ScVbaChartObjects::ScVbaChartObjects( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::table::XTableCharts >& _xTableCharts, const uno::Reference< drawing::XDrawPageSupplier >& _xDrawPageSupplier ) : ChartObjects_BASE(_xParent, _xContext, css::uno::Reference< css::container::XIndexAccess >( _xTableCharts, css::uno::UNO_QUERY ) ), xTableCharts( _xTableCharts ) , xDrawPageSupplier( _xDrawPageSupplier )
+{
+
+}
+
+void
+ScVbaChartObjects::removeByName(const OUString& _sChartName)
+{
+ xTableCharts->removeByName( _sChartName );
+}
+
+uno::Sequence< OUString >
+ScVbaChartObjects::getChartObjectNames() const
+{
+ uno::Sequence< OUString > sChartNames;
+ try
+ {
+ // c++ hackery
+ uno::Reference< uno::XInterface > xIf( xDrawPageSupplier, uno::UNO_QUERY_THROW );
+ ScCellRangesBase* pUno= dynamic_cast< ScCellRangesBase* >( xIf.get() );
+ ScDocShell* pDocShell = nullptr;
+ if ( !pUno )
+ throw uno::RuntimeException("Failed to obtain the impl class from the drawpage" );
+ pDocShell = pUno->GetDocShell();
+ if ( !pDocShell )
+ throw uno::RuntimeException("Failed to obtain the docshell implclass" );
+
+ uno::Reference< sheet::XSpreadsheetDocument > xSpreadsheetDocument( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheets > xSpreadsheets = xSpreadsheetDocument->getSheets();
+ std::vector< OUString > aChartNamesVector;
+
+ const uno::Sequence< OUString > sSheetNames = xSpreadsheets->getElementNames();
+ for (const auto& rSheetName : sSheetNames)
+ {
+ uno::Reference< table::XTableChartsSupplier > xLocTableChartsSupplier( xSpreadsheets->getByName(rSheetName), uno::UNO_QUERY_THROW );
+ const uno::Sequence< OUString > scurchartnames = xLocTableChartsSupplier->getCharts()->getElementNames();
+ aChartNamesVector.insert( aChartNamesVector.end(), scurchartnames.begin(), scurchartnames.end() );
+ }
+ sChartNames = comphelper::containerToSequence( aChartNamesVector );
+ }
+ catch (uno::Exception& )
+ {
+ throw script::BasicErrorException( OUString(), uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+ return sChartNames;
+}
+
+// XChartObjects
+uno::Any SAL_CALL
+ScVbaChartObjects::Add( double _nX, double _nY, double _nWidth, double _nHeight )
+{
+ try
+ {
+ uno::Sequence< table::CellRangeAddress > aCellRangeAddress( 1 );
+ awt::Rectangle aRectangle;
+ aRectangle.X = Millimeter::getInHundredthsOfOneMillimeter(_nX);
+ aRectangle.Y = Millimeter::getInHundredthsOfOneMillimeter(_nY);
+ aRectangle.Width = Millimeter::getInHundredthsOfOneMillimeter(_nWidth);
+ aRectangle.Height = Millimeter::getInHundredthsOfOneMillimeter(_nHeight);
+ // Note the space at the end of the stem ("Chart "). In ChartSheets only "Chart" is the stem
+ OUString sPersistChartName = ContainerUtilities::getUniqueName( getChartObjectNames(), "Chart " , std::u16string_view(), 1);
+ xTableCharts->addNewByName(sPersistChartName, aRectangle, aCellRangeAddress, true, false );
+ uno::Reference< excel::XChartObject > xChartObject( getItemByStringIndex( sPersistChartName ), uno::UNO_QUERY_THROW );
+ xChartObject->getChart()->setChartType(excel::XlChartType::xlColumnClustered);
+ return uno::Any( xChartObject );
+ }
+ catch (const uno::Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("sc");
+ }
+ return aNULL();
+}
+void SAL_CALL ScVbaChartObjects::Delete( )
+{
+ const uno::Sequence< OUString > sChartNames = xTableCharts->getElementNames();
+ for (const auto& rChartName : sChartNames)
+ removeByName(rChartName);
+}
+
+// XEnumerationAccess
+
+uno::Reference< container::XEnumeration >
+ScVbaChartObjects::createEnumeration()
+{
+ css::uno::Reference< container::XEnumerationAccess > xEnumAccess( xTableCharts, uno::UNO_QUERY_THROW );
+ return new ChartObjectEnumerationImpl( mxContext, xEnumAccess->createEnumeration(), xDrawPageSupplier, getParent() /* sheet */);
+}
+
+// XElementAccess
+
+uno::Type
+ScVbaChartObjects::getElementType()
+{
+ return cppu::UnoType<excel::XChartObject>::get();
+}
+
+// ScVbaCollectionBaseImpl
+uno::Any
+ScVbaChartObjects::createCollectionObject( const css::uno::Any& aSource )
+{
+ uno::Reference< table::XTableChart > xTableChart( aSource, uno::UNO_QUERY_THROW );
+ // correct parent object is sheet
+ return uno::Any( uno::Reference< excel::XChartObject > ( new ScVbaChartObject( getParent(), mxContext, xTableChart, xDrawPageSupplier ) ) );
+}
+
+OUString
+ScVbaChartObjects::getServiceImplName()
+{
+ return "ScVbaChartObjects";
+}
+
+css::uno::Sequence<OUString>
+ScVbaChartObjects::getServiceNames()
+{
+ static uno::Sequence< OUString > const sNames
+ {
+ "ooo.vba.excel.ChartObjects"
+ };
+ return sNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbachartobjects.hxx b/sc/source/ui/vba/vbachartobjects.hxx
new file mode 100644
index 000000000..ce116e734
--- /dev/null
+++ b/sc/source/ui/vba/vbachartobjects.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 <ooo/vba/excel/XChartObjects.hpp>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace com::sun::star::container { class XEnumeration; }
+namespace com::sun::star::drawing { class XDrawPageSupplier; }
+namespace com::sun::star::table { class XTableCharts; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+typedef CollTestImplHelper< ov::excel::XChartObjects > ChartObjects_BASE;
+
+class ScVbaChartObjects : public ChartObjects_BASE
+{
+
+ css::uno::Reference< css::table::XTableCharts > xTableCharts;
+ css::uno::Reference< css::drawing::XDrawPageSupplier > xDrawPageSupplier;
+ // method associated with populating the hashmap ( I'm not convinced this is necessary )
+ //css::uno::Reference< ov::excel::XChartObject > putByPersistName( const rtl:::OUString& _sPersistChartName );
+public:
+ ScVbaChartObjects( const css::uno::Reference< ov::XHelperInterface >& _xParent, const css::uno::Reference< css::uno::XComponentContext >& _xContext, const css::uno::Reference< css::table::XTableCharts >& _xTableCharts, const css::uno::Reference< css::drawing::XDrawPageSupplier >& _xDrawPageSupplier );
+
+ /// @throws css::script::BasicErrorException
+ css::uno::Sequence< OUString > getChartObjectNames() const;
+ void removeByName(const OUString& _sChartName);
+
+ // XChartObjects
+ virtual css::uno::Any SAL_CALL Add( double Left, double Top, double Width, double Height ) override;
+ virtual void SAL_CALL Delete( ) override;
+ // XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ // ScVbaCollectionBaseImpl
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+ // ChartObjects_BASE
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbacharttitle.cxx b/sc/source/ui/vba/vbacharttitle.cxx
new file mode 100644
index 000000000..2e881fd61
--- /dev/null
+++ b/sc/source/ui/vba/vbacharttitle.cxx
@@ -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 .
+ */
+#include "vbacharttitle.hxx"
+#include <comphelper/sequence.hxx>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+ScVbaChartTitle::ScVbaChartTitle( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< drawing::XShape >& _xTitleShape ) : ChartTitleBase( xParent, xContext, _xTitleShape )
+{
+}
+
+OUString
+ScVbaChartTitle::getServiceImplName()
+{
+ return "ScVbaChartTitle";
+}
+
+uno::Sequence< OUString >
+ScVbaChartTitle::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames = comphelper::concatSequences(
+ ChartTitleBase::getServiceNames(),
+ uno::Sequence< OUString > { "ooo.vba.excel.Chart" } );
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbacharttitle.hxx b/sc/source/ui/vba/vbacharttitle.hxx
new file mode 100644
index 000000000..2b816357e
--- /dev/null
+++ b/sc/source/ui/vba/vbacharttitle.hxx
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+#include "vbatitle.hxx"
+#include <cppuhelper/implbase.hxx>
+#include <ooo/vba/excel/XChartTitle.hpp>
+
+typedef TitleImpl< cppu::WeakImplHelper< ov::excel::XChartTitle > > ChartTitleBase;
+
+class ScVbaChartTitle : public ChartTitleBase
+{
+public:
+ ScVbaChartTitle( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::drawing::XShape >& _xTitleShape );
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbacomment.cxx b/sc/source/ui/vba/vbacomment.cxx
new file mode 100644
index 000000000..a9b1cf7c4
--- /dev/null
+++ b/sc/source/ui/vba/vbacomment.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 "vbacomment.hxx"
+
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSheetAnnotationAnchor.hpp>
+#include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp>
+#include <com/sun/star/sheet/XSheetAnnotationShapeSupplier.hpp>
+#include <com/sun/star/sheet/XSheetCellRange.hpp>
+#include <com/sun/star/sheet/XCellAddressable.hpp>
+#include <com/sun/star/table/CellAddress.hpp>
+#include <com/sun/star/table/XCell.hpp>
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <com/sun/star/text/XTextCursor.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <ooo/vba/office/MsoShapeType.hpp>
+
+#include <vbahelper/vbashape.hxx>
+#include <sal/log.hxx>
+#include "vbacomments.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+ScVbaComment::ScVbaComment(
+ const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< frame::XModel >& xModel,
+ const uno::Reference< table::XCellRange >& xRange ) :
+ ScVbaComment_BASE( xParent, xContext ),
+ mxModel( xModel, uno::UNO_SET_THROW ),
+ mxRange( xRange )
+{
+ if ( !xRange.is() )
+ throw lang::IllegalArgumentException("range is not set ", uno::Reference< uno::XInterface >() , 1 );
+ getAnnotation();
+}
+
+// private helper functions
+
+uno::Reference< sheet::XSheetAnnotation >
+ScVbaComment::getAnnotation()
+{
+ uno::Reference< table::XCell > xCell( mxRange->getCellByPosition(0, 0), uno::UNO_SET_THROW );
+ uno::Reference< sheet::XSheetAnnotationAnchor > xAnnoAnchor( xCell, uno::UNO_QUERY_THROW );
+ return uno::Reference< sheet::XSheetAnnotation > ( xAnnoAnchor->getAnnotation(), uno::UNO_SET_THROW );
+}
+
+uno::Reference< sheet::XSheetAnnotations >
+ScVbaComment::getAnnotations() const
+{
+ uno::Reference< sheet::XSheetCellRange > xSheetCellRange(mxRange, ::uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet();
+ uno::Reference< sheet::XSheetAnnotationsSupplier > xAnnosSupp( xSheet, uno::UNO_QUERY_THROW );
+
+ return uno::Reference< sheet::XSheetAnnotations > ( xAnnosSupp->getAnnotations(), uno::UNO_SET_THROW );
+}
+
+sal_Int32
+ScVbaComment::getAnnotationIndex()
+{
+ uno::Reference< sheet::XSheetAnnotations > xAnnos = getAnnotations();
+ table::CellAddress aAddress = getAnnotation()->getPosition();
+
+ sal_Int32 aIndex = 0;
+ sal_Int32 aCount = xAnnos->getCount();
+
+ for ( ; aIndex < aCount ; aIndex++ )
+ {
+ uno::Reference< sheet::XSheetAnnotation > xAnno( xAnnos->getByIndex( aIndex ), uno::UNO_QUERY_THROW );
+ table::CellAddress aAnnoAddress = xAnno->getPosition();
+
+ if ( aAnnoAddress.Column == aAddress.Column && aAnnoAddress.Row == aAddress.Row && aAnnoAddress.Sheet == aAddress.Sheet )
+ {
+ SAL_INFO("sc.ui", "terminating search, index is " << aIndex);
+ break;
+ }
+ }
+ SAL_INFO("sc.ui", "returning index is " << aIndex);
+
+ return aIndex;
+}
+
+uno::Reference< excel::XComment >
+ScVbaComment::getCommentByIndex( sal_Int32 Index )
+{
+ uno::Reference< container::XIndexAccess > xIndexAccess( getAnnotations(), uno::UNO_QUERY_THROW );
+ // parent is sheet ( parent of the range which is the parent of the comment )
+ uno::Reference< XCollection > xColl( new ScVbaComments( getParent()->getParent(), mxContext, mxModel, xIndexAccess ) );
+
+ return uno::Reference< excel::XComment > ( xColl->Item( uno::Any( Index ), uno::Any() ), uno::UNO_QUERY_THROW );
+ }
+
+// public vba functions
+
+OUString SAL_CALL
+ScVbaComment::getAuthor()
+{
+ return getAnnotation()->getAuthor();
+}
+
+void SAL_CALL
+ScVbaComment::setAuthor( const OUString& /*_author*/ )
+{
+ // #TODO #FIXME implementation needed
+}
+
+uno::Reference< msforms::XShape > SAL_CALL
+ScVbaComment::getShape()
+{
+ uno::Reference< sheet::XSheetAnnotationShapeSupplier > xAnnoShapeSupp( getAnnotation(), uno::UNO_QUERY_THROW );
+ uno::Reference< drawing::XShape > xAnnoShape( xAnnoShapeSupp->getAnnotationShape(), uno::UNO_SET_THROW );
+ uno::Reference< sheet::XSheetCellRange > xCellRange( mxRange, uno::UNO_QUERY_THROW );
+ uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupp( xCellRange->getSpreadsheet(), uno::UNO_QUERY_THROW );
+ uno::Reference< drawing::XShapes > xShapes( xDrawPageSupp->getDrawPage(), uno::UNO_QUERY_THROW );
+ return new ScVbaShape( this, mxContext, xAnnoShape, xShapes, mxModel, office::MsoShapeType::msoComment );
+}
+
+sal_Bool SAL_CALL
+ScVbaComment::getVisible()
+{
+ return getAnnotation()->getIsVisible();
+}
+
+void SAL_CALL
+ScVbaComment::setVisible( sal_Bool _visible )
+{
+ getAnnotation()->setIsVisible( _visible );
+}
+
+void SAL_CALL
+ScVbaComment::Delete()
+{
+ getAnnotations()->removeByIndex( getAnnotationIndex() );
+}
+
+uno::Reference< excel::XComment > SAL_CALL
+ScVbaComment::Next()
+{
+ // index: uno = 0, vba = 1
+ return getCommentByIndex( getAnnotationIndex() + 2 );
+}
+
+uno::Reference< excel::XComment > SAL_CALL
+ScVbaComment::Previous()
+{
+ // index: uno = 0, vba = 1
+ return getCommentByIndex( getAnnotationIndex() );
+}
+
+OUString SAL_CALL
+ScVbaComment::Text( const uno::Any& aText, const uno::Any& aStart, const uno::Any& Overwrite )
+{
+ OUString sText;
+ aText >>= sText;
+
+ uno::Reference< text::XSimpleText > xAnnoText( getAnnotation(), uno::UNO_QUERY_THROW );
+ OUString sAnnoText = xAnnoText->getString();
+
+ if ( aStart.hasValue() )
+ {
+ sal_Int16 nStart = 0;
+ bool bOverwrite = true;
+ Overwrite >>= bOverwrite;
+
+ if ( aStart >>= nStart )
+ {
+ uno::Reference< text::XTextCursor > xTextCursor( xAnnoText->createTextCursor(), uno::UNO_SET_THROW );
+
+ if ( bOverwrite )
+ {
+ xTextCursor->collapseToStart();
+ xTextCursor->gotoStart( false );
+ xTextCursor->goRight( nStart - 1, false );
+ xTextCursor->gotoEnd( true );
+ }
+ else
+ {
+ xTextCursor->collapseToStart();
+ xTextCursor->gotoStart( false );
+ xTextCursor->goRight( nStart - 1 , true );
+ }
+
+ uno::Reference< text::XTextRange > xRange( xTextCursor, uno::UNO_QUERY_THROW );
+ xAnnoText->insertString( xRange, sText, bOverwrite );
+ return xAnnoText->getString();
+ }
+ throw uno::RuntimeException("ScVbaComment::Text - bad Start value " );
+ }
+ else if ( aText.hasValue() )
+ {
+ uno::Reference< sheet::XCellAddressable > xCellAddr(mxRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW );
+ table::CellAddress aAddress = xCellAddr->getCellAddress();
+ getAnnotations()->insertNew( aAddress, sText );
+ }
+
+ return sAnnoText;
+}
+
+OUString
+ScVbaComment::getServiceImplName()
+{
+ return "ScVbaComment";
+}
+
+uno::Sequence< OUString >
+ScVbaComment::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.ScVbaComment"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbacomment.hxx b/sc/source/ui/vba/vbacomment.hxx
new file mode 100644
index 000000000..fe801899c
--- /dev/null
+++ b/sc/source/ui/vba/vbacomment.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 <ooo/vba/excel/XComment.hpp>
+#include <ooo/vba/msforms/XShape.hpp>
+#include <com/sun/star/sheet/XSheetAnnotations.hpp>
+#include <com/sun/star/sheet/XSheetAnnotation.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XComment > ScVbaComment_BASE;
+
+class ScVbaComment : public ScVbaComment_BASE
+{
+ css::uno::Reference< css::frame::XModel > mxModel;
+ css::uno::Reference< css::table::XCellRange > mxRange;
+
+private:
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sheet::XSheetAnnotation > getAnnotation();
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sheet::XSheetAnnotations > getAnnotations() const;
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getAnnotationIndex();
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< ov::excel::XComment > getCommentByIndex( sal_Int32 Index );
+public:
+ /// @throws css::lang::IllegalArgumentException
+ /// @throws css::uno::RuntimeException
+ ScVbaComment(
+ const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::frame::XModel >& xModel,
+ const css::uno::Reference< css::table::XCellRange >& xRange );
+
+ // Attributes
+ virtual OUString SAL_CALL getAuthor() override;
+ virtual void SAL_CALL setAuthor( const OUString& _author ) override;
+ virtual css::uno::Reference< ov::msforms::XShape > SAL_CALL getShape() override;
+ virtual sal_Bool SAL_CALL getVisible() override;
+ virtual void SAL_CALL setVisible( sal_Bool _visible ) override;
+
+ // Methods
+ virtual void SAL_CALL Delete() override;
+ virtual css::uno::Reference< ov::excel::XComment > SAL_CALL Next() override;
+ virtual css::uno::Reference< ov::excel::XComment > SAL_CALL Previous() override;
+ virtual OUString SAL_CALL Text( const css::uno::Any& Text, const css::uno::Any& Start, const css::uno::Any& Overwrite ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbacomments.cxx b/sc/source/ui/vba/vbacomments.cxx
new file mode 100644
index 000000000..470e468b7
--- /dev/null
+++ b/sc/source/ui/vba/vbacomments.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 "vbacomments.hxx"
+#include "vbacomment.hxx"
+
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/sheet/XSheetAnnotation.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+static uno::Any AnnotationToComment( const uno::Any& aSource, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< frame::XModel >& xModel )
+{
+ uno::Reference< sheet::XSheetAnnotation > xAnno( aSource, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XChild > xChild( xAnno, uno::UNO_QUERY_THROW );
+ uno::Reference< table::XCellRange > xCellRange( xChild->getParent(), uno::UNO_QUERY_THROW );
+
+ // #FIXME needs to find the correct Parent
+ return uno::Any( uno::Reference< excel::XComment > (
+ new ScVbaComment( uno::Reference< XHelperInterface >(), xContext, xModel, xCellRange ) ) );
+}
+
+namespace {
+
+class CommentEnumeration : public EnumerationHelperImpl
+{
+ css::uno::Reference< css::frame::XModel > mxModel;
+public:
+ /// @throws uno::RuntimeException
+ CommentEnumeration(
+ const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< container::XEnumeration >& xEnumeration,
+ const uno::Reference< frame::XModel >& xModel ) :
+ EnumerationHelperImpl( xParent, xContext, xEnumeration ),
+ mxModel( xModel, uno::UNO_SET_THROW )
+ {}
+
+ virtual uno::Any SAL_CALL nextElement() override
+ {
+ return AnnotationToComment( m_xEnumeration->nextElement(), m_xContext, mxModel );
+ }
+
+};
+
+}
+
+ScVbaComments::ScVbaComments(
+ const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext > & xContext,
+ const uno::Reference< frame::XModel >& xModel,
+ const uno::Reference< container::XIndexAccess >& xIndexAccess ) :
+ ScVbaComments_BASE( xParent, xContext, xIndexAccess ),
+ mxModel( xModel, uno::UNO_SET_THROW )
+{
+}
+
+// public helper functions
+
+uno::Reference< container::XEnumeration >
+ScVbaComments::createEnumeration()
+{
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW );
+ return new CommentEnumeration( mxParent, mxContext, xEnumAccess->createEnumeration(), mxModel );
+}
+
+uno::Any
+ScVbaComments::createCollectionObject( const css::uno::Any& aSource )
+{
+ return AnnotationToComment( aSource, mxContext, mxModel );
+}
+
+uno::Type
+ScVbaComments::getElementType()
+{
+ return cppu::UnoType<excel::XComment>::get();
+}
+
+OUString
+ScVbaComments::getServiceImplName()
+{
+ return "ScVbaComments";
+}
+
+css::uno::Sequence<OUString>
+ScVbaComments::getServiceNames()
+{
+ static uno::Sequence< OUString > const sNames
+ {
+ "ooo.vba.excel.Comments"
+ };
+ return sNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbacomments.hxx b/sc/source/ui/vba/vbacomments.hxx
new file mode 100644
index 000000000..83a62b6e8
--- /dev/null
+++ b/sc/source/ui/vba/vbacomments.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 <ooo/vba/excel/XComments.hpp>
+
+#include <vbahelper/vbacollectionimpl.hxx>
+
+typedef CollTestImplHelper< ov::excel::XComments > ScVbaComments_BASE;
+
+class ScVbaComments : public ScVbaComments_BASE
+{
+public:
+ ScVbaComments(
+ const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext > & xContext,
+ const css::uno::Reference< css::frame::XModel >& xModel,
+ const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess );
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+
+ // ScVbaComments_BASE
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+private:
+ css::uno::Reference< css::frame::XModel > mxModel;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbacondition.cxx b/sc/source/ui/vba/vbacondition.cxx
new file mode 100644
index 000000000..c5577a7f8
--- /dev/null
+++ b/sc/source/ui/vba/vbacondition.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 "vbacondition.hxx"
+#include <ooo/vba/excel/XlFormatConditionOperator.hpp>
+#include <ooo/vba/excel/XFormatCondition.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XSheetCondition.hpp>
+#include <basic/sberrors.hxx>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+const sal_Int32 ISFORMULA = 98765432;
+
+template <typename... Ifc>
+ScVbaCondition<Ifc...>::ScVbaCondition(
+ const uno::Reference<XHelperInterface>& xParent,
+ const uno::Reference<uno::XComponentContext>& xContext,
+ const uno::Reference<sheet::XSheetCondition>& _xSheetCondition)
+ : ScVbaCondition_BASE(xParent, xContext)
+ , mxSheetCondition(_xSheetCondition)
+{
+ mxAddressable.set(xParent, uno::UNO_QUERY_THROW);
+}
+
+template <typename... Ifc>
+sheet::ConditionOperator ScVbaCondition<Ifc...>::retrieveAPIOperator(const uno::Any& _aOperator)
+{
+ sheet::ConditionOperator aRetAPIOperator = sheet::ConditionOperator_NONE;
+ sal_Int32 nOperator = 0;
+ if (_aOperator >>= nOperator)
+ {
+ switch (nOperator)
+ {
+ case excel::XlFormatConditionOperator::xlBetween:
+ aRetAPIOperator = sheet::ConditionOperator_BETWEEN;
+ break;
+ case excel::XlFormatConditionOperator::xlNotBetween:
+ aRetAPIOperator = sheet::ConditionOperator_NOT_BETWEEN;
+ break;
+ case excel::XlFormatConditionOperator::xlEqual:
+ aRetAPIOperator = sheet::ConditionOperator_EQUAL;
+ break;
+ case excel::XlFormatConditionOperator::xlNotEqual:
+ aRetAPIOperator = sheet::ConditionOperator_NOT_EQUAL;
+ break;
+ case excel::XlFormatConditionOperator::xlGreater:
+ aRetAPIOperator = sheet::ConditionOperator_GREATER;
+ break;
+ case excel::XlFormatConditionOperator::xlLess:
+ aRetAPIOperator = sheet::ConditionOperator_LESS;
+ break;
+ case excel::XlFormatConditionOperator::xlGreaterEqual:
+ aRetAPIOperator = sheet::ConditionOperator_GREATER_EQUAL;
+ break;
+ case excel::XlFormatConditionOperator::xlLessEqual:
+ aRetAPIOperator = sheet::ConditionOperator_LESS_EQUAL;
+ break;
+ default:
+ aRetAPIOperator = sheet::ConditionOperator_NONE;
+ break;
+ }
+ }
+ return aRetAPIOperator;
+}
+
+template <typename... Ifc> OUString ScVbaCondition<Ifc...>::Formula1()
+{
+ return mxSheetCondition->getFormula1();
+}
+
+template <typename... Ifc> OUString ScVbaCondition<Ifc...>::Formula2()
+{
+ return mxSheetCondition->getFormula2();
+}
+
+template <typename... Ifc> sal_Int32 ScVbaCondition<Ifc...>::Operator(bool _bIncludeFormulaValue)
+{
+ sal_Int32 retvalue = -1;
+ sheet::ConditionOperator aConditionalOperator = mxSheetCondition->getOperator();
+ switch (aConditionalOperator)
+ {
+ case sheet::ConditionOperator_EQUAL:
+ retvalue = excel::XlFormatConditionOperator::xlEqual;
+ break;
+ case sheet::ConditionOperator_NOT_EQUAL:
+ retvalue = excel::XlFormatConditionOperator::xlNotEqual;
+ break;
+ case sheet::ConditionOperator_GREATER:
+ retvalue = excel::XlFormatConditionOperator::xlGreater;
+ break;
+ case sheet::ConditionOperator_GREATER_EQUAL:
+ retvalue = excel::XlFormatConditionOperator::xlGreaterEqual;
+ break;
+ case sheet::ConditionOperator_LESS:
+ retvalue = excel::XlFormatConditionOperator::xlLess;
+ break;
+ case sheet::ConditionOperator_LESS_EQUAL:
+ retvalue = excel::XlFormatConditionOperator::xlLessEqual;
+ break;
+ case sheet::ConditionOperator_BETWEEN:
+ retvalue = excel::XlFormatConditionOperator::xlBetween;
+ break;
+ case sheet::ConditionOperator_NOT_BETWEEN:
+ retvalue = excel::XlFormatConditionOperator::xlNotBetween;
+ break;
+ case sheet::ConditionOperator_FORMULA:
+ if (_bIncludeFormulaValue)
+ {
+ //#FIXME huh what's this all about
+ // from helperapi/impl/.../calc/ConditionImpl
+ retvalue = ISFORMULA;
+ break;
+ }
+ [[fallthrough]]; //TODO ???
+ case sheet::ConditionOperator_NONE:
+ default:
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, u"Operator not supported");
+ break;
+ }
+ return retvalue;
+}
+
+template class ScVbaCondition<excel::XFormatCondition>;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbacondition.hxx b/sc/source/ui/vba/vbacondition.hxx
new file mode 100644
index 000000000..78faf0d5e
--- /dev/null
+++ b/sc/source/ui/vba/vbacondition.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 <vbahelper/vbahelperinterface.hxx>
+#include <com/sun/star/sheet/ConditionOperator.hpp>
+
+namespace com::sun::star::sheet { class XCellRangeAddressable; }
+namespace com::sun::star::sheet { class XSheetCondition; }
+
+template< typename... Ifc >
+class ScVbaCondition : public InheritedHelperInterfaceWeakImpl< Ifc... >
+{
+typedef InheritedHelperInterfaceWeakImpl< Ifc... > ScVbaCondition_BASE;
+protected:
+ css::uno::Reference< css::sheet::XCellRangeAddressable > mxAddressable;
+ css::uno::Reference< css::sheet::XSheetCondition > mxSheetCondition;
+public:
+ ScVbaCondition( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::sheet::XSheetCondition >& _xSheetCondition );
+
+ /// @throws css::script::BasicErrorException
+ static css::sheet::ConditionOperator retrieveAPIOperator( const css::uno::Any& _aOperator);
+
+ virtual OUString SAL_CALL Formula1( ) override;
+ virtual OUString SAL_CALL Formula2( ) override;
+ /// @throws css::script::BasicErrorException
+ virtual sal_Int32 Operator(bool _bIncludeFormulaValue);
+ virtual sal_Int32 SAL_CALL Operator() override = 0;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbadialog.cxx b/sc/source/ui/vba/vbadialog.cxx
new file mode 100644
index 000000000..5537c65a3
--- /dev/null
+++ b/sc/source/ui/vba/vbadialog.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 <string_view>
+
+#include "vbadialog.hxx"
+
+#include <sal/macros.h>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+const std::u16string_view aStringList[]=
+{
+ u".uno:Open",
+ u".uno:FormatCellDialog",
+ u".uno:InsertCell",
+ u".uno:Print",
+ u".uno:PasteSpecial",
+ u".uno:ToolProtectionDocument",
+ u".uno:ColumnWidth",
+ u".uno:DefineName",
+ u".uno:ConfigureDialog",
+ u".uno:HyperlinkDialog",
+ u".uno:InsertGraphic",
+ u".uno:InsertObject",
+ u".uno:PageFormatDialog",
+ u".uno:DataSort",
+ u".uno:RowHeight",
+ u".uno:AutoCorrectDlg",
+ u".uno:ConditionalFormatDialog",
+ u".uno:DataConsolidate",
+ u".uno:CreateNames",
+ u".uno:FillSeries",
+ u".uno:Validation",
+ u".uno:DefineLabelRange",
+ u".uno:DataFilterAutoFilter",
+ u".uno:DataFilterSpecialFilter",
+ u".uno:AutoFormat"
+};
+
+const sal_Int32 nDialogSize = SAL_N_ELEMENTS(aStringList);
+
+OUString
+ScVbaDialog::mapIndexToName( sal_Int32 nIndex )
+{
+ if( nIndex < nDialogSize )
+ return OUString(aStringList[ nIndex ]);
+ return OUString();
+}
+
+OUString
+ScVbaDialog::getServiceImplName()
+{
+ return "ScVbaDialog";
+}
+
+uno::Sequence< OUString >
+ScVbaDialog::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Dialog"
+ };
+ return aServiceNames;
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbadialog.hxx b/sc/source/ui/vba/vbadialog.hxx
new file mode 100644
index 000000000..9317cbfaf
--- /dev/null
+++ b/sc/source/ui/vba/vbadialog.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 <cppuhelper/implbase.hxx>
+#include <ooo/vba/excel/XDialog.hpp>
+#include <vbahelper/vbadialogbase.hxx>
+
+typedef cppu::ImplInheritanceHelper< VbaDialogBase, ov::excel::XDialog > ScVbaDialog_BASE;
+
+class ScVbaDialog : public ScVbaDialog_BASE
+{
+public:
+ ScVbaDialog( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xModel, sal_Int32 nIndex ):ScVbaDialog_BASE( xParent, xContext, xModel, nIndex ) {}
+
+ // Methods
+ virtual OUString mapIndexToName( sal_Int32 nIndex ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbadialogs.cxx b/sc/source/ui/vba/vbadialogs.cxx
new file mode 100644
index 000000000..9264728a2
--- /dev/null
+++ b/sc/source/ui/vba/vbadialogs.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 <ooo/vba/excel/XDialog.hpp>
+#include "vbadialogs.hxx"
+#include "vbadialog.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+uno::Any
+ScVbaDialogs::Item( const uno::Any &aItem )
+{
+ sal_Int32 nIndex = 0;
+ aItem >>= nIndex;
+ uno::Reference< excel::XDialog > aDialog( new ScVbaDialog( uno::Reference< XHelperInterface >( Application(),uno::UNO_QUERY_THROW ), mxContext, m_xModel, nIndex ) );
+ return uno::Any( aDialog );
+}
+
+OUString
+ScVbaDialogs::getServiceImplName()
+{
+ return "ScVbaDialogs";
+}
+
+uno::Sequence< OUString >
+ScVbaDialogs::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Dialogs"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbadialogs.hxx b/sc/source/ui/vba/vbadialogs.hxx
new file mode 100644
index 000000000..97cbbda04
--- /dev/null
+++ b/sc/source/ui/vba/vbadialogs.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 <ooo/vba/excel/XDialogs.hpp>
+#include <vbahelper/vbadialogsbase.hxx>
+#include <cppuhelper/implbase.hxx>
+
+namespace ooo::vba { class XHelperInterface; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+typedef cppu::ImplInheritanceHelper< VbaDialogsBase, ov::excel::XDialogs > ScVbaDialogs_BASE;
+
+class ScVbaDialogs : public ScVbaDialogs_BASE
+{
+public:
+ ScVbaDialogs( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > &xContext, const css::uno::Reference< css::frame::XModel >& xModel ): ScVbaDialogs_BASE( xParent, xContext, xModel ) {}
+
+ // XCollection
+ virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index ) override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaeventshelper.cxx b/sc/source/ui/vba/vbaeventshelper.cxx
new file mode 100644
index 000000000..bd00fdcac
--- /dev/null
+++ b/sc/source/ui/vba/vbaeventshelper.cxx
@@ -0,0 +1,898 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "vbaeventshelper.hxx"
+#include "excelvbahelper.hxx"
+
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/awt/XTopWindowListener.hpp>
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/frame/XBorderResizeListener.hpp>
+#include <com/sun/star/frame/XControllerBorder.hpp>
+#include <com/sun/star/script/ModuleType.hpp>
+#include <com/sun/star/script/vba/VBAEventId.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XSheetCellRangeContainer.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/util/XChangesListener.hpp>
+#include <com/sun/star/util/XChangesNotifier.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <unotools/eventcfg.hxx>
+#include <vcl/event.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/window.hxx>
+#include <vbahelper/vbaaccesshelper.hxx>
+
+#include <docsh.hxx>
+#include <document.hxx>
+#include <cellsuno.hxx>
+#include <convuno.hxx>
+#include "vbaapplication.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::script::vba::VBAEventId;
+using namespace ::ooo::vba;
+
+namespace {
+
+/** Extracts a sheet index from the specified element of the passed sequence.
+ The element may be an integer, a Calc range or ranges object, or a VBA Range object.
+
+ @throws lang::IllegalArgumentException
+ @throws uno::RuntimeException
+*/
+SCTAB lclGetTabFromArgs( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex )
+{
+ VbaEventsHelperBase::checkArgument( rArgs, nIndex );
+
+ // first try to extract a sheet index
+ sal_Int32 nTab = -1;
+ if( rArgs[ nIndex ] >>= nTab )
+ {
+ if( (nTab < 0) || (nTab > MAXTAB) )
+ throw lang::IllegalArgumentException();
+ return static_cast< SCTAB >( nTab );
+ }
+
+ // try VBA Range object
+ uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex );
+ if( xVbaRange.is() )
+ {
+ uno::Reference< XHelperInterface > xVbaHelper( xVbaRange, uno::UNO_QUERY_THROW );
+ // TODO: in the future, the parent may be an excel::XChart (chart sheet) -> will there be a common base interface?
+ uno::Reference< excel::XWorksheet > xVbaSheet( xVbaHelper->getParent(), uno::UNO_QUERY_THROW );
+ // VBA sheet index is 1-based
+ return static_cast< SCTAB >( xVbaSheet->getIndex() - 1 );
+ }
+
+ // try single UNO range object
+ uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable = getXSomethingFromArgs< sheet::XCellRangeAddressable >( rArgs, nIndex );
+ if( xCellRangeAddressable.is() )
+ return xCellRangeAddressable->getRangeAddress().Sheet;
+
+ // at last, try UNO range list
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex );
+ if( xRanges.is() )
+ {
+ uno::Sequence< table::CellRangeAddress > aRangeAddresses = xRanges->getRangeAddresses();
+ if( aRangeAddresses.hasElements() )
+ return aRangeAddresses[ 0 ].Sheet;
+ }
+
+ throw lang::IllegalArgumentException();
+}
+
+/** Returns the AWT container window of the passed controller. */
+uno::Reference< awt::XWindow > lclGetWindowForController( const uno::Reference< frame::XController >& rxController )
+{
+ if( rxController.is() ) try
+ {
+ uno::Reference< frame::XFrame > xFrame( rxController->getFrame(), uno::UNO_SET_THROW );
+ return xFrame->getContainerWindow();
+ }
+ catch( uno::Exception& )
+ {
+ }
+ return nullptr;
+}
+
+} // namespace
+
+// This class is to process Workbook window related event
+class ScVbaEventListener : public ::cppu::WeakImplHelper< awt::XTopWindowListener,
+ awt::XWindowListener,
+ frame::XBorderResizeListener,
+ util::XChangesListener >
+{
+public:
+ ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell );
+
+ /** Starts listening to the passed document controller. */
+ void startControllerListening( const uno::Reference< frame::XController >& rxController );
+ /** Stops listening to the passed document controller. */
+ void stopControllerListening( const uno::Reference< frame::XController >& rxController );
+
+ // XTopWindowListener
+ virtual void SAL_CALL windowOpened( const lang::EventObject& rEvent ) override;
+ virtual void SAL_CALL windowClosing( const lang::EventObject& rEvent ) override;
+ virtual void SAL_CALL windowClosed( const lang::EventObject& rEvent ) override;
+ virtual void SAL_CALL windowMinimized( const lang::EventObject& rEvent ) override;
+ virtual void SAL_CALL windowNormalized( const lang::EventObject& rEvent ) override;
+ virtual void SAL_CALL windowActivated( const lang::EventObject& rEvent ) override;
+ virtual void SAL_CALL windowDeactivated( const lang::EventObject& rEvent ) override;
+
+ // XWindowListener
+ virtual void SAL_CALL windowResized( const awt::WindowEvent& rEvent ) override;
+ virtual void SAL_CALL windowMoved( const awt::WindowEvent& rEvent ) override;
+ virtual void SAL_CALL windowShown( const lang::EventObject& rEvent ) override;
+ virtual void SAL_CALL windowHidden( const lang::EventObject& rEvent ) override;
+
+ // XBorderResizeListener
+ virtual void SAL_CALL borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& aNewSize ) override;
+
+ // XChangesListener
+ virtual void SAL_CALL changesOccurred( const util::ChangesEvent& rEvent ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const lang::EventObject& rEvent ) override;
+
+private:
+ /** Starts listening to the document model. */
+ void startModelListening();
+ /** Stops listening to the document model. */
+ void stopModelListening();
+
+ /** Returns the controller for the passed VCL window. */
+ uno::Reference< frame::XController > getControllerForWindow( vcl::Window* pWindow ) const;
+
+ /** Calls the Workbook_Window[Activate|Deactivate] event handler. */
+ void processWindowActivateEvent( vcl::Window* pWindow, bool bActivate );
+ /** Posts a Workbook_WindowResize user event. */
+ void postWindowResizeEvent( vcl::Window* pWindow );
+ /** Callback link for Application::PostUserEvent(). */
+ DECL_LINK( processWindowResizeEvent, void*, void );
+
+private:
+ typedef ::std::map< VclPtr<vcl::Window>, uno::Reference< frame::XController > > WindowControllerMap;
+
+ ::osl::Mutex maMutex;
+ ScVbaEventsHelper& mrVbaEvents;
+ uno::Reference< frame::XModel > mxModel;
+ ScDocShell* mpDocShell;
+ WindowControllerMap maControllers; /// Maps VCL top windows to their controllers.
+ std::multiset< VclPtr<vcl::Window> > m_PostedWindows; /// Keeps processWindowResizeEvent windows from being deleted between postWindowResizeEvent and processWindowResizeEvent
+ VclPtr<vcl::Window> mpActiveWindow; /// Currently activated window, to prevent multiple (de)activation.
+ bool mbWindowResized; /// True = window resize system event processed.
+ bool mbBorderChanged; /// True = borders changed system event processed.
+ bool mbDisposed;
+};
+
+ScVbaEventListener::ScVbaEventListener( ScVbaEventsHelper& rVbaEvents, const uno::Reference< frame::XModel >& rxModel, ScDocShell* pDocShell ) :
+ mrVbaEvents( rVbaEvents ),
+ mxModel( rxModel ),
+ mpDocShell( pDocShell ),
+ mpActiveWindow( nullptr ),
+ mbWindowResized( false ),
+ mbBorderChanged( false ),
+ mbDisposed( !rxModel.is() )
+{
+ if( !mxModel.is() )
+ return;
+
+ startModelListening();
+ try
+ {
+ uno::Reference< frame::XController > xController( mxModel->getCurrentController(), uno::UNO_SET_THROW );
+ startControllerListening( xController );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+void ScVbaEventListener::startControllerListening( const uno::Reference< frame::XController >& rxController )
+{
+ ::osl::MutexGuard aGuard( maMutex );
+
+ uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController );
+ if( xWindow.is() )
+ try { xWindow->addWindowListener( this ); } catch( uno::Exception& ) {}
+
+ uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY );
+ if( xTopWindow.is() )
+ try { xTopWindow->addTopWindowListener( this ); } catch( uno::Exception& ) {}
+
+ uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY );
+ if( xControllerBorder.is() )
+ try { xControllerBorder->addBorderResizeListener( this ); } catch( uno::Exception& ) {}
+
+ if( VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ) )
+ {
+ maControllers[ pWindow ] = rxController;
+ }
+}
+
+void ScVbaEventListener::stopControllerListening( const uno::Reference< frame::XController >& rxController )
+{
+ ::osl::MutexGuard aGuard( maMutex );
+
+ uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( rxController );
+ if( xWindow.is() )
+ try { xWindow->removeWindowListener( this ); } catch( uno::Exception& ) {}
+
+ uno::Reference< awt::XTopWindow > xTopWindow( xWindow, uno::UNO_QUERY );
+ if( xTopWindow.is() )
+ try { xTopWindow->removeTopWindowListener( this ); } catch( uno::Exception& ) {}
+
+ uno::Reference< frame::XControllerBorder > xControllerBorder( rxController, uno::UNO_QUERY );
+ if( xControllerBorder.is() )
+ try { xControllerBorder->removeBorderResizeListener( this ); } catch( uno::Exception& ) {}
+
+ if( VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow ) )
+ {
+ maControllers.erase( pWindow );
+ if( pWindow == mpActiveWindow )
+ mpActiveWindow = nullptr;
+ }
+}
+
+void SAL_CALL ScVbaEventListener::windowOpened( const lang::EventObject& /*rEvent*/ )
+{
+}
+
+void SAL_CALL ScVbaEventListener::windowClosing( const lang::EventObject& /*rEvent*/ )
+{
+}
+
+void SAL_CALL ScVbaEventListener::windowClosed( const lang::EventObject& /*rEvent*/ )
+{
+}
+
+void SAL_CALL ScVbaEventListener::windowMinimized( const lang::EventObject& /*rEvent*/ )
+{
+}
+
+void SAL_CALL ScVbaEventListener::windowNormalized( const lang::EventObject& /*rEvent*/ )
+{
+}
+
+void SAL_CALL ScVbaEventListener::windowActivated( const lang::EventObject& rEvent )
+{
+ ::osl::MutexGuard aGuard( maMutex );
+
+ if( mbDisposed )
+ return;
+
+ uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ // do not fire activation event multiple time for the same window
+ if( pWindow && (pWindow != mpActiveWindow) )
+ {
+ // if another window is active, fire deactivation event first
+ if( mpActiveWindow )
+ processWindowActivateEvent( mpActiveWindow, false );
+ // fire activation event for the new window
+ processWindowActivateEvent( pWindow, true );
+ mpActiveWindow = pWindow;
+ }
+}
+
+void SAL_CALL ScVbaEventListener::windowDeactivated( const lang::EventObject& rEvent )
+{
+ ::osl::MutexGuard aGuard( maMutex );
+
+ if( !mbDisposed )
+ {
+ uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
+ VclPtr<vcl::Window> pWindow = VCLUnoHelper::GetWindow( xWindow );
+ // do not fire the deactivation event, if the window is not active (prevent multiple deactivation)
+ if( pWindow && (pWindow == mpActiveWindow) )
+ processWindowActivateEvent( pWindow, false );
+ // forget pointer to the active window
+ mpActiveWindow = nullptr;
+ }
+}
+
+void SAL_CALL ScVbaEventListener::windowResized( const awt::WindowEvent& rEvent )
+{
+ ::osl::MutexGuard aGuard( maMutex );
+
+ mbWindowResized = true;
+ if( !mbDisposed && mbBorderChanged )
+ {
+ uno::Reference< awt::XWindow > xWindow( rEvent.Source, uno::UNO_QUERY );
+ postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) );
+ }
+}
+
+void SAL_CALL ScVbaEventListener::windowMoved( const awt::WindowEvent& /*rEvent*/ )
+{
+}
+
+void SAL_CALL ScVbaEventListener::windowShown( const lang::EventObject& /*rEvent*/ )
+{
+}
+
+void SAL_CALL ScVbaEventListener::windowHidden( const lang::EventObject& /*rEvent*/ )
+{
+}
+
+void SAL_CALL ScVbaEventListener::borderWidthsChanged( const uno::Reference< uno::XInterface >& rSource, const frame::BorderWidths& /*aNewSize*/ )
+{
+ ::osl::MutexGuard aGuard( maMutex );
+
+ mbBorderChanged = true;
+ if( !mbDisposed && mbWindowResized )
+ {
+ uno::Reference< frame::XController > xController( rSource, uno::UNO_QUERY );
+ uno::Reference< awt::XWindow > xWindow = lclGetWindowForController( xController );
+ postWindowResizeEvent( VCLUnoHelper::GetWindow( xWindow ) );
+ }
+}
+
+void SAL_CALL ScVbaEventListener::changesOccurred( const util::ChangesEvent& rEvent )
+{
+ ::osl::MutexGuard aGuard( maMutex );
+
+ sal_Int32 nCount = rEvent.Changes.getLength();
+ if( mbDisposed || !mpDocShell || (nCount == 0) )
+ return;
+
+ util::ElementChange aChange = rEvent.Changes[ 0 ];
+ OUString sOperation;
+ aChange.Accessor >>= sOperation;
+ if( !sOperation.equalsIgnoreAsciiCase("cell-change") )
+ return;
+
+ if( nCount == 1 )
+ {
+ uno::Reference< table::XCellRange > xRangeObj;
+ aChange.ReplacedElement >>= xRangeObj;
+ if( xRangeObj.is() )
+ {
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xRangeObj) };
+ mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs );
+ }
+ return;
+ }
+
+ ScRangeList aRangeList;
+ for( const util::ElementChange& rChange : rEvent.Changes )
+ {
+ rChange.Accessor >>= sOperation;
+ uno::Reference< table::XCellRange > xRangeObj;
+ rChange.ReplacedElement >>= xRangeObj;
+ if( xRangeObj.is() && sOperation.equalsIgnoreAsciiCase("cell-change") )
+ {
+ uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable( xRangeObj, uno::UNO_QUERY );
+ if( xCellRangeAddressable.is() )
+ {
+ ScRange aRange;
+ ScUnoConversion::FillScRange( aRange, xCellRangeAddressable->getRangeAddress() );
+ aRangeList.push_back( aRange );
+ }
+ }
+ }
+
+ if (!aRangeList.empty())
+ {
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( mpDocShell, aRangeList ) );
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xRanges) };
+ mrVbaEvents.processVbaEventNoThrow( WORKSHEET_CHANGE, aArgs );
+ }
+}
+
+void SAL_CALL ScVbaEventListener::disposing( const lang::EventObject& rEvent )
+{
+ ::osl::MutexGuard aGuard( maMutex );
+
+ uno::Reference< frame::XModel > xModel( rEvent.Source, uno::UNO_QUERY );
+ if( xModel.is() )
+ {
+ OSL_ENSURE( xModel.get() == mxModel.get(), "ScVbaEventListener::disposing - disposing from unknown model" );
+ stopModelListening();
+ mbDisposed = true;
+ return;
+ }
+
+ uno::Reference< frame::XController > xController( rEvent.Source, uno::UNO_QUERY );
+ if( xController.is() )
+ {
+ stopControllerListening( xController );
+ return;
+ }
+}
+
+// private --------------------------------------------------------------------
+
+void ScVbaEventListener::startModelListening()
+{
+ try
+ {
+ uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW );
+ xChangesNotifier->addChangesListener( this );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+void ScVbaEventListener::stopModelListening()
+{
+ try
+ {
+ uno::Reference< util::XChangesNotifier > xChangesNotifier( mxModel, uno::UNO_QUERY_THROW );
+ xChangesNotifier->removeChangesListener( this );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+uno::Reference< frame::XController > ScVbaEventListener::getControllerForWindow( vcl::Window* pWindow ) const
+{
+ WindowControllerMap::const_iterator aIt = maControllers.find( pWindow );
+ return (aIt == maControllers.end()) ? uno::Reference< frame::XController >() : aIt->second;
+}
+
+void ScVbaEventListener::processWindowActivateEvent( vcl::Window* pWindow, bool bActivate )
+{
+ uno::Reference< frame::XController > xController = getControllerForWindow( pWindow );
+ if( xController.is() )
+ {
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xController) };
+ mrVbaEvents.processVbaEventNoThrow( bActivate ? WORKBOOK_WINDOWACTIVATE : WORKBOOK_WINDOWDEACTIVATE, aArgs );
+ }
+}
+
+void ScVbaEventListener::postWindowResizeEvent( vcl::Window* pWindow )
+{
+ // check that the passed window is still alive (it must be registered in maControllers)
+ if( pWindow && (maControllers.count( pWindow ) > 0) )
+ {
+ mbWindowResized = mbBorderChanged = false;
+ acquire(); // ensure we don't get deleted before the timer fires
+ m_PostedWindows.insert(pWindow);
+ Application::PostUserEvent( LINK( this, ScVbaEventListener, processWindowResizeEvent ), pWindow );
+ }
+}
+
+IMPL_LINK( ScVbaEventListener, processWindowResizeEvent, void*, p, void )
+{
+ vcl::Window* pWindow = static_cast<vcl::Window*>(p);
+ ::osl::MutexGuard aGuard( maMutex );
+
+ /* Check that the passed window is still alive (it must be registered in
+ maControllers). While closing a document, postWindowResizeEvent() may
+ be called on the last window which posts a user event via
+ Application::PostUserEvent to call this event handler. VCL will trigger
+ the handler some time later. Sometimes, the window gets deleted before.
+ This is handled via the disposing() function which removes the window
+ pointer from the member maControllers. Thus, checking whether
+ maControllers contains pWindow ensures that the window is still alive. */
+ if( !mbDisposed && pWindow && !pWindow->isDisposed() && (maControllers.count(pWindow) > 0) )
+ {
+ // do not fire event unless all mouse buttons have been released
+ vcl::Window::PointerState aPointerState = pWindow->GetPointerState();
+ if( (aPointerState.mnState & (MOUSE_LEFT | MOUSE_MIDDLE | MOUSE_RIGHT)) == 0 )
+ {
+ uno::Reference< frame::XController > xController = getControllerForWindow( pWindow );
+ if( xController.is() )
+ {
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xController) };
+ // #163419# do not throw exceptions into application core
+ mrVbaEvents.processVbaEventNoThrow( WORKBOOK_WINDOWRESIZE, aArgs );
+ }
+ }
+ }
+ {
+ // note: there may be multiple processWindowResizeEvent outstanding
+ // for pWindow, so it may have been added to m_PostedWindows multiple
+ // times - so this must delete exactly one of these elements!
+ auto const iter(m_PostedWindows.find(pWindow));
+ assert(iter != m_PostedWindows.end());
+ m_PostedWindows.erase(iter);
+ }
+ release();
+}
+
+ScVbaEventsHelper::ScVbaEventsHelper( const uno::Sequence< uno::Any >& rArgs ) :
+ VbaEventsHelperBase( rArgs ),
+ mbOpened( false )
+{
+ mpDocShell = dynamic_cast< ScDocShell* >( mpShell ); // mpShell from base class
+ mpDoc = mpDocShell ? &mpDocShell->GetDocument() : nullptr;
+
+ if( !mxModel.is() || !mpDocShell || !mpDoc )
+ return;
+
+ // global
+ auto registerAutoEvent = [this](sal_Int32 nID, const char* sName)
+ { registerEventHandler(nID, script::ModuleType::NORMAL, OString(OString::Concat("Auto_") + sName).getStr(), -1, uno::Any(false)); };
+ registerAutoEvent(AUTO_OPEN, "Open");
+ registerAutoEvent(AUTO_CLOSE, "Close");
+
+ // Workbook
+ auto registerWorkbookEvent = [this](sal_Int32 nID, const char* sName, sal_Int32 nCancelIndex)
+ { registerEventHandler(nID, script::ModuleType::DOCUMENT, OString(OString::Concat("Workbook_") + sName).getStr(), nCancelIndex, uno::Any(false)); };
+ registerWorkbookEvent( WORKBOOK_ACTIVATE, "Activate", -1 );
+ registerWorkbookEvent( WORKBOOK_DEACTIVATE, "Deactivate", -1 );
+ registerWorkbookEvent( WORKBOOK_OPEN, "Open", -1 );
+ registerWorkbookEvent( WORKBOOK_BEFORECLOSE, "BeforeClose", 0 );
+ registerWorkbookEvent( WORKBOOK_BEFOREPRINT, "BeforePrint", 0 );
+ registerWorkbookEvent( WORKBOOK_BEFORESAVE, "BeforeSave", 1 );
+ registerWorkbookEvent( WORKBOOK_AFTERSAVE, "AfterSave", -1 );
+ registerWorkbookEvent( WORKBOOK_NEWSHEET, "NewSheet", -1 );
+ registerWorkbookEvent( WORKBOOK_WINDOWACTIVATE, "WindowActivate", -1 );
+ registerWorkbookEvent( WORKBOOK_WINDOWDEACTIVATE, "WindowDeactivate", -1 );
+ registerWorkbookEvent( WORKBOOK_WINDOWRESIZE, "WindowResize", -1 );
+
+ // Worksheet events. All events have a corresponding workbook event.
+ auto registerWorksheetEvent = [this](sal_Int32 nID, const char* sName, sal_Int32 nCancelIndex)
+ {
+ registerEventHandler(nID, script::ModuleType::DOCUMENT, OString(OString::Concat("Worksheet_") + sName).getStr(),
+ nCancelIndex, uno::Any(true));
+ registerEventHandler(USERDEFINED_START + nID, script::ModuleType::DOCUMENT,
+ OString(OString::Concat("Workbook_Worksheet") + sName).getStr(),
+ ((nCancelIndex >= 0) ? (nCancelIndex + 1) : -1), uno::Any(false));
+ };
+ registerWorksheetEvent( WORKSHEET_ACTIVATE, "Activate", -1 );
+ registerWorksheetEvent( WORKSHEET_DEACTIVATE, "Deactivate", -1 );
+ registerWorksheetEvent( WORKSHEET_BEFOREDOUBLECLICK, "BeforeDoubleClick", 1 );
+ registerWorksheetEvent( WORKSHEET_BEFORERIGHTCLICK, "BeforeRightClick", 1 );
+ registerWorksheetEvent( WORKSHEET_CALCULATE, "Calculate", -1 );
+ registerWorksheetEvent( WORKSHEET_CHANGE, "Change", -1 );
+ registerWorksheetEvent( WORKSHEET_SELECTIONCHANGE, "SelectionChange", -1 );
+ registerWorksheetEvent( WORKSHEET_FOLLOWHYPERLINK, "FollowHyperlink", -1 );
+}
+
+ScVbaEventsHelper::~ScVbaEventsHelper()
+{
+}
+
+void SAL_CALL ScVbaEventsHelper::notifyEvent( const css::document::EventObject& rEvent )
+{
+ static const uno::Sequence< uno::Any > saEmptyArgs;
+ if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::OPENDOC )) ||
+ (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CREATEDOC )) ) // CREATEDOC triggered e.g. during VBA Workbooks.Add
+ {
+ processVbaEventNoThrow( WORKBOOK_OPEN, saEmptyArgs );
+ }
+ else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::ACTIVATEDOC ) )
+ {
+ processVbaEventNoThrow( WORKBOOK_ACTIVATE, saEmptyArgs );
+ }
+ else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::DEACTIVATEDOC ) )
+ {
+ processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs );
+ }
+ else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCDONE )) ||
+ (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCDONE )) ||
+ (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCDONE )) )
+ {
+ uno::Sequence< uno::Any > aArgs{ uno::Any(true) };
+ processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs );
+ }
+ else if( (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEDOCFAILED )) ||
+ (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVEASDOCFAILED )) ||
+ (rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::SAVETODOCFAILED )) )
+ {
+ uno::Sequence< uno::Any > aArgs{ uno::Any(false) };
+ processVbaEventNoThrow( WORKBOOK_AFTERSAVE, aArgs );
+ }
+ else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::CLOSEDOC ) )
+ {
+ /* Trigger the WORKBOOK_WINDOWDEACTIVATE and WORKBOOK_DEACTIVATE
+ events and stop listening to the model (done in base class). */
+ uno::Reference< frame::XController > xController( mxModel->getCurrentController() );
+ if( xController.is() )
+ {
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xController) };
+ processVbaEventNoThrow( WORKBOOK_WINDOWDEACTIVATE, aArgs );
+ }
+ processVbaEventNoThrow( WORKBOOK_DEACTIVATE, saEmptyArgs );
+ }
+ else if( rEvent.EventName == GlobalEventConfig::GetEventName( GlobalEventId::VIEWCREATED ) )
+ {
+ uno::Reference< frame::XController > xController( mxModel->getCurrentController() );
+ if( mxListener && xController.is() )
+ mxListener->startControllerListening( xController );
+ }
+ VbaEventsHelperBase::notifyEvent( rEvent );
+}
+
+OUString ScVbaEventsHelper::getImplementationName()
+{
+ return "ScVbaEventsHelper";
+}
+
+css::uno::Sequence<OUString> ScVbaEventsHelper::getSupportedServiceNames()
+{
+ return css::uno::Sequence<OUString>{
+ "com.sun.star.script.vba.VBASpreadsheetEventProcessor"};
+}
+
+// protected ------------------------------------------------------------------
+
+bool ScVbaEventsHelper::implPrepareEvent( EventQueue& rEventQueue,
+ const EventHandlerInfo& rInfo, const uno::Sequence< uno::Any >& rArgs )
+{
+ // document and document shell are needed during event processing
+ if( !mpShell || !mpDoc )
+ throw uno::RuntimeException();
+
+ /* For document events: check if events are enabled via the
+ Application.EnableEvents symbol (this is an Excel-only attribute).
+ Check this again for every event, as the event handler may change the
+ state of the EnableEvents symbol. Global events such as AUTO_OPEN and
+ AUTO_CLOSE are always enabled. */
+ bool bExecuteEvent = (rInfo.mnModuleType != script::ModuleType::DOCUMENT) || ScVbaApplication::getDocumentEventsEnabled();
+
+ // framework and Calc fire a few events before 'OnLoad', ignore them
+ if( bExecuteEvent )
+ bExecuteEvent = (rInfo.mnEventId == WORKBOOK_OPEN) ? !mbOpened : mbOpened;
+
+ // special handling for some events
+ if( bExecuteEvent ) switch( rInfo.mnEventId )
+ {
+ case WORKBOOK_OPEN:
+ {
+ // execute delayed Activate event too (see above)
+ rEventQueue.emplace_back(WORKBOOK_ACTIVATE );
+ uno::Sequence< uno::Any > aArgs{ uno::Any(mxModel->getCurrentController()) };
+ rEventQueue.emplace_back( WORKBOOK_WINDOWACTIVATE, aArgs );
+ rEventQueue.emplace_back(AUTO_OPEN );
+ // remember initial selection
+ maOldSelection <<= mxModel->getCurrentSelection();
+ }
+ break;
+ case WORKSHEET_SELECTIONCHANGE:
+ // if selection is not changed, then do not fire the event
+ bExecuteEvent = isSelectionChanged( rArgs, 0 );
+ break;
+ }
+
+ if( bExecuteEvent )
+ {
+ // add workbook event associated to a sheet event
+ bool bSheetEvent = false;
+ if( (rInfo.maUserData >>= bSheetEvent) && bSheetEvent )
+ rEventQueue.emplace_back( rInfo.mnEventId + USERDEFINED_START, rArgs );
+ }
+
+ return bExecuteEvent;
+}
+
+uno::Sequence< uno::Any > ScVbaEventsHelper::implBuildArgumentList( const EventHandlerInfo& rInfo,
+ const uno::Sequence< uno::Any >& rArgs )
+{
+ // fill arguments for workbook events associated to sheet events according to sheet events, sheet will be added below
+ bool bSheetEventAsBookEvent = rInfo.mnEventId > USERDEFINED_START;
+ sal_Int32 nEventId = bSheetEventAsBookEvent ? (rInfo.mnEventId - USERDEFINED_START) : rInfo.mnEventId;
+
+ uno::Sequence< uno::Any > aVbaArgs;
+ switch( nEventId )
+ {
+ // *** Workbook ***
+
+ // no arguments
+ case WORKBOOK_ACTIVATE:
+ case WORKBOOK_DEACTIVATE:
+ case WORKBOOK_OPEN:
+ break;
+ // 1 arg: cancel
+ case WORKBOOK_BEFORECLOSE:
+ case WORKBOOK_BEFOREPRINT:
+ aVbaArgs.realloc( 1 );
+ // current cancel state will be inserted by caller
+ break;
+ // 2 args: saveAs, cancel
+ case WORKBOOK_BEFORESAVE:
+ checkArgumentType< bool >( rArgs, 0 );
+ aVbaArgs = { rArgs[ 0 ], {} };
+ // current cancel state will be inserted by caller
+ break;
+ // 1 arg: success
+ case WORKBOOK_AFTERSAVE:
+ checkArgumentType< bool >( rArgs, 0 );
+ aVbaArgs = { rArgs[ 0 ] };
+ break;
+ // 1 arg: window
+ case WORKBOOK_WINDOWACTIVATE:
+ case WORKBOOK_WINDOWDEACTIVATE:
+ case WORKBOOK_WINDOWRESIZE:
+ aVbaArgs = { createWindow( rArgs, 0 ) };
+ break;
+ // 1 arg: worksheet
+ case WORKBOOK_NEWSHEET:
+ aVbaArgs = { createWorksheet( rArgs, 0 ) };
+ break;
+
+ // *** Worksheet ***
+
+ // no arguments
+ case WORKSHEET_ACTIVATE:
+ case WORKSHEET_CALCULATE:
+ case WORKSHEET_DEACTIVATE:
+ break;
+ // 1 arg: range
+ case WORKSHEET_CHANGE:
+ case WORKSHEET_SELECTIONCHANGE:
+ aVbaArgs = { createRange( rArgs, 0 ) };
+ break;
+ // 2 args: range, cancel
+ case WORKSHEET_BEFOREDOUBLECLICK:
+ case WORKSHEET_BEFORERIGHTCLICK:
+ aVbaArgs = { createRange( rArgs, 0 ), {} };
+ // current cancel state will be inserted by caller
+ break;
+ // 1 arg: hyperlink
+ case WORKSHEET_FOLLOWHYPERLINK:
+ aVbaArgs = { createHyperlink( rArgs, 0 ) };
+ break;
+ }
+
+ /* For workbook events associated to sheet events, the workbook event gets
+ the same arguments but with a Worksheet object in front of them. */
+ if( bSheetEventAsBookEvent )
+ {
+ sal_Int32 nLength = aVbaArgs.getLength();
+ uno::Sequence< uno::Any > aVbaArgs2( nLength + 1 );
+ auto pVbaArgs2 = aVbaArgs2.getArray();
+ *pVbaArgs2 = createWorksheet( rArgs, 0 );
+ std::copy_n(std::cbegin(aVbaArgs), nLength, std::next(pVbaArgs2));
+ aVbaArgs = aVbaArgs2;
+ }
+
+ return aVbaArgs;
+}
+
+void ScVbaEventsHelper::implPostProcessEvent( EventQueue& rEventQueue,
+ const EventHandlerInfo& rInfo, bool bCancel )
+{
+ switch( rInfo.mnEventId )
+ {
+ case WORKBOOK_OPEN:
+ mbOpened = true;
+ // register the listeners
+ if( !mxListener.is() )
+ mxListener = new ScVbaEventListener( *this, mxModel, mpDocShell );
+ break;
+ case WORKBOOK_BEFORECLOSE:
+ /* Execute Auto_Close only if not cancelled by event handler, but
+ before UI asks user whether to cancel closing the document. */
+ if( !bCancel )
+ rEventQueue.emplace_back(AUTO_CLOSE );
+ break;
+ }
+}
+
+OUString ScVbaEventsHelper::implGetDocumentModuleName( const EventHandlerInfo& rInfo,
+ const uno::Sequence< uno::Any >& rArgs ) const
+{
+ bool bSheetEvent = false;
+ rInfo.maUserData >>= bSheetEvent;
+ SCTAB nTab = bSheetEvent ? lclGetTabFromArgs( rArgs, 0 ) : -1;
+ if( bSheetEvent && (nTab < 0) )
+ throw lang::IllegalArgumentException();
+
+ OUString aCodeName;
+ if( bSheetEvent )
+ mpDoc->GetCodeName( nTab, aCodeName );
+ else
+ aCodeName = mpDoc->GetCodeName();
+ return aCodeName;
+}
+
+// private --------------------------------------------------------------------
+
+namespace {
+
+/** Compares the passed range lists representing sheet selections. Ignores
+ selections that refer to different sheets (returns false in this case). */
+bool lclSelectionChanged( const ScRangeList& rLeft, const ScRangeList& rRight )
+{
+ // one of the range lists empty? -> return false, if both lists empty
+ bool bLeftEmpty = rLeft.empty();
+ bool bRightEmpty = rRight.empty();
+ if( bLeftEmpty || bRightEmpty )
+ return !(bLeftEmpty && bRightEmpty);
+
+ // check sheet indexes of the range lists (assuming that all ranges in a list are on the same sheet)
+ if (rLeft[0].aStart.Tab() != rRight[0].aStart.Tab())
+ return false;
+
+ // compare all ranges
+ return rLeft != rRight;
+}
+
+} // namespace
+
+bool ScVbaEventsHelper::isSelectionChanged( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex )
+{
+ uno::Reference< uno::XInterface > xOldSelection( maOldSelection, uno::UNO_QUERY );
+ uno::Reference< uno::XInterface > xNewSelection = getXSomethingFromArgs< uno::XInterface >( rArgs, nIndex, false );
+ ScCellRangesBase* pOldCellRanges = comphelper::getFromUnoTunnel<ScCellRangesBase>( xOldSelection );
+ ScCellRangesBase* pNewCellRanges = comphelper::getFromUnoTunnel<ScCellRangesBase>( xNewSelection );
+ bool bChanged = !pOldCellRanges || !pNewCellRanges || lclSelectionChanged( pOldCellRanges->GetRangeList(), pNewCellRanges->GetRangeList() );
+ maOldSelection <<= xNewSelection;
+ return bChanged;
+}
+
+uno::Any ScVbaEventsHelper::createWorksheet( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
+{
+ // extract sheet index, will throw, if parameter is invalid
+ SCTAB nTab = lclGetTabFromArgs( rArgs, nIndex );
+ return uno::Any( excel::getUnoSheetModuleObj( mxModel, nTab ) );
+}
+
+uno::Any ScVbaEventsHelper::createRange( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
+{
+ // it is possible to pass an existing VBA Range object
+ uno::Reference< excel::XRange > xVbaRange = getXSomethingFromArgs< excel::XRange >( rArgs, nIndex );
+ if( !xVbaRange.is() )
+ {
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges = getXSomethingFromArgs< sheet::XSheetCellRangeContainer >( rArgs, nIndex );
+ uno::Reference< table::XCellRange > xRange = getXSomethingFromArgs< table::XCellRange >( rArgs, nIndex );
+ if ( !xRanges.is() && !xRange.is() )
+ throw lang::IllegalArgumentException();
+
+ uno::Sequence< uno::Any > aArgs;
+ if ( xRanges.is() )
+ {
+ aArgs = { uno::Any(excel::getUnoSheetModuleObj( xRanges )), uno::Any(xRanges) };
+ }
+ else
+ {
+ aArgs = { uno::Any(excel::getUnoSheetModuleObj( xRange )), uno::Any(xRange) };
+ }
+ xVbaRange.set( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Range", aArgs ), uno::UNO_QUERY_THROW );
+ }
+ return uno::Any( xVbaRange );
+}
+
+uno::Any ScVbaEventsHelper::createHyperlink( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
+{
+ uno::Reference< table::XCell > xCell = getXSomethingFromArgs< table::XCell >( rArgs, nIndex, false );
+ uno::Sequence< uno::Any > aArgs{ uno::Any(excel::getUnoSheetModuleObj( xCell )),
+ uno::Any(xCell) };
+ uno::Reference< uno::XInterface > xHyperlink( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Hyperlink", aArgs ), uno::UNO_SET_THROW );
+ return uno::Any( xHyperlink );
+}
+
+uno::Any ScVbaEventsHelper::createWindow( const uno::Sequence< uno::Any >& rArgs, sal_Int32 nIndex ) const
+{
+ uno::Sequence< uno::Any > aArgs{ uno::Any(getVBADocument( mxModel )),
+ uno::Any(mxModel),
+ uno::Any(getXSomethingFromArgs< frame::XController >( rArgs, nIndex, false )) };
+ uno::Reference< uno::XInterface > xWindow( createVBAUnoAPIServiceWithArgs( mpShell, "ooo.vba.excel.Window", aArgs ), uno::UNO_SET_THROW );
+ return uno::Any( xWindow );
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+ScVbaEventsHelper_get_implementation(
+ css::uno::XComponentContext * /*context*/,
+ css::uno::Sequence<css::uno::Any> const &arguments)
+{
+ return cppu::acquire(new ScVbaEventsHelper(arguments));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaeventshelper.hxx b/sc/source/ui/vba/vbaeventshelper.hxx
new file mode 100644
index 000000000..e5bf11ecb
--- /dev/null
+++ b/sc/source/ui/vba/vbaeventshelper.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 <rtl/ref.hxx>
+#include <vbahelper/vbaeventshelperbase.hxx>
+
+class ScDocShell;
+class ScDocument;
+class ScVbaEventListener;
+
+class ScVbaEventsHelper : public VbaEventsHelperBase
+{
+public:
+ ScVbaEventsHelper( const css::uno::Sequence< css::uno::Any >& rArgs );
+ virtual ~ScVbaEventsHelper() override;
+
+ virtual void SAL_CALL notifyEvent( const css::document::EventObject& rEvent ) override;
+
+ OUString SAL_CALL getImplementationName() override;
+
+ css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override;
+
+protected:
+ virtual bool implPrepareEvent( EventQueue& rEventQueue, const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) override;
+ virtual css::uno::Sequence< css::uno::Any > implBuildArgumentList( const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) override;
+ virtual void implPostProcessEvent( EventQueue& rEventQueue, const EventHandlerInfo& rInfo, bool bCancel ) override;
+ virtual OUString implGetDocumentModuleName( const EventHandlerInfo& rInfo, const css::uno::Sequence< css::uno::Any >& rArgs ) const override;
+
+private:
+ /** Checks if selection has been changed compared to selection of last call.
+ @return true, if the selection has been changed.
+ @throws css::lang::IllegalArgumentException
+ @throws css::uno::RuntimeException
+ */
+ bool isSelectionChanged( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex );
+
+ /** Creates a VBA Worksheet object (the argument must contain a sheet index).
+ @throws css::lang::IllegalArgumentException
+ @throws css::uno::RuntimeException
+ */
+ css::uno::Any createWorksheet( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) const;
+ /** Creates a VBA Range object (the argument must contain a UNO range or UNO range list).
+ @throws css::lang::IllegalArgumentException
+ @throws css::uno::RuntimeException
+ */
+ css::uno::Any createRange( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) const;
+ /** Creates a VBA Hyperlink object (the argument must contain a UNO cell).
+ @throws css::lang::IllegalArgumentException
+ @throws css::uno::RuntimeException
+ */
+ css::uno::Any createHyperlink( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) const;
+ /** Creates a VBA Window object (the argument must contain a model controller).
+ @throws css::lang::IllegalArgumentException
+ @throws css::uno::RuntimeException
+ */
+ css::uno::Any createWindow( const css::uno::Sequence< css::uno::Any >& rArgs, sal_Int32 nIndex ) const;
+
+private:
+ ::rtl::Reference< ScVbaEventListener > mxListener;
+ css::uno::Any maOldSelection;
+ ScDocShell* mpDocShell;
+ ScDocument* mpDoc;
+ bool mbOpened;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbafiledialog.cxx b/sc/source/ui/vba/vbafiledialog.cxx
new file mode 100644
index 000000000..f7f31db2a
--- /dev/null
+++ b/sc/source/ui/vba/vbafiledialog.cxx
@@ -0,0 +1,174 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "vbafiledialog.hxx"
+#include "vbafiledialogitems.hxx"
+
+#include <osl/file.hxx>
+
+#include <ooo/vba/office/MsoFileDialogType.hpp>
+
+#include <com/sun/star/ui/dialogs/FilePicker.hpp>
+#include <com/sun/star/ui/dialogs/FolderPicker.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+ScVbaFileDialog::ScVbaFileDialog( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const sal_Int32 nType )
+ : ScVbaFileDialog_BASE( xParent, xContext)
+ , m_nType(nType)
+ , m_sTitle("FileDialog")
+ , m_bMultiSelectMode(false)
+{}
+
+uno::Any
+ScVbaFileDialog::getInitialFileName() { return uno::Any( m_sInitialFileName ); }
+
+void ScVbaFileDialog::setInitialFileName( const css::uno::Any& rName )
+{
+ OUString sDefaultPath;
+
+ if( rName >>= sDefaultPath )
+ {
+ OUString sDefaultURL;
+ sal_Int32 eSuccess = osl::FileBase::getFileURLFromSystemPath(
+ sDefaultPath, sDefaultURL ) ;
+ if( eSuccess == osl::FileBase::RC::E_INVAL )
+ m_sInitialFileName = sDefaultPath; // the user may gave it in URL form
+ else
+ m_sInitialFileName = sDefaultURL;
+ }
+}
+
+css::uno::Any ScVbaFileDialog::getTitle() { return uno::Any( m_sTitle ); }
+
+void ScVbaFileDialog::setTitle( const css::uno::Any& rTitle )
+{
+ rTitle >>= m_sTitle;
+}
+
+uno::Any ScVbaFileDialog::getAllowMultiSelect()
+{
+ return uno::Any(m_bMultiSelectMode);
+}
+
+void ScVbaFileDialog::setAllowMultiSelect(const uno::Any& rAllowMultiSelect)
+{
+ rAllowMultiSelect >>= m_bMultiSelectMode;
+}
+
+uno::Reference< excel::XFileDialogSelectedItems > SAL_CALL ScVbaFileDialog::getSelectedItems()
+{
+ // TODO use InitialFileName when m_xItems is empty
+ return m_xItems;
+}
+
+sal_Int32 ScVbaFileDialog::Show()
+{
+ std::vector<OUString> sSelectedPaths;
+ sal_Int32 nRet = -1;
+
+ switch (m_nType)
+ {
+ case office::MsoFileDialogType::msoFileDialogOpen:
+ // TODO implement
+ break;
+ case office::MsoFileDialogType::msoFileDialogSaveAs:
+ // TODO implement
+ break;
+ case office::MsoFileDialogType::msoFileDialogFilePicker:
+ {
+ uno::Reference<ui::dialogs::XFilePicker3> xFilePicker =
+ ui::dialogs::FilePicker::createWithMode(
+ mxContext, ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE );
+
+ if( !m_sInitialFileName.isEmpty() )
+ xFilePicker->setDisplayDirectory( m_sInitialFileName );
+
+ if( xFilePicker->execute() != ui::dialogs::ExecutableDialogResults::OK )
+ {
+ nRet = 0; // cancel pressed
+ break;
+ }
+
+ const uno::Sequence<OUString> aSelectedFiles = xFilePicker->getSelectedFiles();
+ for( const auto& sURL : aSelectedFiles )
+ {
+ OUString sPath;
+ osl::FileBase::getSystemPathFromFileURL(sURL, sPath);
+
+ sSelectedPaths.push_back(sPath);
+ }
+ }
+ break;
+ case office::MsoFileDialogType::msoFileDialogFolderPicker:
+ {
+ uno::Reference< ui::dialogs::XFolderPicker2 > xFolderPicker =
+ ui::dialogs::FolderPicker::create(mxContext);
+
+ if( !m_sInitialFileName.isEmpty() )
+ xFolderPicker->setDisplayDirectory( m_sInitialFileName );
+
+ if( xFolderPicker->execute() != ui::dialogs::ExecutableDialogResults::OK )
+ {
+ nRet = 0; // cancel pressed
+ break;
+ }
+
+ OUString sURL = xFolderPicker->getDirectory();
+
+ if(!sURL.isEmpty())
+ {
+ OUString sPath;
+ osl::FileBase::getSystemPathFromFileURL(sURL, sPath);
+
+ sSelectedPaths.push_back(sPath);
+ }
+
+ }
+ break;
+ default:
+ throw uno::RuntimeException();
+ }
+
+ m_xItems = css::uno::Reference< ov::excel::XFileDialogSelectedItems >(
+ new ScVbaFileDialogSelectedItems(this, mxContext, std::move(sSelectedPaths)) );
+ return nRet;
+}
+
+// XHelperInterface
+OUString
+ScVbaFileDialog::getServiceImplName()
+{
+ return "ScVbaFileDialog";
+}
+
+uno::Sequence<OUString>
+ScVbaFileDialog::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.FileDialog"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbafiledialog.hxx b/sc/source/ui/vba/vbafiledialog.hxx
new file mode 100644
index 000000000..f339e4a97
--- /dev/null
+++ b/sc/source/ui/vba/vbafiledialog.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 <ooo/vba/excel/XFileDialog.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace ooo::vba { class XHelperInterface; }
+namespace ooo::vba::excel { class XFileDialogSelectedItems; }
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XFileDialog > ScVbaFileDialog_BASE;
+
+class ScVbaFileDialog : public ScVbaFileDialog_BASE
+{
+private:
+ sal_Int32 m_nType;
+ OUString m_sTitle;
+ OUString m_sInitialFileName;
+ bool m_bMultiSelectMode;
+ css::uno::Reference< ov::excel::XFileDialogSelectedItems> m_xItems;
+public:
+ ScVbaFileDialog( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const sal_Int32 nType);
+
+ virtual css::uno::Any SAL_CALL getInitialFileName() override;
+ virtual void SAL_CALL setInitialFileName( const css::uno::Any& rName ) override;
+ virtual css::uno::Any SAL_CALL getTitle() override;
+ virtual void SAL_CALL setTitle( const css::uno::Any& rTitle ) override;
+ virtual css::uno::Any SAL_CALL getAllowMultiSelect() override;
+ virtual void SAL_CALL setAllowMultiSelect(const css::uno::Any& rAllowMultiSelect) override;
+
+ virtual css::uno::Reference< ov::excel::XFileDialogSelectedItems > SAL_CALL getSelectedItems() override;
+
+ virtual sal_Int32 SAL_CALL Show() override;
+
+ //XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbafiledialogitems.cxx b/sc/source/ui/vba/vbafiledialogitems.cxx
new file mode 100644
index 000000000..d34ace3c5
--- /dev/null
+++ b/sc/source/ui/vba/vbafiledialogitems.cxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <o3tl/safeint.hxx>
+
+#include "vbafiledialogitems.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+namespace {
+
+class FileDialogItemEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration >
+{
+ std::vector< OUString > m_sItems;
+ std::vector< OUString >::iterator mIt;
+public:
+ explicit FileDialogItemEnumeration( std::vector< OUString >&& rVector ) : m_sItems( std::move(rVector) ), mIt( m_sItems.begin() ) {}
+ virtual sal_Bool SAL_CALL hasMoreElements() override
+ {
+ return ( mIt != m_sItems.end() );
+ }
+ virtual uno::Any SAL_CALL nextElement() override
+ {
+ if( !hasMoreElements() )
+ throw container::NoSuchElementException();
+ OUString sPath = *mIt++;
+ return uno::Any( sPath );
+ }
+};
+
+}
+
+ScVbaFileDialogSelectedItems::ScVbaFileDialogSelectedItems(
+ const css::uno::Reference< ov::XHelperInterface >& xParent
+ ,const css::uno::Reference< css::uno::XComponentContext >& xContext
+ ,std::vector< OUString >&& rItems)
+ : FileDialogSelectedItems_BASE( xParent, xContext, uno::Reference< container::XIndexAccess>() )
+ , m_sItems(std::move(rItems)) {}
+
+
+// XEnumerationAccess
+uno::Type SAL_CALL
+ScVbaFileDialogSelectedItems::getElementType()
+{
+ return cppu::UnoType<OUString>::get();
+}
+
+uno::Reference< container::XEnumeration >
+ScVbaFileDialogSelectedItems::createEnumeration()
+{
+ return uno::Reference< container::XEnumeration >( new FileDialogItemEnumeration( std::vector(m_sItems) ) );
+}
+
+uno::Any
+ScVbaFileDialogSelectedItems::createCollectionObject( const uno::Any& aSource )
+{
+ sal_Int32 nPosition = -1;
+ if (!(aSource >>= nPosition))
+ throw uno::RuntimeException("not an sal_Int32");
+ if (nPosition < 0 || o3tl::make_unsigned(nPosition) >= m_sItems.size())
+ throw uno::RuntimeException("out of range");
+
+ OUString sPath = m_sItems[nPosition];
+ return uno::Any( sPath );
+}
+
+// Methods
+uno::Any SAL_CALL
+ScVbaFileDialogSelectedItems::Item( const uno::Any& aIndex, const uno::Any& /*aIndex*/ )
+{
+ sal_Int32 nPosition = -1;
+ aIndex >>= nPosition;
+
+ --nPosition; // vba indexing starts with 1
+
+ if( nPosition < 0 || nPosition >= getCount() )
+ {
+ throw uno::RuntimeException();
+ }
+
+ return createCollectionObject( uno::Any( nPosition ) );
+}
+
+sal_Int32 ScVbaFileDialogSelectedItems::getCount()
+{
+ return m_sItems.size();
+}
+
+// XHelperInterface
+OUString
+ScVbaFileDialogSelectedItems::getServiceImplName()
+{
+ return "ScVbaFileDialogSelectedItems";
+}
+
+uno::Sequence<OUString>
+ScVbaFileDialogSelectedItems::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.FileDialogSelectedItems"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbafiledialogitems.hxx b/sc/source/ui/vba/vbafiledialogitems.hxx
new file mode 100644
index 000000000..5a01df010
--- /dev/null
+++ b/sc/source/ui/vba/vbafiledialogitems.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 <ooo/vba/excel/XFileDialogSelectedItems.hpp>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+typedef CollTestImplHelper< ov::excel::XFileDialogSelectedItems > FileDialogSelectedItems_BASE;
+
+class ScVbaFileDialogSelectedItems final : public FileDialogSelectedItems_BASE
+{
+ const std::vector<OUString> m_sItems;
+public:
+ std::vector<OUString> const& getItems()
+ {
+ return m_sItems;
+ }
+
+ ScVbaFileDialogSelectedItems( const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ std::vector<OUString>&& sItems);
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+
+ // Methods
+ virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index, const css::uno::Any& /*Index2*/ ) override;
+ virtual sal_Int32 SAL_CALL getCount() override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbafont.cxx b/sc/source/ui/vba/vbafont.cxx
new file mode 100644
index 000000000..99afd919b
--- /dev/null
+++ b/sc/source/ui/vba/vbafont.cxx
@@ -0,0 +1,329 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/awt/FontUnderline.hpp>
+#include <ooo/vba/excel/XlColorIndex.hpp>
+#include <ooo/vba/excel/XlUnderlineStyle.hpp>
+#include <svl/itemset.hxx>
+#include <o3tl/string_view.hxx>
+#include "excelvbahelper.hxx"
+#include "vbafont.hxx"
+#include "vbapalette.hxx"
+#include <scitems.hxx>
+#include <cellsuno.hxx>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+ScVbaFont::ScVbaFont(
+ const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const ScVbaPalette& dPalette,
+ const uno::Reference< beans::XPropertySet >& xPropertySet,
+ ScCellRangeObj* pRangeObj, bool bFormControl ) :
+ ScVbaFont_BASE( xParent, xContext, dPalette.getPalette(), xPropertySet, bFormControl ),
+ mpRangeObj( pRangeObj )
+{
+}
+
+SfxItemSet*
+ScVbaFont::GetDataSet()
+{
+ return mpRangeObj ? excel::ScVbaCellRangeAccess::GetDataSet( mpRangeObj ) : nullptr;
+}
+
+ScVbaFont::~ScVbaFont()
+{
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getSize()
+{
+ if ( GetDataSet() )
+ if ( GetDataSet()->GetItemState( ATTR_FONT_HEIGHT) == SfxItemState::DONTCARE )
+ return aNULL();
+ return ScVbaFont_BASE::getSize();
+}
+
+void SAL_CALL
+ScVbaFont::setColorIndex( const uno::Any& _colorindex )
+{
+ if(mbFormControl)
+ return;
+
+ sal_Int32 nIndex = 0;
+ _colorindex >>= nIndex;
+ // #FIXME xlColorIndexAutomatic & xlColorIndexNone are not really
+ // handled properly here
+
+ if ( !nIndex || ( nIndex == excel::XlColorIndex::xlColorIndexAutomatic ) )
+ {
+ nIndex = 1; // check default ( assume black )
+ ScVbaFont_BASE::setColorIndex( uno::Any( nIndex ) );
+ }
+ else
+ ScVbaFont_BASE::setColorIndex( _colorindex );
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getColorIndex()
+{
+ if(mbFormControl)
+ return uno::Any( sal_Int32(0) );
+ if ( GetDataSet() )
+ if ( GetDataSet()->GetItemState( ATTR_FONT_COLOR) == SfxItemState::DONTCARE )
+ return aNULL();
+ return ScVbaFont_BASE::getColorIndex();
+}
+
+void SAL_CALL
+ScVbaFont::setStandardFontSize( const uno::Any& /*aValue*/ )
+{
+//XXX #TODO# #FIXME#
+ //mxFont->setPropertyValue("CharSize", ( uno::Any )fValue );
+ throw uno::RuntimeException(
+ "setStandardFontSize not supported" );
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getStandardFontSize()
+{
+//XXX #TODO# #FIXME#
+ throw uno::RuntimeException( "getStandardFontSize not supported" );
+ // return uno::Any();
+}
+
+void SAL_CALL
+ScVbaFont::setStandardFont( const uno::Any& /*aValue*/ )
+{
+//XXX #TODO# #FIXME#
+ throw uno::RuntimeException("setStandardFont not supported" );
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getStandardFont()
+{
+//XXX #TODO# #FIXME#
+ throw uno::RuntimeException("getStandardFont not supported");
+ // return uno::Any();
+}
+
+void SAL_CALL
+ScVbaFont::setFontStyle( const uno::Any& aValue )
+{
+ bool bBold = false;
+ bool bItalic = false;
+
+ OUString aStyles;
+ aValue >>= aStyles;
+
+ for (sal_Int32 nIdx{ 0 }; nIdx>=0; )
+ {
+ const std::u16string_view aToken{ o3tl::getToken(aStyles, 0, ' ', nIdx ) };
+ if (o3tl::equalsIgnoreAsciiCase(aToken, u"Bold"))
+ {
+ bBold = true;
+ if (bItalic)
+ break;
+ }
+ else if (o3tl::equalsIgnoreAsciiCase(aToken, u"Italic"))
+ {
+ bItalic = true;
+ if (bBold)
+ break;
+ }
+ }
+
+ setBold( uno::Any( bBold ) );
+ setItalic( uno::Any( bItalic ) );
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getFontStyle()
+{
+ OUStringBuffer aStyles;
+ bool bValue = false;
+ getBold() >>= bValue;
+ if( bValue )
+ aStyles.append("Bold");
+
+ getItalic() >>= bValue;
+ if( bValue )
+ {
+ if( !aStyles.isEmpty() )
+ aStyles.append(" ");
+ aStyles.append("Italic");
+ }
+ return uno::Any( aStyles.makeStringAndClear() );
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getBold()
+{
+ if ( GetDataSet() )
+ if ( GetDataSet()->GetItemState( ATTR_FONT_WEIGHT) == SfxItemState::DONTCARE )
+ return aNULL();
+ return ScVbaFont_BASE::getBold();
+}
+
+void SAL_CALL
+ScVbaFont::setUnderline( const uno::Any& aValue )
+{
+ if(mbFormControl)
+ return;
+
+ // default
+ sal_Int32 nValue = excel::XlUnderlineStyle::xlUnderlineStyleNone;
+ aValue >>= nValue;
+ switch ( nValue )
+ {
+// NOTE:: #TODO #FIMXE
+// xlUnderlineStyleDoubleAccounting & xlUnderlineStyleSingleAccounting
+// don't seem to be supported in Openoffice.
+// The import filter converts them to single or double underlines as appropriate
+// So, here at the moment we are similarly silently converting
+// xlUnderlineStyleSingleAccounting to xlUnderlineStyleSingle.
+
+ case excel::XlUnderlineStyle::xlUnderlineStyleNone:
+ nValue = awt::FontUnderline::NONE;
+ break;
+ case excel::XlUnderlineStyle::xlUnderlineStyleSingle:
+ case excel::XlUnderlineStyle::xlUnderlineStyleSingleAccounting:
+ nValue = awt::FontUnderline::SINGLE;
+ break;
+ case excel::XlUnderlineStyle::xlUnderlineStyleDouble:
+ case excel::XlUnderlineStyle::xlUnderlineStyleDoubleAccounting:
+ nValue = awt::FontUnderline::DOUBLE;
+ break;
+ default:
+ throw uno::RuntimeException("Unknown value for Underline" );
+ }
+
+ mxFont->setPropertyValue("CharUnderline", uno::Any(nValue) );
+
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getUnderline()
+{
+ if ( GetDataSet() )
+ if ( GetDataSet()->GetItemState( ATTR_FONT_UNDERLINE) == SfxItemState::DONTCARE )
+ return aNULL();
+
+ sal_Int32 nValue = awt::FontUnderline::NONE;
+
+ if(mbFormControl)
+ return uno::Any( nValue );
+
+ mxFont->getPropertyValue("CharUnderline") >>= nValue;
+ switch ( nValue )
+ {
+ case awt::FontUnderline::DOUBLE:
+ nValue = excel::XlUnderlineStyle::xlUnderlineStyleDouble;
+ break;
+ case awt::FontUnderline::SINGLE:
+ nValue = excel::XlUnderlineStyle::xlUnderlineStyleSingle;
+ break;
+ case awt::FontUnderline::NONE:
+ nValue = excel::XlUnderlineStyle::xlUnderlineStyleNone;
+ break;
+ default:
+ throw uno::RuntimeException("Unknown value retrieved for Underline" );
+
+ }
+ return uno::Any( nValue );
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getStrikethrough()
+{
+ if ( GetDataSet() )
+ if ( GetDataSet()->GetItemState( ATTR_FONT_CROSSEDOUT) == SfxItemState::DONTCARE )
+ return aNULL();
+ return ScVbaFont_BASE::getStrikethrough();
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getShadow()
+{
+ if ( GetDataSet() )
+ if ( GetDataSet()->GetItemState( ATTR_FONT_SHADOWED) == SfxItemState::DONTCARE )
+ return aNULL();
+ return ScVbaFont_BASE::getShadow();
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getItalic()
+{
+ if ( GetDataSet() )
+ if ( GetDataSet()->GetItemState( ATTR_FONT_POSTURE) == SfxItemState::DONTCARE )
+ return aNULL();
+
+ return ScVbaFont_BASE::getItalic();
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getName()
+{
+ if ( GetDataSet() )
+ if ( GetDataSet()->GetItemState( ATTR_FONT) == SfxItemState::DONTCARE )
+ return aNULL();
+ return ScVbaFont_BASE::getName();
+}
+uno::Any
+ScVbaFont::getColor()
+{
+ // #TODO #FIXME - behave like getXXX above ( wrt. GetDataSet )
+ uno::Any aAny = OORGBToXLRGB( mxFont->getPropertyValue("CharColor") );
+ return aAny;
+}
+
+void SAL_CALL
+ScVbaFont::setOutlineFont( const uno::Any& aValue )
+{
+ if(!mbFormControl)
+ mxFont->setPropertyValue("CharContoured", aValue );
+}
+
+uno::Any SAL_CALL
+ScVbaFont::getOutlineFont()
+{
+ if ( GetDataSet() )
+ if ( GetDataSet()->GetItemState( ATTR_FONT_CONTOUR) == SfxItemState::DONTCARE )
+ return aNULL();
+ return mbFormControl ? uno::Any( false ) : mxFont->getPropertyValue("CharContoured");
+}
+
+OUString
+ScVbaFont::getServiceImplName()
+{
+ return "ScVbaFont";
+}
+
+uno::Sequence< OUString >
+ScVbaFont::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Font"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbafont.hxx b/sc/source/ui/vba/vbafont.hxx
new file mode 100644
index 000000000..d6a01b9a0
--- /dev/null
+++ b/sc/source/ui/vba/vbafont.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 <cppuhelper/implbase.hxx>
+
+#include <ooo/vba/excel/XFont.hpp>
+#include <vbahelper/vbafontbase.hxx>
+
+namespace com::sun::star::beans
+{
+class XPropertySet;
+}
+
+class ScCellRangeObj;
+class SfxItemSet;
+class ScVbaPalette;
+
+typedef cppu::ImplInheritanceHelper<VbaFontBase, ov::excel::XFont> ScVbaFont_BASE;
+
+class ScVbaFont : public ScVbaFont_BASE
+{
+ ScCellRangeObj* mpRangeObj;
+ SfxItemSet* GetDataSet();
+
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaFont(const css::uno::Reference<ov::XHelperInterface>& xParent,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ const ScVbaPalette& dPalette,
+ const css::uno::Reference<css::beans::XPropertySet>& xPropertySet,
+ ScCellRangeObj* pRangeObj = nullptr, bool bFormControl = false);
+ virtual ~ScVbaFont() override; // {}
+
+ // Attributes
+ virtual css::uno::Any SAL_CALL getSize() override;
+ virtual css::uno::Any SAL_CALL getStandardFontSize() override;
+ virtual void SAL_CALL setStandardFontSize(const css::uno::Any& _standardfontsize) override;
+ virtual css::uno::Any SAL_CALL getStandardFont() override;
+ virtual void SAL_CALL setStandardFont(const css::uno::Any& _standardfont) override;
+ virtual css::uno::Any SAL_CALL getFontStyle() override;
+ virtual void SAL_CALL setFontStyle(const css::uno::Any& _fontstyle) override;
+ virtual css::uno::Any SAL_CALL getColorIndex() override;
+ virtual void SAL_CALL setColorIndex(const css::uno::Any& _colorindex) override;
+ virtual css::uno::Any SAL_CALL getBold() override;
+ virtual css::uno::Any SAL_CALL getUnderline() override;
+ virtual void SAL_CALL setUnderline(const css::uno::Any& _underline) override;
+ virtual css::uno::Any SAL_CALL getStrikethrough() override;
+ virtual css::uno::Any SAL_CALL getShadow() override;
+ virtual css::uno::Any SAL_CALL getItalic() override;
+ virtual css::uno::Any SAL_CALL getName() override;
+ virtual css::uno::Any SAL_CALL getColor() override;
+ virtual css::uno::Any SAL_CALL getOutlineFont() override;
+ virtual void SAL_CALL setOutlineFont(const css::uno::Any& _outlinefont) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaformat.cxx b/sc/source/ui/vba/vbaformat.cxx
new file mode 100644
index 000000000..a027279ae
--- /dev/null
+++ b/sc/source/ui/vba/vbaformat.cxx
@@ -0,0 +1,814 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "vbaformat.hxx"
+#include <ooo/vba/excel/XFont.hpp>
+#include <ooo/vba/excel/XStyle.hpp>
+#include <ooo/vba/excel/XlVAlign.hpp>
+#include <ooo/vba/excel/XlHAlign.hpp>
+#include <ooo/vba/excel/XlOrientation.hpp>
+#include <ooo/vba/excel/Constants.hpp>
+#include <ooo/vba/excel/XRange.hpp>
+#include <com/sun/star/table/CellVertJustify2.hpp>
+#include <com/sun/star/table/CellHoriJustify.hpp>
+#include <com/sun/star/table/CellOrientation.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/util/CellProtection.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+
+#include <basic/sberrors.hxx>
+#include <rtl/math.hxx>
+
+#include "excelvbahelper.hxx"
+#include "vbaborders.hxx"
+#include "vbapalette.hxx"
+#include "vbafont.hxx"
+#include "vbainterior.hxx"
+
+#include <docsh.hxx>
+#include <unonames.hxx>
+#include <cellsuno.hxx>
+#include <scitems.hxx>
+#include <attrib.hxx>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+constexpr OUStringLiteral FORMATSTRING = u"FormatString";
+constexpr OUStringLiteral LOCALE = u"Locale";
+
+template< typename... Ifc >
+ScVbaFormat< Ifc... >::ScVbaFormat( const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext > & xContext,
+ const uno::Reference< beans::XPropertySet >& _xPropertySet,
+ const uno::Reference< frame::XModel >& xModel,
+ bool bCheckAmbiguoity )
+ : ScVbaFormat_BASE( xParent, xContext ),
+ m_aDefaultLocale( "en", "US", OUString() ),
+ mxPropertySet( _xPropertySet ),
+ mxModel( xModel ),
+ mbCheckAmbiguoity( bCheckAmbiguoity ),
+ mbAddIndent( false )
+{
+ try
+ {
+ if ( !mxModel.is() )
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, u"XModel Interface could not be retrieved" );
+ // mxServiceInfo is unused,
+ // mxNumberFormatsSupplier is initialized when needed in initializeNumberFormats.
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+}
+
+template< typename... Ifc >
+void SAL_CALL
+ScVbaFormat< Ifc... >::setVerticalAlignment( const uno::Any& _oAlignment)
+{
+ try
+ {
+ uno::Any aVal;
+ sal_Int32 nAlignment = 0;
+ if ( !(_oAlignment >>= nAlignment ))
+ throw uno::RuntimeException();
+ switch (nAlignment)
+ {
+ case excel::XlVAlign::xlVAlignBottom :
+ aVal <<= table::CellVertJustify2::BOTTOM;
+ break;
+ case excel::XlVAlign::xlVAlignCenter :
+ aVal <<= table::CellVertJustify2::CENTER;
+ break;
+ case excel::XlVAlign::xlVAlignDistributed:
+ case excel::XlVAlign::xlVAlignJustify:
+ aVal <<= table::CellVertJustify2::STANDARD;
+ break;
+
+ case excel::XlVAlign::xlVAlignTop:
+ aVal <<= table::CellVertJustify2::TOP;
+ break;
+ default:
+ aVal <<= table::CellVertJustify2::STANDARD;
+ break;
+ }
+ mxPropertySet->setPropertyValue( SC_UNONAME_CELLVJUS, aVal );
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::getVerticalAlignment( )
+{
+ uno::Any aResult = aNULL();
+ try
+ {
+ if (!isAmbiguous( SC_UNONAME_CELLVJUS ) )
+ {
+ sal_Int32 aAPIAlignment = table::CellVertJustify2::STANDARD;
+ mxPropertySet->getPropertyValue( SC_UNONAME_CELLVJUS ) >>= aAPIAlignment;
+ switch( aAPIAlignment )
+ {
+ case table::CellVertJustify2::BOTTOM:
+ aResult <<= excel::XlVAlign::xlVAlignBottom;
+ break;
+ case table::CellVertJustify2::CENTER:
+ aResult <<= excel::XlVAlign::xlVAlignCenter;
+ break;
+ case table::CellVertJustify2::STANDARD:
+ aResult <<= excel::XlVAlign::xlVAlignBottom;
+ break;
+ case table::CellVertJustify2::TOP:
+ aResult <<= excel::XlVAlign::xlVAlignTop;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return aResult;
+}
+
+template< typename... Ifc >
+void SAL_CALL
+ScVbaFormat< Ifc... >::setHorizontalAlignment( const uno::Any& HorizontalAlignment )
+{
+ try
+ {
+ uno::Any aVal;
+ sal_Int32 nAlignment = 0;
+ if ( !( HorizontalAlignment >>= nAlignment ) )
+ throw uno::RuntimeException();
+ switch ( nAlignment )
+ {
+ case excel::XlHAlign::xlHAlignJustify:
+ aVal <<= table::CellHoriJustify_BLOCK;
+ break;
+ case excel::XlHAlign::xlHAlignCenter:
+ aVal <<= table::CellHoriJustify_CENTER;
+ break;
+ case excel::XlHAlign::xlHAlignDistributed:
+ aVal <<= table::CellHoriJustify_BLOCK;
+ break;
+ case excel::XlHAlign::xlHAlignLeft:
+ aVal <<= table::CellHoriJustify_LEFT;
+ break;
+ case excel::XlHAlign::xlHAlignRight:
+ aVal <<= table::CellHoriJustify_RIGHT;
+ break;
+ }
+ // #FIXME what about the default case above?
+ // shouldn't need the test below
+ if ( aVal.hasValue() )
+ mxPropertySet->setPropertyValue( SC_UNONAME_CELLHJUS, aVal );
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+
+}
+
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::getHorizontalAlignment( )
+{
+ uno::Any NRetAlignment = aNULL();
+ try
+ {
+ OUString sHoriJust( SC_UNONAME_CELLHJUS );
+ if (!isAmbiguous(sHoriJust))
+ {
+ table::CellHoriJustify aAPIAlignment = table::CellHoriJustify_BLOCK;
+
+ if ( mxPropertySet->getPropertyValue(sHoriJust) >>= aAPIAlignment )
+ {
+ switch( aAPIAlignment )
+ {
+ case table::CellHoriJustify_BLOCK:
+ NRetAlignment <<= excel::XlHAlign::xlHAlignJustify;
+ break;
+ case table::CellHoriJustify_CENTER:
+ NRetAlignment <<= excel::XlHAlign::xlHAlignCenter;
+ break;
+ case table::CellHoriJustify_LEFT:
+ NRetAlignment <<= excel::XlHAlign::xlHAlignLeft;
+ break;
+ case table::CellHoriJustify_RIGHT:
+ NRetAlignment <<= excel::XlHAlign::xlHAlignRight;
+ break;
+ default: // handle those other cases with a NULL return
+ break;
+ }
+ }
+ }
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+ return NRetAlignment;
+}
+
+template< typename... Ifc >
+void SAL_CALL
+ScVbaFormat< Ifc... >::setOrientation( const uno::Any& _aOrientation )
+{
+ try
+ {
+ sal_Int32 nOrientation = 0;
+ if ( !( _aOrientation >>= nOrientation ) )
+ throw uno::RuntimeException();
+ uno::Any aVal;
+ switch( nOrientation )
+ {
+ case excel::XlOrientation::xlDownward:
+ aVal <<= table::CellOrientation_TOPBOTTOM;
+ break;
+ case excel::XlOrientation::xlHorizontal:
+ aVal <<= table::CellOrientation_STANDARD;
+ mxPropertySet->setPropertyValue( SC_UNONAME_ROTANG, uno::Any( sal_Int32(0) ) );
+ break;
+ case excel::XlOrientation::xlUpward:
+ aVal <<= table::CellOrientation_BOTTOMTOP;
+ break;
+ case excel::XlOrientation::xlVertical:
+ aVal <<= table::CellOrientation_STACKED;
+ break;
+ }
+ // #FIXME what about the default case above?
+ // shouldn't need the test below
+ if ( aVal.hasValue() )
+ mxPropertySet->setPropertyValue( SC_UNONAME_CELLORI, aVal );
+
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+}
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::getOrientation( )
+{
+ uno::Any NRetOrientation = aNULL();
+ try
+ {
+ if (!isAmbiguous(SC_UNONAME_CELLORI))
+ {
+ table::CellOrientation aOrientation = table::CellOrientation_STANDARD;
+ if ( !( mxPropertySet->getPropertyValue( SC_UNONAME_CELLORI ) >>= aOrientation ) )
+ throw uno::RuntimeException();
+
+ switch(aOrientation)
+ {
+ case table::CellOrientation_STANDARD:
+ NRetOrientation <<= excel::XlOrientation::xlHorizontal;
+ break;
+ case table::CellOrientation_BOTTOMTOP:
+ NRetOrientation <<= excel::XlOrientation::xlUpward;
+ break;
+ case table::CellOrientation_TOPBOTTOM:
+ NRetOrientation <<= excel::XlOrientation::xlDownward;
+ break;
+ case table::CellOrientation_STACKED:
+ NRetOrientation <<= excel::XlOrientation::xlVertical;
+ break;
+ default:
+ NRetOrientation <<= excel::XlOrientation::xlHorizontal;
+ }
+ }
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return NRetOrientation;
+}
+
+template< typename... Ifc >
+void SAL_CALL
+ScVbaFormat< Ifc... >::setWrapText( const uno::Any& _aWrapText )
+{
+ try
+ {
+ mxPropertySet->setPropertyValue( SC_UNONAME_WRAP, _aWrapText);
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+}
+
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::getWrapText( )
+{
+ uno::Any aWrap = aNULL();
+ try
+ {
+ OUString aPropName( SC_UNONAME_WRAP );
+ if (!isAmbiguous( aPropName ))
+ {
+ aWrap = mxPropertySet->getPropertyValue(aPropName);
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+ return aWrap;
+}
+
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::Borders( const uno::Any& Index )
+{
+ ScVbaPalette aPalette( excel::getDocShell( mxModel ) );
+ uno::Reference< XCollection > xColl = new ScVbaBorders( thisHelperIface(), ScVbaFormat_BASE::mxContext, uno::Reference< table::XCellRange >( mxPropertySet, uno::UNO_QUERY_THROW ), aPalette );
+
+ if ( Index.hasValue() )
+ {
+ return xColl->Item( Index, uno::Any() );
+ }
+ return uno::Any( xColl );
+}
+
+template< typename... Ifc >
+uno::Reference< excel::XFont > SAL_CALL
+ScVbaFormat< Ifc... >::Font( )
+{
+ ScVbaPalette aPalette( excel::getDocShell( mxModel ) );
+ return new ScVbaFont( thisHelperIface(), ScVbaFormat_BASE::mxContext, aPalette, mxPropertySet );
+}
+
+template< typename... Ifc >
+uno::Reference< excel::XInterior > SAL_CALL
+ScVbaFormat< Ifc... >::Interior( )
+{
+ return new ScVbaInterior( thisHelperIface(), ScVbaFormat_BASE::mxContext, mxPropertySet );
+}
+
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::getNumberFormatLocal( )
+{
+ uno::Any aRet{ OUString() };
+ try
+ {
+ OUString sPropName( SC_UNO_DP_NUMBERFO );
+ if (!isAmbiguous( sPropName ))
+ {
+
+ initializeNumberFormats();
+
+ sal_Int32 nFormat = 0;
+ if ( ! (mxPropertySet->getPropertyValue( sPropName ) >>= nFormat ) )
+ throw uno::RuntimeException();
+
+ OUString sFormat;
+ xNumberFormats->getByKey(nFormat)->getPropertyValue( FORMATSTRING ) >>= sFormat;
+ aRet <<= sFormat.toAsciiLowerCase();
+
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return aRet;
+
+}
+
+template< typename... Ifc >
+void SAL_CALL
+ScVbaFormat< Ifc... >::setNumberFormatLocal( const uno::Any& _oLocalFormatString )
+{
+ try
+ {
+ OUString sLocalFormatString;
+ sal_Int32 nFormat = -1;
+ OUString sNumFormat( SC_UNO_DP_NUMBERFO );
+ if ( !(_oLocalFormatString >>= sLocalFormatString )
+ || !( mxPropertySet->getPropertyValue(sNumFormat) >>= nFormat ) )
+ throw uno::RuntimeException();
+
+ sLocalFormatString = sLocalFormatString.toAsciiUpperCase();
+ initializeNumberFormats();
+ lang::Locale aRangeLocale;
+ xNumberFormats->getByKey(nFormat)->getPropertyValue( LOCALE ) >>= aRangeLocale;
+ sal_Int32 nNewFormat = xNumberFormats->queryKey(sLocalFormatString, aRangeLocale, true);
+
+ if (nNewFormat == -1)
+ nNewFormat = xNumberFormats->addNew(sLocalFormatString, aRangeLocale);
+ mxPropertySet->setPropertyValue(sNumFormat, uno::Any( nNewFormat ));
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+}
+
+template< typename... Ifc >
+void SAL_CALL
+ScVbaFormat< Ifc... >::setNumberFormat( const uno::Any& _oFormatString )
+{
+ try
+ {
+ OUString sFormatString;
+ if ( !( _oFormatString >>= sFormatString ) )
+ throw uno::RuntimeException();
+
+ sFormatString = sFormatString.toAsciiUpperCase();
+
+ lang::Locale aDefaultLocale = m_aDefaultLocale;
+ initializeNumberFormats();
+ sal_Int32 nFormat = xNumberFormats->queryKey(sFormatString, aDefaultLocale, true);
+
+ if (nFormat == -1)
+ nFormat = xNumberFormats->addNew(sFormatString, aDefaultLocale);
+
+ lang::Locale aRangeLocale;
+ xNumberFormats->getByKey(nFormat)->getPropertyValue( LOCALE ) >>= aRangeLocale;
+ sal_Int32 nNewFormat = xNumberFormatTypes->getFormatForLocale(nFormat, aRangeLocale);
+ mxPropertySet->setPropertyValue( SC_UNO_DP_NUMBERFO, uno::Any( nNewFormat));
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+
+}
+
+template< typename... Ifc >
+void SAL_CALL
+ScVbaFormat< Ifc... >::setIndentLevel( const uno::Any& _aLevel )
+{
+ try
+ {
+ sal_Int32 nLevel = 0;
+ if ( !(_aLevel >>= nLevel ) )
+ throw uno::RuntimeException();
+ table::CellHoriJustify aAPIAlignment = table::CellHoriJustify_STANDARD;
+
+ OUString sHoriJust( SC_UNONAME_CELLHJUS );
+ if ( !( mxPropertySet->getPropertyValue(sHoriJust) >>= aAPIAlignment ) )
+ throw uno::RuntimeException();
+ if (aAPIAlignment == table::CellHoriJustify_STANDARD)
+ mxPropertySet->setPropertyValue( sHoriJust, uno::Any( table::CellHoriJustify_LEFT) ) ;
+ mxPropertySet->setPropertyValue( SC_UNONAME_PINDENT, uno::Any( sal_Int16(nLevel * 352.8) ) );
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::getIndentLevel( )
+{
+ uno::Any NRetIndentLevel = aNULL();
+ try
+ {
+ OUString sParaIndent( SC_UNONAME_PINDENT );
+ if (!isAmbiguous(sParaIndent))
+ {
+ sal_Int16 IndentLevel = 0;
+ if ( mxPropertySet->getPropertyValue(sParaIndent) >>= IndentLevel )
+ NRetIndentLevel <<= sal_Int32( rtl::math::round(static_cast<double>( IndentLevel ) / 352.8));
+ else
+ NRetIndentLevel <<= sal_Int32(0);
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return NRetIndentLevel;
+}
+
+template< typename... Ifc >
+void SAL_CALL
+ScVbaFormat< Ifc... >::setLocked( const uno::Any& _aLocked )
+{
+ try
+ {
+ bool bIsLocked = false;
+ if ( !( _aLocked >>= bIsLocked ) )
+ throw uno::RuntimeException();
+ util::CellProtection aCellProtection;
+ OUString sCellProt( SC_UNONAME_CELLPRO );
+ mxPropertySet->getPropertyValue(sCellProt) >>= aCellProtection;
+ aCellProtection.IsLocked = bIsLocked;
+ mxPropertySet->setPropertyValue(sCellProt, uno::Any( aCellProtection ) );
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+}
+
+template< typename... Ifc >
+void SAL_CALL
+ScVbaFormat< Ifc... >::setFormulaHidden( const uno::Any& FormulaHidden )
+{
+ try
+ {
+ bool bIsFormulaHidden = false;
+ FormulaHidden >>= bIsFormulaHidden;
+ util::CellProtection aCellProtection;
+ OUString sCellProt( SC_UNONAME_CELLPRO );
+ mxPropertySet->getPropertyValue(sCellProt) >>= aCellProtection;
+ aCellProtection.IsFormulaHidden = bIsFormulaHidden;
+ mxPropertySet->setPropertyValue(sCellProt,uno::Any(aCellProtection));
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception( ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+}
+
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::getLocked( )
+{
+ uno::Any aCellProtection = aNULL();
+ try
+ {
+ OUString sCellProt( SC_UNONAME_CELLPRO );
+
+ if (!isAmbiguous(sCellProt))
+ {
+ SfxItemSet* pDataSet = getCurrentDataSet();
+ if ( pDataSet )
+ {
+ const ScProtectionAttr& rProtAttr = pDataSet->Get(ATTR_PROTECTION);
+ SfxItemState eState = pDataSet->GetItemState(ATTR_PROTECTION);
+ if(eState != SfxItemState::DONTCARE)
+ aCellProtection <<= rProtAttr.GetProtection();
+ }
+ else // fallback to propertyset
+ {
+ util::CellProtection cellProtection;
+ mxPropertySet->getPropertyValue(sCellProt) >>= cellProtection;
+ aCellProtection <<= cellProtection.IsLocked;
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return aCellProtection;
+}
+
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::getFormulaHidden( )
+{
+ uno::Any aBoolRet = aNULL();
+ try
+ {
+ OUString sCellProt( SC_UNONAME_CELLPRO );
+ if (!isAmbiguous(sCellProt))
+ {
+ SfxItemSet* pDataSet = getCurrentDataSet();
+ if ( pDataSet )
+ {
+ const ScProtectionAttr& rProtAttr = pDataSet->Get(ATTR_PROTECTION);
+ SfxItemState eState = pDataSet->GetItemState(ATTR_PROTECTION);
+ if(eState != SfxItemState::DONTCARE)
+ aBoolRet <<= rProtAttr.GetHideFormula();
+ }
+ else
+ {
+ util::CellProtection aCellProtection;
+ mxPropertySet->getPropertyValue(sCellProt) >>= aCellProtection;
+ aBoolRet <<= aCellProtection.IsFormulaHidden;
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return aBoolRet;
+}
+
+template< typename... Ifc >
+void SAL_CALL
+ScVbaFormat< Ifc... >::setShrinkToFit( const uno::Any& ShrinkToFit )
+{
+ try
+ {
+ mxPropertySet->setPropertyValue( SC_UNONAME_SHRINK_TO_FIT, ShrinkToFit);
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {} );
+ }
+
+}
+
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::getShrinkToFit( )
+{
+ uno::Any aRet = aNULL();
+ try
+ {
+ OUString sShrinkToFit( SC_UNONAME_SHRINK_TO_FIT );
+ if (!isAmbiguous(sShrinkToFit))
+ aRet = mxPropertySet->getPropertyValue(sShrinkToFit);
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {});
+ }
+ return aRet;
+}
+
+template< typename... Ifc >
+void SAL_CALL
+ScVbaFormat< Ifc... >::setReadingOrder( const uno::Any& ReadingOrder )
+{
+ try
+ {
+ sal_Int32 nReadingOrder = 0;
+ if ( !(ReadingOrder >>= nReadingOrder ))
+ throw uno::RuntimeException();
+ uno::Any aVal = aNULL();
+ switch(nReadingOrder)
+ {
+ case excel::Constants::xlLTR:
+ aVal <<= sal_Int16(text::WritingMode_LR_TB);
+ break;
+ case excel::Constants::xlRTL:
+ aVal <<= sal_Int16(text::WritingMode_RL_TB);
+ break;
+ case excel::Constants::xlContext:
+ // TODO implement xlContext
+ // Reading order has to depend on the language of the first letter
+ // written.
+ aVal <<= sal_Int16(text::WritingMode_LR_TB);
+ break;
+ default:
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ mxPropertySet->setPropertyValue( SC_UNONAME_WRITING, aVal );
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+
+}
+
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::getReadingOrder( )
+{
+ uno::Any NRetReadingOrder = aNULL();
+ try
+ {
+ OUString sWritingMode( SC_UNONAME_WRITING );
+ if (!isAmbiguous(sWritingMode))
+ {
+ text::WritingMode aWritingMode = text::WritingMode_LR_TB;
+ if ( ( mxPropertySet->getPropertyValue(sWritingMode) ) >>= aWritingMode )
+ switch (aWritingMode)
+ {
+ case text::WritingMode_LR_TB:
+ NRetReadingOrder <<= excel::Constants::xlLTR;
+ break;
+ case text::WritingMode_RL_TB:
+ NRetReadingOrder <<= excel::Constants::xlRTL;
+ break;
+ default:
+ NRetReadingOrder <<= excel::Constants::xlRTL;
+ }
+ }
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {});
+ }
+ return NRetReadingOrder;
+
+}
+
+template< typename... Ifc >
+uno::Any SAL_CALL
+ScVbaFormat< Ifc... >::getNumberFormat( )
+{
+ uno::Any aFormat = aNULL();
+ try
+ {
+ sal_Int32 nFormat = -1;
+ OUString sNumFormat( SC_UNO_DP_NUMBERFO );
+ if (!isAmbiguous(sNumFormat) &&
+ ( mxPropertySet->getPropertyValue(sNumFormat) >>= nFormat) )
+ {
+ initializeNumberFormats();
+
+ sal_Int32 nNewFormat = xNumberFormatTypes->getFormatForLocale(nFormat, m_aDefaultLocale );
+ OUString sFormat;
+ xNumberFormats->getByKey(nNewFormat)->getPropertyValue( FORMATSTRING ) >>= sFormat;
+ aFormat <<= sFormat;
+ }
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return aFormat;
+}
+
+template< typename... Ifc >
+bool
+ScVbaFormat< Ifc... >::isAmbiguous(const OUString& _sPropertyName)
+{
+ bool bResult = false;
+ try
+ {
+ if (mbCheckAmbiguoity)
+ bResult = ( getXPropertyState()->getPropertyState(_sPropertyName) == beans::PropertyState_AMBIGUOUS_VALUE );
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return bResult;
+}
+
+template< typename... Ifc >
+void
+ScVbaFormat< Ifc... >::initializeNumberFormats()
+{
+ if ( !xNumberFormats.is() )
+ {
+ mxNumberFormatsSupplier.set( mxModel, uno::UNO_QUERY_THROW );
+ xNumberFormats = mxNumberFormatsSupplier->getNumberFormats();
+ xNumberFormatTypes.set( xNumberFormats, uno::UNO_QUERY ); // _THROW?
+ }
+}
+
+template< typename... Ifc >
+uno::Reference< beans::XPropertyState > const &
+ScVbaFormat< Ifc... >::getXPropertyState()
+{
+ if ( !xPropertyState.is() )
+ xPropertyState.set( mxPropertySet, uno::UNO_QUERY_THROW );
+ return xPropertyState;
+}
+
+template< typename... Ifc >
+ScCellRangesBase*
+ScVbaFormat< Ifc... >::getCellRangesBase()
+{
+ return comphelper::getFromUnoTunnel<ScCellRangesBase>( mxPropertySet );
+}
+
+template< typename... Ifc >
+SfxItemSet*
+ScVbaFormat< Ifc... >::getCurrentDataSet()
+{
+ SfxItemSet* pDataSet = excel::ScVbaCellRangeAccess::GetDataSet( getCellRangesBase() );
+ if ( !pDataSet )
+ throw uno::RuntimeException("Can't access Itemset for XPropertySet" );
+ return pDataSet;
+}
+
+template class ScVbaFormat< excel::XStyle >;
+template class ScVbaFormat< excel::XRange >;
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaformat.hxx b/sc/source/ui/vba/vbaformat.hxx
new file mode 100644
index 000000000..f3c6750ce
--- /dev/null
+++ b/sc/source/ui/vba/vbaformat.hxx
@@ -0,0 +1,154 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <com/sun/star/lang/Locale.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::beans { class XPropertyState; }
+namespace com::sun::star::frame { class XModel; }
+namespace com::sun::star::util { class XNumberFormats; }
+namespace com::sun::star::util { class XNumberFormatsSupplier; }
+namespace com::sun::star::util { class XNumberFormatTypes; }
+namespace ooo::vba::excel { class XFont; }
+namespace ooo::vba::excel { class XInterior; }
+
+class ScCellRangesBase;
+class SfxItemSet;
+
+template< typename... Ifc >
+class ScVbaFormat : public InheritedHelperInterfaceWeakImpl< Ifc... >
+{
+typedef InheritedHelperInterfaceWeakImpl< Ifc... > ScVbaFormat_BASE;
+ css::lang::Locale m_aDefaultLocale;
+protected:
+ css::uno::Reference< css::beans::XPropertySet > mxPropertySet;
+ css::uno::Reference< css::util::XNumberFormatsSupplier > mxNumberFormatsSupplier;
+ css::uno::Reference< css::util::XNumberFormats > xNumberFormats;
+ css::uno::Reference< css::util::XNumberFormatTypes > xNumberFormatTypes;
+ css::uno::Reference< css::frame::XModel > mxModel;
+ css::uno::Reference< css::beans::XPropertyState > xPropertyState;
+ bool mbCheckAmbiguoity;
+ bool mbAddIndent;
+ /// @throws css::script::BasicErrorException
+ bool isAmbiguous(const OUString& _sPropertyName);
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::beans::XPropertyState > const & getXPropertyState();
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ void initializeNumberFormats();
+ /// @throws css::uno::RuntimeException
+ SfxItemSet* getCurrentDataSet( );
+protected:
+ /// @throws css::uno::RuntimeException
+ virtual ScCellRangesBase* getCellRangesBase();
+public:
+ /// @throws css::script::BasicErrorException
+ ScVbaFormat( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::beans::XPropertySet >& _xPropertySet, const css::uno::Reference< css::frame::XModel >& xModel, bool bCheckAmbiguoity );
+ virtual css::uno::Reference< ov::XHelperInterface > thisHelperIface() = 0;
+ /// @throws css::uno::RuntimeException
+ void SAL_CALL setAddIndent( const css::uno::Any& BAddIndent) { BAddIndent >>= mbAddIndent; }
+ /// @throws css::uno::RuntimeException
+ css::uno::Any SAL_CALL getAddIndent() { return css::uno::Any( mbAddIndent ); }
+ // Interface Methods
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL Borders( const css::uno::Any& Index );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Reference< ::ooo::vba::excel::XFont > SAL_CALL Font( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Reference< ::ooo::vba::excel::XInterior > SAL_CALL Interior( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setNumberFormat( const css::uno::Any& NumberFormat );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getNumberFormat( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setNumberFormatLocal( const css::uno::Any& NumberFormatLocal );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getNumberFormatLocal( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setIndentLevel( const css::uno::Any& IndentLevel );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getIndentLevel( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setHorizontalAlignment( const css::uno::Any& HorizontalAlignment );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getHorizontalAlignment( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setVerticalAlignment( const css::uno::Any& VerticalAlignment );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getVerticalAlignment( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setOrientation( const css::uno::Any& Orientation );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getOrientation( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setShrinkToFit( const css::uno::Any& ShrinkToFit );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getShrinkToFit( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setWrapText( const css::uno::Any& WrapText );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getWrapText( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setLocked( const css::uno::Any& Locked );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getLocked( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setFormulaHidden( const css::uno::Any& FormulaHidden );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getFormulaHidden( );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setMergeCells( const css::uno::Any& MergeCells ) = 0;
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getMergeCells( ) = 0;
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual void SAL_CALL setReadingOrder( const css::uno::Any& ReadingOrder );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any SAL_CALL getReadingOrder( );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaformatcondition.cxx b/sc/source/ui/vba/vbaformatcondition.cxx
new file mode 100644
index 000000000..d9804399c
--- /dev/null
+++ b/sc/source/ui/vba/vbaformatcondition.cxx
@@ -0,0 +1,157 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "vbaformatcondition.hxx"
+#include "vbaformatconditions.hxx"
+#include <unonames.hxx>
+#include <ooo/vba/excel/XlFormatConditionType.hpp>
+#include <basic/sberrors.hxx>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+/// @throws css::script::BasicErrorException
+static ScVbaFormatConditions*
+lcl_getScVbaFormatConditionsPtr( const uno::Reference< excel::XFormatConditions >& xFormatConditions )
+{
+ ScVbaFormatConditions* pFormatConditions = static_cast< ScVbaFormatConditions* >( xFormatConditions.get() );
+ if ( !pFormatConditions )
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ return pFormatConditions;
+}
+
+ScVbaFormatCondition::ScVbaFormatCondition( const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext > & xContext,
+ const uno::Reference< sheet::XSheetConditionalEntry >& _xSheetConditionalEntry,
+ const uno::Reference< excel::XStyle >& _xStyle,
+ const uno::Reference< excel::XFormatConditions >& _xFormatConditions,
+ const uno::Reference< css::beans::XPropertySet >& _xPropertySet )
+ : ScVbaFormatCondition_BASE( xParent, xContext,
+ uno::Reference< sheet::XSheetCondition >( _xSheetConditionalEntry, css::uno::UNO_QUERY_THROW ) ),
+ moFormatConditions( _xFormatConditions ), mxStyle( _xStyle ), mxParentRangePropertySet( _xPropertySet )
+{
+ mxSheetConditionalEntries = lcl_getScVbaFormatConditionsPtr( moFormatConditions )->getSheetConditionalEntries();
+
+ msStyleName = mxStyle->getName();
+}
+
+void SAL_CALL
+ScVbaFormatCondition::Delete( )
+{
+ ScVbaFormatConditions* pFormatConditions = lcl_getScVbaFormatConditionsPtr( moFormatConditions );
+ pFormatConditions->removeFormatCondition(msStyleName, true);
+ notifyRange();
+}
+
+void SAL_CALL
+ScVbaFormatCondition::Modify( ::sal_Int32 _nType, const uno::Any& _aOperator, const uno::Any& _aFormula1, const uno::Any& _aFormula2 )
+{
+ try
+ {
+ ScVbaFormatConditions* pFormatConditions = lcl_getScVbaFormatConditionsPtr( moFormatConditions );
+ pFormatConditions->removeFormatCondition(msStyleName, false);
+ pFormatConditions->Add(_nType, _aOperator, _aFormula1, _aFormula2, mxStyle);
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+}
+
+uno::Reference< excel::XInterior > SAL_CALL
+ScVbaFormatCondition::Interior( )
+{
+ return mxStyle->Interior();
+}
+
+uno::Reference< excel::XFont > SAL_CALL
+ScVbaFormatCondition::Font( )
+{
+ return mxStyle->Font();
+}
+uno::Any SAL_CALL
+ScVbaFormatCondition::Borders( const uno::Any& Index )
+{ return mxStyle->Borders( Index );
+}
+
+sheet::ConditionOperator
+ScVbaFormatCondition::retrieveAPIType(sal_Int32 _nVBAType, const uno::Reference< sheet::XSheetCondition >& _xSheetCondition )
+{
+ sheet::ConditionOperator aAPIType = sheet::ConditionOperator_NONE;
+ switch (_nVBAType)
+ {
+ case excel::XlFormatConditionType::xlExpression:
+ aAPIType = sheet::ConditionOperator_FORMULA;
+ break;
+ case excel::XlFormatConditionType::xlCellValue:
+ if ( _xSheetCondition.is() && (_xSheetCondition->getOperator() == sheet::ConditionOperator_FORMULA ) )
+ aAPIType = sheet::ConditionOperator_NONE;
+ break;
+ default:
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+ return aAPIType;
+}
+
+::sal_Int32 SAL_CALL
+ScVbaFormatCondition::Type( )
+{
+ sal_Int32 nReturnType = 0;
+ if ( mxSheetCondition->getOperator() == sheet::ConditionOperator_FORMULA)
+ nReturnType = excel::XlFormatConditionType::xlExpression;
+ else
+ nReturnType = excel::XlFormatConditionType::xlCellValue;
+ return nReturnType;
+}
+
+::sal_Int32 SAL_CALL
+ScVbaFormatCondition::Operator( )
+{
+ return ScVbaFormatCondition_BASE::Operator( true );
+}
+
+void
+ScVbaFormatCondition::notifyRange()
+{
+ try
+ {
+ mxParentRangePropertySet->setPropertyValue(SC_UNONAME_CONDFMT, uno::Any( mxSheetConditionalEntries));
+ }
+ catch (uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+}
+
+OUString
+ScVbaFormatCondition::getServiceImplName()
+{
+ return "ScVbaFormatCondition";
+}
+
+uno::Sequence< OUString >
+ScVbaFormatCondition::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.FormatCondition"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaformatcondition.hxx b/sc/source/ui/vba/vbaformatcondition.hxx
new file mode 100644
index 000000000..7d09a11b9
--- /dev/null
+++ b/sc/source/ui/vba/vbaformatcondition.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 <ooo/vba/excel/XFormatCondition.hpp>
+#include <ooo/vba/excel/XFormatConditions.hpp>
+#include <ooo/vba/excel/XStyle.hpp>
+#include <com/sun/star/sheet/XSheetConditionalEntries.hpp>
+#include <com/sun/star/sheet/XSheetConditionalEntry.hpp>
+#include <com/sun/star/sheet/XSheetCondition.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include "vbacondition.hxx"
+
+typedef ScVbaCondition< ov::excel::XFormatCondition > ScVbaFormatCondition_BASE;
+class ScVbaFormatCondition final : public ScVbaFormatCondition_BASE
+{
+ OUString msStyleName;
+ css::uno::Reference< css::sheet::XSheetConditionalEntries > mxSheetConditionalEntries;
+ css::uno::Reference< ov::excel::XFormatConditions> moFormatConditions;
+ css::uno::Reference< ov::excel::XStyle > mxStyle;
+ css::uno::Reference< css::beans::XPropertySet > mxParentRangePropertySet;
+
+public:
+ /// @throws css::uno::RuntimeException
+ /// @throws css::script::BasicErrorException
+ ScVbaFormatCondition( const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext > & xContext,
+ const css::uno::Reference< css::sheet::XSheetConditionalEntry >& _xSheetConditionalEntry,
+ const css::uno::Reference< ov::excel::XStyle >&,
+ const css::uno::Reference< ov::excel::XFormatConditions >& _xFormatConditions,
+ const css::uno::Reference< css::beans::XPropertySet >& _xPropertySet );
+
+ /// @throws css::script::BasicErrorException
+ void notifyRange();
+ /// @throws css::script::BasicErrorException
+ static css::sheet::ConditionOperator retrieveAPIType(sal_Int32 _nVBAType, const css::uno::Reference< css::sheet::XSheetCondition >& _xSheetCondition );
+
+ //Methods
+ virtual void SAL_CALL Delete( ) override;
+ virtual void SAL_CALL Modify( ::sal_Int32 Type, const css::uno::Any& Operator, const css::uno::Any& Formula1, const css::uno::Any& Formula2 ) override;
+ virtual ::sal_Int32 SAL_CALL Type( ) override;
+ using ScVbaFormatCondition_BASE::Operator;
+ virtual ::sal_Int32 SAL_CALL Operator( ) override;
+ virtual css::uno::Reference< ::ooo::vba::excel::XInterior > SAL_CALL Interior( ) override;
+ virtual css::uno::Any SAL_CALL Borders( const css::uno::Any& Index ) override;
+ virtual css::uno::Reference< ::ooo::vba::excel::XFont > SAL_CALL Font( ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaformatconditions.cxx b/sc/source/ui/vba/vbaformatconditions.cxx
new file mode 100644
index 000000000..bbf167b3c
--- /dev/null
+++ b/sc/source/ui/vba/vbaformatconditions.cxx
@@ -0,0 +1,289 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ooo/vba/excel/XRange.hpp>
+#include <com/sun/star/sheet/XSheetConditionalEntry.hpp>
+#include <basic/sberrors.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <vector>
+#include <unonames.hxx>
+#include "vbaformatconditions.hxx"
+#include "vbaformatcondition.hxx"
+#include "vbastyles.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+void SAL_CALL
+ScVbaFormatConditions::Delete( )
+{
+ try
+ {
+ ScVbaStyles* pStyles = static_cast< ScVbaStyles* >( mxStyles.get() );
+ if ( !pStyles )
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ sal_Int32 nCount = mxSheetConditionalEntries->getCount();
+ for (sal_Int32 i = nCount - 1; i >= 0; i--)
+ {
+ uno::Reference< sheet::XSheetConditionalEntry > xSheetConditionalEntry( mxSheetConditionalEntries->getByIndex(i), uno::UNO_QUERY_THROW );
+ pStyles->Delete(xSheetConditionalEntry->getStyleName());
+ mxSheetConditionalEntries->removeByIndex(i);
+ }
+ notifyRange();
+ }
+ catch (uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+uno::Type SAL_CALL
+ScVbaFormatConditions::getElementType()
+{
+ return cppu::UnoType<excel::XFormatCondition>::get();
+}
+
+static uno::Any xSheetConditionToFormatCondition( const uno::Reference< XHelperInterface >& xRangeParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< excel::XStyles >& xStyles, const uno::Reference< excel::XFormatConditions >& xFormatConditions, const uno::Reference< beans::XPropertySet >& xRangeProps, const uno::Any& aObject )
+{
+ uno::Reference< sheet::XSheetConditionalEntry > xSheetConditionalEntry;
+ aObject >>= xSheetConditionalEntry;
+
+ uno::Reference< excel::XStyle > xStyle( xStyles->Item( uno::Any( xSheetConditionalEntry->getStyleName() ), uno::Any() ), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XFormatCondition > xCondition = new ScVbaFormatCondition( xRangeParent, xContext, xSheetConditionalEntry, xStyle, xFormatConditions, xRangeProps );
+ return uno::Any( xCondition );
+}
+
+uno::Any
+ScVbaFormatConditions::createCollectionObject(const uno::Any& aObject )
+{
+ return xSheetConditionToFormatCondition( uno::Reference< XHelperInterface >( mxRangeParent, uno::UNO_QUERY_THROW ), mxContext, mxStyles, this, mxParentRangePropertySet, aObject );
+}
+
+namespace {
+
+class EnumWrapper : public EnumerationHelper_BASE
+{
+ uno::Reference<container::XIndexAccess > m_xIndexAccess;
+ uno::Reference<excel::XRange > m_xParentRange;
+ uno::Reference<uno::XComponentContext > m_xContext;
+ uno::Reference<excel::XStyles > m_xStyles;
+ uno::Reference<excel::XFormatConditions > m_xParentCollection;
+ uno::Reference<beans::XPropertySet > m_xProps;
+
+ sal_Int32 nIndex;
+public:
+ EnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess, const uno::Reference<excel::XRange >& xRange, const uno::Reference<uno::XComponentContext >& xContext, const uno::Reference<excel::XStyles >& xStyles, const uno::Reference< excel::XFormatConditions >& xCollection, const uno::Reference<beans::XPropertySet >& xProps ) : m_xIndexAccess( xIndexAccess ), m_xParentRange( xRange ), m_xContext( xContext ), m_xStyles( xStyles ), m_xParentCollection( xCollection ), m_xProps( xProps ), nIndex( 0 ) {}
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override
+ {
+ return ( nIndex < m_xIndexAccess->getCount() );
+ }
+
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ try
+ {
+ if ( nIndex < m_xIndexAccess->getCount() )
+ return xSheetConditionToFormatCondition( uno::Reference< XHelperInterface >( m_xParentRange, uno::UNO_QUERY_THROW ), m_xContext, m_xStyles, m_xParentCollection, m_xProps, m_xIndexAccess->getByIndex( nIndex++ ) );
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ throw;
+ }
+ catch (const lang::WrappedTargetException&)
+ {
+ throw;
+ }
+ catch (const uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception& e)
+ {
+ css::uno::Any a(cppu::getCaughtException());
+ throw css::lang::WrappedTargetException(
+ "wrapped Exception " + e.Message,
+ css::uno::Reference<css::uno::XInterface>(), a);
+ }
+ throw container::NoSuchElementException();
+ }
+};
+
+}
+
+uno::Reference< excel::XFormatCondition > SAL_CALL
+ScVbaFormatConditions::Add( ::sal_Int32 _nType, const uno::Any& _aOperator, const uno::Any& _aFormula1, const uno::Any& _aFormula2 )
+{
+ return Add( _nType, _aOperator, _aFormula1, _aFormula2, uno::Reference< excel::XStyle >() );
+}
+
+uno::Reference< excel::XFormatCondition >
+ScVbaFormatConditions::Add( ::sal_Int32 _nType, const uno::Any& _aOperator, const uno::Any& _aFormula1, const uno::Any& _aFormula2, const css::uno::Reference< excel::XStyle >& _xStyle )
+{
+ // #TODO
+ // #FIXME
+ // This method will NOT handle r1c1 formulas [*]and only assumes that
+ // the formulas are _xlA1 based ( need to hook into calc work this should
+ // address this )
+ // [*] reason: getA1Formula method below is just a hook and just
+ // returns what it gets ( e.g. doesn't convert anything )
+ uno::Reference< excel::XStyle > xStyle( _xStyle );
+ uno::Reference< excel::XFormatCondition > xFormatCondition;
+ try
+ {
+ OUString sStyleName;
+ if ( !xStyle.is() )
+ {
+ sStyleName = getStyleName();
+ xStyle = mxStyles->Add(sStyleName, uno::Any() );
+ }
+ else
+ {
+ sStyleName = xStyle->getName();
+ }
+
+ std::vector< beans::PropertyValue > aPropertyValueVector;
+ sheet::ConditionOperator aType = ScVbaFormatCondition::retrieveAPIType(_nType, uno::Reference< sheet::XSheetCondition >() );
+ uno::Any aValue;
+
+ if ( aType == sheet::ConditionOperator_FORMULA)
+ aValue <<= sheet::ConditionOperator_FORMULA;
+ else
+ aValue <<= ScVbaFormatCondition::retrieveAPIOperator(_aOperator);
+
+ beans::PropertyValue aProperty( "Operator", 0, aValue, beans::PropertyState_DIRECT_VALUE );
+ aPropertyValueVector.push_back( aProperty );
+
+ if ( _aFormula1.hasValue() )
+ {
+ beans::PropertyValue aProp( "Formula1", 0, uno::Any( getA1Formula( _aFormula1 ) ), beans::PropertyState_DIRECT_VALUE );
+ aPropertyValueVector.push_back( aProp );
+ }
+ if ( _aFormula2.hasValue() )
+ {
+ beans::PropertyValue aProp( "Formula2", 0, uno::Any( getA1Formula( _aFormula2 ) ), beans::PropertyState_DIRECT_VALUE );
+ aPropertyValueVector.push_back( aProp );
+ }
+ aProperty.Name = "StyleName";
+ aProperty.Value <<= sStyleName;
+
+ mxSheetConditionalEntries->addNew(comphelper::containerToSequence(aPropertyValueVector));
+ for (sal_Int32 i = mxSheetConditionalEntries->getCount()-1; i >= 0; i--)
+ {
+ uno::Reference< sheet::XSheetConditionalEntry > xSheetConditionalEntry( mxSheetConditionalEntries->getByIndex(i), uno::UNO_QUERY_THROW );
+ if (xSheetConditionalEntry->getStyleName() == sStyleName)
+ {
+ xFormatCondition = new ScVbaFormatCondition(uno::Reference< XHelperInterface >( mxRangeParent, uno::UNO_QUERY_THROW ), mxContext, xSheetConditionalEntry, xStyle, this, mxParentRangePropertySet);
+ notifyRange();
+ return xFormatCondition;
+ }
+ }
+ }
+ catch (uno::Exception& )
+ {
+ }
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ return xFormatCondition;
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL
+ScVbaFormatConditions::createEnumeration()
+{
+ return new EnumWrapper( m_xIndexAccess, mxRangeParent, mxContext, mxStyles, this, mxParentRangePropertySet );
+}
+
+void
+ScVbaFormatConditions::notifyRange()
+{
+ try
+ {
+ mxParentRangePropertySet->setPropertyValue(SC_UNONAME_CONDFMT, uno::Any( mxSheetConditionalEntries ));
+ }
+ catch (uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+OUString
+ScVbaFormatConditions::getA1Formula(const css::uno::Any& _aFormula)
+{
+ // #TODO, #FIXME hook-in proper formula conversion detection & logic
+ OUString sFormula;
+ if ( !( _aFormula >>= sFormula ) )
+ DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} );
+ return sFormula;
+}
+
+OUString
+ScVbaFormatConditions::getStyleName()
+{
+ ScVbaStyles* pStyles = static_cast< ScVbaStyles* >( mxStyles.get() );
+ if ( !pStyles )
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ uno::Sequence< OUString > sCellStyleNames = pStyles->getStyleNames();
+ return ContainerUtilities::getUniqueName(sCellStyleNames, "Excel_CondFormat", u"_");
+}
+
+void
+ScVbaFormatConditions::removeFormatCondition( const OUString& _sStyleName, bool _bRemoveStyle)
+{
+ try
+ {
+ sal_Int32 nElems = mxSheetConditionalEntries->getCount();
+ for (sal_Int32 i = 0; i < nElems; i++)
+ {
+ uno::Reference< sheet::XSheetConditionalEntry > xSheetConditionalEntry( mxSheetConditionalEntries->getByIndex(i), uno::UNO_QUERY_THROW );
+ if (_sStyleName == xSheetConditionalEntry->getStyleName())
+ {
+ mxSheetConditionalEntries->removeByIndex(i);
+ if (_bRemoveStyle)
+ {
+ ScVbaStyles* pStyles = static_cast< ScVbaStyles* >( mxStyles.get() );
+ if ( !pStyles )
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ pStyles->Delete( _sStyleName );
+ }
+ return;
+ }
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+OUString
+ScVbaFormatConditions::getServiceImplName()
+{
+ return "ScVbaFormatConditions";
+}
+
+uno::Sequence< OUString >
+ScVbaFormatConditions::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.FormatConditions"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaformatconditions.hxx b/sc/source/ui/vba/vbaformatconditions.hxx
new file mode 100644
index 000000000..fd5a7fc83
--- /dev/null
+++ b/sc/source/ui/vba/vbaformatconditions.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 <ooo/vba/excel/XFormatConditions.hpp>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::sheet { class XSheetConditionalEntries; }
+namespace ooo::vba::excel { class XRange; }
+namespace ooo::vba::excel { class XStyle; }
+namespace ooo::vba::excel { class XStyles; }
+
+// This class is used only as a target for casting, it seems,
+// and no objects of this type are created as such, I think.
+
+class ScVbaFormatConditions: public CollTestImplHelper< ov::excel::XFormatConditions >
+{
+ css::uno::Reference< css::sheet::XSheetConditionalEntries > mxSheetConditionalEntries;
+ css::uno::Reference< ov::excel::XStyles > mxStyles;
+ css::uno::Reference< ov::excel::XRange > mxRangeParent;
+ css::uno::Reference< css::beans::XPropertySet > mxParentRangePropertySet;
+public:
+ /// @throws css::script::BasicErrorException
+ void notifyRange();
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< ov::excel::XFormatCondition > Add( ::sal_Int32 Type, const css::uno::Any& Operator, const css::uno::Any& Formula1, const css::uno::Any& Formula2, const css::uno::Reference< ov::excel::XStyle >& _xCalcStyle );
+ /// @throws css::script::BasicErrorException
+ static OUString getA1Formula(const css::uno::Any& _aFormula);
+ OUString getStyleName();
+ /// @throws css::script::BasicErrorException
+ void removeFormatCondition( const OUString& _sStyleName, bool _bRemoveStyle);
+ const css::uno::Reference< css::sheet::XSheetConditionalEntries >& getSheetConditionalEntries() const { return mxSheetConditionalEntries; }
+ // XFormatConditions
+ virtual void SAL_CALL Delete( ) override;
+ virtual css::uno::Reference< ov::excel::XFormatCondition > SAL_CALL Add( ::sal_Int32 Type, const css::uno::Any& Operator, const css::uno::Any& Formula1, const css::uno::Any& Formula2 ) override;
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+ virtual css::uno::Any createCollectionObject(const css::uno::Any&) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+ ScVbaFormatConditions() = delete;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaglobals.cxx b/sc/source/ui/vba/vbaglobals.cxx
new file mode 100644
index 000000000..734553d50
--- /dev/null
+++ b/sc/source/ui/vba/vbaglobals.cxx
@@ -0,0 +1,265 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "vbaglobals.hxx"
+
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <comphelper/sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+
+#include "vbaapplication.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::ooo::vba;
+
+// ScVbaGlobals
+
+//ScVbaGlobals::ScVbaGlobals( css::uno::Reference< css::uno::XComponentContext >const& rxContext, ) : ScVbaGlobals_BASE( uno::Reference< XHelperInterface >(), rxContext )
+
+ScVbaGlobals::ScVbaGlobals( uno::Sequence< uno::Any > const& aArgs, uno::Reference< uno::XComponentContext >const& rxContext ) : ScVbaGlobals_BASE( uno::Reference< XHelperInterface >(), rxContext, "ExcelDocumentContext" )
+{
+ uno::Sequence< beans::PropertyValue > aInitArgs( aArgs.hasElements() ? 2 : 1 );
+ auto pInitArgs = aInitArgs.getArray();
+ pInitArgs[ 0 ].Name = "Application";
+ pInitArgs[ 0 ].Value <<= getApplication();
+ if ( aArgs.hasElements() )
+ {
+ pInitArgs[ 1 ].Name = "ExcelDocumentContext";
+ pInitArgs[ 1 ].Value <<= getXSomethingFromArgs< frame::XModel >( aArgs, 0 );
+ }
+ init( aInitArgs );
+}
+
+ScVbaGlobals::~ScVbaGlobals()
+{
+}
+
+// XGlobals
+
+uno::Reference<excel::XApplication > const &
+ScVbaGlobals::getApplication()
+{
+ if ( !mxApplication.is() )
+ mxApplication.set( new ScVbaApplication( mxContext) );
+ return mxApplication;
+}
+
+uno::Reference<excel::XApplication > SAL_CALL
+ScVbaGlobals::getExcel()
+{
+ return getApplication();
+}
+
+uno::Reference< excel::XWorkbook > SAL_CALL
+ScVbaGlobals::getActiveWorkbook()
+{
+ uno::Reference< excel::XWorkbook > xWorkbook( getApplication()->getActiveWorkbook(), uno::UNO_SET_THROW);
+ return xWorkbook;
+}
+
+uno::Reference< excel::XWindow > SAL_CALL
+ScVbaGlobals::getActiveWindow()
+{
+ return getApplication()->getActiveWindow();
+}
+
+uno::Reference< excel::XWorksheet > SAL_CALL
+ScVbaGlobals::getActiveSheet()
+{
+ return getApplication()->getActiveSheet();
+}
+
+uno::Any SAL_CALL
+ScVbaGlobals::WorkBooks( const uno::Any& aIndex )
+{
+ return getApplication()->Workbooks(aIndex);
+}
+
+uno::Any SAL_CALL
+ScVbaGlobals::WorkSheets(const uno::Any& aIndex)
+{
+ return getApplication()->Worksheets( aIndex );
+}
+uno::Any SAL_CALL
+ScVbaGlobals::Sheets( const uno::Any& aIndex )
+{
+ return WorkSheets( aIndex );
+}
+
+uno::Any SAL_CALL
+ScVbaGlobals::Range( const uno::Any& Cell1, const uno::Any& Cell2 )
+{
+ return getApplication()->Range( Cell1, Cell2 );
+}
+
+uno::Any SAL_CALL
+ScVbaGlobals::Names( const css::uno::Any& aIndex )
+{
+ return getApplication()->Names( aIndex );
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaGlobals::getActiveCell()
+{
+ return getApplication()->getActiveCell();
+}
+
+uno::Reference< XAssistant > SAL_CALL
+ScVbaGlobals::getAssistant()
+{
+ return getApplication()->getAssistant();
+}
+
+uno::Any SAL_CALL
+ScVbaGlobals::getSelection()
+{
+ return getApplication()->getSelection();
+}
+
+uno::Reference< excel::XWorkbook > SAL_CALL
+ScVbaGlobals::getThisWorkbook()
+{
+ return getApplication()->getThisWorkbook();
+}
+void SAL_CALL
+ScVbaGlobals::Calculate()
+{
+ return getApplication()->Calculate();
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaGlobals::Cells( const uno::Any& RowIndex, const uno::Any& ColumnIndex )
+{
+ return getApplication()->getActiveSheet()->Cells( RowIndex, ColumnIndex );
+}
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaGlobals::Columns( const uno::Any& aIndex )
+{
+ return getApplication()->getActiveSheet()->Columns( aIndex );
+}
+
+uno::Any SAL_CALL
+ScVbaGlobals::CommandBars( const uno::Any& aIndex )
+{
+ uno::Reference< XApplicationBase > xBase( getApplication(), uno::UNO_QUERY_THROW );
+ return xBase->CommandBars( aIndex );
+}
+
+css::uno::Reference< ov::excel::XRange > SAL_CALL
+ScVbaGlobals::Union( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 )
+{
+ return getApplication()->Union( Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12, Arg13, Arg14, Arg15, Arg16, Arg17, Arg18, Arg19, Arg20, Arg21, Arg22, Arg23, Arg24, Arg25, Arg26, Arg27, Arg28, Arg29, Arg30 );
+}
+css::uno::Reference< ov::excel::XRange > SAL_CALL
+ScVbaGlobals::Intersect( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 )
+{
+ return getApplication()->Intersect( Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10, Arg11, Arg12, Arg13, Arg14, Arg15, Arg16, Arg17, Arg18, Arg19, Arg20, Arg21, Arg22, Arg23, Arg24, Arg25, Arg26, Arg27, Arg28, Arg29, Arg30 );
+}
+
+uno::Any SAL_CALL
+ScVbaGlobals::Evaluate( const OUString& Name )
+{
+ return getApplication()->Evaluate( Name );
+}
+
+css::uno::Any SAL_CALL
+ScVbaGlobals::WorksheetFunction( )
+{
+ return getApplication()->WorksheetFunction();
+}
+
+uno::Any SAL_CALL
+ScVbaGlobals::Windows( const uno::Any& aIndex )
+{
+ return getApplication()->Windows( aIndex );
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaGlobals::Rows( const uno::Any& aIndex )
+{
+ return getApplication()->getActiveSheet()->Rows( aIndex );
+
+}
+
+uno::Any SAL_CALL
+ScVbaGlobals::getDebug()
+{
+ try // return empty object on error
+ {
+ uno::Reference< lang::XMultiComponentFactory > xServiceManager( mxContext->getServiceManager(), uno::UNO_SET_THROW );
+ uno::Reference< uno::XInterface > xVBADebug = xServiceManager->createInstanceWithContext(
+ "ooo.vba.Debug", mxContext );
+ return uno::Any( xVBADebug );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ return uno::Any();
+}
+
+uno::Any SAL_CALL
+ScVbaGlobals::MenuBars( const uno::Any& aIndex )
+{
+ return getApplication()->MenuBars(aIndex);
+}
+
+uno::Sequence< OUString > SAL_CALL
+ScVbaGlobals::getAvailableServiceNames( )
+{
+ static const uno::Sequence< OUString > serviceNames = comphelper::concatSequences(
+ ScVbaGlobals_BASE::getAvailableServiceNames(),
+ uno::Sequence< OUString >
+ {
+ "ooo.vba.excel.Range",
+ "ooo.vba.excel.Workbook",
+ "ooo.vba.excel.Window",
+ "ooo.vba.excel.Worksheet",
+ "ooo.vba.excel.Application",
+ "ooo.vba.excel.Hyperlink",
+ "com.sun.star.script.vba.VBASpreadsheetEventProcessor"
+ } );
+ return serviceNames;
+}
+
+OUString
+ScVbaGlobals::getServiceImplName()
+{
+ return "ScVbaGlobals";
+}
+
+uno::Sequence< OUString >
+ScVbaGlobals::getServiceNames()
+{
+ static uno::Sequence< OUString > aServiceNames
+ {
+ "ooo.vba.excel.Globals"
+ };
+ return aServiceNames;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+ScVbaGlobals_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &arguments)
+{
+ return cppu::acquire(new ScVbaGlobals(arguments, context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaglobals.hxx b/sc/source/ui/vba/vbaglobals.hxx
new file mode 100644
index 000000000..6f978c591
--- /dev/null
+++ b/sc/source/ui/vba/vbaglobals.hxx
@@ -0,0 +1,82 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#ifndef SC_VBA_GLOBALS
+#define SC_VBA_GLOBALS
+
+#include <ooo/vba/excel/XGlobals.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <vbahelper/vbaglobalbase.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace ooo::vba::excel { class XApplication; }
+
+
+typedef ::cppu::ImplInheritanceHelper< VbaGlobalsBase, ov::excel::XGlobals > ScVbaGlobals_BASE;
+
+class ScVbaGlobals : public ScVbaGlobals_BASE
+{
+ css::uno::Reference< ov::excel::XApplication > mxApplication;
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< ov::excel::XApplication > const & getApplication();
+public:
+
+ ScVbaGlobals( css::uno::Sequence< css::uno::Any > const& aArgs,
+ css::uno::Reference< css::uno::XComponentContext >const& rxContext );
+ virtual ~ScVbaGlobals() override;
+
+ // XGlobals
+ virtual css::uno::Reference< ov::excel::XWorkbook > SAL_CALL getActiveWorkbook() override;
+ virtual css::uno::Reference< ov::excel::XWindow > SAL_CALL getActiveWindow() override;
+ virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getActiveSheet() override;
+ virtual css::uno::Reference< ov::XAssistant > SAL_CALL getAssistant() override;
+ virtual void SAL_CALL Calculate( ) override;
+
+ virtual css::uno::Any SAL_CALL getSelection() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getActiveCell() override;
+ virtual css::uno::Reference< ov::excel::XWorkbook > SAL_CALL getThisWorkbook() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Cells( const css::uno::Any& RowIndex, const css::uno::Any& ColumnIndex ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Columns( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL CommandBars( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL Evaluate( const OUString& Name ) override;
+
+ virtual css::uno::Any SAL_CALL WorkSheets(const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL WorkBooks(const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL WorksheetFunction( ) override;
+ virtual css::uno::Any SAL_CALL Windows( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL Sheets( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL Range( const css::uno::Any& Cell1, const css::uno::Any& Cell2 ) override;
+ virtual css::uno::Reference< ::ooo::vba::excel::XRange > SAL_CALL Rows( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL Names( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Intersect( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Union( const css::uno::Reference< ov::excel::XRange >& Arg1, const css::uno::Reference< ov::excel::XRange >& Arg2, const css::uno::Any& Arg3, const css::uno::Any& Arg4, const css::uno::Any& Arg5, const css::uno::Any& Arg6, const css::uno::Any& Arg7, const css::uno::Any& Arg8, const css::uno::Any& Arg9, const css::uno::Any& Arg10, const css::uno::Any& Arg11, const css::uno::Any& Arg12, const css::uno::Any& Arg13, const css::uno::Any& Arg14, const css::uno::Any& Arg15, const css::uno::Any& Arg16, const css::uno::Any& Arg17, const css::uno::Any& Arg18, const css::uno::Any& Arg19, const css::uno::Any& Arg20, const css::uno::Any& Arg21, const css::uno::Any& Arg22, const css::uno::Any& Arg23, const css::uno::Any& Arg24, const css::uno::Any& Arg25, const css::uno::Any& Arg26, const css::uno::Any& Arg27, const css::uno::Any& Arg28, const css::uno::Any& Arg29, const css::uno::Any& Arg30 ) override;
+ virtual css::uno::Reference< ov::excel::XApplication > SAL_CALL getExcel() override;
+ virtual css::uno::Any SAL_CALL getDebug() override;
+ virtual css::uno::Any SAL_CALL MenuBars( const css::uno::Any& aIndex ) override;
+
+ // XMultiServiceFactory
+ virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames( ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+#endif
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbahyperlink.cxx b/sc/source/ui/vba/vbahyperlink.cxx
new file mode 100644
index 000000000..2bd355421
--- /dev/null
+++ b/sc/source/ui/vba/vbahyperlink.cxx
@@ -0,0 +1,236 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 "vbahyperlink.hxx"
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/text/XTextFieldsSupplier.hpp>
+#include <ooo/vba/office/MsoHyperlinkType.hpp>
+#include <ooo/vba/msforms/XShape.hpp>
+#include "vbarange.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+ScVbaHyperlink::ScVbaHyperlink( const uno::Sequence< uno::Any >& rArgs,
+ const uno::Reference< uno::XComponentContext >& rxContext ) :
+ HyperlinkImpl_BASE( getXSomethingFromArgs< XHelperInterface >( rArgs, 0 ), rxContext ),
+ mxCell( getXSomethingFromArgs< table::XCell >( rArgs, 1, false ) ),
+ mnType( office::MsoHyperlinkType::msoHyperlinkRange )
+{
+ uno::Reference< text::XTextFieldsSupplier > xTextFields( mxCell, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xIndex( xTextFields->getTextFields(), uno::UNO_QUERY_THROW );
+ mxTextField.set( xIndex->getByIndex(0), uno::UNO_QUERY_THROW );
+}
+
+ScVbaHyperlink::ScVbaHyperlink( const uno::Reference< XHelperInterface >& rxAnchor,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Any& rAddress, const uno::Any& rSubAddress,
+ const uno::Any& rScreenTip, const uno::Any& rTextToDisplay ) :
+ HyperlinkImpl_BASE( rxAnchor, rxContext ) // parent of Hyperlink is the anchor object
+{
+ // extract parameters, Address must not be empty
+ UrlComponents aUrlComp;
+ OUString aTextToDisplay;
+ if( !(rAddress >>= aUrlComp.first) || aUrlComp.first.isEmpty() )
+ throw uno::RuntimeException("Cannot get address" );
+ rSubAddress >>= aUrlComp.second;
+ rScreenTip >>= maScreenTip;
+ rTextToDisplay >>= aTextToDisplay;
+
+ // get anchor range or anchor shape
+ uno::Reference< excel::XRange > xAnchorRange( rxAnchor, uno::UNO_QUERY );
+ if( xAnchorRange.is() )
+ {
+ mnType = office::MsoHyperlinkType::msoHyperlinkRange;
+ // only single ranges are allowed
+ uno::Reference< table::XCellRange > xUnoRange( ScVbaRange::getCellRange( xAnchorRange ), uno::UNO_QUERY_THROW );
+ // insert the hyperlink into the top-left cell only
+ mxCell.set( xUnoRange->getCellByPosition( 0, 0 ), uno::UNO_SET_THROW );
+ uno::Reference< text::XText > xText( mxCell, uno::UNO_QUERY_THROW );
+ // use cell text or URL if no TextToDisplay has been passed
+ if( aTextToDisplay.isEmpty() )
+ {
+ aTextToDisplay = xText->getString();
+ if( aTextToDisplay.isEmpty() )
+ {
+ OUStringBuffer aBuffer( aUrlComp.first );
+ if( !aUrlComp.second.isEmpty() )
+ aBuffer.append( " - " + aUrlComp.second );
+ aTextToDisplay = aBuffer.makeStringAndClear();
+ }
+ }
+ // create and initialize a new URL text field
+ uno::Reference< lang::XMultiServiceFactory > xFactory( ScVbaRange::getUnoModel( xAnchorRange ), uno::UNO_QUERY_THROW );
+ uno::Reference< text::XTextContent > xUrlField( xFactory->createInstance("com.sun.star.text.TextField.URL"), uno::UNO_QUERY_THROW );
+ mxTextField.set( xUrlField, uno::UNO_QUERY_THROW );
+ setUrlComponents( aUrlComp );
+ setTextToDisplay( aTextToDisplay );
+ // insert the text field into the document
+ xText->setString( OUString() );
+ uno::Reference< text::XTextRange > xRange( xText->createTextCursor(), uno::UNO_QUERY_THROW );
+ xText->insertTextContent( xRange, xUrlField, false );
+ }
+ else
+ {
+ uno::Reference< msforms::XShape > xAnchorShape( rxAnchor, uno::UNO_QUERY_THROW );
+ mnType = office::MsoHyperlinkType::msoHyperlinkShape;
+ // FIXME: insert hyperlink into shape
+ throw uno::RuntimeException();
+ }
+}
+
+ScVbaHyperlink::~ScVbaHyperlink()
+{
+}
+
+OUString ScVbaHyperlink::getName()
+{
+ // it seems this attribute is same as TextToDisplay
+ return getTextToDisplay();
+}
+
+void ScVbaHyperlink::setName( const OUString& rName )
+{
+ setTextToDisplay( rName );
+}
+
+OUString ScVbaHyperlink::getAddress()
+{
+ return getUrlComponents().first;
+}
+
+void ScVbaHyperlink::setAddress( const OUString& rAddress )
+{
+ UrlComponents aUrlComp = getUrlComponents();
+ aUrlComp.first = rAddress;
+ setUrlComponents( aUrlComp );
+}
+
+OUString ScVbaHyperlink::getSubAddress()
+{
+ return getUrlComponents().second;
+}
+
+void ScVbaHyperlink::setSubAddress( const OUString& rSubAddress )
+{
+ UrlComponents aUrlComp = getUrlComponents();
+ aUrlComp.second = rSubAddress;
+ setUrlComponents( aUrlComp );
+}
+
+OUString SAL_CALL ScVbaHyperlink::getScreenTip()
+{
+ return maScreenTip;
+}
+
+void SAL_CALL ScVbaHyperlink::setScreenTip( const OUString& rScreenTip )
+{
+ maScreenTip = rScreenTip;
+}
+
+OUString ScVbaHyperlink::getTextToDisplay()
+{
+ ensureTextField();
+ OUString aTextToDisplay;
+ mxTextField->getPropertyValue("Representation") >>= aTextToDisplay;
+ return aTextToDisplay;
+}
+
+void ScVbaHyperlink::setTextToDisplay( const OUString& rTextToDisplay )
+{
+ ensureTextField();
+ mxTextField->setPropertyValue("Representation", uno::Any( rTextToDisplay ) );
+}
+
+sal_Int32 SAL_CALL ScVbaHyperlink::getType()
+{
+ return mnType;
+}
+
+uno::Reference< excel::XRange > SAL_CALL ScVbaHyperlink::getRange()
+{
+ if( mnType == office::MsoHyperlinkType::msoHyperlinkRange )
+ {
+ // if constructed from Hyperlinks object, range has been passed as parent
+ uno::Reference< excel::XRange > xAnchorRange( getParent(), uno::UNO_QUERY );
+ if( !xAnchorRange.is() )
+ {
+ // if constructed via service c'tor, create new range based on cell
+ uno::Reference< table::XCellRange > xRange( mxCell, uno::UNO_QUERY_THROW );
+ // FIXME: need to pass current worksheet as the parent of XRange.
+ xAnchorRange.set( new ScVbaRange( uno::Reference< XHelperInterface >(), mxContext, xRange ) );
+ }
+ return xAnchorRange;
+ }
+ // error if called at a shape Hyperlink object
+ throw uno::RuntimeException();
+}
+
+uno::Reference< msforms::XShape > SAL_CALL ScVbaHyperlink::getShape()
+{
+ // error if called at a range Hyperlink object
+ return uno::Reference< msforms::XShape >( getParent(), uno::UNO_QUERY_THROW );
+}
+
+VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaHyperlink, "ooo.vba.excel.Hyperlink" )
+
+// private --------------------------------------------------------------------
+
+void ScVbaHyperlink::ensureTextField()
+{
+ if( !mxTextField.is() )
+ throw uno::RuntimeException();
+}
+
+ScVbaHyperlink::UrlComponents ScVbaHyperlink::getUrlComponents()
+{
+ ensureTextField();
+ OUString aUrl;
+ mxTextField->getPropertyValue("URL") >>= aUrl;
+ sal_Int32 nHashPos = aUrl.indexOf( '#' );
+ if( nHashPos < 0 )
+ return UrlComponents( aUrl, OUString() );
+ return UrlComponents( aUrl.copy( 0, nHashPos ), aUrl.copy( nHashPos + 1 ) );
+}
+
+void ScVbaHyperlink::setUrlComponents( const UrlComponents& rUrlComp )
+{
+ ensureTextField();
+ OUStringBuffer aUrl( rUrlComp.first );
+ if( !rUrlComp.second.isEmpty() )
+ aUrl.append( '#' ).append( rUrlComp.second );
+ mxTextField->setPropertyValue("URL", uno::Any( aUrl.makeStringAndClear() ) );
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_ScVbaHyperlink_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args)
+{
+ return cppu::acquire(new ScVbaHyperlink(args, context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbahyperlink.hxx b/sc/source/ui/vba/vbahyperlink.hxx
new file mode 100644
index 000000000..391853be7
--- /dev/null
+++ b/sc/source/ui/vba/vbahyperlink.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 <ooo/vba/excel/XHyperlink.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+#include <tools/long.hxx>
+
+namespace ooo::vba::excel { class XRange; }
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::table { class XCell; }
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XHyperlink > HyperlinkImpl_BASE;
+
+class ScVbaHyperlink : public HyperlinkImpl_BASE
+{
+public:
+ /// @throws css::lang::IllegalArgumentException
+ /// @throws css::uno::RuntimeException
+ ScVbaHyperlink(
+ const css::uno::Sequence< css::uno::Any >& rArgs,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ /// @throws css::uno::RuntimeException
+ ScVbaHyperlink(
+ const css::uno::Reference< ov::XHelperInterface >& rxAnchor,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Any& rAddress, const css::uno::Any& rSubAddress,
+ const css::uno::Any& rScreenTip, const css::uno::Any& rTextToDisplay );
+
+ virtual ~ScVbaHyperlink() override;
+
+ // Attributes
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName( const OUString& rName ) override;
+ virtual OUString SAL_CALL getAddress() override;
+ virtual void SAL_CALL setAddress( const OUString& rAddress ) override;
+ virtual OUString SAL_CALL getSubAddress() override;
+ virtual void SAL_CALL setSubAddress( const OUString& rSubAddress ) override;
+ virtual OUString SAL_CALL getScreenTip() override;
+ virtual void SAL_CALL setScreenTip( const OUString& rScreenTip ) override;
+ virtual OUString SAL_CALL getTextToDisplay() override;
+ virtual void SAL_CALL setTextToDisplay( const OUString& rTextToDisplay ) override;
+ virtual sal_Int32 SAL_CALL getType() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getRange() override;
+ virtual css::uno::Reference< ov::msforms::XShape > SAL_CALL getShape() override;
+
+ // XHelperInterface
+ VBAHELPER_DECL_XHELPERINTERFACE
+
+private:
+ typedef ::std::pair< OUString, OUString > UrlComponents;
+
+ /// @throws css::uno::RuntimeException
+ void ensureTextField();
+ /// @throws css::uno::RuntimeException
+ UrlComponents getUrlComponents();
+ /// @throws css::uno::RuntimeException
+ void setUrlComponents( const UrlComponents& rUrlComp );
+
+private:
+ css::uno::Reference< css::table::XCell > mxCell;
+ css::uno::Reference< css::beans::XPropertySet > mxTextField;
+ OUString maScreenTip;
+ tools::Long mnType;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbahyperlinks.cxx b/sc/source/ui/vba/vbahyperlinks.cxx
new file mode 100644
index 000000000..d309f5f44
--- /dev/null
+++ b/sc/source/ui/vba/vbahyperlinks.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 "vbahyperlinks.hxx"
+#include <algorithm>
+#include <vector>
+#include <cppuhelper/implbase.hxx>
+#include <ooo/vba/office/MsoHyperlinkType.hpp>
+#include <rangelst.hxx>
+#include "vbahyperlink.hxx"
+#include "vbarange.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+namespace {
+
+/** Returns true, if every range of rxInner is contained in any range of rScOuter.
+
+ @throws css::uno::RuntimeException
+*/
+bool lclContains( const ScRangeList& rScOuter, const uno::Reference< excel::XRange >& rxInner )
+{
+ const ScRangeList& rScInner = ScVbaRange::getScRangeList( rxInner );
+ if( rScInner.empty() || rScOuter.empty() )
+ throw uno::RuntimeException("Empty range objects" );
+
+ for( size_t nIndex = 0, nCount = rScInner.size(); nIndex < nCount; ++nIndex )
+ if( !rScOuter.Contains( rScInner[ nIndex ] ) )
+ return false;
+ return true;
+}
+
+/** Functor to decide whether the anchors of two Hyperlink objects are equal. */
+struct EqualAnchorFunctor
+{
+ uno::Reference< excel::XRange > mxAnchorRange;
+ uno::Reference< msforms::XShape > mxAnchorShape;
+ sal_Int32 mnType;
+ /// @throws uno::RuntimeException
+ explicit EqualAnchorFunctor( const uno::Reference< excel::XHyperlink >& rxHlink );
+ /// @throws uno::RuntimeException
+ bool operator()( const uno::Reference< excel::XHyperlink >& rxHlink ) const;
+};
+
+EqualAnchorFunctor::EqualAnchorFunctor( const uno::Reference< excel::XHyperlink >& rxHlink ) :
+ mnType( rxHlink->getType() )
+{
+ switch( mnType )
+ {
+ case office::MsoHyperlinkType::msoHyperlinkRange:
+ mxAnchorRange.set( rxHlink->getRange(), uno::UNO_SET_THROW );
+ break;
+ case office::MsoHyperlinkType::msoHyperlinkShape:
+ case office::MsoHyperlinkType::msoHyperlinkInlineShape:
+ mxAnchorShape.set( rxHlink->getShape(), uno::UNO_SET_THROW );
+ break;
+ default:
+ throw uno::RuntimeException();
+ }
+}
+
+bool EqualAnchorFunctor::operator()( const uno::Reference< excel::XHyperlink >& rxHlink ) const
+{
+ sal_Int32 nType = rxHlink->getType();
+ if( nType != mnType )
+ return false;
+
+ switch( nType )
+ {
+ case office::MsoHyperlinkType::msoHyperlinkRange:
+ {
+ uno::Reference< excel::XRange > xAnchorRange( rxHlink->getRange(), uno::UNO_SET_THROW );
+ const ScRangeList& rScRanges1 = ScVbaRange::getScRangeList( xAnchorRange );
+ const ScRangeList& rScRanges2 = ScVbaRange::getScRangeList( mxAnchorRange );
+ return (rScRanges1.size() == 1) && (rScRanges2.size() == 1) && (rScRanges1[ 0 ] == rScRanges2[ 0 ]);
+ }
+ case office::MsoHyperlinkType::msoHyperlinkShape:
+ case office::MsoHyperlinkType::msoHyperlinkInlineShape:
+ {
+ uno::Reference< msforms::XShape > xAnchorShape( rxHlink->getShape(), uno::UNO_SET_THROW );
+ return xAnchorShape.get() == mxAnchorShape.get();
+ }
+ default:
+ throw uno::RuntimeException();
+ }
+}
+
+} // namespace
+
+namespace detail {
+
+class ScVbaHlinkContainer : public ::cppu::WeakImplHelper< container::XIndexAccess >
+{
+public:
+ /// @throws uno::RuntimeException
+ explicit ScVbaHlinkContainer();
+ /// @throws uno::RuntimeException
+ explicit ScVbaHlinkContainer( const ScVbaHlinkContainerRef& rxSheetContainer, const ScRangeList& rScRanges );
+
+ /** Inserts the passed hyperlink into the collection. Will remove a
+ Hyperlink object with the same anchor as the passed Hyperlink object.
+
+ @throws uno::RuntimeException
+ */
+ void insertHyperlink( const uno::Reference< excel::XHyperlink >& rxHlink );
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual uno::Any SAL_CALL getByIndex( sal_Int32 nIndex ) override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+private:
+ typedef ::std::vector< uno::Reference< excel::XHyperlink > > HyperlinkVector;
+ HyperlinkVector maHlinks;
+};
+
+ScVbaHlinkContainer::ScVbaHlinkContainer()
+{
+ // TODO FIXME: fill with existing hyperlinks
+}
+
+ScVbaHlinkContainer::ScVbaHlinkContainer( const ScVbaHlinkContainerRef& rxSheetContainer,
+ const ScRangeList& rScRanges )
+{
+ for( sal_Int32 nIndex = 0, nCount = rxSheetContainer->getCount(); nIndex < nCount; ++nIndex )
+ {
+ uno::Reference< excel::XHyperlink > xHlink( rxSheetContainer->getByIndex( nIndex ), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XRange > xHlinkRange( xHlink->getRange(), uno::UNO_SET_THROW );
+ if( lclContains( rScRanges, xHlinkRange ) )
+ maHlinks.push_back( xHlink );
+ }
+}
+
+void ScVbaHlinkContainer::insertHyperlink( const uno::Reference< excel::XHyperlink >& rxHlink )
+{
+ HyperlinkVector::iterator aIt = ::std::find_if( maHlinks.begin(), maHlinks.end(), EqualAnchorFunctor( rxHlink ) );
+ if( aIt == maHlinks.end() )
+ maHlinks.push_back( rxHlink );
+ else
+ *aIt = rxHlink;
+}
+
+sal_Int32 SAL_CALL ScVbaHlinkContainer::getCount()
+{
+ return static_cast< sal_Int32 >( maHlinks.size() );
+}
+
+uno::Any SAL_CALL ScVbaHlinkContainer::getByIndex( sal_Int32 nIndex )
+{
+ if( (0 <= nIndex) && (nIndex < getCount()) )
+ return uno::Any( maHlinks[ static_cast< size_t >( nIndex ) ] );
+ throw lang::IndexOutOfBoundsException();
+}
+
+uno::Type SAL_CALL ScVbaHlinkContainer::getElementType()
+{
+ return cppu::UnoType<excel::XHyperlink>::get();
+}
+
+sal_Bool SAL_CALL ScVbaHlinkContainer::hasElements()
+{
+ return !maHlinks.empty();
+}
+
+ScVbaHlinkContainerMember::ScVbaHlinkContainerMember( ScVbaHlinkContainer* pContainer ) :
+ mxContainer( pContainer )
+{
+}
+
+ScVbaHlinkContainerMember::~ScVbaHlinkContainerMember()
+{
+}
+
+} // namespace detail
+
+ScVbaHyperlinks::ScVbaHyperlinks( const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext ) :
+ detail::ScVbaHlinkContainerMember( new detail::ScVbaHlinkContainer ),
+ ScVbaHyperlinks_BASE( rxParent, rxContext, uno::Reference< container::XIndexAccess >( mxContainer ) )
+{
+}
+
+ScVbaHyperlinks::ScVbaHyperlinks( const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const ScVbaHyperlinksRef& rxSheetHlinks, const ScRangeList& rScRanges ) :
+ detail::ScVbaHlinkContainerMember( new detail::ScVbaHlinkContainer( rxSheetHlinks->mxContainer, rScRanges ) ),
+ ScVbaHyperlinks_BASE( rxParent, rxContext, uno::Reference< container::XIndexAccess >( mxContainer ) ),
+ mxSheetHlinks( rxSheetHlinks )
+{
+}
+
+ScVbaHyperlinks::~ScVbaHyperlinks()
+{
+}
+
+// XHyperlinks ----------------------------------------------------------------
+
+uno::Reference< excel::XHyperlink > SAL_CALL ScVbaHyperlinks::Add(
+ const uno::Any& rAnchor, const uno::Any& rAddress, const uno::Any& rSubAddress,
+ const uno::Any& rScreenTip, const uno::Any& rTextToDisplay )
+{
+ /* If this Hyperlinks object has been created from a Range object, the
+ call to Add() is passed to the Hyperlinks object of the parent
+ worksheet. This container will not be modified (it will not contain the
+ inserted hyperlink).
+ For details, see documentation in hyperlinks.hxx.
+ */
+ if( mxSheetHlinks.is() )
+ return mxSheetHlinks->Add( rAnchor, rAddress, rSubAddress, rScreenTip, rTextToDisplay );
+
+ // get anchor object (can be a Range or a Shape object)
+ uno::Reference< XHelperInterface > xAnchor( rAnchor, uno::UNO_QUERY_THROW );
+
+ /* Create the Hyperlink object, this tries to insert the hyperlink into
+ the spreadsheet document. Parent of the Hyperlink is the anchor object. */
+ uno::Reference< excel::XHyperlink > xHlink( new ScVbaHyperlink(
+ xAnchor, mxContext, rAddress, rSubAddress, rScreenTip, rTextToDisplay ) );
+
+ /* If creation of the hyperlink did not throw, insert it into the
+ collection. */
+ mxContainer->insertHyperlink( xHlink );
+ return xHlink;
+}
+
+void SAL_CALL ScVbaHyperlinks::Delete()
+{
+ // FIXME not implemented
+ throw uno::RuntimeException();
+}
+
+// XEnumerationAccess ---------------------------------------------------------
+
+uno::Reference< container::XEnumeration > SAL_CALL ScVbaHyperlinks::createEnumeration()
+{
+ return new SimpleIndexAccessToEnumeration( m_xIndexAccess );
+}
+
+// XElementAccess -------------------------------------------------------------
+
+uno::Type SAL_CALL ScVbaHyperlinks::getElementType()
+{
+ return cppu::UnoType<excel::XHyperlink>::get();
+}
+
+// ScVbaCollectionBase --------------------------------------------------------
+
+uno::Any ScVbaHyperlinks::createCollectionObject( const uno::Any& rSource )
+{
+ // container stores XHyperlink objects, just return the passed object
+ return rSource;
+}
+
+// XHelperInterface -----------------------------------------------------------
+
+VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaHyperlinks, "ooo.vba.excel.Hyperlinks" )
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbahyperlinks.hxx b/sc/source/ui/vba/vbahyperlinks.hxx
new file mode 100644
index 000000000..7538fe50b
--- /dev/null
+++ b/sc/source/ui/vba/vbahyperlinks.hxx
@@ -0,0 +1,136 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <ooo/vba/excel/XHyperlinks.hpp>
+#include <rtl/ref.hxx>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+class ScRangeList;
+
+namespace detail {
+
+class ScVbaHlinkContainer;
+typedef ::rtl::Reference< ScVbaHlinkContainer > ScVbaHlinkContainerRef;
+
+/** Base class for ScVbaHyperlinks to get an initialized ScVbaHlinkContainer
+ class member before the ScVbaHyperlinks_BASE base class will be constructed.
+ */
+struct ScVbaHlinkContainerMember
+{
+ ScVbaHlinkContainerRef mxContainer;
+
+ explicit ScVbaHlinkContainerMember( ScVbaHlinkContainer* pContainer );
+ ~ScVbaHlinkContainerMember();
+};
+
+} // namespace detail
+
+class ScVbaHyperlinks;
+typedef ::rtl::Reference< ScVbaHyperlinks > ScVbaHyperlinksRef;
+
+typedef CollTestImplHelper< ov::excel::XHyperlinks > ScVbaHyperlinks_BASE;
+
+/** Represents a collection of hyperlinks of a worksheet or of a range.
+
+ When a Hyperlinks collection object has been constructed from a VBA
+ Worksheet object, it will always represent the current set of all
+ hyperlinks existing in the sheet. Insertion and deletion of hyperlinks will
+ be reflected by the instance.
+
+ When a Hyperlinks collection object has been constructed from a VBA Range
+ object, it will represent the set of hyperlinks that have existed at its
+ construction time, and that are located completely inside the range(s)
+ represented by the Range object. Insertion and deletion of hyperlinks will
+ *not* be reflected by that instance. The instance will always offer all
+ hyperlinks it has been constructed with, even if they no longer exist.
+ Furthermore, the instance will not offer hyperlinks inserted later, even if
+ the instance itself has been used to insert the new hyperlinks.
+
+ VBA code example:
+
+ With ThisWorkbook.Worksheets(1)
+
+ Set hlinks = .Hyperlinks ' global Hyperlinks object
+ Set myrange = .Range("A1:C3")
+ Set rangelinks1 = myrange.Hyperlinks ' hyperlinks of range A1:C3
+
+ MsgBox hlinks.Count ' 0
+ MsgBox rangelinks1.Count ' 0
+
+ hlinks.Add .Range("A1"), "http://example.com"
+ ' a new hyperlink has been added in cell A1
+
+ MsgBox hlinks.Count ' 1
+ MsgBox rangelinks1.Count ' still 0!
+ Set rangelinks2 = myrange.Hyperlinks ' hyperlinks of range A1:C3
+ MsgBox rangelinks2.Count ' 1 (constructed after Add)
+
+ rangelinks1.Add .Range("A2"), "http://example.com"
+ ' a new hyperlink has been constructed via the rangelinks1 object
+ ' but this addition has been done by the worksheet Hyperlinks object
+
+ MsgBox hlinks.Count ' 2
+ MsgBox rangelinks1.Count ' still 0!!!
+ MsgBox rangelinks2.Count ' still 1!!!
+ MsgBox myrange.Hyperlinks.Count ' 2 (constructed after Add)
+
+ End With
+ */
+class ScVbaHyperlinks : private detail::ScVbaHlinkContainerMember, public ScVbaHyperlinks_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ explicit ScVbaHyperlinks(
+ const css::uno::Reference< ov::XHelperInterface >& rxParent,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext );
+
+ /// @throws css::uno::RuntimeException
+ explicit ScVbaHyperlinks(
+ const css::uno::Reference< ov::XHelperInterface >& rxParent,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const ScVbaHyperlinksRef& rxSheetHlinks, const ScRangeList& rScRanges );
+
+ virtual ~ScVbaHyperlinks() override;
+
+ // XHyperlinks
+ virtual css::uno::Reference< ov::excel::XHyperlink > SAL_CALL Add(
+ const css::uno::Any& rAnchor, const css::uno::Any& rAddress, const css::uno::Any& rSubAddress,
+ const css::uno::Any& rScreenTip, const css::uno::Any& rTextToDisplay ) override;
+
+ virtual void SAL_CALL Delete() override;
+
+ // XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+
+ // ScVbaCollectionBase
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& rSource ) override;
+
+ // XHelperInterface
+ VBAHELPER_DECL_XHELPERINTERFACE
+
+private:
+ ScVbaHyperlinksRef mxSheetHlinks;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbainterior.cxx b/sc/source/ui/vba/vbainterior.cxx
new file mode 100644
index 000000000..2849ed672
--- /dev/null
+++ b/sc/source/ui/vba/vbainterior.cxx
@@ -0,0 +1,413 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <com/sun/star/xml/AttributeData.hpp>
+
+#include <ooo/vba/excel/XlColorIndex.hpp>
+#include <ooo/vba/excel/XlPattern.hpp>
+
+#include <map>
+
+#include <sal/macros.h>
+
+#include "vbainterior.hxx"
+#include "vbapalette.hxx"
+#include <document.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+using namespace ::ooo::vba::excel::XlPattern;
+
+constexpr OUStringLiteral BACKCOLOR = u"CellBackColor";
+constexpr OUStringLiteral PATTERN = u"Pattern";
+constexpr OUStringLiteral PATTERNCOLOR = u"PatternColor";
+
+static std::map< sal_Int32, sal_Int32 > aPatternMap {
+ { xlPatternAutomatic, 0 },
+ { xlPatternChecker, 9 },
+ { xlPatternCrissCross, 16 },
+ { xlPatternDown, 7 },
+ { xlPatternGray16, 17 },
+ { xlPatternGray25, 4 },
+ { xlPatternGray50, 2 },
+ { xlPatternGray75, 3 },
+ { xlPatternGray8, 18 },
+ { xlPatternGrid, 15 },
+ { xlPatternHorizontal, 5 },
+ { xlPatternLightDown, 13 },
+ { xlPatternLightHorizontal, 11 },
+ { xlPatternLightUp, 14 },
+ { xlPatternLightVertical, 12 },
+ { xlPatternNone, 0 },
+ { xlPatternSemiGray75, 10 },
+ { xlPatternSolid, 0 },
+ { xlPatternUp, 8 },
+ { xlPatternVertical, 6 }
+};
+
+ScVbaInterior::ScVbaInterior( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< beans::XPropertySet >& xProps, ScDocument* pScDoc ) : ScVbaInterior_BASE( xParent, xContext ), m_xProps(xProps), m_pScDoc( pScDoc )
+{
+ // auto color
+ m_aPattColor = Color(0);
+ m_nPattern = 0;
+ if ( !m_xProps.is() )
+ throw lang::IllegalArgumentException("properties", uno::Reference< uno::XInterface >(), 2 );
+}
+
+uno::Any
+ScVbaInterior::getColor()
+{
+ return uno::Any( OORGBToXLRGB( GetBackColor() ) );
+}
+
+void
+ScVbaInterior::setColor( const uno::Any& _color )
+{
+ sal_Int32 nColor = 0;
+ if( _color >>= nColor )
+ {
+ SetUserDefinedAttributes( BACKCOLOR, SetAttributeData( XLRGBToOORGB( nColor ) ) );
+ SetMixedColor();
+ }
+}
+
+void
+ScVbaInterior::SetMixedColor()
+{
+ // pattern
+ uno::Any aPattern = GetUserDefinedAttributes( PATTERN );
+ if( aPattern.hasValue() )
+ {
+ m_nPattern = GetAttributeData( aPattern );
+ }
+ sal_Int32 nPattern = aPatternMap[ m_nPattern ];
+ // pattern color
+ uno::Any aPatternColor = GetUserDefinedAttributes( PATTERNCOLOR );
+ if( aPatternColor.hasValue() )
+ {
+ sal_uInt32 nPatternColor = GetAttributeData( aPatternColor );
+ m_aPattColor = Color(ColorTransparency, nPatternColor);
+ }
+ Color nPatternColor = m_aPattColor;
+ // back color
+ Color aBackColor( GetBackColor() );
+ // set mixed color
+ Color aMixedColor;
+ if( nPattern > 0 )
+ aMixedColor = GetPatternColor( nPatternColor, aBackColor, static_cast<sal_uInt32>(nPattern) );
+ else
+ aMixedColor = GetPatternColor( aBackColor, aBackColor, static_cast<sal_uInt32>(nPattern) );
+ Color nMixedColor = aMixedColor.GetRGBColor();
+ m_xProps->setPropertyValue( BACKCOLOR , uno::Any( nMixedColor ) );
+}
+
+uno::Reference< container::XIndexAccess >
+ScVbaInterior::getPalette() const
+{
+ if ( !m_pScDoc )
+ throw uno::RuntimeException();
+ SfxObjectShell* pShell = m_pScDoc->GetDocumentShell();
+ ScVbaPalette aPalette( pShell );
+ return aPalette.getPalette();
+}
+
+void SAL_CALL
+ScVbaInterior::setColorIndex( const css::uno::Any& _colorindex )
+{
+ sal_Int32 nIndex = 0;
+ _colorindex >>= nIndex;
+
+ // hackly for excel::XlColorIndex::xlColorIndexNone
+ if( nIndex == excel::XlColorIndex::xlColorIndexNone )
+ {
+ m_xProps->setPropertyValue( BACKCOLOR, uno::Any( sal_Int32( -1 ) ) );
+ }
+ else
+ {
+ // setColor expects colors in XL RGB values
+ // #FIXME this is daft we convert OO RGB val to XL RGB val and
+ // then back again to OO RGB value
+ setColor( OORGBToXLRGB( GetIndexColor( nIndex ) ) );
+ }
+}
+uno::Any
+ScVbaInterior::GetIndexColor( sal_Int32 nColorIndex )
+{
+ sal_Int32 nIndex = nColorIndex;
+ // #FIXME xlColorIndexAutomatic & xlColorIndexNone are not really
+ // handled properly here
+ if ( !nIndex || ( nIndex == excel::XlColorIndex::xlColorIndexAutomatic ) || ( nIndex == excel::XlColorIndex::xlColorIndexNone ) )
+ nIndex = 2; // default is white ( this maybe will probably break, e.g. we may at some stage need to know what this interior is, a cell or something else and then pick a default colour based on that )
+ --nIndex; // OOo indices are zero bases
+ uno::Reference< container::XIndexAccess > xIndex = getPalette();
+ return xIndex->getByIndex( nIndex );
+}
+
+sal_Int32
+ScVbaInterior::GetColorIndex( const sal_Int32 nColor )
+{
+ uno::Reference< container::XIndexAccess > xIndex = getPalette();
+ sal_Int32 nElems = xIndex->getCount();
+ sal_Int32 nIndex = -1;
+ for ( sal_Int32 count=0; count<nElems; ++count )
+ {
+ sal_Int32 nPaletteColor = 0;
+ xIndex->getByIndex( count ) >>= nPaletteColor;
+ if ( nPaletteColor == nColor )
+ {
+ nIndex = count + 1; // 1 based
+ break;
+ }
+ }
+ return nIndex;
+}
+
+uno::Any SAL_CALL
+ScVbaInterior::getColorIndex()
+{
+ sal_Int32 nColor = 0;
+ // hackly for excel::XlColorIndex::xlColorIndexNone
+ uno::Any aColor = m_xProps->getPropertyValue( BACKCOLOR );
+ if( ( aColor >>= nColor ) && ( nColor == -1 ) )
+ {
+ nColor = excel::XlColorIndex::xlColorIndexNone;
+ return uno::Any( nColor );
+ }
+
+ // getColor returns Xl ColorValue, need to convert it to OO val
+ // as the palette deals with OO RGB values
+ // #FIXME this is daft in getColor we convert OO RGB val to XL RGB val
+ // and then back again to OO RGB value
+ XLRGBToOORGB( getColor() ) >>= nColor;
+
+ return uno::Any( GetColorIndex( nColor ) );
+}
+Color
+ScVbaInterior::GetPatternColor( const Color& rPattColor, const Color& rBackColor, sal_uInt32 nXclPattern )
+{
+ // 0x00 == 0% transparence (full rPattColor)
+ // 0x80 == 100% transparence (full rBackColor)
+ static const sal_uInt8 pnRatioTable[] =
+ {
+ 0x80, 0x00, 0x40, 0x20, 0x60, 0x40, 0x40, 0x40, // 00 - 07
+ 0x40, 0x40, 0x20, 0x60, 0x60, 0x60, 0x60, 0x48, // 08 - 15
+ 0x50, 0x70, 0x78 // 16 - 18
+ };
+ return ( nXclPattern < SAL_N_ELEMENTS( pnRatioTable ) ) ?
+ GetMixedColor( rPattColor, rBackColor, pnRatioTable[ nXclPattern ] ) : rPattColor;
+}
+Color
+ScVbaInterior::GetMixedColor( const Color& rFore, const Color& rBack, sal_uInt8 nTrans )
+{
+ return Color(
+ ColorTransparency, nTrans,
+ GetMixedColorComp( rFore.GetRed(), rBack.GetRed(), nTrans ),
+ GetMixedColorComp( rFore.GetGreen(), rBack.GetGreen(), nTrans ),
+ GetMixedColorComp( rFore.GetBlue(), rBack.GetBlue(), nTrans ));
+}
+sal_uInt8
+ScVbaInterior::GetMixedColorComp( sal_uInt8 nFore, sal_uInt8 nBack, sal_uInt8 nTrans )
+{
+ sal_uInt32 nTemp = ((static_cast< sal_Int32 >( nBack ) - nFore) * nTrans) / 0x80 + nFore;
+ return static_cast< sal_uInt8 >( nTemp );
+}
+uno::Reference< container::XNameContainer >
+ScVbaInterior::GetAttributeContainer()
+{
+ return uno::Reference < container::XNameContainer > ( m_xProps->getPropertyValue("UserDefinedAttributes"), uno::UNO_QUERY_THROW );
+}
+sal_Int32
+ScVbaInterior::GetAttributeData( uno::Any const & aValue )
+{
+ xml::AttributeData aDataValue;
+ if( aValue >>= aDataValue )
+ {
+ return aDataValue.Value.toInt32();
+ }
+ return 0;
+}
+uno::Any
+ScVbaInterior::SetAttributeData( sal_Int32 nValue )
+{
+ xml::AttributeData aAttributeData;
+ aAttributeData.Type = "sal_Int32";
+ aAttributeData.Value = OUString::number( nValue );
+ return uno::Any( aAttributeData );
+}
+uno::Any
+ScVbaInterior::GetUserDefinedAttributes( const OUString& sName )
+{
+ uno::Reference< container::XNameContainer > xNameContainer( GetAttributeContainer(), uno::UNO_SET_THROW );
+ if( xNameContainer->hasByName( sName ) )
+ {
+ return xNameContainer->getByName( sName );
+ }
+ return uno::Any();
+}
+void
+ScVbaInterior::SetUserDefinedAttributes( const OUString& sName, const uno::Any& aValue )
+{
+ if( aValue.hasValue() )
+ {
+ uno::Reference< container::XNameContainer > xNameContainer( GetAttributeContainer(), uno::UNO_SET_THROW );
+ if( xNameContainer->hasByName( sName ) )
+ xNameContainer->removeByName( sName );
+ xNameContainer->insertByName( sName, aValue );
+ m_xProps->setPropertyValue("UserDefinedAttributes", uno::Any( xNameContainer ) );
+ }
+}
+// OOo do not support below API
+uno::Any SAL_CALL
+ScVbaInterior::getPattern()
+{
+ // XlPattern
+ uno::Any aPattern = GetUserDefinedAttributes( PATTERN );
+ if( aPattern.hasValue() )
+ return uno::Any( GetAttributeData( aPattern ) );
+ return uno::Any( excel::XlPattern::xlPatternNone );
+}
+void SAL_CALL
+ScVbaInterior::setPattern( const uno::Any& _pattern )
+{
+ if( !(_pattern >>= m_nPattern) )
+ throw uno::RuntimeException("Invalid Pattern index" );
+
+ SetUserDefinedAttributes( PATTERN, SetAttributeData( m_nPattern ) );
+ SetMixedColor();
+
+}
+Color
+ScVbaInterior::GetBackColor()
+{
+ sal_Int32 nColor = 0;
+ Color aBackColor;
+ uno::Any aColor = GetUserDefinedAttributes( BACKCOLOR );
+ if( aColor.hasValue() )
+ {
+ nColor = GetAttributeData( aColor );
+ aBackColor = Color(ColorTransparency, nColor);
+ }
+ else
+ {
+ uno::Any aAny = OORGBToXLRGB( m_xProps->getPropertyValue( BACKCOLOR ) );
+ if( aAny >>= nColor )
+ {
+ nColor = XLRGBToOORGB( nColor );
+ aBackColor = Color(ColorTransparency, nColor);
+ SetUserDefinedAttributes( BACKCOLOR, SetAttributeData( nColor ) );
+ }
+ }
+ return aBackColor;
+}
+uno::Any SAL_CALL
+ScVbaInterior::getPatternColor()
+{
+ // 0 is the default color. no filled.
+ uno::Any aPatternColor = GetUserDefinedAttributes( PATTERNCOLOR );
+ if( aPatternColor.hasValue() )
+ {
+ sal_uInt32 nPatternColor = GetAttributeData( aPatternColor );
+ return uno::Any( OORGBToXLRGB( Color(ColorTransparency, nPatternColor) ) );
+ }
+ return uno::Any( sal_Int32( 0 ) );
+}
+void SAL_CALL
+ScVbaInterior::setPatternColor( const uno::Any& _patterncolor )
+{
+ sal_Int32 nPattColor = 0;
+ if( !(_patterncolor >>= nPattColor) )
+ throw uno::RuntimeException("Invalid Pattern Color" );
+
+ SetUserDefinedAttributes( PATTERNCOLOR, SetAttributeData( XLRGBToOORGB( nPattColor ) ) );
+ SetMixedColor();
+
+}
+uno::Any SAL_CALL
+ScVbaInterior::getPatternColorIndex()
+{
+ sal_Int32 nColor = 0;
+ XLRGBToOORGB( getPatternColor() ) >>= nColor;
+
+ return uno::Any( GetColorIndex( nColor ) );
+}
+void SAL_CALL
+ScVbaInterior::setPatternColorIndex( const uno::Any& _patterncolorindex )
+{
+ sal_Int32 nColorIndex = 0;
+ if( !(_patterncolorindex >>= nColorIndex) )
+ throw uno::RuntimeException("Invalid Pattern Color" );
+
+ if( nColorIndex == 0 )
+ return;
+ Color nPattColor;
+ GetIndexColor( nColorIndex ) >>= nPattColor;
+ setPatternColor( uno::Any( OORGBToXLRGB( nPattColor ) ) );
+
+}
+
+uno::Any SAL_CALL ScVbaInterior::getThemeColor()
+{
+ // Just a stub for now.
+ return uno::Any(static_cast<sal_Int32>(0));
+}
+
+void SAL_CALL ScVbaInterior::setThemeColor(const uno::Any& /*rAny*/)
+{
+ // Just a stub for now.
+}
+
+uno::Any SAL_CALL ScVbaInterior::getTintAndShade()
+{
+ // Just a stub for now.
+ return uno::Any(static_cast<double>(0));
+}
+
+void SAL_CALL ScVbaInterior::setTintAndShade(const uno::Any& /*rAny*/)
+{
+ // Just a stub for now.
+}
+
+uno::Any SAL_CALL ScVbaInterior::getPatternTintAndShade()
+{
+ // Just a stub for now.
+ return uno::Any(static_cast<double>(0));
+}
+
+void SAL_CALL ScVbaInterior::setPatternTintAndShade(const uno::Any& /*rAny*/)
+{
+ // Just a stub for now.
+}
+
+OUString
+ScVbaInterior::getServiceImplName()
+{
+ return "ScVbaInterior";
+}
+
+uno::Sequence< OUString >
+ScVbaInterior::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Interior"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbainterior.hxx b/sc/source/ui/vba/vbainterior.hxx
new file mode 100644
index 000000000..1ea226e63
--- /dev/null
+++ b/sc/source/ui/vba/vbainterior.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 <ooo/vba/excel/XInterior.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+#include <tools/color.hxx>
+
+class ScDocument;
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XInterior > ScVbaInterior_BASE;
+
+class ScVbaInterior final : public ScVbaInterior_BASE
+{
+ css::uno::Reference< css::beans::XPropertySet > m_xProps;
+ ScDocument* m_pScDoc;
+ Color m_aPattColor;
+ sal_Int32 m_nPattern;
+
+ css::uno::Reference< css::container::XIndexAccess > getPalette() const;
+ css::uno::Reference< css::container::XNameContainer > GetAttributeContainer();
+ static css::uno::Any SetAttributeData( sal_Int32 nValue );
+ static sal_Int32 GetAttributeData( css::uno::Any const & aValue );
+ Color GetBackColor();
+ static Color GetPatternColor( const Color& rPattColor, const Color& rBackColor, sal_uInt32 nXclPattern );
+ static Color GetMixedColor( const Color& rFore, const Color& rBack, sal_uInt8 nTrans );
+ static sal_uInt8 GetMixedColorComp( sal_uInt8 nFore, sal_uInt8 nBack, sal_uInt8 nTrans );
+ css::uno::Any GetIndexColor( sal_Int32 nColorIndex );
+ sal_Int32 GetColorIndex( const sal_Int32 nColor );
+ css::uno::Any GetUserDefinedAttributes( const OUString& sName );
+ void SetUserDefinedAttributes( const OUString& sName, const css::uno::Any& aValue );
+ void SetMixedColor();
+
+public:
+ /// @throws css::lang::IllegalArgumentException
+ ScVbaInterior( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::beans::XPropertySet >& xProps, ScDocument* pScDoc = nullptr);
+
+ virtual css::uno::Any SAL_CALL getColor() override ;
+ virtual void SAL_CALL setColor( const css::uno::Any& _color ) override ;
+
+ virtual css::uno::Any SAL_CALL getColorIndex() override;
+ virtual void SAL_CALL setColorIndex( const css::uno::Any& _colorindex ) override;
+ virtual css::uno::Any SAL_CALL getPattern() override;
+ virtual void SAL_CALL setPattern( const css::uno::Any& _pattern ) override;
+ virtual css::uno::Any SAL_CALL getPatternColor() override;
+ virtual void SAL_CALL setPatternColor( const css::uno::Any& _patterncolor ) override;
+ virtual css::uno::Any SAL_CALL getPatternColorIndex() override;
+ virtual void SAL_CALL setPatternColorIndex( const css::uno::Any& _patterncolorindex ) override;
+ css::uno::Any SAL_CALL getThemeColor() override;
+ void SAL_CALL setThemeColor(const css::uno::Any& rAny) override;
+ css::uno::Any SAL_CALL getTintAndShade() override;
+ void SAL_CALL setTintAndShade(const css::uno::Any& rAny) override;
+ css::uno::Any SAL_CALL getPatternTintAndShade() override;
+ void SAL_CALL setPatternTintAndShade(const css::uno::Any& rAny) override;
+ //XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbalineshape.cxx b/sc/source/ui/vba/vbalineshape.cxx
new file mode 100644
index 000000000..fac0f1715
--- /dev/null
+++ b/sc/source/ui/vba/vbalineshape.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 "vbalineshape.hxx"
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+/*
+ * This is implemented as a new class in order to provide XTypeProvider
+ * interface. This is needed by TypeOf ... Is ... basic operator.
+ */
+
+ScVbaLineShape::ScVbaLineShape( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< drawing::XShape >& xShape, const uno::Reference< drawing::XShapes >& xShapes, const uno::Reference< frame::XModel >& xModel ) : LineShapeImpl_BASE( uno::Reference< XHelperInterface >(), xContext, xShape, xShapes, xModel, ScVbaShape::getType( xShape ) )
+{}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbalineshape.hxx b/sc/source/ui/vba/vbalineshape.hxx
new file mode 100644
index 000000000..953bc87a3
--- /dev/null
+++ b/sc/source/ui/vba/vbalineshape.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <ooo/vba/msforms/XLine.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <vbahelper/vbashape.hxx>
+
+typedef cppu::ImplInheritanceHelper< ScVbaShape, ov::msforms::XLine > LineShapeImpl_BASE;
+
+class ScVbaLineShape : public LineShapeImpl_BASE
+{
+public:
+ ScVbaLineShape( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::drawing::XShapes >& xShapes, const css::uno::Reference< css::frame::XModel >& xModel );
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenu.cxx b/sc/source/ui/vba/vbamenu.cxx
new file mode 100644
index 000000000..38b4feb11
--- /dev/null
+++ b/sc/source/ui/vba/vbamenu.cxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "vbamenu.hxx"
+#include "vbamenuitems.hxx"
+#include <ooo/vba/XCommandBarControls.hpp>
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+ScVbaMenu::ScVbaMenu( const uno::Reference< ov::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Reference< XCommandBarControl >& rCommandBarControl ) : Menu_BASE( rParent, rContext ), m_xCommandBarControl( rCommandBarControl )
+{
+}
+
+OUString SAL_CALL
+ScVbaMenu::getCaption()
+{
+ return m_xCommandBarControl->getCaption();
+}
+
+void SAL_CALL
+ScVbaMenu::setCaption( const OUString& _caption )
+{
+ m_xCommandBarControl->setCaption( _caption );
+}
+
+void SAL_CALL
+ScVbaMenu::Delete( )
+{
+ m_xCommandBarControl->Delete();
+}
+
+uno::Any SAL_CALL
+ScVbaMenu::MenuItems( const uno::Any& aIndex )
+{
+ uno::Reference< XCommandBarControls > xCommandBarControls( m_xCommandBarControl->Controls( uno::Any() ), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XMenuItems > xMenuItems( new ScVbaMenuItems( this, mxContext, xCommandBarControls ) );
+ if( aIndex.hasValue() )
+ {
+ return xMenuItems->Item( aIndex, uno::Any() );
+ }
+ return uno::Any( xMenuItems );
+}
+
+OUString
+ScVbaMenu::getServiceImplName()
+{
+ return "ScVbaMenu";
+}
+
+uno::Sequence<OUString>
+ScVbaMenu::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Menu"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenu.hxx b/sc/source/ui/vba/vbamenu.hxx
new file mode 100644
index 000000000..284e2bc76
--- /dev/null
+++ b/sc/source/ui/vba/vbamenu.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 <ooo/vba/excel/XMenu.hpp>
+#include <ooo/vba/XCommandBarControl.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XMenu > Menu_BASE;
+
+class ScVbaMenu : public Menu_BASE
+{
+private:
+ css::uno::Reference< ov::XCommandBarControl > m_xCommandBarControl;
+
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaMenu( const css::uno::Reference< ov::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, const css::uno::Reference< ov::XCommandBarControl >& rCommandBarControl );
+
+ virtual OUString SAL_CALL getCaption() override;
+ virtual void SAL_CALL setCaption( const OUString& _caption ) override;
+
+ virtual void SAL_CALL Delete( ) override;
+ virtual css::uno::Any SAL_CALL MenuItems( const css::uno::Any& aIndex ) override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenubar.cxx b/sc/source/ui/vba/vbamenubar.cxx
new file mode 100644
index 000000000..bd25c02a7
--- /dev/null
+++ b/sc/source/ui/vba/vbamenubar.cxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include "vbamenubar.hxx"
+#include "vbamenus.hxx"
+#include <ooo/vba/XCommandBarControls.hpp>
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+ScVbaMenuBar::ScVbaMenuBar( const uno::Reference< ov::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Reference< XCommandBar >& rCommandBar ) : MenuBar_BASE(rParent, rContext), m_xCommandBar(rCommandBar)
+{
+}
+
+uno::Any SAL_CALL
+ScVbaMenuBar::Menus( const uno::Any& aIndex )
+{
+ uno::Reference< XCommandBarControls > xCommandBarControls( m_xCommandBar->Controls( uno::Any() ), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XMenus > xMenus( new ScVbaMenus( this, mxContext, xCommandBarControls ) );
+ if( aIndex.hasValue() )
+ {
+ return xMenus->Item( aIndex, uno::Any() );
+ }
+ return uno::Any( xMenus );
+}
+
+OUString
+ScVbaMenuBar::getServiceImplName()
+{
+ return "ScVbaMenuBar";
+}
+
+uno::Sequence<OUString>
+ScVbaMenuBar::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.MenuBar"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenubar.hxx b/sc/source/ui/vba/vbamenubar.hxx
new file mode 100644
index 000000000..75c1854c6
--- /dev/null
+++ b/sc/source/ui/vba/vbamenubar.hxx
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#pragma once
+
+#include <ooo/vba/excel/XMenuBar.hpp>
+#include <ooo/vba/XCommandBar.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XMenuBar > MenuBar_BASE;
+
+class ScVbaMenuBar : public MenuBar_BASE
+{
+private:
+ css::uno::Reference< ov::XCommandBar > m_xCommandBar;
+
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaMenuBar( const css::uno::Reference< ov::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, const css::uno::Reference< ov::XCommandBar >& rCommandBar );
+
+ virtual css::uno::Any SAL_CALL Menus( const css::uno::Any& aIndex ) override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenubars.cxx b/sc/source/ui/vba/vbamenubars.cxx
new file mode 100644
index 000000000..6bcea2baa
--- /dev/null
+++ b/sc/source/ui/vba/vbamenubars.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/.
+ */
+#include "vbamenubars.hxx"
+#include "vbamenubar.hxx"
+#include <cppuhelper/implbase.hxx>
+#include <ooo/vba/excel/XlSheetType.hpp>
+#include <ooo/vba/XCommandBars.hpp>
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+namespace {
+
+class MenuBarEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration >
+{
+ uno::Reference< XHelperInterface > m_xParent;
+ uno::Reference< uno::XComponentContext > m_xContext;
+ uno::Reference< container::XEnumeration > m_xEnumeration;
+public:
+ /// @throws uno::RuntimeException
+ MenuBarEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration) : m_xParent( xParent ), m_xContext( xContext ), m_xEnumeration( xEnumeration )
+ {
+ }
+ virtual sal_Bool SAL_CALL hasMoreElements() override
+ {
+ return m_xEnumeration->hasMoreElements();
+ }
+ virtual uno::Any SAL_CALL nextElement() override
+ {
+ // FIXME: should be add menubar
+ if( !hasMoreElements() )
+ throw container::NoSuchElementException();
+
+ uno::Reference< XCommandBar > xCommandBar( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XMenuBar > xMenuBar( new ScVbaMenuBar( m_xParent, m_xContext, xCommandBar ) );
+ return uno::Any( xMenuBar );
+ }
+};
+
+}
+
+ScVbaMenuBars::ScVbaMenuBars( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< XCommandBars >& xCommandBars ) : MenuBars_BASE( xParent, xContext, uno::Reference< container::XIndexAccess>() ), m_xCommandBars( xCommandBars )
+{
+}
+
+ScVbaMenuBars::~ScVbaMenuBars()
+{
+}
+
+// XEnumerationAccess
+uno::Type SAL_CALL
+ScVbaMenuBars::getElementType()
+{
+ return cppu::UnoType<excel::XMenuBar>::get();
+}
+
+uno::Reference< container::XEnumeration >
+ScVbaMenuBars::createEnumeration()
+{
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xCommandBars, uno::UNO_QUERY_THROW );
+ return uno::Reference< container::XEnumeration >( new MenuBarEnumeration( this, mxContext, xEnumAccess->createEnumeration() ) );
+}
+
+uno::Any
+ScVbaMenuBars::createCollectionObject( const uno::Any& aSource )
+{
+ // make no sense
+ return aSource;
+}
+
+sal_Int32 SAL_CALL
+ScVbaMenuBars::getCount()
+{
+ return m_xCommandBars->getCount();
+}
+
+// ScVbaCollectionBaseImpl
+uno::Any SAL_CALL
+ScVbaMenuBars::Item( const uno::Any& aIndex, const uno::Any& /*aIndex2*/ )
+{
+ sal_Int16 nIndex = 0;
+ aIndex >>= nIndex;
+ if( nIndex == excel::XlSheetType::xlWorksheet )
+ {
+ uno::Any aSource;
+ aSource <<= OUString( "Worksheet Menu Bar" );
+ uno::Reference< XCommandBar > xCommandBar( m_xCommandBars->Item( aSource, uno::Any() ), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XMenuBar > xMenuBar( new ScVbaMenuBar( this, mxContext, xCommandBar ) );
+ return uno::Any( xMenuBar );
+ }
+
+ throw uno::RuntimeException("Not implemented" );
+}
+
+// XHelperInterface
+OUString
+ScVbaMenuBars::getServiceImplName()
+{
+ return "ScVbaMenuBars";
+}
+
+uno::Sequence<OUString>
+ScVbaMenuBars::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.MenuBars"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenubars.hxx b/sc/source/ui/vba/vbamenubars.hxx
new file mode 100644
index 000000000..1303a0ff3
--- /dev/null
+++ b/sc/source/ui/vba/vbamenubars.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 <ooo/vba/excel/XMenuBars.hpp>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace ooo::vba { class XCommandBars; }
+
+typedef CollTestImplHelper< ov::excel::XMenuBars > MenuBars_BASE;
+
+class ScVbaMenuBars : public MenuBars_BASE
+{
+private:
+ css::uno::Reference< ov::XCommandBars > m_xCommandBars;
+
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaMenuBars( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< ov::XCommandBars >& xCommandBars );
+ virtual ~ScVbaMenuBars() override;
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual css::uno::Any SAL_CALL Item( const css::uno::Any& aIndex, const css::uno::Any& /*aIndex2*/ ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenuitem.cxx b/sc/source/ui/vba/vbamenuitem.cxx
new file mode 100644
index 000000000..2dba780ba
--- /dev/null
+++ b/sc/source/ui/vba/vbamenuitem.cxx
@@ -0,0 +1,64 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include "vbamenuitem.hxx"
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+ScVbaMenuItem::ScVbaMenuItem( const uno::Reference< ov::XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Reference< XCommandBarControl >& rCommandBarControl ) : MenuItem_BASE( rParent, rContext ), m_xCommandBarControl( rCommandBarControl )
+{
+}
+
+OUString SAL_CALL
+ScVbaMenuItem::getCaption()
+{
+ return m_xCommandBarControl->getCaption();
+}
+
+void SAL_CALL
+ScVbaMenuItem::setCaption( const OUString& _caption )
+{
+ m_xCommandBarControl->setCaption( _caption );
+}
+
+OUString SAL_CALL
+ScVbaMenuItem::getOnAction()
+{
+ return m_xCommandBarControl->getOnAction();
+}
+
+void SAL_CALL
+ScVbaMenuItem::setOnAction( const OUString& _onaction )
+{
+ m_xCommandBarControl->setOnAction( _onaction );
+}
+
+void SAL_CALL
+ScVbaMenuItem::Delete( )
+{
+ m_xCommandBarControl->Delete();
+}
+
+OUString
+ScVbaMenuItem::getServiceImplName()
+{
+ return "ScVbaMenuItem";
+}
+
+uno::Sequence<OUString>
+ScVbaMenuItem::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.MenuItem"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenuitem.hxx b/sc/source/ui/vba/vbamenuitem.hxx
new file mode 100644
index 000000000..bf8c35b29
--- /dev/null
+++ b/sc/source/ui/vba/vbamenuitem.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 <ooo/vba/excel/XMenuItem.hpp>
+#include <ooo/vba/XCommandBarControl.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XMenuItem > MenuItem_BASE;
+
+class ScVbaMenuItem : public MenuItem_BASE
+{
+private:
+ css::uno::Reference< ov::XCommandBarControl > m_xCommandBarControl;
+
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaMenuItem( const css::uno::Reference< ov::XHelperInterface >& rParent, const css::uno::Reference< css::uno::XComponentContext >& rContext, const css::uno::Reference< ov::XCommandBarControl >& rCommandBarControl );
+
+ virtual OUString SAL_CALL getCaption() override;
+ virtual void SAL_CALL setCaption( const OUString& _caption ) override;
+ virtual OUString SAL_CALL getOnAction() override;
+ virtual void SAL_CALL setOnAction( const OUString& _onaction ) override;
+
+ virtual void SAL_CALL Delete( ) override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenuitems.cxx b/sc/source/ui/vba/vbamenuitems.cxx
new file mode 100644
index 000000000..646fd82cb
--- /dev/null
+++ b/sc/source/ui/vba/vbamenuitems.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/.
+ */
+#include "vbamenuitems.hxx"
+#include "vbamenuitem.hxx"
+#include "vbamenu.hxx"
+#include <cppuhelper/implbase.hxx>
+#include <ooo/vba/office/MsoControlType.hpp>
+#include <ooo/vba/XCommandBarControls.hpp>
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+typedef ::cppu::WeakImplHelper< container::XEnumeration > MenuEnumeration_BASE;
+
+namespace {
+
+class MenuEnumeration : public MenuEnumeration_BASE
+{
+ uno::Reference< XHelperInterface > m_xParent;
+ uno::Reference< uno::XComponentContext > m_xContext;
+ uno::Reference< container::XEnumeration > m_xEnumeration;
+public:
+ /// @throws uno::RuntimeException
+ MenuEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration) : m_xParent( xParent ), m_xContext( xContext ), m_xEnumeration( xEnumeration )
+ {
+ }
+ virtual sal_Bool SAL_CALL hasMoreElements() override
+ {
+ return m_xEnumeration->hasMoreElements();
+ }
+ virtual uno::Any SAL_CALL nextElement() override
+ {
+ // FIXME: should be add menu
+ if( !hasMoreElements() )
+ throw container::NoSuchElementException();
+
+ uno::Reference< XCommandBarControl > xCommandBarControl( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW );
+ if( xCommandBarControl->getType() == office::MsoControlType::msoControlPopup )
+ {
+ uno::Reference< excel::XMenu > xMenu( new ScVbaMenu( m_xParent, m_xContext, xCommandBarControl ) );
+ return uno::Any( xMenu );
+ }
+ else if( xCommandBarControl->getType() == office::MsoControlType::msoControlButton )
+ {
+ uno::Reference< excel::XMenuItem > xMenuItem( new ScVbaMenuItem( m_xParent, m_xContext, xCommandBarControl ) );
+ return uno::Any( xMenuItem );
+ }
+ nextElement();
+
+ return uno::Any();
+ }
+};
+
+}
+
+ScVbaMenuItems::ScVbaMenuItems( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< XCommandBarControls >& xCommandBarControls ) : MenuItems_BASE( xParent, xContext, uno::Reference< container::XIndexAccess>() ), m_xCommandBarControls( xCommandBarControls )
+{
+}
+
+// XEnumerationAccess
+uno::Type SAL_CALL
+ScVbaMenuItems::getElementType()
+{
+ return cppu::UnoType<excel::XMenuItem>::get();
+}
+
+uno::Reference< container::XEnumeration >
+ScVbaMenuItems::createEnumeration()
+{
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xCommandBarControls, uno::UNO_QUERY_THROW );
+ return uno::Reference< container::XEnumeration >( new MenuEnumeration( this, mxContext, xEnumAccess->createEnumeration() ) );
+}
+
+uno::Any
+ScVbaMenuItems::createCollectionObject( const uno::Any& aSource )
+{
+ // make no sense
+ return aSource;
+}
+
+sal_Int32 SAL_CALL
+ScVbaMenuItems::getCount()
+{
+ // FIXME: should check if it is a popup menu
+ return m_xCommandBarControls->getCount();
+}
+
+// ScVbaCollectionBaseImpl
+uno::Any SAL_CALL
+ScVbaMenuItems::Item( const uno::Any& aIndex, const uno::Any& /*aIndex2*/ )
+{
+ uno::Reference< XCommandBarControl > xCommandBarControl( m_xCommandBarControls->Item( aIndex, uno::Any() ), uno::UNO_QUERY_THROW );
+ if( xCommandBarControl->getType() == office::MsoControlType::msoControlPopup )
+ return uno::Any( uno::Reference< excel::XMenu > ( new ScVbaMenu( this, mxContext, xCommandBarControl ) ) );
+ else if( xCommandBarControl->getType() == office::MsoControlType::msoControlButton )
+ return uno::Any( uno::Reference< excel::XMenuItem > ( new ScVbaMenuItem( this, mxContext, xCommandBarControl ) ) );
+ throw uno::RuntimeException();
+}
+
+uno::Reference< excel::XMenuItem > SAL_CALL ScVbaMenuItems::Add( const OUString& Caption, const css::uno::Any& OnAction, const css::uno::Any& /*ShortcutKey*/, const css::uno::Any& Before, const css::uno::Any& Restore, const css::uno::Any& /*StatusBar*/, const css::uno::Any& /*HelpFile*/, const css::uno::Any& /*HelpContextID*/ )
+{
+ uno::Reference< XCommandBarControl > xCommandBarControl = m_xCommandBarControls->Add(
+ uno::Any( office::MsoControlType::msoControlButton ),
+ uno::Any(), uno::Any(), Before, Restore );
+ xCommandBarControl->setCaption( Caption );
+ if( OnAction.hasValue() )
+ {
+ OUString sAction;
+ OnAction >>= sAction;
+ xCommandBarControl->setOnAction( sAction );
+ }
+ return uno::Reference< excel::XMenuItem >( new ScVbaMenuItem( this, mxContext, xCommandBarControl ) );
+}
+
+// XHelperInterface
+OUString
+ScVbaMenuItems::getServiceImplName()
+{
+ return "ScVbaMenuItems";
+}
+
+uno::Sequence<OUString>
+ScVbaMenuItems::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.MenuItems"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenuitems.hxx b/sc/source/ui/vba/vbamenuitems.hxx
new file mode 100644
index 000000000..71f43e634
--- /dev/null
+++ b/sc/source/ui/vba/vbamenuitems.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 <ooo/vba/excel/XMenuItems.hpp>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace ooo::vba { class XCommandBarControls; }
+namespace ooo::vba::excel { class XMenuItem; }
+
+typedef CollTestImplHelper< ov::excel::XMenuItems > MenuItems_BASE;
+
+class ScVbaMenuItems : public MenuItems_BASE
+{
+private:
+ css::uno::Reference< ov::XCommandBarControls > m_xCommandBarControls;
+
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaMenuItems( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< ov::XCommandBarControls >& xCommandBarControls );
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+
+ // Methods
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index, const css::uno::Any& /*Index2*/ ) override;
+ virtual css::uno::Reference< ov::excel::XMenuItem > SAL_CALL Add( const OUString& Caption, const css::uno::Any& OnAction, const css::uno::Any& ShortcutKey, const css::uno::Any& Before, const css::uno::Any& Restore, const css::uno::Any& StatusBar, const css::uno::Any& HelpFile, const css::uno::Any& HelpContextID ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenus.cxx b/sc/source/ui/vba/vbamenus.cxx
new file mode 100644
index 000000000..807f0cf5a
--- /dev/null
+++ b/sc/source/ui/vba/vbamenus.cxx
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#include "vbamenus.hxx"
+#include "vbamenu.hxx"
+#include <cppuhelper/implbase.hxx>
+#include <ooo/vba/office/MsoControlType.hpp>
+#include <ooo/vba/XCommandBarControls.hpp>
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+typedef ::cppu::WeakImplHelper< container::XEnumeration > MenuEnumeration_BASE;
+
+namespace {
+
+class MenuEnumeration : public MenuEnumeration_BASE
+{
+ uno::Reference< XHelperInterface > m_xParent;
+ uno::Reference< uno::XComponentContext > m_xContext;
+ uno::Reference< container::XEnumeration > m_xEnumeration;
+public:
+ /// @throws uno::RuntimeException
+ MenuEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration) : m_xParent( xParent ), m_xContext( xContext ), m_xEnumeration( xEnumeration )
+ {
+ }
+ virtual sal_Bool SAL_CALL hasMoreElements() override
+ {
+ return m_xEnumeration->hasMoreElements();
+ }
+ virtual uno::Any SAL_CALL nextElement() override
+ {
+ // FIXME: should be add menu
+ if( !hasMoreElements() )
+ throw container::NoSuchElementException();
+
+ uno::Reference< XCommandBarControl > xCommandBarControl( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW );
+ if( xCommandBarControl->getType() == office::MsoControlType::msoControlPopup )
+ {
+ uno::Reference< excel::XMenu > xMenu( new ScVbaMenu( m_xParent, m_xContext, xCommandBarControl ) );
+ return uno::Any( xMenu );
+ }
+ nextElement();
+
+ return uno::Any();
+ }
+};
+
+}
+
+ScVbaMenus::ScVbaMenus( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< XCommandBarControls >& xCommandBarControls ) : Menus_BASE( xParent, xContext, uno::Reference< container::XIndexAccess>() ), m_xCommandBarControls( xCommandBarControls )
+{
+}
+
+// XEnumerationAccess
+uno::Type SAL_CALL
+ScVbaMenus::getElementType()
+{
+ return cppu::UnoType<excel::XMenu>::get();
+}
+
+uno::Reference< container::XEnumeration >
+ScVbaMenus::createEnumeration()
+{
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xCommandBarControls, uno::UNO_QUERY_THROW );
+ return uno::Reference< container::XEnumeration >( new MenuEnumeration( this, mxContext, xEnumAccess->createEnumeration() ) );
+}
+
+uno::Any
+ScVbaMenus::createCollectionObject( const uno::Any& aSource )
+{
+ // make no sense
+ return aSource;
+}
+
+sal_Int32 SAL_CALL
+ScVbaMenus::getCount()
+{
+ // FIXME: should check if it is a popup menu
+ return m_xCommandBarControls->getCount();
+}
+
+// ScVbaCollectionBaseImpl
+uno::Any SAL_CALL
+ScVbaMenus::Item( const uno::Any& aIndex, const uno::Any& /*aIndex2*/ )
+{
+ uno::Reference< XCommandBarControl > xCommandBarControl( m_xCommandBarControls->Item( aIndex, uno::Any() ), uno::UNO_QUERY_THROW );
+ if( xCommandBarControl->getType() != office::MsoControlType::msoControlPopup )
+ throw uno::RuntimeException();
+ return uno::Any( uno::Reference< excel::XMenu > ( new ScVbaMenu( this, mxContext, xCommandBarControl ) ) );
+}
+
+uno::Reference< excel::XMenu > SAL_CALL ScVbaMenus::Add( const OUString& Caption, const css::uno::Any& Before, const css::uno::Any& Restore )
+{
+ uno::Reference< XCommandBarControl > xCommandBarControl = m_xCommandBarControls->Add(
+ uno::Any( office::MsoControlType::msoControlPopup ),
+ uno::Any(), uno::Any(), Before, Restore );
+ xCommandBarControl->setCaption( Caption );
+ return uno::Reference< excel::XMenu >( new ScVbaMenu( this, mxContext, xCommandBarControl ) );
+}
+
+// XHelperInterface
+OUString
+ScVbaMenus::getServiceImplName()
+{
+ return "ScVbaMenus";
+}
+
+uno::Sequence<OUString>
+ScVbaMenus::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Menus"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbamenus.hxx b/sc/source/ui/vba/vbamenus.hxx
new file mode 100644
index 000000000..2a14cf3cb
--- /dev/null
+++ b/sc/source/ui/vba/vbamenus.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 <ooo/vba/excel/XMenus.hpp>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace ooo::vba { class XCommandBarControls; }
+namespace ooo::vba::excel { class XMenu; }
+
+typedef CollTestImplHelper< ov::excel::XMenus > Menus_BASE;
+
+class ScVbaMenus : public Menus_BASE
+{
+private:
+ css::uno::Reference< ov::XCommandBarControls > m_xCommandBarControls;
+
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaMenus( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< ov::XCommandBarControls >& xCommandBarControls );
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+
+ // Methods
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index, const css::uno::Any& /*Index2*/ ) override;
+ virtual css::uno::Reference< ov::excel::XMenu > SAL_CALL Add( const OUString& Caption, const css::uno::Any& Before, const css::uno::Any& Restore ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaname.cxx b/sc/source/ui/vba/vbaname.cxx
new file mode 100644
index 000000000..7ef8fe129
--- /dev/null
+++ b/sc/source/ui/vba/vbaname.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 "excelvbahelper.hxx"
+#include "vbaname.hxx"
+#include "vbarange.hxx"
+#include <docsh.hxx>
+#include <rangenam.hxx>
+#include <nameuno.hxx>
+#include <compiler.hxx>
+#include <tokenarray.hxx>
+
+#include <memory>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+ScVbaName::ScVbaName(const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::sheet::XNamedRange >& xName,
+ const css::uno::Reference< css::sheet::XNamedRanges >& xNames,
+ const css::uno::Reference< css::frame::XModel >& xModel ):
+ NameImpl_BASE( xParent , xContext ),
+ mxModel( xModel ),
+ mxNamedRange( xName ),
+ mxNames( xNames )
+{
+}
+
+ScVbaName::~ScVbaName()
+{
+}
+
+OUString
+ScVbaName::getName()
+{
+ return mxNamedRange->getName();
+}
+
+void
+ScVbaName::setName( const OUString & rName )
+{
+ mxNamedRange->setName( rName );
+}
+
+OUString
+ScVbaName::getNameLocal()
+{
+ return getName();
+}
+
+void
+ScVbaName::setNameLocal( const OUString & rName )
+{
+ setName( rName );
+}
+
+sal_Bool
+ScVbaName::getVisible()
+{
+ return true;
+}
+
+void
+ScVbaName::setVisible( sal_Bool /*bVisible*/ )
+{
+}
+
+OUString ScVbaName::getContent( const formula::FormulaGrammar::Grammar eGrammar )
+{
+ ScNamedRangeObj* pNamedRange = dynamic_cast< ScNamedRangeObj* >( mxNamedRange.get() );
+ OUString aContent;
+ if ( pNamedRange )
+ {
+ ScRangeData* pData = pNamedRange->GetRangeData_Impl();
+ if (pData)
+ aContent = pData->GetSymbol( eGrammar );
+ }
+ if (aContent.indexOf('=') != 0)
+ aContent = "=" + aContent;
+ return aContent;
+}
+
+void ScVbaName::setContent( const OUString& rContent, const formula::FormulaGrammar::Grammar eGrammar )
+{
+ OUString sContent( rContent );
+ if (sContent.startsWith("="))
+ sContent = sContent.copy(1);
+ ScNamedRangeObj* pNamedRange = dynamic_cast< ScNamedRangeObj* >( mxNamedRange.get() );
+
+ // We should be able to do the below by just setting calling SetCode on pNamedRange
+ // right?
+ if ( !(pNamedRange && pNamedRange->pDocShell) )
+ return;
+
+ ScDocument& rDoc = pNamedRange->pDocShell->GetDocument();
+ ScRangeData* pOldData = pNamedRange->GetRangeData_Impl();
+ if (pOldData)
+ {
+ // Shorter way of doing this ?
+ ScCompiler aComp( rDoc, pOldData->GetPos(), eGrammar );
+ std::unique_ptr<ScTokenArray> pArray(aComp.CompileString(sContent));
+ pOldData->SetCode(*pArray);
+ }
+}
+
+OUString
+ScVbaName::getValue()
+{
+ OUString sResult = getContent( formula::FormulaGrammar::GRAM_NATIVE_XL_A1 );
+
+ return sResult;
+}
+
+void
+ScVbaName::setValue( const OUString & rValue )
+{
+ setContent( rValue, formula::FormulaGrammar::GRAM_NATIVE_XL_A1 );
+}
+
+OUString
+ScVbaName::getRefersTo()
+{
+ return getValue();
+}
+
+void
+ScVbaName::setRefersTo( const OUString & rRefersTo )
+{
+ setValue( rRefersTo );
+}
+
+OUString
+ScVbaName::getRefersToLocal()
+{
+ return getRefersTo();
+}
+
+void
+ScVbaName::setRefersToLocal( const OUString & rRefersTo )
+{
+ setRefersTo( rRefersTo );
+}
+
+OUString
+ScVbaName::getRefersToR1C1()
+{
+ OUString sResult = getContent( formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 );
+ return sResult;
+}
+
+void
+ScVbaName::setRefersToR1C1( const OUString & rRefersTo )
+{
+ setContent( rRefersTo, formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 );
+}
+
+OUString
+ScVbaName::getRefersToR1C1Local()
+{
+ return getRefersToR1C1();
+}
+
+void
+ScVbaName::setRefersToR1C1Local( const OUString & rRefersTo )
+{
+ setRefersTo( rRefersTo );
+}
+
+css::uno::Reference< ov::excel::XRange >
+ScVbaName::getRefersToRange()
+{
+ uno::Reference< ov::excel::XRange > xRange = ScVbaRange::getRangeObjectForName(
+ mxContext, mxNamedRange->getName(), excel::getDocShell( mxModel ), formula::FormulaGrammar::CONV_XL_R1C1 );
+ return xRange;
+}
+
+void
+ScVbaName::Delete()
+{
+ mxNames->removeByName( mxNamedRange->getName() );
+}
+
+OUString
+ScVbaName::getServiceImplName()
+{
+ return "ScVbaName";
+}
+
+uno::Sequence< OUString >
+ScVbaName::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Name"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaname.hxx b/sc/source/ui/vba/vbaname.hxx
new file mode 100644
index 000000000..194b047fa
--- /dev/null
+++ b/sc/source/ui/vba/vbaname.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 <ooo/vba/excel/XName.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+#include <formula/grammar.hxx>
+
+namespace com::sun::star::sheet { class XNamedRange; }
+namespace com::sun::star::sheet { class XNamedRanges; }
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XName > NameImpl_BASE;
+
+class ScVbaName : public NameImpl_BASE
+{
+ css::uno::Reference< css::frame::XModel > mxModel;
+ css::uno::Reference< css::sheet::XNamedRange > mxNamedRange;
+ css::uno::Reference< css::sheet::XNamedRanges > mxNames;
+ OUString getContent( const formula::FormulaGrammar::Grammar eGrammar );
+ void setContent( const OUString& sContent, const formula::FormulaGrammar::Grammar eGrammar );
+public:
+ ScVbaName( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::sheet::XNamedRange >& xName , const css::uno::Reference< css::sheet::XNamedRanges >& xNames , const css::uno::Reference< css::frame::XModel >& xModel );
+ virtual ~ScVbaName() override;
+
+ // Attributes
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName( const OUString &rName ) override;
+ virtual OUString SAL_CALL getNameLocal() override;
+ virtual void SAL_CALL setNameLocal( const OUString &rName ) override;
+ virtual sal_Bool SAL_CALL getVisible() override;
+ virtual void SAL_CALL setVisible( sal_Bool bVisible ) override;
+ virtual OUString SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const OUString &rValue ) override;
+ virtual OUString SAL_CALL getRefersTo() override;
+ virtual void SAL_CALL setRefersTo( const OUString &rRefersTo ) override;
+ virtual OUString SAL_CALL getRefersToLocal() override;
+ virtual void SAL_CALL setRefersToLocal( const OUString &rRefersTo ) override;
+ virtual OUString SAL_CALL getRefersToR1C1() override;
+ virtual void SAL_CALL setRefersToR1C1( const OUString &rRefersTo ) override;
+ virtual OUString SAL_CALL getRefersToR1C1Local() override;
+ virtual void SAL_CALL setRefersToR1C1Local( const OUString &rRefersTo ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getRefersToRange() override;
+
+ // Methods
+ virtual void SAL_CALL Delete() override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbanames.cxx b/sc/source/ui/vba/vbanames.cxx
new file mode 100644
index 000000000..287dbcf3c
--- /dev/null
+++ b/sc/source/ui/vba/vbanames.cxx
@@ -0,0 +1,260 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XNamedRange.hpp>
+#include <com/sun/star/sheet/XNamedRanges.hpp>
+
+#include "excelvbahelper.hxx"
+#include "vbanames.hxx"
+#include "vbaname.hxx"
+#include "vbarange.hxx"
+#include <tabvwsh.hxx>
+#include <viewdata.hxx>
+#include <compiler.hxx>
+#include <tokenarray.hxx>
+#include <cellsuno.hxx>
+
+#include <memory>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+namespace {
+
+class NamesEnumeration : public EnumerationHelperImpl
+{
+ uno::Reference< frame::XModel > m_xModel;
+ uno::Reference< sheet::XNamedRanges > m_xNames;
+public:
+ /// @throws uno::RuntimeException
+ NamesEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, const uno::Reference< frame::XModel >& xModel , const uno::Reference< sheet::XNamedRanges >& xNames ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), m_xModel( xModel ), m_xNames( xNames ) {}
+
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ uno::Reference< sheet::XNamedRange > xNamed( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW );
+ return uno::Any( uno::Reference< excel::XName > ( new ScVbaName( m_xParent, m_xContext, xNamed ,m_xNames , m_xModel ) ) );
+ }
+
+};
+
+}
+
+ScVbaNames::ScVbaNames(const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::sheet::XNamedRanges >& xNames,
+ const css::uno::Reference< css::frame::XModel >& xModel ):
+ ScVbaNames_BASE( xParent , xContext , uno::Reference< container::XIndexAccess >( xNames, uno::UNO_QUERY ) ),
+ mxModel( xModel ),
+ mxNames( xNames )
+{
+ m_xNameAccess.set( xNames, uno::UNO_QUERY_THROW );
+}
+
+ScVbaNames::~ScVbaNames()
+{
+}
+
+ScDocument&
+ScVbaNames::getScDocument()
+{
+ uno::Reference< frame::XModel > xModel( getModel() , uno::UNO_SET_THROW );
+ ScTabViewShell * pTabViewShell = excel::getBestViewShell( xModel );
+ if ( !pTabViewShell )
+ throw uno::RuntimeException( "No ViewShell available" );
+ ScViewData& rViewData = pTabViewShell->GetViewData();
+ return rViewData.GetDocument();
+}
+
+css::uno::Any
+ScVbaNames::Add( const css::uno::Any& Name ,
+ const css::uno::Any& RefersTo,
+ const css::uno::Any& /*Visible*/,
+ const css::uno::Any& /*MacroType*/,
+ const css::uno::Any& /*ShoutcutKey*/,
+ const css::uno::Any& /*Category*/,
+ const css::uno::Any& NameLocal,
+ const css::uno::Any& /*RefersToLocal*/,
+ const css::uno::Any& /*CategoryLocal*/,
+ const css::uno::Any& RefersToR1C1,
+ const css::uno::Any& RefersToR1C1Local )
+{
+ OUString sName;
+ uno::Reference< excel::XRange > xRange;
+ if ( Name.hasValue() )
+ Name >>= sName;
+ else if ( NameLocal.hasValue() )
+ NameLocal >>= sName;
+ if ( !sName.isEmpty() )
+ {
+ if (ScRangeData::IsNameValid(sName, getScDocument())
+ != ScRangeData::IsNameValidType::NAME_VALID)
+ {
+ const sal_Int32 nIndex{ sName.indexOf('!') };
+ if (nIndex>=0)
+ sName = sName.copy(nIndex+1);
+ if (ScRangeData::IsNameValid(sName, getScDocument())
+ != ScRangeData::IsNameValidType::NAME_VALID)
+ throw uno::RuntimeException( "This Name is not valid ." );
+ }
+ }
+ uno::Reference< table::XCellRange > xUnoRange;
+ if ( RefersTo.hasValue() || RefersToR1C1.hasValue() || RefersToR1C1Local.hasValue() )
+ {
+ OUString sFormula;
+
+ formula::FormulaGrammar::Grammar eGram = formula::FormulaGrammar::GRAM_NATIVE_XL_A1;
+ if ( RefersTo.hasValue() )
+ {
+ if ( RefersTo.getValueTypeClass() == uno::TypeClass_STRING )
+ RefersTo >>= sFormula;
+ else
+ RefersTo >>= xRange;
+ }
+ if ( RefersToR1C1.hasValue() )
+ {
+ if ( RefersToR1C1.getValueTypeClass() == uno::TypeClass_STRING )
+ {
+ RefersToR1C1 >>= sFormula;
+ eGram = formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1;
+ }
+ else
+ RefersToR1C1 >>= xRange;
+ }
+ if ( RefersToR1C1Local.hasValue() )
+ {
+ if ( RefersToR1C1Local.getValueTypeClass() == uno::TypeClass_STRING )
+ {
+ RefersToR1C1Local >>= sFormula;
+ eGram = formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1;
+ }
+ else
+ RefersToR1C1Local >>= xRange;
+ }
+ if ( !xRange.is() && !sFormula.isEmpty() )
+ {
+ ScAddress aBlank;
+ ScCompiler aComp( getScDocument(), aBlank, eGram );
+ std::unique_ptr<ScTokenArray> pTokens(aComp.CompileString(sFormula));
+ if ( pTokens )
+ {
+ ScRange aRange;
+ ScDocShell* pDocSh = excel::getDocShell(getModel());
+ if (pTokens->IsValidReference(aRange, aBlank))
+ xUnoRange = new ScCellRangeObj( pDocSh, aRange );
+ else
+ {
+ // assume it's an address try strip the '=' if it's there
+ // and try and create a range ( must be a better way )
+ if ( sFormula.startsWith("=") )
+ sFormula = sFormula.copy(1);
+ ScRangeList aCellRanges;
+ ScRefFlags nFlags = ScRefFlags::ZERO;
+ formula::FormulaGrammar::AddressConvention eConv = ( eGram == formula::FormulaGrammar::GRAM_NATIVE_XL_A1 ) ? formula::FormulaGrammar::CONV_XL_A1 : formula::FormulaGrammar::CONV_XL_R1C1;
+ if ( ScVbaRange::getCellRangesForAddress( nFlags, sFormula, pDocSh, aCellRanges, eConv , ',' ) )
+ {
+ if ( aCellRanges.size() == 1 )
+ xUnoRange = new ScCellRangeObj( pDocSh, aCellRanges.front() );
+ else
+ {
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDocSh, aCellRanges ) );
+ xRange = new ScVbaRange( mxParent, mxContext, xRanges );
+ }
+ }
+
+ }
+ }
+ }
+ }
+
+ if ( xRange.is() || xUnoRange.is() )
+ {
+ if ( !xRange.is() )
+ xRange = new ScVbaRange( mxParent, mxContext, xUnoRange );
+
+ uno::Reference< excel::XRange > xArea( xRange->Areas( uno::Any( sal_Int32(1) ) ), uno::UNO_QUERY );
+
+ uno::Any aAny = xArea->getCellRange() ;
+
+ uno::Reference< sheet::XCellRangeAddressable > thisRangeAdd( aAny, ::uno::UNO_QUERY_THROW);
+
+ table::CellRangeAddress aAddr = thisRangeAdd->getRangeAddress();
+ uno::Any aAny2;
+ if ( mxNames.is() )
+ {
+ table::CellAddress aCellAddr( aAddr.Sheet , aAddr.StartColumn , aAddr.StartRow );
+ if ( mxNames->hasByName( sName ) )
+ mxNames->removeByName(sName);
+ OUStringBuffer sTmp = "$";
+ uno::Reference< ov::XCollection > xCol( xRange->Areas( uno::Any() ), uno::UNO_QUERY );
+ for ( sal_Int32 nArea = 1; nArea <= xCol->getCount(); ++nArea )
+ {
+ xArea.set( xRange->Areas( uno::Any( nArea ) ), uno::UNO_QUERY_THROW );
+
+ OUString sRangeAdd = xArea->Address( aAny2, aAny2 , aAny2 , aAny2, aAny2 );
+ if ( nArea > 1 )
+ sTmp.append(",");
+ sTmp.append("'" + xRange->getWorksheet()->getName() + "'." + sRangeAdd);
+ }
+ mxNames->addNewByName( sName, sTmp.makeStringAndClear(), aCellAddr, 0/*nUnoType*/);
+ return Item( uno::Any( sName ), uno::Any() );
+ }
+ }
+ return css::uno::Any();
+}
+
+// XEnumerationAccess
+css::uno::Type
+ScVbaNames::getElementType()
+{
+ return cppu::UnoType<ov::excel::XName>::get();
+}
+
+uno::Reference< container::XEnumeration >
+ScVbaNames::createEnumeration()
+{
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( mxNames, uno::UNO_QUERY_THROW );
+ return new NamesEnumeration( getParent(), mxContext, xEnumAccess->createEnumeration(), mxModel , mxNames );
+}
+
+uno::Any
+ScVbaNames::createCollectionObject( const uno::Any& aSource )
+{
+ uno::Reference< sheet::XNamedRange > xName( aSource, uno::UNO_QUERY );
+ return uno::Any( uno::Reference< excel::XName > ( new ScVbaName( getParent(), mxContext, xName, mxNames , mxModel ) ) );
+}
+
+OUString
+ScVbaNames::getServiceImplName()
+{
+ return "ScVbaNames";
+}
+
+css::uno::Sequence<OUString>
+ScVbaNames::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.NamedRanges"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbanames.hxx b/sc/source/ui/vba/vbanames.hxx
new file mode 100644
index 000000000..96f03d435
--- /dev/null
+++ b/sc/source/ui/vba/vbanames.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 <ooo/vba/excel/XNames.hpp>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace com::sun::star::sheet { class XNamedRanges; }
+
+class ScDocument;
+
+typedef CollTestImplHelper< ov::excel::XNames > ScVbaNames_BASE;
+
+class ScVbaNames final : public ScVbaNames_BASE
+{
+ css::uno::Reference< css::frame::XModel > mxModel;
+ css::uno::Reference< css::sheet::XNamedRanges > mxNames;
+
+ const css::uno::Reference< css::frame::XModel >& getModel() const { return mxModel; }
+
+public:
+ ScVbaNames( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::sheet::XNamedRanges >& xNames , const css::uno::Reference< css::frame::XModel >& xModel );
+
+ ScDocument& getScDocument();
+
+ virtual ~ScVbaNames() override;
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+
+ // Methods
+ virtual css::uno::Any SAL_CALL Add( const css::uno::Any& aName ,
+ const css::uno::Any& aRefersTo,
+ const css::uno::Any& aVisible,
+ const css::uno::Any& aMacroType,
+ const css::uno::Any& aShoutcutKey,
+ const css::uno::Any& aCategory,
+ const css::uno::Any& aNameLocal,
+ const css::uno::Any& aRefersToLocal,
+ const css::uno::Any& aCategoryLocal,
+ const css::uno::Any& aRefersToR1C1,
+ const css::uno::Any& aRefersToR1C1Local ) override;
+
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+
+ // ScVbaNames_BASE
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaoleobject.cxx b/sc/source/ui/vba/vbaoleobject.cxx
new file mode 100644
index 000000000..f2cd5de40
--- /dev/null
+++ b/sc/source/ui/vba/vbaoleobject.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 <com/sun/star/awt/XControlModel.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/lang/XMultiComponentFactory.hpp>
+#include <ooo/vba/XControlProvider.hpp>
+
+#include "vbaoleobject.hxx"
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+ScVbaOLEObject::ScVbaOLEObject( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext,
+ css::uno::Reference< css::drawing::XControlShape > const & xControlShape )
+: OLEObjectImpl_BASE( xParent, xContext )
+{
+ //init m_xWindowPeer
+ uno::Reference< awt::XControlModel > xControlModel( xControlShape->getControl(), css::uno::UNO_SET_THROW );
+ uno::Reference< container::XChild > xChild( xControlModel, uno::UNO_QUERY_THROW );
+ xChild.set( xChild->getParent(), uno::UNO_QUERY_THROW );
+ xChild.set( xChild->getParent(), uno::UNO_QUERY_THROW );
+ uno::Reference<frame::XModel> xModel( xChild->getParent(), uno::UNO_QUERY_THROW );
+ uno::Reference<lang::XMultiComponentFactory > xServiceManager( mxContext->getServiceManager(), uno::UNO_SET_THROW );
+ uno::Reference< XControlProvider > xControlProvider( xServiceManager->createInstanceWithContext("ooo.vba.ControlProvider", mxContext ), uno::UNO_QUERY_THROW );
+ m_xControl.set( xControlProvider->createControl( xControlShape, xModel ) );
+}
+
+uno::Reference< uno::XInterface > SAL_CALL
+ScVbaOLEObject::getObject()
+{
+ return uno::Reference< uno::XInterface >( m_xControl, uno::UNO_QUERY_THROW );
+}
+
+sal_Bool SAL_CALL
+ScVbaOLEObject::getEnabled()
+{
+ return m_xControl->getEnabled();
+}
+
+void SAL_CALL
+ScVbaOLEObject::setEnabled( sal_Bool _enabled )
+{
+ m_xControl->setEnabled( _enabled );
+}
+
+sal_Bool SAL_CALL
+ScVbaOLEObject::getVisible()
+{
+ return m_xControl->getVisible();
+}
+
+void SAL_CALL
+ScVbaOLEObject::setVisible( sal_Bool _visible )
+{
+ m_xControl->setVisible( _visible );
+}
+
+double SAL_CALL
+ScVbaOLEObject::getLeft()
+{
+ return m_xControl->getLeft();
+}
+
+void SAL_CALL
+ScVbaOLEObject::setLeft( double _left )
+{
+ m_xControl->setLeft( _left );
+
+}
+
+double SAL_CALL
+ScVbaOLEObject::getTop()
+{
+ return m_xControl->getTop();
+}
+
+void SAL_CALL
+ScVbaOLEObject::setTop( double _top )
+{
+ m_xControl->setTop( _top );
+}
+
+double SAL_CALL
+ScVbaOLEObject::getHeight()
+{
+ return m_xControl->getHeight();
+}
+
+void SAL_CALL
+ScVbaOLEObject::setHeight( double _height )
+{
+ m_xControl->setHeight( _height );
+}
+
+double SAL_CALL
+ScVbaOLEObject::getWidth()
+{
+ return m_xControl->getWidth();
+}
+
+void SAL_CALL
+ScVbaOLEObject::setWidth( double _width )
+{
+ m_xControl->setWidth( _width );
+}
+
+OUString SAL_CALL ScVbaOLEObject::getLinkedCell()
+{
+ return m_xControl->getControlSource();
+}
+
+void SAL_CALL ScVbaOLEObject::setLinkedCell( const OUString& _linkedcell )
+{
+ m_xControl->setControlSource( _linkedcell );
+}
+
+OUString
+ScVbaOLEObject::getServiceImplName()
+{
+ return "ScVbaOLEObject";
+}
+
+uno::Sequence< OUString >
+ScVbaOLEObject::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.OLEObject"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaoleobject.hxx b/sc/source/ui/vba/vbaoleobject.hxx
new file mode 100644
index 000000000..9eecf5fdc
--- /dev/null
+++ b/sc/source/ui/vba/vbaoleobject.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 <com/sun/star/drawing/XControlShape.hpp>
+#include <ooo/vba/excel/XOLEObject.hpp>
+#include <ooo/vba/msforms/XControl.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XOLEObject > OLEObjectImpl_BASE;
+
+class ScVbaOLEObject final : public OLEObjectImpl_BASE
+{
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+ css::uno::Reference< ov::msforms::XControl> m_xControl;
+public:
+ ScVbaOLEObject( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ css::uno::Reference< css::drawing::XControlShape > const & xControlShape );
+
+ // XOLEObject Attributes
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getObject() override;
+ virtual sal_Bool SAL_CALL getEnabled() override;
+ virtual void SAL_CALL setEnabled( sal_Bool _enabled ) override;
+ virtual sal_Bool SAL_CALL getVisible() override;
+ virtual void SAL_CALL setVisible( sal_Bool _visible ) override;
+
+ virtual double SAL_CALL getLeft() override;
+ virtual void SAL_CALL setLeft( double _left ) override;
+ virtual double SAL_CALL getTop() override;
+ virtual void SAL_CALL setTop( double _top ) override;
+ virtual double SAL_CALL getHeight() override;
+ virtual void SAL_CALL setHeight( double _height ) override;
+ virtual double SAL_CALL getWidth() override;
+ virtual void SAL_CALL setWidth( double _width ) override;
+ virtual OUString SAL_CALL getLinkedCell() override;
+ virtual void SAL_CALL setLinkedCell( const OUString& _linkedcell ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaoleobjects.cxx b/sc/source/ui/vba/vbaoleobjects.cxx
new file mode 100644
index 000000000..11a8c3934
--- /dev/null
+++ b/sc/source/ui/vba/vbaoleobjects.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 <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <ooo/vba/excel/XOLEObject.hpp>
+
+#include "vbaoleobject.hxx"
+#include "vbaoleobjects.hxx"
+#include <cppuhelper/implbase.hxx>
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+typedef ::cppu::WeakImplHelper< container::XIndexAccess > XIndexAccess_BASE;
+
+namespace {
+
+class IndexAccessWrapper : public XIndexAccess_BASE
+{
+typedef std::vector< uno::Reference< drawing::XControlShape > > OLEObjects;
+ OLEObjects vObjects;
+public:
+ explicit IndexAccessWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess )
+ {
+ sal_Int32 nLen = xIndexAccess->getCount();
+ for ( sal_Int32 index = 0; index < nLen; ++index )
+ {
+ uno::Reference< drawing::XControlShape > xControlShape( xIndexAccess->getByIndex( index), uno::UNO_QUERY);
+ if ( xControlShape.is() )
+ vObjects.push_back( xControlShape );
+ }
+ }
+
+ virtual ::sal_Int32 SAL_CALL getCount() override
+ {
+ return vObjects.size();
+ }
+
+ virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
+ {
+ if ( Index < 0 || Index >= getCount() )
+ throw lang::IndexOutOfBoundsException();
+ return uno::Any( vObjects[ Index ] );
+ }
+
+ // Methods XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override
+ {
+ return cppu::UnoType<drawing::XControlShape>::get();
+ }
+
+ virtual sal_Bool SAL_CALL hasElements() override
+ {
+ return ( getCount() > 0 );
+ }
+
+};
+
+class EnumWrapper : public EnumerationHelper_BASE
+{
+
+ uno::Reference<XHelperInterface > m_xParent;
+ uno::Reference<uno::XComponentContext > m_xContext;
+ uno::Reference<container::XIndexAccess > m_xIndexAccess;
+ sal_Int32 nIndex;
+public:
+ EnumWrapper( const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< container::XIndexAccess >& xIndexAccess )
+ : m_xParent( xParent ), m_xContext( xContext), m_xIndexAccess( xIndexAccess ), nIndex( 0 ) {}
+
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override
+ {
+ return ( nIndex < m_xIndexAccess->getCount() );
+ }
+
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ if ( nIndex < m_xIndexAccess->getCount() )
+ {
+ uno::Reference< drawing::XControlShape > xControlShape ( m_xIndexAccess->getByIndex( nIndex++ ), uno::UNO_QUERY_THROW );
+ return uno::Any( uno::Reference< ov::excel::XOLEObject >( new ScVbaOLEObject( m_xParent, m_xContext, xControlShape ) ) );
+ }
+ throw container::NoSuchElementException();
+ }
+};
+
+uno::Reference< container::XIndexAccess > oleObjectIndexWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess )
+{
+ return new IndexAccessWrapper( xIndexAccess );
+}
+
+}
+
+ScVbaOLEObjects::ScVbaOLEObjects( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess )
+ : OLEObjectsImpl_BASE( xParent, xContext, oleObjectIndexWrapper( xIndexAccess ) )
+{
+}
+uno::Reference< container::XEnumeration >
+ScVbaOLEObjects::createEnumeration()
+{
+ return new EnumWrapper( getParent(), mxContext, m_xIndexAccess );
+}
+
+uno::Any
+ScVbaOLEObjects::createCollectionObject( const css::uno::Any& aSource )
+{
+ if( aSource.hasValue() )
+ {
+ uno::Reference< drawing::XControlShape > xControlShape( aSource, uno::UNO_QUERY_THROW );
+ // parent of OLEObject is the same parent as the collection ( e.g. the sheet )
+ return uno::Any( uno::Reference< ov::excel::XOLEObject >( new ScVbaOLEObject( getParent(), mxContext, xControlShape ) ) );
+ }
+ return uno::Any();
+}
+
+uno::Any
+ScVbaOLEObjects::getItemByStringIndex( const OUString& sIndex )
+{
+ try
+ {
+ return OLEObjectsImpl_BASE::getItemByStringIndex( sIndex );
+ }
+ catch (const uno::RuntimeException&)
+ {
+ uno::Reference< container::XIndexAccess > xIndexAccess( m_xIndexAccess, uno::UNO_SET_THROW );
+ sal_Int32 nCount = xIndexAccess->getCount();
+ for( int index = 0; index < nCount; index++ )
+ {
+ uno::Any aUnoObj = xIndexAccess->getByIndex( index );
+ uno::Reference< drawing::XControlShape > xControlShape( aUnoObj, uno::UNO_QUERY_THROW );
+ uno::Reference< awt::XControlModel > xControlModel( xControlShape->getControl() );
+ uno::Reference< container::XNamed > xNamed( xControlModel, uno::UNO_QUERY_THROW );
+ if( sIndex == xNamed->getName() )
+ {
+ return createCollectionObject( aUnoObj );
+ }
+
+ }
+ return uno::Any();
+ }
+}
+
+uno::Type
+ScVbaOLEObjects::getElementType()
+{
+ return cppu::UnoType<ooo::vba::excel::XOLEObject>::get();
+}
+
+OUString
+ScVbaOLEObjects::getServiceImplName()
+{
+ return "ScVbaOLEObjects";
+}
+
+uno::Sequence< OUString >
+ScVbaOLEObjects::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.OLEObjects"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaoleobjects.hxx b/sc/source/ui/vba/vbaoleobjects.hxx
new file mode 100644
index 000000000..9d4eab048
--- /dev/null
+++ b/sc/source/ui/vba/vbaoleobjects.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 <ooo/vba/excel/XOLEObjects.hpp>
+
+#include <vbahelper/vbacollectionimpl.hxx>
+
+typedef CollTestImplHelper<ov::excel::XOLEObjects> OLEObjectsImpl_BASE;
+
+class ScVbaOLEObjects : public OLEObjectsImpl_BASE
+{
+protected:
+ virtual css::uno::Any getItemByStringIndex(const OUString& sIndex) override;
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+public:
+ ScVbaOLEObjects(const css::uno::Reference<ov::XHelperInterface>& xParent,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ const css::uno::Reference<css::container::XIndexAccess>& xIndexAccess);
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override;
+
+ // ScVbaCollectionBaseImpl
+ virtual css::uno::Any createCollectionObject(const css::uno::Any& aSource) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaoutline.cxx b/sc/source/ui/vba/vbaoutline.cxx
new file mode 100644
index 000000000..60bc12921
--- /dev/null
+++ b/sc/source/ui/vba/vbaoutline.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 "vbaoutline.hxx"
+#include <com/sun/star/sheet/XSheetOutline.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+void
+ScVbaOutline::ShowLevels( const uno::Any& RowLevels, const uno::Any& ColumnLevels )
+{
+ if (mxOutline.is())
+ {
+ sal_Int16 nLevel = 0;
+ if (RowLevels >>= nLevel)
+ {
+ mxOutline->showLevel(nLevel, table::TableOrientation_ROWS);
+ }
+ if (ColumnLevels >>= nLevel)
+ {
+ mxOutline->showLevel(nLevel,table::TableOrientation_COLUMNS);
+ }
+ }
+}
+
+OUString
+ScVbaOutline::getServiceImplName()
+{
+ return "ScVbaOutline";
+}
+
+uno::Sequence< OUString >
+ScVbaOutline::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Outline"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaoutline.hxx b/sc/source/ui/vba/vbaoutline.hxx
new file mode 100644
index 000000000..4554083e9
--- /dev/null
+++ b/sc/source/ui/vba/vbaoutline.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 <ooo/vba/excel/XOutline.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+namespace com::sun::star::sheet { class XSheetOutline; }
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XOutline > ScVbaOutline_BASE;
+
+class ScVbaOutline : public ScVbaOutline_BASE
+{
+ css::uno::Reference< css::sheet::XSheetOutline > mxOutline;
+public:
+ ScVbaOutline( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ css::uno::Reference<css::sheet::XSheetOutline> const & outline): ScVbaOutline_BASE( xParent, xContext) , mxOutline(outline)
+ {}
+
+ virtual void SAL_CALL ShowLevels( const css::uno::Any& RowLevels, const css::uno::Any& ColumnLevels ) override ;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaovalshape.cxx b/sc/source/ui/vba/vbaovalshape.cxx
new file mode 100644
index 000000000..8efc877ee
--- /dev/null
+++ b/sc/source/ui/vba/vbaovalshape.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 "vbaovalshape.hxx"
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+/*
+ * This is implemented as a new class in order to provide XTypeProvider
+ * interface. This is needed by TypeOf ... Is ... basic operator.
+ */
+
+ScVbaOvalShape::ScVbaOvalShape( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< drawing::XShape >& xShape, const uno::Reference< drawing::XShapes >& xShapes, const uno::Reference< frame::XModel >& xModel ) : OvalShapeImpl_BASE( uno::Reference< XHelperInterface >(), xContext, xShape, xShapes, xModel, ScVbaShape::getType( xShape ) )
+{}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaovalshape.hxx b/sc/source/ui/vba/vbaovalshape.hxx
new file mode 100644
index 000000000..1155cd1fc
--- /dev/null
+++ b/sc/source/ui/vba/vbaovalshape.hxx
@@ -0,0 +1,34 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#pragma once
+
+#include <ooo/vba/msforms/XOval.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <vbahelper/vbashape.hxx>
+
+typedef cppu::ImplInheritanceHelper< ScVbaShape, ov::msforms::XOval > OvalShapeImpl_BASE;
+
+class ScVbaOvalShape : public OvalShapeImpl_BASE
+{
+public:
+ ScVbaOvalShape( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::drawing::XShapes >& xShapes, const css::uno::Reference< css::frame::XModel >& xModel );
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapagebreak.cxx b/sc/source/ui/vba/vbapagebreak.cxx
new file mode 100644
index 000000000..3d9269c72
--- /dev/null
+++ b/sc/source/ui/vba/vbapagebreak.cxx
@@ -0,0 +1,142 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "vbapagebreak.hxx"
+#include "vbarange.hxx"
+#include <basic/sberrors.hxx>
+#include <ooo/vba/excel/XlPageBreak.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+template< typename... Ifc >
+ScVbaPageBreak< Ifc... >::ScVbaPageBreak( const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< beans::XPropertySet >& xProps,
+ sheet::TablePageBreakData aTablePageBreakData):
+ ScVbaPageBreak_BASE( xParent, xContext ),
+ mxRowColPropertySet( xProps ),
+ maTablePageBreakData( aTablePageBreakData )
+{
+}
+
+template< typename... Ifc >
+sal_Int32 ScVbaPageBreak< Ifc... >::getType()
+{
+ uno::Any aValue = mxRowColPropertySet->getPropertyValue("IsStartOfNewPage");
+ bool hasPageBreak = false;
+ aValue >>= hasPageBreak;
+
+ if( !hasPageBreak )
+ return excel::XlPageBreak::xlPageBreakNone;
+
+ if( maTablePageBreakData.ManualBreak )
+ return excel::XlPageBreak::xlPageBreakManual;
+
+ return excel::XlPageBreak::xlPageBreakAutomatic;
+}
+
+template< typename... Ifc >
+void ScVbaPageBreak< Ifc... >::setType(sal_Int32 type)
+{
+ if( (type != excel::XlPageBreak::xlPageBreakNone) &&
+ (type != excel::XlPageBreak::xlPageBreakManual) &&
+ (type != excel::XlPageBreak::xlPageBreakAutomatic) )
+ {
+ DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER);
+ }
+
+ if( type == excel::XlPageBreak::xlPageBreakNone )
+ {
+ mxRowColPropertySet->setPropertyValue("IsStartOfNewPage", uno::Any(false));
+ return;
+ }
+
+ mxRowColPropertySet->setPropertyValue("IsStartOfNewPage", uno::Any(true));
+ if( type == excel::XlPageBreak::xlPageBreakManual )
+ maTablePageBreakData.ManualBreak = true;
+ else
+ maTablePageBreakData.ManualBreak = false;
+}
+
+template< typename... Ifc >
+void ScVbaPageBreak< Ifc... >::Delete()
+{
+ mxRowColPropertySet->setPropertyValue("IsStartOfNewPage", uno::Any(false));
+}
+
+template< typename... Ifc >
+uno::Reference< excel::XRange> ScVbaPageBreak< Ifc... >::Location()
+{
+ uno::Reference< table::XCellRange > xRange( mxRowColPropertySet, uno::UNO_QUERY_THROW );
+ return new ScVbaRange( ScVbaPageBreak_BASE::getParent(), ScVbaPageBreak_BASE::mxContext, xRange);
+}
+
+template class ScVbaPageBreak< excel::XHPageBreak >;
+
+/* class ScVbaHPageBreak */
+OUString
+ScVbaHPageBreak::getServiceImplName()
+{
+ return "ScVbaHPageBreak";
+}
+
+uno::Sequence< OUString >
+ScVbaHPageBreak::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.HPageBreak"
+ };
+ return aServiceNames;
+}
+
+template class ScVbaPageBreak< excel::XVPageBreak >;
+
+/* class ScVbaVPageBreak */
+ScVbaVPageBreak::ScVbaVPageBreak( const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::beans::XPropertySet >& xProps,
+ css::sheet::TablePageBreakData aTablePageBreakData )
+: ScVbaVPageBreak_BASE( xParent, xContext, xProps, aTablePageBreakData )
+{
+}
+
+ScVbaVPageBreak::~ScVbaVPageBreak()
+{
+}
+
+OUString
+ScVbaVPageBreak::getServiceImplName()
+{
+ return "ScVbaVPageBreak";
+}
+
+uno::Sequence< OUString >
+ScVbaVPageBreak::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.VPageBreak"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapagebreak.hxx b/sc/source/ui/vba/vbapagebreak.hxx
new file mode 100644
index 000000000..537258923
--- /dev/null
+++ b/sc/source/ui/vba/vbapagebreak.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 <ooo/vba/excel/XHPageBreak.hpp>
+#include <ooo/vba/excel/XVPageBreak.hpp>
+#include <com/sun/star/sheet/TablePageBreakData.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+
+namespace com::sun::star::beans { class XPropertySet; }
+namespace com::sun::star::uno { class XComponentContext; }
+namespace ooo::vba::excel { class XRange; }
+
+template< typename... Ifc >
+class ScVbaPageBreak : public InheritedHelperInterfaceWeakImpl< Ifc... >
+{
+typedef InheritedHelperInterfaceWeakImpl< Ifc... > ScVbaPageBreak_BASE;
+protected:
+ css::uno::Reference< css::beans::XPropertySet > mxRowColPropertySet;
+ css::sheet::TablePageBreakData maTablePageBreakData;
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaPageBreak( const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::beans::XPropertySet >& xProps,
+ css::sheet::TablePageBreakData aTablePageBreakData);
+
+ virtual sal_Int32 SAL_CALL getType( ) override;
+ virtual void SAL_CALL setType(sal_Int32 type) override;
+
+ virtual void SAL_CALL Delete() override;
+ virtual css::uno::Reference< ov::excel::XRange> SAL_CALL Location() override;
+};
+
+typedef ScVbaPageBreak < ov::excel::XHPageBreak > ScVbaHPageBreak_BASE;
+
+class ScVbaHPageBreak : public ScVbaHPageBreak_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaHPageBreak( const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::beans::XPropertySet >& xProps,
+ css::sheet::TablePageBreakData aTablePageBreakData):
+ ScVbaHPageBreak_BASE( xParent,xContext,xProps,aTablePageBreakData ){}
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+//VPageBreak
+typedef ScVbaPageBreak < ov::excel::XVPageBreak > ScVbaVPageBreak_BASE;
+
+class ScVbaVPageBreak : public ScVbaVPageBreak_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaVPageBreak( const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::beans::XPropertySet >& xProps,
+ css::sheet::TablePageBreakData aTablePageBreakData);
+
+ virtual ~ScVbaVPageBreak() override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapagebreaks.cxx b/sc/source/ui/vba/vbapagebreaks.cxx
new file mode 100644
index 000000000..36d9f5c7f
--- /dev/null
+++ b/sc/source/ui/vba/vbapagebreaks.cxx
@@ -0,0 +1,322 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "vbapagebreaks.hxx"
+#include "vbapagebreak.hxx"
+#include <basic/sberrors.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <ooo/vba/excel/XWorksheet.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sheet/XSheetPageBreak.hpp>
+#include <com/sun/star/table/XColumnRowRange.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+namespace {
+
+class RangePageBreaks : public ::cppu::WeakImplHelper<container::XIndexAccess >
+{
+private:
+ uno::Reference< XHelperInterface > mxParent;
+ uno::Reference< uno::XComponentContext > mxContext;
+ uno::Reference< sheet::XSheetPageBreak > mxSheetPageBreak;
+ bool m_bColumn;
+
+public:
+ RangePageBreaks( const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< sheet::XSheetPageBreak >& xSheetPageBreak,
+ bool bColumn ) : mxParent( xParent ), mxContext( xContext ), mxSheetPageBreak( xSheetPageBreak ), m_bColumn( bColumn )
+ {
+ }
+
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getAPIStartofRange( const uno::Reference< excel::XRange >& xRange )
+ {
+ if( m_bColumn )
+ return xRange->getColumn() - 1;
+ return xRange->getRow() - 1;
+ }
+
+ /// @throws uno::RuntimeException
+ sal_Int32 getAPIEndIndexofRange( const uno::Reference< excel::XRange >& xRange, sal_Int32 nUsedStart )
+ {
+ if( m_bColumn )
+ return nUsedStart + xRange->Columns( uno::Any() )->getCount() - 1;
+ return nUsedStart + xRange->Rows( uno::Any() )->getCount();
+ }
+
+ /// @throws uno::RuntimeException
+ uno::Sequence<sheet::TablePageBreakData> getAllPageBreaks()
+ {
+ if( m_bColumn )
+ return mxSheetPageBreak->getColumnPageBreaks();
+ return mxSheetPageBreak->getRowPageBreaks();
+ }
+
+ /// @throws uno::RuntimeException
+ uno::Reference<container::XIndexAccess> getRowColContainer() const
+ {
+ uno::Reference< table::XColumnRowRange > xColumnRowRange( mxSheetPageBreak, uno::UNO_QUERY_THROW );
+ uno::Reference<container::XIndexAccess> xIndexAccess;
+ if( m_bColumn )
+ xIndexAccess.set( xColumnRowRange->getColumns(), uno::UNO_QUERY_THROW );
+ else
+ xIndexAccess.set( xColumnRowRange->getRows(), uno::UNO_QUERY_THROW );
+ return xIndexAccess;
+ }
+
+ /// @throws uno::RuntimeException
+ sheet::TablePageBreakData getTablePageBreakData( sal_Int32 nAPIItemIndex );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ uno::Any Add( const css::uno::Any& Before );
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override;
+ virtual uno::Any SAL_CALL getByIndex( sal_Int32 Index ) override;
+ virtual uno::Type SAL_CALL getElementType( ) override
+ {
+ if( m_bColumn )
+ return cppu::UnoType<excel::XVPageBreak>::get();
+ return cppu::UnoType<excel::XHPageBreak>::get();
+ }
+ virtual sal_Bool SAL_CALL hasElements( ) override
+ {
+ return true;
+ }
+};
+
+}
+
+/** @TODO Unlike MS Excel this method only considers the pagebreaks that intersect the used range
+* To become completely compatible the print area has to be considered. As far as I found out this printarea
+* also considers the position and sizes of shapes and manually inserted page breaks
+* Note: In MS there is a limit of 1026 horizontal page breaks per sheet.
+*/
+sal_Int32 SAL_CALL RangePageBreaks::getCount( )
+{
+ uno::Reference< excel::XWorksheet > xWorksheet( mxParent, uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XRange > xRange = xWorksheet->getUsedRange();
+ sal_Int32 nUsedStart = getAPIStartofRange( xRange );
+ sal_Int32 nUsedEnd = getAPIEndIndexofRange( xRange, nUsedStart );
+ const uno::Sequence<sheet::TablePageBreakData> aTablePageBreakData = getAllPageBreaks();
+
+ auto pPageBreak = std::find_if(aTablePageBreakData.begin(), aTablePageBreakData.end(),
+ [nUsedEnd](const sheet::TablePageBreakData& rPageBreak) { return rPageBreak.Position > nUsedEnd + 1; });
+
+ return static_cast<sal_Int32>(std::distance(aTablePageBreakData.begin(), pPageBreak));
+}
+
+uno::Any SAL_CALL RangePageBreaks::getByIndex( sal_Int32 Index )
+{
+ if( (Index < getCount()) && ( Index >= 0 ))
+ {
+ sheet::TablePageBreakData aTablePageBreakData = getTablePageBreakData( Index );
+ uno::Reference< container::XIndexAccess > xIndexAccess = getRowColContainer();
+ sal_Int32 nPos = aTablePageBreakData.Position;
+ if( (nPos < xIndexAccess->getCount()) && (nPos > -1) )
+ {
+ uno::Reference< beans::XPropertySet > xRowColPropertySet( xIndexAccess->getByIndex(nPos), uno::UNO_QUERY_THROW );
+ if( m_bColumn )
+ return uno::Any( uno::Reference< excel::XVPageBreak >( new ScVbaVPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) ));
+ return uno::Any( uno::Reference< excel::XHPageBreak >( new ScVbaHPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) ));
+ }
+ }
+ throw lang::IndexOutOfBoundsException();
+}
+
+sheet::TablePageBreakData RangePageBreaks::getTablePageBreakData( sal_Int32 nAPIItemIndex )
+{
+ sal_Int32 index = -1;
+ sheet::TablePageBreakData aTablePageBreakData;
+ uno::Reference< excel::XWorksheet > xWorksheet( mxParent, uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XRange > xRange = xWorksheet->getUsedRange();
+ sal_Int32 nUsedStart = getAPIStartofRange( xRange );
+ sal_Int32 nUsedEnd = getAPIEndIndexofRange( xRange, nUsedStart );
+ const uno::Sequence<sheet::TablePageBreakData> aTablePageBreakDataList = getAllPageBreaks();
+
+ for( const auto& rTablePageBreakData : aTablePageBreakDataList )
+ {
+ aTablePageBreakData = rTablePageBreakData;
+ sal_Int32 nPos = aTablePageBreakData.Position;
+ if( nPos > nUsedEnd + 1 )
+ DebugHelper::runtimeexception(ERRCODE_BASIC_METHOD_FAILED);
+ index++;
+ if( index == nAPIItemIndex )
+ return aTablePageBreakData;
+ }
+
+ return aTablePageBreakData;
+}
+
+uno::Any RangePageBreaks::Add( const css::uno::Any& Before )
+{
+ uno::Reference< excel::XRange > xRange;
+ Before >>= xRange;
+ if( !xRange.is() )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_BAD_ARGUMENT, {});
+ }
+
+ sal_Int32 nAPIRowColIndex = getAPIStartofRange( xRange );
+ uno::Reference< container::XIndexAccess > xIndexAccess = getRowColContainer();
+ uno::Reference< beans::XPropertySet > xRowColPropertySet( xIndexAccess->getByIndex(nAPIRowColIndex), uno::UNO_QUERY_THROW );
+ xRowColPropertySet->setPropertyValue("IsStartOfNewPage", uno::Any(true));
+ sheet::TablePageBreakData aTablePageBreakData;
+ aTablePageBreakData.ManualBreak = true;
+ aTablePageBreakData.Position = nAPIRowColIndex;
+ if( m_bColumn )
+ return uno::Any( uno::Reference< excel::XVPageBreak >( new ScVbaVPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) ));
+ return uno::Any( uno::Reference< excel::XHPageBreak >( new ScVbaHPageBreak( mxParent, mxContext, xRowColPropertySet, aTablePageBreakData) ));
+}
+
+namespace {
+
+class RangePageBreaksEnumWrapper : public EnumerationHelper_BASE
+{
+ uno::Reference<container::XIndexAccess > m_xIndexAccess;
+ sal_Int32 nIndex;
+public:
+ explicit RangePageBreaksEnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess ) : m_xIndexAccess( xIndexAccess ), nIndex( 0 ) {}
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override
+ {
+ return ( nIndex < m_xIndexAccess->getCount() );
+ }
+
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ if ( nIndex < m_xIndexAccess->getCount() )
+ return m_xIndexAccess->getByIndex( nIndex++ );
+ throw container::NoSuchElementException();
+ }
+};
+
+}
+
+ScVbaHPageBreaks::ScVbaHPageBreaks( const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< sheet::XSheetPageBreak >& xSheetPageBreak):
+ ScVbaHPageBreaks_BASE( xParent,xContext, new RangePageBreaks( xParent, xContext, xSheetPageBreak, false ))
+{
+}
+
+uno::Any SAL_CALL ScVbaHPageBreaks::Add( const uno::Any& Before)
+{
+ RangePageBreaks* pPageBreaks = dynamic_cast< RangePageBreaks* >( m_xIndexAccess.get() );
+ if( pPageBreaks )
+ {
+ return pPageBreaks->Add( Before );
+ }
+ return uno::Any();
+}
+
+uno::Reference< container::XEnumeration >
+ScVbaHPageBreaks::createEnumeration()
+{
+ return new RangePageBreaksEnumWrapper( m_xIndexAccess );
+}
+
+uno::Any
+ScVbaHPageBreaks::createCollectionObject( const css::uno::Any& aSource )
+{
+ return aSource; // it's already a pagebreak object
+}
+
+uno::Type
+ScVbaHPageBreaks::getElementType()
+{
+ return cppu::UnoType<excel::XHPageBreak>::get();
+}
+
+OUString
+ScVbaHPageBreaks::getServiceImplName()
+{
+ return "ScVbaHPageBreaks";
+}
+
+uno::Sequence< OUString >
+ScVbaHPageBreaks::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.HPageBreaks"
+ };
+ return aServiceNames;
+}
+
+//VPageBreak
+ScVbaVPageBreaks::ScVbaVPageBreaks( const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< sheet::XSheetPageBreak >& xSheetPageBreak )
+: ScVbaVPageBreaks_BASE( xParent, xContext, new RangePageBreaks( xParent, xContext, xSheetPageBreak, true ) )
+{
+}
+
+ScVbaVPageBreaks::~ScVbaVPageBreaks()
+{
+}
+
+uno::Any SAL_CALL
+ScVbaVPageBreaks::Add( const uno::Any& Before )
+{
+ RangePageBreaks* pPageBreaks = dynamic_cast< RangePageBreaks* >( m_xIndexAccess.get() );
+ if( pPageBreaks )
+ {
+ return pPageBreaks->Add( Before );
+ }
+ return uno::Any();
+}
+
+uno::Reference< container::XEnumeration >
+ScVbaVPageBreaks::createEnumeration()
+{
+ return new RangePageBreaksEnumWrapper( m_xIndexAccess );
+}
+
+uno::Any
+ScVbaVPageBreaks::createCollectionObject( const css::uno::Any& aSource )
+{
+ return aSource; // it's already a pagebreak object
+}
+
+uno::Type
+ScVbaVPageBreaks::getElementType()
+{
+ return cppu::UnoType<excel::XVPageBreak>::get();
+}
+
+OUString
+ScVbaVPageBreaks::getServiceImplName()
+{
+ return "ScVbaVPageBreaks";
+}
+
+uno::Sequence< OUString >
+ScVbaVPageBreaks::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.VPageBreaks"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapagebreaks.hxx b/sc/source/ui/vba/vbapagebreaks.hxx
new file mode 100644
index 000000000..a04f94145
--- /dev/null
+++ b/sc/source/ui/vba/vbapagebreaks.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 <ooo/vba/excel/XHPageBreaks.hpp>
+#include <ooo/vba/excel/XVPageBreaks.hpp>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace com::sun::star::sheet
+{
+class XSheetPageBreak;
+}
+namespace com::sun::star::uno
+{
+class XComponentContext;
+}
+
+typedef CollTestImplHelper<ov::excel::XHPageBreaks> ScVbaHPageBreaks_BASE;
+
+class ScVbaHPageBreaks : public ScVbaHPageBreaks_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaHPageBreaks(const css::uno::Reference<ov::XHelperInterface>& xParent,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ const css::uno::Reference<css::sheet::XSheetPageBreak>& xSheetPageBreak);
+
+ // XHPageBreaks
+ virtual css::uno::Any SAL_CALL Add(const css::uno::Any& Before) override;
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override;
+ virtual css::uno::Any createCollectionObject(const css::uno::Any&) override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+//VPageBreaks
+typedef CollTestImplHelper<ov::excel::XVPageBreaks> ScVbaVPageBreaks_BASE;
+
+class ScVbaVPageBreaks : public ScVbaVPageBreaks_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaVPageBreaks(const css::uno::Reference<ov::XHelperInterface>& xParent,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ const css::uno::Reference<css::sheet::XSheetPageBreak>& xSheetPageBreak);
+
+ virtual ~ScVbaVPageBreaks() override;
+
+ // XVPageBreaks
+ virtual css::uno::Any SAL_CALL Add(const css::uno::Any& Before) override;
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference<css::container::XEnumeration> SAL_CALL createEnumeration() override;
+ virtual css::uno::Any createCollectionObject(const css::uno::Any&) override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapagesetup.cxx b/sc/source/ui/vba/vbapagesetup.cxx
new file mode 100644
index 000000000..7b7b23d16
--- /dev/null
+++ b/sc/source/ui/vba/vbapagesetup.cxx
@@ -0,0 +1,631 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "vbapagesetup.hxx"
+#include <convuno.hxx>
+#include <rangelst.hxx>
+#include <docsh.hxx>
+#include "excelvbahelper.hxx"
+#include "vbarange.hxx"
+#include <com/sun/star/sheet/XPrintAreas.hpp>
+#include <com/sun/star/sheet/XHeaderFooterContent.hpp>
+#include <com/sun/star/text/XText.hpp>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <ooo/vba/excel/XlPageOrientation.hpp>
+#include <ooo/vba/excel/XlOrder.hpp>
+#include <ooo/vba/excel/Constants.hpp>
+#include <ooo/vba/excel/XlPaperSize.hpp>
+#include <basic/sberrors.hxx>
+#include <filter/msfilter/util.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+#define ZOOM_IN 10
+#define ZOOM_MAX 400
+
+ScVbaPageSetup::ScVbaPageSetup(const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< sheet::XSpreadsheet >& xSheet,
+ const uno::Reference< frame::XModel >& xModel):
+ ScVbaPageSetup_BASE( xParent, xContext ), mxSheet( xSheet ), mbIsLandscape( false )
+{
+ // query for current page style
+ mxModel.set( xModel, uno::UNO_SET_THROW );
+ uno::Reference< beans::XPropertySet > xSheetProps( mxSheet, uno::UNO_QUERY_THROW );
+ uno::Any aValue = xSheetProps->getPropertyValue("PageStyle");
+ OUString aStyleName;
+ aValue >>= aStyleName;
+
+ uno::Reference< style::XStyleFamiliesSupplier > xStyleFamiliesSup( mxModel, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xStyleFamilies = xStyleFamiliesSup->getStyleFamilies();
+ uno::Reference< container::XNameAccess > xPageStyle( xStyleFamilies->getByName("PageStyles"), uno::UNO_QUERY_THROW );
+ mxPageProps.set( xPageStyle->getByName(aStyleName), uno::UNO_QUERY_THROW );
+ mnOrientLandscape = excel::XlPageOrientation::xlLandscape;
+ mnOrientPortrait = excel::XlPageOrientation::xlPortrait;
+ mxPageProps->getPropertyValue("IsLandscape") >>= mbIsLandscape;
+}
+
+OUString SAL_CALL ScVbaPageSetup::getPrintArea()
+{
+ OUString aPrintArea;
+ uno::Reference< sheet::XPrintAreas > xPrintAreas( mxSheet, uno::UNO_QUERY_THROW );
+ const uno::Sequence< table::CellRangeAddress > aSeq = xPrintAreas->getPrintAreas();
+ if( aSeq.hasElements() )
+ {
+ ScRangeList aRangeList;
+ for( const auto& rRange : aSeq )
+ {
+ ScRange aRange;
+ ScUnoConversion::FillScRange( aRange, rRange );
+ aRangeList.push_back( aRange );
+ }
+ ScDocument& rDoc = excel::getDocShell( mxModel )->GetDocument();
+ aRangeList.Format( aPrintArea, ScRefFlags::RANGE_ABS, rDoc, formula::FormulaGrammar::CONV_XL_A1, ',' );
+ }
+
+ return aPrintArea;
+}
+
+void SAL_CALL ScVbaPageSetup::setPrintArea( const OUString& rAreas )
+{
+ uno::Reference< sheet::XPrintAreas > xPrintAreas( mxSheet, uno::UNO_QUERY_THROW );
+ if( rAreas.isEmpty() ||
+ rAreas.equalsIgnoreAsciiCase( "FALSE" ) )
+ {
+ // print the whole sheet
+ uno::Sequence< table::CellRangeAddress > aSeq;
+ xPrintAreas->setPrintAreas( aSeq );
+ }
+ else
+ {
+ ScRangeList aCellRanges;
+ ScRange aRange;
+ if( getScRangeListForAddress( rAreas, excel::getDocShell( mxModel ) , aRange, aCellRanges ) )
+ {
+ uno::Sequence< table::CellRangeAddress > aSeq( aCellRanges.size() );
+ auto aSeqRange = asNonConstRange(aSeq);
+ for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i )
+ {
+ ScRange & rRange = aCellRanges[ i ];
+ table::CellRangeAddress aRangeAddress;
+ ScUnoConversion::FillApiRange( aRangeAddress, rRange );
+ aSeqRange[ i++ ] = aRangeAddress;
+ }
+ xPrintAreas->setPrintAreas( aSeq );
+ }
+ }
+}
+
+double SAL_CALL ScVbaPageSetup::getHeaderMargin()
+{
+ return VbaPageSetupBase::getHeaderMargin();
+}
+
+void SAL_CALL ScVbaPageSetup::setHeaderMargin( double margin )
+{
+ VbaPageSetupBase::setHeaderMargin( margin );
+}
+
+double SAL_CALL ScVbaPageSetup::getFooterMargin()
+{
+ return VbaPageSetupBase::getFooterMargin();
+}
+
+void SAL_CALL ScVbaPageSetup::setFooterMargin( double margin )
+{
+ VbaPageSetupBase::setFooterMargin( margin );
+}
+
+uno::Any SAL_CALL ScVbaPageSetup::getFitToPagesTall()
+{
+ return mxPageProps->getPropertyValue("ScaleToPagesY");
+}
+
+void SAL_CALL ScVbaPageSetup::setFitToPagesTall( const uno::Any& fitToPagesTall)
+{
+ try
+ {
+ sal_uInt16 scaleToPageY = 0;
+ bool aValue;
+ if( fitToPagesTall.getValueTypeClass() != uno::TypeClass_BOOLEAN || (fitToPagesTall >>= aValue))
+ {
+ fitToPagesTall >>= scaleToPageY;
+ }
+
+ mxPageProps->setPropertyValue("ScaleToPagesY", uno::Any( scaleToPageY ));
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+uno::Any SAL_CALL ScVbaPageSetup::getFitToPagesWide()
+{
+ return mxPageProps->getPropertyValue("ScaleToPagesX");
+}
+
+void SAL_CALL ScVbaPageSetup::setFitToPagesWide( const uno::Any& fitToPagesWide)
+{
+ try
+ {
+ sal_uInt16 scaleToPageX = 0;
+ bool aValue = false;
+ if( fitToPagesWide.getValueTypeClass() != uno::TypeClass_BOOLEAN || (fitToPagesWide >>= aValue))
+ {
+ fitToPagesWide >>= scaleToPageX;
+ }
+
+ mxPageProps->setPropertyValue("ScaleToPagesX", uno::Any( scaleToPageX ));
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+uno::Any SAL_CALL ScVbaPageSetup::getZoom()
+{
+ return mxPageProps->getPropertyValue("PageScale");
+}
+
+void SAL_CALL ScVbaPageSetup::setZoom( const uno::Any& zoom)
+{
+ sal_uInt16 pageScale = 0;
+ try
+ {
+ if( zoom.getValueTypeClass() == uno::TypeClass_BOOLEAN )
+ {
+ bool aValue = false;
+ zoom >>= aValue;
+ if( aValue )
+ {
+ DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER);
+ }
+ }
+ else
+ {
+ zoom >>= pageScale;
+ if(( pageScale < ZOOM_IN )||( pageScale > ZOOM_MAX ))
+ {
+ DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER);
+ }
+ }
+
+ // these only exist in S08
+ sal_uInt16 nScale = 0;
+ mxPageProps->setPropertyValue("ScaleToPages", uno::Any( nScale ));
+ mxPageProps->setPropertyValue("ScaleToPagesX", uno::Any( nScale ));
+ mxPageProps->setPropertyValue("ScaleToPagesY", uno::Any( nScale ));
+ }
+ catch (const beans::UnknownPropertyException&)
+ {
+ if( pageScale == 0 )
+ {
+ DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER);
+ }
+ }
+ catch (const uno::Exception&)
+ {
+ }
+
+ mxPageProps->setPropertyValue("PageScale", uno::Any( pageScale ));
+}
+
+OUString SAL_CALL ScVbaPageSetup::getLeftHeader()
+{
+ OUString leftHeader;
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xHeaderContent->getLeftText();
+ leftHeader = xText->getString();
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ return leftHeader;
+}
+
+void SAL_CALL ScVbaPageSetup::setLeftHeader( const OUString& leftHeader)
+{
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xHeaderContent->getLeftText();
+ xText->setString( leftHeader );
+ mxPageProps->setPropertyValue("RightPageHeaderContent", uno::Any(xHeaderContent) );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+OUString SAL_CALL ScVbaPageSetup::getCenterHeader()
+{
+ OUString centerHeader;
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xHeaderContent->getCenterText();
+ centerHeader = xText->getString();
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ return centerHeader;
+}
+
+void SAL_CALL ScVbaPageSetup::setCenterHeader( const OUString& centerHeader)
+{
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xHeaderContent->getCenterText();
+ xText->setString( centerHeader );
+ mxPageProps->setPropertyValue("RightPageHeaderContent", uno::Any(xHeaderContent) );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+OUString SAL_CALL ScVbaPageSetup::getRightHeader()
+{
+ OUString rightHeader;
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xHeaderContent->getRightText();
+ rightHeader = xText->getString();
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ return rightHeader;
+}
+
+void SAL_CALL ScVbaPageSetup::setRightHeader( const OUString& rightHeader)
+{
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xHeaderContent( mxPageProps->getPropertyValue("RightPageHeaderContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xHeaderContent->getRightText();
+ xText->setString( rightHeader );
+ mxPageProps->setPropertyValue("RightPageHeaderContent", uno::Any(xHeaderContent) );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+OUString SAL_CALL ScVbaPageSetup::getLeftFooter()
+{
+ OUString leftFooter;
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xFooterContent->getLeftText();
+ leftFooter = xText->getString();
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ return leftFooter;
+}
+
+void SAL_CALL ScVbaPageSetup::setLeftFooter( const OUString& leftFooter)
+{
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xFooterContent->getLeftText();
+ xText->setString( leftFooter );
+ mxPageProps->setPropertyValue("RightPageFooterContent", uno::Any(xFooterContent) );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+OUString SAL_CALL ScVbaPageSetup::getCenterFooter()
+{
+ OUString centerFooter;
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xFooterContent->getCenterText();
+ centerFooter = xText->getString();
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ return centerFooter;
+}
+
+void SAL_CALL ScVbaPageSetup::setCenterFooter( const OUString& centerFooter)
+{
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xFooterContent->getCenterText();
+ xText->setString( centerFooter );
+ mxPageProps->setPropertyValue("RightPageFooterContent", uno::Any(xFooterContent) );
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+}
+
+OUString SAL_CALL ScVbaPageSetup::getRightFooter()
+{
+ OUString rightFooter;
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xFooterContent->getRightText();
+ rightFooter = xText->getString();
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ return rightFooter;
+}
+
+void SAL_CALL ScVbaPageSetup::setRightFooter( const OUString& rightFooter)
+{
+ try
+ {
+ uno::Reference<sheet::XHeaderFooterContent> xFooterContent( mxPageProps->getPropertyValue("RightPageFooterContent"), uno::UNO_QUERY_THROW);
+ uno::Reference< text::XText > xText = xFooterContent->getRightText();
+ xText->setString( rightFooter );
+ mxPageProps->setPropertyValue("RightPageFooterContent", uno::Any(xFooterContent) );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+sal_Int32 SAL_CALL ScVbaPageSetup::getOrder()
+{
+ sal_Int32 order = excel::XlOrder::xlDownThenOver;
+ try
+ {
+ uno::Any aValue = mxPageProps->getPropertyValue("PrintDownFirst");
+ bool bPrintDownFirst = false;
+ aValue >>= bPrintDownFirst;
+ if( !bPrintDownFirst )
+ order = excel::XlOrder::xlOverThenDown;
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ return order;
+}
+
+void SAL_CALL ScVbaPageSetup::setOrder(sal_Int32 order)
+{
+ bool bOrder = true;
+ switch( order )
+ {
+ case excel::XlOrder::xlDownThenOver:
+ break;
+ case excel::XlOrder::xlOverThenDown:
+ bOrder = false;
+ break;
+ default:
+ DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER);
+ }
+
+ try
+ {
+ mxPageProps->setPropertyValue("PrintDownFirst", uno::Any( bOrder ));
+ }
+ catch (const uno::Exception&)
+ {
+ }
+}
+
+sal_Int32 SAL_CALL ScVbaPageSetup::getFirstPageNumber()
+{
+ sal_Int16 number = 0;
+ try
+ {
+ uno::Any aValue = mxPageProps->getPropertyValue("FirstPageNumber");
+ aValue >>= number;
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ if( number ==0 )
+ {
+ number = excel::Constants::xlAutomatic;
+ }
+
+ return number;
+}
+
+void SAL_CALL ScVbaPageSetup::setFirstPageNumber( sal_Int32 firstPageNumber)
+{
+ if( firstPageNumber == excel::Constants::xlAutomatic )
+ firstPageNumber = 0;
+
+ try
+ {
+ uno::Any aValue;
+ aValue <<= static_cast<sal_Int16>(firstPageNumber);
+ mxPageProps->setPropertyValue("FirstPageNumber", aValue );
+ }
+ catch (const uno::Exception&)
+ {
+ }
+}
+
+sal_Bool SAL_CALL ScVbaPageSetup::getCenterVertically()
+{
+ bool centerVertically = false;
+ try
+ {
+ uno::Any aValue = mxPageProps->getPropertyValue("CenterVertically");
+ aValue >>= centerVertically;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ return centerVertically;
+}
+
+void SAL_CALL ScVbaPageSetup::setCenterVertically( sal_Bool centerVertically)
+{
+ try
+ {
+ mxPageProps->setPropertyValue("CenterVertically", uno::Any( centerVertically ));
+ }
+ catch (const uno::Exception&)
+ {
+ }
+}
+
+sal_Bool SAL_CALL ScVbaPageSetup::getCenterHorizontally()
+{
+ bool centerHorizontally = false;
+ try
+ {
+ uno::Any aValue = mxPageProps->getPropertyValue("CenterHorizontally");
+ aValue >>= centerHorizontally;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ return centerHorizontally;
+}
+
+void SAL_CALL ScVbaPageSetup::setCenterHorizontally( sal_Bool centerHorizontally)
+{
+ try
+ {
+ mxPageProps->setPropertyValue("CenterHorizontally", uno::Any( centerHorizontally ));
+ }
+ catch (const uno::Exception&)
+ {
+ }
+}
+
+sal_Bool SAL_CALL ScVbaPageSetup::getPrintHeadings()
+{
+ bool printHeadings = false;
+ try
+ {
+ uno::Any aValue = mxPageProps->getPropertyValue("PrintHeaders");
+ aValue >>= printHeadings;
+ }
+ catch (const uno::Exception&)
+ {
+ }
+ return printHeadings;
+}
+
+void SAL_CALL ScVbaPageSetup::setPrintHeadings( sal_Bool printHeadings)
+{
+ try
+ {
+ mxPageProps->setPropertyValue("PrintHeaders", uno::Any( printHeadings ));
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+sal_Bool SAL_CALL ScVbaPageSetup::getPrintGridlines()
+{
+ return false;
+}
+
+void SAL_CALL ScVbaPageSetup::setPrintGridlines( sal_Bool /*_printgridlines*/ )
+{
+}
+
+OUString SAL_CALL ScVbaPageSetup::getPrintTitleRows()
+{
+ return OUString();
+}
+void SAL_CALL ScVbaPageSetup::setPrintTitleRows( const OUString& /*_printtitlerows*/ )
+{
+}
+OUString SAL_CALL ScVbaPageSetup::getPrintTitleColumns()
+{
+ return OUString();
+}
+
+void SAL_CALL ScVbaPageSetup::setPrintTitleColumns( const OUString& /*_printtitlecolumns*/ )
+{
+}
+
+sal_Int32 SAL_CALL ScVbaPageSetup::getPaperSize()
+{
+ awt::Size aSize; // current papersize
+ mxPageProps->getPropertyValue( "Size" ) >>= aSize;
+ if ( mbIsLandscape )
+ ::std::swap( aSize.Width, aSize.Height );
+
+ sal_Int32 nPaperSizeIndex = msfilter::util::PaperSizeConv::getMSPaperSizeIndex( aSize );
+ if ( nPaperSizeIndex == 0 )
+ nPaperSizeIndex = excel::XlPaperSize::xlPaperUser;
+ return nPaperSizeIndex;
+}
+
+void SAL_CALL ScVbaPageSetup::setPaperSize( sal_Int32 papersize )
+{
+ if ( papersize != excel::XlPaperSize::xlPaperUser )
+ {
+ awt::Size aPaperSize;
+ const msfilter::util::ApiPaperSize& rConvertedSize = msfilter::util::PaperSizeConv::getApiSizeForMSPaperSizeIndex( papersize );
+ aPaperSize.Height = rConvertedSize.mnHeight;
+ aPaperSize.Width = rConvertedSize.mnWidth;
+ if ( mbIsLandscape )
+ ::std::swap( aPaperSize.Width, aPaperSize.Height );
+ mxPageProps->setPropertyValue( "Size", uno::Any( aPaperSize ) );
+ }
+}
+
+OUString
+ScVbaPageSetup::getServiceImplName()
+{
+ return "ScVbaPageSetup";
+}
+
+uno::Sequence< OUString >
+ScVbaPageSetup::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.PageSetup"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapagesetup.hxx b/sc/source/ui/vba/vbapagesetup.hxx
new file mode 100644
index 000000000..75e3ed1d3
--- /dev/null
+++ b/sc/source/ui/vba/vbapagesetup.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 <cppuhelper/implbase.hxx>
+#include <ooo/vba/excel/XPageSetup.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <vbahelper/vbapagesetupbase.hxx>
+
+typedef cppu::ImplInheritanceHelper<VbaPageSetupBase, ov::excel::XPageSetup> ScVbaPageSetup_BASE;
+
+class ScVbaPageSetup : public ScVbaPageSetup_BASE
+{
+ css::uno::Reference<css::sheet::XSpreadsheet> mxSheet;
+ bool mbIsLandscape;
+
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaPageSetup(const css::uno::Reference<ov::XHelperInterface>& xParent,
+ const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ const css::uno::Reference<css::sheet::XSpreadsheet>& xSheet,
+ const css::uno::Reference<css::frame::XModel>& xModel);
+
+ // Attribute
+ virtual OUString SAL_CALL getPrintArea() override;
+ virtual void SAL_CALL setPrintArea(const OUString& rAreas) override;
+ virtual double SAL_CALL getHeaderMargin() override;
+ void SAL_CALL setHeaderMargin(double margin) override;
+ double SAL_CALL getFooterMargin() override;
+ void SAL_CALL setFooterMargin(double margin) override;
+ virtual css::uno::Any SAL_CALL getFitToPagesTall() override;
+ virtual void SAL_CALL setFitToPagesTall(const css::uno::Any& fitToPagesTall) override;
+ virtual css::uno::Any SAL_CALL getFitToPagesWide() override;
+ virtual void SAL_CALL setFitToPagesWide(const css::uno::Any& fitToPagesWide) override;
+ virtual css::uno::Any SAL_CALL getZoom() override;
+ virtual void SAL_CALL setZoom(const css::uno::Any& zoom) override;
+ virtual OUString SAL_CALL getLeftHeader() override;
+ virtual void SAL_CALL setLeftHeader(const OUString& leftHeader) override;
+ virtual OUString SAL_CALL getCenterHeader() override;
+ virtual void SAL_CALL setCenterHeader(const OUString& centerHeader) override;
+ virtual OUString SAL_CALL getRightHeader() override;
+ virtual void SAL_CALL setRightHeader(const OUString& rightHeader) override;
+ virtual OUString SAL_CALL getLeftFooter() override;
+ virtual void SAL_CALL setLeftFooter(const OUString& leftFooter) override;
+ virtual OUString SAL_CALL getCenterFooter() override;
+ virtual void SAL_CALL setCenterFooter(const OUString& centerFooter) override;
+ virtual OUString SAL_CALL getRightFooter() override;
+ virtual void SAL_CALL setRightFooter(const OUString& rightFooter) override;
+ virtual sal_Int32 SAL_CALL getOrder() override;
+ virtual void SAL_CALL setOrder(sal_Int32 order) override;
+ virtual sal_Int32 SAL_CALL getFirstPageNumber() override;
+ virtual void SAL_CALL setFirstPageNumber(sal_Int32 firstPageNumber) override;
+ virtual sal_Bool SAL_CALL getCenterVertically() override;
+ virtual void SAL_CALL setCenterVertically(sal_Bool centerVertically) override;
+ virtual sal_Bool SAL_CALL getCenterHorizontally() override;
+ virtual void SAL_CALL setCenterHorizontally(sal_Bool centerHorizontally) override;
+ virtual sal_Bool SAL_CALL getPrintHeadings() override;
+ virtual void SAL_CALL setPrintHeadings(sal_Bool printHeadings) override;
+
+ virtual sal_Bool SAL_CALL getPrintGridlines() override;
+ virtual void SAL_CALL setPrintGridlines(sal_Bool _printgridlines) override;
+ virtual OUString SAL_CALL getPrintTitleRows() override;
+ virtual void SAL_CALL setPrintTitleRows(const OUString& _printtitlerows) override;
+ virtual OUString SAL_CALL getPrintTitleColumns() override;
+ virtual void SAL_CALL setPrintTitleColumns(const OUString& _printtitlecolumns) override;
+ virtual sal_Int32 SAL_CALL getPaperSize() override;
+ virtual void SAL_CALL setPaperSize(sal_Int32 papersize) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapalette.cxx b/sc/source/ui/vba/vbapalette.cxx
new file mode 100644
index 000000000..81caebab6
--- /dev/null
+++ b/sc/source/ui/vba/vbapalette.cxx
@@ -0,0 +1,115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "vbapalette.hxx"
+
+#include <sal/macros.h>
+#include <cppuhelper/implbase.hxx>
+#include <sfx2/objsh.hxx>
+#include <docsh.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include "excelvbahelper.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+/** Standard EGA colors, bright. */
+#define EXC_PALETTE_EGA_COLORS_LIGHT \
+ Color(0x000000), Color(0xFFFFFF), Color(0xFF0000), Color(0x00FF00), Color(0x0000FF), Color(0xFFFF00), Color(0xFF00FF), Color(0x00FFFF)
+/** Standard EGA colors), dark. */
+#define EXC_PALETTE_EGA_COLORS_DARK \
+ Color(0x800000), Color(0x008000), Color(0x000080), Color(0x808000), Color(0x800080), Color(0x008080), Color(0xC0C0C0), Color(0x808080)
+
+const Color spnDefColorTable8[] =
+{
+/* 8 */ EXC_PALETTE_EGA_COLORS_LIGHT,
+/* 16 */ EXC_PALETTE_EGA_COLORS_DARK,
+/* 24 */ Color(0x9999FF), Color(0x993366), Color(0xFFFFCC), Color(0xCCFFFF), Color(0x660066), Color(0xFF8080), Color(0x0066CC), Color(0xCCCCFF),
+/* 32 */ Color(0x000080), Color(0xFF00FF), Color(0xFFFF00), Color(0x00FFFF), Color(0x800080), Color(0x800000), Color(0x008080), Color(0x0000FF),
+/* 40 */ Color(0x00CCFF), Color(0xCCFFFF), Color(0xCCFFCC), Color(0xFFFF99), Color(0x99CCFF), Color(0xFF99CC), Color(0xCC99FF), Color(0xFFCC99),
+/* 48 */ Color(0x3366FF), Color(0x33CCCC), Color(0x99CC00), Color(0xFFCC00), Color(0xFF9900), Color(0xFF6600), Color(0x666699), Color(0x969696),
+/* 56 */ Color(0x003366), Color(0x339966), Color(0x003300), Color(0x333300), Color(0x993300), Color(0x993366), Color(0x333399), Color(0x333333)
+};
+
+typedef ::cppu::WeakImplHelper< container::XIndexAccess > XIndexAccess_BASE;
+
+namespace {
+
+class DefaultPalette : public XIndexAccess_BASE
+{
+public:
+ DefaultPalette(){}
+
+ // Methods XIndexAccess
+ virtual ::sal_Int32 SAL_CALL getCount() override
+ {
+ return SAL_N_ELEMENTS(spnDefColorTable8);
+ }
+
+ virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
+ {
+ if ( Index < 0 || Index >= getCount() )
+ throw lang::IndexOutOfBoundsException();
+ return uno::Any( sal_Int32( spnDefColorTable8[ Index ] ) );
+ }
+
+ // Methods XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override
+ {
+ return ::cppu::UnoType<sal_Int32>::get();
+ }
+ virtual sal_Bool SAL_CALL hasElements() override
+ {
+ return true;
+ }
+
+};
+
+}
+
+ScVbaPalette::ScVbaPalette( const uno::Reference< frame::XModel >& rxModel ) :
+ m_pShell( excel::getDocShell( rxModel ) )
+{
+}
+
+uno::Reference< container::XIndexAccess >
+ScVbaPalette::getDefaultPalette()
+{
+ return new DefaultPalette();
+}
+
+uno::Reference< container::XIndexAccess >
+ScVbaPalette::getPalette() const
+{
+ uno::Reference< container::XIndexAccess > xIndex;
+ uno::Reference< beans::XPropertySet > xProps;
+ if ( !m_pShell )
+ throw uno::RuntimeException("Can't extract palette, no doc shell" );
+
+ xProps.set( m_pShell->GetModel(), uno::UNO_QUERY_THROW );
+
+ xIndex.set( xProps->getPropertyValue("ColorPalette"), uno::UNO_QUERY );
+ if ( !xIndex.is() )
+ return new DefaultPalette();
+ return xIndex;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapalette.hxx b/sc/source/ui/vba/vbapalette.hxx
new file mode 100644
index 000000000..cc0d66f3c
--- /dev/null
+++ b/sc/source/ui/vba/vbapalette.hxx
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.hxx>
+
+namespace com::sun::star {
+ namespace container { class XIndexAccess; }
+ namespace frame { class XModel; }
+}
+
+class SfxObjectShell;
+
+class ScVbaPalette
+{
+private:
+ SfxObjectShell* m_pShell;
+public:
+ explicit ScVbaPalette( SfxObjectShell* pShell ) : m_pShell( pShell ) {}
+ explicit ScVbaPalette( const css::uno::Reference< css::frame::XModel >& rxModel );
+ // if no palette available e.g. because the document doesn't have a
+ // palette defined then a default palette will be returned.
+ css::uno::Reference< css::container::XIndexAccess > getPalette() const;
+ static css::uno::Reference< css::container::XIndexAccess > getDefaultPalette();
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapane.cxx b/sc/source/ui/vba/vbapane.cxx
new file mode 100644
index 000000000..1f7f0b540
--- /dev/null
+++ b/sc/source/ui/vba/vbapane.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 "vbapane.hxx"
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include "vbarange.hxx"
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+ScVbaPane::ScVbaPane(
+ const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< frame::XModel >& rModel,
+ const uno::Reference< sheet::XViewPane >& rViewPane ) :
+ m_xModel(rModel, uno::UNO_SET_THROW),
+ m_xViewPane(rViewPane, uno::UNO_SET_THROW),
+ m_xParent(xParent),
+ m_xContext(xContext)
+{
+}
+
+sal_Int32 SAL_CALL
+ScVbaPane::getScrollColumn()
+{
+ return ( m_xViewPane->getFirstVisibleColumn() + 1 );
+}
+
+void SAL_CALL
+ScVbaPane::setScrollColumn( sal_Int32 _scrollcolumn )
+{
+ if( _scrollcolumn < 1 )
+ {
+ throw uno::RuntimeException("Column number should not be less than 1" );
+ }
+ m_xViewPane->setFirstVisibleColumn( _scrollcolumn - 1 );
+}
+
+sal_Int32 SAL_CALL
+ScVbaPane::getScrollRow()
+{
+ return ( m_xViewPane->getFirstVisibleRow() + 1 );
+}
+
+void SAL_CALL
+ScVbaPane::setScrollRow( sal_Int32 _scrollrow )
+{
+ if( _scrollrow < 1 )
+ {
+ throw uno::RuntimeException("Row number should not be less than 1" );
+ }
+ m_xViewPane->setFirstVisibleRow( _scrollrow - 1 );
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaPane::getVisibleRange()
+{
+ // TODO: Excel includes partly visible rows/columns, Calc does not
+ table::CellRangeAddress aRangeAddr = m_xViewPane->getVisibleRange();
+ uno::Reference< sheet::XSpreadsheetDocument > xDoc( m_xModel, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xSheetsIA( xDoc->getSheets(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheet > xSheet( xSheetsIA->getByIndex( aRangeAddr.Sheet ), uno::UNO_QUERY_THROW );
+ uno::Reference< table::XCellRange > xRange( xSheet->getCellRangeByPosition( aRangeAddr.StartColumn, aRangeAddr.StartRow, aRangeAddr.EndColumn, aRangeAddr.EndRow ), uno::UNO_SET_THROW );
+ // TODO: m_xParent is the window, Range needs the worksheet
+ return new ScVbaRange( m_xParent, m_xContext, xRange );
+}
+
+//Method
+void SAL_CALL
+ScVbaPane::SmallScroll( const uno::Any& Down, const uno::Any& Up, const uno::Any& ToRight, const uno::Any& ToLeft )
+{
+ OUString messageBuffer;
+ sal_Int32 downRows = 0;
+ sal_Int32 rightCols = 0;
+ table::CellRangeAddress visibleRange = m_xViewPane->getVisibleRange();
+
+ if( Down.hasValue() )
+ {
+ sal_Int32 down = 0;
+ if( Down >>= down )
+ downRows += down;
+ else
+ messageBuffer += "Error getting parameter: Down\n";
+ }
+ if( Up.hasValue() )
+ {
+ sal_Int32 up = 0;
+ if( Up >>= up )
+ downRows -= up;
+ else
+ messageBuffer += "Error getting parameter: Up\n";
+ }
+ if( ToRight.hasValue() )
+ {
+ sal_Int32 right = 0;
+ if( ToRight >>= right )
+ rightCols += right;
+ else
+ messageBuffer += "Error getting parameter: ToRight\n";
+ }
+ if( ToLeft.hasValue() )
+ {
+ sal_Int32 left = 0;
+ if( ToLeft >>= left )
+ rightCols -= left;
+ else
+ messageBuffer += "Error getting parameter: ToLeft\n";
+ }
+ if( !messageBuffer.isEmpty() )
+ throw uno::RuntimeException( messageBuffer );
+
+ sal_Int32 newStartRow = visibleRange.StartRow + downRows;
+ if( newStartRow < 0 )
+ newStartRow = 0;
+ sal_Int32 newStartCol = visibleRange.StartColumn + rightCols;
+ if( newStartCol < 0 )
+ newStartCol = 0;
+ m_xViewPane->setFirstVisibleRow( newStartRow );
+ m_xViewPane->setFirstVisibleColumn( newStartCol );
+}
+
+void SAL_CALL
+ScVbaPane::LargeScroll( const uno::Any& Down, const uno::Any& Up, const uno::Any& ToRight, const uno::Any& ToLeft )
+{
+ OUString messageBuffer;
+ table::CellRangeAddress visibleRange = m_xViewPane->getVisibleRange();
+
+ sal_Int32 vertPageSize = 1 + visibleRange.EndRow - visibleRange.StartRow;
+ sal_Int32 horizPageSize = 1 + visibleRange.EndColumn - visibleRange.StartColumn;
+ sal_Int32 downPages = 0;
+ sal_Int32 acrossPages = 0;
+ if( Down.hasValue() )
+ {
+ sal_Int32 down = 0;
+ if( Down >>= down )
+ downPages += down;
+ else
+ messageBuffer += "Error getting parameter: Down\n";
+ }
+ if( Up.hasValue() )
+ {
+ sal_Int32 up = 0;
+ if( Up >>= up )
+ downPages -= up;
+ else
+ messageBuffer += "Error getting parameter: Up\n";
+ }
+ if( ToRight.hasValue() )
+ {
+ sal_Int32 right = 0;
+ if( ToRight >>= right )
+ acrossPages += right;
+ else
+ messageBuffer += "Error getting parameter: ToRight\n";
+ }
+ if( ToLeft.hasValue() )
+ {
+ sal_Int32 left = 0;
+ if( ToLeft >>= left )
+ acrossPages -= left;
+ else
+ messageBuffer += "Error getting parameter: ToLeft\n";
+ }
+ if( !messageBuffer.isEmpty() )
+ throw uno::RuntimeException( messageBuffer );
+
+ sal_Int32 newStartRow = visibleRange.StartRow + (downPages * vertPageSize );
+ if( newStartRow < 0 )
+ newStartRow = 0;
+ sal_Int32 newStartCol = visibleRange.StartColumn + (acrossPages * horizPageSize );
+ if( newStartCol < 0 )
+ newStartCol = 0;
+ m_xViewPane->setFirstVisibleRow( newStartRow );
+ m_xViewPane->setFirstVisibleColumn( newStartCol );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapane.hxx b/sc/source/ui/vba/vbapane.hxx
new file mode 100644
index 000000000..cf4fd8328
--- /dev/null
+++ b/sc/source/ui/vba/vbapane.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 <com/sun/star/sheet/XViewPane.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <ooo/vba/excel/XPane.hpp>
+#include <vbahelper/vbahelper.hxx>
+
+class ScVbaPane final : public cppu::WeakImplHelper< ov::excel::XPane >
+{
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaPane(
+ const css::uno::Reference< ov::XHelperInterface >& rParent,
+ const css::uno::Reference< css::uno::XComponentContext >& rContext,
+ const css::uno::Reference< css::frame::XModel >& rModel,
+ const css::uno::Reference< css::sheet::XViewPane >& rViewPane );
+
+ // XPane attributes
+ virtual sal_Int32 SAL_CALL getScrollColumn() override;
+ virtual void SAL_CALL setScrollColumn( sal_Int32 _scrollcolumn ) override;
+ virtual sal_Int32 SAL_CALL getScrollRow() override;
+ virtual void SAL_CALL setScrollRow( sal_Int32 _scrollrow ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getVisibleRange() override;
+
+ // XPane methods
+ virtual void SAL_CALL SmallScroll( const css::uno::Any& Down, const css::uno::Any& Up, const css::uno::Any& ToRight, const css::uno::Any& ToLeft ) override;
+ virtual void SAL_CALL LargeScroll( const css::uno::Any& Down, const css::uno::Any& Up, const css::uno::Any& ToRight, const css::uno::Any& ToLeft ) override;
+
+private:
+ css::uno::Reference< css::frame::XModel > m_xModel;
+ css::uno::Reference< css::sheet::XViewPane > m_xViewPane;
+ css::uno::WeakReference< ov::XHelperInterface > m_xParent;
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapivotcache.cxx b/sc/source/ui/vba/vbapivotcache.cxx
new file mode 100644
index 000000000..54c6a4ad7
--- /dev/null
+++ b/sc/source/ui/vba/vbapivotcache.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 "vbapivotcache.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+ScVbaPivotCache::ScVbaPivotCache( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XDataPilotTable >& xTable ) : PivotCacheImpl_BASE( xParent, xContext ), m_xTable( xTable )
+{
+}
+
+void SAL_CALL
+ScVbaPivotCache::Refresh()
+{
+ m_xTable->refresh();
+}
+
+OUString
+ScVbaPivotCache::getServiceImplName()
+{
+ return "ScVbaPivotCache";
+}
+
+uno::Sequence< OUString >
+ScVbaPivotCache::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.PivotCache"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapivotcache.hxx b/sc/source/ui/vba/vbapivotcache.hxx
new file mode 100644
index 000000000..c02f30920
--- /dev/null
+++ b/sc/source/ui/vba/vbapivotcache.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 <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/sheet/XDataPilotTable.hpp>
+
+#include <ooo/vba/excel/XPivotCache.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl<ov::excel::XPivotCache > PivotCacheImpl_BASE;
+
+class ScVbaPivotCache : public PivotCacheImpl_BASE
+{
+ css::uno::Reference< css::sheet::XDataPilotTable > m_xTable;
+public:
+ ScVbaPivotCache( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::sheet::XDataPilotTable >& xTable );
+
+ virtual void SAL_CALL Refresh() override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapivottable.cxx b/sc/source/ui/vba/vbapivottable.cxx
new file mode 100644
index 000000000..775ac390c
--- /dev/null
+++ b/sc/source/ui/vba/vbapivottable.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 "vbapivottable.hxx"
+#include "vbapivotcache.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+ScVbaPivotTable::ScVbaPivotTable( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XDataPilotTable >& xTable ) : PivotTableImpl_BASE( uno::Reference< XHelperInterface >(), xContext), m_xTable( xTable )
+{
+}
+
+uno::Reference< excel::XPivotCache >
+ScVbaPivotTable::PivotCache()
+{
+ // #FIXME with a quick example failed to determine what the parent
+ // should be, leaving as null at the moment
+ return new ScVbaPivotCache( uno::Reference< XHelperInterface >(), mxContext, m_xTable );
+}
+
+OUString
+ScVbaPivotTable::getServiceImplName()
+{
+ return "ScVbaPivotTable";
+}
+
+uno::Sequence< OUString >
+ScVbaPivotTable::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.PivotTable"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapivottable.hxx b/sc/source/ui/vba/vbapivottable.hxx
new file mode 100644
index 000000000..3d3392168
--- /dev/null
+++ b/sc/source/ui/vba/vbapivottable.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 <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/sheet/XDataPilotTable.hpp>
+#include <ooo/vba/excel/XPivotTable.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl<ov::excel::XPivotTable> PivotTableImpl_BASE;
+
+class ScVbaPivotTable : public PivotTableImpl_BASE
+{
+ css::uno::Reference<css::sheet::XDataPilotTable> m_xTable;
+
+public:
+ ScVbaPivotTable(const css::uno::Reference<css::uno::XComponentContext>& xContext,
+ const css::uno::Reference<css::sheet::XDataPilotTable>& xTable);
+ virtual css::uno::Reference<ov::excel::XPivotCache> SAL_CALL PivotCache() override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapivottables.cxx b/sc/source/ui/vba/vbapivottables.cxx
new file mode 100644
index 000000000..f49fbeaeb
--- /dev/null
+++ b/sc/source/ui/vba/vbapivottables.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 "vbapivottables.hxx"
+#include "vbapivottable.hxx"
+#include <com/sun/star/sheet/XDataPilotTable.hpp>
+#include <ooo/vba/excel/XPivotTable.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+static uno::Any DataPilotToPivotTable( const uno::Any& aSource, const uno::Reference< uno::XComponentContext > & xContext )
+{
+ uno::Reference< sheet::XDataPilotTable > xTable( aSource, uno::UNO_QUERY_THROW );
+ return uno::Any( uno::Reference< excel::XPivotTable > ( new ScVbaPivotTable( xContext, xTable ) ) );
+}
+
+namespace {
+
+class PivotTableEnumeration : public EnumerationHelperImpl
+{
+public:
+ /// @throws uno::RuntimeException
+ PivotTableEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ) {}
+
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ return DataPilotToPivotTable( m_xEnumeration->nextElement(), m_xContext );
+ }
+
+};
+
+}
+
+ScVbaPivotTables::ScVbaPivotTables( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext > & xContext, const uno::Reference< container::XIndexAccess >& xIndexAccess ): ScVbaPivotTables_BASE( xParent, xContext, xIndexAccess )
+{
+}
+
+uno::Reference< container::XEnumeration >
+ScVbaPivotTables::createEnumeration()
+{
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW );
+ return new PivotTableEnumeration( mxParent, mxContext, xEnumAccess->createEnumeration() );
+}
+
+uno::Any
+ScVbaPivotTables::createCollectionObject( const css::uno::Any& aSource )
+{
+ return DataPilotToPivotTable( aSource, mxContext );
+}
+
+uno::Type
+ScVbaPivotTables::getElementType()
+{
+ return cppu::UnoType<excel::XPivotTable>::get();
+}
+
+OUString
+ScVbaPivotTables::getServiceImplName()
+{
+ return "ScVbaPivotTables";
+}
+
+css::uno::Sequence<OUString>
+ScVbaPivotTables::getServiceNames()
+{
+ static uno::Sequence< OUString > const sNames
+ {
+ "ooo.vba.excel.PivotTables"
+ };
+ return sNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbapivottables.hxx b/sc/source/ui/vba/vbapivottables.hxx
new file mode 100644
index 000000000..69b16b96f
--- /dev/null
+++ b/sc/source/ui/vba/vbapivottables.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 <ooo/vba/excel/XPivotTables.hpp>
+
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+typedef CollTestImplHelper< ov::excel::XPivotTables > ScVbaPivotTables_BASE;
+
+class ScVbaPivotTables : public ScVbaPivotTables_BASE
+{
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+public:
+ ScVbaPivotTables( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::container::XIndexAccess >& xIndexAccess );
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+
+ // XPivotTables
+
+ // ScVbaPivotTables_BASE
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+
+ virtual OUString getServiceImplName() override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbarange.cxx b/sc/source/ui/vba/vbarange.cxx
new file mode 100644
index 000000000..99933f165
--- /dev/null
+++ b/sc/source/ui/vba/vbarange.cxx
@@ -0,0 +1,5720 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "vbarange.hxx"
+
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <o3tl/any.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <rtl/math.hxx>
+#include <tools/diagnose_ex.h>
+#include <o3tl/string_view.hxx>
+
+#include <com/sun/star/script/ArrayWrapper.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <com/sun/star/script/vba/VBAEventId.hpp>
+#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
+#include <com/sun/star/sheet/XDatabaseRange.hpp>
+#include <com/sun/star/sheet/XUnnamedDatabaseRanges.hpp>
+#include <com/sun/star/sheet/XGoalSeek.hpp>
+#include <com/sun/star/sheet/XSheetOperation.hpp>
+#include <com/sun/star/sheet/CellFlags.hpp>
+#include <com/sun/star/table/XColumnRowRange.hpp>
+#include <com/sun/star/sheet/XCellAddressable.hpp>
+#include <com/sun/star/table/CellContentType.hpp>
+#include <com/sun/star/sheet/XCellSeries.hpp>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/table/CellAddress.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <com/sun/star/sheet/XSpreadsheetView.hpp>
+#include <com/sun/star/sheet/XCellRangeReferrer.hpp>
+#include <com/sun/star/sheet/XSheetCellRange.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XSheetCellCursor.hpp>
+#include <com/sun/star/sheet/XArrayFormulaRange.hpp>
+#include <com/sun/star/sheet/XNamedRange.hpp>
+#include <com/sun/star/sheet/XNamedRanges.hpp>
+#include <com/sun/star/sheet/XPrintAreas.hpp>
+#include <com/sun/star/sheet/XCellRangesQuery.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/table/XTableRows.hpp>
+#include <com/sun/star/table/XTableColumns.hpp>
+#include <com/sun/star/table/TableSortField.hpp>
+#include <com/sun/star/util/XMergeable.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/util/XNumberFormats.hpp>
+#include <com/sun/star/util/NumberFormat.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/util/XReplaceable.hpp>
+#include <com/sun/star/util/XSortable.hpp>
+#include <com/sun/star/sheet/XCellRangeMovement.hpp>
+#include <com/sun/star/sheet/FormulaResult.hpp>
+#include <com/sun/star/sheet/FilterOperator2.hpp>
+#include <com/sun/star/sheet/TableFilterField2.hpp>
+#include <com/sun/star/sheet/XSheetFilterDescriptor2.hpp>
+#include <com/sun/star/sheet/FilterConnection.hpp>
+#include <com/sun/star/util/TriState.hpp>
+
+#include <com/sun/star/sheet/XSubTotalCalculatable.hpp>
+#include <com/sun/star/sheet/XSubTotalDescriptor.hpp>
+#include <com/sun/star/sheet/GeneralFunction.hpp>
+
+#include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp>
+#include <com/sun/star/sheet/XSheetAnnotations.hpp>
+
+#include <ooo/vba/excel/XlPasteSpecialOperation.hpp>
+#include <ooo/vba/excel/XlPasteType.hpp>
+#include <ooo/vba/excel/XlFindLookIn.hpp>
+#include <ooo/vba/excel/XlLookAt.hpp>
+#include <ooo/vba/excel/XlSearchOrder.hpp>
+#include <ooo/vba/excel/XlSortOrder.hpp>
+#include <ooo/vba/excel/XlYesNoGuess.hpp>
+#include <ooo/vba/excel/XlSortOrientation.hpp>
+#include <ooo/vba/excel/XlSortMethod.hpp>
+#include <ooo/vba/excel/XlDirection.hpp>
+#include <ooo/vba/excel/XlSortDataOption.hpp>
+#include <ooo/vba/excel/XlDeleteShiftDirection.hpp>
+#include <ooo/vba/excel/XlInsertShiftDirection.hpp>
+#include <ooo/vba/excel/XlReferenceStyle.hpp>
+#include <ooo/vba/excel/XlBordersIndex.hpp>
+#include <ooo/vba/excel/XlPageBreak.hpp>
+#include <ooo/vba/excel/XlAutoFilterOperator.hpp>
+#include <ooo/vba/excel/XlAutoFillType.hpp>
+#include <ooo/vba/excel/XlCellType.hpp>
+#include <ooo/vba/excel/XlSpecialCellsValue.hpp>
+#include <ooo/vba/excel/XlConsolidationFunction.hpp>
+#include <ooo/vba/excel/XlSearchDirection.hpp>
+
+#include <scitems.hxx>
+#include <svl/srchitem.hxx>
+#include <cellsuno.hxx>
+#include <dbdata.hxx>
+#include <docfunc.hxx>
+#include <columnspanset.hxx>
+#include <queryparam.hxx>
+#include <sortparam.hxx>
+
+#include <sfx2/dispatch.hxx>
+#include <sfx2/app.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sc.hrc>
+#include <unonames.hxx>
+
+#include "excelvbahelper.hxx"
+#include "vbaapplication.hxx"
+#include "vbafont.hxx"
+#include "vbacomment.hxx"
+#include "vbainterior.hxx"
+#include "vbacharacters.hxx"
+#include "vbaborders.hxx"
+#include "vbaworksheet.hxx"
+#include "vbavalidation.hxx"
+#include "vbahyperlinks.hxx"
+
+#include <tabvwsh.hxx>
+#include <rangelst.hxx>
+#include <convuno.hxx>
+#include <compiler.hxx>
+#include <patattr.hxx>
+#include <olinetab.hxx>
+#include <transobj.hxx>
+#include <queryentry.hxx>
+#include <markdata.hxx>
+#include <basic/sberrors.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <global.hxx>
+
+#include "vbastyle.hxx"
+#include "vbaname.hxx"
+#include <vector>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+#include <com/sun/star/bridge/oleautomation/Date.hpp>
+#include <tokenarray.hxx>
+#include <tokenuno.hxx>
+
+#include <memory>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+using ::std::vector;
+
+// difference between VBA and file format width, in character units
+const double fExtraWidth = 182.0 / 256.0;
+
+const sal_Int16 supportedIndexTable[] = { excel::XlBordersIndex::xlEdgeLeft, excel::XlBordersIndex::xlEdgeTop, excel::XlBordersIndex::xlEdgeBottom, excel::XlBordersIndex::xlEdgeRight, excel::XlBordersIndex::xlDiagonalDown, excel::XlBordersIndex::xlDiagonalUp, excel::XlBordersIndex::xlInsideVertical, excel::XlBordersIndex::xlInsideHorizontal };
+
+static sal_uInt16 lcl_pointsToTwips( double nVal )
+{
+ nVal = nVal * static_cast<double>(20);
+ short nTwips = static_cast<short>(nVal);
+ return nTwips;
+}
+static double lcl_TwipsToPoints( sal_uInt16 nVal )
+{
+ double nPoints = nVal;
+ return nPoints / 20;
+}
+
+static double lcl_Round2DecPlaces( double nVal )
+{
+ nVal = (nVal * double(100));
+ tools::Long tmp = static_cast<tools::Long>(nVal);
+ if ( ( nVal - tmp ) >= 0.5 )
+ ++tmp;
+ nVal = double(tmp)/100;
+ return nVal;
+}
+
+static uno::Any lcl_makeRange( const uno::Reference< XHelperInterface >& rParent, const uno::Reference< uno::XComponentContext >& rContext, const uno::Any& rAny, bool bIsRows, bool bIsColumns )
+{
+ uno::Reference< table::XCellRange > xCellRange(rAny, uno::UNO_QUERY_THROW);
+ return uno::Any( uno::Reference< excel::XRange >( new ScVbaRange( rParent, rContext, xCellRange, bIsRows, bIsColumns ) ) );
+}
+
+static uno::Reference< excel::XRange > lcl_makeXRangeFromSheetCellRanges( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XSheetCellRanges >& xLocSheetCellRanges, ScDocShell* pDoc )
+{
+ uno::Reference< excel::XRange > xRange;
+ const uno::Sequence< table::CellRangeAddress > sAddresses = xLocSheetCellRanges->getRangeAddresses();
+ ScRangeList aCellRanges;
+ if ( sAddresses.hasElements() )
+ {
+ for ( const auto& rAddress : sAddresses )
+ {
+ ScRange refRange;
+ ScUnoConversion::FillScRange( refRange, rAddress );
+ aCellRanges.push_back( refRange );
+ }
+ // Single range
+ if ( aCellRanges.size() == 1 )
+ {
+ uno::Reference< table::XCellRange > xTmpRange( new ScCellRangeObj( pDoc, aCellRanges.front() ) );
+ xRange = new ScVbaRange( xParent, xContext, xTmpRange );
+ }
+ else
+ {
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDoc, aCellRanges ) );
+ xRange = new ScVbaRange( xParent, xContext, xRanges );
+ }
+ }
+ return xRange;
+}
+
+ScCellRangesBase* ScVbaRange::getCellRangesBase()
+{
+ if( mxRanges.is() )
+ return comphelper::getFromUnoTunnel<ScCellRangesBase>( mxRanges );
+ if( mxRange.is() )
+ return comphelper::getFromUnoTunnel<ScCellRangesBase>( mxRange );
+ throw uno::RuntimeException("General Error creating range - Unknown" );
+}
+
+ScCellRangeObj* ScVbaRange::getCellRangeObj()
+{
+ return dynamic_cast< ScCellRangeObj* >( getCellRangesBase() );
+}
+
+SfxItemSet* ScVbaRange::getCurrentDataSet( )
+{
+ SfxItemSet* pDataSet = excel::ScVbaCellRangeAccess::GetDataSet( getCellRangesBase() );
+ if ( !pDataSet )
+ throw uno::RuntimeException("Can't access Itemset for range" );
+ return pDataSet;
+}
+
+void ScVbaRange::fireChangeEvent()
+{
+ if( !ScVbaApplication::getDocumentEventsEnabled() )
+ return;
+
+ ScDocument& rDoc = getScDocument();
+ const uno::Reference< script::vba::XVBAEventProcessor >& xVBAEvents = rDoc.GetVbaEventProcessor();
+ if( xVBAEvents.is() ) try
+ {
+ uno::Sequence< uno::Any > aArgs{ uno::Any(uno::Reference< excel::XRange >( this )) };
+ xVBAEvents->processVbaEvent( script::vba::VBAEventId::WORKSHEET_CHANGE, aArgs );
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+namespace {
+
+class SingleRangeEnumeration : public EnumerationHelper_BASE
+{
+ uno::Reference< table::XCellRange > m_xRange;
+ bool bHasMore;
+public:
+ /// @throws uno::RuntimeException
+ explicit SingleRangeEnumeration( const uno::Reference< table::XCellRange >& xRange ) : m_xRange( xRange ), bHasMore( true ) { }
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override { return bHasMore; }
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ if ( !bHasMore )
+ throw container::NoSuchElementException();
+ bHasMore = false;
+ return uno::Any( m_xRange );
+ }
+};
+
+// very simple class to pass to ScVbaCollectionBaseImpl containing
+// just one item
+
+class SingleRangeIndexAccess : public ::cppu::WeakImplHelper< container::XIndexAccess,
+ container::XEnumerationAccess >
+{
+private:
+ uno::Reference< table::XCellRange > m_xRange;
+
+public:
+ explicit SingleRangeIndexAccess( const uno::Reference< table::XCellRange >& xRange ) : m_xRange( xRange ) {}
+ // XIndexAccess
+ virtual ::sal_Int32 SAL_CALL getCount() override { return 1; }
+ virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
+ {
+ if ( Index != 0 )
+ throw lang::IndexOutOfBoundsException();
+ return uno::Any( m_xRange );
+ }
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override { return cppu::UnoType<table::XCellRange>::get(); }
+ virtual sal_Bool SAL_CALL hasElements() override { return true; }
+ // XEnumerationAccess
+ virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration() override { return new SingleRangeEnumeration( m_xRange ); }
+
+};
+
+class RangesEnumerationImpl : public EnumerationHelperImpl
+{
+ bool mbIsRows;
+ bool mbIsColumns;
+public:
+ /// @throws uno::RuntimeException
+ RangesEnumerationImpl( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, bool bIsRows, bool bIsColumns ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), mbIsRows( bIsRows ), mbIsColumns( bIsColumns ) {}
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ return lcl_makeRange( m_xParent, m_xContext, m_xEnumeration->nextElement(), mbIsRows, mbIsColumns );
+ }
+};
+
+class ScVbaRangeAreas : public ScVbaCollectionBaseImpl
+{
+ bool mbIsRows;
+ bool mbIsColumns;
+public:
+ ScVbaRangeAreas( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XIndexAccess >& xIndexAccess, bool bIsRows, bool bIsColumns ) : ScVbaCollectionBaseImpl( xParent, xContext, xIndexAccess ), mbIsRows( bIsRows ), mbIsColumns( bIsColumns ) {}
+
+ // XEnumerationAccess
+ virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration() override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override { return cppu::UnoType<excel::XRange>::get(); }
+
+ virtual uno::Any createCollectionObject( const uno::Any& aSource ) override;
+
+ virtual OUString getServiceImplName() override { return OUString(); }
+
+ virtual uno::Sequence< OUString > getServiceNames() override { return uno::Sequence< OUString >(); }
+
+};
+
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL
+ScVbaRangeAreas::createEnumeration()
+{
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xIndexAccess, uno::UNO_QUERY_THROW );
+ return new RangesEnumerationImpl( mxParent, mxContext, xEnumAccess->createEnumeration(), mbIsRows, mbIsColumns );
+}
+
+uno::Any
+ScVbaRangeAreas::createCollectionObject( const uno::Any& aSource )
+{
+ return lcl_makeRange( mxParent, mxContext, aSource, mbIsRows, mbIsColumns );
+}
+
+// assume that xIf is in fact a ScCellRangesBase
+/// @throws uno::RuntimeException
+static ScDocShell*
+getDocShellFromIf( const uno::Reference< uno::XInterface >& xIf )
+{
+ ScCellRangesBase* pUno = comphelper::getFromUnoTunnel<ScCellRangesBase>( xIf );
+ if ( !pUno )
+ throw uno::RuntimeException("Failed to access underlying uno range object" );
+ return pUno->GetDocShell();
+}
+
+/// @throws uno::RuntimeException
+static ScDocShell*
+getDocShellFromRange( const uno::Reference< table::XCellRange >& xRange )
+{
+ // need the ScCellRangesBase to get docshell
+ uno::Reference< uno::XInterface > xIf( xRange );
+ return getDocShellFromIf(xIf );
+}
+
+/// @throws uno::RuntimeException
+static ScDocShell*
+getDocShellFromRanges( const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges )
+{
+ // need the ScCellRangesBase to get docshell
+ uno::Reference< uno::XInterface > xIf( xRanges );
+ return getDocShellFromIf(xIf );
+}
+
+/// @throws uno::RuntimeException
+static uno::Reference< frame::XModel > getModelFromXIf( const uno::Reference< uno::XInterface >& xIf )
+{
+ ScDocShell* pDocShell = getDocShellFromIf(xIf );
+ return pDocShell->GetModel();
+}
+
+/// @throws uno::RuntimeException
+static uno::Reference< frame::XModel > getModelFromRange( const uno::Reference< table::XCellRange >& xRange )
+{
+ // the XInterface for getImplementation can be any derived interface, no need for queryInterface
+ uno::Reference< uno::XInterface > xIf( xRange );
+ return getModelFromXIf( xIf );
+}
+
+static ScDocument&
+getDocumentFromRange( const uno::Reference< table::XCellRange >& xRange )
+{
+ ScDocShell* pDocShell = getDocShellFromRange( xRange );
+ if ( !pDocShell )
+ throw uno::RuntimeException("Failed to access underlying docshell from uno range object" );
+ ScDocument& rDoc = pDocShell->GetDocument();
+ return rDoc;
+}
+
+ScDocument&
+ScVbaRange::getScDocument()
+{
+ if ( mxRanges.is() )
+ {
+ uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW );
+ uno::Reference< table::XCellRange > xRange( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW );
+ return getDocumentFromRange( xRange );
+ }
+ return getDocumentFromRange( mxRange );
+}
+
+ScDocShell*
+ScVbaRange::getScDocShell()
+{
+ if ( mxRanges.is() )
+ {
+ uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW );
+ uno::Reference< table::XCellRange > xRange( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW );
+ return getDocShellFromRange( xRange );
+ }
+ return getDocShellFromRange( mxRange );
+}
+
+ScVbaRange* ScVbaRange::getImplementation( const uno::Reference< excel::XRange >& rxRange )
+{
+ // FIXME: always save to use dynamic_cast? Or better to (implement and) use XTunnel?
+ return dynamic_cast< ScVbaRange* >( rxRange.get() );
+}
+
+uno::Reference< frame::XModel > ScVbaRange::getUnoModel()
+{
+ if( ScDocShell* pDocShell = getScDocShell() )
+ return pDocShell->GetModel();
+ throw uno::RuntimeException();
+}
+
+uno::Reference< frame::XModel > ScVbaRange::getUnoModel( const uno::Reference< excel::XRange >& rxRange )
+{
+ if( ScVbaRange* pScVbaRange = getImplementation( rxRange ) )
+ return pScVbaRange->getUnoModel();
+ throw uno::RuntimeException();
+}
+
+const ScRangeList& ScVbaRange::getScRangeList()
+{
+ if( ScCellRangesBase* pScRangesBase = getCellRangesBase() )
+ return pScRangesBase->GetRangeList();
+ throw uno::RuntimeException("Cannot obtain UNO range implementation object" );
+}
+
+const ScRangeList& ScVbaRange::getScRangeList( const uno::Reference< excel::XRange >& rxRange )
+{
+ if( ScVbaRange* pScVbaRange = getImplementation( rxRange ) )
+ return pScVbaRange->getScRangeList();
+ throw uno::RuntimeException("Cannot obtain VBA range implementation object" );
+}
+
+namespace {
+
+class NumFormatHelper
+{
+ uno::Reference< util::XNumberFormatsSupplier > mxSupplier;
+ uno::Reference< beans::XPropertySet > mxRangeProps;
+ uno::Reference< util::XNumberFormats > mxFormats;
+public:
+ explicit NumFormatHelper( const uno::Reference< table::XCellRange >& xRange )
+ {
+ mxSupplier.set( getModelFromRange( xRange ), uno::UNO_QUERY_THROW );
+ mxRangeProps.set( xRange, uno::UNO_QUERY_THROW);
+ mxFormats = mxSupplier->getNumberFormats();
+ }
+ uno::Reference< beans::XPropertySet > getNumberProps()
+ {
+ tools::Long nIndexKey = 0;
+ uno::Any aValue = mxRangeProps->getPropertyValue( "NumberFormat" );
+ aValue >>= nIndexKey;
+
+ if ( mxFormats.is() )
+ return mxFormats->getByKey( nIndexKey );
+ return uno::Reference< beans::XPropertySet > ();
+ }
+
+ bool isBooleanType()
+ {
+
+ return (getNumberFormat() & util::NumberFormat::LOGICAL) != 0;
+ }
+
+ bool isDateType()
+ {
+ sal_Int16 nType = getNumberFormat();
+ return ( nType & util::NumberFormat::DATETIME ) != 0;
+ }
+
+ OUString getNumberFormatString()
+ {
+ uno::Reference< uno::XInterface > xIf( mxRangeProps, uno::UNO_QUERY_THROW );
+ ScCellRangesBase* pUnoCellRange = comphelper::getFromUnoTunnel<ScCellRangesBase>( xIf );
+ if ( pUnoCellRange )
+ {
+
+ SfxItemSet* pDataSet = excel::ScVbaCellRangeAccess::GetDataSet( pUnoCellRange );
+ SfxItemState eState = pDataSet->GetItemState( ATTR_VALUE_FORMAT);
+ // one of the cells in the range is not like the other ;-)
+ // so return a zero length format to indicate that
+ if ( eState == SfxItemState::DONTCARE )
+ return OUString();
+ }
+
+ uno::Reference< beans::XPropertySet > xNumberProps( getNumberProps(), uno::UNO_SET_THROW );
+ OUString aFormatString;
+ uno::Any aString = xNumberProps->getPropertyValue( "FormatString" );
+ aString >>= aFormatString;
+ return aFormatString;
+ }
+
+ sal_Int16 getNumberFormat()
+ {
+ uno::Reference< beans::XPropertySet > xNumberProps = getNumberProps();
+ sal_Int16 nType = ::comphelper::getINT16(
+ xNumberProps->getPropertyValue( "Type" ) );
+ return nType;
+ }
+
+ void setNumberFormat( const OUString& rFormat )
+ {
+ // #163288# treat "General" as "Standard" format
+ sal_Int32 nNewIndex = 0;
+ if( !rFormat.equalsIgnoreAsciiCase( "General" ) )
+ {
+ lang::Locale aLocale;
+ uno::Reference< beans::XPropertySet > xNumProps = getNumberProps();
+ xNumProps->getPropertyValue( "Locale" ) >>= aLocale;
+ nNewIndex = mxFormats->queryKey( rFormat, aLocale, false );
+ if ( nNewIndex == -1 ) // format not defined
+ nNewIndex = mxFormats->addNew( rFormat, aLocale );
+ }
+ mxRangeProps->setPropertyValue( "NumberFormat", uno::Any( nNewIndex ) );
+ }
+
+ void setNumberFormat( sal_Int16 nType )
+ {
+ uno::Reference< beans::XPropertySet > xNumberProps = getNumberProps();
+ lang::Locale aLocale;
+ xNumberProps->getPropertyValue( "Locale" ) >>= aLocale;
+ uno::Reference<util::XNumberFormatTypes> xTypes( mxFormats, uno::UNO_QUERY );
+ if ( xTypes.is() )
+ {
+ sal_Int32 nNewIndex = xTypes->getStandardFormat( nType, aLocale );
+ mxRangeProps->setPropertyValue( "NumberFormat", uno::Any( nNewIndex ) );
+ }
+ }
+
+};
+
+struct CellPos
+{
+ CellPos( sal_Int32 nRow, sal_Int32 nCol, sal_Int32 nArea ):m_nRow(nRow), m_nCol(nCol), m_nArea( nArea ) {};
+sal_Int32 m_nRow;
+sal_Int32 m_nCol;
+sal_Int32 m_nArea;
+};
+
+}
+
+typedef ::cppu::WeakImplHelper< container::XEnumeration > CellsEnumeration_BASE;
+typedef ::std::vector< CellPos > vCellPos;
+
+namespace {
+
+// #FIXME - QUICK
+// we could probably could and should modify CellsEnumeration below
+// to handle rows and columns (but I do this separately for now
+// and... this class only handles single areas (does it have to handle
+// multi area ranges??)
+class ColumnsRowEnumeration: public CellsEnumeration_BASE
+{
+ uno::Reference< excel::XRange > mxRange;
+ sal_Int32 mMaxElems;
+ sal_Int32 mCurElem;
+
+public:
+ ColumnsRowEnumeration( const uno::Reference< excel::XRange >& xRange, sal_Int32 nElems ) : mxRange( xRange ), mMaxElems( nElems ), mCurElem( 0 )
+ {
+ }
+
+ virtual sal_Bool SAL_CALL hasMoreElements() override { return mCurElem < mMaxElems; }
+
+ virtual uno::Any SAL_CALL nextElement() override
+ {
+ if ( !hasMoreElements() )
+ throw container::NoSuchElementException();
+ sal_Int32 vbaIndex = 1 + mCurElem++;
+ return uno::Any( mxRange->Item( uno::Any( vbaIndex ), uno::Any() ) );
+ }
+};
+
+class CellsEnumeration : public CellsEnumeration_BASE
+{
+ uno::WeakReference< XHelperInterface > mxParent;
+ uno::Reference< uno::XComponentContext > mxContext;
+ uno::Reference< XCollection > m_xAreas;
+ vCellPos m_CellPositions;
+ vCellPos::const_iterator m_it;
+
+ /// @throws uno::RuntimeException
+ uno::Reference< table::XCellRange > getArea( sal_Int32 nVBAIndex )
+ {
+ if ( nVBAIndex < 1 || nVBAIndex > m_xAreas->getCount() )
+ throw uno::RuntimeException();
+ uno::Reference< excel::XRange > xRange( m_xAreas->Item( uno::Any(nVBAIndex), uno::Any() ), uno::UNO_QUERY_THROW );
+ uno::Reference< table::XCellRange > xCellRange( ScVbaRange::getCellRange( xRange ), uno::UNO_QUERY_THROW );
+ return xCellRange;
+ }
+
+ void populateArea( sal_Int32 nVBAIndex )
+ {
+ uno::Reference< table::XCellRange > xRange = getArea( nVBAIndex );
+ uno::Reference< table::XColumnRowRange > xColumnRowRange(xRange, uno::UNO_QUERY_THROW );
+ sal_Int32 nRowCount = xColumnRowRange->getRows()->getCount();
+ sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount();
+ for ( sal_Int32 i=0; i<nRowCount; ++i )
+ {
+ for ( sal_Int32 j=0; j<nColCount; ++j )
+ m_CellPositions.emplace_back( i,j,nVBAIndex );
+ }
+ }
+public:
+ CellsEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< XCollection >& xAreas ): mxParent( xParent ), mxContext( xContext ), m_xAreas( xAreas )
+ {
+ sal_Int32 nItems = m_xAreas->getCount();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ populateArea( index );
+ }
+ m_it = m_CellPositions.begin();
+ }
+ virtual sal_Bool SAL_CALL hasMoreElements() override { return m_it != m_CellPositions.end(); }
+
+ virtual uno::Any SAL_CALL nextElement() override
+ {
+ if ( !hasMoreElements() )
+ throw container::NoSuchElementException();
+ CellPos aPos = *m_it++;
+
+ uno::Reference< table::XCellRange > xRangeArea = getArea( aPos.m_nArea );
+ uno::Reference< table::XCellRange > xCellRange( xRangeArea->getCellByPosition( aPos.m_nCol, aPos.m_nRow ), uno::UNO_QUERY_THROW );
+ return uno::Any( uno::Reference< excel::XRange >( new ScVbaRange( mxParent, mxContext, xCellRange ) ) );
+
+ }
+};
+
+}
+
+constexpr OUStringLiteral ISVISIBLE = u"IsVisible";
+const char EQUALS[] = "=";
+const char NOTEQUALS[] = "<>";
+const char GREATERTHAN[] = ">";
+const char GREATERTHANEQUALS[] = ">=";
+const char LESSTHAN[] = "<";
+const char LESSTHANEQUALS[] = "<=";
+constexpr OUStringLiteral STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY(u"The command you chose cannot be performed with multiple selections.\nSelect a single range and click the command again");
+constexpr OUStringLiteral CELLSTYLE = u"CellStyle";
+
+namespace {
+
+class CellValueSetter : public ValueSetter
+{
+protected:
+ uno::Any maValue;
+public:
+ explicit CellValueSetter( const uno::Any& aValue );
+ virtual bool processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell ) override;
+ virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override;
+
+};
+
+}
+
+CellValueSetter::CellValueSetter( const uno::Any& aValue ): maValue( aValue ) {}
+
+void
+CellValueSetter::visitNode( sal_Int32 /*i*/, sal_Int32 /*j*/, const uno::Reference< table::XCell >& xCell )
+{
+ processValue( maValue, xCell );
+}
+
+bool
+CellValueSetter::processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell )
+{
+
+ bool isExtracted = false;
+ switch ( aValue.getValueTypeClass() )
+ {
+ case uno::TypeClass_BOOLEAN:
+ {
+ bool bState = false;
+ if ( aValue >>= bState )
+ {
+ uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW );
+ if ( bState )
+ xCell->setValue( double(1) );
+ else
+ xCell->setValue( double(0) );
+ NumFormatHelper cellNumFormat( xRange );
+ cellNumFormat.setNumberFormat( util::NumberFormat::LOGICAL );
+ }
+ break;
+ }
+ case uno::TypeClass_STRING:
+ {
+ OUString aString;
+ if ( aValue >>= aString )
+ {
+ // The required behavior for a string value is:
+ // 1. If the first character is a single quote, use the rest as a string cell, regardless of the cell's number format.
+ // 2. Otherwise, if the cell's number format is "text", use the string value as a string cell.
+ // 3. Otherwise, parse the string value in English locale, and apply a corresponding number format with the cell's locale
+ // if the cell's number format was "General".
+ // Case 1 is handled here, the rest in ScCellObj::InputEnglishString
+
+ if ( aString.toChar() == '\'' ) // case 1 - handle with XTextRange
+ {
+ OUString aRemainder( aString.copy(1) ); // strip the quote
+ uno::Reference< text::XTextRange > xTextRange( xCell, uno::UNO_QUERY_THROW );
+ xTextRange->setString( aRemainder );
+ }
+ else
+ {
+ // call implementation method InputEnglishString
+ ScCellObj* pCellObj = dynamic_cast< ScCellObj* >( xCell.get() );
+ if ( pCellObj )
+ pCellObj->InputEnglishString( aString );
+ }
+ }
+ else
+ isExtracted = false;
+ break;
+ }
+ default:
+ {
+ double nDouble = 0.0;
+ if ( aValue >>= nDouble )
+ {
+ uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW );
+ NumFormatHelper cellFormat( xRange );
+ // If we are setting a number and the cell types was logical
+ // then we need to reset the logical format. ( see case uno::TypeClass_BOOLEAN:
+ // handling above )
+ if ( cellFormat.isBooleanType() )
+ cellFormat.setNumberFormat("General");
+ xCell->setValue( nDouble );
+ }
+ else
+ isExtracted = false;
+ break;
+ }
+ }
+ return isExtracted;
+
+}
+
+namespace {
+
+class CellValueGetter : public ValueGetter
+{
+protected:
+ uno::Any maValue;
+public:
+ CellValueGetter() {}
+ virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override;
+ virtual void processValue( const uno::Any& aValue ) override;
+ const uno::Any& getValue() const override { return maValue; }
+
+};
+
+}
+
+void
+CellValueGetter::processValue( const uno::Any& aValue )
+{
+ maValue = aValue;
+}
+void CellValueGetter::visitNode( sal_Int32 /*x*/, sal_Int32 /*y*/, const uno::Reference< table::XCell >& xCell )
+{
+ uno::Any aValue;
+ table::CellContentType eType = xCell->getType();
+ if( eType == table::CellContentType_VALUE || eType == table::CellContentType_FORMULA )
+ {
+ if ( eType == table::CellContentType_FORMULA )
+ {
+
+ OUString sFormula = xCell->getFormula();
+ if ( sFormula == "=TRUE()" )
+ aValue <<= true;
+ else if ( sFormula == "=FALSE()" )
+ aValue <<= false;
+ else
+ {
+ uno::Reference< beans::XPropertySet > xProp( xCell, uno::UNO_QUERY_THROW );
+
+ sal_Int32 nResultType = sheet::FormulaResult::VALUE;
+ // some formulas give textual results
+ xProp->getPropertyValue( "FormulaResultType2" ) >>= nResultType;
+
+ if ( nResultType == sheet::FormulaResult::STRING )
+ {
+ uno::Reference< text::XTextRange > xTextRange(xCell, ::uno::UNO_QUERY_THROW);
+ aValue <<= xTextRange->getString();
+ }
+ else
+ aValue <<= xCell->getValue();
+ }
+ }
+ else
+ {
+ uno::Reference< table::XCellRange > xRange( xCell, uno::UNO_QUERY_THROW );
+ NumFormatHelper cellFormat( xRange );
+ if ( cellFormat.isBooleanType() )
+ aValue <<= ( xCell->getValue() != 0.0 );
+ else if ( cellFormat.isDateType() )
+ aValue <<= bridge::oleautomation::Date( xCell->getValue() );
+ else
+ aValue <<= xCell->getValue();
+ }
+ }
+ if( eType == table::CellContentType_TEXT )
+ {
+ uno::Reference< text::XTextRange > xTextRange(xCell, ::uno::UNO_QUERY_THROW);
+ aValue <<= xTextRange->getString();
+ }
+ processValue( aValue );
+}
+
+namespace {
+
+class CellFormulaValueSetter : public CellValueSetter
+{
+private:
+ ScDocument& m_rDoc;
+ formula::FormulaGrammar::Grammar m_eGrammar;
+public:
+ CellFormulaValueSetter( const uno::Any& aValue, ScDocument& rDoc, formula::FormulaGrammar::Grammar eGram ):CellValueSetter( aValue ), m_rDoc( rDoc ), m_eGrammar( eGram ){}
+protected:
+ bool processValue( const uno::Any& aValue, const uno::Reference< table::XCell >& xCell ) override
+ {
+ OUString sFormula;
+ double aDblValue = 0.0;
+ if ( aValue >>= sFormula )
+ {
+ // convert to GRAM_API style grammar because XCell::setFormula
+ // always compile it in that grammar. Perhaps
+ // css.sheet.FormulaParser should be used in future to directly
+ // pass formula tokens when that API stabilizes.
+ if ( m_eGrammar != formula::FormulaGrammar::GRAM_API && ( o3tl::starts_with(o3tl::trim(sFormula), u"=") ) )
+ {
+ uno::Reference< uno::XInterface > xIf( xCell, uno::UNO_QUERY_THROW );
+ ScCellRangesBase* pUnoRangesBase = dynamic_cast< ScCellRangesBase* >( xIf.get() );
+ if ( pUnoRangesBase )
+ {
+ const ScRangeList& rCellRanges = pUnoRangesBase->GetRangeList();
+ if (!rCellRanges.empty())
+ {
+ ScCompiler aCompiler( m_rDoc, rCellRanges.front().aStart, m_eGrammar );
+ // compile the string in the format passed in
+ std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sFormula));
+ // convert to API grammar
+ aCompiler.SetGrammar( formula::FormulaGrammar::GRAM_API );
+ OUString sConverted;
+ aCompiler.CreateStringFromTokenArray(sConverted);
+ sFormula = EQUALS + sConverted;
+ }
+ }
+ }
+
+ xCell->setFormula( sFormula );
+ return true;
+ }
+ else if ( aValue >>= aDblValue )
+ {
+ xCell->setValue( aDblValue );
+ return true;
+ }
+ return false;
+ }
+
+};
+
+class CellFormulaValueGetter : public CellValueGetter
+{
+private:
+ ScDocument& m_rDoc;
+ formula::FormulaGrammar::Grammar m_eGrammar;
+public:
+ CellFormulaValueGetter(ScDocument& rDoc, formula::FormulaGrammar::Grammar eGram ) : m_rDoc( rDoc ), m_eGrammar( eGram ) {}
+ virtual void visitNode( sal_Int32 /*x*/, sal_Int32 /*y*/, const uno::Reference< table::XCell >& xCell ) override
+ {
+ uno::Any aValue;
+ aValue <<= xCell->getFormula();
+ // XCell::getFormula() returns the formula in API grammar, convert.
+ if ((xCell->getType() == table::CellContentType_FORMULA)
+ && m_eGrammar != formula::FormulaGrammar::GRAM_API)
+ {
+ uno::Reference< uno::XInterface > xIf( xCell, uno::UNO_QUERY_THROW );
+ ScCellRangesBase* pUnoRangesBase = dynamic_cast< ScCellRangesBase* >( xIf.get() );
+ if (pUnoRangesBase)
+ {
+ OUString sVal;
+ aValue >>= sVal;
+ const ScRangeList& rCellRanges = pUnoRangesBase->GetRangeList();
+ if (!rCellRanges.empty())
+ {
+ // Compile string from API grammar.
+ ScCompiler aCompiler( m_rDoc, rCellRanges.front().aStart, formula::FormulaGrammar::GRAM_API );
+ std::unique_ptr<ScTokenArray> pArray(aCompiler.CompileString(sVal));
+ // Convert to desired grammar.
+ aCompiler.SetGrammar( m_eGrammar );
+ OUString sConverted;
+ aCompiler.CreateStringFromTokenArray(sConverted);
+ sVal = EQUALS + sConverted;
+ aValue <<= sVal;
+ }
+ }
+ }
+
+ processValue( aValue );
+ }
+
+};
+
+class Dim2ArrayValueGetter : public ArrayVisitor
+{
+protected:
+ uno::Any maValue;
+ ValueGetter& mValueGetter;
+ void processValue( sal_Int32 x, sal_Int32 y, const uno::Any& aValue )
+ {
+ uno::Sequence< uno::Sequence< uno::Any > >& aMatrix = const_cast<css::uno::Sequence<css::uno::Sequence<css::uno::Any>> &>(*o3tl::doAccess<uno::Sequence<uno::Sequence<uno::Any>>>(maValue));
+ aMatrix.getArray()[x].getArray()[y] = aValue;
+ }
+
+public:
+ Dim2ArrayValueGetter(sal_Int32 nRowCount, sal_Int32 nColCount, ValueGetter& rValueGetter ): mValueGetter(rValueGetter)
+ {
+ uno::Sequence< uno::Sequence< uno::Any > > aMatrix;
+ aMatrix.realloc( nRowCount );
+ auto pMatrix = aMatrix.getArray();
+ for ( sal_Int32 index = 0; index < nRowCount; ++index )
+ pMatrix[index].realloc( nColCount );
+ maValue <<= aMatrix;
+ }
+ void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override
+
+ {
+ mValueGetter.visitNode( x, y, xCell );
+ processValue( x, y, mValueGetter.getValue() );
+ }
+ const uno::Any& getValue() const { return maValue; }
+
+};
+
+}
+
+constexpr OUStringLiteral sNA = u"#N/A";
+
+namespace {
+
+class Dim1ArrayValueSetter : public ArrayVisitor
+{
+ uno::Sequence< uno::Any > aMatrix;
+ sal_Int32 nColCount;
+ ValueSetter& mCellValueSetter;
+public:
+ Dim1ArrayValueSetter( const uno::Any& aValue, ValueSetter& rCellValueSetter ):mCellValueSetter( rCellValueSetter )
+ {
+ aValue >>= aMatrix;
+ nColCount = aMatrix.getLength();
+ }
+ virtual void visitNode( sal_Int32 /*x*/, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override
+ {
+ if ( y < nColCount )
+ mCellValueSetter.processValue( aMatrix[ y ], xCell );
+ else
+ mCellValueSetter.processValue( uno::Any( OUString(sNA) ), xCell );
+ }
+};
+
+class Dim2ArrayValueSetter : public ArrayVisitor
+{
+ uno::Sequence< uno::Sequence< uno::Any > > aMatrix;
+ ValueSetter& mCellValueSetter;
+ sal_Int32 nRowCount;
+ sal_Int32 nColCount;
+public:
+ Dim2ArrayValueSetter( const uno::Any& aValue, ValueSetter& rCellValueSetter ) : mCellValueSetter( rCellValueSetter )
+ {
+ aValue >>= aMatrix;
+ nRowCount = aMatrix.getLength();
+ nColCount = aMatrix[0].getLength();
+ }
+
+ virtual void visitNode( sal_Int32 x, sal_Int32 y, const uno::Reference< table::XCell >& xCell ) override
+ {
+ if ( x < nRowCount && y < nColCount )
+ mCellValueSetter.processValue( aMatrix[ x ][ y ], xCell );
+ else
+ mCellValueSetter.processValue( uno::Any( OUString(sNA) ), xCell );
+
+ }
+};
+
+class RangeProcessor
+{
+public:
+ virtual void process( const uno::Reference< excel::XRange >& xRange ) = 0;
+
+protected:
+ ~RangeProcessor() {}
+};
+
+class RangeValueProcessor : public RangeProcessor
+{
+ const uno::Any& m_aVal;
+public:
+ explicit RangeValueProcessor( const uno::Any& rVal ):m_aVal( rVal ) {}
+ virtual ~RangeValueProcessor() {}
+ virtual void process( const uno::Reference< excel::XRange >& xRange ) override
+ {
+ xRange->setValue( m_aVal );
+ }
+};
+
+class RangeFormulaProcessor : public RangeProcessor
+{
+ const uno::Any& m_aVal;
+public:
+ explicit RangeFormulaProcessor( const uno::Any& rVal ):m_aVal( rVal ) {}
+ virtual ~RangeFormulaProcessor() {}
+ virtual void process( const uno::Reference< excel::XRange >& xRange ) override
+ {
+ xRange->setFormula( m_aVal );
+ }
+};
+
+class RangeCountProcessor : public RangeProcessor
+{
+ sal_Int32 nCount;
+public:
+ RangeCountProcessor():nCount(0){}
+ virtual ~RangeCountProcessor() {}
+ virtual void process( const uno::Reference< excel::XRange >& xRange ) override
+ {
+ nCount = nCount + xRange->getCount();
+ }
+ sal_Int32 value() { return nCount; }
+};
+class AreasVisitor
+{
+private:
+ uno::Reference< XCollection > m_Areas;
+public:
+ explicit AreasVisitor( const uno::Reference< XCollection >& rAreas ):m_Areas( rAreas ){}
+
+ void visit( RangeProcessor& processor )
+ {
+ if ( m_Areas.is() )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ processor.process( xRange );
+ }
+ }
+ }
+};
+
+class RangeHelper
+{
+ uno::Reference< table::XCellRange > m_xCellRange;
+
+public:
+ /// @throws uno::RuntimeException
+ explicit RangeHelper( const uno::Reference< table::XCellRange >& xCellRange ) : m_xCellRange( xCellRange )
+ {
+ if ( !m_xCellRange.is() )
+ throw uno::RuntimeException();
+ }
+ /// @throws uno::RuntimeException
+ explicit RangeHelper( const uno::Any& rCellRange )
+ {
+ m_xCellRange.set(rCellRange, uno::UNO_QUERY_THROW);
+ }
+ /// @throws uno::RuntimeException
+ uno::Reference< sheet::XSheetCellRange > getSheetCellRange() const
+ {
+ return uno::Reference< sheet::XSheetCellRange >(m_xCellRange, uno::UNO_QUERY_THROW);
+ }
+ /// @throws uno::RuntimeException
+ uno::Reference< sheet::XSpreadsheet > getSpreadSheet() const
+ {
+ return getSheetCellRange()->getSpreadsheet();
+ }
+
+ /// @throws uno::RuntimeException
+ uno::Reference< table::XCellRange > getCellRangeFromSheet() const
+ {
+ return uno::Reference< table::XCellRange >(getSpreadSheet(), uno::UNO_QUERY_THROW );
+ }
+
+ /// @throws uno::RuntimeException
+ uno::Reference< sheet::XCellRangeAddressable > getCellRangeAddressable() const
+ {
+ return uno::Reference< sheet::XCellRangeAddressable >(m_xCellRange, ::uno::UNO_QUERY_THROW);
+
+ }
+
+ /// @throws uno::RuntimeException
+ uno::Reference< sheet::XSheetCellCursor > getSheetCellCursor() const
+ {
+ return uno::Reference< sheet::XSheetCellCursor >( getSpreadSheet()->createCursorByRange( getSheetCellRange() ), uno::UNO_SET_THROW );
+ }
+
+ static uno::Reference< excel::XRange > createRangeFromRange( const uno::Reference< XHelperInterface >& xParent, const uno::Reference<uno::XComponentContext >& xContext,
+ const uno::Reference< table::XCellRange >& xRange, const uno::Reference< sheet::XCellRangeAddressable >& xCellRangeAddressable )
+ {
+ const table::CellRangeAddress aRA( xCellRangeAddressable->getRangeAddress());
+ return uno::Reference< excel::XRange >( new ScVbaRange( xParent, xContext,
+ xRange->getCellRangeByPosition( aRA.StartColumn, aRA.StartRow, aRA.EndColumn, aRA.EndRow)));
+ }
+
+};
+
+}
+
+bool
+ScVbaRange::getCellRangesForAddress( ScRefFlags& rResFlags, std::u16string_view sAddress, ScDocShell* pDocSh, ScRangeList& rCellRanges, formula::FormulaGrammar::AddressConvention eConv, char cDelimiter )
+{
+
+ if ( pDocSh )
+ {
+ ScDocument& rDoc = pDocSh->GetDocument();
+ rResFlags = rCellRanges.Parse( sAddress, rDoc, eConv, 0, cDelimiter );
+ if ( rResFlags & ScRefFlags::VALID )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool getScRangeListForAddress( const OUString& sName, ScDocShell* pDocSh, const ScRange& refRange, ScRangeList& aCellRanges, formula::FormulaGrammar::AddressConvention aConv )
+{
+ // see if there is a match with a named range
+ uno::Reference< beans::XPropertySet > xProps( pDocSh->GetModel(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xNameAccess( xProps->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW );
+ // Strange enough you can have Range( "namedRange1, namedRange2, etc," )
+ // loop around each ',' separated name
+ std::vector< OUString > vNames;
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OUString aToken = sName.getToken( 0, ',', nIndex );
+ vNames.push_back( aToken );
+ } while ( nIndex >= 0 );
+
+ if ( vNames.empty() )
+ vNames.push_back( sName );
+
+ for ( const auto& rName : vNames )
+ {
+ formula::FormulaGrammar::AddressConvention eConv = aConv;
+ // spaces are illegal ( but the user of course can enter them )
+ OUString sAddress = rName.trim();
+ // if a local name ( on the active sheet ) exists this will
+ // take precedence over a global with the same name
+ if ( !xNameAccess->hasByName( sAddress ) )
+ {
+ // try a local name
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nCurTab = ScDocShell::GetCurTab();
+ ScRangeName* pRangeName = rDoc.GetRangeName(nCurTab);
+ if (pRangeName)
+ {
+ // TODO: Handle local names correctly:
+ // bool bLocalName = pRangeName->findByUpperName(ScGlobal::getCharClass().uppercase(sAddress)) != nullptr;
+ }
+ }
+ char aChar = 0;
+ if ( xNameAccess->hasByName( sAddress ) )
+ {
+ uno::Reference< sheet::XNamedRange > xNamed( xNameAccess->getByName( sAddress ), uno::UNO_QUERY_THROW );
+ sAddress = xNamed->getContent();
+ // As the address comes from OOO, the addressing
+ // style is may not be XL_A1
+ eConv = pDocSh->GetDocument().GetAddressConvention();
+ aChar = ';';
+ }
+
+ ScRefFlags nFlags = ScRefFlags::ZERO;
+ if ( !ScVbaRange::getCellRangesForAddress( nFlags, sAddress, pDocSh, aCellRanges, eConv, aChar ) )
+ return false;
+
+ bool bTabFromReferrer = !( nFlags & ScRefFlags::TAB_3D );
+
+ for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i )
+ {
+ ScRange & rRange = aCellRanges[ i ];
+ rRange.aStart.SetCol( refRange.aStart.Col() + rRange.aStart.Col() );
+ rRange.aStart.SetRow( refRange.aStart.Row() + rRange.aStart.Row() );
+ rRange.aStart.SetTab( bTabFromReferrer ? refRange.aStart.Tab() : rRange.aStart.Tab() );
+ rRange.aEnd.SetCol( refRange.aStart.Col() + rRange.aEnd.Col() );
+ rRange.aEnd.SetRow( refRange.aStart.Row() + rRange.aEnd.Row() );
+ rRange.aEnd.SetTab( bTabFromReferrer ? refRange.aEnd.Tab() : rRange.aEnd.Tab() );
+ }
+ }
+ return true;
+}
+
+/// @throws uno::RuntimeException
+static rtl::Reference<ScVbaRange>
+getRangeForName( const uno::Reference< uno::XComponentContext >& xContext, const OUString& sName, ScDocShell* pDocSh, const table::CellRangeAddress& pAddr, formula::FormulaGrammar::AddressConvention eConv = formula::FormulaGrammar::CONV_XL_A1 )
+{
+ ScRangeList aCellRanges;
+ ScRange refRange;
+ ScUnoConversion::FillScRange( refRange, pAddr );
+ if ( !getScRangeListForAddress ( sName, pDocSh, refRange, aCellRanges, eConv ) )
+ throw uno::RuntimeException();
+ // Single range
+ if ( aCellRanges.size() == 1 )
+ {
+ uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pDocSh, aCellRanges.front() ) );
+ uno::Reference< XHelperInterface > xFixThisParent = excel::getUnoSheetModuleObj( xRange );
+ return new ScVbaRange( xFixThisParent, xContext, xRange );
+ }
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pDocSh, aCellRanges ) );
+
+ uno::Reference< XHelperInterface > xFixThisParent = excel::getUnoSheetModuleObj( xRanges );
+ return new ScVbaRange( xFixThisParent, xContext, xRanges );
+}
+
+namespace {
+
+/// @throws uno::RuntimeException
+template< typename RangeType >
+table::CellRangeAddress lclGetRangeAddress( const uno::Reference< RangeType >& rxCellRange )
+{
+ return uno::Reference< sheet::XCellRangeAddressable >( rxCellRange, uno::UNO_QUERY_THROW )->getRangeAddress();
+}
+
+/// @throws uno::RuntimeException
+void lclClearRange( const uno::Reference< table::XCellRange >& rxCellRange )
+{
+ using namespace ::com::sun::star::sheet::CellFlags;
+ sal_Int32 const nFlags = VALUE | DATETIME | STRING | ANNOTATION | FORMULA | HARDATTR | STYLES | EDITATTR | FORMATTED;
+ uno::Reference< sheet::XSheetOperation > xSheetOperation( rxCellRange, uno::UNO_QUERY_THROW );
+ xSheetOperation->clearContents( nFlags );
+}
+
+/// @throws uno::RuntimeException
+uno::Reference< sheet::XSheetCellRange > lclExpandToMerged( const uno::Reference< table::XCellRange >& rxCellRange, bool bRecursive )
+{
+ uno::Reference< sheet::XSheetCellRange > xNewCellRange( rxCellRange, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheet > xSheet( xNewCellRange->getSpreadsheet(), uno::UNO_SET_THROW );
+ table::CellRangeAddress aNewAddress = lclGetRangeAddress( xNewCellRange );
+ table::CellRangeAddress aOldAddress;
+ // expand as long as there are new merged ranges included
+ do
+ {
+ aOldAddress = aNewAddress;
+ uno::Reference< sheet::XSheetCellCursor > xCursor( xSheet->createCursorByRange( xNewCellRange ), uno::UNO_SET_THROW );
+ if (xCursor.is())
+ {
+ xCursor->collapseToMergedArea();
+ xNewCellRange.set( xCursor, uno::UNO_QUERY_THROW );
+ aNewAddress = lclGetRangeAddress( xNewCellRange );
+ }
+ }
+ while( bRecursive && (aOldAddress != aNewAddress) );
+ return xNewCellRange;
+}
+
+/// @throws uno::RuntimeException
+uno::Reference< sheet::XSheetCellRangeContainer > lclExpandToMerged( const uno::Reference< sheet::XSheetCellRangeContainer >& rxCellRanges )
+{
+ if( !rxCellRanges.is() )
+ throw uno::RuntimeException("Missing cell ranges object" );
+ sal_Int32 nCount = rxCellRanges->getCount();
+ if( nCount < 1 )
+ throw uno::RuntimeException("Missing cell ranges object" );
+
+ ScRangeList aScRanges;
+ for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ uno::Reference< table::XCellRange > xRange( rxCellRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW );
+ table::CellRangeAddress aRangeAddr = lclGetRangeAddress( lclExpandToMerged( xRange, /*bRecursive*/true ) );
+ ScRange aScRange;
+ ScUnoConversion::FillScRange( aScRange, aRangeAddr );
+ aScRanges.push_back( aScRange );
+ }
+ return new ScCellRangesObj( getDocShellFromRanges( rxCellRanges ), aScRanges );
+}
+
+/// @throws uno::RuntimeException
+void lclExpandAndMerge( const uno::Reference< table::XCellRange >& rxCellRange, bool bMerge )
+{
+ uno::Reference< util::XMergeable > xMerge( lclExpandToMerged( rxCellRange, true ), uno::UNO_QUERY_THROW );
+ // Calc cannot merge over merged ranges, always unmerge first
+ xMerge->merge( false );
+ if( !bMerge )
+ return;
+
+ // clear all contents of the covered cells (not the top-left cell)
+ table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxCellRange );
+ sal_Int32 nLastColIdx = aRangeAddr.EndColumn - aRangeAddr.StartColumn;
+ sal_Int32 nLastRowIdx = aRangeAddr.EndRow - aRangeAddr.StartRow;
+ // clear cells of top row, right of top-left cell
+ if( nLastColIdx > 0 )
+ lclClearRange( rxCellRange->getCellRangeByPosition( 1, 0, nLastColIdx, 0 ) );
+ // clear all rows below top row
+ if( nLastRowIdx > 0 )
+ lclClearRange( rxCellRange->getCellRangeByPosition( 0, 1, nLastColIdx, nLastRowIdx ) );
+ // merge the range
+ xMerge->merge( true );
+}
+
+/// @throws uno::RuntimeException
+util::TriState lclGetMergedState( const uno::Reference< table::XCellRange >& rxCellRange )
+{
+ /* 1) Check if range is completely inside one single merged range. To do
+ this, try to extend from top-left cell only (not from entire range).
+ This will exclude cases where this range consists of several merged
+ ranges (or parts of them). */
+ table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxCellRange );
+ uno::Reference< table::XCellRange > xTopLeft( rxCellRange->getCellRangeByPosition( 0, 0, 0, 0 ), uno::UNO_SET_THROW );
+ uno::Reference< sheet::XSheetCellRange > xExpanded( lclExpandToMerged( xTopLeft, false ), uno::UNO_SET_THROW );
+ table::CellRangeAddress aExpAddr = lclGetRangeAddress( xExpanded );
+ // check that expanded range has more than one cell (really merged)
+ if( ((aExpAddr.StartColumn < aExpAddr.EndColumn) || (aExpAddr.StartRow < aExpAddr.EndRow)) && ScUnoConversion::Contains( aExpAddr, aRangeAddr ) )
+ return util::TriState_YES;
+
+ /* 2) Check if this range contains any merged cells (completely or
+ partly). This seems to be hardly possible via API, as
+ XMergeable::getIsMerged() returns only true, if the top-left cell of a
+ merged range is part of this range, so cases where just the lower part
+ of a merged range is part of this range are not covered. */
+ ScRange aScRange;
+ ScUnoConversion::FillScRange( aScRange, aRangeAddr );
+ bool bHasMerged = getDocumentFromRange( rxCellRange ).HasAttrib( aScRange, HasAttrFlags::Merged | HasAttrFlags::Overlapped );
+ return bHasMerged ? util::TriState_INDETERMINATE : util::TriState_NO;
+}
+
+} // namespace
+
+css::uno::Reference< excel::XRange >
+ScVbaRange::getRangeObjectForName(
+ const uno::Reference< uno::XComponentContext >& xContext, const OUString& sRangeName,
+ ScDocShell* pDocSh, formula::FormulaGrammar::AddressConvention eConv )
+{
+ table::CellRangeAddress refAddr;
+ return getRangeForName( xContext, sRangeName, pDocSh, refAddr, eConv );
+}
+
+/// @throws uno::RuntimeException
+static table::CellRangeAddress getCellRangeAddressForVBARange( const uno::Any& aParam, ScDocShell* pDocSh )
+{
+ uno::Reference< table::XCellRange > xRangeParam;
+ switch ( aParam.getValueTypeClass() )
+ {
+ case uno::TypeClass_STRING:
+ {
+ OUString rString;
+ aParam >>= rString;
+ ScRangeList aCellRanges;
+ ScRange refRange;
+ if ( getScRangeListForAddress ( rString, pDocSh, refRange, aCellRanges ) )
+ {
+ if ( aCellRanges.size() == 1 )
+ {
+ table::CellRangeAddress aRangeAddress;
+ ScUnoConversion::FillApiRange( aRangeAddress, aCellRanges.front() );
+ return aRangeAddress;
+ }
+ }
+ }
+ break;
+
+ case uno::TypeClass_INTERFACE:
+ {
+ uno::Reference< excel::XRange > xRange;
+ aParam >>= xRange;
+ if ( xRange.is() )
+ xRange->getCellRange() >>= xRangeParam;
+ }
+ break;
+
+ default:
+ throw uno::RuntimeException("Can't extract CellRangeAddress from type" );
+ }
+ return lclGetRangeAddress( xRangeParam );
+}
+
+/// @throws uno::RuntimeException
+static uno::Reference< XCollection >
+lcl_setupBorders( const uno::Reference< excel::XRange >& xParentRange, const uno::Reference<uno::XComponentContext>& xContext, const uno::Reference< table::XCellRange >& xRange )
+{
+ uno::Reference< XHelperInterface > xParent( xParentRange, uno::UNO_QUERY_THROW );
+ ScDocument& rDoc = getDocumentFromRange(xRange);
+ ScVbaPalette aPalette( rDoc.GetDocumentShell() );
+ uno::Reference< XCollection > borders( new ScVbaBorders( xParent, xContext, xRange, aPalette ) );
+ return borders;
+}
+
+ScVbaRange::ScVbaRange( uno::Sequence< uno::Any> const & args,
+ uno::Reference< uno::XComponentContext> const & xContext ) : ScVbaRange_BASE( getXSomethingFromArgs< XHelperInterface >( args, 0 ), xContext, getXSomethingFromArgs< beans::XPropertySet >( args, 1, false ), getModelFromXIf( getXSomethingFromArgs< uno::XInterface >( args, 1 ) ), true ), mbIsRows( false ), mbIsColumns( false )
+{
+ mxRange.set( mxPropertySet, uno::UNO_QUERY );
+ mxRanges.set( mxPropertySet, uno::UNO_QUERY );
+ uno::Reference< container::XIndexAccess > xIndex;
+ if ( mxRange.is() )
+ {
+ xIndex = new SingleRangeIndexAccess( mxRange );
+ }
+ else if ( mxRanges.is() )
+ {
+ xIndex.set( mxRanges, uno::UNO_QUERY_THROW );
+ }
+ m_Areas = new ScVbaRangeAreas( mxParent, mxContext, xIndex, mbIsRows, mbIsColumns );
+}
+
+ScVbaRange::ScVbaRange( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< table::XCellRange >& xRange, bool bIsRows, bool bIsColumns )
+: ScVbaRange_BASE( xParent, xContext, uno::Reference< beans::XPropertySet >( xRange, uno::UNO_QUERY_THROW ), getModelFromRange( xRange), true ), mxRange( xRange ),
+ mbIsRows( bIsRows ),
+ mbIsColumns( bIsColumns )
+{
+ if ( !xContext.is() )
+ throw lang::IllegalArgumentException("context is not set ", uno::Reference< uno::XInterface >() , 1 );
+ if ( !xRange.is() )
+ throw lang::IllegalArgumentException("range is not set ", uno::Reference< uno::XInterface >() , 1 );
+
+ uno::Reference< container::XIndexAccess > xIndex( new SingleRangeIndexAccess( xRange ) );
+ m_Areas = new ScVbaRangeAreas( mxParent, mxContext, xIndex, mbIsRows, mbIsColumns );
+
+}
+
+ScVbaRange::ScVbaRange(const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< sheet::XSheetCellRangeContainer >& xRanges, bool bIsRows, bool bIsColumns)
+: ScVbaRange_BASE( xParent, xContext, uno::Reference< beans::XPropertySet >( xRanges, uno::UNO_QUERY_THROW ), getModelFromXIf( uno::Reference< uno::XInterface >( xRanges, uno::UNO_QUERY_THROW ) ), true ), mxRanges( xRanges ),mbIsRows( bIsRows ), mbIsColumns( bIsColumns )
+
+{
+ uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW );
+ m_Areas = new ScVbaRangeAreas( xParent, mxContext, xIndex, mbIsRows, mbIsColumns );
+
+}
+
+ScVbaRange::~ScVbaRange()
+{
+}
+
+uno::Reference< XCollection >& ScVbaRange::getBorders()
+{
+ if ( !m_Borders.is() )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW );
+ m_Borders = lcl_setupBorders( this, mxContext, uno::Reference< table::XCellRange >( xRange->getCellRange(), uno::UNO_QUERY_THROW ) );
+ }
+ return m_Borders;
+}
+
+void
+ScVbaRange::visitArray( ArrayVisitor& visitor )
+{
+ ScDocShell* pDocSh = nullptr;
+ if(ScCellRangeObj* range = dynamic_cast<ScCellRangeObj*>(mxRange.get()))
+ pDocSh = range->GetDocShell();
+ if ( pDocSh )
+ pDocSh->LockPaint();
+ table::CellRangeAddress aRangeAddr = lclGetRangeAddress( mxRange );
+ sal_Int32 nRowCount = aRangeAddr.EndRow - aRangeAddr.StartRow + 1;
+ sal_Int32 nColCount = aRangeAddr.EndColumn - aRangeAddr.StartColumn + 1;
+ for ( sal_Int32 i=0; i<nRowCount; ++i )
+ {
+ for ( sal_Int32 j=0; j<nColCount; ++j )
+ {
+ uno::Reference< table::XCell > xCell( mxRange->getCellByPosition( j, i ), uno::UNO_SET_THROW );
+
+ visitor.visitNode( i, j, xCell );
+ }
+ }
+ if ( pDocSh )
+ pDocSh->UnlockPaint();
+}
+
+uno::Any
+ScVbaRange::getValue( ValueGetter& valueGetter)
+{
+ uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY_THROW );
+ // single cell range
+ if ( isSingleCellRange() )
+ {
+ visitArray( valueGetter );
+ return valueGetter.getValue();
+ }
+ sal_Int32 nRowCount = xColumnRowRange->getRows()->getCount();
+ sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount();
+ // multi cell range ( return array )
+ Dim2ArrayValueGetter arrayGetter( nRowCount, nColCount, valueGetter );
+ visitArray( arrayGetter );
+ return uno::Any( script::ArrayWrapper( false, arrayGetter.getValue() ) );
+}
+
+uno::Any SAL_CALL
+ScVbaRange::getValue()
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->getValue();
+ }
+
+ CellValueGetter valueGetter;
+ return getValue( valueGetter );
+
+}
+
+void
+ScVbaRange::setValue( const uno::Any& aValue, ValueSetter& valueSetter )
+{
+ uno::TypeClass aClass = aValue.getValueTypeClass();
+ if ( aClass == uno::TypeClass_SEQUENCE )
+ {
+ const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext );
+ uno::Any aConverted;
+ try
+ {
+ // test for single dimension, could do
+ // with a better test than this
+ if ( aValue.getValueTypeName().indexOf('[') == aValue.getValueTypeName().lastIndexOf('[') )
+ {
+ aConverted = xConverter->convertTo( aValue, cppu::UnoType<uno::Sequence< uno::Any >>::get() );
+ Dim1ArrayValueSetter setter( aConverted, valueSetter );
+ visitArray( setter );
+ }
+ else
+ {
+ aConverted = xConverter->convertTo( aValue, cppu::UnoType<uno::Sequence< uno::Sequence< uno::Any > >>::get() );
+ Dim2ArrayValueSetter setter( aConverted, valueSetter );
+ visitArray( setter );
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("sc", "Bahhh, caught" );
+ }
+ }
+ else
+ {
+ visitArray( valueSetter );
+ }
+ fireChangeEvent();
+}
+
+void SAL_CALL
+ScVbaRange::setValue( const uno::Any &aValue )
+{
+ // If this is a multiple selection apply setValue over all areas
+ if ( m_Areas->getCount() > 1 )
+ {
+ AreasVisitor aVisitor( m_Areas );
+ RangeValueProcessor valueProcessor( aValue );
+ aVisitor.visit( valueProcessor );
+ return;
+ }
+ CellValueSetter valueSetter( aValue );
+ setValue( aValue, valueSetter );
+}
+
+void SAL_CALL
+ScVbaRange::Clear()
+{
+ using namespace ::com::sun::star::sheet::CellFlags;
+ sal_Int32 const nFlags = VALUE | DATETIME | STRING | FORMULA | HARDATTR | EDITATTR | FORMATTED;
+ ClearContents( nFlags, true );
+}
+
+//helper ClearContent
+void
+ScVbaRange::ClearContents( sal_Int32 nFlags, bool bFireEvent )
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ ScVbaRange* pRange = getImplementation( xRange );
+ if ( pRange )
+ pRange->ClearContents( nFlags, false ); // do not fire for single ranges
+ }
+ // fire change event for the entire range list
+ if( bFireEvent ) fireChangeEvent();
+ return;
+ }
+
+ uno::Reference< sheet::XSheetOperation > xSheetOperation(mxRange, uno::UNO_QUERY_THROW);
+ xSheetOperation->clearContents( nFlags );
+ if( bFireEvent ) fireChangeEvent();
+}
+
+void SAL_CALL
+ScVbaRange::ClearComments()
+{
+ ClearContents( sheet::CellFlags::ANNOTATION, false );
+}
+
+void SAL_CALL
+ScVbaRange::ClearContents()
+{
+ using namespace ::com::sun::star::sheet::CellFlags;
+ sal_Int32 const nFlags = VALUE | DATETIME | STRING | FORMULA;
+ ClearContents( nFlags, true );
+}
+
+void SAL_CALL
+ScVbaRange::ClearFormats()
+{
+ // FIXME: need to check if we need to combine FORMATTED
+ using namespace ::com::sun::star::sheet::CellFlags;
+ sal_Int32 const nFlags = HARDATTR | FORMATTED | EDITATTR;
+ ClearContents( nFlags, false );
+}
+
+void
+ScVbaRange::setFormulaValue( const uno::Any& rFormula, formula::FormulaGrammar::Grammar eGram )
+{
+ // If this is a multiple selection apply setFormula over all areas
+ if ( m_Areas->getCount() > 1 )
+ {
+ AreasVisitor aVisitor( m_Areas );
+ RangeFormulaProcessor valueProcessor( rFormula );
+ aVisitor.visit( valueProcessor );
+ return;
+ }
+ CellFormulaValueSetter formulaValueSetter( rFormula, getScDocument(), eGram );
+ setValue( rFormula, formulaValueSetter );
+}
+
+uno::Any
+ScVbaRange::getFormulaValue( formula::FormulaGrammar::Grammar eGram )
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->getFormula();
+ }
+ CellFormulaValueGetter valueGetter( getScDocument(), eGram );
+ return getValue( valueGetter );
+
+}
+
+uno::Any
+ScVbaRange::getFormula()
+{
+ return getFormulaValue( formula::FormulaGrammar::GRAM_ENGLISH_XL_A1 );
+}
+
+void
+ScVbaRange::setFormula(const uno::Any &rFormula )
+{
+ setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_ENGLISH_XL_A1 );
+}
+
+uno::Any
+ScVbaRange::getFormulaR1C1()
+{
+ return getFormulaValue( formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1 );
+}
+
+void
+ScVbaRange::setFormulaR1C1(const uno::Any& rFormula )
+{
+ setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_ENGLISH_XL_R1C1 );
+}
+
+uno::Any
+ScVbaRange::getFormulaLocal()
+{
+ return getFormulaValue( formula::FormulaGrammar::GRAM_NATIVE_XL_A1 );
+}
+
+void
+ScVbaRange::setFormulaLocal(const uno::Any &rFormula )
+{
+ setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_NATIVE_XL_A1 );
+}
+
+uno::Any
+ScVbaRange::getFormulaR1C1Local()
+{
+ return getFormulaValue( formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 );
+}
+
+void
+ScVbaRange::setFormulaR1C1Local(const uno::Any& rFormula )
+{
+ setFormulaValue( rFormula, formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1 );
+}
+
+sal_Int32
+ScVbaRange::getCount()
+{
+ // If this is a multiple selection apply setValue over all areas
+ if ( m_Areas->getCount() > 1 )
+ {
+ AreasVisitor aVisitor( m_Areas );
+ RangeCountProcessor valueProcessor;
+ aVisitor.visit( valueProcessor );
+ return valueProcessor.value();
+ }
+ sal_Int32 rowCount = 0;
+ sal_Int32 colCount = 0;
+ uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY_THROW );
+ rowCount = xColumnRowRange->getRows()->getCount();
+ colCount = xColumnRowRange->getColumns()->getCount();
+
+ if( mbIsRows )
+ return rowCount;
+ if( mbIsColumns )
+ return colCount;
+ return rowCount * colCount;
+}
+
+sal_Int32
+ScVbaRange::getRow()
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->getRow();
+ }
+ uno::Reference< sheet::XCellAddressable > xCellAddressable(mxRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW );
+ return xCellAddressable->getCellAddress().Row + 1; // Zero value indexing
+}
+
+sal_Int32
+ScVbaRange::getColumn()
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->getColumn();
+ }
+ uno::Reference< sheet::XCellAddressable > xCellAddressable(mxRange->getCellByPosition(0, 0), uno::UNO_QUERY_THROW );
+ return xCellAddressable->getCellAddress().Column + 1; // Zero value indexing
+}
+
+uno::Any
+ScVbaRange::HasFormula()
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ uno::Any aResult = aNULL();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ // if the HasFormula for any area is different to another
+ // return null
+ if ( index > 1 )
+ if ( aResult != xRange->HasFormula() )
+ return aNULL();
+ aResult = xRange->HasFormula();
+ if ( aNULL() == aResult )
+ return aNULL();
+ }
+ return aResult;
+ }
+ uno::Reference< uno::XInterface > xIf( mxRange, uno::UNO_QUERY_THROW );
+ ScCellRangesBase* pThisRanges = dynamic_cast< ScCellRangesBase * > ( xIf.get() );
+ if ( pThisRanges )
+ {
+ uno::Reference<uno::XInterface> xRanges( pThisRanges->queryFormulaCells( sheet::FormulaResult::ERROR | sheet::FormulaResult::VALUE | sheet::FormulaResult::STRING ), uno::UNO_QUERY_THROW );
+ ScCellRangesBase* pFormulaRanges = dynamic_cast< ScCellRangesBase * > ( xRanges.get() );
+ assert(pFormulaRanges);
+ // check if there are no formula cell, return false
+ if ( pFormulaRanges->GetRangeList().empty() )
+ return uno::Any(false);
+
+ // check if there are holes (where some cells are not formulas)
+ // or returned range is not equal to this range
+ if ( ( pFormulaRanges->GetRangeList().size() > 1 )
+ || ( pFormulaRanges->GetRangeList().front().aStart != pThisRanges->GetRangeList().front().aStart )
+ || ( pFormulaRanges->GetRangeList().front().aEnd != pThisRanges->GetRangeList().front().aEnd )
+ )
+ return aNULL(); // should return aNULL;
+ }
+ return uno::Any( true );
+}
+void
+ScVbaRange::fillSeries( sheet::FillDirection nFillDirection, sheet::FillMode nFillMode, sheet::FillDateMode nFillDateMode, double fStep, double fEndValue )
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ // Multi-Area Range
+ uno::Reference< XCollection > xCollection( m_Areas, uno::UNO_SET_THROW );
+ for ( sal_Int32 index = 1; index <= xCollection->getCount(); ++index )
+ {
+ uno::Reference< excel::XRange > xRange( xCollection->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW );
+ ScVbaRange* pThisRange = getImplementation( xRange );
+ pThisRange->fillSeries( nFillDirection, nFillMode, nFillDateMode, fStep, fEndValue );
+
+ }
+ return;
+ }
+
+ uno::Reference< sheet::XCellSeries > xCellSeries(mxRange, uno::UNO_QUERY_THROW );
+ xCellSeries->fillSeries( nFillDirection, nFillMode, nFillDateMode, fStep, fEndValue );
+ fireChangeEvent();
+}
+
+void
+ScVbaRange::FillLeft()
+{
+ fillSeries(sheet::FillDirection_TO_LEFT,
+ sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF);
+}
+
+void
+ScVbaRange::FillRight()
+{
+ fillSeries(sheet::FillDirection_TO_RIGHT,
+ sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF);
+}
+
+void
+ScVbaRange::FillUp()
+{
+ fillSeries(sheet::FillDirection_TO_TOP,
+ sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF);
+}
+
+void
+ScVbaRange::FillDown()
+{
+ fillSeries(sheet::FillDirection_TO_BOTTOM,
+ sheet::FillMode_SIMPLE, sheet::FillDateMode_FILL_DATE_DAY, 0, 0x7FFFFFFF);
+}
+
+OUString
+ScVbaRange::getText()
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->getText();
+ }
+ uno::Reference< text::XTextRange > xTextRange(mxRange->getCellByPosition(0,0), uno::UNO_QUERY_THROW );
+ return xTextRange->getString();
+}
+
+uno::Reference< excel::XRange >
+ScVbaRange::Offset( const ::uno::Any &nRowOff, const uno::Any &nColOff )
+{
+ SCROW nRowOffset = 0;
+ SCCOL nColOffset = 0;
+ bool bIsRowOffset = ( nRowOff >>= nRowOffset );
+ bool bIsColumnOffset = ( nColOff >>= nColOffset );
+ ScCellRangesBase* pUnoRangesBase = getCellRangesBase();
+
+ ScRangeList aCellRanges = pUnoRangesBase->GetRangeList();
+
+ for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i )
+ {
+ ScRange & rRange = aCellRanges[ i ];
+ if ( bIsColumnOffset )
+ {
+ rRange.aStart.SetCol( rRange.aStart.Col() + nColOffset );
+ rRange.aEnd.SetCol( rRange.aEnd.Col() + nColOffset );
+ }
+ if ( bIsRowOffset )
+ {
+ rRange.aStart.SetRow( rRange.aStart.Row() + nRowOffset );
+ rRange.aEnd.SetRow( rRange.aEnd.Row() + nRowOffset );
+ }
+ }
+
+ if ( aCellRanges.size() > 1 ) // Multi-Area
+ {
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pUnoRangesBase->GetDocShell(), aCellRanges ) );
+ return new ScVbaRange( mxParent, mxContext, xRanges );
+ }
+ // normal range
+ const ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( aCellRanges));
+ uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange));
+ return new ScVbaRange( mxParent, mxContext, xRange );
+}
+
+uno::Reference< excel::XRange >
+ScVbaRange::CurrentRegion()
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->CurrentRegion();
+ }
+
+ RangeHelper helper( mxRange );
+ uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor =
+ helper.getSheetCellCursor();
+ xSheetCellCursor->collapseToCurrentRegion();
+ uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW);
+ return RangeHelper::createRangeFromRange( mxParent, mxContext, helper.getCellRangeFromSheet(), xCellRangeAddressable );
+}
+
+uno::Reference< excel::XRange >
+ScVbaRange::CurrentArray()
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->CurrentArray();
+ }
+ RangeHelper helper( mxRange );
+ uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor =
+ helper.getSheetCellCursor();
+ xSheetCellCursor->collapseToCurrentArray();
+ uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW);
+ return RangeHelper::createRangeFromRange( mxParent, mxContext, helper.getCellRangeFromSheet(), xCellRangeAddressable );
+}
+
+uno::Any
+ScVbaRange::getFormulaArray()
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->getFormulaArray();
+ }
+
+ // return a formula if there is one or else an array
+ // still not sure when the return as array code should run
+ // ( I think it is if there is more than one formula ) at least
+ // that is what the doc says ( but I am not even sure how to detect that )
+ // for the moment any tests we have pass
+ uno::Reference< sheet::XArrayFormulaRange> xFormulaArray( mxRange, uno::UNO_QUERY_THROW );
+ if ( !xFormulaArray->getArrayFormula().isEmpty() )
+ return uno::Any( xFormulaArray->getArrayFormula() );
+
+ uno::Reference< sheet::XCellRangeFormula> xCellRangeFormula( mxRange, uno::UNO_QUERY_THROW );
+ const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext );
+ uno::Any aSingleValueOrMatrix;
+ // When dealing with a single element ( embedded in the sequence of sequence ) unwrap and return
+ // that value
+ uno::Sequence< uno::Sequence<OUString> > aTmpSeq = xCellRangeFormula->getFormulaArray();
+ if ( aTmpSeq.getLength() == 1 )
+ {
+ if ( aTmpSeq[ 0 ].getLength() == 1 )
+ aSingleValueOrMatrix <<= aTmpSeq[ 0 ][ 0 ];
+ }
+ else
+ aSingleValueOrMatrix = xConverter->convertTo( uno::Any( aTmpSeq ) , cppu::UnoType<uno::Sequence< uno::Sequence< uno::Any > >>::get() ) ;
+ return aSingleValueOrMatrix;
+}
+
+void
+ScVbaRange::setFormulaArray(const uno::Any& rFormula)
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->setFormulaArray( rFormula );
+ }
+ // #TODO need to distinguish between getFormula and getFormulaArray e.g. (R1C1)
+ // but for the moment it's just easier to treat them the same for setting
+ // seems
+ uno::Reference< lang::XMultiServiceFactory > xModelFactory( getUnoModel(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XFormulaParser > xParser( xModelFactory->createInstance( "com.sun.star.sheet.FormulaParser" ), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY_THROW);
+
+ table::CellRangeAddress aRangeAddress = xSource->getRangeAddress();
+ // #TODO check if api orders the address
+ // e.g. do we need to order the RangeAddress to get the topleft ( or can we assume it
+ // is in the correct order )
+ table::CellAddress aAddress;
+ aAddress.Sheet = aRangeAddress.Sheet;
+ aAddress.Column = aRangeAddress.StartColumn;
+ aAddress.Row = aRangeAddress.StartRow;
+ OUString sFormula;
+ rFormula >>= sFormula;
+ uno::Sequence<sheet::FormulaToken> aTokens = xParser->parseFormula( sFormula, aAddress );
+ ScTokenArray aTokenArray(getScDocument());
+ (void)ScTokenConversion::ConvertToTokenArray( getScDocument(), aTokenArray, aTokens );
+
+ getScDocShell()->GetDocFunc().EnterMatrix( getScRangeList()[0], nullptr, &aTokenArray, OUString(), true, true, OUString(), formula::FormulaGrammar::GRAM_API );
+}
+
+OUString
+ScVbaRange::Characters(const uno::Any& Start, const uno::Any& Length)
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->Characters( Start, Length );
+ }
+
+ tools::Long nIndex = 0, nCount = 0;
+ OUString rString;
+ uno::Reference< text::XTextRange > xTextRange(mxRange, ::uno::UNO_QUERY_THROW );
+ rString = xTextRange->getString();
+ if( !( Start >>= nIndex ) && !( Length >>= nCount ) )
+ return rString;
+ if(!( Start >>= nIndex ) )
+ nIndex = 1;
+ if(!( Length >>= nCount ) )
+ nIndex = rString.getLength();
+ return rString.copy( --nIndex, nCount ); // Zero value indexing
+}
+
+OUString
+ScVbaRange::Address( const uno::Any& RowAbsolute, const uno::Any& ColumnAbsolute, const uno::Any& ReferenceStyle, const uno::Any& External, const uno::Any& RelativeTo )
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ // Multi-Area Range
+ OUStringBuffer sAddress;
+ uno::Reference< XCollection > xCollection( m_Areas, uno::UNO_SET_THROW );
+ uno::Any aExternalCopy = External;
+ for ( sal_Int32 index = 1; index <= xCollection->getCount(); ++index )
+ {
+ uno::Reference< excel::XRange > xRange( xCollection->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW );
+ if ( index > 1 )
+ {
+ sAddress.append(",");
+ // force external to be false
+ // only first address should have the
+ // document and sheet specifications
+ aExternalCopy <<= false;
+ }
+ sAddress.append(xRange->Address( RowAbsolute, ColumnAbsolute, ReferenceStyle, aExternalCopy, RelativeTo ));
+ }
+ return sAddress.makeStringAndClear();
+
+ }
+ ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 );
+ if ( ReferenceStyle.hasValue() )
+ {
+ sal_Int32 refStyle = excel::XlReferenceStyle::xlA1;
+ ReferenceStyle >>= refStyle;
+ if ( refStyle == excel::XlReferenceStyle::xlR1C1 )
+ dDetails = ScAddress::Details( formula::FormulaGrammar::CONV_XL_R1C1, 0, 0 );
+ }
+ // default
+ ScRefFlags nFlags = ScRefFlags::RANGE_ABS;
+ ScDocShell* pDocShell = getScDocShell();
+ ScDocument& rDoc = pDocShell->GetDocument();
+
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ ScRange aRange( static_cast< SCCOL >( thisAddress.StartColumn ), static_cast< SCROW >( thisAddress.StartRow ), static_cast< SCTAB >( thisAddress.Sheet ), static_cast< SCCOL >( thisAddress.EndColumn ), static_cast< SCROW >( thisAddress.EndRow ), static_cast< SCTAB >( thisAddress.Sheet ) );
+ constexpr ScRefFlags ROW_ABS = ScRefFlags::ROW_ABS | ScRefFlags::ROW2_ABS;
+ constexpr ScRefFlags COL_ABS = ScRefFlags::COL_ABS | ScRefFlags::COL2_ABS;
+
+ if ( RowAbsolute.hasValue() )
+ {
+ bool bVal = true;
+ RowAbsolute >>= bVal;
+ if ( !bVal )
+ nFlags &= ~ROW_ABS;
+ }
+ if ( ColumnAbsolute.hasValue() )
+ {
+ bool bVal = true;
+ ColumnAbsolute >>= bVal;
+ if ( !bVal )
+ nFlags &= ~COL_ABS;
+ }
+ if ( External.hasValue() )
+ {
+ bool bLocal = false;
+ External >>= bLocal;
+ if ( bLocal )
+ nFlags |= ScRefFlags::TAB_3D | ScRefFlags::FORCE_DOC;
+ }
+ if ( RelativeTo.hasValue() )
+ {
+ // #TODO should I throw an error if R1C1 is not set?
+
+ table::CellRangeAddress refAddress = getCellRangeAddressForVBARange( RelativeTo, pDocShell );
+ dDetails = ScAddress::Details( formula::FormulaGrammar::CONV_XL_R1C1, static_cast< SCROW >( refAddress.StartRow ), static_cast< SCCOL >( refAddress.StartColumn ) );
+ }
+ return aRange.Format(rDoc, nFlags, dDetails);
+}
+
+uno::Reference < excel::XFont >
+ScVbaRange::Font()
+{
+ uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY );
+ ScDocument& rDoc = getScDocument();
+ if ( mxRange.is() )
+ xProps.set(mxRange, ::uno::UNO_QUERY );
+ else if ( mxRanges.is() )
+ xProps.set(mxRanges, ::uno::UNO_QUERY );
+
+ ScVbaPalette aPalette( rDoc.GetDocumentShell() );
+ ScCellRangeObj* pRangeObj = nullptr;
+ try
+ {
+ pRangeObj = getCellRangeObj();
+ }
+ catch( uno::Exception& )
+ {
+ }
+ return new ScVbaFont( this, mxContext, aPalette, xProps, pRangeObj );
+}
+
+uno::Reference< excel::XRange >
+ScVbaRange::Cells( const uno::Any &nRowIndex, const uno::Any &nColumnIndex )
+{
+ // #TODO code within the test below "if ( m_Areas... " can be removed
+ // Test is performed only because m_xRange is NOT set to be
+ // the first range in m_Areas ( to force failure while
+ // the implementations for each method are being updated )
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->Cells( nRowIndex, nColumnIndex );
+ }
+
+ // Performance: Use a common helper method for ScVbaRange::Cells and ScVbaWorksheet::Cells,
+ // instead of creating a new ScVbaRange object in often-called ScVbaWorksheet::Cells
+ return CellsHelper( getScDocument(), mxParent, mxContext, mxRange, nRowIndex, nColumnIndex );
+}
+
+// static
+uno::Reference< excel::XRange >
+ScVbaRange::CellsHelper( const ScDocument& rDoc,
+ const uno::Reference< ov::XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< css::table::XCellRange >& xRange,
+ const uno::Any &nRowIndex, const uno::Any &nColumnIndex )
+{
+ sal_Int32 nRow = 0, nColumn = 0;
+
+ bool bIsIndex = nRowIndex.hasValue();
+ bool bIsColumnIndex = nColumnIndex.hasValue();
+
+ // Sometimes we might get a float or a double or whatever
+ // set in the Any, we should convert as appropriate
+ // #FIXME - perhaps worth turning this into some sort of
+ // conversion routine e.g. bSuccess = getValueFromAny( nRow, nRowIndex, cppu::UnoType<sal_Int32>::get() )
+ if ( nRowIndex.hasValue() && !( nRowIndex >>= nRow ) )
+ {
+ const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( xContext );
+ uno::Any aConverted;
+ try
+ {
+ aConverted = xConverter->convertTo( nRowIndex, cppu::UnoType<sal_Int32>::get() );
+ bIsIndex = ( aConverted >>= nRow );
+ }
+ catch( uno::Exception& ) {} // silence any errors
+ }
+
+ if ( bIsColumnIndex )
+ {
+ // Column index can be a col address e.g Cells( 1, "B" ) etc.
+ OUString sCol;
+ if ( nColumnIndex >>= sCol )
+ {
+ ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 );
+ ScRange tmpRange;
+ ScRefFlags flags = tmpRange.ParseCols( rDoc, sCol, dDetails );
+ if ( (flags & ScRefFlags::COL_VALID) == ScRefFlags::ZERO )
+ throw uno::RuntimeException();
+ nColumn = tmpRange.aStart.Col() + 1;
+ }
+ else
+ {
+ if ( !( nColumnIndex >>= nColumn ) )
+ {
+ const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( xContext );
+ uno::Any aConverted;
+ try
+ {
+ aConverted = xConverter->convertTo( nColumnIndex, cppu::UnoType<sal_Int32>::get() );
+ bIsColumnIndex = ( aConverted >>= nColumn );
+ }
+ catch( uno::Exception& ) {} // silence any errors
+ }
+ }
+ }
+ RangeHelper thisRange( xRange );
+ table::CellRangeAddress thisRangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ uno::Reference< table::XCellRange > xSheetRange = thisRange.getCellRangeFromSheet();
+ if( !bIsIndex && !bIsColumnIndex ) // .Cells
+ // #FIXME needs proper parent ( Worksheet )
+ return uno::Reference< excel::XRange >( new ScVbaRange( xParent, xContext, xRange ) );
+
+ sal_Int32 nIndex = --nRow;
+ if( bIsIndex && !bIsColumnIndex ) // .Cells(n)
+ {
+ uno::Reference< table::XColumnRowRange > xColumnRowRange(xRange, ::uno::UNO_QUERY_THROW);
+ sal_Int32 nColCount = xColumnRowRange->getColumns()->getCount();
+
+ if ( !nIndex || nIndex < 0 )
+ nRow = 0;
+ else
+ nRow = nIndex / nColCount;
+ nColumn = nIndex % nColCount;
+ }
+ else
+ --nColumn;
+ nRow = nRow + thisRangeAddress.StartRow;
+ nColumn = nColumn + thisRangeAddress.StartColumn;
+ return new ScVbaRange( xParent, xContext, xSheetRange->getCellRangeByPosition( nColumn, nRow, nColumn, nRow ) );
+}
+
+void
+ScVbaRange::Select()
+{
+ ScCellRangesBase* pUnoRangesBase = getCellRangesBase();
+ if ( !pUnoRangesBase )
+ throw uno::RuntimeException("Failed to access underlying uno range object" );
+ ScDocShell* pShell = pUnoRangesBase->GetDocShell();
+ if ( !pShell )
+ return;
+
+ uno::Reference< frame::XModel > xModel( pShell->GetModel(), uno::UNO_SET_THROW );
+ uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
+ if ( mxRanges.is() )
+ xSelection->select( uno::Any( lclExpandToMerged( mxRanges ) ) );
+ else
+ xSelection->select( uno::Any( lclExpandToMerged( mxRange, true ) ) );
+ // set focus on document e.g.
+ // ThisComponent.CurrentController.Frame.getContainerWindow.SetFocus
+ try
+ {
+ uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW );
+ uno::Reference< frame::XFrame > xFrame( xController->getFrame(), uno::UNO_SET_THROW );
+ uno::Reference< awt::XWindow > xWin( xFrame->getContainerWindow(), uno::UNO_SET_THROW );
+ xWin->setFocus();
+ }
+ catch( uno::Exception& )
+ {
+ }
+}
+
+static bool cellInRange( const table::CellRangeAddress& rAddr, sal_Int32 nCol, sal_Int32 nRow )
+{
+ return nCol >= rAddr.StartColumn && nCol <= rAddr.EndColumn &&
+ nRow >= rAddr.StartRow && nRow <= rAddr.EndRow;
+}
+
+static void setCursor( SCCOL nCol, SCROW nRow, const uno::Reference< frame::XModel >& xModel, bool bInSel = true )
+{
+ ScTabViewShell* pShell = excel::getBestViewShell( xModel );
+ if ( pShell )
+ {
+ if ( bInSel )
+ pShell->SetCursor( nCol, nRow );
+ else
+ pShell->MoveCursorAbs( nCol, nRow, SC_FOLLOW_NONE, false, false, true );
+ }
+}
+
+void
+ScVbaRange::Activate()
+{
+ // get first cell of current range
+ uno::Reference< table::XCellRange > xCellRange;
+ if ( mxRanges.is() )
+ {
+ uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW );
+ xCellRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW );
+ }
+ else
+ xCellRange.set( mxRange, uno::UNO_SET_THROW );
+
+ RangeHelper thisRange( xCellRange );
+ uno::Reference< sheet::XCellRangeAddressable > xThisRangeAddress = thisRange.getCellRangeAddressable();
+ table::CellRangeAddress thisRangeAddress = xThisRangeAddress->getRangeAddress();
+ uno::Reference< frame::XModel > xModel;
+ ScDocShell* pShell = getScDocShell();
+
+ if ( pShell )
+ xModel = pShell->GetModel();
+
+ if ( !xModel.is() )
+ throw uno::RuntimeException();
+
+ // get current selection
+ uno::Reference< sheet::XCellRangeAddressable > xRange( xModel->getCurrentSelection(), ::uno::UNO_QUERY);
+
+ uno::Reference< sheet::XSheetCellRanges > xRanges( xModel->getCurrentSelection(), ::uno::UNO_QUERY);
+
+ if ( xRanges.is() )
+ {
+ const uno::Sequence< table::CellRangeAddress > nAddrs = xRanges->getRangeAddresses();
+ for ( const auto& rAddr : nAddrs )
+ {
+ if ( cellInRange( rAddr, thisRangeAddress.StartColumn, thisRangeAddress.StartRow ) )
+ {
+ setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel );
+ return;
+ }
+
+ }
+ }
+
+ if ( xRange.is() && cellInRange( xRange->getRangeAddress(), thisRangeAddress.StartColumn, thisRangeAddress.StartRow ) )
+ setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel );
+ else
+ {
+ // if this range is multi cell select the range other
+ // wise just position the cell at this single range position
+ if ( isSingleCellRange() )
+ // This top-leftmost cell of this Range is not in the current
+ // selection so just select this range
+ setCursor( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), xModel, false );
+ else
+ Select();
+ }
+
+}
+
+ScRange ScVbaRange::obtainRangeEvenIfRangeListIsEmpty( const ScRangeList& rCellRanges ) const
+{
+ // XXX It may be that using the current range list was never correct, but
+ // always the initial sheet range would be instead, history is unclear.
+
+ if (!rCellRanges.empty())
+ return rCellRanges.front();
+
+ table::CellRangeAddress aRA( lclGetRangeAddress( mxRange ));
+ return ScRange( aRA.StartColumn, aRA.StartRow, aRA.Sheet, aRA.EndColumn, aRA.EndRow, aRA.Sheet);
+}
+
+uno::Reference< excel::XRange >
+ScVbaRange::Rows(const uno::Any& aIndex )
+{
+ if ( aIndex.hasValue() )
+ {
+ ScCellRangesBase* pUnoRangesBase = getCellRangesBase();
+ ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( pUnoRangesBase->GetRangeList()));
+
+ sal_Int32 nValue = 0;
+ OUString sAddress;
+ if( aIndex >>= nValue )
+ {
+ aRange.aStart.SetRow( aRange.aStart.Row() + --nValue );
+ aRange.aEnd.SetRow( aRange.aStart.Row() );
+ }
+ else if ( aIndex >>= sAddress )
+ {
+ ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 );
+ ScRange tmpRange;
+ tmpRange.ParseRows( getScDocument(), sAddress, dDetails );
+ SCROW nStartRow = tmpRange.aStart.Row();
+ SCROW nEndRow = tmpRange.aEnd.Row();
+
+ aRange.aStart.SetRow( aRange.aStart.Row() + nStartRow );
+ aRange.aEnd.SetRow( aRange.aStart.Row() + ( nEndRow - nStartRow ));
+ }
+ else
+ throw uno::RuntimeException("Illegal param" );
+
+ if ( aRange.aStart.Row() < 0 || aRange.aEnd.Row() < 0 )
+ throw uno::RuntimeException("Internal failure, illegal param" );
+ // return a normal range ( even for multi-selection
+ uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange ) );
+ return new ScVbaRange( mxParent, mxContext, xRange, true );
+ }
+ // Rows() - no params
+ if ( m_Areas->getCount() > 1 )
+ return new ScVbaRange( mxParent, mxContext, mxRanges, true );
+ return new ScVbaRange( mxParent, mxContext, mxRange, true );
+}
+
+uno::Reference< excel::XRange >
+ScVbaRange::Columns(const uno::Any& aIndex )
+{
+ ScCellRangesBase* pUnoRangesBase = getCellRangesBase();
+ ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( pUnoRangesBase->GetRangeList()));
+
+ if ( aIndex.hasValue() )
+ {
+ OUString sAddress;
+ sal_Int32 nValue = 0;
+ if ( aIndex >>= nValue )
+ {
+ aRange.aStart.SetCol( aRange.aStart.Col() + static_cast< SCCOL > ( --nValue ) );
+ aRange.aEnd.SetCol( aRange.aStart.Col() );
+ }
+
+ else if ( aIndex >>= sAddress )
+ {
+ ScAddress::Details dDetails( formula::FormulaGrammar::CONV_XL_A1, 0, 0 );
+ ScRange tmpRange;
+ tmpRange.ParseCols( getScDocument(), sAddress, dDetails );
+ SCCOL nStartCol = tmpRange.aStart.Col();
+ SCCOL nEndCol = tmpRange.aEnd.Col();
+
+ aRange.aStart.SetCol( aRange.aStart.Col() + nStartCol );
+ aRange.aEnd.SetCol( aRange.aStart.Col() + ( nEndCol - nStartCol ));
+ }
+ else
+ throw uno::RuntimeException("Illegal param" );
+
+ if ( aRange.aStart.Col() < 0 || aRange.aEnd.Col() < 0 )
+ throw uno::RuntimeException("Internal failure, illegal param" );
+ }
+ // Columns() - no params
+ uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange ) );
+ return new ScVbaRange( mxParent, mxContext, xRange, false, true );
+}
+
+void
+ScVbaRange::setMergeCells( const uno::Any& aIsMerged )
+{
+ bool bMerge = extractBoolFromAny( aIsMerged );
+
+ if( mxRanges.is() )
+ {
+ sal_Int32 nCount = mxRanges->getCount();
+
+ // VBA does nothing (no error) if the own ranges overlap somehow
+ ::std::vector< table::CellRangeAddress > aList;
+ for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ uno::Reference< sheet::XCellRangeAddressable > xRangeAddr( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW );
+ table::CellRangeAddress aAddress = xRangeAddr->getRangeAddress();
+ if (std::any_of(aList.begin(), aList.end(),
+ [&aAddress](const table::CellRangeAddress& rAddress)
+ { return ScUnoConversion::Intersects( rAddress, aAddress ); }))
+ return;
+ aList.push_back( aAddress );
+ }
+
+ // (un)merge every range after it has been extended to intersecting merged ranges from sheet
+ for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ uno::Reference< table::XCellRange > xRange( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW );
+ lclExpandAndMerge( xRange, bMerge );
+ }
+ return;
+ }
+
+ // otherwise, merge single range
+ lclExpandAndMerge( mxRange, bMerge );
+}
+
+uno::Any
+ScVbaRange::getMergeCells()
+{
+ if( mxRanges.is() )
+ {
+ sal_Int32 nCount = mxRanges->getCount();
+ for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
+ {
+ uno::Reference< table::XCellRange > xRange( mxRanges->getByIndex( nIndex ), uno::UNO_QUERY_THROW );
+ util::TriState eMerged = lclGetMergedState( xRange );
+ /* Excel always returns NULL, if one range of the range list is
+ partly or completely merged. Even if all ranges are completely
+ merged, the return value is still NULL. */
+ if( eMerged != util::TriState_NO )
+ return aNULL();
+ }
+ // no range is merged anyhow, return false
+ return uno::Any( false );
+ }
+
+ // otherwise, check single range
+ switch( lclGetMergedState( mxRange ) )
+ {
+ case util::TriState_YES: return uno::Any( true );
+ case util::TriState_NO: return uno::Any( false );
+ default: return aNULL();
+ }
+}
+
+void
+ScVbaRange::Copy(const ::uno::Any& Destination)
+{
+ if ( Destination.hasValue() )
+ {
+ // TODO copy with multiple selections should work here too
+ if ( m_Areas->getCount() > 1 )
+ throw uno::RuntimeException("That command cannot be used on multiple selections" );
+ uno::Reference< excel::XRange > xRange( Destination, uno::UNO_QUERY_THROW );
+ uno::Any aRange = xRange->getCellRange();
+ uno::Reference< table::XCellRange > xCellRange;
+ aRange >>= xCellRange;
+ uno::Reference< sheet::XSheetCellRange > xSheetCellRange(xCellRange, ::uno::UNO_QUERY_THROW);
+ uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet();
+ uno::Reference< table::XCellRange > xDest( xSheet, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XCellRangeMovement > xMover( xSheet, uno::UNO_QUERY_THROW);
+ uno::Reference< sheet::XCellAddressable > xDestination( xDest->getCellByPosition(
+ xRange->getColumn()-1,xRange->getRow()-1), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY);
+ xMover->copyRange( xDestination->getCellAddress(), xSource->getRangeAddress() );
+ if ( ScVbaRange* pRange = getImplementation( xRange ) )
+ pRange->fireChangeEvent();
+ }
+ else
+ {
+ Select();
+ excel::implnCopy(getUnoModel());
+ }
+}
+
+void
+ScVbaRange::Cut(const ::uno::Any& Destination)
+{
+ if ( m_Areas->getCount() > 1 )
+ throw uno::RuntimeException("That command cannot be used on multiple selections" );
+ if (Destination.hasValue())
+ {
+ uno::Reference< excel::XRange > xRange( Destination, uno::UNO_QUERY_THROW );
+ uno::Reference< table::XCellRange > xCellRange( xRange->getCellRange(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSheetCellRange > xSheetCellRange(xCellRange, ::uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheet > xSheet = xSheetCellRange->getSpreadsheet();
+ uno::Reference< table::XCellRange > xDest( xSheet, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XCellRangeMovement > xMover( xSheet, uno::UNO_QUERY_THROW);
+ uno::Reference< sheet::XCellAddressable > xDestination( xDest->getCellByPosition(
+ xRange->getColumn()-1,xRange->getRow()-1), uno::UNO_QUERY);
+ uno::Reference< sheet::XCellRangeAddressable > xSource( mxRange, uno::UNO_QUERY);
+ xMover->moveRange( xDestination->getCellAddress(), xSource->getRangeAddress() );
+ }
+ else
+ {
+ uno::Reference< frame::XModel > xModel = getModelFromRange( mxRange );
+ Select();
+ excel::implnCut( xModel );
+ }
+}
+
+void
+ScVbaRange::setNumberFormat( const uno::Any& aFormat )
+{
+ OUString sFormat;
+ aFormat >>= sFormat;
+ if ( m_Areas->getCount() > 1 )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->setNumberFormat( aFormat );
+ }
+ return;
+ }
+ NumFormatHelper numFormat( mxRange );
+ numFormat.setNumberFormat( sFormat );
+}
+
+uno::Any
+ScVbaRange::getNumberFormat()
+{
+
+ if ( m_Areas->getCount() > 1 )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ uno::Any aResult = aNULL();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ // if the numberformat of one area is different to another
+ // return null
+ if ( index > 1 )
+ if ( aResult != xRange->getNumberFormat() )
+ return aNULL();
+ aResult = xRange->getNumberFormat();
+ if ( aNULL() == aResult )
+ return aNULL();
+ }
+ return aResult;
+ }
+ NumFormatHelper numFormat( mxRange );
+ OUString sFormat = numFormat.getNumberFormatString();
+ if ( !sFormat.isEmpty() )
+ return uno::Any( sFormat );
+ return aNULL();
+}
+
+uno::Reference< excel::XRange >
+ScVbaRange::Resize( const uno::Any &RowSize, const uno::Any &ColumnSize )
+{
+ tools::Long nRowSize = 0, nColumnSize = 0;
+ bool bIsRowChanged = ( RowSize >>= nRowSize ), bIsColumnChanged = ( ColumnSize >>= nColumnSize );
+ uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, ::uno::UNO_QUERY_THROW);
+ uno::Reference< sheet::XSheetCellRange > xSheetRange(mxRange, ::uno::UNO_QUERY_THROW);
+ uno::Reference< sheet::XSheetCellCursor > xCursor( xSheetRange->getSpreadsheet()->createCursorByRange(xSheetRange), ::uno::UNO_SET_THROW );
+
+ if( !bIsRowChanged )
+ nRowSize = xColumnRowRange->getRows()->getCount();
+ if( !bIsColumnChanged )
+ nColumnSize = xColumnRowRange->getColumns()->getCount();
+
+ xCursor->collapseToSize( nColumnSize, nRowSize );
+ uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xCursor, ::uno::UNO_QUERY_THROW );
+ uno::Reference< table::XCellRange > xRange( xSheetRange->getSpreadsheet(), ::uno::UNO_QUERY_THROW );
+ return new ScVbaRange( mxParent, mxContext,xRange->getCellRangeByPosition(
+ xCellRangeAddressable->getRangeAddress().StartColumn,
+ xCellRangeAddressable->getRangeAddress().StartRow,
+ xCellRangeAddressable->getRangeAddress().EndColumn,
+ xCellRangeAddressable->getRangeAddress().EndRow ) );
+}
+
+void
+ScVbaRange::setWrapText( const uno::Any& aIsWrapped )
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->setWrapText( aIsWrapped );
+ }
+ return;
+ }
+
+ uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY_THROW );
+ bool bIsWrapped = extractBoolFromAny( aIsWrapped );
+ xProps->setPropertyValue( "IsTextWrapped", uno::Any( bIsWrapped ) );
+}
+
+uno::Any
+ScVbaRange::getWrapText()
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ uno::Any aResult;
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ if ( index > 1 )
+ if ( aResult != xRange->getWrapText() )
+ return aNULL();
+ aResult = xRange->getWrapText();
+ }
+ return aResult;
+ }
+
+ SfxItemSet* pDataSet = getCurrentDataSet();
+
+ SfxItemState eState = pDataSet->GetItemState( ATTR_LINEBREAK);
+ if ( eState == SfxItemState::DONTCARE )
+ return aNULL();
+
+ uno::Reference< beans::XPropertySet > xProps(mxRange, ::uno::UNO_QUERY_THROW );
+ uno::Any aValue = xProps->getPropertyValue( "IsTextWrapped" );
+ return aValue;
+}
+
+uno::Reference< excel::XInterior > ScVbaRange::Interior( )
+{
+ uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW );
+ return new ScVbaInterior ( this, mxContext, xProps, &getScDocument() );
+}
+uno::Reference< excel::XRange >
+ScVbaRange::Range( const uno::Any &Cell1, const uno::Any &Cell2 )
+{
+ return Range( Cell1, Cell2, false );
+}
+uno::Reference< excel::XRange >
+ScVbaRange::Range( const uno::Any &Cell1, const uno::Any &Cell2, bool bForceUseInpuRangeTab )
+
+{
+ uno::Reference< table::XCellRange > xCellRange = mxRange;
+
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW );
+ xCellRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW );
+ }
+ else
+ xCellRange.set( mxRange );
+
+ RangeHelper thisRange( xCellRange );
+ uno::Reference< table::XCellRange > xRanges = thisRange.getCellRangeFromSheet();
+ uno::Reference< sheet::XCellRangeAddressable > xAddressable( xRanges, uno::UNO_QUERY_THROW );
+
+ uno::Reference< table::XCellRange > xReferrer =
+ xRanges->getCellRangeByPosition( getColumn()-1, getRow()-1,
+ xAddressable->getRangeAddress().EndColumn,
+ xAddressable->getRangeAddress().EndRow );
+ // xAddressable now for this range
+ xAddressable.set( xReferrer, uno::UNO_QUERY_THROW );
+
+ if( !Cell1.hasValue() )
+ throw uno::RuntimeException( "Invalid Argument" );
+
+ table::CellRangeAddress parentRangeAddress = xAddressable->getRangeAddress();
+
+ ScRange aRange;
+ // Cell1 defined only
+ if ( !Cell2.hasValue() )
+ {
+ OUString sName;
+ Cell1 >>= sName;
+ RangeHelper referRange( xReferrer );
+ table::CellRangeAddress referAddress = referRange.getCellRangeAddressable()->getRangeAddress();
+ return getRangeForName( mxContext, sName, getScDocShell(), referAddress );
+
+ }
+ else
+ {
+ table::CellRangeAddress cell1, cell2;
+ cell1 = getCellRangeAddressForVBARange( Cell1, getScDocShell() );
+ // Cell1 & Cell2 defined
+ // Excel seems to combine the range as the range defined by
+ // the combination of Cell1 & Cell2
+
+ cell2 = getCellRangeAddressForVBARange( Cell2, getScDocShell() );
+
+ table::CellRangeAddress resultAddress;
+ resultAddress.StartColumn = ( cell1.StartColumn < cell2.StartColumn ) ? cell1.StartColumn : cell2.StartColumn;
+ resultAddress.StartRow = ( cell1.StartRow < cell2.StartRow ) ? cell1.StartRow : cell2.StartRow;
+ resultAddress.EndColumn = std::max( cell1.EndColumn, cell2.EndColumn );
+ resultAddress.EndRow = std::max( cell1.EndRow, cell2.EndRow );
+ if ( bForceUseInpuRangeTab )
+ {
+ // this is a call from Application.Range( x,y )
+ // it's possible for x or y to specify a different sheet from
+ // the current or active on ( but they must be the same )
+ if ( cell1.Sheet != cell2.Sheet )
+ throw uno::RuntimeException();
+ parentRangeAddress.Sheet = cell1.Sheet;
+ }
+ else
+ {
+ // this is not a call from Application.Range( x,y )
+ // if a different sheet from this range is specified it's
+ // an error
+ if ( parentRangeAddress.Sheet != cell1.Sheet
+ || parentRangeAddress.Sheet != cell2.Sheet
+ )
+ throw uno::RuntimeException();
+
+ }
+ ScUnoConversion::FillScRange( aRange, resultAddress );
+ }
+ ScRange parentAddress;
+ ScUnoConversion::FillScRange( parentAddress, parentRangeAddress);
+ if ( aRange.aStart.Col() >= 0 && aRange.aStart.Row() >= 0 && aRange.aEnd.Col() >= 0 && aRange.aEnd.Row() >= 0 )
+ {
+ sal_Int32 nStartX = parentAddress.aStart.Col() + aRange.aStart.Col();
+ sal_Int32 nStartY = parentAddress.aStart.Row() + aRange.aStart.Row();
+ sal_Int32 nEndX = parentAddress.aStart.Col() + aRange.aEnd.Col();
+ sal_Int32 nEndY = parentAddress.aStart.Row() + aRange.aEnd.Row();
+
+ if ( nStartX <= nEndX && nEndX <= parentAddress.aEnd.Col() &&
+ nStartY <= nEndY && nEndY <= parentAddress.aEnd.Row() )
+ {
+ ScRange aNew( static_cast<SCCOL>(nStartX), static_cast<SCROW>(nStartY), parentAddress.aStart.Tab(),
+ static_cast<SCCOL>(nEndX), static_cast<SCROW>(nEndY), parentAddress.aEnd.Tab() );
+ xCellRange = new ScCellRangeObj( getScDocShell(), aNew );
+ }
+ }
+
+ return new ScVbaRange( mxParent, mxContext, xCellRange );
+
+}
+
+// Allow access to underlying openoffice uno api ( useful for debugging
+// with openoffice basic )
+uno::Any SAL_CALL ScVbaRange::getCellRange( )
+{
+ uno::Any aAny;
+ if ( mxRanges.is() )
+ aAny <<= mxRanges;
+ else if ( mxRange.is() )
+ aAny <<= mxRange;
+ return aAny;
+}
+
+uno::Any ScVbaRange::getCellRange( const uno::Reference< excel::XRange >& rxRange )
+{
+ if( ScVbaRange* pVbaRange = getImplementation( rxRange ) )
+ return pVbaRange->getCellRange();
+ throw uno::RuntimeException();
+}
+
+static InsertDeleteFlags getPasteFlags (sal_Int32 Paste)
+{
+ InsertDeleteFlags nFlags = InsertDeleteFlags::NONE;
+ switch (Paste) {
+ case excel::XlPasteType::xlPasteComments:
+ nFlags = InsertDeleteFlags::NOTE;break;
+ case excel::XlPasteType::xlPasteFormats:
+ nFlags = InsertDeleteFlags::ATTRIB;break;
+ case excel::XlPasteType::xlPasteFormulas:
+ nFlags = InsertDeleteFlags::FORMULA;break;
+ case excel::XlPasteType::xlPasteFormulasAndNumberFormats :
+ case excel::XlPasteType::xlPasteValues:
+ nFlags = ( InsertDeleteFlags::VALUE | InsertDeleteFlags::DATETIME | InsertDeleteFlags::STRING | InsertDeleteFlags::SPECIAL_BOOLEAN ); break;
+ case excel::XlPasteType::xlPasteValuesAndNumberFormats:
+ nFlags = InsertDeleteFlags::VALUE | InsertDeleteFlags::ATTRIB; break;
+ case excel::XlPasteType::xlPasteColumnWidths:
+ case excel::XlPasteType::xlPasteValidation:
+ nFlags = InsertDeleteFlags::NONE;break;
+ case excel::XlPasteType::xlPasteAll:
+ case excel::XlPasteType::xlPasteAllExceptBorders:
+ default:
+ nFlags = InsertDeleteFlags::ALL;break;
+ }
+ return nFlags;
+}
+
+static ScPasteFunc
+getPasteFormulaBits( sal_Int32 Operation)
+{
+ ScPasteFunc nFormulaBits = ScPasteFunc::NONE;
+ switch (Operation)
+ {
+ case excel::XlPasteSpecialOperation::xlPasteSpecialOperationAdd:
+ nFormulaBits = ScPasteFunc::ADD; break;
+ case excel::XlPasteSpecialOperation::xlPasteSpecialOperationSubtract:
+ nFormulaBits = ScPasteFunc::SUB;break;
+ case excel::XlPasteSpecialOperation::xlPasteSpecialOperationMultiply:
+ nFormulaBits = ScPasteFunc::MUL;break;
+ case excel::XlPasteSpecialOperation::xlPasteSpecialOperationDivide:
+ nFormulaBits = ScPasteFunc::DIV;break;
+
+ case excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone:
+ default:
+ nFormulaBits = ScPasteFunc::NONE; break;
+ }
+
+ return nFormulaBits;
+}
+void SAL_CALL
+ScVbaRange::PasteSpecial( const uno::Any& Paste, const uno::Any& Operation, const uno::Any& SkipBlanks, const uno::Any& Transpose )
+{
+ if ( m_Areas->getCount() > 1 )
+ throw uno::RuntimeException("That command cannot be used on multiple selections" );
+ ScDocShell* pShell = getScDocShell();
+
+ if (!pShell)
+ throw uno::RuntimeException("That command cannot be used with no ScDocShell" );
+
+ uno::Reference< frame::XModel > xModel(pShell->GetModel(), uno::UNO_SET_THROW);
+ uno::Reference< view::XSelectionSupplier > xSelection( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
+ // select this range
+ xSelection->select( uno::Any( mxRange ) );
+ // set up defaults
+ sal_Int32 nPaste = excel::XlPasteType::xlPasteAll;
+ sal_Int32 nOperation = excel::XlPasteSpecialOperation::xlPasteSpecialOperationNone;
+ bool bTranspose = false;
+ bool bSkipBlanks = false;
+
+ if ( Paste.hasValue() )
+ Paste >>= nPaste;
+ if ( Operation.hasValue() )
+ Operation >>= nOperation;
+ if ( SkipBlanks.hasValue() )
+ SkipBlanks >>= bSkipBlanks;
+ if ( Transpose.hasValue() )
+ Transpose >>= bTranspose;
+
+ InsertDeleteFlags nFlags = getPasteFlags(nPaste);
+ ScPasteFunc nFormulaBits = getPasteFormulaBits(nOperation);
+
+ excel::implnPasteSpecial(xModel, nFlags, nFormulaBits, bSkipBlanks, bTranspose);
+}
+
+uno::Reference< excel::XRange >
+ScVbaRange::getEntireColumnOrRow( bool bColumn )
+{
+ ScCellRangesBase* pUnoRangesBase = getCellRangesBase();
+ // copy the range list
+ ScRangeList aCellRanges = pUnoRangesBase->GetRangeList();
+ ScDocument& rDoc = getScDocument();
+
+ for ( size_t i = 0, nRanges = aCellRanges.size(); i < nRanges; ++i )
+ {
+ ScRange & rRange = aCellRanges[ i ];
+ if ( bColumn )
+ {
+ rRange.aStart.SetRow( 0 );
+ rRange.aEnd.SetRow( rDoc.MaxRow() );
+ }
+ else
+ {
+ rRange.aStart.SetCol( 0 );
+ rRange.aEnd.SetCol( rDoc.MaxCol() );
+ }
+ }
+ if ( aCellRanges.size() > 1 ) // Multi-Area
+ {
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( pUnoRangesBase->GetDocShell(), aCellRanges ) );
+
+ return new ScVbaRange( mxParent, mxContext, xRanges, !bColumn, bColumn );
+ }
+ const ScRange aRange( obtainRangeEvenIfRangeListIsEmpty( aCellRanges));
+ uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( pUnoRangesBase->GetDocShell(), aRange));
+ return new ScVbaRange( mxParent, mxContext, xRange, !bColumn, bColumn );
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaRange::getEntireRow()
+{
+ return getEntireColumnOrRow(false);
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaRange::getEntireColumn()
+{
+ return getEntireColumnOrRow(true);
+}
+
+uno::Reference< excel::XComment > SAL_CALL
+ScVbaRange::AddComment( const uno::Any& Text )
+{
+ // if there is already a comment in the top-left cell then throw
+ if( getComment().is() )
+ throw uno::RuntimeException();
+
+ // workaround: Excel allows to create empty comment, Calc does not
+ OUString aNoteText;
+ if( Text.hasValue() && !(Text >>= aNoteText) )
+ throw uno::RuntimeException();
+ if( aNoteText.isEmpty() )
+ aNoteText = " ";
+
+ // try to create a new annotation
+ table::CellRangeAddress aRangePos = lclGetRangeAddress( mxRange );
+ table::CellAddress aNotePos( aRangePos.Sheet, aRangePos.StartColumn, aRangePos.StartRow );
+ uno::Reference< sheet::XSheetCellRange > xCellRange( mxRange, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSheetAnnotationsSupplier > xAnnosSupp( xCellRange->getSpreadsheet(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), uno::UNO_SET_THROW );
+ xAnnos->insertNew( aNotePos, aNoteText );
+ return new ScVbaComment( this, mxContext, getUnoModel(), mxRange );
+}
+
+uno::Reference< excel::XComment > SAL_CALL
+ScVbaRange::getComment()
+{
+ // intentional behavior to return a null object if no
+ // comment defined
+ uno::Reference< excel::XComment > xComment( new ScVbaComment( this, mxContext, getUnoModel(), mxRange ) );
+ if ( xComment->Text( uno::Any(), uno::Any(), uno::Any() ).isEmpty() )
+ return nullptr;
+ return xComment;
+
+}
+
+/// @throws uno::RuntimeException
+static uno::Reference< beans::XPropertySet >
+getRowOrColumnProps( const uno::Reference< table::XCellRange >& xCellRange, bool bRows )
+{
+ uno::Reference< table::XColumnRowRange > xColRow( xCellRange, uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xProps;
+ if ( bRows )
+ xProps.set( xColRow->getRows(), uno::UNO_QUERY_THROW );
+ else
+ xProps.set( xColRow->getColumns(), uno::UNO_QUERY_THROW );
+ return xProps;
+}
+
+uno::Any SAL_CALL
+ScVbaRange::getHidden()
+{
+ // if multi-area result is the result of the
+ // first area
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(sal_Int32(1)), uno::Any() ), uno::UNO_QUERY_THROW );
+ return xRange->getHidden();
+ }
+ bool bIsVisible = false;
+ try
+ {
+ uno::Reference< beans::XPropertySet > xProps = getRowOrColumnProps( mxRange, mbIsRows );
+ if ( !( xProps->getPropertyValue( ISVISIBLE ) >>= bIsVisible ) )
+ throw uno::RuntimeException("Failed to get IsVisible property" );
+ }
+ catch( const uno::Exception& e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( e.Message,
+ nullptr, anyEx );
+ }
+ return uno::Any( !bIsVisible );
+}
+
+void SAL_CALL
+ScVbaRange::setHidden( const uno::Any& _hidden )
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->setHidden( _hidden );
+ }
+ return;
+ }
+
+ bool bHidden = extractBoolFromAny( _hidden );
+ try
+ {
+ uno::Reference< beans::XPropertySet > xProps = getRowOrColumnProps( mxRange, mbIsRows );
+ xProps->setPropertyValue( ISVISIBLE, uno::Any( !bHidden ) );
+ }
+ catch( const uno::Exception& e )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( e.Message,
+ nullptr, anyEx );
+ }
+}
+
+sal_Bool SAL_CALL
+ScVbaRange::Replace( const OUString& What, const OUString& Replacement, const uno::Any& LookAt, const uno::Any& SearchOrder, const uno::Any& MatchCase, const uno::Any& MatchByte, const uno::Any& SearchFormat, const uno::Any& ReplaceFormat )
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ for ( sal_Int32 index = 1; index <= m_Areas->getCount(); ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->Replace( What, Replacement, LookAt, SearchOrder, MatchCase, MatchByte, SearchFormat, ReplaceFormat );
+ }
+ return true; // seems to return true always ( or at least I haven't found the trick of
+ }
+
+ // sanity check required params
+ if ( What.isEmpty() )
+ throw uno::RuntimeException("Range::Replace, missing params" );
+ OUString sWhat = VBAToRegexp( What);
+ // #TODO #FIXME SearchFormat & ReplacesFormat are not processed
+ // What do we do about MatchByte... we don't seem to support that
+ const SvxSearchItem& globalSearchOptions = ScGlobal::GetSearchItem();
+ SvxSearchItem newOptions( globalSearchOptions );
+
+ uno::Reference< util::XReplaceable > xReplace( mxRange, uno::UNO_QUERY );
+ if ( xReplace.is() )
+ {
+ uno::Reference< util::XReplaceDescriptor > xDescriptor =
+ xReplace->createReplaceDescriptor();
+
+ xDescriptor->setSearchString( sWhat);
+ xDescriptor->setPropertyValue( SC_UNO_SRCHREGEXP, uno::Any( true ) );
+ xDescriptor->setReplaceString( Replacement);
+ if ( LookAt.hasValue() )
+ {
+ // sets SearchWords ( true is Cell match )
+ sal_Int16 nLook = ::comphelper::getINT16( LookAt );
+ bool bSearchWords = false;
+ if ( nLook == excel::XlLookAt::xlPart )
+ bSearchWords = false;
+ else if ( nLook == excel::XlLookAt::xlWhole )
+ bSearchWords = true;
+ else
+ throw uno::RuntimeException("Range::Replace, illegal value for LookAt" );
+ // set global search props ( affects the find dialog
+ // and of course the defaults for this method
+ newOptions.SetWordOnly( bSearchWords );
+ xDescriptor->setPropertyValue( SC_UNO_SRCHWORDS, uno::Any( bSearchWords ) );
+ }
+ // sets SearchByRow ( true for Rows )
+ if ( SearchOrder.hasValue() )
+ {
+ sal_Int16 nSearchOrder = ::comphelper::getINT16( SearchOrder );
+ bool bSearchByRow = false;
+ if ( nSearchOrder == excel::XlSearchOrder::xlByColumns )
+ bSearchByRow = false;
+ else if ( nSearchOrder == excel::XlSearchOrder::xlByRows )
+ bSearchByRow = true;
+ else
+ throw uno::RuntimeException("Range::Replace, illegal value for SearchOrder" );
+
+ newOptions.SetRowDirection( bSearchByRow );
+ xDescriptor->setPropertyValue( SC_UNO_SRCHBYROW, uno::Any( bSearchByRow ) );
+ }
+ if ( MatchCase.hasValue() )
+ {
+ bool bMatchCase = false;
+
+ // SearchCaseSensitive
+ MatchCase >>= bMatchCase;
+ xDescriptor->setPropertyValue( SC_UNO_SRCHCASE, uno::Any( bMatchCase ) );
+ }
+
+ ScGlobal::SetSearchItem( newOptions );
+ // ignore MatchByte for the moment, it's not supported in
+ // OOo.org afaik
+
+ uno::Reference< container::XIndexAccess > xIndexAccess = xReplace->findAll( xDescriptor );
+ xReplace->replaceAll( xDescriptor );
+ if ( xIndexAccess.is() && xIndexAccess->getCount() > 0 )
+ {
+ for ( sal_Int32 i = 0; i < xIndexAccess->getCount(); ++i )
+ {
+ uno::Reference< table::XCellRange > xCellRange( xIndexAccess->getByIndex( i ), uno::UNO_QUERY );
+ if ( xCellRange.is() )
+ {
+ uno::Reference< excel::XRange > xRange( new ScVbaRange( mxParent, mxContext, xCellRange ) );
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( xRange, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XEnumeration > xEnum = xEnumAccess->createEnumeration();
+ while ( xEnum->hasMoreElements() )
+ {
+ uno::Reference< excel::XRange > xNextRange( xEnum->nextElement(), uno::UNO_QUERY_THROW );
+ ScVbaRange* pRange = dynamic_cast< ScVbaRange * > ( xNextRange.get() );
+ if ( pRange )
+ pRange->fireChangeEvent();
+ }
+ }
+ }
+ }
+ }
+ return true; // always
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaRange::Find( const uno::Any& What, const uno::Any& After, const uno::Any& LookIn, const uno::Any& LookAt, const uno::Any& SearchOrder, const uno::Any& SearchDirection, const uno::Any& MatchCase, const uno::Any& /*MatchByte*/, const uno::Any& /*SearchFormat*/ )
+{
+ // return a Range object that represents the first cell where that information is found.
+ OUString sWhat;
+ sal_Int32 nWhat = 0;
+ double fWhat = 0.0;
+
+ // string.
+ if( What >>= sWhat )
+ {}
+ else if( What >>= nWhat )
+ {
+ sWhat = OUString::number( nWhat );
+ }
+ else if( What >>= fWhat )
+ {
+ sWhat = OUString::number( fWhat );
+ }
+ else
+ throw uno::RuntimeException("Range::Find, missing search-for-what param" );
+
+ OUString sSearch = VBAToRegexp( sWhat );
+
+ const SvxSearchItem& globalSearchOptions = ScGlobal::GetSearchItem();
+ SvxSearchItem newOptions( globalSearchOptions );
+
+ uno::Reference< util::XSearchable > xSearch( mxRange, uno::UNO_QUERY );
+ if( xSearch.is() )
+ {
+ uno::Reference< util::XSearchDescriptor > xDescriptor = xSearch->createSearchDescriptor();
+ xDescriptor->setSearchString( sSearch );
+ xDescriptor->setPropertyValue( SC_UNO_SRCHREGEXP, uno::Any( true ) );
+
+ uno::Reference< excel::XRange > xAfterRange;
+ uno::Reference< table::XCellRange > xStartCell;
+ if( After >>= xAfterRange )
+ {
+ // After must be a single cell in the range
+ if( xAfterRange->getCount() > 1 )
+ throw uno::RuntimeException("After must be a single cell." );
+ uno::Reference< excel::XRange > xCell( Cells( uno::Any( xAfterRange->getRow() ), uno::Any( xAfterRange->getColumn() ) ), uno::UNO_SET_THROW );
+ xStartCell.set( xAfterRange->getCellRange(), uno::UNO_QUERY_THROW );
+ }
+
+ // LookIn
+ if( LookIn.hasValue() )
+ {
+ sal_Int32 nLookIn = 0;
+ if( LookIn >>= nLookIn )
+ {
+ SvxSearchCellType nSearchType;
+ switch( nLookIn )
+ {
+ case excel::XlFindLookIn::xlComments :
+ nSearchType = SvxSearchCellType::NOTE; // Notes
+ break;
+ case excel::XlFindLookIn::xlFormulas :
+ nSearchType = SvxSearchCellType::FORMULA;
+ break;
+ case excel::XlFindLookIn::xlValues :
+ nSearchType = SvxSearchCellType::VALUE;
+ break;
+ default:
+ throw uno::RuntimeException("Range::Find, illegal value for LookIn." );
+ }
+ newOptions.SetCellType( nSearchType );
+ xDescriptor->setPropertyValue( "SearchType", uno::Any( static_cast<sal_uInt16>(nSearchType) ) );
+ }
+ }
+
+ // LookAt
+ if ( LookAt.hasValue() )
+ {
+ sal_Int16 nLookAt = ::comphelper::getINT16( LookAt );
+ bool bSearchWords = false;
+ if ( nLookAt == excel::XlLookAt::xlPart )
+ bSearchWords = false;
+ else if ( nLookAt == excel::XlLookAt::xlWhole )
+ bSearchWords = true;
+ else
+ throw uno::RuntimeException("Range::Find, illegal value for LookAt" );
+ newOptions.SetWordOnly( bSearchWords );
+ xDescriptor->setPropertyValue( SC_UNO_SRCHWORDS, uno::Any( bSearchWords ) );
+ }
+
+ // SearchOrder
+ if ( SearchOrder.hasValue() )
+ {
+ sal_Int16 nSearchOrder = ::comphelper::getINT16( SearchOrder );
+ bool bSearchByRow = false;
+ if ( nSearchOrder == excel::XlSearchOrder::xlByColumns )
+ bSearchByRow = false;
+ else if ( nSearchOrder == excel::XlSearchOrder::xlByRows )
+ bSearchByRow = true;
+ else
+ throw uno::RuntimeException("Range::Find, illegal value for SearchOrder" );
+
+ newOptions.SetRowDirection( bSearchByRow );
+ xDescriptor->setPropertyValue( SC_UNO_SRCHBYROW, uno::Any( bSearchByRow ) );
+ }
+
+ // SearchDirection
+ if ( SearchDirection.hasValue() )
+ {
+ sal_Int32 nSearchDirection = 0;
+ if( SearchDirection >>= nSearchDirection )
+ {
+ bool bSearchBackwards = false;
+ if ( nSearchDirection == excel::XlSearchDirection::xlNext )
+ bSearchBackwards = false;
+ else if( nSearchDirection == excel::XlSearchDirection::xlPrevious )
+ bSearchBackwards = true;
+ else
+ throw uno::RuntimeException("Range::Find, illegal value for SearchDirection" );
+ newOptions.SetBackward( bSearchBackwards );
+ xDescriptor->setPropertyValue( "SearchBackwards", uno::Any( bSearchBackwards ) );
+ }
+ }
+
+ // MatchCase
+ bool bMatchCase = false;
+ if ( MatchCase.hasValue() )
+ {
+ // SearchCaseSensitive
+ if( !( MatchCase >>= bMatchCase ) )
+ throw uno::RuntimeException("Range::Find illegal value for MatchCase" );
+ }
+ xDescriptor->setPropertyValue( SC_UNO_SRCHCASE, uno::Any( bMatchCase ) );
+
+ // MatchByte
+ // SearchFormat
+ // ignore
+
+ ScGlobal::SetSearchItem( newOptions );
+
+ uno::Reference< uno::XInterface > xInterface = xStartCell.is() ? xSearch->findNext( xStartCell, xDescriptor) : xSearch->findFirst( xDescriptor );
+ uno::Reference< table::XCellRange > xCellRange( xInterface, uno::UNO_QUERY );
+ // if we are searching from a starting cell and failed to find a match
+ // then try from the beginning
+ if ( !xCellRange.is() && xStartCell.is() )
+ {
+ xInterface = xSearch->findFirst( xDescriptor );
+ xCellRange.set( xInterface, uno::UNO_QUERY );
+ }
+ if ( xCellRange.is() )
+ {
+ uno::Reference< excel::XRange > xResultRange = new ScVbaRange( mxParent, mxContext, xCellRange );
+ if( xResultRange.is() )
+ {
+ return xResultRange;
+ }
+ }
+
+ }
+
+ return uno::Reference< excel::XRange >();
+}
+
+static uno::Reference< table::XCellRange > processKey( const uno::Any& Key, const uno::Reference< uno::XComponentContext >& xContext, ScDocShell* pDocSh )
+{
+ uno::Reference< excel::XRange > xKeyRange;
+ if ( Key.getValueType() == cppu::UnoType<excel::XRange>::get() )
+ {
+ xKeyRange.set( Key, uno::UNO_QUERY_THROW );
+ }
+ else if ( Key.getValueType() == ::cppu::UnoType<OUString>::get() )
+
+ {
+ OUString sRangeName = ::comphelper::getString( Key );
+ table::CellRangeAddress aRefAddr;
+ if ( !pDocSh )
+ throw uno::RuntimeException("Range::Sort no docshell to calculate key param" );
+ xKeyRange = getRangeForName( xContext, sRangeName, pDocSh, aRefAddr );
+ }
+ else
+ throw uno::RuntimeException("Range::Sort illegal type value for key param" );
+ uno::Reference< table::XCellRange > xKey;
+ xKey.set( xKeyRange->getCellRange(), uno::UNO_QUERY_THROW );
+ return xKey;
+}
+
+// helper method for Sort
+/// @throws uno::RuntimeException
+static sal_Int32 findSortPropertyIndex( const uno::Sequence< beans::PropertyValue >& props,
+const OUString& sPropName )
+{
+ const beans::PropertyValue* pProp = std::find_if(props.begin(), props.end(),
+ [&sPropName](const beans::PropertyValue& rProp) { return rProp.Name == sPropName; });
+
+ if ( pProp == props.end() )
+ throw uno::RuntimeException("Range::Sort unknown sort property" );
+ return static_cast<sal_Int32>(std::distance(props.begin(), pProp));
+}
+
+// helper method for Sort
+/// @throws uno::RuntimeException
+static void updateTableSortField( const uno::Reference< table::XCellRange >& xParentRange,
+ const uno::Reference< table::XCellRange >& xColRowKey, sal_Int16 nOrder,
+ table::TableSortField& aTableField, bool bIsSortColumn, bool bMatchCase )
+{
+ RangeHelper parentRange( xParentRange );
+ RangeHelper colRowRange( xColRowKey );
+
+ table::CellRangeAddress parentRangeAddress = parentRange.getCellRangeAddressable()->getRangeAddress();
+
+ table::CellRangeAddress colRowKeyAddress = colRowRange.getCellRangeAddressable()->getRangeAddress();
+
+ // make sure that upper left point of key range is within the
+ // parent range
+ if (
+ ( bIsSortColumn || colRowKeyAddress.StartColumn < parentRangeAddress.StartColumn ||
+ colRowKeyAddress.StartColumn > parentRangeAddress.EndColumn )
+ &&
+ ( !bIsSortColumn || colRowKeyAddress.StartRow < parentRangeAddress.StartRow ||
+ colRowKeyAddress.StartRow > parentRangeAddress.EndRow )
+ )
+ throw uno::RuntimeException("Illegal Key param" );
+
+ //determine col/row index
+ if ( bIsSortColumn )
+ aTableField.Field = colRowKeyAddress.StartRow - parentRangeAddress.StartRow;
+ else
+ aTableField.Field = colRowKeyAddress.StartColumn - parentRangeAddress.StartColumn;
+ aTableField.IsCaseSensitive = bMatchCase;
+
+ if ( nOrder == excel::XlSortOrder::xlAscending )
+ aTableField.IsAscending = true;
+ else
+ aTableField.IsAscending = false;
+
+
+}
+
+void SAL_CALL
+ScVbaRange::Sort( const uno::Any& Key1, const uno::Any& Order1, const uno::Any& Key2, const uno::Any& /*Type*/, const uno::Any& Order2, const uno::Any& Key3, const uno::Any& Order3, const uno::Any& Header, const uno::Any& OrderCustom, const uno::Any& MatchCase, const uno::Any& Orientation, const uno::Any& SortMethod, const uno::Any& DataOption1, const uno::Any& DataOption2, const uno::Any& DataOption3 )
+{
+ // #TODO# #FIXME# can we do something with Type
+ if ( m_Areas->getCount() > 1 )
+ throw uno::RuntimeException("That command cannot be used on multiple selections" );
+
+ sal_Int16 nDataOption1 = excel::XlSortDataOption::xlSortNormal;
+ sal_Int16 nDataOption2 = excel::XlSortDataOption::xlSortNormal;
+ sal_Int16 nDataOption3 = excel::XlSortDataOption::xlSortNormal;
+
+ ScDocument& rDoc = getScDocument();
+
+ uno::Reference< table::XCellRange > xRangeCurrent;
+ if (isSingleCellRange())
+ {
+ // Expand to CurrentRegion
+ uno::Reference< excel::XRange > xCurrent( CurrentRegion());
+ if (xCurrent.is())
+ {
+ const ScVbaRange* pRange = getImplementation( xCurrent );
+ if (pRange)
+ xRangeCurrent = pRange->mxRange;
+ }
+ }
+ if (!xRangeCurrent.is())
+ xRangeCurrent = mxRange;
+ RangeHelper thisRange( xRangeCurrent );
+ table::CellRangeAddress thisRangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+
+ ScSortParam aSortParam;
+ SCTAB nTab = thisRangeAddress.Sheet;
+ rDoc.GetSortParam( aSortParam, nTab );
+
+ if ( DataOption1.hasValue() )
+ DataOption1 >>= nDataOption1;
+ if ( DataOption2.hasValue() )
+ DataOption2 >>= nDataOption2;
+ if ( DataOption3.hasValue() )
+ DataOption3 >>= nDataOption3;
+
+ // 1) #TODO #FIXME need to process DataOption[1..3] not used currently
+ // 2) #TODO #FIXME need to refactor this ( below ) into an IsSingleCell() method
+ uno::Reference< table::XColumnRowRange > xColumnRowRange(xRangeCurrent, uno::UNO_QUERY_THROW );
+
+ // set up defaults
+
+ sal_Int16 nOrder1 = aSortParam.maKeyState[0].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending;
+ sal_Int16 nOrder2 = aSortParam.maKeyState[1].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending;
+ sal_Int16 nOrder3 = aSortParam.maKeyState[2].bAscending ? excel::XlSortOrder::xlAscending : excel::XlSortOrder::xlDescending;
+
+ sal_Int16 nCustom = aSortParam.nUserIndex;
+ sal_Int16 nSortMethod = excel::XlSortMethod::xlPinYin;
+ bool bMatchCase = aSortParam.bCaseSens;
+
+ // seems to work opposite to expected, see below
+ sal_Int16 nOrientation = aSortParam.bByRow ? excel::XlSortOrientation::xlSortColumns : excel::XlSortOrientation::xlSortRows;
+
+ if ( Orientation.hasValue() )
+ {
+ // Documentation says xlSortRows is default but that doesn't appear to be
+ // the case. Also it appears that xlSortColumns is the default which
+ // strangely enough sorts by Row
+ nOrientation = ::comphelper::getINT16( Orientation );
+ // persist new option to be next calls default
+ if ( nOrientation == excel::XlSortOrientation::xlSortRows )
+ aSortParam.bByRow = false;
+ else
+ aSortParam.bByRow = true;
+
+ }
+
+ bool bIsSortColumns=false; // sort by row
+
+ if ( nOrientation == excel::XlSortOrientation::xlSortRows )
+ bIsSortColumns = true;
+ sal_Int16 nHeader = aSortParam.nCompatHeader;
+ bool bContainsHeader = false;
+
+ if ( Header.hasValue() )
+ {
+ nHeader = ::comphelper::getINT16( Header );
+ aSortParam.nCompatHeader = nHeader;
+ }
+
+ if ( nHeader == excel::XlYesNoGuess::xlGuess )
+ {
+ bool bHasColHeader = rDoc.HasColHeader( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), static_cast< SCCOL >( thisRangeAddress.EndColumn ), static_cast< SCROW >( thisRangeAddress.EndRow ), static_cast< SCTAB >( thisRangeAddress.Sheet ));
+ bool bHasRowHeader = rDoc.HasRowHeader( static_cast< SCCOL >( thisRangeAddress.StartColumn ), static_cast< SCROW >( thisRangeAddress.StartRow ), static_cast< SCCOL >( thisRangeAddress.EndColumn ), static_cast< SCROW >( thisRangeAddress.EndRow ), static_cast< SCTAB >( thisRangeAddress.Sheet ) );
+ if ( bHasColHeader || bHasRowHeader )
+ nHeader = excel::XlYesNoGuess::xlYes;
+ else
+ nHeader = excel::XlYesNoGuess::xlNo;
+ aSortParam.nCompatHeader = nHeader;
+ }
+
+ if ( nHeader == excel::XlYesNoGuess::xlYes )
+ bContainsHeader = true;
+
+ if ( SortMethod.hasValue() )
+ {
+ nSortMethod = ::comphelper::getINT16( SortMethod );
+ }
+
+ if ( OrderCustom.hasValue() )
+ {
+ OrderCustom >>= nCustom;
+ --nCustom; // 0-based in OOo
+ aSortParam.nUserIndex = nCustom;
+ }
+
+ if ( MatchCase.hasValue() )
+ {
+ MatchCase >>= bMatchCase;
+ aSortParam.bCaseSens = bMatchCase;
+ }
+
+ if ( Order1.hasValue() )
+ {
+ nOrder1 = ::comphelper::getINT16(Order1);
+ if ( nOrder1 == excel::XlSortOrder::xlAscending )
+ aSortParam.maKeyState[0].bAscending = true;
+ else
+ aSortParam.maKeyState[0].bAscending = false;
+
+ }
+ if ( Order2.hasValue() )
+ {
+ nOrder2 = ::comphelper::getINT16(Order2);
+ if ( nOrder2 == excel::XlSortOrder::xlAscending )
+ aSortParam.maKeyState[1].bAscending = true;
+ else
+ aSortParam.maKeyState[1].bAscending = false;
+ }
+ if ( Order3.hasValue() )
+ {
+ nOrder3 = ::comphelper::getINT16(Order3);
+ if ( nOrder3 == excel::XlSortOrder::xlAscending )
+ aSortParam.maKeyState[2].bAscending = true;
+ else
+ aSortParam.maKeyState[2].bAscending = false;
+ }
+
+ uno::Reference< table::XCellRange > xKey1;
+ uno::Reference< table::XCellRange > xKey2;
+ uno::Reference< table::XCellRange > xKey3;
+ ScDocShell* pDocShell = getScDocShell();
+ xKey1 = processKey( Key1, mxContext, pDocShell );
+ if ( !xKey1.is() )
+ throw uno::RuntimeException("Range::Sort needs a key1 param" );
+
+ if ( Key2.hasValue() )
+ xKey2 = processKey( Key2, mxContext, pDocShell );
+ if ( Key3.hasValue() )
+ xKey3 = processKey( Key3, mxContext, pDocShell );
+
+ uno::Reference< util::XSortable > xSort( xRangeCurrent, uno::UNO_QUERY_THROW );
+ uno::Sequence< beans::PropertyValue > sortDescriptor = xSort->createSortDescriptor();
+ auto psortDescriptor = sortDescriptor.getArray();
+ sal_Int32 nTableSortFieldIndex = findSortPropertyIndex( sortDescriptor, "SortFields" );
+
+ uno::Sequence< table::TableSortField > sTableFields(1);
+ sal_Int32 nTableIndex = 0;
+ updateTableSortField( xRangeCurrent, xKey1, nOrder1, sTableFields.getArray()[ nTableIndex++ ], bIsSortColumns, bMatchCase );
+
+ if ( xKey2.is() )
+ {
+ sTableFields.realloc( sTableFields.getLength() + 1 );
+ updateTableSortField( xRangeCurrent, xKey2, nOrder2, sTableFields.getArray()[ nTableIndex++ ], bIsSortColumns, bMatchCase );
+ }
+ if ( xKey3.is() )
+ {
+ sTableFields.realloc( sTableFields.getLength() + 1 );
+ updateTableSortField( xRangeCurrent, xKey3, nOrder3, sTableFields.getArray()[ nTableIndex++ ], bIsSortColumns, bMatchCase );
+ }
+ psortDescriptor[ nTableSortFieldIndex ].Value <<= sTableFields;
+
+ sal_Int32 nIndex = findSortPropertyIndex( sortDescriptor, "IsSortColumns" );
+ psortDescriptor[ nIndex ].Value <<= bIsSortColumns;
+
+ nIndex = findSortPropertyIndex( sortDescriptor, "ContainsHeader" );
+ psortDescriptor[ nIndex ].Value <<= bContainsHeader;
+
+ rDoc.SetSortParam( aSortParam, nTab );
+ xSort->sort( sortDescriptor );
+
+ // #FIXME #TODO
+ // The SortMethod param is not processed ( not sure what its all about, need to
+ (void)nSortMethod;
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaRange::End( ::sal_Int32 Direction )
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( getArea( 0 ), uno::UNO_SET_THROW );
+ return xRange->End( Direction );
+ }
+
+ // #FIXME #TODO
+ // euch! found my orig implementation sucked, so
+ // trying this even sucker one (really need to use/expose code in
+ // around ScTabView::MoveCursorArea(), that's the bit that calculates
+ // where the cursor should go)
+ // Main problem with this method is the ultra hacky attempt to preserve
+ // the ActiveCell, there should be no need to go to these extremes
+
+ // Save ActiveSheet/ActiveCell pos (to restore later)
+ uno::Any aDft;
+ uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XWorksheet > sActiveSheet = xApplication->getActiveSheet();
+ OUString sActiveCell = xApplication->getActiveCell()->Address(aDft, aDft, aDft, aDft, aDft );
+
+ // position current cell upper left of this range
+ Cells( uno::Any( sal_Int32(1) ), uno::Any( sal_Int32(1) ) )->Select();
+
+ uno::Reference< frame::XModel > xModel = getModelFromRange( mxRange );
+
+ SfxViewFrame* pViewFrame = excel::getViewFrame( xModel );
+ if ( pViewFrame )
+ {
+ SfxAllItemSet aArgs( SfxGetpApp()->GetPool() );
+ // Hoping this will make sure this slot is called
+ // synchronously
+ SfxBoolItem sfxAsync( SID_ASYNCHRON, false );
+ aArgs.Put( sfxAsync, sfxAsync.Which() );
+ SfxDispatcher* pDispatcher = pViewFrame->GetDispatcher();
+
+ sal_uInt16 nSID = 0;
+
+ switch( Direction )
+ {
+ case excel::XlDirection::xlDown:
+ nSID = SID_CURSORBLKDOWN;
+ break;
+ case excel::XlDirection::xlUp:
+ nSID = SID_CURSORBLKUP;
+ break;
+ case excel::XlDirection::xlToLeft:
+ nSID = SID_CURSORBLKLEFT;
+ break;
+ case excel::XlDirection::xlToRight:
+ nSID = SID_CURSORBLKRIGHT;
+ break;
+ default:
+ throw uno::RuntimeException(": Invalid ColumnIndex" );
+ }
+ if ( pDispatcher )
+ {
+ pDispatcher->Execute( nSID, SfxCallMode::SYNCHRON, aArgs );
+ }
+ }
+
+ // result is the ActiveCell
+ OUString sMoved = xApplication->getActiveCell()->Address(aDft, aDft, aDft, aDft, aDft );
+
+ uno::Any aVoid;
+ uno::Reference< excel::XRange > resultCell;
+ resultCell.set( xApplication->getActiveSheet()->Range( uno::Any( sMoved ), aVoid ), uno::UNO_SET_THROW );
+
+ // restore old ActiveCell
+ uno::Reference< excel::XRange > xOldActiveCell( sActiveSheet->Range( uno::Any( sActiveCell ), aVoid ), uno::UNO_SET_THROW );
+ xOldActiveCell->Select();
+
+
+ // return result
+ return resultCell;
+}
+
+bool
+ScVbaRange::isSingleCellRange() const
+{
+ uno::Reference< sheet::XCellRangeAddressable > xAddressable( mxRange, uno::UNO_QUERY );
+ if ( xAddressable.is() )
+ {
+ table::CellRangeAddress aRangeAddr = xAddressable->getRangeAddress();
+ return ( aRangeAddr.EndColumn == aRangeAddr.StartColumn && aRangeAddr.EndRow == aRangeAddr.StartRow );
+ }
+ return false;
+}
+
+uno::Reference< excel::XCharacters > SAL_CALL
+ScVbaRange::characters( const uno::Any& Start, const uno::Any& Length )
+{
+ if ( !isSingleCellRange() )
+ throw uno::RuntimeException("Can't create Characters property for multicell range " );
+ uno::Reference< text::XSimpleText > xSimple(mxRange->getCellByPosition(0,0) , uno::UNO_QUERY_THROW );
+ ScDocument& rDoc = getDocumentFromRange(mxRange);
+
+ ScVbaPalette aPalette( rDoc.GetDocumentShell() );
+ return new ScVbaCharacters( this, mxContext, aPalette, xSimple, Start, Length );
+}
+
+ void SAL_CALL
+ScVbaRange::Delete( const uno::Any& Shift )
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->Delete( Shift );
+ }
+ return;
+ }
+ sheet::CellDeleteMode mode = sheet::CellDeleteMode_NONE ;
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ if ( Shift.hasValue() )
+ {
+ sal_Int32 nShift = 0;
+ Shift >>= nShift;
+ switch ( nShift )
+ {
+ case excel::XlDeleteShiftDirection::xlShiftUp:
+ mode = sheet::CellDeleteMode_UP;
+ break;
+ case excel::XlDeleteShiftDirection::xlShiftToLeft:
+ mode = sheet::CellDeleteMode_LEFT;
+ break;
+ default:
+ throw uno::RuntimeException("Illegal parameter " );
+ }
+ }
+ else
+ {
+ ScDocument& rDoc = getScDocument();
+ bool bFullRow = ( thisAddress.StartColumn == 0 && thisAddress.EndColumn == rDoc.MaxCol() );
+ sal_Int32 nCols = thisAddress.EndColumn - thisAddress.StartColumn;
+ sal_Int32 nRows = thisAddress.EndRow - thisAddress.StartRow;
+ if ( mbIsRows || bFullRow || ( nCols >= nRows ) )
+ mode = sheet::CellDeleteMode_UP;
+ else
+ mode = sheet::CellDeleteMode_LEFT;
+ }
+ uno::Reference< sheet::XCellRangeMovement > xCellRangeMove( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
+ xCellRangeMove->removeRange( thisAddress, mode );
+
+}
+
+//XElementAccess
+sal_Bool SAL_CALL
+ScVbaRange::hasElements()
+{
+ uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY );
+ if ( xColumnRowRange.is() )
+ if ( xColumnRowRange->getRows()->getCount() ||
+ xColumnRowRange->getColumns()->getCount() )
+ return true;
+ return false;
+}
+
+// XEnumerationAccess
+uno::Reference< container::XEnumeration > SAL_CALL
+ScVbaRange::createEnumeration()
+{
+ if ( mbIsColumns || mbIsRows )
+ {
+ uno::Reference< table::XColumnRowRange > xColumnRowRange(mxRange, uno::UNO_QUERY );
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW );
+ sal_Int32 nElems = 0;
+ if ( mbIsColumns )
+ nElems = xColumnRowRange->getColumns()->getCount();
+ else
+ nElems = xColumnRowRange->getRows()->getCount();
+ return new ColumnsRowEnumeration( xRange, nElems );
+
+ }
+ return new CellsEnumeration( mxParent, mxContext, m_Areas );
+}
+
+OUString SAL_CALL
+ScVbaRange::getDefaultMethodName( )
+{
+ return "Item";
+}
+
+// returns calc internal col. width ( in points )
+double
+ScVbaRange::getCalcColWidth(const table::CellRangeAddress& rAddress)
+{
+ ScDocument& rDoc = getScDocument();
+ sal_uInt16 nWidth = rDoc.GetOriginalWidth( static_cast< SCCOL >( rAddress.StartColumn ), static_cast< SCTAB >( rAddress.Sheet ) );
+ double nPoints = lcl_TwipsToPoints( nWidth );
+ nPoints = lcl_Round2DecPlaces( nPoints );
+ return nPoints;
+}
+
+double
+ScVbaRange::getCalcRowHeight(const table::CellRangeAddress& rAddress)
+{
+ ScDocument& rDoc = getDocumentFromRange( mxRange );
+ sal_uInt16 nWidth = rDoc.GetOriginalHeight( rAddress.StartRow, rAddress.Sheet );
+ double nPoints = lcl_TwipsToPoints( nWidth );
+ nPoints = lcl_Round2DecPlaces( nPoints );
+ return nPoints;
+}
+
+// return Char Width in points
+static double getDefaultCharWidth( ScDocShell* pDocShell )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OutputDevice* pRefDevice = rDoc.GetRefDevice();
+ ScPatternAttr* pAttr = rDoc.GetDefPattern();
+ vcl::Font aDefFont;
+ pAttr->GetFont( aDefFont, SC_AUTOCOL_BLACK, pRefDevice );
+ pRefDevice->SetFont( aDefFont );
+ tools::Long nCharWidth = pRefDevice->GetTextWidth( OUString( '0' ) ); // 1/100th mm
+ return o3tl::convert<double>(nCharWidth, o3tl::Length::mm100, o3tl::Length::pt);
+}
+
+uno::Any SAL_CALL
+ScVbaRange::getColumnWidth()
+{
+ sal_Int32 nLen = m_Areas->getCount();
+ if ( nLen > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW );
+ return xRange->getColumnWidth();
+ }
+
+ double nColWidth = 0;
+ ScDocShell* pShell = getScDocShell();
+ if ( pShell )
+ {
+ double defaultCharWidth = getDefaultCharWidth( pShell );
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ sal_Int32 nStartCol = thisAddress.StartColumn;
+ sal_Int32 nEndCol = thisAddress.EndColumn;
+ sal_uInt16 nColTwips = 0;
+ for( sal_Int32 nCol = nStartCol ; nCol <= nEndCol; ++nCol )
+ {
+ thisAddress.StartColumn = nCol;
+ sal_uInt16 nCurTwips = pShell->GetDocument().GetOriginalWidth( static_cast< SCCOL >( thisAddress.StartColumn ), static_cast< SCTAB >( thisAddress.Sheet ) );
+ if ( nCol == nStartCol )
+ nColTwips = nCurTwips;
+ if ( nColTwips != nCurTwips )
+ return aNULL();
+ }
+ nColWidth = lcl_TwipsToPoints( nColTwips );
+ if ( nColWidth != 0.0 )
+ nColWidth = ( nColWidth / defaultCharWidth ) - fExtraWidth;
+ }
+ nColWidth = lcl_Round2DecPlaces( nColWidth );
+ return uno::Any( nColWidth );
+}
+
+void SAL_CALL
+ScVbaRange::setColumnWidth( const uno::Any& _columnwidth )
+{
+ sal_Int32 nLen = m_Areas->getCount();
+ if ( nLen > 1 )
+ {
+ for ( sal_Int32 index = 1; index != nLen; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->setColumnWidth( _columnwidth );
+ }
+ return;
+ }
+ double nColWidth = 0;
+ _columnwidth >>= nColWidth;
+ nColWidth = lcl_Round2DecPlaces( nColWidth );
+ ScDocShell* pDocShell = getScDocShell();
+ if ( !pDocShell )
+ return;
+
+ if ( nColWidth != 0.0 )
+ nColWidth = ( nColWidth + fExtraWidth ) * getDefaultCharWidth( pDocShell );
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ sal_uInt16 nTwips = lcl_pointsToTwips( nColWidth );
+
+ std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(thisAddress.StartColumn, thisAddress.EndColumn));
+ // #163561# use mode SC_SIZE_DIRECT: hide for width 0, show for other values
+ pDocShell->GetDocFunc().SetWidthOrHeight(
+ true, aColArr, thisAddress.Sheet, SC_SIZE_DIRECT, nTwips, true, true);
+}
+
+uno::Any SAL_CALL
+ScVbaRange::getWidth()
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW );
+ return xRange->getWidth();
+ }
+ uno::Reference< table::XColumnRowRange > xColRowRange( mxRange, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xIndexAccess( xColRowRange->getColumns(), uno::UNO_QUERY_THROW );
+ sal_Int32 nElems = xIndexAccess->getCount();
+ double nWidth = 0;
+ for ( sal_Int32 index=0; index<nElems; ++index )
+ {
+ uno::Reference< sheet::XCellRangeAddressable > xAddressable( xIndexAccess->getByIndex( index ), uno::UNO_QUERY_THROW );
+ double nTmpWidth = getCalcColWidth( xAddressable->getRangeAddress() );
+ nWidth += nTmpWidth;
+ }
+ return uno::Any( nWidth );
+}
+
+uno::Any SAL_CALL
+ScVbaRange::Areas( const uno::Any& item)
+{
+ if ( !item.hasValue() )
+ return uno::Any( m_Areas );
+ return m_Areas->Item( item, uno::Any() );
+}
+
+uno::Reference< excel::XRange >
+ScVbaRange::getArea( sal_Int32 nIndex )
+{
+ if ( !m_Areas.is() )
+ throw uno::RuntimeException("No areas available" );
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( ++nIndex ), uno::Any() ), uno::UNO_QUERY_THROW );
+ return xRange;
+}
+
+uno::Any
+ScVbaRange::Borders( const uno::Any& item )
+{
+ if ( !item.hasValue() )
+ return uno::Any( getBorders() );
+ return getBorders()->Item( item, uno::Any() );
+}
+
+uno::Any SAL_CALL
+ScVbaRange::BorderAround( const css::uno::Any& LineStyle, const css::uno::Any& Weight,
+ const css::uno::Any& ColorIndex, const css::uno::Any& Color )
+{
+ sal_Int32 nCount = getBorders()->getCount();
+
+ for( sal_Int32 i = 0; i < nCount; i++ )
+ {
+ const sal_Int32 nLineType = supportedIndexTable[i];
+ switch( nLineType )
+ {
+ case excel::XlBordersIndex::xlEdgeLeft:
+ case excel::XlBordersIndex::xlEdgeTop:
+ case excel::XlBordersIndex::xlEdgeBottom:
+ case excel::XlBordersIndex::xlEdgeRight:
+ {
+ uno::Reference< excel::XBorder > xBorder( m_Borders->Item( uno::Any( nLineType ), uno::Any() ), uno::UNO_QUERY_THROW );
+ if( LineStyle.hasValue() )
+ {
+ xBorder->setLineStyle( LineStyle );
+ }
+ if( Weight.hasValue() )
+ {
+ xBorder->setWeight( Weight );
+ }
+ if( ColorIndex.hasValue() )
+ {
+ xBorder->setColorIndex( ColorIndex );
+ }
+ if( Color.hasValue() )
+ {
+ xBorder->setColor( Color );
+ }
+ break;
+ }
+ case excel::XlBordersIndex::xlInsideVertical:
+ case excel::XlBordersIndex::xlInsideHorizontal:
+ case excel::XlBordersIndex::xlDiagonalDown:
+ case excel::XlBordersIndex::xlDiagonalUp:
+ break;
+ default:
+ return uno::Any( false );
+ }
+ }
+ return uno::Any( true );
+}
+
+uno::Any SAL_CALL
+ScVbaRange::getRowHeight()
+{
+ sal_Int32 nLen = m_Areas->getCount();
+ if ( nLen > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW );
+ return xRange->getRowHeight();
+ }
+
+ // if any row's RowHeight in the
+ // range is different from any other, then return NULL
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+
+ sal_Int32 nStartRow = thisAddress.StartRow;
+ sal_Int32 nEndRow = thisAddress.EndRow;
+ sal_uInt16 nRowTwips = 0;
+ // #TODO probably possible to use the SfxItemSet (and see if
+ // SfxItemState::DONTCARE is set) to improve performance
+// #CHECKME looks like this is general behaviour not just row Range specific
+// if ( mbIsRows )
+ ScDocShell* pShell = getScDocShell();
+ if ( pShell )
+ {
+ for ( sal_Int32 nRow = nStartRow ; nRow <= nEndRow; ++nRow )
+ {
+ thisAddress.StartRow = nRow;
+ sal_uInt16 nCurTwips = pShell->GetDocument().GetOriginalHeight( thisAddress.StartRow, thisAddress.Sheet );
+ if ( nRow == nStartRow )
+ nRowTwips = nCurTwips;
+ if ( nRowTwips != nCurTwips )
+ return aNULL();
+ }
+ }
+ double nHeight = lcl_Round2DecPlaces( lcl_TwipsToPoints( nRowTwips ) );
+ return uno::Any( nHeight );
+}
+
+void SAL_CALL
+ScVbaRange::setRowHeight( const uno::Any& _rowheight)
+{
+ sal_Int32 nLen = m_Areas->getCount();
+ if ( nLen > 1 )
+ {
+ for ( sal_Int32 index = 1; index != nLen; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->setRowHeight( _rowheight );
+ }
+ return;
+ }
+ double nHeight = 0; // Incoming height is in points
+ _rowheight >>= nHeight;
+ nHeight = lcl_Round2DecPlaces( nHeight );
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ sal_uInt16 nTwips = lcl_pointsToTwips( nHeight );
+
+ ScDocShell* pDocShell = getDocShellFromRange( mxRange );
+ std::vector<sc::ColRowSpan> aRowArr(1, sc::ColRowSpan(thisAddress.StartRow, thisAddress.EndRow));
+ pDocShell->GetDocFunc().SetWidthOrHeight(
+ false, aRowArr, thisAddress.Sheet, SC_SIZE_ORIGINAL, nTwips, true, true);
+}
+
+uno::Any SAL_CALL
+ScVbaRange::getPageBreak()
+{
+ sal_Int32 nPageBreak = excel::XlPageBreak::xlPageBreakNone;
+ ScDocShell* pShell = getDocShellFromRange( mxRange );
+ if ( pShell )
+ {
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ bool bColumn = false;
+
+ if (thisAddress.StartRow==0)
+ bColumn = true;
+
+ uno::Reference< frame::XModel > xModel = pShell->GetModel();
+ if ( xModel.is() )
+ {
+ ScDocument& rDoc = getDocumentFromRange( mxRange );
+
+ ScBreakType nBreak = ScBreakType::NONE;
+ if ( !bColumn )
+ nBreak = rDoc.HasRowBreak(thisAddress.StartRow, thisAddress.Sheet);
+ else
+ nBreak = rDoc.HasColBreak(thisAddress.StartColumn, thisAddress.Sheet);
+
+ if (nBreak & ScBreakType::Page)
+ nPageBreak = excel::XlPageBreak::xlPageBreakAutomatic;
+
+ if (nBreak & ScBreakType::Manual)
+ nPageBreak = excel::XlPageBreak::xlPageBreakManual;
+ }
+ }
+
+ return uno::Any( nPageBreak );
+}
+
+void SAL_CALL
+ScVbaRange::setPageBreak( const uno::Any& _pagebreak)
+{
+ sal_Int32 nPageBreak = 0;
+ _pagebreak >>= nPageBreak;
+
+ ScDocShell* pShell = getDocShellFromRange( mxRange );
+ if ( !pShell )
+ return;
+
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ if ((thisAddress.StartColumn==0) && (thisAddress.StartRow==0))
+ return;
+ bool bColumn = false;
+
+ if (thisAddress.StartRow==0)
+ bColumn = true;
+
+ ScAddress aAddr( static_cast<SCCOL>(thisAddress.StartColumn), thisAddress.StartRow, thisAddress.Sheet );
+ uno::Reference< frame::XModel > xModel = pShell->GetModel();
+ if ( xModel.is() )
+ {
+ ScTabViewShell* pViewShell = excel::getBestViewShell( xModel );
+ if ( nPageBreak == excel::XlPageBreak::xlPageBreakManual )
+ pViewShell->InsertPageBreak( bColumn, true, &aAddr);
+ else if ( nPageBreak == excel::XlPageBreak::xlPageBreakNone )
+ pViewShell->DeletePageBreak( bColumn, true, &aAddr);
+ }
+}
+
+uno::Any SAL_CALL
+ScVbaRange::getHeight()
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32(1) ), uno::Any() ), uno::UNO_QUERY_THROW );
+ return xRange->getHeight();
+ }
+
+ uno::Reference< table::XColumnRowRange > xColRowRange( mxRange, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xIndexAccess( xColRowRange->getRows(), uno::UNO_QUERY_THROW );
+ sal_Int32 nElems = xIndexAccess->getCount();
+ double nHeight = 0;
+ for ( sal_Int32 index=0; index<nElems; ++index )
+ {
+ uno::Reference< sheet::XCellRangeAddressable > xAddressable( xIndexAccess->getByIndex( index ), uno::UNO_QUERY_THROW );
+ nHeight += getCalcRowHeight(xAddressable->getRangeAddress() );
+ }
+ return uno::Any( nHeight );
+}
+
+awt::Point
+ScVbaRange::getPosition() const
+{
+ awt::Point aPoint;
+ uno::Reference< beans::XPropertySet > xProps;
+ if ( mxRange.is() )
+ xProps.set( mxRange, uno::UNO_QUERY_THROW );
+ else
+ xProps.set( mxRanges, uno::UNO_QUERY_THROW );
+ xProps->getPropertyValue( "Position" ) >>= aPoint;
+ return aPoint;
+}
+uno::Any SAL_CALL
+ScVbaRange::getLeft()
+{
+ // helperapi returns the first ranges left ( and top below )
+ if ( m_Areas->getCount() > 1 )
+ return getArea( 0 )->getLeft();
+ awt::Point aPoint = getPosition();
+ return uno::Any(o3tl::convert<double>(aPoint.X, o3tl::Length::mm100, o3tl::Length::pt));
+}
+
+uno::Any SAL_CALL
+ScVbaRange::getTop()
+{
+ // helperapi returns the first ranges top
+ if ( m_Areas->getCount() > 1 )
+ return getArea( 0 )->getTop();
+ awt::Point aPoint= getPosition();
+ return uno::Any(o3tl::convert<double>(aPoint.Y, o3tl::Length::mm100, o3tl::Length::pt));
+}
+
+static uno::Reference< sheet::XCellRangeReferrer > getNamedRange( const uno::Reference< uno::XInterface >& xIf, const uno::Reference< table::XCellRange >& thisRange )
+{
+ uno::Reference< beans::XPropertySet > xProps( xIf, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xNameAccess( xProps->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW );
+
+ const uno::Sequence< OUString > sNames = xNameAccess->getElementNames();
+// uno::Reference< table::XCellRange > thisRange( getCellRange(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XCellRangeReferrer > xNamedRange;
+ for ( const auto& rName : sNames )
+ {
+ uno::Reference< sheet::XCellRangeReferrer > xName( xNameAccess->getByName( rName ), uno::UNO_QUERY );
+ if ( xName.is() )
+ {
+ if ( thisRange == xName->getReferredCells() )
+ {
+ xNamedRange = xName;
+ break;
+ }
+ }
+ }
+ return xNamedRange;
+}
+
+uno::Reference< excel::XName >
+ScVbaRange::getName()
+{
+ uno::Reference< beans::XPropertySet > xProps( getUnoModel(), uno::UNO_QUERY );
+ uno::Reference< table::XCellRange > thisRange( getCellRange(), uno::UNO_QUERY_THROW );
+ // Application range
+ uno::Reference< sheet::XCellRangeReferrer > xNamedRange = getNamedRange( xProps, thisRange );
+
+ if ( !xNamedRange.is() )
+ {
+ // not in application range then assume it might be in
+ // sheet namedranges
+ RangeHelper aRange( thisRange );
+ uno::Reference< sheet::XSpreadsheet > xSheet = aRange.getSpreadSheet();
+ xProps.set( xSheet, uno::UNO_QUERY );
+ // impl here
+ xNamedRange = getNamedRange( xProps, thisRange );
+ }
+ if ( xProps.is() && xNamedRange.is() )
+ {
+ uno::Reference< sheet::XNamedRanges > xNamedRanges( xProps, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XNamedRange > xName( xNamedRange, uno::UNO_QUERY_THROW );
+ return new ScVbaName( mxParent, mxContext, xName, xNamedRanges, getUnoModel() );
+ }
+ return uno::Reference< excel::XName >();
+}
+
+uno::Reference< excel::XWorksheet >
+ScVbaRange::getWorksheet()
+{
+ // #TODO #FIXME parent should always be set up ( currently that's not
+ // the case )
+ uno::Reference< excel::XWorksheet > xSheet( getParent(), uno::UNO_QUERY );
+ if ( !xSheet.is() )
+ {
+ uno::Reference< table::XCellRange > xRange = mxRange;
+
+ if ( mxRanges.is() ) // assign xRange to first range
+ {
+ uno::Reference< container::XIndexAccess > xIndex( mxRanges, uno::UNO_QUERY_THROW );
+ xRange.set( xIndex->getByIndex( 0 ), uno::UNO_QUERY_THROW );
+ }
+ ScDocShell* pDocShell = getDocShellFromRange(xRange);
+ RangeHelper rHelper(xRange);
+ // parent should be Thisworkbook
+ xSheet.set( new ScVbaWorksheet( uno::Reference< XHelperInterface >(), mxContext,rHelper.getSpreadSheet(),pDocShell->GetModel()) );
+ }
+ return xSheet;
+}
+
+// #TODO remove this ugly application processing
+// Process an application Range request e.g. 'Range("a1,b2,a4:b6")
+uno::Reference< excel::XRange >
+ScVbaRange::ApplicationRange( const uno::Reference< uno::XComponentContext >& xContext, const css::uno::Any &Cell1, const css::uno::Any &Cell2 )
+{
+ // Although the documentation seems clear that Range without a
+ // qualifier then it's a shortcut for ActiveSheet.Range
+ // however, similarly Application.Range is apparently also a
+ // shortcut for ActiveSheet.Range
+ // The is however a subtle behavioural difference I've come across
+ // wrt to named ranges.
+ // If a named range "test" exists { Sheet1!$A1 } and the active sheet
+ // is Sheet2 then the following will fail
+ // msgbox ActiveSheet.Range("test").Address ' fails
+ // msgbox WorkSheets("Sheet2").Range("test").Address
+ // but!!!
+ // msgbox Range("test").Address ' works
+ // msgbox Application.Range("test").Address ' works
+
+ // Single param Range
+ OUString sRangeName;
+ Cell1 >>= sRangeName;
+ if ( Cell1.hasValue() && !Cell2.hasValue() && !sRangeName.isEmpty() )
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( getCurrentExcelDoc(xContext), uno::UNO_QUERY_THROW );
+
+ uno::Reference< container::XNameAccess > xNamed( xPropSet->getPropertyValue( "NamedRanges" ), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XCellRangeReferrer > xReferrer;
+ try
+ {
+ xReferrer.set ( xNamed->getByName( sRangeName ), uno::UNO_QUERY );
+ }
+ catch( uno::Exception& /*e*/ )
+ {
+ // do nothing
+ }
+ if ( xReferrer.is() )
+ {
+ uno::Reference< table::XCellRange > xRange = xReferrer->getReferredCells();
+ if ( xRange.is() )
+ {
+ uno::Reference< excel::XRange > xVbRange = new ScVbaRange( excel::getUnoSheetModuleObj( xRange ), xContext, xRange );
+ return xVbRange;
+ }
+ }
+ }
+
+ uno::Reference<table::XCellRange> xSheetRange;
+
+ try
+ {
+ uno::Reference<sheet::XSpreadsheetView> xView(
+ getCurrentExcelDoc(xContext)->getCurrentController(), uno::UNO_QUERY_THROW);
+
+ xSheetRange.set(xView->getActiveSheet(), uno::UNO_QUERY_THROW);
+ }
+ catch (const uno::Exception&)
+ {
+ return uno::Reference<excel::XRange>();
+ }
+
+ rtl::Reference<ScVbaRange> pRange = new ScVbaRange( excel::getUnoSheetModuleObj( xSheetRange ), xContext, xSheetRange );
+ return pRange->Range( Cell1, Cell2, true );
+}
+
+// Helper functions for AutoFilter
+static ScDBData* lcl_GetDBData_Impl( ScDocShell* pDocShell, sal_Int16 nSheet )
+{
+ ScDBData* pRet = nullptr;
+ if (pDocShell)
+ {
+ pRet = pDocShell->GetDocument().GetAnonymousDBData(nSheet);
+ }
+ return pRet;
+}
+
+static void lcl_SelectAll( ScDocShell* pDocShell, const ScQueryParam& aParam )
+{
+ if ( !pDocShell )
+ return;
+
+ ScViewData* pViewData = ScDocShell::GetViewData();
+ if ( !pViewData )
+ {
+ ScTabViewShell* pViewSh = pDocShell->GetBestViewShell( true );
+ pViewData = pViewSh ? &pViewSh->GetViewData() : nullptr;
+ }
+
+ if ( pViewData )
+ {
+ pViewData->GetView()->Query( aParam, nullptr, true );
+ }
+}
+
+static ScQueryParam lcl_GetQueryParam( ScDocShell* pDocShell, sal_Int16 nSheet )
+{
+ ScDBData* pDBData = lcl_GetDBData_Impl( pDocShell, nSheet );
+ ScQueryParam aParam;
+ if (pDBData)
+ {
+ pDBData->GetQueryParam( aParam );
+ }
+ return aParam;
+}
+
+static void lcl_SetAllQueryForField( ScDocShell* pDocShell, SCCOLROW nField, sal_Int16 nSheet )
+{
+ ScQueryParam aParam = lcl_GetQueryParam( pDocShell, nSheet );
+ aParam.RemoveEntryByField(nField);
+ lcl_SelectAll( pDocShell, aParam );
+}
+
+// Modifies sCriteria, and nOp depending on the value of sCriteria
+static void lcl_setTableFieldsFromCriteria( OUString& sCriteria1, const uno::Reference< beans::XPropertySet >& xDescProps, sheet::TableFilterField2& rFilterField )
+{
+ // #TODO make this more efficient and cycle through
+ // sCriteria1 character by character to pick up <,<>,=, * etc.
+ // right now I am more concerned with just getting it to work right
+
+ sCriteria1 = sCriteria1.trim();
+ // table of translation of criteria text to FilterOperators
+ // <>searchtext - NOT_EQUAL
+ // =searchtext - EQUAL
+ // *searchtext - startwith
+ // <>*searchtext - doesn't startwith
+ // *searchtext* - contains
+ // <>*searchtext* - doesn't contain
+ // [>|>=|<=|...]searchtext for GREATER_value, GREATER_EQUAL_value etc.
+ if ( sCriteria1.startsWith( EQUALS ) )
+ {
+ if ( o3tl::make_unsigned(sCriteria1.getLength()) == strlen(EQUALS) )
+ rFilterField.Operator = sheet::FilterOperator2::EMPTY;
+ else
+ {
+ rFilterField.Operator = sheet::FilterOperator2::EQUAL;
+ sCriteria1 = sCriteria1.copy( strlen(EQUALS) );
+ sCriteria1 = VBAToRegexp( sCriteria1 );
+ // UseRegularExpressions
+ if ( xDescProps.is() )
+ xDescProps->setPropertyValue( "UseRegularExpressions", uno::Any( true ) );
+ }
+
+ }
+ else if ( sCriteria1.startsWith( NOTEQUALS ) )
+ {
+ if ( o3tl::make_unsigned(sCriteria1.getLength()) == strlen(NOTEQUALS) )
+ rFilterField.Operator = sheet::FilterOperator2::NOT_EMPTY;
+ else
+ {
+ rFilterField.Operator = sheet::FilterOperator2::NOT_EQUAL;
+ sCriteria1 = sCriteria1.copy( strlen(NOTEQUALS) );
+ sCriteria1 = VBAToRegexp( sCriteria1 );
+ // UseRegularExpressions
+ if ( xDescProps.is() )
+ xDescProps->setPropertyValue( "UseRegularExpressions", uno::Any( true ) );
+ }
+ }
+ else if ( sCriteria1.startsWith( GREATERTHAN ) )
+ {
+ if ( sCriteria1.startsWith( GREATERTHANEQUALS ) )
+ {
+ sCriteria1 = sCriteria1.copy( strlen(GREATERTHANEQUALS) );
+ rFilterField.Operator = sheet::FilterOperator2::GREATER_EQUAL;
+ }
+ else
+ {
+ sCriteria1 = sCriteria1.copy( strlen(GREATERTHAN) );
+ rFilterField.Operator = sheet::FilterOperator2::GREATER;
+ }
+
+ }
+ else if ( sCriteria1.startsWith( LESSTHAN ) )
+ {
+ if ( sCriteria1.startsWith( LESSTHANEQUALS ) )
+ {
+ sCriteria1 = sCriteria1.copy( strlen(LESSTHANEQUALS) );
+ rFilterField.Operator = sheet::FilterOperator2::LESS_EQUAL;
+ }
+ else
+ {
+ sCriteria1 = sCriteria1.copy( strlen(LESSTHAN) );
+ rFilterField.Operator = sheet::FilterOperator2::LESS;
+ }
+
+ }
+ else
+ rFilterField.Operator = sheet::FilterOperator2::EQUAL;
+
+ // tdf#107885 - check if criteria is numeric using locale dependent settings without group separator
+ // or, if the decimal separator is different from the English locale, without any locale.
+ sal_Int32 nParseEnd = 0;
+ rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
+ double fValue = ScGlobal::getLocaleData().stringToDouble( sCriteria1, false, &eStatus, &nParseEnd );
+ if ( nParseEnd == sCriteria1.getLength() && eStatus == rtl_math_ConversionStatus_Ok )
+ {
+ rFilterField.IsNumeric = true;
+ rFilterField.NumericValue = fValue;
+ }
+ else if ( ScGlobal::getLocaleData().getNumDecimalSep().toChar() != '.' )
+ {
+ eStatus = rtl_math_ConversionStatus_Ok;
+ fValue = ::rtl::math::stringToDouble( sCriteria1, '.', 0, &eStatus, &nParseEnd );
+ if ( nParseEnd == sCriteria1.getLength() && eStatus == rtl_math_ConversionStatus_Ok )
+ {
+ rFilterField.IsNumeric = true;
+ rFilterField.NumericValue = fValue;
+ }
+ }
+
+ rFilterField.StringValue = sCriteria1;
+}
+
+void SAL_CALL
+ScVbaRange::AutoFilter( const uno::Any& aField, const uno::Any& Criteria1, const uno::Any& Operator, const uno::Any& Criteria2, const uno::Any& /*VisibleDropDown*/ )
+{
+ // Is there an existing autofilter
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ sal_Int16 nSheet = thisAddress.Sheet;
+ ScDocShell* pShell = getScDocShell();
+ bool bHasAuto = false;
+ uno::Reference< sheet::XDatabaseRange > xDataBaseRange = excel::GetAutoFiltRange( pShell, nSheet );
+ if ( xDataBaseRange.is() )
+ bHasAuto = true;
+
+ if ( !bHasAuto )
+ {
+ if ( m_Areas->getCount() > 1 )
+ throw uno::RuntimeException( STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY );
+
+ table::CellRangeAddress autoFiltAddress;
+ //CurrentRegion()
+ if ( isSingleCellRange() )
+ {
+ uno::Reference< excel::XRange > xCurrent( CurrentRegion() );
+ if ( xCurrent.is() )
+ {
+ ScVbaRange* pRange = getImplementation( xCurrent );
+ if ( pRange )
+ {
+ if ( pRange->isSingleCellRange() )
+ throw uno::RuntimeException("Can't create AutoFilter" );
+ RangeHelper currentRegion( pRange->mxRange );
+ autoFiltAddress = currentRegion.getCellRangeAddressable()->getRangeAddress();
+ }
+ }
+ }
+ else // multi-cell range
+ {
+ RangeHelper multiCellRange( mxRange );
+ autoFiltAddress = multiCellRange.getCellRangeAddressable()->getRangeAddress();
+ // #163530# Filter box shows only entry of first row
+ ScDocument* pDocument = ( pShell ? &pShell->GetDocument() : nullptr );
+ if ( pDocument )
+ {
+ SCCOL nStartCol = autoFiltAddress.StartColumn;
+ SCROW nStartRow = autoFiltAddress.StartRow;
+ SCCOL nEndCol = autoFiltAddress.EndColumn;
+ SCROW nEndRow = autoFiltAddress.EndRow;
+ pDocument->GetDataArea( autoFiltAddress.Sheet, nStartCol, nStartRow, nEndCol, nEndRow, true, true );
+ autoFiltAddress.StartColumn = nStartCol;
+ autoFiltAddress.StartRow = nStartRow;
+ autoFiltAddress.EndColumn = nEndCol;
+ autoFiltAddress.EndRow = nEndRow;
+ }
+ }
+
+ uno::Reference< sheet::XUnnamedDatabaseRanges > xDBRanges = excel::GetUnnamedDataBaseRanges( pShell );
+ if ( xDBRanges.is() )
+ {
+ if ( !xDBRanges->hasByTable( nSheet ) )
+ xDBRanges->setByTable( autoFiltAddress );
+ xDataBaseRange.set( xDBRanges->getByTable(nSheet ), uno::UNO_QUERY_THROW );
+ }
+ if ( !xDataBaseRange.is() )
+ throw uno::RuntimeException("Failed to find the autofilter placeholder range" );
+
+ uno::Reference< beans::XPropertySet > xDBRangeProps( xDataBaseRange, uno::UNO_QUERY_THROW );
+ // set autofilter
+ xDBRangeProps->setPropertyValue( "AutoFilter", uno::Any(true) );
+ // set header (autofilter always need column headers)
+ uno::Reference< beans::XPropertySet > xFiltProps( xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY_THROW );
+ xFiltProps->setPropertyValue( "ContainsHeader", uno::Any( true ) );
+ }
+
+ sal_Int32 nField = 0; // *IS* 1 based
+ sal_Int32 nOperator = excel::XlAutoFilterOperator::xlAnd;
+
+ sheet::FilterConnection nConn = sheet::FilterConnection_AND;
+ double nCriteria1 = 0;
+
+ bool bHasCritValue = Criteria1.hasValue();
+ bool bCritHasNumericValue = false; // not sure if a numeric criteria is possible
+ if ( bHasCritValue )
+ bCritHasNumericValue = ( Criteria1 >>= nCriteria1 );
+
+ if ( !aField.hasValue() && ( Criteria1.hasValue() || Operator.hasValue() || Criteria2.hasValue() ) )
+ throw uno::RuntimeException();
+ uno::Any Field( aField );
+ if ( !( Field >>= nField ) )
+ {
+ const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter( mxContext );
+ try
+ {
+ Field = xConverter->convertTo( aField, cppu::UnoType<sal_Int32>::get() );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ // Use the normal uno api, sometimes e.g. when you want to use ALL as the filter
+ // we can't use refresh as the uno interface doesn't have a concept of ALL
+ // in this case we just call the core calc functionality -
+ if ( Field >>= nField )
+ {
+ uno::Reference< sheet::XSheetFilterDescriptor2 > xDesc(
+ xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY );
+ if ( xDesc.is() )
+ {
+ OUString sCriteria1;
+ bool bAcceptCriteria2 = true;
+ bool bAll = false;
+ uno::Sequence< sheet::TableFilterField2 > sTabFilts;
+ sheet::TableFilterField2* pTabFilts = nullptr;
+ uno::Reference< beans::XPropertySet > xDescProps( xDesc, uno::UNO_QUERY_THROW );
+ if ( Criteria1.hasValue() )
+ {
+ sTabFilts.realloc( 1 );
+ pTabFilts = sTabFilts.getArray();
+ pTabFilts[0].Operator = sheet::FilterOperator2::EQUAL;// sensible default
+ if ( !bCritHasNumericValue )
+ {
+ Criteria1 >>= sCriteria1;
+ if ( sCriteria1.isEmpty() )
+ {
+ uno::Sequence< OUString > aCriteria1;
+ Criteria1 >>= aCriteria1;
+ sal_uInt16 nLength = aCriteria1.getLength();
+ if ( nLength )
+ {
+ // When sequence is provided for Criteria1 don't care about Criteria2
+ bAcceptCriteria2 = false;
+
+ auto pCriteria1 = aCriteria1.getArray();
+ sTabFilts.realloc( nLength );
+ pTabFilts = sTabFilts.getArray();
+ for ( sal_uInt16 i = 0; i < nLength; ++i )
+ {
+ lcl_setTableFieldsFromCriteria( pCriteria1[i], xDescProps, pTabFilts[i] );
+ pTabFilts[i].Connection = sheet::FilterConnection_OR;
+ pTabFilts[i].Field = (nField - 1);
+ }
+ }
+ else
+ bAll = true;
+ }
+ else
+ {
+ pTabFilts[0].IsNumeric = bCritHasNumericValue;
+ if ( bHasCritValue && !sCriteria1.isEmpty() )
+ lcl_setTableFieldsFromCriteria( sCriteria1, xDescProps, pTabFilts[0] );
+ else
+ bAll = true;
+ }
+ }
+ else // numeric
+ {
+ pTabFilts[0].IsNumeric = true;
+ pTabFilts[0].NumericValue = nCriteria1;
+ }
+ }
+ else // no value specified
+ bAll = true;
+ // not sure what the relationship between Criteria1 and Operator is,
+ // e.g. can you have an Operator without a Criteria? In LibreOffice it
+ if ( Operator.hasValue() && ( Operator >>= nOperator ) )
+ {
+ // if it's a bottom/top Ten(Percent/Value) and there
+ // is no value specified for criteria1 set it to 10
+ if ( !bCritHasNumericValue && sCriteria1.isEmpty() && ( nOperator != excel::XlAutoFilterOperator::xlOr ) && ( nOperator != excel::XlAutoFilterOperator::xlAnd ) )
+ {
+ pTabFilts[0].IsNumeric = true;
+ pTabFilts[0].NumericValue = 10;
+ bAll = false;
+ }
+ switch ( nOperator )
+ {
+ case excel::XlAutoFilterOperator::xlBottom10Items:
+ pTabFilts[0].Operator = sheet::FilterOperator2::BOTTOM_VALUES;
+ break;
+ case excel::XlAutoFilterOperator::xlBottom10Percent:
+ pTabFilts[0].Operator = sheet::FilterOperator2::BOTTOM_PERCENT;
+ break;
+ case excel::XlAutoFilterOperator::xlTop10Items:
+ pTabFilts[0].Operator = sheet::FilterOperator2::TOP_VALUES;
+ break;
+ case excel::XlAutoFilterOperator::xlTop10Percent:
+ pTabFilts[0].Operator = sheet::FilterOperator2::TOP_PERCENT;
+ break;
+ case excel::XlAutoFilterOperator::xlOr:
+ nConn = sheet::FilterConnection_OR;
+ break;
+ case excel::XlAutoFilterOperator::xlAnd:
+ nConn = sheet::FilterConnection_AND;
+ break;
+ default:
+ throw uno::RuntimeException("UnknownOption" );
+
+ }
+
+ }
+ if ( !bAll && bAcceptCriteria2 )
+ {
+ pTabFilts[0].Connection = sheet::FilterConnection_AND;
+ pTabFilts[0].Field = (nField - 1);
+
+ uno::Sequence< OUString > aCriteria2;
+ if ( Criteria2.hasValue() ) // there is a Criteria2
+ {
+ sTabFilts.realloc(2);
+ pTabFilts = sTabFilts.getArray();
+ pTabFilts[1].Field = sTabFilts[0].Field;
+ pTabFilts[1].Connection = nConn;
+
+ OUString sCriteria2;
+ if ( Criteria2 >>= sCriteria2 )
+ {
+ if ( !sCriteria2.isEmpty() )
+ {
+ uno::Reference< beans::XPropertySet > xProps;
+ lcl_setTableFieldsFromCriteria( sCriteria2, xProps, pTabFilts[1] );
+ pTabFilts[1].IsNumeric = false;
+ }
+ }
+ else if ( Criteria2 >>= aCriteria2 )
+ {
+ sal_uInt16 nLength = aCriteria2.getLength();
+ if ( nLength )
+ {
+ // For compatibility use only the last value from the sequence
+ lcl_setTableFieldsFromCriteria( aCriteria2.getArray()[nLength - 1], xDescProps, pTabFilts[1] );
+ }
+ }
+ else // numeric
+ {
+ Criteria2 >>= pTabFilts[1].NumericValue;
+ pTabFilts[1].IsNumeric = true;
+ pTabFilts[1].Operator = sheet::FilterOperator2::EQUAL;
+ }
+ }
+ }
+
+ xDesc->setFilterFields2( sTabFilts );
+ if ( !bAll )
+ {
+ xDataBaseRange->refresh();
+ }
+ else
+ // was 0 based now seems to be 1
+ lcl_SetAllQueryForField( pShell, nField, nSheet );
+ }
+ }
+ else
+ {
+ // this is just to toggle autofilter on and off ( not to be confused with
+ // a VisibleDropDown option combined with a field, in that case just the
+ // button should be disabled ) - currently we don't support that
+ uno::Reference< beans::XPropertySet > xDBRangeProps( xDataBaseRange, uno::UNO_QUERY_THROW );
+ if ( bHasAuto )
+ {
+ // find the any field with the query and select all
+ ScQueryParam aParam = lcl_GetQueryParam( pShell, nSheet );
+ for (SCSIZE i = 0; i< aParam.GetEntryCount(); ++i)
+ {
+ ScQueryEntry& rEntry = aParam.GetEntry(i);
+ if ( rEntry.bDoQuery )
+ lcl_SetAllQueryForField( pShell, rEntry.nField, nSheet );
+ }
+ // remove existing filters
+ uno::Reference< sheet::XSheetFilterDescriptor2 > xSheetFilterDescriptor(
+ xDataBaseRange->getFilterDescriptor(), uno::UNO_QUERY );
+ if( xSheetFilterDescriptor.is() )
+ xSheetFilterDescriptor->setFilterFields2( uno::Sequence< sheet::TableFilterField2 >() );
+ }
+ xDBRangeProps->setPropertyValue( "AutoFilter", uno::Any(!bHasAuto) );
+
+ }
+}
+
+void SAL_CALL
+ScVbaRange::Insert( const uno::Any& Shift, const uno::Any& /*CopyOrigin*/ )
+{
+ // It appears (from the web) that the undocumented CopyOrigin
+ // param should contain member of enum XlInsertFormatOrigin
+ // which can have values xlFormatFromLeftOrAbove or xlFormatFromRightOrBelow
+ // #TODO investigate resultant behaviour using these constants
+ // currently just processing Shift
+
+ sheet::CellInsertMode mode = sheet::CellInsertMode_NONE;
+ if ( Shift.hasValue() )
+ {
+ sal_Int32 nShift = 0;
+ Shift >>= nShift;
+ switch ( nShift )
+ {
+ case excel::XlInsertShiftDirection::xlShiftToRight:
+ mode = sheet::CellInsertMode_RIGHT;
+ break;
+ case excel::XlInsertShiftDirection::xlShiftDown:
+ mode = sheet::CellInsertMode_DOWN;
+ break;
+ default:
+ throw uno::RuntimeException("Illegal parameter " );
+ }
+ }
+ else
+ {
+ if ( getRow() >= getColumn() )
+ mode = sheet::CellInsertMode_DOWN;
+ else
+ mode = sheet::CellInsertMode_RIGHT;
+ }
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ uno::Reference< sheet::XCellRangeMovement > xCellRangeMove( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
+ xCellRangeMove->insertCells( thisAddress, mode );
+
+ // Paste from clipboard only if the clipboard content was copied via VBA, and not already pasted via VBA again.
+ // "Insert" behavior should not depend on random clipboard content previously copied by the user.
+ ScDocShell* pDocShell = getDocShellFromRange( mxRange );
+ const ScTransferObj* pClipObj = pDocShell ? ScTransferObj::GetOwnClipboard(pDocShell->GetClipData()) : nullptr;
+ if ( pClipObj && pClipObj->GetUseInApi() )
+ {
+ // After the insert ( this range ) actually has moved
+ ScRange aRange( static_cast< SCCOL >( thisAddress.StartColumn ), static_cast< SCROW >( thisAddress.StartRow ), static_cast< SCTAB >( thisAddress.Sheet ), static_cast< SCCOL >( thisAddress.EndColumn ), static_cast< SCROW >( thisAddress.EndRow ), static_cast< SCTAB >( thisAddress.Sheet ) );
+ uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getDocShellFromRange( mxRange ) , aRange ) );
+ uno::Reference< excel::XRange > xVbaRange( new ScVbaRange( mxParent, mxContext, xRange, mbIsRows, mbIsColumns ) );
+ xVbaRange->PasteSpecial( uno::Any(), uno::Any(), uno::Any(), uno::Any() );
+ }
+}
+
+void SAL_CALL
+ScVbaRange::Autofit()
+{
+ sal_Int32 nLen = m_Areas->getCount();
+ if ( nLen > 1 )
+ {
+ for ( sal_Int32 index = 1; index != nLen; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( index ), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->Autofit();
+ }
+ return;
+ }
+
+ // if the range is a not a row or column range autofit will
+ // throw an error
+ if ( !( mbIsColumns || mbIsRows ) )
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ ScDocShell* pDocShell = getDocShellFromRange( mxRange );
+ if ( !pDocShell )
+ return;
+
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+
+ std::vector<sc::ColRowSpan> aColArr(1, sc::ColRowSpan(thisAddress.StartColumn,thisAddress.EndColumn));
+ bool bDirection = true;
+ if ( mbIsRows )
+ {
+ bDirection = false;
+ aColArr[0].mnStart = thisAddress.StartRow;
+ aColArr[0].mnEnd = thisAddress.EndRow;
+ }
+ pDocShell->GetDocFunc().SetWidthOrHeight(
+ bDirection, aColArr, thisAddress.Sheet, SC_SIZE_OPTIMAL, 0, true, true);
+}
+
+uno::Any SAL_CALL
+ScVbaRange::Hyperlinks( const uno::Any& aIndex )
+{
+ /* The range object always returns a new Hyperlinks object containing a
+ fixed list of existing hyperlinks in the range.
+ See vbahyperlinks.hxx for more details. */
+
+ // get the global hyperlink object of the sheet (sheet should always be the parent of a Range object)
+ uno::Reference< excel::XWorksheet > xWorksheet( getParent(), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XHyperlinks > xSheetHlinks( xWorksheet->Hyperlinks( uno::Any() ), uno::UNO_QUERY_THROW );
+ ScVbaHyperlinksRef xScSheetHlinks( dynamic_cast< ScVbaHyperlinks* >( xSheetHlinks.get() ) );
+ if( !xScSheetHlinks.is() )
+ throw uno::RuntimeException("Cannot obtain hyperlinks implementation object" );
+
+ // create a new local hyperlinks object based on the sheet hyperlinks
+ ScVbaHyperlinksRef xHlinks( new ScVbaHyperlinks( getParent(), mxContext, xScSheetHlinks, getScRangeList() ) );
+ if( aIndex.hasValue() )
+ return xHlinks->Item( aIndex, uno::Any() );
+ return uno::Any( uno::Reference< excel::XHyperlinks >( xHlinks ) );
+}
+
+css::uno::Reference< excel::XValidation > SAL_CALL
+ScVbaRange::getValidation()
+{
+ if ( !m_xValidation.is() )
+ m_xValidation = new ScVbaValidation( this, mxContext, mxRange );
+ return m_xValidation;
+}
+
+namespace {
+
+/// @throws uno::RuntimeException
+sal_Unicode lclGetPrefixChar( const uno::Reference< table::XCell >& rxCell )
+{
+ /* TODO/FIXME: We need an apostroph-prefix property at the cell to
+ implement this correctly. For now, return an apostroph for every text
+ cell.
+
+ TODO/FIXME: When Application.TransitionNavigKeys is supported and true,
+ this function needs to inspect the cell formatting and return different
+ prefixes according to the horizontal cell alignment.
+ */
+ return (rxCell->getType() == table::CellContentType_TEXT) ? '\'' : 0;
+}
+
+/// @throws uno::RuntimeException
+sal_Unicode lclGetPrefixChar( const uno::Reference< table::XCellRange >& rxRange )
+{
+ /* This implementation is able to handle different prefixes (needed if
+ Application.TransitionNavigKeys is true). The function lclGetPrefixChar
+ for single cells called from here may return any prefix. If that
+ function returns an empty prefix (NUL character) or different non-empty
+ prefixes for two cells, this function returns 0.
+ */
+ sal_Unicode cCurrPrefix = 0;
+ table::CellRangeAddress aRangeAddr = lclGetRangeAddress( rxRange );
+ sal_Int32 nEndCol = aRangeAddr.EndColumn - aRangeAddr.StartColumn;
+ sal_Int32 nEndRow = aRangeAddr.EndRow - aRangeAddr.StartRow;
+ for( sal_Int32 nRow = 0; nRow <= nEndRow; ++nRow )
+ {
+ for( sal_Int32 nCol = 0; nCol <= nEndCol; ++nCol )
+ {
+ uno::Reference< table::XCell > xCell( rxRange->getCellByPosition( nCol, nRow ), uno::UNO_SET_THROW );
+ sal_Unicode cNewPrefix = lclGetPrefixChar( xCell );
+ if( (cNewPrefix == 0) || ((cCurrPrefix != 0) && (cNewPrefix != cCurrPrefix)) )
+ return 0;
+ cCurrPrefix = cNewPrefix;
+ }
+ }
+ // all cells contain the same prefix - return it
+ return cCurrPrefix;
+}
+
+/// @throws uno::RuntimeException
+sal_Unicode lclGetPrefixChar( const uno::Reference< sheet::XSheetCellRangeContainer >& rxRanges )
+{
+ sal_Unicode cCurrPrefix = 0;
+ uno::Reference< container::XEnumerationAccess > xRangesEA( rxRanges, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XEnumeration > xRangesEnum( xRangesEA->createEnumeration(), uno::UNO_SET_THROW );
+ while( xRangesEnum->hasMoreElements() )
+ {
+ uno::Reference< table::XCellRange > xRange( xRangesEnum->nextElement(), uno::UNO_QUERY_THROW );
+ sal_Unicode cNewPrefix = lclGetPrefixChar( xRange );
+ if( (cNewPrefix == 0) || ((cCurrPrefix != 0) && (cNewPrefix != cCurrPrefix)) )
+ return 0;
+ cCurrPrefix = cNewPrefix;
+ }
+ // all ranges contain the same prefix - return it
+ return cCurrPrefix;
+}
+
+uno::Any lclGetPrefixVariant( sal_Unicode cPrefixChar )
+{
+ return uno::Any( (cPrefixChar == 0) ? OUString() : OUString( cPrefixChar ) );
+}
+
+} // namespace
+
+uno::Any SAL_CALL ScVbaRange::getPrefixCharacter()
+{
+ /* (1) If Application.TransitionNavigKeys is false, this function returns
+ an apostroph character if the text cell begins with an apostroph
+ character (formula return values are not taken into account); otherwise
+ an empty string.
+
+ (2) If Application.TransitionNavigKeys is true, this function returns
+ an apostroph character, if the cell is left-aligned; a double-quote
+ character, if the cell is right-aligned; a circumflex character, if the
+ cell is centered; a backslash character, if the cell is set to filled;
+ or an empty string, if nothing of the above.
+
+ If a range or a list of ranges contains texts with leading apostroph
+ character as well as other cells, this function returns an empty
+ string.
+ */
+
+ if( mxRange.is() )
+ return lclGetPrefixVariant( lclGetPrefixChar( mxRange ) );
+ if( mxRanges.is() )
+ return lclGetPrefixVariant( lclGetPrefixChar( mxRanges ) );
+ throw uno::RuntimeException("Unexpected empty Range object" );
+}
+
+uno::Any ScVbaRange::getShowDetail()
+{
+ // #FIXME, If the specified range is in a PivotTable report
+
+ // In MSO VBA, the specified range must be a single summary column or row in an outline. otherwise throw exception
+ if( m_Areas->getCount() > 1 )
+ throw uno::RuntimeException("Can not get Range.ShowDetail attribute " );
+
+ RangeHelper helper( mxRange );
+ uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = helper.getSheetCellCursor();
+ xSheetCellCursor->collapseToCurrentRegion();
+ uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW);
+ table::CellRangeAddress aOutlineAddress = xCellRangeAddressable->getRangeAddress();
+
+ // check if the specified range is a single summary column or row.
+ table::CellRangeAddress thisAddress = helper.getCellRangeAddressable()->getRangeAddress();
+ if( (thisAddress.StartRow != thisAddress.EndRow || thisAddress.EndRow != aOutlineAddress.EndRow ) &&
+ (thisAddress.StartColumn != thisAddress.EndColumn || thisAddress.EndColumn != aOutlineAddress.EndColumn ))
+ {
+ throw uno::RuntimeException("Can not set Range.ShowDetail attribute" );
+ }
+
+ bool bColumn = thisAddress.StartRow != thisAddress.EndRow;
+ ScDocument& rDoc = getDocumentFromRange( mxRange );
+ ScOutlineTable* pOutlineTable = rDoc.GetOutlineTable(static_cast<SCTAB>(thisAddress.Sheet), true);
+ const ScOutlineArray& rOutlineArray = bColumn ? pOutlineTable->GetColArray(): pOutlineTable->GetRowArray();
+ SCCOLROW nPos = bColumn ? static_cast<SCCOLROW>(thisAddress.EndColumn-1):static_cast<SCCOLROW>(thisAddress.EndRow-1);
+ const ScOutlineEntry* pEntry = rOutlineArray.GetEntryByPos( 0, nPos );
+ if( pEntry )
+ {
+ const bool bShowDetail = !pEntry->IsHidden();
+ return uno::Any( bShowDetail );
+ }
+
+ return aNULL();
+}
+
+void ScVbaRange::setShowDetail(const uno::Any& aShowDetail)
+{
+ // #FIXME, If the specified range is in a PivotTable report
+
+ // In MSO VBA, the specified range must be a single summary column or row in an outline. otherwise throw exception
+ if( m_Areas->getCount() > 1 )
+ throw uno::RuntimeException("Can not set Range.ShowDetail attribute" );
+
+ bool bShowDetail = extractBoolFromAny( aShowDetail );
+
+ RangeHelper helper( mxRange );
+ uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = helper.getSheetCellCursor();
+ xSheetCellCursor->collapseToCurrentRegion();
+ uno::Reference< sheet::XCellRangeAddressable > xCellRangeAddressable(xSheetCellCursor, uno::UNO_QUERY_THROW);
+ table::CellRangeAddress aOutlineAddress = xCellRangeAddressable->getRangeAddress();
+
+ // check if the specified range is a single summary column or row.
+ table::CellRangeAddress thisAddress = helper.getCellRangeAddressable()->getRangeAddress();
+ if( (thisAddress.StartRow != thisAddress.EndRow || thisAddress.EndRow != aOutlineAddress.EndRow ) &&
+ (thisAddress.StartColumn != thisAddress.EndColumn || thisAddress.EndColumn != aOutlineAddress.EndColumn ))
+ {
+ throw uno::RuntimeException("Can not set Range.ShowDetail attribute" );
+ }
+
+ // #FIXME, seems there is a different behavior between MSO and OOo.
+ // In OOo, the showDetail will show all the level entries, while only show the first level entry in MSO
+ uno::Reference< sheet::XSheetOutline > xSheetOutline( helper.getSpreadSheet(), uno::UNO_QUERY_THROW );
+ if( bShowDetail )
+ xSheetOutline->showDetail( aOutlineAddress );
+ else
+ xSheetOutline->hideDetail( aOutlineAddress );
+
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaRange::MergeArea()
+{
+ uno::Reference< sheet::XSheetCellRange > xMergeShellCellRange(mxRange->getCellRangeByPosition(0,0,0,0), uno::UNO_QUERY_THROW);
+ uno::Reference< sheet::XSheetCellCursor > xMergeSheetCursor(xMergeShellCellRange->getSpreadsheet()->createCursorByRange( xMergeShellCellRange ), uno::UNO_SET_THROW);
+ if( xMergeSheetCursor.is() )
+ {
+ xMergeSheetCursor->collapseToMergedArea();
+ uno::Reference<sheet::XCellRangeAddressable> xMergeCellAddress(xMergeSheetCursor, uno::UNO_QUERY_THROW);
+ table::CellRangeAddress aCellAddress = xMergeCellAddress->getRangeAddress();
+ if( aCellAddress.StartColumn ==0 && aCellAddress.EndColumn==0 &&
+ aCellAddress.StartRow==0 && aCellAddress.EndRow==0)
+ {
+ return new ScVbaRange( mxParent,mxContext,mxRange );
+ }
+ else
+ {
+ ScRange refRange( static_cast< SCCOL >( aCellAddress.StartColumn ), static_cast< SCROW >( aCellAddress.StartRow ), static_cast< SCTAB >( aCellAddress.Sheet ),
+ static_cast< SCCOL >( aCellAddress.EndColumn ), static_cast< SCROW >( aCellAddress.EndRow ), static_cast< SCTAB >( aCellAddress.Sheet ) );
+ uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getScDocShell() , refRange ) );
+ return new ScVbaRange( mxParent, mxContext,xRange );
+ }
+ }
+ return new ScVbaRange( mxParent, mxContext, mxRange );
+}
+
+void SAL_CALL
+ScVbaRange::PrintOut( const uno::Any& From, const uno::Any& To, const uno::Any& Copies, const uno::Any& Preview, const uno::Any& ActivePrinter, const uno::Any& PrintToFile, const uno::Any& Collate, const uno::Any& PrToFileName )
+{
+ ScDocShell* pShell = nullptr;
+
+ sal_Int32 nItems = m_Areas->getCount();
+ uno::Sequence< table::CellRangeAddress > printAreas( nItems );
+ auto printAreasRange = asNonConstRange(printAreas);
+ uno::Reference< sheet::XPrintAreas > xPrintAreas;
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+
+ RangeHelper thisRange( xRange->getCellRange() );
+ table::CellRangeAddress rangeAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ if ( index == 1 )
+ {
+ ScVbaRange* pRange = getImplementation( xRange );
+ // initialise the doc shell and the printareas
+ pShell = getDocShellFromRange( pRange->mxRange );
+ xPrintAreas.set( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
+ }
+ printAreasRange[ index - 1 ] = rangeAddress;
+ }
+ if ( pShell && xPrintAreas.is() )
+ {
+ xPrintAreas->setPrintAreas( printAreas );
+ uno::Reference< frame::XModel > xModel = pShell->GetModel();
+ PrintOutHelper( excel::getBestViewShell( xModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, true );
+ }
+}
+
+void SAL_CALL
+ScVbaRange::AutoFill( const uno::Reference< excel::XRange >& Destination, const uno::Any& Type )
+{
+ uno::Reference< excel::XRange > xDest( Destination, uno::UNO_SET_THROW );
+ ScVbaRange* pRange = getImplementation( xDest );
+ RangeHelper destRangeHelper( pRange->mxRange );
+ table::CellRangeAddress destAddress = destRangeHelper.getCellRangeAddressable()->getRangeAddress();
+
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ ScRange sourceRange;
+ ScRange destRange;
+
+ ScUnoConversion::FillScRange( destRange, destAddress );
+ ScUnoConversion::FillScRange( sourceRange, thisAddress );
+
+ FillDir eDir = FILL_TO_BOTTOM;
+ double fStep = 1.0;
+
+ ScRange aRange( destRange );
+ ScRange aSourceRange( destRange );
+
+ // default to include the number of Rows in the source range;
+ SCCOLROW nSourceCount = ( sourceRange.aEnd.Row() - sourceRange.aStart.Row() ) + 1;
+ SCCOLROW nCount = 0;
+
+ if ( sourceRange != destRange )
+ {
+ // Find direction of fill, vertical or horizontal
+ if ( sourceRange.aStart == destRange.aStart )
+ {
+ if ( sourceRange.aEnd.Row() == destRange.aEnd.Row() )
+ {
+ nSourceCount = ( sourceRange.aEnd.Col() - sourceRange.aStart.Col() + 1 );
+ aSourceRange.aEnd.SetCol( static_cast<SCCOL>( aSourceRange.aStart.Col() + nSourceCount - 1 ) );
+ eDir = FILL_TO_RIGHT;
+ nCount = aRange.aEnd.Col() - aSourceRange.aEnd.Col();
+ }
+ else if ( sourceRange.aEnd.Col() == destRange.aEnd.Col() )
+ {
+ aSourceRange.aEnd.SetRow( static_cast<SCROW>( aSourceRange.aStart.Row() + nSourceCount ) - 1 );
+ nCount = aRange.aEnd.Row() - aSourceRange.aEnd.Row();
+ eDir = FILL_TO_BOTTOM;
+ }
+ }
+
+ else if ( aSourceRange.aEnd == destRange.aEnd )
+ {
+ if ( sourceRange.aStart.Col() == destRange.aStart.Col() )
+ {
+ aSourceRange.aStart.SetRow( static_cast<SCROW>( aSourceRange.aEnd.Row() - nSourceCount + 1 ) );
+ nCount = aSourceRange.aStart.Row() - aRange.aStart.Row();
+ eDir = FILL_TO_TOP;
+ fStep = -fStep;
+ }
+ else if ( sourceRange.aStart.Row() == destRange.aStart.Row() )
+ {
+ nSourceCount = ( sourceRange.aEnd.Col() - sourceRange.aStart.Col() ) + 1;
+ aSourceRange.aStart.SetCol( static_cast<SCCOL>( aSourceRange.aEnd.Col() - nSourceCount + 1 ) );
+ nCount = aSourceRange.aStart.Col() - aRange.aStart.Col();
+ eDir = FILL_TO_LEFT;
+ fStep = -fStep;
+ }
+ }
+ }
+
+ FillCmd eCmd = FILL_AUTO;
+ FillDateCmd eDateCmd = FILL_DAY;
+
+ if ( Type.hasValue() )
+ {
+ sal_Int16 nFillType = excel::XlAutoFillType::xlFillDefault;
+ Type >>= nFillType;
+ switch ( nFillType )
+ {
+ case excel::XlAutoFillType::xlFillCopy:
+ eCmd = FILL_SIMPLE;
+ fStep = 0.0;
+ break;
+ case excel::XlAutoFillType::xlFillDays:
+ eCmd = FILL_DATE;
+ break;
+ case excel::XlAutoFillType::xlFillMonths:
+ eCmd = FILL_DATE;
+ eDateCmd = FILL_MONTH;
+ break;
+ case excel::XlAutoFillType::xlFillWeekdays:
+ eCmd = FILL_DATE;
+ eDateCmd = FILL_WEEKDAY;
+ break;
+ case excel::XlAutoFillType::xlFillYears:
+ eCmd = FILL_DATE;
+ eDateCmd = FILL_YEAR;
+ break;
+ case excel::XlAutoFillType::xlGrowthTrend:
+ eCmd = FILL_GROWTH;
+ break;
+ case excel::XlAutoFillType::xlFillFormats:
+ throw uno::RuntimeException("xlFillFormat not supported for AutoFill" );
+ case excel::XlAutoFillType::xlFillValues:
+ case excel::XlAutoFillType::xlFillSeries:
+ case excel::XlAutoFillType::xlLinearTrend:
+ eCmd = FILL_LINEAR;
+ break;
+ case excel::XlAutoFillType::xlFillDefault:
+ default:
+ eCmd = FILL_AUTO;
+ break;
+ }
+ }
+ ScDocShell* pDocSh = getDocShellFromRange( mxRange );
+ pDocSh->GetDocFunc().FillAuto( aSourceRange, nullptr, eDir, eCmd, eDateCmd,
+ nCount, fStep, MAXDOUBLE/*fEndValue*/, true, true );
+}
+sal_Bool SAL_CALL
+ScVbaRange::GoalSeek( const uno::Any& Goal, const uno::Reference< excel::XRange >& ChangingCell )
+{
+ ScDocShell* pDocShell = getScDocShell();
+ bool bRes = true;
+ ScVbaRange* pRange = static_cast< ScVbaRange* >( ChangingCell.get() );
+ if ( pDocShell && pRange )
+ {
+ uno::Reference< sheet::XGoalSeek > xGoalSeek( pDocShell->GetModel(), uno::UNO_QUERY_THROW );
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ RangeHelper changingCellRange( pRange->mxRange );
+ table::CellRangeAddress changingCellAddr = changingCellRange.getCellRangeAddressable()->getRangeAddress();
+ OUString sGoal = getAnyAsString( Goal );
+ table::CellAddress thisCell( thisAddress.Sheet, thisAddress.StartColumn, thisAddress.StartRow );
+ table::CellAddress changingCell( changingCellAddr.Sheet, changingCellAddr.StartColumn, changingCellAddr.StartRow );
+ sheet::GoalResult res = xGoalSeek->seekGoal( thisCell, changingCell, sGoal );
+ ChangingCell->setValue( uno::Any( res.Result ) );
+
+ // openoffice behaves differently, result is 0 if the divergence is too great
+ // but... if it detects 0 is the value it requires then it will use that
+ // e.g. divergence & result both = 0.0 does NOT mean there is an error
+ if ( ( res.Divergence != 0.0 ) && ( res.Result == 0.0 ) )
+ bRes = false;
+ }
+ else
+ bRes = false;
+ return bRes;
+}
+
+void
+ScVbaRange::Calculate( )
+{
+ getWorksheet()->Calculate();
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaRange::Item( const uno::Any& row, const uno::Any& column )
+{
+ if ( mbIsRows || mbIsColumns )
+ {
+ if ( column.hasValue() )
+ DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} );
+ uno::Reference< excel::XRange > xRange;
+ if ( mbIsColumns )
+ xRange = Columns( row );
+ else
+ xRange = Rows( row );
+ return xRange;
+ }
+ return Cells( row, column );
+}
+
+void
+ScVbaRange::AutoOutline( )
+{
+ // #TODO #FIXME needs to check for summary row/col ( whatever they are )
+ // not valid for multi Area Addresses
+ if ( m_Areas->getCount() > 1 )
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY);
+ // So needs to either span an entire Row or a just be a single cell
+ // ( that contains a summary RowColumn )
+ // also the Single cell cause doesn't seem to be handled specially in
+ // this code ( ported from the helperapi RangeImpl.java,
+ // RangeRowsImpl.java, RangesImpl.java, RangeSingleCellImpl.java
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+
+ if ( isSingleCellRange() || mbIsRows )
+ {
+ uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
+ xSheetOutline->autoOutline( thisAddress );
+ }
+ else
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+}
+
+void SAL_CALL
+ScVbaRange:: ClearOutline( )
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->ClearOutline();
+ }
+ return;
+ }
+ RangeHelper thisRange( mxRange );
+ uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
+ xSheetOutline->clearOutline();
+}
+
+void
+ScVbaRange::groupUnGroup( bool bUnGroup )
+{
+ if ( m_Areas->getCount() > 1 )
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, STR_ERRORMESSAGE_APPLIESTOSINGLERANGEONLY);
+ table::TableOrientation nOrient = table::TableOrientation_ROWS;
+ if ( mbIsColumns )
+ nOrient = table::TableOrientation_COLUMNS;
+ RangeHelper thisRange( mxRange );
+ table::CellRangeAddress thisAddress = thisRange.getCellRangeAddressable()->getRangeAddress();
+ uno::Reference< sheet::XSheetOutline > xSheetOutline( thisRange.getSpreadSheet(), uno::UNO_QUERY_THROW );
+ if ( bUnGroup )
+ xSheetOutline->ungroup( thisAddress, nOrient );
+ else
+ xSheetOutline->group( thisAddress, nOrient );
+}
+
+void SAL_CALL
+ScVbaRange::Group( )
+{
+ groupUnGroup(false);
+}
+void SAL_CALL
+ScVbaRange::Ungroup( )
+{
+ groupUnGroup(true);
+}
+
+/// @throws uno::RuntimeException
+static void lcl_mergeCellsOfRange( const uno::Reference< table::XCellRange >& xCellRange, bool _bMerge )
+{
+ uno::Reference< util::XMergeable > xMergeable( xCellRange, uno::UNO_QUERY_THROW );
+ xMergeable->merge(_bMerge);
+}
+void SAL_CALL
+ScVbaRange::Merge( const uno::Any& Across )
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->Merge(Across);
+ }
+ return;
+ }
+ bool bAcross = false;
+ Across >>= bAcross;
+ if ( !bAcross )
+ lcl_mergeCellsOfRange( mxRange, true );
+ else
+ {
+ uno::Reference< excel::XRange > oRangeRowsImpl = Rows( uno::Any() );
+ // #TODO #FIXME this seems incredibly lame, this can't be right
+ for (sal_Int32 i=1; i <= oRangeRowsImpl->getCount();i++)
+ {
+ oRangeRowsImpl->Cells( uno::Any( i ), uno::Any() )->Merge( uno::Any( false ) );
+ }
+ }
+}
+
+void SAL_CALL
+ScVbaRange::UnMerge( )
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ sal_Int32 nItems = m_Areas->getCount();
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->UnMerge();
+ }
+ return;
+ }
+ lcl_mergeCellsOfRange( mxRange, false);
+}
+
+uno::Any SAL_CALL
+ScVbaRange::getStyle()
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW );
+ return xRange->getStyle();
+ }
+ uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW );
+ OUString sStyleName;
+ xProps->getPropertyValue( CELLSTYLE ) >>= sStyleName;
+ ScDocShell* pShell = getScDocShell();
+ uno::Reference< frame::XModel > xModel( pShell->GetModel() );
+ uno::Reference< excel::XStyle > xStyle = new ScVbaStyle( this, mxContext, sStyleName, xModel );
+ return uno::Any( xStyle );
+}
+void SAL_CALL
+ScVbaRange::setStyle( const uno::Any& _style )
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange->setStyle( _style );
+ return;
+ }
+ uno::Reference< beans::XPropertySet > xProps( mxRange, uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XStyle > xStyle;
+ _style >>= xStyle;
+ if ( xStyle.is() )
+ xProps->setPropertyValue( CELLSTYLE, uno::Any( xStyle->getName() ) );
+}
+
+uno::Reference< excel::XRange >
+ScVbaRange::PreviousNext( bool bIsPrevious )
+{
+ ScMarkData markedRange(getScDocument().GetSheetLimits());
+ ScRange refRange;
+ RangeHelper thisRange( mxRange );
+
+ ScUnoConversion::FillScRange( refRange, thisRange.getCellRangeAddressable()->getRangeAddress());
+ markedRange. SetMarkArea( refRange );
+ short nMove = bIsPrevious ? -1 : 1;
+
+ SCCOL nNewX = refRange.aStart.Col();
+ SCROW nNewY = refRange.aStart.Row();
+ SCTAB nTab = refRange.aStart.Tab();
+
+ ScDocument& rDoc = getScDocument();
+ rDoc.GetNextPos( nNewX,nNewY, nTab, nMove,0, true,true, markedRange );
+ refRange.aStart.SetCol( nNewX );
+ refRange.aStart.SetRow( nNewY );
+ refRange.aStart.SetTab( nTab );
+ refRange.aEnd.SetCol( nNewX );
+ refRange.aEnd.SetRow( nNewY );
+ refRange.aEnd.SetTab( nTab );
+
+ uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getScDocShell() , refRange ) );
+
+ return new ScVbaRange( mxParent, mxContext, xRange );
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaRange::Next()
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ) , uno::UNO_QUERY_THROW );
+ return xRange->Next();
+ }
+ return PreviousNext( false );
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaRange::Previous()
+{
+ if ( m_Areas->getCount() > 1 )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any( sal_Int32( 1 ) ), uno::Any() ), uno::UNO_QUERY_THROW );
+ return xRange->Previous();
+ }
+ return PreviousNext( true );
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaRange::SpecialCells( const uno::Any& _oType, const uno::Any& _oValue)
+{
+ bool bIsSingleCell = isSingleCellRange();
+ bool bIsMultiArea = ( m_Areas->getCount() > 1 );
+ ScVbaRange* pRangeToUse = this;
+ uno::Reference< excel::XRange > xUsedRange( getWorksheet()->getUsedRange() );
+ sal_Int32 nType = 0;
+ if ( !( _oType >>= nType ) )
+ DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} );
+ switch(nType)
+ {
+ case excel::XlCellType::xlCellTypeSameFormatConditions:
+ case excel::XlCellType::xlCellTypeAllValidation:
+ case excel::XlCellType::xlCellTypeSameValidation:
+ DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {});
+ break;
+ case excel::XlCellType::xlCellTypeBlanks:
+ case excel::XlCellType::xlCellTypeComments:
+ case excel::XlCellType::xlCellTypeConstants:
+ case excel::XlCellType::xlCellTypeFormulas:
+ case excel::XlCellType::xlCellTypeVisible:
+ case excel::XlCellType::xlCellTypeLastCell:
+ {
+ if ( bIsMultiArea )
+ {
+ // need to process each area, gather the results and
+ // create a new range from those
+ std::vector< table::CellRangeAddress > rangeResults;
+ sal_Int32 nItems = m_Areas->getCount() + 1;
+ for ( sal_Int32 index=1; index <= nItems; ++index )
+ {
+ uno::Reference< excel::XRange > xRange( m_Areas->Item( uno::Any(index), uno::Any() ), uno::UNO_QUERY_THROW );
+ xRange = xRange->SpecialCells( _oType, _oValue);
+ ScVbaRange* pRange = getImplementation( xRange );
+ if ( xRange.is() && pRange )
+ {
+ sal_Int32 nElems = pRange->m_Areas->getCount() + 1;
+ for ( sal_Int32 nArea = 1; nArea < nElems; ++nArea )
+ {
+ uno::Reference< excel::XRange > xTmpRange( m_Areas->Item( uno::Any( nArea ), uno::Any() ), uno::UNO_QUERY_THROW );
+ RangeHelper rHelper( xTmpRange->getCellRange() );
+ rangeResults.push_back( rHelper.getCellRangeAddressable()->getRangeAddress() );
+ }
+ }
+ }
+ ScRangeList aCellRanges;
+ for ( const auto& rRangeResult : rangeResults )
+ {
+ ScRange refRange;
+ ScUnoConversion::FillScRange( refRange, rRangeResult );
+ aCellRanges.push_back( refRange );
+ }
+ // Single range
+ if ( aCellRanges.size() == 1 )
+ {
+ uno::Reference< table::XCellRange > xRange( new ScCellRangeObj( getScDocShell(), aCellRanges.front() ) );
+ return new ScVbaRange( mxParent, mxContext, xRange );
+ }
+ uno::Reference< sheet::XSheetCellRangeContainer > xRanges( new ScCellRangesObj( getScDocShell(), aCellRanges ) );
+
+ return new ScVbaRange( mxParent, mxContext, xRanges );
+ }
+ else if ( bIsSingleCell )
+ {
+ pRangeToUse = static_cast< ScVbaRange* >( xUsedRange.get() );
+ }
+
+ break;
+ }
+ default:
+ DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} );
+ break;
+ }
+ if ( !pRangeToUse )
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ return pRangeToUse->SpecialCellsImpl( nType, _oValue );
+}
+
+/// @throws script::BasicErrorException
+static sal_Int32 lcl_getFormulaResultFlags(const uno::Any& aType)
+{
+ sal_Int32 nType = excel::XlSpecialCellsValue::xlNumbers;
+ aType >>= nType;
+ sal_Int32 nRes = sheet::FormulaResult::VALUE;
+
+ switch(nType)
+ {
+ case excel::XlSpecialCellsValue::xlErrors:
+ nRes= sheet::FormulaResult::ERROR;
+ break;
+ case excel::XlSpecialCellsValue::xlLogical:
+ //TODO bc93774: ask NN if this is really an appropriate substitute
+ nRes = sheet::FormulaResult::VALUE;
+ break;
+ case excel::XlSpecialCellsValue::xlNumbers:
+ nRes = sheet::FormulaResult::VALUE;
+ break;
+ case excel::XlSpecialCellsValue::xlTextValues:
+ nRes = sheet::FormulaResult::STRING;
+ break;
+ default:
+ DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} );
+ }
+ return nRes;
+}
+
+uno::Reference< excel::XRange >
+ScVbaRange::SpecialCellsImpl( sal_Int32 nType, const uno::Any& _oValue)
+{
+ uno::Reference< excel::XRange > xRange;
+ try
+ {
+ uno::Reference< sheet::XCellRangesQuery > xQuery( mxRange, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSheetCellRanges > xLocSheetCellRanges;
+ switch(nType)
+ {
+ case excel::XlCellType::xlCellTypeAllFormatConditions:
+ case excel::XlCellType::xlCellTypeSameFormatConditions:
+ case excel::XlCellType::xlCellTypeAllValidation:
+ case excel::XlCellType::xlCellTypeSameValidation:
+ // Shouldn't get here ( should be filtered out by
+ // ScVbaRange::SpecialCells()
+ DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {});
+ break;
+ case excel::XlCellType::xlCellTypeBlanks:
+ xLocSheetCellRanges = xQuery->queryEmptyCells();
+ break;
+ case excel::XlCellType::xlCellTypeComments:
+ xLocSheetCellRanges = xQuery->queryContentCells(sheet::CellFlags::ANNOTATION);
+ break;
+ case excel::XlCellType::xlCellTypeConstants:
+ xLocSheetCellRanges = xQuery->queryContentCells(23);
+ break;
+ case excel::XlCellType::xlCellTypeFormulas:
+ {
+ sal_Int32 nFormulaResult = lcl_getFormulaResultFlags(_oValue);
+ xLocSheetCellRanges = xQuery->queryFormulaCells(nFormulaResult);
+ break;
+ }
+ case excel::XlCellType::xlCellTypeLastCell:
+ xRange = Cells( uno::Any( getCount() ), uno::Any() );
+ [[fallthrough]]; //TODO ???
+ case excel::XlCellType::xlCellTypeVisible:
+ xLocSheetCellRanges = xQuery->queryVisibleCells();
+ break;
+ default:
+ DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {} );
+ break;
+ }
+ if (xLocSheetCellRanges.is())
+ {
+ xRange = lcl_makeXRangeFromSheetCellRanges( getParent(), mxContext, xLocSheetCellRanges, getScDocShell() );
+ }
+ }
+ catch (uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, u"No cells were found");
+ }
+ return xRange;
+}
+
+void SAL_CALL
+ScVbaRange::RemoveSubtotal( )
+{
+ uno::Reference< sheet::XSubTotalCalculatable > xSub( mxRange, uno::UNO_QUERY_THROW );
+ xSub->removeSubTotals();
+}
+
+void SAL_CALL
+ScVbaRange::Subtotal( ::sal_Int32 _nGroupBy, ::sal_Int32 _nFunction, const uno::Sequence< ::sal_Int32 >& _nTotalList, const uno::Any& aReplace, const uno::Any& PageBreaks, const uno::Any& /*SummaryBelowData*/ )
+{
+ try
+ {
+ bool bDoReplace = false;
+ aReplace >>= bDoReplace;
+ bool bAddPageBreaks = false;
+ PageBreaks >>= bAddPageBreaks;
+
+ uno::Reference< sheet::XSubTotalCalculatable> xSub(mxRange, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSubTotalDescriptor > xSubDesc = xSub->createSubTotalDescriptor(true);
+ uno::Reference< beans::XPropertySet > xSubDescPropertySet( xSubDesc, uno::UNO_QUERY_THROW );
+ xSubDescPropertySet->setPropertyValue("InsertPageBreaks", uno::Any( bAddPageBreaks));
+ sal_Int32 nLen = _nTotalList.getLength();
+ uno::Sequence< sheet::SubTotalColumn > aColumns( nLen );
+ auto aColumnsRange = asNonConstRange(aColumns);
+ for (int i = 0; i < nLen; i++)
+ {
+ aColumnsRange[i].Column = _nTotalList[i] - 1;
+ switch (_nFunction)
+ {
+ case excel::XlConsolidationFunction::xlAverage:
+ aColumnsRange[i].Function = sheet::GeneralFunction_AVERAGE;
+ break;
+ case excel::XlConsolidationFunction::xlCount:
+ aColumnsRange[i].Function = sheet::GeneralFunction_COUNT;
+ break;
+ case excel::XlConsolidationFunction::xlCountNums:
+ aColumnsRange[i].Function = sheet::GeneralFunction_COUNTNUMS;
+ break;
+ case excel::XlConsolidationFunction::xlMax:
+ aColumnsRange[i].Function = sheet::GeneralFunction_MAX;
+ break;
+ case excel::XlConsolidationFunction::xlMin:
+ aColumnsRange[i].Function = sheet::GeneralFunction_MIN;
+ break;
+ case excel::XlConsolidationFunction::xlProduct:
+ aColumnsRange[i].Function = sheet::GeneralFunction_PRODUCT;
+ break;
+ case excel::XlConsolidationFunction::xlStDev:
+ aColumnsRange[i].Function = sheet::GeneralFunction_STDEV;
+ break;
+ case excel::XlConsolidationFunction::xlStDevP:
+ aColumnsRange[i].Function = sheet::GeneralFunction_STDEVP;
+ break;
+ case excel::XlConsolidationFunction::xlSum:
+ aColumnsRange[i].Function = sheet::GeneralFunction_SUM;
+ break;
+ case excel::XlConsolidationFunction::xlUnknown:
+ aColumnsRange[i].Function = sheet::GeneralFunction_NONE;
+ break;
+ case excel::XlConsolidationFunction::xlVar:
+ aColumnsRange[i].Function = sheet::GeneralFunction_VAR;
+ break;
+ case excel::XlConsolidationFunction::xlVarP:
+ aColumnsRange[i].Function = sheet::GeneralFunction_VARP;
+ break;
+ default:
+ DebugHelper::basicexception(ERRCODE_BASIC_BAD_PARAMETER, {}) ;
+ return;
+ }
+ }
+ xSubDesc->addNew(aColumns, _nGroupBy - 1);
+ xSub->applySubTotals(xSubDesc, bDoReplace);
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+OUString
+ScVbaRange::getServiceImplName()
+{
+ return "ScVbaRange";
+}
+
+uno::Sequence< OUString >
+ScVbaRange::getServiceNames()
+{
+ return { "ooo.vba.excel.Range" };
+}
+
+sal_Bool SAL_CALL
+ScVbaRange::hasError()
+{
+ double dResult = 0.0;
+ uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW );
+ uno::Reference< script::XInvocation > xInvoc( xApplication->WorksheetFunction(), uno::UNO_QUERY_THROW );
+
+ uno::Reference< excel::XRange > aRange( this );
+ uno::Sequence< uno::Any > Params{ uno::Any(aRange) };
+ uno::Sequence< sal_Int16 > OutParamIndex;
+ uno::Sequence< uno::Any > OutParam;
+ xInvoc->invoke( "IsError", Params, OutParamIndex, OutParam ) >>= dResult;
+ return dResult > 0.0;
+}
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_ScVbaRange_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args)
+{
+ return cppu::acquire(new ScVbaRange(args, context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbarange.hxx b/sc/source/ui/vba/vbarange.hxx
new file mode 100644
index 000000000..118ad044c
--- /dev/null
+++ b/sc/source/ui/vba/vbarange.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 <ooo/vba/excel/XRange.hpp>
+
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/sheet/FillDateMode.hpp>
+#include <com/sun/star/sheet/FillMode.hpp>
+#include <com/sun/star/sheet/FillDirection.hpp>
+
+#include "vbaformat.hxx"
+#include <address.hxx>
+#include <formula/grammar.hxx>
+
+namespace com::sun::star::sheet { class XSheetCellRangeContainer; }
+namespace com::sun::star::table { class XCell; }
+namespace com::sun::star::table { class XCellRange; }
+namespace com::sun::star::table { struct CellRangeAddress; }
+namespace com::sun::star::lang { class XServiceInfo; }
+namespace ooo::vba { class XCollection; }
+namespace ooo::vba::excel { class XComment; }
+namespace ooo::vba::excel { class XFont; }
+
+class SfxItemSet;
+class ScCellRangesBase;
+class ScCellRangeObj;
+class ScDocShell;
+class ScDocument;
+class ScRangeList;
+
+class ArrayVisitor
+{
+public:
+ virtual void visitNode( sal_Int32 x, sal_Int32 y, const css::uno::Reference< css::table::XCell >& xCell ) = 0;
+ virtual ~ArrayVisitor(){}
+};
+
+class ValueSetter : public ArrayVisitor
+{
+public:
+ virtual bool processValue( const css::uno::Any& aValue, const css::uno::Reference< css::table::XCell >& xCell ) = 0;
+
+};
+
+class ValueGetter : public ArrayVisitor
+{
+
+public:
+ virtual void processValue( const css::uno::Any& aValue ) = 0;
+ virtual const css::uno::Any& getValue() const = 0;
+};
+
+typedef ScVbaFormat< ov::excel::XRange > ScVbaRange_BASE;
+
+class ScVbaRange : public ScVbaRange_BASE
+{
+ css::uno::Reference< ov::XCollection > m_Areas;
+ css::uno::Reference< ov::XCollection > m_Borders;
+ css::uno::Reference< css::table::XCellRange > mxRange;
+ css::uno::Reference< css::sheet::XSheetCellRangeContainer > mxRanges;
+ bool mbIsRows;
+ bool mbIsColumns;
+ css::uno::Reference< ov::excel::XValidation > m_xValidation;
+ /// @throws css::uno::RuntimeException
+ double getCalcColWidth(const css::table::CellRangeAddress&);
+ /// @throws css::uno::RuntimeException
+ double getCalcRowHeight(const css::table::CellRangeAddress&);
+ void visitArray( ArrayVisitor& visitor );
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< ov::excel::XRange > getEntireColumnOrRow( bool bColumn );
+
+ /// @throws css::uno::RuntimeException
+ void fillSeries( css::sheet::FillDirection nFillDirection, css::sheet::FillMode nFillMode, css::sheet::FillDateMode nFillDateMode, double fStep, double fEndValue );
+
+ /// @throws css::uno::RuntimeException
+ void ClearContents( sal_Int32 nFlags, bool bFireEvent );
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Any getValue( ValueGetter& rValueGetter );
+ /// @throws css::uno::RuntimeException
+ void setValue( const css::uno::Any& aValue, ValueSetter& setter );
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Any getFormulaValue( formula::FormulaGrammar::Grammar );
+ /// @throws css::uno::RuntimeException
+ void setFormulaValue( const css::uno::Any& aValue, formula::FormulaGrammar::Grammar );
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< ov::excel::XRange > getArea( sal_Int32 nIndex );
+ /// @throws css::uno::RuntimeException
+ ScCellRangeObj* getCellRangeObj( );
+ css::uno::Reference< ov::XCollection >& getBorders();
+ /// @throws css::uno::RuntimeException
+ void groupUnGroup( bool bUnGroup );
+ css::uno::Reference< ov::excel::XRange > PreviousNext( bool bIsPrevious );
+ /// @throws css::script::BasicErrorException
+ css::uno::Reference< ov::excel::XRange > SpecialCellsImpl( sal_Int32 nType, const css::uno::Any& _oValue);
+ /// @throws css::uno::RuntimeException
+ css::awt::Point getPosition() const;
+
+ /** Fires a Worksheet_Change event for this range or range list. */
+ void fireChangeEvent();
+
+ /// @throws css::uno::RuntimeException
+ ScRange obtainRangeEvenIfRangeListIsEmpty( const ScRangeList& rCellRanges ) const;
+
+protected:
+ virtual ScCellRangesBase* getCellRangesBase() override;
+ /// @throws css::uno::RuntimeException
+ SfxItemSet* getCurrentDataSet();
+public:
+ /// @throws css::lang::IllegalArgumentException
+ ScVbaRange( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::table::XCellRange >& xRange, bool bIsRows = false, bool bIsColumns = false );
+ /// @throws css::lang::IllegalArgumentException
+ /// @throws css::uno::RuntimeException
+ ScVbaRange( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::sheet::XSheetCellRangeContainer >& xRanges, bool bIsRows = false, bool bIsColumns = false );
+ /// @throws css::lang::IllegalArgumentException
+ /// @throws css::uno::RuntimeException
+ ScVbaRange( css::uno::Sequence< css::uno::Any > const& aArgs, css::uno::Reference< css::uno::XComponentContext >const& xContext );
+
+ /// @throws css::uno::RuntimeException
+ ScDocument& getScDocument();
+ /// @throws css::uno::RuntimeException
+ ScDocShell* getScDocShell();
+
+ /** Returns the ScVbaRange implementation object for the passed VBA Range object. */
+ static ScVbaRange* getImplementation( const css::uno::Reference< ov::excel::XRange >& rxRange );
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::frame::XModel > getUnoModel();
+ /// @throws css::uno::RuntimeException
+ static css::uno::Reference< css::frame::XModel > getUnoModel( const css::uno::Reference< ov::excel::XRange >& rxRange );
+
+ /// @throws css::uno::RuntimeException
+ const ScRangeList& getScRangeList();
+ /// @throws css::uno::RuntimeException
+ static const ScRangeList& getScRangeList( const css::uno::Reference< ov::excel::XRange >& rxRange );
+
+ virtual ~ScVbaRange() override;
+ virtual css::uno::Reference< ov::XHelperInterface > thisHelperIface() override { return this; }
+ bool isSingleCellRange() const;
+
+ /// @throws css::uno::RuntimeException
+ static css::uno::Reference< ov::excel::XRange > getRangeObjectForName(
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const OUString& sRangeName, ScDocShell* pDocSh,
+ formula::FormulaGrammar::AddressConvention eConv );
+
+ /// @throws css::uno::RuntimeException
+ static css::uno::Reference< ov::excel::XRange > CellsHelper(
+ const ScDocument& rDoc,
+ const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::table::XCellRange >& xRange,
+ const css::uno::Any &nRowIndex, const css::uno::Any &nColumnIndex );
+
+ // Attributes
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getFormula() override;
+ virtual void SAL_CALL setFormula( const css::uno::Any& rFormula ) override;
+ virtual css::uno::Any SAL_CALL getFormulaArray() override;
+ virtual void SAL_CALL setFormulaArray(const css::uno::Any& rFormula) override;
+ virtual css::uno::Any SAL_CALL getFormulaR1C1() override;
+ virtual void SAL_CALL setFormulaR1C1( const css::uno::Any &rFormula ) override;
+ virtual css::uno::Any SAL_CALL getFormulaLocal() override;
+ virtual void SAL_CALL setFormulaLocal( const css::uno::Any &rFormula ) override;
+ virtual css::uno::Any SAL_CALL getFormulaR1C1Local() override;
+ virtual void SAL_CALL setFormulaR1C1Local( const css::uno::Any &rFormula ) override;
+ virtual ::sal_Int32 SAL_CALL getCount() override;
+ virtual ::sal_Int32 SAL_CALL getRow() override;
+ virtual ::sal_Int32 SAL_CALL getColumn() override;
+ virtual OUString SAL_CALL getText() override;
+ using ScVbaRange_BASE::setNumberFormat;
+ virtual void SAL_CALL setNumberFormat( const css::uno::Any& rNumberFormat ) override;
+ virtual css::uno::Any SAL_CALL getNumberFormat() override;
+ virtual void SAL_CALL setMergeCells( const css::uno::Any& bMerge ) override;
+ virtual css::uno::Any SAL_CALL getMergeCells() override;
+ virtual void SAL_CALL setWrapText( const css::uno::Any& bIsWrapped ) override;
+ virtual css::uno::Any SAL_CALL getWrapText() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getEntireRow() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getEntireColumn() override;
+ virtual css::uno::Reference< ov::excel::XComment > SAL_CALL getComment() override;
+ virtual css::uno::Any SAL_CALL getHidden() override;
+ virtual void SAL_CALL setHidden( const css::uno::Any& _hidden ) override;
+ virtual css::uno::Any SAL_CALL getColumnWidth() override;
+ virtual void SAL_CALL setColumnWidth( const css::uno::Any& _columnwidth ) override;
+ virtual css::uno::Any SAL_CALL getRowHeight() override;
+ virtual void SAL_CALL setRowHeight( const css::uno::Any& _rowheight ) override;
+ virtual css::uno::Any SAL_CALL getWidth() override;
+ virtual css::uno::Any SAL_CALL getHeight() override;
+ virtual css::uno::Any SAL_CALL getTop() override;
+ virtual css::uno::Any SAL_CALL getLeft() override;
+
+ virtual css::uno::Reference< ov::excel::XName > SAL_CALL getName() override;
+ virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getWorksheet() override;
+ virtual css::uno::Any SAL_CALL getPageBreak() override;
+ virtual void SAL_CALL setPageBreak( const css::uno::Any& _pagebreak ) override;
+ virtual css::uno::Reference< ov::excel::XValidation > SAL_CALL getValidation() override;
+ virtual css::uno::Any SAL_CALL getPrefixCharacter() override;
+ virtual css::uno::Any SAL_CALL getShowDetail() override;
+ virtual void SAL_CALL setShowDetail(const css::uno::Any& aShowDetail) override;
+ // Methods
+ virtual css::uno::Reference< ov::excel::XComment > SAL_CALL AddComment( const css::uno::Any& Text ) override;
+ virtual void SAL_CALL Clear() override;
+ virtual void SAL_CALL ClearComments() override;
+ virtual void SAL_CALL ClearContents() override;
+ virtual void SAL_CALL ClearFormats() override;
+ virtual css::uno::Any SAL_CALL HasFormula() override;
+ virtual void SAL_CALL FillLeft() override;
+ virtual void SAL_CALL FillRight() override;
+ virtual void SAL_CALL FillUp() override;
+ virtual void SAL_CALL FillDown() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Offset( const css::uno::Any &nRowOffset, const css::uno::Any &nColOffset ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL CurrentRegion() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL CurrentArray() override;
+ virtual OUString SAL_CALL Characters( const css::uno::Any& nIndex, const css::uno::Any& nCount ) override;
+
+ virtual OUString SAL_CALL Address( const css::uno::Any& RowAbsolute, const css::uno::Any& ColumnAbsolute, const css::uno::Any& ReferenceStyle, const css::uno::Any& External, const css::uno::Any& RelativeTo ) override;
+
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Cells( const css::uno::Any &nRow, const css::uno::Any &nCol ) override;
+ virtual void SAL_CALL Select() override;
+ virtual void SAL_CALL Activate() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Rows( const css::uno::Any& nIndex ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Columns( const css::uno::Any &nIndex ) override;
+ virtual void SAL_CALL Copy( const css::uno::Any& Destination ) override;
+ virtual void SAL_CALL Cut( const css::uno::Any& Destination ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Resize( const css::uno::Any& RowSize, const css::uno::Any& ColumnSize ) override;
+ virtual css::uno::Reference< ov::excel::XFont > SAL_CALL Font() override;
+ virtual css::uno::Reference< ov::excel::XInterior > SAL_CALL Interior( ) override ;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Range( const css::uno::Any &Cell1, const css::uno::Any &Cell2 ) override;
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< ov::excel::XRange > Range( const css::uno::Any &Cell1, const css::uno::Any &Cell2, bool bForceUseInpuRangeTab );
+ virtual css::uno::Any SAL_CALL getCellRange( ) override;
+ /// @throws css::uno::RuntimeException
+ static css::uno::Any getCellRange( const css::uno::Reference< ov::excel::XRange >& rxRange );
+ virtual void SAL_CALL PasteSpecial( const css::uno::Any& Paste, const css::uno::Any& Operation, const css::uno::Any& SkipBlanks, const css::uno::Any& Transpose ) override;
+ virtual sal_Bool SAL_CALL Replace( const OUString& What, const OUString& Replacement, const css::uno::Any& LookAt, const css::uno::Any& SearchOrder, const css::uno::Any& MatchCase, const css::uno::Any& MatchByte, const css::uno::Any& SearchFormat, const css::uno::Any& ReplaceFormat ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Find( const css::uno::Any& What, const css::uno::Any& After, const css::uno::Any& LookIn, const css::uno::Any& LookAt, const css::uno::Any& SearchOrder, const css::uno::Any& SearchDirection, const css::uno::Any& MatchCase, const css::uno::Any& MatchByte, const css::uno::Any& SearchFormat ) override;
+ virtual void SAL_CALL Sort( const css::uno::Any& Key1, const css::uno::Any& Order1, const css::uno::Any& Key2, const css::uno::Any& Type, const css::uno::Any& Order2, const css::uno::Any& Key3, const css::uno::Any& Order3, const css::uno::Any& Header, const css::uno::Any& OrderCustom, const css::uno::Any& MatchCase, const css::uno::Any& Orientation, const css::uno::Any& SortMethod, const css::uno::Any& DataOption1, const css::uno::Any& DataOption2, const css::uno::Any& DataOption3 ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL End( ::sal_Int32 Direction ) override;
+ virtual css::uno::Reference< ov::excel::XCharacters > SAL_CALL characters( const css::uno::Any& Start, const css::uno::Any& Length ) override;
+ virtual void SAL_CALL Delete( const css::uno::Any& Shift ) override;
+ virtual css::uno::Any SAL_CALL Areas( const css::uno::Any& ) override;
+ virtual css::uno::Any SAL_CALL Borders( const css::uno::Any& ) override;
+ virtual css::uno::Any SAL_CALL BorderAround( const css::uno::Any& LineStyle,
+ const css::uno::Any& Weight, const css::uno::Any& ColorIndex, const css::uno::Any& Color ) override;
+ virtual css::uno::Any SAL_CALL Hyperlinks( const css::uno::Any& aIndex ) override;
+
+ virtual void SAL_CALL AutoFilter( const css::uno::Any& Field, const css::uno::Any& Criteria1, const css::uno::Any& Operator, const css::uno::Any& Criteria2, const css::uno::Any& VisibleDropDown ) override;
+ virtual void SAL_CALL Insert( const css::uno::Any& Shift, const css::uno::Any& CopyOrigin ) override;
+ virtual void SAL_CALL Autofit() override;
+ virtual void SAL_CALL PrintOut( const css::uno::Any& From, const css::uno::Any& To, const css::uno::Any& Copies, const css::uno::Any& Preview, const css::uno::Any& ActivePrinter, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& PrToFileName ) override;
+ virtual void SAL_CALL AutoFill( const css::uno::Reference< ov::excel::XRange >& Destination, const css::uno::Any& Type ) override ;
+ void SAL_CALL Calculate( ) override;
+ virtual void SAL_CALL AutoOutline( ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Item( const css::uno::Any& row, const css::uno::Any& column ) override;
+ virtual void SAL_CALL ClearOutline( ) override;
+ virtual void SAL_CALL Ungroup( ) override;
+ virtual void SAL_CALL Group( ) override;
+ virtual void SAL_CALL Merge( const css::uno::Any& Across ) override;
+ virtual void SAL_CALL UnMerge( ) override;
+ virtual css::uno::Any SAL_CALL getStyle() override;
+ virtual void SAL_CALL setStyle( const css::uno::Any& _style ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Next() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Previous() override;
+ virtual void SAL_CALL RemoveSubtotal( ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL MergeArea() override;
+ virtual void SAL_CALL Subtotal( ::sal_Int32 GroupBy, ::sal_Int32 Function, const css::uno::Sequence< ::sal_Int32 >& TotalList, const css::uno::Any& Replace, const css::uno::Any& PageBreaks, const css::uno::Any& SummaryBelowData ) override;
+
+ // XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override
+ {
+ return cppu::UnoType<ov::excel::XRange>::get();
+
+ }
+ virtual sal_Bool SAL_CALL hasElements() override;
+ // XDefaultMethod
+ OUString SAL_CALL getDefaultMethodName( ) override;
+ // XDefaultProperty
+ OUString SAL_CALL getDefaultPropertyName( ) override { return "Value"; }
+
+// #TODO completely rewrite ScVbaRange, it's become a hackfest
+// it needs to be closer to ScCellRangeBase in that the underlying
+// object model should probably be a ScRangelst.
+// * would be nice to be able to construct a range from an address only
+// * or a list of address ( multi-area )
+// * object should be a lightweight as possible
+// * we shouldn't need hacks like this below
+ /// @throws css::uno::RuntimeException
+ static css::uno::Reference< ov::excel::XRange > ApplicationRange( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Any &Cell1, const css::uno::Any &Cell2 );
+ static bool getCellRangesForAddress(ScRefFlags &rResFlags, std::u16string_view sAddress, ScDocShell* pDocSh, ScRangeList& rCellRanges, formula::FormulaGrammar::AddressConvention eConv, char cDelimiter );
+ virtual sal_Bool SAL_CALL GoalSeek( const css::uno::Any& Goal, const css::uno::Reference< ov::excel::XRange >& ChangingCell ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL SpecialCells( const css::uno::Any& _oType, const css::uno::Any& _oValue) override;
+ // XErrorQuery
+ virtual sal_Bool SAL_CALL hasError( ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/// @throws css::uno::RuntimeException
+bool getScRangeListForAddress( const OUString& sName, ScDocShell* pDocSh, const ScRange& refRange,
+ ScRangeList& aCellRanges,
+ formula::FormulaGrammar::AddressConvention aConv = formula::FormulaGrammar::CONV_XL_A1 );
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbasheetobject.cxx b/sc/source/ui/vba/vbasheetobject.cxx
new file mode 100644
index 000000000..52513095f
--- /dev/null
+++ b/sc/source/ui/vba/vbasheetobject.cxx
@@ -0,0 +1,540 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "vbasheetobject.hxx"
+#include <com/sun/star/awt/TextAlign.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/script/ScriptEventDescriptor.hpp>
+#include <com/sun/star/script/XEventAttacherManager.hpp>
+#include <com/sun/star/style/VerticalAlignment.hpp>
+#include <comphelper/documentinfo.hxx>
+#include <ooo/vba/excel/Constants.hpp>
+#include <ooo/vba/excel/XlOrientation.hpp>
+#include <ooo/vba/excel/XlPlacement.hpp>
+#include <filter/msfilter/msvbahelper.hxx>
+#include "vbafont.hxx"
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+constexpr OUStringLiteral gaListenerType = u"XActionListener";
+constexpr OUStringLiteral gaEventMethod = u"actionPerformed";
+
+
+ScVbaButtonCharacters::ScVbaButtonCharacters(
+ const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< beans::XPropertySet >& rxPropSet,
+ const ScVbaPalette& rPalette,
+ const uno::Any& rStart,
+ const uno::Any& rLength ) :
+ ScVbaButtonCharacters_BASE( rxParent, rxContext ),
+ maPalette( rPalette ),
+ mxPropSet( rxPropSet, uno::UNO_SET_THROW )
+{
+ // extract optional start parameter (missing or invalid -> from beginning)
+ if( !(rStart >>= mnStart) || (mnStart < 1) )
+ mnStart = 1;
+ --mnStart; // VBA is 1-based, rtl string is 0-based
+
+ // extract optional length parameter (missing or invalid -> to end)
+ if( !(rLength >>= mnLength) || (mnLength < 1) )
+ mnLength = SAL_MAX_INT32;
+}
+
+ScVbaButtonCharacters::~ScVbaButtonCharacters()
+{
+}
+
+// XCharacters attributes
+
+OUString SAL_CALL ScVbaButtonCharacters::getCaption()
+{
+ // ignore invalid mnStart and/or mnLength members
+ OUString aString = getFullString();
+ sal_Int32 nStart = ::std::min( mnStart, aString.getLength() );
+ sal_Int32 nLength = ::std::min( mnLength, aString.getLength() - nStart );
+ return aString.copy( nStart, nLength );
+}
+
+void SAL_CALL ScVbaButtonCharacters::setCaption( const OUString& rCaption )
+{
+ /* Replace the covered text with the passed text, ignore invalid mnStart
+ and/or mnLength members. This operation does not affect the mnLength
+ parameter. If the inserted text is longer than mnLength, the additional
+ characters are not covered by this object. If the inserted text is
+ shorter than mnLength, other uncovered characters from the original
+ string will be covered now, thus may be changed with subsequent
+ operations. */
+ OUString aString = getFullString();
+ sal_Int32 nStart = ::std::min( mnStart, aString.getLength() );
+ sal_Int32 nLength = ::std::min( mnLength, aString.getLength() - nStart );
+ setFullString( aString.replaceAt( nStart, nLength, rCaption ) );
+}
+
+sal_Int32 SAL_CALL ScVbaButtonCharacters::getCount()
+{
+ // always return the total length of the caption
+ return getFullString().getLength();
+}
+
+OUString SAL_CALL ScVbaButtonCharacters::getText()
+{
+ // Text attribute same as Caption attribute?
+ return getCaption();
+}
+
+void SAL_CALL ScVbaButtonCharacters::setText( const OUString& rText )
+{
+ // Text attribute same as Caption attribute?
+ setCaption( rText );
+}
+
+uno::Reference< excel::XFont > SAL_CALL ScVbaButtonCharacters::getFont()
+{
+ return new ScVbaFont( this, mxContext, maPalette, mxPropSet, nullptr, true );
+}
+
+void SAL_CALL ScVbaButtonCharacters::setFont( const uno::Reference< excel::XFont >& /*rxFont*/ )
+{
+ // TODO
+}
+
+// XCharacters methods
+
+void SAL_CALL ScVbaButtonCharacters::Insert( const OUString& rString )
+{
+ /* The Insert() operation is in fact "replace covered characters", at
+ least for buttons... It seems there is no easy way to really insert a
+ substring. This operation does not affect the mnLength parameter. */
+ setCaption( rString );
+}
+
+void SAL_CALL ScVbaButtonCharacters::Delete()
+{
+ /* The Delete() operation is nothing else than "replace with empty string".
+ This does not affect the mnLength parameter, multiple calls of Delete()
+ will remove characters as long as there are some more covered by this
+ object. */
+ setCaption( OUString() );
+}
+
+// XHelperInterface
+
+VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaButtonCharacters, "ooo.vba.excel.Characters" )
+
+// private
+
+OUString ScVbaButtonCharacters::getFullString() const
+{
+ return mxPropSet->getPropertyValue( "Label" ).get< OUString >();
+}
+
+void ScVbaButtonCharacters::setFullString( const OUString& rString )
+{
+ mxPropSet->setPropertyValue( "Label", uno::Any( rString ) );
+}
+
+ScVbaSheetObjectBase::ScVbaSheetObjectBase(
+ const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< frame::XModel >& rxModel,
+ const uno::Reference< drawing::XShape >& rxShape ) :
+ ScVbaSheetObject_BASE( rxParent, rxContext ),
+ maPalette( rxModel ),
+ mxModel( rxModel, uno::UNO_SET_THROW ),
+ mxShape( rxShape, uno::UNO_SET_THROW ),
+ mxShapeProps( rxShape, uno::UNO_QUERY_THROW )
+{
+}
+
+// XSheetObject attributes
+
+double SAL_CALL ScVbaSheetObjectBase::getLeft()
+{
+ return HmmToPoints( mxShape->getPosition().X );
+}
+
+void SAL_CALL ScVbaSheetObjectBase::setLeft( double fLeft )
+{
+ if( fLeft < 0.0 )
+ throw uno::RuntimeException();
+ mxShape->setPosition( awt::Point( PointsToHmm( fLeft ), mxShape->getPosition().Y ) );
+}
+
+double SAL_CALL ScVbaSheetObjectBase::getTop()
+{
+ return HmmToPoints( mxShape->getPosition().Y );
+}
+
+void SAL_CALL ScVbaSheetObjectBase::setTop( double fTop )
+{
+ if( fTop < 0.0 )
+ throw uno::RuntimeException();
+ mxShape->setPosition( awt::Point( mxShape->getPosition().X, PointsToHmm( fTop ) ) );
+}
+
+double SAL_CALL ScVbaSheetObjectBase::getWidth()
+{
+ return HmmToPoints( mxShape->getSize().Width );
+}
+
+void SAL_CALL ScVbaSheetObjectBase::setWidth( double fWidth )
+{
+ if( fWidth <= 0.0 )
+ throw uno::RuntimeException();
+ mxShape->setSize( awt::Size( PointsToHmm( fWidth ), mxShape->getSize().Height ) );
+}
+
+double SAL_CALL ScVbaSheetObjectBase::getHeight()
+{
+ return HmmToPoints( mxShape->getSize().Height );
+}
+
+void SAL_CALL ScVbaSheetObjectBase::setHeight( double fHeight )
+{
+ if( fHeight <= 0.0 )
+ throw uno::RuntimeException();
+ mxShape->setSize( awt::Size( mxShape->getSize().Width, PointsToHmm( fHeight ) ) );
+}
+
+OUString SAL_CALL ScVbaSheetObjectBase::getName()
+{
+ return mxShapeProps->getPropertyValue( "Name" ).get< OUString >();
+}
+
+void SAL_CALL ScVbaSheetObjectBase::setName( const OUString& rName )
+{
+ mxShapeProps->setPropertyValue( "Name", uno::Any( rName ) );
+}
+
+sal_Int32 SAL_CALL ScVbaSheetObjectBase::getPlacement()
+{
+ sal_Int32 const nRet = excel::XlPlacement::xlMoveAndSize;
+#if 0 // TODO: not working at the moment.
+ SvxShape* pShape = SdrObject::getSdrObjectFromXShape( mxShape );
+ if(pShape)
+ {
+ SdrObject* pObj = pShape->GetSdrObject();
+ if (pObj)
+ {
+ ScAnchorType eType = ScDrawLayer::GetAnchor(pObj);
+ if (eType == SCA_PAGE)
+ nRet = excel::XlPlacement::xlFreeFloating;
+ }
+ }
+#endif
+ return nRet;
+}
+
+void SAL_CALL ScVbaSheetObjectBase::setPlacement( sal_Int32 /*nPlacement*/ )
+{
+#if 0 // TODO: not working at the moment.
+ SvxShape* pShape = SdrObject::getSdrObjectFromXShape( mxShape );
+ if(pShape)
+ {
+ SdrObject* pObj = pShape->GetSdrObject();
+ if (pObj)
+ {
+ ScAnchorType eType = SCA_CELL;
+ if ( nPlacement == excel::XlPlacement::xlFreeFloating )
+ eType = SCA_PAGE;
+
+ // xlMove is not supported, treated as SCA_CELL (xlMoveAndSize)
+
+ ScDrawLayer::SetAnchor(pObj, eType);
+ }
+ }
+#endif
+}
+
+sal_Bool SAL_CALL ScVbaSheetObjectBase::getPrintObject()
+{
+ // not supported
+ return true;
+}
+
+void SAL_CALL ScVbaSheetObjectBase::setPrintObject( sal_Bool /*bPrintObject*/ )
+{
+ // not supported
+}
+
+// private
+
+void ScVbaSheetObjectBase::setDefaultProperties( sal_Int32 nIndex )
+{
+ OUString aName = implGetBaseName() + OUStringChar(' ') + OUString::number( nIndex + 1 );
+ setName( aName );
+ implSetDefaultProperties();
+}
+
+void ScVbaSheetObjectBase::implSetDefaultProperties()
+{
+}
+
+ScVbaControlObjectBase::ScVbaControlObjectBase(
+ const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< frame::XModel >& rxModel,
+ const uno::Reference< container::XIndexContainer >& rxFormIC,
+ const uno::Reference< drawing::XControlShape >& rxControlShape ) :
+ ScVbaControlObject_BASE( rxParent, rxContext, rxModel, uno::Reference< drawing::XShape >( rxControlShape, uno::UNO_QUERY_THROW ) ),
+ mxFormIC( rxFormIC, uno::UNO_SET_THROW ),
+ mxControlProps( rxControlShape->getControl(), uno::UNO_QUERY_THROW ),
+ mbNotifyMacroEventRead(false)
+{
+}
+
+// XSheetObject attributes
+
+OUString SAL_CALL ScVbaControlObjectBase::getName()
+{
+ return mxControlProps->getPropertyValue( "Name" ).get< OUString >();
+}
+
+void SAL_CALL ScVbaControlObjectBase::setName( const OUString& rName )
+{
+ mxControlProps->setPropertyValue( "Name", uno::Any( rName ) );
+}
+
+OUString SAL_CALL ScVbaControlObjectBase::getOnAction()
+{
+ uno::Reference< script::XEventAttacherManager > xEventMgr( mxFormIC, uno::UNO_QUERY_THROW );
+ sal_Int32 nIndex = getModelIndexInForm();
+ const uno::Sequence< script::ScriptEventDescriptor > aEvents = xEventMgr->getScriptEvents( nIndex );
+ if( aEvents.hasElements() )
+ {
+ const script::ScriptEventDescriptor* pEvent = std::find_if(aEvents.begin(), aEvents.end(),
+ [](const script::ScriptEventDescriptor& rEvent) {
+ return (rEvent.ListenerType == gaListenerType)
+ && (rEvent.EventMethod == gaEventMethod)
+ && (rEvent.ScriptType == "Script");
+ });
+ if (pEvent != aEvents.end())
+ return extractMacroName( pEvent->ScriptCode );
+ }
+ return OUString();
+}
+
+void ScVbaControlObjectBase::NotifyMacroEventRead()
+{
+ if (mbNotifyMacroEventRead)
+ return;
+ comphelper::DocumentInfo::notifyMacroEventRead(mxModel);
+ mbNotifyMacroEventRead = true;
+}
+
+void SAL_CALL ScVbaControlObjectBase::setOnAction( const OUString& rMacroName )
+{
+ uno::Reference< script::XEventAttacherManager > xEventMgr( mxFormIC, uno::UNO_QUERY_THROW );
+ sal_Int32 nIndex = getModelIndexInForm();
+
+ // first, remove a registered event (try/catch just in case implementation throws)
+ try { xEventMgr->revokeScriptEvent( nIndex, gaListenerType, gaEventMethod, OUString() ); } catch( uno::Exception& ) {}
+
+ // if a macro name has been passed, try to attach it to the event
+ if( rMacroName.isEmpty() )
+ return;
+
+ MacroResolvedInfo aResolvedMacro = resolveVBAMacro( getSfxObjShell( mxModel ), rMacroName );
+ if( !aResolvedMacro.mbFound )
+ throw uno::RuntimeException();
+ script::ScriptEventDescriptor aDescriptor;
+ aDescriptor.ListenerType = gaListenerType;
+ aDescriptor.EventMethod = gaEventMethod;
+ aDescriptor.ScriptType = "Script";
+ aDescriptor.ScriptCode = makeMacroURL( aResolvedMacro.msResolvedMacro );
+ NotifyMacroEventRead();
+ xEventMgr->registerScriptEvent( nIndex, aDescriptor );
+}
+
+sal_Bool SAL_CALL ScVbaControlObjectBase::getPrintObject()
+{
+ return mxControlProps->getPropertyValue( "Printable" ).get<bool>();
+}
+
+void SAL_CALL ScVbaControlObjectBase::setPrintObject( sal_Bool bPrintObject )
+{
+ mxControlProps->setPropertyValue( "Printable", uno::Any( bPrintObject ) );
+}
+
+// XControlObject attributes
+
+sal_Bool SAL_CALL ScVbaControlObjectBase::getAutoSize()
+{
+ // not supported
+ return false;
+}
+
+void SAL_CALL ScVbaControlObjectBase::setAutoSize( sal_Bool /*bAutoSize*/ )
+{
+ // not supported
+}
+
+// private
+
+sal_Int32 ScVbaControlObjectBase::getModelIndexInForm() const
+{
+ for( sal_Int32 nIndex = 0, nCount = mxFormIC->getCount(); nIndex < nCount; ++nIndex )
+ {
+ uno::Reference< beans::XPropertySet > xProps( mxFormIC->getByIndex( nIndex ), uno::UNO_QUERY_THROW );
+ if( mxControlProps.get() == xProps.get() )
+ return nIndex;
+ }
+ throw uno::RuntimeException();
+}
+
+ScVbaButton::ScVbaButton(
+ const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< frame::XModel >& rxModel,
+ const uno::Reference< container::XIndexContainer >& rxFormIC,
+ const uno::Reference< drawing::XControlShape >& rxControlShape ) :
+ ScVbaButton_BASE( rxParent, rxContext, rxModel, rxFormIC, rxControlShape )
+{
+}
+
+// XButton attributes
+
+OUString SAL_CALL ScVbaButton::getCaption()
+{
+ return mxControlProps->getPropertyValue( "Label" ).get< OUString >();
+}
+
+void SAL_CALL ScVbaButton::setCaption( const OUString& rCaption )
+{
+ mxControlProps->setPropertyValue( "Label", uno::Any( rCaption ) );
+}
+
+uno::Reference< excel::XFont > SAL_CALL ScVbaButton::getFont()
+{
+ return new ScVbaFont( this, mxContext, maPalette, mxControlProps, nullptr, true );
+}
+
+void SAL_CALL ScVbaButton::setFont( const uno::Reference< excel::XFont >& /*rxFont*/ )
+{
+ // TODO
+}
+
+sal_Int32 SAL_CALL ScVbaButton::getHorizontalAlignment()
+{
+ switch( mxControlProps->getPropertyValue( "Align" ).get< sal_Int16 >() )
+ {
+ case awt::TextAlign::LEFT: return excel::Constants::xlLeft;
+ case awt::TextAlign::RIGHT: return excel::Constants::xlRight;
+ case awt::TextAlign::CENTER: return excel::Constants::xlCenter;
+ }
+ return excel::Constants::xlCenter;
+}
+
+void SAL_CALL ScVbaButton::setHorizontalAlignment( sal_Int32 nAlign )
+{
+ sal_Int32 nAwtAlign = awt::TextAlign::CENTER;
+ switch( nAlign )
+ {
+ case excel::Constants::xlLeft: nAwtAlign = awt::TextAlign::LEFT; break;
+ case excel::Constants::xlRight: nAwtAlign = awt::TextAlign::RIGHT; break;
+ case excel::Constants::xlCenter: nAwtAlign = awt::TextAlign::CENTER; break;
+ }
+ // form controls expect short value
+ mxControlProps->setPropertyValue( "Align", uno::Any( static_cast< sal_Int16 >( nAwtAlign ) ) );
+}
+
+sal_Int32 SAL_CALL ScVbaButton::getVerticalAlignment()
+{
+ switch( mxControlProps->getPropertyValue( "VerticalAlign" ).get< style::VerticalAlignment >() )
+ {
+ case style::VerticalAlignment_TOP: return excel::Constants::xlTop;
+ case style::VerticalAlignment_BOTTOM: return excel::Constants::xlBottom;
+ case style::VerticalAlignment_MIDDLE: return excel::Constants::xlCenter;
+ default:;
+ }
+ return excel::Constants::xlCenter;
+}
+
+void SAL_CALL ScVbaButton::setVerticalAlignment( sal_Int32 nAlign )
+{
+ style::VerticalAlignment eAwtAlign = style::VerticalAlignment_MIDDLE;
+ switch( nAlign )
+ {
+ case excel::Constants::xlTop: eAwtAlign = style::VerticalAlignment_TOP; break;
+ case excel::Constants::xlBottom: eAwtAlign = style::VerticalAlignment_BOTTOM; break;
+ case excel::Constants::xlCenter: eAwtAlign = style::VerticalAlignment_MIDDLE; break;
+ }
+ mxControlProps->setPropertyValue( "VerticalAlign", uno::Any( eAwtAlign ) );
+}
+
+sal_Int32 SAL_CALL ScVbaButton::getOrientation()
+{
+ // not supported
+ return excel::XlOrientation::xlHorizontal;
+}
+
+void SAL_CALL ScVbaButton::setOrientation( sal_Int32 /*nOrientation*/ )
+{
+ // not supported
+}
+
+uno::Any SAL_CALL ScVbaButton::getValue()
+{
+ return mxControlProps->getPropertyValue( "State" );
+}
+
+void SAL_CALL ScVbaButton::setValue( const uno::Any &nValue )
+{
+ return mxControlProps->setPropertyValue( "State", nValue );
+}
+
+OUString SAL_CALL ScVbaButton::getText()
+{
+ return mxControlProps->getPropertyValue( "Label" ).get< OUString >();
+}
+
+void SAL_CALL ScVbaButton::setText( const OUString &aText )
+{
+ return mxControlProps->setPropertyValue( "Label", uno::Any( aText ) );
+}
+
+// XButton methods
+
+uno::Reference< excel::XCharacters > SAL_CALL ScVbaButton::Characters( const uno::Any& rStart, const uno::Any& rLength )
+{
+ return new ScVbaButtonCharacters( this, mxContext, mxControlProps, maPalette, rStart, rLength );
+}
+
+// XHelperInterface
+
+VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaButton, "ooo.vba.excel.Button" )
+
+// private
+
+OUString ScVbaButton::implGetBaseName() const
+{
+ return "Button";
+}
+
+void ScVbaButton::implSetDefaultProperties()
+{
+ setCaption( getName() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbasheetobject.hxx b/sc/source/ui/vba/vbasheetobject.hxx
new file mode 100644
index 000000000..d88b15034
--- /dev/null
+++ b/sc/source/ui/vba/vbasheetobject.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 <ooo/vba/excel/XButton.hpp>
+#include <ooo/vba/excel/XControlObject.hpp>
+#include <ooo/vba/excel/XSheetObject.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <vbahelper/vbahelperinterface.hxx>
+#include "vbapalette.hxx"
+
+namespace com::sun::star {
+ namespace container { class XIndexContainer; }
+ namespace drawing { class XControlShape; }
+}
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XCharacters > ScVbaButtonCharacters_BASE;
+
+/** Simple implementation of the Characters symbol for drawing button objects. */
+class ScVbaButtonCharacters : public ScVbaButtonCharacters_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ explicit ScVbaButtonCharacters(
+ const css::uno::Reference< ov::XHelperInterface >& rxParent,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Reference< css::beans::XPropertySet >& rxPropSet,
+ const ScVbaPalette& rPalette,
+ const css::uno::Any& rStart,
+ const css::uno::Any& rLength );
+ virtual ~ScVbaButtonCharacters() override;
+
+ // XCharacters attributes
+ virtual OUString SAL_CALL getCaption() override;
+ virtual void SAL_CALL setCaption( const OUString& rCaption ) override;
+ virtual OUString SAL_CALL getText() override;
+ virtual void SAL_CALL setText( const OUString& rText ) override;
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual css::uno::Reference< ov::excel::XFont > SAL_CALL getFont() override;
+ virtual void SAL_CALL setFont( const css::uno::Reference< ov::excel::XFont >& rxFont ) override;
+
+ // XCharacters methods
+ virtual void SAL_CALL Insert( const OUString& rString ) override;
+ virtual void SAL_CALL Delete() override;
+
+ // XHelperInterface
+ VBAHELPER_DECL_XHELPERINTERFACE
+
+private:
+ /// @throws css::uno::RuntimeException
+ OUString getFullString() const;
+ /// @throws css::uno::RuntimeException
+ void setFullString( const OUString& rString );
+
+private:
+ ScVbaPalette maPalette;
+ css::uno::Reference< css::beans::XPropertySet > mxPropSet;
+ sal_Int32 mnStart;
+ sal_Int32 mnLength;
+};
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XSheetObject > ScVbaSheetObject_BASE;
+
+/** Base class for drawing objects embedded in sheets. */
+class ScVbaSheetObjectBase : public ScVbaSheetObject_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ explicit ScVbaSheetObjectBase(
+ const css::uno::Reference< ov::XHelperInterface >& rxParent,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Reference< css::frame::XModel >& rxModel,
+ const css::uno::Reference< css::drawing::XShape >& rxShape );
+
+ // XSheetObject attributes
+ virtual double SAL_CALL getLeft() override;
+ virtual void SAL_CALL setLeft( double fLeft ) override;
+ virtual double SAL_CALL getTop() override;
+ virtual void SAL_CALL setTop( double fTop ) override;
+ virtual double SAL_CALL getWidth() override;
+ virtual void SAL_CALL setWidth( double fWidth ) override;
+ virtual double SAL_CALL getHeight() override;
+ virtual void SAL_CALL setHeight( double fHeight ) override;
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName( const OUString& rName ) override;
+ virtual sal_Int32 SAL_CALL getPlacement() override;
+ virtual void SAL_CALL setPlacement( sal_Int32 nPlacement ) override;
+ virtual sal_Bool SAL_CALL getPrintObject() override;
+ virtual void SAL_CALL setPrintObject( sal_Bool bPrintObject ) override;
+
+ /** Sets default properties after a new object has been created.
+
+ @throws css::uno::RuntimeException
+ */
+ void setDefaultProperties( sal_Int32 nIndex );
+
+protected:
+ /** Derived classes return the base name used for new objects. */
+ virtual OUString implGetBaseName() const = 0;
+ /** Derived classes set default properties for new drawing objects.
+
+ @throws css::uno::RuntimeException
+ */
+ virtual void implSetDefaultProperties();
+
+protected:
+ ScVbaPalette maPalette;
+ css::uno::Reference< css::frame::XModel > mxModel;
+ css::uno::Reference< css::drawing::XShape > mxShape;
+ css::uno::Reference< css::beans::XPropertySet > mxShapeProps;
+};
+
+typedef ::cppu::ImplInheritanceHelper< ScVbaSheetObjectBase, ov::excel::XControlObject > ScVbaControlObject_BASE;
+
+class ScVbaControlObjectBase : public ScVbaControlObject_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ explicit ScVbaControlObjectBase(
+ const css::uno::Reference< ov::XHelperInterface >& rxParent,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Reference< css::frame::XModel >& rxModel,
+ const css::uno::Reference< css::container::XIndexContainer >& rxFormIC,
+ const css::uno::Reference< css::drawing::XControlShape >& rxControlShape );
+
+ // XSheetObject attributes
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName( const OUString& rName ) override;
+ virtual OUString SAL_CALL getOnAction() override;
+ virtual void SAL_CALL setOnAction( const OUString& rMacroName ) override;
+ virtual sal_Bool SAL_CALL getPrintObject() override;
+ virtual void SAL_CALL setPrintObject( sal_Bool bPrintObject ) override;
+
+ // XControlObject attributes
+ virtual sal_Bool SAL_CALL getAutoSize() override;
+ virtual void SAL_CALL setAutoSize( sal_Bool bAutoSize ) override;
+
+ /// Notify that the document contains a macro event handler
+ void NotifyMacroEventRead();
+
+protected:
+ /// @throws css::uno::RuntimeException
+ sal_Int32 getModelIndexInForm() const;
+
+protected:
+ css::uno::Reference< css::container::XIndexContainer > mxFormIC;
+ css::uno::Reference< css::beans::XPropertySet > mxControlProps;
+ bool mbNotifyMacroEventRead;
+};
+
+typedef ::cppu::ImplInheritanceHelper< ScVbaControlObjectBase, ov::excel::XButton > ScVbaButton_BASE;
+
+class ScVbaButton : public ScVbaButton_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ explicit ScVbaButton(
+ const css::uno::Reference< ov::XHelperInterface >& rxParent,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Reference< css::frame::XModel >& rxModel,
+ const css::uno::Reference< css::container::XIndexContainer >& rxFormIC,
+ const css::uno::Reference< css::drawing::XControlShape >& rxControlShape );
+
+ // XButton attributes
+ virtual OUString SAL_CALL getCaption() override;
+ virtual void SAL_CALL setCaption( const OUString& rCaption ) override;
+ virtual css::uno::Reference< ov::excel::XFont > SAL_CALL getFont() override;
+ virtual void SAL_CALL setFont( const css::uno::Reference< ov::excel::XFont >& rxFont ) override;
+ virtual sal_Int32 SAL_CALL getHorizontalAlignment() override;
+ virtual void SAL_CALL setHorizontalAlignment( sal_Int32 nAlign ) override;
+ virtual sal_Int32 SAL_CALL getVerticalAlignment() override;
+ virtual void SAL_CALL setVerticalAlignment( sal_Int32 nAlign ) override;
+ virtual sal_Int32 SAL_CALL getOrientation() override;
+ virtual void SAL_CALL setOrientation( sal_Int32 nOrientation ) override;
+ virtual css::uno::Any SAL_CALL getValue() override;
+ virtual void SAL_CALL setValue( const css::uno::Any &nValue ) override;
+ virtual OUString SAL_CALL getText() override;
+ virtual void SAL_CALL setText( const OUString &aText ) override;
+
+ // XButton methods
+ css::uno::Reference< ov::excel::XCharacters > SAL_CALL Characters(
+ const css::uno::Any& rStart, const css::uno::Any& rLength ) override;
+
+ // XHelperInterface
+ VBAHELPER_DECL_XHELPERINTERFACE
+
+protected:
+ virtual OUString implGetBaseName() const override;
+ virtual void implSetDefaultProperties() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbasheetobjects.cxx b/sc/source/ui/vba/vbasheetobjects.cxx
new file mode 100644
index 000000000..32e025a3c
--- /dev/null
+++ b/sc/source/ui/vba/vbasheetobjects.cxx
@@ -0,0 +1,555 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "vbasheetobjects.hxx"
+#include <vector>
+#include <rtl/math.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/drawing/XShapes.hpp>
+#include <com/sun/star/form/FormComponentType.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <com/sun/star/form/XFormComponent.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include "vbasheetobject.hxx"
+#include <cppuhelper/implbase.hxx>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+namespace {
+
+template< typename Type >
+bool lclGetProperty( Type& orValue, const uno::Reference< beans::XPropertySet >& rxPropSet, const OUString& rPropName )
+{
+ try
+ {
+ return rxPropSet->getPropertyValue( rPropName ) >>= orValue;
+ }
+ catch( uno::Exception& )
+ {
+ }
+ return false;
+}
+
+/** Rounds the passed value to a multiple of 0.75 and converts it to 1/100 mm.
+
+ @throws uno::RuntimeException
+*/
+double lclPointsToHmm( const uno::Any& rPoints )
+{
+ return PointsToHmm( ::rtl::math::approxFloor( rPoints.get< double >() / 0.75 ) * 0.75 );
+}
+
+} // namespace
+
+// Base implementations
+
+/** Container for a specific type of drawing object in a spreadsheet.
+
+ Derived classes provide all required functionality specific to the type of
+ shapes covered by the container.
+ */
+class ScVbaObjectContainer : public ::cppu::WeakImplHelper< container::XIndexAccess >
+{
+public:
+ /// @throws uno::RuntimeException
+ explicit ScVbaObjectContainer(
+ const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< frame::XModel >& rxModel,
+ const uno::Reference< sheet::XSpreadsheet >& rxSheet,
+ const uno::Type& rVbaType );
+
+ /** Returns the VBA helper interface of the VBA collection object. */
+ const uno::Reference< XHelperInterface >& getParent() const { return mxParent; }
+ /** Returns the component context of the VBA collection object. */
+ const uno::Reference< uno::XComponentContext >& getContext() const { return mxContext; }
+ /** Returns the VBA type information of the objects in this container. */
+ const uno::Type& getVbaType() const { return maVbaType; }
+
+ /** Collects all shapes supported by this instance and inserts them into
+ the internal shape vector.
+
+ @throws uno::RuntimeException
+ */
+ void collectShapes();
+ /** Creates and returns a new UNO shape.
+
+ @throws uno::RuntimeException
+ */
+ uno::Reference< drawing::XShape > createShape( const awt::Point& rPos, const awt::Size& rSize );
+ /** Inserts the passed shape into the draw page and into this container, and returns its index in the draw page.
+
+ @throws uno::RuntimeException
+ */
+ sal_Int32 insertShape( const uno::Reference< drawing::XShape >& rxShape );
+ /** Creates and returns a new VBA implementation object for the passed shape.
+
+ @throws uno::RuntimeException
+ */
+ ::rtl::Reference< ScVbaSheetObjectBase > createVbaObject( const uno::Reference< drawing::XShape >& rxShape );
+ /** Creates and returns a new VBA implementation object for the passed shape in an Any.
+
+ @throws uno::RuntimeException
+ */
+ uno::Any createCollectionObject( const uno::Any& rSource );
+ /** Returns the VBA implementation object with the specified name.
+
+ @throws uno::RuntimeException
+ */
+ uno::Any getItemByStringIndex( const OUString& rIndex );
+
+ // XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount() override;
+ virtual uno::Any SAL_CALL getByIndex( sal_Int32 nIndex ) override;
+
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType() override;
+ virtual sal_Bool SAL_CALL hasElements() override;
+
+protected:
+ /** Derived classes return true, if the passed shape is supported by the instance. */
+ virtual bool implPickShape( const uno::Reference< drawing::XShape >& rxShape ) const = 0;
+ /** Derived classes create and return a new VBA implementation object for the passed shape.
+
+ @throws uno::RuntimeException
+ */
+ virtual rtl::Reference<ScVbaSheetObjectBase> implCreateVbaObject( const uno::Reference< drawing::XShape >& rxShape ) = 0;
+ /** Derived classes return the service name of the UNO shape. */
+ virtual OUString implGetShapeServiceName() const = 0;
+
+ /** Returns the shape name via 'Name' property of the UNO shape. May be overwritten.
+
+ @throws uno::RuntimeException
+ */
+ virtual OUString implGetShapeName( const uno::Reference< drawing::XShape >& rxShape ) const;
+ /** Is called when a new UNO shape has been created but not yet inserted into the drawing page.
+
+ @throws uno::RuntimeException
+ */
+ virtual void implOnShapeCreated( const uno::Reference< drawing::XShape >& rxShape );
+
+protected:
+ uno::Reference< XHelperInterface > mxParent;
+ uno::Reference< uno::XComponentContext > mxContext;
+ uno::Reference< frame::XModel > mxModel;
+ uno::Reference< lang::XMultiServiceFactory > mxFactory;
+ uno::Reference< drawing::XShapes > mxShapes;
+
+private:
+ typedef ::std::vector< uno::Reference< drawing::XShape > > ShapeVector;
+ const uno::Type maVbaType;
+ ShapeVector maShapes;
+};
+
+ScVbaObjectContainer::ScVbaObjectContainer(
+ const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< frame::XModel >& rxModel,
+ const uno::Reference< sheet::XSpreadsheet >& rxSheet,
+ const uno::Type& rVbaType ) :
+ mxParent( rxParent ),
+ mxContext( rxContext ),
+ mxModel( rxModel, uno::UNO_SET_THROW ),
+ mxFactory( rxModel, uno::UNO_QUERY_THROW ),
+ maVbaType( rVbaType )
+{
+ uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupp( rxSheet, uno::UNO_QUERY_THROW );
+ mxShapes.set( xDrawPageSupp->getDrawPage(), uno::UNO_QUERY_THROW );
+}
+
+void ScVbaObjectContainer::collectShapes()
+{
+ maShapes.clear();
+ for( sal_Int32 nIndex = 0, nCount = mxShapes->getCount(); nIndex < nCount; ++nIndex )
+ {
+ uno::Reference< drawing::XShape > xShape( mxShapes->getByIndex( nIndex ), uno::UNO_QUERY_THROW );
+ if( implPickShape( xShape ) )
+ maShapes.push_back( xShape );
+ }
+}
+
+uno::Reference< drawing::XShape > ScVbaObjectContainer::createShape( const awt::Point& rPos, const awt::Size& rSize )
+{
+ uno::Reference< drawing::XShape > xShape( mxFactory->createInstance( implGetShapeServiceName() ), uno::UNO_QUERY_THROW );
+ xShape->setPosition( rPos );
+ xShape->setSize( rSize );
+ implOnShapeCreated( xShape );
+ return xShape;
+}
+
+sal_Int32 ScVbaObjectContainer::insertShape( const uno::Reference< drawing::XShape >& rxShape )
+{
+ mxShapes->add( rxShape );
+ maShapes.push_back( rxShape );
+ return mxShapes->getCount() - 1;
+}
+
+::rtl::Reference< ScVbaSheetObjectBase > ScVbaObjectContainer::createVbaObject(
+ const uno::Reference< drawing::XShape >& rxShape )
+{
+ return implCreateVbaObject( rxShape );
+}
+
+uno::Any ScVbaObjectContainer::createCollectionObject( const uno::Any& rSource )
+{
+ uno::Reference< drawing::XShape > xShape( rSource, uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XSheetObject > xSheetObject( implCreateVbaObject( xShape ) );
+ return uno::Any( xSheetObject );
+}
+
+uno::Any ScVbaObjectContainer::getItemByStringIndex( const OUString& rIndex )
+{
+ auto aIt = std::find_if(maShapes.begin(), maShapes.end(),
+ [&rIndex, this](const ShapeVector::value_type& rxShape) { return rIndex == implGetShapeName( rxShape ); });
+ if (aIt != maShapes.end())
+ return createCollectionObject( uno::Any( *aIt ) );
+ throw uno::RuntimeException();
+}
+
+// XIndexAccess
+
+sal_Int32 SAL_CALL ScVbaObjectContainer::getCount()
+{
+ return static_cast< sal_Int32 >( maShapes.size() );
+}
+
+uno::Any SAL_CALL ScVbaObjectContainer::getByIndex( sal_Int32 nIndex )
+{
+ if( (0 <= nIndex) && (nIndex < getCount()) )
+ return uno::Any( maShapes[ static_cast< size_t >( nIndex ) ] );
+ throw lang::IndexOutOfBoundsException();
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScVbaObjectContainer::getElementType()
+{
+ return cppu::UnoType<drawing::XShape>::get();
+}
+
+sal_Bool SAL_CALL ScVbaObjectContainer::hasElements()
+{
+ return !maShapes.empty();
+}
+
+// private
+
+OUString ScVbaObjectContainer::implGetShapeName( const uno::Reference< drawing::XShape >& rxShape ) const
+{
+ uno::Reference< beans::XPropertySet > xPropSet( rxShape, uno::UNO_QUERY_THROW );
+ return xPropSet->getPropertyValue( "Name" ).get< OUString >();
+}
+
+void ScVbaObjectContainer::implOnShapeCreated( const uno::Reference< drawing::XShape >& /*rxShape*/ )
+{
+}
+
+namespace {
+
+class ScVbaObjectEnumeration : public SimpleEnumerationBase
+{
+public:
+ explicit ScVbaObjectEnumeration( const ScVbaObjectContainerRef& rxContainer );
+ virtual uno::Any createCollectionObject( const uno::Any& rSource ) override;
+
+private:
+ ScVbaObjectContainerRef mxContainer;
+};
+
+}
+
+ScVbaObjectEnumeration::ScVbaObjectEnumeration( const ScVbaObjectContainerRef& rxContainer ) :
+ SimpleEnumerationBase( rxContainer ),
+ mxContainer( rxContainer )
+{
+}
+
+uno::Any ScVbaObjectEnumeration::createCollectionObject( const uno::Any& rSource )
+{
+ return mxContainer->createCollectionObject( rSource );
+}
+
+ScVbaSheetObjectsBase::ScVbaSheetObjectsBase( const ScVbaObjectContainerRef& rxContainer ) :
+ ScVbaSheetObjects_BASE( rxContainer->getParent(), rxContainer->getContext(), rxContainer ),
+ mxContainer( rxContainer )
+{
+ mxContainer->collectShapes();
+}
+
+ScVbaSheetObjectsBase::~ScVbaSheetObjectsBase()
+{
+}
+
+void ScVbaSheetObjectsBase::collectShapes()
+{
+ mxContainer->collectShapes();
+}
+
+// XEnumerationAccess
+
+uno::Reference< container::XEnumeration > SAL_CALL ScVbaSheetObjectsBase::createEnumeration()
+{
+ return new ScVbaObjectEnumeration( mxContainer );
+}
+
+// XElementAccess
+
+uno::Type SAL_CALL ScVbaSheetObjectsBase::getElementType()
+{
+ return mxContainer->getVbaType();
+}
+
+// ScVbaCollectionBase
+
+uno::Any ScVbaSheetObjectsBase::createCollectionObject( const uno::Any& rSource )
+{
+ return mxContainer->createCollectionObject( rSource );
+}
+
+uno::Any ScVbaSheetObjectsBase::getItemByStringIndex( const OUString& rIndex )
+{
+ return mxContainer->getItemByStringIndex( rIndex );
+}
+
+// Graphic object containers supporting ooo.vba.excel.XGraphicObject
+
+ScVbaGraphicObjectsBase::ScVbaGraphicObjectsBase( const ScVbaObjectContainerRef& rxContainer ) :
+ ScVbaGraphicObjects_BASE( rxContainer )
+{
+}
+
+// XGraphicObjects
+
+uno::Any SAL_CALL ScVbaGraphicObjectsBase::Add( const uno::Any& rLeft, const uno::Any& rTop, const uno::Any& rWidth, const uno::Any& rHeight )
+{
+ /* Extract double values from passed Anys (the lclPointsToHmm() helper
+ function will throw a RuntimeException on any error), and convert from
+ points to 1/100 mm. */
+ awt::Point aPos( static_cast<sal_Int32>(lclPointsToHmm( rLeft )), static_cast<sal_Int32>(lclPointsToHmm( rTop )) );
+ awt::Size aSize( static_cast<sal_Int32>(lclPointsToHmm( rWidth )), static_cast<sal_Int32>(lclPointsToHmm( rHeight )) );
+ // TODO: translate coordinates for RTL sheets
+ if( (aPos.X < 0) || (aPos.Y < 0) || (aSize.Width <= 0) || (aSize.Height <= 0) )
+ throw uno::RuntimeException();
+
+ // create the UNO shape
+ uno::Reference< drawing::XShape > xShape( mxContainer->createShape( aPos, aSize ), uno::UNO_SET_THROW );
+ sal_Int32 nIndex = mxContainer->insertShape( xShape );
+
+ // create and return the VBA object
+ ::rtl::Reference< ScVbaSheetObjectBase > xVbaObject = mxContainer->createVbaObject( xShape );
+ xVbaObject->setDefaultProperties( nIndex );
+ return uno::Any( uno::Reference< excel::XSheetObject >( xVbaObject ) );
+}
+
+// Drawing controls
+
+namespace {
+
+class ScVbaControlContainer : public ScVbaObjectContainer
+{
+public:
+ /// @throws uno::RuntimeException
+ explicit ScVbaControlContainer(
+ const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< frame::XModel >& rxModel,
+ const uno::Reference< sheet::XSpreadsheet >& rxSheet,
+ const uno::Type& rVbaType,
+ const OUString& rModelServiceName,
+ sal_Int16 /* css::form::FormComponentType */ eType );
+
+protected:
+ /// @throws uno::RuntimeException
+ uno::Reference< container::XIndexContainer > const & createForm();
+
+ virtual bool implPickShape( const uno::Reference< drawing::XShape >& rxShape ) const override;
+ virtual OUString implGetShapeServiceName() const override;
+ virtual bool implCheckProperties( const uno::Reference< beans::XPropertySet >& rxModelProps ) const;
+ virtual OUString implGetShapeName( const uno::Reference< drawing::XShape >& rxShape ) const override;
+ virtual void implOnShapeCreated( const uno::Reference< drawing::XShape >& rxShape ) override;
+
+protected:
+ uno::Reference< container::XIndexContainer > mxFormIC;
+ OUString maModelServiceName;
+ sal_Int16 /* css::form::FormComponentType */ meType;
+};
+
+}
+
+ScVbaControlContainer::ScVbaControlContainer(
+ const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< frame::XModel >& rxModel,
+ const uno::Reference< sheet::XSpreadsheet >& rxSheet,
+ const uno::Type& rVbaType,
+ const OUString& rModelServiceName,
+ sal_Int16 /* css::form::FormComponentType */ eType ) :
+ ScVbaObjectContainer( rxParent, rxContext, rxModel, rxSheet, rVbaType ),
+ maModelServiceName( rModelServiceName ),
+ meType( eType )
+{
+}
+
+uno::Reference< container::XIndexContainer > const & ScVbaControlContainer::createForm()
+{
+ if( !mxFormIC.is() )
+ {
+ uno::Reference< form::XFormsSupplier > xFormsSupp( mxShapes, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameContainer > xFormsNC( xFormsSupp->getForms(), uno::UNO_SET_THROW );
+ OUString aFormName = "Standard";
+ if( xFormsNC->hasByName( aFormName ) )
+ {
+ mxFormIC.set( xFormsNC->getByName( aFormName ), uno::UNO_QUERY_THROW );
+ }
+ else
+ {
+ uno::Reference< form::XForm > xForm( mxFactory->createInstance( "com.sun.star.form.component.Form" ), uno::UNO_QUERY_THROW );
+ xFormsNC->insertByName( aFormName, uno::Any( xForm ) );
+ mxFormIC.set( xForm, uno::UNO_QUERY_THROW );
+ }
+ }
+ return mxFormIC;
+}
+
+bool ScVbaControlContainer::implPickShape( const uno::Reference< drawing::XShape >& rxShape ) const
+{
+ try
+ {
+ uno::Reference< drawing::XControlShape > xControlShape( rxShape, uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xModelProps( xControlShape->getControl(), uno::UNO_QUERY_THROW );
+ sal_Int16 nClassId = -1;
+ return lclGetProperty( nClassId, xModelProps, "ClassId" ) &&
+ (nClassId == meType) && implCheckProperties( xModelProps );
+ }
+ catch( uno::Exception& )
+ {
+ }
+ return false;
+}
+
+OUString ScVbaControlContainer::implGetShapeServiceName() const
+{
+ return "com.sun.star.drawing.ControlShape";
+}
+
+bool ScVbaControlContainer::implCheckProperties( const uno::Reference< beans::XPropertySet >& /*rxModelProps*/ ) const
+{
+ return true;
+}
+
+OUString ScVbaControlContainer::implGetShapeName( const uno::Reference< drawing::XShape >& rxShape ) const
+{
+ uno::Reference< drawing::XControlShape > xControlShape( rxShape, uno::UNO_QUERY_THROW );
+ return uno::Reference< container::XNamed >( xControlShape->getControl(), uno::UNO_QUERY_THROW )->getName();
+}
+
+void ScVbaControlContainer::implOnShapeCreated( const uno::Reference< drawing::XShape >& rxShape )
+{
+ // passed shape must be a control shape
+ uno::Reference< drawing::XControlShape > xControlShape( rxShape, uno::UNO_QUERY_THROW );
+
+ // create the UNO control model
+ uno::Reference< form::XFormComponent > xFormComponent( mxFactory->createInstance( maModelServiceName ), uno::UNO_QUERY_THROW );
+ uno::Reference< awt::XControlModel > xControlModel( xFormComponent, uno::UNO_QUERY_THROW );
+
+ // insert the control model into the form and the shape
+ createForm();
+ mxFormIC->insertByIndex( mxFormIC->getCount(), uno::Any( xFormComponent ) );
+ xControlShape->setControl( xControlModel );
+}
+
+// Push button
+
+namespace {
+
+class ScVbaButtonContainer : public ScVbaControlContainer
+{
+ bool mbOptionButtons;
+public:
+ /// @throws uno::RuntimeException
+ explicit ScVbaButtonContainer(
+ const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< frame::XModel >& rxModel,
+ const uno::Reference< sheet::XSpreadsheet >& rxSheet,
+ bool bOptionButtons);
+
+protected:
+ virtual rtl::Reference<ScVbaSheetObjectBase> implCreateVbaObject( const uno::Reference< drawing::XShape >& rxShape ) override;
+ virtual bool implCheckProperties( const uno::Reference< beans::XPropertySet >& rxModelProps ) const override;
+};
+
+}
+
+ScVbaButtonContainer::ScVbaButtonContainer(
+ const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< frame::XModel >& rxModel,
+ const uno::Reference< sheet::XSpreadsheet >& rxSheet,
+ bool bOptionButtons ) :
+ ScVbaControlContainer(
+ rxParent, rxContext, rxModel, rxSheet,
+ cppu::UnoType<excel::XButton>::get(),
+ ( bOptionButtons ?
+ OUString( "com.sun.star.form.component.RadioButton" ) :
+ OUString( "com.sun.star.form.component.CommandButton" ) ),
+ ( bOptionButtons ?
+ form::FormComponentType::RADIOBUTTON :
+ form::FormComponentType::COMMANDBUTTON) ),
+ mbOptionButtons(bOptionButtons)
+{
+}
+
+rtl::Reference<ScVbaSheetObjectBase> ScVbaButtonContainer::implCreateVbaObject( const uno::Reference< drawing::XShape >& rxShape )
+{
+ uno::Reference< drawing::XControlShape > xControlShape( rxShape, uno::UNO_QUERY_THROW );
+ return new ScVbaButton( mxParent, mxContext, mxModel, createForm(), xControlShape );
+}
+
+bool ScVbaButtonContainer::implCheckProperties( const uno::Reference< beans::XPropertySet >& rxModelProps ) const
+{
+ if (mbOptionButtons)
+ return true;
+
+ // do not insert toggle buttons into the 'Buttons' collection
+ bool bToggle = false;
+ return lclGetProperty( bToggle, rxModelProps, "Toggle" ) && !bToggle;
+}
+
+ScVbaButtons::ScVbaButtons(
+ const uno::Reference< XHelperInterface >& rxParent,
+ const uno::Reference< uno::XComponentContext >& rxContext,
+ const uno::Reference< frame::XModel >& rxModel,
+ const uno::Reference< sheet::XSpreadsheet >& rxSheet,
+ bool bOptionButtons) :
+ ScVbaGraphicObjectsBase( new ScVbaButtonContainer( rxParent, rxContext, rxModel, rxSheet, bOptionButtons ) )
+{
+}
+
+VBAHELPER_IMPL_XHELPERINTERFACE( ScVbaButtons, "ooo.vba.excel.Buttons" )
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbasheetobjects.hxx b/sc/source/ui/vba/vbasheetobjects.hxx
new file mode 100644
index 000000000..38d2d1c8d
--- /dev/null
+++ b/sc/source/ui/vba/vbasheetobjects.hxx
@@ -0,0 +1,102 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+#include <ooo/vba/excel/XGraphicObjects.hpp>
+#include <vbahelper/vbacollectionimpl.hxx>
+#include <rtl/ref.hxx>
+
+namespace com::sun::star {
+ namespace container { class XEnumeration; }
+ namespace frame { class XModel; }
+ namespace sheet { class XSpreadsheet; }
+}
+
+class ScVbaObjectContainer;
+typedef ::rtl::Reference< ScVbaObjectContainer > ScVbaObjectContainerRef;
+
+typedef CollTestImplHelper< ov::XCollection > ScVbaSheetObjects_BASE;
+
+/** Base class for collections containing a specific type of drawing object
+ embedded in a sheet (worksheet, chart sheet, or dialog sheet).
+ */
+class ScVbaSheetObjectsBase : public ScVbaSheetObjects_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ explicit ScVbaSheetObjectsBase( const ScVbaObjectContainerRef& rxContainer );
+ virtual ~ScVbaSheetObjectsBase() override;
+
+ /** Updates the collection by fetching all shapes from the draw page.
+
+ @throws css::uno::RuntimeException
+ */
+ void collectShapes();
+
+ // XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+
+ // ScVbaCollectionBase
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& rSource ) override;
+ virtual css::uno::Any getItemByStringIndex( const OUString& rIndex ) override;
+
+protected:
+ ScVbaObjectContainerRef mxContainer;
+};
+
+typedef ::cppu::ImplInheritanceHelper< ScVbaSheetObjectsBase, ov::excel::XGraphicObjects > ScVbaGraphicObjects_BASE;
+
+/** Base class for collections containing a specific type of graphic object
+ from a sheet.
+ */
+class ScVbaGraphicObjectsBase : public ScVbaGraphicObjects_BASE
+{
+public:
+ /// @throws css::uno::RuntimeException
+ explicit ScVbaGraphicObjectsBase( const ScVbaObjectContainerRef& rxContainer );
+
+ // XGraphicObjects
+ virtual css::uno::Any SAL_CALL Add(
+ const css::uno::Any& rLeft,
+ const css::uno::Any& rTop,
+ const css::uno::Any& rWidth,
+ const css::uno::Any& rHeight ) override;
+};
+
+/** Collection containing all button controls from a sheet (not ActiveX controls). */
+class ScVbaButtons : public ScVbaGraphicObjectsBase
+{
+public:
+ /// @throws css::uno::RuntimeException
+ explicit ScVbaButtons(
+ const css::uno::Reference< ov::XHelperInterface >& rxParent,
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const css::uno::Reference< css::frame::XModel >& rxModel,
+ const css::uno::Reference< css::sheet::XSpreadsheet >& rxSheet,
+ bool bOptionButtons);
+
+ VBAHELPER_DECL_XHELPERINTERFACE
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbastyle.cxx b/sc/source/ui/vba/vbastyle.cxx
new file mode 100644
index 000000000..ae393804d
--- /dev/null
+++ b/sc/source/ui/vba/vbastyle.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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "vbastyle.hxx"
+#include <basic/sberrors.hxx>
+#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+constexpr OUStringLiteral DISPLAYNAME = u"DisplayName";
+
+uno::Reference< container::XNameAccess >
+ScVbaStyle::getStylesNameContainer( const uno::Reference< frame::XModel >& xModel )
+{
+ uno::Reference< style::XStyleFamiliesSupplier > xStyleSupplier( xModel, uno::UNO_QUERY_THROW);
+ uno::Reference< container::XNameAccess > xStylesAccess( xStyleSupplier->getStyleFamilies()->getByName("CellStyles"), uno::UNO_QUERY_THROW );
+ return xStylesAccess;
+}
+
+/// @throws script::BasicErrorException
+/// @throws uno::RuntimeException
+static uno::Reference< beans::XPropertySet >
+lcl_getStyleProps( const OUString& sStyleName, const uno::Reference< frame::XModel >& xModel )
+{
+
+ uno::Reference< beans::XPropertySet > xStyleProps( ScVbaStyle::getStylesNameContainer( xModel )->getByName( sStyleName ), uno::UNO_QUERY_THROW );
+ return xStyleProps;
+}
+
+void ScVbaStyle::initialise()
+{
+ if (!mxModel.is() )
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, u"XModel Interface could not be retrieved" );
+ uno::Reference< lang::XServiceInfo > xServiceInfo( mxPropertySet, uno::UNO_QUERY_THROW );
+ if ( !xServiceInfo->supportsService("com.sun.star.style.CellStyle") )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+ mxStyle.set( mxPropertySet, uno::UNO_QUERY_THROW );
+
+ uno::Reference< style::XStyleFamiliesSupplier > xStyleSupplier( mxModel, uno::UNO_QUERY_THROW );
+ mxStyleFamilyNameContainer.set( ScVbaStyle::getStylesNameContainer( mxModel ), uno::UNO_QUERY_THROW );
+
+}
+
+ScVbaStyle::ScVbaStyle( const uno::Reference< ov::XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext > & xContext,
+ const OUString& sStyleName, const uno::Reference< frame::XModel >& _xModel )
+ : ScVbaStyle_BASE( xParent, xContext, lcl_getStyleProps( sStyleName, _xModel ), _xModel, false )
+{
+ try
+ {
+ initialise();
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+ScVbaStyle::ScVbaStyle( const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext > & xContext,
+ const uno::Reference< beans::XPropertySet >& _xPropertySet,
+ const uno::Reference< frame::XModel >& _xModel )
+ : ScVbaStyle_BASE( xParent, xContext, _xPropertySet, _xModel, false )
+{
+ try
+ {
+ initialise();
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+sal_Bool SAL_CALL
+ScVbaStyle::BuiltIn()
+{
+ return !mxStyle->isUserDefined();
+
+}
+void SAL_CALL
+ScVbaStyle::setName( const OUString& Name )
+{
+ mxStyle->setName(Name);
+}
+
+OUString SAL_CALL
+ScVbaStyle::getName()
+{
+ return mxStyle->getName();
+}
+
+void SAL_CALL
+ScVbaStyle::setNameLocal( const OUString& NameLocal )
+{
+ try
+ {
+ mxPropertySet->setPropertyValue(DISPLAYNAME, uno::Any( NameLocal ) );
+ }
+ catch (const uno::Exception& e)
+ {
+ DebugHelper::basicexception(e);
+ }
+}
+
+OUString SAL_CALL
+ScVbaStyle::getNameLocal()
+{
+ OUString sName;
+ try
+ {
+ mxPropertySet->getPropertyValue(DISPLAYNAME) >>= sName;
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {} );
+ }
+ return sName;
+}
+
+void SAL_CALL
+ScVbaStyle::Delete()
+{
+ try
+ {
+ mxStyleFamilyNameContainer->removeByName(mxStyle->getName());
+ }
+ catch (const uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+void SAL_CALL
+ScVbaStyle::setMergeCells( const uno::Any& /*MergeCells*/ )
+{
+ DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {});
+}
+
+uno::Any SAL_CALL
+ScVbaStyle::getMergeCells( )
+{
+ DebugHelper::basicexception(ERRCODE_BASIC_NOT_IMPLEMENTED, {});
+ return uno::Any();
+}
+
+OUString
+ScVbaStyle::getServiceImplName()
+{
+ return "ScVbaStyle";
+}
+
+uno::Sequence< OUString >
+ScVbaStyle::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.XStyle"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbastyle.hxx b/sc/source/ui/vba/vbastyle.hxx
new file mode 100644
index 000000000..cc002ce6f
--- /dev/null
+++ b/sc/source/ui/vba/vbastyle.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 <ooo/vba/excel/XStyle.hpp>
+#include <com/sun/star/style/XStyle.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include "vbaformat.hxx"
+
+typedef ScVbaFormat< ov::excel::XStyle > ScVbaStyle_BASE;
+
+class ScVbaStyle final : public ScVbaStyle_BASE
+{
+ css::uno::Reference< css::style::XStyle > mxStyle;
+ css::uno::Reference< css::container::XNameContainer > mxStyleFamilyNameContainer;
+ /// @throws css::uno::RuntimeException
+ /// @throws css::script::BasicErrorException
+ void initialise();
+public:
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ ScVbaStyle( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const OUString& sStyleName, const css::uno::Reference< css::frame::XModel >& _xModel );
+ /// @throws css::script::BasicErrorException
+ /// @throws css::uno::RuntimeException
+ ScVbaStyle( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::beans::XPropertySet >& _xPropertySet, const css::uno::Reference< css::frame::XModel >& _xModel );
+ /// @throws css::uno::RuntimeException
+ static css::uno::Reference< css::container::XNameAccess > getStylesNameContainer( const css::uno::Reference< css::frame::XModel >& xModel );
+ virtual css::uno::Reference< ov::XHelperInterface > thisHelperIface() override { return this; };
+ // XStyle Methods
+ virtual sal_Bool SAL_CALL BuiltIn() override;
+ virtual void SAL_CALL setName( const OUString& Name ) override;
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setNameLocal( const OUString& NameLocal ) override;
+ virtual OUString SAL_CALL getNameLocal() override;
+ virtual void SAL_CALL Delete() override;
+ // XFormat
+ virtual void SAL_CALL setMergeCells( const css::uno::Any& MergeCells ) override;
+ virtual css::uno::Any SAL_CALL getMergeCells( ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbastyles.cxx b/sc/source/ui/vba/vbastyles.cxx
new file mode 100644
index 000000000..c21adf064
--- /dev/null
+++ b/sc/source/ui/vba/vbastyles.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 "vbastyles.hxx"
+#include "vbastyle.hxx"
+#include <basic/sberrors.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <ooo/vba/excel/XRange.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+static css::uno::Any
+lcl_createAPIStyleToVBAObject( const css::uno::Any& aObject, const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< frame::XModel >& xModel )
+{
+ uno::Reference< beans::XPropertySet > xStyleProps( aObject, uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XStyle > xStyle( new ScVbaStyle( xParent, xContext, xStyleProps, xModel ) );
+ return uno::Any( xStyle );
+}
+
+ScVbaStyles::ScVbaStyles( const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< css::uno::XComponentContext > & xContext,
+ const uno::Reference< frame::XModel >& xModel )
+: ScVbaStyles_BASE( xParent,
+ xContext,
+ uno::Reference< container::XIndexAccess >( ScVbaStyle::getStylesNameContainer( xModel ), uno::UNO_QUERY_THROW ) ),
+ mxModel( xModel )
+{
+ try
+ {
+ mxMSF.set( mxModel, uno::UNO_QUERY_THROW );
+ mxNameContainerCellStyles.set( m_xNameAccess, uno::UNO_QUERY_THROW );
+ }
+ catch (uno::Exception& )
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+uno::Sequence< OUString >
+ScVbaStyles::getStyleNames()
+{
+ return mxNameContainerCellStyles->getElementNames();
+}
+
+uno::Any
+ScVbaStyles::createCollectionObject(const uno::Any& aObject)
+{
+ return lcl_createAPIStyleToVBAObject( aObject, mxParent, mxContext, mxModel );
+}
+
+uno::Type SAL_CALL
+ScVbaStyles::getElementType()
+{
+ return cppu::UnoType<excel::XStyle>::get();
+}
+
+namespace {
+
+class EnumWrapper : public EnumerationHelper_BASE
+{
+ uno::Reference<container::XIndexAccess > m_xIndexAccess;
+ uno::Reference<XHelperInterface > m_xParent;
+ uno::Reference<uno::XComponentContext > m_xContext;
+ uno::Reference<frame::XModel > m_xModel;
+
+ sal_Int32 nIndex;
+public:
+ EnumWrapper( const uno::Reference< container::XIndexAccess >& xIndexAccess, const uno::Reference<XHelperInterface >& xParent, const uno::Reference<uno::XComponentContext >& xContext, const uno::Reference<frame::XModel >& xModel ) : m_xIndexAccess( xIndexAccess ), m_xParent( xParent ), m_xContext( xContext ), m_xModel( xModel ), nIndex( 0 ) {}
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override
+ {
+ return ( nIndex < m_xIndexAccess->getCount() );
+ }
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ try
+ {
+ if ( nIndex < m_xIndexAccess->getCount() )
+ return lcl_createAPIStyleToVBAObject( m_xIndexAccess->getByIndex( nIndex++ ), m_xParent, m_xContext, m_xModel );
+ }
+ catch (const container::NoSuchElementException&)
+ {
+ throw;
+ }
+ catch (const lang::WrappedTargetException&)
+ {
+ throw;
+ }
+ catch (const uno::RuntimeException&)
+ {
+ throw;
+ }
+ catch (const uno::Exception& e)
+ {
+ css::uno::Any a(cppu::getCaughtException());
+ throw css::lang::WrappedTargetException(
+ "wrapped Exception " + e.Message,
+ css::uno::Reference<css::uno::XInterface>(), a);
+ }
+ throw container::NoSuchElementException();
+ }
+};
+
+}
+
+uno::Reference< container::XEnumeration > SAL_CALL
+ScVbaStyles::createEnumeration()
+{
+ return new EnumWrapper( m_xIndexAccess, mxParent, mxContext, mxModel );
+}
+
+uno::Reference< excel::XStyle > SAL_CALL
+ScVbaStyles::Add( const OUString& _sName, const uno::Any& _aBasedOn )
+{
+ uno::Reference< excel::XStyle > aRet;
+ try
+ {
+ OUString sParentCellStyleName("Default");
+ if ( _aBasedOn.hasValue() )
+ {
+ uno::Reference< excel::XRange > oRange;
+ if ( _aBasedOn >>= oRange)
+ {
+ uno::Reference< excel::XStyle > oStyle( oRange->getStyle(), uno::UNO_QUERY_THROW );
+ sParentCellStyleName = oStyle->getName();
+ }
+ else
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_BAD_ARGUMENT, {});
+ }
+ }
+
+ uno::Reference< style::XStyle > xStyle( mxMSF->createInstance("com.sun.star.style.CellStyle"), uno::UNO_QUERY_THROW );
+
+ if (!mxNameContainerCellStyles->hasByName(_sName))
+ {
+ mxNameContainerCellStyles->insertByName(_sName, uno::Any( xStyle) );
+ }
+ if (sParentCellStyleName != "Default")
+ {
+ xStyle->setParentStyle( sParentCellStyleName );
+ }
+ aRet.set( Item( uno::Any( _sName ), uno::Any() ), uno::UNO_QUERY_THROW );
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+ return aRet;
+}
+
+void
+ScVbaStyles::Delete(const OUString& _sStyleName)
+{
+ try
+ {
+ if (mxNameContainerCellStyles->hasByName( _sStyleName ) )
+ mxNameContainerCellStyles->removeByName( _sStyleName );
+ }
+ catch (const uno::Exception&)
+ {
+ DebugHelper::basicexception(ERRCODE_BASIC_METHOD_FAILED, {});
+ }
+}
+
+OUString
+ScVbaStyles::getServiceImplName()
+{
+ return "ScVbaStyles";
+}
+
+uno::Sequence< OUString >
+ScVbaStyles::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.XStyles"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbastyles.hxx b/sc/source/ui/vba/vbastyles.hxx
new file mode 100644
index 000000000..78990bca9
--- /dev/null
+++ b/sc/source/ui/vba/vbastyles.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 <ooo/vba/excel/XStyles.hpp>
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace com::sun::star::lang { class XMultiServiceFactory; }
+namespace com::sun::star::container { class XNameContainer; }
+
+typedef CollTestImplHelper< ov::excel::XStyles > ScVbaStyles_BASE;
+class ScVbaStyles: public ScVbaStyles_BASE
+{
+ css::uno::Reference< css::frame::XModel > mxModel;
+ css::uno::Reference< css::lang::XMultiServiceFactory > mxMSF;
+ css::uno::Reference< css::container::XNameContainer > mxNameContainerCellStyles;
+public:
+ /// @throws css::script::BasicErrorException
+ ScVbaStyles( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::frame::XModel >& xModel );
+ /// @throws css::uno::RuntimeException
+ css::uno::Sequence< OUString > getStyleNames();
+ /// @throws css::script::BasicErrorException
+ void Delete(const OUString& _sStyleName);
+ // XStyles
+ virtual css::uno::Reference< ov::excel::XStyle > SAL_CALL Add( const OUString& Name, const css::uno::Any& BasedOn ) override;
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+ virtual css::uno::Any createCollectionObject(const css::uno::Any&) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbatextboxshape.cxx b/sc/source/ui/vba/vbatextboxshape.cxx
new file mode 100644
index 000000000..66a85e49e
--- /dev/null
+++ b/sc/source/ui/vba/vbatextboxshape.cxx
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "excelvbahelper.hxx"
+#include "vbatextboxshape.hxx"
+#include "vbacharacters.hxx"
+#include <com/sun/star/text/XSimpleText.hpp>
+#include <docsh.hxx>
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+ScVbaTextBoxShape::ScVbaTextBoxShape( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< drawing::XShape >& xShape, const uno::Reference< drawing::XShapes >& xShapes, const uno::Reference< frame::XModel >& xModel ) : TextBoxShapeImpl_BASE( uno::Reference< XHelperInterface >(), xContext, xShape, xShapes, xModel, ScVbaShape::getType( xShape ) )
+{
+ m_xTextRange.set( xShape , uno::UNO_QUERY_THROW );
+}
+
+OUString SAL_CALL
+ScVbaTextBoxShape::getText()
+{
+ return m_xTextRange->getString();
+}
+
+void SAL_CALL
+ScVbaTextBoxShape::setText( const OUString& _text )
+{
+ m_xTextRange->setString( _text );
+}
+
+uno::Reference< excel::XCharacters > SAL_CALL
+ScVbaTextBoxShape::characters( const uno::Any& Start, const uno::Any& Length )
+{
+ ScDocShell* pDocShell = excel::getDocShell( m_xModel );
+ ScDocument* pDoc = pDocShell ? &pDocShell->GetDocument() : nullptr;
+
+ if ( !pDoc )
+ throw uno::RuntimeException("Failed to access document from shell" );
+ uno::Reference< text::XSimpleText > xSimple( m_xTextRange, uno::UNO_QUERY_THROW );
+
+ ScVbaPalette aPalette( pDoc->GetDocumentShell() );
+ return new ScVbaCharacters( this, mxContext, aPalette, xSimple, Start, Length, true );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbatextboxshape.hxx b/sc/source/ui/vba/vbatextboxshape.hxx
new file mode 100644
index 000000000..c97fca8d8
--- /dev/null
+++ b/sc/source/ui/vba/vbatextboxshape.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 <cppuhelper/implbase.hxx>
+#include <com/sun/star/text/XTextRange.hpp>
+#include <ooo/vba/msforms/XTextBoxShape.hpp>
+#include <vbahelper/vbashape.hxx>
+
+typedef cppu::ImplInheritanceHelper< ScVbaShape, ov::msforms::XTextBoxShape > TextBoxShapeImpl_BASE;
+
+class ScVbaTextBoxShape : public TextBoxShapeImpl_BASE
+{
+ css::uno::Reference< css::text::XTextRange > m_xTextRange;
+public:
+ ScVbaTextBoxShape( const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::drawing::XShape >& xShape, const css::uno::Reference< css::drawing::XShapes >& xShapes, const css::uno::Reference< css::frame::XModel >& xModel );
+
+ // Attributes
+ virtual OUString SAL_CALL getText() override;
+ virtual void SAL_CALL setText( const OUString& _text ) override;
+ virtual css::uno::Reference< ov::excel::XCharacters > SAL_CALL characters( const css::uno::Any& Start, const css::uno::Any& Length ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbatextframe.cxx b/sc/source/ui/vba/vbatextframe.cxx
new file mode 100644
index 000000000..9f921a8fa
--- /dev/null
+++ b/sc/source/ui/vba/vbatextframe.cxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/drawing/XShape.hpp>
+#include <sfx2/objsh.hxx>
+#include "vbatextframe.hxx"
+#include "vbacharacters.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+ScVbaTextFrame::ScVbaTextFrame( uno::Sequence< uno::Any> const & args, uno::Reference< uno::XComponentContext> const & xContext ) : ScVbaTextFrame_BASE( getXSomethingFromArgs< XHelperInterface >( args, 0 ), xContext, getXSomethingFromArgs< drawing::XShape >( args, 1, false ) )
+{
+}
+
+// Methods
+uno::Any SAL_CALL
+ScVbaTextFrame::Characters()
+{
+ uno::Reference< text::XSimpleText > xSimpleText( m_xShape, uno::UNO_QUERY_THROW );
+ ScVbaPalette aPalette( SfxObjectShell::Current() );
+ uno::Any aStart( sal_Int32( 1 ) );
+ uno::Any aLength(sal_Int32( -1 ) );
+ return uno::Any( uno::Reference< ov::excel::XCharacters >( new ScVbaCharacters( this, mxContext, aPalette, xSimpleText, aStart, aLength, true ) ) );
+}
+
+OUString
+ScVbaTextFrame::getServiceImplName()
+{
+ return "ScVbaTextFrame";
+}
+
+uno::Sequence< OUString >
+ScVbaTextFrame::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.TextFrame"
+ };
+ return aServiceNames;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+ScVbaTextFrame_get_implementation(
+ css::uno::XComponentContext *context,
+ css::uno::Sequence<css::uno::Any> const &arguments)
+{
+ return cppu::acquire(new ScVbaTextFrame(arguments, context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbatextframe.hxx b/sc/source/ui/vba/vbatextframe.hxx
new file mode 100644
index 000000000..eb7a59a93
--- /dev/null
+++ b/sc/source/ui/vba/vbatextframe.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 <cppuhelper/implbase.hxx>
+#include <ooo/vba/excel/XTextFrame.hpp>
+#include <vbahelper/vbatextframe.hxx>
+
+//typedef InheritedHelperInterfaceWeakImpl< ov::excel::XTextFrame > ScVbaTextFrame_BASE;
+typedef cppu::ImplInheritanceHelper<VbaTextFrame, ov::excel::XTextFrame> ScVbaTextFrame_BASE;
+
+class ScVbaTextFrame : public ScVbaTextFrame_BASE
+{
+public:
+ /// @throws css::lang::IllegalArgumentException
+ ScVbaTextFrame(css::uno::Sequence<css::uno::Any> const& aArgs,
+ css::uno::Reference<css::uno::XComponentContext> const& xContext);
+ // Methods
+ virtual css::uno::Any SAL_CALL Characters() override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbatitle.hxx b/sc/source/ui/vba/vbatitle.hxx
new file mode 100644
index 000000000..550be0060
--- /dev/null
+++ b/sc/source/ui/vba/vbatitle.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 <vbahelper/vbahelperinterface.hxx>
+#include "vbainterior.hxx"
+#include "vbafont.hxx"
+#include "vbapalette.hxx"
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <com/sun/star/script/BasicErrorException.hpp>
+#include <basic/sberrors.hxx>
+#include <memory>
+
+template< typename... Ifc >
+class TitleImpl : public InheritedHelperInterfaceImpl< Ifc... >
+{
+typedef InheritedHelperInterfaceImpl< Ifc... > BaseClass;
+
+ css::uno::Reference< css::drawing::XShape > xTitleShape;
+ css::uno::Reference< css::beans::XPropertySet > xShapePropertySet;
+ std::unique_ptr<ov::ShapeHelper> oShapeHelper;
+ ScVbaPalette m_Palette;
+public:
+ TitleImpl( const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::drawing::XShape >& _xTitleShape )
+ : BaseClass( xParent, xContext ), xTitleShape( _xTitleShape ), m_Palette(nullptr)
+ {
+ xShapePropertySet.set( xTitleShape, css::uno::UNO_QUERY_THROW );
+ oShapeHelper.reset( new ov::ShapeHelper(xTitleShape) );
+ }
+ css::uno::Reference< ov::excel::XInterior > SAL_CALL Interior( ) override
+ {
+ // #TODO find out what the proper parent should be
+ // leaving as set by the helperapi for the moment
+ // #TODO we really need the ScDocument to pass to ScVbaInterior
+ // otherwise attempts to access the palette will fail
+ return new ScVbaInterior( BaseClass::mxParent, BaseClass::mxContext, xShapePropertySet );
+ }
+ css::uno::Reference< ov::excel::XFont > SAL_CALL Font( ) override
+ {
+ // #TODO find out what the proper parent should be
+ // leaving as set by the helperapi for the moment
+ return new ScVbaFont( BaseClass::mxParent, BaseClass::mxContext, m_Palette, xShapePropertySet );
+
+ }
+ void SAL_CALL setText( const OUString& Text ) override
+ {
+ try
+ {
+ xShapePropertySet->setPropertyValue("String", css::uno::Any( Text ));
+ }
+ catch ( css::uno::Exception& )
+ {
+ throw css::script::BasicErrorException( OUString(), css::uno::Reference< css::uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+ }
+ OUString SAL_CALL getText( ) override
+ {
+ OUString sText;
+ try
+ {
+ xShapePropertySet->getPropertyValue("String") >>= sText;
+ }
+ catch ( css::uno::Exception& )
+ {
+ throw css::script::BasicErrorException( OUString(), css::uno::Reference< css::uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+ return sText;
+ }
+
+ void SAL_CALL setTop( double Top ) override
+ {
+ oShapeHelper->setTop( Top );
+ }
+ double SAL_CALL getTop( ) override
+ {
+ return oShapeHelper->getTop();
+ }
+ void SAL_CALL setLeft( double Left ) override
+ {
+ oShapeHelper->setLeft( Left );
+ }
+ double SAL_CALL getLeft( ) override
+ {
+ return oShapeHelper->getLeft();
+ }
+ void SAL_CALL setOrientation( ::sal_Int32 _nOrientation ) override
+ {
+ try
+ {
+ xShapePropertySet->setPropertyValue("TextRotation", css::uno::Any(_nOrientation*100));
+ }
+ catch (css::uno::Exception& )
+ {
+ throw css::script::BasicErrorException( OUString(), css::uno::Reference< css::uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+ }
+ ::sal_Int32 SAL_CALL getOrientation( ) override
+ {
+ sal_Int32 nSOOrientation = 0;
+ try
+ {
+ xShapePropertySet->getPropertyValue("TextRotation") >>= nSOOrientation;
+ }
+ catch (css::uno::Exception& )
+ {
+ throw css::script::BasicErrorException( OUString(), css::uno::Reference< css::uno::XInterface >(), sal_uInt32(ERRCODE_BASIC_METHOD_FAILED), OUString() );
+ }
+ return static_cast< sal_Int32 >(nSOOrientation / 100) ;
+ }
+// XHelperInterface
+ OUString getServiceImplName() override
+ {
+ return "TitleImpl";
+ }
+ css::uno::Sequence< OUString > getServiceNames() override
+ {
+ static const css::uno::Sequence< OUString > aServiceNames{ "ooo.vba.excel.XTitle" };
+ return aServiceNames;
+ }
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbavalidation.cxx b/sc/source/ui/vba/vbavalidation.cxx
new file mode 100644
index 000000000..a30b43fe7
--- /dev/null
+++ b/sc/source/ui/vba/vbavalidation.cxx
@@ -0,0 +1,382 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "vbavalidation.hxx"
+#include "vbaformatcondition.hxx"
+#include <com/sun/star/sheet/XSheetCondition.hpp>
+#include <com/sun/star/sheet/ValidationType.hpp>
+#include <com/sun/star/sheet/ValidationAlertStyle.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <ooo/vba/excel/XlDVType.hpp>
+#include <ooo/vba/excel/XlDVAlertStyle.hpp>
+
+#include <unonames.hxx>
+#include <rangelst.hxx>
+#include "excelvbahelper.hxx"
+#include "vbarange.hxx"
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+static void
+lcl_setValidationProps( const uno::Reference< table::XCellRange >& xRange, const uno::Reference< beans::XPropertySet >& xProps )
+{
+ uno::Reference< beans::XPropertySet > xRangeProps( xRange, uno::UNO_QUERY_THROW );
+ xRangeProps->setPropertyValue( SC_UNONAME_VALIDAT , uno::Any( xProps ) );
+}
+
+static uno::Reference< beans::XPropertySet >
+lcl_getValidationProps( const uno::Reference< table::XCellRange >& xRange )
+{
+ uno::Reference< beans::XPropertySet > xProps( xRange, uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xValProps;
+ xValProps.set( xProps->getPropertyValue( SC_UNONAME_VALIDAT ), uno::UNO_QUERY_THROW );
+ return xValProps;
+}
+
+sal_Bool SAL_CALL
+ScVbaValidation::getIgnoreBlank()
+{
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) );
+ bool bBlank = false;
+ xProps->getPropertyValue( SC_UNONAME_IGNOREBL ) >>= bBlank;
+ return bBlank;
+}
+
+void SAL_CALL
+ScVbaValidation::setIgnoreBlank( sal_Bool _ignoreblank )
+{
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) );
+ xProps->setPropertyValue( SC_UNONAME_IGNOREBL, uno::Any( _ignoreblank ) );
+ lcl_setValidationProps( m_xRange, xProps );
+}
+
+sal_Bool SAL_CALL
+ScVbaValidation::getInCellDropdown()
+{
+ uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange );
+ sal_Int32 nShowList = 0;
+ xProps->getPropertyValue( SC_UNONAME_SHOWLIST ) >>= nShowList;
+ return nShowList != 0;
+}
+
+void SAL_CALL
+ScVbaValidation::setInCellDropdown( sal_Bool _incelldropdown )
+{
+ sal_Int32 nDropDown = 0;
+ if ( _incelldropdown )
+ nDropDown = 1;
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps(m_xRange) );
+ xProps->setPropertyValue( SC_UNONAME_SHOWLIST, uno::Any( nDropDown ) );
+ lcl_setValidationProps( m_xRange, xProps );
+}
+
+sal_Bool SAL_CALL
+ScVbaValidation::getShowInput()
+{
+ uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange );
+ bool bShowInput = false;
+ xProps->getPropertyValue( SC_UNONAME_SHOWINP ) >>= bShowInput;
+ return bShowInput;
+}
+
+void SAL_CALL
+ScVbaValidation:: setShowInput( sal_Bool _showinput )
+{
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps(m_xRange) );
+ xProps->setPropertyValue( SC_UNONAME_IGNOREBL, uno::Any( _showinput ) );
+ lcl_setValidationProps( m_xRange, xProps );
+}
+
+sal_Bool SAL_CALL
+ScVbaValidation::getShowError()
+{
+ uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange );
+ bool bShowError = false;
+ xProps->getPropertyValue( SC_UNONAME_SHOWERR ) >>= bShowError;
+ return bShowError;
+}
+
+void SAL_CALL
+ScVbaValidation::setShowError( sal_Bool _showerror )
+{
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) );
+ xProps->setPropertyValue( SC_UNONAME_SHOWERR, uno::Any( _showerror ) );
+ lcl_setValidationProps( m_xRange, xProps );
+}
+
+OUString SAL_CALL
+ScVbaValidation::getErrorTitle()
+{
+ uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange );
+ OUString sErrorTitle;
+ xProps->getPropertyValue( SC_UNONAME_ERRTITLE ) >>= sErrorTitle;
+ return sErrorTitle;
+}
+
+void
+ScVbaValidation::setErrorTitle( const OUString& _errormessage )
+{
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) );
+ xProps->setPropertyValue( SC_UNONAME_ERRTITLE, uno::Any( _errormessage ) );
+ lcl_setValidationProps( m_xRange, xProps );
+}
+
+OUString SAL_CALL
+ScVbaValidation::getInputMessage()
+{
+ uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange );
+ OUString sMsg;
+ xProps->getPropertyValue( SC_UNONAME_INPMESS ) >>= sMsg;
+ return sMsg;
+}
+
+void SAL_CALL
+ScVbaValidation::setInputMessage( const OUString& _inputmessage )
+{
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) );
+ xProps->setPropertyValue( SC_UNONAME_INPMESS, uno::Any( _inputmessage ) );
+ lcl_setValidationProps( m_xRange, xProps );
+}
+
+OUString SAL_CALL
+ScVbaValidation::getInputTitle()
+{
+ uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange );
+ OUString sString;
+ xProps->getPropertyValue( SC_UNONAME_INPTITLE ) >>= sString;
+ return sString;
+}
+
+void SAL_CALL
+ScVbaValidation::setInputTitle( const OUString& _inputtitle )
+{
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) );
+ xProps->setPropertyValue( SC_UNONAME_INPTITLE, uno::Any( _inputtitle ) );
+ lcl_setValidationProps( m_xRange, xProps );
+}
+
+OUString SAL_CALL
+ScVbaValidation::getErrorMessage()
+{
+ uno::Reference< beans::XPropertySet > xProps = lcl_getValidationProps( m_xRange );
+ OUString sString;
+ xProps->getPropertyValue( SC_UNONAME_ERRMESS ) >>= sString;
+ return sString;
+}
+
+void SAL_CALL
+ScVbaValidation::setErrorMessage( const OUString& _errormessage )
+{
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) );
+ xProps->setPropertyValue( SC_UNONAME_ERRMESS, uno::Any( _errormessage ) );
+ lcl_setValidationProps( m_xRange, xProps );
+}
+
+void SAL_CALL
+ScVbaValidation::Delete( )
+{
+ OUString sBlank;
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) );
+ uno::Reference< sheet::XSheetCondition > xCond( xProps, uno::UNO_QUERY_THROW );
+ xProps->setPropertyValue( SC_UNONAME_IGNOREBL, uno::Any( true ) );
+ xProps->setPropertyValue( SC_UNONAME_SHOWINP, uno::Any( true ) );
+ xProps->setPropertyValue( SC_UNONAME_SHOWERR, uno::Any( true ) );
+ xProps->setPropertyValue( SC_UNONAME_ERRTITLE, uno::Any( sBlank ) );
+ xProps->setPropertyValue( SC_UNONAME_INPMESS, uno::Any( sBlank) );
+ xProps->setPropertyValue( SC_UNONAME_ERRALSTY, uno::Any( sheet::ValidationAlertStyle_STOP) );
+ xProps->setPropertyValue( SC_UNONAME_TYPE, uno::Any( sheet::ValidationType_ANY ) );
+ xCond->setFormula1( sBlank );
+ xCond->setFormula2( sBlank );
+ xCond->setOperator( sheet::ConditionOperator_NONE );
+
+ lcl_setValidationProps( m_xRange, xProps );
+}
+
+// Fix the defect that validation cannot work when the input should be limited between a lower bound and an upper bound
+void SAL_CALL
+ScVbaValidation::Add( const uno::Any& Type, const uno::Any& AlertStyle, const uno::Any& Operator, const uno::Any& Formula1, const uno::Any& Formula2 )
+{
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) );
+ uno::Reference< sheet::XSheetCondition > xCond( xProps, uno::UNO_QUERY_THROW );
+
+ sheet::ValidationType nValType = sheet::ValidationType_ANY;
+ xProps->getPropertyValue( SC_UNONAME_TYPE ) >>= nValType;
+ if ( nValType != sheet::ValidationType_ANY )
+ throw uno::RuntimeException("validation object already exists" );
+ sal_Int32 nType = -1;
+ if ( !Type.hasValue() || !( Type >>= nType ) )
+ throw uno::RuntimeException("missing required param" );
+
+ Delete(); // set up defaults
+ OUString sFormula1;
+ Formula1 >>= sFormula1;
+ OUString sFormula2;
+ Formula2 >>= sFormula2;
+ switch ( nType )
+ {
+ case excel::XlDVType::xlValidateList:
+ {
+ // for validate list
+ // at least formula1 is required
+ if ( !Formula1.hasValue() )
+ throw uno::RuntimeException("missing param" );
+ nValType = sheet::ValidationType_LIST;
+ xProps->setPropertyValue( SC_UNONAME_TYPE, uno::Any(nValType ));
+ // #TODO validate required params
+ // #TODO need to correct the ';' delimited formula on get/set
+ break;
+ }
+ case excel::XlDVType::xlValidateWholeNumber:
+ nValType = sheet::ValidationType_WHOLE;
+ xProps->setPropertyValue( SC_UNONAME_TYPE, uno::Any(nValType ));
+ break;
+ default:
+ throw uno::RuntimeException("unsupported operation..." );
+ }
+
+ sheet::ValidationAlertStyle eStyle = sheet::ValidationAlertStyle_STOP;
+ sal_Int32 nVbaAlertStyle = excel::XlDVAlertStyle::xlValidAlertStop;
+ if ( AlertStyle.hasValue() && ( AlertStyle >>= nVbaAlertStyle ) )
+ {
+ switch( nVbaAlertStyle )
+ {
+ case excel::XlDVAlertStyle::xlValidAlertStop:
+ // yes I know it's already defaulted but safer to assume
+ // someone probably could change the code above
+ eStyle = sheet::ValidationAlertStyle_STOP;
+ break;
+ case excel::XlDVAlertStyle::xlValidAlertWarning:
+ eStyle = sheet::ValidationAlertStyle_WARNING;
+ break;
+ case excel::XlDVAlertStyle::xlValidAlertInformation:
+ eStyle = sheet::ValidationAlertStyle_INFO;
+ break;
+ default:
+ throw uno::RuntimeException("bad param..." );
+
+ }
+ }
+
+ xProps->setPropertyValue( SC_UNONAME_ERRALSTY, uno::Any( eStyle ) );
+
+ // i#108860: fix the defect that validation cannot work when the input
+ // should be limited between a lower bound and an upper bound
+ if ( Operator.hasValue() )
+ {
+ css::sheet::ConditionOperator conOperator = ScVbaFormatCondition::retrieveAPIOperator( Operator );
+ xCond->setOperator( conOperator );
+ }
+
+ if ( !sFormula1.isEmpty() )
+ xCond->setFormula1( sFormula1 );
+ if ( !sFormula2.isEmpty() )
+ xCond->setFormula2( sFormula2 );
+
+ lcl_setValidationProps( m_xRange, xProps );
+}
+
+OUString SAL_CALL
+ScVbaValidation::getFormula1()
+{
+ uno::Reference< sheet::XSheetCondition > xCond( lcl_getValidationProps( m_xRange ), uno::UNO_QUERY_THROW );
+ OUString sString = xCond->getFormula1();
+
+ ScRefFlags nFlags = ScRefFlags::ZERO;
+ ScRangeList aCellRanges;
+
+ ScDocShell* pDocSh = excel::GetDocShellFromRange( m_xRange );
+ // in calc validation formula is either a range or formula
+ // that results in range.
+ // In VBA both formula and address can have a leading '='
+ // in result of getFormula1, however it *seems* that a named range or
+ // real formula has to (or is expected to) have the '='
+ if ( pDocSh && !ScVbaRange::getCellRangesForAddress( nFlags, sString, pDocSh, aCellRanges, formula::FormulaGrammar::CONV_XL_A1, 0 ) )
+ sString = "=" + sString;
+ return sString;
+}
+
+OUString SAL_CALL
+ScVbaValidation::getFormula2()
+{
+ uno::Reference< sheet::XSheetCondition > xCond( lcl_getValidationProps( m_xRange ), uno::UNO_QUERY_THROW );
+ return xCond->getFormula2();
+}
+
+sal_Int32 SAL_CALL
+ScVbaValidation::getType()
+{
+ uno::Reference< beans::XPropertySet > xProps( lcl_getValidationProps( m_xRange ) );
+ sheet::ValidationType nValType = sheet::ValidationType_ANY;
+ xProps->getPropertyValue( SC_UNONAME_TYPE ) >>= nValType;
+ sal_Int32 nExcelType = excel::XlDVType::xlValidateList; // pick a default
+ if ( xProps.is() )
+ {
+ switch ( nValType )
+ {
+ case sheet::ValidationType_LIST:
+ nExcelType = excel::XlDVType::xlValidateList;
+ break;
+ case sheet::ValidationType_ANY: // not ANY not really a great match for anything I fear:-(
+ nExcelType = excel::XlDVType::xlValidateInputOnly;
+ break;
+ case sheet::ValidationType_CUSTOM:
+ nExcelType = excel::XlDVType::xlValidateCustom;
+ break;
+ case sheet::ValidationType_WHOLE:
+ nExcelType = excel::XlDVType::xlValidateWholeNumber;
+ break;
+ case sheet::ValidationType_DECIMAL:
+ nExcelType = excel::XlDVType::xlValidateDecimal;
+ break;
+ case sheet::ValidationType_DATE:
+ nExcelType = excel::XlDVType::xlValidateDate;
+ break;
+ case sheet::ValidationType_TIME:
+ nExcelType = excel::XlDVType::xlValidateTime;
+ break;
+ case sheet::ValidationType_TEXT_LEN:
+ nExcelType = excel::XlDVType::xlValidateTextLength;
+ break;
+ case sheet::ValidationType::ValidationType_MAKE_FIXED_SIZE:
+ default:
+ break;
+ }
+ }
+ return nExcelType;
+}
+
+OUString
+ScVbaValidation::getServiceImplName()
+{
+ return "ScVbaValidation";
+}
+
+uno::Sequence< OUString >
+ScVbaValidation::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Validation"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbavalidation.hxx b/sc/source/ui/vba/vbavalidation.hxx
new file mode 100644
index 000000000..ab16c0533
--- /dev/null
+++ b/sc/source/ui/vba/vbavalidation.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 <ooo/vba/excel/XValidation.hpp>
+#include <vbahelper/vbahelperinterface.hxx>
+
+namespace com::sun::star::table { class XCellRange; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+typedef InheritedHelperInterfaceWeakImpl<ov::excel::XValidation > ValidationImpl_BASE;
+
+class ScVbaValidation : public ValidationImpl_BASE
+{
+ css::uno::Reference< css::table::XCellRange > m_xRange;
+
+public:
+ ScVbaValidation( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, const css::uno::Reference< css::table::XCellRange >& xRange ) : ValidationImpl_BASE( xParent, xContext ), m_xRange( xRange) {}
+ // Attributes
+ virtual sal_Bool SAL_CALL getIgnoreBlank() override;
+ virtual void SAL_CALL setIgnoreBlank( sal_Bool _ignoreblank ) override;
+ virtual sal_Bool SAL_CALL getInCellDropdown() override;
+ virtual void SAL_CALL setInCellDropdown( sal_Bool _incelldropdown ) override;
+ virtual sal_Bool SAL_CALL getShowInput() override;
+ virtual void SAL_CALL setShowInput( sal_Bool _showinput ) override;
+ virtual sal_Bool SAL_CALL getShowError() override;
+ virtual void SAL_CALL setShowError( sal_Bool _showerror ) override;
+ virtual OUString SAL_CALL getInputTitle() override;
+ virtual void SAL_CALL setInputTitle( const OUString& _inputtitle ) override;
+ virtual OUString SAL_CALL getErrorTitle() override;
+ virtual void SAL_CALL setErrorTitle( const OUString& _errortitle ) override;
+ virtual OUString SAL_CALL getInputMessage() override;
+ virtual void SAL_CALL setInputMessage( const OUString& _inputmessage ) override;
+ virtual OUString SAL_CALL getErrorMessage() override;
+ virtual void SAL_CALL setErrorMessage( const OUString& _errormessage ) override;
+ virtual OUString SAL_CALL getFormula1() override ;
+ virtual OUString SAL_CALL getFormula2() override;
+ virtual sal_Int32 SAL_CALL getType() override;
+ // Methods
+ virtual void SAL_CALL Delete( ) override;
+ virtual void SAL_CALL Add( const css::uno::Any& Type, const css::uno::Any& AlertStyle, const css::uno::Any& Operator, const css::uno::Any& Formula1, const css::uno::Any& Formula2 ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbawindow.cxx b/sc/source/ui/vba/vbawindow.cxx
new file mode 100644
index 000000000..3e7cc4f56
--- /dev/null
+++ b/sc/source/ui/vba/vbawindow.cxx
@@ -0,0 +1,868 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "excelvbahelper.hxx"
+#include "vbawindow.hxx"
+#include "vbaworksheets.hxx"
+#include "vbaworksheet.hxx"
+#include "vbaworkbook.hxx"
+#include "vbapane.hxx"
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/sheet/XViewSplitable.hpp>
+#include <com/sun/star/sheet/XViewFreezable.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/view/DocumentZoomType.hpp>
+#include <com/sun/star/table/CellRangeAddress.hpp>
+#include <o3tl/safeint.hxx>
+#include <ooo/vba/excel/XApplication.hpp>
+#include <ooo/vba/excel/XlWindowState.hpp>
+#include <ooo/vba/excel/XlWindowView.hpp>
+#include <basic/sberrors.hxx>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/implbase.hxx>
+
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <docuno.hxx>
+#include <sc.hrc>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/wrkwin.hxx>
+#include <unonames.hxx>
+#include <markdata.hxx>
+#include <unordered_map>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+using namespace ::ooo::vba::excel::XlWindowState;
+
+typedef std::unordered_map< OUString,
+SCTAB > NameIndexHash;
+
+typedef std::vector< uno::Reference< sheet::XSpreadsheet > > Sheets;
+
+typedef ::cppu::WeakImplHelper< container::XEnumerationAccess
+ , css::container::XIndexAccess
+ , css::container::XNameAccess
+ > SelectedSheets_BASE;
+
+namespace {
+
+class SelectedSheetsEnum : public ::cppu::WeakImplHelper< container::XEnumeration >
+{
+public:
+ uno::Reference< uno::XComponentContext > m_xContext;
+ Sheets m_sheets;
+ uno::Reference< frame::XModel > m_xModel;
+ Sheets::const_iterator m_it;
+
+ /// @throws uno::RuntimeException
+ SelectedSheetsEnum( const uno::Reference< uno::XComponentContext >& xContext, Sheets&& sheets, const uno::Reference< frame::XModel >& xModel )
+ : m_xContext( xContext ), m_sheets( std::move(sheets) ), m_xModel( xModel )
+ {
+ m_it = m_sheets.begin();
+ }
+ // XEnumeration
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override
+ {
+ return m_it != m_sheets.end();
+ }
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ if ( !hasMoreElements() )
+ {
+ throw container::NoSuchElementException();
+ }
+ // #FIXME needs ThisWorkbook as parent
+ return uno::Any( uno::Reference< excel::XWorksheet > ( new ScVbaWorksheet( uno::Reference< XHelperInterface >(), m_xContext, *(m_it++), m_xModel ) ) );
+ }
+
+};
+
+class SelectedSheetsEnumAccess : public SelectedSheets_BASE
+{
+ uno::Reference< uno::XComponentContext > m_xContext;
+ NameIndexHash namesToIndices;
+ Sheets sheets;
+ uno::Reference< frame::XModel > m_xModel;
+public:
+ SelectedSheetsEnumAccess( const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< frame::XModel >& xModel ):m_xContext( xContext ), m_xModel( xModel )
+ {
+ ScModelObj* pModel = static_cast< ScModelObj* >( m_xModel.get() );
+ if ( !pModel )
+ throw uno::RuntimeException("Cannot obtain current document" );
+ ScDocShell* pDocShell = static_cast<ScDocShell*>(pModel->GetEmbeddedObject());
+ if ( !pDocShell )
+ throw uno::RuntimeException("Cannot obtain docshell" );
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ if ( !pViewShell )
+ throw uno::RuntimeException("Cannot obtain view shell" );
+
+ SCTAB nTabCount = pDocShell->GetDocument().GetTableCount();
+ SCTAB nIndex = 0;
+ const ScMarkData& rMarkData = pViewShell->GetViewData().GetMarkData();
+ sheets.reserve( nTabCount );
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadSheet( m_xModel, uno::UNO_QUERY_THROW );
+ uno::Reference <container::XIndexAccess> xIndex( xSpreadSheet->getSheets(), uno::UNO_QUERY_THROW );
+ for (const auto& rTab : rMarkData)
+ {
+ if (rTab >= nTabCount)
+ break;
+ uno::Reference< sheet::XSpreadsheet > xSheet( xIndex->getByIndex( rTab ), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNamed > xNamed( xSheet, uno::UNO_QUERY_THROW );
+ sheets.push_back( xSheet );
+ namesToIndices[ xNamed->getName() ] = nIndex++;
+ }
+
+ }
+
+ //XEnumerationAccess
+ virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override
+ {
+ return new SelectedSheetsEnum( m_xContext, std::vector(sheets), m_xModel );
+ }
+ // XIndexAccess
+ virtual ::sal_Int32 SAL_CALL getCount( ) override
+ {
+ return sheets.size();
+ }
+ virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
+ {
+ if ( Index < 0
+ || o3tl::make_unsigned( Index ) >= sheets.size() )
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any( sheets[ Index ] );
+ }
+
+ //XElementAccess
+ virtual uno::Type SAL_CALL getElementType( ) override
+ {
+ return cppu::UnoType<excel::XWorksheet>::get();
+ }
+
+ virtual sal_Bool SAL_CALL hasElements( ) override
+ {
+ return ( !sheets.empty() );
+ }
+
+ //XNameAccess
+ virtual uno::Any SAL_CALL getByName( const OUString& aName ) override
+ {
+ NameIndexHash::const_iterator it = namesToIndices.find( aName );
+ if ( it == namesToIndices.end() )
+ throw container::NoSuchElementException();
+ return uno::Any( sheets[ it->second ] );
+
+ }
+
+ virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override
+ {
+ return comphelper::mapKeysToSequence( namesToIndices );
+ }
+
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
+ {
+ NameIndexHash::const_iterator it = namesToIndices.find( aName );
+ return (it != namesToIndices.end());
+ }
+
+};
+
+}
+
+ScVbaWindow::ScVbaWindow(
+ const uno::Reference< XHelperInterface >& xParent,
+ const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< frame::XModel >& xModel,
+ const uno::Reference< frame::XController >& xController ) :
+ WindowImpl_BASE( xParent, xContext, xModel, xController )
+{
+ init();
+}
+
+ScVbaWindow::ScVbaWindow(
+ const uno::Sequence< uno::Any >& args,
+ const uno::Reference< uno::XComponentContext >& xContext ) :
+ WindowImpl_BASE( args, xContext )
+{
+ init();
+}
+
+void
+ScVbaWindow::init()
+{
+ /* This method is called from the constructor, thus the own refcount is
+ still zero. The implementation of ActivePane() uses a UNO reference of
+ this (to set this window as parent of the pane object). This requires
+ the own refcount to be non-zero, otherwise this instance will be
+ destructed immediately! Guard the call to ActivePane() in try/catch to
+ not miss the decrementation of the reference count on exception. */
+ osl_atomic_increment( &m_refCount );
+ try
+ {
+ m_xPane = ActivePane();
+ }
+ catch( uno::Exception& )
+ {
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+uno::Reference< beans::XPropertySet >
+ScVbaWindow::getControllerProps() const
+{
+ return uno::Reference< beans::XPropertySet >( getController(), uno::UNO_QUERY_THROW );
+}
+
+uno::Reference< beans::XPropertySet >
+ScVbaWindow::getFrameProps() const
+{
+ return uno::Reference< beans::XPropertySet >( getController()->getFrame(), uno::UNO_QUERY_THROW );
+}
+
+uno::Reference< awt::XDevice >
+ScVbaWindow::getDevice() const
+{
+ return uno::Reference< awt::XDevice >( getWindow(), uno::UNO_QUERY_THROW );
+}
+
+void
+ScVbaWindow::Scroll( const uno::Any& Down, const uno::Any& Up, const uno::Any& ToRight, const uno::Any& ToLeft, bool bLargeScroll )
+{
+ if( !m_xPane.is() )
+ throw uno::RuntimeException();
+ if( bLargeScroll )
+ m_xPane->LargeScroll( Down, Up, ToRight, ToLeft );
+ else
+ m_xPane->SmallScroll( Down, Up, ToRight, ToLeft );
+}
+
+void SAL_CALL
+ScVbaWindow::SmallScroll( const uno::Any& Down, const uno::Any& Up, const uno::Any& ToRight, const uno::Any& ToLeft )
+{
+ Scroll( Down, Up, ToRight, ToLeft, false );
+}
+
+void SAL_CALL
+ScVbaWindow::LargeScroll( const uno::Any& Down, const uno::Any& Up, const uno::Any& ToRight, const uno::Any& ToLeft )
+{
+ Scroll( Down, Up, ToRight, ToLeft, true );
+}
+
+uno::Any SAL_CALL
+ScVbaWindow::SelectedSheets( const uno::Any& aIndex )
+{
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( new SelectedSheetsEnumAccess( mxContext, m_xModel ) );
+ // #FIXME needs a workbook as a parent
+ uno::Reference< excel::XWorksheets > xSheets( new ScVbaWorksheets( uno::Reference< XHelperInterface >(), mxContext, xEnumAccess, m_xModel ) );
+ if ( aIndex.hasValue() )
+ {
+ uno::Reference< XCollection > xColl( xSheets, uno::UNO_QUERY_THROW );
+ return xColl->Item( aIndex, uno::Any() );
+ }
+ return uno::Any( xSheets );
+}
+
+void SAL_CALL
+ScVbaWindow::ScrollWorkbookTabs( const uno::Any& /*Sheets*/, const uno::Any& /*Position*/ )
+{
+// #TODO #FIXME need some implementation to scroll through the tabs
+// but where is this done?
+/*
+ sal_Int32 nSheets = 0;
+ sal_Int32 nPosition = 0;
+ throw uno::RuntimeException("No Implemented" );
+ sal_Bool bSheets = ( Sheets >>= nSheets );
+ sal_Bool bPosition = ( Position >>= nPosition );
+ if ( bSheets || bPosition ) // at least one param specified
+ if ( bSheets )
+ ;// use sheets
+ else if ( bPosition )
+ ; //use position
+*/
+
+}
+
+uno::Any SAL_CALL
+ScVbaWindow::getCaption()
+{
+ // tdf#118129 - return only the caption property of the frame
+ OUString sTitle;
+ getFrameProps()->getPropertyValue(SC_UNONAME_TITLE) >>= sTitle;
+ return uno::Any( sTitle );
+}
+
+void SAL_CALL
+ScVbaWindow::setCaption( const uno::Any& _caption )
+{
+ getFrameProps()->setPropertyValue( SC_UNONAME_TITLE, _caption );
+}
+
+uno::Any SAL_CALL
+ScVbaWindow::getScrollRow()
+{
+ sal_Int32 nValue = 0;
+ // !! TODO !! get view shell from controller
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ if ( pViewShell )
+ {
+ ScSplitPos eWhich = pViewShell->GetViewData().GetActivePart();
+ nValue = pViewShell->GetViewData().GetPosY(WhichV(eWhich));
+ }
+
+ return uno::Any( nValue + 1);
+}
+
+void SAL_CALL
+ScVbaWindow::setScrollRow( const uno::Any& _scrollrow )
+{
+ // !! TODO !! get view shell from controller
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ if ( pViewShell )
+ {
+ sal_Int32 scrollRow = 0;
+ _scrollrow >>= scrollRow;
+ ScSplitPos eWhich = pViewShell->GetViewData().GetActivePart();
+ sal_Int32 nOldValue = pViewShell->GetViewData().GetPosY(WhichV(eWhich)) + 1;
+ pViewShell->ScrollLines(0, scrollRow - nOldValue);
+ }
+}
+
+uno::Any SAL_CALL
+ScVbaWindow::getScrollColumn()
+{
+ sal_Int32 nValue = 0;
+ // !! TODO !! get view shell from controller
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ if ( pViewShell )
+ {
+ ScSplitPos eWhich = pViewShell->GetViewData().GetActivePart();
+ nValue = pViewShell->GetViewData().GetPosX(WhichH(eWhich));
+ }
+
+ return uno::Any( nValue + 1);
+}
+
+void SAL_CALL
+ScVbaWindow::setScrollColumn( const uno::Any& _scrollcolumn )
+{
+ // !! TODO !! get view shell from controller
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ if ( pViewShell )
+ {
+ sal_Int32 scrollColumn = 0;
+ _scrollcolumn >>= scrollColumn;
+ ScSplitPos eWhich = pViewShell->GetViewData().GetActivePart();
+ sal_Int32 nOldValue = pViewShell->GetViewData().GetPosX(WhichH(eWhich)) + 1;
+ pViewShell->ScrollLines(scrollColumn - nOldValue, 0);
+ }
+}
+
+uno::Any SAL_CALL
+ScVbaWindow::getWindowState()
+{
+ sal_Int32 nwindowState = xlNormal;
+ // !! TODO !! get view shell from controller
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ SfxViewFrame* pViewFrame = pViewShell -> GetViewFrame();
+ WorkWindow* pWork = static_cast<WorkWindow*>( pViewFrame->GetFrame().GetSystemWindow() );
+ if ( pWork )
+ {
+ if ( pWork -> IsMaximized())
+ nwindowState = xlMaximized;
+ else if (pWork -> IsMinimized())
+ nwindowState = xlMinimized;
+ }
+ return uno::Any( nwindowState );
+}
+
+void SAL_CALL
+ScVbaWindow::setWindowState( const uno::Any& _windowstate )
+{
+ sal_Int32 nwindowState = xlMaximized;
+ _windowstate >>= nwindowState;
+ // !! TODO !! get view shell from controller
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ SfxViewFrame* pViewFrame = pViewShell -> GetViewFrame();
+ WorkWindow* pWork = static_cast<WorkWindow*>( pViewFrame->GetFrame().GetSystemWindow() );
+ if ( pWork )
+ {
+ if ( nwindowState == xlMaximized)
+ pWork -> Maximize();
+ else if (nwindowState == xlMinimized)
+ pWork -> Minimize();
+ else if (nwindowState == xlNormal)
+ pWork -> Restore();
+ else
+ throw uno::RuntimeException("Invalid Parameter" );
+ }
+}
+
+void
+ScVbaWindow::Activate()
+{
+ rtl::Reference<ScVbaWorkbook> workbook( new ScVbaWorkbook( uno::Reference< XHelperInterface >( Application(), uno::UNO_QUERY_THROW ), mxContext, m_xModel ) );
+
+ workbook->Activate();
+}
+
+void
+ScVbaWindow::Close( const uno::Any& SaveChanges, const uno::Any& FileName, const uno::Any& RouteWorkBook )
+{
+ rtl::Reference< ScVbaWorkbook > workbook( new ScVbaWorkbook( uno::Reference< XHelperInterface >( Application(), uno::UNO_QUERY_THROW ), mxContext, m_xModel ) );
+ workbook->Close(SaveChanges, FileName, RouteWorkBook );
+}
+
+uno::Reference< excel::XPane > SAL_CALL
+ScVbaWindow::ActivePane()
+{
+ uno::Reference< sheet::XViewPane > xViewPane( getController(), uno::UNO_QUERY_THROW );
+ return new ScVbaPane( this, mxContext, m_xModel, xViewPane );
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaWindow::ActiveCell( )
+{
+ uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW );
+ return xApplication->getActiveCell();
+}
+
+uno::Any SAL_CALL
+ScVbaWindow::Selection( )
+{
+ uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW );
+ return xApplication->getSelection();
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaWindow::RangeSelection()
+{
+ /* TODO / FIXME: According to documentation, this method returns the range
+ selection even if shapes are selected. */
+ return uno::Reference< excel::XRange >( Selection(), uno::UNO_QUERY_THROW );
+}
+
+sal_Bool SAL_CALL
+ScVbaWindow::getDisplayGridlines()
+{
+ bool bGrid = true;
+ getControllerProps()->getPropertyValue( SC_UNO_SHOWGRID ) >>= bGrid;
+ return bGrid;
+}
+
+void SAL_CALL
+ScVbaWindow::setDisplayGridlines( sal_Bool _displaygridlines )
+{
+ getControllerProps()->setPropertyValue( SC_UNO_SHOWGRID, uno::Any( _displaygridlines ));
+}
+
+sal_Bool SAL_CALL
+ScVbaWindow::getDisplayHeadings()
+{
+ bool bHeading = true;
+ getControllerProps()->getPropertyValue( SC_UNO_COLROWHDR ) >>= bHeading;
+ return bHeading;
+}
+
+void SAL_CALL
+ScVbaWindow::setDisplayHeadings( sal_Bool _bDisplayHeadings )
+{
+ getControllerProps()->setPropertyValue( SC_UNO_COLROWHDR, uno::Any( _bDisplayHeadings ));
+}
+
+sal_Bool SAL_CALL
+ScVbaWindow::getDisplayHorizontalScrollBar()
+{
+ bool bHorizontalScrollBar = true;
+ getControllerProps()->getPropertyValue( SC_UNO_HORSCROLL ) >>= bHorizontalScrollBar;
+ return bHorizontalScrollBar;
+}
+
+void SAL_CALL
+ScVbaWindow::setDisplayHorizontalScrollBar( sal_Bool _bDisplayHorizontalScrollBar )
+{
+ getControllerProps()->setPropertyValue( SC_UNO_HORSCROLL, uno::Any( _bDisplayHorizontalScrollBar ));
+}
+
+sal_Bool SAL_CALL
+ScVbaWindow::getDisplayOutline()
+{
+ bool bOutline = true;
+ getControllerProps()->getPropertyValue( SC_UNO_OUTLSYMB ) >>= bOutline;
+ return bOutline;
+}
+
+void SAL_CALL
+ScVbaWindow::setDisplayOutline( sal_Bool _bDisplayOutline )
+{
+ getControllerProps()->setPropertyValue( SC_UNO_OUTLSYMB, uno::Any( _bDisplayOutline ));
+}
+
+sal_Bool SAL_CALL
+ScVbaWindow::getDisplayVerticalScrollBar()
+{
+ bool bVerticalScrollBar = true;
+ getControllerProps()->getPropertyValue( SC_UNO_VERTSCROLL ) >>= bVerticalScrollBar;
+ return bVerticalScrollBar;
+}
+
+void SAL_CALL
+ScVbaWindow::setDisplayVerticalScrollBar( sal_Bool _bDisplayVerticalScrollBar )
+{
+ getControllerProps()->setPropertyValue( SC_UNO_VERTSCROLL, uno::Any( _bDisplayVerticalScrollBar ));
+}
+
+sal_Bool SAL_CALL
+ScVbaWindow::getDisplayWorkbookTabs()
+{
+ bool bWorkbookTabs = true;
+ getControllerProps()->getPropertyValue( SC_UNO_SHEETTABS ) >>= bWorkbookTabs;
+ return bWorkbookTabs;
+}
+
+void SAL_CALL
+ScVbaWindow::setDisplayWorkbookTabs( sal_Bool _bDisplayWorkbookTabs )
+{
+ getControllerProps()->setPropertyValue( SC_UNO_SHEETTABS, uno::Any( _bDisplayWorkbookTabs ));
+}
+
+sal_Bool SAL_CALL
+ScVbaWindow::getFreezePanes()
+{
+ uno::Reference< sheet::XViewFreezable > xViewFreezable( getController(), uno::UNO_QUERY_THROW );
+ return xViewFreezable->hasFrozenPanes();
+}
+
+void SAL_CALL
+ScVbaWindow::setFreezePanes( sal_Bool _bFreezePanes )
+{
+ uno::Reference< sheet::XViewPane > xViewPane( getController(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XViewSplitable > xViewSplitable( xViewPane, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XViewFreezable > xViewFreezable( xViewPane, uno::UNO_QUERY_THROW );
+ if( _bFreezePanes )
+ {
+ if( xViewSplitable->getIsWindowSplit() )
+ {
+ // if there is a split we freeze at the split
+ sal_Int32 nColumn = getSplitColumn();
+ sal_Int32 nRow = getSplitRow();
+ xViewFreezable->freezeAtPosition( nColumn, nRow );
+ }
+ else
+ {
+ // otherwise we freeze in the center of the visible sheet
+ table::CellRangeAddress aCellRangeAddress = xViewPane->getVisibleRange();
+ sal_Int32 nColumn = aCellRangeAddress.StartColumn + (( aCellRangeAddress.EndColumn - aCellRangeAddress.StartColumn )/2 );
+ sal_Int32 nRow = aCellRangeAddress.StartRow + (( aCellRangeAddress.EndRow - aCellRangeAddress.StartRow )/2 );
+ xViewFreezable->freezeAtPosition( nColumn, nRow );
+ }
+ }
+ else
+ {
+ //remove the freeze panes
+ xViewSplitable->splitAtPosition(0,0);
+ }
+}
+
+sal_Bool SAL_CALL
+ScVbaWindow::getSplit()
+{
+ uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW );
+ return xViewSplitable->getIsWindowSplit();
+}
+
+void SAL_CALL
+ScVbaWindow::setSplit( sal_Bool _bSplit )
+{
+ if( !_bSplit )
+ {
+ uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW );
+ xViewSplitable->splitAtPosition(0,0);
+ }
+ else
+ {
+ uno::Reference< sheet::XViewFreezable > xViewFreezable( getController(), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XRange > xRange = ActiveCell();
+ sal_Int32 nRow = xRange->getRow();
+ sal_Int32 nColumn = xRange->getColumn();
+ SplitAtDefinedPosition( nColumn-1, nRow-1 );
+ }
+}
+
+sal_Int32 SAL_CALL
+ScVbaWindow::getSplitColumn()
+{
+ uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW );
+ return xViewSplitable->getSplitColumn();
+}
+
+void SAL_CALL
+ScVbaWindow::setSplitColumn( sal_Int32 _splitcolumn )
+{
+ if( getSplitColumn() != _splitcolumn )
+ {
+ uno::Reference< sheet::XViewFreezable > xViewFreezable( getController(), uno::UNO_QUERY_THROW );
+ sal_Int32 nRow = getSplitRow();
+ SplitAtDefinedPosition( _splitcolumn, nRow );
+ }
+}
+
+double SAL_CALL
+ScVbaWindow::getSplitHorizontal()
+{
+ uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW );
+ return PixelsToPoints( getDevice(), xViewSplitable->getSplitHorizontal(), true );
+}
+
+void SAL_CALL
+ScVbaWindow::setSplitHorizontal( double _splithorizontal )
+{
+ uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW );
+ double fHoriPixels = PointsToPixels( getDevice(), _splithorizontal, true );
+ xViewSplitable->splitAtPosition( static_cast< sal_Int32 >( fHoriPixels ), 0 );
+}
+
+sal_Int32 SAL_CALL
+ScVbaWindow::getSplitRow()
+{
+ uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW );
+ return xViewSplitable->getSplitRow();
+}
+
+void SAL_CALL
+ScVbaWindow::setSplitRow( sal_Int32 _splitrow )
+{
+ if( getSplitRow() != _splitrow )
+ {
+ uno::Reference< sheet::XViewFreezable > xViewFreezable( getController(), uno::UNO_QUERY_THROW );
+ sal_Int32 nColumn = getSplitColumn();
+ SplitAtDefinedPosition( nColumn, _splitrow );
+ }
+}
+
+double SAL_CALL
+ScVbaWindow::getSplitVertical()
+{
+ uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW );
+ return PixelsToPoints( getDevice(), xViewSplitable->getSplitVertical(), false );
+}
+
+void SAL_CALL
+ScVbaWindow::setSplitVertical(double _splitvertical )
+{
+ uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW );
+ double fVertiPixels = PointsToPixels( getDevice(), _splitvertical, false );
+ xViewSplitable->splitAtPosition( 0, static_cast<sal_Int32>( fVertiPixels ) );
+}
+
+void ScVbaWindow::SplitAtDefinedPosition( sal_Int32 nColumns, sal_Int32 nRows )
+{
+ uno::Reference< sheet::XViewSplitable > xViewSplitable( getController(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XViewFreezable > xViewFreezable( xViewSplitable, uno::UNO_QUERY_THROW );
+ // nColumns and nRows means split columns/rows
+ if( nColumns == 0 && nRows == 0 )
+ return;
+
+ sal_Int32 cellColumn = nColumns + 1;
+ sal_Int32 cellRow = nRows + 1;
+
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ if ( pViewShell )
+ {
+ //firstly remove the old splitter
+ xViewSplitable->splitAtPosition(0,0);
+
+ uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XWorksheet > xSheet( xApplication->getActiveSheet(), uno::UNO_SET_THROW );
+ xSheet->Cells(uno::Any(cellRow), uno::Any(cellColumn))->Select();
+
+ //pViewShell->FreezeSplitters( FALSE );
+ dispatchExecute( pViewShell, SID_WINDOW_SPLIT );
+ }
+}
+
+uno::Any SAL_CALL
+ScVbaWindow::getZoom()
+{
+ uno::Reference< beans::XPropertySet > xProps = getControllerProps();
+ OUString sName( SC_UNO_ZOOMTYPE );
+ sal_Int16 nZoomType = view::DocumentZoomType::PAGE_WIDTH;
+ xProps->getPropertyValue( sName ) >>= nZoomType;
+ if( nZoomType == view::DocumentZoomType::PAGE_WIDTH )
+ {
+ return uno::Any( true );
+ }
+ else if( nZoomType == view::DocumentZoomType::BY_VALUE )
+ {
+ sName = SC_UNO_ZOOMVALUE;
+ sal_Int16 nZoom = 100;
+ xProps->getPropertyValue( sName ) >>= nZoom;
+ return uno::Any( nZoom );
+ }
+ return uno::Any();
+}
+
+void SAL_CALL ScVbaWindow::setZoom(const uno::Any& _zoom)
+{
+ sal_Int16 nZoom = 100;
+ _zoom >>= nZoom;
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( m_xModel, uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XWorksheet > xActiveSheet = ActiveSheet();
+ SCTAB nTab = 0;
+ if ( !ScVbaWorksheets::nameExists (xSpreadDoc, xActiveSheet->getName(), nTab) )
+ throw uno::RuntimeException();
+ std::vector< SCTAB > vTabs { nTab };
+ excel::implSetZoom( m_xModel, nZoom, vTabs );
+}
+
+uno::Reference< excel::XWorksheet > SAL_CALL
+ScVbaWindow::ActiveSheet( )
+{
+ uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW );
+ return xApplication->getActiveSheet();
+}
+
+uno::Any SAL_CALL
+ScVbaWindow::getView()
+{
+ bool bPageBreak = false;
+ sal_Int32 nWindowView = excel::XlWindowView::xlNormalView;
+
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ if (pViewShell)
+ bPageBreak = pViewShell->GetViewData().IsPagebreakMode();
+
+ if( bPageBreak )
+ nWindowView = excel::XlWindowView::xlPageBreakPreview;
+ else
+ nWindowView = excel::XlWindowView::xlNormalView;
+
+ return uno::Any( nWindowView );
+}
+
+void SAL_CALL
+ScVbaWindow::setView( const uno::Any& _view)
+{
+ sal_Int32 nWindowView = excel::XlWindowView::xlNormalView;
+ _view >>= nWindowView;
+ sal_uInt16 nSlot = FID_NORMALVIEWMODE;
+ switch ( nWindowView )
+ {
+ case excel::XlWindowView::xlNormalView:
+ nSlot = FID_NORMALVIEWMODE;
+ break;
+ case excel::XlWindowView::xlPageBreakPreview:
+ nSlot = FID_PAGEBREAKMODE;
+ break;
+ default:
+ DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER);
+ }
+ // !! TODO !! get view shell from controller
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ if ( pViewShell )
+ dispatchExecute( pViewShell, nSlot );
+}
+
+uno::Reference< excel::XRange > SAL_CALL
+ScVbaWindow::getVisibleRange()
+{
+ uno::Reference< container::XIndexAccess > xPanesIA( getController(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XViewPane > xTopLeftPane( xPanesIA->getByIndex( 0 ), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XPane > xPane( new ScVbaPane( this, mxContext, m_xModel, xTopLeftPane ) );
+ return xPane->getVisibleRange();
+}
+
+sal_Int32 SAL_CALL
+ScVbaWindow::PointsToScreenPixelsX(sal_Int32 _points)
+{
+ sal_Int32 nHundredthsofOneMillimeters = Millimeter::getInHundredthsOfOneMillimeter( _points );
+ double fConvertFactor = getDevice()->getInfo().PixelPerMeterX/100000;
+ return static_cast<sal_Int32>(fConvertFactor * nHundredthsofOneMillimeters );
+}
+
+sal_Int32 SAL_CALL
+ScVbaWindow::PointsToScreenPixelsY(sal_Int32 _points)
+{
+ sal_Int32 nHundredthsofOneMillimeters = Millimeter::getInHundredthsOfOneMillimeter( _points );
+ double fConvertFactor = getDevice()->getInfo().PixelPerMeterY/100000;
+ return static_cast<sal_Int32>(fConvertFactor * nHundredthsofOneMillimeters );
+}
+
+void SAL_CALL
+ScVbaWindow::PrintOut( const css::uno::Any& From, const css::uno::Any&To, const css::uno::Any& Copies, const css::uno::Any& Preview, const css::uno::Any& ActivePrinter, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& PrToFileName )
+{
+ // need test, print current active sheet
+ // !! TODO !! get view shell from controller
+ PrintOutHelper( excel::getBestViewShell( m_xModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, true );
+}
+
+void SAL_CALL
+ScVbaWindow::PrintPreview( const css::uno::Any& EnableChanges )
+{
+ // need test, print preview current active sheet
+ // !! TODO !! get view shell from controller
+ PrintPreviewHelper( EnableChanges, excel::getBestViewShell( m_xModel ) );
+}
+
+double SAL_CALL ScVbaWindow::getTabRatio()
+{
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ if ( pViewShell && pViewShell->GetViewData().GetView() )
+ {
+ double fRatio = ScTabView::GetRelTabBarWidth();
+ if ( fRatio >= 0.0 && fRatio <= 1.0 )
+ return fRatio;
+ }
+ return 0.0;
+}
+
+void SAL_CALL ScVbaWindow::setTabRatio( double fRatio )
+{
+ ScTabViewShell* pViewShell = excel::getBestViewShell( m_xModel );
+ if ( pViewShell && pViewShell->GetViewData().GetView() )
+ {
+ if ( fRatio >= 0.0 && fRatio <= 1.0 )
+ pViewShell->GetViewData().GetView()->SetRelTabBarWidth( fRatio );
+ }
+}
+
+OUString
+ScVbaWindow::getServiceImplName()
+{
+ return "ScVbaWindow";
+}
+
+uno::Sequence< OUString >
+ScVbaWindow::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Window"
+ };
+ return aServiceNames;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_ScVbaWindow_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args)
+{
+ return cppu::acquire(new ScVbaWindow(args, context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbawindow.hxx b/sc/source/ui/vba/vbawindow.hxx
new file mode 100644
index 000000000..c4c0a0bec
--- /dev/null
+++ b/sc/source/ui/vba/vbawindow.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 <ooo/vba/excel/XWindow.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <ooo/vba/excel/XPane.hpp>
+#include <com/sun/star/awt/XDevice.hpp>
+#include <cppuhelper/implbase.hxx>
+
+#include <vbahelper/vbawindowbase.hxx>
+
+typedef cppu::ImplInheritanceHelper< VbaWindowBase, ov::excel::XWindow > WindowImpl_BASE;
+
+class ScVbaWindow : public WindowImpl_BASE
+{
+private:
+ css::uno::Reference< ov::excel::XPane > m_xPane;
+
+ void init();
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::beans::XPropertySet > getControllerProps() const;
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::beans::XPropertySet > getFrameProps() const;
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::awt::XDevice > getDevice() const;
+
+protected:
+ void SplitAtDefinedPosition( sal_Int32 nColumns, sal_Int32 nRows );
+
+public:
+ /// @throws css::uno::RuntimeException
+ void Scroll( const css::uno::Any& Down, const css::uno::Any& Up, const css::uno::Any& ToRight, const css::uno::Any& ToLeft, bool bLargeScroll );
+
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaWindow(
+ const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::frame::XModel >& xModel,
+ const css::uno::Reference< css::frame::XController >& xController );
+ /// @throws css::uno::RuntimeException
+ ScVbaWindow(
+ const css::uno::Sequence< css::uno::Any >& aArgs,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext );
+
+ // XWindow
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL ActiveCell( ) override;
+ virtual css::uno::Reference< ov::excel::XPane > SAL_CALL ActivePane() override;
+ virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL ActiveSheet( ) override;
+ virtual void SAL_CALL setCaption( const css::uno::Any& _caption ) override;
+ virtual css::uno::Any SAL_CALL getCaption() override;
+ virtual sal_Bool SAL_CALL getDisplayGridlines() override;
+ virtual void SAL_CALL setDisplayGridlines( sal_Bool _displaygridlines ) override;
+ virtual sal_Bool SAL_CALL getDisplayHeadings() override;
+ virtual void SAL_CALL setDisplayHeadings( sal_Bool _bDisplayHeadings ) override;
+ virtual sal_Bool SAL_CALL getDisplayHorizontalScrollBar() override;
+ virtual void SAL_CALL setDisplayHorizontalScrollBar( sal_Bool _bDisplayHorizontalScrollBar ) override;
+ virtual sal_Bool SAL_CALL getDisplayOutline() override;
+ virtual void SAL_CALL setDisplayOutline( sal_Bool _bDisplayOutline ) override;
+ virtual sal_Bool SAL_CALL getDisplayVerticalScrollBar() override;
+ virtual void SAL_CALL setDisplayVerticalScrollBar( sal_Bool _bDisplayVerticalScrollBar ) override;
+ virtual sal_Bool SAL_CALL getDisplayWorkbookTabs() override;
+ virtual void SAL_CALL setDisplayWorkbookTabs( sal_Bool _bDisplayWorkbookTabs ) override;
+ virtual sal_Bool SAL_CALL getFreezePanes() override;
+ virtual void SAL_CALL setFreezePanes( sal_Bool _bFreezePanes ) override;
+ virtual sal_Bool SAL_CALL getSplit() override;
+ virtual void SAL_CALL setSplit( sal_Bool _bSplit ) override;
+ virtual sal_Int32 SAL_CALL getSplitColumn() override ;
+ virtual void SAL_CALL setSplitColumn( sal_Int32 _splitcolumn ) override ;
+ virtual double SAL_CALL getSplitHorizontal() override ;
+ virtual void SAL_CALL setSplitHorizontal( double _splithorizontal ) override ;
+ virtual sal_Int32 SAL_CALL getSplitRow() override ;
+ virtual void SAL_CALL setSplitRow( sal_Int32 _splitrow ) override ;
+ virtual double SAL_CALL getSplitVertical() override ;
+ virtual void SAL_CALL setSplitVertical( double _splitvertical ) override ;
+ virtual css::uno::Any SAL_CALL getScrollRow() override ;
+ virtual void SAL_CALL setScrollRow( const css::uno::Any& _scrollrow ) override ;
+ virtual css::uno::Any SAL_CALL getScrollColumn() override ;
+ virtual void SAL_CALL setScrollColumn( const css::uno::Any& _scrollcolumn ) override ;
+ virtual css::uno::Any SAL_CALL getView() override;
+ virtual void SAL_CALL setView( const css::uno::Any& _view ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getVisibleRange() override;
+ virtual css::uno::Any SAL_CALL getWindowState() override;
+ virtual void SAL_CALL setWindowState( const css::uno::Any& _windowstate ) override;
+ virtual css::uno::Any SAL_CALL getZoom() override;
+ virtual void SAL_CALL setZoom(const css::uno::Any& _zoom) override;
+ virtual double SAL_CALL getTabRatio() override ;
+ virtual void SAL_CALL setTabRatio( double _tabratio ) override ;
+
+ // Methods
+ virtual void SAL_CALL SmallScroll( const css::uno::Any& Down, const css::uno::Any& Up, const css::uno::Any& ToRight, const css::uno::Any& ToLeft ) override;
+ virtual void SAL_CALL LargeScroll( const css::uno::Any& Down, const css::uno::Any& Up, const css::uno::Any& ToRight, const css::uno::Any& ToLeft ) override;
+ virtual css::uno::Any SAL_CALL SelectedSheets( const css::uno::Any& aIndex ) override;
+ virtual void SAL_CALL ScrollWorkbookTabs( const css::uno::Any& Sheets, const css::uno::Any& Position ) override;
+ virtual void SAL_CALL Activate( ) override;
+ virtual void SAL_CALL Close( const css::uno::Any& SaveChanges, const css::uno::Any& FileName, const css::uno::Any& RouteWorkBook ) override;
+ virtual css::uno::Any SAL_CALL Selection( ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL RangeSelection() override;
+ virtual sal_Int32 SAL_CALL PointsToScreenPixelsX(sal_Int32 _points) override;
+ virtual sal_Int32 SAL_CALL PointsToScreenPixelsY(sal_Int32 _points) override;
+ virtual void SAL_CALL PrintOut( const css::uno::Any& From, const css::uno::Any&To, const css::uno::Any& Copies, const css::uno::Any& Preview, const css::uno::Any& ActivePrinter, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& PrToFileName ) override;
+ virtual void SAL_CALL PrintPreview( const css::uno::Any& EnableChanges ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbawindows.cxx b/sc/source/ui/vba/vbawindows.cxx
new file mode 100644
index 000000000..3a9960378
--- /dev/null
+++ b/sc/source/ui/vba/vbawindows.cxx
@@ -0,0 +1,249 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "vbawindows.hxx"
+
+
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/sequence.hxx>
+#include <o3tl/safeint.hxx>
+#include <rtl/ref.hxx>
+
+#include "vbawindow.hxx"
+#include "vbaworkbook.hxx"
+
+#include <unordered_map>
+
+using namespace ::com::sun::star;
+using namespace ::ooo::vba;
+
+typedef std::unordered_map< OUString,
+sal_Int32 > NameIndexHash;
+
+static uno::Reference< XHelperInterface > lcl_createWorkbookHIParent( const uno::Reference< frame::XModel >& xModel, const uno::Reference< uno::XComponentContext >& xContext, const uno::Any& aApplication )
+{
+ return new ScVbaWorkbook( uno::Reference< XHelperInterface >( aApplication, uno::UNO_QUERY_THROW ), xContext, xModel );
+}
+
+static uno::Any ComponentToWindow( const uno::Any& aSource, const uno::Reference< uno::XComponentContext > & xContext, const uno::Any& aApplication )
+{
+ uno::Reference< frame::XModel > xModel( aSource, uno::UNO_QUERY_THROW );
+ // !! TODO !! iterate over all controllers
+ uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW );
+ uno::Reference< excel::XWindow > xWin( new ScVbaWindow( lcl_createWorkbookHIParent( xModel, xContext, aApplication ), xContext, xModel, xController ) );
+ return uno::Any( xWin );
+}
+
+typedef std::vector < uno::Reference< sheet::XSpreadsheetDocument > > Components;
+
+namespace {
+
+// #TODO more or less the same as class in workwindows ( code sharing needed )
+class WindowComponentEnumImpl : public EnumerationHelper_BASE
+{
+protected:
+ uno::Reference< uno::XComponentContext > m_xContext;
+ Components m_components;
+ Components::const_iterator m_it;
+
+public:
+ /// @throws uno::RuntimeException
+ WindowComponentEnumImpl( const uno::Reference< uno::XComponentContext >& xContext, Components&& components )
+ : m_xContext( xContext ), m_components( std::move(components) )
+ {
+ m_it = m_components.begin();
+ }
+
+ /// @throws uno::RuntimeException
+ explicit WindowComponentEnumImpl( const uno::Reference< uno::XComponentContext >& xContext ) : m_xContext( xContext )
+ {
+ uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(m_xContext);
+ uno::Reference< container::XEnumeration > xComponents = xDesktop->getComponents()->createEnumeration();
+ while( xComponents->hasMoreElements() )
+ {
+ uno::Reference< sheet::XSpreadsheetDocument > xNext( xComponents->nextElement(), uno::UNO_QUERY );
+ if ( xNext.is() )
+ m_components.push_back( xNext );
+ }
+ m_it = m_components.begin();
+ }
+ // XEnumeration
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override
+ {
+ return m_it != m_components.end();
+ }
+
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ if ( !hasMoreElements() )
+ {
+ throw container::NoSuchElementException();
+ }
+ return css::uno::Any( *(m_it++) );
+ }
+};
+
+class WindowEnumImpl : public WindowComponentEnumImpl
+{
+ uno::Any m_aApplication;
+public:
+ WindowEnumImpl( const uno::Reference< uno::XComponentContext >& xContext, const uno::Any& aApplication ): WindowComponentEnumImpl( xContext ), m_aApplication( aApplication ) {}
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ return ComponentToWindow( WindowComponentEnumImpl::nextElement(), m_xContext, m_aApplication );
+ }
+};
+
+}
+
+typedef ::cppu::WeakImplHelper< container::XEnumerationAccess
+ , css::container::XIndexAccess
+ , css::container::XNameAccess
+ > WindowsAccessImpl_BASE;
+
+namespace {
+
+class WindowsAccessImpl : public WindowsAccessImpl_BASE
+{
+ uno::Reference< uno::XComponentContext > m_xContext;
+ Components m_windows;
+ NameIndexHash namesToIndices;
+public:
+ explicit WindowsAccessImpl( const uno::Reference< uno::XComponentContext >& xContext ):m_xContext( xContext )
+ {
+ uno::Reference< container::XEnumeration > xEnum = new WindowComponentEnumImpl( m_xContext );
+ sal_Int32 nIndex=0;
+ while( xEnum->hasMoreElements() )
+ {
+ uno::Reference< sheet::XSpreadsheetDocument > xNext( xEnum->nextElement(), uno::UNO_QUERY );
+ if ( xNext.is() )
+ {
+ m_windows.push_back( xNext );
+ uno::Reference< frame::XModel > xModel( xNext, uno::UNO_QUERY_THROW ); // that the spreadsheetdocument is a xmodel is a given
+ // !! TODO !! iterate over all controllers
+ uno::Reference< frame::XController > xController( xModel->getCurrentController(), uno::UNO_SET_THROW );
+ uno::Reference< XHelperInterface > xTemp; // temporary needed for g++ 3.3.5
+ rtl::Reference< ScVbaWindow > window( new ScVbaWindow( xTemp, m_xContext, xModel, xController ) );
+ OUString sCaption;
+ window->getCaption() >>= sCaption;
+ namesToIndices[ sCaption ] = nIndex++;
+ }
+ }
+
+ }
+
+ //XEnumerationAccess
+ virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override
+ {
+ return new WindowComponentEnumImpl( m_xContext, std::vector(m_windows) );
+ }
+ // XIndexAccess
+ virtual ::sal_Int32 SAL_CALL getCount( ) override
+ {
+ return m_windows.size();
+ }
+ virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
+ {
+ if ( Index < 0
+ || o3tl::make_unsigned( Index ) >= m_windows.size() )
+ throw lang::IndexOutOfBoundsException();
+ return css::uno::Any( m_windows[ Index ] ); // returns xspreadsheetdoc
+ }
+
+ //XElementAccess
+ virtual uno::Type SAL_CALL getElementType( ) override
+ {
+ return cppu::UnoType<sheet::XSpreadsheetDocument>::get();
+ }
+
+ virtual sal_Bool SAL_CALL hasElements( ) override
+ {
+ return ( !m_windows.empty() );
+ }
+
+ //XNameAccess
+ virtual uno::Any SAL_CALL getByName( const OUString& aName ) override
+ {
+ NameIndexHash::const_iterator it = namesToIndices.find( aName );
+ if ( it == namesToIndices.end() )
+ throw container::NoSuchElementException();
+ return css::uno::Any( m_windows[ it->second ] );
+
+ }
+
+ virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override
+ {
+ return comphelper::mapKeysToSequence( namesToIndices );
+ }
+
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
+ {
+ NameIndexHash::const_iterator it = namesToIndices.find( aName );
+ return (it != namesToIndices.end());
+ }
+
+};
+
+}
+
+ScVbaWindows::ScVbaWindows( const uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext ) : ScVbaWindows_BASE( xParent, xContext, uno::Reference< container::XIndexAccess > ( new WindowsAccessImpl( xContext ) ) )
+{
+}
+uno::Reference< container::XEnumeration >
+ScVbaWindows::createEnumeration()
+{
+ return new WindowEnumImpl( mxContext, Application() );
+}
+
+uno::Any
+ScVbaWindows::createCollectionObject( const css::uno::Any& aSource )
+{
+ return ComponentToWindow( aSource, mxContext, Application() );
+}
+
+uno::Type
+ScVbaWindows::getElementType()
+{
+ return cppu::UnoType<excel::XWindows>::get();
+}
+
+void SAL_CALL
+ScVbaWindows::Arrange( ::sal_Int32 /*ArrangeStyle*/, const uno::Any& /*ActiveWorkbook*/, const uno::Any& /*SyncHorizontal*/, const uno::Any& /*SyncVertical*/ )
+{
+ //#TODO #FIXME see what can be done for an implementation here
+}
+
+OUString
+ScVbaWindows::getServiceImplName()
+{
+ return "ScVbaWindows";
+}
+
+css::uno::Sequence<OUString>
+ScVbaWindows::getServiceNames()
+{
+ static uno::Sequence< OUString > const sNames
+ {
+ "ooo.vba.excel.Windows"
+ };
+ return sNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbawindows.hxx b/sc/source/ui/vba/vbawindows.hxx
new file mode 100644
index 000000000..b827bf7e4
--- /dev/null
+++ b/sc/source/ui/vba/vbawindows.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 <ooo/vba/excel/XWindows.hpp>
+
+#include <vbahelper/vbacollectionimpl.hxx>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+typedef CollTestImplHelper< ov::excel::XWindows > ScVbaWindows_BASE;
+
+class ScVbaWindows : public ScVbaWindows_BASE
+{
+public:
+ ScVbaWindows( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext );
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+
+ // XWindows
+ virtual void SAL_CALL Arrange( ::sal_Int32 ArrangeStyle, const css::uno::Any& ActiveWorkbook, const css::uno::Any& SyncHorizontal, const css::uno::Any& SyncVertical ) override;
+ // ScVbaCollectionBaseImpl
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaworkbook.cxx b/sc/source/ui/vba/vbaworkbook.cxx
new file mode 100644
index 000000000..23cc523a1
--- /dev/null
+++ b/sc/source/ui/vba/vbaworkbook.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 <sal/config.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <tools/urlobj.hxx>
+
+#include <com/sun/star/util/XProtectable.hpp>
+#include <com/sun/star/sheet/XNamedRanges.hpp>
+#include <com/sun/star/sheet/XSpreadsheetView.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <ooo/vba/excel/XlFileFormat.hpp>
+#include <ooo/vba/excel/XApplication.hpp>
+
+#include "vbaworksheet.hxx"
+#include "vbaworksheets.hxx"
+#include "vbaworkbook.hxx"
+#include "vbawindows.hxx"
+#include "vbastyles.hxx"
+#include "excelvbahelper.hxx"
+#include "vbapalette.hxx"
+#include <osl/file.hxx>
+#include "vbanames.hxx"
+#include <docoptio.hxx>
+#include <docsh.hxx>
+
+// Much of the impl. for the equivalent UNO module is
+// sc/source/ui/unoobj/docuno.cxx, viewuno.cxx
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+uno::Sequence< sal_Int32 > ScVbaWorkbook::ColorData;
+
+void SAL_CALL
+ScVbaWorkbook::ResetColors( )
+{
+ uno::Reference< container::XIndexAccess > xIndexAccess( ScVbaPalette::getDefaultPalette(), uno::UNO_SET_THROW );
+ sal_Int32 nLen = xIndexAccess->getCount();
+ ColorData.realloc( nLen );
+
+ sal_Int32* pDest = ColorData.getArray();
+ for ( sal_Int32 index=0; index < nLen; ++pDest, ++index )
+ xIndexAccess->getByIndex( index ) >>= *pDest;
+}
+
+::uno::Any SAL_CALL
+ScVbaWorkbook::Colors( const ::uno::Any& Index )
+{
+ uno::Any aRet;
+ if ( Index.hasValue() )
+ {
+ sal_Int32 nIndex = 0;
+ Index >>= nIndex;
+ aRet <<= XLRGBToOORGB( ColorData[ --nIndex ] );
+ }
+ else
+ aRet <<= ColorData;
+ return aRet;
+}
+
+bool ScVbaWorkbook::setFilterPropsFromFormat( sal_Int32 nFormat, uno::Sequence< beans::PropertyValue >& rProps )
+{
+ auto [begin, end] = asNonConstRange(rProps);
+ auto pProp = std::find_if(begin, end,
+ [](const beans::PropertyValue& rProp) { return rProp.Name == "FilterName"; });
+ bool bRes = pProp != end;
+ if (bRes)
+ {
+ switch( nFormat )
+ {
+ case excel::XlFileFormat::xlCSV:
+ pProp->Value <<= OUString(SC_TEXT_CSV_FILTER_NAME);
+ break;
+ case excel::XlFileFormat::xlDBF4:
+ pProp->Value <<= OUString("DBF");
+ break;
+ case excel::XlFileFormat::xlDIF:
+ pProp->Value <<= OUString("DIF");
+ break;
+ case excel::XlFileFormat::xlWK3:
+ pProp->Value <<= OUString("Lotus");
+ break;
+ case excel::XlFileFormat::xlExcel4Workbook:
+ pProp->Value <<= OUString("MS Excel 4.0");
+ break;
+ case excel::XlFileFormat::xlExcel5:
+ pProp->Value <<= OUString("MS Excel 5.0/95");
+ break;
+ case excel::XlFileFormat::xlHtml:
+ pProp->Value <<= OUString("HTML (StarCalc)");
+ break;
+ case excel::XlFileFormat::xlExcel9795:
+ default:
+ pProp->Value <<= OUString("MS Excel 97");
+ break;
+ }
+ }
+ return bRes;
+}
+
+::sal_Int32 SAL_CALL
+ScVbaWorkbook::getFileFormat( )
+{
+ sal_Int32 aFileFormat = 0;
+ OUString aFilterName;
+ uno::Sequence< beans::PropertyValue > aArgs = getModel()->getArgs();
+
+ // #FIXME - seems suspect should we not walk through the properties
+ // to find the FilterName
+ if ( aArgs[0].Name == "FilterName" ) {
+ aArgs[0].Value >>= aFilterName;
+ } else {
+ aArgs[1].Value >>= aFilterName;
+ }
+
+ if (aFilterName == SC_TEXT_CSV_FILTER_NAME) {
+ aFileFormat = excel::XlFileFormat::xlCSV; //xlFileFormat.
+ }
+
+ if ( aFilterName == "DBF" ) {
+ aFileFormat = excel::XlFileFormat::xlDBF4;
+ }
+
+ if ( aFilterName == "DIF" ) {
+ aFileFormat = excel::XlFileFormat::xlDIF;
+ }
+
+ if ( aFilterName == "Lotus" ) {
+ aFileFormat = excel::XlFileFormat::xlWK3;
+ }
+
+ if ( aFilterName == "MS Excel 4.0" ) {
+ aFileFormat = excel::XlFileFormat::xlExcel4Workbook;
+ }
+
+ if ( aFilterName == "MS Excel 5.0/95" ) {
+ aFileFormat = excel::XlFileFormat::xlExcel5;
+ }
+
+ if ( aFilterName == "MS Excel 97" ) {
+ aFileFormat = excel::XlFileFormat::xlExcel9795;
+ }
+
+ if (aFilterName == "HTML (StarCalc)") {
+ aFileFormat = excel::XlFileFormat::xlHtml;
+ }
+
+ if ( aFilterName == "calc_StarOffice_XML_Calc_Template" ) {
+ aFileFormat = excel::XlFileFormat::xlTemplate;
+ }
+
+ if (aFilterName == "StarOffice XML (Calc)") {
+ aFileFormat = excel::XlFileFormat::xlWorkbookNormal;
+ }
+ if ( aFilterName == "calc8" ) {
+ aFileFormat = excel::XlFileFormat::xlWorkbookNormal;
+ }
+
+ return aFileFormat;
+}
+
+void
+ScVbaWorkbook::init()
+{
+ if ( !ColorData.hasElements() )
+ ResetColors();
+ uno::Reference< frame::XModel > xModel = getModel();
+ if ( xModel.is() )
+ excel::getDocShell( xModel )->RegisterAutomationWorkbookObject( this );
+}
+
+ScVbaWorkbook::ScVbaWorkbook( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext, css::uno::Reference< css::frame::XModel > const & xModel ) : ScVbaWorkbook_BASE( xParent, xContext, xModel )
+{
+ init();
+}
+
+ScVbaWorkbook::ScVbaWorkbook( uno::Sequence< uno::Any> const & args,
+ uno::Reference< uno::XComponentContext> const & xContext ) : ScVbaWorkbook_BASE( args, xContext )
+{
+ init();
+}
+
+uno::Reference< excel::XWorksheet >
+ScVbaWorkbook::getActiveSheet()
+{
+ uno::Reference< frame::XModel > xModel( getCurrentExcelDoc( mxContext ), uno::UNO_SET_THROW );
+ uno::Reference< sheet::XSpreadsheetView > xView( xModel->getCurrentController(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheet > xSheet( xView->getActiveSheet(), uno::UNO_SET_THROW );
+ // #162503# return the original sheet module wrapper object, instead of a new instance
+ uno::Reference< excel::XWorksheet > xWorksheet( excel::getUnoSheetModuleObj( xSheet ), uno::UNO_QUERY );
+ if( xWorksheet.is() ) return xWorksheet;
+ // #i116936# excel::getUnoSheetModuleObj() may return null in documents without global VBA mode enabled
+ return new ScVbaWorksheet( this, mxContext, xSheet, xModel );
+}
+
+uno::Any SAL_CALL
+ScVbaWorkbook::Sheets( const uno::Any& aIndex )
+{
+ return Worksheets( aIndex );
+}
+
+uno::Any SAL_CALL
+ScVbaWorkbook::Worksheets( const uno::Any& aIndex )
+{
+ uno::Reference< frame::XModel > xModel( getModel() );
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( xModel, uno::UNO_QUERY_THROW );
+ uno::Reference<container::XIndexAccess > xSheets( xSpreadDoc->getSheets(), uno::UNO_QUERY_THROW );
+ uno::Reference< XCollection > xWorkSheets( new ScVbaWorksheets( this, mxContext, xSheets, xModel ) );
+ if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID )
+ {
+ return uno::Any( xWorkSheets );
+ }
+ // pass on to collection
+ return xWorkSheets->Item( aIndex, uno::Any() );
+}
+uno::Any SAL_CALL
+ScVbaWorkbook::Windows( const uno::Any& aIndex )
+{
+
+ uno::Reference< excel::XWindows > xWindows( new ScVbaWindows( getParent(), mxContext ) );
+ if ( aIndex.getValueTypeClass() == uno::TypeClass_VOID )
+ return uno::Any( xWindows );
+ return xWindows->Item( aIndex, uno::Any() );
+}
+
+void SAL_CALL
+ScVbaWorkbook::Activate()
+{
+ VbaDocumentBase::Activate();
+}
+
+void
+ScVbaWorkbook::Protect( const uno::Any &aPassword )
+{
+ VbaDocumentBase::Protect( aPassword );
+}
+
+sal_Bool
+ScVbaWorkbook::getProtectStructure()
+{
+ uno::Reference< util::XProtectable > xProt( getModel(), uno::UNO_QUERY_THROW );
+ return xProt->isProtected();
+}
+
+sal_Bool SAL_CALL ScVbaWorkbook::getPrecisionAsDisplayed()
+{
+ uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW );
+ ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument();
+ return rDoc.GetDocOptions().IsCalcAsShown();
+}
+
+void SAL_CALL ScVbaWorkbook::setPrecisionAsDisplayed( sal_Bool _precisionAsDisplayed )
+{
+ uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW );
+ ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument();
+ ScDocOptions aOpt = rDoc.GetDocOptions();
+ aOpt.SetCalcAsShown( _precisionAsDisplayed );
+ rDoc.SetDocOptions( aOpt );
+}
+
+OUString SAL_CALL ScVbaWorkbook::getAuthor()
+{
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS( getModel(), uno::UNO_QUERY );
+ if (!xDPS.is())
+ return "?";
+ uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
+ return xDocProps->getAuthor();
+}
+
+void SAL_CALL ScVbaWorkbook::setAuthor( const OUString& _author )
+{
+ uno::Reference<document::XDocumentPropertiesSupplier> xDPS( getModel(), uno::UNO_QUERY );
+ if (!xDPS.is())
+ return;
+ uno::Reference<document::XDocumentProperties> xDocProps = xDPS->getDocumentProperties();
+ xDocProps->setAuthor( _author );
+}
+
+void
+ScVbaWorkbook::SaveCopyAs( const OUString& sFileName )
+{
+ OUString aURL;
+ osl::FileBase::getFileURLFromSystemPath( sFileName, aURL );
+ uno::Reference< frame::XStorable > xStor( getModel(), uno::UNO_QUERY_THROW );
+ uno::Sequence< beans::PropertyValue > storeProps{ comphelper::makePropertyValue(
+ "FilterName", OUString( "MS Excel 97" )) };
+ xStor->storeToURL( aURL, storeProps );
+}
+
+void SAL_CALL
+ScVbaWorkbook::SaveAs( const uno::Any& FileName, const uno::Any& FileFormat, const uno::Any& /*Password*/, const uno::Any& /*WriteResPassword*/, const uno::Any& /*ReadOnlyRecommended*/, const uno::Any& /*CreateBackup*/, const uno::Any& /*AccessMode*/, const uno::Any& /*ConflictResolution*/, const uno::Any& /*AddToMru*/, const uno::Any& /*TextCodepage*/, const uno::Any& /*TextVisualLayout*/, const uno::Any& /*Local*/ )
+{
+ OUString sFileName;
+ FileName >>= sFileName;
+ OUString sURL;
+ osl::FileBase::getFileURLFromSystemPath( sFileName, sURL );
+ // detect if there is no path then we need
+ // to use the current folder
+ INetURLObject aURL( sURL );
+ sURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
+ if( sURL.isEmpty() )
+ {
+ // need to add cur dir ( of this workbook ) or else the 'Work' dir
+ sURL = getModel()->getURL();
+
+ if ( sURL.isEmpty() )
+ {
+ // not path available from 'this' document
+ // need to add the 'document'/work directory then
+ uno::Reference< excel::XApplication > xApplication ( Application(),uno::UNO_QUERY_THROW );
+ OUString sWorkPath = xApplication->getDefaultFilePath();
+ OUString sWorkURL;
+ osl::FileBase::getFileURLFromSystemPath( sWorkPath, sWorkURL );
+ aURL.SetURL( sWorkURL );
+ }
+ else
+ {
+ aURL.SetURL( sURL );
+ aURL.Append( sFileName );
+ }
+ sURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::ToIUri );
+
+ }
+
+ sal_Int32 nFileFormat = excel::XlFileFormat::xlExcel9795;
+ FileFormat >>= nFileFormat;
+
+ uno::Sequence storeProps{ comphelper::makePropertyValue("FilterName", uno::Any()) };
+ setFilterPropsFromFormat( nFileFormat, storeProps );
+
+ uno::Reference< frame::XStorable > xStor( getModel(), uno::UNO_QUERY_THROW );
+ xStor->storeAsURL( sURL, storeProps );
+}
+
+css::uno::Any SAL_CALL
+ScVbaWorkbook::Styles( const uno::Any& Item )
+{
+ // quick look and Styles object doesn't seem to have a valid parent
+ // or a least the object browser just shows an object that has no
+ // variables ( therefore... leave as NULL for now )
+ uno::Reference< XCollection > dStyles = new ScVbaStyles( uno::Reference< XHelperInterface >(), mxContext, getModel() );
+ if ( Item.hasValue() )
+ return dStyles->Item( Item, uno::Any() );
+ return uno::Any( dStyles );
+}
+
+uno::Any SAL_CALL
+ScVbaWorkbook::Names( const uno::Any& aIndex )
+{
+ uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW );
+ uno::Reference< beans::XPropertySet > xProps( xModel, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XNamedRanges > xNamedRanges( xProps->getPropertyValue("NamedRanges"), uno::UNO_QUERY_THROW );
+ uno::Reference< XCollection > xNames( new ScVbaNames( this, mxContext, xNamedRanges, xModel ) );
+ if ( aIndex.hasValue() )
+ return xNames->Item( aIndex, uno::Any() );
+ return uno::Any( xNames );
+}
+
+OUString
+ScVbaWorkbook::getServiceImplName()
+{
+ return "ScVbaWorkbook";
+}
+
+uno::Sequence< OUString >
+ScVbaWorkbook::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Workbook"
+ };
+ return aServiceNames;
+}
+
+OUString SAL_CALL
+ScVbaWorkbook::getCodeName()
+{
+ uno::Reference< beans::XPropertySet > xModelProp( getModel(), uno::UNO_QUERY_THROW );
+ return xModelProp->getPropertyValue("CodeName").get< OUString >();
+}
+
+sal_Int64
+ScVbaWorkbook::getSomething(const uno::Sequence<sal_Int8 >& rId )
+{
+ if (comphelper::isUnoTunnelId<ScVbaWorksheet>(rId)) // ???
+ {
+ return comphelper::getSomething_cast(this);
+ }
+ return 0;
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_ScVbaWorkbook_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args)
+{
+ return cppu::acquire(new ScVbaWorkbook(args, context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaworkbook.hxx b/sc/source/ui/vba/vbaworkbook.hxx
new file mode 100644
index 000000000..886f771bf
--- /dev/null
+++ b/sc/source/ui/vba/vbaworkbook.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 <com/sun/star/frame/XModel.hpp>
+#include <ooo/vba/excel/XWorkbook.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <vbahelper/vbadocumentbase.hxx>
+
+typedef cppu::ImplInheritanceHelper< VbaDocumentBase, ov::excel::XWorkbook > ScVbaWorkbook_BASE;
+
+class ScVbaWorkbook : public ScVbaWorkbook_BASE
+{
+ static css::uno::Sequence< sal_Int32 > ColorData;
+ static bool setFilterPropsFromFormat( sal_Int32 nFormat, css::uno::Sequence< css::beans::PropertyValue >& rProps );
+ void init();
+
+public:
+ ScVbaWorkbook( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ css::uno::Reference< css::frame::XModel > const & xModel );
+ ScVbaWorkbook( css::uno::Sequence< css::uno::Any > const& aArgs, css::uno::Reference< css::uno::XComponentContext >const& xContext );
+
+ // Attributes
+ virtual sal_Bool SAL_CALL getProtectStructure() override;
+ virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getActiveSheet() override;
+ virtual sal_Bool SAL_CALL getPrecisionAsDisplayed() override;
+ virtual void SAL_CALL setPrecisionAsDisplayed( sal_Bool _precisionAsDisplayed ) override;
+ virtual OUString SAL_CALL getAuthor() override;
+ virtual void SAL_CALL setAuthor( const OUString& _author ) override;
+
+ // Methods
+ virtual css::uno::Any SAL_CALL Worksheets( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL Sheets( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL Windows( const css::uno::Any& aIndex ) override;
+ virtual void SAL_CALL Activate() override;
+ virtual void SAL_CALL Protect( const css::uno::Any & aPassword ) override;
+ virtual void SAL_CALL SaveAs( const css::uno::Any& FileName, const css::uno::Any& FileFormat, const css::uno::Any& Password, const css::uno::Any& WriteResPassword, const css::uno::Any& ReadOnlyRecommended, const css::uno::Any& CreateBackup, const css::uno::Any& AccessMode, const css::uno::Any& ConflictResolution, const css::uno::Any& AddToMru, const css::uno::Any& TextCodepage, const css::uno::Any& TextVisualLayout, const css::uno::Any& Local ) override;
+ virtual css::uno::Any SAL_CALL Names( const css::uno::Any& aIndex ) override;
+
+ virtual css::uno::Any SAL_CALL Styles( const css::uno::Any& Item ) override;
+ virtual void SAL_CALL ResetColors( ) override;
+ virtual css::uno::Any SAL_CALL Colors( const css::uno::Any& Index ) override;
+ virtual ::sal_Int32 SAL_CALL getFileFormat( ) override;
+ virtual void SAL_CALL SaveCopyAs( const OUString& Filename ) override;
+
+ // code name
+ virtual OUString SAL_CALL getCodeName() override;
+
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+ // XUnoTunnel
+ virtual ::sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8 >& rId ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaworkbooks.cxx b/sc/source/ui/vba/vbaworkbooks.cxx
new file mode 100644
index 000000000..e3b608b33
--- /dev/null
+++ b/sc/source/ui/vba/vbaworkbooks.cxx
@@ -0,0 +1,291 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/document/XTypeDetection.hpp>
+
+#include <tools/urlobj.hxx>
+
+#include "excelvbahelper.hxx"
+#include "vbaworkbook.hxx"
+#include "vbaworkbooks.hxx"
+#include <vbahelper/vbahelper.hxx>
+
+#include <comphelper/propertyvalue.hxx>
+#include <o3tl/string_view.hxx>
+#include <osl/file.hxx>
+#include <rtl/ref.hxx>
+
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+const sal_Int16 CUSTOM_CHAR = 5;
+
+static uno::Any
+getWorkbook( const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< sheet::XSpreadsheetDocument > &xDoc,
+ const uno::Reference< XHelperInterface >& xParent )
+{
+ // FIXME: fine as long as ScVbaWorkbook is stateless ...
+ uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY );
+ if( !xModel.is() )
+ return uno::Any();
+
+ uno::Reference< excel::XWorkbook > xWb( getVBADocument( xModel ), uno::UNO_QUERY );
+ if ( xWb.is() )
+ {
+ return uno::Any( xWb );
+ }
+
+ rtl::Reference<ScVbaWorkbook> pWb = new ScVbaWorkbook( xParent, xContext, xModel );
+ return uno::Any( uno::Reference< excel::XWorkbook > (pWb) );
+}
+
+namespace {
+
+class WorkBookEnumImpl : public EnumerationHelperImpl
+{
+public:
+ /// @throws uno::RuntimeException
+ WorkBookEnumImpl( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ) {}
+
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ uno::Reference< sheet::XSpreadsheetDocument > xDoc( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW );
+ return getWorkbook( m_xContext, xDoc, m_xParent );
+ }
+
+};
+
+}
+
+ScVbaWorkbooks::ScVbaWorkbooks( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext >& xContext ) : ScVbaWorkbooks_BASE( xParent, xContext, VbaDocumentsBase::EXCEL_DOCUMENT )
+{
+}
+// XEnumerationAccess
+uno::Type
+ScVbaWorkbooks::getElementType()
+{
+ return cppu::UnoType<excel::XWorkbook>::get();
+}
+uno::Reference< container::XEnumeration >
+ScVbaWorkbooks::createEnumeration()
+{
+ // #FIXME it's possible the WorkBookEnumImpl here doesn't reflect
+ // the state of this object ( although it should ) would be
+ // safer to create an enumeration based on this objects state
+ // rather than one effectively based of the desktop component
+ uno::Reference< container::XEnumerationAccess > xEnumerationAccess( m_xIndexAccess, uno::UNO_QUERY_THROW );
+ return new WorkBookEnumImpl( mxParent, mxContext, xEnumerationAccess->createEnumeration() );
+}
+
+uno::Any
+ScVbaWorkbooks::createCollectionObject( const css::uno::Any& aSource )
+{
+ uno::Reference< sheet::XSpreadsheetDocument > xDoc( aSource, uno::UNO_QUERY_THROW );
+ return getWorkbook( mxContext, xDoc, mxParent );
+}
+
+uno::Any SAL_CALL
+ScVbaWorkbooks::Add( const uno::Any& Template )
+{
+ uno::Reference< sheet::XSpreadsheetDocument > xSpreadDoc;
+ sal_Int32 nWorkbookType = 0;
+ OUString aTemplateFileName;
+ if( Template >>= nWorkbookType )
+ {
+ // nWorkbookType is a constant from XlWBATemplate (added in Excel 2007)
+ // TODO: create chart-sheet if supported by Calc
+
+ xSpreadDoc.set( createDocument(), uno::UNO_QUERY_THROW );
+ // create a document with one sheet only
+ uno::Reference< sheet::XSpreadsheets > xSheets( xSpreadDoc->getSheets(), uno::UNO_SET_THROW );
+ uno::Reference< container::XIndexAccess > xSheetsIA( xSheets, uno::UNO_QUERY_THROW );
+ while( xSheetsIA->getCount() > 1 )
+ {
+ uno::Reference< container::XNamed > xSheetName( xSheetsIA->getByIndex( xSheetsIA->getCount() - 1 ), uno::UNO_QUERY_THROW );
+ xSheets->removeByName( xSheetName->getName() );
+ }
+ }
+ else if( Template >>= aTemplateFileName )
+ {
+ // TODO: create document from template
+ xSpreadDoc.set( createDocument(), uno::UNO_QUERY_THROW );
+ }
+ else if( !Template.hasValue() )
+ {
+ // regular spreadsheet document with configured number of sheets
+ xSpreadDoc.set( createDocument(), uno::UNO_QUERY_THROW );
+ }
+ else
+ {
+ // illegal argument
+ throw uno::RuntimeException();
+ }
+
+ // need to set up the document modules ( and vba mode ) here
+ excel::setUpDocumentModules( xSpreadDoc );
+ if (!xSpreadDoc.is())
+ return uno::Any();
+
+ uno::Any aRet = getWorkbook( mxContext, xSpreadDoc, mxParent );
+ uno::Reference< excel::XWorkbook > xWBook( aRet, uno::UNO_QUERY );
+ if (xWBook.is())
+ xWBook->Activate();
+ return aRet;
+}
+
+void SAL_CALL
+ScVbaWorkbooks::Close()
+{
+}
+
+bool
+ScVbaWorkbooks::isTextFile( std::u16string_view sType )
+{
+ // will return true if the file is
+ // a) a variant of a text file
+ // b) a csv file
+ // c) unknown
+ // returning true basically means treat this like a csv file
+ return sType == u"generic_Text" || sType.empty();
+}
+
+bool
+ScVbaWorkbooks::isSpreadSheetFile( std::u16string_view sType )
+{
+ // include calc_QPro etc. ? ( not for the moment anyway )
+ return o3tl::starts_with( sType, u"calc_MS" )
+ || o3tl::starts_with( sType, u"MS Excel" )
+ || o3tl::starts_with( sType, u"calc8" )
+ || o3tl::starts_with( sType, u"calc_StarOffice" );
+}
+
+OUString
+ScVbaWorkbooks::getFileFilterType( const OUString& rFileName )
+{
+ uno::Reference< document::XTypeDetection > xTypeDetect( mxContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", mxContext), uno::UNO_QUERY_THROW );
+ uno::Sequence aMediaDesc{ comphelper::makePropertyValue("URL", rFileName) };
+ OUString sType = xTypeDetect->queryTypeByDescriptor( aMediaDesc, true );
+ return sType;
+}
+
+// #TODO# #FIXME# can any of the unused params below be used?
+uno::Any SAL_CALL
+ScVbaWorkbooks::Open( const OUString& rFileName, const uno::Any& /*UpdateLinks*/, const uno::Any& ReadOnly, const uno::Any& Format, const uno::Any& /*Password*/, const uno::Any& /*WriteResPassword*/, const uno::Any& /*IgnoreReadOnlyRecommended*/, const uno::Any& /*Origin*/, const uno::Any& Delimiter, const uno::Any& /*Editable*/, const uno::Any& /*Notify*/, const uno::Any& /*Converter*/, const uno::Any& /*AddToMru*/ )
+{
+ // we need to detect if this is a URL, if not then assume it's a file path
+ OUString aURL;
+ INetURLObject aObj;
+ aObj.SetURL( rFileName );
+ bool bIsURL = aObj.GetProtocol() != INetProtocol::NotValid;
+ if ( bIsURL )
+ aURL = rFileName;
+ else
+ osl::FileBase::getFileURLFromSystemPath( rFileName, aURL );
+
+ uno::Sequence< beans::PropertyValue > sProps;
+
+ OUString sType = getFileFilterType( aURL );
+ // A text file means it needs to be processed as a csv file
+ if ( isTextFile( sType ) )
+ {
+ // Values for format
+ // 1 Tabs
+ // 2 Commas
+ // 3 Spaces
+ // 4 Semicolons
+ // 5 Nothing
+ // 6 Custom character (see the Delimiter argument
+ // no format means use the current delimiter
+ sal_Int16 const delims[] { 0 /*default not used*/, 9/*tab*/, 44/*comma*/, 32/*space*/, 59/*semicolon*/ };
+
+ OUString sFormat;
+ sal_Int16 nFormat = 0; // default indicator
+
+ if ( Format.hasValue() )
+ {
+ Format >>= nFormat; // val of nFormat overwritten if extracted
+ // validate param
+ if ( nFormat < 1 || nFormat > 6 )
+ throw uno::RuntimeException("Illegal value for Format" );
+ }
+
+ sal_Int16 nDelim = getCurrentDelim();
+
+ if ( nFormat > 0 && nFormat < CUSTOM_CHAR )
+ {
+ nDelim = delims[ nFormat ];
+ }
+ else if ( nFormat > CUSTOM_CHAR )
+ {
+ // Need to check Delimiter param
+ if ( !Delimiter.hasValue() )
+ throw uno::RuntimeException("Expected value for Delimiter" );
+ OUString sStr;
+ Delimiter >>= sStr;
+ if ( sStr.isEmpty() )
+ throw uno::RuntimeException("Incorrect value for Delimiter" );
+
+ nDelim = sStr[0];
+
+ }
+
+ getCurrentDelim() = nDelim; //set new current
+
+ sFormat = OUString::number( nDelim ) + ",34,0,1";
+
+ sProps = { comphelper::makePropertyValue("FilterOptions", sFormat),
+ comphelper::makePropertyValue("FilterName", OUString( SC_TEXT_CSV_FILTER_NAME )),
+ // Ensure WORKAROUND_CSV_TXT_BUG_i60158 gets called in typedetection.cxx so
+ // csv is forced for deep detected 'writerxxx' types
+ comphelper::makePropertyValue(
+ "DocumentService", OUString("com.sun.star.sheet.SpreadsheetDocument")) };
+ }
+ else if ( !isSpreadSheetFile( sType ) )
+ throw uno::RuntimeException("Bad Format" );
+
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( openDocument( rFileName, ReadOnly, sProps ), uno::UNO_QUERY_THROW );
+ uno::Any aRet = getWorkbook( mxContext, xSpreadDoc, mxParent );
+ uno::Reference< excel::XWorkbook > xWBook( aRet, uno::UNO_QUERY );
+ if ( xWBook.is() )
+ xWBook->Activate();
+ return aRet;
+}
+
+OUString
+ScVbaWorkbooks::getServiceImplName()
+{
+ return "ScVbaWorkbooks";
+}
+
+css::uno::Sequence<OUString>
+ScVbaWorkbooks::getServiceNames()
+{
+ static uno::Sequence< OUString > const sNames
+ {
+ "ooo.vba.excel.Workbooks"
+ };
+ return sNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaworkbooks.hxx b/sc/source/ui/vba/vbaworkbooks.hxx
new file mode 100644
index 000000000..45d41757a
--- /dev/null
+++ b/sc/source/ui/vba/vbaworkbooks.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 <sal/config.h>
+
+#include <string_view>
+
+#include <cppuhelper/implbase.hxx>
+#include <ooo/vba/excel/XWorkbooks.hpp>
+#include <vbahelper/vbadocumentsbase.hxx>
+
+typedef cppu::ImplInheritanceHelper< VbaDocumentsBase, ov::excel::XWorkbooks > ScVbaWorkbooks_BASE;
+
+class ScVbaWorkbooks : public ScVbaWorkbooks_BASE
+{
+private:
+ OUString getFileFilterType( const OUString& rString );
+ static bool isTextFile( std::u16string_view rString );
+ static bool isSpreadSheetFile( std::u16string_view rString );
+ static sal_Int16& getCurrentDelim(){ static sal_Int16 nDelim = 44; return nDelim; }
+public:
+ ScVbaWorkbooks( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext );
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+
+ // ScVbaWorkbooks_BASE
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+ // XWorkbooks
+ virtual css::uno::Any SAL_CALL Add( const css::uno::Any& Template ) override;
+ virtual void SAL_CALL Close( ) override;
+ virtual css::uno::Any SAL_CALL Open( const OUString& Filename, const css::uno::Any& UpdateLinks, const css::uno::Any& ReadOnly, const css::uno::Any& Format, const css::uno::Any& Password, const css::uno::Any& WriteResPassword, const css::uno::Any& IgnoreReadOnlyRecommended, const css::uno::Any& Origin, const css::uno::Any& Delimiter, const css::uno::Any& Editable, const css::uno::Any& Notify, const css::uno::Any& Converter, const css::uno::Any& AddToMru ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaworksheet.cxx b/sc/source/ui/vba/vbaworksheet.cxx
new file mode 100644
index 000000000..c51284427
--- /dev/null
+++ b/sc/source/ui/vba/vbaworksheet.cxx
@@ -0,0 +1,1052 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <string_view>
+
+#include "vbaworksheet.hxx"
+#include "vbanames.hxx"
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XIntrospectionAccess.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/util/XProtectable.hpp>
+#include <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/sheet/XSpreadsheetView.hpp>
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/sheet/XCalculatable.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <com/sun/star/sheet/XSheetCellRange.hpp>
+#include <com/sun/star/sheet/XSheetCellCursor.hpp>
+#include <com/sun/star/sheet/XSheetAnnotationsSupplier.hpp>
+#include <com/sun/star/sheet/XUsedAreaCursor.hpp>
+#include <com/sun/star/sheet/XSpreadsheets.hpp>
+#include <com/sun/star/sheet/XSheetOutline.hpp>
+#include <com/sun/star/sheet/XSheetPageBreak.hpp>
+#include <com/sun/star/sheet/XDataPilotTablesSupplier.hpp>
+#include <com/sun/star/sheet/XNamedRanges.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/table/XTableChartsSupplier.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/drawing/XControlShape.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <ooo/vba/excel/XApplication.hpp>
+#include <ooo/vba/excel/XlEnableSelection.hpp>
+#include <ooo/vba/excel/XlSheetVisibility.hpp>
+#include <ooo/vba/XControlProvider.hpp>
+
+#include <basic/sberrors.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <vbahelper/vbashapes.hxx>
+
+//zhangyun showdataform
+#include <scabstdlg.hxx>
+#include <tabvwsh.hxx>
+
+#include <tabprotection.hxx>
+#include "excelvbahelper.hxx"
+#include "vbaoutline.hxx"
+#include "vbarange.hxx"
+#include "vbacomments.hxx"
+#include "vbachartobjects.hxx"
+#include "vbapivottables.hxx"
+#include "vbaoleobjects.hxx"
+#include "vbapagesetup.hxx"
+#include "vbapagebreaks.hxx"
+#include "vbaworksheets.hxx"
+#include "vbahyperlinks.hxx"
+#include "vbasheetobjects.hxx"
+#include <dbdata.hxx>
+
+#include <attrib.hxx>
+
+#define STANDARDWIDTH 2267
+#define STANDARDHEIGHT 427
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+static void getNewSpreadsheetName (OUString &aNewName, std::u16string_view aOldName, const uno::Reference <sheet::XSpreadsheetDocument>& xSpreadDoc )
+{
+ if (!xSpreadDoc.is())
+ throw lang::IllegalArgumentException( "getNewSpreadsheetName() xSpreadDoc is null", uno::Reference< uno::XInterface >(), 1 );
+ static const char aUnderScore[] = "_";
+ int currentNum =2;
+ aNewName = OUString::Concat(aOldName) + aUnderScore + OUString::number(currentNum) ;
+ SCTAB nTab = 0;
+ while ( ScVbaWorksheets::nameExists(xSpreadDoc,aNewName, nTab ) )
+ {
+ aNewName = OUString::Concat(aOldName) + aUnderScore + OUString::number(++currentNum);
+ }
+}
+
+static void removeAllSheets( const uno::Reference <sheet::XSpreadsheetDocument>& xSpreadDoc, const OUString& aSheetName)
+{
+ if (!xSpreadDoc.is())
+ throw lang::IllegalArgumentException( "removeAllSheets() xSpreadDoc is null", uno::Reference< uno::XInterface >(), 1 );
+ uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets();
+ uno::Reference <container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY );
+
+ if ( !xIndex.is() )
+ return;
+
+ uno::Reference<container::XNameContainer> xNameContainer(xSheets,uno::UNO_QUERY_THROW);
+ for (sal_Int32 i = xIndex->getCount() -1; i>= 1; i--)
+ {
+ uno::Reference< sheet::XSpreadsheet > xSheet(xIndex->getByIndex(i), uno::UNO_QUERY);
+ uno::Reference< container::XNamed > xNamed( xSheet, uno::UNO_QUERY_THROW );
+ xNameContainer->removeByName(xNamed->getName());
+ }
+
+ uno::Reference< sheet::XSpreadsheet > xSheet(xIndex->getByIndex(0), uno::UNO_QUERY);
+ uno::Reference< container::XNamed > xNamed( xSheet, uno::UNO_QUERY_THROW );
+ xNamed->setName(aSheetName);
+}
+
+static uno::Reference<frame::XModel>
+openNewDoc(const OUString& aSheetName )
+{
+ uno::Reference<frame::XModel> xModel;
+ try
+ {
+ uno::Reference< uno::XComponentContext > xContext(
+ comphelper::getProcessComponentContext() );
+
+ uno::Reference <frame::XDesktop2 > xComponentLoader = frame::Desktop::create(xContext);
+
+ uno::Reference<lang::XComponent > xComponent( xComponentLoader->loadComponentFromURL(
+ "private:factory/scalc",
+ "_blank", 0,
+ uno::Sequence < css::beans::PropertyValue >() ) );
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( xComponent, uno::UNO_QUERY_THROW );
+ removeAllSheets(xSpreadDoc,aSheetName);
+ xModel.set(xSpreadDoc,uno::UNO_QUERY_THROW);
+ }
+ catch ( uno::Exception & /*e*/ )
+ {
+ }
+ return xModel;
+}
+
+ScVbaWorksheet::ScVbaWorksheet(const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext,
+ const uno::Reference< sheet::XSpreadsheet >& xSheet,
+ const uno::Reference< frame::XModel >& xModel ) : WorksheetImpl_BASE( xParent, xContext ), mxSheet( xSheet ), mxModel(xModel), mbVeryHidden( false )
+{
+}
+
+ScVbaWorksheet::ScVbaWorksheet( uno::Sequence< uno::Any> const & args,
+ uno::Reference< uno::XComponentContext> const & xContext ) : WorksheetImpl_BASE( getXSomethingFromArgs< XHelperInterface >( args, 0 ), xContext ), mxModel( getXSomethingFromArgs< frame::XModel >( args, 1 ) ), mbVeryHidden( false )
+{
+ if ( args.getLength() < 3 )
+ throw lang::IllegalArgumentException();
+
+ OUString sSheetName;
+ args[2] >>= sSheetName;
+
+ uno::Reference< sheet::XSpreadsheetDocument > xSpreadDoc( mxModel, uno::UNO_QUERY_THROW );
+ uno::Reference< container::XNameAccess > xNameAccess( xSpreadDoc->getSheets(), uno::UNO_QUERY_THROW );
+ mxSheet.set( xNameAccess->getByName( sSheetName ), uno::UNO_QUERY_THROW );
+}
+
+ScVbaWorksheet::~ScVbaWorksheet()
+{
+}
+
+const uno::Sequence<sal_Int8>& ScVbaWorksheet::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit theScVbaWorksheetUnoTunnelId;
+ return theScVbaWorksheetUnoTunnelId.getSeq();
+}
+
+uno::Reference< ov::excel::XWorksheet >
+ScVbaWorksheet::createSheetCopyInNewDoc(const OUString& aCurrSheetName)
+{
+ uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = getSheet()->createCursor( );
+ uno::Reference<sheet::XUsedAreaCursor> xUsedCursor(xSheetCellCursor,uno::UNO_QUERY_THROW);
+ uno::Reference<excel::XRange> xRange = new ScVbaRange( this, mxContext, xSheetCellCursor);
+ if (xRange.is())
+ xRange->Select();
+ excel::implnCopy(mxModel);
+ uno::Reference<frame::XModel> xModel = openNewDoc(aCurrSheetName);
+ if (xModel.is())
+ {
+ excel::implnPaste(xModel);
+ }
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( xModel, uno::UNO_QUERY_THROW );
+ excel::setUpDocumentModules(xSpreadDoc);
+ uno::Reference <sheet::XSpreadsheets> xSheets( xSpreadDoc->getSheets(), uno::UNO_SET_THROW );
+ uno::Reference <container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSpreadsheet > xSheet(xIndex->getByIndex(0), uno::UNO_QUERY_THROW);
+
+ ScDocShell* pShell = excel::getDocShell( xModel );
+ OUString aCodeName;
+ pShell->GetDocument().GetCodeName( 0, aCodeName );
+ return uno::Reference< excel::XWorksheet >( getUnoDocModule( aCodeName, pShell ), uno::UNO_QUERY_THROW );
+}
+
+css::uno::Reference< ov::excel::XWorksheet >
+ScVbaWorksheet::createSheetCopy(uno::Reference<excel::XWorksheet> const & xSheet, bool bAfter)
+{
+ OUString aCurrSheetName = getName();
+ ScVbaWorksheet* pDestSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSheet );
+
+ uno::Reference <sheet::XSpreadsheetDocument> xDestDoc( pDestSheet->getModel(), uno::UNO_QUERY );
+ uno::Reference <sheet::XSpreadsheetDocument> xSrcDoc( getModel(), uno::UNO_QUERY );
+
+ SCTAB nDest = 0;
+ SCTAB nSrc = 0;
+ OUString aSheetName = xSheet->getName();
+ bool bSameDoc = ( pDestSheet->getModel() == getModel() );
+ bool bDestSheetExists = ScVbaWorksheets::nameExists (xDestDoc, aSheetName, nDest );
+ bool bSheetExists = ScVbaWorksheets::nameExists (xSrcDoc, aCurrSheetName, nSrc );
+
+ // set sheet name to be newSheet name
+ aSheetName = aCurrSheetName;
+ if ( bSheetExists && bDestSheetExists )
+ {
+ SCTAB nDummy=0;
+ if(bAfter)
+ nDest++;
+ uno::Reference<sheet::XSpreadsheets> xSheets = xDestDoc->getSheets();
+ if ( bSameDoc || ScVbaWorksheets::nameExists( xDestDoc, aCurrSheetName, nDummy ) )
+ getNewSpreadsheetName(aSheetName,aCurrSheetName,xDestDoc);
+ if ( bSameDoc )
+ xSheets->copyByName(aCurrSheetName,aSheetName,nDest);
+ else
+ {
+ ScDocShell* pDestDocShell = excel::getDocShell( pDestSheet->getModel() );
+ ScDocShell* pSrcDocShell = excel::getDocShell( getModel() );
+ if ( pDestDocShell && pSrcDocShell )
+ pDestDocShell->TransferTab( *pSrcDocShell, nSrc, nDest, true, true );
+ }
+ }
+ // return new sheet
+ uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XWorksheet > xNewSheet( xApplication->Worksheets( uno::Any( aSheetName ) ), uno::UNO_QUERY_THROW );
+ return xNewSheet;
+}
+
+OUString
+ScVbaWorksheet::getName()
+{
+ uno::Reference< container::XNamed > xNamed( getSheet(), uno::UNO_QUERY_THROW );
+ return xNamed->getName();
+}
+
+void
+ScVbaWorksheet::setName(const OUString &rName )
+{
+ uno::Reference< container::XNamed > xNamed( getSheet(), uno::UNO_QUERY_THROW );
+ xNamed->setName( rName );
+}
+
+sal_Int32
+ScVbaWorksheet::getVisible()
+{
+ uno::Reference< beans::XPropertySet > xProps( getSheet(), uno::UNO_QUERY_THROW );
+ bool bVisible = false;
+ xProps->getPropertyValue( "IsVisible" ) >>= bVisible;
+ using namespace ::ooo::vba::excel::XlSheetVisibility;
+ return bVisible ? xlSheetVisible : (mbVeryHidden ? xlSheetVeryHidden : xlSheetHidden);
+}
+
+void
+ScVbaWorksheet::setVisible( sal_Int32 nVisible )
+{
+ using namespace ::ooo::vba::excel::XlSheetVisibility;
+ bool bVisible = true;
+ switch( nVisible )
+ {
+ case xlSheetVisible: case 1: // Excel accepts -1 and 1 for visible sheets
+ bVisible = true;
+ mbVeryHidden = false;
+ break;
+ case xlSheetHidden:
+ bVisible = false;
+ mbVeryHidden = false;
+ break;
+ case xlSheetVeryHidden:
+ bVisible = false;
+ mbVeryHidden = true;
+ break;
+ default:
+ throw uno::RuntimeException();
+ }
+ uno::Reference< beans::XPropertySet > xProps( getSheet(), uno::UNO_QUERY_THROW );
+ xProps->setPropertyValue( "IsVisible", uno::Any( bVisible ) );
+}
+
+sal_Int16
+ScVbaWorksheet::getIndex()
+{
+ return getSheetID() + 1;
+}
+
+sal_Int32
+ScVbaWorksheet::getEnableSelection()
+{
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW );
+ SCTAB nTab = 0;
+ if ( !ScVbaWorksheets::nameExists(xSpreadDoc, getName(), nTab) )
+ throw uno::RuntimeException("Sheet Name does not exist." );
+
+ uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW );
+ ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument();
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ bool bLockedCells = false;
+ bool bUnlockedCells = false;
+ if( pProtect )
+ {
+ bLockedCells = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
+ bUnlockedCells = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
+ }
+ if( bLockedCells )
+ return excel::XlEnableSelection::xlNoRestrictions;
+ if( bUnlockedCells )
+ return excel::XlEnableSelection::xlUnlockedCells;
+ return excel::XlEnableSelection::xlNoSelection;
+
+}
+
+void
+ScVbaWorksheet::setEnableSelection( sal_Int32 nSelection )
+{
+ if( (nSelection != excel::XlEnableSelection::xlNoRestrictions) &&
+ (nSelection != excel::XlEnableSelection::xlUnlockedCells) &&
+ (nSelection != excel::XlEnableSelection::xlNoSelection) )
+ {
+ DebugHelper::runtimeexception(ERRCODE_BASIC_BAD_PARAMETER);
+ }
+
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW );
+ SCTAB nTab = 0;
+ if ( !ScVbaWorksheets::nameExists(xSpreadDoc, getName(), nTab) )
+ throw uno::RuntimeException("Sheet Name does not exist." );
+
+ uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW );
+ ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument();
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ // default is xlNoSelection
+ bool bLockedCells = false;
+ bool bUnlockedCells = false;
+ if( nSelection == excel::XlEnableSelection::xlNoRestrictions )
+ {
+ bLockedCells = true;
+ bUnlockedCells = true;
+ }
+ else if( nSelection == excel::XlEnableSelection::xlUnlockedCells )
+ {
+ bUnlockedCells = true;
+ }
+ if( pProtect )
+ {
+ ScTableProtection aNewProtect(*pProtect);
+ aNewProtect.setOption(ScTableProtection::SELECT_LOCKED_CELLS, bLockedCells);
+ aNewProtect.setOption(ScTableProtection::SELECT_UNLOCKED_CELLS, bUnlockedCells);
+ rDoc.SetTabProtection(nTab, &aNewProtect);
+ }
+
+
+}
+
+sal_Bool SAL_CALL ScVbaWorksheet::getAutoFilterMode()
+{
+ uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW );
+ ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument();
+ ScDBData* pDBData = rDoc.GetAnonymousDBData(getSheetID());
+ if (pDBData)
+ return pDBData->HasAutoFilter();
+ return false;
+}
+
+void SAL_CALL ScVbaWorksheet::setAutoFilterMode( sal_Bool bAutoFilterMode )
+{
+ uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW );
+ ScDocShell* pDocShell = excel::getDocShell( xModel );
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDBData* pDBData = rDoc.GetAnonymousDBData(getSheetID());
+ if (!pDBData)
+ return;
+
+ pDBData->SetAutoFilter(bAutoFilterMode);
+ ScRange aRange;
+ pDBData->GetArea(aRange);
+ if (bAutoFilterMode)
+ rDoc.ApplyFlagsTab( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab(), ScMF::Auto );
+ else if (!bAutoFilterMode)
+ rDoc.RemoveFlagsTab(aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aStart.Row(),
+ aRange.aStart.Tab(), ScMF::Auto );
+ ScRange aPaintRange(aRange.aStart, aRange.aEnd);
+ aPaintRange.aEnd.SetRow(aPaintRange.aStart.Row());
+ pDocShell->PostPaint(aPaintRange, PaintPartFlags::Grid);
+}
+
+uno::Reference< excel::XRange >
+ScVbaWorksheet::getUsedRange()
+{
+ uno::Reference< sheet::XSheetCellRange > xSheetCellRange(getSheet(), uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor( getSheet()->createCursorByRange( xSheetCellRange ), uno::UNO_SET_THROW );
+ uno::Reference<sheet::XUsedAreaCursor> xUsedCursor(xSheetCellCursor,uno::UNO_QUERY_THROW);
+ xUsedCursor->gotoStartOfUsedArea( false );
+ xUsedCursor->gotoEndOfUsedArea( true );
+ return new ScVbaRange(this, mxContext, xSheetCellCursor);
+}
+
+uno::Reference< excel::XOutline >
+ScVbaWorksheet::Outline( )
+{
+ uno::Reference<sheet::XSheetOutline> xOutline(getSheet(),uno::UNO_QUERY_THROW);
+ return new ScVbaOutline( this, mxContext, xOutline);
+}
+
+uno::Reference< excel::XPageSetup >
+ScVbaWorksheet::PageSetup( )
+{
+ return new ScVbaPageSetup( this, mxContext, getSheet(), getModel() );
+}
+
+uno::Any
+ScVbaWorksheet::HPageBreaks( const uno::Any& aIndex )
+{
+ uno::Reference< sheet::XSheetPageBreak > xSheetPageBreak(getSheet(),uno::UNO_QUERY_THROW);
+ uno::Reference< excel::XHPageBreaks > xHPageBreaks( new ScVbaHPageBreaks( this, mxContext, xSheetPageBreak));
+ if ( aIndex.hasValue() )
+ return xHPageBreaks->Item( aIndex, uno::Any());
+ return uno::Any( xHPageBreaks );
+}
+
+uno::Any
+ScVbaWorksheet::VPageBreaks( const uno::Any& aIndex )
+{
+ uno::Reference< sheet::XSheetPageBreak > xSheetPageBreak( getSheet(), uno::UNO_QUERY_THROW );
+ uno::Reference< excel::XVPageBreaks > xVPageBreaks( new ScVbaVPageBreaks( this, mxContext, xSheetPageBreak ) );
+ if( aIndex.hasValue() )
+ return xVPageBreaks->Item( aIndex, uno::Any());
+ return uno::Any( xVPageBreaks );
+}
+
+sal_Int32
+ScVbaWorksheet::getStandardWidth()
+{
+ return STANDARDWIDTH ;
+}
+
+sal_Int32
+ScVbaWorksheet::getStandardHeight()
+{
+ return STANDARDHEIGHT;
+}
+
+sal_Bool
+ScVbaWorksheet::getProtectionMode()
+{
+ return false;
+}
+
+sal_Bool
+ScVbaWorksheet::getProtectContents()
+{
+ uno::Reference<util::XProtectable > xProtectable(getSheet(), uno::UNO_QUERY_THROW);
+ return xProtectable->isProtected();
+}
+
+sal_Bool
+ScVbaWorksheet::getProtectDrawingObjects()
+{
+ SCTAB nTab = 0;
+ OUString aSheetName = getName();
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW );
+ bool bSheetExists = ScVbaWorksheets::nameExists (xSpreadDoc, aSheetName, nTab);
+ if ( bSheetExists )
+ {
+ uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW );
+ ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument();
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ if ( pProtect )
+ return pProtect->isOptionEnabled( ScTableProtection::OBJECTS );
+ }
+ return false;
+}
+
+sal_Bool
+ScVbaWorksheet::getProtectScenarios()
+{
+ return false;
+}
+
+void
+ScVbaWorksheet::Activate()
+{
+ uno::Reference< sheet::XSpreadsheetView > xSpreadsheet(
+ getModel()->getCurrentController(), uno::UNO_QUERY_THROW );
+ xSpreadsheet->setActiveSheet(getSheet());
+}
+
+void
+ScVbaWorksheet::Select()
+{
+ Activate();
+}
+
+void
+ScVbaWorksheet::Move( const uno::Any& Before, const uno::Any& After )
+{
+ uno::Reference<excel::XWorksheet> xSheet;
+ OUString aCurrSheetName = getName();
+
+ if (!(Before >>= xSheet) && !(After >>=xSheet)&& !(Before.hasValue()) && !(After.hasValue()))
+ {
+ uno::Reference< sheet::XSheetCellCursor > xSheetCellCursor = getSheet()->createCursor( );
+ uno::Reference<sheet::XUsedAreaCursor> xUsedCursor(xSheetCellCursor,uno::UNO_QUERY_THROW);
+ // #FIXME needs worksheet as parent
+ uno::Reference<excel::XRange> xRange = new ScVbaRange( this, mxContext, xSheetCellCursor);
+ if (xRange.is())
+ xRange->Select();
+ excel::implnCopy(mxModel);
+ uno::Reference<frame::XModel> xModel = openNewDoc(aCurrSheetName);
+ if (xModel.is())
+ {
+ excel::implnPaste(xModel);
+ Delete();
+ }
+ return ;
+ }
+
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW );
+ SCTAB nDest = 0;
+ if ( ScVbaWorksheets::nameExists (xSpreadDoc, xSheet->getName(), nDest) )
+ {
+ bool bAfter = After.hasValue();
+ if (bAfter)
+ nDest++;
+ uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets();
+ xSheets->moveByName(aCurrSheetName,nDest);
+ }
+}
+
+void
+ScVbaWorksheet::Copy( const uno::Any& Before, const uno::Any& After )
+{
+ uno::Reference<excel::XWorksheet> xSheet;
+ if (!(Before >>= xSheet) && !(After >>=xSheet)&& !(Before.hasValue()) && !(After.hasValue()))
+ {
+ createSheetCopyInNewDoc(getName());
+ return;
+ }
+
+ uno::Reference<excel::XWorksheet> xNewSheet = createSheetCopy(xSheet, After.hasValue());
+ xNewSheet->Activate();
+}
+
+void
+ScVbaWorksheet::Paste( const uno::Any& Destination, const uno::Any& /*Link*/ )
+{
+ // #TODO# #FIXME# Link is not used
+ uno::Reference<excel::XRange> xRange( Destination, uno::UNO_QUERY );
+ if ( xRange.is() )
+ xRange->Select();
+ excel::implnPaste( mxModel );
+}
+
+void
+ScVbaWorksheet::Delete()
+{
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW );
+ OUString aSheetName = getName();
+ SCTAB nTab = 0;
+ if (!ScVbaWorksheets::nameExists(xSpreadDoc, aSheetName, nTab ))
+ {
+ return;
+ }
+ uno::Reference<sheet::XSpreadsheets> xSheets = xSpreadDoc->getSheets();
+ uno::Reference<container::XNameContainer> xNameContainer(xSheets,uno::UNO_QUERY_THROW);
+ xNameContainer->removeByName(aSheetName);
+ mxSheet.clear();
+}
+
+uno::Reference< excel::XWorksheet >
+ScVbaWorksheet::getSheetAtOffset(SCTAB offset)
+{
+ uno::Reference <sheet::XSpreadsheetDocument> xSpreadDoc( getModel(), uno::UNO_QUERY_THROW );
+ uno::Reference <sheet::XSpreadsheets> xSheets( xSpreadDoc->getSheets(), uno::UNO_SET_THROW );
+ uno::Reference <container::XIndexAccess> xIndex( xSheets, uno::UNO_QUERY_THROW );
+
+ SCTAB nIdx = 0;
+ if ( !ScVbaWorksheets::nameExists (xSpreadDoc, getName(), nIdx ) )
+ return uno::Reference< excel::XWorksheet >();
+ nIdx = nIdx + offset;
+ uno::Reference< sheet::XSpreadsheet > xSheet(xIndex->getByIndex(nIdx), uno::UNO_QUERY_THROW);
+ // parent will be the parent of 'this' worksheet
+ return new ScVbaWorksheet (getParent(), mxContext, xSheet, getModel());
+}
+
+uno::Reference< excel::XWorksheet >
+ScVbaWorksheet::getNext()
+{
+ return getSheetAtOffset(static_cast<SCTAB>(1));
+}
+
+uno::Reference< excel::XWorksheet >
+ScVbaWorksheet::getPrevious()
+{
+ return getSheetAtOffset(-1);
+}
+
+void
+ScVbaWorksheet::Protect( const uno::Any& Password, const uno::Any& /*DrawingObjects*/, const uno::Any& /*Contents*/, const uno::Any& /*Scenarios*/, const uno::Any& /*UserInterfaceOnly*/ )
+{
+ // #TODO# #FIXME# is there anything we can do with the unused param
+ // can the implementation use anything else here
+ uno::Reference<util::XProtectable > xProtectable(getSheet(), uno::UNO_QUERY_THROW);
+ OUString aPasswd;
+ Password >>= aPasswd;
+ xProtectable->protect( aPasswd );
+}
+
+void
+ScVbaWorksheet::Unprotect( const uno::Any& Password )
+{
+ uno::Reference<util::XProtectable > xProtectable(getSheet(), uno::UNO_QUERY_THROW);
+ OUString aPasswd;
+ Password >>= aPasswd;
+ xProtectable->unprotect( aPasswd );
+}
+
+void
+ScVbaWorksheet::Calculate()
+{
+ uno::Reference <sheet::XCalculatable> xReCalculate(getModel(), uno::UNO_QUERY_THROW);
+ xReCalculate->calculate();
+}
+
+uno::Reference< excel::XRange >
+ScVbaWorksheet::Range( const ::uno::Any& Cell1, const ::uno::Any& Cell2 )
+{
+ uno::Reference< excel::XRange > xSheetRange( new ScVbaRange( this, mxContext
+, uno::Reference< table::XCellRange >( getSheet(), uno::UNO_QUERY_THROW ) ) );
+ return xSheetRange->Range( Cell1, Cell2 );
+}
+
+void
+ScVbaWorksheet::CheckSpelling( const uno::Any& /*CustomDictionary*/,const uno::Any& /*IgnoreUppercase*/,const uno::Any& /*AlwaysSuggest*/, const uno::Any& /*SpellingLang*/ )
+{
+ // #TODO# #FIXME# unused params above, can we do anything with those
+ uno::Reference< frame::XModel > xModel( getModel() );
+ dispatchRequests(xModel,".uno:SpellDialog");
+}
+
+uno::Reference< excel::XRange >
+ScVbaWorksheet::getSheetRange()
+{
+ uno::Reference< table::XCellRange > xRange( getSheet(),uno::UNO_QUERY_THROW );
+ return uno::Reference< excel::XRange >( new ScVbaRange( this, mxContext, xRange ) );
+}
+
+// These are hacks - we prolly (somehow) need to inherit
+// the vbarange functionality here ...
+uno::Reference< excel::XRange >
+ScVbaWorksheet::Cells( const ::uno::Any &nRow, const ::uno::Any &nCol )
+{
+ // Performance optimization for often-called Cells method:
+ // Use a common helper method instead of creating a new ScVbaRange object
+ uno::Reference< table::XCellRange > xRange( getSheet(), uno::UNO_QUERY_THROW );
+ uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW );
+ ScDocument& rDoc = excel::getDocShell( xModel )->GetDocument();
+ return ScVbaRange::CellsHelper( rDoc, this, mxContext, xRange, nRow, nCol );
+}
+
+uno::Reference< excel::XRange >
+ScVbaWorksheet::Rows(const uno::Any& aIndex )
+{
+ return getSheetRange()->Rows( aIndex );
+}
+
+uno::Reference< excel::XRange >
+ScVbaWorksheet::Columns( const uno::Any& aIndex )
+{
+ return getSheetRange()->Columns( aIndex );
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::ChartObjects( const uno::Any& Index )
+{
+ if ( !mxCharts.is() )
+ {
+ uno::Reference< table::XTableChartsSupplier > xChartSupplier( getSheet(), uno::UNO_QUERY_THROW );
+ uno::Reference< table::XTableCharts > xTableCharts = xChartSupplier->getCharts();
+
+ uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( mxSheet, uno::UNO_QUERY_THROW );
+ mxCharts = new ScVbaChartObjects( this, mxContext, xTableCharts, xDrawPageSupplier );
+ }
+ if ( Index.hasValue() )
+ {
+ uno::Reference< XCollection > xColl( mxCharts, uno::UNO_QUERY_THROW );
+ return xColl->Item( Index, uno::Any() );
+ }
+ else
+ return uno::Any( mxCharts );
+
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::PivotTables( const uno::Any& Index )
+{
+ uno::Reference< css::sheet::XSpreadsheet > xSheet = getSheet();
+ uno::Reference< sheet::XDataPilotTablesSupplier > xTables(xSheet, uno::UNO_QUERY_THROW ) ;
+ uno::Reference< container::XIndexAccess > xIndexAccess( xTables->getDataPilotTables(), uno::UNO_QUERY_THROW );
+
+ uno::Reference< XCollection > xColl( new ScVbaPivotTables( this, mxContext, xIndexAccess ) );
+ if ( Index.hasValue() )
+ return xColl->Item( Index, uno::Any() );
+ return uno::Any( xColl );
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::Comments( const uno::Any& Index )
+{
+ uno::Reference< css::sheet::XSpreadsheet > xSheet = getSheet();
+ uno::Reference< sheet::XSheetAnnotationsSupplier > xAnnosSupp( xSheet, uno::UNO_QUERY_THROW );
+ uno::Reference< sheet::XSheetAnnotations > xAnnos( xAnnosSupp->getAnnotations(), uno::UNO_SET_THROW );
+ uno::Reference< container::XIndexAccess > xIndexAccess( xAnnos, uno::UNO_QUERY_THROW );
+ uno::Reference< XCollection > xColl( new ScVbaComments( this, mxContext, mxModel, xIndexAccess ) );
+ if ( Index.hasValue() )
+ return xColl->Item( Index, uno::Any() );
+ return uno::Any( xColl );
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::Hyperlinks( const uno::Any& aIndex )
+{
+ /* The worksheet always returns the same Hyperlinks object.
+ See vbahyperlinks.hxx for more details. */
+ if( !mxHlinks.is() )
+ mxHlinks.set( new ScVbaHyperlinks( this, mxContext ) );
+ if( aIndex.hasValue() )
+ return uno::Reference< XCollection >( mxHlinks, uno::UNO_QUERY_THROW )->Item( aIndex, uno::Any() );
+ return uno::Any( mxHlinks );
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::Names( const css::uno::Any& aIndex )
+{
+ css::uno::Reference<css::beans::XPropertySet> xProps(getSheet(), css::uno::UNO_QUERY_THROW);
+ uno::Reference< sheet::XNamedRanges > xNamedRanges( xProps->getPropertyValue("NamedRanges"), uno::UNO_QUERY_THROW );
+ uno::Reference< XCollection > xNames( new ScVbaNames( this, mxContext, xNamedRanges, mxModel ) );
+ if ( aIndex.hasValue() )
+ return xNames->Item( aIndex, uno::Any() );
+ return uno::Any( xNames );
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::OLEObjects( const uno::Any& Index )
+{
+ uno::Reference< sheet::XSpreadsheet > xSpreadsheet( getSheet(), uno::UNO_SET_THROW );
+ uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( xSpreadsheet, uno::UNO_QUERY_THROW );
+ uno::Reference< drawing::XDrawPage > xDrawPage( xDrawPageSupplier->getDrawPage(), uno::UNO_SET_THROW );
+ uno::Reference< container::XIndexAccess > xIndexAccess( xDrawPage, uno::UNO_QUERY_THROW );
+
+ uno::Reference< excel::XOLEObjects >xOleObjects( new ScVbaOLEObjects( this, mxContext, xIndexAccess ) );
+ if( Index.hasValue() )
+ return xOleObjects->Item( Index, uno::Any() );
+ return uno::Any( xOleObjects );
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::Shapes( const uno::Any& aIndex )
+{
+ uno::Reference< sheet::XSpreadsheet > xSpreadsheet( getSheet(), uno::UNO_SET_THROW );
+ uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( xSpreadsheet, uno::UNO_QUERY_THROW );
+ uno::Reference< drawing::XShapes > xShapes( xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xIndexAccess( xShapes, uno::UNO_QUERY_THROW );
+
+ uno::Reference< msforms::XShapes> xVbaShapes( new ScVbaShapes( this, mxContext, xIndexAccess, getModel() ) );
+ if ( aIndex.hasValue() )
+ return xVbaShapes->Item( aIndex, uno::Any() );
+ return uno::Any( xVbaShapes );
+}
+
+uno::Any
+ScVbaWorksheet::getButtons( const uno::Any &rIndex, bool bOptionButtons )
+{
+ ::rtl::Reference< ScVbaSheetObjectsBase > &rxButtons = bOptionButtons ? mxButtons[0] : mxButtons[1];
+
+ if( !rxButtons.is() )
+ rxButtons.set( new ScVbaButtons( this, mxContext, mxModel, mxSheet, bOptionButtons ) );
+ else
+ rxButtons->collectShapes();
+ if( rIndex.hasValue() )
+ return rxButtons->Item( rIndex, uno::Any() );
+ return uno::Any( uno::Reference< XCollection >( rxButtons ) );
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::Buttons( const uno::Any& rIndex )
+{
+ return getButtons( rIndex, false );
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::CheckBoxes( const uno::Any& /*rIndex*/ )
+{
+ throw uno::RuntimeException();
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::DropDowns( const uno::Any& /*rIndex*/ )
+{
+ throw uno::RuntimeException();
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::GroupBoxes( const uno::Any& /*rIndex*/ )
+{
+ throw uno::RuntimeException();
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::Labels( const uno::Any& /*rIndex*/ )
+{
+ throw uno::RuntimeException();
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::ListBoxes( const uno::Any& /*rIndex*/ )
+{
+ throw uno::RuntimeException();
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::OptionButtons( const uno::Any& rIndex )
+{
+ return getButtons( rIndex, true );
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::ScrollBars( const uno::Any& /*rIndex*/ )
+{
+ throw uno::RuntimeException();
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::Spinners( const uno::Any& /*rIndex*/ )
+{
+ throw uno::RuntimeException();
+}
+
+void SAL_CALL
+ScVbaWorksheet::ShowDataForm( )
+{
+ uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW );
+ ScTabViewShell* pTabViewShell = excel::getBestViewShell( xModel );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScDataFormDlg> pDlg(pFact->CreateScDataFormDlg(pTabViewShell->GetFrameWeld(),
+ pTabViewShell));
+
+ pDlg->Execute();
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::Evaluate( const OUString& Name )
+{
+ // #TODO Evaluate allows other things to be evaluated, e.g. functions
+ // I think ( like SIN(3) etc. ) need to investigate that
+ // named Ranges also? e.g. [MyRange] if so need a list of named ranges
+ uno::Any aVoid;
+ return uno::Any( Range( uno::Any( Name ), aVoid ) );
+}
+
+uno::Reference< beans::XIntrospectionAccess > SAL_CALL
+ScVbaWorksheet::getIntrospection( )
+{
+ return uno::Reference< beans::XIntrospectionAccess >();
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheet::invoke( const OUString& /*aFunctionName*/, const uno::Sequence< uno::Any >& /*aParams*/, uno::Sequence< ::sal_Int16 >& /*aOutParamIndex*/, uno::Sequence< uno::Any >& /*aOutParam*/ )
+{
+ throw uno::RuntimeException("Unsupported"); // unsupported operation
+}
+
+void SAL_CALL
+ScVbaWorksheet::setValue( const OUString& aPropertyName, const uno::Any& aValue )
+{
+ setDefaultPropByIntrospection( getValue( aPropertyName ), aValue );
+}
+uno::Any SAL_CALL
+ScVbaWorksheet::getValue( const OUString& aPropertyName )
+{
+ uno::Reference< drawing::XControlShape > xControlShape( getControlShape( aPropertyName ), uno::UNO_QUERY_THROW );
+
+ uno::Reference<lang::XMultiComponentFactory > xServiceManager( mxContext->getServiceManager(), uno::UNO_SET_THROW );
+ uno::Reference< XControlProvider > xControlProvider( xServiceManager->createInstanceWithContext("ooo.vba.ControlProvider", mxContext ), uno::UNO_QUERY_THROW );
+ uno::Reference< msforms::XControl > xControl( xControlProvider->createControl( xControlShape, getModel() ) );
+ return uno::Any( xControl );
+}
+
+sal_Bool SAL_CALL
+ScVbaWorksheet::hasMethod( const OUString& /*aName*/ )
+{
+ return false;
+}
+
+uno::Reference< container::XNameAccess >
+ScVbaWorksheet::getFormControls() const
+{
+ uno::Reference< container::XNameAccess > xFormControls;
+ try
+ {
+ uno::Reference< sheet::XSpreadsheet > xSpreadsheet( getSheet(), uno::UNO_SET_THROW );
+ uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( xSpreadsheet, uno::UNO_QUERY_THROW );
+ uno::Reference< form::XFormsSupplier > xFormSupplier( xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xIndexAccess( xFormSupplier->getForms(), uno::UNO_QUERY_THROW );
+ // get the www-standard container ( maybe we should access the
+ // 'www-standard' by name rather than index, this seems an
+ // implementation detail
+ if( xIndexAccess->hasElements() )
+ xFormControls.set( xIndexAccess->getByIndex(0), uno::UNO_QUERY );
+
+ }
+ catch( uno::Exception& )
+ {
+ }
+ return xFormControls;
+
+ }
+sal_Bool SAL_CALL
+ScVbaWorksheet::hasProperty( const OUString& aName )
+{
+ uno::Reference< container::XNameAccess > xFormControls( getFormControls() );
+ if ( xFormControls.is() )
+ return xFormControls->hasByName( aName );
+ return false;
+}
+
+uno::Any
+ScVbaWorksheet::getControlShape( std::u16string_view sName )
+{
+ // ideally we would get an XControl object but it appears an XControl
+ // implementation only exists for a Control implementation obtained from the
+ // view ( e.g. in basic you would get this from
+ // thiscomponent.currentcontroller.getControl( controlModel ) )
+ // and the thing to realise is that it is only possible to get an XControl
+ // for a currently displayed control :-( often we would want to modify
+ // a control not on the active sheet. But... you can always access the
+ // XControlShape from the DrawPage whether that is the active drawpage or not
+
+ uno::Reference< drawing::XDrawPageSupplier > xDrawPageSupplier( getSheet(), uno::UNO_QUERY_THROW );
+ uno::Reference< container::XIndexAccess > xIndexAccess( xDrawPageSupplier->getDrawPage(), uno::UNO_QUERY_THROW );
+
+ sal_Int32 nCount = xIndexAccess->getCount();
+ for( int index = 0; index < nCount; index++ )
+ {
+ uno::Any aUnoObj = xIndexAccess->getByIndex( index );
+ // It seems there are some drawing objects that can not query into Control shapes?
+ uno::Reference< drawing::XControlShape > xControlShape( aUnoObj, uno::UNO_QUERY );
+ if( xControlShape.is() )
+ {
+ uno::Reference< container::XNamed > xNamed( xControlShape->getControl(), uno::UNO_QUERY_THROW );
+ if( sName == xNamed->getName() )
+ {
+ return aUnoObj;
+ }
+ }
+ }
+ return uno::Any();
+}
+
+OUString
+ScVbaWorksheet::getServiceImplName()
+{
+ return "ScVbaWorksheet";
+}
+
+void SAL_CALL
+ScVbaWorksheet::setEnableCalculation( sal_Bool bEnableCalculation )
+{
+ uno::Reference <sheet::XCalculatable> xCalculatable(getModel(), uno::UNO_QUERY_THROW);
+ xCalculatable->enableAutomaticCalculation( bEnableCalculation);
+}
+sal_Bool SAL_CALL
+ScVbaWorksheet::getEnableCalculation( )
+{
+ uno::Reference <sheet::XCalculatable> xCalculatable(getModel(), uno::UNO_QUERY_THROW);
+ return xCalculatable->isAutomaticCalculationEnabled();
+}
+
+uno::Sequence< OUString >
+ScVbaWorksheet::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.Worksheet"
+ };
+ return aServiceNames;
+}
+
+OUString SAL_CALL
+ScVbaWorksheet::getCodeName()
+{
+ uno::Reference< beans::XPropertySet > xSheetProp( mxSheet, uno::UNO_QUERY_THROW );
+ return xSheetProp->getPropertyValue("CodeName").get< OUString >();
+}
+
+sal_Int16
+ScVbaWorksheet::getSheetID() const
+{
+ uno::Reference< sheet::XCellRangeAddressable > xAddressable( mxSheet, uno::UNO_QUERY_THROW ); // if ActiveSheet, mxSheet is null.
+ return xAddressable->getRangeAddress().Sheet;
+}
+
+void SAL_CALL
+ScVbaWorksheet::PrintOut( const uno::Any& From, const uno::Any& To, const uno::Any& Copies, const uno::Any& Preview, const uno::Any& ActivePrinter, const uno::Any& PrintToFile, const uno::Any& Collate, const uno::Any& PrToFileName, const uno::Any& )
+{
+ sal_Int32 nTo = 0;
+ sal_Int32 nFrom = 0;
+ bool bSelection = false;
+ From >>= nFrom;
+ To >>= nTo;
+
+ if ( !( nFrom || nTo ) )
+ bSelection = true;
+
+ uno::Reference< frame::XModel > xModel( getModel(), uno::UNO_SET_THROW );
+ PrintOutHelper( excel::getBestViewShell( xModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, bSelection );
+}
+
+sal_Int64 SAL_CALL
+ScVbaWorksheet::getSomething(const uno::Sequence<sal_Int8 > & rId)
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+Calc_ScVbaWorksheet_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& args)
+{
+ return cppu::acquire(new ScVbaWorksheet(args, context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaworksheet.hxx b/sc/source/ui/vba/vbaworksheet.hxx
new file mode 100644
index 000000000..5eee3df4a
--- /dev/null
+++ b/sc/source/ui/vba/vbaworksheet.hxx
@@ -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 .
+ */
+#pragma once
+
+#include <ooo/vba/excel/XWorksheet.hpp>
+#include <rtl/ref.hxx>
+
+#include <vbahelper/vbahelperinterface.hxx>
+#include <types.hxx>
+
+namespace com::sun::star::frame { class XModel; }
+namespace com::sun::star::sheet { class XSpreadsheet; }
+namespace com::sun::star::uno { class XComponentContext; }
+namespace ooo::vba::excel { class XOutline; }
+namespace ooo::vba::excel { class XPageSetup; }
+namespace ooo::vba::excel { class XRange; }
+
+namespace ooo::vba::excel {
+ class XChartObjects;
+ class XHyperlinks;
+}
+
+class ScVbaSheetObjectsBase;
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XWorksheet > WorksheetImpl_BASE;
+
+class ScVbaWorksheet : public WorksheetImpl_BASE
+{
+ css::uno::Reference< css::sheet::XSpreadsheet > mxSheet;
+ css::uno::Reference< css::frame::XModel > mxModel;
+ css::uno::Reference< ov::excel::XChartObjects > mxCharts;
+ css::uno::Reference< ov::excel::XHyperlinks > mxHlinks;
+ ::rtl::Reference< ScVbaSheetObjectsBase > mxButtons[2];
+ bool mbVeryHidden;
+
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< ov::excel::XWorksheet > getSheetAtOffset(SCTAB offset);
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< ov::excel::XRange > getSheetRange();
+
+ css::uno::Reference< css::container::XNameAccess > getFormControls() const;
+ css::uno::Any getControlShape( std::u16string_view sName );
+
+ css::uno::Any getButtons( const css::uno::Any &rIndex, bool bOptionButtons );
+
+public:
+ /// @throws css::uno::RuntimeException
+ ScVbaWorksheet( const css::uno::Reference< ov::XHelperInterface >& xParent,
+ const css::uno::Reference< css::uno::XComponentContext >& xContext,
+ const css::uno::Reference< css::sheet::XSpreadsheet >& xSheet,
+ const css::uno::Reference< css::frame::XModel >& xModel ) ;
+ /// @throws css::lang::IllegalArgumentException
+ /// @throws css::uno::RuntimeException
+ ScVbaWorksheet( css::uno::Sequence< css::uno::Any > const& aArgs, css::uno::Reference< css::uno::XComponentContext >const& xContext );
+
+ virtual ~ScVbaWorksheet() override;
+
+ const css::uno::Reference< css::frame::XModel >& getModel() const
+ { return mxModel; }
+ const css::uno::Reference< css::sheet::XSpreadsheet >& getSheet() const
+ { return mxSheet; }
+ static const css::uno::Sequence<sal_Int8>& getUnoTunnelId();
+ css::uno::Reference< ov::excel::XWorksheet > createSheetCopyInNewDoc( const OUString& );
+ css::uno::Reference< ov::excel::XWorksheet > createSheetCopy(css::uno::Reference< ov::excel::XWorksheet> const & xSheet, bool bAfter);
+
+ // Attributes
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName( const OUString &rName ) override;
+ virtual sal_Int32 SAL_CALL getVisible() override;
+ virtual void SAL_CALL setVisible( sal_Int32 nVisible ) override;
+ virtual ::sal_Int32 SAL_CALL getStandardWidth() override;
+ virtual ::sal_Int32 SAL_CALL getStandardHeight() override;
+ virtual sal_Bool SAL_CALL getProtectionMode() override;
+ virtual sal_Bool SAL_CALL getProtectContents() override;
+ virtual sal_Bool SAL_CALL getProtectDrawingObjects() override;
+ virtual sal_Bool SAL_CALL getProtectScenarios() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL getUsedRange() override ;
+ virtual css::uno::Any SAL_CALL ChartObjects( const css::uno::Any& Index ) override;
+ virtual css::uno::Reference< ov::excel::XOutline > SAL_CALL Outline( ) override;
+ virtual css::uno::Reference< ov::excel::XPageSetup > SAL_CALL PageSetup( ) override;
+ virtual css::uno::Any SAL_CALL HPageBreaks( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL VPageBreaks( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getNext() override;
+ virtual css::uno::Reference< ov::excel::XWorksheet > SAL_CALL getPrevious() override;
+ virtual sal_Int16 SAL_CALL getIndex() override;
+ virtual sal_Int32 SAL_CALL getEnableSelection() override;
+ virtual void SAL_CALL setEnableSelection( sal_Int32 nSelection ) override;
+ virtual sal_Bool SAL_CALL getAutoFilterMode() override;
+ virtual void SAL_CALL setAutoFilterMode( sal_Bool bAutoFilterMode ) override;
+
+ // Methods
+ virtual void SAL_CALL Activate() override;
+ virtual void SAL_CALL Select() override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Range( const css::uno::Any& Cell1, const css::uno::Any& Cell2 ) override;
+ virtual void SAL_CALL Move( const css::uno::Any& Before, const css::uno::Any& After ) override ;
+ virtual void SAL_CALL Copy( const css::uno::Any& Before, const css::uno::Any& After ) override;
+ virtual void SAL_CALL Paste( const css::uno::Any& Destination, const css::uno::Any& Link ) override;
+ virtual void SAL_CALL Delete( ) override;
+ virtual void SAL_CALL Protect( const css::uno::Any& Password, const css::uno::Any& DrawingObjects, const css::uno::Any& Contents, const css::uno::Any& Scenarios, const css::uno::Any& UserInterfaceOnly ) override;
+ virtual void SAL_CALL Unprotect( const css::uno::Any& Password ) override;
+
+ virtual void SAL_CALL Calculate( ) override;
+ virtual void SAL_CALL CheckSpelling( const css::uno::Any& CustomDictionary,const css::uno::Any& IgnoreUppercase,const css::uno::Any& AlwaysSuggest, const css::uno::Any& SpellingLang ) override;
+ // Hacks (?)
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Cells( const css::uno::Any &nRow, const css::uno::Any &nCol ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Rows(const css::uno::Any& aIndex ) override;
+ virtual css::uno::Reference< ov::excel::XRange > SAL_CALL Columns(const css::uno::Any& aIndex ) override;
+
+ virtual css::uno::Any SAL_CALL Evaluate( const OUString& Name ) override;
+ virtual css::uno::Any SAL_CALL PivotTables( const css::uno::Any& Index ) override;
+ virtual css::uno::Any SAL_CALL Comments( const css::uno::Any& Index ) override;
+ virtual css::uno::Any SAL_CALL Hyperlinks( const css::uno::Any& aIndex ) override;
+ virtual css::uno::Any SAL_CALL Names( const css::uno::Any& aIndex ) override;
+
+ virtual css::uno::Any SAL_CALL OLEObjects( const css::uno::Any& Index ) override;
+ virtual css::uno::Any SAL_CALL Shapes( const css::uno::Any& aIndex ) override;
+
+ virtual css::uno::Any SAL_CALL Buttons( const css::uno::Any& rIndex ) override;
+ virtual css::uno::Any SAL_CALL CheckBoxes( const css::uno::Any& rIndex ) override;
+ virtual css::uno::Any SAL_CALL DropDowns( const css::uno::Any& rIndex ) override;
+ virtual css::uno::Any SAL_CALL GroupBoxes( const css::uno::Any& rIndex ) override;
+ virtual css::uno::Any SAL_CALL Labels( const css::uno::Any& rIndex ) override;
+ virtual css::uno::Any SAL_CALL ListBoxes( const css::uno::Any& rIndex ) override;
+ virtual css::uno::Any SAL_CALL OptionButtons( const css::uno::Any& rIndex ) override;
+ virtual css::uno::Any SAL_CALL ScrollBars( const css::uno::Any& rIndex ) override;
+ virtual css::uno::Any SAL_CALL Spinners( const css::uno::Any& rIndex ) override;
+
+ virtual void SAL_CALL setEnableCalculation( sal_Bool EnableCalculation ) override;
+ virtual sal_Bool SAL_CALL getEnableCalculation( ) override;
+ virtual void SAL_CALL ShowDataForm( ) override;
+ // XInvocation
+ virtual css::uno::Reference< css::beans::XIntrospectionAccess > SAL_CALL getIntrospection( ) override;
+ virtual css::uno::Any SAL_CALL invoke( const OUString& aFunctionName, const css::uno::Sequence< css::uno::Any >& aParams, css::uno::Sequence< ::sal_Int16 >& aOutParamIndex, css::uno::Sequence< css::uno::Any >& aOutParam ) override;
+ virtual void SAL_CALL setValue( const OUString& aPropertyName, const css::uno::Any& aValue ) override;
+ virtual css::uno::Any SAL_CALL getValue( const OUString& aPropertyName ) override;
+ virtual sal_Bool SAL_CALL hasMethod( const OUString& aName ) override;
+ virtual sal_Bool SAL_CALL hasProperty( const OUString& aName ) override;
+ // CodeName
+ virtual OUString SAL_CALL getCodeName() override;
+ /// @throws css::uno::RuntimeException
+ sal_Int16 getSheetID() const;
+
+ virtual void SAL_CALL PrintOut( const css::uno::Any& From, const css::uno::Any& To, const css::uno::Any& Copies, const css::uno::Any& Preview, const css::uno::Any& ActivePrinter, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& PrToFileName, const css::uno::Any& IgnorePrintAreas ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+ // XUnoTunnel
+ virtual ::sal_Int64 SAL_CALL getSomething(const css::uno::Sequence<sal_Int8 >& rId ) override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaworksheets.cxx b/sc/source/ui/vba/vbaworksheets.cxx
new file mode 100644
index 000000000..5df1bc622
--- /dev/null
+++ b/sc/source/ui/vba/vbaworksheets.cxx
@@ -0,0 +1,535 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+#include "vbaworksheets.hxx"
+
+#include <sfx2/viewfrm.hxx>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/sheet/XSpreadsheet.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+
+#include <ooo/vba/excel/XApplication.hpp>
+#include <tabvwsh.hxx>
+
+#include "excelvbahelper.hxx"
+#include "vbaworksheet.hxx"
+#include <markdata.hxx>
+
+#include <vector>
+#include <prevwsh.hxx>
+#include <preview.hxx>
+using namespace ::ooo::vba;
+using namespace ::com::sun::star;
+
+// a map ( or hashmap ) won't do as we need also to preserve the order
+// (as added ) of the items
+typedef std::vector< uno::Reference< sheet::XSpreadsheet > > SheetMap;
+
+// #FIXME #TODO the implementation of the Sheets collections sucks,
+// e.g. there is no support for tracking sheets added/removed from the collection
+
+namespace {
+
+class WorkSheetsEnumeration : public ::cppu::WeakImplHelper< container::XEnumeration >
+{
+ SheetMap mSheetMap;
+ SheetMap::iterator mIt;
+public:
+ explicit WorkSheetsEnumeration( SheetMap&& sMap ) : mSheetMap( std::move(sMap) ), mIt( mSheetMap.begin() ) {}
+ virtual sal_Bool SAL_CALL hasMoreElements( ) override
+ {
+ return ( mIt != mSheetMap.end() );
+ }
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ if ( !hasMoreElements() )
+ throw container::NoSuchElementException();
+ uno::Reference< sheet::XSpreadsheet > xSheet( *mIt++ );
+ return uno::Any( xSheet ) ;
+ }
+};
+
+class SheetCollectionHelper : public ::cppu::WeakImplHelper< container::XNameAccess,
+ container::XIndexAccess,
+ container::XEnumerationAccess >
+{
+ SheetMap mSheetMap;
+ SheetMap::iterator cachePos;
+public:
+ explicit SheetCollectionHelper( SheetMap&& sMap ) : mSheetMap( std::move(sMap) ), cachePos(mSheetMap.begin()) {}
+ // XElementAccess
+ virtual uno::Type SAL_CALL getElementType( ) override { return cppu::UnoType<sheet::XSpreadsheet>::get(); }
+ virtual sal_Bool SAL_CALL hasElements( ) override { return ( !mSheetMap.empty() ); }
+ // XNameAccess
+ virtual uno::Any SAL_CALL getByName( const OUString& aName ) override
+ {
+ if ( !hasByName(aName) )
+ throw container::NoSuchElementException();
+ return uno::Any( *cachePos );
+ }
+ virtual uno::Sequence< OUString > SAL_CALL getElementNames( ) override
+ {
+ uno::Sequence< OUString > sNames( mSheetMap.size() );
+ OUString* pString = sNames.getArray();
+
+ for ( const auto& rItem : mSheetMap )
+ {
+ uno::Reference< container::XNamed > xName( rItem, uno::UNO_QUERY_THROW );
+ *pString = xName->getName();
+ ++pString;
+ }
+ return sNames;
+ }
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override
+ {
+ cachePos = mSheetMap.begin();
+ SheetMap::iterator it_end = mSheetMap.end();
+ for ( ; cachePos != it_end; ++cachePos )
+ {
+ uno::Reference< container::XNamed > xName( *cachePos, uno::UNO_QUERY_THROW );
+ if ( aName == xName->getName() )
+ break;
+ }
+ return ( cachePos != it_end );
+ }
+
+ // XElementAccess
+ virtual ::sal_Int32 SAL_CALL getCount( ) override { return mSheetMap.size(); }
+ virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
+ {
+ if ( Index < 0 || Index >= getCount() )
+ throw lang::IndexOutOfBoundsException();
+
+ return uno::Any( mSheetMap[ Index ] );
+
+ }
+ // XEnumerationAccess
+ virtual uno::Reference< container::XEnumeration > SAL_CALL createEnumeration( ) override
+ {
+ return new WorkSheetsEnumeration( std::vector(mSheetMap) );
+ }
+};
+
+class SheetsEnumeration : public EnumerationHelperImpl
+{
+ uno::Reference< frame::XModel > m_xModel;
+public:
+ /// @throws uno::RuntimeException
+ SheetsEnumeration( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< uno::XComponentContext >& xContext, const uno::Reference< container::XEnumeration >& xEnumeration, const uno::Reference< frame::XModel >& xModel ) : EnumerationHelperImpl( xParent, xContext, xEnumeration ), m_xModel( xModel ) {}
+
+ virtual uno::Any SAL_CALL nextElement( ) override
+ {
+ uno::Reference< sheet::XSpreadsheet > xSheet( m_xEnumeration->nextElement(), uno::UNO_QUERY_THROW );
+ uno::Reference< XHelperInterface > xIf = excel::getUnoSheetModuleObj( xSheet );
+ uno::Any aRet;
+ if ( !xIf.is() )
+ {
+ // if the Sheet is in a document created by the api unfortunately ( at the
+ // moment, it actually won't have the special Document modules
+ uno::Reference< excel::XWorksheet > xNewSheet( new ScVbaWorksheet( m_xParent, m_xContext, xSheet, m_xModel ) );
+ aRet <<= xNewSheet;
+ }
+ else
+ aRet <<= xIf;
+ return aRet;
+ }
+
+};
+
+}
+
+ScVbaWorksheets::ScVbaWorksheets( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext > & xContext, const uno::Reference< container::XIndexAccess >& xSheets, const uno::Reference< frame::XModel >& xModel ): ScVbaWorksheets_BASE( xParent, xContext, xSheets ), mxModel( xModel ), m_xSheets( uno::Reference< sheet::XSpreadsheets >( xSheets, uno::UNO_QUERY ) )
+{
+}
+
+ScVbaWorksheets::ScVbaWorksheets( const uno::Reference< XHelperInterface >& xParent, const uno::Reference< css::uno::XComponentContext > & xContext, const uno::Reference< container::XEnumerationAccess >& xEnumAccess, const uno::Reference< frame::XModel >& xModel ): ScVbaWorksheets_BASE( xParent, xContext, uno::Reference< container::XIndexAccess >( xEnumAccess, uno::UNO_QUERY ) ), mxModel(xModel)
+{
+}
+
+// XEnumerationAccess
+uno::Type
+ScVbaWorksheets::getElementType()
+{
+ return cppu::UnoType<excel::XWorksheet>::get();
+}
+
+uno::Reference< container::XEnumeration >
+ScVbaWorksheets::createEnumeration()
+{
+ if ( !m_xSheets.is() )
+ {
+ uno::Reference< container::XEnumerationAccess > xAccess( m_xIndexAccess, uno::UNO_QUERY_THROW );
+ return xAccess->createEnumeration();
+ }
+ uno::Reference< container::XEnumerationAccess > xEnumAccess( m_xSheets, uno::UNO_QUERY_THROW );
+ return new SheetsEnumeration( this, mxContext, xEnumAccess->createEnumeration(), mxModel );
+}
+
+uno::Any
+ScVbaWorksheets::createCollectionObject( const uno::Any& aSource )
+{
+ uno::Reference< sheet::XSpreadsheet > xSheet( aSource, uno::UNO_QUERY );
+ uno::Reference< XHelperInterface > xIf = excel::getUnoSheetModuleObj( xSheet );
+ uno::Any aRet;
+ if ( !xIf.is() )
+ {
+ // if the Sheet is in a document created by the api unfortunately ( at the
+ // moment, it actually won't have the special Document modules
+ uno::Reference< excel::XWorksheet > xNewSheet( new ScVbaWorksheet( getParent(), mxContext, xSheet, mxModel ) );
+ aRet <<= xNewSheet;
+ }
+ else
+ aRet <<= xIf;
+ return aRet;
+}
+
+// XWorksheets
+uno::Any
+ScVbaWorksheets::Add( const uno::Any& Before, const uno::Any& After,
+ const uno::Any& Count, const uno::Any& Type )
+{
+ if ( isSelectedSheets() )
+ return uno::Any(); // or should we throw?
+
+ OUString aStringSheet;
+ bool bBefore(true);
+ SCTAB nSheetIndex = 0;
+ SCTAB nNewSheets = 1, nType = 0;
+ Count >>= nNewSheets;
+ Type >>= nType;
+ SCTAB nCount = 0;
+
+ uno::Reference< excel::XWorksheet > xBeforeAfterSheet;
+
+ if ( Before.hasValue() )
+ {
+ if ( Before >>= xBeforeAfterSheet )
+ aStringSheet = xBeforeAfterSheet->getName();
+ else
+ Before >>= aStringSheet;
+ }
+
+ if (aStringSheet.isEmpty() && After.hasValue() )
+ {
+ if ( After >>= xBeforeAfterSheet )
+ aStringSheet = xBeforeAfterSheet->getName();
+ else
+ After >>= aStringSheet;
+ bBefore = false;
+ }
+ if (aStringSheet.isEmpty())
+ {
+ uno::Reference< excel::XApplication > xApplication( Application(), uno::UNO_QUERY_THROW );
+ aStringSheet = xApplication->getActiveWorkbook()->getActiveSheet()->getName();
+ bBefore = true;
+ }
+ nCount = static_cast< SCTAB >( m_xIndexAccess->getCount() );
+ for (SCTAB i=0; i < nCount; i++)
+ {
+ uno::Reference< sheet::XSpreadsheet > xSheet(m_xIndexAccess->getByIndex(i), uno::UNO_QUERY);
+ uno::Reference< container::XNamed > xNamed( xSheet, uno::UNO_QUERY_THROW );
+ if (xNamed->getName() == aStringSheet)
+ {
+ nSheetIndex = i;
+ break;
+ }
+ }
+
+ if(!bBefore)
+ nSheetIndex++;
+
+ SCTAB nSheetName = nCount + 1;
+ OUString aStringBase( "Sheet" );
+ uno::Any result;
+ for (SCTAB i=0; i < nNewSheets; i++, nSheetName++)
+ {
+ OUString aStringName = aStringBase + OUString::number(nSheetName);
+ while (m_xNameAccess->hasByName(aStringName))
+ {
+ nSheetName++;
+ aStringName = aStringBase + OUString::number(nSheetName);
+ }
+ m_xSheets->insertNewByName(aStringName, nSheetIndex + i);
+ result = getItemByStringIndex( aStringName );
+ }
+ uno::Reference< excel::XWorksheet > xNewSheet( result, uno::UNO_QUERY );
+ if ( xNewSheet.is() )
+ xNewSheet->Activate();
+ return result;
+}
+
+void
+ScVbaWorksheets::Delete()
+{
+ // #TODO #INVESTIGATE
+ // mmm this method could be trouble if the underlying
+ // uno objects ( the m_xIndexAccess etc ) aren't aware of the
+ // contents that are deleted
+ sal_Int32 nElems = getCount();
+ for ( sal_Int32 nItem = 1; nItem <= nElems; ++nItem )
+ {
+ uno::Reference< excel::XWorksheet > xSheet( Item( uno::Any( nItem ), uno::Any() ), uno::UNO_QUERY_THROW );
+ xSheet->Delete();
+ }
+}
+
+bool
+ScVbaWorksheets::isSelectedSheets() const
+{
+ return !m_xSheets.is();
+}
+
+void SAL_CALL
+ScVbaWorksheets::PrintOut( const uno::Any& From, const uno::Any& To, const uno::Any& Copies, const uno::Any& Preview, const uno::Any& ActivePrinter, const uno::Any& PrintToFile, const uno::Any& Collate, const uno::Any& PrToFileName )
+{
+ sal_Int32 nTo = 0;
+ sal_Int32 nFrom = 0;
+ bool bSelection = false;
+ From >>= nFrom;
+ To >>= nTo;
+
+ if ( !( nFrom || nTo ) )
+ if ( isSelectedSheets() )
+ bSelection = true;
+
+ PrintOutHelper( excel::getBestViewShell( mxModel ), From, To, Copies, Preview, ActivePrinter, PrintToFile, Collate, PrToFileName, bSelection );
+}
+
+uno::Any SAL_CALL
+ScVbaWorksheets::getVisible()
+{
+ bool bVisible = true;
+ uno::Reference< container::XEnumeration > xEnum( createEnumeration(), uno::UNO_SET_THROW );
+ while ( xEnum->hasMoreElements() )
+ {
+ uno::Reference< excel::XWorksheet > xSheet( xEnum->nextElement(), uno::UNO_QUERY_THROW );
+ if ( xSheet->getVisible() == 0 )
+ {
+ bVisible = false;
+ break;
+ }
+ }
+ return uno::Any( bVisible );
+}
+
+void SAL_CALL
+ScVbaWorksheets::setVisible( const uno::Any& _visible )
+{
+ bool bState = false;
+ if ( !(_visible >>= bState) )
+ throw uno::RuntimeException("Visible property doesn't support non boolean #FIXME" );
+
+ uno::Reference< container::XEnumeration > xEnum( createEnumeration(), uno::UNO_SET_THROW );
+ while ( xEnum->hasMoreElements() )
+ {
+ uno::Reference< excel::XWorksheet > xSheet( xEnum->nextElement(), uno::UNO_QUERY_THROW );
+ xSheet->setVisible( bState ? 1 : 0 );
+ }
+
+}
+
+void SAL_CALL
+ScVbaWorksheets::Select( const uno::Any& Replace )
+{
+ ScTabViewShell* pViewShell = excel::getBestViewShell( mxModel );
+ if ( !pViewShell )
+ throw uno::RuntimeException("Cannot obtain view shell" );
+
+ ScMarkData& rMarkData = pViewShell->GetViewData().GetMarkData();
+ bool bReplace = true;
+ Replace >>= bReplace;
+ // Replace is defaulted to True, meaning this current collection
+ // becomes the Selection, if it were false then the current selection would
+ // be extended
+ bool bSelectSingle = bReplace;
+ sal_Int32 nElems = getCount();
+ for ( sal_Int32 nItem = 1; nItem <= nElems; ++nItem )
+ {
+ uno::Reference< excel::XWorksheet > xSheet( Item( uno::Any( nItem ), uno::Any() ), uno::UNO_QUERY_THROW );
+ ScVbaWorksheet* pSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSheet );
+ if ( bSelectSingle )
+ {
+ rMarkData.SelectOneTable( static_cast< SCTAB >( pSheet->getSheetID() ) );
+ bSelectSingle = false;
+ }
+ else
+ rMarkData.SelectTable( static_cast< SCTAB >( pSheet->getSheetID() ), true );
+ }
+
+}
+
+void SAL_CALL
+ScVbaWorksheets::Copy ( const uno::Any& Before, const uno::Any& After)
+{
+ uno::Reference<excel::XWorksheet> xSheet;
+ sal_Int32 nElems = getCount();
+ bool bAfter = After.hasValue();
+ std::vector< uno::Reference< excel::XWorksheet > > Sheets;
+ sal_Int32 nItem = 0;
+
+ for ( nItem = 1; nItem <= nElems; ++nItem)
+ {
+ uno::Reference<excel::XWorksheet> xWorksheet(Item( uno::Any( nItem ), uno::Any() ), uno::UNO_QUERY_THROW );
+ Sheets.push_back(xWorksheet);
+ }
+ bool bNewDoc = (!(Before >>= xSheet) && !(After >>=xSheet)&& !(Before.hasValue()) && !(After.hasValue()));
+
+ uno::Reference< excel::XWorksheet > xSrcSheet;
+ if ( bNewDoc )
+ {
+ bAfter = true;
+ xSrcSheet = Sheets.at(0);
+ ScVbaWorksheet* pSrcSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSrcSheet );
+ xSheet = pSrcSheet->createSheetCopyInNewDoc(xSrcSheet->getName());
+ nItem = 1;
+ }
+ else
+ {
+ nItem=0;
+ }
+
+ for (; nItem < nElems; ++nItem )
+ {
+ xSrcSheet = Sheets[nItem];
+ ScVbaWorksheet* pSrcSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSrcSheet );
+ if ( bAfter )
+ xSheet = pSrcSheet->createSheetCopy(xSheet, bAfter);
+ else
+ pSrcSheet->createSheetCopy(xSheet, bAfter);
+ }
+}
+
+//ScVbaCollectionBaseImpl
+uno::Any SAL_CALL
+ScVbaWorksheets::Item(const uno::Any& Index, const uno::Any& Index2)
+{
+ if ( Index.getValueTypeClass() == uno::TypeClass_SEQUENCE )
+ {
+ const uno::Reference< script::XTypeConverter >& xConverter = getTypeConverter(mxContext);
+ uno::Any aConverted = xConverter->convertTo( Index, cppu::UnoType<uno::Sequence< uno::Any >>::get() );
+ SheetMap aSheets;
+ uno::Sequence< uno::Any > sIndices;
+ aConverted >>= sIndices;
+ for( const auto& rIndex : std::as_const(sIndices) )
+ {
+ uno::Reference< excel::XWorksheet > xWorkSheet( ScVbaWorksheets_BASE::Item( rIndex, Index2 ), uno::UNO_QUERY_THROW );
+ ScVbaWorksheet* pWorkSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xWorkSheet );
+ uno::Reference< sheet::XSpreadsheet > xSheet( pWorkSheet->getSheet() , uno::UNO_SET_THROW );
+ uno::Reference< container::XNamed > xName( xSheet, uno::UNO_QUERY_THROW );
+ aSheets.push_back( xSheet );
+ }
+ uno::Reference< container::XIndexAccess > xIndexAccess = new SheetCollectionHelper( std::move(aSheets) );
+ uno::Reference< XCollection > xSelectedSheets( new ScVbaWorksheets( getParent(), mxContext, xIndexAccess, mxModel ) );
+ return uno::Any( xSelectedSheets );
+ }
+ return ScVbaWorksheets_BASE::Item( Index, Index2 );
+}
+
+OUString
+ScVbaWorksheets::getServiceImplName()
+{
+ return "ScVbaWorksheets";
+}
+
+css::uno::Sequence<OUString>
+ScVbaWorksheets::getServiceNames()
+{
+ static uno::Sequence< OUString > const sNames
+ {
+ "ooo.vba.excel.Worksheets"
+ };
+ return sNames;
+}
+
+bool ScVbaWorksheets::nameExists( const uno::Reference <sheet::XSpreadsheetDocument>& xSpreadDoc, std::u16string_view name, SCTAB& nTab )
+{
+ if (!xSpreadDoc.is())
+ throw lang::IllegalArgumentException( "nameExists() xSpreadDoc is null", uno::Reference< uno::XInterface >(), 1 );
+ uno::Reference <container::XIndexAccess> xIndex( xSpreadDoc->getSheets(), uno::UNO_QUERY );
+ if ( xIndex.is() )
+ {
+ SCTAB nCount = static_cast< SCTAB >( xIndex->getCount() );
+ for (SCTAB i=0; i < nCount; i++)
+ {
+ uno::Reference< container::XNamed > xNamed( xIndex->getByIndex(i), uno::UNO_QUERY_THROW );
+ if (xNamed->getName() == name)
+ {
+ nTab = i;
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void ScVbaWorksheets::PrintPreview( const css::uno::Any& /*EnableChanges*/ )
+{
+ // need test, print preview current active sheet
+ // !! TODO !! get view shell from controller
+ ScTabViewShell* pViewShell = excel::getBestViewShell( mxModel );
+ SfxViewFrame* pViewFrame = nullptr;
+ if ( pViewShell )
+ pViewFrame = pViewShell->GetViewFrame();
+ if ( !pViewFrame )
+ return;
+
+ if ( pViewFrame->GetFrame().IsInPlace() )
+ return;
+
+ dispatchExecute( pViewShell, SID_VIEWSHELL1 );
+ SfxViewShell* pShell = SfxViewShell::Get( pViewFrame->GetFrame().GetFrameInterface()->getController() );
+
+ ScPreviewShell* pPrvShell = dynamic_cast< ScPreviewShell* >( pShell );
+ if ( !pPrvShell )
+ return;
+
+ ScPreview* pPrvView = pPrvShell->GetPreview();
+ const ScDocument& rDoc = pViewShell->GetViewData().GetDocument();
+ ScMarkData aMarkData(rDoc.GetSheetLimits());
+ sal_Int32 nElems = getCount();
+ for ( sal_Int32 nItem = 1; nItem <= nElems; ++nItem )
+ {
+ uno::Reference< excel::XWorksheet > xSheet( Item( uno::Any( nItem ), uno::Any() ), uno::UNO_QUERY_THROW );
+ ScVbaWorksheet* pSheet = excel::getImplFromDocModuleWrapper<ScVbaWorksheet>( xSheet );
+ if ( pSheet )
+ aMarkData.SelectTable(static_cast< SCTAB >( pSheet->getSheetID() ), true );
+ }
+ // save old selection, setting the selectedtabs in the preview
+ // can affect the current selection when preview has been
+ // closed
+ ScMarkData::MarkedTabsType aOldTabs = pPrvView->GetSelectedTabs();
+ pPrvView->SetSelectedTabs( aMarkData );
+ // force update
+ pPrvView->DataChanged(false);
+ // set sensible first page
+ tools::Long nPage = pPrvView->GetFirstPage( 1 );
+ pPrvView->SetPageNo( nPage );
+ WaitUntilPreviewIsClosed( pViewFrame );
+ // restore old tab selection
+ pViewShell = excel::getBestViewShell( mxModel );
+ pViewShell->GetViewData().GetMarkData().SetSelectedTabs(aOldTabs);
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbaworksheets.hxx b/sc/source/ui/vba/vbaworksheets.hxx
new file mode 100644
index 000000000..b795fbf5a
--- /dev/null
+++ b/sc/source/ui/vba/vbaworksheets.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 <ooo/vba/excel/XWorksheets.hpp>
+
+#include <vbahelper/vbacollectionimpl.hxx>
+
+#include <types.hxx>
+
+namespace com::sun::star::container { class XEnumerationAccess; }
+namespace com::sun::star::sheet { class XSpreadsheetDocument; }
+namespace com::sun::star::sheet { class XSpreadsheets; }
+namespace com::sun::star::uno { class XComponentContext; }
+
+typedef CollTestImplHelper< ov::excel::XWorksheets > ScVbaWorksheets_BASE;
+
+class ScVbaWorksheets : public ScVbaWorksheets_BASE
+{
+ css::uno::Reference< css::frame::XModel > mxModel;
+ css::uno::Reference< css::sheet::XSpreadsheets > m_xSheets;
+public:
+ ScVbaWorksheets( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::container::XIndexAccess >& xSheets, const css::uno::Reference< css::frame::XModel >& xModel );
+ ScVbaWorksheets( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext > & xContext, const css::uno::Reference< css::container::XEnumerationAccess >& xEnum, const css::uno::Reference< css::frame::XModel >& xModel );
+
+ bool isSelectedSheets() const;
+
+ // XEnumerationAccess
+ virtual css::uno::Type SAL_CALL getElementType() override;
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration() override;
+
+ // XWorksheets
+ virtual css::uno::Any SAL_CALL getVisible() override;
+ virtual void SAL_CALL setVisible( const css::uno::Any& _visible ) override;
+ virtual css::uno::Any SAL_CALL Add( const css::uno::Any& Before, const css::uno::Any& After, const css::uno::Any& Count, const css::uno::Any& Type ) override;
+ virtual void SAL_CALL Delete( ) override;
+ virtual void SAL_CALL PrintOut( const css::uno::Any& From, const css::uno::Any& To, const css::uno::Any& Copies, const css::uno::Any& Preview, const css::uno::Any& ActivePrinter, const css::uno::Any& PrintToFile, const css::uno::Any& Collate, const css::uno::Any& PrToFileName ) override;
+ virtual css::uno::Any createCollectionObject( const css::uno::Any& aSource ) override;
+ virtual void SAL_CALL Select( const css::uno::Any& Replace ) override;
+ virtual void SAL_CALL Copy ( const css::uno::Any& Before, const css::uno::Any& After) override;
+ virtual void SAL_CALL PrintPreview( const css::uno::Any& EnableChanges ) override;
+ // ScVbaWorksheets_BASE
+ virtual css::uno::Any SAL_CALL Item( const css::uno::Any& Index1, const css::uno::Any& Index2 ) override;
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+
+ /// @throws css::lang::IllegalArgumentException
+ /// @throws css::uno::RuntimeException
+ static bool nameExists( const css::uno::Reference <css::sheet::XSpreadsheetDocument>& xSpreadDoc, std::u16string_view name, SCTAB& nTab );
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbawsfunction.cxx b/sc/source/ui/vba/vbawsfunction.cxx
new file mode 100644
index 000000000..6af173223
--- /dev/null
+++ b/sc/source/ui/vba/vbawsfunction.cxx
@@ -0,0 +1,298 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <com/sun/star/table/XCellRange.hpp>
+#include <com/sun/star/beans/XIntrospectionAccess.hpp>
+#include <com/sun/star/sheet/XFunctionAccess.hpp>
+#include <com/sun/star/sheet/XCellRangeAddressable.hpp>
+#include <ooo/vba/excel/XRange.hpp>
+
+#include "vbawsfunction.hxx"
+#include <compiler.hxx>
+
+using namespace com::sun::star;
+using namespace ooo::vba;
+
+namespace {
+
+void lclConvertDoubleToBoolean( uno::Any& rAny )
+{
+ if( rAny.has< double >() )
+ {
+ double fValue = rAny.get< double >();
+ if( fValue == 0.0 )
+ rAny <<= false;
+ else if( fValue == 1.0 )
+ rAny <<= true;
+ // do nothing for other values or types
+ }
+}
+
+void lclConvertBooleanToDouble( uno::Any& rAny )
+{
+ bool bValue( false );
+ if ( rAny >>= bValue )
+ {
+ if ( bValue )
+ rAny <<= 1.0;
+ else
+ rAny <<= 0.0;
+ }
+}
+
+} // namespace
+
+ScVbaWSFunction::ScVbaWSFunction( const uno::Reference< XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext ) :
+ ScVbaWSFunction_BASE( xParent, xContext )
+{
+}
+
+uno::Reference< beans::XIntrospectionAccess >
+ScVbaWSFunction::getIntrospection()
+{
+ return uno::Reference<beans::XIntrospectionAccess>();
+}
+
+uno::Any SAL_CALL
+ScVbaWSFunction::invoke(const OUString& FunctionName, const uno::Sequence< uno::Any >& Params, uno::Sequence< sal_Int16 >& /*OutParamIndex*/, uno::Sequence< uno::Any >& /*OutParam*/)
+{
+ // create copy of parameters, replace Excel range objects with UNO range objects
+ uno::Sequence< uno::Any > aParamTemp( Params );
+ if( aParamTemp.hasElements() )
+ {
+ for( uno::Any & rArray : asNonConstRange(aParamTemp) )
+ {
+ switch( rArray.getValueType().getTypeClass() )
+ {
+ case uno::TypeClass_BOOLEAN:
+ lclConvertBooleanToDouble( rArray );
+ break;
+ case uno::TypeClass_INTERFACE:
+ {
+ uno::Reference< excel::XRange > myRange( rArray, uno::UNO_QUERY );
+ if( myRange.is() )
+ rArray = myRange->getCellRange();
+ }
+ break;
+ case uno::TypeClass_SEQUENCE:
+ {
+ // the sheet.FunctionAccess service doesn't deal with Sequences, only Sequences of Sequence
+ uno::Type aType = rArray.getValueType();
+ if ( aType.equals( cppu::UnoType<uno::Sequence<sal_Int16>>::get() ) )
+ {
+ uno::Sequence< uno::Sequence< sal_Int16 > > aTmp(1);
+ rArray >>= aTmp.getArray()[ 0 ];
+ rArray <<= aTmp;
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence<sal_Int32>>::get() ) )
+ {
+ uno::Sequence< uno::Sequence< sal_Int32 > > aTmp(1);
+ rArray >>= aTmp.getArray()[ 0 ];
+ rArray <<= aTmp;
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence<double>>::get() ) )
+ {
+ uno::Sequence< uno::Sequence< double > > aTmp(1);
+ rArray >>= aTmp.getArray()[ 0 ];
+ rArray <<= aTmp;
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence<OUString>>::get() ) )
+ {
+ uno::Sequence< uno::Sequence< OUString > > aTmp(1);
+ rArray >>= aTmp.getArray()[ 0 ];
+ rArray <<= aTmp;
+ }
+ else if ( aType.equals( cppu::UnoType<uno::Sequence<uno::Any>>::get() ) )
+ {
+ uno::Sequence< uno::Sequence<uno::Any > > aTmp(1);
+ rArray >>= aTmp.getArray()[ 0 ];
+ rArray <<= aTmp;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ uno::Any aRet;
+ bool bAsArray = true;
+
+ // special handing for some functions that don't work correctly in FunctionAccess
+ formula::FormulaCompiler aCompiler;
+ OpCode eOpCode = aCompiler.GetEnglishOpCode( FunctionName.toAsciiUpperCase() );
+ switch( eOpCode )
+ {
+ // ISLOGICAL does not work in array formula mode
+ case ocIsLogical:
+ {
+ if( aParamTemp.getLength() != 1 )
+ throw lang::IllegalArgumentException();
+ const uno::Any& rParam = aParamTemp[ 0 ];
+ if( rParam.has< bool >() )
+ {
+ aRet <<= true;
+ }
+ else if( rParam.has< uno::Reference< table::XCellRange > >() ) try
+ {
+ uno::Reference< sheet::XCellRangeAddressable > xRangeAddr( rParam, uno::UNO_QUERY_THROW );
+ table::CellRangeAddress aRangeAddr = xRangeAddr->getRangeAddress();
+ bAsArray = (aRangeAddr.StartColumn != aRangeAddr.EndColumn) || (aRangeAddr.StartRow != aRangeAddr.EndRow);
+ }
+ catch( uno::Exception& )
+ {
+ }
+ }
+ break;
+ default:;
+ }
+
+ if( !aRet.hasValue() )
+ {
+ uno::Reference< lang::XMultiComponentFactory > xSMgr( mxContext->getServiceManager(), uno::UNO_SET_THROW );
+ uno::Reference< sheet::XFunctionAccess > xFunctionAccess( xSMgr->createInstanceWithContext(
+ "com.sun.star.sheet.FunctionAccess", mxContext ),
+ uno::UNO_QUERY_THROW );
+ uno::Reference< beans::XPropertySet > xPropSet( xFunctionAccess, uno::UNO_QUERY_THROW );
+ xPropSet->setPropertyValue("IsArrayFunction", uno::Any( bAsArray ) );
+ aRet = xFunctionAccess->callFunction( FunctionName, aParamTemp );
+ }
+
+ /* Convert return value from double to Boolean for some functions that
+ return Booleans. */
+ typedef uno::Sequence< uno::Sequence< uno::Any > > AnySeqSeq;
+ if( (eOpCode == ocIsEmpty) || (eOpCode == ocIsString) || (eOpCode == ocIsNonString) || (eOpCode == ocIsLogical) ||
+ (eOpCode == ocIsRef) || (eOpCode == ocIsValue) || (eOpCode == ocIsFormula) || (eOpCode == ocIsNA) ||
+ (eOpCode == ocIsErr) || (eOpCode == ocIsError) || (eOpCode == ocIsEven) || (eOpCode == ocIsOdd) ||
+ (eOpCode == ocAnd) || (eOpCode == ocOr) || (eOpCode == ocXor) || (eOpCode == ocNot) || (eOpCode == ocTrue) || (eOpCode == ocFalse) )
+ {
+ if( aRet.has< AnySeqSeq >() )
+ {
+ AnySeqSeq aAnySeqSeq = aRet.get< AnySeqSeq >();
+ for( auto& rAnySeq : asNonConstRange(aAnySeqSeq) )
+ for( auto& rAny : asNonConstRange(rAnySeq) )
+ lclConvertDoubleToBoolean( rAny );
+ aRet <<= aAnySeqSeq;
+ }
+ else
+ {
+ lclConvertDoubleToBoolean( aRet );
+ }
+ }
+
+ /* Hack/workaround (?): shorten single-row matrix to simple array, shorten
+ 1x1 matrix to single value. */
+ if( aRet.has< AnySeqSeq >() )
+ {
+ AnySeqSeq aAnySeqSeq = aRet.get< AnySeqSeq >();
+ if( aAnySeqSeq.getLength() == 1 )
+ {
+ if( aAnySeqSeq[ 0 ].getLength() == 1 )
+ aRet = aAnySeqSeq[ 0 ][ 0 ];
+ else
+ aRet <<= aAnySeqSeq[ 0 ];
+ }
+ }
+
+#if 0
+ // MATCH function should alwayse return a double value, but currently if the first argument is XCellRange, MATCH function returns an array instead of a double value. Don't know why?
+ // To fix this issue in safe, current solution is to convert this array to a double value just for MATCH function.
+ OUString aUpper( FunctionName.toAsciiUpperCase() );
+ ScCompiler aCompiler( NULL, ScAddress() );
+ OpCode eOp = aCompiler.GetEnglishOpCode( aUpper );
+ if( eOp == ocMatch )
+ {
+ double fVal = 0.0;
+ if( aRet >>= fVal )
+ return aRet;
+ uno::Sequence< uno::Sequence< uno::Any > > aSequence;
+ if( !( ( aRet >>= aSequence ) && ( aSequence.getLength() > 0 ) &&
+ ( aSequence[0].getLength() > 0 ) && ( aSequence[0][0] >>= fVal ) ) )
+ throw uno::RuntimeException();
+ aRet <<= fVal;
+ }
+#endif
+
+ return aRet;
+}
+
+void SAL_CALL
+ScVbaWSFunction::setValue(const OUString& /*PropertyName*/, const uno::Any& /*Value*/)
+{
+ throw beans::UnknownPropertyException();
+}
+
+uno::Any SAL_CALL
+ScVbaWSFunction::getValue(const OUString& /*PropertyName*/)
+{
+ throw beans::UnknownPropertyException();
+}
+
+sal_Bool SAL_CALL
+ScVbaWSFunction::hasMethod(const OUString& Name)
+{
+ bool bIsFound = false;
+ try
+ {
+ // the function name contained in the com.sun.star.sheet.FunctionDescription service is alwayse localized.
+ // but the function name used in WorksheetFunction is a programmatic name (seems English).
+ // So m_xNameAccess->hasByName( Name ) may fail to find name when a function name has a localized name.
+ if( ScCompiler::IsEnglishSymbol( Name ) )
+ bIsFound = true;
+ }
+ catch( uno::Exception& /*e*/ )
+ {
+ // failed to find name
+ }
+ return bIsFound;
+}
+
+sal_Bool SAL_CALL
+ScVbaWSFunction::hasProperty(const OUString& /*Name*/)
+{
+ return false;
+}
+
+OUString SAL_CALL
+ScVbaWSFunction::getExactName( const OUString& aApproximateName )
+{
+ OUString sName = aApproximateName.toAsciiUpperCase();
+ if ( !hasMethod( sName ) )
+ return OUString();
+ return sName;
+}
+
+OUString
+ScVbaWSFunction::getServiceImplName()
+{
+ return "ScVbaWSFunction";
+}
+
+uno::Sequence< OUString >
+ScVbaWSFunction::getServiceNames()
+{
+ static uno::Sequence< OUString > const aServiceNames
+ {
+ "ooo.vba.excel.WorksheetFunction"
+ };
+ return aServiceNames;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/vba/vbawsfunction.hxx b/sc/source/ui/vba/vbawsfunction.hxx
new file mode 100644
index 000000000..9a5dd821f
--- /dev/null
+++ b/sc/source/ui/vba/vbawsfunction.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 <ooo/vba/excel/XWorksheetFunction.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <vbahelper/vbahelperinterface.hxx>
+
+typedef InheritedHelperInterfaceWeakImpl< ov::excel::XWorksheetFunction > ScVbaWSFunction_BASE;
+
+class ScVbaWSFunction : public ScVbaWSFunction_BASE
+{
+public:
+ ScVbaWSFunction( const css::uno::Reference< ov::XHelperInterface >& xParent, const css::uno::Reference< css::uno::XComponentContext >& xContext);
+
+ virtual css::uno::Reference< css::beans::XIntrospectionAccess > SAL_CALL getIntrospection() override;
+ virtual css::uno::Any SAL_CALL invoke(const OUString& FunctionName, const css::uno::Sequence< css::uno::Any >& Params, css::uno::Sequence< sal_Int16 >& OutParamIndex, css::uno::Sequence< css::uno::Any >& OutParam) override;
+ virtual void SAL_CALL setValue(const OUString& PropertyName, const css::uno::Any& Value) override;
+ virtual css::uno::Any SAL_CALL getValue(const OUString& PropertyName) override;
+ virtual sal_Bool SAL_CALL hasMethod(const OUString& Name) override;
+ virtual sal_Bool SAL_CALL hasProperty(const OUString& Name) override;
+ virtual OUString SAL_CALL getExactName( const OUString& aApproximateName ) override;
+ // XHelperInterface
+ virtual OUString getServiceImplName() override;
+ virtual css::uno::Sequence<OUString> getServiceNames() override;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/SparklineShell.cxx b/sc/source/ui/view/SparklineShell.cxx
new file mode 100644
index 000000000..3b3c4f839
--- /dev/null
+++ b/sc/source/ui/view/SparklineShell.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/.
+ *
+ */
+
+#include <scitems.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+#include <svl/whiter.hxx>
+#include <vcl/EnumContext.hxx>
+
+#include <sc.hrc>
+#include <SparklineShell.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+
+#define ShellClass_SparklineShell
+#include <scslots.hxx>
+
+namespace sc
+{
+SFX_IMPL_INTERFACE(SparklineShell, SfxShell)
+
+void SparklineShell::InitInterface_Impl() { GetStaticInterface()->RegisterPopupMenu("sparkline"); }
+
+SparklineShell::SparklineShell(ScTabViewShell* pViewShell)
+ : SfxShell(pViewShell)
+ , m_pViewShell(pViewShell)
+{
+ SetPool(&m_pViewShell->GetPool());
+ ScViewData& rViewData = m_pViewShell->GetViewData();
+ SfxUndoManager* pUndoManager = rViewData.GetSfxDocShell()->GetUndoManager();
+ SetUndoManager(pUndoManager);
+ if (!rViewData.GetDocument().IsUndoEnabled())
+ {
+ pUndoManager->SetMaxUndoActionCount(0);
+ }
+ SetName("Sparkline");
+ SfxShell::SetContextName(
+ vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Sparkline));
+}
+
+SparklineShell::~SparklineShell() = default;
+
+} // end sc namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/auditsh.cxx b/sc/source/ui/view/auditsh.cxx
new file mode 100644
index 000000000..2ea903f59
--- /dev/null
+++ b/sc/source/ui/view/auditsh.cxx
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+#include <vcl/EnumContext.hxx>
+
+#include <auditsh.hxx>
+#include <tabvwsh.hxx>
+#include <sc.hrc>
+#include <document.hxx>
+
+#define ShellClass_ScAuditingShell
+#include <scslots.hxx>
+
+
+SFX_IMPL_INTERFACE(ScAuditingShell, SfxShell)
+
+void ScAuditingShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterPopupMenu("audit");
+}
+
+ScAuditingShell::ScAuditingShell(ScViewData& rData) :
+ SfxShell(rData.GetViewShell()),
+ rViewData( rData ),
+ nFunction( SID_FILL_ADD_PRED )
+{
+ SetPool( &rViewData.GetViewShell()->GetPool() );
+ SfxUndoManager* pMgr = rViewData.GetSfxDocShell()->GetUndoManager();
+ SetUndoManager( pMgr );
+ if ( !rViewData.GetDocument().IsUndoEnabled() )
+ {
+ pMgr->SetMaxUndoActionCount( 0 );
+ }
+ SetName("Auditing");
+ SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Auditing));
+}
+
+ScAuditingShell::~ScAuditingShell()
+{
+}
+
+void ScAuditingShell::Execute( const SfxRequest& rReq )
+{
+ SfxBindings& rBindings = rViewData.GetBindings();
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch ( nSlot )
+ {
+ case SID_FILL_ADD_PRED:
+ case SID_FILL_DEL_PRED:
+ case SID_FILL_ADD_SUCC:
+ case SID_FILL_DEL_SUCC:
+ nFunction = nSlot;
+ rBindings.Invalidate( SID_FILL_ADD_PRED );
+ rBindings.Invalidate( SID_FILL_DEL_PRED );
+ rBindings.Invalidate( SID_FILL_ADD_SUCC );
+ rBindings.Invalidate( SID_FILL_DEL_SUCC );
+ break;
+ case SID_CANCEL: // Escape
+ case SID_FILL_NONE:
+ rViewData.GetViewShell()->SetAuditShell( false );
+ break;
+
+ case SID_FILL_SELECT:
+ {
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ if ( pReqArgs )
+ {
+ const SfxInt16Item* pXItem = pReqArgs->GetItemIfSet( SID_RANGE_COL );
+ const SfxInt32Item* pYItem = pReqArgs->GetItemIfSet( SID_RANGE_ROW );
+ if ( pXItem && pYItem )
+ {
+ SCCOL nCol = static_cast<SCCOL>(pXItem->GetValue());
+ SCROW nRow = static_cast<SCROW>(pYItem->GetValue());
+ ScViewFunc* pView = rViewData.GetView();
+ pView->MoveCursorAbs( nCol, nRow, SC_FOLLOW_LINE, false, false );
+ switch ( nFunction )
+ {
+ case SID_FILL_ADD_PRED:
+ pView->DetectiveAddPred();
+ break;
+ case SID_FILL_DEL_PRED:
+ pView->DetectiveDelPred();
+ break;
+ case SID_FILL_ADD_SUCC:
+ pView->DetectiveAddSucc();
+ break;
+ case SID_FILL_DEL_SUCC:
+ pView->DetectiveDelSucc();
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+}
+
+void ScAuditingShell::GetState( SfxItemSet& rSet )
+{
+ rSet.Put( SfxBoolItem( nFunction, true ) ); // mark active functions
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/cellmergeoption.cxx b/sc/source/ui/view/cellmergeoption.cxx
new file mode 100644
index 000000000..524117080
--- /dev/null
+++ b/sc/source/ui/view/cellmergeoption.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 <cellmergeoption.hxx>
+#include <address.hxx>
+
+ScCellMergeOption::ScCellMergeOption(const ScRange& rRange) :
+ mnStartCol(rRange.aStart.Col()),
+ mnStartRow(rRange.aStart.Row()),
+ mnEndCol(rRange.aEnd.Col()),
+ mnEndRow(rRange.aEnd.Row()),
+ mbCenter(false)
+{
+ SCTAB nTab1 = rRange.aStart.Tab();
+ SCTAB nTab2 = rRange.aEnd.Tab();
+ for (SCTAB i = nTab1; i <= nTab2; ++i)
+ maTabs.insert(i);
+}
+
+ScCellMergeOption::ScCellMergeOption(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, bool bCenter) :
+ mnStartCol(nStartCol),
+ mnStartRow(nStartRow),
+ mnEndCol(nEndCol),
+ mnEndRow(nEndRow),
+ mbCenter(bCenter)
+{
+}
+
+ScRange ScCellMergeOption::getSingleRange(SCTAB nTab) const
+{
+ return ScRange(mnStartCol, mnStartRow, nTab, mnEndCol, mnEndRow, nTab);
+}
+
+ScRange ScCellMergeOption::getFirstSingleRange() const
+{
+ SCTAB nTab = 0;
+ if (!maTabs.empty())
+ nTab = *maTabs.begin();
+
+ return getSingleRange(nTab);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/cellsh.cxx b/sc/source/ui/view/cellsh.cxx
new file mode 100644
index 000000000..215587cfa
--- /dev/null
+++ b/sc/source/ui/view/cellsh.cxx
@@ -0,0 +1,1322 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+
+#include <svl/slstitm.hxx>
+#include <svl/stritem.hxx>
+#include <svl/whiter.hxx>
+#include <svtools/cliplistener.hxx>
+#include <svtools/insdlg.hxx>
+#include <sot/formats.hxx>
+#include <svx/hlnkitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/EnumContext.hxx>
+#include <vcl/svapp.hxx>
+#include <svx/clipfmtitem.hxx>
+
+#include <cellsh.hxx>
+#include <sc.hrc>
+#include <docsh.hxx>
+#include <attrib.hxx>
+#include <tabvwsh.hxx>
+#include <formulacell.hxx>
+#include <scmod.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <transobj.hxx>
+#include <drwtrans.hxx>
+#include <scabstdlg.hxx>
+#include <postit.hxx>
+#include <cliputil.hxx>
+#include <clipparam.hxx>
+#include <markdata.hxx>
+#include <gridwin.hxx>
+#include <Sparkline.hxx>
+#include <SparklineGroup.hxx>
+
+#define ShellClass_ScCellShell
+#define ShellClass_CellMovement
+#include <scslots.hxx>
+
+
+SFX_IMPL_INTERFACE(ScCellShell, ScFormatShell)
+
+void ScCellShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT,
+ SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server,
+ ToolbarId::Objectbar_Format);
+
+ GetStaticInterface()->RegisterPopupMenu("cell");
+}
+
+ScCellShell::ScCellShell(ScViewData& rData, const VclPtr<vcl::Window>& frameWin) :
+ ScFormatShell(rData),
+ pImpl( new CellShell_Impl() ),
+ bPastePossible(false),
+ pFrameWin(frameWin)
+{
+ SetName("Cell");
+ SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Cell));
+}
+
+ScCellShell::~ScCellShell()
+{
+ if ( pImpl->m_xClipEvtLstnr.is() )
+ {
+ pImpl->m_xClipEvtLstnr->RemoveListener( GetViewData().GetActiveWin() );
+
+ // The listener may just now be waiting for the SolarMutex and call the link
+ // afterwards, in spite of RemoveListener. So the link has to be reset, too.
+ pImpl->m_xClipEvtLstnr->ClearCallbackLink();
+
+ pImpl->m_xClipEvtLstnr.clear();
+ }
+
+ pImpl->m_pLinkedDlg.disposeAndClear();
+ delete pImpl->m_pRequest;
+}
+
+void ScCellShell::GetBlockState( SfxItemSet& rSet )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ ScRange aMarkRange;
+ ScMarkType eMarkType = GetViewData().GetSimpleArea( aMarkRange );
+ bool bSimpleArea = (eMarkType == SC_MARK_SIMPLE);
+ bool bOnlyNotBecauseOfMatrix;
+ bool bEditable = pTabViewShell->SelectionEditable( &bOnlyNotBecauseOfMatrix );
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDocShell* pDocShell = GetViewData().GetDocShell();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ nCol1 = aMarkRange.aStart.Col();
+ nRow1 = aMarkRange.aStart.Row();
+ nCol2 = aMarkRange.aEnd.Col();
+ nRow2 = aMarkRange.aEnd.Row();
+ SCTAB nTab = GetViewData().GetTabNo();
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while ( nWhich )
+ {
+ bool bDisable = false;
+ bool bNeedEdit = true; // need selection be editable?
+ switch ( nWhich )
+ {
+ case FID_FILL_TO_BOTTOM: // fill to top / bottom
+ {
+ bDisable = !bSimpleArea || (nRow1 == 0 && nRow2 == 0);
+ if (!bDisable && GetViewData().SelectionForbidsCellFill())
+ bDisable = true;
+ if ( !bDisable && bEditable )
+ { // do not damage matrix
+ bDisable = rDoc.HasSelectedBlockMatrixFragment(
+ nCol1, nRow1, nCol2, nRow1, rMark ); // first row
+ }
+ }
+ break;
+ case FID_FILL_TO_TOP:
+ {
+ bDisable = (!bSimpleArea) || (nRow1 == rDoc.MaxRow() && nRow2 == rDoc.MaxRow());
+ if (!bDisable && GetViewData().SelectionForbidsCellFill())
+ bDisable = true;
+ if ( !bDisable && bEditable )
+ { // do not damage matrix
+ bDisable = rDoc.HasSelectedBlockMatrixFragment(
+ nCol1, nRow2, nCol2, nRow2, rMark ); // last row
+ }
+ }
+ break;
+ case FID_FILL_TO_RIGHT: // fill to left / right
+ {
+ bDisable = !bSimpleArea || (nCol1 == 0 && nCol2 == 0);
+ if (!bDisable && GetViewData().SelectionForbidsCellFill())
+ bDisable = true;
+ if ( !bDisable && bEditable )
+ { // do not damage matrix
+ bDisable = rDoc.HasSelectedBlockMatrixFragment(
+ nCol1, nRow1, nCol1, nRow2, rMark ); // first column
+ }
+ }
+ break;
+ case FID_FILL_TO_LEFT:
+ {
+ bDisable = (!bSimpleArea) || (nCol1 == rDoc.MaxCol() && nCol2 == rDoc.MaxCol());
+ if (!bDisable && GetViewData().SelectionForbidsCellFill())
+ bDisable = true;
+ if ( !bDisable && bEditable )
+ { // do not damage matrix
+ bDisable = rDoc.HasSelectedBlockMatrixFragment(
+ nCol2, nRow1, nCol2, nRow2, rMark ); // last column
+ }
+ }
+ break;
+
+ case SID_RANDOM_NUMBER_GENERATOR_DIALOG:
+ bDisable = !bSimpleArea || GetViewData().SelectionForbidsCellFill();
+ break;
+ case SID_SAMPLING_DIALOG:
+ case SID_DESCRIPTIVE_STATISTICS_DIALOG:
+ case SID_ANALYSIS_OF_VARIANCE_DIALOG:
+ case SID_CORRELATION_DIALOG:
+ case SID_COVARIANCE_DIALOG:
+ case SID_INSERT_SPARKLINE:
+ {
+ bDisable = !bSimpleArea;
+ }
+ break;
+ case SID_GROUP_SPARKLINES:
+ case SID_UNGROUP_SPARKLINES:
+ {
+ bDisable = !bSimpleArea;
+ }
+ break;
+
+ case SID_EDIT_SPARKLINE:
+ {
+ bDisable = !rDoc.HasSparkline(GetViewData().GetCurPos());
+ }
+ break;
+
+ case SID_DELETE_SPARKLINE:
+ case SID_EDIT_SPARKLINE_GROUP:
+ case SID_DELETE_SPARKLINE_GROUP:
+ {
+ bDisable = !rDoc.HasOneSparklineGroup(ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab));
+ }
+ break;
+
+ case FID_FILL_SERIES: // fill block
+ case SID_OPENDLG_TABOP: // multiple-cell operations, are at least 2 cells marked?
+ if (rDoc.GetChangeTrack()!=nullptr &&nWhich ==SID_OPENDLG_TABOP)
+ bDisable = true;
+ else
+ bDisable = (!bSimpleArea) || (nCol1 == nCol2 && nRow1 == nRow2);
+
+ if (!bDisable && GetViewData().SelectionForbidsCellFill())
+ bDisable = true;
+
+ if ( !bDisable && bEditable && nWhich == FID_FILL_SERIES )
+ { // do not damage matrix
+ bDisable = rDoc.HasSelectedBlockMatrixFragment(
+ nCol1, nRow1, nCol2, nRow1, rMark ) // first row
+ || rDoc.HasSelectedBlockMatrixFragment(
+ nCol1, nRow2, nCol2, nRow2, rMark ) // last row
+ || rDoc.HasSelectedBlockMatrixFragment(
+ nCol1, nRow1, nCol1, nRow2, rMark ) // first column
+ || rDoc.HasSelectedBlockMatrixFragment(
+ nCol2, nRow1, nCol2, nRow2, rMark ); // last column
+ }
+ break;
+ case FID_FILL_SINGLE_EDIT:
+ bDisable = false;
+ break;
+ case SID_CUT: // cut
+ bDisable = !bSimpleArea || GetObjectShell()->isContentExtractionLocked();
+ break;
+ case FID_INS_CELL: // insert cells, just simple selection
+ bDisable = (!bSimpleArea);
+ break;
+
+ case SID_PASTE:
+ case SID_PASTE_SPECIAL:
+ case SID_PASTE_UNFORMATTED:
+ case SID_PASTE_ONLY_VALUE:
+ case SID_PASTE_ONLY_TEXT:
+ case SID_PASTE_ONLY_FORMULA:
+ case SID_PASTE_TRANSPOSED:
+ case SID_PASTE_AS_LINK:
+ case SID_PASTE_TEXTIMPORT_DIALOG:
+ bDisable = GetViewData().SelectionForbidsPaste();
+ break;
+
+ case FID_INS_ROW:
+ case FID_INS_ROWS_BEFORE: // insert rows
+ case FID_INS_ROWS_AFTER:
+ {
+ sc::ColRowEditAction eAction = sc::ColRowEditAction::InsertRowsBefore;
+ if (nWhich == FID_INS_ROWS_AFTER)
+ eAction = sc::ColRowEditAction::InsertRowsAfter;
+
+ bDisable = (!bSimpleArea) || GetViewData().SimpleColMarked();
+ if (!bEditable && nCol1 == 0 && nCol2 == rDoc.MaxCol())
+ {
+ // See if row insertions are allowed.
+ bEditable = rDoc.IsEditActionAllowed(eAction, rMark, nRow1, nRow2);
+ }
+ break;
+ }
+ case FID_INS_CELLSDOWN:
+ bDisable = (!bSimpleArea) || GetViewData().SimpleColMarked();
+ break;
+
+ case FID_INS_COLUMN:
+ case FID_INS_COLUMNS_BEFORE: // insert columns
+ case FID_INS_COLUMNS_AFTER:
+ {
+ sc::ColRowEditAction eAction = sc::ColRowEditAction::InsertColumnsBefore;
+ if (nWhich == FID_INS_COLUMNS_AFTER)
+ eAction = sc::ColRowEditAction::InsertColumnsAfter;
+
+ bDisable = (!bSimpleArea && eMarkType != SC_MARK_SIMPLE_FILTERED)
+ || GetViewData().SimpleRowMarked();
+ if (!bEditable && nRow1 == 0 && nRow2 == rDoc.MaxRow())
+ {
+ // See if row insertions are allowed.
+ bEditable = rDoc.IsEditActionAllowed(eAction, rMark, nCol1, nCol2);
+ }
+ break;
+ }
+ case FID_INS_CELLSRIGHT:
+ bDisable = (!bSimpleArea) || GetViewData().SimpleRowMarked();
+ break;
+
+ case SID_COPY: // copy
+ // not editable because of matrix only? Do not damage matrix
+ //! is not called, when protected AND matrix, we will have
+ //! to live with this... is caught in Copy-Routine, otherwise
+ //! work is to be done once more
+ if ( bEditable || !bOnlyNotBecauseOfMatrix )
+ bNeedEdit = false; // allowed when protected/ReadOnly
+ bDisable = GetObjectShell()->isContentExtractionLocked();
+ break;
+
+ case SID_AUTOFORMAT: // Autoformat, at least 3x3 selected
+ bDisable = (!bSimpleArea)
+ || ((nCol2 - nCol1) < 2) || ((nRow2 - nRow1) < 2);
+ break;
+
+ case SID_CELL_FORMAT_RESET :
+ case FID_CELL_FORMAT :
+ case SID_ENABLE_HYPHENATION :
+ // not editable because of matrix only? Attribute ok nonetheless
+ if ( !bEditable && bOnlyNotBecauseOfMatrix )
+ bNeedEdit = false;
+ break;
+
+ case FID_VALIDATION:
+ {
+ if ( pDocShell && pDocShell->IsDocShared() )
+ {
+ bDisable = true;
+ }
+ }
+ break;
+ case SID_TRANSLITERATE_HALFWIDTH:
+ case SID_TRANSLITERATE_FULLWIDTH:
+ case SID_TRANSLITERATE_HIRAGANA:
+ case SID_TRANSLITERATE_KATAKANA:
+ ScViewUtil::HideDisabledSlot( rSet, GetViewData().GetBindings(), nWhich );
+ break;
+ case SID_CONVERT_FORMULA_TO_VALUE:
+ {
+ // Check and see if the marked range has at least one formula cell.
+ bDisable = !rDoc.HasFormulaCell(aMarkRange);
+ }
+ break;
+ }
+ if (!bDisable && bNeedEdit && !bEditable)
+ bDisable = true;
+
+ if (bDisable)
+ rSet.DisableItem(nWhich);
+ else if (nWhich == SID_ENABLE_HYPHENATION)
+ {
+ // toggle slots need a bool item
+ rSet.Put( SfxBoolItem( nWhich, false ) );
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+// functions, disabled depending on cursor position
+// Default:
+// SID_INSERT_POSTIT, SID_CHARMAP, SID_OPENDLG_FUNCTION
+
+void ScCellShell::GetCellState( SfxItemSet& rSet )
+{
+ ScDocShell* pDocShell = GetViewData().GetDocShell();
+ ScDocument& rDoc = GetViewData().GetDocShell()->GetDocument();
+ ScAddress aCursor( GetViewData().GetCurX(), GetViewData().GetCurY(),
+ GetViewData().GetTabNo() );
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while ( nWhich )
+ {
+ bool bDisable = false;
+ bool bNeedEdit = true; // need cursor position be editable?
+ switch ( nWhich )
+ {
+ case SID_THESAURUS:
+ {
+ CellType eType = rDoc.GetCellType( aCursor );
+ bDisable = ( eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT);
+ if (!bDisable)
+ {
+ // test for available languages
+ LanguageType nLang = ScViewUtil::GetEffLanguage( rDoc, aCursor );
+ bDisable = !ScModule::HasThesaurusLanguage( nLang );
+ }
+ }
+ break;
+ case SID_OPENDLG_FUNCTION:
+ {
+ ScMarkData aMarkData = GetViewData().GetMarkData();
+ aMarkData.MarkToSimple();
+ const ScRange& aRange = aMarkData.GetMarkArea();
+ if(aMarkData.IsMarked())
+ {
+ if (!rDoc.IsBlockEditable( aCursor.Tab(), aRange.aStart.Col(),aRange.aStart.Row(),
+ aRange.aEnd.Col(),aRange.aEnd.Row() ))
+ {
+ bDisable = true;
+ }
+ bNeedEdit=false;
+ }
+
+ }
+ break;
+ case SID_INSERT_POSTIT:
+ {
+ ScAddress aPos( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ if( rDoc.GetNote(aPos) )
+ {
+ bDisable = true;
+ }
+ else
+ {
+ bDisable = false;
+ if ( pDocShell && pDocShell->IsDocShared() )
+ {
+ bDisable = true;
+ }
+ }
+ }
+ break;
+ case SID_EDIT_POSTIT:
+ {
+ ScAddress aPos( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ bDisable = rDoc.GetNote(aPos) == nullptr;
+ }
+ break;
+ }
+ if (!bDisable && bNeedEdit)
+ if (!rDoc.IsBlockEditable( aCursor.Tab(), aCursor.Col(),aCursor.Row(),
+ aCursor.Col(),aCursor.Row() ))
+ bDisable = true;
+ if (bDisable)
+ rSet.DisableItem(nWhich);
+ nWhich = aIter.NextWhich();
+ }
+}
+
+static bool lcl_TestFormat( SvxClipboardFormatItem& rFormats, const TransferableDataHelper& rDataHelper,
+ SotClipboardFormatId nFormatId )
+{
+ if ( rDataHelper.HasFormat( nFormatId ) )
+ {
+ // translated format name strings are no longer inserted here,
+ // handled by "paste special" dialog / toolbox controller instead.
+ // Only the object type name has to be set here:
+ OUString aStrVal;
+ if ( nFormatId == SotClipboardFormatId::EMBED_SOURCE )
+ {
+ TransferableObjectDescriptor aDesc;
+ if ( const_cast<TransferableDataHelper&>(rDataHelper).GetTransferableObjectDescriptor(
+ SotClipboardFormatId::OBJECTDESCRIPTOR, aDesc ) )
+ aStrVal = aDesc.maTypeName;
+ }
+ else if ( nFormatId == SotClipboardFormatId::EMBED_SOURCE_OLE
+ || nFormatId == SotClipboardFormatId::EMBEDDED_OBJ_OLE )
+ {
+ OUString aSource;
+ SvPasteObjectHelper::GetEmbeddedName( rDataHelper, aStrVal, aSource, nFormatId );
+ }
+
+ if ( !aStrVal.isEmpty() )
+ rFormats.AddClipbrdFormat( nFormatId, aStrVal );
+ else
+ rFormats.AddClipbrdFormat( nFormatId );
+
+ return true;
+ }
+
+ return false;
+}
+
+void ScCellShell::GetPossibleClipboardFormats( SvxClipboardFormatItem& rFormats )
+{
+ vcl::Window* pWin = GetViewData().GetActiveWin();
+ bool bDraw = ScDrawTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pWin)) != nullptr;
+
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
+
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::DRAWING );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::SVXB );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::GDIMETAFILE );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::PNG );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::BITMAP );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::EMBED_SOURCE );
+
+ if ( !bDraw )
+ {
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::LINK );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::STRING );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::STRING_TSVC );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::DIF );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::RTF );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::RICHTEXT );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::HTML );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::HTML_SIMPLE );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::BIFF_8 );
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::BIFF_5 );
+ }
+
+ if ( !lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::EMBED_SOURCE_OLE ) )
+ lcl_TestFormat( rFormats, aDataHelper, SotClipboardFormatId::EMBEDDED_OBJ_OLE );
+}
+
+// insert, insert contents
+
+static bool lcl_IsCellPastePossible( const TransferableDataHelper& rData )
+{
+ bool bPossible = false;
+ css::uno::Reference< css::datatransfer::XTransferable2 > xTransferable(rData.GetXTransferable(), css::uno::UNO_QUERY);
+ if ( ScTransferObj::GetOwnClipboard(xTransferable) || ScDrawTransferObj::GetOwnClipboard(xTransferable) )
+ bPossible = true;
+ else
+ {
+ if ( rData.HasFormat( SotClipboardFormatId::PNG ) ||
+ rData.HasFormat( SotClipboardFormatId::BITMAP ) ||
+ rData.HasFormat( SotClipboardFormatId::GDIMETAFILE ) ||
+ rData.HasFormat( SotClipboardFormatId::SVXB ) ||
+ rData.HasFormat( SotClipboardFormatId::PRIVATE ) ||
+ rData.HasFormat( SotClipboardFormatId::RTF ) ||
+ rData.HasFormat( SotClipboardFormatId::RICHTEXT ) ||
+ rData.HasFormat( SotClipboardFormatId::EMBED_SOURCE ) ||
+ rData.HasFormat( SotClipboardFormatId::LINK_SOURCE ) ||
+ rData.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ) ||
+ rData.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ) ||
+ rData.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ) ||
+ rData.HasFormat( SotClipboardFormatId::STRING ) ||
+ rData.HasFormat( SotClipboardFormatId::STRING_TSVC ) ||
+ rData.HasFormat( SotClipboardFormatId::SYLK ) ||
+ rData.HasFormat( SotClipboardFormatId::LINK ) ||
+ rData.HasFormat( SotClipboardFormatId::HTML ) ||
+ rData.HasFormat( SotClipboardFormatId::HTML_SIMPLE ) ||
+ rData.HasFormat( SotClipboardFormatId::DIF ) )
+ {
+ bPossible = true;
+ }
+ }
+ return bPossible;
+}
+
+bool ScCellShell::HasClipboardFormat( SotClipboardFormatId nFormatId )
+{
+ vcl::Window* pWin = GetViewData().GetActiveWin();
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ));
+ return aDataHelper.HasFormat( nFormatId );
+}
+
+IMPL_LINK( ScCellShell, ClipboardChanged, TransferableDataHelper*, pDataHelper, void )
+{
+ bPastePossible = lcl_IsCellPastePossible( *pDataHelper );
+
+ SfxBindings& rBindings = GetViewData().GetBindings();
+ rBindings.Invalidate( SID_PASTE );
+ rBindings.Invalidate( SID_PASTE_SPECIAL );
+ rBindings.Invalidate( SID_PASTE_UNFORMATTED );
+ rBindings.Invalidate( SID_PASTE_ONLY_VALUE );
+ rBindings.Invalidate( SID_PASTE_ONLY_TEXT );
+ rBindings.Invalidate( SID_PASTE_ONLY_FORMULA );
+ rBindings.Invalidate( SID_PASTE_TRANSPOSED );
+ rBindings.Invalidate( SID_PASTE_AS_LINK );
+ rBindings.Invalidate( SID_PASTE_TEXTIMPORT_DIALOG );
+ rBindings.Invalidate( SID_CLIPBOARD_FORMAT_ITEMS );
+}
+
+namespace {
+
+bool checkDestRanges(ScViewData& rViewData)
+{
+ ScRange aDummy;
+ ScMarkType eMarkType = rViewData.GetSimpleArea( aDummy);
+ if (eMarkType != SC_MARK_MULTI)
+ {
+ // Single destination range.
+ if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED)
+ return false;
+ }
+
+ // Multiple destination ranges.
+
+ // Same as ScViewData::SelectionForbidsPaste() in
+ // sc/source/ui/view/viewdata.cxx but different return details.
+
+ vcl::Window* pWin = rViewData.GetActiveWin();
+ if (!pWin)
+ return false;
+
+ const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pWin));
+ if (!pOwnClip)
+ // If it's not a Calc document, we won't be picky.
+ return true;
+
+ ScDocument* pClipDoc = pOwnClip->GetDocument();
+ if (!pClipDoc)
+ return false;
+
+ ScRange aSrcRange = pClipDoc->GetClipParam().getWholeRange();
+ SCROW nRowSize = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
+ SCCOL nColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
+
+ if (rViewData.SelectionForbidsPaste( nColSize, nRowSize))
+ return false;
+
+ ScMarkData aMark = rViewData.GetMarkData();
+ ScRangeList aRanges;
+ aMark.MarkToSimple();
+ aMark.FillRangeListWithMarks(&aRanges, false);
+
+ return ScClipUtil::CheckDestRanges(rViewData.GetDocument(), nColSize, nRowSize, aMark, aRanges);
+}
+
+}
+
+void ScCellShell::GetClipState( SfxItemSet& rSet )
+{
+// SID_PASTE
+// SID_PASTE_SPECIAL
+// SID_PASTE_UNFORMATTED
+// SID_CLIPBOARD_FORMAT_ITEMS
+
+ if ( !pImpl->m_xClipEvtLstnr.is() )
+ {
+ // create listener
+ pImpl->m_xClipEvtLstnr = new TransferableClipboardListener( LINK( this, ScCellShell, ClipboardChanged ) );
+ vcl::Window* pWin = GetViewData().GetActiveWin();
+ pImpl->m_xClipEvtLstnr->AddListener( pWin );
+
+ // get initial state
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
+ bPastePossible = lcl_IsCellPastePossible( aDataHelper );
+ }
+
+ bool bDisable = !bPastePossible;
+
+ // cell protection / multiple selection
+
+ if (!bDisable)
+ {
+ SCCOL nCol = GetViewData().GetCurX();
+ SCROW nRow = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDocument& rDoc = GetViewData().GetDocShell()->GetDocument();
+ if (!rDoc.IsBlockEditable( nTab, nCol,nRow, nCol,nRow ))
+ bDisable = true;
+
+ if (!bDisable && !checkDestRanges(GetViewData()))
+ bDisable = true;
+ }
+
+ if (bDisable)
+ {
+ rSet.DisableItem( SID_PASTE );
+ rSet.DisableItem( SID_PASTE_SPECIAL );
+ rSet.DisableItem( SID_PASTE_UNFORMATTED );
+ rSet.DisableItem( SID_PASTE_ONLY_VALUE );
+ rSet.DisableItem( SID_PASTE_ONLY_TEXT );
+ rSet.DisableItem( SID_PASTE_ONLY_FORMULA );
+ rSet.DisableItem( SID_PASTE_TRANSPOSED );
+ rSet.DisableItem( SID_PASTE_AS_LINK );
+ rSet.DisableItem( SID_PASTE_TEXTIMPORT_DIALOG );
+ rSet.DisableItem( SID_CLIPBOARD_FORMAT_ITEMS );
+ }
+ else if ( rSet.GetItemState( SID_CLIPBOARD_FORMAT_ITEMS ) != SfxItemState::UNKNOWN )
+ {
+ SvxClipboardFormatItem aFormats( SID_CLIPBOARD_FORMAT_ITEMS );
+ GetPossibleClipboardFormats( aFormats );
+ rSet.Put( aFormats );
+ }
+}
+
+// only SID_HYPERLINK_GETLINK:
+
+void ScCellShell::GetHLinkState( SfxItemSet& rSet )
+{
+ // always return an item (or inserting will be disabled)
+ // if the cell at the cursor contains only a link, return that link
+
+ SvxHyperlinkItem aHLinkItem;
+ if ( !GetViewData().GetView()->HasBookmarkAtCursor( &aHLinkItem ) )
+ {
+ // tdf#80043 - put selected text into item
+ ScViewData& rData = GetViewData();
+ ScDocument& rDoc = rData.GetDocument();
+ SCCOL nPosX = rData.GetCurX();
+ SCROW nPosY = rData.GetCurY();
+ SCTAB nTab = rData.GetTabNo();
+ aHLinkItem.SetName(rDoc.GetString(nPosX, nPosY, nTab));
+ }
+
+ rSet.Put(aHLinkItem);
+}
+
+void ScCellShell::GetState(SfxItemSet &rSet)
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScViewData& rData = GetViewData();
+ ScDocument& rDoc = rData.GetDocument();
+ ScMarkData& rMark = rData.GetMarkData();
+ SCCOL nPosX = rData.GetCurX();
+ SCROW nPosY = rData.GetCurY();
+ SCTAB nTab = rData.GetTabNo();
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCTAB nTabSelCount = rMark.GetSelectCount();
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while ( nWhich )
+ {
+ switch ( nWhich )
+ {
+ case SID_DETECTIVE_REFRESH:
+ if (!rDoc.HasDetectiveOperations())
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_RANGE_ADDRESS:
+ {
+ ScRange aRange;
+ if ( rData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
+ {
+ OUString aStr(aRange.Format(rDoc, ScRefFlags::VALID | ScRefFlags::TAB_3D));
+ rSet.Put( SfxStringItem( nWhich, aStr ) );
+ }
+ }
+ break;
+
+ case SID_RANGE_NOTETEXT:
+ {
+ // always take cursor position, do not use top-left cell of selection
+ OUString aNoteText;
+ if ( const ScPostIt* pNote = rDoc.GetNote(nPosX, nPosY, nTab) )
+ aNoteText = pNote->GetText();
+ rSet.Put( SfxStringItem( nWhich, aNoteText ) );
+ }
+ break;
+
+ case SID_RANGE_ROW:
+ rSet.Put( SfxInt32Item( nWhich, nPosY+1 ) );
+ break;
+
+ case SID_RANGE_COL:
+ rSet.Put( SfxInt16Item( nWhich, nPosX+1 ) );
+ break;
+
+ case SID_RANGE_TABLE:
+ rSet.Put( SfxInt16Item( nWhich, nTab+1 ) );
+ break;
+
+ case SID_RANGE_FORMULA:
+ {
+ OUString aString = rDoc.GetFormula( nPosX, nPosY, nTab );
+ if( aString.isEmpty() )
+ {
+ aString = rDoc.GetInputString( nPosX, nPosY, nTab );
+ }
+ rSet.Put( SfxStringItem( nWhich, aString ) );
+ }
+ break;
+
+ case SID_RANGE_TEXTVALUE:
+ {
+ OUString aString = rDoc.GetString(nPosX, nPosY, nTab);
+ rSet.Put( SfxStringItem( nWhich, aString ) );
+ }
+ break;
+
+ case SID_STATUS_SELMODE:
+ {
+ /* 0: STD Click cancels Sel
+ * 1: ER Click extends selection
+ * 2: ERG Click defines further selection
+ */
+ sal_uInt16 nMode = pTabViewShell->GetLockedModifiers();
+
+ switch ( nMode )
+ {
+ case KEY_SHIFT: nMode = 1; break;
+ case KEY_MOD1: nMode = 2; break; // Control-key
+ case 0:
+ default:
+ nMode = 0;
+ }
+
+ rSet.Put( SfxUInt16Item( nWhich, nMode ) );
+ }
+ break;
+
+ case SID_STATUS_DOCPOS:
+ {
+ OUString aStr = ScResId( STR_TABLE_COUNT );
+
+ aStr = aStr.replaceFirst("%1", OUString::number( nTab + 1 ) );
+ aStr = aStr.replaceFirst("%2", OUString::number( nTabCount ) );
+
+ rSet.Put( SfxStringItem( nWhich, aStr ) ); }
+ break;
+
+ case SID_ROWCOL_SELCOUNT:
+ {
+ ScRangeListRef aMarkRanges;
+ GetViewData().GetMultiArea(aMarkRanges);
+ const SCCOL nCol1 = aMarkRanges->front().aStart.Col();
+ const SCROW nRow1 = aMarkRanges->front().aStart.Row();
+ const SCCOL nCol2 = aMarkRanges->front().aEnd.Col();
+ const SCROW nRow2 = aMarkRanges->front().aEnd.Row();
+ const size_t nRanges = aMarkRanges->size();
+
+ if ((nRanges == 1 && (nCol2 != nCol1 || nRow1 != nRow2)) || nRanges > 1)
+ {
+ bool bSameRows = true;
+ bool bSameCols = true;
+ SCROW nRowsSum = 0;
+ SCCOL nColsSum = 0;
+ for (size_t i = 0; i < nRanges; ++i)
+ {
+ const ScRange& rRange = (*aMarkRanges)[i];
+ const SCCOL nRangeCol1 = rRange.aStart.Col();
+ const SCROW nRangeRow1 = rRange.aStart.Row();
+ const SCCOL nRangeCol2 = rRange.aEnd.Col();
+ const SCROW nRangeRow2 = rRange.aEnd.Row();
+ bSameRows &= (nRow1 == nRangeRow1 && nRow2 == nRangeRow2);
+ bSameCols &= (nCol1 == nRangeCol1 && nCol2 == nRangeCol2);
+ // Sum rows if the number of cols is the same or
+ // sum columns if the number of rows is the same,
+ // otherwise do not show any count of selected cells.
+ if (bSameRows || bSameCols)
+ {
+ const auto nCols = nRangeCol2 - nRangeCol1 + 1;
+ const auto nRows = (bSameCols || nRowsSum == 0) ?
+ rDoc.CountNonFilteredRows( nRangeRow1, nRangeRow2, rRange.aStart.Tab()) :
+ nRowsSum;
+ if (bSameRows)
+ {
+ nRowsSum = nRows;
+ nColsSum += nCols;
+ }
+ else if (bSameCols)
+ {
+ nRowsSum += nRows;
+ nColsSum = nCols;
+ }
+ }
+ else
+ break;
+ }
+ // Either the rows or columns are the same among selections
+ if (bSameRows || bSameCols)
+ {
+ const LocaleDataWrapper& rLocaleData
+ = Application::GetSettings().GetUILocaleDataWrapper();
+ OUString aRowArg
+ = ScResId(STR_SELCOUNT_ROWARG, nRowsSum)
+ .replaceAll("$1", rLocaleData.getNum(nRowsSum, 0));
+ OUString aColArg
+ = ScResId(STR_SELCOUNT_COLARG, nColsSum)
+ .replaceAll("$1", rLocaleData.getNum(nColsSum, 0));
+ OUString aStr = ScResId(STR_SELCOUNT);
+ aStr = aStr.replaceAll("$1", aRowArg);
+ aStr = aStr.replaceAll("$2", aColArg);
+ rSet.Put(SfxStringItem(nWhich, aStr));
+ }
+ }
+ else
+ {
+ SCSIZE nSelected, nTotal;
+ rDoc.GetFilterSelCount( nPosX, nPosY, nTab, nSelected, nTotal );
+ if( nTotal && nSelected != SCSIZE_MAX )
+ {
+ OUString aStr = ScResId( STR_FILTER_SELCOUNT );
+ aStr = aStr.replaceAll( "$1", OUString::number( nSelected ) );
+ aStr = aStr.replaceAll( "$2", OUString::number( nTotal ) );
+ rSet.Put( SfxStringItem( nWhich, aStr ) );
+ }
+ }
+ }
+ break;
+
+ // calculations etc. with date/time/Fail/position&size together
+
+ // #i34458# The SfxStringItem belongs only into SID_TABLE_CELL. It no longer has to be
+ // duplicated in SID_ATTR_POSITION or SID_ATTR_SIZE for SvxPosSizeStatusBarControl.
+ case SID_TABLE_CELL:
+ {
+ // Test, if error under cursor
+ // (not rDoc.GetErrCode, to avoid erasing circular references)
+
+ // In interpreter may happen via rescheduled Basic
+ if ( rDoc.IsInInterpreter() )
+ rSet.Put( SfxStringItem( nWhich, "..." ) );
+ else
+ {
+ FormulaError nErrCode = FormulaError::NONE;
+ ScFormulaCell* pCell = rDoc.GetFormulaCell(ScAddress(nPosX, nPosY, nTab));
+ if (pCell && !pCell->IsRunning())
+ nErrCode = pCell->GetErrCode();
+
+ OUString aFuncStr;
+ if ( pTabViewShell->GetFunction( aFuncStr, nErrCode ) )
+ rSet.Put( SfxStringItem( nWhich, aFuncStr ) );
+ }
+ }
+ break;
+
+ case SID_DATA_SELECT:
+ // HasSelectionData includes column content and validity,
+ // page fields have to be checked separately.
+ if ( !rDoc.HasSelectionData( nPosX, nPosY, nTab ) &&
+ !pTabViewShell->HasPageFieldDataAtCursor() )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_CURRENTVALIDATION:
+ if ( !rDoc.HasValidationData( nPosX, nPosY, nTab ))
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_STATUS_SUM:
+ {
+ OUString aFuncStr;
+ if ( pTabViewShell->GetFunction( aFuncStr, FormulaError::NONE ) )
+ rSet.Put( SfxStringItem( nWhich, aFuncStr ) );
+ }
+ break;
+
+ case FID_MERGE_ON:
+ if ( rDoc.GetChangeTrack() || !pTabViewShell->TestMergeCells() )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_MERGE_OFF:
+ if ( rDoc.GetChangeTrack() || !pTabViewShell->TestRemoveMerge() )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_MERGE_TOGGLE:
+ if ( rDoc.GetChangeTrack() )
+ rSet.DisableItem( nWhich );
+ else
+ {
+ bool bCanMerge = pTabViewShell->TestMergeCells();
+ bool bCanSplit = pTabViewShell->TestRemoveMerge();
+ if( !bCanMerge && !bCanSplit )
+ rSet.DisableItem( nWhich );
+ else
+ rSet.Put( SfxBoolItem( nWhich, bCanSplit ) );
+ }
+ break;
+
+ case FID_INS_ROWBRK:
+ if ( nPosY==0 || (rDoc.HasRowBreak(nPosY, nTab) & ScBreakType::Manual) || rDoc.IsTabProtected(nTab) )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_INS_COLBRK:
+ if ( nPosX==0 || (rDoc.HasColBreak(nPosX, nTab) & ScBreakType::Manual) || rDoc.IsTabProtected(nTab) )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_DEL_ROWBRK:
+ if ( nPosY==0 || !(rDoc.HasRowBreak(nPosY, nTab) & ScBreakType::Manual) || rDoc.IsTabProtected(nTab) )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_DEL_COLBRK:
+ if ( nPosX==0 || !(rDoc.HasColBreak(nPosX, nTab) & ScBreakType::Manual) || rDoc.IsTabProtected(nTab) )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_FILL_TAB:
+ if ( nTabSelCount < 2 )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_INSERT_CURRENT_DATE:
+ case SID_INSERT_CURRENT_TIME:
+ {
+ if ( rDoc.IsTabProtected(nTab) &&
+ rDoc.HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HasAttrFlags::Protected))
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_SELECT_SCENARIO:
+ {
+ std::vector<OUString> aList;
+ Color aDummyCol;
+
+ if ( !rDoc.IsScenario(nTab) )
+ {
+ OUString aStr;
+ ScScenarioFlags nFlags;
+ SCTAB nScTab = nTab + 1;
+ bool bSheetProtected = rDoc.IsTabProtected(nTab);
+
+ while ( rDoc.IsScenario(nScTab) )
+ {
+ rDoc.GetName( nScTab, aStr );
+ aList.push_back(aStr);
+ rDoc.GetScenarioData( nScTab, aStr, aDummyCol, nFlags );
+ aList.push_back(aStr);
+ // Protection is sal_True if both Sheet and Scenario are protected
+ aList.push_back((bSheetProtected && (nFlags & ScScenarioFlags::Protected)) ? OUString("1") : OUString("0"));
+ ++nScTab;
+ }
+ }
+ else
+ {
+ OUString aComment;
+ ScScenarioFlags nDummyFlags;
+ rDoc.GetScenarioData( nTab, aComment, aDummyCol, nDummyFlags );
+ OSL_ENSURE( aList.empty(), "List not empty!" );
+ aList.push_back(aComment);
+ }
+
+ rSet.Put( SfxStringListItem( nWhich, &aList ) );
+ }
+ break;
+
+ case FID_ROW_HIDE:
+ case FID_ROW_SHOW:
+ case FID_COL_HIDE:
+ case FID_COL_SHOW:
+ case FID_COL_OPT_WIDTH:
+ case FID_ROW_OPT_HEIGHT:
+ case FID_DELETE_CELL:
+ if ( rDoc.IsTabProtected(nTab) || pDocSh->IsReadOnly())
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_OUTLINE_MAKE:
+ {
+ if ( GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() ) )
+ {
+ //! test for data pilot operation
+ }
+ else if (rDoc.GetChangeTrack()!=nullptr || GetViewData().IsMultiMarked())
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+ case SID_OUTLINE_SHOW:
+ if ( GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() ) )
+ {
+ //! test for data pilot operation
+ }
+ else if (!pTabViewShell->OutlinePossible(false))
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_OUTLINE_HIDE:
+ if ( GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() ) )
+ {
+ //! test for data pilot operation
+ }
+ else if (!pTabViewShell->OutlinePossible(true))
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_OUTLINE_REMOVE:
+ {
+ if ( GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() ) )
+ {
+ //! test for data pilot operation
+ }
+ else
+ {
+ bool bCol, bRow;
+ pTabViewShell->TestRemoveOutline( bCol, bRow );
+ if ( !bCol && !bRow )
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case FID_COL_WIDTH:
+ {
+ SfxUInt16Item aWidthItem( FID_COL_WIDTH, rDoc.GetColWidth( nPosX , nTab) );
+ rSet.Put( aWidthItem );
+ if ( pDocSh->IsReadOnly())
+ rSet.DisableItem( nWhich );
+
+ //XXX disable if not conclusive
+ }
+ break;
+
+ case FID_ROW_HEIGHT:
+ {
+ SfxUInt16Item aHeightItem( FID_ROW_HEIGHT, rDoc.GetRowHeight( nPosY , nTab) );
+ rSet.Put( aHeightItem );
+ //XXX disable if not conclusive
+ if ( pDocSh->IsReadOnly())
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_DETECTIVE_FILLMODE:
+ rSet.Put(SfxBoolItem( nWhich, pTabViewShell->IsAuditShell() ));
+ break;
+
+ case FID_INPUTLINE_STATUS:
+ OSL_FAIL( "Old update method. Use ScTabViewShell::UpdateInputHandler()." );
+ break;
+
+ case SID_SCENARIOS: // scenarios:
+ if (!(rMark.IsMarked() || rMark.IsMultiMarked())) // only, if something selected
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_NOTE_VISIBLE:
+ {
+ const ScPostIt* pNote = rDoc.GetNote(nPosX, nPosY, nTab);
+ if ( pNote && rDoc.IsBlockEditable( nTab, nPosX,nPosY, nPosX,nPosY ) )
+ rSet.Put( SfxBoolItem( nWhich, pNote->IsCaptionShown() ) );
+ else
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case FID_HIDE_NOTE:
+ case FID_SHOW_NOTE:
+ {
+ bool bEnable = false;
+ bool bSearchForHidden = nWhich == FID_SHOW_NOTE;
+ if (!rMark.IsMarked() && !rMark.IsMultiMarked())
+ {
+ // Check current cell
+ const ScPostIt* pNote = rDoc.GetNote(nPosX, nPosY, nTab);
+ if ( pNote && rDoc.IsBlockEditable( nTab, nPosX,nPosY, nPosX,nPosY ) )
+ if ( pNote->IsCaptionShown() != bSearchForHidden)
+ bEnable = true;
+ }
+ else
+ {
+ // Check selection range
+ ScRangeListRef aRangesRef;
+ rData.GetMultiArea(aRangesRef);
+ ScRangeList aRanges = *aRangesRef;
+ std::vector<sc::NoteEntry> aNotes;
+ rDoc.GetNotesInRange(aRanges, aNotes);
+ for(const auto& rNote : aNotes)
+ {
+ const ScAddress& rAdr = rNote.maPos;
+ if( rDoc.IsBlockEditable( rAdr.Tab(), rAdr.Col(), rAdr.Row(), rAdr.Col(), rAdr.Row() ))
+ {
+ if (rNote.mpNote->IsCaptionShown() != bSearchForHidden)
+ {
+ bEnable = true;
+ break;
+ }
+ }
+ }
+
+ }
+ if ( !bEnable )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case FID_SHOW_ALL_NOTES:
+ case FID_HIDE_ALL_NOTES:
+ case FID_DELETE_ALL_NOTES:
+ {
+ bool bHasNotes = false;
+
+ for (auto const& rTab : rMark.GetSelectedTabs())
+ {
+ if (rDoc.HasTabNotes( rTab ))
+ {
+ bHasNotes = true;
+ break;
+ }
+ }
+
+ if ( !bHasNotes )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_TOGGLE_NOTES:
+ {
+ bool bHasNotes = false;
+ ScRangeList aRanges;
+
+ for (auto const& rTab : rMark.GetSelectedTabs())
+ {
+ if (rDoc.HasTabNotes( rTab ))
+ {
+ bHasNotes = true;
+ aRanges.push_back(ScRange(0,0,rTab,rDoc.MaxCol(),rDoc.MaxRow(),rTab));
+ }
+ }
+
+ if ( !bHasNotes )
+ rSet.DisableItem( nWhich );
+ else
+ {
+ CommentCaptionState eState = rDoc.GetAllNoteCaptionsState( aRanges );
+ bool bAllNotesInShown = (eState != ALLHIDDEN && eState != MIXED);
+ rSet.Put( SfxBoolItem( SID_TOGGLE_NOTES, bAllNotesInShown) );
+ }
+ }
+ break;
+
+ case SID_DELETE_NOTE:
+ {
+ bool bEnable = false;
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ {
+ if ( rDoc.IsSelectionEditable( rMark ) )
+ {
+ // look for at least one note in selection
+ ScRangeList aRanges;
+ rMark.FillRangeListWithMarks( &aRanges, false );
+ bEnable = rDoc.ContainsNotesInRange( aRanges );
+ }
+ }
+ else
+ {
+ bEnable = rDoc.IsBlockEditable( nTab, nPosX,nPosY, nPosX,nPosY ) &&
+ rDoc.GetNote(nPosX, nPosY, nTab);
+ }
+ if ( !bEnable )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_OPENDLG_CONSOLIDATE:
+ case SCITEM_CONSOLIDATEDATA:
+ {
+ if (rDoc.GetChangeTrack()!=nullptr)
+ rSet.DisableItem( nWhich);
+ }
+ break;
+
+ case SID_CHINESE_CONVERSION:
+ case SID_HANGUL_HANJA_CONVERSION:
+ ScViewUtil::HideDisabledSlot( rSet, rData.GetBindings(), nWhich );
+ break;
+
+ case FID_USE_NAME:
+ {
+ if ( pDocSh && pDocSh->IsDocShared() )
+ rSet.DisableItem( nWhich );
+ else
+ {
+ ScRange aRange;
+ if ( rData.GetSimpleArea( aRange ) != SC_MARK_SIMPLE )
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case FID_DEFINE_NAME:
+ case FID_INSERT_NAME:
+ case FID_ADD_NAME:
+ case SID_DEFINE_COLROWNAMERANGES:
+ {
+ if ( pDocSh && pDocSh->IsDocShared() )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case FID_DEFINE_CURRENT_NAME:
+ {
+ ScAddress aCurrentAddress( nPosX, nPosY, nTab );
+
+ if ( !rDoc.IsAddressInRangeName( RangeNameScope::GLOBAL, aCurrentAddress ) &&
+ !rDoc.IsAddressInRangeName( RangeNameScope::SHEET, aCurrentAddress ))
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case SID_SPELL_DIALOG:
+ {
+ if (rDoc.IsTabProtected(rData.GetTabNo()))
+ {
+ bool bVisible = false;
+ SfxViewFrame* pViewFrame = ( pTabViewShell ? pTabViewShell->GetViewFrame() : nullptr );
+ if ( pViewFrame && pViewFrame->HasChildWindow( nWhich ) )
+ {
+ SfxChildWindow* pChild = pViewFrame->GetChildWindow( nWhich );
+ std::shared_ptr<SfxDialogController> xController = pChild ? pChild->GetController() : nullptr;
+ if (xController && xController->getDialog()->get_visible())
+ {
+ bVisible = true;
+ }
+ }
+ if ( !bVisible )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ }
+ break;
+
+ case SID_OPENDLG_CURRENTCONDFRMT:
+ case SID_OPENDLG_CURRENTCONDFRMT_MANAGER:
+ {
+ const SfxPoolItem* pItem = rDoc.GetAttr( nPosX, nPosY, nTab, ATTR_CONDITIONAL );
+ const ScCondFormatItem* pCondFormatItem = static_cast<const ScCondFormatItem*>(pItem);
+
+ if ( pCondFormatItem->GetCondFormatData().empty() )
+ rSet.DisableItem( nWhich );
+ else if ( pCondFormatItem->GetCondFormatData().size() == 1 )
+ rSet.DisableItem( SID_OPENDLG_CURRENTCONDFRMT_MANAGER );
+ else if ( pCondFormatItem->GetCondFormatData().size() > 1 )
+ rSet.DisableItem( SID_OPENDLG_CURRENTCONDFRMT );
+ }
+ break;
+
+ } // switch ( nWitch )
+ nWhich = aIter.NextWhich();
+ } // while ( nWitch )
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/cellsh1.cxx b/sc/source/ui/view/cellsh1.cxx
new file mode 100644
index 000000000..a48c7ece8
--- /dev/null
+++ b/sc/source/ui/view/cellsh1.cxx
@@ -0,0 +1,3454 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/i18n/TextConversionOption.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+
+#include <scitems.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <basic/sberrors.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <svl/stritem.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/request.hxx>
+#include <vcl/commandinfoprovider.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svx/svxdlg.hxx>
+#include <sot/formats.hxx>
+#include <svx/postattr.hxx>
+#include <editeng/fontitem.hxx>
+#include <svx/clipfmtitem.hxx>
+#include <svx/hlnkitem.hxx>
+#include <basic/sbxcore.hxx>
+#include <editeng/editview.hxx>
+#include <svtools/cliplistener.hxx>
+
+#include <cellsh.hxx>
+#include <ftools.hxx>
+#include <sc.hrc>
+#include <document.hxx>
+#include <patattr.hxx>
+#include <scmod.hxx>
+#include <tabvwsh.hxx>
+#include <uiitems.hxx>
+#include <reffact.hxx>
+#include <inputhdl.hxx>
+#include <transobj.hxx>
+#include <drwtrans.hxx>
+#include <docfunc.hxx>
+#include <editable.hxx>
+#include <dpobject.hxx>
+#include <dpsave.hxx>
+#include <spellparam.hxx>
+#include <postit.hxx>
+#include <dpsdbtab.hxx>
+#include <dpshttab.hxx>
+#include <dbdata.hxx>
+#include <docsh.hxx>
+#include <cliputil.hxx>
+#include <markdata.hxx>
+#include <colorscale.hxx>
+#include <condformatdlg.hxx>
+#include <attrib.hxx>
+#include <condformatdlgitem.hxx>
+#include <impex.hxx>
+
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <scui_def.hxx>
+#include <scabstdlg.hxx>
+#include <tokenstringcontext.hxx>
+#include <cellvalue.hxx>
+#include <tokenarray.hxx>
+#include <formulacell.hxx>
+#include <gridwin.hxx>
+#include <searchresults.hxx>
+#include <Sparkline.hxx>
+
+#include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/bootstrap.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+
+namespace{
+InsertDeleteFlags FlagsFromString(const OUString& rFlagsStr,
+ InsertDeleteFlags nFlagsMask = InsertDeleteFlags::CONTENTS | InsertDeleteFlags::ATTRIB)
+{
+ OUString aFlagsStr = rFlagsStr.toAsciiUpperCase();
+ InsertDeleteFlags nFlags = InsertDeleteFlags::NONE;
+
+ for (sal_Int32 i=0 ; i < aFlagsStr.getLength(); ++i)
+ {
+ switch (aFlagsStr[i])
+ {
+ case 'A': return InsertDeleteFlags::ALL;
+ case 'S': nFlags |= InsertDeleteFlags::STRING & nFlagsMask; break;
+ case 'V': nFlags |= InsertDeleteFlags::VALUE & nFlagsMask; break;
+ case 'D': nFlags |= InsertDeleteFlags::DATETIME & nFlagsMask; break;
+ case 'F': nFlags |= InsertDeleteFlags::FORMULA & nFlagsMask; break;
+ case 'N': nFlags |= InsertDeleteFlags::NOTE & nFlagsMask; break;
+ case 'T': nFlags |= InsertDeleteFlags::ATTRIB & nFlagsMask; break;
+ case 'O': nFlags |= InsertDeleteFlags::OBJECTS & nFlagsMask; break;
+ }
+ }
+ return nFlags;
+}
+
+OUString FlagsToString( InsertDeleteFlags nFlags,
+ InsertDeleteFlags nFlagsMask = InsertDeleteFlags::CONTENTS | InsertDeleteFlags::ATTRIB )
+{
+ OUString aFlagsStr;
+
+ if( nFlags == InsertDeleteFlags::ALL )
+ {
+ aFlagsStr = "A";
+ }
+ else
+ {
+ nFlags &= nFlagsMask;
+
+ if( nFlags & InsertDeleteFlags::STRING ) aFlagsStr += "S";
+ if( nFlags & InsertDeleteFlags::VALUE ) aFlagsStr += "V";
+ if( nFlags & InsertDeleteFlags::DATETIME ) aFlagsStr += "D";
+ if( nFlags & InsertDeleteFlags::FORMULA ) aFlagsStr += "F";
+ if( nFlags & InsertDeleteFlags::NOTE ) aFlagsStr += "N";
+ if( nFlags & InsertDeleteFlags::ATTRIB ) aFlagsStr += "T";
+ if( nFlags & InsertDeleteFlags::OBJECTS ) aFlagsStr += "O";
+ }
+ return aFlagsStr;
+}
+
+void SetTabNoAndCursor( const ScViewData& rViewData, std::u16string_view rCellId )
+{
+ ScTabViewShell* pTabViewShell = rViewData.GetViewShell();
+ assert(pTabViewShell);
+ const ScDocument& rDoc = rViewData.GetDocShell()->GetDocument();
+ std::vector<sc::NoteEntry> aNotes;
+ rDoc.GetAllNoteEntries(aNotes);
+
+ sal_uInt32 nId = o3tl::toUInt32(rCellId);
+ auto lComp = [nId](const sc::NoteEntry& rNote) { return rNote.mpNote->GetId() == nId; };
+
+ const auto& aFoundNoteIt = std::find_if(aNotes.begin(), aNotes.end(), lComp);
+ if (aFoundNoteIt != aNotes.end())
+ {
+ ScAddress aFoundPos = aFoundNoteIt->maPos;
+ pTabViewShell->SetTabNo(aFoundPos.Tab());
+ pTabViewShell->SetCursor(aFoundPos.Col(), aFoundPos.Row());
+ }
+}
+}
+
+void ScCellShell::ExecuteEdit( SfxRequest& rReq )
+{
+ ScModule* pScMod = SC_MOD();
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ SfxBindings& rBindings = pTabViewShell->GetViewFrame()->GetBindings();
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ pTabViewShell->HideListBox(); // Autofilter-DropDown-Listbox
+
+ // finish input
+ if ( GetViewData().HasEditView( GetViewData().GetActivePart() ) )
+ {
+ switch ( nSlot )
+ {
+ case FID_DEFINE_NAME:
+ case FID_ADD_NAME:
+ case FID_USE_NAME:
+ case FID_INSERT_NAME:
+ case SID_SPELL_DIALOG:
+ case SID_HANGUL_HANJA_CONVERSION:
+ case SID_OPENDLG_CONDFRMT:
+ case SID_OPENDLG_CURRENTCONDFRMT:
+ case SID_OPENDLG_COLORSCALE:
+ case SID_OPENDLG_DATABAR:
+ pScMod->InputEnterHandler();
+ pTabViewShell->UpdateInputHandler();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ switch ( nSlot )
+ {
+
+ // insert / delete cells / rows / columns
+
+ case FID_INS_ROW:
+ case FID_INS_ROWS_BEFORE:
+ pTabViewShell->InsertCells(INS_INSROWS_BEFORE);
+ rReq.Done();
+ break;
+
+ case FID_INS_COLUMN:
+ case FID_INS_COLUMNS_BEFORE:
+ pTabViewShell->InsertCells(INS_INSCOLS_BEFORE);
+ rReq.Done();
+ break;
+
+ case FID_INS_ROWS_AFTER:
+ pTabViewShell->InsertCells(INS_INSROWS_AFTER);
+ rReq.Done();
+ break;
+
+ case FID_INS_COLUMNS_AFTER:
+ pTabViewShell->InsertCells(INS_INSCOLS_AFTER);
+ rReq.Done();
+ break;
+
+ case FID_INS_CELLSDOWN:
+ pTabViewShell->InsertCells(INS_CELLSDOWN);
+ rReq.Done();
+ break;
+
+ case FID_INS_CELLSRIGHT:
+ pTabViewShell->InsertCells(INS_CELLSRIGHT);
+ rReq.Done();
+ break;
+
+ case SID_DEL_ROWS:
+ pTabViewShell->DeleteCells( DelCellCmd::Rows );
+ rReq.Done();
+ break;
+
+ case SID_DEL_COLS:
+ pTabViewShell->DeleteCells( DelCellCmd::Cols );
+ rReq.Done();
+ break;
+
+ case FID_INS_CELL:
+ {
+ InsCellCmd eCmd=INS_NONE;
+
+ if ( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ OUString aFlags;
+
+ if( pReqArgs->HasItem( FID_INS_CELL, &pItem ) )
+ aFlags = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ if( !aFlags.isEmpty() )
+ {
+ switch( aFlags[0] )
+ {
+ case 'V': eCmd = INS_CELLSDOWN ;break;
+ case '>': eCmd = INS_CELLSRIGHT ;break;
+ case 'R': eCmd = INS_INSROWS_BEFORE ;break;
+ case 'C': eCmd = INS_INSCOLS_BEFORE ;break;
+ }
+ }
+ }
+ else
+ {
+ if ( GetViewData().SimpleColMarked() )
+ eCmd = INS_INSCOLS_BEFORE;
+ else if ( GetViewData().SimpleRowMarked() )
+ eCmd = INS_INSROWS_BEFORE;
+ else
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ bool bTheFlag=(rDoc.GetChangeTrack()!=nullptr);
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScInsertCellDlg> pDlg(pFact->CreateScInsertCellDlg(pTabViewShell->GetFrameWeld(), bTheFlag));
+ if (pDlg->Execute() == RET_OK)
+ eCmd = pDlg->GetInsCellCmd();
+ }
+ }
+
+ if (eCmd!=INS_NONE)
+ {
+ pTabViewShell->InsertCells( eCmd );
+
+ if( ! rReq.IsAPI() )
+ {
+ OUString aParam;
+
+ switch( eCmd )
+ {
+ case INS_CELLSDOWN: aParam = "V"; break;
+ case INS_CELLSRIGHT: aParam = ">"; break;
+ case INS_INSROWS_BEFORE: aParam = "R"; break;
+ case INS_INSCOLS_BEFORE: aParam = "C"; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ rReq.AppendItem( SfxStringItem( FID_INS_CELL, aParam ) );
+ rReq.Done();
+ }
+ }
+ }
+ break;
+
+ case FID_DELETE_CELL:
+ {
+ DelCellCmd eCmd = DelCellCmd::NONE;
+
+ if ( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ OUString aFlags;
+
+ if( pReqArgs->HasItem( FID_DELETE_CELL, &pItem ) )
+ aFlags = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ if( !aFlags.isEmpty() )
+ {
+ switch( aFlags[0] )
+ {
+ case 'U': eCmd = DelCellCmd::CellsUp ;break;
+ case 'L': eCmd = DelCellCmd::CellsLeft ;break;
+ case 'R': eCmd = DelCellCmd::Rows ;break;
+ case 'C': eCmd = DelCellCmd::Cols ;break;
+ }
+ }
+ }
+ else
+ {
+ if ( GetViewData().SimpleColMarked() )
+ eCmd = DelCellCmd::Cols;
+ else if ( GetViewData().SimpleRowMarked() )
+ eCmd = DelCellCmd::Rows;
+ else
+ {
+ ScRange aRange;
+ ScDocument& rDoc = GetViewData().GetDocument();
+ bool bTheFlag=GetViewData().IsMultiMarked() ||
+ (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE_FILTERED) ||
+ (rDoc.GetChangeTrack() != nullptr);
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScDeleteCellDlg> pDlg(pFact->CreateScDeleteCellDlg( pTabViewShell->GetFrameWeld(), bTheFlag ));
+
+ if (pDlg->Execute() == RET_OK)
+ eCmd = pDlg->GetDelCellCmd();
+ }
+ }
+
+ if (eCmd != DelCellCmd::NONE )
+ {
+ pTabViewShell->DeleteCells( eCmd );
+
+ if( ! rReq.IsAPI() )
+ {
+ OUString aParam;
+
+ switch( eCmd )
+ {
+ case DelCellCmd::CellsUp: aParam = "U"; break;
+ case DelCellCmd::CellsLeft: aParam = "L"; break;
+ case DelCellCmd::Rows: aParam = "R"; break;
+ case DelCellCmd::Cols: aParam = "C"; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ rReq.AppendItem( SfxStringItem( FID_DELETE_CELL, aParam ) );
+ rReq.Done();
+ }
+ }
+ }
+ break;
+
+ // delete contents from cells
+
+ case SID_DELETE_CONTENTS:
+ pTabViewShell->DeleteContents( InsertDeleteFlags::CONTENTS );
+ rReq.Done();
+ break;
+
+ case SID_DELETE:
+ {
+ InsertDeleteFlags nFlags = InsertDeleteFlags::NONE;
+
+ if ( pReqArgs!=nullptr && pTabViewShell->SelectionEditable() )
+ {
+ const SfxPoolItem* pItem;
+ OUString aFlags('A');
+
+ if( pReqArgs->HasItem( SID_DELETE, &pItem ) )
+ aFlags = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ nFlags |= FlagsFromString(aFlags, InsertDeleteFlags::ALL);
+ }
+ else
+ {
+ ScEditableTester aTester( pTabViewShell );
+ if (aTester.IsEditable())
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScDeleteContentsDlg> pDlg(pFact->CreateScDeleteContentsDlg(pTabViewShell->GetFrameWeld()));
+ ScDocument& rDoc = GetViewData().GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ if ( rDoc.IsTabProtected(nTab) )
+ pDlg->DisableObjects();
+ if (pDlg->Execute() == RET_OK)
+ {
+ nFlags = pDlg->GetDelContentsCmdBits();
+ }
+ }
+ else
+ pTabViewShell->ErrorMessage(aTester.GetMessageId());
+ }
+
+ if( nFlags != InsertDeleteFlags::NONE )
+ {
+ pTabViewShell->DeleteContents( nFlags );
+
+ if( ! rReq.IsAPI() )
+ {
+ OUString aFlags = FlagsToString( nFlags, InsertDeleteFlags::ALL );
+
+ rReq.AppendItem( SfxStringItem( SID_DELETE, aFlags ) );
+ rReq.Done();
+ }
+ }
+ }
+ break;
+
+ // fill...
+
+ case FID_FILL_TO_BOTTOM:
+ pTabViewShell->FillSimple( FILL_TO_BOTTOM );
+ rReq.Done();
+ break;
+
+ case FID_FILL_TO_RIGHT:
+ pTabViewShell->FillSimple( FILL_TO_RIGHT );
+ rReq.Done();
+ break;
+
+ case FID_FILL_TO_TOP:
+ pTabViewShell->FillSimple( FILL_TO_TOP );
+ rReq.Done();
+ break;
+
+ case FID_FILL_TO_LEFT:
+ pTabViewShell->FillSimple( FILL_TO_LEFT );
+ rReq.Done();
+ break;
+
+ case FID_FILL_TAB:
+ {
+ InsertDeleteFlags nFlags = InsertDeleteFlags::NONE;
+ ScPasteFunc nFunction = ScPasteFunc::NONE;
+ bool bSkipEmpty = false;
+ bool bAsLink = false;
+
+ if ( pReqArgs!=nullptr && pTabViewShell->SelectionEditable() )
+ {
+ const SfxPoolItem* pItem;
+ OUString aFlags('A');
+
+ if( pReqArgs->HasItem( FID_FILL_TAB, &pItem ) )
+ aFlags = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ nFlags |= FlagsFromString(aFlags);
+ }
+ else
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScInsertContentsDlg> pDlg(pFact->CreateScInsertContentsDlg(pTabViewShell->GetFrameWeld(),
+ new OUString(ScResId(STR_FILL_TAB))));
+ pDlg->SetFillMode(true);
+
+ if (pDlg->Execute() == RET_OK)
+ {
+ nFlags = pDlg->GetInsContentsCmdBits();
+ nFunction = pDlg->GetFormulaCmdBits();
+ bSkipEmpty = pDlg->IsSkipEmptyCells();
+ bAsLink = pDlg->IsLink();
+ // there is no MoveMode with fill tabs
+ }
+ }
+
+ if( nFlags != InsertDeleteFlags::NONE )
+ {
+ pTabViewShell->FillTab( nFlags, nFunction, bSkipEmpty, bAsLink );
+
+ if( ! rReq.IsAPI() )
+ {
+ OUString aFlags = FlagsToString( nFlags );
+
+ rReq.AppendItem( SfxStringItem( FID_FILL_TAB, aFlags ) );
+ rReq.Done();
+ }
+ }
+ }
+ break;
+
+ case FID_FILL_SERIES:
+ {
+ if (GetViewData().SelectionForbidsCellFill())
+ // Slot should be already disabled, but in case it wasn't
+ // don't even attempt to do the evaluation and popup a
+ // dialog.
+ break;
+
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCTAB nStartTab;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ SCTAB nEndTab;
+ sal_uInt16 nPossDir = FDS_OPT_NONE;
+ FillDir eFillDir = FILL_TO_BOTTOM;
+ FillCmd eFillCmd = FILL_LINEAR;
+ FillDateCmd eFillDateCmd = FILL_DAY;
+ double fStartVal = MAXDOUBLE;
+ double fIncVal = 1;
+ double fMaxVal = MAXDOUBLE;
+ bool bDoIt = false;
+
+ GetViewData().GetSimpleArea( nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab );
+
+ if( nStartCol!=nEndCol )
+ {
+ nPossDir |= FDS_OPT_HORZ;
+ eFillDir=FILL_TO_RIGHT;
+ }
+
+ if( nStartRow!=nEndRow )
+ {
+ nPossDir |= FDS_OPT_VERT;
+ eFillDir=FILL_TO_BOTTOM;
+ }
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+
+ if( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ OUString aFillDir, aFillCmd, aFillDateCmd;
+ OUString aFillStep, aFillStart, aFillMax;
+ sal_uInt32 nKey;
+ double fTmpVal;
+
+ if( pReqArgs->HasItem( FID_FILL_SERIES, &pItem ) )
+ aFillDir = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ if( pReqArgs->HasItem( FN_PARAM_1, &pItem ) )
+ aFillCmd = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ if( pReqArgs->HasItem( FN_PARAM_2, &pItem ) )
+ aFillDateCmd = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ if( pReqArgs->HasItem( FN_PARAM_3, &pItem ) )
+ aFillStep = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ if( pReqArgs->HasItem( FN_PARAM_4, &pItem ) )
+ aFillStart = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ if( pReqArgs->HasItem( FN_PARAM_5, &pItem ) )
+ aFillMax = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ if( !aFillDir.isEmpty() )
+ switch( aFillDir[0] )
+ {
+ case 'B': case 'b': eFillDir=FILL_TO_BOTTOM; break;
+ case 'R': case 'r': eFillDir=FILL_TO_RIGHT; break;
+ case 'T': case 't': eFillDir=FILL_TO_TOP; break;
+ case 'L': case 'l': eFillDir=FILL_TO_LEFT; break;
+ }
+
+ if( !aFillCmd.isEmpty() )
+ switch( aFillCmd[0] )
+ {
+ case 'S': case 's': eFillCmd=FILL_SIMPLE; break;
+ case 'L': case 'l': eFillCmd=FILL_LINEAR; break;
+ case 'G': case 'g': eFillCmd=FILL_GROWTH; break;
+ case 'D': case 'd': eFillCmd=FILL_DATE; break;
+ case 'A': case 'a': eFillCmd=FILL_AUTO; break;
+ }
+
+ if( !aFillDateCmd.isEmpty() )
+ switch( aFillDateCmd[0] )
+ {
+ case 'D': case 'd': eFillDateCmd=FILL_DAY; break;
+ case 'W': case 'w': eFillDateCmd=FILL_WEEKDAY; break;
+ case 'M': case 'm': eFillDateCmd=FILL_MONTH; break;
+ case 'Y': case 'y': eFillDateCmd=FILL_YEAR; break;
+ }
+
+ nKey = 0;
+ if( pFormatter->IsNumberFormat( aFillStart, nKey, fTmpVal ))
+ fStartVal = fTmpVal;
+
+ nKey = 0;
+ if( pFormatter->IsNumberFormat( aFillStep, nKey, fTmpVal ))
+ fIncVal = fTmpVal;
+
+ nKey = 0;
+ if( pFormatter->IsNumberFormat( aFillMax, nKey, fTmpVal ))
+ fMaxVal = fTmpVal;
+
+ bDoIt = true;
+
+ }
+ else // (pReqArgs == nullptr) => raise Dialog
+ {
+ sal_uInt32 nPrivFormat = rDoc.GetNumberFormat( nStartCol, nStartRow, nStartTab );
+ CellType eCellType = rDoc.GetCellType( nStartCol, nStartRow, nStartTab );
+ const SvNumberformat* pPrivEntry = pFormatter->GetEntry( nPrivFormat );
+ const SCSIZE nSelectHeight = nEndRow - nStartRow + 1;
+ const SCSIZE nSelectWidth = nEndCol - nStartCol + 1;
+
+ if (!pPrivEntry)
+ {
+ OSL_FAIL("Numberformat not found !!!");
+ }
+ else
+ {
+ SvNumFormatType nPrivType = pPrivEntry->GetType();
+ if (nPrivType & SvNumFormatType::DATE)
+ {
+ eFillCmd=FILL_DATE;
+ }
+ else if(eCellType==CELLTYPE_STRING)
+ {
+ eFillCmd=FILL_AUTO;
+ }
+ }
+
+ OUString aStartStr;
+
+ // suggest default Startvalue only, when just 1 row or column
+ if ( nStartCol == nEndCol || nStartRow == nEndRow )
+ {
+ double fInputEndVal = 0.0;
+ OUString aEndStr;
+
+ const bool forceSystemLocale = true;
+ aStartStr = rDoc.GetInputString( nStartCol, nStartRow, nStartTab, forceSystemLocale );
+ fStartVal = rDoc.GetValue( nStartCol, nStartRow, nStartTab );
+
+ if(eFillDir==FILL_TO_BOTTOM && nStartRow < nEndRow )
+ {
+ aEndStr = rDoc.GetInputString( nStartCol, nStartRow+1, nStartTab, forceSystemLocale );
+ if(!aEndStr.isEmpty())
+ {
+ fInputEndVal = rDoc.GetValue( nStartCol, nStartRow+1, nStartTab );
+ fIncVal=fInputEndVal-fStartVal;
+ }
+ }
+ else
+ {
+ if(nStartCol < nEndCol)
+ {
+ aEndStr = rDoc.GetInputString( nStartCol+1, nStartRow, nStartTab, forceSystemLocale );
+ if(!aEndStr.isEmpty())
+ {
+ fInputEndVal = rDoc.GetValue( nStartCol+1, nStartRow, nStartTab );
+ fIncVal=fInputEndVal-fStartVal;
+ }
+ }
+ }
+ if(eFillCmd==FILL_DATE)
+ {
+ const Date& rNullDate = rDoc.GetFormatTable()->GetNullDate();
+ Date aStartDate = rNullDate;
+ aStartDate.AddDays(fStartVal);
+ Date aEndDate = rNullDate;
+ aEndDate.AddDays(fInputEndVal);
+ double fTempDate=0;
+
+ if(aStartDate.GetYear()!=aEndDate.GetYear())
+ {
+ eFillDateCmd = FILL_YEAR;
+ fTempDate=aEndDate.GetYear()-aStartDate.GetYear();
+ }
+ if(aStartDate.GetMonth()!=aEndDate.GetMonth())
+ {
+ eFillDateCmd = FILL_MONTH;
+ fTempDate=fTempDate*12+aEndDate.GetMonth()-aStartDate.GetMonth();
+ }
+ if(aStartDate.GetDay()==aEndDate.GetDay())
+ {
+ fIncVal=fTempDate;
+ }
+ }
+ }
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScFillSeriesDlg> pDlg(pFact->CreateScFillSeriesDlg( pTabViewShell->GetFrameWeld(),
+ rDoc,
+ eFillDir, eFillCmd, eFillDateCmd,
+ aStartStr, fIncVal, fMaxVal,
+ nSelectHeight, nSelectWidth, nPossDir));
+
+ if ( nStartCol != nEndCol && nStartRow != nEndRow )
+ {
+ pDlg->SetEdStartValEnabled(false);
+ }
+
+ if ( pDlg->Execute() == RET_OK )
+ {
+ eFillDir = pDlg->GetFillDir();
+ eFillCmd = pDlg->GetFillCmd();
+ eFillDateCmd = pDlg->GetFillDateCmd();
+
+ if(eFillCmd==FILL_AUTO)
+ {
+ OUString aStr = pDlg->GetStartStr();
+ if(!aStr.isEmpty())
+ pTabViewShell->EnterData( nStartCol, nStartRow, nStartTab, aStr );
+ }
+ fStartVal = pDlg->GetStart();
+ fIncVal = pDlg->GetStep();
+ fMaxVal = pDlg->GetMax();
+ bDoIt = true;
+ }
+ }
+
+ if( bDoIt )
+ {
+ //nScFillModeMouseModifier = 0; // no Ctrl/Copy
+ pTabViewShell->FillSeries( eFillDir, eFillCmd, eFillDateCmd, fStartVal, fIncVal, fMaxVal );
+
+ if( ! rReq.IsAPI() )
+ {
+ OUString aPara;
+ const Color* pColor = nullptr;
+
+ switch( eFillDir )
+ {
+ case FILL_TO_BOTTOM: aPara = "B"; break;
+ case FILL_TO_RIGHT: aPara = "R"; break;
+ case FILL_TO_TOP: aPara = "T"; break;
+ case FILL_TO_LEFT: aPara = "L"; break;
+ default: break;
+ }
+ rReq.AppendItem( SfxStringItem( FID_FILL_SERIES, aPara ) );
+
+ switch( eFillCmd )
+ {
+ case FILL_SIMPLE: aPara = "S"; break;
+ case FILL_LINEAR: aPara = "L"; break;
+ case FILL_GROWTH: aPara = "G"; break;
+ case FILL_DATE: aPara = "D"; break;
+ case FILL_AUTO: aPara = "A"; break;
+ default: break;
+ }
+ rReq.AppendItem( SfxStringItem( FN_PARAM_1, aPara ) );
+
+ switch( eFillDateCmd )
+ {
+ case FILL_DAY: aPara = "D"; break;
+ case FILL_WEEKDAY: aPara = "W"; break;
+ case FILL_MONTH: aPara = "M"; break;
+ case FILL_YEAR: aPara = "Y"; break;
+ default: break;
+ }
+ rReq.AppendItem( SfxStringItem( FN_PARAM_2, aPara ) );
+
+ sal_uInt32 nFormatKey = pFormatter->GetStandardFormat(SvNumFormatType::NUMBER,
+ ScGlobal::eLnge );
+
+ pFormatter->GetOutputString( fIncVal, nFormatKey, aPara, &pColor );
+ rReq.AppendItem( SfxStringItem( FN_PARAM_3, aPara ) );
+
+ pFormatter->GetOutputString( fStartVal, nFormatKey, aPara, &pColor );
+ rReq.AppendItem( SfxStringItem( FN_PARAM_4, aPara ) );
+
+ pFormatter->GetOutputString( fMaxVal, nFormatKey, aPara, &pColor );
+ rReq.AppendItem( SfxStringItem( FN_PARAM_5, aPara ) );
+
+ rReq.Done();
+ }
+ }
+ }
+ break;
+
+ case FID_FILL_AUTO:
+ {
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+
+ GetViewData().GetFillData( nStartCol, nStartRow, nEndCol, nEndRow );
+ SCCOL nFillCol = GetViewData().GetRefEndX();
+ SCROW nFillRow = GetViewData().GetRefEndY();
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ if( pReqArgs != nullptr )
+ {
+ if( const SfxStringItem* pItem = pReqArgs->GetItemIfSet( FID_FILL_AUTO ) )
+ {
+ ScAddress aScAddress;
+ OUString aArg = pItem->GetValue();
+
+ if( aScAddress.Parse( aArg, rDoc, rDoc.GetAddressConvention() ) & ScRefFlags::VALID )
+ {
+ nFillRow = aScAddress.Row();
+ nFillCol = aScAddress.Col();
+ }
+ }
+
+ SCTAB nStartTab, nEndTab;
+ GetViewData().GetSimpleArea( nStartCol,nStartRow,nStartTab,
+ nEndCol,nEndRow,nEndTab );
+ }
+ else // call via mouse
+ {
+ // not in a merged cell
+
+ if ( nStartCol == nEndCol && nStartRow == nEndRow )
+ {
+ SCCOL nMergeCol = nStartCol;
+ SCROW nMergeRow = nStartRow;
+ if ( GetViewData().GetDocument().ExtendMerge(
+ nStartCol, nStartRow, nMergeCol, nMergeRow,
+ GetViewData().GetTabNo() ) )
+ {
+ if ( nFillCol >= nStartCol && nFillCol <= nMergeCol && nFillRow == nStartRow )
+ nFillCol = nStartCol;
+ if ( nFillRow >= nStartRow && nFillRow <= nMergeRow && nFillCol == nStartCol )
+ nFillRow = nStartRow;
+ }
+ }
+ }
+
+ if ( nFillCol != nEndCol || nFillRow != nEndRow )
+ {
+ if ( nFillCol==nEndCol || nFillRow==nEndRow )
+ {
+ FillDir eDir = FILL_TO_BOTTOM;
+ SCCOLROW nCount = 0;
+
+ if ( nFillCol==nEndCol )
+ {
+ if ( nFillRow > nEndRow )
+ {
+ eDir = FILL_TO_BOTTOM;
+ nCount = nFillRow - nEndRow;
+ }
+ else if ( nFillRow < nStartRow )
+ {
+ eDir = FILL_TO_TOP;
+ nCount = nStartRow - nFillRow;
+ }
+ }
+ else
+ {
+ if ( nFillCol > nEndCol )
+ {
+ eDir = FILL_TO_RIGHT;
+ nCount = nFillCol - nEndCol;
+ }
+ else if ( nFillCol < nStartCol )
+ {
+ eDir = FILL_TO_LEFT;
+ nCount = nStartCol - nFillCol;
+ }
+ }
+
+ if ( nCount != 0)
+ {
+ pTabViewShell->FillAuto( eDir, nStartCol, nStartRow, nEndCol, nEndRow, nCount );
+
+ if( ! rReq.IsAPI() )
+ {
+ ScAddress aAdr( nFillCol, nFillRow, 0 );
+ OUString aAdrStr(aAdr.Format(ScRefFlags::RANGE_ABS, &rDoc, rDoc.GetAddressConvention()));
+
+ rReq.AppendItem( SfxStringItem( FID_FILL_AUTO, aAdrStr ) );
+ rReq.Done();
+ }
+ }
+
+ }
+ else
+ {
+ OSL_FAIL( "Direction not unique for autofill" );
+ }
+ }
+ }
+ break;
+ case FID_FILL_SINGLE_EDIT:
+ ExecuteFillSingleEdit();
+ break;
+ case SID_RANDOM_NUMBER_GENERATOR_DIALOG:
+ {
+ sal_uInt16 nId = ScRandomNumberGeneratorDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+
+ }
+ break;
+ case SID_SAMPLING_DIALOG:
+ {
+ sal_uInt16 nId = ScSamplingDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+ case SID_DESCRIPTIVE_STATISTICS_DIALOG:
+ {
+ sal_uInt16 nId = ScDescriptiveStatisticsDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+ case SID_ANALYSIS_OF_VARIANCE_DIALOG:
+ {
+ sal_uInt16 nId = ScAnalysisOfVarianceDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+ case SID_CORRELATION_DIALOG:
+ {
+ sal_uInt16 nId = ScCorrelationDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+ case SID_COVARIANCE_DIALOG:
+ {
+ sal_uInt16 nId = ScCovarianceDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+ case SID_EXPONENTIAL_SMOOTHING_DIALOG:
+ {
+ sal_uInt16 nId = ScExponentialSmoothingDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+ case SID_MOVING_AVERAGE_DIALOG:
+ {
+ sal_uInt16 nId = ScMovingAverageDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+ case SID_REGRESSION_DIALOG:
+ {
+ sal_uInt16 nId = ScRegressionDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+ case SID_TTEST_DIALOG:
+ {
+ sal_uInt16 nId = ScTTestDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+
+ }
+ break;
+ case SID_FTEST_DIALOG:
+ {
+ sal_uInt16 nId = ScFTestDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+
+ }
+ break;
+ case SID_ZTEST_DIALOG:
+ {
+ sal_uInt16 nId = ScZTestDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+
+ }
+ break;
+ case SID_CHI_SQUARE_TEST_DIALOG:
+ {
+ sal_uInt16 nId = ScChiSquareTestDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+
+ }
+ break;
+ case SID_FOURIER_ANALYSIS_DIALOG:
+ {
+ sal_uInt16 nId = ScFourierAnalysisDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+
+ }
+ break;
+ case SID_SEARCH_RESULTS_DIALOG:
+ {
+ const SfxPoolItem* pItem = nullptr;
+ if (pReqArgs && pReqArgs->HasItem(SID_SEARCH_RESULTS_DIALOG, &pItem))
+ {
+ bool bVisible = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ // The window ID should equal the slot ID, but not a biggie if it wasn't.
+ sal_uInt16 nId = sc::SearchResultsDlgWrapper::GetChildWindowId();
+ pViewFrm->SetChildWindow(nId, bVisible, false);
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_INSERT_SPARKLINE:
+ case SID_EDIT_SPARKLINE_GROUP:
+ {
+ sal_uInt16 nId = sc::SparklineDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrame = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWindow = pViewFrame->GetChildWindow(nId);
+ pScMod->SetRefDialog(nId, pWindow == nullptr);
+ rReq.Done();
+ }
+ break;
+
+ case SID_EDIT_SPARKLINE:
+ {
+ sal_uInt16 nId = sc::SparklineDataRangeDialogWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrame = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWindow = pViewFrame->GetChildWindow(nId);
+ pScMod->SetRefDialog(nId, pWindow == nullptr);
+ rReq.Done();
+ }
+ break;
+
+ case SID_DELETE_SPARKLINE:
+ {
+ pTabViewShell->DeleteContents(InsertDeleteFlags::SPARKLINES);
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_DELETE_SPARKLINE_GROUP:
+ {
+ ScRange aMarkRange;
+ ScMarkType eMarkType = GetViewData().GetSimpleArea(aMarkRange);
+ if (eMarkType == SC_MARK_SIMPLE)
+ {
+ std::shared_ptr<sc::SparklineGroup> pSparklineGroup;
+ if (GetViewData().GetDocument().GetSparklineGroupInRange(aMarkRange, pSparklineGroup) && pSparklineGroup)
+ {
+ GetViewData().GetDocShell()->GetDocFunc().DeleteSparklineGroup(pSparklineGroup, GetViewData().GetTabNo());
+ }
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_GROUP_SPARKLINES:
+ {
+ ScRange aRange;
+ if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ ScAddress aCursorAddress(GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo());
+ auto pSparkline = GetViewData().GetDocument().GetSparkline(aCursorAddress);
+ if (pSparkline)
+ {
+ auto const& rpSparklineGroup = pSparkline->getSparklineGroup();
+ GetViewData().GetDocShell()->GetDocFunc().GroupSparklines(aRange, rpSparklineGroup);
+ }
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_UNGROUP_SPARKLINES:
+ {
+ ScRange aRange;
+ if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ GetViewData().GetDocShell()->GetDocFunc().UngroupSparklines(aRange);
+ }
+ rReq.Done();
+ }
+ break;
+
+ // disposal (Outlines)
+ // SID_AUTO_OUTLINE, SID_OUTLINE_DELETEALL in Execute (in docsh.idl)
+
+ case SID_OUTLINE_HIDE:
+ if ( GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() ) )
+ pTabViewShell->SetDataPilotDetails( false );
+ else
+ pTabViewShell->HideMarkedOutlines();
+ rReq.Done();
+ break;
+
+ case SID_OUTLINE_SHOW:
+ {
+ ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ if ( pDPObj )
+ {
+ Sequence<sheet::DataPilotFieldFilter> aFilters;
+ css::sheet::DataPilotFieldOrientation nOrientation;
+ if ( pTabViewShell->HasSelectionForDrillDown( nOrientation ) )
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractScDPShowDetailDlg> pDlg( pFact->CreateScDPShowDetailDlg(
+ pTabViewShell->GetFrameWeld(), *pDPObj, nOrientation ) );
+ if ( pDlg->Execute() == RET_OK )
+ {
+ OUString aNewDimName( pDlg->GetDimensionName() );
+ pTabViewShell->SetDataPilotDetails( true, &aNewDimName );
+ }
+ }
+ else if ( !pDPObj->IsServiceData() &&
+ pDPObj->GetDataFieldPositionData(
+ ScAddress( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() ),
+ aFilters ) )
+ pTabViewShell->ShowDataPilotSourceData( *pDPObj, aFilters );
+ else
+ pTabViewShell->SetDataPilotDetails(true);
+ }
+ else
+ pTabViewShell->ShowMarkedOutlines();
+ rReq.Done();
+ }
+ break;
+
+ case SID_OUTLINE_MAKE:
+ {
+ bool bColumns = false;
+ bool bOk = true;
+
+ if ( GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() ) )
+ {
+ ScDPNumGroupInfo aNumInfo;
+ aNumInfo.mbEnable = true;
+ aNumInfo.mbAutoStart = true;
+ aNumInfo.mbAutoEnd = true;
+ sal_Int32 nParts = 0;
+ if ( pTabViewShell->HasSelectionForDateGroup( aNumInfo, nParts ) )
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ const Date& rNullDate( GetViewData().GetDocument().GetFormatTable()->GetNullDate() );
+ ScopedVclPtr<AbstractScDPDateGroupDlg> pDlg( pFact->CreateScDPDateGroupDlg(
+ pTabViewShell->GetFrameWeld(),
+ aNumInfo, nParts, rNullDate ) );
+ if( pDlg->Execute() == RET_OK )
+ {
+ aNumInfo = pDlg->GetGroupInfo();
+ pTabViewShell->DateGroupDataPilot( aNumInfo, pDlg->GetDatePart() );
+ }
+ }
+ else if ( pTabViewShell->HasSelectionForNumGroup( aNumInfo ) )
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractScDPNumGroupDlg> pDlg( pFact->CreateScDPNumGroupDlg(
+ pTabViewShell->GetFrameWeld(), aNumInfo ) );
+ if( pDlg->Execute() == RET_OK )
+ pTabViewShell->NumGroupDataPilot( pDlg->GetGroupInfo() );
+ }
+ else
+ pTabViewShell->GroupDataPilot();
+
+ bOk = false;
+ }
+ else if( pReqArgs != nullptr )
+ {
+ const SfxPoolItem* pItem;
+ bOk = false;
+
+ if( pReqArgs->HasItem( SID_OUTLINE_MAKE, &pItem ) )
+ {
+ OUString aCol = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ aCol = aCol.toAsciiUpperCase();
+
+ switch( aCol[0] )
+ {
+ case 'R': bColumns=false; bOk = true;break;
+ case 'C': bColumns=true; bOk = true;break;
+ }
+ }
+ }
+ else // Dialog, when not whole rows/columns are marked
+ {
+ if ( GetViewData().SimpleColMarked() && !GetViewData().SimpleRowMarked() )
+ bColumns = true;
+ else if ( !GetViewData().SimpleColMarked() && GetViewData().SimpleRowMarked() )
+ bColumns = false;
+ else
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ VclPtr<AbstractScGroupDlg> pDlg(pFact->CreateAbstractScGroupDlg(pTabViewShell->GetFrameWeld()));
+
+ pDlg->StartExecuteAsync(
+ [pDlg, pTabViewShell] (sal_Int32 nResult) {
+ if( RET_OK == nResult )
+ {
+ bool bColumn = pDlg->GetColsChecked();
+ pTabViewShell->MakeOutline( bColumn );
+ }
+ pDlg->disposeOnce();
+ }
+ );
+
+ bOk = false;
+ }
+ }
+ if (bOk)
+ {
+ pTabViewShell->MakeOutline( bColumns );
+
+ if( ! rReq.IsAPI() )
+ {
+ OUString aCol = bColumns ? OUString('C') : OUString('R');
+ rReq.AppendItem( SfxStringItem( SID_OUTLINE_MAKE, aCol ) );
+ rReq.Done();
+ }
+ }
+ }
+ break;
+
+ case SID_OUTLINE_REMOVE:
+ {
+ bool bColumns = false;
+ bool bOk = true;
+
+ if ( GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() ) )
+ {
+ pTabViewShell->UngroupDataPilot();
+ bOk = false;
+ }
+ else if( pReqArgs != nullptr )
+ {
+ const SfxPoolItem* pItem;
+ bOk = false;
+
+ if( pReqArgs->HasItem( SID_OUTLINE_REMOVE, &pItem ) )
+ {
+ OUString aCol = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ aCol = aCol.toAsciiUpperCase();
+
+ switch (aCol[0])
+ {
+ case 'R': bColumns=false; bOk = true;break;
+ case 'C': bColumns=true; bOk = true;break;
+ }
+ }
+ }
+ else // Dialog only when removal for rows and columns is possible
+ {
+ bool bColPoss, bRowPoss;
+ pTabViewShell->TestRemoveOutline( bColPoss, bRowPoss );
+ // TODO: handle this case in LOK too
+ if ( bColPoss && bRowPoss && !comphelper::LibreOfficeKit::isActive() )
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ VclPtr<AbstractScGroupDlg> pDlg(pFact->CreateAbstractScGroupDlg(pTabViewShell->GetFrameWeld(), true));
+
+ pDlg->StartExecuteAsync(
+ [pDlg, pTabViewShell] (sal_Int32 nResult) {
+ if( RET_OK == nResult )
+ {
+ bool bColumn = pDlg->GetColsChecked();
+ pTabViewShell->RemoveOutline( bColumn );
+ }
+ pDlg->disposeOnce();
+ }
+ );
+
+ bOk = false;
+ }
+ else if ( bColPoss )
+ bColumns = true;
+ else if ( bRowPoss )
+ bColumns = false;
+ else
+ bOk = false;
+ }
+ if (bOk)
+ {
+ pTabViewShell->RemoveOutline( bColumns );
+
+ if( ! rReq.IsAPI() )
+ {
+ OUString aCol = bColumns ? OUString('C') : OUString('R');
+ rReq.AppendItem( SfxStringItem( SID_OUTLINE_REMOVE, aCol ) );
+ rReq.Done();
+ }
+ }
+ }
+ break;
+
+ // Clipboard
+
+ case SID_COPY: // for graphs in DrawShell
+ {
+ weld::WaitObject aWait( GetViewData().GetDialogParent() );
+ pTabViewShell->CopyToClip( nullptr, false, false, true );
+ rReq.Done();
+ GetViewData().SetPasteMode( ScPasteFlags::Mode | ScPasteFlags::Border );
+ pTabViewShell->ShowCursor();
+ pTabViewShell->UpdateCopySourceOverlay();
+ }
+ break;
+
+ case SID_CUT: // for graphs in DrawShell
+ {
+ weld::WaitObject aWait( GetViewData().GetDialogParent() );
+ pTabViewShell->CutToClip();
+ rReq.Done();
+ GetViewData().SetPasteMode( ScPasteFlags::Mode | ScPasteFlags::Border );
+ pTabViewShell->ShowCursor();
+ pTabViewShell->UpdateCopySourceOverlay();
+ }
+ break;
+
+ case SID_PASTE:
+ {
+ ScClipUtil::PasteFromClipboard( GetViewData(), pTabViewShell, true );
+ rReq.Done();
+ }
+ break;
+
+ case SID_CLIPBOARD_FORMAT_ITEMS:
+ {
+ weld::WaitObject aWait( GetViewData().GetDialogParent() );
+
+ SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
+ if (auto pIntItem = dynamic_cast<const SfxUInt32Item*>(pItem) )
+ nFormat = static_cast<SotClipboardFormatId>(pIntItem->GetValue());
+
+ if ( nFormat != SotClipboardFormatId::NONE )
+ {
+ css::uno::Reference<css::datatransfer::XTransferable2> xTransferable(ScTabViewShell::GetClipData(GetViewData().GetActiveWin()));
+ bool bCells = ( ScTransferObj::GetOwnClipboard(xTransferable) != nullptr );
+ bool bDraw = ( ScDrawTransferObj::GetOwnClipboard(xTransferable) != nullptr );
+ bool bOle = ( nFormat == SotClipboardFormatId::EMBED_SOURCE );
+
+ if ( bCells && bOle )
+ pTabViewShell->PasteFromSystem();
+ else if ( bDraw && bOle )
+ pTabViewShell->PasteDraw();
+ else
+ pTabViewShell->PasteFromSystem(nFormat);
+ }
+ //?else
+ //? pTabViewShell->PasteFromSystem();
+
+ rReq.Done();
+ }
+ pTabViewShell->CellContentChanged();
+ break;
+
+ case FID_INS_CELL_CONTENTS:
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ bool bOtherDoc = !rDoc.IsClipboardSource();
+ // keep a reference in case the clipboard is changed during dialog or PasteFromClip
+ const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(GetViewData().GetActiveWin()));
+ if ( pOwnClip )
+ {
+ InsertDeleteFlags nFlags = InsertDeleteFlags::NONE;
+ ScPasteFunc nFunction = ScPasteFunc::NONE;
+ InsCellCmd eMoveMode = INS_NONE;
+ bool bSkipEmpty = false;
+ bool bTranspose = false;
+ bool bAsLink = false;
+
+ if ( pReqArgs!=nullptr && pTabViewShell->SelectionEditable() )
+ {
+ const SfxPoolItem* pItem;
+ OUString aFlags('A');
+
+ if( pReqArgs->HasItem( FID_INS_CELL_CONTENTS, &pItem ) )
+ aFlags = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ nFlags |= FlagsFromString(aFlags);
+
+ const SfxUInt16Item* pFuncItem = rReq.GetArg<SfxUInt16Item>(FN_PARAM_1);
+ const SfxBoolItem* pSkipItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_2);
+ const SfxBoolItem* pTransposeItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_3);
+ const SfxBoolItem* pLinkItem = rReq.GetArg<SfxBoolItem>(FN_PARAM_4);
+ const SfxInt16Item* pMoveItem = rReq.GetArg<SfxInt16Item>(FN_PARAM_5);
+ if ( pFuncItem )
+ nFunction = static_cast<ScPasteFunc>(pFuncItem->GetValue());
+ if ( pSkipItem )
+ bSkipEmpty = pSkipItem->GetValue();
+ if ( pTransposeItem )
+ bTranspose = pTransposeItem->GetValue();
+ if ( pLinkItem )
+ bAsLink = pLinkItem->GetValue();
+ if ( pMoveItem )
+ eMoveMode = static_cast<InsCellCmd>(pMoveItem->GetValue());
+ }
+ else
+ {
+ ScEditableTester aTester( pTabViewShell );
+ if (aTester.IsEditable())
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScInsertContentsDlg> pDlg(pFact->CreateScInsertContentsDlg(pTabViewShell->GetFrameWeld()));
+ pDlg->SetOtherDoc( bOtherDoc );
+ // if ChangeTrack MoveMode disable
+ pDlg->SetChangeTrack( rDoc.GetChangeTrack() != nullptr );
+ // fdo#56098 disable shift if necessary
+ if (!bOtherDoc)
+ {
+ ScViewData& rData = GetViewData();
+ if ( rData.GetMarkData().GetTableSelect( rData.GetTabNo() ) )
+ {
+ SCCOL nStartX, nEndX, nClipStartX, nClipSizeX, nRangeSizeX;
+ SCROW nStartY, nEndY, nClipStartY, nClipSizeY, nRangeSizeY;
+ SCTAB nStartTab, nEndTab;
+ pOwnClip->GetDocument()->GetClipStart( nClipStartX, nClipStartY );
+ pOwnClip->GetDocument()->GetClipArea( nClipSizeX, nClipSizeY, true );
+
+ if ( rData.GetSimpleArea( nStartX, nStartY, nStartTab,
+ nEndX, nEndY, nEndTab ) != SC_MARK_SIMPLE ||
+ nStartTab != nEndTab )
+ {
+ // the destination is not a simple range,
+ // assume the destination as the current cell
+ nStartX = nEndX = rData.GetCurX();
+ nStartY = nEndY = rData.GetCurY();
+ nStartTab = rData.GetTabNo();
+ }
+ // we now have clip- and range dimensions
+ // the size of the destination area is the larger of the two
+ nRangeSizeX = nClipSizeX >= nEndX - nStartX ? nClipSizeX : nEndX - nStartX;
+ nRangeSizeY = nClipSizeY >= nEndY - nStartY ? nClipSizeY : nEndY - nStartY;
+ // When the source and destination areas intersect things may go wrong,
+ // especially if the area contains references. This may produce data loss
+ // (e.g. formulas that get wrong references), this scenario _must_ be avoided.
+ ScRange aSource( nClipStartX, nClipStartY, nStartTab,
+ nClipStartX + nClipSizeX, nClipStartY + nClipSizeY, nStartTab );
+ ScRange aDest( nStartX, nStartY, nStartTab,
+ nStartX + nRangeSizeX, nStartY + nRangeSizeY, nStartTab );
+ if ( pOwnClip->GetDocument()->IsCutMode() && aSource.Intersects( aDest ) )
+ pDlg->SetCellShiftDisabled( CellShiftDisabledFlags::Down | CellShiftDisabledFlags::Right );
+ else
+ {
+ //no conflict with intersecting ranges,
+ //check if paste plus shift will fit on sheet
+ //and disable shift-option if no fit
+ CellShiftDisabledFlags nDisableShiftX = CellShiftDisabledFlags::NONE;
+ CellShiftDisabledFlags nDisableShiftY = CellShiftDisabledFlags::NONE;
+
+ //check if horizontal shift will fit
+ if ( !rData.GetDocument().IsBlockEmpty(
+ rDoc.MaxCol() - nRangeSizeX, nStartY,
+ rDoc.MaxCol(), nStartY + nRangeSizeY,
+ nStartTab ) )
+ nDisableShiftX = CellShiftDisabledFlags::Right;
+
+ //check if vertical shift will fit
+ if ( !rData.GetDocument().IsBlockEmpty(
+ nStartX, rDoc.MaxRow() - nRangeSizeY,
+ nStartX + nRangeSizeX, rDoc.MaxRow(),
+ nStartTab ) )
+ nDisableShiftY = CellShiftDisabledFlags::Down;
+
+ if ( nDisableShiftX != CellShiftDisabledFlags::NONE || nDisableShiftY != CellShiftDisabledFlags::NONE)
+ pDlg->SetCellShiftDisabled( nDisableShiftX | nDisableShiftY );
+ }
+ }
+ }
+ if (pDlg->Execute() == RET_OK)
+ {
+ nFlags = pDlg->GetInsContentsCmdBits();
+ nFunction = pDlg->GetFormulaCmdBits();
+ bSkipEmpty = pDlg->IsSkipEmptyCells();
+ bTranspose = pDlg->IsTranspose();
+ bAsLink = pDlg->IsLink();
+ eMoveMode = pDlg->GetMoveMode();
+ }
+ }
+ else
+ pTabViewShell->ErrorMessage(aTester.GetMessageId());
+ }
+
+ if( nFlags != InsertDeleteFlags::NONE )
+ {
+ {
+ weld::WaitObject aWait( GetViewData().GetDialogParent() );
+ if ( bAsLink && bOtherDoc )
+ pTabViewShell->PasteFromSystem(SotClipboardFormatId::LINK); // DDE insert
+ else
+ {
+ pTabViewShell->PasteFromClip( nFlags, pOwnClip->GetDocument(),
+ nFunction, bSkipEmpty, bTranspose, bAsLink,
+ eMoveMode, InsertDeleteFlags::NONE, true ); // allow warning dialog
+ }
+ }
+
+ if( !pReqArgs )
+ {
+ OUString aFlags = FlagsToString( nFlags );
+
+ rReq.AppendItem( SfxStringItem( FID_INS_CELL_CONTENTS, aFlags ) );
+ rReq.AppendItem( SfxBoolItem( FN_PARAM_2, bSkipEmpty ) );
+ rReq.AppendItem( SfxBoolItem( FN_PARAM_3, bTranspose ) );
+ rReq.AppendItem( SfxBoolItem( FN_PARAM_4, bAsLink ) );
+ rReq.AppendItem( SfxUInt16Item( FN_PARAM_1, static_cast<sal_uInt16>(nFunction) ) );
+ rReq.AppendItem( SfxInt16Item( FN_PARAM_5, static_cast<sal_Int16>(eMoveMode) ) );
+ rReq.Done();
+ }
+ }
+ }
+ }
+ pTabViewShell->CellContentChanged(); // => PasteFromXXX ???
+ break;
+ case SID_PASTE_ONLY_VALUE:
+ case SID_PASTE_ONLY_TEXT:
+ case SID_PASTE_ONLY_FORMULA:
+ {
+ if ( ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(GetViewData().GetActiveWin())) ) // own cell data
+ {
+ rReq.SetSlot( FID_INS_CELL_CONTENTS );
+ OUString aFlags;
+ if ( nSlot == SID_PASTE_ONLY_VALUE )
+ aFlags = "V";
+ else if ( nSlot == SID_PASTE_ONLY_TEXT )
+ aFlags = "S";
+ else
+ aFlags = "F";
+ rReq.AppendItem( SfxStringItem( FID_INS_CELL_CONTENTS, aFlags ) );
+ ExecuteSlot( rReq, GetInterface() );
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 1)); // 1 = success
+ pTabViewShell->CellContentChanged();
+ }
+ else
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 0)); // 0 = fail
+ break;
+ }
+ case SID_PASTE_TRANSPOSED:
+ {
+ if (ScTransferObj::GetOwnClipboard(
+ ScTabViewShell::GetClipData(GetViewData().GetActiveWin()))) // own cell data
+ {
+ rReq.SetSlot(FID_INS_CELL_CONTENTS);
+ // By default content (values/numbers, strings, formulas and dates),
+ // attributes and notes are pasted
+ rReq.AppendItem(SfxBoolItem(FN_PARAM_3, true)); // transpose
+ ExecuteSlot(rReq, GetInterface());
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 1)); // 1 = success
+ pTabViewShell->CellContentChanged();
+ }
+ else
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 0)); // 0 = fail
+ break;
+ }
+ case SID_PASTE_AS_LINK:
+ {
+ if (ScTransferObj::GetOwnClipboard(
+ ScTabViewShell::GetClipData(GetViewData().GetActiveWin()))) // own cell data
+ {
+ rReq.SetSlot(FID_INS_CELL_CONTENTS);
+ // paste links to values/numbers, strings, formulas and dates
+ // do not paste attributes, notes and objects
+ rReq.AppendItem(SfxStringItem(FID_INS_CELL_CONTENTS, "VSFD"));
+ rReq.AppendItem(SfxBoolItem(FN_PARAM_4, true)); // as link
+ ExecuteSlot(rReq, GetInterface());
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 1)); // 1 = success
+ pTabViewShell->CellContentChanged();
+ }
+ else
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 0)); // 0 = fail
+ break;
+ }
+ case SID_PASTE_TEXTIMPORT_DIALOG:
+ {
+ vcl::Window* pWin = GetViewData().GetActiveWin();
+ TransferableDataHelper aDataHelper(
+ TransferableDataHelper::CreateFromSystemClipboard(pWin));
+ const uno::Reference<datatransfer::XTransferable>& xTransferable
+ = aDataHelper.GetTransferable();
+ SotClipboardFormatId format = SotClipboardFormatId::STRING;
+ bool bSuccess = false;
+ if (xTransferable.is() && HasClipboardFormat(format))
+ {
+ OUString sStrBuffer;
+ bSuccess = aDataHelper.GetString(format, sStrBuffer);
+ if (bSuccess)
+ {
+ auto pStrm = std::make_shared<ScImportStringStream>(sStrBuffer);
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ VclPtr<AbstractScImportAsciiDlg> pDlg(pFact->CreateScImportAsciiDlg(
+ pWin ? pWin->GetFrameWeld() : nullptr, OUString(), pStrm.get(), SC_PASTETEXT));
+ ScRange aRange;
+ SCCOL nPosX = 0;
+ SCROW nPosY = 0;
+ if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ nPosX = aRange.aStart.Col();
+ nPosY = aRange.aStart.Row();
+ }
+ else
+ {
+ nPosX = GetViewData().GetCurX();
+ nPosY = GetViewData().GetCurY();
+ }
+ ScAddress aCellPos(nPosX, nPosY, GetViewData().GetTabNo());
+ auto pObj = std::make_shared<ScImportExport>(GetViewData().GetDocument(), aCellPos);
+ pObj->SetOverwriting(true);
+ if (pDlg->Execute()) {
+ ScAsciiOptions aOptions;
+ pDlg->GetOptions(aOptions);
+ pDlg->SaveParameters();
+ pObj->SetExtOptions(aOptions);
+ pObj->ImportString(sStrBuffer, format);
+ }
+ pDlg->disposeOnce();
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 1)); // 1 = success, 0 = fail
+ rReq.Done();
+ }
+ }
+ if (!bSuccess)
+ {
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 0)); // 0 = fail
+ rReq.Ignore();
+ }
+ }
+ break;
+ case SID_PASTE_SPECIAL:
+ // differentiate between own cell data and draw objects/external data
+ // this makes FID_INS_CELL_CONTENTS superfluous
+ {
+ vcl::Window* pWin = GetViewData().GetActiveWin();
+ css::uno::Reference<css::datatransfer::XTransferable2> xTransferable(ScTabViewShell::GetClipData(pWin));
+
+ // Clipboard-ID given as parameter? Basic "PasteSpecial(Format)"
+ const SfxPoolItem* pItem=nullptr;
+ if ( pReqArgs &&
+ pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET &&
+ dynamic_cast<const SfxUInt32Item*>( pItem) != nullptr )
+ {
+ SotClipboardFormatId nFormat = static_cast<SotClipboardFormatId>(static_cast<const SfxUInt32Item*>(pItem)->GetValue());
+ bool bRet=true;
+ {
+ weld::WaitObject aWait( GetViewData().GetDialogParent() );
+ bool bDraw = ( ScDrawTransferObj::GetOwnClipboard(xTransferable) != nullptr );
+ if ( bDraw && nFormat == SotClipboardFormatId::EMBED_SOURCE )
+ pTabViewShell->PasteDraw();
+ else
+ bRet = pTabViewShell->PasteFromSystem(nFormat, true); // TRUE: no error messages
+ }
+
+ if ( bRet )
+ {
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 1)); // 1 = success, 0 = fail
+ rReq.Done();
+ }
+ else
+ // if format is not available -> fallback to request without parameters
+ pItem = nullptr;
+ }
+
+ if ( !pItem )
+ {
+ if ( ScTransferObj::GetOwnClipboard(xTransferable) ) // own cell data
+ {
+ rReq.SetSlot( FID_INS_CELL_CONTENTS );
+ ExecuteSlot( rReq, GetInterface() );
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 1)); // 1 = success
+ }
+ else // draw objects or external data
+ {
+ bool bDraw = ( ScDrawTransferObj::GetOwnClipboard(xTransferable) != nullptr );
+
+ SvxClipboardFormatItem aFormats( SID_CLIPBOARD_FORMAT_ITEMS );
+ GetPossibleClipboardFormats( aFormats );
+
+ sal_uInt16 nFormatCount = aFormats.Count();
+ if ( nFormatCount )
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractPasteDialog> pDlg(pFact->CreatePasteDialog(pTabViewShell->GetFrameWeld()));
+ for (sal_uInt16 i=0; i<nFormatCount; i++)
+ {
+ SotClipboardFormatId nFormatId = aFormats.GetClipbrdFormatId( i );
+ OUString aName = aFormats.GetClipbrdFormatName( i );
+ // special case for paste dialog: '*' is replaced by object type
+ if ( nFormatId == SotClipboardFormatId::EMBED_SOURCE )
+ aName = "*";
+ pDlg->Insert( nFormatId, aName );
+ }
+
+ SfxViewFrame* pViewFrame = pTabViewShell->GetViewFrame();
+ auto xFrame = pViewFrame->GetFrame().GetFrameInterface();
+ const OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(xFrame));
+ auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:PasteTextImportDialog", aModuleName);
+ OUString sLabel(vcl::CommandInfoProvider::GetTooltipLabelForCommand(aProperties));
+ pDlg->InsertUno(".uno:PasteTextImportDialog", sLabel);
+
+ TransferableDataHelper aDataHelper(
+ TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
+ SotClipboardFormatId nFormat = pDlg->GetFormat( aDataHelper.GetTransferable() );
+ if (nFormat != SotClipboardFormatId::NONE)
+ {
+ {
+ weld::WaitObject aWait( GetViewData().GetDialogParent() );
+ if ( bDraw && nFormat == SotClipboardFormatId::EMBED_SOURCE )
+ pTabViewShell->PasteDraw();
+ else
+ pTabViewShell->PasteFromSystem(nFormat);
+ }
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 1)); // 1 = success
+ rReq.AppendItem( SfxUInt32Item( nSlot, static_cast<sal_uInt32>(nFormat) ) );
+ rReq.Done();
+ }
+ else
+ {
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 0)); // 0 = fail
+ rReq.Ignore();
+ }
+ }
+ else
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 0)); // 0 = fail
+ }
+ }
+ }
+ pTabViewShell->CellContentChanged(); // => PasteFromSystem() ???
+ break;
+
+ case SID_PASTE_UNFORMATTED:
+ // differentiate between own cell data and draw objects/external data
+ // this makes FID_INS_CELL_CONTENTS superfluous
+ {
+ weld::WaitObject aWait( GetViewData().GetDialogParent() );
+
+ // we should differentiate between SotClipboardFormatId::STRING and SotClipboardFormatId::STRING_TSVC,
+ // and paste the SotClipboardFormatId::STRING_TSVC if it is available.
+ // Which makes a difference if the clipboard contains cells with embedded line breaks.
+
+ SotClipboardFormatId nFormat = HasClipboardFormat( SotClipboardFormatId::STRING_TSVC) ?
+ SotClipboardFormatId::STRING_TSVC : SotClipboardFormatId::STRING;
+
+ const bool bRet = pTabViewShell->PasteFromSystem(nFormat, true); // TRUE: no error messages
+ if ( bRet )
+ {
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 1)); // 1 = success
+ rReq.Done();
+ }
+ else
+ {
+ rReq.SetReturnValue(SfxInt16Item(nSlot, 0)); // 0 = fail
+ }
+
+ pTabViewShell->CellContentChanged(); // => PasteFromSystem() ???
+ }
+ break;
+
+ // other
+
+ case FID_INS_ROWBRK:
+ pTabViewShell->InsertPageBreak( false );
+ rReq.Done();
+ break;
+
+ case FID_INS_COLBRK:
+ pTabViewShell->InsertPageBreak( true );
+ rReq.Done();
+ break;
+
+ case FID_DEL_ROWBRK:
+ pTabViewShell->DeletePageBreak( false );
+ rReq.Done();
+ break;
+
+ case FID_DEL_COLBRK:
+ pTabViewShell->DeletePageBreak( true );
+ rReq.Done();
+ break;
+
+ case SID_DETECTIVE_ADD_PRED:
+ pTabViewShell->DetectiveAddPred();
+ rReq.Done();
+ break;
+
+ case SID_DETECTIVE_DEL_PRED:
+ pTabViewShell->DetectiveDelPred();
+ rReq.Done();
+ break;
+
+ case SID_DETECTIVE_ADD_SUCC:
+ pTabViewShell->DetectiveAddSucc();
+ rReq.Done();
+ break;
+
+ case SID_DETECTIVE_DEL_SUCC:
+ pTabViewShell->DetectiveDelSucc();
+ rReq.Done();
+ break;
+
+ case SID_DETECTIVE_ADD_ERR:
+ pTabViewShell->DetectiveAddError();
+ rReq.Done();
+ break;
+
+ case SID_DETECTIVE_INVALID:
+ pTabViewShell->DetectiveMarkInvalid();
+ rReq.Done();
+ break;
+
+ case SID_DETECTIVE_REFRESH:
+ pTabViewShell->DetectiveRefresh();
+ rReq.Done();
+ break;
+
+ case SID_DETECTIVE_MARK_PRED:
+ pTabViewShell->DetectiveMarkPred();
+ break;
+ case SID_DETECTIVE_MARK_SUCC:
+ pTabViewShell->DetectiveMarkSucc();
+ break;
+ case SID_INSERT_CURRENT_DATE:
+ pTabViewShell->InsertCurrentTime(
+ SvNumFormatType::DATE, ScResId(STR_UNDO_INSERT_CURRENT_DATE));
+ break;
+ case SID_INSERT_CURRENT_TIME:
+ pTabViewShell->InsertCurrentTime(
+ SvNumFormatType::TIME, ScResId(STR_UNDO_INSERT_CURRENT_TIME));
+ break;
+
+ case SID_SPELL_DIALOG:
+ {
+ SfxViewFrame* pViewFrame = pTabViewShell->GetViewFrame();
+ if( rReq.GetArgs() )
+ 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;
+
+ case SID_HANGUL_HANJA_CONVERSION:
+ pTabViewShell->DoHangulHanjaConversion();
+ break;
+
+ case SID_CHINESE_CONVERSION:
+ {
+ //open ChineseTranslationDialog
+ Reference< XComponentContext > xContext(
+ ::cppu::defaultBootstrap_InitialComponentContext() ); //@todo get context from calc if that has one
+ if(xContext.is())
+ {
+ Reference< lang::XMultiComponentFactory > xMCF( xContext->getServiceManager() );
+ if(xMCF.is())
+ {
+ 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
+ uno::Sequence<uno::Any> aSeq(comphelper::InitAnyPropertySequence(
+ {
+ {"ParentWindow", uno::Any(Reference< awt::XWindow >())}
+ }));
+ 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 eSourceLang = bToSimplified ? LANGUAGE_CHINESE_TRADITIONAL : LANGUAGE_CHINESE_SIMPLIFIED;
+ LanguageType eTargetLang = bToSimplified ? LANGUAGE_CHINESE_SIMPLIFIED : LANGUAGE_CHINESE_TRADITIONAL;
+ sal_Int32 nOptions = bUseVariants ? i18n::TextConversionOption::USE_CHARACTER_VARIANTS : 0;
+ if( !bCommonTerms )
+ nOptions |= i18n::TextConversionOption::CHARACTER_BY_CHARACTER;
+
+ vcl::Font aTargetFont = OutputDevice::GetDefaultFont(
+ DefaultFontType::CJK_SPREADSHEET,
+ eTargetLang, GetDefaultFontFlags::OnlyOne );
+ ScConversionParam aConvParam( SC_CONVERSION_CHINESE_TRANSL,
+ eSourceLang, eTargetLang, aTargetFont, nOptions, false );
+ pTabViewShell->DoSheetConversion( aConvParam );
+ }
+ }
+ Reference< lang::XComponent > xComponent( xDialog, UNO_QUERY );
+ if( xComponent.is() )
+ xComponent->dispose();
+ }
+ }
+ }
+ break;
+
+ case SID_CONVERT_FORMULA_TO_VALUE:
+ {
+ pTabViewShell->ConvertFormulaToValue();
+ }
+ break;
+ case SID_THESAURUS:
+ pTabViewShell->DoThesaurus();
+ break;
+
+ case SID_TOGGLE_REL:
+ pTabViewShell->DoRefConversion();
+ break;
+
+ case SID_DEC_INDENT:
+ pTabViewShell->ChangeIndent( false );
+ break;
+ case SID_INC_INDENT:
+ pTabViewShell->ChangeIndent( true );
+ break;
+
+ case FID_USE_NAME:
+ {
+ CreateNameFlags nFlags = pTabViewShell->GetCreateNameFlags();
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScNameCreateDlg> pDlg(pFact->CreateScNameCreateDlg(pTabViewShell->GetFrameWeld(), nFlags));
+
+ if( pDlg->Execute() )
+ {
+ pTabViewShell->CreateNames(pDlg->GetFlags());
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_CONSOLIDATE:
+ {
+ const ScConsolidateItem* pItem;
+ if ( pReqArgs && (pItem =
+ pReqArgs->GetItemIfSet( SCITEM_CONSOLIDATEDATA )) )
+ {
+ const ScConsolidateParam& rParam = pItem->GetData();
+
+ pTabViewShell->Consolidate( rParam );
+ GetViewData().GetDocument().SetConsolidateDlgData( std::unique_ptr<ScConsolidateParam>(new ScConsolidateParam(rParam)) );
+
+ rReq.Done();
+ }
+#if HAVE_FEATURE_SCRIPTING
+ else if (rReq.IsAPI())
+ SbxBase::SetError(ERRCODE_BASIC_BAD_PARAMETER);
+#endif
+ }
+ break;
+
+ case SID_INS_FUNCTION:
+ {
+ const SfxBoolItem* pOkItem = static_cast<const SfxBoolItem*>(&pReqArgs->Get( SID_DLG_RETOK ));
+
+ if ( pOkItem->GetValue() ) // OK
+ {
+ OUString aFormula;
+ const SfxStringItem* pSItem = &pReqArgs->Get( SCITEM_STRING );
+ const SfxBoolItem* pMatrixItem = static_cast<const SfxBoolItem*>(&pReqArgs->Get( SID_DLG_MATRIX ));
+
+ aFormula += pSItem->GetValue();
+ pScMod->ActivateInputWindow( &aFormula, pMatrixItem->GetValue() );
+ }
+ else // CANCEL
+ {
+ pScMod->ActivateInputWindow();
+ }
+ rReq.Ignore(); // only SID_ENTER_STRING is recorded
+ }
+ break;
+
+ case FID_DEFINE_NAME:
+ case FID_DEFINE_CURRENT_NAME:
+ if ( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ OUString aName, aSymbol, aAttrib;
+
+ if( pReqArgs->HasItem( FID_DEFINE_NAME, &pItem ) )
+ aName = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ if( pReqArgs->HasItem( FN_PARAM_1, &pItem ) )
+ aSymbol = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ if( pReqArgs->HasItem( FN_PARAM_2, &pItem ) )
+ aAttrib = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ if ( !aName.isEmpty() && !aSymbol.isEmpty() )
+ {
+ if (pTabViewShell->InsertName( aName, aSymbol, aAttrib ))
+ rReq.Done();
+#if HAVE_FEATURE_SCRIPTING
+ else
+ SbxBase::SetError( ERRCODE_BASIC_BAD_PARAMETER ); // Basic-error
+#endif
+ }
+ }
+ else
+ {
+ sal_uInt16 nId = ScNameDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+ case FID_ADD_NAME:
+ {
+ sal_uInt16 nId = ScNameDefDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+
+ case SID_OPENDLG_CONDFRMT:
+ case SID_OPENDLG_CURRENTCONDFRMT:
+ case SID_OPENDLG_COLORSCALE:
+ case SID_OPENDLG_DATABAR:
+ case SID_OPENDLG_ICONSET:
+ case SID_OPENDLG_CONDDATE:
+ {
+ sal_uInt32 nIndex = sal_uInt32(-1);
+ bool bManaged = false;
+
+ // Get the pool item stored by Conditional Format Manager Dialog.
+ auto itemsRange = pTabViewShell->GetPool().GetItemSurrogates(SCITEM_CONDFORMATDLGDATA);
+ if (itemsRange.begin() != itemsRange.end())
+ {
+ const ScCondFormatDlgItem* pDlgItem = static_cast<const ScCondFormatDlgItem*>(*itemsRange.begin());
+ nIndex = pDlgItem->GetIndex();
+ bManaged = true;
+ }
+
+ // Check if the Conditional Manager Dialog is editing or adding
+ // conditional format item.
+ if ( bManaged )
+ {
+ sal_uInt16 nId = ScCondFormatDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ break;
+ }
+
+ ScRangeList aRangeList;
+ ScViewData& rData = GetViewData();
+ rData.GetMarkData().FillRangeListWithMarks(&aRangeList, false);
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ if(rDoc.IsTabProtected(rData.GetTabNo()))
+ {
+ pTabViewShell->ErrorMessage( STR_ERR_CONDFORMAT_PROTECTED );
+ break;
+ }
+
+ ScAddress aPos(rData.GetCurX(), rData.GetCurY(), rData.GetTabNo());
+ if(aRangeList.empty())
+ {
+ aRangeList.push_back(ScRange(aPos));
+ }
+
+ // try to find an existing conditional format
+ const ScConditionalFormat* pCondFormat = nullptr;
+ const ScPatternAttr* pPattern = rDoc.GetPattern(aPos.Col(), aPos.Row(), aPos.Tab());
+ ScConditionalFormatList* pList = rDoc.GetCondFormList(aPos.Tab());
+ const ScCondFormatIndexes& rCondFormats = pPattern->GetItem(ATTR_CONDITIONAL).GetCondFormatData();
+ bool bContainsCondFormat = !rCondFormats.empty();
+ bool bCondFormatDlg = false;
+ bool bContainsExistingCondFormat = false;
+ if(bContainsCondFormat)
+ {
+ for (const auto& rCondFormat : rCondFormats)
+ {
+ // check if at least one existing conditional format has the same range
+ pCondFormat = pList->GetFormat(rCondFormat);
+ if(!pCondFormat)
+ continue;
+
+ bContainsExistingCondFormat = true;
+ const ScRangeList& rCondFormatRange = pCondFormat->GetRange();
+ if(rCondFormatRange == aRangeList)
+ {
+ // found a matching range, edit this conditional format
+ bCondFormatDlg = true;
+ nIndex = pCondFormat->GetKey();
+ break;
+ }
+ }
+ }
+
+ // do we have a parameter with the conditional formatting type?
+ const SfxInt16Item* pParam = rReq.GetArg<SfxInt16Item>(FN_PARAM_1);
+ if (pParam && nSlot == SID_OPENDLG_ICONSET)
+ {
+ auto pFormat = std::make_unique<ScConditionalFormat>(0, &rDoc);
+ pFormat->SetRange(aRangeList);
+
+ ScIconSetType eIconSetType = limit_cast<ScIconSetType>(pParam->GetValue(), IconSet_3Arrows, IconSet_5Boxes);
+ const int nSteps = ScIconSetFormat::getIconSetElements(eIconSetType);
+
+ ScIconSetFormat* pEntry = new ScIconSetFormat(&rDoc);
+ ScIconSetFormatData* pIconSetFormatData = new ScIconSetFormatData(eIconSetType);
+
+ pIconSetFormatData->m_Entries.emplace_back(new ScColorScaleEntry(0, COL_RED, COLORSCALE_PERCENT));
+ pIconSetFormatData->m_Entries.emplace_back(new ScColorScaleEntry(round(100. / nSteps), COL_BROWN, COLORSCALE_PERCENT));
+ pIconSetFormatData->m_Entries.emplace_back(new ScColorScaleEntry(round(200. / nSteps), COL_YELLOW, COLORSCALE_PERCENT));
+ if (nSteps > 3)
+ pIconSetFormatData->m_Entries.emplace_back(new ScColorScaleEntry(round(300. / nSteps), COL_WHITE, COLORSCALE_PERCENT));
+ if (nSteps > 4)
+ pIconSetFormatData->m_Entries.emplace_back(new ScColorScaleEntry(round(400. / nSteps), COL_GREEN, COLORSCALE_PERCENT));
+
+ pEntry->SetIconSetData(pIconSetFormatData);
+ pFormat->AddEntry(pEntry);
+
+ // use the new conditional formatting
+ GetViewData().GetDocShell()->GetDocFunc().ReplaceConditionalFormat(nIndex, std::move(pFormat), aPos.Tab(), aRangeList);
+
+ break;
+ }
+
+ // if not found a conditional format ask whether we should edit one of the existing
+ // or should create a new overlapping conditional format
+ if(bContainsCondFormat && !bCondFormatDlg && bContainsExistingCondFormat)
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pTabViewShell->GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_EDIT_EXISTING_COND_FORMATS)));
+ xQueryBox->set_default_response(RET_YES);
+ bool bEditExisting = xQueryBox->run() == RET_YES;
+ if (bEditExisting)
+ {
+ // differentiate between ranges where one conditional format is defined
+ // and several formats are defined
+ // if we have only one => open the cond format dlg to edit it
+ // otherwise open the manage cond format dlg
+ if (rCondFormats.size() == 1)
+ {
+ pCondFormat = pList->GetFormat(rCondFormats[0]);
+ assert(pCondFormat);
+ nIndex = pCondFormat->GetKey();
+ bCondFormatDlg = true;
+ }
+ else
+ {
+ // Queue message to open Conditional Format Manager Dialog.
+ GetViewData().GetDispatcher().Execute( SID_OPENDLG_CONDFRMT_MANAGER, SfxCallMode::ASYNCHRON );
+ break;
+ }
+ }
+ else
+ {
+ // define an overlapping conditional format
+ pCondFormat = pList->GetFormat(rCondFormats[0]);
+ assert(pCondFormat);
+ bCondFormatDlg = true;
+ }
+ }
+
+ condformat::dialog::ScCondFormatDialogType eType = condformat::dialog::NONE;
+ switch(nSlot)
+ {
+ case SID_OPENDLG_CONDFRMT:
+ case SID_OPENDLG_CURRENTCONDFRMT:
+ eType = condformat::dialog::CONDITION;
+ break;
+ case SID_OPENDLG_COLORSCALE:
+ eType = condformat::dialog::COLORSCALE;
+ break;
+ case SID_OPENDLG_DATABAR:
+ eType = condformat::dialog::DATABAR;
+ break;
+ case SID_OPENDLG_ICONSET:
+ eType = condformat::dialog::ICONSET;
+ break;
+ case SID_OPENDLG_CONDDATE:
+ eType = condformat::dialog::DATE;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+
+ if(bCondFormatDlg || !bContainsCondFormat)
+ {
+ // Put the xml string parameter to initialize the
+ // Conditional Format Dialog.
+ ScCondFormatDlgItem aDlgItem(nullptr, nIndex, false);
+ aDlgItem.SetDialogType(eType);
+ pTabViewShell->GetPool().Put(aDlgItem);
+
+ sal_uInt16 nId = ScCondFormatDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ }
+ break;
+
+ case SID_DEFINE_COLROWNAMERANGES:
+ {
+
+ sal_uInt16 nId = ScColRowNameRangesDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+
+ }
+ break;
+
+ case SID_UPDATECHART:
+ {
+ bool bAll = false;
+
+ if( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+
+ if( pReqArgs->HasItem( SID_UPDATECHART, &pItem ) )
+ bAll = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ }
+
+ pTabViewShell->UpdateCharts( bAll );
+
+ if( ! rReq.IsAPI() )
+ {
+ rReq.AppendItem( SfxBoolItem( SID_UPDATECHART, bAll ) );
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_TABOP:
+ if (pReqArgs)
+ {
+ const ScTabOpItem& rItem =
+ static_cast<const ScTabOpItem&>(
+ pReqArgs->Get( SID_TABOP ));
+
+ pTabViewShell->TabOp( rItem.GetData() );
+
+ rReq.Done( *pReqArgs );
+ }
+ break;
+
+ case SID_SOLVE:
+ if (pReqArgs)
+ {
+ const ScSolveItem& rItem =
+ pReqArgs->Get( SCITEM_SOLVEDATA );
+
+ pTabViewShell->Solve( rItem.GetData() );
+
+ rReq.Done( *pReqArgs );
+ }
+ break;
+
+ case FID_INSERT_NAME:
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScNamePasteDlg> pDlg(pFact->CreateScNamePasteDlg(pTabViewShell->GetFrameWeld(), GetViewData().GetDocShell()));
+ switch( pDlg->Execute() )
+ {
+ case BTN_PASTE_LIST:
+ pTabViewShell->InsertNameList();
+ break;
+ case BTN_PASTE_NAME:
+ {
+ ScInputHandler* pHdl = pScMod->GetInputHdl( pTabViewShell );
+ if (pHdl)
+ {
+ // "=" in KeyEvent, switches to input-mode
+ (void)pScMod->InputKeyEvent( KeyEvent('=', vcl::KeyCode()) );
+
+ std::vector<OUString> aNames = pDlg->GetSelectedNames();
+ if (!aNames.empty())
+ {
+ OUStringBuffer aBuffer;
+ for (const auto& rName : aNames)
+ {
+ aBuffer.append(rName).append(' ');
+ }
+ pHdl->InsertFunction( aBuffer.makeStringAndClear(), false ); // without "()"
+ }
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case SID_RANGE_NOTETEXT:
+ if (pReqArgs)
+ {
+ const SfxStringItem& rTextItem = static_cast<const SfxStringItem&>(pReqArgs->Get( SID_RANGE_NOTETEXT ));
+
+ // always cursor position
+ ScAddress aPos( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ pTabViewShell->SetNoteText( aPos, rTextItem.GetValue() );
+ rReq.Done();
+ }
+ break;
+
+ case SID_INSERT_POSTIT:
+ case SID_EDIT_POSTIT:
+ {
+ const SvxPostItTextItem* pTextItem;
+ if ( pReqArgs && (pTextItem = pReqArgs->GetItemIfSet( SID_ATTR_POSTIT_TEXT )) )
+ {
+ OUString aCellId;
+ // SID_ATTR_POSTIT_ID only argument for SID_EDIT_POSTIT
+ if (const SvxPostItIdItem* pCellId = pReqArgs->GetItemIfSet( SID_ATTR_POSTIT_ID ))
+ aCellId = pCellId->GetValue();
+
+ const SvxPostItAuthorItem* pAuthorItem = pReqArgs->GetItem( SID_ATTR_POSTIT_AUTHOR );
+ const SvxPostItDateItem* pDateItem = pReqArgs->GetItem( SID_ATTR_POSTIT_DATE );
+
+ if (!aCellId.isEmpty())
+ {
+ SetTabNoAndCursor( GetViewData(), aCellId );
+ }
+
+ ScAddress aPos( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ pTabViewShell->ReplaceNote( aPos, pTextItem->GetValue(),
+ pAuthorItem ? &pAuthorItem->GetValue() : nullptr,
+ pDateItem ? &pDateItem->GetValue() : nullptr );
+ }
+ else if (!comphelper::LibreOfficeKit::isActive() || comphelper::LibreOfficeKit::isTiledAnnotations())
+ {
+ pTabViewShell->EditNote(); // note object to edit
+ }
+ rReq.Done();
+ }
+ break;
+
+ case FID_NOTE_VISIBLE:
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScAddress aPos( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ if( ScPostIt* pNote = rDoc.GetNote(aPos) )
+ {
+ bool bShow;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && (pReqArgs->GetItemState( FID_NOTE_VISIBLE, true, &pItem ) == SfxItemState::SET) )
+ bShow = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ else
+ bShow = !pNote->IsCaptionShown();
+
+ pTabViewShell->ShowNote( bShow );
+
+ if (!pReqArgs)
+ rReq.AppendItem( SfxBoolItem( FID_NOTE_VISIBLE, bShow ) );
+
+ rReq.Done();
+ rBindings.Invalidate( FID_NOTE_VISIBLE );
+ }
+ else
+ rReq.Ignore();
+ }
+ break;
+
+ case FID_HIDE_NOTE:
+ case FID_SHOW_NOTE:
+ {
+ bool bShowNote = nSlot == FID_SHOW_NOTE;
+ ScViewData& rData = GetViewData();
+ ScDocument& rDoc = rData.GetDocument();
+ ScMarkData& rMark = rData.GetMarkData();
+
+ if (!rMark.IsMarked() && !rMark.IsMultiMarked())
+ {
+ // Check current cell
+ ScAddress aPos( rData.GetCurX(), rData.GetCurY(), rData.GetTabNo() );
+ if( rDoc.GetNote(aPos) )
+ {
+ rData.GetDocShell()->GetDocFunc().ShowNote( aPos, bShowNote );
+ }
+ }
+ else
+ {
+ // Check selection range
+ bool bDone = false;
+ ScRangeListRef aRangesRef;
+ rData.GetMultiArea(aRangesRef);
+ const ScRangeList aRanges = *aRangesRef;
+
+ OUString aUndo = ScResId( bShowNote ? STR_UNDO_SHOWNOTE : STR_UNDO_HIDENOTE );
+ rData.GetDocShell()->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, rData.GetViewShell()->GetViewShellId() );
+
+ for (auto const& rTab : rMark.GetSelectedTabs())
+ {
+ // get notes
+ std::vector<sc::NoteEntry> aNotes;
+ rDoc.GetAllNoteEntries(rTab, aNotes);
+
+ for (const sc::NoteEntry& rNote : aNotes)
+ {
+ // check if note is in our selection range
+ const ScAddress& rAdr = rNote.maPos;
+ const ScRange* rRange = aRanges.Find(rAdr);
+ if (! rRange)
+ continue;
+
+ // check if cell is editable
+ const SCTAB nRangeTab = rRange->aStart.Tab();
+ if (rDoc.IsBlockEditable( nRangeTab, rAdr.Col(), rAdr.Row(), rAdr.Col(), rAdr.Row() ))
+ {
+ rData.GetDocShell()->GetDocFunc().ShowNote( rAdr, bShowNote );
+ bDone = true;
+ }
+ }
+ }
+
+ rData.GetDocShell()->GetUndoManager()->LeaveListAction();
+
+ if ( bDone )
+ {
+ rReq.Done();
+ rBindings.Invalidate( nSlot );
+ }
+ else
+ rReq.Ignore();
+ }
+
+ }
+ break;
+
+ case FID_SHOW_ALL_NOTES:
+ case FID_HIDE_ALL_NOTES:
+ {
+ bool bShowNote = nSlot == FID_SHOW_ALL_NOTES;
+ ScViewData& rData = GetViewData();
+ ScMarkData& rMark = rData.GetMarkData();
+ ScDocument& rDoc = rData.GetDocument();
+ std::vector<sc::NoteEntry> aNotes;
+
+ OUString aUndo = ScResId( bShowNote ? STR_UNDO_SHOWALLNOTES : STR_UNDO_HIDEALLNOTES );
+ rData.GetDocShell()->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, rData.GetViewShell()->GetViewShellId() );
+
+ for (auto const& rTab : rMark.GetSelectedTabs())
+ {
+ rDoc.GetAllNoteEntries(rTab, aNotes);
+ }
+
+ for (const sc::NoteEntry& rNote : aNotes)
+ {
+ const ScAddress& rAdr = rNote.maPos;
+ rData.GetDocShell()->GetDocFunc().ShowNote( rAdr, bShowNote );
+ }
+
+ rData.GetDocShell()->GetUndoManager()->LeaveListAction();
+ }
+ break;
+
+ case SID_TOGGLE_NOTES:
+ {
+ ScViewData& rData = GetViewData();
+ ScMarkData& rMark = rData.GetMarkData();
+ ScDocument& rDoc = rData.GetDocument();
+ ScRangeList aRanges;
+ std::vector<sc::NoteEntry> aNotes;
+
+ for (auto const& rTab : rMark.GetSelectedTabs())
+ aRanges.push_back(ScRange(0,0,rTab,rDoc.MaxCol(),rDoc.MaxRow(),rTab));
+
+ CommentCaptionState eState = rDoc.GetAllNoteCaptionsState( aRanges );
+ rDoc.GetNotesInRange(aRanges, aNotes);
+ bool bShowNote = (eState == ALLHIDDEN || eState == MIXED);
+
+ OUString aUndo = ScResId( bShowNote ? STR_UNDO_SHOWALLNOTES : STR_UNDO_HIDEALLNOTES );
+ rData.GetDocShell()->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, rData.GetViewShell()->GetViewShellId() );
+
+ for(const auto& rNote : aNotes)
+ {
+ const ScAddress& rAdr = rNote.maPos;
+ rData.GetDocShell()->GetDocFunc().ShowNote( rAdr, bShowNote );
+ }
+
+ rData.GetDocShell()->GetUndoManager()->LeaveListAction();
+
+ if (!pReqArgs)
+ rReq.AppendItem( SfxBoolItem( SID_TOGGLE_NOTES, bShowNote ) );
+
+ rReq.Done();
+ rBindings.Invalidate( SID_TOGGLE_NOTES );
+ }
+ break;
+
+ case SID_DELETE_NOTE:
+ {
+ const SvxPostItIdItem* pIdItem;
+ // If Id is mentioned, select the appropriate cell first
+ if ( pReqArgs && (pIdItem = pReqArgs->GetItemIfSet( SID_ATTR_POSTIT_ID )) )
+ {
+ const OUString& aCellId = pIdItem->GetValue();
+ if (!aCellId.isEmpty())
+ {
+ SetTabNoAndCursor( GetViewData(), aCellId );
+ }
+ }
+
+ pTabViewShell->DeleteContents( InsertDeleteFlags::NOTE ); // delete all notes in selection
+ rReq.Done();
+ }
+ break;
+
+ case FID_DELETE_ALL_NOTES:
+ {
+ ScViewData& rData = GetViewData();
+ ScMarkData& rMark = rData.GetMarkData();
+ ScDocument& rDoc = rData.GetDocument();
+ ScMarkData aNewMark(rDoc.GetSheetLimits());
+ ScRangeList aRangeList;
+
+ for (auto const& rTab : rMark.GetSelectedTabs())
+ {
+ aRangeList.push_back(ScRange(0,0,rTab,rDoc.MaxCol(),rDoc.MaxRow(),rTab));
+ }
+
+ aNewMark.MarkFromRangeList( aRangeList, true );
+ rData.GetDocShell()->GetDocFunc().DeleteContents(aNewMark, InsertDeleteFlags::NOTE, true, false );
+ }
+ break;
+
+ case SID_CHARMAP:
+ if( pReqArgs != nullptr )
+ {
+ OUString aChars, aFontName;
+ const SfxItemSet *pArgs = rReq.GetArgs();
+ const SfxPoolItem* pItem = nullptr;
+ if ( pArgs )
+ pArgs->GetItemState(SID_CHARMAP, false, &pItem);
+ if ( pItem )
+ {
+ const SfxStringItem* pStringItem = dynamic_cast<const SfxStringItem*>( pItem );
+ if ( pStringItem )
+ aChars = pStringItem->GetValue();
+ const SfxStringItem* pFontItem =
+ pArgs->GetItemIfSet( SID_ATTR_SPECIALCHAR, false);
+ if ( pFontItem )
+ aFontName = pFontItem->GetValue();
+ }
+
+ if ( !aChars.isEmpty() )
+ {
+ vcl::Font aFont;
+ pTabViewShell->GetSelectionPattern()->GetFont( aFont, SC_AUTOCOL_BLACK, nullptr, nullptr, nullptr,
+ pTabViewShell->GetSelectionScriptType() );
+ if ( !aFontName.isEmpty() )
+ aFont = vcl::Font( aFontName, Size(1,1) );
+ pTabViewShell->InsertSpecialChar( aChars, aFont );
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+ }
+ }
+ else
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+
+ // font color doesn't matter here
+ vcl::Font aCurFont;
+ pTabViewShell->GetSelectionPattern()->GetFont( aCurFont, SC_AUTOCOL_BLACK, nullptr, nullptr, nullptr,
+ pTabViewShell->GetSelectionScriptType() );
+
+ SfxAllItemSet aSet( GetPool() );
+ aSet.Put( SfxBoolItem( FN_PARAM_1, false ) );
+ aSet.Put( SvxFontItem( aCurFont.GetFamilyType(), aCurFont.GetFamilyName(), aCurFont.GetStyleName(), aCurFont.GetPitch(), aCurFont.GetCharSet(), GetPool().GetWhich(SID_ATTR_CHAR_FONT) ) );
+ SfxViewFrame* pViewFrame = pTabViewShell->GetViewFrame();
+ auto xFrame = pViewFrame->GetFrame().GetFrameInterface();
+ ScopedVclPtr<SfxAbstractDialog> pDlg(pFact->CreateCharMapDialog(pTabViewShell->GetFrameWeld(), aSet, xFrame));
+ pDlg->Execute();
+ }
+ break;
+
+ case SID_SELECT_SCENARIO:
+ {
+ // Testing
+
+ if ( pReqArgs )
+ {
+ const SfxStringItem& rItem
+ = static_cast<const SfxStringItem&>(pReqArgs->Get(SID_SELECT_SCENARIO));
+ pTabViewShell->UseScenario(rItem.GetValue());
+ //! why should the return value be valid?!?!
+ rReq.SetReturnValue(SfxStringItem(SID_SELECT_SCENARIO, rItem.GetValue()));
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_HYPERLINK_SETLINK:
+ if( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ if( pReqArgs->HasItem( SID_HYPERLINK_SETLINK, &pItem ) )
+ {
+ const SvxHyperlinkItem* pHyper = static_cast<const SvxHyperlinkItem*>(pItem);
+ const OUString& rName = pHyper->GetName();
+ const OUString& rURL = pHyper->GetURL();
+ const OUString& rTarget = pHyper->GetTargetFrame();
+ sal_uInt16 nType = static_cast<sal_uInt16>(pHyper->GetInsertMode());
+
+ pTabViewShell->InsertURL( rName, rURL, rTarget, nType );
+ rReq.Done();
+ }
+ else
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_OPENDLG_CONDFRMT_MANAGER:
+ case SID_OPENDLG_CURRENTCONDFRMT_MANAGER:
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScViewData& rData = GetViewData();
+ ScDocument& rDoc = rData.GetDocument();
+
+ if (rDoc.IsTabProtected(rData.GetTabNo()))
+ {
+ pTabViewShell->ErrorMessage( STR_ERR_CONDFORMAT_PROTECTED );
+ break;
+ }
+
+ ScAddress aPos(rData.GetCurX(), rData.GetCurY(), rData.GetTabNo());
+
+ ScConditionalFormatList* pList = nullptr;
+
+ const ScCondFormatDlgItem* pDlgItem = nullptr;
+ auto itemsRange = pTabViewShell->GetPool().GetItemSurrogates(SCITEM_CONDFORMATDLGDATA);
+ if (itemsRange.begin() != itemsRange.end())
+ {
+ pDlgItem= static_cast<const ScCondFormatDlgItem*>(*itemsRange.begin());
+ pList = const_cast<ScCondFormatDlgItem*>(pDlgItem)->GetConditionalFormatList();
+ }
+
+ if (!pList)
+ pList = rDoc.GetCondFormList( aPos.Tab() );
+
+ VclPtr<AbstractScCondFormatManagerDlg> pDlg(pFact->CreateScCondFormatMgrDlg(
+ pTabViewShell->GetFrameWeld(), rDoc, pList));
+
+ if (pDlgItem)
+ pDlg->SetModified();
+
+ pDlg->StartExecuteAsync([this, pDlg, &rData, pTabViewShell, pDlgItem, aPos](sal_Int32 nRet){
+ std::unique_ptr<ScConditionalFormatList> pCondFormatList = pDlg->GetConditionalFormatList();
+ if(nRet == RET_OK && pDlg->CondFormatsChanged())
+ {
+ rData.GetDocShell()->GetDocFunc().SetConditionalFormatList(pCondFormatList.release(), aPos.Tab());
+ }
+ else if(nRet == DLG_RET_ADD)
+ {
+ // Put the xml string parameter to initialize the
+ // Conditional Format Dialog. ( add new )
+ pTabViewShell->GetPool().Put(ScCondFormatDlgItem(
+ std::shared_ptr<ScConditionalFormatList>(pCondFormatList.release()), -1, true));
+ // Queue message to open Conditional Format Dialog
+ GetViewData().GetDispatcher().Execute( SID_OPENDLG_CONDFRMT, SfxCallMode::ASYNCHRON );
+ }
+ else if (nRet == DLG_RET_EDIT)
+ {
+ ScConditionalFormat* pFormat = pDlg->GetCondFormatSelected();
+ sal_Int32 nIndex = pFormat ? pFormat->GetKey() : -1;
+ // Put the xml string parameter to initialize the
+ // Conditional Format Dialog. ( edit selected conditional format )
+ pTabViewShell->GetPool().Put(ScCondFormatDlgItem(
+ std::shared_ptr<ScConditionalFormatList>(pCondFormatList.release()), nIndex, true));
+
+ // Queue message to open Conditional Format Dialog
+ GetViewData().GetDispatcher().Execute( SID_OPENDLG_CONDFRMT, SfxCallMode::ASYNCHRON );
+ }
+ else
+ pCondFormatList.reset();
+
+ if (pDlgItem)
+ pTabViewShell->GetPool().Remove(*pDlgItem);
+
+ pDlg->disposeOnce();
+ });
+ }
+ break;
+
+ case SID_EXTERNAL_SOURCE:
+ {
+ const SfxStringItem* pFile = rReq.GetArg<SfxStringItem>(SID_FILE_NAME);
+ const SfxStringItem* pSource = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if ( pFile && pSource )
+ {
+ OUString aFile;
+ OUString aFilter;
+ OUString aOptions;
+ OUString aSource;
+ sal_Int32 nRefreshDelaySeconds=0;
+
+ aFile = pFile->GetValue();
+ aSource = pSource->GetValue();
+ const SfxStringItem* pFilter = rReq.GetArg<SfxStringItem>(SID_FILTER_NAME);
+ if ( pFilter )
+ aFilter = pFilter->GetValue();
+ const SfxStringItem* pOptions = rReq.GetArg<SfxStringItem>(SID_FILE_FILTEROPTIONS);
+ if ( pOptions )
+ aOptions = pOptions->GetValue();
+ const SfxUInt32Item* pRefresh = rReq.GetArg<SfxUInt32Item>(FN_PARAM_2);
+ if ( pRefresh )
+ nRefreshDelaySeconds = pRefresh->GetValue();
+
+ ExecuteExternalSource( aFile, aFilter, aOptions, aSource, nRefreshDelaySeconds, rReq );
+ }
+ else
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ pImpl->m_pLinkedDlg.disposeAndClear();
+ pImpl->m_pLinkedDlg =
+ pFact->CreateScLinkedAreaDlg(pTabViewShell->GetFrameWeld());
+ delete pImpl->m_pRequest;
+ pImpl->m_pRequest = new SfxRequest( rReq );
+ OUString sFile, sFilter, sOptions, sSource;
+ sal_Int32 nRefreshDelaySeconds = 0;
+ if (pImpl->m_pLinkedDlg->Execute() == RET_OK)
+ {
+ sFile = pImpl->m_pLinkedDlg->GetURL();
+ sFilter = pImpl->m_pLinkedDlg->GetFilter();
+ sOptions = pImpl->m_pLinkedDlg->GetOptions();
+ sSource = pImpl->m_pLinkedDlg->GetSource();
+ nRefreshDelaySeconds = pImpl->m_pLinkedDlg->GetRefreshDelaySeconds();
+ if ( !sFile.isEmpty() )
+ pImpl->m_pRequest->AppendItem( SfxStringItem( SID_FILE_NAME, sFile ) );
+ if ( !sFilter.isEmpty() )
+ pImpl->m_pRequest->AppendItem( SfxStringItem( SID_FILTER_NAME, sFilter ) );
+ if ( !sOptions.isEmpty() )
+ pImpl->m_pRequest->AppendItem( SfxStringItem( SID_FILE_FILTEROPTIONS, sOptions ) );
+ if ( !sSource.isEmpty() )
+ pImpl->m_pRequest->AppendItem( SfxStringItem( FN_PARAM_1, sSource ) );
+ if ( nRefreshDelaySeconds )
+ pImpl->m_pRequest->AppendItem( SfxUInt32Item( FN_PARAM_2, nRefreshDelaySeconds ) );
+ }
+
+ ExecuteExternalSource( sFile, sFilter, sOptions, sSource, nRefreshDelaySeconds, *(pImpl->m_pRequest) );
+ }
+ }
+ break;
+
+ case SID_AUTO_SUM:
+ {
+ const SfxItemSet *pArgs = rReq.GetArgs();
+ const OUString sFunction = pArgs ?
+ static_cast<const SfxStringItem&>( pArgs->Get( SID_AUTO_SUM ) ).GetValue()
+ : "";
+
+ OpCode eFunction = ocSum;
+ if (sFunction == "average")
+ eFunction = ocAverage;
+ else if (sFunction == "count")
+ eFunction = ocCount;
+ else if (sFunction == "min")
+ eFunction = ocMin;
+ if (sFunction == "max")
+ eFunction = ocMax;
+
+ bool bSubTotal = false;
+ bool bRangeFinder = false;
+ const OUString aFormula = pTabViewShell->DoAutoSum( bRangeFinder, bSubTotal , eFunction );
+ if ( !aFormula.isEmpty() )
+ {
+ const sal_Int32 nPar = aFormula.indexOf( '(' );
+ const sal_Int32 nLen = aFormula.getLength();
+ ScInputHandler* pHdl = pScMod->GetInputHdl( pTabViewShell );
+
+ if ( pHdl && nPar != -1 )
+ {
+ if ( !pScMod->IsEditMode() )
+ {
+ pScMod->SetInputMode( SC_INPUT_TABLE );
+ }
+
+ EditView *pEditView=pHdl->GetActiveView();
+ if ( pEditView )
+ {
+ ESelection aTextSel = pEditView->GetSelection();
+ aTextSel.nStartPos = 0;
+ aTextSel.nEndPos = EE_TEXTPOS_ALL;
+ pHdl->DataChanging();
+ pEditView->SetSelection(aTextSel);
+ pEditView->InsertText(aFormula);
+ pEditView->SetSelection( bRangeFinder ? ESelection( 0, nPar + ( bSubTotal ? 3 : 1 ), 0, nLen - 1 ) : ESelection( 0, nLen - 1, 0, nLen - 1 ) );
+ pHdl->DataChanged();
+
+ if ( bRangeFinder )
+ {
+ pHdl->InitRangeFinder( aFormula );
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case SID_SELECT_UNPROTECTED_CELLS:
+ {
+ ScViewData& rData = GetViewData();
+ SCTAB aTab = rData.GetTabNo();
+ ScMarkData& rMark = rData.GetMarkData();
+ ScDocument& rDoc = rData.GetDocument();
+ ScRangeList rRangeList;
+
+ rDoc.GetUnprotectedCells(rRangeList, aTab);
+ rMark.MarkFromRangeList(rRangeList, true);
+ pTabViewShell->SetMarkData(rMark);
+ }
+ break;
+
+ case SID_SELECT_VISIBLE_ROWS:
+ {
+ ScViewData& rData = GetViewData();
+ ScMarkData& rMark = rData.GetMarkData();
+ ScDocument& rDoc = rData.GetDocument();
+
+ rMark.MarkToMulti();
+
+ const ScRange& aMultiArea = rMark.GetMultiMarkArea();
+ SCCOL nStartCol = aMultiArea.aStart.Col();
+ SCROW nStartRow = aMultiArea.aStart.Row();
+ SCCOL nEndCol = aMultiArea.aEnd.Col();
+ SCROW nEndRow = aMultiArea.aEnd.Row();
+
+ bool bChanged = false;
+ for (const SCTAB& nTab : rMark)
+ {
+ for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
+ {
+ SCROW nLastRow = nRow;
+ if (rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow))
+ {
+ rMark.SetMultiMarkArea(
+ ScRange(nStartCol, nRow, nTab, nEndCol, nLastRow, nTab), false);
+ bChanged = true;
+ nRow = nLastRow;
+ }
+ }
+ }
+
+ if (bChanged && !rMark.HasAnyMultiMarks())
+ rMark.ResetMark();
+
+ rMark.MarkToSimple();
+
+ pTabViewShell->SelectionChanged();
+ }
+ break;
+
+ case SID_SELECT_VISIBLE_COLUMNS:
+ {
+ ScViewData& rData = GetViewData();
+ ScMarkData& rMark = rData.GetMarkData();
+ ScDocument& rDoc = rData.GetDocument();
+
+ rMark.MarkToMulti();
+
+ const ScRange& aMultiArea = rMark.GetMultiMarkArea();
+ SCCOL nStartCol = aMultiArea.aStart.Col();
+ SCROW nStartRow = aMultiArea.aStart.Row();
+ SCCOL nEndCol = aMultiArea.aEnd.Col();
+ SCROW nEndRow = aMultiArea.aEnd.Row();
+
+ bool bChanged = false;
+ for (const SCTAB& nTab : rMark)
+ {
+ for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
+ {
+ SCCOL nLastCol = nCol;
+ if (rDoc.ColHidden(nCol, nTab, nullptr, &nLastCol))
+ {
+ rMark.SetMultiMarkArea(
+ ScRange(nCol, nStartRow, nTab, nLastCol, nEndRow, nTab), false);
+ bChanged = true;
+ nCol = nLastCol;
+ }
+ }
+ }
+
+ if (bChanged && !rMark.HasAnyMultiMarks())
+ rMark.ResetMark();
+
+ rMark.MarkToSimple();
+
+ pTabViewShell->SelectionChanged();
+ }
+ break;
+
+ case SID_CURRENT_FORMULA_RANGE:
+ {
+ const SfxInt32Item* param1 = rReq.GetArg<SfxInt32Item>(FN_PARAM_1);
+ SCCOL colStart = param1 ? param1->GetValue() : 0;
+
+ const SfxInt32Item* param2 = rReq.GetArg<SfxInt32Item>(FN_PARAM_2);
+ SCROW rowStart = param2 ? param2->GetValue() : 0;
+
+ const SfxInt32Item* param3 = rReq.GetArg<SfxInt32Item>(FN_PARAM_3);
+ SCCOL colEnd = param3 ? param3->GetValue() : 0;
+
+ const SfxInt32Item* param4 = rReq.GetArg<SfxInt32Item>(FN_PARAM_4);
+ SCROW rowEnd = param4 ? param4->GetValue() : 0;
+
+ const SfxInt32Item* param5 = rReq.GetArg<SfxInt32Item>(FN_PARAM_5);
+ SCROW table = param5 ? param5->GetValue() : 0;
+
+ ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
+
+ if (param3 && param4 && pInputHdl)
+ {
+ ScViewData& rData = pTabViewShell->GetViewData();
+ ScTabView* pTabView = rData.GetView();
+
+ if (param1 && param2)
+ rData.SetRefStart(colStart, rowStart, table);
+
+ pTabView->UpdateRef( colEnd, rowEnd, table ); // setup the end & refresh formula
+
+ ScRange aRef(
+ colStart, rowStart, rData.GetRefStartZ(),
+ colEnd, rowEnd, rData.GetRefEndZ() );
+ SC_MOD()->SetReference( aRef, rData.GetDocument(), &rData.GetMarkData() );
+
+ pInputHdl->UpdateLokReferenceMarks();
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL("incorrect slot in ExecuteEdit");
+ break;
+ }
+}
+
+void ScCellShell::ExecuteTrans( SfxRequest& rReq )
+{
+ TransliterationFlags nType = ScViewUtil::GetTransliterationType( rReq.GetSlot() );
+ if ( nType != TransliterationFlags::NONE )
+ {
+ GetViewData().GetView()->TransliterateText( nType );
+ rReq.Done();
+ }
+}
+
+void ScCellShell::ExecuteRotateTrans( const SfxRequest& rReq )
+{
+ if( rReq.GetSlot() == SID_TRANSLITERATE_ROTATE_CASE )
+ GetViewData().GetView()->TransliterateText( m_aRotateCase.getNextMode() );
+}
+
+void ScCellShell::ExecuteExternalSource(
+ const OUString& _rFile, const OUString& _rFilter, const OUString& _rOptions,
+ const OUString& _rSource, sal_Int32 _nRefreshDelaySeconds, SfxRequest& _rRequest )
+{
+ if ( !_rFile.isEmpty() && !_rSource.isEmpty() ) // filter may be empty
+ {
+ ScRange aLinkRange;
+ bool bMove = false;
+
+ ScViewData& rData = GetViewData();
+ ScMarkData& rMark = rData.GetMarkData();
+ rMark.MarkToSimple();
+ if ( rMark.IsMarked() )
+ {
+ aLinkRange = rMark.GetMarkArea();
+ bMove = true; // insert/delete cells to fit range
+ }
+ else
+ aLinkRange = ScRange( rData.GetCurX(), rData.GetCurY(), rData.GetTabNo() );
+
+ rData.GetDocFunc().InsertAreaLink( _rFile, _rFilter, _rOptions, _rSource,
+ aLinkRange, _nRefreshDelaySeconds, bMove, false );
+ _rRequest.Done();
+ }
+ else
+ _rRequest.Ignore();
+}
+
+namespace {
+
+bool isDPSourceValid(const ScDPObject& rDPObj)
+{
+ if (rDPObj.IsImportData())
+ {
+ // If the data type is database, check if the database is still valid.
+ const ScImportSourceDesc* pDesc = rDPObj.GetImportSourceDesc();
+ if (!pDesc)
+ return false;
+
+ const ScDPSaveData* pSaveData = rDPObj.GetSaveData();
+ const ScDPDimensionSaveData* pDimData = nullptr;
+ if (pSaveData)
+ pDimData = pSaveData->GetExistingDimensionData();
+
+ const ScDPCache* pCache = pDesc->CreateCache(pDimData);
+ if (!pCache)
+ // cache creation failed, probably due to invalid connection.
+ return false;
+ }
+ return true;
+}
+
+void RunPivotLayoutDialog(ScModule* pScMod,
+ ScTabViewShell* pTabViewShell,
+ std::unique_ptr<ScDPObject>& pNewDPObject)
+{
+ bool bHadNewDPObject = pNewDPObject != nullptr;
+ pTabViewShell->SetDialogDPObject( std::move(pNewDPObject) );
+ if ( bHadNewDPObject )
+ {
+ // start layout dialog
+
+ sal_uInt16 nId = ScPivotLayoutWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+}
+
+void SetupRangeForPivotTableDialog(const ScRange& rRange,
+ ScAddress& rDestPos,
+ ScDocument* pDoc,
+ TranslateId pSrcErrorId,
+ std::unique_ptr<ScDPObject>& pNewDPObject)
+{
+ ScSheetSourceDesc aShtDesc(pDoc);
+ aShtDesc.SetSourceRange(rRange);
+ pSrcErrorId = aShtDesc.CheckSourceRange();
+ if (!pSrcErrorId)
+ {
+ pNewDPObject.reset(new ScDPObject(pDoc));
+ pNewDPObject->SetSheetDesc( aShtDesc );
+ }
+
+ // output below source data
+ if ( rRange.aEnd.Row()+2 <= pDoc->MaxRow() - 4 )
+ rDestPos = ScAddress( rRange.aStart.Col(),
+ rRange.aEnd.Row()+2,
+ rRange.aStart.Tab() );
+}
+
+void ErrorOrRunPivotLayoutDialog(TranslateId pSrcErrorId,
+ const ScAddress& rDestPos,
+ ScModule* pScMod,
+ ScTabViewShell* pTabViewShell,
+ std::unique_ptr<ScDPObject>& pNewDPObject)
+{
+ if (pSrcErrorId)
+ {
+ // Error occurred during data creation. Launch an error and bail out.
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pTabViewShell->GetFrameWeld(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(pSrcErrorId)));
+ xInfoBox->run();
+ return;
+ }
+
+ if ( pNewDPObject )
+ pNewDPObject->SetOutRange( rDestPos );
+
+ RunPivotLayoutDialog(pScMod, pTabViewShell, pNewDPObject);
+}
+
+}
+
+void ScCellShell::ExecuteDataPilotDialog()
+{
+ ScModule* pScMod = SC_MOD();
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ ScViewData& rData = GetViewData();
+ ScDocument& rDoc = rData.GetDocument();
+
+ // ScPivot is no longer used...
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor(
+ rData.GetCurX(), rData.GetCurY(),
+ rData.GetTabNo() );
+ if ( pDPObj ) // on an existing table?
+ {
+ std::unique_ptr<ScDPObject> pNewDPObject;
+
+ if (isDPSourceValid(*pDPObj))
+ pNewDPObject.reset(new ScDPObject(*pDPObj));
+
+ RunPivotLayoutDialog(pScMod, pTabViewShell, pNewDPObject);
+ }
+ else // create new table
+ {
+ // select database range or data
+ pTabViewShell->GetDBData( true, SC_DB_OLD );
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
+ pTabViewShell->MarkDataArea( false );
+
+ // output to cursor position for non-sheet data
+ ScAddress aDestPos( rData.GetCurX(), rData.GetCurY(),
+ rData.GetTabNo() );
+
+ // first select type of source data
+
+ bool bEnableExt = ScDPObject::HasRegisteredSources();
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ VclPtr<AbstractScDataPilotSourceTypeDlg> pTypeDlg(
+ pFact->CreateScDataPilotSourceTypeDlg(
+ pTabViewShell->GetFrameWeld(), bEnableExt));
+
+ // Populate named ranges (if any).
+ ScRangeName* pRangeName = rDoc.GetRangeName();
+ if (pRangeName)
+ {
+ ScRangeName::const_iterator itr = pRangeName->begin(), itrEnd = pRangeName->end();
+ for (; itr != itrEnd; ++itr)
+ pTypeDlg->AppendNamedRange(itr->second->GetName());
+ }
+
+ pTypeDlg->StartExecuteAsync([this, pTypeDlg, pTabViewShell,
+ pScMod, pFact, &rDoc, &rMark, aDestPos](int nResult) mutable {
+
+ if (nResult == RET_OK )
+ {
+ if ( pTypeDlg->IsExternal() )
+ {
+ std::vector<OUString> aSources = ScDPObject::GetRegisteredSources();
+ VclPtr<AbstractScDataPilotServiceDlg> pServDlg(
+ pFact->CreateScDataPilotServiceDlg(
+ pTabViewShell->GetFrameWeld(), aSources));
+
+ pServDlg->StartExecuteAsync([pServDlg, pScMod, pTabViewShell,
+ aDestPos, &rDoc](int nResult2) mutable {
+ if ( nResult2 == RET_OK )
+ {
+ ScDPServiceDesc aServDesc(
+ pServDlg->GetServiceName(),
+ pServDlg->GetParSource(),
+ pServDlg->GetParName(),
+ pServDlg->GetParUser(),
+ pServDlg->GetParPass() );
+ std::unique_ptr<ScDPObject> pNewDPObject(new ScDPObject(&rDoc));
+ pNewDPObject->SetServiceData( aServDesc );
+ pNewDPObject->SetOutRange(aDestPos);
+
+ RunPivotLayoutDialog(pScMod, pTabViewShell, pNewDPObject);
+ }
+
+ pServDlg->disposeOnce();
+ });
+ }
+ else if ( pTypeDlg->IsDatabase() )
+ {
+ assert(pFact && "ScAbstractFactory create fail!");
+ VclPtr<AbstractScDataPilotDatabaseDlg> pDataDlg(
+ pFact->CreateScDataPilotDatabaseDlg(pTabViewShell->GetFrameWeld()));
+ assert(pDataDlg && "Dialog create fail!");
+
+ pDataDlg->StartExecuteAsync([pDataDlg, pScMod, pTabViewShell,
+ aDestPos, &rDoc](int nResult2) mutable {
+ if ( nResult2 == RET_OK )
+ {
+ ScImportSourceDesc aImpDesc(&rDoc);
+ pDataDlg->GetValues( aImpDesc );
+ std::unique_ptr<ScDPObject> pNewDPObject(new ScDPObject(&rDoc));
+ pNewDPObject->SetImportDesc( aImpDesc );
+ pNewDPObject->SetOutRange(aDestPos);
+
+ RunPivotLayoutDialog(pScMod, pTabViewShell, pNewDPObject);
+ }
+
+ pDataDlg->disposeOnce();
+ });
+ }
+ else
+ {
+ TranslateId pSrcErrorId;
+
+ if (pTypeDlg->IsNamedRange())
+ {
+ std::unique_ptr<ScDPObject> pNewDPObject;
+ OUString aName = pTypeDlg->GetSelectedNamedRange();
+ ScSheetSourceDesc aShtDesc(&rDoc);
+ aShtDesc.SetRangeName(aName);
+ pSrcErrorId = aShtDesc.CheckSourceRange();
+ if (!pSrcErrorId)
+ {
+ pNewDPObject.reset(new ScDPObject(&rDoc));
+ pNewDPObject->SetSheetDesc(aShtDesc);
+ }
+
+ ErrorOrRunPivotLayoutDialog(pSrcErrorId, aDestPos, pScMod, pTabViewShell, pNewDPObject);
+ }
+ else // selection
+ {
+ //! use database ranges (select before type dialog?)
+ ScRange aRange;
+ ScMarkType eType = GetViewData().GetSimpleArea(aRange);
+ if ( (eType & SC_MARK_SIMPLE) == SC_MARK_SIMPLE )
+ {
+ ScDocument* pDoc = &rDoc;
+
+ // Shrink the range to the data area.
+ SCCOL nStartCol = aRange.aStart.Col(), nEndCol = aRange.aEnd.Col();
+ SCROW nStartRow = aRange.aStart.Row(), nEndRow = aRange.aEnd.Row();
+ if (rDoc.ShrinkToDataArea(aRange.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow))
+ {
+ aRange.aStart.SetCol(nStartCol);
+ aRange.aStart.SetRow(nStartRow);
+ aRange.aEnd.SetCol(nEndCol);
+ aRange.aEnd.SetRow(nEndRow);
+ rMark.SetMarkArea(aRange);
+ pTabViewShell->MarkRange(aRange);
+ }
+
+ if ( rDoc.HasSubTotalCells( aRange ) )
+ {
+ // confirm selection if it contains SubTotal cells
+ std::shared_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pTabViewShell->GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_DATAPILOT_SUBTOTAL)));
+ xQueryBox->set_default_response(RET_YES);
+ xQueryBox->runAsync(xQueryBox, [aRange, pDoc, pTypeDlg, aDestPos,
+ pScMod, pTabViewShell, pSrcErrorId] (int nResult2) mutable {
+ if (nResult2 == RET_NO)
+ return;
+
+ std::unique_ptr<ScDPObject> pNewDPObject;
+ SetupRangeForPivotTableDialog(aRange, aDestPos, pDoc, pSrcErrorId, pNewDPObject);
+ ErrorOrRunPivotLayoutDialog(pSrcErrorId, aDestPos, pScMod, pTabViewShell, pNewDPObject);
+ });
+
+ pTypeDlg->disposeOnce();
+ return;
+ }
+
+ std::unique_ptr<ScDPObject> pNewDPObject;
+ SetupRangeForPivotTableDialog(aRange, aDestPos, pDoc, pSrcErrorId, pNewDPObject);
+ ErrorOrRunPivotLayoutDialog(pSrcErrorId, aDestPos, pScMod, pTabViewShell, pNewDPObject);
+ }
+ }
+ }
+ }
+
+ pTypeDlg->disposeOnce();
+ });
+ }
+}
+
+void ScCellShell::ExecuteXMLSourceDialog()
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ if (!pTabViewShell)
+ return;
+
+ ScModule* pScMod = SC_MOD();
+
+ sal_uInt16 nId = ScXMLSourceDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrame = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrame->GetChildWindow(nId);
+ pScMod->SetRefDialog(nId, pWnd == nullptr);
+}
+
+void ScCellShell::ExecuteSubtotals(SfxRequest& rReq)
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if ( pArgs )
+ {
+ pTabViewShell->DoSubTotals( pArgs->Get( SCITEM_SUBTDATA ).
+ GetSubTotalData() );
+ rReq.Done();
+ return;
+ }
+
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg;
+ ScSubTotalParam aSubTotalParam;
+ SfxItemSetFixed<SCITEM_SUBTDATA, SCITEM_SUBTDATA> aArgSet( GetPool() );
+
+ bool bAnonymous;
+
+ // Only get existing named database range.
+ ScDBData* pDBData = pTabViewShell->GetDBData(true, SC_DB_OLD);
+ if (pDBData)
+ bAnonymous = false;
+ else
+ {
+ // No existing DB data at this position. Create an
+ // anonymous DB.
+ bAnonymous = true;
+ pDBData = pTabViewShell->GetAnonymousDBData();
+ ScRange aDataRange;
+ pDBData->GetArea(aDataRange);
+ pTabViewShell->MarkRange(aDataRange, false);
+ }
+
+ pDBData->GetSubTotalParam( aSubTotalParam );
+ aSubTotalParam.bRemoveOnly = false;
+ if (bAnonymous)
+ {
+ // Preset sort formatting along with values and also create formula
+ // cells with "needs formatting". Subtotals on data of different types
+ // doesn't make much sense anyway.
+ aSubTotalParam.bIncludePattern = true;
+ }
+
+ aArgSet.Put( ScSubTotalItem( SCITEM_SUBTDATA, &GetViewData(), &aSubTotalParam ) );
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ pDlg.disposeAndReset(pFact->CreateScSubTotalDlg(pTabViewShell->GetFrameWeld(), aArgSet));
+ pDlg->SetCurPageId("1stgroup");
+
+ short bResult = pDlg->Execute();
+
+ if ( (bResult == RET_OK) || (bResult == SCRET_REMOVE) )
+ {
+ const SfxItemSet* pOutSet = nullptr;
+
+ if ( bResult == RET_OK )
+ {
+ pOutSet = pDlg->GetOutputItemSet();
+ aSubTotalParam =
+ pOutSet->Get( SCITEM_SUBTDATA ).GetSubTotalData();
+ }
+ else // if (bResult == SCRET_REMOVE)
+ {
+ pOutSet = &aArgSet;
+ aSubTotalParam.bRemoveOnly = true;
+ aSubTotalParam.bReplace = true;
+ aArgSet.Put( ScSubTotalItem( SCITEM_SUBTDATA,
+ &GetViewData(),
+ &aSubTotalParam ) );
+ }
+
+ pTabViewShell->DoSubTotals( aSubTotalParam );
+ rReq.Done( *pOutSet );
+ }
+ else
+ GetViewData().GetDocShell()->CancelAutoDBRange();
+}
+
+void ScCellShell::ExecuteFillSingleEdit()
+{
+ ScAddress aCurPos = GetViewData().GetCurPos();
+
+ OUString aInit;
+
+ if (aCurPos.Row() > 0)
+ {
+ // Get the initial text value from the above cell.
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScAddress aPrevPos = aCurPos;
+ aPrevPos.IncRow(-1);
+ ScRefCellValue aCell(rDoc, aPrevPos);
+
+ if (aCell.meType == CELLTYPE_FORMULA)
+ {
+ aInit = "=";
+ const ScTokenArray* pCode = aCell.mpFormula->GetCode();
+ sc::TokenStringContext aCxt(rDoc, rDoc.GetGrammar());
+ aInit += pCode->CreateString(aCxt, aCurPos);
+ }
+ else
+ aInit = aCell.getString(&rDoc);
+ }
+
+ SC_MOD()->SetInputMode(SC_INPUT_TABLE, &aInit);
+}
+
+CellShell_Impl::CellShell_Impl() :
+ m_pRequest( nullptr ) {}
+
+CellShell_Impl::~CellShell_Impl()
+{
+}
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/cellsh2.cxx b/sc/source/ui/view/cellsh2.cxx
new file mode 100644
index 000000000..bc9dc416b
--- /dev/null
+++ b/sc/source/ui/view/cellsh2.cxx
@@ -0,0 +1,1263 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <basic/sberrors.hxx>
+#include <scitems.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/request.hxx>
+#include <basic/sbxcore.hxx>
+#include <svl/whiter.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/stritem.hxx>
+#include <svl/visitem.hxx>
+#include <unotools/moduleoptions.hxx>
+
+#include <com/sun/star/frame/FrameSearchFlag.hpp>
+#include <com/sun/star/sheet/TableValidationVisibility.hpp>
+
+#include <cellsh.hxx>
+#include <dbdata.hxx>
+#include <queryparam.hxx>
+#include <tabvwsh.hxx>
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <scmod.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <uiitems.hxx>
+#include <dbdocfun.hxx>
+#include <reffact.hxx>
+#include <validat.hxx>
+#include <validate.hxx>
+#include <datamapper.hxx>
+
+#include <scui_def.hxx>
+#include <scabstdlg.hxx>
+#include <impex.hxx>
+#include <asciiopt.hxx>
+#include <datastream.hxx>
+#include <datastreamdlg.hxx>
+#include <dataproviderdlg.hxx>
+#include <queryentry.hxx>
+#include <markdata.hxx>
+#include <documentlinkmgr.hxx>
+#include <officecfg/Office/Common.hxx>
+
+#include <o3tl/make_shared.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+
+static bool lcl_GetTextToColumnsRange( const ScViewData& rData, ScRange& rRange, bool bDoEmptyCheckOnly )
+{
+ bool bRet = false;
+ const ScMarkData& rMark = rData.GetMarkData();
+
+ if ( rMark.IsMarked() )
+ {
+ if ( !rMark.IsMultiMarked() )
+ {
+ rRange = rMark.GetMarkArea();
+ if ( rRange.aStart.Col() == rRange.aEnd.Col() )
+ {
+ bRet = true;
+ }
+ }
+ }
+ else
+ {
+ const SCCOL nCol = rData.GetCurX();
+ const SCROW nRow = rData.GetCurY();
+ const SCTAB nTab = rData.GetTabNo();
+ rRange = ScRange( nCol, nRow, nTab, nCol, nRow, nTab );
+ bRet = true;
+ }
+
+ const ScDocument& rDoc = rData.GetDocument();
+
+ if ( bDoEmptyCheckOnly )
+ {
+ if ( bRet && rDoc.IsBlockEmpty( rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(),
+ rRange.aStart.Tab() ) )
+ {
+ bRet = false;
+ }
+ }
+ else if ( bRet )
+ {
+ rRange.PutInOrder();
+ SCCOL nStartCol = rRange.aStart.Col(), nEndCol = rRange.aEnd.Col();
+ SCROW nStartRow = rRange.aStart.Row(), nEndRow = rRange.aEnd.Row();
+ bool bShrunk = false;
+ rDoc.ShrinkToUsedDataArea( bShrunk, rRange.aStart.Tab(), nStartCol, nStartRow,
+ nEndCol, nEndRow, false, false, true );
+ if ( bShrunk )
+ {
+ rRange.aStart.SetRow( nStartRow );
+ rRange.aEnd.SetRow( nEndRow );
+ }
+ }
+
+ return bRet;
+}
+
+static bool lcl_GetSortParam( const ScViewData& rData, const ScSortParam& rSortParam )
+{
+ ScTabViewShell* pTabViewShell = rData.GetViewShell();
+ ScDBData* pDBData = pTabViewShell->GetDBData();
+ ScDocument& rDoc = rData.GetDocument();
+ SCTAB nTab = rData.GetTabNo();
+ ScDirection eFillDir = DIR_TOP;
+ bool bSort = true;
+ ScRange aExternalRange;
+
+ if( rSortParam.nCol1 != rSortParam.nCol2 )
+ eFillDir = DIR_LEFT;
+ if( rSortParam.nRow1 != rSortParam.nRow2 )
+ eFillDir = DIR_TOP;
+
+ if( rSortParam.nRow2 == rDoc.MaxRow() )
+ {
+ // Assume that user selected entire column(s), but cater for the
+ // possibility that the start row is not the first row.
+ SCSIZE nCount = rDoc.GetEmptyLinesInBlock( rSortParam.nCol1, rSortParam.nRow1, nTab,
+ rSortParam.nCol2, rSortParam.nRow2, nTab, eFillDir );
+ aExternalRange = ScRange( rSortParam.nCol1,
+ ::std::min( rSortParam.nRow1 + sal::static_int_cast<SCROW>( nCount ), rDoc.MaxRow()), nTab,
+ rSortParam.nCol2, rSortParam.nRow2, nTab);
+ aExternalRange.PutInOrder();
+ }
+ else if (rSortParam.nCol1 != rSortParam.nCol2 || rSortParam.nRow1 != rSortParam.nRow2)
+ {
+ // Preserve a preselected area.
+ aExternalRange = ScRange( rSortParam.nCol1, rSortParam.nRow1, nTab, rSortParam.nCol2, rSortParam.nRow2, nTab);
+ aExternalRange.PutInOrder();
+ }
+ else
+ aExternalRange = ScRange( rData.GetCurX(), rData.GetCurY(), nTab );
+
+ SCROW nStartRow = aExternalRange.aStart.Row();
+ SCCOL nStartCol = aExternalRange.aStart.Col();
+ SCROW nEndRow = aExternalRange.aEnd.Row();
+ SCCOL nEndCol = aExternalRange.aEnd.Col();
+ rDoc.GetDataArea( aExternalRange.aStart.Tab(), nStartCol, nStartRow, nEndCol, nEndRow, false, false );
+ aExternalRange.aStart.SetRow( nStartRow );
+ aExternalRange.aStart.SetCol( nStartCol );
+ aExternalRange.aEnd.SetRow( nEndRow );
+ aExternalRange.aEnd.SetCol( nEndCol );
+
+ // with LibreOfficeKit, don't try to interact with the user
+ if (!comphelper::LibreOfficeKit::isActive() &&
+ ((rSortParam.nCol1 == rSortParam.nCol2 && aExternalRange.aStart.Col() != aExternalRange.aEnd.Col()) ||
+ (rSortParam.nRow1 == rSortParam.nRow2 && aExternalRange.aStart.Row() != aExternalRange.aEnd.Row())))
+ {
+ pTabViewShell->AddHighlightRange( aExternalRange,COL_LIGHTBLUE );
+ OUString aExtendStr( aExternalRange.Format(rDoc, ScRefFlags::VALID));
+
+ ScRange aCurrentRange( rSortParam.nCol1, rSortParam.nRow1, nTab, rSortParam.nCol2, rSortParam.nRow2, nTab );
+ OUString aCurrentStr(aCurrentRange.Format(rDoc, ScRefFlags::VALID));
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScSortWarningDlg> pWarningDlg(pFact->CreateScSortWarningDlg(pTabViewShell->GetFrameWeld(), aExtendStr, aCurrentStr));
+ short bResult = pWarningDlg->Execute();
+ if( bResult == BTN_EXTEND_RANGE || bResult == BTN_CURRENT_SELECTION )
+ {
+ if( bResult == BTN_EXTEND_RANGE )
+ {
+ pTabViewShell->MarkRange( aExternalRange, false );
+ pDBData->SetArea( nTab, aExternalRange.aStart.Col(), aExternalRange.aStart.Row(), aExternalRange.aEnd.Col(), aExternalRange.aEnd.Row() );
+ }
+ }
+ else
+ {
+ bSort = false;
+ rData.GetDocShell()->CancelAutoDBRange();
+ }
+
+ pTabViewShell->ClearHighlightRanges();
+ }
+ return bSort;
+}
+
+namespace
+{
+ // this registers the dialog which Find1RefWindow search for
+ class ScValidationRegisteredDlg
+ {
+ std::shared_ptr<SfxDialogController> m_xDlg;
+ public:
+ ScValidationRegisteredDlg(weld::Window* pParent, const std::shared_ptr<SfxDialogController>& rDlg)
+ : m_xDlg(rDlg)
+ {
+ SC_MOD()->RegisterRefController(static_cast<sal_uInt16>(ScValidationDlg::SLOTID), m_xDlg, pParent);
+ }
+ ~ScValidationRegisteredDlg()
+ {
+ m_xDlg->Close();
+ SC_MOD()->UnregisterRefController(static_cast<sal_uInt16>(ScValidationDlg::SLOTID), m_xDlg);
+ }
+ };
+}
+
+void ScCellShell::ExecuteDB( SfxRequest& rReq )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ sal_uInt16 nSlotId = rReq.GetSlot();
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ ScModule* pScMod = SC_MOD();
+
+ pTabViewShell->HideListBox(); // Autofilter-DropDown-Listbox
+
+ if ( GetViewData().HasEditView( GetViewData().GetActivePart() ) )
+ {
+ pScMod->InputEnterHandler();
+ pTabViewShell->UpdateInputHandler();
+ }
+
+ switch ( nSlotId )
+ {
+ case SID_VIEW_DATA_SOURCE_BROWSER:
+ {
+ // check if database beamer is open
+
+ SfxViewFrame* pViewFrame = pTabViewShell->GetViewFrame();
+ bool bWasOpen = false;
+ {
+ uno::Reference<frame::XFrame> xFrame = pViewFrame->GetFrame().GetFrameInterface();
+ uno::Reference<frame::XFrame> xBeamerFrame = xFrame->findFrame(
+ "_beamer",
+ frame::FrameSearchFlag::CHILDREN);
+ if ( xBeamerFrame.is() )
+ bWasOpen = true;
+ }
+
+ if ( bWasOpen )
+ {
+ // close database beamer: just forward to SfxViewFrame
+
+ pViewFrame->ExecuteSlot( rReq );
+ }
+ else
+ {
+ // show database beamer: SfxViewFrame call must be synchronous
+
+ pViewFrame->ExecuteSlot( rReq, false ); // false = synchronous
+
+ // select current database in database beamer
+
+ ScImportParam aImportParam;
+ ScDBData* pDBData = pTabViewShell->GetDBData(true,SC_DB_OLD); // don't create if none found
+ if (pDBData)
+ pDBData->GetImportParam( aImportParam );
+
+ ScDBDocFunc::ShowInBeamer( aImportParam, pTabViewShell->GetViewFrame() );
+ }
+ rReq.Done(); // needed because it's a toggle slot
+ }
+ break;
+
+ case SID_REIMPORT_DATA:
+ {
+ bool bOk = false;
+ ScDBData* pDBData = pTabViewShell->GetDBData(true,SC_DB_OLD);
+ if (pDBData)
+ {
+ ScImportParam aImportParam;
+ pDBData->GetImportParam( aImportParam );
+ if (aImportParam.bImport && !pDBData->HasImportSelection())
+ {
+ pTabViewShell->ImportData( aImportParam );
+ pDBData->SetImportParam( aImportParam ); //! Undo ??
+ bOk = true;
+ }
+ }
+
+ if (!bOk && ! rReq.IsAPI() )
+ pTabViewShell->ErrorMessage(STR_REIMPORT_EMPTY);
+
+ if( bOk )
+ rReq.Done();
+ }
+ break;
+
+ case SID_REFRESH_DBAREA:
+ {
+ ScDBData* pDBData = pTabViewShell->GetDBData(true,SC_DB_OLD);
+ if (pDBData)
+ {
+ // repeat import like SID_REIMPORT_DATA
+
+ bool bContinue = true;
+ ScImportParam aImportParam;
+ pDBData->GetImportParam( aImportParam );
+ if (aImportParam.bImport && !pDBData->HasImportSelection())
+ {
+ bContinue = pTabViewShell->ImportData( aImportParam );
+ pDBData->SetImportParam( aImportParam ); //! Undo ??
+
+ // mark (size may have been changed)
+ ScRange aNewRange;
+ pDBData->GetArea(aNewRange);
+ pTabViewShell->MarkRange(aNewRange);
+ }
+
+ if ( bContinue ) // fail at import -> break
+ {
+ // internal operations, when any stored
+
+ if ( pDBData->HasQueryParam() || pDBData->HasSortParam() ||
+ pDBData->HasSubTotalParam() )
+ pTabViewShell->RepeatDB();
+
+ // pivot tables that have the range as data source
+
+ ScRange aRange;
+ pDBData->GetArea(aRange);
+ GetViewData().GetDocShell()->RefreshPivotTables(aRange);
+ }
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_SBA_BRW_INSERT:
+ {
+ OSL_FAIL( "Deprecated Slot" );
+ }
+ break;
+
+ case SID_DATA_FORM:
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScDataFormDlg> pDlg(pFact->CreateScDataFormDlg(
+ pTabViewShell->GetFrameWeld(), pTabViewShell));
+
+ pDlg->Execute();
+
+ rReq.Done();
+ }
+ break;
+
+ case SID_SUBTOTALS:
+ ExecuteSubtotals(rReq);
+ break;
+
+ case SID_SORT_DESCENDING:
+ case SID_SORT_ASCENDING:
+ {
+ //#i60401 ux-ctest: Calc does not support all users' strategies regarding sorting data
+ //the patch comes from maoyg
+ ScSortParam aSortParam;
+ ScDBData* pDBData = pTabViewShell->GetDBData();
+ ScViewData& rData = GetViewData();
+
+ pDBData->GetSortParam( aSortParam );
+
+ if( lcl_GetSortParam( rData, aSortParam ) )
+ {
+ SCCOL nCol = GetViewData().GetCurX();
+ SCCOL nTab = GetViewData().GetTabNo();
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ pDBData->GetSortParam( aSortParam );
+ bool bHasHeader = rDoc.HasColHeader( aSortParam.nCol1, aSortParam.nRow1, aSortParam.nCol2, aSortParam.nRow2, nTab );
+
+ if( nCol < aSortParam.nCol1 )
+ nCol = aSortParam.nCol1;
+ else if( nCol > aSortParam.nCol2 )
+ nCol = aSortParam.nCol2;
+
+ aSortParam.bHasHeader = bHasHeader;
+ aSortParam.bByRow = true;
+ aSortParam.bCaseSens = false;
+ aSortParam.bNaturalSort = false;
+ aSortParam.aDataAreaExtras.mbCellNotes = false;
+ aSortParam.aDataAreaExtras.mbCellDrawObjects = true;
+ aSortParam.aDataAreaExtras.mbCellFormats = true;
+ aSortParam.bInplace = true;
+ aSortParam.maKeyState[0].bDoSort = true;
+ aSortParam.maKeyState[0].nField = nCol;
+ aSortParam.maKeyState[0].bAscending = ( nSlotId == SID_SORT_ASCENDING );
+
+ for ( sal_uInt16 i=1; i<aSortParam.GetSortKeyCount(); i++ )
+ aSortParam.maKeyState[i].bDoSort = false;
+
+ pTabViewShell->UISort( aSortParam ); // subtotal when needed new
+
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_SORT:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ //#i60401 ux-ctest: Calc does not support all users' strategies regarding sorting data
+ //the patch comes from maoyg
+
+ if ( pArgs ) // Basic
+ {
+ ScSortParam aSortParam;
+ ScDBData* pDBData = pTabViewShell->GetDBData();
+ ScViewData& rData = GetViewData();
+
+ pDBData->GetSortParam( aSortParam );
+
+ if( lcl_GetSortParam( rData, aSortParam ) )
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ pDBData->GetSortParam( aSortParam );
+ bool bHasHeader = rDoc.HasColHeader( aSortParam.nCol1, aSortParam.nRow1, aSortParam.nCol2, aSortParam.nRow2, rData.GetTabNo() );
+ if( bHasHeader )
+ aSortParam.bHasHeader = bHasHeader;
+
+ aSortParam.bInplace = true; // from Basic always
+
+ if ( const SfxBoolItem* pItem = pArgs->GetItemIfSet( SID_SORT_BYROW ) )
+ aSortParam.bByRow = pItem->GetValue();
+ if ( const SfxBoolItem* pItem = pArgs->GetItemIfSet( SID_SORT_HASHEADER ) )
+ aSortParam.bHasHeader = pItem->GetValue();
+ if ( const SfxBoolItem* pItem = pArgs->GetItemIfSet( SID_SORT_CASESENS ) )
+ aSortParam.bCaseSens = pItem->GetValue();
+ if ( const SfxBoolItem* pItem = pArgs->GetItemIfSet( SID_SORT_NATURALSORT ) )
+ aSortParam.bNaturalSort = pItem->GetValue();
+ if ( const SfxBoolItem* pItem = pArgs->GetItemIfSet( SID_SORT_INCCOMMENTS ) )
+ aSortParam.aDataAreaExtras.mbCellNotes = pItem->GetValue();
+ if ( const SfxBoolItem* pItem = pArgs->GetItemIfSet( SID_SORT_INCIMAGES ) )
+ aSortParam.aDataAreaExtras.mbCellDrawObjects = pItem->GetValue();
+ if ( const SfxBoolItem* pItem = pArgs->GetItemIfSet( SID_SORT_ATTRIBS ) )
+ aSortParam.aDataAreaExtras.mbCellFormats = pItem->GetValue();
+ if ( const SfxUInt16Item* pItem = pArgs->GetItemIfSet( SID_SORT_USERDEF ) )
+ {
+ sal_uInt16 nUserIndex = pItem->GetValue();
+ aSortParam.bUserDef = ( nUserIndex != 0 );
+ if ( nUserIndex )
+ aSortParam.nUserIndex = nUserIndex - 1; // Basic: 1-based
+ }
+
+ SCCOLROW nField0 = 0;
+ const SfxPoolItem* pItem = nullptr;
+ if ( pArgs->GetItemState( FN_PARAM_1, true, &pItem ) == SfxItemState::SET )
+ nField0 = static_cast<const SfxInt32Item*>(pItem)->GetValue();
+ aSortParam.maKeyState[0].bDoSort = ( nField0 != 0 );
+ aSortParam.maKeyState[0].nField = nField0 > 0 ? (nField0-1) : 0;
+ if ( pArgs->GetItemState( FN_PARAM_2, true, &pItem ) == SfxItemState::SET )
+ aSortParam.maKeyState[0].bAscending = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ SCCOLROW nField1 = 0;
+ if ( pArgs->GetItemState( FN_PARAM_3, true, &pItem ) == SfxItemState::SET )
+ nField1 = static_cast<const SfxInt32Item*>(pItem)->GetValue();
+ aSortParam.maKeyState[1].bDoSort = ( nField1 != 0 );
+ aSortParam.maKeyState[1].nField = nField1 > 0 ? (nField1-1) : 0;
+ if ( pArgs->GetItemState( FN_PARAM_4, true, &pItem ) == SfxItemState::SET )
+ aSortParam.maKeyState[1].bAscending = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ SCCOLROW nField2 = 0;
+ if ( pArgs->GetItemState( FN_PARAM_5, true, &pItem ) == SfxItemState::SET )
+ nField2 = static_cast<const SfxInt32Item*>(pItem)->GetValue();
+ aSortParam.maKeyState[2].bDoSort = ( nField2 != 0 );
+ aSortParam.maKeyState[2].nField = nField2 > 0 ? (nField2-1) : 0;
+ if ( pArgs->GetItemState( FN_PARAM_6, true, &pItem ) == SfxItemState::SET )
+ aSortParam.maKeyState[2].bAscending = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ // subtotal when needed new
+ pTabViewShell->UISort( aSortParam );
+ rReq.Done();
+ }
+ }
+ else
+ {
+ ScSortParam aSortParam;
+ ScDBData* pDBData = pTabViewShell->GetDBData();
+ ScViewData& rData = GetViewData();
+
+ pDBData->GetSortParam( aSortParam );
+
+ if( lcl_GetSortParam( rData, aSortParam ) )
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ SfxItemSetFixed<SCITEM_SORTDATA, SCITEM_SORTDATA> aArgSet( GetPool() );
+
+ pDBData->GetSortParam( aSortParam );
+ bool bHasHeader = rDoc.HasColHeader( aSortParam.nCol1, aSortParam.nRow1, aSortParam.nCol2, aSortParam.nRow2, rData.GetTabNo() );
+ if( bHasHeader )
+ aSortParam.bHasHeader = bHasHeader;
+
+ aArgSet.Put( ScSortItem( SCITEM_SORTDATA, &GetViewData(), &aSortParam ) );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ std::shared_ptr<ScAsyncTabController> pDlg(pFact->CreateScSortDlg(pTabViewShell->GetFrameWeld(), &aArgSet));
+ pDlg->SetCurPageId("criteria"); // 1=sort field tab 2=sort options tab
+
+ VclAbstractDialog::AsyncContext aContext;
+ aContext.maEndDialogFn = [pDlg, &rData, pTabViewShell](sal_Int32 nResult)
+ {
+ if ( nResult == RET_OK )
+ {
+ const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
+ const ScSortParam& rOutParam =
+ pOutSet->Get( SCITEM_SORTDATA ).GetSortData();
+
+ // subtotal when needed new
+
+ pTabViewShell->UISort( rOutParam );
+
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ if (pViewFrm)
+ {
+ SfxRequest aRequest(pViewFrm, SID_SORT);
+
+ if ( rOutParam.bInplace )
+ {
+ aRequest.AppendItem( SfxBoolItem( SID_SORT_BYROW,
+ rOutParam.bByRow ) );
+ aRequest.AppendItem( SfxBoolItem( SID_SORT_HASHEADER,
+ rOutParam.bHasHeader ) );
+ aRequest.AppendItem( SfxBoolItem( SID_SORT_CASESENS,
+ rOutParam.bCaseSens ) );
+ aRequest.AppendItem( SfxBoolItem( SID_SORT_NATURALSORT,
+ rOutParam.bNaturalSort ) );
+ aRequest.AppendItem( SfxBoolItem( SID_SORT_INCCOMMENTS,
+ rOutParam.aDataAreaExtras.mbCellNotes ) );
+ aRequest.AppendItem( SfxBoolItem( SID_SORT_INCIMAGES,
+ rOutParam.aDataAreaExtras.mbCellDrawObjects ) );
+ aRequest.AppendItem( SfxBoolItem( SID_SORT_ATTRIBS,
+ rOutParam.aDataAreaExtras.mbCellFormats ) );
+ sal_uInt16 nUser = rOutParam.bUserDef ? ( rOutParam.nUserIndex + 1 ) : 0;
+ aRequest.AppendItem( SfxUInt16Item( SID_SORT_USERDEF, nUser ) );
+ if ( rOutParam.maKeyState[0].bDoSort )
+ {
+ aRequest.AppendItem( SfxInt32Item( FN_PARAM_1,
+ rOutParam.maKeyState[0].nField + 1 ) );
+ aRequest.AppendItem( SfxBoolItem( FN_PARAM_2,
+ rOutParam.maKeyState[0].bAscending ) );
+ }
+ if ( rOutParam.maKeyState[1].bDoSort )
+ {
+ aRequest.AppendItem( SfxInt32Item( FN_PARAM_3,
+ rOutParam.maKeyState[1].nField + 1 ) );
+ aRequest.AppendItem( SfxBoolItem( FN_PARAM_4,
+ rOutParam.maKeyState[1].bAscending ) );
+ }
+ if ( rOutParam.maKeyState[2].bDoSort )
+ {
+ aRequest.AppendItem( SfxInt32Item( FN_PARAM_5,
+ rOutParam.maKeyState[2].nField + 1 ) );
+ aRequest.AppendItem( SfxBoolItem( FN_PARAM_6,
+ rOutParam.maKeyState[2].bAscending ) );
+ }
+ }
+
+ aRequest.Done();
+ }
+ }
+ else
+ {
+ rData.GetDocShell()->CancelAutoDBRange();
+ }
+ };
+
+ pDlg->StartExecuteAsync(aContext);
+ }
+ }
+ }
+ break;
+
+ case SID_FILTER:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if ( pArgs )
+ {
+ OSL_FAIL("SID_FILTER with arguments?");
+ pTabViewShell->Query(
+ pArgs->Get( SCITEM_QUERYDATA ).GetQueryData(), nullptr, true );
+ rReq.Done();
+ }
+ else
+ {
+ sal_uInt16 nId = ScFilterDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ }
+ break;
+
+ case SID_SPECIAL_FILTER:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if ( pArgs )
+ {
+ OSL_FAIL("SID_SPECIAL_FILTER with arguments?");
+ pTabViewShell->Query(
+ pArgs->Get( SCITEM_QUERYDATA ).GetQueryData(), nullptr, true );
+ rReq.Done();
+ }
+ else
+ {
+ sal_uInt16 nId = ScSpecialFilterDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ }
+ break;
+
+ case FID_FILTER_OK:
+ {
+ const ScQueryItem* pQueryItem;
+ if ( pReqArgs && (pQueryItem =
+ pReqArgs->GetItemIfSet( SCITEM_QUERYDATA )) )
+ {
+ SCTAB nCurTab = GetViewData().GetTabNo();
+ SCTAB nRefTab = GetViewData().GetRefTabNo();
+
+ // If RefInput switched to a different sheet from the data sheet,
+ // switch back:
+
+ if ( nCurTab != nRefTab )
+ {
+ pTabViewShell->SetTabNo( nRefTab );
+ pTabViewShell->PaintExtras();
+ }
+
+ ScRange aAdvSource;
+ if (pQueryItem->GetAdvancedQuerySource(aAdvSource))
+ pTabViewShell->Query( pQueryItem->GetQueryData(), &aAdvSource, true );
+ else
+ pTabViewShell->Query( pQueryItem->GetQueryData(), nullptr, true );
+ rReq.Done( *pReqArgs );
+ }
+ }
+ break;
+
+ case SID_UNFILTER:
+ {
+ ScQueryParam aParam;
+ ScDBData* pDBData = pTabViewShell->GetDBData();
+
+ pDBData->GetQueryParam( aParam );
+ SCSIZE nEC = aParam.GetEntryCount();
+ for (SCSIZE i=0; i<nEC; i++)
+ aParam.GetEntry(i).bDoQuery = false;
+ aParam.bDuplicate = true;
+ pTabViewShell->Query( aParam, nullptr, true );
+ rReq.Done();
+ }
+ break;
+
+ case SID_AUTO_FILTER:
+ pTabViewShell->ToggleAutoFilter();
+ rReq.Done();
+ break;
+
+ case SID_AUTOFILTER_HIDE:
+ pTabViewShell->HideAutoFilter();
+ rReq.Done();
+ break;
+
+ case SID_PIVOT_TABLE:
+ {
+ const ScPivotItem* pPItem;
+ if ( pReqArgs && (pPItem =
+ pReqArgs->GetItemIfSet( SCITEM_PIVOTDATA )) )
+ {
+ SCTAB nCurTab = GetViewData().GetTabNo();
+ SCTAB nRefTab = GetViewData().GetRefTabNo();
+
+ // If RefInput switched to a different sheet from the data sheet,
+ // switch back:
+
+ if ( nCurTab != nRefTab )
+ {
+ pTabViewShell->SetTabNo( nRefTab );
+ pTabViewShell->PaintExtras();
+ }
+
+ const ScDPObject* pDPObject = pTabViewShell->GetDialogDPObject();
+ if ( pDPObject )
+ {
+ bool bSuccess = pTabViewShell->MakePivotTable(
+ pPItem->GetData(), pPItem->GetDestRange(), pPItem->IsNewSheet(), *pDPObject );
+ SfxBoolItem aRet(0, bSuccess);
+ rReq.SetReturnValue(aRet);
+ }
+ rReq.Done();
+ }
+#if HAVE_FEATURE_SCRIPTING
+ else if (rReq.IsAPI())
+ SbxBase::SetError(ERRCODE_BASIC_BAD_PARAMETER);
+#endif
+ }
+ break;
+
+ case SID_OPENDLG_PIVOTTABLE:
+ ExecuteDataPilotDialog();
+ break;
+ case SID_DEFINE_DBNAME:
+ {
+
+ sal_uInt16 nId = ScDbNameDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+
+ }
+ break;
+
+ case SID_SELECT_DB:
+ {
+ if ( pReqArgs )
+ {
+ const SfxStringItem& rItem
+ = static_cast<const SfxStringItem&>(pReqArgs->Get(SID_SELECT_DB));
+ pTabViewShell->GotoDBArea(rItem.GetValue());
+ rReq.Done();
+ }
+ else
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDBCollection* pDBCol = rDoc.GetDBCollection();
+
+ if ( pDBCol )
+ {
+ std::vector<OUString> aList;
+ const ScDBCollection::NamedDBs& rDBs = pDBCol->getNamedDBs();
+ for (const auto& rxDB : rDBs)
+ aList.push_back(rxDB->GetName());
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScSelEntryDlg> pDlg(pFact->CreateScSelEntryDlg(pTabViewShell->GetFrameWeld(), aList));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ OUString aName = pDlg->GetSelectedEntry();
+ pTabViewShell->GotoDBArea( aName );
+ rReq.AppendItem( SfxStringItem( SID_SELECT_DB, aName ) );
+ rReq.Done();
+ }
+ }
+ }
+ }
+ break;
+ case SID_DATA_STREAMS:
+ {
+ sc::DataStreamDlg aDialog(GetViewData().GetDocShell(), pTabViewShell->GetFrameWeld());
+ ScDocument& rDoc = GetViewData().GetDocument();
+ sc::DocumentLinkManager& rMgr = rDoc.GetDocLinkManager();
+ sc::DataStream* pStrm = rMgr.getDataStream();
+ if (pStrm)
+ aDialog.Init(*pStrm);
+
+ if (aDialog.run() == RET_OK)
+ aDialog.StartStream();
+ }
+ break;
+ case SID_DATA_STREAMS_PLAY:
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ sc::DocumentLinkManager& rMgr = rDoc.GetDocLinkManager();
+ sc::DataStream* pStrm = rMgr.getDataStream();
+ if (pStrm)
+ pStrm->StartImport();
+ }
+ break;
+ case SID_DATA_STREAMS_STOP:
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ sc::DocumentLinkManager& rMgr = rDoc.GetDocLinkManager();
+ sc::DataStream* pStrm = rMgr.getDataStream();
+ if (pStrm)
+ pStrm->StopImport();
+ }
+ break;
+ case SID_DATA_PROVIDER:
+ {
+ auto xDoc = o3tl::make_shared<ScDocument>();
+ xDoc->InsertTab(0, "test");
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDataProviderDlg aDialog(pTabViewShell->GetDialogParent(), xDoc, &rDoc);
+ if (aDialog.run() == RET_OK)
+ {
+ aDialog.import(rDoc);
+ }
+ }
+ break;
+ case SID_DATA_PROVIDER_REFRESH:
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ auto& rDataMapper = rDoc.GetExternalDataMapper();
+ for (auto& rDataSource : rDataMapper.getDataSources())
+ {
+ rDataSource.refresh(&rDoc, false);
+ }
+ }
+ break;
+ case SID_MANAGE_XML_SOURCE:
+ ExecuteXMLSourceDialog();
+ break;
+ case FID_VALIDATION:
+ case FID_CURRENTVALIDATION:
+ {
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ if ( pArgs )
+ {
+ OSL_FAIL("later...");
+ }
+ else
+ {
+ SfxItemSet aArgSet( GetPool(), ScTPValidationValue::GetRanges() );
+ ScValidationMode eMode = SC_VALID_ANY;
+ ScConditionMode eOper = ScConditionMode::Equal;
+ OUString aExpr1, aExpr2;
+ bool bBlank = true;
+ sal_Int16 nListType = css::sheet::TableValidationVisibility::UNSORTED;
+ bool bShowHelp = false;
+ OUString aHelpTitle, aHelpText;
+ bool bShowError = false;
+ ScValidErrorStyle eErrStyle = SC_VALERR_STOP;
+ OUString aErrTitle, aErrText;
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ SCCOL nCurX = GetViewData().GetCurX();
+ SCROW nCurY = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScAddress aCursorPos( nCurX, nCurY, nTab );
+ sal_uLong nIndex = rDoc.GetAttr(
+ nCurX, nCurY, nTab, ATTR_VALIDDATA )->GetValue();
+ if ( nIndex )
+ {
+ const ScValidationData* pOldData = rDoc.GetValidationEntry( nIndex );
+ if ( pOldData )
+ {
+ eMode = pOldData->GetDataMode();
+ eOper = pOldData->GetOperation();
+ sal_uInt32 nNumFmt = 0;
+ if ( eMode == SC_VALID_DATE || eMode == SC_VALID_TIME )
+ {
+ SvNumFormatType nType = ( eMode == SC_VALID_DATE ) ? SvNumFormatType::DATE
+ : SvNumFormatType::TIME;
+ nNumFmt = rDoc.GetFormatTable()->GetStandardFormat(
+ nType, ScGlobal::eLnge );
+ }
+ aExpr1 = pOldData->GetExpression( aCursorPos, 0, nNumFmt );
+ aExpr2 = pOldData->GetExpression( aCursorPos, 1, nNumFmt );
+ bBlank = pOldData->IsIgnoreBlank();
+ nListType = pOldData->GetListType();
+
+ bShowHelp = pOldData->GetInput( aHelpTitle, aHelpText );
+ bShowError = pOldData->GetErrMsg( aErrTitle, aErrText, eErrStyle );
+
+ aArgSet.Put( SfxUInt16Item( FID_VALID_MODE, sal::static_int_cast<sal_uInt16>(eMode) ) );
+ aArgSet.Put( SfxUInt16Item( FID_VALID_CONDMODE, sal::static_int_cast<sal_uInt16>(eOper) ) );
+ aArgSet.Put( SfxStringItem( FID_VALID_VALUE1, aExpr1 ) );
+ aArgSet.Put( SfxStringItem( FID_VALID_VALUE2, aExpr2 ) );
+ aArgSet.Put( SfxBoolItem( FID_VALID_BLANK, bBlank ) );
+ aArgSet.Put( SfxInt16Item( FID_VALID_LISTTYPE, nListType ) );
+ aArgSet.Put( SfxBoolItem( FID_VALID_SHOWHELP, bShowHelp ) );
+ aArgSet.Put( SfxStringItem( FID_VALID_HELPTITLE, aHelpTitle ) );
+ aArgSet.Put( SfxStringItem( FID_VALID_HELPTEXT, aHelpText ) );
+ aArgSet.Put( SfxBoolItem( FID_VALID_SHOWERR, bShowError ) );
+ aArgSet.Put( SfxUInt16Item( FID_VALID_ERRSTYLE, sal::static_int_cast<sal_uInt16>(eErrStyle) ) );
+ aArgSet.Put( SfxStringItem( FID_VALID_ERRTITLE, aErrTitle ) );
+ aArgSet.Put( SfxStringItem( FID_VALID_ERRTEXT, aErrText ) );
+ }
+ }
+
+ // cell range picker
+ vcl::Window* pWin = GetViewData().GetActiveWin();
+ weld::Window* pParentWin = pWin ? pWin->GetFrameWeld() : nullptr;
+ auto xDlg = std::make_shared<ScValidationDlg>(pParentWin, &aArgSet, pTabViewShell);
+ ScValidationRegisteredDlg aRegisterThatDlgExists(pParentWin, xDlg);
+
+ short nResult = xDlg->run();
+ if ( nResult == RET_OK )
+ {
+ const SfxItemSet* pOutSet = xDlg->GetOutputItemSet();
+
+ if ( const SfxUInt16Item* pItem = pOutSet->GetItemIfSet( FID_VALID_MODE ) )
+ eMode = static_cast<ScValidationMode>(pItem->GetValue());
+ if ( const SfxUInt16Item* pItem = pOutSet->GetItemIfSet( FID_VALID_CONDMODE ) )
+ eOper = static_cast<ScConditionMode>(pItem->GetValue());
+ if ( const SfxStringItem* pItem = pOutSet->GetItemIfSet( FID_VALID_VALUE1 ) )
+ {
+ OUString aTemp1 = pItem->GetValue();
+ if (eMode == SC_VALID_DATE || eMode == SC_VALID_TIME)
+ {
+ sal_uInt32 nNumIndex = 0;
+ double nVal;
+ if (rDoc.GetFormatTable()->IsNumberFormat(aTemp1, nNumIndex, nVal))
+ aExpr1 = ::rtl::math::doubleToUString( nVal,
+ rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
+ ScGlobal::getLocaleData().getNumDecimalSep()[0], true);
+ else
+ aExpr1 = aTemp1;
+ }
+ else
+ aExpr1 = aTemp1;
+ }
+ if ( const SfxStringItem* pItem = pOutSet->GetItemIfSet( FID_VALID_VALUE2 ) )
+ {
+ OUString aTemp2 = pItem->GetValue();
+ if (eMode == SC_VALID_DATE || eMode == SC_VALID_TIME)
+ {
+ sal_uInt32 nNumIndex = 0;
+ double nVal;
+ if (rDoc.GetFormatTable()->IsNumberFormat(aTemp2, nNumIndex, nVal))
+ aExpr2 = ::rtl::math::doubleToUString( nVal,
+ rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max,
+ ScGlobal::getLocaleData().getNumDecimalSep()[0], true);
+ else
+ aExpr2 = aTemp2;
+ if ( eMode == SC_VALID_TIME ) {
+ sal_Int32 wraparound = aExpr1.compareTo(aExpr2);
+ if (wraparound > 0) {
+ if (eOper == ScConditionMode::Between) {
+ eOper = ScConditionMode::NotBetween;
+ OUString tmp = aExpr1;
+ aExpr1 = aExpr2;
+ aExpr2 = tmp;
+ }
+ else if (eOper == ScConditionMode::NotBetween) {
+ eOper = ScConditionMode::Between;
+ OUString tmp = aExpr1;
+ aExpr1 = aExpr2;
+ aExpr2 = tmp;
+ }
+ }
+ }
+ }
+ else
+ aExpr2 = aTemp2;
+ }
+ if ( const SfxBoolItem* pItem = pOutSet->GetItemIfSet( FID_VALID_BLANK ) )
+ bBlank = pItem->GetValue();
+ if ( const SfxInt16Item* pItem = pOutSet->GetItemIfSet( FID_VALID_LISTTYPE ) )
+ nListType = pItem->GetValue();
+
+ if ( const SfxBoolItem* pItem = pOutSet->GetItemIfSet( FID_VALID_SHOWHELP ) )
+ bShowHelp = pItem->GetValue();
+ if ( const SfxStringItem* pItem = pOutSet->GetItemIfSet( FID_VALID_HELPTITLE ) )
+ aHelpTitle = pItem->GetValue();
+ if ( const SfxStringItem* pItem = pOutSet->GetItemIfSet( FID_VALID_HELPTEXT ) )
+ aHelpText = pItem->GetValue();
+
+ if ( const SfxBoolItem* pItem = pOutSet->GetItemIfSet( FID_VALID_SHOWERR ) )
+ bShowError = pItem->GetValue();
+ if ( const SfxUInt16Item* pItem = pOutSet->GetItemIfSet( FID_VALID_ERRSTYLE ) )
+ eErrStyle = static_cast<ScValidErrorStyle>(pItem->GetValue());
+ if ( const SfxStringItem* pItem = pOutSet->GetItemIfSet( FID_VALID_ERRTITLE ) )
+ aErrTitle = pItem->GetValue();
+ if ( const SfxStringItem* pItem = pOutSet->GetItemIfSet( FID_VALID_ERRTEXT ) )
+ aErrText = pItem->GetValue();
+
+ ScValidationData aData( eMode, eOper, aExpr1, aExpr2, rDoc, aCursorPos );
+ aData.SetIgnoreBlank( bBlank );
+ aData.SetListType( nListType );
+
+ aData.SetInput(aHelpTitle, aHelpText); // sets bShowInput to TRUE
+ if (!bShowHelp)
+ aData.ResetInput(); // reset only bShowInput
+
+ aData.SetError(aErrTitle, aErrText, eErrStyle); // sets bShowError to TRUE
+ if (!bShowError)
+ aData.ResetError(); // reset only bShowError
+
+ pTabViewShell->SetValidation( aData );
+ pTabViewShell->TestHintWindow();
+ rReq.Done( *pOutSet );
+ }
+ }
+ }
+ break;
+
+ case SID_TEXT_TO_COLUMNS:
+ {
+ ScViewData& rData = GetViewData();
+ ScRange aRange;
+
+ if ( lcl_GetTextToColumnsRange( rData, aRange, false ) )
+ {
+ ScDocument& rDoc = rData.GetDocument();
+
+ ScImportExport aExport( rDoc, aRange );
+ aExport.SetExportTextOptions( ScExportTextOptions( ScExportTextOptions::None, 0, false ) );
+
+ // #i87703# text to columns fails with tab separator
+ aExport.SetDelimiter( u'\0' );
+
+ SvMemoryStream aStream;
+ aStream.SetStreamCharSet( RTL_TEXTENCODING_UNICODE );
+ ScImportExport::SetNoEndianSwap( aStream );
+ aExport.ExportStream( aStream, OUString(), SotClipboardFormatId::STRING );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractScImportAsciiDlg> pDlg(pFact->CreateScImportAsciiDlg(
+ pTabViewShell->GetFrameWeld(), OUString(), &aStream, SC_TEXTTOCOLUMNS));
+
+ if ( pDlg->Execute() == RET_OK )
+ {
+ ScDocShell* pDocSh = rData.GetDocShell();
+ OSL_ENSURE( pDocSh, "ScCellShell::ExecuteDB: SID_TEXT_TO_COLUMNS - pDocSh is null!" );
+
+ OUString aUndo = ScResId( STR_UNDO_TEXTTOCOLUMNS );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, rData.GetViewShell()->GetViewShellId() );
+
+ ScImportExport aImport( rDoc, aRange.aStart );
+ ScAsciiOptions aOptions;
+ pDlg->GetOptions( aOptions );
+ pDlg->SaveParameters();
+ aImport.SetExtOptions( aOptions );
+ aImport.SetApi( false );
+ aImport.SetImportBroadcast( true );
+ aImport.SetOverwriting( true );
+ aStream.Seek( 0 );
+ aImport.ImportStream( aStream, OUString(), SotClipboardFormatId::STRING );
+
+ pDocSh->GetUndoManager()->LeaveListAction();
+ }
+ }
+ }
+ break;
+ }
+}
+
+void ScCellShell::GetDBState( SfxItemSet& rSet )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ ScViewData& rData = GetViewData();
+ ScDocShell* pDocSh = rData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCCOL nPosX = rData.GetCurX();
+ SCROW nPosY = rData.GetCurY();
+ SCTAB nTab = rData.GetTabNo();
+
+ bool bAutoFilter = false;
+ bool bAutoFilterTested = false;
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich)
+ {
+ switch (nWhich)
+ {
+ case SID_REFRESH_DBAREA:
+ {
+ // imported data without selection
+ // or filter,sort,subtotal (also without import)
+ bool bOk = false;
+ ScDBData* pDBData = pTabViewShell->GetDBData(false,SC_DB_OLD);
+ if (pDBData && rDoc.GetChangeTrack() == nullptr)
+ {
+ if ( pDBData->HasImportParam() )
+ bOk = !pDBData->HasImportSelection();
+ else
+ {
+ bOk = pDBData->HasQueryParam() ||
+ pDBData->HasSortParam() ||
+ pDBData->HasSubTotalParam();
+ }
+ }
+ if (!bOk)
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_FILTER:
+ case SID_SPECIAL_FILTER:
+ {
+ ScRange aDummy;
+ ScMarkType eMarkType = GetViewData().GetSimpleArea( aDummy);
+ if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED)
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ //in case of Redlining and multiselection disable
+ case SID_SORT_ASCENDING:
+ case SID_SORT_DESCENDING:
+ case SCITEM_SORTDATA:
+ case SCITEM_SUBTDATA:
+ case SID_OPENDLG_PIVOTTABLE:
+ {
+ //! move ReadOnly check to idl flags
+
+ if ( pDocSh->IsReadOnly() || rDoc.GetChangeTrack()!=nullptr ||
+ GetViewData().IsMultiMarked() )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case SID_REIMPORT_DATA:
+ {
+ // only imported data without selection
+ ScDBData* pDBData = pTabViewShell->GetDBData(false,SC_DB_OLD);
+ if (!pDBData || !pDBData->HasImportParam() || pDBData->HasImportSelection() ||
+ rDoc.GetChangeTrack()!=nullptr)
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case SID_VIEW_DATA_SOURCE_BROWSER:
+ {
+ if (!SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::EModule::DATABASE))
+ rSet.Put(SfxVisibilityItem(nWhich, false));
+ else
+ // get state (BoolItem) from SfxViewFrame
+ pTabViewShell->GetViewFrame()->GetSlotState( nWhich, nullptr, &rSet );
+ }
+ break;
+ case SID_SBA_BRW_INSERT:
+ {
+ // SBA wants a sal_Bool-item, enabled
+
+ rSet.Put(SfxBoolItem(nWhich, true));
+ }
+ break;
+
+ case SID_AUTO_FILTER:
+ case SID_AUTOFILTER_HIDE:
+ {
+ if (!bAutoFilterTested)
+ {
+ bAutoFilter = rDoc.HasAutoFilter( nPosX, nPosY, nTab );
+ bAutoFilterTested = true;
+ }
+ if ( nWhich == SID_AUTO_FILTER )
+ {
+ ScRange aDummy;
+ ScMarkType eMarkType = GetViewData().GetSimpleArea( aDummy);
+ if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED)
+ {
+ rSet.DisableItem( nWhich );
+ }
+ else if (rDoc.GetDPAtBlock(aDummy))
+ {
+ rSet.DisableItem( nWhich );
+ }
+ else
+ rSet.Put( SfxBoolItem( nWhich, bAutoFilter ) );
+ }
+ else
+ if (!bAutoFilter)
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_UNFILTER:
+ {
+ SCCOL nStartCol, nEndCol;
+ SCROW nStartRow, nEndRow;
+ SCTAB nStartTab, nEndTab;
+ bool bAnyQuery = false;
+
+ bool bSelected = (GetViewData().GetSimpleArea(
+ nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab )
+ == SC_MARK_SIMPLE);
+
+ if ( bSelected )
+ {
+ if (nStartCol==nEndCol && nStartRow==nEndRow)
+ bSelected = false;
+ }
+ else
+ {
+ nStartCol = GetViewData().GetCurX();
+ nStartRow = GetViewData().GetCurY();
+ nStartTab = GetViewData().GetTabNo();
+ }
+
+ ScDBData* pDBData = bSelected
+ ? rDoc.GetDBAtArea( nStartTab, nStartCol, nStartRow, nEndCol, nEndRow )
+ : rDoc.GetDBAtCursor( nStartCol, nStartRow, nStartTab, ScDBDataPortion::AREA );
+
+ if ( pDBData )
+ {
+ ScQueryParam aParam;
+ pDBData->GetQueryParam( aParam );
+ if ( aParam.GetEntry(0).bDoQuery )
+ bAnyQuery = true;
+ }
+
+ if ( !bAnyQuery )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_DEFINE_DBNAME:
+ {
+ if ( pDocSh->IsDocShared() )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+ case SID_DATA_PROVIDER:
+ break;
+ case SID_DATA_PROVIDER_REFRESH:
+ {
+ ScDocument& rViewDoc = GetViewData().GetDocument();
+ auto& rDataMapper = rViewDoc.GetExternalDataMapper();
+ if (rDataMapper.getDataSources().empty())
+ rSet.DisableItem(nWhich);
+ }
+ break;
+ case SID_DATA_STREAMS:
+ case SID_DATA_STREAMS_PLAY:
+ case SID_DATA_STREAMS_STOP:
+ {
+ if ( !officecfg::Office::Common::Misc::ExperimentalMode::get() )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+ case SID_TEXT_TO_COLUMNS:
+ {
+ ScRange aRange;
+ if ( !lcl_GetTextToColumnsRange( rData, aRange, true ) )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+ case SID_MANAGE_XML_SOURCE:
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/cellsh3.cxx b/sc/source/ui/view/cellsh3.cxx
new file mode 100644
index 000000000..a0d08a605
--- /dev/null
+++ b/sc/source/ui/view/cellsh3.cxx
@@ -0,0 +1,1067 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editeng.hxx>
+#include <formula/formulahelper.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/request.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <scmod.hxx>
+#include <appoptio.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <sc.hrc>
+#include <reffact.hxx>
+#include <uiitems.hxx>
+#include <autoform.hxx>
+#include <cellsh.hxx>
+#include <inputhdl.hxx>
+#include <editable.hxx>
+#include <funcdesc.hxx>
+#include <markdata.hxx>
+#include <scabstdlg.hxx>
+#include <columnspanset.hxx>
+#include <comphelper/lok.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <inputwin.hxx>
+
+#include <memory>
+
+using sc::TwipsToEvenHMM;
+
+namespace
+{
+/// Rid ourselves of unwanted " quoted json characters.
+OString escapeJSON(const OUString &aStr)
+{
+ OUString aEscaped = aStr;
+ aEscaped = aEscaped.replaceAll("\n", " ");
+ aEscaped = aEscaped.replaceAll("\"", "'");
+ return OUStringToOString(aEscaped, RTL_TEXTENCODING_UTF8);
+}
+
+void lcl_lokGetWholeFunctionList()
+{
+ const SfxViewShell* pViewShell = SfxViewShell::Current();
+ if (!(comphelper::LibreOfficeKit::isActive()
+ && pViewShell && pViewShell->isLOKMobilePhone()))
+ return;
+
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ sal_uInt32 nListCount = pFuncList->GetCount();
+ std::set<OUString> aFuncNameOrderedSet;
+ for(sal_uInt32 i = 0; i < nListCount; ++i)
+ {
+ const ScFuncDesc* pDesc = pFuncList->GetFunction( i );
+ if ( pDesc->mxFuncName )
+ {
+ aFuncNameOrderedSet.insert(*pDesc->mxFuncName);
+ }
+ }
+ ScFunctionMgr* pFuncManager = ScGlobal::GetStarCalcFunctionMgr();
+ if (!(pFuncManager && aFuncNameOrderedSet.size()))
+ return;
+
+ OStringBuffer aPayload;
+ aPayload.append("{ \"wholeList\": true, ");
+ aPayload.append("\"categories\": [ ");
+
+ formula::FormulaHelper aHelper(pFuncManager);
+ sal_uInt32 nCategoryCount = pFuncManager->getCount();
+ for (sal_uInt32 i = 0; i < nCategoryCount; ++i)
+ {
+ OUString sCategoryName = ScFunctionMgr::GetCategoryName(i);
+ aPayload.append("{");
+ aPayload.append("\"name\": \"");
+ aPayload.append(escapeJSON(sCategoryName));
+ aPayload.append("\"}, ");
+ }
+ sal_Int32 nLen = aPayload.getLength();
+ aPayload[nLen - 2] = ' ';
+ aPayload[nLen - 1] = ']';
+ aPayload.append(", ");
+
+ OUString aDescFuncNameStr;
+ aPayload.append("\"functions\": [ ");
+ sal_uInt32 nCurIndex = 0;
+ for (const OUString& aFuncNameStr : aFuncNameOrderedSet)
+ {
+ aDescFuncNameStr = aFuncNameStr + "()";
+ sal_Int32 nNextFStart = 0;
+ const formula::IFunctionDescription* ppFDesc;
+ ::std::vector< OUString > aArgs;
+ OUString eqPlusFuncName = "=" + aDescFuncNameStr;
+ if ( aHelper.GetNextFunc( eqPlusFuncName, false, nNextFStart, nullptr, &ppFDesc, &aArgs ) )
+ {
+ if ( ppFDesc && !ppFDesc->getFunctionName().isEmpty() )
+ {
+ if (ppFDesc->getCategory())
+ {
+ aPayload.append("{");
+ aPayload.append("\"index\": ");
+ aPayload.append(static_cast<sal_Int64>(nCurIndex));
+ aPayload.append(", ");
+ aPayload.append("\"category\": ");
+ aPayload.append(static_cast<sal_Int64>(ppFDesc->getCategory()->getNumber()));
+ aPayload.append(", ");
+ aPayload.append("\"signature\": \"");
+ aPayload.append(escapeJSON(ppFDesc->getSignature()));
+ aPayload.append("\", ");
+ aPayload.append("\"description\": \"");
+ aPayload.append(escapeJSON(ppFDesc->getDescription()));
+ aPayload.append("\"}, ");
+ }
+ }
+ }
+ ++nCurIndex;
+ }
+ nLen = aPayload.getLength();
+ aPayload[nLen - 2] = ' ';
+ aPayload[nLen - 1] = ']';
+ aPayload.append(" }");
+
+ OString s = aPayload.makeStringAndClear();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CALC_FUNCTION_LIST, s.getStr());
+}
+
+} // end namespace
+
+void ScCellShell::Execute( SfxRequest& rReq )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ SfxBindings& rBindings = pTabViewShell->GetViewFrame()->GetBindings();
+ ScModule* pScMod = SC_MOD();
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ if (nSlot != SID_CURRENTCELL) // this comes with MouseButtonUp
+ pTabViewShell->HideListBox(); // Autofilter-DropDown-Listbox
+
+ if ( GetViewData().HasEditView( GetViewData().GetActivePart() ) )
+ {
+ switch ( nSlot )
+ {
+ // when opening a reference-dialog the subshell may not be switched
+ // (on closing the dialog StopEditShell is called)
+ case SID_OPENDLG_FUNCTION:
+ // inplace leads to trouble with EditShell ...
+ //! cannot always be switched ????
+ if (!pTabViewShell->GetViewFrame()->GetFrame().IsInPlace())
+ pTabViewShell->SetDontSwitch(true); // do not switch off EditShell
+ [[fallthrough]];
+
+ case FID_CELL_FORMAT:
+ case SID_ENABLE_HYPHENATION:
+ case SID_DATA_SELECT:
+ case SID_OPENDLG_CONSOLIDATE:
+ case SID_OPENDLG_SOLVE:
+ case SID_OPENDLG_OPTSOLVER:
+
+ pScMod->InputEnterHandler();
+ pTabViewShell->UpdateInputHandler();
+
+ pTabViewShell->SetDontSwitch(false);
+
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ switch ( nSlot )
+ {
+ case SID_STATUS_SELMODE:
+ if ( pReqArgs )
+ {
+ /* 0: STD Click cancels selection
+ * 1: ER Click extends selection
+ * 2: ERG Click defines further selection
+ */
+ sal_uInt16 nMode = static_cast<const SfxUInt16Item&>(pReqArgs->Get( nSlot )).GetValue();
+
+ switch ( nMode )
+ {
+ case 1: nMode = KEY_SHIFT; break;
+ case 2: nMode = KEY_MOD1; break; // control-key
+ case 0:
+ default:
+ nMode = 0;
+ }
+
+ pTabViewShell->LockModifiers( nMode );
+ }
+ else
+ {
+ // no arguments (also executed by double click on the status bar controller):
+ // advance to next selection mode
+
+ sal_uInt16 nModifiers = pTabViewShell->GetLockedModifiers();
+ switch ( nModifiers )
+ {
+ case KEY_SHIFT: nModifiers = KEY_MOD1; break; // EXT -> ADD
+ case KEY_MOD1: nModifiers = 0; break; // ADD -> STD
+ default: nModifiers = KEY_SHIFT; break; // STD -> EXT
+ }
+ pTabViewShell->LockModifiers( nModifiers );
+ }
+
+ rBindings.Invalidate( SID_STATUS_SELMODE );
+ rReq.Done();
+ break;
+
+ // SID_STATUS_SELMODE_NORM is not used ???
+
+ case SID_STATUS_SELMODE_NORM:
+ pTabViewShell->LockModifiers( 0 );
+ rBindings.Invalidate( SID_STATUS_SELMODE );
+ break;
+
+ // SID_STATUS_SELMODE_ERG / SID_STATUS_SELMODE_ERW as toggles:
+
+ case SID_STATUS_SELMODE_ERG:
+ if ( pTabViewShell->GetLockedModifiers() & KEY_MOD1 )
+ pTabViewShell->LockModifiers( 0 );
+ else
+ pTabViewShell->LockModifiers( KEY_MOD1 );
+ rBindings.Invalidate( SID_STATUS_SELMODE );
+ break;
+
+ case SID_STATUS_SELMODE_ERW:
+ if ( pTabViewShell->GetLockedModifiers() & KEY_SHIFT )
+ pTabViewShell->LockModifiers( 0 );
+ else
+ pTabViewShell->LockModifiers( KEY_SHIFT );
+ rBindings.Invalidate( SID_STATUS_SELMODE );
+ break;
+
+ case SID_ENTER_STRING:
+ {
+ if ( pReqArgs )
+ {
+ // In the LOK case, we want to set the document modified state
+ // right away at the start of the edit, so that the content is
+ // saved even when the user leaves the document before hitting
+ // Enter
+ // NOTE: This also means we want to set the modified state
+ // regardless of the DontCommit parameter's value.
+ if (comphelper::LibreOfficeKit::isActive() && !GetViewData().GetDocShell()->IsModified())
+ {
+ GetViewData().GetDocShell()->SetModified();
+ rBindings.Invalidate(SID_SAVEDOC);
+ rBindings.Invalidate(SID_DOC_MODIFIED);
+ }
+
+ OUString aStr( static_cast<const SfxStringItem&>(pReqArgs->
+ Get( SID_ENTER_STRING )).GetValue() );
+ const SfxPoolItem* pDontCommitItem;
+ bool bCommit = true;
+ if (pReqArgs->HasItem(FN_PARAM_1, &pDontCommitItem))
+ bCommit = !(static_cast<const SfxBoolItem*>(pDontCommitItem)->GetValue());
+
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl( pTabViewShell );
+ if (bCommit)
+ {
+ pTabViewShell->EnterData( GetViewData().GetCurX(),
+ GetViewData().GetCurY(),
+ GetViewData().GetTabNo(),
+ aStr, nullptr,
+ true /*bMatrixExpand*/);
+ }
+ else if (pHdl)
+ {
+ SC_MOD()->SetInputMode(SC_INPUT_TABLE);
+
+ EditView* pTableView = pHdl->GetActiveView();
+ pHdl->DataChanging();
+ if (pTableView)
+ pTableView->GetEditEngine()->SetText(aStr);
+ pHdl->DataChanged();
+
+ SC_MOD()->SetInputMode(SC_INPUT_NONE);
+ }
+
+ if ( !pHdl || !pHdl->IsInEnterHandler() )
+ {
+ // UpdateInputHandler is needed after the cell content
+ // has changed, but if called from EnterHandler, UpdateInputHandler
+ // will be called later when moving the cursor.
+ pTabViewShell->UpdateInputHandler();
+ }
+
+ rReq.Done();
+
+ // no GrabFocus here, as otherwise on a Mac the tab jumps before the
+ // sideview, when the input was not finished
+ // (GrabFocus is called in KillEditView)
+ }
+ }
+ break;
+
+ case SID_INSERT_MATRIX:
+ {
+ if ( pReqArgs )
+ {
+ OUString aStr = static_cast<const SfxStringItem&>(pReqArgs->
+ Get( SID_INSERT_MATRIX )).GetValue();
+ ScDocument& rDoc = GetViewData().GetDocument();
+ pTabViewShell->EnterMatrix( aStr, rDoc.GetGrammar() );
+ rReq.Done();
+ }
+ }
+ break;
+
+ case FID_INPUTLINE_ENTER:
+ case FID_INPUTLINE_BLOCK:
+ case FID_INPUTLINE_MATRIX:
+ {
+ if( pReqArgs == nullptr ) //XXX temporary HACK to avoid GPF
+ break;
+
+ const ScInputStatusItem* pStatusItem
+ = static_cast<const ScInputStatusItem*>(&pReqArgs->
+ Get( FID_INPUTLINE_STATUS ));
+
+ const ScAddress& aCursorPos = pStatusItem->GetPos();
+ const OUString& aString = pStatusItem->GetString();
+ const EditTextObject* pData = pStatusItem->GetEditData();
+
+ if (pData)
+ {
+ if (nSlot == FID_INPUTLINE_BLOCK)
+ {
+ pTabViewShell->EnterBlock( aString, pData );
+ }
+ else if ( !aString.isEmpty() && ( aString[0] == '=' || aString[0] == '+' || aString[0] == '-' ) )
+ {
+ pTabViewShell->EnterData( aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(),
+ aString, pData, true /*bMatrixExpand*/);
+ }
+ else
+ {
+ pTabViewShell->EnterData(aCursorPos.Col(), aCursorPos.Row(), aCursorPos.Tab(), *pData);
+ }
+ }
+ else
+ {
+ if (nSlot == FID_INPUTLINE_ENTER)
+ {
+ if (
+ aCursorPos.Col() == GetViewData().GetCurX() &&
+ aCursorPos.Row() == GetViewData().GetCurY() &&
+ aCursorPos.Tab() == GetViewData().GetTabNo()
+ )
+ {
+ SfxStringItem aItem( SID_ENTER_STRING, aString );
+
+ const SfxPoolItem* aArgs[2];
+ aArgs[0] = &aItem;
+ aArgs[1] = nullptr;
+ rBindings.Execute( SID_ENTER_STRING, aArgs );
+ }
+ else
+ {
+ pTabViewShell->EnterData( aCursorPos.Col(),
+ aCursorPos.Row(),
+ aCursorPos.Tab(),
+ aString, nullptr,
+ true /*bMatrixExpand*/);
+ rReq.Done();
+ }
+ }
+ else if (nSlot == FID_INPUTLINE_BLOCK)
+ {
+ pTabViewShell->EnterBlock( aString, nullptr );
+ rReq.Done();
+ }
+ else
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ pTabViewShell->EnterMatrix( aString, rDoc.GetGrammar() );
+ rReq.Done();
+ }
+ }
+
+ pTabViewShell->SetAutoSpellData(
+ aCursorPos.Col(), aCursorPos.Row(), pStatusItem->GetMisspellRanges());
+
+ // no GrabFocus here, as otherwise on a Mac the tab jumps before the
+ // sideview, when the input was not finished
+ // (GrabFocus is called in KillEditView)
+ }
+ break;
+
+ case SID_OPENDLG_FUNCTION:
+ {
+ const SfxViewShell* pViewShell = SfxViewShell::Current();
+ if (comphelper::LibreOfficeKit::isActive()
+ && pViewShell && pViewShell->isLOKMobilePhone())
+ {
+ // not set the dialog id in the mobile case or we would
+ // not be able to get cell address pasted in the edit view
+ // by just tapping on them
+ lcl_lokGetWholeFunctionList();
+ }
+ else
+ {
+ sal_uInt16 nId = SID_OPENDLG_FUNCTION;
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+ bool bVis = comphelper::LibreOfficeKit::isActive() || pWnd == nullptr;
+ pScMod->SetRefDialog( nId, bVis );
+ }
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_OPENDLG_CONSOLIDATE:
+ {
+ sal_uInt16 nId = ScConsolidateDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+
+ case FID_CELL_FORMAT:
+ {
+ if ( pReqArgs != nullptr )
+ {
+
+ // set cell attribute without dialog:
+
+ SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aEmptySet( *pReqArgs->GetPool() );
+
+ SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aNewSet( *pReqArgs->GetPool() );
+
+ const SfxPoolItem* pAttr = nullptr;
+ sal_uInt16 nWhich = 0;
+
+ for ( nWhich=ATTR_PATTERN_START; nWhich<=ATTR_PATTERN_END; nWhich++ )
+ if ( pReqArgs->GetItemState( nWhich, true, &pAttr ) == SfxItemState::SET )
+ aNewSet.Put( *pAttr );
+
+ pTabViewShell->ApplyAttributes( &aNewSet, &aEmptySet );
+
+ rReq.Done();
+ }
+ else
+ {
+ pTabViewShell->ExecuteCellFormatDlg( rReq, "" );
+ }
+ }
+ break;
+
+ case SID_ENABLE_HYPHENATION:
+ pTabViewShell->ExecuteCellFormatDlg(rReq, "alignment");
+ break;
+
+ case SID_PROPERTY_PANEL_CELLTEXT_DLG:
+ pTabViewShell->ExecuteCellFormatDlg( rReq, "font" );
+ break;
+
+ case SID_CELL_FORMAT_BORDER:
+ pTabViewShell->ExecuteCellFormatDlg( rReq, "borders" );
+ break;
+
+ case SID_CHAR_DLG_EFFECT:
+ pTabViewShell->ExecuteCellFormatDlg( rReq, "fonteffects" );
+ break;
+
+ case SID_OPENDLG_SOLVE:
+ {
+ sal_uInt16 nId = ScSolverDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+
+ case SID_OPENDLG_OPTSOLVER:
+ {
+ sal_uInt16 nId = ScOptSolverDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+
+ case SID_OPENDLG_TABOP:
+ {
+ sal_uInt16 nId = ScTabOpDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = pTabViewShell->GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+
+ case SID_SCENARIOS:
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ SCTAB nTab = GetViewData().GetTabNo();
+
+ if ( rDoc.IsScenario(nTab) )
+ {
+ rMark.MarkToMulti();
+ if ( rMark.IsMultiMarked() )
+ {
+
+ bool bExtend = rReq.IsAPI();
+ if (!bExtend)
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(pTabViewShell->GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_UPDATE_SCENARIO)));
+ xQueryBox->set_default_response(RET_YES);
+ bExtend = xQueryBox->run() == RET_YES;
+ }
+
+ if (bExtend)
+ {
+ pTabViewShell->ExtendScenario();
+ rReq.Done();
+ }
+ }
+ else if( ! rReq.IsAPI() )
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pTabViewShell->GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(STR_NOAREASELECTED)));
+ xErrorBox->run();
+ }
+ }
+ else
+ {
+ rMark.MarkToMulti();
+ if ( rMark.IsMultiMarked() )
+ {
+ SCTAB i=1;
+ OUString aBaseName;
+ OUString aName;
+ Color aColor;
+ ScScenarioFlags nFlags;
+
+ OUString aTmp;
+ rDoc.GetName(nTab, aTmp);
+ aBaseName = aTmp + "_" + ScResId(STR_SCENARIO) + "_";
+
+ // first test, if the prefix is recognised as valid,
+ // else avoid only doubles
+ bool bPrefix = ScDocument::ValidTabName( aBaseName );
+ OSL_ENSURE(bPrefix, "invalid sheet name");
+
+ while ( rDoc.IsScenario(nTab+i) )
+ i++;
+
+ bool bValid;
+ SCTAB nDummy;
+ do
+ {
+ aName = aBaseName + OUString::number( i );
+ if (bPrefix)
+ bValid = rDoc.ValidNewTabName( aName );
+ else
+ bValid = !rDoc.GetTable( aName, nDummy );
+ ++i;
+ }
+ while ( !bValid && i <= MAXTAB + 2 );
+
+ if ( pReqArgs != nullptr )
+ {
+ OUString aArgName;
+ OUString aArgComment;
+ if ( const SfxStringItem* pItem = pReqArgs->GetItemIfSet( SID_SCENARIOS ) )
+ aArgName = pItem->GetValue();
+ if ( const SfxStringItem* pItem = pReqArgs->GetItemIfSet( SID_NEW_TABLENAME ) )
+ aArgComment = pItem->GetValue();
+
+ aColor = COL_LIGHTGRAY; // Default
+ nFlags = ScScenarioFlags::NONE; // not TwoWay
+
+ pTabViewShell->MakeScenario( aArgName, aArgComment, aColor, nFlags );
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+ }
+ else
+ {
+ bool bSheetProtected = rDoc.IsTabProtected(nTab);
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScNewScenarioDlg> pNewDlg(pFact->CreateScNewScenarioDlg(pTabViewShell->GetFrameWeld(), aName, false, bSheetProtected));
+ if ( pNewDlg->Execute() == RET_OK )
+ {
+ OUString aComment;
+ pNewDlg->GetScenarioData( aName, aComment, aColor, nFlags );
+ pTabViewShell->MakeScenario( aName, aComment, aColor, nFlags );
+
+ rReq.AppendItem( SfxStringItem( SID_SCENARIOS, aName ) );
+ rReq.AppendItem( SfxStringItem( SID_NEW_TABLENAME, aComment ) );
+ rReq.Done();
+ }
+ }
+ }
+ else if( ! rReq.IsAPI() )
+ {
+ pTabViewShell->ErrorMessage(STR_ERR_NEWSCENARIO);
+ }
+ }
+ }
+ break;
+
+ case SID_SELECTALL:
+ {
+ pTabViewShell->SelectAll();
+ rReq.Done();
+ }
+ break;
+
+ case FID_ROW_HEIGHT:
+ {
+ const SfxPoolItem* pRow;
+ const SfxUInt16Item* pHeight;
+ sal_uInt16 nHeight;
+
+ if ( pReqArgs && (pHeight = pReqArgs->GetItemIfSet( FID_ROW_HEIGHT )) &&
+ pReqArgs->HasItem( FN_PARAM_1, &pRow ) )
+ {
+ std::vector<sc::ColRowSpan> aRanges;
+ SCCOLROW nRow = static_cast<const SfxInt32Item*>(pRow)->GetValue() - 1;
+ nHeight = pHeight->GetValue();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+
+ if ( rMark.IsRowMarked( static_cast<SCROW>(nRow) ) )
+ {
+ aRanges = rMark.GetMarkedRowSpans();
+ }
+ else
+ {
+ aRanges.emplace_back(nRow, nRow);
+ }
+
+ pTabViewShell->SetWidthOrHeight(false, aRanges, SC_SIZE_DIRECT, o3tl::toTwips(nHeight, o3tl::Length::mm100));
+ }
+ else if ( pReqArgs && (pHeight = pReqArgs->GetItemIfSet( FID_ROW_HEIGHT )) )
+ {
+ nHeight = pHeight->GetValue();
+
+ // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
+ pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_DIRECT,
+ o3tl::toTwips(nHeight, o3tl::Length::mm100));
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+ }
+ else
+ {
+ ScViewData& rData = GetViewData();
+ FieldUnit eMetric = SC_MOD()->GetAppOptions().GetAppMetric();
+ sal_uInt16 nCurHeight = rData.GetDocument().
+ GetRowHeight( rData.GetCurY(),
+ rData.GetTabNo() );
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
+ pTabViewShell->GetFrameWeld(), "RowHeightDialog",
+ nCurHeight, ScGlobal::nStdRowHeight,
+ eMetric, 2, MAX_ROW_HEIGHT));
+
+ if ( pDlg->Execute() == RET_OK )
+ {
+ tools::Long nVal = pDlg->GetInputValue();
+ pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_DIRECT, static_cast<sal_uInt16>(nVal) );
+
+ // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
+ rReq.AppendItem( SfxUInt16Item( FID_ROW_HEIGHT, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal)) ) );
+ rReq.Done();
+
+ }
+ }
+ }
+ break;
+
+ case FID_ROW_OPT_HEIGHT:
+ {
+ if ( pReqArgs )
+ {
+ const SfxUInt16Item& rUInt16Item = static_cast<const SfxUInt16Item&>(pReqArgs->Get( FID_ROW_OPT_HEIGHT ));
+
+ // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
+ pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_OPTIMAL,
+ o3tl::toTwips(rUInt16Item.GetValue(), o3tl::Length::mm100) );
+ ScGlobal::nLastRowHeightExtra = rUInt16Item.GetValue();
+
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+ }
+ else
+ {
+ FieldUnit eMetric = SC_MOD()->GetAppOptions().GetAppMetric();
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
+ pTabViewShell->GetFrameWeld(), "OptimalRowHeightDialog",
+ ScGlobal::nLastRowHeightExtra, 0, eMetric, 2, MAX_EXTRA_HEIGHT));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ tools::Long nVal = pDlg->GetInputValue();
+ pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_OPTIMAL, static_cast<sal_uInt16>(nVal) );
+ ScGlobal::nLastRowHeightExtra = nVal;
+
+ // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
+ rReq.AppendItem( SfxUInt16Item( FID_ROW_OPT_HEIGHT, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal)) ) );
+ rReq.Done();
+
+ }
+ }
+ }
+ break;
+
+ case FID_COL_WIDTH:
+ {
+ const SfxPoolItem* pColumn;
+ const SfxUInt16Item* pWidth;
+ sal_uInt16 nWidth;
+
+ if ( pReqArgs && (pWidth = pReqArgs->GetItemIfSet( FID_COL_WIDTH )) &&
+ pReqArgs->HasItem( FN_PARAM_1, &pColumn ) )
+ {
+ std::vector<sc::ColRowSpan> aRanges;
+ SCCOLROW nColumn = static_cast<const SfxUInt16Item*>(pColumn)->GetValue() - 1;
+ nWidth = pWidth->GetValue();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+
+ if ( rMark.IsColumnMarked( static_cast<SCCOL>(nColumn) ) )
+ {
+ aRanges = rMark.GetMarkedColSpans();
+ }
+ else
+ {
+ aRanges.emplace_back(nColumn, nColumn);
+ }
+
+ pTabViewShell->SetWidthOrHeight(true, aRanges, SC_SIZE_DIRECT, o3tl::toTwips(nWidth, o3tl::Length::mm100));
+ }
+ else if ( pReqArgs && (pWidth = pReqArgs->GetItemIfSet( FID_COL_WIDTH )) )
+ {
+ nWidth = pWidth->GetValue();
+
+ // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
+ pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_DIRECT,
+ o3tl::toTwips(nWidth, o3tl::Length::mm100));
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+ }
+ else
+ {
+ FieldUnit eMetric = SC_MOD()->GetAppOptions().GetAppMetric();
+ ScViewData& rData = GetViewData();
+ sal_uInt16 nCurHeight = rData.GetDocument().
+ GetColWidth( rData.GetCurX(),
+ rData.GetTabNo() );
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
+ pTabViewShell->GetFrameWeld(), "ColWidthDialog", nCurHeight,
+ STD_COL_WIDTH, eMetric, 2, MAX_COL_WIDTH));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ tools::Long nVal = pDlg->GetInputValue();
+ pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_DIRECT, static_cast<sal_uInt16>(nVal) );
+
+ // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
+ rReq.AppendItem( SfxUInt16Item( FID_COL_WIDTH, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal))) );
+ rReq.Done();
+
+ }
+ }
+ }
+ break;
+
+ case FID_COL_OPT_WIDTH:
+ {
+ if ( pReqArgs )
+ {
+ const SfxUInt16Item& rUInt16Item = static_cast<const SfxUInt16Item&>(pReqArgs->Get( FID_COL_OPT_WIDTH ));
+
+ // #101390#; the value of the macro is in HMM so use convertMm100ToTwip to convert
+ pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_OPTIMAL,
+ o3tl::toTwips(rUInt16Item.GetValue(), o3tl::Length::mm100) );
+ ScGlobal::nLastColWidthExtra = rUInt16Item.GetValue();
+
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+ }
+ else
+ {
+ FieldUnit eMetric = SC_MOD()->GetAppOptions().GetAppMetric();
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractScMetricInputDlg> pDlg(pFact->CreateScMetricInputDlg(
+ pTabViewShell->GetFrameWeld(), "OptimalColWidthDialog",
+ ScGlobal::nLastColWidthExtra, STD_EXTRA_WIDTH, eMetric, 2, MAX_EXTRA_WIDTH));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ tools::Long nVal = pDlg->GetInputValue();
+ pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_OPTIMAL, static_cast<sal_uInt16>(nVal) );
+ ScGlobal::nLastColWidthExtra = nVal;
+
+ // #101390#; the value of the macro should be in HMM so use TwipsToEvenHMM to convert
+ rReq.AppendItem( SfxUInt16Item( FID_COL_OPT_WIDTH, static_cast<sal_uInt16>(TwipsToEvenHMM(nVal)) ) );
+ rReq.Done();
+ }
+ }
+ }
+ break;
+
+ case FID_COL_OPT_DIRECT:
+ pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_OPTIMAL, STD_EXTRA_WIDTH );
+ rReq.Done();
+ break;
+
+ case FID_ROW_HIDE:
+ pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_DIRECT, 0 );
+ rReq.Done();
+ break;
+ case FID_ROW_SHOW:
+ pTabViewShell->SetMarkedWidthOrHeight( false, SC_SIZE_SHOW, 0 );
+ rReq.Done();
+ break;
+ case FID_COL_HIDE:
+ pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_DIRECT, 0 );
+ rReq.Done();
+ break;
+ case FID_COL_SHOW:
+ pTabViewShell->SetMarkedWidthOrHeight( true, SC_SIZE_SHOW, 0 );
+ rReq.Done();
+ break;
+
+ case SID_CELL_FORMAT_RESET:
+ {
+ pTabViewShell->DeleteContents( InsertDeleteFlags::HARDATTR | InsertDeleteFlags::EDITATTR );
+ rReq.Done();
+ }
+ break;
+
+ case FID_MERGE_ON:
+ case FID_MERGE_OFF:
+ case FID_MERGE_TOGGLE:
+ {
+ if ( !GetViewData().GetDocument().GetChangeTrack() )
+ {
+ // test whether to merge or to split
+ bool bMerge = false;
+ bool bCenter = false;
+ switch( nSlot )
+ {
+ case FID_MERGE_ON:
+ bMerge = true;
+ break;
+ case FID_MERGE_OFF:
+ bMerge = false;
+ break;
+ case FID_MERGE_TOGGLE:
+ {
+ bCenter = true;
+ std::unique_ptr<SfxPoolItem> pItem;
+ if( rBindings.QueryState( nSlot, pItem ) >= SfxItemState::DEFAULT )
+ bMerge = !static_cast< SfxBoolItem* >( pItem.get() )->GetValue();
+ }
+ break;
+ }
+
+ if( bMerge )
+ {
+ // merge - check if to move contents of covered cells
+ bool bMoveContents = false;
+ bool bApi = rReq.IsAPI();
+ const SfxPoolItem* pItem;
+ if ( pReqArgs &&
+ pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
+ {
+ assert(dynamic_cast<const SfxBoolItem*>( pItem) && "wrong item");
+ bMoveContents = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ }
+
+ if (pTabViewShell->MergeCells( bApi, bMoveContents, bCenter ))
+ {
+ if (!bApi && bMoveContents) // "yes" clicked in dialog
+ rReq.AppendItem( SfxBoolItem( nSlot, bMoveContents ) );
+ rBindings.Invalidate( nSlot );
+ rReq.Done();
+ }
+ }
+ else
+ {
+ // split cells
+ if (pTabViewShell->RemoveMerge())
+ {
+ rBindings.Invalidate( nSlot );
+ rReq.Done();
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ case SID_AUTOFORMAT:
+ {
+ weld::Window* pDlgParent = pTabViewShell->GetFrameWeld();
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCTAB nStartTab;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ SCTAB nEndTab;
+
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
+ pTabViewShell->MarkDataArea();
+
+ GetViewData().GetSimpleArea( nStartCol,nStartRow,nStartTab,
+ nEndCol,nEndRow,nEndTab );
+
+ if ( ( std::abs(nEndCol-nStartCol) > 1 )
+ && ( std::abs(nEndRow-nStartRow) > 1 ) )
+ {
+ if ( pReqArgs )
+ {
+ const SfxStringItem& rNameItem = pReqArgs->Get( SID_AUTOFORMAT );
+ ScAutoFormat* pFormat = ScGlobal::GetOrCreateAutoFormat();
+ ScAutoFormat::const_iterator it = pFormat->find(rNameItem.GetValue());
+ ScAutoFormat::const_iterator itBeg = pFormat->begin();
+ size_t nIndex = std::distance(itBeg, it);
+
+ pTabViewShell->AutoFormat( nIndex );
+
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+ }
+ else
+ {
+ ScGlobal::ClearAutoFormat();
+ std::unique_ptr<ScAutoFormatData> pNewEntry(pTabViewShell->CreateAutoFormatData());
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScAutoFormatDlg> pDlg(pFact->CreateScAutoFormatDlg(pDlgParent, ScGlobal::GetOrCreateAutoFormat(), pNewEntry.get(), GetViewData()));
+
+ if ( pDlg->Execute() == RET_OK )
+ {
+ ScEditableTester aTester( pTabViewShell );
+ if ( !aTester.IsEditable() )
+ {
+ pTabViewShell->ErrorMessage(aTester.GetMessageId());
+ }
+ else
+ {
+ pTabViewShell->AutoFormat( pDlg->GetIndex() );
+
+ rReq.AppendItem( SfxStringItem( SID_AUTOFORMAT, pDlg->GetCurrFormatName() ) );
+ rReq.Done();
+ }
+ }
+ }
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(pDlgParent,
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(STR_INVALID_AFAREA)));
+ xErrorBox->run();
+ }
+ }
+ break;
+
+ case SID_CANCEL:
+ {
+ if (GetViewData().HasEditView(GetViewData().GetActivePart()))
+ pScMod->InputCancelHandler();
+ else if (pTabViewShell->HasPaintBrush())
+ pTabViewShell->ResetBrushDocument(); // abort format paint brush
+ else if (pTabViewShell->HasHintWindow())
+ pTabViewShell->RemoveHintWindow();
+ else if( ScViewUtil::IsFullScreen( *pTabViewShell ) )
+ ScViewUtil::SetFullScreen( *pTabViewShell, false );
+ else
+ {
+ // TODO/LATER: when is this code executed?
+ pTabViewShell->Escape();
+ }
+ }
+ break;
+
+ case SID_ACCEPT_FORMULA:
+ {
+ if (GetViewData().HasEditView(GetViewData().GetActivePart()))
+ pScMod->InputEnterHandler();
+ }
+ break;
+
+ case SID_START_FORMULA:
+ {
+ ScInputHandler* pInputHandler = pScMod->GetInputHdl();
+ if (pInputHandler && pInputHandler->GetInputWindow())
+ pInputHandler->GetInputWindow()->StartFormula();
+ }
+ break;
+
+ case SID_DATA_SELECT:
+ pTabViewShell->StartDataSelect();
+ break;
+
+ case SID_DETECTIVE_FILLMODE:
+ {
+ bool bOldMode = pTabViewShell->IsAuditShell();
+ pTabViewShell->SetAuditShell( !bOldMode );
+ pTabViewShell->Invalidate( nSlot );
+ }
+ break;
+
+ case FID_INPUTLINE_STATUS:
+ OSL_FAIL("Execute from InputLine status");
+ break;
+
+ case SID_STATUS_DOCPOS:
+ // Launch navigator.
+ GetViewData().GetDispatcher().Execute(
+ SID_NAVIGATOR, SfxCallMode::SYNCHRON|SfxCallMode::RECORD );
+ break;
+
+ case SID_MARKAREA:
+ // called from Basic at the hidden view to select a range in the visible view
+ OSL_FAIL("old slot SID_MARKAREA");
+ break;
+
+ default:
+ OSL_FAIL("ScCellShell::Execute: unknown slot");
+ break;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/cellsh4.cxx b/sc/source/ui/view/cellsh4.cxx
new file mode 100644
index 000000000..13d699363
--- /dev/null
+++ b/sc/source/ui/view/cellsh4.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 <sfx2/request.hxx>
+#include <osl/diagnose.h>
+
+#include <cellsh.hxx>
+#include <tabvwsh.hxx>
+#include <global.hxx>
+#include <scmod.hxx>
+#include <inputhdl.hxx>
+#include <inputwin.hxx>
+#include <document.hxx>
+#include <sc.hrc>
+
+void ScCellShell::ExecuteCursor( SfxRequest& rReq )
+{
+ ScViewData& rData = GetViewData();
+ ScTabViewShell* pTabViewShell = rData.GetViewShell();
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlotId = rReq.GetSlot();
+ SCCOLROW nRepeat = 1;
+ bool bSel = false;
+ bool bKeep = false;
+
+ if ( pReqArgs != nullptr )
+ {
+ const SfxPoolItem* pItem;
+ if (pReqArgs->HasItem(FN_PARAM_1, &pItem))
+ nRepeat = static_cast<SCCOLROW>(static_cast<const SfxInt16Item*>(pItem)->GetValue());
+ if (pReqArgs->HasItem(FN_PARAM_2, &pItem))
+ bSel = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ }
+ else
+ {
+ // evaluate locked selection mode
+
+ sal_uInt16 nLocked = pTabViewShell->GetLockedModifiers();
+ if ( nLocked & KEY_SHIFT )
+ bSel = true; // EXT
+ else if ( nLocked & KEY_MOD1 )
+ {
+ // ADD mode: keep the selection, start a new block when marking with shift again
+ bKeep = true;
+ }
+ }
+
+ if (bSel)
+ {
+ switch (nSlotId)
+ {
+ case SID_CURSORDOWN:
+ rReq.SetSlot(SID_CURSORDOWN_SEL);
+ break;
+ case SID_CURSORUP:
+ rReq.SetSlot(SID_CURSORUP_SEL);
+ break;
+ case SID_CURSORRIGHT:
+ rReq.SetSlot(SID_CURSORRIGHT_SEL);
+ break;
+ case SID_CURSORLEFT:
+ rReq.SetSlot(SID_CURSORLEFT_SEL);
+ break;
+ case SID_CURSORPAGEDOWN:
+ rReq.SetSlot(SID_CURSORPAGEDOWN_SEL);
+ break;
+ case SID_CURSORPAGEUP:
+ rReq.SetSlot(SID_CURSORPAGEUP_SEL);
+ break;
+ case SID_CURSORBLKDOWN:
+ rReq.SetSlot(SID_CURSORBLKDOWN_SEL);
+ break;
+ case SID_CURSORBLKUP:
+ rReq.SetSlot(SID_CURSORBLKUP_SEL);
+ break;
+ case SID_CURSORBLKRIGHT:
+ rReq.SetSlot(SID_CURSORBLKRIGHT_SEL);
+ break;
+ case SID_CURSORBLKLEFT:
+ rReq.SetSlot(SID_CURSORBLKLEFT_SEL);
+ break;
+ default:
+ ;
+ }
+ ExecuteCursorSel(rReq);
+ return;
+ }
+
+ SCCOLROW nRTLSign = 1;
+ if ( rData.GetDocument().IsLayoutRTL( rData.GetTabNo() ) )
+ {
+ //! evaluate cursor movement option?
+ nRTLSign = -1;
+ }
+
+ // once extra, so that the cursor will not be painted too often with ExecuteInputDirect:
+ pTabViewShell->HideAllCursors();
+
+ // #i123629#
+ if( pTabViewShell->GetCurObjectSelectionType() == OST_Editing )
+ pTabViewShell->SetForceFocusOnCurCell(true);
+ else
+ pTabViewShell->SetForceFocusOnCurCell(false);
+
+ // If ScrollLock key is active, cell cursor stays on the current cell while
+ // scrolling the grid.
+ bool bScrollLock = false;
+ KeyIndicatorState eState = pFrameWin->GetIndicatorState();
+ if (eState & KeyIndicatorState::SCROLLLOCK)
+ bScrollLock = true;
+
+ //OS: once for all should do, however!
+ pTabViewShell->ExecuteInputDirect();
+ switch ( nSlotId )
+ {
+ case SID_CURSORDOWN:
+ if (bScrollLock)
+ pTabViewShell->ScrollY( nRepeat, SC_SPLIT_BOTTOM );
+ else
+ pTabViewShell->MoveCursorRel( 0, nRepeat, SC_FOLLOW_LINE, bSel, bKeep );
+ break;
+
+ case SID_CURSORBLKDOWN:
+ pTabViewShell->MoveCursorArea( 0, nRepeat, SC_FOLLOW_JUMP, bSel, bKeep );
+ break;
+
+ case SID_CURSORUP:
+ if (bScrollLock)
+ pTabViewShell->ScrollY( -nRepeat, SC_SPLIT_BOTTOM);
+ else
+ pTabViewShell->MoveCursorRel( 0, -nRepeat, SC_FOLLOW_LINE, bSel, bKeep );
+ break;
+
+ case SID_CURSORBLKUP:
+ pTabViewShell->MoveCursorArea( 0, -nRepeat, SC_FOLLOW_JUMP, bSel, bKeep );
+ break;
+
+ case SID_CURSORLEFT:
+ if (bScrollLock)
+ pTabViewShell->ScrollX( static_cast<SCCOL>(-nRepeat * nRTLSign), SC_SPLIT_LEFT);
+ else
+ pTabViewShell->MoveCursorRel( static_cast<SCCOL>(-nRepeat * nRTLSign), 0, SC_FOLLOW_LINE, bSel, bKeep );
+ break;
+
+ case SID_CURSORBLKLEFT:
+ pTabViewShell->MoveCursorArea( static_cast<SCCOL>(-nRepeat * nRTLSign), 0, SC_FOLLOW_JUMP, bSel, bKeep );
+ break;
+
+ case SID_CURSORRIGHT:
+ if (bScrollLock)
+ pTabViewShell->ScrollX( static_cast<SCCOL>(nRepeat * nRTLSign), SC_SPLIT_LEFT);
+ else
+ pTabViewShell->MoveCursorRel( static_cast<SCCOL>(nRepeat * nRTLSign), 0, SC_FOLLOW_LINE, bSel, bKeep );
+ break;
+
+ case SID_CURSORBLKRIGHT:
+ pTabViewShell->MoveCursorArea( static_cast<SCCOL>(nRepeat * nRTLSign), 0, SC_FOLLOW_JUMP, bSel, bKeep );
+ break;
+
+ case SID_CURSORPAGEDOWN:
+ if (bScrollLock)
+ {
+ SCCOL nPageX;
+ SCROW nPageY;
+ pTabViewShell->GetPageMoveEndPosition( 0, nRepeat, nPageX, nPageY);
+ pTabViewShell->ScrollY( nPageY, SC_SPLIT_BOTTOM);
+ }
+ else
+ pTabViewShell->MoveCursorPage( 0, nRepeat, SC_FOLLOW_FIX, bSel, bKeep );
+ break;
+
+ case SID_CURSORPAGEUP:
+ if (bScrollLock)
+ {
+ SCCOL nPageX;
+ SCROW nPageY;
+ pTabViewShell->GetPageMoveEndPosition( 0, nRepeat, nPageX, nPageY);
+ pTabViewShell->ScrollY( -nPageY, SC_SPLIT_BOTTOM);
+ }
+ else
+ pTabViewShell->MoveCursorPage( 0, -nRepeat, SC_FOLLOW_FIX, bSel, bKeep );
+ break;
+
+ case SID_CURSORPAGERIGHT_: //XXX !!!
+ if (bScrollLock)
+ {
+ SCCOL nPageX;
+ SCROW nPageY;
+ pTabViewShell->GetPageMoveEndPosition( static_cast<SCCOL>(nRepeat), 0, nPageX, nPageY);
+ pTabViewShell->ScrollX( nPageX, SC_SPLIT_LEFT);
+ }
+ else
+ pTabViewShell->MoveCursorPage( static_cast<SCCOL>(nRepeat), 0, SC_FOLLOW_FIX, bSel, bKeep );
+ break;
+
+ case SID_CURSORPAGELEFT_: //XXX !!!
+ if (bScrollLock)
+ {
+ SCCOL nPageX;
+ SCROW nPageY;
+ pTabViewShell->GetPageMoveEndPosition( static_cast<SCCOL>(nRepeat), 0, nPageX, nPageY);
+ pTabViewShell->ScrollX( -nPageX, SC_SPLIT_LEFT);
+ }
+ else
+ pTabViewShell->MoveCursorPage( static_cast<SCCOL>(-nRepeat), 0, SC_FOLLOW_FIX, bSel, bKeep );
+ break;
+
+ default:
+ OSL_FAIL("Unknown message in ViewShell (Cursor)");
+ return;
+ }
+
+ pTabViewShell->ShowAllCursors();
+
+ rReq.AppendItem( SfxInt16Item(FN_PARAM_1, static_cast<sal_Int16>(nRepeat)) );
+ rReq.AppendItem( SfxBoolItem(FN_PARAM_2, bSel) );
+ rReq.Done();
+}
+
+void ScCellShell::GetStateCursor( SAL_UNUSED_PARAMETER SfxItemSet& /* rSet */ )
+{
+}
+
+void ScCellShell::ExecuteCursorSel( SfxRequest& rReq )
+{
+ sal_uInt16 nSlotId = rReq.GetSlot();
+ ScTabViewShell* pViewShell = GetViewData().GetViewShell();
+ ScInputHandler* pInputHdl = pViewShell->GetInputHandler();
+ pViewShell->HideAllCursors();
+ if (pInputHdl && pInputHdl->IsInputMode())
+ {
+ // the current cell is in edit mode. Commit the text before moving on.
+ pViewShell->ExecuteInputDirect();
+ }
+
+ SCCOLROW nRepeat = 1;
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ // get repetition
+ if ( pReqArgs != nullptr )
+ {
+ const SfxPoolItem* pItem;
+ if (pReqArgs->HasItem(FN_PARAM_1, &pItem))
+ nRepeat = static_cast<SCCOLROW>(static_cast<const SfxInt16Item*>(pItem)->GetValue());
+ }
+
+ SCROW nMovY = nRepeat;
+ // Horizontal direction depends on whether or not the UI language is RTL.
+ SCCOL nMovX = nRepeat;
+ if (GetViewData().GetDocument().IsLayoutRTL(GetViewData().GetTabNo()))
+ {
+ // mirror horizontal movement for right-to-left mode.
+ nMovX = -nRepeat;
+ }
+
+ switch (nSlotId)
+ {
+ case SID_CURSORDOWN_SEL:
+ pViewShell->ExpandBlock(0, nMovY, SC_FOLLOW_LINE);
+ break;
+ case SID_CURSORUP_SEL:
+ pViewShell->ExpandBlock(0, -nMovY, SC_FOLLOW_LINE);
+ break;
+ case SID_CURSORRIGHT_SEL:
+ pViewShell->ExpandBlock(nMovX, 0, SC_FOLLOW_LINE);
+ break;
+ case SID_CURSORLEFT_SEL:
+ pViewShell->ExpandBlock(-nMovX, 0, SC_FOLLOW_LINE);
+ break;
+ case SID_CURSORPAGEUP_SEL:
+ pViewShell->ExpandBlockPage(0, -nMovY);
+ break;
+ case SID_CURSORPAGEDOWN_SEL:
+ pViewShell->ExpandBlockPage(0, nMovY);
+ break;
+ case SID_CURSORPAGERIGHT_SEL:
+ pViewShell->ExpandBlockPage(nMovX, 0);
+ break;
+ case SID_CURSORPAGELEFT_SEL:
+ pViewShell->ExpandBlockPage(-nMovX, 0);
+ break;
+ case SID_CURSORBLKDOWN_SEL:
+ pViewShell->ExpandBlockArea(0, nMovY);
+ break;
+ case SID_CURSORBLKUP_SEL:
+ pViewShell->ExpandBlockArea(0, -nMovY);
+ break;
+ case SID_CURSORBLKRIGHT_SEL:
+ pViewShell->ExpandBlockArea(nMovX , 0);
+ break;
+ case SID_CURSORBLKLEFT_SEL:
+ pViewShell->ExpandBlockArea(-nMovX, 0);
+ break;
+ default:
+ ;
+ }
+ pViewShell->ShowAllCursors();
+
+ rReq.AppendItem( SfxInt16Item(FN_PARAM_1,static_cast<sal_Int16>(nRepeat)) );
+ rReq.Done();
+}
+
+void ScCellShell::ExecuteMove( SfxRequest& rReq )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ sal_uInt16 nSlotId = rReq.GetSlot();
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ if(nSlotId != SID_CURSORTOPOFSCREEN && nSlotId != SID_CURSORENDOFSCREEN)
+ pTabViewShell->ExecuteInputDirect();
+ switch ( nSlotId )
+ {
+ case SID_NEXT_TABLE:
+ case SID_NEXT_TABLE_SEL:
+ pTabViewShell->SelectNextTab( 1, (nSlotId == SID_NEXT_TABLE_SEL) );
+ break;
+
+ case SID_PREV_TABLE:
+ case SID_PREV_TABLE_SEL:
+ pTabViewShell->SelectNextTab( -1, (nSlotId == SID_PREV_TABLE_SEL) );
+ break;
+
+ // cursor movements in range do not originate from Basic,
+ // because the ScSbxRange-object changes the marking at input
+
+ case SID_NEXT_UNPROTECT:
+ pTabViewShell->FindNextUnprot( false, !rReq.IsAPI() );
+ break;
+
+ case SID_PREV_UNPROTECT:
+ pTabViewShell->FindNextUnprot( true, !rReq.IsAPI() );
+ break;
+
+ case SID_CURSORENTERUP:
+ if (rReq.IsAPI())
+ pTabViewShell->MoveCursorRel( 0, -1, SC_FOLLOW_LINE, false );
+ else
+ pTabViewShell->MoveCursorEnter( true );
+ break;
+
+ case SID_CURSORENTERDOWN:
+ if (rReq.IsAPI())
+ pTabViewShell->MoveCursorRel( 0, 1, SC_FOLLOW_LINE, false );
+ else
+ pTabViewShell->MoveCursorEnter( false );
+ break;
+
+ case SID_SELECT_COL:
+ {
+ const SfxPoolItem* pColItem;
+ const SfxPoolItem* pModifierItem;
+ if ( pReqArgs && pReqArgs->HasItem( FN_PARAM_1, &pColItem ) &&
+ pReqArgs->HasItem( FN_PARAM_2, &pModifierItem ) )
+ {
+ SCCOL nCol = static_cast<SCCOL>(static_cast<const SfxInt32Item*>(pColItem)->GetValue());
+ sal_Int16 nModifier = static_cast<const SfxInt16Item*>(pModifierItem)->GetValue();
+
+ pTabViewShell->MarkColumns( nCol, nModifier );
+ }
+ else
+ pTabViewShell->MarkColumns();
+ }
+ break;
+
+ case SID_SELECT_ROW:
+ {
+ const SfxPoolItem* pRowItem;
+ const SfxPoolItem* pModifierItem;
+ if ( pReqArgs && pReqArgs->HasItem( FN_PARAM_1, &pRowItem ) &&
+ pReqArgs->HasItem( FN_PARAM_2, &pModifierItem ) )
+ {
+ SCROW nRow = static_cast<SCROW>(static_cast<const SfxInt32Item*>(pRowItem)->GetValue());
+ sal_Int16 nModifier = static_cast<const SfxInt16Item*>(pModifierItem)->GetValue();
+
+ pTabViewShell->MarkRows( nRow, nModifier );
+ }
+ else
+ pTabViewShell->MarkRows();
+ }
+ break;
+
+ case SID_SELECT_NONE:
+ pTabViewShell->Unmark();
+ break;
+
+ case SID_ALIGNCURSOR:
+ pTabViewShell->AlignToCursor( GetViewData().GetCurX(), GetViewData().GetCurY(), SC_FOLLOW_JUMP );
+ break;
+
+ case SID_MARKDATAAREA:
+ pTabViewShell->MarkDataArea();
+ break;
+
+ case SID_MARKARRAYFORMULA:
+ pTabViewShell->MarkMatrixFormula();
+ break;
+
+ case SID_SETINPUTMODE:
+ SC_MOD()->SetInputMode( SC_INPUT_TABLE );
+ break;
+
+ case SID_FOCUS_INPUTLINE:
+ {
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl( pTabViewShell );
+ if (pHdl)
+ {
+ ScInputWindow* pWin = pHdl->GetInputWindow();
+ if (pWin)
+ pWin->SwitchToTextWin();
+ }
+ }
+ break;
+
+ case SID_CURSORTOPOFSCREEN:
+ pTabViewShell->MoveCursorScreen( 0, -1, SC_FOLLOW_LINE, false );
+ break;
+
+ case SID_CURSORENDOFSCREEN:
+ pTabViewShell->MoveCursorScreen( 0, 1, SC_FOLLOW_LINE, false );
+ break;
+
+ default:
+ OSL_FAIL("Unknown message in ViewShell (Cursor)");
+ return;
+ }
+
+ rReq.Done();
+}
+
+void ScCellShell::ExecutePageSel( SfxRequest& rReq )
+{
+ sal_uInt16 nSlotId = rReq.GetSlot();
+ switch ( nSlotId )
+ {
+ case SID_CURSORHOME_SEL: rReq.SetSlot( SID_CURSORHOME ); break;
+ case SID_CURSOREND_SEL: rReq.SetSlot( SID_CURSOREND ); break;
+ case SID_CURSORTOPOFFILE_SEL: rReq.SetSlot( SID_CURSORTOPOFFILE ); break;
+ case SID_CURSORENDOFFILE_SEL: rReq.SetSlot( SID_CURSORENDOFFILE ); break;
+ default:
+ OSL_FAIL("Unknown message in ViewShell (ExecutePageSel)");
+ return;
+ }
+ rReq.AppendItem( SfxBoolItem(FN_PARAM_2, true) );
+ ExecuteSlot( rReq, GetInterface() );
+}
+
+void ScCellShell::ExecutePage( SfxRequest& rReq )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlotId = rReq.GetSlot();
+ bool bSel = false;
+ bool bKeep = false;
+
+ if ( pReqArgs != nullptr )
+ {
+ const SfxPoolItem* pItem;
+ if (pReqArgs->HasItem(FN_PARAM_2, &pItem))
+ bSel = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ }
+ else
+ {
+ // evaluate locked selection mode
+
+ sal_uInt16 nLocked = pTabViewShell->GetLockedModifiers();
+ if ( nLocked & KEY_SHIFT )
+ bSel = true; // EXT
+ else if ( nLocked & KEY_MOD1 )
+ {
+ // ADD mode: keep the selection, start a new block when marking with shift again
+ bKeep = true;
+ }
+ }
+
+ pTabViewShell->ExecuteInputDirect();
+ switch ( nSlotId )
+ {
+ case SID_CURSORHOME:
+ pTabViewShell->MoveCursorEnd( -1, 0, SC_FOLLOW_LINE, bSel, bKeep );
+ break;
+
+ case SID_CURSOREND:
+ pTabViewShell->MoveCursorEnd( 1, 0, SC_FOLLOW_JUMP, bSel, bKeep );
+ break;
+
+ case SID_CURSORTOPOFFILE:
+ pTabViewShell->MoveCursorEnd( -1, -1, SC_FOLLOW_LINE, bSel, bKeep );
+ break;
+
+ case SID_CURSORENDOFFILE:
+ pTabViewShell->MoveCursorEnd( 1, 1, SC_FOLLOW_JUMP, bSel, bKeep );
+ break;
+
+ default:
+ OSL_FAIL("Unknown message in ViewShell (ExecutePage)");
+ return;
+ }
+
+ rReq.AppendItem( SfxBoolItem(FN_PARAM_2, bSel) );
+ rReq.Done();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/cliputil.cxx b/sc/source/ui/view/cliputil.cxx
new file mode 100644
index 000000000..770e309db
--- /dev/null
+++ b/sc/source/ui/view/cliputil.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/.
+ */
+
+#include <cliputil.hxx>
+#include <attrib.hxx>
+#include <viewdata.hxx>
+#include <tabvwsh.hxx>
+#include <transobj.hxx>
+#include <document.hxx>
+#include <dpobject.hxx>
+#include <globstr.hrc>
+#include <clipparam.hxx>
+#include <clipoptions.hxx>
+#include <rangelst.hxx>
+#include <viewutil.hxx>
+#include <markdata.hxx>
+#include <gridwin.hxx>
+#include <scitems.hxx>
+
+#include <sfx2/classificationhelper.hxx>
+#include <comphelper/lok.hxx>
+
+namespace
+{
+
+/// Paste only if SfxClassificationHelper recommends so.
+bool lcl_checkClassification(ScDocument* pSourceDoc, const ScDocument& rDestinationDoc)
+{
+ if (!pSourceDoc)
+ return true;
+
+ ScClipOptions* pSourceOptions = pSourceDoc->GetClipOptions();
+ SfxObjectShell* pDestinationShell = rDestinationDoc.GetDocumentShell();
+ if (!pSourceOptions || !pDestinationShell)
+ return true;
+
+ SfxClassificationCheckPasteResult eResult = SfxClassificationHelper::CheckPaste(pSourceOptions->m_xDocumentProperties, pDestinationShell->getDocProperties());
+ return SfxClassificationHelper::ShowPasteInfo(eResult);
+}
+
+}
+
+void ScClipUtil::PasteFromClipboard( ScViewData& rViewData, ScTabViewShell* pTabViewShell, bool bShowDialog )
+{
+ const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(rViewData.GetActiveWin()));
+ ScDocument& rThisDoc = rViewData.GetDocument();
+ SCCOL nThisCol = rViewData.GetCurX();
+ SCROW nThisRow = rViewData.GetCurY();
+ SCTAB nThisTab = rViewData.GetTabNo();
+ ScDPObject* pDPObj = rThisDoc.GetDPAtCursor( nThisCol, nThisRow, nThisTab );
+
+ if ( pOwnClip && pDPObj )
+ {
+ // paste from Calc into DataPilot table: sort (similar to drag & drop)
+
+ ScDocument* pClipDoc = pOwnClip->GetDocument();
+ SCTAB nSourceTab = pOwnClip->GetVisibleTab();
+
+ SCCOL nClipStartX;
+ SCROW nClipStartY;
+ SCCOL nClipEndX;
+ SCROW nClipEndY;
+ pClipDoc->GetClipStart( nClipStartX, nClipStartY );
+ pClipDoc->GetClipArea( nClipEndX, nClipEndY, true );
+ nClipEndX = nClipEndX + nClipStartX;
+ nClipEndY = nClipEndY + nClipStartY; // GetClipArea returns the difference
+
+ ScRange aSource( nClipStartX, nClipStartY, nSourceTab, nClipEndX, nClipEndY, nSourceTab );
+ bool bDone = pTabViewShell->DataPilotMove( aSource, rViewData.GetCurPos() );
+ if ( !bDone )
+ pTabViewShell->ErrorMessage( STR_ERR_DATAPILOT_INPUT );
+ }
+ else
+ {
+ // normal paste
+ weld::WaitObject aWait( rViewData.GetDialogParent() );
+ if (!pOwnClip)
+ {
+ pTabViewShell->PasteFromSystem();
+ // Anchor To Cell rather than To Page
+ ScDrawView* pDrawView = pTabViewShell->GetScDrawView();
+ if(pDrawView && 1 == pDrawView->GetMarkedObjectCount())
+ {
+ SdrObject* pPickObj = pDrawView->GetMarkedObjectByIndex(0);
+ if(pPickObj)
+ {
+ ScDrawLayer::SetCellAnchoredFromPosition( *pPickObj, rThisDoc, nThisTab, false );
+ }
+ }
+ }
+ else
+ {
+ ScDocument* pClipDoc = pOwnClip->GetDocument();
+ InsertDeleteFlags nFlags = InsertDeleteFlags::ALL;
+ if (pClipDoc->GetClipParam().isMultiRange())
+ // For multi-range paste, we paste values by default.
+ nFlags &= ~InsertDeleteFlags::FORMULA;
+
+ if (lcl_checkClassification(pClipDoc, rThisDoc))
+ pTabViewShell->PasteFromClip( nFlags, pClipDoc,
+ ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
+ bShowDialog ); // allow warning dialog
+ }
+ }
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ bool entireColumnOrRowSelected = false;
+ if (pOwnClip)
+ {
+ ScClipParam clipParam = pOwnClip->GetDocument()->GetClipParam();
+ if (clipParam.maRanges.size() > 0)
+ {
+ if (clipParam.maRanges[0].aEnd.Col() == pOwnClip->GetDocument()->MaxCol()
+ || clipParam.maRanges[0].aEnd.Row() == pOwnClip->GetDocument()->MaxRow())
+ {
+ entireColumnOrRowSelected = true;
+ }
+ }
+ }
+ const SfxBoolItem* pItem = rThisDoc.GetAttr(nThisCol, nThisRow, nThisTab, ATTR_LINEBREAK);
+ if (pItem->GetValue() || entireColumnOrRowSelected)
+ {
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ pTabViewShell, true /* bColumns */, true /* bRows */, true /* bSizes*/,
+ true /* bHidden */, true /* bFiltered */, true /* bGroups */, nThisTab);
+ }
+ }
+ pTabViewShell->CellContentChanged(); // => PasteFromSystem() ???
+}
+
+bool ScClipUtil::CheckDestRanges(
+ const ScDocument& rDoc, SCCOL nSrcCols, SCROW nSrcRows, const ScMarkData& rMark, const ScRangeList& rDest)
+{
+ for (size_t i = 0, n = rDest.size(); i < n; ++i)
+ {
+ ScRange aTest = rDest[i];
+ // Check for filtered rows in all selected sheets.
+ for (const auto& rTab : rMark)
+ {
+ aTest.aStart.SetTab(rTab);
+ aTest.aEnd.SetTab(rTab);
+ if (ScViewUtil::HasFiltered(aTest, rDoc))
+ {
+ // I don't know how to handle pasting into filtered rows yet.
+ return false;
+ }
+ }
+
+ // Destination range must be an exact multiple of the source range.
+ SCROW nRows = aTest.aEnd.Row() - aTest.aStart.Row() + 1;
+ SCCOL nCols = aTest.aEnd.Col() - aTest.aStart.Col() + 1;
+ SCROW nRowTest = (nRows / nSrcRows) * nSrcRows;
+ SCCOL nColTest = (nCols / nSrcCols) * nSrcCols;
+ if ( rDest.size() > 1 && ( nRows != nRowTest || nCols != nColTest ) )
+ {
+ // Destination range is not a multiple of the source range. Bail out.
+ return false;
+ }
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/colrowba.cxx b/sc/source/ui/view/colrowba.cxx
new file mode 100644
index 000000000..ab9e82282
--- /dev/null
+++ b/sc/source/ui/view/colrowba.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 <sal/config.h>
+
+#include <string_view>
+
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/fieldvalues.hxx>
+
+#include <colrowba.hxx>
+#include <document.hxx>
+#include <scmod.hxx>
+#include <tabvwsh.hxx>
+#include <appoptio.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <markdata.hxx>
+#include <tabview.hxx>
+#include <columnspanset.hxx>
+
+static OUString lcl_MetricString( tools::Long nTwips, std::u16string_view rText )
+{
+ if ( nTwips <= 0 )
+ return ScResId(STR_TIP_HIDE);
+ else
+ {
+ FieldUnit eUserMet = SC_MOD()->GetAppOptions().GetAppMetric();
+
+ sal_Int64 nUserVal = vcl::ConvertValue( nTwips*100, 1, 2, FieldUnit::TWIP, eUserMet );
+
+ OUString aStr = OUString::Concat(rText) + " "
+ + ScGlobal::getLocaleData().getNum( nUserVal, 2 )
+ + " " + SdrFormatter::GetUnitStr(eUserMet);
+ return aStr;
+ }
+}
+
+ScColBar::ScColBar( vcl::Window* pParent, ScHSplitPos eWhich,
+ ScHeaderFunctionSet* pFuncSet, ScHeaderSelectionEngine* pEng,
+ ScTabView* pTab ) :
+ ScHeaderControl( pParent, pEng, pTab->GetViewData().GetDocument().MaxCol()+1, false, pTab ),
+ meWhich( eWhich ),
+ mpFuncSet( pFuncSet )
+{
+ Show();
+}
+
+ScColBar::~ScColBar()
+{
+}
+
+SCCOLROW ScColBar::GetPos() const
+{
+ return pTabView->GetViewData().GetPosX(meWhich);
+}
+
+sal_uInt16 ScColBar::GetEntrySize( SCCOLROW nEntryNo ) const
+{
+ const ScViewData& rViewData = pTabView->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ if (rDoc.ColHidden(static_cast<SCCOL>(nEntryNo), nTab))
+ return 0;
+ else
+ return static_cast<sal_uInt16>(ScViewData::ToPixel( rDoc.GetColWidth( static_cast<SCCOL>(nEntryNo), nTab ), rViewData.GetPPTX() ));
+}
+
+OUString ScColBar::GetEntryText( SCCOLROW nEntryNo ) const
+{
+ return pTabView->GetViewData().GetDocument().GetAddressConvention() == formula::FormulaGrammar::CONV_XL_R1C1
+ ? OUString::number(nEntryNo + 1)
+ : ScColToAlpha( static_cast<SCCOL>(nEntryNo) );
+}
+
+void ScColBar::SetEntrySize( SCCOLROW nPos, sal_uInt16 nNewSize )
+{
+ const ScViewData& rViewData = pTabView->GetViewData();
+ sal_uInt16 nSizeTwips;
+ ScSizeMode eMode = SC_SIZE_DIRECT;
+ if (nNewSize < 10) nNewSize = 10; // pixels
+
+ if ( nNewSize == HDR_SIZE_OPTIMUM )
+ {
+ nSizeTwips = STD_EXTRA_WIDTH;
+ eMode = SC_SIZE_OPTIMAL;
+ }
+ else
+ nSizeTwips = static_cast<sal_uInt16>( nNewSize / rViewData.GetPPTX() );
+
+ const ScMarkData& rMark = rViewData.GetMarkData();
+
+ std::vector<sc::ColRowSpan> aRanges;
+ if ( rMark.IsColumnMarked( static_cast<SCCOL>(nPos) ) )
+ {
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCCOL nStart = 0;
+ while (nStart<=rDoc.MaxCol())
+ {
+ while (nStart<rDoc.MaxCol() && !rMark.IsColumnMarked(nStart))
+ ++nStart;
+ if (rMark.IsColumnMarked(nStart))
+ {
+ SCCOL nEnd = nStart;
+ while (nEnd<rDoc.MaxCol() && rMark.IsColumnMarked(nEnd))
+ ++nEnd;
+ if (!rMark.IsColumnMarked(nEnd))
+ --nEnd;
+ aRanges.emplace_back(nStart,nEnd);
+ nStart = nEnd+1;
+ }
+ else
+ nStart = rDoc.MaxCol()+1;
+ }
+ }
+ else
+ {
+ aRanges.emplace_back(nPos,nPos);
+ }
+
+ rViewData.GetView()->SetWidthOrHeight(true, aRanges, eMode, nSizeTwips);
+}
+
+void ScColBar::HideEntries( SCCOLROW nStart, SCCOLROW nEnd )
+{
+ std::vector<sc::ColRowSpan> aRanges(1, sc::ColRowSpan(nStart,nEnd));
+ pTabView->GetViewData().GetView()->SetWidthOrHeight(true, aRanges, SC_SIZE_DIRECT, 0);
+}
+
+void ScColBar::SetMarking( bool bSet )
+{
+ pTabView->GetViewData().GetMarkData().SetMarking( bSet );
+ if (!bSet)
+ {
+ pTabView->GetViewData().GetView()->UpdateAutoFillMark();
+ }
+}
+
+void ScColBar::SelectWindow()
+{
+ const ScViewData& rViewData = pTabView->GetViewData();
+ ScTabViewShell* pViewSh = rViewData.GetViewShell();
+
+ pViewSh->SetActive(); // Appear and SetViewFrame
+ pViewSh->DrawDeselectAll();
+
+ ScSplitPos eActive = rViewData.GetActivePart();
+ if (meWhich==SC_SPLIT_LEFT)
+ {
+ if (eActive==SC_SPLIT_TOPRIGHT) eActive=SC_SPLIT_TOPLEFT;
+ if (eActive==SC_SPLIT_BOTTOMRIGHT) eActive=SC_SPLIT_BOTTOMLEFT;
+ }
+ else
+ {
+ if (eActive==SC_SPLIT_TOPLEFT) eActive=SC_SPLIT_TOPRIGHT;
+ if (eActive==SC_SPLIT_BOTTOMLEFT) eActive=SC_SPLIT_BOTTOMRIGHT;
+ }
+ pViewSh->ActivatePart( eActive );
+
+ mpFuncSet->SetColumn( true );
+ mpFuncSet->SetWhich( eActive );
+
+ pViewSh->ActiveGrabFocus();
+}
+
+bool ScColBar::IsDisabled() const
+{
+ ScModule* pScMod = SC_MOD();
+ return pScMod->IsModalMode();
+}
+
+bool ScColBar::ResizeAllowed() const
+{
+ const ScViewData& rViewData = pTabView->GetViewData();
+ return !rViewData.HasEditView( rViewData.GetActivePart() );
+}
+
+void ScColBar::DrawInvert( tools::Long nDragPosP )
+{
+ tools::Rectangle aRect( nDragPosP,0, nDragPosP+HDR_SLIDERSIZE-1,GetOutputSizePixel().Width()-1 );
+ PaintImmediately();
+ GetOutDev()->Invert(aRect);
+
+ pTabView->GetViewData().GetView()->InvertVertical(meWhich,nDragPosP);
+}
+
+OUString ScColBar::GetDragHelp( tools::Long nVal )
+{
+ tools::Long nTwips = static_cast<tools::Long>( nVal / pTabView->GetViewData().GetPPTX() );
+ return lcl_MetricString( nTwips, ScResId(STR_TIP_WIDTH) );
+}
+
+bool ScColBar::IsLayoutRTL() const // override only for columns
+{
+ const ScViewData& rViewData = pTabView->GetViewData();
+ return rViewData.GetDocument().IsLayoutRTL( rViewData.GetTabNo() );
+}
+
+ScRowBar::ScRowBar( vcl::Window* pParent, ScVSplitPos eWhich,
+ ScHeaderFunctionSet* pFuncSet, ScHeaderSelectionEngine* pEng,
+ ScTabView* pTab ) :
+ ScHeaderControl( pParent, pEng, pTab->GetViewData().GetDocument().MaxRow()+1, true, pTab ),
+ meWhich( eWhich ),
+ mpFuncSet( pFuncSet )
+{
+ Show();
+}
+
+ScRowBar::~ScRowBar()
+{
+}
+
+SCCOLROW ScRowBar::GetPos() const
+{
+ return pTabView->GetViewData().GetPosY(meWhich);
+}
+
+sal_uInt16 ScRowBar::GetEntrySize( SCCOLROW nEntryNo ) const
+{
+ const ScViewData& rViewData = pTabView->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ SCROW nLastRow = -1;
+ if (rDoc.RowHidden(nEntryNo, nTab, nullptr, &nLastRow))
+ return 0;
+ else
+ return static_cast<sal_uInt16>(ScViewData::ToPixel( rDoc.GetOriginalHeight( nEntryNo,
+ nTab ), rViewData.GetPPTY() ));
+}
+
+OUString ScRowBar::GetEntryText( SCCOLROW nEntryNo ) const
+{
+ return OUString::number( nEntryNo + 1 );
+}
+
+void ScRowBar::SetEntrySize( SCCOLROW nPos, sal_uInt16 nNewSize )
+{
+ const ScViewData& rViewData = pTabView->GetViewData();
+ sal_uInt16 nSizeTwips;
+ ScSizeMode eMode = SC_SIZE_DIRECT;
+ if (nNewSize < 10) nNewSize = 10; // pixels
+
+ if ( nNewSize == HDR_SIZE_OPTIMUM )
+ {
+ nSizeTwips = 0;
+ eMode = SC_SIZE_OPTIMAL;
+ }
+ else
+ nSizeTwips = static_cast<sal_uInt16>( nNewSize / rViewData.GetPPTY() );
+
+ const ScMarkData& rMark = rViewData.GetMarkData();
+
+ std::vector<sc::ColRowSpan> aRanges;
+ if ( rMark.IsRowMarked( nPos ) )
+ {
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCROW nStart = 0;
+ while (nStart<=rDoc.MaxRow())
+ {
+ while (nStart<rDoc.MaxRow() && !rMark.IsRowMarked(nStart))
+ ++nStart;
+ if (rMark.IsRowMarked(nStart))
+ {
+ SCROW nEnd = nStart;
+ while (nEnd<rDoc.MaxRow() && rMark.IsRowMarked(nEnd))
+ ++nEnd;
+ if (!rMark.IsRowMarked(nEnd))
+ --nEnd;
+ aRanges.emplace_back(nStart,nEnd);
+ nStart = nEnd+1;
+ }
+ else
+ nStart = rDoc.MaxRow()+1;
+ }
+ }
+ else
+ {
+ aRanges.emplace_back(nPos,nPos);
+ }
+
+ rViewData.GetView()->SetWidthOrHeight(false, aRanges, eMode, nSizeTwips);
+}
+
+void ScRowBar::HideEntries( SCCOLROW nStart, SCCOLROW nEnd )
+{
+ std::vector<sc::ColRowSpan> aRange(1, sc::ColRowSpan(nStart,nEnd));
+ pTabView->GetViewData().GetView()->SetWidthOrHeight(false, aRange, SC_SIZE_DIRECT, 0);
+}
+
+void ScRowBar::SetMarking( bool bSet )
+{
+ pTabView->GetViewData().GetMarkData().SetMarking( bSet );
+ if (!bSet)
+ {
+ pTabView->GetViewData().GetView()->UpdateAutoFillMark();
+ }
+}
+
+void ScRowBar::SelectWindow()
+{
+ const ScViewData& rViewData = pTabView->GetViewData();
+ ScTabViewShell* pViewSh = rViewData.GetViewShell();
+
+ pViewSh->SetActive(); // Appear and SetViewFrame
+ pViewSh->DrawDeselectAll();
+
+ ScSplitPos eActive = rViewData.GetActivePart();
+ if (meWhich==SC_SPLIT_TOP)
+ {
+ if (eActive==SC_SPLIT_BOTTOMLEFT) eActive=SC_SPLIT_TOPLEFT;
+ if (eActive==SC_SPLIT_BOTTOMRIGHT) eActive=SC_SPLIT_TOPRIGHT;
+ }
+ else
+ {
+ if (eActive==SC_SPLIT_TOPLEFT) eActive=SC_SPLIT_BOTTOMLEFT;
+ if (eActive==SC_SPLIT_TOPRIGHT) eActive=SC_SPLIT_BOTTOMRIGHT;
+ }
+ pViewSh->ActivatePart( eActive );
+
+ mpFuncSet->SetColumn( false );
+ mpFuncSet->SetWhich( eActive );
+
+ pViewSh->ActiveGrabFocus();
+}
+
+bool ScRowBar::IsDisabled() const
+{
+ ScModule* pScMod = SC_MOD();
+ return pScMod->IsModalMode();
+}
+
+bool ScRowBar::ResizeAllowed() const
+{
+ const ScViewData& rViewData = pTabView->GetViewData();
+ return !rViewData.HasEditView( rViewData.GetActivePart() );
+}
+
+void ScRowBar::DrawInvert( tools::Long nDragPosP )
+{
+ tools::Rectangle aRect( 0,nDragPosP, GetOutputSizePixel().Width()-1,nDragPosP+HDR_SLIDERSIZE-1 );
+ PaintImmediately();
+ GetOutDev()->Invert(aRect);
+
+ pTabView->GetViewData().GetView()->InvertHorizontal(meWhich,nDragPosP);
+}
+
+OUString ScRowBar::GetDragHelp( tools::Long nVal )
+{
+ tools::Long nTwips = static_cast<tools::Long>( nVal / pTabView->GetViewData().GetPPTY() );
+ return lcl_MetricString( nTwips, ScResId(STR_TIP_HEIGHT) );
+}
+
+SCCOLROW ScRowBar::GetHiddenCount( SCCOLROW nEntryNo ) const // override only for rows
+{
+ const ScViewData& rViewData = pTabView->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ return rDoc.GetHiddenRowCount( nEntryNo, nTab );
+}
+
+bool ScRowBar::IsMirrored() const // override only for rows
+{
+ const ScViewData& rViewData = pTabView->GetViewData();
+ return rViewData.GetDocument().IsLayoutRTL( rViewData.GetTabNo() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/dbfunc.cxx b/sc/source/ui/view/dbfunc.cxx
new file mode 100644
index 000000000..24376b509
--- /dev/null
+++ b/sc/source/ui/view/dbfunc.cxx
@@ -0,0 +1,447 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <sfx2/bindings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/diagnose.h>
+
+#include <dbfunc.hxx>
+#include <docsh.hxx>
+#include <attrib.hxx>
+#include <sc.hrc>
+#include <undodat.hxx>
+#include <dbdata.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <dbdocfun.hxx>
+#include <editable.hxx>
+#include <queryentry.hxx>
+#include <markdata.hxx>
+#include <tabvwsh.hxx>
+#include <sortparam.hxx>
+
+ScDBFunc::ScDBFunc( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
+ ScViewFunc( pParent, rDocSh, pViewShell )
+{
+}
+
+ScDBFunc::~ScDBFunc()
+{
+}
+
+// auxiliary functions
+
+void ScDBFunc::GotoDBArea( const OUString& rDBName )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDBCollection* pDBCol = rDoc.GetDBCollection();
+ ScDBData* pData = pDBCol->getNamedDBs().findByUpperName(ScGlobal::getCharClass().uppercase(rDBName));
+ if (!pData)
+ return;
+
+ SCTAB nTab = 0;
+ SCCOL nStartCol = 0;
+ SCROW nStartRow = 0;
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+
+ pData->GetArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow );
+ SetTabNo( nTab );
+
+ MoveCursorAbs( nStartCol, nStartRow, SC_FOLLOW_JUMP,
+ false, false ); // bShift,bControl
+ DoneBlockMode();
+ InitBlockMode( nStartCol, nStartRow, nTab );
+ MarkCursor( nEndCol, nEndRow, nTab );
+ SelectionChanged();
+}
+
+// search current datarange for sort / filter
+
+ScDBData* ScDBFunc::GetDBData( bool bMark, ScGetDBMode eMode, ScGetDBSelection eSel )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDBData* pData = nullptr;
+ ScRange aRange;
+ ScMarkType eMarkType = GetViewData().GetSimpleArea(aRange);
+ if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
+ {
+ bool bShrinkColumnsOnly = false;
+ if (eSel == ScGetDBSelection::RowDown)
+ {
+ // Don't alter row range, additional rows may have been selected on
+ // purpose to append data, or to have a fake header row.
+ bShrinkColumnsOnly = true;
+ // Select further rows only if only one row or a portion thereof is
+ // selected.
+ if (aRange.aStart.Row() != aRange.aEnd.Row())
+ {
+ // If an area is selected shrink that to the actual used
+ // columns, don't draw filter buttons for empty columns.
+ eSel = ScGetDBSelection::ShrinkToUsedData;
+ }
+ else if (aRange.aStart.Col() == aRange.aEnd.Col())
+ {
+ // One cell only, if it is not marked obtain entire used data
+ // area.
+ const ScMarkData& rMarkData = GetViewData().GetMarkData();
+ if (!(rMarkData.IsMarked() || rMarkData.IsMultiMarked()))
+ eSel = ScGetDBSelection::Keep;
+ }
+ }
+ switch (eSel)
+ {
+ case ScGetDBSelection::ShrinkToUsedData:
+ case ScGetDBSelection::RowDown:
+ {
+ // Shrink the selection to actual used area.
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCCOL nCol1 = aRange.aStart.Col(), nCol2 = aRange.aEnd.Col();
+ SCROW nRow1 = aRange.aStart.Row(), nRow2 = aRange.aEnd.Row();
+ bool bShrunk;
+ rDoc.ShrinkToUsedDataArea( bShrunk, aRange.aStart.Tab(),
+ nCol1, nRow1, nCol2, nRow2, bShrinkColumnsOnly);
+ if (bShrunk)
+ {
+ aRange.aStart.SetCol(nCol1);
+ aRange.aEnd.SetCol(nCol2);
+ aRange.aStart.SetRow(nRow1);
+ aRange.aEnd.SetRow(nRow2);
+ }
+ }
+ break;
+ default:
+ ; // nothing
+ }
+ pData = pDocSh->GetDBData( aRange, eMode, eSel );
+ }
+ else if ( eMode != SC_DB_OLD )
+ pData = pDocSh->GetDBData(
+ ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(),
+ GetViewData().GetTabNo() ),
+ eMode, ScGetDBSelection::Keep );
+
+ if (!pData)
+ return nullptr;
+
+ if (bMark)
+ {
+ ScRange aFound;
+ pData->GetArea(aFound);
+ MarkRange( aFound, false );
+ }
+ return pData;
+}
+
+ScDBData* ScDBFunc::GetAnonymousDBData()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScRange aRange;
+ ScMarkType eMarkType = GetViewData().GetSimpleArea(aRange);
+ if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED)
+ return nullptr;
+
+ // Expand to used data area if not explicitly marked.
+ const ScMarkData& rMarkData = GetViewData().GetMarkData();
+ if (!rMarkData.IsMarked() && !rMarkData.IsMultiMarked())
+ {
+ SCCOL nCol1 = aRange.aStart.Col();
+ SCCOL nCol2 = aRange.aEnd.Col();
+ SCROW nRow1 = aRange.aStart.Row();
+ SCROW nRow2 = aRange.aEnd.Row();
+ pDocSh->GetDocument().GetDataArea(aRange.aStart.Tab(), nCol1, nRow1, nCol2, nRow2, false, false);
+ aRange.aStart.SetCol(nCol1);
+ aRange.aStart.SetRow(nRow1);
+ aRange.aEnd.SetCol(nCol2);
+ aRange.aEnd.SetRow(nRow2);
+ }
+
+ return pDocSh->GetAnonymousDBData(aRange);
+}
+
+// main functions
+
+// Sort
+
+void ScDBFunc::UISort( const ScSortParam& rSortParam )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rSortParam.nCol1, rSortParam.nRow1,
+ rSortParam.nCol2, rSortParam.nRow2 );
+ if (!pDBData)
+ {
+ OSL_FAIL( "Sort: no DBData" );
+ return;
+ }
+
+ ScSubTotalParam aSubTotalParam;
+ pDBData->GetSubTotalParam( aSubTotalParam );
+ if (aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly)
+ {
+ // repeat subtotals, with new sortorder
+
+ DoSubTotals( aSubTotalParam, true/*bRecord*/, &rSortParam );
+ }
+ else
+ {
+ Sort( rSortParam ); // just sort
+ }
+}
+
+void ScDBFunc::Sort( const ScSortParam& rSortParam, bool bRecord, bool bPaint )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDBDocFunc aDBDocFunc( *pDocSh );
+ bool bSuccess = aDBDocFunc.Sort( nTab, rSortParam, bRecord, bPaint, false );
+ if ( bSuccess && !rSortParam.bInplace )
+ {
+ // mark target
+ ScRange aDestRange( rSortParam.nDestCol, rSortParam.nDestRow, rSortParam.nDestTab,
+ rSortParam.nDestCol + rSortParam.nCol2 - rSortParam.nCol1,
+ rSortParam.nDestRow + rSortParam.nRow2 - rSortParam.nRow1,
+ rSortParam.nDestTab );
+ MarkRange( aDestRange );
+ }
+
+ ResetAutoSpellForContentChange();
+}
+
+// filters
+
+void ScDBFunc::Query( const ScQueryParam& rQueryParam, const ScRange* pAdvSource, bool bRecord )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDBDocFunc aDBDocFunc( *pDocSh );
+ bool bSuccess = aDBDocFunc.Query( nTab, rQueryParam, pAdvSource, bRecord, false );
+
+ if (!bSuccess)
+ return;
+
+ bool bCopy = !rQueryParam.bInplace;
+ if (bCopy)
+ {
+ // mark target range (data base range has been set up if applicable)
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScDBData* pDestData = rDoc.GetDBAtCursor(
+ rQueryParam.nDestCol, rQueryParam.nDestRow,
+ rQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
+ if (pDestData)
+ {
+ ScRange aDestRange;
+ pDestData->GetArea(aDestRange);
+ MarkRange( aDestRange );
+ }
+ }
+
+ if (!bCopy)
+ {
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ GetViewData().GetViewShell(),
+ false /* bColumns */, true /* bRows */,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ false /* bGroups */, nTab);
+ UpdateScrollBars(ROW_HEADER);
+ SelectionChanged(); // for attribute states (filtered rows are ignored)
+ }
+
+ GetViewData().GetBindings().Invalidate( SID_UNFILTER );
+}
+
+// autofilter-buttons show / hide
+
+void ScDBFunc::ToggleAutoFilter()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocShellModificator aModificator( *pDocSh );
+
+ ScQueryParam aParam;
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDBData* pDBData = GetDBData(false, SC_DB_AUTOFILTER, ScGetDBSelection::RowDown);
+
+ pDBData->SetByRow( true ); //! undo, retrieve beforehand ??
+ pDBData->GetQueryParam( aParam );
+
+ SCCOL nCol;
+ SCROW nRow = aParam.nRow1;
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScMF nFlag;
+ bool bHasAuto = true;
+ bool bHeader = pDBData->HasHeader();
+ bool bPaint = false;
+
+ //! instead retrieve from DB-range?
+
+ for (nCol=aParam.nCol1; nCol<=aParam.nCol2 && bHasAuto; nCol++)
+ {
+ nFlag = rDoc.GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG )->GetValue();
+
+ if ( !(nFlag & ScMF::Auto) )
+ bHasAuto = false;
+ }
+
+ if (bHasAuto) // remove
+ {
+ // hide filter buttons
+
+ for (nCol=aParam.nCol1; nCol<=aParam.nCol2; nCol++)
+ {
+ nFlag = rDoc.GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG )->GetValue();
+ rDoc.ApplyAttr( nCol, nRow, nTab, ScMergeFlagAttr( nFlag & ~ScMF::Auto ) );
+ }
+
+ // use a list action for the AutoFilter buttons (ScUndoAutoFilter) and the filter operation
+
+ OUString aUndo = ScResId( STR_UNDO_QUERY );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
+
+ ScRange aRange;
+ pDBData->GetArea( aRange );
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAutoFilter>( pDocSh, aRange, pDBData->GetName(), false ) );
+
+ pDBData->SetAutoFilter(false);
+
+ // remove filter (incl. Paint / Undo)
+
+ SCSIZE nEC = aParam.GetEntryCount();
+ for (SCSIZE i=0; i<nEC; i++)
+ aParam.GetEntry(i).bDoQuery = false;
+ aParam.bDuplicate = true;
+ Query( aParam, nullptr, true );
+
+ pDocSh->GetUndoManager()->LeaveListAction();
+
+ bPaint = true;
+ }
+ else // show filter buttons
+ {
+ if ( !rDoc.IsBlockEmpty( aParam.nCol1, aParam.nRow1,
+ aParam.nCol2, aParam.nRow2, nTab ) )
+ {
+ if (!bHeader)
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
+ VclMessageType::Question,
+ VclButtonsType::YesNo, ScResId(STR_MSSG_MAKEAUTOFILTER_0))); // header from first row?
+ xBox->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0)); // "StarCalc"
+ xBox->set_default_response(RET_YES);
+ if (xBox->run() == RET_YES)
+ {
+ pDBData->SetHeader( true ); //! Undo ??
+ }
+ }
+
+ ScRange aRange;
+ pDBData->GetArea( aRange );
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAutoFilter>( pDocSh, aRange, pDBData->GetName(), true ) );
+
+ pDBData->SetAutoFilter(true);
+
+ for (nCol=aParam.nCol1; nCol<=aParam.nCol2; nCol++)
+ {
+ nFlag = rDoc.GetAttr( nCol, nRow, nTab, ATTR_MERGE_FLAG )->GetValue();
+ rDoc.ApplyAttr( nCol, nRow, nTab, ScMergeFlagAttr( nFlag | ScMF::Auto ) );
+ }
+ pDocSh->PostPaint(ScRange(aParam.nCol1, nRow, nTab, aParam.nCol2, nRow, nTab),
+ PaintPartFlags::Grid);
+ bPaint = true;
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xErrorBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
+ VclMessageType::Warning, VclButtonsType::Ok,
+ ScResId(STR_ERR_AUTOFILTER)));
+ xErrorBox->run();
+ }
+ }
+
+ if ( bPaint )
+ {
+ aModificator.SetDocumentModified();
+
+ SfxBindings& rBindings = GetViewData().GetBindings();
+ rBindings.Invalidate( SID_AUTO_FILTER );
+ rBindings.Invalidate( SID_AUTOFILTER_HIDE );
+ }
+}
+
+// just hide, no data change
+
+void ScDBFunc::HideAutoFilter()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocShellModificator aModificator( *pDocSh );
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ ScDBData* pDBData = GetDBData( false );
+
+ SCTAB nTab;
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ pDBData->GetArea(nTab, nCol1, nRow1, nCol2, nRow2);
+
+ for (SCCOL nCol=nCol1; nCol<=nCol2; nCol++)
+ {
+ ScMF nFlag = rDoc.GetAttr( nCol, nRow1, nTab, ATTR_MERGE_FLAG )->GetValue();
+ rDoc.ApplyAttr( nCol, nRow1, nTab, ScMergeFlagAttr( nFlag & ~ScMF::Auto ) );
+ }
+
+ ScRange aRange;
+ pDBData->GetArea( aRange );
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoAutoFilter>( pDocSh, aRange, pDBData->GetName(), false ) );
+
+ pDBData->SetAutoFilter(false);
+
+ pDocSh->PostPaint(ScRange(nCol1, nRow1, nTab, nCol2, nRow1, nTab), PaintPartFlags::Grid );
+ aModificator.SetDocumentModified();
+
+ SfxBindings& rBindings = GetViewData().GetBindings();
+ rBindings.Invalidate( SID_AUTO_FILTER );
+ rBindings.Invalidate( SID_AUTOFILTER_HIDE );
+}
+
+// Re-Import
+
+bool ScDBFunc::ImportData( const ScImportParam& rParam )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScEditableTester aTester( rDoc, GetViewData().GetTabNo(), rParam.nCol1,rParam.nRow1,
+ rParam.nCol2,rParam.nRow2 );
+ if ( !aTester.IsEditable() )
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ ScDBDocFunc aDBDocFunc( *GetViewData().GetDocShell() );
+ return aDBDocFunc.DoImport( GetViewData().GetTabNo(), rParam, nullptr );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/dbfunc2.cxx b/sc/source/ui/view/dbfunc2.cxx
new file mode 100644
index 000000000..fffa16909
--- /dev/null
+++ b/sc/source/ui/view/dbfunc2.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 <dbfunc.hxx>
+#include <document.hxx>
+#include <globstr.hrc>
+
+void ScDBFunc::UpdateCharts( bool bAllCharts )
+{
+ sal_uInt16 nFound = 0;
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+
+ if ( rDoc.GetDrawLayer() )
+ nFound = DoUpdateCharts( ScAddress( rViewData.GetCurX(),
+ rViewData.GetCurY(),
+ rViewData.GetTabNo()),
+ rDoc,
+ bAllCharts );
+
+ if ( !nFound && !bAllCharts )
+ ErrorMessage(STR_NOCHARTATCURSOR);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/dbfunc3.cxx b/sc/source/ui/view/dbfunc3.cxx
new file mode 100644
index 000000000..1eaea7037
--- /dev/null
+++ b/sc/source/ui/view/dbfunc3.cxx
@@ -0,0 +1,2314 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <dbfunc.hxx>
+#include <scitems.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <sfx2/app.hxx>
+#include <unotools/collatorwrapper.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+#include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/DataPilotFieldSortMode.hpp>
+#include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
+#include <com/sun/star/sheet/MemberResultFlags.hpp>
+#include <com/sun/star/sheet/XDimensionsSupplier.hpp>
+#include <com/sun/star/sheet/XDrillDownDataSupplier.hpp>
+
+#include <global.hxx>
+#include <scresid.hxx>
+#include <globstr.hrc>
+#include <undotab.hxx>
+#include <undodat.hxx>
+#include <dbdata.hxx>
+#include <rangenam.hxx>
+#include <docsh.hxx>
+#include <olinetab.hxx>
+#include <olinefun.hxx>
+#include <dpobject.hxx>
+#include <dpsave.hxx>
+#include <dpdimsave.hxx>
+#include <dbdocfun.hxx>
+#include <dpoutput.hxx>
+#include <editable.hxx>
+#include <docpool.hxx>
+#include <patattr.hxx>
+#include <unonames.hxx>
+#include <userlist.hxx>
+#include <queryentry.hxx>
+#include <markdata.hxx>
+#include <tabvwsh.hxx>
+#include <generalfunction.hxx>
+#include <sortparam.hxx>
+
+#include <comphelper/lok.hxx>
+#include <osl/diagnose.h>
+
+#include <memory>
+#include <string_view>
+#include <unordered_set>
+#include <unordered_map>
+#include <vector>
+#include <algorithm>
+
+using namespace com::sun::star;
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::UNO_QUERY;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::container::XNameAccess;
+using ::com::sun::star::sheet::XDimensionsSupplier;
+using ::std::vector;
+
+// outliner
+
+// create outline grouping
+
+void ScDBFunc::MakeOutline( bool bColumns, bool bRecord )
+{
+ ScRange aRange;
+ if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.MakeOutline( aRange, bColumns, bRecord, false );
+
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), bColumns ? COLUMN_HEADER : ROW_HEADER, GetViewData().GetTabNo());
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
+ bColumns, !bColumns, false /* bSizes*/,
+ false /* bHidden */, false /* bFiltered */,
+ true /* bGroups */, GetViewData().GetTabNo());
+ }
+ else
+ ErrorMessage(STR_NOMULTISELECT);
+}
+
+// delete outline grouping
+
+void ScDBFunc::RemoveOutline( bool bColumns, bool bRecord )
+{
+ ScRange aRange;
+ if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.RemoveOutline( aRange, bColumns, bRecord, false );
+
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), bColumns ? COLUMN_HEADER : ROW_HEADER, GetViewData().GetTabNo());
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
+ bColumns, !bColumns, false /* bSizes*/,
+ true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, GetViewData().GetTabNo());
+ }
+ else
+ ErrorMessage(STR_NOMULTISELECT);
+}
+
+// menu status: delete outlines
+
+void ScDBFunc::TestRemoveOutline( bool& rCol, bool& rRow )
+{
+ bool bColFound = false;
+ bool bRowFound = false;
+
+ SCCOL nStartCol, nEndCol;
+ SCROW nStartRow, nEndRow;
+ SCTAB nStartTab, nEndTab;
+ if (GetViewData().GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
+ {
+ SCTAB nTab = nStartTab;
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+ if (pTable)
+ {
+ ScOutlineEntry* pEntry;
+ SCCOLROW nStart;
+ SCCOLROW nEnd;
+ bool bColMarked = ( nStartRow == 0 && nEndRow == rDoc.MaxRow() );
+ bool bRowMarked = ( nStartCol == 0 && nEndCol == rDoc.MaxCol() );
+
+ // columns
+
+ if ( !bRowMarked || bColMarked ) // not when entire rows are marked
+ {
+ ScOutlineArray& rArray = pTable->GetColArray();
+ ScSubOutlineIterator aColIter( &rArray );
+ while (!bColFound)
+ {
+ pEntry=aColIter.GetNext();
+ if (!pEntry)
+ break;
+ nStart = pEntry->GetStart();
+ nEnd = pEntry->GetEnd();
+ if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) )
+ bColFound = true;
+ }
+ }
+
+ // rows
+
+ if ( !bColMarked || bRowMarked ) // not when entire columns are marked
+ {
+ ScOutlineArray& rArray = pTable->GetRowArray();
+ ScSubOutlineIterator aRowIter( &rArray );
+ while (!bRowFound)
+ {
+ pEntry=aRowIter.GetNext();
+ if (!pEntry)
+ break;
+ nStart = pEntry->GetStart();
+ nEnd = pEntry->GetEnd();
+ if ( nStartRow<=nEnd && nEndRow>=nStart )
+ bRowFound = true;
+ }
+ }
+ }
+ }
+
+ rCol = bColFound;
+ rRow = bRowFound;
+}
+
+void ScDBFunc::RemoveAllOutlines( bool bRecord )
+{
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScOutlineDocFunc aFunc(*pDocSh);
+
+ bool bOk = aFunc.RemoveAllOutlines( nTab, bRecord );
+
+ if (bOk)
+ {
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
+ true /* bColumns */, true /* bRows */, false /* bSizes*/,
+ true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+ UpdateScrollBars(BOTH_HEADERS);
+ }
+}
+
+// auto outlines
+
+void ScDBFunc::AutoOutline( )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScRange aRange( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab ); // the complete sheet, if nothing is marked
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ {
+ rMark.MarkToMulti();
+ aRange = rMark.GetMultiMarkArea();
+ }
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScOutlineDocFunc aFunc(*pDocSh);
+ aFunc.AutoOutline( aRange, true );
+}
+
+// select outline level
+
+void ScDBFunc::SelectLevel( bool bColumns, sal_uInt16 nLevel, bool bRecord )
+{
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScOutlineDocFunc aFunc(*pDocSh);
+
+ bool bOk = aFunc.SelectLevel( nTab, bColumns, nLevel, bRecord, true/*bPaint*/ );
+
+ if (bOk)
+ {
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
+ bColumns, !bColumns, false /* bSizes*/,
+ true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+ UpdateScrollBars(bColumns ? COLUMN_HEADER : ROW_HEADER);
+ }
+}
+
+// show individual outline groups
+
+void ScDBFunc::SetOutlineState( bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bHidden)
+{
+ const sal_uInt16 nHeadEntry = static_cast< sal_uInt16 >( -1 );
+ if ( nEntry == nHeadEntry)
+ SelectLevel( bColumns, sal::static_int_cast<sal_uInt16>(nLevel) );
+ else
+ {
+ if ( !bHidden )
+ ShowOutline( bColumns, sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) );
+ else
+ HideOutline( bColumns, sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) );
+ }
+}
+
+void ScDBFunc::ShowOutline( bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bRecord, bool bPaint )
+{
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScOutlineDocFunc aFunc(*pDocSh);
+
+ aFunc.ShowOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint );
+
+ if ( bPaint )
+ {
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
+ bColumns, !bColumns, false /* bSizes*/,
+ true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+ UpdateScrollBars(bColumns ? COLUMN_HEADER : ROW_HEADER);
+ }
+}
+
+// hide individual outline groups
+
+void ScDBFunc::HideOutline( bool bColumns, sal_uInt16 nLevel, sal_uInt16 nEntry, bool bRecord, bool bPaint )
+{
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScOutlineDocFunc aFunc(*pDocSh);
+
+ bool bOk = aFunc.HideOutline( nTab, bColumns, nLevel, nEntry, bRecord, bPaint );
+
+ if ( bOk && bPaint )
+ {
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
+ bColumns, !bColumns, false /* bSizes*/,
+ true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, nTab);
+ UpdateScrollBars(bColumns ? COLUMN_HEADER : ROW_HEADER);
+ }
+}
+
+// menu status: show/hide marked range
+
+bool ScDBFunc::OutlinePossible(bool bHide)
+{
+ bool bEnable = false;
+
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCTAB nStartTab;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ SCTAB nEndTab;
+
+ if (GetViewData().GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+ if (pTable)
+ {
+ SCCOLROW nStart;
+ SCCOLROW nEnd;
+
+ // columns
+
+ ScOutlineArray& rColArray = pTable->GetColArray();
+ ScSubOutlineIterator aColIter( &rColArray );
+ while (!bEnable)
+ {
+ ScOutlineEntry* pEntry = aColIter.GetNext();
+ if (!pEntry)
+ break;
+ nStart = pEntry->GetStart();
+ nEnd = pEntry->GetEnd();
+ if ( bHide )
+ {
+ if ( nStartCol<=static_cast<SCCOL>(nEnd) && nEndCol>=static_cast<SCCOL>(nStart) )
+ if (!pEntry->IsHidden())
+ bEnable = true;
+ }
+ else
+ {
+ if ( nStart>=nStartCol && nEnd<=nEndCol )
+ if (pEntry->IsHidden())
+ bEnable = true;
+ }
+ }
+
+ // rows
+
+ ScOutlineArray& rRowArray = pTable->GetRowArray();
+ ScSubOutlineIterator aRowIter( &rRowArray );
+ for (;;)
+ {
+ ScOutlineEntry* pEntry = aRowIter.GetNext();
+ if (!pEntry)
+ break;
+ nStart = pEntry->GetStart();
+ nEnd = pEntry->GetEnd();
+ if ( bHide )
+ {
+ if ( nStartRow<=nEnd && nEndRow>=nStart )
+ if (!pEntry->IsHidden())
+ bEnable = true;
+ }
+ else
+ {
+ if ( nStart>=nStartRow && nEnd<=nEndRow )
+ if (pEntry->IsHidden())
+ bEnable = true;
+ }
+ }
+ }
+ }
+
+ return bEnable;
+}
+
+// show marked range
+
+void ScDBFunc::ShowMarkedOutlines( bool bRecord )
+{
+ ScRange aRange;
+ if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScOutlineDocFunc aFunc(*pDocSh);
+ bool bDone = aFunc.ShowMarkedOutlines( aRange, bRecord );
+ if (bDone)
+ {
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ GetViewData().GetViewShell(), true, true,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, GetViewData().GetTabNo());
+ UpdateScrollBars();
+ }
+ }
+ else
+ ErrorMessage(STR_NOMULTISELECT);
+}
+
+// hide marked range
+
+void ScDBFunc::HideMarkedOutlines( bool bRecord )
+{
+ ScRange aRange;
+ if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScOutlineDocFunc aFunc(*pDocSh);
+ bool bDone = aFunc.HideMarkedOutlines( aRange, bRecord );
+ if (bDone)
+ {
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ GetViewData().GetViewShell(), true, true,
+ false /* bSizes*/, true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, GetViewData().GetTabNo());
+ UpdateScrollBars();
+ }
+ }
+ else
+ ErrorMessage(STR_NOMULTISELECT);
+}
+
+// sub totals
+
+void ScDBFunc::DoSubTotals( const ScSubTotalParam& rParam, bool bRecord,
+ const ScSortParam* pForceNewSort )
+{
+ bool bDo = !rParam.bRemoveOnly; // sal_False = only delete
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ SCTAB nTab = GetViewData().GetTabNo();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScDBData* pDBData = rDoc.GetDBAtArea( nTab, rParam.nCol1, rParam.nRow1,
+ rParam.nCol2, rParam.nRow2 );
+ if (!pDBData)
+ {
+ OSL_FAIL( "SubTotals: no DBData" );
+ return;
+ }
+
+ ScEditableTester aTester( rDoc, nTab, 0,rParam.nRow1+1, rDoc.MaxCol(),rDoc.MaxRow() );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ if (rDoc.HasAttrib( rParam.nCol1, rParam.nRow1+1, nTab,
+ rParam.nCol2, rParam.nRow2, nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
+ {
+ ErrorMessage(STR_MSSG_INSERTCELLS_0); // do not insert into merged
+ return;
+ }
+
+ weld::WaitObject aWait(GetViewData().GetDialogParent());
+ bool bOk = true;
+ if (rParam.bReplace)
+ {
+ if (rDoc.TestRemoveSubTotals( nTab, rParam ))
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_MSSG_DOSUBTOTALS_1))); // "delete data?"
+ xBox->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0)); // "StarCalc"
+ xBox->set_default_response(RET_YES);
+ bOk = xBox->run() == RET_YES;
+ }
+ }
+
+ if (!bOk)
+ return;
+
+ ScDocShellModificator aModificator( *pDocSh );
+
+ ScSubTotalParam aNewParam( rParam ); // change end of range
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScOutlineTable> pUndoTab;
+ std::unique_ptr<ScRangeName> pUndoRange;
+ std::unique_ptr<ScDBCollection> pUndoDB;
+
+ if (bRecord) // record old data
+ {
+ bool bOldFilter = bDo && rParam.bDoSort;
+ SCTAB nTabCount = rDoc.GetTableCount();
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+ if (pTable)
+ {
+ pUndoTab.reset(new ScOutlineTable( *pTable ));
+
+ SCCOLROW nOutStartCol; // row/column status
+ SCCOLROW nOutStartRow;
+ SCCOLROW nOutEndCol;
+ SCCOLROW nOutEndRow;
+ pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
+ pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
+
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ rDoc.CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
+ rDoc.CopyToDocument( 0, nOutStartRow, nTab, rDoc.MaxCol(), nOutEndRow, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
+ }
+ else
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, false, bOldFilter );
+
+ // record data range - including filter results
+ rDoc.CopyToDocument( 0,rParam.nRow1+1,nTab, rDoc.MaxCol(),rParam.nRow2,nTab,
+ InsertDeleteFlags::ALL, false, *pUndoDoc );
+
+ // all formulas for reference
+ rDoc.CopyToDocument( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),nTabCount-1,
+ InsertDeleteFlags::FORMULA, false, *pUndoDoc );
+
+ // database and other ranges
+ ScRangeName* pDocRange = rDoc.GetRangeName();
+ if (!pDocRange->empty())
+ pUndoRange.reset(new ScRangeName( *pDocRange ));
+ ScDBCollection* pDocDB = rDoc.GetDBCollection();
+ if (!pDocDB->empty())
+ pUndoDB.reset(new ScDBCollection( *pDocDB ));
+ }
+
+ ScOutlineTable* pOut = rDoc.GetOutlineTable( nTab );
+ if (pOut)
+ {
+ // Remove all existing outlines in the specified range.
+ ScOutlineArray& rRowArray = pOut->GetRowArray();
+ sal_uInt16 nDepth = rRowArray.GetDepth();
+ for (sal_uInt16 i = 0; i < nDepth; ++i)
+ {
+ bool bSize;
+ rRowArray.Remove(aNewParam.nRow1, aNewParam.nRow2, bSize);
+ }
+ }
+
+ if (rParam.bReplace)
+ rDoc.RemoveSubTotals( nTab, aNewParam );
+ bool bSuccess = true;
+ if (bDo)
+ {
+ // Sort
+ if ( rParam.bDoSort || pForceNewSort )
+ {
+ pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
+
+ // set subtotal fields before sorting
+ // (duplicate values are dropped, so that they can be called again)
+
+ ScSortParam aOldSort;
+ pDBData->GetSortParam( aOldSort );
+ ScSortParam aSortParam( aNewParam, pForceNewSort ? *pForceNewSort : aOldSort );
+ Sort( aSortParam, false, false );
+ }
+
+ bSuccess = rDoc.DoSubTotals( nTab, aNewParam );
+ }
+ ScRange aDirtyRange( aNewParam.nCol1, aNewParam.nRow1, nTab,
+ aNewParam.nCol2, aNewParam.nRow2, nTab );
+ rDoc.SetDirty( aDirtyRange, true );
+
+ if (bRecord)
+ {
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoSubTotals>( pDocSh, nTab,
+ rParam, aNewParam.nRow2,
+ std::move(pUndoDoc), std::move(pUndoTab), // pUndoDBData,
+ std::move(pUndoRange), std::move(pUndoDB) ) );
+ }
+
+ if (!bSuccess)
+ {
+ // "Can not insert any rows"
+ ErrorMessage(STR_MSSG_DOSUBTOTALS_2);
+ }
+
+ // store
+ pDBData->SetSubTotalParam( aNewParam );
+ pDBData->SetArea( nTab, aNewParam.nCol1,aNewParam.nRow1, aNewParam.nCol2,aNewParam.nRow2 );
+ rDoc.CompileDBFormula();
+
+ const ScRange aMarkRange( aNewParam.nCol1, aNewParam.nRow1, nTab, aNewParam.nCol2, aNewParam.nRow2, nTab);
+ DoneBlockMode();
+ InitOwnBlockMode( aMarkRange );
+ rMark.SetMarkArea( aMarkRange );
+ MarkDataChanged();
+
+ pDocSh->PostPaint(ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab),
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top | PaintPartFlags::Size);
+
+ aModificator.SetDocumentModified();
+
+ SelectionChanged();
+}
+
+// consolidate
+
+void ScDBFunc::Consolidate( const ScConsolidateParam& rParam )
+{
+ ScDocShell* pDocShell = GetViewData().GetDocShell();
+ pDocShell->DoConsolidate( rParam );
+ SetTabNo( rParam.nTab, true );
+}
+
+// pivot
+
+static OUString lcl_MakePivotTabName( std::u16string_view rPrefix, SCTAB nNumber )
+{
+ OUString aName = rPrefix + OUString::number( nNumber );
+ return aName;
+}
+
+bool ScDBFunc::MakePivotTable(
+ const ScDPSaveData& rData, const ScRange& rDest, bool bNewTable,
+ const ScDPObject& rSource )
+{
+ // error message if no fields are set
+ // this must be removed when drag&drop of fields from a toolbox is available
+
+ if ( rData.IsEmpty() )
+ {
+ ErrorMessage(STR_PIVOT_NODATA);
+ return false;
+ }
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = GetViewData().GetDocument();
+ bool bUndo = rDoc.IsUndoEnabled();
+
+ ScRange aDestRange = rDest;
+ if ( bNewTable )
+ {
+ SCTAB nSrcTab = GetViewData().GetTabNo();
+
+ OUString aName( ScResId(STR_PIVOT_TABLE) );
+ OUString aStr;
+
+ rDoc.GetName( nSrcTab, aStr );
+ aName += "_" + aStr + "_";
+
+ SCTAB nNewTab = nSrcTab+1;
+
+ SCTAB i=1;
+ while ( !rDoc.InsertTab( nNewTab, lcl_MakePivotTabName( aName, i ) ) && i <= MAXTAB )
+ i++;
+
+ bool bAppend = ( nNewTab+1 == rDoc.GetTableCount() );
+ if (bUndo)
+ {
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoInsertTab>( pDocSh, nNewTab, bAppend, lcl_MakePivotTabName( aName, i ) ));
+ }
+
+ GetViewData().InsertTab( nNewTab );
+ SetTabNo(nNewTab, true);
+
+ aDestRange = ScRange( 0, 0, nNewTab );
+ }
+
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor(
+ aDestRange.aStart.Col(), aDestRange.aStart.Row(), aDestRange.aStart.Tab() );
+
+ ScDPObject aObj( rSource );
+ aObj.SetOutRange( aDestRange );
+ if ( pDPObj && !rData.GetExistingDimensionData() )
+ {
+ // copy dimension data from old object - lost in the dialog
+ //! change the dialog to keep the dimension data
+
+ ScDPSaveData aNewData( rData );
+ const ScDPSaveData* pOldData = pDPObj->GetSaveData();
+ if ( pOldData )
+ {
+ const ScDPDimensionSaveData* pDimSave = pOldData->GetExistingDimensionData();
+ aNewData.SetDimensionData( pDimSave );
+ }
+ aObj.SetSaveData( aNewData );
+ }
+ else
+ aObj.SetSaveData( rData );
+
+ bool bAllowMove = (pDPObj != nullptr); // allow re-positioning when editing existing table
+
+ ScDBDocFunc aFunc( *pDocSh );
+ bool bSuccess = aFunc.DataPilotUpdate(pDPObj, &aObj, true, false, bAllowMove);
+
+ CursorPosChanged(); // shells may be switched
+
+ if ( bNewTable )
+ {
+ pDocSh->PostPaintExtras();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ }
+
+ return bSuccess;
+}
+
+void ScDBFunc::DeletePivotTable()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(),
+ GetViewData().GetTabNo() );
+ if ( pDPObj )
+ {
+ ScDBDocFunc aFunc( *pDocSh );
+ aFunc.RemovePivotTable(*pDPObj, true, false);
+ CursorPosChanged(); // shells may be switched
+ }
+ else
+ ErrorMessage(STR_PIVOT_NOTFOUND);
+}
+
+void ScDBFunc::RecalcPivotTable()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(),
+ GetViewData().GetTabNo() );
+ if (pDPObj)
+ {
+ // Remove existing data cache for the data that this datapilot uses,
+ // to force re-build data cache.
+ ScDBDocFunc aFunc(*pDocSh);
+ aFunc.RefreshPivotTables(pDPObj, false);
+
+ CursorPosChanged(); // shells may be switched
+ }
+ else
+ ErrorMessage(STR_PIVOT_NOTFOUND);
+}
+
+void ScDBFunc::GetSelectedMemberList(ScDPUniqueStringSet& rEntries, tools::Long& rDimension)
+{
+ ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ if ( !pDPObj )
+ return;
+
+ tools::Long nStartDimension = -1;
+ tools::Long nStartHierarchy = -1;
+ tools::Long nStartLevel = -1;
+
+ ScRangeListRef xRanges;
+ GetViewData().GetMultiArea( xRanges ); // incl. cursor if nothing is selected
+ size_t nRangeCount = xRanges->size();
+ bool bContinue = true;
+
+ for (size_t nRangePos=0; nRangePos < nRangeCount && bContinue; nRangePos++)
+ {
+ ScRange const & rRange = (*xRanges)[nRangePos];
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ SCCOL nEndCol = rRange.aEnd.Col();
+ SCROW nEndRow = rRange.aEnd.Row();
+ SCTAB nTab = rRange.aStart.Tab();
+
+ for (SCROW nRow=nStartRow; nRow<=nEndRow && bContinue; nRow++)
+ for (SCCOL nCol=nStartCol; nCol<=nEndCol && bContinue; nCol++)
+ {
+ sheet::DataPilotTableHeaderData aData;
+ pDPObj->GetHeaderPositionData(ScAddress(nCol, nRow, nTab), aData);
+ if ( aData.Dimension < 0 )
+ bContinue = false; // not part of any dimension
+ else
+ {
+ if ( nStartDimension < 0 ) // first member?
+ {
+ nStartDimension = aData.Dimension;
+ nStartHierarchy = aData.Hierarchy;
+ nStartLevel = aData.Level;
+ }
+ if ( aData.Dimension != nStartDimension ||
+ aData.Hierarchy != nStartHierarchy ||
+ aData.Level != nStartLevel )
+ {
+ bContinue = false; // cannot mix dimensions
+ }
+ }
+ if ( bContinue )
+ {
+ // accept any part of a member description, also subtotals,
+ // but don't stop if empty parts are contained
+ if ( aData.Flags & sheet::MemberResultFlags::HASMEMBER )
+ rEntries.insert(aData.MemberName);
+ }
+ }
+ }
+
+ rDimension = nStartDimension; // dimension from which the found members came
+ if (!bContinue)
+ rEntries.clear(); // remove all if not valid
+}
+
+bool ScDBFunc::HasSelectionForDateGroup( ScDPNumGroupInfo& rOldInfo, sal_Int32& rParts )
+{
+ // determine if the date group dialog has to be shown for the current selection
+
+ bool bFound = false;
+
+ SCCOL nCurX = GetViewData().GetCurX();
+ SCROW nCurY = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor( nCurX, nCurY, nTab );
+ if ( pDPObj )
+ {
+ ScDPUniqueStringSet aEntries;
+ tools::Long nSelectDimension = -1;
+ GetSelectedMemberList( aEntries, nSelectDimension );
+
+ if (!aEntries.empty())
+ {
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
+ OUString aBaseDimName( aDimName );
+
+ bool bInGroupDim = false;
+ bool bFoundParts = false;
+
+ ScDPDimensionSaveData* pDimData =
+ const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() );
+ if ( pDimData )
+ {
+ const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
+ const ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDim( aDimName );
+ if ( pNumGroupDim )
+ {
+ // existing num group dimension
+
+ if ( pNumGroupDim->GetDatePart() != 0 )
+ {
+ // dimension has date info -> edit settings of this dimension
+ // (parts are collected below)
+
+ rOldInfo = pNumGroupDim->GetDateInfo();
+ bFound = true;
+ }
+ else if ( pNumGroupDim->GetInfo().mbDateValues )
+ {
+ // Numerical grouping with DateValues flag is used for grouping
+ // of days with a "Number of days" value.
+
+ rOldInfo = pNumGroupDim->GetInfo();
+ rParts = css::sheet::DataPilotFieldGroupBy::DAYS; // not found in CollectDateParts
+ bFoundParts = true;
+ bFound = true;
+ }
+ bInGroupDim = true;
+ }
+ else if ( pGroupDim )
+ {
+ // existing additional group dimension
+
+ if ( pGroupDim->GetDatePart() != 0 )
+ {
+ // dimension has date info -> edit settings of this dimension
+ // (parts are collected below)
+
+ rOldInfo = pGroupDim->GetDateInfo();
+ aBaseDimName = pGroupDim->GetSourceDimName();
+ bFound = true;
+ }
+ bInGroupDim = true;
+ }
+ }
+ if ( bFound && !bFoundParts )
+ {
+ // collect date parts from all group dimensions
+ rParts = pDimData->CollectDateParts( aBaseDimName );
+ }
+ if ( !bFound && !bInGroupDim )
+ {
+ // create new date group dimensions if the selection is a single cell
+ // in a normal dimension with date content
+
+ ScRange aSelRange;
+ if ( (GetViewData().GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) &&
+ aSelRange.aStart == aSelRange.aEnd )
+ {
+ SCCOL nSelCol = aSelRange.aStart.Col();
+ SCROW nSelRow = aSelRange.aStart.Row();
+ SCTAB nSelTab = aSelRange.aStart.Tab();
+ if ( rDoc.HasValueData( nSelCol, nSelRow, nSelTab ) )
+ {
+ sal_uLong nIndex = rDoc.GetAttr(
+ nSelCol, nSelRow, nSelTab, ATTR_VALUE_FORMAT)->GetValue();
+ SvNumFormatType nType = rDoc.GetFormatTable()->GetType(nIndex);
+ if ( nType == SvNumFormatType::DATE || nType == SvNumFormatType::TIME || nType == SvNumFormatType::DATETIME )
+ {
+ bFound = true;
+ // use currently selected value for automatic limits
+ if( rOldInfo.mbAutoStart )
+ rOldInfo.mfStart = rDoc.GetValue( aSelRange.aStart );
+ if( rOldInfo.mbAutoEnd )
+ rOldInfo.mfEnd = rDoc.GetValue( aSelRange.aStart );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return bFound;
+}
+
+bool ScDBFunc::HasSelectionForNumGroup( ScDPNumGroupInfo& rOldInfo )
+{
+ // determine if the numeric group dialog has to be shown for the current selection
+
+ bool bFound = false;
+
+ SCCOL nCurX = GetViewData().GetCurX();
+ SCROW nCurY = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor( nCurX, nCurY, nTab );
+ if ( pDPObj )
+ {
+ ScDPUniqueStringSet aEntries;
+ tools::Long nSelectDimension = -1;
+ GetSelectedMemberList( aEntries, nSelectDimension );
+
+ if (!aEntries.empty())
+ {
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
+
+ bool bInGroupDim = false;
+
+ ScDPDimensionSaveData* pDimData =
+ const_cast<ScDPDimensionSaveData*>( pDPObj->GetSaveData()->GetExistingDimensionData() );
+ if ( pDimData )
+ {
+ const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
+ if ( pNumGroupDim )
+ {
+ // existing num group dimension
+ // -> edit settings of this dimension
+
+ rOldInfo = pNumGroupDim->GetInfo();
+ bFound = true;
+ }
+ else if ( pDimData->GetNamedGroupDim( aDimName ) )
+ bInGroupDim = true; // in a group dimension
+ }
+ if ( !bFound && !bInGroupDim )
+ {
+ // create a new num group dimension if the selection is a single cell
+ // in a normal dimension with numeric content
+
+ ScRange aSelRange;
+ if ( (GetViewData().GetSimpleArea( aSelRange ) == SC_MARK_SIMPLE) &&
+ aSelRange.aStart == aSelRange.aEnd )
+ {
+ if ( rDoc.HasValueData( aSelRange.aStart.Col(), aSelRange.aStart.Row(),
+ aSelRange.aStart.Tab() ) )
+ {
+ bFound = true;
+ // use currently selected value for automatic limits
+ if( rOldInfo.mbAutoStart )
+ rOldInfo.mfStart = rDoc.GetValue( aSelRange.aStart );
+ if( rOldInfo.mbAutoEnd )
+ rOldInfo.mfEnd = rDoc.GetValue( aSelRange.aStart );
+ }
+ }
+ }
+ }
+ }
+
+ return bFound;
+}
+
+void ScDBFunc::DateGroupDataPilot( const ScDPNumGroupInfo& rInfo, sal_Int32 nParts )
+{
+ ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ if (!pDPObj)
+ return;
+
+ ScDPUniqueStringSet aEntries;
+ tools::Long nSelectDimension = -1;
+ GetSelectedMemberList( aEntries, nSelectDimension );
+
+ if (aEntries.empty())
+ return;
+
+ std::vector<OUString> aDeletedNames;
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
+
+ ScDPSaveData aData( *pDPObj->GetSaveData() );
+ ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
+
+ // find the source dimension name.
+ OUString aBaseDimName = aDimName;
+ if( const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName ) )
+ aBaseDimName = pBaseGroupDim->GetSourceDimName();
+
+ // Remove all group dimensions associated with this source dimension. For
+ // date grouping, we need to remove all existing groups for the affected
+ // source dimension and build new one(s) from scratch. Keep the deleted
+ // names so that they can be reused during re-construction.
+ aData.RemoveAllGroupDimensions(aBaseDimName, &aDeletedNames);
+
+ if ( nParts )
+ {
+ // create date group dimensions
+
+ bool bFirst = true;
+ sal_Int32 nMask = 1;
+ for (sal_uInt16 nBit=0; nBit<32; nBit++)
+ {
+ if ( nParts & nMask )
+ {
+ if ( bFirst )
+ {
+ // innermost part: create NumGroupDimension (replacing original values)
+ // Dimension name is left unchanged
+
+ if ( (nParts == sheet::DataPilotFieldGroupBy::DAYS) && (rInfo.mfStep >= 1.0) )
+ {
+ // only days, and a step value specified: use numerical grouping
+ // with DateValues flag, not date grouping
+
+ ScDPNumGroupInfo aNumInfo( rInfo );
+ aNumInfo.mbDateValues = true;
+
+ ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, aNumInfo );
+ pDimData->AddNumGroupDimension( aNumGroupDim );
+ }
+ else
+ {
+ ScDPSaveNumGroupDimension aNumGroupDim( aBaseDimName, rInfo, nMask );
+ pDimData->AddNumGroupDimension( aNumGroupDim );
+ }
+
+ bFirst = false;
+ }
+ else
+ {
+ // additional parts: create GroupDimension (shown as additional dimensions)
+ OUString aGroupDimName =
+ pDimData->CreateDateGroupDimName(nMask, *pDPObj, true, &aDeletedNames);
+ ScDPSaveGroupDimension aGroupDim( aBaseDimName, aGroupDimName );
+ aGroupDim.SetDateInfo( rInfo, nMask );
+ pDimData->AddGroupDimension( aGroupDim );
+
+ // set orientation
+ ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName );
+ if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN )
+ {
+ ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aBaseDimName );
+ pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
+ aData.SetPosition( pSaveDimension, 0 ); //! before (immediate) base
+ }
+ }
+ }
+ nMask *= 2;
+ }
+ }
+
+ // apply changes
+ ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
+ pDPObj->SetSaveData( aData );
+ aFunc.RefreshPivotTableGroups(pDPObj);
+
+ // unmark cell selection
+ Unmark();
+}
+
+void ScDBFunc::NumGroupDataPilot( const ScDPNumGroupInfo& rInfo )
+{
+ ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ if (!pDPObj)
+ return;
+
+ ScDPUniqueStringSet aEntries;
+ tools::Long nSelectDimension = -1;
+ GetSelectedMemberList( aEntries, nSelectDimension );
+
+ if (aEntries.empty())
+ return;
+
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
+
+ ScDPSaveData aData( *pDPObj->GetSaveData() );
+ ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
+
+ ScDPSaveNumGroupDimension* pExisting = pDimData->GetNumGroupDimAcc( aDimName );
+ if ( pExisting )
+ {
+ // modify existing group dimension
+ pExisting->SetGroupInfo( rInfo );
+ }
+ else
+ {
+ // create new group dimension
+ ScDPSaveNumGroupDimension aNumGroupDim( aDimName, rInfo );
+ pDimData->AddNumGroupDimension( aNumGroupDim );
+ }
+
+ // apply changes
+ ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
+ pDPObj->SetSaveData( aData );
+ aFunc.RefreshPivotTableGroups(pDPObj);
+
+ // unmark cell selection
+ Unmark();
+}
+
+void ScDBFunc::GroupDataPilot()
+{
+ ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ if (!pDPObj)
+ return;
+
+ ScDPUniqueStringSet aEntries;
+ tools::Long nSelectDimension = -1;
+ GetSelectedMemberList( aEntries, nSelectDimension );
+
+ if (aEntries.empty())
+ return;
+
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
+
+ ScDPSaveData aData( *pDPObj->GetSaveData() );
+ ScDPDimensionSaveData* pDimData = aData.GetDimensionData(); // created if not there
+
+ // find original base
+ OUString aBaseDimName = aDimName;
+ const ScDPSaveGroupDimension* pBaseGroupDim = pDimData->GetNamedGroupDim( aDimName );
+ if ( pBaseGroupDim )
+ {
+ // any entry's SourceDimName is the original base
+ aBaseDimName = pBaseGroupDim->GetSourceDimName();
+ }
+
+ // find existing group dimension
+ // (using the selected dim, can be intermediate group dim)
+ ScDPSaveGroupDimension* pGroupDimension = pDimData->GetGroupDimAccForBase( aDimName );
+
+ // remove the selected items from their groups
+ // (empty groups are removed, too)
+ if ( pGroupDimension )
+ {
+ for (const OUString& aEntryName : aEntries)
+ {
+ if ( pBaseGroupDim )
+ {
+ // for each selected (intermediate) group, remove all its items
+ // (same logic as for adding, below)
+ const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
+ if ( pBaseGroup )
+ pBaseGroup->RemoveElementsFromGroups( *pGroupDimension ); // remove all elements
+ else
+ pGroupDimension->RemoveFromGroups( aEntryName );
+ }
+ else
+ pGroupDimension->RemoveFromGroups( aEntryName );
+ }
+ }
+
+ std::unique_ptr<ScDPSaveGroupDimension> pNewGroupDim;
+ if ( !pGroupDimension )
+ {
+ // create a new group dimension
+ OUString aGroupDimName =
+ pDimData->CreateGroupDimName(aBaseDimName, *pDPObj, false, nullptr);
+ pNewGroupDim.reset(new ScDPSaveGroupDimension( aBaseDimName, aGroupDimName ));
+
+ pGroupDimension = pNewGroupDim.get(); // make changes to the new dim if none existed
+
+ if ( pBaseGroupDim )
+ {
+ // If it's a higher-order group dimension, pre-allocate groups for all
+ // non-selected original groups, so the individual base members aren't
+ // used for automatic groups (this would make the original groups hard
+ // to find).
+ //! Also do this when removing groups?
+ //! Handle this case dynamically with automatic groups?
+
+ tools::Long nGroupCount = pBaseGroupDim->GetGroupCount();
+ for ( tools::Long nGroup = 0; nGroup < nGroupCount; nGroup++ )
+ {
+ const ScDPSaveGroupItem& rBaseGroup = pBaseGroupDim->GetGroupByIndex( nGroup );
+
+ if (!aEntries.count(rBaseGroup.GetGroupName()))
+ {
+ // add an additional group for each item that is not in the selection
+ ScDPSaveGroupItem aGroup( rBaseGroup.GetGroupName() );
+ aGroup.AddElementsFromGroup( rBaseGroup );
+ pGroupDimension->AddGroupItem( aGroup );
+ }
+ }
+ }
+ }
+ OUString aGroupDimName = pGroupDimension->GetGroupDimName();
+
+ OUString aGroupName = pGroupDimension->CreateGroupName(ScResId(STR_PIVOT_GROUP));
+ ScDPSaveGroupItem aGroup( aGroupName );
+ for (const OUString& aEntryName : aEntries)
+ {
+ if ( pBaseGroupDim )
+ {
+ // for each selected (intermediate) group, add all its items
+ const ScDPSaveGroupItem* pBaseGroup = pBaseGroupDim->GetNamedGroup( aEntryName );
+ if ( pBaseGroup )
+ aGroup.AddElementsFromGroup( *pBaseGroup );
+ else
+ aGroup.AddElement( aEntryName ); // no group found -> automatic group, add the item itself
+ }
+ else
+ aGroup.AddElement( aEntryName ); // no group dimension, add all items directly
+ }
+
+ pGroupDimension->AddGroupItem( aGroup );
+
+ if ( pNewGroupDim )
+ {
+ pDimData->AddGroupDimension( *pNewGroupDim );
+ pNewGroupDim.reset(); // AddGroupDimension copies the object
+ // don't access pGroupDimension after here
+ }
+ pGroupDimension = nullptr;
+
+ // set orientation
+ ScDPSaveDimension* pSaveDimension = aData.GetDimensionByName( aGroupDimName );
+ if ( pSaveDimension->GetOrientation() == sheet::DataPilotFieldOrientation_HIDDEN )
+ {
+ ScDPSaveDimension* pOldDimension = aData.GetDimensionByName( aDimName );
+ pSaveDimension->SetOrientation( pOldDimension->GetOrientation() );
+ aData.SetPosition( pSaveDimension, 0 ); //! before (immediate) base
+ }
+
+ // apply changes
+ ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
+ pDPObj->SetSaveData( aData );
+ aFunc.RefreshPivotTableGroups(pDPObj);
+
+ // unmark cell selection
+ Unmark();
+}
+
+void ScDBFunc::UngroupDataPilot()
+{
+ ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ if (!pDPObj)
+ return;
+
+ ScDPUniqueStringSet aEntries;
+ tools::Long nSelectDimension = -1;
+ GetSelectedMemberList( aEntries, nSelectDimension );
+
+ if (aEntries.empty())
+ return;
+
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
+
+ ScDPSaveData aData( *pDPObj->GetSaveData() );
+ if (!aData.GetExistingDimensionData())
+ // There is nothing to ungroup.
+ return;
+
+ ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
+
+ ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName );
+ const ScDPSaveNumGroupDimension* pNumGroupDim = pDimData->GetNumGroupDim( aDimName );
+ if ( ( pGroupDim && pGroupDim->GetDatePart() != 0 ) ||
+ ( pNumGroupDim && pNumGroupDim->GetDatePart() != 0 ) )
+ {
+ // Date grouping: need to remove all affected group dimensions.
+ // This is done using DateGroupDataPilot with nParts=0.
+
+ DateGroupDataPilot( ScDPNumGroupInfo(), 0 );
+ return;
+ }
+
+ if ( pGroupDim )
+ {
+ for (const auto& rEntry : aEntries)
+ pGroupDim->RemoveGroup(rEntry);
+
+ // remove group dimension if empty
+ bool bEmptyDim = pGroupDim->IsEmpty();
+ if ( !bEmptyDim )
+ {
+ // If all remaining groups in the dimension aren't shown, remove
+ // the dimension too, as if it was completely empty.
+ ScDPUniqueStringSet aVisibleEntries;
+ pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension );
+ bEmptyDim = pGroupDim->HasOnlyHidden( aVisibleEntries );
+ }
+ if ( bEmptyDim )
+ {
+ pDimData->RemoveGroupDimension( aDimName ); // pGroupDim is deleted
+
+ // also remove SaveData settings for the dimension that no longer exists
+ aData.RemoveDimensionByName( aDimName );
+ }
+ }
+ else if ( pNumGroupDim )
+ {
+ // remove the numerical grouping
+ pDimData->RemoveNumGroupDimension( aDimName );
+ // SaveData settings can remain unchanged - the same dimension still exists
+ }
+
+ // apply changes
+ ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
+ pDPObj->SetSaveData( aData );
+ aFunc.RefreshPivotTableGroups(pDPObj);
+
+ // unmark cell selection
+ Unmark();
+}
+
+static OUString lcl_replaceMemberNameInSubtotal(const OUString& rSubtotal, std::u16string_view rMemberName)
+{
+ sal_Int32 n = rSubtotal.getLength();
+ const sal_Unicode* p = rSubtotal.getStr();
+ OUStringBuffer aBuf, aWordBuf;
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ sal_Unicode c = p[i];
+ if (c == ' ')
+ {
+ OUString aWord = aWordBuf.makeStringAndClear();
+ if (aWord == rMemberName)
+ aBuf.append('?');
+ else
+ aBuf.append(aWord);
+ aBuf.append(c);
+ }
+ else if (c == '\\')
+ {
+ // Escape a backslash character.
+ aWordBuf.append(c);
+ aWordBuf.append(c);
+ }
+ else if (c == '?')
+ {
+ // A literal '?' must be escaped with a backslash ('\');
+ aWordBuf.append('\\');
+ aWordBuf.append(c);
+ }
+ else
+ aWordBuf.append(c);
+ }
+
+ if (!aWordBuf.isEmpty())
+ {
+ OUString aWord = aWordBuf.makeStringAndClear();
+ if (aWord == rMemberName)
+ aBuf.append('?');
+ else
+ aBuf.append(aWord);
+ }
+
+ return aBuf.makeStringAndClear();
+}
+
+void ScDBFunc::DataPilotInput( const ScAddress& rPos, const OUString& rString )
+{
+ using namespace ::com::sun::star::sheet;
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor( rPos.Col(), rPos.Row(), rPos.Tab() );
+ if (!pDPObj)
+ return;
+
+ OUString aOldText = rDoc.GetString(rPos.Col(), rPos.Row(), rPos.Tab());
+
+ if ( aOldText == rString )
+ {
+ // nothing to do: silently exit
+ return;
+ }
+
+ TranslateId pErrorId;
+
+ pDPObj->BuildAllDimensionMembers();
+ ScDPSaveData aData( *pDPObj->GetSaveData() );
+ bool bChange = false;
+ bool bNeedReloadGroups = false;
+
+ DataPilotFieldOrientation nOrient = DataPilotFieldOrientation_HIDDEN;
+ tools::Long nField = pDPObj->GetHeaderDim( rPos, nOrient );
+ if ( nField >= 0 )
+ {
+ // changing a field title
+ if ( aData.GetExistingDimensionData() )
+ {
+ // only group dimensions can be renamed
+
+ ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
+ ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aOldText );
+ if ( pGroupDim )
+ {
+ // valid name: not empty, no existing dimension (group or other)
+ if (!rString.isEmpty() && !pDPObj->IsDimNameInUse(rString))
+ {
+ pGroupDim->Rename( rString );
+
+ // also rename in SaveData to preserve the field settings
+ ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aOldText );
+ pSaveDim->SetName( rString );
+
+ bChange = true;
+ }
+ else
+ pErrorId = STR_INVALIDNAME;
+ }
+ }
+ else if (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW)
+ {
+ bool bDataLayout = false;
+ OUString aDimName = pDPObj->GetDimName(nField, bDataLayout);
+ ScDPSaveDimension* pDim = bDataLayout ? aData.GetDataLayoutDimension() : aData.GetDimensionByName(aDimName);
+ if (pDim)
+ {
+ if (!rString.isEmpty())
+ {
+ if (rString.equalsIgnoreAsciiCase(aDimName))
+ {
+ pDim->RemoveLayoutName();
+ bChange = true;
+ }
+ else if (!pDPObj->IsDimNameInUse(rString))
+ {
+ pDim->SetLayoutName(rString);
+ bChange = true;
+ }
+ else
+ pErrorId = STR_INVALIDNAME;
+ }
+ else
+ pErrorId = STR_INVALIDNAME;
+ }
+ }
+ }
+ else if (pDPObj->IsDataDescriptionCell(rPos))
+ {
+ // There is only one data dimension.
+ ScDPSaveDimension* pDim = aData.GetFirstDimension(sheet::DataPilotFieldOrientation_DATA);
+ if (pDim)
+ {
+ if (!rString.isEmpty())
+ {
+ if (pDim->GetName().equalsIgnoreAsciiCase(rString))
+ {
+ pDim->RemoveLayoutName();
+ bChange = true;
+ }
+ else if (!pDPObj->IsDimNameInUse(rString))
+ {
+ pDim->SetLayoutName(rString);
+ bChange = true;
+ }
+ else
+ pErrorId = STR_INVALIDNAME;
+ }
+ else
+ pErrorId = STR_INVALIDNAME;
+ }
+ }
+ else
+ {
+ // This is not a field header.
+ sheet::DataPilotTableHeaderData aPosData;
+ pDPObj->GetHeaderPositionData(rPos, aPosData);
+
+ if ((aPosData.Flags & MemberResultFlags::HASMEMBER) && !aOldText.isEmpty())
+ {
+ if ( aData.GetExistingDimensionData() && !(aPosData.Flags & MemberResultFlags::SUBTOTAL))
+ {
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName( aPosData.Dimension, bIsDataLayout );
+
+ ScDPDimensionSaveData* pDimData = aData.GetDimensionData();
+ ScDPSaveGroupDimension* pGroupDim = pDimData->GetNamedGroupDimAcc( aDimName );
+ if ( pGroupDim )
+ {
+ // valid name: not empty, no existing group in this dimension
+ //! ignore case?
+ if (!rString.isEmpty() && !pGroupDim->GetNamedGroup(rString))
+ {
+ ScDPSaveGroupItem* pGroup = pGroupDim->GetNamedGroupAcc( aOldText );
+ if ( pGroup )
+ pGroup->Rename( rString ); // rename the existing group
+ else
+ {
+ // create a new group to replace the automatic group
+ ScDPSaveGroupItem aGroup( rString );
+ aGroup.AddElement( aOldText );
+ pGroupDim->AddGroupItem( aGroup );
+ }
+
+ // in both cases also adjust savedata, to preserve member settings (show details)
+ ScDPSaveDimension* pSaveDim = aData.GetDimensionByName( aDimName );
+ ScDPSaveMember* pSaveMember = pSaveDim->GetExistingMemberByName( aOldText );
+ if ( pSaveMember )
+ pSaveMember->SetName( rString );
+
+ bChange = true;
+ bNeedReloadGroups = true;
+ }
+ else
+ pErrorId = STR_INVALIDNAME;
+ }
+ }
+ else if (aPosData.Flags & MemberResultFlags::GRANDTOTAL)
+ {
+ aData.SetGrandTotalName(rString);
+ bChange = true;
+ }
+ else if (aPosData.Dimension >= 0 && !aPosData.MemberName.isEmpty())
+ {
+ bool bDataLayout = false;
+ OUString aDimName = pDPObj->GetDimName(static_cast<tools::Long>(aPosData.Dimension), bDataLayout);
+ if (bDataLayout)
+ {
+ // data dimension
+ do
+ {
+ if (aPosData.Flags & MemberResultFlags::SUBTOTAL)
+ break;
+
+ ScDPSaveDimension* pDim = aData.GetDimensionByName(aPosData.MemberName);
+ if (!pDim)
+ break;
+
+ if (rString.isEmpty())
+ {
+ pErrorId = STR_INVALIDNAME;
+ break;
+ }
+
+ if (aPosData.MemberName.equalsIgnoreAsciiCase(rString))
+ {
+ pDim->RemoveLayoutName();
+ bChange = true;
+ }
+ else if (!pDPObj->IsDimNameInUse(rString))
+ {
+ pDim->SetLayoutName(rString);
+ bChange = true;
+ }
+ else
+ pErrorId = STR_INVALIDNAME;
+ }
+ while (false);
+ }
+ else
+ {
+ // field member
+ do
+ {
+ ScDPSaveDimension* pDim = aData.GetDimensionByName(aDimName);
+ if (!pDim)
+ break;
+
+ ScDPSaveMember* pMem = pDim->GetExistingMemberByName(aPosData.MemberName);
+ if (!pMem)
+ break;
+
+ if (aPosData.Flags & MemberResultFlags::SUBTOTAL)
+ {
+ // Change subtotal only when the table has one data dimension.
+ if (aData.GetDataDimensionCount() > 1)
+ break;
+
+ // display name for subtotal is allowed only if the subtotal type is 'Automatic'.
+ if (pDim->GetSubTotalsCount() != 1)
+ break;
+
+ if (pDim->GetSubTotalFunc(0) != ScGeneralFunction::AUTO)
+ break;
+
+ const std::optional<OUString> & pLayoutName = pMem->GetLayoutName();
+ OUString aMemberName;
+ if (pLayoutName)
+ aMemberName = *pLayoutName;
+ else
+ aMemberName = aPosData.MemberName;
+
+ OUString aNew = lcl_replaceMemberNameInSubtotal(rString, aMemberName);
+ pDim->SetSubtotalName(aNew);
+ bChange = true;
+ }
+ else
+ {
+ // Check to make sure the member name isn't
+ // already used.
+ if (!rString.isEmpty())
+ {
+ if (rString.equalsIgnoreAsciiCase(pMem->GetName()))
+ {
+ pMem->RemoveLayoutName();
+ bChange = true;
+ }
+ else if (!pDim->IsMemberNameInUse(rString))
+ {
+ pMem->SetLayoutName(rString);
+ bChange = true;
+ }
+ else
+ pErrorId = STR_INVALIDNAME;
+ }
+ else
+ pErrorId = STR_INVALIDNAME;
+ }
+ }
+ while (false);
+ }
+ }
+ }
+ }
+
+ if ( bChange )
+ {
+ // apply changes
+ ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
+ pDPObj->SetSaveData( aData );
+ if (bNeedReloadGroups)
+ {
+ ScDPCollection* pDPs = rDoc.GetDPCollection();
+ if (pDPs)
+ {
+ o3tl::sorted_vector<ScDPObject*> aRefs;
+ // tdf#111305: Reload groups in cache after modifications.
+ pDPs->ReloadGroupsInCache(pDPObj, aRefs);
+ } // pDPs
+ } // bNeedReloadGroups
+ aFunc.UpdatePivotTable(*pDPObj, true, false);
+ }
+ else
+ {
+ if (!pErrorId)
+ pErrorId = STR_ERR_DATAPILOT_INPUT;
+ ErrorMessage(pErrorId);
+ }
+}
+
+static void lcl_MoveToEnd( ScDPSaveDimension& rDim, const OUString& rItemName )
+{
+ std::unique_ptr<ScDPSaveMember> pNewMember;
+ const ScDPSaveMember* pOldMember = rDim.GetExistingMemberByName( rItemName );
+ if ( pOldMember )
+ pNewMember.reset(new ScDPSaveMember( *pOldMember ));
+ else
+ pNewMember.reset(new ScDPSaveMember( rItemName ));
+ rDim.AddMember( std::move(pNewMember) );
+ // AddMember takes ownership of the new pointer,
+ // puts it to the end of the list even if it was in the list before.
+}
+
+namespace {
+
+struct ScOUStringCollate
+{
+ CollatorWrapper* mpCollator;
+
+ explicit ScOUStringCollate(CollatorWrapper* pColl) : mpCollator(pColl) {}
+
+ bool operator()(const OUString& rStr1, const OUString& rStr2) const
+ {
+ return ( mpCollator->compareString(rStr1, rStr2) < 0 );
+ }
+};
+
+}
+
+void ScDBFunc::DataPilotSort(ScDPObject* pDPObj, tools::Long nDimIndex, bool bAscending, const sal_uInt16* pUserListId)
+{
+ if (!pDPObj)
+ return;
+
+ // We need to run this to get all members later.
+ if ( pUserListId )
+ pDPObj->BuildAllDimensionMembers();
+
+ if (nDimIndex < 0)
+ // Invalid dimension index. Bail out.
+ return;
+
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ if (!pSaveData)
+ return;
+
+ ScDPSaveData aNewSaveData(*pSaveData);
+ bool bDataLayout;
+ OUString aDimName = pDPObj->GetDimName(nDimIndex, bDataLayout);
+ ScDPSaveDimension* pSaveDim = aNewSaveData.GetDimensionByName(aDimName);
+ if (!pSaveDim)
+ return;
+
+ // manual evaluation of sort order is only needed if a user list id is given
+ if ( pUserListId )
+ {
+ typedef ScDPSaveDimension::MemberList MemList;
+ const MemList& rDimMembers = pSaveDim->GetMembers();
+ vector<OUString> aMembers;
+ std::unordered_set<OUString> aMemberSet;
+ size_t nMemberCount = 0;
+ for (ScDPSaveMember* pMem : rDimMembers)
+ {
+ aMembers.push_back(pMem->GetName());
+ aMemberSet.insert(pMem->GetName());
+ ++nMemberCount;
+ }
+
+ // Sort the member list in ascending order.
+ ScOUStringCollate aCollate( &ScGlobal::GetCollator() );
+ std::stable_sort(aMembers.begin(), aMembers.end(), aCollate);
+
+ // Collect and rank those custom sort strings that also exist in the member name list.
+
+ typedef std::unordered_map<OUString, sal_uInt16> UserSortMap;
+ UserSortMap aSubStrs;
+ sal_uInt16 nSubCount = 0;
+ ScUserList* pUserList = ScGlobal::GetUserList();
+ if (!pUserList)
+ return;
+
+ {
+ size_t n = pUserList->size();
+ if (!n || *pUserListId >= static_cast<sal_uInt16>(n))
+ return;
+ }
+
+ const ScUserListData& rData = (*pUserList)[*pUserListId];
+ sal_uInt16 n = rData.GetSubCount();
+ for (sal_uInt16 i = 0; i < n; ++i)
+ {
+ OUString aSub = rData.GetSubStr(i);
+ if (!aMemberSet.count(aSub))
+ // This string doesn't exist in the member name set. Don't add this.
+ continue;
+
+ aSubStrs.emplace(aSub, nSubCount++);
+ }
+
+ // Rank all members.
+
+ vector<OUString> aRankedNames(nMemberCount);
+ sal_uInt16 nCurStrId = 0;
+ for (auto const& aMemberName : aMembers)
+ {
+ sal_uInt16 nRank = 0;
+ UserSortMap::const_iterator itrSub = aSubStrs.find(aMemberName);
+ if (itrSub == aSubStrs.end())
+ nRank = nSubCount + nCurStrId++;
+ else
+ nRank = itrSub->second;
+
+ if (!bAscending)
+ nRank = static_cast< sal_uInt16 >( nMemberCount - nRank - 1 );
+
+ aRankedNames[nRank] = aMemberName;
+ }
+
+ // Re-order ScDPSaveMember instances with the new ranks.
+ for (auto const& aRankedName : aRankedNames)
+ {
+ const ScDPSaveMember* pOldMem = pSaveDim->GetExistingMemberByName(aRankedName);
+ if (!pOldMem)
+ // All members are supposed to be present.
+ continue;
+
+ pSaveDim->AddMember(std::unique_ptr<ScDPSaveMember>(new ScDPSaveMember(*pOldMem)));
+ }
+
+ // Set the sorting mode to manual for now. We may introduce a new sorting
+ // mode later on.
+
+ sheet::DataPilotFieldSortInfo aSortInfo;
+ aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL;
+ pSaveDim->SetSortInfo(&aSortInfo);
+ }
+ else
+ {
+ // without user list id, just apply sorting mode
+
+ sheet::DataPilotFieldSortInfo aSortInfo;
+ aSortInfo.Mode = sheet::DataPilotFieldSortMode::NAME;
+ aSortInfo.IsAscending = bAscending;
+ pSaveDim->SetSortInfo(&aSortInfo);
+ }
+
+ // Update the datapilot with the newly sorted field members.
+
+ std::unique_ptr<ScDPObject> pNewObj(new ScDPObject(*pDPObj));
+ pNewObj->SetSaveData(aNewSaveData);
+ ScDBDocFunc aFunc(*GetViewData().GetDocShell());
+
+ aFunc.DataPilotUpdate(pDPObj, pNewObj.get(), true, false);
+}
+
+bool ScDBFunc::DataPilotMove( const ScRange& rSource, const ScAddress& rDest )
+{
+ bool bRet = false;
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor( rSource.aStart.Col(), rSource.aStart.Row(), rSource.aStart.Tab() );
+ if ( pDPObj && pDPObj == rDoc.GetDPAtCursor( rDest.Col(), rDest.Row(), rDest.Tab() ) )
+ {
+ sheet::DataPilotTableHeaderData aDestData;
+ pDPObj->GetHeaderPositionData( rDest, aDestData );
+ bool bValid = ( aDestData.Dimension >= 0 ); // dropping onto a field
+
+ // look through the source range
+ std::unordered_set< OUString > aMembersSet; // for lookup
+ std::vector< OUString > aMembersVector; // members in original order, for inserting
+ aMembersVector.reserve( std::max( static_cast<SCSIZE>( rSource.aEnd.Col() - rSource.aStart.Col() + 1 ),
+ static_cast<SCSIZE>( rSource.aEnd.Row() - rSource.aStart.Row() + 1 ) ) );
+ for (SCROW nRow = rSource.aStart.Row(); bValid && nRow <= rSource.aEnd.Row(); ++nRow )
+ for (SCCOL nCol = rSource.aStart.Col(); bValid && nCol <= rSource.aEnd.Col(); ++nCol )
+ {
+ sheet::DataPilotTableHeaderData aSourceData;
+ pDPObj->GetHeaderPositionData( ScAddress( nCol, nRow, rSource.aStart.Tab() ), aSourceData );
+ if ( aSourceData.Dimension == aDestData.Dimension && !aSourceData.MemberName.isEmpty() )
+ {
+ if ( aMembersSet.insert( aSourceData.MemberName ).second )
+ {
+ aMembersVector.push_back( aSourceData.MemberName );
+ }
+ // duplicates are ignored
+ }
+ else
+ bValid = false; // empty (subtotal) or different field
+ }
+
+ if ( bValid )
+ {
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName( aDestData.Dimension, bIsDataLayout );
+ if ( !bIsDataLayout )
+ {
+ ScDPSaveData aData( *pDPObj->GetSaveData() );
+ ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName );
+
+ // get all member names in source order
+ uno::Sequence<OUString> aMemberNames;
+ pDPObj->GetMemberNames( aDestData.Dimension, aMemberNames );
+
+ bool bInserted = false;
+
+ for (const OUString& aMemberStr : std::as_const(aMemberNames))
+ {
+ if ( !bInserted && aMemberStr == aDestData.MemberName )
+ {
+ // insert dragged items before this item
+ for ( const auto& rMember : aMembersVector )
+ lcl_MoveToEnd( *pDim, rMember );
+ bInserted = true;
+ }
+
+ if ( aMembersSet.find( aMemberStr ) == aMembersSet.end() ) // skip dragged items
+ lcl_MoveToEnd( *pDim, aMemberStr );
+ }
+ // insert dragged item at end if dest wasn't found (for example, empty)
+ if ( !bInserted )
+ for ( const auto& rMember : aMembersVector )
+ lcl_MoveToEnd( *pDim, rMember );
+
+ // Items that were in SaveData, but not in the source, end up at the start of the list.
+
+ // set flag for manual sorting
+ sheet::DataPilotFieldSortInfo aSortInfo;
+ aSortInfo.Mode = sheet::DataPilotFieldSortMode::MANUAL;
+ pDim->SetSortInfo( &aSortInfo );
+
+ // apply changes
+ ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
+ std::unique_ptr<ScDPObject> pNewObj(new ScDPObject( *pDPObj ));
+ pNewObj->SetSaveData( aData );
+ aFunc.DataPilotUpdate( pDPObj, pNewObj.get(), true, false ); //! bApi for drag&drop?
+ pNewObj.reset();
+
+ Unmark(); // entry was moved - no use in leaving the old cell selected
+
+ bRet = true;
+ }
+ }
+ }
+
+ return bRet;
+}
+
+bool ScDBFunc::HasSelectionForDrillDown( css::sheet::DataPilotFieldOrientation& rOrientation )
+{
+ bool bRet = false;
+
+ ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ if ( pDPObj )
+ {
+ ScDPUniqueStringSet aEntries;
+ tools::Long nSelectDimension = -1;
+ GetSelectedMemberList( aEntries, nSelectDimension );
+
+ if (!aEntries.empty())
+ {
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
+ if ( !bIsDataLayout )
+ {
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ ScDPSaveDimension* pDim = pSaveData->GetExistingDimensionByName( aDimName );
+ if ( pDim )
+ {
+ css::sheet::DataPilotFieldOrientation nDimOrient = pDim->GetOrientation();
+ ScDPSaveDimension* pInner = pSaveData->GetInnermostDimension( nDimOrient );
+ if ( pDim == pInner )
+ {
+ rOrientation = nDimOrient;
+ bRet = true;
+ }
+ }
+ }
+ }
+ }
+
+ return bRet;
+}
+
+void ScDBFunc::SetDataPilotDetails(bool bShow, const OUString* pNewDimensionName)
+{
+ ScDPObject* pDPObj = GetViewData().GetDocument().GetDPAtCursor( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ if ( !pDPObj )
+ return;
+
+ ScDPUniqueStringSet aEntries;
+ tools::Long nSelectDimension = -1;
+ GetSelectedMemberList( aEntries, nSelectDimension );
+
+ if (aEntries.empty())
+ return;
+
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName( nSelectDimension, bIsDataLayout );
+ if ( bIsDataLayout )
+ return;
+
+ ScDPSaveData aData( *pDPObj->GetSaveData() );
+ ScDPSaveDimension* pDim = aData.GetDimensionByName( aDimName );
+
+ if ( bShow && pNewDimensionName )
+ {
+ // add the new dimension with the same orientation, at the end
+
+ ScDPSaveDimension* pNewDim = aData.GetDimensionByName( *pNewDimensionName );
+ ScDPSaveDimension* pDuplicated = nullptr;
+ if ( pNewDim->GetOrientation() == sheet::DataPilotFieldOrientation_DATA )
+ {
+ // Need to duplicate the dimension, create column/row in addition to data:
+ // The duplicated dimension inherits the existing settings, pNewDim is modified below.
+ pDuplicated = aData.DuplicateDimension( *pNewDimensionName );
+ }
+
+ css::sheet::DataPilotFieldOrientation nOrientation = pDim->GetOrientation();
+ pNewDim->SetOrientation( nOrientation );
+
+ tools::Long nPosition = LONG_MAX;
+ aData.SetPosition( pNewDim, nPosition );
+
+ ScDPSaveDimension* pDataLayout = aData.GetDataLayoutDimension();
+ if ( pDataLayout->GetOrientation() == nOrientation &&
+ aData.GetDataDimensionCount() <= 1 )
+ {
+ // If there is only one data dimension, the data layout dimension
+ // must still be the last one in its orientation.
+ aData.SetPosition( pDataLayout, nPosition );
+ }
+
+ if ( pDuplicated )
+ {
+ // The duplicated (data) dimension needs to be behind the original dimension
+ aData.SetPosition( pDuplicated, nPosition );
+ }
+
+ // Hide details for all visible members (selected are changed below).
+ //! Use all members from source level instead (including non-visible)?
+
+ ScDPUniqueStringSet aVisibleEntries;
+ pDPObj->GetMemberResultNames( aVisibleEntries, nSelectDimension );
+
+ for (const OUString& aVisName : aVisibleEntries)
+ {
+ ScDPSaveMember* pMember = pDim->GetMemberByName( aVisName );
+ pMember->SetShowDetails( false );
+ }
+ }
+
+ for (const auto& rEntry : aEntries)
+ {
+ ScDPSaveMember* pMember = pDim->GetMemberByName(rEntry);
+ pMember->SetShowDetails( bShow );
+ }
+
+ // apply changes
+ ScDBDocFunc aFunc( *GetViewData().GetDocShell() );
+ std::unique_ptr<ScDPObject> pNewObj(new ScDPObject( *pDPObj ));
+ pNewObj->SetSaveData( aData );
+ aFunc.DataPilotUpdate( pDPObj, pNewObj.get(), true, false );
+ pNewObj.reset();
+
+ // unmark cell selection
+ Unmark();
+}
+
+void ScDBFunc::ShowDataPilotSourceData( ScDPObject& rDPObj, const Sequence<sheet::DataPilotFieldFilter>& rFilters )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ if (rDoc.GetDocumentShell()->IsReadOnly())
+ {
+ ErrorMessage(STR_READONLYERR);
+ return;
+ }
+
+ Reference<sheet::XDimensionsSupplier> xDimSupplier = rDPObj.GetSource();
+ Reference<container::XNameAccess> xDims = xDimSupplier->getDimensions();
+ Reference<sheet::XDrillDownDataSupplier> xDDSupplier(xDimSupplier, UNO_QUERY);
+ if (!xDDSupplier.is())
+ return;
+
+ Sequence< Sequence<Any> > aTabData = xDDSupplier->getDrillDownData(rFilters);
+ sal_Int32 nRowSize = aTabData.getLength();
+ if (nRowSize <= 1)
+ // There is no data to show. Bail out.
+ return;
+
+ SCCOL nColSize = aTabData[0].getLength();
+
+ SCTAB nNewTab = GetViewData().GetTabNo();
+
+ ScDocumentUniquePtr pInsDoc(new ScDocument(SCDOCMODE_CLIP));
+ pInsDoc->ResetClip( &rDoc, nNewTab );
+ for (SCROW nRow = 0; nRow < nRowSize; ++nRow)
+ {
+ for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
+ {
+ const Any& rAny = aTabData[nRow][nCol];
+ OUString aStr;
+ double fVal;
+ if (rAny >>= aStr)
+ {
+ pInsDoc->SetString(ScAddress(nCol,nRow,nNewTab), aStr);
+ }
+ else if (rAny >>= fVal)
+ pInsDoc->SetValue(nCol, nRow, nNewTab, fVal);
+ }
+ }
+
+ // set number format (important for dates)
+ for (SCCOL nCol = 0; nCol < nColSize; ++nCol)
+ {
+ OUString aStr;
+ if (!(aTabData[0][nCol] >>= aStr))
+ continue;
+
+ Reference<XPropertySet> xPropSet(xDims->getByName(aStr), UNO_QUERY);
+ if (!xPropSet.is())
+ continue;
+
+ Any any = xPropSet->getPropertyValue( SC_UNO_DP_NUMBERFO );
+ sal_Int32 nNumFmt = 0;
+ if (!(any >>= nNumFmt))
+ continue;
+
+ ScPatternAttr aPattern( pInsDoc->GetPool() );
+ aPattern.GetItemSet().Put( SfxUInt32Item(ATTR_VALUE_FORMAT, static_cast<sal_uInt32>(nNumFmt)) );
+ pInsDoc->ApplyPatternAreaTab(nCol, 1, nCol, nRowSize-1, nNewTab, aPattern);
+ }
+
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ pInsDoc->GetCellArea( nNewTab, nEndCol, nEndRow );
+ pInsDoc->SetClipArea( ScRange( 0, 0, nNewTab, nEndCol, nEndRow, nNewTab ) );
+
+ SfxUndoManager* pMgr = GetViewData().GetDocShell()->GetUndoManager();
+ OUString aUndo = ScResId( STR_UNDO_DOOUTLINE );
+ pMgr->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
+
+ OUString aNewTabName;
+ rDoc.CreateValidTabName(aNewTabName);
+ if ( InsertTable(aNewTabName, nNewTab) )
+ PasteFromClip( InsertDeleteFlags::ALL, pInsDoc.get() );
+
+ pMgr->LeaveListAction();
+}
+
+// repeat data base operations (sorting, filtering, subtotals)
+
+void ScDBFunc::RepeatDB( bool bRecord )
+{
+ SCCOL nCurX = GetViewData().GetCurX();
+ SCROW nCurY = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDBData* pDBData = GetDBData();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScQueryParam aQueryParam;
+ pDBData->GetQueryParam( aQueryParam );
+ bool bQuery = aQueryParam.GetEntry(0).bDoQuery;
+
+ ScSortParam aSortParam;
+ pDBData->GetSortParam( aSortParam );
+ bool bSort = aSortParam.maKeyState[0].bDoSort;
+
+ ScSubTotalParam aSubTotalParam;
+ pDBData->GetSubTotalParam( aSubTotalParam );
+ bool bSubTotal = aSubTotalParam.bGroupActive[0] && !aSubTotalParam.bRemoveOnly;
+
+ if ( bQuery || bSort || bSubTotal )
+ {
+ bool bQuerySize = false;
+ ScRange aOldQuery;
+ ScRange aNewQuery;
+ if (bQuery && !aQueryParam.bInplace)
+ {
+ ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
+ aQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
+ if (pDest && pDest->IsDoSize())
+ {
+ pDest->GetArea( aOldQuery );
+ bQuerySize = true;
+ }
+ }
+
+ SCTAB nDummy;
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ pDBData->GetArea( nDummy, nStartCol, nStartRow, nEndCol, nEndRow );
+
+ //! undo only needed data ?
+
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScOutlineTable> pUndoTab;
+ std::unique_ptr<ScRangeName> pUndoRange;
+ std::unique_ptr<ScDBCollection> pUndoDB;
+
+ if (bRecord)
+ {
+ SCTAB nTabCount = rDoc.GetTableCount();
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nTab );
+ if (pTable)
+ {
+ pUndoTab.reset(new ScOutlineTable( *pTable ));
+
+ SCCOLROW nOutStartCol; // row/column status
+ SCCOLROW nOutStartRow;
+ SCCOLROW nOutEndCol;
+ SCCOLROW nOutEndRow;
+ pTable->GetColArray().GetRange( nOutStartCol, nOutEndCol );
+ pTable->GetRowArray().GetRange( nOutStartRow, nOutEndRow );
+
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ rDoc.CopyToDocument( static_cast<SCCOL>(nOutStartCol), 0, nTab, static_cast<SCCOL>(nOutEndCol), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
+ rDoc.CopyToDocument( 0, nOutStartRow, nTab, rDoc.MaxCol(), nOutEndRow, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
+ }
+ else
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
+
+ // Record data range - including filter results
+ rDoc.CopyToDocument( 0,nStartRow,nTab, rDoc.MaxCol(),nEndRow,nTab, InsertDeleteFlags::ALL, false, *pUndoDoc );
+
+ // all formulas for reference
+ rDoc.CopyToDocument( 0,0,0, rDoc.MaxCol(),rDoc.MaxRow(),nTabCount-1, InsertDeleteFlags::FORMULA, false, *pUndoDoc );
+
+ // data base and other ranges
+ ScRangeName* pDocRange = rDoc.GetRangeName();
+ if (!pDocRange->empty())
+ pUndoRange.reset(new ScRangeName( *pDocRange ));
+ ScDBCollection* pDocDB = rDoc.GetDBCollection();
+ if (!pDocDB->empty())
+ pUndoDB.reset(new ScDBCollection( *pDocDB ));
+ }
+
+ if (bSort && bSubTotal)
+ {
+ // sort without subtotals
+
+ aSubTotalParam.bRemoveOnly = true; // is reset below
+ DoSubTotals( aSubTotalParam, false );
+ }
+
+ if (bSort)
+ {
+ pDBData->GetSortParam( aSortParam ); // range may have changed
+ Sort( aSortParam, false, false);
+ }
+ if (bQuery)
+ {
+ pDBData->GetQueryParam( aQueryParam ); // range may have changed
+ ScRange aAdvSource;
+ if (pDBData->GetAdvancedQuerySource(aAdvSource))
+ {
+ rDoc.CreateQueryParam(aAdvSource, aQueryParam);
+ Query( aQueryParam, &aAdvSource, false );
+ }
+ else
+ Query( aQueryParam, nullptr, false );
+
+ // if not inplace the sheet may have changed
+ if ( !aQueryParam.bInplace && aQueryParam.nDestTab != nTab )
+ SetTabNo( nTab );
+ }
+ if (bSubTotal)
+ {
+ pDBData->GetSubTotalParam( aSubTotalParam ); // range may have changed
+ aSubTotalParam.bRemoveOnly = false;
+ DoSubTotals( aSubTotalParam, false );
+ }
+
+ if (bRecord)
+ {
+ SCTAB nDummyTab;
+ SCCOL nDummyCol;
+ SCROW nDummyRow, nNewEndRow;
+ pDBData->GetArea( nDummyTab, nDummyCol,nDummyRow, nDummyCol,nNewEndRow );
+
+ const ScRange* pOld = nullptr;
+ const ScRange* pNew = nullptr;
+ if (bQuerySize)
+ {
+ ScDBData* pDest = rDoc.GetDBAtCursor( aQueryParam.nDestCol, aQueryParam.nDestRow,
+ aQueryParam.nDestTab, ScDBDataPortion::TOP_LEFT );
+ if (pDest)
+ {
+ pDest->GetArea( aNewQuery );
+ pOld = &aOldQuery;
+ pNew = &aNewQuery;
+ }
+ }
+
+ GetViewData().GetDocShell()->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRepeatDB>( GetViewData().GetDocShell(), nTab,
+ nStartCol, nStartRow, nEndCol, nEndRow,
+ nNewEndRow,
+ nCurX, nCurY,
+ std::move(pUndoDoc), std::move(pUndoTab),
+ std::move(pUndoRange), std::move(pUndoDB),
+ pOld, pNew ) );
+ }
+
+ GetViewData().GetDocShell()->PostPaint(
+ ScRange(0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab),
+ PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top | PaintPartFlags::Size);
+ }
+ else // "no not execute any operations"
+ ErrorMessage(STR_MSSG_REPEATDB_0);
+}
+
+void ScDBFunc::OnLOKShowHideColRow(bool bColumns, SCCOLROW nStart)
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ SCTAB nCurrentTabIndex = GetViewData().GetTabNo();
+ SfxViewShell* pThisViewShell = GetViewData().GetViewShell();
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pTabViewShell && pTabViewShell->GetDocId() == pThisViewShell->GetDocId())
+ {
+ if (bColumns)
+ {
+ if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKWidthHelper(nCurrentTabIndex))
+ pPosHelper->invalidateByIndex(nStart);
+ }
+ else
+ {
+ if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKHeightHelper(nCurrentTabIndex))
+ pPosHelper->invalidateByIndex(nStart);
+ }
+
+ if (pTabViewShell->getPart() == nCurrentTabIndex)
+ {
+ pTabViewShell->ShowCursor();
+ pTabViewShell->MarkDataChanged();
+ }
+ }
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/dbfunc4.cxx b/sc/source/ui/view/dbfunc4.cxx
new file mode 100644
index 000000000..f13035b29
--- /dev/null
+++ b/sc/source/ui/view/dbfunc4.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 <svx/svditer.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+#include <osl/diagnose.h>
+
+#include <dbfunc.hxx>
+#include <drwlayer.hxx>
+#include <document.hxx>
+
+using namespace com::sun::star;
+
+sal_uInt16 ScDBFunc::DoUpdateCharts(const ScAddress& rPos, ScDocument& rDoc, bool bAllCharts)
+{
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ if (!pModel)
+ return 0;
+
+ sal_uInt16 nFound = 0;
+
+ sal_uInt16 nPageCount = pModel->GetPageCount();
+ for (sal_uInt16 nPageNo = 0; nPageNo < nPageCount; nPageNo++)
+ {
+ SdrPage* pPage = pModel->GetPage(nPageNo);
+ OSL_ENSURE(pPage, "Page ?");
+
+ SdrObjListIter aIter(pPage, SdrIterMode::DeepNoGroups);
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if (pObject->GetObjIdentifier() == SdrObjKind::OLE2 && ScDocument::IsChart(pObject))
+ {
+ OUString aName = static_cast<SdrOle2Obj*>(pObject)->GetPersistName();
+ bool bHit = true;
+ if (!bAllCharts)
+ {
+ ScRangeList aRanges;
+ bool bColHeaders = false;
+ bool bRowHeaders = false;
+ rDoc.GetOldChartParameters(aName, aRanges, bColHeaders, bRowHeaders);
+ bHit = aRanges.Contains(rPos);
+ }
+ if (bHit)
+ {
+ rDoc.UpdateChart(aName);
+ ++nFound;
+ }
+ }
+ pObject = aIter.Next();
+ }
+ }
+ return nFound;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/drawutil.cxx b/sc/source/ui/view/drawutil.cxx
new file mode 100644
index 000000000..9658fa7ff
--- /dev/null
+++ b/sc/source/ui/view/drawutil.cxx
@@ -0,0 +1,89 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/unit_conversion.hxx>
+#include <vcl/outdev.hxx>
+
+#include <drawutil.hxx>
+#include <document.hxx>
+#include <viewdata.hxx>
+
+void ScDrawUtil::CalcScale( const ScDocument& rDoc, SCTAB nTab,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ const OutputDevice* pDev,
+ const Fraction& rZoomX, const Fraction& rZoomY,
+ double nPPTX, double nPPTY,
+ Fraction& rScaleX, Fraction& rScaleY )
+{
+ tools::Long nPixelX = 0;
+ tools::Long nTwipsX = 0;
+ tools::Long nPixelY = 0;
+ tools::Long nTwipsY = 0;
+ for (SCCOL i=nStartCol; i<nEndCol; i++)
+ {
+ sal_uInt16 nWidth = rDoc.GetColWidth(i,nTab);
+ nTwipsX += static_cast<tools::Long>(nWidth);
+ nPixelX += ScViewData::ToPixel( nWidth, nPPTX );
+ }
+
+ for (SCROW nRow = nStartRow; nRow <= nEndRow-1; ++nRow)
+ {
+ SCROW nLastRow = nRow;
+ if (rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow))
+ {
+ nRow = nLastRow;
+ continue;
+ }
+
+ sal_uInt16 nHeight = rDoc.GetRowHeight(nRow, nTab);
+ nTwipsY += static_cast<tools::Long>(nHeight);
+ nPixelY += ScViewData::ToPixel(nHeight, nPPTY);
+ }
+
+ MapMode aHMMMode( MapUnit::Map100thMM, Point(), rZoomX, rZoomY );
+ Point aPixelLog = pDev->PixelToLogic( Point( nPixelX,nPixelY ), aHMMMode );
+
+ // Fraction(double) ctor can be used here (and avoid overflows of PixelLog * Zoom)
+ // because ReduceInaccurate is called later anyway.
+
+ if ( aPixelLog.X() && nTwipsX )
+ rScaleX = Fraction( static_cast<double>(aPixelLog.X()) *
+ static_cast<double>(rZoomX.GetNumerator()) /
+ o3tl::convert<double>(nTwipsX, o3tl::Length::twip, o3tl::Length::mm100) /
+ static_cast<double>(rZoomX.GetDenominator()) );
+ else
+ rScaleX = Fraction( 1, 1 );
+
+ if ( aPixelLog.Y() && nTwipsY )
+ rScaleY = Fraction( static_cast<double>(aPixelLog.Y()) *
+ static_cast<double>(rZoomY.GetNumerator()) /
+ o3tl::convert<double>(nTwipsY, o3tl::Length::twip, o3tl::Length::mm100) /
+ static_cast<double>(rZoomY.GetDenominator()) );
+ else
+ rScaleY = Fraction( 1, 1 );
+
+ // 25 bits of accuracy are needed to always hit the right part of
+ // cells in the last rows (was 17 before 1M rows).
+ rScaleX.ReduceInaccurate( 25 );
+ rScaleY.ReduceInaccurate( 25 );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/drawvie3.cxx b/sc/source/ui/view/drawvie3.cxx
new file mode 100644
index 000000000..ce4d132b8
--- /dev/null
+++ b/sc/source/ui/view/drawvie3.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 <sal/config.h>
+
+#include <cstdlib>
+
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <comphelper/lok.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+
+#include <strings.hrc>
+#include <scresid.hxx>
+#include <drawview.hxx>
+#include <drwlayer.hxx>
+#include "imapwrap.hxx"
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <userdat.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+
+ScDrawView::ScDrawView(
+ OutputDevice* pOut,
+ ScViewData* pData )
+: FmFormView(*pData->GetDocument().GetDrawLayer(), pOut),
+ pViewData( pData ),
+ pDev( pOut ),
+ rDoc( pData->GetDocument() ),
+ nTab( pData->GetTabNo() ),
+ pDropMarkObj( nullptr ),
+ bInConstruct( true )
+{
+ SetNegativeX(comphelper::LibreOfficeKit::isActive() && rDoc.IsLayoutRTL(nTab));
+ // #i73602# Use default from the configuration
+ SetBufferedOverlayAllowed(SvtOptionsDrawinglayer::IsOverlayBuffer_Calc());
+
+ // #i74769#, #i75172# Use default from the configuration
+ SetBufferedOutputAllowed(SvtOptionsDrawinglayer::IsPaintBuffer_Calc());
+
+ Construct();
+}
+
+// set anchor
+
+void ScDrawView::SetPageAnchored()
+{
+ if( !AreObjectsMarked() )
+ return;
+
+ const SdrMarkList* pMark = &GetMarkedObjectList();
+ const size_t nCount = pMark->GetMarkCount();
+
+ BegUndo(ScResId(SCSTR_UNDO_PAGE_ANCHOR));
+ for( size_t i=0; i<nCount; ++i )
+ {
+ SdrObject* pObj = pMark->GetMark(i)->GetMarkedSdrObj();
+ AddUndo (std::make_unique<ScUndoAnchorData>( pObj, &rDoc, nTab ));
+ ScDrawLayer::SetPageAnchored( *pObj );
+ }
+ EndUndo();
+
+ if ( pViewData )
+ pViewData->GetDocShell()->SetDrawModified();
+
+ // Remove the anchor object.
+ maHdlList.RemoveAllByKind(SdrHdlKind::Anchor);
+ maHdlList.RemoveAllByKind(SdrHdlKind::Anchor_TR);
+}
+
+void ScDrawView::SetCellAnchored(bool bResizeWithCell)
+{
+ if( !AreObjectsMarked() )
+ return;
+
+ const SdrMarkList* pMark = &GetMarkedObjectList();
+ const size_t nCount = pMark->GetMarkCount();
+
+ BegUndo(ScResId(SCSTR_UNDO_CELL_ANCHOR));
+ for( size_t i=0; i<nCount; ++i )
+ {
+ SdrObject* pObj = pMark->GetMark(i)->GetMarkedSdrObj();
+ AddUndo (std::make_unique<ScUndoAnchorData>( pObj, &rDoc, nTab ));
+ ScDrawLayer::SetCellAnchoredFromPosition(*pObj, rDoc, nTab, bResizeWithCell);
+ }
+ EndUndo();
+
+ if ( pViewData )
+ {
+ pViewData->GetDocShell()->SetDrawModified();
+
+ // Set the anchor object.
+ AddCustomHdl();
+ }
+}
+
+ScAnchorType ScDrawView::GetAnchorType() const
+{
+ bool bPage = false;
+ bool bCell = false;
+ bool bCellResize = false;
+ if( AreObjectsMarked() )
+ {
+ const SdrMarkList* pMark = &GetMarkedObjectList();
+ const size_t nCount = pMark->GetMarkCount();
+ for( size_t i=0; i<nCount; ++i )
+ {
+ const SdrObject* pObj = pMark->GetMark(i)->GetMarkedSdrObj();
+ const ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType( *pObj );
+ if( aAnchorType == SCA_CELL )
+ bCell =true;
+ else if (aAnchorType == SCA_CELL_RESIZE)
+ bCellResize = true;
+ else
+ bPage = true;
+ }
+ }
+ if( bPage && !bCell && !bCellResize )
+ return SCA_PAGE;
+ if( !bPage && bCell && !bCellResize )
+ return SCA_CELL;
+ if( !bPage && !bCell && bCellResize )
+ return SCA_CELL_RESIZE;
+ return SCA_DONTKNOW;
+}
+
+namespace {
+
+bool lcl_AreRectanglesApproxEqual(const tools::Rectangle& rRectA, const tools::Rectangle& rRectB)
+{
+ // Twips <-> Hmm conversions introduce +-1 differences although the rectangles should actually
+ // be equal. Therefore test with == is not appropriate in some cases.
+ if (std::abs(rRectA.Left() - rRectB.Left()) > 1)
+ return false;
+ if (std::abs(rRectA.Top() - rRectB.Top()) > 1)
+ return false;
+ if (std::abs(rRectA.Right() - rRectB.Right()) > 1)
+ return false;
+ if (std::abs(rRectA.Bottom() - rRectB.Bottom()) > 1)
+ return false;
+ return true;
+}
+
+/**
+ * Updated the anchors of any non-note object that is cell anchored which
+ * has been moved since the last anchors for its position was calculated.
+ */
+void adjustAnchoredPosition(const SdrHint& rHint, const ScDocument& rDoc, SCTAB nTab)
+{
+ if (rHint.GetKind() != SdrHintKind::ObjectChange && rHint.GetKind() != SdrHintKind::ObjectInserted)
+ return;
+
+ SdrObject* pObj = const_cast<SdrObject*>(rHint.GetObject());
+ if (!pObj)
+ return;
+
+ ScDrawObjData *pAnchor = ScDrawLayer::GetObjData(pObj);
+ if (!pAnchor)
+ return;
+
+ if (pAnchor->meType == ScDrawObjData::CellNote)
+ return;
+
+ // SetCellAnchoredFromPosition has to be called only if shape geometry has been changed, and not
+ // if only shape visibility has been changed. It is not enough to test shape rect, because e.g. a
+ // 180deg rotation changes only the logic rect (tdf#139583).
+ ScDrawObjData& rNoRotatedAnchor = *ScDrawLayer::GetNonRotatedObjData(pObj, true /*bCreate*/);
+ if (lcl_AreRectanglesApproxEqual(pAnchor->getShapeRect(), pObj->GetSnapRect())
+ && lcl_AreRectanglesApproxEqual(rNoRotatedAnchor.getShapeRect(), pObj->GetLogicRect()))
+ return;
+
+ if (pAnchor->maStart.Tab() != nTab)
+ // The object is not anchored on the current sheet. Skip it.
+ // TODO: In the future, we may want to adjust objects that are
+ // anchored on all selected sheets.
+ return;
+
+ ScDrawLayer::SetCellAnchoredFromPosition(*pObj, rDoc, pAnchor->maStart.Tab(), pAnchor->mbResizeWithCell);
+}
+
+}
+
+void ScDrawView::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>( &rHint );
+ adjustAnchoredPosition(*pSdrHint, rDoc, nTab);
+ FmFormView::Notify( rBC,rHint );
+ }
+ else if (auto pDeletedHint = dynamic_cast<const ScTabDeletedHint*>(&rHint)) // Sheet has been deleted
+ {
+ SCTAB nDelTab = pDeletedHint->GetTab();
+ if (ValidTab(nDelTab))
+ {
+ // used to be: HidePagePgNum(nDelTab) - hide only if the deleted sheet is shown here
+ if ( nDelTab == nTab )
+ HideSdrPage();
+ }
+ }
+ else if (auto pChangedHint = dynamic_cast<const ScTabSizeChangedHint*>(&rHint)) // Size has been changed
+ {
+ if ( nTab == pChangedHint->GetTab() )
+ UpdateWorkArea();
+ }
+ else
+ FmFormView::Notify( rBC,rHint );
+}
+
+void ScDrawView::UpdateIMap( SdrObject* pObj )
+{
+ if ( !(pViewData &&
+ pViewData->GetViewShell()->GetViewFrame()->HasChildWindow( ScIMapChildWindowId() ) &&
+ pObj && ( dynamic_cast<const SdrGrafObj*>( pObj) != nullptr || dynamic_cast<const SdrOle2Obj*>( pObj) != nullptr )) )
+ return;
+
+ Graphic aGraphic;
+ TargetList aTargetList;
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo( pObj );
+ const ImageMap* pImageMap = nullptr;
+ if ( pIMapInfo )
+ pImageMap = &pIMapInfo->GetImageMap();
+
+ // handle target list
+ SfxViewFrame::GetTargetList( aTargetList );
+
+ // handle graphics from object
+ if ( auto pGrafObj = dynamic_cast<SdrGrafObj*>( pObj) )
+ aGraphic = pGrafObj->GetGraphic();
+ else
+ {
+ const Graphic* pGraphic = static_cast<const SdrOle2Obj*>(pObj)->GetGraphic();
+ if ( pGraphic )
+ aGraphic = *pGraphic;
+ }
+
+ ScIMapDlgSet( aGraphic, pImageMap, &aTargetList, pObj ); // from imapwrap
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/drawvie4.cxx b/sc/source/ui/view/drawvie4.cxx
new file mode 100644
index 000000000..9efc96a34
--- /dev/null
+++ b/sc/source/ui/view/drawvie4.cxx
@@ -0,0 +1,579 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svditer.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdundo.hxx>
+#include <sfx2/docfile.hxx>
+#include <tools/urlobj.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+#include <drawview.hxx>
+#include <global.hxx>
+#include <drwlayer.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <drwtrans.hxx>
+#include <transobj.hxx>
+#include <drawutil.hxx>
+#include <scmod.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <gridwin.hxx>
+#include <userdat.hxx>
+
+#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/chart2/XChartTypeContainer.hpp>
+#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
+#include <com/sun/star/chart2/XDataSeriesContainer.hpp>
+#include <com/sun/star/chart2/XChartDocument.hpp>
+
+using namespace com::sun::star;
+
+Point aDragStartDiff;
+
+void ScDrawView::BeginDrag( vcl::Window* pWindow, const Point& rStartPos )
+{
+ if ( !AreObjectsMarked() )
+ return;
+
+ BrkAction();
+
+ tools::Rectangle aMarkedRect = GetAllMarkedRect();
+
+ aDragStartDiff = rStartPos - aMarkedRect.TopLeft();
+
+ bool bAnyOle, bOneOle;
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ CheckOle( rMarkList, bAnyOle, bOneOle );
+
+ ScDocShellRef aDragShellRef;
+ if (bAnyOle)
+ {
+ aDragShellRef = new ScDocShell; // DocShell needs a Ref immediately
+ aDragShellRef->DoInitNew();
+ }
+ ScDrawLayer::SetGlobalDrawPersist( aDragShellRef.get() );
+ std::unique_ptr<SdrModel> pModel(CreateMarkedObjModel());
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+
+ // Charts now always copy their data in addition to the source reference, so
+ // there's no need to call SchDLL::Update for the charts in the clipboard doc.
+ // Update with the data (including NumberFormatter) from the live document would
+ // also store the NumberFormatter in the clipboard chart (#88749#)
+
+ ScDocShell* pDocSh = pViewData->GetDocShell();
+
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScDrawTransferObj ctor
+
+ rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pModel), pDocSh, aObjDesc );
+
+ pTransferObj->SetDrawPersist( aDragShellRef.get() ); // keep persist for ole objects alive
+ pTransferObj->SetDragSource( this ); // copies selection
+
+ SC_MOD()->SetDragObject( nullptr, pTransferObj.get() ); // for internal D&D
+ pTransferObj->StartDrag( pWindow, DND_ACTION_COPYMOVE | DND_ACTION_LINK );
+}
+
+namespace {
+
+void getRangeFromDataSource( uno::Reference< chart2::data::XDataSource > const & xDataSource, std::vector<OUString>& rRangeRep)
+{
+ const uno::Sequence<uno::Reference<chart2::data::XLabeledDataSequence> > xSeqs = xDataSource->getDataSequences();
+ for (const uno::Reference<chart2::data::XLabeledDataSequence>& xLS : xSeqs)
+ {
+ uno::Reference<chart2::data::XDataSequence> xSeq = xLS->getValues();
+ if (xSeq.is())
+ {
+ OUString aRep = xSeq->getSourceRangeRepresentation();
+ rRangeRep.push_back(aRep);
+ }
+ xSeq = xLS->getLabel();
+ if (xSeq.is())
+ {
+ OUString aRep = xSeq->getSourceRangeRepresentation();
+ rRangeRep.push_back(aRep);
+ }
+ }
+}
+
+void getRangeFromErrorBar(const uno::Reference< chart2::XChartDocument >& rChartDoc, std::vector<OUString>& rRangeRep)
+{
+ uno::Reference <chart2::XDiagram > xDiagram = rChartDoc->getFirstDiagram();
+ if(!xDiagram.is())
+ return;
+
+ uno::Reference< chart2::XCoordinateSystemContainer > xCooSysContainer( xDiagram, uno::UNO_QUERY);
+ if(!xCooSysContainer.is())
+ return;
+
+ const uno::Sequence< uno::Reference< chart2::XCoordinateSystem > > xCooSysSequence( xCooSysContainer->getCoordinateSystems());
+ for(const auto& rCooSys : xCooSysSequence)
+ {
+ uno::Reference< chart2::XChartTypeContainer > xChartTypeContainer( rCooSys, uno::UNO_QUERY);
+ if(!xChartTypeContainer.is())
+ continue;
+
+ const uno::Sequence< uno::Reference< chart2::XChartType > > xChartTypeSequence( xChartTypeContainer->getChartTypes() );
+ for(const auto& rChartType : xChartTypeSequence)
+ {
+ uno::Reference< chart2::XDataSeriesContainer > xDataSequenceContainer( rChartType, uno::UNO_QUERY);
+ if(!xDataSequenceContainer.is())
+ continue;
+
+ const uno::Sequence< uno::Reference< chart2::XDataSeries > > xSeriesSequence( xDataSequenceContainer->getDataSeries() );
+ for(const uno::Reference<chart2::XDataSeries>& xSeries : xSeriesSequence)
+ {
+ uno::Reference< beans::XPropertySet > xPropSet( xSeries, uno::UNO_QUERY);
+ uno::Reference< chart2::data::XDataSource > xErrorBarY;
+ xPropSet->getPropertyValue("ErrorBarY") >>= xErrorBarY;
+ if(xErrorBarY.is())
+ getRangeFromDataSource(xErrorBarY, rRangeRep);
+ uno::Reference< chart2::data::XDataSource > xErrorBarX;
+ xPropSet->getPropertyValue("ErrorBarX") >>= xErrorBarX;
+ if(xErrorBarX.is())
+ getRangeFromDataSource(xErrorBarX, rRangeRep);
+ }
+ }
+ }
+}
+
+void getRangeFromOle2Object(const SdrOle2Obj& rObj, std::vector<OUString>& rRangeRep)
+{
+ if (!rObj.IsChart())
+ // not a chart object.
+ return;
+
+ const uno::Reference<embed::XEmbeddedObject>& xObj = rObj.GetObjRef();
+ if (!xObj.is())
+ return;
+
+ uno::Reference<chart2::XChartDocument> xChartDoc(xObj->getComponent(), uno::UNO_QUERY);
+ if (!xChartDoc.is())
+ return;
+
+ if(xChartDoc->hasInternalDataProvider())
+ return;
+
+ getRangeFromErrorBar(xChartDoc, rRangeRep);
+
+ uno::Reference<chart2::data::XDataSource> xDataSource(xChartDoc, uno::UNO_QUERY);
+ if (!xDataSource.is())
+ return;
+
+ // Get all data sources used in this chart.
+ getRangeFromDataSource(xDataSource, rRangeRep);
+
+ return;
+}
+
+// Get all cell ranges that are referenced by the selected chart objects.
+void getOleSourceRanges(const SdrMarkList& rMarkList, bool& rAnyOle, bool& rOneOle, std::vector<ScRange>* pRanges = nullptr, const ScDocument* pDoc = nullptr )
+{
+ bool bCalcSourceRanges = pRanges && pDoc;
+ std::vector<OUString> aRangeReps;
+ rAnyOle = rOneOle = false;
+ const size_t nCount = rMarkList.GetMarkCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ SdrMark* pMark = rMarkList.GetMark(i);
+ if ( !pMark )
+ continue;
+
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+ if ( !pObj )
+ continue;
+
+ SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
+ if (nSdrObjKind == SdrObjKind::OLE2)
+ {
+ rAnyOle = true;
+ rOneOle = (nCount == 1);
+ if ( bCalcSourceRanges )
+ getRangeFromOle2Object( static_cast<const SdrOle2Obj&>( *pObj ), aRangeReps );
+ else
+ break;
+ }
+ else if ( dynamic_cast<const SdrObjGroup*>( pObj) != nullptr )
+ {
+ SdrObjListIter aIter( *pObj, SdrIterMode::DeepNoGroups );
+ SdrObject* pSubObj = aIter.Next();
+ while (pSubObj)
+ {
+ if ( pSubObj->GetObjIdentifier() == SdrObjKind::OLE2 )
+ {
+ rAnyOle = true;
+ // rOneOle remains false - a group isn't treated like a single OLE object
+ if ( !bCalcSourceRanges )
+ return;
+
+ getRangeFromOle2Object( static_cast<const SdrOle2Obj&>( *pSubObj ), aRangeReps );
+ }
+ pSubObj = aIter.Next();
+ }
+ }
+ }
+
+ if (!bCalcSourceRanges)
+ return;
+
+ // Compile all range representation strings into ranges.
+ for (const auto& rRangeRep : aRangeReps)
+ {
+ ScRangeList aRange;
+ ScAddress aAddr;
+ if (aRange.Parse(rRangeRep, *pDoc, pDoc->GetAddressConvention()) & ScRefFlags::VALID)
+ {
+ pRanges->insert(pRanges->end(), aRange.begin(), aRange.end());
+ }
+ else if (aAddr.Parse(rRangeRep, *pDoc, pDoc->GetAddressConvention()) & ScRefFlags::VALID)
+ pRanges->push_back(aAddr);
+ }
+
+ return;
+}
+
+class InsertTabIndex
+{
+ std::vector<SCTAB>& mrTabs;
+public:
+ explicit InsertTabIndex(std::vector<SCTAB>& rTabs) : mrTabs(rTabs) {}
+ void operator() (const ScRange& rRange)
+ {
+ mrTabs.push_back(rRange.aStart.Tab());
+ }
+};
+
+class CopyRangeData
+{
+ ScDocument& mrSrc;
+ ScDocument& mrDest;
+public:
+ CopyRangeData(ScDocument& rSrc, ScDocument& rDest) : mrSrc(rSrc), mrDest(rDest) {}
+
+ void operator() (const ScRange& rRange)
+ {
+ OUString aTabName;
+ mrSrc.GetName(rRange.aStart.Tab(), aTabName);
+
+ SCTAB nTab;
+ if (!mrDest.GetTable(aTabName, nTab))
+ // Sheet by this name doesn't exist.
+ return;
+
+ mrSrc.CopyStaticToDocument(rRange, nTab, mrDest);
+ }
+};
+
+void copyChartRefDataToClipDoc(ScDocument& rSrcDoc, ScDocument& rClipDoc, const std::vector<ScRange>& rRanges)
+{
+ // Get a list of referenced table indices.
+ std::vector<SCTAB> aTabs;
+ std::for_each(rRanges.begin(), rRanges.end(), InsertTabIndex(aTabs));
+ std::sort(aTabs.begin(), aTabs.end());
+ aTabs.erase(std::unique(aTabs.begin(), aTabs.end()), aTabs.end());
+
+ // Get table names.
+ if (aTabs.empty())
+ return;
+
+ // Create sheets only for referenced source sheets.
+ OUString aName;
+ std::vector<SCTAB>::const_iterator it = aTabs.begin(), itEnd = aTabs.end();
+ if (!rSrcDoc.GetName(*it, aName))
+ return;
+
+ rClipDoc.SetTabNameOnLoad(0, aName); // document initially has one sheet.
+
+ for (++it; it != itEnd; ++it)
+ {
+ if (!rSrcDoc.GetName(*it, aName))
+ return;
+
+ rClipDoc.AppendTabOnLoad(aName);
+ }
+
+ std::for_each(rRanges.begin(), rRanges.end(), CopyRangeData(rSrcDoc, rClipDoc));
+}
+
+}
+
+void ScDrawView::CheckOle( const SdrMarkList& rMarkList, bool& rAnyOle, bool& rOneOle )
+{
+ getOleSourceRanges( rMarkList, rAnyOle, rOneOle );
+}
+
+void ScDrawView::DoCopy()
+{
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ std::vector<ScRange> aRanges;
+ bool bAnyOle = false, bOneOle = false;
+ getOleSourceRanges( rMarkList, bAnyOle, bOneOle, &aRanges, &rDoc );
+
+ // update ScGlobal::xDrawClipDocShellRef
+ ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
+ if (ScGlobal::xDrawClipDocShellRef.is() && !aRanges.empty())
+ {
+ // Copy data referenced by the chart objects to the draw clip
+ // document. We need to do this before CreateMarkedObjModel() below.
+ ScDocShellRef xDocSh = ScGlobal::xDrawClipDocShellRef;
+ ScDocument& rClipDoc = xDocSh->GetDocument();
+ copyChartRefDataToClipDoc(rDoc, rClipDoc, aRanges);
+ }
+ std::unique_ptr<SdrModel> pModel(CreateMarkedObjModel());
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+
+ // Charts now always copy their data in addition to the source reference, so
+ // there's no need to call SchDLL::Update for the charts in the clipboard doc.
+ // Update with the data (including NumberFormatter) from the live document would
+ // also store the NumberFormatter in the clipboard chart (#88749#)
+
+ ScDocShell* pDocSh = pViewData->GetDocShell();
+
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScDrawTransferObj ctor
+
+ rtl::Reference<ScDrawTransferObj> pTransferObj(new ScDrawTransferObj( std::move(pModel), pDocSh, aObjDesc ));
+
+ if ( ScGlobal::xDrawClipDocShellRef.is() )
+ {
+ pTransferObj->SetDrawPersist( ScGlobal::xDrawClipDocShellRef.get() ); // keep persist for ole objects alive
+ }
+
+ pTransferObj->CopyToClipboard( pViewData->GetActiveWin() ); // system clipboard
+}
+
+uno::Reference<datatransfer::XTransferable> ScDrawView::CopyToTransferable()
+{
+ bool bAnyOle, bOneOle;
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ CheckOle( rMarkList, bAnyOle, bOneOle );
+
+ // update ScGlobal::xDrawClipDocShellRef
+ ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
+ std::unique_ptr<SdrModel> pModel( CreateMarkedObjModel() );
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+
+ // Charts now always copy their data in addition to the source reference, so
+ // there's no need to call SchDLL::Update for the charts in the clipboard doc.
+ // Update with the data (including NumberFormatter) from the live document would
+ // also store the NumberFormatter in the clipboard chart (#88749#)
+ // lcl_RefreshChartData( pModel, pViewData->GetDocument() );
+
+ ScDocShell* pDocSh = pViewData->GetDocShell();
+
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScDrawTransferObj ctor
+
+ rtl::Reference<ScDrawTransferObj> pTransferObj = new ScDrawTransferObj( std::move(pModel), pDocSh, aObjDesc );
+
+ if ( ScGlobal::xDrawClipDocShellRef.is() )
+ {
+ pTransferObj->SetDrawPersist( ScGlobal::xDrawClipDocShellRef.get() ); // keep persist for ole objects alive
+ }
+
+ return pTransferObj;
+}
+
+// Calculate correction for 100%, regardless of current settings
+
+void ScDrawView::CalcNormScale( Fraction& rFractX, Fraction& rFractY ) const
+{
+ double nPPTX = ScGlobal::nScreenPPTX;
+ double nPPTY = ScGlobal::nScreenPPTY;
+
+ if (pViewData)
+ nPPTX /= pViewData->GetDocShell()->GetOutputFactor();
+
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ rDoc.GetTableArea( nTab, nEndCol, nEndRow );
+ if (nEndCol<20)
+ nEndCol = 20;
+ if (nEndRow<20)
+ nEndRow = 1000;
+
+ Fraction aZoom(1,1);
+ ScDrawUtil::CalcScale( rDoc, nTab, 0,0, nEndCol,nEndRow, pDev, aZoom,aZoom,
+ nPPTX, nPPTY, rFractX,rFractY );
+}
+
+void ScDrawView::SetMarkedOriginalSize()
+{
+ std::unique_ptr<SdrUndoGroup> pUndoGroup(new SdrUndoGroup(*GetModel()));
+
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ tools::Long nDone = 0;
+ const size_t nCount = rMarkList.GetMarkCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ SdrObjKind nIdent = pObj->GetObjIdentifier();
+ bool bDo = false;
+ Size aOriginalSize;
+ if (nIdent == SdrObjKind::OLE2)
+ {
+ // TODO/LEAN: working with visual area can switch object to running state
+ uno::Reference < embed::XEmbeddedObject > xObj = static_cast<SdrOle2Obj*>(pObj)->GetObjRef();
+ if ( xObj.is() ) // NULL for an invalid object that couldn't be loaded
+ {
+ sal_Int64 nAspect = static_cast<SdrOle2Obj*>(pObj)->GetAspect();
+
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ {
+ MapMode aMapMode( MapUnit::Map100thMM );
+ aOriginalSize = static_cast<SdrOle2Obj*>(pObj)->GetOrigObjSize( &aMapMode );
+ bDo = true;
+ }
+ else
+ {
+ MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( static_cast<SdrOle2Obj*>(pObj)->GetAspect() ) );
+ try
+ {
+ awt::Size aSz = xObj->getVisualAreaSize( static_cast<SdrOle2Obj*>(pObj)->GetAspect() );
+ aOriginalSize = OutputDevice::LogicToLogic(
+ Size( aSz.Width, aSz.Height ),
+ MapMode(aUnit),
+ MapMode(MapUnit::Map100thMM));
+ bDo = true;
+ } catch( embed::NoVisualAreaSizeException& )
+ {
+ OSL_ENSURE( false, "Can't get the original size of the object!" );
+ }
+ }
+ }
+ }
+ else if (nIdent == SdrObjKind::Graphic)
+ {
+ const Graphic& rGraphic = static_cast<SdrGrafObj*>(pObj)->GetGraphic();
+
+ MapMode aSourceMap = rGraphic.GetPrefMapMode();
+ MapMode aDestMap( MapUnit::Map100thMM );
+ if (aSourceMap.GetMapUnit() == MapUnit::MapPixel)
+ {
+ // consider pixel correction, so that the bitmap is correct on the screen
+ Fraction aNormScaleX, aNormScaleY;
+ CalcNormScale( aNormScaleX, aNormScaleY );
+ aDestMap.SetScaleX(aNormScaleX);
+ aDestMap.SetScaleY(aNormScaleY);
+ }
+ if (pViewData)
+ {
+ vcl::Window* pActWin = pViewData->GetActiveWin();
+ if (pActWin)
+ {
+ aOriginalSize = pActWin->LogicToLogic(
+ rGraphic.GetPrefSize(), &aSourceMap, &aDestMap );
+ bDo = true;
+ }
+ }
+ }
+
+ if ( bDo )
+ {
+ tools::Rectangle aDrawRect = pObj->GetLogicRect();
+
+ pUndoGroup->AddAction( std::make_unique<SdrUndoGeoObj>( *pObj ) );
+ pObj->Resize( aDrawRect.TopLeft(), Fraction( aOriginalSize.Width(), aDrawRect.GetWidth() ),
+ Fraction( aOriginalSize.Height(), aDrawRect.GetHeight() ) );
+ ++nDone;
+ }
+ }
+
+ if (nDone && pViewData)
+ {
+ pUndoGroup->SetComment(ScResId( STR_UNDO_ORIGINALSIZE ));
+ ScDocShell* pDocSh = pViewData->GetDocShell();
+ pDocSh->GetUndoManager()->AddUndoAction(std::move(pUndoGroup));
+ pDocSh->SetDrawModified();
+ }
+}
+
+void ScDrawView::FitToCellSize()
+{
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() != 1)
+ {
+ SAL_WARN("sc.ui", "Fit to cell only works with one graphic!");
+ return;
+ }
+
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+
+ ScAnchorType aAnchorType = ScDrawLayer::GetAnchorType(*pObj);
+ if (aAnchorType != SCA_CELL && aAnchorType != SCA_CELL_RESIZE)
+ {
+ SAL_WARN("sc.ui", "Fit to cell only works with cell anchored graphics!");
+ return;
+ }
+
+ ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pObj);
+ if (!pObjData)
+ {
+ SAL_WARN("sc.ui", "Missing ScDrawObjData!");
+ return;
+ }
+
+ std::unique_ptr<SdrUndoGroup> pUndoGroup(new SdrUndoGroup(*GetModel()));
+ tools::Rectangle aGraphicRect = pObj->GetSnapRect();
+ tools::Rectangle aCellRect = ScDrawLayer::GetCellRect( rDoc, pObjData->maStart, true);
+
+ // For graphic objects, we want to keep the aspect ratio
+ if (pObj->shouldKeepAspectRatio())
+ {
+ tools::Long nWidth = aGraphicRect.GetWidth();
+ assert(nWidth && "div-by-zero");
+ double fScaleX = static_cast<double>(aCellRect.GetWidth()) / static_cast<double>(nWidth);
+ tools::Long nHeight = aGraphicRect.GetHeight();
+ assert(nHeight && "div-by-zero");
+ double fScaleY = static_cast<double>(aCellRect.GetHeight()) / static_cast<double>(nHeight);
+ double fScaleMin = std::min(fScaleX, fScaleY);
+
+ aCellRect.setWidth(static_cast<double>(aGraphicRect.GetWidth()) * fScaleMin);
+ aCellRect.setHeight(static_cast<double>(aGraphicRect.GetHeight()) * fScaleMin);
+ }
+
+ pUndoGroup->AddAction( std::make_unique<SdrUndoGeoObj>( *pObj ) );
+ if (pObj->GetObjIdentifier() == SdrObjKind::CustomShape)
+ pObj->AdjustToMaxRect(aCellRect);
+ else
+ pObj->SetSnapRect(aCellRect);
+
+ pUndoGroup->SetComment(ScResId( STR_UNDO_FITCELLSIZE ));
+ ScDocShell* pDocSh = pViewData->GetDocShell();
+ pDocSh->GetUndoManager()->AddUndoAction(std::move(pUndoGroup));
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/drawview.cxx b/sc/source/ui/view/drawview.cxx
new file mode 100644
index 000000000..2774e962a
--- /dev/null
+++ b/sc/source/ui/view/drawview.cxx
@@ -0,0 +1,1264 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/XEmbeddedObject.hpp>
+
+#include <svx/svditer.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdundo.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svx/sdrundomanager.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xbtmpit.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <tools/UnitConversion.hxx>
+#include <osl/diagnose.h>
+
+#include <drawview.hxx>
+#include <global.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <drawutil.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <tabvwsh.hxx>
+#include <client.hxx>
+#include <scmod.hxx>
+#include <drwlayer.hxx>
+#include <docsh.hxx>
+#include <viewuno.hxx>
+#include <userdat.hxx>
+#include <postit.hxx>
+#include <undocell.hxx>
+#include <gridwin.hxx>
+
+#include <sc.hrc>
+
+using namespace com::sun::star;
+
+#define SC_HANDLESIZE_BIG 9
+
+void ScDrawView::Construct()
+{
+ EnableExtendedKeyInputDispatcher(false);
+ EnableExtendedMouseEventDispatcher(false);
+
+ SetFrameDragSingles();
+
+ SetMinMoveDistancePixel( 2 );
+ SetHitTolerancePixel( 2 );
+
+ if (pViewData)
+ {
+ SCTAB nViewTab = pViewData->GetTabNo();
+ ShowSdrPage(GetModel()->GetPage(nViewTab));
+
+ bool bEx = pViewData->GetViewShell()->IsDrawSelMode();
+ bool bProt = rDoc.IsTabProtected( nViewTab ) ||
+ pViewData->GetSfxDocShell()->IsReadOnly();
+
+ SdrLayer* pLayer;
+ SdrLayerAdmin& rAdmin = GetModel()->GetLayerAdmin();
+ pLayer = rAdmin.GetLayerPerID(SC_LAYER_BACK);
+ if (pLayer)
+ SetLayerLocked( pLayer->GetName(), bProt || !bEx );
+ pLayer = rAdmin.GetLayerPerID(SC_LAYER_INTERN);
+ if (pLayer)
+ SetLayerLocked( pLayer->GetName() );
+ pLayer = rAdmin.GetLayerPerID(SC_LAYER_FRONT);
+ if (pLayer)
+ {
+ SetLayerLocked( pLayer->GetName(), bProt );
+ SetActiveLayer( pLayer->GetName() ); // set active layer to FRONT
+ }
+ pLayer = rAdmin.GetLayerPerID(SC_LAYER_CONTROLS);
+ if (pLayer)
+ SetLayerLocked( pLayer->GetName(), bProt );
+ pLayer = rAdmin.GetLayerPerID(SC_LAYER_HIDDEN);
+ if (pLayer)
+ {
+ SetLayerLocked( pLayer->GetName(), bProt );
+ SetLayerVisible( pLayer->GetName(), false);
+ }
+
+ SetSwapAsynchron();
+ }
+ else
+ {
+ ShowSdrPage(GetModel()->GetPage(nTab));
+ }
+
+ UpdateUserViewOptions();
+ RecalcScale();
+ UpdateWorkArea();
+
+ bInConstruct = false;
+}
+
+void ScDrawView::ImplClearCalcDropMarker()
+{
+ pDropMarker.reset();
+}
+
+ScDrawView::~ScDrawView()
+{
+ ImplClearCalcDropMarker();
+}
+
+void ScDrawView::AddCustomHdl()
+{
+ const SdrMarkList &rMrkList = GetMarkedObjectList();
+ const size_t nCount = rMrkList.GetMarkCount();
+ for(size_t nPos=0; nPos<nCount; ++nPos )
+ {
+ SdrObject* pObj = rMrkList.GetMark(nPos)->GetMarkedSdrObj();
+ if (ScDrawObjData *pAnchor = ScDrawLayer::GetObjDataTab(pObj, nTab))
+ {
+ if (ScTabView* pView = pViewData->GetView())
+ pView->CreateAnchorHandles(maHdlList, pAnchor->maStart);
+ }
+ }
+}
+
+void ScDrawView::InvalidateAttribs()
+{
+ if (!pViewData) return;
+ SfxBindings& rBindings = pViewData->GetBindings();
+
+ // true status values:
+ rBindings.InvalidateAll( true );
+}
+
+void ScDrawView::InvalidateDrawTextAttrs()
+{
+ if (!pViewData) return;
+ SfxBindings& rBindings = pViewData->GetBindings();
+
+ // cjk/ctl font items have no configured slots,
+ // need no invalidate
+
+ rBindings.Invalidate( SID_ATTR_CHAR_FONT );
+ rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
+ rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
+ rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
+ rBindings.Invalidate( SID_ULINE_VAL_NONE );
+ rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
+ rBindings.Invalidate( SID_ATTR_CHAR_OVERLINE );
+ rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
+ rBindings.Invalidate( SID_ATTR_CHAR_BACK_COLOR );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_LEFT );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_RIGHT );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_BLOCK );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_CENTER);
+ rBindings.Invalidate( SID_ALIGNLEFT );
+ rBindings.Invalidate( SID_ALIGNCENTERHOR );
+ rBindings.Invalidate( SID_ALIGNRIGHT );
+ rBindings.Invalidate( SID_ALIGNBLOCK );
+ rBindings.Invalidate( SID_ATTR_PARA_LINESPACE_10 );
+ rBindings.Invalidate( SID_ATTR_PARA_LINESPACE_15 );
+ rBindings.Invalidate( SID_ATTR_PARA_LINESPACE_20 );
+ rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
+ rBindings.Invalidate( SID_SET_SUB_SCRIPT );
+ rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
+ rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
+ rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
+ rBindings.Invalidate( SID_TEXTDIRECTION_LEFT_TO_RIGHT );
+ rBindings.Invalidate( SID_TEXTDIRECTION_TOP_TO_BOTTOM );
+ rBindings.Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ rBindings.Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT );
+ rBindings.Invalidate( SID_TABLE_VERT_NONE );
+ rBindings.Invalidate( SID_TABLE_VERT_CENTER );
+ rBindings.Invalidate( SID_TABLE_VERT_BOTTOM );
+ // pseudo slots for Format menu
+ rBindings.Invalidate( SID_ALIGN_ANY_LEFT );
+ rBindings.Invalidate( SID_ALIGN_ANY_HCENTER );
+ rBindings.Invalidate( SID_ALIGN_ANY_RIGHT );
+ rBindings.Invalidate( SID_ALIGN_ANY_JUSTIFIED );
+}
+
+void ScDrawView::SetMarkedToLayer( SdrLayerID nLayerNo )
+{
+ if (!AreObjectsMarked())
+ return;
+
+ // #i11702# use SdrUndoObjectLayerChange for undo
+ // STR_UNDO_SELATTR is "Attributes" - should use a different text later
+ BegUndo( ScResId( STR_UNDO_SELATTR ) );
+
+ const SdrMarkList& rMark = GetMarkedObjectList();
+ const size_t nCount = rMark.GetMarkCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ SdrObject* pObj = rMark.GetMark(i)->GetMarkedSdrObj();
+ if ( dynamic_cast<const SdrUnoObj*>( pObj) == nullptr && (pObj->GetLayer() != SC_LAYER_INTERN) )
+ {
+ AddUndo( std::make_unique<SdrUndoObjectLayerChange>( *pObj, pObj->GetLayer(), nLayerNo) );
+ pObj->SetLayer( nLayerNo );
+ }
+ }
+
+ EndUndo();
+
+ // repaint is done in SetLayer
+
+ pViewData->GetDocShell()->SetDrawModified();
+
+ // check mark list now instead of later in a timer
+ CheckMarked();
+ MarkListHasChanged();
+}
+
+bool ScDrawView::HasMarkedControl() const
+{
+ SdrObjListIter aIter( GetMarkedObjectList() );
+ for( SdrObject* pObj = aIter.Next(); pObj; pObj = aIter.Next() )
+ if( dynamic_cast<const SdrUnoObj*>( pObj) != nullptr )
+ return true;
+ return false;
+}
+
+bool ScDrawView::HasMarkedInternal() const
+{
+ // internal objects should not be inside a group, but who knows...
+ SdrObjListIter aIter( GetMarkedObjectList() );
+ for( SdrObject* pObj = aIter.Next(); pObj; pObj = aIter.Next() )
+ if( pObj->GetLayer() == SC_LAYER_INTERN )
+ return true;
+ return false;
+}
+
+void ScDrawView::UpdateWorkArea()
+{
+ SdrPage* pPage = GetModel()->GetPage(static_cast<sal_uInt16>(nTab));
+ if (pPage)
+ {
+ Size aPageSize( pPage->GetSize() );
+ tools::Rectangle aNewArea( Point(), aPageSize );
+ if ( aPageSize.Width() < 0 )
+ {
+ // RTL: from max.negative (left) to zero (right)
+ aNewArea.SetRight( 0 );
+ aNewArea.SetLeft( aPageSize.Width() + 1 );
+ }
+ SetWorkArea( aNewArea );
+ }
+ else
+ {
+ OSL_FAIL("Page not found");
+ }
+}
+
+void ScDrawView::DoCut()
+{
+ DoCopy();
+ BegUndo( ScResId( STR_UNDO_CUT ) );
+ DeleteMarked(); // In this View - not affected by 505f change
+ EndUndo();
+}
+
+void ScDrawView::GetScale( Fraction& rFractX, Fraction& rFractY ) const
+{
+ rFractX = aScaleX;
+ rFractY = aScaleY;
+}
+
+void ScDrawView::RecalcScale()
+{
+ double nPPTX;
+ double nPPTY;
+ Fraction aZoomX(1,1);
+ Fraction aZoomY(1,1);
+
+ if (pViewData)
+ {
+ nTab = pViewData->GetTabNo();
+ nPPTX = pViewData->GetPPTX();
+ nPPTY = pViewData->GetPPTY();
+ aZoomX = pViewData->GetZoomX();
+ aZoomY = pViewData->GetZoomY();
+ }
+ else
+ {
+ Point aLogic = pDev->LogicToPixel(Point(1000,1000), MapMode(MapUnit::MapTwip));
+ nPPTX = aLogic.X() / 1000.0;
+ nPPTY = aLogic.Y() / 1000.0;
+ //! Zoom, handed over ???
+ }
+
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ rDoc.GetTableArea( nTab, nEndCol, nEndRow );
+ if (nEndCol<20)
+ nEndCol = 20;
+ if (nEndRow<20)
+ nEndRow = 20;
+
+ ScDrawUtil::CalcScale(
+ rDoc, nTab, 0, 0, nEndCol, nEndRow, pDev, aZoomX, aZoomY, nPPTX, nPPTY,
+ aScaleX, aScaleY);
+
+ // clear all evtl existing GridOffset vectors
+ resetGridOffsetsForAllSdrPageViews();
+
+ SdrPageView* pPV = GetSdrPageView();
+ if ( !(pViewData && pPV) )
+ return;
+
+ if ( SdrPage* pPage = pPV->GetPage() )
+ {
+ const size_t nCount = pPage->GetObjCount();
+ for ( size_t i = 0; i < nCount; ++i )
+ {
+ SdrObject* pObj = pPage->GetObj( i );
+ // Align objects to nearest grid position
+ SyncForGrid( pObj );
+ }
+ }
+}
+
+void ScDrawView::DoConnect(SdrOle2Obj* pOleObj)
+{
+ if ( pViewData )
+ pViewData->GetViewShell()->ConnectObject( pOleObj );
+}
+
+void ScDrawView::MarkListHasChanged()
+{
+ FmFormView::MarkListHasChanged();
+
+ ScTabViewShell* pViewSh = pViewData->GetViewShell();
+
+ // #i110829# remove the cell selection only if drawing objects are selected
+ if ( !bInConstruct && GetMarkedObjectList().GetMarkCount() )
+ {
+ pViewSh->Unmark(); // remove cell selection
+
+ // end cell edit mode if drawing objects are selected
+ SC_MOD()->InputEnterHandler();
+ }
+
+ // deactivate IP
+
+ ScModule* pScMod = SC_MOD();
+ bool bUnoRefDialog = pScMod->IsRefDialogOpen() && pScMod->GetCurRefDlgId() == WID_SIMPLE_REF;
+
+ ScClient* pClient = static_cast<ScClient*>( pViewSh->GetIPClient() );
+ if ( pClient && pClient->IsObjectInPlaceActive() && !bUnoRefDialog )
+ {
+ // do not display the handles for ViewShell::Activate from the Reset2Open
+ pClient->DeactivateObject();
+ // replacing image ole graphics is now done in ScClient::UIActivate
+ }
+
+ // Select Ole object?
+
+ SdrOle2Obj* pOle2Obj = nullptr;
+ SdrGrafObj* pGrafObj = nullptr;
+
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ const size_t nMarkCount = rMarkList.GetMarkCount();
+
+ if ( nMarkCount == 0 && !pViewData->GetViewShell()->IsDrawSelMode() && !bInConstruct )
+ {
+ // relock layers that may have been unlocked before
+ LockBackgroundLayer(true);
+ LockInternalLayer();
+ }
+
+ bool bSubShellSet = false;
+ if (nMarkCount == 1)
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if (pObj->GetObjIdentifier() == SdrObjKind::OLE2)
+ {
+ pOle2Obj = static_cast<SdrOle2Obj*>(pObj);
+ if (!ScDocument::IsChart(pObj) )
+ pViewSh->SetOleObjectShell(true);
+ else
+ pViewSh->SetChartShell(true);
+ bSubShellSet = true;
+ }
+ else if (pObj->GetObjIdentifier() == SdrObjKind::Graphic)
+ {
+ pGrafObj = static_cast<SdrGrafObj*>(pObj);
+ pViewSh->SetGraphicShell(true);
+ bSubShellSet = true;
+ }
+ else if (pObj->GetObjIdentifier() == SdrObjKind::Media)
+ {
+ pViewSh->SetMediaShell(true);
+ bSubShellSet = true;
+ }
+ else if (pObj->GetObjIdentifier() != SdrObjKind::Text // prevent switching to the drawing shell
+ || !pViewSh->IsDrawTextShell()) // when creating a text object @#70206#
+ {
+ pViewSh->SetDrawShell(true);
+ }
+ }
+
+ if ( nMarkCount && !bSubShellSet )
+ {
+ bool bOnlyControls = true;
+ bool bOnlyGraf = true;
+ for (size_t i=0; i<nMarkCount; ++i)
+ {
+ SdrObject* pObj = rMarkList.GetMark(i)->GetMarkedSdrObj();
+ if ( auto pObjGroup = dynamic_cast<const SdrObjGroup*>( pObj) )
+ {
+ const SdrObjList *pLst = pObjGroup->GetSubList();
+ const size_t nListCount = pLst->GetObjCount();
+ if ( nListCount == 0 )
+ {
+ // An empty group (may occur during Undo) is no control or graphics object.
+ // Creating the form shell during undo would lead to problems with the undo manager.
+ bOnlyControls = false;
+ bOnlyGraf = false;
+ }
+ for ( size_t j = 0; j < nListCount; ++j )
+ {
+ SdrObject *pSubObj = pLst->GetObj( j );
+
+ if (dynamic_cast<const SdrUnoObj*>( pSubObj) == nullptr)
+ bOnlyControls = false;
+ if (pSubObj->GetObjIdentifier() != SdrObjKind::Graphic)
+ bOnlyGraf = false;
+
+ if ( !bOnlyControls && !bOnlyGraf ) break;
+ }
+ }
+ else
+ {
+ if (dynamic_cast<const SdrUnoObj*>( pObj) == nullptr)
+ bOnlyControls = false;
+ if (pObj->GetObjIdentifier() != SdrObjKind::Graphic)
+ bOnlyGraf = false;
+ }
+
+ if ( !bOnlyControls && !bOnlyGraf ) break;
+ }
+
+ if(bOnlyControls)
+ {
+ pViewSh->SetDrawFormShell(true); // now UNO controls
+ }
+ else if(bOnlyGraf)
+ {
+ pViewSh->SetGraphicShell(true);
+ }
+ else if(nMarkCount>1)
+ {
+ pViewSh->SetDrawShell(true);
+ }
+ }
+
+ // adjust verbs
+
+ SfxViewFrame* pViewFrame = pViewSh->GetViewFrame();
+ bool bOle = pViewSh->GetViewFrame()->GetFrame().IsInPlace();
+ uno::Sequence< embed::VerbDescriptor > aVerbs;
+ if ( pOle2Obj && !bOle )
+ {
+ const uno::Reference < embed::XEmbeddedObject >& xObj = pOle2Obj->GetObjRef();
+ OSL_ENSURE( xObj.is(), "SdrOle2Obj without ObjRef" );
+ if (xObj.is())
+ aVerbs = xObj->getSupportedVerbs();
+ }
+ pViewSh->SetVerbs( aVerbs );
+
+ // image map editor
+
+ if ( pOle2Obj )
+ UpdateIMap( pOle2Obj );
+ else if ( pGrafObj )
+ UpdateIMap( pGrafObj );
+
+ InvalidateAttribs(); // after the image map editor update
+ InvalidateDrawTextAttrs();
+
+ for(sal_uInt32 a(0); a < PaintWindowCount(); a++)
+ {
+ SdrPaintWindow* pPaintWindow = GetPaintWindow(a);
+ OutputDevice& rOutDev = pPaintWindow->GetOutputDevice();
+
+ if(OUTDEV_WINDOW == rOutDev.GetOutDevType())
+ {
+ rOutDev.GetOwnerWindow()->PaintImmediately();
+ }
+ }
+
+ // uno object for view returns drawing objects as selection,
+ // so it must notify its SelectionChangeListeners
+
+ if (pViewFrame)
+ {
+ SfxFrame& rFrame = pViewFrame->GetFrame();
+ uno::Reference<frame::XController> xController = rFrame.GetController();
+ if (xController.is())
+ {
+ ScTabViewObj* pImp = comphelper::getFromUnoTunnel<ScTabViewObj>( xController );
+ if (pImp)
+ pImp->SelectionChanged();
+ }
+ }
+
+ // update selection transfer object
+
+ pViewSh->CheckSelectionTransfer();
+
+}
+
+bool ScDrawView::SdrBeginTextEdit(
+ SdrObject* pObj,
+ SdrPageView* pPV,
+ vcl::Window* pWinL,
+ bool bIsNewObj,
+ SdrOutliner* pGivenOutliner,
+ OutlinerView* pGivenOutlinerView,
+ bool bDontDeleteOutliner,
+ bool bOnlyOneView,
+ bool bGrabFocus )
+{
+ const bool bRet = FmFormView::SdrBeginTextEdit(
+ pObj, pPV, pWinL, bIsNewObj,
+ pGivenOutliner, pGivenOutlinerView, bDontDeleteOutliner,
+ bOnlyOneView, bGrabFocus );
+
+ ScTabViewShell* pViewSh = pViewData->GetViewShell();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (OutlinerView* pView = GetTextEditOutlinerView())
+ {
+ tools::Rectangle aRectangle = pView->GetOutputArea();
+ if (pWinL && pWinL->GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ {
+ aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip);
+ }
+ OString sRectangle = aRectangle.toString();
+ SfxLokHelper::notifyOtherViews(pViewSh, LOK_CALLBACK_VIEW_LOCK, "rectangle", sRectangle);
+ }
+ }
+
+ if ( pViewSh->GetViewFrame() )
+ {
+ SfxFrame& rFrame = pViewSh->GetViewFrame()->GetFrame();
+ uno::Reference< frame::XController > xController = rFrame.GetController();
+ if (xController.is())
+ {
+ ScTabViewObj* pImp = comphelper::getFromUnoTunnel<ScTabViewObj>( xController );
+ if (pImp)
+ pImp->SelectionChanged();
+ }
+ }
+
+ return bRet;
+}
+
+SdrEndTextEditKind ScDrawView::SdrEndTextEdit( bool bDontDeleteReally )
+{
+ const SdrEndTextEditKind eRet = FmFormView::SdrEndTextEdit( bDontDeleteReally );
+
+ ScTabViewShell* pViewSh = pViewData->GetViewShell();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ SfxLokHelper::notifyOtherViews(pViewSh, LOK_CALLBACK_VIEW_LOCK, "rectangle", "EMPTY");
+
+ if ( pViewSh->GetViewFrame() )
+ {
+ SfxFrame& rFrame = pViewSh->GetViewFrame()->GetFrame();
+ uno::Reference< frame::XController > xController = rFrame.GetController();
+ if (xController.is())
+ {
+ ScTabViewObj* pImp = comphelper::getFromUnoTunnel<ScTabViewObj>( xController );
+ if (pImp)
+ pImp->SelectionChanged();
+ }
+ }
+
+ return eRet;
+}
+
+void ScDrawView::ModelHasChanged()
+{
+ SdrObject* pEditObj = GetTextEditObject();
+ if ( pEditObj && !pEditObj->IsInserted() && pViewData )
+ {
+ // SdrObjEditView::ModelHasChanged will end text edit in this case,
+ // so make sure the EditEngine's undo manager is no longer used.
+ pViewData->GetViewShell()->SetDrawTextUndo(nullptr);
+ SetCreateMode(); // don't leave FuText in a funny state
+ }
+
+ FmFormView::ModelHasChanged();
+}
+
+void ScDrawView::UpdateUserViewOptions()
+{
+ if (!pViewData)
+ return;
+
+ const ScViewOptions& rOpt = pViewData->GetOptions();
+ const ScGridOptions& rGrid = rOpt.GetGridOptions();
+
+ SetDragStripes( rOpt.GetOption( VOPT_HELPLINES ) );
+ SetMarkHdlSizePixel( SC_HANDLESIZE_BIG );
+
+ SetGridVisible( rGrid.GetGridVisible() );
+ SetSnapEnabled( rGrid.GetUseGridSnap() );
+ SetGridSnap( rGrid.GetUseGridSnap() );
+
+ Fraction aFractX( rGrid.GetFieldDrawX(), rGrid.GetFieldDivisionX() + 1 );
+ Fraction aFractY( rGrid.GetFieldDrawY(), rGrid.GetFieldDivisionY() + 1 );
+ SetSnapGridWidth( aFractX, aFractY );
+
+ SetGridCoarse( Size( rGrid.GetFieldDrawX(), rGrid.GetFieldDrawY() ) );
+ SetGridFine( Size( rGrid.GetFieldDrawX() / (rGrid.GetFieldDivisionX() + 1),
+ rGrid.GetFieldDrawY() / (rGrid.GetFieldDivisionY() + 1) ) );
+}
+
+SdrObject* ScDrawView::GetObjectByName(std::u16string_view rName)
+{
+ SfxObjectShell* pShell = rDoc.GetDocumentShell();
+ if (pShell)
+ {
+ SdrModel* pDrawLayer = GetModel();
+ sal_uInt16 nTabCount = rDoc.GetTableCount();
+ for (sal_uInt16 i=0; i<nTabCount; i++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(i);
+ DBG_ASSERT(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( ScDrawLayer::GetVisibleName( pObject ) == rName )
+ {
+ return pObject;
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+ return nullptr;
+}
+
+//realize multi-selection of objects
+
+void ScDrawView::SelectCurrentViewObject( std::u16string_view rName )
+{
+ sal_uInt16 nObjectTab = 0;
+ SdrObject* pFound = nullptr;
+ SfxObjectShell* pShell = rDoc.GetDocumentShell();
+ if (pShell)
+ {
+ SdrModel* pDrawLayer = GetModel();
+ sal_uInt16 nTabCount = rDoc.GetTableCount();
+ for (sal_uInt16 i=0; i<nTabCount && !pFound; i++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(i);
+ DBG_ASSERT(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !pFound)
+ {
+ if ( ScDrawLayer::GetVisibleName( pObject ) == rName )
+ {
+ pFound = pObject;
+ nObjectTab = i;
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+ if ( !pFound )
+ return;
+
+ ScTabView* pView = pViewData->GetView();
+ if ( nObjectTab != nTab ) // switch sheet
+ pView->SetTabNo( nObjectTab );
+ DBG_ASSERT( nTab == nObjectTab, "Switching sheets did not work" );
+ pView->ScrollToObject( pFound );
+ if ( pFound->GetLayer() == SC_LAYER_BACK &&
+ !pViewData->GetViewShell()->IsDrawSelMode() &&
+ !rDoc.IsTabProtected( nTab ) &&
+ !pViewData->GetSfxDocShell()->IsReadOnly() )
+ {
+ SdrLayer* pLayer = GetModel()->GetLayerAdmin().GetLayerPerID(SC_LAYER_BACK);
+ if (pLayer)
+ SetLayerLocked( pLayer->GetName(), false );
+ }
+ SdrPageView* pPV = GetSdrPageView();
+ const bool bUnMark = IsObjMarked(pFound);
+ MarkObj( pFound, pPV, bUnMark);
+}
+
+bool ScDrawView::SelectObject( std::u16string_view rName )
+{
+ UnmarkAll();
+
+ SCTAB nObjectTab = 0;
+ SdrObject* pFound = nullptr;
+
+ SfxObjectShell* pShell = rDoc.GetDocumentShell();
+ if (pShell)
+ {
+ SdrModel* pDrawLayer = GetModel();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB i=0; i<nTabCount && !pFound; i++)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(static_cast<sal_uInt16>(i));
+ OSL_ENSURE(pPage,"Page ?");
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject && !pFound)
+ {
+ if ( ScDrawLayer::GetVisibleName( pObject ) == rName )
+ {
+ pFound = pObject;
+ nObjectTab = i;
+ }
+ pObject = aIter.Next();
+ }
+ }
+ }
+ }
+
+ if ( pFound )
+ {
+ ScTabView* pView = pViewData->GetView();
+ if ( nObjectTab != nTab ) // switch sheet
+ pView->SetTabNo( nObjectTab );
+
+ OSL_ENSURE( nTab == nObjectTab, "Switching sheets did not work" );
+
+ pView->ScrollToObject( pFound );
+
+ /* To select an object on the background layer, the layer has to
+ be unlocked even if exclusive drawing selection mode is not active
+ (this is reversed in MarkListHasChanged when nothing is selected) */
+ if ( pFound->GetLayer() == SC_LAYER_BACK &&
+ !pViewData->GetViewShell()->IsDrawSelMode() &&
+ !rDoc.IsTabProtected( nTab ) &&
+ !pViewData->GetSfxDocShell()->IsReadOnly() )
+ {
+ LockBackgroundLayer(false);
+ }
+
+ SdrPageView* pPV = GetSdrPageView();
+ MarkObj( pFound, pPV );
+ }
+
+ return ( pFound != nullptr );
+}
+
+//If object is marked , return true , else return false .
+bool ScDrawView::GetObjectIsMarked( const SdrObject* pObject )
+{
+ bool bisMarked = false;
+ if (pObject )
+ {
+ bisMarked = IsObjMarked(pObject);
+ }
+ return bisMarked;
+}
+
+bool ScDrawView::InsertObjectSafe(SdrObject* pObj, SdrPageView& rPV)
+{
+ SdrInsertFlags nOptions=SdrInsertFlags::NONE;
+ // Do not change marks when the ole object is active
+ // (for Drop from ole object would otherwise be deactivated in the middle of ExecuteDrag!)
+
+ if (pViewData)
+ {
+ SfxInPlaceClient* pClient = pViewData->GetViewShell()->GetIPClient();
+ if ( pClient && pClient->IsObjectInPlaceActive() )
+ nOptions |= SdrInsertFlags::DONTMARK;
+ }
+
+ return InsertObjectAtView(pObj, rPV, nOptions);
+}
+
+SdrObject* ScDrawView::GetMarkedNoteCaption( ScDrawObjData** ppCaptData )
+{
+ const SdrMarkList& rMarkList = GetMarkedObjectList();
+ if( pViewData && (rMarkList.GetMarkCount() == 1) )
+ {
+ SdrObject* pObj = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
+ if( ScDrawObjData* pCaptData = ScDrawLayer::GetNoteCaptionData( pObj, pViewData->GetTabNo() ) )
+ {
+ if( ppCaptData ) *ppCaptData = pCaptData;
+ return pObj;
+ }
+ }
+ return nullptr;
+}
+
+void ScDrawView::LockCalcLayer( SdrLayerID nLayer, bool bLock )
+{
+ SdrLayer* pLockLayer = GetModel()->GetLayerAdmin().GetLayerPerID( nLayer );
+ if( pLockLayer && (IsLayerLocked( pLockLayer->GetName() ) != bLock) )
+ SetLayerLocked( pLockLayer->GetName(), bLock );
+}
+
+void ScDrawView::MakeVisible( const tools::Rectangle& rRect, vcl::Window& rWin )
+{
+ //! Evaluate rWin properly
+ //! change zoom if necessary
+
+ if ( pViewData && pViewData->GetActiveWin() == &rWin )
+ pViewData->GetView()->MakeVisible( rRect );
+}
+
+SfxViewShell* ScDrawView::GetSfxViewShell() const
+{
+ return pViewData->GetViewShell();
+}
+
+void ScDrawView::DeleteMarked()
+{
+ // try to delete a note caption object with its cell note in the Calc document
+ ScDrawObjData* pCaptData = nullptr;
+ if( SdrObject* pCaptObj = GetMarkedNoteCaption( &pCaptData ) )
+ {
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ ScDocShell* pDocShell = pViewData ? pViewData->GetDocShell() : nullptr;
+ SfxUndoManager* pUndoMgr = pDocShell ? pDocShell->GetUndoManager() : nullptr;
+ bool bUndo = pDrawLayer && pDocShell && pUndoMgr && rDoc.IsUndoEnabled();
+
+ // remove the cell note from document, we are its owner now
+ std::unique_ptr<ScPostIt> pNote = rDoc.ReleaseNote( pCaptData->maStart );
+ OSL_ENSURE( pNote, "ScDrawView::DeleteMarked - cell note missing in document" );
+ if( pNote )
+ {
+ // rescue note data for undo (with pointer to caption object)
+ ScNoteData aNoteData = pNote->GetNoteData();
+ OSL_ENSURE( aNoteData.mxCaption.get() == pCaptObj, "ScDrawView::DeleteMarked - caption object does not match" );
+ // collect the drawing undo action created while deleting the note
+ if( bUndo )
+ pDrawLayer->BeginCalcUndo(false);
+ // delete the note (already removed from document above)
+ pNote.reset();
+ // add the undo action for the note
+ if( bUndo )
+ pUndoMgr->AddUndoAction( std::make_unique<ScUndoReplaceNote>( *pDocShell, pCaptData->maStart, aNoteData, false, pDrawLayer->GetCalcUndo() ) );
+ // repaint the cell to get rid of the note marker
+ if( pDocShell )
+ pDocShell->PostPaintCell( pCaptData->maStart );
+ // done, return now to skip call of FmFormView::DeleteMarked()
+ return;
+ }
+ }
+
+ FmFormView::DeleteMarked();
+}
+
+SdrEndTextEditKind ScDrawView::ScEndTextEdit()
+{
+ bool bIsTextEdit = IsTextEdit();
+ SdrEndTextEditKind eKind = SdrEndTextEdit();
+
+ if (bIsTextEdit)
+ pViewData->GetViewShell()->SetDrawTextUndo(nullptr); // the "normal" undo manager
+
+ return eKind;
+}
+
+void ScDrawView::MarkDropObj( SdrObject* pObj )
+{
+ if ( pDropMarkObj != pObj )
+ {
+ pDropMarkObj = pObj;
+ ImplClearCalcDropMarker();
+
+ if(pDropMarkObj)
+ {
+ pDropMarker.reset( new SdrDropMarkerOverlay(*this, *pDropMarkObj) );
+ }
+ }
+}
+
+// In order to counteract the effects of rounding due to the nature of how the
+// grid positions are calculated and drawn we calculate the offset needed at the
+// current zoom to be applied to an SrdObject when it is drawn in order to make
+// sure that it's position relative to the nearest cell anchor doesn't change.
+// Of course not all shape(s)/control(s) are cell anchored, if the
+// object doesn't have a cell anchor we synthesise a temporary anchor.
+void ScDrawView::SyncForGrid( SdrObject* pObj )
+{
+ // process members of a group shape separately
+ if ( auto pObjGroup = dynamic_cast<const SdrObjGroup*>( pObj) )
+ {
+ SdrObjList *pLst = pObjGroup->GetSubList();
+ for ( size_t i = 0, nCount = pLst->GetObjCount(); i < nCount; ++i )
+ SyncForGrid( pLst->GetObj( i ) );
+ }
+
+ ScSplitPos eWhich = pViewData->GetActivePart();
+ ScGridWindow* pGridWin = pViewData->GetActiveWin();
+ ScDrawObjData* pData = ScDrawLayer::GetObjData( pObj );
+ if ( !pGridWin )
+ return;
+
+ ScAddress aOldStt;
+ if( pData && pData->maStart.IsValid())
+ {
+ aOldStt = pData->maStart;
+ }
+ else
+ {
+ // Page anchored object so...
+ // synthesise an anchor ( but don't attach it to
+ // the object as we want to maintain page anchoring )
+ ScDrawObjData aAnchor;
+ const tools::Rectangle aObjRect(pObj->GetLogicRect());
+ ScDrawLayer::GetCellAnchorFromPosition(
+ aObjRect,
+ aAnchor,
+ rDoc,
+ GetTab());
+ aOldStt = aAnchor.maStart;
+ }
+ MapMode aDrawMode = pGridWin->GetDrawMapMode();
+ // find pos anchor position
+ Point aOldPos( rDoc.GetColOffset( aOldStt.Col(), aOldStt.Tab() ), rDoc.GetRowOffset( aOldStt.Row(), aOldStt.Tab() ) );
+ aOldPos.setX(convertTwipToMm100(aOldPos.X()));
+ aOldPos.setY(convertTwipToMm100(aOldPos.Y()));
+ // find position of same point on the screen ( e.g. grid )
+ Point aCurPos = pViewData->GetScrPos( aOldStt.Col(), aOldStt.Row(), eWhich, true );
+ Point aCurPosHmm = pGridWin->PixelToLogic(aCurPos, aDrawMode );
+ Point aGridOff = aCurPosHmm - aOldPos;
+ // fdo#63878 Fix the X position for RTL Sheet
+ if( rDoc.IsNegativePage( GetTab() ) && !comphelper::LibreOfficeKit::isActive() )
+ aGridOff.setX( aCurPosHmm.getX() + aOldPos.getX() );
+}
+
+void ScDrawView::resetGridOffsetsForAllSdrPageViews()
+{
+ SdrPageView* pPageView(GetSdrPageView());
+
+ if(nullptr == pPageView)
+ return;
+
+ for(sal_uInt32 a(0); a < pPageView->PageWindowCount(); a++)
+ {
+ SdrPageWindow* pPageWindow(pPageView->GetPageWindow(a));
+ assert(pPageWindow && "SdrView::SetMasterPagePaintCaching: Corrupt SdrPageWindow list (!)");
+
+ if(nullptr != pPageWindow)
+ {
+ sdr::contact::ObjectContact& rObjectContact(pPageWindow->GetObjectContact());
+
+ if(rObjectContact.supportsGridOffsets())
+ {
+ rObjectContact.resetAllGridOffsets();
+ }
+ }
+ }
+}
+
+bool ScDrawView::calculateGridOffsetForSdrObject(
+ SdrObject& rSdrObject,
+ basegfx::B2DVector& rTarget) const
+{
+ if (comphelper::LibreOfficeKit::isActive() &&
+ !comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ return false;
+
+ ScGridWindow* pGridWin(pViewData->GetActiveWin());
+
+ if(nullptr == pGridWin)
+ {
+ return false;
+ }
+
+ ScDrawObjData* pData(ScDrawLayer::GetObjData(&rSdrObject));
+ ScAddress aOldStt;
+
+ if(nullptr != pData && pData->maStart.IsValid())
+ {
+ aOldStt = pData->maStart;
+ }
+ else
+ {
+ // Page anchored object so...
+ // synthesise an anchor ( but don't attach it to
+ // the object as we want to maintain page anchoring )
+ ScDrawObjData aAnchor;
+ const tools::Rectangle aObjRect(rSdrObject.GetLogicRect());
+ ScDrawLayer::GetCellAnchorFromPosition(
+ aObjRect,
+ aAnchor,
+ rDoc,
+ GetTab());
+ aOldStt = aAnchor.maStart;
+ }
+
+ MapMode aDrawMode = pGridWin->GetDrawMapMode();
+
+ // find pos anchor position
+ Point aOldPos(rDoc.GetColOffset(aOldStt.Col(), aOldStt.Tab()), rDoc.GetRowOffset(aOldStt.Row(), aOldStt.Tab()));
+ aOldPos.setX(convertTwipToMm100(aOldPos.X()));
+ aOldPos.setY(convertTwipToMm100(aOldPos.Y()));
+
+ // find position of same point on the screen ( e.g. grid )
+ ScSplitPos eWhich(pViewData->GetActivePart());
+ Point aCurPos(pViewData->GetScrPos(aOldStt.Col(), aOldStt.Row(), eWhich, true));
+ Point aCurPosHmm(pGridWin->PixelToLogic(aCurPos, aDrawMode));
+ Point aGridOff(aCurPosHmm - aOldPos);
+
+ bool bLOKActive = comphelper::LibreOfficeKit::isActive();
+ bool bNegativePage = rDoc.IsNegativePage(GetTab());
+
+ // fdo#63878 Fix the X position for RTL Sheet
+ if(bNegativePage && !bLOKActive)
+ {
+ aGridOff.setX(aCurPosHmm.getX() + aOldPos.getX());
+ }
+
+ rTarget.setX(bNegativePage && bLOKActive ? -aGridOff.X() : aGridOff.X());
+ rTarget.setY(aGridOff.Y());
+ return true;
+}
+
+bool ScDrawView::calculateGridOffsetForB2DRange(
+ const basegfx::B2DRange& rB2DRange,
+ basegfx::B2DVector& rTarget) const
+{
+ ScGridWindow* pGridWin(pViewData->GetActiveWin());
+
+ if(nullptr == pGridWin || rB2DRange.isEmpty())
+ {
+ return false;
+ }
+
+ // No SdrObject, so synthesise an anchor ( but don't attach it to
+ // the object as we want to maintain page anchoring )
+ ScDrawObjData aAnchor;
+ const tools::Rectangle aRectangle(
+ basegfx::fround(rB2DRange.getMinX()), basegfx::fround(rB2DRange.getMinY()),
+ basegfx::fround(rB2DRange.getMaxX()), basegfx::fround(rB2DRange.getMaxY()));
+ ScDrawLayer::GetCellAnchorFromPosition(
+ aRectangle,
+ aAnchor,
+ rDoc,
+ GetTab());
+ ScAddress aOldStt(aAnchor.maStart);
+
+ MapMode aDrawMode = pGridWin->GetDrawMapMode();
+
+ // find pos anchor position
+ Point aOldPos(rDoc.GetColOffset(aOldStt.Col(), aOldStt.Tab()), rDoc.GetRowOffset(aOldStt.Row(), aOldStt.Tab()));
+ aOldPos.setX(convertTwipToMm100(aOldPos.X()));
+ aOldPos.setY(convertTwipToMm100(aOldPos.Y()));
+
+ // find position of same point on the screen ( e.g. grid )
+ ScSplitPos eWhich(pViewData->GetActivePart());
+ Point aCurPos(pViewData->GetScrPos(aOldStt.Col(), aOldStt.Row(), eWhich, true));
+ Point aCurPosHmm(pGridWin->PixelToLogic(aCurPos, aDrawMode));
+ Point aGridOff(aCurPosHmm - aOldPos);
+
+ bool bLOKActive = comphelper::LibreOfficeKit::isActive();
+ bool bNegativePage = rDoc.IsNegativePage(GetTab());
+
+ // fdo#63878 Fix the X position for RTL Sheet
+ if(bNegativePage && !bLOKActive)
+ {
+ aGridOff.setX(aCurPosHmm.getX() + aOldPos.getX());
+ }
+
+ rTarget.setX(bLOKActive && bNegativePage ? -aGridOff.X() : aGridOff.X());
+ rTarget.setY(aGridOff.Y());
+ return true;
+}
+
+// Create a new view-local UndoManager manager for Calc
+std::unique_ptr<SdrUndoManager> ScDrawView::createLocalTextUndoManager()
+{
+ std::unique_ptr<SdrUndoManager> pUndoManager(new SdrUndoManager);
+ ScDocShell* pDocShell = pViewData ? pViewData->GetDocShell() : nullptr;
+ pUndoManager->SetDocShell(pDocShell);
+ return pUndoManager;
+}
+
+// #i123922# helper to apply a Graphic to an existing SdrObject
+SdrObject* ScDrawView::ApplyGraphicToObject(
+ SdrObject& rHitObject,
+ const Graphic& rGraphic,
+ const OUString& rBeginUndoText,
+ const OUString& rFile)
+{
+ if(dynamic_cast< SdrGrafObj* >(&rHitObject))
+ {
+ SdrGrafObj* pNewGrafObj(static_cast<SdrGrafObj*>(rHitObject.CloneSdrObject(rHitObject.getSdrModelFromSdrObject())));
+
+ pNewGrafObj->SetGraphic(rGraphic);
+ BegUndo(rBeginUndoText);
+ ReplaceObjectAtView(&rHitObject, *GetSdrPageView(), pNewGrafObj);
+
+ // set in all cases - the Clone() will have copied an existing link (!)
+ pNewGrafObj->SetGraphicLink( rFile );
+
+ EndUndo();
+ return pNewGrafObj;
+ }
+ else if(rHitObject.IsClosedObj() && !dynamic_cast< SdrOle2Obj* >(&rHitObject))
+ {
+ AddUndo(std::make_unique<SdrUndoAttrObj>(rHitObject));
+
+ SfxItemSetFixed<XATTR_FILLSTYLE, XATTR_FILLBITMAP> aSet(GetModel()->GetItemPool());
+
+ aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP));
+ aSet.Put(XFillBitmapItem(OUString(), rGraphic));
+ rHitObject.SetMergedItemSetAndBroadcast(aSet);
+ return &rHitObject;
+ }
+
+ return nullptr;
+}
+
+// Own derivation of ObjectContact to allow on-demand calculation of
+// GridOffset for non-linear ViewToDevice transformation (calc)
+namespace sdr::contact
+{
+ namespace {
+
+ class ObjectContactOfScDrawView final : public ObjectContactOfPageView
+ {
+ private:
+ // The ScDrawView to work on
+ const ScDrawView& mrScDrawView;
+
+ public:
+ explicit ObjectContactOfScDrawView(
+ const ScDrawView& rScDrawView,
+ SdrPageWindow& rPageWindow,
+ const char* pDebugName);
+
+ virtual bool supportsGridOffsets() const override;
+ virtual void calculateGridOffsetForViewOjectContact(
+ basegfx::B2DVector& rTarget,
+ const ViewObjectContact& rClient) const override;
+ virtual void calculateGridOffsetForB2DRange(
+ basegfx::B2DVector& rTarget,
+ const basegfx::B2DRange& rB2DRange) const override;
+ };
+
+ }
+
+ ObjectContactOfScDrawView::ObjectContactOfScDrawView(
+ const ScDrawView& rScDrawView,
+ SdrPageWindow& rPageWindow,
+ const char* pDebugName)
+ : ObjectContactOfPageView(rPageWindow, pDebugName),
+ mrScDrawView(rScDrawView)
+ {
+ }
+
+ bool ObjectContactOfScDrawView::supportsGridOffsets() const
+ {
+ // Except when scPrintTwipsMsgs flag is active,
+ // Calc in LOK mode directly sets pixel-aligned logical coordinates for draw-objects.
+ if (comphelper::LibreOfficeKit::isActive() &&
+ !comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ return false;
+
+ // no GridOffset support for printer
+ if(isOutputToPrinter())
+ {
+ return false;
+ }
+
+ // no GridOffset support for PDF export
+ if(isOutputToPDFFile())
+ {
+ return false;
+ }
+
+ // yes - we support it
+ return true;
+ }
+
+ void ObjectContactOfScDrawView::calculateGridOffsetForViewOjectContact(
+ basegfx::B2DVector& rTarget,
+ const ViewObjectContact& rClient) const
+ {
+ // Here the on-demand calculation happens. Try to access the SdrObject involved
+ SdrObject* pTargetSdrObject(rClient.GetViewContact().TryToGetSdrObject());
+
+ if(nullptr != pTargetSdrObject)
+ {
+ mrScDrawView.calculateGridOffsetForSdrObject(
+ *pTargetSdrObject,
+ rTarget);
+ }
+ }
+
+ void ObjectContactOfScDrawView::calculateGridOffsetForB2DRange(
+ basegfx::B2DVector& rTarget,
+ const basegfx::B2DRange& rB2DRange) const
+ {
+ // Here the on-demand calculation happens. Try to access the SdrObject involved
+ if(!rB2DRange.isEmpty())
+ {
+ mrScDrawView.calculateGridOffsetForB2DRange(
+ rB2DRange,
+ rTarget);
+ }
+ }
+}
+
+// Create own derivation of ObjectContact for calc
+sdr::contact::ObjectContact* ScDrawView::createViewSpecificObjectContact(
+ SdrPageWindow& rPageWindow,
+ const char* pDebugName) const
+{
+ return new sdr::contact::ObjectContactOfScDrawView(
+ *this,
+ rPageWindow,
+ pDebugName);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/editsh.cxx b/sc/source/ui/view/editsh.cxx
new file mode 100644
index 000000000..796000efe
--- /dev/null
+++ b/sc/source/ui/view/editsh.cxx
@@ -0,0 +1,1367 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/string.hxx>
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+#include <i18nutil/unicode.hxx>
+#include <i18nutil/transliteration.hxx>
+
+#include <svx/clipfmtitem.hxx>
+#include <svx/svxdlg.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/escapementitem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/flstitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/urlfieldhelper.hxx>
+#include <svx/hlnkitem.hxx>
+#include <vcl/EnumContext.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/msg.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svtools/cliplistener.hxx>
+#include <svl/whiter.hxx>
+#include <sot/formats.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/unohelp2.hxx>
+#include <svl/stritem.hxx>
+#include <editeng/colritem.hxx>
+
+#include <editsh.hxx>
+#include <global.hxx>
+#include <sc.hrc>
+#include <scmod.hxx>
+#include <inputhdl.hxx>
+#include <viewutil.hxx>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <reffind.hxx>
+#include <tabvwsh.hxx>
+#include <editutil.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <gridwin.hxx>
+
+#define ShellClass_ScEditShell
+#include <scslots.hxx>
+
+#include <scui_def.hxx>
+#include <scabstdlg.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+
+
+SFX_IMPL_INTERFACE(ScEditShell, SfxShell)
+
+void ScEditShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterPopupMenu("celledit");
+}
+
+ScEditShell::ScEditShell(EditView* pView, ScViewData& rData) :
+ pEditView (pView),
+ rViewData (rData),
+ bPastePossible (false),
+ bIsInsertMode (true)
+{
+ SetPool( pEditView->GetEditEngine()->GetEmptyItemSet().GetPool() );
+ SetUndoManager( &pEditView->GetEditEngine()->GetUndoManager() );
+ SetName("EditCell");
+ SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::EditCell));
+}
+
+ScEditShell::~ScEditShell()
+{
+ if ( mxClipEvtLstnr.is() )
+ {
+ mxClipEvtLstnr->RemoveListener( rViewData.GetActiveWin() );
+
+ // The listener may just now be waiting for the SolarMutex and call the link
+ // afterwards, in spite of RemoveListener. So the link has to be reset, too.
+ mxClipEvtLstnr->ClearCallbackLink();
+ }
+}
+
+ScInputHandler* ScEditShell::GetMyInputHdl()
+{
+ return SC_MOD()->GetInputHdl( rViewData.GetViewShell() );
+}
+
+void ScEditShell::SetEditView(EditView* pView)
+{
+ pEditView = pView;
+ pEditView->SetInsertMode( bIsInsertMode );
+ SetPool( pEditView->GetEditEngine()->GetEmptyItemSet().GetPool() );
+ SetUndoManager( &pEditView->GetEditEngine()->GetUndoManager() );
+}
+
+static void lcl_RemoveAttribs( EditView& rEditView )
+{
+ ScEditEngineDefaulter* pEngine = static_cast<ScEditEngineDefaulter*>(rEditView.GetEditEngine());
+
+ bool bOld = pEngine->SetUpdateLayout(false);
+
+ OUString aName = ScResId( STR_UNDO_DELETECONTENTS );
+ ViewShellId nViewShellId(-1);
+ if (ScTabViewShell* pViewSh = ScTabViewShell::GetActiveViewShell())
+ nViewShellId = pViewSh->GetViewShellId();
+ pEngine->GetUndoManager().EnterListAction( aName, aName, 0, nViewShellId );
+
+ rEditView.RemoveAttribs(true);
+ pEngine->RepeatDefaults(); // paragraph attributes from cell formats must be preserved
+
+ pEngine->GetUndoManager().LeaveListAction();
+
+ pEngine->SetUpdateLayout(bOld);
+}
+
+static void lclInsertCharacter( EditView* pTableView, EditView* pTopView, sal_Unicode cChar )
+{
+ OUString aString( cChar );
+ if( pTableView )
+ pTableView->InsertText( aString );
+ if( pTopView )
+ pTopView->InsertText( aString );
+}
+
+void ScEditShell::Execute( SfxRequest& rReq )
+{
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+ SfxBindings& rBindings = rViewData.GetBindings();
+
+ ScInputHandler* pHdl = GetMyInputHdl();
+ OSL_ENSURE(pHdl,"no ScInputHandler");
+
+ EditView* pTopView = pHdl->GetTopView(); // Has thee input cell the focus?
+ EditView* pTableView = pHdl->GetTableView();
+
+ OSL_ENSURE(pTableView,"no EditView :-(");
+ /* #i91683# No EditView if spell-check dialog is active and positioned on
+ * an error and user immediately (without double click or F2) selected a
+ * text portion of that cell with the mouse and wanted to modify it. */
+ /* FIXME: Bailing out only cures the symptom and prevents a crash, no edit
+ * action is possible. A real fix somehow would need to create a valid
+ * EditView from the spell-check view. */
+ if (!pTableView)
+ return;
+
+ EditEngine* pEngine = pTableView->GetEditEngine();
+
+ pHdl->DataChanging();
+ bool bSetSelIsRef = false;
+ bool bSetModified = true;
+
+ switch ( nSlot )
+ {
+ case SID_ATTR_INSERT:
+ case FID_INS_CELL_CONTENTS: // Insert taste, while defined as Acc
+ bIsInsertMode = !pTableView->IsInsertMode();
+ pTableView->SetInsertMode( bIsInsertMode );
+ if (pTopView)
+ pTopView->SetInsertMode( bIsInsertMode );
+ rBindings.Invalidate( SID_ATTR_INSERT );
+ 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( *pEditView, aReplaceText );
+ }
+ break;
+
+ case SID_COPY:
+ pTableView->Copy();
+ bSetModified = false;
+ break;
+
+ case SID_CUT:
+ pTableView->Cut();
+ if (pTopView)
+ pTopView->DeleteSelected();
+ break;
+
+ case SID_PASTE:
+ {
+ EVControlBits nControl = pTableView->GetControlWord();
+ if (pTopView)
+ {
+ pTopView->Paste();
+ pTableView->SetControlWord(nControl | EVControlBits::SINGLELINEPASTE);
+ }
+
+ pTableView->PasteSpecial();
+ pTableView->SetControlWord(nControl);
+ }
+ break;
+
+ case SID_DELETE:
+ pTableView->DeleteSelected();
+ if (pTopView)
+ pTopView->DeleteSelected();
+ break;
+
+ case SID_CELL_FORMAT_RESET: // "Standard"
+ lcl_RemoveAttribs( *pTableView );
+ if ( pTopView )
+ lcl_RemoveAttribs( *pTopView );
+ break;
+
+ case SID_CLIPBOARD_FORMAT_ITEMS:
+ {
+ SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
+ if (auto pIntItem = dynamic_cast<const SfxUInt32Item*>( pItem))
+ nFormat = static_cast<SotClipboardFormatId>(pIntItem->GetValue());
+
+ if ( nFormat != SotClipboardFormatId::NONE )
+ {
+ if (SotClipboardFormatId::STRING == nFormat)
+ pTableView->Paste();
+ else
+ pTableView->PasteSpecial();
+
+ if (pTopView)
+ pTopView->Paste();
+ }
+ }
+ break;
+
+ case SID_PASTE_SPECIAL:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractPasteDialog> pDlg(pFact->CreatePasteDialog(rViewData.GetDialogParent()));
+ SotClipboardFormatId nFormat = SotClipboardFormatId::NONE;
+ pDlg->Insert( SotClipboardFormatId::STRING, OUString() );
+ pDlg->Insert( SotClipboardFormatId::RTF, OUString() );
+ pDlg->Insert( SotClipboardFormatId::RICHTEXT, OUString() );
+ // Do not offer SotClipboardFormatId::STRING_TSVC for
+ // in-cell paste.
+
+ TransferableDataHelper aDataHelper(
+ TransferableDataHelper::CreateFromSystemClipboard( rViewData.GetActiveWin() ) );
+
+ nFormat = pDlg->GetFormat( aDataHelper.GetTransferable() );
+ pDlg.disposeAndClear();
+
+ // while the dialog was open, edit mode may have been stopped
+ if (!SC_MOD()->IsInputMode())
+ return;
+
+ if (nFormat != SotClipboardFormatId::NONE)
+ {
+ if (SotClipboardFormatId::STRING == nFormat)
+ pTableView->Paste();
+ else
+ pTableView->PasteSpecial();
+
+ if (pTopView)
+ pTopView->Paste();
+ }
+
+ if (vcl::Window* pViewWindow = pTopView ? pTopView->GetWindow() : nullptr)
+ pViewWindow->GrabFocus();
+ }
+ break;
+
+ case SID_PASTE_UNFORMATTED:
+ {
+ pTableView->Paste();
+
+ if (pTopView)
+ {
+ pTopView->Paste();
+ if (vcl::Window* pViewWindow = pTopView->GetWindow())
+ pViewWindow->GrabFocus();
+ }
+ }
+ break;
+
+ case SID_SELECTALL:
+ {
+ sal_Int32 nPar = pEngine->GetParagraphCount();
+ if (nPar)
+ {
+ sal_Int32 nLen = pEngine->GetTextLen(nPar-1);
+ pTableView->SetSelection(ESelection(0,0,nPar-1,nLen));
+ if (pTopView)
+ pTopView->SetSelection(ESelection(0,0,nPar-1,nLen));
+ rBindings.Invalidate( SID_ATTR_CHAR_FONT );
+ rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
+ rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
+ rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
+ rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
+ rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
+ rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
+ rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
+ rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
+ rBindings.Invalidate( SID_SET_SUB_SCRIPT );
+ }
+ }
+ return;
+ case SID_UNICODE_NOTATION_TOGGLE:
+ {
+ EditView* pActiveView = pHdl->GetActiveView();
+ if( pActiveView )
+ {
+ OUString sInput = pEngine->GetText();
+ ESelection aSel( pActiveView->GetSelection() );
+ if( aSel.HasRange() )
+ sInput = pActiveView->GetSelected();
+
+ 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);
+ if( nUtf16Pos > aSel.nEndPos )
+ aSel.nEndPos = nUtf16Pos;
+ }
+
+ ToggleUnicodeCodepoint aToggle;
+ while( nUtf16Pos && aToggle.AllowMoreInput( sInput[nUtf16Pos-1]) )
+ --nUtf16Pos;
+ OUString sReplacement = aToggle.ReplacementString();
+ if( !sReplacement.isEmpty() )
+ {
+ aSel.nStartPos = aSel.nEndPos - aToggle.StringToReplace().getLength();
+ pTableView->SetSelection( aSel );
+ pTableView->InsertText(sReplacement, true);
+ if( pTopView )
+ {
+ pTopView->SetSelection( aSel );
+ pTopView->InsertText(sReplacement, true);
+ }
+ }
+ }
+ }
+ break;
+
+ case SID_CHARMAP:
+ {
+ SvtScriptType nScript = pTableView->GetSelectedScriptType();
+ sal_uInt16 nFontWhich = ( nScript == SvtScriptType::ASIAN ) ? EE_CHAR_FONTINFO_CJK :
+ ( ( nScript == SvtScriptType::COMPLEX ) ? EE_CHAR_FONTINFO_CTL :
+ EE_CHAR_FONTINFO );
+ const SvxFontItem& rItem = static_cast<const SvxFontItem&>(
+ pTableView->GetAttribs().Get(nFontWhich));
+
+ OUString aString;
+ std::shared_ptr<SvxFontItem> aNewItem(std::make_shared<SvxFontItem>(EE_CHAR_FONTINFO));
+
+ const SfxItemSet *pArgs = rReq.GetArgs();
+ const SfxPoolItem* pItem = nullptr;
+ if( pArgs )
+ pArgs->GetItemState(SID_CHARMAP, false, &pItem);
+
+ if ( pItem )
+ {
+ aString = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ const SfxStringItem* pFontItem = pArgs->GetItemIfSet( SID_ATTR_SPECIALCHAR, false);
+ if ( pFontItem )
+ {
+ const OUString& aFontName(pFontItem->GetValue());
+ vcl::Font aFont(aFontName, Size(1,1)); // Size just because CTOR
+ // tdf#125054 see comment in drtxob.cxx, same ID
+ aNewItem = std::make_shared<SvxFontItem>(
+ aFont.GetFamilyType(), aFont.GetFamilyName(),
+ aFont.GetStyleName(), aFont.GetPitch(),
+ aFont.GetCharSet(), ATTR_FONT);
+ }
+ else
+ {
+ aNewItem.reset(rItem.Clone());
+ }
+
+ // tdf#125054 force Item to correct intended ID
+ aNewItem->SetWhich(EE_CHAR_FONTINFO);
+ }
+ else
+ {
+ ScViewUtil::ExecuteCharMap(rItem, *rViewData.GetViewShell());
+
+ // while the dialog was open, edit mode may have been stopped
+ if (!SC_MOD()->IsInputMode())
+ return;
+ }
+
+ if ( !aString.isEmpty() )
+ {
+ // if string contains WEAK characters, set all fonts
+ SvtScriptType nSetScript;
+ ScDocument& rDoc = rViewData.GetDocument();
+ if ( rDoc.HasStringWeakCharacters( aString ) )
+ nSetScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
+ else
+ nSetScript = rDoc.GetStringScriptType( aString );
+
+ SfxItemSet aSet( pTableView->GetEmptyItemSet() );
+ SvxScriptSetItem aSetItem( SID_ATTR_CHAR_FONT, GetPool() );
+ aSetItem.PutItemForScriptType( nSetScript, *aNewItem );
+ aSet.Put( aSetItem.GetItemSet(), false );
+
+ // SetAttribs on the View selects a word, when nothing is selected
+ pTableView->GetEditEngine()->QuickSetAttribs( aSet, pTableView->GetSelection() );
+ pTableView->InsertText(aString);
+ if (pTopView)
+ pTopView->InsertText(aString);
+
+ SfxStringItem aStringItem( SID_CHARMAP, aString );
+ SfxStringItem aFontItem( SID_ATTR_SPECIALCHAR, aNewItem->GetFamilyName() );
+ rReq.AppendItem( aFontItem );
+ rReq.AppendItem( aStringItem );
+ rReq.Done();
+
+ }
+
+ if (vcl::Window* pViewWindow = pTopView ? pTopView->GetWindow() : nullptr)
+ pViewWindow->GrabFocus();
+ }
+ break;
+
+ case FID_INSERT_NAME:
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScNamePasteDlg> pDlg(pFact->CreateScNamePasteDlg(rViewData.GetDialogParent(), rViewData.GetDocShell()));
+ short nRet = pDlg->Execute();
+ // pDlg is needed below
+
+ // while the dialog was open, edit mode may have been stopped
+ if (!SC_MOD()->IsInputMode())
+ return;
+
+ if ( nRet == BTN_PASTE_NAME )
+ {
+ std::vector<OUString> aNames = pDlg->GetSelectedNames();
+ if (!aNames.empty())
+ {
+ OUStringBuffer aBuffer;
+ for (const auto& rName : aNames)
+ {
+ aBuffer.append(rName).append(' ');
+ }
+ const OUString s = aBuffer.makeStringAndClear();
+ pTableView->InsertText(s);
+ if (pTopView)
+ pTopView->InsertText(s);
+ }
+ }
+ pDlg.disposeAndClear();
+
+ if (vcl::Window* pViewWindow = pTopView ? pTopView->GetWindow() : nullptr)
+ pViewWindow->GrabFocus();
+ }
+ break;
+
+ case SID_CHAR_DLG_EFFECT:
+ case SID_CHAR_DLG:
+ {
+ SfxItemSet aAttrs( pTableView->GetAttribs() );
+
+ SfxObjectShell* pObjSh = rViewData.GetSfxDocShell();
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateScCharDlg(
+ rViewData.GetDialogParent(), &aAttrs, pObjSh, false));
+ if (nSlot == SID_CHAR_DLG_EFFECT)
+ {
+ pDlg->SetCurPageId("fonteffects");
+ }
+ short nRet = pDlg->Execute();
+ // pDlg is needed below
+
+ // while the dialog was open, edit mode may have been stopped
+ if (!SC_MOD()->IsInputMode())
+ return;
+
+ if ( nRet == RET_OK )
+ {
+ const SfxItemSet* pOut = pDlg->GetOutputItemSet();
+ pTableView->SetAttribs( *pOut );
+ }
+ }
+ break;
+
+ case SID_TOGGLE_REL:
+ {
+ /* TODO: MLFORMULA: this should work also with multi-line formulas. */
+ if (pEngine->GetParagraphCount() == 1)
+ {
+ OUString aText = pEngine->GetText();
+ ESelection aSel = pEditView->GetSelection(); // current View
+
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScRefFinder aFinder(aText, rViewData.GetCurPos(), rDoc, rDoc.GetAddressConvention());
+ aFinder.ToggleRel( aSel.nStartPos, aSel.nEndPos );
+ if (aFinder.GetFound())
+ {
+ const OUString& aNew = aFinder.GetText();
+ ESelection aNewSel( 0,aFinder.GetSelStart(), 0,aFinder.GetSelEnd() );
+ pEngine->SetText( aNew );
+ pTableView->SetSelection( aNewSel );
+ if ( pTopView )
+ {
+ pTopView->GetEditEngine()->SetText( aNew );
+ pTopView->SetSelection( aNewSel );
+ }
+
+ // reference is being selected -> do not overwrite when typing
+ bSetSelIsRef = true;
+ }
+ }
+ }
+ break;
+
+ case SID_HYPERLINK_SETLINK:
+ if( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs->GetItemState( SID_HYPERLINK_SETLINK, true, &pItem ) == SfxItemState::SET )
+ {
+ const SvxHyperlinkItem* pHyper = static_cast<const SvxHyperlinkItem*>(pItem);
+ const OUString& rName = pHyper->GetName();
+ const OUString& rURL = pHyper->GetURL();
+ const OUString& rTarget = pHyper->GetTargetFrame();
+ SvxLinkInsertMode eMode = pHyper->GetInsertMode();
+
+ bool bDone = false;
+ if ( eMode == HLINK_DEFAULT || eMode == HLINK_FIELD )
+ {
+ const SvxURLField* pURLField = GetURLField();
+ if ( pURLField )
+ {
+ // select old field
+
+ ESelection aSel = pTableView->GetSelection();
+ aSel.Adjust();
+ aSel.nEndPara = aSel.nStartPara;
+ aSel.nEndPos = aSel.nStartPos + 1;
+ pTableView->SetSelection( aSel );
+
+ // insert new field
+
+ SvxURLField aURLField( rURL, rName, SvxURLFormat::Repr );
+ aURLField.SetTargetFrame( rTarget );
+ SvxFieldItem aURLItem( aURLField, EE_FEATURE_FIELD );
+ pTableView->InsertField( aURLItem );
+ pTableView->SetSelection( aSel ); // select inserted field
+
+ // now also fields in the Top-View
+
+ if ( pTopView )
+ {
+ aSel = pTopView->GetSelection();
+ aSel.nEndPara = aSel.nStartPara;
+ aSel.nEndPos = aSel.nStartPos + 1;
+ pTopView->SetSelection( aSel );
+ pTopView->InsertField( aURLItem );
+ pTopView->SetSelection( aSel ); // select inserted field
+ }
+
+ bDone = true;
+ }
+ }
+
+ if (!bDone)
+ {
+ rViewData.GetViewShell()->
+ InsertURL( rName, rURL, rTarget, static_cast<sal_uInt16>(eMode) );
+
+ // when "Button", the InsertURL in ViewShell turns the EditShell off
+ // thus the immediate return statement
+ return;
+ }
+ }
+ }
+ break;
+ case SID_OPEN_HYPERLINK:
+ {
+ const SvxURLField* pURLField = GetURLField();
+ if ( pURLField )
+ ScGlobal::OpenURL( pURLField->GetURL(), pURLField->GetTargetFrame(), true );
+ return;
+ }
+ case SID_EDIT_HYPERLINK:
+ {
+ // Ensure the field is selected first
+ pEditView->SelectFieldAtCursor();
+ rViewData.GetViewShell()->GetViewFrame()->GetDispatcher()->Execute(
+ SID_HYPERLINK_DIALOG);
+ }
+ break;
+ case SID_COPY_HYPERLINK_LOCATION:
+ {
+ const SvxFieldData* pField = pEditView->GetFieldAtCursor();
+ if (const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(pField))
+ {
+ uno::Reference<datatransfer::clipboard::XClipboard> xClipboard
+ = pEditView->GetClipboard();
+ vcl::unohelper::TextDataObject::CopyStringTo(pURLField->GetURL(), xClipboard, SfxViewShell::Current());
+ }
+ }
+ break;
+ case SID_REMOVE_HYPERLINK:
+ {
+ URLFieldHelper::RemoveURLField(*pEditView);
+ }
+ break;
+
+ case FN_INSERT_SOFT_HYPHEN:
+ lclInsertCharacter( pTableView, pTopView, CHAR_SHY );
+ break;
+ case FN_INSERT_HARDHYPHEN:
+ lclInsertCharacter( pTableView, pTopView, CHAR_NBHY );
+ break;
+ case FN_INSERT_HARD_SPACE:
+ lclInsertCharacter( pTableView, pTopView, CHAR_NBSP );
+ break;
+ case FN_INSERT_NNBSP:
+ lclInsertCharacter( pTableView, pTopView, CHAR_NNBSP );
+ break;
+ case SID_INSERT_RLM:
+ lclInsertCharacter( pTableView, pTopView, CHAR_RLM );
+ break;
+ case SID_INSERT_LRM:
+ lclInsertCharacter( pTableView, pTopView, CHAR_LRM );
+ break;
+ case SID_INSERT_ZWSP:
+ lclInsertCharacter( pTableView, pTopView, CHAR_ZWSP );
+ break;
+ case SID_INSERT_WJ:
+ lclInsertCharacter( pTableView, pTopView, CHAR_WJ );
+ break;
+ case SID_INSERT_FIELD_SHEET:
+ {
+ SvxTableField aField(rViewData.GetTabNo());
+ SvxFieldItem aItem(aField, EE_FEATURE_FIELD);
+ pTableView->InsertField(aItem);
+ }
+ break;
+ case SID_INSERT_FIELD_TITLE:
+ {
+ SvxFileField aField;
+ SvxFieldItem aItem(aField, EE_FEATURE_FIELD);
+ pTableView->InsertField(aItem);
+ }
+ break;
+ case SID_INSERT_FIELD_DATE_VAR:
+ {
+ SvxDateField aField;
+ SvxFieldItem aItem(aField, EE_FEATURE_FIELD);
+ pTableView->InsertField(aItem);
+ }
+ break;
+ }
+
+ pHdl->DataChanged(false, bSetModified);
+ if (bSetSelIsRef)
+ pHdl->SetSelIsRef(true);
+}
+
+static void lcl_DisableAll( SfxItemSet& rSet ) // disable all slots
+{
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich)
+ {
+ rSet.DisableItem( nWhich );
+ nWhich = aIter.NextWhich();
+ }
+}
+
+bool ScEditShell::ShouldDisableEditHyperlink() const
+{
+ return !rViewData.HasEditView(rViewData.GetActivePart()) || !URLFieldHelper::IsCursorAtURLField(*pEditView);
+}
+
+void ScEditShell::EnableEditHyperlink()
+{
+ moAtContextMenu_DisableEditHyperlink = false;
+}
+
+void ScEditShell::GetState( SfxItemSet& rSet )
+{
+ // When deactivating the view, edit mode is stopped, but the EditShell is left active
+ // (a shell can't be removed from within Deactivate). In that state, the EditView isn't inserted
+ // into the EditEngine, so it can have an invalid selection and must not be used.
+ if ( !rViewData.HasEditView( rViewData.GetActivePart() ) )
+ {
+ lcl_DisableAll( rSet );
+ return;
+ }
+
+ ScInputHandler* pHdl = GetMyInputHdl();
+ EditView* pActiveView = pHdl ? pHdl->GetActiveView() : pEditView;
+
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich)
+ {
+ switch (nWhich)
+ {
+ case SID_ATTR_INSERT: // Status row
+ {
+ if ( pActiveView )
+ rSet.Put( SfxBoolItem( nWhich, pActiveView->IsInsertMode() ) );
+ else
+ {
+ // Here the code used to pass the value 42 and it used
+ // to "work" without warnings because the SfxBoolItem
+ // was based on 'sal_Bool', which is actually 'unsigned
+ // char'. But now it uses actual 'bool', and passing 42
+ // for a 'bool' parameter causes a warning at least with
+ // MSVC. So use 'true'. I really really hope there is
+ // not code somewhere that retrieves this "boolean" item
+ // and checks it value for the magic value 42...
+ rSet.Put( SfxBoolItem( nWhich, true) );
+ }
+ }
+ break;
+
+ case SID_HYPERLINK_GETLINK:
+ {
+ SvxHyperlinkItem aHLinkItem;
+ const SvxURLField* pURLField = GetURLField();
+ if ( pURLField )
+ {
+ aHLinkItem.SetName( pURLField->GetRepresentation() );
+ aHLinkItem.SetURL( pURLField->GetURL() );
+ aHLinkItem.SetTargetFrame( pURLField->GetTargetFrame() );
+ }
+ else if ( pActiveView )
+ {
+ // use selected text as name for urls
+ OUString sReturn = pActiveView->GetSelected();
+ sReturn = sReturn.copy(0, std::min(sReturn.getLength(), static_cast<sal_Int32>(255)));
+ aHLinkItem.SetName(comphelper::string::stripEnd(sReturn, ' '));
+ }
+ rSet.Put(aHLinkItem);
+ }
+ break;
+
+ case SID_OPEN_HYPERLINK:
+ case SID_EDIT_HYPERLINK:
+ case SID_COPY_HYPERLINK_LOCATION:
+ case SID_REMOVE_HYPERLINK:
+ {
+ bool bDisableEditHyperlink;
+ if (!moAtContextMenu_DisableEditHyperlink)
+ bDisableEditHyperlink = ShouldDisableEditHyperlink();
+ else
+ {
+ // tdf#140361 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();
+ }
+
+ if (bDisableEditHyperlink)
+ rSet.DisableItem (nWhich);
+ }
+ break;
+
+ case SID_TRANSLITERATE_HALFWIDTH:
+ case SID_TRANSLITERATE_FULLWIDTH:
+ case SID_TRANSLITERATE_HIRAGANA:
+ case SID_TRANSLITERATE_KATAKANA:
+ case SID_INSERT_RLM:
+ case SID_INSERT_LRM:
+ ScViewUtil::HideDisabledSlot( rSet, rViewData.GetBindings(), nWhich );
+ break;
+
+ case SID_THES:
+ {
+ OUString aStatusVal;
+ LanguageType nLang = LANGUAGE_NONE;
+ bool bIsLookUpWord = pActiveView &&
+ GetStatusValueForThesaurusFromContext(aStatusVal, nLang, *pActiveView);
+ rSet.Put( SfxStringItem( SID_THES, aStatusVal ) );
+
+ // disable thesaurus context menu entry if there is nothing to look up
+ bool bCanDoThesaurus = ScModule::HasThesaurusLanguage( nLang );
+ if (!bIsLookUpWord || !bCanDoThesaurus)
+ rSet.DisableItem( SID_THES );
+ }
+ break;
+ case SID_INSERT_FIELD_SHEET:
+ case SID_INSERT_FIELD_TITLE:
+ case SID_INSERT_FIELD_DATE_VAR:
+ break;
+ case SID_COPY:
+ case SID_CUT:
+ if (GetObjectShell() && GetObjectShell()->isContentExtractionLocked())
+ {
+ rSet.DisableItem(SID_COPY);
+ rSet.DisableItem(SID_CUT);
+ }
+ break;
+
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+const SvxURLField* ScEditShell::GetURLField()
+{
+ ScInputHandler* pHdl = GetMyInputHdl();
+ EditView* pActiveView = pHdl ? pHdl->GetActiveView() : pEditView;
+ if (!pActiveView)
+ return nullptr;
+
+ const SvxFieldData* pField = pActiveView->GetFieldAtCursor();
+ if (auto pURLField = dynamic_cast<const SvxURLField*>(pField))
+ return pURLField;
+
+ return nullptr;
+}
+
+IMPL_LINK( ScEditShell, ClipboardChanged, TransferableDataHelper*, pDataHelper, void )
+{
+ bPastePossible = ( pDataHelper->HasFormat( SotClipboardFormatId::STRING )
+ || pDataHelper->HasFormat( SotClipboardFormatId::RTF )
+ || pDataHelper->HasFormat( SotClipboardFormatId::RICHTEXT ));
+
+ SfxBindings& rBindings = rViewData.GetBindings();
+ rBindings.Invalidate( SID_PASTE );
+ rBindings.Invalidate( SID_PASTE_SPECIAL );
+ rBindings.Invalidate( SID_PASTE_UNFORMATTED );
+ rBindings.Invalidate( SID_CLIPBOARD_FORMAT_ITEMS );
+}
+
+void ScEditShell::GetClipState( SfxItemSet& rSet )
+{
+ // Do not offer SotClipboardFormatId::STRING_TSVC for in-cell paste.
+
+ if ( !mxClipEvtLstnr.is() )
+ {
+ // create listener
+ mxClipEvtLstnr = new TransferableClipboardListener( LINK( this, ScEditShell, ClipboardChanged ) );
+ vcl::Window* pWin = rViewData.GetActiveWin();
+ mxClipEvtLstnr->AddListener( pWin );
+
+ // get initial state
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( rViewData.GetActiveWin() ) );
+ bPastePossible = ( aDataHelper.HasFormat( SotClipboardFormatId::STRING )
+ || aDataHelper.HasFormat( SotClipboardFormatId::RTF )
+ || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) );
+ }
+
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich)
+ {
+ switch (nWhich)
+ {
+ case SID_PASTE:
+ case SID_PASTE_SPECIAL:
+ case SID_PASTE_UNFORMATTED:
+ if( !bPastePossible )
+ rSet.DisableItem( nWhich );
+ break;
+ case SID_CLIPBOARD_FORMAT_ITEMS:
+ if( bPastePossible )
+ {
+ SvxClipboardFormatItem aFormats( SID_CLIPBOARD_FORMAT_ITEMS );
+ TransferableDataHelper aDataHelper(
+ TransferableDataHelper::CreateFromSystemClipboard( rViewData.GetActiveWin() ) );
+
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) )
+ aFormats.AddClipbrdFormat( SotClipboardFormatId::STRING );
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
+ aFormats.AddClipbrdFormat( SotClipboardFormatId::RTF );
+
+ rSet.Put( aFormats );
+ }
+ else
+ rSet.DisableItem( nWhich );
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+static void lcl_InvalidateUnder( SfxBindings& rBindings )
+{
+ rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
+ rBindings.Invalidate( SID_ULINE_VAL_NONE );
+ rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
+}
+
+void ScEditShell::ExecuteAttr(SfxRequest& rReq)
+{
+ SfxItemSet aSet( pEditView->GetEmptyItemSet() );
+ SfxBindings& rBindings = rViewData.GetBindings();
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ switch ( nSlot )
+ {
+ case SID_ATTR_CHAR_FONTHEIGHT:
+ case SID_ATTR_CHAR_FONT:
+ {
+ if (pArgs)
+ {
+ // #i78017 establish the same behaviour as in Writer
+ SvtScriptType nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
+ if (nSlot == SID_ATTR_CHAR_FONT)
+ {
+ nScript = pEditView->GetSelectedScriptType();
+ if (nScript == SvtScriptType::NONE) nScript = ScGlobal::GetDefaultScriptType();
+ }
+
+ SfxItemPool& rPool = GetPool();
+ SvxScriptSetItem aSetItem( nSlot, rPool );
+ sal_uInt16 nWhich = rPool.GetWhich( nSlot );
+ aSetItem.PutItemForScriptType( nScript, pArgs->Get( nWhich ) );
+
+ aSet.Put( aSetItem.GetItemSet(), false );
+ }
+ }
+ break;
+
+ case SID_ATTR_CHAR_COLOR:
+ {
+ if (pArgs)
+ {
+ if ( const SfxStringItem* pColorStringItem = pArgs->GetItemIfSet( SID_ATTR_COLOR_STR, false ) )
+ {
+ Color aColor;
+ OUString sColor = pColorStringItem->GetValue();
+ if ( sColor == "transparent" )
+ aColor = COL_TRANSPARENT;
+ else
+ aColor = Color( ColorTransparency, sColor.toInt32( 16 ) );
+
+ aSet.Put( SvxColorItem( aColor, EE_CHAR_COLOR ) );
+ }
+ else
+ {
+ aSet.Put( pArgs->Get( pArgs->GetPool()->GetWhich( nSlot ) ) );
+ }
+ rBindings.Invalidate( nSlot );
+ }
+ }
+ break;
+
+ // Toggles
+
+ case SID_ATTR_CHAR_WEIGHT:
+ {
+ // #i78017 establish the same behaviour as in Writer
+ SvtScriptType nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
+
+ SfxItemPool& rPool = GetPool();
+
+ bool bOld = false;
+ SvxScriptSetItem aOldSetItem( nSlot, rPool );
+ aOldSetItem.GetItemSet().Put( pEditView->GetAttribs(), false );
+ const SfxPoolItem* pCore = aOldSetItem.GetItemOfScript( nScript );
+ if ( pCore && static_cast<const SvxWeightItem*>(pCore)->GetWeight() > WEIGHT_NORMAL )
+ bOld = true;
+
+ SvxScriptSetItem aSetItem( nSlot, rPool );
+ aSetItem.PutItemForScriptType( nScript,
+ SvxWeightItem( bOld ? WEIGHT_NORMAL : WEIGHT_BOLD, EE_CHAR_WEIGHT ) );
+ aSet.Put( aSetItem.GetItemSet(), false );
+
+ rBindings.Invalidate( nSlot );
+ }
+ break;
+
+ case SID_ATTR_CHAR_POSTURE:
+ {
+ // #i78017 establish the same behaviour as in Writer
+ SvtScriptType nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
+
+ SfxItemPool& rPool = GetPool();
+
+ bool bOld = false;
+ SvxScriptSetItem aOldSetItem( nSlot, rPool );
+ aOldSetItem.GetItemSet().Put( pEditView->GetAttribs(), false );
+ const SfxPoolItem* pCore = aOldSetItem.GetItemOfScript( nScript );
+ if ( pCore && static_cast<const SvxPostureItem*>(pCore)->GetValue() != ITALIC_NONE )
+ bOld = true;
+
+ SvxScriptSetItem aSetItem( nSlot, rPool );
+ aSetItem.PutItemForScriptType( nScript,
+ SvxPostureItem( bOld ? ITALIC_NONE : ITALIC_NORMAL, EE_CHAR_ITALIC ) );
+ aSet.Put( aSetItem.GetItemSet(), false );
+
+ rBindings.Invalidate( nSlot );
+ }
+ break;
+
+ case SID_ULINE_VAL_NONE:
+ aSet.Put( SvxUnderlineItem( LINESTYLE_NONE, EE_CHAR_UNDERLINE ) );
+ lcl_InvalidateUnder( rBindings );
+ break;
+
+ case SID_ATTR_CHAR_UNDERLINE:
+ case SID_ULINE_VAL_SINGLE:
+ case SID_ULINE_VAL_DOUBLE:
+ case SID_ULINE_VAL_DOTTED:
+ {
+ FontLineStyle eOld = pEditView->GetAttribs().Get(EE_CHAR_UNDERLINE).GetLineStyle();
+ FontLineStyle eNew = eOld;
+ switch (nSlot)
+ {
+ case SID_ATTR_CHAR_UNDERLINE:
+ if ( pArgs )
+ {
+ const SvxTextLineItem& rTextLineItem = static_cast< const SvxTextLineItem& >( pArgs->Get( pArgs->GetPool()->GetWhich(nSlot) ) );
+ eNew = rTextLineItem.GetLineStyle();
+ }
+ else
+ {
+ eNew = ( eOld != LINESTYLE_NONE ) ? LINESTYLE_NONE : LINESTYLE_SINGLE;
+ }
+ break;
+ 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;
+ }
+ aSet.Put( SvxUnderlineItem( eNew, EE_CHAR_UNDERLINE ) );
+ lcl_InvalidateUnder( rBindings );
+ }
+ break;
+
+ case SID_ATTR_CHAR_OVERLINE:
+ {
+ FontLineStyle eOld = pEditView->GetAttribs().Get(EE_CHAR_OVERLINE).GetLineStyle();
+ FontLineStyle eNew = ( eOld != LINESTYLE_NONE ) ? LINESTYLE_NONE : LINESTYLE_SINGLE;
+ aSet.Put( SvxOverlineItem( eNew, EE_CHAR_OVERLINE ) );
+ rBindings.Invalidate( nSlot );
+ }
+ break;
+
+ case SID_ATTR_CHAR_STRIKEOUT:
+ {
+ bool bOld = pEditView->GetAttribs().Get(EE_CHAR_STRIKEOUT).GetValue() != STRIKEOUT_NONE;
+ aSet.Put( SvxCrossedOutItem( bOld ? STRIKEOUT_NONE : STRIKEOUT_SINGLE, EE_CHAR_STRIKEOUT ) );
+ rBindings.Invalidate( nSlot );
+ }
+ break;
+
+ case SID_ATTR_CHAR_SHADOWED:
+ {
+ bool bOld = pEditView->GetAttribs().Get(EE_CHAR_SHADOW).GetValue();
+ aSet.Put( SvxShadowedItem( !bOld, EE_CHAR_SHADOW ) );
+ rBindings.Invalidate( nSlot );
+ }
+ break;
+
+ case SID_ATTR_CHAR_CONTOUR:
+ {
+ bool bOld = pEditView->GetAttribs().Get(EE_CHAR_OUTLINE).GetValue();
+ aSet.Put( SvxContourItem( !bOld, EE_CHAR_OUTLINE ) );
+ rBindings.Invalidate( nSlot );
+ }
+ break;
+
+ case SID_SET_SUPER_SCRIPT:
+ {
+ SvxEscapement eOld = static_cast<SvxEscapement>(pEditView->GetAttribs().Get(EE_CHAR_ESCAPEMENT).GetEnumValue());
+ SvxEscapement eNew = (eOld == SvxEscapement::Superscript) ?
+ SvxEscapement::Off : SvxEscapement::Superscript;
+ aSet.Put( SvxEscapementItem( eNew, EE_CHAR_ESCAPEMENT ) );
+ rBindings.Invalidate( nSlot );
+ }
+ break;
+ case SID_SET_SUB_SCRIPT:
+ {
+ SvxEscapement eOld = static_cast<SvxEscapement>(pEditView->GetAttribs().Get(EE_CHAR_ESCAPEMENT).GetEnumValue());
+ SvxEscapement eNew = (eOld == SvxEscapement::Subscript) ?
+ SvxEscapement::Off : SvxEscapement::Subscript;
+ aSet.Put( SvxEscapementItem( eNew, EE_CHAR_ESCAPEMENT ) );
+ rBindings.Invalidate( nSlot );
+ }
+ break;
+ case SID_ATTR_CHAR_KERNING:
+ {
+ if(pArgs)
+ {
+ aSet.Put ( pArgs->Get(pArgs->GetPool()->GetWhich(nSlot)));
+ rBindings.Invalidate( nSlot );
+ }
+ }
+ break;
+
+ case SID_GROW_FONT_SIZE:
+ case SID_SHRINK_FONT_SIZE:
+ {
+ SfxObjectShell* pObjSh = SfxObjectShell::Current();
+ const SvxFontListItem* pFontListItem = static_cast<const SvxFontListItem*>
+ (pObjSh ? pObjSh->GetItem(SID_ATTR_CHAR_FONTLIST) : nullptr);
+ const FontList* pFontList = pFontListItem ? pFontListItem->GetFontList() : nullptr;
+ pEditView->ChangeFontSize( nSlot == SID_GROW_FONT_SIZE, pFontList );
+ rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ }
+ break;
+ }
+
+ // apply
+
+ EditEngine* pEngine = pEditView->GetEditEngine();
+ bool bOld = pEngine->SetUpdateLayout(false);
+
+ pEditView->SetAttribs( aSet );
+
+ pEngine->SetUpdateLayout(bOld);
+ pEditView->Invalidate();
+
+ ScInputHandler* pHdl = GetMyInputHdl();
+ pHdl->SetModified();
+
+ rReq.Done();
+}
+
+void ScEditShell::GetAttrState(SfxItemSet &rSet)
+{
+ if ( !rViewData.HasEditView( rViewData.GetActivePart() ) )
+ {
+ lcl_DisableAll( rSet );
+ return;
+ }
+
+ SfxItemSet aAttribs = pEditView->GetAttribs();
+ rSet.Put( aAttribs );
+
+ // choose font info according to selection script type
+
+ SvtScriptType nScript = pEditView->GetSelectedScriptType();
+ if (nScript == SvtScriptType::NONE) nScript = ScGlobal::GetDefaultScriptType();
+
+ // #i55929# input-language-dependent script type (depends on input language if nothing selected)
+ SvtScriptType nInputScript = nScript;
+ if ( !pEditView->GetSelection().HasRange() )
+ {
+ LanguageType nInputLang = rViewData.GetActiveWin()->GetInputLanguage();
+ if (nInputLang != LANGUAGE_DONTKNOW && nInputLang != LANGUAGE_SYSTEM)
+ nInputScript = SvtLanguageOptions::GetScriptTypeOfLanguage( nInputLang );
+ }
+
+ // #i55929# according to spec, nInputScript is used for font and font height only
+ if ( rSet.GetItemState( EE_CHAR_FONTINFO ) != SfxItemState::UNKNOWN )
+ ScViewUtil::PutItemScript( rSet, aAttribs, EE_CHAR_FONTINFO, nInputScript );
+ if ( rSet.GetItemState( EE_CHAR_FONTHEIGHT ) != SfxItemState::UNKNOWN )
+ ScViewUtil::PutItemScript( rSet, aAttribs, EE_CHAR_FONTHEIGHT, nInputScript );
+ if ( rSet.GetItemState( EE_CHAR_WEIGHT ) != SfxItemState::UNKNOWN )
+ ScViewUtil::PutItemScript( rSet, aAttribs, EE_CHAR_WEIGHT, nScript );
+ if ( rSet.GetItemState( EE_CHAR_ITALIC ) != SfxItemState::UNKNOWN )
+ ScViewUtil::PutItemScript( rSet, aAttribs, EE_CHAR_ITALIC, nScript );
+
+ // underline
+ SfxItemState eState = aAttribs.GetItemState( EE_CHAR_UNDERLINE );
+ if ( eState == SfxItemState::DONTCARE )
+ {
+ rSet.InvalidateItem( SID_ULINE_VAL_NONE );
+ rSet.InvalidateItem( SID_ULINE_VAL_SINGLE );
+ rSet.InvalidateItem( SID_ULINE_VAL_DOUBLE );
+ rSet.InvalidateItem( SID_ULINE_VAL_DOTTED );
+ }
+ else
+ {
+ FontLineStyle eUnderline = aAttribs.Get(EE_CHAR_UNDERLINE).GetLineStyle();
+ rSet.Put(SfxBoolItem(SID_ULINE_VAL_SINGLE, eUnderline == LINESTYLE_SINGLE));
+ rSet.Put(SfxBoolItem(SID_ULINE_VAL_DOUBLE, eUnderline == LINESTYLE_DOUBLE));
+ rSet.Put(SfxBoolItem(SID_ULINE_VAL_DOTTED, eUnderline == LINESTYLE_DOTTED));
+ rSet.Put(SfxBoolItem(SID_ULINE_VAL_NONE, eUnderline == LINESTYLE_NONE));
+ }
+
+ //! Testing whether brace highlighting is active !!!!
+ ScInputHandler* pHdl = GetMyInputHdl();
+ if ( pHdl && pHdl->IsFormulaMode() )
+ rSet.ClearItem( EE_CHAR_WEIGHT ); // Highlighted brace not here
+
+ SvxEscapement eEsc = static_cast<SvxEscapement>(aAttribs.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));
+ rViewData.GetBindings().Invalidate( SID_SET_SUPER_SCRIPT );
+ rViewData.GetBindings().Invalidate( SID_SET_SUB_SCRIPT );
+
+ eState = aAttribs.GetItemState( EE_CHAR_KERNING );
+ rViewData.GetBindings().Invalidate( SID_ATTR_CHAR_KERNING );
+ if ( eState == SfxItemState::DONTCARE )
+ {
+ rSet.InvalidateItem(EE_CHAR_KERNING);
+ }
+}
+
+OUString ScEditShell::GetSelectionText( bool bWholeWord )
+{
+ OUString aStrSelection;
+
+ if ( rViewData.HasEditView( rViewData.GetActivePart() ) )
+ {
+ if ( bWholeWord )
+ {
+ EditEngine* pEngine = pEditView->GetEditEngine();
+ ESelection aSel = pEditView->GetSelection();
+ OUString aStrCurrentDelimiters = pEngine->GetWordDelimiters();
+
+ pEngine->SetWordDelimiters(" .,;\"'");
+ aStrSelection = pEngine->GetWord( aSel.nEndPara, aSel.nEndPos );
+ pEngine->SetWordDelimiters( aStrCurrentDelimiters );
+ }
+ else
+ {
+ aStrSelection = pEditView->GetSelected();
+ }
+ }
+
+ return aStrSelection;
+}
+
+void ScEditShell::ExecuteUndo(const SfxRequest& rReq)
+{
+ // Undo must be handled here because it's called for both EditViews
+
+ ScInputHandler* pHdl = GetMyInputHdl();
+ OSL_ENSURE(pHdl,"no ScInputHandler");
+ EditView* pTopView = pHdl->GetTopView();
+ EditView* pTableView = pHdl->GetTableView();
+ OSL_ENSURE(pTableView,"no EditView");
+
+ pHdl->DataChanging();
+
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch ( nSlot )
+ {
+ case SID_UNDO:
+ case SID_REDO:
+ {
+ bool bIsUndo = ( nSlot == SID_UNDO );
+
+ sal_uInt16 nCount = 1;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
+ nCount = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
+
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ if ( bIsUndo )
+ {
+ pTableView->Undo();
+ if (pTopView)
+ pTopView->Undo();
+ }
+ else
+ {
+ pTableView->Redo();
+ if (pTopView)
+ pTopView->Redo();
+ }
+ }
+ }
+ break;
+ }
+ rViewData.GetBindings().InvalidateAll(false);
+
+ pHdl->DataChanged();
+}
+
+void ScEditShell::GetUndoState(SfxItemSet &rSet)
+{
+ // Undo state is taken from normal ViewFrame state function
+
+ SfxViewFrame* pViewFrm = rViewData.GetViewShell()->GetViewFrame();
+ if ( pViewFrm && GetUndoManager() )
+ {
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while( nWhich )
+ {
+ pViewFrm->GetSlotState( nWhich, nullptr, &rSet );
+ nWhich = aIter.NextWhich();
+ }
+ }
+
+ // disable if no action in input line EditView
+
+ ScInputHandler* pHdl = GetMyInputHdl();
+ OSL_ENSURE(pHdl,"no ScInputHandler");
+ EditView* pTopView = pHdl->GetTopView();
+ if (pTopView)
+ {
+ SfxUndoManager& rTopMgr = pTopView->GetEditEngine()->GetUndoManager();
+ if ( rTopMgr.GetUndoActionCount() == 0 )
+ rSet.DisableItem( SID_UNDO );
+ if ( rTopMgr.GetRedoActionCount() == 0 )
+ rSet.DisableItem( SID_REDO );
+ }
+}
+
+void ScEditShell::ExecuteTrans( const SfxRequest& rReq )
+{
+ TransliterationFlags nType = ScViewUtil::GetTransliterationType( rReq.GetSlot() );
+ if ( nType == TransliterationFlags::NONE )
+ return;
+
+ ScInputHandler* pHdl = GetMyInputHdl();
+ assert(pHdl && "no ScInputHandler");
+
+ EditView* pTopView = pHdl->GetTopView();
+ EditView* pTableView = pHdl->GetTableView();
+ assert(pTableView && "no EditView");
+
+ pHdl->DataChanging();
+
+ pTableView->TransliterateText( nType );
+ if (pTopView)
+ pTopView->TransliterateText( nType );
+
+ pHdl->DataChanged();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/formatsh.cxx b/sc/source/ui/view/formatsh.cxx
new file mode 100644
index 000000000..913915a20
--- /dev/null
+++ b/sc/source/ui/view/formatsh.cxx
@@ -0,0 +1,2868 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <scitems.hxx>
+#include <editeng/borderline.hxx>
+
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/newstyle.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <svl/whiter.hxx>
+
+#include <svl/stritem.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zformat.hxx>
+#include <svl/languageoptions.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/langitem.hxx>
+#include <svx/numinf.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/tplpitem.hxx>
+#include <editeng/svxenum.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/lineitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <sal/log.hxx>
+#include <comphelper/lok.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+#include <formatsh.hxx>
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <docsh.hxx>
+#include <patattr.hxx>
+#include <scmod.hxx>
+#include <stlpool.hxx>
+#include <stlsheet.hxx>
+#include <printfun.hxx>
+#include <docpool.hxx>
+#include <tabvwsh.hxx>
+#include <undostyl.hxx>
+#include <markdata.hxx>
+#include <attrib.hxx>
+
+#define ShellClass_ScFormatShell
+#define ShellClass_TableFont
+#define ShellClass_FormatForSelection
+#include <scslots.hxx>
+
+#include <scabstdlg.hxx>
+#include <editeng/fontitem.hxx>
+#include <sfx2/classificationhelper.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+
+namespace {
+
+SvxCellHorJustify lclConvertSlotToHAlign( sal_uInt16 nSlot )
+{
+ SvxCellHorJustify eHJustify = SvxCellHorJustify::Standard;
+ switch( nSlot )
+ {
+ case SID_ALIGN_ANY_HDEFAULT: eHJustify = SvxCellHorJustify::Standard; break;
+ case SID_ALIGN_ANY_LEFT: eHJustify = SvxCellHorJustify::Left; break;
+ case SID_ALIGN_ANY_HCENTER: eHJustify = SvxCellHorJustify::Center; break;
+ case SID_ALIGN_ANY_RIGHT: eHJustify = SvxCellHorJustify::Right; break;
+ case SID_ALIGN_ANY_JUSTIFIED: eHJustify = SvxCellHorJustify::Block; break;
+ default: OSL_FAIL( "lclConvertSlotToHAlign - invalid slot" );
+ }
+ return eHJustify;
+}
+
+SvxCellVerJustify lclConvertSlotToVAlign( sal_uInt16 nSlot )
+{
+ SvxCellVerJustify eVJustify = SvxCellVerJustify::Standard;
+ switch( nSlot )
+ {
+ case SID_ALIGN_ANY_VDEFAULT: eVJustify = SvxCellVerJustify::Standard; break;
+ case SID_ALIGN_ANY_TOP: eVJustify = SvxCellVerJustify::Top; break;
+ case SID_ALIGN_ANY_VCENTER: eVJustify = SvxCellVerJustify::Center; break;
+ case SID_ALIGN_ANY_BOTTOM: eVJustify = SvxCellVerJustify::Bottom; break;
+ default: OSL_FAIL( "lclConvertSlotToVAlign - invalid slot" );
+ }
+ return eVJustify;
+}
+
+} // namespace
+
+
+SFX_IMPL_INTERFACE(ScFormatShell, SfxShell)
+
+void ScFormatShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT,
+ SfxVisibilityFlags::Standard | SfxVisibilityFlags::Server,
+ ToolbarId::Objectbar_Format);
+}
+
+ScFormatShell::ScFormatShell(ScViewData& rData) :
+ SfxShell(rData.GetViewShell()),
+ rViewData(rData)
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+
+ SetPool( &pTabViewShell->GetPool() );
+ SfxUndoManager* pMgr = rViewData.GetSfxDocShell()->GetUndoManager();
+ SetUndoManager( pMgr );
+ if ( !rViewData.GetDocument().IsUndoEnabled() )
+ {
+ pMgr->SetMaxUndoActionCount( 0 );
+ }
+ SetName("Format");
+}
+
+ScFormatShell::~ScFormatShell()
+{
+}
+
+void ScFormatShell::GetStyleState( SfxItemSet& rSet )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ SfxStyleSheetBasePool* pStylePool = rDoc.GetStyleSheetPool();
+
+ bool bProtected = false;
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB i=0; i<nTabCount && !bProtected; i++)
+ if (rDoc.IsTabProtected(i)) // look after protected table
+ bProtected = true;
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ sal_uInt16 nSlotId = 0;
+
+ while ( nWhich )
+ {
+ nSlotId = SfxItemPool::IsWhich( nWhich )
+ ? GetPool().GetSlotId( nWhich )
+ : nWhich;
+
+ switch ( nSlotId )
+ {
+ case SID_STYLE_APPLY:
+ if ( !pStylePool )
+ rSet.DisableItem( nSlotId );
+ break;
+
+ case SID_STYLE_FAMILY2: // cell style sheets
+ {
+ SfxStyleSheet* pStyleSheet = const_cast<SfxStyleSheet*>(
+ pTabViewShell->GetStyleSheetFromMarked());
+
+ if ( pStyleSheet )
+ rSet.Put( SfxTemplateItem( nSlotId, pStyleSheet->GetName() ) );
+ else
+ rSet.Put( SfxTemplateItem( nSlotId, OUString() ) );
+ }
+ break;
+
+ case SID_STYLE_FAMILY4: // page style sheets
+ {
+ SCTAB nCurTab = GetViewData().GetTabNo();
+ OUString aPageStyle = rDoc.GetPageStyle( nCurTab );
+ SfxStyleSheet* pStyleSheet = pStylePool ? static_cast<SfxStyleSheet*>(pStylePool->
+ Find( aPageStyle, SfxStyleFamily::Page )) : nullptr;
+
+ if ( pStyleSheet )
+ rSet.Put( SfxTemplateItem( nSlotId, aPageStyle ) );
+ else
+ rSet.Put( SfxTemplateItem( nSlotId, OUString() ) );
+ }
+ break;
+
+ case SID_STYLE_WATERCAN:
+ {
+ rSet.Put( SfxBoolItem( nSlotId, SC_MOD()->GetIsWaterCan() ) );
+ }
+ break;
+
+ case SID_STYLE_UPDATE_BY_EXAMPLE:
+ {
+ std::unique_ptr<SfxUInt16Item> pFamilyItem;
+ pTabViewShell->GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem);
+
+ bool bPage = pFamilyItem && SfxStyleFamily::Page == static_cast<SfxStyleFamily>(pFamilyItem->GetValue());
+
+ if ( bProtected || bPage )
+ rSet.DisableItem( nSlotId );
+ }
+ break;
+
+ case SID_STYLE_EDIT:
+ case SID_STYLE_DELETE:
+ case SID_STYLE_HIDE:
+ case SID_STYLE_SHOW:
+ {
+ std::unique_ptr<SfxUInt16Item> pFamilyItem;
+ pTabViewShell->GetViewFrame()->GetBindings().QueryState(SID_STYLE_FAMILY, pFamilyItem);
+ bool bPage = pFamilyItem && SfxStyleFamily::Page == static_cast<SfxStyleFamily>(pFamilyItem->GetValue());
+
+ if ( bProtected && !bPage )
+ rSet.DisableItem( nSlotId );
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void ScFormatShell::ExecuteStyle( SfxRequest& rReq )
+{
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ const sal_uInt16 nSlotId = rReq.GetSlot();
+ if ( !pArgs && nSlotId != SID_STYLE_NEW_BY_EXAMPLE && nSlotId != SID_STYLE_UPDATE_BY_EXAMPLE )
+ {
+ // in case of vertical toolbar
+ rViewData.GetDispatcher().Execute( SID_STYLE_DESIGNER, SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ return;
+ }
+
+ SfxBindings& rBindings = rViewData.GetBindings();
+ const SCTAB nCurTab = GetViewData().GetTabNo();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScTabViewShell* pTabViewShell= GetViewData().GetViewShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ ScModule* pScMod = SC_MOD();
+ OUString aRefName;
+ bool bUndo = rDoc.IsUndoEnabled();
+ SfxStyleSheetBasePool* pStylePool = rDoc.GetStyleSheetPool();
+
+ if ( (nSlotId == SID_STYLE_PREVIEW)
+ || (nSlotId == SID_STYLE_END_PREVIEW) )
+ {
+ if (nSlotId == SID_STYLE_PREVIEW)
+ {
+ SfxStyleFamily eFamily = SfxStyleFamily::Para;
+ const SfxUInt16Item* pFamItem;
+ if ( pArgs && (pFamItem = pArgs->GetItemIfSet( SID_STYLE_FAMILY )) )
+ eFamily = static_cast<SfxStyleFamily>(pFamItem->GetValue());
+ const SfxPoolItem* pNameItem;
+ OUString aStyleName;
+ if (pArgs && SfxItemState::SET == pArgs->GetItemState( nSlotId, true, &pNameItem ))
+ aStyleName = static_cast<const SfxStringItem*>(pNameItem)->GetValue();
+ if ( eFamily == SfxStyleFamily::Para ) // CellStyles
+ {
+ ScMarkData aFuncMark( rViewData.GetMarkData() );
+ ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
+ aFuncMark.MarkToMulti();
+
+ if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() )
+ {
+ SCCOL nCol = rViewData.GetCurX();
+ SCROW nRow = rViewData.GetCurY();
+ SCTAB nTab = rViewData.GetTabNo();
+ ScRange aRange( nCol, nRow, nTab );
+ aFuncMark.SetMarkArea( aRange );
+ }
+ rDoc.SetPreviewSelection( aFuncMark );
+ ScStyleSheet* pPreviewStyle = static_cast<ScStyleSheet*>( pStylePool->Find( aStyleName, eFamily ) );
+ rDoc.SetPreviewCellStyle( pPreviewStyle );
+ ScPatternAttr aAttr( *rDoc.GetSelectionPattern( aFuncMark ) );
+ aAttr.SetStyleSheet( pPreviewStyle );
+
+ SfxItemSet aItemSet( GetPool() );
+
+ ScPatternAttr aNewAttrs( GetViewData().GetDocument().GetPool() );
+ SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
+ rNewSet.Put( aItemSet, false );
+
+ rDoc.ApplySelectionPattern( aNewAttrs, rDoc.GetPreviewSelection() );
+ pTabViewShell->UpdateSelectionArea( aFuncMark, &aAttr );
+ }
+ }
+ else
+ {
+ // No mark at all happens when creating a new document, in which
+ // case the selection pattern obtained would be empty (created of
+ // GetPool()) anyway and nothing needs to be applied.
+ ScMarkData aPreviewMark( rDoc.GetPreviewSelection());
+ if (aPreviewMark.IsMarked() || aPreviewMark.IsMultiMarked())
+ {
+ ScPatternAttr aAttr( *rDoc.GetSelectionPattern( aPreviewMark ) );
+ if ( ScStyleSheet* pPreviewStyle = rDoc.GetPreviewCellStyle() )
+ aAttr.SetStyleSheet( pPreviewStyle );
+ rDoc.SetPreviewCellStyle(nullptr);
+
+ SfxItemSet aItemSet( GetPool() );
+
+ ScPatternAttr aNewAttrs( GetViewData().GetDocument().GetPool() );
+ SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
+ rNewSet.Put( aItemSet, false );
+ rDoc.ApplySelectionPattern( aNewAttrs, aPreviewMark );
+ pTabViewShell->UpdateSelectionArea( aPreviewMark, &aAttr );
+ }
+ }
+ }
+ else if ( (nSlotId == SID_STYLE_NEW)
+ || (nSlotId == SID_STYLE_EDIT)
+ || (nSlotId == SID_STYLE_DELETE)
+ || (nSlotId == SID_STYLE_HIDE)
+ || (nSlotId == SID_STYLE_SHOW)
+ || (nSlotId == SID_STYLE_APPLY)
+ || (nSlotId == SID_STYLE_WATERCAN)
+ || (nSlotId == SID_STYLE_FAMILY)
+ || (nSlotId == SID_STYLE_NEW_BY_EXAMPLE)
+ || (nSlotId == SID_STYLE_UPDATE_BY_EXAMPLE) )
+ {
+ SfxStyleSheetBase* pStyleSheet = nullptr;
+
+ bool bStyleToMarked = false;
+ bool bListAction = false;
+ bool bAddUndo = false; // add ScUndoModifyStyle (style modified)
+ ScStyleSaveData aOldData; // for undo/redo
+ ScStyleSaveData aNewData;
+
+ SfxStyleFamily eFamily = SfxStyleFamily::Para;
+ const SfxUInt16Item* pFamItem;
+ const SfxStringItem* pFamilyNameItem;
+ if ( pArgs && (pFamItem = pArgs->GetItemIfSet( SID_STYLE_FAMILY )) )
+ eFamily = static_cast<SfxStyleFamily>(pFamItem->GetValue());
+ else if ( pArgs && (pFamilyNameItem = pArgs->GetItemIfSet( SID_STYLE_FAMILYNAME )) )
+ {
+ OUString sFamily = pFamilyNameItem->GetValue();
+ if (sFamily == "CellStyles")
+ eFamily = SfxStyleFamily::Para;
+ else if (sFamily == "PageStyles")
+ eFamily = SfxStyleFamily::Page;
+ }
+
+ OUString aStyleName;
+ sal_uInt16 nRetMask = 0xffff;
+
+ switch ( nSlotId )
+ {
+ case SID_STYLE_NEW:
+ {
+ const SfxPoolItem* pNameItem;
+ if (pArgs && SfxItemState::SET == pArgs->GetItemState( nSlotId, true, &pNameItem ))
+ aStyleName = static_cast<const SfxStringItem*>(pNameItem)->GetValue();
+
+ const SfxStringItem* pRefItem=nullptr;
+ if (pArgs && (pRefItem = pArgs->GetItemIfSet( SID_STYLE_REFERENCE )))
+ {
+ aRefName = pRefItem->GetValue();
+ }
+
+ pStyleSheet = &(pStylePool->Make( aStyleName, eFamily,
+ SfxStyleSearchBits::UserDefined ) );
+
+ if (pStyleSheet->HasParentSupport())
+ pStyleSheet->SetParent(aRefName);
+ }
+ break;
+
+ case SID_STYLE_APPLY:
+ {
+ const SfxStringItem* pNameItem = rReq.GetArg<SfxStringItem>(SID_APPLY_STYLE);
+ const SfxStringItem* pFamilyItem = rReq.GetArg<SfxStringItem>(SID_STYLE_FAMILYNAME);
+ if ( pFamilyItem && pNameItem )
+ {
+ css::uno::Reference< css::style::XStyleFamiliesSupplier > xModel(pDocSh->GetModel(), css::uno::UNO_QUERY);
+ try
+ {
+ css::uno::Reference< css::container::XNameAccess > xStyles;
+ css::uno::Reference< css::container::XNameAccess > xCont = xModel->getStyleFamilies();
+ xCont->getByName(pFamilyItem->GetValue()) >>= xStyles;
+ css::uno::Reference< css::beans::XPropertySet > xInfo;
+ xStyles->getByName( pNameItem->GetValue() ) >>= xInfo;
+ OUString aUIName;
+ xInfo->getPropertyValue("DisplayName") >>= aUIName;
+ if ( !aUIName.isEmpty() )
+ rReq.AppendItem( SfxStringItem( SID_STYLE_APPLY, aUIName ) );
+ }
+ catch( css::uno::Exception& )
+ {
+ }
+ }
+ [[fallthrough]];
+ }
+ case SID_STYLE_EDIT:
+ case SID_STYLE_DELETE:
+ case SID_STYLE_HIDE:
+ case SID_STYLE_SHOW:
+ case SID_STYLE_NEW_BY_EXAMPLE:
+ {
+ const SfxPoolItem* pNameItem;
+ if (pArgs && SfxItemState::SET == pArgs->GetItemState( nSlotId, true, &pNameItem ))
+ aStyleName = static_cast<const SfxStringItem*>(pNameItem)->GetValue();
+ else if ( nSlotId == SID_STYLE_NEW_BY_EXAMPLE )
+ {
+ weld::Window* pDialogParent = rReq.GetFrameWeld();
+ if (!pDialogParent)
+ pDialogParent = pTabViewShell->GetFrameWeld();
+ SfxNewStyleDlg aDlg(pDialogParent, *pStylePool, eFamily);
+ if (aDlg.run() != RET_OK)
+ return;
+ aStyleName = aDlg.GetName();
+ }
+
+ pStyleSheet = pStylePool->Find( aStyleName, eFamily );
+
+ aOldData.InitFromStyle( pStyleSheet );
+ }
+ break;
+
+ case SID_STYLE_WATERCAN:
+ {
+ bool bWaterCan = pScMod->GetIsWaterCan();
+
+ if( !bWaterCan )
+ {
+ const SfxPoolItem* pItem;
+
+ if ( SfxItemState::SET ==
+ pArgs->GetItemState( nSlotId, true, &pItem ) )
+ {
+ const SfxStringItem* pStrItem = dynamic_cast< const SfxStringItem *>( pItem );
+ if ( pStrItem )
+ {
+ aStyleName = pStrItem->GetValue();
+ pStyleSheet = pStylePool->Find( aStyleName, eFamily );
+
+ if ( pStyleSheet )
+ {
+ static_cast<ScStyleSheetPool*>(pStylePool)->
+ SetActualStyleSheet( pStyleSheet );
+ rReq.Done();
+ }
+ }
+ }
+ }
+
+ if ( !bWaterCan && pStyleSheet )
+ {
+ pScMod->SetWaterCan( true );
+ pTabViewShell->SetActivePointer( PointerStyle::Fill );
+ rReq.Done();
+ }
+ else
+ {
+ pScMod->SetWaterCan( false );
+ pTabViewShell->SetActivePointer( PointerStyle::Arrow );
+ rReq.Done();
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // set new style for paintbrush format mode
+ if ( nSlotId == SID_STYLE_APPLY && pScMod->GetIsWaterCan() && pStyleSheet )
+ static_cast<ScStyleSheetPool*>(pStylePool)->SetActualStyleSheet( pStyleSheet );
+
+ switch ( eFamily )
+ {
+ case SfxStyleFamily::Para:
+ {
+ switch ( nSlotId )
+ {
+ case SID_STYLE_DELETE:
+ {
+ if ( pStyleSheet )
+ {
+ pTabViewShell->RemoveStyleSheetInUse( pStyleSheet );
+ pStylePool->Remove( pStyleSheet );
+ pTabViewShell->InvalidateAttribs();
+ nRetMask = sal_uInt16(true);
+ bAddUndo = true;
+ rReq.Done();
+ }
+ else
+ nRetMask = sal_uInt16(false);
+ }
+ break;
+
+ case SID_STYLE_HIDE:
+ case SID_STYLE_SHOW:
+ {
+ if ( pStyleSheet )
+ {
+ pStyleSheet->SetHidden( nSlotId == SID_STYLE_HIDE );
+ pTabViewShell->InvalidateAttribs();
+ rReq.Done();
+ }
+ else
+ nRetMask = sal_uInt16(false);
+ }
+ break;
+
+ case SID_STYLE_APPLY:
+ {
+ if ( pStyleSheet && !pScMod->GetIsWaterCan() )
+ {
+ // apply style sheet to document
+ pTabViewShell->SetStyleSheetToMarked( static_cast<SfxStyleSheet*>(pStyleSheet) );
+ pTabViewShell->InvalidateAttribs();
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_STYLE_NEW_BY_EXAMPLE:
+ case SID_STYLE_UPDATE_BY_EXAMPLE:
+ {
+ // create/replace style sheet by attributes
+ // at cursor position:
+
+ const ScPatternAttr* pAttrItem = nullptr;
+
+ // The query if marked, was always wrong here,
+ // so now no more, and just from the cursor.
+ // If attributes are to be removed from the selection, still need to be
+ // cautious not to adopt items from templates
+ // (GetSelectionPattern also collects items from originals) (# 44748 #)
+ SCCOL nCol = rViewData.GetCurX();
+ SCROW nRow = rViewData.GetCurY();
+ pAttrItem = rDoc.GetPattern( nCol, nRow, nCurTab );
+
+ SfxItemSet aAttrSet = pAttrItem->GetItemSet();
+ aAttrSet.ClearItem( ATTR_MERGE );
+ aAttrSet.ClearItem( ATTR_MERGE_FLAG );
+
+ // Do not adopt conditional formatting and validity,
+ // because they can not be edited in the template
+ aAttrSet.ClearItem( ATTR_VALIDDATA );
+ aAttrSet.ClearItem( ATTR_CONDITIONAL );
+
+ if ( SID_STYLE_NEW_BY_EXAMPLE == nSlotId )
+ {
+ if ( bUndo )
+ {
+ OUString aUndo = ScResId( STR_UNDO_EDITCELLSTYLE );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, pTabViewShell->GetViewShellId() );
+ bListAction = true;
+ }
+
+ bool bConvertBack = false;
+ SfxStyleSheet* pSheetInUse = const_cast<SfxStyleSheet*>(
+ pTabViewShell->GetStyleSheetFromMarked());
+
+ // when a new style is present and is used in the selection,
+ // then the parent can not be adopted:
+ if ( pStyleSheet && pSheetInUse && pStyleSheet == pSheetInUse )
+ pSheetInUse = nullptr;
+
+ // if already present, first remove ...
+ if ( pStyleSheet )
+ {
+ // style pointer to names before erase,
+ // otherwise cells will get invalid pointer
+ //!!! As it happens, a method that does it for a particular style
+ rDoc.StylesToNames();
+ bConvertBack = true;
+ pStylePool->Remove(pStyleSheet);
+ }
+
+ // ...and create new
+ pStyleSheet = &pStylePool->Make( aStyleName, eFamily,
+ SfxStyleSearchBits::UserDefined );
+
+ // when a style is present, then this will become
+ // the parent of the new style:
+ if ( pSheetInUse && pStyleSheet->HasParentSupport() )
+ pStyleSheet->SetParent( pSheetInUse->GetName() );
+
+ if ( bConvertBack )
+ // Name to style pointer
+ rDoc.UpdStlShtPtrsFrmNms();
+ else
+ rDoc.GetPool()->CellStyleCreated( aStyleName, rDoc );
+
+ // Adopt attribute and use style
+ pStyleSheet->GetItemSet().Put( aAttrSet );
+ pTabViewShell->UpdateStyleSheetInUse( pStyleSheet );
+
+ // call SetStyleSheetToMarked after adding the ScUndoModifyStyle
+ // (pStyleSheet pointer is used!)
+ bStyleToMarked = true;
+ }
+ else // ( nSlotId == SID_STYLE_UPDATE_BY_EXAMPLE )
+ {
+ pStyleSheet = const_cast<SfxStyleSheet*>(pTabViewShell->GetStyleSheetFromMarked());
+
+ if ( pStyleSheet )
+ {
+ aOldData.InitFromStyle( pStyleSheet );
+
+ if ( bUndo )
+ {
+ OUString aUndo = ScResId( STR_UNDO_EDITCELLSTYLE );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, pTabViewShell->GetViewShellId() );
+ bListAction = true;
+ }
+
+ pStyleSheet->GetItemSet().Put( aAttrSet );
+ pTabViewShell->UpdateStyleSheetInUse( pStyleSheet );
+
+ // call SetStyleSheetToMarked after adding the ScUndoModifyStyle
+ // (pStyleSheet pointer is used!)
+ bStyleToMarked = true;
+ }
+ }
+
+ aNewData.InitFromStyle( pStyleSheet );
+ bAddUndo = true;
+ rReq.Done();
+ }
+ break;
+
+ default:
+ break;
+ }
+ } // case SfxStyleFamily::Para:
+ break;
+
+ case SfxStyleFamily::Page:
+ {
+ switch ( nSlotId )
+ {
+ case SID_STYLE_DELETE:
+ {
+ nRetMask = sal_uInt16( nullptr != pStyleSheet );
+ if ( pStyleSheet )
+ {
+ if ( rDoc.RemovePageStyleInUse( pStyleSheet->GetName() ) )
+ {
+ ScPrintFunc( pDocSh, pTabViewShell->GetPrinter(true), nCurTab ).UpdatePages();
+ rBindings.Invalidate( SID_STATUS_PAGESTYLE );
+ rBindings.Invalidate( FID_RESET_PRINTZOOM );
+ }
+ pStylePool->Remove( pStyleSheet );
+ rBindings.Invalidate( SID_STYLE_FAMILY4 );
+ pDocSh->SetDocumentModified();
+ bAddUndo = true;
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_STYLE_HIDE:
+ case SID_STYLE_SHOW:
+ {
+ nRetMask = sal_uInt16( nullptr != pStyleSheet );
+ if ( pStyleSheet )
+ {
+ pStyleSheet->SetHidden( nSlotId == SID_STYLE_HIDE );
+ rBindings.Invalidate( SID_STYLE_FAMILY4 );
+ pDocSh->SetDocumentModified();
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_STYLE_APPLY:
+ {
+ nRetMask = sal_uInt16( nullptr != pStyleSheet );
+ if ( pStyleSheet && !pScMod->GetIsWaterCan() )
+ {
+ std::unique_ptr<ScUndoApplyPageStyle> pUndoAction;
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (const auto& rTab : rMark)
+ {
+ if (rTab >= nTabCount)
+ break;
+ OUString aOldName = rDoc.GetPageStyle( rTab );
+ if ( aOldName != aStyleName )
+ {
+ rDoc.SetPageStyle( rTab, aStyleName );
+ ScPrintFunc( pDocSh, pTabViewShell->GetPrinter(true), rTab ).UpdatePages();
+ if( !pUndoAction )
+ pUndoAction.reset(new ScUndoApplyPageStyle( pDocSh, aStyleName ));
+ pUndoAction->AddSheetAction( rTab, aOldName );
+ }
+ }
+ if( pUndoAction )
+ {
+ pDocSh->GetUndoManager()->AddUndoAction( std::move(pUndoAction) );
+ pDocSh->SetDocumentModified();
+ rBindings.Invalidate( SID_STYLE_FAMILY4 );
+ rBindings.Invalidate( SID_STATUS_PAGESTYLE );
+ rBindings.Invalidate( FID_RESET_PRINTZOOM );
+ }
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_STYLE_NEW_BY_EXAMPLE:
+ {
+ const OUString& rStrCurStyle = rDoc.GetPageStyle( nCurTab );
+
+ if ( rStrCurStyle != aStyleName )
+ {
+ SfxStyleSheetBase* pCurStyle = pStylePool->Find( rStrCurStyle, eFamily );
+ SfxItemSet aAttrSet = pCurStyle->GetItemSet();
+ SCTAB nInTab;
+ bool bUsed = rDoc.IsPageStyleInUse( aStyleName, &nInTab );
+
+ // if already present, first remove...
+ if ( pStyleSheet )
+ pStylePool->Remove( pStyleSheet );
+
+ // ...and create new
+ pStyleSheet = &pStylePool->Make( aStyleName, eFamily,
+ SfxStyleSearchBits::UserDefined );
+
+ // Adopt attribute
+ pStyleSheet->GetItemSet().Put( aAttrSet );
+ pDocSh->SetDocumentModified();
+
+ // If being used -> Update
+ if ( bUsed )
+ ScPrintFunc( pDocSh, pTabViewShell->GetPrinter(true), nInTab ).UpdatePages();
+
+ aNewData.InitFromStyle( pStyleSheet );
+ bAddUndo = true;
+ rReq.Done();
+ nRetMask = sal_uInt16(true);
+ }
+ }
+ break;
+
+ default:
+ break;
+ } // switch ( nSlotId )
+ } // case SfxStyleFamily::Page:
+ break;
+
+ default:
+ break;
+ } // switch ( eFamily )
+
+ // create new or process through Dialog:
+ if ( nSlotId == SID_STYLE_NEW || nSlotId == SID_STYLE_EDIT )
+ {
+ if ( pStyleSheet )
+ {
+ SfxStyleFamily eFam = pStyleSheet->GetFamily();
+ ScopedVclPtr<SfxAbstractTabDialog> pDlg;
+ bool bPage = false;
+
+ // Store old Items from the style
+ SfxItemSet aOldSet = pStyleSheet->GetItemSet();
+ OUString aOldName = pStyleSheet->GetName();
+
+ switch ( eFam )
+ {
+ case SfxStyleFamily::Page:
+ bPage = true;
+ break;
+
+ case SfxStyleFamily::Para:
+ default:
+ {
+ SfxItemSet& rSet = pStyleSheet->GetItemSet();
+
+ if ( const SfxUInt32Item* pItem = rSet.GetItemIfSet( ATTR_VALUE_FORMAT,
+ false ) )
+ {
+ // Produce and format NumberFormat Value from Value and Language
+ sal_uLong nFormat = pItem->GetValue();
+ LanguageType eLang =
+ rSet.Get(ATTR_LANGUAGE_FORMAT ).GetLanguage();
+ sal_uLong nLangFormat = rDoc.GetFormatTable()->
+ GetFormatForLanguageIfBuiltIn( nFormat, eLang );
+ if ( nLangFormat != nFormat )
+ {
+ SfxUInt32Item aNewItem( ATTR_VALUE_FORMAT, nLangFormat );
+ rSet.Put( aNewItem );
+ aOldSet.Put( aNewItem );
+ // Also in aOldSet for comparison after the dialog,
+ // Otherwise might miss a language change
+ }
+ }
+
+ std::unique_ptr<SvxNumberInfoItem> pNumberInfoItem(
+ ScTabViewShell::MakeNumberInfoItem(rDoc, GetViewData()));
+
+ pDocSh->PutItem( *pNumberInfoItem );
+ bPage = false;
+
+ // Definitely a SvxBoxInfoItem with Table = sal_False in set:
+ // (If there is no item, the dialogue will also delete the
+ // BORDER_OUTER SvxBoxItem from the Template Set)
+ if ( rSet.GetItemState( ATTR_BORDER_INNER, false ) != SfxItemState::SET )
+ {
+ SvxBoxInfoItem aBoxInfoItem( ATTR_BORDER_INNER );
+ aBoxInfoItem.SetTable(false); // no inner lines
+ aBoxInfoItem.SetDist(true);
+ aBoxInfoItem.SetMinDist(false);
+ rSet.Put( aBoxInfoItem );
+ }
+ }
+ break;
+ }
+
+ pTabViewShell->SetInFormatDialog(true);
+
+ SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
+ rStyleSet.MergeRange( XATTR_FILL_FIRST, XATTR_FILL_LAST );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ weld::Window* pDialogParent = rReq.GetFrameWeld();
+ if (!pDialogParent)
+ pDialogParent = pTabViewShell->GetFrameWeld();
+ pDlg.disposeAndReset(pFact->CreateScStyleDlg(pDialogParent, *pStyleSheet, bPage));
+ short nResult = pDlg->Execute();
+ pTabViewShell->SetInFormatDialog(false);
+
+ if ( nResult == RET_OK )
+ {
+ const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
+
+ if ( pOutSet )
+ {
+ nRetMask = sal_uInt16(pStyleSheet->GetMask());
+
+ // Attribute comparisons (earlier in ModifyStyleSheet) now here
+ // with the old values (the style is already changed)
+ if ( SfxStyleFamily::Para == eFam )
+ {
+ SfxItemSet& rNewSet = pStyleSheet->GetItemSet();
+ bool bNumFormatChanged;
+ if ( ScGlobal::CheckWidthInvalidate(
+ bNumFormatChanged, rNewSet, aOldSet ) )
+ rDoc.InvalidateTextWidth( nullptr, nullptr, bNumFormatChanged );
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ rDoc.SetStreamValid(nTab, false);
+
+ sal_uLong nOldFormat = aOldSet.Get( ATTR_VALUE_FORMAT ).GetValue();
+ sal_uLong nNewFormat = rNewSet.Get( ATTR_VALUE_FORMAT ).GetValue();
+ if ( nNewFormat != nOldFormat )
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ const SvNumberformat* pOld = pFormatter->GetEntry( nOldFormat );
+ const SvNumberformat* pNew = pFormatter->GetEntry( nNewFormat );
+ if ( pOld && pNew && pOld->GetLanguage() != pNew->GetLanguage() )
+ rNewSet.Put( SvxLanguageItem(
+ pNew->GetLanguage(), ATTR_LANGUAGE_FORMAT ) );
+ }
+
+ rDoc.GetPool()->CellStyleCreated( pStyleSheet->GetName(), rDoc );
+ }
+ else
+ {
+ //! Here also queries for Page Styles
+
+ OUString aNewName = pStyleSheet->GetName();
+ if ( aNewName != aOldName &&
+ rDoc.RenamePageStyleInUse( aOldName, aNewName ) )
+ {
+ rBindings.Invalidate( SID_STATUS_PAGESTYLE );
+ rBindings.Invalidate( FID_RESET_PRINTZOOM );
+ }
+
+ rDoc.ModifyStyleSheet( *pStyleSheet, *pOutSet );
+ rBindings.Invalidate( FID_RESET_PRINTZOOM );
+ }
+
+ pDocSh->SetDocumentModified();
+
+ if ( SfxStyleFamily::Para == eFam )
+ {
+ ScTabViewShell::UpdateNumberFormatter(
+ *( pDocSh->GetItem(SID_ATTR_NUMBERFORMAT_INFO) ));
+
+ pTabViewShell->UpdateStyleSheetInUse( pStyleSheet );
+ pTabViewShell->InvalidateAttribs();
+ }
+
+ aNewData.InitFromStyle( pStyleSheet );
+ bAddUndo = true;
+ }
+ }
+ else
+ {
+ if ( nSlotId == SID_STYLE_NEW )
+ pStylePool->Remove( pStyleSheet );
+ else
+ {
+ // If in the meantime something was painted with the
+ // temporary changed item set
+ pDocSh->PostPaintGridAll();
+ }
+ }
+ }
+ }
+
+ rReq.SetReturnValue( SfxUInt16Item( nSlotId, nRetMask ) );
+
+ if ( bAddUndo && bUndo)
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoModifyStyle>( pDocSh, eFamily, aOldData, aNewData ) );
+
+ if ( bStyleToMarked )
+ {
+ // call SetStyleSheetToMarked after adding the ScUndoModifyStyle,
+ // so redo will find the modified style
+ pTabViewShell->SetStyleSheetToMarked( static_cast<SfxStyleSheet*>(pStyleSheet) );
+ pTabViewShell->InvalidateAttribs();
+ }
+
+ if ( bListAction )
+ pDocSh->GetUndoManager()->LeaveListAction();
+ }
+ else if (nSlotId == SID_CLASSIFICATION_APPLY)
+ {
+ const SfxPoolItem* pItem = nullptr;
+ if (pArgs && pArgs->GetItemState(nSlotId, false, &pItem) == SfxItemState::SET)
+ {
+ const OUString& rName = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ SfxClassificationHelper aHelper(pDocSh->getDocProperties());
+ auto eType = SfxClassificationPolicyType::IntellectualProperty;
+ if (const SfxStringItem* pNameItem = pArgs->GetItemIfSet(SID_TYPE_NAME, false))
+ {
+ const OUString& rType = pNameItem->GetValue();
+ eType = SfxClassificationHelper::stringToPolicyType(rType);
+ }
+ aHelper.SetBACName(rName, eType);
+ }
+ else
+ SAL_WARN("sc.ui", "missing parameter for SID_CLASSIFICATION_APPLY");
+ }
+ else
+ {
+ OSL_FAIL( "Unknown slot (ScViewShell::ExecuteStyle)" );
+ }
+}
+
+void ScFormatShell::ExecuteNumFormat( SfxRequest& rReq )
+{
+ ScModule* pScMod = SC_MOD();
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+ SfxBindings& rBindings = pTabViewShell->GetViewFrame()->GetBindings();
+
+ pTabViewShell->HideListBox(); // Autofilter-DropDown-Listbox
+
+ // End input
+ if ( GetViewData().HasEditView( GetViewData().GetActivePart() ) )
+ {
+ switch ( nSlot )
+ {
+ case SID_NUMBER_TYPE_FORMAT:
+ case SID_NUMBER_TWODEC:
+ case SID_NUMBER_SCIENTIFIC:
+ case SID_NUMBER_DATE:
+ case SID_NUMBER_CURRENCY:
+ case SID_NUMBER_PERCENT:
+ case SID_NUMBER_STANDARD:
+ case SID_NUMBER_FORMAT:
+ case SID_NUMBER_INCDEC:
+ case SID_NUMBER_DECDEC:
+ case SID_NUMBER_THOUSANDS:
+ case FID_DEFINE_NAME:
+ case FID_ADD_NAME:
+ case FID_USE_NAME:
+ case FID_INSERT_NAME:
+ case SID_SPELL_DIALOG:
+ case SID_HANGUL_HANJA_CONVERSION:
+
+ pScMod->InputEnterHandler();
+ pTabViewShell->UpdateInputHandler();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ SvNumFormatType nType = GetCurrentNumberFormatType();
+ switch ( nSlot )
+ {
+ case SID_NUMBER_TWODEC:
+ {
+ const SfxItemSet& rAttrSet = pTabViewShell->GetSelectionPattern()->GetItemSet();
+ sal_uInt32 nNumberFormat = rAttrSet.Get(ATTR_VALUE_FORMAT).GetValue();
+
+ if ((nType & SvNumFormatType::NUMBER) && nNumberFormat == 4)
+ pTabViewShell->SetNumberFormat( SvNumFormatType::NUMBER );
+ else
+ pTabViewShell->SetNumberFormat( SvNumFormatType::NUMBER, 4 );
+ rBindings.Invalidate( nSlot );
+ rReq.Done();
+ }
+ break;
+ case SID_NUMBER_SCIENTIFIC:
+ if (nType & SvNumFormatType::SCIENTIFIC)
+ pTabViewShell->SetNumberFormat( SvNumFormatType::NUMBER );
+ else
+ pTabViewShell->SetNumberFormat( SvNumFormatType::SCIENTIFIC );
+ rBindings.Invalidate( nSlot );
+ rReq.Done();
+ break;
+ case SID_NUMBER_DATE:
+ if (nType & SvNumFormatType::DATE)
+ pTabViewShell->SetNumberFormat( SvNumFormatType::NUMBER );
+ else
+ pTabViewShell->SetNumberFormat( SvNumFormatType::DATE );
+ rBindings.Invalidate( nSlot );
+ rReq.Done();
+ break;
+ case SID_NUMBER_TIME:
+ if (nType & SvNumFormatType::TIME)
+ pTabViewShell->SetNumberFormat( SvNumFormatType::NUMBER );
+ else
+ pTabViewShell->SetNumberFormat( SvNumFormatType::TIME );
+ rBindings.Invalidate( nSlot );
+ rReq.Done();
+ break;
+ case SID_NUMBER_CURRENCY:
+ if(pReqArgs)
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs->HasItem( SID_NUMBER_CURRENCY, &pItem ) )
+ {
+ sal_uInt32 nNewFormat = static_cast<const SfxUInt32Item*>(pItem)->GetValue();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ const SfxItemSet& rOldSet = pTabViewShell->GetSelectionPattern()->GetItemSet();
+
+ LanguageType eOldLang = rOldSet.Get( ATTR_LANGUAGE_FORMAT ).GetLanguage();
+ sal_uInt32 nOldFormat = rOldSet.Get( ATTR_VALUE_FORMAT ).GetValue();
+
+ if ( nOldFormat != nNewFormat )
+ {
+ const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
+ ScPatternAttr aNewAttrs( rDoc.GetPool() );
+ SfxItemSet& rSet = aNewAttrs.GetItemSet();
+ LanguageType eNewLang = pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
+ if ( eNewLang != eOldLang && eNewLang != LANGUAGE_DONTKNOW )
+ rSet.Put( SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
+ rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
+ pTabViewShell->ApplySelectionPattern( aNewAttrs );
+ }
+ else
+ pTabViewShell->SetNumberFormat( SvNumFormatType::NUMBER );
+ }
+ }
+ else
+ {
+ if ( nType & SvNumFormatType::CURRENCY )
+ pTabViewShell->SetNumberFormat( SvNumFormatType::NUMBER );
+ else
+ pTabViewShell->SetNumberFormat( SvNumFormatType::CURRENCY );
+ }
+ rBindings.Invalidate( nSlot );
+ rReq.Done();
+ break;
+ case SID_NUMBER_PERCENT:
+ if (nType & SvNumFormatType::PERCENT)
+ pTabViewShell->SetNumberFormat( SvNumFormatType::NUMBER );
+ else
+ pTabViewShell->SetNumberFormat( SvNumFormatType::PERCENT );
+ rBindings.Invalidate( nSlot );
+ rReq.Done();
+ break;
+ case SID_NUMBER_STANDARD:
+ pTabViewShell->SetNumberFormat( SvNumFormatType::NUMBER );
+ rReq.Done();
+ break;
+ case SID_NUMBER_INCDEC:
+ pTabViewShell->ChangeNumFmtDecimals( true );
+ rReq.Done();
+ break;
+ case SID_NUMBER_DECDEC:
+ pTabViewShell->ChangeNumFmtDecimals( false );
+ rReq.Done();
+ break;
+ case SID_NUMBER_THOUSANDS:
+ {
+ ScDocument& rDoc = rViewData.GetDocument();
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ bool bThousand(false);
+ bool bNegRed(false);
+ sal_uInt16 nPrecision(0);
+ sal_uInt16 nLeadZeroes(0);
+ LanguageType eLanguage = ScGlobal::eLnge;
+
+ sal_uInt32 nCurrentNumberFormat = rDoc.GetNumberFormat(
+ rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo());
+ const SvNumberformat* pEntry = pFormatter->GetEntry(nCurrentNumberFormat);
+
+ if (pEntry)
+ eLanguage = pEntry->GetLanguage();
+
+ pFormatter->GetFormatSpecialInfo(nCurrentNumberFormat, bThousand, bNegRed, nPrecision, nLeadZeroes);
+ bThousand = !bThousand;
+ OUString aCode = pFormatter->GenerateFormat(
+ nCurrentNumberFormat,
+ eLanguage,
+ bThousand,
+ bNegRed,
+ nPrecision,
+ nLeadZeroes);
+ pTabViewShell->SetNumFmtByStr(aCode);
+
+ rBindings.Invalidate(nSlot);
+ rReq.Done();
+ }
+ break;
+ case SID_NUMBER_FORMAT:
+ // symphony version with format interpretation
+ if(pReqArgs)
+ {
+ const SfxPoolItem* pItem;
+ ScDocument& rDoc = rViewData.GetDocument();
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+
+ sal_uInt32 nCurrentNumberFormat = rDoc.GetNumberFormat(
+ rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo());
+ const SvNumberformat* pEntry = pFormatter->GetEntry(nCurrentNumberFormat);
+
+ if(!pEntry)
+ break;
+
+ LanguageType eLanguage = pEntry->GetLanguage();
+ SvNumFormatType eType = pEntry->GetMaskedType();
+
+ //Just use eType to judge whether the command is fired for NUMBER/PERCENT/CURRENCY/SCIENTIFIC/FRACTION/TIME
+ //In sidebar, users can fire SID_NUMBER_FORMAT command by operating the related UI controls before they are disable
+ if(!(eType == SvNumFormatType::ALL
+ || eType == SvNumFormatType::NUMBER
+ || eType == SvNumFormatType::PERCENT
+ || eType == SvNumFormatType::CURRENCY
+ || eType == SvNumFormatType::SCIENTIFIC
+ || eType == SvNumFormatType::TIME
+ || eType == SvNumFormatType::FRACTION))
+ pEntry = nullptr;
+
+ if(SfxItemState::SET == pReqArgs->GetItemState(nSlot, true, &pItem) && pEntry)
+ {
+ OUString aCode = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ sal_uInt16 aLen = aCode.getLength();
+ std::unique_ptr<OUString[]> sFormat( new OUString[4] );
+ OUStringBuffer sTmpStr;
+ sal_uInt16 nCount(0);
+ sal_uInt16 nStrCount(0);
+
+ while(nCount < aLen)
+ {
+ sal_Unicode cChar = aCode[nCount];
+
+ if(cChar == ',')
+ {
+ sFormat[nStrCount] = sTmpStr.makeStringAndClear();
+ nStrCount++;
+ }
+ else
+ {
+ sTmpStr.append(cChar);
+ }
+
+ nCount++;
+
+ if(nStrCount > 3)
+ break;
+ }
+
+ const bool bThousand = static_cast<bool>(sFormat[0].toInt32());
+ const bool bNegRed = static_cast<bool>(sFormat[1].toInt32());
+ const sal_uInt16 nPrecision = static_cast<sal_uInt16>(sFormat[2].toInt32());
+ const sal_uInt16 nLeadZeroes = static_cast<sal_uInt16>(sFormat[3].toInt32());
+
+ aCode = pFormatter->GenerateFormat(
+ nCurrentNumberFormat,//modify
+ eLanguage,
+ bThousand,
+ bNegRed,
+ nPrecision,
+ nLeadZeroes);
+ pTabViewShell->SetNumFmtByStr(aCode);
+ }
+ }
+ break;
+
+ case SID_ATTR_NUMBERFORMAT_VALUE:
+ if ( pReqArgs )
+ {
+ if ( const SfxUInt32Item* pItem = pReqArgs->GetItemIfSet( ATTR_VALUE_FORMAT ) )
+ {
+ // We have to accomplish this using ApplyAttributes()
+ // because we also need the language information to be
+ // considered.
+ const SfxItemSet& rOldSet =
+ pTabViewShell->GetSelectionPattern()->GetItemSet();
+ SfxItemPool* pDocPool = GetViewData().GetDocument().GetPool();
+ SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aNewSet( *pDocPool );
+ aNewSet.Put( *pItem );
+ pTabViewShell->ApplyAttributes( &aNewSet, &rOldSet );
+ }
+ }
+ break;
+
+ case SID_NUMBER_TYPE_FORMAT:
+ if ( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
+ {
+ sal_uInt16 nFormat = static_cast<const SfxInt16Item *>(pItem)->GetValue();
+ switch(nFormat)
+ {
+ case 0:
+ pTabViewShell->SetNumberFormat( SvNumFormatType::NUMBER); //Modify
+ break;
+ case 1:
+ pTabViewShell->SetNumberFormat( SvNumFormatType::NUMBER, 2 ); //Modify
+ break;
+ case 2:
+ pTabViewShell->SetNumberFormat( SvNumFormatType::PERCENT );
+ break;
+ case 3:
+ pTabViewShell->SetNumberFormat( SvNumFormatType::CURRENCY );
+ break;
+ case 4:
+ pTabViewShell->SetNumberFormat( SvNumFormatType::DATE );
+ break;
+ case 5:
+ pTabViewShell->SetNumberFormat( SvNumFormatType::TIME );
+ break;
+ case 6:
+ pTabViewShell->SetNumberFormat( SvNumFormatType::SCIENTIFIC );
+ break;
+ case 7:
+ pTabViewShell->SetNumberFormat( SvNumFormatType::FRACTION );
+ break;
+ case 8:
+ pTabViewShell->SetNumberFormat( SvNumFormatType::LOGICAL );
+ break;
+ case 9:
+ pTabViewShell->SetNumberFormat( SvNumFormatType::TEXT );
+ break;
+ default:
+ ;
+ }
+ rReq.Done();
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL("ExecuteEdit: invalid slot");
+ break;
+ }
+}
+
+void ScFormatShell::ExecuteAlignment( SfxRequest& rReq )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ SfxBindings& rBindings = rViewData.GetBindings();
+ const SfxItemSet* pSet = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ pTabViewShell->HideListBox(); // Autofilter-DropDown-Listbox
+
+ switch( nSlot )
+ {
+ // pseudo slots for Format menu
+ case SID_ALIGN_ANY_HDEFAULT:
+ case SID_ALIGN_ANY_LEFT:
+ case SID_ALIGN_ANY_HCENTER:
+ case SID_ALIGN_ANY_RIGHT:
+ case SID_ALIGN_ANY_JUSTIFIED:
+ pTabViewShell->ApplyAttr( SvxHorJustifyItem( lclConvertSlotToHAlign( nSlot ), ATTR_HOR_JUSTIFY ) );
+ break;
+ case SID_ALIGN_ANY_VDEFAULT:
+ case SID_ALIGN_ANY_TOP:
+ case SID_ALIGN_ANY_VCENTER:
+ case SID_ALIGN_ANY_BOTTOM:
+ pTabViewShell->ApplyAttr( SvxVerJustifyItem( lclConvertSlotToVAlign( nSlot ), ATTR_VER_JUSTIFY ) );
+ break;
+
+ default:
+ if( pSet )
+ {
+ const SfxPoolItem* pItem = nullptr;
+ if( pSet->GetItemState(GetPool().GetWhich(nSlot), true, &pItem ) == SfxItemState::SET )
+ {
+
+ switch ( nSlot )
+ {
+ case SID_ATTR_ALIGN_HOR_JUSTIFY:
+ case SID_ATTR_ALIGN_VER_JUSTIFY:
+ case SID_ATTR_ALIGN_INDENT:
+ case SID_ATTR_ALIGN_HYPHENATION:
+ case SID_ATTR_ALIGN_DEGREES:
+ case SID_ATTR_ALIGN_LOCKPOS:
+ case SID_ATTR_ALIGN_MARGIN:
+ case SID_ATTR_ALIGN_STACKED:
+ pTabViewShell->ApplyAttr( *pItem );
+ break;
+
+ case SID_H_ALIGNCELL:
+ {
+ SvxCellHorJustify eJust = static_cast<const SvxHorJustifyItem*>(pItem)->GetValue();
+ // #i78476# update alignment of text in cell edit mode
+ pTabViewShell->UpdateInputHandlerCellAdjust( eJust );
+ pTabViewShell->ApplyAttr( SvxHorJustifyItem( eJust, ATTR_HOR_JUSTIFY ) );
+ }
+ break;
+ case SID_V_ALIGNCELL:
+ pTabViewShell->ApplyAttr( SvxVerJustifyItem( static_cast<const SvxVerJustifyItem*>(pItem)->GetValue(), ATTR_VER_JUSTIFY ) );
+ break;
+ default:
+ OSL_FAIL( "ExecuteAlignment: invalid slot" );
+ return;
+ }
+ }
+ }
+ }
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_LEFT );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_RIGHT );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_BLOCK );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_CENTER);
+ rBindings.Invalidate( SID_ALIGNLEFT );
+ rBindings.Invalidate( SID_ALIGNRIGHT );
+ rBindings.Invalidate( SID_ALIGNCENTERHOR );
+ rBindings.Invalidate( SID_ALIGNBLOCK );
+ rBindings.Invalidate( SID_ALIGNTOP );
+ rBindings.Invalidate( SID_ALIGNBOTTOM );
+ rBindings.Invalidate( SID_ALIGNCENTERVER );
+ rBindings.Invalidate( SID_V_ALIGNCELL );
+ rBindings.Invalidate( SID_H_ALIGNCELL );
+ // pseudo slots for Format menu
+ rBindings.Invalidate( SID_ALIGN_ANY_HDEFAULT );
+ rBindings.Invalidate( SID_ALIGN_ANY_LEFT );
+ rBindings.Invalidate( SID_ALIGN_ANY_HCENTER );
+ rBindings.Invalidate( SID_ALIGN_ANY_RIGHT );
+ rBindings.Invalidate( SID_ALIGN_ANY_JUSTIFIED );
+ rBindings.Invalidate( SID_ALIGN_ANY_VDEFAULT );
+ rBindings.Invalidate( SID_ALIGN_ANY_TOP );
+ rBindings.Invalidate( SID_ALIGN_ANY_VCENTER );
+ rBindings.Invalidate( SID_ALIGN_ANY_BOTTOM );
+ rBindings.Update();
+
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+}
+
+void ScFormatShell::ExecuteTextAttr( SfxRequest& rReq )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ SfxBindings& rBindings = rViewData.GetBindings();
+ const ScPatternAttr* pAttrs = pTabViewShell->GetSelectionPattern();
+ const SfxItemSet* pSet = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+ std::optional<SfxAllItemSet> pNewSet;
+
+ pTabViewShell->HideListBox(); // Autofilter-DropDown-Listbox
+
+ if ( (nSlot == SID_ATTR_CHAR_WEIGHT)
+ ||(nSlot == SID_ATTR_CHAR_POSTURE)
+ ||(nSlot == SID_ATTR_CHAR_UNDERLINE)
+ ||(nSlot == SID_ULINE_VAL_NONE)
+ ||(nSlot == SID_ULINE_VAL_SINGLE)
+ ||(nSlot == SID_ULINE_VAL_DOUBLE)
+ ||(nSlot == SID_ULINE_VAL_DOTTED) )
+ {
+ pNewSet.emplace( GetPool() );
+
+ switch ( nSlot )
+ {
+ case SID_ATTR_CHAR_WEIGHT:
+ {
+ // #i78017 establish the same behaviour as in Writer
+ SvtScriptType nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
+
+ SfxItemPool& rPool = GetPool();
+ SvxScriptSetItem aSetItem( nSlot, rPool );
+ if ( pSet )
+ aSetItem.PutItemForScriptType( nScript, pSet->Get( ATTR_FONT_WEIGHT ) );
+ else
+ {
+ // toggle manually
+
+ FontWeight eWeight = WEIGHT_BOLD;
+ SvxScriptSetItem aOldSetItem( nSlot, rPool );
+ aOldSetItem.GetItemSet().Put( pAttrs->GetItemSet(), false );
+ const SfxPoolItem* pCore = aOldSetItem.GetItemOfScript( nScript );
+ if ( pCore && static_cast<const SvxWeightItem*>(pCore)->GetWeight() == WEIGHT_BOLD )
+ eWeight = WEIGHT_NORMAL;
+
+ aSetItem.PutItemForScriptType( nScript, SvxWeightItem( eWeight, ATTR_FONT_WEIGHT ) );
+ }
+ pTabViewShell->ApplyUserItemSet( aSetItem.GetItemSet() );
+ pNewSet->Put( aSetItem.GetItemSet(), false );
+ }
+ break;
+
+ case SID_ATTR_CHAR_POSTURE:
+ {
+ // #i78017 establish the same behaviour as in Writer
+ SvtScriptType nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
+
+ SfxItemPool& rPool = GetPool();
+ SvxScriptSetItem aSetItem( nSlot, rPool );
+ if ( pSet )
+ aSetItem.PutItemForScriptType( nScript, pSet->Get( ATTR_FONT_POSTURE ) );
+ else
+ {
+ // toggle manually
+
+ FontItalic eItalic = ITALIC_NORMAL;
+ SvxScriptSetItem aOldSetItem( nSlot, rPool );
+ aOldSetItem.GetItemSet().Put( pAttrs->GetItemSet(), false );
+ const SfxPoolItem* pCore = aOldSetItem.GetItemOfScript( nScript );
+ if ( pCore && static_cast<const SvxPostureItem*>(pCore)->GetPosture() == ITALIC_NORMAL )
+ eItalic = ITALIC_NONE;
+
+ aSetItem.PutItemForScriptType( nScript, SvxPostureItem( eItalic, ATTR_FONT_POSTURE ) );
+ }
+ pTabViewShell->ApplyUserItemSet( aSetItem.GetItemSet() );
+ pNewSet->Put( aSetItem.GetItemSet(), false );
+ }
+ break;
+
+ case SID_ATTR_CHAR_UNDERLINE:
+ {
+ if( pSet )
+ {
+ const SfxPoolItem& rUnderline = pSet->Get( ATTR_FONT_UNDERLINE );
+
+ if( dynamic_cast<const SvxUnderlineItem*>( &rUnderline) != nullptr )
+ {
+ pTabViewShell->ApplyAttr( rUnderline );
+ pNewSet->Put( rUnderline,rUnderline.Which() );
+ }
+ else if ( auto pTextLineItem = dynamic_cast<const SvxTextLineItem*>( &rUnderline) )
+ {
+ // #i106580# also allow SvxTextLineItem (base class of SvxUnderlineItem)
+ SvxUnderlineItem aNewItem( pTextLineItem->GetLineStyle(), pTextLineItem->Which() );
+ aNewItem.SetColor( pTextLineItem->GetColor() );
+ pTabViewShell->ApplyAttr( aNewItem );
+ pNewSet->Put( aNewItem, aNewItem.Which() );
+ }
+ }
+ else
+ {
+ SvxUnderlineItem aUnderline( pAttrs->GetItem( ATTR_FONT_UNDERLINE ) );
+ FontLineStyle eUnderline = (LINESTYLE_NONE != aUnderline.GetLineStyle())
+ ? LINESTYLE_NONE
+ : LINESTYLE_SINGLE;
+ aUnderline.SetLineStyle( eUnderline );
+ pTabViewShell->ApplyAttr( aUnderline );
+ pNewSet->Put( aUnderline,aUnderline.Which() );
+ }
+ }
+ break;
+
+ case SID_ULINE_VAL_NONE:
+ pTabViewShell->ApplyAttr( SvxUnderlineItem( LINESTYLE_NONE, ATTR_FONT_UNDERLINE ) );
+ break;
+ case SID_ULINE_VAL_SINGLE: // Toggles
+ case SID_ULINE_VAL_DOUBLE:
+ case SID_ULINE_VAL_DOTTED:
+ {
+ FontLineStyle eOld = pAttrs->GetItem(ATTR_FONT_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;
+ }
+ pTabViewShell->ApplyAttr( SvxUnderlineItem( eNew, ATTR_FONT_UNDERLINE ) );
+ }
+ break;
+
+ default:
+ break;
+ }
+ rBindings.Invalidate( nSlot );
+ }
+ else
+ {
+ /*
+ * "Self-made" functionality of radio buttons
+ * At the toggle the default state is used, this means
+ * no button was clicked.
+ */
+
+ const SfxItemSet& rAttrSet = pTabViewShell->GetSelectionPattern()->GetItemSet();
+ const SvxHorJustifyItem* pHorJustify = rAttrSet.GetItemIfSet(ATTR_HOR_JUSTIFY);
+ const SvxVerJustifyItem* pVerJustify = rAttrSet.GetItemIfSet(ATTR_VER_JUSTIFY );
+ SvxCellHorJustify eHorJustify = SvxCellHorJustify::Standard;
+ SvxCellVerJustify eVerJustify = SvxCellVerJustify::Standard;
+
+ if (pHorJustify)
+ {
+ eHorJustify = pHorJustify->GetValue();
+ }
+ if (pVerJustify)
+ {
+ eVerJustify = pVerJustify->GetValue();
+ }
+
+ switch ( nSlot )
+ {
+ case SID_ALIGNLEFT:
+ rReq.SetSlot( SID_H_ALIGNCELL );
+ rReq.AppendItem( SvxHorJustifyItem(
+ !pHorJustify || (eHorJustify != SvxCellHorJustify::Left) ?
+ SvxCellHorJustify::Left : SvxCellHorJustify::Standard, SID_H_ALIGNCELL ) );
+ ExecuteSlot( rReq, GetInterface() );
+ return;
+
+ case SID_ALIGNRIGHT:
+ rReq.SetSlot( SID_H_ALIGNCELL );
+ rReq.AppendItem( SvxHorJustifyItem(
+ !pHorJustify || (eHorJustify != SvxCellHorJustify::Right) ?
+ SvxCellHorJustify::Right : SvxCellHorJustify::Standard, SID_H_ALIGNCELL ) );
+ ExecuteSlot( rReq, GetInterface() );
+ return;
+
+ case SID_ALIGNCENTERHOR:
+ rReq.SetSlot( SID_H_ALIGNCELL );
+ rReq.AppendItem( SvxHorJustifyItem(
+ !pHorJustify || (eHorJustify != SvxCellHorJustify::Center) ?
+ SvxCellHorJustify::Center : SvxCellHorJustify::Standard, SID_H_ALIGNCELL ) );
+ ExecuteSlot( rReq, GetInterface() );
+ return;
+
+ case SID_ALIGNBLOCK:
+ rReq.SetSlot( SID_H_ALIGNCELL );
+ rReq.AppendItem( SvxHorJustifyItem(
+ !pHorJustify || (eHorJustify != SvxCellHorJustify::Block) ?
+ SvxCellHorJustify::Block : SvxCellHorJustify::Standard, SID_H_ALIGNCELL ) );
+ ExecuteSlot( rReq, GetInterface() );
+ return;
+
+ case SID_ALIGNTOP:
+ rReq.SetSlot( SID_V_ALIGNCELL );
+ rReq.AppendItem( SvxVerJustifyItem(
+ !pVerJustify || (eVerJustify != SvxCellVerJustify::Top) ?
+ SvxCellVerJustify::Top : SvxCellVerJustify::Standard, SID_V_ALIGNCELL ) );
+ ExecuteSlot( rReq, GetInterface() );
+ return;
+
+ case SID_ALIGNBOTTOM:
+ rReq.SetSlot( SID_V_ALIGNCELL );
+ rReq.AppendItem( SvxVerJustifyItem(
+ !pVerJustify || (eVerJustify != SvxCellVerJustify::Bottom) ?
+ SvxCellVerJustify::Bottom : SvxCellVerJustify::Standard, SID_V_ALIGNCELL ) );
+ ExecuteSlot( rReq, GetInterface() );
+ return;
+
+ case SID_ALIGNCENTERVER:
+ rReq.SetSlot( SID_V_ALIGNCELL );
+ rReq.AppendItem( SvxVerJustifyItem(
+ !pVerJustify || (eVerJustify != SvxCellVerJustify::Center) ?
+ SvxCellVerJustify::Center : SvxCellVerJustify::Standard, SID_V_ALIGNCELL ) );
+ ExecuteSlot( rReq, GetInterface() );
+ return;
+
+ default:
+ break;
+ }
+
+ }
+
+ rBindings.Update();
+
+ if( pNewSet )
+ {
+ rReq.Done( *pNewSet );
+ pNewSet.reset();
+ }
+ else
+ {
+ rReq.Done();
+ }
+
+}
+
+namespace
+{
+ bool lcl_getColorFromStr(const SfxItemSet *pArgs, Color &rColor)
+ {
+ const SfxStringItem* pColorStringItem = nullptr;
+
+ if (pArgs && (pColorStringItem = pArgs->GetItemIfSet(SID_ATTR_COLOR_STR, false)))
+ {
+ OUString sColor;
+ sColor = pColorStringItem->GetValue();
+
+ if (sColor == "transparent")
+ rColor = COL_TRANSPARENT;
+ else
+ rColor = Color(ColorTransparency, sColor.toInt32(16));
+ return true;
+ }
+ return false;
+ }
+}
+
+void ScFormatShell::ExecuteAttr( SfxRequest& rReq )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ SfxBindings& rBindings = rViewData.GetBindings();
+ const SfxItemSet* pNewAttrs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ pTabViewShell->HideListBox(); // Autofilter-DropDown-Listbox
+ ScDocument& rDoc = GetViewData().GetDocument();
+ if ( !pNewAttrs )
+ {
+ switch ( nSlot )
+ {
+ case SID_GROW_FONT_SIZE:
+ case SID_SHRINK_FONT_SIZE:
+ {
+ SfxItemPool& rPool = GetPool();
+ SvxScriptSetItem aSetItem( SID_ATTR_CHAR_FONTHEIGHT, rPool );
+ aSetItem.GetItemSet().Put( pTabViewShell->GetSelectionPattern()->GetItemSet(), false );
+
+ SvtScriptType nScriptTypes = pTabViewShell->GetSelectionScriptType();
+ const SvxFontHeightItem* pSize( static_cast<const SvxFontHeightItem*>( aSetItem.GetItemOfScript( nScriptTypes ) ) );
+
+ if ( pSize )
+ {
+ SvxFontHeightItem aSize( *pSize );
+ sal_uInt32 nSize = aSize.GetHeight();
+
+ const sal_uInt32 nFontInc = 40; // 2pt
+ const sal_uInt32 nFontMaxSz = 19998; // 999.9pt
+ if ( nSlot == SID_GROW_FONT_SIZE )
+ nSize = std::min< sal_uInt32 >( nSize + nFontInc, nFontMaxSz );
+ else
+ nSize = std::max< sal_Int32 >( nSize - nFontInc, nFontInc );
+
+ aSize.SetHeight( nSize );
+ aSetItem.PutItemForScriptType( nScriptTypes, aSize );
+ pTabViewShell->ApplyUserItemSet( aSetItem.GetItemSet() );
+ }
+ rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ }
+ break;
+
+ case SID_ATTR_CHAR_ENDPREVIEW_FONT:
+ {
+ rDoc.SetPreviewFont(nullptr);
+ pTabViewShell->UpdateSelectionArea( rDoc.GetPreviewSelection() );
+ break;
+ }
+ case SID_ATTR_CHAR_COLOR:
+ case SID_ATTR_CHAR_FONT:
+ case SID_ATTR_CHAR_FONTHEIGHT:
+ pTabViewShell->ExecuteCellFormatDlg(rReq, "font"); // when ToolBar is vertical
+ break;
+
+ case SID_BACKGROUND_COLOR:
+ {
+ SvxBrushItem aBrushItem(
+ pTabViewShell->GetSelectionPattern()->GetItem( ATTR_BACKGROUND ) );
+ aBrushItem.SetColor( COL_TRANSPARENT );
+ pTabViewShell->ApplyAttr( aBrushItem, false );
+ }
+ break;
+
+ case SID_ATTR_ALIGN_LINEBREAK: // without parameter as toggle
+ {
+ const ScPatternAttr* pAttrs = pTabViewShell->GetSelectionPattern();
+ bool bOld = pAttrs->GetItem(ATTR_LINEBREAK).GetValue();
+ ScLineBreakCell aBreakItem(!bOld);
+ pTabViewShell->ApplyAttr( aBreakItem );
+
+ SfxAllItemSet aNewSet( GetPool() );
+ aNewSet.Put( aBreakItem,aBreakItem.Which() );
+ rReq.Done( aNewSet );
+
+ rBindings.Invalidate( nSlot );
+ }
+ break;
+
+ case SID_SCATTR_CELLPROTECTION: // without parameter as toggle
+ {
+ const ScPatternAttr* pAttrs = pTabViewShell->GetSelectionPattern();
+ bool bProtect = pAttrs->GetItem(ATTR_PROTECTION).GetProtection();
+ bool bHideFormula = pAttrs->GetItem(ATTR_PROTECTION).GetHideFormula();
+ bool bHideCell = pAttrs->GetItem(ATTR_PROTECTION).GetHideCell();
+ bool bHidePrint = pAttrs->GetItem(ATTR_PROTECTION).GetHidePrint();
+
+ ScProtectionAttr aProtectionItem( !bProtect, bHideFormula, bHideCell, bHidePrint );
+ pTabViewShell->ApplyAttr( aProtectionItem );
+
+ SfxAllItemSet aNewSet( GetPool() );
+ aNewSet.Put( aProtectionItem, aProtectionItem.Which());
+ aNewSet.Put( SfxBoolItem( SID_SCATTR_CELLPROTECTION, !bProtect ) );
+ rReq.Done( aNewSet );
+
+ rBindings.Invalidate( nSlot );
+ }
+ break;
+ }
+ }
+ else
+ {
+ switch ( nSlot )
+ {
+ case SID_ATTR_CHAR_PREVIEW_FONT:
+ {
+ SfxItemPool& rPool = GetPool();
+ sal_uInt16 nWhich = rPool.GetWhich( nSlot );
+ const SvxFontItem& rFont = static_cast<const SvxFontItem&>(pNewAttrs->Get( nWhich ));
+ SvxScriptSetItem aSetItem( SID_ATTR_CHAR_FONT, rPool );
+ SvtScriptType nScript = pTabViewShell->GetSelectionScriptType();
+ aSetItem.PutItemForScriptType( nScript, rFont );
+
+ ScMarkData aFuncMark( rViewData.GetMarkData() );
+ ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
+ rDoc.SetPreviewFont( aSetItem.GetItemSet().Clone() );
+ aFuncMark.MarkToMulti();
+
+ if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() )
+ {
+ SCCOL nCol = rViewData.GetCurX();
+ SCROW nRow = rViewData.GetCurY();
+ SCTAB nTab = rViewData.GetTabNo();
+ ScRange aRange( nCol, nRow, nTab );
+ aFuncMark.SetMarkArea( aRange );
+ }
+ rDoc.SetPreviewSelection( aFuncMark );
+ pTabViewShell->UpdateSelectionArea( aFuncMark );
+ break;
+ }
+ case SID_ATTR_CHAR_OVERLINE:
+ case SID_ATTR_CHAR_STRIKEOUT:
+ case SID_ATTR_ALIGN_LINEBREAK:
+ case SID_ATTR_CHAR_CONTOUR:
+ case SID_ATTR_CHAR_SHADOWED:
+ case SID_ATTR_CHAR_RELIEF:
+ pTabViewShell->ApplyAttr( pNewAttrs->Get( pNewAttrs->GetPool()->GetWhich( nSlot ) ) );
+ rBindings.Invalidate( nSlot );
+ rBindings.Update( nSlot );
+ break;
+ case SID_ATTR_CHAR_COLOR:
+ case SID_SCATTR_PROTECTION :
+ {
+ Color aColor;
+ if (lcl_getColorFromStr(pNewAttrs, aColor))
+ {
+ SvxColorItem aColorItem(pTabViewShell->GetSelectionPattern()->
+ GetItem( ATTR_FONT_COLOR ) );
+ aColorItem.SetValue(aColor);
+ pTabViewShell->ApplyAttr(aColorItem, false);
+ }
+ else
+ {
+ pTabViewShell->ApplyAttr( pNewAttrs->Get( pNewAttrs->GetPool()->GetWhich( nSlot) ), false);
+ }
+
+ rBindings.Invalidate( nSlot );
+ rBindings.Update( nSlot );
+ }
+
+ break;
+
+ case SID_ATTR_CHAR_FONT:
+ case SID_ATTR_CHAR_FONTHEIGHT:
+ {
+ // #i78017 establish the same behaviour as in Writer
+ SvtScriptType nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
+ if (nSlot == SID_ATTR_CHAR_FONT)
+ nScript = pTabViewShell->GetSelectionScriptType();
+
+ SfxItemPool& rPool = GetPool();
+ SvxScriptSetItem aSetItem( nSlot, rPool );
+ sal_uInt16 nWhich = rPool.GetWhich( nSlot );
+ aSetItem.PutItemForScriptType( nScript, pNewAttrs->Get( nWhich ) );
+
+ pTabViewShell->ApplyUserItemSet( aSetItem.GetItemSet() );
+
+ rBindings.Invalidate( nSlot );
+ rBindings.Update( nSlot );
+ }
+ break;
+
+ case SID_FRAME_LINESTYLE:
+ {
+ // Update default line
+ const ::editeng::SvxBorderLine* pLine =
+ pNewAttrs->Get( SID_FRAME_LINESTYLE ).
+ GetLine();
+
+ if ( pLine )
+ {
+ ::editeng::SvxBorderLine* pDefLine = pTabViewShell->GetDefaultFrameLine();
+
+ if ( pDefLine )
+ {
+ pDefLine->SetBorderLineStyle(
+ pLine->GetBorderLineStyle());
+ pDefLine->SetWidth( pLine->GetWidth( ) );
+ pTabViewShell->SetSelectionFrameLines( pDefLine, false );
+ }
+ else
+ {
+ pTabViewShell->SetDefaultFrameLine( pLine );
+ pTabViewShell->GetDefaultFrameLine()->SetColor( COL_BLACK );
+ pTabViewShell->SetSelectionFrameLines( pLine, false );
+ }
+ }
+ else
+ {
+ Color aColorBlack( COL_BLACK );
+ ::editeng::SvxBorderLine aDefLine( &aColorBlack, 20,
+ SvxBorderLineStyle::SOLID );
+ pTabViewShell->SetDefaultFrameLine( &aDefLine );
+ pTabViewShell->SetSelectionFrameLines( nullptr, false );
+ }
+ }
+ break;
+
+ case SID_FRAME_LINECOLOR:
+ {
+ ::editeng::SvxBorderLine* pDefLine = pTabViewShell->GetDefaultFrameLine();
+
+ Color aColor;
+ if (!lcl_getColorFromStr(pNewAttrs, aColor))
+ aColor = pNewAttrs->Get( SID_FRAME_LINECOLOR ).GetValue();
+
+ // Update default line
+ if ( pDefLine )
+ {
+ pDefLine->SetColor( aColor );
+ pTabViewShell->SetSelectionFrameLines( pDefLine, true );
+ }
+ else
+ {
+ ::editeng::SvxBorderLine aDefLine( &aColor, 20, SvxBorderLineStyle::SOLID );
+ pTabViewShell->SetDefaultFrameLine( &aDefLine );
+ pTabViewShell->SetSelectionFrameLines( &aDefLine, false );
+ }
+ }
+ break;
+
+ case SID_ATTR_BORDER_OUTER:
+ case SID_ATTR_BORDER:
+ {
+ ::editeng::SvxBorderLine* pDefLine = pTabViewShell->GetDefaultFrameLine();
+ const ScPatternAttr* pOldAttrs = pTabViewShell->GetSelectionPattern();
+ SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aOldSet( *rDoc.GetPool() );
+ SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aNewSet( *rDoc.GetPool() );
+ const SfxPoolItem& rBorderAttr =
+ pOldAttrs->GetItemSet().
+ Get( ATTR_BORDER );
+
+ // Evaluate border items from controller:
+
+ if ( const SvxBoxItem* pBoxItem = pNewAttrs->GetItemIfSet( ATTR_BORDER ) )
+ {
+ // The SvxFrameToolBoxControl toolbox controller uses a default
+ // SvxBorderLine (all widths 0) to mark the lines that should be set.
+ // Macro recording uses a SvxBoxItem with the real values (OutWidth > 0)
+ // or NULL pointers for no lines.
+ // -> Substitute existing lines with pDefLine only if widths are 0.
+ SvxBoxItem aBoxItem ( *pBoxItem );
+ if ( aBoxItem.GetTop() && aBoxItem.GetTop()->GetOutWidth() == 0 )
+ aBoxItem.SetLine( pDefLine, SvxBoxItemLine::TOP );
+ if ( aBoxItem.GetBottom() && aBoxItem.GetBottom()->GetOutWidth() == 0 )
+ aBoxItem.SetLine( pDefLine, SvxBoxItemLine::BOTTOM );
+ if ( aBoxItem.GetLeft() && aBoxItem.GetLeft()->GetOutWidth() == 0 )
+ aBoxItem.SetLine( pDefLine, SvxBoxItemLine::LEFT );
+ if ( aBoxItem.GetRight() && aBoxItem.GetRight()->GetOutWidth() == 0 )
+ aBoxItem.SetLine( pDefLine, SvxBoxItemLine::RIGHT );
+ aNewSet.Put( aBoxItem );
+ rReq.AppendItem( aBoxItem );
+ }
+
+ if ( const SvxBoxInfoItem* pBoxInfoItem = pNewAttrs->GetItemIfSet( ATTR_BORDER_INNER ) )
+ {
+ SvxBoxInfoItem aBoxInfoItem( *pBoxInfoItem );
+ if ( aBoxInfoItem.GetHori() && aBoxInfoItem.GetHori()->GetOutWidth() == 0 )
+ aBoxInfoItem.SetLine( pDefLine, SvxBoxInfoItemLine::HORI );
+ if ( aBoxInfoItem.GetVert() && aBoxInfoItem.GetVert()->GetOutWidth() == 0 )
+ aBoxInfoItem.SetLine( pDefLine, SvxBoxInfoItemLine::VERT );
+ aNewSet.Put( aBoxInfoItem );
+ rReq.AppendItem( aBoxInfoItem );
+ }
+ else
+ {
+ SvxBoxInfoItem aBoxInfoItem( ATTR_BORDER_INNER );
+ aBoxInfoItem.SetLine( nullptr, SvxBoxInfoItemLine::HORI );
+ aBoxInfoItem.SetLine( nullptr, SvxBoxInfoItemLine::VERT );
+ aNewSet.Put( aBoxInfoItem );
+ }
+
+ aOldSet.Put( rBorderAttr );
+ pTabViewShell->ApplyAttributes( &aNewSet, &aOldSet );
+ }
+ break;
+
+ case SID_ATTR_BORDER_DIAG_TLBR:
+ case SID_ATTR_BORDER_DIAG_BLTR:
+ {
+ const ScPatternAttr* pOldAttrs = pTabViewShell->GetSelectionPattern();
+ SfxItemSet aOldSet(pOldAttrs->GetItemSet());
+ SfxItemSet aNewSet(pOldAttrs->GetItemSet());
+
+ if(SID_ATTR_BORDER_DIAG_TLBR == nSlot)
+ {
+ if(SfxItemState::SET == pNewAttrs->GetItemState(ATTR_BORDER_TLBR))
+ {
+ SvxLineItem aItem(ATTR_BORDER_TLBR);
+ aItem.SetLine(pNewAttrs->Get(ATTR_BORDER_TLBR).GetLine());
+ aNewSet.Put(aItem);
+ rReq.AppendItem(aItem);
+ pTabViewShell->ApplyAttributes(&aNewSet, &aOldSet);
+ }
+ }
+ else // if( nSlot == SID_ATTR_BORDER_DIAG_BLTR )
+ {
+ if(SfxItemState::SET == pNewAttrs->GetItemState(ATTR_BORDER_BLTR ))
+ {
+ SvxLineItem aItem(ATTR_BORDER_BLTR);
+ aItem.SetLine(pNewAttrs->Get(ATTR_BORDER_BLTR).GetLine());
+ aNewSet.Put(aItem);
+ rReq.AppendItem(aItem);
+ pTabViewShell->ApplyAttributes(&aNewSet, &aOldSet);
+ }
+ }
+
+ rBindings.Invalidate(nSlot);
+ }
+ break;
+
+ // ATTR_BACKGROUND (=SID_ATTR_BRUSH) has to be set to two IDs:
+ case SID_BACKGROUND_COLOR:
+ {
+ Color aColor;
+
+ if (!lcl_getColorFromStr(pNewAttrs, aColor))
+ {
+ const SvxColorItem& rNewColorItem = pNewAttrs->Get( SID_BACKGROUND_COLOR );
+ aColor = rNewColorItem.GetValue();
+ }
+
+ SvxBrushItem aBrushItem(
+ pTabViewShell->GetSelectionPattern()->GetItem( ATTR_BACKGROUND ) );
+ aBrushItem.SetColor( aColor );
+
+ pTabViewShell->ApplyAttr( aBrushItem, false );
+ }
+ break;
+
+ case SID_ATTR_BRUSH:
+ {
+ SvxBrushItem aBrushItem( pTabViewShell->GetSelectionPattern()->
+ GetItem( ATTR_BACKGROUND ) );
+ const SvxBrushItem& rNewBrushItem = static_cast<const SvxBrushItem&>(
+ pNewAttrs->Get( GetPool().GetWhich(nSlot) ) );
+ aBrushItem.SetColor(rNewBrushItem.GetColor());
+ pTabViewShell->ApplyAttr( aBrushItem );
+ }
+ break;
+
+ case SID_ATTR_BORDER_SHADOW:
+ {
+ const SvxShadowItem& rNewShadowItem =
+ pNewAttrs->Get( ATTR_SHADOW );
+ pTabViewShell->ApplyAttr( rNewShadowItem );
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if( ! rReq.IsAPI() && ! rReq.IsDone() )
+ rReq.Done();
+ }
+}
+
+void ScFormatShell::GetAttrState( SfxItemSet& rSet )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ const SfxItemSet& rAttrSet = pTabViewShell->GetSelectionPattern()->GetItemSet();
+ const SvxBrushItem& rBrushItem = rAttrSet.Get( ATTR_BACKGROUND );
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ rSet.Put( rAttrSet, false );
+
+ // choose font info according to selection script type
+ SvtScriptType nScript = SvtScriptType::NONE; // GetSelectionScriptType never returns 0
+ if ( rSet.GetItemState( ATTR_FONT ) != SfxItemState::UNKNOWN )
+ {
+ nScript = pTabViewShell->GetSelectionScriptType();
+ ScViewUtil::PutItemScript( rSet, rAttrSet, ATTR_FONT, nScript );
+ }
+ if ( rSet.GetItemState( ATTR_FONT_HEIGHT ) != SfxItemState::UNKNOWN )
+ {
+ if (nScript == SvtScriptType::NONE) nScript = pTabViewShell->GetSelectionScriptType();
+ ScViewUtil::PutItemScript( rSet, rAttrSet, ATTR_FONT_HEIGHT, nScript );
+ }
+
+ while ( nWhich )
+ {
+ switch(nWhich)
+ {
+ case SID_BACKGROUND_COLOR:
+ {
+ rSet.Put( SvxColorItem( rBrushItem.GetColor(), SID_BACKGROUND_COLOR ) );
+ if(SfxItemState::DONTCARE == rAttrSet.GetItemState(ATTR_BACKGROUND))
+ {
+ rSet.InvalidateItem(SID_BACKGROUND_COLOR);
+ }
+ }
+ break;
+ case SID_FRAME_LINESTYLE:
+ case SID_FRAME_LINECOLOR:
+ {
+ // handled together because both need the cell border information for decisions
+ Color aCol;
+ editeng::SvxBorderLine aLine(nullptr,0,SvxBorderLineStyle::SOLID);
+ bool bCol = false;
+ bool bColDisable = false, bStyleDisable = false;
+ std::shared_ptr<SvxBoxItem> aBoxItem(std::make_shared<SvxBoxItem>(ATTR_BORDER));
+ std::shared_ptr<SvxBoxInfoItem> aInfoItem(std::make_shared<SvxBoxInfoItem>(ATTR_BORDER_INNER));
+
+ pTabViewShell->GetSelectionFrame(aBoxItem, aInfoItem);
+
+ if( aBoxItem->GetTop() )
+ {
+ bCol = true;
+ aCol = aBoxItem->GetTop()->GetColor() ;
+ aLine.SetColor(aCol);
+ aLine.SetWidth( aBoxItem->GetTop()->GetWidth());
+ aLine.SetBorderLineStyle( aBoxItem->GetTop()->GetBorderLineStyle());
+ }
+
+ if( aBoxItem->GetBottom() )
+ {
+ if(!bCol)
+ {
+ bCol = true;
+ aCol = aBoxItem->GetBottom()->GetColor() ;
+ aLine.SetColor(aCol);
+ aLine.SetWidth( aBoxItem->GetBottom()->GetWidth());
+ aLine.SetBorderLineStyle( aBoxItem->GetBottom()->GetBorderLineStyle());
+ }
+ else
+ {
+ if(aCol != aBoxItem->GetBottom()->GetColor() )
+ bColDisable = true;
+ if( aLine != *aBoxItem->GetBottom() )
+ bStyleDisable = true;
+ }
+ }
+
+ if( aBoxItem->GetLeft() )
+ {
+ if(!bCol)
+ {
+ bCol = true;
+ aCol = aBoxItem->GetLeft()->GetColor() ;
+ aLine.SetColor(aCol);
+ aLine.SetWidth( aBoxItem->GetLeft()->GetWidth());
+ aLine.SetBorderLineStyle( aBoxItem->GetLeft()->GetBorderLineStyle());
+ }
+ else
+ {
+ if(aCol != aBoxItem->GetLeft()->GetColor() )
+ bColDisable = true;
+ if( aLine != *aBoxItem->GetLeft() )
+ bStyleDisable = true;
+ }
+ }
+
+ if( aBoxItem->GetRight() )
+ {
+ if(!bCol)
+ {
+ bCol = true;
+ aCol = aBoxItem->GetRight()->GetColor() ;
+ aLine.SetColor(aCol);
+ aLine.SetWidth( aBoxItem->GetRight()->GetWidth());
+ aLine.SetBorderLineStyle( aBoxItem->GetRight()->GetBorderLineStyle());
+ }
+ else
+ {
+ if(aCol != aBoxItem->GetRight()->GetColor() )
+ bColDisable = true;
+ if( aLine != *aBoxItem->GetRight() )
+ bStyleDisable = true;
+ }
+ }
+
+ if( aInfoItem->GetVert())
+ {
+ if(!bCol)
+ {
+ bCol = true;
+ aCol = aInfoItem->GetVert()->GetColor() ;
+ aLine.SetColor(aCol);
+ aLine.SetWidth( aInfoItem->GetVert()->GetWidth());
+ aLine.SetBorderLineStyle( aInfoItem->GetVert()->GetBorderLineStyle());
+ }
+ else
+ {
+ if(aCol != aInfoItem->GetVert()->GetColor() )
+ bColDisable = true;
+ if( aLine != *aInfoItem->GetVert() )
+ bStyleDisable = true;
+ }
+ }
+
+ if( aInfoItem->GetHori())
+ {
+ if(!bCol)
+ {
+ bCol = true;
+ aCol = aInfoItem->GetHori()->GetColor() ;
+ aLine.SetColor(aCol);
+ aLine.SetWidth( aInfoItem->GetHori()->GetWidth());
+ aLine.SetBorderLineStyle( aInfoItem->GetHori()->GetBorderLineStyle());
+ }
+ else
+ {
+ if(aCol != aInfoItem->GetHori()->GetColor() )
+ bColDisable = true;
+ if( aLine != *aInfoItem->GetHori() )
+ bStyleDisable = true;
+ }
+ }
+
+ if( !aInfoItem->IsValid( SvxBoxInfoItemValidFlags::VERT )
+ || !aInfoItem->IsValid( SvxBoxInfoItemValidFlags::HORI )
+ || !aInfoItem->IsValid( SvxBoxInfoItemValidFlags::LEFT )
+ || !aInfoItem->IsValid( SvxBoxInfoItemValidFlags::RIGHT )
+ || !aInfoItem->IsValid( SvxBoxInfoItemValidFlags::TOP )
+ || !aInfoItem->IsValid( SvxBoxInfoItemValidFlags::BOTTOM ) )
+ {
+ bColDisable = true;
+ bStyleDisable = true;
+ }
+
+ if(SID_FRAME_LINECOLOR == nWhich)
+ {
+ if(bColDisable) // if different lines have different colors
+ {
+ aCol = COL_TRANSPARENT;
+ rSet.Put( SvxColorItem(aCol, SID_FRAME_LINECOLOR ) );
+ rSet.InvalidateItem(SID_FRAME_LINECOLOR);
+ }
+ else if (!bCol) // if no line available
+ {
+ aCol = COL_AUTO;
+ rSet.Put( SvxColorItem(aCol, SID_FRAME_LINECOLOR ) );
+ }
+ else
+ rSet.Put( SvxColorItem(aCol, SID_FRAME_LINECOLOR ) );
+ }
+ else // if( nWhich == SID_FRAME_LINESTYLE)
+ {
+ if(bStyleDisable) // if have several lines but don't have same style
+ {
+ aLine.SetWidth( 1 );
+ SvxLineItem aItem(SID_FRAME_LINESTYLE);
+ aItem.SetLine(&aLine);
+ rSet.Put( aItem );
+ rSet.InvalidateItem(SID_FRAME_LINESTYLE);
+ }
+ else // all the lines have same style or no line available, use initial value (0,0,0,0)
+ {
+ SvxLineItem aItem(SID_FRAME_LINESTYLE);
+ aItem.SetLine(&aLine);
+ rSet.Put( aItem );
+ }
+ }
+ }
+ break;
+ case SID_ATTR_BRUSH:
+ {
+ rSet.Put( rBrushItem.CloneSetWhich(GetPool().GetWhich(nWhich)) );
+ }
+ break;
+ case SID_SCATTR_CELLPROTECTION:
+ {
+ bool bProtect = rAttrSet.Get( ATTR_PROTECTION ).GetProtection();
+ rSet.Put( SfxBoolItem(SID_SCATTR_CELLPROTECTION, bProtect) );
+ }
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+
+ // stuff for sidebar panels
+ Invalidate(SID_ATTR_ALIGN_DEGREES);
+ Invalidate(SID_ATTR_ALIGN_LOCKPOS);
+ Invalidate(SID_ATTR_ALIGN_STACKED);
+}
+
+void ScFormatShell::GetTextAttrState( SfxItemSet& rSet )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ const SfxItemSet& rAttrSet = pTabViewShell->GetSelectionPattern()->GetItemSet();
+ rSet.Put( rAttrSet, false ); // Include ItemStates in copy
+
+ // choose font info according to selection script type
+ SvtScriptType nScript = SvtScriptType::NONE; // GetSelectionScriptType never returns 0
+ if ( rSet.GetItemState( ATTR_FONT_WEIGHT ) != SfxItemState::UNKNOWN )
+ {
+ nScript = pTabViewShell->GetSelectionScriptType();
+ ScViewUtil::PutItemScript( rSet, rAttrSet, ATTR_FONT_WEIGHT, nScript );
+ }
+ if ( rSet.GetItemState( ATTR_FONT_POSTURE ) != SfxItemState::UNKNOWN )
+ {
+ if (nScript == SvtScriptType::NONE) nScript = pTabViewShell->GetSelectionScriptType();
+ ScViewUtil::PutItemScript( rSet, rAttrSet, ATTR_FONT_POSTURE, nScript );
+ }
+
+ SfxItemState eState;
+
+ // own control on radio button functionality:
+
+ // underline
+
+ eState = rAttrSet.GetItemState( ATTR_FONT_UNDERLINE );
+ if ( eState == SfxItemState::DONTCARE )
+ {
+ rSet.InvalidateItem( SID_ULINE_VAL_NONE );
+ rSet.InvalidateItem( SID_ULINE_VAL_SINGLE );
+ rSet.InvalidateItem( SID_ULINE_VAL_DOUBLE );
+ rSet.InvalidateItem( SID_ULINE_VAL_DOTTED );
+ }
+ else
+ {
+ FontLineStyle eUnderline =
+ rAttrSet.Get(ATTR_FONT_UNDERLINE).GetLineStyle();
+ rSet.Put(SfxBoolItem(SID_ULINE_VAL_SINGLE, eUnderline == LINESTYLE_SINGLE));
+ rSet.Put(SfxBoolItem(SID_ULINE_VAL_DOUBLE, eUnderline == LINESTYLE_DOUBLE));
+ rSet.Put(SfxBoolItem(SID_ULINE_VAL_DOTTED, eUnderline == LINESTYLE_DOTTED));
+ rSet.Put(SfxBoolItem(SID_ULINE_VAL_NONE, eUnderline == LINESTYLE_NONE));
+ }
+
+ // horizontal alignment
+
+ const SvxHorJustifyItem* pHorJustify = nullptr;
+ const SvxVerJustifyItem* pVerJustify = nullptr;
+ SvxCellVerJustify eVerJustify = SvxCellVerJustify::Standard;
+ sal_uInt16 nWhich = 0;
+ bool bJustifyStd = false;
+ SfxBoolItem aBoolItem ( 0, true );
+
+ eState = rAttrSet.GetItemState( ATTR_HOR_JUSTIFY, true,
+ reinterpret_cast<const SfxPoolItem**>(&pHorJustify) );
+ switch ( eState )
+ {
+ case SfxItemState::SET:
+ {
+ switch ( pHorJustify->GetValue() )
+ {
+ case SvxCellHorJustify::Standard:
+ break;
+
+ case SvxCellHorJustify::Left:
+ nWhich = SID_ALIGNLEFT;
+ break;
+
+ case SvxCellHorJustify::Right:
+ nWhich = SID_ALIGNRIGHT;
+ break;
+
+ case SvxCellHorJustify::Center:
+ nWhich = SID_ALIGNCENTERHOR;
+ break;
+
+ case SvxCellHorJustify::Block:
+ nWhich = SID_ALIGNBLOCK;
+ break;
+
+ case SvxCellHorJustify::Repeat:
+ default:
+ bJustifyStd = true;
+ break;
+ }
+ }
+ break;
+
+ case SfxItemState::DONTCARE:
+ rSet.InvalidateItem( SID_ALIGNLEFT );
+ rSet.InvalidateItem( SID_ALIGNRIGHT );
+ rSet.InvalidateItem( SID_ALIGNCENTERHOR );
+ rSet.InvalidateItem( SID_ALIGNBLOCK );
+ break;
+
+ default:
+ bJustifyStd = true;
+ break;
+ }
+
+ if ( nWhich )
+ {
+ aBoolItem.SetWhich( nWhich );
+ rSet.Put( aBoolItem );
+ }
+ else if ( bJustifyStd )
+ {
+ aBoolItem.SetValue( false );
+ aBoolItem.SetWhich( SID_ALIGNLEFT ); rSet.Put( aBoolItem );
+ aBoolItem.SetWhich( SID_ALIGNRIGHT ); rSet.Put( aBoolItem );
+ aBoolItem.SetWhich( SID_ALIGNCENTERHOR ); rSet.Put( aBoolItem );
+ aBoolItem.SetWhich( SID_ALIGNBLOCK ); rSet.Put( aBoolItem );
+ bJustifyStd = false;
+ }
+
+ // vertical alignment
+
+ nWhich = 0;
+ aBoolItem.SetValue( true );
+
+ eState = rAttrSet.GetItemState( ATTR_VER_JUSTIFY, true,
+ reinterpret_cast<const SfxPoolItem**>(&pVerJustify) );
+
+ switch ( eState )
+ {
+ case SfxItemState::SET:
+ {
+ eVerJustify = pVerJustify->GetValue();
+
+ switch ( eVerJustify )
+ {
+ case SvxCellVerJustify::Top:
+ nWhich = SID_ALIGNTOP;
+ break;
+
+ case SvxCellVerJustify::Bottom:
+ nWhich = SID_ALIGNBOTTOM;
+ break;
+
+ case SvxCellVerJustify::Center:
+ nWhich = SID_ALIGNCENTERVER;
+ break;
+
+ case SvxCellVerJustify::Standard:
+ default:
+ bJustifyStd = true;
+ break;
+ }
+ }
+ break;
+
+ case SfxItemState::DONTCARE:
+ rSet.InvalidateItem( SID_ALIGNTOP );
+ rSet.InvalidateItem( SID_ALIGNBOTTOM );
+ rSet.InvalidateItem( SID_ALIGNCENTERVER );
+ break;
+
+ default:
+ bJustifyStd = true;
+ break;
+ }
+
+ if ( nWhich )
+ {
+ aBoolItem.SetWhich( nWhich );
+ rSet.Put( aBoolItem );
+ }
+ else if ( bJustifyStd )
+ {
+ aBoolItem.SetValue( false );
+ aBoolItem.SetWhich( SID_ALIGNTOP ); rSet.Put( aBoolItem );
+ aBoolItem.SetWhich( SID_ALIGNBOTTOM ); rSet.Put( aBoolItem );
+ aBoolItem.SetWhich( SID_ALIGNCENTERVER ); rSet.Put( aBoolItem );
+ }
+}
+
+void ScFormatShell::GetBorderState( SfxItemSet& rSet )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ std::shared_ptr<SvxBoxItem> aBoxItem(std::make_shared<SvxBoxItem>(ATTR_BORDER));
+ std::shared_ptr<SvxBoxInfoItem> aInfoItem(std::make_shared<SvxBoxInfoItem>(ATTR_BORDER_INNER));
+
+ pTabViewShell->GetSelectionFrame( aBoxItem, aInfoItem );
+
+ if ( rSet.GetItemState( ATTR_BORDER ) != SfxItemState::UNKNOWN )
+ rSet.Put( *aBoxItem );
+ if ( rSet.GetItemState( ATTR_BORDER_INNER ) != SfxItemState::UNKNOWN )
+ rSet.Put( *aInfoItem );
+}
+
+void ScFormatShell::GetAlignState( SfxItemSet& rSet )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ const SfxItemSet& rAttrSet = pTabViewShell->GetSelectionPattern()->GetItemSet();
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ SvxCellHorJustify eHAlign = SvxCellHorJustify::Standard;
+ bool bHasHAlign = rAttrSet.GetItemState( ATTR_HOR_JUSTIFY ) != SfxItemState::DONTCARE;
+ if( bHasHAlign )
+ eHAlign = rAttrSet.Get( ATTR_HOR_JUSTIFY ).GetValue();
+
+ SvxCellVerJustify eVAlign = SvxCellVerJustify::Standard;
+ bool bHasVAlign = rAttrSet.GetItemState( ATTR_VER_JUSTIFY ) != SfxItemState::DONTCARE;
+ if( bHasVAlign )
+ eVAlign = rAttrSet.Get( ATTR_VER_JUSTIFY ).GetValue();
+
+ while ( nWhich )
+ {
+ switch ( nWhich )
+ {
+ case SID_H_ALIGNCELL:
+ if ( bHasHAlign )
+ rSet.Put( SvxHorJustifyItem( eHAlign, nWhich ));
+ break;
+ case SID_V_ALIGNCELL:
+ if ( bHasVAlign )
+ rSet.Put( SvxVerJustifyItem( eVAlign, nWhich ));
+ break;
+
+ // pseudo slots for Format menu
+ case SID_ALIGN_ANY_HDEFAULT:
+ case SID_ALIGN_ANY_LEFT:
+ case SID_ALIGN_ANY_HCENTER:
+ case SID_ALIGN_ANY_RIGHT:
+ case SID_ALIGN_ANY_JUSTIFIED:
+ rSet.Put( SfxBoolItem( nWhich, bHasHAlign && (eHAlign == lclConvertSlotToHAlign( nWhich )) ) );
+ break;
+ case SID_ALIGN_ANY_VDEFAULT:
+ case SID_ALIGN_ANY_TOP:
+ case SID_ALIGN_ANY_VCENTER:
+ case SID_ALIGN_ANY_BOTTOM:
+ rSet.Put( SfxBoolItem( nWhich, bHasVAlign && (eVAlign == lclConvertSlotToVAlign( nWhich )) ) );
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void ScFormatShell::GetNumFormatState( SfxItemSet& rSet )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ ScDocument& rDoc = rViewData.GetDocument();
+ const SfxItemSet& rAttrSet = pTabViewShell->GetSelectionPattern()->GetItemSet();
+ const SfxItemState eItemState = rAttrSet.GetItemState( ATTR_VALUE_FORMAT );
+ sal_uInt32 nNumberFormat = rAttrSet.Get(ATTR_VALUE_FORMAT).GetValue();
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ // If item state is default or set it
+ // indicates one number format so we
+ // don't have to iterate over all
+ // selected cells' attribute ranges to
+ // determine selected types.
+ // Does *NOT* include the
+ // SvNumFormatType::DEFINED bit.
+ const SvNumFormatType nType = (eItemState >= SfxItemState::DEFAULT ? pFormatter->GetType( nNumberFormat) :
+ GetCurrentNumberFormatType());
+ NfIndexTableOffset nOffset = pFormatter->GetIndexTableOffset(nNumberFormat);
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ while ( nWhich )
+ {
+ switch ( nWhich )
+ {
+ case SID_NUMBER_THOUSANDS:
+ {
+ bool bEnable = (SfxItemState::DONTCARE != eItemState);
+ if (bEnable)
+ {
+ bEnable = ((nType != SvNumFormatType::ALL) && (nType &
+ (SvNumFormatType::NUMBER |
+ SvNumFormatType::PERCENT |
+ SvNumFormatType::CURRENCY |
+ SvNumFormatType::FRACTION)));
+ if (bEnable)
+ {
+ bool bThousand( false );
+ bool bNegRed( false );
+ sal_uInt16 nPrecision( 0 );
+ sal_uInt16 nLeadZeroes( 0 );
+ pFormatter->GetFormatSpecialInfo( nNumberFormat, bThousand, bNegRed, nPrecision, nLeadZeroes);
+ rSet.Put( SfxBoolItem( nWhich, bThousand));
+ }
+ }
+ if (!bEnable)
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+ case SID_NUMBER_FORMAT:
+ // symphony version with format interpretation
+ {
+ if(SfxItemState::DONTCARE != eItemState)
+ {
+ bool bThousand(false);
+ bool bNegRed(false);
+ sal_uInt16 nPrecision(0);
+ sal_uInt16 nLeadZeroes(0);
+
+ pFormatter->GetFormatSpecialInfo(nNumberFormat,bThousand, bNegRed, nPrecision, nLeadZeroes);
+
+ const SvNumberformat* pFormatEntry = pFormatter->GetEntry( nNumberFormat );
+ if (pFormatEntry && (pFormatEntry->GetType() & SvNumFormatType::SCIENTIFIC))
+ {
+ // if scientific, bThousand is used for engineering notation
+ const sal_uInt16 nIntegerDigits = pFormatEntry->GetFormatIntegerDigits();
+ bThousand = nIntegerDigits > 0 && ((nIntegerDigits % 3) == 0);
+ }
+ OUString aFormat;
+ static constexpr OUStringLiteral sBreak = u",";
+ const OUString sThousand = OUString::number(static_cast<sal_Int32>(bThousand));
+ const OUString sNegRed = OUString::number(static_cast<sal_Int32>(bNegRed));
+ const OUString sPrecision = OUString::number(nPrecision);
+ const OUString sLeadZeroes = OUString::number(nLeadZeroes);
+
+ aFormat += sThousand +
+ sBreak +
+ sNegRed +
+ sBreak +
+ sPrecision +
+ sBreak +
+ sLeadZeroes +
+ sBreak;
+
+ rSet.Put(SfxStringItem(nWhich, aFormat));
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ OUString sPayload = ".uno:NumberFormat=" + aFormat;
+ GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_STATE_CHANGED,
+ OUStringToOString(sPayload, RTL_TEXTENCODING_ASCII_US).getStr());
+ }
+ }
+ else
+ {
+ rSet.InvalidateItem( nWhich );
+ }
+ }
+ break;
+
+ case SID_NUMBER_TYPE_FORMAT:
+ {
+ sal_Int16 nFormatCategory = -1;
+ if ( eItemState >= SfxItemState::DEFAULT ) //Modify for more robust
+ {
+ switch(nType)
+ {
+ case SvNumFormatType::NUMBER:
+ // Determine if General format.
+ if ((nNumberFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
+ nFormatCategory = 0;
+ else
+ nFormatCategory = 1;
+ break;
+ case SvNumFormatType::PERCENT:
+ nFormatCategory = 2;
+ break;
+ case SvNumFormatType::CURRENCY:
+ nFormatCategory = 3;
+ break;
+ case SvNumFormatType::DATE:
+ //Add
+ case SvNumFormatType::DATETIME:
+ nFormatCategory = 4;
+ break;
+ case SvNumFormatType::TIME:
+ nFormatCategory = 5;
+ break;
+ case SvNumFormatType::SCIENTIFIC:
+ nFormatCategory = 6;
+ break;
+ case SvNumFormatType::FRACTION:
+ nFormatCategory = 7;
+ break;
+ case SvNumFormatType::LOGICAL:
+ nFormatCategory = 8;
+ break;
+ case SvNumFormatType::TEXT:
+ nFormatCategory = 9;
+ break;
+ default:
+ nFormatCategory = -1; //for more robust
+ }
+ if( nFormatCategory == -1 )
+ rSet.InvalidateItem( nWhich );
+ else
+ rSet.Put( SfxInt16Item( nWhich, nFormatCategory ) );
+ }
+ else
+ {
+ rSet.InvalidateItem( nWhich );
+ }
+
+ }
+ break;
+ case SID_NUMBER_CURRENCY:
+ rSet.Put( SfxBoolItem(nWhich, bool(nType & SvNumFormatType::CURRENCY)) );
+ break;
+ case SID_NUMBER_SCIENTIFIC:
+ rSet.Put( SfxBoolItem(nWhich, bool(nType & SvNumFormatType::SCIENTIFIC)) );
+ break;
+ case SID_NUMBER_DATE:
+ rSet.Put( SfxBoolItem(nWhich, bool(nType & SvNumFormatType::DATE)) );
+ break;
+ case SID_NUMBER_PERCENT:
+ rSet.Put( SfxBoolItem(nWhich, bool(nType & SvNumFormatType::PERCENT)) );
+ break;
+ case SID_NUMBER_TIME:
+ rSet.Put( SfxBoolItem(nWhich, bool(nType & SvNumFormatType::TIME)) );
+ break;
+ case SID_NUMBER_TWODEC:
+ rSet.Put( SfxBoolItem(nWhich, (nType & SvNumFormatType::NUMBER) && nOffset == NF_NUMBER_1000DEC2 ) );
+ break;
+ case SID_NUMBER_STANDARD:
+ rSet.Put( SfxBoolItem(nWhich, (nType & SvNumFormatType::NUMBER) && (nNumberFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0) );
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void ScFormatShell::ExecuteTextDirection( const SfxRequest& rReq )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ pTabViewShell->HideListBox(); // Autofilter-DropDown-Listbox
+ bool bEditMode = false;
+ if ( GetViewData().HasEditView( GetViewData().GetActivePart() ) )
+ {
+ bEditMode=true;
+ SC_MOD()->InputEnterHandler();
+ pTabViewShell->UpdateInputHandler();
+ }
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch( nSlot )
+ {
+ case SID_TEXTDIRECTION_LEFT_TO_RIGHT:
+ case SID_TEXTDIRECTION_TOP_TO_BOTTOM:
+ {
+ bool bVert = (nSlot == SID_TEXTDIRECTION_TOP_TO_BOTTOM);
+ ScPatternAttr aAttr( GetViewData().GetDocument().GetPool() );
+ SfxItemSet& rItemSet = aAttr.GetItemSet();
+ rItemSet.Put( ScVerticalStackCell( bVert ) );
+ rItemSet.Put( SfxBoolItem( ATTR_VERTICAL_ASIAN, bVert ) );
+ pTabViewShell->ApplySelectionPattern( aAttr );
+ pTabViewShell->AdjustBlockHeight();
+ }
+ break;
+
+ case SID_ATTR_PARA_LEFT_TO_RIGHT:
+ case SID_ATTR_PARA_RIGHT_TO_LEFT:
+ {
+ SvxFrameDirection eDirection = ( nSlot == SID_ATTR_PARA_LEFT_TO_RIGHT ) ?
+ SvxFrameDirection::Horizontal_LR_TB : SvxFrameDirection::Horizontal_RL_TB;
+ pTabViewShell->ApplyAttr( SvxFrameDirectionItem( eDirection, ATTR_WRITINGDIR ) );
+ }
+ break;
+ }
+ if (bEditMode)
+ SC_MOD()->SetInputMode( SC_INPUT_TABLE );
+}
+
+void ScFormatShell::GetTextDirectionState( SfxItemSet& rSet )
+{
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ const SfxItemSet& rAttrSet = pTabViewShell->GetSelectionPattern()->GetItemSet();
+
+ bool bVertDontCare =
+ (rAttrSet.GetItemState( ATTR_VERTICAL_ASIAN ) == SfxItemState::DONTCARE) ||
+ (rAttrSet.GetItemState( ATTR_STACKED ) == SfxItemState::DONTCARE);
+ bool bLeftRight = !bVertDontCare &&
+ !rAttrSet.Get( ATTR_STACKED ).GetValue();
+ bool bTopBottom = !bVertDontCare && !bLeftRight &&
+ rAttrSet.Get( ATTR_VERTICAL_ASIAN ).GetValue();
+
+ bool bBidiDontCare = (rAttrSet.GetItemState( ATTR_WRITINGDIR ) == SfxItemState::DONTCARE);
+ EEHorizontalTextDirection eBidiDir = EEHorizontalTextDirection::Default;
+ if ( !bBidiDontCare )
+ {
+ SvxFrameDirection eCellDir = rAttrSet.Get( ATTR_WRITINGDIR ).GetValue();
+ if ( eCellDir == SvxFrameDirection::Environment )
+ eBidiDir = GetViewData().GetDocument().
+ GetEditTextDirection( GetViewData().GetTabNo() );
+ else if ( eCellDir == SvxFrameDirection::Horizontal_RL_TB )
+ eBidiDir = EEHorizontalTextDirection::R2L;
+ else
+ eBidiDir = EEHorizontalTextDirection::L2R;
+ }
+
+ bool bDisableCTLFont = !SvtCTLOptions().IsCTLFontEnabled();
+ bool bDisableVerticalText = !SvtCJKOptions::IsVerticalTextEnabled();
+
+ SfxWhichIter aIter( rSet );
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while( nWhich )
+ {
+ switch( nWhich )
+ {
+ case SID_TEXTDIRECTION_LEFT_TO_RIGHT:
+ case SID_TEXTDIRECTION_TOP_TO_BOTTOM:
+ if ( bDisableVerticalText )
+ rSet.DisableItem( nWhich );
+ else
+ {
+ if( bVertDontCare )
+ rSet.InvalidateItem( nWhich );
+ else if ( nWhich == SID_TEXTDIRECTION_LEFT_TO_RIGHT )
+ rSet.Put( SfxBoolItem( nWhich, bLeftRight ) );
+ else
+ rSet.Put( SfxBoolItem( nWhich, bTopBottom ) );
+ }
+ break;
+
+ case SID_ATTR_PARA_LEFT_TO_RIGHT:
+ case SID_ATTR_PARA_RIGHT_TO_LEFT:
+ if ( bDisableCTLFont )
+ rSet.DisableItem( nWhich );
+ else
+ {
+ if ( bTopBottom )
+ rSet.DisableItem( nWhich );
+ else if ( bBidiDontCare )
+ rSet.InvalidateItem( nWhich );
+ else if ( nWhich == SID_ATTR_PARA_LEFT_TO_RIGHT )
+ rSet.Put( SfxBoolItem( nWhich, eBidiDir == EEHorizontalTextDirection::L2R ) );
+ else
+ rSet.Put( SfxBoolItem( nWhich, eBidiDir == EEHorizontalTextDirection::R2L ) );
+ }
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void ScFormatShell::ExecFormatPaintbrush( const SfxRequest& rReq )
+{
+ ScViewFunc* pView = rViewData.GetView();
+ if ( pView->HasPaintBrush() )
+ {
+ // cancel paintbrush mode
+ pView->ResetBrushDocument();
+ }
+ else
+ {
+ bool bLock = false;
+ const SfxItemSet *pArgs = rReq.GetArgs();
+ if( pArgs && pArgs->Count() >= 1 )
+ bLock = pArgs->Get(SID_FORMATPAINTBRUSH).GetValue();
+
+ // in case of multi selection, deselect all and use the cursor position
+ ScRange aDummy;
+ if ( rViewData.GetSimpleArea(aDummy) != SC_MARK_SIMPLE )
+ pView->Unmark();
+
+ ScDocumentUniquePtr pBrushDoc(new ScDocument( SCDOCMODE_CLIP ));
+ pView->CopyToClip( pBrushDoc.get(), false, true );
+ pView->SetBrushDocument( std::move(pBrushDoc), bLock );
+ }
+}
+
+void ScFormatShell::StateFormatPaintbrush( SfxItemSet& rSet )
+{
+ if ( rViewData.HasEditView( rViewData.GetActivePart() ) )
+ rSet.DisableItem( SID_FORMATPAINTBRUSH );
+ else
+ rSet.Put( SfxBoolItem( SID_FORMATPAINTBRUSH, rViewData.GetView()->HasPaintBrush() ) );
+}
+
+SvNumFormatType ScFormatShell::GetCurrentNumberFormatType()
+{
+ SvNumFormatType nType = SvNumFormatType::ALL;
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScMarkData aMark(GetViewData().GetMarkData());
+ const SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ if (!pFormatter)
+ return nType;
+
+ // TODO: Find out how to get a selected table range in case multiple tables
+ // are selected. Currently we only check for the current active table.
+
+ if ( aMark.IsMarked() || aMark.IsMultiMarked() )
+ {
+ aMark.MarkToMulti();
+ const ScRange& aRange = aMark.GetMultiMarkArea();
+ const ScMultiSel& rMultiSel = aMark.GetMultiSelData();
+
+ SvNumFormatType nComboType = SvNumFormatType::ALL;
+ bool bFirstItem = true;
+ for (SCCOL nCol = aRange.aStart.Col(); nCol <= aRange.aEnd.Col(); ++nCol)
+ {
+ if (!rMultiSel.HasMarks(nCol))
+ continue;
+
+ SCROW nRow1, nRow2;
+ ScMultiSelIter aMultiIter(rMultiSel, nCol);
+ while (aMultiIter.Next(nRow1, nRow2))
+ {
+ ScRange aColRange(nCol, nRow1, aRange.aStart.Tab());
+ aColRange.aEnd.SetRow(nRow2);
+ sal_uInt32 nNumFmt = rDoc.GetNumberFormat(aColRange);
+ SvNumFormatType nThisType = pFormatter->GetType(nNumFmt);
+ if (bFirstItem)
+ {
+ bFirstItem = false;
+ nComboType = nThisType;
+ }
+ else if (nComboType != nThisType)
+ // mixed number format type.
+ return SvNumFormatType::ALL;
+ }
+ }
+ nType = nComboType;
+ }
+ else
+ {
+ sal_uInt32 nNumFmt = rDoc.GetNumberFormat( rViewData.GetCurX(), rViewData.GetCurY(),
+ rViewData.GetTabNo());
+ nType = pFormatter->GetType( nNumFmt );
+ }
+ return nType;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/gridmerg.cxx b/sc/source/ui/view/gridmerg.cxx
new file mode 100644
index 000000000..a21be85fc
--- /dev/null
+++ b/sc/source/ui/view/gridmerg.cxx
@@ -0,0 +1,227 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <vcl/lineinfo.hxx>
+#include <vcl/outdev.hxx>
+
+#include <gridmerg.hxx>
+
+#define PAGEBREAK_LINE_DISTANCE_PIXEL 5
+#define PAGEBREAK_LINE_DASH_LEN_PIXEL 5
+#define PAGEBREAK_LINE_DASH_COUNT 1
+
+ScGridMerger::ScGridMerger( OutputDevice* pOutDev, tools::Long nOnePixelX, tools::Long nOnePixelY )
+ : pDev(pOutDev)
+ , nOneX(nOnePixelX)
+ , nOneY(nOnePixelY)
+ , nFixStart(0)
+ , nFixEnd(0)
+ , nVarStart(0)
+ , nVarDiff(0)
+ , nCount(0)
+ , bVertical(false)
+{
+ // optimize (DrawGrid) only for pixel MapMode,
+ // to avoid rounding errors
+
+ bOptimize = ( pDev->GetMapMode().GetMapUnit() == MapUnit::MapPixel );
+}
+
+ScGridMerger::~ScGridMerger()
+{
+ Flush();
+}
+
+void ScGridMerger::AddLine( tools::Long nStart, tools::Long nEnd, tools::Long nPos )
+{
+ if ( nCount )
+ {
+ // not first line - test fix position
+ // more than one previous line - test distance
+
+ if ( nStart != nFixStart || nEnd != nFixEnd )
+ {
+ if ( nCount == 1 && nPos == nVarStart &&
+ ( nStart == nFixEnd ||
+ nStart == nFixEnd + ( bVertical ? nOneY : nOneX ) ) )
+ {
+ // additional optimization: extend connected lines
+ // keep nCount at 1
+ nFixEnd = nEnd;
+ }
+ else
+ Flush();
+ }
+ else if ( nCount == 1 )
+ {
+ nVarDiff = nPos - nVarStart;
+ ++nCount;
+ }
+ else if ( nPos != nVarStart + nCount * nVarDiff ) //! keep VarEnd?
+ Flush();
+ else
+ ++nCount;
+ }
+
+ if ( !nCount )
+ {
+ // first line (or flushed above) - just store
+
+ nFixStart = nStart;
+ nFixEnd = nEnd;
+ nVarStart = nPos;
+ nVarDiff = 0;
+ nCount = 1;
+ }
+}
+
+void ScGridMerger::AddHorLine(bool bWorksInPixels, tools::Long nX1, tools::Long nX2, tools::Long nY, bool bDashed)
+{
+ if ( bWorksInPixels )
+ {
+ Point aPoint(pDev->PixelToLogic(Point(nX1, nY)));
+ nX1 = aPoint.X();
+ nY = aPoint.Y();
+ nX2 = pDev->PixelToLogic(Point(nX2, 0)).X();
+ }
+
+ if ( bDashed )
+ {
+ // If there are some unflushed lines they must be flushed since
+ // new line is of different style
+ if (bOptimize) {
+ Flush();
+ bVertical = false;
+ }
+
+ LineInfo aLineInfo(LineStyle::Dash, 1);
+ aLineInfo.SetDashCount( PAGEBREAK_LINE_DASH_COUNT );
+
+ // Calculating logic values of DashLen and Distance from fixed pixel values
+ Size aDashDistanceLen( pDev->PixelToLogic( Size( PAGEBREAK_LINE_DISTANCE_PIXEL,
+ PAGEBREAK_LINE_DASH_LEN_PIXEL )));
+
+ aLineInfo.SetDistance( aDashDistanceLen.Width() );
+ aLineInfo.SetDashLen( aDashDistanceLen.Height() );
+
+ pDev->DrawLine( Point( nX1, nY ), Point( nX2, nY ), aLineInfo );
+ }
+ else if ( bOptimize )
+ {
+ if ( bVertical )
+ {
+ Flush();
+ bVertical = false;
+ }
+ AddLine( nX1, nX2, nY );
+ }
+ else
+ pDev->DrawLine( Point( nX1, nY ), Point( nX2, nY ) );
+}
+
+void ScGridMerger::AddVerLine(bool bWorksInPixels, tools::Long nX, tools::Long nY1, tools::Long nY2, bool bDashed)
+{
+ if (bWorksInPixels)
+ {
+ Point aPoint(pDev->PixelToLogic(Point(nX, nY1)));
+ nX = aPoint.X();
+ nY1 = aPoint.Y();
+ nY2 = pDev->PixelToLogic(Point(0, nY2)).Y();
+ }
+
+ if ( bDashed )
+ {
+ // If there are some unflushed lines they must be flushed since
+ // new line is of different style
+ if (bOptimize) {
+ Flush();
+ bVertical = false;
+ }
+
+ LineInfo aLineInfo(LineStyle::Dash, 1);
+ aLineInfo.SetDashCount( PAGEBREAK_LINE_DASH_COUNT );
+
+ // Calculating logic values of DashLen and Distance from fixed pixel values
+ Size aDashDistanceLen( pDev->PixelToLogic( Size( PAGEBREAK_LINE_DISTANCE_PIXEL,
+ PAGEBREAK_LINE_DASH_LEN_PIXEL )));
+
+ aLineInfo.SetDistance( aDashDistanceLen.Width() );
+ aLineInfo.SetDashLen( aDashDistanceLen.Height() );
+
+ pDev->DrawLine( Point( nX, nY1 ), Point( nX, nY2 ), aLineInfo);
+ }
+ else if ( bOptimize )
+ {
+ if ( !bVertical )
+ {
+ Flush();
+ bVertical = true;
+ }
+ AddLine( nY1, nY2, nX );
+ }
+ else
+ pDev->DrawLine( Point( nX, nY1 ), Point( nX, nY2 ) );
+}
+
+void ScGridMerger::Flush()
+{
+ if (!nCount)
+ return;
+
+ if (bVertical)
+ {
+ if ( nCount == 1 )
+ pDev->DrawLine( Point( nVarStart, nFixStart ), Point( nVarStart, nFixEnd ) );
+ else
+ {
+ tools::Long nVarEnd = nVarStart + ( nCount - 1 ) * nVarDiff;
+ if ( nVarDiff < 0 )
+ {
+ // nVarDiff is negative in RTL layout mode
+ // Change the positions so DrawGrid is called with a positive distance
+ // (nVarStart / nVarDiff can be modified, aren't used after Flush)
+
+ nVarDiff = -nVarDiff;
+ tools::Long nTemp = nVarStart;
+ nVarStart = nVarEnd;
+ nVarEnd = nTemp;
+ }
+ pDev->DrawGrid( tools::Rectangle( nVarStart, nFixStart, nVarEnd, nFixEnd ),
+ Size( nVarDiff, nFixEnd - nFixStart ),
+ DrawGridFlags::VertLines );
+ }
+ }
+ else
+ {
+ if ( nCount == 1 )
+ pDev->DrawLine( Point( nFixStart, nVarStart ), Point( nFixEnd, nVarStart ) );
+ else
+ {
+ tools::Long nVarEnd = nVarStart + ( nCount - 1 ) * nVarDiff;
+ pDev->DrawGrid( tools::Rectangle( nFixStart, nVarStart, nFixEnd, nVarEnd ),
+ Size( nFixEnd - nFixStart, nVarDiff ),
+ DrawGridFlags::HorzLines );
+ }
+ }
+ nCount = 0;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
new file mode 100644
index 000000000..0c471e4c5
--- /dev/null
+++ b/sc/source/ui/view/gridwin.cxx
@@ -0,0 +1,7094 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+
+#include <cstdlib>
+#include <memory>
+#include <editeng/adjustitem.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <sot/storage.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/misspellrange.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/ipclient.hxx>
+#include <svl/stritem.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <vcl/canvastools.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/dialoghelper.hxx>
+#include <vcl/inputctx.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/weldutils.hxx>
+#include <sot/formats.hxx>
+#include <comphelper/classids.hxx>
+
+#include <svx/svdview.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdpagv.hxx>
+#include <svtools/optionsdrawinglayer.hxx>
+
+#include <com/sun/star/sheet/DataPilotFieldFilter.hpp>
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+#include <com/sun/star/sheet/DataPilotTableHeaderData.hpp>
+#include <com/sun/star/sheet/MemberResultFlags.hpp>
+#include <com/sun/star/sheet/TableValidationVisibility.hpp>
+#include <com/sun/star/awt/KeyModifier.hpp>
+#include <com/sun/star/awt/MouseButton.hpp>
+#include <com/sun/star/script/vba/VBAEventId.hpp>
+#include <com/sun/star/script/vba/XVBAEventProcessor.hpp>
+#include <com/sun/star/text/textfield/Type.hpp>
+
+#include <gridwin.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <viewdata.hxx>
+#include <tabview.hxx>
+#include <select.hxx>
+#include <scmod.hxx>
+#include <document.hxx>
+#include <attrib.hxx>
+#include <dbdata.hxx>
+#include <stlpool.hxx>
+#include <printfun.hxx>
+#include <cbutton.hxx>
+#include <sc.hrc>
+#include <helpids.h>
+#include <globstr.hrc>
+#include <strings.hrc>
+#include <editutil.hxx>
+#include <scresid.hxx>
+#include <inputhdl.hxx>
+#include <uiitems.hxx>
+#include <formulacell.hxx>
+#include <patattr.hxx>
+#include <notemark.hxx>
+#include <rfindlst.hxx>
+#include <output.hxx>
+#include <docfunc.hxx>
+#include <dbdocfun.hxx>
+#include <dpobject.hxx>
+#include <transobj.hxx>
+#include <drwtrans.hxx>
+#include <seltrans.hxx>
+#include <sizedev.hxx>
+#include <AccessibilityHints.hxx>
+#include <dpsave.hxx>
+#include <viewuno.hxx>
+#include <compiler.hxx>
+#include <editable.hxx>
+#include <fillinfo.hxx>
+#include <filterentries.hxx>
+#include <drwlayer.hxx>
+#include <validat.hxx>
+#include <tabprotection.hxx>
+#include <postit.hxx>
+#include <dpcontrol.hxx>
+#include <checklistmenu.hxx>
+#include <clipparam.hxx>
+#include <overlayobject.hxx>
+#include <cellsuno.hxx>
+#include <drawview.hxx>
+#include <dragdata.hxx>
+#include <cliputil.hxx>
+#include <queryentry.hxx>
+#include <markdata.hxx>
+#include <externalrefmgr.hxx>
+#include <spellcheckcontext.hxx>
+#include <uiobject.hxx>
+#include <undoblk.hxx>
+#include <datamapper.hxx>
+#include <inputopt.hxx>
+#include <queryparam.hxx>
+#include <SparklineList.hxx>
+
+#include <officecfg/Office/Common.hxx>
+
+#include <svx/PaletteManager.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+#include <svx/sdr/overlay/overlayselection.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/lokhelper.hxx>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+#include <vector>
+#include <boost/property_tree/json_parser.hpp>
+
+#include <FilterListBox.hxx>
+
+using namespace css;
+using namespace css::uno;
+
+struct ScGridWindow::MouseEventState
+{
+ bool mbActivatePart;
+
+ MouseEventState() :
+ mbActivatePart(false)
+ {}
+};
+
+#define SC_FILTERLISTBOX_LINES 12
+
+ScGridWindow::VisibleRange::VisibleRange(const ScDocument& rDoc)
+ : mnCol1(0)
+ , mnCol2(rDoc.MaxCol())
+ , mnRow1(0)
+ , mnRow2(rDoc.MaxRow())
+{
+}
+
+bool ScGridWindow::VisibleRange::isInside(SCCOL nCol, SCROW nRow) const
+{
+ return mnCol1 <= nCol && nCol <= mnCol2 && mnRow1 <= nRow && nRow <= mnRow2;
+}
+
+bool ScGridWindow::VisibleRange::set(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2)
+{
+ bool bChanged = mnCol1 != nCol1 || mnRow1 != nRow1 || mnCol2 != nCol2 || mnRow2 != nRow2;
+
+ mnCol1 = nCol1;
+ mnRow1 = nRow1;
+ mnCol2 = nCol2;
+ mnRow2 = nRow2;
+
+ return bChanged;
+}
+
+// ListBox in a FloatingWindow (pParent)
+ScFilterListBox::ScFilterListBox(weld::Window* pParent, ScGridWindow* pGrid,
+ SCCOL nNewCol, SCROW nNewRow, ScFilterBoxMode eNewMode)
+ : xBuilder(Application::CreateBuilder(pParent, "modules/scalc/ui/filterlist.ui"))
+ , xPopover(xBuilder->weld_popover("FilterList"))
+ , xTreeView(xBuilder->weld_tree_view("list"))
+ , pGridWin(pGrid)
+ , nCol(nNewCol)
+ , nRow(nNewRow)
+ , bInit(true)
+ , bCancelled(false)
+ , bGridHadMouseCaptured(pGrid->IsMouseCaptured())
+ , nSel(0)
+ , eMode(eNewMode)
+ , nAsyncSelectHdl(nullptr)
+{
+ xTreeView->connect_row_activated(LINK(this, ScFilterListBox, SelectHdl));
+ xTreeView->connect_key_press(LINK(this, ScFilterListBox, KeyInputHdl));
+}
+
+ScFilterListBox::~ScFilterListBox()
+{
+ if (nAsyncSelectHdl)
+ {
+ Application::RemoveUserEvent(nAsyncSelectHdl);
+ nAsyncSelectHdl = nullptr;
+ }
+}
+
+void ScFilterListBox::EndInit()
+{
+ sal_Int32 nPos = xTreeView->get_selected_index();
+ if (nPos == -1)
+ nSel = 0;
+ else
+ nSel = nPos;
+
+ bInit = false;
+}
+
+IMPL_LINK(ScFilterListBox, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
+{
+ bool bDone = false;
+
+ vcl::KeyCode aCode = rKeyEvent.GetKeyCode();
+ // esc with no modifiers
+ if (!aCode.GetModifier() && aCode.GetCode() == KEY_ESCAPE)
+ {
+ pGridWin->ClickExtern(); // clears the listbox
+ bDone = true;
+ }
+
+ // nowhere to tab to
+ if (aCode.GetCode() == KEY_TAB)
+ bDone = true;
+
+ return bDone;
+}
+
+IMPL_LINK_NOARG(ScFilterListBox, SelectHdl, weld::TreeView&, bool)
+{
+ if (!bInit && !bCancelled && !nAsyncSelectHdl)
+ {
+ int nPos = xTreeView->get_selected_index();
+ if (nPos != -1)
+ {
+ nSel = nPos;
+ // #i81298# launch async so the box isn't deleted from modifications within FilterSelect
+ nAsyncSelectHdl = Application::PostUserEvent(LINK(this, ScFilterListBox, AsyncSelectHdl));
+ }
+ }
+ return true;
+}
+
+IMPL_LINK_NOARG(ScFilterListBox, AsyncSelectHdl, void*, void)
+{
+ nAsyncSelectHdl = nullptr;
+
+ //tdf#133971 hold self-ref until we return
+ auto xThis(shared_from_this());
+ pGridWin->FilterSelect(nSel);
+ if (xThis.use_count() == 1)
+ {
+ // tdf#133855 we got disposed by FilterSelect
+ return;
+ }
+ pGridWin->ClickExtern();
+}
+
+static bool lcl_IsEditableMatrix( ScDocument& rDoc, const ScRange& rRange )
+{
+ // If it is an editable range and if there is a Matrix cell at the bottom right with an
+ // origin top left then the range will be set to contain the exact matrix.
+ //! Extract the MatrixEdges functions directly from the column ???
+ if ( !rDoc.IsBlockEditable( rRange.aStart.Tab(), rRange.aStart.Col(),rRange.aStart.Row(),
+ rRange.aEnd.Col(),rRange.aEnd.Row() ) )
+ return false;
+
+ ScRefCellValue aCell(rDoc, rRange.aEnd);
+ ScAddress aPos;
+ return (aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->GetMatrixOrigin(rDoc, aPos) && aPos == rRange.aStart);
+}
+
+static void lcl_UnLockComment( ScDrawView* pView, const Point& rPos, const ScViewData& rViewData )
+{
+ if (!pView)
+ return;
+
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScAddress aCellPos( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
+ ScPostIt* pNote = rDoc.GetNote( aCellPos );
+ SdrObject* pObj = pNote ? pNote->GetCaption() : nullptr;
+ if( pObj && pObj->GetLogicRect().Contains( rPos ) && ScDrawLayer::IsNoteCaption( pObj ) )
+ {
+ const ScProtectionAttr* pProtAttr = rDoc.GetAttr( aCellPos, ATTR_PROTECTION );
+ bool bProtectAttr = pProtAttr->GetProtection() || pProtAttr->GetHideCell() ;
+ bool bProtectDoc = rDoc.IsTabProtected( aCellPos.Tab() ) || rViewData.GetSfxDocShell()->IsReadOnly() ;
+ // unlock internal layer (if not protected), will be relocked in ScDrawView::MarkListHasChanged()
+ pView->LockInternalLayer( bProtectDoc && bProtectAttr );
+ }
+}
+
+static bool lcl_GetHyperlinkCell(
+ ScDocument& rDoc, SCCOL& rPosX, SCROW nPosY, SCTAB nTab, ScRefCellValue& rCell, OUString& rURL )
+{
+ bool bFound = false;
+ do
+ {
+ ScAddress aPos(rPosX, nPosY, nTab);
+ rCell.assign(rDoc, aPos);
+ if (rCell.isEmpty())
+ {
+ if ( rPosX <= 0 )
+ return false; // everything empty to the links
+ else
+ --rPosX; // continue search
+ }
+ else
+ {
+ const ScPatternAttr* pPattern = rDoc.GetPattern(aPos);
+ if ( !pPattern->GetItem(ATTR_HYPERLINK).GetValue().isEmpty() )
+ {
+ rURL = pPattern->GetItem(ATTR_HYPERLINK).GetValue();
+ bFound = true;
+ }
+ else if (rCell.meType == CELLTYPE_EDIT)
+ bFound = true;
+ else if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->IsHyperLinkCell())
+ bFound = true;
+ else
+ return false; // other cell
+ }
+ }
+ while ( !bFound );
+
+ return bFound;
+}
+
+// WB_DIALOGCONTROL needed for UNO-Controls
+ScGridWindow::ScGridWindow( vcl::Window* pParent, ScViewData& rData, ScSplitPos eWhichPos )
+: Window( pParent, WB_CLIPCHILDREN | WB_DIALOGCONTROL ),
+ DropTargetHelper( this ),
+ DragSourceHelper( this ),
+ maVisibleRange(rData.GetDocument()),
+ mrViewData( rData ),
+ eWhich( eWhichPos ),
+ nCursorHideCount( 0 ),
+ nButtonDown( 0 ),
+ nMouseStatus( SC_GM_NONE ),
+ nNestedButtonState( ScNestedButtonState::NONE ),
+ nDPField( 0 ),
+ pDragDPObj( nullptr ),
+ nRFIndex( 0 ),
+ nRFAddX( 0 ),
+ nRFAddY( 0 ),
+ nPagebreakMouse( SC_PD_NONE ),
+ nPagebreakBreak( 0 ),
+ nPagebreakPrev( 0 ),
+ nPageScript( SvtScriptType::NONE ),
+ nDragStartX( -1 ),
+ nDragStartY( -1 ),
+ nDragEndX( -1 ),
+ nDragEndY( -1 ),
+ meDragInsertMode( INS_NONE ),
+ aComboButton( GetOutDev() ),
+ aCurMousePos( 0,0 ),
+ nPaintCount( 0 ),
+ aRFSelectedCorned( NONE ),
+ maShowPageBreaksTimer("ScGridWindow maShowPageBreaksTimer"),
+ bEEMouse( false ),
+ bDPMouse( false ),
+ bRFMouse( false ),
+ bRFSize( false ),
+ bPagebreakDrawn( false ),
+ bDragRect( false ),
+ bIsInPaint( false ),
+ bNeedsRepaint( false ),
+ bAutoMarkVisible( false ),
+ bListValButton( false )
+{
+ set_id("grid_window");
+ switch(eWhich)
+ {
+ case SC_SPLIT_TOPLEFT:
+ eHWhich = SC_SPLIT_LEFT;
+ eVWhich = SC_SPLIT_TOP;
+ break;
+ case SC_SPLIT_TOPRIGHT:
+ eHWhich = SC_SPLIT_RIGHT;
+ eVWhich = SC_SPLIT_TOP;
+ break;
+ case SC_SPLIT_BOTTOMLEFT:
+ eHWhich = SC_SPLIT_LEFT;
+ eVWhich = SC_SPLIT_BOTTOM;
+ break;
+ case SC_SPLIT_BOTTOMRIGHT:
+ eHWhich = SC_SPLIT_RIGHT;
+ eVWhich = SC_SPLIT_BOTTOM;
+ break;
+ default:
+ OSL_FAIL("GridWindow: wrong position");
+ }
+
+ SetUseFrameData(comphelper::LibreOfficeKit::isActive());
+ SetBackground();
+
+ SetMapMode(mrViewData.GetLogicMode(eWhich));
+ EnableChildTransparentMode();
+ SetDialogControlFlags( DialogControlFlags::Return | DialogControlFlags::WantFocus );
+
+ SetHelpId( HID_SC_WIN_GRIDWIN );
+
+ GetOutDev()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
+ EnableRTL( false );
+
+ bInitialPageBreaks = true;
+ maShowPageBreaksTimer.SetInvokeHandler(LINK(this, ScGridWindow, InitiatePageBreaksTimer));
+ maShowPageBreaksTimer.SetTimeout(1);
+}
+
+ScGridWindow::~ScGridWindow()
+{
+ disposeOnce();
+}
+
+void ScGridWindow::dispose()
+{
+ maShowPageBreaksTimer.Stop();
+
+ ImpDestroyOverlayObjects();
+
+ mpFilterBox.reset();
+ mpNoteMarker.reset();
+ mpAutoFilterPopup.reset();
+ mpDPFieldPopup.reset();
+ aComboButton.SetOutputDevice(nullptr);
+
+ if (mpSpellCheckCxt)
+ mpSpellCheckCxt->reset();
+ mpSpellCheckCxt.reset();
+
+ vcl::Window::dispose();
+}
+
+void ScGridWindow::ClickExtern()
+{
+ do
+ {
+ // #i84277# when initializing the filter box, a Basic error can deactivate the view
+ if (mpFilterBox && mpFilterBox->IsInInit())
+ break;
+ mpFilterBox.reset();
+ }
+ while (false);
+
+ if (mpDPFieldPopup)
+ {
+ mpDPFieldPopup->close(false);
+ mpDPFieldPopup.reset();
+ }
+}
+
+IMPL_LINK_NOARG(ScGridWindow, PopupModeEndHdl, weld::Popover&, void)
+{
+ if (mpFilterBox)
+ {
+ bool bMouseWasCaptured = mpFilterBox->MouseWasCaptured();
+ mpFilterBox->SetCancelled(); // cancel select
+ // restore the mouse capture state of the GridWindow to
+ // what it was at initial popup time
+ SAL_WARN_IF(bMouseWasCaptured, "sc.ui", "Is there a scenario where the mouse was captured before mouse down?");
+ if (bMouseWasCaptured)
+ CaptureMouse();
+ }
+ GrabFocus();
+}
+
+IMPL_LINK( ScGridWindow, PopupSpellingHdl, SpellCallbackInfo&, rInfo, void )
+{
+ if( rInfo.nCommand == SpellCallbackCommand::STARTSPELLDLG )
+ mrViewData.GetDispatcher().Execute( SID_SPELL_DIALOG, SfxCallMode::ASYNCHRON );
+ else if (rInfo.nCommand == SpellCallbackCommand::AUTOCORRECT_OPTIONS)
+ mrViewData.GetDispatcher().Execute( SID_AUTO_CORRECT_DLG, SfxCallMode::ASYNCHRON );
+ else //IGNOREWORD, ADDTODICTIONARY, WORDLANGUAGE, PARALANGUAGE
+ {
+ // The spelling status of the word has changed. Close the cell to reset the caches
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl(mrViewData.GetViewShell());
+ if (pHdl)
+ pHdl->EnterHandler();
+ }
+}
+
+namespace {
+
+struct AutoFilterData : public ScCheckListMenuControl::ExtendedData
+{
+ ScAddress maPos;
+ ScDBData* mpData;
+};
+
+class AutoFilterAction : public ScCheckListMenuControl::Action
+{
+protected:
+ VclPtr<ScGridWindow> mpWindow;
+ ScGridWindow::AutoFilterMode meMode;
+public:
+ AutoFilterAction(ScGridWindow* p, ScGridWindow::AutoFilterMode eMode) :
+ mpWindow(p), meMode(eMode) {}
+ virtual bool execute() override
+ {
+ mpWindow->UpdateAutoFilterFromMenu(meMode);
+ // UpdateAutoFilterFromMenu manually closes the popup so return
+ // false to not attempt a second close
+ return false;
+ }
+};
+
+class AutoFilterPopupEndAction : public ScCheckListMenuControl::Action
+{
+ VclPtr<ScGridWindow> mpWindow;
+ ScAddress maPos;
+public:
+ AutoFilterPopupEndAction(ScGridWindow* p, const ScAddress& rPos) :
+ mpWindow(p), maPos(rPos) {}
+ virtual bool execute() override
+ {
+ mpWindow->RefreshAutoFilterButton(maPos);
+ mpWindow->GrabFocus();
+ return false; // this is called after the popup has been closed
+ }
+};
+
+class AutoFilterSubMenuAction : public AutoFilterAction
+{
+protected:
+ ScListSubMenuControl* m_pSubMenu;
+
+public:
+ AutoFilterSubMenuAction(ScGridWindow* p, ScListSubMenuControl* pSubMenu, ScGridWindow::AutoFilterMode eMode)
+ : AutoFilterAction(p, eMode)
+ , m_pSubMenu(pSubMenu)
+ {
+ }
+};
+
+class AutoFilterColorAction : public AutoFilterSubMenuAction
+{
+private:
+ Color m_aColor;
+
+public:
+ AutoFilterColorAction(ScGridWindow* p, ScListSubMenuControl* pSubMenu, ScGridWindow::AutoFilterMode eMode, const Color& rColor)
+ : AutoFilterSubMenuAction(p, pSubMenu, eMode)
+ , m_aColor(rColor)
+ {
+ }
+
+ virtual bool execute() override
+ {
+ const AutoFilterData* pData =
+ static_cast<const AutoFilterData*>(m_pSubMenu->getExtendedData());
+
+ if (!pData)
+ return false;
+
+ ScDBData* pDBData = pData->mpData;
+ if (!pDBData)
+ return false;
+
+ const ScAddress& rPos = pData->maPos;
+
+ ScViewData& rViewData = m_pSubMenu->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+
+ ScQueryParam aParam;
+ pDBData->GetQueryParam(aParam);
+
+ // Try to use the existing entry for the column (if one exists).
+ ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);
+
+ if (!pEntry)
+ {
+ // Something went terribly wrong!
+ return false;
+ }
+
+ if (ScTabViewShell::isAnyEditViewInRange(rViewData.GetViewShell(), /*bColumns*/ false, aParam.nRow1, aParam.nRow2))
+ return false;
+
+ pEntry->bDoQuery = true;
+ pEntry->nField = rPos.Col();
+ pEntry->eConnect = SC_AND;
+
+ ScFilterEntries aFilterEntries;
+ rDoc.GetFilterEntries(rPos.Col(), rPos.Row(), rPos.Tab(), aFilterEntries);
+
+ bool bActive = false;
+ auto aItem = pEntry->GetQueryItem();
+ if (aItem.maColor == m_aColor
+ && ((meMode == ScGridWindow::AutoFilterMode::TextColor
+ && aItem.meType == ScQueryEntry::ByTextColor)
+ || (meMode == ScGridWindow::AutoFilterMode::BackgroundColor
+ && aItem.meType == ScQueryEntry::ByBackgroundColor)))
+ {
+ bActive = true;
+ }
+
+ // Disable color filter when active color was selected
+ if (bActive)
+ {
+ aParam.RemoveAllEntriesByField(rPos.Col());
+ pEntry = nullptr; // invalidated by RemoveAllEntriesByField call
+
+ // tdf#46184 reset filter options to default values
+ aParam.eSearchType = utl::SearchParam::SearchType::Normal;
+ aParam.bCaseSens = false;
+ aParam.bDuplicate = true;
+ aParam.bInplace = true;
+ }
+ else
+ {
+ if (meMode == ScGridWindow::AutoFilterMode::TextColor)
+ pEntry->SetQueryByTextColor(m_aColor);
+ else
+ pEntry->SetQueryByBackgroundColor(m_aColor);
+ }
+
+ rViewData.GetView()->Query(aParam, nullptr, true);
+ pDBData->SetQueryParam(aParam);
+
+ return true;
+ }
+};
+
+class AutoFilterColorPopupStartAction : public AutoFilterSubMenuAction
+{
+public:
+ AutoFilterColorPopupStartAction(ScGridWindow* p, ScListSubMenuControl* pSubMenu)
+ : AutoFilterSubMenuAction(p, pSubMenu, ScGridWindow::AutoFilterMode::Normal)
+ {
+ }
+
+ virtual bool execute() override
+ {
+ const AutoFilterData* pData =
+ static_cast<const AutoFilterData*>(m_pSubMenu->getExtendedData());
+
+ if (!pData)
+ return false;
+
+ ScDBData* pDBData = pData->mpData;
+ if (!pDBData)
+ return false;
+
+ ScViewData& rViewData = m_pSubMenu->GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ const ScAddress& rPos = pData->maPos;
+
+ ScFilterEntries aFilterEntries;
+ rDoc.GetFilterEntries(rPos.Col(), rPos.Row(), rPos.Tab(), aFilterEntries);
+
+ m_pSubMenu->clearMenuItems();
+
+ XColorListRef xUserColorList;
+
+ OUString aPaletteName(officecfg::Office::Common::UserColors::PaletteName::get());
+ PaletteManager aPaletteManager;
+ std::vector<OUString> aPaletteNames = aPaletteManager.GetPaletteList();
+ for (size_t i = 0, nLen = aPaletteNames.size(); i < nLen; ++i)
+ {
+ if (aPaletteName == aPaletteNames[i])
+ {
+ aPaletteManager.SetPalette(i);
+ xUserColorList = XPropertyList::AsColorList(
+ XPropertyList::CreatePropertyListFromURL(
+ XPropertyListType::Color, aPaletteManager.GetSelectedPalettePath()));
+ if (!xUserColorList->Load())
+ xUserColorList = nullptr;
+ break;
+ }
+ }
+
+ ScQueryParam aParam;
+ pDBData->GetQueryParam(aParam);
+ ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);
+
+ int nMenu = 0;
+ for (auto eMode : {ScGridWindow::AutoFilterMode::BackgroundColor, ScGridWindow::AutoFilterMode::TextColor})
+ {
+ std::set<Color> aColors = eMode == ScGridWindow::AutoFilterMode::TextColor
+ ? aFilterEntries.getTextColors()
+ : aFilterEntries.getBackgroundColors();
+
+ for (auto& rColor : aColors)
+ {
+ bool bActive = false;
+
+ if (pEntry)
+ {
+ auto aItem = pEntry->GetQueryItem();
+ if (aItem.maColor == rColor
+ && ((eMode == ScGridWindow::AutoFilterMode::TextColor
+ && aItem.meType == ScQueryEntry::ByTextColor)
+ || (eMode == ScGridWindow::AutoFilterMode::BackgroundColor
+ && aItem.meType == ScQueryEntry::ByBackgroundColor)))
+ {
+ bActive = true;
+ }
+ }
+
+ const bool bAutoColor = rColor == COL_AUTO;
+
+ // ColorListBox::ShowPreview is similar
+ ScopedVclPtr<VirtualDevice> xDev(m_pSubMenu->create_virtual_device());
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ Size aImageSize(rStyleSettings.GetListBoxPreviewDefaultPixelSize());
+ xDev->SetOutputSize(aImageSize);
+ const tools::Rectangle aRect(Point(0, 0), aImageSize);
+
+ if (bAutoColor)
+ {
+ const Color aW(COL_WHITE);
+ const Color aG(0xef, 0xef, 0xef);
+ int nMinDim = std::min(aImageSize.Width(), aImageSize.Height()) + 1;
+ int nCheckSize = nMinDim / 3;
+ xDev->DrawCheckered(aRect.TopLeft(), aRect.GetSize(), std::min(nCheckSize, 8), aW, aG);
+ xDev->SetFillColor();
+ }
+ else
+ xDev->SetFillColor(rColor);
+
+ xDev->SetLineColor(rStyleSettings.GetDisableColor());
+ xDev->DrawRect(aRect);
+
+ if (bAutoColor)
+ {
+ OUString sText = eMode == ScGridWindow::AutoFilterMode::TextColor
+ ? ScResId(SCSTR_FILTER_AUTOMATIC_COLOR)
+ : ScResId(SCSTR_FILTER_NO_FILL);
+ m_pSubMenu->addMenuColorItem(sText, bActive, *xDev, nMenu,
+ new AutoFilterColorAction(mpWindow, m_pSubMenu, eMode, rColor));
+ }
+ else
+ {
+ OUString sName;
+
+ bool bFoundColorName = false;
+ if (xUserColorList)
+ {
+ sal_Int32 nPos = xUserColorList->GetIndexOfColor(rColor);
+ if (nPos != -1)
+ {
+ XColorEntry* pColorEntry = xUserColorList->GetColor(nPos);
+ sName = pColorEntry->GetName();
+ bFoundColorName = true;
+ }
+ }
+ if (!bFoundColorName)
+ sName = "#" + rColor.AsRGBHexString().toAsciiUpperCase();
+
+ m_pSubMenu->addMenuColorItem(sName, bActive, *xDev, nMenu,
+ new AutoFilterColorAction(mpWindow, m_pSubMenu, eMode, rColor));
+ }
+ }
+
+ ++nMenu;
+ }
+
+ m_pSubMenu->resizeToFitMenuItems();
+
+ return false;
+ }
+};
+
+class AddItemToEntry
+{
+ ScQueryEntry::QueryItemsType& mrItems;
+ svl::SharedStringPool& mrPool;
+public:
+ AddItemToEntry(ScQueryEntry::QueryItemsType& rItems, svl::SharedStringPool& rPool) :
+ mrItems(rItems), mrPool(rPool) {}
+ void operator() (const ScCheckListMenuControl::ResultEntry& rEntry)
+ {
+ if (rEntry.bValid)
+ {
+ ScQueryEntry::Item aNew;
+ aNew.maString = mrPool.intern(rEntry.aName);
+ // set the filter type to ByValue, if the filter condition is value
+ aNew.meType = rEntry.bDate ? ScQueryEntry::ByDate : rEntry.bValue ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
+ aNew.mfVal = rEntry.nValue;
+ mrItems.push_back(aNew);
+ }
+ }
+};
+
+class AddSelectedItemString
+{
+ std::unordered_set<OUString>& mrSetString;
+ std::unordered_set<double>& mrSetValue;
+public:
+ explicit AddSelectedItemString(std::unordered_set<OUString>& rString, std::unordered_set<double>& rValue) :
+ mrSetString(rString), mrSetValue(rValue) {}
+
+ void operator() (const ScQueryEntry::Item& rItem)
+ {
+ if( rItem.meType == ScQueryEntry::QueryType::ByValue )
+ mrSetValue.insert(rItem.mfVal);
+ else
+ mrSetString.insert(rItem.maString.getString());
+ }
+};
+
+void collectUIInformation(const OUString& aRow, const OUString& aCol , const OUString& aevent)
+{
+ EventDescription aDescription;
+ aDescription.aAction = "LAUNCH";
+ aDescription.aID = "grid_window";
+ aDescription.aParameters = {{aevent, ""},
+ {"ROW", aRow}, {"COL", aCol}};
+ aDescription.aParent = "MainWindow";
+ aDescription.aKeyWord = "ScGridWinUIObject";
+
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+void ScGridWindow::LaunchAutoFilterMenu(SCCOL nCol, SCROW nRow)
+{
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScDocument& rDoc = mrViewData.GetDocument();
+ bool bLOKActive = comphelper::LibreOfficeKit::isActive();
+
+ mpAutoFilterPopup.reset();
+
+ // Estimate the width (in pixels) of the longest text in the list
+ ScFilterEntries aFilterEntries;
+ rDoc.GetFilterEntries(nCol, nRow, nTab, aFilterEntries);
+
+ weld::Window* pPopupParent = GetFrameWeld();
+ int nColWidth = ScViewData::ToPixel(rDoc.GetColWidth(nCol, nTab), mrViewData.GetPPTX());
+ mpAutoFilterPopup.reset(new ScCheckListMenuControl(pPopupParent, mrViewData,
+ aFilterEntries.mbHasDates, nColWidth));
+
+ int nMaxTextWidth = 0;
+ if (aFilterEntries.size() <= 10)
+ {
+ // do pixel calculation for all elements of short lists
+ for (const auto& rEntry : aFilterEntries)
+ {
+ const OUString& aText = rEntry.GetString();
+ nMaxTextWidth = std::max<int>(nMaxTextWidth, mpAutoFilterPopup->GetTextWidth(aText) + aText.getLength() * 2);
+ }
+ }
+ else
+ {
+ // find the longest string, probably it will be the longest rendered text, too
+ // (performance optimization for long lists)
+ auto itMax = aFilterEntries.begin();
+ for (auto it = itMax; it != aFilterEntries.end(); ++it)
+ {
+ int nTextWidth = it->GetString().getLength();
+ if (nMaxTextWidth < nTextWidth)
+ {
+ nMaxTextWidth = nTextWidth;
+ itMax = it;
+ }
+ }
+ nMaxTextWidth = mpAutoFilterPopup->GetTextWidth(itMax->GetString()) + nMaxTextWidth * 2;
+ }
+
+ // window should be at least as wide as the column, or the longest text + checkbox, scrollbar ... (it is estimated with 70 pixel now)
+ // window should be maximum 1024 pixel wide.
+ int nWindowWidth = std::min<int>(1024, nMaxTextWidth + 70);
+ nWindowWidth = mpAutoFilterPopup->IncreaseWindowWidthToFitText(nWindowWidth);
+ nMaxTextWidth = std::max<int>(nMaxTextWidth, nWindowWidth - 70);
+
+ mpAutoFilterPopup->setOKAction(new AutoFilterAction(this, AutoFilterMode::Normal));
+ mpAutoFilterPopup->setPopupEndAction(
+ new AutoFilterPopupEndAction(this, ScAddress(nCol, nRow, nTab)));
+ std::unique_ptr<AutoFilterData> pData(new AutoFilterData);
+ pData->maPos = ScAddress(nCol, nRow, nTab);
+
+ Point aPos = mrViewData.GetScrPos(nCol, nRow, eWhich);
+ tools::Long nSizeX = 0;
+ tools::Long nSizeY = 0;
+ mrViewData.GetMergeSizePixel(nCol, nRow, nSizeX, nSizeY);
+ if (bLOKActive)
+ {
+ // Reverse the zoom factor from aPos and nSize[X|Y]
+ // before letting the autofilter window convert the to twips
+ // with no zoom information.
+ double fZoomX(mrViewData.GetZoomX());
+ double fZoomY(mrViewData.GetZoomY());
+ aPos.setX(aPos.getX() / fZoomX);
+ aPos.setY(aPos.getY() / fZoomY);
+ nSizeX = nSizeX / fZoomX;
+ nSizeY = nSizeY / fZoomY;
+ }
+ tools::Rectangle aCellRect(bLOKActive ? aPos : OutputToScreenPixel(aPos), Size(nSizeX, nSizeY));
+
+ ScDBData* pDBData = rDoc.GetDBAtCursor(nCol, nRow, nTab, ScDBDataPortion::AREA);
+ if (!pDBData)
+ return;
+
+ pData->mpData = pDBData;
+ mpAutoFilterPopup->setExtendedData(std::move(pData));
+
+ ScQueryParam aParam;
+ pDBData->GetQueryParam(aParam);
+ std::vector<ScQueryEntry*> aEntries = aParam.FindAllEntriesByField(nCol);
+ std::unordered_set<OUString> aSelectedString;
+ std::unordered_set<double> aSelectedValue;
+ bool bQueryByNonEmpty = aEntries.size() == 1 && aEntries[0]->IsQueryByNonEmpty();
+
+ if (!bQueryByNonEmpty)
+ {
+ for (ScQueryEntry* pEntry : aEntries)
+ {
+ if (pEntry && pEntry->eOp == SC_EQUAL)
+ {
+ ScQueryEntry::QueryItemsType& rItems = pEntry->GetQueryItems();
+ std::for_each(rItems.begin(), rItems.end(), AddSelectedItemString(aSelectedString, aSelectedValue));
+ }
+ }
+ }
+
+ // Populate the check box list.
+ mpAutoFilterPopup->setMemberSize(aFilterEntries.size());
+ for (auto it = aFilterEntries.begin(); it != aFilterEntries.end(); ++it)
+ {
+ // tdf#140745 show (empty) entry on top of the checkbox list
+ if (it->GetString().isEmpty())
+ {
+ const OUString& aStringVal = it->GetString();
+ const double aDoubleVal = it->GetValue();
+ bool bSelected = true;
+ if (!aSelectedValue.empty() || !aSelectedString.empty())
+ bSelected = aSelectedString.count(aStringVal) > 0;
+ else if (bQueryByNonEmpty)
+ bSelected = false;
+ mpAutoFilterPopup->addMember(aStringVal, aDoubleVal, bSelected);
+ aFilterEntries.maStrData.erase(it);
+ break;
+ }
+ }
+ for (const auto& rEntry : aFilterEntries)
+ {
+ const OUString& aStringVal = rEntry.GetString();
+ const double aDoubleVal = rEntry.GetValue();
+ const double aRDoubleVal = rEntry.GetRoundedValue();
+ bool bSelected = true;
+
+ if (!aSelectedValue.empty() || !aSelectedString.empty())
+ {
+ if (rEntry.GetStringType() == ScTypedStrData::Value)
+ {
+ if (aDoubleVal == aRDoubleVal)
+ bSelected = aSelectedValue.count(aDoubleVal) > 0
+ || aSelectedString.count(aStringVal) > 0;
+ else
+ bSelected = aSelectedValue.count(aDoubleVal) > 0
+ || aSelectedValue.count(aRDoubleVal) > 0
+ || aSelectedString.count(aStringVal) > 0;
+ }
+ else
+ bSelected = aSelectedString.count(aStringVal) > 0;
+ }
+
+ if ( rEntry.IsDate() )
+ mpAutoFilterPopup->addDateMember( aStringVal, rEntry.GetValue(), bSelected );
+ else
+ mpAutoFilterPopup->addMember( aStringVal, aRDoubleVal, bSelected, rEntry.GetStringType() == ScTypedStrData::Value );
+ }
+
+ // Populate the menu.
+ mpAutoFilterPopup->addMenuItem(
+ ScResId(STR_MENU_SORT_ASC),
+ new AutoFilterAction(this, AutoFilterMode::SortAscending));
+ mpAutoFilterPopup->addMenuItem(
+ ScResId(STR_MENU_SORT_DESC),
+ new AutoFilterAction(this, AutoFilterMode::SortDescending));
+ mpAutoFilterPopup->addSeparator();
+ if (ScListSubMenuControl* pSubMenu = mpAutoFilterPopup->addSubMenuItem(ScResId(SCSTR_FILTER_COLOR), true, true))
+ pSubMenu->setPopupStartAction(new AutoFilterColorPopupStartAction(this, pSubMenu));
+ if (ScListSubMenuControl* pSubMenu = mpAutoFilterPopup->addSubMenuItem(ScResId(SCSTR_FILTER_CONDITION), true, false))
+ {
+ pSubMenu->addMenuItem(
+ ScResId(SCSTR_FILTER_EMPTY), new AutoFilterAction(this, AutoFilterMode::Empty));
+ pSubMenu->addMenuItem(
+ ScResId(SCSTR_FILTER_NOTEMPTY), new AutoFilterAction(this, AutoFilterMode::NonEmpty));
+ pSubMenu->addMenuItem(
+ ScResId(SCSTR_TOP10FILTER), new AutoFilterAction(this, AutoFilterMode::Top10));
+ pSubMenu->addMenuItem(
+ ScResId(SCSTR_BOTTOM10FILTER), new AutoFilterAction(this, AutoFilterMode::Bottom10));
+ pSubMenu->addSeparator();
+ pSubMenu->addMenuItem(
+ ScResId(SCSTR_STDFILTER), new AutoFilterAction(this, AutoFilterMode::Custom));
+ pSubMenu->resizeToFitMenuItems();
+ }
+ if (aEntries.size())
+ mpAutoFilterPopup->addMenuItem(
+ ScResId(SCSTR_CLEAR_FILTER), new AutoFilterAction(this, AutoFilterMode::Clear));
+
+ mpAutoFilterPopup->initMembers(nMaxTextWidth + 20); // 20 pixel estimated for the checkbox
+
+ ScCheckListMenuControl::Config aConfig;
+ aConfig.mbAllowEmptySet = false;
+ aConfig.mbRTL = mrViewData.GetDocument().IsLayoutRTL(mrViewData.GetTabNo());
+ mpAutoFilterPopup->setConfig(aConfig);
+ if (IsMouseCaptured())
+ ReleaseMouse();
+ mpAutoFilterPopup->launch(pPopupParent, aCellRect);
+
+ // remember filter rules before modification
+ mpAutoFilterPopup->getResult(aSaveAutoFilterResult);
+
+ collectUIInformation(OUString::number(nRow), OUString::number(nCol),"AUTOFILTER");
+}
+
+void ScGridWindow::RefreshAutoFilterButton(const ScAddress& rPos)
+{
+ if (mpFilterButton)
+ {
+ bool bFilterActive = IsAutoFilterActive(rPos.Col(), rPos.Row(), rPos.Tab());
+ mpFilterButton->setHasHiddenMember(bFilterActive);
+ mpFilterButton->setPopupPressed(false);
+ mpFilterButton->draw();
+ }
+}
+
+void ScGridWindow::UpdateAutoFilterFromMenu(AutoFilterMode eMode)
+{
+ // Terminate autofilter popup now when there is no further user input needed
+ bool bColorMode = eMode == AutoFilterMode::TextColor || eMode == AutoFilterMode::BackgroundColor;
+ if (!bColorMode)
+ mpAutoFilterPopup->terminateAllPopupMenus();
+
+ const AutoFilterData* pData =
+ static_cast<const AutoFilterData*>(mpAutoFilterPopup->getExtendedData());
+
+ if (!pData)
+ return;
+
+ const ScAddress& rPos = pData->maPos;
+ ScDBData* pDBData = pData->mpData;
+ if (!pDBData)
+ return;
+
+ ScDocument& rDoc = mrViewData.GetDocument();
+ svl::SharedStringPool& rPool = rDoc.GetSharedStringPool();
+ switch (eMode)
+ {
+ case AutoFilterMode::SortAscending:
+ case AutoFilterMode::SortDescending:
+ {
+ SCCOL nCol = rPos.Col();
+ ScSortParam aSortParam;
+ pDBData->GetSortParam(aSortParam);
+ if (nCol < aSortParam.nCol1 || nCol > aSortParam.nCol2)
+ // out of bound
+ return;
+
+ bool bHasHeader = pDBData->HasHeader();
+
+ aSortParam.bHasHeader = bHasHeader;
+ aSortParam.bByRow = true;
+ aSortParam.bCaseSens = false;
+ aSortParam.bNaturalSort = false;
+ aSortParam.aDataAreaExtras.mbCellNotes = false;
+ aSortParam.aDataAreaExtras.mbCellDrawObjects = true;
+ aSortParam.aDataAreaExtras.mbCellFormats = true;
+ aSortParam.bInplace = true;
+ aSortParam.maKeyState[0].bDoSort = true;
+ aSortParam.maKeyState[0].nField = nCol;
+ aSortParam.maKeyState[0].bAscending = (eMode == AutoFilterMode::SortAscending);
+
+ for (size_t i = 1; i < aSortParam.GetSortKeyCount(); ++i)
+ aSortParam.maKeyState[i].bDoSort = false;
+
+ mrViewData.GetViewShell()->UISort(aSortParam);
+ return;
+ }
+ case AutoFilterMode::Custom:
+ {
+ ScRange aRange;
+ pDBData->GetArea(aRange);
+ mrViewData.GetView()->MarkRange(aRange);
+ mrViewData.GetView()->SetCursor(rPos.Col(), rPos.Row());
+ mrViewData.GetDispatcher().Execute(SID_FILTER, SfxCallMode::SLOT | SfxCallMode::RECORD);
+ return;
+ }
+ default:
+ ;
+ }
+
+ ScQueryParam aParam;
+ pDBData->GetQueryParam(aParam);
+
+ if (eMode == AutoFilterMode::Normal)
+ {
+ // Do not recreate autofilter rules if there are no changes from the user
+ ScCheckListMenuControl::ResultType aResult;
+ mpAutoFilterPopup->getResult(aResult);
+
+ if (aResult == aSaveAutoFilterResult)
+ {
+ SAL_INFO("sc.ui", "Apply autofilter to data when entries are the same");
+
+ if (!mpAutoFilterPopup->isAllSelected())
+ {
+ // Apply autofilter to data
+ ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);
+ pEntry->bDoQuery = true;
+ pEntry->nField = rPos.Col();
+ pEntry->eConnect = SC_AND;
+ pEntry->eOp = SC_EQUAL;
+ mrViewData.GetView()->Query(aParam, nullptr, true);
+ }
+
+ return;
+ }
+ }
+
+ // Remove old entries in auto-filter rules
+ if (!bColorMode)
+ {
+ aParam.RemoveAllEntriesByField(rPos.Col());
+
+ // tdf#46184 reset filter options to default values
+ aParam.eSearchType = utl::SearchParam::SearchType::Normal;
+ aParam.bCaseSens = false;
+ aParam.bDuplicate = true;
+ aParam.bInplace = true;
+ }
+
+ if (eMode != AutoFilterMode::Clear
+ && !(eMode == AutoFilterMode::Normal && mpAutoFilterPopup->isAllSelected()))
+ {
+ // Try to use the existing entry for the column (if one exists).
+ ScQueryEntry* pEntry = aParam.FindEntryByField(rPos.Col(), true);
+
+ if (!pEntry)
+ // Something went terribly wrong!
+ return;
+
+ if (ScTabViewShell::isAnyEditViewInRange(mrViewData.GetViewShell(), /*bColumns*/ false, aParam.nRow1, aParam.nRow2))
+ return;
+
+ pEntry->bDoQuery = true;
+ pEntry->nField = rPos.Col();
+ pEntry->eConnect = SC_AND;
+
+ switch (eMode)
+ {
+ case AutoFilterMode::Normal:
+ {
+ pEntry->eOp = SC_EQUAL;
+
+ ScCheckListMenuControl::ResultType aResult;
+ mpAutoFilterPopup->getResult(aResult);
+
+ ScQueryEntry::QueryItemsType& rItems = pEntry->GetQueryItems();
+ rItems.clear();
+ std::for_each(aResult.begin(), aResult.end(), AddItemToEntry(rItems, rPool));
+ }
+ break;
+ case AutoFilterMode::Top10:
+ pEntry->eOp = SC_TOPVAL;
+ pEntry->GetQueryItem().meType = ScQueryEntry::ByString;
+ pEntry->GetQueryItem().maString = rPool.intern("10");
+ break;
+ case AutoFilterMode::Bottom10:
+ pEntry->eOp = SC_BOTVAL;
+ pEntry->GetQueryItem().meType = ScQueryEntry::ByString;
+ pEntry->GetQueryItem().maString = rPool.intern("10");
+ break;
+ case AutoFilterMode::Empty:
+ pEntry->SetQueryByEmpty();
+ break;
+ case AutoFilterMode::NonEmpty:
+ pEntry->SetQueryByNonEmpty();
+ break;
+ case AutoFilterMode::TextColor:
+ case AutoFilterMode::BackgroundColor:
+ assert(false && "should be handled by AutoFilterColorAction::execute");
+ break;
+ break;
+ default:
+ // We don't know how to handle this!
+ return;
+ }
+ }
+
+ mrViewData.GetView()->Query(aParam, nullptr, true);
+ pDBData->SetQueryParam(aParam);
+}
+
+namespace {
+
+void getCellGeometry(Point& rScrPos, Size& rScrSize, const ScViewData& rViewData, SCCOL nCol, SCROW nRow, ScSplitPos eWhich)
+{
+ // Get the screen position of the cell.
+ rScrPos = rViewData.GetScrPos(nCol, nRow, eWhich);
+
+ // Get the screen size of the cell.
+ tools::Long nSizeX, nSizeY;
+ rViewData.GetMergeSizePixel(nCol, nRow, nSizeX, nSizeY);
+ rScrSize = Size(nSizeX-1, nSizeY-1);
+}
+
+}
+
+void ScGridWindow::LaunchPageFieldMenu( SCCOL nCol, SCROW nRow )
+{
+ if (nCol == 0)
+ // We assume that the page field button is located in cell to the immediate left.
+ return;
+
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScDPObject* pDPObj = mrViewData.GetDocument().GetDPAtCursor(nCol, nRow, nTab);
+ if (!pDPObj)
+ return;
+
+ Point aScrPos;
+ Size aScrSize;
+ getCellGeometry(aScrPos, aScrSize, mrViewData, nCol, nRow, eWhich);
+ bool bLOK = comphelper::LibreOfficeKit::isActive();
+ DPLaunchFieldPopupMenu(bLOK ? aScrPos : OutputToScreenPixel(aScrPos), aScrSize, ScAddress(nCol-1, nRow, nTab), pDPObj);
+}
+
+void ScGridWindow::LaunchDPFieldMenu( SCCOL nCol, SCROW nRow )
+{
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScDPObject* pDPObj = mrViewData.GetDocument().GetDPAtCursor(nCol, nRow, nTab);
+ if (!pDPObj)
+ return;
+
+ Point aScrPos;
+ Size aScrSize;
+ getCellGeometry(aScrPos, aScrSize, mrViewData, nCol, nRow, eWhich);
+ bool bLOK = comphelper::LibreOfficeKit::isActive();
+ DPLaunchFieldPopupMenu(bLOK ? aScrPos : OutputToScreenPixel(aScrPos), aScrSize, ScAddress(nCol, nRow, nTab), pDPObj);
+}
+
+void ScGridWindow::ShowFilterMenu(weld::Window* pParent, const tools::Rectangle& rCellRect, bool bLayoutRTL)
+{
+ auto nSizeX = rCellRect.GetWidth();
+
+ // minimum width in pixel
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ const tools::Long nMinLOKWinWidth = o3tl::convert(STD_COL_WIDTH * 13 / 10, o3tl::Length::twip, o3tl::Length::px);
+ if (nSizeX < nMinLOKWinWidth)
+ nSizeX = nMinLOKWinWidth;
+ }
+
+ weld::TreeView& rFilterBox = mpFilterBox->get_widget();
+ int nEntryCount = rFilterBox.n_children();
+ if (nEntryCount > SC_FILTERLISTBOX_LINES)
+ nEntryCount = SC_FILTERLISTBOX_LINES;
+ auto nHeight = rFilterBox.get_height_rows(nEntryCount);
+ rFilterBox.set_size_request(-1, nHeight);
+ Size aSize(rFilterBox.get_preferred_size());
+ auto nMaxToExpandTo = std::min(nSizeX, static_cast<decltype(nSizeX)>(300)); // do not over do it (Pixel)
+ if (aSize.Width() < nMaxToExpandTo)
+ aSize.setWidth(nMaxToExpandTo);
+
+ aSize.AdjustWidth(4); // add a little margin
+ nSizeX += 4;
+ aSize.AdjustHeight(4);
+
+ tools::Rectangle aCellRect(rCellRect);
+ aCellRect.AdjustLeft(-2); // offset the little margin above
+
+ if (!bLayoutRTL && aSize.Width() > nSizeX)
+ {
+ // move popup position
+ tools::Long nDiff = aSize.Width() - nSizeX;
+ tools::Long nNewX = aCellRect.Left() - nDiff;
+ if ( nNewX < 0 )
+ nNewX = 0;
+ aCellRect.SetLeft( nNewX );
+ }
+
+ rFilterBox.set_size_request(aSize.Width(), aSize.Height());
+
+ if (IsMouseCaptured())
+ ReleaseMouse();
+ mpFilterBox->popup_at_rect(pParent, aCellRect);
+}
+
+void ScGridWindow::DoScenarioMenu( const ScRange& rScenRange )
+{
+ bool bMenuAtTop = true;
+
+ ScDocument& rDoc = mrViewData.GetDocument();
+ mpFilterBox.reset();
+
+ SCCOL nCol = rScenRange.aEnd.Col(); // Cell is below the Buttons
+ SCROW nRow = rScenRange.aStart.Row();
+ if (nRow == 0)
+ {
+ nRow = rScenRange.aEnd.Row() + 1; // Range at very the top -> Button below
+ if (nRow>rDoc.MaxRow()) nRow = rDoc.MaxRow();
+ bMenuAtTop = false;
+ }
+
+ SCTAB nTab = mrViewData.GetTabNo();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ tools::Long nSizeX = 0;
+ tools::Long nSizeY = 0;
+ mrViewData.GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
+ // The button height should not use the merged cell height, should still use single row height
+ nSizeY = ScViewData::ToPixel(rDoc.GetRowHeight(nRow, nTab), mrViewData.GetPPTY());
+ Point aPos = mrViewData.GetScrPos( nCol, nRow, eWhich );
+ if ( bLayoutRTL )
+ aPos.AdjustX( -nSizeX );
+ tools::Rectangle aCellRect(aPos, Size(nSizeX, nSizeY));
+ aCellRect.AdjustTop( -nSizeY );
+ aCellRect.AdjustBottom( -(nSizeY - 1) );
+ if (!bMenuAtTop)
+ {
+ Size aButSize = mrViewData.GetScenButSize();
+ aCellRect.AdjustBottom(aButSize.Height());
+ }
+
+ // Place the ListBox directly below the black line of the cell grid
+ // (It looks odd if the line gets hidden...)
+
+ weld::Window* pParent = weld::GetPopupParent(*this, aCellRect);
+ mpFilterBox = std::make_shared<ScFilterListBox>(pParent, this, nCol, nRow, ScFilterBoxMode::Scenario);
+ mpFilterBox->connect_closed(LINK(this, ScGridWindow, PopupModeEndHdl));
+ weld::TreeView& rFilterBox = mpFilterBox->get_widget();
+ rFilterBox.set_direction(bLayoutRTL); // Fix for bug fdo#44925 use sheet direction for widget RTL/LTR
+
+ // Listbox fill
+ rFilterBox.freeze();
+ OUString aCurrent;
+ OUString aTabName;
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB i=nTab+1; i<nTabCount && rDoc.IsScenario(i); i++)
+ {
+ if (rDoc.HasScenarioRange( i, rScenRange ))
+ if (rDoc.GetName( i, aTabName ))
+ {
+ rFilterBox.append_text(aTabName);
+ if (rDoc.IsActiveScenario(i))
+ aCurrent = aTabName;
+ }
+ }
+ rFilterBox.thaw();
+
+ ShowFilterMenu(pParent, aCellRect, bLayoutRTL);
+
+ rFilterBox.grab_focus();
+
+ sal_Int32 nPos = -1;
+ if (!aCurrent.isEmpty())
+ {
+ nPos = rFilterBox.find_text(aCurrent);
+ }
+ if (nPos == -1 && rFilterBox.n_children() > 0 )
+ {
+ nPos = 0;
+ }
+ if (nPos != -1)
+ {
+ rFilterBox.set_cursor(nPos);
+ rFilterBox.select(nPos);
+ }
+ mpFilterBox->EndInit();
+}
+
+void ScGridWindow::LaunchDataSelectMenu( SCCOL nCol, SCROW nRow )
+{
+ mpFilterBox.reset();
+
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ tools::Long nSizeX = 0;
+ tools::Long nSizeY = 0;
+ mrViewData.GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
+ Point aPos = mrViewData.GetScrPos( nCol, nRow, eWhich );
+ bool bLOKActive = comphelper::LibreOfficeKit::isActive();
+
+ if (bLOKActive)
+ {
+ // aPos is now view-zoom adjusted and in pixels an more importantly this is pixel aligned to the view-zoom,
+ // but once we use this to set the position of the floating window, it has no information of view-zoom level
+ // so if we don't reverse the zoom now, a simple PixelToLogic(aPos, MapMode(MapUnit::MapTwip)) employed in
+ // FloatingWindow::ImplCalcPos will produce a 'scaled' twips position which will again get zoom scaled in the
+ // client (effective double scaling) causing wrong positioning/size.
+ double fZoomX(mrViewData.GetZoomX());
+ double fZoomY(mrViewData.GetZoomY());
+ aPos.setX(aPos.getX() / fZoomX);
+ aPos.setY(aPos.getY() / fZoomY);
+ nSizeX = nSizeX / fZoomX;
+ nSizeY = nSizeY / fZoomY;
+ }
+
+ if ( bLayoutRTL )
+ aPos.AdjustX( -nSizeX );
+ tools::Rectangle aCellRect(aPos, Size(nSizeX, nSizeY));
+
+ weld::Window* pParent = weld::GetPopupParent(*this, aCellRect);
+ mpFilterBox = std::make_shared<ScFilterListBox>(pParent, this, nCol, nRow, ScFilterBoxMode::DataSelect);
+ mpFilterBox->connect_closed(LINK(this, ScGridWindow, PopupModeEndHdl));
+ weld::TreeView& rFilterBox = mpFilterBox->get_widget();
+ rFilterBox.set_direction(bLayoutRTL); // Fix for bug fdo#44925 use sheet direction for widget RTL/LTR
+
+ // SetSize later
+
+ bool bEmpty = false;
+ std::vector<ScTypedStrData> aStrings; // case sensitive
+ // Fill List
+ rDoc.GetDataEntries(nCol, nRow, nTab, aStrings, true /* bValidation */);
+ if (aStrings.empty())
+ bEmpty = true;
+
+ if (!bEmpty)
+ {
+ rFilterBox.freeze();
+
+ // Fill Listbox
+ bool bWait = aStrings.size() > 100;
+
+ if (bWait)
+ EnterWait();
+
+ for (const auto& rString : aStrings)
+ rFilterBox.append_text(rString.GetString());
+
+ if (bWait)
+ LeaveWait();
+
+ rFilterBox.thaw();
+
+ ShowFilterMenu(pParent, aCellRect, bLayoutRTL);
+ }
+
+ sal_Int32 nSelPos = -1;
+
+ sal_uLong nIndex = rDoc.GetAttr( nCol, nRow, nTab, ATTR_VALIDDATA )->GetValue();
+ if ( nIndex )
+ {
+ const ScValidationData* pData = rDoc.GetValidationEntry( nIndex );
+ if (pData)
+ {
+ std::unique_ptr<ScTypedStrData> pNew;
+ OUString aDocStr = rDoc.GetString(nCol, nRow, nTab);
+ if ( rDoc.HasValueData( nCol, nRow, nTab ) )
+ {
+ double fVal = rDoc.GetValue(ScAddress(nCol, nRow, nTab));
+ pNew.reset(new ScTypedStrData(aDocStr, fVal, fVal, ScTypedStrData::Value));
+ }
+ else
+ pNew.reset(new ScTypedStrData(aDocStr, 0.0, 0.0, ScTypedStrData::Standard));
+
+ if (pData->GetListType() == css::sheet::TableValidationVisibility::SORTEDASCENDING)
+ {
+ auto it = std::lower_bound(aStrings.begin(), aStrings.end(), *pNew, ScTypedStrData::LessCaseSensitive());
+ if (it != aStrings.end() && ScTypedStrData::EqualCaseSensitive()(*it, *pNew))
+ nSelPos = static_cast<sal_Int32>(std::distance(aStrings.begin(), it));
+ }
+ else
+ {
+ auto it = std::find_if(aStrings.begin(), aStrings.end(), FindTypedStrData(*pNew, true));
+ if (it != aStrings.end())
+ nSelPos = static_cast<sal_Int32>(std::distance(aStrings.begin(), it));
+ }
+ }
+ }
+
+ // Do not show an empty selection List:
+
+ if ( bEmpty )
+ {
+ mpFilterBox.reset();
+ }
+ else
+ {
+ rFilterBox.grab_focus();
+
+ if (rFilterBox.n_children())
+ {
+ if (nSelPos != -1)
+ rFilterBox.set_cursor(nSelPos);
+ else
+ rFilterBox.set_cursor(0);
+ }
+ // Select only after GrabFocus, so that the focus rectangle gets correct
+ if (nSelPos != -1)
+ rFilterBox.select(nSelPos);
+ else
+ rFilterBox.unselect_all();
+
+ mpFilterBox->EndInit();
+ }
+ collectUIInformation(OUString::number(nRow), OUString::number(nCol),"SELECTMENU");
+}
+
+void ScGridWindow::FilterSelect( sal_uLong nSel )
+{
+ weld::TreeView& rFilterBox = mpFilterBox->get_widget();
+ OUString aString = rFilterBox.get_text(static_cast<sal_Int32>(nSel));
+
+ SCCOL nCol = mpFilterBox->GetCol();
+ SCROW nRow = mpFilterBox->GetRow();
+ switch (mpFilterBox->GetMode())
+ {
+ case ScFilterBoxMode::DataSelect:
+ ExecDataSelect(nCol, nRow, aString);
+ break;
+ case ScFilterBoxMode::Scenario:
+ mrViewData.GetView()->UseScenario(aString);
+ break;
+ }
+
+ if (mpFilterBox)
+ mpFilterBox->popdown();
+
+ GrabFocus(); // Otherwise the focus would be wrong on OS/2
+}
+
+void ScGridWindow::ExecDataSelect( SCCOL nCol, SCROW nRow, const OUString& rStr )
+{
+ ScModule* pScMod = SC_MOD();
+ ScInputHandler* pViewHdl = pScMod->GetInputHdl(mrViewData.GetViewShell());
+ if (pViewHdl && mrViewData.HasEditView(mrViewData.GetActivePart()))
+ pViewHdl->CancelHandler();
+
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScViewFunc* pView = mrViewData.GetView();
+ pView->EnterData( nCol, nRow, nTab, rStr );
+
+ // #i52307# CellContentChanged is not in EnterData so it isn't called twice
+ // if the cursor is moved afterwards.
+ pView->CellContentChanged();
+}
+
+void ScGridWindow::MoveMouseStatus( ScGridWindow& rDestWin )
+{
+ if (nButtonDown)
+ {
+ rDestWin.nButtonDown = nButtonDown;
+ rDestWin.nMouseStatus = nMouseStatus;
+ }
+
+ if (bRFMouse)
+ {
+ rDestWin.bRFMouse = bRFMouse;
+ rDestWin.bRFSize = bRFSize;
+ rDestWin.nRFIndex = nRFIndex;
+ rDestWin.nRFAddX = nRFAddX;
+ rDestWin.nRFAddY = nRFAddY;
+ bRFMouse = false;
+ }
+
+ if (nPagebreakMouse)
+ {
+ rDestWin.nPagebreakMouse = nPagebreakMouse;
+ rDestWin.nPagebreakBreak = nPagebreakBreak;
+ rDestWin.nPagebreakPrev = nPagebreakPrev;
+ rDestWin.aPagebreakSource = aPagebreakSource;
+ rDestWin.aPagebreakDrag = aPagebreakDrag;
+ nPagebreakMouse = SC_PD_NONE;
+ }
+}
+
+bool ScGridWindow::TestMouse( const MouseEvent& rMEvt, bool bAction )
+{
+ // MouseEvent buttons must only be checked if bAction==TRUE
+ // to allow changing the mouse pointer in MouseMove,
+ // but not start AutoFill with right button (#74229#).
+ // with bAction==sal_True, SetFillMode / SetDragMode is called
+
+ if ( bAction && !rMEvt.IsLeft() )
+ return false;
+
+ bool bNewPointer = false;
+
+ SfxInPlaceClient* pClient = mrViewData.GetViewShell()->GetIPClient();
+ bool bOleActive = ( pClient && pClient->IsObjectInPlaceActive() );
+
+ if ( mrViewData.IsActive() && !bOleActive )
+ {
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ // Auto-Fill
+
+ ScRange aMarkRange;
+ if (mrViewData.GetSimpleArea( aMarkRange ) == SC_MARK_SIMPLE)
+ {
+ if (aMarkRange.aStart.Tab() == mrViewData.GetTabNo() && mpAutoFillRect)
+ {
+ Point aMousePos = rMEvt.GetPosPixel();
+ if (mpAutoFillRect->Contains(aMousePos))
+ {
+ SetPointer( PointerStyle::Cross ); //! bold cross ?
+ if (bAction)
+ {
+ SCCOL nX = aMarkRange.aEnd.Col();
+ SCROW nY = aMarkRange.aEnd.Row();
+
+ if ( lcl_IsEditableMatrix( mrViewData.GetDocument(), aMarkRange ) )
+ mrViewData.SetDragMode(
+ aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nX, nY, ScFillMode::MATRIX );
+ else
+ mrViewData.SetFillMode(
+ aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nX, nY );
+
+ // The simple selection must also be recognized when dragging,
+ // where the Marking flag is set and MarkToSimple won't work anymore.
+ mrViewData.GetMarkData().MarkToSimple();
+ }
+ bNewPointer = true;
+ }
+ }
+ }
+
+ // Embedded rectangle
+
+ if (rDoc.IsEmbedded())
+ {
+ ScRange aRange;
+ rDoc.GetEmbedded( aRange );
+ if ( mrViewData.GetTabNo() == aRange.aStart.Tab() )
+ {
+ Point aStartPos = mrViewData.GetScrPos( aRange.aStart.Col(), aRange.aStart.Row(), eWhich );
+ Point aEndPos = mrViewData.GetScrPos( aRange.aEnd.Col()+1, aRange.aEnd.Row()+1, eWhich );
+ Point aMousePos = rMEvt.GetPosPixel();
+ if ( bLayoutRTL )
+ {
+ aStartPos.AdjustX(2 );
+ aEndPos.AdjustX(2 );
+ }
+ bool bTop = ( aMousePos.X() >= aStartPos.X()-3 && aMousePos.X() <= aStartPos.X()+1 &&
+ aMousePos.Y() >= aStartPos.Y()-3 && aMousePos.Y() <= aStartPos.Y()+1 );
+ bool bBottom = ( aMousePos.X() >= aEndPos.X()-3 && aMousePos.X() <= aEndPos.X()+1 &&
+ aMousePos.Y() >= aEndPos.Y()-3 && aMousePos.Y() <= aEndPos.Y()+1 );
+ if ( bTop || bBottom )
+ {
+ SetPointer( PointerStyle::Cross );
+ if (bAction)
+ {
+ ScFillMode nMode = bTop ? ScFillMode::EMBED_LT : ScFillMode::EMBED_RB;
+ mrViewData.SetDragMode(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), nMode );
+ }
+ bNewPointer = true;
+ }
+ }
+ }
+ }
+
+ if (!bNewPointer && bAction)
+ {
+ mrViewData.ResetFillMode();
+ }
+
+ return bNewPointer;
+}
+
+void ScGridWindow::LogicMouseButtonDown(const MouseEvent& rMouseEvent)
+{
+ MouseButtonDown(rMouseEvent);
+}
+
+void ScGridWindow::LogicMouseButtonUp(const MouseEvent& rMouseEvent)
+{
+ MouseButtonUp(rMouseEvent);
+}
+
+void ScGridWindow::LogicMouseMove(const MouseEvent& rMouseEvent)
+{
+ MouseMove(rMouseEvent);
+}
+
+void ScGridWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if (SfxLokHelper::getDeviceFormFactor() == LOKDeviceFormFactor::MOBILE)
+ {
+ ScViewFunc* pView = mrViewData.GetView();
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ bool bRefMode = pViewShell && pViewShell->IsRefInputMode();
+
+ Point aPos(rMEvt.GetPosPixel());
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel(aPos.X(), aPos.Y(), eWhich, nPosX, nPosY);
+
+ if (bRefMode && pView->GetFunctionSet().CheckRefBounds(nPosX, nPosY))
+ return;
+ }
+
+ nNestedButtonState = ScNestedButtonState::Down;
+
+ MouseEventState aState;
+ HandleMouseButtonDown(rMEvt, aState);
+ if (aState.mbActivatePart)
+ mrViewData.GetView()->ActivatePart(eWhich);
+
+ if ( nNestedButtonState == ScNestedButtonState::Up )
+ {
+ // #i41690# If an object is deactivated from MouseButtonDown, it might reschedule,
+ // so MouseButtonUp comes before the MouseButtonDown call is finished. In this case,
+ // simulate another MouseButtonUp call, so the selection state is consistent.
+
+ nButtonDown = rMEvt.GetButtons();
+ FakeButtonUp();
+
+ if ( IsTracking() )
+ EndTracking(); // normally done in VCL as part of MouseButtonUp handling
+ }
+ nNestedButtonState = ScNestedButtonState::NONE;
+}
+
+bool ScGridWindow::IsCellCoveredByText(SCCOL nPosX, SCROW nPosY, SCTAB nTab, SCCOL &rTextStartPosX)
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+
+ // find the first non-empty cell (this, or to the left)
+ SCCOL nNonEmptyX = nPosX;
+ for (; nNonEmptyX >= 0; --nNonEmptyX)
+ {
+ ScRefCellValue aCell(rDoc, ScAddress(nNonEmptyX, nPosY, nTab));
+ if (!aCell.isEmpty())
+ break;
+ }
+
+ // the initial cell already contains text
+ if (nNonEmptyX == nPosX)
+ {
+ rTextStartPosX = nNonEmptyX;
+ return true;
+ }
+
+ // to the left, there is no cell that would contain (potentially
+ // overrunning) text
+ if (nNonEmptyX < 0 || rDoc.HasAttrib(nNonEmptyX, nPosY, nTab, nPosX, nPosY, nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped))
+ return false;
+
+ double nPPTX = mrViewData.GetPPTX();
+ double nPPTY = mrViewData.GetPPTY();
+
+ ScTableInfo aTabInfo;
+ rDoc.FillInfo(aTabInfo, 0, nPosY, nPosX, nPosY, nTab, nPPTX, nPPTY, false, false);
+
+ Fraction aZoomX = mrViewData.GetZoomX();
+ Fraction aZoomY = mrViewData.GetZoomY();
+ ScOutputData aOutputData(GetOutDev(), OUTTYPE_WINDOW, aTabInfo, &rDoc, nTab,
+ 0, 0, 0, nPosY, nPosX, nPosY, nPPTX, nPPTY,
+ &aZoomX, &aZoomY);
+
+ MapMode aCurrentMapMode(GetMapMode());
+ SetMapMode(MapMode(MapUnit::MapPixel));
+
+ // obtain the bounding box of the text in first non-empty cell
+ // to the left
+ tools::Rectangle aRect(aOutputData.LayoutStrings(false, false, ScAddress(nNonEmptyX, nPosY, nTab)));
+
+ SetMapMode(aCurrentMapMode);
+
+ // the text does not overrun from the cell
+ if (aRect.IsEmpty())
+ return false;
+
+ SCCOL nTextEndX;
+ SCROW nTextEndY;
+
+ // test the rightmost position of the text bounding box
+ tools::Long nMiddle = (aRect.Top() + aRect.Bottom()) / 2;
+ mrViewData.GetPosFromPixel(aRect.Right(), nMiddle, eWhich, nTextEndX, nTextEndY);
+ if (nTextEndX >= nPosX)
+ {
+ rTextStartPosX = nNonEmptyX;
+ return true;
+ }
+
+ return false;
+}
+
+void ScGridWindow::HandleMouseButtonDown( const MouseEvent& rMEvt, MouseEventState& rState )
+{
+ // 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 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)
+ SfxViewShell* pViewSh = mrViewData.GetViewShell();
+ SfxInPlaceClient* pClient = pViewSh->GetIPClient();
+ if ( pClient &&
+ pClient->IsObjectInPlaceActive() &&
+ vcl::IsInPopupMenuExecute() )
+ return;
+
+ aCurMousePos = rMEvt.GetPosPixel();
+
+ // Filter popup is ended with its own mouse click, not when clicking into the Grid Window,
+ // so the following query is no longer necessary:
+ ClickExtern(); // deletes FilterBox when available
+
+ HideNoteMarker();
+
+ bEEMouse = false;
+
+ ScModule* pScMod = SC_MOD();
+ if (pScMod->IsModalMode(mrViewData.GetSfxDocShell()))
+ return;
+
+ const bool bWasMouseCaptured = IsMouseCaptured();
+ SAL_WARN_IF(bWasMouseCaptured, "sc.ui", "Is there a scenario where the mouse is captured before mouse down?");
+
+ pScActiveViewShell = mrViewData.GetViewShell(); // if left is clicked
+ nScClickMouseModifier = rMEvt.GetModifier(); // to always catch a control click
+
+ bool bDetective = mrViewData.GetViewShell()->IsAuditShell();
+ bool bRefMode = mrViewData.IsRefMode(); // Start reference
+ bool bFormulaMode = pScMod->IsFormulaMode(); // next click -> reference
+ bool bEditMode = mrViewData.HasEditView(eWhich); // also in Mode==SC_INPUT_TYPE
+ bool bDouble = (rMEvt.GetClicks() == 2);
+ ScDocument& rDoc = mrViewData.GetDocument();
+ bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
+
+ // DeactivateIP does only happen when MarkListHasChanged
+
+ // An error message can show up during GrabFocus call
+ // (for instance when renaming tables per sheet title)
+
+ if ( !nButtonDown || !bDouble ) // single (first) click is always valid
+ nButtonDown = rMEvt.GetButtons(); // set nButtonDown first, so StopMarking works
+
+ // special handling of empty cells with tiled rendering
+ if (bIsTiledRendering)
+ {
+ Point aPos(rMEvt.GetPosPixel());
+ SCCOL nPosX, nNonEmptyX(0);
+ SCROW nPosY;
+ SCTAB nTab = mrViewData.GetTabNo();
+ mrViewData.GetPosFromPixel(aPos.X(), aPos.Y(), eWhich, nPosX, nPosY);
+
+ ScRefCellValue aCell(rDoc, ScAddress(nPosX, nPosY, nTab));
+ bool bIsEmpty = aCell.isEmpty();
+ bool bIsCoveredByText = bIsEmpty && IsCellCoveredByText(nPosX, nPosY, nTab, nNonEmptyX);
+
+ if (bIsCoveredByText)
+ {
+ // if there's any text flowing to this cell, activate the
+ // editengine, so that the text actually gets the events
+ if (bDouble)
+ {
+ ScViewFunc* pView = mrViewData.GetView();
+
+ pView->SetCursor(nNonEmptyX, nPosY);
+ SC_MOD()->SetInputMode(SC_INPUT_TABLE);
+
+ bEditMode = mrViewData.HasEditView(eWhich);
+ assert(bEditMode);
+
+ // synthesize the 1st click
+ EditView* pEditView = mrViewData.GetEditView(eWhich);
+ MouseEvent aEditEvt(rMEvt.GetPosPixel(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0);
+ pEditView->MouseButtonDown(aEditEvt);
+ pEditView->MouseButtonUp(aEditEvt);
+ }
+ }
+ else if (bIsEmpty && bEditMode && bDouble)
+ {
+ // double-click in an empty cell: the entire cell is selected
+ SetCellSelectionPixel(LOK_SETTEXTSELECTION_START, aPos.X(), aPos.Y());
+ SetCellSelectionPixel(LOK_SETTEXTSELECTION_END, aPos.X(), aPos.Y());
+ return;
+ }
+ }
+
+ if ( ( bEditMode && mrViewData.GetActivePart() == eWhich ) || !bFormulaMode )
+ GrabFocus();
+
+ // #i31846# need to cancel a double click if the first click has set the "ignore" state,
+ // but a single (first) click is always valid
+ if ( nMouseStatus == SC_GM_IGNORE && bDouble )
+ {
+ nButtonDown = 0;
+ nMouseStatus = SC_GM_NONE;
+ return;
+ }
+
+ if ( bDetective ) // Detectiv fill mode
+ {
+ if ( rMEvt.IsLeft() && !rMEvt.GetModifier() )
+ {
+ Point aPos = rMEvt.GetPosPixel();
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+
+ SfxInt16Item aPosXItem( SID_RANGE_COL, nPosX );
+ SfxInt32Item aPosYItem( SID_RANGE_ROW, nPosY );
+ mrViewData.GetDispatcher().ExecuteList(SID_FILL_SELECT,
+ SfxCallMode::SLOT | SfxCallMode::RECORD,
+ { &aPosXItem, &aPosYItem });
+
+ }
+ nButtonDown = 0;
+ nMouseStatus = SC_GM_NONE;
+ return;
+ }
+
+ if (!bDouble)
+ nMouseStatus = SC_GM_NONE;
+
+ rState.mbActivatePart = !bFormulaMode; // Don't activate when in formula mode.
+
+ if (bFormulaMode)
+ {
+ ScViewSelectionEngine* pSelEng = mrViewData.GetView()->GetSelEngine();
+ pSelEng->SetWindow(this);
+ pSelEng->SetWhich(eWhich);
+ pSelEng->SetVisibleArea( tools::Rectangle(Point(), GetOutputSizePixel()) );
+ }
+
+ if (bEditMode && (mrViewData.GetRefTabNo() == mrViewData.GetTabNo()))
+ {
+ Point aPos = rMEvt.GetPosPixel();
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+
+ EditView* pEditView;
+ SCCOL nEditCol;
+ SCROW nEditRow;
+ mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
+ SCCOL nEndCol = mrViewData.GetEditEndCol();
+ SCROW nEndRow = mrViewData.GetEditEndRow();
+
+ if ( nPosX >= nEditCol && nPosX <= nEndCol &&
+ nPosY >= nEditRow && nPosY <= nEndRow )
+ {
+ // when clicking in the table EditView, always reset the focus
+ if (bFormulaMode) // otherwise this has already happen above
+ GrabFocus();
+
+ pScMod->SetInputMode( SC_INPUT_TABLE );
+ bEEMouse = true;
+ pEditView->MouseButtonDown( rMEvt );
+ return;
+ }
+ }
+
+ if (pScMod->GetIsWaterCan())
+ {
+ //! what's up with the Mac ???
+ if ( rMEvt.GetModifier() + rMEvt.GetButtons() == MOUSE_RIGHT )
+ {
+ nMouseStatus = SC_GM_WATERUNDO;
+ return;
+ }
+ }
+
+ // Order that matches the displayed Cursor:
+ // RangeFinder, AutoFill, PageBreak, Drawing
+
+ RfCorner rCorner = NONE;
+ bool bFound = HitRangeFinder(rMEvt.GetPosPixel(), rCorner, &nRFIndex, &nRFAddX, &nRFAddY);
+ bRFSize = (rCorner != NONE);
+ aRFSelectedCorned = rCorner;
+
+ if (bFound)
+ {
+ bRFMouse = true; // the other variables are initialized above
+
+ rState.mbActivatePart = true; // always activate ?
+ StartTracking();
+ return;
+ }
+
+ bool bCrossPointer = TestMouse( rMEvt, true );
+ if ( bCrossPointer )
+ {
+ if ( bDouble )
+ mrViewData.GetView()->FillCrossDblClick();
+ else
+ pScMod->InputEnterHandler(); // Autofill etc.
+ }
+
+ if ( !bCrossPointer )
+ {
+ nPagebreakMouse = HitPageBreak( rMEvt.GetPosPixel(), &aPagebreakSource,
+ &nPagebreakBreak, &nPagebreakPrev );
+ if (nPagebreakMouse)
+ {
+ bPagebreakDrawn = false;
+ StartTracking();
+ PagebreakMove( rMEvt, false );
+ return;
+ }
+ }
+
+ // in the tiled rendering case, single clicks into drawing objects take
+ // precedence over bEditMode
+ if (((!bFormulaMode && !bEditMode) || bIsTiledRendering) && rMEvt.IsLeft())
+ {
+ if ( !bCrossPointer && DrawMouseButtonDown(rMEvt) )
+ {
+ return;
+ }
+
+ mrViewData.GetViewShell()->SetDrawShell( false ); // no Draw-object selected
+
+ // TestMouse has already happened above
+ }
+
+ Point aPos = rMEvt.GetPosPixel();
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+ SCTAB nTab = mrViewData.GetTabNo();
+
+ // FIXME: this is to limit the number of rows handled in the Online
+ // to 1000; this will be removed again when the performance
+ // bottlenecks are sorted out
+ if ( comphelper::LibreOfficeKit::isActive() && nPosY > MAXTILEDROW - 1 )
+ {
+ nButtonDown = 0;
+ nMouseStatus = SC_GM_NONE;
+ return;
+ }
+
+ // Auto filter / pivot table / data select popup. This shouldn't activate the part.
+
+ if ( !bDouble && !bFormulaMode && rMEvt.IsLeft() )
+ {
+ SCCOL nRealPosX;
+ SCROW nRealPosY;
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nRealPosX, nRealPosY, false );//the real row/col
+
+ // show in the merged cells the filter of the first cell (nPosX instead of nRealPosX)
+ const ScMergeFlagAttr* pRealPosAttr = rDoc.GetAttr(nPosX, nRealPosY, nTab, ATTR_MERGE_FLAG);
+ if( pRealPosAttr->HasAutoFilter() )
+ {
+ SC_MOD()->InputEnterHandler();
+ if (DoAutoFilterButton(nPosX, nRealPosY, rMEvt))
+ return;
+ }
+
+ const ScMergeFlagAttr* pAttr = rDoc.GetAttr(nPosX, nPosY, nTab, ATTR_MERGE_FLAG);
+ if (pAttr->HasAutoFilter())
+ {
+ if (DoAutoFilterButton(nPosX, nPosY, rMEvt))
+ {
+ rState.mbActivatePart = false;
+ return;
+ }
+ }
+
+ if (pAttr->HasPivotButton() || pAttr->HasPivotPopupButton())
+ {
+ DoPushPivotButton(nPosX, nPosY, rMEvt, pAttr->HasPivotButton(), pAttr->HasPivotPopupButton());
+ rState.mbActivatePart = false;
+ return;
+ }
+
+ // List Validity drop-down button
+
+ if ( bListValButton )
+ {
+ tools::Rectangle aButtonRect = GetListValButtonRect( aListValPos );
+ if ( aButtonRect.Contains( aPos ) )
+ {
+ // tdf#149609 if we captured the mouse in the course of this function
+ // release it before showing the data select menu to undo any unhelpful
+ // seleng capture
+ if (!bWasMouseCaptured && IsMouseCaptured())
+ ReleaseMouse();
+
+ LaunchDataSelectMenu( aListValPos.Col(), aListValPos.Row() );
+
+ nMouseStatus = SC_GM_FILTER; // not set in DoAutoFilterMenue for bDataSelect
+ rState.mbActivatePart = false;
+ return;
+ }
+ }
+ }
+
+ // scenario selection
+
+ ScRange aScenRange;
+ if ( rMEvt.IsLeft() && HasScenarioButton( aPos, aScenRange ) )
+ {
+ // tdf#149609 if we captured the mouse in the course of this function
+ // release it before showing the data scenario menu to undo any unhelpful
+ // seleng capture
+ if (!bWasMouseCaptured && IsMouseCaptured())
+ ReleaseMouse();
+
+ DoScenarioMenu( aScenRange );
+
+ // Scenario selection comes from MouseButtonDown:
+ // The next MouseMove on the FilterBox is like a ButtonDown
+ nMouseStatus = SC_GM_FILTER;
+ return;
+ }
+
+ // double click started ?
+
+ // StopMarking can be called from DrawMouseButtonDown
+
+ if ( nMouseStatus != SC_GM_IGNORE && !bRefMode )
+ {
+ if ( bDouble && !bCrossPointer )
+ {
+ if (nMouseStatus == SC_GM_TABDOWN)
+ nMouseStatus = SC_GM_DBLDOWN;
+ }
+ else
+ nMouseStatus = SC_GM_TABDOWN;
+ }
+
+ // links in the edit cell
+
+ bool bAlt = rMEvt.IsMod2();
+ if ( !bAlt && rMEvt.IsLeft() && ScGlobal::ShouldOpenURL() &&
+ GetEditUrl(rMEvt.GetPosPixel()) ) // click on link: do not move cursor
+ {
+ SetPointer( PointerStyle::RefHand );
+ nMouseStatus = SC_GM_URLDOWN; // also only execute when ButtonUp
+ return;
+ }
+
+ // Gridwin - Selection Engine
+
+ if ( !rMEvt.IsLeft() )
+ return;
+
+ ScViewSelectionEngine* pSelEng = mrViewData.GetView()->GetSelEngine();
+ pSelEng->SetWindow(this);
+ pSelEng->SetWhich(eWhich);
+ pSelEng->SetVisibleArea( tools::Rectangle(Point(), GetOutputSizePixel()) );
+
+ // SelMouseButtonDown on the View is still setting the bMoveIsShift flag
+ if ( mrViewData.GetView()->SelMouseButtonDown( rMEvt ) )
+ {
+ if (IsMouseCaptured())
+ {
+ // Tracking instead of CaptureMouse, so it can be canceled cleanly
+ //! Someday SelectionEngine should call StartTracking on its own!?!
+ ReleaseMouse();
+ StartTracking();
+ }
+ mrViewData.GetMarkData().SetMarking(true);
+ return;
+ }
+}
+
+void ScGridWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ aCurMousePos = rMEvt.GetPosPixel();
+ ScDocument& rDoc = mrViewData.GetDocument();
+ ScMarkData& rMark = mrViewData.GetMarkData();
+ // #i41690# detect a MouseButtonUp call from within MouseButtonDown
+ // (possible through Reschedule from storing an OLE object that is deselected)
+
+ if ( nNestedButtonState == ScNestedButtonState::Down )
+ nNestedButtonState = ScNestedButtonState::Up;
+
+ if (nButtonDown != rMEvt.GetButtons())
+ nMouseStatus = SC_GM_IGNORE; // reset and return
+
+ nButtonDown = 0;
+
+ if (nMouseStatus == SC_GM_IGNORE)
+ {
+ nMouseStatus = SC_GM_NONE;
+ // Selection engine: cancel selection
+ mrViewData.GetView()->GetSelEngine()->Reset();
+ rMark.SetMarking(false);
+ if (mrViewData.IsAnyFillMode())
+ {
+ mrViewData.GetView()->StopRefMode();
+ mrViewData.ResetFillMode();
+ }
+ StopMarking();
+ DrawEndAction(); // cancel selection/moving in drawing layer
+ ReleaseMouse();
+ return;
+ }
+
+ if (nMouseStatus == SC_GM_FILTER)
+ {
+ nMouseStatus = SC_GM_NONE;
+ ReleaseMouse();
+ return; // nothing more should happen here
+ }
+
+ ScModule* pScMod = SC_MOD();
+ if (pScMod->IsModalMode(mrViewData.GetSfxDocShell()))
+ return;
+
+ SfxBindings& rBindings = mrViewData.GetBindings();
+ if (bEEMouse && mrViewData.HasEditView( eWhich ))
+ {
+ EditView* pEditView;
+ SCCOL nEditCol;
+ SCROW nEditRow;
+ mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
+ pEditView->MouseButtonUp( rMEvt );
+
+ if ( rMEvt.IsMiddle() &&
+ GetSettings().GetMouseSettings().GetMiddleButtonAction() == MouseMiddleButtonAction::PasteSelection )
+ {
+ // EditView may have pasted from selection
+ pScMod->InputChanged( pEditView );
+ }
+ else
+ pScMod->InputSelection( pEditView ); // parentheses etc.
+
+ mrViewData.GetView()->InvalidateAttribs();
+ rBindings.Invalidate( SID_HYPERLINK_GETLINK );
+ bEEMouse = false;
+ return;
+ }
+
+ if (bDPMouse)
+ {
+ DPMouseButtonUp( rMEvt ); // resets bDPMouse
+ return;
+ }
+
+ if (bRFMouse)
+ {
+ RFMouseMove( rMEvt, true ); // Again the proper range
+ bRFMouse = false;
+ SetPointer( PointerStyle::Arrow );
+ ReleaseMouse();
+ return;
+ }
+
+ if (nPagebreakMouse)
+ {
+ PagebreakMove( rMEvt, true );
+ nPagebreakMouse = SC_PD_NONE;
+ SetPointer( PointerStyle::Arrow );
+ ReleaseMouse();
+ return;
+ }
+
+ if (nMouseStatus == SC_GM_WATERUNDO) // Undo in format paintbrush mode
+ {
+ SfxUndoManager* pMgr = mrViewData.GetDocShell()->GetUndoManager();
+ if ( pMgr->GetUndoActionCount() && dynamic_cast<ScUndoSelectionStyle*>(pMgr->GetUndoAction()) )
+ pMgr->Undo();
+ return;
+ }
+
+ if (DrawMouseButtonUp(rMEvt)) // includes format paint brush handling for drawing objects
+ {
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ SfxBindings& rFrmBindings=pViewShell->GetViewFrame()->GetBindings();
+ rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_WIDTH);
+ rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_HEIGHT);
+ rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_POS_X);
+ rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_POS_Y);
+ rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ANGLE);
+ rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ROT_X);
+ rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_ROT_Y);
+ rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_AUTOWIDTH);
+ rFrmBindings.Invalidate(SID_ATTR_TRANSFORM_AUTOHEIGHT);
+ return;
+ }
+
+ rMark.SetMarking(false);
+
+ SetPointer( mrViewData.IsThemedCursor() ? PointerStyle::FatCross : PointerStyle::Arrow );
+
+ if (mrViewData.IsFillMode() ||
+ ( mrViewData.GetFillMode() == ScFillMode::MATRIX && rMEvt.IsMod1() ))
+ {
+ nScFillModeMouseModifier = rMEvt.GetModifier();
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ mrViewData.GetFillData( nStartCol, nStartRow, nEndCol, nEndRow );
+ ScRange aDelRange;
+ bool bIsDel = mrViewData.GetDelMark( aDelRange );
+
+ ScViewFunc* pView = mrViewData.GetView();
+ pView->StopRefMode();
+ mrViewData.ResetFillMode();
+ pView->GetFunctionSet().SetAnchorFlag( false ); // #i5819# don't use AutoFill anchor flag for selection
+
+ if ( bIsDel )
+ {
+ pView->MarkRange( aDelRange, false );
+ pView->DeleteContents( InsertDeleteFlags::CONTENTS );
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScRange aBlockRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
+ if ( aBlockRange != aDelRange )
+ {
+ if ( aDelRange.aStart.Row() == nStartRow )
+ aBlockRange.aEnd.SetCol( aDelRange.aStart.Col() - 1 );
+ else
+ aBlockRange.aEnd.SetRow( aDelRange.aStart.Row() - 1 );
+ pView->MarkRange( aBlockRange, false );
+ }
+ }
+ else
+ mrViewData.GetDispatcher().Execute( FID_FILL_AUTO, SfxCallMode::SLOT | SfxCallMode::RECORD );
+ }
+ else if (mrViewData.GetFillMode() == ScFillMode::MATRIX)
+ {
+ SCTAB nTab = mrViewData.GetTabNo();
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ mrViewData.GetFillData( nStartCol, nStartRow, nEndCol, nEndRow );
+ ScRange aBlockRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab );
+ SCCOL nFillCol = mrViewData.GetRefEndX();
+ SCROW nFillRow = mrViewData.GetRefEndY();
+ ScAddress aEndPos( nFillCol, nFillRow, nTab );
+
+ ScTabView* pView = mrViewData.GetView();
+ pView->StopRefMode();
+ mrViewData.ResetFillMode();
+ pView->GetFunctionSet().SetAnchorFlag( false );
+
+ if ( aEndPos != aBlockRange.aEnd )
+ {
+ mrViewData.GetDocShell()->GetDocFunc().ResizeMatrix( aBlockRange, aEndPos );
+ mrViewData.GetView()->MarkRange( ScRange( aBlockRange.aStart, aEndPos ) );
+ }
+ }
+ else if (mrViewData.IsAnyFillMode())
+ {
+ // Embedded area has been changed
+ ScTabView* pView = mrViewData.GetView();
+ pView->StopRefMode();
+ mrViewData.ResetFillMode();
+ pView->GetFunctionSet().SetAnchorFlag( false );
+ mrViewData.GetDocShell()->UpdateOle(mrViewData);
+ }
+
+ bool bRefMode = mrViewData.IsRefMode();
+ if (bRefMode)
+ pScMod->EndReference();
+
+ // Format paintbrush mode (Switch)
+
+ if (pScMod->GetIsWaterCan())
+ {
+ // Check on undo already done above
+
+ ScStyleSheetPool* pStylePool = mrViewData.GetDocument().
+ GetStyleSheetPool();
+ if ( pStylePool )
+ {
+ SfxStyleSheet* pStyleSheet = static_cast<SfxStyleSheet*>(
+ pStylePool->GetActualStyleSheet());
+
+ if ( pStyleSheet )
+ {
+ SfxStyleFamily eFamily = pStyleSheet->GetFamily();
+
+ switch ( eFamily )
+ {
+ case SfxStyleFamily::Para:
+ mrViewData.GetView()->SetStyleSheetToMarked( pStyleSheet );
+ mrViewData.GetView()->DoneBlockMode();
+ break;
+
+ case SfxStyleFamily::Page:
+ mrViewData.GetDocument().SetPageStyle( mrViewData.GetTabNo(),
+ pStyleSheet->GetName() );
+
+ ScPrintFunc( mrViewData.GetDocShell(),
+ mrViewData.GetViewShell()->GetPrinter(true),
+ mrViewData.GetTabNo() ).UpdatePages();
+
+ rBindings.Invalidate( SID_STATUS_PAGESTYLE );
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ ScDBFunc* pView = mrViewData.GetView();
+ ScDocument* pBrushDoc = pView->GetBrushDocument();
+ if ( pBrushDoc )
+ {
+ pView->PasteFromClip( InsertDeleteFlags::ATTRIB, pBrushDoc );
+ if ( !pView->IsPaintBrushLocked() )
+ pView->ResetBrushDocument(); // invalidates pBrushDoc pointer
+ }
+
+ Point aPos = rMEvt.GetPosPixel();
+ SCCOL nPosX;
+ SCROW nPosY;
+ SCTAB nTab = mrViewData.GetTabNo();
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor( nPosX, nPosY, nTab );
+
+ bool bInDataPilotTable = (pDPObj != nullptr);
+
+ // double click (only left button)
+ // in the tiled rendering case, single click works this way too
+
+ bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
+ bool bDouble = ( rMEvt.GetClicks() == 2 && rMEvt.IsLeft() );
+ if ((bDouble || (bIsTiledRendering && !bInDataPilotTable))
+ && !bRefMode
+ && (nMouseStatus == SC_GM_DBLDOWN || (bIsTiledRendering && nMouseStatus != SC_GM_URLDOWN))
+ && !pScMod->IsRefDialogOpen())
+ {
+ // data pilot table
+ if ( pDPObj && pDPObj->GetSaveData()->GetDrillDown() )
+ {
+ ScAddress aCellPos( nPosX, nPosY, mrViewData.GetTabNo() );
+
+ // Check for header drill-down first.
+ sheet::DataPilotTableHeaderData aData;
+ pDPObj->GetHeaderPositionData(aCellPos, aData);
+
+ if ( ( aData.Flags & sheet::MemberResultFlags::HASMEMBER ) &&
+ ! ( aData.Flags & sheet::MemberResultFlags::SUBTOTAL ) )
+ {
+ css::sheet::DataPilotFieldOrientation nDummy;
+ if ( pView->HasSelectionForDrillDown( nDummy ) )
+ {
+ // execute slot to show dialog
+ mrViewData.GetDispatcher().Execute( SID_OUTLINE_SHOW, SfxCallMode::SLOT | SfxCallMode::RECORD );
+ }
+ else
+ {
+ // toggle single entry
+ ScDPObject aNewObj( *pDPObj );
+ pDPObj->ToggleDetails( aData, &aNewObj );
+ ScDBDocFunc aFunc( *mrViewData.GetDocShell() );
+ aFunc.DataPilotUpdate( pDPObj, &aNewObj, true, false );
+ mrViewData.GetView()->CursorPosChanged(); // shells may be switched
+ }
+ }
+ else
+ {
+ // Check if the data area is double-clicked.
+
+ Sequence<sheet::DataPilotFieldFilter> aFilters;
+ if ( pDPObj->GetDataFieldPositionData(aCellPos, aFilters) )
+ mrViewData.GetView()->ShowDataPilotSourceData( *pDPObj, aFilters );
+ }
+
+ return;
+ }
+
+ // Check for cell protection attribute.
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ bool bEditAllowed = true;
+ if ( pProtect && pProtect->isProtected() )
+ {
+ bool bCellProtected = rDoc.HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HasAttrFlags::Protected);
+ bool bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
+ bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
+
+ if ( bSkipProtected && bSkipUnprotected )
+ bEditAllowed = false;
+ else if ( (bCellProtected && bSkipProtected) || (!bCellProtected && bSkipUnprotected) )
+ bEditAllowed = false;
+ }
+
+ // We don't want to activate the edit view for a single click in tiled rendering
+ // (but we should probably keep the same behaviour for double clicks).
+ if ( bEditAllowed && (!bIsTiledRendering || bDouble) )
+ {
+ // don't forward the event to an empty cell, causes deselection in
+ // case we used the double-click to select the empty cell
+ if (bIsTiledRendering && bDouble)
+ {
+ ScRefCellValue aCell(mrViewData.GetDocument(), ScAddress(nPosX, nPosY, nTab));
+ if (aCell.isEmpty())
+ return;
+ }
+
+ // edit cell contents
+ mrViewData.GetViewShell()->UpdateInputHandler();
+ pScMod->SetInputMode( SC_INPUT_TABLE );
+ if (mrViewData.HasEditView(eWhich))
+ {
+ // Set text cursor where clicked
+ EditView* pEditView = mrViewData.GetEditView( eWhich );
+ MouseEvent aEditEvt( rMEvt.GetPosPixel(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0 );
+ pEditView->MouseButtonDown( aEditEvt );
+ pEditView->MouseButtonUp( aEditEvt );
+ }
+ }
+
+ if ( bIsTiledRendering && rMEvt.IsLeft() && mrViewData.GetView()->GetSelEngine()->SelMouseButtonUp( rMEvt ) )
+ {
+ mrViewData.GetView()->SelectionChanged();
+ }
+
+ if ( bDouble )
+ return;
+ }
+
+ // Links in edit cells
+
+ bool bAlt = rMEvt.IsMod2();
+ if ( !bAlt && !bRefMode && !bDouble && nMouseStatus == SC_GM_URLDOWN )
+ {
+ // Only execute on ButtonUp, if ButtonDown also was done on a URL
+
+ OUString aName, aUrl, aTarget;
+ if ( GetEditUrl( rMEvt.GetPosPixel(), &aName, &aUrl, &aTarget ) )
+ {
+ nMouseStatus = SC_GM_NONE; // Ignore double-click
+ bool isTiledRendering = comphelper::LibreOfficeKit::isActive();
+ // ScGlobal::OpenURL() only understands Calc A1 style syntax.
+ // Convert it to Calc A1 before calling OpenURL().
+ if (rDoc.GetAddressConvention() == formula::FormulaGrammar::CONV_OOO)
+ {
+ if (aUrl.startsWith("#")) {
+ ScGlobal::OpenURL(aUrl, aTarget, isTiledRendering);
+ return;
+ }
+ // On a mobile device view there is no ctrl+click and for hyperlink popup
+ // the cell coordinates must be sent along with click position for elegance
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ if (isTiledRendering && pViewShell &&
+ (pViewShell->isLOKMobilePhone() || pViewShell->isLOKTablet()))
+ {
+ aPos = rMEvt.GetPosPixel();
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+ OString aCursor = pViewShell->GetViewData().describeCellCursorAt(nPosX, nPosY);
+ double fPPTX = pViewShell->GetViewData().GetPPTX();
+ int mouseX = aPos.X() / fPPTX;
+ OString aMsg(aUrl.toUtf8() + " coordinates: " + aCursor + ", " + OString::number(mouseX));
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_HYPERLINK_CLICKED, aMsg.getStr());
+ } else
+ ScGlobal::OpenURL(aUrl, aTarget);
+ }
+ else
+ {
+ ScAddress aTempAddr;
+ ScAddress::ExternalInfo aExtInfo;
+ ScRefFlags nRes = aTempAddr.Parse(aUrl, rDoc, rDoc.GetAddressConvention(), &aExtInfo);
+ if (!(nRes & ScRefFlags::VALID))
+ {
+ // Not a reference string. Pass it through unmodified.
+ ScGlobal::OpenURL(aUrl, aTarget);
+ return;
+ }
+
+ OUStringBuffer aBuf;
+ if (aExtInfo.mbExternal)
+ {
+ // External reference.
+ ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
+ const OUString* pStr = pRefMgr->getExternalFileName(aExtInfo.mnFileId);
+ if (pStr)
+ aBuf.append(*pStr);
+
+ aBuf.append('#');
+ aBuf.append(aExtInfo.maTabName);
+ aBuf.append('.');
+ OUString aRefCalcA1(aTempAddr.Format(ScRefFlags::ADDR_ABS, nullptr, formula::FormulaGrammar::CONV_OOO));
+ aBuf.append(aRefCalcA1);
+ ScGlobal::OpenURL(aBuf.makeStringAndClear(), aTarget);
+ }
+ else
+ {
+ // Internal reference.
+ aBuf.append('#');
+ OUString aUrlCalcA1(aTempAddr.Format(ScRefFlags::ADDR_ABS_3D, &rDoc, formula::FormulaGrammar::CONV_OOO));
+ aBuf.append(aUrlCalcA1);
+ ScGlobal::OpenURL(aBuf.makeStringAndClear(), aTarget, isTiledRendering);
+ }
+ }
+
+ // fire worksheet_followhyperlink event
+ uno::Reference< script::vba::XVBAEventProcessor > xVbaEvents = rDoc.GetVbaEventProcessor();
+ if( xVbaEvents.is() ) try
+ {
+ aPos = rMEvt.GetPosPixel();
+ nTab = mrViewData.GetTabNo();
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+ OUString sURL;
+ ScRefCellValue aCell;
+ if (lcl_GetHyperlinkCell(rDoc, nPosX, nPosY, nTab, aCell, sURL))
+ {
+ ScAddress aCellPos( nPosX, nPosY, nTab );
+ uno::Reference< table::XCell > xCell( new ScCellObj( mrViewData.GetDocShell(), aCellPos ) );
+ uno::Sequence< uno::Any > aArgs{ uno::Any(xCell) };
+ xVbaEvents->processVbaEvent( script::vba::VBAEventId::WORKSHEET_FOLLOWHYPERLINK, aArgs );
+ }
+ }
+ catch( uno::Exception& )
+ {
+ }
+
+ return;
+ }
+ }
+
+ // Gridwin - SelectionEngine
+
+ // SelMouseButtonDown is called only for left button, but SelMouseButtonUp would return
+ // sal_True for any call, so IsLeft must be checked here, too.
+
+ if ( !(rMEvt.IsLeft() && mrViewData.GetView()->GetSelEngine()->SelMouseButtonUp( rMEvt )) )
+ return;
+
+ mrViewData.GetView()->SelectionChanged();
+
+ SfxDispatcher* pDisp = mrViewData.GetViewShell()->GetDispatcher();
+ bool bFormulaMode = pScMod->IsFormulaMode();
+ OSL_ENSURE( pDisp || bFormulaMode, "Cursor moved on inactive View ?" );
+
+ // #i14927# execute SID_CURRENTCELL (for macro recording) only if there is no
+ // multiple selection, so the argument string completely describes the selection,
+ // and executing the slot won't change the existing selection (executing the slot
+ // here and from a recorded macro is treated equally)
+ if ( pDisp && !bFormulaMode && !rMark.IsMultiMarked() )
+ {
+ OUString aAddr; // CurrentCell
+ if( rMark.IsMarked() )
+ {
+ const ScRange& aScRange = rMark.GetMarkArea();
+ aAddr = aScRange.Format(rDoc, ScRefFlags::RANGE_ABS);
+ if ( aScRange.aStart == aScRange.aEnd )
+ {
+ // make sure there is a range selection string even for a single cell
+ aAddr += ":" + aAddr;
+ }
+
+ //! SID_MARKAREA does not exist anymore ???
+ //! What happens when selecting with the cursor ???
+ }
+ else // only move cursor
+ {
+ ScAddress aScAddress( mrViewData.GetCurX(), mrViewData.GetCurY(), 0 );
+ aAddr = aScAddress.Format(ScRefFlags::ADDR_ABS);
+ }
+
+ SfxStringItem aPosItem( SID_CURRENTCELL, aAddr );
+ // We don't want to align to the cursor position because if the
+ // cell cursor isn't visible after making selection, it would jump
+ // back to the origin of the selection where the cell cursor is.
+ SfxBoolItem aAlignCursorItem( FN_PARAM_2, false );
+ pDisp->ExecuteList(SID_CURRENTCELL,
+ SfxCallMode::SLOT | SfxCallMode::RECORD,
+ { &aPosItem, &aAlignCursorItem });
+
+ mrViewData.GetView()->InvalidateAttribs();
+
+ }
+ mrViewData.GetViewShell()->SelectionChanged();
+
+ return;
+}
+
+void ScGridWindow::FakeButtonUp()
+{
+ if ( nButtonDown )
+ {
+ MouseEvent aEvent( aCurMousePos ); // nButtons = 0 -> ignore
+ MouseButtonUp( aEvent );
+ }
+}
+
+void ScGridWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ aCurMousePos = rMEvt.GetPosPixel();
+
+ if (rMEvt.IsLeaveWindow() && mpNoteMarker && !mpNoteMarker->IsByKeyboard())
+ HideNoteMarker();
+
+ ScModule* pScMod = SC_MOD();
+ if (pScMod->IsModalMode(mrViewData.GetSfxDocShell()))
+ return;
+
+ // If the Drag&Drop is started in the edit mode then sadly nothing else is kept
+ if (bEEMouse && nButtonDown && !rMEvt.GetButtons())
+ {
+ bEEMouse = false;
+ nButtonDown = 0;
+ nMouseStatus = SC_GM_NONE;
+ return;
+ }
+
+ if (nMouseStatus == SC_GM_IGNORE)
+ return;
+
+ if (nMouseStatus == SC_GM_WATERUNDO) // Undo in format paintbrush mode -> only what for Up
+ return;
+
+ if ( mrViewData.GetViewShell()->IsAuditShell() ) // Detective Fill Mode
+ {
+ SetPointer( PointerStyle::Fill );
+ return;
+ }
+
+ bool bFormulaMode = pScMod->IsFormulaMode(); // next click -> reference
+
+ if (bEEMouse && mrViewData.HasEditView( eWhich ))
+ {
+ EditView* pEditView;
+ SCCOL nEditCol;
+ SCROW nEditRow;
+ mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
+ pEditView->MouseMove( rMEvt );
+ return;
+ }
+
+ if (bDPMouse)
+ {
+ DPMouseMove( rMEvt );
+ return;
+ }
+
+ if (bRFMouse)
+ {
+ RFMouseMove( rMEvt, false );
+ return;
+ }
+
+ if (nPagebreakMouse)
+ {
+ PagebreakMove( rMEvt, false );
+ return;
+ }
+
+ // Show other mouse pointer?
+
+ bool bEditMode = mrViewData.HasEditView(eWhich);
+
+ //! Test if refMode dragging !!!
+ if ( bEditMode && (mrViewData.GetRefTabNo() == mrViewData.GetTabNo()) )
+ {
+ Point aPos = rMEvt.GetPosPixel();
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+
+ EditView* pEditView;
+ SCCOL nEditCol;
+ SCROW nEditRow;
+ mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
+ SCCOL nEndCol = mrViewData.GetEditEndCol();
+ SCROW nEndRow = mrViewData.GetEditEndRow();
+
+ if ( nPosX >= nEditCol && nPosX <= nEndCol &&
+ nPosY >= nEditRow && nPosY <= nEndRow )
+ {
+ if ( !pEditView )
+ {
+ SetPointer( PointerStyle::Text );
+ return;
+ }
+
+ const SvxFieldItem* pFld;
+ if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ Point aLogicClick = pEditView->GetOutputDevice().PixelToLogic(aPos);
+ pFld = pEditView->GetField( aLogicClick );
+ }
+ else
+ {
+ pFld = pEditView->GetFieldUnderMousePointer();
+ }
+ // Field can only be URL field
+ bool bAlt = rMEvt.IsMod2();
+ if ( !bAlt && !nButtonDown && ScGlobal::ShouldOpenURL() && pFld )
+ SetPointer( PointerStyle::RefHand );
+ else if ( pEditView->GetEditEngine()->IsEffectivelyVertical() )
+ SetPointer( PointerStyle::TextVertical );
+ else
+ SetPointer( PointerStyle::Text );
+ return;
+ }
+ }
+
+ bool bWater = SC_MOD()->GetIsWaterCan() || mrViewData.GetView()->HasPaintBrush();
+ if (bWater)
+ SetPointer( PointerStyle::Fill );
+
+ if (!bWater)
+ {
+ bool bCross = false;
+
+ // range finder
+
+ RfCorner rCorner = NONE;
+ if ( HitRangeFinder( rMEvt.GetPosPixel(), rCorner, nullptr, nullptr, nullptr ) )
+ {
+ if (rCorner != NONE)
+ SetPointer( PointerStyle::Cross );
+ else
+ SetPointer( PointerStyle::Hand );
+ bCross = true;
+ }
+
+ // Page-Break-Mode
+
+ if ( !nButtonDown && mrViewData.IsPagebreakMode() )
+ {
+ sal_uInt16 nBreakType = HitPageBreak( rMEvt.GetPosPixel(), nullptr, nullptr, nullptr );
+ if (nBreakType != 0 )
+ {
+ PointerStyle eNew = PointerStyle::Arrow;
+ switch ( nBreakType )
+ {
+ case SC_PD_RANGE_L:
+ case SC_PD_RANGE_R:
+ case SC_PD_BREAK_H:
+ eNew = PointerStyle::ESize;
+ break;
+ case SC_PD_RANGE_T:
+ case SC_PD_RANGE_B:
+ case SC_PD_BREAK_V:
+ eNew = PointerStyle::SSize;
+ break;
+ case SC_PD_RANGE_TL:
+ case SC_PD_RANGE_BR:
+ eNew = PointerStyle::SESize;
+ break;
+ case SC_PD_RANGE_TR:
+ case SC_PD_RANGE_BL:
+ eNew = PointerStyle::NESize;
+ break;
+ }
+ SetPointer( eNew );
+ bCross = true;
+ }
+ }
+
+ // Show fill cursor?
+
+ if ( !bFormulaMode && !nButtonDown )
+ if (TestMouse( rMEvt, false ))
+ bCross = true;
+
+ if ( nButtonDown && mrViewData.IsAnyFillMode() )
+ {
+ SetPointer( PointerStyle::Cross );
+ bCross = true;
+ nScFillModeMouseModifier = rMEvt.GetModifier(); // evaluated for AutoFill and Matrix
+ }
+
+ if (!bCross)
+ {
+ bool bAlt = rMEvt.IsMod2();
+
+ if (bEditMode) // First has to be in edit mode!
+ SetPointer( mrViewData.IsThemedCursor() ? PointerStyle::FatCross : PointerStyle::Arrow );
+ else if ( !bAlt && !nButtonDown && ScGlobal::ShouldOpenURL() &&
+ GetEditUrl(rMEvt.GetPosPixel()) )
+ SetPointer( PointerStyle::RefHand );
+ else if ( DrawMouseMove(rMEvt) ) // Reset pointer
+ return;
+ }
+ }
+
+ // In LOK case, avoid spurious "leavingwindow" mouse move events which has negative coordinates.
+ // Such events occur for some reason when a user is selecting a range, (even when not leaving the view area)
+ // with one or more other viewers in that sheet.
+ bool bSkipSelectionUpdate = comphelper::LibreOfficeKit::isActive() &&
+ rMEvt.IsLeaveWindow() && (aCurMousePos.X() < 0 || aCurMousePos.Y() < 0);
+
+ if (!bSkipSelectionUpdate)
+ mrViewData.GetView()->GetSelEngine()->SelMouseMove( rMEvt );
+}
+
+static void lcl_InitMouseEvent(css::awt::MouseEvent& rEvent, const MouseEvent& rEvt)
+{
+ rEvent.Modifiers = 0;
+ if ( rEvt.IsShift() )
+ rEvent.Modifiers |= css::awt::KeyModifier::SHIFT;
+ if ( rEvt.IsMod1() )
+ rEvent.Modifiers |= css::awt::KeyModifier::MOD1;
+ if ( rEvt.IsMod2() )
+ rEvent.Modifiers |= css::awt::KeyModifier::MOD2;
+ if ( rEvt.IsMod3() )
+ rEvent.Modifiers |= css::awt::KeyModifier::MOD3;
+
+ rEvent.Buttons = 0;
+ if ( rEvt.IsLeft() )
+ rEvent.Buttons |= css::awt::MouseButton::LEFT;
+ if ( rEvt.IsRight() )
+ rEvent.Buttons |= css::awt::MouseButton::RIGHT;
+ if ( rEvt.IsMiddle() )
+ rEvent.Buttons |= css::awt::MouseButton::MIDDLE;
+
+ rEvent.X = rEvt.GetPosPixel().X();
+ rEvent.Y = rEvt.GetPosPixel().Y();
+ rEvent.ClickCount = rEvt.GetClicks();
+ rEvent.PopupTrigger = false;
+}
+
+bool ScGridWindow::PreNotify( NotifyEvent& rNEvt )
+{
+ bool bDone = false;
+ MouseNotifyEvent nType = rNEvt.GetType();
+ if ( nType == MouseNotifyEvent::MOUSEBUTTONUP || nType == MouseNotifyEvent::MOUSEBUTTONDOWN )
+ {
+ vcl::Window* pWindow = rNEvt.GetWindow();
+ if (pWindow == this)
+ {
+ SfxViewFrame* pViewFrame = mrViewData.GetViewShell()->GetViewFrame();
+ if (pViewFrame)
+ {
+ css::uno::Reference<css::frame::XController> xController = pViewFrame->GetFrame().GetController();
+ if (xController.is())
+ {
+ ScTabViewObj* pImp = comphelper::getFromUnoTunnel<ScTabViewObj>( xController );
+ if (pImp && pImp->IsMouseListening())
+ {
+ css::awt::MouseEvent aEvent;
+ lcl_InitMouseEvent( aEvent, *rNEvt.GetMouseEvent() );
+ if ( rNEvt.GetWindow() )
+ aEvent.Source = rNEvt.GetWindow()->GetComponentInterface();
+ if ( nType == MouseNotifyEvent::MOUSEBUTTONDOWN)
+ bDone = pImp->MousePressed( aEvent );
+ else
+ bDone = pImp->MouseReleased( aEvent );
+ }
+ }
+ }
+ }
+ }
+ if (bDone) // event consumed by a listener
+ {
+ if ( nType == MouseNotifyEvent::MOUSEBUTTONDOWN )
+ {
+ const MouseEvent* pMouseEvent = rNEvt.GetMouseEvent();
+ if ( pMouseEvent->IsRight() && pMouseEvent->GetClicks() == 1 )
+ {
+ // If a listener returned true for a right-click call, also prevent opening the context menu
+ // (this works only if the context menu is opened on mouse-down)
+ nMouseStatus = SC_GM_IGNORE;
+ }
+ }
+
+ return true;
+ }
+ else
+ return Window::PreNotify( rNEvt );
+}
+
+void ScGridWindow::Tracking( const TrackingEvent& rTEvt )
+{
+ // Since the SelectionEngine does not track, the events have to be
+ // handed to the different MouseHandler...
+
+ const MouseEvent& rMEvt = rTEvt.GetMouseEvent();
+
+ if ( rTEvt.IsTrackingCanceled() ) // Cancel everything...
+ {
+ if (!mrViewData.GetView()->IsInActivatePart() && !SC_MOD()->IsRefDialogOpen())
+ {
+ if (bDPMouse)
+ bDPMouse = false; // Paint for each bDragRect
+ if (bDragRect)
+ {
+ bDragRect = false;
+ UpdateDragRectOverlay();
+ }
+ if (bRFMouse)
+ {
+ RFMouseMove( rMEvt, true ); // Not possible to cancel properly...
+ bRFMouse = false;
+ }
+ if (nPagebreakMouse)
+ {
+ bPagebreakDrawn = false;
+ UpdateDragRectOverlay();
+ nPagebreakMouse = SC_PD_NONE;
+ }
+
+ SetPointer( PointerStyle::Arrow );
+ StopMarking();
+ MouseButtonUp( rMEvt ); // With status SC_GM_IGNORE from StopMarking
+
+ bool bRefMode = mrViewData.IsRefMode();
+ if (bRefMode)
+ SC_MOD()->EndReference(); // Do not let the Dialog remain minimized
+ }
+ }
+ else if ( rTEvt.IsTrackingEnded() )
+ {
+ // MouseButtonUp always with matching buttons (eg for test tool, # 63148 #)
+ // The tracking event will indicate if it was completed and not canceled.
+ MouseEvent aUpEvt( rMEvt.GetPosPixel(), rMEvt.GetClicks(),
+ rMEvt.GetMode(), nButtonDown, rMEvt.GetModifier() );
+ MouseButtonUp( aUpEvt );
+ }
+ else
+ MouseMove( rMEvt );
+}
+
+void ScGridWindow::StartDrag( sal_Int8 /* nAction */, const Point& rPosPixel )
+{
+ if (mpFilterBox || nPagebreakMouse)
+ return;
+
+ HideNoteMarker();
+
+ CommandEvent aDragEvent( rPosPixel, CommandEventId::StartDrag, true );
+
+ if (bEEMouse && mrViewData.HasEditView( eWhich ))
+ {
+ EditView* pEditView;
+ SCCOL nEditCol;
+ SCROW nEditRow;
+ mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
+
+ // don't remove the edit view while switching views
+ ScModule* pScMod = SC_MOD();
+ pScMod->SetInEditCommand( true );
+
+ pEditView->Command( aDragEvent );
+
+ ScInputHandler* pHdl = pScMod->GetInputHdl();
+ if (pHdl)
+ pHdl->DataChanged();
+
+ pScMod->SetInEditCommand( false );
+ if (!mrViewData.IsActive()) // dropped to different view?
+ {
+ ScInputHandler* pViewHdl = pScMod->GetInputHdl( mrViewData.GetViewShell() );
+ if ( pViewHdl && mrViewData.HasEditView( eWhich ) )
+ {
+ pViewHdl->CancelHandler();
+ ShowCursor(); // missing from KillEditView
+ }
+ }
+ }
+ else
+ if ( !DrawCommand(aDragEvent) )
+ mrViewData.GetView()->GetSelEngine()->Command( aDragEvent );
+}
+
+static void lcl_SetTextCursorPos( ScViewData& rViewData, ScSplitPos eWhich, vcl::Window* pWin )
+{
+ SCCOL nCol = rViewData.GetCurX();
+ SCROW nRow = rViewData.GetCurY();
+ tools::Rectangle aEditArea = rViewData.GetEditArea( eWhich, nCol, nRow, pWin, nullptr, true );
+ aEditArea.SetRight( aEditArea.Left() );
+ aEditArea = pWin->PixelToLogic( aEditArea );
+ pWin->SetCursorRect( &aEditArea );
+}
+
+void ScGridWindow::Command( const CommandEvent& rCEvt )
+{
+ // 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.
+ CommandEventId nCmd = rCEvt.GetCommand();
+ ScTabViewShell* pTabViewSh = mrViewData.GetViewShell();
+ SfxInPlaceClient* pClient = pTabViewSh->GetIPClient();
+ if ( pClient &&
+ pClient->IsObjectInPlaceActive() &&
+ nCmd == CommandEventId::ContextMenu )
+ {
+ pTabViewSh->DeactivateOle();
+ return;
+ }
+
+ ScModule* pScMod = SC_MOD();
+ OSL_ENSURE( nCmd != CommandEventId::StartDrag, "ScGridWindow::Command called with CommandEventId::StartDrag" );
+
+ if (nCmd == CommandEventId::ModKeyChange)
+ {
+ Window::Command(rCEvt);
+ return;
+ }
+
+ if ( nCmd == CommandEventId::StartExtTextInput ||
+ nCmd == CommandEventId::EndExtTextInput ||
+ nCmd == CommandEventId::ExtTextInput ||
+ nCmd == CommandEventId::CursorPos ||
+ nCmd == CommandEventId::QueryCharPosition )
+ {
+ bool bEditView = mrViewData.HasEditView( eWhich );
+ if (!bEditView)
+ {
+ // only if no cell editview is active, look at drawview
+ SdrView* pSdrView = mrViewData.GetView()->GetScDrawView();
+ if ( pSdrView )
+ {
+ OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView();
+ if ( pOlView && pOlView->GetWindow() == this )
+ {
+ pOlView->Command( rCEvt );
+ return; // done
+ }
+ }
+ }
+
+ if ( nCmd == CommandEventId::CursorPos && !bEditView )
+ {
+ // CURSORPOS may be called without following text input,
+ // to set the input method window position
+ // -> input mode must not be started,
+ // manually calculate text insert position if not in input mode
+
+ lcl_SetTextCursorPos( mrViewData, eWhich, this );
+ return;
+ }
+
+ ScInputHandler* pHdl = pScMod->GetInputHdl( mrViewData.GetViewShell() );
+ if ( pHdl )
+ {
+ pHdl->InputCommand( rCEvt );
+ return; // done
+ }
+
+ Window::Command( rCEvt );
+ return;
+ }
+
+ if ( nCmd == CommandEventId::PasteSelection )
+ {
+ if ( bEEMouse )
+ {
+ // EditEngine handles selection in MouseButtonUp - no action
+ // needed in command handler
+ }
+ else
+ {
+ PasteSelection( rCEvt.GetMousePosPixel() );
+ }
+ return;
+ }
+
+ if ( nCmd == CommandEventId::InputLanguageChange )
+ {
+ // #i55929# Font and font size state depends on input language if nothing is selected,
+ // so the slots have to be invalidated when the input language is changed.
+
+ SfxBindings& rBindings = mrViewData.GetBindings();
+ rBindings.Invalidate( SID_ATTR_CHAR_FONT );
+ rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ return;
+ }
+
+ if ( nCmd == CommandEventId::Wheel || nCmd == CommandEventId::StartAutoScroll || nCmd == CommandEventId::AutoScroll )
+ {
+ bool bDone = mrViewData.GetView()->ScrollCommand( rCEvt, eWhich );
+ if (!bDone)
+ Window::Command(rCEvt);
+ return;
+ }
+ // #i7560# FormulaMode check is below scrolling - scrolling is allowed during formula input
+ bool bDisable = pScMod->IsFormulaMode() ||
+ pScMod->IsModalMode(mrViewData.GetSfxDocShell());
+ if (bDisable)
+ return;
+
+ if (nCmd != CommandEventId::ContextMenu || SC_MOD()->GetIsWaterCan())
+ return;
+
+ bool bMouse = rCEvt.IsMouseEvent();
+ if ( bMouse && nMouseStatus == SC_GM_IGNORE )
+ return;
+
+ if (mrViewData.IsAnyFillMode())
+ {
+ mrViewData.GetView()->StopRefMode();
+ mrViewData.ResetFillMode();
+ }
+ ReleaseMouse();
+ StopMarking();
+
+ Point aPosPixel = rCEvt.GetMousePosPixel();
+ Point aMenuPos = aPosPixel;
+
+ bool bPosIsInEditView = mrViewData.HasEditView(eWhich);
+ SCCOL nCellX = -1;
+ SCROW nCellY = -1;
+ mrViewData.GetPosFromPixel(aPosPixel.X(), aPosPixel.Y(), eWhich, nCellX, nCellY);
+ // GetPosFromPixel ignores the fact that when editing a cell, the cell might grow to cover
+ // other rows/columns. In addition, the mouse might now be outside the edited cell.
+ if (bPosIsInEditView)
+ {
+ if (nCellX >= mrViewData.GetEditViewCol() && nCellX <= mrViewData.GetEditEndCol())
+ nCellX = mrViewData.GetEditViewCol();
+ else
+ bPosIsInEditView = false;
+
+ if (nCellY >= mrViewData.GetEditViewRow() && nCellY <= mrViewData.GetEditEndRow())
+ nCellY = mrViewData.GetEditViewRow();
+ else
+ bPosIsInEditView = false;
+
+ if (!bPosIsInEditView)
+ {
+ // Close the edit view when moving outside of the edited cell
+ // to avoid showing the edit popup, or providing the wrong EditView to spellcheck.
+ ScInputHandler* pHdl = pScMod->GetInputHdl();
+ if (pHdl)
+ pHdl->EnterHandler();
+ }
+ }
+
+ bool bSpellError = false;
+ SCCOL nColSpellError = nCellX;
+
+ if ( bMouse )
+ {
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ bool bSelectAllowed = true;
+ if ( pProtect && pProtect->isProtected() )
+ {
+ // This sheet is protected. Check if a context menu is allowed on this cell.
+ bool bCellProtected = rDoc.HasAttrib(nCellX, nCellY, nTab, nCellX, nCellY, nTab, HasAttrFlags::Protected);
+ bool bSelProtected = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
+ bool bSelUnprotected = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
+
+ if (bCellProtected)
+ bSelectAllowed = bSelProtected;
+ else
+ bSelectAllowed = bSelUnprotected;
+ }
+ if (!bSelectAllowed)
+ // Selecting this cell is not allowed, neither is context menu.
+ return;
+
+ if (mpSpellCheckCxt)
+ {
+ // Find the first string to the left for spell checking in case the current cell is empty.
+ ScAddress aPos(nCellX, nCellY, nTab);
+ ScRefCellValue aSpellCheckCell(rDoc, aPos);
+ while (!bPosIsInEditView && aSpellCheckCell.meType == CELLTYPE_NONE)
+ {
+ // Loop until we get the first non-empty cell in the row.
+ aPos.IncCol(-1);
+ if (aPos.Col() < 0)
+ break;
+
+ aSpellCheckCell.assign(rDoc, aPos);
+ }
+
+ if (aPos.Col() >= 0 && (aSpellCheckCell.meType == CELLTYPE_STRING || aSpellCheckCell.meType == CELLTYPE_EDIT))
+ nColSpellError = aPos.Col();
+
+ // Is there a misspelled word somewhere in the cell?
+ // A "yes" does not mean that the word under the mouse pointer is wrong though.
+ bSpellError = (mpSpellCheckCxt->isMisspelled(nColSpellError, nCellY));
+ }
+
+ // #i18735# First select the item under the mouse pointer.
+ // This can change the selection, and the view state (edit mode, etc).
+ SelectForContextMenu(aPosPixel, bSpellError ? nColSpellError : nCellX, nCellY);
+ }
+
+ bool bDone = false;
+ bool bEdit = mrViewData.HasEditView(eWhich);
+
+ if ( !bEdit )
+ {
+ // Edit cell with spelling errors?
+ // tdf#127341 the formerly used GetEditUrl(aPosPixel) additionally
+ // to bSpellError activated EditMode here for right-click on URL
+ // which prevents the regular context-menu from appearing. Since this
+ // is more expected than the context-menu for editing an URL, I removed
+ // this. If this was wanted and can be argued it might be re-activated.
+ // For now, reduce to spelling errors - as the original comment above
+ // suggests.
+ if (bMouse && bSpellError)
+ {
+ // GetEditUrlOrError has already moved the Cursor
+
+ pScMod->SetInputMode( SC_INPUT_TABLE );
+ bEdit = mrViewData.HasEditView(eWhich); // Did it work?
+
+ OSL_ENSURE( bEdit, "Can not be switched in edit mode" );
+ }
+ }
+ if ( bEdit )
+ {
+ EditView* pEditView = mrViewData.GetEditView( eWhich ); // is then not 0
+
+ if ( !bMouse )
+ {
+ vcl::Cursor* pCur = pEditView->GetCursor();
+ if ( pCur )
+ {
+ Point aLogicPos = pCur->GetPos();
+ // use the position right of the cursor (spell popup is opened if
+ // the cursor is before the word, but not if behind it)
+ aLogicPos.AdjustX(pCur->GetWidth() );
+ aLogicPos.AdjustY(pCur->GetHeight() / 2 ); // center vertically
+ aMenuPos = LogicToPixel( aLogicPos );
+ }
+ }
+
+ // if edit mode was just started above, online spelling may be incomplete
+ pEditView->GetEditEngine()->CompleteOnlineSpelling();
+
+ // IsCursorAtWrongSpelledWord could be used for !bMouse
+ // if there was a corresponding ExecuteSpellPopup call
+
+ if (bSpellError)
+ {
+ // On OS/2 when clicking next to the Popup menu, the MouseButtonDown
+ // comes before the end of menu execute, thus the SetModified has to
+ // be done prior to this (Bug #40968#)
+ ScInputHandler* pHdl = pScMod->GetInputHdl();
+ if (pHdl)
+ pHdl->SetModified();
+
+ const OUString sOldText = pHdl ? pHdl->GetEditString() : "";
+
+ // Only done/shown if a misspelled word is actually under the mouse pointer.
+ Link<SpellCallbackInfo&,void> aLink = LINK( this, ScGridWindow, PopupSpellingHdl );
+ bDone = pEditView->ExecuteSpellPopup(aMenuPos, aLink);
+
+ // If the spelling is corrected, stop editing to flush any cached spelling info.
+ // Or, if no misspelled word at this position, and it wasn't initially in edit mode,
+ // then exit the edit mode in order to get the full context popup (not edit popup).
+ if (pHdl && (pHdl->GetEditString() != sOldText
+ || (!bDone && !bPosIsInEditView)))
+ {
+ pHdl->EnterHandler();
+ }
+
+ if (!bDone && nColSpellError != nCellX)
+ {
+ // NOTE: This call can change the selection, and the view state (edit mode, etc).
+ SelectForContextMenu(aPosPixel, nCellX, nCellY);
+ }
+ }
+ }
+ else if ( !bMouse )
+ {
+ // non-edit menu by keyboard -> use lower right of cell cursor position
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTabNo = mrViewData.GetTabNo();
+ bool bLayoutIsRTL = rDoc.IsLayoutRTL(nTabNo);
+
+ SCCOL nCurX = mrViewData.GetCurX();
+ SCROW nCurY = mrViewData.GetCurY();
+ aMenuPos = mrViewData.GetScrPos( nCurX, nCurY, eWhich, true );
+ tools::Long nSizeXPix;
+ tools::Long nSizeYPix;
+ mrViewData.GetMergeSizePixel( nCurX, nCurY, nSizeXPix, nSizeYPix );
+ // fdo#55432 take the correct position for RTL sheet
+ aMenuPos.AdjustX(bLayoutIsRTL ? -nSizeXPix : nSizeXPix );
+ aMenuPos.AdjustY(nSizeYPix );
+
+ ScTabViewShell* pViewSh = mrViewData.GetViewShell();
+ if (pViewSh)
+ {
+ // Is a draw object selected?
+
+ SdrView* pDrawView = pViewSh->GetScDrawView();
+ if (pDrawView && pDrawView->AreObjectsMarked())
+ {
+ // #100442#; the context menu should open in the middle of the selected objects
+ tools::Rectangle aSelectRect(LogicToPixel(pDrawView->GetAllMarkedBoundRect()));
+ aMenuPos = aSelectRect.Center();
+ }
+ }
+ }
+
+ if (bDone)
+ return;
+
+ // tdf#140361 at this context menu popup time get what the
+ // DisableEditHyperlink would be for this position
+ bool bShouldDisableEditHyperlink = mrViewData.GetViewShell()->ShouldDisableEditHyperlink();
+
+ SfxDispatcher::ExecutePopup( this, &aMenuPos );
+
+ if (!bShouldDisableEditHyperlink)
+ {
+ SfxBindings& rBindings = mrViewData.GetBindings();
+ // tdf#140361 set what the menu popup state for this was
+ mrViewData.GetViewShell()->EnableEditHyperlink();
+ // ensure moAtContextMenu_DisableEditHyperlink will be cleared
+ // in the case that EditHyperlink is not dispatched by the menu
+ rBindings.Invalidate(SID_EDIT_HYPERLINK);
+ }
+}
+
+void ScGridWindow::SelectForContextMenu( const Point& rPosPixel, SCCOL nCellX, SCROW nCellY )
+{
+ // #i18735# if the click was outside of the current selection,
+ // the cursor is moved or an object at the click position selected.
+ // (see SwEditWin::SelectMenuPosition in Writer)
+
+ ScTabView* pView = mrViewData.GetView();
+ ScDrawView* pDrawView = pView->GetScDrawView();
+
+ // check cell edit mode
+
+ if ( mrViewData.HasEditView(eWhich) )
+ {
+ ScModule* pScMod = SC_MOD();
+ SCCOL nEditStartCol = mrViewData.GetEditViewCol(); //! change to GetEditStartCol after calcrtl is integrated
+ SCROW nEditStartRow = mrViewData.GetEditViewRow();
+ SCCOL nEditEndCol = mrViewData.GetEditEndCol();
+ SCROW nEditEndRow = mrViewData.GetEditEndRow();
+
+ if ( nCellX >= nEditStartCol && nCellX <= nEditEndCol &&
+ nCellY >= nEditStartRow && nCellY <= nEditEndRow )
+ {
+ // handle selection within the EditView
+
+ EditView* pEditView = mrViewData.GetEditView( eWhich ); // not NULL (HasEditView)
+ EditEngine* pEditEngine = pEditView->GetEditEngine();
+ tools::Rectangle aOutputArea = pEditView->GetOutputArea();
+ tools::Rectangle aVisArea = pEditView->GetVisArea();
+
+ Point aTextPos = PixelToLogic( rPosPixel );
+ if ( pEditEngine->IsEffectivelyVertical() ) // have to manually transform position
+ {
+ aTextPos -= aOutputArea.TopRight();
+ tools::Long nTemp = -aTextPos.X();
+ aTextPos.setX( aTextPos.Y() );
+ aTextPos.setY( nTemp );
+ }
+ else
+ aTextPos -= aOutputArea.TopLeft();
+ aTextPos += aVisArea.TopLeft(); // position in the edit document
+
+ EPosition aDocPosition = pEditEngine->FindDocPosition(aTextPos);
+ ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex);
+ ESelection aSelection = pEditView->GetSelection();
+ aSelection.Adjust(); // needed for IsLess/IsGreater
+ if ( aCompare < aSelection || aCompare > aSelection )
+ {
+ // clicked outside the selected text - deselect and move text cursor
+ MouseEvent aEvent( rPosPixel );
+ pEditView->MouseButtonDown( aEvent );
+ pEditView->MouseButtonUp( aEvent );
+ pScMod->InputSelection( pEditView );
+ }
+
+ return; // clicked within the edit view - keep edit mode
+ }
+ else
+ {
+ // outside of the edit view - end edit mode, regardless of cell selection, then continue
+ pScMod->InputEnterHandler();
+ }
+ }
+
+ // check draw text edit mode
+
+ Point aLogicPos = PixelToLogic( rPosPixel ); // after cell edit mode is ended
+ if ( pDrawView && pDrawView->GetTextEditObject() && pDrawView->GetTextEditOutlinerView() )
+ {
+ OutlinerView* pOlView = pDrawView->GetTextEditOutlinerView();
+ tools::Rectangle aOutputArea = pOlView->GetOutputArea();
+ if ( aOutputArea.Contains( aLogicPos ) )
+ {
+ // handle selection within the OutlinerView
+
+ Outliner* pOutliner = pOlView->GetOutliner();
+ const EditEngine& rEditEngine = pOutliner->GetEditEngine();
+ tools::Rectangle aVisArea = pOlView->GetVisArea();
+
+ Point aTextPos = aLogicPos;
+ if ( pOutliner->IsVertical() ) // have to manually transform position
+ {
+ aTextPos -= aOutputArea.TopRight();
+ tools::Long nTemp = -aTextPos.X();
+ aTextPos.setX( aTextPos.Y() );
+ aTextPos.setY( nTemp );
+ }
+ else
+ aTextPos -= aOutputArea.TopLeft();
+ aTextPos += aVisArea.TopLeft(); // position in the edit document
+
+ EPosition aDocPosition = rEditEngine.FindDocPosition(aTextPos);
+ ESelection aCompare(aDocPosition.nPara, aDocPosition.nIndex);
+ ESelection aSelection = pOlView->GetSelection();
+ aSelection.Adjust(); // needed for IsLess/IsGreater
+ if ( aCompare < aSelection || aCompare > aSelection )
+ {
+ // clicked outside the selected text - deselect and move text cursor
+ // use DrawView to allow extra handling there (none currently)
+ MouseEvent aEvent( rPosPixel );
+ pDrawView->MouseButtonDown( aEvent, GetOutDev() );
+ pDrawView->MouseButtonUp( aEvent, GetOutDev() );
+ }
+
+ return; // clicked within the edit area - keep edit mode
+ }
+ else
+ {
+ // Outside of the edit area - end text edit mode, then continue.
+ // DrawDeselectAll also ends text edit mode and updates the shells.
+ // If the click was on the edited object, it will be selected again below.
+ pView->DrawDeselectAll();
+ }
+ }
+
+ // look for existing selection
+
+ bool bHitSelected = false;
+ if ( pDrawView && pDrawView->IsMarkedObjHit( aLogicPos ) )
+ {
+ // clicked on selected object -> don't change anything
+ bHitSelected = true;
+ }
+ else if ( mrViewData.GetMarkData().IsCellMarked(nCellX, nCellY) )
+ {
+ // clicked on selected cell -> don't change anything
+ bHitSelected = true;
+ }
+
+ // select drawing object or move cell cursor
+
+ if ( bHitSelected )
+ return;
+
+ bool bWasDraw = ( pDrawView && pDrawView->AreObjectsMarked() );
+ bool bHitDraw = false;
+ if ( pDrawView )
+ {
+ pDrawView->UnmarkAllObj();
+ // Unlock the Internal Layer in order to activate the context menu.
+ // re-lock in ScDrawView::MarkListHasChanged()
+ lcl_UnLockComment(pDrawView, aLogicPos, mrViewData);
+ bHitDraw = pDrawView->MarkObj( aLogicPos );
+ // draw shell is activated in MarkListHasChanged
+ }
+ if ( !bHitDraw )
+ {
+ pView->Unmark();
+ pView->SetCursor(nCellX, nCellY);
+ if ( bWasDraw )
+ mrViewData.GetViewShell()->SetDrawShell( false ); // switch shells
+ }
+}
+
+void ScGridWindow::KeyInput(const KeyEvent& rKEvt)
+{
+ // Cursor control for ref input dialog
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+
+#ifdef DBG_UTIL
+
+ if (rKeyCode.IsMod1() && rKeyCode.IsShift())
+ {
+ if (rKeyCode.GetCode() == KEY_F12)
+ {
+ dumpColumnInformationPixel();
+ }
+ else if (rKeyCode.GetCode() == KEY_F11)
+ {
+ dumpGraphicInformation();
+ }
+ else if (rKeyCode.GetCode() == KEY_F10)
+ {
+ dumpColumnInformationHmm();
+ }
+ else if (rKeyCode.GetCode() == KEY_F6)
+ {
+ dumpCellProperties();
+ }
+ else if (rKeyCode.GetCode() == KEY_F8)
+ {
+ dumpColumnCellStorage();
+ }
+ else if (rKeyCode.GetCode() == KEY_F7)
+ {
+ ScDocument& rDoc = mrViewData.GetDocument();
+ auto& rMapper = rDoc.GetExternalDataMapper();
+ for (auto& itr : rMapper.getDataSources())
+ {
+ itr.refresh(&rDoc);
+ }
+ return;
+ }
+ }
+
+#endif
+
+ if( SC_MOD()->IsRefDialogOpen() )
+ {
+ if( !rKeyCode.GetModifier() && (rKeyCode.GetCode() == KEY_F2) )
+ {
+ SC_MOD()->EndReference();
+ }
+ else if( mrViewData.GetViewShell()->MoveCursorKeyInput( rKEvt ) )
+ {
+ ScRange aRef(
+ mrViewData.GetRefStartX(), mrViewData.GetRefStartY(), mrViewData.GetRefStartZ(),
+ mrViewData.GetRefEndX(), mrViewData.GetRefEndY(), mrViewData.GetRefEndZ() );
+ SC_MOD()->SetReference( aRef, mrViewData.GetDocument() );
+ }
+ mrViewData.GetViewShell()->SelectionChanged();
+ return ;
+ }
+ else if( rKeyCode.GetCode() == KEY_RETURN && mrViewData.IsPasteMode()
+ && SC_MOD()->GetInputOptions().GetEnterPasteMode() )
+ {
+ ScTabViewShell* pTabViewShell = mrViewData.GetViewShell();
+ ScClipUtil::PasteFromClipboard( mrViewData, pTabViewShell, true );
+
+ // Clear clipboard content.
+ uno::Reference<datatransfer::clipboard::XClipboard> xSystemClipboard =
+ GetClipboard();
+ if (xSystemClipboard.is())
+ {
+ xSystemClipboard->setContents(
+ uno::Reference<datatransfer::XTransferable>(),
+ uno::Reference<datatransfer::clipboard::XClipboardOwner>());
+ }
+
+ // hide the border around the copy source
+ mrViewData.SetPasteMode( ScPasteFlags::NONE );
+ // Clear CopySourceOverlay in each window of a split/frozen tabview
+ mrViewData.GetView()->UpdateCopySourceOverlay();
+ return;
+ }
+ // if semi-modeless SfxChildWindow dialog above, then no KeyInputs:
+ else if( !mrViewData.IsAnyFillMode() )
+ {
+ if (rKeyCode.GetCode() == KEY_ESCAPE)
+ {
+ mrViewData.SetPasteMode( ScPasteFlags::NONE );
+ // Clear CopySourceOverlay in each window of a split/frozen tabview
+ mrViewData.GetView()->UpdateCopySourceOverlay();
+ }
+ // query for existing note marker before calling ViewShell's keyboard handling
+ // which may remove the marker
+ bool bHadKeyMarker = mpNoteMarker && mpNoteMarker->IsByKeyboard();
+ ScTabViewShell* pViewSh = mrViewData.GetViewShell();
+
+ if (mrViewData.GetDocShell()->GetProgress())
+ return;
+
+ if (DrawKeyInput(rKEvt, this))
+ {
+ const vcl::KeyCode& rLclKeyCode = rKEvt.GetKeyCode();
+ if (rLclKeyCode.GetCode() == KEY_DOWN
+ || rLclKeyCode.GetCode() == KEY_UP
+ || rLclKeyCode.GetCode() == KEY_LEFT
+ || rLclKeyCode.GetCode() == KEY_RIGHT)
+ {
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ SfxBindings& rBindings = pViewShell->GetViewFrame()->GetBindings();
+ rBindings.Invalidate(SID_ATTR_TRANSFORM_POS_X);
+ rBindings.Invalidate(SID_ATTR_TRANSFORM_POS_Y);
+ }
+ return;
+ }
+
+ if (!mrViewData.GetView()->IsDrawSelMode() && !DrawHasMarkedObj()) // No entries in draw mode
+ { //! check DrawShell !!!
+ if (pViewSh->TabKeyInput(rKEvt))
+ return;
+ }
+ else
+ if (pViewSh->SfxViewShell::KeyInput(rKEvt)) // from SfxViewShell
+ return;
+
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+ if ( aCode.GetCode() == KEY_ESCAPE && aCode.GetModifier() == 0 )
+ {
+ if ( bHadKeyMarker )
+ HideNoteMarker();
+ else
+ pViewSh->Escape();
+ return;
+ }
+ if ( aCode.GetCode() == KEY_F1 && aCode.GetModifier() == KEY_MOD1 )
+ {
+ // ctrl-F1 shows or hides the note or redlining info for the cursor position
+ // (hard-coded because F1 can't be configured)
+
+ if ( bHadKeyMarker )
+ HideNoteMarker(); // hide when previously visible
+ else
+ ShowNoteMarker( mrViewData.GetCurX(), mrViewData.GetCurY(), true );
+ return;
+ }
+ if (aCode.GetCode() == KEY_BRACKETLEFT && aCode.GetModifier() == KEY_MOD1)
+ {
+ pViewSh->DetectiveMarkPred();
+ return;
+ }
+ if (aCode.GetCode() == KEY_BRACKETRIGHT && aCode.GetModifier() == KEY_MOD1)
+ {
+ pViewSh->DetectiveMarkSucc();
+ return;
+ }
+
+ }
+
+ Window::KeyInput(rKEvt);
+}
+
+OUString ScGridWindow::GetSurroundingText() const
+{
+ bool bEditView = mrViewData.HasEditView(eWhich);
+ if (bEditView)
+ {
+ ScModule* pScMod = SC_MOD();
+ ScInputHandler* pHdl = pScMod->GetInputHdl(mrViewData.GetViewShell());
+ if (pHdl)
+ return pHdl->GetSurroundingText();
+ }
+ else if (SdrView* pSdrView = mrViewData.GetView()->GetScDrawView())
+ {
+ // if no cell editview is active, look at drawview
+ OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView();
+ if (pOlView && pOlView->GetWindow() == this)
+ return pOlView->GetSurroundingText();
+ }
+
+ return Window::GetSurroundingText();
+}
+
+Selection ScGridWindow::GetSurroundingTextSelection() const
+{
+ bool bEditView = mrViewData.HasEditView(eWhich);
+ if (bEditView)
+ {
+ ScModule* pScMod = SC_MOD();
+ ScInputHandler* pHdl = pScMod->GetInputHdl(mrViewData.GetViewShell());
+ if (pHdl)
+ return pHdl->GetSurroundingTextSelection();
+ }
+ else if (SdrView* pSdrView = mrViewData.GetView()->GetScDrawView())
+ {
+ // if no cell editview is active, look at drawview
+ OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView();
+ if (pOlView && pOlView->GetWindow() == this)
+ return pOlView->GetSurroundingTextSelection();
+ }
+
+ return Window::GetSurroundingTextSelection();
+}
+
+bool ScGridWindow::DeleteSurroundingText(const Selection& rSelection)
+{
+ bool bEditView = mrViewData.HasEditView(eWhich);
+ if (bEditView)
+ {
+ ScModule* pScMod = SC_MOD();
+ ScInputHandler* pHdl = pScMod->GetInputHdl(mrViewData.GetViewShell());
+ if (pHdl)
+ return pHdl->DeleteSurroundingText(rSelection);
+ }
+ else if (SdrView* pSdrView = mrViewData.GetView()->GetScDrawView())
+ {
+ // if no cell editview is active, look at drawview
+ OutlinerView* pOlView = pSdrView->GetTextEditOutlinerView();
+ if (pOlView && pOlView->GetWindow() == this)
+ return pOlView->DeleteSurroundingText(rSelection);
+ }
+
+ return Window::DeleteSurroundingText(rSelection);
+}
+
+void ScGridWindow::StopMarking()
+{
+ DrawEndAction(); // Cancel Select/move on Drawing-Layer
+
+ if (nButtonDown)
+ {
+ mrViewData.GetMarkData().SetMarking(false);
+ nMouseStatus = SC_GM_IGNORE;
+ }
+}
+
+void ScGridWindow::UpdateInputContext()
+{
+ bool bReadOnly = mrViewData.GetDocShell()->IsReadOnly();
+ InputContextFlags nOptions = bReadOnly ? InputContextFlags::NONE : ( InputContextFlags::Text | InputContextFlags::ExtText );
+
+ // when font from InputContext is used,
+ // it must be taken from the cursor position's cell attributes
+
+ InputContext aContext;
+ aContext.SetOptions( nOptions );
+ SetInputContext( aContext );
+}
+
+ // sensitive range (Pixel)
+#define SCROLL_SENSITIVE 20
+
+void ScGridWindow::DropScroll( const Point& rMousePos )
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCCOL nDx = 0;
+ SCROW nDy = 0;
+ Size aSize = GetOutputSizePixel();
+
+ if (aSize.Width() > SCROLL_SENSITIVE * 3)
+ {
+ if ( rMousePos.X() < SCROLL_SENSITIVE && mrViewData.GetPosX(WhichH(eWhich)) > 0 )
+ nDx = -1;
+ if ( rMousePos.X() >= aSize.Width() - SCROLL_SENSITIVE
+ && mrViewData.GetPosX(WhichH(eWhich)) < rDoc.MaxCol() )
+ nDx = 1;
+ }
+ if (aSize.Height() > SCROLL_SENSITIVE * 3)
+ {
+ if ( rMousePos.Y() < SCROLL_SENSITIVE && mrViewData.GetPosY(WhichV(eWhich)) > 0 )
+ nDy = -1;
+ if ( rMousePos.Y() >= aSize.Height() - SCROLL_SENSITIVE
+ && mrViewData.GetPosY(WhichV(eWhich)) < rDoc.MaxRow() )
+ nDy = 1;
+ }
+
+ if ( nDx != 0 || nDy != 0 )
+ {
+ if ( nDx != 0 )
+ mrViewData.GetView()->ScrollX( nDx, WhichH(eWhich) );
+ if ( nDy != 0 )
+ mrViewData.GetView()->ScrollY( nDy, WhichV(eWhich) );
+ }
+}
+
+static bool lcl_TestScenarioRedliningDrop( const ScDocument* pDoc, const ScRange& aDragRange)
+{
+ // Test, if a scenario is affected by a drop when turing on RedLining,
+ bool bReturn = false;
+ SCTAB nTab = aDragRange.aStart.Tab();
+ SCTAB nTabCount = pDoc->GetTableCount();
+
+ if(pDoc->GetChangeTrack()!=nullptr)
+ {
+ if( pDoc->IsScenario(nTab) && pDoc->HasScenarioRange(nTab, aDragRange))
+ {
+ bReturn = true;
+ }
+ else
+ {
+ for(SCTAB i=nTab+1; i<nTabCount && pDoc->IsScenario(i); i++)
+ {
+ if(pDoc->HasScenarioRange(i, aDragRange))
+ {
+ bReturn = true;
+ break;
+ }
+ }
+ }
+ }
+ return bReturn;
+}
+
+static ScRange lcl_MakeDropRange( const ScDocument& rDoc, SCCOL nPosX, SCROW nPosY, SCTAB nTab, const ScRange& rSource )
+{
+ SCCOL nCol1 = nPosX;
+ SCCOL nCol2 = nCol1 + ( rSource.aEnd.Col() - rSource.aStart.Col() );
+ if ( nCol2 > rDoc.MaxCol() )
+ {
+ nCol1 -= nCol2 - rDoc.MaxCol();
+ nCol2 = rDoc.MaxCol();
+ }
+ SCROW nRow1 = nPosY;
+ SCROW nRow2 = nRow1 + ( rSource.aEnd.Row() - rSource.aStart.Row() );
+ if ( nRow2 > rDoc.MaxRow() )
+ {
+ nRow1 -= nRow2 - rDoc.MaxRow();
+ nRow2 = rDoc.MaxRow();
+ }
+
+ return ScRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab );
+}
+
+sal_Int8 ScGridWindow::AcceptPrivateDrop( const AcceptDropEvent& rEvt, const ScDragData& rData )
+{
+ if ( rEvt.mbLeaving )
+ {
+ bDragRect = false;
+ UpdateDragRectOverlay();
+ return rEvt.mnAction;
+ }
+
+ if ( rData.pCellTransfer )
+ {
+ // Don't move source that would include filtered rows.
+ if ((rEvt.mnAction & DND_ACTION_MOVE) && rData.pCellTransfer->HasFilteredRows())
+ {
+ if (bDragRect)
+ {
+ bDragRect = false;
+ UpdateDragRectOverlay();
+ }
+ return DND_ACTION_NONE;
+ }
+
+ Point aPos = rEvt.maPosPixel;
+
+ ScDocument* pSourceDoc = rData.pCellTransfer->GetSourceDocument();
+ ScDocument& rThisDoc = mrViewData.GetDocument();
+ if (pSourceDoc == &rThisDoc)
+ {
+ OUString aName;
+ if ( rThisDoc.HasChartAtPoint(mrViewData.GetTabNo(), PixelToLogic(aPos), aName ))
+ {
+ if (bDragRect) // Remove rectangle
+ {
+ bDragRect = false;
+ UpdateDragRectOverlay();
+ }
+
+ //! highlight chart? (selection border?)
+
+ sal_Int8 nRet = rEvt.mnAction;
+ return nRet;
+ }
+ }
+
+ if (rData.pCellTransfer->GetDragSourceFlags() & ScDragSrc::Table) // whole sheet?
+ {
+ bool bOk = rThisDoc.IsDocEditable();
+ return bOk ? rEvt.mnAction : 0; // don't draw selection frame
+ }
+
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+
+ ScRange aSourceRange = rData.pCellTransfer->GetRange();
+ SCCOL nSourceStartX = aSourceRange.aStart.Col();
+ SCROW nSourceStartY = aSourceRange.aStart.Row();
+ SCCOL nSourceEndX = aSourceRange.aEnd.Col();
+ SCROW nSourceEndY = aSourceRange.aEnd.Row();
+ SCCOL nSizeX = nSourceEndX - nSourceStartX + 1;
+ SCROW nSizeY = nSourceEndY - nSourceStartY + 1;
+
+ if ( rEvt.mnAction != DND_ACTION_MOVE )
+ nSizeY = rData.pCellTransfer->GetNonFilteredRows(); // copy/link: no filtered rows
+
+ SCCOL nNewDragX = nPosX - rData.pCellTransfer->GetDragHandleX();
+ if (nNewDragX<0) nNewDragX=0;
+ if (nNewDragX+(nSizeX-1) > rThisDoc.MaxCol())
+ nNewDragX = rThisDoc.MaxCol()-(nSizeX-1);
+ SCROW nNewDragY = nPosY - rData.pCellTransfer->GetDragHandleY();
+ if (nNewDragY<0) nNewDragY=0;
+ if (nNewDragY+(nSizeY-1) > rThisDoc.MaxRow())
+ nNewDragY = rThisDoc.MaxRow()-(nSizeY-1);
+
+ // don't break scenario ranges, don't drop on filtered
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScRange aDropRange = lcl_MakeDropRange( rThisDoc, nNewDragX, nNewDragY, nTab, aSourceRange );
+ if ( lcl_TestScenarioRedliningDrop( &rThisDoc, aDropRange ) ||
+ lcl_TestScenarioRedliningDrop( pSourceDoc, aSourceRange ) ||
+ ScViewUtil::HasFiltered( aDropRange, rThisDoc) )
+ {
+ if (bDragRect)
+ {
+ bDragRect = false;
+ UpdateDragRectOverlay();
+ }
+ return DND_ACTION_NONE;
+ }
+
+ InsCellCmd eDragInsertMode = INS_NONE;
+ Window::PointerState aState = GetPointerState();
+
+ // check for datapilot item sorting
+ ScDPObject* pDPObj = nullptr;
+ if ( &rThisDoc == pSourceDoc && ( pDPObj = rThisDoc.GetDPAtCursor( nNewDragX, nNewDragY, nTab ) ) != nullptr )
+ {
+ // drop on DataPilot table: sort or nothing
+
+ bool bDPSort = false;
+ if ( rThisDoc.GetDPAtCursor( nSourceStartX, nSourceStartY, aSourceRange.aStart.Tab() ) == pDPObj )
+ {
+ sheet::DataPilotTableHeaderData aDestData;
+ pDPObj->GetHeaderPositionData( ScAddress(nNewDragX, nNewDragY, nTab), aDestData );
+ bool bValid = ( aDestData.Dimension >= 0 ); // dropping onto a field
+
+ // look through the source range
+ for (SCROW nRow = aSourceRange.aStart.Row(); bValid && nRow <= aSourceRange.aEnd.Row(); ++nRow )
+ for (SCCOL nCol = aSourceRange.aStart.Col(); bValid && nCol <= aSourceRange.aEnd.Col(); ++nCol )
+ {
+ sheet::DataPilotTableHeaderData aSourceData;
+ pDPObj->GetHeaderPositionData( ScAddress( nCol, nRow, aSourceRange.aStart.Tab() ), aSourceData );
+ if ( aSourceData.Dimension != aDestData.Dimension || aSourceData.MemberName.isEmpty() )
+ bValid = false; // empty (subtotal) or different field
+ }
+
+ if ( bValid )
+ {
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName( aDestData.Dimension, bIsDataLayout );
+ const ScDPSaveDimension* pDim = pDPObj->GetSaveData()->GetExistingDimensionByName( aDimName );
+ if ( pDim )
+ {
+ ScRange aOutRange = pDPObj->GetOutRange();
+
+ sheet::DataPilotFieldOrientation nOrient = pDim->GetOrientation();
+ if ( nOrient == sheet::DataPilotFieldOrientation_COLUMN )
+ {
+ eDragInsertMode = INS_CELLSRIGHT;
+ nSizeY = aOutRange.aEnd.Row() - nNewDragY + 1;
+ bDPSort = true;
+ }
+ else if ( nOrient == sheet::DataPilotFieldOrientation_ROW )
+ {
+ eDragInsertMode = INS_CELLSDOWN;
+ nSizeX = aOutRange.aEnd.Col() - nNewDragX + 1;
+ bDPSort = true;
+ }
+ }
+ }
+ }
+
+ if ( !bDPSort )
+ {
+ // no valid sorting in a DataPilot table -> disallow
+ if ( bDragRect )
+ {
+ bDragRect = false;
+ UpdateDragRectOverlay();
+ }
+ return DND_ACTION_NONE;
+ }
+ }
+ else if ( aState.mnState & KEY_MOD2 )
+ {
+ if ( &rThisDoc == pSourceDoc && nTab == aSourceRange.aStart.Tab() )
+ {
+ tools::Long nDeltaX = std::abs( static_cast< tools::Long >( nNewDragX - nSourceStartX ) );
+ tools::Long nDeltaY = std::abs( static_cast< tools::Long >( nNewDragY - nSourceStartY ) );
+ if ( nDeltaX <= nDeltaY )
+ {
+ eDragInsertMode = INS_CELLSDOWN;
+ }
+ else
+ {
+ eDragInsertMode = INS_CELLSRIGHT;
+ }
+
+ if ( ( eDragInsertMode == INS_CELLSDOWN && nNewDragY <= nSourceEndY &&
+ ( nNewDragX + nSizeX - 1 ) >= nSourceStartX && nNewDragX <= nSourceEndX &&
+ ( nNewDragX != nSourceStartX || nNewDragY >= nSourceStartY ) ) ||
+ ( eDragInsertMode == INS_CELLSRIGHT && nNewDragX <= nSourceEndX &&
+ ( nNewDragY + nSizeY - 1 ) >= nSourceStartY && nNewDragY <= nSourceEndY &&
+ ( nNewDragY != nSourceStartY || nNewDragX >= nSourceStartX ) ) )
+ {
+ if ( bDragRect )
+ {
+ bDragRect = false;
+ UpdateDragRectOverlay();
+ }
+ return DND_ACTION_NONE;
+ }
+ }
+ else
+ {
+ if ( static_cast< tools::Long >( nSizeX ) >= static_cast< tools::Long >( nSizeY ) )
+ {
+ eDragInsertMode = INS_CELLSDOWN;
+
+ }
+ else
+ {
+ eDragInsertMode = INS_CELLSRIGHT;
+ }
+ }
+ }
+
+ if ( nNewDragX != nDragStartX || nNewDragY != nDragStartY ||
+ nDragStartX+nSizeX-1 != nDragEndX || nDragStartY+nSizeY-1 != nDragEndY ||
+ !bDragRect || eDragInsertMode != meDragInsertMode )
+ {
+ nDragStartX = nNewDragX;
+ nDragStartY = nNewDragY;
+ nDragEndX = nDragStartX+nSizeX-1;
+ nDragEndY = nDragStartY+nSizeY-1;
+ bDragRect = true;
+ meDragInsertMode = eDragInsertMode;
+
+ UpdateDragRectOverlay();
+ }
+ }
+
+ return rEvt.mnAction;
+}
+
+sal_Int8 ScGridWindow::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ const ScDragData& rData = SC_MOD()->GetDragData();
+ if ( rEvt.mbLeaving )
+ {
+ DrawMarkDropObj( nullptr );
+ if ( rData.pCellTransfer )
+ return AcceptPrivateDrop( rEvt, rData ); // hide drop marker for internal D&D
+ else
+ return rEvt.mnAction;
+ }
+
+ if ( mrViewData.GetDocShell()->IsReadOnly() )
+ return DND_ACTION_NONE;
+
+ ScDocument& rThisDoc = mrViewData.GetDocument();
+ sal_Int8 nRet = DND_ACTION_NONE;
+
+ if (rData.pCellTransfer)
+ {
+ ScRange aSource = rData.pCellTransfer->GetRange();
+ if ( aSource.aStart.Col() != 0 || aSource.aEnd.Col() != rThisDoc.MaxCol() ||
+ aSource.aStart.Row() != 0 || aSource.aEnd.Row() != rThisDoc.MaxRow() )
+ DropScroll( rEvt.maPosPixel );
+
+ nRet = AcceptPrivateDrop( rEvt, rData );
+ }
+ else
+ {
+ if ( !rData.aLinkDoc.isEmpty() )
+ {
+ OUString aThisName;
+ ScDocShell* pDocSh = mrViewData.GetDocShell();
+ if (pDocSh && pDocSh->HasName())
+ aThisName = pDocSh->GetMedium()->GetName();
+
+ if ( rData.aLinkDoc != aThisName )
+ nRet = rEvt.mnAction;
+ }
+ else if (!rData.aJumpTarget.isEmpty())
+ {
+ // internal bookmarks (from Navigator)
+ // local jumps from an unnamed document are possible only within a document
+
+ if ( !rData.pJumpLocalDoc || rData.pJumpLocalDoc == &mrViewData.GetDocument() )
+ nRet = rEvt.mnAction;
+ }
+ else
+ {
+ sal_Int8 nMyAction = rEvt.mnAction;
+
+ // clear DND_ACTION_LINK when other actions are set. The usage below cannot handle
+ // multiple set values
+ if((nMyAction & DND_ACTION_LINK) && (nMyAction & DND_ACTION_COPYMOVE))
+ {
+ nMyAction &= ~DND_ACTION_LINK;
+ }
+
+ if ( !rData.pDrawTransfer ||
+ !IsMyModel(rData.pDrawTransfer->GetDragSourceView()) ) // drawing within the document
+ if ( rEvt.mbDefault && nMyAction == DND_ACTION_MOVE )
+ nMyAction = DND_ACTION_COPY;
+
+ SdrObject* pHitObj = rThisDoc.GetObjectAtPoint(
+ mrViewData.GetTabNo(), PixelToLogic(rEvt.maPosPixel) );
+ if ( pHitObj && nMyAction == DND_ACTION_LINK )
+ {
+ if ( IsDropFormatSupported(SotClipboardFormatId::SVXB)
+ || IsDropFormatSupported(SotClipboardFormatId::GDIMETAFILE)
+ || IsDropFormatSupported(SotClipboardFormatId::PNG)
+ || IsDropFormatSupported(SotClipboardFormatId::BITMAP) )
+ {
+ // graphic dragged onto drawing object
+ DrawMarkDropObj( pHitObj );
+ nRet = nMyAction;
+ }
+ }
+ if (!nRet)
+ {
+ DrawMarkDropObj(nullptr);
+
+ switch ( nMyAction )
+ {
+ case DND_ACTION_COPY:
+ case DND_ACTION_MOVE:
+ case DND_ACTION_COPYMOVE:
+ {
+ bool bMove = ( nMyAction == DND_ACTION_MOVE );
+ if ( IsDropFormatSupported( SotClipboardFormatId::EMBED_SOURCE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::EMBED_SOURCE_OLE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE_OLE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::EMBEDDED_OBJ_OLE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::STRING ) ||
+ IsDropFormatSupported( SotClipboardFormatId::STRING_TSVC ) ||
+ IsDropFormatSupported( SotClipboardFormatId::SYLK ) ||
+ IsDropFormatSupported( SotClipboardFormatId::LINK ) ||
+ IsDropFormatSupported( SotClipboardFormatId::HTML ) ||
+ IsDropFormatSupported( SotClipboardFormatId::HTML_SIMPLE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::DIF ) ||
+ IsDropFormatSupported( SotClipboardFormatId::DRAWING ) ||
+ IsDropFormatSupported( SotClipboardFormatId::SVXB ) ||
+ IsDropFormatSupported( SotClipboardFormatId::RTF ) ||
+ IsDropFormatSupported( SotClipboardFormatId::RICHTEXT ) ||
+ IsDropFormatSupported( SotClipboardFormatId::GDIMETAFILE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::PNG ) ||
+ IsDropFormatSupported( SotClipboardFormatId::BITMAP ) ||
+ IsDropFormatSupported( SotClipboardFormatId::SBA_DATAEXCHANGE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::SBA_FIELDDATAEXCHANGE ) ||
+ ( !bMove && (
+ IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) ||
+ IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::SOLK ) ||
+ IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) ||
+ IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK ) ||
+ IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR ) ) ) )
+ {
+ nRet = nMyAction;
+ }
+ }
+ break;
+ case DND_ACTION_LINK:
+ if ( IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::LINK_SOURCE_OLE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::LINK ) ||
+ IsDropFormatSupported( SotClipboardFormatId::FILE_LIST ) ||
+ IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ||
+ IsDropFormatSupported( SotClipboardFormatId::SOLK ) ||
+ IsDropFormatSupported( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) ||
+ IsDropFormatSupported( SotClipboardFormatId::NETSCAPE_BOOKMARK ) ||
+ IsDropFormatSupported( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
+ {
+ nRet = nMyAction;
+ }
+ break;
+ }
+
+ if ( nRet )
+ {
+ // Simple check for protection: It's not known here if the drop will result
+ // in cells or drawing objects (some formats can be both) and how many cells
+ // the result will be. But if IsFormatEditable for the drop cell position
+ // is sal_False (ignores matrix formulas), nothing can be pasted, so the drop
+ // can already be rejected here.
+
+ Point aPos = rEvt.maPosPixel;
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScDocument& rDoc = mrViewData.GetDocument();
+
+ ScEditableTester aTester( rDoc, nTab, nPosX,nPosY, nPosX,nPosY );
+ if ( !aTester.IsFormatEditable() )
+ nRet = DND_ACTION_NONE; // forbidden
+ }
+ }
+ }
+
+ // scroll only for accepted formats
+ if (nRet)
+ DropScroll( rEvt.maPosPixel );
+ }
+
+ return nRet;
+}
+
+static SotClipboardFormatId lcl_GetDropFormatId( const uno::Reference<datatransfer::XTransferable>& xTransfer, bool bPreferText )
+{
+ TransferableDataHelper aDataHelper( xTransfer );
+
+ if ( !aDataHelper.HasFormat( SotClipboardFormatId::SBA_DATAEXCHANGE ) )
+ {
+ // use bookmark formats if no sba is present
+
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::SOLK ) )
+ return SotClipboardFormatId::SOLK;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) )
+ return SotClipboardFormatId::UNIFORMRESOURCELOCATOR;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) )
+ return SotClipboardFormatId::NETSCAPE_BOOKMARK;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
+ return SotClipboardFormatId::FILEGRPDESCRIPTOR;
+ }
+
+ SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ) )
+ nFormatId = SotClipboardFormatId::DRAWING;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
+ nFormatId = SotClipboardFormatId::SVXB;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ) )
+ {
+ // If it's a Writer object, insert RTF instead of OLE
+
+ bool bDoRtf = false;
+ tools::SvRef<SotTempStream> xStm;
+ TransferableObjectDescriptor aObjDesc;
+ if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) &&
+ aDataHelper.GetSotStorageStream( SotClipboardFormatId::EMBED_SOURCE, xStm ) )
+ {
+ bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
+ aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
+ && ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ) );
+ }
+ if ( bDoRtf )
+ nFormatId = aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT;
+ else
+ nFormatId = SotClipboardFormatId::EMBED_SOURCE;
+ }
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ) )
+ nFormatId = SotClipboardFormatId::LINK_SOURCE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::SBA_DATAEXCHANGE ) )
+ nFormatId = SotClipboardFormatId::SBA_DATAEXCHANGE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::SBA_FIELDDATAEXCHANGE ) )
+ nFormatId = SotClipboardFormatId::SBA_FIELDDATAEXCHANGE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::BIFF_8 ) )
+ nFormatId = SotClipboardFormatId::BIFF_8;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::BIFF_5 ) )
+ nFormatId = SotClipboardFormatId::BIFF_5;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ) )
+ nFormatId = SotClipboardFormatId::EMBED_SOURCE_OLE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ) )
+ nFormatId = SotClipboardFormatId::EMBEDDED_OBJ_OLE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ) )
+ nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
+ nFormatId = SotClipboardFormatId::RTF;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) )
+ nFormatId = SotClipboardFormatId::RICHTEXT;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::HTML ) )
+ nFormatId = SotClipboardFormatId::HTML;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::HTML_SIMPLE ) )
+ nFormatId = SotClipboardFormatId::HTML_SIMPLE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::SYLK ) )
+ nFormatId = SotClipboardFormatId::SYLK;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK ) )
+ nFormatId = SotClipboardFormatId::LINK;
+ else if ( bPreferText && aDataHelper.HasFormat( SotClipboardFormatId::STRING ) ) // #i86734# the behaviour introduced in #i62773# is wrong when pasting
+ nFormatId = SotClipboardFormatId::STRING;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) )
+ nFormatId = SotClipboardFormatId::FILE_LIST;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) ) // #i62773# FILE_LIST/FILE before STRING (Unix file managers)
+ nFormatId = SotClipboardFormatId::SIMPLE_FILE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::STRING_TSVC ) )
+ nFormatId = SotClipboardFormatId::STRING_TSVC;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) )
+ nFormatId = SotClipboardFormatId::STRING;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
+ nFormatId = SotClipboardFormatId::GDIMETAFILE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::PNG ) )
+ nFormatId = SotClipboardFormatId::PNG;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) )
+ nFormatId = SotClipboardFormatId::BITMAP;
+
+ return nFormatId;
+}
+
+static SotClipboardFormatId lcl_GetDropLinkId( const uno::Reference<datatransfer::XTransferable>& xTransfer )
+{
+ TransferableDataHelper aDataHelper( xTransfer );
+
+ SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ) )
+ nFormatId = SotClipboardFormatId::LINK_SOURCE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ) )
+ nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::LINK ) )
+ nFormatId = SotClipboardFormatId::LINK;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILE_LIST ) )
+ nFormatId = SotClipboardFormatId::FILE_LIST;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::SIMPLE_FILE ) )
+ nFormatId = SotClipboardFormatId::SIMPLE_FILE;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::SOLK ) )
+ nFormatId = SotClipboardFormatId::SOLK;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::UNIFORMRESOURCELOCATOR ) )
+ nFormatId = SotClipboardFormatId::UNIFORMRESOURCELOCATOR;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::NETSCAPE_BOOKMARK ) )
+ nFormatId = SotClipboardFormatId::NETSCAPE_BOOKMARK;
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::FILEGRPDESCRIPTOR ) )
+ nFormatId = SotClipboardFormatId::FILEGRPDESCRIPTOR;
+
+ return nFormatId;
+}
+
+sal_Int8 ScGridWindow::ExecutePrivateDrop( const ExecuteDropEvent& rEvt, const ScDragData& rData )
+{
+ // hide drop marker
+ bDragRect = false;
+ UpdateDragRectOverlay();
+
+ return DropTransferObj( rData.pCellTransfer, nDragStartX, nDragStartY,
+ PixelToLogic(rEvt.maPosPixel), rEvt.mnAction );
+}
+
+sal_Int8 ScGridWindow::DropTransferObj( ScTransferObj* pTransObj, SCCOL nDestPosX, SCROW nDestPosY,
+ const Point& rLogicPos, sal_Int8 nDndAction )
+{
+ if ( !pTransObj )
+ return 0;
+
+ ScDocument* pSourceDoc = pTransObj->GetSourceDocument();
+ ScDocShell* pDocSh = mrViewData.GetDocShell();
+ ScDocument& rThisDoc = mrViewData.GetDocument();
+ ScViewFunc* pView = mrViewData.GetView();
+ SCTAB nThisTab = mrViewData.GetTabNo();
+ ScDragSrc nFlags = pTransObj->GetDragSourceFlags();
+
+ bool bIsNavi = (nFlags & ScDragSrc::Navigator) == ScDragSrc::Navigator;
+ bool bIsMove = ( nDndAction == DND_ACTION_MOVE && !bIsNavi );
+
+ // workaround for wrong nDndAction on Windows when pressing solely
+ // the Alt key during drag and drop;
+ // can be removed after #i79215# has been fixed
+ if ( meDragInsertMode != INS_NONE )
+ {
+ bIsMove = ( nDndAction & DND_ACTION_MOVE && !bIsNavi );
+ }
+
+ bool bIsLink = ( nDndAction == DND_ACTION_LINK );
+
+ ScRange aSource = pTransObj->GetRange();
+
+ // only use visible tab from source range - when dragging within one table,
+ // all selected tables at the time of dropping are used (handled in MoveBlockTo)
+ SCTAB nSourceTab = pTransObj->GetVisibleTab();
+ aSource.aStart.SetTab( nSourceTab );
+ aSource.aEnd.SetTab( nSourceTab );
+
+ SCCOL nSizeX = aSource.aEnd.Col() - aSource.aStart.Col() + 1;
+ SCROW nSizeY = (bIsMove ? (aSource.aEnd.Row() - aSource.aStart.Row() + 1) :
+ pTransObj->GetNonFilteredRows()); // copy/link: no filtered rows
+ ScRange aDest( nDestPosX, nDestPosY, nThisTab,
+ nDestPosX + nSizeX - 1, nDestPosY + nSizeY - 1, nThisTab );
+
+ /* NOTE: AcceptPrivateDrop() already checked for filtered conditions during
+ * dragging and adapted drawing of the selection frame. We check here
+ * (again) because this may actually also be called from PasteSelection(),
+ * we would have to duplicate determination of flags and destination range
+ * and would lose the context of the "filtered destination is OK" cases
+ * below, which is already awkward enough as is. */
+
+ // Don't move filtered source.
+ bool bFiltered = (bIsMove && pTransObj->HasFilteredRows());
+ if (!bFiltered)
+ {
+ if (pSourceDoc != &rThisDoc && ((nFlags & ScDragSrc::Table) ||
+ (!bIsLink && meDragInsertMode == INS_NONE)))
+ {
+ // Nothing. Either entire sheet to be dropped, or the one case
+ // where PasteFromClip() is to be called that handles a filtered
+ // destination itself. Drag-copy from another document without
+ // inserting cells.
+ }
+ else
+ // Don't copy or move to filtered destination.
+ bFiltered = ScViewUtil::HasFiltered(aDest, rThisDoc);
+ }
+
+ bool bDone = false;
+
+ if (!bFiltered && pSourceDoc == &rThisDoc)
+ {
+ if (nFlags & ScDragSrc::Table) // whole sheet?
+ {
+ if ( rThisDoc.IsDocEditable() )
+ {
+ SCTAB nSrcTab = aSource.aStart.Tab();
+ mrViewData.GetDocShell()->MoveTable( nSrcTab, nThisTab, !bIsMove, true ); // with Undo
+ pView->SetTabNo( nThisTab, true );
+ bDone = true;
+ }
+ }
+ else // move/copy block
+ {
+ OUString aChartName;
+ if (rThisDoc.HasChartAtPoint( nThisTab, rLogicPos, aChartName ))
+ {
+ OUString aRangeName(aSource.Format(rThisDoc, ScRefFlags::RANGE_ABS_3D,
+ rThisDoc.GetAddressConvention()));
+ SfxStringItem aNameItem( SID_CHART_NAME, aChartName );
+ SfxStringItem aRangeItem( SID_CHART_SOURCE, aRangeName );
+ sal_uInt16 nId = bIsMove ? SID_CHART_SOURCE : SID_CHART_ADDSOURCE;
+ mrViewData.GetDispatcher().ExecuteList(nId,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD,
+ { &aRangeItem, &aNameItem });
+ bDone = true;
+ }
+ else if ( rThisDoc.GetDPAtCursor( nDestPosX, nDestPosY, nThisTab ) )
+ {
+ // drop on DataPilot table: try to sort, fail if that isn't possible
+
+ ScAddress aDestPos( nDestPosX, nDestPosY, nThisTab );
+ if ( aDestPos != aSource.aStart )
+ bDone = mrViewData.GetView()->DataPilotMove( aSource, aDestPos );
+ else
+ bDone = true; // same position: nothing
+ }
+ else if ( nDestPosX != aSource.aStart.Col() || nDestPosY != aSource.aStart.Row() ||
+ nSourceTab != nThisTab )
+ {
+ OUString aUndo = ScResId( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, mrViewData.GetViewShell()->GetViewShellId() );
+
+ SCCOL nCorrectCursorPosCol = 0;
+ SCROW nCorrectCursorPosRow = 0;
+
+ bDone = true;
+ if ( meDragInsertMode != INS_NONE )
+ {
+ // call with bApi = sal_True to avoid error messages in drop handler
+ bDone = pDocSh->GetDocFunc().InsertCells( aDest, nullptr, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
+ if ( bDone )
+ {
+ if ( nThisTab == nSourceTab )
+ {
+ if ( meDragInsertMode == INS_CELLSDOWN &&
+ nDestPosX == aSource.aStart.Col() && nDestPosY < aSource.aStart.Row() )
+ {
+ ScRange aErrorRange( ScAddress::UNINITIALIZED );
+ bDone = aSource.Move( 0, nSizeY, 0, aErrorRange, *pSourceDoc );
+ nCorrectCursorPosRow = nSizeY;
+ }
+ else if ( meDragInsertMode == INS_CELLSRIGHT &&
+ nDestPosY == aSource.aStart.Row() && nDestPosX < aSource.aStart.Col() )
+ {
+ ScRange aErrorRange( ScAddress::UNINITIALIZED );
+ bDone = aSource.Move( nSizeX, 0, 0, aErrorRange, *pSourceDoc );
+ nCorrectCursorPosCol = nSizeX;
+ }
+ }
+ pDocSh->UpdateOle(mrViewData);
+ pView->CellContentChanged();
+ }
+ }
+
+ if ( bDone )
+ {
+ if ( bIsLink )
+ {
+ bDone = pView->LinkBlock( aSource, aDest.aStart );
+ }
+ else
+ {
+ bDone = pView->MoveBlockTo( aSource, aDest.aStart, bIsMove );
+ }
+ }
+
+ if ( bDone && meDragInsertMode != INS_NONE && bIsMove && nThisTab == nSourceTab )
+ {
+ DelCellCmd eCmd = DelCellCmd::NONE;
+ if ( meDragInsertMode == INS_CELLSDOWN )
+ {
+ eCmd = DelCellCmd::CellsUp;
+ }
+ else if ( meDragInsertMode == INS_CELLSRIGHT )
+ {
+ eCmd = DelCellCmd::CellsLeft;
+ }
+
+ if ( ( eCmd == DelCellCmd::CellsUp && nDestPosX == aSource.aStart.Col() ) ||
+ ( eCmd == DelCellCmd::CellsLeft && nDestPosY == aSource.aStart.Row() ) )
+ {
+ // call with bApi = sal_True to avoid error messages in drop handler
+ bDone = pDocSh->GetDocFunc().DeleteCells( aSource, nullptr, eCmd, true /*bApi*/ );
+ if ( bDone )
+ {
+ if ( eCmd == DelCellCmd::CellsUp && nDestPosY > aSource.aEnd.Row() )
+ {
+ ScRange aErrorRange( ScAddress::UNINITIALIZED );
+ bDone = aDest.Move( 0, -nSizeY, 0, aErrorRange, rThisDoc );
+ }
+ else if ( eCmd == DelCellCmd::CellsLeft && nDestPosX > aSource.aEnd.Col() )
+ {
+ ScRange aErrorRange( ScAddress::UNINITIALIZED );
+ bDone = aDest.Move( -nSizeX, 0, 0, aErrorRange, rThisDoc );
+ }
+ pDocSh->UpdateOle(mrViewData);
+ pView->CellContentChanged();
+ }
+ }
+ }
+
+ if ( bDone )
+ {
+ pView->MarkRange( aDest, false );
+
+ SCCOL nDCol;
+ SCROW nDRow;
+ if (pTransObj->WasSourceCursorInSelection())
+ {
+ nDCol = pTransObj->GetSourceCursorX() - aSource.aStart.Col() + nCorrectCursorPosCol;
+ nDRow = pTransObj->GetSourceCursorY() - aSource.aStart.Row() + nCorrectCursorPosRow;
+ }
+ else
+ {
+ nDCol = 0;
+ nDRow = 0;
+ }
+ pView->SetCursor( aDest.aStart.Col() + nDCol, aDest.aStart.Row() + nDRow );
+ }
+
+ pDocSh->GetUndoManager()->LeaveListAction();
+
+ }
+ else
+ bDone = true; // nothing to do
+ }
+
+ if (bDone)
+ pTransObj->SetDragWasInternal(); // don't delete source in DragFinished
+ }
+ else if ( !bFiltered && pSourceDoc ) // between documents
+ {
+ if (nFlags & ScDragSrc::Table) // copy/link sheets between documents
+ {
+ if ( rThisDoc.IsDocEditable() )
+ {
+ ScDocShell* pSrcShell = pTransObj->GetSourceDocShell();
+
+ std::vector<SCTAB> nTabs;
+
+ ScMarkData aMark = pTransObj->GetSourceMarkData();
+ SCTAB nTabCount = pSourceDoc->GetTableCount();
+
+ for(SCTAB i=0; i<nTabCount; i++)
+ {
+ if(aMark.GetTableSelect(i))
+ {
+ nTabs.push_back(i);
+ for(SCTAB j=i+1;j<nTabCount;j++)
+ {
+ if((!pSourceDoc->IsVisible(j))&&(pSourceDoc->IsScenario(j)))
+ {
+ nTabs.push_back( j );
+ i=j;
+ }
+ else break;
+ }
+ }
+ }
+
+ pView->ImportTables( pSrcShell,static_cast<SCTAB>(nTabs.size()), nTabs.data(), bIsLink, nThisTab );
+ bDone = true;
+ }
+ }
+ else if ( bIsLink )
+ {
+ // as in PasteDDE
+ // (external references might be used instead?)
+
+ SfxObjectShell* pSourceSh = pSourceDoc->GetDocumentShell();
+ OSL_ENSURE(pSourceSh, "drag document has no shell");
+ if (pSourceSh)
+ {
+ OUString aUndo = ScResId( STR_UNDO_COPY );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, mrViewData.GetViewShell()->GetViewShellId() );
+
+ bDone = true;
+ if ( meDragInsertMode != INS_NONE )
+ {
+ // call with bApi = sal_True to avoid error messages in drop handler
+ bDone = pDocSh->GetDocFunc().InsertCells( aDest, nullptr, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
+ if ( bDone )
+ {
+ pDocSh->UpdateOle(mrViewData);
+ pView->CellContentChanged();
+ }
+ }
+
+ if ( bDone )
+ {
+ OUString aApp = Application::GetAppName();
+ OUString aTopic = pSourceSh->GetTitle( SFX_TITLE_FULLNAME );
+ OUString aItem(aSource.Format(*pSourceDoc, ScRefFlags::VALID | ScRefFlags::TAB_3D));
+
+ // TODO: we could define ocQuote for "
+ const OUString aQuote('"');
+ const OUString& sSep = ScCompiler::GetNativeSymbol( ocSep);
+ OUString aFormula =
+ "=" +
+ ScCompiler::GetNativeSymbol(ocDde) +
+ ScCompiler::GetNativeSymbol(ocOpen) +
+ aQuote +
+ aApp +
+ aQuote +
+ sSep +
+ aQuote +
+ aTopic +
+ aQuote +
+ sSep +
+ aQuote +
+ aItem +
+ aQuote +
+ ScCompiler::GetNativeSymbol(ocClose);
+
+ pView->DoneBlockMode();
+ pView->InitBlockMode( nDestPosX, nDestPosY, nThisTab );
+ pView->MarkCursor( nDestPosX + nSizeX - 1,
+ nDestPosY + nSizeY - 1, nThisTab );
+
+ pView->EnterMatrix( aFormula, ::formula::FormulaGrammar::GRAM_NATIVE );
+
+ pView->MarkRange( aDest, false );
+ pView->SetCursor( aDest.aStart.Col(), aDest.aStart.Row() );
+ }
+
+ pDocSh->GetUndoManager()->LeaveListAction();
+ }
+ }
+ else
+ {
+ //! HasSelectedBlockMatrixFragment without selected sheet?
+ //! or don't start dragging on a part of a matrix
+
+ OUString aUndo = ScResId( bIsMove ? STR_UNDO_MOVE : STR_UNDO_COPY );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, mrViewData.GetViewShell()->GetViewShellId() );
+
+ bDone = true;
+ if ( meDragInsertMode != INS_NONE )
+ {
+ // call with bApi = sal_True to avoid error messages in drop handler
+ bDone = pDocSh->GetDocFunc().InsertCells( aDest, nullptr, meDragInsertMode, true /*bRecord*/, true /*bApi*/, true /*bPartOfPaste*/ );
+ if ( bDone )
+ {
+ pDocSh->UpdateOle(mrViewData);
+ pView->CellContentChanged();
+ }
+ }
+
+ if ( bDone )
+ {
+ pView->Unmark(); // before SetCursor, so CheckSelectionTransfer isn't called with a selection
+ pView->SetCursor( nDestPosX, nDestPosY );
+ bDone = pView->PasteFromClip( InsertDeleteFlags::ALL, pTransObj->GetDocument() ); // clip-doc
+ if ( bDone )
+ {
+ pView->MarkRange( aDest, false );
+ pView->SetCursor( aDest.aStart.Col(), aDest.aStart.Row() );
+ }
+ }
+
+ pDocSh->GetUndoManager()->LeaveListAction();
+
+ // no longer call ResetMark here - the inserted block has been selected
+ // and may have been copied to primary selection
+ }
+ }
+
+ sal_Int8 nRet = bDone ? nDndAction : DND_ACTION_NONE;
+ return nRet;
+}
+
+sal_Int8 ScGridWindow::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ DrawMarkDropObj( nullptr ); // drawing layer
+
+ ScModule* pScMod = SC_MOD();
+ const ScDragData& rData = pScMod->GetDragData();
+ if (rData.pCellTransfer)
+ return ExecutePrivateDrop( rEvt, rData );
+
+ Point aPos = rEvt.maPosPixel;
+
+ if ( !rData.aLinkDoc.isEmpty() )
+ {
+ // try to insert a link
+
+ bool bOk = true;
+ OUString aThisName;
+ ScDocShell* pDocSh = mrViewData.GetDocShell();
+ if (pDocSh && pDocSh->HasName())
+ aThisName = pDocSh->GetMedium()->GetName();
+
+ if ( rData.aLinkDoc == aThisName ) // error - no link within a document
+ bOk = false;
+ else
+ {
+ ScViewFunc* pView = mrViewData.GetView();
+ if ( !rData.aLinkTable.isEmpty() )
+ pView->InsertTableLink( rData.aLinkDoc, OUString(), OUString(),
+ rData.aLinkTable );
+ else if ( !rData.aLinkArea.isEmpty() )
+ {
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+ pView->MoveCursorAbs( nPosX, nPosY, SC_FOLLOW_NONE, false, false );
+
+ pView->InsertAreaLink( rData.aLinkDoc, OUString(), OUString(),
+ rData.aLinkArea );
+ }
+ else
+ {
+ OSL_FAIL("drop with link: no sheet nor area");
+ bOk = false;
+ }
+ }
+
+ return bOk ? rEvt.mnAction : DND_ACTION_NONE; // don't try anything else
+ }
+
+ Point aLogicPos = PixelToLogic(aPos);
+ bool bIsLink = ( rEvt.mnAction == DND_ACTION_LINK );
+
+ if (!bIsLink && rData.pDrawTransfer)
+ {
+ ScDragSrc nFlags = rData.pDrawTransfer->GetDragSourceFlags();
+
+ bool bIsNavi = (nFlags & ScDragSrc::Navigator) == ScDragSrc::Navigator;
+ bool bIsMove = ( rEvt.mnAction == DND_ACTION_MOVE && !bIsNavi );
+
+ bPasteIsMove = bIsMove;
+
+ mrViewData.GetView()->PasteDraw(
+ aLogicPos, rData.pDrawTransfer->GetModel(), false, u"A", u"B");
+
+ if (bPasteIsMove)
+ rData.pDrawTransfer->SetDragWasInternal();
+ bPasteIsMove = false;
+
+ return rEvt.mnAction;
+ }
+
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+
+ if (!rData.aJumpTarget.isEmpty())
+ {
+ // internal bookmark (from Navigator)
+ // bookmark clipboard formats are in PasteScDataObject
+
+ if ( !rData.pJumpLocalDoc || rData.pJumpLocalDoc == &mrViewData.GetDocument() )
+ {
+ mrViewData.GetViewShell()->InsertBookmark( rData.aJumpText, rData.aJumpTarget,
+ nPosX, nPosY );
+ return rEvt.mnAction;
+ }
+ }
+
+ ScDocument& rThisDoc = mrViewData.GetDocument();
+ SdrObject* pHitObj = rThisDoc.GetObjectAtPoint( mrViewData.GetTabNo(), PixelToLogic(aPos) );
+ if ( pHitObj && bIsLink )
+ {
+ // dropped on drawing object
+ // PasteOnDrawObjectLinked checks for valid formats
+ if ( mrViewData.GetView()->PasteOnDrawObjectLinked( rEvt.maDropEvent.Transferable, *pHitObj ) )
+ return rEvt.mnAction;
+ }
+
+ bool bDone = false;
+
+ SotClipboardFormatId nFormatId = bIsLink ?
+ lcl_GetDropLinkId( rEvt.maDropEvent.Transferable ) :
+ lcl_GetDropFormatId( rEvt.maDropEvent.Transferable, false );
+ if ( nFormatId != SotClipboardFormatId::NONE )
+ {
+ pScMod->SetInExecuteDrop( true ); // #i28468# prevent error messages from PasteDataFormat
+ bDone = mrViewData.GetView()->PasteDataFormat(
+ nFormatId, rEvt.maDropEvent.Transferable, nPosX, nPosY, &aLogicPos, bIsLink );
+ pScMod->SetInExecuteDrop( false );
+ }
+
+ sal_Int8 nRet = bDone ? rEvt.mnAction : DND_ACTION_NONE;
+ return nRet;
+}
+
+void ScGridWindow::PasteSelection( const Point& rPosPixel )
+{
+ Point aLogicPos = PixelToLogic( rPosPixel );
+
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( rPosPixel.X(), rPosPixel.Y(), eWhich, nPosX, nPosY );
+
+ // If the mouse down was inside a visible note window, ignore it and
+ // leave it up to the ScPostIt to handle it
+ SdrView* pDrawView = mrViewData.GetViewShell()->GetScDrawView();
+ if (pDrawView)
+ {
+ const size_t nCount = pDrawView->GetMarkedObjectCount();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ SdrObject* pObj = pDrawView->GetMarkedObjectByIndex(i);
+ if (pObj && pObj->GetLogicRect().Contains(aLogicPos))
+ {
+ // Inside an active drawing object. Bail out.
+ return;
+ }
+ }
+ }
+
+ ScSelectionTransferObj* pOwnSelection = SC_MOD()->GetSelectionTransfer();
+ if ( pOwnSelection )
+ {
+ // within Calc
+
+ // keep a reference to the data in case the selection is changed during paste
+ rtl::Reference<ScTransferObj> pCellTransfer = pOwnSelection->GetCellData();
+ if ( pCellTransfer )
+ {
+ DropTransferObj( pCellTransfer.get(), nPosX, nPosY, aLogicPos, DND_ACTION_COPY );
+ }
+ else
+ {
+ // keep a reference to the data in case the selection is changed during paste
+ rtl::Reference<ScDrawTransferObj> pDrawTransfer = pOwnSelection->GetDrawData();
+ if ( pDrawTransfer )
+ {
+ // bSameDocClipboard argument for PasteDraw is needed
+ // because only DragData is checked directly inside PasteDraw
+ mrViewData.GetView()->PasteDraw(
+ aLogicPos, pDrawTransfer->GetModel(), false,
+ pDrawTransfer->GetShellID(), SfxObjectShell::CreateShellID(mrViewData.GetDocShell()));
+ }
+ }
+ }
+ else
+ {
+ // get selection from system
+ TransferableDataHelper aDataHelper(TransferableDataHelper::CreateFromPrimarySelection());
+ const uno::Reference<datatransfer::XTransferable>& xTransferable = aDataHelper.GetTransferable();
+ if ( xTransferable.is() )
+ {
+ SotClipboardFormatId nFormatId = lcl_GetDropFormatId( xTransferable, true );
+ if ( nFormatId != SotClipboardFormatId::NONE )
+ mrViewData.GetView()->PasteDataFormat( nFormatId, xTransferable, nPosX, nPosY, &aLogicPos );
+ }
+ }
+}
+
+void ScGridWindow::UpdateEditViewPos()
+{
+ if (!mrViewData.HasEditView(eWhich))
+ return;
+
+ EditView* pView;
+ SCCOL nCol;
+ SCROW nRow;
+ mrViewData.GetEditView( eWhich, pView, nCol, nRow );
+ SCCOL nEndCol = mrViewData.GetEditEndCol();
+ SCROW nEndRow = mrViewData.GetEditEndRow();
+
+ // hide EditView?
+
+ bool bHide = ( nEndCol<mrViewData.GetPosX(eHWhich) || nEndRow<mrViewData.GetPosY(eVWhich) );
+ if ( SC_MOD()->IsFormulaMode() )
+ if ( mrViewData.GetTabNo() != mrViewData.GetRefTabNo() )
+ bHide = true;
+
+ if (bHide)
+ {
+ tools::Rectangle aRect = pView->GetOutputArea();
+ tools::Long nHeight = aRect.Bottom() - aRect.Top();
+ aRect.SetTop( PixelToLogic(GetOutputSizePixel(), mrViewData.GetLogicMode()).
+ Height() * 2 );
+ aRect.SetBottom( aRect.Top() + nHeight );
+ pView->SetOutputArea( aRect );
+ pView->HideCursor();
+ }
+ else
+ {
+ // bForceToTop = sal_True for editing
+ tools::Rectangle aPixRect = mrViewData.GetEditArea( eWhich, nCol, nRow, this, nullptr, true );
+
+ if (comphelper::LibreOfficeKit::isActive() &&
+ comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ {
+ tools::Rectangle aPTwipsRect = mrViewData.GetEditArea(eWhich, nCol, nRow, this, nullptr,
+ true, true /* bInPrintTwips */);
+ tools::Rectangle aOutputAreaPTwips = pView->GetLOKSpecialOutputArea();
+ aOutputAreaPTwips.SetPos(aPTwipsRect.TopLeft());
+ pView->SetLOKSpecialOutputArea(aOutputAreaPTwips);
+ }
+
+ Point aScrPos = PixelToLogic( aPixRect.TopLeft(), mrViewData.GetLogicMode() );
+
+ tools::Rectangle aRect = pView->GetOutputArea();
+ aRect.SetPos( aScrPos );
+ pView->SetOutputArea( aRect );
+ pView->ShowCursor();
+ }
+}
+
+void ScGridWindow::ScrollPixel( tools::Long nDifX, tools::Long nDifY )
+{
+ ClickExtern();
+ HideNoteMarker();
+
+ SetMapMode(MapMode(MapUnit::MapPixel));
+ Scroll( nDifX, nDifY, ScrollFlags::Children );
+ SetMapMode( GetDrawMapMode() ); // generated shifted MapMode
+
+ UpdateEditViewPos();
+
+ DrawAfterScroll();
+}
+
+// Update Formulas ------------------------------------------------------
+
+void ScGridWindow::UpdateFormulas(SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2)
+{
+ if (mrViewData.GetView()->IsMinimized())
+ return;
+
+ if ( nPaintCount )
+ {
+ // Do not start, switched to paint
+ // (then at least the MapMode would no longer be right)
+
+ bNeedsRepaint = true; // -> at end of paint run Invalidate on all
+ aRepaintPixel = tools::Rectangle(); // All
+ return;
+ }
+
+ if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ if (nX1 < 0)
+ nX1 = pViewShell->GetLOKStartHeaderCol() + 1;
+ if (nY1 < 0)
+ nY1 = pViewShell->GetLOKStartHeaderRow() + 1;
+ if (nX2 < 0)
+ nX2 = pViewShell->GetLOKEndHeaderCol();
+ if (nY2 < 0)
+ nY2 = pViewShell->GetLOKEndHeaderRow();
+
+ if (nX1 < 0 || nY1 < 0) return;
+ }
+ else
+ {
+ nX1 = mrViewData.GetPosX( eHWhich );
+ nY1 = mrViewData.GetPosY( eVWhich );
+ nX2 = nX1 + mrViewData.VisibleCellsX( eHWhich );
+ nY2 = nY1 + mrViewData.VisibleCellsY( eVWhich );
+ }
+
+ if (nX2 < nX1) nX2 = nX1;
+ if (nY2 < nY1) nY2 = nY1;
+
+ ScDocument& rDoc = mrViewData.GetDocument();
+
+ if (nX2 > rDoc.MaxCol()) nX2 = rDoc.MaxCol();
+ if (nY2 > rDoc.MaxRow()) nY2 = rDoc.MaxRow();
+
+ // Draw( nX1, nY1, nX2, nY2, SC_UPDATE_CHANGED );
+
+ // don't draw directly - instead use OutputData to find changed area and invalidate
+
+ SCROW nPosY = nY1;
+
+ SCTAB nTab = mrViewData.GetTabNo();
+
+ if ( !comphelper::LibreOfficeKit::isActive() )
+ {
+ rDoc.ExtendHidden( nX1, nY1, nX2, nY2, nTab );
+ }
+
+ Point aScrPos = mrViewData.GetScrPos( nX1, nY1, eWhich );
+ tools::Long nMirrorWidth = GetSizePixel().Width();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ if ( bLayoutRTL )
+ {
+ tools::Long nEndPixel = mrViewData.GetScrPos( nX2+1, nPosY, eWhich ).X();
+ nMirrorWidth = aScrPos.X() - nEndPixel;
+ aScrPos.setX( nEndPixel + 1 );
+ }
+
+ tools::Long nScrX = aScrPos.X();
+ tools::Long nScrY = aScrPos.Y();
+
+ double nPPTX = mrViewData.GetPPTX();
+ double nPPTY = mrViewData.GetPPTY();
+
+ ScTableInfo aTabInfo;
+ rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nTab, nPPTX, nPPTY, false, false );
+
+ Fraction aZoomX = mrViewData.GetZoomX();
+ Fraction aZoomY = mrViewData.GetZoomY();
+ ScOutputData aOutputData( GetOutDev(), OUTTYPE_WINDOW, aTabInfo, &rDoc, nTab,
+ nScrX, nScrY, nX1, nY1, nX2, nY2, nPPTX, nPPTY,
+ &aZoomX, &aZoomY );
+ aOutputData.SetMirrorWidth( nMirrorWidth );
+
+ aOutputData.FindChanged();
+
+ // #i122149# do not use old GetChangedArea() which used polygon-based Regions, but use
+ // the region-band based new version; anyways, only rectangles are added
+ vcl::Region aChangedRegion( aOutputData.GetChangedAreaRegion() ); // logic (PixelToLogic)
+ if(!aChangedRegion.IsEmpty())
+ {
+ Invalidate(aChangedRegion);
+ }
+
+ CheckNeedsRepaint(); // #i90362# used to be called via Draw() - still needed here
+}
+
+void ScGridWindow::UpdateAutoFillMark(bool bMarked, const ScRange& rMarkRange)
+{
+ if ( bMarked != bAutoMarkVisible || ( bMarked && rMarkRange.aEnd != aAutoMarkPos ) )
+ {
+ bAutoMarkVisible = bMarked;
+ if ( bMarked )
+ aAutoMarkPos = rMarkRange.aEnd;
+
+ UpdateAutoFillOverlay();
+ }
+}
+
+void ScGridWindow::updateLOKInputHelp(const OUString& title, const OUString& content) const
+{
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+
+ boost::property_tree::ptree aTree;
+ aTree.put("title", title);
+ aTree.put("content", content);
+
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, aTree);
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_VALIDITY_INPUT_HELP, aStream.str().c_str());
+}
+
+void ScGridWindow::updateLOKValListButton( bool bVisible, const ScAddress& rPos ) const
+{
+ SCCOL nX = rPos.Col();
+ SCROW nY = rPos.Row();
+ std::stringstream ss;
+ ss << nX << ", " << nY << ", " << static_cast<unsigned int>(bVisible);
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_VALIDITY_LIST_BUTTON, ss.str().c_str());
+}
+
+void ScGridWindow::notifyKitCellFollowJump( ) const
+{
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SC_FOLLOW_JUMP, getCellCursor().getStr());
+}
+
+void ScGridWindow::UpdateListValPos( bool bVisible, const ScAddress& rPos )
+{
+ bool bOldButton = bListValButton;
+ ScAddress aOldPos = aListValPos;
+
+ bListValButton = bVisible;
+ aListValPos = rPos;
+
+ if ( bListValButton )
+ {
+ if ( !bOldButton || aListValPos != aOldPos )
+ {
+ // paint area of new button
+ if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ updateLOKValListButton( true, aListValPos );
+ }
+ else
+ {
+ Invalidate( PixelToLogic( GetListValButtonRect( aListValPos ) ) );
+ }
+ }
+ }
+ if ( !bOldButton )
+ return;
+
+ if ( !bListValButton || aListValPos != aOldPos )
+ {
+ // paint area of old button
+ if ( comphelper::LibreOfficeKit::isActive() )
+ {
+ updateLOKValListButton( false, aOldPos );
+ }
+ else
+ {
+ Invalidate( PixelToLogic( GetListValButtonRect( aOldPos ) ) );
+ }
+ }
+}
+
+void ScGridWindow::HideCursor()
+{
+ ++nCursorHideCount;
+}
+
+void ScGridWindow::ShowCursor()
+{
+ --nCursorHideCount;
+}
+
+void ScGridWindow::GetFocus()
+{
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ pViewShell->SetFormShellAtTop( false ); // focus in GridWindow -> FormShell no longer on top
+
+ if (pViewShell->HasAccessibilityObjects())
+ pViewShell->BroadcastAccessibility(ScAccGridWinFocusGotHint(eWhich));
+
+ if ( !SC_MOD()->IsFormulaMode() )
+ {
+ pViewShell->UpdateInputHandler();
+// StopMarking(); // If Dialog (error), because then no ButtonUp
+ // MO: only when not in RefInput mode
+ // -> GetFocus/MouseButtonDown order on Mac
+ }
+
+ mrViewData.GetDocShell()->CheckConfigOptions();
+ Window::GetFocus();
+}
+
+void ScGridWindow::LoseFocus()
+{
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+
+ if (pViewShell && pViewShell->HasAccessibilityObjects())
+ pViewShell->BroadcastAccessibility(ScAccGridWinFocusLostHint(eWhich));
+
+ Window::LoseFocus();
+}
+
+bool ScGridWindow::HitRangeFinder( const Point& rMouse, RfCorner& rCorner,
+ sal_uInt16* pIndex, SCCOL* pAddX, SCROW* pAddY)
+{
+ bool bFound = false;
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl( mrViewData.GetViewShell() );
+ if (pHdl)
+ {
+ ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList();
+ if ( pRangeFinder && !pRangeFinder->IsHidden() &&
+ pRangeFinder->GetDocName() == mrViewData.GetDocShell()->GetTitle() )
+ {
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( rMouse.X(), rMouse.Y(), eWhich, nPosX, nPosY );
+ // merged (single/Range) ???
+ ScAddress aAddr( nPosX, nPosY, nTab );
+
+ Point aCellStart = mrViewData.GetScrPos( nPosX, nPosY, eWhich, true );
+ Point aCellEnd = aCellStart;
+ tools::Long nSizeXPix;
+ tools::Long nSizeYPix;
+ mrViewData.GetMergeSizePixel( nPosX, nPosY, nSizeXPix, nSizeYPix );
+
+ aCellEnd.AdjustX(nSizeXPix * nLayoutSign );
+ aCellEnd.AdjustY(nSizeYPix );
+
+ bool bCornerHorizontalRight;
+ bool bCornerHorizontalLeft;
+ if ( bLayoutRTL )
+ {
+ bCornerHorizontalRight = ( rMouse.X() >= aCellEnd.X() && rMouse.X() <= aCellEnd.X() + 8 );
+ bCornerHorizontalLeft = ( rMouse.X() >= aCellStart.X() - 8 && rMouse.X() <= aCellStart.X() );
+ }
+ else
+ {
+ bCornerHorizontalRight = ( rMouse.X() >= aCellEnd.X() - 8 && rMouse.X() <= aCellEnd.X() );
+ bCornerHorizontalLeft = ( rMouse.X() >= aCellStart.X() && rMouse.X() <= aCellStart.X() + 8 );
+ }
+
+ bool bCornerVerticalDown = rMouse.Y() >= aCellEnd.Y() - 8 && rMouse.Y() <= aCellEnd.Y();
+ bool bCornerVerticalUp = rMouse.Y() >= aCellStart.Y() && rMouse.Y() <= aCellStart.Y() + 8;
+
+ // corner is hit only if the mouse is within the cell
+ sal_uInt16 nCount = static_cast<sal_uInt16>(pRangeFinder->Count());
+ for (sal_uInt16 i=nCount; i;)
+ {
+ // search backwards so that the last repainted frame is found
+ --i;
+ ScRangeFindData& rData = pRangeFinder->GetObject(i);
+ if ( rData.aRef.Contains(aAddr) )
+ {
+ if (pIndex)
+ *pIndex = i;
+ if (pAddX)
+ *pAddX = nPosX - rData.aRef.aStart.Col();
+ if (pAddY)
+ *pAddY = nPosY - rData.aRef.aStart.Row();
+
+ bFound = true;
+
+ rCorner = NONE;
+
+ ScAddress aEnd = rData.aRef.aEnd;
+ ScAddress aStart = rData.aRef.aStart;
+
+ if ( bCornerHorizontalLeft && bCornerVerticalUp &&
+ aAddr == aStart)
+ {
+ rCorner = LEFT_UP;
+ }
+ else if (bCornerHorizontalRight && bCornerVerticalDown &&
+ aAddr == aEnd)
+ {
+ rCorner = RIGHT_DOWN;
+ }
+ else if (bCornerHorizontalRight && bCornerVerticalUp &&
+ aAddr == ScAddress(aEnd.Col(), aStart.Row(), aStart.Tab()))
+ {
+ rCorner = RIGHT_UP;
+ }
+ else if (bCornerHorizontalLeft && bCornerVerticalDown &&
+ aAddr == ScAddress(aStart.Col(), aEnd.Row(), aStart.Tab()))
+ {
+ rCorner = LEFT_DOWN;
+ }
+ break;
+ }
+ }
+ }
+ }
+ return bFound;
+}
+
+#define SCE_TOP 1
+#define SCE_BOTTOM 2
+#define SCE_LEFT 4
+#define SCE_RIGHT 8
+#define SCE_ALL 15
+
+static void lcl_PaintOneRange( ScDocShell* pDocSh, const ScRange& rRange, sal_uInt16 nEdges )
+{
+ // the range is always properly oriented
+
+ SCCOL nCol1 = rRange.aStart.Col();
+ SCROW nRow1 = rRange.aStart.Row();
+ SCTAB nTab1 = rRange.aStart.Tab();
+ SCCOL nCol2 = rRange.aEnd.Col();
+ SCROW nRow2 = rRange.aEnd.Row();
+ SCTAB nTab2 = rRange.aEnd.Tab();
+ bool bHiddenEdge = false;
+ SCROW nTmp;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ while ( nCol1 > 0 && rDoc.ColHidden(nCol1, nTab1) )
+ {
+ --nCol1;
+ bHiddenEdge = true;
+ }
+ while ( nCol2 < rDoc.MaxCol() && rDoc.ColHidden(nCol2, nTab1) )
+ {
+ ++nCol2;
+ bHiddenEdge = true;
+ }
+ nTmp = rDoc.FirstVisibleRow(0, nRow1, nTab1);
+ if (!rDoc.ValidRow(nTmp))
+ nTmp = 0;
+ if (nTmp < nRow1)
+ {
+ nRow1 = nTmp;
+ bHiddenEdge = true;
+ }
+ nTmp = rDoc.FirstVisibleRow(nRow2, rDoc.MaxRow(), nTab1);
+ if (!rDoc.ValidRow(nTmp))
+ nTmp = rDoc.MaxRow();
+ if (nTmp > nRow2)
+ {
+ nRow2 = nTmp;
+ bHiddenEdge = true;
+ }
+
+ if ( nCol2 > nCol1 + 1 && nRow2 > nRow1 + 1 && !bHiddenEdge )
+ {
+ // Only along the edges (The corners are hit twice)
+ if ( nEdges & SCE_TOP )
+ pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol2, nRow1, nTab2, PaintPartFlags::Marks );
+ if ( nEdges & SCE_LEFT )
+ pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol1, nRow2, nTab2, PaintPartFlags::Marks );
+ if ( nEdges & SCE_RIGHT )
+ pDocSh->PostPaint( nCol2, nRow1, nTab1, nCol2, nRow2, nTab2, PaintPartFlags::Marks );
+ if ( nEdges & SCE_BOTTOM )
+ pDocSh->PostPaint( nCol1, nRow2, nTab1, nCol2, nRow2, nTab2, PaintPartFlags::Marks );
+ }
+ else // everything in one call
+ pDocSh->PostPaint( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2, PaintPartFlags::Marks );
+}
+
+static void lcl_PaintRefChanged( ScDocShell* pDocSh, const ScRange& rOldUn, const ScRange& rNewUn )
+{
+ // Repaint for the parts of the frame in old, which in are no more in New
+
+ ScRange aOld = rOldUn;
+ ScRange aNew = rNewUn;
+ aOld.PutInOrder();
+ aNew.PutInOrder();
+
+ if ( aOld.aStart == aOld.aEnd ) //! Ignore sheet ?
+ pDocSh->GetDocument().ExtendMerge(aOld);
+ if ( aNew.aStart == aNew.aEnd ) //! Ignore sheet ?
+ pDocSh->GetDocument().ExtendMerge(aNew);
+
+ SCCOL nOldCol1 = aOld.aStart.Col();
+ SCROW nOldRow1 = aOld.aStart.Row();
+ SCCOL nOldCol2 = aOld.aEnd.Col();
+ SCROW nOldRow2 = aOld.aEnd.Row();
+ SCCOL nNewCol1 = aNew.aStart.Col();
+ SCROW nNewRow1 = aNew.aStart.Row();
+ SCCOL nNewCol2 = aNew.aEnd.Col();
+ SCROW nNewRow2 = aNew.aEnd.Row();
+ SCTAB nTab1 = aOld.aStart.Tab(); // sheet is not changed
+ SCTAB nTab2 = aOld.aEnd.Tab();
+
+ if ( nNewRow2 < nOldRow1 || nNewRow1 > nOldRow2 ||
+ nNewCol2 < nOldCol1 || nNewCol1 > nOldCol2 ||
+ ( nNewCol1 != nOldCol1 && nNewRow1 != nOldRow1 &&
+ nNewCol2 != nOldCol2 && nNewRow2 != nOldRow2 ) )
+ {
+ // Completely removed or changed all sides
+ // (check <= instead of < goes wrong for single rows/columns)
+
+ lcl_PaintOneRange( pDocSh, aOld, SCE_ALL );
+ }
+ else // Test all four corners separately
+ {
+ // upper part
+ if ( nNewRow1 < nOldRow1 ) // only delete upper line
+ lcl_PaintOneRange( pDocSh, ScRange(
+ nOldCol1, nOldRow1, nTab1, nOldCol2, nOldRow1, nTab2 ), SCE_ALL );
+ else if ( nNewRow1 > nOldRow1 ) // the upper part which is will be removed
+ lcl_PaintOneRange( pDocSh, ScRange(
+ nOldCol1, nOldRow1, nTab1, nOldCol2, nNewRow1-1, nTab2 ),
+ SCE_ALL &~ SCE_BOTTOM );
+
+ // bottom part
+ if ( nNewRow2 > nOldRow2 ) // only delete bottom line
+ lcl_PaintOneRange( pDocSh, ScRange(
+ nOldCol1, nOldRow2, nTab1, nOldCol2, nOldRow2, nTab2 ), SCE_ALL );
+ else if ( nNewRow2 < nOldRow2 ) // the bottom part which is will be removed
+ lcl_PaintOneRange( pDocSh, ScRange(
+ nOldCol1, nNewRow2+1, nTab1, nOldCol2, nOldRow2, nTab2 ),
+ SCE_ALL &~ SCE_TOP );
+
+ // left part
+ if ( nNewCol1 < nOldCol1 ) // only delete left line
+ lcl_PaintOneRange( pDocSh, ScRange(
+ nOldCol1, nOldRow1, nTab1, nOldCol1, nOldRow2, nTab2 ), SCE_ALL );
+ else if ( nNewCol1 > nOldCol1 ) // the left part which is will be removed
+ lcl_PaintOneRange( pDocSh, ScRange(
+ nOldCol1, nOldRow1, nTab1, nNewCol1-1, nOldRow2, nTab2 ),
+ SCE_ALL &~ SCE_RIGHT );
+
+ // right part
+ if ( nNewCol2 > nOldCol2 ) // only delete right line
+ lcl_PaintOneRange( pDocSh, ScRange(
+ nOldCol2, nOldRow1, nTab1, nOldCol2, nOldRow2, nTab2 ), SCE_ALL );
+ else if ( nNewCol2 < nOldCol2 ) // the right part which is will be removed
+ lcl_PaintOneRange( pDocSh, ScRange(
+ nNewCol2+1, nOldRow1, nTab1, nOldCol2, nOldRow2, nTab2 ),
+ SCE_ALL &~ SCE_LEFT );
+ }
+}
+
+void ScGridWindow::RFMouseMove( const MouseEvent& rMEvt, bool bUp )
+{
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl( mrViewData.GetViewShell() );
+ if (!pHdl)
+ return;
+ ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList();
+ if (!pRangeFinder || nRFIndex >= pRangeFinder->Count())
+ return;
+ ScRangeFindData& rData = pRangeFinder->GetObject( nRFIndex );
+
+ // Mouse pointer
+
+ if (bRFSize)
+ SetPointer( PointerStyle::Cross );
+ else
+ SetPointer( PointerStyle::Hand );
+
+ // Scrolling
+
+ bool bTimer = false;
+ Point aPos = rMEvt.GetPosPixel();
+ SCCOL nDx = 0;
+ SCROW nDy = 0;
+ if ( aPos.X() < 0 ) nDx = -1;
+ if ( aPos.Y() < 0 ) nDy = -1;
+ Size aSize = GetOutputSizePixel();
+ if ( aPos.X() >= aSize.Width() )
+ nDx = 1;
+ if ( aPos.Y() >= aSize.Height() )
+ nDy = 1;
+ if ( nDx != 0 || nDy != 0 )
+ {
+ if ( nDx != 0) mrViewData.GetView()->ScrollX( nDx, WhichH(eWhich) );
+ if ( nDy != 0 ) mrViewData.GetView()->ScrollY( nDy, WhichV(eWhich) );
+ bTimer = true;
+ }
+
+ // Switching when fixating (so Scrolling works)
+
+ if ( eWhich == mrViewData.GetActivePart() ) //??
+ {
+ if ( mrViewData.GetHSplitMode() == SC_SPLIT_FIX )
+ if ( nDx > 0 )
+ {
+ if ( eWhich == SC_SPLIT_TOPLEFT )
+ mrViewData.GetView()->ActivatePart( SC_SPLIT_TOPRIGHT );
+ else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
+ mrViewData.GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
+ }
+
+ if ( mrViewData.GetVSplitMode() == SC_SPLIT_FIX )
+ if ( nDy > 0 )
+ {
+ if ( eWhich == SC_SPLIT_TOPLEFT )
+ mrViewData.GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT );
+ else if ( eWhich == SC_SPLIT_TOPRIGHT )
+ mrViewData.GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
+ }
+ }
+
+ // Move
+
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+
+ ScRange aOld = rData.aRef;
+ ScRange aNew = aOld;
+ if ( bRFSize )
+ {
+ switch (aRFSelectedCorned)
+ {
+ case LEFT_UP:
+ aNew.aStart.SetCol(nPosX);
+ aNew.aStart.SetRow(nPosY);
+ break;
+ case LEFT_DOWN:
+ aNew.aStart.SetCol(nPosX);
+ aNew.aEnd.SetRow(nPosY);
+ break;
+ case RIGHT_UP:
+ aNew.aEnd.SetCol(nPosX);
+ aNew.aStart.SetRow(nPosY);
+ break;
+ case RIGHT_DOWN:
+ aNew.aEnd.SetCol(nPosX);
+ aNew.aEnd.SetRow(nPosY);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ ScDocument& rDoc = mrViewData.GetDocument();
+ tools::Long nStartX = nPosX - nRFAddX;
+ if ( nStartX < 0 ) nStartX = 0;
+ tools::Long nStartY = nPosY - nRFAddY;
+ if ( nStartY < 0 ) nStartY = 0;
+ tools::Long nEndX = nStartX + aOld.aEnd.Col() - aOld.aStart.Col();
+ if ( nEndX > rDoc.MaxCol() )
+ {
+ nStartX -= ( nEndX - rDoc.MaxRow() );
+ nEndX = rDoc.MaxCol();
+ }
+ tools::Long nEndY = nStartY + aOld.aEnd.Row() - aOld.aStart.Row();
+ if ( nEndY > rDoc.MaxRow() )
+ {
+ nStartY -= ( nEndY - rDoc.MaxRow() );
+ nEndY = rDoc.MaxRow();
+ }
+
+ aNew.aStart.SetCol(static_cast<SCCOL>(nStartX));
+ aNew.aStart.SetRow(static_cast<SCROW>(nStartY));
+ aNew.aEnd.SetCol(static_cast<SCCOL>(nEndX));
+ aNew.aEnd.SetRow(static_cast<SCROW>(nEndY));
+ }
+
+ if ( bUp )
+ aNew.PutInOrder(); // For ButtonUp again in the proper order
+
+ if ( aNew != aOld )
+ {
+ pHdl->UpdateRange( nRFIndex, aNew );
+
+ ScDocShell* pDocSh = mrViewData.GetDocShell();
+
+ pHdl->UpdateLokReferenceMarks();
+
+ // only redrawing what has been changed...
+ lcl_PaintRefChanged( pDocSh, aOld, aNew );
+
+ // only redraw new frame (synchronously)
+ pDocSh->Broadcast( ScIndexHint( SfxHintId::ScShowRangeFinder, nRFIndex ) );
+
+ PaintImmediately(); // what you move, will be seen immediately
+ }
+
+ // Timer for Scrolling
+
+ if (bTimer)
+ mrViewData.GetView()->SetTimer( this, rMEvt ); // repeat event
+ else
+ mrViewData.GetView()->ResetTimer();
+}
+
+namespace {
+
+SvxAdjust toSvxAdjust( const ScPatternAttr& rPat )
+{
+ SvxCellHorJustify eHorJust =
+ rPat.GetItem(ATTR_HOR_JUSTIFY).GetValue();
+
+ SvxAdjust eSvxAdjust = SvxAdjust::Left;
+ switch (eHorJust)
+ {
+ case SvxCellHorJustify::Left:
+ case SvxCellHorJustify::Repeat: // not implemented
+ case SvxCellHorJustify::Standard: // always Text if an EditCell type
+ eSvxAdjust = SvxAdjust::Left;
+ break;
+ case SvxCellHorJustify::Right:
+ eSvxAdjust = SvxAdjust::Right;
+ break;
+ case SvxCellHorJustify::Center:
+ eSvxAdjust = SvxAdjust::Center;
+ break;
+ case SvxCellHorJustify::Block:
+ eSvxAdjust = SvxAdjust::Block;
+ break;
+ }
+
+ return eSvxAdjust;
+}
+
+std::shared_ptr<ScFieldEditEngine> createEditEngine( ScDocShell* pDocSh, const ScPatternAttr& rPat )
+{
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ auto pEngine = std::make_shared<ScFieldEditEngine>(&rDoc, rDoc.GetEditPool());
+ ScSizeDeviceProvider aProv(pDocSh);
+ pEngine->SetRefDevice(aProv.GetDevice());
+ pEngine->SetRefMapMode(MapMode(MapUnit::Map100thMM));
+ SfxItemSet aDefault = pEngine->GetEmptyItemSet();
+ rPat.FillEditItemSet(&aDefault);
+ aDefault.Put( SvxAdjustItem(toSvxAdjust(rPat), EE_PARA_JUST) );
+ pEngine->SetDefaults(aDefault);
+
+ return pEngine;
+}
+
+bool extractURLInfo( const SvxFieldItem* pFieldItem, OUString* pName, OUString* pUrl, OUString* pTarget )
+{
+ if (!pFieldItem)
+ return false;
+
+ const SvxFieldData* pField = pFieldItem->GetField();
+ if (pField->GetClassId() != text::textfield::Type::URL)
+ return false;
+
+ const SvxURLField* pURLField = static_cast<const SvxURLField*>(pField);
+
+ if (pName)
+ *pName = pURLField->GetRepresentation();
+ if (pUrl)
+ *pUrl = pURLField->GetURL();
+ if (pTarget)
+ *pTarget = pURLField->GetTargetFrame();
+
+ return true;
+}
+
+}
+
+bool ScGridWindow::GetEditUrl( const Point& rPos,
+ OUString* pName, OUString* pUrl, OUString* pTarget )
+{
+ ScTabViewShell* pViewSh = mrViewData.GetViewShell();
+ ScInputHandler* pInputHdl = nullptr;
+ if (pViewSh)
+ pInputHdl = pViewSh->GetInputHandler();
+ EditView* pView = (pInputHdl && pInputHdl->IsInputMode()) ? pInputHdl->GetTableView() : nullptr;
+ if (pView)
+ return extractURLInfo(pView->GetFieldUnderMousePointer(), pName, pUrl, pTarget);
+
+ //! Pass on nPosX/Y?
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( rPos.X(), rPos.Y(), eWhich, nPosX, nPosY );
+
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScDocShell* pDocSh = mrViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ OUString sURL;
+ ScRefCellValue aCell;
+ bool bFound = lcl_GetHyperlinkCell(rDoc, nPosX, nPosY, nTab, aCell, sURL);
+ if( !bFound )
+ return false;
+
+ const ScPatternAttr* pPattern = rDoc.GetPattern( nPosX, nPosY, nTab );
+ // bForceToTop = sal_False, use the cell's real position
+ tools::Rectangle aEditRect = mrViewData.GetEditArea( eWhich, nPosX, nPosY, this, pPattern, false );
+ if (rPos.Y() < aEditRect.Top())
+ return false;
+
+ // vertical can not (yet) be clicked:
+
+ if (pPattern->GetCellOrientation() != SvxCellOrientation::Standard)
+ return false;
+
+ bool bBreak = pPattern->GetItem(ATTR_LINEBREAK).GetValue() ||
+ (pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue() == SvxCellHorJustify::Block);
+ SvxCellHorJustify eHorJust = pPattern->GetItem(ATTR_HOR_JUSTIFY).GetValue();
+
+ // EditEngine
+
+ std::shared_ptr<ScFieldEditEngine> pEngine = createEditEngine(pDocSh, *pPattern);
+
+ MapMode aEditMode = mrViewData.GetLogicMode(eWhich); // without draw scaling
+ tools::Rectangle aLogicEdit = PixelToLogic( aEditRect, aEditMode );
+ tools::Long nThisColLogic = aLogicEdit.Right() - aLogicEdit.Left() + 1;
+ Size aPaperSize( 1000000, 1000000 );
+ if (aCell.meType == CELLTYPE_FORMULA)
+ {
+ tools::Long nSizeX = 0;
+ tools::Long nSizeY = 0;
+ mrViewData.GetMergeSizePixel( nPosX, nPosY, nSizeX, nSizeY );
+ aPaperSize = Size(nSizeX, nSizeY );
+ aPaperSize = PixelToLogic(aPaperSize);
+ }
+
+ if (bBreak)
+ aPaperSize.setWidth( nThisColLogic );
+ pEngine->SetPaperSize( aPaperSize );
+
+ std::unique_ptr<EditTextObject> pTextObj;
+ if (aCell.meType == CELLTYPE_EDIT)
+ {
+ if (aCell.mpEditText)
+ pEngine->SetTextCurrentDefaults(*aCell.mpEditText);
+ }
+ else // Not an Edit cell and is a formula cell with 'Hyperlink'
+ // function if we have no URL, otherwise it could be a formula
+ // cell ( or other type ? ) with a hyperlink associated with it.
+ {
+ if (sURL.isEmpty())
+ pTextObj = aCell.mpFormula->CreateURLObject();
+ else
+ {
+ OUString aRepres = sURL;
+
+ // TODO: text content of formatted numbers can be different
+ if (aCell.hasNumeric())
+ aRepres = OUString::number(aCell.getValue());
+ else if (aCell.meType == CELLTYPE_FORMULA)
+ aRepres = aCell.mpFormula->GetString().getString();
+
+ pTextObj = ScEditUtil::CreateURLObjectFromURL(rDoc, sURL, aRepres);
+ }
+
+ if (pTextObj)
+ pEngine->SetTextCurrentDefaults(*pTextObj);
+ }
+
+ tools::Long nStartX = aLogicEdit.Left();
+
+ tools::Long nTextWidth = pEngine->CalcTextWidth();
+ tools::Long nTextHeight = pEngine->GetTextHeight();
+ if ( nTextWidth < nThisColLogic )
+ {
+ if (eHorJust == SvxCellHorJustify::Right)
+ nStartX += nThisColLogic - nTextWidth;
+ else if (eHorJust == SvxCellHorJustify::Center)
+ nStartX += (nThisColLogic - nTextWidth) / 2;
+ }
+
+ aLogicEdit.SetLeft( nStartX );
+ if (!bBreak)
+ aLogicEdit.SetRight( nStartX + nTextWidth );
+
+ // There is one glitch when dealing with a hyperlink cell and
+ // the cell content is NUMERIC. This defaults to right aligned and
+ // we need to adjust accordingly.
+ if (aCell.hasNumeric() && eHorJust == SvxCellHorJustify::Standard)
+ {
+ aLogicEdit.SetRight( aLogicEdit.Left() + nThisColLogic - 1 );
+ aLogicEdit.SetLeft( aLogicEdit.Right() - nTextWidth );
+ }
+ aLogicEdit.SetBottom( aLogicEdit.Top() + nTextHeight );
+
+ Point aLogicClick = PixelToLogic(rPos,aEditMode);
+ if ( aLogicEdit.Contains(aLogicClick) )
+ {
+ EditView aTempView(pEngine.get(), this);
+ aTempView.SetOutputArea( aLogicEdit );
+
+ bool bRet;
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ bRet = extractURLInfo(aTempView.GetField(aLogicClick), pName, pUrl, pTarget);
+ }
+ else
+ {
+ MapMode aOld = GetMapMode();
+ SetMapMode(aEditMode); // no return anymore
+ bRet = extractURLInfo(aTempView.GetFieldUnderMousePointer(), pName, pUrl, pTarget);
+ SetMapMode(aOld);
+ }
+ return bRet;
+ }
+ return false;
+}
+
+bool ScGridWindow::HasScenarioButton( const Point& rPosPixel, ScRange& rScenRange )
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ if ( nTab+1<nTabCount && rDoc.IsScenario(nTab+1) && !rDoc.IsScenario(nTab) )
+ {
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ Size aButSize = mrViewData.GetScenButSize();
+ tools::Long nBWidth = aButSize.Width();
+ if (!nBWidth)
+ return false; // No Button drawn yet -> there is none
+ tools::Long nBHeight = aButSize.Height();
+ tools::Long nHSpace = static_cast<tools::Long>( SC_SCENARIO_HSPACE * mrViewData.GetPPTX() );
+
+ //! cache the Ranges in Table!!!!
+
+ ScMarkData aMarks(rDoc.GetSheetLimits());
+ for (SCTAB i=nTab+1; i<nTabCount && rDoc.IsScenario(i); i++)
+ rDoc.MarkScenario( i, nTab, aMarks, false, ScScenarioFlags::ShowFrame );
+ ScRangeList aRanges;
+ aMarks.FillRangeListWithMarks( &aRanges, false );
+
+ size_t nRangeCount = aRanges.size();
+ for (size_t j=0; j< nRangeCount; ++j)
+ {
+ ScRange aRange = aRanges[j];
+ // Always extend scenario frame to merged cells where no new non-covered cells
+ // are framed
+ rDoc.ExtendTotalMerge( aRange );
+
+ bool bTextBelow = ( aRange.aStart.Row() == 0 );
+
+ Point aButtonPos;
+ if ( bTextBelow )
+ {
+ aButtonPos = mrViewData.GetScrPos( aRange.aEnd.Col()+1, aRange.aEnd.Row()+1,
+ eWhich, true );
+ }
+ else
+ {
+ aButtonPos = mrViewData.GetScrPos( aRange.aEnd.Col()+1, aRange.aStart.Row(),
+ eWhich, true );
+ aButtonPos.AdjustY( -nBHeight );
+ }
+ if ( bLayoutRTL )
+ aButtonPos.AdjustX( -(nHSpace - 1) );
+ else
+ aButtonPos.AdjustX( -(nBWidth - nHSpace) ); // same for top or bottom
+
+ tools::Rectangle aButRect( aButtonPos, Size(nBWidth,nBHeight) );
+ if ( aButRect.Contains( rPosPixel ) )
+ {
+ rScenRange = aRange;
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+void ScGridWindow::DrawLayerCreated()
+{
+ SetMapMode( GetDrawMapMode() );
+
+ // initially create overlay objects
+ ImpCreateOverlayObjects();
+}
+
+void ScGridWindow::SetAutoSpellContext( const std::shared_ptr<sc::SpellCheckContext> &ctx )
+{
+ mpSpellCheckCxt = ctx;
+}
+
+void ScGridWindow::ResetAutoSpell()
+{
+ if (mpSpellCheckCxt)
+ mpSpellCheckCxt->reset();
+}
+
+void ScGridWindow::ResetAutoSpellForContentChange()
+{
+ if (mpSpellCheckCxt)
+ mpSpellCheckCxt->resetForContentChange();
+}
+
+void ScGridWindow::SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const std::vector<editeng::MisspellRanges>* pRanges )
+{
+ if (!mpSpellCheckCxt)
+ return;
+
+ mpSpellCheckCxt->setMisspellRanges(nPosX, nPosY, pRanges);
+}
+
+const std::vector<editeng::MisspellRanges>* ScGridWindow::GetAutoSpellData( SCCOL nPosX, SCROW nPosY )
+{
+ if (!mpSpellCheckCxt)
+ return nullptr;
+
+ if (!maVisibleRange.isInside(nPosX, nPosY))
+ return nullptr;
+
+ return mpSpellCheckCxt->getMisspellRanges(nPosX, nPosY);
+}
+
+bool ScGridWindow::InsideVisibleRange( SCCOL nPosX, SCROW nPosY )
+{
+ return maVisibleRange.isInside(nPosX, nPosY);
+}
+
+OString ScGridWindow::getCellCursor() const
+{
+ // GridWindow stores a shown cell cursor in mpOOCursors, hence
+ // we can use that to determine whether we would want to be showing
+ // one (client-side) for tiled rendering too.
+ if (!mpOOCursors)
+ return "EMPTY";
+
+ if (comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ return mrViewData.describeCellCursorInPrintTwips();
+
+ return mrViewData.describeCellCursor();
+}
+
+void ScGridWindow::notifyKitCellCursor() const
+{
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_CURSOR, getCellCursor().getStr());
+ if (bListValButton && aListValPos == mrViewData.GetCurPos())
+ updateLOKValListButton(true, aListValPos);
+ std::vector<tools::Rectangle> aRects;
+ GetSelectionRects(aRects);
+ if (aRects.empty() || !mrViewData.IsActive())
+ {
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, "");
+ SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "EMPTY");
+ }
+}
+
+void ScGridWindow::notifyKitCellViewCursor(const SfxViewShell* pForShell) const
+{
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+
+ if (pViewShell->GetDocId() != pForShell->GetDocId())
+ return;
+
+ OString aCursor("EMPTY");
+ if (mpOOCursors) // cf. getCellCursor above
+ {
+ auto pForTabView = dynamic_cast<const ScTabViewShell *>(pForShell);
+ if (!pForTabView)
+ return;
+
+ if (comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ aCursor = mrViewData.describeCellCursorInPrintTwips();
+ else
+ aCursor = pForTabView->GetViewData().describeCellCursorAt(
+ mrViewData.GetCurX(), mrViewData.GetCurY()); // our position.
+ }
+ SfxLokHelper::notifyOtherView(pViewShell, pForShell, LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", aCursor);
+}
+
+// Send our cursor details to a view described by @pForShell, or all views
+// if @pForShell is null. In each case send the current view a cell-cursor
+// event, and others a cell_view_cursor event.
+//
+// NB. we need to re-construct the cursor details for each other view in their
+// own zoomed co-ordinate system (but not in scPrintTwipsMsgs mode).
+void ScGridWindow::updateKitCellCursor(const SfxViewShell* pForShell) const
+{
+ if (comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ {
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ // Generate the cursor info string just once and directly send to all.
+ // Calling notifyKitCellViewCursor() would regenerate the
+ // cursor-string unnecessarily.
+ OString aCursor = getCellCursor();
+
+ if (pForShell)
+ {
+ SfxLokHelper::notifyOtherView(pViewShell, pForShell,
+ LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", aCursor);
+ }
+ else
+ {
+ notifyKitCellCursor();
+ SfxLokHelper::notifyOtherViews(pViewShell,
+ LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", aCursor);
+ }
+
+ return;
+ }
+
+ if (!pForShell)
+ {
+ for (SfxViewShell* it = SfxViewShell::GetFirst(); it;
+ it = SfxViewShell::GetNext(*it))
+ updateKitCellCursor(it);
+ return;
+ }
+
+ if (pForShell == mrViewData.GetViewShell())
+ notifyKitCellCursor();
+ else
+ notifyKitCellViewCursor(pForShell);
+}
+
+void ScGridWindow::updateKitOtherCursors() const
+{
+ for (SfxViewShell* it = SfxViewShell::GetFirst(); it;
+ it = SfxViewShell::GetNext(*it))
+ {
+ auto pOther = dynamic_cast<const ScTabViewShell *>(it);
+ if (!pOther)
+ continue;
+ const ScGridWindow *pGrid = pOther->GetViewData().GetActiveWin();
+ assert(pGrid);
+ if (pGrid == this)
+ notifyKitCellCursor();
+ else
+ pGrid->notifyKitCellViewCursor(mrViewData.GetViewShell());
+ }
+}
+
+void ScGridWindow::CursorChanged()
+{
+ // here the created OverlayObjects may be transformed in later versions. For
+ // now, just re-create them
+
+ UpdateCursorOverlay();
+ UpdateSparklineGroupOverlay();
+}
+
+void ScGridWindow::ImpCreateOverlayObjects()
+{
+ UpdateCursorOverlay();
+ UpdateCopySourceOverlay();
+ UpdateSelectionOverlay();
+ UpdateAutoFillOverlay();
+ UpdateDragRectOverlay();
+ UpdateHeaderOverlay();
+ UpdateShrinkOverlay();
+ UpdateSparklineGroupOverlay();
+}
+
+void ScGridWindow::ImpDestroyOverlayObjects()
+{
+ DeleteCursorOverlay();
+ DeleteCopySourceOverlay();
+ DeleteSelectionOverlay();
+ DeleteAutoFillOverlay();
+ DeleteDragRectOverlay();
+ DeleteHeaderOverlay();
+ DeleteShrinkOverlay();
+ DeleteSparklineGroupOverlay();
+}
+
+void ScGridWindow::UpdateAllOverlays()
+{
+ // delete and re-allocate all overlay objects
+
+ ImpDestroyOverlayObjects();
+ ImpCreateOverlayObjects();
+}
+
+void ScGridWindow::DeleteCursorOverlay()
+{
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_CURSOR, "EMPTY");
+ SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", "EMPTY");
+ mpOOCursors.reset();
+}
+
+void ScGridWindow::DeleteCopySourceOverlay()
+{
+ mpOOSelectionBorder.reset();
+}
+
+void ScGridWindow::UpdateCopySourceOverlay()
+{
+ MapMode aDrawMode = GetDrawMapMode();
+ MapMode aOldMode = GetMapMode();
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aDrawMode );
+
+ DeleteCopySourceOverlay();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+ if (!mrViewData.ShowPasteSource())
+ return;
+ if (!SC_MOD()->GetInputOptions().GetEnterPasteMode())
+ return;
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
+ if (!xOverlayManager.is())
+ return;
+ const ScTransferObj* pTransObj = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(mrViewData.GetActiveWin()));
+ if (!pTransObj)
+ return;
+ ScDocument* pClipDoc = pTransObj->GetDocument();
+ if (!pClipDoc)
+ return;
+
+ SCTAB nCurTab = mrViewData.GetCurPos().Tab();
+
+ ScClipParam& rClipParam = pClipDoc->GetClipParam();
+ mpOOSelectionBorder.reset(new sdr::overlay::OverlayObjectList);
+ for ( size_t i = 0; i < rClipParam.maRanges.size(); ++i )
+ {
+ ScRange const & r = rClipParam.maRanges[i];
+ if (r.aStart.Tab() != nCurTab)
+ continue;
+
+ SCCOL nClipStartX = r.aStart.Col();
+ SCROW nClipStartY = r.aStart.Row();
+ SCCOL nClipEndX = r.aEnd.Col();
+ SCROW nClipEndY = r.aEnd.Row();
+
+ Point aClipStartScrPos = mrViewData.GetScrPos( nClipStartX, nClipStartY, eWhich );
+ Point aClipEndScrPos = mrViewData.GetScrPos( nClipEndX + 1, nClipEndY + 1, eWhich );
+ aClipStartScrPos -= Point(1, 1);
+ tools::Long nSizeXPix = aClipEndScrPos.X() - aClipStartScrPos.X();
+ tools::Long nSizeYPix = aClipEndScrPos.Y() - aClipStartScrPos.Y();
+
+ tools::Rectangle aRect( aClipStartScrPos, Size(nSizeXPix, nSizeYPix) );
+
+ Color aHighlight = GetSettings().GetStyleSettings().GetHighlightColor();
+
+ tools::Rectangle aLogic = PixelToLogic(aRect, aDrawMode);
+ ::basegfx::B2DRange aRange = vcl::unotools::b2DRectangleFromRectangle(aLogic);
+ std::unique_ptr<ScOverlayDashedBorder> pDashedBorder(new ScOverlayDashedBorder(aRange, aHighlight));
+ xOverlayManager->add(*pDashedBorder);
+ mpOOSelectionBorder->append(std::move(pDashedBorder));
+ }
+
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aOldMode );
+}
+
+static std::vector<tools::Rectangle> convertPixelToLogical(
+ const ScViewData& rViewData,
+ const std::vector<tools::Rectangle>& rRectangles,
+ tools::Rectangle &rBoundingBox)
+{
+ std::vector<tools::Rectangle> aLogicRects;
+
+ double nPPTX = rViewData.GetPPTX();
+ double nPPTY = rViewData.GetPPTY();
+
+ for (const auto& rRectangle : rRectangles)
+ {
+ // We explicitly create a copy, since we need to expand
+ // the rectangle before coordinate conversion
+ tools::Rectangle aRectangle(rRectangle);
+ aRectangle.AdjustRight(1 );
+ aRectangle.AdjustBottom(1 );
+
+ tools::Rectangle aRect(aRectangle.Left() / nPPTX, aRectangle.Top() / nPPTY,
+ aRectangle.Right() / nPPTX, aRectangle.Bottom() / nPPTY);
+
+ rBoundingBox.Union(aRect);
+ aLogicRects.push_back(aRect);
+ }
+ return aLogicRects;
+}
+
+static OString rectanglesToString(const std::vector<tools::Rectangle> &rLogicRects)
+{
+ bool bFirst = true;
+ OStringBuffer aRects;
+ for (const auto &rRect : rLogicRects)
+ {
+ if (!bFirst)
+ aRects.append("; ");
+ bFirst = false;
+ aRects.append(rRect.toString());
+ }
+ return aRects.makeStringAndClear();
+}
+
+/**
+ * Turn the selection ranges rRectangles into the LibreOfficeKit selection, and send to other views.
+ *
+ * @param pLogicRects - if set then don't invoke the callback, just collect the rectangles in the pointed vector.
+ */
+void ScGridWindow::UpdateKitSelection(const std::vector<tools::Rectangle>& rRectangles, std::vector<tools::Rectangle>* pLogicRects)
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ // If this is true, rRectangles should already in print twips.
+ // If false, rRectangles are in pixels.
+ bool bInPrintTwips = comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
+
+ tools::Rectangle aBoundingBox;
+ std::vector<tools::Rectangle> aConvertedRects;
+
+ if (bInPrintTwips)
+ std::for_each(rRectangles.begin(), rRectangles.end(),
+ [&aBoundingBox](const tools::Rectangle& rRect) { aBoundingBox.Union(rRect); });
+ else
+ aConvertedRects = convertPixelToLogical(mrViewData, rRectangles, aBoundingBox);
+
+ const std::vector<tools::Rectangle>& rLogicRects = bInPrintTwips ? rRectangles : aConvertedRects;
+ if (pLogicRects)
+ {
+ *pLogicRects = rLogicRects;
+ return;
+ }
+
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ pViewShell->UpdateInputHandler();
+ OString sBoundingBoxString = "EMPTY";
+ if (!aBoundingBox.IsEmpty())
+ sBoundingBoxString = aBoundingBox.toString();
+ OString aRectListString = rectanglesToString(rLogicRects);
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_SELECTION_AREA, sBoundingBoxString.getStr());
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, aRectListString.getStr());
+
+ if (bInPrintTwips)
+ {
+ SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION,
+ "selection", aRectListString);
+ return;
+ }
+
+ for (SfxViewShell* it = SfxViewShell::GetFirst(); it;
+ it = SfxViewShell::GetNext(*it))
+ {
+ if (it == pViewShell)
+ continue;
+ auto pOther = dynamic_cast<const ScTabViewShell *>(it);
+ if (!pOther)
+ return;
+
+ const ScGridWindow *pGrid = pOther->GetViewData().GetActiveWin();
+ assert(pGrid);
+
+ // Fetch pixels & convert for each view separately.
+ tools::Rectangle aDummyBBox;
+ std::vector<tools::Rectangle> aPixelRects;
+ pGrid->GetPixelRectsFor(mrViewData.GetMarkData() /* ours */, aPixelRects);
+ auto aOtherLogicRects = convertPixelToLogical(pOther->GetViewData(), aPixelRects, aDummyBBox);
+ SfxLokHelper::notifyOtherView(pViewShell, pOther, LOK_CALLBACK_TEXT_VIEW_SELECTION,
+ "selection", rectanglesToString(aOtherLogicRects).getStr());
+ }
+}
+
+/**
+ * Fetch the selection ranges for other views into the LibreOfficeKit selection,
+ * map them into our view co-ordinates and send to our view.
+ */
+void ScGridWindow::updateOtherKitSelections() const
+{
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ bool bInPrintTwips = comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
+
+ for (SfxViewShell* it = SfxViewShell::GetFirst(); it;
+ it = SfxViewShell::GetNext(*it))
+ {
+ auto pOther = dynamic_cast<const ScTabViewShell *>(it);
+ if (!pOther)
+ return;
+
+ // Fetch pixels & convert for each view separately.
+ tools::Rectangle aBoundingBox;
+ std::vector<tools::Rectangle> aRects;
+ OString aRectsString;
+ GetRectsAnyFor(pOther->GetViewData().GetMarkData() /* theirs */, aRects, bInPrintTwips);
+ if (bInPrintTwips)
+ {
+ std::for_each(aRects.begin(), aRects.end(),
+ [&aBoundingBox](const tools::Rectangle& rRect) { aBoundingBox.Union(rRect); });
+ aRectsString = rectanglesToString(aRects);
+ }
+ else
+ aRectsString = rectanglesToString(
+ convertPixelToLogical(pViewShell->GetViewData(), aRects, aBoundingBox));
+
+ if (it == pViewShell)
+ {
+ OString sBoundingBoxString = "EMPTY";
+ if (!aBoundingBox.IsEmpty())
+ sBoundingBoxString = aBoundingBox.toString();
+
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_SELECTION_AREA, sBoundingBoxString.getStr());
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, aRectsString.getStr());
+ }
+ else
+ SfxLokHelper::notifyOtherView(it, pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION,
+ "selection", aRectsString);
+ }
+}
+
+namespace
+{
+
+void updateLibreOfficeKitAutoFill(const ScViewData& rViewData, tools::Rectangle const & rRectangle)
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ double nPPTX = rViewData.GetPPTX();
+ double nPPTY = rViewData.GetPPTY();
+
+ OString sRectangleString = "EMPTY";
+ if (!rRectangle.IsEmpty())
+ {
+ // selection start handle
+ tools::Rectangle aLogicRectangle(
+ rRectangle.Left() / nPPTX, rRectangle.Top() / nPPTY,
+ rRectangle.Right() / nPPTX, rRectangle.Bottom() / nPPTY);
+ sRectangleString = aLogicRectangle.toString();
+ }
+
+ ScTabViewShell* pViewShell = rViewData.GetViewShell();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_AUTO_FILL_AREA, sRectangleString.getStr());
+}
+
+} //end anonymous namespace
+
+void ScGridWindow::UpdateCursorOverlay()
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+
+ MapMode aDrawMode = GetDrawMapMode();
+ MapMode aOldMode = GetMapMode();
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aDrawMode );
+
+ // Existing OverlayObjects may be transformed in later versions.
+ // For now, just re-create them.
+
+ DeleteCursorOverlay();
+
+ std::vector<tools::Rectangle> aPixelRects;
+
+ // determine the cursor rectangles in pixels (moved from ScGridWindow::DrawCursor)
+
+ SCTAB nTab = mrViewData.GetTabNo();
+ SCCOL nX = mrViewData.GetCurX();
+ SCROW nY = mrViewData.GetCurY();
+
+ const ScPatternAttr* pPattern = rDoc.GetPattern(nX,nY,nTab);
+
+ if (!comphelper::LibreOfficeKit::isActive() && !maVisibleRange.isInside(nX, nY))
+ {
+ if (maVisibleRange.mnCol2 < nX || maVisibleRange.mnRow2 < nY)
+ return; // no further check needed, nothing visible
+
+ // fdo#87382 Also display the cell cursor for the visible part of
+ // merged cells if the view position is part of merged cells.
+ const ScMergeAttr& rMerge = pPattern->GetItem(ATTR_MERGE);
+ if (rMerge.GetColMerge() <= 1 && rMerge.GetRowMerge() <= 1)
+ return; // not merged and invisible
+
+ SCCOL nX2 = nX + rMerge.GetColMerge() - 1;
+ SCROW nY2 = nY + rMerge.GetRowMerge() - 1;
+ // Check if the middle or tail of the merged range is visible.
+ if (maVisibleRange.mnCol1 > nX2 || maVisibleRange.mnRow1 > nY2)
+ return; // no visible part
+ }
+
+ // don't show the cursor in overlapped cells
+ const ScMergeFlagAttr& rMergeFlag = pPattern->GetItem(ATTR_MERGE_FLAG);
+ bool bOverlapped = rMergeFlag.IsOverlapped();
+
+ // left or above of the screen?
+ bool bVis = comphelper::LibreOfficeKit::isActive() || ( nX>=mrViewData.GetPosX(eHWhich) && nY>=mrViewData.GetPosY(eVWhich) );
+ if (!bVis)
+ {
+ SCCOL nEndX = nX;
+ SCROW nEndY = nY;
+ const ScMergeAttr& rMerge = pPattern->GetItem(ATTR_MERGE);
+ if (rMerge.GetColMerge() > 1)
+ nEndX += rMerge.GetColMerge()-1;
+ if (rMerge.GetRowMerge() > 1)
+ nEndY += rMerge.GetRowMerge()-1;
+ bVis = ( nEndX>=mrViewData.GetPosX(eHWhich) && nEndY>=mrViewData.GetPosY(eVWhich) );
+ }
+
+ if ( bVis && !bOverlapped && !mrViewData.HasEditView(eWhich) && mrViewData.IsActive() )
+ {
+ Point aScrPos = mrViewData.GetScrPos( nX, nY, eWhich, true );
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ // completely right of/below the screen?
+ // (test with logical start position in aScrPos)
+ bool bMaybeVisible;
+ if ( bLayoutRTL )
+ bMaybeVisible = ( aScrPos.X() >= -2 && aScrPos.Y() >= -2 );
+ else
+ {
+ Size aOutSize = GetOutputSizePixel();
+ bMaybeVisible = ( aScrPos.X() <= aOutSize.Width() + 2 && aScrPos.Y() <= aOutSize.Height() + 2 );
+ }
+
+ // in the tiled rendering case, don't limit to the screen size
+ if (bMaybeVisible || comphelper::LibreOfficeKit::isActive())
+ {
+ tools::Long nSizeXPix;
+ tools::Long nSizeYPix;
+ mrViewData.GetMergeSizePixel( nX, nY, nSizeXPix, nSizeYPix );
+
+ if (bLayoutRTL)
+ aScrPos.AdjustX( -(nSizeXPix - 2) ); // move instead of mirroring
+
+ // show the cursor as 4 (thin) rectangles
+ tools::Rectangle aRect(aScrPos, Size(nSizeXPix - 1, nSizeYPix - 1));
+
+ float fScaleFactor = GetDPIScaleFactor();
+
+ tools::Long aCursorWidth = 1 * fScaleFactor;
+
+ tools::Rectangle aLeft = aRect;
+ aLeft.AdjustTop( -aCursorWidth );
+ aLeft.AdjustBottom(aCursorWidth );
+ aLeft.SetRight( aLeft.Left() );
+ aLeft.AdjustLeft( -aCursorWidth );
+
+ tools::Rectangle aRight = aRect;
+ aRight.AdjustTop( -aCursorWidth );
+ aRight.AdjustBottom(aCursorWidth );
+ aRight.SetLeft( aRight.Right() );
+ aRight.AdjustRight(aCursorWidth );
+
+ tools::Rectangle aTop = aRect;
+ aTop.SetBottom( aTop.Top() );
+ aTop.AdjustTop( -aCursorWidth );
+
+ tools::Rectangle aBottom = aRect;
+ aBottom.SetTop( aBottom.Bottom() );
+ aBottom.AdjustBottom(aCursorWidth );
+
+ aPixelRects.push_back(aLeft);
+ aPixelRects.push_back(aRight);
+ aPixelRects.push_back(aTop);
+ aPixelRects.push_back(aBottom);
+ }
+ }
+
+ if ( !aPixelRects.empty() )
+ {
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ mpOOCursors.reset(new sdr::overlay::OverlayObjectList);
+ updateKitCellCursor(nullptr);
+ }
+ else
+ {
+ // #i70788# get the OverlayManager safely
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
+
+ if (xOverlayManager.is())
+ {
+ Color aCursorColor = GetSettings().GetStyleSettings().GetHighlightColor();
+ if (mrViewData.GetActivePart() != eWhich)
+ // non-active pane uses a different color.
+ aCursorColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor;
+ std::vector< basegfx::B2DRange > aRanges;
+ const basegfx::B2DHomMatrix aTransform(GetOutDev()->GetInverseViewTransformation());
+
+ // tdf#143733, tdf#145080 - improve border visibility
+ // constants picked for maximum consistency at 100% and adequate response on zoom
+ // line width = 1.5 at 100% (0.75 left +/- 0.75 right), 50% = 1, 200% = 1.25, 400% = 2.25
+ const double MinSize = 0.25 * GetDPIScaleFactor();
+ double fZoom(mrViewData.GetZoomX() * 0.5);
+ for(const tools::Rectangle & rRA : aPixelRects)
+ {
+ basegfx::B2DRange aRB(rRA.Left() - MinSize - fZoom, rRA.Top() - MinSize - fZoom,
+ rRA.Right() + MinSize + fZoom, rRA.Bottom() + MinSize + fZoom);
+ aRB.transform(aTransform);
+ aRanges.push_back(aRB);
+ }
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
+ sdr::overlay::OverlayType::Solid,
+ aCursorColor,
+ std::move(aRanges),
+ false));
+
+ xOverlayManager->add(*pOverlay);
+ mpOOCursors.reset(new sdr::overlay::OverlayObjectList);
+ mpOOCursors->append(std::move(pOverlay));
+ }
+ }
+ }
+
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aOldMode );
+}
+
+void ScGridWindow::GetCellSelection(std::vector<tools::Rectangle>& rLogicRects)
+{
+ std::vector<tools::Rectangle> aRects;
+ if (comphelper::LibreOfficeKit::isActive() &&
+ comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ GetSelectionRectsPrintTwips(aRects);
+ else
+ GetSelectionRects(aRects);
+ UpdateKitSelection(aRects, &rLogicRects);
+}
+
+void ScGridWindow::DeleteSelectionOverlay()
+{
+ mpOOSelection.reset();
+}
+
+void ScGridWindow::UpdateSelectionOverlay()
+{
+ MapMode aDrawMode = GetDrawMapMode();
+ MapMode aOldMode = GetMapMode();
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aDrawMode );
+
+ DeleteSelectionOverlay();
+ std::vector<tools::Rectangle> aRects;
+ if (comphelper::LibreOfficeKit::isActive() &&
+ comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ GetSelectionRectsPrintTwips(aRects);
+ else
+ GetSelectionRects(aRects);
+
+ if (!aRects.empty() && mrViewData.IsActive())
+ {
+ // #i70788# get the OverlayManager safely
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // notify the LibreOfficeKit too
+ UpdateKitSelection(aRects);
+ }
+ else if (xOverlayManager.is())
+ {
+ std::vector< basegfx::B2DRange > aRanges;
+ const basegfx::B2DHomMatrix aTransform(GetOutDev()->GetInverseViewTransformation());
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ for(const tools::Rectangle & rRA : aRects)
+ {
+ if (bLayoutRTL)
+ {
+ basegfx::B2DRange aRB(rRA.Left(), rRA.Top() - 1, rRA.Right() + 1, rRA.Bottom());
+ aRB.transform(aTransform);
+ aRanges.push_back(aRB);
+ }
+ else
+ {
+ basegfx::B2DRange aRB(rRA.Left() - 1, rRA.Top() - 1, rRA.Right(), rRA.Bottom());
+ aRB.transform(aTransform);
+ aRanges.push_back(aRB);
+ }
+ }
+
+ // get the system's highlight color
+ const Color aHighlight(SvtOptionsDrawinglayer::getHilightColor());
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
+ sdr::overlay::OverlayType::Transparent,
+ aHighlight,
+ std::move(aRanges),
+ true));
+
+ xOverlayManager->add(*pOverlay);
+ mpOOSelection.reset(new sdr::overlay::OverlayObjectList);
+ mpOOSelection->append(std::move(pOverlay));
+ }
+ }
+ else
+ {
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, "EMPTY");
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_SELECTION_AREA, "EMPTY");
+ SfxLokHelper::notifyOtherViews(pViewShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection", "EMPTY");
+
+ ScInputHandler* pViewHdl = SC_MOD()->GetInputHdl(pViewShell);
+ if (!pViewHdl || !pViewHdl->IsEditMode())
+ {
+ std::vector<ReferenceMark> aReferenceMarks;
+ ScInputHandler::SendReferenceMarks(pViewShell, aReferenceMarks);
+ }
+ }
+
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aOldMode );
+}
+
+void ScGridWindow::DeleteAutoFillOverlay()
+{
+ mpOOAutoFill.reset();
+ mpAutoFillRect.reset();
+}
+
+void ScGridWindow::UpdateAutoFillOverlay()
+{
+ MapMode aDrawMode = GetDrawMapMode();
+ MapMode aOldMode = GetMapMode();
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aDrawMode );
+
+ DeleteAutoFillOverlay();
+
+ // get the AutoFill handle rectangle in pixels
+
+ if ( !(bAutoMarkVisible && aAutoMarkPos.Tab() == mrViewData.GetTabNo() &&
+ !mrViewData.HasEditView(eWhich) && mrViewData.IsActive()) )
+ return;
+
+ SCCOL nX = aAutoMarkPos.Col();
+ SCROW nY = aAutoMarkPos.Row();
+
+ if (!maVisibleRange.isInside(nX, nY) && !comphelper::LibreOfficeKit::isActive())
+ {
+ // Autofill mark is not visible. Bail out.
+ return;
+ }
+
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScDocument& rDoc = mrViewData.GetDocument();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ // tdf#143733 tdf#145080 - improve border visibility
+ // constants picked for maximum consistency at 100%
+ // size = 6 at 100% (as before), 50% = 4.5, 200% = 9, 400% = 15
+ const float fScaleFactor = 3 * GetDPIScaleFactor();
+ const double fZoom(3 * mrViewData.GetZoomX());
+ // Size should be even
+ Size aFillHandleSize(fZoom + fScaleFactor, fZoom + fScaleFactor);
+
+ Point aFillPos = mrViewData.GetScrPos( nX, nY, eWhich, true );
+ tools::Long nSizeXPix;
+ tools::Long nSizeYPix;
+ mrViewData.GetMergeSizePixel( nX, nY, nSizeXPix, nSizeYPix );
+
+ if (bLayoutRTL)
+ aFillPos.AdjustX( -(nSizeXPix - 2 + (aFillHandleSize.Width() / 2)) );
+ else
+ aFillPos.AdjustX(nSizeXPix - (aFillHandleSize.Width() / 2) );
+
+ aFillPos.AdjustY(nSizeYPix );
+ aFillPos.AdjustY( -(aFillHandleSize.Height() / 2) );
+
+ tools::Rectangle aFillRect(aFillPos, aFillHandleSize);
+
+ // expand rect to increase hit area
+ mpAutoFillRect = aFillRect;
+ mpAutoFillRect->expand(fScaleFactor);
+
+ // #i70788# get the OverlayManager safely
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
+ if (comphelper::LibreOfficeKit::isActive()) // notify the LibreOfficeKit
+ {
+ updateLibreOfficeKitAutoFill(mrViewData, aFillRect);
+ }
+ else if (xOverlayManager.is())
+ {
+ Color aHandleColor = GetSettings().GetStyleSettings().GetHighlightColor();
+ if (mrViewData.GetActivePart() != eWhich)
+ // non-active pane uses a different color.
+ aHandleColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor;
+ std::vector< basegfx::B2DRange > aRanges;
+ const basegfx::B2DHomMatrix aTransform(GetOutDev()->GetInverseViewTransformation());
+ basegfx::B2DRange aRB = vcl::unotools::b2DRectangleFromRectangle(aFillRect);
+
+ aRB.transform(aTransform);
+ aRanges.push_back(aRB);
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
+ sdr::overlay::OverlayType::Solid,
+ aHandleColor,
+ std::move(aRanges),
+ false));
+
+ xOverlayManager->add(*pOverlay);
+ mpOOAutoFill.reset(new sdr::overlay::OverlayObjectList);
+ mpOOAutoFill->append(std::move(pOverlay));
+ }
+
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aOldMode );
+}
+
+void ScGridWindow::DeleteDragRectOverlay()
+{
+ mpOODragRect.reset();
+}
+
+void ScGridWindow::UpdateDragRectOverlay()
+{
+ bool bInPrintTwips = comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
+
+ MapMode aDrawMode = GetDrawMapMode();
+ MapMode aOldMode = GetMapMode();
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aDrawMode );
+
+ DeleteDragRectOverlay();
+
+ // get the rectangles in pixels (moved from DrawDragRect)
+
+ if ( bDragRect || bPagebreakDrawn )
+ {
+ std::vector<tools::Rectangle> aPixelRects;
+
+ SCCOL nX1 = bDragRect ? nDragStartX : aPagebreakDrag.aStart.Col();
+ SCROW nY1 = bDragRect ? nDragStartY : aPagebreakDrag.aStart.Row();
+ SCCOL nX2 = bDragRect ? nDragEndX : aPagebreakDrag.aEnd.Col();
+ SCROW nY2 = bDragRect ? nDragEndY : aPagebreakDrag.aEnd.Row();
+
+ SCTAB nTab = mrViewData.GetTabNo();
+
+ SCCOL nPosX = mrViewData.GetPosX(WhichH(eWhich));
+ SCROW nPosY = mrViewData.GetPosY(WhichV(eWhich));
+ if (nX1 < nPosX) nX1 = nPosX;
+ if (nX2 < nPosX) nX2 = nPosX;
+ if (nY1 < nPosY) nY1 = nPosY;
+ if (nY2 < nPosY) nY2 = nPosY;
+
+ Point aScrPos(bInPrintTwips ? mrViewData.GetPrintTwipsPos( nX1, nY1 )
+ : mrViewData.GetScrPos( nX1, nY1, eWhich ) );
+
+ tools::Long nSizeXPix=0;
+ tools::Long nSizeYPix=0;
+ ScDocument& rDoc = mrViewData.GetDocument();
+ double nPPTX = mrViewData.GetPPTX();
+ double nPPTY = mrViewData.GetPPTY();
+ SCCOLROW i;
+
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+ tools::Long nAdjust = comphelper::LibreOfficeKit::isActive() ? 0 : 2;
+
+ if (rDoc.ValidCol(nX2) && nX2>=nX1)
+ for (i=nX1; i<=nX2; i++)
+ {
+ tools::Long nWidth = rDoc.GetColWidth( static_cast<SCCOL>(i), nTab );
+ nSizeXPix += bInPrintTwips ? nWidth : ScViewData::ToPixel( nWidth, nPPTX );
+ }
+ else
+ {
+ aScrPos.AdjustX( -nLayoutSign );
+ nSizeXPix += nAdjust;
+ }
+
+ if (rDoc.ValidRow(nY2) && nY2>=nY1)
+ for (i=nY1; i<=nY2; i++)
+ {
+ tools::Long nHeight = rDoc.GetRowHeight( i, nTab );
+ nSizeYPix += bInPrintTwips ? nHeight : ScViewData::ToPixel( nHeight, nPPTY );
+ }
+ else
+ {
+ aScrPos.AdjustY( -1 );
+ nSizeYPix += nAdjust;
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ nSizeXPix -= 2;
+ nSizeYPix -= 2;
+ }
+
+ aScrPos.AdjustX( -(nAdjust * nLayoutSign) );
+ aScrPos.AdjustY( -1 * nAdjust );
+ tools::Rectangle aRect( aScrPos.X(), aScrPos.Y(),
+ aScrPos.X() + ( nSizeXPix + nAdjust ) * nLayoutSign, aScrPos.Y() + nSizeYPix + nAdjust );
+ if ( bLayoutRTL )
+ {
+ aRect.SetLeft( aRect.Right() ); // end position is left
+ aRect.SetRight( aScrPos.X() );
+ }
+
+ if ( meDragInsertMode == INS_CELLSDOWN )
+ {
+ aPixelRects.emplace_back( aRect.Left()+1, aRect.Top()+3, aRect.Left()+1, aRect.Bottom()-2 );
+ aPixelRects.emplace_back( aRect.Right()-1, aRect.Top()+3, aRect.Right()-1, aRect.Bottom()-2 );
+ aPixelRects.emplace_back( aRect.Left()+1, aRect.Top(), aRect.Right()-1, aRect.Top()+2 );
+ aPixelRects.emplace_back( aRect.Left()+1, aRect.Bottom()-1, aRect.Right()-1, aRect.Bottom()-1 );
+ }
+ else if ( meDragInsertMode == INS_CELLSRIGHT )
+ {
+ aPixelRects.emplace_back( aRect.Left(), aRect.Top()+1, aRect.Left()+2, aRect.Bottom()-1 );
+ aPixelRects.emplace_back( aRect.Right()-1, aRect.Top()+1, aRect.Right()-1, aRect.Bottom()-1 );
+ aPixelRects.emplace_back( aRect.Left()+3, aRect.Top()+1, aRect.Right()-2, aRect.Top()+1 );
+ aPixelRects.emplace_back( aRect.Left()+3, aRect.Bottom()-1, aRect.Right()-2, aRect.Bottom()-1 );
+ }
+ else
+ {
+ aPixelRects.emplace_back( aRect.Left(), aRect.Top(), aRect.Left()+2, aRect.Bottom() );
+ aPixelRects.emplace_back( aRect.Right()-2, aRect.Top(), aRect.Right(), aRect.Bottom() );
+ aPixelRects.emplace_back( aRect.Left()+3, aRect.Top(), aRect.Right()-3, aRect.Top()+2 );
+ aPixelRects.emplace_back( aRect.Left()+3, aRect.Bottom()-2, aRect.Right()-3, aRect.Bottom() );
+ }
+
+ // #i70788# get the OverlayManager safely
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
+
+ if (xOverlayManager.is() && !comphelper::LibreOfficeKit::isActive())
+ {
+ std::vector< basegfx::B2DRange > aRanges;
+ const basegfx::B2DHomMatrix aTransform(GetOutDev()->GetInverseViewTransformation());
+
+ for(const tools::Rectangle & rRA : aPixelRects)
+ {
+ basegfx::B2DRange aRB(rRA.Left(), rRA.Top(), rRA.Right() + 1, rRA.Bottom() + 1);
+ aRB.transform(aTransform);
+ aRanges.push_back(aRB);
+ }
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
+ sdr::overlay::OverlayType::Invert,
+ COL_BLACK,
+ std::move(aRanges),
+ false));
+
+ xOverlayManager->add(*pOverlay);
+ mpOODragRect.reset(new sdr::overlay::OverlayObjectList);
+ mpOODragRect->append(std::move(pOverlay));
+ }
+
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (comphelper::LibreOfficeKit::isActive() && pViewShell)
+ {
+ OString aRectsString;
+ tools::Rectangle aBoundingBox;
+
+ std::vector<tools::Rectangle> aRectangles;
+ aRectangles.push_back(aRect);
+
+ if (bInPrintTwips)
+ {
+ aBoundingBox = aRect;
+ aRectsString = rectanglesToString(aRectangles);
+ }
+ else
+ {
+ aRectsString = rectanglesToString(convertPixelToLogical(pViewShell->GetViewData(), aRectangles, aBoundingBox));
+ }
+
+ OString sBoundingBoxString = "EMPTY";
+ if (!aBoundingBox.IsEmpty())
+ sBoundingBoxString = aBoundingBox.toString();
+
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_CELL_SELECTION_AREA, sBoundingBoxString.getStr());
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, aRectsString.getStr());
+ }
+ }
+
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aOldMode );
+}
+
+void ScGridWindow::DeleteHeaderOverlay()
+{
+ mpOOHeader.reset();
+}
+
+void ScGridWindow::UpdateHeaderOverlay()
+{
+ MapMode aDrawMode = GetDrawMapMode();
+ MapMode aOldMode = GetMapMode();
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aDrawMode );
+
+ DeleteHeaderOverlay();
+
+ // Pixel rectangle is in aInvertRect
+ if ( !aInvertRect.IsEmpty() )
+ {
+ // #i70788# get the OverlayManager safely
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
+
+ if (xOverlayManager.is() && !comphelper::LibreOfficeKit::isActive())
+ {
+ // Color aHighlight = GetSettings().GetStyleSettings().GetHighlightColor();
+ std::vector< basegfx::B2DRange > aRanges;
+ const basegfx::B2DHomMatrix aTransform(GetOutDev()->GetInverseViewTransformation());
+ basegfx::B2DRange aRB(aInvertRect.Left(), aInvertRect.Top(), aInvertRect.Right() + 1, aInvertRect.Bottom() + 1);
+
+ aRB.transform(aTransform);
+ aRanges.push_back(aRB);
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
+ sdr::overlay::OverlayType::Invert,
+ COL_BLACK,
+ std::move(aRanges),
+ false));
+
+ xOverlayManager->add(*pOverlay);
+ mpOOHeader.reset(new sdr::overlay::OverlayObjectList);
+ mpOOHeader->append(std::move(pOverlay));
+ }
+ }
+
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aOldMode );
+}
+
+void ScGridWindow::DeleteShrinkOverlay()
+{
+ mpOOShrink.reset();
+}
+
+void ScGridWindow::UpdateShrinkOverlay()
+{
+ MapMode aDrawMode = GetDrawMapMode();
+ MapMode aOldMode = GetMapMode();
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aDrawMode );
+
+ DeleteShrinkOverlay();
+
+ // get the rectangle in pixels
+
+ tools::Rectangle aPixRect;
+ ScRange aRange;
+ SCTAB nTab = mrViewData.GetTabNo();
+ if ( mrViewData.IsRefMode() && nTab >= mrViewData.GetRefStartZ() && nTab <= mrViewData.GetRefEndZ() &&
+ mrViewData.GetDelMark( aRange ) )
+ {
+ //! limit to visible area
+ if ( aRange.aStart.Col() <= aRange.aEnd.Col() &&
+ aRange.aStart.Row() <= aRange.aEnd.Row() )
+ {
+ Point aStart = mrViewData.GetScrPos( aRange.aStart.Col(),
+ aRange.aStart.Row(), eWhich );
+ Point aEnd = mrViewData.GetScrPos( aRange.aEnd.Col()+1,
+ aRange.aEnd.Row()+1, eWhich );
+ aEnd.AdjustX( -1 );
+ aEnd.AdjustY( -1 );
+
+ aPixRect = tools::Rectangle( aStart,aEnd );
+ }
+ }
+
+ if ( !aPixRect.IsEmpty() )
+ {
+ // #i70788# get the OverlayManager safely
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
+
+ if (xOverlayManager.is() && !comphelper::LibreOfficeKit::isActive())
+ {
+ std::vector< basegfx::B2DRange > aRanges;
+ const basegfx::B2DHomMatrix aTransform(GetOutDev()->GetInverseViewTransformation());
+ basegfx::B2DRange aRB(aPixRect.Left(), aPixRect.Top(), aPixRect.Right() + 1, aPixRect.Bottom() + 1);
+
+ aRB.transform(aTransform);
+ aRanges.push_back(aRB);
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
+ sdr::overlay::OverlayType::Invert,
+ COL_BLACK,
+ std::move(aRanges),
+ false));
+
+ xOverlayManager->add(*pOverlay);
+ mpOOShrink.reset(new sdr::overlay::OverlayObjectList);
+ mpOOShrink->append(std::move(pOverlay));
+ }
+ }
+
+ if ( aOldMode != aDrawMode )
+ SetMapMode( aOldMode );
+}
+
+void ScGridWindow::DeleteSparklineGroupOverlay()
+{
+ mpOOSparklineGroup.reset();
+}
+
+void ScGridWindow::UpdateSparklineGroupOverlay()
+{
+ MapMode aDrawMode = GetDrawMapMode();
+
+ MapMode aOldMode = GetMapMode();
+ if (aOldMode != aDrawMode)
+ SetMapMode(aDrawMode);
+
+ DeleteSparklineGroupOverlay();
+
+ ScAddress aCurrentAddress = mrViewData.GetCurPos();
+
+ ScDocument& rDocument = mrViewData.GetDocument();
+ if (auto pSparkline = rDocument.GetSparkline(aCurrentAddress))
+ {
+ mpOOSparklineGroup.reset(new sdr::overlay::OverlayObjectList);
+
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
+ if (xOverlayManager.is())
+ {
+ auto* pList = rDocument.GetSparklineList(aCurrentAddress.Tab());
+ if (pList)
+ {
+ auto const& pSparklines = pList->getSparklinesFor(pSparkline->getSparklineGroup());
+
+ Color aColor = SvtOptionsDrawinglayer::getHilightColor();
+
+ std::vector<basegfx::B2DRange> aRanges;
+ const basegfx::B2DHomMatrix aTransform(GetOutDev()->GetInverseViewTransformation());
+
+ for (auto const& pCurrentSparkline : pSparklines)
+ {
+ SCCOL nColumn = pCurrentSparkline->getColumn();
+ SCROW nRow = pCurrentSparkline->getRow();
+
+ Point aStart = mrViewData.GetScrPos(nColumn, nRow, eWhich);
+ Point aEnd = mrViewData.GetScrPos(nColumn + 1, nRow + 1, eWhich);
+
+ basegfx::B2DRange aRange(aStart.X(), aStart.Y(), aEnd.X(), aEnd.Y());
+
+ aRange.transform(aTransform);
+ aRanges.push_back(aRange);
+ }
+
+ std::unique_ptr<sdr::overlay::OverlayObject> pOverlay(new sdr::overlay::OverlaySelection(
+ sdr::overlay::OverlayType::Transparent,
+ aColor, std::move(aRanges), true));
+
+ xOverlayManager->add(*pOverlay);
+ mpOOSparklineGroup->append(std::move(pOverlay));
+ }
+ }
+ }
+
+ if (aOldMode != aDrawMode)
+ SetMapMode(aOldMode);
+}
+
+// #i70788# central method to get the OverlayManager safely
+rtl::Reference<sdr::overlay::OverlayManager> ScGridWindow::getOverlayManager() const
+{
+ SdrPageView* pPV = mrViewData.GetView()->GetScDrawView()->GetSdrPageView();
+
+ if(pPV)
+ {
+ SdrPageWindow* pPageWin = pPV->FindPageWindow( *GetOutDev() );
+
+ if ( pPageWin )
+ {
+ return pPageWin->GetOverlayManager();
+ }
+ }
+
+ return rtl::Reference<sdr::overlay::OverlayManager>();
+}
+
+void ScGridWindow::flushOverlayManager()
+{
+ // #i70788# get the OverlayManager safely
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = getOverlayManager();
+
+ if (xOverlayManager.is())
+ xOverlayManager->flush();
+}
+
+ScViewData& ScGridWindow::getViewData()
+{
+ return mrViewData;
+}
+
+FactoryFunction ScGridWindow::GetUITestFactory() const
+{
+ return ScGridWinUIObject::create;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/gridwin2.cxx b/sc/source/ui/view/gridwin2.cxx
new file mode 100644
index 000000000..4c9e62ac3
--- /dev/null
+++ b/sc/source/ui/view/gridwin2.cxx
@@ -0,0 +1,1090 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <vcl/settings.hxx>
+#include <comphelper/lok.hxx>
+
+#include <gridwin.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <viewdata.hxx>
+#include <pivot.hxx>
+#include <uiitems.hxx>
+#include <scresid.hxx>
+#include <globstr.hrc>
+#include <strings.hrc>
+#include <pagedata.hxx>
+#include <dpobject.hxx>
+#include <dpsave.hxx>
+#include <dpshttab.hxx>
+#include <dbdocfun.hxx>
+#include <checklistmenu.hxx>
+#include <dpcontrol.hxx>
+#include <userlist.hxx>
+#include <scabstdlg.hxx>
+
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+
+#include <unordered_map>
+#include <memory>
+#include <vector>
+
+using namespace css;
+using namespace css::sheet;
+using css::sheet::DataPilotFieldOrientation;
+using std::vector;
+
+DataPilotFieldOrientation ScGridWindow::GetDPFieldOrientation( SCCOL nCol, SCROW nRow ) const
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor(nCol, nRow, nTab);
+ if (!pDPObj)
+ return DataPilotFieldOrientation_HIDDEN;
+
+ DataPilotFieldOrientation nOrient = DataPilotFieldOrientation_HIDDEN;
+
+ // Check for page field first.
+ if (nCol > 0)
+ {
+ // look for the dimension header left of the drop-down arrow
+ tools::Long nField = pDPObj->GetHeaderDim( ScAddress( nCol-1, nRow, nTab ), nOrient );
+ if ( nField >= 0 && nOrient == DataPilotFieldOrientation_PAGE )
+ {
+ bool bIsDataLayout = false;
+ OUString aFieldName = pDPObj->GetDimName( nField, bIsDataLayout );
+ if ( !aFieldName.isEmpty() && !bIsDataLayout )
+ return DataPilotFieldOrientation_PAGE;
+ }
+ }
+
+ nOrient = DataPilotFieldOrientation_HIDDEN;
+
+ // Now, check for row/column field.
+ tools::Long nField = pDPObj->GetHeaderDim(ScAddress(nCol, nRow, nTab), nOrient);
+ if (nField >= 0 && (nOrient == DataPilotFieldOrientation_COLUMN || nOrient == DataPilotFieldOrientation_ROW) )
+ {
+ bool bIsDataLayout = false;
+ OUString aFieldName = pDPObj->GetDimName(nField, bIsDataLayout);
+ if (!aFieldName.isEmpty() && !bIsDataLayout)
+ return nOrient;
+ }
+
+ return DataPilotFieldOrientation_HIDDEN;
+}
+
+// private method for mouse button handling
+bool ScGridWindow::DoPageFieldSelection( SCCOL nCol, SCROW nRow )
+{
+ if (GetDPFieldOrientation( nCol, nRow ) == DataPilotFieldOrientation_PAGE)
+ {
+ LaunchPageFieldMenu( nCol, nRow );
+ return true;
+ }
+ return false;
+}
+
+bool ScGridWindow::DoAutoFilterButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt )
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ Point aScrPos = mrViewData.GetScrPos(nCol, nRow, eWhich);
+ Point aDiffPix = rMEvt.GetPosPixel();
+
+ aDiffPix -= aScrPos;
+ bool bLOKActive = comphelper::LibreOfficeKit::isActive();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ if ( bLayoutRTL && !bLOKActive )
+ aDiffPix.setX( -aDiffPix.X() );
+
+ tools::Long nSizeX, nSizeY;
+ mrViewData.GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
+ // The button height should not use the merged cell height, should still use single row height
+ nSizeY = ScViewData::ToPixel(rDoc.GetRowHeight(nRow, nTab), mrViewData.GetPPTY());
+ Size aScrSize(nSizeX-1, nSizeY-1);
+
+ // Check if the mouse cursor is clicking on the popup arrow box.
+ mpFilterButton.reset(new ScDPFieldButton(GetOutDev(), &GetSettings().GetStyleSettings(), &mrViewData.GetZoomY(), &rDoc));
+ mpFilterButton->setBoundingBox(aScrPos, aScrSize, bLayoutRTL && !bLOKActive);
+ mpFilterButton->setPopupLeft(bLayoutRTL && bLOKActive ? false : bLayoutRTL); // #i114944# AutoFilter button is left-aligned in RTL
+ Point aPopupPos;
+ Size aPopupSize;
+ mpFilterButton->getPopupBoundingBox(aPopupPos, aPopupSize);
+ tools::Rectangle aRect(aPopupPos, aPopupSize);
+ if (aRect.Contains(rMEvt.GetPosPixel()))
+ {
+ if ( DoPageFieldSelection( nCol, nRow ) )
+ return true;
+
+ bool bFilterActive = IsAutoFilterActive(nCol, nRow, nTab);
+ mpFilterButton->setHasHiddenMember(bFilterActive);
+ mpFilterButton->setDrawBaseButton(false);
+ mpFilterButton->setDrawPopupButton(true);
+ mpFilterButton->setPopupPressed(true);
+ mpFilterButton->draw();
+ LaunchAutoFilterMenu(nCol, nRow);
+ return true;
+ }
+
+ return false;
+}
+
+void ScGridWindow::DoPushPivotButton( SCCOL nCol, SCROW nRow, const MouseEvent& rMEvt, bool bButton, bool bPopup )
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+
+ ScDPObject* pDPObj = rDoc.GetDPAtCursor(nCol, nRow, nTab);
+
+ if (pDPObj)
+ {
+ DataPilotFieldOrientation nOrient = DataPilotFieldOrientation_HIDDEN;
+ ScAddress aPos( nCol, nRow, nTab );
+ ScAddress aDimPos = aPos;
+ if (!bButton && bPopup && aDimPos.Col() > 0)
+ // For page field selection cell, the real field position is to the left.
+ aDimPos.IncCol(-1);
+
+ tools::Long nField = pDPObj->GetHeaderDim(aDimPos, nOrient);
+ if ( nField >= 0 )
+ {
+ bDPMouse = false;
+ nDPField = nField;
+ pDragDPObj = pDPObj;
+ if (bPopup && DPTestFieldPopupArrow(rMEvt, aPos, aDimPos, pDPObj))
+ {
+ // field name pop up menu has been launched. Don't activate
+ // field move.
+ return;
+ }
+
+ if (bButton)
+ {
+ bDPMouse = true;
+ DPTestMouse( rMEvt, true );
+ StartTracking();
+ }
+ }
+ else if ( pDPObj->IsFilterButton(aPos) )
+ {
+ ReleaseMouse(); // may have been captured in ButtonDown
+
+ ScQueryParam aQueryParam;
+ SCTAB nSrcTab = 0;
+ const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
+ OSL_ENSURE(pDesc, "no sheet source for filter button");
+ if (pDesc)
+ {
+ aQueryParam = pDesc->GetQueryParam();
+ nSrcTab = pDesc->GetSourceRange().aStart.Tab();
+ }
+
+ SfxItemSetFixed<SCITEM_QUERYDATA, SCITEM_QUERYDATA> aArgSet( mrViewData.GetViewShell()->GetPool() );
+ aArgSet.Put( ScQueryItem( SCITEM_QUERYDATA, &mrViewData, &aQueryParam ) );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScPivotFilterDlg> pDlg(
+ pFact->CreateScPivotFilterDlg(
+ mrViewData.GetViewShell()->GetFrameWeld(), aArgSet, nSrcTab));
+ if ( pDlg->Execute() == RET_OK )
+ {
+ ScSheetSourceDesc aNewDesc(&rDoc);
+ if (pDesc)
+ aNewDesc = *pDesc;
+
+ const ScQueryItem& rQueryItem = pDlg->GetOutputItem();
+ aNewDesc.SetQueryParam(rQueryItem.GetQueryData());
+
+ ScDPObject aNewObj( *pDPObj );
+ aNewObj.SetSheetDesc( aNewDesc );
+ ScDBDocFunc aFunc( *mrViewData.GetDocShell() );
+ aFunc.DataPilotUpdate( pDPObj, &aNewObj, true, false );
+ mrViewData.GetView()->CursorPosChanged(); // shells may be switched
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("Nothing here");
+ }
+}
+
+// Data Pilot interaction
+
+void ScGridWindow::DPTestMouse( const MouseEvent& rMEvt, bool bMove )
+{
+ OSL_ENSURE(pDragDPObj, "pDragDPObj missing");
+
+ // scroll window if at edges
+ //! move this to separate method
+
+ bool bTimer = false;
+ Point aPixel = rMEvt.GetPosPixel();
+
+ SCCOL nDx = 0;
+ SCROW nDy = 0;
+ if ( aPixel.X() < 0 )
+ nDx = -1;
+ if ( aPixel.Y() < 0 )
+ nDy = -1;
+ Size aSize = GetOutputSizePixel();
+ if ( aPixel.X() >= aSize.Width() )
+ nDx = 1;
+ if ( aPixel.Y() >= aSize.Height() )
+ nDy = 1;
+ if ( nDx != 0 || nDy != 0 )
+ {
+ UpdateDragRect( false, tools::Rectangle() );
+
+ if ( nDx != 0)
+ mrViewData.GetView()->ScrollX( nDx, WhichH(eWhich) );
+ if ( nDy != 0 )
+ mrViewData.GetView()->ScrollY( nDy, WhichV(eWhich) );
+
+ bTimer = true;
+ }
+
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPixel.X(), aPixel.Y(), eWhich, nPosX, nPosY );
+ bool bMouseLeft;
+ bool bMouseTop;
+ mrViewData.GetMouseQuadrant( aPixel, eWhich, nPosX, nPosY, bMouseLeft, bMouseTop );
+
+ ScAddress aPos( nPosX, nPosY, mrViewData.GetTabNo() );
+
+ tools::Rectangle aPosRect;
+ DataPilotFieldOrientation nOrient;
+ tools::Long nDimPos;
+ bool bHasRange = pDragDPObj->GetHeaderDrag( aPos, bMouseLeft, bMouseTop, nDPField,
+ aPosRect, nOrient, nDimPos );
+ UpdateDragRect( bHasRange && bMove, aPosRect );
+
+ bool bIsDataLayout;
+ sal_Int32 nDimFlags = 0;
+ OUString aDimName = pDragDPObj->GetDimName( nDPField, bIsDataLayout, &nDimFlags );
+ bool bAllowed = !bHasRange || ScDPObject::IsOrientationAllowed( nOrient, nDimFlags );
+
+ if (bMove) // set mouse pointer
+ {
+ PointerStyle ePointer = PointerStyle::PivotDelete;
+ if ( !bAllowed )
+ ePointer = PointerStyle::NotAllowed;
+ else if ( bHasRange )
+ switch (nOrient)
+ {
+ case DataPilotFieldOrientation_COLUMN: ePointer = PointerStyle::PivotCol; break;
+ case DataPilotFieldOrientation_ROW: ePointer = PointerStyle::PivotRow; break;
+ case DataPilotFieldOrientation_PAGE:
+ case DataPilotFieldOrientation_DATA: ePointer = PointerStyle::PivotField; break;
+ default: break;
+ }
+ SetPointer( ePointer );
+ }
+ else // execute change
+ {
+ if (!bHasRange)
+ nOrient = DataPilotFieldOrientation_HIDDEN;
+
+ if ( bIsDataLayout && ( nOrient != DataPilotFieldOrientation_COLUMN &&
+ nOrient != DataPilotFieldOrientation_ROW ) )
+ {
+ // removing data layout is not allowed
+ mrViewData.GetView()->ErrorMessage(STR_PIVOT_MOVENOTALLOWED);
+ }
+ else if ( bAllowed )
+ {
+ ScDPSaveData aSaveData( *pDragDPObj->GetSaveData() );
+
+ ScDPSaveDimension* pDim;
+ if ( bIsDataLayout )
+ pDim = aSaveData.GetDataLayoutDimension();
+ else
+ pDim = aSaveData.GetDimensionByName(aDimName);
+ pDim->SetOrientation( nOrient );
+ aSaveData.SetPosition( pDim, nDimPos );
+
+ //! docfunc method with ScDPSaveData as argument?
+
+ ScDPObject aNewObj( *pDragDPObj );
+ aNewObj.SetSaveData( aSaveData );
+ ScDBDocFunc aFunc( *mrViewData.GetDocShell() );
+ // when dragging fields, allow re-positioning (bAllowMove)
+ aFunc.DataPilotUpdate( pDragDPObj, &aNewObj, true, false, true );
+ mrViewData.GetView()->CursorPosChanged(); // shells may be switched
+ }
+ }
+
+ if (bTimer && bMove)
+ mrViewData.GetView()->SetTimer( this, rMEvt ); // repeat event
+ else
+ mrViewData.GetView()->ResetTimer();
+}
+
+bool ScGridWindow::DPTestFieldPopupArrow(
+ const MouseEvent& rMEvt, const ScAddress& rPos, const ScAddress& rDimPos, ScDPObject* pDPObj)
+{
+ bool bLayoutRTL = mrViewData.GetDocument().IsLayoutRTL( mrViewData.GetTabNo() );
+ bool bLOK = comphelper::LibreOfficeKit::isActive();
+
+ // Get the geometry of the cell.
+ Point aScrPos = mrViewData.GetScrPos(rPos.Col(), rPos.Row(), eWhich);
+ tools::Long nSizeX, nSizeY;
+ mrViewData.GetMergeSizePixel(rPos.Col(), rPos.Row(), nSizeX, nSizeY);
+ Size aScrSize(nSizeX-1, nSizeY-1);
+
+ // Check if the mouse cursor is clicking on the popup arrow box.
+ ScDPFieldButton aBtn(GetOutDev(), &GetSettings().GetStyleSettings(), &GetMapMode().GetScaleY());
+ aBtn.setBoundingBox(aScrPos, aScrSize, bLayoutRTL);
+ aBtn.setPopupLeft(false); // DataPilot popup is always right-aligned for now
+ Point aPopupPos;
+ Size aPopupSize;
+ aBtn.getPopupBoundingBox(aPopupPos, aPopupSize);
+ tools::Rectangle aRect(aPopupPos, aPopupSize);
+ if (aRect.Contains(rMEvt.GetPosPixel()))
+ {
+ // Mouse cursor inside the popup arrow box. Launch the field menu.
+ DPLaunchFieldPopupMenu(bLOK ? aScrPos : OutputToScreenPixel(aScrPos), aScrSize, rDimPos, pDPObj);
+ return true;
+ }
+
+ return false;
+}
+
+namespace {
+
+struct DPFieldPopupData : public ScCheckListMenuControl::ExtendedData
+{
+ ScDPLabelData maLabels;
+ ScDPObject* mpDPObj;
+ tools::Long mnDim;
+};
+
+class DPFieldPopupOKAction : public ScCheckListMenuControl::Action
+{
+public:
+ explicit DPFieldPopupOKAction(ScGridWindow* p) :
+ mpGridWindow(p) {}
+
+ virtual bool execute() override
+ {
+ mpGridWindow->UpdateDPFromFieldPopupMenu();
+ return true;
+ }
+private:
+ VclPtr<ScGridWindow> mpGridWindow;
+};
+
+class PopupSortAction : public ScCheckListMenuControl::Action
+{
+public:
+ enum SortType { ASCENDING, DESCENDING, CUSTOM };
+
+ explicit PopupSortAction(ScDPObject* pDPObject, tools::Long nDimIndex, SortType eType,
+ sal_uInt16 nUserListIndex, ScTabViewShell* pViewShell)
+ : mpDPObject(pDPObject)
+ , mnDimIndex(nDimIndex)
+ , meType(eType)
+ , mnUserListIndex(nUserListIndex)
+ , mpViewShell(pViewShell)
+ {}
+
+ virtual bool execute() override
+ {
+ switch (meType)
+ {
+ case ASCENDING:
+ mpViewShell->DataPilotSort(mpDPObject, mnDimIndex, true);
+ break;
+ case DESCENDING:
+ mpViewShell->DataPilotSort(mpDPObject, mnDimIndex, false);
+ break;
+ case CUSTOM:
+ mpViewShell->DataPilotSort(mpDPObject, mnDimIndex, true, &mnUserListIndex);
+ break;
+ default:
+ ;
+ }
+ return true;
+ }
+
+private:
+ ScDPObject* mpDPObject;
+ tools::Long mnDimIndex;
+ SortType meType;
+ sal_uInt16 mnUserListIndex;
+ ScTabViewShell* mpViewShell;
+};
+
+}
+
+void ScGridWindow::DPLaunchFieldPopupMenu(const Point& rScreenPosition, const Size& rScreenSize,
+ const ScAddress& rAddress, ScDPObject* pDPObject)
+{
+ DataPilotFieldOrientation nOrient;
+ tools::Long nDimIndex = pDPObject->GetHeaderDim(rAddress, nOrient);
+
+ DPLaunchFieldPopupMenu(rScreenPosition, rScreenSize, nDimIndex, pDPObject);
+}
+
+void ScGridWindow::DPLaunchFieldPopupMenu(const Point& rScrPos, const Size& rScrSize,
+ tools::Long nDimIndex, ScDPObject* pDPObj)
+{
+ std::unique_ptr<DPFieldPopupData> pDPData(new DPFieldPopupData);
+ pDPData->mnDim = nDimIndex;
+ pDPObj->GetSource();
+
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName(pDPData->mnDim, bIsDataLayout);
+ pDPObj->BuildAllDimensionMembers();
+ const ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+ const ScDPSaveDimension* pDim = pSaveData->GetExistingDimensionByName(aDimName);
+ if (!pDim)
+ // This should never happen.
+ return;
+
+ bool bDimOrientNotPage = pDim->GetOrientation() != DataPilotFieldOrientation_PAGE;
+
+ // We need to get the list of field members.
+ pDPObj->FillLabelData(pDPData->mnDim, pDPData->maLabels);
+ pDPData->mpDPObj = pDPObj;
+
+ const ScDPLabelData& rLabelData = pDPData->maLabels;
+
+ mpDPFieldPopup.reset();
+
+ weld::Window* pPopupParent = GetFrameWeld();
+ mpDPFieldPopup.reset(new ScCheckListMenuControl(pPopupParent, mrViewData,
+ false, -1));
+
+ mpDPFieldPopup->setExtendedData(std::move(pDPData));
+ mpDPFieldPopup->setOKAction(new DPFieldPopupOKAction(this));
+ {
+ // Populate field members.
+ size_t n = rLabelData.maMembers.size();
+ mpDPFieldPopup->setMemberSize(n);
+ for (size_t i = 0; i < n; ++i)
+ {
+ const ScDPLabelData::Member& rMem = rLabelData.maMembers[i];
+ OUString aName = rMem.getDisplayName();
+ if (aName.isEmpty())
+ // Use special string for an empty name.
+ mpDPFieldPopup->addMember(ScResId(STR_EMPTYDATA), 0.0, rMem.mbVisible);
+ else
+ mpDPFieldPopup->addMember(rMem.getDisplayName(), 0.0, rMem.mbVisible);
+ }
+ }
+
+ if (bDimOrientNotPage)
+ {
+ vector<OUString> aUserSortNames;
+ ScUserList* pUserList = ScGlobal::GetUserList();
+ if (pUserList)
+ {
+ size_t n = pUserList->size();
+ aUserSortNames.reserve(n);
+ for (size_t i = 0; i < n; ++i)
+ {
+ const ScUserListData& rData = (*pUserList)[i];
+ aUserSortNames.push_back(rData.GetString());
+ }
+ }
+
+ // Populate the menus.
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ mpDPFieldPopup->addMenuItem(
+ ScResId(STR_MENU_SORT_ASC),
+ new PopupSortAction(pDPObj, nDimIndex, PopupSortAction::ASCENDING, 0, pViewShell));
+ mpDPFieldPopup->addMenuItem(
+ ScResId(STR_MENU_SORT_DESC),
+ new PopupSortAction(pDPObj, nDimIndex, PopupSortAction::DESCENDING, 0, pViewShell));
+
+ ScListSubMenuControl* pSubMenu = mpDPFieldPopup->addSubMenuItem(ScResId(STR_MENU_SORT_CUSTOM), !aUserSortNames.empty(), false);
+ if (pSubMenu)
+ {
+ size_t n = aUserSortNames.size();
+ for (size_t i = 0; i < n; ++i)
+ {
+ pSubMenu->addMenuItem(aUserSortNames[i],
+ new PopupSortAction(pDPObj, nDimIndex, PopupSortAction::CUSTOM, sal_uInt16(i), pViewShell));
+ }
+ pSubMenu->resizeToFitMenuItems();
+ }
+ }
+
+ mpDPFieldPopup->initMembers();
+
+ tools::Rectangle aCellRect(rScrPos, rScrSize);
+ ScCheckListMenuControl::Config aConfig;
+ aConfig.mbAllowEmptySet = false;
+ aConfig.mbRTL = mrViewData.GetDocument().IsLayoutRTL(mrViewData.GetTabNo());
+ mpDPFieldPopup->setConfig(aConfig);
+ if (IsMouseCaptured())
+ ReleaseMouse();
+ mpDPFieldPopup->launch(pPopupParent, aCellRect);
+}
+
+void ScGridWindow::UpdateDPFromFieldPopupMenu()
+{
+ typedef std::unordered_map<OUString, OUString> MemNameMapType;
+
+ if (!mpDPFieldPopup)
+ return;
+
+ DPFieldPopupData* pDPData = static_cast<DPFieldPopupData*>(mpDPFieldPopup->getExtendedData());
+ if (!pDPData)
+ return;
+
+ ScDPObject* pDPObj = pDPData->mpDPObj;
+ ScDPSaveData* pSaveData = pDPObj->GetSaveData();
+
+ bool bIsDataLayout;
+ OUString aDimName = pDPObj->GetDimName(pDPData->mnDim, bIsDataLayout);
+ ScDPSaveDimension* pDim = pSaveData->GetDimensionByName(aDimName);
+ if (!pDim)
+ return;
+
+ // Build a map of layout names to original names.
+ const ScDPLabelData& rLabelData = pDPData->maLabels;
+ MemNameMapType aMemNameMap;
+ for (const auto& rMember : rLabelData.maMembers)
+ aMemNameMap.emplace(rMember.maLayoutName, rMember.maName);
+
+ // The raw result may contain a mixture of layout names and original names.
+ ScCheckListMenuControl::ResultType aRawResult;
+ mpDPFieldPopup->getResult(aRawResult);
+
+ std::unordered_map<OUString, bool> aResult;
+ for (const auto& rItem : aRawResult)
+ {
+ MemNameMapType::const_iterator itrNameMap = aMemNameMap.find(rItem.aName);
+ if (itrNameMap == aMemNameMap.end())
+ {
+ // This is an original member name. Use it as-is.
+ OUString aName = rItem.aName;
+ if (aName == ScResId(STR_EMPTYDATA))
+ // Translate the special empty name into an empty string.
+ aName.clear();
+
+ aResult.emplace(aName, rItem.bValid);
+ }
+ else
+ {
+ // This is a layout name. Get the original member name and use it.
+ aResult.emplace(itrNameMap->second, rItem.bValid);
+ }
+ }
+ pDim->UpdateMemberVisibility(aResult);
+
+ ScDBDocFunc aFunc(*mrViewData.GetDocShell());
+ aFunc.UpdatePivotTable(*pDPObj, true, false);
+}
+
+namespace {
+
+template <typename T>
+inline
+T lcl_getValidValue(T value, T defvalue)
+{
+ return (value <0) ? defvalue : value;
+}
+
+} // anonymous namespace
+
+bool ScGridWindow::UpdateVisibleRange()
+{
+ ScDocument const& rDoc = mrViewData.GetDocument();
+ SCCOL nPosX = 0;
+ SCROW nPosY = 0;
+ SCCOL nXRight = rDoc.MaxCol();
+ SCROW nYBottom = rDoc.MaxRow();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ nPosX = lcl_getValidValue(pViewShell->GetLOKStartHeaderCol(), nPosX);
+ nPosY = lcl_getValidValue(pViewShell->GetLOKStartHeaderRow(), nPosY);
+ nXRight = lcl_getValidValue(pViewShell->GetLOKEndHeaderCol(), nXRight);
+ nYBottom = lcl_getValidValue(pViewShell->GetLOKEndHeaderRow(), nYBottom);
+ }
+ else
+ {
+ nPosX = mrViewData.GetPosX(eHWhich);
+ nPosY = mrViewData.GetPosY(eVWhich);
+ nXRight = nPosX + mrViewData.VisibleCellsX(eHWhich);
+ if (nXRight > rDoc.MaxCol())
+ nXRight = rDoc.MaxCol();
+ nYBottom = nPosY + mrViewData.VisibleCellsY(eVWhich);
+ if (nYBottom > rDoc.MaxRow())
+ nYBottom = rDoc.MaxRow();
+ }
+
+ // Store the current visible range.
+ return maVisibleRange.set(nPosX, nPosY, nXRight, nYBottom);
+}
+
+void ScGridWindow::DPMouseMove( const MouseEvent& rMEvt )
+{
+ DPTestMouse( rMEvt, true );
+}
+
+void ScGridWindow::DPMouseButtonUp( const MouseEvent& rMEvt )
+{
+ bDPMouse = false;
+ ReleaseMouse();
+
+ DPTestMouse( rMEvt, false );
+ SetPointer( PointerStyle::Arrow );
+}
+
+void ScGridWindow::UpdateDragRect( bool bShowRange, const tools::Rectangle& rPosRect )
+{
+ SCCOL nStartX = ( rPosRect.Left() >= 0 ) ? static_cast<SCCOL>(rPosRect.Left()) : SCCOL_MAX;
+ SCROW nStartY = ( rPosRect.Top() >= 0 ) ? static_cast<SCROW>(rPosRect.Top()) : SCROW_MAX;
+ SCCOL nEndX = ( rPosRect.Right() >= 0 ) ? static_cast<SCCOL>(rPosRect.Right()) : SCCOL_MAX;
+ SCROW nEndY = ( rPosRect.Bottom() >= 0 ) ? static_cast<SCROW>(rPosRect.Bottom()) : SCROW_MAX;
+
+ if ( bShowRange == bDragRect && nDragStartX == nStartX && nDragEndX == nEndX &&
+ nDragStartY == nStartY && nDragEndY == nEndY )
+ {
+ return; // everything unchanged
+ }
+
+ if ( bShowRange )
+ {
+ nDragStartX = nStartX;
+ nDragStartY = nStartY;
+ nDragEndX = nEndX;
+ nDragEndY = nEndY;
+ bDragRect = true;
+ }
+ else
+ bDragRect = false;
+
+ UpdateDragRectOverlay();
+}
+
+// Page-Break Mode
+
+sal_uInt16 ScGridWindow::HitPageBreak( const Point& rMouse, ScRange* pSource,
+ SCCOLROW* pBreak, SCCOLROW* pPrev )
+{
+ sal_uInt16 nFound = SC_PD_NONE; // 0
+ ScRange aSource;
+ SCCOLROW nBreak = 0;
+ SCCOLROW nPrev = 0;
+
+ ScPageBreakData* pPageData = mrViewData.GetView()->GetPageBreakData();
+ if ( pPageData )
+ {
+ bool bHori = false;
+ bool bVert = false;
+ SCCOL nHitX = 0;
+ SCROW nHitY = 0;
+
+ tools::Long nMouseX = rMouse.X();
+ tools::Long nMouseY = rMouse.Y();
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( nMouseX, nMouseY, eWhich, nPosX, nPosY );
+ Point aTL = mrViewData.GetScrPos( nPosX, nPosY, eWhich );
+ Point aBR = mrViewData.GetScrPos( nPosX+1, nPosY+1, eWhich );
+
+ // Horizontal more tolerances as for vertical, because there is more space
+ if ( nMouseX <= aTL.X() + 4 )
+ {
+ bHori = true;
+ nHitX = nPosX;
+ }
+ else if ( nMouseX >= aBR.X() - 6 )
+ {
+ bHori = true;
+ nHitX = nPosX+1; // left edge of the next cell
+ }
+ if ( nMouseY <= aTL.Y() + 2 )
+ {
+ bVert = true;
+ nHitY = nPosY;
+ }
+ else if ( nMouseY >= aBR.Y() - 4 )
+ {
+ bVert = true;
+ nHitY = nPosY+1; // upper edge of the next cell
+ }
+
+ if ( bHori || bVert )
+ {
+ sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() );
+ for (sal_uInt16 nPos=0; nPos<nCount && !nFound; nPos++)
+ {
+ ScPrintRangeData& rData = pPageData->GetData(nPos);
+ ScRange aRange = rData.GetPrintRange();
+ bool bLHit = ( bHori && nHitX == aRange.aStart.Col() );
+ bool bRHit = ( bHori && nHitX == aRange.aEnd.Col() + 1 );
+ bool bTHit = ( bVert && nHitY == aRange.aStart.Row() );
+ bool bBHit = ( bVert && nHitY == aRange.aEnd.Row() + 1 );
+ bool bInsideH = ( nPosX >= aRange.aStart.Col() && nPosX <= aRange.aEnd.Col() );
+ bool bInsideV = ( nPosY >= aRange.aStart.Row() && nPosY <= aRange.aEnd.Row() );
+
+ if ( bLHit )
+ {
+ if ( bTHit )
+ nFound = SC_PD_RANGE_TL;
+ else if ( bBHit )
+ nFound = SC_PD_RANGE_BL;
+ else if ( bInsideV )
+ nFound = SC_PD_RANGE_L;
+ }
+ else if ( bRHit )
+ {
+ if ( bTHit )
+ nFound = SC_PD_RANGE_TR;
+ else if ( bBHit )
+ nFound = SC_PD_RANGE_BR;
+ else if ( bInsideV )
+ nFound = SC_PD_RANGE_R;
+ }
+ else if ( bTHit && bInsideH )
+ nFound = SC_PD_RANGE_T;
+ else if ( bBHit && bInsideH )
+ nFound = SC_PD_RANGE_B;
+ if (nFound)
+ aSource = aRange;
+
+ // breaks
+
+ if ( bVert && bInsideH && !nFound )
+ {
+ size_t nRowCount = rData.GetPagesY();
+ const SCROW* pRowEnd = rData.GetPageEndY();
+ for (size_t nRowPos=0; nRowPos+1<nRowCount; nRowPos++)
+ if ( pRowEnd[nRowPos]+1 == nHitY )
+ {
+ nFound = SC_PD_BREAK_V;
+ aSource = aRange;
+ nBreak = nHitY;
+ if ( nRowPos )
+ nPrev = pRowEnd[nRowPos-1]+1;
+ else
+ nPrev = aRange.aStart.Row();
+ }
+ }
+ if ( bHori && bInsideV && !nFound )
+ {
+ size_t nColCount = rData.GetPagesX();
+ const SCCOL* pColEnd = rData.GetPageEndX();
+ for (size_t nColPos=0; nColPos+1<nColCount; nColPos++)
+ if ( pColEnd[nColPos]+1 == nHitX )
+ {
+ nFound = SC_PD_BREAK_H;
+ aSource = aRange;
+ nBreak = nHitX;
+ if ( nColPos )
+ nPrev = pColEnd[nColPos-1]+1;
+ else
+ nPrev = aRange.aStart.Col();
+ }
+ }
+ }
+ }
+ }
+
+ if (pSource)
+ *pSource = aSource; // print break
+ if (pBreak)
+ *pBreak = nBreak; // X/Y position of the moved page break
+ if (pPrev)
+ *pPrev = nPrev; // X/Y beginning of the page, which is above the break
+ return nFound;
+}
+
+void ScGridWindow::PagebreakMove( const MouseEvent& rMEvt, bool bUp )
+{
+ //! Combine scrolling and switching with RFMouseMove !
+ //! (Inverting before scrolling is different)
+
+ // Scrolling
+
+ bool bTimer = false;
+ Point aPos = rMEvt.GetPosPixel();
+ SCCOL nDx = 0;
+ SCROW nDy = 0;
+ if ( aPos.X() < 0 ) nDx = -1;
+ if ( aPos.Y() < 0 ) nDy = -1;
+ Size aSize = GetOutputSizePixel();
+ if ( aPos.X() >= aSize.Width() )
+ nDx = 1;
+ if ( aPos.Y() >= aSize.Height() )
+ nDy = 1;
+ if ( nDx != 0 || nDy != 0 )
+ {
+ if ( bPagebreakDrawn ) // invert
+ {
+ bPagebreakDrawn = false;
+ UpdateDragRectOverlay();
+ }
+
+ if ( nDx != 0 ) mrViewData.GetView()->ScrollX( nDx, WhichH(eWhich) );
+ if ( nDy != 0 ) mrViewData.GetView()->ScrollY( nDy, WhichV(eWhich) );
+ bTimer = true;
+ }
+
+ // Switching when fixating (so Scrolling works)
+
+ if ( eWhich == mrViewData.GetActivePart() ) //??
+ {
+ if ( mrViewData.GetHSplitMode() == SC_SPLIT_FIX )
+ if ( nDx > 0 )
+ {
+ if ( eWhich == SC_SPLIT_TOPLEFT )
+ mrViewData.GetView()->ActivatePart( SC_SPLIT_TOPRIGHT );
+ else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
+ mrViewData.GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
+ }
+
+ if ( mrViewData.GetVSplitMode() == SC_SPLIT_FIX )
+ if ( nDy > 0 )
+ {
+ if ( eWhich == SC_SPLIT_TOPLEFT )
+ mrViewData.GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT );
+ else if ( eWhich == SC_SPLIT_TOPRIGHT )
+ mrViewData.GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
+ }
+ }
+
+ // from here new
+
+ // Searching for a position between the cells (before nPosX / nPosY)
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPos.X(), aPos.Y(), eWhich, nPosX, nPosY );
+ bool bLeft, bTop;
+ mrViewData.GetMouseQuadrant( aPos, eWhich, nPosX, nPosY, bLeft, bTop );
+ if ( !bLeft ) ++nPosX;
+ if ( !bTop ) ++nPosY;
+
+ bool bBreak = ( nPagebreakMouse == SC_PD_BREAK_H || nPagebreakMouse == SC_PD_BREAK_V );
+ bool bHide = false;
+ bool bToEnd = false;
+ ScRange aDrawRange = aPagebreakSource;
+ if ( bBreak )
+ {
+ if ( nPagebreakMouse == SC_PD_BREAK_H )
+ {
+ if ( nPosX > aPagebreakSource.aStart.Col() &&
+ nPosX <= aPagebreakSource.aEnd.Col() + 1 ) // to the end is also allowed
+ {
+ bToEnd = ( nPosX == aPagebreakSource.aEnd.Col() + 1 );
+ aDrawRange.aStart.SetCol( nPosX );
+ aDrawRange.aEnd.SetCol( nPosX - 1 );
+ }
+ else
+ bHide = true;
+ }
+ else
+ {
+ if ( nPosY > aPagebreakSource.aStart.Row() &&
+ nPosY <= aPagebreakSource.aEnd.Row() + 1 ) // to the end is also allowed
+ {
+ bToEnd = ( nPosY == aPagebreakSource.aEnd.Row() + 1 );
+ aDrawRange.aStart.SetRow( nPosY );
+ aDrawRange.aEnd.SetRow( nPosY - 1 );
+ }
+ else
+ bHide = true;
+ }
+ }
+ else
+ {
+ if ( nPagebreakMouse & SC_PD_RANGE_L )
+ aDrawRange.aStart.SetCol( nPosX );
+ if ( nPagebreakMouse & SC_PD_RANGE_T )
+ aDrawRange.aStart.SetRow( nPosY );
+ if ( nPagebreakMouse & SC_PD_RANGE_R )
+ {
+ if ( nPosX > 0 )
+ aDrawRange.aEnd.SetCol( nPosX-1 );
+ else
+ bHide = true;
+ }
+ if ( nPagebreakMouse & SC_PD_RANGE_B )
+ {
+ if ( nPosY > 0 )
+ aDrawRange.aEnd.SetRow( nPosY-1 );
+ else
+ bHide = true;
+ }
+ if ( aDrawRange.aStart.Col() > aDrawRange.aEnd.Col() ||
+ aDrawRange.aStart.Row() > aDrawRange.aEnd.Row() )
+ bHide = true;
+ }
+
+ if ( !bPagebreakDrawn || bUp || aDrawRange != aPagebreakDrag )
+ {
+ // draw...
+
+ if ( bPagebreakDrawn )
+ {
+ // invert
+ bPagebreakDrawn = false;
+ }
+ aPagebreakDrag = aDrawRange;
+ if ( !bUp && !bHide )
+ {
+ // revert
+ bPagebreakDrawn = true;
+ }
+ UpdateDragRectOverlay();
+ }
+
+ // when ButtonUp execute the changes
+
+ if ( bUp )
+ {
+ ScViewFunc* pViewFunc = mrViewData.GetView();
+ ScDocShell* pDocSh = mrViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ bool bUndo (rDoc.IsUndoEnabled());
+
+ if ( bBreak )
+ {
+ bool bColumn = ( nPagebreakMouse == SC_PD_BREAK_H );
+ SCCOLROW nNew = bColumn ? static_cast<SCCOLROW>(nPosX) : static_cast<SCCOLROW>(nPosY);
+ if ( nNew != nPagebreakBreak )
+ {
+ if (bUndo)
+ {
+ OUString aUndo = ScResId( STR_UNDO_DRAG_BREAK );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, mrViewData.GetViewShell()->GetViewShellId() );
+ }
+
+ bool bGrow = !bHide && nNew > nPagebreakBreak;
+ if ( bColumn )
+ {
+ if (rDoc.HasColBreak(static_cast<SCCOL>(nPagebreakBreak), nTab) & ScBreakType::Manual)
+ {
+ ScAddress aOldAddr( static_cast<SCCOL>(nPagebreakBreak), nPosY, nTab );
+ pViewFunc->DeletePageBreak( true, true, &aOldAddr, false );
+ }
+ if ( !bHide && !bToEnd ) // not at the end
+ {
+ ScAddress aNewAddr( static_cast<SCCOL>(nNew), nPosY, nTab );
+ pViewFunc->InsertPageBreak( true, true, &aNewAddr, false );
+ }
+ if ( bGrow )
+ {
+ // change last break to hard, and change scaling
+ bool bManualBreak(rDoc.HasColBreak(static_cast<SCCOL>(nPagebreakPrev), nTab) & ScBreakType::Manual);
+ if ( static_cast<SCCOL>(nPagebreakPrev) > aPagebreakSource.aStart.Col() && !bManualBreak )
+ {
+ ScAddress aPrev( static_cast<SCCOL>(nPagebreakPrev), nPosY, nTab );
+ pViewFunc->InsertPageBreak( true, true, &aPrev, false );
+ }
+
+ if (!pDocSh->AdjustPrintZoom( ScRange(
+ static_cast<SCCOL>(nPagebreakPrev),0,nTab, static_cast<SCCOL>(nNew-1),0,nTab ) ))
+ bGrow = false;
+ }
+ }
+ else
+ {
+ if (rDoc.HasRowBreak(nPagebreakBreak, nTab) & ScBreakType::Manual)
+ {
+ ScAddress aOldAddr( nPosX, nPagebreakBreak, nTab );
+ pViewFunc->DeletePageBreak( false, true, &aOldAddr, false );
+ }
+ if ( !bHide && !bToEnd ) // not at the end
+ {
+ ScAddress aNewAddr( nPosX, nNew, nTab );
+ pViewFunc->InsertPageBreak( false, true, &aNewAddr, false );
+ }
+ if ( bGrow )
+ {
+ // change last break to hard, and change scaling
+ bool bManualBreak(rDoc.HasRowBreak(nPagebreakPrev, nTab) & ScBreakType::Manual);
+ if ( nPagebreakPrev > aPagebreakSource.aStart.Row() && !bManualBreak )
+ {
+ ScAddress aPrev( nPosX, nPagebreakPrev, nTab );
+ pViewFunc->InsertPageBreak( false, true, &aPrev, false );
+ }
+
+ if (!pDocSh->AdjustPrintZoom( ScRange(
+ 0,nPagebreakPrev,nTab, 0,nNew-1,nTab ) ))
+ bGrow = false;
+ }
+ }
+
+ if (bUndo)
+ {
+ pDocSh->GetUndoManager()->LeaveListAction();
+ }
+
+ if (!bGrow) // otherwise has already happened in AdjustPrintZoom
+ {
+ pViewFunc->UpdatePageBreakData( true );
+ pDocSh->SetDocumentModified();
+ }
+ }
+ }
+ else if ( bHide || aPagebreakDrag != aPagebreakSource )
+ {
+ // set print range
+
+ OUString aNewRanges;
+ sal_uInt16 nOldCount = rDoc.GetPrintRangeCount( nTab );
+ if ( nOldCount )
+ {
+ for (sal_uInt16 nPos=0; nPos<nOldCount; nPos++)
+ {
+ const ScRange* pOld = rDoc.GetPrintRange( nTab, nPos );
+ if ( pOld )
+ {
+ OUString aTemp;
+ if ( *pOld != aPagebreakSource )
+ aTemp = pOld->Format(rDoc, ScRefFlags::VALID);
+ else if ( !bHide )
+ aTemp = aPagebreakDrag.Format(rDoc, ScRefFlags::VALID);
+ if (!aTemp.isEmpty())
+ {
+ if ( !aNewRanges.isEmpty() )
+ aNewRanges += ";";
+ aNewRanges += aTemp;
+ }
+ }
+ }
+ }
+ else if (!bHide)
+ aNewRanges = aPagebreakDrag.Format(rDoc, ScRefFlags::VALID);
+
+ pViewFunc->SetPrintRanges( rDoc.IsPrintEntireSheet( nTab ), &aNewRanges, nullptr, nullptr, false );
+ }
+ }
+
+ // Timer for Scrolling
+
+ if (bTimer && !bUp)
+ mrViewData.GetView()->SetTimer( this, rMEvt ); // repeat event
+ else
+ mrViewData.GetView()->ResetTimer();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/gridwin3.cxx b/sc/source/ui/view/gridwin3.cxx
new file mode 100644
index 000000000..e550447da
--- /dev/null
+++ b/sc/source/ui/view/gridwin3.cxx
@@ -0,0 +1,399 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/svdpagv.hxx>
+#include <svx/svxids.hrc>
+#include <editeng/sizeitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <svl/ptitem.hxx>
+#include <osl/diagnose.h>
+
+#include <tabvwsh.hxx>
+#include <gridwin.hxx>
+#include <dbfunc.hxx>
+#include <viewdata.hxx>
+#include <output.hxx>
+#include <drawview.hxx>
+#include <fupoor.hxx>
+
+#include <drawutil.hxx>
+#include <document.hxx>
+#include <comphelper/lok.hxx>
+
+bool ScGridWindow::DrawMouseButtonDown(const MouseEvent& rMEvt)
+{
+ bool bRet = false;
+ FuPoor* pDraw = mrViewData.GetView()->GetDrawFuncPtr();
+ if (pDraw && !mrViewData.IsRefMode())
+ {
+ MapMode aDrawMode = GetDrawMapMode();
+ MapMode aOldMode = GetMapMode();
+ if ( comphelper::LibreOfficeKit::isActive() && aOldMode != aDrawMode )
+ SetMapMode( aDrawMode );
+
+ pDraw->SetWindow( this );
+ Point aLogicPos = PixelToLogic(rMEvt.GetPosPixel());
+ if ( pDraw->IsDetectiveHit( aLogicPos ) )
+ {
+ // nothing on detective arrows (double click is evaluated on ButtonUp)
+ bRet = true;
+ }
+ else
+ {
+ bRet = pDraw->MouseButtonDown( rMEvt );
+ if ( bRet )
+ UpdateStatusPosSize();
+ }
+
+ if ( comphelper::LibreOfficeKit::isActive() && aOldMode != aDrawMode )
+ SetMapMode( aOldMode );
+ }
+
+ // cancel draw with right key
+ ScDrawView* pDrView = mrViewData.GetScDrawView();
+ if ( pDrView && !rMEvt.IsLeft() && !bRet )
+ {
+ pDrView->BrkAction();
+ bRet = true;
+ }
+ return bRet;
+}
+
+bool ScGridWindow::DrawMouseButtonUp(const MouseEvent& rMEvt)
+{
+ ScViewFunc* pView = mrViewData.GetView();
+ bool bRet = false;
+ FuPoor* pDraw = pView->GetDrawFuncPtr();
+ if (pDraw && !mrViewData.IsRefMode())
+ {
+ MapMode aDrawMode = GetDrawMapMode();
+ MapMode aOldMode = GetMapMode();
+ if ( comphelper::LibreOfficeKit::isActive() && aOldMode != aDrawMode )
+ SetMapMode( aDrawMode );
+
+ pDraw->SetWindow( this );
+ bRet = pDraw->MouseButtonUp( rMEvt );
+
+ // execute "format paint brush" for drawing objects
+ SfxItemSet* pDrawBrush = pView->GetDrawBrushSet();
+ if ( pDrawBrush )
+ {
+ ScDrawView* pDrView = mrViewData.GetScDrawView();
+ if ( pDrView )
+ {
+ pDrView->SetAttrToMarked(*pDrawBrush, true/*bReplaceAll*/);
+ }
+
+ if ( !pView->IsPaintBrushLocked() )
+ pView->ResetBrushDocument(); // end paint brush mode if not locked
+ }
+
+ if ( comphelper::LibreOfficeKit::isActive() && aOldMode != aDrawMode )
+ SetMapMode( aOldMode );
+ }
+
+ return bRet;
+}
+
+bool ScGridWindow::DrawMouseMove(const MouseEvent& rMEvt)
+{
+ FuPoor* pDraw = mrViewData.GetView()->GetDrawFuncPtr();
+ if (pDraw && !mrViewData.IsRefMode())
+ {
+ MapMode aDrawMode = GetDrawMapMode();
+ MapMode aOldMode = GetMapMode();
+ if ( comphelper::LibreOfficeKit::isActive() && aOldMode != aDrawMode )
+ SetMapMode( aDrawMode );
+
+ pDraw->SetWindow( this );
+ bool bRet = pDraw->MouseMove( rMEvt );
+ if ( bRet )
+ UpdateStatusPosSize();
+
+ if ( comphelper::LibreOfficeKit::isActive() && aOldMode != aDrawMode )
+ SetMapMode( aOldMode );
+
+ return bRet;
+ }
+ else
+ {
+ SetPointer( PointerStyle::Arrow );
+ return false;
+ }
+}
+
+void ScGridWindow::DrawEndAction()
+{
+ ScDrawView* pDrView = mrViewData.GetScDrawView();
+ if ( pDrView && pDrView->IsAction() )
+ pDrView->BrkAction();
+
+ FuPoor* pDraw = mrViewData.GetView()->GetDrawFuncPtr();
+ if (pDraw)
+ pDraw->StopDragTimer();
+
+ // ReleaseMouse on call
+}
+
+bool ScGridWindow::DrawCommand(const CommandEvent& rCEvt)
+{
+ ScDrawView* pDrView = mrViewData.GetScDrawView();
+ FuPoor* pDraw = mrViewData.GetView()->GetDrawFuncPtr();
+ if (pDrView && pDraw && !mrViewData.IsRefMode())
+ {
+ pDraw->SetWindow( this );
+ sal_uInt8 nUsed = pDraw->Command( rCEvt );
+ if( nUsed == SC_CMD_USED )
+ nButtonDown = 0; // MouseButtonUp is swallowed...
+ if( nUsed || pDrView->IsAction() )
+ return true;
+ }
+
+ return false;
+}
+
+bool ScGridWindow::DrawKeyInput(const KeyEvent& rKEvt, vcl::Window* pWin)
+{
+ ScDrawView* pDrView = mrViewData.GetScDrawView();
+ FuPoor* pDraw = mrViewData.GetView()->GetDrawFuncPtr();
+
+
+ if (pDrView && pDrView->KeyInput(rKEvt, pWin))
+ return true;
+
+ if (pDrView && pDraw && !mrViewData.IsRefMode())
+ {
+ pDraw->SetWindow( this );
+ bool bOldMarked = pDrView->AreObjectsMarked();
+ if (pDraw->KeyInput( rKEvt ))
+ {
+ bool bLeaveDraw = false;
+ bool bUsed = true;
+ bool bNewMarked = pDrView->AreObjectsMarked();
+ if ( !mrViewData.GetView()->IsDrawSelMode() )
+ if ( !bNewMarked )
+ {
+ mrViewData.GetViewShell()->SetDrawShell( false );
+ bLeaveDraw = true;
+ if ( !bOldMarked &&
+ rKEvt.GetKeyCode().GetCode() == KEY_DELETE )
+ bUsed = false; // nothing deleted
+ if(bOldMarked)
+ GetFocus();
+ }
+ if (!bLeaveDraw)
+ UpdateStatusPosSize(); // for moving/resizing etc. by keyboard
+ return bUsed;
+ }
+ }
+
+ return false;
+}
+
+void ScGridWindow::DrawRedraw( ScOutputData& rOutputData, SdrLayerID nLayer )
+{
+ const ScViewOptions& rOpts = mrViewData.GetOptions();
+
+ // use new flags at SdrPaintView for hiding objects
+ const bool bDrawOle(VOBJ_MODE_SHOW == rOpts.GetObjMode(VOBJ_TYPE_OLE));
+ const bool bDrawChart(VOBJ_MODE_SHOW == rOpts.GetObjMode(VOBJ_TYPE_CHART));
+ const bool bDrawDraw(VOBJ_MODE_SHOW == rOpts.GetObjMode(VOBJ_TYPE_DRAW));
+
+ if(!(bDrawOle || bDrawChart || bDrawDraw))
+ return;
+
+ ScDrawView* pDrView = mrViewData.GetView()->GetScDrawView();
+
+ if(pDrView)
+ {
+ pDrView->setHideOle(!bDrawOle);
+ pDrView->setHideChart(!bDrawChart);
+ pDrView->setHideDraw(!bDrawDraw);
+ pDrView->setHideFormControl(!bDrawDraw);
+ }
+
+ rOutputData.DrawSelectiveObjects(nLayer);
+}
+
+void ScGridWindow::DrawSdrGrid( const tools::Rectangle& rDrawingRect, OutputDevice* pContentDev )
+{
+ // Draw grid lines
+
+ ScDrawView* pDrView = mrViewData.GetView()->GetScDrawView();
+ if ( pDrView && pDrView->IsGridVisible() )
+ {
+ SdrPageView* pPV = pDrView->GetSdrPageView();
+ OSL_ENSURE(pPV, "PageView not available");
+ if (pPV)
+ {
+ pContentDev->SetLineColor(COL_GRAY);
+
+ pPV->DrawPageViewGrid( *pContentDev, rDrawingRect );
+ }
+ }
+}
+
+MapMode ScGridWindow::GetDrawMapMode( bool bForce )
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+
+ // FIXME this shouldn't be necessary once we change the entire Calc to
+ // work in the logic coordinates (ideally 100ths of mm - so that it is
+ // the same as editeng and drawinglayer), and get rid of all the
+ // SetMapMode's and other unnecessary fun we have with pixels
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ return mrViewData.GetLogicMode();
+ }
+
+ SCTAB nTab = mrViewData.GetTabNo();
+ bool bNegativePage = rDoc.IsNegativePage( nTab );
+
+ MapMode aDrawMode = mrViewData.GetLogicMode();
+
+ ScDrawView* pDrView = mrViewData.GetView()->GetScDrawView();
+ if ( pDrView || bForce )
+ {
+ Fraction aScaleX;
+ Fraction aScaleY;
+ if (pDrView)
+ pDrView->GetScale( aScaleX, aScaleY );
+ else
+ {
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ rDoc.GetTableArea( nTab, nEndCol, nEndRow );
+ if (nEndCol<20) nEndCol = 20;
+ if (nEndRow<20) nEndRow = 1000;
+ ScDrawUtil::CalcScale( rDoc, nTab, 0,0, nEndCol,nEndRow, GetOutDev(),
+ mrViewData.GetZoomX(),mrViewData.GetZoomY(),
+ mrViewData.GetPPTX(),mrViewData.GetPPTY(),
+ aScaleX,aScaleY );
+ }
+ aDrawMode.SetScaleX(aScaleX);
+ aDrawMode.SetScaleY(aScaleY);
+ }
+ aDrawMode.SetOrigin(Point());
+ Point aStartPos = mrViewData.GetPixPos(eWhich);
+ if ( bNegativePage )
+ {
+ // RTL uses negative positions for drawing objects
+ aStartPos.setX( -aStartPos.X() + GetOutputSizePixel().Width() - 1 );
+ }
+ aDrawMode.SetOrigin( PixelToLogic( aStartPos, aDrawMode ) );
+
+ return aDrawMode;
+}
+
+void ScGridWindow::DrawAfterScroll()
+{
+ PaintImmediately(); // always, so the behaviour with and without DrawingLayer is the same
+
+ ScDrawView* pDrView = mrViewData.GetView()->GetScDrawView();
+ if (pDrView)
+ {
+ OutlinerView* pOlView = pDrView->GetTextEditOutlinerView();
+ if (pOlView && pOlView->GetWindow() == this)
+ pOlView->ShowCursor(false); // was removed at scrolling
+ }
+}
+
+void ScGridWindow::CreateAnchorHandle(SdrHdlList& rHdl, const ScAddress& rAddress)
+{
+ ScDrawView* pDrView = mrViewData.GetView()->GetScDrawView();
+ if (pDrView)
+ {
+ const ScViewOptions& rOpts = mrViewData.GetOptions();
+ if(rOpts.GetOption( VOPT_ANCHOR ))
+ {
+ bool bNegativePage = mrViewData.GetDocument().IsNegativePage( mrViewData.GetTabNo() );
+ Point aPos = mrViewData.GetScrPos( rAddress.Col(), rAddress.Row(), eWhich, true );
+ aPos = PixelToLogic(aPos);
+ rHdl.AddHdl(std::make_unique<SdrHdl>(aPos, bNegativePage ? SdrHdlKind::Anchor_TR : SdrHdlKind::Anchor));
+ }
+ }
+}
+
+void ScGridWindow::UpdateStatusPosSize()
+{
+ ScDrawView* pDrView = mrViewData.GetView()->GetScDrawView();
+ if (!pDrView)
+ return; // shouldn't be called in that case
+
+ SdrPageView* pPV = pDrView->GetSdrPageView();
+ if (!pPV)
+ return; // shouldn't be called in that case either
+
+ SfxItemSetFixed<SID_ATTR_POSITION, SID_ATTR_SIZE> aSet(mrViewData.GetViewShell()->GetPool());
+
+ // Fill items for position and size:
+ // show action rectangle during action,
+ // position and size of selected object(s) if something is selected,
+ // mouse position otherwise
+
+ bool bActionItem = false;
+ if ( pDrView->IsAction() ) // action rectangle
+ {
+ tools::Rectangle aRect;
+ pDrView->TakeActionRect( aRect );
+ if ( !aRect.IsEmpty() )
+ {
+ pPV->LogicToPagePos(aRect);
+ aSet.Put( SfxPointItem( SID_ATTR_POSITION, aRect.TopLeft() ) );
+ aSet.Put( SvxSizeItem( SID_ATTR_SIZE,
+ Size( aRect.Right() - aRect.Left(), aRect.Bottom() - aRect.Top() ) ) );
+ bActionItem = true;
+ }
+ }
+ if ( !bActionItem )
+ {
+ if ( pDrView->AreObjectsMarked() ) // selected objects
+ {
+ tools::Rectangle aRect = pDrView->GetAllMarkedRect();
+ pPV->LogicToPagePos(aRect);
+ aSet.Put( SfxPointItem( SID_ATTR_POSITION, aRect.TopLeft() ) );
+ aSet.Put( SvxSizeItem( SID_ATTR_SIZE,
+ Size( aRect.Right() - aRect.Left(), aRect.Bottom() - aRect.Top() ) ) );
+ }
+ else // mouse position
+ {
+ Point aPos = PixelToLogic(aCurMousePos);
+ pPV->LogicToPagePos(aPos);
+ aSet.Put( SfxPointItem( SID_ATTR_POSITION, aPos ) );
+ aSet.Put( SvxSizeItem( SID_ATTR_SIZE, Size( 0, 0 ) ) );
+ }
+ }
+
+ mrViewData.GetBindings().SetState(aSet);
+}
+
+bool ScGridWindow::DrawHasMarkedObj()
+{
+ ScDrawView* p = mrViewData.GetScDrawView();
+ return p && p->AreObjectsMarked();
+}
+
+void ScGridWindow::DrawMarkDropObj( SdrObject* pObj )
+{
+ ScDrawView* pDrView = mrViewData.GetView()->GetScDrawView();
+ if (pDrView)
+ pDrView->MarkDropObj(pObj);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
new file mode 100644
index 000000000..6f305576b
--- /dev/null
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -0,0 +1,2608 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <scitems.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <svtools/colorcfg.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/printer.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/settings.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <osl/diagnose.h>
+
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <sfx2/lokcomponenthelpers.hxx>
+
+#include <svx/svdview.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/sdrpagewindow.hxx>
+#include <svx/sdr/contact/objectcontactofpageview.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <tabvwsh.hxx>
+#include <vcl/lineinfo.hxx>
+#include <vcl/sysdata.hxx>
+
+#include <gridwin.hxx>
+#include <viewdata.hxx>
+#include <output.hxx>
+#include <document.hxx>
+#include <attrib.hxx>
+#include <patattr.hxx>
+#include <dbdata.hxx>
+#include <docoptio.hxx>
+#include <notemark.hxx>
+#include <dbfunc.hxx>
+#include <scmod.hxx>
+#include <inputhdl.hxx>
+#include <rfindlst.hxx>
+#include <hiranges.hxx>
+#include <pagedata.hxx>
+#include <docpool.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <docsh.hxx>
+#include <cbutton.hxx>
+#include <invmerge.hxx>
+#include <editutil.hxx>
+#include <inputopt.hxx>
+#include <fillinfo.hxx>
+#include <dpcontrol.hxx>
+#include <queryparam.hxx>
+#include <queryentry.hxx>
+#include <markdata.hxx>
+#include <sc.hrc>
+#include <vcl/virdev.hxx>
+#include <svx/sdrpaintwindow.hxx>
+#include <drwlayer.hxx>
+
+static void lcl_LimitRect( tools::Rectangle& rRect, const tools::Rectangle& rVisible )
+{
+ if ( rRect.Top() < rVisible.Top()-1 ) rRect.SetTop( rVisible.Top()-1 );
+ if ( rRect.Bottom() > rVisible.Bottom()+1 ) rRect.SetBottom( rVisible.Bottom()+1 );
+
+ // The header row must be drawn also when the inner rectangle is not visible,
+ // that is why there is no return value anymore.
+ // When it is far away, then lcl_DrawOneFrame is not even called.
+}
+
+static void lcl_DrawOneFrame( vcl::RenderContext* pDev, const tools::Rectangle& rInnerPixel,
+ const OUString& rTitle, const Color& rColor, bool bTextBelow,
+ double nPPTX, double nPPTY, const Fraction& rZoomY,
+ ScDocument& rDoc, ScViewData& rButtonViewData, bool bLayoutRTL )
+{
+ // rButtonViewData is only used to set the button size,
+
+ tools::Rectangle aInner = rInnerPixel;
+ if ( bLayoutRTL )
+ {
+ aInner.SetLeft( rInnerPixel.Right() );
+ aInner.SetRight( rInnerPixel.Left() );
+ }
+
+ tools::Rectangle aVisible( Point(0,0), pDev->GetOutputSizePixel() );
+ lcl_LimitRect( aInner, aVisible );
+
+ tools::Rectangle aOuter = aInner;
+ tools::Long nHor = static_cast<tools::Long>( SC_SCENARIO_HSPACE * nPPTX );
+ tools::Long nVer = static_cast<tools::Long>( SC_SCENARIO_VSPACE * nPPTY );
+ aOuter.AdjustLeft( -nHor );
+ aOuter.AdjustRight(nHor );
+ aOuter.AdjustTop( -nVer );
+ aOuter.AdjustBottom(nVer );
+
+ // use ScPatternAttr::GetFont only for font size
+ vcl::Font aAttrFont;
+ rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN).
+ GetFont(aAttrFont,SC_AUTOCOL_BLACK,pDev,&rZoomY);
+
+ // everything else from application font
+ vcl::Font aAppFont = pDev->GetSettings().GetStyleSettings().GetAppFont();
+ aAppFont.SetFontSize( aAttrFont.GetFontSize() );
+
+ aAppFont.SetAlignment( ALIGN_TOP );
+ pDev->SetFont( aAppFont );
+
+ Size aTextSize( pDev->GetTextWidth( rTitle ), pDev->GetTextHeight() );
+
+ if ( bTextBelow )
+ aOuter.AdjustBottom(aTextSize.Height() );
+ else
+ aOuter.AdjustTop( -(aTextSize.Height()) );
+
+ pDev->SetLineColor();
+ pDev->SetFillColor( rColor );
+ // left, top, right, bottom
+ pDev->DrawRect( tools::Rectangle( aOuter.Left(), aOuter.Top(), aInner.Left(), aOuter.Bottom() ) );
+ pDev->DrawRect( tools::Rectangle( aOuter.Left(), aOuter.Top(), aOuter.Right(), aInner.Top() ) );
+ pDev->DrawRect( tools::Rectangle( aInner.Right(), aOuter.Top(), aOuter.Right(), aOuter.Bottom() ) );
+ pDev->DrawRect( tools::Rectangle( aOuter.Left(), aInner.Bottom(), aOuter.Right(), aOuter.Bottom() ) );
+
+ tools::Long nButtonY = bTextBelow ? aInner.Bottom() : aOuter.Top();
+
+ ScDDComboBoxButton aComboButton(pDev);
+ aComboButton.SetOptSizePixel();
+ tools::Long nBWidth = tools::Long(aComboButton.GetSizePixel().Width() * rZoomY);
+ tools::Long nBHeight = nVer + aTextSize.Height() + 1;
+ Size aButSize( nBWidth, nBHeight );
+ tools::Long nButtonPos = bLayoutRTL ? aOuter.Left() : aOuter.Right()-nBWidth+1;
+ aComboButton.Draw( Point(nButtonPos, nButtonY), aButSize );
+ rButtonViewData.SetScenButSize( aButSize );
+
+ tools::Long nTextStart = bLayoutRTL ? aInner.Right() - aTextSize.Width() + 1 : aInner.Left();
+
+ bool bWasClip = false;
+ vcl::Region aOldClip;
+ bool bClip = ( aTextSize.Width() > aOuter.Right() - nBWidth - aInner.Left() );
+ if ( bClip )
+ {
+ if (pDev->IsClipRegion())
+ {
+ bWasClip = true;
+ aOldClip = pDev->GetActiveClipRegion();
+ }
+ tools::Long nClipStartX = bLayoutRTL ? aOuter.Left() + nBWidth : aInner.Left();
+ tools::Long nClipEndX = bLayoutRTL ? aInner.Right() : aOuter.Right() - nBWidth;
+ pDev->SetClipRegion( vcl::Region(tools::Rectangle( nClipStartX, nButtonY + nVer/2,
+ nClipEndX, nButtonY + nVer/2 + aTextSize.Height())) );
+ }
+
+ pDev->DrawText( Point( nTextStart, nButtonY + nVer/2 ), rTitle );
+
+ if ( bClip )
+ {
+ if ( bWasClip )
+ pDev->SetClipRegion(aOldClip);
+ else
+ pDev->SetClipRegion();
+ }
+
+ pDev->SetFillColor();
+ pDev->SetLineColor( COL_BLACK );
+ pDev->DrawRect( aInner );
+ pDev->DrawRect( aOuter );
+}
+
+static void lcl_DrawScenarioFrames( OutputDevice* pDev, ScViewData& rViewData, ScSplitPos eWhich,
+ SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2 )
+{
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ if ( nTab+1 >= nTabCount || !rDoc.IsScenario(nTab+1) || rDoc.IsScenario(nTab) )
+ return;
+
+ if ( nX1 > 0 ) --nX1;
+ if ( nY1>=2 ) nY1 -= 2; // Hack: Header row affects two cells
+ else if ( nY1 > 0 ) --nY1;
+ if ( nX2 < rDoc.MaxCol() ) ++nX2;
+ if ( nY2 < rDoc.MaxRow()-1 ) nY2 += 2; // Hack: Header row affects two cells
+ else if ( nY2 < rDoc.MaxRow() ) ++nY2;
+ ScRange aViewRange( nX1,nY1,nTab, nX2,nY2,nTab );
+
+ //! cache the ranges in table!!!!
+
+ ScMarkData aMarks(rDoc.GetSheetLimits());
+ for (SCTAB i=nTab+1; i<nTabCount && rDoc.IsScenario(i); i++)
+ rDoc.MarkScenario( i, nTab, aMarks, false, ScScenarioFlags::ShowFrame );
+ ScRangeListRef xRanges = new ScRangeList;
+ aMarks.FillRangeListWithMarks( xRanges.get(), false );
+
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ for (size_t j = 0, n = xRanges->size(); j < n; ++j)
+ {
+ ScRange aRange = (*xRanges)[j];
+ // Always extend scenario frame to merged cells where no new non-covered cells
+ // are framed
+ rDoc.ExtendTotalMerge( aRange );
+
+ //! -> Extend repaint when merging !!!
+
+ if ( aRange.Intersects( aViewRange ) ) //! Space for Text/Button?
+ {
+ Point aStartPos = rViewData.GetScrPos(
+ aRange.aStart.Col(), aRange.aStart.Row(), eWhich, true );
+ Point aEndPos = rViewData.GetScrPos(
+ aRange.aEnd.Col()+1, aRange.aEnd.Row()+1, eWhich, true );
+ // on the grid:
+ aStartPos.AdjustX( -nLayoutSign );
+ aStartPos.AdjustY( -1 );
+ aEndPos.AdjustX( -nLayoutSign );
+ aEndPos.AdjustY( -1 );
+
+ bool bTextBelow = ( aRange.aStart.Row() == 0 );
+
+ OUString aCurrent;
+ Color aColor( COL_LIGHTGRAY );
+ for (SCTAB nAct=nTab+1; nAct<nTabCount && rDoc.IsScenario(nAct); nAct++)
+ if ( rDoc.IsActiveScenario(nAct) && rDoc.HasScenarioRange(nAct,aRange) )
+ {
+ OUString aDummyComment;
+ ScScenarioFlags nDummyFlags;
+ rDoc.GetName( nAct, aCurrent );
+ rDoc.GetScenarioData( nAct, aDummyComment, aColor, nDummyFlags );
+ }
+
+ if (aCurrent.isEmpty())
+ aCurrent = ScResId( STR_EMPTYDATA );
+
+ //! Own text "(None)" instead of "(Empty)" ???
+
+ lcl_DrawOneFrame( pDev, tools::Rectangle( aStartPos, aEndPos ),
+ aCurrent, aColor, bTextBelow,
+ rViewData.GetPPTX(), rViewData.GetPPTY(), rViewData.GetZoomY(),
+ rDoc, rViewData, bLayoutRTL );
+ }
+ }
+}
+
+static void lcl_DrawHighlight( ScOutputData& rOutputData, const ScViewData& rViewData,
+ const std::vector<ScHighlightEntry>& rHighlightRanges )
+{
+ SCTAB nTab = rViewData.GetTabNo();
+ for ( const auto& rHighlightRange : rHighlightRanges)
+ {
+ ScRange aRange = rHighlightRange.aRef;
+ if ( nTab >= aRange.aStart.Tab() && nTab <= aRange.aEnd.Tab() )
+ {
+ rOutputData.DrawRefMark(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(),
+ rHighlightRange.aColor, false );
+ }
+ }
+}
+
+// Calculates top-left offset to be applied based on margins and indent.
+static void lcl_GetEditAreaTLOffset(tools::Long& nOffsetX, tools::Long& nOffsetY, const ScAddress& rAddr,
+ const ScViewData& rViewData, ScDocument& rDoc)
+{
+ tools::Long nLeftMargin = 0;
+ tools::Long nTopMargin = 0;
+ tools::Long nIndent = 0;
+ tools::Long nDummy = 0;
+ ScEditUtil aEUtil(&rDoc, rAddr.Col(), rAddr.Row(), rAddr.Tab(),
+ Point(0, 0), nullptr, rViewData.GetPPTX(),
+ rViewData.GetPPTY(), Fraction(1.0), Fraction(1.0),
+ false /* bPrintTwips */);
+ const ScPatternAttr* pPattern = rDoc.GetPattern(rAddr);
+ if (!rDoc.IsLayoutRTL(rAddr.Tab()))
+ nIndent = aEUtil.GetIndent(pPattern);
+ aEUtil.GetMargins(pPattern, nLeftMargin, nTopMargin, nDummy, nDummy);
+ nOffsetX = nIndent + nLeftMargin;
+ nOffsetY = nTopMargin;
+}
+
+void ScGridWindow::DoInvertRect( const tools::Rectangle& rPixel )
+{
+ if ( rPixel == aInvertRect )
+ aInvertRect = tools::Rectangle(); // Cancel
+ else
+ {
+ OSL_ENSURE( aInvertRect.IsEmpty(), "DoInvertRect no pairs" );
+
+ aInvertRect = rPixel; // Mark new rectangle
+ }
+
+ UpdateHeaderOverlay(); // uses aInvertRect
+}
+
+void ScGridWindow::PrePaint(vcl::RenderContext& /*rRenderContext*/)
+{
+ // forward PrePaint to DrawingLayer
+ ScTabViewShell* pTabViewShell = mrViewData.GetViewShell();
+
+ if(pTabViewShell)
+ {
+ SdrView* pDrawView = pTabViewShell->GetScDrawView();
+
+ if (pDrawView)
+ {
+ pDrawView->PrePaint();
+ }
+ }
+}
+
+bool ScGridWindow::NeedLOKCursorInvalidation(const tools::Rectangle& rCursorRect,
+ const Fraction aScaleX, const Fraction aScaleY)
+{
+ // Don't see the need for a map as there will be only a few zoom levels
+ // and as of now X and Y zooms in online are the same.
+ for (auto& rEntry : maLOKLastCursor)
+ {
+ if (aScaleX == rEntry.aScaleX && aScaleY == rEntry.aScaleY)
+ {
+ if (rCursorRect == rEntry.aRect)
+ return false; // No change
+
+ // Update and allow invalidate.
+ rEntry.aRect = rCursorRect;
+ return true;
+ }
+ }
+
+ maLOKLastCursor.push_back(LOKCursorEntry{aScaleX, aScaleY, rCursorRect});
+ return true;
+}
+
+void ScGridWindow::InvalidateLOKViewCursor(const tools::Rectangle& rCursorRect,
+ const Fraction aScaleX, const Fraction aScaleY)
+{
+ if (!NeedLOKCursorInvalidation(rCursorRect, aScaleX, aScaleY))
+ return;
+
+ ScTabViewShell* pThisViewShell = mrViewData.GetViewShell();
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+
+ while (pViewShell)
+ {
+ if (pViewShell != pThisViewShell && pViewShell->GetDocId() == pThisViewShell->GetDocId())
+ {
+ ScTabViewShell* pOtherViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pOtherViewShell)
+ {
+ ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
+ Fraction aZoomX = rOtherViewData.GetZoomX();
+ Fraction aZoomY = rOtherViewData.GetZoomY();
+ if (aZoomX == aScaleX && aZoomY == aScaleY)
+ {
+ SfxLokHelper::notifyOtherView(pThisViewShell, pOtherViewShell,
+ LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, "rectangle", rCursorRect.toString());
+ }
+ }
+ }
+
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
+void ScGridWindow::Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect )
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ if ( rDoc.IsInInterpreter() )
+ {
+ // Via Reschedule, interpreted cells do not trigger Invalidate again,
+ // otherwise for instance an error box would never appear (bug 36381).
+ // Later, through bNeedsRepaint everything is painted again.
+ if ( bNeedsRepaint )
+ {
+ //! Merge Rectangle?
+ aRepaintPixel = tools::Rectangle(); // multiple -> paint all
+ }
+ else
+ {
+ bNeedsRepaint = true;
+ aRepaintPixel = LogicToPixel(rRect); // only affected ranges
+ }
+ return;
+ }
+
+ // #i117893# If GetSizePixel needs to call the resize handler, the resulting nested Paint call
+ // (possibly for a larger rectangle) has to be allowed. Call GetSizePixel before setting bIsInPaint.
+ GetSizePixel();
+
+ if (bIsInPaint)
+ return;
+
+ bIsInPaint = true;
+
+ tools::Rectangle aPixRect = LogicToPixel( rRect );
+
+ SCCOL nX1 = mrViewData.GetPosX(eHWhich);
+ SCROW nY1 = mrViewData.GetPosY(eVWhich);
+
+ SCTAB nTab = mrViewData.GetTabNo();
+
+ double nPPTX = mrViewData.GetPPTX();
+ double nPPTY = mrViewData.GetPPTY();
+
+ tools::Rectangle aMirroredPixel = aPixRect;
+ if ( rDoc.IsLayoutRTL( nTab ) )
+ {
+ // mirror and swap
+ tools::Long nWidth = GetSizePixel().Width();
+ aMirroredPixel.SetLeft( nWidth - 1 - aPixRect.Right() );
+ aMirroredPixel.SetRight( nWidth - 1 - aPixRect.Left() );
+ }
+
+ tools::Long nScrX = ScViewData::ToPixel( rDoc.GetColWidth( nX1, nTab ), nPPTX );
+ while ( nScrX <= aMirroredPixel.Left() && nX1 < rDoc.MaxCol() )
+ {
+ ++nX1;
+ nScrX += ScViewData::ToPixel( rDoc.GetColWidth( nX1, nTab ), nPPTX );
+ }
+ SCCOL nX2 = nX1;
+ while ( nScrX <= aMirroredPixel.Right() && nX2 < rDoc.MaxCol() )
+ {
+ ++nX2;
+ nScrX += ScViewData::ToPixel( rDoc.GetColWidth( nX2, nTab ), nPPTX );
+ }
+
+ tools::Long nScrY = 0;
+ ScViewData::AddPixelsWhile( nScrY, aPixRect.Top(), nY1, rDoc.MaxRow(), nPPTY, &rDoc, nTab);
+ SCROW nY2 = nY1;
+ if (nScrY <= aPixRect.Bottom() && nY2 < rDoc.MaxRow())
+ {
+ ++nY2;
+ ScViewData::AddPixelsWhile( nScrY, aPixRect.Bottom(), nY2, rDoc.MaxRow(), nPPTY, &rDoc, nTab);
+ }
+
+ Draw( nX1,nY1,nX2,nY2, ScUpdateMode::Marks ); // don't continue with painting
+
+ bIsInPaint = false;
+}
+
+void ScGridWindow::Draw( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, ScUpdateMode eMode )
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+
+ // let's ignore the normal Draw() attempts when doing the tiled rendering,
+ // all the rendering should go through PaintTile() in that case.
+ // TODO revisit if we can actually turn this into an assert(), and clean
+ // up the callers
+ if (comphelper::LibreOfficeKit::isActive())
+ return;
+
+ ScModule* pScMod = SC_MOD();
+ bool bTextWysiwyg = pScMod->GetInputOptions().GetTextWysiwyg();
+
+ if (mrViewData.IsMinimized())
+ return;
+
+ PutInOrder( nX1, nX2 );
+ PutInOrder( nY1, nY2 );
+
+ OSL_ENSURE( rDoc.ValidCol(nX2) && rDoc.ValidRow(nY2), "GridWin Draw area too big" );
+
+ UpdateVisibleRange();
+
+ if (nX2 < maVisibleRange.mnCol1 || nY2 < maVisibleRange.mnRow1)
+ return;
+ // invisible
+ if (nX1 < maVisibleRange.mnCol1)
+ nX1 = maVisibleRange.mnCol1;
+ if (nY1 < maVisibleRange.mnRow1)
+ nY1 = maVisibleRange.mnRow1;
+
+ if (nX1 > maVisibleRange.mnCol2 || nY1 > maVisibleRange.mnRow2)
+ return;
+
+ if (nX2 > maVisibleRange.mnCol2)
+ nX2 = maVisibleRange.mnCol2;
+ if (nY2 > maVisibleRange.mnRow2)
+ nY2 = maVisibleRange.mnRow2;
+
+ if ( eMode != ScUpdateMode::Marks && nX2 < maVisibleRange.mnCol2)
+ nX2 = maVisibleRange.mnCol2; // to continue painting
+
+ // point of no return
+
+ ++nPaintCount; // mark that painting is in progress
+
+ SCTAB nTab = mrViewData.GetTabNo();
+ rDoc.ExtendHidden( nX1, nY1, nX2, nY2, nTab );
+
+ Point aScrPos = mrViewData.GetScrPos( nX1, nY1, eWhich );
+ tools::Long nMirrorWidth = GetSizePixel().Width();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ if ( bLayoutRTL )
+ {
+ tools::Long nEndPixel = mrViewData.GetScrPos( nX2+1, maVisibleRange.mnRow1, eWhich ).X();
+ nMirrorWidth = aScrPos.X() - nEndPixel;
+ aScrPos.setX( nEndPixel + 1 );
+ }
+
+ tools::Long nScrX = aScrPos.X();
+ tools::Long nScrY = aScrPos.Y();
+
+ SCCOL nCurX = mrViewData.GetCurX();
+ SCROW nCurY = mrViewData.GetCurY();
+ SCCOL nCurEndX = nCurX;
+ SCROW nCurEndY = nCurY;
+ rDoc.ExtendMerge( nCurX, nCurY, nCurEndX, nCurEndY, nTab );
+ bool bCurVis = nCursorHideCount==0 &&
+ ( nCurEndX+1 >= nX1 && nCurX <= nX2+1 && nCurEndY+1 >= nY1 && nCurY <= nY2+1 );
+
+ // AutoFill Handles
+ if ( !bCurVis && nCursorHideCount==0 && bAutoMarkVisible && aAutoMarkPos.Tab() == nTab &&
+ ( aAutoMarkPos.Col() != nCurX || aAutoMarkPos.Row() != nCurY ) )
+ {
+ SCCOL nHdlX = aAutoMarkPos.Col();
+ SCROW nHdlY = aAutoMarkPos.Row();
+ rDoc.ExtendMerge( nHdlX, nHdlY, nHdlX, nHdlY, nTab );
+ // left and top is unaffected
+
+ //! Paint AutoFill handles alone (without Cursor) ???
+ }
+
+ double nPPTX = mrViewData.GetPPTX();
+ double nPPTY = mrViewData.GetPPTY();
+
+ const ScViewOptions& rOpts = mrViewData.GetOptions();
+
+ // data block
+
+ ScTableInfo aTabInfo;
+ rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nTab,
+ nPPTX, nPPTY, false, rOpts.GetOption(VOPT_FORMULAS),
+ &mrViewData.GetMarkData() );
+
+ Fraction aZoomX = mrViewData.GetZoomX();
+ Fraction aZoomY = mrViewData.GetZoomY();
+ ScOutputData aOutputData( GetOutDev(), OUTTYPE_WINDOW, aTabInfo, &rDoc, nTab,
+ nScrX, nScrY, nX1, nY1, nX2, nY2, nPPTX, nPPTY,
+ &aZoomX, &aZoomY );
+
+ aOutputData.SetMirrorWidth( nMirrorWidth ); // needed for RTL
+ aOutputData.SetSpellCheckContext(mpSpellCheckCxt.get());
+
+ ScopedVclPtr< VirtualDevice > xFmtVirtDev;
+ bool bLogicText = bTextWysiwyg; // call DrawStrings in logic MapMode?
+
+ if ( bTextWysiwyg )
+ {
+ // use printer for text formatting
+
+ OutputDevice* pFmtDev = rDoc.GetPrinter();
+ pFmtDev->SetMapMode( mrViewData.GetLogicMode(eWhich) );
+ aOutputData.SetFmtDevice( pFmtDev );
+ }
+ else if ( aZoomX != aZoomY && mrViewData.IsOle() )
+ {
+ // #i45033# For OLE inplace editing with different zoom factors,
+ // use a virtual device with 1/100th mm as text formatting reference
+
+ xFmtVirtDev.disposeAndReset( VclPtr<VirtualDevice>::Create() );
+ xFmtVirtDev->SetMapMode(MapMode(MapUnit::Map100thMM));
+ aOutputData.SetFmtDevice( xFmtVirtDev.get() );
+
+ bLogicText = true; // use logic MapMode
+ }
+
+ DrawContent(*GetOutDev(), aTabInfo, aOutputData, bLogicText);
+
+ // If something was inverted during the Paint (selection changed from Basic Macro)
+ // then this is now mixed up and has to be repainted
+ OSL_ENSURE(nPaintCount, "Wrong nPaintCount");
+ --nPaintCount;
+ if (!nPaintCount)
+ CheckNeedsRepaint();
+
+ // Flag drawn formula cells "unchanged".
+ rDoc.ResetChanged(ScRange(nX1, nY1, nTab, nX2, nY2, nTab));
+ rDoc.PrepareFormulaCalc();
+}
+
+namespace {
+
+class SuppressEditViewMessagesGuard
+{
+public:
+ SuppressEditViewMessagesGuard(EditView& rEditView) :
+ mrEditView(rEditView),
+ mbOrigSuppressFlag(rEditView.IsSuppressLOKMessages())
+ {
+ if (!mbOrigSuppressFlag)
+ mrEditView.SuppressLOKMessages(true);
+ }
+
+ ~SuppressEditViewMessagesGuard()
+ {
+ if (mrEditView.IsSuppressLOKMessages() != mbOrigSuppressFlag)
+ mrEditView.SuppressLOKMessages(mbOrigSuppressFlag);
+ }
+
+private:
+ EditView& mrEditView;
+ const bool mbOrigSuppressFlag;
+};
+
+}
+
+/**
+ * Used to store the necessary information about the (combined-)tile
+ * area relevant to coordinate transformations in RTL mode.
+ */
+class ScLokRTLContext
+{
+public:
+ ScLokRTLContext(const ScOutputData& rOutputData, const tools::Long nTileDeviceOriginPixelX):
+ mrOutputData(rOutputData),
+ mnTileDevOriginX(nTileDeviceOriginPixelX)
+ {}
+
+ /**
+ * Converts from document x pixel position to the
+ * corresponding pixel position w.r.t the tile device origin.
+ */
+ tools::Long docToTilePos(tools::Long nPosX) const
+ {
+ tools::Long nMirrorX = (-2 * mnTileDevOriginX) + mrOutputData.GetScrW();
+ return nMirrorX - 1 - nPosX;
+ }
+
+
+private:
+ const ScOutputData& mrOutputData;
+ const tools::Long mnTileDevOriginX;
+};
+
+void ScGridWindow::DrawContent(OutputDevice &rDevice, const ScTableInfo& rTableInfo, ScOutputData& aOutputData,
+ bool bLogicText)
+{
+ ScModule* pScMod = SC_MOD();
+ ScDocument& rDoc = mrViewData.GetDocument();
+ const ScViewOptions& rOpts = mrViewData.GetOptions();
+ bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
+ bool bNoBackgroundAndGrid = bIsTiledRendering
+ && comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scNoGridBackground);
+
+ SCTAB nTab = aOutputData.nTab;
+ SCCOL nX1 = aOutputData.nX1;
+ SCROW nY1 = aOutputData.nY1;
+ SCCOL nX2 = aOutputData.nX2;
+ SCROW nY2 = aOutputData.nY2;
+ tools::Long nScrX = aOutputData.nScrX;
+ tools::Long nScrY = aOutputData.nScrY;
+
+ const svtools::ColorConfig& rColorCfg = pScMod->GetColorConfig();
+ Color aGridColor( rColorCfg.GetColorValue( svtools::CALCGRID, false ).nColor );
+ if ( aGridColor == COL_TRANSPARENT )
+ {
+ // use view options' grid color only if color config has "automatic" color
+ aGridColor = rOpts.GetGridColor();
+ }
+
+ aOutputData.SetSyntaxMode ( mrViewData.IsSyntaxMode() );
+ aOutputData.SetGridColor ( aGridColor );
+ aOutputData.SetShowNullValues ( rOpts.GetOption( VOPT_NULLVALS ) );
+ aOutputData.SetShowFormulas ( rOpts.GetOption( VOPT_FORMULAS ) );
+ aOutputData.SetShowSpellErrors ( rDoc.GetDocOptions().IsAutoSpell() );
+ aOutputData.SetMarkClipped ( rOpts.GetOption( VOPT_CLIPMARKS ) );
+
+ aOutputData.SetUseStyleColor( true ); // always set in table view
+
+ aOutputData.SetViewShell( mrViewData.GetViewShell() );
+
+ bool bGrid = rOpts.GetOption( VOPT_GRID ) && mrViewData.GetShowGrid();
+ bool bGridFirst = !rOpts.GetOption( VOPT_GRID_ONTOP );
+
+ bool bPage = rOpts.GetOption( VOPT_PAGEBREAKS ) && !bIsTiledRendering;
+
+ bool bPageMode = mrViewData.IsPagebreakMode();
+ if (bPageMode) // after FindChanged
+ {
+ // SetPagebreakMode also initializes bPrinted Flags
+ aOutputData.SetPagebreakMode( mrViewData.GetView()->GetPageBreakData() );
+ }
+
+ EditView* pEditView = nullptr;
+ bool bEditMode = mrViewData.HasEditView(eWhich);
+ if ( bEditMode && mrViewData.GetRefTabNo() == nTab )
+ {
+ SCCOL nEditCol;
+ SCROW nEditRow;
+ mrViewData.GetEditView( eWhich, pEditView, nEditCol, nEditRow );
+ SCCOL nEditEndCol = mrViewData.GetEditEndCol();
+ SCROW nEditEndRow = mrViewData.GetEditEndRow();
+
+ if ( nEditEndCol >= nX1 && nEditCol <= nX2 && nEditEndRow >= nY1 && nEditRow <= nY2 )
+ aOutputData.SetEditCell( nEditCol, nEditRow );
+ else
+ bEditMode = false;
+ }
+
+ const MapMode aOriginalMode = rDevice.GetMapMode();
+
+ // define drawing layer map mode and paint rectangle
+ MapMode aDrawMode = GetDrawMapMode();
+ if (bIsTiledRendering)
+ {
+ // FIXME this shouldn't be necessary once we change the entire Calc to
+ // work in the logic coordinates (ideally 100ths of mm - so that it is
+ // the same as editeng and drawinglayer), and get rid of all the
+ // SetMapMode's and other unnecessary fun we have with pixels
+ // See also ScGridWindow::GetDrawMapMode() for the rest of this hack
+ aDrawMode.SetOrigin(PixelToLogic(Point(tools::Long(nScrX / aOutputData.aZoomX),
+ tools::Long(nScrY / aOutputData.aZoomY)), aDrawMode));
+ }
+ tools::Rectangle aDrawingRectLogic;
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ bool bLokRTL = bLayoutRTL && bIsTiledRendering;
+ std::unique_ptr<ScLokRTLContext> pLokRTLCtxt(
+ bLokRTL ?
+ new ScLokRTLContext(aOutputData, o3tl::convert(aOriginalMode.GetOrigin().X(), o3tl::Length::twip, o3tl::Length::px)) :
+ nullptr);
+
+ {
+ // get drawing pixel rect
+ tools::Rectangle aDrawingRectPixel(
+ bLokRTL ? Point(-(nScrX + aOutputData.GetScrW()), nScrY) : Point(nScrX, nScrY),
+ Size(aOutputData.GetScrW(), aOutputData.GetScrH()));
+
+ // correct for border (left/right)
+ if(rDoc.MaxCol() == nX2 && !bLokRTL)
+ {
+ if(bLayoutRTL)
+ {
+ aDrawingRectPixel.SetLeft( 0 );
+ }
+ else
+ {
+ aDrawingRectPixel.SetRight( GetOutputSizePixel().getWidth() );
+ }
+ }
+
+ // correct for border (bottom)
+ if(rDoc.MaxRow() == nY2)
+ {
+ aDrawingRectPixel.SetBottom( GetOutputSizePixel().getHeight() );
+ }
+
+ // get logic positions
+ aDrawingRectLogic = PixelToLogic(aDrawingRectPixel, aDrawMode);
+ }
+
+ bool bInPlaceEditing = bEditMode && (mrViewData.GetRefTabNo() == mrViewData.GetTabNo());
+ vcl::Cursor* pInPlaceCrsr = nullptr;
+ bool bInPlaceVisCursor = false;
+ if (bInPlaceEditing)
+ {
+ // toggle the cursor off if it's on to ensure the cursor invert
+ // background logic remains valid after the background is cleared on
+ // the next cursor flash
+ pInPlaceCrsr = pEditView->GetCursor();
+ bInPlaceVisCursor = pInPlaceCrsr && pInPlaceCrsr->IsVisible();
+ if (bInPlaceVisCursor)
+ pInPlaceCrsr->Hide();
+ }
+
+ OutputDevice* pContentDev = &rDevice; // device for document content, used by overlay manager
+ SdrPaintWindow* pTargetPaintWindow = nullptr; // #i74769# work with SdrPaintWindow directly
+
+ {
+ // init redraw
+ ScTabViewShell* pTabViewShell = mrViewData.GetViewShell();
+
+ if(pTabViewShell)
+ {
+ MapMode aCurrentMapMode(pContentDev->GetMapMode());
+ pContentDev->SetMapMode(aDrawMode);
+ SdrView* pDrawView = pTabViewShell->GetScDrawView();
+
+ if(pDrawView)
+ {
+ // #i74769# Use new BeginDrawLayers() interface
+ vcl::Region aDrawingRegion(aDrawingRectLogic);
+ pTargetPaintWindow = pDrawView->BeginDrawLayers(pContentDev, aDrawingRegion);
+ OSL_ENSURE(pTargetPaintWindow, "BeginDrawLayers: Got no SdrPaintWindow (!)");
+
+ if (!bIsTiledRendering)
+ {
+ // #i74769# get target device from SdrPaintWindow, this may be the prerender
+ // device now, too.
+ pContentDev = &(pTargetPaintWindow->GetTargetOutputDevice());
+ aOutputData.SetContentDevice(pContentDev);
+ }
+ }
+
+ pContentDev->SetMapMode(aCurrentMapMode);
+ }
+ }
+
+ // app-background / document edge (area) (Pixel)
+ if ( !bIsTiledRendering && ( nX2 == rDoc.MaxCol() || nY2 == rDoc.MaxRow() ) )
+ {
+ // save MapMode and set to pixel
+ MapMode aCurrentMapMode(pContentDev->GetMapMode());
+ pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
+
+ tools::Rectangle aPixRect( Point(), GetOutputSizePixel() );
+ pContentDev->SetFillColor( rColorCfg.GetColorValue(svtools::APPBACKGROUND).nColor );
+ pContentDev->SetLineColor();
+ if ( nX2==rDoc.MaxCol() )
+ {
+ tools::Rectangle aDrawRect( aPixRect );
+ if ( bLayoutRTL )
+ aDrawRect.SetRight( nScrX - 1 );
+ else
+ aDrawRect.SetLeft( nScrX + aOutputData.GetScrW() );
+ if (aDrawRect.Right() >= aDrawRect.Left())
+ pContentDev->DrawRect( aDrawRect );
+ }
+ if ( nY2==rDoc.MaxRow() )
+ {
+ tools::Rectangle aDrawRect( aPixRect );
+ aDrawRect.SetTop( nScrY + aOutputData.GetScrH() );
+ if ( nX2==rDoc.MaxCol() )
+ {
+ // no double painting of the corner
+ if ( bLayoutRTL )
+ aDrawRect.SetLeft( nScrX );
+ else
+ aDrawRect.SetRight( nScrX + aOutputData.GetScrW() - 1 );
+ }
+ if (aDrawRect.Bottom() >= aDrawRect.Top())
+ pContentDev->DrawRect( aDrawRect );
+ }
+
+ // restore MapMode
+ pContentDev->SetMapMode(aCurrentMapMode);
+ }
+
+ if ( rDoc.HasBackgroundDraw( nTab, aDrawingRectLogic ) )
+ {
+ pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
+ aOutputData.DrawClear();
+
+ // drawing background
+
+ pContentDev->SetMapMode(aDrawMode);
+ DrawRedraw( aOutputData, SC_LAYER_BACK );
+ }
+ else
+ aOutputData.SetSolidBackground(!bNoBackgroundAndGrid);
+
+ aOutputData.DrawDocumentBackground();
+
+ if (bGridFirst && (bGrid || bPage))
+ {
+ // Draw lines in background color cover over lok client grid lines in merged cell areas if bNoBackgroundAndGrid is set.
+ if (bNoBackgroundAndGrid)
+ aOutputData.DrawGrid(*pContentDev, false /* bGrid */, false /* bPage */, true /* bMergeCover */);
+ else
+ aOutputData.DrawGrid(*pContentDev, bGrid, bPage);
+ }
+
+ aOutputData.DrawBackground(*pContentDev);
+
+ if (!bGridFirst && (bGrid || bPage) && !bNoBackgroundAndGrid)
+ aOutputData.DrawGrid(*pContentDev, bGrid, bPage);
+
+ pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
+
+ //tdf#128258 - draw a dotted line before hidden columns/rows
+ DrawHiddenIndicator(nX1,nY1,nX2,nY2, *pContentDev);
+
+ if ( bPageMode )
+ {
+ // DrawPagePreview draws complete lines/page numbers, must always be clipped
+ if ( aOutputData.SetChangedClip() )
+ {
+ DrawPagePreview(nX1,nY1,nX2,nY2, *pContentDev);
+ pContentDev->SetClipRegion();
+ }
+ }
+
+ aOutputData.DrawShadow();
+ aOutputData.DrawFrame(*pContentDev);
+
+ aOutputData.DrawSparklines(*pContentDev);
+
+ // Show Note Mark
+ if ( rOpts.GetOption( VOPT_NOTES ) )
+ aOutputData.DrawNoteMarks(*pContentDev);
+
+ if ( !bLogicText )
+ aOutputData.DrawStrings(); // in pixel MapMode
+
+ // edit cells and printer-metrics text must be before the buttons
+ // (DataPilot buttons contain labels in UI font)
+
+ pContentDev->SetMapMode(mrViewData.GetLogicMode(eWhich));
+ if ( bLogicText )
+ aOutputData.DrawStrings(true); // in logic MapMode if bLogicText is set
+ aOutputData.DrawEdit(true);
+
+ // the buttons are painted in absolute coordinates
+ if (bIsTiledRendering)
+ {
+ // Tiled offset nScrX, nScrY
+ MapMode aMap( MapUnit::MapPixel );
+ Point aOrigin = aOriginalMode.GetOrigin();
+ aOrigin.setX(o3tl::convert(aOrigin.getX(), o3tl::Length::twip, o3tl::Length::px) + nScrX);
+ aOrigin.setY(o3tl::convert(aOrigin.getY(), o3tl::Length::twip, o3tl::Length::px) + nScrY);
+ aMap.SetOrigin(aOrigin);
+ pContentDev->SetMapMode(aMap);
+ }
+ else
+ pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
+
+ // Autofilter- and Pivot-Buttons
+ DrawButtons(nX1, nX2, rTableInfo, pContentDev, pLokRTLCtxt.get()); // Pixel
+
+ pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
+
+ aOutputData.DrawClipMarks();
+
+ // In any case, Scenario / ChangeTracking must happen after DrawGrid, also for !bGridFirst
+
+ //! test if ChangeTrack display is active
+ //! Disable scenario frame via view option?
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ const std::vector<ScHighlightEntry> &rHigh = mrViewData.GetView()->GetHighlightRanges();
+ bool bHasScenario = ( nTab+1<nTabCount && rDoc.IsScenario(nTab+1) && !rDoc.IsScenario(nTab) );
+ bool bHasChange = ( rDoc.GetChangeTrack() != nullptr );
+
+ if ( bHasChange || bHasScenario || !rHigh.empty() )
+ {
+ //! Merge SetChangedClip() with DrawMarks() ?? (different MapMode!)
+
+ if ( bHasChange )
+ aOutputData.DrawChangeTrack();
+
+ if ( bHasScenario )
+ lcl_DrawScenarioFrames( pContentDev, mrViewData, eWhich, nX1,nY1,nX2,nY2 );
+
+ lcl_DrawHighlight( aOutputData, mrViewData, rHigh );
+ }
+
+ // Drawing foreground
+
+ pContentDev->SetMapMode(aDrawMode);
+
+ // Bitmaps and buttons are in absolute pixel coordinates.
+ const MapMode aOrig = pContentDev->GetMapMode();
+ if (bIsTiledRendering)
+ {
+ Point aOrigin = aOriginalMode.GetOrigin();
+ tools::Long nXOffset = bLayoutRTL ?
+ (-o3tl::convert(aOrigin.getX(), o3tl::Length::twip, o3tl::Length::px) + aOutputData.GetScrW()) :
+ o3tl::convert(aOrigin.getX(), o3tl::Length::twip, o3tl::Length::px);
+ Size aPixelOffset(nXOffset, o3tl::convert(aOrigin.getY(), o3tl::Length::twip, o3tl::Length::px));
+ pContentDev->SetPixelOffset(aPixelOffset);
+ comphelper::LibreOfficeKit::setLocalRendering();
+ }
+
+ DrawRedraw( aOutputData, SC_LAYER_FRONT );
+ DrawRedraw( aOutputData, SC_LAYER_INTERN );
+ DrawSdrGrid( aDrawingRectLogic, pContentDev );
+
+ if (bIsTiledRendering)
+ {
+ pContentDev->SetPixelOffset(Size());
+ pContentDev->SetMapMode(aOrig);
+ }
+
+ pContentDev->SetMapMode(MapMode(MapUnit::MapPixel));
+
+ if ( mrViewData.IsRefMode() && nTab >= mrViewData.GetRefStartZ() && nTab <= mrViewData.GetRefEndZ() )
+ {
+ Color aRefColor( rColorCfg.GetColorValue(svtools::CALCREFERENCE).nColor );
+ aOutputData.DrawRefMark( mrViewData.GetRefStartX(), mrViewData.GetRefStartY(),
+ mrViewData.GetRefEndX(), mrViewData.GetRefEndY(),
+ aRefColor, false );
+ }
+
+ // range finder
+
+ ScInputHandler* pHdl = pScMod->GetInputHdl( mrViewData.GetViewShell() );
+ if (pHdl)
+ {
+ ScDocShell* pDocSh = mrViewData.GetDocShell();
+ ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList();
+ if ( pRangeFinder && !pRangeFinder->IsHidden() &&
+ pRangeFinder->GetDocName() == pDocSh->GetTitle() )
+ {
+ sal_uInt16 nCount = static_cast<sal_uInt16>(pRangeFinder->Count());
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ ScRangeFindData& rData = pRangeFinder->GetObject(i);
+
+ ScRange aRef = rData.aRef;
+ aRef.PutInOrder();
+ if ( aRef.aStart.Tab() >= nTab && aRef.aEnd.Tab() <= nTab )
+ aOutputData.DrawRefMark( aRef.aStart.Col(), aRef.aStart.Row(),
+ aRef.aEnd.Col(), aRef.aEnd.Row(),
+ rData.nColor,
+ true );
+ }
+ }
+ }
+
+ {
+ // end redraw
+ ScTabViewShell* pTabViewShell = mrViewData.GetViewShell();
+
+ if(pTabViewShell)
+ {
+ MapMode aCurrentMapMode(pContentDev->GetMapMode());
+ pContentDev->SetMapMode(aDrawMode);
+
+ if (bIsTiledRendering)
+ {
+ const double fZoomX = static_cast<double>(aOutputData.aZoomX);
+ const double fZoomY = static_cast<double>(aOutputData.aZoomY);
+
+ Point aOrigin = aOriginalMode.GetOrigin();
+ if (bLayoutRTL)
+ aOrigin.setX(-o3tl::convert(aOrigin.getX(), o3tl::Length::twip, o3tl::Length::px)
+ + aOutputData.nScrX + aOutputData.GetScrW());
+ else
+ aOrigin.setX(o3tl::convert(aOrigin.getX(), o3tl::Length::twip, o3tl::Length::px)
+ + aOutputData.nScrX);
+
+ aOrigin.setY(o3tl::convert(aOrigin.getY(), o3tl::Length::twip, o3tl::Length::px)
+ + aOutputData.nScrY);
+ const double twipFactor = 15 * 1.76388889; // 26.45833335
+ aOrigin = Point(aOrigin.getX() * twipFactor / fZoomX,
+ aOrigin.getY() * twipFactor / fZoomY);
+ MapMode aNew = rDevice.GetMapMode();
+ aNew.SetOrigin(aOrigin);
+ rDevice.SetMapMode(aNew);
+ }
+
+ SdrView* pDrawView = pTabViewShell->GetScDrawView();
+
+ if(pDrawView)
+ {
+ // #i74769# work with SdrPaintWindow directly
+ pDrawView->EndDrawLayers(*pTargetPaintWindow, true);
+ }
+
+ pContentDev->SetMapMode(aCurrentMapMode);
+ }
+ }
+
+ // paint in-place editing on other views
+ if (bIsTiledRendering)
+ {
+ ScTabViewShell* pThisViewShell = mrViewData.GetViewShell();
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+
+ while (pViewShell)
+ {
+ if (pViewShell != pThisViewShell && pViewShell->GetDocId() == pThisViewShell->GetDocId())
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pTabViewShell)
+ {
+ ScViewData& rOtherViewData = pTabViewShell->GetViewData();
+ ScSplitPos eOtherWhich = rOtherViewData.GetEditActivePart();
+
+ bool bOtherEditMode = rOtherViewData.HasEditView(eOtherWhich);
+ SCCOL nCol1 = rOtherViewData.GetEditStartCol();
+ SCROW nRow1 = rOtherViewData.GetEditStartRow();
+ SCCOL nCol2 = rOtherViewData.GetEditEndCol();
+ SCROW nRow2 = rOtherViewData.GetEditEndRow();
+ bOtherEditMode = bOtherEditMode
+ && ( nCol2 >= nX1 && nCol1 <= nX2 && nRow2 >= nY1 && nRow1 <= nY2 );
+ if (bOtherEditMode && rOtherViewData.GetRefTabNo() == nTab)
+ {
+ EditView* pOtherEditView = rOtherViewData.GetEditView(eOtherWhich);
+ if (pOtherEditView)
+ {
+ tools::Long nScreenX = aOutputData.nScrX;
+ tools::Long nScreenY = aOutputData.nScrY;
+
+ rDevice.SetLineColor();
+ rDevice.SetFillColor(pOtherEditView->GetBackgroundColor());
+ Point aStart = mrViewData.GetScrPos( nCol1, nRow1, eOtherWhich );
+ Point aEnd = mrViewData.GetScrPos( nCol2+1, nRow2+1, eOtherWhich );
+
+ if (bLokRTL)
+ {
+ // Transform the cell range X coordinates such that the edit cell area is
+ // horizontally mirrored w.r.t the (combined-)tile.
+ aStart.setX(pLokRTLCtxt->docToTilePos(aStart.X()));
+ aEnd.setX(pLokRTLCtxt->docToTilePos(aEnd.X()));
+ }
+
+ // don't overwrite grid
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+ aEnd.AdjustX( -(2 * nLayoutSign) );
+ aEnd.AdjustY( -2 );
+
+ tools::Rectangle aBackground(aStart, aEnd);
+ if (bLokRTL)
+ aBackground.Justify();
+
+ // Need to draw the background in absolute coords.
+ Point aOrigin = aOriginalMode.GetOrigin();
+ aOrigin.setX(
+ o3tl::convert(aOrigin.getX(), o3tl::Length::twip, o3tl::Length::px)
+ + nScreenX);
+ aOrigin.setY(
+ o3tl::convert(aOrigin.getY(), o3tl::Length::twip, o3tl::Length::px)
+ + nScreenY);
+ aBackground += aOrigin;
+ rDevice.SetMapMode(aDrawMode);
+
+ static const double twipFactor = 15 * 1.76388889; // 26.45833335
+ // keep into account the zoom factor
+ aOrigin = Point((aOrigin.getX() * twipFactor) / static_cast<double>(aDrawMode.GetScaleX()),
+ (aOrigin.getY() * twipFactor) / static_cast<double>(aDrawMode.GetScaleY()));
+
+ MapMode aNew = rDevice.GetMapMode();
+ aNew.SetOrigin(aOrigin);
+ rDevice.SetMapMode(aNew);
+
+ // paint the background
+ rDevice.DrawRect(rDevice.PixelToLogic(aBackground));
+
+ tools::Rectangle aEditRect(aBackground);
+ tools::Long nOffsetX = 0, nOffsetY = 0;
+ // Get top-left offset because of margin and indent.
+ lcl_GetEditAreaTLOffset(nOffsetX, nOffsetY, ScAddress(nCol1, nRow1, nTab), mrViewData, rDoc);
+ aEditRect.AdjustLeft(nOffsetX + 1);
+ aEditRect.AdjustTop(nOffsetY + 1);
+
+ // EditView has an 'output area' which is used to clip the 'paint area' we provide below.
+ // So they need to be in the same coordinates/units. This is tied to the mapmode of the gridwin
+ // attached to the EditView, so we have to change its mapmode too (temporarily). We save the
+ // original mapmode and 'output area' and roll them back when we finish painting to rDevice.
+ OutputDevice& rOtherWin = pOtherEditView->GetOutputDevice();
+ const tools::Rectangle aOrigOutputArea(pOtherEditView->GetOutputArea()); // Not in pixels.
+ const MapMode aOrigMapMode = rOtherWin.GetMapMode();
+ rOtherWin.SetMapMode(rDevice.GetMapMode());
+
+ // Avoid sending wrong cursor/selection messages by the 'other' view, as the output-area is going
+ // to be tweaked temporarily to match the current view's zoom.
+ SuppressEditViewMessagesGuard aGuard(*pOtherEditView);
+
+ pOtherEditView->SetOutputArea(rDevice.PixelToLogic(aEditRect));
+ pOtherEditView->Paint(rDevice.PixelToLogic(aEditRect), &rDevice);
+
+ // Rollback the mapmode and 'output area'.
+ rOtherWin.SetMapMode(aOrigMapMode);
+ pOtherEditView->SetOutputArea(aOrigOutputArea);
+ rDevice.SetMapMode(MapMode(MapUnit::MapPixel));
+ }
+ }
+ }
+ }
+
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+
+ }
+
+ // In-place editing - when the user is typing, we need to paint the text
+ // using the editeng.
+ // It's being done after EndDrawLayers() to get it outside the overlay
+ // buffer and on top of everything.
+ if (bInPlaceEditing)
+ {
+ // get the coordinates of the area we need to clear (overpaint by
+ // the background)
+ SCCOL nCol1 = mrViewData.GetEditStartCol();
+ SCROW nRow1 = mrViewData.GetEditStartRow();
+ SCCOL nCol2 = mrViewData.GetEditEndCol();
+ SCROW nRow2 = mrViewData.GetEditEndRow();
+ rDevice.SetLineColor();
+ rDevice.SetFillColor(pEditView->GetBackgroundColor());
+ Point aStart = mrViewData.GetScrPos( nCol1, nRow1, eWhich );
+ Point aEnd = mrViewData.GetScrPos( nCol2+1, nRow2+1, eWhich );
+
+ if (bLokRTL)
+ {
+ // Transform the cell range X coordinates such that the edit cell area is
+ // horizontally mirrored w.r.t the (combined-)tile.
+ aStart.setX(pLokRTLCtxt->docToTilePos(aStart.X()));
+ aEnd.setX(pLokRTLCtxt->docToTilePos(aEnd.X()));
+ }
+
+ // don't overwrite grid
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+ aEnd.AdjustX( -(2 * nLayoutSign) );
+ aEnd.AdjustY( -2 );
+
+ // set the correct mapmode
+ tools::Rectangle aBackground(aStart, aEnd);
+ if (bLokRTL)
+ aBackground.Justify();
+ tools::Rectangle aBGAbs(aBackground);
+
+ if (bIsTiledRendering)
+ {
+ // Need to draw the background in absolute coords.
+ Point aOrigin = aOriginalMode.GetOrigin();
+ aOrigin.setX(o3tl::convert(aOrigin.getX(), o3tl::Length::twip, o3tl::Length::px)
+ + nScrX);
+ aOrigin.setY(o3tl::convert(aOrigin.getY(), o3tl::Length::twip, o3tl::Length::px)
+ + nScrY);
+ aBackground += aOrigin;
+ rDevice.SetMapMode(aDrawMode);
+ }
+ else
+ rDevice.SetMapMode(mrViewData.GetLogicMode());
+
+ if (bIsTiledRendering)
+ {
+ Point aOrigin = aOriginalMode.GetOrigin();
+ aOrigin.setX(o3tl::convert(aOrigin.getX(), o3tl::Length::twip, o3tl::Length::px)
+ + nScrX);
+ aOrigin.setY(o3tl::convert(aOrigin.getY(), o3tl::Length::twip, o3tl::Length::px)
+ + nScrY);
+ static const double twipFactor = 15 * 1.76388889; // 26.45833335
+ // keep into account the zoom factor
+ aOrigin = Point((aOrigin.getX() * twipFactor) / static_cast<double>(aDrawMode.GetScaleX()),
+ (aOrigin.getY() * twipFactor) / static_cast<double>(aDrawMode.GetScaleY()));
+ MapMode aNew = rDevice.GetMapMode();
+ aNew.SetOrigin(aOrigin);
+ rDevice.SetMapMode(aNew);
+ }
+
+ // paint the background
+ tools::Rectangle aLogicRect(rDevice.PixelToLogic(aBackground));
+ //tdf#100925, rhbz#1283420, Draw some text here, to get
+ //X11CairoTextRender::getCairoContext called, so that the forced read
+ //from the underlying X Drawable gets it to sync.
+ rDevice.DrawText(aLogicRect.BottomLeft(), " ");
+ rDevice.DrawRect(aLogicRect);
+
+ // paint the editeng text
+ if (bIsTiledRendering)
+ {
+ tools::Rectangle aEditRect(aBackground);
+ tools::Long nOffsetX = 0, nOffsetY = 0;
+ // Get top-left offset because of margin and indent.
+ lcl_GetEditAreaTLOffset(nOffsetX, nOffsetY, ScAddress(nCol1, nRow1, mrViewData.GetTabNo()), mrViewData, rDoc);
+ aEditRect.AdjustLeft(nOffsetX + 1);
+ aEditRect.AdjustTop(nOffsetY + 1);
+
+ // EditView has an 'output area' which is used to clip the paint area we provide below.
+ // So they need to be in the same coordinates/units. This is tied to the mapmode of the gridwin
+ // attached to the EditView, so we have to change its mapmode too (temporarily). We save the
+ // original mapmode and 'output area' and roll them back when we finish painting to rDevice.
+ const tools::Rectangle aOrigOutputArea(pEditView->GetOutputArea()); // Not in pixels.
+ const MapMode aOrigMapMode = GetMapMode();
+ SetMapMode(rDevice.GetMapMode());
+
+ // Avoid sending wrong cursor/selection messages by the current view, as the output-area is going
+ // to be tweaked temporarily to match other view's zoom. (This does not affect the manual
+ // cursor-messaging done in the non print-twips mode)
+ SuppressEditViewMessagesGuard aGuard(*pEditView);
+
+ pEditView->SetOutputArea(rDevice.PixelToLogic(aEditRect));
+ pEditView->Paint(rDevice.PixelToLogic(aEditRect), &rDevice);
+
+ // EditView will do the cursor notifications correctly if we're in
+ // print-twips messaging mode.
+ if (!comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ {
+ // Now we need to get relative cursor position within the editview.
+ // This is for sending the pixel-aligned twips position of the cursor to the specific views with
+ // the same given zoom level.
+ tools::Rectangle aCursorRect = pEditView->GetEditCursor();
+ Point aCursPos = o3tl::toTwips(aCursorRect.TopLeft(), o3tl::Length::mm100);
+
+ const MapMode& rDevMM = rDevice.GetMapMode();
+ MapMode aMM(MapUnit::MapTwip);
+ aMM.SetScaleX(rDevMM.GetScaleX());
+ aMM.SetScaleY(rDevMM.GetScaleY());
+
+ aBGAbs.AdjustLeft(1);
+ aBGAbs.AdjustTop(1);
+ aCursorRect = GetOutDev()->PixelToLogic(aBGAbs, aMM);
+ aCursorRect.setWidth(0);
+ aCursorRect.Move(aCursPos.getX(), 0);
+ // Sends view cursor position to views of all matching zooms if needed (avoids duplicates).
+ InvalidateLOKViewCursor(aCursorRect, aMM.GetScaleX(), aMM.GetScaleY());
+ }
+
+ // Rollback the mapmode and 'output area'.
+ SetMapMode(aOrigMapMode);
+ pEditView->SetOutputArea(aOrigOutputArea);
+ }
+ else
+ {
+ tools::Rectangle aEditRect(Point(nScrX, nScrY), Size(aOutputData.GetScrW(), aOutputData.GetScrH()));
+ pEditView->Paint(rDevice.PixelToLogic(aEditRect), &rDevice);
+ }
+
+ rDevice.SetMapMode(MapMode(MapUnit::MapPixel));
+
+ // restore the cursor it was originally visible
+ if (bInPlaceVisCursor)
+ pInPlaceCrsr->Show();
+ }
+
+ if (mrViewData.HasEditView(eWhich))
+ {
+ // flush OverlayManager before changing the MapMode
+ flushOverlayManager();
+
+ // set MapMode for text edit
+ rDevice.SetMapMode(mrViewData.GetLogicMode());
+ }
+ else
+ rDevice.SetMapMode(aDrawMode);
+
+ if (mpNoteMarker)
+ mpNoteMarker->Draw(); // Above the cursor, in drawing map mode
+
+ if (bPage && bInitialPageBreaks)
+ SetupInitialPageBreaks(rDoc, nTab);
+}
+
+
+void ScGridWindow::SetupInitialPageBreaks(const ScDocument& rDoc, SCTAB nTab)
+{
+ // tdf#124983, if option LibreOfficeDev Calc/View/Visual Aids/Page breaks
+ // is enabled, breaks should be visible. If the document is opened the first
+ // time, the breaks are not calculated yet, so for this initialization
+ // a timer will be triggered here.
+ std::set<SCCOL> aColBreaks;
+ std::set<SCROW> aRowBreaks;
+ rDoc.GetAllColBreaks(aColBreaks, nTab, true, false);
+ rDoc.GetAllRowBreaks(aRowBreaks, nTab, true, false);
+ if (aColBreaks.size() == 0 || aRowBreaks.size() == 0)
+ {
+ maShowPageBreaksTimer.SetPriority(TaskPriority::DEFAULT_IDLE);
+ maShowPageBreaksTimer.Start();
+ }
+ bInitialPageBreaks = false;
+}
+
+namespace
+{
+ template<typename IndexType>
+ void lcl_getBoundingRowColumnforTile(ScViewData& rViewData,
+ tools::Long nTileStartPosPx, tools::Long nTileEndPosPx,
+ sal_Int32& nTopLeftTileOffset, sal_Int32& nTopLeftTileOrigin,
+ sal_Int32& nTopLeftTileIndex, sal_Int32& nBottomRightTileIndex)
+ {
+ const bool bColumnHeader = std::is_same<IndexType, SCCOL>::value;
+
+ SCTAB nTab = rViewData.GetTabNo();
+
+ IndexType nStartIndex = -1;
+ IndexType nEndIndex = -1;
+ tools::Long nStartPosPx = 0;
+ tools::Long nEndPosPx = 0;
+
+ ScPositionHelper& rPositionHelper =
+ bColumnHeader ? rViewData.GetLOKWidthHelper() : rViewData.GetLOKHeightHelper();
+ const auto& rStartNearest = rPositionHelper.getNearestByPosition(nTileStartPosPx);
+ const auto& rEndNearest = rPositionHelper.getNearestByPosition(nTileEndPosPx);
+
+ ScBoundsProvider aBoundsProvider(rViewData, nTab, bColumnHeader);
+ aBoundsProvider.Compute(rStartNearest, rEndNearest, nTileStartPosPx, nTileEndPosPx);
+ aBoundsProvider.GetStartIndexAndPosition(nStartIndex, nStartPosPx); ++nStartIndex;
+ aBoundsProvider.GetEndIndexAndPosition(nEndIndex, nEndPosPx);
+
+ nTopLeftTileOffset = nTileStartPosPx - nStartPosPx;
+ nTopLeftTileOrigin = nStartPosPx;
+ nTopLeftTileIndex = nStartIndex;
+ nBottomRightTileIndex = nEndIndex;
+ }
+
+ void lcl_RTLAdjustTileColOffset(ScViewData& rViewData, sal_Int32& nTileColOffset,
+ tools::Long nTileEndPx, sal_Int32 nEndCol, SCTAB nTab,
+ const ScDocument& rDoc, double fPPTX)
+ {
+ auto GetColWidthPx = [&rDoc, nTab, fPPTX](SCCOL nCol) {
+ const sal_uInt16 nSize = rDoc.GetColWidth(nCol, nTab);
+ const tools::Long nSizePx = ScViewData::ToPixel(nSize, fPPTX);
+ return nSizePx;
+ };
+
+ ScPositionHelper rHelper = rViewData.GetLOKWidthHelper();
+ tools::Long nEndColPos = rHelper.computePosition(nEndCol, GetColWidthPx);
+
+ nTileColOffset += (nEndColPos - nTileEndPx - nTileColOffset);
+ }
+
+ class ScLOKProxyObjectContact final : public sdr::contact::ObjectContactOfPageView
+ {
+ private:
+ ScDrawView* mpScDrawView;
+
+ public:
+ explicit ScLOKProxyObjectContact(
+ ScDrawView* pDrawView,
+ SdrPageWindow& rPageWindow,
+ const char* pDebugName) :
+ ObjectContactOfPageView(rPageWindow, pDebugName),
+ mpScDrawView(pDrawView)
+ {
+ }
+
+ virtual bool supportsGridOffsets() const override { return true; }
+
+ virtual void calculateGridOffsetForViewOjectContact(
+ basegfx::B2DVector& rTarget,
+ const sdr::contact::ViewObjectContact& rClient) const override
+ {
+ if (!mpScDrawView)
+ return;
+
+ SdrPageView* pPageView(mpScDrawView->GetSdrPageView());
+ if (!pPageView)
+ return;
+
+ SdrPageWindow* pSdrPageWindow = nullptr;
+ if (pPageView->PageWindowCount() > 0)
+ pSdrPageWindow = pPageView->GetPageWindow(0);
+ if (!pSdrPageWindow)
+ return;
+
+ sdr::contact::ObjectContact& rObjContact(pSdrPageWindow->GetObjectContact());
+
+ SdrObject* pTargetSdrObject(rClient.GetViewContact().TryToGetSdrObject());
+ if (pTargetSdrObject)
+ rTarget = pTargetSdrObject->GetViewContact().GetViewObjectContact(rObjContact).getGridOffset();
+ }
+ };
+
+ class ScLOKDrawView : public FmFormView
+ {
+ public:
+ ScLOKDrawView(OutputDevice* pOut, ScViewData& rData) :
+ FmFormView(*rData.GetDocument().GetDrawLayer(), pOut),
+ mpScDrawView(rData.GetScDrawView())
+ {
+ }
+
+ virtual sdr::contact::ObjectContact* createViewSpecificObjectContact(
+ SdrPageWindow& rPageWindow, const char* pDebugName) const override
+ {
+ if (!mpScDrawView)
+ return SdrView::createViewSpecificObjectContact(rPageWindow, pDebugName);
+
+ return new ScLOKProxyObjectContact(mpScDrawView, rPageWindow, pDebugName);
+ }
+
+ private:
+ ScDrawView* mpScDrawView;
+ };
+} // anonymous namespace
+
+void ScGridWindow::PaintTile( VirtualDevice& rDevice,
+ int nOutputWidth, int nOutputHeight,
+ int nTilePosX, int nTilePosY,
+ tools::Long nTileWidth, tools::Long nTileHeight )
+{
+ Fraction origZoomX = mrViewData.GetZoomX();
+ Fraction origZoomY = mrViewData.GetZoomY();
+
+ // Output size is in pixels while tile position and size are in logical units (twips).
+
+ // Assumption: always paint the whole sheet i.e. "visible" range is always
+ // from (0,0) to last data position.
+
+ // Tile geometry is independent of the zoom level, but the output size is
+ // dependent of the zoom level. Determine the correct zoom level before
+ // we start.
+
+ // FIXME the painting works using a mixture of drawing with coordinates in
+ // pixels and in logic coordinates; it should be cleaned up to use logic
+ // coords only, and avoid all the SetMapMode()'s.
+ // Similarly to Writer, we should set the mapmode once on the rDevice, and
+ // not care about any zoom settings.
+
+ Fraction aFracX(o3tl::convert(nOutputWidth, o3tl::Length::px, o3tl::Length::twip), nTileWidth);
+ Fraction aFracY(o3tl::convert(nOutputHeight, o3tl::Length::px, o3tl::Length::twip), nTileHeight);
+
+ const bool bChangeZoom = (aFracX != origZoomX || aFracY != origZoomY);
+
+ // page break zoom, and aLogicMode in ScViewData
+ // FIXME: there are issues when SetZoom is called conditionally.
+ mrViewData.SetZoom(aFracX, aFracY, true);
+ if (bChangeZoom)
+ {
+ if (ScDrawView* pDrawView = mrViewData.GetScDrawView())
+ pDrawView->resetGridOffsetsForAllSdrPageViews();
+ }
+
+ const double fTilePosXPixel = static_cast<double>(nTilePosX) * nOutputWidth / nTileWidth;
+ const double fTilePosYPixel = static_cast<double>(nTilePosY) * nOutputHeight / nTileHeight;
+ const double fTileBottomPixel = static_cast<double>(nTilePosY + nTileHeight) * nOutputHeight / nTileHeight;
+ const double fTileRightPixel = static_cast<double>(nTilePosX + nTileWidth) * nOutputWidth / nTileWidth;
+
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScDocument& rDoc = mrViewData.GetDocument();
+
+ const double fPPTX = mrViewData.GetPPTX();
+ const double fPPTY = mrViewData.GetPPTY();
+
+ // find approximate col/row offsets of nearby.
+ sal_Int32 nTopLeftTileRowOffset = 0;
+ sal_Int32 nTopLeftTileColOffset = 0;
+ sal_Int32 nTopLeftTileRowOrigin = 0;
+ sal_Int32 nTopLeftTileColOrigin = 0;
+
+ sal_Int32 nTopLeftTileRow = 0;
+ sal_Int32 nTopLeftTileCol = 0;
+ sal_Int32 nBottomRightTileRow = 0;
+ sal_Int32 nBottomRightTileCol = 0;
+
+ lcl_getBoundingRowColumnforTile<SCROW>(mrViewData,
+ fTilePosYPixel, fTileBottomPixel,
+ nTopLeftTileRowOffset, nTopLeftTileRowOrigin,
+ nTopLeftTileRow, nBottomRightTileRow);
+
+ lcl_getBoundingRowColumnforTile<SCCOL>(mrViewData,
+ fTilePosXPixel, fTileRightPixel,
+ nTopLeftTileColOffset, nTopLeftTileColOrigin,
+ nTopLeftTileCol, nBottomRightTileCol);
+
+ // Enlarge
+ nBottomRightTileCol++;
+ nBottomRightTileRow++;
+
+ if (nBottomRightTileCol > rDoc.MaxCol())
+ nBottomRightTileCol = rDoc.MaxCol();
+
+ if (nBottomRightTileRow > MAXTILEDROW)
+ nBottomRightTileRow = MAXTILEDROW;
+
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ if (bLayoutRTL)
+ {
+ lcl_RTLAdjustTileColOffset(mrViewData, nTopLeftTileColOffset,
+ fTileRightPixel, nBottomRightTileCol, nTab,
+ rDoc, fPPTX);
+ }
+
+ // size of the document including drawings, charts, etc.
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ rDoc.GetTiledRenderingArea(nTab, nEndCol, nEndRow);
+
+ if (nEndCol < nBottomRightTileCol)
+ nEndCol = nBottomRightTileCol;
+
+ if (nEndRow < nBottomRightTileRow)
+ nEndRow = nBottomRightTileRow;
+
+ nTopLeftTileCol = std::max<sal_Int32>(nTopLeftTileCol, 0);
+ nTopLeftTileRow = std::max<sal_Int32>(nTopLeftTileRow, 0);
+ nTopLeftTileColOrigin = o3tl::convert(nTopLeftTileColOrigin, o3tl::Length::px, o3tl::Length::twip);
+ nTopLeftTileRowOrigin = o3tl::convert(nTopLeftTileRowOrigin, o3tl::Length::px, o3tl::Length::twip);
+
+ // Checkout -> 'rDoc.ExtendMerge' ... if we miss merged cells.
+
+ // Origin must be the offset of the first col and row
+ // containing our top-left pixel.
+ const MapMode aOriginalMode = rDevice.GetMapMode();
+ MapMode aAbsMode = aOriginalMode;
+ const Point aOrigin(-nTopLeftTileColOrigin, -nTopLeftTileRowOrigin);
+ aAbsMode.SetOrigin(aOrigin);
+ rDevice.SetMapMode(aAbsMode);
+
+ ScTableInfo aTabInfo(nEndRow + 3);
+ rDoc.FillInfo(aTabInfo, nTopLeftTileCol, nTopLeftTileRow,
+ nBottomRightTileCol, nBottomRightTileRow,
+ nTab, fPPTX, fPPTY, false, false);
+
+// FIXME: is this called some
+// Point aScrPos = mrViewData.GetScrPos( nX1, nY1, eWhich );
+
+ ScOutputData aOutputData(&rDevice, OUTTYPE_WINDOW, aTabInfo, &rDoc, nTab,
+ -nTopLeftTileColOffset,
+ -nTopLeftTileRowOffset,
+ nTopLeftTileCol, nTopLeftTileRow,
+ nBottomRightTileCol, nBottomRightTileRow,
+ fPPTX, fPPTY, &aFracX, &aFracY);
+
+ // setup the SdrPage so that drawinglayer works correctly
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ if (pModel)
+ {
+ bool bPrintTwipsMsgs = comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
+ mpLOKDrawView.reset(bPrintTwipsMsgs ?
+ new ScLOKDrawView(
+ &rDevice,
+ mrViewData) :
+ new FmFormView(
+ *pModel,
+ &rDevice));
+
+ mpLOKDrawView->SetNegativeX(bLayoutRTL);
+ mpLOKDrawView->ShowSdrPage(mpLOKDrawView->GetModel()->GetPage(nTab));
+ aOutputData.SetDrawView(mpLOKDrawView.get());
+ aOutputData.SetSpellCheckContext(mpSpellCheckCxt.get());
+ }
+
+ // draw the content
+ DrawContent(rDevice, aTabInfo, aOutputData, true);
+ rDevice.SetMapMode(aOriginalMode);
+
+ // Paint the chart(s) in edit mode.
+ LokChartHelper::PaintAllChartsOnTile(rDevice, nOutputWidth, nOutputHeight,
+ nTilePosX, nTilePosY, nTileWidth, nTileHeight, bLayoutRTL);
+
+ rDevice.SetMapMode(aOriginalMode);
+
+ // Flag drawn formula cells "unchanged".
+ rDoc.ResetChanged(ScRange(nTopLeftTileCol, nTopLeftTileRow, nTab, nBottomRightTileCol, nBottomRightTileRow, nTab));
+ rDoc.PrepareFormulaCalc();
+
+ mrViewData.SetZoom(origZoomX, origZoomY, true);
+ if (bChangeZoom)
+ {
+ if (ScDrawView* pDrawView = mrViewData.GetScDrawView())
+ pDrawView->resetGridOffsetsForAllSdrPageViews();
+ }
+
+ if (bLayoutRTL)
+ {
+ Bitmap aCellBMP = rDevice.GetBitmap(Point(0, 0), Size(nOutputWidth, nOutputHeight));
+ aCellBMP.Mirror(BmpMirrorFlags::Horizontal);
+ rDevice.DrawBitmap(Point(0, 0), Size(nOutputWidth, nOutputHeight), aCellBMP);
+ }
+}
+
+void ScGridWindow::LogicInvalidate(const tools::Rectangle* pRectangle)
+{
+ tools::Rectangle aRectangle;
+ tools::Rectangle* pResultRectangle;
+ if (!pRectangle)
+ pResultRectangle = nullptr;
+ else
+ {
+ aRectangle = *pRectangle;
+ // When dragging shapes the map mode is disabled.
+ if (IsMapModeEnabled())
+ {
+ if (GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
+ {
+ aRectangle = o3tl::convert(aRectangle, o3tl::Length::mm100, o3tl::Length::twip);
+ }
+ }
+ else
+ aRectangle = PixelToLogic(aRectangle, MapMode(MapUnit::MapTwip));
+ pResultRectangle = &aRectangle;
+ }
+
+ // Trim invalidation rectangle overlapping negative X region in RTL mode.
+ if (pResultRectangle && pResultRectangle->Left() < 0
+ && mrViewData.GetDocument().IsLayoutRTL(mrViewData.GetTabNo()))
+ {
+ pResultRectangle->SetLeft(0);
+ if (pResultRectangle->Right() < 0)
+ pResultRectangle->SetRight(0);
+ }
+
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ SfxLokHelper::notifyInvalidation(pViewShell, pResultRectangle);
+}
+
+void ScGridWindow::SetCellSelectionPixel(int nType, int nPixelX, int nPixelY)
+{
+ ScTabView* pTabView = mrViewData.GetView();
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ ScInputHandler* pInputHandler = SC_MOD()->GetInputHdl(pViewShell);
+
+ if (pInputHandler && pInputHandler->IsInputMode())
+ {
+ // we need to switch off the editeng
+ ScTabView::UpdateInputLine();
+ pViewShell->UpdateInputHandler();
+ }
+
+ if (nType == LOK_SETTEXTSELECTION_RESET)
+ {
+ pTabView->DoneBlockMode();
+ return;
+ }
+
+ // obtain the current selection
+ ScRangeList aRangeList = mrViewData.GetMarkData().GetMarkedRanges();
+
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ SCTAB nTab1, nTab2;
+
+ bool bWasEmpty = false;
+ if (aRangeList.empty())
+ {
+ nCol1 = nCol2 = mrViewData.GetCurX();
+ nRow1 = nRow2 = mrViewData.GetCurY();
+ bWasEmpty = true;
+ }
+ else
+ aRangeList.Combine().GetVars(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+
+ // convert the coordinates to column/row
+ SCCOL nNewPosX;
+ SCROW nNewPosY;
+ SCTAB nTab = mrViewData.GetTabNo();
+ mrViewData.GetPosFromPixel(nPixelX, nPixelY, eWhich, nNewPosX, nNewPosY);
+
+ // change the selection
+ switch (nType)
+ {
+ case LOK_SETTEXTSELECTION_START:
+ if (nNewPosX != nCol1 || nNewPosY != nRow1 || bWasEmpty)
+ {
+ pTabView->SetCursor(nNewPosX, nNewPosY);
+ pTabView->DoneBlockMode();
+ pTabView->InitBlockMode(nNewPosX, nNewPosY, nTab, true);
+ pTabView->MarkCursor(nCol2, nRow2, nTab);
+ }
+ break;
+ case LOK_SETTEXTSELECTION_END:
+ if (nNewPosX != nCol2 || nNewPosY != nRow2 || bWasEmpty)
+ {
+ pTabView->SetCursor(nCol1, nRow1);
+ pTabView->DoneBlockMode();
+ pTabView->InitBlockMode(nCol1, nRow1, nTab, true);
+ pTabView->MarkCursor(nNewPosX, nNewPosY, nTab);
+ }
+ break;
+ default:
+ assert(false);
+ break;
+ }
+}
+
+void ScGridWindow::CheckNeedsRepaint()
+{
+ // called at the end of painting, and from timer after background text width calculation
+
+ if (!bNeedsRepaint)
+ return;
+
+ bNeedsRepaint = false;
+ if (aRepaintPixel.IsEmpty())
+ Invalidate();
+ else
+ Invalidate(PixelToLogic(aRepaintPixel));
+ aRepaintPixel = tools::Rectangle();
+
+ // selection function in status bar might also be invalid
+ SfxBindings& rBindings = mrViewData.GetBindings();
+ rBindings.Invalidate( SID_STATUS_SUM );
+ rBindings.Invalidate( SID_ATTR_SIZE );
+ rBindings.Invalidate( SID_TABLE_CELL );
+}
+
+void ScGridWindow::DrawHiddenIndicator( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, vcl::RenderContext& rRenderContext)
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
+ const svtools::ColorConfigValue aColorValue = rColorCfg.GetColorValue(svtools::CALCHIDDENROWCOL);
+ if (aColorValue.bIsVisible) {
+ rRenderContext.SetLineColor(aColorValue.nColor);
+ LineInfo aLineInfo(LineStyle::Dash, 2);
+ aLineInfo.SetDashCount(0);
+ aLineInfo.SetDotCount(1);
+ aLineInfo.SetDistance(15);
+ // round caps except when running VCL_PLUGIN=gen due to a performance issue
+ // https://bugs.documentfoundation.org/show_bug.cgi?id=128258#c14
+ if (mrViewData.GetActiveWin()->GetSystemData()->toolkit != SystemEnvData::Toolkit::Gen)
+ aLineInfo.SetLineCap(css::drawing::LineCap_ROUND);
+ aLineInfo.SetDotLen(1);
+ for (int i=nX1; i<nX2; i++) {
+ if (rDoc.ColHidden(i,nTab) && (i<rDoc.MaxCol() ? !rDoc.ColHidden(i+1,nTab) : true)) {
+ Point aStart = mrViewData.GetScrPos(i, nY1, eWhich, true );
+ Point aEnd = mrViewData.GetScrPos(i, nY2, eWhich, true );
+ rRenderContext.DrawLine(aStart,aEnd,aLineInfo);
+ }
+ }
+ for (int i=nY1; i<nY2; i++) {
+ if (rDoc.RowHidden(i,nTab) && (i<rDoc.MaxRow() ? !rDoc.RowHidden(i+1,nTab) : true)) {
+ Point aStart = mrViewData.GetScrPos(nX1, i, eWhich, true );
+ Point aEnd = mrViewData.GetScrPos(nX2, i, eWhich, true );
+ rRenderContext.DrawLine(aStart,aEnd,aLineInfo);
+ }
+ }
+ } //visible
+}
+
+void ScGridWindow::DrawPagePreview( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, vcl::RenderContext& rRenderContext)
+{
+ ScPageBreakData* pPageData = mrViewData.GetView()->GetPageBreakData();
+ if (!pPageData)
+ return;
+
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ Size aWinSize = GetOutputSizePixel();
+ const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
+ Color aManual( rColorCfg.GetColorValue(svtools::CALCPAGEBREAKMANUAL).nColor );
+ Color aAutomatic( rColorCfg.GetColorValue(svtools::CALCPAGEBREAK).nColor );
+
+ OUString aPageStr = ScResId( STR_PGNUM );
+ if ( nPageScript == SvtScriptType::NONE )
+ {
+ // get script type of translated "Page" string only once
+ nPageScript = rDoc.GetStringScriptType( aPageStr );
+ if (nPageScript == SvtScriptType::NONE)
+ nPageScript = ScGlobal::GetDefaultScriptType();
+ }
+
+ vcl::Font aFont;
+ std::unique_ptr<ScEditEngineDefaulter> pEditEng;
+ const ScPatternAttr& rDefPattern = rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN);
+ if ( nPageScript == SvtScriptType::LATIN )
+ {
+ // use single font and call DrawText directly
+ rDefPattern.GetFont( aFont, SC_AUTOCOL_BLACK );
+ aFont.SetColor( COL_LIGHTGRAY );
+ // font size is set as needed
+ }
+ else
+ {
+ // use EditEngine to draw mixed-script string
+ pEditEng.reset(new ScEditEngineDefaulter( EditEngine::CreatePool().get(), true ));
+ pEditEng->SetRefMapMode(rRenderContext.GetMapMode());
+ auto pEditDefaults = std::make_unique<SfxItemSet>( pEditEng->GetEmptyItemSet() );
+ rDefPattern.FillEditItemSet( pEditDefaults.get() );
+ pEditDefaults->Put( SvxColorItem( COL_LIGHTGRAY, EE_CHAR_COLOR ) );
+ pEditEng->SetDefaults( std::move(pEditDefaults) );
+ }
+
+ sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() );
+ for (sal_uInt16 nPos=0; nPos<nCount; nPos++)
+ {
+ ScPrintRangeData& rData = pPageData->GetData(nPos);
+ ScRange aRange = rData.GetPrintRange();
+ if ( aRange.aStart.Col() <= nX2+1 && aRange.aEnd.Col()+1 >= nX1 &&
+ aRange.aStart.Row() <= nY2+1 && aRange.aEnd.Row()+1 >= nY1 )
+ {
+ // 3 pixel frame around the print area
+ // (middle pixel on the grid lines)
+
+ rRenderContext.SetLineColor();
+ if (rData.IsAutomatic())
+ rRenderContext.SetFillColor( aAutomatic );
+ else
+ rRenderContext.SetFillColor( aManual );
+
+ Point aStart = mrViewData.GetScrPos(
+ aRange.aStart.Col(), aRange.aStart.Row(), eWhich, true );
+ Point aEnd = mrViewData.GetScrPos(
+ aRange.aEnd.Col() + 1, aRange.aEnd.Row() + 1, eWhich, true );
+ aStart.AdjustX( -2 );
+ aStart.AdjustY( -2 );
+
+ // Prevent overflows:
+ if ( aStart.X() < -10 ) aStart.setX( -10 );
+ if ( aStart.Y() < -10 ) aStart.setY( -10 );
+ if ( aEnd.X() > aWinSize.Width() + 10 )
+ aEnd.setX( aWinSize.Width() + 10 );
+ if ( aEnd.Y() > aWinSize.Height() + 10 )
+ aEnd.setY( aWinSize.Height() + 10 );
+
+ rRenderContext.DrawRect( tools::Rectangle( aStart, Point(aEnd.X(),aStart.Y()+2) ) );
+ rRenderContext.DrawRect( tools::Rectangle( aStart, Point(aStart.X()+2,aEnd.Y()) ) );
+ rRenderContext.DrawRect( tools::Rectangle( Point(aStart.X(),aEnd.Y()-2), aEnd ) );
+ rRenderContext.DrawRect( tools::Rectangle( Point(aEnd.X()-2,aStart.Y()), aEnd ) );
+
+ // Page breaks
+ //! Display differently (dashed ????)
+
+ size_t nColBreaks = rData.GetPagesX();
+ const SCCOL* pColEnd = rData.GetPageEndX();
+ size_t nColPos;
+ for (nColPos=0; nColPos+1<nColBreaks; nColPos++)
+ {
+ SCCOL nBreak = pColEnd[nColPos]+1;
+ if ( nBreak >= nX1 && nBreak <= nX2+1 )
+ {
+ //! Search for hidden
+ if (rDoc.HasColBreak(nBreak, nTab) & ScBreakType::Manual)
+ rRenderContext.SetFillColor( aManual );
+ else
+ rRenderContext.SetFillColor( aAutomatic );
+ Point aBreak = mrViewData.GetScrPos(
+ nBreak, aRange.aStart.Row(), eWhich, true );
+ rRenderContext.DrawRect( tools::Rectangle( aBreak.X()-1, aStart.Y(), aBreak.X(), aEnd.Y() ) );
+ }
+ }
+
+ size_t nRowBreaks = rData.GetPagesY();
+ const SCROW* pRowEnd = rData.GetPageEndY();
+ size_t nRowPos;
+ for (nRowPos=0; nRowPos+1<nRowBreaks; nRowPos++)
+ {
+ SCROW nBreak = pRowEnd[nRowPos]+1;
+ if ( nBreak >= nY1 && nBreak <= nY2+1 )
+ {
+ //! Search for hidden
+ if (rDoc.HasRowBreak(nBreak, nTab) & ScBreakType::Manual)
+ rRenderContext.SetFillColor( aManual );
+ else
+ rRenderContext.SetFillColor( aAutomatic );
+ Point aBreak = mrViewData.GetScrPos(
+ aRange.aStart.Col(), nBreak, eWhich, true );
+ rRenderContext.DrawRect( tools::Rectangle( aStart.X(), aBreak.Y()-1, aEnd.X(), aBreak.Y() ) );
+ }
+ }
+
+ // Page numbers
+
+ SCROW nPrStartY = aRange.aStart.Row();
+ for (nRowPos=0; nRowPos<nRowBreaks; nRowPos++)
+ {
+ SCROW nPrEndY = pRowEnd[nRowPos];
+ if ( nPrEndY >= nY1 && nPrStartY <= nY2 )
+ {
+ SCCOL nPrStartX = aRange.aStart.Col();
+ for (nColPos=0; nColPos<nColBreaks; nColPos++)
+ {
+ SCCOL nPrEndX = pColEnd[nColPos];
+ if ( nPrEndX >= nX1 && nPrStartX <= nX2 )
+ {
+ Point aPageStart = mrViewData.GetScrPos(
+ nPrStartX, nPrStartY, eWhich, true );
+ Point aPageEnd = mrViewData.GetScrPos(
+ nPrEndX+1,nPrEndY+1, eWhich, true );
+
+ tools::Long nPageNo = rData.GetFirstPage();
+ if ( rData.IsTopDown() )
+ nPageNo += static_cast<tools::Long>(nColPos)*nRowBreaks+nRowPos;
+ else
+ nPageNo += static_cast<tools::Long>(nRowPos)*nColBreaks+nColPos;
+
+ OUString aThisPageStr = aPageStr.replaceFirst("%1", OUString::number(nPageNo));
+
+ if ( pEditEng )
+ {
+ // find right font size with EditEngine
+ tools::Long nHeight = 100;
+ pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
+ pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
+ pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );
+ pEditEng->SetTextCurrentDefaults( aThisPageStr );
+ Size aSize100( pEditEng->CalcTextWidth(), pEditEng->GetTextHeight() );
+
+ // 40% of width or 60% of height
+ tools::Long nSizeX = 40 * ( aPageEnd.X() - aPageStart.X() ) / aSize100.Width();
+ tools::Long nSizeY = 60 * ( aPageEnd.Y() - aPageStart.Y() ) / aSize100.Height();
+ nHeight = std::min(nSizeX,nSizeY);
+ pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT ) );
+ pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CJK ) );
+ pEditEng->SetDefaultItem( SvxFontHeightItem( nHeight, 100, EE_CHAR_FONTHEIGHT_CTL ) );
+
+ // centered output with EditEngine
+ Size aTextSize( pEditEng->CalcTextWidth(), pEditEng->GetTextHeight() );
+ Point aPos( (aPageStart.X()+aPageEnd.X()-aTextSize.Width())/2,
+ (aPageStart.Y()+aPageEnd.Y()-aTextSize.Height())/2 );
+ pEditEng->Draw(rRenderContext, aPos);
+ }
+ else
+ {
+ // find right font size for DrawText
+ aFont.SetFontSize( Size( 0,100 ) );
+ rRenderContext.SetFont( aFont );
+
+ Size aSize100(rRenderContext.GetTextWidth( aThisPageStr ), rRenderContext.GetTextHeight() );
+ if (aSize100.Width() && aSize100.Height())
+ {
+ // 40% of width or 60% of height
+ tools::Long nSizeX = 40 * ( aPageEnd.X() - aPageStart.X() ) / aSize100.Width();
+ tools::Long nSizeY = 60 * ( aPageEnd.Y() - aPageStart.Y() ) / aSize100.Height();
+ aFont.SetFontSize( Size( 0,std::min(nSizeX,nSizeY) ) );
+ rRenderContext.SetFont( aFont );
+ }
+
+ // centered output with DrawText
+ Size aTextSize(rRenderContext.GetTextWidth( aThisPageStr ), rRenderContext.GetTextHeight() );
+ Point aPos( (aPageStart.X()+aPageEnd.X()-aTextSize.Width())/2,
+ (aPageStart.Y()+aPageEnd.Y()-aTextSize.Height())/2 );
+ rRenderContext.DrawText( aPos, aThisPageStr );
+ }
+ }
+ nPrStartX = nPrEndX + 1;
+ }
+ }
+ nPrStartY = nPrEndY + 1;
+ }
+ }
+ }
+}
+
+void ScGridWindow::DrawButtons(SCCOL nX1, SCCOL nX2, const ScTableInfo& rTabInfo, OutputDevice* pContentDev, const ScLokRTLContext* pLokRTLContext)
+{
+ aComboButton.SetOutputDevice( pContentDev );
+
+ ScDocument& rDoc = mrViewData.GetDocument();
+ ScDPFieldButton aCellBtn(pContentDev, &GetSettings().GetStyleSettings(), &mrViewData.GetZoomY(), &rDoc);
+
+ SCCOL nCol;
+ SCROW nRow;
+ SCSIZE nArrY;
+ SCSIZE nQuery;
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScDBData* pDBData = nullptr;
+ std::unique_ptr<ScQueryParam> pQueryParam;
+
+ RowInfo* pRowInfo = rTabInfo.mpRowInfo.get();
+ sal_uInt16 nArrCount = rTabInfo.mnArrCount;
+
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ Point aOldPos = aComboButton.GetPosPixel(); // store state for MouseDown/Up
+ Size aOldSize = aComboButton.GetSizePixel();
+
+ for (nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ if ( pRowInfo[nArrY].bAutoFilter && pRowInfo[nArrY].bChanged )
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+
+ nRow = pThisRowInfo->nRowNo;
+
+ for (nCol=nX1; nCol<=nX2; nCol++)
+ {
+ ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nCol);
+ //if several columns merged on a row, there should be only one auto button at the end of the columns.
+ //if several rows merged on a column, the button may be in the middle, so "!pInfo->bVOverlapped" should not be used
+ if ( pInfo->bAutoFilter && !pInfo->bHOverlapped )
+ {
+ if (!pQueryParam)
+ pQueryParam.reset(new ScQueryParam);
+
+ bool bNewData = true;
+ if (pDBData)
+ {
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ SCTAB nAreaTab;
+ pDBData->GetArea( nAreaTab, nStartCol, nStartRow, nEndCol, nEndRow );
+ if ( nCol >= nStartCol && nCol <= nEndCol &&
+ nRow >= nStartRow && nRow <= nEndRow )
+ bNewData = false;
+ }
+ if (bNewData)
+ {
+ pDBData = rDoc.GetDBAtCursor( nCol, nRow, nTab, ScDBDataPortion::AREA );
+ if (pDBData)
+ pDBData->GetQueryParam( *pQueryParam );
+ else
+ {
+ // can also be part of DataPilot table
+ }
+ }
+
+ // pQueryParam can only include MAXQUERY entries
+
+ bool bArrowState = false;
+ if (pQueryParam->bInplace)
+ {
+ SCSIZE nCount = pQueryParam->GetEntryCount();
+ for (nQuery = 0; nQuery < nCount; ++nQuery)
+ {
+ // Do no restrict to EQUAL here
+ // (Column head should become blue also when ">1")
+ const ScQueryEntry& rEntry = pQueryParam->GetEntry(nQuery);
+ if (rEntry.bDoQuery && rEntry.nField == nCol)
+ {
+ bArrowState = true;
+ break;
+ }
+ }
+ }
+
+ tools::Long nSizeX;
+ tools::Long nSizeY;
+ SCCOL nStartCol= nCol;
+ SCROW nStartRow = nRow;
+ //if address(nCol,nRow) is not the start pos of the merge area, the value of the nSizeX will be incorrect, it will be the length of the cell.
+ //should first get the start pos of the merge area, then get the nSizeX through the start pos.
+ rDoc.ExtendOverlapped(nStartCol, nStartRow,nCol, nRow, nTab);//get nStartCol,nStartRow
+ mrViewData.GetMergeSizePixel( nStartCol, nStartRow, nSizeX, nSizeY );//get nSizeX
+ nSizeY = ScViewData::ToPixel(rDoc.GetRowHeight(nRow, nTab), mrViewData.GetPPTY());
+ Point aScrPos = mrViewData.GetScrPos( nCol, nRow, eWhich );
+ if (pLokRTLContext)
+ aScrPos.setX(pLokRTLContext->docToTilePos(aScrPos.X()));
+
+ aCellBtn.setBoundingBox(aScrPos, Size(nSizeX-1, nSizeY-1), bLayoutRTL);
+ aCellBtn.setPopupLeft(bLayoutRTL); // #i114944# AutoFilter button is left-aligned in RTL
+ aCellBtn.setDrawBaseButton(false);
+ aCellBtn.setDrawPopupButton(true);
+ aCellBtn.setHasHiddenMember(bArrowState);
+ aCellBtn.draw();
+ }
+ }
+ }
+
+ if ( pRowInfo[nArrY].bPivotButton && pRowInfo[nArrY].bChanged )
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ nRow = pThisRowInfo->nRowNo;
+ for (nCol=nX1; nCol<=nX2; nCol++)
+ {
+ ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nCol);
+ if (pInfo->bHOverlapped || pInfo->bVOverlapped)
+ continue;
+
+ Point aScrPos = mrViewData.GetScrPos( nCol, nRow, eWhich );
+ tools::Long nSizeX;
+ tools::Long nSizeY;
+ mrViewData.GetMergeSizePixel( nCol, nRow, nSizeX, nSizeY );
+ tools::Long nPosX = aScrPos.X();
+ tools::Long nPosY = aScrPos.Y();
+ // bLayoutRTL is handled in setBoundingBox
+
+ OUString aStr = rDoc.GetString(nCol, nRow, nTab);
+ aCellBtn.setText(aStr);
+ aCellBtn.setBoundingBox(Point(nPosX, nPosY), Size(nSizeX-1, nSizeY-1), bLayoutRTL);
+ aCellBtn.setPopupLeft(false); // DataPilot popup is always right-aligned for now
+ aCellBtn.setDrawBaseButton(pInfo->bPivotButton);
+ aCellBtn.setDrawPopupButton(pInfo->bPivotPopupButton);
+ aCellBtn.setHasHiddenMember(pInfo->bFilterActive);
+ aCellBtn.draw();
+ }
+ }
+
+ if ( !comphelper::LibreOfficeKit::isActive() && bListValButton && pRowInfo[nArrY].nRowNo == aListValPos.Row() && pRowInfo[nArrY].bChanged )
+ {
+ tools::Rectangle aRect = GetListValButtonRect( aListValPos );
+ aComboButton.SetPosPixel( aRect.TopLeft() );
+ aComboButton.SetSizePixel( aRect.GetSize() );
+ pContentDev->SetClipRegion(vcl::Region(aRect));
+ aComboButton.Draw();
+ pContentDev->SetClipRegion(); // always called from Draw() without clip region
+ aComboButton.SetPosPixel( aOldPos ); // restore old state
+ aComboButton.SetSizePixel( aOldSize ); // for MouseUp/Down (AutoFilter)
+ }
+ }
+
+ pQueryParam.reset();
+ aComboButton.SetOutputDevice( GetOutDev() );
+}
+
+tools::Rectangle ScGridWindow::GetListValButtonRect( const ScAddress& rButtonPos )
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ ScDDComboBoxButton aButton( GetOutDev() ); // for optimal size
+ Size aBtnSize = aButton.GetSizePixel();
+
+ SCCOL nCol = rButtonPos.Col();
+ SCROW nRow = rButtonPos.Row();
+
+ tools::Long nCellSizeX; // width of this cell, including merged
+ tools::Long nDummy;
+ mrViewData.GetMergeSizePixel( nCol, nRow, nCellSizeX, nDummy );
+
+ // for height, only the cell's row is used, excluding merged cells
+ tools::Long nCellSizeY = ScViewData::ToPixel( rDoc.GetRowHeight( nRow, nTab ), mrViewData.GetPPTY() );
+ tools::Long nAvailable = nCellSizeX;
+
+ // left edge of next cell if there is a non-hidden next column
+ SCCOL nNextCol = nCol + 1;
+ const ScMergeAttr* pMerge = rDoc.GetAttr( nCol,nRow,nTab, ATTR_MERGE );
+ if ( pMerge->GetColMerge() > 1 )
+ nNextCol = nCol + pMerge->GetColMerge(); // next cell after the merged area
+ while ( nNextCol <= rDoc.MaxCol() && rDoc.ColHidden(nNextCol, nTab) )
+ ++nNextCol;
+ bool bNextCell = ( nNextCol <= rDoc.MaxCol() );
+ if ( bNextCell )
+ nAvailable = ScViewData::ToPixel( rDoc.GetColWidth( nNextCol, nTab ), mrViewData.GetPPTX() );
+
+ if ( nAvailable < aBtnSize.Width() )
+ aBtnSize.setWidth( nAvailable );
+ if ( nCellSizeY < aBtnSize.Height() )
+ aBtnSize.setHeight( nCellSizeY );
+
+ Point aPos = mrViewData.GetScrPos( nCol, nRow, eWhich, true );
+ aPos.AdjustX(nCellSizeX * nLayoutSign ); // start of next cell
+ if (!bNextCell)
+ aPos.AdjustX( -(aBtnSize.Width() * nLayoutSign) ); // right edge of cell if next cell not available
+ aPos.AdjustY(nCellSizeY - aBtnSize.Height() );
+ // X remains at the left edge
+
+ if ( bLayoutRTL )
+ aPos.AdjustX( -(aBtnSize.Width()-1) ); // align right edge of button with cell border
+
+ return tools::Rectangle( aPos, aBtnSize );
+}
+
+bool ScGridWindow::IsAutoFilterActive( SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ ScDBData* pDBData = rDoc.GetDBAtCursor( nCol, nRow, nTab, ScDBDataPortion::AREA );
+ ScQueryParam aQueryParam;
+
+ if ( pDBData )
+ pDBData->GetQueryParam( aQueryParam );
+ else
+ {
+ OSL_FAIL("Auto filter button without DBData");
+ }
+
+ bool bSimpleQuery = true;
+ bool bColumnFound = false;
+ SCSIZE nQuery;
+
+ if ( !aQueryParam.bInplace )
+ bSimpleQuery = false;
+
+ // aQueryParam can only include MAXQUERY entries
+
+ SCSIZE nCount = aQueryParam.GetEntryCount();
+ for (nQuery = 0; nQuery < nCount && bSimpleQuery; ++nQuery)
+ if ( aQueryParam.GetEntry(nQuery).bDoQuery )
+ {
+ if (aQueryParam.GetEntry(nQuery).nField == nCol)
+ bColumnFound = true;
+
+ if (nQuery > 0)
+ if (aQueryParam.GetEntry(nQuery).eConnect != SC_AND)
+ bSimpleQuery = false;
+ }
+
+ return ( bSimpleQuery && bColumnFound );
+}
+
+void ScGridWindow::GetSelectionRects( ::std::vector< tools::Rectangle >& rPixelRects ) const
+{
+ GetPixelRectsFor( mrViewData.GetMarkData(), rPixelRects );
+}
+
+void ScGridWindow::GetSelectionRectsPrintTwips(::std::vector< tools::Rectangle >& rRects) const
+{
+ GetRectsAnyFor(mrViewData.GetMarkData(), rRects, true);
+}
+
+/// convert rMarkData into pixel rectangles for this view
+void ScGridWindow::GetPixelRectsFor( const ScMarkData &rMarkData,
+ ::std::vector< tools::Rectangle >& rPixelRects ) const
+{
+ GetRectsAnyFor(rMarkData, rPixelRects, false);
+}
+
+void ScGridWindow::GetRectsAnyFor(const ScMarkData &rMarkData,
+ ::std::vector< tools::Rectangle >& rRects,
+ bool bInPrintTwips) const
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ double nPPTX = mrViewData.GetPPTX();
+ double nPPTY = mrViewData.GetPPTY();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ // LOK clients needs exact document coordinates, so don't horizontally mirror them.
+ tools::Long nLayoutSign = (!comphelper::LibreOfficeKit::isActive() && bLayoutRTL) ? -1 : 1;
+
+ ScMarkData aMultiMark( rMarkData );
+ aMultiMark.SetMarking( false );
+
+ if (!aMultiMark.IsMultiMarked())
+ {
+ // simple range case - simplify calculation
+ const ScRange& aSimpleRange = aMultiMark.GetMarkArea();
+
+ aMultiMark.MarkToMulti();
+ if ( !aMultiMark.IsMultiMarked() )
+ return;
+
+ SCCOL nX1 = aSimpleRange.aStart.Col();
+ SCROW nY1 = aSimpleRange.aStart.Row();
+ SCCOL nX2 = aSimpleRange.aEnd.Col();
+ SCROW nY2 = aSimpleRange.aEnd.Row();
+
+ PutInOrder( nX1, nX2 );
+ PutInOrder( nY1, nY2 );
+
+ SCCOL nPosX = mrViewData.GetPosX( eHWhich );
+ SCROW nPosY = mrViewData.GetPosY( eVWhich );
+ // is the selection visible at all?
+ if (nX2 < nPosX || nY2 < nPosY)
+ return;
+
+ Point aScrStartPos = bInPrintTwips ? mrViewData.GetPrintTwipsPos(nX1, nY1) :
+ mrViewData.GetScrPos(nX1, nY1, eWhich);
+
+ tools::Long nStartX = aScrStartPos.X();
+ tools::Long nStartY = aScrStartPos.Y();
+
+ Point aScrEndPos = bInPrintTwips ? mrViewData.GetPrintTwipsPos(nX2, nY2) :
+ mrViewData.GetScrPos(nX2, nY2, eWhich);
+
+ tools::Long nWidthTwips = rDoc.GetColWidth(nX2, nTab);
+ const tools::Long nWidth = bInPrintTwips ?
+ nWidthTwips : ScViewData::ToPixel(nWidthTwips, nPPTX);
+ tools::Long nEndX = aScrEndPos.X() + (nWidth - 1) * nLayoutSign;
+
+ sal_uInt16 nHeightTwips = rDoc.GetRowHeight( nY2, nTab );
+ const tools::Long nHeight = bInPrintTwips ?
+ nHeightTwips : ScViewData::ToPixel(nHeightTwips, nPPTY);
+ tools::Long nEndY = aScrEndPos.Y() + nHeight - 1;
+
+ ScInvertMerger aInvert( &rRects );
+ aInvert.AddRect( tools::Rectangle( nStartX, nStartY, nEndX, nEndY ) );
+
+ return;
+ }
+
+ aMultiMark.MarkToMulti();
+ if ( !aMultiMark.IsMultiMarked() )
+ return;
+ const ScRange& aMultiRange = aMultiMark.GetMultiMarkArea();
+ SCCOL nX1 = aMultiRange.aStart.Col();
+ SCROW nY1 = aMultiRange.aStart.Row();
+ SCCOL nX2 = aMultiRange.aEnd.Col();
+ SCROW nY2 = aMultiRange.aEnd.Row();
+
+ PutInOrder( nX1, nX2 );
+ PutInOrder( nY1, nY2 );
+
+ SCCOL nTestX2 = nX2;
+ SCROW nTestY2 = nY2;
+
+ rDoc.ExtendMerge( nX1,nY1, nTestX2,nTestY2, nTab );
+
+ SCCOL nPosX = mrViewData.GetPosX( eHWhich );
+ SCROW nPosY = mrViewData.GetPosY( eVWhich );
+ // is the selection visible at all?
+ if (nTestX2 < nPosX || nTestY2 < nPosY)
+ return;
+ SCCOL nRealX1 = nX1;
+ if (nX1 < nPosX)
+ nX1 = nPosX;
+ if (nY1 < nPosY)
+ nY1 = nPosY;
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ // limit the selection to only what is visible on the screen
+ SCCOL nXRight = nPosX + mrViewData.VisibleCellsX(eHWhich);
+ if (nXRight > rDoc.MaxCol())
+ nXRight = rDoc.MaxCol();
+
+ SCROW nYBottom = nPosY + mrViewData.VisibleCellsY(eVWhich);
+ if (nYBottom > rDoc.MaxRow())
+ nYBottom = rDoc.MaxRow();
+
+ // is the selection visible at all?
+ if (nX1 > nXRight || nY1 > nYBottom)
+ return;
+
+ if (nX2 > nXRight)
+ nX2 = nXRight;
+ if (nY2 > nYBottom)
+ nY2 = nYBottom;
+ }
+ else
+ {
+ SCCOL nMaxTiledCol;
+ SCROW nMaxTiledRow;
+ rDoc.GetTiledRenderingArea(nTab, nMaxTiledCol, nMaxTiledRow);
+
+ if (nX2 > nMaxTiledCol)
+ nX2 = nMaxTiledCol;
+ if (nY2 > nMaxTiledRow)
+ nY2 = nMaxTiledRow;
+ }
+
+ ScInvertMerger aInvert( &rRects );
+
+ Point aScrPos = bInPrintTwips ? mrViewData.GetPrintTwipsPos(nX1, nY1) :
+ mrViewData.GetScrPos(nX1, nY1, eWhich);
+ tools::Long nScrY = aScrPos.Y();
+ bool bWasHidden = false;
+ for (SCROW nY=nY1; nY<=nY2; nY++)
+ {
+ bool bFirstRow = ( nY == nPosY ); // first visible row?
+ bool bDoHidden = false; // repeat hidden ?
+ sal_uInt16 nHeightTwips = rDoc.GetRowHeight( nY,nTab );
+ bool bDoRow = ( nHeightTwips != 0 );
+ if (bDoRow)
+ {
+ if (bWasHidden) // test hidden merge
+ {
+ bDoHidden = true;
+ bDoRow = true;
+ }
+
+ bWasHidden = false;
+ }
+ else
+ {
+ bWasHidden = true;
+ if (nY==nY2)
+ bDoRow = true; // last cell of the block
+ }
+
+ if ( bDoRow )
+ {
+ SCCOL nLoopEndX = nX2;
+ if (nX2 < nX1) // the rest of the merge
+ {
+ SCCOL nStartX = nX1;
+ while ( rDoc.GetAttr(nStartX,nY,nTab,ATTR_MERGE_FLAG)->IsHorOverlapped() )
+ --nStartX;
+ if (nStartX <= nX2)
+ nLoopEndX = nX1;
+ }
+
+ const tools::Long nHeight = bInPrintTwips ?
+ nHeightTwips : ScViewData::ToPixel(nHeightTwips, nPPTY);
+ tools::Long nEndY = nScrY + nHeight - 1;
+ tools::Long nScrX = aScrPos.X();
+ for (SCCOL nX=nX1; nX<=nLoopEndX; nX++)
+ {
+ tools::Long nWidth = rDoc.GetColWidth(nX, nTab);
+ if (!bInPrintTwips)
+ nWidth = ScViewData::ToPixel(nWidth, nPPTX);
+
+ if ( nWidth > 0 )
+ {
+ tools::Long nEndX = nScrX + ( nWidth - 1 ) * nLayoutSign;
+
+ SCROW nThisY = nY;
+ const ScPatternAttr* pPattern = rDoc.GetPattern( nX, nY, nTab );
+ const ScMergeFlagAttr* pMergeFlag = &pPattern->GetItem(ATTR_MERGE_FLAG);
+ if ( pMergeFlag->IsVerOverlapped() && ( bDoHidden || bFirstRow ) )
+ {
+ while ( pMergeFlag->IsVerOverlapped() && nThisY > 0 &&
+ (rDoc.RowHidden(nThisY-1, nTab) || bFirstRow) )
+ {
+ --nThisY;
+ pPattern = rDoc.GetPattern( nX, nThisY, nTab );
+ pMergeFlag = &pPattern->GetItem(ATTR_MERGE_FLAG);
+ }
+ }
+
+ // only the rest of the merged is seen ?
+ SCCOL nThisX = nX;
+ if ( pMergeFlag->IsHorOverlapped() && nX == nPosX && nX > nRealX1 )
+ {
+ while ( pMergeFlag->IsHorOverlapped() )
+ {
+ --nThisX;
+ pPattern = rDoc.GetPattern( nThisX, nThisY, nTab );
+ pMergeFlag = &pPattern->GetItem(ATTR_MERGE_FLAG);
+ }
+ }
+
+ if ( aMultiMark.IsCellMarked( nThisX, nThisY, true ) )
+ {
+ if ( !pMergeFlag->IsOverlapped() )
+ {
+ const ScMergeAttr* pMerge = &pPattern->GetItem(ATTR_MERGE);
+ if (pMerge->GetColMerge() > 0 || pMerge->GetRowMerge() > 0)
+ {
+ const SCCOL nEndColMerge = nThisX + pMerge->GetColMerge();
+ const SCROW nEndRowMerge = nThisY + pMerge->GetRowMerge();
+ Point aEndPos = bInPrintTwips ?
+ mrViewData.GetPrintTwipsPos(nEndColMerge, nEndRowMerge) :
+ mrViewData.GetScrPos(nEndColMerge, nEndRowMerge, eWhich);
+ if ( aEndPos.X() * nLayoutSign > nScrX * nLayoutSign && aEndPos.Y() > nScrY )
+ {
+ aInvert.AddRect( tools::Rectangle( nScrX,nScrY,
+ aEndPos.X()-nLayoutSign,aEndPos.Y()-1 ) );
+ }
+ }
+ else if ( nEndX * nLayoutSign >= nScrX * nLayoutSign && nEndY >= nScrY )
+ {
+ aInvert.AddRect( tools::Rectangle( nScrX,nScrY,nEndX,nEndY ) );
+ }
+ }
+ }
+
+ nScrX = nEndX + nLayoutSign;
+ }
+ }
+ nScrY = nEndY + 1;
+ }
+ }
+}
+
+void ScGridWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged(rDCEvt);
+
+ 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::FONTS && eWhich == mrViewData.GetActivePart() )
+ mrViewData.GetDocShell()->UpdateFontList();
+
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ if ( eWhich == mrViewData.GetActivePart() ) // only once for the view
+ {
+ ScTabView* pView = mrViewData.GetView();
+
+ pView->RecalcPPT();
+
+ // RepeatResize in case scroll bar sizes have changed
+ pView->RepeatResize();
+ pView->UpdateAllOverlays();
+
+ // invalidate cell attribs in input handler, in case the
+ // EditEngine BackgroundColor has to be changed
+ if ( mrViewData.IsActive() )
+ {
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if (pHdl)
+ pHdl->ForgetLastPattern();
+ }
+ }
+ }
+
+ Invalidate();
+}
+
+void ScGridWindow::initiatePageBreaks()
+{
+ bInitialPageBreaks = true;
+}
+
+IMPL_LINK(ScGridWindow, InitiatePageBreaksTimer, Timer*, pTimer, void)
+{
+ if (pTimer != &maShowPageBreaksTimer)
+ return;
+
+ const ScViewOptions& rOpts = mrViewData.GetOptions();
+ const bool bPage = rOpts.GetOption(VOPT_PAGEBREAKS);
+ // tdf#124983, if option LibreOfficeDev Calc/View/Visual Aids/Page
+ // breaks is enabled, breaks should be visible. If the document is
+ // opened the first time or a tab is activated the first time, the
+ // breaks are not calculated yet, so this initialization is done here.
+ if (bPage)
+ {
+ const SCTAB nCurrentTab = mrViewData.GetTabNo();
+ ScDocument& rDoc = mrViewData.GetDocument();
+ const Size aPageSize = rDoc.GetPageSize(nCurrentTab);
+ // Do not attempt to calculate a page size here if it is empty if
+ // that involves counting pages.
+ // An earlier implementation did
+ // ScPrintFunc(pDocSh, pDocSh->GetPrinter(), nCurrentTab);
+ // rDoc.SetPageSize(nCurrentTab, rDoc.GetPageSize(nCurrentTab));
+ // which resulted in tremendous waiting times after having loaded
+ // larger documents i.e. imported from CSV, in which UI is entirely
+ // blocked. All time is spent under ScPrintFunc::CountPages() in
+ // ScTable::ExtendPrintArea() in the loop that calls
+ // MaybeAddExtraColumn() to do stuff for each text string content
+ // cell (each row in each column). Maybe that can be optimized, or
+ // obtaining page size without that overhead would be possible, but
+ // as is calling that from here is a no-no so this is a quick
+ // disable things.
+ if (!aPageSize.IsEmpty())
+ {
+ ScDocShell* pDocSh = mrViewData.GetDocShell();
+ const bool bModified = pDocSh->IsModified();
+ // Even setting the same size sets page size valid, so
+ // UpdatePageBreaks() actually does something.
+ rDoc.SetPageSize( nCurrentTab, aPageSize);
+ rDoc.UpdatePageBreaks(nCurrentTab);
+ pDocSh->PostPaint(0, 0, nCurrentTab, rDoc.MaxCol(), rDoc.MaxRow(), nCurrentTab, PaintPartFlags::Grid);
+ pDocSh->SetModified(bModified);
+ }
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/gridwin5.cxx b/sc/source/ui/view/gridwin5.cxx
new file mode 100644
index 000000000..ffa6569ac
--- /dev/null
+++ b/sc/source/ui/view/gridwin5.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 <editeng/flditem.hxx>
+
+#include <svx/fmpage.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <vcl/imapobj.hxx>
+#include <vcl/help.hxx>
+#include <tools/urlobj.hxx>
+#include <sfx2/sfxhelp.hxx>
+
+#include <AccessibleDocument.hxx>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+
+#include <gridwin.hxx>
+#include <viewdata.hxx>
+#include <drawview.hxx>
+#include <drwlayer.hxx>
+#include <document.hxx>
+#include <notemark.hxx>
+#include <chgtrack.hxx>
+#include <chgviset.hxx>
+#include <dbfunc.hxx>
+#include <postit.hxx>
+#include <global.hxx>
+
+bool ScGridWindow::ShowNoteMarker( SCCOL nPosX, SCROW nPosY, bool bKeyboard )
+{
+ bool bDone = false;
+
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ ScAddress aCellPos( nPosX, nPosY, nTab );
+
+ OUString aTrackText;
+ bool bLeftEdge = false;
+
+ // change tracking
+
+ ScChangeTrack* pTrack = rDoc.GetChangeTrack();
+ ScChangeViewSettings* pSettings = rDoc.GetChangeViewSettings();
+ if ( pTrack && pTrack->GetFirst() && pSettings && pSettings->ShowChanges())
+ {
+ const ScChangeAction* pFound = nullptr;
+ const ScChangeAction* pFoundContent = nullptr;
+ const ScChangeAction* pFoundMove = nullptr;
+ const ScChangeAction* pAction = pTrack->GetFirst();
+ while (pAction)
+ {
+ if ( pAction->IsVisible() &&
+ ScViewUtil::IsActionShown( *pAction, *pSettings, rDoc ) )
+ {
+ ScChangeActionType eType = pAction->GetType();
+ const ScBigRange& rBig = pAction->GetBigRange();
+ if ( rBig.aStart.Tab() == nTab )
+ {
+ ScRange aRange = rBig.MakeRange( rDoc );
+
+ if ( eType == SC_CAT_DELETE_ROWS )
+ aRange.aEnd.SetRow( aRange.aStart.Row() );
+ else if ( eType == SC_CAT_DELETE_COLS )
+ aRange.aEnd.SetCol( aRange.aStart.Col() );
+
+ if ( aRange.Contains( aCellPos ) )
+ {
+ pFound = pAction; // the last one wins
+ switch ( eType )
+ {
+ case SC_CAT_CONTENT :
+ pFoundContent = pAction;
+ break;
+ case SC_CAT_MOVE :
+ pFoundMove = pAction;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+ }
+ if ( eType == SC_CAT_MOVE )
+ {
+ ScRange aRange =
+ static_cast<const ScChangeActionMove*>(pAction)->
+ GetFromRange().MakeRange( rDoc );
+ if ( aRange.Contains( aCellPos ) )
+ {
+ pFound = pAction;
+ }
+ }
+ }
+ pAction = pAction->GetNext();
+ }
+
+ if ( pFound )
+ {
+ if ( pFoundContent && pFound->GetType() != SC_CAT_CONTENT )
+ pFound = pFoundContent; // content wins
+ if ( pFoundMove && pFound->GetType() != SC_CAT_MOVE &&
+ pFoundMove->GetActionNumber() >
+ pFound->GetActionNumber() )
+ pFound = pFoundMove; // move wins
+
+ // for deleted columns: Arrow on the left side of the cell
+ if ( pFound->GetType() == SC_CAT_DELETE_COLS )
+ bLeftEdge = true;
+
+ DateTime aDT = pFound->GetDateTime();
+ aTrackText = pFound->GetUser()
+ + ", "
+ + ScGlobal::getLocaleData().getDate(aDT)
+ + " "
+ + ScGlobal::getLocaleData().getTime(aDT)
+ + ":\n";
+ OUString aComStr=pFound->GetComment();
+ if(!aComStr.isEmpty())
+ {
+ aTrackText += aComStr + "\n( ";
+ }
+ OUString aTmp = pFound->GetDescription(rDoc);
+ aTrackText += aTmp;
+ if(!aComStr.isEmpty())
+ {
+ aTrackText += ")";
+ }
+ }
+ }
+
+ // Note, only if it is not already displayed on the Drawing Layer:
+ const ScPostIt* pNote = rDoc.GetNote( aCellPos );
+ if ( (!aTrackText.isEmpty()) || (pNote && !pNote->IsCaptionShown()) )
+ {
+ bool bNew = true;
+ bool bFast = false;
+ if (mpNoteMarker) // A note already shown
+ {
+ if (mpNoteMarker->GetDocPos() == aCellPos)
+ bNew = false; // then stop
+ else
+ bFast = true; // otherwise, at once
+
+ // marker which was shown for ctrl-F1 isn't removed by mouse events
+ if (mpNoteMarker->IsByKeyboard() && !bKeyboard)
+ bNew = false;
+ }
+ if (bNew)
+ {
+ if (bKeyboard)
+ bFast = true; // keyboard also shows the marker immediately
+
+ mpNoteMarker.reset();
+
+ bool bHSplit = mrViewData.GetHSplitMode() != SC_SPLIT_NONE;
+ bool bVSplit = mrViewData.GetVSplitMode() != SC_SPLIT_NONE;
+
+ vcl::Window* pLeft = mrViewData.GetView()->GetWindowByPos( bVSplit ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT );
+ vcl::Window* pRight = bHSplit ? mrViewData.GetView()->GetWindowByPos( bVSplit ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT ) : nullptr;
+ vcl::Window* pBottom = bVSplit ? mrViewData.GetView()->GetWindowByPos( SC_SPLIT_BOTTOMLEFT ) : nullptr;
+ vcl::Window* pDiagonal = (bHSplit && bVSplit) ? mrViewData.GetView()->GetWindowByPos( SC_SPLIT_BOTTOMRIGHT ) : nullptr;
+ OSL_ENSURE( pLeft, "ScGridWindow::ShowNoteMarker - missing top-left grid window" );
+
+ /* If caption is shown from right or bottom windows, adjust
+ mapmode to include size of top-left window. */
+ MapMode aMapMode = GetDrawMapMode( true );
+ Size aLeftSize = pLeft->PixelToLogic( pLeft->GetOutputSizePixel(), aMapMode );
+ Point aOrigin = aMapMode.GetOrigin();
+ if( (this == pRight) || (this == pDiagonal) )
+ aOrigin.AdjustX(aLeftSize.Width() );
+ if( (this == pBottom) || (this == pDiagonal) )
+ aOrigin.AdjustY(aLeftSize.Height() );
+ aMapMode.SetOrigin( aOrigin );
+
+ mpNoteMarker.reset(new ScNoteMarker(pLeft, pRight, pBottom, pDiagonal,
+ &rDoc, aCellPos, aTrackText,
+ aMapMode, bLeftEdge, bFast, bKeyboard));
+ }
+
+ bDone = true; // something is shown (old or new)
+ }
+
+ return bDone;
+}
+
+void ScGridWindow::RequestHelp(const HelpEvent& rHEvt)
+{
+ bool bDone = false;
+ bool bHelpEnabled = bool(rHEvt.GetMode() & ( HelpEventMode::BALLOON | HelpEventMode::QUICK ));
+ SdrView* pDrView = mrViewData.GetScDrawView();
+ bool bDrawTextEdit = false;
+ if (pDrView)
+ bDrawTextEdit = pDrView->IsTextEdit();
+ // notes or change tracking
+ if ( bHelpEnabled && !bDrawTextEdit )
+ {
+ Point aPosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() );
+ SCCOL nPosX;
+ SCROW nPosY;
+ mrViewData.GetPosFromPixel( aPosPixel.X(), aPosPixel.Y(), eWhich, nPosX, nPosY );
+
+ if ( ShowNoteMarker( nPosX, nPosY, false ) )
+ {
+ Window::RequestHelp( rHEvt ); // turn off old Tip/Balloon
+ bDone = true;
+ }
+ }
+
+ if (!bDone && mpNoteMarker)
+ {
+ if (mpNoteMarker->IsByKeyboard())
+ {
+ // marker which was shown for ctrl-F1 isn't removed by mouse events
+ }
+ else
+ {
+ mpNoteMarker.reset();
+ }
+ }
+
+ // Image-Map / Text-URL
+
+ if ( bHelpEnabled && !bDone && !nButtonDown ) // only without pressed button
+ {
+ OUString aHelpText;
+ tools::Rectangle aPixRect;
+ Point aPosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() );
+
+ if ( pDrView ) // URL / Image-Map
+ {
+ SdrViewEvent aVEvt;
+ MouseEvent aMEvt( aPosPixel, 1, MouseEventModifiers::NONE, MOUSE_LEFT );
+ SdrHitKind eHit = pDrView->PickAnything( aMEvt, SdrMouseEventKind::BUTTONDOWN, aVEvt );
+
+ if ( eHit != SdrHitKind::NONE && aVEvt.mpObj != nullptr )
+ {
+ // URL for IMapObject below Pointer is help text
+ if (SvxIMapInfo::GetIMapInfo(aVEvt.mpObj))
+ {
+ Point aLogicPos = PixelToLogic( aPosPixel );
+ IMapObject* pIMapObj = SvxIMapInfo::GetHitIMapObject(
+ aVEvt.mpObj, aLogicPos, GetOutDev() );
+
+ if ( pIMapObj )
+ {
+ // For image maps show the description, if available
+ aHelpText = pIMapObj->GetAltText();
+ if (aHelpText.isEmpty())
+ aHelpText = SfxHelp::GetURLHelpText(pIMapObj->GetURL());
+ aPixRect = LogicToPixel(aVEvt.mpObj->GetLogicRect());
+ }
+ }
+ // URL in shape text or at shape itself (URL in text overrides object URL)
+ if ( aHelpText.isEmpty() )
+ {
+ if( aVEvt.meEvent == SdrEventKind::ExecuteUrl )
+ {
+ aHelpText = SfxHelp::GetURLHelpText(aVEvt.mpURLField->GetURL());
+ aPixRect = LogicToPixel(aVEvt.mpObj->GetLogicRect());
+ }
+ else
+ {
+ SdrPageView* pPV = nullptr;
+ Point aMDPos = PixelToLogic( aPosPixel );
+ SdrObject* pObj = pDrView->PickObj(aMDPos, pDrView->getHitTolLog(), pPV, SdrSearchOptions::ALSOONMASTER);
+ if (pObj)
+ {
+ if ( pObj->IsGroupObject() )
+ {
+ SdrObject* pHit = pDrView->PickObj(aMDPos, pDrView->getHitTolLog(), pPV, SdrSearchOptions::DEEP);
+ if (pHit)
+ pObj = pHit;
+ }
+ // Fragments pointing into the current document need no tooltip
+ // describing the ctrl-click functionality.
+ if ( !pObj->getHyperlink().isEmpty() && !pObj->getHyperlink().startsWith("#") )
+ {
+ aPixRect = LogicToPixel(aVEvt.mpObj->GetLogicRect());
+ aHelpText = SfxHelp::GetURLHelpText(pObj->getHyperlink());
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ( aHelpText.isEmpty() ) // Text-URL
+ {
+ OUString aUrl;
+ if ( GetEditUrl( aPosPixel, nullptr, &aUrl ) )
+ {
+ aHelpText = SfxHelp::GetURLHelpText(
+ INetURLObject::decode(aUrl, INetURLObject::DecodeMechanism::Unambiguous));
+
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCCOL nPosX;
+ SCROW nPosY;
+ SCTAB nTab = mrViewData.GetTabNo();
+ mrViewData.GetPosFromPixel( aPosPixel.X(), aPosPixel.Y(), eWhich, nPosX, nPosY );
+ const ScPatternAttr* pPattern = rDoc.GetPattern( nPosX, nPosY, nTab );
+
+ // bForceToTop = sal_False, use the cell's real position
+ aPixRect = mrViewData.GetEditArea( eWhich, nPosX, nPosY, this, pPattern, false );
+ }
+ }
+
+ if ( !aHelpText.isEmpty() )
+ {
+ tools::Rectangle aScreenRect(OutputToScreenPixel(aPixRect.TopLeft()),
+ OutputToScreenPixel(aPixRect.BottomRight()));
+
+ if ( rHEvt.GetMode() & HelpEventMode::BALLOON )
+ Help::ShowBalloon(this,rHEvt.GetMousePosPixel(), aScreenRect, aHelpText);
+ else if ( rHEvt.GetMode() & HelpEventMode::QUICK )
+ Help::ShowQuickHelp(this,aScreenRect, aHelpText);
+
+ bDone = true;
+ }
+ }
+
+ // basic controls
+
+ if ( pDrView && bHelpEnabled && !bDone )
+ {
+ SdrPageView* pPV = pDrView->GetSdrPageView();
+ OSL_ENSURE( pPV, "SdrPageView* is NULL" );
+ if (pPV)
+ bDone = FmFormPage::RequestHelp( this, pDrView, rHEvt );
+ }
+
+ // If QuickHelp for AutoFill is shown, do not allow it to be removed
+
+ if ( nMouseStatus == SC_GM_TABDOWN && mrViewData.GetRefType() == SC_REFTYPE_FILL &&
+ Help::IsQuickHelpEnabled() )
+ bDone = true;
+
+ if (!bDone)
+ Window::RequestHelp( rHEvt );
+}
+
+bool ScGridWindow::IsMyModel(const SdrEditView* pSdrView)
+{
+ return pSdrView &&
+ pSdrView->GetModel() == mrViewData.GetDocument().GetDrawLayer();
+}
+
+void ScGridWindow::HideNoteMarker()
+{
+ mpNoteMarker.reset();
+}
+
+css::uno::Reference< css::accessibility::XAccessible >
+ ScGridWindow::CreateAccessible()
+{
+ css::uno::Reference< css::accessibility::XAccessible > xAcc= GetAccessible(false);
+ if (xAcc.is())
+ {
+ return xAcc;
+ }
+
+ rtl::Reference<ScAccessibleDocument> pAccessibleDocument =
+ new ScAccessibleDocument(GetAccessibleParentWindow()->GetAccessible(),
+ mrViewData.GetViewShell(), eWhich);
+ pAccessibleDocument->PreInit();
+
+ xAcc = pAccessibleDocument;
+ SetAccessible(xAcc);
+
+ pAccessibleDocument->Init();
+
+ return xAcc;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/gridwin_dbgutil.cxx b/sc/source/ui/view/gridwin_dbgutil.cxx
new file mode 100644
index 000000000..b141bddd7
--- /dev/null
+++ b/sc/source/ui/view/gridwin_dbgutil.cxx
@@ -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/.
+ */
+
+#include <iostream>
+
+#include <gridwin.hxx>
+#include <svx/svdpage.hxx>
+#include <libxml/xmlwriter.h>
+#include <viewdata.hxx>
+#include <document.hxx>
+#include <patattr.hxx>
+#include <userdat.hxx>
+#include <dpobject.hxx>
+
+namespace {
+
+std::ostream& operator<<(std::ostream& rStrm, const ScAddress& rAddr)
+{
+ rStrm << "Col: " << rAddr.Col() << ", Row: " << rAddr.Row() << ", Tab: " << rAddr.Tab();
+ return rStrm;
+}
+
+void dumpScDrawObjData(const ScGridWindow& rWindow, const ScDrawObjData& rData, MapUnit eMapUnit)
+{
+ const Point& rStartOffset = rData.maStartOffset;
+ Point aStartOffsetPixel = rWindow.LogicToPixel(rStartOffset, MapMode(eMapUnit));
+ std::cout << " Start: " << rData.maStart << ", Offset: " << aStartOffsetPixel << std::endl;
+
+ const Point& rEndOffset = rData.maEndOffset;
+ Point aEndOffsetPixel = rWindow.LogicToPixel(rEndOffset, MapMode(eMapUnit));
+ std::cout << " End: : " << rData.maEnd << ", Offset: " << aEndOffsetPixel << std::endl;
+}
+
+}
+
+void ScGridWindow::dumpColumnInformationPixel()
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ for (SCCOL nCol = 0; nCol <= 20; ++nCol)
+ {
+ sal_uInt16 nWidth = rDoc.GetColWidth(nCol, nTab);
+ tools::Long nPixel = LogicToPixel(Point(nWidth, 0), MapMode(MapUnit::MapTwip)).getX();
+ std::cout << "Column: " << nCol << ", Width: " << nPixel << "px" << std::endl;
+ }
+}
+
+void ScGridWindow::dumpColumnInformationHmm()
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ SCTAB nTab = mrViewData.GetTabNo();
+ for (SCCOL nCol = 0; nCol <= 20; ++nCol)
+ {
+ sal_uInt16 nWidth = rDoc.GetColWidth(nCol, nTab);
+ tools::Long nPixel = o3tl::convert(nWidth, o3tl::Length::twip, o3tl::Length::mm100);
+ std::cout << "Column: " << nCol << ", Width: " << nPixel << "hmm" << std::endl;
+ }
+}
+
+void ScGridWindow::dumpCellProperties()
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ const ScMarkData& rMark = mrViewData.GetMarkData();
+ SCTAB nTab = mrViewData.GetTabNo();
+
+ ScRangeList aList;
+ if (rMark.IsMultiMarked())
+ {
+ aList = rMark.GetMarkedRangesForTab(nTab);
+ }
+ else if (rMark.IsMarked())
+ {
+ aList.Join(rMark.GetMarkArea());
+ }
+ else
+ {
+ SCCOL nCol = mrViewData.GetCurX();
+ SCROW nRow = mrViewData.GetCurY();
+
+ ScRange aRange(nCol, nRow, nTab);
+ aList.Join(aRange, false);
+ }
+
+ xmlTextWriterPtr writer = xmlNewTextWriterFilename( "dump.xml", 0 );
+ xmlTextWriterSetIndent(writer,1);
+ (void)xmlTextWriterSetIndentString(writer, BAD_CAST(" "));
+
+ (void)xmlTextWriterStartDocument( writer, nullptr, nullptr, nullptr );
+
+ (void)xmlTextWriterStartElement(writer, BAD_CAST("selection"));
+
+ for (size_t i = 0, n = aList.size(); i < n; ++i)
+ {
+ ScRange const & rRange = aList[i];
+
+ for (SCCOL nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); ++nCol)
+ {
+ for (SCROW nRow = rRange.aStart.Row(); nRow <= rRange.aEnd.Row(); ++nRow)
+ {
+ const ScPatternAttr* pPatternAttr = rDoc.GetPattern(nCol, nRow, nTab);
+ (void)xmlTextWriterStartElement(writer, BAD_CAST("cell"));
+ (void)xmlTextWriterWriteAttribute(writer, BAD_CAST("column"), BAD_CAST(OString::number(nCol).getStr()));
+ (void)xmlTextWriterWriteAttribute(writer, BAD_CAST("row"), BAD_CAST(OString::number(nRow).getStr()));
+ (void)xmlTextWriterWriteAttribute(writer, BAD_CAST("tab"), BAD_CAST(OString::number(nTab).getStr()));
+
+ pPatternAttr->GetItemSet().dumpAsXml(writer);
+
+ (void)xmlTextWriterEndElement(writer);
+ }
+ }
+ }
+
+ (void)xmlTextWriterEndElement(writer);
+
+ (void)xmlTextWriterEndDocument( writer );
+ xmlFreeTextWriter (writer);
+}
+
+void ScGridWindow::dumpGraphicInformation()
+{
+ ScDocument& rDoc = mrViewData.GetDocument();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ if (!pDrawLayer)
+ return;
+
+ sal_uInt16 nPageCount = pDrawLayer->GetPageCount();
+ for (sal_uInt16 nPage = 0; nPage < nPageCount; ++nPage)
+ {
+ SdrPage* pPage = pDrawLayer->GetPage(nPage);
+ size_t nObjCount = pPage->GetObjCount();
+ for (size_t nObj = 0; nObj < nObjCount; ++nObj)
+ {
+ SdrObject* pObj = pPage->GetObj(nObj);
+ std::cout << "Graphic Object" << std::endl;
+ ScDrawObjData* pObjData = ScDrawLayer::GetObjData(pObj);
+ if (pObjData)
+ dumpScDrawObjData(*this, *pObjData, pDrawLayer->GetScaleUnit());
+
+ const tools::Rectangle& rRect = pObj->GetSnapRect();
+ tools::Rectangle aRect = LogicToPixel(rRect, MapMode(pDrawLayer->GetScaleUnit()));
+ std::cout << "Snap Rectangle (in pixel): " << aRect << std::endl;
+ }
+ }
+}
+
+void ScGridWindow::dumpColumnCellStorage()
+{
+ // Get the current cursor position.
+ ScAddress aCurPos = mrViewData.GetCurPos();
+
+ ScDocument& rDoc = mrViewData.GetDocument();
+ const ScDPObject* pDP = rDoc.GetDPAtCursor(aCurPos.Col(), aCurPos.Row(), aCurPos.Tab());
+ if (pDP)
+ {
+ // Dump the pivot table info if the cursor is over a pivot table.
+ pDP->Dump();
+ pDP->DumpCache();
+ return;
+ }
+
+ // Dump the column cell storage info.
+ rDoc.DumpColumnStorage(aCurPos.Tab(), aCurPos.Col());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/hdrcont.cxx b/sc/source/ui/view/hdrcont.cxx
new file mode 100644
index 000000000..f2799b644
--- /dev/null
+++ b/sc/source/ui/view/hdrcont.cxx
@@ -0,0 +1,1123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <vcl/commandevent.hxx>
+#include <vcl/help.hxx>
+#include <vcl/settings.hxx>
+#include <svtools/colorcfg.hxx>
+#include <osl/diagnose.h>
+
+#include <tabvwsh.hxx>
+#include <hdrcont.hxx>
+#include <dbdata.hxx>
+#include <scmod.hxx>
+#include <inputopt.hxx>
+#include <gridmerg.hxx>
+#include <document.hxx>
+#include <markdata.hxx>
+#include <tabview.hxx>
+#include <viewdata.hxx>
+#include <columnspanset.hxx>
+
+#define SC_DRAG_MIN 2
+
+// passes in paint
+// (selection left/right must be first because the continuous lines
+// are partly overwritten later)
+
+#define SC_HDRPAINT_SEL_BOTTOM 4
+#define SC_HDRPAINT_BOTTOM 5
+#define SC_HDRPAINT_TEXT 6
+#define SC_HDRPAINT_COUNT 7
+
+ScHeaderControl::ScHeaderControl( vcl::Window* pParent, SelectionEngine* pSelectionEngine,
+ SCCOLROW nNewSize, bool bNewVertical, ScTabView* pTab ) :
+ Window ( pParent ),
+ pSelEngine ( pSelectionEngine ),
+ aShowHelpTimer("sc HeaderControl Popover Timer"),
+ bVertical ( bNewVertical ),
+ nSize ( nNewSize ),
+ nMarkStart ( 0 ),
+ nMarkEnd ( 0 ),
+ bMarkRange ( false ),
+ bDragging ( false ),
+ nDragNo ( 0 ),
+ nDragStart ( 0 ),
+ nDragPos ( 0 ),
+ nTipVisible ( nullptr ),
+ bDragMoved ( false ),
+ bIgnoreMove ( false ),
+ bInRefMode ( false ),
+ pTabView ( pTab )
+{
+ // RTL: no default mirroring for this window, the spreadsheet itself
+ // is also not mirrored
+ // mirror the vertical window for correct border drawing
+ // table layout depends on sheet format, not UI setting, so the
+ // borders of the vertical window have to be handled manually, too.
+ EnableRTL( false );
+
+ aNormFont = GetFont();
+ aNormFont.SetTransparent( true ); //! hard-set WEIGHT_NORMAL ???
+ aBoldFont = aNormFont;
+ aBoldFont.SetWeight( WEIGHT_BOLD );
+ aAutoFilterFont = aNormFont;
+
+ SetFont(aBoldFont);
+ bBoldSet = true;
+ bAutoFilterSet = false;
+
+ Size aSize = LogicToPixel( Size(
+ GetTextWidth("8888"),
+ GetTextHeight() ) );
+ aSize.AdjustWidth(4 ); // place for highlight border
+ aSize.AdjustHeight(3 );
+ SetSizePixel( aSize );
+
+ nWidth = nSmallWidth = aSize.Width();
+ nBigWidth = LogicToPixel( Size( GetTextWidth("8888888"), 0 ) ).Width() + 5;
+
+ aShowHelpTimer.SetInvokeHandler(LINK(this, ScHeaderControl, ShowDragHelpHdl));
+ aShowHelpTimer.SetTimeout(GetSettings().GetMouseSettings().GetDoubleClickTime());
+
+ SetBackground();
+}
+
+void ScHeaderControl::dispose()
+{
+ aShowHelpTimer.Stop();
+ vcl::Window::dispose();
+}
+
+void ScHeaderControl::SetWidth( tools::Long nNew )
+{
+ OSL_ENSURE( bVertical, "SetWidth works only on row headers" );
+ if ( nNew != nWidth )
+ {
+ Size aSize( nNew, GetSizePixel().Height() );
+ SetSizePixel( aSize );
+
+ nWidth = nNew;
+
+ Invalidate();
+ }
+}
+
+ScHeaderControl::~ScHeaderControl()
+{
+}
+
+void ScHeaderControl::DoPaint( SCCOLROW nStart, SCCOLROW nEnd )
+{
+ bool bLayoutRTL = IsLayoutRTL();
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ tools::Rectangle aRect( Point(0,0), GetOutputSizePixel() );
+ if ( bVertical )
+ {
+ aRect.SetTop( GetScrPos( nStart )-nLayoutSign ); // extra pixel for line at top of selection
+ aRect.SetBottom( GetScrPos( nEnd+1 )-nLayoutSign );
+ }
+ else
+ {
+ aRect.SetLeft( GetScrPos( nStart )-nLayoutSign ); // extra pixel for line left of selection
+ aRect.SetRight( GetScrPos( nEnd+1 )-nLayoutSign );
+ }
+ Invalidate(aRect);
+}
+
+void ScHeaderControl::SetMark( bool bNewSet, SCCOLROW nNewStart, SCCOLROW nNewEnd )
+{
+ bool bEnabled = SC_MOD()->GetInputOptions().GetMarkHeader(); //! cache?
+ if (!bEnabled)
+ bNewSet = false;
+
+ bool bOldSet = bMarkRange;
+ SCCOLROW nOldStart = nMarkStart;
+ SCCOLROW nOldEnd = nMarkEnd;
+ PutInOrder( nNewStart, nNewEnd );
+ bMarkRange = bNewSet;
+ nMarkStart = nNewStart;
+ nMarkEnd = nNewEnd;
+
+ // Paint
+
+ if ( bNewSet )
+ {
+ if ( bOldSet )
+ {
+ if ( nNewStart == nOldStart )
+ {
+ if ( nNewEnd != nOldEnd )
+ DoPaint( std::min( nNewEnd, nOldEnd ) + 1, std::max( nNewEnd, nOldEnd ) );
+ }
+ else if ( nNewEnd == nOldEnd )
+ DoPaint( std::min( nNewStart, nOldStart ), std::max( nNewStart, nOldStart ) - 1 );
+ else if ( nNewStart > nOldEnd || nNewEnd < nOldStart )
+ {
+ // two areas
+ DoPaint( nOldStart, nOldEnd );
+ DoPaint( nNewStart, nNewEnd );
+ }
+ else // somehow overlapping... (it is not often)
+ DoPaint( std::min( nNewStart, nOldStart ), std::max( nNewEnd, nOldEnd ) );
+ }
+ else
+ DoPaint( nNewStart, nNewEnd ); // completely new selection
+ }
+ else if ( bOldSet )
+ DoPaint( nOldStart, nOldEnd ); // cancel selection
+}
+
+tools::Long ScHeaderControl::GetScrPos( SCCOLROW nEntryNo ) const
+{
+ tools::Long nScrPos;
+
+ tools::Long nMax = ( bVertical ? GetOutputSizePixel().Height() : GetOutputSizePixel().Width() ) + 1;
+ if (nEntryNo >= nSize)
+ nScrPos = nMax;
+ else
+ {
+ nScrPos = 0;
+ for (SCCOLROW i=GetPos(); i<nEntryNo && nScrPos<nMax; i++)
+ {
+ sal_uInt16 nAdd = GetEntrySize(i);
+ if (nAdd)
+ nScrPos += nAdd;
+ else
+ {
+ SCCOLROW nHidden = GetHiddenCount(i);
+ if (nHidden > 0)
+ i += nHidden - 1;
+ }
+ }
+ }
+
+ if ( IsLayoutRTL() )
+ nScrPos = nMax - nScrPos - 2;
+
+ return nScrPos;
+}
+
+void ScHeaderControl::Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect )
+{
+ // It is important for VCL to have few calls, that is why the outer lines are
+ // grouped together
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ bool bHighContrast = rStyleSettings.GetHighContrastMode();
+ bool bDark = rStyleSettings.GetFaceColor().IsDark();
+ // Use the same distinction for bDark as in Window::DrawSelectionBackground
+
+ Color aTextColor = rStyleSettings.GetButtonTextColor();
+ Color aSelTextColor = rStyleSettings.GetHighlightTextColor();
+ Color aAFilterTextColor = rStyleSettings.GetButtonTextColor();
+ aAFilterTextColor.Merge(COL_LIGHTBLUE, bDark ? 150 : 10); // color of filtered row numbers
+ aNormFont.SetColor( aTextColor );
+ aAutoFilterFont.SetColor(aAFilterTextColor);
+ if ( bHighContrast )
+ aBoldFont.SetColor( aTextColor );
+ else
+ aBoldFont.SetColor( aSelTextColor );
+
+ if (bAutoFilterSet)
+ SetTextColor(aAFilterTextColor);
+ else
+ SetTextColor((bBoldSet && !bHighContrast) ? aSelTextColor : aTextColor);
+
+ Color aSelLineColor = rStyleSettings.GetHighlightColor();
+ aSelLineColor.Merge( COL_BLACK, 0xe0 ); // darken just a little bit
+
+ bool bLayoutRTL = IsLayoutRTL();
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+ bool bMirrored = IsMirrored();
+
+ OUString aString;
+ sal_uInt16 nBarSize;
+ Point aScrPos;
+ Size aTextSize;
+
+ if (bVertical)
+ nBarSize = static_cast<sal_uInt16>(GetSizePixel().Width());
+ else
+ nBarSize = static_cast<sal_uInt16>(GetSizePixel().Height());
+
+ SCCOLROW nPos = GetPos();
+
+ tools::Long nPStart = bVertical ? rRect.Top() : rRect.Left();
+ tools::Long nPEnd = bVertical ? rRect.Bottom() : rRect.Right();
+
+ tools::Long nTransStart = nPEnd + 1;
+ tools::Long nTransEnd = 0;
+
+ tools::Long nInitScrPos = 0;
+ if ( bLayoutRTL )
+ {
+ tools::Long nTemp = nPStart; // swap nPStart / nPEnd
+ nPStart = nPEnd;
+ nPEnd = nTemp;
+ nTemp = nTransStart; // swap nTransStart / nTransEnd
+ nTransStart = nTransEnd;
+ nTransEnd = nTemp;
+ if ( bVertical ) // start loops from the end
+ nInitScrPos = GetSizePixel().Height() - 1;
+ else
+ nInitScrPos = GetSizePixel().Width() - 1;
+ }
+
+ // complete the painting of the outer lines
+ // first find the end of the last cell
+
+ tools::Long nLineEnd = nInitScrPos - nLayoutSign;
+
+ for (SCCOLROW i=nPos; i<nSize; i++)
+ {
+ sal_uInt16 nSizePix = GetEntrySize( i );
+ if (nSizePix)
+ {
+ nLineEnd += nSizePix * nLayoutSign;
+
+ if ( bMarkRange && i >= nMarkStart && i <= nMarkEnd )
+ {
+ tools::Long nLineStart = nLineEnd - ( nSizePix - 1 ) * nLayoutSign;
+ if ( nLineStart * nLayoutSign < nTransStart * nLayoutSign )
+ nTransStart = nLineStart;
+ if ( nLineEnd * nLayoutSign > nTransEnd * nLayoutSign )
+ nTransEnd = nLineEnd;
+ }
+
+ if ( nLineEnd * nLayoutSign > nPEnd * nLayoutSign )
+ {
+ nLineEnd = nPEnd;
+ break;
+ }
+ }
+ else
+ {
+ SCCOLROW nHidden = GetHiddenCount(i);
+ if (nHidden > 0)
+ i += nHidden - 1;
+ }
+ }
+
+ // background is different for entry area and behind the entries
+
+ tools::Rectangle aFillRect;
+ GetOutDev()->SetLineColor();
+
+ if ( nLineEnd * nLayoutSign >= nInitScrPos * nLayoutSign )
+ {
+ GetOutDev()->SetFillColor( rStyleSettings.GetFaceColor() );
+ if ( bVertical )
+ aFillRect = tools::Rectangle( 0, nInitScrPos, nBarSize-1, nLineEnd );
+ else
+ aFillRect = tools::Rectangle( nInitScrPos, 0, nLineEnd, nBarSize-1 );
+ GetOutDev()->DrawRect( aFillRect );
+ }
+
+ if ( nLineEnd * nLayoutSign < nPEnd * nLayoutSign )
+ {
+ GetOutDev()->SetFillColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::APPBACKGROUND).nColor );
+ if ( bVertical )
+ aFillRect = tools::Rectangle( 0, nLineEnd+nLayoutSign, nBarSize-1, nPEnd );
+ else
+ aFillRect = tools::Rectangle( nLineEnd+nLayoutSign, 0, nPEnd, nBarSize-1 );
+ GetOutDev()->DrawRect( aFillRect );
+ }
+
+ if ( nLineEnd * nLayoutSign >= nPStart * nLayoutSign )
+ {
+ if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign )
+ {
+ if (bVertical)
+ aFillRect = tools::Rectangle( 0, nTransStart, nBarSize-1, nTransEnd );
+ else
+ aFillRect = tools::Rectangle( nTransStart, 0, nTransEnd, nBarSize-1 );
+
+ if ( bHighContrast )
+ {
+ if ( bDark )
+ {
+ // solid grey background for dark face color is drawn before lines
+ GetOutDev()->SetLineColor();
+ GetOutDev()->SetFillColor( COL_LIGHTGRAY );
+ GetOutDev()->DrawRect( aFillRect );
+ }
+ }
+ else
+ {
+ // background for selection
+ GetOutDev()->SetLineColor();
+ GetOutDev()->SetFillColor( rStyleSettings.GetHighlightColor() );
+ GetOutDev()->DrawRect( aFillRect );
+ }
+ }
+
+ GetOutDev()->SetLineColor( rStyleSettings.GetDarkShadowColor() );
+ if (bVertical)
+ {
+ tools::Long nDarkPos = bMirrored ? 0 : nBarSize-1;
+ GetOutDev()->DrawLine( Point( nDarkPos, nPStart ), Point( nDarkPos, nLineEnd ) );
+ }
+ else
+ GetOutDev()->DrawLine( Point( nPStart, nBarSize-1 ), Point( nLineEnd, nBarSize-1 ) );
+
+ // line in different color for selection
+ if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign && !bHighContrast )
+ {
+ GetOutDev()->SetLineColor( aSelLineColor );
+ if (bVertical)
+ {
+ tools::Long nDarkPos = bMirrored ? 0 : nBarSize-1;
+ GetOutDev()->DrawLine( Point( nDarkPos, nTransStart ), Point( nDarkPos, nTransEnd ) );
+ }
+ else
+ GetOutDev()->DrawLine( Point( nTransStart, nBarSize-1 ), Point( nTransEnd, nBarSize-1 ) );
+ }
+ }
+
+ // tdf#89841 Use blue row numbers when Autofilter selected
+ std::vector<sc::ColRowSpan> aSpans;
+ if (bVertical && pTabView)
+ {
+ SCTAB nTab = pTabView->GetViewData().GetTabNo();
+ ScDocument& rDoc = pTabView->GetViewData().GetDocument();
+
+ ScDBData* pDBData = rDoc.GetAnonymousDBData(nTab);
+ if (pDBData && pDBData->HasAutoFilter())
+ {
+ SCSIZE nSelected = 0;
+ SCSIZE nTotal = 0;
+ pDBData->GetFilterSelCount(nSelected, nTotal);
+ if (nTotal > nSelected)
+ {
+ ScRange aRange;
+ pDBData->GetArea(aRange);
+ SCCOLROW nStartRow = static_cast<SCCOLROW>(aRange.aStart.Row());
+ SCCOLROW nEndRow = static_cast<SCCOLROW>(aRange.aEnd.Row());
+ if (pDBData->HasHeader())
+ nStartRow++;
+ aSpans.push_back(sc::ColRowSpan(nStartRow, nEndRow));
+ }
+ }
+
+ ScDBCollection* pDocColl = rDoc.GetDBCollection();
+ if (!pDocColl->empty())
+ {
+ ScDBCollection::NamedDBs& rDBs = pDocColl->getNamedDBs();
+ for (const auto& rxDB : rDBs)
+ {
+ if (rxDB->GetTab() == nTab && rxDB->HasAutoFilter())
+ {
+ SCSIZE nSelected = 0;
+ SCSIZE nTotal = 0;
+ rxDB->GetFilterSelCount(nSelected, nTotal);
+ if (nTotal > nSelected)
+ {
+ ScRange aRange;
+ rxDB->GetArea(aRange);
+ SCCOLROW nStartRow = static_cast<SCCOLROW>(aRange.aStart.Row());
+ SCCOLROW nEndRow = static_cast<SCCOLROW>(aRange.aEnd.Row());
+ if (rxDB->HasHeader())
+ nStartRow++;
+ aSpans.push_back(sc::ColRowSpan(nStartRow, nEndRow));
+ }
+ }
+ }
+ }
+ }
+
+ // loop through entries several times to avoid changing the line color too often
+ // and to allow merging of lines
+
+ ScGridMerger aGrid( GetOutDev(), 1, 1 );
+
+ // start at SC_HDRPAINT_BOTTOM instead of 0 - selection doesn't get different
+ // borders, light border at top isn't used anymore
+ // use SC_HDRPAINT_SEL_BOTTOM for different color
+
+ for (sal_uInt16 nPass = SC_HDRPAINT_SEL_BOTTOM; nPass < SC_HDRPAINT_COUNT; nPass++)
+ {
+ // set line color etc. before entry loop
+ switch ( nPass )
+ {
+ case SC_HDRPAINT_SEL_BOTTOM:
+ // same as non-selected for high contrast
+ GetOutDev()->SetLineColor( bHighContrast ? rStyleSettings.GetDarkShadowColor() : aSelLineColor );
+ break;
+ case SC_HDRPAINT_BOTTOM:
+ GetOutDev()->SetLineColor( rStyleSettings.GetDarkShadowColor() );
+ break;
+ case SC_HDRPAINT_TEXT:
+ // DrawSelectionBackground is used only for high contrast on light background
+ if ( nTransEnd * nLayoutSign >= nTransStart * nLayoutSign && bHighContrast && !bDark )
+ {
+ // Transparent selection background is drawn after lines, before text.
+ // Use DrawSelectionBackground to make sure there is a visible
+ // difference. The case of a dark face color, where DrawSelectionBackground
+ // would just paint over the lines, is handled separately (bDark).
+ // Otherwise, GetHighlightColor is used with 80% transparency.
+ // The window's background color (SetBackground) has to be the background
+ // of the cell area, for the contrast comparison in DrawSelectionBackground.
+
+ tools::Rectangle aTransRect;
+ if (bVertical)
+ aTransRect = tools::Rectangle( 0, nTransStart, nBarSize-1, nTransEnd );
+ else
+ aTransRect = tools::Rectangle( nTransStart, 0, nTransEnd, nBarSize-1 );
+ SetBackground( rStyleSettings.GetFaceColor() );
+ DrawSelectionBackground( aTransRect, 0, true, false );
+ SetBackground();
+ }
+ break;
+ }
+
+ SCCOLROW nCount=0;
+ tools::Long nScrPos=nInitScrPos;
+ do
+ {
+ if (bVertical)
+ aScrPos = Point( 0, nScrPos );
+ else
+ aScrPos = Point( nScrPos, 0 );
+
+ SCCOLROW nEntryNo = nCount + nPos;
+ if ( nEntryNo >= nSize ) // rDoc.MaxCol()/rDoc.MaxRow()
+ nScrPos = nPEnd + nLayoutSign; // beyond nPEnd -> stop
+ else
+ {
+ sal_uInt16 nSizePix = GetEntrySize( nEntryNo );
+
+ if (nSizePix == 0)
+ {
+ SCCOLROW nHidden = GetHiddenCount(nEntryNo);
+ if (nHidden > 0)
+ nCount += nHidden - 1;
+ }
+ else if ((nScrPos+nSizePix*nLayoutSign)*nLayoutSign >= nPStart*nLayoutSign)
+ {
+ Point aEndPos(aScrPos);
+ if (bVertical)
+ aEndPos = Point( aScrPos.X()+nBarSize-1, aScrPos.Y()+(nSizePix-1)*nLayoutSign );
+ else
+ aEndPos = Point( aScrPos.X()+(nSizePix-1)*nLayoutSign, aScrPos.Y()+nBarSize-1 );
+
+ bool bMark = bMarkRange && nEntryNo >= nMarkStart && nEntryNo <= nMarkEnd;
+ bool bNextToMark = bMarkRange && nEntryNo + 1 >= nMarkStart && nEntryNo <= nMarkEnd;
+
+ switch ( nPass )
+ {
+ case SC_HDRPAINT_SEL_BOTTOM:
+ case SC_HDRPAINT_BOTTOM:
+ if ( nPass == ( bNextToMark ? SC_HDRPAINT_SEL_BOTTOM : SC_HDRPAINT_BOTTOM ) )
+ {
+ if (bVertical)
+ aGrid.AddHorLine(/* here we work in pixels */ true, aScrPos.X(), aEndPos.X(), aEndPos.Y());
+ else
+ aGrid.AddVerLine(/* here we work in pixels */ true, aEndPos.X(), aScrPos.Y(), aEndPos.Y());
+
+ // thick bottom for hidden rows
+ // (drawn directly, without aGrid)
+ if ( nEntryNo+1 < nSize )
+ if ( GetEntrySize(nEntryNo+1)==0 )
+ {
+ if (bVertical)
+ GetOutDev()->DrawLine( Point(aScrPos.X(),aEndPos.Y()-nLayoutSign),
+ Point(aEndPos.X(),aEndPos.Y()-nLayoutSign) );
+ else
+ GetOutDev()->DrawLine( Point(aEndPos.X()-nLayoutSign,aScrPos.Y()),
+ Point(aEndPos.X()-nLayoutSign,aEndPos.Y()) );
+ }
+ }
+ break;
+
+ case SC_HDRPAINT_TEXT:
+ if ( nSizePix > 1 ) // minimal check for small columns/rows
+ {
+ if (bVertical)
+ {
+ bool bAutoFilterPos = false;
+ for (const auto& rSpan : aSpans)
+ {
+ if (nEntryNo >= rSpan.mnStart && nEntryNo <= rSpan.mnEnd)
+ {
+ bAutoFilterPos = true;
+ break;
+ }
+ }
+
+ if (bMark != bBoldSet || bAutoFilterPos != bAutoFilterSet)
+ {
+ if (bMark)
+ SetFont(aBoldFont);
+ else if (bAutoFilterPos)
+ SetFont(aAutoFilterFont);
+ else
+ SetFont(aNormFont);
+ bBoldSet = bMark;
+ bAutoFilterSet = bAutoFilterPos && !bMark;
+ }
+ }
+ else
+ {
+ if (bMark != bBoldSet)
+ {
+ if (bMark)
+ SetFont(aBoldFont);
+ else
+ SetFont(aNormFont);
+ bBoldSet = bMark;
+ }
+ }
+
+ aString = GetEntryText( nEntryNo );
+ aTextSize.setWidth( GetTextWidth( aString ) );
+ aTextSize.setHeight( GetTextHeight() );
+
+ Point aTxtPos(aScrPos);
+ if (bVertical)
+ {
+ aTxtPos.AdjustX((nBarSize-aTextSize.Width())/2 );
+ aTxtPos.AdjustY((nSizePix*nLayoutSign-aTextSize.Height())/2 );
+ if ( bMirrored )
+ aTxtPos.AdjustX(1 ); // dark border is left instead of right
+ }
+ else
+ {
+ aTxtPos.AdjustX((nSizePix*nLayoutSign-aTextSize.Width()+1)/2 );
+ aTxtPos.AdjustY((nBarSize-aTextSize.Height())/2 );
+ }
+ GetOutDev()->DrawText( aTxtPos, aString );
+ }
+ break;
+ }
+
+ // when selecting the complete row/column:
+ // InvertRect( Rectangle( aScrPos, aEndPos ) );
+ }
+ nScrPos += nSizePix * nLayoutSign; // also if before the visible area
+ }
+ ++nCount;
+ }
+ while ( nScrPos * nLayoutSign <= nPEnd * nLayoutSign );
+
+ aGrid.Flush();
+ }
+}
+
+SCCOLROW ScHeaderControl::GetMousePos(const Point& rPos, bool& rBorder) const
+{
+ bool bFound = false;
+ SCCOLROW nPos = GetPos();
+ SCCOLROW nHitNo = nPos;
+ SCCOLROW nEntryNo = 1 + nPos;
+ tools::Long nScrPos;
+ tools::Long nMousePos = bVertical ? rPos.Y() : rPos.X();
+ tools::Long nDif;
+ Size aSize = GetOutputSizePixel();
+ tools::Long nWinSize = bVertical ? aSize.Height() : aSize.Width();
+
+ bool bLayoutRTL = IsLayoutRTL();
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+ tools::Long nEndPos = bLayoutRTL ? -1 : nWinSize;
+
+ nScrPos = GetScrPos( nPos ) - nLayoutSign;
+ do
+ {
+ if (nEntryNo > nSize)
+ nScrPos = nEndPos + nLayoutSign;
+ else
+ nScrPos += GetEntrySize( nEntryNo - 1 ) * nLayoutSign; //! GetHiddenCount() ??
+
+ nDif = nMousePos - nScrPos;
+ if (nDif >= -2 && nDif <= 2)
+ {
+ bFound = true;
+ nHitNo=nEntryNo-1;
+ }
+ else if (nDif * nLayoutSign >= 0 && nEntryNo < nSize)
+ nHitNo = nEntryNo;
+ ++nEntryNo;
+ }
+ while ( nScrPos * nLayoutSign < nEndPos * nLayoutSign && nDif * nLayoutSign > 0 );
+
+ rBorder = bFound;
+ return nHitNo;
+}
+
+bool ScHeaderControl::IsSelectionAllowed(SCCOLROW nPos) const
+{
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
+ if (!pViewSh)
+ return false;
+
+ ScViewData& rViewData = pViewSh->GetViewData();
+ sal_uInt16 nTab = rViewData.GetTabNo();
+ ScDocument& rDoc = rViewData.GetDocument();
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ bool bSelectAllowed = true;
+ if ( pProtect && pProtect->isProtected() )
+ {
+ // This sheet is protected. Check if a context menu is allowed on this cell.
+ bool bCellsProtected = false;
+ if (bVertical)
+ {
+ // row header
+ SCROW nRPos = static_cast<SCROW>(nPos);
+ bCellsProtected = rDoc.HasAttrib(0, nRPos, nTab, rDoc.MaxCol(), nRPos, nTab, HasAttrFlags::Protected);
+ }
+ else
+ {
+ // column header
+ SCCOL nCPos = static_cast<SCCOL>(nPos);
+ bCellsProtected = rDoc.HasAttrib(nCPos, 0, nTab, nCPos, rDoc.MaxRow(), nTab, HasAttrFlags::Protected);
+ }
+
+ bool bSelProtected = pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
+ bool bSelUnprotected = pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
+
+ if (bCellsProtected)
+ bSelectAllowed = bSelProtected;
+ else
+ bSelectAllowed = bSelUnprotected;
+ }
+ return bSelectAllowed;
+}
+
+void ScHeaderControl::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if (IsDisabled())
+ return;
+
+ bIgnoreMove = false;
+ SelectWindow();
+
+ bool bIsBorder;
+ SCCOLROW nHitNo = GetMousePos(rMEvt.GetPosPixel(), bIsBorder);
+ if (!IsSelectionAllowed(nHitNo))
+ return;
+ if ( ! rMEvt.IsLeft() )
+ return;
+ if ( SC_MOD()->IsFormulaMode() )
+ {
+ if( !pTabView )
+ return;
+ SCTAB nTab = pTabView->GetViewData().GetTabNo();
+ if( !rMEvt.IsShift() )
+ pTabView->DoneRefMode( rMEvt.IsMod1() );
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
+ ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
+ if( !bVertical )
+ {
+ pTabView->InitRefMode( nHitNo, 0, nTab, SC_REFTYPE_REF );
+ pTabView->UpdateRef( nHitNo, rDoc.MaxRow(), nTab );
+ }
+ else
+ {
+ pTabView->InitRefMode( 0, nHitNo, nTab, SC_REFTYPE_REF );
+ pTabView->UpdateRef( rDoc.MaxCol(), nHitNo, nTab );
+ }
+ bInRefMode = true;
+ return;
+ }
+ if ( bIsBorder && ResizeAllowed() )
+ {
+ nDragNo = nHitNo;
+ sal_uInt16 nClicks = rMEvt.GetClicks();
+ if ( nClicks && nClicks%2==0 )
+ {
+ SetEntrySize( nDragNo, HDR_SIZE_OPTIMUM );
+ SetPointer( PointerStyle::Arrow );
+ }
+ else
+ {
+ if (bVertical)
+ nDragStart = rMEvt.GetPosPixel().Y();
+ else
+ nDragStart = rMEvt.GetPosPixel().X();
+ nDragPos = nDragStart;
+ // tdf#140833 launch help tip to show after the double click time has expired
+ // so under gtk the popover isn't active when the double click is processed
+ // by gtk because under load on wayland the double click is getting handled
+ // by something else and getting sent to the window underneath our window
+ aShowHelpTimer.Start();
+ DrawInvert( nDragPos );
+
+ StartTracking();
+ bDragging = true;
+ bDragMoved = false;
+ }
+ }
+ else
+ {
+ pSelEngine->SetWindow( this );
+ tools::Rectangle aVis( Point(), GetOutputSizePixel() );
+ if (bVertical)
+ {
+ aVis.SetLeft( LONG_MIN );
+ aVis.SetRight( LONG_MAX );
+ }
+ else
+ {
+ aVis.SetTop( LONG_MIN );
+ aVis.SetBottom( LONG_MAX );
+ }
+ pSelEngine->SetVisibleArea( aVis );
+
+ SetMarking( true ); // must precede SelMouseButtonDown
+ pSelEngine->SelMouseButtonDown( rMEvt );
+
+ // In column/row headers a simple click already is a selection.
+ // -> Call SelMouseMove to ensure CreateAnchor is called (and DestroyAnchor
+ // if the next click is somewhere else with Control key).
+ pSelEngine->SelMouseMove( rMEvt );
+
+ if (IsMouseCaptured())
+ {
+ // tracking instead of CaptureMouse, so it can be cancelled cleanly
+ //! someday SelectionEngine itself should call StartTracking!?!
+ ReleaseMouse();
+ StartTracking();
+ }
+ }
+}
+
+void ScHeaderControl::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ if ( IsDisabled() )
+ return;
+
+ if ( SC_MOD()->IsFormulaMode() )
+ {
+ SC_MOD()->EndReference();
+ bInRefMode = false;
+ return;
+ }
+
+ SetMarking( false );
+ bIgnoreMove = false;
+
+ if ( bDragging )
+ {
+ DrawInvert( nDragPos );
+ ReleaseMouse();
+ HideDragHelp();
+ bDragging = false;
+
+ tools::Long nScrPos = GetScrPos( nDragNo );
+ tools::Long nMousePos = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X();
+ bool bLayoutRTL = IsLayoutRTL();
+ tools::Long nNewWidth = bLayoutRTL ? ( nScrPos - nMousePos + 1 )
+ : ( nMousePos + 2 - nScrPos );
+
+ if ( nNewWidth < 0 /* && !IsSelected(nDragNo) */ )
+ {
+ SCCOLROW nStart = 0;
+ SCCOLROW nEnd = nDragNo;
+ while (nNewWidth < 0)
+ {
+ nStart = nDragNo;
+ if (nDragNo>0)
+ {
+ --nDragNo;
+ nNewWidth += GetEntrySize( nDragNo ); //! GetHiddenCount() ???
+ }
+ else
+ nNewWidth = 0;
+ }
+ HideEntries( nStart, nEnd );
+ }
+ else
+ {
+ if (bDragMoved)
+ SetEntrySize( nDragNo, static_cast<sal_uInt16>(nNewWidth) );
+ }
+ }
+ else
+ {
+ pSelEngine->SelMouseButtonUp( rMEvt );
+ ReleaseMouse();
+ }
+}
+
+void ScHeaderControl::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( IsDisabled() )
+ {
+ SetPointer( PointerStyle::Arrow );
+ return;
+ }
+
+ if ( bInRefMode && rMEvt.IsLeft() && SC_MOD()->IsFormulaMode() )
+ {
+ if( !pTabView )
+ return;
+ bool bTmp;
+ SCCOLROW nHitNo = GetMousePos(rMEvt.GetPosPixel(), bTmp);
+ SCTAB nTab = pTabView->GetViewData().GetTabNo();
+ ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
+ ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
+ if( !bVertical )
+ pTabView->UpdateRef( nHitNo, rDoc.MaxRow(), nTab );
+ else
+ pTabView->UpdateRef( rDoc.MaxCol(), nHitNo, nTab );
+
+ return;
+ }
+
+ if ( bDragging )
+ {
+ tools::Long nNewPos = bVertical ? rMEvt.GetPosPixel().Y() : rMEvt.GetPosPixel().X();
+ if ( nNewPos != nDragPos )
+ {
+ DrawInvert( nDragPos );
+ nDragPos = nNewPos;
+ ShowDragHelp();
+ DrawInvert( nDragPos );
+
+ if (nDragPos <= nDragStart-SC_DRAG_MIN || nDragPos >= nDragStart+SC_DRAG_MIN)
+ bDragMoved = true;
+ }
+ }
+ else
+ {
+ bool bIsBorder;
+ (void)GetMousePos(rMEvt.GetPosPixel(), bIsBorder);
+
+ if ( bIsBorder && rMEvt.GetButtons()==0 && ResizeAllowed() )
+ SetPointer( bVertical ? PointerStyle::VSizeBar : PointerStyle::HSizeBar );
+ else
+ SetPointer( PointerStyle::Arrow );
+
+ if (!bIgnoreMove)
+ pSelEngine->SelMouseMove( rMEvt );
+ }
+}
+
+void ScHeaderControl::Tracking( const TrackingEvent& rTEvt )
+{
+ // Distribute the tracking events to the various MouseEvents, because
+ // SelectionEngine does not know anything about Tracking
+
+ if ( rTEvt.IsTrackingCanceled() )
+ StopMarking();
+ else if ( rTEvt.IsTrackingEnded() )
+ MouseButtonUp( rTEvt.GetMouseEvent() );
+ else
+ MouseMove( rTEvt.GetMouseEvent() );
+}
+
+void ScHeaderControl::Command( const CommandEvent& rCEvt )
+{
+ CommandEventId nCmd = rCEvt.GetCommand();
+ if ( nCmd == CommandEventId::ContextMenu )
+ {
+ StopMarking(); // finish selection / dragging
+
+ // execute popup menu
+
+ ScTabViewShell* pViewSh = dynamic_cast< ScTabViewShell *>( SfxViewShell::Current() );
+ if ( pViewSh )
+ {
+ if ( rCEvt.IsMouseEvent() )
+ {
+ // #i18735# select the column/row under the mouse pointer
+ ScViewData& rViewData = pViewSh->GetViewData();
+
+ SelectWindow(); // also deselects drawing objects, stops draw text edit
+ if ( rViewData.HasEditView( rViewData.GetActivePart() ) )
+ SC_MOD()->InputEnterHandler(); // always end edit mode
+
+ bool bBorder;
+ SCCOLROW nPos = GetMousePos(rCEvt.GetMousePosPixel(), bBorder );
+ if (!IsSelectionAllowed(nPos))
+ // Selecting this cell is not allowed, neither is context menu.
+ return;
+
+ SCTAB nTab = rViewData.GetTabNo();
+ ScDocument& rDoc = pViewSh->GetViewData().GetDocument();
+ ScRange aNewRange;
+ if ( bVertical )
+ aNewRange = ScRange( 0, sal::static_int_cast<SCROW>(nPos), nTab,
+ rDoc.MaxCol(), sal::static_int_cast<SCROW>(nPos), nTab );
+ else
+ aNewRange = ScRange( sal::static_int_cast<SCCOL>(nPos), 0, nTab,
+ sal::static_int_cast<SCCOL>(nPos), rDoc.MaxRow(), nTab );
+
+ // see if any part of the range is already selected
+ ScRangeList aRanges;
+ rViewData.GetMarkData().FillRangeListWithMarks( &aRanges, false );
+ bool bSelected = aRanges.Intersects(aNewRange);
+
+ // select the range if no part of it was selected
+ if ( !bSelected )
+ pViewSh->MarkRange( aNewRange );
+ }
+
+ pViewSh->GetDispatcher()->ExecutePopup( bVertical ? OUString( "rowheader" ) : OUString( "colheader" ) );
+ }
+ }
+ else if ( nCmd == CommandEventId::StartDrag )
+ {
+ pSelEngine->Command( rCEvt );
+ }
+}
+
+void ScHeaderControl::StopMarking()
+{
+ if ( bDragging )
+ {
+ DrawInvert( nDragPos );
+ HideDragHelp();
+ bDragging = false;
+ }
+
+ SetMarking( false );
+ bIgnoreMove = true;
+
+ // don't call pSelEngine->Reset, so selection across the parts of
+ // a split/frozen view is possible
+ if (IsMouseCaptured())
+ ReleaseMouse();
+}
+
+IMPL_LINK_NOARG(ScHeaderControl, ShowDragHelpHdl, Timer*, void)
+{
+ ShowDragHelp();
+}
+
+void ScHeaderControl::ShowDragHelp()
+{
+ aShowHelpTimer.Stop();
+ if (!Help::IsQuickHelpEnabled())
+ return;
+
+ tools::Long nScrPos = GetScrPos( nDragNo );
+ bool bLayoutRTL = IsLayoutRTL();
+ tools::Long nVal = bLayoutRTL ? ( nScrPos - nDragPos + 1 )
+ : ( nDragPos + 2 - nScrPos );
+
+ OUString aHelpStr = GetDragHelp( nVal );
+ Point aPos = OutputToScreenPixel( Point(0,0) );
+ Size aSize = GetSizePixel();
+
+ Point aMousePos = OutputToScreenPixel(GetPointerPosPixel());
+
+ tools::Rectangle aRect;
+ QuickHelpFlags nAlign;
+ if (!bVertical)
+ {
+ // above
+ aRect.SetLeft( aMousePos.X() );
+ aRect.SetTop( aPos.Y() - 4 );
+ nAlign = QuickHelpFlags::Bottom|QuickHelpFlags::Center;
+ }
+ else
+ {
+ // top right
+ aRect.SetLeft( aPos.X() + aSize.Width() + 8 );
+ aRect.SetTop( aMousePos.Y() - 2 );
+ nAlign = QuickHelpFlags::Left|QuickHelpFlags::Bottom;
+ }
+
+ aRect.SetRight( aRect.Left() );
+ aRect.SetBottom( aRect.Top() );
+
+ if (nTipVisible)
+ Help::HidePopover(this, nTipVisible);
+ nTipVisible = Help::ShowPopover(this, aRect, aHelpStr, nAlign);
+}
+
+void ScHeaderControl::HideDragHelp()
+{
+ aShowHelpTimer.Stop();
+ if (nTipVisible)
+ {
+ Help::HidePopover(this, nTipVisible);
+ nTipVisible = nullptr;
+ }
+}
+
+void ScHeaderControl::RequestHelp( const HelpEvent& rHEvt )
+{
+ // If the own QuickHelp is displayed, don't let RequestHelp remove it
+
+ bool bOwn = bDragging && Help::IsQuickHelpEnabled();
+ if (!bOwn)
+ Window::RequestHelp(rHEvt);
+}
+
+// dummies for virtual methods
+
+SCCOLROW ScHeaderControl::GetHiddenCount( SCCOLROW nEntryNo ) const
+{
+ SCCOLROW nHidden = 0;
+ while ( nEntryNo < nSize && GetEntrySize( nEntryNo ) == 0 )
+ {
+ ++nEntryNo;
+ ++nHidden;
+ }
+ return nHidden;
+}
+
+bool ScHeaderControl::IsLayoutRTL() const
+{
+ return false;
+}
+
+bool ScHeaderControl::IsMirrored() const
+{
+ return false;
+}
+
+bool ScHeaderControl::IsDisabled() const
+{
+ return false;
+}
+
+bool ScHeaderControl::ResizeAllowed() const
+{
+ return true;
+}
+
+void ScHeaderControl::SelectWindow()
+{
+}
+
+void ScHeaderControl::DrawInvert( tools::Long /* nDragPos */ )
+{
+}
+
+OUString ScHeaderControl::GetDragHelp( tools::Long /* nVal */ )
+{
+ return OUString();
+}
+
+void ScHeaderControl::SetMarking( bool /* bSet */ )
+{
+}
+
+void ScHeaderControl::GetMarkRange(SCCOLROW& rStart, SCCOLROW& rEnd) const
+{
+ rStart = nMarkStart;
+ rEnd = nMarkEnd;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/hintwin.cxx b/sc/source/ui/view/hintwin.cxx
new file mode 100644
index 000000000..09f32f020
--- /dev/null
+++ b/sc/source/ui/view/hintwin.cxx
@@ -0,0 +1,181 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <overlayobject.hxx>
+
+#include <drawinglayer/attribute/fontattribute.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <tools/lineend.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/metric.hxx>
+#include <sal/log.hxx>
+
+#define HINT_LINESPACE 2
+#define HINT_INDENT 3
+#define HINT_MARGIN 4
+
+ScOverlayHint::ScOverlayHint(const OUString& rTit, const OUString& rMsg, const Color& rColor, const vcl::Font& rFont)
+ : OverlayObject(rColor)
+ , m_aTitle(rTit)
+ , m_aMessage(convertLineEnd(rMsg, LINEEND_CR))
+ , m_aTextFont(rFont)
+ , m_aMapMode(MapUnit::MapPixel)
+ , m_nLeft(0)
+ , m_nTop(0)
+{
+}
+
+drawinglayer::primitive2d::Primitive2DContainer ScOverlayHint::createOverlaySequence(sal_Int32 nLeft, sal_Int32 nTop,
+ const MapMode &rMapMode,
+ basegfx::B2DRange &rRange) const
+{
+ OutputDevice* pDefaultDev = Application::GetDefaultDevice();
+ MapMode aOld = pDefaultDev->GetMapMode();
+ pDefaultDev->SetMapMode(rMapMode);
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ const Color& rColor = rStyleSettings.GetLabelTextColor();
+ vcl::Font aTextFont = m_aTextFont;
+ aTextFont.SetFontSize(pDefaultDev->PixelToLogic(aTextFont.GetFontSize(), rMapMode));
+ vcl::Font aHeadFont = aTextFont;
+ aHeadFont.SetWeight(WEIGHT_BOLD);
+
+ // Create the text primitive for the title
+ basegfx::B2DVector aFontSize;
+ drawinglayer::attribute::FontAttribute aFontAttr =
+ drawinglayer::primitive2d::getFontAttributeFromVclFont(aFontSize, aHeadFont, false, false);
+
+ FontMetric aFontMetric = pDefaultDev->GetFontMetric(aHeadFont);
+ Size aHintMargin = pDefaultDev->PixelToLogic(Size(HINT_MARGIN, HINT_MARGIN), rMapMode);
+ Size aIndent = pDefaultDev->PixelToLogic(Size(HINT_INDENT, HINT_LINESPACE), rMapMode);
+ double nTextOffsetY = nTop + aHintMargin.Height() + aFontMetric.GetAscent();
+ Point aTextPos(nLeft + aHintMargin.Width() , nTextOffsetY);
+ rRange = basegfx::B2DRange(nLeft, nTop, nLeft + aHintMargin.Width(), nTop + aHintMargin.Height());
+
+ basegfx::B2DHomMatrix aTextMatrix(basegfx::utils::createScaleTranslateB2DHomMatrix(
+ aFontSize.getX(), aFontSize.getY(),
+ aTextPos.X(), aTextPos.Y()));
+
+ rtl::Reference<drawinglayer::primitive2d::TextSimplePortionPrimitive2D> pTitle =
+ new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aTextMatrix, m_aTitle, 0, m_aTitle.getLength(),
+ std::vector<double>(), aFontAttr, css::lang::Locale(),
+ rColor.getBColor());
+
+ Point aTextStart(nLeft + aHintMargin.Width() + aIndent.Width(),
+ nTop + aHintMargin.Height() + aFontMetric.GetLineHeight() + aIndent.Height());
+
+ drawinglayer::geometry::ViewInformation2D aDummy;
+ rRange.expand(pTitle->getB2DRange(aDummy));
+
+ drawinglayer::primitive2d::Primitive2DContainer aSeq { pTitle };
+
+ aFontMetric = pDefaultDev->GetFontMetric(aTextFont);
+ pDefaultDev->SetMapMode(aOld);
+
+ nTextOffsetY = aFontMetric.GetAscent();
+ sal_Int32 nLineHeight = aFontMetric.GetLineHeight();
+
+ aFontAttr = drawinglayer::primitive2d::getFontAttributeFromVclFont(aFontSize, aTextFont, false, false);
+
+ sal_Int32 nIndex = 0;
+ Point aLineStart = aTextStart;
+ sal_Int32 nLineCount = 0;
+ while (nIndex != -1)
+ {
+ OUString aLine = m_aMessage.getToken( 0, '\r', nIndex );
+ if (aLine.getLength() > 255)
+ {
+ // prevent silliness higher up from hanging up the program
+ SAL_WARN("sc", "ridiculously long line, truncating, len=" << aLine.getLength());
+ aLine = aLine.copy(0,255);
+ }
+
+ aTextMatrix = basegfx::utils::createScaleTranslateB2DHomMatrix(
+ aFontSize.getX(), aFontSize.getY(),
+ aLineStart.X(), aLineStart.Y() + nTextOffsetY);
+
+ // Create the text primitive for each line of text
+ rtl::Reference<drawinglayer::primitive2d::TextSimplePortionPrimitive2D> pMessage =
+ new drawinglayer::primitive2d::TextSimplePortionPrimitive2D(
+ aTextMatrix, aLine, 0, aLine.getLength(),
+ std::vector<double>(), aFontAttr, css::lang::Locale(),
+ rColor.getBColor());
+
+ rRange.expand(pMessage->getB2DRange(aDummy));
+
+ aSeq.push_back(pMessage);
+
+ aLineStart.AdjustY(nLineHeight );
+ nLineCount++;
+ if (nLineCount > 50)
+ {
+ // prevent silliness higher up from hanging up the program
+ SAL_WARN("sc", "ridiculously long message, bailing out");
+ break;
+ }
+ }
+
+ rRange.expand(basegfx::B2DTuple(rRange.getMaxX() + aHintMargin.Width(),
+ rRange.getMaxY() + aHintMargin.Height()));
+
+ basegfx::B2DPolygon aPoly(basegfx::utils::createPolygonFromRect(rRange));
+
+ const drawinglayer::primitive2d::Primitive2DReference aBg(
+ new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPoly), getBaseColor().getBColor()));
+
+ basegfx::BColor aBorderColor(0.5, 0.5, 0.5);
+ const drawinglayer::primitive2d::Primitive2DReference aBorder(
+ new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(
+ aPoly, aBorderColor));
+
+ aSeq.insert(aSeq.begin(), aBorder);
+ aSeq.insert(aSeq.begin(), aBg);
+
+ return aSeq;
+}
+
+drawinglayer::primitive2d::Primitive2DContainer ScOverlayHint::createOverlayObjectPrimitive2DSequence()
+{
+ basegfx::B2DRange aRange;
+ return createOverlaySequence(m_nLeft, m_nTop, m_aMapMode, aRange);
+}
+
+Size ScOverlayHint::GetSizePixel() const
+{
+ basegfx::B2DRange aRange;
+ createOverlaySequence(0, 0, MapMode(MapUnit::MapPixel), aRange);
+ return Size(aRange.getWidth(), aRange.getHeight());
+}
+
+void ScOverlayHint::SetPos(const Point& rPos, const MapMode& rMode)
+{
+ m_nLeft = rPos.X();
+ m_nTop = rPos.Y();
+ m_aMapMode = rMode;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/imapwrap.cxx b/sc/source/ui/view/imapwrap.cxx
new file mode 100644
index 000000000..72d137339
--- /dev/null
+++ b/sc/source/ui/view/imapwrap.cxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <svx/imapdlg.hxx>
+
+#include "imapwrap.hxx"
+
+sal_uInt16 ScIMapChildWindowId()
+{
+ return SvxIMapDlgChildWindow::GetChildWindowId();
+}
+
+void ScIMapDlgSet( const Graphic& rGraphic, const ImageMap* pImageMap,
+ const TargetList* pTargetList, void* pEditingObj )
+{
+ SvxIMapDlgChildWindow::UpdateIMapDlg( rGraphic, pImageMap, pTargetList, pEditingObj );
+}
+
+const void* ScIMapDlgGetObj( const SvxIMapDlg* pDlg )
+{
+ if ( pDlg )
+ return pDlg->GetEditingObject();
+ else
+ return nullptr;
+}
+
+const ImageMap& ScIMapDlgGetMap( const SvxIMapDlg* pDlg )
+{
+ return pDlg->GetImageMap();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/imapwrap.hxx b/sc/source/ui/view/imapwrap.hxx
new file mode 100644
index 000000000..9b46b1bc8
--- /dev/null
+++ b/sc/source/ui/view/imapwrap.hxx
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+
+#include <sal/types.h>
+#include <sfx2/frame.hxx>
+
+class Graphic;
+class ImageMap;
+class SvxIMapDlg;
+
+sal_uInt16 ScIMapChildWindowId();
+
+ImageMap const & ScIMapDlgGetMap(const SvxIMapDlg * pDlg);
+
+void const * ScIMapDlgGetObj(const SvxIMapDlg * pDlg);
+
+void ScIMapDlgSet(
+ Graphic const & rGraphic, ImageMap const * pImageMap,
+ TargetList const * pTargetList, void * pEditingObj);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/invmerge.cxx b/sc/source/ui/view/invmerge.cxx
new file mode 100644
index 000000000..a08222197
--- /dev/null
+++ b/sc/source/ui/view/invmerge.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 <osl/diagnose.h>
+
+#include <invmerge.hxx>
+
+ScInvertMerger::ScInvertMerger( ::std::vector< tools::Rectangle >* pRectangles ) :
+ pRects( pRectangles )
+{
+ // collect rectangles instead of inverting
+}
+
+ScInvertMerger::~ScInvertMerger()
+{
+ Flush();
+}
+
+void ScInvertMerger::Flush()
+{
+ FlushLine();
+ FlushTotal();
+
+ OSL_ENSURE( aLineRect.IsEmpty() && aTotalRect.IsEmpty(), "Flush: not empty" );
+
+ if ( !pRects )
+ return;
+
+ // also join vertically if there are non-adjacent columns involved
+
+ size_t nComparePos = 0;
+ while ( nComparePos < pRects->size() )
+ {
+ tools::Rectangle aCompRect = (*pRects)[nComparePos];
+ sal_Int32 nBottom = aCompRect.Bottom();
+ size_t nOtherPos = nComparePos + 1;
+
+ while ( nOtherPos < pRects->size() )
+ {
+ tools::Rectangle aOtherRect = (*pRects)[nOtherPos];
+ if ( aOtherRect.Top() > nBottom + 1 )
+ {
+ // rectangles are sorted, so we can stop searching
+ break;
+ }
+ if ( aOtherRect.Top() == nBottom + 1 &&
+ aOtherRect.Left() == aCompRect.Left() &&
+ aOtherRect.Right() == aCompRect.Right() )
+ {
+ // extend first rectangle
+ nBottom = aOtherRect.Bottom();
+ aCompRect.SetBottom( nBottom );
+ (*pRects)[nComparePos].SetBottom( nBottom );
+
+ // remove second rectangle
+ pRects->erase( pRects->begin() + nOtherPos );
+
+ // continue at unmodified nOtherPos
+ }
+ else
+ ++nOtherPos;
+ }
+
+ ++nComparePos;
+ }
+}
+
+void ScInvertMerger::FlushTotal()
+{
+ if( aTotalRect.IsEmpty() )
+ return; // nothing to do
+
+ if ( pRects )
+ pRects->push_back( aTotalRect );
+
+ aTotalRect.SetEmpty();
+}
+
+void ScInvertMerger::FlushLine()
+{
+ if( aLineRect.IsEmpty() )
+ return; // nothing to do
+
+ if ( aTotalRect.IsEmpty() )
+ {
+ aTotalRect = aLineRect; // start new total rect
+ }
+ else
+ {
+ if ( aLineRect.Left() == aTotalRect.Left() &&
+ aLineRect.Right() == aTotalRect.Right() &&
+ aLineRect.Top() == aTotalRect.Bottom() + 1 )
+ {
+ // extend total rect
+ aTotalRect.SetBottom( aLineRect.Bottom() );
+ }
+ else
+ {
+ FlushTotal(); // draw old total rect
+ aTotalRect = aLineRect; // and start new one
+ }
+ }
+
+ aLineRect.SetEmpty();
+}
+
+void ScInvertMerger::AddRect( const tools::Rectangle& rRect )
+{
+ tools::Rectangle aJustified = rRect;
+ if ( rRect.Left() > rRect.Right() ) // switch for RTL layout
+ {
+ aJustified.SetLeft( rRect.Right() );
+ aJustified.SetRight( rRect.Left() );
+ }
+
+ if ( aLineRect.IsEmpty() )
+ {
+ aLineRect = aJustified; // start new line rect
+ }
+ else
+ {
+ bool bDone = false;
+ if ( aJustified.Top() == aLineRect.Top() &&
+ aJustified.Bottom() == aLineRect.Bottom() )
+ {
+ // try to extend line rect
+ if ( aJustified.Left() == aLineRect.Right() + 1 )
+ {
+ aLineRect.SetRight( aJustified.Right() );
+ bDone = true;
+ }
+ else if ( aJustified.Right() + 1 == aLineRect.Left() ) // for RTL layout
+ {
+ aLineRect.SetLeft( aJustified.Left() );
+ bDone = true;
+ }
+ }
+ if (!bDone)
+ {
+ FlushLine(); // use old line rect for total rect
+ aLineRect = aJustified; // and start new one
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/notemark.cxx b/sc/source/ui/view/notemark.cxx
new file mode 100644
index 000000000..ba0d3c1da
--- /dev/null
+++ b/sc/source/ui/view/notemark.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 <svx/svdoutl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdocapt.hxx>
+#include <svl/itempool.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/window.hxx>
+
+#include <notemark.hxx>
+#include <document.hxx>
+#include <postit.hxx>
+
+#define SC_NOTEMARK_TIME 800
+#define SC_NOTEMARK_SHORT 70
+
+ScNoteMarker::ScNoteMarker( vcl::Window* pWin, vcl::Window* pRight, vcl::Window* pBottom, vcl::Window* pDiagonal,
+ ScDocument* pD, const ScAddress& aPos, const OUString& rUser,
+ const MapMode& rMap, bool bLeftEdge, bool bForce, bool bKeyboard) :
+ m_pWindow( pWin ),
+ m_pRightWin( pRight ),
+ m_pBottomWin( pBottom ),
+ m_pDiagWin( pDiagonal ),
+ m_pDoc( pD ),
+ m_aDocPos( aPos ),
+ m_aUserText( rUser ),
+ m_aTimer("ScNoteMarker m_aTimer"),
+ m_aMapMode( rMap ),
+ m_bLeft( bLeftEdge ),
+ m_bByKeyboard( bKeyboard ),
+ m_bVisible( false )
+{
+ Size aSizePixel = m_pWindow->GetOutputSizePixel();
+ if( m_pRightWin )
+ aSizePixel.AdjustWidth(m_pRightWin->GetOutputSizePixel().Width() );
+ if( m_pBottomWin )
+ aSizePixel.AdjustHeight(m_pBottomWin->GetOutputSizePixel().Height() );
+ tools::Rectangle aVisPixel( Point( 0, 0 ), aSizePixel );
+ m_aVisRect = m_pWindow->PixelToLogic( aVisPixel, m_aMapMode );
+
+ m_aTimer.SetInvokeHandler( LINK( this, ScNoteMarker, TimeHdl ) );
+ m_aTimer.SetTimeout( bForce ? SC_NOTEMARK_SHORT : SC_NOTEMARK_TIME );
+ m_aTimer.Start();
+}
+
+ScNoteMarker::~ScNoteMarker()
+{
+ if (m_pModel)
+ m_xObject.release(); // deleting pModel also deletes the SdrCaptionObj
+
+ InvalidateWin();
+
+ m_pModel.reset();
+}
+
+IMPL_LINK_NOARG(ScNoteMarker, TimeHdl, Timer *, void)
+{
+ if (!m_bVisible)
+ {
+ m_pModel.reset( new SdrModel() );
+ m_pModel->SetScaleUnit(MapUnit::Map100thMM);
+ SfxItemPool& rPool = m_pModel->GetItemPool();
+ rPool.SetDefaultMetric(MapUnit::Map100thMM);
+ rPool.FreezeIdRanges();
+
+ OutputDevice* pPrinter = m_pDoc->GetRefDevice();
+ if (pPrinter)
+ {
+ // On the outliner of the draw model also the printer is set as RefDevice,
+ // and it should look uniform.
+ Outliner& rOutliner = m_pModel->GetDrawOutliner();
+ rOutliner.SetRefDevice(pPrinter);
+ }
+
+ if( rtl::Reference<SdrPage> pPage = m_pModel->AllocPage( false ) )
+
+ {
+ m_xObject = ScNoteUtil::CreateTempCaption( *m_pDoc, m_aDocPos, *pPage, m_aUserText, m_aVisRect, m_bLeft );
+ if( m_xObject )
+ {
+ // Here, SyncForGrid and GetGridOffset was used with the comment:
+ // // Need to include grid offset: GetCurrentBoundRect is removing it
+ // // but we need to know actual rect position
+ // This is no longer true - SdrObject::RecalcBoundRect() uses the
+ // GetViewContact().getViewIndependentPrimitive2DContainer()) call
+ // that now by default adds the eventually needed GridOffset. Thus
+ // I have removed that adaptation stuff.
+ m_aRect = m_xObject->GetCurrentBoundRect();
+ }
+
+ // Insert page so that the model recognise it and also deleted
+ m_pModel->InsertPage( pPage.get() );
+
+ }
+ m_bVisible = true;
+ }
+
+ Draw();
+}
+
+static void lcl_DrawWin( const SdrObject* pObject, vcl::RenderContext* pWindow, const MapMode& rMap )
+{
+ MapMode aOld = pWindow->GetMapMode();
+ pWindow->SetMapMode( rMap );
+
+ DrawModeFlags nOldDrawMode = pWindow->GetDrawMode();
+ if ( Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ pWindow->SetDrawMode( nOldDrawMode | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill |
+ DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
+ }
+
+ pObject->SingleObjectPainter( *pWindow ); // #110094#-17
+
+ pWindow->SetDrawMode( nOldDrawMode );
+ pWindow->SetMapMode( aOld );
+}
+
+static MapMode lcl_MoveMapMode( const MapMode& rMap, const Size& rMove )
+{
+ MapMode aNew = rMap;
+ Point aOrigin = aNew.GetOrigin();
+ aOrigin.AdjustX( -(rMove.Width()) );
+ aOrigin.AdjustY( -rMove.Height() );
+ aNew.SetOrigin(aOrigin);
+ return aNew;
+}
+
+void ScNoteMarker::Draw()
+{
+ if ( !(m_xObject && m_bVisible) )
+ return;
+
+ lcl_DrawWin( m_xObject.get(), m_pWindow->GetOutDev(), m_aMapMode );
+
+ if ( m_pRightWin || m_pBottomWin )
+ {
+ Size aWinSize = m_pWindow->PixelToLogic( m_pWindow->GetOutputSizePixel(), m_aMapMode );
+ if ( m_pRightWin )
+ lcl_DrawWin( m_xObject.get(), m_pRightWin->GetOutDev(),
+ lcl_MoveMapMode( m_aMapMode, Size( aWinSize.Width(), 0 ) ) );
+ if ( m_pBottomWin )
+ lcl_DrawWin( m_xObject.get(), m_pBottomWin->GetOutDev(),
+ lcl_MoveMapMode( m_aMapMode, Size( 0, aWinSize.Height() ) ) );
+ if ( m_pDiagWin )
+ lcl_DrawWin( m_xObject.get(), m_pDiagWin->GetOutDev(), lcl_MoveMapMode( m_aMapMode, aWinSize ) );
+ }
+}
+
+void ScNoteMarker::InvalidateWin()
+{
+ if (!m_bVisible)
+ return;
+
+ // Extend the invalidated rectangle by 1 pixel in each direction in case AA would slightly
+ // paint outside the nominal area.
+ tools::Rectangle aRect(m_aRect);
+ const Size aPixelSize = m_pWindow->PixelToLogic(Size(1, 1));
+ aRect.AdjustLeft(-aPixelSize.getWidth());
+ aRect.AdjustTop(-aPixelSize.getHeight());
+ aRect.AdjustRight(aPixelSize.getWidth());
+ aRect.AdjustBottom(aPixelSize.getHeight());
+
+ m_pWindow->Invalidate( OutputDevice::LogicToLogic(aRect, m_aMapMode, m_pWindow->GetMapMode()) );
+
+ if ( !(m_pRightWin || m_pBottomWin) )
+ return;
+
+ Size aWinSize = m_pWindow->PixelToLogic( m_pWindow->GetOutputSizePixel(), m_aMapMode );
+ if ( m_pRightWin )
+ m_pRightWin->Invalidate( OutputDevice::LogicToLogic(aRect,
+ lcl_MoveMapMode( m_aMapMode, Size( aWinSize.Width(), 0 ) ),
+ m_pRightWin->GetMapMode()) );
+ if ( m_pBottomWin )
+ m_pBottomWin->Invalidate( OutputDevice::LogicToLogic(aRect,
+ lcl_MoveMapMode( m_aMapMode, Size( 0, aWinSize.Height() ) ),
+ m_pBottomWin->GetMapMode()) );
+ if ( m_pDiagWin )
+ m_pDiagWin->Invalidate( OutputDevice::LogicToLogic(aRect,
+ lcl_MoveMapMode( m_aMapMode, aWinSize ),
+ m_pDiagWin->GetMapMode()) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/olinewin.cxx b/sc/source/ui/view/olinewin.cxx
new file mode 100644
index 000000000..dcfbccb6c
--- /dev/null
+++ b/sc/source/ui/view/olinewin.cxx
@@ -0,0 +1,1040 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <vcl/image.hxx>
+#include <vcl/taskpanelist.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/syswin.hxx>
+#include <osl/diagnose.h>
+
+#include <olinewin.hxx>
+#include <olinetab.hxx>
+#include <document.hxx>
+#include <dbfunc.hxx>
+#include <bitmaps.hlst>
+
+const tools::Long SC_OL_BITMAPSIZE = 12;
+const tools::Long SC_OL_POSOFFSET = 2;
+
+const size_t SC_OL_NOLEVEL = static_cast< size_t >( -1 );
+const size_t SC_OL_HEADERENTRY = static_cast< size_t >( -1 );
+
+ScOutlineWindow::ScOutlineWindow( vcl::Window* pParent, ScOutlineMode eMode, ScViewData* pViewData, ScSplitPos eWhich ) :
+ Window( pParent ),
+ mrViewData( *pViewData ),
+ meWhich( eWhich ),
+ mbHoriz( eMode == SC_OUTLINE_HOR ),
+ mbMirrorEntries( false ), // updated in SetHeaderSize
+ mbMirrorLevels( false ), // updated in SetHeaderSize
+ maLineColor( COL_BLACK ),
+ mnHeaderSize( 0 ),
+ mnHeaderPos( 0 ),
+ mnMainFirstPos( 0 ),
+ mnMainLastPos( 0 ),
+ mbMTActive( false ),
+ mbMTPressed( false ),
+ mnFocusLevel( 0 ),
+ mnFocusEntry( SC_OL_HEADERENTRY ),
+ mbDontDrawFocus( false )
+{
+ EnableRTL( false ); // mirroring is done manually
+
+ InitSettings();
+ maFocusRect.SetEmpty();
+ SetHeaderSize( 0 );
+
+ // insert the window into task pane list for "F6 cycling"
+ if( SystemWindow* pSysWin = GetSystemWindow() )
+ if( TaskPaneList* pTaskPaneList = pSysWin->GetTaskPaneList() )
+ pTaskPaneList->AddWindow( this );
+}
+
+ScOutlineWindow::~ScOutlineWindow()
+{
+ disposeOnce();
+}
+
+void ScOutlineWindow::dispose()
+{
+ // remove the window from task pane list
+ if( SystemWindow* pSysWin = GetSystemWindow() )
+ if( TaskPaneList* pTaskPaneList = pSysWin->GetTaskPaneList() )
+ pTaskPaneList->RemoveWindow( this );
+ vcl::Window::dispose();
+}
+
+void ScOutlineWindow::SetHeaderSize( tools::Long nNewSize )
+{
+ bool bLayoutRTL = GetDoc().IsLayoutRTL( GetTab() );
+ mbMirrorEntries = bLayoutRTL && mbHoriz;
+ mbMirrorLevels = bLayoutRTL && !mbHoriz;
+
+ bool bNew = (nNewSize != mnHeaderSize);
+ mnHeaderSize = nNewSize;
+ mnHeaderPos = mbMirrorEntries ? (GetOutputSizeEntry() - mnHeaderSize) : 0;
+ mnMainFirstPos = mbMirrorEntries ? 0 : mnHeaderSize;
+ mnMainLastPos = GetOutputSizeEntry() - (mbMirrorEntries ? mnHeaderSize : 0) - 1;
+ if ( bNew )
+ Invalidate();
+}
+
+tools::Long ScOutlineWindow::GetDepthSize() const
+{
+ tools::Long nSize = GetLevelCount() * SC_OL_BITMAPSIZE;
+ if ( nSize > 0 )
+ nSize += 2 * SC_OL_POSOFFSET + 1;
+ return nSize;
+}
+
+void ScOutlineWindow::ScrollPixel( tools::Long nDiff )
+{
+ HideFocus();
+ mbDontDrawFocus = true;
+
+ tools::Long nStart = mnMainFirstPos;
+ tools::Long nEnd = mnMainLastPos;
+
+ tools::Long nInvStart, nInvEnd;
+ if (nDiff < 0)
+ {
+ nStart -= nDiff;
+ nInvStart = nEnd + nDiff;
+ nInvEnd = nEnd;
+ }
+ else
+ {
+ nEnd -= nDiff;
+ nInvStart = nStart;
+ nInvEnd = nStart + nDiff;
+ }
+
+ ScrollRel( nDiff, nStart, nEnd );
+ Invalidate( GetRectangle( 0, nInvStart, GetOutputSizeLevel() - 1, nInvEnd ) );
+
+ // if focus becomes invisible, move it to next visible button
+ ImplMoveFocusToVisible( nDiff < 0 );
+
+ mbDontDrawFocus = false;
+ ShowFocus();
+}
+
+void ScOutlineWindow::ScrollRel( tools::Long nEntryDiff, tools::Long nEntryStart, tools::Long nEntryEnd )
+{
+ tools::Rectangle aRect( GetRectangle( 0, nEntryStart, GetOutputSizeLevel() - 1, nEntryEnd ) );
+ if ( mbHoriz )
+ Scroll( nEntryDiff, 0, aRect );
+ else
+ Scroll( 0, nEntryDiff, aRect );
+}
+
+// internal -------------------------------------------------------------------
+
+void ScOutlineWindow::InitSettings()
+{
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ SetBackground( rStyleSettings.GetFaceColor() );
+ maLineColor = rStyleSettings.GetButtonTextColor();
+ Invalidate();
+}
+
+const ScOutlineArray* ScOutlineWindow::GetOutlineArray() const
+{
+ const ScOutlineTable* pTable = GetDoc().GetOutlineTable( GetTab() );
+ if ( !pTable ) return nullptr;
+ return mbHoriz ? &pTable->GetColArray() : &pTable->GetRowArray();
+}
+
+const ScOutlineEntry* ScOutlineWindow::GetOutlineEntry( size_t nLevel, size_t nEntry ) const
+{
+ const ScOutlineArray* pArray = GetOutlineArray();
+ return pArray ? pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) ) : nullptr;
+}
+
+bool ScOutlineWindow::IsHidden( SCCOLROW nColRowIndex ) const
+{
+ return mbHoriz ?
+ GetDoc().ColHidden(static_cast<SCCOL>(nColRowIndex), GetTab()) :
+ GetDoc().RowHidden(static_cast<SCROW>(nColRowIndex), GetTab());
+}
+
+bool ScOutlineWindow::IsFiltered( SCCOLROW nColRowIndex ) const
+{
+ // columns cannot be filtered
+ return !mbHoriz && GetDoc().RowFiltered( static_cast<SCROW>(nColRowIndex), GetTab() );
+}
+
+bool ScOutlineWindow::IsFirstVisible( SCCOLROW nColRowIndex ) const
+{
+ bool bAllHidden = true;
+ for ( SCCOLROW nPos = 0; (nPos < nColRowIndex) && bAllHidden; ++nPos )
+ bAllHidden = IsHidden( nPos );
+ return bAllHidden;
+}
+
+void ScOutlineWindow::GetVisibleRange( SCCOLROW& rnColRowStart, SCCOLROW& rnColRowEnd ) const
+{
+ if ( mbHoriz )
+ {
+ rnColRowStart = mrViewData.GetPosX( WhichH( meWhich ) );
+ rnColRowEnd = rnColRowStart + mrViewData.VisibleCellsX( WhichH( meWhich ) );
+ }
+ else
+ {
+ rnColRowStart = mrViewData.GetPosY( WhichV( meWhich ) );
+ rnColRowEnd = rnColRowStart + mrViewData.VisibleCellsY( WhichV( meWhich ) );
+ }
+
+ // include collapsed columns/rows in front of visible range
+ while ( (rnColRowStart > 0) && IsHidden( rnColRowStart - 1 ) )
+ --rnColRowStart;
+}
+
+Point ScOutlineWindow::GetPoint( tools::Long nLevelPos, tools::Long nEntryPos ) const
+{
+ return mbHoriz ? Point( nEntryPos, nLevelPos ) : Point( nLevelPos, nEntryPos );
+}
+
+tools::Rectangle ScOutlineWindow::GetRectangle(
+ tools::Long nLevelStart, tools::Long nEntryStart, tools::Long nLevelEnd, tools::Long nEntryEnd ) const
+{
+ return tools::Rectangle( GetPoint( nLevelStart, nEntryStart ), GetPoint( nLevelEnd, nEntryEnd ) );
+}
+
+tools::Long ScOutlineWindow::GetOutputSizeLevel() const
+{
+ Size aSize( GetOutputSizePixel() );
+ return mbHoriz ? aSize.Height() : aSize.Width();
+}
+
+tools::Long ScOutlineWindow::GetOutputSizeEntry() const
+{
+ Size aSize( GetOutputSizePixel() );
+ return mbHoriz ? aSize.Width() : aSize.Height();
+}
+
+size_t ScOutlineWindow::GetLevelCount() const
+{
+ const ScOutlineArray* pArray = GetOutlineArray();
+ size_t nLevelCount = pArray ? pArray->GetDepth() : 0;
+ return nLevelCount ? (nLevelCount + 1) : 0;
+}
+
+tools::Long ScOutlineWindow::GetLevelPos( size_t nLevel ) const
+{
+ // #i51970# must always return the *left* edge of the area used by a level
+ tools::Long nPos = static_cast< tools::Long >( SC_OL_POSOFFSET + nLevel * SC_OL_BITMAPSIZE );
+ return mbMirrorLevels ? (GetOutputSizeLevel() - nPos - SC_OL_BITMAPSIZE) : nPos;
+}
+
+size_t ScOutlineWindow::GetLevelFromPos( tools::Long nLevelPos ) const
+{
+ if( mbMirrorLevels ) nLevelPos = GetOutputSizeLevel() - nLevelPos - 1;
+ tools::Long nStart = SC_OL_POSOFFSET;
+ if ( nLevelPos < nStart ) return SC_OL_NOLEVEL;
+ size_t nLevel = static_cast< size_t >( (nLevelPos - nStart) / SC_OL_BITMAPSIZE );
+ return (nLevel < GetLevelCount()) ? nLevel : SC_OL_NOLEVEL;
+}
+
+tools::Long ScOutlineWindow::GetColRowPos( SCCOLROW nColRowIndex ) const
+{
+ tools::Long nDocPos = mbHoriz ?
+ mrViewData.GetScrPos( static_cast<SCCOL>(nColRowIndex), 0, meWhich, true ).X() :
+ mrViewData.GetScrPos( 0, static_cast<SCROW>(nColRowIndex), meWhich, true ).Y();
+ return mnMainFirstPos + nDocPos;
+}
+
+tools::Long ScOutlineWindow::GetHeaderEntryPos() const
+{
+ return mnHeaderPos + (mnHeaderSize - SC_OL_BITMAPSIZE) / 2;
+}
+
+bool ScOutlineWindow::GetEntryPos(
+ size_t nLevel, size_t nEntry,
+ tools::Long& rnStartPos, tools::Long& rnEndPos, tools::Long& rnImagePos ) const
+{
+ const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
+ if ( !pEntry || !pEntry->IsVisible() )
+ return false;
+
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+
+ tools::Long nEntriesSign = mbMirrorEntries ? -1 : 1;
+
+ // --- common calculation ---
+
+ rnStartPos = GetColRowPos( nStart );
+ rnEndPos = GetColRowPos( nEnd + 1 );
+
+ bool bHidden = IsHidden( nStart );
+ rnImagePos = bHidden ?
+ (rnStartPos - ( SC_OL_BITMAPSIZE / 2 ) * nEntriesSign) :
+ rnStartPos + nEntriesSign;
+ tools::Long nCenter = (rnStartPos + rnEndPos - SC_OL_BITMAPSIZE * nEntriesSign +
+ ( mbMirrorEntries ? 1 : 0 )) / 2;
+ rnImagePos = mbMirrorEntries ? std::max( rnImagePos, nCenter ) : std::min( rnImagePos, nCenter );
+
+ // --- refinements ---
+
+ // do not cut leftmost/topmost image
+ if ( bHidden && IsFirstVisible( nStart ) )
+ rnImagePos = rnStartPos;
+
+ // do not cover previous collapsed image
+ bool bDoNoCover = !bHidden && nEntry;
+ const ScOutlineEntry* pPrevEntry = bDoNoCover ? GetOutlineEntry(nLevel, nEntry - 1) : nullptr;
+ if (pPrevEntry)
+ {
+ SCCOLROW nPrevEnd = pPrevEntry->GetEnd();
+ if ( (nPrevEnd + 1 == nStart) && IsHidden( nPrevEnd ) )
+ {
+ if ( IsFirstVisible( pPrevEntry->GetStart() ) )
+ rnStartPos += SC_OL_BITMAPSIZE * nEntriesSign;
+ else
+ rnStartPos += ( SC_OL_BITMAPSIZE / 2 ) * nEntriesSign;
+ rnImagePos = rnStartPos;
+ }
+ }
+
+ // restrict rnStartPos...rnEndPos to valid area
+ rnStartPos = std::max( rnStartPos, mnMainFirstPos );
+ rnEndPos = std::max( rnEndPos, mnMainFirstPos );
+
+ if ( mbMirrorEntries )
+ rnImagePos -= SC_OL_BITMAPSIZE - 1; // start pos aligns with right edge of bitmap
+
+ // --- all rows filtered? ---
+
+ bool bVisible = true;
+ if ( !mbHoriz )
+ {
+ bVisible = false;
+ for ( SCCOLROW nRow = nStart; (nRow <= nEnd) && !bVisible; ++nRow )
+ bVisible = !IsFiltered( nRow );
+ }
+ return bVisible;
+}
+
+bool ScOutlineWindow::GetImagePos( size_t nLevel, size_t nEntry, Point& rPos ) const
+{
+ bool bRet = nLevel < GetLevelCount();
+ if ( bRet )
+ {
+ tools::Long nLevelPos = GetLevelPos( nLevel );
+ if ( nEntry == SC_OL_HEADERENTRY )
+ rPos = GetPoint( nLevelPos, GetHeaderEntryPos() );
+ else
+ {
+ tools::Long nStartPos, nEndPos, nImagePos;
+ bRet = GetEntryPos( nLevel, nEntry, nStartPos, nEndPos, nImagePos );
+ rPos = GetPoint( nLevelPos, nImagePos );
+ }
+ }
+ return bRet;
+}
+
+bool ScOutlineWindow::IsButtonVisible( size_t nLevel, size_t nEntry ) const
+{
+ bool bRet = false;
+ if ( nEntry == SC_OL_HEADERENTRY )
+ bRet = (mnHeaderSize > 0) && (nLevel < GetLevelCount());
+ else
+ {
+ const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
+ if ( pEntry && pEntry->IsVisible() )
+ {
+ SCCOLROW nStart, nEnd;
+ GetVisibleRange( nStart, nEnd );
+ bRet = (nStart <= pEntry->GetStart()) && (pEntry->GetStart() <= nEnd);
+ }
+ }
+ return bRet;
+}
+
+bool ScOutlineWindow::ItemHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry, bool& rbButton ) const
+{
+ const ScOutlineArray* pArray = GetOutlineArray();
+ if ( !pArray ) return false;
+
+ SCCOLROW nStartIndex, nEndIndex;
+ GetVisibleRange( nStartIndex, nEndIndex );
+
+ size_t nLevel = GetLevelFromPos( mbHoriz ? rPos.Y() : rPos.X() );
+ if ( nLevel == SC_OL_NOLEVEL )
+ return false;
+
+ tools::Long nEntryMousePos = mbHoriz ? rPos.X() : rPos.Y();
+
+ // --- level buttons ---
+
+ if ( mnHeaderSize > 0 )
+ {
+ tools::Long nImagePos = GetHeaderEntryPos();
+ if ( (nImagePos <= nEntryMousePos) && (nEntryMousePos < nImagePos + SC_OL_BITMAPSIZE) )
+ {
+ rnLevel = nLevel;
+ rnEntry = SC_OL_HEADERENTRY;
+ rbButton = true;
+ return true;
+ }
+ }
+
+ // --- expand/collapse buttons and expanded lines ---
+
+ // search outline entries backwards
+ size_t nEntry = pArray->GetCount( sal::static_int_cast<sal_uInt16>(nLevel) );
+ while ( nEntry )
+ {
+ --nEntry;
+
+ const ScOutlineEntry* pEntry = pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel),
+ sal::static_int_cast<sal_uInt16>(nEntry) );
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+
+ if ( (nEnd >= nStartIndex) && (nStart <= nEndIndex) )
+ {
+ tools::Long nStartPos, nEndPos, nImagePos;
+ if ( GetEntryPos( nLevel, nEntry, nStartPos, nEndPos, nImagePos ) )
+ {
+ rnLevel = nLevel;
+ rnEntry = nEntry;
+
+ // button?
+ if ( (nStart >= nStartIndex) && (nImagePos <= nEntryMousePos) && (nEntryMousePos < nImagePos + SC_OL_BITMAPSIZE) )
+ {
+ rbButton = true;
+ return true;
+ }
+
+ // line?
+ if ( mbMirrorEntries )
+ ::std::swap( nStartPos, nEndPos ); // in RTL mode, nStartPos is the larger value
+ if ( (nStartPos <= nEntryMousePos) && (nEntryMousePos <= nEndPos) )
+ {
+ rbButton = false;
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ScOutlineWindow::ButtonHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry ) const
+{
+ bool bButton;
+ bool bRet = ItemHit( rPos, rnLevel, rnEntry, bButton );
+ return bRet && bButton;
+}
+
+bool ScOutlineWindow::LineHit( const Point& rPos, size_t& rnLevel, size_t& rnEntry ) const
+{
+ bool bButton;
+ bool bRet = ItemHit( rPos, rnLevel, rnEntry, bButton );
+ return bRet && !bButton;
+}
+
+void ScOutlineWindow::DoFunction( size_t nLevel, size_t nEntry ) const
+{
+ ScDBFunc& rFunc = *mrViewData.GetView();
+ if ( nEntry == SC_OL_HEADERENTRY )
+ rFunc.SelectLevel( mbHoriz, sal::static_int_cast<sal_uInt16>(nLevel) );
+ else
+ {
+ const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
+ if ( pEntry )
+ {
+ if ( pEntry->IsHidden() )
+ rFunc.ShowOutline( mbHoriz, sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) );
+ else
+ rFunc.HideOutline( mbHoriz, sal::static_int_cast<sal_uInt16>(nLevel), sal::static_int_cast<sal_uInt16>(nEntry) );
+ }
+ }
+}
+
+void ScOutlineWindow::DoExpand( size_t nLevel, size_t nEntry ) const
+{
+ const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
+ if ( pEntry && pEntry->IsHidden() )
+ DoFunction( nLevel, nEntry );
+}
+
+void ScOutlineWindow::DoCollapse( size_t nLevel, size_t nEntry ) const
+{
+ const ScOutlineEntry* pEntry = GetOutlineEntry( nLevel, nEntry );
+ if ( pEntry && !pEntry->IsHidden() )
+ DoFunction( nLevel, nEntry );
+}
+
+void ScOutlineWindow::Resize()
+{
+ Window::Resize();
+ SetHeaderSize( mnHeaderSize ); // recalculates header/group positions
+ if ( !IsFocusButtonVisible() )
+ {
+ HideFocus();
+ ShowFocus(); // calculates valid position
+ }
+}
+
+void ScOutlineWindow::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ if ( (rDCEvt.GetType() == DataChangedEventType::SETTINGS) &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ InitSettings();
+ Invalidate();
+ }
+ Window::DataChanged( rDCEvt );
+}
+
+// drawing --------------------------------------------------------------------
+
+void ScOutlineWindow::SetEntryAreaClipRegion()
+{
+ GetOutDev()->SetClipRegion( vcl::Region(tools::Rectangle(
+ GetPoint( 0, mnMainFirstPos ),
+ GetPoint( GetOutputSizeLevel() - 1, mnMainLastPos ))));
+}
+
+void ScOutlineWindow::DrawLineRel(
+ tools::Long nLevelStart, tools::Long nEntryStart, tools::Long nLevelEnd, tools::Long nEntryEnd )
+{
+ GetOutDev()->DrawLine( GetPoint( nLevelStart, nEntryStart ), GetPoint( nLevelEnd, nEntryEnd ) );
+}
+
+void ScOutlineWindow::DrawRectRel(
+ tools::Long nLevelStart, tools::Long nEntryStart, tools::Long nLevelEnd, tools::Long nEntryEnd )
+{
+ GetOutDev()->DrawRect( GetRectangle( nLevelStart, nEntryStart, nLevelEnd, nEntryEnd ) );
+}
+
+namespace
+{
+ Image GetImage(const OUString& rId)
+ {
+ return Image(StockImage::Yes, rId);
+ }
+}
+
+void ScOutlineWindow::DrawImageRel(tools::Long nLevelPos, tools::Long nEntryPos, const OUString& rId)
+{
+ const Image& rImage = GetImage(rId);
+ GetOutDev()->SetLineColor();
+ GetOutDev()->SetFillColor( GetBackground().GetColor() );
+ Point aPos( GetPoint( nLevelPos, nEntryPos ) );
+ GetOutDev()->DrawRect( tools::Rectangle( aPos, rImage.GetSizePixel() ) );
+ GetOutDev()->DrawImage( aPos, rImage );
+}
+
+void ScOutlineWindow::DrawBorderRel( size_t nLevel, size_t nEntry, bool bPressed )
+{
+ Point aPos;
+ if ( GetImagePos( nLevel, nEntry, aPos ) )
+ {
+ OUString sId = bPressed ? OUString(RID_BMP_PRESSED) : OUString(RID_BMP_NOTPRESSED);
+ bool bClip = (nEntry != SC_OL_HEADERENTRY);
+ if ( bClip )
+ SetEntryAreaClipRegion();
+ GetOutDev()->DrawImage(aPos, GetImage(sId));
+ if ( bClip )
+ GetOutDev()->SetClipRegion();
+ }
+ mbMTPressed = bPressed;
+}
+
+void ScOutlineWindow::ShowFocus()
+{
+ if ( !HasFocus() )
+ return;
+
+ // first move to a visible position
+ ImplMoveFocusToVisible( true );
+
+ if ( !IsFocusButtonVisible() )
+ return;
+
+ Point aPos;
+ if ( GetImagePos( mnFocusLevel, mnFocusEntry, aPos ) )
+ {
+ aPos += Point( 1, 1 );
+ maFocusRect = tools::Rectangle( aPos, Size( SC_OL_BITMAPSIZE - 2, SC_OL_BITMAPSIZE - 2 ) );
+ bool bClip = (mnFocusEntry != SC_OL_HEADERENTRY);
+ if ( bClip )
+ SetEntryAreaClipRegion();
+ InvertTracking( maFocusRect, ShowTrackFlags::Small | ShowTrackFlags::TrackWindow );
+ if ( bClip )
+ GetOutDev()->SetClipRegion();
+ }
+}
+
+void ScOutlineWindow::HideFocus()
+{
+ if ( !maFocusRect.IsEmpty() )
+ {
+ bool bClip = (mnFocusEntry != SC_OL_HEADERENTRY);
+ if ( bClip )
+ SetEntryAreaClipRegion();
+ InvertTracking( maFocusRect, ShowTrackFlags::Small | ShowTrackFlags::TrackWindow );
+ if ( bClip )
+ GetOutDev()->SetClipRegion();
+ maFocusRect.SetEmpty();
+ }
+}
+
+constexpr rtl::OUStringConstExpr aLevelBmps[]=
+{
+ RID_BMP_LEVEL1,
+ RID_BMP_LEVEL2,
+ RID_BMP_LEVEL3,
+ RID_BMP_LEVEL4,
+ RID_BMP_LEVEL5,
+ RID_BMP_LEVEL6,
+ RID_BMP_LEVEL7,
+ RID_BMP_LEVEL8
+};
+
+void ScOutlineWindow::Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& /* rRect */ )
+{
+ tools::Long nEntriesSign = mbMirrorEntries ? -1 : 1;
+ tools::Long nLevelsSign = mbMirrorLevels ? -1 : 1;
+
+ Size aSize = GetOutputSizePixel();
+ tools::Long nLevelEnd = (mbHoriz ? aSize.Height() : aSize.Width()) - 1;
+ tools::Long nEntryEnd = (mbHoriz ? aSize.Width() : aSize.Height()) - 1;
+
+ GetOutDev()->SetLineColor( maLineColor );
+ tools::Long nBorderPos = mbMirrorLevels ? 0 : nLevelEnd;
+ DrawLineRel( nBorderPos, 0, nBorderPos, nEntryEnd );
+
+ const ScOutlineArray* pArray = GetOutlineArray();
+ if ( !pArray ) return;
+
+ size_t nLevelCount = GetLevelCount();
+
+ // --- draw header images ---
+
+ if ( mnHeaderSize > 0 )
+ {
+ tools::Long nEntryPos = GetHeaderEntryPos();
+ for ( size_t nLevel = 0; nLevel < nLevelCount; ++nLevel )
+ DrawImageRel(GetLevelPos(nLevel), nEntryPos, OUString(aLevelBmps[nLevel]));
+
+ GetOutDev()->SetLineColor( maLineColor );
+ tools::Long nLinePos = mnHeaderPos + (mbMirrorEntries ? 0 : (mnHeaderSize - 1));
+ DrawLineRel( 0, nLinePos, nLevelEnd, nLinePos );
+ }
+
+ // --- draw lines & collapse/expand images ---
+
+ SetEntryAreaClipRegion();
+
+ SCCOLROW nStartIndex, nEndIndex;
+ GetVisibleRange( nStartIndex, nEndIndex );
+
+ for ( size_t nLevel = 0; nLevel + 1 < nLevelCount; ++nLevel )
+ {
+ tools::Long nLevelPos = GetLevelPos( nLevel );
+ tools::Long nEntryPos1 = 0, nEntryPos2 = 0, nImagePos = 0;
+
+ size_t nEntryCount = pArray->GetCount( sal::static_int_cast<sal_uInt16>(nLevel) );
+ size_t nEntry;
+
+ // first draw all lines in the current level
+ GetOutDev()->SetLineColor();
+ GetOutDev()->SetFillColor( maLineColor );
+ for ( nEntry = 0; nEntry < nEntryCount; ++nEntry )
+ {
+ const ScOutlineEntry* pEntry = pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel),
+ sal::static_int_cast<sal_uInt16>(nEntry) );
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+
+ // visible range?
+ bool bDraw = (nEnd >= nStartIndex) && (nStart <= nEndIndex);
+ // find output coordinates
+ if ( bDraw )
+ bDraw = GetEntryPos( nLevel, nEntry, nEntryPos1, nEntryPos2, nImagePos );
+ // draw, if not collapsed
+ if ( bDraw && !pEntry->IsHidden() )
+ {
+ if ( nStart >= nStartIndex )
+ nEntryPos1 += nEntriesSign;
+ nEntryPos2 -= 2 * nEntriesSign;
+ tools::Long nLinePos = nLevelPos;
+ if ( mbMirrorLevels )
+ nLinePos += SC_OL_BITMAPSIZE - 1; // align with right edge of bitmap
+ DrawRectRel( nLinePos, nEntryPos1, nLinePos + nLevelsSign, nEntryPos2 );
+
+ if ( nEnd <= nEndIndex )
+ DrawRectRel( nLinePos, nEntryPos2 - nEntriesSign,
+ nLinePos + ( SC_OL_BITMAPSIZE / 3 ) * nLevelsSign, nEntryPos2 );
+ }
+ }
+
+ // draw all images in the level from last to first
+ nEntry = nEntryCount;
+ while ( nEntry )
+ {
+ --nEntry;
+
+ const ScOutlineEntry* pEntry = pArray->GetEntry( sal::static_int_cast<sal_uInt16>(nLevel),
+ sal::static_int_cast<sal_uInt16>(nEntry) );
+ SCCOLROW nStart = pEntry->GetStart();
+
+ // visible range?
+ bool bDraw = (nStartIndex <= nStart) && (nStart <= nEndIndex + 1);
+ // find output coordinates
+ if ( bDraw )
+ bDraw = GetEntryPos( nLevel, nEntry, nEntryPos1, nEntryPos2, nImagePos );
+ // draw, if not hidden by higher levels
+ if ( bDraw )
+ {
+ OUString sImageId = pEntry->IsHidden() ? OUString(RID_BMP_PLUS) : OUString(RID_BMP_MINUS);
+ DrawImageRel(nLevelPos, nImagePos, sImageId);
+ }
+ }
+ }
+
+ GetOutDev()->SetClipRegion();
+
+ if ( !mbDontDrawFocus )
+ ShowFocus();
+}
+
+// focus ----------------------------------------------------------------------
+
+/** Increments or decrements a value and wraps at the specified limits.
+ @return true = value wrapped. */
+static bool lcl_RotateValue( size_t& rnValue, size_t nMin, size_t nMax, bool bForward )
+{
+ OSL_ENSURE( nMin <= nMax, "lcl_RotateValue - invalid range" );
+ OSL_ENSURE( nMax < static_cast< size_t >( -1 ), "lcl_RotateValue - range overflow" );
+ bool bWrap = false;
+ if ( bForward )
+ {
+ if ( rnValue < nMax )
+ ++rnValue;
+ else
+ {
+ rnValue = nMin;
+ bWrap = true;
+ }
+ }
+ else
+ {
+ if ( rnValue > nMin )
+ --rnValue;
+ else
+ {
+ rnValue = nMax;
+ bWrap = true;
+ }
+ }
+ return bWrap;
+}
+
+bool ScOutlineWindow::IsFocusButtonVisible() const
+{
+ return IsButtonVisible( mnFocusLevel, mnFocusEntry );
+}
+
+bool ScOutlineWindow::ImplMoveFocusByEntry( bool bForward, bool bFindVisible )
+{
+ const ScOutlineArray* pArray = GetOutlineArray();
+ if ( !pArray )
+ return false;
+
+ bool bWrapped = false;
+ size_t nEntryCount = pArray->GetCount( sal::static_int_cast<sal_uInt16>(mnFocusLevel) );
+ // #i29530# entry count may be decreased after changing active sheet
+ if( mnFocusEntry >= nEntryCount )
+ mnFocusEntry = SC_OL_HEADERENTRY;
+ size_t nOldEntry = mnFocusEntry;
+
+ do
+ {
+ if ( mnFocusEntry == SC_OL_HEADERENTRY )
+ {
+ // move from header to first or last entry
+ if ( nEntryCount > 0 )
+ mnFocusEntry = bForward ? 0 : (nEntryCount - 1);
+ /* wrapped, if forward from right header to first entry,
+ or if backward from left header to last entry */
+ // Header and entries are now always in consistent order,
+ // so there's no need to check for mirroring here.
+ if ( !nEntryCount || !bForward )
+ bWrapped = true;
+ }
+ else if ( lcl_RotateValue( mnFocusEntry, 0, nEntryCount - 1, bForward ) )
+ {
+ // lcl_RotateValue returns true -> wrapped the entry range -> move to header
+ mnFocusEntry = SC_OL_HEADERENTRY;
+ /* wrapped, if forward from last entry to left header,
+ or if backward from first entry to right header */
+ if ( bForward )
+ bWrapped = true;
+ }
+ }
+ while ( bFindVisible && !IsFocusButtonVisible() && (nOldEntry != mnFocusEntry) );
+
+ return bWrapped;
+}
+
+bool ScOutlineWindow::ImplMoveFocusByLevel( bool bForward )
+{
+ const ScOutlineArray* pArray = GetOutlineArray();
+ if ( !pArray )
+ return false;
+
+ bool bWrapped = false;
+ size_t nLevelCount = GetLevelCount();
+
+ if ( mnFocusEntry == SC_OL_HEADERENTRY )
+ {
+ if ( nLevelCount > 0 )
+ bWrapped = lcl_RotateValue( mnFocusLevel, 0, nLevelCount - 1, bForward );
+ }
+ else
+ {
+ const ScOutlineEntry* pEntry = pArray->GetEntry(
+ mnFocusLevel, mnFocusEntry);
+
+ if ( pEntry )
+ {
+ SCCOLROW nStart = pEntry->GetStart();
+ SCCOLROW nEnd = pEntry->GetEnd();
+ size_t nNewLevel = mnFocusLevel;
+ size_t nNewEntry = 0;
+
+ bool bFound = false;
+ if ( bForward && (mnFocusLevel + 2 < nLevelCount) )
+ {
+ // next level -> find first child entry
+ nNewLevel = mnFocusLevel + 1;
+ bFound = pArray->GetEntryIndexInRange(nNewLevel, nStart, nEnd, nNewEntry);
+ }
+ else if ( !bForward && (mnFocusLevel > 0) )
+ {
+ // previous level -> find parent entry
+ nNewLevel = mnFocusLevel - 1;
+ bFound = pArray->GetEntryIndex(nNewLevel, nStart, nNewEntry);
+ }
+
+ if ( bFound && IsButtonVisible( nNewLevel, nNewEntry ) )
+ {
+ mnFocusLevel = nNewLevel;
+ mnFocusEntry = nNewEntry;
+ }
+ }
+ }
+
+ return bWrapped;
+}
+
+bool ScOutlineWindow::ImplMoveFocusByTabOrder( bool bForward )
+{
+ bool bRet = false;
+ size_t nOldLevel = mnFocusLevel;
+ size_t nOldEntry = mnFocusEntry;
+
+ do
+ {
+ /* one level up, if backward from left header,
+ or one level down, if forward from right header */
+ if ( (!bForward) && (mnFocusEntry == SC_OL_HEADERENTRY) )
+ bRet |= ImplMoveFocusByLevel( bForward );
+ // move to next/previous entry
+ bool bWrapInLevel = ImplMoveFocusByEntry( bForward, false );
+ bRet |= bWrapInLevel;
+ /* one level up, if wrapped backward to right header,
+ or one level down, if wrapped forward to right header */
+ if ( bForward && bWrapInLevel )
+ bRet |= ImplMoveFocusByLevel( bForward );
+ }
+ while ( !IsFocusButtonVisible() && ((nOldLevel != mnFocusLevel) || (nOldEntry != mnFocusEntry)) );
+
+ return bRet;
+}
+
+void ScOutlineWindow::ImplMoveFocusToVisible( bool bForward )
+{
+ // first try to find an entry in the same level
+ if ( !IsFocusButtonVisible() )
+ ImplMoveFocusByEntry( bForward, true );
+ // then try to find any other entry
+ if ( !IsFocusButtonVisible() )
+ ImplMoveFocusByTabOrder( bForward );
+}
+
+void ScOutlineWindow::MoveFocusByEntry( bool bForward )
+{
+ HideFocus();
+ ImplMoveFocusByEntry( bForward, true );
+ ShowFocus();
+}
+
+void ScOutlineWindow::MoveFocusByLevel( bool bForward )
+{
+ HideFocus();
+ ImplMoveFocusByLevel( bForward );
+ ShowFocus();
+}
+
+void ScOutlineWindow::MoveFocusByTabOrder( bool bForward )
+{
+ HideFocus();
+ ImplMoveFocusByTabOrder( bForward );
+ ShowFocus();
+}
+
+void ScOutlineWindow::GetFocus()
+{
+ Window::GetFocus();
+ ShowFocus();
+}
+
+void ScOutlineWindow::LoseFocus()
+{
+ HideFocus();
+ Window::LoseFocus();
+}
+
+// mouse ----------------------------------------------------------------------
+
+void ScOutlineWindow::StartMouseTracking( size_t nLevel, size_t nEntry )
+{
+ mbMTActive = true;
+ mnMTLevel = nLevel;
+ mnMTEntry = nEntry;
+ DrawBorderRel( nLevel, nEntry, true );
+}
+
+void ScOutlineWindow::EndMouseTracking()
+{
+ if ( mbMTPressed )
+ DrawBorderRel( mnMTLevel, mnMTEntry, false );
+ mbMTActive = false;
+}
+
+void ScOutlineWindow::MouseMove( const MouseEvent& rMEvt )
+{
+ if ( IsMouseTracking() )
+ {
+ size_t nLevel, nEntry;
+ bool bHit = false;
+
+ if ( ButtonHit( rMEvt.GetPosPixel(), nLevel, nEntry ) )
+ bHit = (nLevel == mnMTLevel) && (nEntry == mnMTEntry);
+
+ if ( bHit != mbMTPressed )
+ DrawBorderRel( mnMTLevel, mnMTEntry, bHit );
+ }
+}
+
+void ScOutlineWindow::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ if ( IsMouseTracking() )
+ {
+ EndMouseTracking();
+
+ size_t nLevel, nEntry;
+ if ( ButtonHit( rMEvt.GetPosPixel(), nLevel, nEntry ) )
+ if ( (nLevel == mnMTLevel) && (nEntry == mnMTEntry) )
+ DoFunction( nLevel, nEntry );
+ }
+}
+
+void ScOutlineWindow::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ size_t nLevel, nEntry;
+ bool bHit = ButtonHit( rMEvt.GetPosPixel(), nLevel, nEntry );
+ if ( bHit )
+ StartMouseTracking( nLevel, nEntry );
+ else if ( rMEvt.GetClicks() == 2 )
+ {
+ bHit = LineHit( rMEvt.GetPosPixel(), nLevel, nEntry );
+ if ( bHit )
+ DoFunction( nLevel, nEntry );
+ }
+
+ // if an item has been hit and window is focused, move focus to this item
+ if ( bHit && HasFocus() )
+ {
+ HideFocus();
+ mnFocusLevel = nLevel;
+ mnFocusEntry = nEntry;
+ ShowFocus();
+ }
+}
+
+// keyboard -------------------------------------------------------------------
+
+void ScOutlineWindow::KeyInput( const KeyEvent& rKEvt )
+{
+ const vcl::KeyCode& rKCode = rKEvt.GetKeyCode();
+ bool bNoMod = !rKCode.GetModifier();
+ bool bShift = (rKCode.GetModifier() == KEY_SHIFT);
+ bool bCtrl = (rKCode.GetModifier() == KEY_MOD1);
+
+ sal_uInt16 nCode = rKCode.GetCode();
+ bool bUpDownKey = (nCode == KEY_UP) || (nCode == KEY_DOWN);
+ bool bLeftRightKey = (nCode == KEY_LEFT) || (nCode == KEY_RIGHT);
+
+ // TAB key
+ if ( (nCode == KEY_TAB) && (bNoMod || bShift) )
+ // move forward without SHIFT key
+ MoveFocusByTabOrder( bNoMod ); // TAB uses logical order, regardless of mirroring
+
+ // LEFT/RIGHT/UP/DOWN keys
+ else if ( bNoMod && (bUpDownKey || bLeftRightKey) )
+ {
+ bool bForward = (nCode == KEY_DOWN) || (nCode == KEY_RIGHT);
+ if ( mbHoriz == bLeftRightKey )
+ // move inside level with LEFT/RIGHT in horizontal and with UP/DOWN in vertical
+ MoveFocusByEntry( bForward != mbMirrorEntries );
+ else
+ // move to next/prev level with LEFT/RIGHT in vertical and with UP/DOWN in horizontal
+ MoveFocusByLevel( bForward != mbMirrorLevels );
+ }
+
+ // CTRL + number
+ else if ( bCtrl && (nCode >= KEY_1) && (nCode <= KEY_9) )
+ {
+ size_t nLevel = static_cast< size_t >( nCode - KEY_1 );
+ if ( nLevel < GetLevelCount() )
+ DoFunction( nLevel, SC_OL_HEADERENTRY );
+ }
+
+ // other key codes
+ else switch ( rKCode.GetFullCode() )
+ {
+ case KEY_ADD: DoExpand( mnFocusLevel, mnFocusEntry ); break;
+ case KEY_SUBTRACT: DoCollapse( mnFocusLevel, mnFocusEntry ); break;
+ case KEY_SPACE:
+ case KEY_RETURN: DoFunction( mnFocusLevel, mnFocusEntry ); break;
+ default: Window::KeyInput( rKEvt );
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
new file mode 100644
index 000000000..38417d000
--- /dev/null
+++ b/sc/source/ui/view/output.cxx
@@ -0,0 +1,2698 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/brushitem.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svx/rotmodit.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/svxfont.hxx>
+#include <tools/poly.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
+#include <svtools/accessibilityoptions.hxx>
+#include <svx/framelinkarray.hxx>
+#include <drawinglayer/geometry/viewinformation2d.hxx>
+#include <drawinglayer/processor2d/baseprocessor2d.hxx>
+#include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
+#include <vcl/lineinfo.hxx>
+#include <vcl/gradient.hxx>
+#include <vcl/settings.hxx>
+#include <svx/unoapi.hxx>
+#include <sal/log.hxx>
+#include <comphelper/lok.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/range/b2drectangle.hxx>
+
+#include <output.hxx>
+#include <document.hxx>
+#include <drwlayer.hxx>
+#include <formulacell.hxx>
+#include <attrib.hxx>
+#include <patattr.hxx>
+#include <progress.hxx>
+#include <pagedata.hxx>
+#include <chgtrack.hxx>
+#include <chgviset.hxx>
+#include <viewutil.hxx>
+#include <gridmerg.hxx>
+#include <fillinfo.hxx>
+#include <scmod.hxx>
+#include <appoptio.hxx>
+#include <postit.hxx>
+#include <validat.hxx>
+#include <detfunc.hxx>
+
+#include <SparklineRenderer.hxx>
+#include <colorscale.hxx>
+
+#include <math.h>
+#include <memory>
+
+using namespace com::sun::star;
+
+// Static Data
+
+// color for ChangeTracking "by author" as in the writer (swmodul1.cxx)
+
+#define SC_AUTHORCOLORCOUNT 9
+
+const Color nAuthorColor[ SC_AUTHORCOLORCOUNT ] = {
+ COL_LIGHTRED, COL_LIGHTBLUE, COL_LIGHTMAGENTA,
+ COL_GREEN, COL_RED, COL_BLUE,
+ COL_BROWN, COL_MAGENTA, COL_CYAN };
+
+// Helper class for color assignment to avoid repeated lookups for the same user
+
+ScActionColorChanger::ScActionColorChanger( const ScChangeTrack& rTrack ) :
+ rOpt( SC_MOD()->GetAppOptions() ),
+ rUsers( rTrack.GetUserCollection() ),
+ nLastUserIndex( 0 ),
+ nColor( COL_BLACK )
+{
+}
+
+void ScActionColorChanger::Update( const ScChangeAction& rAction )
+{
+ Color nSetColor;
+ switch (rAction.GetType())
+ {
+ case SC_CAT_INSERT_COLS:
+ case SC_CAT_INSERT_ROWS:
+ case SC_CAT_INSERT_TABS:
+ nSetColor = rOpt.GetTrackInsertColor();
+ break;
+ case SC_CAT_DELETE_COLS:
+ case SC_CAT_DELETE_ROWS:
+ case SC_CAT_DELETE_TABS:
+ nSetColor = rOpt.GetTrackDeleteColor();
+ break;
+ case SC_CAT_MOVE:
+ nSetColor = rOpt.GetTrackMoveColor();
+ break;
+ default:
+ nSetColor = rOpt.GetTrackContentColor();
+ break;
+ }
+ if ( nSetColor != COL_TRANSPARENT ) // color assigned
+ nColor = nSetColor;
+ else // by author
+ {
+ if (aLastUserName != rAction.GetUser())
+ {
+ aLastUserName = rAction.GetUser();
+ std::set<OUString>::const_iterator it = rUsers.find(aLastUserName);
+ if (it == rUsers.end())
+ {
+ // empty string is possible if a name wasn't found while saving a 5.0 file
+ SAL_INFO_IF( aLastUserName.isEmpty(), "sc.ui", "Author not found" );
+ nLastUserIndex = 0;
+ }
+ else
+ {
+ size_t nPos = std::distance(rUsers.begin(), it);
+ nLastUserIndex = nPos % SC_AUTHORCOLORCOUNT;
+ }
+ }
+ nColor = nAuthorColor[nLastUserIndex];
+ }
+}
+
+ScOutputData::ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType,
+ ScTableInfo& rTabInfo, ScDocument* pNewDoc,
+ SCTAB nNewTab, tools::Long nNewScrX, tools::Long nNewScrY,
+ SCCOL nNewX1, SCROW nNewY1, SCCOL nNewX2, SCROW nNewY2,
+ double nPixelPerTwipsX, double nPixelPerTwipsY,
+ const Fraction* pZoomX, const Fraction* pZoomY ) :
+ mpDev( pNewDev ),
+ mpRefDevice( pNewDev ), // default is output device
+ pFmtDevice( pNewDev ), // default is output device
+ mrTabInfo( rTabInfo ),
+ pRowInfo( rTabInfo.mpRowInfo.get() ),
+ nArrCount( rTabInfo.mnArrCount ),
+ mpDoc( pNewDoc ),
+ nTab( nNewTab ),
+ nScrX( nNewScrX ),
+ nScrY( nNewScrY ),
+ nX1( nNewX1 ),
+ nY1( nNewY1 ),
+ nX2( nNewX2 ),
+ nY2( nNewY2 ),
+ eType( eNewType ),
+ mnPPTX( nPixelPerTwipsX ),
+ mnPPTY( nPixelPerTwipsY ),
+ pViewShell( nullptr ),
+ pDrawView( nullptr ),
+ bEditMode( false ),
+ nEditCol( 0 ),
+ nEditRow( 0 ),
+ bMetaFile( false ),
+ bPagebreakMode( false ),
+ bSolidBackground( false ),
+ mbUseStyleColor( false ),
+ mbForceAutoColor( SC_MOD()->GetAccessOptions().GetIsAutomaticFontColor() ),
+ mbSyntaxMode( false ),
+ aGridColor( COL_BLACK ),
+ mbShowNullValues( true ),
+ mbShowFormulas( false ),
+ bShowSpellErrors( false ),
+ bMarkClipped( false ), // sal_False for printer/metafile etc.
+ bSnapPixel( false ),
+ bAnyClipped( false ),
+ bVertical(false),
+ mpTargetPaintWindow(nullptr), // #i74769# use SdrPaintWindow direct
+ mpSpellCheckCxt(nullptr)
+{
+ if (pZoomX)
+ aZoomX = *pZoomX;
+ else
+ aZoomX = Fraction(1,1);
+ if (pZoomY)
+ aZoomY = *pZoomY;
+ else
+ aZoomY = Fraction(1,1);
+
+ nVisX1 = nX1;
+ nVisY1 = nY1;
+ nVisX2 = nX2;
+ nVisY2 = nY2;
+ mpDoc->StripHidden( nVisX1, nVisY1, nVisX2, nVisY2, nTab );
+
+ nScrW = 0;
+ for (SCCOL nX=nVisX1; nX<=nVisX2; nX++)
+ nScrW += pRowInfo[0].basicCellInfo(nX).nWidth;
+
+ nMirrorW = nScrW;
+
+ nScrH = 0;
+ for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
+ nScrH += pRowInfo[nArrY].nHeight;
+
+ bTabProtected = mpDoc->IsTabProtected( nTab );
+ bLayoutRTL = mpDoc->IsLayoutRTL( nTab );
+
+ // always needed, so call at the end of the constructor
+ SetCellRotations();
+}
+
+ScOutputData::~ScOutputData()
+{
+}
+
+void ScOutputData::SetSpellCheckContext( const sc::SpellCheckContext* pCxt )
+{
+ mpSpellCheckCxt = pCxt;
+}
+
+void ScOutputData::SetContentDevice( OutputDevice* pContentDev )
+{
+ // use pContentDev instead of pDev where used
+
+ if ( mpRefDevice == mpDev )
+ mpRefDevice = pContentDev;
+ if ( pFmtDevice == mpDev )
+ pFmtDevice = pContentDev;
+ mpDev = pContentDev;
+}
+
+void ScOutputData::SetMirrorWidth( tools::Long nNew )
+{
+ nMirrorW = nNew;
+}
+
+void ScOutputData::SetGridColor( const Color& rColor )
+{
+ aGridColor = rColor;
+}
+
+void ScOutputData::SetMarkClipped( bool bSet )
+{
+ bMarkClipped = bSet;
+}
+
+void ScOutputData::SetShowNullValues( bool bSet )
+{
+ mbShowNullValues = bSet;
+}
+
+void ScOutputData::SetShowFormulas( bool bSet )
+{
+ mbShowFormulas = bSet;
+}
+
+void ScOutputData::SetShowSpellErrors( bool bSet )
+{
+ bShowSpellErrors = bSet;
+}
+
+void ScOutputData::SetSnapPixel()
+{
+ bSnapPixel = true;
+}
+
+void ScOutputData::SetEditCell( SCCOL nCol, SCROW nRow )
+{
+ nEditCol = nCol;
+ nEditRow = nRow;
+ bEditMode = true;
+}
+
+void ScOutputData::SetMetaFileMode( bool bNewMode )
+{
+ bMetaFile = bNewMode;
+}
+
+void ScOutputData::SetSyntaxMode( bool bNewMode )
+{
+ mbSyntaxMode = bNewMode;
+ if ( bNewMode && !mxValueColor )
+ {
+ const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
+ mxValueColor = rColorCfg.GetColorValue( svtools::CALCVALUE ).nColor;
+ mxTextColor = rColorCfg.GetColorValue( svtools::CALCTEXT ).nColor;
+ mxFormulaColor = rColorCfg.GetColorValue( svtools::CALCFORMULA ).nColor;
+ }
+}
+
+void ScOutputData::DrawGrid(vcl::RenderContext& rRenderContext, bool bGrid, bool bPage, bool bMergeCover)
+{
+ // bMergeCover : Draw lines in sheet bgcolor to cover lok client grid lines in merged cell areas.
+ // When scNoGridBackground is set in lok mode, bMergeCover is set to true and bGrid to false.
+
+ SCCOL nX;
+ SCROW nY;
+ tools::Long nPosX;
+ tools::Long nPosY;
+ SCSIZE nArrY;
+ ScBreakType nBreak = ScBreakType::NONE;
+ ScBreakType nBreakOld = ScBreakType::NONE;
+
+ bool bSingle;
+ bool bDashed = false;
+ Color aPageColor;
+ Color aManualColor;
+
+ if (bPagebreakMode)
+ bPage = false; // no "normal" breaks over the whole width/height
+
+ // It is a big mess to distinguish when we are using pixels and when logic
+ // units for drawing. Ultimately we want to work only in the logic units,
+ // but until that happens, we need to special-case:
+ //
+ // * metafile
+ // * drawing to the screen - everything is internally counted in pixels there
+ //
+ // 'Internally' in the above means the pCellInfo[...].nWidth and
+ // pRowInfo[...]->nHeight:
+ //
+ // * when bWorksInPixels is true: these are in pixels
+ // * when bWorksInPixels is false: these are in the logic units
+ //
+ // This is where all the confusion comes from, ultimately we want them
+ // always in the logic units (100th of millimeters), but we need to get
+ // there gradually (get rid of setting MapUnit::MapPixel first), otherwise we'd
+ // break all the drawing by one change.
+ // So until that happens, we need to special case.
+ bool bWorksInPixels = bMetaFile;
+ const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
+ Color aSheetBGColor = rColorCfg.GetColorValue(::svtools::DOCCOLOR).nColor;
+
+ if ( eType == OUTTYPE_WINDOW )
+ {
+ bWorksInPixels = true;
+ aPageColor = rColorCfg.GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor;
+ aManualColor = rColorCfg.GetColorValue(svtools::CALCPAGEBREAKMANUAL).nColor;
+ }
+ else
+ {
+ aPageColor = aGridColor;
+ aManualColor = aGridColor;
+ }
+
+ tools::Long nOneX = 1;
+ tools::Long nOneY = 1;
+ if (!bWorksInPixels)
+ {
+ Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
+ nOneX = aOnePixel.Width();
+ nOneY = aOnePixel.Height();
+ }
+
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+ tools::Long nSignedOneX = nOneX * nLayoutSign;
+
+ rRenderContext.SetLineColor(bMergeCover ? aSheetBGColor : aGridColor);
+
+ ScGridMerger aGrid(&rRenderContext, nOneX, nOneY);
+
+ // vertical lines
+
+ nPosX = nScrX;
+ if ( bLayoutRTL )
+ nPosX += nMirrorW - nOneX;
+
+ for (nX=nX1; nX<=nX2; nX++)
+ {
+ sal_uInt16 nWidth = pRowInfo[0].basicCellInfo(nX).nWidth;
+ if (nWidth)
+ {
+ nPosX += nWidth * nLayoutSign;
+
+ if ( bPage )
+ {
+ // Search also in hidden part for page breaks
+ SCCOL nCol = nX + 1;
+ while (nCol <= mpDoc->MaxCol())
+ {
+ nBreak = mpDoc->HasColBreak(nCol, nTab);
+ bool bHidden = mpDoc->ColHidden(nCol, nTab);
+
+ if ( nBreak != ScBreakType::NONE || !bHidden )
+ break;
+ ++nCol;
+ }
+
+ if (nBreak != nBreakOld)
+ {
+ aGrid.Flush();
+
+ if (static_cast<int>(nBreak))
+ {
+ rRenderContext.SetLineColor( (nBreak & ScBreakType::Manual) ? aManualColor :
+ aPageColor );
+ bDashed = true;
+ }
+ else
+ {
+ rRenderContext.SetLineColor(bMergeCover ? aSheetBGColor : aGridColor);
+ bDashed = false;
+ }
+
+ nBreakOld = nBreak;
+ }
+ }
+
+ bool bDraw = bGrid || nBreakOld != ScBreakType::NONE || bMergeCover; // simple grid only if set that way
+
+ sal_uInt16 nWidthXplus1 = pRowInfo[0].basicCellInfo(nX+1).nWidth;
+ bSingle = false; //! get into Fillinfo !!!!!
+ if ( nX<mpDoc->MaxCol() && !bSingle )
+ {
+ bSingle = ( nWidthXplus1 == 0 );
+ for (nArrY=1; nArrY+1<nArrCount && !bSingle; nArrY++)
+ {
+ if (pRowInfo[nArrY].cellInfo(nX+1).bHOverlapped)
+ bSingle = true;
+ if (pRowInfo[nArrY].cellInfo(nX).bHideGrid)
+ bSingle = true;
+ }
+ }
+
+ if (bDraw)
+ {
+ if ( nX<mpDoc->MaxCol() && bSingle )
+ {
+ SCCOL nVisX = nX + 1;
+ while ( nVisX < mpDoc->MaxCol() && !mpDoc->GetColWidth(nVisX,nTab) )
+ ++nVisX;
+
+ nPosY = nScrY;
+ for (nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ const tools::Long nNextY = nPosY + pThisRowInfo->nHeight;
+
+ bool bHOver = pThisRowInfo->cellInfo(nX).bHideGrid;
+ if (!bHOver)
+ {
+ if (nWidthXplus1)
+ bHOver = pThisRowInfo->cellInfo(nX+1).bHOverlapped;
+ else
+ {
+ if (nVisX <= nX2)
+ bHOver = pThisRowInfo->cellInfo(nVisX).bHOverlapped;
+ else
+ bHOver = mpDoc->GetAttr(
+ nVisX,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG)
+ ->IsHorOverlapped();
+ if (bHOver)
+ bHOver = mpDoc->GetAttr(
+ nX + 1,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG)
+ ->IsHorOverlapped();
+ }
+ }
+
+ if ((pThisRowInfo->bChanged && !bHOver && !bMergeCover) || (bHOver && bMergeCover))
+ {
+ aGrid.AddVerLine(bWorksInPixels, nPosX-nSignedOneX, nPosY, nNextY-nOneY, bDashed);
+ }
+ nPosY = nNextY;
+ }
+ }
+ else if (!bMergeCover)
+ {
+ aGrid.AddVerLine(bWorksInPixels, nPosX-nSignedOneX, nScrY, nScrY+nScrH-nOneY, bDashed);
+ }
+ }
+ }
+ }
+
+ // horizontal lines
+
+ bool bHiddenRow = true;
+ SCROW nHiddenEndRow = -1;
+ nPosY = nScrY;
+ for (nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ SCSIZE nArrYplus1 = nArrY+1;
+ nY = pRowInfo[nArrY].nRowNo;
+ SCROW nYplus1 = nY+1;
+ nPosY += pRowInfo[nArrY].nHeight;
+
+ if (pRowInfo[nArrY].bChanged)
+ {
+ if ( bPage )
+ {
+ for (SCROW i = nYplus1; i <= mpDoc->MaxRow(); ++i)
+ {
+ if (i > nHiddenEndRow)
+ bHiddenRow = mpDoc->RowHidden(i, nTab, nullptr, &nHiddenEndRow);
+ /* TODO: optimize the row break thing for large hidden
+ * segments where HasRowBreak() has to be called
+ * nevertheless for each row, as a row break is drawn also
+ * for hidden rows, above them. This needed to be done only
+ * once per hidden segment, maybe giving manual breaks
+ * priority. Something like GetNextRowBreak() and
+ * GetNextManualRowBreak(). */
+ nBreak = mpDoc->HasRowBreak(i, nTab);
+ if (!bHiddenRow || nBreak != ScBreakType::NONE)
+ break;
+ }
+
+ if (nBreakOld != nBreak)
+ {
+ aGrid.Flush();
+
+ if (static_cast<int>(nBreak))
+ {
+ rRenderContext.SetLineColor( (nBreak & ScBreakType::Manual) ? aManualColor :
+ aPageColor );
+ bDashed = true;
+ }
+ else
+ {
+ rRenderContext.SetLineColor(bMergeCover ? aSheetBGColor : aGridColor);
+ bDashed = false;
+ }
+
+ nBreakOld = nBreak;
+ }
+ }
+
+ bool bDraw = bGrid || nBreakOld != ScBreakType::NONE || bMergeCover; // simple grid only if set so
+
+ bool bNextYisNextRow = (pRowInfo[nArrYplus1].nRowNo == nYplus1);
+ bSingle = !bNextYisNextRow; // Hidden
+ for (SCCOL i=nX1; i<=nX2 && !bSingle; i++)
+ {
+ if (pRowInfo[nArrYplus1].cellInfo(i).bVOverlapped)
+ bSingle = true;
+ }
+
+ if (bDraw)
+ {
+ if ( bSingle && nY<mpDoc->MaxRow() )
+ {
+ SCROW nVisY = pRowInfo[nArrYplus1].nRowNo;
+
+ nPosX = nScrX;
+ if ( bLayoutRTL )
+ nPosX += nMirrorW - nOneX;
+
+ for (SCCOL i=nX1; i<=nX2; i++)
+ {
+ const tools::Long nNextX = nPosX + pRowInfo[0].basicCellInfo(i).nWidth * nLayoutSign;
+ if (nNextX != nPosX) // visible
+ {
+ bool bVOver;
+ if ( bNextYisNextRow )
+ bVOver = pRowInfo[nArrYplus1].cellInfo(i).bVOverlapped;
+ else
+ {
+ bVOver = mpDoc->GetAttr(
+ i,nYplus1,nTab,ATTR_MERGE_FLAG)
+ ->IsVerOverlapped()
+ && mpDoc->GetAttr(
+ i,nVisY,nTab,ATTR_MERGE_FLAG)
+ ->IsVerOverlapped();
+ //! nVisY from Array ??
+ }
+
+ if ((!bVOver && !bMergeCover) || (bVOver && bMergeCover))
+ {
+ aGrid.AddHorLine(bWorksInPixels, nPosX, nNextX-nSignedOneX, nPosY-nOneY, bDashed);
+ }
+ }
+ nPosX = nNextX;
+ }
+ }
+ else if (!bMergeCover)
+ {
+ aGrid.AddHorLine(bWorksInPixels, nScrX, nScrX+nScrW-nOneX, nPosY-nOneY, bDashed);
+ }
+ }
+ }
+ }
+}
+
+void ScOutputData::SetPagebreakMode( ScPageBreakData* pPageData )
+{
+ bPagebreakMode = true;
+ if (!pPageData)
+ return; // not yet initialized -> everything "not printed"
+
+ // mark printed range
+ // (everything in FillInfo is already initialized to sal_False)
+
+ sal_uInt16 nRangeCount = sal::static_int_cast<sal_uInt16>(pPageData->GetCount());
+ for (sal_uInt16 nPos=0; nPos<nRangeCount; nPos++)
+ {
+ ScRange aRange = pPageData->GetData( nPos ).GetPrintRange();
+
+ SCCOL nStartX = std::max( aRange.aStart.Col(), nX1 );
+ SCCOL nEndX = std::min( aRange.aEnd.Col(), nX2 );
+ SCROW nStartY = std::max( aRange.aStart.Row(), nY1 );
+ SCROW nEndY = std::min( aRange.aEnd.Row(), nY2 );
+
+ for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ if ( pThisRowInfo->bChanged && pThisRowInfo->nRowNo >= nStartY &&
+ pThisRowInfo->nRowNo <= nEndY )
+ {
+ for (SCCOL nX=nStartX; nX<=nEndX; nX++)
+ pThisRowInfo->cellInfo(nX).bPrinted = true;
+ }
+ }
+ }
+}
+
+void ScOutputData::SetCellRotations()
+{
+ //! save nRotMax
+ SCCOL nRotMax = nX2;
+ for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
+ if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
+ nRotMax = pRowInfo[nRotY].nRotMaxCol;
+
+ for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ if ( pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE &&
+ ( pThisRowInfo->bChanged || pRowInfo[nArrY-1].bChanged ||
+ ( nArrY+1<nArrCount && pRowInfo[nArrY+1].bChanged ) ) )
+ {
+ SCROW nY = pThisRowInfo->nRowNo;
+
+ for (SCCOL nX=0; nX<=nRotMax; nX++)
+ {
+ ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
+ const ScPatternAttr* pPattern = pInfo->pPatternAttr;
+ const SfxItemSet* pCondSet = pInfo->pConditionSet;
+
+ if ( !pPattern && !mpDoc->ColHidden(nX, nTab) )
+ {
+ pPattern = mpDoc->GetPattern( nX, nY, nTab );
+ pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
+ }
+
+ if ( pPattern ) // column isn't hidden
+ {
+ ScRotateDir nDir = pPattern->GetRotateDir( pCondSet );
+ if (nDir != ScRotateDir::NONE)
+ {
+ // Needed for ScCellInfo internal decisions (bg fill, ...)
+ pInfo->nRotateDir = nDir;
+
+ // create target coordinates
+ const SCCOL nTargetX(nX - nVisX1 + 1);
+ const SCROW nTargetY(nY - nVisY1 + 1);
+
+ // Check for values - below in SetCellRotation these will
+ // be converted to size_t and thus may not be negative
+ if(nTargetX >= 0 && nTargetY >= 0)
+ {
+ // add rotation info to Array information
+ const Degree100 nAttrRotate(pPattern->GetRotateVal(pCondSet));
+ const SvxRotateMode eRotMode(pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue());
+ const double fOrient((bLayoutRTL ? -1.0 : 1.0) * toRadians(nAttrRotate)); // 1/100th degrees -> [0..2PI]
+ svx::frame::Array& rArray = mrTabInfo.maArray;
+
+ rArray.SetCellRotation(nTargetX, nTargetY, eRotMode, fOrient);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static ScRotateDir lcl_GetRotateDir( const ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
+ const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
+
+ ScRotateDir nRet = ScRotateDir::NONE;
+
+ Degree100 nAttrRotate = pPattern->GetRotateVal( pCondSet );
+ if ( nAttrRotate )
+ {
+ SvxRotateMode eRotMode =
+ pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue();
+
+ if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
+ nRet = ScRotateDir::Standard;
+ else if ( eRotMode == SVX_ROTATE_MODE_CENTER )
+ nRet = ScRotateDir::Center;
+ else if ( eRotMode == SVX_ROTATE_MODE_TOP || eRotMode == SVX_ROTATE_MODE_BOTTOM )
+ {
+ tools::Long nRot180 = nAttrRotate.get() % 18000; // 1/100 degree
+ if ( nRot180 == 9000 )
+ nRet = ScRotateDir::Center;
+ else if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nRot180 < 9000 ) ||
+ ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nRot180 > 9000 ) )
+ nRet = ScRotateDir::Left;
+ else
+ nRet = ScRotateDir::Right;
+ }
+ }
+
+ return nRet;
+}
+
+static const SvxBrushItem* lcl_FindBackground( const ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
+ const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
+ const SvxBrushItem* pBackground =
+ &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
+
+ ScRotateDir nDir = lcl_GetRotateDir( pDoc, nCol, nRow, nTab );
+
+ // treat CENTER like RIGHT
+ if ( nDir == ScRotateDir::Right || nDir == ScRotateDir::Center )
+ {
+ // text goes to the right -> take background from the left
+ while ( nCol > 0 && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
+ pBackground->GetColor().GetAlpha() != 0 )
+ {
+ --nCol;
+ pPattern = pDoc->GetPattern( nCol, nRow, nTab );
+ pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
+ pBackground = &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
+ }
+ }
+ else if ( nDir == ScRotateDir::Left )
+ {
+ // text goes to the left -> take background from the right
+ while ( nCol < pDoc->MaxCol() && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
+ pBackground->GetColor().GetAlpha() != 0 )
+ {
+ ++nCol;
+ pPattern = pDoc->GetPattern( nCol, nRow, nTab );
+ pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
+ pBackground = &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
+ }
+ }
+
+ return pBackground;
+}
+
+static bool lcl_EqualBack( const RowInfo& rFirst, const RowInfo& rOther,
+ SCCOL nX1, SCCOL nX2, bool bShowProt, bool bPagebreakMode )
+{
+ if ( rFirst.bChanged != rOther.bChanged ||
+ rFirst.bEmptyBack != rOther.bEmptyBack )
+ return false;
+
+ SCCOL nX;
+ if ( bShowProt )
+ {
+ for ( nX=nX1; nX<=nX2; nX++ )
+ {
+ const ScPatternAttr* pPat1 = rFirst.cellInfo(nX).pPatternAttr;
+ const ScPatternAttr* pPat2 = rOther.cellInfo(nX).pPatternAttr;
+ if ( !pPat1 || !pPat2 ||
+ &pPat1->GetItem(ATTR_PROTECTION) != &pPat2->GetItem(ATTR_PROTECTION) )
+ return false;
+ }
+ }
+ else
+ {
+ for ( nX=nX1; nX<=nX2; nX++ )
+ if ( rFirst.cellInfo(nX).pBackground != rOther.cellInfo(nX).pBackground )
+ return false;
+ }
+
+ if ( rFirst.nRotMaxCol != SC_ROTMAX_NONE || rOther.nRotMaxCol != SC_ROTMAX_NONE )
+ for ( nX=nX1; nX<=nX2; nX++ )
+ if ( rFirst.cellInfo(nX).nRotateDir != rOther.cellInfo(nX).nRotateDir )
+ return false;
+
+ if ( bPagebreakMode )
+ for ( nX=nX1; nX<=nX2; nX++ )
+ if ( rFirst.cellInfo(nX).bPrinted != rOther.cellInfo(nX).bPrinted )
+ return false;
+
+ for ( nX=nX1; nX<=nX2; nX++ )
+ {
+ std::optional<Color> const & pCol1 = rFirst.cellInfo(nX).mxColorScale;
+ std::optional<Color> const & pCol2 = rOther.cellInfo(nX).mxColorScale;
+ if( (pCol1 && !pCol2) || (!pCol1 && pCol2) )
+ return false;
+
+ if (pCol1 && (*pCol1 != *pCol2))
+ return false;
+
+ const ScDataBarInfo* pInfo1 = rFirst.cellInfo(nX).pDataBar;
+ const ScDataBarInfo* pInfo2 = rOther.cellInfo(nX).pDataBar;
+
+ if( (pInfo1 && !pInfo2) || (!pInfo1 && pInfo2) )
+ return false;
+
+ if (pInfo1 && (*pInfo1 != *pInfo2))
+ return false;
+
+ // each cell with an icon set should be painted the same way
+ const ScIconSetInfo* pIconSet1 = rFirst.cellInfo(nX).pIconSet;
+ const ScIconSetInfo* pIconSet2 = rOther.cellInfo(nX).pIconSet;
+
+ if(pIconSet1 || pIconSet2)
+ return false;
+ }
+
+ return true;
+}
+
+void ScOutputData::DrawDocumentBackground()
+{
+ if ( !bSolidBackground )
+ return;
+
+ Color aBgColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
+ mpDev->SetLineColor(aBgColor);
+ mpDev->SetFillColor(aBgColor);
+
+ Point aScreenPos = mpDev->PixelToLogic(Point(nScrX, nScrY));
+ Size aScreenSize = mpDev->PixelToLogic(Size(nScrW - 1,nScrH - 1));
+
+ mpDev->DrawRect(tools::Rectangle(aScreenPos, aScreenSize));
+}
+
+namespace {
+
+const double lclCornerRectTransparency = 40.0;
+
+void drawDataBars(vcl::RenderContext& rRenderContext, const ScDataBarInfo* pOldDataBarInfo, const tools::Rectangle& rRect, tools::Long nOneX, tools::Long nOneY)
+{
+ tools::Long nPosZero = 0;
+ tools::Rectangle aPaintRect = rRect;
+ aPaintRect.AdjustTop(2 * nOneY );
+ aPaintRect.AdjustBottom( -(2 * nOneY) );
+ aPaintRect.AdjustLeft( 2 * nOneX );
+ aPaintRect.AdjustRight( -(2 * nOneX) );
+ if(pOldDataBarInfo->mnZero)
+ {
+ // need to calculate null point in cell
+ tools::Long nLength = aPaintRect.Right() - aPaintRect.Left();
+ nPosZero = static_cast<tools::Long>(aPaintRect.Left() + nLength*pOldDataBarInfo->mnZero/100.0);
+ }
+ else
+ {
+ nPosZero = aPaintRect.Left();
+ }
+
+ if(pOldDataBarInfo->mnLength < 0)
+ {
+ aPaintRect.SetRight( nPosZero );
+ tools::Long nLength = nPosZero - aPaintRect.Left();
+ aPaintRect.SetLeft( nPosZero + static_cast<tools::Long>(nLength * pOldDataBarInfo->mnLength/100.0) );
+ }
+ else if(pOldDataBarInfo->mnLength > 0)
+ {
+ aPaintRect.SetLeft( nPosZero );
+ tools::Long nLength = aPaintRect.Right() - nPosZero;
+ aPaintRect.SetRight( nPosZero + static_cast<tools::Long>(nLength * pOldDataBarInfo->mnLength/100.0) );
+ }
+ else
+ return;
+
+ if(pOldDataBarInfo->mbGradient)
+ {
+ rRenderContext.SetLineColor(pOldDataBarInfo->maColor);
+ Gradient aGradient(GradientStyle::Linear, pOldDataBarInfo->maColor, COL_TRANSPARENT);
+ aGradient.SetSteps(255);
+
+ if(pOldDataBarInfo->mnLength < 0)
+ aGradient.SetAngle(2700_deg10);
+ else
+ aGradient.SetAngle(900_deg10);
+
+ rRenderContext.DrawGradient(aPaintRect, aGradient);
+
+ rRenderContext.SetLineColor();
+ }
+ else
+ {
+ rRenderContext.SetFillColor(pOldDataBarInfo->maColor);
+ rRenderContext.DrawRect(aPaintRect);
+ }
+
+ //draw axis
+ if(!(pOldDataBarInfo->mnZero && pOldDataBarInfo->mnZero != 100))
+ return;
+
+ Point aPoint1(nPosZero, rRect.Top());
+ Point aPoint2(nPosZero, rRect.Bottom());
+ LineInfo aLineInfo(LineStyle::Dash, 1);
+ aLineInfo.SetDashCount( 4 );
+ aLineInfo.SetDistance( 3 );
+ aLineInfo.SetDashLen( 3 );
+ rRenderContext.SetFillColor(pOldDataBarInfo->maAxisColor);
+ rRenderContext.SetLineColor(pOldDataBarInfo->maAxisColor);
+ rRenderContext.DrawLine(aPoint1, aPoint2, aLineInfo);
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor();
+}
+
+const BitmapEx& getIcon(sc::IconSetBitmapMap & rIconSetBitmapMap, ScIconSetType eType, sal_Int32 nIndex)
+{
+ return ScIconSetFormat::getBitmap(rIconSetBitmapMap, eType, nIndex);
+}
+
+void drawIconSets(vcl::RenderContext& rRenderContext, const ScIconSetInfo* pOldIconSetInfo, const tools::Rectangle& rRect, tools::Long nOneX, tools::Long nOneY,
+ sc::IconSetBitmapMap & rIconSetBitmapMap)
+{
+ ScIconSetType eType = pOldIconSetInfo->eIconSetType;
+ sal_Int32 nIndex = pOldIconSetInfo->nIconIndex;
+ const BitmapEx& rIcon = getIcon(rIconSetBitmapMap, eType, nIndex);
+
+ tools::Long aHeight = o3tl::convert(10, o3tl::Length::pt, o3tl::Length::mm100);
+
+ if (pOldIconSetInfo->mnHeight)
+ {
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ aHeight = rRenderContext.LogicToPixel(Size(0, pOldIconSetInfo->mnHeight), MapMode(MapUnit::MapTwip)).Height();
+ aHeight *= comphelper::LibreOfficeKit::getDPIScale();
+ }
+ else
+ {
+ aHeight = o3tl::convert(pOldIconSetInfo->mnHeight, o3tl::Length::twip, o3tl::Length::mm100);
+ }
+ }
+
+ Size aSize = rIcon.GetSizePixel();
+ double fRatio = static_cast<double>(aSize.Width()) / aSize.Height();
+ tools::Long aWidth = fRatio * aHeight;
+
+ rRenderContext.Push();
+ rRenderContext.SetClipRegion(vcl::Region(rRect));
+ rRenderContext.DrawBitmapEx(Point(rRect.Left() + 2 * nOneX, rRect.Bottom() - 2 * nOneY - aHeight), Size(aWidth, aHeight), rIcon);
+ rRenderContext.Pop();
+}
+
+void drawCells(vcl::RenderContext& rRenderContext, std::optional<Color> const & pColor, const SvxBrushItem* pBackground, std::optional<Color>& pOldColor, const SvxBrushItem*& pOldBackground,
+ tools::Rectangle& rRect, tools::Long nPosX, tools::Long nLayoutSign, tools::Long nOneX, tools::Long nOneY, const ScDataBarInfo* pDataBarInfo, const ScDataBarInfo*& pOldDataBarInfo,
+ const ScIconSetInfo* pIconSetInfo, const ScIconSetInfo*& pOldIconSetInfo,
+ sc::IconSetBitmapMap & rIconSetBitmapMap)
+{
+ tools::Long nSignedOneX = nOneX * nLayoutSign;
+ // need to paint if old color scale has been used and now
+ // we have a different color or a style based background
+ // we can here fall back to pointer comparison
+ if (pOldColor && (pBackground || pOldColor != pColor || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo))
+ {
+ rRect.SetRight( nPosX-nSignedOneX );
+ if( !pOldColor->IsTransparent() )
+ {
+ rRenderContext.SetFillColor( *pOldColor );
+ rRenderContext.DrawRect( rRect );
+ }
+ if( pOldDataBarInfo )
+ drawDataBars(rRenderContext, pOldDataBarInfo, rRect, nOneX, nOneY);
+ if( pOldIconSetInfo )
+ drawIconSets(rRenderContext, pOldIconSetInfo, rRect, nOneX, nOneY, rIconSetBitmapMap);
+
+ rRect.SetLeft( nPosX - nSignedOneX );
+ }
+
+ if ( pOldBackground && (pColor ||pBackground != pOldBackground || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo) )
+ {
+ rRect.SetRight( nPosX-nSignedOneX );
+ if (pOldBackground) // ==0 if hidden
+ {
+ Color aBackCol = pOldBackground->GetColor();
+ if ( !aBackCol.IsTransparent() ) //! partial transparency?
+ {
+ rRenderContext.SetFillColor( aBackCol );
+ rRenderContext.DrawRect( rRect );
+ }
+ }
+ if( pOldDataBarInfo )
+ drawDataBars(rRenderContext, pOldDataBarInfo, rRect, nOneX, nOneY);
+ if( pOldIconSetInfo )
+ drawIconSets(rRenderContext, pOldIconSetInfo, rRect, nOneX, nOneY, rIconSetBitmapMap);
+
+ rRect.SetLeft( nPosX - nSignedOneX );
+ }
+
+ if (!pOldBackground && !pOldColor && (pDataBarInfo || pIconSetInfo))
+ {
+ rRect.SetRight( nPosX -nSignedOneX );
+ rRect.SetLeft( nPosX - nSignedOneX );
+ }
+
+ if(pColor)
+ {
+ // only update pOldColor if the colors changed
+ if (!pOldColor || *pOldColor != *pColor)
+ pOldColor = pColor;
+
+ pOldBackground = nullptr;
+ }
+ else if(pBackground)
+ {
+ pOldBackground = pBackground;
+ pOldColor.reset();
+ }
+
+ if(pDataBarInfo)
+ pOldDataBarInfo = pDataBarInfo;
+ else
+ pOldDataBarInfo = nullptr;
+
+ if(pIconSetInfo)
+ pOldIconSetInfo = pIconSetInfo;
+ else
+ pOldIconSetInfo = nullptr;
+}
+
+}
+
+void ScOutputData::DrawBackground(vcl::RenderContext& rRenderContext)
+{
+ Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
+ tools::Long nOneXLogic = aOnePixel.Width();
+ tools::Long nOneYLogic = aOnePixel.Height();
+
+ // See more about bWorksInPixels in ScOutputData::DrawGrid
+ bool bWorksInPixels = false;
+ if (eType == OUTTYPE_WINDOW)
+ bWorksInPixels = true;
+
+ tools::Long nOneX = 1;
+ tools::Long nOneY = 1;
+ if (!bWorksInPixels)
+ {
+ nOneX = nOneXLogic;
+ nOneY = nOneYLogic;
+ }
+
+ tools::Rectangle aRect;
+
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ rRenderContext.SetLineColor();
+
+ bool bShowProt = mbSyntaxMode && mpDoc->IsTabProtected(nTab);
+ bool bDoAll = bShowProt || bPagebreakMode || bSolidBackground;
+
+ bool bCellContrast = mbUseStyleColor &&
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode();
+
+ tools::Long nPosY = nScrY;
+
+ const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
+ Color aProtectedColor( rColorCfg.GetColorValue( svtools::CALCPROTECTEDBACKGROUND ).nColor );
+ auto pProtectedBackground = std::make_shared<SvxBrushItem>( aProtectedColor, ATTR_BACKGROUND );
+
+ // iterate through the rows to show
+ for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ tools::Long nRowHeight = pThisRowInfo->nHeight;
+
+ if ( pThisRowInfo->bChanged )
+ {
+ if ( ( ( pThisRowInfo->bEmptyBack ) || mbSyntaxMode ) && !bDoAll )
+ {
+ // nothing
+ }
+ else
+ {
+ // scan for rows with the same background:
+ SCSIZE nSkip = 0;
+ while ( nArrY+nSkip+2<nArrCount &&
+ lcl_EqualBack( *pThisRowInfo, pRowInfo[nArrY+nSkip+1],
+ nX1, nX2, bShowProt, bPagebreakMode ) )
+ {
+ ++nSkip;
+ nRowHeight += pRowInfo[nArrY+nSkip].nHeight; // after incrementing
+ }
+
+ tools::Long nPosX = nScrX;
+
+ if ( bLayoutRTL )
+ nPosX += nMirrorW - nOneX;
+
+ aRect = tools::Rectangle(nPosX, nPosY - nOneY, nPosX, nPosY - nOneY + nRowHeight);
+ if (bWorksInPixels)
+ aRect = rRenderContext.PixelToLogic(aRect); // internal data in pixels, but we'll be drawing in logic units
+
+ const SvxBrushItem* pOldBackground = nullptr;
+ const SvxBrushItem* pBackground = nullptr;
+ std::optional<Color> pOldColor;
+ const ScDataBarInfo* pOldDataBarInfo = nullptr;
+ const ScIconSetInfo* pOldIconSetInfo = nullptr;
+ SCCOL nMergedCols = 1;
+ SCCOL nOldMerged = 0;
+
+ for (SCCOL nX=nX1; nX + nMergedCols <= nX2 + 1; nX += nOldMerged)
+ {
+ ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX-1+nMergedCols);
+
+ nOldMerged = nMergedCols;
+
+ tools::Long nNewPosX = nPosX;
+ // extend for all merged cells
+ nMergedCols = 1;
+ if (pInfo->bMerged && pInfo->pPatternAttr)
+ {
+ const ScMergeAttr* pMerge =
+ &pInfo->pPatternAttr->GetItem(ATTR_MERGE);
+ nMergedCols = std::max<SCCOL>(1, pMerge->GetColMerge());
+ }
+
+ for (SCCOL nMerged = 0; nMerged < nMergedCols; ++nMerged)
+ {
+ SCCOL nCol = nX+nOldMerged+nMerged;
+ if (nCol > nX2+2)
+ break;
+ nNewPosX += pRowInfo[0].basicCellInfo(nCol-1).nWidth * nLayoutSign;
+ }
+
+ if (nNewPosX == nPosX)
+ continue; // Zero width, no need to draw.
+
+ if (bCellContrast)
+ {
+ // high contrast for cell borders and backgrounds -> empty background
+ pBackground = ScGlobal::GetEmptyBrushItem();
+ }
+ else if (bShowProt) // show cell protection in syntax mode
+ {
+ const ScPatternAttr* pP = pInfo->pPatternAttr;
+ if (pP)
+ {
+ const ScProtectionAttr& rProt = pP->GetItem(ATTR_PROTECTION);
+ if (rProt.GetProtection() || rProt.GetHideCell())
+ pBackground = pProtectedBackground.get();
+ else
+ pBackground = ScGlobal::GetEmptyBrushItem();
+ }
+ else
+ pBackground = nullptr;
+ }
+ else
+ pBackground = pInfo->pBackground;
+
+ if ( bPagebreakMode && !pInfo->bPrinted )
+ pBackground = pProtectedBackground.get();
+
+ if ( pInfo->nRotateDir > ScRotateDir::Standard &&
+ !pBackground->GetColor().IsFullyTransparent() &&
+ !bCellContrast )
+ {
+ SCROW nY = pRowInfo[nArrY].nRowNo;
+ pBackground = lcl_FindBackground( mpDoc, nX, nY, nTab );
+ }
+
+ std::optional<Color> const & pColor = pInfo->mxColorScale;
+ const ScDataBarInfo* pDataBarInfo = pInfo->pDataBar;
+ const ScIconSetInfo* pIconSetInfo = pInfo->pIconSet;
+
+ tools::Long nPosXLogic = nPosX;
+ if (bWorksInPixels)
+ nPosXLogic = rRenderContext.PixelToLogic(Point(nPosX, 0)).X();
+
+ drawCells(rRenderContext, pColor, pBackground, pOldColor, pOldBackground, aRect, nPosXLogic, nLayoutSign, nOneXLogic, nOneYLogic, pDataBarInfo, pOldDataBarInfo, pIconSetInfo, pOldIconSetInfo, mpDoc->GetIconSetBitmapMap());
+
+ nPosX = nNewPosX;
+ }
+
+ tools::Long nPosXLogic = nPosX;
+ if (bWorksInPixels)
+ nPosXLogic = rRenderContext.PixelToLogic(Point(nPosX, 0)).X();
+
+ drawCells(rRenderContext, std::optional<Color>(), nullptr, pOldColor, pOldBackground, aRect, nPosXLogic, nLayoutSign, nOneXLogic, nOneYLogic, nullptr, pOldDataBarInfo, nullptr, pOldIconSetInfo, mpDoc->GetIconSetBitmapMap());
+
+ nArrY += nSkip;
+ }
+ }
+ nPosY += nRowHeight;
+ }
+}
+
+void ScOutputData::DrawShadow()
+{
+ DrawExtraShadow( false, false, false, false );
+}
+
+void ScOutputData::DrawExtraShadow(bool bLeft, bool bTop, bool bRight, bool bBottom)
+{
+ mpDev->SetLineColor();
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
+ Color aAutoTextColor;
+ if ( bCellContrast )
+ aAutoTextColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
+
+ tools::Long nInitPosX = nScrX;
+ if ( bLayoutRTL )
+ {
+ Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ nInitPosX += nMirrorW - nOneX;
+ }
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ tools::Long nPosY = nScrY - pRowInfo[0].nHeight;
+ for (SCSIZE nArrY=0; nArrY<nArrCount; nArrY++)
+ {
+ bool bCornerY = ( nArrY == 0 ) || ( nArrY+1 == nArrCount );
+ bool bSkipY = ( nArrY==0 && !bTop ) || ( nArrY+1 == nArrCount && !bBottom );
+
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ tools::Long nRowHeight = pThisRowInfo->nHeight;
+
+ if ( pThisRowInfo->bChanged && !bSkipY )
+ {
+ tools::Long nPosX = nInitPosX - pRowInfo[0].basicCellInfo(nX1-1).nWidth * nLayoutSign;
+ for (SCCOL nCol=nX1-1; nCol<=nX2+1; nCol++)
+ {
+ bool bCornerX = ( nCol==nX1-1 || nCol==nX2+1 );
+ bool bSkipX = ( nCol==nX1-1 && !bLeft ) || ( nCol==nX2+1 && !bRight );
+
+ for (sal_uInt16 nPass=0; nPass<2; nPass++) // horizontal / vertical
+ {
+ const SvxShadowItem* pAttr = nPass ?
+ pThisRowInfo->cellInfo(nCol).pVShadowOrigin :
+ pThisRowInfo->cellInfo(nCol).pHShadowOrigin;
+ if ( pAttr && !bSkipX )
+ {
+ ScShadowPart ePart = nPass ?
+ pThisRowInfo->cellInfo(nCol).eVShadowPart :
+ pThisRowInfo->cellInfo(nCol).eHShadowPart;
+
+ bool bDo = true;
+ if ( (nPass==0 && bCornerX) || (nPass==1 && bCornerY) )
+ if ( ePart != SC_SHADOW_CORNER )
+ bDo = false;
+
+ if (bDo)
+ {
+ tools::Long nThisWidth = pRowInfo[0].basicCellInfo(nCol).nWidth;
+ tools::Long nMaxWidth = nThisWidth;
+ if (!nMaxWidth)
+ {
+ //! direction must depend on shadow location
+ SCCOL nWx = nCol+1;
+ while (nWx<nX2 && !pRowInfo[0].basicCellInfo(nWx).nWidth)
+ ++nWx;
+ nMaxWidth = pRowInfo[0].basicCellInfo(nWx).nWidth;
+ }
+
+ // rectangle is in logical orientation
+ tools::Rectangle aRect( nPosX, nPosY,
+ nPosX + ( nThisWidth - 1 ) * nLayoutSign,
+ nPosY + pRowInfo[nArrY].nHeight - 1 );
+
+ tools::Long nSize = pAttr->GetWidth();
+ tools::Long nSizeX = static_cast<tools::Long>(nSize*mnPPTX);
+ if (nSizeX >= nMaxWidth) nSizeX = nMaxWidth-1;
+ tools::Long nSizeY = static_cast<tools::Long>(nSize*mnPPTY);
+ if (nSizeY >= nRowHeight) nSizeY = nRowHeight-1;
+
+ nSizeX *= nLayoutSign; // used only to add to rectangle values
+
+ SvxShadowLocation eLoc = pAttr->GetLocation();
+ if ( bLayoutRTL )
+ {
+ // Shadow location is specified as "visual" (right is always right),
+ // so the attribute's location value is mirrored here and in FillInfo.
+ switch (eLoc)
+ {
+ case SvxShadowLocation::BottomRight: eLoc = SvxShadowLocation::BottomLeft; break;
+ case SvxShadowLocation::BottomLeft: eLoc = SvxShadowLocation::BottomRight; break;
+ case SvxShadowLocation::TopRight: eLoc = SvxShadowLocation::TopLeft; break;
+ case SvxShadowLocation::TopLeft: eLoc = SvxShadowLocation::TopRight; break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+
+ if (ePart == SC_SHADOW_HORIZ || ePart == SC_SHADOW_HSTART ||
+ ePart == SC_SHADOW_CORNER)
+ {
+ if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::TopRight)
+ aRect.SetTop( aRect.Bottom() - nSizeY );
+ else
+ aRect.SetBottom( aRect.Top() + nSizeY );
+ }
+ if (ePart == SC_SHADOW_VERT || ePart == SC_SHADOW_VSTART ||
+ ePart == SC_SHADOW_CORNER)
+ {
+ if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::BottomLeft)
+ aRect.SetLeft( aRect.Right() - nSizeX );
+ else
+ aRect.SetRight( aRect.Left() + nSizeX );
+ }
+ if (ePart == SC_SHADOW_HSTART)
+ {
+ if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::BottomLeft)
+ aRect.AdjustRight( -nSizeX );
+ else
+ aRect.AdjustLeft(nSizeX );
+ }
+ if (ePart == SC_SHADOW_VSTART)
+ {
+ if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::TopRight)
+ aRect.AdjustBottom( -nSizeY );
+ else
+ aRect.AdjustTop(nSizeY );
+ }
+
+ //! merge rectangles?
+ mpDev->SetFillColor( bCellContrast ? aAutoTextColor : pAttr->GetColor() );
+ mpDev->DrawRect( aRect );
+ }
+ }
+ }
+
+ nPosX += pRowInfo[0].basicCellInfo(nCol).nWidth * nLayoutSign;
+ }
+ }
+ nPosY += nRowHeight;
+ }
+}
+
+void ScOutputData::DrawClear()
+{
+ tools::Rectangle aRect;
+ Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+
+ // (called only for ScGridWindow)
+ Color aBgColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
+
+ if (bMetaFile)
+ nOneX = nOneY = 0;
+
+ mpDev->SetLineColor();
+
+ mpDev->SetFillColor( aBgColor );
+
+ tools::Long nPosY = nScrY;
+ for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ tools::Long nRowHeight = pThisRowInfo->nHeight;
+
+ if ( pThisRowInfo->bChanged )
+ {
+ // scan for more rows which must be painted:
+ SCSIZE nSkip = 0;
+ while ( nArrY+nSkip+2<nArrCount && pRowInfo[nArrY+nSkip+1].bChanged )
+ {
+ ++nSkip;
+ nRowHeight += pRowInfo[nArrY+nSkip].nHeight; // after incrementing
+ }
+
+ aRect = tools::Rectangle( Point( nScrX, nPosY ),
+ Size( nScrW+1-nOneX, nRowHeight+1-nOneY) );
+ mpDev->DrawRect( aRect );
+
+ nArrY += nSkip;
+ }
+ nPosY += nRowHeight;
+ }
+}
+
+// Lines
+
+static tools::Long lclGetSnappedX( const OutputDevice& rDev, tools::Long nPosX, bool bSnapPixel )
+{
+ return (bSnapPixel && nPosX) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( nPosX, 0 ) ) ).Width() : nPosX;
+}
+
+static tools::Long lclGetSnappedY( const OutputDevice& rDev, tools::Long nPosY, bool bSnapPixel )
+{
+ return (bSnapPixel && nPosY) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( 0, nPosY ) ) ).Height() : nPosY;
+}
+
+void ScOutputData::DrawFrame(vcl::RenderContext& rRenderContext)
+{
+ DrawModeFlags nOldDrawMode = rRenderContext.GetDrawMode();
+
+ Color aSingleColor;
+ bool bUseSingleColor = false;
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
+
+ // if a Calc OLE object is embedded in Draw/Impress, the VCL DrawMode is used
+ // for display mode / B&W printing. The VCL DrawMode handling doesn't work for lines
+ // that are drawn with DrawRect, so if the line/background bits are set, the DrawMode
+ // must be reset and the border colors handled here.
+
+ if ( ( nOldDrawMode & DrawModeFlags::WhiteFill ) && ( nOldDrawMode & DrawModeFlags::BlackLine ) )
+ {
+ rRenderContext.SetDrawMode( nOldDrawMode & (~DrawModeFlags::WhiteFill) );
+ aSingleColor = COL_BLACK;
+ bUseSingleColor = true;
+ }
+ else if ( ( nOldDrawMode & DrawModeFlags::SettingsFill ) && ( nOldDrawMode & DrawModeFlags::SettingsLine ) )
+ {
+ rRenderContext.SetDrawMode( nOldDrawMode & (~DrawModeFlags::SettingsFill) );
+ aSingleColor = rStyleSettings.GetWindowTextColor(); // same as used in VCL for DrawModeFlags::SettingsLine
+ bUseSingleColor = true;
+ }
+ else if ( bCellContrast )
+ {
+ aSingleColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
+ bUseSingleColor = true;
+ }
+
+ const Color* pForceColor = bUseSingleColor ? &aSingleColor : nullptr;
+
+ if (mrTabInfo.maArray.HasCellRotation())
+ {
+ DrawRotatedFrame(rRenderContext); // removes the lines that must not be painted here
+ }
+
+ tools::Long nInitPosX = nScrX;
+ if ( bLayoutRTL )
+ {
+ Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ nInitPosX += nMirrorW - nOneX;
+ }
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ // *** set column and row sizes of the frame border array ***
+
+ svx::frame::Array& rArray = mrTabInfo.maArray;
+ size_t nColCount = rArray.GetColCount();
+ size_t nRowCount = rArray.GetRowCount();
+
+ // row heights
+
+ // row 0 is not visible (dummy for borders from top) - subtract its height from initial position
+ // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit before
+ tools::Long nOldPosY = nScrY - 1 - pRowInfo[ 0 ].nHeight;
+ tools::Long nOldSnapY = lclGetSnappedY( rRenderContext, nOldPosY, bSnapPixel );
+ rArray.SetYOffset( nOldSnapY );
+ for( size_t nRow = 0; nRow < nRowCount; ++nRow )
+ {
+ tools::Long nNewPosY = nOldPosY + pRowInfo[ nRow ].nHeight;
+ tools::Long nNewSnapY = lclGetSnappedY( rRenderContext, nNewPosY, bSnapPixel );
+ rArray.SetRowHeight( nRow, nNewSnapY - nOldSnapY );
+ nOldPosY = nNewPosY;
+ nOldSnapY = nNewSnapY;
+ }
+
+ // column widths
+
+ // column nX1-1 is not visible (dummy for borders from left) - subtract its width from initial position
+ // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit above
+ tools::Long nOldPosX = nInitPosX - nLayoutSign * (1 + pRowInfo[ 0 ].basicCellInfo( nX1 - 1 ).nWidth);
+ tools::Long nOldSnapX = lclGetSnappedX( rRenderContext, nOldPosX, bSnapPixel );
+ // set X offset for left-to-right sheets; for right-to-left sheets this is done after for() loop
+ if( !bLayoutRTL )
+ rArray.SetXOffset( nOldSnapX );
+ for( SCCOL nCol = nX1 - 1; nCol <= nX2 + 1; ++nCol )
+ {
+ size_t nArrCol = bLayoutRTL ? nX2 + 1 - nCol : nCol - (nX1 - 1);
+ tools::Long nNewPosX = nOldPosX + pRowInfo[ 0 ].basicCellInfo( nCol ).nWidth * nLayoutSign;
+ tools::Long nNewSnapX = lclGetSnappedX( rRenderContext, nNewPosX, bSnapPixel );
+ rArray.SetColWidth( nArrCol, std::abs( nNewSnapX - nOldSnapX ) );
+ nOldPosX = nNewPosX;
+ nOldSnapX = nNewSnapX;
+ }
+ if( bLayoutRTL )
+ rArray.SetXOffset( nOldSnapX );
+
+ // *** draw the array ***
+
+ size_t nFirstCol = 1;
+ size_t nFirstRow = 1;
+ size_t nLastCol = nColCount - 2;
+ size_t nLastRow = nRowCount - 2;
+
+ if( mrTabInfo.mbPageMode )
+ rArray.SetClipRange( nFirstCol, nFirstRow, nLastCol, nLastRow );
+
+ // draw only rows with set RowInfo::bChanged flag
+ size_t nRow1 = nFirstRow;
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(CreateProcessor2D());
+ if (!pProcessor)
+ return;
+ while( nRow1 <= nLastRow )
+ {
+ while( (nRow1 <= nLastRow) && !pRowInfo[ nRow1 ].bChanged ) ++nRow1;
+ if( nRow1 <= nLastRow )
+ {
+ size_t nRow2 = nRow1;
+ while( (nRow2 + 1 <= nLastRow) && pRowInfo[ nRow2 + 1 ].bChanged ) ++nRow2;
+ auto xPrimitive = rArray.CreateB2DPrimitiveRange(
+ nFirstCol, nRow1, nLastCol, nRow2, pForceColor );
+ pProcessor->process(xPrimitive);
+ nRow1 = nRow2 + 1;
+ }
+ }
+ pProcessor.reset();
+
+ rRenderContext.SetDrawMode(nOldDrawMode);
+}
+
+void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext)
+{
+ //! save nRotMax
+ SCCOL nRotMax = nX2;
+ for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
+ if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
+ nRotMax = pRowInfo[nRotY].nRotMaxCol;
+
+ const ScPatternAttr* pPattern;
+ const SfxItemSet* pCondSet;
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
+
+ tools::Long nInitPosX = nScrX;
+ if ( bLayoutRTL )
+ {
+ Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ nInitPosX += nMirrorW - nOneX;
+ }
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ tools::Rectangle aClipRect( Point(nScrX, nScrY), Size(nScrW, nScrH) );
+ if (bMetaFile)
+ {
+ rRenderContext.Push();
+ rRenderContext.IntersectClipRegion( aClipRect );
+ }
+ else
+ rRenderContext.SetClipRegion( vcl::Region( aClipRect ) );
+
+ std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(CreateProcessor2D( ));
+ tools::Long nPosY = nScrY;
+ for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
+ {
+ // Rotated is also drawn one line above/below Changed if parts extend into the cell
+
+ RowInfo& rPrevRowInfo = pRowInfo[nArrY-1];
+ RowInfo& rThisRowInfo = pRowInfo[nArrY];
+ RowInfo& rNextRowInfo = pRowInfo[nArrY+1];
+
+ tools::Long nRowHeight = rThisRowInfo.nHeight;
+ if ( rThisRowInfo.nRotMaxCol != SC_ROTMAX_NONE &&
+ ( rThisRowInfo.bChanged || rPrevRowInfo.bChanged ||
+ ( nArrY+1<nArrCount && rNextRowInfo.bChanged ) ) )
+ {
+ SCROW nY = rThisRowInfo.nRowNo;
+ tools::Long nPosX = 0;
+ SCCOL nX;
+ for (nX=0; nX<=nRotMax; nX++)
+ {
+ if (nX==nX1) nPosX = nInitPosX; // calculated individually for preceding positions
+
+ ScCellInfo* pInfo = &rThisRowInfo.cellInfo(nX);
+ tools::Long nColWidth = pRowInfo[0].basicCellInfo(nX).nWidth;
+ if ( pInfo->nRotateDir > ScRotateDir::Standard &&
+ !pInfo->bHOverlapped && !pInfo->bVOverlapped )
+ {
+ pPattern = pInfo->pPatternAttr;
+ pCondSet = pInfo->pConditionSet;
+ if (!pPattern)
+ {
+ pPattern = mpDoc->GetPattern( nX, nY, nTab );
+ pInfo->pPatternAttr = pPattern;
+ pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
+ pInfo->pConditionSet = pCondSet;
+ }
+
+ //! LastPattern etc.
+
+ Degree100 nAttrRotate = pPattern->GetRotateVal( pCondSet );
+ SvxRotateMode eRotMode =
+ pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue();
+
+ if (nAttrRotate)
+ {
+ if (nX < nX1) // compute negative position
+ {
+ nPosX = nInitPosX;
+ SCCOL nCol = nX1;
+ while (nCol > nX)
+ {
+ --nCol;
+ nPosX -= nLayoutSign * static_cast<tools::Long>(pRowInfo[0].basicCellInfo(nCol).nWidth);
+ }
+ }
+
+ // start position minus 1 so rotated backgrounds suit the border
+ // (border is on the grid)
+
+ tools::Long nTop = nPosY - 1;
+ tools::Long nBottom = nPosY + nRowHeight - 1;
+ tools::Long nTopLeft = nPosX - nLayoutSign;
+ tools::Long nTopRight = nPosX + (nColWidth - 1) * nLayoutSign;
+ tools::Long nBotLeft = nTopLeft;
+ tools::Long nBotRight = nTopRight;
+
+ // inclusion of the sign here hasn't been decided yet
+ // (if not, the extension of the non-rotated background must also be changed)
+ double nRealOrient = nLayoutSign * toRadians(nAttrRotate); // 1/100th degrees
+ double nCos = cos(nRealOrient);
+ double nSin = sin(nRealOrient);
+ //! restrict !!!
+ tools::Long nSkew = static_cast<tools::Long>(nRowHeight * nCos / nSin);
+
+ switch (eRotMode)
+ {
+ case SVX_ROTATE_MODE_BOTTOM:
+ nTopLeft += nSkew;
+ nTopRight += nSkew;
+ break;
+ case SVX_ROTATE_MODE_CENTER:
+ nSkew /= 2;
+ nTopLeft += nSkew;
+ nTopRight += nSkew;
+ nBotLeft -= nSkew;
+ nBotRight -= nSkew;
+ break;
+ case SVX_ROTATE_MODE_TOP:
+ nBotLeft -= nSkew;
+ nBotRight -= nSkew;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ Point aPoints[4];
+ aPoints[0] = Point(nTopLeft, nTop);
+ aPoints[1] = Point(nTopRight, nTop);
+ aPoints[2] = Point(nBotRight, nBottom);
+ aPoints[3] = Point(nBotLeft, nBottom);
+
+ const SvxBrushItem* pBackground = pInfo->pBackground;
+ if (!pBackground)
+ pBackground = &pPattern->GetItem(ATTR_BACKGROUND, pCondSet);
+ if (bCellContrast)
+ {
+ // high contrast for cell borders and backgrounds -> empty background
+ pBackground = ScGlobal::GetEmptyBrushItem();
+ }
+ if (!pInfo->mxColorScale)
+ {
+ const Color& rColor = pBackground->GetColor();
+ if (rColor.GetAlpha() != 0)
+ {
+ // draw background only for the changed row itself
+ // (background doesn't extend into other cells).
+ // For the borders (rotated and normal), clipping should be
+ // set if the row isn't changed, but at least the borders
+ // don't cover the cell contents.
+ if (rThisRowInfo.bChanged)
+ {
+ tools::Polygon aPoly(4, aPoints);
+
+ // for DrawPolygon, without Pen one pixel is left out
+ // to the right and below...
+ if (!rColor.IsTransparent())
+ rRenderContext.SetLineColor(rColor);
+ else
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(rColor);
+ rRenderContext.DrawPolygon(aPoly);
+ }
+ }
+ }
+ else
+ {
+ tools::Polygon aPoly(4, aPoints);
+ std::optional<Color> const & pColor = pInfo->mxColorScale;
+
+ // for DrawPolygon, without Pen one pixel is left out
+ // to the right and below...
+ if (!pColor->IsTransparent())
+ rRenderContext.SetLineColor(*pColor);
+ else
+ rRenderContext.SetLineColor();
+ rRenderContext.SetFillColor(*pColor);
+ rRenderContext.DrawPolygon(aPoly);
+
+ }
+ }
+ }
+ nPosX += nColWidth * nLayoutSign;
+ }
+ }
+ nPosY += nRowHeight;
+ }
+
+ pProcessor.reset();
+
+ if (bMetaFile)
+ rRenderContext.Pop();
+ else
+ rRenderContext.SetClipRegion();
+}
+
+std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> ScOutputData::CreateProcessor2D( )
+{
+ mpDoc->InitDrawLayer(mpDoc->GetDocumentShell());
+ ScDrawLayer* pDrawLayer = mpDoc->GetDrawLayer();
+ if (!pDrawLayer)
+ return nullptr;
+
+ basegfx::B2DRange aViewRange;
+ SdrPage *pDrawPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) );
+ const drawinglayer::geometry::ViewInformation2D aNewViewInfos(
+ basegfx::B2DHomMatrix( ),
+ mpDev->GetViewTransformation(),
+ aViewRange,
+ GetXDrawPageForSdrPage( pDrawPage ),
+ 0.0);
+
+ return drawinglayer::processor2d::createBaseProcessor2DFromOutputDevice(
+ *mpDev, aNewViewInfos );
+}
+
+// Printer
+
+vcl::Region ScOutputData::GetChangedAreaRegion()
+{
+ vcl::Region aRegion;
+ tools::Rectangle aDrawingRect;
+ bool bHad(false);
+ tools::Long nPosY = nScrY;
+ SCSIZE nArrY;
+
+ aDrawingRect.SetLeft( nScrX );
+ aDrawingRect.SetRight( nScrX+nScrW-1 );
+
+ for(nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+
+ if(pThisRowInfo->bChanged)
+ {
+ if(!bHad)
+ {
+ aDrawingRect.SetTop( nPosY );
+ bHad = true;
+ }
+
+ aDrawingRect.SetBottom( nPosY + pRowInfo[nArrY].nHeight - 1 );
+ }
+ else if(bHad)
+ {
+ aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
+ bHad = false;
+ }
+
+ nPosY += pRowInfo[nArrY].nHeight;
+ }
+
+ if(bHad)
+ {
+ aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
+ }
+
+ return aRegion;
+}
+
+bool ScOutputData::SetChangedClip()
+{
+ tools::PolyPolygon aPoly;
+
+ tools::Rectangle aDrawingRect;
+ aDrawingRect.SetLeft( nScrX );
+ aDrawingRect.SetRight( nScrX+nScrW-1 );
+
+ bool bHad = false;
+ tools::Long nPosY = nScrY;
+ SCSIZE nArrY;
+ for (nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+
+ if ( pThisRowInfo->bChanged )
+ {
+ if (!bHad)
+ {
+ aDrawingRect.SetTop( nPosY );
+ bHad = true;
+ }
+ aDrawingRect.SetBottom( nPosY + pRowInfo[nArrY].nHeight - 1 );
+ }
+ else if (bHad)
+ {
+ aPoly.Insert( tools::Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
+ bHad = false;
+ }
+ nPosY += pRowInfo[nArrY].nHeight;
+ }
+
+ if (bHad)
+ aPoly.Insert( tools::Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
+
+ bool bRet = (aPoly.Count() != 0);
+ if (bRet)
+ mpDev->SetClipRegion(vcl::Region(aPoly));
+ return bRet;
+}
+
+void ScOutputData::FindChanged()
+{
+ SCCOL nX;
+ SCSIZE nArrY;
+
+ bool bWasIdleEnabled = mpDoc->IsIdleEnabled();
+ mpDoc->EnableIdle(false);
+ for (nArrY=0; nArrY<nArrCount; nArrY++)
+ pRowInfo[nArrY].bChanged = false;
+
+ SCCOL nCol1 = mpDoc->MaxCol(), nCol2 = 0;
+ SCROW nRow1 = mpDoc->MaxRow(), nRow2 = 0;
+ bool bAnyDirty = false;
+ bool bAnyChanged = false;
+
+ for (nArrY=0; nArrY<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ for (nX=nX1; nX<=nX2; nX++)
+ {
+ const ScRefCellValue& rCell = pThisRowInfo->cellInfo(nX).maCell;
+
+ if (rCell.meType != CELLTYPE_FORMULA)
+ continue;
+
+ ScFormulaCell* pFCell = rCell.mpFormula;
+ if (pFCell->IsRunning())
+ // still being interpreted. Skip it.
+ continue;
+
+ bool bDirty = pFCell->GetDirty();
+ bAnyChanged = bAnyChanged || pFCell->IsChanged();
+
+ if (bDirty)
+ {
+ if (!bAnyDirty)
+ {
+ ScProgress::CreateInterpretProgress(mpDoc);
+ bAnyDirty = true;
+ }
+
+ ScAddress& rPos(pFCell->aPos);
+ nCol1 = std::min(rPos.Col(), nCol1);
+ nCol2 = std::max(rPos.Col(), nCol2);
+ nRow1 = std::min(rPos.Row(), nRow1);
+ nRow2 = std::max(rPos.Row(), nRow2);
+
+ const SfxUInt32Item* pItem = mpDoc->GetAttr(rPos, ATTR_VALIDDATA);
+ const ScValidationData* pData = mpDoc->GetValidationEntry(pItem->GetValue());
+ if (pData)
+ {
+ ScRefCellValue aCell(*mpDoc, rPos);
+ if (pData->IsDataValid(aCell, rPos))
+ ScDetectiveFunc(*mpDoc, rPos.Tab()).DeleteCirclesAt(rPos.Col(), rPos.Row());
+ }
+ }
+ }
+ }
+
+ if (bAnyDirty || bAnyChanged)
+ {
+ if (bAnyDirty)
+ mpDoc->EnsureFormulaCellResults(ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab), true);
+
+ for (nArrY=0; nArrY<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ for (nX=nX1; nX<=nX2; nX++)
+ {
+ const ScRefCellValue& rCell = pThisRowInfo->cellInfo(nX).maCell;
+
+ if (rCell.meType != CELLTYPE_FORMULA)
+ continue;
+
+ ScFormulaCell* pFCell = rCell.mpFormula;
+ if (pFCell->IsRunning())
+ // still being interpreted. Skip it.
+ continue;
+
+ if (!pFCell->IsChanged())
+ // the result hasn't changed. Skip it.
+ continue;
+
+ pThisRowInfo->bChanged = true;
+ if ( pThisRowInfo->cellInfo(nX).bMerged )
+ {
+ SCSIZE nOverY = nArrY + 1;
+ while ( nOverY<nArrCount &&
+ pRowInfo[nOverY].cellInfo(nX).bVOverlapped )
+ {
+ pRowInfo[nOverY].bChanged = true;
+ ++nOverY;
+ }
+ }
+ }
+ }
+
+ if (bAnyDirty)
+ ScProgress::DeleteInterpretProgress();
+ }
+
+ mpDoc->EnableIdle(bWasIdleEnabled);
+}
+
+ReferenceMark ScOutputData::FillReferenceMark( SCCOL nRefStartX, SCROW nRefStartY,
+ SCCOL nRefEndX, SCROW nRefEndY, const Color& rColor)
+{
+ ReferenceMark aResult;
+
+ PutInOrder( nRefStartX, nRefEndX );
+ PutInOrder( nRefStartY, nRefEndY );
+
+ if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
+ mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
+
+ if ( nRefStartX <= nVisX2 && nRefEndX >= nVisX1 &&
+ nRefStartY <= nVisY2 && nRefEndY >= nVisY1 )
+ {
+ tools::Long nMinX = nScrX;
+ tools::Long nMinY = nScrY;
+ tools::Long nMaxX = nScrX + nScrW - 1;
+ tools::Long nMaxY = nScrY + nScrH - 1;
+ if ( bLayoutRTL )
+ {
+ tools::Long nTemp = nMinX;
+ nMinX = nMaxX;
+ nMaxX = nTemp;
+ }
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ bool bTop = false;
+ bool bBottom = false;
+ bool bLeft = false;
+ bool bRight = false;
+
+ tools::Long nPosY = nScrY;
+ bool bNoStartY = ( nY1 < nRefStartY );
+ bool bNoEndY = false;
+ for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
+ {
+ SCROW nY = pRowInfo[nArrY].nRowNo;
+
+ if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
+ {
+ nMinY = nPosY;
+ bTop = true;
+ }
+ if ( nY==nRefEndY )
+ {
+ nMaxY = nPosY + pRowInfo[nArrY].nHeight - 2;
+ bBottom = true;
+ }
+ if ( nY>nRefEndY && bNoEndY )
+ {
+ nMaxY = nPosY-2;
+ bBottom = true;
+ }
+ bNoStartY = ( nY < nRefStartY );
+ bNoEndY = ( nY < nRefEndY );
+ nPosY += pRowInfo[nArrY].nHeight;
+ }
+
+ tools::Long nPosX = nScrX;
+ if ( bLayoutRTL )
+ nPosX += nMirrorW - 1; // always in pixels
+
+ for (SCCOL nX=nX1; nX<=nX2; nX++)
+ {
+ if ( nX==nRefStartX )
+ {
+ nMinX = nPosX;
+ bLeft = true;
+ }
+ if ( nX==nRefEndX )
+ {
+ nMaxX = nPosX + ( pRowInfo[0].basicCellInfo(nX).nWidth - 2 ) * nLayoutSign;
+ bRight = true;
+ }
+ nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
+ }
+
+ if (bTop && bBottom && bLeft && bRight)
+ {
+ // mnPPT[XY] already has the factor aZoom[XY] in it.
+ aResult = ReferenceMark( nMinX / mnPPTX,
+ nMinY / mnPPTY,
+ ( nMaxX - nMinX ) / mnPPTX,
+ ( nMaxY - nMinY ) / mnPPTY,
+ nTab,
+ rColor );
+ }
+ }
+
+ return aResult;
+}
+
+void ScOutputData::DrawRefMark( SCCOL nRefStartX, SCROW nRefStartY,
+ SCCOL nRefEndX, SCROW nRefEndY,
+ const Color& rColor, bool bHandle )
+{
+ PutInOrder( nRefStartX, nRefEndX );
+ PutInOrder( nRefStartY, nRefEndY );
+
+ if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
+ mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
+
+ if ( !(nRefStartX <= nVisX2 && nRefEndX >= nVisX1 &&
+ nRefStartY <= nVisY2 && nRefEndY >= nVisY1) )
+ return;
+
+ tools::Long nMinX = nScrX;
+ tools::Long nMinY = nScrY;
+ tools::Long nMaxX = nScrX + nScrW - 1;
+ tools::Long nMaxY = nScrY + nScrH - 1;
+ if ( bLayoutRTL )
+ {
+ tools::Long nTemp = nMinX;
+ nMinX = nMaxX;
+ nMaxX = nTemp;
+ }
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ bool bTop = false;
+ bool bBottom = false;
+ bool bLeft = false;
+ bool bRight = false;
+
+ tools::Long nPosY = nScrY;
+ bool bNoStartY = ( nY1 < nRefStartY );
+ bool bNoEndY = false;
+ for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
+ {
+ SCROW nY = pRowInfo[nArrY].nRowNo;
+
+ if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
+ {
+ nMinY = nPosY;
+ bTop = true;
+ }
+ if ( nY==nRefEndY )
+ {
+ nMaxY = nPosY + pRowInfo[nArrY].nHeight - 2;
+ bBottom = true;
+ }
+ if ( nY>nRefEndY && bNoEndY )
+ {
+ nMaxY = nPosY-2;
+ bBottom = true;
+ }
+ bNoStartY = ( nY < nRefStartY );
+ bNoEndY = ( nY < nRefEndY );
+ nPosY += pRowInfo[nArrY].nHeight;
+ }
+
+ tools::Long nPosX = nScrX;
+ if ( bLayoutRTL )
+ nPosX += nMirrorW - 1; // always in pixels
+
+ for (SCCOL nX=nX1; nX<=nX2; nX++)
+ {
+ if ( nX==nRefStartX )
+ {
+ nMinX = nPosX;
+ bLeft = true;
+ }
+ if ( nX==nRefEndX )
+ {
+ nMaxX = nPosX + ( pRowInfo[0].basicCellInfo(nX).nWidth - 2 ) * nLayoutSign;
+ bRight = true;
+ }
+ nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
+ }
+
+ if ( nMaxX * nLayoutSign < nMinX * nLayoutSign || nMaxY < nMinY )
+ return;
+
+ mpDev->SetLineColor( rColor );
+ if (bTop && bBottom && bLeft && bRight && !comphelper::LibreOfficeKit::isActive() )
+ {
+ mpDev->SetFillColor();
+ mpDev->DrawRect( tools::Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
+ }
+ else if ( !comphelper::LibreOfficeKit::isActive() )
+ {
+ if (bTop)
+ mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMaxX, nMinY ) );
+ if (bBottom)
+ mpDev->DrawLine( Point( nMinX, nMaxY ), Point( nMaxX, nMaxY ) );
+ if (bLeft)
+ mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMinX, nMaxY ) );
+ if (bRight)
+ mpDev->DrawLine( Point( nMaxX, nMinY ), Point( nMaxX, nMaxY ) );
+ }
+ if ( !bHandle || !bRight || !bBottom || comphelper::LibreOfficeKit::isActive() )
+ return;
+
+ mpDev->SetLineColor( rColor );
+ mpDev->SetFillColor( rColor );
+
+ const sal_Int32 aRadius = 4;
+
+ sal_Int32 aRectMaxX1 = nMaxX - nLayoutSign * aRadius;
+ sal_Int32 aRectMaxX2 = nMaxX + nLayoutSign;
+ sal_Int32 aRectMinX1 = nMinX - nLayoutSign;
+ sal_Int32 aRectMinX2 = nMinX + nLayoutSign * aRadius;
+
+ sal_Int32 aRectMaxY1 = nMaxY - aRadius;
+ sal_Int32 aRectMaxY2 = nMaxY + 1;
+ sal_Int32 aRectMinY1 = nMinY - 1;
+ sal_Int32 aRectMinY2 = nMinY + aRadius;
+
+ // Draw corner rectangles
+ tools::Rectangle aLowerRight( aRectMaxX1, aRectMaxY1, aRectMaxX2, aRectMaxY2 );
+ tools::Rectangle aUpperLeft ( aRectMinX1, aRectMinY1, aRectMinX2, aRectMinY2 );
+ tools::Rectangle aLowerLeft ( aRectMinX1, aRectMaxY1, aRectMinX2, aRectMaxY2 );
+ tools::Rectangle aUpperRight( aRectMaxX1, aRectMinY1, aRectMaxX2, aRectMinY2 );
+
+ mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aLowerRight ) ), lclCornerRectTransparency );
+ mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aUpperLeft ) ), lclCornerRectTransparency );
+ mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aLowerLeft ) ), lclCornerRectTransparency );
+ mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aUpperRight ) ), lclCornerRectTransparency );
+}
+
+void ScOutputData::DrawOneChange( SCCOL nRefStartX, SCROW nRefStartY,
+ SCCOL nRefEndX, SCROW nRefEndY,
+ const Color& rColor, sal_uInt16 nType )
+{
+ PutInOrder( nRefStartX, nRefEndX );
+ PutInOrder( nRefStartY, nRefEndY );
+
+ if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
+ mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
+
+ if ( !(nRefStartX <= nVisX2 + 1 && nRefEndX >= nVisX1 &&
+ nRefStartY <= nVisY2 + 1 && nRefEndY >= nVisY1) ) // +1 because it touches next cells left/top
+ return;
+
+ tools::Long nMinX = nScrX;
+ tools::Long nMinY = nScrY;
+ tools::Long nMaxX = nScrX+nScrW-1;
+ tools::Long nMaxY = nScrY+nScrH-1;
+ if ( bLayoutRTL )
+ {
+ tools::Long nTemp = nMinX;
+ nMinX = nMaxX;
+ nMaxX = nTemp;
+ }
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ bool bTop = false;
+ bool bBottom = false;
+ bool bLeft = false;
+ bool bRight = false;
+
+ tools::Long nPosY = nScrY;
+ bool bNoStartY = ( nY1 < nRefStartY );
+ bool bNoEndY = false;
+ for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++) // loop to end for bNoEndY check
+ {
+ SCROW nY = pRowInfo[nArrY].nRowNo;
+
+ if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
+ {
+ nMinY = nPosY - 1;
+ bTop = true;
+ }
+ if ( nY==nRefEndY )
+ {
+ nMaxY = nPosY + pRowInfo[nArrY].nHeight - 1;
+ bBottom = true;
+ }
+ if ( nY>nRefEndY && bNoEndY )
+ {
+ nMaxY = nPosY - 1;
+ bBottom = true;
+ }
+ bNoStartY = ( nY < nRefStartY );
+ bNoEndY = ( nY < nRefEndY );
+ nPosY += pRowInfo[nArrY].nHeight;
+ }
+
+ tools::Long nPosX = nScrX;
+ if ( bLayoutRTL )
+ nPosX += nMirrorW - 1; // always in pixels
+
+ for (SCCOL nX=nX1; nX<=nX2+1; nX++)
+ {
+ if ( nX==nRefStartX )
+ {
+ nMinX = nPosX - nLayoutSign;
+ bLeft = true;
+ }
+ if ( nX==nRefEndX )
+ {
+ nMaxX = nPosX + ( pRowInfo[0].basicCellInfo(nX).nWidth - 1 ) * nLayoutSign;
+ bRight = true;
+ }
+ nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
+ }
+
+ if ( nMaxX * nLayoutSign < nMinX * nLayoutSign || nMaxY < nMinY )
+ return;
+
+ if ( nType == SC_CAT_DELETE_ROWS )
+ bLeft = bRight = bBottom = false; //! thick lines???
+ else if ( nType == SC_CAT_DELETE_COLS )
+ bTop = bBottom = bRight = false; //! thick lines???
+
+ mpDev->SetLineColor( rColor );
+ if (bTop && bBottom && bLeft && bRight)
+ {
+ mpDev->SetFillColor();
+ mpDev->DrawRect( tools::Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
+ }
+ else
+ {
+ if (bTop)
+ {
+ mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMaxX,nMinY ) );
+ if ( nType == SC_CAT_DELETE_ROWS )
+ mpDev->DrawLine( Point( nMinX,nMinY+1 ), Point( nMaxX,nMinY+1 ) );
+ }
+ if (bBottom)
+ mpDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
+ if (bLeft)
+ {
+ mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMinX,nMaxY ) );
+ if ( nType == SC_CAT_DELETE_COLS )
+ mpDev->DrawLine( Point( nMinX+nLayoutSign,nMinY ), Point( nMinX+nLayoutSign,nMaxY ) );
+ }
+ if (bRight)
+ mpDev->DrawLine( Point( nMaxX,nMinY ), Point( nMaxX,nMaxY ) );
+ }
+ if ( bLeft && bTop )
+ {
+ mpDev->SetLineColor();
+ mpDev->SetFillColor( rColor );
+ mpDev->DrawRect( tools::Rectangle( nMinX+nLayoutSign, nMinY+1, nMinX+3*nLayoutSign, nMinY+3 ) );
+ }
+}
+
+void ScOutputData::DrawChangeTrack()
+{
+ ScChangeTrack* pTrack = mpDoc->GetChangeTrack();
+ ScChangeViewSettings* pSettings = mpDoc->GetChangeViewSettings();
+ if ( !pTrack || !pTrack->GetFirst() || !pSettings || !pSettings->ShowChanges() )
+ return; // nothing there or hidden
+
+ ScActionColorChanger aColorChanger(*pTrack);
+
+ // clipping happens from the outside
+ //! without clipping, only paint affected cells ??!??!?
+
+ SCCOL nEndX = nX2;
+ SCROW nEndY = nY2;
+ if ( nEndX < mpDoc->MaxCol() ) ++nEndX; // also from the next cell since the mark
+ if ( nEndY < mpDoc->MaxRow() ) ++nEndY; // protrudes from the preceding cell
+ ScRange aViewRange( nX1, nY1, nTab, nEndX, nEndY, nTab );
+ const ScChangeAction* pAction = pTrack->GetFirst();
+ while (pAction)
+ {
+ if ( pAction->IsVisible() )
+ {
+ ScChangeActionType eActionType = pAction->GetType();
+ const ScBigRange& rBig = pAction->GetBigRange();
+ if ( rBig.aStart.Tab() == nTab )
+ {
+ ScRange aRange = rBig.MakeRange( *mpDoc );
+
+ if ( eActionType == SC_CAT_DELETE_ROWS )
+ aRange.aEnd.SetRow( aRange.aStart.Row() );
+ else if ( eActionType == SC_CAT_DELETE_COLS )
+ aRange.aEnd.SetCol( aRange.aStart.Col() );
+
+ if ( aRange.Intersects( aViewRange ) &&
+ ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
+ {
+ aColorChanger.Update( *pAction );
+ Color aColor( aColorChanger.GetColor() );
+ DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
+
+ }
+ }
+ if ( eActionType == SC_CAT_MOVE &&
+ static_cast<const ScChangeActionMove*>(pAction)->
+ GetFromRange().aStart.Tab() == nTab )
+ {
+ ScRange aRange = static_cast<const ScChangeActionMove*>(pAction)->
+ GetFromRange().MakeRange( *mpDoc );
+ if ( aRange.Intersects( aViewRange ) &&
+ ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
+ {
+ aColorChanger.Update( *pAction );
+ Color aColor( aColorChanger.GetColor() );
+ DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
+ }
+ }
+ }
+
+ pAction = pAction->GetNext();
+ }
+}
+
+void ScOutputData::DrawSparklines(vcl::RenderContext& rRenderContext)
+{
+ Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
+ tools::Long nOneXLogic = aOnePixel.Width();
+ tools::Long nOneYLogic = aOnePixel.Height();
+
+ // See more about bWorksInPixels in ScOutputData::DrawGrid
+ bool bWorksInPixels = false;
+ if (eType == OUTTYPE_WINDOW)
+ bWorksInPixels = true;
+
+ tools::Long nOneX = 1;
+ tools::Long nOneY = 1;
+ if (!bWorksInPixels)
+ {
+ nOneX = nOneXLogic;
+ nOneY = nOneYLogic;
+ }
+
+ tools::Long nInitPosX = nScrX;
+ if ( bLayoutRTL )
+ nInitPosX += nMirrorW - 1; // always in pixels
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ tools::Long nPosY = nScrY;
+ for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ if ( pThisRowInfo->bChanged )
+ {
+ tools::Long nPosX = nInitPosX;
+ for (SCCOL nX=nX1; nX<=nX2; nX++)
+ {
+ ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
+ bool bIsMerged = false;
+
+ if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
+ {
+ // find start of merged cell
+ bIsMerged = true;
+ SCROW nY = pRowInfo[nArrY].nRowNo;
+ SCCOL nMergeX = nX;
+ SCROW nMergeY = nY;
+ mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
+ }
+
+ std::shared_ptr<sc::Sparkline> pSparkline;
+ ScAddress aCurrentAddress(nX, pRowInfo[nArrY].nRowNo, nTab);
+
+ if (!mpDoc->ColHidden(nX, nTab) && (pSparkline = mpDoc->GetSparkline(aCurrentAddress))
+ && (bIsMerged || (!pInfo->bHOverlapped && !pInfo->bVOverlapped)))
+ {
+ const tools::Long nWidth = pRowInfo[0].basicCellInfo(nX).nWidth;
+ const tools::Long nHeight = pThisRowInfo->nHeight;
+
+ Point aPoint(nPosX, nPosY);
+ Size aSize(nWidth, nHeight);
+
+ sc::SparklineRenderer renderer(*mpDoc);
+ renderer.render(pSparkline, rRenderContext, tools::Rectangle(aPoint, aSize), nOneX, nOneY, double(aZoomX), double(aZoomY));
+ }
+
+ nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
+ }
+ }
+ nPosY += pThisRowInfo->nHeight;
+ }
+
+}
+
+//TODO: moggi Need to check if this can't be written simpler
+void ScOutputData::DrawNoteMarks(vcl::RenderContext& rRenderContext)
+{
+
+ bool bFirst = true;
+
+ tools::Long nInitPosX = nScrX;
+ if ( bLayoutRTL )
+ nInitPosX += nMirrorW - 1; // always in pixels
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ tools::Long nPosY = nScrY;
+ for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ if ( pThisRowInfo->bChanged )
+ {
+ tools::Long nPosX = nInitPosX;
+ for (SCCOL nX=nX1; nX<=nX2; nX++)
+ {
+ ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
+ bool bIsMerged = false;
+
+ if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
+ {
+ // find start of merged cell
+ bIsMerged = true;
+ SCROW nY = pRowInfo[nArrY].nRowNo;
+ SCCOL nMergeX = nX;
+ SCROW nMergeY = nY;
+ mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
+ }
+
+ if (!mpDoc->ColHidden(nX, nTab) && mpDoc->GetNote(nX, pRowInfo[nArrY].nRowNo, nTab)
+ && (bIsMerged || (!pInfo->bHOverlapped && !pInfo->bVOverlapped)))
+ {
+ if (bFirst)
+ {
+ rRenderContext.SetLineColor(COL_WHITE);
+
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
+ rRenderContext.SetFillColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
+ else
+ rRenderContext.SetFillColor(COL_LIGHTRED);
+
+ bFirst = false;
+ }
+
+ tools::Long nMarkX = nPosX + ( pRowInfo[0].basicCellInfo(nX).nWidth - 4 ) * nLayoutSign;
+ if ( bIsMerged || pInfo->bMerged )
+ {
+ // if merged, add widths of all cells
+ SCCOL nNextX = nX + 1;
+ while ( nNextX <= nX2 + 1 && pThisRowInfo->cellInfo(nNextX).bHOverlapped )
+ {
+ nMarkX += pRowInfo[0].basicCellInfo(nNextX).nWidth * nLayoutSign;
+ ++nNextX;
+ }
+ }
+ if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
+ rRenderContext.DrawRect( tools::Rectangle( nMarkX-5*nLayoutSign,nPosY,nMarkX+1*nLayoutSign,nPosY+6 ) );
+ }
+
+ nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
+ }
+ }
+ nPosY += pThisRowInfo->nHeight;
+ }
+}
+
+void ScOutputData::AddPDFNotes()
+{
+ vcl::PDFExtOutDevData* pPDFData = dynamic_cast< vcl::PDFExtOutDevData* >( mpDev->GetExtOutDevData() );
+ if ( !pPDFData || !pPDFData->GetIsExportNotes() )
+ return;
+
+ tools::Long nInitPosX = nScrX;
+ if ( bLayoutRTL )
+ {
+ Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ nInitPosX += nMirrorW - nOneX;
+ }
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ tools::Long nPosY = nScrY;
+ for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ if ( pThisRowInfo->bChanged )
+ {
+ tools::Long nPosX = nInitPosX;
+ for (SCCOL nX=nX1; nX<=nX2; nX++)
+ {
+ ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
+ bool bIsMerged = false;
+ SCROW nY = pRowInfo[nArrY].nRowNo;
+ SCCOL nMergeX = nX;
+ SCROW nMergeY = nY;
+
+ if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
+ {
+ // find start of merged cell
+ bIsMerged = true;
+ mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
+ // use origin's pCell for NotePtr test below
+ }
+
+ if ( mpDoc->GetNote(nMergeX, nMergeY, nTab) && ( bIsMerged ||
+ ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
+ {
+ tools::Long nNoteWidth = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
+ tools::Long nNoteHeight = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTY );
+
+ tools::Long nMarkX = nPosX + ( pRowInfo[0].basicCellInfo(nX).nWidth - nNoteWidth ) * nLayoutSign;
+ if ( bIsMerged || pInfo->bMerged )
+ {
+ // if merged, add widths of all cells
+ SCCOL nNextX = nX + 1;
+ while ( nNextX <= nX2 + 1 && pThisRowInfo->cellInfo(nNextX).bHOverlapped )
+ {
+ nMarkX += pRowInfo[0].basicCellInfo(nNextX).nWidth * nLayoutSign;
+ ++nNextX;
+ }
+ }
+ if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
+ {
+ tools::Rectangle aNoteRect( nMarkX, nPosY, nMarkX+nNoteWidth*nLayoutSign, nPosY+nNoteHeight );
+ const ScPostIt* pNote = mpDoc->GetNote(nMergeX, nMergeY, nTab);
+
+ // Note title is the cell address (as on printed note pages)
+ ScAddress aAddress( nMergeX, nMergeY, nTab );
+ OUString aTitle(aAddress.Format(ScRefFlags::VALID, mpDoc, mpDoc->GetAddressConvention()));
+
+ // Content has to be a simple string without line breaks
+ OUString aContent = pNote->GetText();
+ aContent = aContent.replaceAll("\n", " ");
+
+ vcl::PDFNote aNote;
+ aNote.Title = aTitle;
+ aNote.Contents = aContent;
+ pPDFData->CreateNote( aNoteRect, aNote );
+ }
+ }
+
+ nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
+ }
+ }
+ nPosY += pThisRowInfo->nHeight;
+ }
+}
+
+void ScOutputData::DrawClipMarks()
+{
+ if (!bAnyClipped)
+ return;
+
+ Color aArrowFillCol( COL_LIGHTRED );
+
+ DrawModeFlags nOldDrawMode = mpDev->GetDrawMode();
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
+ {
+ // use DrawMode to change the arrow's outline color
+ mpDev->SetDrawMode( nOldDrawMode | DrawModeFlags::SettingsLine );
+ // use text color also for the fill color
+ aArrowFillCol = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
+ }
+
+ tools::Long nInitPosX = nScrX;
+ if ( bLayoutRTL )
+ nInitPosX += nMirrorW - 1; // always in pixels
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ tools::Rectangle aCellRect;
+ tools::Long nPosY = nScrY;
+ for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ if ( pThisRowInfo->bChanged )
+ {
+ SCROW nY = pThisRowInfo->nRowNo;
+ tools::Long nPosX = nInitPosX;
+ for (SCCOL nX=nX1; nX<=nX2; nX++)
+ {
+ ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
+ if (pInfo->nClipMark != ScClipMark::NONE)
+ {
+ if (pInfo->bHOverlapped || pInfo->bVOverlapped)
+ {
+ // merge origin may be outside of visible area - use document functions
+
+ SCCOL nOverX = nX;
+ SCROW nOverY = nY;
+ tools::Long nStartPosX = nPosX;
+ tools::Long nStartPosY = nPosY;
+
+ while ( nOverX > 0 && ( mpDoc->GetAttr(
+ nOverX, nOverY, nTab, ATTR_MERGE_FLAG )->GetValue() & ScMF::Hor ) )
+ {
+ --nOverX;
+ nStartPosX -= nLayoutSign * static_cast<tools::Long>( mpDoc->GetColWidth(nOverX,nTab) * mnPPTX );
+ }
+
+ while ( nOverY > 0 && ( mpDoc->GetAttr(
+ nOverX, nOverY, nTab, ATTR_MERGE_FLAG )->GetValue() & ScMF::Ver ) )
+ {
+ --nOverY;
+ nStartPosY -= nLayoutSign * static_cast<tools::Long>( mpDoc->GetRowHeight(nOverY,nTab) * mnPPTY );
+ }
+
+ tools::Long nOutWidth = static_cast<tools::Long>( mpDoc->GetColWidth(nOverX,nTab) * mnPPTX );
+ tools::Long nOutHeight = static_cast<tools::Long>( mpDoc->GetRowHeight(nOverY,nTab) * mnPPTY );
+
+ const ScMergeAttr* pMerge = mpDoc->GetAttr( nOverX, nOverY, nTab, ATTR_MERGE );
+ SCCOL nCountX = pMerge->GetColMerge();
+ for (SCCOL i=1; i<nCountX; i++)
+ nOutWidth += mpDoc->GetColWidth(nOverX+i,nTab) * mnPPTX;
+ SCROW nCountY = pMerge->GetRowMerge();
+ nOutHeight += mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, mnPPTY);
+
+ if ( bLayoutRTL )
+ nStartPosX -= nOutWidth - 1;
+ aCellRect = tools::Rectangle( Point( nStartPosX, nStartPosY ), Size( nOutWidth, nOutHeight ) );
+ }
+ else
+ {
+ tools::Long nOutWidth = pRowInfo[0].basicCellInfo(nX).nWidth;
+ tools::Long nOutHeight = pThisRowInfo->nHeight;
+
+ if ( pInfo->bMerged && pInfo->pPatternAttr )
+ {
+ SCCOL nOverX = nX;
+ SCROW nOverY = nY;
+ const ScMergeAttr* pMerge =
+ &pInfo->pPatternAttr->GetItem(ATTR_MERGE);
+ SCCOL nCountX = pMerge->GetColMerge();
+ for (SCCOL i=1; i<nCountX; i++)
+ nOutWidth += mpDoc->GetColWidth(nOverX+i,nTab) * mnPPTX;
+ SCROW nCountY = pMerge->GetRowMerge();
+ nOutHeight += mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, mnPPTY);
+ }
+
+ tools::Long nStartPosX = nPosX;
+ if ( bLayoutRTL )
+ nStartPosX -= nOutWidth - 1;
+ // #i80447# create aCellRect from two points in case nOutWidth is 0
+ aCellRect = tools::Rectangle( Point( nStartPosX, nPosY ),
+ Point( nStartPosX+nOutWidth-1, nPosY+nOutHeight-1 ) );
+ }
+
+ aCellRect.AdjustBottom( -1 ); // don't paint over the cell grid
+ if ( bLayoutRTL )
+ aCellRect.AdjustLeft(1 );
+ else
+ aCellRect.AdjustRight( -1 );
+
+ tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
+ Size aMarkSize( nMarkPixel, (nMarkPixel-1)*2 );
+
+ if (bVertical)
+ {
+ if (pInfo->nClipMark & (bLayoutRTL ? ScClipMark::Bottom : ScClipMark::Top))
+ {
+ // visually top
+ tools::Rectangle aMarkRect = aCellRect;
+ aMarkRect.SetBottom(aCellRect.Top() + nMarkPixel - 1);
+ SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, true, true);
+ }
+ if (pInfo->nClipMark & (bLayoutRTL ? ScClipMark::Top : ScClipMark::Bottom))
+ {
+ // visually bottom
+ tools::Rectangle aMarkRect = aCellRect;
+ aMarkRect.SetTop(aCellRect.Bottom() + nMarkPixel + 1);
+ SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, false,
+ true);
+ }
+ }
+ else
+ {
+ if (pInfo->nClipMark & (bLayoutRTL ? ScClipMark::Right : ScClipMark::Left))
+ {
+ // visually left
+ tools::Rectangle aMarkRect = aCellRect;
+ aMarkRect.SetRight(aCellRect.Left() + nMarkPixel - 1);
+ SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, true,
+ false);
+ }
+ if (pInfo->nClipMark & (bLayoutRTL ? ScClipMark::Left : ScClipMark::Right))
+ {
+ // visually right
+ tools::Rectangle aMarkRect = aCellRect;
+ aMarkRect.SetLeft(aCellRect.Right() - nMarkPixel + 1);
+ SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, false,
+ false);
+ }
+ }
+ }
+ nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
+ }
+ }
+ nPosY += pThisRowInfo->nHeight;
+ }
+
+ mpDev->SetDrawMode(nOldDrawMode);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx
new file mode 100644
index 000000000..5c234df79
--- /dev/null
+++ b/sc/source/ui/view/output2.cxx
@@ -0,0 +1,5123 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <editeng/adjustitem.hxx>
+#include <svx/algitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <svtools/colorcfg.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/charreliefitem.hxx>
+#include <editeng/crossedoutitem.hxx>
+#include <editeng/contouritem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/emphasismarkitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/forbiddenruleitem.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <svx/rotmodit.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/unolingu.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/shdditem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/wrlmitem.hxx>
+#include <formula/errorcodes.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/metric.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/pdfextoutdevdata.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/glyphitem.hxx>
+#include <vcl/vcllayout.hxx>
+#include <vcl/glyphitemcache.hxx>
+#include <sal/log.hxx>
+#include <unotools/charclass.hxx>
+#include <osl/diagnose.h>
+#include <tools/stream.hxx>
+
+#include <output.hxx>
+#include <document.hxx>
+#include <formulacell.hxx>
+#include <attrib.hxx>
+#include <patattr.hxx>
+#include <cellform.hxx>
+#include <editutil.hxx>
+#include <progress.hxx>
+#include <scmod.hxx>
+#include <fillinfo.hxx>
+#include <stlsheet.hxx>
+#include <spellcheckcontext.hxx>
+#include <scopetools.hxx>
+
+#include <com/sun/star/i18n/DirectionProperty.hpp>
+#include <comphelper/scopeguard.hxx>
+#include <comphelper/string.hxx>
+
+#include <memory>
+#include <vector>
+#include <o3tl/lru_map.hxx>
+#include <o3tl/hash_combine.hxx>
+
+#include <math.h>
+
+using namespace com::sun::star;
+
+//! Merge Autofilter width with column.cxx
+#define DROPDOWN_BITMAP_SIZE 18
+
+#define DRAWTEXT_MAX 32767
+
+const sal_uInt16 SC_SHRINKAGAIN_MAX = 7;
+constexpr auto HMM_PER_TWIPS = o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100);
+
+class ScDrawStringsVars
+{
+ ScOutputData* pOutput; // connection
+
+ const ScPatternAttr* pPattern; // attribute
+ const SfxItemSet* pCondSet; // from conditional formatting
+
+ vcl::Font aFont; // created from attributes
+ FontMetric aMetric;
+ tools::Long nAscentPixel; // always pixels
+ SvxCellOrientation eAttrOrient;
+ SvxCellHorJustify eAttrHorJust;
+ SvxCellVerJustify eAttrVerJust;
+ SvxCellJustifyMethod eAttrHorJustMethod;
+ const SvxMarginItem* pMargin;
+ sal_uInt16 nIndent;
+ bool bRotated;
+
+ OUString aString; // contents
+ Size aTextSize;
+ tools::Long nOriginalWidth;
+ tools::Long nMaxDigitWidth;
+ tools::Long nSignWidth;
+ tools::Long nDotWidth;
+ tools::Long nExpWidth;
+
+ ScRefCellValue maLastCell;
+ sal_uLong nValueFormat;
+ bool bLineBreak;
+ bool bRepeat;
+ bool bShrink;
+
+ bool bPixelToLogic;
+ bool bCellContrast;
+
+ Color aBackConfigColor; // used for ScPatternAttr::GetFont calls
+ Color aTextConfigColor;
+ sal_Int32 nRepeatPos;
+ sal_Unicode nRepeatChar;
+
+public:
+ ScDrawStringsVars(ScOutputData* pData, bool bPTL);
+
+ // SetPattern = ex-SetVars
+ // SetPatternSimple: without Font
+
+ void SetPattern(
+ const ScPatternAttr* pNew, const SfxItemSet* pSet, const ScRefCellValue& rCell,
+ SvtScriptType nScript );
+
+ void SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet );
+
+ bool SetText( const ScRefCellValue& rCell ); // TRUE -> drop pOldPattern
+ void SetHashText();
+ void SetTextToWidthOrHash( ScRefCellValue& rCell, tools::Long nWidth );
+ void SetAutoText( const OUString& rAutoText );
+
+ SvxCellOrientation GetOrient() const { return eAttrOrient; }
+ SvxCellHorJustify GetHorJust() const { return eAttrHorJust; }
+ SvxCellVerJustify GetVerJust() const { return eAttrVerJust; }
+ SvxCellJustifyMethod GetHorJustMethod() const { return eAttrHorJustMethod; }
+ const SvxMarginItem* GetMargin() const { return pMargin; }
+
+ sal_uInt16 GetLeftTotal() const { return pMargin->GetLeftMargin() + nIndent; }
+ sal_uInt16 GetRightTotal() const { return pMargin->GetRightMargin() + nIndent; }
+
+ const OUString& GetString() const { return aString; }
+ const Size& GetTextSize() const { return aTextSize; }
+ tools::Long GetOriginalWidth() const { return nOriginalWidth; }
+ tools::Long GetFmtTextWidth(const OUString& rString);
+
+ // Get the effective number format, including formula result types.
+ // This assumes that a formula cell has already been calculated.
+ sal_uLong GetResultValueFormat() const { return nValueFormat;}
+
+ bool GetLineBreak() const { return bLineBreak; }
+ bool IsRepeat() const { return bRepeat; }
+ bool IsShrink() const { return bShrink; }
+ void RepeatToFill( tools::Long nColWidth );
+
+ tools::Long GetAscent() const { return nAscentPixel; }
+ bool IsRotated() const { return bRotated; }
+
+ void SetShrinkScale( tools::Long nScale, SvtScriptType nScript );
+
+ bool HasCondHeight() const { return pCondSet && SfxItemState::SET ==
+ pCondSet->GetItemState( ATTR_FONT_HEIGHT ); }
+
+ bool HasEditCharacters() const;
+
+ // ScOutputData::LayoutStrings() usually triggers a number of calls that require
+ // to lay out the text, which is relatively slow, so cache that operation.
+ const SalLayoutGlyphs* GetLayoutGlyphs(const OUString& rString) const
+ {
+ return SalLayoutGlyphsCache::self()->GetLayoutGlyphs(pOutput->pFmtDevice, rString);
+ }
+
+private:
+ tools::Long GetMaxDigitWidth(); // in logic units
+ tools::Long GetSignWidth();
+ tools::Long GetDotWidth();
+ tools::Long GetExpWidth();
+ void TextChanged();
+};
+
+ScDrawStringsVars::ScDrawStringsVars(ScOutputData* pData, bool bPTL) :
+ pOutput ( pData ),
+ pPattern ( nullptr ),
+ pCondSet ( nullptr ),
+ nAscentPixel(0),
+ eAttrOrient ( SvxCellOrientation::Standard ),
+ eAttrHorJust( SvxCellHorJustify::Standard ),
+ eAttrVerJust( SvxCellVerJustify::Bottom ),
+ eAttrHorJustMethod( SvxCellJustifyMethod::Auto ),
+ pMargin ( nullptr ),
+ nIndent ( 0 ),
+ bRotated ( false ),
+ nOriginalWidth( 0 ),
+ nMaxDigitWidth( 0 ),
+ nSignWidth( 0 ),
+ nDotWidth( 0 ),
+ nExpWidth( 0 ),
+ nValueFormat( 0 ),
+ bLineBreak ( false ),
+ bRepeat ( false ),
+ bShrink ( false ),
+ bPixelToLogic( bPTL ),
+ nRepeatPos( -1 ),
+ nRepeatChar( 0x0 )
+{
+ ScModule* pScMod = SC_MOD();
+ bCellContrast = pOutput->mbUseStyleColor &&
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode();
+
+ const svtools::ColorConfig& rColorConfig = pScMod->GetColorConfig();
+ aBackConfigColor = rColorConfig.GetColorValue(svtools::DOCCOLOR).nColor;
+ aTextConfigColor = rColorConfig.GetColorValue(svtools::FONTCOLOR).nColor;
+}
+
+void ScDrawStringsVars::SetShrinkScale( tools::Long nScale, SvtScriptType nScript )
+{
+ // text remains valid, size is updated
+
+ OutputDevice* pDev = pOutput->mpDev;
+ OutputDevice* pRefDevice = pOutput->mpRefDevice;
+ OutputDevice* pFmtDevice = pOutput->pFmtDevice;
+
+ // call GetFont with a modified fraction, use only the height
+
+ Fraction aFraction( nScale, 100 );
+ if ( !bPixelToLogic )
+ aFraction *= pOutput->aZoomY;
+ vcl::Font aTmpFont;
+ pPattern->GetFont( aTmpFont, SC_AUTOCOL_RAW, pFmtDevice, &aFraction, pCondSet, nScript );
+ tools::Long nNewHeight = aTmpFont.GetFontHeight();
+ if ( nNewHeight > 0 )
+ aFont.SetFontHeight( nNewHeight );
+
+ // set font and dependent variables as in SetPattern
+
+ pDev->SetFont( aFont );
+ if ( pFmtDevice != pDev )
+ pFmtDevice->SetFont( aFont );
+
+ aMetric = pFmtDevice->GetFontMetric();
+ if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetInternalLeading() == 0 )
+ {
+ OutputDevice* pDefaultDev = Application::GetDefaultDevice();
+ MapMode aOld = pDefaultDev->GetMapMode();
+ pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
+ aMetric = pDefaultDev->GetFontMetric( aFont );
+ pDefaultDev->SetMapMode( aOld );
+ }
+
+ nAscentPixel = aMetric.GetAscent();
+ if ( bPixelToLogic )
+ nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
+
+ SetAutoText( aString ); // same text again, to get text size
+}
+
+namespace {
+
+template<typename ItemType, typename EnumType>
+EnumType lcl_GetValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
+{
+ const ItemType& rItem = static_cast<const ItemType&>(rPattern.GetItem(nWhich, pCondSet));
+ return static_cast<EnumType>(rItem.GetValue());
+}
+
+bool lcl_GetBoolValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
+{
+ return lcl_GetValue<SfxBoolItem, bool>(rPattern, nWhich, pCondSet);
+}
+
+}
+
+static bool lcl_isNumberFormatText(const ScDocument* pDoc, SCCOL nCellX, SCROW nCellY, SCTAB nTab )
+{
+ sal_uInt32 nCurrentNumberFormat = pDoc->GetNumberFormat( nCellX, nCellY, nTab );
+ SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable();
+ return pNumberFormatter->GetType( nCurrentNumberFormat ) == SvNumFormatType::TEXT;
+}
+
+void ScDrawStringsVars::SetPattern(
+ const ScPatternAttr* pNew, const SfxItemSet* pSet, const ScRefCellValue& rCell,
+ SvtScriptType nScript )
+{
+ nMaxDigitWidth = 0;
+ nSignWidth = 0;
+ nDotWidth = 0;
+ nExpWidth = 0;
+
+ pPattern = pNew;
+ pCondSet = pSet;
+
+ // evaluate pPattern
+
+ OutputDevice* pDev = pOutput->mpDev;
+ OutputDevice* pRefDevice = pOutput->mpRefDevice;
+ OutputDevice* pFmtDevice = pOutput->pFmtDevice;
+
+ // font
+
+ ScAutoFontColorMode eColorMode;
+ if ( pOutput->mbUseStyleColor )
+ {
+ if ( pOutput->mbForceAutoColor )
+ eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREALL : SC_AUTOCOL_IGNOREFONT;
+ else
+ eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREBACK : SC_AUTOCOL_DISPLAY;
+ }
+ else
+ eColorMode = SC_AUTOCOL_PRINT;
+
+ if ( bPixelToLogic )
+ pPattern->GetFont( aFont, eColorMode, pFmtDevice, nullptr, pCondSet, nScript,
+ &aBackConfigColor, &aTextConfigColor );
+ else
+ pPattern->GetFont( aFont, eColorMode, pFmtDevice, &pOutput->aZoomY, pCondSet, nScript,
+ &aBackConfigColor, &aTextConfigColor );
+ aFont.SetAlignment(ALIGN_BASELINE);
+
+ // orientation
+
+ eAttrOrient = pPattern->GetCellOrientation( pCondSet );
+
+ // alignment
+
+ eAttrHorJust = pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet ).GetValue();
+
+ eAttrVerJust = pPattern->GetItem( ATTR_VER_JUSTIFY, pCondSet ).GetValue();
+ if ( eAttrVerJust == SvxCellVerJustify::Standard )
+ eAttrVerJust = SvxCellVerJustify::Bottom;
+
+ // justification method
+
+ eAttrHorJustMethod = lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet);
+
+ // line break
+
+ bLineBreak = pPattern->GetItem( ATTR_LINEBREAK, pCondSet ).GetValue();
+
+ // handle "repeat" alignment
+
+ bRepeat = ( eAttrHorJust == SvxCellHorJustify::Repeat );
+ if ( bRepeat )
+ {
+ // "repeat" disables rotation (before constructing the font)
+ eAttrOrient = SvxCellOrientation::Standard;
+
+ // #i31843# "repeat" with "line breaks" is treated as default alignment (but rotation is still disabled)
+ if ( bLineBreak )
+ eAttrHorJust = SvxCellHorJustify::Standard;
+ }
+
+ sal_Int16 nRot;
+ switch (eAttrOrient)
+ {
+ case SvxCellOrientation::Standard:
+ nRot = 0;
+ bRotated = pPattern->GetItem( ATTR_ROTATE_VALUE, pCondSet ).GetValue() != 0_deg100 &&
+ !bRepeat;
+ break;
+ case SvxCellOrientation::Stacked:
+ nRot = 0;
+ bRotated = false;
+ break;
+ case SvxCellOrientation::TopBottom:
+ nRot = 2700;
+ bRotated = false;
+ break;
+ case SvxCellOrientation::BottomUp:
+ nRot = 900;
+ bRotated = false;
+ break;
+ default:
+ OSL_FAIL("Invalid SvxCellOrientation value");
+ nRot = 0;
+ bRotated = false;
+ break;
+ }
+ aFont.SetOrientation( Degree10(nRot) );
+
+ // syntax mode
+
+ if (pOutput->mbSyntaxMode)
+ pOutput->SetSyntaxColor(&aFont, rCell);
+
+ // There is no cell attribute for kerning, default is kerning OFF, all
+ // kerning is stored at an EditText object that is drawn using EditEngine.
+ aFont.SetKerning( FontKerning::NONE);
+
+ pDev->SetFont( aFont );
+ if ( pFmtDevice != pDev )
+ pFmtDevice->SetFont( aFont );
+
+ aMetric = pFmtDevice->GetFontMetric();
+
+ // if there is the leading 0 on a printer device, we have problems
+ // -> take metric from the screen (as for EditEngine!)
+ if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetInternalLeading() == 0 )
+ {
+ OutputDevice* pDefaultDev = Application::GetDefaultDevice();
+ MapMode aOld = pDefaultDev->GetMapMode();
+ pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
+ aMetric = pDefaultDev->GetFontMetric( aFont );
+ pDefaultDev->SetMapMode( aOld );
+ }
+
+ nAscentPixel = aMetric.GetAscent();
+ if ( bPixelToLogic )
+ nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
+
+ Color aULineColor( pPattern->GetItem( ATTR_FONT_UNDERLINE, pCondSet ).GetColor() );
+ pDev->SetTextLineColor( aULineColor );
+
+ Color aOLineColor( pPattern->GetItem( ATTR_FONT_OVERLINE, pCondSet ).GetColor() );
+ pDev->SetOverlineColor( aOLineColor );
+
+ // number format
+
+ nValueFormat = pPattern->GetNumberFormat( pOutput->mpDoc->GetFormatTable(), pCondSet );
+
+ // margins
+ pMargin = &pPattern->GetItem( ATTR_MARGIN, pCondSet );
+ if ( eAttrHorJust == SvxCellHorJustify::Left || eAttrHorJust == SvxCellHorJustify::Right )
+ nIndent = pPattern->GetItem( ATTR_INDENT, pCondSet ).GetValue();
+ else
+ nIndent = 0;
+
+ // "Shrink to fit"
+
+ bShrink = pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet ).GetValue();
+
+ // at least the text size needs to be retrieved again
+ //! differentiate and do not get the text again from the number format?
+ maLastCell.clear();
+}
+
+void ScDrawStringsVars::SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet )
+{
+ nMaxDigitWidth = 0;
+ nSignWidth = 0;
+ nDotWidth = 0;
+ nExpWidth = 0;
+
+ // Is called, when the font variables do not change (!StringDiffer)
+
+ pPattern = pNew;
+ pCondSet = pSet; //! is this needed ???
+
+ // number format
+
+ sal_uLong nOld = nValueFormat;
+ nValueFormat = pPattern->GetNumberFormat( pOutput->mpDoc->GetFormatTable(), pCondSet );
+
+ if (nValueFormat != nOld)
+ maLastCell.clear(); // always reformat
+
+ // margins
+
+ pMargin = &pPattern->GetItem( ATTR_MARGIN, pCondSet );
+
+ if ( eAttrHorJust == SvxCellHorJustify::Left )
+ nIndent = pPattern->GetItem( ATTR_INDENT, pCondSet ).GetValue();
+ else
+ nIndent = 0;
+
+ // "Shrink to fit"
+
+ bShrink = pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet ).GetValue();
+}
+
+static bool SameValue( const ScRefCellValue& rCell, const ScRefCellValue& rOldCell )
+{
+ return rOldCell.meType == CELLTYPE_VALUE && rCell.meType == CELLTYPE_VALUE &&
+ rCell.mfValue == rOldCell.mfValue;
+}
+
+bool ScDrawStringsVars::SetText( const ScRefCellValue& rCell )
+{
+ bool bChanged = false;
+
+ if (!rCell.isEmpty())
+ {
+ if (!SameValue(rCell, maLastCell))
+ {
+ maLastCell = rCell; // store cell
+
+ const Color* pColor;
+ sal_uLong nFormat = nValueFormat;
+ aString = ScCellFormat::GetString( rCell,
+ nFormat, &pColor,
+ *pOutput->mpDoc->GetFormatTable(),
+ *pOutput->mpDoc,
+ pOutput->mbShowNullValues,
+ pOutput->mbShowFormulas,
+ true );
+ if ( nFormat )
+ {
+ nRepeatPos = aString.indexOf( 0x1B );
+ if ( nRepeatPos != -1 )
+ {
+ if (nRepeatPos + 1 == aString.getLength())
+ nRepeatPos = -1;
+ else
+ {
+ nRepeatChar = aString[ nRepeatPos + 1 ];
+ // delete placeholder and char to repeat
+ aString = aString.replaceAt( nRepeatPos, 2, u"" );
+ // Do not cache/reuse a repeat-filled string, column
+ // widths or fonts or sizes may differ.
+ maLastCell.clear();
+ }
+ }
+ }
+ else
+ {
+ nRepeatPos = -1;
+ nRepeatChar = 0x0;
+ }
+ if (aString.getLength() > DRAWTEXT_MAX)
+ aString = aString.copy(0, DRAWTEXT_MAX);
+
+ if ( pColor && !pOutput->mbSyntaxMode && !( pOutput->mbUseStyleColor && pOutput->mbForceAutoColor ) )
+ {
+ OutputDevice* pDev = pOutput->mpDev;
+ aFont.SetColor(*pColor);
+ pDev->SetFont( aFont ); // only for output
+ bChanged = true;
+ maLastCell.clear(); // next time return here again
+ }
+
+ TextChanged();
+ }
+ // otherwise keep string/size
+ }
+ else
+ {
+ aString.clear();
+ maLastCell.clear();
+ aTextSize = Size(0,0);
+ nOriginalWidth = 0;
+ }
+
+ return bChanged;
+}
+
+void ScDrawStringsVars::SetHashText()
+{
+ SetAutoText("###");
+}
+
+void ScDrawStringsVars::RepeatToFill( tools::Long nColWidth )
+{
+ if ( nRepeatPos == -1 || nRepeatPos > aString.getLength() )
+ return;
+
+ tools::Long nCharWidth = GetFmtTextWidth(OUString(nRepeatChar));
+
+ if ( nCharWidth < 1 || (bPixelToLogic && nCharWidth < pOutput->mpRefDevice->PixelToLogic(Size(1,0)).Width()) )
+ return;
+
+ // Are there restrictions on the cell type we should filter out here ?
+ tools::Long nTextWidth = aTextSize.Width();
+ if ( bPixelToLogic )
+ {
+ nColWidth = pOutput->mpRefDevice->PixelToLogic(Size(nColWidth,0)).Width();
+ nTextWidth = pOutput->mpRefDevice->PixelToLogic(Size(nTextWidth,0)).Width();
+ }
+
+ tools::Long nSpaceToFill = nColWidth - nTextWidth;
+ if ( nSpaceToFill <= nCharWidth )
+ return;
+
+ sal_Int32 nCharsToInsert = nSpaceToFill / nCharWidth;
+ OUStringBuffer aFill(nCharsToInsert);
+ comphelper::string::padToLength(aFill, nCharsToInsert, nRepeatChar);
+ aString = aString.replaceAt( nRepeatPos, 0, aFill );
+ TextChanged();
+}
+
+void ScDrawStringsVars::SetTextToWidthOrHash( ScRefCellValue& rCell, tools::Long nWidth )
+{
+ // #i113045# do the single-character width calculations in logic units
+ if (bPixelToLogic)
+ nWidth = pOutput->mpRefDevice->PixelToLogic(Size(nWidth,0)).Width();
+
+ CellType eType = rCell.meType;
+ if (eType != CELLTYPE_VALUE && eType != CELLTYPE_FORMULA)
+ // must be a value or formula cell.
+ return;
+
+ if (eType == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = rCell.mpFormula;
+ if (pFCell->GetErrCode() != FormulaError::NONE || pOutput->mbShowFormulas)
+ {
+ SetHashText(); // If the error string doesn't fit, always use "###". Also for "display formulas" (#i116691#)
+ return;
+ }
+ // If it's formula, the result must be a value.
+ if (!pFCell->IsValue())
+ return;
+ }
+
+ sal_uLong nFormat = GetResultValueFormat();
+ if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
+ {
+ // Not 'General' number format. Set hash text and bail out.
+ SetHashText();
+ return;
+ }
+
+ double fVal = rCell.getValue();
+
+ const SvNumberformat* pNumFormat = pOutput->mpDoc->GetFormatTable()->GetEntry(nFormat);
+ if (!pNumFormat)
+ return;
+
+ tools::Long nMaxDigit = GetMaxDigitWidth();
+ if (!nMaxDigit)
+ return;
+
+ sal_uInt16 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
+ {
+ OUString sTempOut(aString);
+ if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
+ {
+ aString = sTempOut;
+ // Failed to get output string. Bail out.
+ return;
+ }
+ aString = sTempOut;
+ }
+ sal_uInt8 nSignCount = 0, nDecimalCount = 0, nExpCount = 0;
+ sal_Int32 nLen = aString.getLength();
+ sal_Unicode cDecSep = ScGlobal::getLocaleData().getLocaleItem().decimalSeparator[0];
+ for( sal_Int32 i = 0; i < nLen; ++i )
+ {
+ sal_Unicode c = aString[i];
+ if (c == '-')
+ ++nSignCount;
+ else if (c == cDecSep)
+ ++nDecimalCount;
+ else if (c == 'E')
+ ++nExpCount;
+ }
+
+ // #i112250# A small value might be formatted as "0" when only counting the digits,
+ // but fit into the column when considering the smaller width of the decimal separator.
+ if (aString == "0" && fVal != 0.0)
+ nDecimalCount = 1;
+
+ if (nDecimalCount)
+ nWidth += (nMaxDigit - GetDotWidth()) * nDecimalCount;
+ if (nSignCount)
+ nWidth += (nMaxDigit - GetSignWidth()) * nSignCount;
+ if (nExpCount)
+ nWidth += (nMaxDigit - GetExpWidth()) * nExpCount;
+
+ if (nDecimalCount || nSignCount || nExpCount)
+ {
+ // Re-calculate.
+ nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
+ OUString sTempOut(aString);
+ if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
+ {
+ aString = sTempOut;
+ // Failed to get output string. Bail out.
+ return;
+ }
+ aString = sTempOut;
+ }
+
+ tools::Long nActualTextWidth = GetFmtTextWidth(aString);
+ if (nActualTextWidth > nWidth)
+ {
+ // Even after the decimal adjustment the text doesn't fit. Give up.
+ SetHashText();
+ return;
+ }
+
+ TextChanged();
+ maLastCell.clear(); // #i113022# equal cell and format in another column may give different string
+}
+
+void ScDrawStringsVars::SetAutoText( const OUString& rAutoText )
+{
+ aString = rAutoText;
+
+ OutputDevice* pRefDevice = pOutput->mpRefDevice;
+ OutputDevice* pFmtDevice = pOutput->pFmtDevice;
+ aTextSize.setWidth( GetFmtTextWidth( aString ) );
+ aTextSize.setHeight( pFmtDevice->GetTextHeight() );
+
+ if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
+ {
+ double fMul = pOutput->GetStretch();
+ aTextSize.setWidth( static_cast<tools::Long>(aTextSize.Width() / fMul + 0.5) );
+ }
+
+ aTextSize.setHeight( aMetric.GetAscent() + aMetric.GetDescent() );
+ if ( GetOrient() != SvxCellOrientation::Standard )
+ {
+ tools::Long nTemp = aTextSize.Height();
+ aTextSize.setHeight( aTextSize.Width() );
+ aTextSize.setWidth( nTemp );
+ }
+
+ nOriginalWidth = aTextSize.Width();
+ if ( bPixelToLogic )
+ aTextSize = pRefDevice->LogicToPixel( aTextSize );
+
+ maLastCell.clear(); // the same text may fit in the next cell
+}
+
+tools::Long ScDrawStringsVars::GetMaxDigitWidth()
+{
+ if (nMaxDigitWidth > 0)
+ return nMaxDigitWidth;
+
+ for (char i = 0; i < 10; ++i)
+ {
+ char cDigit = '0' + i;
+ // Do not cache this with GetFmtTextWidth(), nMaxDigitWidth is already cached.
+ tools::Long n = pOutput->pFmtDevice->GetTextWidth(OUString(cDigit));
+ nMaxDigitWidth = ::std::max(nMaxDigitWidth, n);
+ }
+ return nMaxDigitWidth;
+}
+
+tools::Long ScDrawStringsVars::GetSignWidth()
+{
+ if (nSignWidth > 0)
+ return nSignWidth;
+
+ nSignWidth = pOutput->pFmtDevice->GetTextWidth(OUString('-'));
+ return nSignWidth;
+}
+
+tools::Long ScDrawStringsVars::GetDotWidth()
+{
+ if (nDotWidth > 0)
+ return nDotWidth;
+
+ const OUString& sep = ScGlobal::getLocaleData().getLocaleItem().decimalSeparator;
+ nDotWidth = pOutput->pFmtDevice->GetTextWidth(sep);
+ return nDotWidth;
+}
+
+tools::Long ScDrawStringsVars::GetExpWidth()
+{
+ if (nExpWidth > 0)
+ return nExpWidth;
+
+ nExpWidth = pOutput->pFmtDevice->GetTextWidth(OUString('E'));
+ return nExpWidth;
+}
+
+tools::Long ScDrawStringsVars::GetFmtTextWidth( const OUString& rString )
+{
+ return pOutput->pFmtDevice->GetTextWidth( rString, 0, -1, nullptr, GetLayoutGlyphs( rString ));
+}
+
+void ScDrawStringsVars::TextChanged()
+{
+ OutputDevice* pRefDevice = pOutput->mpRefDevice;
+ OutputDevice* pFmtDevice = pOutput->pFmtDevice;
+ aTextSize.setWidth( GetFmtTextWidth( aString ) );
+ aTextSize.setHeight( pFmtDevice->GetTextHeight() );
+
+ if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
+ {
+ double fMul = pOutput->GetStretch();
+ aTextSize.setWidth( static_cast<tools::Long>(aTextSize.Width() / fMul + 0.5) );
+ }
+
+ aTextSize.setHeight( aMetric.GetAscent() + aMetric.GetDescent() );
+ if ( GetOrient() != SvxCellOrientation::Standard )
+ {
+ tools::Long nTemp = aTextSize.Height();
+ aTextSize.setHeight( aTextSize.Width() );
+ aTextSize.setWidth( nTemp );
+ }
+
+ nOriginalWidth = aTextSize.Width();
+ if ( bPixelToLogic )
+ aTextSize = pRefDevice->LogicToPixel( aTextSize );
+}
+
+bool ScDrawStringsVars::HasEditCharacters() const
+{
+ for (sal_Int32 nIdx = 0; nIdx < aString.getLength(); ++nIdx)
+ {
+ switch(aString[nIdx])
+ {
+ case CHAR_NBSP:
+ case CHAR_SHY:
+ case CHAR_ZWSP:
+ case CHAR_LRM:
+ case CHAR_RLM:
+ case CHAR_NBHY:
+ case CHAR_WJ:
+ return true;
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
+double ScOutputData::GetStretch() const
+{
+ if ( mpRefDevice->IsMapModeEnabled() )
+ {
+ // If a non-trivial MapMode is set, its scale is now already
+ // taken into account in the OutputDevice's font handling
+ // (OutputDevice::ImplNewFont, see #95414#).
+ // The old handling below is only needed for pixel output.
+ return 1.0;
+ }
+
+ // calculation in double is faster than Fraction multiplication
+ // and doesn't overflow
+
+ if ( mpRefDevice == pFmtDevice )
+ {
+ MapMode aOld = mpRefDevice->GetMapMode();
+ return static_cast<double>(aOld.GetScaleY()) / static_cast<double>(aOld.GetScaleX()) * static_cast<double>(aZoomY) / static_cast<double>(aZoomX);
+ }
+ else
+ {
+ // when formatting for printer, device map mode has already been taken care of
+ return static_cast<double>(aZoomY) / static_cast<double>(aZoomX);
+ }
+}
+
+// output strings
+
+static void lcl_DoHyperlinkResult( const OutputDevice* pDev, const tools::Rectangle& rRect, ScRefCellValue& rCell )
+{
+ vcl::PDFExtOutDevData* pPDFData = dynamic_cast< vcl::PDFExtOutDevData* >( pDev->GetExtOutDevData() );
+
+ OUString aURL;
+ OUString aCellText;
+ if (rCell.meType == CELLTYPE_FORMULA)
+ {
+ ScFormulaCell* pFCell = rCell.mpFormula;
+ if ( pFCell->IsHyperLinkCell() )
+ pFCell->GetURLResult( aURL, aCellText );
+ }
+
+ if ( !aURL.isEmpty() && pPDFData )
+ {
+ vcl::PDFExtOutDevBookmarkEntry aBookmark;
+ aBookmark.nLinkId = pPDFData->CreateLink(rRect, aCellText);
+ aBookmark.aBookmark = aURL;
+ std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFData->GetBookmarks();
+ rBookmarks.push_back( aBookmark );
+ }
+}
+
+void ScOutputData::SetSyntaxColor( vcl::Font* pFont, const ScRefCellValue& rCell )
+{
+ switch (rCell.meType)
+ {
+ case CELLTYPE_VALUE:
+ pFont->SetColor(*mxValueColor);
+ break;
+ case CELLTYPE_STRING:
+ pFont->SetColor(*mxTextColor);
+ break;
+ case CELLTYPE_FORMULA:
+ pFont->SetColor(*mxFormulaColor);
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+}
+
+static void lcl_SetEditColor( EditEngine& rEngine, const Color& rColor )
+{
+ ESelection aSel( 0, 0, rEngine.GetParagraphCount(), 0 );
+ SfxItemSet aSet( rEngine.GetEmptyItemSet() );
+ aSet.Put( SvxColorItem( rColor, EE_CHAR_COLOR ) );
+ rEngine.QuickSetAttribs( aSet, aSel );
+ // function is called with update mode set to FALSE
+}
+
+void ScOutputData::SetEditSyntaxColor( EditEngine& rEngine, const ScRefCellValue& rCell )
+{
+ Color aColor;
+ switch (rCell.meType)
+ {
+ case CELLTYPE_VALUE:
+ aColor = *mxValueColor;
+ break;
+ case CELLTYPE_STRING:
+ aColor = *mxTextColor;
+ break;
+ case CELLTYPE_FORMULA:
+ aColor = *mxFormulaColor;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ lcl_SetEditColor( rEngine, aColor );
+}
+
+bool ScOutputData::GetMergeOrigin( SCCOL nX, SCROW nY, SCSIZE nArrY,
+ SCCOL& rOverX, SCROW& rOverY,
+ bool bVisRowChanged )
+{
+ bool bDoMerge = false;
+ bool bIsLeft = ( nX == nVisX1 );
+ bool bIsTop = ( nY == nVisY1 ) || bVisRowChanged;
+
+ bool bHOver;
+ bool bVOver;
+ bool bHidden;
+
+ if (!mpDoc->ColHidden(nX, nTab) && nX >= nX1 && nX <= nX2
+ && !mpDoc->RowHidden(nY, nTab) && nY >= nY1 && nY <= nY2)
+ {
+ ScCellInfo* pInfo = &pRowInfo[nArrY].cellInfo(nX);
+ bHOver = pInfo->bHOverlapped;
+ bVOver = pInfo->bVOverlapped;
+ }
+ else
+ {
+ ScMF nOverlap2 = mpDoc->GetAttr(nX, nY, nTab, ATTR_MERGE_FLAG)->GetValue();
+ bHOver = bool(nOverlap2 & ScMF::Hor);
+ bVOver = bool(nOverlap2 & ScMF::Ver);
+ }
+
+ if ( bHOver && bVOver )
+ bDoMerge = bIsLeft && bIsTop;
+ else if ( bHOver )
+ bDoMerge = bIsLeft;
+ else if ( bVOver )
+ bDoMerge = bIsTop;
+
+ rOverX = nX;
+ rOverY = nY;
+
+ while (bHOver) // nY constant
+ {
+ --rOverX;
+ bHidden = mpDoc->ColHidden(rOverX, nTab);
+ if ( !bDoMerge && !bHidden )
+ return false;
+
+ if (rOverX >= nX1 && !bHidden)
+ {
+ bHOver = pRowInfo[nArrY].cellInfo(rOverX).bHOverlapped;
+ bVOver = pRowInfo[nArrY].cellInfo(rOverX).bVOverlapped;
+ }
+ else
+ {
+ ScMF nOverlap = mpDoc->GetAttr(rOverX, rOverY, nTab, ATTR_MERGE_FLAG)->GetValue();
+ bHOver = bool(nOverlap & ScMF::Hor);
+ bVOver = bool(nOverlap & ScMF::Ver);
+ }
+ }
+
+ while (bVOver)
+ {
+ --rOverY;
+ bHidden = mpDoc->RowHidden(rOverY, nTab);
+ if ( !bDoMerge && !bHidden )
+ return false;
+
+ if (nArrY>0)
+ --nArrY; // local copy !
+
+ if (rOverX >= nX1 && rOverY >= nY1 &&
+ !mpDoc->ColHidden(rOverX, nTab) &&
+ !mpDoc->RowHidden(rOverY, nTab) &&
+ pRowInfo[nArrY].nRowNo == rOverY)
+ {
+ bVOver = pRowInfo[nArrY].cellInfo(rOverX).bVOverlapped;
+ }
+ else
+ {
+ ScMF nOverlap = mpDoc->GetAttr( rOverX, rOverY, nTab, ATTR_MERGE_FLAG )->GetValue();
+ bVOver = bool(nOverlap & ScMF::Ver);
+ }
+ }
+
+ return true;
+}
+
+static bool StringDiffer( const ScPatternAttr*& rpOldPattern, const ScPatternAttr* pNewPattern )
+{
+ OSL_ENSURE( pNewPattern, "pNewPattern" );
+
+ if ( pNewPattern == rpOldPattern )
+ return false;
+ else if ( !rpOldPattern )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT ) != &rpOldPattern->GetItem( ATTR_FONT ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_CJK_FONT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_CTL_FONT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_UNDERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_OVERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_WORDLINE ) != &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ) != &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_CONTOUR ) != &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_SHADOWED ) != &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_COLOR ) != &rpOldPattern->GetItem( ATTR_FONT_COLOR ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_HOR_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_VER_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_STACKED ) != &rpOldPattern->GetItem( ATTR_STACKED ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_LINEBREAK ) != &rpOldPattern->GetItem( ATTR_LINEBREAK ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_MARGIN ) != &rpOldPattern->GetItem( ATTR_MARGIN ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_ROTATE_VALUE ) != &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FORBIDDEN_RULES ) != &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ) != &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_FONT_RELIEF ) != &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) )
+ return true;
+ else if ( &pNewPattern->GetItem( ATTR_BACKGROUND ) != &rpOldPattern->GetItem( ATTR_BACKGROUND ) )
+ return true; // needed with automatic text color
+ else
+ {
+ rpOldPattern = pNewPattern;
+ return false;
+ }
+}
+
+static void lcl_CreateInterpretProgress( bool& bProgress, ScDocument* pDoc,
+ const ScFormulaCell* pFCell )
+{
+ if ( !bProgress && pFCell->GetDirty() )
+ {
+ ScProgress::CreateInterpretProgress( pDoc );
+ bProgress = true;
+ }
+}
+
+static bool IsAmbiguousScript( SvtScriptType nScript )
+{
+ return ( nScript != SvtScriptType::LATIN &&
+ nScript != SvtScriptType::ASIAN &&
+ nScript != SvtScriptType::COMPLEX );
+}
+
+bool ScOutputData::IsEmptyCellText( const RowInfo* pThisRowInfo, SCCOL nX, SCROW nY )
+{
+ // pThisRowInfo may be NULL
+
+ bool bEmpty;
+ if ( pThisRowInfo && nX <= nX2 )
+ bEmpty = pThisRowInfo->basicCellInfo(nX).bEmptyCellText;
+ else
+ {
+ ScRefCellValue aCell(*mpDoc, ScAddress(nX, nY, nTab));
+ bEmpty = aCell.isEmpty();
+ }
+
+ if ( !bEmpty && ( nX < nX1 || nX > nX2 || !pThisRowInfo ) )
+ {
+ // for the range nX1..nX2 in RowInfo, cell protection attribute is already evaluated
+ // into bEmptyCellText in ScDocument::FillInfo / lcl_HidePrint (printfun)
+
+ bool bIsPrint = ( eType == OUTTYPE_PRINTER );
+
+ if ( bIsPrint || bTabProtected )
+ {
+ const ScProtectionAttr* pAttr =
+ mpDoc->GetEffItem( nX, nY, nTab, ATTR_PROTECTION );
+ if ( bIsPrint && pAttr->GetHidePrint() )
+ bEmpty = true;
+ else if ( bTabProtected )
+ {
+ if ( pAttr->GetHideCell() )
+ bEmpty = true;
+ else if ( mbShowFormulas && pAttr->GetHideFormula() )
+ {
+ if (mpDoc->GetCellType(ScAddress(nX, nY, nTab)) == CELLTYPE_FORMULA)
+ bEmpty = true;
+ }
+ }
+ }
+ }
+ return bEmpty;
+}
+
+void ScOutputData::GetVisibleCell( SCCOL nCol, SCROW nRow, SCTAB nTabP, ScRefCellValue& rCell )
+{
+ rCell.assign(*mpDoc, ScAddress(nCol, nRow, nTabP));
+ if (!rCell.isEmpty() && IsEmptyCellText(nullptr, nCol, nRow))
+ rCell.clear();
+}
+
+bool ScOutputData::IsAvailable( SCCOL nX, SCROW nY )
+{
+ // apply the same logic here as in DrawStrings/DrawEdit:
+ // Stop at non-empty or merged or overlapped cell,
+ // where a note is empty as well as a cell that's hidden by protection settings
+
+ ScRefCellValue aCell(*mpDoc, ScAddress(nX, nY, nTab));
+ if (!aCell.isEmpty() && !IsEmptyCellText(nullptr, nX, nY))
+ return false;
+
+ const ScPatternAttr* pPattern = mpDoc->GetPattern( nX, nY, nTab );
+ return !(pPattern->GetItem(ATTR_MERGE).IsMerged() ||
+ pPattern->GetItem(ATTR_MERGE_FLAG).IsOverlapped());
+}
+
+// nX, nArrY: loop variables from DrawStrings / DrawEdit
+// nPosX, nPosY: corresponding positions for nX, nArrY
+// nCellX, nCellY: position of the cell that contains the text
+// nNeeded: Text width, including margin
+// rPattern: cell format at nCellX, nCellY
+// nHorJustify: horizontal alignment (visual) to determine which cells to use for long strings
+// bCellIsValue: if set, don't extend into empty cells
+// bBreak: if set, don't extend, and don't set clip marks (but rLeftClip/rRightClip is set)
+// bOverwrite: if set, also extend into non-empty cells (for rotated text)
+// rParam output: various area parameters.
+
+void ScOutputData::GetOutputArea( SCCOL nX, SCSIZE nArrY, tools::Long nPosX, tools::Long nPosY,
+ SCCOL nCellX, SCROW nCellY, tools::Long nNeeded,
+ const ScPatternAttr& rPattern,
+ sal_uInt16 nHorJustify, bool bCellIsValue,
+ bool bBreak, bool bOverwrite,
+ OutputAreaParam& rParam )
+{
+ // rThisRowInfo may be for a different row than nCellY, is still used for clip marks
+ RowInfo& rThisRowInfo = pRowInfo[nArrY];
+
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ tools::Long nCellPosX = nPosX; // find nCellX position, starting at nX/nPosX
+ SCCOL nCompCol = nX;
+ while ( nCellX > nCompCol )
+ {
+ //! extra member function for width?
+ tools::Long nColWidth = ( nCompCol <= nX2 ) ?
+ pRowInfo[0].basicCellInfo(nCompCol).nWidth :
+ static_cast<tools::Long>( mpDoc->GetColWidth( nCompCol, nTab ) * mnPPTX );
+ nCellPosX += nColWidth * nLayoutSign;
+ ++nCompCol;
+ }
+ while ( nCellX < nCompCol )
+ {
+ --nCompCol;
+ tools::Long nColWidth = ( nCompCol <= nX2 ) ?
+ pRowInfo[0].basicCellInfo(nCompCol).nWidth :
+ static_cast<tools::Long>( mpDoc->GetColWidth( nCompCol, nTab ) * mnPPTX );
+ nCellPosX -= nColWidth * nLayoutSign;
+ }
+
+ tools::Long nCellPosY = nPosY; // find nCellY position, starting at nArrY/nPosY
+ SCSIZE nCompArr = nArrY;
+ SCROW nCompRow = pRowInfo[nCompArr].nRowNo;
+ while ( nCellY > nCompRow )
+ {
+ if ( nCompArr + 1 < nArrCount )
+ {
+ nCellPosY += pRowInfo[nCompArr].nHeight;
+ ++nCompArr;
+ nCompRow = pRowInfo[nCompArr].nRowNo;
+ }
+ else
+ {
+ sal_uInt16 nDocHeight = mpDoc->GetRowHeight( nCompRow, nTab );
+ if ( nDocHeight )
+ nCellPosY += static_cast<tools::Long>( nDocHeight * mnPPTY );
+ ++nCompRow;
+ }
+ }
+ nCellPosY -= mpDoc->GetScaledRowHeight( nCellY, nCompRow-1, nTab, mnPPTY );
+
+ const ScMergeAttr* pMerge = &rPattern.GetItem( ATTR_MERGE );
+ bool bMerged = pMerge->IsMerged();
+ tools::Long nMergeCols = pMerge->GetColMerge();
+ if ( nMergeCols == 0 )
+ nMergeCols = 1;
+ tools::Long nMergeRows = pMerge->GetRowMerge();
+ if ( nMergeRows == 0 )
+ nMergeRows = 1;
+
+ tools::Long nMergeSizeX = 0;
+ for ( tools::Long i=0; i<nMergeCols; i++ )
+ {
+ tools::Long nColWidth = ( nCellX+i <= nX2 ) ?
+ pRowInfo[0].basicCellInfo(nCellX+i).nWidth :
+ static_cast<tools::Long>( mpDoc->GetColWidth( sal::static_int_cast<SCCOL>(nCellX+i), nTab ) * mnPPTX );
+ nMergeSizeX += nColWidth;
+ }
+ tools::Long nMergeSizeY = 0;
+ short nDirect = 0;
+ if ( rThisRowInfo.nRowNo == nCellY )
+ {
+ // take first row's height from row info
+ nMergeSizeY += rThisRowInfo.nHeight;
+ nDirect = 1; // skip in loop
+ }
+ // following rows always from document
+ nMergeSizeY += mpDoc->GetScaledRowHeight( nCellY+nDirect, nCellY+nMergeRows-1, nTab, mnPPTY);
+
+ --nMergeSizeX; // leave out the grid horizontally, also for alignment (align between grid lines)
+
+ rParam.mnColWidth = nMergeSizeX; // store the actual column width.
+ rParam.mnLeftClipLength = rParam.mnRightClipLength = 0;
+
+ // construct the rectangles using logical left/right values (justify is called at the end)
+
+ // rAlignRect is the single cell or merged area, used for alignment.
+
+ rParam.maAlignRect.SetLeft( nCellPosX );
+ rParam.maAlignRect.SetRight( nCellPosX + ( nMergeSizeX - 1 ) * nLayoutSign );
+ rParam.maAlignRect.SetTop( nCellPosY );
+ rParam.maAlignRect.SetBottom( nCellPosY + nMergeSizeY - 1 );
+
+ // rClipRect is all cells that are used for output.
+ // For merged cells this is the same as rAlignRect, otherwise neighboring cells can also be used.
+
+ rParam.maClipRect = rParam.maAlignRect;
+ if ( nNeeded > nMergeSizeX )
+ {
+ SvxCellHorJustify eHorJust = static_cast<SvxCellHorJustify>(nHorJustify);
+
+ tools::Long nMissing = nNeeded - nMergeSizeX;
+ tools::Long nLeftMissing = 0;
+ tools::Long nRightMissing = 0;
+ switch ( eHorJust )
+ {
+ case SvxCellHorJustify::Left:
+ nRightMissing = nMissing;
+ break;
+ case SvxCellHorJustify::Right:
+ nLeftMissing = nMissing;
+ break;
+ case SvxCellHorJustify::Center:
+ nLeftMissing = nMissing / 2;
+ nRightMissing = nMissing - nLeftMissing;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ // nLeftMissing, nRightMissing are logical, eHorJust values are visual
+ if ( bLayoutRTL )
+ ::std::swap( nLeftMissing, nRightMissing );
+
+ SCCOL nRightX = nCellX;
+ SCCOL nLeftX = nCellX;
+ if ( !bMerged && !bCellIsValue && !bBreak )
+ {
+ // look for empty cells into which the text can be extended
+
+ while ( nRightMissing > 0 && nRightX < mpDoc->MaxCol() && ( bOverwrite || IsAvailable( nRightX+1, nCellY ) ) )
+ {
+ ++nRightX;
+ tools::Long nAdd = static_cast<tools::Long>( mpDoc->GetColWidth( nRightX, nTab ) * mnPPTX );
+ nRightMissing -= nAdd;
+ rParam.maClipRect.AdjustRight(nAdd * nLayoutSign );
+
+ if ( rThisRowInfo.nRowNo == nCellY && nRightX >= nX1 && nRightX <= nX2 )
+ rThisRowInfo.cellInfo(nRightX-1).bHideGrid = true;
+ }
+
+ while ( nLeftMissing > 0 && nLeftX > 0 && ( bOverwrite || IsAvailable( nLeftX-1, nCellY ) ) )
+ {
+ if ( rThisRowInfo.nRowNo == nCellY && nLeftX >= nX1 && nLeftX <= nX2 )
+ rThisRowInfo.cellInfo(nLeftX-1).bHideGrid = true;
+
+ --nLeftX;
+ tools::Long nAdd = static_cast<tools::Long>( mpDoc->GetColWidth( nLeftX, nTab ) * mnPPTX );
+ nLeftMissing -= nAdd;
+ rParam.maClipRect.AdjustLeft( -(nAdd * nLayoutSign) );
+ }
+ }
+
+ // Set flag and reserve space for clipping mark triangle,
+ // even if rThisRowInfo isn't for nCellY (merged cells).
+ if ( nRightMissing > 0 && bMarkClipped && nRightX >= nX1 && nRightX <= nX2 && !bBreak && !bCellIsValue )
+ {
+ rThisRowInfo.cellInfo(nRightX).nClipMark |= ScClipMark::Right;
+ bAnyClipped = true;
+ tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
+ rParam.maClipRect.AdjustRight( -(nMarkPixel * nLayoutSign) );
+ }
+ if ( nLeftMissing > 0 && bMarkClipped && nLeftX >= nX1 && nLeftX <= nX2 && !bBreak && !bCellIsValue )
+ {
+ rThisRowInfo.cellInfo(nLeftX).nClipMark |= ScClipMark::Left;
+ bAnyClipped = true;
+ tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
+ rParam.maClipRect.AdjustLeft(nMarkPixel * nLayoutSign );
+ }
+
+ rParam.mbLeftClip = ( nLeftMissing > 0 );
+ rParam.mbRightClip = ( nRightMissing > 0 );
+ rParam.mnLeftClipLength = nLeftMissing;
+ rParam.mnRightClipLength = nRightMissing;
+ }
+ else
+ {
+ rParam.mbLeftClip = rParam.mbRightClip = false;
+
+ // leave space for AutoFilter on screen
+ // (for automatic line break: only if not formatting for printer, as in ScColumn::GetNeededSize)
+
+ if ( eType==OUTTYPE_WINDOW &&
+ ( rPattern.GetItem(ATTR_MERGE_FLAG).GetValue() & (ScMF::Auto|ScMF::Button|ScMF::ButtonPopup) ) &&
+ ( !bBreak || mpRefDevice == pFmtDevice ) )
+ {
+ // filter drop-down width depends on row height
+ double fZoom = mpRefDevice ? static_cast<double>(mpRefDevice->GetMapMode().GetScaleY()) : 1.0;
+ fZoom = fZoom > 1.0 ? fZoom : 1.0;
+ const tools::Long nFilter = fZoom * DROPDOWN_BITMAP_SIZE;
+ bool bFit = ( nNeeded + nFilter <= nMergeSizeX );
+ if ( bFit )
+ {
+ // content fits even in the remaining area without the filter button
+ // -> align within that remaining area
+
+ rParam.maAlignRect.AdjustRight( -(nFilter * nLayoutSign) );
+ rParam.maClipRect.AdjustRight( -(nFilter * nLayoutSign) );
+ }
+ }
+ }
+
+ // justify both rectangles for alignment calculation, use with DrawText etc.
+
+ rParam.maAlignRect.Justify();
+ rParam.maClipRect.Justify();
+}
+
+namespace {
+
+bool beginsWithRTLCharacter(const OUString& rStr)
+{
+ if (rStr.isEmpty())
+ return false;
+
+ switch (ScGlobal::getCharClass().getCharacterDirection(rStr, 0))
+ {
+ case i18n::DirectionProperty_RIGHT_TO_LEFT:
+ case i18n::DirectionProperty_RIGHT_TO_LEFT_ARABIC:
+ case i18n::DirectionProperty_RIGHT_TO_LEFT_EMBEDDING:
+ case i18n::DirectionProperty_RIGHT_TO_LEFT_OVERRIDE:
+ return true;
+ default:
+ ;
+ }
+
+ return false;
+}
+
+}
+
+/** Get left, right or centered alignment from RTL context.
+
+ Does not return standard, block or repeat, for these the contextual left or
+ right alignment is returned.
+ */
+static SvxCellHorJustify getAlignmentFromContext( SvxCellHorJustify eInHorJust,
+ bool bCellIsValue, const OUString& rText,
+ const ScPatternAttr& rPattern, const SfxItemSet* pCondSet,
+ const ScDocument* pDoc, SCTAB nTab, const bool bNumberFormatIsText )
+{
+ SvxCellHorJustify eHorJustContext = eInHorJust;
+ bool bUseWritingDirection = false;
+ if (eInHorJust == SvxCellHorJustify::Standard)
+ {
+ // fdo#32530: Default alignment depends on value vs
+ // string, and the direction of the 1st letter.
+ if (beginsWithRTLCharacter( rText)) //If language is RTL
+ {
+ if (bCellIsValue)
+ eHorJustContext = bNumberFormatIsText ? SvxCellHorJustify::Right : SvxCellHorJustify::Left;
+ else
+ eHorJustContext = SvxCellHorJustify::Right;
+ }
+ else if (bCellIsValue) //If language is not RTL
+ eHorJustContext = bNumberFormatIsText ? SvxCellHorJustify::Left : SvxCellHorJustify::Right;
+ else
+ bUseWritingDirection = true;
+ }
+
+ if (bUseWritingDirection ||
+ eInHorJust == SvxCellHorJustify::Block || eInHorJust == SvxCellHorJustify::Repeat)
+ {
+ SvxFrameDirection nDirection = lcl_GetValue<SvxFrameDirectionItem, SvxFrameDirection>(rPattern, ATTR_WRITINGDIR, pCondSet);
+ if (nDirection == SvxFrameDirection::Horizontal_LR_TB || nDirection == SvxFrameDirection::Vertical_LR_TB)
+ eHorJustContext = SvxCellHorJustify::Left;
+ else if (nDirection == SvxFrameDirection::Environment)
+ {
+ SAL_WARN_IF( !pDoc, "sc.ui", "getAlignmentFromContext - pDoc==NULL");
+ // fdo#73588: The content of the cell must also
+ // begin with a RTL character to be right
+ // aligned; otherwise, it should be left aligned.
+ eHorJustContext = (pDoc && pDoc->IsLayoutRTL(nTab) && (beginsWithRTLCharacter( rText))) ? SvxCellHorJustify::Right : SvxCellHorJustify::Left;
+ }
+ else
+ eHorJustContext = SvxCellHorJustify::Right;
+ }
+ return eHorJustContext;
+}
+
+void ScOutputData::DrawStrings( bool bPixelToLogic )
+{
+ LayoutStrings(bPixelToLogic);
+}
+
+tools::Rectangle ScOutputData::LayoutStrings(bool bPixelToLogic, bool bPaint, const ScAddress &rAddress)
+{
+ bool bOrigIsInLayoutStrings = mpDoc->IsInLayoutStrings();
+ mpDoc->SetLayoutStrings(true);
+ comphelper::ScopeGuard g([this, bOrigIsInLayoutStrings] {
+ mpDoc->SetLayoutStrings(bOrigIsInLayoutStrings);
+ });
+
+ OSL_ENSURE( mpDev == mpRefDevice ||
+ mpDev->GetMapMode().GetMapUnit() == mpRefDevice->GetMapMode().GetMapUnit(),
+ "LayoutStrings: different MapUnits ?!?!" );
+
+ vcl::PDFExtOutDevData* pPDFData = dynamic_cast< vcl::PDFExtOutDevData* >(mpDev->GetExtOutDevData() );
+
+ sc::IdleSwitch aIdleSwitch(*mpDoc, false);
+ ScDrawStringsVars aVars( this, bPixelToLogic );
+
+ bool bProgress = false;
+
+ tools::Long nInitPosX = nScrX;
+ if ( bLayoutRTL )
+ nInitPosX += nMirrorW - 1; // pixels
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ SCCOL nLastContentCol = mpDoc->MaxCol();
+ if ( nX2 < mpDoc->MaxCol() )
+ nLastContentCol = sal::static_int_cast<SCCOL>(
+ nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, mpDoc->MaxCol(), nY2, nTab, DIR_RIGHT ) );
+ SCCOL nLoopStartX = nX1;
+ if ( nX1 > 0 )
+ --nLoopStartX; // start before nX1 for rest of long text to the left
+
+ // variables for GetOutputArea
+ OutputAreaParam aAreaParam;
+ bool bCellIsValue = false;
+ tools::Long nNeededWidth = 0;
+ const ScPatternAttr* pPattern = nullptr;
+ const SfxItemSet* pCondSet = nullptr;
+ const ScPatternAttr* pOldPattern = nullptr;
+ const SfxItemSet* pOldCondSet = nullptr;
+ SvtScriptType nOldScript = SvtScriptType::NONE;
+
+ // Try to limit interpreting to only visible cells. Calling e.g. IsValue()
+ // on a formula cell that needs interpreting would call Interpret()
+ // for the entire formula group, which could be large.
+ mpDoc->InterpretCellsIfNeeded( ScRange( nX1, nY1, nTab, nX2, nY2, nTab ));
+
+ // alternative pattern instances in case we need to modify the pattern
+ // before processing the cell value.
+ std::vector<std::unique_ptr<ScPatternAttr> > aAltPatterns;
+
+ std::vector<sal_Int32> aDX;
+ tools::Long nPosY = nScrY;
+ for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ SCROW nY = pThisRowInfo->nRowNo;
+ if ((bPaint && pThisRowInfo->bChanged) || (!bPaint && rAddress.Row() == nY))
+ {
+ tools::Long nPosX = nInitPosX;
+ if ( nLoopStartX < nX1 )
+ nPosX -= pRowInfo[0].basicCellInfo(nLoopStartX).nWidth * nLayoutSign;
+ for (SCCOL nX=nLoopStartX; nX<=nX2; nX++)
+ {
+ bool bMergeEmpty = false;
+ const ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
+ bool bEmpty = nX < nX1 || pThisRowInfo->basicCellInfo(nX).bEmptyCellText;
+
+ SCCOL nCellX = nX; // position where the cell really starts
+ SCROW nCellY = nY;
+ bool bDoCell = false;
+ bool bUseEditEngine = false;
+
+ // Part of a merged cell?
+
+ bool bOverlapped = (pInfo->bHOverlapped || pInfo->bVOverlapped);
+ if ( bOverlapped )
+ {
+ bEmpty = true;
+
+ SCCOL nOverX; // start of the merged cells
+ SCROW nOverY;
+ bool bVisChanged = !pRowInfo[nArrY-1].bChanged;
+ if (GetMergeOrigin( nX,nY, nArrY, nOverX,nOverY, bVisChanged ))
+ {
+ nCellX = nOverX;
+ nCellY = nOverY;
+ bDoCell = true;
+ }
+ else
+ bMergeEmpty = true;
+ }
+
+ // Rest of a long text further to the left?
+
+ if ( bEmpty && !bMergeEmpty && nX < nX1 && !bOverlapped )
+ {
+ SCCOL nTempX=nX1;
+ while (nTempX > 0 && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
+ --nTempX;
+
+ if ( nTempX < nX1 &&
+ !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
+ !mpDoc->HasAttrib( nTempX,nY,nTab, nX1,nY,nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
+ {
+ nCellX = nTempX;
+ bDoCell = true;
+ }
+ }
+
+ // Rest of a long text further to the right?
+
+ if ( bEmpty && !bMergeEmpty && nX == nX2 && !bOverlapped )
+ {
+ // don't have to look further than nLastContentCol
+
+ SCCOL nTempX=nX;
+ while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
+ ++nTempX;
+
+ if ( nTempX > nX &&
+ !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
+ !mpDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
+ {
+ nCellX = nTempX;
+ bDoCell = true;
+ }
+ }
+
+ // normal visible cell
+
+ if (!bEmpty)
+ bDoCell = true;
+
+ // don't output the cell that's being edited
+
+ if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
+ bDoCell = false;
+
+ // skip text in cell if data bar/icon set is set and only value selected
+ if ( bDoCell )
+ {
+ if(pInfo->pDataBar && !pInfo->pDataBar->mbShowValue)
+ bDoCell = false;
+ if(pInfo->pIconSet && !pInfo->pIconSet->mbShowValue)
+ bDoCell = false;
+ }
+
+ // output the cell text
+
+ ScRefCellValue aCell;
+ if (bDoCell)
+ {
+ if ( nCellY == nY && nCellX == nX && nCellX >= nX1 && nCellX <= nX2 )
+ aCell = pThisRowInfo->cellInfo(nCellX).maCell;
+ else
+ GetVisibleCell( nCellX, nCellY, nTab, aCell ); // get from document
+ if (aCell.isEmpty())
+ bDoCell = false;
+ else if (aCell.meType == CELLTYPE_EDIT)
+ bUseEditEngine = true;
+ }
+
+ // Check if this cell is mis-spelled.
+ if (bDoCell && !bUseEditEngine && aCell.meType == CELLTYPE_STRING)
+ {
+ if (mpSpellCheckCxt && mpSpellCheckCxt->isMisspelled(nCellX, nCellY))
+ bUseEditEngine = true;
+ }
+
+ if (bDoCell && !bUseEditEngine)
+ {
+ if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 )
+ {
+ ScCellInfo& rCellInfo = pThisRowInfo->cellInfo(nCellX);
+ pPattern = rCellInfo.pPatternAttr;
+ pCondSet = rCellInfo.pConditionSet;
+
+ if ( !pPattern )
+ {
+ // #i68085# pattern from cell info for hidden columns is null,
+ // test for null is quicker than using column flags
+ pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
+ pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
+ }
+ }
+ else // get from document
+ {
+ pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
+ pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
+ }
+ if ( mpDoc->GetPreviewFont() || mpDoc->GetPreviewCellStyle() )
+ {
+ aAltPatterns.push_back(std::make_unique<ScPatternAttr>(*pPattern));
+ ScPatternAttr* pAltPattern = aAltPatterns.back().get();
+ if ( ScStyleSheet* pPreviewStyle = mpDoc->GetPreviewCellStyle( nCellX, nCellY, nTab ) )
+ {
+ pAltPattern->SetStyleSheet(pPreviewStyle);
+ }
+ else if ( SfxItemSet* pFontSet = mpDoc->GetPreviewFont( nCellX, nCellY, nTab ) )
+ {
+ if ( const SvxFontItem* pItem = pFontSet->GetItemIfSet( ATTR_FONT ) )
+ pAltPattern->GetItemSet().Put( *pItem );
+ if ( const SvxFontItem* pItem = pFontSet->GetItemIfSet( ATTR_CJK_FONT ) )
+ pAltPattern->GetItemSet().Put( *pItem );
+ if ( const SvxFontItem* pItem = pFontSet->GetItemIfSet( ATTR_CTL_FONT ) )
+ pAltPattern->GetItemSet().Put( *pItem );
+ }
+ pPattern = pAltPattern;
+ }
+
+ if (aCell.hasNumeric() &&
+ pPattern->GetItem(ATTR_LINEBREAK, pCondSet).GetValue())
+ {
+ // Disable line break when the cell content is numeric.
+ aAltPatterns.push_back(std::make_unique<ScPatternAttr>(*pPattern));
+ ScPatternAttr* pAltPattern = aAltPatterns.back().get();
+ ScLineBreakCell aLineBreak(false);
+ pAltPattern->GetItemSet().Put(aLineBreak);
+ pPattern = pAltPattern;
+ }
+
+ SvtScriptType nScript = mpDoc->GetCellScriptType(
+ ScAddress(nCellX, nCellY, nTab),
+ pPattern->GetNumberFormat(mpDoc->GetFormatTable(), pCondSet));
+
+ if (nScript == SvtScriptType::NONE)
+ nScript = ScGlobal::GetDefaultScriptType();
+
+ if ( pPattern != pOldPattern || pCondSet != pOldCondSet ||
+ nScript != nOldScript || mbSyntaxMode )
+ {
+ if ( StringDiffer(pOldPattern,pPattern) ||
+ pCondSet != pOldCondSet || nScript != nOldScript || mbSyntaxMode )
+ {
+ aVars.SetPattern(pPattern, pCondSet, aCell, nScript);
+ }
+ else
+ aVars.SetPatternSimple( pPattern, pCondSet );
+ pOldPattern = pPattern;
+ pOldCondSet = pCondSet;
+ nOldScript = nScript;
+ }
+
+ // use edit engine for rotated, stacked or mixed-script text
+ if ( aVars.GetOrient() == SvxCellOrientation::Stacked ||
+ aVars.IsRotated() || IsAmbiguousScript(nScript) )
+ bUseEditEngine = true;
+ }
+ if (bDoCell && !bUseEditEngine)
+ {
+ bool bFormulaCell = (aCell.meType == CELLTYPE_FORMULA);
+ if ( bFormulaCell )
+ lcl_CreateInterpretProgress(bProgress, mpDoc, aCell.mpFormula);
+ if ( aVars.SetText(aCell) )
+ pOldPattern = nullptr;
+ bUseEditEngine = aVars.HasEditCharacters() || (bFormulaCell && aCell.mpFormula->IsMultilineResult());
+ }
+ tools::Long nTotalMargin = 0;
+ SvxCellHorJustify eOutHorJust = SvxCellHorJustify::Standard;
+ if (bDoCell && !bUseEditEngine)
+ {
+ CellType eCellType = aCell.meType;
+ bCellIsValue = ( eCellType == CELLTYPE_VALUE );
+ if ( eCellType == CELLTYPE_FORMULA )
+ {
+ ScFormulaCell* pFCell = aCell.mpFormula;
+ bCellIsValue = pFCell->IsRunning() || pFCell->IsValue();
+ }
+
+ const bool bNumberFormatIsText = lcl_isNumberFormatText( mpDoc, nCellX, nCellY, nTab );
+ eOutHorJust = getAlignmentFromContext( aVars.GetHorJust(), bCellIsValue, aVars.GetString(),
+ *pPattern, pCondSet, mpDoc, nTab, bNumberFormatIsText );
+
+ bool bBreak = ( aVars.GetLineBreak() || aVars.GetHorJust() == SvxCellHorJustify::Block );
+ // #i111387# #o11817313# tdf#121040 disable automatic line breaks for all number formats
+ // Must be synchronized with ScColumn::GetNeededSize()
+ SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
+ if (bBreak && bCellIsValue && (pFormatter->GetType(aVars.GetResultValueFormat()) == SvNumFormatType::NUMBER))
+ bBreak = false;
+
+ bool bRepeat = aVars.IsRepeat() && !bBreak;
+ bool bShrink = aVars.IsShrink() && !bBreak && !bRepeat;
+
+ nTotalMargin =
+ static_cast<tools::Long>(aVars.GetLeftTotal() * mnPPTX) +
+ static_cast<tools::Long>(aVars.GetMargin()->GetRightMargin() * mnPPTX);
+
+ nNeededWidth = aVars.GetTextSize().Width() + nTotalMargin;
+
+ // GetOutputArea gives justified rectangles
+ GetOutputArea( nX, nArrY, nPosX, nPosY, nCellX, nCellY, nNeededWidth,
+ *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ bCellIsValue || bRepeat || bShrink, bBreak, false,
+ aAreaParam );
+
+ aVars.RepeatToFill( aAreaParam.mnColWidth - nTotalMargin );
+ if ( bShrink )
+ {
+ if ( aVars.GetOrient() != SvxCellOrientation::Standard )
+ {
+ // Only horizontal scaling is handled here.
+ // DrawEdit is used to vertically scale 90 deg rotated text.
+ bUseEditEngine = true;
+ }
+ else if ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) // horizontal
+ {
+ tools::Long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
+ tools::Long nScaleSize = aVars.GetTextSize().Width(); // without margin
+
+ if ( nAvailable > 0 && nScaleSize > 0 ) // 0 if the text is empty (formulas, number formats)
+ {
+ tools::Long nScale = ( nAvailable * 100 ) / nScaleSize;
+
+ aVars.SetShrinkScale( nScale, nOldScript );
+ tools::Long nNewSize = aVars.GetTextSize().Width();
+
+ sal_uInt16 nShrinkAgain = 0;
+ while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
+ {
+ // If the text is still too large, reduce the scale again by 10%, until it fits,
+ // at most 7 times (it's less than 50% of the calculated scale then).
+
+ nScale = ( nScale * 9 ) / 10;
+ aVars.SetShrinkScale( nScale, nOldScript );
+ nNewSize = aVars.GetTextSize().Width();
+ ++nShrinkAgain;
+ }
+ // If even at half the size the font still isn't rendered smaller,
+ // fall back to normal clipping (showing ### for numbers).
+ if ( nNewSize <= nAvailable )
+ {
+ // Reset relevant parameters.
+ aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
+ aAreaParam.mnLeftClipLength = aAreaParam.mnRightClipLength = 0;
+ }
+
+ pOldPattern = nullptr;
+ }
+ }
+ }
+
+ if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip )
+ {
+ tools::Long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
+ tools::Long nRepeatSize = aVars.GetTextSize().Width(); // without margin
+ // When formatting for the printer, the text sizes don't always add up.
+ // Round down (too few repetitions) rather than exceeding the cell size then:
+ if ( pFmtDevice != mpRefDevice )
+ ++nRepeatSize;
+ if ( nRepeatSize > 0 )
+ {
+ tools::Long nRepeatCount = nAvailable / nRepeatSize;
+ if ( nRepeatCount > 1 )
+ {
+ OUString aCellStr = aVars.GetString();
+ OUStringBuffer aRepeated(aCellStr);
+ for ( tools::Long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
+ aRepeated.append(aCellStr);
+ aVars.SetAutoText( aRepeated.makeStringAndClear() );
+ }
+ }
+ }
+
+ // use edit engine if automatic line breaks are needed
+ if ( bBreak )
+ {
+ if ( aVars.GetOrient() == SvxCellOrientation::Standard )
+ bUseEditEngine = ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip );
+ else
+ {
+ tools::Long nHeight = aVars.GetTextSize().Height() +
+ static_cast<tools::Long>(aVars.GetMargin()->GetTopMargin()*mnPPTY) +
+ static_cast<tools::Long>(aVars.GetMargin()->GetBottomMargin()*mnPPTY);
+ bUseEditEngine = ( nHeight > aAreaParam.maClipRect.GetHeight() );
+ }
+ }
+ if (!bUseEditEngine)
+ {
+ bUseEditEngine =
+ aVars.GetHorJust() == SvxCellHorJustify::Block &&
+ aVars.GetHorJustMethod() == SvxCellJustifyMethod::Distribute;
+ }
+ }
+ if (bUseEditEngine)
+ {
+ // mark the cell in ScCellInfo to be drawn in DrawEdit:
+ // Cells to the left are marked directly, cells to the
+ // right are handled by the flag for nX2
+ SCCOL nMarkX = ( nCellX <= nX2 ) ? nCellX : nX2;
+ RowInfo* pMarkRowInfo = ( nCellY == nY ) ? pThisRowInfo : &pRowInfo[0];
+ pMarkRowInfo->basicCellInfo(nMarkX).bEditEngine = true;
+ bDoCell = false; // don't draw here
+ }
+ if ( bDoCell )
+ {
+ if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
+ {
+ if (mbShowFormulas)
+ aVars.SetHashText();
+ else
+ // Adjust the decimals to fit the available column width.
+ aVars.SetTextToWidthOrHash(aCell, aAreaParam.mnColWidth - nTotalMargin);
+
+ nNeededWidth = aVars.GetTextSize().Width() +
+ static_cast<tools::Long>( aVars.GetLeftTotal() * mnPPTX ) +
+ static_cast<tools::Long>( aVars.GetMargin()->GetRightMargin() * mnPPTX );
+ if ( nNeededWidth <= aAreaParam.maClipRect.GetWidth() )
+ {
+ // Cell value is no longer clipped. Reset relevant parameters.
+ aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
+ aAreaParam.mnLeftClipLength = aAreaParam.mnRightClipLength = 0;
+ }
+
+ // If the "###" replacement doesn't fit into the cells, no clip marks
+ // are shown, as the "###" already denotes too little space.
+ // The rectangles from the first GetOutputArea call remain valid.
+ }
+
+ tools::Long nJustPosX = aAreaParam.maAlignRect.Left(); // "justified" - effect of alignment will be added
+ tools::Long nJustPosY = aAreaParam.maAlignRect.Top();
+ tools::Long nAvailWidth = aAreaParam.maAlignRect.GetWidth();
+ tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight();
+
+ bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW );
+ // Take adjusted values of aAreaParam.mbLeftClip and aAreaParam.mbRightClip
+ bool bVClip = AdjustAreaParamClipRect(aAreaParam);
+ bool bHClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
+
+ // check horizontal space
+
+ if ( !bOutside )
+ {
+ bool bRightAdjusted = false; // to correct text width calculation later
+ switch (eOutHorJust)
+ {
+ case SvxCellHorJustify::Left:
+ nJustPosX += static_cast<tools::Long>( aVars.GetLeftTotal() * mnPPTX );
+ break;
+ case SvxCellHorJustify::Right:
+ nJustPosX += nAvailWidth - aVars.GetTextSize().Width() -
+ static_cast<tools::Long>( aVars.GetRightTotal() * mnPPTX );
+ bRightAdjusted = true;
+ break;
+ case SvxCellHorJustify::Center:
+ nJustPosX += ( nAvailWidth - aVars.GetTextSize().Width() +
+ static_cast<tools::Long>( aVars.GetLeftTotal() * mnPPTX ) -
+ static_cast<tools::Long>( aVars.GetMargin()->GetRightMargin() * mnPPTX ) ) / 2;
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ tools::Long nTestClipHeight = aVars.GetTextSize().Height();
+ switch (aVars.GetVerJust())
+ {
+ case SvxCellVerJustify::Top:
+ case SvxCellVerJustify::Block:
+ {
+ tools::Long nTop = static_cast<tools::Long>( aVars.GetMargin()->GetTopMargin() * mnPPTY );
+ nJustPosY += nTop;
+ nTestClipHeight += nTop;
+ }
+ break;
+ case SvxCellVerJustify::Bottom:
+ {
+ tools::Long nBot = static_cast<tools::Long>( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
+ nJustPosY += nOutHeight - aVars.GetTextSize().Height() - nBot;
+ nTestClipHeight += nBot;
+ }
+ break;
+ case SvxCellVerJustify::Center:
+ {
+ tools::Long nTop = static_cast<tools::Long>( aVars.GetMargin()->GetTopMargin() * mnPPTY );
+ tools::Long nBot = static_cast<tools::Long>( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
+ nJustPosY += ( nOutHeight + nTop -
+ aVars.GetTextSize().Height() - nBot ) / 2;
+ nTestClipHeight += std::abs( nTop - nBot );
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if ( nTestClipHeight > nOutHeight )
+ {
+ // no vertical clipping when printing cells with optimal height,
+ // except when font size is from conditional formatting.
+ if ( eType != OUTTYPE_PRINTER ||
+ ( mpDoc->GetRowFlags( nCellY, nTab ) & CRFlags::ManualSize ) ||
+ ( aVars.HasCondHeight() ) )
+ bVClip = true;
+ }
+
+ if ( bHClip || bVClip )
+ {
+ // only clip the affected dimension so that not all right-aligned
+ // columns are cut off when performing a non-proportional resize
+ if (!bHClip)
+ {
+ aAreaParam.maClipRect.SetLeft( nScrX );
+ aAreaParam.maClipRect.SetRight( nScrX+nScrW );
+ }
+ if (!bVClip)
+ {
+ aAreaParam.maClipRect.SetTop( nScrY );
+ aAreaParam.maClipRect.SetBottom( nScrY+nScrH );
+ }
+
+ // aClipRect is not used after SetClipRegion/IntersectClipRegion,
+ // so it can be modified here
+ if (bPixelToLogic)
+ aAreaParam.maClipRect = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
+
+ if (bMetaFile)
+ {
+ mpDev->Push();
+ mpDev->IntersectClipRegion( aAreaParam.maClipRect );
+ }
+ else
+ mpDev->SetClipRegion( vcl::Region( aAreaParam.maClipRect ) );
+ }
+
+ Point aURLStart( nJustPosX, nJustPosY ); // copy before modifying for orientation
+
+ switch (aVars.GetOrient())
+ {
+ case SvxCellOrientation::Standard:
+ nJustPosY += aVars.GetAscent();
+ break;
+ case SvxCellOrientation::TopBottom:
+ nJustPosX += aVars.GetTextSize().Width() - aVars.GetAscent();
+ break;
+ case SvxCellOrientation::BottomUp:
+ nJustPosY += aVars.GetTextSize().Height();
+ nJustPosX += aVars.GetAscent();
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ // When clipping, the visible part is now completely defined by the alignment,
+ // there's no more special handling to show the right part of RTL text.
+
+ Point aDrawTextPos( nJustPosX, nJustPosY );
+ if ( bPixelToLogic )
+ {
+ // undo text width adjustment in pixels
+ if (bRightAdjusted)
+ aDrawTextPos.AdjustX(aVars.GetTextSize().Width() );
+
+ aDrawTextPos = mpRefDevice->PixelToLogic( aDrawTextPos );
+
+ // redo text width adjustment in logic units
+ if (bRightAdjusted)
+ aDrawTextPos.AdjustX( -(aVars.GetOriginalWidth()) );
+ }
+
+ // in Metafiles always use DrawTextArray to ensure that positions are
+ // recorded (for non-proportional resize):
+
+ const OUString& aString = aVars.GetString();
+ if (!aString.isEmpty())
+ {
+ // If the string is clipped, make it shorter for
+ // better performance since drawing by HarfBuzz is
+ // quite expensive especially for long string.
+
+ OUString aShort = aString;
+
+ // But never fiddle with numeric values.
+ // (Which was the cause of tdf#86024).
+ // The General automatic format output takes
+ // care of this, or fixed width numbers either fit
+ // or display as ###.
+ if (!bCellIsValue)
+ {
+ double fVisibleRatio = 1.0;
+ double fTextWidth = aVars.GetTextSize().Width();
+ sal_Int32 nTextLen = aString.getLength();
+ if (eOutHorJust == SvxCellHorJustify::Left && aAreaParam.mnRightClipLength > 0)
+ {
+ fVisibleRatio = (fTextWidth - aAreaParam.mnRightClipLength) / fTextWidth;
+ if (0.0 < fVisibleRatio && fVisibleRatio < 1.0)
+ {
+ // Only show the left-end segment.
+ sal_Int32 nShortLen = fVisibleRatio*nTextLen + 1;
+ aShort = aShort.copy(0, nShortLen);
+ }
+ }
+ else if (eOutHorJust == SvxCellHorJustify::Right && aAreaParam.mnLeftClipLength > 0)
+ {
+ fVisibleRatio = (fTextWidth - aAreaParam.mnLeftClipLength) / fTextWidth;
+ if (0.0 < fVisibleRatio && fVisibleRatio < 1.0)
+ {
+ // Only show the right-end segment.
+ sal_Int32 nShortLen = fVisibleRatio*nTextLen + 1;
+ aShort = aShort.copy(nTextLen-nShortLen);
+
+ // Adjust the text position after shortening of the string.
+ double fShortWidth = aVars.GetFmtTextWidth(aShort);
+ double fOffset = fTextWidth - fShortWidth;
+ aDrawTextPos.Move(fOffset, 0);
+ }
+ }
+ }
+
+ // if we are not painting, it means we are interested in
+ // the area of the text that covers the specified cell
+ if (!bPaint && rAddress.Col() == nX)
+ {
+ tools::Rectangle aRect;
+ mpDev->GetTextBoundRect(aRect, aShort);
+ aRect += aDrawTextPos;
+ return aRect;
+ }
+
+ if (bMetaFile || pFmtDevice != mpDev || aZoomX != aZoomY)
+ {
+ size_t nLen = aShort.getLength();
+ if (aDX.size() < nLen)
+ aDX.resize(nLen, 0);
+
+ pFmtDevice->GetTextArray(aShort, &aDX);
+
+ if ( !mpRefDevice->GetConnectMetaFile() ||
+ mpRefDevice->GetOutDevType() == OUTDEV_PRINTER )
+ {
+ double fMul = GetStretch();
+ for (size_t i = 0; i < nLen; ++i)
+ aDX[i] = static_cast<sal_Int32>(aDX[i] / fMul + 0.5);
+ }
+
+ if (bPaint)
+ mpDev->DrawTextArray(aDrawTextPos, aShort, aDX);
+ }
+ else
+ {
+ if (bPaint)
+ mpDev->DrawText(aDrawTextPos, aShort, 0, -1, nullptr, nullptr,
+ aVars.GetLayoutGlyphs(aShort));
+ }
+ }
+
+ if ( bHClip || bVClip )
+ {
+ if (bMetaFile)
+ mpDev->Pop();
+ else
+ mpDev->SetClipRegion();
+ }
+
+ // PDF: whole-cell hyperlink from formula?
+ bool bHasURL = pPDFData && aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->IsHyperLinkCell();
+ if (bPaint && bHasURL)
+ {
+ tools::Rectangle aURLRect( aURLStart, aVars.GetTextSize() );
+ lcl_DoHyperlinkResult(mpDev, aURLRect, aCell);
+ }
+ }
+ }
+ nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
+ }
+ }
+ nPosY += pRowInfo[nArrY].nHeight;
+ }
+ if ( bProgress )
+ ScProgress::DeleteInterpretProgress();
+
+ return tools::Rectangle();
+}
+
+std::unique_ptr<ScFieldEditEngine> ScOutputData::CreateOutputEditEngine()
+{
+ std::unique_ptr<ScFieldEditEngine> pEngine(new ScFieldEditEngine(mpDoc, mpDoc->GetEnginePool()));
+ pEngine->SetUpdateLayout( false );
+ // a RefDevice always has to be set, otherwise EditEngine would create a VirtualDevice
+ pEngine->SetRefDevice( pFmtDevice );
+ EEControlBits nCtrl = pEngine->GetControlWord();
+ if ( bShowSpellErrors )
+ nCtrl |= EEControlBits::ONLINESPELLING;
+ if ( eType == OUTTYPE_PRINTER )
+ nCtrl &= ~EEControlBits::MARKFIELDS;
+ else
+ nCtrl &= ~EEControlBits::MARKURLFIELDS; // URLs not shaded for output
+ if ( eType == OUTTYPE_WINDOW && mpRefDevice == pFmtDevice )
+ nCtrl &= ~EEControlBits::FORMAT100; // use the actual MapMode
+ pEngine->SetControlWord( nCtrl );
+ mpDoc->ApplyAsianEditSettings( *pEngine );
+ pEngine->EnableAutoColor( mbUseStyleColor );
+ pEngine->SetDefaultHorizontalTextDirection( mpDoc->GetEditTextDirection( nTab ) );
+ return pEngine;
+}
+
+static void lcl_ClearEdit( EditEngine& rEngine ) // text and attributes
+{
+ rEngine.SetUpdateLayout( false );
+
+ rEngine.SetText(OUString());
+ // do not keep any para-attributes
+ const SfxItemSet& rPara = rEngine.GetParaAttribs(0);
+ if (rPara.Count())
+ rEngine.SetParaAttribs( 0,
+ SfxItemSet( *rPara.GetPool(), rPara.GetRanges() ) );
+ rEngine.EnableSkipOutsideFormat(false);
+}
+
+static bool lcl_SafeIsValue( ScRefCellValue& rCell )
+{
+ switch (rCell.meType)
+ {
+ case CELLTYPE_VALUE:
+ return true;
+ case CELLTYPE_FORMULA:
+ {
+ ScFormulaCell* pFCell = rCell.mpFormula;
+ if (pFCell->IsRunning() || pFCell->IsValue())
+ return true;
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return false;
+}
+
+static void lcl_ScaleFonts( EditEngine& rEngine, tools::Long nPercent )
+{
+ bool bUpdateMode = rEngine.SetUpdateLayout( false );
+
+ sal_Int32 nParCount = rEngine.GetParagraphCount();
+ for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
+ {
+ std::vector<sal_Int32> aPortions;
+ rEngine.GetPortions( nPar, aPortions );
+
+ sal_Int32 nStart = 0;
+ for ( const sal_Int32 nEnd : aPortions )
+ {
+ ESelection aSel( nPar, nStart, nPar, nEnd );
+ SfxItemSet aAttribs = rEngine.GetAttribs( aSel );
+
+ tools::Long nWestern = aAttribs.Get(EE_CHAR_FONTHEIGHT).GetHeight();
+ tools::Long nCJK = aAttribs.Get(EE_CHAR_FONTHEIGHT_CJK).GetHeight();
+ tools::Long nCTL = aAttribs.Get(EE_CHAR_FONTHEIGHT_CTL).GetHeight();
+
+ nWestern = ( nWestern * nPercent ) / 100;
+ nCJK = ( nCJK * nPercent ) / 100;
+ nCTL = ( nCTL * nPercent ) / 100;
+
+ aAttribs.Put( SvxFontHeightItem( nWestern, 100, EE_CHAR_FONTHEIGHT ) );
+ aAttribs.Put( SvxFontHeightItem( nCJK, 100, EE_CHAR_FONTHEIGHT_CJK ) );
+ aAttribs.Put( SvxFontHeightItem( nCTL, 100, EE_CHAR_FONTHEIGHT_CTL ) );
+
+ rEngine.QuickSetAttribs( aAttribs, aSel ); //! remove paragraph attributes from aAttribs?
+
+ nStart = nEnd;
+ }
+ }
+
+ if ( bUpdateMode )
+ rEngine.SetUpdateLayout( true );
+}
+
+static tools::Long lcl_GetEditSize( EditEngine& rEngine, bool bWidth, bool bSwap, Degree100 nAttrRotate )
+{
+ if ( bSwap )
+ bWidth = !bWidth;
+
+ if ( nAttrRotate )
+ {
+ tools::Long nRealWidth = static_cast<tools::Long>(rEngine.CalcTextWidth());
+ tools::Long nRealHeight = rEngine.GetTextHeight();
+
+ // assuming standard mode, otherwise width isn't used
+
+ double nRealOrient = toRadians(nAttrRotate); // 1/100th degrees
+ double nAbsCos = fabs( cos( nRealOrient ) );
+ double nAbsSin = fabs( sin( nRealOrient ) );
+ if ( bWidth )
+ return static_cast<tools::Long>( nRealWidth * nAbsCos + nRealHeight * nAbsSin );
+ else
+ return static_cast<tools::Long>( nRealHeight * nAbsCos + nRealWidth * nAbsSin );
+ }
+ else if ( bWidth )
+ return static_cast<tools::Long>(rEngine.CalcTextWidth());
+ else
+ return rEngine.GetTextHeight();
+}
+
+void ScOutputData::ShrinkEditEngine( EditEngine& rEngine, const tools::Rectangle& rAlignRect,
+ tools::Long nLeftM, tools::Long nTopM, tools::Long nRightM, tools::Long nBottomM,
+ bool bWidth, SvxCellOrientation nOrient, Degree100 nAttrRotate, bool bPixelToLogic,
+ tools::Long& rEngineWidth, tools::Long& rEngineHeight, tools::Long& rNeededPixel, bool& rLeftClip, bool& rRightClip )
+{
+ if ( !bWidth )
+ {
+ // vertical
+
+ tools::Long nScaleSize = bPixelToLogic ?
+ mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
+
+ // Don't scale if it fits already.
+ // Allowing to extend into the margin, to avoid scaling at optimal height.
+ if ( nScaleSize <= rAlignRect.GetHeight() )
+ return;
+
+ bool bSwap = ( nOrient == SvxCellOrientation::TopBottom || nOrient == SvxCellOrientation::BottomUp );
+ tools::Long nAvailable = rAlignRect.GetHeight() - nTopM - nBottomM;
+ tools::Long nScale = ( nAvailable * 100 ) / nScaleSize;
+
+ lcl_ScaleFonts( rEngine, nScale );
+ rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
+ tools::Long nNewSize = bPixelToLogic ?
+ mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
+
+ sal_uInt16 nShrinkAgain = 0;
+ while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
+ {
+ // further reduce, like in DrawStrings
+ lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
+ rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
+ nNewSize = bPixelToLogic ?
+ mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
+ ++nShrinkAgain;
+ }
+
+ // sizes for further processing (alignment etc):
+ rEngineWidth = lcl_GetEditSize( rEngine, true, bSwap, nAttrRotate );
+ tools::Long nPixelWidth = bPixelToLogic ?
+ mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
+ rNeededPixel = nPixelWidth + nLeftM + nRightM;
+ }
+ else if ( rLeftClip || rRightClip )
+ {
+ // horizontal
+
+ tools::Long nAvailable = rAlignRect.GetWidth() - nLeftM - nRightM;
+ tools::Long nScaleSize = rNeededPixel - nLeftM - nRightM; // without margin
+
+ if ( nScaleSize <= nAvailable )
+ return;
+
+ tools::Long nScale = ( nAvailable * 100 ) / nScaleSize;
+
+ lcl_ScaleFonts( rEngine, nScale );
+ rEngineWidth = lcl_GetEditSize( rEngine, true, false, nAttrRotate );
+ tools::Long nNewSize = bPixelToLogic ?
+ mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
+
+ sal_uInt16 nShrinkAgain = 0;
+ while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
+ {
+ // further reduce, like in DrawStrings
+ lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
+ rEngineWidth = lcl_GetEditSize( rEngine, true, false, nAttrRotate );
+ nNewSize = bPixelToLogic ?
+ mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
+ ++nShrinkAgain;
+ }
+ if ( nNewSize <= nAvailable )
+ rLeftClip = rRightClip = false;
+
+ // sizes for further processing (alignment etc):
+ rNeededPixel = nNewSize + nLeftM + nRightM;
+ rEngineHeight = lcl_GetEditSize( rEngine, false, false, nAttrRotate );
+ }
+}
+
+ScOutputData::DrawEditParam::DrawEditParam(const ScPatternAttr* pPattern, const SfxItemSet* pCondSet, bool bCellIsValue) :
+ meHorJustAttr( lcl_GetValue<SvxHorJustifyItem, SvxCellHorJustify>(*pPattern, ATTR_HOR_JUSTIFY, pCondSet) ),
+ meHorJustContext( meHorJustAttr ),
+ meHorJustResult( meHorJustAttr ),
+ meVerJust( lcl_GetValue<SvxVerJustifyItem, SvxCellVerJustify>(*pPattern, ATTR_VER_JUSTIFY, pCondSet) ),
+ meHorJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet) ),
+ meVerJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_VER_JUSTIFY_METHOD, pCondSet) ),
+ meOrient( pPattern->GetCellOrientation(pCondSet) ),
+ mnArrY(0),
+ mnX(0), mnCellX(0), mnCellY(0),
+ mnPosX(0), mnPosY(0), mnInitPosX(0),
+ mbBreak( (meHorJustAttr == SvxCellHorJustify::Block) || lcl_GetBoolValue(*pPattern, ATTR_LINEBREAK, pCondSet) ),
+ mbCellIsValue(bCellIsValue),
+ mbAsianVertical(false),
+ mbPixelToLogic(false),
+ mbHyphenatorSet(false),
+ mpEngine(nullptr),
+ mpPattern(pPattern),
+ mpCondSet(pCondSet),
+ mpPreviewFontSet(nullptr),
+ mpOldPattern(nullptr),
+ mpOldCondSet(nullptr),
+ mpOldPreviewFontSet(nullptr),
+ mpThisRowInfo(nullptr),
+ mpMisspellRanges(nullptr)
+{}
+
+bool ScOutputData::DrawEditParam::readCellContent(
+ const ScDocument* pDoc, bool bShowNullValues, bool bShowFormulas, bool bSyntaxMode, bool bUseStyleColor, bool bForceAutoColor, bool& rWrapFields)
+{
+ if (maCell.meType == CELLTYPE_EDIT)
+ {
+ const EditTextObject* pData = maCell.mpEditText;
+ if (pData)
+ {
+ mpEngine->SetTextCurrentDefaults(*pData);
+
+ if ( mbBreak && !mbAsianVertical && pData->HasField() )
+ {
+ // Fields aren't wrapped, so clipping is enabled to prevent
+ // a field from being drawn beyond the cell size
+
+ rWrapFields = true;
+ }
+ }
+ else
+ {
+ OSL_FAIL("pData == 0");
+ return false;
+ }
+ }
+ else
+ {
+ sal_uInt32 nFormat = mpPattern->GetNumberFormat(
+ pDoc->GetFormatTable(), mpCondSet );
+ const Color* pColor;
+ OUString aString = ScCellFormat::GetString( maCell,
+ nFormat, &pColor,
+ *pDoc->GetFormatTable(),
+ *pDoc,
+ bShowNullValues,
+ bShowFormulas);
+
+ mpEngine->SetTextCurrentDefaults(aString);
+ if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) )
+ lcl_SetEditColor( *mpEngine, *pColor );
+ }
+
+ if (mpMisspellRanges)
+ mpEngine->SetAllMisspellRanges(*mpMisspellRanges);
+
+ return true;
+}
+
+void ScOutputData::DrawEditParam::setPatternToEngine(bool bUseStyleColor)
+{
+ // syntax highlighting mode is ignored here
+ // StringDiffer doesn't look at hyphenate, language items
+
+ if (mpPattern == mpOldPattern && mpCondSet == mpOldCondSet && mpPreviewFontSet == mpOldPreviewFontSet )
+ return;
+
+ Color nConfBackColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+ bool bCellContrast = bUseStyleColor &&
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode();
+
+ auto pSet = std::make_unique<SfxItemSet>( mpEngine->GetEmptyItemSet() );
+ mpPattern->FillEditItemSet( pSet.get(), mpCondSet );
+ if ( mpPreviewFontSet )
+ {
+ if ( const SvxFontItem* pItem = mpPreviewFontSet->GetItemIfSet( ATTR_FONT ) )
+ {
+ // tdf#125054 adapt WhichID
+ pSet->Put(*pItem, EE_CHAR_FONTINFO);
+ }
+ if ( const SvxFontItem* pItem = mpPreviewFontSet->GetItemIfSet( ATTR_CJK_FONT ) )
+ {
+ // tdf#125054 adapt WhichID
+ pSet->Put(*pItem, EE_CHAR_FONTINFO_CJK);
+ }
+ if ( const SvxFontItem* pItem = mpPreviewFontSet->GetItemIfSet( ATTR_CTL_FONT ) )
+ {
+ // tdf#125054 adapt WhichID
+ pSet->Put(*pItem, EE_CHAR_FONTINFO_CTL);
+ }
+ }
+ bool bParaHyphenate = pSet->Get(EE_PARA_HYPHENATE).GetValue();
+ mpEngine->SetDefaults( std::move(pSet) );
+ mpOldPattern = mpPattern;
+ mpOldCondSet = mpCondSet;
+ mpOldPreviewFontSet = mpPreviewFontSet;
+
+ EEControlBits nControl = mpEngine->GetControlWord();
+ if (meOrient == SvxCellOrientation::Stacked)
+ nControl |= EEControlBits::ONECHARPERLINE;
+ else
+ nControl &= ~EEControlBits::ONECHARPERLINE;
+ mpEngine->SetControlWord( nControl );
+
+ if ( !mbHyphenatorSet && bParaHyphenate )
+ {
+ // set hyphenator the first time it is needed
+ css::uno::Reference<css::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
+ mpEngine->SetHyphenator( xXHyphenator );
+ mbHyphenatorSet = true;
+ }
+
+ Color aBackCol = mpPattern->GetItem( ATTR_BACKGROUND, mpCondSet ).GetColor();
+ if ( bUseStyleColor && ( aBackCol.IsTransparent() || bCellContrast ) )
+ aBackCol = nConfBackColor;
+ mpEngine->SetBackgroundColor( aBackCol );
+}
+
+void ScOutputData::DrawEditParam::calcMargins(tools::Long& rTopM, tools::Long& rLeftM, tools::Long& rBottomM, tools::Long& rRightM, double nPPTX, double nPPTY) const
+{
+ const SvxMarginItem& rMargin = mpPattern->GetItem(ATTR_MARGIN, mpCondSet);
+
+ sal_uInt16 nIndent = 0;
+ if (meHorJustAttr == SvxCellHorJustify::Left || meHorJustAttr == SvxCellHorJustify::Right)
+ nIndent = lcl_GetValue<ScIndentItem, sal_uInt16>(*mpPattern, ATTR_INDENT, mpCondSet);
+
+ rLeftM = static_cast<tools::Long>(((rMargin.GetLeftMargin() + nIndent) * nPPTX));
+ rTopM = static_cast<tools::Long>((rMargin.GetTopMargin() * nPPTY));
+ rRightM = static_cast<tools::Long>((rMargin.GetRightMargin() * nPPTX));
+ rBottomM = static_cast<tools::Long>((rMargin.GetBottomMargin() * nPPTY));
+ if(meHorJustAttr == SvxCellHorJustify::Right)
+ {
+ rLeftM = static_cast<tools::Long>((rMargin.GetLeftMargin() * nPPTX));
+ rRightM = static_cast<tools::Long>(((rMargin.GetRightMargin() + nIndent) * nPPTX));
+ }
+}
+
+void ScOutputData::DrawEditParam::calcPaperSize(
+ Size& rPaperSize, const tools::Rectangle& rAlignRect, double nPPTX, double nPPTY) const
+{
+ tools::Long nTopM, nLeftM, nBottomM, nRightM;
+ calcMargins(nTopM, nLeftM, nBottomM, nRightM, nPPTX, nPPTY);
+
+ if (isVerticallyOriented())
+ {
+ rPaperSize.setWidth( rAlignRect.GetHeight() - nTopM - nBottomM );
+ rPaperSize.setHeight( rAlignRect.GetWidth() - nLeftM - nRightM );
+ }
+ else
+ {
+ rPaperSize.setWidth( rAlignRect.GetWidth() - nLeftM - nRightM );
+ rPaperSize.setHeight( rAlignRect.GetHeight() - nTopM - nBottomM );
+ }
+
+ if (mbAsianVertical)
+ {
+ rPaperSize.setHeight( rAlignRect.GetHeight() - nTopM - nBottomM );
+ // Subtract some extra value from the height or else the text would go
+ // outside the cell area. The value of 5 is arbitrary, and is based
+ // entirely on heuristics.
+ rPaperSize.AdjustHeight( -5 );
+ }
+}
+
+void ScOutputData::DrawEditParam::getEngineSize(ScFieldEditEngine* pEngine, tools::Long& rWidth, tools::Long& rHeight) const
+{
+ tools::Long nEngineWidth = 0;
+ if (!mbBreak || meOrient == SvxCellOrientation::Stacked || mbAsianVertical)
+ nEngineWidth = static_cast<tools::Long>(pEngine->CalcTextWidth());
+
+ tools::Long nEngineHeight = pEngine->GetTextHeight();
+
+ if (isVerticallyOriented())
+ {
+ tools::Long nTemp = nEngineWidth;
+ nEngineWidth = nEngineHeight;
+ nEngineHeight = nTemp;
+ }
+
+ if (meOrient == SvxCellOrientation::Stacked)
+ nEngineWidth = nEngineWidth * 11 / 10;
+
+ rWidth = nEngineWidth;
+ rHeight = nEngineHeight;
+}
+
+bool ScOutputData::DrawEditParam::hasLineBreak() const
+{
+ return (mbBreak || (meOrient == SvxCellOrientation::Stacked) || mbAsianVertical);
+}
+
+bool ScOutputData::DrawEditParam::isHyperlinkCell() const
+{
+ if (maCell.meType != CELLTYPE_FORMULA)
+ return false;
+
+ return maCell.mpFormula->IsHyperLinkCell();
+}
+
+bool ScOutputData::DrawEditParam::isVerticallyOriented() const
+{
+ return (meOrient == SvxCellOrientation::TopBottom || meOrient == SvxCellOrientation::BottomUp);
+}
+
+void ScOutputData::DrawEditParam::calcStartPosForVertical(
+ Point& rLogicStart, tools::Long nCellWidth, tools::Long nEngineWidth, tools::Long nTopM, const OutputDevice* pRefDevice)
+{
+ OSL_ENSURE(isVerticallyOriented(), "Use this only for vertically oriented cell!");
+
+ if (mbPixelToLogic)
+ rLogicStart = pRefDevice->PixelToLogic(rLogicStart);
+
+ if (!mbBreak)
+ return;
+
+ // vertical adjustment is within the EditEngine
+ if (mbPixelToLogic)
+ rLogicStart.AdjustY(pRefDevice->PixelToLogic(Size(0,nTopM)).Height() );
+ else
+ rLogicStart.AdjustY(nTopM );
+
+ switch (meHorJustResult)
+ {
+ case SvxCellHorJustify::Center:
+ rLogicStart.AdjustX((nCellWidth - nEngineWidth) / 2 );
+ break;
+ case SvxCellHorJustify::Right:
+ rLogicStart.AdjustX(nCellWidth - nEngineWidth );
+ break;
+ default:
+ ; // do nothing
+ }
+}
+
+void ScOutputData::DrawEditParam::setAlignmentToEngine()
+{
+ if (isVerticallyOriented() || mbAsianVertical)
+ {
+ SvxAdjust eSvxAdjust = SvxAdjust::Left;
+ switch (meVerJust)
+ {
+ case SvxCellVerJustify::Top:
+ eSvxAdjust = (meOrient == SvxCellOrientation::TopBottom || mbAsianVertical) ?
+ SvxAdjust::Left : SvxAdjust::Right;
+ break;
+ case SvxCellVerJustify::Center:
+ eSvxAdjust = SvxAdjust::Center;
+ break;
+ case SvxCellVerJustify::Bottom:
+ case SvxCellVerJustify::Standard:
+ eSvxAdjust = (meOrient == SvxCellOrientation::TopBottom || mbAsianVertical) ?
+ SvxAdjust::Right : SvxAdjust::Left;
+ break;
+ case SvxCellVerJustify::Block:
+ eSvxAdjust = SvxAdjust::Block;
+ break;
+ }
+
+ mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
+ mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
+
+ if (meHorJustResult == SvxCellHorJustify::Block)
+ mpEngine->SetDefaultItem( SvxVerJustifyItem(SvxCellVerJustify::Block, EE_PARA_VER_JUST) );
+ }
+ else
+ {
+ // horizontal alignment now may depend on cell content
+ // (for values with number formats with mixed script types)
+ // -> always set adjustment
+
+ SvxAdjust eSvxAdjust = SvxAdjust::Left;
+ if (meOrient == SvxCellOrientation::Stacked)
+ eSvxAdjust = SvxAdjust::Center;
+ else if (mbBreak)
+ {
+ if (meOrient == SvxCellOrientation::Standard)
+ switch (meHorJustResult)
+ {
+ case SvxCellHorJustify::Repeat: // repeat is not yet implemented
+ case SvxCellHorJustify::Standard:
+ SAL_WARN("sc.ui","meHorJustResult does not match getAlignmentFromContext()");
+ [[fallthrough]];
+ case SvxCellHorJustify::Left:
+ eSvxAdjust = SvxAdjust::Left;
+ break;
+ case SvxCellHorJustify::Center:
+ eSvxAdjust = SvxAdjust::Center;
+ break;
+ case SvxCellHorJustify::Right:
+ eSvxAdjust = SvxAdjust::Right;
+ break;
+ case SvxCellHorJustify::Block:
+ eSvxAdjust = SvxAdjust::Block;
+ break;
+ }
+ else
+ switch (meVerJust)
+ {
+ case SvxCellVerJustify::Top:
+ eSvxAdjust = SvxAdjust::Right;
+ break;
+ case SvxCellVerJustify::Center:
+ eSvxAdjust = SvxAdjust::Center;
+ break;
+ case SvxCellVerJustify::Bottom:
+ case SvxCellVerJustify::Standard:
+ eSvxAdjust = SvxAdjust::Left;
+ break;
+ case SvxCellVerJustify::Block:
+ eSvxAdjust = SvxAdjust::Block;
+ break;
+ }
+ }
+
+ mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
+
+ if (mbAsianVertical)
+ {
+ mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
+ if (meHorJustResult == SvxCellHorJustify::Block)
+ mpEngine->SetDefaultItem( SvxVerJustifyItem(SvxCellVerJustify::Block, EE_PARA_VER_JUST) );
+ }
+ else
+ {
+ mpEngine->SetDefaultItem( SvxJustifyMethodItem(meHorJustMethod, EE_PARA_JUST_METHOD) );
+ if (meVerJust == SvxCellVerJustify::Block)
+ mpEngine->SetDefaultItem( SvxVerJustifyItem(SvxCellVerJustify::Block, EE_PARA_VER_JUST) );
+ }
+ }
+
+ mpEngine->SetVertical(mbAsianVertical);
+ if (maCell.meType == CELLTYPE_EDIT)
+ {
+ // We need to synchronize the vertical mode in the EditTextObject
+ // instance too. No idea why we keep this state in two separate
+ // instances.
+ const EditTextObject* pData = maCell.mpEditText;
+ if (pData)
+ const_cast<EditTextObject*>(pData)->SetVertical(mbAsianVertical);
+ }
+}
+
+bool ScOutputData::DrawEditParam::adjustHorAlignment(ScFieldEditEngine* pEngine)
+{
+ if (meHorJustResult == SvxCellHorJustify::Right || meHorJustResult == SvxCellHorJustify::Center)
+ {
+ SvxAdjust eEditAdjust = (meHorJustResult == SvxCellHorJustify::Center) ?
+ SvxAdjust::Center : SvxAdjust::Right;
+
+ const bool bPrevUpdateLayout = pEngine->SetUpdateLayout(false);
+ pEngine->SetDefaultItem( SvxAdjustItem(eEditAdjust, EE_PARA_JUST) );
+ pEngine->SetUpdateLayout(bPrevUpdateLayout);
+ return true;
+ }
+ return false;
+}
+
+void ScOutputData::DrawEditParam::adjustForHyperlinkInPDF(Point aURLStart, const OutputDevice* pDev)
+{
+ // PDF: whole-cell hyperlink from formula?
+ vcl::PDFExtOutDevData* pPDFData = dynamic_cast<vcl::PDFExtOutDevData* >( pDev->GetExtOutDevData() );
+ bool bHasURL = pPDFData && isHyperlinkCell();
+ if (!bHasURL)
+ return;
+
+ tools::Long nURLWidth = static_cast<tools::Long>(mpEngine->CalcTextWidth());
+ tools::Long nURLHeight = mpEngine->GetTextHeight();
+ if (mbBreak)
+ {
+ Size aPaper = mpEngine->GetPaperSize();
+ if ( mbAsianVertical )
+ nURLHeight = aPaper.Height();
+ else
+ nURLWidth = aPaper.Width();
+ }
+ if (isVerticallyOriented())
+ std::swap( nURLWidth, nURLHeight );
+ else if (mbAsianVertical)
+ aURLStart.AdjustX( -nURLWidth );
+
+ tools::Rectangle aURLRect( aURLStart, Size( nURLWidth, nURLHeight ) );
+ lcl_DoHyperlinkResult(pDev, aURLRect, maCell);
+}
+
+// Returns true if the rect is clipped vertically
+bool ScOutputData::AdjustAreaParamClipRect(OutputAreaParam& rAreaParam)
+{
+ if( rAreaParam.maClipRect.Left() < nScrX )
+ {
+ rAreaParam.maClipRect.SetLeft( nScrX );
+ rAreaParam.mbLeftClip = true;
+ }
+ if( rAreaParam.maClipRect.Right() > nScrX + nScrW )
+ {
+ rAreaParam.maClipRect.SetRight( nScrX + nScrW ); //! minus one?
+ rAreaParam.mbRightClip = true;
+ }
+
+ bool bVClip = false;
+
+ if( rAreaParam.maClipRect.Top() < nScrY )
+ {
+ rAreaParam.maClipRect.SetTop( nScrY );
+ bVClip = true;
+ }
+ if( rAreaParam.maClipRect.Bottom() > nScrY + nScrH )
+ {
+ rAreaParam.maClipRect.SetBottom( nScrY + nScrH ); //! minus one?
+ bVClip = true;
+ }
+ return bVClip;
+}
+
+// Doesn't handle clip marks - should be handled in advance using GetOutputArea
+class ClearableClipRegion
+{
+public:
+ ClearableClipRegion( const tools::Rectangle& rRect, bool bClip, bool bSimClip,
+ const VclPtr<OutputDevice>& pDev, bool bMetaFile )
+ :mbMetaFile(bMetaFile)
+ {
+ if (!(bClip || bSimClip))
+ return;
+
+ maRect = rRect;
+ if (bClip) // for bSimClip only initialize aClipRect
+ {
+ mpDev.reset(pDev);
+ if (mbMetaFile)
+ {
+ mpDev->Push();
+ mpDev->IntersectClipRegion(maRect);
+ }
+ else
+ mpDev->SetClipRegion(vcl::Region(maRect));
+ }
+ }
+
+ ~ClearableClipRegion() COVERITY_NOEXCEPT_FALSE
+ {
+ // Pop() or SetClipRegion() must only be called in case bClip was true
+ // in the ctor, and only then mpDev is set.
+ if (mpDev)
+ {
+ if (mbMetaFile)
+ mpDev->Pop();
+ else
+ mpDev->SetClipRegion();
+ }
+ }
+
+ const tools::Rectangle& getRect() const { return maRect; }
+
+private:
+ tools::Rectangle maRect;
+ VclPtr<OutputDevice> mpDev;
+ bool mbMetaFile;
+};
+
+// Returns needed width in current units; sets rNeededPixel to needed width in pixels
+tools::Long ScOutputData::SetEngineTextAndGetWidth( DrawEditParam& rParam, const OUString& rSetString,
+ tools::Long& rNeededPixel, tools::Long nAddWidthPixels )
+{
+ rParam.mpEngine->SetTextCurrentDefaults( rSetString );
+ tools::Long nEngineWidth = static_cast<tools::Long>( rParam.mpEngine->CalcTextWidth() );
+ if ( rParam.mbPixelToLogic )
+ rNeededPixel = mpRefDevice->LogicToPixel( Size( nEngineWidth, 0 ) ).Width();
+ else
+ rNeededPixel = nEngineWidth;
+
+ rNeededPixel += nAddWidthPixels;
+
+ return nEngineWidth;
+}
+
+void ScOutputData::DrawEditStandard(DrawEditParam& rParam)
+{
+ OSL_ASSERT(rParam.meOrient == SvxCellOrientation::Standard);
+ OSL_ASSERT(!rParam.mbAsianVertical);
+
+ Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
+
+ bool bRepeat = (rParam.meHorJustAttr == SvxCellHorJustify::Repeat && !rParam.mbBreak);
+ bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
+ Degree100 nAttrRotate = lcl_GetValue<ScRotateValueItem, Degree100>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
+
+ if ( rParam.meHorJustAttr == SvxCellHorJustify::Repeat )
+ {
+ // ignore orientation/rotation if "repeat" is active
+ rParam.meOrient = SvxCellOrientation::Standard;
+ nAttrRotate = 0_deg100;
+
+ // #i31843# "repeat" with "line breaks" is treated as default alignment
+ // (but rotation is still disabled).
+ // Default again leads to context dependent alignment instead of
+ // SvxCellHorJustify::Standard.
+ if ( rParam.mbBreak )
+ rParam.meHorJustResult = rParam.meHorJustContext;
+ }
+
+ if (nAttrRotate)
+ {
+ //! set flag to find the cell in DrawRotated again ?
+ //! (or flag already set during DrawBackground, then no query here)
+ return; // rotated is outputted separately
+ }
+
+ SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
+
+ //! mirror margin values for RTL?
+ //! move margin down to after final GetOutputArea call
+ tools::Long nTopM, nLeftM, nBottomM, nRightM;
+ rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
+
+ SCCOL nXForPos = rParam.mnX;
+ if ( nXForPos < nX1 )
+ {
+ nXForPos = nX1;
+ rParam.mnPosX = rParam.mnInitPosX;
+ }
+ SCSIZE nArrYForPos = rParam.mnArrY;
+ if ( nArrYForPos < 1 )
+ {
+ nArrYForPos = 1;
+ rParam.mnPosY = nScrY;
+ }
+
+ OutputAreaParam aAreaParam;
+
+ // Initial page size - large for normal text, cell size for automatic line breaks
+
+ Size aPaperSize( 1000000, 1000000 );
+ if (rParam.mbBreak)
+ {
+ // call GetOutputArea with nNeeded=0, to get only the cell width
+
+ //! handle nArrY == 0
+ GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
+ *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ rParam.mbCellIsValue, true, false, aAreaParam );
+
+ //! special ScEditUtil handling if formatting for printer
+ rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
+ }
+ if (rParam.mbPixelToLogic)
+ {
+ Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
+ if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
+ {
+ // #i85342# screen display and formatting for printer,
+ // use same GetEditArea call as in ScViewData::SetEditEngine
+
+ Fraction aFract(1,1);
+ tools::Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
+ HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
+ aLogicSize.setWidth( aUtilRect.GetWidth() );
+ }
+ rParam.mpEngine->SetPaperSize(aLogicSize);
+ }
+ else
+ rParam.mpEngine->SetPaperSize(aPaperSize);
+
+ // Fill the EditEngine (cell attributes and text)
+
+ // default alignment for asian vertical mode is top-right
+ if ( rParam.mbAsianVertical && rParam.meVerJust == SvxCellVerJustify::Standard )
+ rParam.meVerJust = SvxCellVerJustify::Top;
+
+ rParam.setPatternToEngine(mbUseStyleColor);
+ rParam.setAlignmentToEngine();
+ // Don't format unnecessary parts if the text will be drawn from top (Standard will
+ // act that way if text doesn't fit, see below).
+ rParam.mpEngine->EnableSkipOutsideFormat(rParam.meVerJust==SvxCellVerJustify::Top
+ || rParam.meVerJust==SvxCellVerJustify::Standard);
+
+ // Read content from cell
+
+ bool bWrapFields = false;
+ if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
+ // Failed to read cell content. Bail out.
+ return;
+
+ if ( mbSyntaxMode )
+ SetEditSyntaxColor(*rParam.mpEngine, rParam.maCell);
+ else if ( mbUseStyleColor && mbForceAutoColor )
+ lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
+
+ rParam.mpEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
+
+ // Get final output area using the calculated width
+
+ tools::Long nEngineWidth, nEngineHeight;
+ rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
+
+ tools::Long nNeededPixel = nEngineWidth;
+ if (rParam.mbPixelToLogic)
+ nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
+ nNeededPixel += nLeftM + nRightM;
+
+ if (!rParam.mbBreak || bShrink)
+ {
+ // for break, the first GetOutputArea call is sufficient
+ GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
+ *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
+
+ if ( bShrink )
+ {
+ ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
+ nLeftM, nTopM, nRightM, nBottomM, true,
+ rParam.meOrient, 0_deg100, rParam.mbPixelToLogic,
+ nEngineWidth, nEngineHeight, nNeededPixel,
+ aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
+ }
+ if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
+ {
+ // First check if twice the space for the formatted text is available
+ // (otherwise just keep it unchanged).
+
+ tools::Long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
+ tools::Long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
+ if ( nAvailable >= 2 * nFormatted )
+ {
+ // "repeat" is handled with unformatted text (for performance reasons)
+ OUString aCellStr = rParam.mpEngine->GetText();
+
+ tools::Long nRepeatSize = 0;
+ SetEngineTextAndGetWidth( rParam, aCellStr, nRepeatSize, 0 );
+ if ( pFmtDevice != mpRefDevice )
+ ++nRepeatSize;
+ if ( nRepeatSize > 0 )
+ {
+ tools::Long nRepeatCount = nAvailable / nRepeatSize;
+ if ( nRepeatCount > 1 )
+ {
+ OUStringBuffer aRepeated(aCellStr);
+ for ( tools::Long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
+ aRepeated.append(aCellStr);
+
+ SetEngineTextAndGetWidth( rParam, aRepeated.makeStringAndClear(),
+ nNeededPixel, (nLeftM + nRightM ) );
+
+ nEngineHeight = rParam.mpEngine->GetTextHeight();
+ }
+ }
+ }
+ }
+
+
+ if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
+ {
+ SetEngineTextAndGetWidth( rParam, "###", nNeededPixel, ( nLeftM + nRightM ) );
+
+ // No clip marks if "###" doesn't fit (same as in DrawStrings)
+ }
+
+ if (eOutHorJust != SvxCellHorJustify::Left)
+ {
+ aPaperSize.setWidth( nNeededPixel + 1 );
+ if (rParam.mbPixelToLogic)
+ rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
+ else
+ rParam.mpEngine->SetPaperSize(aPaperSize);
+ }
+ }
+
+ tools::Long nStartX = aAreaParam.maAlignRect.Left();
+ tools::Long nStartY = aAreaParam.maAlignRect.Top();
+ tools::Long nCellWidth = aAreaParam.maAlignRect.GetWidth();
+ tools::Long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
+ tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
+
+ if (rParam.mbBreak)
+ {
+ // text with automatic breaks is aligned only within the
+ // edit engine's paper size, the output of the whole area
+ // is always left-aligned
+
+ nStartX += nLeftM;
+ }
+ else
+ {
+ if ( eOutHorJust == SvxCellHorJustify::Right )
+ nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
+ else if ( eOutHorJust == SvxCellHorJustify::Center )
+ nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
+ else
+ nStartX += nLeftM;
+ }
+
+ bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
+ if (bOutside)
+ return;
+
+ // Also take fields in a cell with automatic breaks into account: clip to cell width
+ bool bClip = AdjustAreaParamClipRect(aAreaParam) || aAreaParam.mbLeftClip || aAreaParam.mbRightClip || bWrapFields;
+ bool bSimClip = false;
+
+ Size aCellSize; // output area, excluding margins, in logical units
+ if (rParam.mbPixelToLogic)
+ aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
+ else
+ aCellSize = Size( nOutWidth, nOutHeight );
+
+ if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
+ {
+ const ScMergeAttr* pMerge = &rParam.mpPattern->GetItem(ATTR_MERGE);
+ bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
+
+ // Don't clip for text height when printing rows with optimal height,
+ // except when font size is from conditional formatting.
+ //! Allow clipping when vertically merged?
+ if ( eType != OUTTYPE_PRINTER ||
+ ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CRFlags::ManualSize ) ||
+ ( rParam.mpCondSet && SfxItemState::SET ==
+ rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT) ) )
+ bClip = true;
+ else
+ bSimClip = true;
+
+ // Show clip marks if height is at least 5pt too small and
+ // there are several lines of text.
+ // Not for asian vertical text, because that would interfere
+ // with the default right position of the text.
+ // Only with automatic line breaks, to avoid having to find
+ // the cells with the horizontal end of the text again.
+ if ( nEngineHeight - aCellSize.Height() > 100 &&
+ rParam.mbBreak && bMarkClipped &&
+ ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
+ {
+ ScCellInfo* pClipMarkCell = nullptr;
+ if ( bMerged )
+ {
+ // anywhere in the merged area...
+ SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
+ pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].cellInfo(nClipX);
+ }
+ else
+ pClipMarkCell = &rParam.mpThisRowInfo->cellInfo(rParam.mnX);
+
+ pClipMarkCell->nClipMark |= ScClipMark::Right; //! also allow left?
+ bAnyClipped = true;
+
+ tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
+ if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
+ aAreaParam.maClipRect.AdjustRight( -nMarkPixel );
+
+ // Standard is normally treated as Bottom, but if text height is clipped, then
+ // Top looks better and also allows using EditEngine::EnableSkipOutsideFormat().
+ if (rParam.meVerJust==SvxCellVerJustify::Standard)
+ rParam.meVerJust=SvxCellVerJustify::Top;
+ }
+ }
+
+ Point aURLStart;
+
+ { // Clip marks are already handled in GetOutputArea
+ ClearableClipRegion aClip(rParam.mbPixelToLogic ? mpRefDevice->PixelToLogic(aAreaParam.maClipRect)
+ : aAreaParam.maClipRect, bClip, bSimClip, mpDev, bMetaFile);
+
+ Point aLogicStart;
+ if (rParam.mbPixelToLogic)
+ aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
+ else
+ aLogicStart = Point(nStartX, nStartY);
+
+ if (!rParam.mbBreak)
+ {
+ // horizontal alignment
+ if (rParam.adjustHorAlignment(rParam.mpEngine))
+ // reset adjustment for the next cell
+ rParam.mpOldPattern = nullptr;
+ }
+
+ if (rParam.meVerJust==SvxCellVerJustify::Bottom ||
+ rParam.meVerJust==SvxCellVerJustify::Standard)
+ {
+ //! if pRefDevice != pFmtDevice, keep heights in logic units,
+ //! only converting margin?
+
+ if (rParam.mbPixelToLogic)
+ aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0, nTopM +
+ mpRefDevice->LogicToPixel(aCellSize).Height() -
+ mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
+ )).Height() );
+ else
+ aLogicStart.AdjustY(nTopM + aCellSize.Height() - nEngineHeight );
+ }
+ else if (rParam.meVerJust==SvxCellVerJustify::Center)
+ {
+ if (rParam.mbPixelToLogic)
+ aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0, nTopM + (
+ mpRefDevice->LogicToPixel(aCellSize).Height() -
+ mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
+ / 2)).Height() );
+ else
+ aLogicStart.AdjustY(nTopM + (aCellSize.Height() - nEngineHeight) / 2 );
+ }
+ else // top
+ {
+ if (rParam.mbPixelToLogic)
+ aLogicStart.AdjustY(mpRefDevice->PixelToLogic(Size(0,nTopM)).Height() );
+ else
+ aLogicStart.AdjustY(nTopM );
+ }
+
+ aURLStart = aLogicStart; // copy before modifying for orientation
+
+ // bMoveClipped handling has been replaced by complete alignment
+ // handling (also extending to the left).
+
+ if (bSimClip)
+ {
+ // no hard clip, only draw the affected rows
+ Point aDocStart = aClip.getRect().TopLeft();
+ aDocStart -= aLogicStart;
+ rParam.mpEngine->Draw(*mpDev, aClip.getRect(), aDocStart, false);
+ }
+ else
+ {
+ rParam.mpEngine->Draw(*mpDev, aLogicStart);
+ }
+ }
+
+ rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
+}
+
+void ScOutputData::ShowClipMarks( DrawEditParam& rParam, tools::Long nEngineWidth, const Size& aCellSize,
+ bool bMerged, OutputAreaParam& aAreaParam, bool bTop)
+{
+ // Show clip marks if width is at least 5pt too small and
+ // there are several lines of text.
+ // Not for asian vertical text, because that would interfere
+ // with the default right position of the text.
+ // Only with automatic line breaks, to avoid having to find
+ // the cells with the horizontal end of the text again.
+ if (nEngineWidth - aCellSize.Width() <= 100 || !rParam.mbBreak || !bMarkClipped
+ || (rParam.mpEngine->GetParagraphCount() <= 1 && rParam.mpEngine->GetLineCount(0) <= 1))
+ return;
+
+ ScCellInfo* pClipMarkCell = nullptr;
+ if (bMerged)
+ {
+ // anywhere in the merged area...
+ SCCOL nClipX = (rParam.mnX < nX1) ? nX1 : rParam.mnX;
+ pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].cellInfo(nClipX);
+ }
+ else
+ pClipMarkCell = &rParam.mpThisRowInfo->cellInfo(rParam.mnX);
+
+ bAnyClipped = true;
+ bVertical = true;
+ const tools::Long nMarkPixel = static_cast<tools::Long>(SC_CLIPMARK_SIZE * mnPPTX);
+ if (bTop)
+ {
+ pClipMarkCell->nClipMark |= ScClipMark::Top;
+ if (aAreaParam.maClipRect.Top() - nMarkPixel < aAreaParam.maClipRect.Bottom())
+ aAreaParam.maClipRect.AdjustTop(+nMarkPixel);
+ }
+ else
+ {
+ pClipMarkCell->nClipMark |= ScClipMark::Bottom;
+ if (aAreaParam.maClipRect.Top() - nMarkPixel < aAreaParam.maClipRect.Bottom())
+ aAreaParam.maClipRect.AdjustBottom(-nMarkPixel);
+ }
+}
+
+ClearableClipRegionPtr ScOutputData::Clip( DrawEditParam& rParam, const Size& aCellSize,
+ OutputAreaParam& aAreaParam, tools::Long nEngineWidth,
+ bool bWrapFields, bool bTop)
+{
+ // Also take fields in a cell with automatic breaks into account: clip to cell width
+ bool bClip = AdjustAreaParamClipRect(aAreaParam) || aAreaParam.mbLeftClip || aAreaParam.mbRightClip || bWrapFields;
+ bool bSimClip = false;
+
+ const Size& aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
+ if ( nEngineWidth >= aCellSize.Width() + aRefOne.Width() )
+ {
+ const ScMergeAttr* pMerge = &rParam.mpPattern->GetItem(ATTR_MERGE);
+ const bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
+
+ // Don't clip for text height when printing rows with optimal height,
+ // except when font size is from conditional formatting.
+ //! Allow clipping when vertically merged?
+ if ( eType != OUTTYPE_PRINTER ||
+ ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CRFlags::ManualSize ) ||
+ ( rParam.mpCondSet && SfxItemState::SET ==
+ rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT) ) )
+ bClip = true;
+ else
+ bSimClip = true;
+
+ ShowClipMarks( rParam, nEngineWidth, aCellSize, bMerged, aAreaParam, bTop);
+ }
+
+ // Clip marks are already handled in GetOutputArea
+ return ClearableClipRegionPtr(new ClearableClipRegion(rParam.mbPixelToLogic ?
+ mpRefDevice->PixelToLogic(aAreaParam.maClipRect)
+ : aAreaParam.maClipRect, bClip, bSimClip, mpDev, bMetaFile));
+}
+
+void ScOutputData::DrawEditBottomTop(DrawEditParam& rParam)
+{
+ OSL_ASSERT(rParam.meHorJustAttr != SvxCellHorJustify::Repeat);
+
+ const bool bRepeat = (rParam.meHorJustAttr == SvxCellHorJustify::Repeat && !rParam.mbBreak);
+ const bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
+
+ SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
+
+ //! mirror margin values for RTL?
+ //! move margin down to after final GetOutputArea call
+ tools::Long nTopM, nLeftM, nBottomM, nRightM;
+ rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
+
+ SCCOL nXForPos = rParam.mnX;
+ if ( nXForPos < nX1 )
+ {
+ nXForPos = nX1;
+ rParam.mnPosX = rParam.mnInitPosX;
+ }
+ SCSIZE nArrYForPos = rParam.mnArrY;
+ if ( nArrYForPos < 1 )
+ {
+ nArrYForPos = 1;
+ rParam.mnPosY = nScrY;
+ }
+
+ OutputAreaParam aAreaParam;
+
+ // Initial page size - large for normal text, cell size for automatic line breaks
+
+ Size aPaperSize( 1000000, 1000000 );
+ if (rParam.mbBreak)
+ {
+ // call GetOutputArea with nNeeded=0, to get only the cell width
+
+ //! handle nArrY == 0
+ GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
+ *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ rParam.mbCellIsValue, true, false, aAreaParam );
+
+ //! special ScEditUtil handling if formatting for printer
+ rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
+ }
+ if (rParam.mbPixelToLogic)
+ {
+ Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
+ rParam.mpEngine->SetPaperSize(aLogicSize);
+ }
+ else
+ rParam.mpEngine->SetPaperSize(aPaperSize);
+
+ // Fill the EditEngine (cell attributes and text)
+
+ rParam.setPatternToEngine(mbUseStyleColor);
+ rParam.setAlignmentToEngine();
+
+ // Read content from cell
+
+ bool bWrapFields = false;
+ if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
+ // Failed to read cell content. Bail out.
+ return;
+
+ if ( mbSyntaxMode )
+ SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
+ else if ( mbUseStyleColor && mbForceAutoColor )
+ lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
+
+ rParam.mpEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
+
+ // Get final output area using the calculated width
+
+ tools::Long nEngineWidth, nEngineHeight;
+ rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
+
+ tools::Long nNeededPixel = nEngineWidth;
+ if (rParam.mbPixelToLogic)
+ nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
+ nNeededPixel += nLeftM + nRightM;
+
+ if (!rParam.mbBreak || bShrink)
+ {
+ // for break, the first GetOutputArea call is sufficient
+ GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
+ *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
+
+ if ( bShrink )
+ {
+ ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
+ nLeftM, nTopM, nRightM, nBottomM, false,
+ (rParam.meOrient), 0_deg100, rParam.mbPixelToLogic,
+ nEngineWidth, nEngineHeight, nNeededPixel,
+ aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
+ }
+ if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
+ {
+ // First check if twice the space for the formatted text is available
+ // (otherwise just keep it unchanged).
+
+ const tools::Long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
+ const tools::Long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
+ if ( nAvailable >= 2 * nFormatted )
+ {
+ // "repeat" is handled with unformatted text (for performance reasons)
+ OUString aCellStr = rParam.mpEngine->GetText();
+
+ tools::Long nRepeatSize = 0;
+ SetEngineTextAndGetWidth( rParam, aCellStr, nRepeatSize, 0 );
+ if ( pFmtDevice != mpRefDevice )
+ ++nRepeatSize;
+ if ( nRepeatSize > 0 )
+ {
+ const tools::Long nRepeatCount = nAvailable / nRepeatSize;
+ if ( nRepeatCount > 1 )
+ {
+ OUStringBuffer aRepeated(aCellStr);
+ for ( tools::Long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
+ aRepeated.append(aCellStr);
+
+ nEngineWidth = SetEngineTextAndGetWidth( rParam, aRepeated.makeStringAndClear(),
+ nNeededPixel, (nLeftM + nRightM ) );
+
+ nEngineHeight = rParam.mpEngine->GetTextHeight();
+ }
+ }
+ }
+ }
+ if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
+ {
+ nEngineWidth = SetEngineTextAndGetWidth( rParam, "###", nNeededPixel, ( nLeftM + nRightM ) );
+
+ // No clip marks if "###" doesn't fit (same as in DrawStrings)
+ }
+ }
+
+ tools::Long nStartX = aAreaParam.maAlignRect.Left();
+ const tools::Long nStartY = aAreaParam.maAlignRect.Top();
+ const tools::Long nCellWidth = aAreaParam.maAlignRect.GetWidth();
+ const tools::Long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
+ const tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
+
+ if (rParam.mbBreak)
+ {
+ // text with automatic breaks is aligned only within the
+ // edit engine's paper size, the output of the whole area
+ // is always left-aligned
+
+ nStartX += nLeftM;
+ }
+ else
+ {
+ if ( eOutHorJust == SvxCellHorJustify::Right )
+ nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
+ else if ( eOutHorJust == SvxCellHorJustify::Center )
+ nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
+ else
+ nStartX += nLeftM;
+ }
+
+ const bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
+ if (bOutside)
+ return;
+
+ // output area, excluding margins, in logical units
+ const Size& aCellSize = rParam.mbPixelToLogic
+ ? mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) )
+ : Size( nOutWidth, nOutHeight );
+
+ Point aURLStart;
+
+ {
+ const auto pClipRegion = Clip( rParam, aCellSize, aAreaParam, nEngineWidth, bWrapFields, true );
+
+ Point aLogicStart(nStartX, nStartY);
+ rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
+
+ aURLStart = aLogicStart; // copy before modifying for orientation
+
+ if (rParam.meHorJustResult == SvxCellHorJustify::Block || rParam.mbBreak)
+ {
+ Size aPSize = rParam.mpEngine->GetPaperSize();
+ aPSize.setWidth( aCellSize.Height() );
+ rParam.mpEngine->SetPaperSize(aPSize);
+ aLogicStart.AdjustY(
+ rParam.mbBreak ? aPSize.Width() : nEngineHeight );
+ }
+ else
+ {
+ // Note that the "paper" is rotated 90 degrees to the left, so
+ // paper's width is in vertical direction. Also, the whole text
+ // is on a single line, as text wrap is not in effect.
+
+ // Set the paper width to be the width of the text.
+ Size aPSize = rParam.mpEngine->GetPaperSize();
+ aPSize.setWidth( rParam.mpEngine->CalcTextWidth() );
+ rParam.mpEngine->SetPaperSize(aPSize);
+
+ tools::Long nGap = 0;
+ tools::Long nTopOffset = 0;
+ if (rParam.mbPixelToLogic)
+ {
+ nGap = mpRefDevice->LogicToPixel(aCellSize).Height() - mpRefDevice->LogicToPixel(aPSize).Width();
+ nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
+ nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
+ }
+ else
+ {
+ nGap = aCellSize.Height() - aPSize.Width();
+ nTopOffset = nTopM;
+ }
+
+ // First, align text to bottom.
+ aLogicStart.AdjustY(aCellSize.Height() );
+ aLogicStart.AdjustY(nTopOffset );
+
+ switch (rParam.meVerJust)
+ {
+ case SvxCellVerJustify::Standard:
+ case SvxCellVerJustify::Bottom:
+ // align to bottom (do nothing).
+ break;
+ case SvxCellVerJustify::Center:
+ // center it.
+ aLogicStart.AdjustY( -(nGap / 2) );
+ break;
+ case SvxCellVerJustify::Block:
+ case SvxCellVerJustify::Top:
+ // align to top
+ aLogicStart.AdjustY( -nGap );
+ break;
+ default:
+ ;
+ }
+ }
+
+ rParam.mpEngine->Draw(*mpDev, aLogicStart, 900_deg10);
+ }
+
+ rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
+}
+
+void ScOutputData::DrawEditTopBottom(DrawEditParam& rParam)
+{
+ OSL_ASSERT(rParam.meHorJustAttr != SvxCellHorJustify::Repeat);
+
+ const bool bRepeat = (rParam.meHorJustAttr == SvxCellHorJustify::Repeat && !rParam.mbBreak);
+ const bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
+
+ SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
+
+ //! mirror margin values for RTL?
+ //! move margin down to after final GetOutputArea call
+ tools::Long nTopM, nLeftM, nBottomM, nRightM;
+ rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
+
+ SCCOL nXForPos = rParam.mnX;
+ if ( nXForPos < nX1 )
+ {
+ nXForPos = nX1;
+ rParam.mnPosX = rParam.mnInitPosX;
+ }
+ SCSIZE nArrYForPos = rParam.mnArrY;
+ if ( nArrYForPos < 1 )
+ {
+ nArrYForPos = 1;
+ rParam.mnPosY = nScrY;
+ }
+
+ OutputAreaParam aAreaParam;
+
+ // Initial page size - large for normal text, cell size for automatic line breaks
+
+ Size aPaperSize( 1000000, 1000000 );
+ if (rParam.hasLineBreak())
+ {
+ // call GetOutputArea with nNeeded=0, to get only the cell width
+
+ //! handle nArrY == 0
+ GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
+ *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ rParam.mbCellIsValue, true, false, aAreaParam );
+
+ //! special ScEditUtil handling if formatting for printer
+ rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
+ }
+ if (rParam.mbPixelToLogic)
+ {
+ Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
+ rParam.mpEngine->SetPaperSize(aLogicSize);
+ }
+ else
+ rParam.mpEngine->SetPaperSize(aPaperSize);
+
+ // Fill the EditEngine (cell attributes and text)
+
+ rParam.setPatternToEngine(mbUseStyleColor);
+ rParam.setAlignmentToEngine();
+
+ // Read content from cell
+
+ bool bWrapFields = false;
+ if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
+ // Failed to read cell content. Bail out.
+ return;
+
+ if ( mbSyntaxMode )
+ SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
+ else if ( mbUseStyleColor && mbForceAutoColor )
+ lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
+
+ rParam.mpEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
+
+ // Get final output area using the calculated width
+
+ tools::Long nEngineWidth, nEngineHeight;
+ rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
+
+ tools::Long nNeededPixel = nEngineWidth;
+ if (rParam.mbPixelToLogic)
+ nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
+ nNeededPixel += nLeftM + nRightM;
+
+ if (!rParam.mbBreak || bShrink)
+ {
+ // for break, the first GetOutputArea call is sufficient
+ GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
+ *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
+
+ if ( bShrink )
+ {
+ ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
+ nLeftM, nTopM, nRightM, nBottomM, false,
+ rParam.meOrient, 0_deg100, rParam.mbPixelToLogic,
+ nEngineWidth, nEngineHeight, nNeededPixel,
+ aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
+ }
+ if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
+ {
+ // First check if twice the space for the formatted text is available
+ // (otherwise just keep it unchanged).
+
+ const tools::Long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
+ const tools::Long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
+ if ( nAvailable >= 2 * nFormatted )
+ {
+ // "repeat" is handled with unformatted text (for performance reasons)
+ OUString aCellStr = rParam.mpEngine->GetText();
+
+ tools::Long nRepeatSize = 0;
+ SetEngineTextAndGetWidth( rParam, aCellStr, nRepeatSize, 0 );
+
+ if ( pFmtDevice != mpRefDevice )
+ ++nRepeatSize;
+ if ( nRepeatSize > 0 )
+ {
+ const tools::Long nRepeatCount = nAvailable / nRepeatSize;
+ if ( nRepeatCount > 1 )
+ {
+ OUStringBuffer aRepeated(aCellStr);
+ for ( tools::Long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
+ aRepeated.append(aCellStr);
+
+ nEngineWidth = SetEngineTextAndGetWidth( rParam, aRepeated.makeStringAndClear(),
+ nNeededPixel, (nLeftM + nRightM ) );
+
+ nEngineHeight = rParam.mpEngine->GetTextHeight();
+ }
+ }
+ }
+ }
+ if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
+ {
+ nEngineWidth = SetEngineTextAndGetWidth( rParam, "###", nNeededPixel, ( nLeftM + nRightM ) );
+
+ // No clip marks if "###" doesn't fit (same as in DrawStrings)
+ }
+ }
+
+ tools::Long nStartX = aAreaParam.maAlignRect.Left();
+ const tools::Long nStartY = aAreaParam.maAlignRect.Top();
+ const tools::Long nCellWidth = aAreaParam.maAlignRect.GetWidth();
+ const tools::Long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
+ const tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
+
+ if (rParam.mbBreak)
+ {
+ // text with automatic breaks is aligned only within the
+ // edit engine's paper size, the output of the whole area
+ // is always left-aligned
+
+ nStartX += nLeftM;
+ if (rParam.meHorJustResult == SvxCellHorJustify::Block)
+ nStartX += aPaperSize.Height();
+ }
+ else
+ {
+ if ( eOutHorJust == SvxCellHorJustify::Right )
+ nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
+ else if ( eOutHorJust == SvxCellHorJustify::Center )
+ nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
+ else
+ nStartX += nLeftM;
+ }
+
+ const bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
+ if (bOutside)
+ return;
+
+ // output area, excluding margins, in logical units
+ const Size& aCellSize = rParam.mbPixelToLogic
+ ? mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) )
+ : Size( nOutWidth, nOutHeight );
+
+ Point aURLStart;
+
+ {
+ const auto pClipRegion = Clip( rParam, aCellSize, aAreaParam, nEngineWidth, bWrapFields, false );
+
+ Point aLogicStart(nStartX, nStartY);
+ rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
+
+ aURLStart = aLogicStart; // copy before modifying for orientation
+
+ if (rParam.meHorJustResult != SvxCellHorJustify::Block)
+ {
+ aLogicStart.AdjustX(nEngineWidth );
+ if (!rParam.mbBreak)
+ {
+ // Set the paper width to text size.
+ Size aPSize = rParam.mpEngine->GetPaperSize();
+ aPSize.setWidth( rParam.mpEngine->CalcTextWidth() );
+ rParam.mpEngine->SetPaperSize(aPSize);
+
+ tools::Long nGap = 0;
+ tools::Long nTopOffset = 0; // offset by top margin
+ if (rParam.mbPixelToLogic)
+ {
+ nGap = mpRefDevice->LogicToPixel(aPSize).Width() - mpRefDevice->LogicToPixel(aCellSize).Height();
+ nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
+ nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
+ }
+ else
+ {
+ nGap = aPSize.Width() - aCellSize.Height();
+ nTopOffset = nTopM;
+ }
+ aLogicStart.AdjustY(nTopOffset );
+
+ switch (rParam.meVerJust)
+ {
+ case SvxCellVerJustify::Standard:
+ case SvxCellVerJustify::Bottom:
+ // align to bottom
+ aLogicStart.AdjustY( -nGap );
+ break;
+ case SvxCellVerJustify::Center:
+ // center it.
+ aLogicStart.AdjustY( -(nGap / 2) );
+ break;
+ case SvxCellVerJustify::Block:
+ case SvxCellVerJustify::Top:
+ // align to top (do nothing)
+ default:
+ ;
+ }
+ }
+ }
+
+ // bMoveClipped handling has been replaced by complete alignment
+ // handling (also extending to the left).
+
+ rParam.mpEngine->Draw(*mpDev, aLogicStart, 2700_deg10);
+ }
+
+ rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
+}
+
+void ScOutputData::DrawEditStacked(DrawEditParam& rParam)
+{
+ OSL_ASSERT(rParam.meHorJustAttr != SvxCellHorJustify::Repeat);
+ Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
+
+ bool bRepeat = (rParam.meHorJustAttr == SvxCellHorJustify::Repeat && !rParam.mbBreak);
+ bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
+
+ rParam.mbAsianVertical =
+ lcl_GetBoolValue(*rParam.mpPattern, ATTR_VERTICAL_ASIAN, rParam.mpCondSet);
+
+ if ( rParam.mbAsianVertical )
+ {
+ // in asian mode, use EditEngine::SetVertical instead of EEControlBits::ONECHARPERLINE
+ rParam.meOrient = SvxCellOrientation::Standard;
+ DrawEditAsianVertical(rParam);
+ return;
+ }
+
+ SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
+
+ //! mirror margin values for RTL?
+ //! move margin down to after final GetOutputArea call
+ tools::Long nTopM, nLeftM, nBottomM, nRightM;
+ rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
+
+ SCCOL nXForPos = rParam.mnX;
+ if ( nXForPos < nX1 )
+ {
+ nXForPos = nX1;
+ rParam.mnPosX = rParam.mnInitPosX;
+ }
+ SCSIZE nArrYForPos = rParam.mnArrY;
+ if ( nArrYForPos < 1 )
+ {
+ nArrYForPos = 1;
+ rParam.mnPosY = nScrY;
+ }
+
+ OutputAreaParam aAreaParam;
+
+ // Initial page size - large for normal text, cell size for automatic line breaks
+
+ Size aPaperSize( 1000000, 1000000 );
+ // call GetOutputArea with nNeeded=0, to get only the cell width
+
+ //! handle nArrY == 0
+ GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
+ *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ rParam.mbCellIsValue, true, false, aAreaParam );
+
+ //! special ScEditUtil handling if formatting for printer
+ rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
+
+ if (rParam.mbPixelToLogic)
+ {
+ Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
+ if ( rParam.mbBreak && mpRefDevice != pFmtDevice )
+ {
+ // #i85342# screen display and formatting for printer,
+ // use same GetEditArea call as in ScViewData::SetEditEngine
+
+ Fraction aFract(1,1);
+ tools::Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
+ HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
+ aLogicSize.setWidth( aUtilRect.GetWidth() );
+ }
+ rParam.mpEngine->SetPaperSize(aLogicSize);
+ }
+ else
+ rParam.mpEngine->SetPaperSize(aPaperSize);
+
+ // Fill the EditEngine (cell attributes and text)
+
+ rParam.setPatternToEngine(mbUseStyleColor);
+ rParam.setAlignmentToEngine();
+
+ // Read content from cell
+
+ bool bWrapFields = false;
+ if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
+ // Failed to read cell content. Bail out.
+ return;
+
+ if ( mbSyntaxMode )
+ SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
+ else if ( mbUseStyleColor && mbForceAutoColor )
+ lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
+
+ rParam.mpEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
+
+ // Get final output area using the calculated width
+
+ tools::Long nEngineWidth, nEngineHeight;
+ rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
+
+ tools::Long nNeededPixel = nEngineWidth;
+ if (rParam.mbPixelToLogic)
+ nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
+ nNeededPixel += nLeftM + nRightM;
+
+ if (bShrink)
+ {
+ // for break, the first GetOutputArea call is sufficient
+ GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
+ *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ true, false, false, aAreaParam );
+
+ ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
+ nLeftM, nTopM, nRightM, nBottomM, true,
+ rParam.meOrient, 0_deg100, rParam.mbPixelToLogic,
+ nEngineWidth, nEngineHeight, nNeededPixel,
+ aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
+
+ if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
+ {
+ nEngineWidth = SetEngineTextAndGetWidth( rParam, "###", nNeededPixel, ( nLeftM + nRightM ) );
+
+ // No clip marks if "###" doesn't fit (same as in DrawStrings)
+ }
+
+ if ( eOutHorJust != SvxCellHorJustify::Left )
+ {
+ aPaperSize.setWidth( nNeededPixel + 1 );
+ if (rParam.mbPixelToLogic)
+ rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
+ else
+ rParam.mpEngine->SetPaperSize(aPaperSize);
+ }
+ }
+
+ tools::Long nStartX = aAreaParam.maAlignRect.Left();
+ tools::Long nStartY = aAreaParam.maAlignRect.Top();
+ tools::Long nCellWidth = aAreaParam.maAlignRect.GetWidth();
+ tools::Long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
+ tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
+
+ if (rParam.mbBreak)
+ {
+ // text with automatic breaks is aligned only within the
+ // edit engine's paper size, the output of the whole area
+ // is always left-aligned
+
+ nStartX += nLeftM;
+ }
+ else
+ {
+ if ( eOutHorJust == SvxCellHorJustify::Right )
+ nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
+ else if ( eOutHorJust == SvxCellHorJustify::Center )
+ nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
+ else
+ nStartX += nLeftM;
+ }
+
+ bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
+ if (bOutside)
+ return;
+
+ // Also take fields in a cell with automatic breaks into account: clip to cell width
+ bool bClip = AdjustAreaParamClipRect(aAreaParam) || aAreaParam.mbLeftClip || aAreaParam.mbRightClip || bWrapFields;
+ bool bSimClip = false;
+
+ Size aCellSize; // output area, excluding margins, in logical units
+ if (rParam.mbPixelToLogic)
+ aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
+ else
+ aCellSize = Size( nOutWidth, nOutHeight );
+
+ if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
+ {
+ const ScMergeAttr* pMerge = &rParam.mpPattern->GetItem(ATTR_MERGE);
+ bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
+
+ // Don't clip for text height when printing rows with optimal height,
+ // except when font size is from conditional formatting.
+ //! Allow clipping when vertically merged?
+ if ( eType != OUTTYPE_PRINTER ||
+ ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CRFlags::ManualSize ) ||
+ ( rParam.mpCondSet && SfxItemState::SET ==
+ rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT) ) )
+ bClip = true;
+ else
+ bSimClip = true;
+
+ // Show clip marks if height is at least 5pt too small and
+ // there are several lines of text.
+ // Not for asian vertical text, because that would interfere
+ // with the default right position of the text.
+ // Only with automatic line breaks, to avoid having to find
+ // the cells with the horizontal end of the text again.
+ if ( nEngineHeight - aCellSize.Height() > 100 &&
+ rParam.mbBreak && bMarkClipped &&
+ ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
+ {
+ ScCellInfo* pClipMarkCell = nullptr;
+ if ( bMerged )
+ {
+ // anywhere in the merged area...
+ SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
+ pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].cellInfo(nClipX);
+ }
+ else
+ pClipMarkCell = &rParam.mpThisRowInfo->cellInfo(rParam.mnX);
+
+ pClipMarkCell->nClipMark |= ScClipMark::Right; //! also allow left?
+ bAnyClipped = true;
+
+ tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
+ if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
+ aAreaParam.maClipRect.AdjustRight( -nMarkPixel );
+ }
+ }
+
+ Point aURLStart;
+
+ { // Clip marks are already handled in GetOutputArea
+ ClearableClipRegion aClip(rParam.mbPixelToLogic ? mpRefDevice->PixelToLogic(aAreaParam.maClipRect)
+ : aAreaParam.maClipRect, bClip, bSimClip, mpDev, bMetaFile);
+
+ Point aLogicStart;
+ if (rParam.mbPixelToLogic)
+ aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
+ else
+ aLogicStart = Point(nStartX, nStartY);
+
+ if (rParam.meVerJust==SvxCellVerJustify::Bottom ||
+ rParam.meVerJust==SvxCellVerJustify::Standard)
+ {
+ //! if pRefDevice != pFmtDevice, keep heights in logic units,
+ //! only converting margin?
+
+ if (rParam.mbPixelToLogic)
+ aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0, nTopM +
+ mpRefDevice->LogicToPixel(aCellSize).Height() -
+ mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
+ )).Height() );
+ else
+ aLogicStart.AdjustY(nTopM + aCellSize.Height() - nEngineHeight );
+ }
+ else if (rParam.meVerJust==SvxCellVerJustify::Center)
+ {
+ if (rParam.mbPixelToLogic)
+ aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0, nTopM + (
+ mpRefDevice->LogicToPixel(aCellSize).Height() -
+ mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
+ / 2)).Height() );
+ else
+ aLogicStart.AdjustY(nTopM + (aCellSize.Height() - nEngineHeight) / 2 );
+ }
+ else // top
+ {
+ if (rParam.mbPixelToLogic)
+ aLogicStart.AdjustY(mpRefDevice->PixelToLogic(Size(0,nTopM)).Height() );
+ else
+ aLogicStart.AdjustY(nTopM );
+ }
+
+ aURLStart = aLogicStart; // copy before modifying for orientation
+
+ Size aPaperLogic = rParam.mpEngine->GetPaperSize();
+ aPaperLogic.setWidth( nEngineWidth );
+ rParam.mpEngine->SetPaperSize(aPaperLogic);
+
+ // bMoveClipped handling has been replaced by complete alignment
+ // handling (also extending to the left).
+
+ if (bSimClip)
+ {
+ // no hard clip, only draw the affected rows
+ Point aDocStart = aClip.getRect().TopLeft();
+ aDocStart -= aLogicStart;
+ rParam.mpEngine->Draw(*mpDev, aClip.getRect(), aDocStart, false);
+ }
+ else
+ {
+ rParam.mpEngine->Draw(*mpDev, aLogicStart);
+ }
+ }
+
+ rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
+}
+
+void ScOutputData::DrawEditAsianVertical(DrawEditParam& rParam)
+{
+ // When in asian vertical orientation, the orientation value is STANDARD,
+ // and the asian vertical boolean is true.
+ OSL_ASSERT(rParam.meOrient == SvxCellOrientation::Standard);
+ OSL_ASSERT(rParam.mbAsianVertical);
+ OSL_ASSERT(rParam.meHorJustAttr != SvxCellHorJustify::Repeat);
+
+ Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
+
+ bool bHidden = false;
+ bool bShrink = !rParam.mbBreak && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
+ Degree100 nAttrRotate = lcl_GetValue<ScRotateValueItem, Degree100>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
+
+ if (nAttrRotate)
+ {
+ //! set flag to find the cell in DrawRotated again ?
+ //! (or flag already set during DrawBackground, then no query here)
+ bHidden = true; // rotated is outputted separately
+ }
+
+ // default alignment for asian vertical mode is top-right
+ /* TODO: is setting meHorJustContext and meHorJustResult unconditionally to
+ * SvxCellHorJustify::Right really wanted? Seems this was done all the time,
+ * also before context was introduced and everything was attr only. */
+ if ( rParam.meHorJustAttr == SvxCellHorJustify::Standard )
+ rParam.meHorJustResult = rParam.meHorJustContext = SvxCellHorJustify::Right;
+
+ if (bHidden)
+ return;
+
+ SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
+
+ //! mirror margin values for RTL?
+ //! move margin down to after final GetOutputArea call
+ tools::Long nTopM, nLeftM, nBottomM, nRightM;
+ rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
+
+ SCCOL nXForPos = rParam.mnX;
+ if ( nXForPos < nX1 )
+ {
+ nXForPos = nX1;
+ rParam.mnPosX = rParam.mnInitPosX;
+ }
+ SCSIZE nArrYForPos = rParam.mnArrY;
+ if ( nArrYForPos < 1 )
+ {
+ nArrYForPos = 1;
+ rParam.mnPosY = nScrY;
+ }
+
+ OutputAreaParam aAreaParam;
+
+ // Initial page size - large for normal text, cell size for automatic line breaks
+
+ Size aPaperSize( 1000000, 1000000 );
+ // call GetOutputArea with nNeeded=0, to get only the cell width
+
+ //! handle nArrY == 0
+ GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
+ *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ rParam.mbCellIsValue, true, false, aAreaParam );
+
+ //! special ScEditUtil handling if formatting for printer
+ rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
+
+ if (rParam.mbPixelToLogic)
+ {
+ Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
+ if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
+ {
+ // #i85342# screen display and formatting for printer,
+ // use same GetEditArea call as in ScViewData::SetEditEngine
+
+ Fraction aFract(1,1);
+ tools::Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
+ HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
+ aLogicSize.setWidth( aUtilRect.GetWidth() );
+ }
+ rParam.mpEngine->SetPaperSize(aLogicSize);
+ }
+ else
+ rParam.mpEngine->SetPaperSize(aPaperSize);
+
+ // Fill the EditEngine (cell attributes and text)
+
+ // default alignment for asian vertical mode is top-right
+ if ( rParam.meVerJust == SvxCellVerJustify::Standard )
+ rParam.meVerJust = SvxCellVerJustify::Top;
+
+ rParam.setPatternToEngine(mbUseStyleColor);
+ rParam.setAlignmentToEngine();
+
+ // Read content from cell
+
+ bool bWrapFields = false;
+ if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
+ // Failed to read cell content. Bail out.
+ return;
+
+ if ( mbSyntaxMode )
+ SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
+ else if ( mbUseStyleColor && mbForceAutoColor )
+ lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
+
+ rParam.mpEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
+
+ // Get final output area using the calculated width
+
+ tools::Long nEngineWidth, nEngineHeight;
+ rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
+
+ tools::Long nNeededPixel = nEngineWidth;
+ if (rParam.mbPixelToLogic)
+ nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
+ nNeededPixel += nLeftM + nRightM;
+
+ // for break, the first GetOutputArea call is sufficient
+ GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
+ *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ rParam.mbCellIsValue || bShrink, false, false, aAreaParam );
+
+ if ( bShrink )
+ {
+ ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
+ nLeftM, nTopM, nRightM, nBottomM, false,
+ rParam.meOrient, 0_deg100, rParam.mbPixelToLogic,
+ nEngineWidth, nEngineHeight, nNeededPixel,
+ aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
+ }
+ if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
+ {
+ nEngineWidth = SetEngineTextAndGetWidth( rParam, "###", nNeededPixel, ( nLeftM + nRightM ) );
+
+ // No clip marks if "###" doesn't fit (same as in DrawStrings)
+ }
+
+ if (eOutHorJust != SvxCellHorJustify::Left)
+ {
+ aPaperSize.setWidth( nNeededPixel + 1 );
+ if (rParam.mbPixelToLogic)
+ rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
+ else
+ rParam.mpEngine->SetPaperSize(aPaperSize);
+ }
+
+ tools::Long nStartX = aAreaParam.maAlignRect.Left();
+ tools::Long nStartY = aAreaParam.maAlignRect.Top();
+ tools::Long nCellWidth = aAreaParam.maAlignRect.GetWidth();
+ tools::Long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
+ tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
+
+ // text with automatic breaks is aligned only within the
+ // edit engine's paper size, the output of the whole area
+ // is always left-aligned
+
+ nStartX += nLeftM;
+
+ bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
+ if (bOutside)
+ return;
+
+ // Also take fields in a cell with automatic breaks into account: clip to cell width
+ bool bClip = AdjustAreaParamClipRect(aAreaParam) || aAreaParam.mbLeftClip || aAreaParam.mbRightClip || bWrapFields;
+ bool bSimClip = false;
+
+ Size aCellSize; // output area, excluding margins, in logical units
+ if (rParam.mbPixelToLogic)
+ aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
+ else
+ aCellSize = Size( nOutWidth, nOutHeight );
+
+ if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
+ {
+ const ScMergeAttr* pMerge = &rParam.mpPattern->GetItem(ATTR_MERGE);
+ bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
+
+ // Don't clip for text height when printing rows with optimal height,
+ // except when font size is from conditional formatting.
+ //! Allow clipping when vertically merged?
+ if ( eType != OUTTYPE_PRINTER ||
+ ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CRFlags::ManualSize ) ||
+ ( rParam.mpCondSet && SfxItemState::SET ==
+ rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT) ) )
+ bClip = true;
+ else
+ bSimClip = true;
+
+ // Show clip marks if height is at least 5pt too small and
+ // there are several lines of text.
+ // Not for asian vertical text, because that would interfere
+ // with the default right position of the text.
+ // Only with automatic line breaks, to avoid having to find
+ // the cells with the horizontal end of the text again.
+ if ( nEngineHeight - aCellSize.Height() > 100 &&
+ ( rParam.mbBreak || rParam.meOrient == SvxCellOrientation::Stacked ) &&
+ !rParam.mbAsianVertical && bMarkClipped &&
+ ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
+ {
+ ScCellInfo* pClipMarkCell = nullptr;
+ if ( bMerged )
+ {
+ // anywhere in the merged area...
+ SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
+ pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].cellInfo(nClipX);
+ }
+ else
+ pClipMarkCell = &rParam.mpThisRowInfo->cellInfo(rParam.mnX);
+
+ pClipMarkCell->nClipMark |= ScClipMark::Right; //! also allow left?
+ bAnyClipped = true;
+
+ tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
+ if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
+ aAreaParam.maClipRect.AdjustRight( -nMarkPixel );
+ }
+ }
+
+ Point aURLStart;
+
+ { // Clip marks are already handled in GetOutputArea
+ ClearableClipRegion aClip(rParam.mbPixelToLogic ? mpRefDevice->PixelToLogic(aAreaParam.maClipRect)
+ : aAreaParam.maClipRect, bClip, bSimClip, mpDev, bMetaFile);
+
+ Point aLogicStart;
+ if (rParam.mbPixelToLogic)
+ aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
+ else
+ aLogicStart = Point(nStartX, nStartY);
+
+ tools::Long nAvailWidth = aCellSize.Width();
+ // space for AutoFilter is already handled in GetOutputArea
+
+ // horizontal alignment
+
+ if (rParam.meHorJustResult==SvxCellHorJustify::Right)
+ aLogicStart.AdjustX(nAvailWidth - nEngineWidth );
+ else if (rParam.meHorJustResult==SvxCellHorJustify::Center)
+ aLogicStart.AdjustX((nAvailWidth - nEngineWidth) / 2 );
+
+ // paper size is subtracted below
+ aLogicStart.AdjustX(nEngineWidth );
+
+ // vertical adjustment is within the EditEngine
+ if (rParam.mbPixelToLogic)
+ aLogicStart.AdjustY(mpRefDevice->PixelToLogic(Size(0,nTopM)).Height() );
+ else
+ aLogicStart.AdjustY(nTopM );
+
+ aURLStart = aLogicStart; // copy before modifying for orientation
+
+ // bMoveClipped handling has been replaced by complete alignment
+ // handling (also extending to the left).
+
+ // with SetVertical, the start position is top left of
+ // the whole output area, not the text itself
+ aLogicStart.AdjustX( -(rParam.mpEngine->GetPaperSize().Width()) );
+
+ rParam.mpEngine->Draw(*mpDev, aLogicStart);
+ }
+
+ rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
+}
+
+void ScOutputData::DrawEdit(bool bPixelToLogic)
+{
+ std::unique_ptr<ScFieldEditEngine> pEngine;
+ bool bHyphenatorSet = false;
+ const ScPatternAttr* pOldPattern = nullptr;
+ const SfxItemSet* pOldCondSet = nullptr;
+ const SfxItemSet* pOldPreviewFontSet = nullptr;
+ ScRefCellValue aCell;
+
+ tools::Long nInitPosX = nScrX;
+ if ( bLayoutRTL )
+ {
+ nInitPosX += nMirrorW - 1;
+ }
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ //! store nLastContentCol as member!
+ SCCOL nLastContentCol = mpDoc->MaxCol();
+ if ( nX2 < mpDoc->MaxCol() )
+ nLastContentCol = sal::static_int_cast<SCCOL>(
+ nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, mpDoc->MaxCol(), nY2, nTab, DIR_RIGHT ) );
+
+ tools::Long nRowPosY = nScrY;
+ for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 of the rest of the merged
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+
+ if (nArrY==1) nRowPosY = nScrY; // positions before are calculated individually
+
+ if ( pThisRowInfo->bChanged || nArrY==0 )
+ {
+ tools::Long nPosX = 0;
+ for (SCCOL nX=0; nX<=nX2; nX++) // due to overflow
+ {
+ std::unique_ptr< ScPatternAttr > pPreviewPattr;
+ if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
+
+ if (pThisRowInfo->basicCellInfo(nX).bEditEngine)
+ {
+ SCROW nY = pThisRowInfo->nRowNo;
+
+ SCCOL nCellX = nX; // position where the cell really starts
+ SCROW nCellY = nY;
+ bool bDoCell = false;
+
+ tools::Long nPosY = nRowPosY;
+ if ( nArrY == 0 )
+ {
+ nPosY = nScrY;
+ nY = pRowInfo[1].nRowNo;
+ SCCOL nOverX; // start of the merged cells
+ SCROW nOverY;
+ if (GetMergeOrigin( nX,nY, 1, nOverX,nOverY, true ))
+ {
+ nCellX = nOverX;
+ nCellY = nOverY;
+ bDoCell = true;
+ }
+ }
+ else if ( nX == nX2 && pThisRowInfo->cellInfo(nX).maCell.isEmpty() )
+ {
+ // Rest of a long text further to the right?
+
+ SCCOL nTempX=nX;
+ while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
+ ++nTempX;
+
+ if ( nTempX > nX &&
+ !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
+ !mpDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
+ {
+ nCellX = nTempX;
+ bDoCell = true;
+ }
+ }
+ else
+ {
+ bDoCell = true;
+ }
+
+ if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
+ bDoCell = false;
+
+ const ScPatternAttr* pPattern = nullptr;
+ const SfxItemSet* pCondSet = nullptr;
+ if (bDoCell)
+ {
+ if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 &&
+ !mpDoc->ColHidden(nCellX, nTab) )
+ {
+ ScCellInfo& rCellInfo = pThisRowInfo->cellInfo(nCellX);
+ pPattern = rCellInfo.pPatternAttr;
+ pCondSet = rCellInfo.pConditionSet;
+ aCell = rCellInfo.maCell;
+ }
+ else // get from document
+ {
+ pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
+ pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
+ GetVisibleCell( nCellX, nCellY, nTab, aCell );
+ }
+ if (aCell.isEmpty())
+ bDoCell = false;
+ }
+ if (bDoCell)
+ {
+ if ( mpDoc->GetPreviewCellStyle() )
+ {
+ if ( ScStyleSheet* pPreviewStyle = mpDoc->GetPreviewCellStyle( nCellX, nCellY, nTab ) )
+ {
+ pPreviewPattr.reset( new ScPatternAttr(*pPattern) );
+ pPreviewPattr->SetStyleSheet(pPreviewStyle);
+ pPattern = pPreviewPattr.get();
+ }
+ }
+ SfxItemSet* pPreviewFontSet = mpDoc->GetPreviewFont( nCellX, nCellY, nTab );
+ if (!pEngine)
+ pEngine = CreateOutputEditEngine();
+ else
+ lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
+
+ // fdo#32530: Check if the first character is RTL.
+ OUString aStr = mpDoc->GetString(nCellX, nCellY, nTab);
+
+ DrawEditParam aParam(pPattern, pCondSet, lcl_SafeIsValue(aCell));
+ const bool bNumberFormatIsText = lcl_isNumberFormatText( mpDoc, nCellX, nCellY, nTab );
+ aParam.meHorJustContext = getAlignmentFromContext( aParam.meHorJustAttr,
+ aParam.mbCellIsValue, aStr, *pPattern, pCondSet, mpDoc, nTab, bNumberFormatIsText);
+ aParam.meHorJustResult = (aParam.meHorJustAttr == SvxCellHorJustify::Block) ?
+ SvxCellHorJustify::Block : aParam.meHorJustContext;
+ aParam.mbPixelToLogic = bPixelToLogic;
+ aParam.mbHyphenatorSet = bHyphenatorSet;
+ aParam.mpEngine = pEngine.get();
+ aParam.maCell = aCell;
+ aParam.mnArrY = nArrY;
+ aParam.mnX = nX;
+ aParam.mnCellX = nCellX;
+ aParam.mnCellY = nCellY;
+ aParam.mnPosX = nPosX;
+ aParam.mnPosY = nPosY;
+ aParam.mnInitPosX = nInitPosX;
+ aParam.mpPreviewFontSet = pPreviewFontSet;
+ aParam.mpOldPattern = pOldPattern;
+ aParam.mpOldCondSet = pOldCondSet;
+ aParam.mpOldPreviewFontSet = pOldPreviewFontSet;
+ aParam.mpThisRowInfo = pThisRowInfo;
+ if (mpSpellCheckCxt)
+ aParam.mpMisspellRanges = mpSpellCheckCxt->getMisspellRanges(nCellX, nCellY);
+
+ if (aParam.meHorJustAttr == SvxCellHorJustify::Repeat)
+ {
+ // ignore orientation/rotation if "repeat" is active
+ aParam.meOrient = SvxCellOrientation::Standard;
+ }
+ switch (aParam.meOrient)
+ {
+ case SvxCellOrientation::BottomUp:
+ DrawEditBottomTop(aParam);
+ break;
+ case SvxCellOrientation::TopBottom:
+ DrawEditTopBottom(aParam);
+ break;
+ case SvxCellOrientation::Stacked:
+ // this can be vertically stacked or asian vertical.
+ DrawEditStacked(aParam);
+ break;
+ default:
+ DrawEditStandard(aParam);
+ }
+
+ // Retrieve parameters for next iteration.
+ pOldPattern = aParam.mpOldPattern;
+ pOldCondSet = aParam.mpOldCondSet;
+ pOldPreviewFontSet = aParam.mpOldPreviewFontSet;
+ bHyphenatorSet = aParam.mbHyphenatorSet;
+ }
+ }
+ nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
+ }
+ }
+ nRowPosY += pRowInfo[nArrY].nHeight;
+ }
+
+ pEngine.reset();
+
+ if (mrTabInfo.maArray.HasCellRotation())
+ {
+ DrawRotated(bPixelToLogic); //! call from outside ?
+ }
+}
+
+void ScOutputData::DrawRotated(bool bPixelToLogic)
+{
+ //! store nRotMax
+ SCCOL nRotMax = nX2;
+ for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
+ if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
+ nRotMax = pRowInfo[nRotY].nRotMaxCol;
+
+ ScModule* pScMod = SC_MOD();
+ Color nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+ bool bCellContrast = mbUseStyleColor &&
+ Application::GetSettings().GetStyleSettings().GetHighContrastMode();
+
+ std::unique_ptr<ScFieldEditEngine> pEngine;
+ bool bHyphenatorSet = false;
+ const ScPatternAttr* pPattern;
+ const SfxItemSet* pCondSet;
+ const ScPatternAttr* pOldPattern = nullptr;
+ const SfxItemSet* pOldCondSet = nullptr;
+ ScRefCellValue aCell;
+
+ tools::Long nInitPosX = nScrX;
+ if ( bLayoutRTL )
+ {
+ nInitPosX += nMirrorW - 1;
+ }
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ tools::Long nRowPosY = nScrY;
+ for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 for the rest of the merged
+ {
+ RowInfo* pThisRowInfo = &pRowInfo[nArrY];
+ tools::Long nCellHeight = static_cast<tools::Long>(pThisRowInfo->nHeight);
+ if (nArrY==1) nRowPosY = nScrY; // positions before are calculated individually
+
+ if ( ( pThisRowInfo->bChanged || nArrY==0 ) && pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE )
+ {
+ tools::Long nPosX = 0;
+ for (SCCOL nX=0; nX<=nRotMax; nX++)
+ {
+ if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
+
+ const ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
+ if ( pInfo->nRotateDir != ScRotateDir::NONE )
+ {
+ SCROW nY = pThisRowInfo->nRowNo;
+
+ bool bHidden = false;
+ if (bEditMode)
+ if ( nX == nEditCol && nY == nEditRow )
+ bHidden = true;
+
+ if (!bHidden)
+ {
+ if (!pEngine)
+ pEngine = CreateOutputEditEngine();
+ else
+ lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
+
+ tools::Long nPosY = nRowPosY;
+
+ //! rest from merged cells further up do not work!
+
+ bool bFromDoc = false;
+ pPattern = pInfo->pPatternAttr;
+ pCondSet = pInfo->pConditionSet;
+ if (!pPattern)
+ {
+ pPattern = mpDoc->GetPattern( nX, nY, nTab );
+ bFromDoc = true;
+ }
+ aCell = pInfo->maCell;
+ if (bFromDoc)
+ pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
+
+ if (aCell.isEmpty() && nX>nX2)
+ GetVisibleCell( nX, nY, nTab, aCell );
+
+ if (aCell.isEmpty() || IsEmptyCellText(pThisRowInfo, nX, nY))
+ bHidden = true; // nRotateDir is also set without a cell
+
+ tools::Long nCellWidth = static_cast<tools::Long>(pRowInfo[0].basicCellInfo(nX).nWidth);
+
+ SvxCellHorJustify eHorJust =
+ pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet).GetValue();
+ bool bBreak = ( eHorJust == SvxCellHorJustify::Block ) ||
+ pPattern->GetItem(ATTR_LINEBREAK, pCondSet).GetValue();
+ bool bRepeat = ( eHorJust == SvxCellHorJustify::Repeat && !bBreak );
+ bool bShrink = !bBreak && !bRepeat &&
+ pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet ).GetValue();
+ SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
+
+ const ScMergeAttr* pMerge = &pPattern->GetItem(ATTR_MERGE);
+ bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
+
+ tools::Long nStartX = nPosX;
+ tools::Long nStartY = nPosY;
+ if (nX<nX1)
+ {
+ if ((bBreak || eOrient!=SvxCellOrientation::Standard) && !bMerged)
+ bHidden = true;
+ else
+ {
+ nStartX = nInitPosX;
+ SCCOL nCol = nX1;
+ while (nCol > nX)
+ {
+ --nCol;
+ nStartX -= nLayoutSign * static_cast<tools::Long>(pRowInfo[0].basicCellInfo(nCol).nWidth);
+ }
+ }
+ }
+ tools::Long nCellStartX = nStartX;
+
+ // omit substitute representation of small text
+
+ if (!bHidden)
+ {
+ tools::Long nOutWidth = nCellWidth - 1;
+ tools::Long nOutHeight = nCellHeight;
+
+ if ( bMerged )
+ {
+ SCCOL nCountX = pMerge->GetColMerge();
+ for (SCCOL i=1; i<nCountX; i++)
+ nOutWidth += mpDoc->GetColWidth(nX+i,nTab) * mnPPTX;
+ SCROW nCountY = pMerge->GetRowMerge();
+ nOutHeight += mpDoc->GetScaledRowHeight( nY+1, nY+nCountY-1, nTab, mnPPTY);
+ }
+
+ SvxCellVerJustify eVerJust =
+ pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet).GetValue();
+
+ // syntax mode is ignored here...
+
+ // StringDiffer doesn't look at hyphenate, language items
+ if ( pPattern != pOldPattern || pCondSet != pOldCondSet )
+ {
+ auto pSet = std::make_unique<SfxItemSet>( pEngine->GetEmptyItemSet() );
+ pPattern->FillEditItemSet( pSet.get(), pCondSet );
+
+ // adjustment for EditEngine
+ SvxAdjust eSvxAdjust = SvxAdjust::Left;
+ if (eOrient==SvxCellOrientation::Stacked)
+ eSvxAdjust = SvxAdjust::Center;
+ // adjustment for bBreak is omitted here
+ pSet->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
+
+ bool bParaHyphenate = pSet->Get(EE_PARA_HYPHENATE).GetValue();
+ pEngine->SetDefaults( std::move(pSet) );
+ pOldPattern = pPattern;
+ pOldCondSet = pCondSet;
+
+ EEControlBits nControl = pEngine->GetControlWord();
+ if (eOrient==SvxCellOrientation::Stacked)
+ nControl |= EEControlBits::ONECHARPERLINE;
+ else
+ nControl &= ~EEControlBits::ONECHARPERLINE;
+ pEngine->SetControlWord( nControl );
+
+ if ( !bHyphenatorSet && bParaHyphenate )
+ {
+ // set hyphenator the first time it is needed
+ css::uno::Reference<css::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
+ pEngine->SetHyphenator( xXHyphenator );
+ bHyphenatorSet = true;
+ }
+
+ Color aBackCol =
+ pPattern->GetItem( ATTR_BACKGROUND, pCondSet ).GetColor();
+ if ( mbUseStyleColor && ( aBackCol.IsTransparent() || bCellContrast ) )
+ aBackCol = nConfBackColor;
+ pEngine->SetBackgroundColor( aBackCol );
+ }
+
+ // margins
+
+ //! change position and paper size to EditUtil !!!
+
+ const SvxMarginItem* pMargin =
+ &pPattern->GetItem(ATTR_MARGIN, pCondSet);
+ sal_uInt16 nIndent = 0;
+ if ( eHorJust == SvxCellHorJustify::Left )
+ nIndent = pPattern->GetItem(ATTR_INDENT, pCondSet).GetValue();
+
+ tools::Long nTotalHeight = nOutHeight; // without subtracting the margin
+ if ( bPixelToLogic )
+ nTotalHeight = mpRefDevice->PixelToLogic(Size(0,nTotalHeight)).Height();
+
+ tools::Long nLeftM = static_cast<tools::Long>( (pMargin->GetLeftMargin() + nIndent) * mnPPTX );
+ tools::Long nTopM = static_cast<tools::Long>( pMargin->GetTopMargin() * mnPPTY );
+ tools::Long nRightM = static_cast<tools::Long>( pMargin->GetRightMargin() * mnPPTX );
+ tools::Long nBottomM = static_cast<tools::Long>( pMargin->GetBottomMargin() * mnPPTY );
+ nStartX += nLeftM;
+ nStartY += nTopM;
+ nOutWidth -= nLeftM + nRightM;
+ nOutHeight -= nTopM + nBottomM;
+
+ // rotate here already, to adjust paper size for page breaks
+ Degree100 nAttrRotate;
+ double nSin = 0.0;
+ double nCos = 1.0;
+ SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
+ if ( eOrient == SvxCellOrientation::Standard )
+ {
+ nAttrRotate = pPattern->
+ GetItem(ATTR_ROTATE_VALUE, pCondSet).GetValue();
+ if ( nAttrRotate )
+ {
+ eRotMode = pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue();
+
+ if ( nAttrRotate == 18000_deg100 )
+ eRotMode = SVX_ROTATE_MODE_STANDARD; // no overflow
+
+ if ( bLayoutRTL )
+ nAttrRotate = -nAttrRotate;
+
+ double nRealOrient = toRadians(nAttrRotate); // 1/100 degree
+ nCos = cos( nRealOrient );
+ nSin = sin( nRealOrient );
+ }
+ }
+
+ Size aPaperSize( 1000000, 1000000 );
+ if (eOrient==SvxCellOrientation::Stacked)
+ aPaperSize.setWidth( nOutWidth ); // to center
+ else if (bBreak)
+ {
+ if (nAttrRotate)
+ {
+ //! the correct paper size for break depends on the number
+ //! of rows, as long as the rows can not be outputted individually
+ //! offsetted -> therefore unlimited, so no wrapping.
+ //! With offset rows the following would be correct:
+ aPaperSize.setWidth( static_cast<tools::Long>(nOutHeight / fabs(nSin)) );
+ }
+ else if (eOrient == SvxCellOrientation::Standard)
+ aPaperSize.setWidth( nOutWidth );
+ else
+ aPaperSize.setWidth( nOutHeight - 1 );
+ }
+ if (bPixelToLogic)
+ pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
+ else
+ pEngine->SetPaperSize(aPaperSize); // scale is always 1
+
+ // read data from cell
+
+ if (aCell.meType == CELLTYPE_EDIT)
+ {
+ if (aCell.mpEditText)
+ pEngine->SetTextCurrentDefaults(*aCell.mpEditText);
+ else
+ {
+ OSL_FAIL("pData == 0");
+ }
+ }
+ else
+ {
+ sal_uInt32 nFormat = pPattern->GetNumberFormat(
+ mpDoc->GetFormatTable(), pCondSet );
+ const Color* pColor;
+ OUString aString = ScCellFormat::GetString( aCell,
+ nFormat, &pColor,
+ *mpDoc->GetFormatTable(),
+ *mpDoc,
+ mbShowNullValues,
+ mbShowFormulas);
+
+ pEngine->SetTextCurrentDefaults(aString);
+ if ( pColor && !mbSyntaxMode && !( mbUseStyleColor && mbForceAutoColor ) )
+ lcl_SetEditColor( *pEngine, *pColor );
+ }
+
+ if ( mbSyntaxMode )
+ {
+ SetEditSyntaxColor(*pEngine, aCell);
+ }
+ else if ( mbUseStyleColor && mbForceAutoColor )
+ lcl_SetEditColor( *pEngine, COL_AUTO ); //! or have a flag at EditEngine
+
+ pEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
+
+ tools::Long nEngineWidth = static_cast<tools::Long>(pEngine->CalcTextWidth());
+ tools::Long nEngineHeight = pEngine->GetTextHeight();
+
+ if (nAttrRotate && bBreak)
+ {
+ double nAbsCos = fabs( nCos );
+ double nAbsSin = fabs( nSin );
+
+ // adjust width of papersize for height of text
+ int nSteps = 5;
+ while (nSteps > 0)
+ {
+ // everything is in pixels
+ tools::Long nEnginePixel = mpRefDevice->LogicToPixel(
+ Size(0,nEngineHeight)).Height();
+ tools::Long nEffHeight = nOutHeight - static_cast<tools::Long>(nEnginePixel * nAbsCos) + 2;
+ tools::Long nNewWidth = static_cast<tools::Long>(nEffHeight / nAbsSin) + 2;
+ bool bFits = ( nNewWidth >= aPaperSize.Width() );
+ if ( bFits )
+ nSteps = 0;
+ else
+ {
+ if ( nNewWidth < 4 )
+ {
+ // can't fit -> fall back to using half height
+ nEffHeight = nOutHeight / 2;
+ nNewWidth = static_cast<tools::Long>(nEffHeight / nAbsSin) + 2;
+ nSteps = 0;
+ }
+ else
+ --nSteps;
+
+ // set paper width and get new text height
+ aPaperSize.setWidth( nNewWidth );
+ if (bPixelToLogic)
+ pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
+ else
+ pEngine->SetPaperSize(aPaperSize); // Scale is always 1
+ //pEngine->QuickFormatDoc( sal_True );
+
+ nEngineWidth = static_cast<tools::Long>(pEngine->CalcTextWidth());
+ nEngineHeight = pEngine->GetTextHeight();
+ }
+ }
+ }
+
+ tools::Long nRealWidth = nEngineWidth;
+ tools::Long nRealHeight = nEngineHeight;
+
+ // when rotated, adjust size
+ if (nAttrRotate)
+ {
+ double nAbsCos = fabs( nCos );
+ double nAbsSin = fabs( nSin );
+
+ if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
+ nEngineWidth = static_cast<tools::Long>( nRealWidth * nAbsCos +
+ nRealHeight * nAbsSin );
+ else
+ nEngineWidth = static_cast<tools::Long>( nRealHeight / nAbsSin );
+ //! limit !!!
+
+ nEngineHeight = static_cast<tools::Long>( nRealHeight * nAbsCos +
+ nRealWidth * nAbsSin );
+ }
+
+ if (!nAttrRotate) // only rotated text here
+ bHidden = true; //! check first !!!
+
+ //! omit which doesn't stick out
+
+ if (!bHidden)
+ {
+ Size aClipSize( nScrX+nScrW-nStartX, nScrY+nScrH-nStartY );
+
+ // go on writing
+
+ Size aCellSize;
+ if (bPixelToLogic)
+ aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
+ else
+ aCellSize = Size( nOutWidth, nOutHeight ); // scale is one
+
+ tools::Long nGridWidth = nEngineWidth;
+ bool bNegative = false;
+ if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
+ {
+ nGridWidth = aCellSize.Width() +
+ std::abs(static_cast<tools::Long>( aCellSize.Height() * nCos / nSin ));
+ bNegative = ( pInfo->nRotateDir == ScRotateDir::Left );
+ if ( bLayoutRTL )
+ bNegative = !bNegative;
+ }
+
+ // use GetOutputArea to hide the grid
+ // (clip region is done manually below)
+ OutputAreaParam aAreaParam;
+
+ SCCOL nCellX = nX;
+ SCROW nCellY = nY;
+ SvxCellHorJustify eOutHorJust = eHorJust;
+ if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
+ eOutHorJust = bNegative ? SvxCellHorJustify::Right : SvxCellHorJustify::Left;
+ tools::Long nNeededWidth = nGridWidth; // in pixel for GetOutputArea
+ if ( bPixelToLogic )
+ nNeededWidth = mpRefDevice->LogicToPixel(Size(nNeededWidth,0)).Width();
+
+ GetOutputArea( nX, nArrY, nCellStartX, nPosY, nCellX, nCellY, nNeededWidth,
+ *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
+ false, false, true, aAreaParam );
+
+ if ( bShrink )
+ {
+ tools::Long nPixelWidth = bPixelToLogic ?
+ mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width() : nEngineWidth;
+ tools::Long nNeededPixel = nPixelWidth + nLeftM + nRightM;
+
+ aAreaParam.mbLeftClip = aAreaParam.mbRightClip = true;
+
+ // always do height
+ ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
+ false, eOrient, nAttrRotate, bPixelToLogic,
+ nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
+
+ if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
+ {
+ // do width only if rotating within the cell (standard mode)
+ ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
+ true, eOrient, nAttrRotate, bPixelToLogic,
+ nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
+ }
+
+ // nEngineWidth/nEngineHeight is updated in ShrinkEditEngine
+ // (but width is only valid for standard mode)
+ nRealWidth = static_cast<tools::Long>(pEngine->CalcTextWidth());
+ nRealHeight = pEngine->GetTextHeight();
+
+ if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
+ nEngineWidth = static_cast<tools::Long>( nRealHeight / fabs( nSin ) );
+ }
+
+ tools::Long nClipStartX = nStartX;
+ if (nX<nX1)
+ {
+ //! clipping is not needed when on the left side of the window
+
+ if (nStartX<nScrX)
+ {
+ tools::Long nDif = nScrX - nStartX;
+ nClipStartX = nScrX;
+ aClipSize.AdjustWidth( -nDif );
+ }
+ }
+
+ tools::Long nClipStartY = nStartY;
+ if (nArrY==0 && nClipStartY < nRowPosY )
+ {
+ tools::Long nDif = nRowPosY - nClipStartY;
+ nClipStartY = nRowPosY;
+ aClipSize.AdjustHeight( -nDif );
+ }
+
+ if ( nAttrRotate /* && eRotMode != SVX_ROTATE_MODE_STANDARD */ )
+ {
+ // only clip rotated output text at the page border
+ nClipStartX = nScrX;
+ aClipSize.setWidth( nScrW );
+ }
+
+ if (bPixelToLogic)
+ aAreaParam.maClipRect = mpRefDevice->PixelToLogic( tools::Rectangle(
+ Point(nClipStartX,nClipStartY), aClipSize ) );
+ else
+ aAreaParam.maClipRect = tools::Rectangle(Point(nClipStartX, nClipStartY),
+ aClipSize ); // Scale = 1
+
+ if (bMetaFile)
+ {
+ mpDev->Push();
+ mpDev->IntersectClipRegion( aAreaParam.maClipRect );
+ }
+ else
+ mpDev->SetClipRegion( vcl::Region( aAreaParam.maClipRect ) );
+
+ Point aLogicStart;
+ if (bPixelToLogic)
+ aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
+ else
+ aLogicStart = Point(nStartX, nStartY);
+ if ( eOrient!=SvxCellOrientation::Standard || !bBreak )
+ {
+ tools::Long nAvailWidth = aCellSize.Width();
+ if (eType==OUTTYPE_WINDOW &&
+ eOrient!=SvxCellOrientation::Stacked &&
+ pInfo->bAutoFilter)
+ {
+ // filter drop-down width depends on row height
+ double fZoom = mpRefDevice ? static_cast<double>(mpRefDevice->GetMapMode().GetScaleY()) : 1.0;
+ fZoom = fZoom > 1.0 ? fZoom : 1.0;
+ if (bPixelToLogic)
+ nAvailWidth -= mpRefDevice->PixelToLogic(Size(0,fZoom * DROPDOWN_BITMAP_SIZE)).Height();
+ else
+ nAvailWidth -= fZoom * DROPDOWN_BITMAP_SIZE;
+ tools::Long nComp = nEngineWidth;
+ if (nAvailWidth<nComp) nAvailWidth=nComp;
+ }
+
+ // horizontal orientation
+
+ if (eOrient==SvxCellOrientation::Standard && !nAttrRotate)
+ {
+ if (eHorJust==SvxCellHorJustify::Right ||
+ eHorJust==SvxCellHorJustify::Center)
+ {
+ pEngine->SetUpdateLayout( false );
+
+ SvxAdjust eSvxAdjust =
+ (eHorJust==SvxCellHorJustify::Right) ?
+ SvxAdjust::Right : SvxAdjust::Center;
+ pEngine->SetDefaultItem(
+ SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
+
+ aPaperSize.setWidth( nOutWidth );
+ if (bPixelToLogic)
+ pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
+ else
+ pEngine->SetPaperSize(aPaperSize);
+
+ pEngine->SetUpdateLayout( true );
+ }
+ }
+ else
+ {
+ // rotated text is centered by default
+ if (eHorJust==SvxCellHorJustify::Right)
+ aLogicStart.AdjustX(nAvailWidth - nEngineWidth );
+ else if (eHorJust==SvxCellHorJustify::Center ||
+ eHorJust==SvxCellHorJustify::Standard)
+ aLogicStart.AdjustX((nAvailWidth - nEngineWidth) / 2 );
+ }
+ }
+
+ if ( bLayoutRTL )
+ {
+ if (bPixelToLogic)
+ aLogicStart.AdjustX( -(mpRefDevice->PixelToLogic(
+ Size( nCellWidth, 0 ) ).Width()) );
+ else
+ aLogicStart.AdjustX( -nCellWidth );
+ }
+
+ if ( eOrient==SvxCellOrientation::Standard ||
+ eOrient==SvxCellOrientation::Stacked || !bBreak )
+ {
+ if (eVerJust==SvxCellVerJustify::Bottom ||
+ eVerJust==SvxCellVerJustify::Standard)
+ {
+ if (bPixelToLogic)
+ aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0,
+ mpRefDevice->LogicToPixel(aCellSize).Height() -
+ mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
+ )).Height() );
+ else
+ aLogicStart.AdjustY(aCellSize.Height() - nEngineHeight );
+ }
+
+ else if (eVerJust==SvxCellVerJustify::Center)
+ {
+ if (bPixelToLogic)
+ aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0,(
+ mpRefDevice->LogicToPixel(aCellSize).Height() -
+ mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height())
+ / 2)).Height() );
+ else
+ aLogicStart.AdjustY((aCellSize.Height() - nEngineHeight) / 2 );
+ }
+ }
+
+ // TOPBOTTOM and BOTTOMTOP are handled in DrawStrings/DrawEdit
+ OSL_ENSURE( eOrient == SvxCellOrientation::Standard && nAttrRotate,
+ "DrawRotated: no rotation" );
+
+ Degree10 nOriVal = 0_deg10;
+ if ( nAttrRotate )
+ {
+ // attribute is 1/100, Font 1/10 degrees
+ nOriVal = to<Degree10>(nAttrRotate);
+
+ double nAddX = 0.0;
+ double nAddY = 0.0;
+ if ( nCos > 0.0 && eRotMode != SVX_ROTATE_MODE_STANDARD )
+ {
+ //! limit !!!
+ double nH = nRealHeight * nCos;
+ nAddX += nH * ( nCos / fabs(nSin) );
+ }
+ if ( nCos < 0.0 && eRotMode == SVX_ROTATE_MODE_STANDARD )
+ nAddX -= nRealWidth * nCos;
+ if ( nSin < 0.0 )
+ nAddX -= nRealHeight * nSin;
+ if ( nSin > 0.0 )
+ nAddY += nRealWidth * nSin;
+ if ( nCos < 0.0 )
+ nAddY -= nRealHeight * nCos;
+
+ if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
+ {
+ //! limit !!!
+ double nSkew = nTotalHeight * nCos / fabs(nSin);
+ if ( eRotMode == SVX_ROTATE_MODE_CENTER )
+ nAddX -= nSkew * 0.5;
+ if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nSin > 0.0 ) ||
+ ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nSin < 0.0 ) )
+ nAddX -= nSkew;
+
+ tools::Long nUp = 0;
+ if ( eVerJust == SvxCellVerJustify::Center )
+ nUp = ( aCellSize.Height() - nEngineHeight ) / 2;
+ else if ( eVerJust == SvxCellVerJustify::Top )
+ {
+ if ( nSin > 0.0 )
+ nUp = aCellSize.Height() - nEngineHeight;
+ }
+ else // BOTTOM / STANDARD
+ {
+ if ( nSin < 0.0 )
+ nUp = aCellSize.Height() - nEngineHeight;
+ }
+ if ( nUp )
+ nAddX += ( nUp * nCos / fabs(nSin) );
+ }
+
+ aLogicStart.AdjustX(static_cast<tools::Long>(nAddX) );
+ aLogicStart.AdjustY(static_cast<tools::Long>(nAddY) );
+ }
+
+ // bSimClip is not used here (because nOriVal is set)
+
+ pEngine->Draw(*mpDev, aLogicStart, nOriVal);
+
+ if (bMetaFile)
+ mpDev->Pop();
+ else
+ mpDev->SetClipRegion();
+ }
+ }
+ }
+ }
+ nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
+ }
+ }
+ nRowPosY += pRowInfo[nArrY].nHeight;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/output3.cxx b/sc/source/ui/view/output3.cxx
new file mode 100644
index 000000000..eec75c396
--- /dev/null
+++ b/sc/source/ui/view/output3.cxx
@@ -0,0 +1,215 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/unit_conversion.hxx>
+#include <svx/svdoutl.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdview.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <osl/diagnose.h>
+
+#include <output.hxx>
+#include <drwlayer.hxx>
+#include <document.hxx>
+#include <tabvwsh.hxx>
+
+#include <svx/fmview.hxx>
+
+// #i72502#
+Point ScOutputData::PrePrintDrawingLayer(tools::Long nLogStX, tools::Long nLogStY )
+{
+ tools::Rectangle aRect;
+ SCCOL nCol;
+ Point aOffset;
+ tools::Long nLayoutSign(bLayoutRTL ? -1 : 1);
+
+ for (nCol=0; nCol<nX1; nCol++)
+ aOffset.AdjustX( -(mpDoc->GetColWidth( nCol, nTab ) * nLayoutSign) );
+ aOffset.AdjustY( -sal_Int32(mpDoc->GetRowHeight( 0, nY1-1, nTab )) );
+
+ tools::Long nDataWidth = 0;
+ for (nCol=nX1; nCol<=nX2; nCol++)
+ nDataWidth += mpDoc->GetColWidth( nCol, nTab );
+
+ if ( bLayoutRTL )
+ aOffset.AdjustX(nDataWidth );
+
+ aRect.SetLeft( -aOffset.X() );
+ aRect.SetRight( -aOffset.X() );
+ aRect.SetTop( -aOffset.Y() );
+ aRect.SetBottom( -aOffset.Y() );
+
+ Point aMMOffset( aOffset );
+ aMMOffset.setX(o3tl::convert(aMMOffset.X(), o3tl::Length::twip, o3tl::Length::mm100));
+ aMMOffset.setY(o3tl::convert(aMMOffset.Y(), o3tl::Length::twip, o3tl::Length::mm100));
+
+ if (!bMetaFile)
+ aMMOffset += Point( nLogStX, nLogStY );
+
+ for (nCol=nX1; nCol<=nX2; nCol++)
+ aRect.AdjustRight(mpDoc->GetColWidth( nCol, nTab ) );
+ aRect.AdjustBottom(mpDoc->GetRowHeight( nY1, nY2, nTab ) );
+
+ aRect.SetLeft(o3tl::convert(aRect.Left(), o3tl::Length::twip, o3tl::Length::mm100));
+ aRect.SetTop(o3tl::convert(aRect.Top(), o3tl::Length::twip, o3tl::Length::mm100));
+ aRect.SetRight(o3tl::convert(aRect.Right(), o3tl::Length::twip, o3tl::Length::mm100));
+ aRect.SetBottom(o3tl::convert(aRect.Bottom(), o3tl::Length::twip, o3tl::Length::mm100));
+
+ if(pViewShell || pDrawView)
+ {
+ SdrView* pLocalDrawView = pDrawView ? pDrawView : pViewShell->GetScDrawView();
+
+ if(pLocalDrawView)
+ {
+ // #i76114# MapMode has to be set because BeginDrawLayers uses GetPaintRegion
+ MapMode aOldMode = mpDev->GetMapMode();
+ if (!bMetaFile)
+ mpDev->SetMapMode( MapMode( MapUnit::Map100thMM, aMMOffset, aOldMode.GetScaleX(), aOldMode.GetScaleY() ) );
+
+ // #i74769# work with SdrPaintWindow directly
+ // #i76114# pass bDisableIntersect = true, because the intersection of the table area
+ // with the Window's paint region can be empty
+ vcl::Region aRectRegion(aRect);
+ mpTargetPaintWindow = pLocalDrawView->BeginDrawLayers(mpDev, aRectRegion, true);
+ OSL_ENSURE(mpTargetPaintWindow, "BeginDrawLayers: Got no SdrPaintWindow (!)");
+
+ if (!bMetaFile)
+ mpDev->SetMapMode( aOldMode );
+ }
+ }
+
+ return aMMOffset;
+}
+
+// #i72502#
+void ScOutputData::PostPrintDrawingLayer(const Point& rMMOffset) // #i74768#
+{
+ // #i74768# just use offset as in PrintDrawingLayer() to also get the form controls
+ // painted with offset
+ MapMode aOldMode = mpDev->GetMapMode();
+
+ if (!bMetaFile)
+ {
+ mpDev->SetMapMode( MapMode( MapUnit::Map100thMM, rMMOffset, aOldMode.GetScaleX(), aOldMode.GetScaleY() ) );
+ }
+
+ if(pViewShell || pDrawView)
+ {
+ SdrView* pLocalDrawView = pDrawView ? pDrawView : pViewShell->GetScDrawView();
+
+ if(pLocalDrawView)
+ {
+ // #i74769# work with SdrPaintWindow directly
+ pLocalDrawView->EndDrawLayers(*mpTargetPaintWindow, true);
+ mpTargetPaintWindow = nullptr;
+ }
+ }
+
+ // #i74768#
+ if (!bMetaFile)
+ {
+ mpDev->SetMapMode( aOldMode );
+ }
+}
+
+// #i72502#
+void ScOutputData::PrintDrawingLayer(SdrLayerID nLayer, const Point& rMMOffset)
+{
+ bool bHideAllDrawingLayer(false);
+
+ if(pViewShell || pDrawView)
+ {
+ SdrView* pLocalDrawView = pDrawView ? pDrawView : pViewShell->GetScDrawView();
+
+ if(pLocalDrawView)
+ {
+ bHideAllDrawingLayer = pLocalDrawView->getHideOle() && pLocalDrawView->getHideChart()
+ && pLocalDrawView->getHideDraw() && pLocalDrawView->getHideFormControl();
+ }
+ }
+
+ if(bHideAllDrawingLayer || (!mpDoc->GetDrawLayer()))
+ {
+ return;
+ }
+
+ MapMode aOldMode = mpDev->GetMapMode();
+
+ if (!bMetaFile)
+ {
+ mpDev->SetMapMode( MapMode( MapUnit::Map100thMM, rMMOffset, aOldMode.GetScaleX(), aOldMode.GetScaleY() ) );
+ }
+
+ DrawSelectiveObjects( nLayer );
+
+ if (!bMetaFile)
+ {
+ mpDev->SetMapMode( aOldMode );
+ }
+}
+
+void ScOutputData::DrawSelectiveObjects(SdrLayerID nLayer)
+{
+ ScDrawLayer* pModel = mpDoc->GetDrawLayer();
+ if (!pModel)
+ return;
+
+ // #i46362# high contrast mode (and default text direction) must be handled
+ // by the application, so it's still needed when using DrawLayer().
+
+ SdrOutliner& rOutl = pModel->GetDrawOutliner();
+ rOutl.EnableAutoColor( mbUseStyleColor );
+ rOutl.SetDefaultHorizontalTextDirection(
+ mpDoc->GetEditTextDirection( nTab ) );
+
+ // #i69767# The hyphenator must be set (used to be before drawing a text shape with hyphenation).
+ // LinguMgr::GetHyphenator (EditEngine) uses a wrapper now that creates the real hyphenator on demand,
+ // so it's not a performance problem to call UseHyphenator even when it's not needed.
+
+ pModel->UseHyphenator();
+
+ DrawModeFlags nOldDrawMode = mpDev->GetDrawMode();
+ if ( mbUseStyleColor && Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+ {
+ mpDev->SetDrawMode( nOldDrawMode | DrawModeFlags::SettingsLine | DrawModeFlags::SettingsFill |
+ DrawModeFlags::SettingsText | DrawModeFlags::SettingsGradient );
+ }
+
+ if(pViewShell || pDrawView)
+ {
+ SdrView* pLocalDrawView = pDrawView ? pDrawView : pViewShell->GetScDrawView();
+
+ if(pLocalDrawView)
+ {
+ SdrPageView* pPageView = pLocalDrawView->GetSdrPageView();
+
+ if(pPageView)
+ {
+ pPageView->DrawLayer(sal::static_int_cast<SdrLayerID>(nLayer), mpDev);
+ }
+ }
+ }
+
+ mpDev->SetDrawMode(nOldDrawMode);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/overlayobject.cxx b/sc/source/ui/view/overlayobject.cxx
new file mode 100644
index 000000000..67a77884f
--- /dev/null
+++ b/sc/source/ui/view/overlayobject.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 <overlayobject.hxx>
+#include <basegfx/range/b2drange.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonMarkerPrimitive2D.hxx>
+#include <officecfg/Office/Common.hxx>
+
+using sdr::overlay::OverlayObject;
+using sdr::overlay::OverlayManager;
+
+#define DASH_UPDATE_INTERVAL 500 // in msec
+
+ScOverlayDashedBorder::ScOverlayDashedBorder(const ::basegfx::B2DRange& rRange, const Color& rColor) :
+ OverlayObject(rColor),
+ mbToggle(true)
+{
+ mbAllowsAnimation = officecfg::Office::Common::VCL::AnimationsEnabled::get();
+ maRange = rRange;
+}
+
+ScOverlayDashedBorder::~ScOverlayDashedBorder()
+{
+}
+
+void ScOverlayDashedBorder::Trigger(sal_uInt32 nTime)
+{
+ OverlayManager* pMgr = getOverlayManager();
+ if (pMgr)
+ {
+ SetTime(nTime + DASH_UPDATE_INTERVAL);
+ mbToggle = !mbToggle;
+ pMgr->InsertEvent(*this);
+ objectChange();
+ }
+}
+
+void ScOverlayDashedBorder::stripeDefinitionHasChanged()
+{
+ objectChange();
+}
+
+drawinglayer::primitive2d::Primitive2DContainer ScOverlayDashedBorder::createOverlayObjectPrimitive2DSequence()
+{
+ using ::basegfx::B2DPolygon;
+ using ::basegfx::B2DPolyPolygon;
+
+ OverlayManager* pMgr = getOverlayManager();
+ if (!pMgr)
+ return drawinglayer::primitive2d::Primitive2DContainer();
+
+ basegfx::BColor aColorA = pMgr->getStripeColorA().getBColor();
+ basegfx::BColor aColorB = pMgr->getStripeColorB().getBColor();
+ if (!mbToggle)
+ ::std::swap(aColorA, aColorB);
+
+ const basegfx::B2DPolygon aPoly = basegfx::utils::createPolygonFromRect(maRange);
+ B2DPolyPolygon aPolygon(aPoly);
+ const drawinglayer::primitive2d::Primitive2DReference aReference(
+ new drawinglayer::primitive2d::PolyPolygonMarkerPrimitive2D(
+ aPolygon, aColorA, aColorB, pMgr->getStripeLengthPixel()));
+
+ return drawinglayer::primitive2d::Primitive2DContainer { aReference };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/pfuncache.cxx b/sc/source/ui/view/pfuncache.cxx
new file mode 100644
index 000000000..b54952cb8
--- /dev/null
+++ b/sc/source/ui/view/pfuncache.cxx
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/multisel.hxx>
+#include <osl/diagnose.h>
+
+#include <pfuncache.hxx>
+#include <printfun.hxx>
+#include <docsh.hxx>
+#include <markdata.hxx>
+#include <prevloc.hxx>
+
+ScPrintFuncCache::ScPrintFuncCache( ScDocShell* pD, const ScMarkData& rMark,
+ const ScPrintSelectionStatus& rStatus ) :
+ aSelection( rStatus ),
+ pDocSh( pD ),
+ nTotalPages( 0 ),
+ bLocInitialized( false )
+{
+ // page count uses the stored cell widths for the printer anyway,
+ // so ScPrintFunc with the document's printer can be used to count
+
+ SfxPrinter* pPrinter = pDocSh->GetPrinter();
+
+ ScRange aRange;
+ const ScRange* pSelRange = nullptr;
+ if ( rMark.IsMarked() )
+ {
+ aRange = rMark.GetMarkArea();
+ pSelRange = &aRange;
+ }
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+
+ // avoid repeated progress bars if row heights for all sheets are needed
+ if ( nTabCount > 1 && rMark.GetSelectCount() == nTabCount )
+ pDocSh->UpdatePendingRowHeights( nTabCount-1, true );
+
+ SCTAB nTab;
+ for ( nTab=0; nTab<nTabCount; nTab++ )
+ {
+ tools::Long nAttrPage = nTab > 0 ? nFirstAttr[nTab-1] : 1;
+
+ tools::Long nThisTab = 0;
+ if ( rMark.GetTableSelect( nTab ) )
+ {
+ ScPrintFunc aFunc( pDocSh, pPrinter, nTab, nAttrPage, 0, pSelRange, &aSelection.GetOptions() );
+ nThisTab = aFunc.GetTotalPages();
+ nFirstAttr.push_back( aFunc.GetFirstPageNo() ); // from page style or previous sheet
+ }
+ else
+ nFirstAttr.push_back( nAttrPage );
+
+ nPages.push_back( nThisTab );
+ nTotalPages += nThisTab;
+ }
+}
+
+ScPrintFuncCache::~ScPrintFuncCache()
+{
+}
+
+void ScPrintFuncCache::InitLocations( const ScMarkData& rMark, OutputDevice* pDev )
+{
+ if ( bLocInitialized )
+ return; // initialize only once
+
+ ScRange aRange;
+ const ScRange* pSelRange = nullptr;
+ if ( rMark.IsMarked() )
+ {
+ aRange = rMark.GetMarkArea();
+ pSelRange = &aRange;
+ }
+
+ tools::Long nRenderer = 0; // 0-based physical page number across sheets
+ tools::Long nTabStart = 0;
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab : rMark)
+ {
+ if (nTab >= nTabCount)
+ break;
+ ScPrintFunc aFunc( pDev, pDocSh, nTab, nFirstAttr[nTab], nTotalPages, pSelRange, &aSelection.GetOptions() );
+ aFunc.SetRenderFlag( true );
+
+ tools::Long nDisplayStart = GetDisplayStart( nTab );
+
+ for ( tools::Long nPage=0; nPage<nPages[nTab]; nPage++ )
+ {
+ Range aPageRange( nRenderer+1, nRenderer+1 );
+ MultiSelection aPage( aPageRange );
+ aPage.SetTotalRange( Range(0,RANGE_MAX) );
+ aPage.Select( aPageRange );
+
+ ScPreviewLocationData aLocData( &rDoc, pDev );
+ aFunc.DoPrint( aPage, nTabStart, nDisplayStart, false, &aLocData );
+
+ ScRange aCellRange;
+ tools::Rectangle aPixRect;
+ if ( aLocData.GetMainCellRange( aCellRange, aPixRect ) )
+ aLocations.emplace_back( nRenderer, aCellRange, aPixRect );
+
+ ++nRenderer;
+ }
+
+ nTabStart += nPages[nTab];
+ }
+
+ bLocInitialized = true;
+}
+
+bool ScPrintFuncCache::FindLocation( const ScAddress& rCell, ScPrintPageLocation& rLocation ) const
+{
+ auto aIter = std::find_if(aLocations.begin(), aLocations.end(),
+ [&rCell](const ScPrintPageLocation& rLoc) { return rLoc.aCellRange.Contains(rCell); });
+ if (aIter != aLocations.end())
+ {
+ rLocation = *aIter;
+ return true;
+ }
+ return false; // not found
+}
+
+bool ScPrintFuncCache::IsSameSelection( const ScPrintSelectionStatus& rStatus ) const
+{
+ return aSelection == rStatus;
+}
+
+SCTAB ScPrintFuncCache::GetTabForPage( tools::Long nPage ) const
+{
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCTAB nTab = 0;
+ while ( nTab < nTabCount && nPage >= nPages[nTab] )
+ nPage -= nPages[nTab++];
+ if (nTab >= nTabCount)
+ nTab = nTabCount - 1;
+ return nTab;
+}
+
+tools::Long ScPrintFuncCache::GetTabStart( SCTAB nTab ) const
+{
+ tools::Long nRet = 0;
+ const SCTAB maxIndex = std::min(nTab, static_cast<SCTAB>(nPages.size()));
+ for ( SCTAB i=0; i<maxIndex; i++ )
+ nRet += nPages[i];
+ return nRet;
+}
+
+tools::Long ScPrintFuncCache::GetDisplayStart( SCTAB nTab ) const
+{
+ //! merge with lcl_GetDisplayStart in preview?
+
+ tools::Long nDisplayStart = 0;
+ ScDocument& rDoc = pDocSh->GetDocument();
+ for (SCTAB i=0; i<nTab; i++)
+ {
+ if ( rDoc.NeedPageResetAfterTab(i) )
+ nDisplayStart = 0;
+ else
+ {
+ if ( i < static_cast<SCTAB>(nPages.size()) )
+ nDisplayStart += nPages[i];
+ else
+ OSL_FAIL("nPages out of bounds, FIX IT!");
+ }
+ }
+ return nDisplayStart;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/pgbrksh.cxx b/sc/source/ui/view/pgbrksh.cxx
new file mode 100644
index 000000000..a0cdb21be
--- /dev/null
+++ b/sc/source/ui/view/pgbrksh.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/objface.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <pgbrksh.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+
+#define ShellClass_ScPageBreakShell
+#include <scslots.hxx>
+
+SFX_IMPL_INTERFACE(ScPageBreakShell, SfxShell)
+
+void ScPageBreakShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterPopupMenu("pagebreak");
+}
+
+ScPageBreakShell::ScPageBreakShell(ScTabViewShell* pViewSh)
+ : SfxShell(pViewSh)
+{
+ SetPool(&pViewSh->GetPool());
+ ScViewData& rViewData = pViewSh->GetViewData();
+ SfxUndoManager* pMgr = rViewData.GetSfxDocShell()->GetUndoManager();
+ SetUndoManager(pMgr);
+ if (!rViewData.GetDocument().IsUndoEnabled())
+ {
+ pMgr->SetMaxUndoActionCount(0);
+ }
+ SetName("PageBreak");
+}
+
+ScPageBreakShell::~ScPageBreakShell() {}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/pivotsh.cxx b/sc/source/ui/view/pivotsh.cxx
new file mode 100644
index 000000000..b4ef807ff
--- /dev/null
+++ b/sc/source/ui/view/pivotsh.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 <scitems.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+#include <svl/whiter.hxx>
+#include <vcl/EnumContext.hxx>
+
+#include <sc.hrc>
+#include <pivotsh.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <dpobject.hxx>
+#include <dpshttab.hxx>
+#include <dbdocfun.hxx>
+#include <uiitems.hxx>
+#include <scabstdlg.hxx>
+
+#define ShellClass_ScPivotShell
+#include <scslots.hxx>
+
+
+SFX_IMPL_INTERFACE(ScPivotShell, SfxShell)
+
+void ScPivotShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterPopupMenu("pivot");
+}
+
+ScPivotShell::ScPivotShell( ScTabViewShell* pViewSh ) :
+ SfxShell(pViewSh),
+ pViewShell( pViewSh )
+{
+ SetPool( &pViewSh->GetPool() );
+ ScViewData& rViewData = pViewSh->GetViewData();
+ SfxUndoManager* pMgr = rViewData.GetSfxDocShell()->GetUndoManager();
+ SetUndoManager( pMgr );
+ if ( !rViewData.GetDocument().IsUndoEnabled() )
+ {
+ pMgr->SetMaxUndoActionCount( 0 );
+ }
+ SetName("Pivot");
+ SfxShell::SetContextName(vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Pivot));
+}
+
+ScPivotShell::~ScPivotShell()
+{
+}
+
+void ScPivotShell::Execute( const SfxRequest& rReq )
+{
+ switch ( rReq.GetSlot() )
+ {
+ case SID_PIVOT_RECALC:
+ pViewShell->RecalcPivotTable();
+ break;
+
+ case SID_PIVOT_KILL:
+ pViewShell->DeletePivotTable();
+ break;
+
+ case SID_DP_FILTER:
+ {
+ ScDPObject* pDPObj = GetCurrDPObject();
+ if( pDPObj )
+ {
+ ScQueryParam aQueryParam;
+ SCTAB nSrcTab = 0;
+ const ScSheetSourceDesc* pDesc = pDPObj->GetSheetDesc();
+ OSL_ENSURE( pDesc, "no sheet source for DP filter dialog" );
+ if( pDesc )
+ {
+ aQueryParam = pDesc->GetQueryParam();
+ nSrcTab = pDesc->GetSourceRange().aStart.Tab();
+ }
+
+ ScViewData& rViewData = pViewShell->GetViewData();
+ SfxItemSetFixed<SCITEM_QUERYDATA, SCITEM_QUERYDATA> aArgSet( pViewShell->GetPool() );
+ aArgSet.Put( ScQueryItem( SCITEM_QUERYDATA, &rViewData, &aQueryParam ) );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScPivotFilterDlg> pDlg(pFact->CreateScPivotFilterDlg(
+ pViewShell->GetFrameWeld(), aArgSet, nSrcTab));
+
+ if( pDlg->Execute() == RET_OK )
+ {
+ ScSheetSourceDesc aNewDesc(&rViewData.GetDocument());
+ if( pDesc )
+ aNewDesc = *pDesc;
+
+ const ScQueryItem& rQueryItem = pDlg->GetOutputItem();
+ aNewDesc.SetQueryParam(rQueryItem.GetQueryData());
+
+ ScDPObject aNewObj( *pDPObj );
+ aNewObj.SetSheetDesc( aNewDesc );
+ ScDBDocFunc aFunc( *rViewData.GetDocShell() );
+ aFunc.DataPilotUpdate( pDPObj, &aNewObj, true, false );
+ rViewData.GetView()->CursorPosChanged(); // shells may be switched
+ }
+ }
+ }
+ break;
+ }
+}
+
+void ScPivotShell::GetState( SfxItemSet& rSet )
+{
+ ScDocShell* pDocSh = pViewShell->GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bool bDisable = pDocSh->IsReadOnly() || rDoc.GetChangeTrack();
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while (nWhich)
+ {
+ switch (nWhich)
+ {
+ case SID_PIVOT_RECALC:
+ case SID_PIVOT_KILL:
+ {
+ //! move ReadOnly check to idl flags
+ if ( bDisable )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+ case SID_DP_FILTER:
+ {
+ ScDPObject* pDPObj = GetCurrDPObject();
+ if( bDisable || !pDPObj || !pDPObj->IsSheetData() )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+ScDPObject* ScPivotShell::GetCurrDPObject()
+{
+ const ScViewData& rViewData = pViewShell->GetViewData();
+ return rViewData.GetDocument().GetDPAtCursor(
+ rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/preview.cxx b/sc/source/ui/view/preview.cxx
new file mode 100644
index 000000000..a122544f1
--- /dev/null
+++ b/sc/source/ui/view/preview.cxx
@@ -0,0 +1,1575 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <officecfg/Office/Common.hxx>
+#include <svtools/colorcfg.hxx>
+#include <svx/fmview.hxx>
+#include <editeng/sizeitem.hxx>
+#include <svx/svdpagv.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svl/itemset.hxx>
+#include <tools/multisel.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/settings.hxx>
+#include <o3tl/deleter.hxx>
+#include <o3tl/unit_conversion.hxx>
+
+#include <preview.hxx>
+#include <prevwsh.hxx>
+#include <prevloc.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <printfun.hxx>
+#include <printopt.hxx>
+#include <stlpool.hxx>
+#include <undostyl.hxx>
+#include <drwlayer.hxx>
+#include <scmod.hxx>
+#include <markdata.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <sc.hrc>
+#include <helpids.h>
+#include <AccessibleDocumentPagePreview.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <com/sun/star/accessibility/XAccessible.hpp>
+#include <AccessibilityHints.hxx>
+#include <vcl/svapp.hxx>
+#include <viewutil.hxx>
+#include <docpool.hxx>
+#include <patattr.hxx>
+#include <columnspanset.hxx>
+
+#include <memory>
+
+#define SC_PREVIEW_SHADOWSIZE 2
+
+static tools::Long lcl_GetDisplayStart( SCTAB nTab, const ScDocument* pDoc, std::vector<tools::Long>& nPages )
+{
+ tools::Long nDisplayStart = 0;
+ for (SCTAB i=0; i<nTab; i++)
+ {
+ if ( pDoc->NeedPageResetAfterTab(i) )
+ nDisplayStart = 0;
+ else
+ nDisplayStart += nPages[i];
+ }
+ return nDisplayStart;
+}
+
+ScPreview::ScPreview( vcl::Window* pParent, ScDocShell* pDocSh, ScPreviewShell* pViewSh ) :
+ Window( pParent ),
+ nPageNo( 0 ),
+ nZoom( 100 ),
+ nTabCount( 0 ),
+ nTabsTested( 0 ),
+ nTab( 0 ),
+ nTabPage( 0 ),
+ nTabStart( 0 ),
+ nDisplayStart( 0 ),
+ aDateTime( DateTime::SYSTEM ),
+ nTotalPages( 0 ),
+ pDocShell( pDocSh ),
+ pViewShell( pViewSh ),
+ bInGetState( false ),
+ bValid( false ),
+ bStateValid( false ),
+ bLocationValid( false ),
+ bInPaint( false ),
+ bInSetZoom( false ),
+ bLeftRulerMove( false ),
+ bRightRulerMove( false ),
+ bTopRulerMove( false ),
+ bBottomRulerMove( false ),
+ bHeaderRulerMove( false ),
+ bFooterRulerMove( false ),
+ bLeftRulerChange( false ),
+ bRightRulerChange( false ),
+ bTopRulerChange( false ),
+ bBottomRulerChange( false ),
+ bHeaderRulerChange( false ),
+ bFooterRulerChange( false ),
+ bPageMargin ( false ),
+ bColRulerMove( false ),
+ mbHasEmptyRangeTable(false),
+ nLeftPosition( 0 ),
+ mnScale( 0 ),
+ nColNumberButtonDown( 0 ),
+ nHeaderHeight ( 0 ),
+ nFooterHeight ( 0 )
+{
+ GetOutDev()->SetOutDevViewType( OutDevViewType::PrintPreview );
+ SetBackground();
+
+ SetHelpId( HID_SC_WIN_PREVIEW );
+
+ GetOutDev()->SetDigitLanguage( SC_MOD()->GetOptDigitLanguage() );
+}
+
+ScPreview::~ScPreview()
+{
+ disposeOnce();
+}
+
+void ScPreview::dispose()
+{
+ pDrawView.reset();
+ pLocationData.reset();
+ vcl::Window::dispose();
+}
+
+void ScPreview::UpdateDrawView() // nTab must be right
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ ScDrawLayer* pModel = rDoc.GetDrawLayer(); // is not 0
+
+ if ( pModel )
+ {
+ SdrPage* pPage = pModel->GetPage(nTab);
+ if ( pDrawView && ( !pDrawView->GetSdrPageView() || pDrawView->GetSdrPageView()->GetPage() != pPage ) )
+ {
+ // convert the displayed Page of drawView (see below) does not work?!?
+ pDrawView.reset();
+ }
+
+ if ( !pDrawView ) // New Drawing?
+ {
+ pDrawView.reset( new FmFormView( *pModel, GetOutDev()) );
+
+ // The DrawView takes over the Design-Mode from the Model
+ // (Settings "In opening Draftmode"), therefore to restore here
+ pDrawView->SetDesignMode();
+ pDrawView->SetPrintPreview();
+ pDrawView->ShowSdrPage(pPage);
+ }
+ }
+ else if ( pDrawView )
+ {
+ pDrawView.reset(); // for this Chart is not needed
+ }
+}
+
+void ScPreview::TestLastPage()
+{
+ if (nPageNo < nTotalPages)
+ return;
+
+ if (nTotalPages)
+ {
+ nPageNo = nTotalPages - 1;
+ nTab = static_cast<SCTAB>(nPages.size()) -1;
+ while (nTab > 0 && !nPages[nTab]) // not the last empty Table
+ --nTab;
+ OSL_ENSURE(0 < static_cast<SCTAB>(nPages.size()),"are all tables empty?");
+ nTabPage = nPages[nTab] - 1;
+ nTabStart = 0;
+ for (sal_uInt16 i=0; i<nTab; i++)
+ nTabStart += nPages[i];
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ nDisplayStart = lcl_GetDisplayStart( nTab, &rDoc, nPages );
+ }
+ else // empty Document
+ {
+ nTab = 0;
+ nPageNo = nTabPage = nTabStart = nDisplayStart = 0;
+ aState.nPrintTab = 0;
+ aState.nStartCol = aState.nEndCol = 0;
+ aState.nStartRow = aState.nEndRow = 0;
+ aState.nZoom = 0;
+ aState.nPagesX = aState.nPagesY = 0;
+ aState.nTabPages = aState.nTotalPages =
+ aState.nPageStart = aState.nDocPages = 0;
+ }
+}
+
+void ScPreview::CalcPages()
+{
+ weld::WaitObject aWait(GetFrameWeld());
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ nTabCount = rDoc.GetTableCount();
+
+ if (maSelectedTabs.empty())
+ {
+ SCTAB nCurrentTab = ScDocShell::GetCurTab();
+ maSelectedTabs.insert(nCurrentTab);
+ }
+
+ SCTAB nStart = nTabsTested;
+ if (!bValid)
+ {
+ nStart = 0;
+ nTotalPages = 0;
+ nTabsTested = 0;
+ }
+
+ // update all pending row heights with a single progress bar,
+ // instead of a separate progress for each sheet from ScPrintFunc
+ pDocShell->UpdatePendingRowHeights( nTabCount-1, true );
+
+ // PrintOptions is passed to PrintFunc for SkipEmpty flag,
+ // but always all sheets are used (there is no selected sheet)
+ ScPrintOptions aOptions = SC_MOD()->GetPrintOptions();
+
+ while (nStart > static_cast<SCTAB>(nPages.size()))
+ nPages.push_back(0);
+ while (nStart > static_cast<SCTAB>(nFirstAttr.size()))
+ nFirstAttr.push_back(1);
+
+ for (SCTAB i=nStart; i<nTabCount; i++)
+ {
+ if ( i == static_cast<SCTAB>(nPages.size()))
+ nPages.push_back(0);
+ if ( i == static_cast<SCTAB>(nFirstAttr.size()))
+ nFirstAttr.push_back(1);
+ if (!aOptions.GetAllSheets() && maSelectedTabs.count(i) == 0)
+ {
+ nPages[i] = 0;
+ nFirstAttr[i] = 1;
+ continue;
+ }
+
+ tools::Long nAttrPage = i > 0 ? nFirstAttr[i-1] : 1;
+
+ tools::Long nThisStart = nTotalPages;
+ ScPrintFunc aPrintFunc( GetOutDev(), pDocShell, i, nAttrPage, 0, nullptr, &aOptions );
+ tools::Long nThisTab = aPrintFunc.GetTotalPages();
+ if (!aPrintFunc.HasPrintRange())
+ mbHasEmptyRangeTable = true;
+
+ nPages[i] = nThisTab;
+ nTotalPages += nThisTab;
+ nFirstAttr[i] = aPrintFunc.GetFirstPageNo(); // to keep or from template
+
+ if (nPageNo>=nThisStart && nPageNo<nTotalPages)
+ {
+ nTab = i;
+ nTabPage = nPageNo - nThisStart;
+ nTabStart = nThisStart;
+
+ aPrintFunc.GetPrintState( aState );
+ }
+ }
+
+ nDisplayStart = lcl_GetDisplayStart( nTab, &rDoc, nPages );
+
+ if (nTabCount > nTabsTested)
+ nTabsTested = nTabCount;
+
+ TestLastPage();
+
+ aState.nDocPages = nTotalPages;
+
+ bValid = true;
+ bStateValid = true;
+ DoInvalidate();
+}
+
+void ScPreview::RecalcPages() // only nPageNo is changed
+{
+ if (!bValid)
+ return; // then CalcPages is called
+
+ SCTAB nOldTab = nTab;
+
+ bool bDone = false;
+ while (nPageNo >= nTotalPages && nTabsTested < nTabCount)
+ {
+ CalcPages();
+ bDone = true;
+ }
+
+ if (!bDone)
+ {
+ tools::Long nPartPages = 0;
+ for (SCTAB i=0; i<nTabsTested && nTab < static_cast<SCTAB>(nPages.size()); i++)
+ {
+ tools::Long nThisStart = nPartPages;
+ nPartPages += nPages[i];
+
+ if (nPageNo>=nThisStart && nPageNo<nPartPages)
+ {
+ nTab = i;
+ nTabPage = nPageNo - nThisStart;
+ nTabStart = nThisStart;
+ }
+ }
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ nDisplayStart = lcl_GetDisplayStart( nTab, &rDoc, nPages );
+ }
+
+ TestLastPage(); // to test, if after last page
+
+ if ( nTab != nOldTab )
+ bStateValid = false;
+
+ DoInvalidate();
+}
+
+void ScPreview::DoPrint( ScPreviewLocationData* pFillLocation )
+{
+ if (!bValid)
+ {
+ CalcPages();
+ RecalcPages();
+ UpdateDrawView(); // Spreadsheet eventually changes
+ }
+
+ Fraction aPreviewZoom( nZoom, 100 );
+ Fraction aHorPrevZoom( static_cast<tools::Long>( 100 * nZoom / pDocShell->GetOutputFactor() ), 10000 );
+ MapMode aMMMode( MapUnit::Map100thMM, Point(), aHorPrevZoom, aPreviewZoom );
+
+ bool bDoPrint = ( pFillLocation == nullptr );
+ bool bValidPage = ( nPageNo < nTotalPages );
+
+ ScModule* pScMod = SC_MOD();
+ const svtools::ColorConfig& rColorCfg = pScMod->GetColorConfig();
+ Color aBackColor( rColorCfg.GetColorValue(svtools::APPBACKGROUND).nColor );
+
+ if ( bDoPrint && ( aOffset.X() < 0 || aOffset.Y() < 0 ) && bValidPage )
+ {
+ SetMapMode( aMMMode );
+ GetOutDev()->SetLineColor();
+ GetOutDev()->SetFillColor(aBackColor);
+
+ Size aWinSize = GetOutDev()->GetOutputSize();
+ if ( aOffset.X() < 0 )
+ GetOutDev()->DrawRect(tools::Rectangle( 0, 0, -aOffset.X(), aWinSize.Height() ));
+ if ( aOffset.Y() < 0 )
+ GetOutDev()->DrawRect(tools::Rectangle( 0, 0, aWinSize.Width(), -aOffset.Y() ));
+ }
+
+ tools::Long nLeftMargin = 0;
+ tools::Long nRightMargin = 0;
+ tools::Long nTopMargin = 0;
+ tools::Long nBottomMargin = 0;
+ bool bHeaderOn = false;
+ bool bFooterOn = false;
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ Size aLocalPageSize;
+ if ( bValidPage )
+ {
+ ScPrintOptions aOptions = pScMod->GetPrintOptions();
+
+ std::unique_ptr<ScPrintFunc, o3tl::default_delete<ScPrintFunc>> pPrintFunc;
+ if (bStateValid)
+ pPrintFunc.reset(new ScPrintFunc(GetOutDev(), pDocShell, aState, &aOptions));
+ else
+ pPrintFunc.reset(new ScPrintFunc(GetOutDev(), pDocShell, nTab, nFirstAttr[nTab], nTotalPages, nullptr, &aOptions));
+
+ pPrintFunc->SetOffset(aOffset);
+ pPrintFunc->SetManualZoom(nZoom);
+ pPrintFunc->SetDateTime(aDateTime);
+ pPrintFunc->SetClearFlag(true);
+ pPrintFunc->SetUseStyleColor( officecfg::Office::Common::Accessibility::IsForPagePreviews::get() );
+
+ pPrintFunc->SetDrawView( pDrawView.get() );
+
+ // MultiSelection for the one Page must produce something inconvenient
+ Range aPageRange( nPageNo+1, nPageNo+1 );
+ MultiSelection aPage( aPageRange );
+ aPage.SetTotalRange( Range(0,RANGE_MAX) );
+ aPage.Select( aPageRange );
+
+ tools::Long nPrinted = pPrintFunc->DoPrint( aPage, nTabStart, nDisplayStart, bDoPrint, pFillLocation );
+ OSL_ENSURE(nPrinted<=1, "What is happening?");
+
+ SetMapMode(aMMMode);
+
+ //init nLeftMargin ... in the ScPrintFunc::InitParam!!!
+ nLeftMargin = pPrintFunc->GetLeftMargin();
+ nRightMargin = pPrintFunc->GetRightMargin();
+ nTopMargin = pPrintFunc->GetTopMargin();
+ nBottomMargin = pPrintFunc->GetBottomMargin();
+ nHeaderHeight = pPrintFunc->GetHeader().nHeight;
+ nFooterHeight = pPrintFunc->GetFooter().nHeight;
+ bHeaderOn = pPrintFunc->GetHeader().bEnable;
+ bFooterOn = pPrintFunc->GetFooter().bEnable;
+ mnScale = pPrintFunc->GetZoom();
+
+ if ( bDoPrint && bPageMargin && pLocationData ) // don't make use of pLocationData while filling it
+ {
+ tools::Rectangle aPixRect;
+ tools::Rectangle aRectCellPosition;
+ tools::Rectangle aRectPosition;
+ pLocationData->GetMainCellRange( aPageArea, aPixRect );
+ mvRight.resize(aPageArea.aEnd.Col()+1);
+ if( !bLayoutRTL )
+ {
+ pLocationData->GetCellPosition( aPageArea.aStart, aRectPosition );
+ nLeftPosition = aRectPosition.Left();
+ for( SCCOL i = aPageArea.aStart.Col(); i <= aPageArea.aEnd.Col(); i++ )
+ {
+ pLocationData->GetCellPosition( ScAddress( i,aPageArea.aStart.Row(),aPageArea.aStart.Tab()),aRectCellPosition );
+ mvRight[i] = aRectCellPosition.Right();
+ }
+ }
+ else
+ {
+ pLocationData->GetCellPosition( aPageArea.aEnd, aRectPosition );
+ nLeftPosition = aRectPosition.Right()+1;
+
+ pLocationData->GetCellPosition( aPageArea.aStart,aRectCellPosition );
+ mvRight[ aPageArea.aEnd.Col() ] = aRectCellPosition.Left();
+ for( SCCOL i = aPageArea.aEnd.Col(); i > aPageArea.aStart.Col(); i-- )
+ {
+ pLocationData->GetCellPosition( ScAddress( i,aPageArea.aEnd.Row(),aPageArea.aEnd.Tab()),aRectCellPosition );
+ mvRight[ i-1 ] = mvRight[ i ] + aRectCellPosition.Right() - aRectCellPosition.Left() + 1;
+ }
+ }
+ }
+
+ if (nPrinted) // if not, draw everything grey
+ {
+ aLocalPageSize = pPrintFunc->GetPageSize();
+ aLocalPageSize.setWidth(
+ o3tl::convert(aLocalPageSize.Width(), o3tl::Length::twip, o3tl::Length::mm100));
+ aLocalPageSize.setHeight(
+ o3tl::convert(aLocalPageSize.Height(), o3tl::Length::twip, o3tl::Length::mm100));
+
+ nLeftMargin = o3tl::convert(nLeftMargin, o3tl::Length::twip, o3tl::Length::mm100);
+ nRightMargin = o3tl::convert(nRightMargin, o3tl::Length::twip, o3tl::Length::mm100);
+ nTopMargin = o3tl::convert(nTopMargin, o3tl::Length::twip, o3tl::Length::mm100);
+ nBottomMargin = o3tl::convert(nBottomMargin, o3tl::Length::twip, o3tl::Length::mm100);
+ constexpr auto md = o3tl::getConversionMulDiv(o3tl::Length::twip, o3tl::Length::mm10);
+ const auto m = md.first * mnScale, d = md.second * 100;
+ nHeaderHeight = o3tl::convert(nHeaderHeight, m, d) + nTopMargin;
+ nFooterHeight = o3tl::convert(nFooterHeight, m, d) + nBottomMargin;
+ }
+
+ if (!bStateValid)
+ {
+ pPrintFunc->GetPrintState( aState );
+ aState.nDocPages = nTotalPages;
+ bStateValid = true;
+ }
+ }
+
+ if ( !bDoPrint )
+ return;
+
+ tools::Long nPageEndX = aLocalPageSize.Width() - aOffset.X();
+ tools::Long nPageEndY = aLocalPageSize.Height() - aOffset.Y();
+ if ( !bValidPage )
+ nPageEndX = nPageEndY = 0;
+
+ Size aWinSize = GetOutDev()->GetOutputSize();
+ Point aWinEnd( aWinSize.Width(), aWinSize.Height() );
+ bool bRight = nPageEndX <= aWinEnd.X();
+ bool bBottom = nPageEndY <= aWinEnd.Y();
+
+ if (!nTotalPages)
+ {
+ // There is no data to print. Print a friendly warning message and
+ // bail out.
+
+ SetMapMode(aMMMode);
+
+ // Draw background first.
+ GetOutDev()->SetLineColor();
+ GetOutDev()->SetFillColor(aBackColor);
+ GetOutDev()->DrawRect(tools::Rectangle(0, 0, aWinEnd.X(), aWinEnd.Y()));
+
+ const ScPatternAttr& rDefPattern =
+ rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN);
+
+ std::unique_ptr<ScEditEngineDefaulter> pEditEng(
+ new ScEditEngineDefaulter(EditEngine::CreatePool().get(), true));
+
+ pEditEng->SetRefMapMode(aMMMode);
+ auto pEditDefaults = std::make_unique<SfxItemSet>( pEditEng->GetEmptyItemSet() );
+ rDefPattern.FillEditItemSet(pEditDefaults.get());
+ pEditDefaults->Put(SvxColorItem(COL_LIGHTGRAY, EE_CHAR_COLOR));
+ pEditEng->SetDefaults(std::move(pEditDefaults));
+
+ OUString aEmptyMsg;
+ if (mbHasEmptyRangeTable)
+ aEmptyMsg = ScResId(STR_PRINT_PREVIEW_EMPTY_RANGE);
+ else
+ aEmptyMsg = ScResId(STR_PRINT_PREVIEW_NODATA);
+
+ tools::Long nHeight = 3000;
+ pEditEng->SetDefaultItem(SvxFontHeightItem(nHeight, 100, EE_CHAR_FONTHEIGHT));
+ pEditEng->SetDefaultItem(SvxFontHeightItem(nHeight, 100, EE_CHAR_FONTHEIGHT_CJK));
+ pEditEng->SetDefaultItem(SvxFontHeightItem(nHeight, 100, EE_CHAR_FONTHEIGHT_CTL));
+
+ pEditEng->SetTextCurrentDefaults(aEmptyMsg);
+
+ Point aCenter(
+ (aWinEnd.X() - pEditEng->CalcTextWidth())/2,
+ (aWinEnd.Y() - pEditEng->GetTextHeight())/2);
+
+ pEditEng->Draw(*GetOutDev(), aCenter);
+
+ return;
+ }
+
+ if( bPageMargin && bValidPage )
+ {
+ SetMapMode(aMMMode);
+ GetOutDev()->SetLineColor( COL_BLACK );
+ DrawInvert( static_cast<tools::Long>( nTopMargin - aOffset.Y() ), PointerStyle::VSizeBar );
+ DrawInvert( static_cast<tools::Long>(nPageEndY - nBottomMargin ), PointerStyle::VSizeBar );
+ DrawInvert( static_cast<tools::Long>( nLeftMargin - aOffset.X() ), PointerStyle::HSizeBar );
+ DrawInvert( static_cast<tools::Long>( nPageEndX - nRightMargin ) , PointerStyle::HSizeBar );
+ if( bHeaderOn )
+ {
+ DrawInvert( nHeaderHeight - aOffset.Y(), PointerStyle::VSizeBar );
+ }
+ if( bFooterOn )
+ {
+ DrawInvert( nPageEndY - nFooterHeight, PointerStyle::VSizeBar );
+ }
+
+ SetMapMode( MapMode( MapUnit::MapPixel ) );
+ for( int i= aPageArea.aStart.Col(); i<= aPageArea.aEnd.Col(); i++ )
+ {
+ Point aColumnTop = LogicToPixel( Point( 0, -aOffset.Y() ) ,aMMMode );
+ GetOutDev()->SetLineColor( COL_BLACK );
+ GetOutDev()->SetFillColor( COL_BLACK );
+ GetOutDev()->DrawRect( tools::Rectangle( Point( mvRight[i] - 2, aColumnTop.Y() ),Point( mvRight[i] + 2 , 4 + aColumnTop.Y()) ));
+ GetOutDev()->DrawLine( Point( mvRight[i], aColumnTop.Y() ), Point( mvRight[i], 10 + aColumnTop.Y()) );
+ }
+ SetMapMode( aMMMode );
+ }
+
+ if (bRight || bBottom)
+ {
+ SetMapMode(aMMMode);
+ GetOutDev()->SetLineColor();
+ GetOutDev()->SetFillColor(aBackColor);
+ if (bRight)
+ GetOutDev()->DrawRect(tools::Rectangle(nPageEndX,0, aWinEnd.X(),aWinEnd.Y()));
+ if (bBottom)
+ {
+ if (bRight)
+ GetOutDev()->DrawRect(tools::Rectangle(0,nPageEndY, nPageEndX,aWinEnd.Y())); // Corner not duplicated
+ else
+ GetOutDev()->DrawRect(tools::Rectangle(0,nPageEndY, aWinEnd.X(),aWinEnd.Y()));
+ }
+ }
+
+ if ( !bValidPage )
+ return;
+
+ Color aBorderColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
+
+ // draw border
+
+ if ( aOffset.X() <= 0 || aOffset.Y() <= 0 || bRight || bBottom )
+ {
+ GetOutDev()->SetLineColor( aBorderColor );
+ GetOutDev()->SetFillColor();
+
+ tools::Rectangle aPixel( LogicToPixel( tools::Rectangle( -aOffset.X(), -aOffset.Y(), nPageEndX, nPageEndY ) ) );
+ aPixel.AdjustRight( -1 );
+ aPixel.AdjustBottom( -1 );
+ GetOutDev()->DrawRect( PixelToLogic( aPixel ) );
+ }
+
+ // draw shadow
+
+ GetOutDev()->SetLineColor();
+ GetOutDev()->SetFillColor( aBorderColor );
+
+ tools::Rectangle aPixel;
+
+ aPixel = LogicToPixel( tools::Rectangle( nPageEndX, -aOffset.Y(), nPageEndX, nPageEndY ) );
+ aPixel.AdjustTop(SC_PREVIEW_SHADOWSIZE );
+ aPixel.AdjustRight(SC_PREVIEW_SHADOWSIZE - 1 );
+ aPixel.AdjustBottom(SC_PREVIEW_SHADOWSIZE - 1 );
+ GetOutDev()->DrawRect( PixelToLogic( aPixel ) );
+
+ aPixel = LogicToPixel( tools::Rectangle( -aOffset.X(), nPageEndY, nPageEndX, nPageEndY ) );
+ aPixel.AdjustLeft(SC_PREVIEW_SHADOWSIZE );
+ aPixel.AdjustRight(SC_PREVIEW_SHADOWSIZE - 1 );
+ aPixel.AdjustBottom(SC_PREVIEW_SHADOWSIZE - 1 );
+ GetOutDev()->DrawRect( PixelToLogic( aPixel ) );
+}
+
+void ScPreview::Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& /* rRect */ )
+{
+ bool bWasInPaint = bInPaint; // nested calls shouldn't be necessary, but allow for now
+ bInPaint = true;
+
+ if (bPageMargin)
+ GetLocationData(); // fill location data for column positions
+ DoPrint( nullptr );
+ pViewShell->UpdateScrollBars();
+
+ bInPaint = bWasInPaint;
+}
+
+void ScPreview::Command( const CommandEvent& rCEvt )
+{
+ CommandEventId nCmd = rCEvt.GetCommand();
+ if ( nCmd == CommandEventId::Wheel || nCmd == CommandEventId::StartAutoScroll || nCmd == CommandEventId::AutoScroll )
+ {
+ bool bDone = pViewShell->ScrollCommand( rCEvt );
+ if (!bDone)
+ Window::Command(rCEvt);
+ }
+ else if ( nCmd == CommandEventId::ContextMenu )
+ SfxDispatcher::ExecutePopup();
+ else
+ Window::Command( rCEvt );
+}
+
+void ScPreview::KeyInput( const KeyEvent& rKEvt )
+{
+ // The + and - keys can't be configured as accelerator entries, so they must be handled directly
+ // (in ScPreview, not ScPreviewShell -> only if the preview window has the focus)
+
+ const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode();
+ sal_uInt16 nKey = rKeyCode.GetCode();
+ bool bHandled = false;
+ if(!rKeyCode.GetModifier())
+ {
+ sal_uInt16 nSlot = 0;
+ switch(nKey)
+ {
+ case KEY_ADD: nSlot = SID_ZOOM_IN; break;
+ case KEY_ESCAPE: nSlot = ScViewUtil::IsFullScreen( *pViewShell ) ? SID_CANCEL : SID_PREVIEW_CLOSE; break;
+ case KEY_SUBTRACT: nSlot = SID_ZOOM_OUT; break;
+ }
+ if(nSlot)
+ {
+ bHandled = true;
+ pViewShell->GetViewFrame()->GetDispatcher()->Execute( nSlot, SfxCallMode::ASYNCHRON );
+ }
+ }
+
+ if ( !bHandled && !pViewShell->KeyInput(rKEvt) )
+ Window::KeyInput(rKEvt);
+}
+
+const ScPreviewLocationData& ScPreview::GetLocationData()
+{
+ if ( !pLocationData )
+ {
+ pLocationData.reset( new ScPreviewLocationData( &pDocShell->GetDocument(), GetOutDev() ) );
+ bLocationValid = false;
+ }
+ if ( !bLocationValid )
+ {
+ pLocationData->Clear();
+ DoPrint( pLocationData.get() );
+ bLocationValid = true;
+ }
+ return *pLocationData;
+}
+
+void ScPreview::DataChanged(bool bNewTime)
+{
+ if (bNewTime)
+ aDateTime = DateTime( DateTime::SYSTEM );
+
+ bValid = false;
+ InvalidateLocationData( SfxHintId::ScDataChanged );
+ Invalidate();
+}
+
+OUString ScPreview::GetPosString()
+{
+ if (!bValid)
+ {
+ CalcPages();
+ UpdateDrawView(); // The table eventually changes
+ }
+
+ OUString aString = ScResId( STR_PAGE ) +
+ " " + OUString::number(nPageNo+1);
+
+ if (nTabsTested >= nTabCount)
+ aString += " / " + OUString::number(nTotalPages);
+
+ return aString;
+}
+
+void ScPreview::SetZoom(sal_uInt16 nNewZoom)
+{
+ if (nNewZoom < 20)
+ nNewZoom = 20;
+ if (nNewZoom > 400)
+ nNewZoom = 400;
+ if (nNewZoom == nZoom)
+ return;
+
+ nZoom = nNewZoom;
+
+ // apply new MapMode and call UpdateScrollBars to update aOffset
+
+ Fraction aPreviewZoom( nZoom, 100 );
+ Fraction aHorPrevZoom( static_cast<tools::Long>( 100 * nZoom / pDocShell->GetOutputFactor() ), 10000 );
+ MapMode aMMMode( MapUnit::Map100thMM, Point(), aHorPrevZoom, aPreviewZoom );
+ SetMapMode( aMMMode );
+
+ bInSetZoom = true; // don't scroll during SetYOffset in UpdateScrollBars
+ pViewShell->UpdateNeededScrollBars(true);
+ bInSetZoom = false;
+
+ bStateValid = false;
+ InvalidateLocationData( SfxHintId::ScAccVisAreaChanged );
+ DoInvalidate();
+ Invalidate();
+}
+
+void ScPreview::SetPageNo( tools::Long nPage )
+{
+ nPageNo = nPage;
+ RecalcPages();
+ UpdateDrawView(); // The table eventually changes
+ InvalidateLocationData( SfxHintId::ScDataChanged );
+ Invalidate();
+}
+
+tools::Long ScPreview::GetFirstPage(SCTAB nTabP)
+{
+ SCTAB nDocTabCount = pDocShell->GetDocument().GetTableCount();
+ if (nTabP >= nDocTabCount)
+ nTabP = nDocTabCount-1;
+
+ tools::Long nPage = 0;
+ if (nTabP>0)
+ {
+ CalcPages();
+ if (nTabP >= static_cast<SCTAB>(nPages.size()) )
+ OSL_FAIL("nPages out of bounds, FIX IT");
+ UpdateDrawView(); // The table eventually changes
+
+ for (SCTAB i=0; i<nTabP; i++)
+ nPage += nPages[i];
+
+ // An empty Table on the previous Page
+
+ if ( nPages[nTabP]==0 && nPage > 0 )
+ --nPage;
+ }
+
+ return nPage;
+}
+
+static Size lcl_GetDocPageSize( const ScDocument* pDoc, SCTAB nTab )
+{
+ OUString aName = pDoc->GetPageStyle( nTab );
+ ScStyleSheetPool* pStylePool = pDoc->GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aName, SfxStyleFamily::Page );
+ if ( pStyleSheet )
+ {
+ SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
+ return rStyleSet.Get(ATTR_PAGE_SIZE).GetSize();
+ }
+ else
+ {
+ OSL_FAIL( "PageStyle not found" );
+ return Size();
+ }
+}
+
+sal_uInt16 ScPreview::GetOptimalZoom(bool bWidthOnly)
+{
+ double nWinScaleX = ScGlobal::nScreenPPTX / pDocShell->GetOutputFactor();
+ double nWinScaleY = ScGlobal::nScreenPPTY;
+ Size aWinSize = GetOutputSizePixel();
+
+ // desired margin is 0.25cm in default MapMode (like Writer),
+ // but some additional margin is introduced by integer scale values
+ // -> add only 0.10cm, so there is some margin in all cases.
+ Size aMarginSize( LogicToPixel(Size(100, 100), MapMode(MapUnit::Map100thMM)) );
+ aWinSize.AdjustWidth( -(2 * aMarginSize.Width()) );
+ aWinSize.AdjustHeight( -(2 * aMarginSize.Height()) );
+
+ Size aLocalPageSize = lcl_GetDocPageSize( &pDocShell->GetDocument(), nTab );
+ if ( aLocalPageSize.Width() && aLocalPageSize.Height() )
+ {
+ tools::Long nZoomX = static_cast<tools::Long>( aWinSize.Width() * 100 / ( aLocalPageSize.Width() * nWinScaleX ));
+ tools::Long nZoomY = static_cast<tools::Long>( aWinSize.Height() * 100 / ( aLocalPageSize.Height() * nWinScaleY ));
+
+ tools::Long nOptimal = nZoomX;
+ if (!bWidthOnly && nZoomY<nOptimal)
+ nOptimal = nZoomY;
+
+ if (nOptimal<20)
+ nOptimal = 20;
+ if (nOptimal>400)
+ nOptimal = 400;
+
+ return static_cast<sal_uInt16>(nOptimal);
+ }
+ else
+ return nZoom;
+}
+
+void ScPreview::SetXOffset( tools::Long nX )
+{
+ if ( aOffset.X() == nX )
+ return;
+
+ if (bValid)
+ {
+ tools::Long nDif = LogicToPixel(aOffset).X() - LogicToPixel(Point(nX,0)).X();
+ aOffset.setX( nX );
+ if (nDif && !bInSetZoom)
+ {
+ MapMode aOldMode = GetMapMode();
+ SetMapMode(MapMode(MapUnit::MapPixel));
+ Scroll( nDif, 0 );
+ SetMapMode(aOldMode);
+ }
+ }
+ else
+ {
+ aOffset.setX( nX );
+ if (!bInSetZoom)
+ Invalidate();
+ }
+ InvalidateLocationData( SfxHintId::ScAccVisAreaChanged );
+ Invalidate();
+}
+
+void ScPreview::SetYOffset( tools::Long nY )
+{
+ if ( aOffset.Y() == nY )
+ return;
+
+ if (bValid)
+ {
+ tools::Long nDif = LogicToPixel(aOffset).Y() - LogicToPixel(Point(0,nY)).Y();
+ aOffset.setY( nY );
+ if (nDif && !bInSetZoom)
+ {
+ MapMode aOldMode = GetMapMode();
+ SetMapMode(MapMode(MapUnit::MapPixel));
+ Scroll( 0, nDif );
+ SetMapMode(aOldMode);
+ }
+ }
+ else
+ {
+ aOffset.setY( nY );
+ if (!bInSetZoom)
+ Invalidate();
+ }
+ InvalidateLocationData( SfxHintId::ScAccVisAreaChanged );
+ Invalidate();
+}
+
+void ScPreview::DoInvalidate()
+{
+ // If the whole GetState of the shell is called
+ // The Invalidate must come behind asynchronously
+
+ if (bInGetState)
+ Application::PostUserEvent( LINK( this, ScPreview, InvalidateHdl ), nullptr, true );
+ else
+ StaticInvalidate(); // Immediately
+}
+
+void ScPreview::StaticInvalidate()
+{
+ // static method, because it's called asynchronously
+ // -> must use current viewframe
+
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ if (!pViewFrm)
+ return;
+
+ SfxBindings& rBindings = pViewFrm->GetBindings();
+ rBindings.Invalidate(SID_STATUS_DOCPOS);
+ rBindings.Invalidate(SID_ROWCOL_SELCOUNT);
+ rBindings.Invalidate(SID_STATUS_PAGESTYLE);
+ rBindings.Invalidate(SID_PREVIEW_PREVIOUS);
+ rBindings.Invalidate(SID_PREVIEW_NEXT);
+ rBindings.Invalidate(SID_PREVIEW_FIRST);
+ rBindings.Invalidate(SID_PREVIEW_LAST);
+ rBindings.Invalidate(SID_ATTR_ZOOM);
+ rBindings.Invalidate(SID_ZOOM_IN);
+ rBindings.Invalidate(SID_ZOOM_OUT);
+ rBindings.Invalidate(SID_PREVIEW_SCALINGFACTOR);
+ rBindings.Invalidate(SID_ATTR_ZOOMSLIDER);
+}
+
+IMPL_STATIC_LINK_NOARG( ScPreview, InvalidateHdl, void*, void )
+{
+ StaticInvalidate();
+}
+
+void ScPreview::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged(rDCEvt);
+
+ 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::FONTS )
+ pDocShell->UpdateFontList();
+
+ // #i114518# Paint of form controls may modify the window's settings.
+ // Ignore the event if it is called from within Paint.
+ if ( !bInPaint )
+ {
+ if ( rDCEvt.GetType() == DataChangedEventType::SETTINGS &&
+ (rDCEvt.GetFlags() & AllSettingsFlags::STYLE) )
+ {
+ // scroll bar size may have changed
+ pViewShell->InvalidateBorder(); // calls OuterResizePixel
+ }
+ Invalidate();
+ InvalidateLocationData( SfxHintId::ScDataChanged );
+ }
+}
+
+void ScPreview::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ Fraction aPreviewZoom( nZoom, 100 );
+ Fraction aHorPrevZoom( static_cast<tools::Long>( 100 * nZoom / pDocShell->GetOutputFactor() ), 10000 );
+ MapMode aMMMode( MapUnit::Map100thMM, Point(), aHorPrevZoom, aPreviewZoom );
+
+ aButtonDownChangePoint = PixelToLogic( rMEvt.GetPosPixel(),aMMMode );
+ aButtonDownPt = PixelToLogic( rMEvt.GetPosPixel(),aMMMode );
+
+ CaptureMouse();
+
+ if( rMEvt.IsLeft() && GetPointer() == PointerStyle::HSizeBar )
+ {
+ SetMapMode( aMMMode );
+ if( bLeftRulerChange )
+ {
+ DrawInvert( aButtonDownChangePoint.X(), PointerStyle::HSizeBar );
+ bLeftRulerMove = true;
+ bRightRulerMove = false;
+ }
+ else if( bRightRulerChange )
+ {
+ DrawInvert( aButtonDownChangePoint.X(), PointerStyle::HSizeBar );
+ bLeftRulerMove = false;
+ bRightRulerMove = true;
+ }
+ }
+
+ if( rMEvt.IsLeft() && GetPointer() == PointerStyle::VSizeBar )
+ {
+ SetMapMode( aMMMode );
+ if( bTopRulerChange )
+ {
+ DrawInvert( aButtonDownChangePoint.Y(), PointerStyle::VSizeBar );
+ bTopRulerMove = true;
+ bBottomRulerMove = false;
+ }
+ else if( bBottomRulerChange )
+ {
+ DrawInvert( aButtonDownChangePoint.Y(), PointerStyle::VSizeBar );
+ bTopRulerMove = false;
+ bBottomRulerMove = true;
+ }
+ else if( bHeaderRulerChange )
+ {
+ DrawInvert( aButtonDownChangePoint.Y(), PointerStyle::VSizeBar );
+ bHeaderRulerMove = true;
+ bFooterRulerMove = false;
+ }
+ else if( bFooterRulerChange )
+ {
+ DrawInvert( aButtonDownChangePoint.Y(), PointerStyle::VSizeBar );
+ bHeaderRulerMove = false;
+ bFooterRulerMove = true;
+ }
+ }
+
+ if( !(rMEvt.IsLeft() && GetPointer() == PointerStyle::HSplit) )
+ return;
+
+ Point aNowPt = rMEvt.GetPosPixel();
+ SCCOL i = 0;
+ for( i = aPageArea.aStart.Col(); i<= aPageArea.aEnd.Col(); i++ )
+ {
+ if( aNowPt.X() < mvRight[i] + 2 && aNowPt.X() > mvRight[i] - 2 )
+ {
+ nColNumberButtonDown = i;
+ break;
+ }
+ }
+ if( i == aPageArea.aEnd.Col()+1 )
+ return;
+
+ SetMapMode( aMMMode );
+ if( nColNumberButtonDown == aPageArea.aStart.Col() )
+ DrawInvert( PixelToLogic( Point( nLeftPosition, 0 ),aMMMode ).X() ,PointerStyle::HSplit );
+ else
+ DrawInvert( PixelToLogic( Point( mvRight[ nColNumberButtonDown-1 ], 0 ),aMMMode ).X() ,PointerStyle::HSplit );
+
+ DrawInvert( aButtonDownChangePoint.X(), PointerStyle::HSplit );
+ bColRulerMove = true;
+}
+
+void ScPreview::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ Fraction aPreviewZoom( nZoom, 100 );
+ Fraction aHorPrevZoom( static_cast<tools::Long>( 100 * nZoom / pDocShell->GetOutputFactor() ), 10000 );
+ MapMode aMMMode( MapUnit::Map100thMM, Point(), aHorPrevZoom, aPreviewZoom );
+
+ aButtonUpPt = PixelToLogic( rMEvt.GetPosPixel(),aMMMode );
+
+ tools::Long nWidth = lcl_GetDocPageSize(&pDocShell->GetDocument(), nTab).Width();
+ tools::Long nHeight = lcl_GetDocPageSize(&pDocShell->GetDocument(), nTab).Height();
+
+ if( rMEvt.IsLeft() && GetPointer() == PointerStyle::HSizeBar )
+ {
+ SetPointer( PointerStyle::Arrow );
+
+ ScDocument& rDoc = pDocShell->GetDocument();
+ OUString aOldName = rDoc.GetPageStyle( nTab );
+ bool bUndo = rDoc.IsUndoEnabled();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aOldName, SfxStyleFamily::Page );
+
+ if ( pStyleSheet )
+ {
+ bool bMoveRulerAction= true;
+ ScStyleSaveData aOldData;
+ if( bUndo )
+ aOldData.InitFromStyle( pStyleSheet );
+
+ SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
+
+ SvxLRSpaceItem aLRItem = rStyleSet.Get( ATTR_LRSPACE );
+
+ if(( bLeftRulerChange || bRightRulerChange ) && ( aButtonUpPt.X() <= ( 0 - aOffset.X() ) || aButtonUpPt.X() > o3tl::convert(nWidth, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.X() ) )
+ {
+ bMoveRulerAction = false;
+ Invalidate(tools::Rectangle(0, 0, 10000, 10000));
+ }
+ else if( bLeftRulerChange && ( o3tl::convert(aButtonUpPt.X(), o3tl::Length::mm100, o3tl::Length::twip) > nWidth - aLRItem.GetRight() - o3tl::convert(aOffset.X(), o3tl::Length::mm100, o3tl::Length::twip) ) )
+ {
+ bMoveRulerAction = false;
+ Invalidate(tools::Rectangle(0, 0, 10000, 10000));
+ }
+ else if( bRightRulerChange && ( o3tl::convert(aButtonUpPt.X(), o3tl::Length::mm100, o3tl::Length::twip) < aLRItem.GetLeft() - o3tl::convert(aOffset.X(), o3tl::Length::mm100, o3tl::Length::twip) ) )
+ {
+ bMoveRulerAction = false;
+ Invalidate(tools::Rectangle(0, 0, 10000, 10000));
+ }
+ else if( aButtonDownPt.X() == aButtonUpPt.X() )
+ {
+ bMoveRulerAction = false;
+ DrawInvert( aButtonUpPt.X(), PointerStyle::HSizeBar );
+ }
+ if( bMoveRulerAction )
+ {
+ ScDocShellModificator aModificator( *pDocShell );
+ if( bLeftRulerChange && bLeftRulerMove )
+ {
+ aLRItem.SetLeft(o3tl::convert( aButtonUpPt.X(), o3tl::Length::mm100, o3tl::Length::twip) + o3tl::convert(aOffset.X(), o3tl::Length::mm100, o3tl::Length::twip));
+ rStyleSet.Put( aLRItem );
+ pDocShell->SetModified();
+ }
+ else if( bRightRulerChange && bRightRulerMove )
+ {
+ aLRItem.SetRight(nWidth - o3tl::convert(aButtonUpPt.X(), o3tl::Length::mm100, o3tl::Length::twip) - o3tl::convert(aOffset.X(), o3tl::Length::mm100, o3tl::Length::twip));
+ rStyleSet.Put( aLRItem );
+ pDocShell->SetModified();
+ }
+
+ ScStyleSaveData aNewData;
+ aNewData.InitFromStyle( pStyleSheet );
+ if( bUndo )
+ {
+ pDocShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoModifyStyle>( pDocShell, SfxStyleFamily::Page,
+ aOldData, aNewData ) );
+ }
+
+ if ( ValidTab( nTab ) )
+ {
+ ScPrintFunc aPrintFunc( GetOutDev(), pDocShell, nTab );
+ aPrintFunc.UpdatePages();
+ }
+
+ tools::Rectangle aRect(0,0,10000,10000);
+ Invalidate(aRect);
+ aModificator.SetDocumentModified();
+ bLeftRulerChange = false;
+ bRightRulerChange = false;
+ }
+ }
+ bLeftRulerMove = false;
+ bRightRulerMove = false;
+ }
+
+ if( rMEvt.IsLeft() && GetPointer() == PointerStyle::VSizeBar )
+ {
+ SetPointer( PointerStyle::Arrow );
+
+ bool bMoveRulerAction = true;
+ if( ( bTopRulerChange || bBottomRulerChange || bHeaderRulerChange || bFooterRulerChange ) && ( aButtonUpPt.Y() <= ( 0 - aOffset.Y() ) || aButtonUpPt.Y() > o3tl::convert(nHeight, o3tl::Length::twip, o3tl::Length::mm100) -aOffset.Y() ) )
+ {
+ bMoveRulerAction = false;
+ Invalidate(tools::Rectangle(0, 0, 10000, 10000));
+ }
+ else if( aButtonDownPt.Y() == aButtonUpPt.Y() )
+ {
+ bMoveRulerAction = false;
+ DrawInvert( aButtonUpPt.Y(), PointerStyle::VSizeBar );
+ }
+ if( bMoveRulerAction )
+ {
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bUndo = rDoc.IsUndoEnabled();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( rDoc.GetPageStyle( nTab ), SfxStyleFamily::Page );
+ OSL_ENSURE( pStyleSheet, "PageStyle not found" );
+ if ( pStyleSheet )
+ {
+ ScDocShellModificator aModificator( *pDocShell );
+ ScStyleSaveData aOldData;
+ if( bUndo )
+ aOldData.InitFromStyle( pStyleSheet );
+
+ SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
+
+ SvxULSpaceItem aULItem = rStyleSet.Get( ATTR_ULSPACE );
+
+ if( bTopRulerMove && bTopRulerChange )
+ {
+ aULItem.SetUpperValue(o3tl::convert(aButtonUpPt.Y(), o3tl::Length::mm100, o3tl::Length::twip) + o3tl::convert(aOffset.Y(), o3tl::Length::mm100, o3tl::Length::twip));
+ rStyleSet.Put( aULItem );
+ pDocShell->SetModified();
+ }
+ else if( bBottomRulerMove && bBottomRulerChange )
+ {
+ aULItem.SetLowerValue(nHeight - o3tl::convert(aButtonUpPt.Y(), o3tl::Length::mm100, o3tl::Length::twip) - o3tl::convert(aOffset.Y(), o3tl::Length::mm100, o3tl::Length::twip));
+ rStyleSet.Put( aULItem );
+ pDocShell->SetModified();
+ }
+ else if( bHeaderRulerMove && bHeaderRulerChange )
+ {
+ if ( const SvxSetItem* pSetItem = rStyleSet.GetItemIfSet( ATTR_PAGE_HEADERSET, false ) )
+ {
+ const SfxItemSet& rHeaderSet = pSetItem->GetItemSet();
+ Size aHeaderSize = rHeaderSet.Get(ATTR_PAGE_SIZE).GetSize();
+ aHeaderSize.setHeight(o3tl::convert( aButtonUpPt.Y(), o3tl::Length::mm100, o3tl::Length::twip) + o3tl::convert(aOffset.Y(), o3tl::Length::mm100, o3tl::Length::twip) - aULItem.GetUpper());
+ aHeaderSize.setHeight( aHeaderSize.Height() * 100 / mnScale );
+ SvxSetItem aNewHeader( rStyleSet.Get(ATTR_PAGE_HEADERSET) );
+ aNewHeader.GetItemSet().Put( SvxSizeItem( ATTR_PAGE_SIZE, aHeaderSize ) );
+ rStyleSet.Put( aNewHeader );
+ pDocShell->SetModified();
+ }
+ }
+ else if( bFooterRulerMove && bFooterRulerChange )
+ {
+ if( const SvxSetItem* pSetItem = rStyleSet.GetItemIfSet( ATTR_PAGE_FOOTERSET, false ) )
+ {
+ const SfxItemSet& rFooterSet = pSetItem->GetItemSet();
+ Size aFooterSize = rFooterSet.Get(ATTR_PAGE_SIZE).GetSize();
+ aFooterSize.setHeight(nHeight - o3tl::convert(aButtonUpPt.Y(), o3tl::Length::mm100, o3tl::Length::twip) - o3tl::convert(aOffset.Y(), o3tl::Length::mm100, o3tl::Length::twip) - aULItem.GetLower());
+ aFooterSize.setHeight( aFooterSize.Height() * 100 / mnScale );
+ SvxSetItem aNewFooter( rStyleSet.Get(ATTR_PAGE_FOOTERSET) );
+ aNewFooter.GetItemSet().Put( SvxSizeItem( ATTR_PAGE_SIZE, aFooterSize ) );
+ rStyleSet.Put( aNewFooter );
+ pDocShell->SetModified();
+ }
+ }
+
+ ScStyleSaveData aNewData;
+ aNewData.InitFromStyle( pStyleSheet );
+ if( bUndo )
+ {
+ pDocShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoModifyStyle>( pDocShell, SfxStyleFamily::Page,
+ aOldData, aNewData ) );
+ }
+
+ if ( ValidTab( nTab ) )
+ {
+ ScPrintFunc aPrintFunc( GetOutDev(), pDocShell, nTab );
+ aPrintFunc.UpdatePages();
+ }
+
+ tools::Rectangle aRect(0, 0, 10000, 10000);
+ Invalidate(aRect);
+ aModificator.SetDocumentModified();
+ bTopRulerChange = false;
+ bBottomRulerChange = false;
+ bHeaderRulerChange = false;
+ bFooterRulerChange = false;
+ }
+ }
+ bTopRulerMove = false;
+ bBottomRulerMove = false;
+ bHeaderRulerMove = false;
+ bFooterRulerMove = false;
+ }
+ if( rMEvt.IsLeft() && GetPointer() == PointerStyle::HSplit )
+ {
+ SetPointer(PointerStyle::Arrow);
+ ScDocument& rDoc = pDocShell->GetDocument();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ bool bMoveRulerAction = true;
+ if( aButtonDownPt.X() == aButtonUpPt.X() )
+ {
+ bMoveRulerAction = false;
+ if( nColNumberButtonDown == aPageArea.aStart.Col() )
+ DrawInvert( PixelToLogic( Point( nLeftPosition, 0 ),aMMMode ).X() ,PointerStyle::HSplit );
+ else
+ DrawInvert( PixelToLogic( Point( mvRight[ nColNumberButtonDown-1 ], 0 ),aMMMode ).X() ,PointerStyle::HSplit );
+ DrawInvert( aButtonUpPt.X(), PointerStyle::HSplit );
+ }
+ if( bMoveRulerAction )
+ {
+ tools::Long nNewColWidth = 0;
+ std::vector<sc::ColRowSpan> aCols(1, sc::ColRowSpan(nColNumberButtonDown,nColNumberButtonDown));
+
+ constexpr auto md = o3tl::getConversionMulDiv(o3tl::Length::mm100, o3tl::Length::twip);
+ const auto m = md.first * 100, d = md.second * mnScale;
+ if( !bLayoutRTL )
+ {
+ nNewColWidth = o3tl::convert(PixelToLogic( Point( rMEvt.GetPosPixel().X() - mvRight[ nColNumberButtonDown ], 0), aMMMode ).X(), m, d);
+ nNewColWidth += pDocShell->GetDocument().GetColWidth( nColNumberButtonDown, nTab );
+ }
+ else
+ {
+
+ nNewColWidth = o3tl::convert(PixelToLogic( Point( mvRight[ nColNumberButtonDown ] - rMEvt.GetPosPixel().X(), 0), aMMMode ).X(), m, d);
+ nNewColWidth += pDocShell->GetDocument().GetColWidth( nColNumberButtonDown, nTab );
+ }
+
+ if( nNewColWidth >= 0 )
+ {
+ pDocShell->GetDocFunc().SetWidthOrHeight(
+ true, aCols, nTab, SC_SIZE_DIRECT, static_cast<sal_uInt16>(nNewColWidth), true, true);
+ pDocShell->SetModified();
+ }
+ if ( ValidTab( nTab ) )
+ {
+ ScPrintFunc aPrintFunc( GetOutDev(), pDocShell, nTab );
+ aPrintFunc.UpdatePages();
+ }
+ tools::Rectangle aRect(0, 0, 10000, 10000);
+ Invalidate(aRect);
+ }
+ bColRulerMove = false;
+ }
+ ReleaseMouse();
+}
+
+void ScPreview::MouseMove( const MouseEvent& rMEvt )
+{
+ Fraction aPreviewZoom( nZoom, 100 );
+ Fraction aHorPrevZoom( static_cast<tools::Long>( 100 * nZoom / pDocShell->GetOutputFactor() ), 10000 );
+ MapMode aMMMode( MapUnit::Map100thMM, Point(), aHorPrevZoom, aPreviewZoom );
+ Point aMouseMovePoint = PixelToLogic( rMEvt.GetPosPixel(), aMMMode );
+
+ tools::Long nLeftMargin = 0;
+ tools::Long nRightMargin = 0;
+ tools::Long nTopMargin = 0;
+ tools::Long nBottomMargin = 0;
+
+ tools::Long nWidth = lcl_GetDocPageSize(&pDocShell->GetDocument(), nTab).Width();
+ tools::Long nHeight = lcl_GetDocPageSize(&pDocShell->GetDocument(), nTab).Height();
+
+ if ( nPageNo < nTotalPages )
+ {
+ ScPrintOptions aOptions = SC_MOD()->GetPrintOptions();
+
+ std::unique_ptr<ScPrintFunc, o3tl::default_delete<ScPrintFunc>> pPrintFunc;
+ if (bStateValid)
+ pPrintFunc.reset(new ScPrintFunc( GetOutDev(), pDocShell, aState, &aOptions ));
+ else
+ pPrintFunc.reset(new ScPrintFunc( GetOutDev(), pDocShell, nTab, nFirstAttr[nTab], nTotalPages, nullptr, &aOptions ));
+
+ nLeftMargin = o3tl::convert(pPrintFunc->GetLeftMargin(), o3tl::Length::twip, o3tl::Length::mm100) - aOffset.X();
+ nRightMargin = o3tl::convert(pPrintFunc->GetRightMargin(), o3tl::Length::twip, o3tl::Length::mm100);
+ nRightMargin = o3tl::convert(nWidth, o3tl::Length::twip, o3tl::Length::mm100) - nRightMargin - aOffset.X();
+ nTopMargin = o3tl::convert(pPrintFunc->GetTopMargin(), o3tl::Length::twip, o3tl::Length::mm100) - aOffset.Y();
+ nBottomMargin = o3tl::convert(pPrintFunc->GetBottomMargin(), o3tl::Length::twip, o3tl::Length::mm100);
+ nBottomMargin = o3tl::convert(nHeight, o3tl::Length::twip, o3tl::Length::mm100) - nBottomMargin - aOffset.Y();
+ if( mnScale > 0 )
+ {
+ constexpr auto md = o3tl::getConversionMulDiv(o3tl::Length::twip, o3tl::Length::mm100);
+ const auto m = md.first * mnScale, d = md.second * 100;
+ nHeaderHeight = nTopMargin + o3tl::convert(pPrintFunc->GetHeader().nHeight, m, d);
+ nFooterHeight = nBottomMargin - o3tl::convert(pPrintFunc->GetFooter().nHeight, m, d);
+ }
+ else
+ {
+ nHeaderHeight = nTopMargin + o3tl::convert(pPrintFunc->GetHeader().nHeight, o3tl::Length::twip, o3tl::Length::mm100);
+ nFooterHeight = nBottomMargin - o3tl::convert(pPrintFunc->GetFooter().nHeight, o3tl::Length::twip, o3tl::Length::mm100);
+ }
+ }
+
+ Point aPixPt( rMEvt.GetPosPixel() );
+ Point aLeftTop = LogicToPixel( Point( nLeftMargin, -aOffset.Y() ) , aMMMode );
+ Point aLeftBottom = LogicToPixel( Point( nLeftMargin, o3tl::convert(nHeight, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.Y()), aMMMode );
+ Point aRightTop = LogicToPixel( Point( nRightMargin, -aOffset.Y() ), aMMMode );
+ Point aTopLeft = LogicToPixel( Point( -aOffset.X(), nTopMargin ), aMMMode );
+ Point aTopRight = LogicToPixel( Point( o3tl::convert(nWidth, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.X(), nTopMargin ), aMMMode );
+ Point aBottomLeft = LogicToPixel( Point( -aOffset.X(), nBottomMargin ), aMMMode );
+ Point aHeaderLeft = LogicToPixel( Point( -aOffset.X(), nHeaderHeight ), aMMMode );
+ Point aFooderLeft = LogicToPixel( Point( -aOffset.X(), nFooterHeight ), aMMMode );
+
+ bool bOnColRulerChange = false;
+
+ for( SCCOL i=aPageArea.aStart.Col(); i<= aPageArea.aEnd.Col(); i++ )
+ {
+ Point aColumnTop = LogicToPixel( Point( 0, -aOffset.Y() ) ,aMMMode );
+ Point aColumnBottom = LogicToPixel( Point( 0, o3tl::convert(nHeight, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.Y()), aMMMode );
+ tools::Long nRight = i < static_cast<SCCOL>(mvRight.size()) ? mvRight[i] : 0;
+ if( aPixPt.X() < ( nRight + 2 ) && ( aPixPt.X() > ( nRight - 2 ) ) && ( aPixPt.X() < aRightTop.X() ) && ( aPixPt.X() > aLeftTop.X() )
+ && ( aPixPt.Y() > aColumnTop.Y() ) && ( aPixPt.Y() < aColumnBottom.Y() ) && !bLeftRulerMove && !bRightRulerMove
+ && !bTopRulerMove && !bBottomRulerMove && !bHeaderRulerMove && !bFooterRulerMove )
+ {
+ bOnColRulerChange = true;
+ if( !rMEvt.GetButtons() && GetPointer() == PointerStyle::HSplit )
+ nColNumberButtonDown = i;
+ break;
+ }
+ }
+
+ if( aPixPt.X() < ( aLeftTop.X() + 2 ) && aPixPt.X() > ( aLeftTop.X() - 2 ) && !bRightRulerMove )
+ {
+ bLeftRulerChange = true;
+ bRightRulerChange = false;
+ }
+ else if( aPixPt.X() < ( aRightTop.X() + 2 ) && aPixPt.X() > ( aRightTop.X() - 2 ) && !bLeftRulerMove )
+ {
+ bLeftRulerChange = false;
+ bRightRulerChange = true;
+ }
+ else if( aPixPt.Y() < ( aTopLeft.Y() + 2 ) && aPixPt.Y() > ( aTopLeft.Y() - 2 ) && !bBottomRulerMove && !bHeaderRulerMove && !bFooterRulerMove )
+ {
+ bTopRulerChange = true;
+ bBottomRulerChange = false;
+ bHeaderRulerChange = false;
+ bFooterRulerChange = false;
+ }
+ else if( aPixPt.Y() < ( aBottomLeft.Y() + 2 ) && aPixPt.Y() > ( aBottomLeft.Y() - 2 ) && !bTopRulerMove && !bHeaderRulerMove && !bFooterRulerMove )
+ {
+ bTopRulerChange = false;
+ bBottomRulerChange = true;
+ bHeaderRulerChange = false;
+ bFooterRulerChange = false;
+ }
+ else if( aPixPt.Y() < ( aHeaderLeft.Y() + 2 ) && aPixPt.Y() > ( aHeaderLeft.Y() - 2 ) && !bTopRulerMove && !bBottomRulerMove && !bFooterRulerMove )
+ {
+ bTopRulerChange = false;
+ bBottomRulerChange = false;
+ bHeaderRulerChange = true;
+ bFooterRulerChange = false;
+ }
+ else if( aPixPt.Y() < ( aFooderLeft.Y() + 2 ) && aPixPt.Y() > ( aFooderLeft.Y() - 2 ) && !bTopRulerMove && !bBottomRulerMove && !bHeaderRulerMove )
+ {
+ bTopRulerChange = false;
+ bBottomRulerChange = false;
+ bHeaderRulerChange = false;
+ bFooterRulerChange = true;
+ }
+
+ if( !bPageMargin )
+ return;
+
+ if(( (aPixPt.X() < ( aLeftTop.X() + 2 ) && aPixPt.X() > ( aLeftTop.X() - 2 )) || bLeftRulerMove ||
+ ( aPixPt.X() < ( aRightTop.X() + 2 ) && aPixPt.X() > ( aRightTop.X() - 2 ) ) || bRightRulerMove || bOnColRulerChange || bColRulerMove )
+ && aPixPt.Y() > aLeftTop.Y() && aPixPt.Y() < aLeftBottom.Y() )
+ {
+ if( bOnColRulerChange || bColRulerMove )
+ {
+ SetPointer( PointerStyle::HSplit );
+ if( bColRulerMove )
+ {
+ if( aMouseMovePoint.X() > -aOffset.X() && aMouseMovePoint.X() < o3tl::convert(nWidth, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.X() )
+ DragMove( aMouseMovePoint.X(), PointerStyle::HSplit );
+ }
+ }
+ else
+ {
+ if( bLeftRulerChange && !bTopRulerMove && !bBottomRulerMove && !bHeaderRulerMove && !bFooterRulerMove )
+ {
+ SetPointer( PointerStyle::HSizeBar );
+ if( bLeftRulerMove )
+ {
+ if( aMouseMovePoint.X() > -aOffset.X() && aMouseMovePoint.X() < o3tl::convert(nWidth, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.X() )
+ DragMove( aMouseMovePoint.X(), PointerStyle::HSizeBar );
+ }
+ }
+ else if( bRightRulerChange && !bTopRulerMove && !bBottomRulerMove && !bHeaderRulerMove && !bFooterRulerMove )
+ {
+ SetPointer( PointerStyle::HSizeBar );
+ if( bRightRulerMove )
+ {
+ if( aMouseMovePoint.X() > -aOffset.X() && aMouseMovePoint.X() < o3tl::convert(nWidth, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.X() )
+ DragMove( aMouseMovePoint.X(), PointerStyle::HSizeBar );
+ }
+ }
+ }
+ }
+ else
+ {
+ if( ( ( aPixPt.Y() < ( aTopLeft.Y() + 2 ) && aPixPt.Y() > ( aTopLeft.Y() - 2 ) ) || bTopRulerMove ||
+ ( aPixPt.Y() < ( aBottomLeft.Y() + 2 ) && aPixPt.Y() > ( aBottomLeft.Y() - 2 ) ) || bBottomRulerMove ||
+ ( aPixPt.Y() < ( aHeaderLeft.Y() + 2 ) && aPixPt.Y() > ( aHeaderLeft.Y() - 2 ) ) || bHeaderRulerMove ||
+ ( aPixPt.Y() < ( aFooderLeft.Y() + 2 ) && aPixPt.Y() > ( aFooderLeft.Y() - 2 ) ) || bFooterRulerMove )
+ && aPixPt.X() > aTopLeft.X() && aPixPt.X() < aTopRight.X() )
+ {
+ if( bTopRulerChange )
+ {
+ SetPointer( PointerStyle::VSizeBar );
+ if( bTopRulerMove )
+ {
+ if( aMouseMovePoint.Y() > -aOffset.Y() && aMouseMovePoint.Y() < o3tl::convert(nHeight, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.Y() )
+ DragMove( aMouseMovePoint.Y(), PointerStyle::VSizeBar );
+ }
+ }
+ else if( bBottomRulerChange )
+ {
+ SetPointer( PointerStyle::VSizeBar );
+ if( bBottomRulerMove )
+ {
+ if( aMouseMovePoint.Y() > -aOffset.Y() && aMouseMovePoint.Y() < o3tl::convert(nHeight, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.Y() )
+ DragMove( aMouseMovePoint.Y(), PointerStyle::VSizeBar );
+ }
+ }
+ else if( bHeaderRulerChange )
+ {
+ SetPointer( PointerStyle::VSizeBar );
+ if( bHeaderRulerMove )
+ {
+ if( aMouseMovePoint.Y() > -aOffset.Y() && aMouseMovePoint.Y() < o3tl::convert(nHeight, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.Y() )
+ DragMove( aMouseMovePoint.Y(), PointerStyle::VSizeBar );
+ }
+ }
+ else if( bFooterRulerChange )
+ {
+ SetPointer( PointerStyle::VSizeBar );
+ if( bFooterRulerMove )
+ {
+ if( aMouseMovePoint.Y() > -aOffset.Y() && aMouseMovePoint.Y() < o3tl::convert(nHeight, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.Y() )
+ DragMove( aMouseMovePoint.Y(), PointerStyle::VSizeBar );
+ }
+ }
+ }
+ else
+ SetPointer( PointerStyle::Arrow );
+ }
+}
+
+void ScPreview::InvalidateLocationData(SfxHintId nId)
+{
+ bLocationValid = false;
+ if (pViewShell->HasAccessibilityObjects())
+ pViewShell->BroadcastAccessibility( SfxHint( nId ) );
+}
+
+void ScPreview::GetFocus()
+{
+ Window::GetFocus();
+ if (pViewShell && pViewShell->HasAccessibilityObjects())
+ pViewShell->BroadcastAccessibility( ScAccWinFocusGotHint() );
+}
+
+void ScPreview::LoseFocus()
+{
+ if (pViewShell && pViewShell->HasAccessibilityObjects())
+ pViewShell->BroadcastAccessibility( ScAccWinFocusLostHint() );
+ Window::LoseFocus();
+}
+
+css::uno::Reference<css::accessibility::XAccessible> ScPreview::CreateAccessible()
+{
+ css::uno::Reference<css::accessibility::XAccessible> xAcc= GetAccessible(false);
+ if (xAcc.is())
+ {
+ return xAcc;
+ }
+
+ rtl::Reference<ScAccessibleDocumentPagePreview> pAccessible =
+ new ScAccessibleDocumentPagePreview( GetAccessibleParentWindow()->GetAccessible(), pViewShell );
+
+ xAcc = pAccessible;
+ SetAccessible(xAcc);
+ pAccessible->Init();
+ return xAcc;
+}
+
+void ScPreview::DragMove( tools::Long nDragMovePos, PointerStyle nFlags )
+{
+ Fraction aPreviewZoom( nZoom, 100 );
+ Fraction aHorPrevZoom( static_cast<tools::Long>( 100 * nZoom / pDocShell->GetOutputFactor() ), 10000 );
+ MapMode aMMMode( MapUnit::Map100thMM, Point(), aHorPrevZoom, aPreviewZoom );
+ SetMapMode( aMMMode );
+ tools::Long nPos = nDragMovePos;
+ if( nFlags == PointerStyle::HSizeBar || nFlags == PointerStyle::HSplit )
+ {
+ if( nDragMovePos != aButtonDownChangePoint.X() )
+ {
+ DrawInvert( aButtonDownChangePoint.X(), nFlags );
+ aButtonDownChangePoint.setX( nPos );
+ DrawInvert( aButtonDownChangePoint.X(), nFlags );
+ }
+ }
+ else if( nFlags == PointerStyle::VSizeBar )
+ {
+ if( nDragMovePos != aButtonDownChangePoint.Y() )
+ {
+ DrawInvert( aButtonDownChangePoint.Y(), nFlags );
+ aButtonDownChangePoint.setY( nPos );
+ DrawInvert( aButtonDownChangePoint.Y(), nFlags );
+ }
+ }
+}
+
+void ScPreview::DrawInvert( tools::Long nDragPos, PointerStyle nFlags )
+{
+ tools::Long nHeight = lcl_GetDocPageSize( &pDocShell->GetDocument(), nTab ).Height();
+ tools::Long nWidth = lcl_GetDocPageSize( &pDocShell->GetDocument(), nTab ).Width();
+ if( nFlags == PointerStyle::HSizeBar || nFlags == PointerStyle::HSplit )
+ {
+ tools::Rectangle aRect( nDragPos, -aOffset.Y(), nDragPos + 1, o3tl::convert(nHeight, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.Y());
+ GetOutDev()->Invert( aRect, InvertFlags::N50 );
+ }
+ else if( nFlags == PointerStyle::VSizeBar )
+ {
+ tools::Rectangle aRect( -aOffset.X(), nDragPos, o3tl::convert(nWidth, o3tl::Length::twip, o3tl::Length::mm100) - aOffset.X(), nDragPos + 1 );
+ GetOutDev()->Invert( aRect, InvertFlags::N50 );
+ }
+}
+
+void ScPreview::SetSelectedTabs(const ScMarkData& rMark)
+{
+ maSelectedTabs = rMark.GetSelectedTabs();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/prevloc.cxx b/sc/source/ui/view/prevloc.cxx
new file mode 100644
index 000000000..1e2375ab5
--- /dev/null
+++ b/sc/source/ui/view/prevloc.cxx
@@ -0,0 +1,718 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <prevloc.hxx>
+#include <document.hxx>
+
+#include <o3tl/unit_conversion.hxx>
+#include <osl/diagnose.h>
+#include <vcl/outdev.hxx>
+
+namespace {
+
+enum ScPreviewLocationType : sal_uInt8
+{
+ SC_PLOC_CELLRANGE,
+ SC_PLOC_COLHEADER,
+ SC_PLOC_ROWHEADER,
+ SC_PLOC_LEFTHEADER,
+ SC_PLOC_RIGHTHEADER,
+ SC_PLOC_LEFTFOOTER,
+ SC_PLOC_RIGHTFOOTER,
+ SC_PLOC_NOTEMARK,
+ SC_PLOC_NOTETEXT
+};
+
+}
+
+struct ScPreviewLocationEntry
+{
+ tools::Rectangle aPixelRect;
+ ScRange aCellRange;
+ ScPreviewLocationType eType;
+ bool bRepeatCol;
+ bool bRepeatRow;
+
+ ScPreviewLocationEntry( ScPreviewLocationType eNewType, const tools::Rectangle& rPixel, const ScRange& rRange,
+ bool bRepCol, bool bRepRow ) :
+ aPixelRect( rPixel ),
+ aCellRange( rRange ),
+ eType( eNewType ),
+ bRepeatCol( bRepCol ),
+ bRepeatRow( bRepRow )
+ {
+ }
+};
+
+ScPreviewTableInfo::ScPreviewTableInfo() :
+ nTab(0),
+ nCols(0),
+ nRows(0)
+{
+}
+
+ScPreviewTableInfo::~ScPreviewTableInfo()
+{
+}
+
+void ScPreviewTableInfo::SetTab( SCTAB nNewTab )
+{
+ nTab = nNewTab;
+}
+
+void ScPreviewTableInfo::SetColInfo( SCCOL nCount, ScPreviewColRowInfo* pNewInfo )
+{
+ pColInfo.reset(pNewInfo);
+ nCols = nCount;
+}
+
+void ScPreviewTableInfo::SetRowInfo( SCROW nCount, ScPreviewColRowInfo* pNewInfo )
+{
+ pRowInfo.reset(pNewInfo);
+ nRows = nCount;
+}
+
+void ScPreviewTableInfo::LimitToArea( const tools::Rectangle& rPixelArea )
+{
+ if ( pColInfo )
+ {
+ // cells completely left of the visible area
+ SCCOL nStart = 0;
+ while ( nStart < nCols && pColInfo[nStart].nPixelEnd < rPixelArea.Left() )
+ ++nStart;
+
+ // cells completely right of the visible area
+ SCCOL nEnd = nCols;
+ while ( nEnd > 0 && pColInfo[nEnd-1].nPixelStart > rPixelArea.Right() )
+ --nEnd;
+
+ if ( nStart > 0 || nEnd < nCols )
+ {
+ if ( nEnd > nStart )
+ {
+ SCCOL nNewCount = nEnd - nStart;
+ ScPreviewColRowInfo* pNewInfo = new ScPreviewColRowInfo[nNewCount];
+ for (SCCOL i=0; i<nNewCount; i++)
+ pNewInfo[i] = pColInfo[nStart + i];
+ SetColInfo( nNewCount, pNewInfo );
+ }
+ else
+ SetColInfo( 0, nullptr ); // all invisible
+ }
+ }
+
+ if ( !pRowInfo )
+ return;
+
+ // cells completely above the visible area
+ SCROW nStart = 0;
+ while ( nStart < nRows && pRowInfo[nStart].nPixelEnd < rPixelArea.Top() )
+ ++nStart;
+
+ // cells completely below the visible area
+ SCROW nEnd = nRows;
+ while ( nEnd > 0 && pRowInfo[nEnd-1].nPixelStart > rPixelArea.Bottom() )
+ --nEnd;
+
+ if ( nStart <= 0 && nEnd >= nRows )
+ return;
+
+ if ( nEnd > nStart )
+ {
+ SCROW nNewCount = nEnd - nStart;
+ ScPreviewColRowInfo* pNewInfo = new ScPreviewColRowInfo[nNewCount];
+ for (SCROW i=0; i<nNewCount; i++)
+ pNewInfo[i] = pRowInfo[nStart + i];
+ SetRowInfo( nNewCount, pNewInfo );
+ }
+ else
+ SetRowInfo( 0, nullptr ); // all invisible
+}
+
+ScPreviewLocationData::ScPreviewLocationData( ScDocument* pDocument, OutputDevice* pWin ) :
+ pWindow( pWin ),
+ pDoc( pDocument ),
+ nDrawRanges( 0 ),
+ nPrintTab( 0 )
+{
+}
+
+ScPreviewLocationData::~ScPreviewLocationData()
+{
+ Clear();
+}
+
+void ScPreviewLocationData::SetCellMapMode( const MapMode& rMapMode )
+{
+ aCellMapMode = rMapMode;
+}
+
+void ScPreviewLocationData::SetPrintTab( SCTAB nNew )
+{
+ nPrintTab = nNew;
+}
+
+void ScPreviewLocationData::Clear()
+{
+ m_Entries.clear();
+
+ nDrawRanges = 0;
+}
+
+void ScPreviewLocationData::AddCellRange( const tools::Rectangle& rRect, const ScRange& rRange, bool bRepCol, bool bRepRow,
+ const MapMode& rDrawMap )
+{
+ tools::Rectangle aPixelRect( pWindow->LogicToPixel( rRect ) );
+ m_Entries.push_front( std::make_unique<ScPreviewLocationEntry>(SC_PLOC_CELLRANGE, aPixelRect, rRange, bRepCol, bRepRow) );
+
+ OSL_ENSURE( nDrawRanges < SC_PREVIEW_MAXRANGES, "too many ranges" );
+
+ if ( nDrawRanges >= SC_PREVIEW_MAXRANGES )
+ return;
+
+ aDrawRectangle[nDrawRanges] = aPixelRect;
+ aDrawMapMode[nDrawRanges] = rDrawMap;
+
+ if (bRepCol)
+ {
+ if (bRepRow)
+ aDrawRangeId[nDrawRanges] = SC_PREVIEW_RANGE_EDGE;
+ else
+ aDrawRangeId[nDrawRanges] = SC_PREVIEW_RANGE_REPCOL;
+ }
+ else
+ {
+ if (bRepRow)
+ aDrawRangeId[nDrawRanges] = SC_PREVIEW_RANGE_REPROW;
+ else
+ aDrawRangeId[nDrawRanges] = SC_PREVIEW_RANGE_TAB;
+ }
+
+ ++nDrawRanges;
+}
+
+void ScPreviewLocationData::AddColHeaders( const tools::Rectangle& rRect, SCCOL nStartCol, SCCOL nEndCol, bool bRepCol )
+{
+ SCTAB nTab = 0; //! ?
+ ScRange aRange( nStartCol, 0, nTab, nEndCol, 0, nTab );
+ tools::Rectangle aPixelRect( pWindow->LogicToPixel( rRect ) );
+
+ m_Entries.push_front( std::make_unique<ScPreviewLocationEntry>(SC_PLOC_COLHEADER, aPixelRect, aRange, bRepCol, false) );
+}
+
+void ScPreviewLocationData::AddRowHeaders( const tools::Rectangle& rRect, SCROW nStartRow, SCROW nEndRow, bool bRepRow )
+{
+ SCTAB nTab = 0; //! ?
+ ScRange aRange( 0, nStartRow, nTab, 0, nEndRow, nTab );
+ tools::Rectangle aPixelRect( pWindow->LogicToPixel( rRect ) );
+
+ m_Entries.push_front( std::make_unique<ScPreviewLocationEntry>(SC_PLOC_ROWHEADER, aPixelRect, aRange, false, bRepRow) );
+}
+
+void ScPreviewLocationData::AddHeaderFooter( const tools::Rectangle& rRect, bool bHeader, bool bLeft )
+{
+ ScRange aRange; //! ?
+ tools::Rectangle aPixelRect( pWindow->LogicToPixel( rRect ) );
+
+ ScPreviewLocationType eType = bHeader ?
+ ( bLeft ? SC_PLOC_LEFTHEADER : SC_PLOC_RIGHTHEADER ) :
+ ( bLeft ? SC_PLOC_LEFTFOOTER : SC_PLOC_RIGHTFOOTER );
+
+ m_Entries.push_front( std::make_unique<ScPreviewLocationEntry>(eType, aPixelRect, aRange, false, false) );
+}
+
+void ScPreviewLocationData::AddNoteMark( const tools::Rectangle& rRect, const ScAddress& rPos )
+{
+ ScRange aRange( rPos );
+ tools::Rectangle aPixelRect( pWindow->LogicToPixel( rRect ) );
+
+ m_Entries.push_front( std::make_unique<ScPreviewLocationEntry>(SC_PLOC_NOTEMARK, aPixelRect, aRange, false, false) );
+}
+
+void ScPreviewLocationData::AddNoteText( const tools::Rectangle& rRect, const ScAddress& rPos )
+{
+ ScRange aRange( rPos );
+ tools::Rectangle aPixelRect( pWindow->LogicToPixel( rRect ) );
+
+ m_Entries.push_front( std::make_unique<ScPreviewLocationEntry>(SC_PLOC_NOTETEXT, aPixelRect, aRange, false, false) );
+}
+
+void ScPreviewLocationData::GetDrawRange( sal_uInt16 nPos, tools::Rectangle& rPixelRect, MapMode& rMapMode, sal_uInt8& rRangeId ) const
+{
+ OSL_ENSURE( nPos < nDrawRanges, "wrong position" );
+ if ( nPos < nDrawRanges )
+ {
+ rPixelRect = aDrawRectangle[nPos];
+ rMapMode = aDrawMapMode[nPos];
+ rRangeId = aDrawRangeId[nPos];
+ }
+}
+
+static ScPreviewLocationEntry* lcl_GetEntryByAddress(
+ ScPreviewLocationData::Entries_t const& rEntries,
+ const ScAddress& rPos, ScPreviewLocationType const eType)
+{
+ for (auto const& it : rEntries)
+ {
+ if ( it->eType == eType && it->aCellRange.Contains( rPos ) )
+ return it.get();
+ }
+
+ return nullptr;
+}
+
+tools::Rectangle ScPreviewLocationData::GetOffsetPixel( const ScAddress& rCellPos, const ScRange& rRange ) const
+{
+ SCTAB nTab = rRange.aStart.Tab();
+
+ tools::Long nPosX = 0;
+ SCCOL nEndCol = rCellPos.Col();
+ for (SCCOL nCol = rRange.aStart.Col(); nCol < nEndCol; nCol++)
+ {
+ sal_uInt16 nDocW = pDoc->GetColWidth( nCol, nTab );
+ if (nDocW)
+ nPosX += o3tl::convert(nDocW, o3tl::Length::twip, o3tl::Length::mm100);
+ }
+ const tools::Long nSizeX
+ = o3tl::convert(pDoc->GetColWidth(nEndCol, nTab), o3tl::Length::twip, o3tl::Length::mm100);
+
+ SCROW nEndRow = rCellPos.Row();
+ tools::Long nPosY = o3tl::convert(pDoc->GetRowHeight(rRange.aStart.Row(), nEndRow, nTab),
+ o3tl::Length::twip, o3tl::Length::mm100);
+ tools::Long nSizeY
+ = o3tl::convert(pDoc->GetRowHeight(nEndRow, nTab), o3tl::Length::twip, o3tl::Length::mm100);
+
+ Size aOffsetLogic( nPosX, nPosY );
+ Size aSizeLogic( nSizeX, nSizeY );
+ Size aOffsetPixel = pWindow->LogicToPixel( aOffsetLogic, aCellMapMode );
+ Size aSizePixel = pWindow->LogicToPixel( aSizeLogic, aCellMapMode );
+
+ return tools::Rectangle( Point( aOffsetPixel.Width(), aOffsetPixel.Height() ), aSizePixel );
+}
+
+void ScPreviewLocationData::GetCellPosition( const ScAddress& rCellPos, tools::Rectangle& rCellRect ) const
+{
+ ScPreviewLocationEntry* pEntry = lcl_GetEntryByAddress( m_Entries, rCellPos, SC_PLOC_CELLRANGE );
+ if ( pEntry )
+ {
+ tools::Rectangle aOffsetRect = GetOffsetPixel( rCellPos, pEntry->aCellRange );
+ rCellRect = tools::Rectangle( aOffsetRect.Left() + pEntry->aPixelRect.Left(),
+ aOffsetRect.Top() + pEntry->aPixelRect.Top(),
+ aOffsetRect.Right() + pEntry->aPixelRect.Left(),
+ aOffsetRect.Bottom() + pEntry->aPixelRect.Top() );
+ }
+}
+
+bool ScPreviewLocationData::HasCellsInRange( const tools::Rectangle& rVisiblePixel ) const
+{
+ for (auto const& it : m_Entries)
+ {
+ if ( it->eType == SC_PLOC_CELLRANGE || it->eType == SC_PLOC_COLHEADER || it->eType == SC_PLOC_ROWHEADER )
+ if ( it->aPixelRect.Overlaps( rVisiblePixel ) )
+ return true;
+ }
+
+ return false;
+}
+
+bool ScPreviewLocationData::GetHeaderPosition( tools::Rectangle& rRect ) const
+{
+ for (auto const& it : m_Entries)
+ {
+ if ( it->eType == SC_PLOC_LEFTHEADER || it->eType == SC_PLOC_RIGHTHEADER )
+ {
+ rRect = it->aPixelRect;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ScPreviewLocationData::GetFooterPosition( tools::Rectangle& rRect ) const
+{
+ for (auto const& it : m_Entries)
+ {
+ if ( it->eType == SC_PLOC_LEFTFOOTER || it->eType == SC_PLOC_RIGHTFOOTER )
+ {
+ rRect = it->aPixelRect;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ScPreviewLocationData::IsHeaderLeft() const
+{
+ for (auto const& it : m_Entries)
+ {
+ if ( it->eType == SC_PLOC_LEFTHEADER )
+ return true;
+
+ if ( it->eType == SC_PLOC_RIGHTHEADER )
+ return false;
+ }
+
+ return false;
+}
+
+bool ScPreviewLocationData::IsFooterLeft() const
+{
+ for (auto const& it : m_Entries)
+ {
+ if ( it->eType == SC_PLOC_LEFTFOOTER )
+ return true;
+
+ if ( it->eType == SC_PLOC_RIGHTFOOTER )
+ return false;
+ }
+
+ return false;
+}
+
+tools::Long ScPreviewLocationData::GetNoteCountInRange( const tools::Rectangle& rVisiblePixel, bool bNoteMarks ) const
+{
+ ScPreviewLocationType eType = bNoteMarks ? SC_PLOC_NOTEMARK : SC_PLOC_NOTETEXT;
+
+ sal_uLong nRet = 0;
+ for (auto const& it : m_Entries)
+ {
+ if ( it->eType == eType && it->aPixelRect.Overlaps( rVisiblePixel ) )
+ ++nRet;
+ }
+
+ return nRet;
+}
+
+bool ScPreviewLocationData::GetNoteInRange( const tools::Rectangle& rVisiblePixel, tools::Long nIndex, bool bNoteMarks,
+ ScAddress& rCellPos, tools::Rectangle& rNoteRect ) const
+{
+ ScPreviewLocationType eType = bNoteMarks ? SC_PLOC_NOTEMARK : SC_PLOC_NOTETEXT;
+
+ sal_uLong nPos = 0;
+ for (auto const& it : m_Entries)
+ {
+ if ( it->eType == eType && it->aPixelRect.Overlaps( rVisiblePixel ) )
+ {
+ if ( nPos == sal::static_int_cast<sal_uLong>(nIndex) )
+ {
+ rCellPos = it->aCellRange.aStart;
+ rNoteRect = it->aPixelRect;
+ return true;
+ }
+ ++nPos;
+ }
+ }
+
+ return false;
+}
+
+tools::Rectangle ScPreviewLocationData::GetNoteInRangeOutputRect(const tools::Rectangle& rVisiblePixel, bool bNoteMarks, const ScAddress& aCellPos) const
+{
+ ScPreviewLocationType eType = bNoteMarks ? SC_PLOC_NOTEMARK : SC_PLOC_NOTETEXT;
+
+ for (auto const& it : m_Entries)
+ {
+ if ( it->eType == eType && it->aPixelRect.Overlaps( rVisiblePixel ) )
+ {
+ if ( aCellPos == it->aCellRange.aStart )
+ return it->aPixelRect;
+ }
+ }
+
+ return tools::Rectangle();
+}
+
+void ScPreviewLocationData::GetTableInfo( const tools::Rectangle& rVisiblePixel, ScPreviewTableInfo& rInfo ) const
+{
+ // from left to right:
+ bool bHasHeaderCol = false;
+ bool bHasRepCols = false;
+ bool bHasMainCols = false;
+ SCCOL nRepeatColStart = 0;
+ SCCOL nRepeatColEnd = 0;
+ SCCOL nMainColStart = 0;
+ SCCOL nMainColEnd = 0;
+
+ // from top to bottom:
+ bool bHasHeaderRow = false;
+ bool bHasRepRows = false;
+ bool bHasMainRows = false;
+ SCROW nRepeatRowStart = 0;
+ SCROW nRepeatRowEnd = 0;
+ SCROW nMainRowStart = 0;
+ SCROW nMainRowEnd = 0;
+
+ tools::Rectangle aHeaderRect, aRepeatRect, aMainRect;
+ SCTAB nTab = 0;
+
+ for (auto const& it : m_Entries)
+ {
+ if ( it->eType == SC_PLOC_CELLRANGE )
+ {
+ if ( it->bRepeatCol )
+ {
+ bHasRepCols = true;
+ nRepeatColStart = it->aCellRange.aStart.Col();
+ nRepeatColEnd = it->aCellRange.aEnd.Col();
+ aRepeatRect.SetLeft( it->aPixelRect.Left() );
+ aRepeatRect.SetRight( it->aPixelRect.Right() );
+ }
+ else
+ {
+ bHasMainCols = true;
+ nMainColStart = it->aCellRange.aStart.Col();
+ nMainColEnd = it->aCellRange.aEnd.Col();
+ aMainRect.SetLeft( it->aPixelRect.Left() );
+ aMainRect.SetRight( it->aPixelRect.Right() );
+ }
+ if ( it->bRepeatRow )
+ {
+ bHasRepRows = true;
+ nRepeatRowStart = it->aCellRange.aStart.Row();
+ nRepeatRowEnd = it->aCellRange.aEnd.Row();
+ aRepeatRect.SetTop( it->aPixelRect.Top() );
+ aRepeatRect.SetBottom( it->aPixelRect.Bottom() );
+ }
+ else
+ {
+ bHasMainRows = true;
+ nMainRowStart = it->aCellRange.aStart.Row();
+ nMainRowEnd = it->aCellRange.aEnd.Row();
+ aMainRect.SetTop( it->aPixelRect.Top() );
+ aMainRect.SetBottom( it->aPixelRect.Bottom() );
+ }
+ nTab = it->aCellRange.aStart.Tab(); //! store separately?
+ }
+ else if ( it->eType == SC_PLOC_ROWHEADER )
+ {
+ // row headers result in an additional column
+ bHasHeaderCol = true;
+ aHeaderRect.SetLeft( it->aPixelRect.Left() );
+ aHeaderRect.SetRight( it->aPixelRect.Right() );
+ }
+ else if ( it->eType == SC_PLOC_COLHEADER )
+ {
+ // column headers result in an additional row
+ bHasHeaderRow = true;
+ aHeaderRect.SetTop( it->aPixelRect.Top() );
+ aHeaderRect.SetBottom( it->aPixelRect.Bottom() );
+ }
+ }
+
+ // get column info
+
+ SCCOL nColCount = 0;
+ SCCOL nCol;
+ if ( bHasHeaderCol )
+ ++nColCount;
+ if ( bHasRepCols )
+ for ( nCol=nRepeatColStart; nCol<=nRepeatColEnd; nCol++ )
+ if (!pDoc->ColHidden(nCol, nTab))
+ ++nColCount;
+ if ( bHasMainCols )
+ for ( nCol=nMainColStart; nCol<=nMainColEnd; nCol++ )
+ if (!pDoc->ColHidden(nCol, nTab))
+ ++nColCount;
+
+ if ( nColCount > 0 )
+ {
+ ScPreviewColRowInfo* pColInfo = new ScPreviewColRowInfo[ nColCount ];
+ SCCOL nColPos = 0;
+
+ if ( bHasHeaderCol )
+ {
+ pColInfo[nColPos].Set( true, 0, aHeaderRect.Left(), aHeaderRect.Right() );
+ ++nColPos;
+ }
+ if ( bHasRepCols )
+ {
+ tools::Long nPosX = 0;
+ for ( nCol=nRepeatColStart; nCol<=nRepeatColEnd; nCol++ )
+ if (!pDoc->ColHidden(nCol, nTab))
+ {
+ sal_uInt16 nDocW = pDoc->GetColWidth( nCol, nTab );
+ tools::Long nNextX
+ = nPosX + o3tl::convert(nDocW, o3tl::Length::twip, o3tl::Length::mm100);
+
+ tools::Long nPixelStart = pWindow->LogicToPixel( Size( nPosX, 0 ), aCellMapMode ).Width();
+ tools::Long nPixelEnd = pWindow->LogicToPixel( Size( nNextX, 0 ), aCellMapMode ).Width() - 1;
+ pColInfo[nColPos].Set( false, nCol,
+ aRepeatRect.Left() + nPixelStart,
+ aRepeatRect.Left() + nPixelEnd );
+
+ nPosX = nNextX;
+ ++nColPos;
+ }
+ }
+ if ( bHasMainCols )
+ {
+ tools::Long nPosX = 0;
+ for ( nCol=nMainColStart; nCol<=nMainColEnd; nCol++ )
+ if (!pDoc->ColHidden(nCol, nTab))
+ {
+ sal_uInt16 nDocW = pDoc->GetColWidth( nCol, nTab );
+ tools::Long nNextX
+ = nPosX + o3tl::convert(nDocW, o3tl::Length::twip, o3tl::Length::mm100);
+
+ tools::Long nPixelStart = pWindow->LogicToPixel( Size( nPosX, 0 ), aCellMapMode ).Width();
+ tools::Long nPixelEnd = pWindow->LogicToPixel( Size( nNextX, 0 ), aCellMapMode ).Width() - 1;
+ pColInfo[nColPos].Set( false, nCol,
+ aMainRect.Left() + nPixelStart,
+ aMainRect.Left() + nPixelEnd );
+
+ nPosX = nNextX;
+ ++nColPos;
+ }
+ }
+ rInfo.SetColInfo( nColCount, pColInfo );
+ }
+ else
+ rInfo.SetColInfo( 0, nullptr );
+
+ // get row info
+
+ SCROW nRowCount = 0;
+ if ( bHasHeaderRow )
+ ++nRowCount;
+ if ( bHasRepRows )
+ nRowCount += pDoc->CountVisibleRows(nRepeatRowStart, nRepeatRowEnd, nTab);
+ if ( bHasMainRows )
+ nRowCount += pDoc->CountVisibleRows(nMainRowStart, nMainRowEnd, nTab);
+
+ if ( nRowCount > 0 )
+ {
+ ScPreviewColRowInfo* pRowInfo = new ScPreviewColRowInfo[ nRowCount ];
+ SCROW nRowPos = 0;
+
+ if ( bHasHeaderRow )
+ {
+ pRowInfo[nRowPos].Set( true, 0, aHeaderRect.Top(), aHeaderRect.Bottom() );
+ ++nRowPos;
+ }
+ if ( bHasRepRows )
+ {
+ tools::Long nPosY = 0;
+ for (SCROW nRow = nRepeatRowStart; nRow <= nRepeatRowEnd; ++nRow)
+ {
+ if (pDoc->RowHidden(nRow, nTab))
+ continue;
+
+ sal_uInt16 nDocH = pDoc->GetOriginalHeight( nRow, nTab );
+ tools::Long nNextY
+ = nPosY + o3tl::convert(nDocH, o3tl::Length::twip, o3tl::Length::mm100);
+
+ tools::Long nPixelStart = pWindow->LogicToPixel( Size( 0, nPosY ), aCellMapMode ).Height();
+ tools::Long nPixelEnd = pWindow->LogicToPixel( Size( 0, nNextY ), aCellMapMode ).Height() - 1;
+ pRowInfo[nRowPos].Set( false, nRow,
+ aRepeatRect.Top() + nPixelStart,
+ aRepeatRect.Top() + nPixelEnd );
+
+ nPosY = nNextY;
+ ++nRowPos;
+ }
+ }
+ if ( bHasMainRows )
+ {
+ tools::Long nPosY = 0;
+ for (SCROW nRow = nMainRowStart; nRow <= nMainRowEnd; ++nRow)
+ {
+ if (pDoc->RowHidden(nRow, nTab))
+ continue;
+
+ sal_uInt16 nDocH = pDoc->GetOriginalHeight( nRow, nTab );
+ tools::Long nNextY
+ = nPosY + o3tl::convert(nDocH, o3tl::Length::twip, o3tl::Length::mm100);
+
+ tools::Long nPixelStart = pWindow->LogicToPixel( Size( 0, nPosY ), aCellMapMode ).Height();
+ tools::Long nPixelEnd = pWindow->LogicToPixel( Size( 0, nNextY ), aCellMapMode ).Height() - 1;
+ pRowInfo[nRowPos].Set( false, nRow,
+ aMainRect.Top() + nPixelStart,
+ aMainRect.Top() + nPixelEnd );
+
+ nPosY = nNextY;
+ ++nRowPos;
+ }
+ }
+ rInfo.SetRowInfo( nRowCount, pRowInfo );
+ }
+ else
+ rInfo.SetRowInfo( 0, nullptr );
+
+ // limit to visible area
+
+ rInfo.SetTab( nTab );
+ rInfo.LimitToArea( rVisiblePixel );
+}
+
+tools::Rectangle ScPreviewLocationData::GetHeaderCellOutputRect(const tools::Rectangle& rVisRect, const ScAddress& rCellPos, bool bColHeader) const
+{
+ // first a stupid implementation
+ // NN says here should be done more
+ tools::Rectangle aClipRect;
+ ScPreviewTableInfo aTableInfo;
+ GetTableInfo( rVisRect, aTableInfo );
+
+ if ( (rCellPos.Col() >= 0) &&
+ (rCellPos.Row() >= 0) && (rCellPos.Col() < aTableInfo.GetCols()) &&
+ (rCellPos.Row() < aTableInfo.GetRows()) )
+ {
+ SCCOL nCol(0);
+ SCROW nRow(0);
+ if (bColHeader)
+ nCol = rCellPos.Col();
+ else
+ nRow = rCellPos.Row();
+ const ScPreviewColRowInfo& rColInfo = aTableInfo.GetColInfo()[nCol];
+ const ScPreviewColRowInfo& rRowInfo = aTableInfo.GetRowInfo()[nRow];
+
+ if ( rColInfo.bIsHeader || rRowInfo.bIsHeader )
+ aClipRect = tools::Rectangle( rColInfo.nPixelStart, rRowInfo.nPixelStart, rColInfo.nPixelEnd, rRowInfo.nPixelEnd );
+ }
+ return aClipRect;
+}
+
+tools::Rectangle ScPreviewLocationData::GetCellOutputRect(const ScAddress& rCellPos) const
+{
+ // first a stupid implementation
+ // NN says here should be done more
+ tools::Rectangle aRect;
+ GetCellPosition(rCellPos, aRect);
+ return aRect;
+}
+
+// GetMainCellRange is used for links in PDF export
+
+bool ScPreviewLocationData::GetMainCellRange( ScRange& rRange, tools::Rectangle& rPixRect ) const
+{
+ for (auto const& it : m_Entries)
+ {
+ if ( it->eType == SC_PLOC_CELLRANGE && !it->bRepeatCol && !it->bRepeatRow )
+ {
+ rRange = it->aCellRange;
+ rPixRect = it->aPixelRect;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/prevwsh.cxx b/sc/source/ui/view/prevwsh.cxx
new file mode 100644
index 000000000..18cae4063
--- /dev/null
+++ b/sc/source/ui/view/prevwsh.cxx
@@ -0,0 +1,1189 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <scitems.hxx>
+
+#include <comphelper/SetFlagContextHelper.hxx>
+#include <sfx2/app.hxx>
+#include <editeng/sizeitem.hxx>
+#include <svx/zoomslideritem.hxx>
+#include <svx/svdview.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/request.hxx>
+#include <svl/stritem.hxx>
+#include <svl/whiter.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/help.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <tools/urlobj.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/viewfac.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <drwlayer.hxx>
+#include <prevwsh.hxx>
+#include <preview.hxx>
+#include <printfun.hxx>
+#include <scmod.hxx>
+#include <inputhdl.hxx>
+#include <docsh.hxx>
+#include <tabvwsh.hxx>
+#include <stlpool.hxx>
+#include <editutil.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <sc.hrc>
+#include <ViewSettingsSequenceDefines.hxx>
+#include <viewuno.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <svx/dialogs.hrc>
+
+#include <basegfx/utils/zoomtools.hxx>
+#include <svx/zoom_def.hxx>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+
+#include <scabstdlg.hxx>
+#include <vcl/EnumContext.hxx>
+#include <vcl/notebookbar/notebookbar.hxx>
+
+// for mouse wheel
+#define MINZOOM_SLIDER 10
+#define MAXZOOM_SLIDER 400
+
+#define SC_USERDATA_SEP ';'
+
+using namespace com::sun::star;
+
+#define ShellClass_ScPreviewShell
+#include <scslots.hxx>
+
+#include <memory>
+
+
+SFX_IMPL_INTERFACE(ScPreviewShell, SfxViewShell)
+
+void ScPreviewShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_OBJECT,
+ SfxVisibilityFlags::Standard|SfxVisibilityFlags::Server|SfxVisibilityFlags::ReadonlyDoc,
+ ToolbarId::Objectbar_Preview);
+
+ GetStaticInterface()->RegisterPopupMenu("preview");
+}
+
+SFX_IMPL_NAMED_VIEWFACTORY( ScPreviewShell, "PrintPreview" )
+{
+ SFX_VIEW_REGISTRATION(ScDocShell);
+}
+
+void ScPreviewShell::Construct( vcl::Window* pParent )
+{
+ // Find the top-most window, and set the close window handler to intercept
+ // the window close event.
+ vcl::Window* pWin = pParent;
+ while (!pWin->IsSystemWindow())
+ {
+ if (pWin->GetParent())
+ pWin = pWin->GetParent();
+ else
+ break;
+ }
+
+ mpFrameWindow = dynamic_cast<SystemWindow*>(pWin);
+ if (mpFrameWindow)
+ mpFrameWindow->SetCloseHdl(LINK(this, ScPreviewShell, CloseHdl));
+
+ eZoom = SvxZoomType::WHOLEPAGE;
+
+ pCorner = VclPtr<ScrollBarBox>::Create( pParent, WB_SIZEABLE );
+
+ pHorScroll = VclPtr<ScrollBar>::Create(pParent, WB_HSCROLL );
+ pVerScroll = VclPtr<ScrollBar>::Create(pParent, WB_VSCROLL);
+
+ // RTL: no mirroring for horizontal scrollbars
+ pHorScroll->EnableRTL( false );
+
+ pHorScroll->SetEndScrollHdl( LINK( this, ScPreviewShell, ScrollHandler ) );
+ pVerScroll->SetEndScrollHdl( LINK( this, ScPreviewShell, ScrollHandler ) );
+
+ pPreview = VclPtr<ScPreview>::Create( pParent, pDocShell, this );
+
+ SetPool( &SC_MOD()->GetPool() );
+ SetWindow( pPreview );
+ StartListening(*pDocShell, DuplicateHandling::Prevent);
+ StartListening(*SfxGetpApp(), DuplicateHandling::Prevent); // #i62045# #i62046# application is needed for Calc's own hints
+ SfxBroadcaster* pDrawBC = pDocShell->GetDocument().GetDrawBroadcaster();
+ if (pDrawBC)
+ StartListening(*pDrawBC);
+
+ pHorScroll->Show( false );
+ pVerScroll->Show( false );
+ pCorner->Show();
+ SetName("Preview");
+}
+
+ScPreviewShell::ScPreviewShell( SfxViewFrame* pViewFrame,
+ SfxViewShell* pOldSh ) :
+ SfxViewShell( pViewFrame, SfxViewShellFlags::HAS_PRINTOPTIONS ),
+ pDocShell( static_cast<ScDocShell*>(pViewFrame->GetObjectShell()) ),
+ mpFrameWindow(nullptr),
+ nSourceDesignMode( TRISTATE_INDET ),
+ nMaxVertPos(0)
+{
+ Construct( &pViewFrame->GetWindow() );
+
+ try
+ {
+ SfxShell::SetContextBroadcasterEnabled(true);
+ SfxShell::SetContextName(
+ vcl::EnumContext::GetContextName(vcl::EnumContext::Context::Printpreview));
+ SfxShell::BroadcastContextForActivation(true);
+ }
+ catch (const css::uno::RuntimeException& e)
+ {
+ // tdf#130559: allow BackingComp to fail adding listener when opening document
+ css::uno::Reference<css::lang::XServiceInfo> xServiceInfo(e.Context, css::uno::UNO_QUERY);
+ if (!xServiceInfo || !xServiceInfo->supportsService("com.sun.star.frame.StartModule"))
+ throw;
+ SAL_WARN("sc.ui", "Opening file from StartModule straight into print preview");
+ }
+
+ auto& pNotebookBar = pViewFrame->GetWindow().GetSystemWindow()->GetNotebookBar();
+ if (pNotebookBar)
+ pNotebookBar->ControlListenerForCurrentController(false); // stop listening
+
+ if ( auto pTabViewShell = dynamic_cast<ScTabViewShell*>( pOldSh) )
+ {
+ // store view settings, show table from TabView
+ //! store live ScViewData instead, and update on ScTablesHint?
+ //! or completely forget aSourceData on ScTablesHint?
+
+ const ScViewData& rData = pTabViewShell->GetViewData();
+ pPreview->SetSelectedTabs(rData.GetMarkData());
+ InitStartTable( rData.GetTabNo() );
+
+ // also have to store the TabView's DesignMode state
+ // (only if draw view exists)
+ SdrView* pDrawView = pTabViewShell->GetScDrawView();
+ if ( pDrawView )
+ nSourceDesignMode
+ = pDrawView->IsDesignMode() ? TRISTATE_TRUE : TRISTATE_FALSE;
+ }
+
+ new ScPreviewObj(this);
+}
+
+ScPreviewShell::~ScPreviewShell()
+{
+ if (mpFrameWindow)
+ mpFrameWindow->SetCloseHdl(Link<SystemWindow&,void>()); // Remove close handler.
+
+ if (auto& pBar = GetViewFrame()->GetWindow().GetSystemWindow()->GetNotebookBar())
+ pBar->ControlListenerForCurrentController(true); // let it start listening now
+
+ // #108333#; notify Accessibility that Shell is dying and before destroy all
+ BroadcastAccessibility( SfxHint( SfxHintId::Dying ) );
+ pAccessibilityBroadcaster.reset();
+
+ SfxBroadcaster* pDrawBC = pDocShell->GetDocument().GetDrawBroadcaster();
+ if (pDrawBC)
+ EndListening(*pDrawBC);
+ EndListening(*SfxGetpApp());
+ EndListening(*pDocShell);
+
+ SetWindow(nullptr);
+ pPreview.disposeAndClear();
+ pHorScroll.disposeAndClear();
+ pVerScroll.disposeAndClear();
+ pCorner.disposeAndClear();
+
+ // normal mode of operation is switching back to default view in the same frame,
+ // so there's no need to activate any other window here anymore
+}
+
+void ScPreviewShell::InitStartTable(SCTAB nTab)
+{
+ pPreview->SetPageNo( pPreview->GetFirstPage(nTab) );
+}
+
+void ScPreviewShell::AdjustPosSizePixel( const Point &rPos, const Size &rSize )
+{
+ Size aOutSize( rSize );
+ pPreview->SetPosSizePixel( rPos, aOutSize );
+
+ if ( SvxZoomType::WHOLEPAGE == eZoom )
+ pPreview->SetZoom( pPreview->GetOptimalZoom(false) );
+ else if ( SvxZoomType::PAGEWIDTH == eZoom )
+ pPreview->SetZoom( pPreview->GetOptimalZoom(true) );
+
+ UpdateNeededScrollBars(false);
+}
+
+void ScPreviewShell::InnerResizePixel( const Point &rOfs, const Size &rSize, bool )
+{
+ AdjustPosSizePixel( rOfs,rSize );
+}
+
+void ScPreviewShell::OuterResizePixel( const Point &rOfs, const Size &rSize )
+{
+ AdjustPosSizePixel( rOfs,rSize );
+}
+
+bool ScPreviewShell::GetPageSize( Size& aPageSize )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab = pPreview->GetTab();
+
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( rDoc.GetPageStyle( nTab ),
+ SfxStyleFamily::Page );
+ OSL_ENSURE(pStyleSheet,"No style sheet");
+ if (!pStyleSheet) return false;
+ const SfxItemSet* pParamSet = &pStyleSheet->GetItemSet();
+
+ aPageSize = pParamSet->Get(ATTR_PAGE_SIZE).GetSize();
+ aPageSize.setWidth(o3tl::convert(aPageSize.Width(), o3tl::Length::twip, o3tl::Length::mm100));
+ aPageSize.setHeight(o3tl::convert(aPageSize.Height(), o3tl::Length::twip, o3tl::Length::mm100));
+ return true;
+}
+
+void ScPreviewShell::UpdateNeededScrollBars( bool bFromZoom )
+{
+ Size aPageSize;
+ OutputDevice* pDevice = Application::GetDefaultDevice();
+
+ tools::Long nBarW = GetViewFrame()->GetWindow().GetSettings().GetStyleSettings().GetScrollBarSize();
+ tools::Long nBarH = nBarW;
+
+ tools::Long aHeightOffSet = pDevice ? pDevice->PixelToLogic( Size( nBarW, nBarH ), pPreview->GetMapMode() ).Height() : 0;
+ tools::Long aWidthOffSet = aHeightOffSet;
+
+ if (!GetPageSize( aPageSize ))
+ return;
+
+ // for centering, page size without the shadow is used
+ bool bVert = pVerScroll->IsVisible();
+ bool bHori = pHorScroll->IsVisible();
+ Size aWindowSize = pPreview->GetOutDev()->GetOutputSize();
+ Point aPos = pPreview->GetPosPixel();
+ Size aWindowPixelSize = pPreview->GetOutputSizePixel();
+
+ // if we are called from Zoom then we need to compensate for whatever
+ // scrollbars were displayed before the zoom was called
+ if ( bFromZoom )
+ {
+ if ( bVert )
+ {
+ aWindowPixelSize.AdjustWidth(nBarH );
+ aWindowSize.AdjustWidth(aHeightOffSet );
+ }
+ if ( bHori )
+ {
+ aWindowPixelSize.AdjustHeight(nBarW );
+ aWindowSize.AdjustHeight(aWidthOffSet );
+ }
+ }
+
+ // recalculate any needed scrollbars
+ tools::Long nMaxWidthPos = aPageSize.Width() - aWindowSize.Width();
+ bHori = nMaxWidthPos >= 0;
+ tools::Long nMaxHeightPos = aPageSize.Height() - aWindowSize.Height();
+ bVert = nMaxHeightPos >= 0;
+
+ // see if having a scroll bar requires the other
+ if ( bVert != bHori && ( bVert || bHori ) )
+ {
+ if ( bVert && ( (nMaxWidthPos + aWidthOffSet ) > 0 ) )
+ bHori = true;
+ else if ( (nMaxHeightPos + aHeightOffSet ) > 0 )
+ bVert = true;
+ }
+ pHorScroll->Show( bHori );
+ pVerScroll->Show( bVert );
+
+ // make room for needed scrollbars ( and reduce the size
+ // of the preview appropriately )
+ if ( bHori )
+ aWindowPixelSize.AdjustHeight( -nBarW );
+ if ( bVert )
+ aWindowPixelSize.AdjustWidth( -nBarH );
+
+ pPreview->SetSizePixel( aWindowPixelSize );
+ pHorScroll->SetPosSizePixel( Point( aPos.X(), aPos.Y() + aWindowPixelSize.Height() ),
+ Size( aWindowPixelSize.Width(), nBarH ) );
+ pVerScroll->SetPosSizePixel( Point( aPos.X() + aWindowPixelSize.Width(), aPos.Y() ),
+ Size( nBarW, aWindowPixelSize.Height() ) );
+ pCorner->SetPosSizePixel( Point( aPos.X() + aWindowPixelSize.Width(), aPos.Y() + aWindowPixelSize.Height() ),
+ Size( nBarW, nBarH ) );
+ UpdateScrollBars();
+}
+
+void ScPreviewShell::UpdateScrollBars()
+{
+ Size aPageSize;
+ if ( !GetPageSize( aPageSize ) )
+ return;
+
+ // for centering, page size without the shadow is used
+
+ Size aWindowSize = pPreview->GetOutDev()->GetOutputSize();
+
+ Point aOfs = pPreview->GetOffset();
+
+ if( pHorScroll )
+ {
+ pHorScroll->SetRange( Range( 0, aPageSize.Width() ) );
+ pHorScroll->SetLineSize( aWindowSize.Width() / 16 );
+ pHorScroll->SetPageSize( aWindowSize.Width() );
+ pHorScroll->SetVisibleSize( aWindowSize.Width() );
+ tools::Long nMaxPos = aPageSize.Width() - aWindowSize.Width();
+ if ( nMaxPos<0 )
+ {
+ // page smaller than window -> center (but put scrollbar to 0)
+ aOfs.setX( 0 );
+ pPreview->SetXOffset( nMaxPos / 2 );
+ }
+ else if (aOfs.X() < 0)
+ {
+ // page larger than window -> never use negative offset
+ aOfs.setX( 0 );
+ pPreview->SetXOffset( 0 );
+ }
+ else if (aOfs.X() > nMaxPos)
+ {
+ // limit offset to align with right edge of window
+ aOfs.setX( nMaxPos );
+ pPreview->SetXOffset(nMaxPos);
+ }
+ pHorScroll->SetThumbPos( aOfs.X() );
+ }
+
+ if( !pVerScroll )
+ return;
+
+ tools::Long nPageNo = pPreview->GetPageNo();
+ tools::Long nTotalPages = pPreview->GetTotalPages();
+
+ nMaxVertPos = aPageSize.Height() - aWindowSize.Height();
+ pVerScroll->SetLineSize( aWindowSize.Height() / 16 );
+ pVerScroll->SetPageSize( aWindowSize.Height() );
+ pVerScroll->SetVisibleSize( aWindowSize.Height() );
+ if ( nMaxVertPos < 0 )
+ {
+ // page smaller than window -> center (but put scrollbar to 0)
+ aOfs.setY( 0 );
+ pPreview->SetYOffset( nMaxVertPos / 2 );
+ pVerScroll->SetThumbPos( nPageNo * aWindowSize.Height() );
+ pVerScroll->SetRange( Range( 0, aWindowSize.Height() * nTotalPages ));
+ }
+ else if (aOfs.Y() < 0)
+ {
+ // page larger than window -> never use negative offset
+ pVerScroll->SetRange( Range( 0, aPageSize.Height() ) );
+ aOfs.setY( 0 );
+ pPreview->SetYOffset( 0 );
+ pVerScroll->SetThumbPos( aOfs.Y() );
+ }
+ else if (aOfs.Y() > nMaxVertPos )
+ {
+ // limit offset to align with window bottom
+ pVerScroll->SetRange( Range( 0, aPageSize.Height() ) );
+ aOfs.setY( nMaxVertPos );
+ pPreview->SetYOffset( nMaxVertPos );
+ pVerScroll->SetThumbPos( aOfs.Y() );
+ }
+}
+
+IMPL_LINK( ScPreviewShell, ScrollHandler, ScrollBar*, pScroll, void )
+{
+ tools::Long nPos = pScroll->GetThumbPos();
+ tools::Long nDelta = pScroll->GetDelta();
+ tools::Long nMaxRange = pScroll->GetRangeMax();
+ tools::Long nTotalPages = pPreview->GetTotalPages();
+ tools::Long nPageNo = 0;
+ tools::Long nPerPageLength = 0;
+ bool bIsDivide = true;
+
+ if( nTotalPages )
+ nPerPageLength = nMaxRange / nTotalPages;
+
+ if( nPerPageLength )
+ {
+ nPageNo = nPos / nPerPageLength;
+ if( nPos % nPerPageLength )
+ {
+ bIsDivide = false;
+ nPageNo ++;
+ }
+ }
+
+ bool bHoriz = ( pScroll == pHorScroll );
+
+ if( bHoriz )
+ pPreview->SetXOffset( nPos );
+ else
+ {
+ if( nMaxVertPos > 0 )
+ pPreview->SetYOffset( nPos );
+ else
+ {
+ Point aMousePos = pScroll->OutputToNormalizedScreenPixel( pScroll->GetPointerPosPixel() );
+ Point aPos = pScroll->GetParent()->OutputToNormalizedScreenPixel( pScroll->GetPosPixel() );
+ OUString aHelpStr;
+ tools::Rectangle aRect;
+ QuickHelpFlags nAlign;
+
+ if( nDelta < 0 )
+ {
+ if ( nTotalPages && nPageNo > 0 && !bIsDivide )
+ pPreview->SetPageNo( nPageNo-1 );
+ if( bIsDivide )
+ pPreview->SetPageNo( nPageNo );
+
+ aHelpStr = ScResId( STR_PAGE ) +
+ " " + OUString::number( nPageNo ) +
+ " / " + OUString::number( nTotalPages );
+ }
+ else if( nDelta > 0 )
+ {
+ bool bAllTested = pPreview->AllTested();
+ if ( nTotalPages && ( nPageNo < nTotalPages || !bAllTested ) )
+ pPreview->SetPageNo( nPageNo );
+
+ aHelpStr = ScResId( STR_PAGE ) +
+ " " + OUString::number( nPageNo+1 ) +
+ " / " + OUString::number( nTotalPages );
+ }
+
+ aRect.SetLeft( aPos.X() - 8 );
+ aRect.SetTop( aMousePos.Y() );
+ aRect.SetRight( aRect.Left() );
+ aRect.SetBottom( aRect.Top() );
+ nAlign = QuickHelpFlags::Bottom|QuickHelpFlags::Center;
+ Help::ShowQuickHelp( pScroll->GetParent(), aRect, aHelpStr, nAlign );
+ }
+ }
+}
+
+IMPL_LINK_NOARG(ScPreviewShell, CloseHdl, SystemWindow&, void)
+{
+ ExitPreview();
+}
+
+bool ScPreviewShell::ScrollCommand( const CommandEvent& rCEvt )
+{
+ bool bDone = false;
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if ( pData && pData->GetMode() == CommandWheelMode::ZOOM )
+ {
+ tools::Long nOld = pPreview->GetZoom();
+ tools::Long nNew;
+ if ( pData->GetDelta() < 0 )
+ nNew = std::max( tools::Long(MINZOOM), basegfx::zoomtools::zoomOut( nOld ));
+ else
+ nNew = std::min( tools::Long(MAXZOOM), basegfx::zoomtools::zoomIn( nOld ));
+
+ if ( nNew != nOld )
+ {
+ eZoom = SvxZoomType::PERCENT;
+ pPreview->SetZoom( static_cast<sal_uInt16>(nNew) );
+ }
+
+ bDone = true;
+ }
+ else
+ {
+ bDone = pPreview->HandleScrollCommand( rCEvt, pHorScroll, pVerScroll );
+ }
+
+ return bDone;
+}
+
+SfxPrinter* ScPreviewShell::GetPrinter( bool bCreate )
+{
+ return pDocShell->GetPrinter(bCreate);
+}
+
+sal_uInt16 ScPreviewShell::SetPrinter( SfxPrinter *pNewPrinter, SfxPrinterChangeFlags nDiffFlags )
+{
+ return pDocShell->SetPrinter( pNewPrinter, nDiffFlags );
+}
+
+bool ScPreviewShell::HasPrintOptionsPage() const
+{
+ return true;
+}
+
+std::unique_ptr<SfxTabPage> ScPreviewShell::CreatePrintOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rOptions)
+{
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ::CreateTabPage ScTpPrintOptionsCreate = pFact->GetTabPageCreatorFunc(RID_SC_TP_PRINT);
+ if ( ScTpPrintOptionsCreate )
+ return ScTpPrintOptionsCreate(pPage, pController, &rOptions);
+ return nullptr;
+}
+
+void ScPreviewShell::Activate(bool bMDI)
+{
+ SfxViewShell::Activate(bMDI);
+
+ //! Basic etc. -> outsource to its own file (see tabvwsh4)
+
+ if (bMDI)
+ {
+ // InputHdl is now mostly Null, no more assertion!
+ ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
+ if ( pInputHdl )
+ pInputHdl->NotifyChange( nullptr );
+ }
+}
+
+void ScPreviewShell::Execute( SfxRequest& rReq )
+{
+ sal_uInt16 nSlot = rReq.GetSlot();
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ switch ( nSlot )
+ {
+ case SID_FORMATPAGE:
+ case SID_STATUS_PAGESTYLE:
+ case SID_HFEDIT:
+ pDocShell->ExecutePageStyle( *this, rReq, pPreview->GetTab() );
+ break;
+ case SID_REPAINT:
+ pPreview->Invalidate();
+ rReq.Done();
+ break;
+ case SID_PREV_TABLE: // Accelerator
+ case SID_PREVIEW_PREVIOUS:
+ {
+ tools::Long nPage = pPreview->GetPageNo();
+ tools::Long nTotal = pPreview->GetTotalPages();
+ if (nTotal && nPage > 0)
+ pPreview->SetPageNo( nPage-1 );
+ }
+ break;
+ case SID_NEXT_TABLE: // Accelerator
+ case SID_PREVIEW_NEXT:
+ {
+ bool bAllTested = pPreview->AllTested();
+ tools::Long nPage = pPreview->GetPageNo();
+ tools::Long nTotal = pPreview->GetTotalPages();
+ if (nTotal && (nPage+1 < nTotal || !bAllTested))
+ pPreview->SetPageNo( nPage+1 );
+ }
+ break;
+ case SID_CURSORTOPOFFILE: // Accelerator
+ case SID_PREVIEW_FIRST:
+ {
+ tools::Long nPage = pPreview->GetPageNo();
+ tools::Long nTotal = pPreview->GetTotalPages();
+ if (nTotal && nPage != 0)
+ pPreview->SetPageNo( 0 );
+ }
+ break;
+ case SID_CURSORENDOFFILE: // Accelerator
+ case SID_PREVIEW_LAST:
+ {
+ if (!pPreview->AllTested())
+ pPreview->CalcAll();
+
+ tools::Long nPage = pPreview->GetPageNo();
+ tools::Long nTotal = pPreview->GetTotalPages();
+ if (nTotal && nPage+1 != nTotal)
+ pPreview->SetPageNo( nTotal-1 );
+ }
+ break;
+ case SID_ATTR_ZOOM:
+ case FID_SCALE:
+ {
+ sal_uInt16 nZoom = 100;
+ bool bCancel = false;
+
+ eZoom = SvxZoomType::PERCENT;
+
+ if ( pReqArgs )
+ {
+
+ const SvxZoomItem& rZoomItem = pReqArgs->Get(SID_ATTR_ZOOM);
+
+ eZoom = rZoomItem.GetType();
+ nZoom = rZoomItem.GetValue();
+ }
+ else
+ {
+ SfxItemSetFixed<SID_ATTR_ZOOM, SID_ATTR_ZOOM> aSet( GetPool() );
+ SvxZoomItem aZoomItem( SvxZoomType::PERCENT, pPreview->GetZoom(), SID_ATTR_ZOOM );
+
+ aSet.Put( aZoomItem );
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSvxZoomDialog> pDlg(pFact->CreateSvxZoomDialog(nullptr, aSet));
+ pDlg->SetLimits( 20, 400 );
+ pDlg->HideButton( ZoomButtonId::OPTIMAL );
+ bCancel = ( RET_CANCEL == pDlg->Execute() );
+
+ if ( !bCancel )
+ {
+ const SvxZoomItem& rZoomItem = pDlg->GetOutputItemSet()->
+ Get( SID_ATTR_ZOOM );
+
+ eZoom = rZoomItem.GetType();
+ nZoom = rZoomItem.GetValue();
+ }
+ }
+
+ if ( !bCancel )
+ {
+ switch ( eZoom )
+ {
+ case SvxZoomType::OPTIMAL:
+ case SvxZoomType::WHOLEPAGE:
+ nZoom = pPreview->GetOptimalZoom(false);
+ break;
+ case SvxZoomType::PAGEWIDTH:
+ nZoom = pPreview->GetOptimalZoom(true);
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ pPreview->SetZoom( nZoom );
+ rReq.Done();
+ }
+ }
+ break;
+ case SID_ZOOM_IN:
+ {
+ sal_uInt16 nNew = pPreview->GetZoom() + 20 ;
+ nNew -= nNew % 20;
+ pPreview->SetZoom( nNew );
+ eZoom = SvxZoomType::PERCENT;
+ rReq.Done();
+ }
+ break;
+ case SID_ZOOM_OUT:
+ {
+ sal_uInt16 nNew = pPreview->GetZoom() - 1;
+ nNew -= nNew % 20;
+ pPreview->SetZoom( nNew );
+ eZoom = SvxZoomType::PERCENT;
+ rReq.Done();
+ }
+ break;
+ case SID_PREVIEW_MARGIN:
+ {
+ bool bMargin = pPreview->GetPageMargins();
+ pPreview->SetPageMargins( !bMargin );
+ pPreview->Invalidate();
+ rReq.Done();
+ }
+ break;
+ case SID_ATTR_ZOOMSLIDER:
+ {
+ const SvxZoomSliderItem* pItem;
+ eZoom = SvxZoomType::PERCENT;
+ if( pReqArgs && (pItem = pReqArgs->GetItemIfSet( SID_ATTR_ZOOMSLIDER )) )
+ {
+ const sal_uInt16 nCurrentZoom = pItem->GetValue();
+ if( nCurrentZoom )
+ {
+ pPreview->SetZoom( nCurrentZoom );
+ rReq.Done();
+ }
+ }
+ }
+ break;
+ case SID_PREVIEW_SCALINGFACTOR:
+ {
+ const SvxZoomSliderItem* pItem;
+ SCTAB nTab = pPreview->GetTab();
+ OUString aOldName = pDocShell->GetDocument().GetPageStyle( pPreview->GetTab() );
+ ScStyleSheetPool* pStylePool = pDocShell->GetDocument().GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aOldName, SfxStyleFamily::Page );
+ OSL_ENSURE( pStyleSheet, "PageStyle not found! :-/" );
+
+ if ( pReqArgs && pStyleSheet && (pItem = pReqArgs->GetItemIfSet( SID_PREVIEW_SCALINGFACTOR )) )
+ {
+ const sal_uInt16 nCurrentZoom = pItem->GetValue();
+ SfxItemSet& rSet = pStyleSheet->GetItemSet();
+ rSet.Put( SfxUInt16Item( ATTR_PAGE_SCALE, nCurrentZoom ) );
+ ScPrintFunc aPrintFunc( pDocShell, pDocShell->GetPrinter(), nTab );
+ aPrintFunc.UpdatePages();
+ rReq.Done();
+ }
+ GetViewFrame()->GetBindings().Invalidate( nSlot );
+ }
+ break;
+ case SID_PRINTPREVIEW:
+ case SID_PREVIEW_CLOSE:
+ // print preview is now always in the same frame as the tab view
+ // -> always switch this frame back to normal view
+ // (ScTabViewShell ctor reads stored view data)
+
+ ExitPreview();
+ break;
+ case SID_CURSORPAGEUP:
+ case SID_CURSORPAGEDOWN:
+ case SID_CURSORHOME:
+ case SID_CURSOREND:
+ case SID_CURSORUP:
+ case SID_CURSORDOWN:
+ case SID_CURSORLEFT:
+ case SID_CURSORRIGHT:
+ DoScroll( nSlot );
+ break;
+ case SID_CANCEL:
+ if( ScViewUtil::IsFullScreen( *this ) )
+ ScViewUtil::SetFullScreen( *this, false );
+ break;
+
+ default:
+ break;
+ }
+}
+
+void ScPreviewShell::GetState( SfxItemSet& rSet )
+{
+ pPreview->SetInGetState(true);
+
+ SCTAB nTab = pPreview->GetTab();
+ tools::Long nPage = pPreview->GetPageNo();
+ tools::Long nTotal = pPreview->GetTotalPages();
+ sal_uInt16 nZoom = pPreview->GetZoom();
+ bool bAllTested = pPreview->AllTested();
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while ( nWhich )
+ {
+ switch (nWhich)
+ {
+ case SID_STATUS_PAGESTYLE:
+ case SID_HFEDIT:
+ pDocShell->GetStatePageStyle( rSet, nTab );
+ break;
+ case SID_UNDO:
+ case SID_REDO:
+ case SID_REPEAT:
+ case SID_SAVEDOC:
+ case SID_SAVEASDOC:
+ case SID_MAIL_SENDDOC:
+ case SID_VIEW_DATA_SOURCE_BROWSER:
+ case SID_QUITAPP:
+ rSet.DisableItem(nWhich);
+ break;
+ case SID_PREVIEW_PREVIOUS:
+ case SID_PREVIEW_FIRST:
+ if (!nTotal || nPage==0)
+ rSet.DisableItem(nWhich);
+ break;
+ case SID_PREVIEW_NEXT:
+ case SID_PREVIEW_LAST:
+ if (bAllTested)
+ if (!nTotal || nPage==nTotal-1)
+ rSet.DisableItem(nWhich);
+ break;
+ case SID_ZOOM_IN:
+ if (nZoom >= 400)
+ rSet.DisableItem(nWhich);
+ break;
+ case SID_ZOOM_OUT:
+ if (nZoom <= 20)
+ rSet.DisableItem(nWhich);
+ break;
+ case SID_ATTR_ZOOM:
+ {
+ SvxZoomItem aZoom( eZoom, nZoom, nWhich );
+ aZoom.SetValueSet( SvxZoomEnableFlags::ALL & ~SvxZoomEnableFlags::OPTIMAL );
+ rSet.Put( aZoom );
+ }
+ break;
+ case SID_ATTR_ZOOMSLIDER:
+ {
+ SvxZoomSliderItem aZoomSliderItem( nZoom, MINZOOM, MAXZOOM, SID_ATTR_ZOOMSLIDER );
+ aZoomSliderItem.AddSnappingPoint( 100 );
+ rSet.Put( aZoomSliderItem );
+ }
+ break;
+ case SID_PREVIEW_SCALINGFACTOR:
+ {
+ if( pDocShell->IsReadOnly() )
+ rSet.DisableItem( nWhich );
+ else
+ {
+ OUString aOldName = pDocShell->GetDocument().GetPageStyle( pPreview->GetTab() );
+ ScStyleSheetPool* pStylePool = pDocShell->GetDocument().GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aOldName, SfxStyleFamily::Page );
+ OSL_ENSURE( pStyleSheet, "PageStyle not found! :-/" );
+
+ if ( pStyleSheet )
+ {
+ SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
+ sal_uInt16 nCurrentZoom = rStyleSet.Get(ATTR_PAGE_SCALE).GetValue();
+ if( nCurrentZoom )
+ {
+ SvxZoomSliderItem aZoomSliderItem( nCurrentZoom, MINZOOM_SLIDER, MAXZOOM_SLIDER, SID_PREVIEW_SCALINGFACTOR );
+ aZoomSliderItem.AddSnappingPoint( 100 );
+ rSet.Put( aZoomSliderItem );
+ }
+ else
+ rSet.DisableItem( nWhich );
+ }
+ }
+ }
+ break;
+ case SID_STATUS_DOCPOS:
+ rSet.Put( SfxStringItem( nWhich, pPreview->GetPosString() ) );
+ break;
+ case SID_PRINTPREVIEW:
+ rSet.Put( SfxBoolItem( nWhich, true ) );
+ break;
+ case SID_FORMATPAGE:
+ case SID_PREVIEW_MARGIN:
+ if( pDocShell->IsReadOnly() )
+ rSet.DisableItem( nWhich );
+ break;
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+
+ pPreview->SetInGetState(false);
+}
+
+void ScPreviewShell::FillFieldData( ScHeaderFieldData& rData )
+{
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab = pPreview->GetTab();
+ OUString aTmp;
+ rDoc.GetName(nTab, aTmp);
+ rData.aTabName = aTmp;
+
+ if( pDocShell->getDocProperties()->getTitle().getLength() != 0 )
+ rData.aTitle = pDocShell->getDocProperties()->getTitle();
+ else
+ rData.aTitle = pDocShell->GetTitle();
+
+ const INetURLObject& rURLObj = pDocShell->GetMedium()->GetURLObject();
+ rData.aLongDocName = rURLObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+ if ( !rData.aLongDocName.isEmpty() )
+ rData.aShortDocName = rURLObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
+ else
+ rData.aShortDocName = rData.aLongDocName = rData.aTitle;
+ rData.nPageNo = pPreview->GetPageNo() + 1;
+
+ bool bAllTested = pPreview->AllTested();
+ if (bAllTested)
+ rData.nTotalPages = pPreview->GetTotalPages();
+ else
+ rData.nTotalPages = 99;
+
+ // the dialog knows eNumType
+}
+
+void ScPreviewShell::WriteUserData(OUString& rData, bool /* bBrowse */)
+{
+ // nZoom
+ // nPageNo
+
+ rData = OUString::number(pPreview->GetZoom())
+ + OUStringChar(SC_USERDATA_SEP)
+ + OUString::number(pPreview->GetPageNo());
+}
+
+void ScPreviewShell::ReadUserData(const OUString& rData, bool /* bBrowse */)
+{
+ if (!rData.isEmpty())
+ {
+ sal_Int32 nIndex = 0;
+ pPreview->SetZoom(static_cast<sal_uInt16>(o3tl::toInt32(o3tl::getToken(rData, 0, SC_USERDATA_SEP, nIndex))));
+ pPreview->SetPageNo(o3tl::toInt32(o3tl::getToken(rData, 0, SC_USERDATA_SEP, nIndex)));
+ eZoom = SvxZoomType::PERCENT;
+ }
+}
+
+void ScPreviewShell::WriteUserDataSequence(uno::Sequence < beans::PropertyValue >& rSeq)
+{
+ // tdf#130559: don't export preview view data if active
+ if (comphelper::IsContextFlagActive("NoPreviewData"))
+ return;
+
+ rSeq.realloc(3);
+ beans::PropertyValue* pSeq = rSeq.getArray();
+ sal_uInt16 nViewID(GetViewFrame()->GetCurViewId());
+ pSeq[0].Name = SC_VIEWID;
+ pSeq[0].Value <<= SC_VIEW + OUString::number(nViewID);
+ pSeq[1].Name = SC_ZOOMVALUE;
+ pSeq[1].Value <<= sal_Int32 (pPreview->GetZoom());
+ pSeq[2].Name = "PageNumber";
+ pSeq[2].Value <<= pPreview->GetPageNo();
+
+ // Common SdrModel processing
+ if (ScDrawLayer* pDrawLayer = GetDocument().GetDrawLayer())
+ pDrawLayer->WriteUserDataSequence(rSeq);
+}
+
+void ScPreviewShell::ReadUserDataSequence(const uno::Sequence < beans::PropertyValue >& rSeq)
+{
+ for (const auto& propval : rSeq)
+ {
+ if (propval.Name == SC_ZOOMVALUE)
+ {
+ sal_Int32 nTemp = 0;
+ if (propval.Value >>= nTemp)
+ pPreview->SetZoom(sal_uInt16(nTemp));
+ }
+ else if (propval.Name == "PageNumber")
+ {
+ sal_Int32 nTemp = 0;
+ if (propval.Value >>= nTemp)
+ pPreview->SetPageNo(nTemp);
+ }
+ // Fallback to common SdrModel processing
+ else
+ pDocShell->MakeDrawLayer()->ReadUserDataSequenceValue(&propval);
+ }
+}
+
+void ScPreviewShell::DoScroll( sal_uInt16 nMode )
+{
+ Point aCurPos, aPrevPos;
+
+ tools::Long nHRange = pHorScroll->GetRange().Max();
+ tools::Long nHLine = pHorScroll->GetLineSize();
+ tools::Long nHPage = pHorScroll->GetPageSize();
+ tools::Long nVRange = pVerScroll->GetRange().Max();
+ tools::Long nVLine = pVerScroll->GetLineSize();
+ tools::Long nVPage = pVerScroll->GetPageSize();
+
+ aCurPos.setX( pHorScroll->GetThumbPos() );
+ aCurPos.setY( pVerScroll->GetThumbPos() );
+ aPrevPos = aCurPos;
+
+ tools::Long nThumbPos = pVerScroll->GetThumbPos();
+ tools::Long nRangeMax = pVerScroll->GetRangeMax();
+
+ switch( nMode )
+ {
+ case SID_CURSORUP:
+ if( nMaxVertPos<0 )
+ {
+ tools::Long nPage = pPreview->GetPageNo();
+
+ if( nPage>0 )
+ {
+ SfxViewFrame* pSfxViewFrame = GetViewFrame();
+ SfxRequest aSfxRequest( pSfxViewFrame, SID_PREVIEW_PREVIOUS );
+ Execute( aSfxRequest );
+ }
+ }
+ else
+ aCurPos.AdjustY( -nVLine );
+ break;
+ case SID_CURSORDOWN:
+ if( nMaxVertPos<0 )
+ {
+ tools::Long nPage = pPreview->GetPageNo();
+ tools::Long nTotal = pPreview->GetTotalPages();
+
+ // before testing for last page, make sure all page counts are calculated
+ if ( nPage+1 == nTotal && !pPreview->AllTested() )
+ {
+ pPreview->CalcAll();
+ nTotal = pPreview->GetTotalPages();
+ }
+
+ if( nPage<nTotal-1 )
+ {
+ SfxViewFrame* pSfxViewFrame = GetViewFrame();
+ SfxRequest aSfxRequest( pSfxViewFrame, SID_PREVIEW_NEXT );
+ Execute( aSfxRequest );
+ }
+ }
+ else
+ aCurPos.AdjustY(nVLine );
+ break;
+ case SID_CURSORLEFT:
+ aCurPos.AdjustX( -nHLine );
+ break;
+ case SID_CURSORRIGHT:
+ aCurPos.AdjustX(nHLine );
+ break;
+ case SID_CURSORPAGEUP:
+ if( nThumbPos==0 || nMaxVertPos<0 )
+ {
+ tools::Long nPage = pPreview->GetPageNo();
+
+ if( nPage>0 )
+ {
+ SfxViewFrame* pSfxViewFrame = GetViewFrame();
+ SfxRequest aSfxRequest( pSfxViewFrame, SID_PREVIEW_PREVIOUS );
+ Execute( aSfxRequest );
+ aCurPos.setY( nVRange );
+ }
+ }
+ else
+ aCurPos.AdjustY( -nVPage );
+ break;
+ case SID_CURSORPAGEDOWN:
+ if( (std::abs(nVPage+nThumbPos-nRangeMax)<10) || nMaxVertPos<0 )
+ {
+ tools::Long nPage = pPreview->GetPageNo();
+ tools::Long nTotal = pPreview->GetTotalPages();
+
+ // before testing for last page, make sure all page counts are calculated
+ if ( nPage+1 == nTotal && !pPreview->AllTested() )
+ {
+ pPreview->CalcAll();
+ nTotal = pPreview->GetTotalPages();
+ }
+ if( nPage<nTotal-1 )
+ {
+ SfxViewFrame* pSfxViewFrame = GetViewFrame();
+ SfxRequest aSfxRequest( pSfxViewFrame, SID_PREVIEW_NEXT );
+ Execute( aSfxRequest );
+ aCurPos.setY( 0 );
+ }
+ }
+ else
+ aCurPos.AdjustY(nVPage );
+ break;
+ case SID_CURSORHOME:
+ if( nMaxVertPos<0 )
+ {
+ tools::Long nPage = pPreview->GetPageNo();
+ tools::Long nTotal = pPreview->GetTotalPages();
+ if( nTotal && nPage != 0 )
+ {
+ SfxViewFrame* pSfxViewFrame = GetViewFrame();
+ SfxRequest aSfxRequest( pSfxViewFrame, SID_PREVIEW_FIRST );
+ Execute( aSfxRequest );
+ }
+ }
+ else
+ {
+ aCurPos.setY( 0 );
+ aCurPos.setX( 0 );
+ }
+ break;
+ case SID_CURSOREND:
+ if( nMaxVertPos<0 )
+ {
+ if( !pPreview->AllTested() )
+ pPreview->CalcAll();
+ tools::Long nPage = pPreview->GetPageNo();
+ tools::Long nTotal = pPreview->GetTotalPages();
+ if( nTotal && nPage+1 != nTotal )
+ {
+ SfxViewFrame* pSfxViewFrame = GetViewFrame();
+ SfxRequest aSfxRequest( pSfxViewFrame, SID_PREVIEW_LAST );
+ Execute( aSfxRequest );
+ }
+ }
+ else
+ {
+ aCurPos.setY( nVRange );
+ aCurPos.setX( nHRange );
+ }
+ break;
+ }
+
+ // nHRange-nHPage might be negative, that's why we check for < 0 afterwards
+
+ if( aCurPos.Y() > (nVRange-nVPage) )
+ aCurPos.setY( nVRange-nVPage );
+ if( aCurPos.Y() < 0 )
+ aCurPos.setY( 0 );
+ if( aCurPos.X() > (nHRange-nHPage) )
+ aCurPos.setX( nHRange-nHPage );
+ if( aCurPos.X() < 0 )
+ aCurPos.setX( 0 );
+
+ if( nMaxVertPos>=0 )
+ {
+ if( aCurPos.Y() != aPrevPos.Y() )
+ {
+ pVerScroll->SetThumbPos( aCurPos.Y() );
+ pPreview->SetYOffset( aCurPos.Y() );
+ }
+ }
+
+ if( aCurPos.X() != aPrevPos.X() )
+ {
+ pHorScroll->SetThumbPos( aCurPos.X() );
+ pPreview->SetXOffset( aCurPos.X() );
+ }
+
+}
+
+void ScPreviewShell::ExitPreview()
+{
+ GetViewFrame()->GetDispatcher()->Execute(SID_VIEWSHELL0, SfxCallMode::ASYNCHRON);
+}
+
+void ScPreviewShell::AddAccessibilityObject( SfxListener& rObject )
+{
+ if (!pAccessibilityBroadcaster)
+ pAccessibilityBroadcaster.reset( new SfxBroadcaster );
+
+ rObject.StartListening( *pAccessibilityBroadcaster );
+}
+
+void ScPreviewShell::RemoveAccessibilityObject( SfxListener& rObject )
+{
+ if (pAccessibilityBroadcaster)
+ rObject.EndListening( *pAccessibilityBroadcaster );
+ else
+ {
+ OSL_FAIL("no accessibility broadcaster?");
+ }
+}
+
+void ScPreviewShell::BroadcastAccessibility( const SfxHint &rHint )
+{
+ if (pAccessibilityBroadcaster)
+ pAccessibilityBroadcaster->Broadcast( rHint );
+}
+
+bool ScPreviewShell::HasAccessibilityObjects() const
+{
+ return pAccessibilityBroadcaster && pAccessibilityBroadcaster->HasListeners();
+}
+
+const ScPreviewLocationData& ScPreviewShell::GetLocationData()
+{
+ return pPreview->GetLocationData();
+}
+
+ScDocument& ScPreviewShell::GetDocument()
+{
+ return pDocShell->GetDocument();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/prevwsh2.cxx b/sc/source/ui/view/prevwsh2.cxx
new file mode 100644
index 000000000..bb15ac24a
--- /dev/null
+++ b/sc/source/ui/view/prevwsh2.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 <svx/svdmodel.hxx>
+#include <svl/hint.hxx>
+
+#include <prevwsh.hxx>
+#include <docsh.hxx>
+#include <preview.hxx>
+#include <hints.hxx>
+
+void ScPreviewShell::Notify( SfxBroadcaster&, const SfxHint& rHint )
+{
+ bool bDataChanged = false;
+
+ if (rHint.GetId() == SfxHintId::ThisIsAnSdrHint)
+ {
+ const SdrHint* pSdrHint = static_cast<const SdrHint*>(&rHint);
+ // SdrHints are no longer used for invalidating, thus react on objectchange instead
+ if(SdrHintKind::ObjectChange == pSdrHint->GetKind())
+ bDataChanged = true;
+ }
+ else if (const ScPaintHint* pPaintHint = dynamic_cast<const ScPaintHint*>(&rHint))
+ {
+ PaintPartFlags nParts = pPaintHint->GetParts();
+ if (nParts & ( PaintPartFlags::Grid | PaintPartFlags::Left | PaintPartFlags::Top | PaintPartFlags::Size ))
+ bDataChanged = true;
+ }
+ else
+ {
+ switch ( rHint.GetId() )
+ {
+ case SfxHintId::ScDataChanged:
+ case SfxHintId::ScPrintOptions:
+ bDataChanged = true;
+ break;
+ case SfxHintId::ScDrawLayerNew:
+ {
+ SfxBroadcaster* pDrawBC = pDocShell->GetDocument().GetDrawBroadcaster();
+ if (pDrawBC)
+ StartListening(*pDrawBC);
+ }
+ break;
+ default: break;
+ }
+ }
+
+ if (bDataChanged)
+ pPreview->DataChanged(true);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/printfun.cxx b/sc/source/ui/view/printfun.cxx
new file mode 100644
index 000000000..3cb543a8f
--- /dev/null
+++ b/sc/source/ui/view/printfun.cxx
@@ -0,0 +1,3229 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+
+#include <printfun.hxx>
+
+#include <editeng/adjustitem.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <svtools/colorcfg.hxx>
+#include <editeng/editstat.hxx>
+#include <svx/fmview.hxx>
+#include <editeng/frmdiritem.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/paperinf.hxx>
+#include <editeng/pbinitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <editeng/sizeitem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <sfx2/printer.hxx>
+#include <tools/multisel.hxx>
+#include <sfx2/docfile.hxx>
+#include <tools/urlobj.hxx>
+#include <osl/diagnose.h>
+
+#include <editutil.hxx>
+#include <docsh.hxx>
+#include <output.hxx>
+#include <viewdata.hxx>
+#include <viewopti.hxx>
+#include <stlpool.hxx>
+#include <pagepar.hxx>
+#include <attrib.hxx>
+#include <patattr.hxx>
+#include <docpool.hxx>
+#include <dociter.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <pagedata.hxx>
+#include <printopt.hxx>
+#include <prevloc.hxx>
+#include <scmod.hxx>
+#include <drwlayer.hxx>
+#include <fillinfo.hxx>
+#include <postit.hxx>
+
+#include <memory>
+#include <com/sun/star/document/XDocumentProperties.hpp>
+
+#define ZOOM_MIN 10
+
+namespace{
+
+bool lcl_GetBool(const SfxItemSet* pSet, sal_uInt16 nWhich)
+{
+ return static_cast<const SfxBoolItem&>(pSet->Get(nWhich)).GetValue();
+}
+
+sal_uInt16 lcl_GetUShort(const SfxItemSet* pSet, sal_uInt16 nWhich)
+{
+ return static_cast<const SfxUInt16Item&>(pSet->Get(nWhich)).GetValue();
+}
+
+bool lcl_GetShow(const SfxItemSet* pSet, sal_uInt16 nWhich)
+{
+ return ScVObjMode::VOBJ_MODE_SHOW == static_cast<const ScViewObjectModeItem&>(pSet->Get(nWhich)).GetValue();
+}
+
+
+} // namespace
+
+ScPageRowEntry::ScPageRowEntry(const ScPageRowEntry& r)
+{
+ nStartRow = r.nStartRow;
+ nEndRow = r.nEndRow;
+ nPagesX = r.nPagesX;
+ aHidden = r.aHidden;
+ aHidden.resize(nPagesX, false);
+}
+
+ScPageRowEntry& ScPageRowEntry::operator=(const ScPageRowEntry& r)
+{
+ nStartRow = r.nStartRow;
+ nEndRow = r.nEndRow;
+ nPagesX = r.nPagesX;
+ aHidden = r.aHidden;
+ aHidden.resize(nPagesX, false);
+ return *this;
+}
+
+void ScPageRowEntry::SetPagesX(size_t nNew)
+{
+ nPagesX = nNew;
+ aHidden.resize(nPagesX, false);
+}
+
+void ScPageRowEntry::SetHidden(size_t nX)
+{
+ if ( nX < nPagesX )
+ {
+ if ( nX+1 == nPagesX ) // last page?
+ --nPagesX;
+ else
+ {
+ aHidden.resize(nPagesX, false);
+ aHidden[nX] = true;
+ }
+ }
+}
+
+bool ScPageRowEntry::IsHidden(size_t nX) const
+{
+ return nX >= nPagesX || aHidden[nX]; //! inline?
+}
+
+size_t ScPageRowEntry::CountVisible() const
+{
+ if (!aHidden.empty())
+ {
+ size_t nVis = 0;
+ for (size_t i=0; i<nPagesX; i++)
+ if (!aHidden[i])
+ ++nVis;
+ return nVis;
+ }
+ else
+ return nPagesX;
+}
+
+static tools::Long lcl_LineTotal(const ::editeng::SvxBorderLine* pLine)
+{
+ return pLine ? ( pLine->GetScaledWidth() ) : 0;
+}
+
+void ScPrintFunc::Construct( const ScPrintOptions* pOptions )
+{
+ pDocShell->UpdatePendingRowHeights( nPrintTab );
+
+ SfxPrinter* pDocPrinter = rDoc.GetPrinter(); // use the printer, even for preview
+ if (pDocPrinter)
+ aOldPrinterMode = pDocPrinter->GetMapMode();
+
+ // unified MapMode for all calls (e.g. Repaint!!!)
+ // else, EditEngine outputs different text heights
+ pDev->SetMapMode(MapMode(MapUnit::MapPixel));
+
+ pBorderItem = nullptr;
+ pBackgroundItem = nullptr;
+ pShadowItem = nullptr;
+
+ pEditEngine = nullptr;
+ pEditDefaults = nullptr;
+
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find(
+ rDoc.GetPageStyle( nPrintTab ),
+ SfxStyleFamily::Page );
+ if (pStyleSheet)
+ pParamSet = &pStyleSheet->GetItemSet();
+ else
+ {
+ OSL_FAIL("Template not found" );
+ pParamSet = nullptr;
+ }
+
+ if (!bFromPrintState)
+ nZoom = 100;
+ nManualZoom = 100;
+ bClearWin = false;
+ bUseStyleColor = false;
+ bIsRender = false;
+
+ InitParam(pOptions);
+
+ pPageData = nullptr; // is only needed for initialisation
+}
+
+ScPrintFunc::ScPrintFunc( ScDocShell* pShell, SfxPrinter* pNewPrinter, SCTAB nTab,
+ tools::Long nPage, tools::Long nDocP, const ScRange* pArea,
+ const ScPrintOptions* pOptions,
+ ScPageBreakData* pData )
+ : pDocShell ( pShell ),
+ rDoc(pDocShell->GetDocument()),
+ pPrinter ( pNewPrinter ),
+ pDrawView ( nullptr ),
+ nPrintTab ( nTab ),
+ nPageStart ( nPage ),
+ nDocPages ( nDocP ),
+ pUserArea ( pArea ),
+ bFromPrintState ( false ),
+ bSourceRangeValid ( false ),
+ bPrintCurrentTable ( false ),
+ bMultiArea ( false ),
+ mbHasPrintRange(true),
+ nTabPages ( 0 ),
+ nTotalPages ( 0 ),
+ bPrintAreaValid ( false ),
+ pPageData ( pData )
+{
+ pDev = pPrinter.get();
+ aSrcOffset = pPrinter->PixelToLogic(pPrinter->GetPageOffsetPixel(), MapMode(MapUnit::Map100thMM));
+ m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
+ m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
+ m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
+ Construct( pOptions );
+}
+
+ScPrintFunc::ScPrintFunc(ScDocShell* pShell, SfxPrinter* pNewPrinter,
+ const ScPrintState& rState, const ScPrintOptions* pOptions)
+ : pDocShell ( pShell ),
+ rDoc(pDocShell->GetDocument()),
+ pPrinter ( pNewPrinter ),
+ pDrawView ( nullptr ),
+ pUserArea ( nullptr ),
+ bSourceRangeValid ( false ),
+ bPrintCurrentTable ( false ),
+ bMultiArea ( false ),
+ mbHasPrintRange(true),
+ pPageData ( nullptr )
+{
+ pDev = pPrinter.get();
+
+ nPrintTab = rState.nPrintTab;
+ nStartCol = rState.nStartCol;
+ nStartRow = rState.nStartRow;
+ nEndCol = rState.nEndCol;
+ nEndRow = rState.nEndRow;
+ bPrintAreaValid = rState.bPrintAreaValid;
+ nZoom = rState.nZoom;
+ m_aRanges.m_nPagesX = rState.nPagesX;
+ m_aRanges.m_nPagesY = rState.nPagesY;
+ nTabPages = rState.nTabPages;
+ nTotalPages = rState.nTotalPages;
+ nPageStart = rState.nPageStart;
+ nDocPages = rState.nDocPages;
+ bFromPrintState = true;
+
+ if (rState.bSavedStateRanges)
+ {
+ m_aRanges.m_nTotalY = rState.nTotalY;
+ m_aRanges.m_xPageEndX = rState.xPageEndX;
+ m_aRanges.m_xPageEndY = rState.xPageEndY;
+ m_aRanges.m_xPageRows = rState.xPageRows;
+ m_aRanges.m_aInput = rState.aPrintPageRangesInput;
+ }
+ else
+ {
+ m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
+ m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
+ m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
+ }
+
+ aSrcOffset = pPrinter->PixelToLogic(pPrinter->GetPageOffsetPixel(), MapMode(MapUnit::Map100thMM));
+ Construct( pOptions );
+}
+
+ScPrintFunc::ScPrintFunc( OutputDevice* pOutDev, ScDocShell* pShell, SCTAB nTab,
+ tools::Long nPage, tools::Long nDocP, const ScRange* pArea,
+ const ScPrintOptions* pOptions )
+ : pDocShell ( pShell ),
+ rDoc(pDocShell->GetDocument()),
+ pPrinter ( nullptr ),
+ pDrawView ( nullptr ),
+ nPrintTab ( nTab ),
+ nPageStart ( nPage ),
+ nDocPages ( nDocP ),
+ pUserArea ( pArea ),
+ bFromPrintState ( false ),
+ bSourceRangeValid ( false ),
+ bPrintCurrentTable ( false ),
+ bMultiArea ( false ),
+ mbHasPrintRange(true),
+ nTabPages ( 0 ),
+ nTotalPages ( 0 ),
+ bPrintAreaValid ( false ),
+ pPageData ( nullptr )
+{
+ pDev = pOutDev;
+ m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
+ m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
+ m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
+ Construct( pOptions );
+}
+
+ScPrintFunc::ScPrintFunc( OutputDevice* pOutDev, ScDocShell* pShell,
+ const ScPrintState& rState, const ScPrintOptions* pOptions )
+ : pDocShell ( pShell ),
+ rDoc(pDocShell->GetDocument()),
+ pPrinter ( nullptr ),
+ pDrawView ( nullptr ),
+ pUserArea ( nullptr ),
+ bSourceRangeValid ( false ),
+ bPrintCurrentTable ( false ),
+ bMultiArea ( false ),
+ mbHasPrintRange(true),
+ pPageData ( nullptr )
+{
+ pDev = pOutDev;
+
+ nPrintTab = rState.nPrintTab;
+ nStartCol = rState.nStartCol;
+ nStartRow = rState.nStartRow;
+ nEndCol = rState.nEndCol;
+ nEndRow = rState.nEndRow;
+ bPrintAreaValid = rState.bPrintAreaValid;
+ nZoom = rState.nZoom;
+ m_aRanges.m_nPagesX = rState.nPagesX;
+ m_aRanges.m_nPagesY = rState.nPagesY;
+ nTabPages = rState.nTabPages;
+ nTotalPages = rState.nTotalPages;
+ nPageStart = rState.nPageStart;
+ nDocPages = rState.nDocPages;
+ bFromPrintState = true;
+
+ if (rState.bSavedStateRanges)
+ {
+ m_aRanges.m_nTotalY = rState.nTotalY;
+ m_aRanges.m_xPageEndX = rState.xPageEndX;
+ m_aRanges.m_xPageEndY = rState.xPageEndY;
+ m_aRanges.m_xPageRows = rState.xPageRows;
+ m_aRanges.m_aInput = rState.aPrintPageRangesInput;
+ }
+ else
+ {
+ m_aRanges.m_xPageEndX = std::make_shared<std::vector<SCCOL>>();
+ m_aRanges.m_xPageEndY = std::make_shared<std::vector<SCROW>>();
+ m_aRanges.m_xPageRows = std::make_shared<std::map<size_t, ScPageRowEntry>>();
+ }
+
+ Construct( pOptions );
+}
+
+void ScPrintFunc::GetPrintState(ScPrintState& rState, bool bSavePageRanges)
+{
+ rState.nPrintTab = nPrintTab;
+ rState.nStartCol = nStartCol;
+ rState.nStartRow = nStartRow;
+ rState.nEndCol = nEndCol;
+ rState.nEndRow = nEndRow;
+ rState.bPrintAreaValid = bPrintAreaValid;
+ rState.nZoom = nZoom;
+ rState.nPagesX = m_aRanges.m_nPagesX;
+ rState.nPagesY = m_aRanges.m_nPagesY;
+ rState.nTabPages = nTabPages;
+ rState.nTotalPages = nTotalPages;
+ rState.nPageStart = nPageStart;
+ rState.nDocPages = nDocPages;
+ if (bSavePageRanges)
+ {
+ rState.bSavedStateRanges = true;
+ rState.nTotalY = m_aRanges.m_nTotalY;
+ rState.xPageEndX = m_aRanges.m_xPageEndX;
+ rState.xPageEndY = m_aRanges.m_xPageEndY;
+ rState.xPageRows = m_aRanges.m_xPageRows;
+ rState.aPrintPageRangesInput = m_aRanges.m_aInput;
+ }
+}
+
+bool ScPrintFunc::GetLastSourceRange( ScRange& rRange ) const
+{
+ rRange = aLastSourceRange;
+ return bSourceRangeValid;
+}
+
+void ScPrintFunc::FillPageData()
+{
+ if (!pPageData)
+ return;
+
+ sal_uInt16 nCount = sal::static_int_cast<sal_uInt16>( pPageData->GetCount() );
+ ScPrintRangeData& rData = pPageData->GetData(nCount); // count up
+
+ assert( bPrintAreaValid );
+ rData.SetPrintRange( ScRange( nStartCol, nStartRow, nPrintTab,
+ nEndCol, nEndRow, nPrintTab ) );
+ // #i123672#
+ if(m_aRanges.m_xPageEndX->empty())
+ {
+ OSL_ENSURE(false, "vector access error for maPageEndX (!)");
+ }
+ else
+ {
+ rData.SetPagesX( m_aRanges.m_nPagesX, m_aRanges.m_xPageEndX->data());
+ }
+
+ // #i123672#
+ if(m_aRanges.m_xPageEndY->empty())
+ {
+ OSL_ENSURE(false, "vector access error for maPageEndY (!)");
+ }
+ else
+ {
+ rData.SetPagesY( m_aRanges.m_nTotalY, m_aRanges.m_xPageEndY->data());
+ }
+
+ // Settings
+ rData.SetTopDown( aTableParam.bTopDown );
+ rData.SetAutomatic( !aAreaParam.bPrintArea );
+}
+
+ScPrintFunc::~ScPrintFunc()
+{
+ pEditDefaults.reset();
+ pEditEngine.reset();
+
+ // Printer settings are now restored from outside
+
+ // For DrawingLayer/Charts, the MapMode of the printer (RefDevice) must always be correct
+ SfxPrinter* pDocPrinter = rDoc.GetPrinter(); // use Preview also for the printer
+ if (pDocPrinter)
+ pDocPrinter->SetMapMode(aOldPrinterMode);
+}
+
+void ScPrintFunc::SetDrawView( FmFormView* pNew )
+{
+ pDrawView = pNew;
+}
+
+static void lcl_HidePrint( const ScTableInfo& rTabInfo, SCCOL nX1, SCCOL nX2 )
+{
+ for (SCSIZE nArrY=1; nArrY+1<rTabInfo.mnArrCount; nArrY++)
+ {
+ RowInfo* pThisRowInfo = &rTabInfo.mpRowInfo[nArrY];
+ for (SCCOL nX=nX1; nX<=nX2; nX++)
+ {
+ ScCellInfo& rCellInfo = pThisRowInfo->cellInfo(nX);
+ ScBasicCellInfo& rBasicCellInfo = pThisRowInfo->basicCellInfo(nX);
+ if (!rBasicCellInfo.bEmptyCellText)
+ if (rCellInfo.pPatternAttr->
+ GetItem(ATTR_PROTECTION, rCellInfo.pConditionSet).GetHidePrint())
+ {
+ rCellInfo.maCell.clear();
+ rBasicCellInfo.bEmptyCellText = true;
+ }
+ }
+ }
+}
+
+// output to Device (static)
+//
+// us used for:
+// - Clipboard/Bitmap
+// - Ole-Object (DocShell::Draw)
+// - Preview of templates
+
+void ScPrintFunc::DrawToDev(ScDocument& rDoc, OutputDevice* pDev, double /* nPrintFactor */,
+ const tools::Rectangle& rBound, ScViewData* pViewData, bool bMetaFile)
+{
+ //! evaluate nPrintFactor !!!
+
+ SCTAB nTab = 0;
+ if (pViewData)
+ nTab = pViewData->GetTabNo();
+
+ bool bDoGrid, bNullVal, bFormula;
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( rDoc.GetPageStyle( nTab ), SfxStyleFamily::Page );
+ if (pStyleSheet)
+ {
+ SfxItemSet& rSet = pStyleSheet->GetItemSet();
+ bDoGrid = rSet.Get(ATTR_PAGE_GRID).GetValue();
+ bNullVal = rSet.Get(ATTR_PAGE_NULLVALS).GetValue();
+ bFormula = rSet.Get(ATTR_PAGE_FORMULAS).GetValue();
+ }
+ else
+ {
+ const ScViewOptions& rOpt = rDoc.GetViewOptions();
+ bDoGrid = rOpt.GetOption(VOPT_GRID);
+ bNullVal = rOpt.GetOption(VOPT_NULLVALS);
+ bFormula = rOpt.GetOption(VOPT_FORMULAS);
+ }
+
+ MapMode aMode = pDev->GetMapMode();
+
+ tools::Rectangle aRect = rBound;
+
+ if (aRect.Right() < aRect.Left() || aRect.Bottom() < aRect.Top())
+ aRect = tools::Rectangle( Point(), pDev->GetOutputSize() );
+
+ SCCOL nX1 = 0;
+ SCROW nY1 = 0;
+ SCCOL nX2 = OLE_STD_CELLS_X - 1;
+ SCROW nY2 = OLE_STD_CELLS_Y - 1;
+ if (bMetaFile)
+ {
+ ScRange aRange = rDoc.GetRange( nTab, rBound );
+ nX1 = aRange.aStart.Col();
+ nY1 = aRange.aStart.Row();
+ nX2 = aRange.aEnd.Col();
+ nY2 = aRange.aEnd.Row();
+ }
+ else if (pViewData)
+ {
+ ScSplitPos eWhich = pViewData->GetActivePart();
+ ScHSplitPos eHWhich = WhichH(eWhich);
+ ScVSplitPos eVWhich = WhichV(eWhich);
+ nX1 = pViewData->GetPosX(eHWhich);
+ nY1 = pViewData->GetPosY(eVWhich);
+ nX2 = nX1 + pViewData->VisibleCellsX(eHWhich);
+ if (nX2>nX1) --nX2;
+ nY2 = nY1 + pViewData->VisibleCellsY(eVWhich);
+ if (nY2>nY1) --nY2;
+ }
+
+ if (nX1 > rDoc.MaxCol()) nX1 = rDoc.MaxCol();
+ if (nX2 > rDoc.MaxCol()) nX2 = rDoc.MaxCol();
+ if (nY1 > rDoc.MaxRow()) nY1 = rDoc.MaxRow();
+ if (nY2 > rDoc.MaxRow()) nY2 = rDoc.MaxRow();
+
+ tools::Long nDevSizeX = aRect.Right()-aRect.Left()+1;
+ tools::Long nDevSizeY = aRect.Bottom()-aRect.Top()+1;
+
+ tools::Long nTwipsSizeX = 0;
+ for (SCCOL i=nX1; i<=nX2; i++)
+ nTwipsSizeX += rDoc.GetColWidth( i, nTab );
+ tools::Long nTwipsSizeY = rDoc.GetRowHeight( nY1, nY2, nTab );
+
+ // if no lines, still space for the outline frame (20 Twips = 1pt)
+ // (HasLines initializes aLines to 0,0,0,0)
+ nTwipsSizeX += 20;
+ nTwipsSizeY += 20;
+
+ double nScaleX = static_cast<double>(nDevSizeX) / nTwipsSizeX;
+ double nScaleY = static_cast<double>(nDevSizeY) / nTwipsSizeY;
+
+ //! hand over Flag at FillInfo !!!!!
+ ScRange aERange;
+ bool bEmbed = rDoc.IsEmbedded();
+ if (bEmbed)
+ {
+ rDoc.GetEmbedded(aERange);
+ rDoc.ResetEmbedded();
+ }
+
+ // Assemble data
+
+ ScTableInfo aTabInfo;
+ rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nTab,
+ nScaleX, nScaleY, false, bFormula );
+ lcl_HidePrint( aTabInfo, nX1, nX2 );
+
+ if (bEmbed)
+ rDoc.SetEmbedded(aERange);
+
+ tools::Long nScrX = aRect.Left();
+ tools::Long nScrY = aRect.Top();
+
+ // If no lines, still leave space for grid lines
+ // (would be elseways cut away)
+ nScrX += 1;
+ nScrY += 1;
+
+ ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, &rDoc, nTab,
+ nScrX, nScrY, nX1, nY1, nX2, nY2, nScaleX, nScaleY );
+ aOutputData.SetMetaFileMode(bMetaFile);
+ aOutputData.SetShowNullValues(bNullVal);
+ aOutputData.SetShowFormulas(bFormula);
+
+ ScDrawLayer* pModel = rDoc.GetDrawLayer();
+ std::unique_ptr<FmFormView> pDrawView;
+
+ if( pModel )
+ {
+ pDrawView.reset(
+ new FmFormView(
+ *pModel,
+ pDev));
+ pDrawView->ShowSdrPage(pDrawView->GetModel()->GetPage(nTab));
+ pDrawView->SetPrintPreview();
+ aOutputData.SetDrawView( pDrawView.get() );
+ }
+
+ //! SetUseStyleColor ??
+
+ if ( bMetaFile && pDev->IsVirtual() )
+ aOutputData.SetSnapPixel();
+
+ Point aLogStart = pDev->PixelToLogic(Point(nScrX, nScrY), MapMode(MapUnit::Map100thMM));
+ tools::Long nLogStX = aLogStart.X();
+ tools::Long nLogStY = aLogStart.Y();
+
+ //! nZoom for GetFont in OutputData ???
+
+ if (!bMetaFile && pViewData)
+ pDev->SetMapMode(pViewData->GetLogicMode(pViewData->GetActivePart()));
+
+ // #i72502#
+ const Point aMMOffset(aOutputData.PrePrintDrawingLayer(nLogStX, nLogStY));
+ aOutputData.PrintDrawingLayer(SC_LAYER_BACK, aMMOffset);
+
+ if (!bMetaFile && pViewData)
+ pDev->SetMapMode(aMode);
+
+ aOutputData.DrawBackground(*pDev);
+
+ aOutputData.DrawShadow();
+ aOutputData.DrawFrame(*pDev);
+ aOutputData.DrawSparklines(*pDev);
+ aOutputData.DrawStrings();
+
+ if (!bMetaFile && pViewData)
+ pDev->SetMapMode(pViewData->GetLogicMode(pViewData->GetActivePart()));
+
+ aOutputData.DrawEdit(!bMetaFile);
+
+ if (bDoGrid)
+ {
+ if (!bMetaFile && pViewData)
+ pDev->SetMapMode(aMode);
+
+ aOutputData.DrawGrid(*pDev, true, false); // no page breaks
+
+ pDev->SetLineColor( COL_BLACK );
+
+ Size aOne = pDev->PixelToLogic( Size(1,1) );
+ if (bMetaFile)
+ aOne = Size(1,1); // compatible with DrawGrid
+ tools::Long nRight = nScrX + aOutputData.GetScrW() - aOne.Width();
+ tools::Long nBottom = nScrY + aOutputData.GetScrH() - aOne.Height();
+
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ // extra line at the left edge for left-to-right, right for right-to-left
+ if ( bLayoutRTL )
+ pDev->DrawLine( Point(nRight,nScrY), Point(nRight,nBottom) );
+ else
+ pDev->DrawLine( Point(nScrX,nScrY), Point(nScrX,nBottom) );
+ // extra line at the top in both cases
+ pDev->DrawLine( Point(nScrX,nScrY), Point(nRight,nScrY) );
+ }
+
+ // #i72502#
+ aOutputData.PrintDrawingLayer(SC_LAYER_FRONT, aMMOffset);
+ aOutputData.PrintDrawingLayer(SC_LAYER_INTERN, aMMOffset);
+ aOutputData.PostPrintDrawingLayer(aMMOffset); // #i74768#
+}
+
+// Printing
+
+static void lcl_FillHFParam( ScPrintHFParam& rParam, const SfxItemSet* pHFSet )
+{
+ // nDistance must be initialized differently before
+
+ if ( pHFSet == nullptr )
+ {
+ rParam.bEnable = false;
+ rParam.pBorder = nullptr;
+ rParam.pBack = nullptr;
+ rParam.pShadow = nullptr;
+ }
+ else
+ {
+ rParam.bEnable = pHFSet->Get(ATTR_PAGE_ON).GetValue();
+ rParam.bDynamic = pHFSet->Get(ATTR_PAGE_DYNAMIC).GetValue();
+ rParam.bShared = pHFSet->Get(ATTR_PAGE_SHARED).GetValue();
+ rParam.bSharedFirst = pHFSet->Get(ATTR_PAGE_SHARED_FIRST).GetValue();
+ rParam.nHeight = pHFSet->Get(ATTR_PAGE_SIZE).GetSize().Height();
+ const SvxLRSpaceItem* pHFLR = &pHFSet->Get(ATTR_LRSPACE);
+ tools::Long nTmp;
+ nTmp = pHFLR->GetLeft();
+ rParam.nLeft = nTmp < 0 ? 0 : sal_uInt16(nTmp);
+ nTmp = pHFLR->GetRight();
+ rParam.nRight = nTmp < 0 ? 0 : sal_uInt16(nTmp);
+ rParam.pBorder = &pHFSet->Get(ATTR_BORDER);
+ rParam.pBack = &pHFSet->Get(ATTR_BACKGROUND);
+ rParam.pShadow = &pHFSet->Get(ATTR_SHADOW);
+
+// now back in the dialog:
+// rParam.nHeight += rParam.nDistance; // not in the dialog any more ???
+
+ rParam.nHeight += lcl_LineTotal( rParam.pBorder->GetTop() ) +
+ lcl_LineTotal( rParam.pBorder->GetBottom() );
+
+ rParam.nManHeight = rParam.nHeight;
+ }
+
+ if (!rParam.bEnable)
+ rParam.nHeight = 0;
+}
+
+// bNew = TRUE: search for used part of the document
+// bNew = FALSE: only limit whole lines/columns
+
+bool ScPrintFunc::AdjustPrintArea( bool bNew )
+{
+ SCCOL nOldEndCol = nEndCol; // only important for !bNew
+ SCROW nOldEndRow = nEndRow;
+ bool bChangeCol = true; // at bNew both are being adjusted
+ bool bChangeRow = true;
+
+ bool bNotes = aTableParam.bNotes;
+ if ( bNew )
+ {
+ nStartCol = 0;
+ nStartRow = 0;
+ if (!rDoc.GetPrintArea( nPrintTab, nEndCol, nEndRow, bNotes ))
+ return false; // nothing
+ bPrintAreaValid = true;
+ }
+ else
+ {
+ bool bFound = true;
+ bChangeCol = ( nStartCol == 0 && nEndCol == rDoc.MaxCol() );
+ bChangeRow = ( nStartRow == 0 && nEndRow == rDoc.MaxRow() );
+ bool bForcedChangeRow = false;
+
+ // #i53558# Crop entire column of old row limit to real print area with
+ // some fuzzyness.
+ if (!bChangeRow && nStartRow == 0)
+ {
+ SCROW nPAEndRow;
+ bFound = rDoc.GetPrintAreaVer( nPrintTab, nStartCol, nEndCol, nPAEndRow, bNotes );
+ // Say we don't want to print more than ~1000 empty rows, which are
+ // about 14 pages intentionally left blank...
+ const SCROW nFuzzy = 23*42;
+ if (nPAEndRow + nFuzzy < nEndRow)
+ {
+ bForcedChangeRow = true;
+ nEndRow = nPAEndRow;
+ }
+ else
+ bFound = true; // user seems to _want_ to print some empty rows
+ }
+ // TODO: in case we extend the number of columns we may have to do the
+ // same for horizontal cropping.
+
+ if ( bChangeCol && bChangeRow )
+ bFound = rDoc.GetPrintArea( nPrintTab, nEndCol, nEndRow, bNotes );
+ else if ( bChangeCol )
+ bFound = rDoc.GetPrintAreaHor( nPrintTab, nStartRow, nEndRow, nEndCol );
+ else if ( bChangeRow )
+ bFound = rDoc.GetPrintAreaVer( nPrintTab, nStartCol, nEndCol, nEndRow, bNotes );
+
+ if (!bFound)
+ return false; // empty
+
+ bPrintAreaValid = true;
+ if (bForcedChangeRow)
+ bChangeRow = true;
+ }
+
+ assert( bPrintAreaValid );
+ rDoc.ExtendMerge( nStartCol,nStartRow, nEndCol,nEndRow, nPrintTab ); // no Refresh, incl. Attrs
+
+ if ( bChangeCol )
+ {
+ OutputDevice* pRefDev = rDoc.GetPrinter(); // use the printer also for Preview
+ pRefDev->SetMapMode(MapMode(MapUnit::MapPixel)); // important for GetNeededSize
+
+ rDoc.ExtendPrintArea( pRefDev,
+ nPrintTab, nStartCol, nStartRow, nEndCol, nEndRow );
+ // changing nEndCol
+ }
+
+ if ( nEndCol < rDoc.MaxCol() && rDoc.HasAttrib(
+ nEndCol,nStartRow,nPrintTab, nEndCol,nEndRow,nPrintTab, HasAttrFlags::ShadowRight ) )
+ ++nEndCol;
+ if ( nEndRow < rDoc.MaxRow() && rDoc.HasAttrib(
+ nStartCol,nEndRow,nPrintTab, nEndCol,nEndRow,nPrintTab, HasAttrFlags::ShadowDown ) )
+ ++nEndRow;
+
+ if (!bChangeCol) nEndCol = nOldEndCol;
+ if (!bChangeRow) nEndRow = nOldEndRow;
+
+ return true;
+}
+
+tools::Long ScPrintFunc::TextHeight( const EditTextObject* pObject )
+{
+ if (!pObject)
+ return 0;
+
+ pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
+
+ return static_cast<tools::Long>(pEditEngine->GetTextHeight());
+}
+
+// nZoom must be set !!!
+// and the respective Twip-MapMode configured
+
+void ScPrintFunc::UpdateHFHeight( ScPrintHFParam& rParam )
+{
+ OSL_ENSURE( aPageSize.Width(), "UpdateHFHeight without aPageSize");
+
+ if (!(rParam.bEnable && rParam.bDynamic))
+ return;
+
+ // calculate nHeight from content
+
+ MakeEditEngine();
+ tools::Long nPaperWidth = ( aPageSize.Width() - nLeftMargin - nRightMargin -
+ rParam.nLeft - rParam.nRight ) * 100 / nZoom;
+ if (rParam.pBorder)
+ nPaperWidth -= ( rParam.pBorder->GetDistance(SvxBoxItemLine::LEFT) +
+ rParam.pBorder->GetDistance(SvxBoxItemLine::RIGHT) +
+ lcl_LineTotal(rParam.pBorder->GetLeft()) +
+ lcl_LineTotal(rParam.pBorder->GetRight()) ) * 100 / nZoom;
+
+ if (rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE)
+ nPaperWidth -= ( rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT) +
+ rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT) ) * 100 / nZoom;
+
+ pEditEngine->SetPaperSize( Size( nPaperWidth, 10000 ) );
+
+ tools::Long nMaxHeight = 0;
+ if ( rParam.pLeft )
+ {
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pLeft->GetLeftArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pLeft->GetCenterArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pLeft->GetRightArea() ) );
+ }
+ if ( rParam.pRight )
+ {
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pRight->GetLeftArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pRight->GetCenterArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pRight->GetRightArea() ) );
+ }
+ if ( rParam.pFirst )
+ {
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pFirst->GetLeftArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pFirst->GetCenterArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( rParam.pFirst->GetRightArea() ) );
+ }
+
+ rParam.nHeight = nMaxHeight + rParam.nDistance;
+ if (rParam.pBorder)
+ rParam.nHeight += rParam.pBorder->GetDistance(SvxBoxItemLine::TOP) +
+ rParam.pBorder->GetDistance(SvxBoxItemLine::BOTTOM) +
+ lcl_LineTotal( rParam.pBorder->GetTop() ) +
+ lcl_LineTotal( rParam.pBorder->GetBottom() );
+ if (rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE)
+ rParam.nHeight += rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::TOP) +
+ rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM);
+
+ if (rParam.nHeight < rParam.nManHeight)
+ rParam.nHeight = rParam.nManHeight; // configured minimum
+}
+
+void ScPrintFunc::InitParam( const ScPrintOptions* pOptions )
+{
+ if (!pParamSet)
+ return;
+
+ // TabPage "Page"
+ const SvxLRSpaceItem* pLRItem = &pParamSet->Get( ATTR_LRSPACE );
+ tools::Long nTmp;
+ nTmp = pLRItem->GetLeft();
+ nLeftMargin = nTmp < 0 ? 0 : sal_uInt16(nTmp);
+ nTmp = pLRItem->GetRight();
+ nRightMargin = nTmp < 0 ? 0 : sal_uInt16(nTmp);
+ const SvxULSpaceItem* pULItem = &pParamSet->Get( ATTR_ULSPACE );
+ nTopMargin = pULItem->GetUpper();
+ nBottomMargin = pULItem->GetLower();
+
+ const SvxPageItem* pPageItem = &pParamSet->Get( ATTR_PAGE );
+ nPageUsage = pPageItem->GetPageUsage();
+ bLandscape = pPageItem->IsLandscape();
+ aFieldData.eNumType = pPageItem->GetNumType();
+
+ bCenterHor = pParamSet->Get(ATTR_PAGE_HORCENTER).GetValue();
+ bCenterVer = pParamSet->Get(ATTR_PAGE_VERCENTER).GetValue();
+
+ aPageSize = pParamSet->Get(ATTR_PAGE_SIZE).GetSize();
+ if ( !aPageSize.Width() || !aPageSize.Height() )
+ {
+ OSL_FAIL("PageSize Null ?!?!?");
+ aPageSize = SvxPaperInfo::GetPaperSize( PAPER_A4 );
+ }
+
+ pBorderItem = &pParamSet->Get(ATTR_BORDER);
+ pBackgroundItem = &pParamSet->Get(ATTR_BACKGROUND);
+ pShadowItem = &pParamSet->Get(ATTR_SHADOW);
+
+ // TabPage "Headline"
+
+ aHdr.pLeft = &pParamSet->Get(ATTR_PAGE_HEADERLEFT); // Content
+ aHdr.pRight = &pParamSet->Get(ATTR_PAGE_HEADERRIGHT);
+ aHdr.pFirst = &pParamSet->Get(ATTR_PAGE_HEADERFIRST);
+
+ const SfxItemSet* pHeaderSet = nullptr;
+ if ( const SvxSetItem* pHeaderSetItem = pParamSet->GetItemIfSet( ATTR_PAGE_HEADERSET, false ) )
+ {
+ pHeaderSet = &pHeaderSetItem->GetItemSet();
+ // Headline has space below
+ aHdr.nDistance = pHeaderSet->Get(ATTR_ULSPACE).GetLower();
+ }
+ lcl_FillHFParam( aHdr, pHeaderSet );
+
+ // TabPage "Footline"
+
+ aFtr.pLeft = &pParamSet->Get(ATTR_PAGE_FOOTERLEFT); // Content
+ aFtr.pRight = &pParamSet->Get(ATTR_PAGE_FOOTERRIGHT);
+ aFtr.pFirst = &pParamSet->Get(ATTR_PAGE_FOOTERFIRST);
+
+ const SfxItemSet* pFooterSet = nullptr;
+ if ( const SvxSetItem* pFooterSetItem = pParamSet->GetItemIfSet( ATTR_PAGE_FOOTERSET, false ) )
+ {
+ pFooterSet = &pFooterSetItem->GetItemSet();
+ // Footline has space above
+ aFtr.nDistance = pFooterSet->Get(ATTR_ULSPACE).GetUpper();
+ }
+ lcl_FillHFParam( aFtr, pFooterSet );
+
+ // Compile Table-/Area-Params from single Items
+
+ // TabPage "Table"
+
+ const SfxUInt16Item* pScaleItem = nullptr;
+ const ScPageScaleToItem* pScaleToItem = nullptr;
+ const SfxUInt16Item* pScaleToPagesItem = nullptr;
+ SfxItemState eState;
+
+ eState = pParamSet->GetItemState( ATTR_PAGE_SCALE, false,
+ reinterpret_cast<const SfxPoolItem**>(&pScaleItem) );
+ if ( SfxItemState::DEFAULT == eState )
+ pScaleItem = &pParamSet->GetPool()->GetDefaultItem( ATTR_PAGE_SCALE );
+
+ eState = pParamSet->GetItemState( ATTR_PAGE_SCALETO, false,
+ reinterpret_cast<const SfxPoolItem**>(&pScaleToItem) );
+ if ( SfxItemState::DEFAULT == eState )
+ pScaleToItem = &pParamSet->GetPool()->GetDefaultItem( ATTR_PAGE_SCALETO );
+
+ eState = pParamSet->GetItemState( ATTR_PAGE_SCALETOPAGES, false,
+ reinterpret_cast<const SfxPoolItem**>(&pScaleToPagesItem) );
+ if ( SfxItemState::DEFAULT == eState )
+ pScaleToPagesItem = &pParamSet->GetPool()->GetDefaultItem( ATTR_PAGE_SCALETOPAGES );
+
+ OSL_ENSURE( pScaleItem && pScaleToItem && pScaleToPagesItem, "Missing ScaleItem! :-/" );
+
+ aTableParam.bCellContent = true;
+ aTableParam.bNotes = lcl_GetBool(pParamSet,ATTR_PAGE_NOTES);
+ aTableParam.bGrid = lcl_GetBool(pParamSet,ATTR_PAGE_GRID);
+ aTableParam.bHeaders = lcl_GetBool(pParamSet,ATTR_PAGE_HEADERS);
+ aTableParam.bFormulas = lcl_GetBool(pParamSet,ATTR_PAGE_FORMULAS);
+ aTableParam.bNullVals = lcl_GetBool(pParamSet,ATTR_PAGE_NULLVALS);
+ aTableParam.bCharts = lcl_GetShow(pParamSet,ATTR_PAGE_CHARTS);
+ aTableParam.bObjects = lcl_GetShow(pParamSet,ATTR_PAGE_OBJECTS);
+ aTableParam.bDrawings = lcl_GetShow(pParamSet,ATTR_PAGE_DRAWINGS);
+ aTableParam.bTopDown = lcl_GetBool(pParamSet,ATTR_PAGE_TOPDOWN);
+ aTableParam.bLeftRight = !aTableParam.bLeftRight;
+ aTableParam.nFirstPageNo = lcl_GetUShort(pParamSet,ATTR_PAGE_FIRSTPAGENO);
+ if (!aTableParam.nFirstPageNo)
+ aTableParam.nFirstPageNo = static_cast<sal_uInt16>(nPageStart); // from previous table
+
+ if ( pScaleItem && pScaleToItem && pScaleToPagesItem )
+ {
+ sal_uInt16 nScaleAll = pScaleItem->GetValue();
+ sal_uInt16 nScaleToPages = pScaleToPagesItem->GetValue();
+
+ aTableParam.bScaleNone = (nScaleAll == 100);
+ aTableParam.bScaleAll = (nScaleAll > 0 );
+ aTableParam.bScaleTo = pScaleToItem->IsValid();
+ aTableParam.bScalePageNum = (nScaleToPages > 0 );
+ aTableParam.nScaleAll = nScaleAll;
+ aTableParam.nScaleWidth = pScaleToItem->GetWidth();
+ aTableParam.nScaleHeight = pScaleToItem->GetHeight();
+ aTableParam.nScalePageNum = nScaleToPages;
+ }
+ else
+ {
+ aTableParam.bScaleNone = true;
+ aTableParam.bScaleAll = false;
+ aTableParam.bScaleTo = false;
+ aTableParam.bScalePageNum = false;
+ aTableParam.nScaleAll = 0;
+ aTableParam.nScaleWidth = 0;
+ aTableParam.nScaleHeight = 0;
+ aTableParam.nScalePageNum = 0;
+ }
+
+ // skip empty pages only if options with that flag are passed
+ aTableParam.bSkipEmpty = pOptions && pOptions->GetSkipEmpty();
+ if ( pPageData )
+ aTableParam.bSkipEmpty = false;
+ // If pPageData is set, only the breaks are interesting for the
+ // pagebreak preview, empty pages are not addressed separately.
+
+ aTableParam.bForceBreaks = pOptions && pOptions->GetForceBreaks();
+
+ // TabPage "Parts":
+
+ //! walk through all PrintAreas of the table !!!
+ const ScRange* pPrintArea = rDoc.GetPrintRange( nPrintTab, 0 );
+ std::optional<ScRange> oRepeatCol = rDoc.GetRepeatColRange( nPrintTab );
+ std::optional<ScRange> oRepeatRow = rDoc.GetRepeatRowRange( nPrintTab );
+
+ // ignoring ATTR_PAGE_PRINTTABLES
+
+ bool bHasPrintRange = rDoc.HasPrintRange();
+ sal_uInt16 nPrintRangeCount = rDoc.GetPrintRangeCount(nPrintTab);
+ bool bPrintEntireSheet = rDoc.IsPrintEntireSheet(nPrintTab);
+
+ if (!bPrintEntireSheet && !nPrintRangeCount)
+ mbHasPrintRange = false;
+
+ if ( pUserArea ) // UserArea (selection) has priority
+ {
+ bPrintCurrentTable =
+ aAreaParam.bPrintArea = true; // Selection
+ aAreaParam.aPrintArea = *pUserArea;
+
+ // The table-query is already in DocShell::Print, here always
+ aAreaParam.aPrintArea.aStart.SetTab(nPrintTab);
+ aAreaParam.aPrintArea.aEnd.SetTab(nPrintTab);
+ }
+ else if (bHasPrintRange)
+ {
+ if ( pPrintArea ) // at least one set?
+ {
+ bPrintCurrentTable =
+ aAreaParam.bPrintArea = true;
+ aAreaParam.aPrintArea = *pPrintArea;
+
+ bMultiArea = nPrintRangeCount > 1;
+ }
+ else
+ {
+ // do not print hidden sheets with "Print entire sheet" flag
+ bPrintCurrentTable = rDoc.IsPrintEntireSheet( nPrintTab ) && rDoc.IsVisible( nPrintTab );
+ aAreaParam.bPrintArea = !bPrintCurrentTable; // otherwise the table is always counted
+ }
+ }
+ else
+ {
+ // don't print hidden tables if there's no print range defined there
+ if ( rDoc.IsVisible( nPrintTab ) )
+ {
+ aAreaParam.bPrintArea = false;
+ bPrintCurrentTable = true;
+ }
+ else
+ {
+ aAreaParam.bPrintArea = true; // otherwise the table is always counted
+ bPrintCurrentTable = false;
+ }
+ }
+
+ if ( oRepeatCol )
+ {
+ aAreaParam.bRepeatCol = true;
+ nRepeatStartCol = oRepeatCol->aStart.Col();
+ nRepeatEndCol = oRepeatCol->aEnd .Col();
+ }
+ else
+ {
+ aAreaParam.bRepeatCol = false;
+ nRepeatStartCol = nRepeatEndCol = SCCOL_REPEAT_NONE;
+ }
+
+ if ( oRepeatRow )
+ {
+ aAreaParam.bRepeatRow = true;
+ nRepeatStartRow = oRepeatRow->aStart.Row();
+ nRepeatEndRow = oRepeatRow->aEnd .Row();
+ }
+ else
+ {
+ aAreaParam.bRepeatRow = false;
+ nRepeatStartRow = nRepeatEndRow = SCROW_REPEAT_NONE;
+ }
+
+ // Split pages
+
+ if (!bPrintAreaValid)
+ {
+ nTabPages = CountPages(); // also calculates zoom
+ nTotalPages = nTabPages;
+ nTotalPages += CountNotePages();
+ }
+ else
+ {
+ CalcPages(); // search breaks only
+ CountNotePages(); // Count notes, even if number of pages is already known
+ }
+
+ if (nDocPages)
+ aFieldData.nTotalPages = nDocPages;
+ else
+ aFieldData.nTotalPages = nTotalPages;
+
+ SetDateTime( DateTime( DateTime::SYSTEM ) );
+
+ if( pDocShell->getDocProperties()->getTitle().getLength() != 0 )
+ aFieldData.aTitle = pDocShell->getDocProperties()->getTitle();
+ else
+ aFieldData.aTitle = pDocShell->GetTitle();
+
+ const INetURLObject& rURLObj = pDocShell->GetMedium()->GetURLObject();
+ aFieldData.aLongDocName = rURLObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+ if ( !aFieldData.aLongDocName.isEmpty() )
+ aFieldData.aShortDocName = rURLObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
+ else
+ aFieldData.aShortDocName = aFieldData.aLongDocName = aFieldData.aTitle;
+
+ // Printer settings (Orientation, Paper) at DoPrint
+}
+
+Size ScPrintFunc::GetDataSize() const
+{
+ Size aSize = aPageSize;
+ aSize.AdjustWidth( -(nLeftMargin + nRightMargin) );
+ aSize.AdjustHeight( -(nTopMargin + nBottomMargin) );
+ aSize.AdjustHeight( -(aHdr.nHeight + aFtr.nHeight) );
+ return aSize;
+}
+
+void ScPrintFunc::GetScaleData( Size& rPhysSize, tools::Long& rDocHdr, tools::Long& rDocFtr )
+{
+ rPhysSize = aPageSize;
+ rPhysSize.AdjustWidth( -(nLeftMargin + nRightMargin) );
+ rPhysSize.AdjustHeight( -(nTopMargin + nBottomMargin) );
+
+ rDocHdr = aHdr.nHeight;
+ rDocFtr = aFtr.nHeight;
+}
+
+void ScPrintFunc::SetDateTime( const DateTime& rDateTime )
+{
+ aFieldData.aDateTime = rDateTime;
+}
+
+static void lcl_DrawGraphic( const Graphic &rGraphic, vcl::RenderContext& rOutDev,
+ const tools::Rectangle &rGrf, const tools::Rectangle &rOut )
+{
+ const bool bNotInside = !rOut.Contains( rGrf );
+ if ( bNotInside )
+ {
+ rOutDev.Push();
+ rOutDev.IntersectClipRegion( rOut );
+ }
+
+ rGraphic.Draw(rOutDev, rGrf.TopLeft(), rGrf.GetSize());
+
+ if ( bNotInside )
+ rOutDev.Pop();
+}
+
+static void lcl_DrawGraphic( const SvxBrushItem &rBrush, vcl::RenderContext& rOutDev, const OutputDevice* pRefDev,
+ const tools::Rectangle &rOrg, const tools::Rectangle &rOut,
+ OUString const & referer )
+{
+ Size aGrfSize(0,0);
+ const Graphic *pGraphic = rBrush.GetGraphic(referer);
+ SvxGraphicPosition ePos;
+ if ( pGraphic && pGraphic->IsSupportedGraphic() )
+ {
+ const MapMode aMapMM( MapUnit::Map100thMM );
+ if ( pGraphic->GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel )
+ aGrfSize = pRefDev->PixelToLogic( pGraphic->GetPrefSize(), aMapMM );
+ else
+ aGrfSize = OutputDevice::LogicToLogic( pGraphic->GetPrefSize(),
+ pGraphic->GetPrefMapMode(), aMapMM );
+ ePos = rBrush.GetGraphicPos();
+ }
+ else
+ ePos = GPOS_NONE;
+
+ Point aPos;
+ Size aDrawSize = aGrfSize;
+
+ bool bDraw = true;
+ switch ( ePos )
+ {
+ case GPOS_LT: aPos = rOrg.TopLeft();
+ break;
+ case GPOS_MT: aPos.setY( rOrg.Top() );
+ aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
+ break;
+ case GPOS_RT: aPos.setY( rOrg.Top() );
+ aPos.setX( rOrg.Right() - aGrfSize.Width() );
+ break;
+
+ case GPOS_LM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
+ aPos.setX( rOrg.Left() );
+ break;
+ case GPOS_MM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
+ aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
+ break;
+ case GPOS_RM: aPos.setY( rOrg.Top() + rOrg.GetSize().Height()/2 - aGrfSize.Height()/2 );
+ aPos.setX( rOrg.Right() - aGrfSize.Width() );
+ break;
+
+ case GPOS_LB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
+ aPos.setX( rOrg.Left() );
+ break;
+ case GPOS_MB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
+ aPos.setX( rOrg.Left() + rOrg.GetSize().Width()/2 - aGrfSize.Width()/2 );
+ break;
+ case GPOS_RB: aPos.setY( rOrg.Bottom() - aGrfSize.Height() );
+ aPos.setX( rOrg.Right() - aGrfSize.Width() );
+ break;
+
+ case GPOS_AREA:
+ aPos = rOrg.TopLeft();
+ aDrawSize = rOrg.GetSize();
+ break;
+ case GPOS_TILED:
+ {
+ // use GraphicObject::DrawTiled instead of an own loop
+ // (pixel rounding is handled correctly, and a very small bitmap
+ // is duplicated into a bigger one for better performance)
+
+ GraphicObject aObject( *pGraphic );
+
+ if( rOutDev.GetOutDevType() == OUTDEV_PDF &&
+ (aObject.GetType() == GraphicType::Bitmap || aObject.GetType() == GraphicType::Default) )
+ {
+ // For PDF export, every draw
+ // operation for bitmaps takes a noticeable
+ // amount of place (~50 characters). Thus,
+ // optimize between tile bitmap size and
+ // number of drawing operations here.
+ //
+ // A_out
+ // n_chars = k1 * ---------- + k2 * A_bitmap
+ // A_bitmap
+ //
+ // minimum n_chars is obtained for (derive for
+ // A_bitmap, set to 0, take positive
+ // solution):
+ // k1
+ // A_bitmap = Sqrt( ---- A_out )
+ // k2
+ //
+ // where k1 is the number of chars per draw
+ // operation, and k2 is the number of chars
+ // per bitmap pixel. This is approximately 50
+ // and 7 for current PDF writer, respectively.
+
+ const double k1( 50 );
+ const double k2( 7 );
+ const Size aSize( rOrg.GetSize() );
+ const double Abitmap( k1/k2 * aSize.Width()*aSize.Height() );
+
+ aObject.DrawTiled( rOutDev, rOrg, aGrfSize, Size(0,0),
+ ::std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap)) + .5 ) ) );
+ }
+ else
+ {
+ aObject.DrawTiled( rOutDev, rOrg, aGrfSize, Size(0,0) );
+ }
+
+ bDraw = false;
+ }
+ break;
+
+ case GPOS_NONE:
+ bDraw = false;
+ break;
+
+ default: OSL_ENSURE( false, "new Graphic position?" );
+ }
+ tools::Rectangle aGrf( aPos,aDrawSize );
+ if ( bDraw && aGrf.Overlaps( rOut ) )
+ {
+ lcl_DrawGraphic( *pGraphic, rOutDev, aGrf, rOut );
+ }
+}
+
+// The frame is drawn inwards
+
+void ScPrintFunc::DrawBorder( tools::Long nScrX, tools::Long nScrY, tools::Long nScrW, tools::Long nScrH,
+ const SvxBoxItem* pBorderData, const SvxBrushItem* pBackground,
+ const SvxShadowItem* pShadow )
+{
+ //! direct output from SvxBoxItem !!!
+
+ if (pBorderData)
+ if ( !pBorderData->GetTop() && !pBorderData->GetBottom() && !pBorderData->GetLeft() &&
+ !pBorderData->GetRight() )
+ pBorderData = nullptr;
+
+ if (!pBorderData && !pBackground && !pShadow)
+ return; // nothing to do
+
+ tools::Long nLeft = 0;
+ tools::Long nRight = 0;
+ tools::Long nTop = 0;
+ tools::Long nBottom = 0;
+
+ // aFrameRect - outside around frame, without shadow
+ if ( pShadow && pShadow->GetLocation() != SvxShadowLocation::NONE )
+ {
+ nLeft += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT) * nScaleX );
+ nRight += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT) * nScaleX );
+ nTop += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::TOP) * nScaleY );
+ nBottom += static_cast<tools::Long>( pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM) * nScaleY );
+ }
+ tools::Rectangle aFrameRect( Point(nScrX+nLeft, nScrY+nTop),
+ Size(nScrW-nLeft-nRight, nScrH-nTop-nBottom) );
+
+ // center of frame, to paint lines through OutputData
+ if (pBorderData)
+ {
+ nLeft += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetLeft()) * nScaleX / 2 );
+ nRight += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetRight()) * nScaleX / 2 );
+ nTop += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetTop()) * nScaleY / 2 );
+ nBottom += static_cast<tools::Long>( lcl_LineTotal(pBorderData->GetBottom()) * nScaleY / 2 );
+ }
+ tools::Long nEffHeight = nScrH - nTop - nBottom;
+ tools::Long nEffWidth = nScrW - nLeft - nRight;
+ if (nEffHeight<=0 || nEffWidth<=0)
+ return; // empty
+
+ if ( pBackground )
+ {
+ if (pBackground->GetGraphicPos() != GPOS_NONE)
+ {
+ OutputDevice* pRefDev;
+ if ( bIsRender )
+ pRefDev = pDev; // don't use printer for PDF
+ else
+ pRefDev = rDoc.GetPrinter(); // use printer also for preview
+ OUString referer;
+ if (pDocShell->HasName()) {
+ referer = pDocShell->GetMedium()->GetName();
+ }
+ lcl_DrawGraphic(*pBackground, *pDev, pRefDev, aFrameRect, aFrameRect, referer);
+ }
+ else
+ {
+ pDev->SetFillColor(pBackground->GetColor());
+ pDev->SetLineColor();
+ pDev->DrawRect(aFrameRect);
+ }
+ }
+
+ if ( pShadow && pShadow->GetLocation() != SvxShadowLocation::NONE )
+ {
+ pDev->SetFillColor(pShadow->GetColor());
+ pDev->SetLineColor();
+ tools::Long nShadowX = static_cast<tools::Long>( pShadow->GetWidth() * nScaleX );
+ tools::Long nShadowY = static_cast<tools::Long>( pShadow->GetWidth() * nScaleY );
+ switch (pShadow->GetLocation())
+ {
+ case SvxShadowLocation::TopLeft:
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()-nShadowX, aFrameRect.Top()-nShadowY,
+ aFrameRect.Right()-nShadowX, aFrameRect.Top() ) );
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()-nShadowX, aFrameRect.Top()-nShadowY,
+ aFrameRect.Left(), aFrameRect.Bottom()-nShadowY ) );
+ break;
+ case SvxShadowLocation::TopRight:
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()+nShadowX, aFrameRect.Top()-nShadowY,
+ aFrameRect.Right()+nShadowX, aFrameRect.Top() ) );
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Right(), aFrameRect.Top()-nShadowY,
+ aFrameRect.Right()+nShadowX, aFrameRect.Bottom()-nShadowY ) );
+ break;
+ case SvxShadowLocation::BottomLeft:
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()-nShadowX, aFrameRect.Bottom(),
+ aFrameRect.Right()-nShadowX, aFrameRect.Bottom()+nShadowY ) );
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()-nShadowX, aFrameRect.Top()+nShadowY,
+ aFrameRect.Left(), aFrameRect.Bottom()+nShadowY ) );
+ break;
+ case SvxShadowLocation::BottomRight:
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Left()+nShadowX, aFrameRect.Bottom(),
+ aFrameRect.Right()+nShadowX, aFrameRect.Bottom()+nShadowY ) );
+ pDev->DrawRect( tools::Rectangle(
+ aFrameRect.Right(), aFrameRect.Top()+nShadowY,
+ aFrameRect.Right()+nShadowX, aFrameRect.Bottom()+nShadowY ) );
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+
+ if (!pBorderData)
+ return;
+
+ ScDocumentUniquePtr pBorderDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pBorderDoc->InitUndo( rDoc, 0,0, true,true );
+ pBorderDoc->ApplyAttr( 0,0,0, *pBorderData );
+
+ ScTableInfo aTabInfo;
+ pBorderDoc->FillInfo( aTabInfo, 0,0, 0,0, 0,
+ nScaleX, nScaleY, false, false );
+ OSL_ENSURE(aTabInfo.mnArrCount,"nArrCount == 0");
+
+ aTabInfo.mpRowInfo[1].nHeight = static_cast<sal_uInt16>(nEffHeight);
+ aTabInfo.mpRowInfo[0].basicCellInfo(0).nWidth =
+ aTabInfo.mpRowInfo[1].basicCellInfo(0).nWidth = static_cast<sal_uInt16>(nEffWidth);
+
+ ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, pBorderDoc.get(), 0,
+ nScrX+nLeft, nScrY+nTop, 0,0, 0,0, nScaleX, nScaleY );
+ aOutputData.SetUseStyleColor( bUseStyleColor );
+
+ aOutputData.DrawFrame(*pDev);
+}
+
+void ScPrintFunc::PrintColHdr( SCCOL nX1, SCCOL nX2, tools::Long nScrX, tools::Long nScrY )
+{
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+ SCCOL nCol;
+
+ tools::Long nHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
+ tools::Long nEndY = nScrY + nHeight - nOneY;
+
+ tools::Long nPosX = nScrX;
+ if ( bLayoutRTL )
+ {
+ for (nCol=nX1; nCol<=nX2; nCol++)
+ nPosX += static_cast<tools::Long>( rDoc.GetColWidth( nCol, nPrintTab ) * nScaleX );
+ }
+ else
+ nPosX -= nOneX;
+ tools::Long nPosY = nScrY - nOneY;
+ OUString aText;
+
+ for (nCol=nX1; nCol<=nX2; nCol++)
+ {
+ sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
+ if (nDocW)
+ {
+ tools::Long nWidth = static_cast<tools::Long>(nDocW * nScaleX);
+ tools::Long nEndX = nPosX + nWidth * nLayoutSign;
+
+ pDev->DrawRect( tools::Rectangle( nPosX,nPosY,nEndX,nEndY ) );
+
+ aText = ::ScColToAlpha( nCol);
+ tools::Long nTextWidth = pDev->GetTextWidth(aText);
+ tools::Long nTextHeight = pDev->GetTextHeight();
+ tools::Long nAddX = ( nWidth - nTextWidth ) / 2;
+ tools::Long nAddY = ( nHeight - nTextHeight ) / 2;
+ tools::Long nTextPosX = nPosX+nAddX;
+ if ( bLayoutRTL )
+ nTextPosX -= nWidth;
+ pDev->DrawText( Point( nTextPosX,nPosY+nAddY ), aText );
+
+ nPosX = nEndX;
+ }
+ }
+}
+
+void ScPrintFunc::PrintRowHdr( SCROW nY1, SCROW nY2, tools::Long nScrX, tools::Long nScrY )
+{
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
+
+ tools::Long nWidth = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
+ tools::Long nEndX = nScrX + nWidth;
+ tools::Long nPosX = nScrX;
+ if ( !bLayoutRTL )
+ {
+ nEndX -= nOneX;
+ nPosX -= nOneX;
+ }
+ tools::Long nPosY = nScrY - nOneY;
+ OUString aText;
+
+ for (SCROW nRow=nY1; nRow<=nY2; nRow++)
+ {
+ sal_uInt16 nDocH = rDoc.GetRowHeight( nRow, nPrintTab );
+ if (nDocH)
+ {
+ tools::Long nHeight = static_cast<tools::Long>(nDocH * nScaleY);
+ tools::Long nEndY = nPosY + nHeight;
+
+ pDev->DrawRect( tools::Rectangle( nPosX,nPosY,nEndX,nEndY ) );
+
+ aText = OUString::number( nRow+1 );
+ tools::Long nTextWidth = pDev->GetTextWidth(aText);
+ tools::Long nTextHeight = pDev->GetTextHeight();
+ tools::Long nAddX = ( nWidth - nTextWidth ) / 2;
+ tools::Long nAddY = ( nHeight - nTextHeight ) / 2;
+ pDev->DrawText( Point( nPosX+nAddX,nPosY+nAddY ), aText );
+
+ nPosY = nEndY;
+ }
+ }
+}
+
+void ScPrintFunc::LocateColHdr( SCCOL nX1, SCCOL nX2, tools::Long nScrX, tools::Long nScrY,
+ bool bRepCol, ScPreviewLocationData& rLocationData )
+{
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+
+ tools::Long nHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
+ tools::Long nEndY = nScrY + nHeight - nOneY;
+
+ tools::Long nPosX = nScrX - nOneX;
+ for (SCCOL nCol=nX1; nCol<=nX2; nCol++)
+ {
+ sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
+ if (nDocW)
+ nPosX += static_cast<tools::Long>(nDocW * nScaleX);
+ }
+ tools::Rectangle aCellRect( nScrX, nScrY, nPosX, nEndY );
+ rLocationData.AddColHeaders( aCellRect, nX1, nX2, bRepCol );
+}
+
+void ScPrintFunc::LocateRowHdr( SCROW nY1, SCROW nY2, tools::Long nScrX, tools::Long nScrY,
+ bool bRepRow, ScPreviewLocationData& rLocationData )
+{
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
+
+ tools::Long nWidth = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
+ tools::Long nEndX = nScrX + nWidth;
+ if ( !bLayoutRTL )
+ nEndX -= nOneX;
+
+ tools::Long nPosY = nScrY - nOneY;
+ nPosY += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab, nScaleY);
+ tools::Rectangle aCellRect( nScrX, nScrY, nEndX, nPosY );
+ rLocationData.AddRowHeaders( aCellRect, nY1, nY2, bRepRow );
+}
+
+void ScPrintFunc::LocateArea( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ tools::Long nScrX, tools::Long nScrY, bool bRepCol, bool bRepRow,
+ ScPreviewLocationData& rLocationData )
+{
+ // get MapMode for drawing objects (same MapMode as in ScOutputData::PrintDrawingLayer)
+
+ Point aLogPos = OutputDevice::LogicToLogic(Point(nScrX,nScrY), aOffsetMode, aLogicMode);
+ tools::Long nLogStX = aLogPos.X();
+ tools::Long nLogStY = aLogPos.Y();
+
+ SCCOL nCol;
+ Point aTwipOffset;
+ for (nCol=0; nCol<nX1; nCol++)
+ aTwipOffset.AdjustX( -(rDoc.GetColWidth( nCol, nPrintTab )) );
+ aTwipOffset.AdjustY( -sal_Int32(rDoc.GetRowHeight( 0, nY1-1, nPrintTab )) );
+
+ Point aMMOffset(o3tl::convert(aTwipOffset, o3tl::Length::twip, o3tl::Length::mm100));
+ aMMOffset += Point( nLogStX, nLogStY );
+ MapMode aDrawMapMode( MapUnit::Map100thMM, aMMOffset, aLogicMode.GetScaleX(), aLogicMode.GetScaleY() );
+
+ // get pixel rectangle
+
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+
+ tools::Long nPosX = nScrX - nOneX;
+ for (nCol=nX1; nCol<=nX2; nCol++)
+ {
+ sal_uInt16 nDocW = rDoc.GetColWidth( nCol, nPrintTab );
+ if (nDocW)
+ nPosX += static_cast<tools::Long>(nDocW * nScaleX);
+ }
+
+ tools::Long nPosY = nScrY - nOneY;
+ nPosY += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab, nScaleY);
+ tools::Rectangle aCellRect( nScrX, nScrY, nPosX, nPosY );
+ rLocationData.AddCellRange( aCellRect, ScRange( nX1,nY1,nPrintTab, nX2,nY2,nPrintTab ),
+ bRepCol, bRepRow, aDrawMapMode );
+}
+
+void ScPrintFunc::PrintArea( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ tools::Long nScrX, tools::Long nScrY,
+ bool bShLeft, bool bShTop, bool bShRight, bool bShBottom )
+{
+ // #i47547# nothing to do if the end of the print area is before the end of
+ // the repeat columns/rows (don't use negative size for ScOutputData)
+ if ( nX2 < nX1 || nY2 < nY1 )
+ return;
+
+ //! hand over Flag at FillInfo !!!!!
+ ScRange aERange;
+ bool bEmbed = rDoc.IsEmbedded();
+ if (bEmbed)
+ {
+ rDoc.GetEmbedded(aERange);
+ rDoc.ResetEmbedded();
+ }
+
+ Point aPos = OutputDevice::LogicToLogic(Point(nScrX,nScrY), aOffsetMode, aLogicMode);
+ tools::Long nLogStX = aPos.X();
+ tools::Long nLogStY = aPos.Y();
+
+ // Assemble data
+
+ ScTableInfo aTabInfo;
+ rDoc.FillInfo( aTabInfo, nX1, nY1, nX2, nY2, nPrintTab,
+ nScaleX, nScaleY, true, aTableParam.bFormulas );
+ lcl_HidePrint( aTabInfo, nX1, nX2 );
+
+ if (bEmbed)
+ rDoc.SetEmbedded(aERange);
+
+ ScOutputData aOutputData( pDev, OUTTYPE_PRINTER, aTabInfo, &rDoc, nPrintTab,
+ nScrX, nScrY, nX1, nY1, nX2, nY2, nScaleX, nScaleY );
+
+ aOutputData.SetDrawView( pDrawView );
+
+ // test if all paint parts are hidden, then a paint is not necessary at all
+ const Point aMMOffset(aOutputData.PrePrintDrawingLayer(nLogStX, nLogStY));
+ const bool bHideAllDrawingLayer( pDrawView && pDrawView->getHideOle() && pDrawView->getHideChart()
+ && pDrawView->getHideDraw() && pDrawView->getHideFormControl() );
+
+ if(!bHideAllDrawingLayer)
+ {
+ pDev->SetMapMode(aLogicMode);
+ // don's set Clipping here (Mapmode is being moved)
+
+ // #i72502#
+ aOutputData.PrintDrawingLayer(SC_LAYER_BACK, aMMOffset);
+ }
+
+ pDev->SetMapMode(aOffsetMode);
+
+ aOutputData.SetShowFormulas( aTableParam.bFormulas );
+ aOutputData.SetShowNullValues( aTableParam.bNullVals );
+ aOutputData.SetUseStyleColor( bUseStyleColor );
+
+ Color aGridColor( COL_BLACK );
+ if ( bUseStyleColor )
+ aGridColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
+ aOutputData.SetGridColor( aGridColor );
+
+ if ( !pPrinter )
+ {
+ OutputDevice* pRefDev = rDoc.GetPrinter(); // use the printer also for Preview
+ Fraction aPrintFrac( nZoom, 100 ); // without nManualZoom
+ // MapMode, as it would arrive at the printer:
+ pRefDev->SetMapMode( MapMode( MapUnit::Map100thMM, Point(), aPrintFrac, aPrintFrac ) );
+
+ // when rendering (PDF), don't use printer as ref device, but printer's MapMode
+ // has to be set anyway, as charts still use it (#106409#)
+ if ( !bIsRender )
+ aOutputData.SetRefDevice( pRefDev );
+ }
+
+ if( aTableParam.bCellContent )
+ aOutputData.DrawBackground(*pDev);
+
+ pDev->SetClipRegion(vcl::Region(tools::Rectangle(
+ aPos, Size(aOutputData.GetScrW(), aOutputData.GetScrH()))));
+ pDev->SetClipRegion();
+
+ if( aTableParam.bCellContent )
+ {
+ aOutputData.DrawExtraShadow( bShLeft, bShTop, bShRight, bShBottom );
+ aOutputData.DrawFrame(*pDev);
+ aOutputData.DrawSparklines(*pDev);
+ aOutputData.DrawStrings();
+ aOutputData.DrawEdit(false);
+ }
+
+ if (aTableParam.bGrid)
+ aOutputData.DrawGrid(*pDev, true, false); // no page breaks
+
+ aOutputData.AddPDFNotes(); // has no effect if not rendering PDF with notes enabled
+
+ // test if all paint parts are hidden, then a paint is not necessary at all
+ if(!bHideAllDrawingLayer)
+ {
+ // #i72502#
+ aOutputData.PrintDrawingLayer(SC_LAYER_FRONT, aMMOffset);
+ }
+
+ // #i72502#
+ aOutputData.PrintDrawingLayer(SC_LAYER_INTERN, aMMOffset);
+ aOutputData.PostPrintDrawingLayer(aMMOffset); // #i74768#
+}
+
+bool ScPrintFunc::IsMirror( tools::Long nPageNo ) // Mirror margins?
+{
+ return nPageUsage == SvxPageUsage::Mirror && (nPageNo & 1);
+}
+
+bool ScPrintFunc::IsLeft( tools::Long nPageNo ) // left foot notes?
+{
+ bool bLeft;
+ if (nPageUsage == SvxPageUsage::Left)
+ bLeft = true;
+ else if (nPageUsage == SvxPageUsage::Right)
+ bLeft = false;
+ else
+ bLeft = (nPageNo & 1) != 0;
+ return bLeft;
+}
+
+void ScPrintFunc::MakeTableString()
+{
+ OUString aTmp;
+ rDoc.GetName(nPrintTab, aTmp);
+ aFieldData.aTabName = aTmp;
+}
+
+void ScPrintFunc::MakeEditEngine()
+{
+ if (!pEditEngine)
+ {
+ // can't use document's edit engine pool here,
+ // because pool must have twips as default metric
+ pEditEngine.reset( new ScHeaderEditEngine( EditEngine::CreatePool().get() ) );
+
+ pEditEngine->EnableUndo(false);
+ //fdo#45869 we want text to be positioned as it would be for the
+ //high dpi printed output, not as would be ideal for the 96dpi preview
+ //window itself
+ pEditEngine->SetRefDevice(pPrinter ? pPrinter : rDoc.GetRefDevice());
+ pEditEngine->SetWordDelimiters(
+ ScEditUtil::ModifyDelimiters( pEditEngine->GetWordDelimiters() ) );
+ pEditEngine->SetControlWord( pEditEngine->GetControlWord() & ~EEControlBits::RTFSTYLESHEETS );
+ rDoc.ApplyAsianEditSettings( *pEditEngine );
+ pEditEngine->EnableAutoColor( bUseStyleColor );
+
+ // Default-Set for alignment
+ pEditDefaults.reset( new SfxItemSet( pEditEngine->GetEmptyItemSet() ) );
+
+ const ScPatternAttr& rPattern = rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN);
+ rPattern.FillEditItemSet( pEditDefaults.get() );
+ // FillEditItemSet adjusts font height to 1/100th mm,
+ // but for header/footer twips is needed, as in the PatternAttr:
+ pEditDefaults->Put( rPattern.GetItem(ATTR_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT) );
+ pEditDefaults->Put( rPattern.GetItem(ATTR_CJK_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CJK) );
+ pEditDefaults->Put( rPattern.GetItem(ATTR_CTL_FONT_HEIGHT).CloneSetWhich(EE_CHAR_FONTHEIGHT_CTL) );
+ // don't use font color, because background color is not used
+ //! there's no way to set the background for note pages
+ pEditDefaults->ClearItem( EE_CHAR_COLOR );
+ if (ScGlobal::IsSystemRTL())
+ pEditDefaults->Put( SvxFrameDirectionItem( SvxFrameDirection::Horizontal_RL_TB, EE_PARA_WRITINGDIR ) );
+ }
+
+ pEditEngine->SetData( aFieldData ); // Set page count etc.
+}
+
+// nStartY = logic
+void ScPrintFunc::PrintHF( tools::Long nPageNo, bool bHeader, tools::Long nStartY,
+ bool bDoPrint, ScPreviewLocationData* pLocationData )
+{
+ const ScPrintHFParam& rParam = bHeader ? aHdr : aFtr;
+
+ pDev->SetMapMode( aTwipMode ); // Head-/Footlines in Twips
+
+ bool bFirst = 0 == nPageNo && !rParam.bSharedFirst;
+ bool bLeft = IsLeft(nPageNo) && !rParam.bShared;
+ const ScPageHFItem* pHFItem = bFirst ? rParam.pFirst : (bLeft ? rParam.pLeft : rParam.pRight);
+
+ tools::Long nLineStartX = aPageRect.Left() + rParam.nLeft;
+ tools::Long nLineEndX = aPageRect.Right() - rParam.nRight;
+ tools::Long nLineWidth = nLineEndX - nLineStartX + 1;
+
+ // Edit-Engine
+
+ Point aStart( nLineStartX, nStartY );
+ Size aPaperSize( nLineWidth, rParam.nHeight-rParam.nDistance );
+ if ( rParam.pBorder )
+ {
+ tools::Long nLeft = lcl_LineTotal( rParam.pBorder->GetLeft() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::LEFT);
+ tools::Long nTop = lcl_LineTotal( rParam.pBorder->GetTop() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::TOP);
+ aStart.AdjustX(nLeft );
+ aStart.AdjustY(nTop );
+ aPaperSize.AdjustWidth( -(nLeft + lcl_LineTotal( rParam.pBorder->GetRight() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::RIGHT)) );
+ aPaperSize.AdjustHeight( -(nTop + lcl_LineTotal( rParam.pBorder->GetBottom() ) + rParam.pBorder->GetDistance(SvxBoxItemLine::BOTTOM)) );
+ }
+
+ if ( rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE )
+ {
+ tools::Long nLeft = rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::LEFT);
+ tools::Long nTop = rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::TOP);
+ aStart.AdjustX(nLeft );
+ aStart.AdjustY(nTop );
+ aPaperSize.AdjustWidth( -(nLeft + rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::RIGHT)) );
+ aPaperSize.AdjustHeight( -(nTop + rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM)) );
+ }
+
+ aFieldData.nPageNo = nPageNo+aTableParam.nFirstPageNo;
+ MakeEditEngine();
+
+ pEditEngine->SetPaperSize(aPaperSize);
+
+ // Frame / Background
+
+ Point aBorderStart( nLineStartX, nStartY );
+ Size aBorderSize( nLineWidth, rParam.nHeight-rParam.nDistance );
+ if ( rParam.bDynamic )
+ {
+ // adjust here again, for even/odd head-/footlines
+ // and probably other breaks by variable (page number etc.)
+
+ tools::Long nMaxHeight = 0;
+ nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetLeftArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetCenterArea() ) );
+ nMaxHeight = std::max( nMaxHeight, TextHeight( pHFItem->GetRightArea() ) );
+ if (rParam.pBorder)
+ nMaxHeight += lcl_LineTotal( rParam.pBorder->GetTop() ) +
+ lcl_LineTotal( rParam.pBorder->GetBottom() ) +
+ rParam.pBorder->GetDistance(SvxBoxItemLine::TOP) +
+ rParam.pBorder->GetDistance(SvxBoxItemLine::BOTTOM);
+ if (rParam.pShadow && rParam.pShadow->GetLocation() != SvxShadowLocation::NONE)
+ nMaxHeight += rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::TOP) +
+ rParam.pShadow->CalcShadowSpace(SvxShadowItemSide::BOTTOM);
+
+ if (nMaxHeight < rParam.nManHeight-rParam.nDistance)
+ nMaxHeight = rParam.nManHeight-rParam.nDistance; // configured Minimum
+
+ aBorderSize.setHeight( nMaxHeight );
+ }
+
+ if ( bDoPrint )
+ {
+ double nOldScaleX = nScaleX;
+ double nOldScaleY = nScaleY;
+ nScaleX = nScaleY = 1.0; // output directly in Twips
+ DrawBorder( aBorderStart.X(), aBorderStart.Y(), aBorderSize.Width(), aBorderSize.Height(),
+ rParam.pBorder, rParam.pBack, rParam.pShadow );
+ nScaleX = nOldScaleX;
+ nScaleY = nOldScaleY;
+
+ // Clipping for Text
+
+ pDev->SetClipRegion(vcl::Region(tools::Rectangle(aStart, aPaperSize)));
+
+ // left
+
+ const EditTextObject* pObject = pHFItem->GetLeftArea();
+ if (pObject)
+ {
+ pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
+ pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
+ Point aDraw = aStart;
+ tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
+ if (nDif > 0)
+ aDraw.AdjustY(nDif / 2 );
+ pEditEngine->Draw(*pDev, aDraw);
+ }
+
+ // center
+
+ pObject = pHFItem->GetCenterArea();
+ if (pObject)
+ {
+ pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
+ pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
+ Point aDraw = aStart;
+ tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
+ if (nDif > 0)
+ aDraw.AdjustY(nDif / 2 );
+ pEditEngine->Draw(*pDev, aDraw);
+ }
+
+ // right
+
+ pObject = pHFItem->GetRightArea();
+ if (pObject)
+ {
+ pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
+ pEditEngine->SetTextNewDefaults( *pObject, *pEditDefaults, false );
+ Point aDraw = aStart;
+ tools::Long nDif = aPaperSize.Height() - static_cast<tools::Long>(pEditEngine->GetTextHeight());
+ if (nDif > 0)
+ aDraw.AdjustY(nDif / 2 );
+ pEditEngine->Draw(*pDev, aDraw);
+ }
+
+ pDev->SetClipRegion();
+ }
+
+ if ( pLocationData )
+ {
+ tools::Rectangle aHeaderRect( aBorderStart, aBorderSize );
+ pLocationData->AddHeaderFooter( aHeaderRect, bHeader, bLeft );
+ }
+}
+
+tools::Long ScPrintFunc::DoNotes( tools::Long nNoteStart, bool bDoPrint, ScPreviewLocationData* pLocationData )
+{
+ if (bDoPrint)
+ pDev->SetMapMode(aTwipMode);
+
+ MakeEditEngine();
+ pEditDefaults->Put( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
+ pEditEngine->SetDefaults( *pEditDefaults );
+
+ vcl::Font aMarkFont;
+ ScAutoFontColorMode eColorMode = bUseStyleColor ? SC_AUTOCOL_DISPLAY : SC_AUTOCOL_PRINT;
+ rDoc.GetPool()->GetDefaultItem(ATTR_PATTERN).GetFont( aMarkFont, eColorMode );
+ pDev->SetFont( aMarkFont );
+ tools::Long nMarkLen = pDev->GetTextWidth("GW99999:");
+ // without Space-Char, because it rarely arrives there
+
+ Size aDataSize = aPageRect.GetSize();
+ if ( nMarkLen > aDataSize.Width() / 2 ) // everything much too small?
+ nMarkLen = aDataSize.Width() / 2; // split the page appropriately
+ aDataSize.AdjustWidth( -nMarkLen );
+
+ pEditEngine->SetPaperSize( aDataSize );
+ tools::Long nPosX = aPageRect.Left() + nMarkLen;
+ tools::Long nPosY = aPageRect.Top();
+
+ tools::Long nCount = 0;
+ tools::Long nSize = aNotePosList.size();
+ bool bOk;
+ do
+ {
+ bOk = false;
+ if ( nNoteStart + nCount < nSize)
+ {
+ ScAddress &rPos = aNotePosList[ nNoteStart + nCount ];
+
+ if( const ScPostIt* pNote = rDoc.GetNote( rPos ) )
+ {
+ if(const EditTextObject *pEditText = pNote->GetEditTextObject())
+ pEditEngine->SetTextCurrentDefaults(*pEditText);
+ tools::Long nTextHeight = pEditEngine->GetTextHeight();
+ if ( nPosY + nTextHeight < aPageRect.Bottom() )
+ {
+ if (bDoPrint)
+ {
+ pEditEngine->Draw(*pDev, Point(nPosX, nPosY));
+
+ OUString aMarkStr(rPos.Format(ScRefFlags::VALID, &rDoc, rDoc.GetAddressConvention()) + ":");
+
+ // cell position also via EditEngine, for correct positioning
+ pEditEngine->SetTextCurrentDefaults(aMarkStr);
+ pEditEngine->Draw(*pDev, Point(aPageRect.Left(), nPosY));
+ }
+
+ if ( pLocationData )
+ {
+ tools::Rectangle aTextRect( Point( nPosX, nPosY ), Size( aDataSize.Width(), nTextHeight ) );
+ pLocationData->AddNoteText( aTextRect, rPos );
+ tools::Rectangle aMarkRect( Point( aPageRect.Left(), nPosY ), Size( nMarkLen, nTextHeight ) );
+ pLocationData->AddNoteMark( aMarkRect, rPos );
+ }
+
+ nPosY += nTextHeight;
+ nPosY += 200; // Distance
+ ++nCount;
+ bOk = true;
+ }
+ }
+ }
+ }
+ while (bOk);
+
+ return nCount;
+}
+
+tools::Long ScPrintFunc::PrintNotes( tools::Long nPageNo, tools::Long nNoteStart, bool bDoPrint, ScPreviewLocationData* pLocationData )
+{
+ if ( nNoteStart >= static_cast<tools::Long>(aNotePosList.size()) || !aTableParam.bNotes )
+ return 0;
+
+ if ( bDoPrint && bClearWin )
+ {
+ //! aggregate PrintPage !!!
+
+ Color aBackgroundColor( COL_WHITE );
+ if ( bUseStyleColor )
+ aBackgroundColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+
+ pDev->SetMapMode(aOffsetMode);
+ pDev->SetLineColor();
+ pDev->SetFillColor(aBackgroundColor);
+ pDev->DrawRect(tools::Rectangle(Point(),
+ Size(static_cast<tools::Long>(aPageSize.Width() * nScaleX * 100 / nZoom),
+ static_cast<tools::Long>(aPageSize.Height() * nScaleY * 100 / nZoom))));
+ }
+
+ // adjust aPageRect for left/right page
+
+ tools::Rectangle aTempRect( Point(), aPageSize );
+ if (IsMirror(nPageNo))
+ {
+ aPageRect.SetLeft( ( aTempRect.Left() + nRightMargin ) * 100 / nZoom );
+ aPageRect.SetRight( ( aTempRect.Right() - nLeftMargin ) * 100 / nZoom );
+ }
+ else
+ {
+ aPageRect.SetLeft( ( aTempRect.Left() + nLeftMargin ) * 100 / nZoom );
+ aPageRect.SetRight( ( aTempRect.Right() - nRightMargin ) * 100 / nZoom );
+ }
+
+ if ( pPrinter && bDoPrint )
+ {
+ OSL_FAIL( "StartPage does not exist anymore" );
+ }
+
+ if ( bDoPrint || pLocationData )
+ {
+ // Head and foot lines
+
+ if (aHdr.bEnable)
+ {
+ tools::Long nHeaderY = aPageRect.Top()-aHdr.nHeight;
+ PrintHF( nPageNo, true, nHeaderY, bDoPrint, pLocationData );
+ }
+ if (aFtr.bEnable)
+ {
+ tools::Long nFooterY = aPageRect.Bottom()+aFtr.nDistance;
+ PrintHF( nPageNo, false, nFooterY, bDoPrint, pLocationData );
+ }
+ }
+
+ tools::Long nCount = DoNotes( nNoteStart, bDoPrint, pLocationData );
+
+ if ( pPrinter && bDoPrint )
+ {
+ OSL_FAIL( "EndPage does not exist anymore" );
+ }
+
+ return nCount;
+}
+
+void ScPrintFunc::PrintPage( tools::Long nPageNo, SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2,
+ bool bDoPrint, ScPreviewLocationData* pLocationData )
+{
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nPrintTab );
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ // nPageNo is the page number within all sheets of one "start page" setting
+
+ if ( bClearWin && bDoPrint )
+ {
+ // must exactly fit to painting the frame in preview.cxx !!!
+
+ Color aBackgroundColor( COL_WHITE );
+ if ( bUseStyleColor )
+ aBackgroundColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+
+ pDev->SetMapMode(aOffsetMode);
+ pDev->SetLineColor();
+ pDev->SetFillColor(aBackgroundColor);
+ pDev->DrawRect(tools::Rectangle(Point(),
+ Size(static_cast<tools::Long>(aPageSize.Width() * nScaleX * 100 / nZoom),
+ static_cast<tools::Long>(aPageSize.Height() * nScaleY * 100 / nZoom))));
+ }
+
+ // adjust aPageRect for left/right page
+
+ tools::Rectangle aTempRect( Point(), aPageSize );
+ if (IsMirror(nPageNo))
+ {
+ aPageRect.SetLeft( ( aTempRect.Left() + nRightMargin ) * 100 / nZoom );
+ aPageRect.SetRight( ( aTempRect.Right() - nLeftMargin ) * 100 / nZoom );
+ }
+ else
+ {
+ aPageRect.SetLeft( ( aTempRect.Left() + nLeftMargin ) * 100 / nZoom );
+ aPageRect.SetRight( ( aTempRect.Right() - nRightMargin ) * 100 / nZoom );
+ }
+
+ if ( aAreaParam.bRepeatCol )
+ if ( nX1 > nRepeatStartCol && nX1 <= nRepeatEndCol )
+ nX1 = nRepeatEndCol + 1;
+ bool bDoRepCol = (aAreaParam.bRepeatCol && nX1 > nRepeatEndCol);
+ if ( aAreaParam.bRepeatRow )
+ if ( nY1 > nRepeatStartRow && nY1 <= nRepeatEndRow )
+ nY1 = nRepeatEndRow + 1;
+ bool bDoRepRow = (aAreaParam.bRepeatRow && nY1 > nRepeatEndRow);
+
+ // use new object hide flags in SdrPaintView
+ if(pDrawView)
+ {
+ pDrawView->setHideOle(!aTableParam.bObjects);
+ pDrawView->setHideChart(!aTableParam.bCharts);
+ pDrawView->setHideDraw(!aTableParam.bDrawings);
+ pDrawView->setHideFormControl(!aTableParam.bDrawings);
+ }
+
+ if ( pPrinter && bDoPrint )
+ {
+ OSL_FAIL( "StartPage does not exist anymore" );
+ }
+
+ // head and foot lines (without centering)
+
+ if (aHdr.bEnable)
+ {
+ tools::Long nHeaderY = aPageRect.Top()-aHdr.nHeight;
+ PrintHF( nPageNo, true, nHeaderY, bDoPrint, pLocationData );
+ }
+ if (aFtr.bEnable)
+ {
+ tools::Long nFooterY = aPageRect.Bottom()+aFtr.nDistance;
+ PrintHF( nPageNo, false, nFooterY, bDoPrint, pLocationData );
+ }
+
+ // Position ( margins / centering )
+
+ tools::Long nLeftSpace = aPageRect.Left(); // Document-Twips
+ tools::Long nTopSpace = aPageRect.Top();
+ if ( bCenterHor || bLayoutRTL )
+ {
+ tools::Long nDataWidth = 0;
+ SCCOL i;
+ for (i=nX1; i<=nX2; i++)
+ nDataWidth += rDoc.GetColWidth( i,nPrintTab );
+ if (bDoRepCol)
+ for (i=nRepeatStartCol; i<=nRepeatEndCol; i++)
+ nDataWidth += rDoc.GetColWidth( i,nPrintTab );
+ if (aTableParam.bHeaders)
+ nDataWidth += tools::Long(PRINT_HEADER_WIDTH);
+ if (pBorderItem)
+ nDataWidth += pBorderItem->GetDistance(SvxBoxItemLine::LEFT) +
+ pBorderItem->GetDistance(SvxBoxItemLine::RIGHT); //! Line width?
+ if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
+ nDataWidth += pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) +
+ pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT);
+ if ( bCenterHor )
+ {
+ nLeftSpace += ( aPageRect.GetWidth() - nDataWidth ) / 2; // LTR or RTL
+ if (pBorderItem)
+ nLeftSpace -= lcl_LineTotal(pBorderItem->GetLeft());
+ }
+ else if ( bLayoutRTL )
+ nLeftSpace += aPageRect.GetWidth() - nDataWidth; // align to the right edge of the page
+ }
+ if ( bCenterVer )
+ {
+ tools::Long nDataHeight = rDoc.GetRowHeight( nY1, nY2, nPrintTab);
+ if (bDoRepRow)
+ nDataHeight += rDoc.GetRowHeight( nRepeatStartRow,
+ nRepeatEndRow, nPrintTab);
+ if (aTableParam.bHeaders)
+ nDataHeight += tools::Long(PRINT_HEADER_HEIGHT);
+ if (pBorderItem)
+ nDataHeight += pBorderItem->GetDistance(SvxBoxItemLine::TOP) +
+ pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM); //! Line width?
+ if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
+ nDataHeight += pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) +
+ pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM);
+ nTopSpace += ( aPageRect.GetHeight() - nDataHeight ) / 2;
+ if (pBorderItem)
+ nTopSpace -= lcl_LineTotal(pBorderItem->GetTop());
+ }
+
+ // calculate sizes of the elements for partitioning
+ // (header, repeat, data)
+
+ tools::Long nHeaderWidth = 0;
+ tools::Long nHeaderHeight = 0;
+ tools::Long nRepeatWidth = 0;
+ tools::Long nRepeatHeight = 0;
+ tools::Long nContentWidth = 0; // scaled - not the same as nDataWidth above
+ tools::Long nContentHeight = 0;
+ if (aTableParam.bHeaders)
+ {
+ nHeaderWidth = static_cast<tools::Long>(PRINT_HEADER_WIDTH * nScaleX);
+ nHeaderHeight = static_cast<tools::Long>(PRINT_HEADER_HEIGHT * nScaleY);
+ }
+ if (bDoRepCol)
+ for (SCCOL i=nRepeatStartCol; i<=nRepeatEndCol; i++)
+ nRepeatWidth += static_cast<tools::Long>(rDoc.GetColWidth(i,nPrintTab) * nScaleX);
+ if (bDoRepRow)
+ nRepeatHeight += rDoc.GetScaledRowHeight( nRepeatStartRow,
+ nRepeatEndRow, nPrintTab, nScaleY);
+ for (SCCOL i=nX1; i<=nX2; i++)
+ nContentWidth += static_cast<tools::Long>(rDoc.GetColWidth(i,nPrintTab) * nScaleX);
+ nContentHeight += rDoc.GetScaledRowHeight( nY1, nY2, nPrintTab,
+ nScaleY);
+
+ // partition the page
+
+ tools::Long nStartX = static_cast<tools::Long>( nLeftSpace * nScaleX );
+ tools::Long nStartY = static_cast<tools::Long>( nTopSpace * nScaleY );
+ tools::Long nInnerStartX = nStartX;
+ tools::Long nInnerStartY = nStartY;
+ if (pBorderItem)
+ {
+ nInnerStartX += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetLeft()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::LEFT) ) * nScaleX );
+ nInnerStartY += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetTop()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::TOP) ) * nScaleY );
+ }
+ if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
+ {
+ nInnerStartX += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) * nScaleX );
+ nInnerStartY += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) * nScaleY );
+ }
+
+ if ( bLayoutRTL )
+ {
+ // arrange elements starting from the right edge
+ nInnerStartX += nHeaderWidth + nRepeatWidth + nContentWidth;
+
+ // make rounding easier so the elements are really next to each other in preview
+ Size aOffsetOnePixel = pDev->PixelToLogic( Size(1,1), aOffsetMode );
+ tools::Long nOffsetOneX = aOffsetOnePixel.Width();
+ nInnerStartX += nOffsetOneX / 2;
+ }
+
+ tools::Long nFrameStartX = nInnerStartX;
+ tools::Long nFrameStartY = nInnerStartY;
+
+ tools::Long nRepStartX = nInnerStartX + nHeaderWidth * nLayoutSign; // widths/heights are 0 if not used
+ tools::Long nRepStartY = nInnerStartY + nHeaderHeight;
+ tools::Long nDataX = nRepStartX + nRepeatWidth * nLayoutSign;
+ tools::Long nDataY = nRepStartY + nRepeatHeight;
+ tools::Long nEndX = nDataX + nContentWidth * nLayoutSign;
+ tools::Long nEndY = nDataY + nContentHeight;
+ tools::Long nFrameEndX = nEndX;
+ tools::Long nFrameEndY = nEndY;
+
+ if ( bLayoutRTL )
+ {
+ // each element's start position is its left edge
+ //! subtract one pixel less?
+ nInnerStartX -= nHeaderWidth; // used for header
+ nRepStartX -= nRepeatWidth;
+ nDataX -= nContentWidth;
+
+ // continue right of the main elements again
+ nEndX += nHeaderWidth + nRepeatWidth + nContentWidth;
+ }
+
+ // Page frame / background
+
+ //! adjust nEndX/Y
+
+ tools::Long nBorderEndX = nEndX;
+ tools::Long nBorderEndY = nEndY;
+ if (pBorderItem)
+ {
+ nBorderEndX += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetRight()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::RIGHT) ) * nScaleX );
+ nBorderEndY += static_cast<tools::Long>( ( lcl_LineTotal(pBorderItem->GetBottom()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM) ) * nScaleY );
+ }
+ if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
+ {
+ nBorderEndX += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT) * nScaleX );
+ nBorderEndY += static_cast<tools::Long>( pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM) * nScaleY );
+ }
+
+ if ( bDoPrint )
+ {
+ pDev->SetMapMode( aOffsetMode );
+ DrawBorder( nStartX, nStartY, nBorderEndX-nStartX, nBorderEndY-nStartY,
+ pBorderItem, pBackgroundItem, pShadowItem );
+
+ pDev->SetMapMode( aTwipMode );
+ }
+
+ pDev->SetMapMode( aOffsetMode );
+
+ // Output repeating rows/columns
+
+ if (bDoRepCol && bDoRepRow)
+ {
+ if ( bDoPrint )
+ PrintArea( nRepeatStartCol,nRepeatStartRow, nRepeatEndCol,nRepeatEndRow,
+ nRepStartX,nRepStartY, true, true, false, false );
+ if ( pLocationData )
+ LocateArea( nRepeatStartCol,nRepeatStartRow, nRepeatEndCol,nRepeatEndRow,
+ nRepStartX,nRepStartY, true, true, *pLocationData );
+ }
+ if (bDoRepCol)
+ {
+ if ( bDoPrint )
+ PrintArea( nRepeatStartCol,nY1, nRepeatEndCol,nY2, nRepStartX,nDataY,
+ true, !bDoRepRow, false, true );
+ if ( pLocationData )
+ LocateArea( nRepeatStartCol,nY1, nRepeatEndCol,nY2, nRepStartX,nDataY, true, false, *pLocationData );
+ }
+ if (bDoRepRow)
+ {
+ if ( bDoPrint )
+ PrintArea( nX1,nRepeatStartRow, nX2,nRepeatEndRow, nDataX,nRepStartY,
+ !bDoRepCol, true, true, false );
+ if ( pLocationData )
+ LocateArea( nX1,nRepeatStartRow, nX2,nRepeatEndRow, nDataX,nRepStartY, false, true, *pLocationData );
+ }
+
+ // output data
+
+ if ( bDoPrint )
+ PrintArea( nX1,nY1, nX2,nY2, nDataX,nDataY, !bDoRepCol,!bDoRepRow, true, true );
+ if ( pLocationData )
+ LocateArea( nX1,nY1, nX2,nY2, nDataX,nDataY, false,false, *pLocationData );
+
+ // output column/row headers
+ // after data (through probably shadow)
+
+ Color aGridColor( COL_BLACK );
+ if ( bUseStyleColor )
+ aGridColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
+
+ if (aTableParam.bHeaders)
+ {
+ if ( bDoPrint )
+ {
+ pDev->SetLineColor( aGridColor );
+ pDev->SetFillColor();
+ pDev->SetMapMode(aOffsetMode);
+ }
+
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ vcl::Font aFont;
+ ScAutoFontColorMode eColorMode = bUseStyleColor ? SC_AUTOCOL_DISPLAY : SC_AUTOCOL_PRINT;
+ aPattern.GetFont( aFont, eColorMode, pDev );
+ pDev->SetFont( aFont );
+
+ if (bDoRepCol)
+ {
+ if ( bDoPrint )
+ PrintColHdr( nRepeatStartCol,nRepeatEndCol, nRepStartX,nInnerStartY );
+ if ( pLocationData )
+ LocateColHdr( nRepeatStartCol,nRepeatEndCol, nRepStartX,nInnerStartY, true, *pLocationData );
+ }
+ if ( bDoPrint )
+ PrintColHdr( nX1,nX2, nDataX,nInnerStartY );
+ if ( pLocationData )
+ LocateColHdr( nX1,nX2, nDataX,nInnerStartY, false, *pLocationData );
+ if (bDoRepRow)
+ {
+ if ( bDoPrint )
+ PrintRowHdr( nRepeatStartRow,nRepeatEndRow, nInnerStartX,nRepStartY );
+ if ( pLocationData )
+ LocateRowHdr( nRepeatStartRow,nRepeatEndRow, nInnerStartX,nRepStartY, true, *pLocationData );
+ }
+ if ( bDoPrint )
+ PrintRowHdr( nY1,nY2, nInnerStartX,nDataY );
+ if ( pLocationData )
+ LocateRowHdr( nY1,nY2, nInnerStartX,nDataY, false, *pLocationData );
+ }
+
+ // simple frame
+
+ if ( bDoPrint && ( aTableParam.bGrid || aTableParam.bHeaders ) )
+ {
+ Size aOnePixel = pDev->PixelToLogic(Size(1,1));
+ tools::Long nOneX = aOnePixel.Width();
+ tools::Long nOneY = aOnePixel.Height();
+
+ tools::Long nLeftX = nFrameStartX;
+ tools::Long nTopY = nFrameStartY - nOneY;
+ tools::Long nRightX = nFrameEndX;
+ tools::Long nBottomY = nFrameEndY - nOneY;
+ if ( !bLayoutRTL )
+ {
+ nLeftX -= nOneX;
+ nRightX -= nOneX;
+ }
+ pDev->SetMapMode(aOffsetMode);
+ pDev->SetLineColor( aGridColor );
+ pDev->SetFillColor();
+ pDev->DrawRect( tools::Rectangle( nLeftX, nTopY, nRightX, nBottomY ) );
+ // nEndX/Y without frame-adaptation
+ }
+
+ if ( pPrinter && bDoPrint )
+ {
+ OSL_FAIL( "EndPage does not exist anymore" );
+ }
+
+ aLastSourceRange = ScRange( nX1, nY1, nPrintTab, nX2, nY2, nPrintTab );
+ bSourceRangeValid = true;
+}
+
+void ScPrintFunc::SetOffset( const Point& rOfs )
+{
+ aSrcOffset = rOfs;
+}
+
+void ScPrintFunc::SetManualZoom( sal_uInt16 nNewZoom )
+{
+ nManualZoom = nNewZoom;
+}
+
+void ScPrintFunc::SetClearFlag( bool bFlag )
+{
+ bClearWin = bFlag;
+}
+
+void ScPrintFunc::SetUseStyleColor( bool bFlag )
+{
+ bUseStyleColor = bFlag;
+ if (pEditEngine)
+ pEditEngine->EnableAutoColor( bUseStyleColor );
+}
+
+void ScPrintFunc::SetRenderFlag( bool bFlag )
+{
+ bIsRender = bFlag; // set when using XRenderable (PDF)
+}
+
+void ScPrintFunc::SetExclusivelyDrawOleAndDrawObjects()
+{
+ aTableParam.bCellContent = false;
+ aTableParam.bNotes = false;
+ aTableParam.bGrid = false;
+ aTableParam.bHeaders = false;
+ aTableParam.bFormulas = false;
+ aTableParam.bNullVals = false;
+}
+
+// UpdatePages is only called from outside to set the breaks correctly for viewing
+// - always without UserArea
+
+bool ScPrintFunc::UpdatePages()
+{
+ if (!pParamSet)
+ return false;
+
+ // Zoom
+
+ nZoom = 100;
+ if (aTableParam.bScalePageNum || aTableParam.bScaleTo)
+ nZoom = ZOOM_MIN; // correct for breaks
+ else if (aTableParam.bScaleAll)
+ {
+ nZoom = aTableParam.nScaleAll;
+ if ( nZoom <= ZOOM_MIN )
+ nZoom = ZOOM_MIN;
+ }
+
+ OUString aName = rDoc.GetPageStyle( nPrintTab );
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB nTab=0; nTab<nTabCount; nTab++)
+ if ( nTab==nPrintTab || rDoc.GetPageStyle(nTab)==aName )
+ {
+ // Repeating rows/columns
+ rDoc.SetRepeatArea( nTab, nRepeatStartCol,nRepeatEndCol, nRepeatStartRow,nRepeatEndRow );
+
+ // set breaks
+ ResetBreaks(nTab);
+ pDocShell->PostPaint(0,0,nTab,rDoc.MaxCol(),rDoc.MaxRow(),nTab, PaintPartFlags::Grid);
+ }
+
+ return true;
+}
+
+tools::Long ScPrintFunc::CountPages() // sets also nPagesX, nPagesY
+{
+ bool bAreaOk = false;
+
+ if (rDoc.HasTable( nPrintTab ))
+ {
+ if (aAreaParam.bPrintArea) // Specify print area?
+ {
+ if ( bPrintCurrentTable )
+ {
+ ScRange& rRange = aAreaParam.aPrintArea;
+
+ // Here, no comparison of the tables any more. Area is always valid for this table
+ // If comparison should be done here, the table of print ranges must be adjusted
+ // when inserting tables etc.!
+
+ nStartCol = rRange.aStart.Col();
+ nStartRow = rRange.aStart.Row();
+ nEndCol = rRange.aEnd .Col();
+ nEndRow = rRange.aEnd .Row();
+ bAreaOk = AdjustPrintArea(false); // limit
+ }
+ else
+ bAreaOk = false;
+ }
+ else // search from document
+ bAreaOk = AdjustPrintArea(true);
+ }
+
+ if (bAreaOk)
+ {
+ tools::Long nPages = 0;
+ size_t nY;
+ if (bMultiArea)
+ {
+ sal_uInt16 nRCount = rDoc.GetPrintRangeCount( nPrintTab );
+ for (sal_uInt16 i=0; i<nRCount; i++)
+ {
+ CalcZoom(i);
+ if ( aTableParam.bSkipEmpty )
+ for (nY=0; nY< m_aRanges.m_nPagesY; nY++)
+ nPages += (*m_aRanges.m_xPageRows)[nY].CountVisible();
+ else
+ nPages += static_cast<tools::Long>(m_aRanges.m_nPagesX) * m_aRanges.m_nPagesY;
+ if ( pPageData )
+ FillPageData();
+ }
+ }
+ else
+ {
+ CalcZoom(RANGENO_NORANGE); // calculate Zoom
+ if ( aTableParam.bSkipEmpty )
+ for (nY=0; nY<m_aRanges.m_nPagesY; nY++)
+ nPages += (*m_aRanges.m_xPageRows)[nY].CountVisible();
+ else
+ nPages += static_cast<tools::Long>(m_aRanges.m_nPagesX) * m_aRanges.m_nPagesY;
+ if ( pPageData )
+ FillPageData();
+ }
+ return nPages;
+ }
+ else
+ {
+ m_aRanges.m_nPagesX = m_aRanges.m_nPagesY = m_aRanges.m_nTotalY = 0;
+ return 0;
+ }
+}
+
+tools::Long ScPrintFunc::CountNotePages()
+{
+ if ( !aTableParam.bNotes || !bPrintCurrentTable )
+ return 0;
+
+ bool bError = false;
+ if (!aAreaParam.bPrintArea)
+ bError = !AdjustPrintArea(true); // completely search in Doc
+
+ sal_uInt16 nRepeats = 1; // how often go through it ?
+ if (bMultiArea)
+ nRepeats = rDoc.GetPrintRangeCount(nPrintTab);
+ if (bError)
+ nRepeats = 0;
+
+ for (sal_uInt16 nStep=0; nStep<nRepeats; nStep++)
+ {
+ bool bDoThis = true;
+ if (bMultiArea) // go through all Areas
+ {
+ const ScRange* pThisRange = rDoc.GetPrintRange( nPrintTab, nStep );
+ if ( pThisRange )
+ {
+ nStartCol = pThisRange->aStart.Col();
+ nStartRow = pThisRange->aStart.Row();
+ nEndCol = pThisRange->aEnd .Col();
+ nEndRow = pThisRange->aEnd .Row();
+ bDoThis = AdjustPrintArea(false);
+ }
+ }
+
+ if (bDoThis)
+ {
+ assert( bPrintAreaValid );
+ for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
+ {
+ if (rDoc.HasColNotes(nCol, nPrintTab))
+ {
+ for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow )
+ {
+ if ( rDoc.HasNote(nCol, nRow, nPrintTab) )
+ aNotePosList.emplace_back( nCol, nRow, nPrintTab );
+ }
+ }
+ }
+ }
+ }
+
+ tools::Long nPages = 0;
+ tools::Long nNoteNr = 0;
+ tools::Long nNoteAdd;
+ do
+ {
+ nNoteAdd = PrintNotes( nPages, nNoteNr, false, nullptr );
+ if (nNoteAdd)
+ {
+ nNoteNr += nNoteAdd;
+ ++nPages;
+ }
+ }
+ while (nNoteAdd);
+
+ return nPages;
+}
+
+void ScPrintFunc::InitModes() // set MapModes from nZoom etc.
+{
+ aOffset = Point( aSrcOffset.X()*100/nZoom, aSrcOffset.Y()*100/nZoom );
+
+ tools::Long nEffZoom = nZoom * static_cast<tools::Long>(nManualZoom);
+ constexpr auto HMM_PER_TWIPS = o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100);
+ nScaleX = nScaleY = HMM_PER_TWIPS; // output in 1/100 mm
+
+ Fraction aZoomFract( nEffZoom,10000 );
+ Fraction aHorFract = aZoomFract;
+
+ if ( !pPrinter && !bIsRender ) // adjust scale for preview
+ {
+ double nFact = pDocShell->GetOutputFactor();
+ aHorFract = Fraction( static_cast<tools::Long>( nEffZoom / nFact ), 10000 );
+ }
+
+ aLogicMode = MapMode( MapUnit::Map100thMM, Point(), aHorFract, aZoomFract );
+
+ Point aLogicOfs( -aOffset.X(), -aOffset.Y() );
+ aOffsetMode = MapMode( MapUnit::Map100thMM, aLogicOfs, aHorFract, aZoomFract );
+
+ Point aTwipsOfs( static_cast<tools::Long>( -aOffset.X() / nScaleX + 0.5 ), static_cast<tools::Long>( -aOffset.Y() / nScaleY + 0.5 ) );
+ aTwipMode = MapMode( MapUnit::MapTwip, aTwipsOfs, aHorFract, aZoomFract );
+}
+
+void ScPrintFunc::ApplyPrintSettings()
+{
+ if ( !pPrinter )
+ return;
+
+ // Configure Printer to Printing
+
+ Size aEnumSize = aPageSize;
+
+ pPrinter->SetOrientation( bLandscape ? Orientation::Landscape : Orientation::Portrait );
+ if ( bLandscape )
+ {
+ // landscape is always interpreted as a rotation by 90 degrees !
+ // this leads to non WYSIWIG but at least it prints!
+ // #i21775#
+ tools::Long nTemp = aEnumSize.Width();
+ aEnumSize.setWidth( aEnumSize.Height() );
+ aEnumSize.setHeight( nTemp );
+ }
+ Paper ePaper = SvxPaperInfo::GetSvxPaper( aEnumSize, MapUnit::MapTwip );
+ sal_uInt16 nPaperBin = pParamSet->Get(ATTR_PAGE_PAPERBIN).GetValue();
+
+ pPrinter->SetPaper( ePaper );
+ if ( PAPER_USER == ePaper )
+ {
+ MapMode aPrinterMode = pPrinter->GetMapMode();
+ MapMode aLocalMode( MapUnit::MapTwip );
+ pPrinter->SetMapMode( aLocalMode );
+ pPrinter->SetPaperSizeUser( aEnumSize );
+ pPrinter->SetMapMode( aPrinterMode );
+ }
+
+ pPrinter->SetPaperBin( nPaperBin );
+}
+
+// rPageRanges = range for all tables
+// nStartPage = rPageRanges starts at nStartPage
+// nDisplayStart = continuous number for displaying the page number
+
+tools::Long ScPrintFunc::DoPrint( const MultiSelection& rPageRanges,
+ tools::Long nStartPage, tools::Long nDisplayStart, bool bDoPrint,
+ ScPreviewLocationData* pLocationData )
+{
+ OSL_ENSURE(pDev,"Device == NULL");
+ if (!pParamSet)
+ return 0;
+
+ if ( pPrinter && bDoPrint )
+ ApplyPrintSettings();
+
+ InitModes();
+ if ( pLocationData )
+ {
+ pLocationData->SetCellMapMode( aOffsetMode );
+ pLocationData->SetPrintTab( nPrintTab );
+ }
+
+ MakeTableString();
+
+ tools::Long nPageNo = 0;
+ tools::Long nPrinted = 0;
+ tools::Long nEndPage = rPageRanges.GetTotalRange().Max();
+
+ sal_uInt16 nRepeats = 1;
+ if (bMultiArea)
+ nRepeats = rDoc.GetPrintRangeCount(nPrintTab);
+ for (sal_uInt16 nStep=0; nStep<nRepeats; nStep++)
+ {
+ if (bMultiArea) // replace area
+ {
+ CalcZoom(nStep); // also sets nStartCol etc. new
+ InitModes();
+ }
+
+ SCCOL nX1;
+ SCROW nY1;
+ SCCOL nX2;
+ SCROW nY2;
+ size_t nCountX;
+ size_t nCountY;
+
+ if (aTableParam.bTopDown) // top-bottom
+ {
+ nX1 = nStartCol;
+ for (nCountX=0; nCountX<m_aRanges.m_nPagesX; nCountX++)
+ {
+ OSL_ENSURE(nCountX < m_aRanges.m_xPageEndX->size(), "vector access error for aPageEndX (!)");
+ nX2 = (*m_aRanges.m_xPageEndX)[nCountX];
+ for (nCountY=0; nCountY<m_aRanges.m_nPagesY; nCountY++)
+ {
+ auto& rPageRow = (*m_aRanges.m_xPageRows)[nCountY];
+ nY1 = rPageRow.GetStartRow();
+ nY2 = rPageRow.GetEndRow();
+ if ( !aTableParam.bSkipEmpty || !rPageRow.IsHidden(nCountX) )
+ {
+ if ( rPageRanges.IsSelected( nPageNo+nStartPage+1 ) )
+ {
+ PrintPage( nPageNo+nDisplayStart, nX1, nY1, nX2, nY2,
+ bDoPrint, pLocationData );
+ ++nPrinted;
+ }
+ ++nPageNo;
+ }
+ }
+ nX1 = nX2 + 1;
+ }
+ }
+ else // left to right
+ {
+ for (nCountY=0; nCountY<m_aRanges.m_nPagesY; nCountY++)
+ {
+ auto& rPageRow = (*m_aRanges.m_xPageRows)[nCountY];
+ nY1 = rPageRow.GetStartRow();
+ nY2 = rPageRow.GetEndRow();
+ nX1 = nStartCol;
+ for (nCountX=0; nCountX<m_aRanges.m_nPagesX; nCountX++)
+ {
+ OSL_ENSURE(nCountX < m_aRanges.m_xPageEndX->size(), "vector access error for aPageEndX");
+ nX2 = (*m_aRanges.m_xPageEndX)[nCountX];
+ if ( !aTableParam.bSkipEmpty || !rPageRow.IsHidden(nCountX) )
+ {
+ if ( rPageRanges.IsSelected( nPageNo+nStartPage+1 ) )
+ {
+ PrintPage( nPageNo+nDisplayStart, nX1, nY1, nX2, nY2,
+ bDoPrint, pLocationData );
+ ++nPrinted;
+ }
+ ++nPageNo;
+ }
+ nX1 = nX2 + 1;
+ }
+ }
+ }
+ }
+
+ aFieldData.aTabName = ScResId( STR_NOTES );
+
+ tools::Long nNoteNr = 0;
+ tools::Long nNoteAdd;
+ do
+ {
+ if ( nPageNo+nStartPage <= nEndPage )
+ {
+ bool bPageSelected = rPageRanges.IsSelected( nPageNo+nStartPage+1 );
+ nNoteAdd = PrintNotes( nPageNo+nStartPage, nNoteNr, bDoPrint && bPageSelected,
+ ( bPageSelected ? pLocationData : nullptr ) );
+ if ( nNoteAdd )
+ {
+ nNoteNr += nNoteAdd;
+ if (bPageSelected)
+ {
+ ++nPrinted;
+ bSourceRangeValid = false; // last page was no cell range
+ }
+ ++nPageNo;
+ }
+ }
+ else
+ nNoteAdd = 0;
+ }
+ while (nNoteAdd);
+
+ if ( bMultiArea )
+ ResetBreaks(nPrintTab); //breaks correct for displaying
+
+ return nPrinted;
+}
+
+void ScPrintFunc::CalcZoom( sal_uInt16 nRangeNo ) // calculate zoom
+{
+ sal_uInt16 nRCount = rDoc.GetPrintRangeCount( nPrintTab );
+ const ScRange* pThisRange = nullptr;
+ if (nRangeNo != RANGENO_NORANGE && nRangeNo < nRCount)
+ pThisRange = rDoc.GetPrintRange( nPrintTab, nRangeNo );
+ if ( pThisRange )
+ {
+ nStartCol = pThisRange->aStart.Col();
+ nStartRow = pThisRange->aStart.Row();
+ nEndCol = pThisRange->aEnd .Col();
+ nEndRow = pThisRange->aEnd .Row();
+ }
+
+ if (!AdjustPrintArea(false)) // empty
+ {
+ nZoom = 100;
+ m_aRanges.m_nPagesX = m_aRanges.m_nPagesY = m_aRanges.m_nTotalY = 0;
+ return;
+ }
+
+ rDoc.SetRepeatArea( nPrintTab, nRepeatStartCol,nRepeatEndCol, nRepeatStartRow,nRepeatEndRow );
+
+ if (aTableParam.bScalePageNum)
+ {
+ nZoom = 100;
+ sal_uInt16 nPagesToFit = aTableParam.nScalePageNum;
+
+ // If manual breaks are forced, calculate minimum # pages required
+ if (aTableParam.bForceBreaks)
+ {
+ sal_uInt16 nMinPages = 0;
+ std::set<SCROW> aRowBreaks;
+ std::set<SCCOL> aColBreaks;
+ rDoc.GetAllRowBreaks(aRowBreaks, nPrintTab, false, true);
+ rDoc.GetAllColBreaks(aColBreaks, nPrintTab, false, true);
+ nMinPages = (aRowBreaks.size() + 1) * (aColBreaks.size() + 1);
+
+ // #i54993# use min forced by breaks if it's > # pages in
+ // scale parameter to avoid bottoming out at <= ZOOM_MIN
+ nPagesToFit = std::max(nMinPages, nPagesToFit);
+ }
+
+ sal_uInt16 nLastFitZoom = 0, nLastNonFitZoom = 0;
+ while (true)
+ {
+ if (nZoom <= ZOOM_MIN)
+ break;
+
+ CalcPages();
+ bool bFitsPage = (m_aRanges.m_nPagesX * m_aRanges.m_nPagesY <= nPagesToFit);
+
+ if (bFitsPage)
+ {
+ if (nZoom == 100)
+ // If it fits at 100%, it's good enough for me.
+ break;
+
+ nLastFitZoom = nZoom;
+ nZoom = (nLastNonFitZoom + nZoom) / 2;
+
+ if (nLastFitZoom == nZoom)
+ // It converged. Use this zoom level.
+ break;
+ }
+ else
+ {
+ if (nZoom - nLastFitZoom <= 1)
+ {
+ nZoom = nLastFitZoom;
+ CalcPages();
+ break;
+ }
+
+ nLastNonFitZoom = nZoom;
+ nZoom = (nLastFitZoom + nZoom) / 2;
+ }
+ }
+ }
+ else if (aTableParam.bScaleTo)
+ {
+ nZoom = 100;
+ sal_uInt16 nW = aTableParam.nScaleWidth;
+ sal_uInt16 nH = aTableParam.nScaleHeight;
+
+ // If manual breaks are forced, calculate minimum # pages required
+ if (aTableParam.bForceBreaks)
+ {
+ sal_uInt16 nMinPagesW = 0, nMinPagesH = 0;
+ std::set<SCROW> aRowBreaks;
+ std::set<SCCOL> aColBreaks;
+ rDoc.GetAllRowBreaks(aRowBreaks, nPrintTab, false, true);
+ rDoc.GetAllColBreaks(aColBreaks, nPrintTab, false, true);
+ nMinPagesW = aColBreaks.size() + 1;
+ nMinPagesH = aRowBreaks.size() + 1;
+
+ // #i54993# use min forced by breaks if it's > # pages in
+ // scale parameters to avoid bottoming out at <= ZOOM_MIN
+ nW = std::max(nMinPagesW, nW);
+ nH = std::max(nMinPagesH, nH);
+ }
+
+ sal_uInt16 nLastFitZoom = 0, nLastNonFitZoom = 0;
+ while (true)
+ {
+ if (nZoom <= ZOOM_MIN)
+ break;
+
+ CalcPages();
+ bool bFitsPage = ((!nW || (m_aRanges.m_nPagesX <= nW)) && (!nH || (m_aRanges.m_nPagesY <= nH)));
+
+ if (bFitsPage)
+ {
+ if (nZoom == 100)
+ // If it fits at 100%, it's good enough for me.
+ break;
+
+ nLastFitZoom = nZoom;
+ nZoom = (nLastNonFitZoom + nZoom) / 2;
+
+ if (nLastFitZoom == nZoom)
+ // It converged. Use this zoom level.
+ break;
+ }
+ else
+ {
+ if (nZoom - nLastFitZoom <= 1)
+ {
+ nZoom = nLastFitZoom;
+ CalcPages();
+ break;
+ }
+
+ nLastNonFitZoom = nZoom;
+ nZoom = (nLastFitZoom + nZoom) / 2;
+ }
+ }
+ // tdf#103516 remove the almost blank page(s) for better
+ // interoperability by using slightly smaller zoom
+ if (nW > 0 && nH == 0 && m_aRanges.m_nPagesY > 1)
+ {
+ sal_uInt32 nLastPagesY = m_aRanges.m_nPagesY;
+ nLastFitZoom = nZoom;
+ nZoom *= 0.98;
+ if (nZoom < nLastFitZoom)
+ {
+ CalcPages();
+ // same page count with smaller zoom: use the original zoom
+ if (m_aRanges.m_nPagesY == nLastPagesY)
+ {
+ nZoom = nLastFitZoom;
+ CalcPages();
+ }
+ }
+ }
+ }
+ else if (aTableParam.bScaleAll)
+ {
+ nZoom = aTableParam.nScaleAll;
+ if ( nZoom <= ZOOM_MIN )
+ nZoom = ZOOM_MIN;
+ CalcPages();
+ }
+ else
+ {
+ OSL_ENSURE( aTableParam.bScaleNone, "no scale flag is set" );
+ nZoom = 100;
+ CalcPages();
+ }
+}
+
+Size ScPrintFunc::GetDocPageSize()
+{
+ // Adjust height of head/foot line
+
+ InitModes(); // initialize aTwipMode from nZoom
+ pDev->SetMapMode( aTwipMode ); // head/foot line in Twips
+ UpdateHFHeight( aHdr );
+ UpdateHFHeight( aFtr );
+
+ // Page size in Document-Twips
+ // Calculating Left / Right also in PrintPage
+
+ aPageRect = tools::Rectangle( Point(), aPageSize );
+ aPageRect.SetLeft( ( aPageRect.Left() + nLeftMargin ) * 100 / nZoom );
+ aPageRect.SetRight( ( aPageRect.Right() - nRightMargin ) * 100 / nZoom );
+ aPageRect.SetTop( ( aPageRect.Top() + nTopMargin ) * 100 / nZoom + aHdr.nHeight );
+ aPageRect.SetBottom( ( aPageRect.Bottom() - nBottomMargin ) * 100 / nZoom - aFtr.nHeight );
+
+ Size aDocPageSize = aPageRect.GetSize();
+ if (aTableParam.bHeaders)
+ {
+ aDocPageSize.AdjustWidth( -(tools::Long(PRINT_HEADER_WIDTH)) );
+ aDocPageSize.AdjustHeight( -(tools::Long(PRINT_HEADER_HEIGHT)) );
+ }
+ if (pBorderItem)
+ {
+ aDocPageSize.AdjustWidth( -(lcl_LineTotal(pBorderItem->GetLeft()) +
+ lcl_LineTotal(pBorderItem->GetRight()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::LEFT) +
+ pBorderItem->GetDistance(SvxBoxItemLine::RIGHT)) );
+ aDocPageSize.AdjustHeight( -(lcl_LineTotal(pBorderItem->GetTop()) +
+ lcl_LineTotal(pBorderItem->GetBottom()) +
+ pBorderItem->GetDistance(SvxBoxItemLine::TOP) +
+ pBorderItem->GetDistance(SvxBoxItemLine::BOTTOM)) );
+ }
+ if (pShadowItem && pShadowItem->GetLocation() != SvxShadowLocation::NONE)
+ {
+ aDocPageSize.AdjustWidth( -(pShadowItem->CalcShadowSpace(SvxShadowItemSide::LEFT) +
+ pShadowItem->CalcShadowSpace(SvxShadowItemSide::RIGHT)) );
+ aDocPageSize.AdjustHeight( -(pShadowItem->CalcShadowSpace(SvxShadowItemSide::TOP) +
+ pShadowItem->CalcShadowSpace(SvxShadowItemSide::BOTTOM)) );
+ }
+ return aDocPageSize;
+}
+
+void ScPrintFunc::ResetBreaks( SCTAB nTab ) // Set Breaks correctly for view
+{
+ rDoc.SetPageSize( nTab, GetDocPageSize() );
+ rDoc.UpdatePageBreaks( nTab );
+}
+
+static void lcl_SetHidden( const ScDocument& rDoc, SCTAB nPrintTab, ScPageRowEntry& rPageRowEntry,
+ SCCOL nStartCol, const std::vector< SCCOL >& rPageEndX )
+{
+ size_t nPagesX = rPageRowEntry.GetPagesX();
+ SCROW nStartRow = rPageRowEntry.GetStartRow();
+ SCROW nEndRow = rPageRowEntry.GetEndRow();
+
+ bool bLeftIsEmpty = false;
+ ScRange aTempRange;
+ tools::Rectangle aTempRect = rDoc.GetMMRect( 0,0, 0,0, 0 );
+
+ for (size_t i=0; i<nPagesX; i++)
+ {
+ OSL_ENSURE(i < rPageEndX.size(), "vector access error for aPageEndX");
+ SCCOL nEndCol = rPageEndX[i];
+ if ( rDoc.IsPrintEmpty( nStartCol, nStartRow, nEndCol, nEndRow, nPrintTab,
+ bLeftIsEmpty, &aTempRange, &aTempRect ) )
+ {
+ rPageRowEntry.SetHidden(i);
+ bLeftIsEmpty = true;
+ }
+ else
+ bLeftIsEmpty = false;
+
+ nStartCol = nEndCol+1;
+ }
+}
+
+void ScPrintFunc::CalcPages() // calculates aPageRect and pages from nZoom
+{
+ assert( bPrintAreaValid );
+ m_aRanges.calculate(rDoc, aTableParam.bSkipEmpty, aAreaParam.bPrintArea, nStartRow, nEndRow, nStartCol, nEndCol, nPrintTab, GetDocPageSize());
+}
+
+namespace sc
+{
+
+PrintPageRanges::PrintPageRanges()
+ : m_nPagesX(0)
+ , m_nPagesY(0)
+ , m_nTotalY(0)
+{}
+
+bool PrintPageRanges::checkIfAlreadyCalculatedAndSet(
+ bool bSkipEmpty, bool bPrintArea,
+ SCROW nStartRow, SCROW nEndRow,
+ SCCOL nStartCol, SCCOL nEndCol,
+ SCTAB nPrintTab, Size const & rDocSize)
+{
+ if (bSkipEmpty == m_aInput.m_bSkipEmpty &&
+ bPrintArea == m_aInput.m_bPrintArea &&
+ nStartRow == m_aInput.m_nStartRow && nEndRow == m_aInput.m_nEndRow &&
+ nStartCol == m_aInput.m_nStartCol && nEndCol == m_aInput.m_nEndCol &&
+ nPrintTab == m_aInput.m_nPrintTab &&
+ rDocSize == m_aInput.m_aDocSize)
+ {
+ return true;
+ }
+
+ m_aInput.m_bSkipEmpty = bSkipEmpty;
+ m_aInput.m_bPrintArea = bPrintArea;
+ m_aInput.m_nStartRow = nStartRow;
+ m_aInput.m_nEndRow = nEndRow;
+ m_aInput.m_nStartCol = nStartCol;
+ m_aInput.m_nEndCol = nEndCol;
+ m_aInput.m_nPrintTab = nPrintTab;
+ m_aInput.m_aDocSize = rDocSize;
+
+ return false;
+}
+
+void PrintPageRanges::calculate(ScDocument& rDoc,
+ bool bSkipEmpty, bool bPrintArea,
+ SCROW nStartRow, SCROW nEndRow,
+ SCCOL nStartCol, SCCOL nEndCol,
+ SCTAB nPrintTab, Size const & rDocSize)
+{
+ // Already calculated?
+ if (checkIfAlreadyCalculatedAndSet(bSkipEmpty, bPrintArea,
+ nStartRow, nEndRow, nStartCol, nEndCol,
+ nPrintTab, rDocSize))
+ return;
+
+ rDoc.SetPageSize(nPrintTab, rDocSize);
+
+ // Clear the map to prevent any outdated values to "survive" when
+ // we have to recalculate the new values anyway
+ m_xPageRows->clear();
+
+ // #i123672# use dynamic mem to react on size changes
+ if (m_xPageEndX->size() < static_cast<size_t>(rDoc.MaxCol()) + 1)
+ {
+ m_xPageEndX->resize(rDoc.MaxCol()+1, SCCOL());
+ }
+
+ if (bPrintArea)
+ {
+ ScRange aRange(nStartCol, nStartRow, nPrintTab, nEndCol, nEndRow, nPrintTab);
+ rDoc.UpdatePageBreaks(nPrintTab, &aRange);
+ }
+ else
+ {
+ rDoc.UpdatePageBreaks(nPrintTab); // else, end is marked
+ }
+
+ const size_t nRealCnt = nEndRow - nStartRow + 1;
+
+ // #i123672# use dynamic mem to react on size changes
+ if (m_xPageEndY->size() < nRealCnt+1)
+ {
+ m_xPageEndY->resize(nRealCnt + 1, SCROW());
+ }
+
+ // Page alignment/splitting after breaks in Col/RowFlags
+ // Of several breaks in a hidden area, only one counts.
+
+ m_nPagesX = 0;
+ m_nPagesY = 0;
+ m_nTotalY = 0;
+
+ bool bVisCol = false;
+ for (SCCOL i = nStartCol; i <= nEndCol; i++)
+ {
+ bool bHidden = rDoc.ColHidden(i, nPrintTab);
+ bool bPageBreak(rDoc.HasColBreak(i, nPrintTab) & ScBreakType::Page);
+ if (i > nStartCol && bVisCol && bPageBreak)
+ {
+ OSL_ENSURE(m_nPagesX < m_xPageEndX->size(), "vector access error for aPageEndX");
+ (*m_xPageEndX)[m_nPagesX] = i-1;
+ ++m_nPagesX;
+ bVisCol = false;
+ }
+ if (!bHidden)
+ bVisCol = true;
+ }
+ if (bVisCol) // also at the end, no empty pages
+ {
+ OSL_ENSURE(m_nPagesX < m_xPageEndX->size(), "vector access error for aPageEndX");
+ (*m_xPageEndX)[m_nPagesX] = nEndCol;
+ ++m_nPagesX;
+ }
+
+ bool bVisRow = false;
+ SCROW nPageStartRow = nStartRow;
+ SCROW nLastVisibleRow = -1;
+
+ std::unique_ptr<ScRowBreakIterator> pRowBreakIter(rDoc.GetRowBreakIterator(nPrintTab));
+ SCROW nNextPageBreak = pRowBreakIter->first();
+ while (nNextPageBreak != ScRowBreakIterator::NOT_FOUND && nNextPageBreak < nStartRow)
+ // Skip until the page break position is at the start row or greater.
+ nNextPageBreak = pRowBreakIter->next();
+
+ for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
+ {
+ bool bPageBreak = (nNextPageBreak == nRow);
+ if (bPageBreak)
+ nNextPageBreak = pRowBreakIter->next();
+
+ if (nRow > nStartRow && bVisRow && bPageBreak)
+ {
+ OSL_ENSURE(m_nTotalY < m_xPageEndY->size(), "vector access error for rPageEndY");
+ (*m_xPageEndY)[m_nTotalY] = nRow - 1;
+ ++m_nTotalY;
+
+ if (!bSkipEmpty || !rDoc.IsPrintEmpty(nStartCol, nPageStartRow, nEndCol, nRow-1, nPrintTab))
+ {
+ auto& rPageRow = (*m_xPageRows)[m_nPagesY];
+ rPageRow.SetStartRow(nPageStartRow);
+ rPageRow.SetEndRow(nRow - 1);
+ rPageRow.SetPagesX(m_nPagesX);
+ if (bSkipEmpty)
+ lcl_SetHidden(rDoc, nPrintTab, rPageRow, nStartCol, *m_xPageEndX);
+ ++m_nPagesY;
+ }
+
+ nPageStartRow = nRow;
+ bVisRow = false;
+ }
+
+ if (nRow <= nLastVisibleRow)
+ {
+ // This row is still visible. Don't bother calling RowHidden() to
+ // find out, for speed optimization.
+ bVisRow = true;
+ continue;
+ }
+
+ SCROW nLastRow = -1;
+ if (!rDoc.RowHidden(nRow, nPrintTab, nullptr, &nLastRow))
+ {
+ bVisRow = true;
+ nLastVisibleRow = nLastRow;
+ }
+ else
+ {
+ // Skip all hidden rows until next pagebreak.
+ nRow = ((nNextPageBreak == ScRowBreakIterator::NOT_FOUND) ? nLastRow :
+ std::min(nLastRow, nNextPageBreak - 1));
+ }
+ }
+
+ if (!bVisRow)
+ return;
+
+ OSL_ENSURE(m_nTotalY < m_xPageEndY->size(), "vector access error for maPageEndY");
+ (*m_xPageEndY)[m_nTotalY] = nEndRow;
+ ++m_nTotalY;
+
+ if (!bSkipEmpty || !rDoc.IsPrintEmpty(nStartCol, nPageStartRow, nEndCol, nEndRow, nPrintTab))
+ {
+ auto& rPageRow = (*m_xPageRows)[m_nPagesY];
+ rPageRow.SetStartRow(nPageStartRow);
+ rPageRow.SetEndRow(nEndRow);
+ rPageRow.SetPagesX(m_nPagesX);
+ if (bSkipEmpty)
+ lcl_SetHidden(rDoc, nPrintTab, rPageRow, nStartCol, *m_xPageEndX);
+ ++m_nPagesY;
+ }
+}
+
+} // end namespace sc
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/reffact.cxx b/sc/source/ui/view/reffact.cxx
new file mode 100644
index 000000000..0133a9074
--- /dev/null
+++ b/sc/source/ui/view/reffact.cxx
@@ -0,0 +1,298 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/basedlgs.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <reffact.hxx>
+#include <tabvwsh.hxx>
+#include <sc.hrc>
+#include <acredlin.hxx>
+#include <simpref.hxx>
+#include <scmod.hxx>
+#include <scres.hrc>
+#include <validate.hxx>
+
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScNameDlgWrapper, FID_DEFINE_NAME)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScNameDefDlgWrapper, FID_ADD_NAME)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScSolverDlgWrapper, SID_OPENDLG_SOLVE)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScOptSolverDlgWrapper, SID_OPENDLG_OPTSOLVER)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScXMLSourceDlgWrapper, SID_MANAGE_XML_SOURCE)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScPivotLayoutWrapper, SID_OPENDLG_PIVOTTABLE)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScTabOpDlgWrapper, SID_OPENDLG_TABOP)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScFilterDlgWrapper, SID_FILTER)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScSpecialFilterDlgWrapper, SID_SPECIAL_FILTER)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScDbNameDlgWrapper, SID_DEFINE_DBNAME)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScConsolidateDlgWrapper, SID_OPENDLG_CONSOLIDATE)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScPrintAreasDlgWrapper, SID_OPENDLG_EDIT_PRINTAREA)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScColRowNameRangesDlgWrapper, SID_DEFINE_COLROWNAMERANGES)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScFormulaDlgWrapper, SID_OPENDLG_FUNCTION)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScAcceptChgDlgWrapper, FID_CHG_ACCEPT)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScHighlightChgDlgWrapper, FID_CHG_SHOW)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScSimpleRefDlgWrapper, WID_SIMPLE_REF)
+SFX_IMPL_MODELESSDIALOGCONTOLLER_WITHID(ScCondFormatDlgWrapper, WID_CONDFRMT_REF)
+
+SFX_IMPL_CHILDWINDOW_WITHID(ScValidityRefChildWin, SID_VALIDITY_REFERENCE)
+
+SfxChildWinInfo ScValidityRefChildWin::GetInfo() const
+{
+ SfxChildWinInfo aInfo = SfxChildWindow::GetInfo();
+ return aInfo;
+}
+
+namespace
+{
+ ScTabViewShell* lcl_GetTabViewShell( const SfxBindings* pBindings );
+}
+
+#define IMPL_CONTROLLER_CHILD_CTOR(Class,sid) \
+ Class::Class( vcl::Window* pParentP, \
+ sal_uInt16 nId, \
+ SfxBindings* p, \
+ const SfxChildWinInfo* pInfo ) \
+ : SfxChildWindow(pParentP, nId) \
+ { \
+ /************************************************************************************/\
+ /* When a new document is creating, the SfxViewFrame may be ready, */\
+ /* But the ScTabViewShell may have not been activated yet. In this */\
+ /* situation, SfxViewShell::Current() does not get the correct shell, */\
+ /* and we should lcl_GetTabViewShell( p ) instead of SfxViewShell::Current() */\
+ /************************************************************************************/\
+ ScTabViewShell* pViewShell = lcl_GetTabViewShell( p ); \
+ if (!pViewShell) \
+ pViewShell = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() ); \
+ OSL_ENSURE( pViewShell, "missing view shell :-(" ); \
+ SetController( pViewShell ? \
+ pViewShell->CreateRefDialogController( p, this, pInfo, pParentP->GetFrameWeld(), sid ) : nullptr ); \
+ if (pViewShell && !GetController()) \
+ pViewShell->GetViewFrame()->SetChildWindow( nId, false ); \
+ }
+
+
+IMPL_CONTROLLER_CHILD_CTOR( ScNameDlgWrapper, FID_DEFINE_NAME )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScNameDefDlgWrapper, FID_ADD_NAME )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScSolverDlgWrapper, SID_OPENDLG_SOLVE )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScOptSolverDlgWrapper, SID_OPENDLG_OPTSOLVER )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScXMLSourceDlgWrapper, SID_MANAGE_XML_SOURCE)
+
+IMPL_CONTROLLER_CHILD_CTOR( ScPivotLayoutWrapper, SID_OPENDLG_PIVOTTABLE )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScTabOpDlgWrapper, SID_OPENDLG_TABOP )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScFilterDlgWrapper, SID_FILTER )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScSpecialFilterDlgWrapper, SID_SPECIAL_FILTER )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScDbNameDlgWrapper, SID_DEFINE_DBNAME )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScColRowNameRangesDlgWrapper, SID_DEFINE_COLROWNAMERANGES )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScConsolidateDlgWrapper, SID_OPENDLG_CONSOLIDATE )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScPrintAreasDlgWrapper, SID_OPENDLG_EDIT_PRINTAREA )
+
+IMPL_CONTROLLER_CHILD_CTOR( ScFormulaDlgWrapper, SID_OPENDLG_FUNCTION )
+
+// ScSimpleRefDlgWrapper
+
+static bool bScSimpleRefFlag;
+static tools::Long nScSimpleRefHeight;
+static tools::Long nScSimpleRefWidth;
+static tools::Long nScSimpleRefX;
+static tools::Long nScSimpleRefY;
+static bool bAutoReOpen = true;
+
+ScSimpleRefDlgWrapper::ScSimpleRefDlgWrapper( vcl::Window* pParentP,
+ sal_uInt16 nId,
+ SfxBindings* p,
+ SfxChildWinInfo* pInfo )
+ : SfxChildWindow(pParentP, nId)
+{
+
+ ScTabViewShell* pViewShell = nullptr;
+ SfxDispatcher* pDisp = p->GetDispatcher();
+ if ( pDisp )
+ {
+ SfxViewFrame* pViewFrm = pDisp->GetFrame();
+ if ( pViewFrm )
+ pViewShell = dynamic_cast<ScTabViewShell*>( pViewFrm->GetViewShell() );
+ }
+
+ OSL_ENSURE( pViewShell, "missing view shell :-(" );
+
+ if(pInfo!=nullptr && bScSimpleRefFlag)
+ {
+ pInfo->aPos.setX(nScSimpleRefX );
+ pInfo->aPos.setY(nScSimpleRefY );
+ pInfo->aSize.setHeight(nScSimpleRefHeight );
+ pInfo->aSize.setWidth(nScSimpleRefWidth );
+ }
+ SetController(nullptr);
+
+ if (bAutoReOpen && pViewShell)
+ SetController(pViewShell->CreateRefDialogController(p, this, pInfo, pParentP->GetFrameWeld(), WID_SIMPLE_REF));
+
+ if (!GetController())
+ {
+ SC_MOD()->SetRefDialog( nId, false );
+ }
+}
+
+void ScSimpleRefDlgWrapper::SetAutoReOpen(bool bFlag)
+{
+ bAutoReOpen=bFlag;
+}
+
+void ScSimpleRefDlgWrapper::SetRefString(const OUString& rStr)
+{
+ auto xDlgController = GetController();
+ if (xDlgController)
+ {
+ static_cast<ScSimpleRefDlg*>(xDlgController.get())->SetRefString(rStr);
+ }
+}
+
+void ScSimpleRefDlgWrapper::SetCloseHdl( const Link<const OUString*,void>& rLink )
+{
+ auto xDlgController = GetController();
+ if (xDlgController)
+ {
+ static_cast<ScSimpleRefDlg*>(xDlgController.get())->SetCloseHdl(rLink);
+ }
+}
+
+void ScSimpleRefDlgWrapper::SetUnoLinks( const Link<const OUString&,void>& rDone,
+ const Link<const OUString&,void>& rAbort, const Link<const OUString&,void>& rChange )
+{
+ auto xDlgController = GetController();
+ if (xDlgController)
+ {
+ static_cast<ScSimpleRefDlg*>(xDlgController.get())->SetUnoLinks( rDone, rAbort, rChange );
+ }
+}
+
+void ScSimpleRefDlgWrapper::SetFlags( bool bCloseOnButtonUp, bool bSingleCell, bool bMultiSelection )
+{
+ auto xDlgController = GetController();
+ if (xDlgController)
+ {
+ static_cast<ScSimpleRefDlg*>(xDlgController.get())->SetFlags( bCloseOnButtonUp, bSingleCell, bMultiSelection );
+ }
+}
+
+void ScSimpleRefDlgWrapper::StartRefInput()
+{
+ auto xDlgController = GetController();
+ if (xDlgController)
+ {
+ static_cast<ScSimpleRefDlg*>(xDlgController.get())->StartRefInput();
+ }
+}
+
+// ScAcceptChgDlgWrapper //FIXME: should be moved into ViewShell
+
+ScAcceptChgDlgWrapper::ScAcceptChgDlgWrapper(vcl::Window* pParentP,
+ sal_uInt16 nId,
+ SfxBindings* pBindings,
+ SfxChildWinInfo* pInfo ) :
+ SfxChildWindow( pParentP, nId )
+{
+ ScTabViewShell* pViewShell =
+ dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ OSL_ENSURE( pViewShell, "missing view shell :-(" );
+ if (pViewShell)
+ {
+ auto xDlg = std::make_shared<ScAcceptChgDlg>(pBindings, this, pParentP->GetFrameWeld(), &pViewShell->GetViewData());
+ SetController(xDlg);
+ xDlg->Initialize( pInfo );
+ }
+ else
+ SetController( nullptr );
+ if (pViewShell && !GetController())
+ pViewShell->GetViewFrame()->SetChildWindow( nId, false );
+}
+
+void ScAcceptChgDlgWrapper::ReInitDlg()
+{
+ ScTabViewShell* pViewShell =
+ dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ OSL_ENSURE( pViewShell, "missing view shell :-(" );
+
+ if (GetController() && pViewShell)
+ {
+ static_cast<ScAcceptChgDlg*>(GetController().get())->ReInit(&pViewShell->GetViewData());
+ }
+}
+
+// ScHighlightChgDlgWrapper
+
+IMPL_CONTROLLER_CHILD_CTOR(ScHighlightChgDlgWrapper, FID_CHG_SHOW)
+
+namespace
+{
+ ScTabViewShell * lcl_GetTabViewShell( const SfxBindings *pBindings )
+ {
+ if( pBindings )
+ if( SfxDispatcher* pDisp = pBindings ->GetDispatcher() )
+ if( SfxViewFrame *pFrm = pDisp->GetFrame() )
+ if( SfxViewShell* pViewSh = pFrm->GetViewShell() )
+ return dynamic_cast<ScTabViewShell*>( pViewSh );
+
+ return nullptr;
+ }
+}
+
+ScValidityRefChildWin::ScValidityRefChildWin(vcl::Window* pParentP,
+ sal_uInt16 nId,
+ const SfxBindings* p,
+ SAL_UNUSED_PARAMETER SfxChildWinInfo* /*pInfo*/ )
+ : SfxChildWindow(pParentP, nId)
+ , m_bVisibleLock(false)
+ , m_bFreeWindowLock(false)
+{
+ SetWantsFocus( false );
+ std::shared_ptr<SfxDialogController> xDlg(ScValidationDlg::Find1AliveObject(pParentP->GetFrameWeld()));
+ SetController(xDlg);
+ ScTabViewShell* pViewShell;
+ if (xDlg)
+ pViewShell = static_cast<ScValidationDlg*>(xDlg.get())->GetTabViewShell();
+ else
+ pViewShell = lcl_GetTabViewShell( p );
+ if (!pViewShell)
+ pViewShell = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() );
+ OSL_ENSURE( pViewShell, "missing view shell :-(" );
+ if (pViewShell && !xDlg)
+ pViewShell->GetViewFrame()->SetChildWindow( nId, false );
+}
+
+ScValidityRefChildWin::~ScValidityRefChildWin()
+{
+ if (m_bFreeWindowLock)
+ SetController(nullptr);
+}
+
+IMPL_CONTROLLER_CHILD_CTOR( ScCondFormatDlgWrapper, WID_CONDFRMT_REF )
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/scextopt.cxx b/sc/source/ui/view/scextopt.cxx
new file mode 100644
index 000000000..206b7cdc8
--- /dev/null
+++ b/sc/source/ui/view/scextopt.cxx
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scextopt.hxx>
+
+#include <osl/diagnose.h>
+
+#include <map>
+#include <memory>
+#include <vector>
+
+ScExtDocSettings::ScExtDocSettings() :
+ mfTabBarWidth( -1.0 ),
+ mnLinkCnt( 0 ),
+ mnDisplTab( -1 )
+{
+}
+
+ScExtTabSettings::ScExtTabSettings() :
+ maUsedArea( ScAddress::INITIALIZE_INVALID ),
+ maCursor( ScAddress::INITIALIZE_INVALID ),
+ maFirstVis( ScAddress::INITIALIZE_INVALID ),
+ maSecondVis( ScAddress::INITIALIZE_INVALID ),
+ maFreezePos( 0, 0, 0 ),
+ maSplitPos( 0, 0 ),
+ meActivePane( SCEXT_PANE_TOPLEFT ),
+ maGridColor( COL_AUTO ),
+ mnNormalZoom( 0 ),
+ mnPageZoom( 0 ),
+ mbSelected( false ),
+ mbFrozenPanes( false ),
+ mbPageMode( false ),
+ mbShowGrid( true )
+{
+}
+
+namespace {
+
+/** A container for ScExtTabSettings objects.
+ @descr Internally, a std::map with shared pointers to ScExtTabSettings is
+ used. The copy constructor and assignment operator make deep copies of the
+ objects. */
+class ScExtTabSettingsCont
+{
+public:
+ explicit ScExtTabSettingsCont();
+ ScExtTabSettingsCont( const ScExtTabSettingsCont& rSrc );
+ ScExtTabSettingsCont& operator=( const ScExtTabSettingsCont& rSrc );
+
+ const ScExtTabSettings* GetTabSettings( SCTAB nTab ) const;
+ ScExtTabSettings& GetOrCreateTabSettings( SCTAB nTab );
+
+ SCTAB GetLastTab() const;
+
+private:
+ typedef std::shared_ptr< ScExtTabSettings > ScExtTabSettingsRef;
+ typedef ::std::map< SCTAB, ScExtTabSettingsRef > ScExtTabSettingsMap;
+
+ /** Makes a deep copy of all objects in the passed map. */
+ void CopyFromMap( const ScExtTabSettingsMap& rMap );
+
+ ScExtTabSettingsMap maMap;
+};
+
+}
+
+ScExtTabSettingsCont::ScExtTabSettingsCont()
+{
+}
+
+ScExtTabSettingsCont::ScExtTabSettingsCont( const ScExtTabSettingsCont& rSrc )
+{
+ CopyFromMap( rSrc.maMap );
+}
+
+ScExtTabSettingsCont& ScExtTabSettingsCont::operator=( const ScExtTabSettingsCont& rSrc )
+{
+ CopyFromMap( rSrc.maMap );
+ return *this;
+}
+
+const ScExtTabSettings* ScExtTabSettingsCont::GetTabSettings( SCTAB nTab ) const
+{
+ ScExtTabSettingsMap::const_iterator aIt = maMap.find( nTab );
+ return (aIt == maMap.end()) ? nullptr : aIt->second.get();
+}
+
+ScExtTabSettings& ScExtTabSettingsCont::GetOrCreateTabSettings( SCTAB nTab )
+{
+ ScExtTabSettingsRef& rxTabSett = maMap[ nTab ];
+ if( !rxTabSett )
+ rxTabSett = std::make_shared<ScExtTabSettings>();
+ return *rxTabSett;
+}
+
+SCTAB ScExtTabSettingsCont::GetLastTab() const
+{
+ return maMap.empty() ? -1 : maMap.rbegin()->first;
+}
+
+void ScExtTabSettingsCont::CopyFromMap( const ScExtTabSettingsMap& rMap )
+{
+ maMap.clear();
+ for( const auto& [rTab, rxSettings] : rMap )
+ maMap[ rTab ] = std::make_shared<ScExtTabSettings>( *rxSettings );
+}
+
+/** Implementation struct for ScExtDocOptions containing all members. */
+struct ScExtDocOptionsImpl
+{
+ ScExtDocSettings maDocSett; /// Global document settings.
+ ScExtTabSettingsCont maTabSett; /// Settings for all sheets.
+ std::vector< OUString > maCodeNames; /// Codenames for all sheets (VBA module names).
+ bool mbChanged; /// Use only if something has been changed.
+
+ explicit ScExtDocOptionsImpl();
+};
+
+ScExtDocOptionsImpl::ScExtDocOptionsImpl() :
+ mbChanged( false )
+{
+}
+
+ScExtDocOptions::ScExtDocOptions() :
+ mxImpl( new ScExtDocOptionsImpl )
+{
+}
+
+ScExtDocOptions::ScExtDocOptions( const ScExtDocOptions& rSrc ) :
+ mxImpl( new ScExtDocOptionsImpl( *rSrc.mxImpl ) )
+{
+}
+
+ScExtDocOptions::~ScExtDocOptions()
+{
+}
+
+ScExtDocOptions& ScExtDocOptions::operator=( const ScExtDocOptions& rSrc )
+{
+ *mxImpl = *rSrc.mxImpl;
+ return *this;
+}
+
+bool ScExtDocOptions::IsChanged() const
+{
+ return mxImpl->mbChanged;
+}
+
+void ScExtDocOptions::SetChanged( bool bChanged )
+{
+ mxImpl->mbChanged = bChanged;
+}
+
+const ScExtDocSettings& ScExtDocOptions::GetDocSettings() const
+{
+ return mxImpl->maDocSett;
+}
+
+ScExtDocSettings& ScExtDocOptions::GetDocSettings()
+{
+ return mxImpl->maDocSett;
+}
+
+const ScExtTabSettings* ScExtDocOptions::GetTabSettings( SCTAB nTab ) const
+{
+ return mxImpl->maTabSett.GetTabSettings( nTab );
+}
+
+SCTAB ScExtDocOptions::GetLastTab() const
+{
+ return mxImpl->maTabSett.GetLastTab();
+}
+
+ScExtTabSettings& ScExtDocOptions::GetOrCreateTabSettings( SCTAB nTab )
+{
+ return mxImpl->maTabSett.GetOrCreateTabSettings( nTab );
+}
+
+SCTAB ScExtDocOptions::GetCodeNameCount() const
+{
+ return static_cast< SCTAB >( mxImpl->maCodeNames.size() );
+}
+
+OUString ScExtDocOptions::GetCodeName( SCTAB nTab ) const
+{
+ OSL_ENSURE( (0 <= nTab) && (nTab < GetCodeNameCount()), "ScExtDocOptions::GetCodeName - invalid sheet index" );
+ return ((0 <= nTab) && (nTab < GetCodeNameCount())) ? mxImpl->maCodeNames[ static_cast< size_t >( nTab ) ] : OUString();
+}
+
+void ScExtDocOptions::SetCodeName( SCTAB nTab, const OUString& rCodeName )
+{
+ OSL_ENSURE( nTab >= 0, "ScExtDocOptions::SetCodeName - invalid sheet index" );
+ if( nTab >= 0 )
+ {
+ size_t nIndex = static_cast< size_t >( nTab );
+ if( nIndex >= mxImpl->maCodeNames.size() )
+ mxImpl->maCodeNames.resize( nIndex + 1 );
+ mxImpl->maCodeNames[ nIndex ] = rCodeName;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/select.cxx b/sc/source/ui/view/select.cxx
new file mode 100644
index 000000000..3dbe74373
--- /dev/null
+++ b/sc/source/ui/view/select.cxx
@@ -0,0 +1,983 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tools/urlobj.hxx>
+#include <sfx2/docfile.hxx>
+#include <osl/diagnose.h>
+
+#include <select.hxx>
+#include <tabvwsh.hxx>
+#include <scmod.hxx>
+#include <document.hxx>
+#include <transobj.hxx>
+#include <docsh.hxx>
+#include <tabprotection.hxx>
+#include <markdata.hxx>
+#include <gridwin.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <comphelper/lok.hxx>
+
+#if defined(_WIN32)
+#define SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN 65
+#endif
+
+using namespace com::sun::star;
+
+static Point aSwitchPos; //! Member
+static bool bDidSwitch = false;
+
+// View (Gridwin / keyboard)
+ScViewFunctionSet::ScViewFunctionSet( ScViewData* pNewViewData ) :
+ pViewData( pNewViewData ),
+ pEngine( nullptr ),
+ bAnchor( false ),
+ bStarted( false )
+{
+ OSL_ENSURE(pViewData, "ViewData==0 at FunctionSet");
+}
+
+ScSplitPos ScViewFunctionSet::GetWhich() const
+{
+ if (pEngine)
+ return pEngine->GetWhich();
+ else
+ return pViewData->GetActivePart();
+}
+
+sal_uLong ScViewFunctionSet::CalcUpdateInterval( const Size& rWinSize, const Point& rEffPos,
+ bool bLeftScroll, bool bTopScroll, bool bRightScroll, bool bBottomScroll )
+{
+ sal_uLong nUpdateInterval = SELENG_AUTOREPEAT_INTERVAL_MAX;
+ vcl::Window* pWin = pEngine->GetWindow();
+ tools::Rectangle aScrRect = pWin->GetDesktopRectPixel();
+ Point aRootPos = pWin->OutputToAbsoluteScreenPixel(Point(0,0));
+ if (bRightScroll)
+ {
+ double nWinRight = rWinSize.getWidth() + aRootPos.getX();
+ double nMarginRight = aScrRect.GetWidth() - nWinRight;
+ double nHOffset = rEffPos.X() - rWinSize.Width();
+ double nHAccelRate = nHOffset / nMarginRight;
+
+ if (nHAccelRate > 1.0)
+ nHAccelRate = 1.0;
+
+ nUpdateInterval = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nHAccelRate));
+ }
+
+ if (bLeftScroll)
+ {
+ double nMarginLeft = aRootPos.getX();
+ double nHOffset = -rEffPos.X();
+ double nHAccelRate = nHOffset / nMarginLeft;
+
+ if (nHAccelRate > 1.0)
+ nHAccelRate = 1.0;
+
+ sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nHAccelRate));
+ if (nUpdateInterval > nTmp)
+ nUpdateInterval = nTmp;
+ }
+
+ if (bBottomScroll)
+ {
+ double nWinBottom = rWinSize.getHeight() + aRootPos.getY();
+ double nMarginBottom = aScrRect.GetHeight() - nWinBottom;
+ double nVOffset = rEffPos.Y() - rWinSize.Height();
+ double nVAccelRate = nVOffset / nMarginBottom;
+
+ if (nVAccelRate > 1.0)
+ nVAccelRate = 1.0;
+
+ sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nVAccelRate));
+ if (nUpdateInterval > nTmp)
+ nUpdateInterval = nTmp;
+ }
+
+ if (bTopScroll)
+ {
+ double nMarginTop = aRootPos.getY();
+ double nVOffset = -rEffPos.Y();
+ double nVAccelRate = nVOffset / nMarginTop;
+
+ if (nVAccelRate > 1.0)
+ nVAccelRate = 1.0;
+
+ sal_uLong nTmp = static_cast<sal_uLong>(SELENG_AUTOREPEAT_INTERVAL_MAX*(1.0 - nVAccelRate));
+ if (nUpdateInterval > nTmp)
+ nUpdateInterval = nTmp;
+ }
+
+#ifdef _WIN32
+ ScTabViewShell* pViewShell = pViewData->GetViewShell();
+ bool bRefMode = pViewShell && pViewShell->IsRefInputMode();
+ if (bRefMode && nUpdateInterval < SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN)
+ // Lower the update interval during ref mode, because re-draw can be
+ // expensive on Windows. Making this interval too small would queue up
+ // the scroll/paint requests which would cause semi-infinite
+ // scrolls even after the mouse cursor is released. We don't have
+ // this problem on Linux.
+ nUpdateInterval = SC_SELENG_REFMODE_UPDATE_INTERVAL_MIN;
+#endif
+ return nUpdateInterval;
+}
+
+void ScViewFunctionSet::SetSelectionEngine( ScViewSelectionEngine* pSelEngine )
+{
+ pEngine = pSelEngine;
+}
+
+// Drag & Drop
+void ScViewFunctionSet::BeginDrag()
+{
+ SCTAB nTab = pViewData->GetTabNo();
+
+ SCCOL nPosX;
+ SCROW nPosY;
+ if (pEngine)
+ {
+ Point aMPos = pEngine->GetMousePosPixel();
+ pViewData->GetPosFromPixel( aMPos.X(), aMPos.Y(), GetWhich(), nPosX, nPosY );
+ }
+ else
+ {
+ nPosX = pViewData->GetCurX();
+ nPosY = pViewData->GetCurY();
+ }
+
+ ScModule* pScMod = SC_MOD();
+ bool bRefMode = pScMod->IsFormulaMode();
+ if (bRefMode)
+ return;
+
+ pViewData->GetView()->FakeButtonUp( GetWhich() ); // ButtonUp is swallowed
+
+ ScMarkData& rMark = pViewData->GetMarkData();
+ rMark.MarkToSimple();
+ if ( !rMark.IsMarked() || rMark.IsMultiMarked() )
+ return;
+
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+ // bApi = TRUE -> no error messages
+ bool bCopied = pViewData->GetView()->CopyToClip( pClipDoc.get(), false, true );
+ if ( !bCopied )
+ return;
+
+ sal_Int8 nDragActions = pViewData->GetView()->SelectionEditable() ?
+ ( DND_ACTION_COPYMOVE | DND_ACTION_LINK ) :
+ ( DND_ACTION_COPY | DND_ACTION_LINK );
+
+ ScDocShell* pDocSh = pViewData->GetDocShell();
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScTransferObj ctor
+
+ rtl::Reference<ScTransferObj> pTransferObj = new ScTransferObj( std::move(pClipDoc), aObjDesc );
+
+ // set position of dragged cell within range
+ ScRange aMarkRange = pTransferObj->GetRange();
+ SCCOL nStartX = aMarkRange.aStart.Col();
+ SCROW nStartY = aMarkRange.aStart.Row();
+ SCCOL nHandleX = (nPosX >= nStartX) ? nPosX - nStartX : 0;
+ SCROW nHandleY = (nPosY >= nStartY) ? nPosY - nStartY : 0;
+ pTransferObj->SetDragHandlePos( nHandleX, nHandleY );
+ pTransferObj->SetSourceCursorPos( pViewData->GetCurX(), pViewData->GetCurY() );
+ pTransferObj->SetVisibleTab( nTab );
+
+ pTransferObj->SetDragSource( pDocSh, rMark );
+
+ vcl::Window* pWindow = pViewData->GetActiveWin();
+ if ( pWindow->IsTracking() )
+ pWindow->EndTracking( TrackingEventFlags::Cancel ); // abort selecting
+
+ if (comphelper::LibreOfficeKit::isActive())
+ pWindow->LocalStartDrag();
+
+ SC_MOD()->SetDragObject( pTransferObj.get(), nullptr ); // for internal D&D
+ pTransferObj->StartDrag( pWindow, nDragActions );
+
+ return; // dragging started
+
+}
+
+// Selection
+void ScViewFunctionSet::CreateAnchor()
+{
+ if (bAnchor) return;
+
+ bool bRefMode = SC_MOD()->IsFormulaMode();
+ if (bRefMode)
+ SetAnchor( pViewData->GetRefStartX(), pViewData->GetRefStartY() );
+ else
+ SetAnchor( pViewData->GetCurX(), pViewData->GetCurY() );
+}
+
+void ScViewFunctionSet::SetAnchor( SCCOL nPosX, SCROW nPosY )
+{
+ bool bRefMode = SC_MOD()->IsFormulaMode();
+ ScTabView* pView = pViewData->GetView();
+ SCTAB nTab = pViewData->GetTabNo();
+
+ if (bRefMode)
+ {
+ pView->DoneRefMode();
+ aAnchorPos.Set( nPosX, nPosY, nTab );
+ pView->InitRefMode( aAnchorPos.Col(), aAnchorPos.Row(), aAnchorPos.Tab(),
+ SC_REFTYPE_REF );
+ bStarted = true;
+ }
+ else if (pViewData->IsAnyFillMode())
+ {
+ aAnchorPos.Set( nPosX, nPosY, nTab );
+ bStarted = true;
+ }
+ else
+ {
+ // don't go there and back again
+ if ( bStarted && pView->IsMarking( nPosX, nPosY, nTab ) )
+ {
+ // don't do anything
+ }
+ else
+ {
+ pView->DoneBlockMode( true );
+ aAnchorPos.Set( nPosX, nPosY, nTab );
+ ScMarkData& rMark = pViewData->GetMarkData();
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ {
+ pView->InitBlockMode( aAnchorPos.Col(), aAnchorPos.Row(),
+ aAnchorPos.Tab(), true );
+ bStarted = true;
+ }
+ else
+ bStarted = false;
+ }
+ }
+ bAnchor = true;
+}
+
+void ScViewFunctionSet::DestroyAnchor()
+{
+ bool bRefMode = SC_MOD()->IsFormulaMode();
+ if (bRefMode)
+ pViewData->GetView()->DoneRefMode( true );
+ else
+ pViewData->GetView()->DoneBlockMode( true );
+
+ bAnchor = false;
+}
+
+void ScViewFunctionSet::SetAnchorFlag( bool bSet )
+{
+ bAnchor = bSet;
+}
+
+void ScViewFunctionSet::SetCursorAtPoint( const Point& rPointPixel, bool /* bDontSelectAtCursor */ )
+{
+ if ( bDidSwitch )
+ {
+ if ( rPointPixel == aSwitchPos )
+ return; // don't scroll in wrong window
+ else
+ bDidSwitch = false;
+ }
+ aSwitchPos = rPointPixel; // only important, if bDidSwitch
+
+ // treat position 0 as -1, so scrolling is always possible
+ // (with full screen and hidden headers, the top left border may be at 0)
+ // (moved from ScViewData::GetPosFromPixel)
+
+ Point aEffPos = rPointPixel;
+ if ( aEffPos.X() == 0 )
+ aEffPos.setX( -1 );
+ if ( aEffPos.Y() == 0 )
+ aEffPos.setY( -1 );
+
+ // Scrolling
+ Size aWinSize = pEngine->GetWindow()->GetOutputSizePixel();
+ bool bLeftScroll = ( aEffPos.X() < 0 );
+ bool bTopScroll = ( aEffPos.Y() < 0 );
+
+ SCCOL nPosX;
+ SCROW nPosY;
+ pViewData->GetPosFromPixel( aEffPos.X(), aEffPos.Y(), GetWhich(),
+ nPosX, nPosY, true, true ); // with Repair
+
+ tools::Rectangle aEditArea = pViewData->GetEditArea(GetWhich(), nPosX, nPosY,
+ pEngine->GetWindow(),
+ nullptr, false);
+
+ bool bFillingSelection = pViewData->IsFillMode() || pViewData->GetFillMode() == ScFillMode::MATRIX;
+ bool bBottomScroll;
+ bool bRightScroll;
+ // for Autofill don't yet assume we want to auto-scroll to the cell under the mouse
+ // because the autofill handle extends into a cells neighbours so initial click is usually
+ // above a neighbour cell
+ if (bFillingSelection)
+ {
+ bBottomScroll = aEffPos.Y() >= aWinSize.Height();
+ bRightScroll = aEffPos.X() >= aWinSize.Width();
+ }
+ else
+ {
+ //in the normal case make the full selected cell visible
+ bBottomScroll = aEditArea.Bottom() >= aWinSize.Height();
+ bRightScroll = aEditArea.Right() >= aWinSize.Width();
+ }
+
+ bool bScroll = bRightScroll || bBottomScroll || bLeftScroll || bTopScroll;
+
+ // for Autofill switch in the center of cell thereby don't prevent scrolling to bottom/right
+ if (bFillingSelection)
+ {
+ bool bLeft, bTop;
+ pViewData->GetMouseQuadrant( aEffPos, GetWhich(), nPosX, nPosY, bLeft, bTop );
+ ScDocument& rDoc = pViewData->GetDocument();
+ SCTAB nTab = pViewData->GetTabNo();
+ if ( bLeft && !bRightScroll )
+ do --nPosX; while ( nPosX>=0 && rDoc.ColHidden( nPosX, nTab ) );
+ if ( bTop && !bBottomScroll )
+ {
+ if (--nPosY >= 0)
+ {
+ nPosY = rDoc.LastVisibleRow(0, nPosY, nTab);
+ if (!rDoc.ValidRow(nPosY))
+ nPosY = -1;
+ }
+ }
+ // negative value is allowed
+ }
+
+ // moved out of fix limit?
+ ScSplitPos eWhich = GetWhich();
+ if ( eWhich == pViewData->GetActivePart() )
+ {
+ if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX )
+ if ( aEffPos.X() >= aWinSize.Width() )
+ {
+ if ( eWhich == SC_SPLIT_TOPLEFT )
+ {
+ pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT );
+ bScroll = false;
+ bDidSwitch = true;
+ }
+ else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
+ {
+ pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
+ bScroll = false;
+ bDidSwitch = true;
+ }
+ }
+
+ if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX )
+ if ( aEffPos.Y() >= aWinSize.Height() )
+ {
+ if ( eWhich == SC_SPLIT_TOPLEFT )
+ {
+ pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT );
+ bScroll = false;
+ bDidSwitch = true;
+ }
+ else if ( eWhich == SC_SPLIT_TOPRIGHT )
+ {
+ pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
+ bScroll = false;
+ bDidSwitch = true;
+ }
+ }
+ }
+
+ if (bScroll)
+ {
+ // Adjust update interval based on how far the mouse pointer is from the edge.
+ sal_uLong nUpdateInterval = CalcUpdateInterval(
+ aWinSize, aEffPos, bLeftScroll, bTopScroll, bRightScroll, bBottomScroll);
+ pEngine->SetUpdateInterval(nUpdateInterval);
+ }
+ else
+ {
+ // Don't forget to reset the interval when not scrolling!
+ pEngine->SetUpdateInterval(SELENG_AUTOREPEAT_INTERVAL);
+ }
+
+ pViewData->ResetOldCursor();
+ SetCursorAtCell( nPosX, nPosY, bScroll );
+}
+
+bool ScViewFunctionSet::CheckRefBounds(SCCOL nPosX, SCROW nPosY)
+{
+ SCCOL startX = pViewData->GetRefStartX();
+ SCROW startY = pViewData->GetRefStartY();
+
+ SCCOL endX = pViewData->GetRefEndX();
+ SCROW endY = pViewData->GetRefEndY();
+
+ return nPosX >= startX && nPosX <= endX && nPosY >= startY && nPosY <= endY;
+}
+
+bool ScViewFunctionSet::SetCursorAtCell( SCCOL nPosX, SCROW nPosY, bool bScroll )
+{
+ ScTabView* pView = pViewData->GetView();
+ SCTAB nTab = pViewData->GetTabNo();
+ ScDocument& rDoc = pViewData->GetDocument();
+
+ if ( rDoc.IsTabProtected(nTab) )
+ {
+ if (nPosX < 0 || nPosY < 0)
+ return false;
+
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ if (!pProtect)
+ return false;
+
+ bool bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
+ bool bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
+
+ if ( bSkipProtected && bSkipUnprotected )
+ return false;
+
+ bool bCellProtected = rDoc.HasAttrib(nPosX, nPosY, nTab, nPosX, nPosY, nTab, HasAttrFlags::Protected);
+ if ( (bCellProtected && bSkipProtected) || (!bCellProtected && bSkipUnprotected) )
+ // Don't select this cell!
+ return false;
+ }
+
+ ScModule* pScMod = SC_MOD();
+ ScTabViewShell* pViewShell = pViewData->GetViewShell();
+ bool bRefMode = pViewShell && pViewShell->IsRefInputMode();
+
+ bool bHide = !bRefMode && !pViewData->IsAnyFillMode() &&
+ ( nPosX != pViewData->GetCurX() || nPosY != pViewData->GetCurY() );
+
+ if (bHide)
+ pView->HideAllCursors();
+
+ if (bScroll)
+ {
+ if (bRefMode)
+ {
+ ScSplitPos eWhich = GetWhich();
+ pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE, &eWhich );
+ }
+ else
+ pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE );
+ }
+
+ if (bRefMode)
+ {
+ // if no input is possible from this doc, don't move the reference cursor around
+ if ( !pScMod->IsModalMode(pViewData->GetSfxDocShell()) && (!CheckRefBounds(nPosX, nPosY) || SfxLokHelper::getDeviceFormFactor() != LOKDeviceFormFactor::MOBILE))
+ {
+ if (!bAnchor)
+ {
+ pView->DoneRefMode( true );
+ pView->InitRefMode( nPosX, nPosY, pViewData->GetTabNo(), SC_REFTYPE_REF );
+ }
+
+ if(SfxLokHelper::getDeviceFormFactor() != LOKDeviceFormFactor::MOBILE)
+ pView->UpdateRef( nPosX, nPosY, pViewData->GetTabNo() );
+
+ pView->SelectionChanged();
+ }
+ }
+ else if (pViewData->IsFillMode() ||
+ (pViewData->GetFillMode() == ScFillMode::MATRIX && (nScFillModeMouseModifier & KEY_MOD1) ))
+ {
+ // If a matrix got touched, switch back to Autofill is possible with Ctrl
+
+ SCCOL nStartX, nEndX;
+ SCROW nStartY, nEndY; // Block
+ SCTAB nDummy;
+ pViewData->GetSimpleArea( nStartX, nStartY, nDummy, nEndX, nEndY, nDummy );
+
+ if (pViewData->GetRefType() != SC_REFTYPE_FILL)
+ {
+ pView->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
+ CreateAnchor();
+ }
+
+ ScRange aDelRange;
+ bool bOldDelMark = pViewData->GetDelMark( aDelRange );
+
+ if ( nPosX+1 >= nStartX && nPosX <= nEndX &&
+ nPosY+1 >= nStartY && nPosY <= nEndY &&
+ ( nPosX != nEndX || nPosY != nEndY ) ) // minimize?
+ {
+ // direction (left or top)
+
+ tools::Long nSizeX = 0;
+ for (SCCOL i=nPosX+1; i<=nEndX; i++)
+ nSizeX += rDoc.GetColWidth( i, nTab );
+ tools::Long nSizeY = rDoc.GetRowHeight( nPosY+1, nEndY, nTab );
+
+ SCCOL nDelStartX = nStartX;
+ SCROW nDelStartY = nStartY;
+ if ( nSizeX > nSizeY )
+ nDelStartX = nPosX + 1;
+ else
+ nDelStartY = nPosY + 1;
+ // there is no need to check for zero, because nPosX/Y is also negative
+
+ if ( nDelStartX < nStartX )
+ nDelStartX = nStartX;
+ if ( nDelStartY < nStartY )
+ nDelStartY = nStartY;
+
+ // set range
+
+ pViewData->SetDelMark( ScRange( nDelStartX,nDelStartY,nTab,
+ nEndX,nEndY,nTab ) );
+ pViewData->GetView()->UpdateShrinkOverlay();
+
+ pViewData->GetView()->
+ PaintArea( nStartX,nDelStartY, nEndX,nEndY, ScUpdateMode::Marks );
+
+ nPosX = nEndX; // keep red border around range
+ nPosY = nEndY;
+
+ // reference the right way up, if it's upside down below
+ if ( nStartX != pViewData->GetRefStartX() || nStartY != pViewData->GetRefStartY() )
+ {
+ pViewData->GetView()->DoneRefMode();
+ pViewData->GetView()->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
+ }
+ }
+ else
+ {
+ if ( bOldDelMark )
+ {
+ pViewData->ResetDelMark();
+ pViewData->GetView()->UpdateShrinkOverlay();
+ }
+
+ bool bNegX = ( nPosX < nStartX );
+ bool bNegY = ( nPosY < nStartY );
+
+ tools::Long nSizeX = 0;
+ if ( bNegX )
+ {
+ // in SetCursorAtPoint hidden columns are skipped.
+ // They must be skipped here too, or the result will always be the first hidden column.
+ do ++nPosX; while ( nPosX<nStartX && rDoc.ColHidden(nPosX, nTab) );
+ for (SCCOL i=nPosX; i<nStartX; i++)
+ nSizeX += rDoc.GetColWidth( i, nTab );
+ }
+ else
+ for (SCCOL i=nEndX+1; i<=nPosX; i++)
+ nSizeX += rDoc.GetColWidth( i, nTab );
+
+ tools::Long nSizeY = 0;
+ if ( bNegY )
+ {
+ // in SetCursorAtPoint hidden rows are skipped.
+ // They must be skipped here too, or the result will always be the first hidden row.
+ if (++nPosY < nStartY)
+ {
+ nPosY = rDoc.FirstVisibleRow(nPosY, nStartY-1, nTab);
+ if (!rDoc.ValidRow(nPosY))
+ nPosY = nStartY;
+ }
+ nSizeY += rDoc.GetRowHeight( nPosY, nStartY-1, nTab );
+ }
+ else
+ nSizeY += rDoc.GetRowHeight( nEndY+1, nPosY, nTab );
+
+ if ( nSizeX > nSizeY ) // Fill only ever in one direction
+ {
+ nPosY = nEndY;
+ bNegY = false;
+ }
+ else
+ {
+ nPosX = nEndX;
+ bNegX = false;
+ }
+
+ SCCOL nRefStX = bNegX ? nEndX : nStartX;
+ SCROW nRefStY = bNegY ? nEndY : nStartY;
+ if ( nRefStX != pViewData->GetRefStartX() || nRefStY != pViewData->GetRefStartY() )
+ {
+ pViewData->GetView()->DoneRefMode();
+ pViewData->GetView()->InitRefMode( nRefStX, nRefStY, nTab, SC_REFTYPE_FILL );
+ }
+ }
+
+ pView->UpdateRef( nPosX, nPosY, nTab );
+ }
+ else if (pViewData->IsAnyFillMode())
+ {
+ ScFillMode nMode = pViewData->GetFillMode();
+ if ( nMode == ScFillMode::EMBED_LT || nMode == ScFillMode::EMBED_RB )
+ {
+ OSL_ENSURE( rDoc.IsEmbedded(), "!rDoc.IsEmbedded()" );
+ ScRange aRange;
+ rDoc.GetEmbedded( aRange);
+ ScRefType eRefMode = (nMode == ScFillMode::EMBED_LT) ? SC_REFTYPE_EMBED_LT : SC_REFTYPE_EMBED_RB;
+ if (pViewData->GetRefType() != eRefMode)
+ {
+ if ( nMode == ScFillMode::EMBED_LT )
+ pView->InitRefMode( aRange.aEnd.Col(), aRange.aEnd.Row(), nTab, eRefMode );
+ else
+ pView->InitRefMode( aRange.aStart.Col(), aRange.aStart.Row(), nTab, eRefMode );
+ CreateAnchor();
+ }
+
+ pView->UpdateRef( nPosX, nPosY, nTab );
+ }
+ else if ( nMode == ScFillMode::MATRIX )
+ {
+ SCCOL nStartX, nEndX;
+ SCROW nStartY, nEndY; // Block
+ SCTAB nDummy;
+ pViewData->GetSimpleArea( nStartX, nStartY, nDummy, nEndX, nEndY, nDummy );
+
+ if (pViewData->GetRefType() != SC_REFTYPE_FILL)
+ {
+ pView->InitRefMode( nStartX, nStartY, nTab, SC_REFTYPE_FILL );
+ CreateAnchor();
+ }
+
+ if ( nPosX < nStartX ) nPosX = nStartX;
+ if ( nPosY < nStartY ) nPosY = nStartY;
+
+ pView->UpdateRef( nPosX, nPosY, nTab );
+ }
+ // else new modes
+ }
+ else // regular selection
+ {
+ bool bHideCur = bAnchor && ( nPosX != pViewData->GetCurX() ||
+ nPosY != pViewData->GetCurY() );
+ if (bHideCur)
+ pView->HideAllCursors(); // otherwise twice: Block and SetCursor
+
+ if (bAnchor)
+ {
+ if (!bStarted)
+ {
+ bool bMove = ( nPosX != aAnchorPos.Col() ||
+ nPosY != aAnchorPos.Row() );
+ if ( bMove || ( pEngine && pEngine->GetMouseEvent().IsShift() ) )
+ {
+ pView->InitBlockMode( aAnchorPos.Col(), aAnchorPos.Row(),
+ aAnchorPos.Tab(), true );
+ bStarted = true;
+ }
+ }
+ if (bStarted)
+ // If the selection is already started, don't set the cursor.
+ pView->MarkCursor( nPosX, nPosY, nTab, false, false, true );
+ else
+ pView->SetCursor( nPosX, nPosY );
+ }
+ else
+ {
+ ScMarkData& rMark = pViewData->GetMarkData();
+ if (rMark.IsMarked() || rMark.IsMultiMarked())
+ {
+ pView->DoneBlockMode(true);
+ pView->InitBlockMode( nPosX, nPosY, nTab, true );
+ pView->MarkCursor( nPosX, nPosY, nTab );
+
+ aAnchorPos.Set( nPosX, nPosY, nTab );
+ bStarted = true;
+ }
+ // #i3875# *Hack* When a new cell is Ctrl-clicked with no pre-selected cells,
+ // it highlights that new cell as well as the old cell where the cursor is
+ // positioned prior to the click. A selection mode via Shift-F8 should also
+ // follow the same behavior.
+ else if ( pViewData->IsSelCtrlMouseClick() )
+ {
+ SCCOL nOldX = pViewData->GetCurX();
+ SCROW nOldY = pViewData->GetCurY();
+
+ pView->InitBlockMode( nOldX, nOldY, nTab, true );
+ pView->MarkCursor( nOldX, nOldY, nTab );
+
+ if ( nOldX != nPosX || nOldY != nPosY )
+ {
+ pView->DoneBlockMode( true );
+ pView->InitBlockMode( nPosX, nPosY, nTab, true );
+ pView->MarkCursor( nPosX, nPosY, nTab );
+ aAnchorPos.Set( nPosX, nPosY, nTab );
+ }
+
+ bStarted = true;
+ }
+ pView->SetCursor( nPosX, nPosY );
+ }
+
+ pViewData->SetRefStart( nPosX, nPosY, nTab );
+ if (bHideCur)
+ pView->ShowAllCursors();
+ }
+
+ if (bHide)
+ pView->ShowAllCursors();
+
+ return true;
+}
+
+bool ScViewFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
+{
+ bool bRefMode = SC_MOD()->IsFormulaMode();
+ if (bRefMode)
+ return false;
+
+ if (pViewData->IsAnyFillMode())
+ return false;
+
+ ScMarkData& rMark = pViewData->GetMarkData();
+ if (bAnchor || !rMark.IsMultiMarked())
+ {
+ SCCOL nPosX;
+ SCROW nPosY;
+ pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), GetWhich(), nPosX, nPosY );
+ return pViewData->GetMarkData().IsCellMarked( nPosX, nPosY );
+ }
+
+ return false;
+}
+
+void ScViewFunctionSet::DeselectAtPoint( const Point& /* rPointPixel */ )
+{
+ // doesn't exist
+}
+
+void ScViewFunctionSet::DeselectAll()
+{
+ if (pViewData->IsAnyFillMode())
+ return;
+
+ bool bRefMode = SC_MOD()->IsFormulaMode();
+ if (bRefMode)
+ {
+ pViewData->GetView()->DoneRefMode();
+ }
+ else
+ {
+ pViewData->GetView()->DoneBlockMode();
+ pViewData->GetViewShell()->UpdateInputHandler();
+ }
+
+ bAnchor = false;
+}
+
+ScViewSelectionEngine::ScViewSelectionEngine( vcl::Window* pWindow, ScTabView* pView,
+ ScSplitPos eSplitPos ) :
+ SelectionEngine( pWindow, &pView->GetFunctionSet() ),
+ eWhich( eSplitPos )
+{
+ SetSelectionMode( SelectionMode::Multiple );
+ EnableDrag( true );
+}
+
+// column and row headers
+ScHeaderFunctionSet::ScHeaderFunctionSet( ScViewData* pNewViewData ) :
+ pViewData( pNewViewData ),
+ bColumn( false ),
+ eWhich( SC_SPLIT_TOPLEFT ),
+ bAnchor( false ),
+ nCursorPos( 0 )
+{
+ OSL_ENSURE(pViewData, "ViewData==0 at FunctionSet");
+}
+
+void ScHeaderFunctionSet::SetColumn( bool bSet )
+{
+ bColumn = bSet;
+}
+
+void ScHeaderFunctionSet::SetWhich( ScSplitPos eNew )
+{
+ eWhich = eNew;
+}
+
+void ScHeaderFunctionSet::BeginDrag()
+{
+ // doesn't exist
+}
+
+void ScHeaderFunctionSet::CreateAnchor()
+{
+ if (bAnchor)
+ return;
+
+ ScTabView* pView = pViewData->GetView();
+ pView->DoneBlockMode( true );
+ if (bColumn)
+ {
+ pView->InitBlockMode( static_cast<SCCOL>(nCursorPos), 0, pViewData->GetTabNo(), true, true );
+ pView->MarkCursor( static_cast<SCCOL>(nCursorPos), pViewData->MaxRow(), pViewData->GetTabNo() );
+ }
+ else
+ {
+ pView->InitBlockMode( 0, nCursorPos, pViewData->GetTabNo(), true, false, true );
+ pView->MarkCursor( pViewData->MaxCol(), nCursorPos, pViewData->GetTabNo() );
+ }
+ bAnchor = true;
+}
+
+void ScHeaderFunctionSet::DestroyAnchor()
+{
+ pViewData->GetView()->DoneBlockMode( true );
+ bAnchor = false;
+}
+
+void ScHeaderFunctionSet::SetCursorAtPoint( const Point& rPointPixel, bool /* bDontSelectAtCursor */ )
+{
+ if ( bDidSwitch )
+ {
+ // next valid position has to be originated from another window
+ if ( rPointPixel == aSwitchPos )
+ return; // don't scroll in the wrong window
+ else
+ bDidSwitch = false;
+ }
+
+ // Scrolling
+ Size aWinSize = pViewData->GetActiveWin()->GetOutputSizePixel();
+ bool bScroll;
+ if (bColumn)
+ bScroll = ( rPointPixel.X() < 0 || rPointPixel.X() >= aWinSize.Width() );
+ else
+ bScroll = ( rPointPixel.Y() < 0 || rPointPixel.Y() >= aWinSize.Height() );
+
+ // moved out of fix limit?
+ bool bSwitched = false;
+ if ( bColumn )
+ {
+ if ( pViewData->GetHSplitMode() == SC_SPLIT_FIX )
+ {
+ if ( rPointPixel.X() > aWinSize.Width() )
+ {
+ if ( eWhich == SC_SPLIT_TOPLEFT )
+ {
+ pViewData->GetView()->ActivatePart( SC_SPLIT_TOPRIGHT );
+ bSwitched = true;
+ }
+ else if ( eWhich == SC_SPLIT_BOTTOMLEFT )
+ {
+ pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
+ bSwitched = true;
+ }
+ }
+ }
+ }
+ else // column headers
+ {
+ if ( pViewData->GetVSplitMode() == SC_SPLIT_FIX )
+ {
+ if ( rPointPixel.Y() > aWinSize.Height() )
+ {
+ if ( eWhich == SC_SPLIT_TOPLEFT )
+ {
+ pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMLEFT );
+ bSwitched = true;
+ }
+ else if ( eWhich == SC_SPLIT_TOPRIGHT )
+ {
+ pViewData->GetView()->ActivatePart( SC_SPLIT_BOTTOMRIGHT );
+ bSwitched = true;
+ }
+ }
+ }
+ }
+ if (bSwitched)
+ {
+ aSwitchPos = rPointPixel;
+ bDidSwitch = true;
+ return; // do not crunch with wrong positions
+ }
+
+ SCCOL nPosX;
+ SCROW nPosY;
+ pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), pViewData->GetActivePart(),
+ nPosX, nPosY, false );
+ if (bColumn)
+ {
+ nCursorPos = static_cast<SCCOLROW>(nPosX);
+ nPosY = pViewData->GetPosY(WhichV(pViewData->GetActivePart()));
+ }
+ else
+ {
+ nCursorPos = static_cast<SCCOLROW>(nPosY);
+ nPosX = pViewData->GetPosX(WhichH(pViewData->GetActivePart()));
+ }
+
+ ScTabView* pView = pViewData->GetView();
+ bool bHide = pViewData->GetCurX() != nPosX ||
+ pViewData->GetCurY() != nPosY;
+ if (bHide)
+ pView->HideAllCursors();
+
+ if (bScroll)
+ pView->AlignToCursor( nPosX, nPosY, SC_FOLLOW_LINE );
+ pView->SetCursor( nPosX, nPosY );
+
+ if ( !bAnchor || !pView->IsBlockMode() )
+ {
+ pView->DoneBlockMode( true );
+ pViewData->GetMarkData().MarkToMulti(); //! who changes this?
+ pView->InitBlockMode( nPosX, nPosY, pViewData->GetTabNo(), true, bColumn, !bColumn );
+
+ bAnchor = true;
+ }
+
+ pView->MarkCursor( nPosX, nPosY, pViewData->GetTabNo(), bColumn, !bColumn );
+
+ // SelectionChanged inside of HideCursor because of UpdateAutoFillMark
+ pView->SelectionChanged();
+
+ if (bHide)
+ pView->ShowAllCursors();
+}
+
+bool ScHeaderFunctionSet::IsSelectionAtPoint( const Point& rPointPixel )
+{
+ SCCOL nPosX;
+ SCROW nPosY;
+ pViewData->GetPosFromPixel( rPointPixel.X(), rPointPixel.Y(), pViewData->GetActivePart(),
+ nPosX, nPosY, false );
+
+ ScMarkData& rMark = pViewData->GetMarkData();
+ if (bColumn)
+ return rMark.IsColumnMarked( nPosX );
+ else
+ return rMark.IsRowMarked( nPosY );
+}
+
+void ScHeaderFunctionSet::DeselectAtPoint( const Point& /* rPointPixel */ )
+{
+}
+
+void ScHeaderFunctionSet::DeselectAll()
+{
+ pViewData->GetView()->DoneBlockMode();
+ bAnchor = false;
+}
+
+ScHeaderSelectionEngine::ScHeaderSelectionEngine( vcl::Window* pWindow, ScHeaderFunctionSet* pFuncSet ) :
+ SelectionEngine( pWindow, pFuncSet )
+{
+ SetSelectionMode( SelectionMode::Multiple );
+ EnableDrag( false );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/selectionstate.cxx b/sc/source/ui/view/selectionstate.cxx
new file mode 100644
index 000000000..91c6a278c
--- /dev/null
+++ b/sc/source/ui/view/selectionstate.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 <selectionstate.hxx>
+
+#include <editeng/editview.hxx>
+#include <viewdata.hxx>
+#include <markdata.hxx>
+
+ScSelectionState::ScSelectionState( ScViewData& rViewData ) :
+ meType( SC_SELECTTYPE_NONE )
+{
+ maCursor.SetTab( rViewData.GetTabNo() );
+ ScSplitPos eWhich = rViewData.GetActivePart();
+
+ if( rViewData.HasEditView( eWhich ) )
+ {
+ meType = SC_SELECTTYPE_EDITCELL;
+ maCursor.SetCol( rViewData.GetEditViewCol() );
+ maCursor.SetRow( rViewData.GetEditViewRow() );
+ maEditSel = rViewData.GetEditView( eWhich )->GetSelection();
+ }
+ else
+ {
+ maCursor.SetCol( rViewData.GetCurX() );
+ maCursor.SetRow( rViewData.GetCurY() );
+
+ ScMarkData& rMarkData = rViewData.GetMarkData();
+ rMarkData.MarkToMulti();
+ if( rMarkData.IsMultiMarked() )
+ {
+ meType = SC_SELECTTYPE_SHEET;
+ }
+ // else type is SC_SELECTTYPE_NONE - already initialized
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/spellcheckcontext.cxx b/sc/source/ui/view/spellcheckcontext.cxx
new file mode 100644
index 000000000..1d39fe512
--- /dev/null
+++ b/sc/source/ui/view/spellcheckcontext.cxx
@@ -0,0 +1,387 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <spellcheckcontext.hxx>
+#include <svl/sharedstring.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/unolingu.hxx>
+
+#include <scitems.hxx>
+#include <document.hxx>
+#include <cellvalue.hxx>
+#include <editutil.hxx>
+#include <dpobject.hxx>
+
+#include <com/sun/star/linguistic2/XSpellChecker1.hpp>
+
+#include <o3tl/hash_combine.hxx>
+
+#include <unordered_map>
+
+using namespace css;
+
+using sc::SpellCheckContext;
+
+class SpellCheckContext::SpellCheckCache
+{
+ struct CellPos
+ {
+ struct Hash
+ {
+ size_t operator() (const CellPos& rPos) const
+ {
+ std::size_t seed = 0;
+ o3tl::hash_combine(seed, rPos.mnCol);
+ o3tl::hash_combine(seed, rPos.mnRow);
+ return seed;
+ }
+ };
+
+ SCCOL mnCol;
+ SCROW mnRow;
+
+ CellPos(SCCOL nCol, SCROW nRow) : mnCol(nCol), mnRow(nRow) {}
+
+ bool operator== (const CellPos& r) const
+ {
+ return mnCol == r.mnCol && mnRow == r.mnRow;
+ }
+
+ };
+
+ typedef std::vector<editeng::MisspellRanges> MisspellType;
+ typedef std::unordered_map<CellPos, std::unique_ptr<MisspellType>, CellPos::Hash> CellMapType;
+ typedef std::unordered_map<const rtl_uString*, std::unique_ptr<MisspellType>> SharedStringMapType;
+ typedef std::unordered_map<CellPos, LanguageType, CellPos::Hash> CellLangMapType;
+
+ SharedStringMapType maStringMisspells;
+ CellMapType maEditTextMisspells;
+ CellLangMapType maCellLanguages;
+ LanguageType meDefCellLanguage;
+
+public:
+
+ SpellCheckCache(LanguageType eDefaultCellLanguage) : meDefCellLanguage(eDefaultCellLanguage)
+ {
+ }
+
+ bool query(SCCOL nCol, SCROW nRow, const ScRefCellValue& rCell, MisspellType*& rpRanges) const
+ {
+ CellType eType = rCell.meType;
+ if (eType == CELLTYPE_STRING)
+ {
+ SharedStringMapType::const_iterator it = maStringMisspells.find(rCell.mpString->getData());
+ if (it == maStringMisspells.end())
+ return false; // Not available
+
+ rpRanges = it->second.get();
+ return true;
+ }
+
+ if (eType == CELLTYPE_EDIT)
+ {
+ CellMapType::const_iterator it = maEditTextMisspells.find(CellPos(nCol, nRow));
+ if (it == maEditTextMisspells.end())
+ return false; // Not available
+
+ rpRanges = it->second.get();
+ return true;
+ }
+
+ rpRanges = nullptr;
+ return true;
+ }
+
+ void set(SCCOL nCol, SCROW nRow, const ScRefCellValue& rCell, std::unique_ptr<MisspellType> pRanges)
+ {
+ CellType eType = rCell.meType;
+ if (eType == CELLTYPE_STRING)
+ maStringMisspells.insert_or_assign(rCell.mpString->getData(), std::move(pRanges));
+ else if (eType == CELLTYPE_EDIT)
+ maEditTextMisspells.insert_or_assign(CellPos(nCol, nRow), std::move(pRanges));
+ }
+
+ LanguageType getLanguage(SCCOL nCol, SCROW nRow) const
+ {
+ CellLangMapType::const_iterator it = maCellLanguages.find(CellPos(nCol, nRow));
+ if (it == maCellLanguages.end())
+ return meDefCellLanguage;
+
+ return it->second;
+ }
+
+ void setLanguage(LanguageType eCellLang, SCCOL nCol, SCROW nRow)
+ {
+ if (eCellLang == meDefCellLanguage)
+ maCellLanguages.erase(CellPos(nCol, nRow));
+ else
+ maCellLanguages.insert_or_assign(CellPos(nCol, nRow), eCellLang);
+ }
+
+ void clear(LanguageType eDefaultCellLanguage)
+ {
+ maStringMisspells.clear();
+ maEditTextMisspells.clear();
+ maCellLanguages.clear();
+ meDefCellLanguage = eDefaultCellLanguage;
+ }
+
+ void clearEditTextMap()
+ {
+ maEditTextMisspells.clear();
+ }
+};
+
+struct SpellCheckContext::SpellCheckStatus
+{
+ bool mbModified;
+
+ SpellCheckStatus() : mbModified(false) {};
+
+ DECL_LINK( EventHdl, EditStatus&, void );
+};
+
+IMPL_LINK(SpellCheckContext::SpellCheckStatus, EventHdl, EditStatus&, rStatus, void)
+{
+ EditStatusFlags nStatus = rStatus.GetStatusWord();
+ if (nStatus & EditStatusFlags::WRONGWORDCHANGED)
+ mbModified = true;
+}
+
+struct SpellCheckContext::SpellCheckResult
+{
+ SCCOL mnCol;
+ SCROW mnRow;
+ const std::vector<editeng::MisspellRanges>* pRanges;
+
+ SpellCheckResult() : mnCol(-1), mnRow(-1), pRanges(nullptr) {}
+
+ void set(SCCOL nCol, SCROW nRow, const std::vector<editeng::MisspellRanges>* pMisspells)
+ {
+ mnCol = nCol;
+ mnRow = nRow;
+ pRanges = pMisspells;
+ }
+
+ const std::vector<editeng::MisspellRanges>* query(SCCOL nCol, SCROW nRow) const
+ {
+ assert(mnCol == nCol);
+ assert(mnRow == nRow);
+ (void)nCol;
+ (void)nRow;
+ return pRanges;
+ }
+
+ void clear()
+ {
+ mnCol = -1;
+ mnRow = -1;
+ pRanges = nullptr;
+ }
+};
+
+SpellCheckContext::SpellCheckContext(ScDocument* pDocument, SCTAB nTab) :
+ pDoc(pDocument),
+ mnTab(nTab),
+ meLanguage(ScGlobal::GetEditDefaultLanguage())
+{
+ // defer init of engine and cache till the first query/set
+}
+
+SpellCheckContext::~SpellCheckContext()
+{
+}
+
+void SpellCheckContext::dispose()
+{
+ mpEngine.reset();
+ mpCache.reset();
+ pDoc = nullptr;
+}
+
+void SpellCheckContext::setTabNo(SCTAB nTab)
+{
+ if (mnTab == nTab)
+ return;
+ mnTab = nTab;
+ reset();
+}
+
+bool SpellCheckContext::isMisspelled(SCCOL nCol, SCROW nRow) const
+{
+ const_cast<SpellCheckContext*>(this)->ensureResults(nCol, nRow);
+ return mpResult->query(nCol, nRow);
+}
+
+const std::vector<editeng::MisspellRanges>* SpellCheckContext::getMisspellRanges(
+ SCCOL nCol, SCROW nRow ) const
+{
+ const_cast<SpellCheckContext*>(this)->ensureResults(nCol, nRow);
+ return mpResult->query(nCol, nRow);
+}
+
+void SpellCheckContext::setMisspellRanges(
+ SCCOL nCol, SCROW nRow, const std::vector<editeng::MisspellRanges>* pRanges )
+{
+ if (!mpEngine || !mpCache)
+ reset();
+
+ ScRefCellValue aCell(*pDoc, ScAddress(nCol, nRow, mnTab));
+ CellType eType = aCell.meType;
+
+ if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
+ return;
+
+ typedef std::vector<editeng::MisspellRanges> MisspellType;
+ std::unique_ptr<MisspellType> pMisspells(pRanges ? new MisspellType(*pRanges) : nullptr);
+ mpCache->set(nCol, nRow, aCell, std::move(pMisspells));
+}
+
+void SpellCheckContext::reset()
+{
+ meLanguage = ScGlobal::GetEditDefaultLanguage();
+ resetCache();
+ mpEngine.reset();
+ mpStatus.reset();
+}
+
+void SpellCheckContext::resetForContentChange()
+{
+ resetCache(true /* bContentChangeOnly */);
+}
+
+void SpellCheckContext::ensureResults(SCCOL nCol, SCROW nRow)
+{
+ if (!mpEngine || !mpCache ||
+ ScGlobal::GetEditDefaultLanguage() != meLanguage)
+ {
+ reset();
+ setup();
+ }
+
+ // perhaps compute the pivot rangelist once in some pivot-table change handler ?
+ if (pDoc->HasPivotTable())
+ {
+ if (ScDPCollection* pDPs = pDoc->GetDPCollection())
+ {
+ ScRangeList aPivotRanges = pDPs->GetAllTableRanges(mnTab);
+ if (aPivotRanges.Contains(ScAddress(nCol, nRow, mnTab))) // Don't spell check within pivot tables
+ {
+ mpResult->set(nCol, nRow, nullptr);
+ return;
+ }
+ }
+ }
+
+ ScRefCellValue aCell(*pDoc, ScAddress(nCol, nRow, mnTab));
+ CellType eType = aCell.meType;
+
+ if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
+ {
+ // No spell-check required.
+ mpResult->set(nCol, nRow, nullptr);
+ return;
+ }
+
+
+ // Cell content is either shared-string or EditTextObject
+
+ // For spell-checking, we currently only use the primary
+ // language; not CJK nor CTL.
+ const ScPatternAttr* pPattern = pDoc->GetPattern(nCol, nRow, mnTab);
+ LanguageType eCellLang = pPattern->GetItem(ATTR_FONT_LANGUAGE).GetValue();
+
+ if (eCellLang == LANGUAGE_SYSTEM)
+ eCellLang = meLanguage; // never use SYSTEM for spelling
+
+ if (eCellLang == LANGUAGE_NONE)
+ {
+ mpResult->set(nCol, nRow, nullptr); // No need to spell check this cell.
+ return;
+ }
+
+ typedef std::vector<editeng::MisspellRanges> MisspellType;
+
+ LanguageType eCachedCellLang = mpCache->getLanguage(nCol, nRow);
+
+ if (eCellLang != eCachedCellLang)
+ mpCache->setLanguage(eCellLang, nCol, nRow);
+
+ else
+ {
+ MisspellType* pRanges = nullptr;
+ bool bFound = mpCache->query(nCol, nRow, aCell, pRanges);
+ if (bFound)
+ {
+ // Cache hit.
+ mpResult->set(nCol, nRow, pRanges);
+ return;
+ }
+ }
+
+ // Cache miss, the cell needs spell-check..
+ if (eType == CELLTYPE_STRING)
+ mpEngine->SetText(aCell.mpString->getString());
+ else
+ mpEngine->SetText(*aCell.mpEditText);
+
+ // it has to happen after we set text
+ mpEngine->SetDefaultItem(SvxLanguageItem(eCellLang, EE_CHAR_LANGUAGE));
+
+ mpStatus->mbModified = false;
+ mpEngine->CompleteOnlineSpelling();
+ std::unique_ptr<MisspellType> pRanges;
+ if (mpStatus->mbModified)
+ {
+ pRanges.reset(new MisspellType);
+ mpEngine->GetAllMisspellRanges(*pRanges);
+
+ if (pRanges->empty())
+ pRanges.reset(nullptr);
+ }
+ // else : No change in status for EditStatusFlags::WRONGWORDCHANGED => no spell errors (which is the default status).
+
+ mpResult->set(nCol, nRow, pRanges.get());
+ mpCache->set(nCol, nRow, aCell, std::move(pRanges));
+}
+
+void SpellCheckContext::resetCache(bool bContentChangeOnly)
+{
+ if (!mpResult)
+ mpResult.reset(new SpellCheckResult());
+ else
+ mpResult->clear();
+
+ if (!mpCache)
+ mpCache.reset(new SpellCheckCache(meLanguage));
+ else if (bContentChangeOnly)
+ mpCache->clearEditTextMap();
+ else
+ mpCache->clear(meLanguage);
+}
+
+void SpellCheckContext::setup()
+{
+ mpEngine.reset(new ScTabEditEngine(pDoc));
+ mpStatus.reset(new SpellCheckStatus());
+
+ mpEngine->SetControlWord(
+ mpEngine->GetControlWord() | (EEControlBits::ONLINESPELLING | EEControlBits::ALLOWBIGOBJS));
+ mpEngine->SetStatusEventHdl(LINK(mpStatus.get(), SpellCheckStatus, EventHdl));
+ // Delimiters here like in inputhdl.cxx !!!
+ mpEngine->SetWordDelimiters(
+ ScEditUtil::ModifyDelimiters(mpEngine->GetWordDelimiters()));
+
+ uno::Reference<linguistic2::XSpellChecker1> xXSpellChecker1(LinguMgr::GetSpellChecker());
+ mpEngine->SetSpeller(xXSpellChecker1);
+ mpEngine->SetDefaultLanguage(meLanguage);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/spelldialog.cxx b/sc/source/ui/view/spelldialog.cxx
new file mode 100644
index 000000000..da1e90698
--- /dev/null
+++ b/sc/source/ui/view/spelldialog.cxx
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <spelldialog.hxx>
+
+#include <sfx2/bindings.hxx>
+#include <svx/svxids.hrc>
+#include <editeng/editstat.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/unolingu.hxx>
+#include <selectionstate.hxx>
+#include <osl/diagnose.h>
+
+#include <spelleng.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <scmod.hxx>
+#include <editable.hxx>
+#include <undoblk.hxx>
+#include <gridwin.hxx>
+#include <refupdatecontext.hxx>
+#include <vcl/svapp.hxx>
+
+SFX_IMPL_CHILDWINDOW_WITHID( ScSpellDialogChildWindow, SID_SPELL_DIALOG )
+
+ScSpellDialogChildWindow::ScSpellDialogChildWindow( vcl::Window* pParentP, sal_uInt16 nId,
+ SfxBindings* pBindings, SAL_UNUSED_PARAMETER SfxChildWinInfo* /*pInfo*/ ) :
+ svx::SpellDialogChildWindow( pParentP, nId, pBindings ),
+ mpViewShell( nullptr ),
+ mpViewData( nullptr ),
+ mpDocShell( nullptr ),
+ mpDoc( nullptr ),
+ mbNeedNextObj( false ),
+ mbOldIdleEnabled(true)
+{
+ Init();
+}
+
+ScSpellDialogChildWindow::~ScSpellDialogChildWindow()
+{
+ Reset();
+}
+
+SfxChildWinInfo ScSpellDialogChildWindow::GetInfo() const
+{
+ return svx::SpellDialogChildWindow::GetInfo();
+}
+
+void ScSpellDialogChildWindow::InvalidateSpellDialog()
+{
+ svx::SpellDialogChildWindow::InvalidateSpellDialog();
+}
+
+// protected ------------------------------------------------------------------
+
+svx::SpellPortions ScSpellDialogChildWindow::GetNextWrongSentence( bool /*bRecheck*/ )
+{
+ svx::SpellPortions aPortions;
+ if( mxEngine && mpViewData )
+ {
+ if( EditView* pEditView = mpViewData->GetSpellingView() )
+ {
+ // edit engine handles cell iteration internally
+ do
+ {
+ if( mbNeedNextObj )
+ mxEngine->SpellNextDocument();
+ mbNeedNextObj = !mxEngine->IsFinished() && !mxEngine->SpellSentence( *pEditView, aPortions );
+ }
+ while( mbNeedNextObj );
+ }
+ }
+ return aPortions;
+}
+
+void ScSpellDialogChildWindow::ApplyChangedSentence( const svx::SpellPortions& rChanged, bool bRecheck )
+{
+ if( mxEngine && mpViewData )
+ if( EditView* pEditView = mpViewData->GetSpellingView() )
+ {
+ mxEngine->ApplyChangedSentence( *pEditView, rChanged, bRecheck );
+
+ // Reset the spell checking results to clear the markers.
+ mpViewData->GetActiveWin()->ResetAutoSpell();
+ }
+}
+
+void ScSpellDialogChildWindow::GetFocus()
+{
+ SolarMutexGuard aGuard;
+
+ if( IsSelectionChanged() )
+ {
+ Reset();
+ InvalidateSpellDialog();
+ Init();
+ }
+}
+
+void ScSpellDialogChildWindow::LoseFocus()
+{
+}
+
+// private --------------------------------------------------------------------
+
+void ScSpellDialogChildWindow::Reset()
+{
+ if( mpViewShell && (mpViewShell == dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() )) )
+ {
+ if( mxEngine && mxEngine->IsAnyModified() )
+ {
+ const ScAddress& rCursor = mxOldSel->GetCellCursor();
+ SCTAB nTab = rCursor.Tab();
+ SCCOL nOldCol = rCursor.Col();
+ SCROW nOldRow = rCursor.Row();
+ SCCOL nNewCol = mpViewData->GetCurX();
+ SCROW nNewRow = mpViewData->GetCurY();
+ mpDocShell->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoConversion>(
+ mpDocShell, mpViewData->GetMarkData(),
+ nOldCol, nOldRow, nTab, std::move(mxUndoDoc),
+ nNewCol, nNewRow, nTab, std::move(mxRedoDoc),
+ ScConversionParam( SC_CONVERSION_SPELLCHECK ) ) );
+
+ sc::SetFormulaDirtyContext aCxt;
+ mpDoc->SetAllFormulasDirty(aCxt);
+
+ mpDocShell->SetDocumentModified();
+ }
+
+ mpViewData->SetSpellingView( nullptr );
+ mpViewShell->KillEditView( true );
+ mpDocShell->PostPaintGridAll();
+ mpViewShell->UpdateInputHandler();
+ mpDoc->EnableIdle(mbOldIdleEnabled);
+ }
+ mxEngine.reset();
+ mxUndoDoc.reset();
+ mxRedoDoc.reset();
+ mxOldSel.reset();
+ mxOldRangeList.clear();
+ mpViewShell = nullptr;
+ mpViewData = nullptr;
+ mpDocShell = nullptr;
+ mpDoc = nullptr;
+ mbNeedNextObj = false;
+ mbOldIdleEnabled = true;
+}
+
+void ScSpellDialogChildWindow::Init()
+{
+ if( mpViewShell )
+ return;
+ if( (mpViewShell = dynamic_cast<ScTabViewShell*>( SfxViewShell::Current() )) == nullptr )
+ return;
+
+ mpViewData = &mpViewShell->GetViewData();
+
+ // exit edit mode - TODO support spelling in edit mode
+ if( mpViewData->HasEditView( mpViewData->GetActivePart() ) )
+ SC_MOD()->InputEnterHandler();
+
+ mxOldSel.reset( new ScSelectionState( *mpViewData ) );
+
+ mpDocShell = mpViewData->GetDocShell();
+ mpDoc = &mpDocShell->GetDocument();
+
+ const ScAddress& rCursor = mxOldSel->GetCellCursor();
+ SCCOL nCol = rCursor.Col();
+ SCROW nRow = rCursor.Row();
+ SCTAB nTab = rCursor.Tab();
+
+ ScMarkData& rMarkData = mpViewData->GetMarkData();
+
+ mxOldRangeList = new ScRangeList;
+ rMarkData.FillRangeListWithMarks(mxOldRangeList.get(), true);
+
+ rMarkData.MarkToMulti();
+
+ switch( mxOldSel->GetSelectionType() )
+ {
+ case SC_SELECTTYPE_NONE:
+ case SC_SELECTTYPE_SHEET:
+ {
+ // test if there is something editable
+ ScEditableTester aTester( *mpDoc, rMarkData );
+ if( !aTester.IsEditable() )
+ {
+ // #i85751# Don't show an ErrorMessage here, because the vcl
+ // parent of the InfoBox is not fully initialized yet.
+ // This leads to problems in the modality behaviour of the
+ // ScSpellDialogChildWindow.
+
+ //mpViewShell->ErrorMessage( aTester.GetMessageId() );
+ return;
+ }
+ }
+ break;
+
+ // edit mode exited, see TODO above
+// case SC_SELECTTYPE_EDITCELL:
+// break;
+
+ default:
+ OSL_FAIL( "ScSpellDialogChildWindow::Init - unknown selection type" );
+ }
+
+ mbOldIdleEnabled = mpDoc->IsIdleEnabled();
+ mpDoc->EnableIdle(false); // stop online spelling
+
+ // *** create Undo/Redo documents *** -------------------------------------
+
+ mxUndoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
+ mxUndoDoc->InitUndo( *mpDoc, nTab, nTab );
+ mxRedoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
+ mxRedoDoc->InitUndo( *mpDoc, nTab, nTab );
+
+ if ( rMarkData.GetSelectCount() > 1 )
+ {
+ for (const auto& rTab : rMarkData)
+ {
+ if( rTab != nTab )
+ {
+ mxUndoDoc->AddUndoTab( rTab, rTab );
+ mxRedoDoc->AddUndoTab( rTab, rTab );
+ }
+ }
+ }
+
+ // *** create and init the edit engine *** --------------------------------
+
+ mxEngine.reset( new ScSpellingEngine(
+ mpDoc->GetEnginePool(), *mpViewData, mxUndoDoc.get(), mxRedoDoc.get(), LinguMgr::GetSpellChecker() ) );
+ mxEngine->SetRefDevice( mpViewData->GetActiveWin()->GetOutDev() );
+
+ mpViewShell->MakeEditView( mxEngine.get(), nCol, nRow );
+ EditView* pEditView = mpViewData->GetEditView( mpViewData->GetActivePart() );
+ mpViewData->SetSpellingView( pEditView );
+ tools::Rectangle aRect( Point( 0, 0 ), Point( 0, 0 ) );
+ pEditView->SetOutputArea( aRect );
+ mxEngine->SetControlWord( EEControlBits::USECHARATTRIBS );
+ mxEngine->EnableUndo( false );
+ mxEngine->SetPaperSize( aRect.GetSize() );
+ mxEngine->SetTextCurrentDefaults( OUString() );
+ mxEngine->ClearModifyFlag();
+
+ mbNeedNextObj = true;
+}
+
+bool ScSpellDialogChildWindow::IsSelectionChanged()
+{
+ if (!mxOldRangeList || !mpViewShell
+ || (mpViewShell != dynamic_cast<ScTabViewShell*>(SfxViewShell::Current())))
+ return true;
+
+ if( EditView* pEditView = mpViewData->GetSpellingView() )
+ if( pEditView->GetEditEngine() != mxEngine.get() )
+ return true;
+
+ ScRangeList aCurrentRangeList;
+ mpViewData->GetMarkData().FillRangeListWithMarks(&aCurrentRangeList, true);
+
+ return (*mxOldRangeList != aCurrentRangeList);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/spelleng.cxx b/sc/source/ui/view/spelleng.cxx
new file mode 100644
index 000000000..cb3c4f4ad
--- /dev/null
+++ b/sc/source/ui/view/spelleng.cxx
@@ -0,0 +1,447 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <spelleng.hxx>
+#include <com/sun/star/i18n/TextConversionOption.hpp>
+
+#include <scitems.hxx>
+
+#include <editeng/langitem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/eeitem.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/settings.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <osl/diagnose.h>
+
+#include <spelldialog.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <cellvalue.hxx>
+#include <cellform.hxx>
+#include <patattr.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <markdata.hxx>
+#include <docpool.hxx>
+
+#include <memory>
+
+using namespace ::com::sun::star;
+
+ScConversionEngineBase::ScConversionEngineBase(
+ SfxItemPool* pEnginePoolP, ScViewData& rViewData,
+ ScDocument* pUndoDoc, ScDocument* pRedoDoc ) :
+ ScEditEngineDefaulter( pEnginePoolP ),
+ mrViewData( rViewData ),
+ mrDocShell( *rViewData.GetDocShell() ),
+ mrDoc( rViewData.GetDocShell()->GetDocument() ),
+ maSelState( rViewData ),
+ mpUndoDoc( pUndoDoc ),
+ mpRedoDoc( pRedoDoc ),
+ meCurrLang( LANGUAGE_ENGLISH_US ),
+ mbIsAnyModified( false ),
+ mbInitialState( true ),
+ mbWrappedInTable( false ),
+ mbFinished( false )
+{
+ maSelState.GetCellCursor().GetVars( mnStartCol, mnStartRow, mnStartTab );
+ // start with cell A1 in cell/range/multi-selection, will seek to first selected
+ if( maSelState.GetSelectionType() == SC_SELECTTYPE_SHEET )
+ {
+ mnStartCol = 0;
+ mnStartRow = 0;
+ }
+ mnCurrCol = mnStartCol;
+ mnCurrRow = mnStartRow;
+}
+
+ScConversionEngineBase::~ScConversionEngineBase()
+{
+}
+
+bool ScConversionEngineBase::FindNextConversionCell()
+{
+ ScMarkData& rMark = mrViewData.GetMarkData();
+ ScTabViewShell* pViewShell = mrViewData.GetViewShell();
+ const ScPatternAttr* pPattern = nullptr;
+ const ScPatternAttr* pLastPattern = nullptr;
+
+ SfxItemSet aEditDefaults(GetEmptyItemSet());
+
+ if( IsModified() )
+ {
+ mbIsAnyModified = true;
+
+ OUString aNewStr = GetText();
+
+ // Check if the user has changed the language. If the new language is
+ // applied to the entire string length, we will set the language as cell
+ // attribute. Otherwise we will commit this as an edit-engine string.
+ editeng::LanguageSpan aLang = GetLanguage(0, 0);
+
+ bool bSimpleString = GetParagraphCount() == 1 &&
+ aLang.nLang != LANGUAGE_DONTKNOW &&
+ aLang.nStart == 0 &&
+ aLang.nEnd == aNewStr.getLength();
+
+ bool bMultiTab = (rMark.GetSelectCount() > 1);
+
+ OUString aVisibleStr;
+ if( bMultiTab )
+ aVisibleStr = mrDoc.GetString(mnCurrCol, mnCurrRow, mnStartTab);
+
+ for( SCTAB nTab = 0, nTabCount = mrDoc.GetTableCount(); nTab < nTabCount; ++nTab )
+ {
+ // always change the cell on the visible tab,
+ // on the other selected tabs only if they contain the same text
+
+ if ((nTab == mnStartTab) ||
+ (bMultiTab && rMark.GetTableSelect(nTab) && mrDoc.GetString(mnCurrCol, mnCurrRow, nTab) == aVisibleStr))
+ {
+ ScAddress aPos( mnCurrCol, mnCurrRow, nTab );
+ CellType eCellType = mrDoc.GetCellType( aPos );
+ bool bEmptyCell = eCellType == CELLTYPE_NONE;
+
+ if (mpUndoDoc && !bEmptyCell)
+ mrDoc.CopyCellToDocument(aPos, aPos, *mpUndoDoc);
+
+ if (!bSimpleString || eCellType == CELLTYPE_EDIT)
+ {
+ std::unique_ptr<EditTextObject> pEditObj(CreateTextObject());
+ mrDoc.SetEditText(aPos, *pEditObj, GetEditTextObjectPool());
+ }
+ else
+ {
+ // Set the new string and update the language with the cell.
+ mrDoc.SetString(aPos, aNewStr);
+
+ const ScPatternAttr* pAttr = mrDoc.GetPattern(aPos);
+ std::unique_ptr<ScPatternAttr> pNewAttr;
+
+ if (pAttr)
+ pNewAttr = std::make_unique<ScPatternAttr>(*pAttr);
+ else
+ pNewAttr = std::make_unique<ScPatternAttr>(mrDoc.GetPool());
+
+ pNewAttr->GetItemSet().Put(SvxLanguageItem(aLang.nLang, EE_CHAR_LANGUAGE), ATTR_FONT_LANGUAGE);
+ mrDoc.SetPattern(aPos, std::move(pNewAttr));
+ }
+
+ if (mpRedoDoc && !bEmptyCell)
+ mrDoc.CopyCellToDocument(aPos, aPos, *mpRedoDoc);
+
+ mrDocShell.PostPaintCell(aPos);
+ }
+ }
+ }
+
+ SCCOL nNewCol = mnCurrCol;
+ SCROW nNewRow = mnCurrRow;
+
+ if( mbInitialState )
+ {
+ /* On very first call, decrement row to let GetNextSpellingCell() find
+ the first cell of current range. */
+ mbInitialState = false;
+ --nNewRow;
+ }
+
+ bool bSheetSel = maSelState.GetSelectionType() == SC_SELECTTYPE_SHEET;
+ bool bLoop = true;
+ bool bFound = false;
+ while( bLoop && !bFound )
+ {
+ bLoop = mrDoc.GetNextSpellingCell( nNewCol, nNewRow, mnStartTab, bSheetSel, rMark );
+ if( bLoop )
+ {
+ FillFromCell( mnCurrCol, mnCurrRow, mnStartTab );
+
+ if( mbWrappedInTable && ((nNewCol > mnStartCol) || ((nNewCol == mnStartCol) && (nNewRow >= mnStartRow))) )
+ {
+ ShowFinishDialog();
+ bLoop = false;
+ mbFinished = true;
+ }
+ else if( nNewCol >= mrDoc.GetAllocatedColumnsCount(mnStartTab) )
+ {
+ // no more cells in the sheet - try to restart at top of sheet
+
+ if( bSheetSel || ((mnStartCol == 0) && (mnStartRow == 0)) )
+ {
+ // conversion started at cell A1 or in selection, do not query to restart at top
+ ShowFinishDialog();
+ bLoop = false;
+ mbFinished = true;
+ }
+ else if( ShowTableWrapDialog() )
+ {
+ // conversion started anywhere but in cell A1, user wants to restart
+ nNewRow = mrDoc.MaxRow() + 2;
+ mbWrappedInTable = true;
+ }
+ else
+ {
+ bLoop = false;
+ mbFinished = true;
+ }
+ }
+ else
+ {
+ // GetPattern may implicitly allocates the column if not exists,
+ pPattern = mrDoc.GetPattern( nNewCol, nNewRow, mnStartTab );
+ if( pPattern && (pPattern != pLastPattern) )
+ {
+ pPattern->FillEditItemSet( &aEditDefaults );
+ SetDefaults( aEditDefaults );
+ pLastPattern = pPattern;
+ }
+
+ // language changed?
+ const SfxPoolItem* pItem = mrDoc.GetAttr( nNewCol, nNewRow, mnStartTab, ATTR_FONT_LANGUAGE );
+ if( const SvxLanguageItem* pLangItem = dynamic_cast<const SvxLanguageItem*>( pItem ) )
+ {
+ LanguageType eLang = pLangItem->GetValue();
+ if( eLang == LANGUAGE_SYSTEM )
+ eLang = Application::GetSettings().GetLanguageTag().getLanguageType(); // never use SYSTEM for spelling
+ if( eLang != meCurrLang )
+ {
+ meCurrLang = eLang;
+ SetDefaultLanguage( eLang );
+ }
+ }
+
+ FillFromCell( nNewCol, nNewRow, mnStartTab );
+
+ bFound = bLoop && NeedsConversion();
+ }
+ }
+ }
+
+ if( bFound )
+ {
+ pViewShell->AlignToCursor( nNewCol, nNewRow, SC_FOLLOW_JUMP );
+ pViewShell->SetCursor( nNewCol, nNewRow, true );
+ mrViewData.GetView()->MakeEditView( this, nNewCol, nNewRow );
+ EditView* pEditView = mrViewData.GetSpellingView();
+ // maSelState.GetEditSelection() returns (0,0) if not in edit mode -> ok
+ pEditView->SetSelection( maSelState.GetEditSelection() );
+
+ ClearModifyFlag();
+ mnCurrCol = nNewCol;
+ mnCurrRow = nNewRow;
+ }
+
+ return bFound;
+}
+
+void ScConversionEngineBase::RestoreCursorPos()
+{
+ const ScAddress& rPos = maSelState.GetCellCursor();
+ mrViewData.GetViewShell()->SetCursor( rPos.Col(), rPos.Row() );
+}
+
+bool ScConversionEngineBase::ShowTableWrapDialog()
+{
+ // default: no dialog, always restart at top
+ return true;
+}
+
+void ScConversionEngineBase::ShowFinishDialog()
+{
+ // default: no dialog
+}
+
+// private --------------------------------------------------------------------
+
+void ScConversionEngineBase::FillFromCell( SCCOL nCol, SCROW nRow, SCTAB nTab )
+{
+ ScAddress aPos(nCol, nRow, nTab);
+
+ ScRefCellValue aCell(mrDoc, aPos);
+ switch (aCell.meType)
+ {
+ case CELLTYPE_STRING:
+ {
+ SvNumberFormatter* pFormatter = mrDoc.GetFormatTable();
+ sal_uInt32 nNumFmt = mrDoc.GetNumberFormat(aPos);
+ const Color* pColor;
+ OUString aText = ScCellFormat::GetString(aCell, nNumFmt, &pColor, *pFormatter, mrDoc);
+
+ SetTextCurrentDefaults(aText);
+ }
+ break;
+ case CELLTYPE_EDIT:
+ {
+ const EditTextObject* pNewEditObj = aCell.mpEditText;
+ SetTextCurrentDefaults(*pNewEditObj);
+ }
+ break;
+ default:
+ SetTextCurrentDefaults(OUString());
+ }
+}
+
+ScSpellingEngine::ScSpellingEngine(
+ SfxItemPool* pEnginePoolP, ScViewData& rViewData,
+ ScDocument* pUndoDoc, ScDocument* pRedoDoc,
+ css::uno::Reference< css::linguistic2::XSpellChecker1 > const & xSpeller ) :
+ ScConversionEngineBase( pEnginePoolP, rViewData, pUndoDoc, pRedoDoc )
+{
+ SetSpeller( xSpeller );
+}
+
+void ScSpellingEngine::ConvertAll(weld::Widget* pDialogParent, EditView& rEditView)
+{
+ EESpellState eState = EESpellState::Ok;
+ if( FindNextConversionCell() )
+ eState = rEditView.StartSpeller(pDialogParent, true);
+
+ OSL_ENSURE( eState != EESpellState::NoSpeller, "ScSpellingEngine::Convert - no spell checker" );
+}
+
+bool ScSpellingEngine::SpellNextDocument()
+{
+ return FindNextConversionCell();
+}
+
+bool ScSpellingEngine::NeedsConversion()
+{
+ return HasSpellErrors() != EESpellState::Ok;
+}
+
+bool ScSpellingEngine::ShowTableWrapDialog()
+{
+ weld::Widget* pParent = GetDialogParent();
+ weld::WaitObject aWaitOff(pParent);
+
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_SPELLING_BEGIN_TAB))); // "delete data?"
+ xBox->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0));
+ xBox->set_default_response(RET_YES);
+ return xBox->run() == RET_YES;
+}
+
+void ScSpellingEngine::ShowFinishDialog()
+{
+ weld::Widget* pParent = GetDialogParent();
+ weld::WaitObject aWaitOff(pParent);
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(pParent,
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(STR_SPELLING_STOP_OK)));
+ xInfoBox->run();
+}
+
+weld::Widget* ScSpellingEngine::GetDialogParent()
+{
+ sal_uInt16 nWinId = ScSpellDialogChildWindow::GetChildWindowId();
+ SfxViewFrame* pViewFrm = mrViewData.GetViewShell()->GetViewFrame();
+ if( pViewFrm->HasChildWindow( nWinId ) )
+ {
+ if( SfxChildWindow* pChild = pViewFrm->GetChildWindow( nWinId ) )
+ {
+ auto xController = pChild->GetController();
+ if (xController)
+ {
+ if (weld::Window *pRet = xController->getDialog())
+ {
+ if (pRet->get_visible())
+ return pRet;
+ }
+ }
+ }
+ }
+
+ // fall back to standard dialog parent
+ return ScDocShell::GetActiveDialogParent();
+}
+
+ScConversionParam::ScConversionParam( ScConversionType eConvType ) :
+ meConvType( eConvType ),
+ meSourceLang( LANGUAGE_NONE ),
+ meTargetLang( LANGUAGE_NONE ),
+ mnOptions( 0 ),
+ mbUseTargetFont( false ),
+ mbIsInteractive( false )
+{
+}
+
+ScConversionParam::ScConversionParam( ScConversionType eConvType,
+ LanguageType eLang, sal_Int32 nOptions, bool bIsInteractive ) :
+ meConvType( eConvType ),
+ meSourceLang( eLang ),
+ meTargetLang( eLang ),
+ mnOptions( nOptions ),
+ mbUseTargetFont( false ),
+ mbIsInteractive( bIsInteractive )
+{
+ if (LANGUAGE_KOREAN == eLang)
+ mnOptions = i18n::TextConversionOption::CHARACTER_BY_CHARACTER;
+}
+
+ScConversionParam::ScConversionParam( ScConversionType eConvType,
+ LanguageType eSourceLang, LanguageType eTargetLang, const vcl::Font& rTargetFont,
+ sal_Int32 nOptions, bool bIsInteractive ) :
+ meConvType( eConvType ),
+ meSourceLang( eSourceLang ),
+ meTargetLang( eTargetLang ),
+ maTargetFont( rTargetFont ),
+ mnOptions( nOptions ),
+ mbUseTargetFont( true ),
+ mbIsInteractive( bIsInteractive )
+{
+ if (LANGUAGE_KOREAN == meSourceLang && LANGUAGE_KOREAN == meTargetLang)
+ mnOptions = i18n::TextConversionOption::CHARACTER_BY_CHARACTER;
+}
+
+ScTextConversionEngine::ScTextConversionEngine(
+ SfxItemPool* pEnginePoolP, ScViewData& rViewData,
+ const ScConversionParam& rConvParam,
+ ScDocument* pUndoDoc, ScDocument* pRedoDoc ) :
+ ScConversionEngineBase( pEnginePoolP, rViewData, pUndoDoc, pRedoDoc ),
+ maConvParam( rConvParam )
+{
+}
+
+void ScTextConversionEngine::ConvertAll(weld::Widget* pDialogParent, EditView& rEditView)
+{
+ if( FindNextConversionCell() )
+ {
+ rEditView.StartTextConversion(pDialogParent,
+ maConvParam.GetSourceLang(), maConvParam.GetTargetLang(), maConvParam.GetTargetFont(),
+ maConvParam.GetOptions(), maConvParam.IsInteractive(), true );
+ // #i34769# restore initial cursor position
+ RestoreCursorPos();
+ }
+}
+
+bool ScTextConversionEngine::ConvertNextDocument()
+{
+ return FindNextConversionCell();
+}
+
+bool ScTextConversionEngine::NeedsConversion()
+{
+ return HasConvertibleTextPortion( maConvParam.GetSourceLang() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabcont.cxx b/sc/source/ui/view/tabcont.cxx
new file mode 100644
index 000000000..a15b1c20e
--- /dev/null
+++ b/sc/source/ui/view/tabcont.cxx
@@ -0,0 +1,669 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <osl/diagnose.h>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfile.hxx>
+#include <tools/urlobj.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weldutils.hxx>
+#include <tabcont.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <scmod.hxx>
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <transobj.hxx>
+#include <clipparam.hxx>
+#include <dragdata.hxx>
+#include <markdata.hxx>
+#include <gridwin.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+
+ScTabControl::ScTabControl( vcl::Window* pParent, ScViewData* pData )
+ : TabBar(pParent, WB_3DLOOK | WB_MINSCROLL | WB_SCROLL | WB_RANGESELECT | WB_MULTISELECT | WB_DRAG)
+ , DropTargetHelper(this)
+ , DragSourceHelper(this)
+ , pViewData(pData)
+ , nMouseClickPageId(TabBar::PAGE_NOT_FOUND)
+ , nSelPageIdByMouse(TabBar::PAGE_NOT_FOUND)
+ , bErrorShown(false)
+{
+ ScDocument& rDoc = pViewData->GetDocument();
+
+ OUString aString;
+ Color aTabBgColor;
+ SCTAB nCount = rDoc.GetTableCount();
+ for (SCTAB i=0; i<nCount; i++)
+ {
+ if (rDoc.IsVisible(i))
+ {
+ if (rDoc.GetName(i,aString))
+ {
+ if ( rDoc.IsScenario(i) )
+ InsertPage( static_cast<sal_uInt16>(i)+1, aString, TabBarPageBits::Blue);
+ else
+ InsertPage( static_cast<sal_uInt16>(i)+1, aString );
+
+ if ( rDoc.IsTabProtected(i) )
+ SetProtectionSymbol(static_cast<sal_uInt16>(i)+1, true);
+
+ if ( !rDoc.IsDefaultTabBgColor(i) )
+ {
+ aTabBgColor = rDoc.GetTabBgColor(i);
+ SetTabBgColor( static_cast<sal_uInt16>(i)+1, aTabBgColor );
+ }
+ }
+ }
+ }
+
+ SetCurPageId( static_cast<sal_uInt16>(pViewData->GetTabNo()) + 1 );
+
+ SetSizePixel( Size(SC_TABBAR_DEFWIDTH, 0) );
+
+ SetSplitHdl( LINK( pViewData->GetView(), ScTabView, TabBarResize ) );
+
+ EnableEditMode();
+ UpdateInputContext();
+
+ SetScrollAlwaysEnabled(false);
+
+ SetScrollAreaContextHdl( LINK( this, ScTabControl, ShowPageList ) );
+}
+
+IMPL_LINK(ScTabControl, ShowPageList, const CommandEvent &, rEvent, void)
+{
+ tools::Rectangle aRect(rEvent.GetMousePosPixel(), Size(1, 1));
+ weld::Window* pPopupParent = weld::GetPopupParent(*this, aRect);
+ std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(pPopupParent, "modules/scalc/ui/pagelistmenu.ui"));
+ std::unique_ptr<weld::Menu> xPopup(xBuilder->weld_menu("menu"));
+
+ sal_uInt16 nCurPageId = GetCurPageId();
+
+ ScDocument& rDoc = pViewData->GetDocument();
+ SCTAB nCount = rDoc.GetTableCount();
+ for (SCTAB i=0; i<nCount; ++i)
+ {
+ if (!rDoc.IsVisible(i))
+ continue;
+ OUString aString;
+ if (!rDoc.GetName(i, aString))
+ continue;
+ sal_uInt16 nId = static_cast<sal_uInt16>(i)+1;
+ OUString sId = OUString::number(nId);
+ xPopup->append_radio(sId, aString);
+ if (nId == nCurPageId)
+ xPopup->set_active(sId.toUtf8(), true);
+ }
+
+ OString sIdent(xPopup->popup_at_rect(pPopupParent, aRect));
+ if (!sIdent.isEmpty())
+ SwitchToPageId(sIdent.toUInt32());
+}
+
+ScTabControl::~ScTabControl()
+{
+ disposeOnce();
+}
+
+void ScTabControl::dispose()
+{
+ DragSourceHelper::dispose();
+ DropTargetHelper::dispose();
+ TabBar::dispose();
+}
+
+sal_uInt16 ScTabControl::GetMaxId() const
+{
+ sal_uInt16 nVisCnt = GetPageCount();
+ if (nVisCnt)
+ return GetPageId(nVisCnt-1);
+
+ return 0;
+}
+
+SCTAB ScTabControl::GetPrivatDropPos(const Point& rPos )
+{
+ sal_uInt16 nPos = ShowDropPos(rPos);
+
+ SCTAB nRealPos = static_cast<SCTAB>(nPos);
+
+ if(nPos !=0 )
+ {
+ ScDocument& rDoc = pViewData->GetDocument();
+
+ SCTAB nCount = rDoc.GetTableCount();
+
+ sal_uInt16 nViewPos=0;
+ nRealPos = nCount;
+ for (SCTAB i=0; i<nCount; i++)
+ {
+ if (rDoc.IsVisible(i))
+ {
+ nViewPos++;
+ if(nViewPos==nPos)
+ {
+ SCTAB j;
+ for (j=i+1; j<nCount; j++)
+ {
+ if (rDoc.IsVisible(j))
+ {
+ break;
+ }
+ }
+ nRealPos =j;
+ break;
+ }
+ }
+ }
+ }
+ return nRealPos ;
+}
+
+void ScTabControl::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ ScModule* pScMod = SC_MOD();
+ if ( !pScMod->IsModalMode() && !pScMod->IsFormulaMode() && !IsInEditMode() )
+ {
+ // activate View
+ pViewData->GetViewShell()->SetActive(); // Appear and SetViewFrame
+ pViewData->GetView()->ActiveGrabFocus();
+ }
+
+ if (rMEvt.IsLeft() && rMEvt.GetModifier() == 0)
+ nMouseClickPageId = GetPageId(rMEvt.GetPosPixel());
+
+ TabBar::MouseButtonDown( rMEvt );
+}
+
+void ScTabControl::MouseButtonUp( const MouseEvent& rMEvt )
+{
+ Point aPos = PixelToLogic( rMEvt.GetPosPixel() );
+
+ // mouse button down and up on same page?
+ if( nMouseClickPageId != GetPageId(aPos))
+ nMouseClickPageId = TabBar::PAGE_NOT_FOUND;
+
+ if ( rMEvt.GetClicks() == 2 && rMEvt.IsLeft() && nMouseClickPageId != 0 && nMouseClickPageId != TabBar::PAGE_NOT_FOUND )
+ {
+ SfxDispatcher* pDispatcher = pViewData->GetViewShell()->GetViewFrame()->GetDispatcher();
+ pDispatcher->Execute( FID_TAB_MENU_RENAME, SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
+ return;
+ }
+
+ if( nMouseClickPageId == 0 )
+ {
+ // Click in the area next to the existing tabs:
+ // #i70320# if several sheets are selected, deselect all except the current sheet,
+ // otherwise add new sheet
+ sal_uInt16 nSlot = ( GetSelectPageCount() > 1 ) ? FID_TAB_DESELECTALL : FID_INS_TABLE;
+ SfxDispatcher* pDispatcher = pViewData->GetViewShell()->GetViewFrame()->GetDispatcher();
+ pDispatcher->Execute( nSlot, SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
+ // forget page ID, to be really sure that the dialog is not called twice
+ nMouseClickPageId = TabBar::PAGE_NOT_FOUND;
+ }
+
+ TabBar::MouseButtonUp( rMEvt );
+}
+
+void ScTabControl::AddTabClick()
+{
+ TabBar::AddTabClick();
+
+ // Insert a new sheet at the right end, with default name.
+ ScDocument& rDoc = pViewData->GetDocument();
+ ScModule* pScMod = SC_MOD();
+ if (!rDoc.IsDocEditable() || pScMod->IsTableLocked())
+ return;
+
+ // auto-accept any in-process input - which would otherwise end up on the new sheet
+ if (!pScMod->IsFormulaMode())
+ pScMod->InputEnterHandler();
+
+ OUString aName;
+ rDoc.CreateValidTabName(aName);
+ SCTAB nTabCount = rDoc.GetTableCount();
+ pViewData->GetViewShell()->InsertTable(aName, nTabCount);
+}
+
+void ScTabControl::Select()
+{
+ /* Remember last clicked page ID. */
+ nSelPageIdByMouse = nMouseClickPageId;
+ /* Reset nMouseClickPageId, so that next Select() call may invalidate
+ nSelPageIdByMouse (i.e. if called from keyboard). */
+ nMouseClickPageId = TabBar::PAGE_NOT_FOUND;
+
+ ScModule* pScMod = SC_MOD();
+ ScDocument& rDoc = pViewData->GetDocument();
+ ScMarkData& rMark = pViewData->GetMarkData();
+ SCTAB nCount = rDoc.GetTableCount();
+ SCTAB i;
+
+ if ( pScMod->IsTableLocked() ) // may not be switched now ?
+ {
+ // restore the old state of TabControls
+
+ for (i=0; i<nCount; i++)
+ SelectPage( static_cast<sal_uInt16>(i)+1, rMark.GetTableSelect(i) );
+ SetCurPageId( static_cast<sal_uInt16>(pViewData->GetTabNo()) + 1 );
+
+ return;
+ }
+
+ sal_uInt16 nCurId = GetCurPageId();
+ if (!nCurId) return; // for Excel import it can happen that everything is hidden
+ sal_uInt16 nPage = nCurId - 1;
+
+ // OLE-inplace deactivate
+ if ( nPage != static_cast<sal_uInt16>(pViewData->GetTabNo()) )
+ pViewData->GetView()->DrawMarkListHasChanged();
+
+ // InputEnterHandler onlw when not reference input
+
+ bool bRefMode = pScMod->IsFormulaMode();
+ if (!bRefMode)
+ pScMod->InputEnterHandler();
+
+ for (i=0; i<nCount; i++)
+ rMark.SelectTable( i, IsPageSelected(static_cast<sal_uInt16>(i)+1) );
+
+ SfxDispatcher& rDisp = pViewData->GetDispatcher();
+ if (rDisp.IsLocked())
+ pViewData->GetView()->SetTabNo( static_cast<SCTAB>(nPage) );
+ else
+ {
+ // sheet for basic is 1-based
+ SfxUInt16Item aItem( SID_CURRENTTAB, nPage + 1 );
+ rDisp.ExecuteList(SID_CURRENTTAB,
+ SfxCallMode::SLOT | SfxCallMode::RECORD, { &aItem });
+ }
+
+ SfxBindings& rBind = pViewData->GetBindings();
+ rBind.Invalidate( FID_FILL_TAB );
+ rBind.Invalidate( FID_TAB_DESELECTALL );
+
+ rBind.Invalidate( FID_INS_TABLE );
+ rBind.Invalidate( FID_TAB_APPEND );
+ rBind.Invalidate( FID_TAB_MOVE );
+ rBind.Invalidate( FID_TAB_DUPLICATE );
+ rBind.Invalidate( FID_TAB_RENAME );
+ rBind.Invalidate( FID_DELETE_TABLE );
+ rBind.Invalidate( FID_TABLE_SHOW );
+ rBind.Invalidate( FID_TABLE_HIDE );
+ rBind.Invalidate( FID_TAB_SET_TAB_BG_COLOR );
+
+ // Recalculate status bar functions.
+ rBind.Invalidate( SID_TABLE_CELL );
+
+ // SetReference onlw when the consolidate dialog is open
+ // (for references over multiple sheets)
+ // for others this is only needed fidgeting
+
+ if ( bRefMode && pViewData->GetRefType() == SC_REFTYPE_REF )
+ if ( pViewData->GetViewShell()->GetViewFrame()->HasChildWindow(SID_OPENDLG_CONSOLIDATE) )
+ {
+ ScRange aRange(
+ pViewData->GetRefStartX(), pViewData->GetRefStartY(), pViewData->GetRefStartZ(),
+ pViewData->GetRefEndX(), pViewData->GetRefEndY(), pViewData->GetRefEndZ() );
+ pScMod->SetReference( aRange, rDoc, &rMark );
+ pScMod->EndReference(); // due to Auto-Hide
+ }
+}
+
+void ScTabControl::UpdateInputContext()
+{
+ ScDocument& rDoc = pViewData->GetDocument();
+ WinBits nStyle = GetStyle();
+ if (rDoc.GetDocumentShell()->IsReadOnly())
+ // no insert sheet tab for readonly doc.
+ SetStyle(nStyle & ~WB_INSERTTAB);
+ else
+ SetStyle(nStyle | WB_INSERTTAB);
+}
+
+void ScTabControl::UpdateStatus()
+{
+ ScDocument& rDoc = pViewData->GetDocument();
+ ScMarkData& rMark = pViewData->GetMarkData();
+ bool bActive = pViewData->IsActive();
+
+ SCTAB nCount = rDoc.GetTableCount();
+ SCTAB i;
+ OUString aString;
+ SCTAB nMaxCnt = std::max( nCount, static_cast<SCTAB>(GetMaxId()) );
+ Color aTabBgColor;
+
+ bool bModified = false; // sheet name
+ for (i=0; i<nMaxCnt && !bModified; i++)
+ {
+ if (rDoc.IsVisible(i))
+ {
+ rDoc.GetName(i,aString);
+ aTabBgColor = rDoc.GetTabBgColor(i);
+ }
+ else
+ {
+ aString.clear();
+ }
+
+ if ( aString != GetPageText(static_cast<sal_uInt16>(i)+1) || (GetTabBgColor(static_cast<sal_uInt16>(i)+1) != aTabBgColor) )
+ bModified = true;
+ }
+
+ if (bModified)
+ {
+ Clear();
+ for (i=0; i<nCount; i++)
+ {
+ if (rDoc.IsVisible(i))
+ {
+ if (rDoc.GetName(i,aString))
+ {
+ if ( rDoc.IsScenario(i) )
+ InsertPage(static_cast<sal_uInt16>(i)+1, aString, TabBarPageBits::Blue);
+ else
+ InsertPage( static_cast<sal_uInt16>(i)+1, aString );
+
+ if ( rDoc.IsTabProtected(i) )
+ SetProtectionSymbol(static_cast<sal_uInt16>(i)+1, true);
+
+ if ( !rDoc.IsDefaultTabBgColor(i) )
+ {
+ aTabBgColor = rDoc.GetTabBgColor(i);
+ SetTabBgColor(static_cast<sal_uInt16>(i)+1, aTabBgColor );
+ }
+ }
+ }
+ }
+ }
+ SetCurPageId( static_cast<sal_uInt16>(pViewData->GetTabNo()) + 1 );
+
+ if (bActive)
+ {
+ bModified = false; // selection
+ for (i=0; i<nMaxCnt && !bModified; i++)
+ if ( rMark.GetTableSelect(i) != IsPageSelected(static_cast<sal_uInt16>(i)+1) )
+ bModified = true;
+
+ if ( bModified )
+ for (i=0; i<nCount; i++)
+ SelectPage( static_cast<sal_uInt16>(i)+1, rMark.GetTableSelect(i) );
+ }
+}
+
+void ScTabControl::SetSheetLayoutRTL( bool bSheetRTL )
+{
+ SetEffectiveRTL( bSheetRTL );
+ nSelPageIdByMouse = TabBar::PAGE_NOT_FOUND;
+}
+
+void ScTabControl::SwitchToPageId(sal_uInt16 nId)
+{
+ if (!nId)
+ return;
+
+ bool bAlreadySelected = IsPageSelected( nId );
+ //make the clicked page the current one
+ SetCurPageId( nId );
+ //change the selection when the current one is not already
+ //selected or part of a multi selection
+ if(bAlreadySelected)
+ return;
+
+ sal_uInt16 nCount = GetMaxId();
+
+ for (sal_uInt16 i=1; i<=nCount; i++)
+ SelectPage( i, i==nId );
+ Select();
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ // notify LibreOfficeKit about changed page
+ OString aPayload = OString::number(nId - 1);
+ pViewData->GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SET_PART, aPayload.getStr());
+ }
+}
+
+void ScTabControl::Command( const CommandEvent& rCEvt )
+{
+ ScModule* pScMod = SC_MOD();
+ ScTabViewShell* pViewSh = pViewData->GetViewShell();
+ bool bDisable = pScMod->IsFormulaMode() || pScMod->IsModalMode();
+
+ // first activate ViewFrame (Bug 19493):
+ pViewSh->SetActive();
+
+ if (rCEvt.GetCommand() != CommandEventId::ContextMenu || bDisable)
+ return;
+
+ // #i18735# select the page that is under the mouse cursor
+ // if multiple tables are selected and the one under the cursor
+ // is not part of them then unselect them
+ sal_uInt16 nId = GetPageId( rCEvt.GetMousePosPixel() );
+ SwitchToPageId(nId);
+
+ // #i52073# OLE inplace editing has to be stopped before showing the sheet tab context menu
+ pViewSh->DeactivateOle();
+
+ // Popup-Menu:
+ // get Dispatcher from ViewData (ViewFrame) instead of Shell (Frame), so it can't be null
+ pViewData->GetDispatcher().ExecutePopup( "sheettab" );
+}
+
+void ScTabControl::StartDrag( sal_Int8 /* nAction */, const Point& rPosPixel )
+{
+ ScModule* pScMod = SC_MOD();
+ bool bDisable = pScMod->IsFormulaMode() || pScMod->IsModalMode();
+
+ if (!bDisable)
+ {
+ vcl::Region aRegion( tools::Rectangle(0,0,0,0) );
+ CommandEvent aCEvt( rPosPixel, CommandEventId::StartDrag, true ); // needed for StartDrag
+ if (TabBar::StartDrag( aCEvt, aRegion ))
+ DoDrag();
+ }
+}
+
+void ScTabControl::DoDrag()
+{
+ ScDocShell* pDocSh = pViewData->GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ SCTAB nTab = pViewData->GetTabNo();
+ ScRange aTabRange( 0, 0, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab );
+ ScMarkData aTabMark = pViewData->GetMarkData();
+ aTabMark.ResetMark(); // doesn't change marked table information
+ aTabMark.SetMarkArea( aTabRange );
+
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+ ScClipParam aClipParam(aTabRange, false);
+ rDoc.CopyToClip(aClipParam, pClipDoc.get(), &aTabMark, false, false);
+
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScTransferObj ctor
+
+ rtl::Reference<ScTransferObj> pTransferObj = new ScTransferObj( std::move(pClipDoc), aObjDesc );
+
+ pTransferObj->SetDragSourceFlags(ScDragSrc::Table);
+
+ pTransferObj->SetDragSource( pDocSh, aTabMark );
+
+ pTransferObj->SetSourceCursorPos( pViewData->GetCurX(), pViewData->GetCurY() );
+
+ vcl::Window* pWindow = pViewData->GetActiveWin();
+ SC_MOD()->SetDragObject( pTransferObj.get(), nullptr ); // for internal D&D
+ pTransferObj->StartDrag( pWindow, DND_ACTION_COPYMOVE | DND_ACTION_LINK );
+}
+
+static sal_uInt16 lcl_DocShellNr( const ScDocument& rDoc )
+{
+ sal_uInt16 nShellCnt = 0;
+ SfxObjectShell* pShell = SfxObjectShell::GetFirst();
+ while ( pShell )
+ {
+ if ( auto pDocShell = dynamic_cast<const ScDocShell *>(pShell) )
+ {
+ if ( &pDocShell->GetDocument() == &rDoc )
+ return nShellCnt;
+
+ ++nShellCnt;
+ }
+ pShell = SfxObjectShell::GetNext( *pShell );
+ }
+
+ OSL_FAIL("Document not found");
+ return 0;
+}
+
+sal_Int8 ScTabControl::ExecuteDrop( const ExecuteDropEvent& rEvt )
+{
+ EndSwitchPage();
+
+ ScDocument& rDoc = pViewData->GetDocument();
+ const ScDragData& rData = SC_MOD()->GetDragData();
+ if ( rData.pCellTransfer && (rData.pCellTransfer->GetDragSourceFlags() & ScDragSrc::Table) &&
+ rData.pCellTransfer->GetSourceDocument() == &rDoc )
+ {
+ // moving of tables within the document
+ SCTAB nPos = GetPrivatDropPos( rEvt.maPosPixel );
+ HideDropPos();
+
+ if ( nPos == rData.pCellTransfer->GetVisibleTab() && rEvt.mnAction == DND_ACTION_MOVE )
+ {
+ // #i83005# do nothing - don't move to the same position
+ // (too easily triggered unintentionally, and might take a long time in large documents)
+ }
+ else
+ {
+ if ( !rDoc.GetChangeTrack() && rDoc.IsDocEditable() )
+ {
+ //! use table selection from the tab control where dragging was started?
+ pViewData->GetView()->MoveTable( lcl_DocShellNr(rDoc), nPos, rEvt.mnAction != DND_ACTION_MOVE );
+
+ rData.pCellTransfer->SetDragWasInternal(); // don't delete
+ return DND_ACTION_COPY;
+ }
+ }
+ }
+
+ return DND_ACTION_NONE;
+}
+
+sal_Int8 ScTabControl::AcceptDrop( const AcceptDropEvent& rEvt )
+{
+ if ( rEvt.mbLeaving )
+ {
+ EndSwitchPage();
+ HideDropPos();
+ return rEvt.mnAction;
+ }
+
+ const ScDocument& rDoc = pViewData->GetDocument();
+ const ScDragData& rData = SC_MOD()->GetDragData();
+ if ( rData.pCellTransfer && (rData.pCellTransfer->GetDragSourceFlags() & ScDragSrc::Table) &&
+ rData.pCellTransfer->GetSourceDocument() == &rDoc )
+ {
+ // moving of tables within the document
+ if ( !rDoc.GetChangeTrack() && rDoc.IsDocEditable() )
+ {
+ ShowDropPos( rEvt.maPosPixel );
+ return rEvt.mnAction;
+ }
+ }
+ else // switch sheets for all formats
+ {
+ SwitchPage( rEvt.maPosPixel ); // switch sheet after timeout
+ return 0; // nothing can be dropped here
+ }
+
+ return 0;
+}
+
+bool ScTabControl::StartRenaming()
+{
+ return pViewData->GetDocument().IsDocEditable();
+}
+
+TabBarAllowRenamingReturnCode ScTabControl::AllowRenaming()
+{
+ ScTabViewShell* pViewSh = pViewData->GetViewShell();
+ OSL_ENSURE( pViewSh, "pViewData->GetViewShell()" );
+
+ TabBarAllowRenamingReturnCode nRet = TABBAR_RENAMING_CANCEL;
+ sal_uInt16 nId = GetEditPageId();
+ if ( nId )
+ {
+ SCTAB nTab = nId - 1;
+ OUString aNewName = GetEditText();
+ bool bDone = pViewSh->RenameTable( aNewName, nTab );
+ if ( bDone )
+ nRet = TABBAR_RENAMING_YES;
+ else if ( bErrorShown )
+ {
+ // if the error message from this TabControl is currently visible,
+ // don't end edit mode now, to avoid problems when returning to
+ // the other call (showing the error) - this should not happen
+ OSL_FAIL("ScTabControl::AllowRenaming: nested calls");
+ nRet = TABBAR_RENAMING_NO;
+ }
+ else if (pViewData->GetDocShell()->IsInModalMode())
+ {
+ // don't show error message above any modal dialog
+ // instead cancel renaming without error message
+ // e.g. start with default Sheet1, add another sheet
+ // alt+left click on Sheet2 tab, edit to say Sheet1
+ // ctrl+S to trigger modal file save dialog
+ nRet = TABBAR_RENAMING_CANCEL;
+ }
+ else
+ {
+ bErrorShown = true;
+ pViewSh->ErrorMessage( STR_INVALIDTABNAME );
+ bErrorShown = false;
+ nRet = TABBAR_RENAMING_NO;
+ }
+ }
+ return nRet;
+}
+
+void ScTabControl::EndRenaming()
+{
+ if ( HasFocus() )
+ pViewData->GetView()->ActiveGrabFocus();
+}
+
+void ScTabControl::Mirror()
+{
+ TabBar::Mirror();
+ if( nSelPageIdByMouse != TabBar::PAGE_NOT_FOUND )
+ {
+ tools::Rectangle aRect( GetPageRect( GetCurPageId() ) );
+ if( !aRect.IsEmpty() )
+ SetPointerPosPixel( aRect.Center() );
+ nSelPageIdByMouse = TabBar::PAGE_NOT_FOUND; // only once after a Select()
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabsplit.cxx b/sc/source/ui/view/tabsplit.cxx
new file mode 100644
index 000000000..fb8435b27
--- /dev/null
+++ b/sc/source/ui/view/tabsplit.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 <tabsplit.hxx>
+#include <viewdata.hxx>
+
+#include <vcl/settings.hxx>
+
+ScTabSplitter::ScTabSplitter( vcl::Window* pParent, WinBits nWinStyle, const ScViewData* pData ) :
+ Splitter(pParent, nWinStyle),
+ pViewData(pData)
+{
+ SetFixed(false);
+ EnableRTL(false);
+}
+
+ScTabSplitter::~ScTabSplitter()
+{
+}
+
+void ScTabSplitter::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ if (bFixed)
+ Window::MouseButtonDown( rMEvt );
+ else
+ Splitter::MouseButtonDown( rMEvt );
+}
+
+void ScTabSplitter::SetFixed(bool bSet)
+{
+ bFixed = bSet;
+ if (bSet)
+ SetPointer(PointerStyle::Arrow);
+ else if (IsHorizontal())
+ SetPointer(PointerStyle::HSplit);
+ else
+ SetPointer(PointerStyle::VSplit);
+}
+
+void ScTabSplitter::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect )
+{
+ rRenderContext.Push(vcl::PushFlags::FILLCOLOR | vcl::PushFlags::LINECOLOR);
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+
+ if (IsHorizontal())
+ {
+ switch (pViewData->GetHSplitMode())
+ {
+ case SC_SPLIT_NONE:
+ {
+ rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
+ rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
+ rRenderContext.DrawRect(tools::Rectangle(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom()));
+
+ // Draw handle
+ rRenderContext.SetLineColor(COL_BLACK);
+ rRenderContext.SetFillColor(COL_BLACK);
+ const tools::Long xc = rRect.Right() + rRect.Left();
+ const tools::Long h4 = rRect.GetHeight() / 4;
+ // First xc fraction is truncated, second one is rounded. This will draw a centered line
+ // in handlers with odd width and a centered rectangle in those with even width.
+ rRenderContext.DrawRect(tools::Rectangle(Point(xc / 2, rRect.Top() + h4),
+ Point((xc + 1) / 2, rRect.Bottom() - h4)));
+ break;
+ }
+ case SC_SPLIT_NORMAL:
+ rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
+ rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
+ rRenderContext.DrawRect(tools::Rectangle(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom()));
+ break;
+ case SC_SPLIT_FIX:
+ // Nothing to draw
+ break;
+ }
+ }
+ else
+ {
+ switch (pViewData->GetVSplitMode())
+ {
+ case SC_SPLIT_NONE:
+ {
+ rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
+ rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
+ rRenderContext.DrawRect(tools::Rectangle(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom()));
+
+ // Draw handle
+ rRenderContext.SetLineColor(COL_BLACK);
+ rRenderContext.SetFillColor(COL_BLACK);
+ const tools::Long yc = rRect.Top() + rRect.Bottom();
+ const tools::Long w4 = rRect.GetWidth() / 4;
+ // First yc fraction is truncated, second one is rounded. This will draw a centered line
+ // in handlers with odd height and a centered rectangle in those with even height.
+ GetOutDev()->DrawRect(tools::Rectangle(Point(rRect.Left() + w4, yc / 2),
+ Point(rRect.Right() - w4, (yc + 1) / 2)));
+ break;
+ }
+ case SC_SPLIT_NORMAL:
+ rRenderContext.SetLineColor(rStyleSettings.GetShadowColor());
+ rRenderContext.SetFillColor(rStyleSettings.GetShadowColor());
+ rRenderContext.DrawRect(tools::Rectangle(rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom()));
+ break;
+ case SC_SPLIT_FIX:
+ // Nothing to draw
+ break;
+ }
+ }
+
+ rRenderContext.Pop();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabview.cxx b/sc/source/ui/view/tabview.cxx
new file mode 100644
index 000000000..523044c75
--- /dev/null
+++ b/sc/source/ui/view/tabview.cxx
@@ -0,0 +1,3016 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/bindings.hxx>
+#include <vcl/commandevent.hxx>
+#include <vcl/help.hxx>
+#include <vcl/settings.hxx>
+#include <sal/log.hxx>
+#include <tools/svborder.hxx>
+#include <tools/json_writer.hxx>
+#include <o3tl/unit_conversion.hxx>
+
+#include <pagedata.hxx>
+#include <tabview.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <gridwin.hxx>
+#include <olinewin.hxx>
+#include <olinetab.hxx>
+#include <tabsplit.hxx>
+#include <colrowba.hxx>
+#include <tabcont.hxx>
+#include <scmod.hxx>
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <drawview.hxx>
+#include <docsh.hxx>
+#include <viewuno.hxx>
+#include <appoptio.hxx>
+#include <attrib.hxx>
+#include <spellcheckcontext.hxx>
+#include <comphelper/lok.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <osl/diagnose.h>
+
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/json_parser.hpp>
+
+#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
+
+#include <algorithm>
+
+#include <basegfx/utils/zoomtools.hxx>
+
+#define SPLIT_MARGIN 30
+#define SPLIT_HANDLE_SIZE 5
+constexpr sal_Int32 TAB_HEIGHT_MARGIN = 10;
+
+#define SC_ICONSIZE 36
+
+#define SC_SCROLLBAR_MIN 30
+#define SC_TABBAR_MIN 6
+
+using namespace ::com::sun::star;
+
+// Corner-Button
+
+ScCornerButton::ScCornerButton( vcl::Window* pParent, ScViewData* pData ) :
+ Window( pParent, WinBits( 0 ) ),
+ pViewData( pData )
+{
+ EnableRTL( false );
+}
+
+ScCornerButton::~ScCornerButton()
+{
+}
+
+void ScCornerButton::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect)
+{
+ const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings();
+ SetBackground(rStyleSettings.GetFaceColor());
+
+ Size aSize(GetOutputSizePixel());
+ tools::Long nPosX = aSize.Width() - 1;
+ tools::Long nPosY = aSize.Height() - 1;
+
+ Window::Paint(rRenderContext, rRect);
+
+ bool bLayoutRTL = pViewData->GetDocument().IsLayoutRTL( pViewData->GetTabNo() );
+ tools::Long nDarkX = bLayoutRTL ? 0 : nPosX;
+
+ // both buttons have the same look now - only dark right/bottom lines
+ rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor());
+ rRenderContext.DrawLine(Point(0, nPosY), Point(nPosX, nPosY));
+ rRenderContext.DrawLine(Point(nDarkX, 0), Point(nDarkX, nPosY));
+}
+
+void ScCornerButton::StateChanged( StateChangedType nType )
+{
+ Window::StateChanged( nType );
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ SetBackground( rStyleSettings.GetFaceColor() );
+ Invalidate();
+}
+
+void ScCornerButton::DataChanged( const DataChangedEvent& rDCEvt )
+{
+ Window::DataChanged( rDCEvt );
+
+ const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
+ SetBackground( rStyleSettings.GetFaceColor() );
+ Invalidate();
+}
+
+void ScCornerButton::Resize()
+{
+ Invalidate();
+}
+
+void ScCornerButton::MouseButtonDown( const MouseEvent& rMEvt )
+{
+ ScModule* pScMod = SC_MOD();
+ bool bDisable = pScMod->IsFormulaMode() || pScMod->IsModalMode();
+ if (!bDisable)
+ {
+ ScTabViewShell* pViewSh = pViewData->GetViewShell();
+ pViewSh->SetActive(); // Appear and SetViewFrame
+ pViewSh->ActiveGrabFocus();
+
+ bool bControl = rMEvt.IsMod1();
+ pViewSh->SelectAll( bControl );
+ }
+}
+namespace
+{
+
+bool lcl_HasColOutline( const ScViewData& rViewData )
+{
+ const ScOutlineTable* pTable = rViewData.GetDocument().GetOutlineTable(rViewData.GetTabNo());
+ if (pTable)
+ {
+ const ScOutlineArray& rArray = pTable->GetColArray();
+ if ( rArray.GetDepth() > 0 )
+ return true;
+ }
+ return false;
+}
+
+bool lcl_HasRowOutline( const ScViewData& rViewData )
+{
+ const ScOutlineTable* pTable = rViewData.GetDocument().GetOutlineTable(rViewData.GetTabNo());
+ if (pTable)
+ {
+ const ScOutlineArray& rArray = pTable->GetRowArray();
+ if ( rArray.GetDepth() > 0 )
+ return true;
+ }
+ return false;
+}
+
+} // anonymous namespace
+
+ScTabView::ScTabView( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
+ pFrameWin( pParent ),
+ aViewData( rDocSh, pViewShell ),
+ aFunctionSet( &aViewData ),
+ aHdrFunc( &aViewData ),
+ aVScrollTop( VclPtr<ScrollBar>::Create( pFrameWin, WinBits( WB_VSCROLL | WB_DRAG ) ) ),
+ aVScrollBottom( VclPtr<ScrollBar>::Create( pFrameWin, WinBits( WB_VSCROLL | WB_DRAG ) ) ),
+ aHScrollLeft( VclPtr<ScrollBar>::Create( pFrameWin, WinBits( WB_HSCROLL | WB_DRAG ) ) ),
+ aHScrollRight( VclPtr<ScrollBar>::Create( pFrameWin, WinBits( WB_HSCROLL | WB_DRAG ) ) ),
+ aCornerButton( VclPtr<ScCornerButton>::Create( pFrameWin, &aViewData ) ),
+ aTopButton( VclPtr<ScCornerButton>::Create( pFrameWin, &aViewData ) ),
+ aScrollBarBox( VclPtr<ScrollBarBox>::Create( pFrameWin, WB_SIZEABLE ) ),
+ aScrollTimer("ScTabView aScrollTimer"),
+ pTimerWindow( nullptr ),
+ aExtraEditViewManager( pViewShell, pGridWin ),
+ nTipVisible( nullptr ),
+ nTipAlign( QuickHelpFlags::NONE ),
+ nPrevDragPos( 0 ),
+ meBlockMode(None),
+ nBlockStartX( 0 ),
+ nBlockStartXOrig( 0 ),
+ nBlockEndX( 0 ),
+ nBlockStartY( 0 ),
+ nBlockStartYOrig( 0 ),
+ nBlockEndY( 0 ),
+ nBlockStartZ( 0 ),
+ nBlockEndZ( 0 ),
+ nOldCurX( 0 ),
+ nOldCurY( 0 ),
+ mfPendingTabBarWidth( -1.0 ),
+ mnLOKStartHeaderRow( -2 ),
+ mnLOKEndHeaderRow( -1 ),
+ mnLOKStartHeaderCol( -2 ),
+ mnLOKEndHeaderCol( -1 ),
+ bMinimized( false ),
+ bInUpdateHeader( false ),
+ bInActivatePart( false ),
+ bInZoomUpdate( false ),
+ bMoveIsShift( false ),
+ bDrawSelMode( false ),
+ bLockPaintBrush( false ),
+ bDragging( false ),
+ bBlockNeg( false ),
+ bBlockCols( false ),
+ bBlockRows( false ),
+ mbInlineWithScrollbar( false )
+{
+ Init();
+}
+
+void ScTabView::InitScrollBar( ScrollBar& rScrollBar, tools::Long nMaxVal )
+{
+ rScrollBar.SetRange( Range( 0, nMaxVal ) );
+ rScrollBar.SetLineSize( 1 );
+ rScrollBar.SetPageSize( 1 ); // is queried separately
+ rScrollBar.SetVisibleSize( 10 ); // is reset by Resize
+
+ rScrollBar.SetScrollHdl( LINK(this, ScTabView, ScrollHdl) );
+ rScrollBar.SetEndScrollHdl( LINK(this, ScTabView, EndScrollHdl) );
+
+ rScrollBar.EnableRTL( aViewData.GetDocument().IsLayoutRTL( aViewData.GetTabNo() ) );
+}
+
+// Scroll-Timer
+
+void ScTabView::SetTimer( ScGridWindow* pWin, const MouseEvent& rMEvt )
+{
+ pTimerWindow = pWin;
+ aTimerMEvt = rMEvt;
+ aScrollTimer.Start();
+}
+
+void ScTabView::ResetTimer()
+{
+ aScrollTimer.Stop();
+ pTimerWindow = nullptr;
+}
+
+IMPL_LINK_NOARG(ScTabView, TimerHdl, Timer *, void)
+{
+ if (pTimerWindow)
+ pTimerWindow->MouseMove( aTimerMEvt );
+}
+
+// --- Resize ---------------------------------------------------------------------
+
+static void lcl_SetPosSize( vcl::Window& rWindow, const Point& rPos, const Size& rSize,
+ tools::Long nTotalWidth, bool bLayoutRTL )
+{
+ Point aNewPos = rPos;
+ if ( bLayoutRTL )
+ {
+ aNewPos.setX( nTotalWidth - rPos.X() - rSize.Width() );
+ if ( aNewPos == rWindow.GetPosPixel() && rSize.Width() != rWindow.GetSizePixel().Width() )
+ {
+ // Document windows are manually painted right-to-left, so they need to
+ // be repainted if the size changes.
+ rWindow.Invalidate();
+ }
+ }
+ rWindow.SetPosSizePixel( aNewPos, rSize );
+}
+
+void ScTabView::DoResize( const Point& rOffset, const Size& rSize, bool bInner )
+{
+ HideListBox();
+
+ bool bHasHint = HasHintWindow();
+ if (bHasHint)
+ RemoveHintWindow();
+
+ bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.GetTabNo() );
+ tools::Long nTotalWidth = rSize.Width();
+ if ( bLayoutRTL )
+ nTotalWidth += 2*rOffset.X();
+
+ bool bVScroll = aViewData.IsVScrollMode();
+ bool bHScroll = aViewData.IsHScrollMode();
+ bool bTabControl = aViewData.IsTabMode();
+ bool bHeaders = aViewData.IsHeaderMode();
+ bool bOutlMode = aViewData.IsOutlineMode();
+ bool bHOutline = bOutlMode && lcl_HasColOutline(aViewData);
+ bool bVOutline = bOutlMode && lcl_HasRowOutline(aViewData);
+
+ if ( aViewData.GetDocShell()->IsPreview() )
+ bHScroll = bVScroll = bTabControl = bHeaders = bHOutline = bVOutline = false;
+
+ tools::Long nBarX = 0;
+ tools::Long nBarY = 0;
+ tools::Long nOutlineX = 0;
+ tools::Long nOutlineY = 0;
+ tools::Long nOutPosX;
+ tools::Long nOutPosY;
+
+ tools::Long nPosX = rOffset.X();
+ tools::Long nPosY = rOffset.Y();
+ tools::Long nSizeX = rSize.Width();
+ tools::Long nSizeY = rSize.Height();
+
+ bMinimized = ( nSizeX<=SC_ICONSIZE || nSizeY<=SC_ICONSIZE );
+ if ( bMinimized )
+ return;
+
+ float fScaleFactor = pFrameWin->GetDPIScaleFactor();
+
+ tools::Long nSplitSizeX = SPLIT_HANDLE_SIZE * fScaleFactor;
+ if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
+ nSplitSizeX = 1;
+ tools::Long nSplitSizeY = SPLIT_HANDLE_SIZE * fScaleFactor;
+ if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
+ nSplitSizeY = 1;
+
+ aBorderPos = rOffset;
+ aFrameSize = rSize;
+
+ const StyleSettings& rStyleSettings = pFrameWin->GetSettings().GetStyleSettings();
+
+
+ Size aFontSize = rStyleSettings.GetTabFont().GetFontSize();
+ MapMode aPtMapMode(MapUnit::MapPoint);
+ aFontSize = pFrameWin->LogicToPixel(aFontSize, aPtMapMode);
+ sal_Int32 nTabHeight = aFontSize.Height() + TAB_HEIGHT_MARGIN;
+
+ if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ {
+ if ( aViewData.GetHSplitPos() > nSizeX - SPLIT_MARGIN )
+ {
+ aViewData.SetHSplitMode( SC_SPLIT_NONE );
+ if ( WhichH( aViewData.GetActivePart() ) == SC_SPLIT_RIGHT )
+ ActivatePart( SC_SPLIT_BOTTOMLEFT );
+ InvalidateSplit();
+ }
+ }
+ if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ {
+ if ( aViewData.GetVSplitPos() > nSizeY - SPLIT_MARGIN )
+ {
+ aViewData.SetVSplitMode( SC_SPLIT_NONE );
+ if ( WhichV( aViewData.GetActivePart() ) == SC_SPLIT_TOP )
+ ActivatePart( SC_SPLIT_BOTTOMLEFT );
+ InvalidateSplit();
+ }
+ }
+
+ UpdateShow();
+
+ if (bHScroll || bVScroll) // Scrollbars horizontal or vertical
+ {
+ tools::Long nScrollBarSize = rStyleSettings.GetScrollBarSize();
+ if (bVScroll)
+ {
+ nBarX = nScrollBarSize;
+ nSizeX -= nBarX;
+ }
+ if (bHScroll)
+ {
+ nBarY = nTabHeight;
+
+ if (!mbInlineWithScrollbar)
+ nBarY += nScrollBarSize;
+
+ nSizeY -= nBarY;
+ }
+
+ // window at the bottom right
+ lcl_SetPosSize( *aScrollBarBox, Point( nPosX+nSizeX, nPosY+nSizeY ), Size( nBarX, nBarY ),
+ nTotalWidth, bLayoutRTL );
+
+ if (bHScroll) // Scrollbars horizontal
+ {
+ tools::Long nSizeLt = 0; // left scroll bar
+ tools::Long nSizeRt = 0; // right scroll bar
+ tools::Long nSizeSp = 0; // splitter
+
+ switch (aViewData.GetHSplitMode())
+ {
+ case SC_SPLIT_NONE:
+ nSizeSp = nSplitSizeX;
+ nSizeLt = nSizeX - nSizeSp; // Convert the corner
+ break;
+ case SC_SPLIT_NORMAL:
+ nSizeSp = nSplitSizeX;
+ nSizeLt = aViewData.GetHSplitPos();
+ break;
+ case SC_SPLIT_FIX:
+ nSizeSp = 0;
+ nSizeLt = 0;
+ break;
+ }
+ nSizeRt = nSizeX - nSizeLt - nSizeSp;
+
+ tools::Long nTabSize = 0;
+
+ if (bTabControl)
+ {
+ // pending relative tab bar width from extended document options
+ if( mfPendingTabBarWidth >= 0.0 )
+ {
+ SetRelTabBarWidth( mfPendingTabBarWidth );
+ mfPendingTabBarWidth = -1.0;
+ }
+
+ if (mbInlineWithScrollbar)
+ {
+ nTabSize = pTabControl->GetSizePixel().Width();
+
+ if ( aViewData.GetHSplitMode() != SC_SPLIT_FIX ) // left Scrollbar
+ {
+ if (nTabSize > nSizeLt-SC_SCROLLBAR_MIN)
+ nTabSize = nSizeLt-SC_SCROLLBAR_MIN;
+ if (nTabSize < SC_TABBAR_MIN)
+ nTabSize = SC_TABBAR_MIN;
+ nSizeLt -= nTabSize;
+ }
+ else // right Scrollbar
+ {
+ if (nTabSize > nSizeRt-SC_SCROLLBAR_MIN)
+ nTabSize = nSizeRt-SC_SCROLLBAR_MIN;
+ if (nTabSize < SC_TABBAR_MIN)
+ nTabSize = SC_TABBAR_MIN;
+ nSizeRt -= nTabSize;
+ }
+ }
+ }
+
+ if (mbInlineWithScrollbar)
+ {
+ Point aTabPoint(nPosX, nPosY + nSizeY);
+ Size aTabSize(nTabSize, nBarY);
+ lcl_SetPosSize(*pTabControl, aTabPoint, aTabSize, nTotalWidth, bLayoutRTL);
+ pTabControl->SetSheetLayoutRTL(bLayoutRTL);
+
+ Point aHScrollLeftPoint(nPosX + nTabSize, nPosY + nSizeY);
+ Size aHScrollLeftSize(nSizeLt, nBarY);
+ lcl_SetPosSize(*aHScrollLeft, aHScrollLeftPoint, aHScrollLeftSize, nTotalWidth, bLayoutRTL);
+
+ Point aHSplitterPoint(nPosX + nTabSize + nSizeLt, nPosY + nSizeY);
+ Size aHSplitterSize(nSizeSp, nBarY);
+ lcl_SetPosSize(*pHSplitter, aHSplitterPoint, aHSplitterSize, nTotalWidth, bLayoutRTL);
+
+ Point aHScrollRightPoint(nPosX + nTabSize + nSizeLt + nSizeSp, nPosY + nSizeY);
+ Size aHScrollRightSize(nSizeRt, nBarY);
+ lcl_SetPosSize(*aHScrollRight, aHScrollRightPoint, aHScrollRightSize, nTotalWidth, bLayoutRTL);
+ }
+ else
+ {
+ Point aTabPoint(nPosX, nPosY + nSizeY + nScrollBarSize);
+ Size aTabSize(nSizeX, nTabHeight);
+ lcl_SetPosSize(*pTabControl, aTabPoint, aTabSize, nTotalWidth, bLayoutRTL);
+ pTabControl->SetSheetLayoutRTL(bLayoutRTL);
+
+ Point aHScrollLeftPoint(nPosX, nPosY + nSizeY);
+ Size aHScrollLeftSize(nSizeLt, nScrollBarSize);
+ lcl_SetPosSize(*aHScrollLeft, aHScrollLeftPoint, aHScrollLeftSize, nTotalWidth, bLayoutRTL);
+
+ Point aHSplitterPoint(nPosX + nSizeLt, nPosY + nSizeY);
+ Size aHSplitterSize(nSizeSp, nScrollBarSize);
+ lcl_SetPosSize(*pHSplitter, aHSplitterPoint, aHSplitterSize, nTotalWidth, bLayoutRTL);
+
+ Point aHScrollRightPoint(nPosX + nSizeLt + nSizeSp, nPosY + nSizeY);
+ Size aHScrollRightSize(nSizeRt, nScrollBarSize);
+ lcl_SetPosSize(*aHScrollRight, aHScrollRightPoint, aHScrollRightSize, nTotalWidth, bLayoutRTL);
+ }
+ // SetDragRectPixel is done below
+ }
+
+ if (bVScroll)
+ {
+ tools::Long nSizeUp = 0; // upper scroll bar
+ tools::Long nSizeSp = 0; // splitter
+ tools::Long nSizeDn; // lower scroll bar
+
+ switch (aViewData.GetVSplitMode())
+ {
+ case SC_SPLIT_NONE:
+ nSizeUp = 0;
+ nSizeSp = nSplitSizeY;
+ break;
+ case SC_SPLIT_NORMAL:
+ nSizeUp = aViewData.GetVSplitPos();
+ nSizeSp = nSplitSizeY;
+ break;
+ case SC_SPLIT_FIX:
+ nSizeUp = 0;
+ nSizeSp = 0;
+ break;
+ }
+ nSizeDn = nSizeY - nSizeUp - nSizeSp;
+
+ lcl_SetPosSize( *aVScrollTop, Point(nPosX + nSizeX, nPosY),
+ Size(nBarX, nSizeUp), nTotalWidth, bLayoutRTL );
+ lcl_SetPosSize( *pVSplitter, Point( nPosX + nSizeX, nPosY+nSizeUp ),
+ Size( nBarX, nSizeSp ), nTotalWidth, bLayoutRTL );
+ lcl_SetPosSize( *aVScrollBottom, Point(nPosX + nSizeX,
+ nPosY + nSizeUp + nSizeSp),
+ Size(nBarX, nSizeDn), nTotalWidth, bLayoutRTL );
+
+ // SetDragRectPixel is done below
+ }
+ }
+
+ // SetDragRectPixel also without Scrollbars etc., when already split
+ if ( bHScroll || aViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ pHSplitter->SetDragRectPixel(
+ tools::Rectangle( nPosX, nPosY, nPosX+nSizeX, nPosY+nSizeY ), pFrameWin );
+ if ( bVScroll || aViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ pVSplitter->SetDragRectPixel(
+ tools::Rectangle( nPosX, nPosY, nPosX+nSizeX, nPosY+nSizeY ), pFrameWin );
+
+ if (bTabControl && ! bHScroll )
+ {
+ nBarY = aHScrollLeft->GetSizePixel().Height();
+ nBarX = aVScrollBottom->GetSizePixel().Width();
+
+ tools::Long nSize1 = nSizeX;
+
+ tools::Long nTabSize = nSize1;
+ if (nTabSize < 0) nTabSize = 0;
+
+ lcl_SetPosSize( *pTabControl, Point(nPosX, nPosY+nSizeY-nBarY),
+ Size(nTabSize, nBarY), nTotalWidth, bLayoutRTL );
+ nSizeY -= nBarY;
+ lcl_SetPosSize( *aScrollBarBox, Point( nPosX+nSizeX, nPosY+nSizeY ), Size( nBarX, nBarY ),
+ nTotalWidth, bLayoutRTL );
+
+ if( bVScroll )
+ {
+ Size aVScrSize = aVScrollBottom->GetSizePixel();
+ aVScrSize.AdjustHeight( -nBarY );
+ aVScrollBottom->SetSizePixel( aVScrSize );
+ }
+ }
+
+ nOutPosX = nPosX;
+ nOutPosY = nPosY;
+
+ // Outline-Controls
+ if (bVOutline && pRowOutline[SC_SPLIT_BOTTOM])
+ {
+ nOutlineX = pRowOutline[SC_SPLIT_BOTTOM]->GetDepthSize();
+ nSizeX -= nOutlineX;
+ nPosX += nOutlineX;
+ }
+ if (bHOutline && pColOutline[SC_SPLIT_LEFT])
+ {
+ nOutlineY = pColOutline[SC_SPLIT_LEFT]->GetDepthSize();
+ nSizeY -= nOutlineY;
+ nPosY += nOutlineY;
+ }
+
+ if (bHeaders) // column/row header
+ {
+ nBarX = pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width();
+ nBarY = pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height();
+ nSizeX -= nBarX;
+ nSizeY -= nBarY;
+ nPosX += nBarX;
+ nPosY += nBarY;
+ }
+ else
+ nBarX = nBarY = 0;
+
+ // evaluate splitter
+
+ tools::Long nLeftSize = nSizeX;
+ tools::Long nRightSize = 0;
+ tools::Long nTopSize = 0;
+ tools::Long nBottomSize = nSizeY;
+ tools::Long nSplitPosX = nPosX;
+ tools::Long nSplitPosY = nPosY;
+
+ if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ {
+ tools::Long nSplitHeight = rSize.Height();
+ if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
+ {
+ // Do not allow freeze splitter to overlap scroll bar/tab bar
+ if ( bHScroll )
+ nSplitHeight -= aHScrollLeft->GetSizePixel().Height();
+ else if ( bTabControl && pTabControl )
+ nSplitHeight -= pTabControl->GetSizePixel().Height();
+ }
+ nSplitPosX = aViewData.GetHSplitPos();
+ lcl_SetPosSize( *pHSplitter,
+ Point(nSplitPosX, nOutPosY),
+ Size(nSplitSizeX, nSplitHeight - nTabHeight), nTotalWidth, bLayoutRTL);
+ nLeftSize = nSplitPosX - nPosX;
+ nSplitPosX += nSplitSizeX;
+ nRightSize = nSizeX - nLeftSize - nSplitSizeX;
+ }
+ if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ {
+ tools::Long nSplitWidth = rSize.Width();
+ if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX && bVScroll )
+ nSplitWidth -= aVScrollBottom->GetSizePixel().Width();
+ nSplitPosY = aViewData.GetVSplitPos();
+ lcl_SetPosSize( *pVSplitter,
+ Point( nOutPosX, nSplitPosY ), Size( nSplitWidth, nSplitSizeY ), nTotalWidth, bLayoutRTL );
+ nTopSize = nSplitPosY - nPosY;
+ nSplitPosY += nSplitSizeY;
+ nBottomSize = nSizeY - nTopSize - nSplitSizeY;
+ }
+
+ // ShowHide for pColOutline / pRowOutline happens in UpdateShow
+
+ if (bHOutline) // Outline-Controls
+ {
+ if (pColOutline[SC_SPLIT_LEFT])
+ {
+ pColOutline[SC_SPLIT_LEFT]->SetHeaderSize( nBarX );
+ lcl_SetPosSize( *pColOutline[SC_SPLIT_LEFT],
+ Point(nPosX-nBarX,nOutPosY), Size(nLeftSize+nBarX,nOutlineY), nTotalWidth, bLayoutRTL );
+ }
+ if (pColOutline[SC_SPLIT_RIGHT])
+ {
+ pColOutline[SC_SPLIT_RIGHT]->SetHeaderSize( 0 ); // always call to update RTL flag
+ lcl_SetPosSize( *pColOutline[SC_SPLIT_RIGHT],
+ Point(nSplitPosX,nOutPosY), Size(nRightSize,nOutlineY), nTotalWidth, bLayoutRTL );
+ }
+ }
+ if (bVOutline)
+ {
+ if (nTopSize)
+ {
+ if (pRowOutline[SC_SPLIT_TOP] && pRowOutline[SC_SPLIT_BOTTOM])
+ {
+ pRowOutline[SC_SPLIT_TOP]->SetHeaderSize( nBarY );
+ lcl_SetPosSize( *pRowOutline[SC_SPLIT_TOP],
+ Point(nOutPosX,nPosY-nBarY), Size(nOutlineX,nTopSize+nBarY), nTotalWidth, bLayoutRTL );
+ pRowOutline[SC_SPLIT_BOTTOM]->SetHeaderSize( 0 );
+ lcl_SetPosSize( *pRowOutline[SC_SPLIT_BOTTOM],
+ Point(nOutPosX,nSplitPosY), Size(nOutlineX,nBottomSize), nTotalWidth, bLayoutRTL );
+ }
+ }
+ else if (pRowOutline[SC_SPLIT_BOTTOM])
+ {
+ pRowOutline[SC_SPLIT_BOTTOM]->SetHeaderSize( nBarY );
+ lcl_SetPosSize( *pRowOutline[SC_SPLIT_BOTTOM],
+ Point(nOutPosX,nSplitPosY-nBarY), Size(nOutlineX,nBottomSize+nBarY), nTotalWidth, bLayoutRTL );
+ }
+ }
+ if (bHOutline && bVOutline)
+ {
+ lcl_SetPosSize( *aTopButton, Point(nOutPosX,nOutPosY), Size(nOutlineX,nOutlineY), nTotalWidth, bLayoutRTL );
+ aTopButton->Show();
+ }
+ else
+ aTopButton->Hide();
+
+ if (bHeaders) // column/row header
+ {
+ lcl_SetPosSize( *pColBar[SC_SPLIT_LEFT],
+ Point(nPosX,nPosY-nBarY), Size(nLeftSize,nBarY), nTotalWidth, bLayoutRTL );
+ if (pColBar[SC_SPLIT_RIGHT])
+ lcl_SetPosSize( *pColBar[SC_SPLIT_RIGHT],
+ Point(nSplitPosX,nPosY-nBarY), Size(nRightSize,nBarY), nTotalWidth, bLayoutRTL );
+
+ if (pRowBar[SC_SPLIT_TOP])
+ lcl_SetPosSize( *pRowBar[SC_SPLIT_TOP],
+ Point(nPosX-nBarX,nPosY), Size(nBarX,nTopSize), nTotalWidth, bLayoutRTL );
+ lcl_SetPosSize( *pRowBar[SC_SPLIT_BOTTOM],
+ Point(nPosX-nBarX,nSplitPosY), Size(nBarX,nBottomSize), nTotalWidth, bLayoutRTL );
+
+ lcl_SetPosSize( *aCornerButton, Point(nPosX-nBarX,nPosY-nBarY), Size(nBarX,nBarY), nTotalWidth, bLayoutRTL );
+ aCornerButton->Show();
+ pColBar[SC_SPLIT_LEFT]->Show();
+ pRowBar[SC_SPLIT_BOTTOM]->Show();
+ }
+ else
+ {
+ aCornerButton->Hide();
+ pColBar[SC_SPLIT_LEFT]->Hide(); // always here
+ pRowBar[SC_SPLIT_BOTTOM]->Hide();
+ }
+
+ // Grid-Windows
+
+ if (bInner)
+ {
+ tools::Long nInnerPosX = bLayoutRTL ? ( nTotalWidth - nPosX - nLeftSize ) : nPosX;
+ pGridWin[SC_SPLIT_BOTTOMLEFT]->SetPosPixel( Point(nInnerPosX,nSplitPosY) );
+ }
+ else
+ {
+ lcl_SetPosSize( *pGridWin[SC_SPLIT_BOTTOMLEFT],
+ Point(nPosX,nSplitPosY), Size(nLeftSize,nBottomSize), nTotalWidth, bLayoutRTL );
+ if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ lcl_SetPosSize( *pGridWin[SC_SPLIT_BOTTOMRIGHT],
+ Point(nSplitPosX,nSplitPosY), Size(nRightSize,nBottomSize), nTotalWidth, bLayoutRTL );
+ if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ lcl_SetPosSize( *pGridWin[SC_SPLIT_TOPLEFT],
+ Point(nPosX,nPosY), Size(nLeftSize,nTopSize), nTotalWidth, bLayoutRTL );
+ if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE && aViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ lcl_SetPosSize( *pGridWin[SC_SPLIT_TOPRIGHT],
+ Point(nSplitPosX,nPosY), Size(nRightSize,nTopSize), nTotalWidth, bLayoutRTL );
+ }
+
+ // update scroll bars
+
+ if (!bInUpdateHeader)
+ {
+ UpdateScrollBars(); // don't reset scroll bars when scrolling
+ UpdateHeaderWidth();
+
+ InterpretVisible(); // have everything calculated before painting
+ }
+
+ if (bHasHint)
+ TestHintWindow(); // reposition
+
+ UpdateVarZoom(); // update variable zoom types (after resizing GridWindows)
+
+ if (aViewData.GetViewShell()->HasAccessibilityObjects())
+ aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccWindowResized));
+}
+
+void ScTabView::UpdateVarZoom()
+{
+ // update variable zoom types
+
+ SvxZoomType eZoomType = GetZoomType();
+ if (eZoomType == SvxZoomType::PERCENT || bInZoomUpdate)
+ return;
+
+ bInZoomUpdate = true;
+ const Fraction& rOldX = GetViewData().GetZoomX();
+ const Fraction& rOldY = GetViewData().GetZoomY();
+ tools::Long nOldPercent = tools::Long(rOldY * 100);
+ sal_uInt16 nNewZoom = CalcZoom( eZoomType, static_cast<sal_uInt16>(nOldPercent) );
+ Fraction aNew( nNewZoom, 100 );
+
+ if ( aNew != rOldX || aNew != rOldY )
+ {
+ SetZoom( aNew, aNew, false ); // always separately per sheet
+ PaintGrid();
+ PaintTop();
+ PaintLeft();
+ aViewData.GetViewShell()->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOM );
+ aViewData.GetViewShell()->GetViewFrame()->GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
+ aViewData.GetBindings().Invalidate(SID_ZOOM_IN);
+ aViewData.GetBindings().Invalidate(SID_ZOOM_OUT);
+ }
+ bInZoomUpdate = false;
+}
+
+void ScTabView::UpdateFixPos()
+{
+ bool bResize = false;
+ if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
+ if (aViewData.UpdateFixX())
+ bResize = true;
+ if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
+ if (aViewData.UpdateFixY())
+ bResize = true;
+ if (bResize)
+ RepeatResize(false);
+}
+
+void ScTabView::RepeatResize( bool bUpdateFix )
+{
+ if ( bUpdateFix )
+ {
+ ScSplitMode eHSplit = aViewData.GetHSplitMode();
+ ScSplitMode eVSplit = aViewData.GetVSplitMode();
+
+ // #i46796# UpdateFixX / UpdateFixY uses GetGridOffset, which requires the
+ // outline windows to be available. So UpdateShow has to be called before
+ // (also called from DoResize).
+ if ( eHSplit == SC_SPLIT_FIX || eVSplit == SC_SPLIT_FIX )
+ UpdateShow();
+
+ if ( eHSplit == SC_SPLIT_FIX )
+ aViewData.UpdateFixX();
+ if ( eVSplit == SC_SPLIT_FIX )
+ aViewData.UpdateFixY();
+ }
+
+ DoResize( aBorderPos, aFrameSize );
+
+ //! border must be reset ???
+}
+
+void ScTabView::GetBorderSize( SvBorder& rBorder, const Size& /* rSize */ )
+{
+ bool bScrollBars = aViewData.IsVScrollMode();
+ bool bHeaders = aViewData.IsHeaderMode();
+ bool bOutlMode = aViewData.IsOutlineMode();
+ bool bHOutline = bOutlMode && lcl_HasColOutline(aViewData);
+ bool bVOutline = bOutlMode && lcl_HasRowOutline(aViewData);
+ bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.GetTabNo() );
+
+ rBorder = SvBorder();
+
+ if (bScrollBars) // Scrollbars horizontal or vertical
+ {
+ rBorder.Right() += aVScrollBottom->GetSizePixel().Width();
+ rBorder.Bottom() += aHScrollLeft->GetSizePixel().Height();
+ }
+
+ // Outline-Controls
+ if (bVOutline && pRowOutline[SC_SPLIT_BOTTOM])
+ rBorder.Left() += pRowOutline[SC_SPLIT_BOTTOM]->GetDepthSize();
+ if (bHOutline && pColOutline[SC_SPLIT_LEFT])
+ rBorder.Top() += pColOutline[SC_SPLIT_LEFT]->GetDepthSize();
+
+ if (bHeaders) // column/row headers
+ {
+ rBorder.Left() += pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width();
+ rBorder.Top() += pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height();
+ }
+
+ if ( bLayoutRTL )
+ ::std::swap( rBorder.Left(), rBorder.Right() );
+}
+
+IMPL_LINK_NOARG(ScTabView, TabBarResize, TabBar*, void)
+{
+ if (!aViewData.IsHScrollMode())
+ return;
+
+ tools::Long nSize = pTabControl->GetSplitSize();
+
+ if (aViewData.GetHSplitMode() != SC_SPLIT_FIX)
+ {
+ tools::Long nMax = pHSplitter->GetPosPixel().X();
+ if( pTabControl->IsEffectiveRTL() )
+ nMax = pFrameWin->GetSizePixel().Width() - nMax;
+ --nMax;
+ if (nSize>nMax) nSize = nMax;
+ }
+
+ if ( nSize != pTabControl->GetSizePixel().Width() )
+ {
+ pTabControl->SetSizePixel( Size( nSize,
+ pTabControl->GetSizePixel().Height() ) );
+ RepeatResize();
+ }
+}
+
+void ScTabView::SetTabBarWidth( tools::Long nNewWidth )
+{
+ Size aSize = pTabControl->GetSizePixel();
+
+ if ( aSize.Width() != nNewWidth )
+ {
+ aSize.setWidth( nNewWidth );
+ pTabControl->SetSizePixel( aSize );
+ }
+}
+
+void ScTabView::SetRelTabBarWidth( double fRelTabBarWidth )
+{
+ if( (0.0 <= fRelTabBarWidth) && (fRelTabBarWidth <= 1.0) )
+ if( tools::Long nFrameWidth = pFrameWin->GetSizePixel().Width() )
+ SetTabBarWidth( static_cast< tools::Long >( fRelTabBarWidth * nFrameWidth + 0.5 ) );
+}
+
+void ScTabView::SetPendingRelTabBarWidth( double fRelTabBarWidth )
+{
+ mfPendingTabBarWidth = fRelTabBarWidth;
+ SetRelTabBarWidth( fRelTabBarWidth );
+}
+
+tools::Long ScTabView::GetTabBarWidth() const
+{
+ return pTabControl->GetSizePixel().Width();
+}
+
+double ScTabView::GetRelTabBarWidth()
+{
+ return 0.5;
+}
+
+ScGridWindow* ScTabView::GetActiveWin()
+{
+ ScSplitPos ePos = aViewData.GetActivePart();
+ OSL_ENSURE(pGridWin[ePos],"no active window");
+ return pGridWin[ePos];
+}
+
+void ScTabView::SetActivePointer( PointerStyle nPointer )
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ if (pWin)
+ pWin->SetPointer( nPointer );
+}
+
+void ScTabView::ActiveGrabFocus()
+{
+ ScSplitPos ePos = aViewData.GetActivePart();
+ if (pGridWin[ePos])
+ pGridWin[ePos]->GrabFocus();
+}
+
+ScSplitPos ScTabView::FindWindow( const vcl::Window* pWindow ) const
+{
+ ScSplitPos eVal = SC_SPLIT_BOTTOMLEFT; // Default
+ for (sal_uInt16 i=0; i<4; i++)
+ if ( pGridWin[i] == pWindow )
+ eVal = static_cast<ScSplitPos>(i);
+
+ return eVal;
+}
+
+Point ScTabView::GetGridOffset() const
+{
+ Point aPos;
+
+ // size as in DoResize
+
+ bool bHeaders = aViewData.IsHeaderMode();
+ bool bOutlMode = aViewData.IsOutlineMode();
+ bool bHOutline = bOutlMode && lcl_HasColOutline(aViewData);
+ bool bVOutline = bOutlMode && lcl_HasRowOutline(aViewData);
+
+ // Outline-Controls
+ if (bVOutline && pRowOutline[SC_SPLIT_BOTTOM])
+ aPos.AdjustX(pRowOutline[SC_SPLIT_BOTTOM]->GetDepthSize() );
+ if (bHOutline && pColOutline[SC_SPLIT_LEFT])
+ aPos.AdjustY(pColOutline[SC_SPLIT_LEFT]->GetDepthSize() );
+
+ if (bHeaders) // column/row headers
+ {
+ if (pRowBar[SC_SPLIT_BOTTOM])
+ aPos.AdjustX(pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width() );
+ if (pColBar[SC_SPLIT_LEFT])
+ aPos.AdjustY(pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height() );
+ }
+
+ return aPos;
+}
+
+// --- Scroll-Bars --------------------------------------------------------
+
+bool ScTabView::ScrollCommand( const CommandEvent& rCEvt, ScSplitPos ePos )
+{
+ HideNoteMarker();
+
+ bool bDone = false;
+ const CommandWheelData* pData = rCEvt.GetWheelData();
+ if (pData && pData->GetMode() == CommandWheelMode::ZOOM)
+ {
+ if ( !aViewData.GetViewShell()->GetViewFrame()->GetFrame().IsInPlace() )
+ {
+ // for ole inplace editing, the scale is defined by the visarea and client size
+ // and can't be changed directly
+
+ const Fraction& rOldY = aViewData.GetZoomY();
+ tools::Long nOld = static_cast<tools::Long>( rOldY * 100 );
+ tools::Long nNew;
+ if ( pData->GetDelta() < 0 )
+ nNew = std::max( tools::Long(MINZOOM), basegfx::zoomtools::zoomOut( nOld ));
+ else
+ nNew = std::min( tools::Long(MAXZOOM), basegfx::zoomtools::zoomIn( nOld ));
+ if ( nNew != nOld )
+ {
+ // scroll wheel doesn't set the AppOptions default
+
+ bool bSyncZoom = SC_MOD()->GetAppOptions().GetSynchronizeZoom();
+ SetZoomType( SvxZoomType::PERCENT, bSyncZoom );
+ Fraction aFract( nNew, 100 );
+ SetZoom( aFract, aFract, bSyncZoom );
+ PaintGrid();
+ PaintTop();
+ PaintLeft();
+ aViewData.GetBindings().Invalidate( SID_ATTR_ZOOM );
+ aViewData.GetBindings().Invalidate( SID_ATTR_ZOOMSLIDER );
+ aViewData.GetBindings().Invalidate( SID_ZOOM_IN);
+ aViewData.GetBindings().Invalidate( SID_ZOOM_OUT);
+ }
+
+ bDone = true;
+ }
+ }
+ else
+ {
+ ScHSplitPos eHPos = WhichH(ePos);
+ ScVSplitPos eVPos = WhichV(ePos);
+ ScrollBar* pHScroll = ( eHPos == SC_SPLIT_LEFT ) ? aHScrollLeft.get() : aHScrollRight.get();
+ ScrollBar* pVScroll = ( eVPos == SC_SPLIT_TOP ) ? aVScrollTop.get() : aVScrollBottom.get();
+ if ( pGridWin[ePos] )
+ bDone = pGridWin[ePos]->HandleScrollCommand( rCEvt, pHScroll, pVScroll );
+ }
+ return bDone;
+}
+
+IMPL_LINK_NOARG(ScTabView, EndScrollHdl, ScrollBar*, void)
+{
+ if ( bDragging )
+ {
+ UpdateScrollBars();
+ bDragging = false;
+ }
+}
+
+IMPL_LINK( ScTabView, ScrollHdl, ScrollBar*, pScroll, void )
+{
+ bool bHoriz = ( pScroll == aHScrollLeft.get() || pScroll == aHScrollRight.get() );
+ tools::Long nViewPos;
+ if ( bHoriz )
+ nViewPos = aViewData.GetPosX( (pScroll == aHScrollLeft.get()) ?
+ SC_SPLIT_LEFT : SC_SPLIT_RIGHT );
+ else
+ nViewPos = aViewData.GetPosY( (pScroll == aVScrollTop.get()) ?
+ SC_SPLIT_TOP : SC_SPLIT_BOTTOM );
+
+ bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.GetTabNo() );
+
+ ScrollType eType = pScroll->GetType();
+ if ( eType == ScrollType::Drag )
+ {
+ if (!bDragging)
+ {
+ bDragging = true;
+ nPrevDragPos = nViewPos;
+ }
+
+ // show scroll position
+ // (only QuickHelp, there is no entry for it in the status bar)
+
+ if (Help::IsQuickHelpEnabled())
+ {
+ Size aSize = pScroll->GetSizePixel();
+
+ /* Convert scrollbar mouse position to screen position. If RTL
+ mode of scrollbar differs from RTL mode of its parent, then the
+ direct call to Window::OutputToNormalizedScreenPixel() will
+ give unusable results, because calculation of screen position
+ is based on parent orientation and expects equal orientation of
+ the child position. Need to mirror mouse position before. */
+ Point aMousePos = pScroll->GetPointerPosPixel();
+ if( pScroll->IsRTLEnabled() != pScroll->GetParent()->IsRTLEnabled() )
+ aMousePos.setX( aSize.Width() - aMousePos.X() - 1 );
+ aMousePos = pScroll->OutputToNormalizedScreenPixel( aMousePos );
+
+ // convert top-left position of scrollbar to screen position
+ Point aPos = pScroll->OutputToNormalizedScreenPixel( Point() );
+
+ // get scrollbar scroll position for help text (row number/column name)
+ tools::Long nScrollMin = 0; // simulate RangeMin
+ if ( aViewData.GetHSplitMode()==SC_SPLIT_FIX && pScroll == aHScrollRight.get() )
+ nScrollMin = aViewData.GetFixPosX();
+ if ( aViewData.GetVSplitMode()==SC_SPLIT_FIX && pScroll == aVScrollBottom.get() )
+ nScrollMin = aViewData.GetFixPosY();
+ tools::Long nScrollPos = GetScrollBarPos( *pScroll ) + nScrollMin;
+
+ OUString aHelpStr;
+ tools::Rectangle aRect;
+ QuickHelpFlags nAlign;
+ if (bHoriz)
+ {
+ aHelpStr = ScResId(STR_COLUMN) +
+ " " + ScColToAlpha(static_cast<SCCOL>(nScrollPos));
+
+ aRect.SetLeft( aMousePos.X() );
+ aRect.SetTop( aPos.Y() - 4 );
+ nAlign = QuickHelpFlags::Bottom|QuickHelpFlags::Center;
+ }
+ else
+ {
+ aHelpStr = ScResId(STR_ROW) +
+ " " + OUString::number(nScrollPos + 1);
+
+ // show quicktext always inside sheet area
+ aRect.SetLeft( bLayoutRTL ? (aPos.X() + aSize.Width() + 8) : (aPos.X() - 8) );
+ aRect.SetTop( aMousePos.Y() );
+ nAlign = (bLayoutRTL ? QuickHelpFlags::Left : QuickHelpFlags::Right) | QuickHelpFlags::VCenter;
+ }
+ aRect.SetRight( aRect.Left() );
+ aRect.SetBottom( aRect.Top() );
+
+ Help::ShowQuickHelp(pScroll->GetParent(), aRect, aHelpStr, nAlign);
+ }
+ }
+
+ tools::Long nDelta = pScroll->GetDelta();
+ switch ( eType )
+ {
+ case ScrollType::LineUp:
+ nDelta = -1;
+ break;
+ case ScrollType::LineDown:
+ nDelta = 1;
+ break;
+ case ScrollType::PageUp:
+ if ( pScroll == aHScrollLeft.get() ) nDelta = -static_cast<tools::Long>(aViewData.PrevCellsX( SC_SPLIT_LEFT ));
+ if ( pScroll == aHScrollRight.get() ) nDelta = -static_cast<tools::Long>(aViewData.PrevCellsX( SC_SPLIT_RIGHT ));
+ if ( pScroll == aVScrollTop.get() ) nDelta = -static_cast<tools::Long>(aViewData.PrevCellsY( SC_SPLIT_TOP ));
+ if ( pScroll == aVScrollBottom.get() ) nDelta = -static_cast<tools::Long>(aViewData.PrevCellsY( SC_SPLIT_BOTTOM ));
+ if (nDelta==0) nDelta=-1;
+ break;
+ case ScrollType::PageDown:
+ if ( pScroll == aHScrollLeft.get() ) nDelta = aViewData.VisibleCellsX( SC_SPLIT_LEFT );
+ if ( pScroll == aHScrollRight.get() ) nDelta = aViewData.VisibleCellsX( SC_SPLIT_RIGHT );
+ if ( pScroll == aVScrollTop.get() ) nDelta = aViewData.VisibleCellsY( SC_SPLIT_TOP );
+ if ( pScroll == aVScrollBottom.get() ) nDelta = aViewData.VisibleCellsY( SC_SPLIT_BOTTOM );
+ if (nDelta==0) nDelta=1;
+ break;
+ case ScrollType::Drag:
+ {
+ // only scroll in the correct direction, do not jitter around hidden ranges
+ tools::Long nScrollMin = 0; // simulate RangeMin
+ if ( aViewData.GetHSplitMode()==SC_SPLIT_FIX && pScroll == aHScrollRight.get() )
+ nScrollMin = aViewData.GetFixPosX();
+ if ( aViewData.GetVSplitMode()==SC_SPLIT_FIX && pScroll == aVScrollBottom.get() )
+ nScrollMin = aViewData.GetFixPosY();
+
+ tools::Long nScrollPos = GetScrollBarPos( *pScroll ) + nScrollMin;
+ nDelta = nScrollPos - nViewPos;
+ if ( nScrollPos > nPrevDragPos )
+ {
+ if (nDelta<0) nDelta=0;
+ }
+ else if ( nScrollPos < nPrevDragPos )
+ {
+ if (nDelta>0) nDelta=0;
+ }
+ else
+ nDelta = 0;
+ nPrevDragPos = nScrollPos;
+ }
+ break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+
+ if (nDelta)
+ {
+ bool bUpdate = ( eType != ScrollType::Drag ); // don't alter the ranges while dragging
+ if ( bHoriz )
+ ScrollX( nDelta, (pScroll == aHScrollLeft.get()) ? SC_SPLIT_LEFT : SC_SPLIT_RIGHT, bUpdate );
+ else
+ ScrollY( nDelta, (pScroll == aVScrollTop.get()) ? SC_SPLIT_TOP : SC_SPLIT_BOTTOM, bUpdate );
+ }
+}
+
+void ScTabView::ScrollX( tools::Long nDeltaX, ScHSplitPos eWhich, bool bUpdBars )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCCOL nOldX = aViewData.GetPosX(eWhich);
+ SCCOL nNewX = nOldX + static_cast<SCCOL>(nDeltaX);
+ if ( nNewX < 0 )
+ {
+ nDeltaX -= nNewX;
+ nNewX = 0;
+ }
+ if ( nNewX > rDoc.MaxCol() )
+ {
+ nDeltaX -= nNewX - rDoc.MaxCol();
+ nNewX = rDoc.MaxCol();
+ }
+
+ SCCOL nDir = ( nDeltaX > 0 ) ? 1 : -1;
+ SCTAB nTab = aViewData.GetTabNo();
+ while ( rDoc.ColHidden(nNewX, nTab) &&
+ nNewX+nDir >= 0 && nNewX+nDir <= rDoc.MaxCol() )
+ nNewX = sal::static_int_cast<SCCOL>( nNewX + nDir );
+
+ // freeze
+
+ if (aViewData.GetHSplitMode() == SC_SPLIT_FIX)
+ {
+ if (eWhich == SC_SPLIT_LEFT)
+ nNewX = nOldX; // always keep the left part
+ else
+ {
+ SCCOL nFixX = aViewData.GetFixPosX();
+ if (nNewX < nFixX)
+ nNewX = nFixX;
+ }
+ }
+ if (nNewX == nOldX)
+ return;
+
+ HideAllCursors();
+
+ if ( nNewX >= 0 && nNewX <= rDoc.MaxCol() && nDeltaX )
+ {
+ SCCOL nTrackX = std::max( nOldX, nNewX );
+
+ // with VCL Update() affects all windows at the moment, that is why
+ // calling Update after scrolling of the GridWindow would possibly
+ // already have painted the column/row bar with updated position. -
+ // Therefore call Update once before on column/row bar
+ if (pColBar[eWhich])
+ pColBar[eWhich]->PaintImmediately();
+
+ tools::Long nOldPos = aViewData.GetScrPos( nTrackX, 0, eWhich ).X();
+ aViewData.SetPosX( eWhich, nNewX );
+ tools::Long nDiff = aViewData.GetScrPos( nTrackX, 0, eWhich ).X() - nOldPos;
+
+ if ( eWhich==SC_SPLIT_LEFT )
+ {
+ pGridWin[SC_SPLIT_BOTTOMLEFT]->ScrollPixel( nDiff, 0 );
+ if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ pGridWin[SC_SPLIT_TOPLEFT]->ScrollPixel( nDiff, 0 );
+ }
+ else
+ {
+ pGridWin[SC_SPLIT_BOTTOMRIGHT]->ScrollPixel( nDiff, 0 );
+ if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ pGridWin[SC_SPLIT_TOPRIGHT]->ScrollPixel( nDiff, 0 );
+ }
+ if (pColBar[eWhich]) { pColBar[eWhich]->Scroll( nDiff,0 ); pColBar[eWhich]->PaintImmediately(); }
+ if (pColOutline[eWhich]) pColOutline[eWhich]->ScrollPixel( nDiff );
+ if (bUpdBars)
+ UpdateScrollBars();
+ }
+
+ if (nDeltaX==1 || nDeltaX==-1)
+ pGridWin[aViewData.GetActivePart()]->PaintImmediately();
+
+ ShowAllCursors();
+
+ SetNewVisArea(); // MapMode must already be set
+
+ TestHintWindow();
+}
+
+void ScTabView::ScrollY( tools::Long nDeltaY, ScVSplitPos eWhich, bool bUpdBars )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCROW nOldY = aViewData.GetPosY(eWhich);
+ SCROW nNewY = nOldY + static_cast<SCROW>(nDeltaY);
+ if ( nNewY < 0 )
+ {
+ nDeltaY -= nNewY;
+ nNewY = 0;
+ }
+ if ( nNewY > rDoc.MaxRow() )
+ {
+ nDeltaY -= nNewY - rDoc.MaxRow();
+ nNewY = rDoc.MaxRow();
+ }
+
+ SCROW nDir = ( nDeltaY > 0 ) ? 1 : -1;
+ SCTAB nTab = aViewData.GetTabNo();
+ while ( rDoc.RowHidden(nNewY, nTab) &&
+ nNewY+nDir >= 0 && nNewY+nDir <= rDoc.MaxRow() )
+ nNewY += nDir;
+
+ // freeze
+
+ if (aViewData.GetVSplitMode() == SC_SPLIT_FIX)
+ {
+ if (eWhich == SC_SPLIT_TOP)
+ nNewY = nOldY; // always keep the upper part
+ else
+ {
+ SCROW nFixY = aViewData.GetFixPosY();
+ if (nNewY < nFixY)
+ nNewY = nFixY;
+ }
+ }
+ if (nNewY == nOldY)
+ return;
+
+ HideAllCursors();
+
+ if ( nNewY >= 0 && nNewY <= rDoc.MaxRow() && nDeltaY )
+ {
+ SCROW nTrackY = std::max( nOldY, nNewY );
+
+ // adjust row headers before the actual scrolling, so it does not get painted twice
+ // PosY may then also not be set yet, pass on new value
+ SCROW nUNew = nNewY;
+ UpdateHeaderWidth( &eWhich, &nUNew ); // adjust row headers
+
+ if (pRowBar[eWhich])
+ pRowBar[eWhich]->PaintImmediately();
+
+ tools::Long nOldPos = aViewData.GetScrPos( 0, nTrackY, eWhich ).Y();
+ aViewData.SetPosY( eWhich, nNewY );
+ tools::Long nDiff = aViewData.GetScrPos( 0, nTrackY, eWhich ).Y() - nOldPos;
+
+ if ( eWhich==SC_SPLIT_TOP )
+ {
+ pGridWin[SC_SPLIT_TOPLEFT]->ScrollPixel( 0, nDiff );
+ if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ pGridWin[SC_SPLIT_TOPRIGHT]->ScrollPixel( 0, nDiff );
+ }
+ else
+ {
+ pGridWin[SC_SPLIT_BOTTOMLEFT]->ScrollPixel( 0, nDiff );
+ if ( aViewData.GetHSplitMode() != SC_SPLIT_NONE )
+ pGridWin[SC_SPLIT_BOTTOMRIGHT]->ScrollPixel( 0, nDiff );
+ }
+ if (pRowBar[eWhich]) { pRowBar[eWhich]->Scroll( 0,nDiff ); pRowBar[eWhich]->PaintImmediately(); }
+ if (pRowOutline[eWhich]) pRowOutline[eWhich]->ScrollPixel( nDiff );
+ if (bUpdBars)
+ UpdateScrollBars();
+ }
+
+ if (nDeltaY==1 || nDeltaY==-1)
+ pGridWin[aViewData.GetActivePart()]->PaintImmediately();
+
+ ShowAllCursors();
+
+ SetNewVisArea(); // MapMode must already be set
+
+ TestHintWindow();
+}
+
+void ScTabView::ScrollLines( tools::Long nDeltaX, tools::Long nDeltaY )
+{
+ ScSplitPos eWhich = aViewData.GetActivePart();
+ if (nDeltaX)
+ ScrollX(nDeltaX,WhichH(eWhich));
+ if (nDeltaY)
+ ScrollY(nDeltaY,WhichV(eWhich));
+}
+
+namespace
+{
+
+SCROW lcl_LastVisible( const ScViewData& rViewData )
+{
+ // If many rows are hidden at end of the document,
+ // then there should not be a switch to wide row headers because of this
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+
+ SCROW nVis = rDoc.MaxRow();
+ SCROW startRow;
+ while ( nVis > 0 && rDoc.GetRowHeight( nVis, nTab, &startRow, nullptr ) == 0 )
+ nVis = std::max<SCROW>( startRow - 1, 0 );
+ return nVis;
+}
+
+} // anonymous namespace
+
+void ScTabView::UpdateHeaderWidth( const ScVSplitPos* pWhich, const SCROW* pPosY )
+{
+ if (!pRowBar[SC_SPLIT_BOTTOM])
+ return;
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCROW nEndPos = rDoc.MaxRow();
+ if ( !aViewData.GetViewShell()->GetViewFrame()->GetFrame().IsInPlace() )
+ {
+ // for OLE Inplace always MAXROW
+
+ if ( pWhich && *pWhich == SC_SPLIT_BOTTOM && pPosY )
+ nEndPos = *pPosY;
+ else
+ nEndPos = aViewData.GetPosY( SC_SPLIT_BOTTOM );
+ nEndPos += aViewData.CellsAtY( nEndPos, 1, SC_SPLIT_BOTTOM ); // VisibleCellsY
+ if (nEndPos > rDoc.MaxRow())
+ nEndPos = lcl_LastVisible( aViewData );
+
+ if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ {
+ SCROW nTopEnd;
+ if ( pWhich && *pWhich == SC_SPLIT_TOP && pPosY )
+ nTopEnd = *pPosY;
+ else
+ nTopEnd = aViewData.GetPosY( SC_SPLIT_TOP );
+ nTopEnd += aViewData.CellsAtY( nTopEnd, 1, SC_SPLIT_TOP );// VisibleCellsY
+ if (nTopEnd > rDoc.MaxRow())
+ nTopEnd = lcl_LastVisible( aViewData );
+
+ if ( nTopEnd > nEndPos )
+ nEndPos = nTopEnd;
+ }
+ }
+
+ tools::Long nSmall = pRowBar[SC_SPLIT_BOTTOM]->GetSmallWidth();
+ tools::Long nBig = pRowBar[SC_SPLIT_BOTTOM]->GetBigWidth();
+ tools::Long nDiff = nBig - nSmall;
+
+ if (nEndPos>10000)
+ nEndPos = 10000;
+ else if (nEndPos<1) // avoid extra step at 0 (when only one row is visible)
+ nEndPos = 1;
+ tools::Long nWidth = nBig - ( 10000 - nEndPos ) * nDiff / 10000;
+
+ if (nWidth == pRowBar[SC_SPLIT_BOTTOM]->GetWidth() || bInUpdateHeader)
+ return;
+
+ bInUpdateHeader = true;
+
+ pRowBar[SC_SPLIT_BOTTOM]->SetWidth( nWidth );
+ if (pRowBar[SC_SPLIT_TOP])
+ pRowBar[SC_SPLIT_TOP]->SetWidth( nWidth );
+
+ RepeatResize();
+
+ // on VCL there are endless updates (each Update is valid for all windows)
+ //aCornerButton->Update(); // otherwise this never gets an Update
+
+ bInUpdateHeader = false;
+}
+
+static void ShowHide( vcl::Window* pWin, bool bShow )
+{
+ OSL_ENSURE(pWin || !bShow, "window is not present");
+ if (pWin)
+ pWin->Show(bShow);
+}
+
+void ScTabView::UpdateShow()
+{
+ bool bHScrollMode = aViewData.IsHScrollMode();
+ bool bVScrollMode = aViewData.IsVScrollMode();
+ bool bTabMode = aViewData.IsTabMode();
+ bool bOutlMode = aViewData.IsOutlineMode();
+ bool bHOutline = bOutlMode && lcl_HasColOutline(aViewData);
+ bool bVOutline = bOutlMode && lcl_HasRowOutline(aViewData);
+ bool bHeader = aViewData.IsHeaderMode();
+
+ bool bShowH = ( aViewData.GetHSplitMode() != SC_SPLIT_NONE );
+ bool bShowV = ( aViewData.GetVSplitMode() != SC_SPLIT_NONE );
+
+ if ( aViewData.GetDocShell()->IsPreview() )
+ bHScrollMode = bVScrollMode = bTabMode = bHeader = bHOutline = bVOutline = false;
+
+ // create Windows
+
+ if (bShowH && !pGridWin[SC_SPLIT_BOTTOMRIGHT])
+ {
+ pGridWin[SC_SPLIT_BOTTOMRIGHT] = VclPtr<ScGridWindow>::Create( pFrameWin, aViewData, SC_SPLIT_BOTTOMRIGHT );
+ DoAddWin( pGridWin[SC_SPLIT_BOTTOMRIGHT] );
+ }
+ if (bShowV && !pGridWin[SC_SPLIT_TOPLEFT])
+ {
+ pGridWin[SC_SPLIT_TOPLEFT] = VclPtr<ScGridWindow>::Create( pFrameWin, aViewData, SC_SPLIT_TOPLEFT );
+ DoAddWin( pGridWin[SC_SPLIT_TOPLEFT] );
+ }
+ if (bShowH && bShowV && !pGridWin[SC_SPLIT_TOPRIGHT])
+ {
+ pGridWin[SC_SPLIT_TOPRIGHT] = VclPtr<ScGridWindow>::Create( pFrameWin, aViewData, SC_SPLIT_TOPRIGHT );
+ DoAddWin( pGridWin[SC_SPLIT_TOPRIGHT] );
+ }
+
+ if (bHOutline && !pColOutline[SC_SPLIT_LEFT])
+ pColOutline[SC_SPLIT_LEFT] = VclPtr<ScOutlineWindow>::Create( pFrameWin, SC_OUTLINE_HOR, &aViewData, SC_SPLIT_BOTTOMLEFT );
+ if (bShowH && bHOutline && !pColOutline[SC_SPLIT_RIGHT])
+ pColOutline[SC_SPLIT_RIGHT] = VclPtr<ScOutlineWindow>::Create( pFrameWin, SC_OUTLINE_HOR, &aViewData, SC_SPLIT_BOTTOMRIGHT );
+
+ if (bVOutline && !pRowOutline[SC_SPLIT_BOTTOM])
+ pRowOutline[SC_SPLIT_BOTTOM] = VclPtr<ScOutlineWindow>::Create( pFrameWin, SC_OUTLINE_VER, &aViewData, SC_SPLIT_BOTTOMLEFT );
+ if (bShowV && bVOutline && !pRowOutline[SC_SPLIT_TOP])
+ pRowOutline[SC_SPLIT_TOP] = VclPtr<ScOutlineWindow>::Create( pFrameWin, SC_OUTLINE_VER, &aViewData, SC_SPLIT_TOPLEFT );
+
+ if (bShowH && bHeader && !pColBar[SC_SPLIT_RIGHT])
+ pColBar[SC_SPLIT_RIGHT] = VclPtr<ScColBar>::Create( pFrameWin, SC_SPLIT_RIGHT,
+ &aHdrFunc, pHdrSelEng.get(), this );
+ if (bShowV && bHeader && !pRowBar[SC_SPLIT_TOP])
+ pRowBar[SC_SPLIT_TOP] = VclPtr<ScRowBar>::Create( pFrameWin, SC_SPLIT_TOP,
+ &aHdrFunc, pHdrSelEng.get(), this );
+
+ // show Windows
+
+ ShowHide( aHScrollLeft.get(), bHScrollMode );
+ ShowHide( aHScrollRight.get(), bShowH && bHScrollMode );
+ ShowHide( aVScrollBottom.get(), bVScrollMode );
+ ShowHide( aVScrollTop.get(), bShowV && bVScrollMode );
+ ShowHide( aScrollBarBox.get(), bVScrollMode || bHScrollMode );
+
+ ShowHide( pHSplitter, bHScrollMode || bShowH ); // always generated
+ ShowHide( pVSplitter, bVScrollMode || bShowV );
+ ShowHide( pTabControl, bTabMode );
+
+ // from here dynamically generated
+
+ ShowHide( pGridWin[SC_SPLIT_BOTTOMRIGHT], bShowH );
+ ShowHide( pGridWin[SC_SPLIT_TOPLEFT], bShowV );
+ ShowHide( pGridWin[SC_SPLIT_TOPRIGHT], bShowH && bShowV );
+
+ ShowHide( pColOutline[SC_SPLIT_LEFT], bHOutline );
+ ShowHide( pColOutline[SC_SPLIT_RIGHT], bShowH && bHOutline );
+
+ ShowHide( pRowOutline[SC_SPLIT_BOTTOM], bVOutline );
+ ShowHide( pRowOutline[SC_SPLIT_TOP], bShowV && bVOutline );
+
+ ShowHide( pColBar[SC_SPLIT_RIGHT], bShowH && bHeader );
+ ShowHide( pRowBar[SC_SPLIT_TOP], bShowV && bHeader );
+
+ //! register new Gridwindows
+}
+
+bool ScTabView::UpdateVisibleRange()
+{
+ bool bChanged = false;
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ {
+ if (!pWin || !pWin->IsVisible())
+ continue;
+
+ if (pWin->UpdateVisibleRange())
+ bChanged = true;
+ }
+
+ return bChanged;
+}
+
+// --- Splitter --------------------------------------------------------
+
+IMPL_LINK( ScTabView, SplitHdl, Splitter*, pSplitter, void )
+{
+ if ( pSplitter == pHSplitter )
+ DoHSplit( pHSplitter->GetSplitPosPixel() );
+ else
+ DoVSplit( pVSplitter->GetSplitPosPixel() );
+
+ if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX || aViewData.GetVSplitMode() == SC_SPLIT_FIX )
+ FreezeSplitters( true );
+
+ DoResize( aBorderPos, aFrameSize );
+}
+
+void ScTabView::DoHSplit(tools::Long nSplitPos)
+{
+ // nSplitPos is the real pixel position on the frame window,
+ // mirroring for RTL has to be done here.
+
+ bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.GetTabNo() );
+ if ( bLayoutRTL )
+ nSplitPos = pFrameWin->GetOutputSizePixel().Width() - nSplitPos - 1;
+
+ tools::Long nMinPos;
+ tools::Long nMaxPos;
+
+ nMinPos = SPLIT_MARGIN;
+ if ( pRowBar[SC_SPLIT_BOTTOM] && pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width() >= nMinPos )
+ nMinPos = pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width() + 1;
+ nMaxPos = aFrameSize.Width() - SPLIT_MARGIN;
+
+ ScSplitMode aOldMode = aViewData.GetHSplitMode();
+ ScSplitMode aNewMode = SC_SPLIT_NORMAL;
+
+ aViewData.SetHSplitPos( nSplitPos );
+ if ( nSplitPos < nMinPos || nSplitPos > nMaxPos )
+ aNewMode = SC_SPLIT_NONE;
+
+ aViewData.SetHSplitMode( aNewMode );
+
+ if ( aNewMode == aOldMode )
+ return;
+
+ UpdateShow(); // before ActivatePart !!
+
+ if ( aNewMode == SC_SPLIT_NONE )
+ {
+ if (aViewData.GetActivePart() == SC_SPLIT_TOPRIGHT)
+ ActivatePart( SC_SPLIT_TOPLEFT );
+ if (aViewData.GetActivePart() == SC_SPLIT_BOTTOMRIGHT)
+ ActivatePart( SC_SPLIT_BOTTOMLEFT );
+ }
+ else
+ {
+ SCCOL nOldDelta = aViewData.GetPosX( SC_SPLIT_LEFT );
+ tools::Long nLeftWidth = nSplitPos - pRowBar[SC_SPLIT_BOTTOM]->GetSizePixel().Width();
+ if ( nLeftWidth < 0 ) nLeftWidth = 0;
+ SCCOL nNewDelta = nOldDelta + aViewData.CellsAtX( nOldDelta, 1, SC_SPLIT_LEFT,
+ static_cast<sal_uInt16>(nLeftWidth) );
+ ScDocument& rDoc = aViewData.GetDocument();
+ if ( nNewDelta > rDoc.MaxCol() )
+ nNewDelta = rDoc.MaxCol();
+ aViewData.SetPosX( SC_SPLIT_RIGHT, nNewDelta );
+ if ( nNewDelta > aViewData.GetCurX() )
+ ActivatePart( (WhichV(aViewData.GetActivePart()) == SC_SPLIT_BOTTOM) ?
+ SC_SPLIT_BOTTOMLEFT : SC_SPLIT_TOPLEFT );
+ else
+ ActivatePart( (WhichV(aViewData.GetActivePart()) == SC_SPLIT_BOTTOM) ?
+ SC_SPLIT_BOTTOMRIGHT : SC_SPLIT_TOPRIGHT );
+ }
+
+ // Form Layer needs to know the visible part of all windows
+ // that is why MapMode must already be correct here
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ if (pWin)
+ pWin->SetMapMode( pWin->GetDrawMapMode() );
+ SetNewVisArea();
+
+ PaintGrid();
+ PaintTop();
+
+ InvalidateSplit();
+}
+
+void ScTabView::DoVSplit(tools::Long nSplitPos)
+{
+ tools::Long nMinPos;
+ tools::Long nMaxPos;
+ SCROW nOldDelta;
+
+ nMinPos = SPLIT_MARGIN;
+ if ( pColBar[SC_SPLIT_LEFT] && pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height() >= nMinPos )
+ nMinPos = pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height() + 1;
+ nMaxPos = aFrameSize.Height() - SPLIT_MARGIN;
+
+ ScSplitMode aOldMode = aViewData.GetVSplitMode();
+ ScSplitMode aNewMode = SC_SPLIT_NORMAL;
+
+ aViewData.SetVSplitPos( nSplitPos );
+ if ( nSplitPos < nMinPos || nSplitPos > nMaxPos )
+ aNewMode = SC_SPLIT_NONE;
+
+ aViewData.SetVSplitMode( aNewMode );
+
+ if ( aNewMode == aOldMode )
+ return;
+
+ UpdateShow(); // before ActivatePart !!
+
+ if ( aNewMode == SC_SPLIT_NONE )
+ {
+ nOldDelta = aViewData.GetPosY( SC_SPLIT_TOP );
+ aViewData.SetPosY( SC_SPLIT_BOTTOM, nOldDelta );
+
+ if (aViewData.GetActivePart() == SC_SPLIT_TOPLEFT)
+ ActivatePart( SC_SPLIT_BOTTOMLEFT );
+ if (aViewData.GetActivePart() == SC_SPLIT_TOPRIGHT)
+ ActivatePart( SC_SPLIT_BOTTOMRIGHT );
+ }
+ else
+ {
+ if ( aOldMode == SC_SPLIT_NONE )
+ nOldDelta = aViewData.GetPosY( SC_SPLIT_BOTTOM );
+ else
+ nOldDelta = aViewData.GetPosY( SC_SPLIT_TOP );
+
+ aViewData.SetPosY( SC_SPLIT_TOP, nOldDelta );
+ tools::Long nTopHeight = nSplitPos - pColBar[SC_SPLIT_LEFT]->GetSizePixel().Height();
+ if ( nTopHeight < 0 ) nTopHeight = 0;
+ SCROW nNewDelta = nOldDelta + aViewData.CellsAtY( nOldDelta, 1, SC_SPLIT_TOP,
+ static_cast<sal_uInt16>(nTopHeight) );
+ ScDocument& rDoc = aViewData.GetDocument();
+ if ( nNewDelta > rDoc.MaxRow() )
+ nNewDelta = rDoc.MaxRow();
+ aViewData.SetPosY( SC_SPLIT_BOTTOM, nNewDelta );
+ if ( nNewDelta > aViewData.GetCurY() )
+ ActivatePart( (WhichH(aViewData.GetActivePart()) == SC_SPLIT_LEFT) ?
+ SC_SPLIT_TOPLEFT : SC_SPLIT_TOPRIGHT );
+ else
+ ActivatePart( (WhichH(aViewData.GetActivePart()) == SC_SPLIT_LEFT) ?
+ SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT );
+ }
+
+ // Form Layer needs to know the visible part of all windows
+ // that is why MapMode must already be correct here
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ if (pWin)
+ pWin->SetMapMode( pWin->GetDrawMapMode() );
+ SetNewVisArea();
+
+ PaintGrid();
+ PaintLeft();
+
+ InvalidateSplit();
+}
+
+Point ScTabView::GetInsertPos() const
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCCOL nCol = aViewData.GetCurX();
+ SCROW nRow = aViewData.GetCurY();
+ SCTAB nTab = aViewData.GetTabNo();
+ tools::Long nPosX = 0;
+ for (SCCOL i=0; i<nCol; i++)
+ nPosX += rDoc.GetColWidth(i,nTab);
+ nPosX = o3tl::convert(nPosX, o3tl::Length::twip, o3tl::Length::mm100);
+ if ( rDoc.IsNegativePage( nTab ) )
+ nPosX = -nPosX;
+ tools::Long nPosY = rDoc.GetRowHeight( 0, nRow-1, nTab);
+ nPosY = o3tl::convert(nPosY, o3tl::Length::twip, o3tl::Length::mm100);
+ return Point(nPosX,nPosY);
+}
+
+Point ScTabView::GetChartInsertPos( const Size& rSize, const ScRange& rCellRange )
+{
+ Point aInsertPos;
+ const tools::Long nBorder = 100; // leave 1mm for border
+ tools::Long nNeededWidth = rSize.Width() + 2 * nBorder;
+ tools::Long nNeededHeight = rSize.Height() + 2 * nBorder;
+
+ // use the active window, or lower/right if frozen (as in CalcZoom)
+ ScSplitPos eUsedPart = aViewData.GetActivePart();
+ if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
+ eUsedPart = (WhichV(eUsedPart)==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT;
+ if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
+ eUsedPart = (WhichH(eUsedPart)==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT;
+
+ ScGridWindow* pWin = pGridWin[eUsedPart].get();
+ OSL_ENSURE( pWin, "Window not found" );
+ if (pWin)
+ {
+ ActivatePart( eUsedPart );
+
+ // get the visible rectangle in logic units
+ bool bLOKActive = comphelper::LibreOfficeKit::isActive();
+ MapMode aDrawMode = pWin->GetDrawMapMode();
+ tools::Rectangle aVisible(
+ bLOKActive ?
+ OutputDevice::LogicToLogic( aViewData.getLOKVisibleArea(), MapMode(MapUnit::MapTwip), MapMode(MapUnit::Map100thMM) )
+ : pWin->PixelToLogic( tools::Rectangle( Point(0,0), pWin->GetOutputSizePixel() ), aDrawMode ) );
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ tools::Long nDocX = o3tl::convert(rDoc.GetColOffset(rDoc.MaxCol() + 1, nTab), o3tl::Length::twip, o3tl::Length::mm100) * nLayoutSign;
+ tools::Long nDocY = o3tl::convert(rDoc.GetRowOffset( rDoc.MaxRow() + 1, nTab ), o3tl::Length::twip, o3tl::Length::mm100);
+
+ if ( aVisible.Left() * nLayoutSign > nDocX * nLayoutSign )
+ aVisible.SetLeft( nDocX );
+ if ( aVisible.Right() * nLayoutSign > nDocX * nLayoutSign )
+ aVisible.SetRight( nDocX );
+ if ( aVisible.Top() > nDocY )
+ aVisible.SetTop( nDocY );
+ if ( aVisible.Bottom() > nDocY )
+ aVisible.SetBottom( nDocY );
+
+ // get the logic position of the selection
+
+ tools::Rectangle aSelection = rDoc.GetMMRect( rCellRange.aStart.Col(), rCellRange.aStart.Row(),
+ rCellRange.aEnd.Col(), rCellRange.aEnd.Row(), nTab );
+
+ if (bLOKActive && bLayoutRTL)
+ {
+ // In this case we operate in negative X coordinates. The rectangle aSelection already
+ // has negative X coordinates. So the x coordinates in the rectangle aVisible(from getLOKVisibleArea)
+ // need be negated to match.
+ aVisible = tools::Rectangle(-aVisible.Right(), aVisible.Top(), -aVisible.Left(), aVisible.Bottom());
+ }
+
+ tools::Long nLeftSpace = aSelection.Left() - aVisible.Left();
+ tools::Long nRightSpace = aVisible.Right() - aSelection.Right();
+ tools::Long nTopSpace = aSelection.Top() - aVisible.Top();
+ tools::Long nBottomSpace = aVisible.Bottom() - aSelection.Bottom();
+
+ bool bFitLeft = ( nLeftSpace >= nNeededWidth );
+ bool bFitRight = ( nRightSpace >= nNeededWidth );
+
+ if ( bFitLeft || bFitRight )
+ {
+ // first preference: completely left or right of the selection
+
+ // if both fit, prefer left in RTL mode, right otherwise
+ bool bPutLeft = bFitLeft && ( bLayoutRTL || !bFitRight );
+
+ if ( bPutLeft )
+ aInsertPos.setX( aSelection.Left() - nNeededWidth );
+ else
+ aInsertPos.setX( aSelection.Right() + 1 );
+
+ // align with top of selection (is moved again if it doesn't fit)
+ aInsertPos.setY( std::max( aSelection.Top(), aVisible.Top() ) );
+ }
+ else if ( nTopSpace >= nNeededHeight || nBottomSpace >= nNeededHeight )
+ {
+ // second preference: completely above or below the selection
+ if ( nBottomSpace > nNeededHeight ) // bottom is preferred
+ aInsertPos.setY( aSelection.Bottom() + 1 );
+ else
+ aInsertPos.setY( aSelection.Top() - nNeededHeight );
+
+ // align with (logic) left edge of selection (moved again if it doesn't fit)
+ if ( bLayoutRTL )
+ aInsertPos.setX( std::min( aSelection.Right(), aVisible.Right() ) - nNeededWidth + 1 );
+ else
+ aInsertPos.setX( std::max( aSelection.Left(), aVisible.Left() ) );
+ }
+ else
+ {
+ // place to the (logic) right of the selection and move so it fits
+
+ if ( bLayoutRTL )
+ aInsertPos.setX( aSelection.Left() - nNeededWidth );
+ else
+ aInsertPos.setX( aSelection.Right() + 1 );
+ aInsertPos.setY( std::max( aSelection.Top(), aVisible.Top() ) );
+ }
+
+ // move the position if the object doesn't fit in the screen
+
+ tools::Rectangle aCompareRect( aInsertPos, Size( nNeededWidth, nNeededHeight ) );
+ if ( aCompareRect.Right() > aVisible.Right() )
+ aInsertPos.AdjustX( -(aCompareRect.Right() - aVisible.Right()) );
+ if ( aCompareRect.Bottom() > aVisible.Bottom() )
+ aInsertPos.AdjustY( -(aCompareRect.Bottom() - aVisible.Bottom()) );
+
+ if ( aInsertPos.X() < aVisible.Left() )
+ aInsertPos.setX( aVisible.Left() );
+ if ( aInsertPos.Y() < aVisible.Top() )
+ aInsertPos.setY( aVisible.Top() );
+
+ // nNeededWidth / nNeededHeight includes all borders - move aInsertPos to the
+ // object position, inside the border
+
+ aInsertPos.AdjustX(nBorder );
+ aInsertPos.AdjustY(nBorder );
+ }
+ return aInsertPos;
+}
+
+Point ScTabView::GetChartDialogPos( const Size& rDialogSize, const tools::Rectangle& rLogicChart )
+{
+ // rDialogSize must be in pixels, rLogicChart in 1/100 mm. Return value is in pixels.
+
+ Point aRet;
+
+ // use the active window, or lower/right if frozen (as in CalcZoom)
+ ScSplitPos eUsedPart = aViewData.GetActivePart();
+ if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
+ eUsedPart = (WhichV(eUsedPart)==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT;
+ if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
+ eUsedPart = (WhichH(eUsedPart)==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT;
+
+ ScGridWindow* pWin = pGridWin[eUsedPart].get();
+ OSL_ENSURE( pWin, "Window not found" );
+ if (pWin)
+ {
+ MapMode aDrawMode = pWin->GetDrawMapMode();
+ tools::Rectangle aObjPixel = pWin->LogicToPixel( rLogicChart, aDrawMode );
+ tools::Rectangle aObjAbs( pWin->OutputToAbsoluteScreenPixel( aObjPixel.TopLeft() ),
+ pWin->OutputToAbsoluteScreenPixel( aObjPixel.BottomRight() ) );
+
+ tools::Rectangle aDesktop = pWin->GetDesktopRectPixel();
+ Size aSpace = pWin->LogicToPixel( Size(8, 12), MapMode(MapUnit::MapAppFont));
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+
+ bool bCenterHor = false;
+
+ if ( aDesktop.Bottom() - aObjAbs.Bottom() >= rDialogSize.Height() + aSpace.Height() )
+ {
+ // first preference: below the chart
+
+ aRet.setY( aObjAbs.Bottom() + aSpace.Height() );
+ bCenterHor = true;
+ }
+ else if ( aObjAbs.Top() - aDesktop.Top() >= rDialogSize.Height() + aSpace.Height() )
+ {
+ // second preference: above the chart
+
+ aRet.setY( aObjAbs.Top() - rDialogSize.Height() - aSpace.Height() );
+ bCenterHor = true;
+ }
+ else
+ {
+ bool bFitLeft = ( aObjAbs.Left() - aDesktop.Left() >= rDialogSize.Width() + aSpace.Width() );
+ bool bFitRight = ( aDesktop.Right() - aObjAbs.Right() >= rDialogSize.Width() + aSpace.Width() );
+
+ if ( bFitLeft || bFitRight )
+ {
+ // if both fit, prefer right in RTL mode, left otherwise
+ bool bPutRight = bFitRight && ( bLayoutRTL || !bFitLeft );
+ if ( bPutRight )
+ aRet.setX( aObjAbs.Right() + aSpace.Width() );
+ else
+ aRet.setX( aObjAbs.Left() - rDialogSize.Width() - aSpace.Width() );
+
+ // center vertically
+ aRet.setY( aObjAbs.Top() + ( aObjAbs.GetHeight() - rDialogSize.Height() ) / 2 );
+ }
+ else
+ {
+ // doesn't fit on any edge - put at the bottom of the screen
+ aRet.setY( aDesktop.Bottom() - rDialogSize.Height() );
+ bCenterHor = true;
+ }
+ }
+ if ( bCenterHor )
+ aRet.setX( aObjAbs.Left() + ( aObjAbs.GetWidth() - rDialogSize.Width() ) / 2 );
+
+ // limit to screen (centering might lead to invalid positions)
+ if ( aRet.X() + rDialogSize.Width() - 1 > aDesktop.Right() )
+ aRet.setX( aDesktop.Right() - rDialogSize.Width() + 1 );
+ if ( aRet.X() < aDesktop.Left() )
+ aRet.setX( aDesktop.Left() );
+ if ( aRet.Y() + rDialogSize.Height() - 1 > aDesktop.Bottom() )
+ aRet.setY( aDesktop.Bottom() - rDialogSize.Height() + 1 );
+ if ( aRet.Y() < aDesktop.Top() )
+ aRet.setY( aDesktop.Top() );
+ }
+
+ return aRet;
+}
+
+void ScTabView::LockModifiers( sal_uInt16 nModifiers )
+{
+ pSelEngine->LockModifiers( nModifiers );
+ pHdrSelEng->LockModifiers( nModifiers );
+}
+
+sal_uInt16 ScTabView::GetLockedModifiers() const
+{
+ return pSelEngine->GetLockedModifiers();
+}
+
+Point ScTabView::GetMousePosPixel()
+{
+ Point aPos;
+ ScGridWindow* pWin = GetActiveWin();
+
+ if ( pWin )
+ aPos = pWin->GetMousePosPixel();
+
+ return aPos;
+}
+
+void ScTabView::FreezeSplitters( bool bFreeze, SplitMethod eSplitMethod, SCCOLROW nFreezeIndex)
+{
+ if ((eSplitMethod == SC_SPLIT_METHOD_COL || eSplitMethod == SC_SPLIT_METHOD_ROW) && nFreezeIndex < 0)
+ nFreezeIndex = 0;
+
+ ScSplitMode eOldH = aViewData.GetHSplitMode();
+ ScSplitMode eOldV = aViewData.GetVSplitMode();
+
+ ScSplitPos ePos = SC_SPLIT_BOTTOMLEFT;
+ if ( eOldV != SC_SPLIT_NONE )
+ ePos = SC_SPLIT_TOPLEFT;
+ vcl::Window* pWin = pGridWin[ePos];
+
+ bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.GetTabNo() );
+
+ if ( bFreeze )
+ {
+ Point aWinStart = pWin->GetPosPixel();
+ aViewData.GetDocShell()->SetDocumentModified();
+
+ Point aSplit;
+ SCCOL nPosX = 1;
+ SCROW nPosY = 1;
+ if (eOldV != SC_SPLIT_NONE || eOldH != SC_SPLIT_NONE)
+ {
+ if ( eOldV != SC_SPLIT_NONE && (eSplitMethod == SC_SPLIT_METHOD_ROW || eSplitMethod == SC_SPLIT_METHOD_CURSOR))
+ aSplit.setY( aViewData.GetVSplitPos() - aWinStart.Y() );
+
+ if ( eOldH != SC_SPLIT_NONE && (eSplitMethod == SC_SPLIT_METHOD_COL || eSplitMethod == SC_SPLIT_METHOD_CURSOR))
+ {
+ tools::Long nSplitPos = aViewData.GetHSplitPos();
+ if ( bLayoutRTL )
+ nSplitPos = pFrameWin->GetOutputSizePixel().Width() - nSplitPos - 1;
+ aSplit.setX( nSplitPos - aWinStart.X() );
+ }
+
+ aViewData.GetPosFromPixel( aSplit.X(), aSplit.Y(), ePos, nPosX, nPosY );
+ bool bLeft;
+ bool bTop;
+ aViewData.GetMouseQuadrant( aSplit, ePos, nPosX, nPosY, bLeft, bTop );
+ if (eSplitMethod == SC_SPLIT_METHOD_COL)
+ nPosX = static_cast<SCCOL>(nFreezeIndex);
+ else if (!bLeft)
+ ++nPosX;
+ if (eSplitMethod == SC_SPLIT_METHOD_ROW)
+ nPosY = static_cast<SCROW>(nFreezeIndex);
+ else if (!bTop)
+ ++nPosY;
+ }
+ else
+ {
+ switch(eSplitMethod)
+ {
+ case SC_SPLIT_METHOD_ROW:
+ {
+ nPosX = 0;
+ nPosY = static_cast<SCROW>(nFreezeIndex);
+ }
+ break;
+ case SC_SPLIT_METHOD_COL:
+ {
+ nPosX = static_cast<SCCOL>(nFreezeIndex);
+ nPosY = 0;
+ }
+ break;
+ case SC_SPLIT_METHOD_CURSOR:
+ {
+ nPosX = aViewData.GetCurX();
+ nPosY = aViewData.GetCurY();
+ }
+ break;
+ }
+ }
+
+ SCROW nTopPos = aViewData.GetPosY(SC_SPLIT_BOTTOM);
+ SCROW nBottomPos = nPosY;
+ SCCOL nLeftPos = aViewData.GetPosX(SC_SPLIT_LEFT);
+ SCCOL nRightPos = nPosX;
+
+ if (eSplitMethod == SC_SPLIT_METHOD_ROW || eSplitMethod == SC_SPLIT_METHOD_CURSOR)
+ {
+ if (eOldV != SC_SPLIT_NONE)
+ {
+ nTopPos = aViewData.GetPosY(SC_SPLIT_TOP);
+ if (aViewData.GetPosY(SC_SPLIT_BOTTOM) > nBottomPos)
+ nBottomPos = aViewData.GetPosY(SC_SPLIT_BOTTOM);
+ }
+ aSplit = aViewData.GetScrPos( nPosX, nPosY, ePos, true );
+ if (aSplit.Y() > 0)
+ {
+ aViewData.SetVSplitMode( SC_SPLIT_FIX );
+ aViewData.SetVSplitPos( aSplit.Y() + aWinStart.Y() );
+ aViewData.SetFixPosY( nPosY );
+
+ aViewData.SetPosY(SC_SPLIT_TOP, nTopPos);
+ aViewData.SetPosY(SC_SPLIT_BOTTOM, nBottomPos);
+ }
+ else
+ aViewData.SetVSplitMode( SC_SPLIT_NONE );
+ }
+
+ if (eSplitMethod == SC_SPLIT_METHOD_COL || eSplitMethod == SC_SPLIT_METHOD_CURSOR)
+ {
+ if (eOldH != SC_SPLIT_NONE)
+ {
+ if (aViewData.GetPosX(SC_SPLIT_RIGHT) > nRightPos)
+ nRightPos = aViewData.GetPosX(SC_SPLIT_RIGHT);
+ }
+ aSplit = aViewData.GetScrPos( nPosX, nPosY, ePos, true );
+ if (nPosX > aViewData.GetPosX(SC_SPLIT_LEFT)) // (aSplit.X() > 0) doesn't work for RTL
+ {
+ tools::Long nSplitPos = aSplit.X() + aWinStart.X();
+ if ( bLayoutRTL )
+ nSplitPos = pFrameWin->GetOutputSizePixel().Width() - nSplitPos - 1;
+
+ aViewData.SetHSplitMode( SC_SPLIT_FIX );
+ aViewData.SetHSplitPos( nSplitPos );
+ aViewData.SetFixPosX( nPosX );
+
+ aViewData.SetPosX(SC_SPLIT_LEFT, nLeftPos);
+ aViewData.SetPosX(SC_SPLIT_RIGHT, nRightPos);
+ }
+ else
+ aViewData.SetHSplitMode( SC_SPLIT_NONE );
+ }
+ }
+ else // unfreeze
+ {
+ if ( eOldH == SC_SPLIT_FIX )
+ aViewData.SetHSplitMode( SC_SPLIT_NORMAL );
+ if ( eOldV == SC_SPLIT_FIX )
+ aViewData.SetVSplitMode( SC_SPLIT_NORMAL );
+ }
+
+ // Form Layer needs to know the visible part of all windows
+ // that is why MapMode must already be correct here
+ for (VclPtr<ScGridWindow> & p : pGridWin)
+ if (p)
+ p->SetMapMode( p->GetDrawMapMode() );
+ SetNewVisArea();
+
+ RepeatResize(false);
+
+ UpdateShow();
+ PaintLeft();
+ PaintTop();
+ PaintGrid();
+
+ // SC_FOLLOW_NONE: only update active part
+ AlignToCursor( aViewData.GetCurX(), aViewData.GetCurY(), SC_FOLLOW_NONE );
+ UpdateAutoFillMark();
+
+ InvalidateSplit();
+}
+
+void ScTabView::RemoveSplit()
+{
+ DoHSplit( 0 );
+ DoVSplit( 0 );
+ RepeatResize();
+}
+
+void ScTabView::SplitAtCursor()
+{
+ ScSplitPos ePos = SC_SPLIT_BOTTOMLEFT;
+ if ( aViewData.GetVSplitMode() != SC_SPLIT_NONE )
+ ePos = SC_SPLIT_TOPLEFT;
+ vcl::Window* pWin = pGridWin[ePos];
+ Point aWinStart = pWin->GetPosPixel();
+
+ SCCOL nPosX = aViewData.GetCurX();
+ SCROW nPosY = aViewData.GetCurY();
+ Point aSplit = aViewData.GetScrPos( nPosX, nPosY, ePos, true );
+ if ( nPosX > 0 )
+ DoHSplit( aSplit.X() + aWinStart.X() );
+ else
+ DoHSplit( 0 );
+ if ( nPosY > 0 )
+ DoVSplit( aSplit.Y() + aWinStart.Y() );
+ else
+ DoVSplit( 0 );
+ RepeatResize();
+}
+
+void ScTabView::SplitAtPixel( const Point& rPixel )
+{
+ // pixel is relative to the entire View, not to the first GridWin
+
+ if ( rPixel.X() > 0 )
+ DoHSplit( rPixel.X() );
+ else
+ DoHSplit( 0 );
+ if ( rPixel.Y() > 0 )
+ DoVSplit( rPixel.Y() );
+ else
+ DoVSplit( 0 );
+ RepeatResize();
+}
+
+void ScTabView::InvalidateSplit()
+{
+ SfxBindings& rBindings = aViewData.GetBindings();
+ rBindings.Invalidate( SID_WINDOW_SPLIT );
+ rBindings.Invalidate( SID_WINDOW_FIX );
+ rBindings.Invalidate( SID_WINDOW_FIX_COL );
+ rBindings.Invalidate( SID_WINDOW_FIX_ROW );
+
+ pHSplitter->SetFixed( aViewData.GetHSplitMode() == SC_SPLIT_FIX );
+ pVSplitter->SetFixed( aViewData.GetVSplitMode() == SC_SPLIT_FIX );
+}
+
+void ScTabView::SetNewVisArea()
+{
+ // Draw-MapMode must be set for Controls when VisAreaChanged
+ // (also when Edit-MapMode is set instead)
+ MapMode aOldMode[4];
+ MapMode aDrawMode[4];
+ sal_uInt16 i;
+ for (i=0; i<4; i++)
+ if (pGridWin[i])
+ {
+ aOldMode[i] = pGridWin[i]->GetMapMode();
+ aDrawMode[i] = pGridWin[i]->GetDrawMapMode();
+ if (aDrawMode[i] != aOldMode[i])
+ pGridWin[i]->SetMapMode(aDrawMode[i]);
+ }
+
+ vcl::Window* pActive = pGridWin[aViewData.GetActivePart()];
+ if (pActive)
+ aViewData.GetViewShell()->VisAreaChanged();
+ if (pDrawView)
+ pDrawView->VisAreaChanged(nullptr); // no window passed on -> for all windows
+
+ UpdateAllOverlays(); // #i79909# with drawing MapMode set
+
+ for (i=0; i<4; i++)
+ if (pGridWin[i] && aDrawMode[i] != aOldMode[i])
+ {
+ pGridWin[i]->flushOverlayManager(); // #i79909# flush overlays before switching to edit MapMode
+ pGridWin[i]->SetMapMode(aOldMode[i]);
+ }
+
+ SfxViewFrame* pViewFrame = aViewData.GetViewShell()->GetViewFrame();
+ if (pViewFrame)
+ {
+ SfxFrame& rFrame = pViewFrame->GetFrame();
+ css::uno::Reference<css::frame::XController> xController = rFrame.GetController();
+ if (xController.is())
+ {
+ ScTabViewObj* pImp = comphelper::getFromUnoTunnel<ScTabViewObj>( xController );
+ if (pImp)
+ pImp->VisAreaChanged();
+ }
+ }
+ if (aViewData.GetViewShell()->HasAccessibilityObjects())
+ aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccVisAreaChanged));
+}
+
+bool ScTabView::HasPageFieldDataAtCursor() const
+{
+ ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get();
+ SCCOL nCol = aViewData.GetCurX();
+ SCROW nRow = aViewData.GetCurY();
+ if (pWin)
+ return pWin->GetDPFieldOrientation( nCol, nRow ) == sheet::DataPilotFieldOrientation_PAGE;
+
+ return false;
+}
+
+void ScTabView::StartDataSelect()
+{
+ ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get();
+ SCCOL nCol = aViewData.GetCurX();
+ SCROW nRow = aViewData.GetCurY();
+
+ if (!pWin)
+ return;
+
+ switch (pWin->GetDPFieldOrientation(nCol, nRow))
+ {
+ case sheet::DataPilotFieldOrientation_PAGE:
+ // #i36598# If the cursor is on a page field's data cell,
+ // no meaningful input is possible anyway, so this function
+ // can be used to select a page field entry.
+ pWin->LaunchPageFieldMenu( nCol, nRow );
+ return;
+ case sheet::DataPilotFieldOrientation_COLUMN:
+ case sheet::DataPilotFieldOrientation_ROW:
+ pWin->LaunchDPFieldMenu( nCol, nRow );
+ return;
+ default:
+ ;
+ }
+
+ // Do autofilter if the current cell has autofilter button. Otherwise do
+ // a normal data select popup.
+ const ScMergeFlagAttr* pAttr =
+ aViewData.GetDocument().GetAttr(
+ nCol, nRow, aViewData.GetTabNo(), ATTR_MERGE_FLAG);
+
+ if (pAttr->HasAutoFilter())
+ pWin->LaunchAutoFilterMenu(nCol, nRow);
+ else
+ pWin->LaunchDataSelectMenu(nCol, nRow);
+}
+
+void ScTabView::EnableRefInput(bool bFlag)
+{
+ aHScrollLeft->EnableInput(bFlag);
+ aHScrollRight->EnableInput(bFlag);
+ aVScrollBottom->EnableInput(bFlag);
+ aVScrollTop->EnableInput(bFlag);
+ aScrollBarBox->EnableInput(bFlag);
+
+ // from here on dynamically created ones
+
+ if(pTabControl!=nullptr) pTabControl->EnableInput(bFlag);
+
+ for (auto& p : pGridWin)
+ if (p)
+ p->EnableInput(bFlag, false);
+ for (auto& p : pColBar)
+ if (p)
+ p->EnableInput(bFlag, false);
+ for (auto& p : pRowBar)
+ if (p)
+ p->EnableInput(bFlag, false);
+}
+
+void ScTabView::EnableAutoSpell( bool bEnable )
+{
+ if (bEnable)
+ mpSpellCheckCxt =
+ std::make_shared<sc::SpellCheckContext>(&aViewData.GetDocument(),
+ aViewData.GetTabNo());
+ else
+ mpSpellCheckCxt.reset();
+
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ {
+ if (!pWin)
+ continue;
+
+ pWin->SetAutoSpellContext(mpSpellCheckCxt);
+ }
+}
+
+void ScTabView::ResetAutoSpell()
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ {
+ if (!pWin)
+ continue;
+
+ pWin->ResetAutoSpell();
+ }
+}
+
+void ScTabView::ResetAutoSpellForContentChange()
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ {
+ if (!pWin)
+ continue;
+
+ pWin->ResetAutoSpellForContentChange();
+ }
+}
+
+void ScTabView::SetAutoSpellData( SCCOL nPosX, SCROW nPosY, const std::vector<editeng::MisspellRanges>* pRanges )
+{
+ for (VclPtr<ScGridWindow> & pWin: pGridWin)
+ {
+ if (!pWin)
+ continue;
+
+ pWin->SetAutoSpellData(nPosX, nPosY, pRanges);
+ }
+}
+
+namespace
+{
+
+tools::Long lcl_GetRowHeightPx(const ScViewData &rViewData, SCROW nRow, SCTAB nTab)
+{
+ const sal_uInt16 nSize = rViewData.GetDocument().GetRowHeight(nRow, nTab);
+ return ScViewData::ToPixel(nSize, rViewData.GetPPTY());
+}
+
+tools::Long lcl_GetColWidthPx(const ScViewData &rViewData, SCCOL nCol, SCTAB nTab)
+{
+ const sal_uInt16 nSize = rViewData.GetDocument().GetColWidth(nCol, nTab);
+ return ScViewData::ToPixel(nSize, rViewData.GetPPTX());
+}
+
+void lcl_getGroupIndexes(const ScOutlineArray& rArray, SCCOLROW nStart, SCCOLROW nEnd, std::vector<size_t>& rGroupIndexes)
+{
+ rGroupIndexes.clear();
+ const size_t nGroupDepth = rArray.GetDepth();
+ rGroupIndexes.resize(nGroupDepth);
+
+ // Get first group per each level
+ for (size_t nLevel = 0; nLevel < nGroupDepth; ++nLevel)
+ {
+ if (rArray.GetCount(nLevel))
+ {
+ // look for a group inside the [nStartRow+1, nEndRow] range
+ size_t nIndex;
+ bool bFound = rArray.GetEntryIndexInRange(nLevel, nStart + 1, nEnd, nIndex);
+ if (bFound)
+ {
+ if (nIndex > 0)
+ {
+ // is there a previous group not inside the range
+ // but anyway intersecting it ?
+ const ScOutlineEntry* pPrevEntry = rArray.GetEntry(nLevel, nIndex - 1);
+ if (pPrevEntry && nStart < pPrevEntry->GetEnd())
+ {
+ --nIndex;
+ }
+ }
+ }
+ else
+ {
+ // look for a group which contains nStartRow+1
+ bFound = rArray.GetEntryIndex(nLevel, nStart + 1, nIndex);
+ if (!bFound)
+ {
+ // look for a group which contains nEndRow
+ bFound = rArray.GetEntryIndex(nLevel, nEnd, nIndex);
+ }
+ }
+
+ if (bFound)
+ {
+ // skip groups with no visible control
+ bFound = false;
+ while (nIndex < rArray.GetCount(nLevel))
+ {
+ const ScOutlineEntry* pEntry = rArray.GetEntry(nLevel, nIndex);
+ if (pEntry && pEntry->IsVisible())
+ {
+ bFound = true;
+ break;
+ }
+ if (pEntry && pEntry->GetStart() > nEnd)
+ {
+ break;
+ }
+ ++nIndex;
+ }
+ }
+
+ rGroupIndexes[nLevel] = bFound ? nIndex : -1;
+ }
+ }
+}
+
+void lcl_createGroupsData(
+ SCCOLROW nHeaderIndex, SCCOLROW nEnd, tools::Long nSizePx, tools::Long nTotalPx,
+ const ScOutlineArray& rArray, std::vector<size_t>& rGroupIndexes,
+ std::vector<tools::Long>& rGroupStartPositions, OStringBuffer& rGroupsBuffer)
+{
+ const size_t nGroupDepth = rArray.GetDepth();
+ // create string data for group controls
+ for (size_t nLevel = nGroupDepth - 1; nLevel != size_t(-1); --nLevel)
+ {
+ size_t nIndex = rGroupIndexes[nLevel];
+ if (nIndex == size_t(-1))
+ continue;
+ const ScOutlineEntry* pEntry = rArray.GetEntry(nLevel, nIndex);
+ if (pEntry)
+ {
+ if (nHeaderIndex < pEntry->GetStart())
+ {
+ continue;
+ }
+ else if (nHeaderIndex == pEntry->GetStart())
+ {
+ rGroupStartPositions[nLevel] = nTotalPx - nSizePx;
+ }
+ else if (nHeaderIndex > pEntry->GetStart() && (nHeaderIndex < nEnd && nHeaderIndex < pEntry->GetEnd()))
+ {
+ // for handling group started before the current view range
+ if (rGroupStartPositions[nLevel] < 0)
+ rGroupStartPositions[nLevel] *= -1;
+ break;
+ }
+ if (nHeaderIndex == pEntry->GetEnd() || (nHeaderIndex == nEnd && rGroupStartPositions[nLevel] != -1))
+ {
+ // nHeaderIndex is the end col/row of a group or is the last col/row and a group started and not yet ended
+
+ // append a new group control data
+ auto len = rGroupsBuffer.getLength();
+ if (len && rGroupsBuffer[len-1] == '}')
+ {
+ rGroupsBuffer.append(", ");
+ }
+
+ bool bGroupHidden = pEntry->IsHidden();
+
+ rGroupsBuffer.append(
+ "{ \"level\": " + OString::number(nLevel + 1) + ", "
+ "\"index\": " + OString::number(nIndex) + ", "
+ "\"startPos\": " + OString::number(rGroupStartPositions[nLevel]) + ", "
+ "\"endPos\": " + OString::number(nTotalPx) + ", "
+ "\"hidden\": " + OString::number(bGroupHidden ? 1 : 0) + " }");
+
+ // look for the next visible group control at level nLevel
+ bool bFound = false;
+ ++nIndex;
+ while (nIndex < rArray.GetCount(nLevel))
+ {
+ pEntry = rArray.GetEntry(nLevel, nIndex);
+ if (pEntry && pEntry->IsVisible())
+ {
+ bFound = true;
+ break;
+ }
+ if (pEntry && pEntry->GetStart() > nEnd)
+ {
+ break;
+ }
+ ++nIndex;
+ }
+ rGroupIndexes[nLevel] = bFound ? nIndex : -1;
+ rGroupStartPositions[nLevel] = -1;
+ }
+ }
+ }
+}
+
+class ScRangeProvider
+{
+public:
+ ScRangeProvider(const tools::Rectangle& rArea, bool bInPixels,
+ ScViewData& rViewData):
+ mrViewData(rViewData)
+ {
+ tools::Rectangle aAreaPx = bInPixels ? rArea :
+ tools::Rectangle(rArea.Left() * mrViewData.GetPPTX(),
+ rArea.Top() * mrViewData.GetPPTY(),
+ rArea.Right() * mrViewData.GetPPTX(),
+ rArea.Bottom() * mrViewData.GetPPTY());
+ calculateBounds(aAreaPx);
+ }
+
+ const ScRange& getCellRange() const
+ {
+ return maRange;
+ }
+
+ void getColPositions(tools::Long& rStartColPos, tools::Long& rEndColPos) const
+ {
+ rStartColPos = maBoundPositions.Left();
+ rEndColPos = maBoundPositions.Right();
+ }
+
+ void getRowPositions(tools::Long& rStartRowPos, tools::Long& rEndRowPos) const
+ {
+ rStartRowPos = maBoundPositions.Top();
+ rEndRowPos = maBoundPositions.Bottom();
+ }
+
+private:
+ void calculateBounds(const tools::Rectangle& rAreaPx)
+ {
+ tools::Long nLeftPx = 0, nRightPx = 0;
+ SCCOLROW nStartCol = -1, nEndCol = -1;
+ calculateDimensionBounds(rAreaPx.Left(), rAreaPx.Right(), true,
+ nStartCol, nEndCol, nLeftPx, nRightPx,
+ mnEnlargeX, mrViewData);
+ tools::Long nTopPx = 0, nBottomPx = 0;
+ SCCOLROW nStartRow = -1, nEndRow = -1;
+ calculateDimensionBounds(rAreaPx.Top(), rAreaPx.Bottom(), false,
+ nStartRow, nEndRow, nTopPx, nBottomPx,
+ mnEnlargeY, mrViewData);
+
+ maRange.aStart.Set(nStartCol, nStartRow, mrViewData.GetTabNo());
+ maRange.aEnd.Set(nEndCol, nEndRow, mrViewData.GetTabNo());
+
+ maBoundPositions.SetLeft(nLeftPx);
+ maBoundPositions.SetRight(nRightPx);
+ maBoundPositions.SetTop(nTopPx);
+ maBoundPositions.SetBottom(nBottomPx);
+ }
+
+ // All positions are in pixels.
+ static void calculateDimensionBounds(const tools::Long nStartPos, const tools::Long nEndPos,
+ bool bColumns, SCCOLROW& rStartIndex,
+ SCCOLROW& rEndIndex, tools::Long& rBoundStart,
+ tools::Long& rBoundEnd, SCCOLROW nEnlarge,
+ ScViewData& rViewData)
+ {
+ ScPositionHelper& rPosHelper = bColumns ? rViewData.GetLOKWidthHelper() :
+ rViewData.GetLOKHeightHelper();
+ const auto& rStartNearest = rPosHelper.getNearestByPosition(nStartPos);
+ const auto& rEndNearest = rPosHelper.getNearestByPosition(nEndPos);
+
+ ScBoundsProvider aBoundsProvider(rViewData, rViewData.GetTabNo(), bColumns);
+ aBoundsProvider.Compute(rStartNearest, rEndNearest, nStartPos, nEndPos);
+ aBoundsProvider.EnlargeBy(nEnlarge);
+ if (bColumns)
+ {
+ SCCOL nStartCol = -1, nEndCol = -1;
+ aBoundsProvider.GetStartIndexAndPosition(nStartCol, rBoundStart);
+ aBoundsProvider.GetEndIndexAndPosition(nEndCol, rBoundEnd);
+ rStartIndex = nStartCol;
+ rEndIndex = nEndCol;
+ }
+ else
+ {
+ SCROW nStartRow = -1, nEndRow = -1;
+ aBoundsProvider.GetStartIndexAndPosition(nStartRow, rBoundStart);
+ aBoundsProvider.GetEndIndexAndPosition(nEndRow, rBoundEnd);
+ rStartIndex = nStartRow;
+ rEndIndex = nEndRow;
+ }
+ }
+
+private:
+
+ ScRange maRange;
+ tools::Rectangle maBoundPositions;
+ ScViewData& mrViewData;
+ static const SCCOLROW mnEnlargeX = 2;
+ static const SCCOLROW mnEnlargeY = 2;
+};
+
+void lcl_ExtendTiledDimension(bool bColumn, const SCCOLROW nEnd, const SCCOLROW nExtra,
+ ScTabView& rTabView, ScViewData& rViewData)
+{
+ ScDocument& rDoc = rViewData.GetDocument();
+ // If we are approaching current max tiled row/col, signal a size changed event
+ // and invalidate the involved area
+ SCCOLROW nMaxTiledIndex = bColumn ? rViewData.GetMaxTiledCol() : rViewData.GetMaxTiledRow();
+ SCCOLROW nHardLimit = !bColumn ? MAXTILEDROW : rDoc.MaxCol();
+
+ if (nMaxTiledIndex >= nHardLimit)
+ return;
+
+ if (nEnd <= nMaxTiledIndex - nExtra) // No need to extend.
+ return;
+
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScModelObj* pModelObj = pDocSh ?
+ comphelper::getFromUnoTunnel<ScModelObj>( pDocSh->GetModel() ) : nullptr;
+ Size aOldSize(0, 0);
+ if (pModelObj)
+ aOldSize = pModelObj->getDocumentSize();
+
+ SCCOLROW nNewMaxTiledIndex = std::min(std::max(nEnd, nMaxTiledIndex) + nExtra, nHardLimit);
+
+ if (bColumn)
+ rViewData.SetMaxTiledCol(nNewMaxTiledIndex);
+ else
+ rViewData.SetMaxTiledRow(nNewMaxTiledIndex);
+
+ Size aNewSize(0, 0);
+ if (pModelObj)
+ aNewSize = pModelObj->getDocumentSize();
+
+ if (aOldSize == aNewSize)
+ return;
+
+ if (!pDocSh)
+ return;
+
+ // New area extended to the right/bottom of the sheet after last col/row
+ // excluding overlapping area with aNewArea
+ tools::Rectangle aNewArea = bColumn ?
+ tools::Rectangle(aOldSize.getWidth(), 0, aNewSize.getWidth(), aNewSize.getHeight()):
+ tools::Rectangle(0, aOldSize.getHeight(), aNewSize.getWidth(), aNewSize.getHeight());
+
+ // Only invalidate if spreadsheet has extended to the right or bottom
+ if ((bColumn && aNewArea.getWidth()) || (!bColumn && aNewArea.getHeight()))
+ {
+ rTabView.UpdateSelectionOverlay();
+ SfxLokHelper::notifyInvalidation(rViewData.GetViewShell(), &aNewArea);
+ }
+
+ // Provide size in the payload, so clients don't have to query for that.
+ std::stringstream ss;
+ ss << aNewSize.Width() << ", " << aNewSize.Height();
+ OString sSize = ss.str().c_str();
+ ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>(
+ rViewData.GetViewShell()->GetCurrentDocument());
+ SfxLokHelper::notifyDocumentSizeChanged(rViewData.GetViewShell(), sSize, pModel, false);
+}
+
+} // anonymous namespace
+
+void ScTabView::getRowColumnHeaders(const tools::Rectangle& rRectangle, tools::JsonWriter& rJsonWriter)
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+
+ if (rRectangle.IsEmpty())
+ return;
+
+ bool bRangeHeaderSupport = comphelper::LibreOfficeKit::isRangeHeaders();
+
+ rJsonWriter.put("commandName", ".uno:ViewRowColumnHeaders");
+
+ SCTAB nTab = aViewData.GetTabNo();
+ SCROW nStartRow = -1;
+ SCROW nEndRow = -1;
+ tools::Long nStartHeightPx = 0;
+ SCCOL nStartCol = -1;
+ SCCOL nEndCol = -1;
+ tools::Long nStartWidthPx = 0;
+
+ tools::Rectangle aOldVisArea(
+ mnLOKStartHeaderCol + 1, mnLOKStartHeaderRow + 1,
+ mnLOKEndHeaderCol, mnLOKEndHeaderRow);
+
+ ScRangeProvider aRangeProvider(rRectangle, /* bInPixels */ false, aViewData);
+ const ScRange& rCellRange = aRangeProvider.getCellRange();
+
+ /// *** start collecting ROWS ***
+
+ /// 1) compute start and end rows
+
+ if (rRectangle.Top() < rRectangle.Bottom())
+ {
+ SAL_INFO("sc.lok.header", "Row Header: compute start/end rows.");
+ tools::Long nEndHeightPx = 0;
+ nStartRow = rCellRange.aStart.Row();
+ nEndRow = rCellRange.aEnd.Row();
+ aRangeProvider.getRowPositions(nStartHeightPx, nEndHeightPx);
+
+ aViewData.GetLOKHeightHelper().removeByIndex(mnLOKStartHeaderRow);
+ aViewData.GetLOKHeightHelper().removeByIndex(mnLOKEndHeaderRow);
+ aViewData.GetLOKHeightHelper().insert(nStartRow, nStartHeightPx);
+ aViewData.GetLOKHeightHelper().insert(nEndRow, nEndHeightPx);
+
+ mnLOKStartHeaderRow = nStartRow;
+ mnLOKEndHeaderRow = nEndRow;
+ }
+
+ sal_Int32 nVisibleRows = nEndRow - nStartRow;
+ if (nVisibleRows < 25)
+ nVisibleRows = 25;
+
+ SAL_INFO("sc.lok.header", "Row Header: visible rows: " << nVisibleRows);
+
+
+ // Get row groups
+ // per each level store the index of the first group intersecting
+ // [nStartRow, nEndRow] range
+
+ const ScOutlineTable* pTable = rDoc.GetOutlineTable(nTab);
+ const ScOutlineArray* pRowArray = pTable ? &(pTable->GetRowArray()) : nullptr;
+ size_t nRowGroupDepth = 0;
+ std::vector<size_t> aRowGroupIndexes;
+ if (bRangeHeaderSupport && pTable)
+ {
+ nRowGroupDepth = pRowArray->GetDepth();
+ lcl_getGroupIndexes(*pRowArray, nStartRow, nEndRow, aRowGroupIndexes);
+ }
+
+ /// 2) if we are approaching current max tiled row, signal a size changed event
+ /// and invalidate the involved area
+ lcl_ExtendTiledDimension(/* bColumn */ false, nEndRow, nVisibleRows, *this, aViewData);
+
+ /// 3) create string data for rows
+
+ tools::Long nTotalPixels = nStartHeightPx;
+ tools::Long nPrevSizePx = -1;
+ OStringBuffer aRowGroupsBuffer = "\"rowGroups\": [\n";
+ {
+ auto rowsNode = rJsonWriter.startArray("rows");
+
+ SAL_INFO("sc.lok.header", "Row Header: [create string data for rows]: start row: "
+ << nStartRow << " start height: " << nTotalPixels);
+
+ if (nStartRow != nEndRow)
+ {
+ auto node = rJsonWriter.startStruct();
+ rJsonWriter.put("text", nStartRow + 1);
+ rJsonWriter.put("size", nTotalPixels);
+ rJsonWriter.put("groupLevels", static_cast<sal_Int64>(nRowGroupDepth));
+ }
+
+ std::vector<tools::Long> aRowGroupStartPositions(nRowGroupDepth, -nTotalPixels);
+ for (SCROW nRow = nStartRow + 1; nRow <= nEndRow; ++nRow)
+ {
+ // nSize will be 0 for hidden rows.
+ const tools::Long nSizePx = lcl_GetRowHeightPx(aViewData, nRow, nTab);
+ nTotalPixels += nSizePx;
+
+ if (bRangeHeaderSupport && nRowGroupDepth > 0)
+ {
+ lcl_createGroupsData(nRow, nEndRow, nSizePx, nTotalPixels,
+ *pRowArray, aRowGroupIndexes, aRowGroupStartPositions,
+ aRowGroupsBuffer);
+ }
+
+ if (bRangeHeaderSupport && nRow < nEndRow && nSizePx == nPrevSizePx)
+ continue;
+ nPrevSizePx = nSizePx;
+
+ auto node = rJsonWriter.startStruct();
+ rJsonWriter.put("text", pRowBar[SC_SPLIT_BOTTOM]->GetEntryText(nRow));
+ rJsonWriter.put("size", nTotalPixels);
+ }
+
+ aRowGroupsBuffer.append("]");
+ }
+ if (nRowGroupDepth > 0)
+ {
+ aRowGroupsBuffer.append(",\n");
+ rJsonWriter.putRaw(aRowGroupsBuffer);
+ }
+ /// end collecting ROWS
+
+
+ /// *** start collecting COLS ***
+
+ /// 1) compute start and end columns
+
+ if (rRectangle.Left() < rRectangle.Right())
+ {
+ SAL_INFO("sc.lok.header", "Column Header: compute start/end columns.");
+ tools::Long nEndWidthPx = 0;
+ nStartCol = rCellRange.aStart.Col();
+ nEndCol = rCellRange.aEnd.Col();
+ aRangeProvider.getColPositions(nStartWidthPx, nEndWidthPx);
+
+ aViewData.GetLOKWidthHelper().removeByIndex(mnLOKStartHeaderCol);
+ aViewData.GetLOKWidthHelper().removeByIndex(mnLOKEndHeaderCol);
+ aViewData.GetLOKWidthHelper().insert(nStartCol, nStartWidthPx);
+ aViewData.GetLOKWidthHelper().insert(nEndCol, nEndWidthPx);
+
+ mnLOKStartHeaderCol = nStartCol;
+ mnLOKEndHeaderCol = nEndCol;
+ }
+
+ sal_Int32 nVisibleCols = nEndCol - nStartCol;
+ if (nVisibleCols < 10)
+ nVisibleCols = 10;
+
+
+ // Get column groups
+ // per each level store the index of the first group intersecting
+ // [nStartCol, nEndCol] range
+
+ const ScOutlineArray* pColArray = pTable ? &(pTable->GetColArray()) : nullptr;
+ size_t nColGroupDepth = 0;
+ std::vector<size_t> aColGroupIndexes;
+ if (bRangeHeaderSupport && pTable)
+ {
+ nColGroupDepth = pColArray->GetDepth();
+ lcl_getGroupIndexes(*pColArray, nStartCol, nEndCol, aColGroupIndexes);
+ }
+
+ /// 2) if we are approaching current max tiled column, signal a size changed event
+ /// and invalidate the involved area
+ lcl_ExtendTiledDimension(/* bColumn */ true, nEndCol, nVisibleCols, *this, aViewData);
+
+ /// 3) create string data for columns
+ OStringBuffer aColGroupsBuffer = "\"columnGroups\": [\n";
+ {
+ auto columnsNode = rJsonWriter.startArray("columns");
+
+ nTotalPixels = nStartWidthPx;
+ SAL_INFO("sc.lok.header", "Col Header: [create string data for cols]: start col: "
+ << nStartRow << " start width: " << nTotalPixels);
+
+ if (nStartCol != nEndCol)
+ {
+ auto node = rJsonWriter.startStruct();
+ rJsonWriter.put("text", static_cast<sal_Int64>(nStartCol + 1));
+ rJsonWriter.put("size", nTotalPixels);
+ rJsonWriter.put("groupLevels", static_cast<sal_Int64>(nColGroupDepth));
+ }
+
+ std::vector<tools::Long> aColGroupStartPositions(nColGroupDepth, -nTotalPixels);
+ nPrevSizePx = -1;
+ for (SCCOL nCol = nStartCol + 1; nCol <= nEndCol; ++nCol)
+ {
+ // nSize will be 0 for hidden columns.
+ const tools::Long nSizePx = lcl_GetColWidthPx(aViewData, nCol, nTab);
+ nTotalPixels += nSizePx;
+
+ if (bRangeHeaderSupport && nColGroupDepth > 0)
+ lcl_createGroupsData(nCol, nEndCol, nSizePx, nTotalPixels,
+ *pColArray, aColGroupIndexes,
+ aColGroupStartPositions, aColGroupsBuffer);
+
+ if (bRangeHeaderSupport && nCol < nEndCol && nSizePx == nPrevSizePx)
+ continue;
+ nPrevSizePx = nSizePx;
+
+ OUString aText = bRangeHeaderSupport ?
+ OUString::number(nCol + 1) : pColBar[SC_SPLIT_LEFT]->GetEntryText(nCol);
+
+ auto node = rJsonWriter.startStruct();
+ rJsonWriter.put("text", aText);
+ rJsonWriter.put("size", nTotalPixels);
+ }
+
+ aColGroupsBuffer.append("]");
+ }
+ if (nColGroupDepth > 0)
+ {
+ aColGroupsBuffer.append(",\n");
+ rJsonWriter.putRaw(aColGroupsBuffer);
+ }
+ /// end collecting COLs
+
+ vcl::Region aNewVisArea(
+ tools::Rectangle(mnLOKStartHeaderCol + 1, mnLOKStartHeaderRow + 1,
+ mnLOKEndHeaderCol, mnLOKEndHeaderRow));
+ aNewVisArea.Exclude(aOldVisArea);
+ tools::Rectangle aChangedArea = aNewVisArea.GetBoundRect();
+ if (!aChangedArea.IsEmpty())
+ {
+ UpdateVisibleRange();
+ UpdateFormulas(aChangedArea.Left(), aChangedArea.Top(), aChangedArea.Right(), aChangedArea.Bottom());
+ }
+}
+
+OString ScTabView::getSheetGeometryData(bool bColumns, bool bRows, bool bSizes, bool bHidden,
+ bool bFiltered, bool bGroups)
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+
+ boost::property_tree::ptree aTree;
+ aTree.put("commandName", ".uno:SheetGeometryData");
+ aTree.put("maxtiledcolumn", rDoc.MaxCol());
+ aTree.put("maxtiledrow", MAXTILEDROW);
+
+ auto getJSONString = [](const boost::property_tree::ptree& rTree) {
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, rTree);
+ return aStream.str();
+ };
+
+ if ((!bSizes && !bHidden && !bFiltered && !bGroups) ||
+ (!bColumns && !bRows))
+ {
+ return getJSONString(aTree).c_str();
+ }
+
+ struct GeomEntry
+ {
+ SheetGeomType eType;
+ const char* pKey;
+ bool bEnabled;
+ };
+
+ const GeomEntry aGeomEntries[] = {
+ { SheetGeomType::SIZES, "sizes", bSizes },
+ { SheetGeomType::HIDDEN, "hidden", bHidden },
+ { SheetGeomType::FILTERED, "filtered", bFiltered },
+ { SheetGeomType::GROUPS, "groups", bGroups }
+ };
+
+ struct DimensionEntry
+ {
+ const char* pKey;
+ bool bDimIsCol;
+ bool bEnabled;
+ };
+
+ const DimensionEntry aDimEntries[] = {
+ { "columns", true, bColumns },
+ { "rows", false, bRows }
+ };
+
+ SCTAB nTab = aViewData.GetTabNo();
+
+ for (const auto& rDimEntry : aDimEntries)
+ {
+ if (!rDimEntry.bEnabled)
+ continue;
+
+ bool bDimIsCol = rDimEntry.bDimIsCol;
+
+ boost::property_tree::ptree aDimTree;
+ for (const auto& rGeomEntry : aGeomEntries)
+ {
+ if (!rGeomEntry.bEnabled)
+ continue;
+
+ OString aGeomDataEncoding = rDoc.dumpSheetGeomData(nTab, bDimIsCol, rGeomEntry.eType);
+ // TODO: Investigate if we can avoid the copy of the 'value' string in put().
+ aDimTree.put(rGeomEntry.pKey, aGeomDataEncoding.getStr());
+ }
+
+ aTree.add_child(rDimEntry.pKey, aDimTree);
+ }
+
+ return getJSONString(aTree).c_str();
+}
+
+void ScTabView::extendTiledAreaIfNeeded()
+{
+ SAL_INFO("sc.lok.header",
+ "extendTiledAreaIfNeeded: START: ClientView: ColRange["
+ << mnLOKStartHeaderCol << "," << mnLOKEndHeaderCol
+ << "] RowRange[" << mnLOKStartHeaderRow << "," << mnLOKEndHeaderRow
+ << "] MaxTiledCol = " << aViewData.GetMaxTiledCol()
+ << " MaxTiledRow = " << aViewData.GetMaxTiledRow());
+
+ const tools::Rectangle rVisArea = aViewData.getLOKVisibleArea();
+ if (rVisArea.Top() >= rVisArea.Bottom() ||
+ rVisArea.Left() >= rVisArea.Right())
+ return;
+
+ // Needed for conditional updating of visible-range/formula.
+ tools::Rectangle aOldVisCellRange(mnLOKStartHeaderCol + 1, mnLOKStartHeaderRow + 1,
+ mnLOKEndHeaderCol, mnLOKEndHeaderRow);
+
+ ScRangeProvider aRangeProvider(rVisArea, /* bInPixels */ false, aViewData);
+ // Index bounds.
+ const ScRange& rCellRange = aRangeProvider.getCellRange();
+ const SCCOL nStartCol = rCellRange.aStart.Col();
+ const SCCOL nEndCol = rCellRange.aEnd.Col();
+ const SCROW nStartRow = rCellRange.aStart.Row();
+ const SCROW nEndRow = rCellRange.aEnd.Row();
+
+ // Column/Row positions.
+ tools::Long nStartColPos, nEndColPos, nStartRowPos, nEndRowPos;
+ aRangeProvider.getColPositions(nStartColPos, nEndColPos);
+ aRangeProvider.getRowPositions(nStartRowPos, nEndRowPos);
+
+ ScPositionHelper& rWidthHelper = aViewData.GetLOKWidthHelper();
+ ScPositionHelper& rHeightHelper = aViewData.GetLOKHeightHelper();
+
+ // Update mnLOKStartHeaderCol and mnLOKEndHeaderCol members.
+ // These are consulted in some ScGridWindow methods.
+ if (mnLOKStartHeaderCol != nStartCol)
+ {
+ rWidthHelper.removeByIndex(mnLOKStartHeaderCol);
+ rWidthHelper.insert(nStartCol, nStartColPos);
+ mnLOKStartHeaderCol = nStartCol;
+ }
+
+ if (mnLOKEndHeaderCol != nEndCol)
+ {
+ rWidthHelper.removeByIndex(mnLOKEndHeaderCol);
+ rWidthHelper.insert(nEndCol, nEndColPos);
+ mnLOKEndHeaderCol = nEndCol;
+ }
+
+ // Update mnLOKStartHeaderRow and mnLOKEndHeaderRow members.
+ // These are consulted in some ScGridWindow methods.
+ if (mnLOKStartHeaderRow != nStartRow)
+ {
+ rHeightHelper.removeByIndex(mnLOKStartHeaderRow);
+ rHeightHelper.insert(nStartRow, nStartRowPos);
+ mnLOKStartHeaderRow = nStartRow;
+ }
+
+ if (mnLOKEndHeaderRow != nEndRow)
+ {
+ rHeightHelper.removeByIndex(mnLOKEndHeaderRow);
+ rHeightHelper.insert(nEndRow, nEndRowPos);
+ mnLOKEndHeaderRow = nEndRow;
+ }
+
+ constexpr SCCOL nMinExtraCols = 10;
+ SCCOL nExtraCols = std::max<SCCOL>(nMinExtraCols, nEndCol - nStartCol);
+ // If we are approaching current max tiled column, signal a size changed event
+ // and invalidate the involved area.
+ lcl_ExtendTiledDimension(/* bColumn */ true, nEndCol, nExtraCols, *this, aViewData);
+
+ constexpr SCROW nMinExtraRows = 25;
+ SCROW nExtraRows = std::max(nMinExtraRows, nEndRow - nStartRow);
+ // If we are approaching current max tiled row, signal a size changed event
+ // and invalidate the involved area.
+ lcl_ExtendTiledDimension(/* bColumn */ false, nEndRow, nExtraRows, *this, aViewData);
+
+ vcl::Region aNewVisCellRange(
+ tools::Rectangle(mnLOKStartHeaderCol + 1, mnLOKStartHeaderRow + 1,
+ mnLOKEndHeaderCol, mnLOKEndHeaderRow));
+ aNewVisCellRange.Exclude(aOldVisCellRange);
+ tools::Rectangle aChangedCellRange = aNewVisCellRange.GetBoundRect();
+ if (!aChangedCellRange.IsEmpty())
+ {
+ UpdateVisibleRange();
+ UpdateFormulas(aChangedCellRange.Left(), aChangedCellRange.Top(),
+ aChangedCellRange.Right(), aChangedCellRange.Bottom());
+ }
+
+ SAL_INFO("sc.lok.header",
+ "extendTiledAreaIfNeeded: END: ClientView: ColRange["
+ << mnLOKStartHeaderCol << "," << mnLOKEndHeaderCol
+ << "] RowRange[" << mnLOKStartHeaderRow << "," << mnLOKEndHeaderRow
+ << "] MaxTiledCol = " << aViewData.GetMaxTiledCol()
+ << " MaxTiledRow = " << aViewData.GetMaxTiledRow());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabview2.cxx b/sc/source/ui/view/tabview2.cxx
new file mode 100644
index 000000000..400ea89b6
--- /dev/null
+++ b/sc/source/ui/view/tabview2.cxx
@@ -0,0 +1,1510 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/bindings.hxx>
+#include <osl/diagnose.h>
+
+#include <attrib.hxx>
+#include <pagedata.hxx>
+#include <tabview.hxx>
+#include <tabvwsh.hxx>
+#include <printfun.hxx>
+#include <stlpool.hxx>
+#include <docsh.hxx>
+#include <gridwin.hxx>
+#include <sc.hrc>
+#include <viewutil.hxx>
+#include <colrowba.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <scmod.hxx>
+#include <tabprotection.hxx>
+#include <markdata.hxx>
+#include <inputopt.hxx>
+#include <comphelper/lok.hxx>
+
+namespace {
+
+bool isCellQualified(const ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab, bool bSelectLocked, bool bSelectUnlocked)
+{
+ bool bCellProtected = pDoc->HasAttrib(
+ nCol, nRow, nTab, nCol, nRow, nTab, HasAttrFlags::Protected);
+
+ if (bCellProtected && !bSelectLocked)
+ return false;
+
+ if (!bCellProtected && !bSelectUnlocked)
+ return false;
+
+ return true;
+}
+
+void moveCursorByProtRule(
+ SCCOL& rCol, SCROW& rRow, SCCOL nMovX, SCROW nMovY, SCTAB nTab, const ScDocument* pDoc)
+{
+ bool bSelectLocked = true;
+ bool bSelectUnlocked = true;
+ const ScTableProtection* pTabProtection = pDoc->GetTabProtection(nTab);
+ if (pTabProtection && pTabProtection->isProtected())
+ {
+ bSelectLocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
+ bSelectUnlocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
+ }
+
+ if (nMovX > 0)
+ {
+ for (SCCOL i = 0; i < nMovX && rCol < pDoc->MaxCol(); ++i)
+ {
+ SCCOL nNewUnhiddenCol = rCol + 1;
+ SCCOL nEndCol = 0;
+ while(pDoc->ColHidden(nNewUnhiddenCol, nTab, nullptr, &nEndCol))
+ {
+ if(nNewUnhiddenCol >= pDoc->MaxCol())
+ return;
+
+ i += nEndCol - nNewUnhiddenCol + 1;
+ nNewUnhiddenCol = nEndCol +1;
+ }
+
+ if (!isCellQualified(pDoc, nNewUnhiddenCol, rRow, nTab, bSelectLocked, bSelectUnlocked))
+ break;
+ rCol = nNewUnhiddenCol;
+ }
+ }
+ else if (nMovX < 0)
+ {
+ for (SCCOL i = 0; i > nMovX && rCol > 0; --i)
+ {
+ SCCOL nNewUnhiddenCol = rCol - 1;
+ SCCOL nStartCol = 0;
+ while(pDoc->ColHidden(nNewUnhiddenCol, nTab, &nStartCol))
+ {
+ if(nNewUnhiddenCol <= 0)
+ return;
+
+ i -= nNewUnhiddenCol - nStartCol + 1;
+ nNewUnhiddenCol = nStartCol - 1;
+ }
+
+ if (!isCellQualified(pDoc, nNewUnhiddenCol, rRow, nTab, bSelectLocked, bSelectUnlocked))
+ break;
+ rCol = nNewUnhiddenCol;
+ }
+ }
+
+ if (nMovY > 0)
+ {
+ for (SCROW i = 0; i < nMovY && rRow < pDoc->MaxRow(); ++i)
+ {
+ SCROW nNewUnhiddenRow = rRow + 1;
+ SCROW nEndRow = 0;
+ while(pDoc->RowHidden(nNewUnhiddenRow, nTab, nullptr, &nEndRow))
+ {
+ if(nNewUnhiddenRow >= pDoc->MaxRow())
+ return;
+
+ i += nEndRow - nNewUnhiddenRow + 1;
+ nNewUnhiddenRow = nEndRow + 1;
+ }
+
+ if (!isCellQualified(pDoc, rCol, nNewUnhiddenRow, nTab, bSelectLocked, bSelectUnlocked))
+ break;
+ rRow = nNewUnhiddenRow;
+ }
+ }
+ else if (nMovY < 0)
+ {
+ for (SCROW i = 0; i > nMovY && rRow > 0; --i)
+ {
+ SCROW nNewUnhiddenRow = rRow - 1;
+ SCROW nStartRow = 0;
+ while(pDoc->RowHidden(nNewUnhiddenRow, nTab, &nStartRow))
+ {
+ if(nNewUnhiddenRow <= 0)
+ return;
+
+ i -= nNewUnhiddenRow - nStartRow + 1;
+ nNewUnhiddenRow = nStartRow - 1;
+ }
+
+ if (!isCellQualified(pDoc, rCol, nNewUnhiddenRow, nTab, bSelectLocked, bSelectUnlocked))
+ break;
+ rRow = nNewUnhiddenRow;
+ }
+ }
+}
+
+bool checkBoundary(const ScDocument* pDoc, SCCOL& rCol, SCROW& rRow)
+{
+ bool bGood = true;
+ if (rCol < 0)
+ {
+ rCol = 0;
+ bGood = false;
+ }
+ else if (rCol > pDoc->MaxCol())
+ {
+ rCol = pDoc->MaxCol();
+ bGood = false;
+ }
+
+ if (rRow < 0)
+ {
+ rRow = 0;
+ bGood = false;
+ }
+ else if (rRow > pDoc->MaxRow())
+ {
+ rRow = pDoc->MaxRow();
+ bGood = false;
+ }
+ return bGood;
+}
+
+void moveCursorByMergedCell(
+ SCCOL& rCol, SCROW& rRow, SCCOL nMovX, SCROW nMovY, SCTAB nTab,
+ const ScDocument* pDoc, const ScViewData& rViewData)
+{
+ SCCOL nOrigX = rViewData.GetCurX();
+ SCROW nOrigY = rViewData.GetCurY();
+
+ const ScTableProtection* pTabProtection = pDoc->GetTabProtection(nTab);
+ bool bSelectLocked = true;
+ bool bSelectUnlocked = true;
+ if (pTabProtection && pTabProtection->isProtected())
+ {
+ bSelectLocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
+ bSelectUnlocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
+ }
+
+ const ScMergeAttr* pMergeAttr = pDoc->GetAttr(nOrigX, nOrigY, nTab, ATTR_MERGE);
+
+ bool bOriginMerged = false;
+ SCCOL nColSpan = 1;
+ SCROW nRowSpan = 1;
+ if (pMergeAttr && pMergeAttr->IsMerged())
+ {
+ nColSpan = pMergeAttr->GetColMerge();
+ nRowSpan = pMergeAttr->GetRowMerge();
+ bOriginMerged = true;
+ }
+
+ if (nMovX > 0)
+ {
+ SCCOL nOld = rCol;
+ if (bOriginMerged)
+ {
+ // Original cell is merged. Push the block end outside the merged region.
+ if (nOrigX < pDoc->MaxCol() && nOrigX < rCol && rCol <= nOrigX + nColSpan - 1)
+ rCol = nOrigX + nColSpan;
+ }
+ else
+ {
+ pDoc->SkipOverlapped(rCol, rRow, nTab);
+ }
+
+ if (nOld < rCol)
+ {
+ // The block end has moved. Check the protection setting and move back if needed.
+ checkBoundary(pDoc, rCol, rRow);
+ if (!isCellQualified(pDoc, rCol, rRow, nTab, bSelectLocked, bSelectUnlocked))
+ --rCol;
+ }
+ }
+ if (nMovX < 0)
+ {
+ SCCOL nOld = rCol;
+ if (bOriginMerged)
+ {
+ if (nOrigX > 0 && nOrigX <= rCol && rCol < nOrigX + nColSpan - 1)
+ // Block end is still within the merged region. Push it outside.
+ rCol = nOrigX - 1;
+ }
+ else
+ {
+ pDoc->SkipOverlapped(rCol, rRow, nTab);
+ }
+
+ if (nOld > rCol)
+ {
+ // The block end has moved. Check the protection setting and move back if needed.
+ checkBoundary(pDoc, rCol, rRow);
+ if (!isCellQualified(pDoc, rCol, rRow, nTab, bSelectLocked, bSelectUnlocked))
+ ++rCol;
+ }
+ }
+ if (nMovY > 0)
+ {
+ SCROW nOld = rRow;
+ if (bOriginMerged)
+ {
+ // Original cell is merged. Push the block end outside the merged region.
+ if (nOrigY < pDoc->MaxRow() && nOrigY < rRow && rRow <= nOrigY + nRowSpan - 1)
+ rRow = nOrigY + nRowSpan;
+ }
+ else
+ {
+ pDoc->SkipOverlapped(rCol, rRow, nTab);
+ }
+
+ if (nOld < rRow)
+ {
+ // The block end has moved. Check the protection setting and move back if needed.
+ checkBoundary(pDoc, rCol, rRow);
+ if (!isCellQualified(pDoc, rCol, rRow, nTab, bSelectLocked, bSelectUnlocked))
+ --rRow;
+ }
+ }
+ if (nMovY >= 0)
+ return;
+
+ SCROW nOld = rRow;
+ if (bOriginMerged)
+ {
+ if (nOrigY > 0 && nOrigY <= rRow && rRow < nOrigY + nRowSpan - 1)
+ // Block end is still within the merged region. Push it outside.
+ rRow = nOrigY - 1;
+ }
+ else
+ {
+ pDoc->SkipOverlapped(rCol, rRow, nTab);
+ }
+
+ if (nOld > rRow)
+ {
+ // The block end has moved. Check the protection setting and move back if needed.
+ checkBoundary(pDoc, rCol, rRow);
+ if (!isCellQualified(pDoc, rCol, rRow, nTab, bSelectLocked, bSelectUnlocked))
+ ++rRow;
+ }
+}
+
+}
+
+void ScTabView::PaintMarks(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
+{
+ auto& rDoc = aViewData.GetDocument();
+ if (!rDoc.ValidCol(nStartCol)) nStartCol = rDoc.MaxCol();
+ if (!rDoc.ValidRow(nStartRow)) nStartRow = rDoc.MaxRow();
+ if (!rDoc.ValidCol(nEndCol)) nEndCol = rDoc.MaxCol();
+ if (!rDoc.ValidRow(nEndRow)) nEndRow = rDoc.MaxRow();
+
+ bool bLeft = (nStartCol==0 && nEndCol==rDoc.MaxCol());
+ bool bTop = (nStartRow==0 && nEndRow==rDoc.MaxRow());
+
+ if (bLeft)
+ PaintLeftArea( nStartRow, nEndRow );
+ if (bTop)
+ PaintTopArea( nStartCol, nEndCol );
+
+ aViewData.GetDocument().ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow,
+ aViewData.GetTabNo() );
+ PaintArea( nStartCol, nStartRow, nEndCol, nEndRow, ScUpdateMode::Marks );
+}
+
+bool ScTabView::IsMarking( SCCOL nCol, SCROW nRow, SCTAB nTab ) const
+{
+ return IsBlockMode()
+ && nBlockStartX == nCol
+ && nBlockStartY == nRow
+ && nBlockStartZ == nTab;
+}
+
+void ScTabView::InitOwnBlockMode( const ScRange& rMarkRange )
+{
+ if (IsBlockMode())
+ return;
+
+ // when there is no (old) selection anymore, delete anchor in SelectionEngine:
+ ScMarkData& rMark = aViewData.GetMarkData();
+ if (!rMark.IsMarked() && !rMark.IsMultiMarked())
+ GetSelEngine()->CursorPosChanging( false, false );
+
+ meBlockMode = Own;
+ nBlockStartX = rMarkRange.aStart.Col();
+ nBlockStartY = rMarkRange.aStart.Row();
+ nBlockStartZ = rMarkRange.aStart.Tab();
+ nBlockEndX = rMarkRange.aEnd.Col();
+ nBlockEndY = rMarkRange.aEnd.Row();
+ nBlockEndZ = rMarkRange.aEnd.Tab();
+
+ SelectionChanged(); // status is checked with mark set
+}
+
+void ScTabView::InitBlockMode( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
+ bool bTestNeg, bool bCols, bool bRows, bool bForceNeg )
+{
+ if (IsBlockMode())
+ return;
+
+ auto& rDoc = aViewData.GetDocument();
+ if (!rDoc.ValidCol(nCurX)) nCurX = rDoc.MaxCol();
+ if (!rDoc.ValidRow(nCurY)) nCurY = rDoc.MaxRow();
+
+ ScMarkData& rMark = aViewData.GetMarkData();
+ SCTAB nTab = aViewData.GetTabNo();
+
+ // unmark part?
+ if (bForceNeg)
+ bBlockNeg = true;
+ else if (bTestNeg)
+ {
+ if ( bCols )
+ bBlockNeg = rMark.IsColumnMarked( nCurX );
+ else if ( bRows )
+ bBlockNeg = rMark.IsRowMarked( nCurY );
+ else
+ bBlockNeg = rMark.IsCellMarked( nCurX, nCurY );
+ }
+ else
+ bBlockNeg = false;
+ rMark.SetMarkNegative(bBlockNeg);
+
+ meBlockMode = Normal;
+ bBlockCols = bCols;
+ bBlockRows = bRows;
+ nBlockStartX = nBlockStartXOrig = nCurX;
+ nBlockStartY = nBlockStartYOrig = nCurY;
+ nBlockStartZ = nCurZ;
+ nBlockEndX = nOldCurX = nBlockStartX;
+ nBlockEndY = nOldCurY = nBlockStartY;
+ nBlockEndZ = nBlockStartZ;
+
+ if (bBlockCols)
+ {
+ nBlockStartY = nBlockStartYOrig = 0;
+ nBlockEndY = rDoc.MaxRow();
+ }
+
+ if (bBlockRows)
+ {
+ nBlockStartX = nBlockStartXOrig = 0;
+ nBlockEndX = rDoc.MaxCol();
+ }
+
+ rMark.SetMarkArea( ScRange( nBlockStartX,nBlockStartY, nTab, nBlockEndX,nBlockEndY, nTab ) );
+
+ UpdateSelectionOverlay();
+}
+
+void ScTabView::DoneBlockMode( bool bContinue )
+{
+ // When switching between sheet and header SelectionEngine DeselectAll may be called,
+ // because the other engine does not have any anchor.
+ // bMoveIsShift prevents the selection to be canceled.
+
+ if (!IsBlockMode() || bMoveIsShift)
+ return;
+
+ ScMarkData& rMark = aViewData.GetMarkData();
+ bool bFlag = rMark.GetMarkingFlag();
+ rMark.SetMarking(false);
+
+ if (bBlockNeg && !bContinue)
+ rMark.MarkToMulti();
+
+ if (bContinue)
+ rMark.MarkToMulti();
+ else
+ {
+ // the sheet may be invalid at this point because DoneBlockMode from SetTabNo is
+ // called (for example, when the current sheet is closed from another View)
+ SCTAB nTab = aViewData.GetTabNo();
+ ScDocument& rDoc = aViewData.GetDocument();
+ if ( rDoc.HasTable(nTab) )
+ PaintBlock( true ); // true -> delete block
+ else
+ rMark.ResetMark();
+ }
+ meBlockMode = None;
+
+ rMark.SetMarking(bFlag);
+ rMark.SetMarkNegative(false);
+}
+
+bool ScTabView::IsBlockMode() const
+{
+ return meBlockMode != None;
+}
+
+void ScTabView::MarkCursor( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ,
+ bool bCols, bool bRows, bool bCellSelection )
+{
+ ScDocument& rDocument = aViewData.GetDocument();
+ if (!rDocument.ValidCol(nCurX)) nCurX = rDocument.MaxCol();
+ if (!rDocument.ValidRow(nCurY)) nCurY = rDocument.MaxRow();
+
+ if (!IsBlockMode())
+ {
+ OSL_FAIL( "MarkCursor not in BlockMode" );
+ InitBlockMode( nCurX, nCurY, nCurZ, false, bCols, bRows );
+ }
+
+ if (bCols)
+ nCurY = rDocument.MaxRow();
+ if (bRows)
+ nCurX = rDocument.MaxCol();
+
+ ScMarkData& rMark = aViewData.GetMarkData();
+ OSL_ENSURE(rMark.IsMarked() || rMark.IsMultiMarked(), "MarkCursor, !IsMarked()");
+ const ScRange& aMarkRange = rMark.GetMarkArea();
+ if (( aMarkRange.aStart.Col() != nBlockStartX && aMarkRange.aEnd.Col() != nBlockStartX ) ||
+ ( aMarkRange.aStart.Row() != nBlockStartY && aMarkRange.aEnd.Row() != nBlockStartY ) ||
+ ( meBlockMode == Own ))
+ {
+ // Mark has been changed
+ // (Eg MarkToSimple if by negative everything was erased, except for a rectangle)
+ // or after InitOwnBlockMode is further marked with shift-
+ bool bOldShift = bMoveIsShift;
+ bMoveIsShift = false; // really move
+ DoneBlockMode(); //! Set variables directly? (-> no flicker)
+ bMoveIsShift = bOldShift;
+
+ InitBlockMode( aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
+ nBlockStartZ, rMark.IsMarkNegative(), bCols, bRows );
+ }
+
+ if ( nCurX != nOldCurX || nCurY != nOldCurY )
+ {
+ // Current cursor has moved
+
+ SCTAB nTab = nCurZ;
+
+ if ( bCellSelection )
+ {
+ // Expand selection area accordingly when the current selection ends
+ // with a merged cell.
+ SCCOL nCurXOffset = 0;
+ SCCOL nBlockStartXOffset = 0;
+ SCROW nCurYOffset = 0;
+ SCROW nBlockStartYOffset = 0;
+ bool bBlockStartMerged = false;
+
+ // The following block checks whether or not the "BlockStart" (anchor)
+ // cell is merged. If it's merged, it'll then move the position of the
+ // anchor cell to the corner that's diagonally opposite of the
+ // direction of a current selection area. For instance, if a current
+ // selection is moving in the upperleft direction, the anchor cell will
+ // move to the lower-right corner of the merged anchor cell, and so on.
+
+ const ScMergeAttr* pMergeAttr =
+ rDocument.GetAttr( nBlockStartXOrig, nBlockStartYOrig, nTab, ATTR_MERGE );
+ if ( pMergeAttr->IsMerged() )
+ {
+ SCCOL nColSpan = pMergeAttr->GetColMerge();
+ SCROW nRowSpan = pMergeAttr->GetRowMerge();
+
+ if ( nCurX < nBlockStartXOrig + nColSpan - 1 || nCurY < nBlockStartYOrig + nRowSpan - 1 )
+ {
+ nBlockStartX = nCurX >= nBlockStartXOrig ? nBlockStartXOrig : nBlockStartXOrig + nColSpan - 1;
+ nBlockStartY = nCurY >= nBlockStartYOrig ? nBlockStartYOrig : nBlockStartYOrig + nRowSpan - 1;
+ nCurXOffset = (nCurX >= nBlockStartXOrig && nCurX < nBlockStartXOrig + nColSpan - 1) ?
+ nBlockStartXOrig - nCurX + nColSpan - 1 : 0;
+ nCurYOffset = (nCurY >= nBlockStartYOrig && nCurY < nBlockStartYOrig + nRowSpan - 1) ?
+ nBlockStartYOrig - nCurY + nRowSpan - 1 : 0;
+ bBlockStartMerged = true;
+ }
+ }
+
+ // The following block checks whether or not the current cell is
+ // merged. If it is, it'll then set the appropriate X & Y offset
+ // values (nCurXOffset & nCurYOffset) such that the selection area will
+ // grow by those specified offset amounts. Note that the values of
+ // nCurXOffset/nCurYOffset may also be specified in the previous code
+ // block, in which case whichever value is greater will take on.
+
+ pMergeAttr = rDocument.GetAttr( nCurX, nCurY, nTab, ATTR_MERGE );
+ if ( pMergeAttr->IsMerged() )
+ {
+ SCCOL nColSpan = pMergeAttr->GetColMerge();
+ SCROW nRowSpan = pMergeAttr->GetRowMerge();
+
+ if ( nBlockStartX < nCurX + nColSpan - 1 || nBlockStartY < nCurY + nRowSpan - 1 )
+ {
+ if ( nBlockStartX <= nCurX + nColSpan - 1 )
+ {
+ SCCOL nCurXOffsetTemp = (nCurX < nCurX + nColSpan - 1) ? nColSpan - 1 : 0;
+ nCurXOffset = std::max(nCurXOffset, nCurXOffsetTemp);
+ }
+ if ( nBlockStartY <= nCurY + nRowSpan - 1 )
+ {
+ SCROW nCurYOffsetTemp = (nCurY < nCurY + nRowSpan - 1) ? nRowSpan - 1 : 0;
+ nCurYOffset = std::max(nCurYOffset, nCurYOffsetTemp);
+ }
+ if ( ( nBlockStartX > nCurX || nBlockStartY > nCurY ) &&
+ ( nBlockStartX <= nCurX + nColSpan - 1 || nBlockStartY <= nCurY + nRowSpan - 1 ) )
+ {
+ nBlockStartXOffset = (nBlockStartX > nCurX && nBlockStartX <= nCurX + nColSpan - 1) ? nCurX - nBlockStartX : 0;
+ nBlockStartYOffset = (nBlockStartY > nCurY && nBlockStartY <= nCurY + nRowSpan - 1) ? nCurY - nBlockStartY : 0;
+ }
+ }
+ }
+ else
+ {
+ // The current cell is not merged. Move the anchor cell to its
+ // original position.
+ if ( !bBlockStartMerged )
+ {
+ nBlockStartX = nBlockStartXOrig;
+ nBlockStartY = nBlockStartYOrig;
+ }
+ }
+
+ nBlockStartX = nBlockStartX + nBlockStartXOffset >= 0 ? nBlockStartX + nBlockStartXOffset : 0;
+ nBlockStartY = nBlockStartY + nBlockStartYOffset >= 0 ? nBlockStartY + nBlockStartYOffset : 0;
+ nBlockEndX = std::min<SCCOL>(nCurX + nCurXOffset, rDocument.MaxCol());
+ nBlockEndY = std::min(nCurY + nCurYOffset, rDocument.MaxRow());
+ }
+ else
+ {
+ nBlockEndX = nCurX;
+ nBlockEndY = nCurY;
+ }
+
+ // Set new selection area
+ rMark.SetMarkArea( ScRange( nBlockStartX, nBlockStartY, nTab, nBlockEndX, nBlockEndY, nTab ) );
+
+ UpdateSelectionOverlay();
+ SelectionChanged();
+
+ nOldCurX = nCurX;
+ nOldCurY = nCurY;
+
+ aViewData.GetViewShell()->UpdateInputHandler();
+ }
+
+ if ( !bCols && !bRows )
+ aHdrFunc.SetAnchorFlag( false );
+}
+
+void ScTabView::GetPageMoveEndPosition(SCCOL nMovX, SCROW nMovY, SCCOL& rPageX, SCROW& rPageY)
+{
+ SCCOL nCurX;
+ SCROW nCurY;
+ if (aViewData.IsRefMode())
+ {
+ nCurX = aViewData.GetRefEndX();
+ nCurY = aViewData.GetRefEndY();
+ }
+ else if (IsBlockMode())
+ {
+ // block end position.
+ nCurX = nBlockEndX;
+ nCurY = nBlockEndY;
+ }
+ else
+ {
+ // cursor position
+ nCurX = aViewData.GetCurX();
+ nCurY = aViewData.GetCurY();
+ }
+
+ ScSplitPos eWhich = aViewData.GetActivePart();
+ ScHSplitPos eWhichX = WhichH( eWhich );
+ ScVSplitPos eWhichY = WhichV( eWhich );
+
+ sal_uInt16 nScrSizeY = SC_SIZE_NONE;
+ if (comphelper::LibreOfficeKit::isActive() && aViewData.GetPageUpDownOffset() > 0) {
+ nScrSizeY = ScViewData::ToPixel( aViewData.GetPageUpDownOffset(), aViewData.GetPPTX() );
+ }
+
+ SCCOL nPageX;
+ SCROW nPageY;
+ if (nMovX >= 0)
+ nPageX = aViewData.CellsAtX( nCurX, 1, eWhichX ) * nMovX;
+ else
+ nPageX = aViewData.CellsAtX( nCurX, -1, eWhichX ) * nMovX;
+
+ if (nMovY >= 0)
+ nPageY = aViewData.CellsAtY( nCurY, 1, eWhichY, nScrSizeY ) * nMovY;
+ else
+ nPageY = aViewData.CellsAtY( nCurY, -1, eWhichY, nScrSizeY ) * nMovY;
+
+ if (nMovX != 0 && nPageX == 0) nPageX = (nMovX>0) ? 1 : -1;
+ if (nMovY != 0 && nPageY == 0) nPageY = (nMovY>0) ? 1 : -1;
+
+ rPageX = nPageX;
+ rPageY = nPageY;
+}
+
+void ScTabView::GetAreaMoveEndPosition(SCCOL nMovX, SCROW nMovY, ScFollowMode eMode,
+ SCCOL& rAreaX, SCROW& rAreaY, ScFollowMode& rMode)
+{
+ SCCOL nNewX = -1;
+ SCROW nNewY = -1;
+
+ // current cursor position.
+ SCCOL nCurX = aViewData.GetCurX();
+ SCROW nCurY = aViewData.GetCurY();
+
+ if (aViewData.IsRefMode())
+ {
+ nNewX = aViewData.GetRefEndX();
+ nNewY = aViewData.GetRefEndY();
+ nCurX = aViewData.GetRefStartX();
+ nCurY = aViewData.GetRefStartY();
+ }
+ else if (IsBlockMode())
+ {
+ // block end position.
+ nNewX = nBlockEndX;
+ nNewY = nBlockEndY;
+ }
+ else
+ {
+ nNewX = nCurX;
+ nNewY = nCurY;
+ }
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+
+ // FindAreaPos knows only -1 or 1 as direction
+ ScModule* pScModule = SC_MOD();
+ bool bLegacyCellSelection = pScModule->GetInputOptions().GetLegacyCellSelection();
+ SCCOL nVirtualX = bLegacyCellSelection ? nNewX : nCurX;
+ SCROW nVirtualY = bLegacyCellSelection ? nNewY : nCurY;
+
+ SCCOLROW i;
+ if ( nMovX > 0 )
+ for ( i=0; i<nMovX; i++ )
+ rDoc.FindAreaPos( nNewX, nVirtualY, nTab, SC_MOVE_RIGHT );
+ if ( nMovX < 0 )
+ for ( i=0; i<-nMovX; i++ )
+ rDoc.FindAreaPos( nNewX, nVirtualY, nTab, SC_MOVE_LEFT );
+ if ( nMovY > 0 )
+ for ( i=0; i<nMovY; i++ )
+ rDoc.FindAreaPos( nVirtualX, nNewY, nTab, SC_MOVE_DOWN );
+ if ( nMovY < 0 )
+ for ( i=0; i<-nMovY; i++ )
+ rDoc.FindAreaPos( nVirtualX, nNewY, nTab, SC_MOVE_UP );
+
+ if (eMode==SC_FOLLOW_JUMP) // bottom right do not show too much grey
+ {
+ if (nMovX != 0 && nNewX == rDoc.MaxCol())
+ eMode = SC_FOLLOW_LINE;
+ if (nMovY != 0 && nNewY == rDoc.MaxRow())
+ eMode = SC_FOLLOW_LINE;
+ }
+
+ if (aViewData.IsRefMode())
+ {
+ rAreaX = nNewX - aViewData.GetRefEndX();
+ rAreaY = nNewY - aViewData.GetRefEndY();
+ }
+ else if (IsBlockMode())
+ {
+ rAreaX = nNewX - nBlockEndX;
+ rAreaY = nNewY - nBlockEndY;
+ }
+ else
+ {
+ rAreaX = nNewX - nCurX;
+ rAreaY = nNewY - nCurY;
+ }
+ rMode = eMode;
+}
+
+void ScTabView::SkipCursorHorizontal(SCCOL& rCurX, SCROW& rCurY, SCCOL nOldX, SCCOL nMovX)
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+
+ bool bSkipProtected = false, bSkipUnprotected = false;
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ if (pProtect && pProtect->isProtected())
+ {
+ bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
+ bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
+ }
+
+ bool bSkipCell = false;
+ bool bHFlip = false;
+ // If a number of last columns are hidden, search up to and including the first of them,
+ // because after it nothing changes.
+ SCCOL nMaxCol;
+ if(rDoc.ColHidden(rDoc.MaxCol(), nTab, &nMaxCol))
+ ++nMaxCol;
+ else
+ nMaxCol = rDoc.MaxCol();
+ // Search also at least up to and including the first unallocated column (all unallocated columns
+ // share a set of attrs).
+ nMaxCol = std::max( nMaxCol, std::min<SCCOL>( rDoc.GetAllocatedColumnsCount(nTab) + 1, rDoc.MaxCol()));
+ do
+ {
+ bSkipCell = rDoc.ColHidden(rCurX, nTab) || rDoc.IsHorOverlapped(rCurX, rCurY, nTab);
+ if (bSkipProtected && !bSkipCell)
+ bSkipCell = rDoc.HasAttrib(rCurX, rCurY, nTab, rCurX, rCurY, nTab, HasAttrFlags::Protected);
+ if (bSkipUnprotected && !bSkipCell)
+ bSkipCell = !rDoc.HasAttrib(rCurX, rCurY, nTab, rCurX, rCurY, nTab, HasAttrFlags::Protected);
+
+ if (bSkipCell)
+ {
+ if (rCurX <= 0 || rCurX >= nMaxCol)
+ {
+ if (bHFlip)
+ {
+ rCurX = nOldX;
+ bSkipCell = false;
+ }
+ else
+ {
+ nMovX = -nMovX;
+ if (nMovX > 0)
+ ++rCurX;
+ else
+ --rCurX;
+ bHFlip = true;
+ }
+ }
+ else
+ if (nMovX > 0)
+ ++rCurX;
+ else
+ --rCurX;
+ }
+ }
+ while (bSkipCell);
+
+ if (rDoc.IsVerOverlapped(rCurX, rCurY, nTab))
+ {
+ aViewData.SetOldCursor(rCurX, rCurY);
+ while (rDoc.IsVerOverlapped(rCurX, rCurY, nTab))
+ --rCurY;
+ }
+}
+
+void ScTabView::SkipCursorVertical(SCCOL& rCurX, SCROW& rCurY, SCROW nOldY, SCROW nMovY)
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+
+ bool bSkipProtected = false, bSkipUnprotected = false;
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ if (pProtect && pProtect->isProtected())
+ {
+ bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
+ bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
+ }
+
+ bool bSkipCell = false;
+ bool bVFlip = false;
+ // Avoid repeated calls to RowHidden(), IsVerOverlapped() and HasAttrib().
+ SCROW nFirstSameHiddenRow = -1;
+ SCROW nLastSameHiddenRow = -1;
+ bool bRowHidden = false;
+ SCROW nFirstSameIsVerOverlapped = -1;
+ SCROW nLastSameIsVerOverlapped = -1;
+ bool bIsVerOverlapped = false;
+ SCROW nFirstSameHasAttribRow = -1;
+ SCROW nLastSameHasAttribRow = -1;
+ bool bHasAttribProtected = false;
+ do
+ {
+ if( rCurY < nFirstSameHiddenRow || rCurY > nLastSameHiddenRow )
+ bRowHidden = rDoc.RowHidden(rCurY, nTab, &nFirstSameHiddenRow, &nLastSameHiddenRow);
+ bSkipCell = bRowHidden;
+ if( !bSkipCell )
+ {
+ if( rCurY < nFirstSameIsVerOverlapped || rCurY > nLastSameIsVerOverlapped )
+ bIsVerOverlapped = rDoc.IsVerOverlapped(rCurX, rCurY, nTab, &nFirstSameIsVerOverlapped, &nLastSameIsVerOverlapped);
+ bSkipCell = bIsVerOverlapped;
+ }
+ if (bSkipProtected && !bSkipCell)
+ {
+ if( rCurY < nFirstSameHasAttribRow || rCurY > nLastSameHasAttribRow )
+ bHasAttribProtected = rDoc.HasAttrib(rCurX, rCurY, nTab, HasAttrFlags::Protected,
+ &nFirstSameHasAttribRow, &nLastSameHasAttribRow);
+ bSkipCell = bHasAttribProtected;
+ }
+ if (bSkipUnprotected && !bSkipCell)
+ {
+ if( rCurY < nFirstSameHasAttribRow || rCurY > nLastSameHasAttribRow )
+ bHasAttribProtected = rDoc.HasAttrib(rCurX, rCurY, nTab, HasAttrFlags::Protected,
+ &nFirstSameHasAttribRow, &nLastSameHasAttribRow);
+ bSkipCell = !bHasAttribProtected;
+ }
+
+ if (bSkipCell)
+ {
+ if (rCurY <= 0 || rCurY >= rDoc.MaxRow())
+ {
+ if (bVFlip)
+ {
+ rCurY = nOldY;
+ bSkipCell = false;
+ }
+ else
+ {
+ nMovY = -nMovY;
+ if (nMovY > 0)
+ ++rCurY;
+ else
+ --rCurY;
+ bVFlip = true;
+ }
+ }
+ else
+ if (nMovY > 0)
+ ++rCurY;
+ else
+ --rCurY;
+ }
+ }
+ while (bSkipCell);
+
+ if (rDoc.IsHorOverlapped(rCurX, rCurY, nTab))
+ {
+ aViewData.SetOldCursor(rCurX, rCurY);
+ while (rDoc.IsHorOverlapped(rCurX, rCurY, nTab))
+ --rCurX;
+ }
+}
+
+void ScTabView::ExpandBlock(SCCOL nMovX, SCROW nMovY, ScFollowMode eMode)
+{
+ if (!nMovX && !nMovY)
+ // Nothing to do. Bail out.
+ return;
+
+ ScTabViewShell* pViewShell = aViewData.GetViewShell();
+ bool bRefInputMode = pViewShell && pViewShell->IsRefInputMode();
+ if (bRefInputMode && !aViewData.IsRefMode())
+ // initialize formula reference mode if it hasn't already.
+ InitRefMode(aViewData.GetCurX(), aViewData.GetCurY(), aViewData.GetTabNo(), SC_REFTYPE_REF);
+
+ ScDocument& rDoc = aViewData.GetDocument();
+
+ if (aViewData.IsRefMode())
+ {
+ // formula reference mode
+
+ SCCOL nNewX = aViewData.GetRefEndX();
+ SCROW nNewY = aViewData.GetRefEndY();
+ SCTAB nRefTab = aViewData.GetRefEndZ();
+
+ bool bSelectLocked = true;
+ bool bSelectUnlocked = true;
+ const ScTableProtection* pTabProtection = rDoc.GetTabProtection(nRefTab);
+ if (pTabProtection && pTabProtection->isProtected())
+ {
+ bSelectLocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
+ bSelectUnlocked = pTabProtection->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
+ }
+
+ moveCursorByProtRule(nNewX, nNewY, nMovX, nMovY, nRefTab, &rDoc);
+ checkBoundary(&rDoc, nNewX, nNewY);
+
+ if (nMovX)
+ {
+ SCCOL nTempX = nNewX;
+ while (rDoc.IsHorOverlapped(nTempX, nNewY, nRefTab))
+ {
+ if (nMovX > 0)
+ ++nTempX;
+ else
+ --nTempX;
+ if (!checkBoundary(&rDoc, nTempX, nNewY))
+ break;
+ }
+ if (isCellQualified(&rDoc, nTempX, nNewY, nRefTab, bSelectLocked, bSelectUnlocked))
+ nNewX = nTempX;
+ }
+
+ if (nMovY)
+ {
+ SCROW nTempY = nNewY;
+ while (rDoc.IsVerOverlapped(nNewX, nTempY, nRefTab))
+ {
+ if (nMovY > 0)
+ ++nTempY;
+ else
+ --nTempY;
+ if (!checkBoundary(&rDoc, nNewX, nTempY))
+ break;
+ }
+ if (isCellQualified(&rDoc, nNewX, nTempY, nRefTab, bSelectLocked, bSelectUnlocked))
+ nNewY = nTempY;
+ }
+
+ rDoc.SkipOverlapped(nNewX, nNewY, nRefTab);
+ UpdateRef(nNewX, nNewY, nRefTab);
+ SCCOL nTargetCol = nNewX;
+ SCROW nTargetRow = nNewY;
+ if (((aViewData.GetRefStartX() == 0) || (aViewData.GetRefStartY() == 0)) &&
+ ((nNewX != rDoc.MaxCol()) || (nNewY != rDoc.MaxRow())))
+ {
+ // Row selection
+ if ((aViewData.GetRefStartX() == 0) && (nNewX == rDoc.MaxCol()))
+ nTargetCol = aViewData.GetCurX();
+ // Column selection
+ if ((aViewData.GetRefStartY() == 0) && (nNewY == rDoc.MaxRow()))
+ nTargetRow = aViewData.GetCurY();
+ }
+ AlignToCursor(nTargetCol, nTargetRow, eMode);
+ }
+ else
+ {
+ // normal selection mode
+
+ SCTAB nTab = aViewData.GetTabNo();
+ SCCOL nOrigX = aViewData.GetCurX();
+ SCROW nOrigY = aViewData.GetCurY();
+
+ // Note that the origin position *never* moves during selection.
+
+ if (!IsBlockMode())
+ InitBlockMode(nOrigX, nOrigY, nTab, true);
+
+ moveCursorByProtRule(nBlockEndX, nBlockEndY, nMovX, nMovY, nTab, &rDoc);
+ checkBoundary(&rDoc, nBlockEndX, nBlockEndY);
+ moveCursorByMergedCell(nBlockEndX, nBlockEndY, nMovX, nMovY, nTab, &rDoc, aViewData);
+ checkBoundary(&rDoc, nBlockEndX, nBlockEndY);
+
+ MarkCursor(nBlockEndX, nBlockEndY, nTab, false, false, true);
+
+ // Check if the entire row(s) or column(s) are selected.
+ ScSplitPos eActive = aViewData.GetActivePart();
+ bool bRowSelected = (nBlockStartX == 0 && nBlockEndX == rDoc.MaxCol());
+ bool bColSelected = (nBlockStartY == 0 && nBlockEndY == rDoc.MaxRow());
+ SCCOL nAlignX = bRowSelected ? aViewData.GetPosX(WhichH(eActive)) : nBlockEndX;
+ SCROW nAlignY = bColSelected ? aViewData.GetPosY(WhichV(eActive)) : nBlockEndY;
+ AlignToCursor(nAlignX, nAlignY, eMode);
+
+ SelectionChanged();
+ }
+}
+
+void ScTabView::ExpandBlockPage(SCCOL nMovX, SCROW nMovY)
+{
+ SCCOL nPageX;
+ SCROW nPageY;
+ GetPageMoveEndPosition(nMovX, nMovY, nPageX, nPageY);
+ ExpandBlock(nPageX, nPageY, SC_FOLLOW_FIX);
+}
+
+void ScTabView::ExpandBlockArea(SCCOL nMovX, SCROW nMovY)
+{
+ SCCOL nAreaX;
+ SCROW nAreaY;
+ ScFollowMode eMode;
+ GetAreaMoveEndPosition(nMovX, nMovY, SC_FOLLOW_JUMP, nAreaX, nAreaY, eMode);
+ ExpandBlock(nAreaX, nAreaY, eMode);
+}
+
+void ScTabView::UpdateCopySourceOverlay()
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ if (pWin && pWin->IsVisible())
+ pWin->UpdateCopySourceOverlay();
+}
+
+void ScTabView::UpdateSelectionOverlay()
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ if ( pWin && pWin->IsVisible() )
+ pWin->UpdateSelectionOverlay();
+}
+
+void ScTabView::UpdateShrinkOverlay()
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ if ( pWin && pWin->IsVisible() )
+ pWin->UpdateShrinkOverlay();
+}
+
+void ScTabView::UpdateAllOverlays()
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ if ( pWin && pWin->IsVisible() )
+ pWin->UpdateAllOverlays();
+}
+
+//!
+//! divide PaintBlock into two methods: RepaintBlock and RemoveBlock or similar
+//!
+
+void ScTabView::PaintBlock( bool bReset )
+{
+ ScMarkData& rMark = aViewData.GetMarkData();
+ SCTAB nTab = aViewData.GetTabNo();
+ bool bMulti = rMark.IsMultiMarked();
+ if (!(rMark.IsMarked() || bMulti))
+ return;
+
+ ScRange aMarkRange;
+ HideAllCursors();
+ if (bMulti)
+ {
+ bool bFlag = rMark.GetMarkingFlag();
+ rMark.SetMarking(false);
+ rMark.MarkToMulti();
+ aMarkRange = rMark.GetMultiMarkArea();
+ rMark.MarkToSimple();
+ rMark.SetMarking(bFlag);
+ }
+ else
+ aMarkRange = rMark.GetMarkArea();
+
+ nBlockStartX = aMarkRange.aStart.Col();
+ nBlockStartY = aMarkRange.aStart.Row();
+ nBlockStartZ = aMarkRange.aStart.Tab();
+ nBlockEndX = aMarkRange.aEnd.Col();
+ nBlockEndY = aMarkRange.aEnd.Row();
+ nBlockEndZ = aMarkRange.aEnd.Tab();
+
+ bool bDidReset = false;
+
+ if ( nTab>=nBlockStartZ && nTab<=nBlockEndZ )
+ {
+ if ( bReset )
+ {
+ // Inverting when deleting only on active View
+ if ( aViewData.IsActive() )
+ {
+ rMark.ResetMark();
+ UpdateSelectionOverlay();
+ bDidReset = true;
+ }
+ }
+ else
+ PaintMarks( nBlockStartX, nBlockStartY, nBlockEndX, nBlockEndY );
+ }
+
+ if ( bReset && !bDidReset )
+ rMark.ResetMark();
+
+ ShowAllCursors();
+}
+
+void ScTabView::SelectAll( bool bContinue )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ ScMarkData& rMark = aViewData.GetMarkData();
+ SCTAB nTab = aViewData.GetTabNo();
+
+ if (rMark.IsMarked())
+ {
+ if ( rMark.GetMarkArea() == ScRange( 0,0,nTab, rDoc.MaxCol(),rDoc.MaxRow(),nTab ) )
+ return;
+ }
+
+ DoneBlockMode( bContinue );
+ InitBlockMode( 0,0,nTab );
+ MarkCursor( rDoc.MaxCol(),rDoc.MaxRow(),nTab );
+
+ SelectionChanged();
+}
+
+void ScTabView::SelectAllTables()
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ ScMarkData& rMark = aViewData.GetMarkData();
+ SCTAB nCount = rDoc.GetTableCount();
+
+ if (nCount>1)
+ {
+ for (SCTAB i=0; i<nCount; i++)
+ rMark.SelectTable( i, true );
+
+ aViewData.GetDocShell()->PostPaintExtras();
+ SfxBindings& rBind = aViewData.GetBindings();
+ rBind.Invalidate( FID_FILL_TAB );
+ rBind.Invalidate( FID_TAB_DESELECTALL );
+ }
+}
+
+void ScTabView::DeselectAllTables()
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ ScMarkData& rMark = aViewData.GetMarkData();
+ SCTAB nTab = aViewData.GetTabNo();
+ SCTAB nCount = rDoc.GetTableCount();
+
+ for (SCTAB i=0; i<nCount; i++)
+ rMark.SelectTable( i, ( i == nTab ) );
+
+ aViewData.GetDocShell()->PostPaintExtras();
+ SfxBindings& rBind = aViewData.GetBindings();
+ rBind.Invalidate( FID_FILL_TAB );
+ rBind.Invalidate( FID_TAB_DESELECTALL );
+}
+
+static bool lcl_FitsInWindow( double fScaleX, double fScaleY, sal_uInt16 nZoom,
+ tools::Long nWindowX, tools::Long nWindowY, const ScDocument* pDoc, SCTAB nTab,
+ SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ SCCOL nFixPosX, SCROW nFixPosY )
+{
+ double fZoomFactor = static_cast<double>(Fraction(nZoom,100));
+ fScaleX *= fZoomFactor;
+ fScaleY *= fZoomFactor;
+
+ tools::Long nBlockX = 0;
+ SCCOL nCol;
+ for (nCol=0; nCol<nFixPosX; nCol++)
+ {
+ // for frozen panes, add both parts
+ sal_uInt16 nColTwips = pDoc->GetColWidth( nCol, nTab );
+ if (nColTwips)
+ {
+ nBlockX += static_cast<tools::Long>(nColTwips * fScaleX);
+ if (nBlockX > nWindowX)
+ return false;
+ }
+ }
+ for (nCol=nStartCol; nCol<=nEndCol; nCol++)
+ {
+ sal_uInt16 nColTwips = pDoc->GetColWidth( nCol, nTab );
+ if (nColTwips)
+ {
+ nBlockX += static_cast<tools::Long>(nColTwips * fScaleX);
+ if (nBlockX > nWindowX)
+ return false;
+ }
+ }
+
+ tools::Long nBlockY = 0;
+ for (SCROW nRow = 0; nRow <= nFixPosY-1; ++nRow)
+ {
+ if (pDoc->RowHidden(nRow, nTab))
+ continue;
+
+ // for frozen panes, add both parts
+ sal_uInt16 nRowTwips = pDoc->GetRowHeight(nRow, nTab);
+ if (nRowTwips)
+ {
+ nBlockY += static_cast<tools::Long>(nRowTwips * fScaleY);
+ if (nBlockY > nWindowY)
+ return false;
+ }
+ }
+ for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
+ {
+ sal_uInt16 nRowTwips = pDoc->GetRowHeight(nRow, nTab);
+ if (nRowTwips)
+ {
+ nBlockY += static_cast<tools::Long>(nRowTwips * fScaleY);
+ if (nBlockY > nWindowY)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+sal_uInt16 ScTabView::CalcZoom( SvxZoomType eType, sal_uInt16 nOldZoom )
+{
+ sal_uInt16 nZoom = 100;
+
+ switch ( eType )
+ {
+ case SvxZoomType::PERCENT: // rZoom is no particular percent value
+ nZoom = nOldZoom;
+ break;
+
+ case SvxZoomType::OPTIMAL: // nZoom corresponds to the optimal size
+ {
+ ScMarkData& rMark = aViewData.GetMarkData();
+ ScDocument& rDoc = aViewData.GetDocument();
+
+ if (!rMark.IsMarked() && !rMark.IsMultiMarked())
+ nZoom = 100; // nothing selected
+ else
+ {
+ SCTAB nTab = aViewData.GetTabNo();
+ ScRange aMarkRange;
+ if ( aViewData.GetSimpleArea( aMarkRange ) != SC_MARK_SIMPLE )
+ aMarkRange = rMark.GetMultiMarkArea();
+
+ SCCOL nStartCol = aMarkRange.aStart.Col();
+ SCROW nStartRow = aMarkRange.aStart.Row();
+ SCTAB nStartTab = aMarkRange.aStart.Tab();
+ SCCOL nEndCol = aMarkRange.aEnd.Col();
+ SCROW nEndRow = aMarkRange.aEnd.Row();
+ SCTAB nEndTab = aMarkRange.aEnd.Tab();
+
+ if ( nTab < nStartTab && nTab > nEndTab )
+ nTab = nStartTab;
+
+ ScSplitPos eUsedPart = aViewData.GetActivePart();
+
+ SCCOL nFixPosX = 0;
+ SCROW nFixPosY = 0;
+ if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
+ {
+ // use right part
+ eUsedPart = (WhichV(eUsedPart)==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT;
+ nFixPosX = aViewData.GetFixPosX();
+ if ( nStartCol < nFixPosX )
+ nStartCol = nFixPosX;
+ }
+ if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
+ {
+ // use bottom part
+ eUsedPart = (WhichH(eUsedPart)==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT;
+ nFixPosY = aViewData.GetFixPosY();
+ if ( nStartRow < nFixPosY )
+ nStartRow = nFixPosY;
+ }
+
+ if (pGridWin[eUsedPart])
+ {
+ // Because scale is rounded to pixels, the only reliable way to find
+ // the right scale is to check if a zoom fits
+
+ Size aWinSize = pGridWin[eUsedPart]->GetOutputSizePixel();
+
+ // for frozen panes, use sum of both parts for calculation
+
+ if ( nFixPosX != 0 )
+ aWinSize.AdjustWidth(GetGridWidth( SC_SPLIT_LEFT ) );
+ if ( nFixPosY != 0 )
+ aWinSize.AdjustHeight(GetGridHeight( SC_SPLIT_TOP ) );
+
+ ScDocShell* pDocSh = aViewData.GetDocShell();
+ double nPPTX = ScGlobal::nScreenPPTX / pDocSh->GetOutputFactor();
+ double nPPTY = ScGlobal::nScreenPPTY;
+
+ sal_uInt16 nMin = MINZOOM;
+ sal_uInt16 nMax = MAXZOOM;
+ while ( nMax > nMin )
+ {
+ sal_uInt16 nTest = (nMin+nMax+1)/2;
+ if ( lcl_FitsInWindow(
+ nPPTX, nPPTY, nTest, aWinSize.Width(), aWinSize.Height(),
+ &rDoc, nTab, nStartCol, nStartRow, nEndCol, nEndRow,
+ nFixPosX, nFixPosY ) )
+ nMin = nTest;
+ else
+ nMax = nTest-1;
+ }
+ OSL_ENSURE( nMin == nMax, "Nesting is wrong" );
+ nZoom = nMin;
+
+ if ( nZoom != nOldZoom )
+ {
+ // scroll to block only in active split part
+ // (the part for which the size was calculated)
+
+ if ( nStartCol <= nEndCol )
+ aViewData.SetPosX( WhichH(eUsedPart), nStartCol );
+ if ( nStartRow <= nEndRow )
+ aViewData.SetPosY( WhichV(eUsedPart), nStartRow );
+ }
+ }
+ }
+ }
+ break;
+
+ case SvxZoomType::WHOLEPAGE: // nZoom corresponds to the whole page or
+ case SvxZoomType::PAGEWIDTH: // nZoom corresponds to the page width
+ {
+ SCTAB nCurTab = aViewData.GetTabNo();
+ ScDocument& rDoc = aViewData.GetDocument();
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet =
+ pStylePool->Find( rDoc.GetPageStyle( nCurTab ),
+ SfxStyleFamily::Page );
+
+ OSL_ENSURE( pStyleSheet, "PageStyle not found :-/" );
+
+ if ( pStyleSheet )
+ {
+ ScPrintFunc aPrintFunc( aViewData.GetDocShell(),
+ aViewData.GetViewShell()->GetPrinter(true),
+ nCurTab );
+
+ Size aPageSize = aPrintFunc.GetDataSize();
+
+ // use the size of the largest GridWin for normal split,
+ // or both combined for frozen panes, with the (document) size
+ // of the frozen part added to the page size
+ // (with frozen panes, the size of the individual parts
+ // depends on the scale that is to be calculated)
+
+ if (!pGridWin[SC_SPLIT_BOTTOMLEFT])
+ return nZoom;
+
+ Size aWinSize = pGridWin[SC_SPLIT_BOTTOMLEFT]->GetOutputSizePixel();
+ ScSplitMode eHMode = aViewData.GetHSplitMode();
+ if ( eHMode != SC_SPLIT_NONE && pGridWin[SC_SPLIT_BOTTOMRIGHT] )
+ {
+ tools::Long nOtherWidth = pGridWin[SC_SPLIT_BOTTOMRIGHT]->
+ GetOutputSizePixel().Width();
+ if ( eHMode == SC_SPLIT_FIX )
+ {
+ aWinSize.AdjustWidth(nOtherWidth );
+ for ( SCCOL nCol = aViewData.GetPosX(SC_SPLIT_LEFT);
+ nCol < aViewData.GetFixPosX(); nCol++ )
+ aPageSize.AdjustWidth(rDoc.GetColWidth( nCol, nCurTab ) );
+ }
+ else if ( nOtherWidth > aWinSize.Width() )
+ aWinSize.setWidth( nOtherWidth );
+ }
+ ScSplitMode eVMode = aViewData.GetVSplitMode();
+ if ( eVMode != SC_SPLIT_NONE && pGridWin[SC_SPLIT_TOPLEFT] )
+ {
+ tools::Long nOtherHeight = pGridWin[SC_SPLIT_TOPLEFT]->
+ GetOutputSizePixel().Height();
+ if ( eVMode == SC_SPLIT_FIX )
+ {
+ aWinSize.AdjustHeight(nOtherHeight );
+ aPageSize.AdjustHeight(rDoc.GetRowHeight(
+ aViewData.GetPosY(SC_SPLIT_TOP),
+ aViewData.GetFixPosY()-1, nCurTab) );
+ }
+ else if ( nOtherHeight > aWinSize.Height() )
+ aWinSize.setHeight( nOtherHeight );
+ }
+
+ double nPPTX = ScGlobal::nScreenPPTX / aViewData.GetDocShell()->GetOutputFactor();
+ double nPPTY = ScGlobal::nScreenPPTY;
+
+ tools::Long nZoomX = static_cast<tools::Long>( aWinSize.Width() * 100 /
+ ( aPageSize.Width() * nPPTX ) );
+ tools::Long nZoomY = static_cast<tools::Long>( aWinSize.Height() * 100 /
+ ( aPageSize.Height() * nPPTY ) );
+
+ if (nZoomX > 0)
+ nZoom = static_cast<sal_uInt16>(nZoomX);
+
+ if (eType == SvxZoomType::WHOLEPAGE && nZoomY > 0 && nZoomY < nZoom)
+ nZoom = static_cast<sal_uInt16>(nZoomY);
+ }
+ }
+ break;
+
+ default:
+ OSL_FAIL("Unknown Zoom-Revision");
+ }
+
+ return nZoom;
+}
+
+// is called for instance when the view window is shifted:
+
+void ScTabView::StopMarking()
+{
+ ScSplitPos eActive = aViewData.GetActivePart();
+ if (pGridWin[eActive])
+ pGridWin[eActive]->StopMarking();
+
+ ScHSplitPos eH = WhichH(eActive);
+ if (pColBar[eH])
+ pColBar[eH]->StopMarking();
+
+ ScVSplitPos eV = WhichV(eActive);
+ if (pRowBar[eV])
+ pRowBar[eV]->StopMarking();
+}
+
+void ScTabView::HideNoteMarker()
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ if (pWin && pWin->IsVisible())
+ pWin->HideNoteMarker();
+}
+
+void ScTabView::MakeDrawLayer()
+{
+ if (pDrawView)
+ return;
+
+ aViewData.GetDocShell()->MakeDrawLayer();
+
+ // pDrawView is set per Notify
+ OSL_ENSURE(pDrawView,"ScTabView::MakeDrawLayer does not work");
+
+ for(VclPtr<ScGridWindow> & pWin : pGridWin)
+ {
+ if(pWin)
+ {
+ pWin->DrawLayerCreated();
+ }
+ }
+}
+
+void ScTabView::ErrorMessage(TranslateId pGlobStrId)
+{
+ if ( SC_MOD()->IsInExecuteDrop() )
+ {
+ // #i28468# don't show error message when called from Drag&Drop, silently abort instead
+ return;
+ }
+
+ StopMarking(); // if called by Focus from MouseButtonDown
+
+ weld::Window* pParent = aViewData.GetDialogParent();
+ weld::WaitObject aWaitOff( pParent );
+ bool bFocus = pParent && pParent->has_focus();
+
+ if (pGlobStrId && pGlobStrId == STR_PROTECTIONERR)
+ {
+ if (aViewData.GetDocShell()->IsReadOnly())
+ {
+ pGlobStrId = STR_READONLYERR;
+ }
+ }
+
+ m_xMessageBox.reset(Application::CreateMessageDialog(pParent,
+ VclMessageType::Info, VclButtonsType::Ok,
+ ScResId(pGlobStrId)));
+ weld::Window* pGrabOnClose = bFocus ? pParent : nullptr;
+ m_xMessageBox->runAsync(m_xMessageBox, [this, pGrabOnClose](sal_Int32 /*nResult*/) {
+ m_xMessageBox.reset();
+ if (pGrabOnClose)
+ pGrabOnClose->grab_focus();
+ });
+}
+
+void ScTabView::UpdatePageBreakData( bool bForcePaint )
+{
+ std::unique_ptr<ScPageBreakData> pNewData;
+
+ if (aViewData.IsPagebreakMode())
+ {
+ ScDocShell* pDocSh = aViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+
+ sal_uInt16 nCount = rDoc.GetPrintRangeCount(nTab);
+ if (!nCount)
+ nCount = 1;
+ pNewData.reset( new ScPageBreakData(nCount) );
+
+ ScPrintFunc aPrintFunc( pDocSh, pDocSh->GetPrinter(), nTab, 0,0,nullptr, nullptr, pNewData.get() );
+ // ScPrintFunc fills the PageBreakData in ctor
+ if ( nCount > 1 )
+ {
+ aPrintFunc.ResetBreaks(nTab);
+ pNewData->AddPages();
+ }
+
+ // print area changed?
+ if ( bForcePaint || ( pPageBreakData && !( *pPageBreakData == *pNewData ) ) )
+ PaintGrid();
+ }
+
+ pPageBreakData = std::move(pNewData);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabview3.cxx b/sc/source/ui/view/tabview3.cxx
new file mode 100644
index 000000000..0fe06e1c4
--- /dev/null
+++ b/sc/source/ui/view/tabview3.cxx
@@ -0,0 +1,3112 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <rangelst.hxx>
+#include <scitems.hxx>
+
+#include <editeng/editview.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/sdr/overlay/overlaymanager.hxx>
+#include <svx/svdoole2.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <vcl/cursor.hxx>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+#include <IAnyRefDialog.hxx>
+#include <tabview.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <gridwin.hxx>
+#include <olinewin.hxx>
+#include <overlayobject.hxx>
+#include <colrowba.hxx>
+#include <tabcont.hxx>
+#include <scmod.hxx>
+#include <sc.hrc>
+#include <viewutil.hxx>
+#include <editutil.hxx>
+#include <inputhdl.hxx>
+#include <inputwin.hxx>
+#include <validat.hxx>
+#include <inputopt.hxx>
+#include <rfindlst.hxx>
+#include <hiranges.hxx>
+#include <viewuno.hxx>
+#include <dpobject.hxx>
+#include <seltrans.hxx>
+#include <fillinfo.hxx>
+#include <rangeutl.hxx>
+#include <client.hxx>
+#include <tabprotection.hxx>
+#include <spellcheckcontext.hxx>
+#include <markdata.hxx>
+#include <formula/FormulaCompiler.hxx>
+#include <comphelper/lok.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <output.hxx>
+
+#include <utility>
+
+#include <com/sun/star/chart2/data/HighlightedRange.hpp>
+
+namespace
+{
+
+ScRange lcl_getSubRangeByIndex( const ScRange& rRange, sal_Int32 nIndex )
+{
+ ScAddress aResult( rRange.aStart );
+
+ SCCOL nWidth = rRange.aEnd.Col() - rRange.aStart.Col() + 1;
+ SCROW nHeight = rRange.aEnd.Row() - rRange.aStart.Row() + 1;
+ SCTAB nDepth = rRange.aEnd.Tab() - rRange.aStart.Tab() + 1;
+ if( (nWidth > 0) && (nHeight > 0) && (nDepth > 0) )
+ {
+ // row by row from first to last sheet
+ sal_Int32 nArea = nWidth * nHeight;
+ aResult.IncCol( static_cast< SCCOL >( nIndex % nWidth ) );
+ aResult.IncRow( static_cast< SCROW >( (nIndex % nArea) / nWidth ) );
+ aResult.IncTab( static_cast< SCTAB >( nIndex / nArea ) );
+ if( !rRange.Contains( aResult ) )
+ aResult = rRange.aStart;
+ }
+
+ return ScRange( aResult );
+}
+
+} // anonymous namespace
+
+using namespace com::sun::star;
+
+ScExtraEditViewManager::~ScExtraEditViewManager()
+{
+ DBG_ASSERT(nTotalWindows == 0, "ScExtraEditViewManager dtor: some out window has not yet been removed!");
+}
+
+inline void ScExtraEditViewManager::Add(SfxViewShell* pViewShell, ScSplitPos eWhich)
+{
+ Apply<Adder>(pViewShell, eWhich);
+}
+
+inline void ScExtraEditViewManager::Remove(SfxViewShell* pViewShell, ScSplitPos eWhich)
+{
+ Apply<Remover>(pViewShell, eWhich);
+}
+
+
+template<ScExtraEditViewManager::ModifierTagType ModifierTag>
+void ScExtraEditViewManager::Apply(SfxViewShell* pViewShell, ScSplitPos eWhich)
+{
+ ScTabViewShell* pOtherViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pOtherViewShell == nullptr || pOtherViewShell == mpThisViewShell)
+ return;
+
+ mpOtherEditView = pOtherViewShell->GetViewData().GetEditView(eWhich);
+ if (mpOtherEditView != nullptr)
+ {
+ DBG_ASSERT(mpOtherEditView->GetEditEngine(), "Edit view has no valid engine.");
+ for (int i = 0; i < 4; ++i)
+ {
+ ScGridWindow* pWin = mpGridWin[i].get();
+ if (pWin != nullptr)
+ {
+ Modifier<ModifierTag>(pWin);
+ }
+ }
+ }
+}
+
+template<ScExtraEditViewManager::ModifierTagType ModifierTag>
+void ScExtraEditViewManager::Modifier(ScGridWindow* /*pWin*/)
+{
+ (void)this;
+ SAL_WARN("sc", "ScExtraEditViewManager::Modifier<ModifierTag>: non-specialized version should not be invoked.");
+}
+
+template<>
+void ScExtraEditViewManager::Modifier<ScExtraEditViewManager::Adder>(ScGridWindow* pWin)
+{
+ if (mpOtherEditView->AddOtherViewWindow(pWin))
+ ++nTotalWindows;
+}
+
+template<>
+void ScExtraEditViewManager::Modifier<ScExtraEditViewManager::Remover>(ScGridWindow* pWin)
+{
+ if (mpOtherEditView->RemoveOtherViewWindow(pWin))
+ --nTotalWindows;
+}
+
+// --- public functions
+
+void ScTabView::ClickCursor( SCCOL nPosX, SCROW nPosY, bool bControl )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+ rDoc.SkipOverlapped(nPosX, nPosY, nTab);
+
+ bool bRefMode = SC_MOD()->IsFormulaMode();
+
+ if ( bRefMode )
+ {
+ DoneRefMode();
+
+ if (bControl)
+ SC_MOD()->AddRefEntry();
+
+ InitRefMode( nPosX, nPosY, nTab, SC_REFTYPE_REF );
+ }
+ else
+ {
+ DoneBlockMode( bControl );
+ aViewData.ResetOldCursor();
+ SetCursor( nPosX, nPosY );
+ }
+}
+
+void ScTabView::UpdateAutoFillMark(bool bFromPaste)
+{
+ // single selection or cursor
+ ScRange aMarkRange;
+ ScMarkType eMarkType = aViewData.GetSimpleArea(aMarkRange);
+ bool bMarked = eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED;
+
+ for (sal_uInt16 i = 0; i < 4; i++)
+ {
+ if (pGridWin[i] && pGridWin[i]->IsVisible())
+ pGridWin[i]->UpdateAutoFillMark( bMarked, aMarkRange );
+ }
+
+ for (sal_uInt16 i = 0; i < 2; i++)
+ {
+ if (pColBar[i] && pColBar[i]->IsVisible())
+ pColBar[i]->SetMark( bMarked, aMarkRange.aStart.Col(), aMarkRange.aEnd.Col() );
+ if (pRowBar[i] && pRowBar[i]->IsVisible())
+ pRowBar[i]->SetMark( bMarked, aMarkRange.aStart.Row(), aMarkRange.aEnd.Row() );
+ }
+
+ // selection transfer object is checked together with AutoFill marks,
+ // because it has the same requirement of a single continuous block.
+ if (!bFromPaste)
+ CheckSelectionTransfer(); // update selection transfer object
+}
+
+void ScTabView::FakeButtonUp( ScSplitPos eWhich )
+{
+ if (pGridWin[eWhich])
+ pGridWin[eWhich]->FakeButtonUp();
+}
+
+void ScTabView::HideAllCursors()
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ {
+ if (pWin && pWin->IsVisible())
+ {
+ vcl::Cursor* pCur = pWin->GetCursor();
+ if (pCur && pCur->IsVisible())
+ pCur->Hide();
+ pWin->HideCursor();
+ }
+ }
+}
+
+void ScTabView::ShowAllCursors()
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ {
+ if (pWin && pWin->IsVisible())
+ {
+ pWin->ShowCursor();
+ pWin->CursorChanged();
+ }
+ }
+}
+
+void ScTabView::ShowCursor()
+{
+ pGridWin[aViewData.GetActivePart()]->ShowCursor();
+ pGridWin[aViewData.GetActivePart()]->CursorChanged();
+}
+
+void ScTabView::InvalidateAttribs()
+{
+ SfxBindings& rBindings = aViewData.GetBindings();
+
+ rBindings.Invalidate( SID_STYLE_APPLY );
+ rBindings.Invalidate( SID_STYLE_FAMILY2 );
+ // StarCalc knows only paragraph- or cell format templates
+
+ rBindings.Invalidate( SID_ATTR_CHAR_FONT );
+ rBindings.Invalidate( SID_ATTR_CHAR_FONTHEIGHT );
+ rBindings.Invalidate( SID_ATTR_CHAR_COLOR );
+
+ rBindings.Invalidate( SID_ATTR_CHAR_WEIGHT );
+ rBindings.Invalidate( SID_ATTR_CHAR_POSTURE );
+ rBindings.Invalidate( SID_ATTR_CHAR_UNDERLINE );
+ rBindings.Invalidate( SID_ULINE_VAL_NONE );
+ rBindings.Invalidate( SID_ULINE_VAL_SINGLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOUBLE );
+ rBindings.Invalidate( SID_ULINE_VAL_DOTTED );
+
+ rBindings.Invalidate( SID_ATTR_CHAR_OVERLINE );
+
+ rBindings.Invalidate( SID_ATTR_CHAR_KERNING );
+ rBindings.Invalidate( SID_SET_SUPER_SCRIPT );
+ rBindings.Invalidate( SID_SET_SUB_SCRIPT );
+ rBindings.Invalidate( SID_ATTR_CHAR_STRIKEOUT );
+ rBindings.Invalidate( SID_ATTR_CHAR_SHADOWED );
+
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_LEFT );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_RIGHT );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_BLOCK );
+ rBindings.Invalidate( SID_ATTR_PARA_ADJUST_CENTER);
+ rBindings.Invalidate( SID_NUMBER_TYPE_FORMAT);
+
+ rBindings.Invalidate( SID_ALIGNLEFT );
+ rBindings.Invalidate( SID_ALIGNRIGHT );
+ rBindings.Invalidate( SID_ALIGNBLOCK );
+ rBindings.Invalidate( SID_ALIGNCENTERHOR );
+
+ rBindings.Invalidate( SID_ALIGNTOP );
+ rBindings.Invalidate( SID_ALIGNBOTTOM );
+ rBindings.Invalidate( SID_ALIGNCENTERVER );
+
+ rBindings.Invalidate( SID_SCATTR_CELLPROTECTION );
+
+ // stuff for sidebar panels
+ {
+ rBindings.Invalidate( SID_H_ALIGNCELL );
+ rBindings.Invalidate( SID_V_ALIGNCELL );
+ rBindings.Invalidate( SID_ATTR_ALIGN_INDENT );
+ rBindings.Invalidate( SID_FRAME_LINECOLOR );
+ rBindings.Invalidate( SID_FRAME_LINESTYLE );
+ rBindings.Invalidate( SID_ATTR_BORDER_OUTER );
+ rBindings.Invalidate( SID_ATTR_BORDER_INNER );
+ rBindings.Invalidate( SID_ATTR_BORDER_DIAG_TLBR );
+ rBindings.Invalidate( SID_ATTR_BORDER_DIAG_BLTR );
+ rBindings.Invalidate( SID_NUMBER_TYPE_FORMAT );
+ }
+
+ rBindings.Invalidate( SID_BACKGROUND_COLOR );
+
+ rBindings.Invalidate( SID_ATTR_ALIGN_LINEBREAK );
+ rBindings.Invalidate( SID_NUMBER_FORMAT );
+
+ rBindings.Invalidate( SID_TEXTDIRECTION_LEFT_TO_RIGHT );
+ rBindings.Invalidate( SID_TEXTDIRECTION_TOP_TO_BOTTOM );
+ rBindings.Invalidate( SID_ATTR_PARA_LEFT_TO_RIGHT );
+ rBindings.Invalidate( SID_ATTR_PARA_RIGHT_TO_LEFT );
+
+ // pseudo slots for Format menu
+ rBindings.Invalidate( SID_ALIGN_ANY_HDEFAULT );
+ rBindings.Invalidate( SID_ALIGN_ANY_LEFT );
+ rBindings.Invalidate( SID_ALIGN_ANY_HCENTER );
+ rBindings.Invalidate( SID_ALIGN_ANY_RIGHT );
+ rBindings.Invalidate( SID_ALIGN_ANY_JUSTIFIED );
+ rBindings.Invalidate( SID_ALIGN_ANY_VDEFAULT );
+ rBindings.Invalidate( SID_ALIGN_ANY_TOP );
+ rBindings.Invalidate( SID_ALIGN_ANY_VCENTER );
+ rBindings.Invalidate( SID_ALIGN_ANY_BOTTOM );
+
+ rBindings.Invalidate( SID_NUMBER_CURRENCY );
+ rBindings.Invalidate( SID_NUMBER_SCIENTIFIC );
+ rBindings.Invalidate( SID_NUMBER_DATE );
+ rBindings.Invalidate( SID_NUMBER_CURRENCY );
+ rBindings.Invalidate( SID_NUMBER_PERCENT );
+ rBindings.Invalidate( SID_NUMBER_TWODEC );
+ rBindings.Invalidate( SID_NUMBER_TIME );
+ rBindings.Invalidate( SID_NUMBER_STANDARD );
+ rBindings.Invalidate( SID_NUMBER_THOUSANDS );
+}
+
+namespace {
+
+void collectUIInformation(std::map<OUString, OUString>&& aParameters)
+{
+ EventDescription aDescription;
+ aDescription.aID = "grid_window";
+ aDescription.aAction = "SELECT";
+ aDescription.aParameters = std::move(aParameters);
+ aDescription.aParent = "MainWindow";
+ aDescription.aKeyWord = "ScGridWinUIObject";
+
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+// SetCursor - Cursor, set, draw, update InputWin
+// or send reference
+// Optimising breaks the functionality
+
+void ScTabView::SetCursor( SCCOL nPosX, SCROW nPosY, bool bNew )
+{
+ SCCOL nOldX = aViewData.GetCurX();
+ SCROW nOldY = aViewData.GetCurY();
+
+ // DeactivateIP only for MarkListHasChanged
+
+ // FIXME: this is to limit the number of rows handled in the Online
+ // to 1000; this will be removed again when the performance
+ // bottlenecks are sorted out
+ if (comphelper::LibreOfficeKit::isActive())
+ nPosY = std::min(nPosY, MAXTILEDROW);
+
+ if ( !(nPosX != nOldX || nPosY != nOldY || bNew) )
+ return;
+
+ ScTabViewShell* pViewShell = aViewData.GetViewShell();
+ bool bRefMode = pViewShell && pViewShell->IsRefInputMode();
+ if ( aViewData.HasEditView( aViewData.GetActivePart() ) && !bRefMode ) // 23259 or so
+ {
+ UpdateInputLine();
+ }
+
+ HideAllCursors();
+
+ aViewData.SetCurX( nPosX );
+ aViewData.SetCurY( nPosY );
+
+ ShowAllCursors();
+
+ CursorPosChanged();
+
+ OUString aCurrAddress = ScAddress(nPosX,nPosY,0).GetColRowString();
+ collectUIInformation({{"CELL", aCurrAddress}});
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ if (nPosX <= aViewData.GetMaxTiledCol() - 10 && nPosY <= aViewData.GetMaxTiledRow() - 25)
+ return;
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ ScDocShell* pDocSh = aViewData.GetDocShell();
+ ScModelObj* pModelObj = pDocSh ? comphelper::getFromUnoTunnel<ScModelObj>( pDocSh->GetModel() ) : nullptr;
+ Size aOldSize(0, 0);
+ if (pModelObj)
+ aOldSize = pModelObj->getDocumentSize();
+
+ if (nPosX > aViewData.GetMaxTiledCol() - 10)
+ aViewData.SetMaxTiledCol(std::min<SCCOL>(std::max(nPosX, aViewData.GetMaxTiledCol()) + 10, rDoc.MaxCol()));
+
+ if (nPosY > aViewData.GetMaxTiledRow() - 25)
+ aViewData.SetMaxTiledRow(std::min<SCROW>(std::max(nPosY, aViewData.GetMaxTiledRow()) + 25, MAXTILEDROW));
+
+ Size aNewSize(0, 0);
+ if (pModelObj)
+ aNewSize = pModelObj->getDocumentSize();
+
+ if (!pDocSh)
+ return;
+
+ // New area extended to the right of the sheet after last column
+ // including overlapping area with aNewRowArea
+ tools::Rectangle aNewColArea(aOldSize.getWidth(), 0, aNewSize.getWidth(), aNewSize.getHeight());
+ // New area extended to the bottom of the sheet after last row
+ // excluding overlapping area with aNewColArea
+ tools::Rectangle aNewRowArea(0, aOldSize.getHeight(), aOldSize.getWidth(), aNewSize.getHeight());
+
+ // Only invalidate if spreadsheet extended to the right
+ if (aNewColArea.getWidth())
+ {
+ SfxLokHelper::notifyInvalidation(aViewData.GetViewShell(), &aNewColArea);
+ }
+
+ // Only invalidate if spreadsheet extended to the bottom
+ if (aNewRowArea.getHeight())
+ {
+ SfxLokHelper::notifyInvalidation(aViewData.GetViewShell(), &aNewRowArea);
+ }
+
+ // Provide size in the payload, so clients don't have to
+ // call lok::Document::getDocumentSize().
+ std::stringstream ss;
+ ss << aNewSize.Width() << ", " << aNewSize.Height();
+ OString sSize = ss.str().c_str();
+ ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>(aViewData.GetViewShell()->GetCurrentDocument());
+ SfxLokHelper::notifyDocumentSizeChanged(aViewData.GetViewShell(), sSize, pModel, false);
+}
+
+static bool lcl_IsRefDlgActive(SfxViewFrame* pViewFrm)
+{
+ ScModule* pScMod = SC_MOD();
+ if (!pScMod->IsRefDialogOpen())
+ return false;
+
+ auto nDlgId = pScMod->GetCurRefDlgId();
+ if (!pViewFrm->HasChildWindow(nDlgId))
+ return false;
+
+ SfxChildWindow* pChild = pViewFrm->GetChildWindow(nDlgId);
+ if (!pChild)
+ return false;
+
+ auto xDlgController = pChild->GetController();
+ if (!xDlgController || !xDlgController->getDialog()->get_visible())
+ return false;
+
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(xDlgController.get());
+ return pRefDlg && pRefDlg->IsRefInputMode();
+}
+
+void ScTabView::CheckSelectionTransfer()
+{
+ if ( !aViewData.IsActive() ) // only for active view
+ return;
+
+ ScModule* pScMod = SC_MOD();
+ ScSelectionTransferObj* pOld = pScMod->GetSelectionTransfer();
+ rtl::Reference<ScSelectionTransferObj> pNew = ScSelectionTransferObj::CreateFromView( this );
+ if ( !pNew )
+ return;
+
+ // create new selection
+
+ if (pOld)
+ pOld->ForgetView();
+
+ pScMod->SetSelectionTransfer( pNew.get() );
+
+ // tdf#124975/tdf#136242 changing the calc selection can trigger removal of the
+ // selection of an open RefDlg dialog, so don't inform the
+ // desktop clipboard of the changed selection if that dialog is open
+ if (!lcl_IsRefDlgActive(aViewData.GetViewShell()->GetViewFrame()))
+ pNew->CopyToPrimarySelection(); // may delete pOld
+
+ // Log the selection change
+ ScMarkData& rMark = aViewData.GetMarkData();
+ if (rMark.IsMarked())
+ {
+ const ScRange& aMarkRange = rMark.GetMarkArea();
+ OUString aStartAddress = aMarkRange.aStart.GetColRowString();
+ OUString aEndAddress = aMarkRange.aEnd.GetColRowString();
+ collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}});
+ }
+}
+
+// update input row / menus
+// CursorPosChanged calls SelectionChanged
+// SelectionChanged calls CellContentChanged
+
+void ScTabView::CellContentChanged()
+{
+ SfxBindings& rBindings = aViewData.GetBindings();
+
+ rBindings.Invalidate( SID_ATTR_SIZE ); // -> show error message
+ rBindings.Invalidate( SID_THESAURUS );
+ rBindings.Invalidate( SID_HYPERLINK_GETLINK );
+ rBindings.Invalidate( SID_ROWCOL_SELCOUNT );
+
+ InvalidateAttribs(); // attributes updates
+
+ aViewData.GetViewShell()->UpdateInputHandler();
+}
+
+void ScTabView::SetTabProtectionSymbol( SCTAB nTab, const bool bProtect )
+{
+ pTabControl->SetProtectionSymbol( static_cast<sal_uInt16>(nTab)+1, bProtect);
+}
+
+void ScTabView::SelectionChanged(bool bFromPaste)
+{
+ SfxViewFrame* pViewFrame = aViewData.GetViewShell()->GetViewFrame();
+ if (pViewFrame)
+ {
+ uno::Reference<frame::XController> xController = pViewFrame->GetFrame().GetController();
+ if (xController.is())
+ {
+ ScTabViewObj* pImp = comphelper::getFromUnoTunnel<ScTabViewObj>( xController );
+ if (pImp)
+ pImp->SelectionChanged();
+ }
+ }
+
+ UpdateAutoFillMark(bFromPaste); // also calls CheckSelectionTransfer
+
+ SfxBindings& rBindings = aViewData.GetBindings();
+
+ rBindings.Invalidate( SID_CURRENTCELL ); // -> Navigator
+ rBindings.Invalidate( SID_AUTO_FILTER ); // -> Menu
+ rBindings.Invalidate( FID_NOTE_VISIBLE );
+ rBindings.Invalidate( FID_SHOW_NOTE );
+ rBindings.Invalidate( FID_HIDE_NOTE );
+ rBindings.Invalidate( FID_SHOW_ALL_NOTES );
+ rBindings.Invalidate( FID_HIDE_ALL_NOTES );
+ rBindings.Invalidate( SID_TOGGLE_NOTES );
+ rBindings.Invalidate( SID_DELETE_NOTE );
+ rBindings.Invalidate( SID_ROWCOL_SELCOUNT );
+
+ // functions than may need to be disabled
+
+ rBindings.Invalidate( FID_INS_ROWBRK );
+ rBindings.Invalidate( FID_INS_COLBRK );
+ rBindings.Invalidate( FID_DEL_ROWBRK );
+ rBindings.Invalidate( FID_DEL_COLBRK );
+ rBindings.Invalidate( FID_MERGE_ON );
+ rBindings.Invalidate( FID_MERGE_OFF );
+ rBindings.Invalidate( FID_MERGE_TOGGLE );
+ rBindings.Invalidate( SID_AUTOFILTER_HIDE );
+ rBindings.Invalidate( SID_UNFILTER );
+ rBindings.Invalidate( SID_REIMPORT_DATA );
+ rBindings.Invalidate( SID_REFRESH_DBAREA );
+ rBindings.Invalidate( SID_OUTLINE_SHOW );
+ rBindings.Invalidate( SID_OUTLINE_HIDE );
+ rBindings.Invalidate( SID_OUTLINE_REMOVE );
+ rBindings.Invalidate( FID_FILL_TO_BOTTOM );
+ rBindings.Invalidate( FID_FILL_TO_RIGHT );
+ rBindings.Invalidate( FID_FILL_TO_TOP );
+ rBindings.Invalidate( FID_FILL_TO_LEFT );
+ rBindings.Invalidate( FID_FILL_SERIES );
+ rBindings.Invalidate( SID_SCENARIOS );
+ rBindings.Invalidate( SID_AUTOFORMAT );
+ rBindings.Invalidate( SID_OPENDLG_TABOP );
+ rBindings.Invalidate( SID_DATA_SELECT );
+
+ rBindings.Invalidate( SID_CUT );
+ rBindings.Invalidate( SID_COPY );
+ rBindings.Invalidate( SID_PASTE );
+ rBindings.Invalidate( SID_PASTE_SPECIAL );
+ rBindings.Invalidate( SID_PASTE_UNFORMATTED );
+
+ rBindings.Invalidate( FID_INS_ROW );
+ rBindings.Invalidate( FID_INS_COLUMN );
+ rBindings.Invalidate( FID_INS_ROWS_BEFORE );
+ rBindings.Invalidate( FID_INS_COLUMNS_BEFORE );
+ rBindings.Invalidate( FID_INS_ROWS_AFTER );
+ rBindings.Invalidate( FID_INS_COLUMNS_AFTER );
+ rBindings.Invalidate( FID_INS_CELL );
+ rBindings.Invalidate( FID_INS_CELLSDOWN );
+ rBindings.Invalidate( FID_INS_CELLSRIGHT );
+
+ rBindings.Invalidate( FID_CHG_COMMENT );
+
+ // only due to protect cell:
+
+ rBindings.Invalidate( SID_CELL_FORMAT_RESET );
+ rBindings.Invalidate( SID_DELETE );
+ rBindings.Invalidate( SID_DELETE_CONTENTS );
+ rBindings.Invalidate( FID_DELETE_CELL );
+ rBindings.Invalidate( FID_CELL_FORMAT );
+ rBindings.Invalidate( SID_ENABLE_HYPHENATION );
+ rBindings.Invalidate( SID_INSERT_POSTIT );
+ rBindings.Invalidate( SID_CHARMAP );
+ rBindings.Invalidate( SID_OPENDLG_FUNCTION );
+ rBindings.Invalidate( FID_VALIDATION );
+ rBindings.Invalidate( SID_EXTERNAL_SOURCE );
+ rBindings.Invalidate( SID_TEXT_TO_COLUMNS );
+ rBindings.Invalidate( SID_SORT_ASCENDING );
+ rBindings.Invalidate( SID_SORT_DESCENDING );
+ rBindings.Invalidate( SID_SELECT_UNPROTECTED_CELLS );
+
+ if (aViewData.GetViewShell()->HasAccessibilityObjects())
+ aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccCursorChanged));
+
+ CellContentChanged();
+}
+
+void ScTabView::CursorPosChanged()
+{
+ bool bRefMode = SC_MOD()->IsFormulaMode();
+ if ( !bRefMode ) // check that RefMode works when switching sheets
+ aViewData.GetDocShell()->Broadcast( SfxHint( SfxHintId::ScKillEditView ) );
+
+ // Broadcast, so that other Views of the document also switch
+
+ ScDocument& rDocument = aViewData.GetDocument();
+ bool bDataPilot = rDocument.HasDataPilotAtPosition(aViewData.GetCurPos());
+ aViewData.GetViewShell()->SetPivotShell(bDataPilot);
+
+ if (!bDataPilot)
+ {
+ bool bSparkline = rDocument.HasSparkline(aViewData.GetCurPos());
+ aViewData.GetViewShell()->SetSparklineShell(bSparkline);
+ }
+
+ // UpdateInputHandler now in CellContentChanged
+
+ SelectionChanged();
+
+ aViewData.SetTabStartCol( SC_TABSTART_NONE );
+}
+
+namespace {
+
+Point calcHintWindowPosition(
+ const Point& rCellPos, const Size& rCellSize, const Size& rFrameWndSize, const Size& rHintWndSize)
+{
+ const tools::Long nMargin = 20;
+
+ tools::Long nMLeft = rCellPos.X();
+ tools::Long nMRight = rFrameWndSize.Width() - rCellPos.X() - rCellSize.Width();
+ tools::Long nMTop = rCellPos.Y();
+ tools::Long nMBottom = rFrameWndSize.Height() - rCellPos.Y() - rCellSize.Height();
+
+ // First, see if we can fit the entire hint window in the visible region.
+
+ if (nMRight - nMargin >= rHintWndSize.Width())
+ {
+ // Right margin is wide enough.
+ if (rFrameWndSize.Height() >= rHintWndSize.Height())
+ {
+ // The frame has enough height. Take it.
+ Point aPos = rCellPos;
+ aPos.AdjustX(rCellSize.Width() + nMargin );
+ if (aPos.Y() + rHintWndSize.Height() > rFrameWndSize.Height())
+ {
+ // Push the hint window up a bit to make it fit.
+ aPos.setY( rFrameWndSize.Height() - rHintWndSize.Height() );
+ }
+ return aPos;
+ }
+ }
+
+ if (nMBottom - nMargin >= rHintWndSize.Height())
+ {
+ // Bottom margin is high enough.
+ if (rFrameWndSize.Width() >= rHintWndSize.Width())
+ {
+ // The frame has enough width. Take it.
+ Point aPos = rCellPos;
+ aPos.AdjustY(rCellSize.Height() + nMargin );
+ if (aPos.X() + rHintWndSize.Width() > rFrameWndSize.Width())
+ {
+ // Move the hint window to the left to make it fit.
+ aPos.setX( rFrameWndSize.Width() - rHintWndSize.Width() );
+ }
+ return aPos;
+ }
+ }
+
+ if (nMLeft - nMargin >= rHintWndSize.Width())
+ {
+ // Left margin is wide enough.
+ if (rFrameWndSize.Height() >= rHintWndSize.Height())
+ {
+ // The frame is high enough. Take it.
+ Point aPos = rCellPos;
+ aPos.AdjustX( -(rHintWndSize.Width() + nMargin) );
+ if (aPos.Y() + rHintWndSize.Height() > rFrameWndSize.Height())
+ {
+ // Push the hint window up a bit to make it fit.
+ aPos.setY( rFrameWndSize.Height() - rHintWndSize.Height() );
+ }
+ return aPos;
+ }
+ }
+
+ if (nMTop - nMargin >= rHintWndSize.Height())
+ {
+ // Top margin is high enough.
+ if (rFrameWndSize.Width() >= rHintWndSize.Width())
+ {
+ // The frame is wide enough. Take it.
+ Point aPos = rCellPos;
+ aPos.AdjustY( -(rHintWndSize.Height() + nMargin) );
+ if (aPos.X() + rHintWndSize.Width() > rFrameWndSize.Width())
+ {
+ // Move the hint window to the left to make it fit.
+ aPos.setX( rFrameWndSize.Width() - rHintWndSize.Width() );
+ }
+ return aPos;
+ }
+ }
+
+ // The popup doesn't fit in any direction in its entirety. Do our best.
+
+ if (nMRight - nMargin >= rHintWndSize.Width())
+ {
+ // Right margin is good enough.
+ Point aPos = rCellPos;
+ aPos.AdjustX(nMargin + rCellSize.Width() );
+ aPos.setY( 0 );
+ return aPos;
+ }
+
+ if (nMBottom - nMargin >= rHintWndSize.Height())
+ {
+ // Bottom margin is good enough.
+ Point aPos = rCellPos;
+ aPos.AdjustY(nMargin + rCellSize.Height() );
+ aPos.setX( 0 );
+ return aPos;
+ }
+
+ if (nMLeft - nMargin >= rHintWndSize.Width())
+ {
+ // Left margin is good enough.
+ Point aPos = rCellPos;
+ aPos.AdjustX( -(rHintWndSize.Width() + nMargin) );
+ aPos.setY( 0 );
+ return aPos;
+ }
+
+ if (nMTop - nMargin >= rHintWndSize.Height())
+ {
+ // Top margin is good enough.
+ Point aPos = rCellPos;
+ aPos.AdjustY( -(rHintWndSize.Height() + nMargin) );
+ aPos.setX( 0 );
+ return aPos;
+ }
+
+ // None of the above. Hopeless. At least try not to cover the current
+ // cell.
+ Point aPos = rCellPos;
+ aPos.AdjustX(rCellSize.Width() );
+ return aPos;
+}
+
+}
+
+void ScTabView::TestHintWindow()
+{
+ // show input help window and list drop-down button for validity
+
+ mxInputHintOO.reset();
+
+ bool bListValButton = false;
+ ScAddress aListValPos;
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ const SfxUInt32Item* pItem = rDoc.GetAttr( aViewData.GetCurX(),
+ aViewData.GetCurY(),
+ aViewData.GetTabNo(),
+ ATTR_VALIDDATA );
+ if ( pItem->GetValue() )
+ {
+ const ScValidationData* pData = rDoc.GetValidationEntry( pItem->GetValue() );
+ OSL_ENSURE(pData,"ValidationData not found");
+ OUString aTitle, aMessage;
+
+ if ( pData && pData->GetInput( aTitle, aMessage ) && !aMessage.isEmpty() )
+ {
+ ScSplitPos eWhich = aViewData.GetActivePart();
+ ScGridWindow* pWin = pGridWin[eWhich].get();
+ SCCOL nCol = aViewData.GetCurX();
+ SCROW nRow = aViewData.GetCurY();
+ Point aPos = aViewData.GetScrPos( nCol, nRow, eWhich );
+ Size aWinSize = pWin->GetOutputSizePixel();
+ // cursor visible?
+ if ( nCol >= aViewData.GetPosX(WhichH(eWhich)) &&
+ nRow >= aViewData.GetPosY(WhichV(eWhich)) &&
+ aPos.X() < aWinSize.Width() && aPos.Y() < aWinSize.Height() )
+ {
+ const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
+ Color aCommentColor = rColorCfg.GetColorValue(svtools::CALCNOTESBACKGROUND).nColor;
+ // create HintWindow, determines its size by itself
+ ScOverlayHint* pOverlay = new ScOverlayHint(aTitle, aMessage, aCommentColor, pFrameWin->GetFont());
+
+ mxInputHintOO.reset(new sdr::overlay::OverlayObjectList);
+ mxInputHintOO->append(std::unique_ptr<sdr::overlay::OverlayObject>(pOverlay));
+
+ Size aHintWndSize = pOverlay->GetSizePixel();
+ tools::Long nCellSizeX = 0;
+ tools::Long nCellSizeY = 0;
+ aViewData.GetMergeSizePixel(nCol, nRow, nCellSizeX, nCellSizeY);
+
+ Point aHintPos = calcHintWindowPosition(
+ aPos, Size(nCellSizeX,nCellSizeY), aWinSize, aHintWndSize);
+
+ pOverlay->SetPos(pWin->PixelToLogic(aHintPos, pWin->GetDrawMapMode()), pWin->GetDrawMapMode());
+ for (VclPtr<ScGridWindow> & pWindow : pGridWin)
+ {
+ if (!pWindow)
+ continue;
+ if (!pWindow->IsVisible())
+ continue;
+ rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager = pWindow->getOverlayManager();
+ if (!xOverlayManager.is())
+ continue;
+ if (pWindow == pWin)
+ {
+ xOverlayManager->add(*pOverlay);
+ pWindow->updateLOKInputHelp(aTitle, aMessage);
+ }
+ else
+ {
+ //tdf#92530 if the help tip doesn't fit into its allocated area in a split window
+ //scenario, then because here we place it into the other split windows as well the
+ //missing portions will be displayed in the other split windows to form an apparent
+ //single tip, albeit "under" the split lines
+ Point aOtherPos(pWindow->ScreenToOutputPixel(pWin->OutputToScreenPixel(aHintPos)));
+ std::unique_ptr<ScOverlayHint> pOtherOverlay(new ScOverlayHint(aTitle, aMessage, aCommentColor, pFrameWin->GetFont()));
+ Point aFooPos(pWindow->PixelToLogic(aOtherPos, pWindow->GetDrawMapMode()));
+ pOtherOverlay->SetPos(aFooPos, pWindow->GetDrawMapMode());
+ xOverlayManager->add(*pOtherOverlay);
+ mxInputHintOO->append(std::move(pOtherOverlay));
+ }
+ }
+ }
+ }
+
+ // list drop-down button
+ if ( pData && pData->HasSelectionList() )
+ {
+ aListValPos.Set( aViewData.GetCurX(), aViewData.GetCurY(), aViewData.GetTabNo() );
+ bListValButton = true;
+ }
+ }
+
+ for (VclPtr<ScGridWindow> const & pWin : pGridWin)
+ {
+ if (pWin && pWin->IsVisible())
+ pWin->UpdateListValPos(bListValButton, aListValPos);
+ }
+}
+
+bool ScTabView::HasHintWindow() const { return mxInputHintOO != nullptr; }
+
+void ScTabView::RemoveHintWindow()
+{
+ mxInputHintOO.reset();
+}
+
+// find window that should not be over the cursor
+static weld::Window* lcl_GetCareWin(SfxViewFrame* pViewFrm)
+{
+ //! also spelling ??? (then set the member variables when calling)
+
+ // search & replace
+ if (pViewFrm->HasChildWindow(SID_SEARCH_DLG))
+ {
+ SfxChildWindow* pChild = pViewFrm->GetChildWindow(SID_SEARCH_DLG);
+ if (pChild)
+ {
+ auto xDlgController = pChild->GetController();
+ if (xDlgController && xDlgController->getDialog()->get_visible())
+ return xDlgController->getDialog();
+ }
+ }
+
+ // apply changes
+ if ( pViewFrm->HasChildWindow(FID_CHG_ACCEPT) )
+ {
+ SfxChildWindow* pChild = pViewFrm->GetChildWindow(FID_CHG_ACCEPT);
+ if (pChild)
+ {
+ auto xDlgController = pChild->GetController();
+ if (xDlgController && xDlgController->getDialog()->get_visible())
+ return xDlgController->getDialog();
+ }
+ }
+
+ return nullptr;
+}
+
+ // adjust screen with respect to cursor position
+
+void ScTabView::AlignToCursor( SCCOL nCurX, SCROW nCurY, ScFollowMode eMode,
+ const ScSplitPos* pWhich )
+{
+ // now switch active part here
+
+ ScSplitPos eActive = aViewData.GetActivePart();
+ ScHSplitPos eActiveX = WhichH(eActive);
+ ScVSplitPos eActiveY = WhichV(eActive);
+ bool bHFix = (aViewData.GetHSplitMode() == SC_SPLIT_FIX);
+ bool bVFix = (aViewData.GetVSplitMode() == SC_SPLIT_FIX);
+ if (bHFix && eActiveX == SC_SPLIT_LEFT && nCurX >= aViewData.GetFixPosX())
+ {
+ ActivatePart( (eActiveY==SC_SPLIT_TOP) ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT );
+ eActiveX = SC_SPLIT_RIGHT;
+ }
+ if (bVFix && eActiveY == SC_SPLIT_TOP && nCurY >= aViewData.GetFixPosY())
+ {
+ ActivatePart( (eActiveX==SC_SPLIT_LEFT) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT );
+ eActiveY = SC_SPLIT_BOTTOM;
+ }
+
+ // actual align
+
+ if ( eMode != SC_FOLLOW_NONE )
+ {
+ ScSplitPos eAlign;
+ if (pWhich)
+ eAlign = *pWhich;
+ else
+ eAlign = aViewData.GetActivePart();
+ ScHSplitPos eAlignX = WhichH(eAlign);
+ ScVSplitPos eAlignY = WhichV(eAlign);
+
+ SCCOL nDeltaX = aViewData.GetPosX(eAlignX);
+ SCROW nDeltaY = aViewData.GetPosY(eAlignY);
+ SCCOL nSizeX = aViewData.VisibleCellsX(eAlignX);
+ SCROW nSizeY = aViewData.VisibleCellsY(eAlignY);
+
+ tools::Long nCellSizeX;
+ tools::Long nCellSizeY;
+ if ( nCurX >= 0 && nCurY >= 0 )
+ aViewData.GetMergeSizePixel( nCurX, nCurY, nCellSizeX, nCellSizeY );
+ else
+ nCellSizeX = nCellSizeY = 0;
+ Size aScrSize = aViewData.GetScrSize();
+ tools::Long nSpaceX = ( aScrSize.Width() - nCellSizeX ) / 2;
+ tools::Long nSpaceY = ( aScrSize.Height() - nCellSizeY ) / 2;
+ // nSpaceY: desired start position of cell for FOLLOW_JUMP, modified if dialog interferes
+
+ bool bForceNew = false; // force new calculation of JUMP position (vertical only)
+
+ // VisibleCellsY == CellsAtY( GetPosY( eWhichY ), 1, eWhichY )
+
+ // when for instance a search dialog is open, don't put the cursor behind the dialog
+ // if possible, put the row with the cursor above or below the dialog
+ //! not if already completely visible
+
+ if ( eMode == SC_FOLLOW_JUMP )
+ {
+ weld::Window* pCare = lcl_GetCareWin( aViewData.GetViewShell()->GetViewFrame() );
+ if (pCare)
+ {
+ bool bLimit = false;
+ tools::Rectangle aDlgPixel;
+ Size aWinSize;
+ vcl::Window* pWin = GetActiveWin();
+ weld::Window* pFrame = pWin ? pWin->GetFrameWeld() : nullptr;
+ int x, y, width, height;
+ if (pFrame && pCare->get_extents_relative_to(*pFrame, x, y, width, height))
+ {
+ aDlgPixel = tools::Rectangle(Point(x, y), Size(width, height));
+ aWinSize = pWin->GetOutputSizePixel();
+ // dos the dialog cover the GridWin?
+ if ( aDlgPixel.Right() >= 0 && aDlgPixel.Left() < aWinSize.Width() )
+ {
+ if ( nCurX < nDeltaX || nCurX >= nDeltaX+nSizeX ||
+ nCurY < nDeltaY || nCurY >= nDeltaY+nSizeY )
+ bLimit = true; // scroll anyway
+ else
+ {
+ // cursor is on the screen
+ Point aStart = aViewData.GetScrPos( nCurX, nCurY, eAlign );
+ tools::Long nCSX, nCSY;
+ aViewData.GetMergeSizePixel( nCurX, nCurY, nCSX, nCSY );
+ tools::Rectangle aCursor( aStart, Size( nCSX, nCSY ) );
+ if ( aCursor.Overlaps( aDlgPixel ) )
+ bLimit = true; // cell is covered by the dialog
+ }
+ }
+ }
+
+ if (bLimit)
+ {
+ bool bBottom = false;
+ tools::Long nTopSpace = aDlgPixel.Top();
+ tools::Long nBotSpace = aWinSize.Height() - aDlgPixel.Bottom();
+ if ( nBotSpace > 0 && nBotSpace > nTopSpace )
+ {
+ tools::Long nDlgBot = aDlgPixel.Bottom();
+ SCCOL nWPosX;
+ SCROW nWPosY;
+ aViewData.GetPosFromPixel( 0,nDlgBot, eAlign, nWPosX, nWPosY );
+ ++nWPosY; // below the last affected cell
+
+ SCROW nDiff = nWPosY - nDeltaY;
+ if ( nCurY >= nDiff ) // position can not be negative
+ {
+ nSpaceY = nDlgBot + ( nBotSpace - nCellSizeY ) / 2;
+ bBottom = true;
+ bForceNew = true;
+ }
+ }
+ if ( !bBottom && nTopSpace > 0 )
+ {
+ nSpaceY = ( nTopSpace - nCellSizeY ) / 2;
+ bForceNew = true;
+ }
+ }
+ }
+ }
+
+ SCCOL nNewDeltaX = nDeltaX;
+ SCROW nNewDeltaY = nDeltaY;
+ bool bDoLine = false;
+
+ switch (eMode)
+ {
+ case SC_FOLLOW_JUMP:
+ if ( nCurX < nDeltaX || nCurX >= nDeltaX+nSizeX )
+ {
+ nNewDeltaX = nCurX - aViewData.CellsAtX( nCurX, -1, eAlignX, static_cast<sal_uInt16>(nSpaceX) );
+ if (nNewDeltaX < 0)
+ nNewDeltaX = 0;
+ nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX );
+ }
+ if ( nCurY < nDeltaY || nCurY >= nDeltaY+nSizeY || bForceNew )
+ {
+ nNewDeltaY = nCurY - aViewData.CellsAtY( nCurY, -1, eAlignY, static_cast<sal_uInt16>(nSpaceY) );
+ if (nNewDeltaY < 0)
+ nNewDeltaY = 0;
+ nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY );
+ }
+ bDoLine = true;
+ break;
+
+ case SC_FOLLOW_LINE:
+ bDoLine = true;
+ break;
+
+ case SC_FOLLOW_FIX:
+ if ( nCurX < nDeltaX || nCurX >= nDeltaX+nSizeX )
+ {
+ nNewDeltaX = nDeltaX + nCurX - aViewData.GetCurX();
+ if (nNewDeltaX < 0)
+ nNewDeltaX = 0;
+ nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX );
+ }
+ if ( nCurY < nDeltaY || nCurY >= nDeltaY+nSizeY )
+ {
+ nNewDeltaY = nDeltaY + nCurY - aViewData.GetCurY();
+ if (nNewDeltaY < 0)
+ nNewDeltaY = 0;
+ nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY );
+ }
+
+ // like old version of SC_FOLLOW_JUMP:
+
+ if ( nCurX < nNewDeltaX || nCurX >= nNewDeltaX+nSizeX )
+ {
+ nNewDeltaX = nCurX - (nSizeX / 2);
+ if (nNewDeltaX < 0)
+ nNewDeltaX = 0;
+ nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX );
+ }
+ if ( nCurY < nNewDeltaY || nCurY >= nNewDeltaY+nSizeY )
+ {
+ nNewDeltaY = nCurY - (nSizeY / 2);
+ if (nNewDeltaY < 0)
+ nNewDeltaY = 0;
+ nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY );
+ }
+
+ bDoLine = true;
+ break;
+
+ case SC_FOLLOW_NONE:
+ break;
+ default:
+ OSL_FAIL("Wrong cursor mode");
+ break;
+ }
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ if (bDoLine)
+ {
+ while ( nCurX >= nNewDeltaX+nSizeX )
+ {
+ nNewDeltaX = nCurX-nSizeX+1;
+ SCTAB nTab = aViewData.GetTabNo();
+ while ( nNewDeltaX < rDoc.MaxCol() && !rDoc.GetColWidth( nNewDeltaX, nTab ) )
+ ++nNewDeltaX;
+ nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX );
+ }
+ while ( nCurY >= nNewDeltaY+nSizeY )
+ {
+ nNewDeltaY = nCurY-nSizeY+1;
+ SCTAB nTab = aViewData.GetTabNo();
+ while ( nNewDeltaY < rDoc.MaxRow() && !rDoc.GetRowHeight( nNewDeltaY, nTab ) )
+ ++nNewDeltaY;
+ nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY );
+ }
+ if ( nCurX < nNewDeltaX )
+ nNewDeltaX = nCurX;
+ if ( nCurY < nNewDeltaY )
+ nNewDeltaY = nCurY;
+ }
+
+ if ( nNewDeltaX != nDeltaX )
+ nSizeX = aViewData.CellsAtX( nNewDeltaX, 1, eAlignX );
+ if (nNewDeltaX+nSizeX-1 > rDoc.MaxCol())
+ nNewDeltaX = rDoc.MaxCol()-nSizeX+1;
+ if (nNewDeltaX < 0)
+ nNewDeltaX = 0;
+
+ if ( nNewDeltaY != nDeltaY )
+ nSizeY = aViewData.CellsAtY( nNewDeltaY, 1, eAlignY );
+ if (nNewDeltaY+nSizeY-1 > rDoc.MaxRow())
+ nNewDeltaY = rDoc.MaxRow()-nSizeY+1;
+ if (nNewDeltaY < 0)
+ nNewDeltaY = 0;
+
+ if ( nNewDeltaX != nDeltaX )
+ ScrollX( nNewDeltaX - nDeltaX, eAlignX );
+ if ( nNewDeltaY != nDeltaY )
+ ScrollY( nNewDeltaY - nDeltaY, eAlignY );
+ }
+
+ // switch active part again
+
+ if (bHFix)
+ if (eActiveX == SC_SPLIT_RIGHT && nCurX < aViewData.GetFixPosX())
+ {
+ ActivatePart( (eActiveY==SC_SPLIT_TOP) ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT );
+ eActiveX = SC_SPLIT_LEFT;
+ }
+ if (bVFix)
+ if (eActiveY == SC_SPLIT_BOTTOM && nCurY < aViewData.GetFixPosY())
+ {
+ ActivatePart( (eActiveX==SC_SPLIT_LEFT) ? SC_SPLIT_TOPLEFT : SC_SPLIT_TOPRIGHT );
+ }
+}
+
+bool ScTabView::SelMouseButtonDown( const MouseEvent& rMEvt )
+{
+ bool bRet = false;
+
+ // #i3875# *Hack*
+ bool bMod1Locked = (aViewData.GetViewShell()->GetLockedModifiers() & KEY_MOD1) != 0;
+ aViewData.SetSelCtrlMouseClick( rMEvt.IsMod1() || bMod1Locked );
+
+ if ( pSelEngine )
+ {
+ bMoveIsShift = rMEvt.IsShift();
+ bRet = pSelEngine->SelMouseButtonDown( rMEvt );
+ bMoveIsShift = false;
+ }
+
+ aViewData.SetSelCtrlMouseClick( false ); // #i3875# *Hack*
+
+ return bRet;
+}
+
+ // MoveCursor - with adjustment of the view section
+
+void ScTabView::MoveCursorAbs( SCCOL nCurX, SCROW nCurY, ScFollowMode eMode,
+ bool bShift, bool bControl, bool bKeepOld, bool bKeepSel )
+{
+ if (!bKeepOld)
+ aViewData.ResetOldCursor();
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ // #i123629#
+ if( aViewData.GetViewShell()->GetForceFocusOnCurCell() )
+ aViewData.GetViewShell()->SetForceFocusOnCurCell( !rDoc.ValidColRow(nCurX, nCurY) );
+
+ if (nCurX < 0) nCurX = 0;
+ if (nCurY < 0) nCurY = 0;
+ if (nCurX > rDoc.MaxCol()) nCurX = rDoc.MaxCol();
+ if (nCurY > rDoc.MaxRow()) nCurY = rDoc.MaxRow();
+
+ // FIXME: this is to limit the number of rows handled in the Online
+ // to 1000; this will be removed again when the performance
+ // bottlenecks are sorted out
+ if (comphelper::LibreOfficeKit::isActive())
+ nCurY = std::min(nCurY, MAXTILEDROW);
+
+ HideAllCursors();
+
+ // switch of active now in AlignToCursor
+
+ AlignToCursor( nCurX, nCurY, eMode );
+
+ if (bKeepSel)
+ {
+ SetCursor( nCurX, nCurY ); // keep selection
+
+ // If the cursor is in existing selection, it's a cursor movement by
+ // ENTER or TAB. If not, then it's a new selection during ADD
+ // selection mode.
+
+ const ScMarkData& rMark = aViewData.GetMarkData();
+ ScRangeList aSelList;
+ rMark.FillRangeListWithMarks(&aSelList, false);
+ if (!aSelList.Contains(ScRange(nCurX, nCurY, aViewData.GetTabNo())))
+ // Cursor not in existing selection. Start a new selection.
+ DoneBlockMode(true);
+ }
+ else
+ {
+ if (!bShift)
+ {
+ // Remove all marked data on cursor movement unless the Shift is
+ // locked or while editing a formula. It is cheaper to check for
+ // marks first and then formula mode.
+ ScMarkData& rMark = aViewData.GetMarkData();
+ bool bMarked = rMark.IsMarked() || rMark.IsMultiMarked();
+ if (bMarked && !SC_MOD()->IsFormulaMode())
+ {
+ rMark.ResetMark();
+ DoneBlockMode();
+ InitOwnBlockMode( ScRange( nCurX, nCurY, aViewData.GetTabNo()));
+ MarkDataChanged();
+ }
+ }
+
+ bool bSame = ( nCurX == aViewData.GetCurX() && nCurY == aViewData.GetCurY() );
+ bMoveIsShift = bShift;
+ pSelEngine->CursorPosChanging( bShift, bControl );
+ bMoveIsShift = false;
+ aFunctionSet.SetCursorAtCell( nCurX, nCurY, false );
+
+ // If the cursor has not been moved, the SelectionChanged for canceling the
+ // selection has to happen here individually:
+ if (bSame)
+ SelectionChanged();
+ }
+
+ ShowAllCursors();
+ TestHintWindow();
+}
+
+void ScTabView::MoveCursorRel( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode,
+ bool bShift, bool bKeepSel )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+
+ bool bSkipProtected = false, bSkipUnprotected = false;
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ if ( pProtect && pProtect->isProtected() )
+ {
+ bSkipProtected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS);
+ bSkipUnprotected = !pProtect->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS);
+ }
+
+ if ( bSkipProtected && bSkipUnprotected )
+ return;
+
+ SCCOL nOldX;
+ SCROW nOldY;
+ SCCOL nCurX;
+ SCROW nCurY;
+ if ( aViewData.IsRefMode() )
+ {
+ nOldX = aViewData.GetRefEndX();
+ nOldY = aViewData.GetRefEndY();
+ nCurX = nOldX + nMovX;
+ nCurY = nOldY + nMovY;
+ }
+ else
+ {
+ nOldX = aViewData.GetCurX();
+ nOldY = aViewData.GetCurY();
+ nCurX = (nMovX != 0) ? nOldX+nMovX : aViewData.GetOldCurX();
+ nCurY = (nMovY != 0) ? nOldY+nMovY : aViewData.GetOldCurY();
+ }
+
+ if (nMovX < 0 && nOldX == 0)
+ { // trying to go left from 1st column
+ if (nMovY == 0) // done, because no vertical move is requested
+ return;
+ }
+ if (nMovY < 0 && nOldY == 0)
+ { // trying to go up from 1st row
+ if (nMovX == 0) // done, because no horizontal move is requested
+ return;
+ }
+
+ aViewData.ResetOldCursor();
+
+ if (nMovX != 0 && rDoc.ValidColRow(nCurX,nCurY))
+ SkipCursorHorizontal(nCurX, nCurY, nOldX, nMovX);
+
+ if (nMovY != 0 && rDoc.ValidColRow(nCurX,nCurY))
+ SkipCursorVertical(nCurX, nCurY, nOldY, nMovY);
+
+ MoveCursorAbs( nCurX, nCurY, eMode, bShift, false, true, bKeepSel );
+}
+
+void ScTabView::MoveCursorPage( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift, bool bKeepSel )
+{
+ SCCOL nPageX;
+ SCROW nPageY;
+ GetPageMoveEndPosition(nMovX, nMovY, nPageX, nPageY);
+ MoveCursorRel( nPageX, nPageY, eMode, bShift, bKeepSel );
+}
+
+void ScTabView::MoveCursorArea( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift, bool bKeepSel )
+{
+ SCCOL nNewX;
+ SCROW nNewY;
+ GetAreaMoveEndPosition(nMovX, nMovY, eMode, nNewX, nNewY, eMode);
+ MoveCursorRel(nNewX, nNewY, eMode, bShift, bKeepSel);
+}
+
+void ScTabView::MoveCursorEnd( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift, bool bKeepSel )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+
+ SCCOL nCurX;
+ SCROW nCurY;
+ aViewData.GetMoveCursor( nCurX,nCurY );
+ SCCOL nNewX = nCurX;
+ SCROW nNewY = nCurY;
+
+ SCCOL nUsedX = 0;
+ SCROW nUsedY = 0;
+ if ( nMovX > 0 || nMovY > 0 )
+ rDoc.GetPrintArea( nTab, nUsedX, nUsedY ); // get end
+
+ if (nMovX<0)
+ nNewX=0;
+ else if (nMovX>0)
+ nNewX=nUsedX; // last used range
+
+ if (nMovY<0)
+ nNewY=0;
+ else if (nMovY>0)
+ nNewY=nUsedY;
+
+ aViewData.ResetOldCursor();
+ MoveCursorRel( nNewX-nCurX, nNewY-nCurY, eMode, bShift, bKeepSel );
+}
+
+void ScTabView::MoveCursorScreen( SCCOL nMovX, SCROW nMovY, ScFollowMode eMode, bool bShift )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+
+ SCCOL nCurX;
+ SCROW nCurY;
+ aViewData.GetMoveCursor( nCurX,nCurY );
+ SCCOL nNewX = nCurX;
+ SCROW nNewY = nCurY;
+
+ ScSplitPos eWhich = aViewData.GetActivePart();
+ SCCOL nPosX = aViewData.GetPosX( WhichH(eWhich) );
+ SCROW nPosY = aViewData.GetPosY( WhichV(eWhich) );
+
+ SCCOL nAddX = aViewData.VisibleCellsX( WhichH(eWhich) );
+ if (nAddX != 0)
+ --nAddX;
+ SCROW nAddY = aViewData.VisibleCellsY( WhichV(eWhich) );
+ if (nAddY != 0)
+ --nAddY;
+
+ if (nMovX<0)
+ nNewX=nPosX;
+ else if (nMovX>0)
+ nNewX=nPosX+nAddX;
+
+ if (nMovY<0)
+ nNewY=nPosY;
+ else if (nMovY>0)
+ nNewY=nPosY+nAddY;
+
+ aViewData.SetOldCursor( nNewX,nNewY );
+ rDoc.SkipOverlapped(nNewX, nNewY, nTab);
+ MoveCursorAbs( nNewX, nNewY, eMode, bShift, false, true );
+}
+
+void ScTabView::MoveCursorEnter( bool bShift ) // bShift -> up/down
+{
+ const ScInputOptions& rOpt = SC_MOD()->GetInputOptions();
+ if (!rOpt.GetMoveSelection())
+ {
+ aViewData.UpdateInputHandler(true);
+ return;
+ }
+
+ SCCOL nMoveX = 0;
+ SCROW nMoveY = 0;
+ switch (static_cast<ScDirection>(rOpt.GetMoveDir()))
+ {
+ case DIR_BOTTOM:
+ nMoveY = bShift ? -1 : 1;
+ break;
+ case DIR_RIGHT:
+ nMoveX = bShift ? -1 : 1;
+ break;
+ case DIR_TOP:
+ nMoveY = bShift ? 1 : -1;
+ break;
+ case DIR_LEFT:
+ nMoveX = bShift ? 1 : -1;
+ break;
+ }
+
+ SCCOL nCurX;
+ SCROW nCurY;
+ aViewData.GetMoveCursor( nCurX,nCurY );
+ SCCOL nNewX = nCurX;
+ SCROW nNewY = nCurY;
+ SCTAB nTab = aViewData.GetTabNo();
+
+ ScMarkData& rMark = aViewData.GetMarkData();
+ ScDocument& rDoc = aViewData.GetDocument();
+
+ if (rMark.IsMarked() || rMark.IsMultiMarked())
+ {
+ rDoc.GetNextPos( nNewX, nNewY, nTab, nMoveX, nMoveY, true, false, rMark );
+
+ MoveCursorRel( nNewX - nCurX, nNewY - nCurY, SC_FOLLOW_LINE, false, true );
+
+ // update input line even if cursor was not moved
+ if ( nNewX == nCurX && nNewY == nCurY )
+ aViewData.UpdateInputHandler(true);
+ }
+ else
+ {
+ // After Tab and Enter back to the starting column again.
+ const SCCOL nTabStartCol = ((nMoveY != 0 && !nMoveX) ? aViewData.GetTabStartCol() : SC_TABSTART_NONE);
+ rDoc.GetNextPos( nNewX, nNewY, nTab, nMoveX, nMoveY, false, true, rMark, nTabStartCol );
+
+ MoveCursorRel( nNewX - nCurX, nNewY - nCurY, SC_FOLLOW_LINE, false);
+ }
+}
+
+bool ScTabView::MoveCursorKeyInput( const KeyEvent& rKeyEvent )
+{
+ const vcl::KeyCode& rKCode = rKeyEvent.GetKeyCode();
+
+ enum { MOD_NONE, MOD_CTRL, MOD_ALT, MOD_BOTH } eModifier =
+ rKCode.IsMod1() ?
+ (rKCode.IsMod2() ? MOD_BOTH : MOD_CTRL) :
+ (rKCode.IsMod2() ? MOD_ALT : MOD_NONE);
+
+ bool bSel = rKCode.IsShift();
+ sal_uInt16 nCode = rKCode.GetCode();
+
+ // CURSOR keys
+ SCCOL nDX = 0;
+ SCROW nDY = 0;
+ switch( nCode )
+ {
+ case KEY_LEFT: nDX = -1; break;
+ case KEY_RIGHT: nDX = 1; break;
+ case KEY_UP: nDY = -1; break;
+ case KEY_DOWN: nDY = 1; break;
+ }
+ if( nDX != 0 || nDY != 0 )
+ {
+ switch( eModifier )
+ {
+ case MOD_NONE: MoveCursorRel( nDX, nDY, SC_FOLLOW_LINE, bSel ); break;
+ case MOD_CTRL: MoveCursorArea( nDX, nDY, SC_FOLLOW_JUMP, bSel ); break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ // always true to suppress changes of col/row size (ALT+CURSOR)
+ return true;
+ }
+
+ // PAGEUP/PAGEDOWN
+ if( (nCode == KEY_PAGEUP) || (nCode == KEY_PAGEDOWN) )
+ {
+ nDX = (nCode == KEY_PAGEUP) ? -1 : 1;
+ switch( eModifier )
+ {
+ case MOD_NONE: MoveCursorPage( 0, static_cast<SCCOLROW>(nDX), SC_FOLLOW_FIX, bSel ); break;
+ case MOD_ALT: MoveCursorPage( nDX, 0, SC_FOLLOW_FIX, bSel ); break;
+ case MOD_CTRL: SelectNextTab( nDX, false ); break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return true;
+ }
+
+ // HOME/END
+ if( (nCode == KEY_HOME) || (nCode == KEY_END) )
+ {
+ nDX = (nCode == KEY_HOME) ? -1 : 1;
+ ScFollowMode eMode = (nCode == KEY_HOME) ? SC_FOLLOW_LINE : SC_FOLLOW_JUMP;
+ switch( eModifier )
+ {
+ case MOD_NONE: MoveCursorEnd( nDX, 0, eMode, bSel ); break;
+ case MOD_CTRL: MoveCursorEnd( nDX, static_cast<SCCOLROW>(nDX), eMode, bSel ); break;
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ return true;
+ }
+
+ return false;
+}
+
+ // next/previous unprotected cell
+void ScTabView::FindNextUnprot( bool bShift, bool bInSelection )
+{
+ short nMove = bShift ? -1 : 1;
+
+ ScMarkData& rMark = aViewData.GetMarkData();
+ bool bMarked = bInSelection && (rMark.IsMarked() || rMark.IsMultiMarked());
+
+ SCCOL nCurX;
+ SCROW nCurY;
+ aViewData.GetMoveCursor( nCurX,nCurY );
+ SCCOL nNewX = nCurX;
+ SCROW nNewY = nCurY;
+ SCTAB nTab = aViewData.GetTabNo();
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ rDoc.GetNextPos( nNewX,nNewY, nTab, nMove,0, bMarked, true, rMark );
+
+ SCCOL nTabCol = aViewData.GetTabStartCol();
+ if ( nTabCol == SC_TABSTART_NONE )
+ nTabCol = nCurX; // back to this column after Enter
+
+ MoveCursorRel( nNewX-nCurX, nNewY-nCurY, SC_FOLLOW_LINE, false, true );
+
+ // TabCol is reset in MoveCursorRel...
+ aViewData.SetTabStartCol( nTabCol );
+}
+
+void ScTabView::MarkColumns()
+{
+ SCCOL nStartCol;
+ SCCOL nEndCol;
+
+ ScMarkData& rMark = aViewData.GetMarkData();
+ if (rMark.IsMarked())
+ {
+ const ScRange& aMarkRange = rMark.GetMarkArea();
+ nStartCol = aMarkRange.aStart.Col();
+ nEndCol = aMarkRange.aEnd.Col();
+ }
+ else
+ {
+ SCROW nDummy;
+ aViewData.GetMoveCursor( nStartCol, nDummy );
+ nEndCol=nStartCol;
+ }
+
+ SCTAB nTab = aViewData.GetTabNo();
+ ScDocument& rDoc = aViewData.GetDocument();
+ DoneBlockMode();
+ InitBlockMode( nStartCol,0, nTab );
+ MarkCursor( nEndCol, rDoc.MaxRow(), nTab );
+ SelectionChanged();
+}
+
+void ScTabView::MarkRows()
+{
+ SCROW nStartRow;
+ SCROW nEndRow;
+
+ ScMarkData& rMark = aViewData.GetMarkData();
+ if (rMark.IsMarked())
+ {
+ const ScRange& aMarkRange = rMark.GetMarkArea();
+ nStartRow = aMarkRange.aStart.Row();
+ nEndRow = aMarkRange.aEnd.Row();
+ }
+ else
+ {
+ SCCOL nDummy;
+ aViewData.GetMoveCursor( nDummy, nStartRow );
+ nEndRow=nStartRow;
+ }
+
+ SCTAB nTab = aViewData.GetTabNo();
+ ScDocument& rDoc = aViewData.GetDocument();
+ DoneBlockMode();
+ InitBlockMode( 0,nStartRow, nTab );
+ MarkCursor( rDoc.MaxCol(), nEndRow, nTab );
+ SelectionChanged();
+}
+
+
+void ScTabView::MarkColumns(SCCOL nCol, sal_Int16 nModifier)
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCCOL nStartCol = nCol;
+ SCTAB nTab = aViewData.GetTabNo();
+
+ if ((nModifier & KEY_SHIFT) == KEY_SHIFT)
+ bMoveIsShift = true;
+
+ DoneBlockMode( nModifier != 0 );
+ InitBlockMode( nStartCol, 0, nTab, true, true);
+ MarkCursor( nCol, rDoc.MaxRow(), nTab );
+ bMoveIsShift = false;
+ SetCursor( nCol, 0 );
+ SelectionChanged();
+}
+
+void ScTabView::MarkRows(SCROW nRow, sal_Int16 nModifier)
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCROW nStartRow = nRow;
+ SCTAB nTab = aViewData.GetTabNo();
+
+ if ((nModifier & KEY_SHIFT) == KEY_SHIFT)
+ bMoveIsShift = true;
+
+ DoneBlockMode( nModifier != 0 );
+ InitBlockMode( 0, nStartRow, nTab, true, false, true );
+ MarkCursor( rDoc.MaxCol(), nRow, nTab );
+ bMoveIsShift = false;
+ SetCursor( 0, nRow );
+ SelectionChanged();
+}
+
+void ScTabView::MarkDataArea( bool bIncludeCursor )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+ SCCOL nStartCol = aViewData.GetCurX();
+ SCROW nStartRow = aViewData.GetCurY();
+ SCCOL nEndCol = nStartCol;
+ SCROW nEndRow = nStartRow;
+
+ rDoc.GetDataArea( nTab, nStartCol, nStartRow, nEndCol, nEndRow, bIncludeCursor, false );
+
+ HideAllCursors();
+ DoneBlockMode();
+ InitBlockMode( nStartCol, nStartRow, nTab );
+ MarkCursor( nEndCol, nEndRow, nTab );
+ ShowAllCursors();
+
+ SelectionChanged();
+}
+
+void ScTabView::MarkMatrixFormula()
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ ScAddress aCursor( aViewData.GetCurX(), aViewData.GetCurY(), aViewData.GetTabNo() );
+ ScRange aMatrix;
+ if ( rDoc.GetMatrixFormulaRange( aCursor, aMatrix ) )
+ {
+ MarkRange( aMatrix, false ); // cursor is already within the range
+ }
+}
+
+void ScTabView::MarkRange( const ScRange& rRange, bool bSetCursor, bool bContinue )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = rRange.aStart.Tab();
+ SetTabNo( nTab );
+
+ HideAllCursors();
+ DoneBlockMode( bContinue ); // bContinue==true -> clear old mark
+ if (bSetCursor) // if Cursor is set, also always align
+ {
+ SCCOL nAlignX = rRange.aStart.Col();
+ SCROW nAlignY = rRange.aStart.Row();
+ bool bCol = ( rRange.aStart.Col() == 0 && rRange.aEnd.Col() == rDoc.MaxCol() ) && !aViewData.GetDocument().IsInVBAMode();
+ bool bRow = ( rRange.aStart.Row() == 0 && rRange.aEnd.Row() == rDoc.MaxRow() );
+ if ( bCol )
+ nAlignX = aViewData.GetPosX(WhichH(aViewData.GetActivePart()));
+ if ( bRow )
+ nAlignY = aViewData.GetPosY(WhichV(aViewData.GetActivePart()));
+ AlignToCursor( nAlignX, nAlignY, SC_FOLLOW_JUMP );
+ }
+ InitBlockMode( rRange.aStart.Col(), rRange.aStart.Row(), nTab );
+ MarkCursor( rRange.aEnd.Col(), rRange.aEnd.Row(), nTab );
+ if (bSetCursor)
+ {
+ SCCOL nPosX = rRange.aStart.Col();
+ SCROW nPosY = rRange.aStart.Row();
+ rDoc.SkipOverlapped(nPosX, nPosY, nTab);
+
+ aViewData.ResetOldCursor();
+ SetCursor( nPosX, nPosY );
+ }
+ ShowAllCursors();
+
+ SelectionChanged();
+}
+
+void ScTabView::Unmark()
+{
+ ScMarkData& rMark = aViewData.GetMarkData();
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ {
+ SCCOL nCurX;
+ SCROW nCurY;
+ aViewData.GetMoveCursor( nCurX,nCurY );
+ MoveCursorAbs( nCurX, nCurY, SC_FOLLOW_NONE, false, false );
+
+ SelectionChanged();
+ }
+}
+
+void ScTabView::SetMarkData( const ScMarkData& rNew )
+{
+ DoneBlockMode();
+ InitOwnBlockMode( rNew.GetMarkArea());
+ aViewData.GetMarkData() = rNew;
+
+ MarkDataChanged();
+}
+
+void ScTabView::MarkDataChanged()
+{
+ // has to be called after making direct changes to mark data (not via MarkCursor etc)
+
+ UpdateSelectionOverlay();
+}
+
+void ScTabView::SelectNextTab( short nDir, bool bExtendSelection )
+{
+ if (!nDir)
+ return;
+ OSL_ENSURE( nDir==-1 || nDir==1, "SelectNextTab: invalid value");
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+ if (nDir<0)
+ {
+ if (!nTab)
+ return;
+ --nTab;
+ while (!rDoc.IsVisible(nTab))
+ {
+ if (!nTab)
+ return;
+ --nTab;
+ }
+ }
+ else
+ {
+ SCTAB nCount = rDoc.GetTableCount();
+ ++nTab;
+ if (nTab >= nCount)
+ return;
+ while (!rDoc.IsVisible(nTab))
+ {
+ ++nTab;
+ if (nTab >= nCount)
+ return;
+ }
+ }
+
+ SetTabNo( nTab, false, bExtendSelection );
+ PaintExtras();
+}
+
+void ScTabView::SelectTabPage( const sal_uInt16 nTab )
+{
+ pTabControl->SwitchToPageId( nTab );
+}
+
+// SetTabNo - set the displayed sheet
+
+void ScTabView::SetTabNo( SCTAB nTab, bool bNew, bool bExtendSelection, bool bSameTabButMoved )
+{
+ if ( !ValidTab(nTab) )
+ {
+ OSL_FAIL("SetTabNo: invalid sheet");
+ return;
+ }
+
+ if (!bNew && nTab == aViewData.GetTabNo())
+ return;
+
+ // FormShell would like to be informed before the switch
+ FmFormShell* pFormSh = aViewData.GetViewShell()->GetFormShell();
+ if (pFormSh)
+ {
+ bool bAllowed = pFormSh->PrepareClose();
+ if (!bAllowed)
+ {
+ //! error message? or does FormShell do it?
+ //! return error flag and cancel actions
+
+ return; // FormShell says that it can not be switched
+ }
+ }
+
+ // not InputEnterHandler due to reference input
+
+ ScDocument& rDoc = aViewData.GetDocument();
+
+ rDoc.MakeTable( nTab );
+
+ // Update pending row heights before switching the sheet, so Reschedule from the progress bar
+ // doesn't paint the new sheet with old heights
+ aViewData.GetDocShell()->UpdatePendingRowHeights( nTab );
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCTAB nOldPos = nTab;
+ while (!rDoc.IsVisible(nTab)) // search for next visible
+ {
+ bool bUp = (nTab>=nOldPos);
+ if (bUp)
+ {
+ ++nTab;
+ if (nTab>=nTabCount)
+ {
+ nTab = nOldPos;
+ bUp = false;
+ }
+ }
+
+ if (!bUp)
+ {
+ if (nTab != 0)
+ --nTab;
+ else
+ {
+ OSL_FAIL("no visible sheets");
+ rDoc.SetVisible( 0, true );
+ }
+ }
+ }
+
+ // #i71490# Deselect drawing objects before changing the sheet number in view data,
+ // so the handling of notes still has the sheet selected on which the notes are.
+ DrawDeselectAll();
+
+ ScModule* pScMod = SC_MOD();
+ bool bRefMode = pScMod->IsFormulaMode();
+ if ( !bRefMode ) // query, so that RefMode works when switching sheet
+ {
+ DoneBlockMode();
+ pSelEngine->Reset(); // reset all flags, including locked modifiers
+ aViewData.SetRefTabNo( nTab );
+ }
+
+ ScSplitPos eOldActive = aViewData.GetActivePart(); // before switching
+ bool bFocus = pGridWin[eOldActive] && pGridWin[eOldActive]->HasFocus();
+
+ aViewData.SetTabNo( nTab );
+ if (mpSpellCheckCxt)
+ mpSpellCheckCxt->setTabNo( nTab );
+ // UpdateShow before SetCursor, so that UpdateAutoFillMark finds the correct
+ // window (is called from SetCursor)
+ UpdateShow();
+ aViewData.GetView()->TestHintWindow();
+
+ SfxBindings& rBindings = aViewData.GetBindings();
+ ScMarkData& rMark = aViewData.GetMarkData();
+
+ bool bAllSelected = true;
+ for (SCTAB nSelTab = 0; nSelTab < nTabCount; ++nSelTab)
+ {
+ if (!rDoc.IsVisible(nSelTab) || rMark.GetTableSelect(nSelTab))
+ {
+ if (nTab == nSelTab)
+ // This tab is already in selection. Keep the current
+ // selection.
+ bExtendSelection = true;
+ }
+ else
+ {
+ bAllSelected = false;
+ if (bExtendSelection)
+ // We got what we need. No need to stay in the loop.
+ break;
+ }
+ }
+ if (bAllSelected && !bNew)
+ // #i6327# if all tables are selected, a selection event (#i6330#) will deselect all
+ // (not if called with bNew to update settings)
+ bExtendSelection = false;
+
+ if (bExtendSelection)
+ rMark.SelectTable( nTab, true );
+ else
+ {
+ rMark.SelectOneTable( nTab );
+ rBindings.Invalidate( FID_FILL_TAB );
+ rBindings.Invalidate( FID_TAB_DESELECTALL );
+ }
+
+ bool bUnoRefDialog = pScMod->IsRefDialogOpen() && pScMod->GetCurRefDlgId() == WID_SIMPLE_REF;
+
+ // recalc zoom-dependent values (before TabChanged, before UpdateEditViewPos)
+ RefreshZoom();
+ UpdateVarZoom();
+
+ if ( bRefMode ) // hide EditView if necessary (after aViewData.SetTabNo !)
+ {
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ {
+ if (pWin && pWin->IsVisible())
+ pWin->UpdateEditViewPos();
+ }
+ }
+
+ TabChanged(bSameTabButMoved); // DrawView
+ collectUIInformation({{"TABLE", OUString::number(nTab)}});
+ UpdateVisibleRange();
+
+ aViewData.GetViewShell()->WindowChanged(); // if the active window has changed
+ aViewData.ResetOldCursor();
+ SetCursor( aViewData.GetCurX(), aViewData.GetCurY(), true );
+
+ if ( !bUnoRefDialog )
+ aViewData.GetViewShell()->DisconnectAllClients(); // important for floating frames
+ else
+ {
+ // hide / show inplace client
+ ScClient* pClient = static_cast<ScClient*>(aViewData.GetViewShell()->GetIPClient());
+ if ( pClient && pClient->IsObjectInPlaceActive() )
+ {
+ tools::Rectangle aObjArea = pClient->GetObjArea();
+ if ( nTab == aViewData.GetRefTabNo() )
+ {
+ // move to its original position
+
+ SdrOle2Obj* pDrawObj = pClient->GetDrawObj();
+ if ( pDrawObj )
+ {
+ tools::Rectangle aRect = pDrawObj->GetLogicRect();
+ MapMode aMapMode( MapUnit::Map100thMM );
+ Size aOleSize = pDrawObj->GetOrigObjSize( &aMapMode );
+ aRect.SetSize( aOleSize );
+ aObjArea = aRect;
+ }
+ }
+ else
+ {
+ // move to an invisible position
+
+ aObjArea.SetPos( Point( 0, -2*aObjArea.GetHeight() ) );
+ }
+ pClient->SetObjArea( aObjArea );
+ }
+ }
+
+ if ( bFocus && aViewData.GetActivePart() != eOldActive && !bRefMode )
+ ActiveGrabFocus(); // grab focus to the pane that's active now
+
+ // freeze
+
+ bool bResize = false;
+ if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX )
+ if (aViewData.UpdateFixX())
+ bResize = true;
+ if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX )
+ if (aViewData.UpdateFixY())
+ bResize = true;
+ if (bResize)
+ RepeatResize();
+ InvalidateSplit();
+
+ if ( aViewData.IsPagebreakMode() )
+ UpdatePageBreakData(); //! asynchronously ??
+
+ // Form Layer must know the visible area of the new sheet
+ // that is why MapMode must already be correct here
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ {
+ if (pWin)
+ pWin->SetMapMode(pWin->GetDrawMapMode());
+ }
+ SetNewVisArea();
+
+ PaintGrid();
+ PaintTop();
+ PaintLeft();
+ PaintExtras();
+
+ DoResize( aBorderPos, aFrameSize );
+ rBindings.Invalidate( SID_DELETE_PRINTAREA ); // Menu
+ rBindings.Invalidate( FID_DEL_MANUALBREAKS );
+ rBindings.Invalidate( FID_RESET_PRINTZOOM );
+ rBindings.Invalidate( SID_STATUS_DOCPOS ); // Status bar
+ rBindings.Invalidate( SID_ROWCOL_SELCOUNT ); // Status bar
+ rBindings.Invalidate( SID_STATUS_PAGESTYLE ); // Status bar
+ rBindings.Invalidate( SID_CURRENTTAB ); // Navigator
+ rBindings.Invalidate( SID_STYLE_FAMILY2 ); // Designer
+ rBindings.Invalidate( SID_STYLE_FAMILY4 ); // Designer
+ rBindings.Invalidate( SID_TABLES_COUNT );
+
+ if (pScMod->IsRefDialogOpen())
+ {
+ sal_uInt16 nCurRefDlgId=pScMod->GetCurRefDlgId();
+ SfxViewFrame* pViewFrm = aViewData.GetViewShell()->GetViewFrame();
+ SfxChildWindow* pChildWnd = pViewFrm->GetChildWindow( nCurRefDlgId );
+ if (pChildWnd)
+ {
+ if (pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pChildWnd->GetController().get());
+ if (pRefDlg)
+ pRefDlg->ViewShellChanged();
+ }
+ }
+ }
+
+ OnLibreOfficeKitTabChanged();
+}
+
+void ScTabView::AddWindowToForeignEditView(SfxViewShell* pViewShell, ScSplitPos eWhich)
+{
+ aExtraEditViewManager.Add(pViewShell, eWhich);
+}
+
+void ScTabView::RemoveWindowFromForeignEditView(SfxViewShell* pViewShell, ScSplitPos eWhich)
+{
+ aExtraEditViewManager.Remove(pViewShell, eWhich);
+}
+
+void ScTabView::OnLibreOfficeKitTabChanged()
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ ScTabViewShell* pThisViewShell = aViewData.GetViewShell();
+ SCTAB nThisTabNo = pThisViewShell->GetViewData().GetTabNo();
+ auto lTabSwitch = [pThisViewShell, nThisTabNo] (ScTabViewShell* pOtherViewShell)
+ {
+ ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
+ SCTAB nOtherTabNo = rOtherViewData.GetTabNo();
+ if (nThisTabNo == nOtherTabNo)
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ if (rOtherViewData.HasEditView(ScSplitPos(i)))
+ {
+ pThisViewShell->AddWindowToForeignEditView(pOtherViewShell, ScSplitPos(i));
+ }
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 4; ++i)
+ {
+ if (rOtherViewData.HasEditView(ScSplitPos(i)))
+ {
+ pThisViewShell->RemoveWindowFromForeignEditView(pOtherViewShell, ScSplitPos(i));
+ }
+ }
+ }
+ };
+
+ SfxLokHelper::forEachOtherView(pThisViewShell, lTabSwitch);
+
+ pThisViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_HEADER, "all");
+
+ if (pThisViewShell->GetInputHandler())
+ pThisViewShell->GetInputHandler()->UpdateLokReferenceMarks();
+}
+
+// paint functions - only for this View
+
+void ScTabView::MakeEditView( ScEditEngineDefaulter* pEngine, SCCOL nCol, SCROW nRow )
+{
+ DrawDeselectAll();
+
+ if (pDrawView)
+ DrawEnableAnim( false );
+
+ EditView* pSpellingView = aViewData.GetSpellingView();
+
+ for (sal_uInt16 i = 0; i < 4; i++)
+ {
+ if (pGridWin[i] && pGridWin[i]->IsVisible() && !aViewData.HasEditView(ScSplitPos(i)))
+ {
+ ScHSplitPos eHWhich = WhichH( static_cast<ScSplitPos>(i) );
+ ScVSplitPos eVWhich = WhichV( static_cast<ScSplitPos>(i) );
+ SCCOL nScrX = aViewData.GetPosX( eHWhich );
+ SCROW nScrY = aViewData.GetPosY( eVWhich );
+
+ bool bPosVisible =
+ ( nCol >= nScrX && nCol <= nScrX + aViewData.VisibleCellsX(eHWhich) - 1 &&
+ nRow >= nScrY && nRow <= nScrY + aViewData.VisibleCellsY(eVWhich) - 1 );
+
+ // for the active part, create edit view even if outside the visible area,
+ // so input isn't lost (and the edit view may be scrolled into the visible area)
+
+ // #i26433# during spelling, the spelling view must be active
+ if ( bPosVisible || aViewData.GetActivePart() == static_cast<ScSplitPos>(i) ||
+ ( pSpellingView && aViewData.GetEditView(static_cast<ScSplitPos>(i)) == pSpellingView ) )
+ {
+ pGridWin[i]->HideCursor();
+
+ pGridWin[i]->DeleteCursorOverlay();
+ pGridWin[i]->DeleteAutoFillOverlay();
+ pGridWin[i]->DeleteCopySourceOverlay();
+
+ // flush OverlayManager before changing MapMode to text edit
+ pGridWin[i]->flushOverlayManager();
+
+ // MapMode must be set after HideCursor
+ pGridWin[i]->SetMapMode(aViewData.GetLogicMode());
+
+ aViewData.SetEditEngine( static_cast<ScSplitPos>(i), pEngine, pGridWin[i], nCol, nRow );
+
+ if ( !bPosVisible )
+ {
+ // move the edit view area to the real (possibly negative) position,
+ // or hide if completely above or left of the window
+ pGridWin[i]->UpdateEditViewPos();
+ }
+ }
+ }
+ }
+
+ if (aViewData.GetViewShell()->HasAccessibilityObjects())
+ aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccEnterEditMode));
+}
+
+void ScTabView::UpdateEditView()
+{
+ ScSplitPos eActive = aViewData.GetActivePart();
+ for (sal_uInt16 i = 0; i < 4; i++)
+ {
+ ScSplitPos eCurrent = ScSplitPos(i);
+ if (aViewData.HasEditView(eCurrent))
+ {
+ EditView* pEditView = aViewData.GetEditView(eCurrent);
+
+ tools::Long nRefTabNo = GetViewData().GetRefTabNo();
+ tools::Long nX = GetViewData().GetCurXForTab(nRefTabNo);
+ tools::Long nY = GetViewData().GetCurYForTab(nRefTabNo);
+
+ aViewData.SetEditEngine(eCurrent,
+ static_cast<ScEditEngineDefaulter*>(pEditView->GetEditEngine()),
+ pGridWin[i], nX, nY );
+ if (eCurrent == eActive)
+ pEditView->ShowCursor( false );
+ }
+ }
+}
+
+void ScTabView::KillEditView( bool bNoPaint )
+{
+ SCCOL nCol1 = aViewData.GetEditStartCol();
+ SCROW nRow1 = aViewData.GetEditStartRow();
+ SCCOL nCol2 = aViewData.GetEditEndCol();
+ SCROW nRow2 = aViewData.GetEditEndRow();
+ bool bPaint[4];
+ bool bNotifyAcc = false;
+ tools::Rectangle aRectangle[4];
+
+ bool bExtended = nRow1 != nRow2; // column is painted to the end anyway
+
+ bool bAtCursor = nCol1 <= aViewData.GetCurX() &&
+ nCol2 >= aViewData.GetCurX() &&
+ nRow1 == aViewData.GetCurY();
+ for (sal_uInt16 i = 0; i < 4; i++)
+ {
+ bPaint[i] = aViewData.HasEditView( static_cast<ScSplitPos>(i) );
+ if (bPaint[i])
+ {
+ bNotifyAcc = true;
+
+ EditView* pView = aViewData.GetEditView( static_cast<ScSplitPos>(i) );
+ aRectangle[i] = pView->GetInvalidateRect();
+ }
+ }
+
+ // notify accessibility before all things happen
+ if (bNotifyAcc && aViewData.GetViewShell()->HasAccessibilityObjects())
+ aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccLeaveEditMode));
+
+ aViewData.ResetEditView();
+ for (sal_uInt16 i = 0; i < 4; i++)
+ {
+ if (pGridWin[i] && bPaint[i] && pGridWin[i]->IsVisible())
+ {
+ pGridWin[i]->ShowCursor();
+
+ pGridWin[i]->SetMapMode(pGridWin[i]->GetDrawMapMode());
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ const tools::Rectangle& rInvRect = aRectangle[i];
+ pGridWin[i]->Invalidate(rInvRect);
+
+ // invalidate other views
+ auto lInvalidateWindows =
+ [&rInvRect] (ScTabView* pTabView)
+ {
+ for (VclPtr<ScGridWindow> const & pWin: pTabView->pGridWin)
+ {
+ if (pWin)
+ pWin->Invalidate(rInvRect);
+ }
+ };
+
+ SfxLokHelper::forEachOtherView(GetViewData().GetViewShell(), lInvalidateWindows);
+ }
+ // #i73567# the cell still has to be repainted
+ else if (bExtended || ( bAtCursor && !bNoPaint ))
+ {
+ pGridWin[i]->Draw( nCol1, nRow1, nCol2, nRow2, ScUpdateMode::All );
+ pGridWin[i]->UpdateSelectionOverlay();
+ }
+ }
+ }
+
+ if (pDrawView)
+ DrawEnableAnim( true );
+
+ // GrabFocus always when this View is active and
+ // when the input row has the focus
+
+ bool bGrabFocus = false;
+ if (aViewData.IsActive())
+ {
+ ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
+ if ( pInputHdl )
+ {
+ ScInputWindow* pInputWin = pInputHdl->GetInputWindow();
+ if (pInputWin && pInputWin->IsInputActive())
+ bGrabFocus = true;
+ }
+ }
+
+ if (bGrabFocus)
+ {
+// should be done like this, so that Sfx notice it, but it does not work:
+//! aViewData.GetViewShell()->GetViewFrame()->GetWindow().GrabFocus();
+// therefore first like this:
+ GetActiveWin()->GrabFocus();
+ }
+
+ // cursor query only after GrabFocus
+
+ for (sal_uInt16 i = 0; i < 4; i++)
+ {
+ if (pGridWin[i] && pGridWin[i]->IsVisible())
+ {
+ vcl::Cursor* pCur = pGridWin[i]->GetCursor();
+ if (pCur && pCur->IsVisible())
+ pCur->Hide();
+
+ if (bPaint[i])
+ {
+ pGridWin[i]->UpdateCursorOverlay();
+ pGridWin[i]->UpdateAutoFillOverlay();
+ }
+ }
+ }
+}
+
+void ScTabView::UpdateFormulas(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow)
+{
+ if ( aViewData.GetDocument().IsAutoCalcShellDisabled() )
+ return;
+
+ for (sal_uInt16 i = 0; i < 4; i++)
+ {
+ if (pGridWin[i] && pGridWin[i]->IsVisible())
+ pGridWin[i]->UpdateFormulas(nStartCol, nStartRow, nEndCol, nEndRow);
+ }
+
+ if ( aViewData.IsPagebreakMode() )
+ UpdatePageBreakData(); //! asynchronous
+
+ UpdateHeaderWidth();
+
+ // if in edit mode, adjust edit view area because widths/heights may have changed
+ if ( aViewData.HasEditView( aViewData.GetActivePart() ) )
+ UpdateEditView();
+}
+
+// PaintArea - repaint block
+
+void ScTabView::PaintArea( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ ScUpdateMode eMode )
+{
+ SCCOL nCol1;
+ SCROW nRow1;
+ SCCOL nCol2;
+ SCROW nRow2;
+ bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
+ ScDocument& rDoc = aViewData.GetDocument();
+
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartRow, nEndRow );
+
+ for (size_t i = 0; i < 4; ++i)
+ {
+ if (!pGridWin[i] || !pGridWin[i]->IsVisible())
+ continue;
+
+ ScHSplitPos eHWhich = WhichH( static_cast<ScSplitPos>(i) );
+ ScVSplitPos eVWhich = WhichV( static_cast<ScSplitPos>(i) );
+ bool bOut = false;
+
+ nCol1 = nStartCol;
+ nRow1 = nStartRow;
+ nCol2 = nEndCol;
+ nRow2 = nEndRow;
+
+ SCCOL nLastX = 0;
+ SCROW nLastY = 0;
+
+ if (bIsTiledRendering)
+ {
+ nLastX = aViewData.GetMaxTiledCol();
+ nLastY = aViewData.GetMaxTiledRow();
+ }
+ else
+ {
+
+ SCCOL nScrX = aViewData.GetPosX( eHWhich );
+ SCROW nScrY = aViewData.GetPosY( eVWhich );
+
+ if (nCol1 < nScrX)
+ nCol1 = nScrX;
+ if (nCol2 < nScrX)
+ {
+ if ( eMode == ScUpdateMode::All ) // for UPDATE_ALL, paint anyway
+ nCol2 = nScrX; // (because of extending strings to the right)
+ else
+ bOut = true; // completely outside the window
+ }
+ if (nRow1 < nScrY)
+ nRow1 = nScrY;
+ if (nRow2 < nScrY)
+ bOut = true;
+
+ nLastX = nScrX + aViewData.VisibleCellsX( eHWhich ) + 1;
+ nLastY = nScrY + aViewData.VisibleCellsY( eVWhich ) + 1;
+ }
+
+ if (nCol1 > nLastX)
+ bOut = true;
+ if (nCol2 > nLastX)
+ nCol2 = nLastX;
+ if (nRow1 > nLastY)
+ bOut = true;
+ if (nRow2 > nLastY)
+ nRow2 = nLastY;
+
+ if (bOut)
+ continue;
+
+ bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( aViewData.GetTabNo() );
+ tools::Long nLayoutSign = (!bIsTiledRendering && bLayoutRTL) ? -1 : 1;
+
+ Point aStart = aViewData.GetScrPos( nCol1, nRow1, static_cast<ScSplitPos>(i) );
+ Point aEnd = aViewData.GetScrPos( nCol2+1, nRow2+1, static_cast<ScSplitPos>(i) );
+
+ if ( eMode == ScUpdateMode::All )
+ {
+ if (bIsTiledRendering)
+ {
+ // When a cell content is deleted we have no clue about
+ // the width of the embedded text.
+ // Anyway, clients will ask only for tiles that overlaps
+ // the visible area.
+ // Remember that wsd expects int and that aEnd.X() is
+ // in pixels and will be converted in twips, before performing
+ // the lok callback, so we need to avoid that an overflow occurs.
+ aEnd.setX( std::numeric_limits<int>::max() / 1000 );
+ }
+ else
+ {
+ aEnd.setX( bLayoutRTL ? 0 : pGridWin[i]->GetOutputSizePixel().Width() );
+ }
+ }
+ aEnd.AdjustX( -nLayoutSign );
+ aEnd.AdjustY( -1 );
+
+ // #i85232# include area below cells (could be done in GetScrPos?)
+ if ( eMode == ScUpdateMode::All && nRow2 >= rDoc.MaxRow() && !bIsTiledRendering )
+ aEnd.setY( pGridWin[i]->GetOutputSizePixel().Height() );
+
+ aStart.AdjustX( -nLayoutSign ); // include change marks
+ aStart.AdjustY( -1 );
+
+ bool bMarkClipped = aViewData.GetOptions().GetOption( VOPT_CLIPMARKS );
+ if (bMarkClipped)
+ {
+ // ScColumn::IsEmptyData has to be optimized for this
+ // (switch to Search() )
+ //!if ( nCol1 > 0 && !aViewData.GetDocument()->IsBlockEmpty(
+ //! 0, nRow1, nCol1-1, nRow2.
+ //! aViewData.GetTabNo() ) )
+ tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * aViewData.GetPPTX() );
+ aStart.AdjustX( -(nMarkPixel * nLayoutSign) );
+ }
+
+ pGridWin[i]->Invalidate( pGridWin[i]->PixelToLogic( tools::Rectangle( aStart,aEnd ) ) );
+ }
+
+ // #i79909# Calling UpdateAllOverlays here isn't necessary and would lead to overlay calls from a timer,
+ // with a wrong MapMode if editing in a cell (reference input).
+ // #i80499# Overlays need updates in a lot of cases, e.g. changing row/column size,
+ // or showing/hiding outlines. TODO: selections in inactive windows are vanishing.
+ // #i84689# With relative conditional formats, PaintArea may be called often (for each changed cell),
+ // so UpdateAllOverlays was moved to ScTabViewShell::Notify and is called only if PaintPartFlags::Left/PaintPartFlags::Top
+ // is set (width or height changed).
+}
+
+void ScTabView::PaintRangeFinderEntry (const ScRangeFindData* pData, const SCTAB nTab)
+{
+ ScRange aRef = pData->aRef;
+ aRef.PutInOrder(); // PutInOrder for the queries below
+
+ if ( aRef.aStart == aRef.aEnd ) //! ignore sheet?
+ aViewData.GetDocument().ExtendMerge(aRef);
+
+ if (aRef.aStart.Tab() < nTab || aRef.aEnd.Tab() > nTab)
+ return;
+
+ SCCOL nCol1 = aRef.aStart.Col();
+ SCROW nRow1 = aRef.aStart.Row();
+ SCCOL nCol2 = aRef.aEnd.Col();
+ SCROW nRow2 = aRef.aEnd.Row();
+
+ // remove -> repaint
+ // ScUpdateMode::Marks: Invalidate, nothing until end of row
+
+ bool bHiddenEdge = false;
+ SCROW nTmp;
+ ScDocument& rDoc = aViewData.GetDocument();
+ while ( nCol1 > 0 && rDoc.ColHidden(nCol1, nTab) )
+ {
+ --nCol1;
+ bHiddenEdge = true;
+ }
+ while ( nCol2 < rDoc.MaxCol() && rDoc.ColHidden(nCol2, nTab) )
+ {
+ ++nCol2;
+ bHiddenEdge = true;
+ }
+ nTmp = rDoc.LastVisibleRow(0, nRow1, nTab);
+ if (!rDoc.ValidRow(nTmp))
+ nTmp = 0;
+ if (nTmp < nRow1)
+ {
+ nRow1 = nTmp;
+ bHiddenEdge = true;
+ }
+ nTmp = rDoc.FirstVisibleRow(nRow2, rDoc.MaxRow(), nTab);
+ if (!rDoc.ValidRow(nTmp))
+ nTmp = rDoc.MaxRow();
+ if (nTmp > nRow2)
+ {
+ nRow2 = nTmp;
+ bHiddenEdge = true;
+ }
+
+ if ( nCol2 - nCol1 > 1 && nRow2 - nRow1 > 1 && !bHiddenEdge )
+ {
+ // only along the edges
+ PaintArea( nCol1, nRow1, nCol2, nRow1, ScUpdateMode::Marks );
+ PaintArea( nCol1, nRow1+1, nCol1, nRow2-1, ScUpdateMode::Marks );
+ PaintArea( nCol2, nRow1+1, nCol2, nRow2-1, ScUpdateMode::Marks );
+ PaintArea( nCol1, nRow2, nCol2, nRow2, ScUpdateMode::Marks );
+ }
+ else // all in one
+ PaintArea( nCol1, nRow1, nCol2, nRow2, ScUpdateMode::Marks );
+}
+
+void ScTabView::PaintRangeFinder( tools::Long nNumber )
+{
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl( aViewData.GetViewShell() );
+ if (!pHdl)
+ return;
+
+ ScRangeFindList* pRangeFinder = pHdl->GetRangeFindList();
+ if ( !(pRangeFinder && pRangeFinder->GetDocName() == aViewData.GetDocShell()->GetTitle()) )
+ return;
+
+ SCTAB nTab = aViewData.GetTabNo();
+ sal_uInt16 nCount = static_cast<sal_uInt16>(pRangeFinder->Count());
+
+ if (nNumber < 0)
+ {
+ for (sal_uInt16 i=0; i<nCount; i++)
+ PaintRangeFinderEntry(&pRangeFinder->GetObject(i),nTab);
+ }
+ else
+ {
+ sal_uInt16 idx = nNumber;
+ if (idx < nCount)
+ PaintRangeFinderEntry(&pRangeFinder->GetObject(idx),nTab);
+ }
+}
+
+// for chart data selection
+
+void ScTabView::AddHighlightRange( const ScRange& rRange, const Color& rColor )
+{
+ maHighlightRanges.emplace_back( rRange, rColor );
+
+ SCTAB nTab = aViewData.GetTabNo();
+ if ( nTab >= rRange.aStart.Tab() && nTab <= rRange.aEnd.Tab() )
+ PaintArea( rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), ScUpdateMode::Marks );
+}
+
+void ScTabView::ClearHighlightRanges()
+{
+ SCTAB nTab = aViewData.GetTabNo();
+ for (ScHighlightEntry const & rEntry : maHighlightRanges)
+ {
+ ScRange aRange = rEntry.aRef;
+ if ( nTab >= aRange.aStart.Tab() && nTab <= aRange.aEnd.Tab() )
+ PaintArea( aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(), ScUpdateMode::Marks );
+ }
+
+ maHighlightRanges.clear();
+}
+
+void ScTabView::DoChartSelection(
+ const uno::Sequence< chart2::data::HighlightedRange > & rHilightRanges )
+{
+ ClearHighlightRanges();
+ const sal_Unicode sep = ::formula::FormulaCompiler::GetNativeSymbolChar(ocSep);
+ size_t nSize = 0;
+ size_t nIndex = 0;
+ std::vector<ReferenceMark> aReferenceMarks( nSize );
+
+ for (chart2::data::HighlightedRange const & rHighlightedRange : rHilightRanges)
+ {
+ Color aSelColor(ColorTransparency, rHighlightedRange.PreferredColor);
+ ScRangeList aRangeList;
+ ScDocument& rDoc = aViewData.GetDocShell()->GetDocument();
+ if( ScRangeStringConverter::GetRangeListFromString(
+ aRangeList, rHighlightedRange.RangeRepresentation, rDoc, rDoc.GetAddressConvention(), sep ))
+ {
+ size_t nListSize = aRangeList.size();
+ nSize += nListSize;
+ aReferenceMarks.resize(nSize);
+
+ for ( size_t j = 0; j < nListSize; ++j )
+ {
+ ScRange& p = aRangeList[j];
+ ScRange aTargetRange;
+ if( rHighlightedRange.Index == - 1 )
+ {
+ aTargetRange = p;
+ AddHighlightRange( aTargetRange, aSelColor );
+ }
+ else
+ {
+ aTargetRange = lcl_getSubRangeByIndex( p, rHighlightedRange.Index );
+ AddHighlightRange( aTargetRange, aSelColor );
+ }
+
+ if ( comphelper::LibreOfficeKit::isActive() && aViewData.GetViewShell() )
+ {
+ aTargetRange.PutInOrder();
+
+ tools::Long nX1 = aTargetRange.aStart.Col();
+ tools::Long nX2 = aTargetRange.aEnd.Col();
+ tools::Long nY1 = aTargetRange.aStart.Row();
+ tools::Long nY2 = aTargetRange.aEnd.Row();
+ tools::Long nTab = aTargetRange.aStart.Tab();
+
+ aReferenceMarks[nIndex++] = ScInputHandler::GetReferenceMark( aViewData, aViewData.GetDocShell(),
+ nX1, nX2, nY1, nY2,
+ nTab, aSelColor );
+ }
+ }
+ }
+ }
+
+ if ( comphelper::LibreOfficeKit::isActive() && aViewData.GetViewShell() )
+ ScInputHandler::SendReferenceMarks( aViewData.GetViewShell(), aReferenceMarks );
+}
+
+void ScTabView::DoDPFieldPopup(std::u16string_view rPivotTableName, sal_Int32 nDimensionIndex, Point aPoint, Size aSize)
+{
+ ScDocument& rDocument = aViewData.GetDocShell()->GetDocument();
+ ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get();
+
+ if (!pWin)
+ return;
+
+ ScDPCollection* pDPCollection = rDocument.GetDPCollection();
+ ScDPObject* pDPObject = pDPCollection->GetByName(rPivotTableName);
+ if (!pDPObject)
+ return;
+
+ pDPObject->BuildAllDimensionMembers();
+
+ Point aPos = pWin->LogicToPixel(aPoint);
+ bool bLOK = comphelper::LibreOfficeKit::isActive();
+ Point aScreenPoint = bLOK ? aPos : pWin->OutputToScreenPixel(aPos);
+ Size aScreenSize = pWin->LogicToPixel(aSize);
+
+ pWin->DPLaunchFieldPopupMenu(aScreenPoint, aScreenSize, nDimensionIndex, pDPObject);
+}
+
+// PaintGrid - repaint data range
+
+void ScTabView::PaintGrid()
+{
+ for (sal_uInt16 i = 0; i < 4; i++)
+ {
+ if (pGridWin[i] && pGridWin[i]->IsVisible())
+ pGridWin[i]->Invalidate();
+ }
+}
+
+// PaintTop - repaint top control elements
+
+void ScTabView::PaintTop()
+{
+ for (sal_uInt16 i = 0; i < 2; i++)
+ {
+ if (pColBar[i])
+ pColBar[i]->Invalidate();
+ if (pColOutline[i])
+ pColOutline[i]->Invalidate();
+ }
+}
+
+void ScTabView::CreateAnchorHandles(SdrHdlList& rHdl, const ScAddress& rAddress)
+{
+ for (sal_uInt16 i = 0; i < 4; i++)
+ {
+ if(pGridWin[i] && pGridWin[i]->IsVisible())
+ pGridWin[i]->CreateAnchorHandle(rHdl, rAddress);
+ }
+}
+
+void ScTabView::PaintTopArea( SCCOL nStartCol, SCCOL nEndCol )
+{
+ // pixel position of the left edge
+
+ if ( nStartCol < aViewData.GetPosX(SC_SPLIT_LEFT) ||
+ nStartCol < aViewData.GetPosX(SC_SPLIT_RIGHT) )
+ aViewData.RecalcPixPos();
+
+ // adjust freeze (UpdateFixX resets HSplitPos)
+
+ if ( aViewData.GetHSplitMode() == SC_SPLIT_FIX && nStartCol < aViewData.GetFixPosX() )
+ if (aViewData.UpdateFixX())
+ RepeatResize();
+
+ // paint
+
+ if (nStartCol>0)
+ --nStartCol; //! general ?
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( aViewData.GetTabNo() );
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ for (sal_uInt16 i = 0; i < 2; i++)
+ {
+ ScHSplitPos eWhich = ScHSplitPos(i);
+ if (pColBar[eWhich])
+ {
+ Size aWinSize = pColBar[eWhich]->GetSizePixel();
+ tools::Long nStartX = aViewData.GetScrPos( nStartCol, 0, eWhich ).X();
+ tools::Long nEndX;
+ if (nEndCol >= rDoc.MaxCol())
+ nEndX = bLayoutRTL ? 0 : ( aWinSize.Width()-1 );
+ else
+ nEndX = aViewData.GetScrPos( nEndCol+1, 0, eWhich ).X() - nLayoutSign;
+ if (nStartX > nEndX)
+ std::swap(nStartX, nEndX);
+ pColBar[eWhich]->Invalidate(
+ tools::Rectangle( nStartX, 0, nEndX, aWinSize.Height()-1 ) );
+ }
+ if (pColOutline[eWhich])
+ pColOutline[eWhich]->Invalidate();
+ }
+}
+
+// PaintLeft - repaint left control elements
+
+void ScTabView::PaintLeft()
+{
+ for (sal_uInt16 i = 0; i < 2; i++)
+ {
+ if (pRowBar[i])
+ pRowBar[i]->Invalidate();
+ if (pRowOutline[i])
+ pRowOutline[i]->Invalidate();
+ }
+}
+
+void ScTabView::PaintLeftArea( SCROW nStartRow, SCROW nEndRow )
+{
+ // pixel position of the upper edge
+
+ if ( nStartRow < aViewData.GetPosY(SC_SPLIT_TOP) ||
+ nStartRow < aViewData.GetPosY(SC_SPLIT_BOTTOM) )
+ aViewData.RecalcPixPos();
+
+ // adjust freeze (UpdateFixY reset VSplitPos)
+
+ if ( aViewData.GetVSplitMode() == SC_SPLIT_FIX && nStartRow < aViewData.GetFixPosY() )
+ if (aViewData.UpdateFixY())
+ RepeatResize();
+
+ // paint
+
+ if (nStartRow>0)
+ --nStartRow;
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ for (sal_uInt16 i = 0; i < 2; i++)
+ {
+ ScVSplitPos eWhich = ScVSplitPos(i);
+ if (pRowBar[eWhich])
+ {
+ Size aWinSize = pRowBar[eWhich]->GetSizePixel();
+ tools::Long nStartY = aViewData.GetScrPos( 0, nStartRow, eWhich ).Y();
+ tools::Long nEndY;
+ if (nEndRow >= rDoc.MaxRow())
+ nEndY = aWinSize.Height() - 1;
+ else
+ nEndY = aViewData.GetScrPos( 0, nEndRow+1, eWhich ).Y() - 1;
+ if (nStartY > nEndY)
+ std::swap(nStartY, nEndY);
+ pRowBar[eWhich]->Invalidate(
+ tools::Rectangle( 0, nStartY, aWinSize.Width()-1, nEndY ) );
+ }
+ if (pRowOutline[eWhich])
+ pRowOutline[eWhich]->Invalidate();
+ }
+}
+
+bool ScTabView::PaintExtras()
+{
+ bool bRet = false;
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+ if (!rDoc.HasTable(nTab)) // sheet is deleted?
+ {
+ SCTAB nCount = rDoc.GetTableCount();
+ aViewData.SetTabNo(nCount-1);
+ bRet = true;
+ }
+ pTabControl->UpdateStatus(); // true = active
+ return bRet;
+}
+
+void ScTabView::RecalcPPT()
+{
+ // called after changes that require the PPT values to be recalculated
+ // (currently from detective operations)
+
+ double nOldX = aViewData.GetPPTX();
+ double nOldY = aViewData.GetPPTY();
+
+ aViewData.RefreshZoom(); // pre-calculate new PPT values
+
+ bool bChangedX = ( aViewData.GetPPTX() != nOldX );
+ bool bChangedY = ( aViewData.GetPPTY() != nOldY );
+ if ( !(bChangedX || bChangedY) )
+ return;
+
+ // call view SetZoom (including draw scale, split update etc)
+ // and paint only if values changed
+
+ Fraction aZoomX = aViewData.GetZoomX();
+ Fraction aZoomY = aViewData.GetZoomY();
+ SetZoom( aZoomX, aZoomY, false );
+
+ PaintGrid();
+ if (bChangedX)
+ PaintTop();
+ if (bChangedY)
+ PaintLeft();
+}
+
+void ScTabView::ActivateView( bool bActivate, bool bFirst )
+{
+ if ( bActivate == aViewData.IsActive() && !bFirst )
+ {
+ // no assertion anymore - occurs when previously in Drag&Drop switching over
+ // to another document
+ return;
+ }
+
+ // is only called for MDI-(De)Activate
+ // aViewData.Activate behind due to cursor show for KillEditView
+ // don't delete selection - if Activate(false) is set in ViewData,
+ // then the selection is not displayed
+
+ if (!bActivate)
+ {
+ ScModule* pScMod = SC_MOD();
+ bool bRefMode = pScMod->IsFormulaMode();
+
+ // don't cancel reference input, to allow reference
+ // to other document
+
+ if (!bRefMode)
+ {
+ // pass view to GetInputHdl, this view may not be current anymore
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl(aViewData.GetViewShell());
+ if (pHdl)
+ pHdl->EnterHandler();
+ }
+ }
+
+ PaintExtras();
+
+ aViewData.Activate(bActivate);
+
+ PaintBlock(false); // repaint, selection after active status
+
+ if (!bActivate)
+ HideAllCursors(); // Cursor
+ else if (!bFirst)
+ ShowAllCursors();
+
+ if (bActivate)
+ {
+ if ( bFirst )
+ {
+ ScSplitPos eWin = aViewData.GetActivePart();
+ OSL_ENSURE( pGridWin[eWin], "Corrupted document, not all SplitPos in GridWin" );
+ if ( !pGridWin[eWin] )
+ {
+ eWin = SC_SPLIT_BOTTOMLEFT;
+ if ( !pGridWin[eWin] )
+ {
+ short i;
+ for ( i=0; i<4; i++ )
+ {
+ if ( pGridWin[i] )
+ {
+ eWin = static_cast<ScSplitPos>(i);
+ break; // for
+ }
+ }
+ OSL_ENSURE( i<4, "and BOOM" );
+ }
+ aViewData.SetActivePart( eWin );
+ }
+ }
+ // do not call GrabFocus from here!
+ // if the document is processed, then Sfx calls GrabFocus in the window of the shell.
+ // if it is a mail body for instance, then it can't get the focus
+ UpdateInputContext();
+ }
+ else
+ pGridWin[aViewData.GetActivePart()]->ClickExtern();
+}
+
+void ScTabView::ActivatePart( ScSplitPos eWhich )
+{
+ ScSplitPos eOld = aViewData.GetActivePart();
+ if ( eOld == eWhich )
+ return;
+
+ bInActivatePart = true;
+
+ bool bRefMode = SC_MOD()->IsFormulaMode();
+
+ // the HasEditView call during SetCursor would fail otherwise
+ if ( aViewData.HasEditView(eOld) && !bRefMode )
+ UpdateInputLine();
+
+ ScHSplitPos eOldH = WhichH(eOld);
+ ScVSplitPos eOldV = WhichV(eOld);
+ ScHSplitPos eNewH = WhichH(eWhich);
+ ScVSplitPos eNewV = WhichV(eWhich);
+ bool bTopCap = pColBar[eOldH] && pColBar[eOldH]->IsMouseCaptured();
+ bool bLeftCap = pRowBar[eOldV] && pRowBar[eOldV]->IsMouseCaptured();
+
+ bool bFocus = pGridWin[eOld]->HasFocus();
+ bool bCapture = pGridWin[eOld]->IsMouseCaptured();
+ if (bCapture)
+ pGridWin[eOld]->ReleaseMouse();
+ pGridWin[eOld]->ClickExtern();
+ pGridWin[eOld]->HideCursor();
+ pGridWin[eWhich]->HideCursor();
+ aViewData.SetActivePart( eWhich );
+
+ ScTabViewShell* pShell = aViewData.GetViewShell();
+ pShell->WindowChanged();
+
+ pSelEngine->SetWindow(pGridWin[eWhich]);
+ pSelEngine->SetWhich(eWhich);
+ pSelEngine->SetVisibleArea( tools::Rectangle(Point(), pGridWin[eWhich]->GetOutputSizePixel()) );
+
+ pGridWin[eOld]->MoveMouseStatus(*pGridWin[eWhich]);
+
+ if ( bCapture || pGridWin[eWhich]->IsMouseCaptured() )
+ {
+ // tracking instead of CaptureMouse, so it can be cancelled cleanly
+ // (SelectionEngine calls CaptureMouse for SetWindow)
+ //! someday SelectionEngine itself should call StartTracking!?!
+ pGridWin[eWhich]->ReleaseMouse();
+ pGridWin[eWhich]->StartTracking();
+ }
+
+ if ( bTopCap && pColBar[eNewH] )
+ {
+ pColBar[eOldH]->SetIgnoreMove(true);
+ pColBar[eNewH]->SetIgnoreMove(false);
+ pHdrSelEng->SetWindow( pColBar[eNewH] );
+ tools::Long nWidth = pColBar[eNewH]->GetOutputSizePixel().Width();
+ pHdrSelEng->SetVisibleArea( tools::Rectangle( 0, LONG_MIN, nWidth-1, LONG_MAX ) );
+ pColBar[eNewH]->CaptureMouse();
+ }
+ if ( bLeftCap && pRowBar[eNewV] )
+ {
+ pRowBar[eOldV]->SetIgnoreMove(true);
+ pRowBar[eNewV]->SetIgnoreMove(false);
+ pHdrSelEng->SetWindow( pRowBar[eNewV] );
+ tools::Long nHeight = pRowBar[eNewV]->GetOutputSizePixel().Height();
+ pHdrSelEng->SetVisibleArea( tools::Rectangle( LONG_MIN, 0, LONG_MAX, nHeight-1 ) );
+ pRowBar[eNewV]->CaptureMouse();
+ }
+ aHdrFunc.SetWhich(eWhich);
+
+ pGridWin[eOld]->ShowCursor();
+ pGridWin[eWhich]->ShowCursor();
+
+ SfxInPlaceClient* pClient = aViewData.GetViewShell()->GetIPClient();
+ bool bOleActive = ( pClient && pClient->IsObjectInPlaceActive() );
+
+ // don't switch ViewShell's active window during RefInput, because the focus
+ // might change, and subsequent SetReference calls wouldn't find the right EditView
+ if ( !bRefMode && !bOleActive )
+ aViewData.GetViewShell()->SetWindow( pGridWin[eWhich] );
+
+ if ( bFocus && !aViewData.IsAnyFillMode() && !bRefMode )
+ {
+ // GrabFocus only if previously the other GridWindow had the focus
+ // (for instance due to search and replace)
+ pGridWin[eWhich]->GrabFocus();
+ }
+
+ bInActivatePart = false;
+}
+
+void ScTabView::HideListBox()
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ {
+ if (pWin)
+ pWin->ClickExtern();
+ }
+}
+
+void ScTabView::UpdateInputContext()
+{
+ ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get();
+ if (pWin)
+ pWin->UpdateInputContext();
+
+ if (pTabControl)
+ pTabControl->UpdateInputContext();
+}
+
+// GetGridWidth - width of an output range (for ViewData)
+
+tools::Long ScTabView::GetGridWidth( ScHSplitPos eWhich )
+{
+ // at present only the size of the current pane is synchronized with
+ // the size of the visible area in Online;
+ // as a workaround we use the same width for all panes independently
+ // from the eWhich value
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScGridWindow* pGridWindow = aViewData.GetActiveWin();
+ if (pGridWindow)
+ return pGridWindow->GetSizePixel().Width();
+ }
+
+ ScSplitPos eGridWhich = ( eWhich == SC_SPLIT_LEFT ) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT;
+ if (pGridWin[eGridWhich])
+ return pGridWin[eGridWhich]->GetSizePixel().Width();
+ else
+ return 0;
+}
+
+// GetGridHeight - height of an output range (for ViewData)
+
+tools::Long ScTabView::GetGridHeight( ScVSplitPos eWhich )
+{
+ // at present only the size of the current pane is synchronized with
+ // the size of the visible area in Online;
+ // as a workaround we use the same height for all panes independently
+ // from the eWhich value
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScGridWindow* pGridWindow = aViewData.GetActiveWin();
+ if (pGridWindow)
+ return pGridWindow->GetSizePixel().Height();
+ }
+
+ ScSplitPos eGridWhich = ( eWhich == SC_SPLIT_TOP ) ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT;
+ if (pGridWin[eGridWhich])
+ return pGridWin[eGridWhich]->GetSizePixel().Height();
+ else
+ return 0;
+}
+
+void ScTabView::UpdateInputLine()
+{
+ SC_MOD()->InputEnterHandler();
+}
+
+void ScTabView::ZoomChanged()
+{
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl(aViewData.GetViewShell());
+ if (pHdl)
+ pHdl->SetRefScale( aViewData.GetZoomX(), aViewData.GetZoomY() );
+
+ UpdateFixPos();
+
+ UpdateScrollBars();
+
+ // VisArea...
+ // AW: Discussed with NN if there is a reason that new map mode was only set for one window,
+ // but is not. Setting only on one window causes the first repaint to have the old mapMode
+ // in three of four views, so the overlay will save the wrong content e.g. when zooming out.
+ // Changing to setting map mode at all windows.
+
+ for (sal_uInt32 i = 0; i < 4; i++)
+ {
+ if (pGridWin[i])
+ pGridWin[i]->SetMapMode(pGridWin[i]->GetDrawMapMode());
+ }
+
+ SetNewVisArea();
+
+ InterpretVisible(); // have everything calculated before painting
+
+ SfxBindings& rBindings = aViewData.GetBindings();
+ rBindings.Invalidate( SID_ATTR_ZOOM );
+ rBindings.Invalidate( SID_ATTR_ZOOMSLIDER );
+ rBindings.Invalidate(SID_ZOOM_IN);
+ rBindings.Invalidate(SID_ZOOM_OUT);
+
+ HideNoteMarker();
+
+ // To not change too much, use pWin here
+ ScGridWindow* pWin = pGridWin[aViewData.GetActivePart()].get();
+
+ if ( pWin && aViewData.HasEditView( aViewData.GetActivePart() ) )
+ {
+ // flush OverlayManager before changing the MapMode
+ pWin->flushOverlayManager();
+
+ // make sure the EditView's position and size are updated
+ // with the right (logic, not drawing) MapMode
+ pWin->SetMapMode( aViewData.GetLogicMode() );
+ UpdateEditView();
+ }
+}
+
+void ScTabView::CheckNeedsRepaint()
+{
+ for (sal_uInt16 i = 0; i < 4; i++)
+ {
+ if (pGridWin[i] && pGridWin[i]->IsVisible())
+ pGridWin[i]->CheckNeedsRepaint();
+ }
+}
+
+bool ScTabView::NeedsRepaint()
+{
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ {
+ if (pWin && pWin->IsVisible() && pWin->NeedsRepaint())
+ return true;
+ }
+ return false;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabview4.cxx b/sc/source/ui/view/tabview4.cxx
new file mode 100644
index 000000000..5238947a8
--- /dev/null
+++ b/sc/source/ui/view/tabview4.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 <vcl/help.hxx>
+
+#include <tabview.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <docsh.hxx>
+#include <scmod.hxx>
+#include <gridwin.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <inputhdl.hxx>
+
+// --- Referenz-Eingabe / Fill-Cursor
+
+void ScTabView::HideTip()
+{
+ if ( nTipVisible )
+ {
+ ScSplitPos eWhich = aViewData.GetActivePart();
+ vcl::Window* pWin = pGridWin[eWhich];
+ Help::HidePopover(pWin, nTipVisible);
+ nTipVisible = nullptr;
+ aTipRectangle = tools::Rectangle();
+ nTipAlign = QuickHelpFlags::NONE;
+ sTipString.clear();
+ sTopParent.clear();
+ }
+}
+
+void ScTabView::ShowRefTip()
+{
+ bool bDone = false;
+ if ( aViewData.GetRefType() == SC_REFTYPE_REF && Help::IsQuickHelpEnabled() )
+ {
+ SCCOL nStartX = aViewData.GetRefStartX();
+ SCROW nStartY = aViewData.GetRefStartY();
+ SCCOL nEndX = aViewData.GetRefEndX();
+ SCROW nEndY = aViewData.GetRefEndY();
+ if ( nEndX != nStartX || nEndY != nStartY ) // not for a single cell
+ {
+ bool bLeft = ( nEndX < nStartX );
+ bool bTop = ( nEndY < nStartY );
+ PutInOrder( nStartX, nEndX );
+ PutInOrder( nStartY, nEndY );
+ SCCOL nCols = nEndX+1-nStartX;
+ SCROW nRows = nEndY+1-nStartY;
+
+ OUString aHelp = ScResId( STR_QUICKHELP_REF );
+ aHelp = aHelp.replaceFirst("%1", OUString::number(nRows) );
+ aHelp = aHelp.replaceFirst("%2", OUString::number(nCols) );
+
+ ScSplitPos eWhich = aViewData.GetActivePart();
+ vcl::Window* pWin = pGridWin[eWhich];
+ if ( pWin )
+ {
+ Point aStart = aViewData.GetScrPos( nStartX, nStartY, eWhich );
+ Point aEnd = aViewData.GetScrPos( nEndX+1, nEndY+1, eWhich );
+
+ Point aPos( bLeft ? aStart.X() : ( aEnd.X() + 3 ),
+ bTop ? aStart.Y() : ( aEnd.Y() + 3 ) );
+ QuickHelpFlags nFlags = ( bLeft ? QuickHelpFlags::Right : QuickHelpFlags::Left ) |
+ ( bTop ? QuickHelpFlags::Bottom : QuickHelpFlags::Top );
+
+ // not over the edited formula
+ if ( !bTop && aViewData.HasEditView( eWhich ) &&
+ nEndY+1 == aViewData.GetEditViewRow() )
+ {
+ // then align at the upper border of edited cell
+ aPos.AdjustY( -2 ); // the three from above
+ nFlags = ( nFlags & ~QuickHelpFlags::Top ) | QuickHelpFlags::Bottom;
+ }
+
+ tools::Rectangle aRect( pWin->OutputToScreenPixel( aPos ), Size(1,1) );
+
+ // Test if changed.
+ if (!nTipVisible || nFlags != nTipAlign || aRect != aTipRectangle || sTipString != aHelp || sTopParent != pWin)
+ {
+ HideTip();
+ nTipVisible = Help::ShowPopover(pWin, aRect, aHelp, nFlags);
+ aTipRectangle = aRect;
+ nTipAlign = nFlags;
+ sTipString = aHelp;
+ sTopParent = pWin;
+ }
+ bDone = true;
+ }
+ }
+ }
+
+ if (!bDone)
+ HideTip();
+}
+
+void ScTabView::StopRefMode()
+{
+ if (aViewData.IsRefMode())
+ {
+ aViewData.SetRefMode( false, SC_REFTYPE_NONE );
+
+ HideTip();
+ UpdateShrinkOverlay();
+
+ if ( aViewData.GetTabNo() >= aViewData.GetRefStartZ() &&
+ aViewData.GetTabNo() <= aViewData.GetRefEndZ() )
+ {
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCCOL nStartX = aViewData.GetRefStartX();
+ SCROW nStartY = aViewData.GetRefStartY();
+ SCCOL nEndX = aViewData.GetRefEndX();
+ SCROW nEndY = aViewData.GetRefEndY();
+ if ( nStartX == nEndX && nStartY == nEndY )
+ rDoc.ExtendMerge( nStartX, nStartY, nEndX, nEndY, aViewData.GetTabNo() );
+
+ PaintArea( nStartX,nStartY,nEndX,nEndY, ScUpdateMode::Marks );
+ }
+
+ pSelEngine->Reset();
+ pSelEngine->SetAddMode( false ); //! shouldn't that happen during reset?
+
+ ScSplitPos eOld = pSelEngine->GetWhich();
+ ScSplitPos eNew = aViewData.GetActivePart();
+ if ( eNew != eOld )
+ {
+ pSelEngine->SetWindow( pGridWin[ eNew ] );
+ pSelEngine->SetWhich( eNew );
+ pSelEngine->SetVisibleArea( tools::Rectangle(Point(),
+ pGridWin[eNew]->GetOutputSizePixel()) );
+ pGridWin[eOld]->MoveMouseStatus(*pGridWin[eNew]);
+ }
+ }
+
+ // AlignToCursor(SC_FOLLOW_NONE): Only switch active part.
+ // This must also be done if no RefMode was active (for RangeFinder dragging),
+ // but if RefMode was set, AlignToCursor must be after SelectionEngine reset,
+ // so the SelectionEngine SetWindow call from AlignToCursor doesn't capture
+ // the mouse again when called from Tracking/MouseButtonUp (#94562#).
+ AlignToCursor( aViewData.GetCurX(), aViewData.GetCurY(), SC_FOLLOW_NONE );
+}
+
+void ScTabView::DoneRefMode( bool bContinue )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ if ( aViewData.GetRefType() == SC_REFTYPE_REF && bContinue )
+ SC_MOD()->AddRefEntry();
+
+ bool bWasRef = aViewData.IsRefMode();
+ aViewData.SetRefMode( false, SC_REFTYPE_NONE );
+
+ HideTip();
+ UpdateShrinkOverlay();
+
+ // Paint:
+ if ( bWasRef && aViewData.GetTabNo() >= aViewData.GetRefStartZ() &&
+ aViewData.GetTabNo() <= aViewData.GetRefEndZ() )
+ {
+ SCCOL nStartX = aViewData.GetRefStartX();
+ SCROW nStartY = aViewData.GetRefStartY();
+ SCCOL nEndX = aViewData.GetRefEndX();
+ SCROW nEndY = aViewData.GetRefEndY();
+ if ( nStartX == nEndX && nStartY == nEndY )
+ rDoc.ExtendMerge( nStartX, nStartY, nEndX, nEndY, aViewData.GetTabNo() );
+
+ PaintArea( nStartX,nStartY,nEndX,nEndY, ScUpdateMode::Marks );
+ }
+}
+
+void ScTabView::UpdateRef( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+
+ if (!aViewData.IsRefMode())
+ {
+ // This will happen, when first at a reference dialog with Control in
+ // the table is clicked. Then append the new reference to the old content:
+
+ ScModule* pScMod = SC_MOD();
+ if (pScMod->IsFormulaMode())
+ pScMod->AddRefEntry();
+
+ InitRefMode( nCurX, nCurY, nCurZ, SC_REFTYPE_REF );
+ }
+
+ if ( nCurX != aViewData.GetRefEndX() || nCurY != aViewData.GetRefEndY() ||
+ nCurZ != aViewData.GetRefEndZ() )
+ {
+ ScMarkData& rMark = aViewData.GetMarkData();
+ SCTAB nTab = aViewData.GetTabNo();
+
+ SCCOL nStartX = aViewData.GetRefStartX();
+ SCROW nStartY = aViewData.GetRefStartY();
+ SCCOL nEndX = aViewData.GetRefEndX();
+ SCROW nEndY = aViewData.GetRefEndY();
+ if ( nStartX == nEndX && nStartY == nEndY )
+ rDoc.ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
+ ScUpdateRect aRect( nStartX, nStartY, nEndX, nEndY );
+
+ aViewData.SetRefEnd( nCurX, nCurY, nCurZ );
+
+ nStartX = aViewData.GetRefStartX();
+ nStartY = aViewData.GetRefStartY();
+ nEndX = aViewData.GetRefEndX();
+ nEndY = aViewData.GetRefEndY();
+ if ( nStartX == nEndX && nStartY == nEndY )
+ rDoc.ExtendMerge( nStartX, nStartY, nEndX, nEndY, nTab );
+ aRect.SetNew( nStartX, nStartY, nEndX, nEndY );
+
+ ScRefType eType = aViewData.GetRefType();
+ if ( eType == SC_REFTYPE_REF )
+ {
+ ScRange aRef(
+ aViewData.GetRefStartX(), aViewData.GetRefStartY(), aViewData.GetRefStartZ(),
+ aViewData.GetRefEndX(), aViewData.GetRefEndY(), aViewData.GetRefEndZ() );
+ SC_MOD()->SetReference( aRef, rDoc, &rMark );
+ ShowRefTip();
+ }
+ else if ( eType == SC_REFTYPE_EMBED_LT || eType == SC_REFTYPE_EMBED_RB )
+ {
+ PutInOrder(nStartX,nEndX);
+ PutInOrder(nStartY,nEndY);
+ rDoc.SetEmbedded( ScRange(nStartX,nStartY,nTab, nEndX,nEndY,nTab) );
+ ScDocShell* pDocSh = aViewData.GetDocShell();
+ pDocSh->UpdateOle( aViewData, true );
+ pDocSh->SetDocumentModified();
+ }
+
+ SCCOL nPaintStartX;
+ SCROW nPaintStartY;
+ SCCOL nPaintEndX;
+ SCROW nPaintEndY;
+ if (aRect.GetDiff( nPaintStartX, nPaintStartY, nPaintEndX, nPaintEndY ))
+ PaintArea( nPaintStartX, nPaintStartY, nPaintEndX, nPaintEndY, ScUpdateMode::Marks );
+
+ ScInputHandler* pInputHandler = SC_MOD()->GetInputHdl();
+ if (pInputHandler)
+ {
+ pInputHandler->UpdateLokReferenceMarks();
+ }
+ }
+
+ // autocomplete for Auto-Fill
+ if ( !(aViewData.GetRefType() == SC_REFTYPE_FILL && Help::IsQuickHelpEnabled()) )
+ return;
+
+ vcl::Window* pWin = GetActiveWin();
+ if ( !pWin )
+ return;
+
+ OUString aHelpStr;
+ ScRange aMarkRange;
+ aViewData.GetSimpleArea( aMarkRange );
+ SCCOL nEndX = aViewData.GetRefEndX();
+ SCROW nEndY = aViewData.GetRefEndY();
+ ScRange aDelRange;
+ if ( aViewData.GetFillMode() == ScFillMode::MATRIX && !(nScFillModeMouseModifier & KEY_MOD1) )
+ {
+ aHelpStr = ScResId( STR_TIP_RESIZEMATRIX );
+ SCCOL nCols = nEndX + 1 - aViewData.GetRefStartX(); // order is right
+ SCROW nRows = nEndY + 1 - aViewData.GetRefStartY();
+ aHelpStr = aHelpStr.replaceFirst("%1", OUString::number(nRows) );
+ aHelpStr = aHelpStr.replaceFirst("%2", OUString::number(nCols) );
+ }
+ else if ( aViewData.GetDelMark( aDelRange ) )
+ aHelpStr = ScResId( STR_QUICKHELP_DELETE );
+ else if ( nEndX != aMarkRange.aEnd.Col() || nEndY != aMarkRange.aEnd.Row() )
+ aHelpStr = rDoc.GetAutoFillPreview( aMarkRange, nEndX, nEndY );
+
+ if (!aHelpStr.getLength())
+ return;
+
+ // depending on direction the upper or lower corner
+ SCCOL nAddX = ( nEndX >= aMarkRange.aEnd.Col() ) ? 1 : 0;
+ SCROW nAddY = ( nEndY >= aMarkRange.aEnd.Row() ) ? 1 : 0;
+ Point aPos = aViewData.GetScrPos( nEndX+nAddX, nEndY+nAddY, aViewData.GetActivePart() );
+ aPos.AdjustX(8 );
+ aPos.AdjustY(4 );
+ aPos = pWin->OutputToScreenPixel( aPos );
+ tools::Rectangle aRect( aPos, aPos );
+ QuickHelpFlags nAlign = QuickHelpFlags::Left|QuickHelpFlags::Top;
+ if (!nTipVisible || nAlign != nTipAlign || aRect != aTipRectangle || sTipString != aHelpStr || sTopParent != pWin)
+ {
+ HideTip();
+ nTipVisible = Help::ShowPopover(pWin, aRect, aHelpStr, nAlign);
+ aTipRectangle = aRect;
+ nTipAlign = nAlign;
+ sTipString = aHelpStr;
+ sTopParent = pWin;
+ }
+}
+
+void ScTabView::InitRefMode( SCCOL nCurX, SCROW nCurY, SCTAB nCurZ, ScRefType eType )
+{
+ ScDocument& rDoc = aViewData.GetDocument();
+ ScMarkData& rMark = aViewData.GetMarkData();
+ if (aViewData.IsRefMode())
+ return;
+
+ aViewData.SetRefMode( true, eType );
+ aViewData.SetRefStart( nCurX, nCurY, nCurZ );
+ aViewData.SetRefEnd( nCurX, nCurY, nCurZ );
+
+ if (nCurZ == aViewData.GetTabNo())
+ {
+ SCCOL nStartX = nCurX;
+ SCROW nStartY = nCurY;
+ SCCOL nEndX = nCurX;
+ SCROW nEndY = nCurY;
+ rDoc.ExtendMerge( nStartX, nStartY, nEndX, nEndY, aViewData.GetTabNo() );
+
+ //! draw only markings over content!
+ PaintArea( nStartX,nStartY,nEndX,nEndY, ScUpdateMode::Marks );
+
+ // SetReference without Merge-Adjustment
+ ScRange aRef( nCurX,nCurY,nCurZ, nCurX,nCurY,nCurZ );
+ SC_MOD()->SetReference( aRef, rDoc, &rMark );
+ }
+
+ ScInputHandler* pInputHandler = SC_MOD()->GetInputHdl();
+ if (pInputHandler)
+ {
+ pInputHandler->UpdateLokReferenceMarks();
+ }
+}
+
+void ScTabView::SetScrollBar( ScrollBar& rScroll, tools::Long nRangeMax, tools::Long nVisible, tools::Long nPos, bool bLayoutRTL )
+{
+ if ( nVisible == 0 )
+ nVisible = 1; // #i59893# don't use visible size 0
+
+ rScroll.SetRange( Range( 0, nRangeMax ) );
+ rScroll.SetVisibleSize( nVisible );
+ rScroll.SetThumbPos( nPos );
+
+ rScroll.EnableRTL( bLayoutRTL );
+}
+
+tools::Long ScTabView::GetScrollBarPos( const ScrollBar& rScroll )
+{
+ return rScroll.GetThumbPos();
+}
+
+// UpdateScrollBars - set visible area and scroll width of scroll bars
+
+static tools::Long lcl_UpdateBar( ScrollBar& rScroll, SCCOLROW nSize ) // Size = (complete) cells
+{
+ tools::Long nOldPos;
+ tools::Long nNewPos;
+
+ nOldPos = rScroll.GetThumbPos();
+ rScroll.SetPageSize( static_cast<tools::Long>(nSize) );
+ nNewPos = rScroll.GetThumbPos();
+#ifndef UNX
+ rScroll.SetPageSize( 1 ); // always possible !
+#endif
+
+ return nNewPos - nOldPos;
+}
+
+static tools::Long lcl_GetScrollRange( SCCOLROW nDocEnd, SCCOLROW nPos, SCCOLROW nVis, SCCOLROW nMax, SCCOLROW nStart )
+{
+ // get the end (positive) of a scroll bar range that always starts at 0
+
+ ++nVis;
+ ++nMax; // for partially visible cells
+ SCCOLROW nEnd = std::max(nDocEnd, static_cast<SCCOLROW>(nPos+nVis)) + nVis;
+ if (nEnd > nMax)
+ nEnd = nMax;
+
+ return ( nEnd - nStart ); // for range starting at 0
+}
+
+void ScTabView::UpdateScrollBars( HeaderType eHeaderType )
+{
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), eHeaderType, GetViewData().GetTabNo());
+
+ tools::Long nDiff;
+ bool bTop = ( aViewData.GetVSplitMode() != SC_SPLIT_NONE );
+ bool bRight = ( aViewData.GetHSplitMode() != SC_SPLIT_NONE );
+ ScDocument& rDoc = aViewData.GetDocument();
+ SCTAB nTab = aViewData.GetTabNo();
+ bool bLayoutRTL = rDoc.IsLayoutRTL( nTab );
+ SCCOL nUsedX;
+ SCROW nUsedY;
+ rDoc.GetTableArea( nTab, nUsedX, nUsedY ); //! cached !!!!!!!!!!!!!!!
+
+ SCCOL nVisXL = 0;
+ SCCOL nVisXR = 0;
+ SCROW nVisYB = 0;
+ SCROW nVisYT = 0;
+
+ SCCOL nStartX = 0;
+ SCROW nStartY = 0;
+ if (aViewData.GetHSplitMode()==SC_SPLIT_FIX)
+ nStartX = aViewData.GetFixPosX();
+ if (aViewData.GetVSplitMode()==SC_SPLIT_FIX)
+ nStartY = aViewData.GetFixPosY();
+
+ nVisXL = aViewData.VisibleCellsX( SC_SPLIT_LEFT );
+ tools::Long nMaxXL = lcl_GetScrollRange( nUsedX, aViewData.GetPosX(SC_SPLIT_LEFT), nVisXL, rDoc.MaxCol(), 0 );
+ SetScrollBar( *aHScrollLeft, nMaxXL, nVisXL, aViewData.GetPosX( SC_SPLIT_LEFT ), bLayoutRTL );
+
+ nVisYB = aViewData.VisibleCellsY( SC_SPLIT_BOTTOM );
+ tools::Long nMaxYB = lcl_GetScrollRange( nUsedY, aViewData.GetPosY(SC_SPLIT_BOTTOM), nVisYB, rDoc.MaxRow(), nStartY );
+ SetScrollBar( *aVScrollBottom, nMaxYB, nVisYB, aViewData.GetPosY( SC_SPLIT_BOTTOM ) - nStartY, bLayoutRTL );
+
+ if (bRight)
+ {
+ nVisXR = aViewData.VisibleCellsX( SC_SPLIT_RIGHT );
+ tools::Long nMaxXR = lcl_GetScrollRange( nUsedX, aViewData.GetPosX(SC_SPLIT_RIGHT), nVisXR, rDoc.MaxCol(), nStartX );
+ SetScrollBar( *aHScrollRight, nMaxXR, nVisXR, aViewData.GetPosX( SC_SPLIT_RIGHT ) - nStartX, bLayoutRTL );
+ }
+
+ if (bTop)
+ {
+ nVisYT = aViewData.VisibleCellsY( SC_SPLIT_TOP );
+ tools::Long nMaxYT = lcl_GetScrollRange( nUsedY, aViewData.GetPosY(SC_SPLIT_TOP), nVisYT, rDoc.MaxRow(), 0 );
+ SetScrollBar( *aVScrollTop, nMaxYT, nVisYT, aViewData.GetPosY( SC_SPLIT_TOP ), bLayoutRTL );
+ }
+
+ // test the range
+
+ nDiff = lcl_UpdateBar( *aHScrollLeft, nVisXL );
+ if (nDiff) ScrollX( nDiff, SC_SPLIT_LEFT );
+ if (bRight)
+ {
+ nDiff = lcl_UpdateBar( *aHScrollRight, nVisXR );
+ if (nDiff) ScrollX( nDiff, SC_SPLIT_RIGHT );
+ }
+
+ nDiff = lcl_UpdateBar( *aVScrollBottom, nVisYB );
+ if (nDiff) ScrollY( nDiff, SC_SPLIT_BOTTOM );
+ if (bTop)
+ {
+ nDiff = lcl_UpdateBar( *aVScrollTop, nVisYT );
+ if (nDiff) ScrollY( nDiff, SC_SPLIT_TOP );
+ }
+
+ // set visible area for online spelling
+
+ if ( aViewData.IsActive() )
+ {
+ if (UpdateVisibleRange())
+ SC_MOD()->AnythingChanged(); // if visible area has changed
+ }
+}
+
+#ifndef HDR_SLIDERSIZE
+#define HDR_SLIDERSIZE 2
+#endif
+
+void ScTabView::InvertHorizontal( ScVSplitPos eWhich, tools::Long nDragPos )
+{
+ for (sal_uInt16 i=0; i<4; i++)
+ if (WhichV(static_cast<ScSplitPos>(i))==eWhich)
+ {
+ ScGridWindow* pWin = pGridWin[i].get();
+ if (pWin)
+ {
+ tools::Rectangle aRect( 0,nDragPos, pWin->GetOutputSizePixel().Width()-1,nDragPos+HDR_SLIDERSIZE-1 );
+ pWin->PaintImmediately();
+ pWin->DoInvertRect( aRect ); // Pixel
+ }
+ }
+}
+
+void ScTabView::InvertVertical( ScHSplitPos eWhich, tools::Long nDragPos )
+{
+ for (sal_uInt16 i=0; i<4; i++)
+ if (WhichH(static_cast<ScSplitPos>(i))==eWhich)
+ {
+ ScGridWindow* pWin = pGridWin[i].get();
+ if (pWin)
+ {
+ tools::Rectangle aRect( nDragPos,0, nDragPos+HDR_SLIDERSIZE-1,pWin->GetOutputSizePixel().Height()-1 );
+ pWin->PaintImmediately();
+ pWin->DoInvertRect( aRect ); // Pixel
+ }
+ }
+}
+
+void ScTabView::InterpretVisible()
+{
+ // make sure all visible cells are interpreted,
+ // so the next paint will not execute a macro function
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ if ( !rDoc.GetAutoCalc() )
+ return;
+
+ SCTAB nTab = aViewData.GetTabNo();
+ for (sal_uInt16 i=0; i<4; i++)
+ {
+ // rely on gridwin pointers to find used panes
+ // no IsVisible test in case the whole view is not yet shown
+
+ if (pGridWin[i])
+ {
+ ScHSplitPos eHWhich = WhichH( ScSplitPos(i) );
+ ScVSplitPos eVWhich = WhichV( ScSplitPos(i) );
+
+ SCCOL nX1 = rDoc.SanitizeCol( aViewData.GetPosX( eHWhich ));
+ SCROW nY1 = rDoc.SanitizeRow( aViewData.GetPosY( eVWhich ));
+ SCCOL nX2 = rDoc.SanitizeCol( nX1 + aViewData.VisibleCellsX( eHWhich ));
+ SCROW nY2 = rDoc.SanitizeRow( nY1 + aViewData.VisibleCellsY( eVWhich ));
+
+ rDoc.InterpretDirtyCells(ScRange(nX1, nY1, nTab, nX2, nY2, nTab));
+ }
+ }
+
+ // #i65047# repaint during the above loop may have set the bNeedsRepaint flag
+ CheckNeedsRepaint();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabview5.cxx b/sc/source/ui/view/tabview5.cxx
new file mode 100644
index 000000000..6db05da9c
--- /dev/null
+++ b/sc/source/ui/view/tabview5.cxx
@@ -0,0 +1,708 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/fmshell.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdocapt.hxx>
+#include <svx/svdoutl.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <osl/diagnose.h>
+
+#include <tabview.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <gridwin.hxx>
+#include <olinewin.hxx>
+#include <tabsplit.hxx>
+#include <colrowba.hxx>
+#include <tabcont.hxx>
+#include <sc.hrc>
+#include <pagedata.hxx>
+#include <hiranges.hxx>
+#include <drawview.hxx>
+#include <drwlayer.hxx>
+#include <fusel.hxx>
+#include <seltrans.hxx>
+#include <scmod.hxx>
+#include <docsh.hxx>
+#include <viewuno.hxx>
+#include <postit.hxx>
+#include <spellcheckcontext.hxx>
+
+#include <vcl/settings.hxx>
+
+#include <comphelper/lok.hxx>
+#include <officecfg/Office/Calc.hxx>
+
+using namespace com::sun::star;
+
+void ScTabView::Init()
+{
+ /* RTL layout of the view windows is done manually, because it depends on
+ the sheet orientation, not the UI setting. Note: controls that are
+ already constructed (e.g. scroll bars) have the RTL setting of the GUI.
+ Eventually this has to be disabled manually (see below). */
+ pFrameWin->EnableRTL( false );
+
+ sal_uInt16 i;
+
+ mbInlineWithScrollbar = officecfg::Office::Calc::Layout::Other::TabbarInlineWithScrollbar::get();
+
+ aScrollTimer.SetTimeout(10);
+ aScrollTimer.SetInvokeHandler( LINK( this, ScTabView, TimerHdl ) );
+
+ for (i=0; i<4; i++)
+ pGridWin[i] = nullptr;
+ pGridWin[SC_SPLIT_BOTTOMLEFT] = VclPtr<ScGridWindow>::Create( pFrameWin, aViewData, SC_SPLIT_BOTTOMLEFT );
+
+ pSelEngine.reset( new ScViewSelectionEngine( pGridWin[SC_SPLIT_BOTTOMLEFT], this,
+ SC_SPLIT_BOTTOMLEFT ) );
+ aFunctionSet.SetSelectionEngine( pSelEngine.get() );
+
+ pHdrSelEng.reset( new ScHeaderSelectionEngine( pFrameWin, &aHdrFunc ) );
+
+ pColBar[SC_SPLIT_LEFT] = VclPtr<ScColBar>::Create( pFrameWin, SC_SPLIT_LEFT,
+ &aHdrFunc, pHdrSelEng.get(), this );
+ pColBar[SC_SPLIT_RIGHT] = nullptr;
+ pRowBar[SC_SPLIT_BOTTOM] = VclPtr<ScRowBar>::Create( pFrameWin, SC_SPLIT_BOTTOM,
+ &aHdrFunc, pHdrSelEng.get(), this );
+ pRowBar[SC_SPLIT_TOP] = nullptr;
+ for (i=0; i<2; i++)
+ pColOutline[i] = pRowOutline[i] = nullptr;
+
+ pHSplitter = VclPtr<ScTabSplitter>::Create( pFrameWin, WinBits( WB_HSCROLL ), &aViewData );
+ pVSplitter = VclPtr<ScTabSplitter>::Create( pFrameWin, WinBits( WB_VSCROLL ), &aViewData );
+
+ // SSA: override default keyboard step size to allow snap to row/column
+ pHSplitter->SetKeyboardStepSize( 1 );
+ pVSplitter->SetKeyboardStepSize( 1 );
+
+ pTabControl = VclPtr<ScTabControl>::Create(pFrameWin, &aViewData);
+ if (mbInlineWithScrollbar)
+ pTabControl->SetStyle(pTabControl->GetStyle() | WB_SIZEABLE);
+
+ /* #i97900# The tab control has to remain in RTL mode if GUI is RTL, this
+ is needed to draw the 3D effect correctly. The base TabBar implements
+ mirroring independent from the GUI direction. Have to set RTL mode
+ explicitly because the parent frame window is already RTL disabled. */
+ pTabControl->EnableRTL( AllSettings::GetLayoutRTL() );
+
+ InitScrollBar( *aHScrollLeft, aViewData.GetDocument().MaxCol()+1 );
+ InitScrollBar( *aHScrollRight, aViewData.GetDocument().MaxCol()+1 );
+ InitScrollBar( *aVScrollTop, aViewData.GetDocument().MaxRow()+1 );
+ InitScrollBar( *aVScrollBottom, aViewData.GetDocument().MaxRow()+1 );
+ /* #i97900# scrollbars remain in correct RTL mode, needed mirroring etc.
+ is now handled correctly at the respective places. */
+
+ // Don't show anything here, because still in wrong order
+ // Show is received from UpdateShow during first resize
+ // pTabControl, pGridWin, aHScrollLeft, aVScrollBottom,
+ // aCornerButton, aScrollBarBox, pHSplitter, pVSplitter
+
+ // fragment
+
+ pHSplitter->SetSplitHdl( LINK( this, ScTabView, SplitHdl ) );
+ pVSplitter->SetSplitHdl( LINK( this, ScTabView, SplitHdl ) );
+
+ // UpdateShow is done during resize or a copy of an existing view from ctor
+
+ pDrawActual = nullptr;
+ pDrawOld = nullptr;
+
+ // DrawView cannot be create in the TabView - ctor
+ // when the ViewShell isn't constructed yet...
+ // The also applies to ViewOptionsHasChanged()
+
+ TestHintWindow();
+}
+
+ScTabView::~ScTabView()
+{
+ sal_uInt16 i;
+
+ // remove selection object
+ ScModule* pScMod = SC_MOD();
+ ScSelectionTransferObj* pOld = pScMod->GetSelectionTransfer();
+ if ( pOld && pOld->GetView() == this )
+ {
+ pOld->ForgetView();
+ pScMod->SetSelectionTransfer( nullptr );
+ TransferableHelper::ClearPrimarySelection(); // may delete pOld
+ }
+
+ pBrushDocument.reset();
+ pDrawBrushSet.reset();
+
+ pPageBreakData.reset();
+
+ delete pDrawActual;
+ pDrawActual = nullptr;
+ delete pDrawOld;
+ pDrawOld = nullptr;
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell* pThisViewShell = GetViewData().GetViewShell();
+
+ auto lRemoveWindows =
+ [pThisViewShell] (ScTabViewShell* pOtherViewShell)
+ {
+ ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
+ for (int k = 0; k < 4; ++k)
+ {
+ if (rOtherViewData.HasEditView(static_cast<ScSplitPos>(k)))
+ pThisViewShell->RemoveWindowFromForeignEditView(pOtherViewShell, static_cast<ScSplitPos>(k));
+ }
+ };
+
+ SfxLokHelper::forEachOtherView(pThisViewShell, lRemoveWindows);
+ }
+
+ aViewData.KillEditView(); // as long as GridWins still exist
+
+ if (pDrawView)
+ {
+ for (i=0; i<4; i++)
+ if (pGridWin[i])
+ {
+ pDrawView->DeleteWindowFromPaintView(pGridWin[i]->GetOutDev());
+ }
+
+ pDrawView->HideSdrPage();
+ pDrawView.reset();
+ }
+
+ pSelEngine.reset();
+
+ if (mpSpellCheckCxt)
+ mpSpellCheckCxt->dispose();
+ mpSpellCheckCxt.reset();
+
+ mxInputHintOO.reset();
+ for (i=0; i<4; i++)
+ pGridWin[i].disposeAndClear();
+
+ pHdrSelEng.reset();
+
+ for (i=0; i<2; i++)
+ {
+ pColBar[i].disposeAndClear();
+ pRowBar[i].disposeAndClear();
+ pColOutline[i].disposeAndClear();
+ pRowOutline[i].disposeAndClear();
+ }
+
+ aScrollBarBox.disposeAndClear();
+ aCornerButton.disposeAndClear();
+ aTopButton.disposeAndClear();
+ aHScrollLeft.disposeAndClear();
+ aHScrollRight.disposeAndClear();
+ aVScrollTop.disposeAndClear();
+ aVScrollBottom.disposeAndClear();
+
+ pHSplitter.disposeAndClear();
+ pVSplitter.disposeAndClear();
+ pTabControl.disposeAndClear();
+}
+
+void ScTabView::MakeDrawView( TriState nForceDesignMode )
+{
+ if (pDrawView)
+ return;
+
+ ScDrawLayer* pLayer = aViewData.GetDocument().GetDrawLayer();
+ OSL_ENSURE(pLayer, "Where is the Draw Layer ??");
+
+ sal_uInt16 i;
+ pDrawView.reset( new ScDrawView( pGridWin[SC_SPLIT_BOTTOMLEFT]->GetOutDev(), &aViewData ) );
+ for (i=0; i<4; i++)
+ if (pGridWin[i])
+ {
+ if ( SC_SPLIT_BOTTOMLEFT != static_cast<ScSplitPos>(i) )
+ pDrawView->AddWindowToPaintView(pGridWin[i]->GetOutDev(), nullptr);
+ }
+ pDrawView->RecalcScale();
+ for (i=0; i<4; i++)
+ if (pGridWin[i])
+ {
+ pGridWin[i]->SetMapMode(pGridWin[i]->GetDrawMapMode());
+
+ pGridWin[i]->PaintImmediately(); // because of Invalidate in DrawView ctor (ShowPage),
+ // so that immediately can be drawn
+ }
+ SfxRequest aSfxRequest(SID_OBJECT_SELECT, SfxCallMode::SLOT, aViewData.GetViewShell()->GetPool());
+ SetDrawFuncPtr(new FuSelection(*aViewData.GetViewShell(), GetActiveWin(), pDrawView.get(),
+ pLayer,aSfxRequest));
+
+ // used when switching back from page preview: restore saved design mode state
+ // (otherwise, keep the default from the draw view ctor)
+ if ( nForceDesignMode != TRISTATE_INDET )
+ pDrawView->SetDesignMode( nForceDesignMode != TRISTATE_FALSE );
+
+ // register at FormShell
+ FmFormShell* pFormSh = aViewData.GetViewShell()->GetFormShell();
+ if (pFormSh)
+ pFormSh->SetView(pDrawView.get());
+
+ if (aViewData.GetViewShell()->HasAccessibilityObjects())
+ aViewData.GetViewShell()->BroadcastAccessibility(SfxHint(SfxHintId::ScAccMakeDrawLayer));
+}
+
+void ScTabView::DoAddWin( ScGridWindow* pWin )
+{
+ if (pDrawView)
+ {
+ pDrawView->AddWindowToPaintView(pWin->GetOutDev(), nullptr);
+ pWin->DrawLayerCreated();
+ }
+ pWin->SetAutoSpellContext(mpSpellCheckCxt);
+}
+
+void ScTabView::TabChanged( bool bSameTabButMoved )
+{
+ if (pDrawView)
+ {
+ DrawDeselectAll(); // end also text edit mode
+
+ SCTAB nTab = aViewData.GetTabNo();
+ pDrawView->HideSdrPage();
+ pDrawView->ShowSdrPage(pDrawView->GetModel()->GetPage(nTab));
+
+ UpdateLayerLocks();
+
+ pDrawView->RecalcScale();
+ pDrawView->UpdateWorkArea(); // PageSize is different per page
+ }
+
+ SfxBindings& rBindings = aViewData.GetBindings();
+
+ // There is no easy way to invalidate all slots of the FormShell
+ // (for disabled slots on protected tables), therefore simply everything...
+ rBindings.InvalidateAll(false);
+
+ if (aViewData.GetViewShell()->HasAccessibilityObjects())
+ {
+ SfxHint aAccHint(SfxHintId::ScAccTableChanged);
+ aViewData.GetViewShell()->BroadcastAccessibility(aAccHint);
+ }
+
+ // notification for XActivationBroadcaster
+ SfxViewFrame* pViewFrame = aViewData.GetViewShell()->GetViewFrame();
+ if (pViewFrame)
+ {
+ uno::Reference<frame::XController> xController = pViewFrame->GetFrame().GetController();
+ if (xController.is())
+ {
+ ScTabViewObj* pImp = comphelper::getFromUnoTunnel<ScTabViewObj>( xController );
+ if (pImp)
+ pImp->SheetChanged( bSameTabButMoved );
+ }
+ }
+
+ for (int i = 0; i < 4; i++)
+ {
+ if (pGridWin[i])
+ {
+ pGridWin[i]->initiatePageBreaks();
+ // Trigger calculating page breaks only once.
+ break;
+ }
+ }
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScModelObj* pModelObj = pDocSh ? comphelper::getFromUnoTunnel<ScModelObj>( pDocSh->GetModel()) : nullptr;
+
+ if (!pModelObj)
+ return;
+
+ Size aDocSize = pModelObj->getDocumentSize();
+ std::stringstream ss;
+ ss << aDocSize.Width() << ", " << aDocSize.Height();
+ OString sRect = ss.str().c_str();
+ ScTabViewShell* pViewShell = aViewData.GetViewShell();
+
+ // Invalidate first
+ tools::Rectangle aRectangle(0, 0, 1000000000, 1000000000);
+ pViewShell->libreOfficeKitViewInvalidateTilesCallback(&aRectangle, aViewData.GetTabNo());
+
+ ScModelObj* pModel = comphelper::getFromUnoTunnel<ScModelObj>(pViewShell->GetCurrentDocument());
+ SfxLokHelper::notifyDocumentSizeChanged(pViewShell, sRect, pModel, false);
+}
+
+void ScTabView::UpdateLayerLocks()
+{
+ if (!pDrawView)
+ return;
+
+ SCTAB nTab = aViewData.GetTabNo();
+ bool bEx = aViewData.GetViewShell()->IsDrawSelMode();
+ bool bProt = aViewData.GetDocument().IsTabProtected( nTab ) ||
+ aViewData.GetSfxDocShell()->IsReadOnly();
+ bool bShared = aViewData.GetDocShell()->IsDocShared();
+
+ SdrLayer* pLayer;
+ SdrLayerAdmin& rAdmin = pDrawView->GetModel()->GetLayerAdmin();
+ pLayer = rAdmin.GetLayerPerID(SC_LAYER_BACK);
+ if (pLayer)
+ pDrawView->SetLayerLocked( pLayer->GetName(), bProt || !bEx || bShared );
+ pLayer = rAdmin.GetLayerPerID(SC_LAYER_INTERN);
+ if (pLayer)
+ pDrawView->SetLayerLocked( pLayer->GetName() );
+ pLayer = rAdmin.GetLayerPerID(SC_LAYER_FRONT);
+ if (pLayer)
+ pDrawView->SetLayerLocked( pLayer->GetName(), bProt || bShared );
+ pLayer = rAdmin.GetLayerPerID(SC_LAYER_CONTROLS);
+ if (pLayer)
+ pDrawView->SetLayerLocked( pLayer->GetName(), bProt || bShared );
+ pLayer = rAdmin.GetLayerPerID(SC_LAYER_HIDDEN);
+ if (pLayer)
+ {
+ pDrawView->SetLayerLocked( pLayer->GetName(), bProt || bShared );
+ pDrawView->SetLayerVisible( pLayer->GetName(), false);
+ }
+ pTabControl->SetAddButtonEnabled(aViewData.GetDocument().IsDocEditable());
+}
+
+void ScTabView::DrawDeselectAll()
+{
+ if (!pDrawView)
+ return;
+
+ ScTabViewShell* pViewSh = aViewData.GetViewShell();
+ if ( pDrawActual &&
+ ( pViewSh->IsDrawTextShell() || pDrawActual->GetSlotID() == SID_DRAW_NOTEEDIT ) )
+ {
+ // end text edit (as if escape pressed, in FuDraw)
+ aViewData.GetDispatcher().Execute( pDrawActual->GetSlotID(),
+ SfxCallMode::SLOT | SfxCallMode::RECORD );
+ }
+
+ pDrawView->ScEndTextEdit();
+ pDrawView->UnmarkAll();
+
+ if (!pViewSh->IsDrawSelMode())
+ pViewSh->SetDrawShell( false );
+}
+
+bool ScTabView::IsDrawTextEdit() const
+{
+ if (pDrawView)
+ return pDrawView->IsTextEdit();
+ else
+ return false;
+}
+
+SvxZoomType ScTabView::GetZoomType() const
+{
+ return aViewData.GetZoomType();
+}
+
+void ScTabView::SetZoomType( SvxZoomType eNew, bool bAll )
+{
+ aViewData.SetZoomType( eNew, bAll );
+}
+
+void ScTabView::SetZoom( const Fraction& rNewX, const Fraction& rNewY, bool bAll )
+{
+ aViewData.SetZoom( rNewX, rNewY, bAll );
+ if (pDrawView)
+ pDrawView->RecalcScale();
+ ZoomChanged();
+}
+
+void ScTabView::RefreshZoom()
+{
+ aViewData.RefreshZoom();
+ if (pDrawView)
+ pDrawView->RecalcScale();
+ ZoomChanged();
+}
+
+void ScTabView::SetPagebreakMode( bool bSet )
+{
+ aViewData.SetPagebreakMode(bSet);
+ if (pDrawView)
+ pDrawView->RecalcScale();
+ ZoomChanged();
+}
+
+void ScTabView::ResetDrawDragMode()
+{
+ if (pDrawView)
+ pDrawView->SetDragMode( SdrDragMode::Move );
+}
+
+void ScTabView::ViewOptionsHasChanged( bool bHScrollChanged, bool bGraphicsChanged )
+{
+ // create DrawView when grid should be displayed
+ if ( !pDrawView && aViewData.GetOptions().GetGridOptions().GetGridVisible() )
+ MakeDrawLayer();
+
+ if (pDrawView)
+ pDrawView->UpdateUserViewOptions();
+
+ if (bGraphicsChanged)
+ DrawEnableAnim(true); // DrawEnableAnim checks the options state
+
+ // if TabBar is set to visible, make sure its size is not 0
+ bool bGrow = ( aViewData.IsTabMode() && pTabControl->GetSizePixel().Width() <= 0 );
+
+ // if ScrollBar is set to visible, TabBar must make room
+ bool bShrink = ( bHScrollChanged && aViewData.IsTabMode() && aViewData.IsHScrollMode() &&
+ pTabControl->GetSizePixel().Width() > SC_TABBAR_DEFWIDTH );
+
+ if ( bGrow || bShrink )
+ {
+ Size aSize = pTabControl->GetSizePixel();
+ aSize.setWidth( SC_TABBAR_DEFWIDTH ); // initial size
+ pTabControl->SetSizePixel(aSize); // DoResize is called later...
+ }
+}
+
+// helper function against including the drawing layer
+
+void ScTabView::DrawMarkListHasChanged()
+{
+ if ( pDrawView )
+ pDrawView->MarkListHasChanged();
+}
+
+void ScTabView::UpdateAnchorHandles()
+{
+ if ( pDrawView )
+ pDrawView->AdjustMarkHdl();
+}
+
+void ScTabView::UpdateIMap( SdrObject* pObj )
+{
+ if ( pDrawView )
+ pDrawView->UpdateIMap( pObj );
+}
+
+void ScTabView::DrawEnableAnim(bool bSet)
+{
+ sal_uInt16 i;
+ if ( !pDrawView )
+ return;
+
+ // don't start animations if display of graphics is disabled
+ // graphics are controlled by VOBJ_TYPE_OLE
+ if ( bSet && aViewData.GetOptions().GetObjMode(VOBJ_TYPE_OLE) == VOBJ_MODE_SHOW )
+ {
+ if ( !pDrawView->IsAnimationEnabled() )
+ {
+ pDrawView->SetAnimationEnabled();
+
+ // animated GIFs must be restarted:
+ ScDocument& rDoc = aViewData.GetDocument();
+ for (i=0; i<4; i++)
+ if ( pGridWin[i] && pGridWin[i]->IsVisible() )
+ rDoc.StartAnimations( aViewData.GetTabNo() );
+ }
+ }
+ else
+ {
+ pDrawView->SetAnimationEnabled(false);
+ }
+}
+
+void ScTabView::UpdateDrawTextOutliner()
+{
+ if ( pDrawView )
+ {
+ Outliner* pOL = pDrawView->GetTextEditOutliner();
+ if (pOL)
+ aViewData.UpdateOutlinerFlags( *pOL );
+ }
+}
+
+void ScTabView::DigitLanguageChanged()
+{
+ LanguageType eNewLang = SC_MOD()->GetOptDigitLanguage();
+ for (VclPtr<ScGridWindow> & pWin : pGridWin)
+ if ( pWin )
+ pWin->GetOutDev()->SetDigitLanguage( eNewLang );
+}
+
+void ScTabView::ScrollToObject( const SdrObject* pDrawObj )
+{
+ if ( pDrawObj )
+ {
+ // #i118524# use the BoundRect, this defines the visible area
+ MakeVisible(pDrawObj->GetCurrentBoundRect());
+ }
+}
+
+void ScTabView::MakeVisible( const tools::Rectangle& rHMMRect )
+{
+ vcl::Window* pWin = GetActiveWin();
+ Size aWinSize = pWin->GetOutputSizePixel();
+ SCTAB nTab = aViewData.GetTabNo();
+
+ tools::Rectangle aRect = pWin->LogicToPixel( rHMMRect );
+
+ tools::Long nScrollX=0, nScrollY=0; // pixel
+
+ if ( aRect.Right() >= aWinSize.Width() ) // right out
+ {
+ nScrollX = aRect.Right() - aWinSize.Width() + 1; // right border visible
+ if ( aRect.Left() < nScrollX )
+ nScrollX = aRect.Left(); // left visible (if too big)
+ }
+ if ( aRect.Bottom() >= aWinSize.Height() ) // bottom out
+ {
+ nScrollY = aRect.Bottom() - aWinSize.Height() + 1; // bottom border visible
+ if ( aRect.Top() < nScrollY )
+ nScrollY = aRect.Top(); // top visible (if too big)
+ }
+
+ if ( aRect.Left() < 0 ) // left out
+ nScrollX = aRect.Left(); // left border visible
+ if ( aRect.Top() < 0 ) // top out
+ nScrollY = aRect.Top(); // top border visible
+
+ if (!(nScrollX || nScrollY))
+ return;
+
+ ScDocument& rDoc = aViewData.GetDocument();
+ if ( rDoc.IsNegativePage( nTab ) )
+ nScrollX = -nScrollX;
+
+ double nPPTX = aViewData.GetPPTX();
+ double nPPTY = aViewData.GetPPTY();
+ ScSplitPos eWhich = aViewData.GetActivePart();
+ SCCOL nPosX = aViewData.GetPosX(WhichH(eWhich));
+ SCROW nPosY = aViewData.GetPosY(WhichV(eWhich));
+
+ tools::Long nLinesX=0, nLinesY=0; // columns/rows - scroll at least nScrollX/Y
+
+ if (nScrollX > 0)
+ while (nScrollX > 0 && nPosX < rDoc.MaxCol())
+ {
+ nScrollX -= static_cast<tools::Long>( rDoc.GetColWidth(nPosX, nTab) * nPPTX );
+ ++nPosX;
+ ++nLinesX;
+ }
+ else if (nScrollX < 0)
+ while (nScrollX < 0 && nPosX > 0)
+ {
+ --nPosX;
+ nScrollX += static_cast<tools::Long>( rDoc.GetColWidth(nPosX, nTab) * nPPTX );
+ --nLinesX;
+ }
+
+ if (nScrollY > 0)
+ while (nScrollY > 0 && nPosY < rDoc.MaxRow())
+ {
+ nScrollY -= static_cast<tools::Long>( rDoc.GetRowHeight(nPosY, nTab) * nPPTY );
+ ++nPosY;
+ ++nLinesY;
+ }
+ else if (nScrollY < 0)
+ while (nScrollY < 0 && nPosY > 0)
+ {
+ --nPosY;
+ nScrollY += static_cast<tools::Long>( rDoc.GetRowHeight(nPosY, nTab) * nPPTY );
+ --nLinesY;
+ }
+
+ ScrollLines( nLinesX, nLinesY ); // execute
+}
+
+void ScTabView::SetBrushDocument( ScDocumentUniquePtr pNew, bool bLock )
+{
+ pDrawBrushSet.reset();
+ pBrushDocument = std::move(pNew);
+
+ bLockPaintBrush = bLock;
+
+ aViewData.GetBindings().Invalidate(SID_FORMATPAINTBRUSH);
+}
+
+void ScTabView::SetDrawBrushSet( std::unique_ptr<SfxItemSet> pNew, bool bLock )
+{
+ pBrushDocument.reset();
+ pDrawBrushSet = std::move(pNew);
+
+ bLockPaintBrush = bLock;
+
+ aViewData.GetBindings().Invalidate(SID_FORMATPAINTBRUSH);
+}
+
+void ScTabView::ResetBrushDocument()
+{
+ if ( HasPaintBrush() )
+ {
+ SetBrushDocument( nullptr, false );
+ SetActivePointer( aViewData.IsThemedCursor() ? PointerStyle::FatCross : PointerStyle::Arrow ); // switch pointers also when ended with escape key
+ }
+}
+
+void ScTabView::OnLOKNoteStateChanged(const ScPostIt* pNote)
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ const SdrCaptionObj* pCaption = pNote->GetCaption();
+ if (!pCaption) return;
+
+ tools::Rectangle aRect = pCaption->GetLogicRect();
+ basegfx::B2DRange aTailRange = pCaption->getTailPolygon().getB2DRange();
+ tools::Rectangle aTailRect(aTailRange.getMinX(), aTailRange.getMinY(),
+ aTailRange.getMaxX(), aTailRange.getMaxY());
+ aRect.Union( aTailRect );
+
+ // This is a temporary workaround: sometime in tiled rendering mode
+ // the tip of the note arrow is misplaced by a fixed offset.
+ // The value used below is enough to get the tile, where the arrow tip is
+ // placed, invalidated.
+ const int nBorderSize = 200;
+ tools::Rectangle aInvalidRect = aRect;
+ aInvalidRect.AdjustLeft( -nBorderSize );
+ aInvalidRect.AdjustRight( nBorderSize );
+ aInvalidRect.AdjustTop( -nBorderSize );
+ aInvalidRect.AdjustBottom( nBorderSize );
+
+ SfxViewShell* pCurrentViewShell = SfxViewShell::Current();
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pTabViewShell && pViewShell->GetDocId() == pCurrentViewShell->GetDocId())
+ {
+ for (auto& pWin: pTabViewShell->pGridWin)
+ {
+ if (pWin && pWin->IsVisible())
+ {
+ pWin->Invalidate(aInvalidRect);
+ }
+ }
+ }
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwsh.cxx b/sc/source/ui/view/tabvwsh.cxx
new file mode 100644
index 000000000..669c7554f
--- /dev/null
+++ b/sc/source/ui/view/tabvwsh.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 <svx/imapdlg.hxx>
+#include <svx/srchdlg.hxx>
+#include <sfx2/objface.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/infobar.hxx>
+#include <sfx2/sidebar/SidebarChildWindow.hxx>
+#include <sfx2/devtools/DevelopmentToolChildWindow.hxx>
+#include <sfx2/viewfac.hxx>
+
+#include <cellvalue.hxx>
+
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <reffact.hxx>
+#include <sc.hrc>
+#include <spelldialog.hxx>
+#include <formulacell.hxx>
+#include <searchresults.hxx>
+
+ // needed for -fsanitize=function visibility of typeinfo for functions of
+ // type void(SfxShell*,SfxRequest&) defined in scslots.hxx
+#define ShellClass_ScTabViewShell
+#include <scslots.hxx>
+
+
+SFX_IMPL_INTERFACE(ScTabViewShell, SfxViewShell)
+
+void ScTabViewShell::InitInterface_Impl()
+{
+ GetStaticInterface()->RegisterObjectBar(SFX_OBJECTBAR_TOOLS,
+ SfxVisibilityFlags::Standard | SfxVisibilityFlags::FullScreen | SfxVisibilityFlags::Server,
+ ToolbarId::Objectbar_Tools);
+
+ GetStaticInterface()->RegisterChildWindow(FID_INPUTLINE_STATUS);
+ GetStaticInterface()->RegisterChildWindow(SfxInfoBarContainerChild::GetChildWindowId());
+
+ GetStaticInterface()->RegisterChildWindow(SID_NAVIGATOR, true);
+
+ GetStaticInterface()->RegisterChildWindow(::sfx2::sidebar::SidebarChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(DevelopmentToolChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScNameDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScNameDefDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScSolverDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScOptSolverDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScXMLSourceDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScPivotLayoutWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScTabOpDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScFilterDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScSpecialFilterDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScDbNameDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScConsolidateDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScPrintAreasDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScColRowNameRangesDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScFormulaDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxIMapDlgChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScFormulaDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScAcceptChgDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScHighlightChgDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScSimpleRefDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SvxSearchDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(SID_HYPERLINK_DIALOG);
+ GetStaticInterface()->RegisterChildWindow(ScSpellDialogChildWindow::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScValidityRefChildWin::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(sc::SearchResultsDlgWrapper::GetChildWindowId());
+
+ GetStaticInterface()->RegisterChildWindow(ScRandomNumberGeneratorDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScSamplingDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScDescriptiveStatisticsDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScAnalysisOfVarianceDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScCorrelationDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScCovarianceDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScExponentialSmoothingDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScMovingAverageDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScRegressionDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScTTestDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScFTestDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScZTestDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScChiSquareTestDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScFourierAnalysisDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(ScCondFormatDlgWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(sc::SparklineDialogWrapper::GetChildWindowId());
+ GetStaticInterface()->RegisterChildWindow(sc::SparklineDataRangeDialogWrapper::GetChildWindowId());
+}
+
+SFX_IMPL_NAMED_VIEWFACTORY( ScTabViewShell, "Default" )
+{
+ SFX_VIEW_REGISTRATION(ScDocShell);
+}
+
+OUString ScTabViewShell::GetFormula(const ScAddress& rAddress)
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScRefCellValue aCell(rDoc, rAddress);
+ if (!aCell.isEmpty() && aCell.meType == CELLTYPE_FORMULA)
+ {
+ return aCell.mpFormula->GetFormula();
+ }
+ return OUString();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwsh2.cxx b/sc/source/ui/view/tabvwsh2.cxx
new file mode 100644
index 000000000..a1cf1879c
--- /dev/null
+++ b/sc/source/ui/view/tabvwsh2.cxx
@@ -0,0 +1,472 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <comphelper/lok.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/whiter.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <svl/cjkoptions.hxx>
+#include <sfx2/dispatch.hxx>
+#include <tools/UnitConversion.hxx>
+
+#include <tabvwsh.hxx>
+#include <drawview.hxx>
+#include <fupoor.hxx>
+#include <fuconrec.hxx>
+#include <fuconpol.hxx>
+#include <fuconarc.hxx>
+#include <fuconuno.hxx>
+#include <fusel.hxx>
+#include <futext.hxx>
+#include <fuinsert.hxx>
+#include <sc.hrc>
+#include <scmod.hxx>
+#include <appoptio.hxx>
+#include <gridwin.hxx>
+
+// Create default drawing objects via keyboard
+#include <svx/svdpagv.hxx>
+#include <svl/stritem.hxx>
+#include <fuconcustomshape.hxx>
+
+SdrView* ScTabViewShell::GetDrawView() const
+{
+ return const_cast<ScTabViewShell*>(this)->GetScDrawView(); // GetScDrawView is non-const
+}
+
+void ScTabViewShell::WindowChanged()
+{
+ vcl::Window* pWin = GetActiveWin();
+
+ ScDrawView* pDrView = GetScDrawView();
+ if (pDrView)
+ pDrView->SetActualWin(pWin->GetOutDev());
+
+ FuPoor* pFunc = GetDrawFuncPtr();
+ if (pFunc)
+ pFunc->SetWindow(pWin);
+
+ // when font from InputContext is used,
+ // this must be moved to change of cursor position:
+ UpdateInputContext();
+}
+
+void ScTabViewShell::ExecDraw(SfxRequest& rReq)
+{
+ SC_MOD()->InputEnterHandler();
+ UpdateInputHandler();
+
+ MakeDrawLayer();
+
+ ScTabView* pTabView = GetViewData().GetView();
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+
+ vcl::Window* pWin = pTabView->GetActiveWin();
+ ScDrawView* pView = pTabView->GetScDrawView();
+ SdrModel* pDoc = pView->GetModel();
+
+ const SfxItemSet *pArgs = rReq.GetArgs();
+ sal_uInt16 nNewId = rReq.GetSlot();
+
+ if ( nNewId == SID_DRAW_CHART )
+ {
+ // #i71254# directly insert a chart instead of drawing its output rectangle
+ FuInsertChart(*this, pWin, pView, pDoc, rReq, LINK( this, ScTabViewShell, DialogClosedHdl ));
+ return;
+ }
+
+ if ( nNewId == SID_DRAW_SELECT )
+ nNewId = SID_OBJECT_SELECT;
+
+ SdrObjKind eNewFormObjKind = SdrObjKind::NONE;
+ if (nNewId == SID_FM_CREATE_CONTROL)
+ {
+ const SfxUInt16Item* pIdentifierItem = rReq.GetArg<SfxUInt16Item>(SID_FM_CONTROL_IDENTIFIER);
+ if (pIdentifierItem)
+ eNewFormObjKind = static_cast<SdrObjKind>(pIdentifierItem->GetValue());
+ }
+
+ OUString sStringItemValue;
+ if ( pArgs )
+ {
+ const SfxPoolItem* pItem;
+ if ( pArgs->GetItemState( nNewId, true, &pItem ) == SfxItemState::SET )
+ if (auto pStringItem = dynamic_cast<const SfxStringItem*>(pItem) )
+ sStringItemValue = pStringItem->GetValue();
+ }
+ bool bSwitchCustom = ( !sStringItemValue.isEmpty() && !sDrawCustom.isEmpty() && sStringItemValue != sDrawCustom );
+
+ if (nNewId == SID_INSERT_FRAME) // from Tbx button
+ nNewId = SID_DRAW_TEXT;
+
+ // CTRL-SID_OBJECT_SELECT is used to select the first object,
+ // but not if SID_OBJECT_SELECT is the result of clicking a create function again,
+ // so this must be tested before changing nNewId below.
+ bool bSelectFirst = ( nNewId == SID_OBJECT_SELECT && (rReq.GetModifier() & KEY_MOD1) );
+
+ bool bEx = IsDrawSelMode();
+ if ( rReq.GetModifier() & KEY_MOD1 )
+ {
+ // always allow keyboard selection also on background layer
+ // also allow creation of default objects if the same object type
+ // was already active
+ bEx = true;
+ }
+ else if ( nNewId == nDrawSfxId && ( nNewId != SID_FM_CREATE_CONTROL ||
+ eNewFormObjKind == eFormObjKind || eNewFormObjKind == SdrObjKind::NONE ) && !bSwitchCustom )
+ {
+ // #i52871# if a different custom shape is selected, the slot id can be the same,
+ // so the custom shape type string has to be compared, too.
+
+ // SID_FM_CREATE_CONTROL with eNewFormObjKind==OBJ_NONE (without parameter) comes
+ // from FuConstruct::SimpleMouseButtonUp when deactivating
+ // Execute for the form shell, to deselect the controller
+ if ( nNewId == SID_FM_CREATE_CONTROL )
+ {
+ GetViewData().GetDispatcher().Execute(SID_FM_LEAVE_CREATE);
+ GetViewFrame()->GetBindings().InvalidateAll(false);
+ //! what kind of slot does the weird controller really need to display this????
+ }
+
+ bEx = !bEx;
+ nNewId = SID_OBJECT_SELECT;
+ }
+ else
+ bEx = true;
+
+ if ( nDrawSfxId == SID_FM_CREATE_CONTROL && nNewId != nDrawSfxId )
+ {
+ // switching from control- to paint function -> deselect in control-controller
+ GetViewData().GetDispatcher().Execute(SID_FM_LEAVE_CREATE);
+ GetViewFrame()->GetBindings().InvalidateAll(false);
+ //! what kind of slot does the weird controller really need to display this????
+ }
+
+ SetDrawSelMode(bEx);
+
+ pView->LockBackgroundLayer( !bEx );
+
+ if ( bSelectFirst )
+ {
+ // select first draw object if none is selected yet
+ if(!pView->AreObjectsMarked())
+ {
+ // select first object
+ pView->UnmarkAllObj();
+ pView->MarkNextObj(true);
+
+ // ...and make it visible
+ if(pView->AreObjectsMarked())
+ pView->MakeVisible(pView->GetAllMarkedRect(), *pWin);
+ }
+ }
+
+ nDrawSfxId = nNewId;
+ sDrawCustom.clear(); // value is set below for custom shapes
+
+ if (nNewId == SID_DRAW_TEXT || nNewId == SID_DRAW_TEXT_VERTICAL
+ || nNewId == SID_DRAW_TEXT_MARQUEE || nNewId == SID_DRAW_NOTEEDIT)
+ SetDrawTextShell(true);
+ else
+ {
+ if (bEx || pView->GetMarkedObjectList().GetMarkCount() != 0)
+ SetDrawShellOrSub();
+ else
+ SetDrawShell(false);
+ }
+
+ if (pTabView->GetDrawFuncPtr())
+ {
+ if (pTabView->GetDrawFuncOldPtr() != pTabView->GetDrawFuncPtr())
+ delete pTabView->GetDrawFuncOldPtr();
+
+ pTabView->GetDrawFuncPtr()->Deactivate();
+ pTabView->SetDrawFuncOldPtr(pTabView->GetDrawFuncPtr());
+ pTabView->SetDrawFuncPtr(nullptr);
+ }
+
+ SfxRequest aNewReq(rReq);
+ aNewReq.SetSlot(nDrawSfxId);
+
+ assert(nNewId != SID_DRAW_CHART); //#i71254# handled already above
+
+ // for LibreOfficeKit - choosing a shape should construct it directly
+ bool bCreateDirectly = false;
+
+ switch (nNewId)
+ {
+ case SID_OBJECT_SELECT:
+ // not always switch back
+ if(pView->GetMarkedObjectList().GetMarkCount() == 0) SetDrawShell(bEx);
+ pTabView->SetDrawFuncPtr(new FuSelection(*this, pWin, pView, pDoc, aNewReq));
+ break;
+
+ case SID_DRAW_LINE:
+ case SID_DRAW_XLINE:
+ case SID_LINE_ARROW_END:
+ case SID_LINE_ARROW_CIRCLE:
+ case SID_LINE_ARROW_SQUARE:
+ case SID_LINE_ARROW_START:
+ case SID_LINE_CIRCLE_ARROW:
+ case SID_LINE_SQUARE_ARROW:
+ case SID_LINE_ARROWS:
+ case SID_DRAW_RECT:
+ case SID_DRAW_ELLIPSE:
+ case SID_DRAW_MEASURELINE:
+ pTabView->SetDrawFuncPtr(new FuConstRectangle(*this, pWin, pView, pDoc, aNewReq));
+ bCreateDirectly = comphelper::LibreOfficeKit::isActive();
+ break;
+
+ case SID_DRAW_CAPTION:
+ case SID_DRAW_CAPTION_VERTICAL:
+ pTabView->SetDrawFuncPtr(new FuConstRectangle(*this, pWin, pView, pDoc, aNewReq));
+ pView->SetFrameDragSingles( false );
+ rBindings.Invalidate( SID_BEZIER_EDIT );
+ break;
+
+ case SID_DRAW_XPOLYGON:
+ case SID_DRAW_XPOLYGON_NOFILL:
+ case SID_DRAW_POLYGON:
+ case SID_DRAW_POLYGON_NOFILL:
+ case SID_DRAW_BEZIER_NOFILL:
+ case SID_DRAW_BEZIER_FILL:
+ case SID_DRAW_FREELINE:
+ case SID_DRAW_FREELINE_NOFILL:
+ pTabView->SetDrawFuncPtr(new FuConstPolygon(*this, pWin, pView, pDoc, aNewReq));
+ break;
+
+ case SID_DRAW_ARC:
+ case SID_DRAW_PIE:
+ case SID_DRAW_CIRCLECUT:
+ pTabView->SetDrawFuncPtr(new FuConstArc(*this, pWin, pView, pDoc, aNewReq));
+ break;
+
+ case SID_DRAW_TEXT:
+ case SID_DRAW_TEXT_VERTICAL:
+ case SID_DRAW_TEXT_MARQUEE:
+ case SID_DRAW_NOTEEDIT:
+ pTabView->SetDrawFuncPtr(new FuText(*this, pWin, pView, pDoc, aNewReq));
+ bCreateDirectly = comphelper::LibreOfficeKit::isActive();
+ break;
+
+ case SID_FM_CREATE_CONTROL:
+ SetDrawFormShell(true);
+ pTabView->SetDrawFuncPtr(new FuConstUnoControl(*this, pWin, pView, pDoc, aNewReq));
+ eFormObjKind = eNewFormObjKind;
+ 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 :
+ {
+ pTabView->SetDrawFuncPtr(new FuConstCustomShape(*this, pWin, pView, pDoc, aNewReq));
+
+ bCreateDirectly = comphelper::LibreOfficeKit::isActive();
+
+ if ( nNewId != SID_DRAW_CS_ID )
+ {
+ const SfxStringItem* pEnumCommand = rReq.GetArg<SfxStringItem>(nNewId);
+ if ( pEnumCommand )
+ {
+ SfxBindings& rBind = GetViewFrame()->GetBindings();
+ rBind.Invalidate( nNewId );
+ rBind.Update( nNewId );
+
+ sDrawCustom = pEnumCommand->GetValue(); // to detect when a different shape type is selected
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (pTabView->GetDrawFuncPtr())
+ pTabView->GetDrawFuncPtr()->Activate();
+
+ rReq.Done();
+
+ Invalidate();
+
+ // Create default drawing objects via keyboard
+ // with qualifier construct directly
+ FuPoor* pFuActual = GetDrawFuncPtr();
+
+ if(!(pFuActual && ((rReq.GetModifier() & KEY_MOD1) || bCreateDirectly)))
+ return;
+
+ // Create default drawing objects via keyboard
+ const ScAppOptions& rAppOpt = SC_MOD()->GetAppOptions();
+ sal_uInt32 nDefaultObjectSizeWidth = rAppOpt.GetDefaultObjectSizeWidth();
+ sal_uInt32 nDefaultObjectSizeHeight = rAppOpt.GetDefaultObjectSizeHeight();
+
+ // calc position and size
+ bool bLOKIsActive = comphelper::LibreOfficeKit::isActive();
+ Point aInsertPos;
+ if(!bLOKIsActive)
+ {
+ tools::Rectangle aVisArea = pWin->PixelToLogic(tools::Rectangle(Point(0,0), pWin->GetOutputSizePixel()));
+ aInsertPos = aVisArea.Center();
+ aInsertPos.AdjustX( -sal_Int32(nDefaultObjectSizeWidth / 2) );
+ aInsertPos.AdjustY( -sal_Int32(nDefaultObjectSizeHeight / 2) );
+ }
+ else
+ {
+ ScViewData& rViewData = GetViewData();
+ tools::Long nLayoutSign = rViewData.GetDocument().IsLayoutRTL(rViewData.GetTabNo()) ? -1 : 1;
+ aInsertPos = rViewData.getLOKVisibleArea().Center();
+ if (comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ aInsertPos = rViewData.GetPrintTwipsPosFromTileTwips(aInsertPos);
+
+ aInsertPos.setX(nLayoutSign * convertTwipToMm100(aInsertPos.X()));
+ aInsertPos.setY(convertTwipToMm100(aInsertPos.Y()));
+
+ aInsertPos.AdjustX( -sal_Int32(nDefaultObjectSizeWidth / 2) );
+ aInsertPos.AdjustY( -sal_Int32(nDefaultObjectSizeHeight / 2) );
+ }
+
+ tools::Rectangle aNewObjectRectangle(aInsertPos, Size(nDefaultObjectSizeWidth, nDefaultObjectSizeHeight));
+
+ ScDrawView* pDrView = GetScDrawView();
+
+ if(!pDrView)
+ return;
+
+ SdrPageView* pPageView = pDrView->GetSdrPageView();
+
+ if(!pPageView)
+ return;
+
+ // create the default object
+ SdrObjectUniquePtr pObj = pFuActual->CreateDefaultObject(nNewId, aNewObjectRectangle);
+
+ if(!pObj)
+ return;
+
+ // insert into page
+ pView->InsertObjectAtView(pObj.release(), *pPageView);
+
+ switch ( nNewId )
+ {
+ case SID_DRAW_CAPTION:
+ case SID_DRAW_CAPTION_VERTICAL:
+ case SID_DRAW_TEXT:
+ case SID_DRAW_TEXT_VERTICAL:
+ // use KeyInput to start edit mode (FuText is created).
+ // For FuText objects, edit mode is handled within CreateDefaultObject.
+ // KEY_F2 is handled in FuDraw::KeyInput.
+
+ pFuActual->KeyInput( KeyEvent( 0, vcl::KeyCode( KEY_F2 ) ) );
+ break;
+ default:
+ break;
+ }
+}
+
+void ScTabViewShell::GetDrawState(SfxItemSet &rSet)
+{
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ while ( nWhich )
+ {
+ switch ( nWhich )
+ {
+ case SID_DRAW_CHART:
+ {
+ bool bOle = GetViewFrame()->GetFrame().IsInPlace();
+ if ( bOle || !SvtModuleOptions().IsChart() )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_DRAW_LINE:
+ case SID_DRAW_XLINE:
+ case SID_LINE_ARROW_END:
+ case SID_LINE_ARROW_CIRCLE:
+ case SID_LINE_ARROW_SQUARE:
+ case SID_LINE_ARROW_START:
+ case SID_LINE_CIRCLE_ARROW:
+ case SID_LINE_SQUARE_ARROW:
+ case SID_LINE_ARROWS:
+ case SID_DRAW_MEASURELINE:
+ case SID_DRAW_RECT:
+ case SID_DRAW_ELLIPSE:
+ case SID_DRAW_POLYGON:
+ case SID_DRAW_POLYGON_NOFILL:
+ case SID_DRAW_XPOLYGON:
+ case SID_DRAW_XPOLYGON_NOFILL:
+ case SID_DRAW_BEZIER_FILL:
+ case SID_DRAW_BEZIER_NOFILL:
+ case SID_DRAW_FREELINE:
+ case SID_DRAW_FREELINE_NOFILL:
+ case SID_DRAW_ARC:
+ case SID_DRAW_PIE:
+ case SID_DRAW_CIRCLECUT:
+ case SID_DRAW_TEXT:
+ case SID_DRAW_TEXT_MARQUEE:
+ case SID_DRAW_CAPTION:
+ rSet.Put( SfxBoolItem( nWhich, nDrawSfxId == nWhich ) );
+ break;
+
+ case SID_DRAW_TEXT_VERTICAL:
+ case SID_DRAW_CAPTION_VERTICAL:
+ if ( !SvtCJKOptions::IsVerticalTextEnabled() )
+ rSet.DisableItem( nWhich );
+ else
+ rSet.Put( SfxBoolItem( nWhich, nDrawSfxId == nWhich ) );
+ break;
+
+ case SID_OBJECT_SELECT: // important for the old control-controller
+ rSet.Put( SfxBoolItem( nWhich, nDrawSfxId == SID_OBJECT_SELECT && IsDrawSelMode() ) );
+ 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:
+ rSet.Put( SfxStringItem( nWhich, nDrawSfxId == nWhich ? sDrawCustom : OUString() ) );
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+bool ScTabViewShell::SelectObject( std::u16string_view rName )
+{
+ ScDrawView* pView = GetViewData().GetScDrawView();
+ if (!pView)
+ return false;
+
+ bool bFound = pView->SelectObject( rName );
+ // DrawShell etc. is handled in MarkListHasChanged
+
+ return bFound;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwsh3.cxx b/sc/source/ui/view/tabvwsh3.cxx
new file mode 100644
index 000000000..766f6c762
--- /dev/null
+++ b/sc/source/ui/view/tabvwsh3.cxx
@@ -0,0 +1,1352 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <sfx2/passwd.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sidebar/Sidebar.hxx>
+#include <svl/ptitem.hxx>
+#include <svl/stritem.hxx>
+#include <tools/urlobj.hxx>
+#include <sfx2/objface.hxx>
+#include <vcl/vclenum.hxx>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+
+#include <globstr.hrc>
+#include <strings.hrc>
+#include <scmod.hxx>
+#include <appoptio.hxx>
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <sc.hrc>
+#include <helpids.h>
+#include <inputwin.hxx>
+#include <scresid.hxx>
+#include <docsh.hxx>
+#include <rangeutl.hxx>
+#include <reffact.hxx>
+#include <tabprotection.hxx>
+#include <protectiondlg.hxx>
+#include <markdata.hxx>
+
+#include <svl/ilstitem.hxx>
+#include <vector>
+
+#include <svx/zoomslideritem.hxx>
+#include <svx/svxdlg.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/string.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <scabstdlg.hxx>
+
+#include <basegfx/utils/zoomtools.hxx>
+
+namespace
+{
+ void collectUIInformation(const OUString& aZoom)
+ {
+ EventDescription aDescription;
+ aDescription.aID = "grid_window";
+ aDescription.aParameters = {{"ZOOM", aZoom}};
+ aDescription.aAction = "SET";
+ aDescription.aKeyWord = "ScGridWinUIObject";
+ aDescription.aParent = "MainWindow";
+ UITestLogger::getInstance().logEvent(aDescription);
+ }
+
+ enum class DetectFlags
+ {
+ NONE,
+ RANGE,
+ ADDRESS
+ };
+
+ struct ScRefFlagsAndType
+ {
+ ScRefFlags nResult;
+ DetectFlags eDetected;
+ };
+
+ ScRefFlagsAndType lcl_ParseRangeOrAddress(ScRange& rScRange, ScAddress& rScAddress,
+ const OUString& aAddress, const ScDocument& rDoc,
+ SCCOL nCurCol, SCROW nCurRow)
+ {
+ ScRefFlagsAndType aRet;
+
+ // Relative address parsing needs current position.
+ // row,col parameters, not col,row!
+ ScAddress::Details aDetails( rDoc.GetAddressConvention(), nCurRow, nCurCol);
+
+ // start with the address convention set in the document
+ aRet.nResult = rScRange.Parse(aAddress, rDoc, aDetails);
+ if (aRet.nResult & ScRefFlags::VALID)
+ {
+ aRet.eDetected = DetectFlags::RANGE;
+ return aRet;
+ }
+
+ aRet.nResult = rScAddress.Parse(aAddress, rDoc, aDetails);
+ if (aRet.nResult & ScRefFlags::VALID)
+ {
+ aRet.eDetected = DetectFlags::ADDRESS;
+ return aRet;
+ }
+
+ // try the default Calc (A1) address convention
+ aRet.nResult = rScRange.Parse(aAddress, rDoc);
+ if (aRet.nResult & ScRefFlags::VALID)
+ {
+ aRet.eDetected = DetectFlags::RANGE;
+ return aRet;
+ }
+
+ aRet.nResult = rScAddress.Parse(aAddress, rDoc);
+ if (aRet.nResult & ScRefFlags::VALID)
+ {
+ aRet.eDetected = DetectFlags::ADDRESS;
+ return aRet;
+ }
+
+ // try the Excel A1 address convention
+ aRet.nResult = rScRange.Parse(aAddress, rDoc, formula::FormulaGrammar::CONV_XL_A1);
+ if (aRet.nResult & ScRefFlags::VALID)
+ {
+ aRet.eDetected = DetectFlags::RANGE;
+ return aRet;
+ }
+
+ // try the Excel A1 address convention
+ aRet.nResult = rScAddress.Parse(aAddress, rDoc, formula::FormulaGrammar::CONV_XL_A1);
+ if (aRet.nResult & ScRefFlags::VALID)
+ {
+ aRet.eDetected = DetectFlags::ADDRESS;
+ return aRet;
+ }
+
+ // try Excel R1C1 address convention
+ aDetails.eConv = formula::FormulaGrammar::CONV_XL_R1C1;
+ aRet.nResult = rScRange.Parse(aAddress, rDoc, aDetails);
+ if (aRet.nResult & ScRefFlags::VALID)
+ {
+ aRet.eDetected = DetectFlags::RANGE;
+ return aRet;
+ }
+
+ aRet.nResult = rScAddress.Parse(aAddress, rDoc, aDetails);
+ if (aRet.nResult & ScRefFlags::VALID)
+ {
+ aRet.eDetected = DetectFlags::ADDRESS;
+ return aRet;
+ }
+
+ aRet.nResult = ScRefFlags::ZERO;
+ aRet.eDetected = DetectFlags::NONE;
+
+ return aRet;
+ }
+}
+
+void ScTabViewShell::Execute( SfxRequest& rReq )
+{
+ SfxViewFrame* pThisFrame = GetViewFrame();
+ SfxBindings& rBindings = pThisFrame->GetBindings();
+ ScModule* pScMod = SC_MOD();
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+
+ if (nSlot != SID_CURRENTCELL) // comes with MouseButtonUp
+ HideListBox(); // Autofilter-DropDown-Listbox
+
+ switch ( nSlot )
+ {
+ case FID_INSERT_FILE:
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs &&
+ pReqArgs->GetItemState(FID_INSERT_FILE,true,&pItem) == SfxItemState::SET )
+ {
+ OUString aFileName = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ // insert position
+
+ Point aInsertPos;
+ if ( pReqArgs->GetItemState(FN_PARAM_1,true,&pItem) == SfxItemState::SET )
+ aInsertPos = static_cast<const SfxPointItem*>(pItem)->GetValue();
+ else
+ aInsertPos = GetInsertPos();
+
+ // as Link?
+
+ bool bAsLink = false;
+ if ( pReqArgs->GetItemState(FN_PARAM_2,true,&pItem) == SfxItemState::SET )
+ bAsLink = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ // execute
+
+ PasteFile( aInsertPos, aFileName, bAsLink );
+ }
+ }
+ break;
+
+ case SID_OPENDLG_EDIT_PRINTAREA:
+ {
+ sal_uInt16 nId = ScPrintAreasDlgWrapper::GetChildWindowId();
+ SfxChildWindow* pWnd = pThisFrame->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+
+ case SID_CHANGE_PRINTAREA:
+ {
+ if ( pReqArgs ) // OK from dialog
+ {
+ OUString aPrintStr;
+ OUString aRowStr;
+ OUString aColStr;
+ bool bEntire = false;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs->GetItemState( SID_CHANGE_PRINTAREA, true, &pItem ) == SfxItemState::SET )
+ aPrintStr = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ if ( pReqArgs->GetItemState( FN_PARAM_2, true, &pItem ) == SfxItemState::SET )
+ aRowStr = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ if ( pReqArgs->GetItemState( FN_PARAM_3, true, &pItem ) == SfxItemState::SET )
+ aColStr = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ if ( pReqArgs->GetItemState( FN_PARAM_4, true, &pItem ) == SfxItemState::SET )
+ bEntire = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ SetPrintRanges( bEntire, &aPrintStr, &aColStr, &aRowStr, false );
+
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_ADD_PRINTAREA:
+ case SID_DEFINE_PRINTAREA: // menu or basic
+ {
+ bool bAdd = ( nSlot == SID_ADD_PRINTAREA );
+ if ( pReqArgs )
+ {
+ OUString aPrintStr;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs->GetItemState( SID_DEFINE_PRINTAREA, true, &pItem ) == SfxItemState::SET )
+ aPrintStr = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ SetPrintRanges( false, &aPrintStr, nullptr, nullptr, bAdd );
+ }
+ else
+ {
+ SetPrintRanges( false, nullptr, nullptr, nullptr, bAdd ); // from selection
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_DELETE_PRINTAREA:
+ {
+ // Clear currently defined print range if any, and reset it to
+ // print entire sheet which is the default.
+ OUString aEmpty;
+ SetPrintRanges(true, &aEmpty, nullptr, nullptr, false);
+ rReq.Done();
+ }
+ break;
+
+ case FID_DEL_MANUALBREAKS:
+ RemoveManualBreaks();
+ rReq.Done();
+ break;
+
+ case FID_ADJUST_PRINTZOOM:
+ AdjustPrintZoom();
+ rReq.Done();
+ break;
+
+ case FID_RESET_PRINTZOOM:
+ SetPrintZoom( 100 ); // 100%, not on pages
+ rReq.Done();
+ break;
+
+ case SID_FORMATPAGE:
+ case SID_STATUS_PAGESTYLE:
+ case SID_HFEDIT:
+ GetViewData().GetDocShell()->
+ ExecutePageStyle( *this, rReq, GetViewData().GetTabNo() );
+ break;
+
+ case SID_JUMPTOMARK:
+ case SID_CURRENTCELL:
+ if ( pReqArgs )
+ {
+ OUString aAddress;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
+ aAddress = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ else if ( nSlot == SID_JUMPTOMARK && pReqArgs->GetItemState(
+ SID_JUMPTOMARK, true, &pItem ) == SfxItemState::SET )
+ aAddress = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ // #i14927# SID_CURRENTCELL with a single cell must unmark if FN_PARAM_1
+ // isn't set (for recorded macros, because IsAPI is no longer available).
+ // ScGridWindow::MouseButtonUp no longer executes the slot for a single
+ // cell if there is a multi selection.
+ bool bUnmark = ( nSlot == SID_CURRENTCELL );
+ if ( pReqArgs->GetItemState( FN_PARAM_1, true, &pItem ) == SfxItemState::SET )
+ bUnmark = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ bool bAlignToCursor = true;
+ if (pReqArgs->GetItemState(FN_PARAM_2, true, &pItem) == SfxItemState::SET)
+ bAlignToCursor = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ bool bForceGlobalName = false;
+ if (pReqArgs->GetItemState(FN_PARAM_3, true, &pItem) == SfxItemState::SET)
+ bForceGlobalName = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ if ( nSlot == SID_JUMPTOMARK )
+ {
+ // URL has to be decoded for escaped characters (%20)
+ aAddress = INetURLObject::decode( aAddress,
+ INetURLObject::DecodeMechanism::WithCharset );
+ }
+
+ bool bFound = false;
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScMarkData& rMark = rViewData.GetMarkData();
+ ScRange aScRange;
+ ScAddress aScAddress;
+ ScRefFlagsAndType aResult = lcl_ParseRangeOrAddress(aScRange, aScAddress, aAddress, rDoc,
+ rViewData.GetCurX(), rViewData.GetCurY());
+ ScRefFlags nResult = aResult.nResult;
+ SCTAB nTab = rViewData.GetTabNo();
+ bool bMark = true;
+
+ // Is this a range ?
+ if (aResult.eDetected == DetectFlags::RANGE)
+ {
+ if ( nResult & ScRefFlags::TAB_3D )
+ {
+ if( aScRange.aStart.Tab() != nTab )
+ {
+ nTab = aScRange.aStart.Tab();
+ SetTabNo( nTab );
+ }
+ }
+ else
+ {
+ aScRange.aStart.SetTab( nTab );
+ aScRange.aEnd.SetTab( nTab );
+ }
+ }
+ // Is this a cell ?
+ else if (aResult.eDetected == DetectFlags::ADDRESS)
+ {
+ if ( nResult & ScRefFlags::TAB_3D )
+ {
+ if( aScAddress.Tab() != nTab )
+ {
+ nTab = aScAddress.Tab();
+ SetTabNo( nTab );
+ }
+ }
+ else
+ aScAddress.SetTab( nTab );
+
+ aScRange = ScRange( aScAddress, aScAddress );
+ // cells should not be marked
+ bMark = false;
+ }
+ // Is it a named area (first named ranges then database ranges)?
+ else
+ {
+ const RutlNameScope eScope = (bForceGlobalName ? RUTL_NAMES_GLOBAL : RUTL_NAMES);
+ ScAddress::Details aDetails( rDoc.GetAddressConvention(), rViewData.GetCurY(), rViewData.GetCurX());
+ if (ScRangeUtil::MakeRangeFromName( aAddress, rDoc, nTab, aScRange, eScope, aDetails, true) ||
+ ScRangeUtil::MakeRangeFromName( aAddress, rDoc, nTab, aScRange, RUTL_DBASE, aDetails, true))
+ {
+ nResult |= ScRefFlags::VALID;
+ if( aScRange.aStart.Tab() != nTab )
+ {
+ nTab = aScRange.aStart.Tab();
+ SetTabNo( nTab );
+ }
+ }
+ }
+
+ if ( !(nResult & ScRefFlags::VALID) && comphelper::string::isdigitAsciiString(aAddress) )
+ {
+ sal_Int32 nNumeric = aAddress.toInt32();
+ if ( nNumeric > 0 && nNumeric <= rDoc.MaxRow()+1 )
+ {
+ // one-based row numbers
+
+ aScAddress.SetRow( static_cast<SCROW>(nNumeric - 1) );
+ aScAddress.SetCol( rViewData.GetCurX() );
+ aScAddress.SetTab( nTab );
+ aScRange = ScRange( aScAddress, aScAddress );
+ bMark = false;
+ nResult = ScRefFlags::VALID;
+ }
+ }
+
+ if ( !rDoc.ValidRow(aScRange.aStart.Row()) || !rDoc.ValidRow(aScRange.aEnd.Row()) )
+ nResult = ScRefFlags::ZERO;
+
+ // we have found something
+ if( nResult & ScRefFlags::VALID )
+ {
+ bFound = true;
+ SCCOL nCol = aScRange.aStart.Col();
+ SCROW nRow = aScRange.aStart.Row();
+ bool bNothing = ( rViewData.GetCurX()==nCol && rViewData.GetCurY()==nRow );
+
+ // mark
+ if( bMark )
+ {
+ if (rMark.IsMarked()) // is the same range already marked?
+ {
+ ScRange aOldMark = rMark.GetMarkArea();
+ aOldMark.PutInOrder();
+ ScRange aCurrent = aScRange;
+ aCurrent.PutInOrder();
+ bNothing = ( aCurrent == aOldMark );
+ }
+ else
+ bNothing = false;
+
+ if (!bNothing)
+ MarkRange( aScRange, false ); // cursor comes after...
+ }
+ else
+ {
+ // remove old selection, unless bUnmark argument is sal_False (from navigator)
+ if( bUnmark )
+ {
+ MoveCursorAbs( nCol, nRow,
+ SC_FOLLOW_NONE, false, false );
+ }
+ }
+
+ // and set cursor
+
+ // consider merged cells:
+ rDoc.SkipOverlapped(nCol, nRow, nTab);
+
+ // navigator calls are not part of the API!!!
+
+ if( bNothing )
+ {
+ if (rReq.IsAPI())
+ rReq.Ignore(); // if macro, then nothing
+ else
+ rReq.Done(); // then at least paint it
+ }
+ else
+ {
+ rViewData.ResetOldCursor();
+ SetCursor( nCol, nRow );
+ rBindings.Invalidate( SID_CURRENTCELL );
+ rBindings.Update( nSlot );
+
+ if (!rReq.IsAPI())
+ rReq.Done();
+ }
+
+ if (bAlignToCursor)
+ {
+ // align to cursor even if the cursor position hasn't changed,
+ // because the cursor may be set outside the visible area.
+ AlignToCursor( nCol, nRow, SC_FOLLOW_JUMP );
+ if ( nSlot == SID_JUMPTOMARK && comphelper::LibreOfficeKit::isActive() )
+ rViewData.GetActiveWin()->notifyKitCellFollowJump();
+ }
+
+ rReq.SetReturnValue( SfxStringItem( SID_CURRENTCELL, aAddress ) );
+ }
+
+ if (!bFound) // no valid range
+ {
+ // if it is a sheet name, then switch (for Navigator/URL)
+
+ SCTAB nNameTab;
+ if ( rDoc.GetTable( aAddress, nNameTab ) )
+ {
+ bFound = true;
+ if ( nNameTab != nTab )
+ SetTabNo( nNameTab );
+ }
+ }
+
+ if ( !bFound && nSlot == SID_JUMPTOMARK )
+ {
+ // test graphics objects (only for URL)
+
+ bFound = SelectObject( aAddress );
+ }
+
+ if (!bFound && !rReq.IsAPI())
+ ErrorMessage( STR_ERR_INVALID_AREA );
+ }
+ break;
+
+ case SID_CURRENTOBJECT:
+ if ( pReqArgs )
+ {
+ OUString aName = static_cast<const SfxStringItem&>(pReqArgs->Get(nSlot)).GetValue();
+ SelectObject( aName );
+ }
+ break;
+
+ case SID_CURRENTTAB:
+ {
+ SCTAB nTab;
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ if ( pReqArgs ) // command from Navigator with nTab
+ {
+ // sheet for basic is one-based
+ nTab = static_cast<const SfxUInt16Item&>(pReqArgs->Get(nSlot)).GetValue() - 1;
+ }
+ else // command from Menu: ask for nTab
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScGoToTabDlg> pDlg(pFact->CreateScGoToTabDlg(GetFrameWeld()));
+ pDlg->SetDescription(
+ ScResId( STR_DLG_SELECTTABLE_TITLE ),
+ ScResId( STR_DLG_SELECTTABLE_MASK ),
+ ScResId( STR_DLG_SELECTTABLE_LBNAME ),
+ GetStaticInterface()->GetSlot(SID_CURRENTTAB)->GetCommand(), HID_GOTOTABLEMASK, HID_GOTOTABLE );
+
+ // fill all table names and select current tab
+ OUString aTabName;
+ for( nTab = 0; nTab < nTabCount; ++nTab )
+ {
+ if( rDoc.IsVisible( nTab ) )
+ {
+ rDoc.GetName( nTab, aTabName );
+ pDlg->Insert( aTabName, rViewData.GetTabNo() == nTab );
+ }
+ }
+
+ if( pDlg->Execute() == RET_OK )
+ {
+ if( !rDoc.GetTable( pDlg->GetSelectedEntry(), nTab ) )
+ nTab = nTabCount;
+ pDlg.disposeAndClear();
+ }
+ else
+ {
+ rReq.Ignore();
+ }
+ }
+ if ( nTab < nTabCount )
+ {
+ SetTabNo( nTab );
+ rBindings.Update( nSlot );
+
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+ }
+ //! otherwise an error ?
+ }
+ break;
+
+ case SID_CURRENTDOC:
+ if ( pReqArgs )
+ {
+ OUString aStrDocName( static_cast<const SfxStringItem&>(pReqArgs->
+ Get(nSlot)).GetValue() );
+
+ SfxViewFrame* pViewFrame = nullptr;
+ ScDocShell* pDocSh = static_cast<ScDocShell*>(SfxObjectShell::GetFirst());
+ bool bFound = false;
+
+ // search for ViewFrame to be activated
+
+ while ( pDocSh && !bFound )
+ {
+ if ( pDocSh->GetTitle() == aStrDocName )
+ {
+ pViewFrame = SfxViewFrame::GetFirst( pDocSh );
+ bFound = ( nullptr != pViewFrame );
+ }
+
+ pDocSh = static_cast<ScDocShell*>(SfxObjectShell::GetNext( *pDocSh ));
+ }
+
+ if ( bFound )
+ pViewFrame->GetFrame().Appear();
+
+ rReq.Ignore();//XXX is handled by SFX
+ }
+ break;
+
+ case SID_PRINTPREVIEW:
+ {
+ if ( !pThisFrame->GetFrame().IsInPlace() ) // not for OLE
+ {
+ // print preview is now always in the same frame as the tab view
+ // -> always switch this frame back to normal view
+ // (ScPreviewShell ctor reads view data)
+
+ // #102785#; finish input
+ pScMod->InputEnterHandler();
+
+ pThisFrame->GetDispatcher()->Execute( SID_VIEWSHELL1, SfxCallMode::ASYNCHRON );
+ }
+ // else error (e.g. Ole)
+ }
+ break;
+
+ case SID_DETECTIVE_DEL_ALL:
+ DetectiveDelAll();
+ rReq.Done();
+ break;
+
+ // SID_TABLE_ACTIVATE and SID_MARKAREA are called by basic for the
+ // hidden View, to mark/switch on the visible View:
+
+ case SID_TABLE_ACTIVATE:
+ OSL_FAIL("old slot SID_TABLE_ACTIVATE");
+ break;
+
+ case SID_REPAINT:
+ PaintGrid();
+ PaintTop();
+ PaintLeft();
+ PaintExtras();
+ rReq.Done();
+ break;
+
+ case FID_NORMALVIEWMODE:
+ case FID_PAGEBREAKMODE:
+ {
+ bool bWantPageBreak = nSlot == FID_PAGEBREAKMODE;
+
+ // check whether there is an explicit argument, use it
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
+ {
+ bool bItemValue = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ bWantPageBreak = (nSlot == FID_PAGEBREAKMODE) == bItemValue;
+ }
+
+ if( GetViewData().IsPagebreakMode() != bWantPageBreak )
+ {
+ SetPagebreakMode( bWantPageBreak );
+ UpdatePageBreakData();
+ SetCurSubShell( GetCurObjectSelectionType(), true );
+ PaintGrid();
+ PaintTop();
+ PaintLeft();
+ rBindings.Invalidate( nSlot );
+ rReq.AppendItem( SfxBoolItem( nSlot, true ) );
+ rReq.Done();
+ }
+ }
+ break;
+
+ case FID_FUNCTION_BOX:
+ {
+ // First make sure that the sidebar is visible
+ pThisFrame->ShowChildWindow(SID_SIDEBAR);
+
+ ::sfx2::sidebar::Sidebar::ShowPanel(u"ScFunctionsPanel",
+ pThisFrame->GetFrame().GetFrameInterface());
+ rReq.Done ();
+ }
+ break;
+
+ case FID_TOGGLESYNTAX:
+ {
+ bool bSet = !GetViewData().IsSyntaxMode();
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
+ bSet = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ GetViewData().SetSyntaxMode( bSet );
+ PaintGrid();
+ rBindings.Invalidate( FID_TOGGLESYNTAX );
+ rReq.AppendItem( SfxBoolItem( nSlot, bSet ) );
+ rReq.Done();
+ }
+ break;
+ case FID_TOGGLEHEADERS:
+ {
+ bool bSet = !GetViewData().IsHeaderMode();
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
+ bSet = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ GetViewData().SetHeaderMode( bSet );
+ RepeatResize();
+ rBindings.Invalidate( FID_TOGGLEHEADERS );
+ rReq.AppendItem( SfxBoolItem( nSlot, bSet ) );
+ rReq.Done();
+ }
+ break;
+
+ case FID_TOGGLEFORMULA:
+ {
+ ScViewData& rViewData = GetViewData();
+ const ScViewOptions& rOpts = rViewData.GetOptions();
+ bool bFormulaMode = !rOpts.GetOption( VOPT_FORMULAS );
+ const SfxPoolItem *pItem;
+ if( pReqArgs && pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
+ bFormulaMode = static_cast<const SfxBoolItem *>(pItem)->GetValue();
+
+ ScViewOptions aSetOpts = rOpts;
+ aSetOpts.SetOption( VOPT_FORMULAS, bFormulaMode );
+ rViewData.SetOptions( aSetOpts );
+
+ rViewData.GetDocShell()->PostPaintGridAll();
+
+ rBindings.Invalidate( FID_TOGGLEFORMULA );
+ rReq.AppendItem( SfxBoolItem( nSlot, bFormulaMode ) );
+ rReq.Done();
+ }
+ break;
+
+ case FID_TOGGLEINPUTLINE:
+ {
+ sal_uInt16 nId = ScInputWindowWrapper::GetChildWindowId();
+ SfxChildWindow* pWnd = pThisFrame->GetChildWindow( nId );
+ bool bSet = ( pWnd == nullptr );
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && pReqArgs->GetItemState(nSlot, true, &pItem) == SfxItemState::SET )
+ bSet = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ pThisFrame->SetChildWindow( nId, bSet );
+ rBindings.Invalidate( FID_TOGGLEINPUTLINE );
+ rReq.AppendItem( SfxBoolItem( nSlot, bSet ) );
+ rReq.Done();
+ }
+ break;
+
+ // handling for SID_ZOOM_IN and SID_ZOOM_OUT is ScTabView::ScrollCommand
+ // CommandWheelMode::ZOOM inspired
+ case SID_ZOOM_IN:
+ case SID_ZOOM_OUT:
+ {
+ HideNoteMarker();
+
+ if (!GetViewData().GetViewShell()->GetViewFrame()->GetFrame().IsInPlace())
+ {
+ // for ole inplace editing, the scale is defined by the visarea and client size
+ // and can't be changed directly
+
+ const Fraction& rOldY = GetViewData().GetZoomY();
+ tools::Long nOld = tools::Long(rOldY * 100);
+ tools::Long nNew;
+ if (SID_ZOOM_OUT == nSlot)
+ nNew = std::max(tools::Long(MINZOOM), basegfx::zoomtools::zoomOut(nOld));
+ else
+ nNew = std::min(tools::Long(MAXZOOM), basegfx::zoomtools::zoomIn(nOld));
+ if ( nNew != nOld)
+ {
+ bool bSyncZoom = SC_MOD()->GetAppOptions().GetSynchronizeZoom();
+ SetZoomType(SvxZoomType::PERCENT, bSyncZoom);
+ Fraction aFract(nNew, 100);
+ SetZoom(aFract, aFract, bSyncZoom);
+ PaintGrid();
+ PaintTop();
+ PaintLeft();
+ rBindings.Invalidate(SID_ATTR_ZOOM);
+ rBindings.Invalidate(SID_ATTR_ZOOMSLIDER);
+ rBindings.Invalidate(SID_ZOOM_IN);
+ rBindings.Invalidate(SID_ZOOM_OUT);
+ rReq.Done();
+ }
+ }
+ }
+ break;
+
+ case SID_ATTR_ZOOM: // status row
+ case FID_SCALE:
+ {
+ bool bSyncZoom = SC_MOD()->GetAppOptions().GetSynchronizeZoom();
+ SvxZoomType eOldZoomType = GetZoomType();
+ SvxZoomType eNewZoomType = eOldZoomType;
+ const Fraction& rOldY = GetViewData().GetZoomY(); // Y is shown
+ sal_uInt16 nOldZoom = static_cast<sal_uInt16>(tools::Long( rOldY * 100 ));
+ sal_uInt16 nZoom = nOldZoom;
+ bool bCancel = false;
+
+ if ( pReqArgs )
+ {
+ const SvxZoomItem& rZoomItem = pReqArgs->Get(SID_ATTR_ZOOM);
+
+ eNewZoomType = rZoomItem.GetType();
+ nZoom = rZoomItem.GetValue();
+ }
+ else
+ {
+ SfxItemSetFixed<SID_ATTR_ZOOM, SID_ATTR_ZOOM> aSet( GetPool() );
+ SvxZoomItem aZoomItem( eOldZoomType, nOldZoom, SID_ATTR_ZOOM );
+ ScopedVclPtr<AbstractSvxZoomDialog> pDlg;
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ SvxZoomEnableFlags nBtnFlags = SvxZoomEnableFlags::N50
+ | SvxZoomEnableFlags::N75
+ | SvxZoomEnableFlags::N100
+ | SvxZoomEnableFlags::N150
+ | SvxZoomEnableFlags::N200
+ | SvxZoomEnableFlags::WHOLEPAGE
+ | SvxZoomEnableFlags::PAGEWIDTH;
+
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ nBtnFlags = nBtnFlags | SvxZoomEnableFlags::OPTIMAL;
+
+ aZoomItem.SetValueSet( nBtnFlags );
+ aSet.Put( aZoomItem );
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ pDlg.disposeAndReset(pFact->CreateSvxZoomDialog(GetFrameWeld(), aSet));
+ pDlg->SetLimits( MINZOOM, MAXZOOM );
+
+ bCancel = ( RET_CANCEL == pDlg->Execute() );
+
+ // bCancel is True only if we were in the previous if block,
+ // so no need to check again pDlg
+ if ( !bCancel )
+ {
+ const SvxZoomItem& rZoomItem = pDlg->GetOutputItemSet()->
+ Get( SID_ATTR_ZOOM );
+
+ eNewZoomType = rZoomItem.GetType();
+ nZoom = rZoomItem.GetValue();
+ }
+ }
+
+ if ( !bCancel )
+ {
+ if ( eNewZoomType == SvxZoomType::PERCENT )
+ {
+ if ( nZoom < MINZOOM ) nZoom = MINZOOM;
+ if ( nZoom > MAXZOOM ) nZoom = MAXZOOM;
+ }
+ else
+ {
+ nZoom = CalcZoom( eNewZoomType, nOldZoom );
+ bCancel = nZoom == 0;
+ }
+
+ switch ( eNewZoomType )
+ {
+ case SvxZoomType::WHOLEPAGE:
+ case SvxZoomType::PAGEWIDTH:
+ SetZoomType( eNewZoomType, bSyncZoom );
+ break;
+
+ default:
+ SetZoomType( SvxZoomType::PERCENT, bSyncZoom );
+ }
+ }
+
+ if ( nZoom != nOldZoom && !bCancel )
+ {
+ if (!GetViewData().IsPagebreakMode())
+ {
+ ScAppOptions aNewOpt = pScMod->GetAppOptions();
+ aNewOpt.SetZoom( nZoom );
+ aNewOpt.SetZoomType( GetZoomType() );
+ pScMod->SetAppOptions( aNewOpt );
+ }
+ Fraction aFract( nZoom, 100 );
+ SetZoom( aFract, aFract, bSyncZoom );
+ PaintGrid();
+ PaintTop();
+ PaintLeft();
+ rBindings.Invalidate( SID_ATTR_ZOOM );
+ rReq.AppendItem( SvxZoomItem( GetZoomType(), nZoom, nSlot ) );
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_ATTR_ZOOMSLIDER:
+ {
+ const SfxPoolItem* pItem = nullptr;
+ bool bSyncZoom = SC_MOD()->GetAppOptions().GetSynchronizeZoom();
+ if ( pReqArgs && pReqArgs->GetItemState(SID_ATTR_ZOOMSLIDER, true, &pItem) == SfxItemState::SET )
+ {
+ const sal_uInt16 nCurrentZoom = static_cast<const SvxZoomSliderItem *>(pItem)->GetValue();
+ if( nCurrentZoom )
+ {
+ SetZoomType( SvxZoomType::PERCENT, bSyncZoom );
+ if (!GetViewData().IsPagebreakMode())
+ {
+ ScAppOptions aNewOpt = pScMod->GetAppOptions();
+ aNewOpt.SetZoom( nCurrentZoom );
+ collectUIInformation(OUString::number(nCurrentZoom));
+ aNewOpt.SetZoomType( GetZoomType() );
+ pScMod->SetAppOptions( aNewOpt );
+ }
+ Fraction aFract( nCurrentZoom,100 );
+ SetZoom( aFract, aFract, bSyncZoom );
+ PaintGrid();
+ PaintTop();
+ PaintLeft();
+ rBindings.Invalidate( SID_ATTR_ZOOMSLIDER );
+ rBindings.Invalidate( SID_ZOOM_IN );
+ rBindings.Invalidate( SID_ZOOM_OUT );
+ rReq.Done();
+ }
+ }
+ }
+ break;
+
+ case FID_TAB_SELECTALL:
+ SelectAllTables();
+ rReq.Done();
+ break;
+
+ case FID_TAB_DESELECTALL:
+ DeselectAllTables();
+ rReq.Done();
+ break;
+
+ case SID_SELECT_TABLES:
+ {
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScMarkData& rMark = rViewData.GetMarkData();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCTAB nTab;
+
+ ::std::vector < sal_Int32 > aIndexList;
+ const SfxIntegerListItem* pItem = rReq.GetArg<SfxIntegerListItem>(SID_SELECT_TABLES);
+ if ( pItem )
+ aIndexList = pItem->GetList();
+ else
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScShowTabDlg> pDlg(pFact->CreateScShowTabDlg(GetFrameWeld()));
+ pDlg->SetDescription(
+ ScResId( STR_DLG_SELECTTABLES_TITLE ),
+ ScResId( STR_DLG_SELECTTABLES_LBNAME ),
+ GetStaticInterface()->GetSlot(SID_SELECT_TABLES)->GetCommand(), HID_SELECTTABLES );
+
+ // fill all table names with selection state
+ OUString aTabName;
+ for( nTab = 0; nTab < nTabCount; ++nTab )
+ {
+ rDoc.GetName( nTab, aTabName );
+ pDlg->Insert( aTabName, rMark.GetTableSelect( nTab ) );
+ }
+
+ if( pDlg->Execute() == RET_OK )
+ {
+ aIndexList = pDlg->GetSelectedRows();
+ pDlg.disposeAndClear();
+ rReq.AppendItem( SfxIntegerListItem( SID_SELECT_TABLES, std::vector(aIndexList) ) );
+ }
+ else
+ rReq.Ignore();
+ }
+
+ if ( !aIndexList.empty() )
+ {
+ sal_uInt16 nSelCount = aIndexList.size();
+ sal_uInt16 nSelIx;
+ SCTAB nFirstVisTab = 0;
+
+ // special case: only hidden tables selected -> do nothing
+ bool bVisSelected = false;
+ for( nSelIx = 0; !bVisSelected && (nSelIx < nSelCount); ++nSelIx )
+ {
+ nFirstVisTab = static_cast<SCTAB>(aIndexList[nSelIx]);
+ bVisSelected = rDoc.IsVisible( nFirstVisTab );
+ }
+ if( !bVisSelected )
+ nSelCount = 0;
+
+ // select the tables
+ if( nSelCount )
+ {
+ for( nTab = 0; nTab < nTabCount; ++nTab )
+ rMark.SelectTable( nTab, false );
+
+ for( nSelIx = 0; nSelIx < nSelCount; ++nSelIx )
+ rMark.SelectTable( static_cast<SCTAB>(aIndexList[nSelIx]), true );
+
+ // activate another table, if current is deselected
+ if( !rMark.GetTableSelect( rViewData.GetTabNo() ) )
+ {
+ rMark.SelectTable( nFirstVisTab, true );
+ SetTabNo( nFirstVisTab );
+ }
+
+ rViewData.GetDocShell()->PostPaintExtras();
+ SfxBindings& rBind = rViewData.GetBindings();
+ rBind.Invalidate( FID_FILL_TAB );
+ rBind.Invalidate( FID_TAB_DESELECTALL );
+ }
+
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_OUTLINE_DELETEALL:
+ RemoveAllOutlines();
+ rReq.Done();
+ break;
+
+ case SID_AUTO_OUTLINE:
+ AutoOutline();
+ rReq.Done();
+ break;
+
+ case SID_WINDOW_SPLIT:
+ {
+ ScSplitMode eHSplit = GetViewData().GetHSplitMode();
+ ScSplitMode eVSplit = GetViewData().GetVSplitMode();
+ if ( eHSplit == SC_SPLIT_NORMAL || eVSplit == SC_SPLIT_NORMAL ) // remove
+ RemoveSplit();
+ else if ( eHSplit == SC_SPLIT_FIX || eVSplit == SC_SPLIT_FIX ) // normal
+ FreezeSplitters( false );
+ else // create
+ SplitAtCursor();
+ rReq.Done();
+
+ InvalidateSplit();
+ }
+ break;
+
+ case SID_WINDOW_FIX:
+ {
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ ScSplitMode eHSplit = GetViewData().GetHSplitMode();
+ ScSplitMode eVSplit = GetViewData().GetVSplitMode();
+ if ( eHSplit == SC_SPLIT_FIX || eVSplit == SC_SPLIT_FIX ) // remove
+ RemoveSplit();
+ else
+ FreezeSplitters( true, SC_SPLIT_METHOD_CURSOR); // create or fixate
+ rReq.Done();
+ InvalidateSplit();
+ }
+ else
+ {
+ ScViewData& rViewData = GetViewData();
+ SCTAB nThisTab = rViewData.GetTabNo();
+ bool bChangedX = false, bChangedY = false;
+ if (rViewData.GetLOKSheetFreezeIndex(true) > 0 ||
+ rViewData.GetLOKSheetFreezeIndex(false) > 0 ) // remove freeze
+ {
+ bChangedX = rViewData.RemoveLOKFreeze();
+ } // create or fixate
+ else
+ {
+ bChangedX = rViewData.SetLOKSheetFreezeIndex(rViewData.GetCurX(), true); // Freeze column
+ bChangedY = rViewData.SetLOKSheetFreezeIndex(rViewData.GetCurY(), false); // Freeze row
+ }
+
+ rReq.Done();
+ if (bChangedX || bChangedY)
+ {
+ rBindings.Invalidate( SID_WINDOW_FIX );
+ rBindings.Invalidate( SID_WINDOW_FIX_COL );
+ rBindings.Invalidate( SID_WINDOW_FIX_ROW );
+ // Invalidate the slot for all views on the same tab of the document.
+ SfxLokHelper::forEachOtherView(this, [nThisTab](ScTabViewShell* pOther) {
+ ScViewData& rOtherViewData = pOther->GetViewData();
+ if (rOtherViewData.GetTabNo() != nThisTab)
+ return;
+
+ SfxBindings& rOtherBind = rOtherViewData.GetBindings();
+ rOtherBind.Invalidate( SID_WINDOW_FIX );
+ rOtherBind.Invalidate( SID_WINDOW_FIX_COL );
+ rOtherBind.Invalidate( SID_WINDOW_FIX_ROW );
+ });
+ if (!GetViewData().GetDocShell()->IsReadOnly())
+ GetViewData().GetDocShell()->SetDocumentModified();
+ }
+ }
+ }
+ break;
+
+ case SID_WINDOW_FIX_COL:
+ case SID_WINDOW_FIX_ROW:
+ {
+ bool bIsCol = (nSlot == SID_WINDOW_FIX_COL);
+ sal_Int32 nFreezeIndex = 1;
+ if (const SfxInt32Item* pItem = rReq.GetArg<SfxInt32Item>(nSlot))
+ {
+ nFreezeIndex = pItem->GetValue();
+ if (nFreezeIndex < 0)
+ nFreezeIndex = 0;
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScViewData& rViewData = GetViewData();
+ SCTAB nThisTab = rViewData.GetTabNo();
+ bool bChanged = rViewData.SetLOKSheetFreezeIndex(nFreezeIndex, bIsCol);
+ rReq.Done();
+ if (bChanged)
+ {
+ rBindings.Invalidate( SID_WINDOW_FIX );
+ rBindings.Invalidate(nSlot);
+ // Invalidate the slot for all views on the same tab of the document.
+ SfxLokHelper::forEachOtherView(this, [nSlot, nThisTab](ScTabViewShell* pOther) {
+ ScViewData& rOtherViewData = pOther->GetViewData();
+ if (rOtherViewData.GetTabNo() != nThisTab)
+ return;
+
+ SfxBindings& rOtherBind = rOtherViewData.GetBindings();
+ rOtherBind.Invalidate( SID_WINDOW_FIX );
+ rOtherBind.Invalidate(nSlot);
+ });
+ if (!GetViewData().GetDocShell()->IsReadOnly())
+ GetViewData().GetDocShell()->SetDocumentModified();
+ }
+ }
+ else
+ {
+ FreezeSplitters( true, bIsCol ? SC_SPLIT_METHOD_COL : SC_SPLIT_METHOD_ROW, nFreezeIndex);
+ rReq.Done();
+ InvalidateSplit();
+ }
+ }
+ break;
+
+ case FID_CHG_SHOW:
+ {
+ sal_uInt16 nId = ScHighlightChgDlgWrapper::GetChildWindowId();
+ SfxChildWindow* pWnd = pThisFrame->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd == nullptr );
+ }
+ break;
+
+ case FID_CHG_ACCEPT:
+ {
+ pThisFrame->ToggleChildWindow(ScAcceptChgDlgWrapper::GetChildWindowId());
+ GetViewFrame()->GetBindings().Invalidate(FID_CHG_ACCEPT);
+ rReq.Done ();
+
+ /*
+ sal_uInt16 nId = ScAcceptChgDlgWrapper::GetChildWindowId();
+ SfxChildWindow* pWnd = pThisFrame->GetChildWindow( nId );
+
+ pScMod->SetRefDialog( nId, pWnd ? sal_False : sal_True );
+ */
+ }
+ break;
+
+ case FID_CHG_COMMENT:
+ {
+ ScViewData& rData = GetViewData();
+ ScAddress aCursorPos( rData.GetCurX(), rData.GetCurY(), rData.GetTabNo() );
+ ScDocShell* pDocSh = rData.GetDocShell();
+
+ ScChangeAction* pAction = pDocSh->GetChangeAction( aCursorPos );
+ if ( pAction )
+ {
+ const SfxPoolItem* pItem;
+ if ( pReqArgs &&
+ pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET &&
+ dynamic_cast<const SfxStringItem*>( pItem) != nullptr )
+ {
+ OUString aComment = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ pDocSh->SetChangeComment( pAction, aComment );
+ rReq.Done();
+ }
+ else
+ {
+ pDocSh->ExecuteChangeCommentDialog(pAction, GetFrameWeld());
+ rReq.Done();
+ }
+ }
+ }
+ break;
+
+ case SID_CREATE_SW_DRAWVIEW:
+ // is called by Forms, when the DrawView has to be created with all
+ // the extras
+ if (!GetScDrawView())
+ {
+ GetViewData().GetDocShell()->MakeDrawLayer();
+ rBindings.InvalidateAll(false);
+ }
+ break;
+
+ case FID_PROTECT_DOC:
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ if( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ if( pReqArgs->HasItem( FID_PROTECT_DOC, &pItem ) &&
+ static_cast<const SfxBoolItem*>(pItem)->GetValue() == rDoc.IsDocProtected() )
+ {
+ rReq.Ignore();
+ break;
+ }
+ }
+
+ ScDocProtection* pProtect = rDoc.GetDocProtection();
+ if (pProtect && pProtect->isProtected())
+ {
+ bool bCancel = false;
+ OUString aPassword;
+
+ if (pProtect->isProtectedWithPass())
+ {
+ OUString aText(ScResId(SCSTR_PASSWORD));
+
+ SfxPasswordDialog aDlg(GetFrameWeld(), &aText);
+ aDlg.set_title(ScResId(SCSTR_UNPROTECTDOC));
+ aDlg.SetMinLen(0);
+ aDlg.set_help_id(GetStaticInterface()->GetSlot(FID_PROTECT_DOC)->GetCommand());
+ aDlg.SetEditHelpId(HID_PASSWD_DOC);
+
+ if (aDlg.run() == RET_OK)
+ aPassword = aDlg.GetPassword();
+ else
+ bCancel = true;
+ }
+ if (!bCancel)
+ {
+ Unprotect( TABLEID_DOC, aPassword );
+ rReq.AppendItem( SfxBoolItem( FID_PROTECT_DOC, false ) );
+ rReq.Done();
+ }
+ }
+ else
+ {
+ OUString aText(ScResId(SCSTR_PASSWORDOPT));
+
+ SfxPasswordDialog aDlg(GetFrameWeld(), &aText);
+ aDlg.set_title(ScResId(SCSTR_PROTECTDOC));
+ aDlg.SetMinLen( 0 );
+ aDlg.set_help_id(GetStaticInterface()->GetSlot(FID_PROTECT_DOC)->GetCommand());
+ aDlg.SetEditHelpId(HID_PASSWD_DOC);
+ aDlg.ShowExtras(SfxShowExtras::CONFIRM);
+ aDlg.SetConfirmHelpId(HID_PASSWD_DOC_CONFIRM);
+
+ if (aDlg.run() == RET_OK)
+ {
+ OUString aPassword = aDlg.GetPassword();
+ ProtectDoc( aPassword );
+ rReq.AppendItem( SfxBoolItem( FID_PROTECT_DOC, true ) );
+ rReq.Done();
+ }
+ }
+ rBindings.Invalidate( FID_PROTECT_DOC );
+ }
+ break;
+
+ case FID_PROTECT_TABLE:
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ bool bOldProtection = rDoc.IsTabProtected(nTab);
+
+ if( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ bool bNewProtection = !bOldProtection;
+ if( pReqArgs->HasItem( FID_PROTECT_TABLE, &pItem ) )
+ bNewProtection = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ if( bNewProtection == bOldProtection )
+ {
+ rReq.Ignore();
+ break;
+ }
+ }
+
+ if (bOldProtection)
+ {
+ // Unprotect a protected sheet.
+
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ if (pProtect && pProtect->isProtectedWithPass())
+ {
+ OUString aText( ScResId(SCSTR_PASSWORDOPT) );
+ SfxPasswordDialog aDlg(GetFrameWeld(), &aText);
+ aDlg.set_title(ScResId(SCSTR_UNPROTECTTAB));
+ aDlg.SetMinLen(0);
+ aDlg.set_help_id(GetStaticInterface()->GetSlot(FID_PROTECT_TABLE)->GetCommand());
+ aDlg.SetEditHelpId(HID_PASSWD_TABLE);
+
+ if (aDlg.run() == RET_OK)
+ {
+ OUString aPassword = aDlg.GetPassword();
+ Unprotect(nTab, aPassword);
+ }
+ }
+ else
+ // this sheet is not password-protected.
+ Unprotect(nTab, OUString());
+
+ if (!pReqArgs)
+ {
+ rReq.AppendItem( SfxBoolItem(FID_PROTECT_TABLE, false) );
+ rReq.Done();
+ }
+ }
+ else
+ {
+ // Protect a current sheet.
+
+ ScTableProtectionDlg aDlg(GetFrameWeld());
+
+ const ScTableProtection* pProtect = rDoc.GetTabProtection(nTab);
+ if (pProtect)
+ aDlg.SetDialogData(*pProtect);
+
+ if (aDlg.run() == RET_OK)
+ {
+ pScMod->InputEnterHandler();
+
+ ScTableProtection aNewProtect;
+ aDlg.WriteData(aNewProtect);
+ ProtectSheet(nTab, aNewProtect);
+ if (!pReqArgs)
+ {
+ rReq.AppendItem( SfxBoolItem(FID_PROTECT_TABLE, true) );
+ rReq.Done();
+ }
+ }
+ }
+ TabChanged();
+ UpdateInputHandler(true); // to immediately enable input again
+ SelectionChanged();
+ }
+ break;
+
+ case SID_OPT_LOCALE_CHANGED :
+ { // locale changed, SYSTEM number formats changed => repaint cell contents
+ PaintGrid();
+ rReq.Done();
+ }
+ break;
+
+ default:
+ OSL_FAIL("Unknown Slot at ScTabViewShell::Execute");
+ break;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwsh4.cxx b/sc/source/ui/view/tabvwsh4.cxx
new file mode 100644
index 000000000..edf1c5c3e
--- /dev/null
+++ b/sc/source/ui/view/tabvwsh4.cxx
@@ -0,0 +1,1942 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <formdata.hxx>
+
+#include <sfx2/app.hxx>
+#include <svx/dialogs.hrc>
+#include <svx/extrusionbar.hxx>
+#include <svx/fontworkbar.hxx>
+#include <editeng/borderline.hxx>
+#include <svx/fmshell.hxx>
+#include <svx/sidebar/ContextChangeEventMultiplexer.hxx>
+#include <sfx2/printer.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/ipclient.hxx>
+#include <tools/urlobj.hxx>
+#include <sfx2/docfile.hxx>
+#include <tools/svborder.hxx>
+
+#include <IAnyRefDialog.hxx>
+#include <tabvwsh.hxx>
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <docsh.hxx>
+#include <scmod.hxx>
+#include <appoptio.hxx>
+#include <drawsh.hxx>
+#include <drformsh.hxx>
+#include <editsh.hxx>
+#include <pivotsh.hxx>
+#include <SparklineShell.hxx>
+#include <auditsh.hxx>
+#include <drtxtob.hxx>
+#include <inputhdl.hxx>
+#include <editutil.hxx>
+#include <inputopt.hxx>
+#include <inputwin.hxx>
+#include <dbdata.hxx>
+#include <reffact.hxx>
+#include <viewuno.hxx>
+#include <dispuno.hxx>
+#include <chgtrack.hxx>
+#include <cellsh.hxx>
+#include <oleobjsh.hxx>
+#include <chartsh.hxx>
+#include <graphsh.hxx>
+#include <mediash.hxx>
+#include <pgbrksh.hxx>
+#include <dpobject.hxx>
+#include <prevwsh.hxx>
+#include <scextopt.hxx>
+#include <drawview.hxx>
+#include <fupoor.hxx>
+#include <navsett.hxx>
+#include <scabstdlg.hxx>
+#include <externalrefmgr.hxx>
+#include <defaultsoptions.hxx>
+#include <markdata.hxx>
+#include <preview.hxx>
+#include <docoptio.hxx>
+#include <documentlinkmgr.hxx>
+#include <gridwin.hxx>
+
+#include <com/sun/star/document/XDocumentProperties.hpp>
+#include <sfx2/lokhelper.hxx>
+#include <comphelper/flagguard.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <sfx2/sidebar/SidebarController.hxx>
+
+using namespace com::sun::star;
+using namespace sfx2::sidebar;
+
+namespace {
+
+bool inChartContext(const ScTabViewShell* pViewShell)
+{
+ SidebarController* pSidebar = SidebarController::GetSidebarControllerForView(pViewShell);
+ if (pSidebar)
+ return pSidebar->hasChartContextCurrently();
+
+ return false;
+}
+
+} // anonymous namespace
+
+void ScTabViewShell::Activate(bool bMDI)
+{
+ SfxViewShell::Activate(bMDI);
+ bIsActive = true;
+ // here no GrabFocus, otherwise there will be problems when something is edited inplace!
+
+ if ( bMDI )
+ {
+ // for input row (ClearCache)
+ ScModule* pScMod = SC_MOD();
+ pScMod->ViewShellChanged(/*bStopEditing=*/ !comphelper::LibreOfficeKit::isActive());
+
+ ActivateView( true, bFirstActivate );
+
+ // update AutoCorrect, if Writer has newly created this
+ UpdateDrawTextOutliner();
+
+ // RegisterNewTargetNames does not exist anymore
+
+ SfxViewFrame* pThisFrame = GetViewFrame();
+ if ( mpInputHandler && pThisFrame->HasChildWindow(FID_INPUTLINE_STATUS) )
+ {
+ // actually only required for Reload (last version):
+ // The InputWindow remains, but the View along with the InputHandler is newly created,
+ // that is why the InputHandler must be set at the InputWindow.
+ SfxChildWindow* pChild = pThisFrame->GetChildWindow(FID_INPUTLINE_STATUS);
+ if (pChild)
+ {
+ ScInputWindow* pWin = static_cast<ScInputWindow*>(pChild->GetWindow());
+ if (pWin && pWin->IsVisible())
+ {
+ pWin->NumLinesChanged(); // tdf#150664
+ ScInputHandler* pOldHdl=pWin->GetInputHandler();
+
+ SfxViewShell* pSh = SfxViewShell::GetFirst( true, checkSfxViewShell<ScTabViewShell> );
+ while ( pSh!=nullptr && pOldHdl!=nullptr)
+ {
+ // Hmm, what if pSh is a shell for a different document? But as this code
+ // does not seem to be LibreOfficeKit-specific, probably that doesn't
+ // happen, because having multiple documents open simultaneously has of
+ // course not been a problem at all in traditional desktop LibreOffice.
+ // (Unlike in a LibreOfficeKit-based process where it has been a problem.)
+ if (static_cast<ScTabViewShell*>(pSh)->GetInputHandler() == pOldHdl)
+ {
+ pOldHdl->ResetDelayTimer();
+ break;
+ }
+ pSh = SfxViewShell::GetNext( *pSh, true, checkSfxViewShell<ScTabViewShell> );
+ }
+
+ pWin->SetInputHandler( mpInputHandler.get() );
+ }
+ }
+ }
+
+ UpdateInputHandler( /*bForce=*/ true, /*bStopEditing=*/ !comphelper::LibreOfficeKit::isActive() );
+
+ if ( bFirstActivate )
+ {
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScNavigatorUpdateAll ) );
+ bFirstActivate = false;
+
+ // ReadExtOptions (view settings from Excel import) must also be done
+ // after the ctor, because of the potential calls to Window::Show.
+ // Even after a bugfix (Window::Show no longer notifies the access
+ // bridge, it's done in ImplSetReallyVisible), there are problems if Window::Show
+ // is called during the ViewShell ctor and reschedules asynchronous calls
+ // (for example from the FmFormShell ctor).
+ ScExtDocOptions* pExtOpt = GetViewData().GetDocument().GetExtDocOptions();
+ if ( pExtOpt && pExtOpt->IsChanged() )
+ {
+ GetViewData().ReadExtOptions(*pExtOpt); // Excel view settings
+ SetTabNo( GetViewData().GetTabNo(), true );
+ pExtOpt->SetChanged( false );
+ }
+ }
+
+ pScActiveViewShell = this;
+
+ ScInputHandler* pHdl = pScMod->GetInputHdl(this);
+ if (pHdl)
+ {
+ pHdl->SetRefScale( GetViewData().GetZoomX(), GetViewData().GetZoomY() );
+ }
+
+ // update change dialog
+
+ if ( pThisFrame->HasChildWindow(FID_CHG_ACCEPT) )
+ {
+ SfxChildWindow* pChild = pThisFrame->GetChildWindow(FID_CHG_ACCEPT);
+ if (pChild)
+ {
+ static_cast<ScAcceptChgDlgWrapper*>(pChild)->ReInitDlg();
+ }
+ }
+
+ if(pScMod->IsRefDialogOpen())
+ {
+ sal_uInt16 nModRefDlgId=pScMod->GetCurRefDlgId();
+ SfxChildWindow* pChildWnd = pThisFrame->GetChildWindow( nModRefDlgId );
+ if ( pChildWnd )
+ {
+ if (auto pController = pChildWnd->GetController())
+ {
+ IAnyRefDialog* pRefDlg = dynamic_cast<IAnyRefDialog*>(pController.get());
+ if (pRefDlg)
+ pRefDlg->ViewShellChanged();
+ }
+ }
+ }
+ }
+
+ // don't call CheckSelectionTransfer here - activating a view should not change the
+ // primary selection (may be happening just because the mouse was moved over the window)
+
+ if (!inChartContext(this))
+ {
+ ContextChangeEventMultiplexer::NotifyContextChange(
+ GetController(),
+ vcl::EnumContext::Context::Default);
+ }
+}
+
+void ScTabViewShell::Deactivate(bool bMDI)
+{
+ HideTip();
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ ScChangeTrack* pChanges = rDoc.GetChangeTrack();
+
+ if(pChanges!=nullptr)
+ {
+ Link<ScChangeTrack&,void> aLink;
+ pChanges->SetModifiedLink(aLink);
+ }
+
+ SfxViewShell::Deactivate(bMDI);
+ bIsActive = false;
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl(this);
+
+ if( bMDI && !comphelper::LibreOfficeKit::isActive())
+ {
+ // during shell deactivation, shells must not be switched, or the loop
+ // through the shell stack (in SfxDispatcher::DoDeactivate_Impl) will not work
+ bool bOldDontSwitch = bDontSwitch;
+ bDontSwitch = true;
+
+ ActivateView( false, false );
+
+ if ( GetViewFrame()->GetFrame().IsInPlace() ) // inplace
+ GetViewData().GetDocShell()->UpdateOle(GetViewData(), true);
+
+ if ( pHdl )
+ pHdl->NotifyChange( nullptr, true ); // timer-delayed due to document switching
+
+ if (pScActiveViewShell == this)
+ pScActiveViewShell = nullptr;
+
+ bDontSwitch = bOldDontSwitch;
+ }
+ else
+ {
+ HideNoteMarker(); // note marker
+
+ if ( pHdl )
+ pHdl->HideTip(); // Hide formula auto input tip
+ }
+}
+
+void ScTabViewShell::SetActive()
+{
+ // SFX-View would like to activate itself, since then magical things would happen
+ // (eg else the designer may crash)
+ ActiveGrabFocus();
+}
+
+bool ScTabViewShell::PrepareClose(bool bUI)
+{
+ comphelper::FlagRestorationGuard aFlagGuard(bInPrepareClose, true);
+
+ // Call EnterHandler even in formula mode here,
+ // so a formula change in an embedded object isn't lost
+ // (ScDocShell::PrepareClose isn't called then).
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl( this );
+ if ( pHdl && pHdl->IsInputMode() )
+ {
+ pHdl->EnterHandler();
+ }
+
+ // draw text edit mode must be closed
+ FuPoor* pPoor = GetDrawFuncPtr();
+ if (pPoor && IsDrawTextShell())
+ {
+ // "clean" end of text edit, including note handling, subshells and draw func switching,
+ // as in FuDraw and ScTabView::DrawDeselectAll
+ GetViewData().GetDispatcher().Execute( pPoor->GetSlotID(), SfxCallMode::SLOT | SfxCallMode::RECORD );
+ }
+ ScDrawView* pDrView = GetScDrawView();
+ if ( pDrView )
+ {
+ // force end of text edit, to be safe
+ // ScEndTextEdit must always be used, to ensure correct UndoManager
+ pDrView->ScEndTextEdit();
+ }
+
+ if ( pFormShell )
+ {
+ bool bRet = pFormShell->PrepareClose(bUI);
+ if (!bRet)
+ return bRet;
+ }
+ return SfxViewShell::PrepareClose(bUI);
+}
+
+// calculate zoom for in-place
+// from the ratio of VisArea and window size of GridWin
+
+void ScTabViewShell::UpdateOleZoom()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ if ( pDocSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
+ {
+ //TODO/LATER: is there a difference between the two GetVisArea methods?
+ Size aObjSize = static_cast<const SfxObjectShell*>(pDocSh)->GetVisArea().GetSize();
+ if ( !aObjSize.IsEmpty() )
+ {
+ vcl::Window* pWin = GetActiveWin();
+ Size aWinHMM = pWin->PixelToLogic(pWin->GetOutputSizePixel(), MapMode(MapUnit::Map100thMM));
+ SetZoomFactor( Fraction( aWinHMM.Width(),aObjSize.Width() ),
+ Fraction( aWinHMM.Height(),aObjSize.Height() ) );
+ }
+ }
+}
+
+void ScTabViewShell::InnerResizePixel( const Point &rOfs, const Size &rSize, bool inplaceEditModeChange )
+{
+ Size aNewSize( rSize );
+ if ( GetViewFrame()->GetFrame().IsInPlace() )
+ {
+ SvBorder aBorder;
+ GetBorderSize( aBorder, rSize );
+ SetBorderPixel( aBorder );
+
+ Size aObjSize = GetObjectShell()->GetVisArea().GetSize();
+
+ Size aSize( rSize );
+ aSize.AdjustWidth( -(aBorder.Left() + aBorder.Right()) );
+ aSize.AdjustHeight( -(aBorder.Top() + aBorder.Bottom()) );
+
+ if ( !aObjSize.IsEmpty() )
+ {
+ Size aLogicSize = GetWindow()->PixelToLogic(aSize, MapMode(MapUnit::Map100thMM));
+ SfxViewShell::SetZoomFactor( Fraction( aLogicSize.Width(),aObjSize.Width() ),
+ Fraction( aLogicSize.Height(),aObjSize.Height() ) );
+ }
+
+ Point aPos( rOfs );
+ aPos.AdjustX(aBorder.Left() );
+ aPos.AdjustY(aBorder.Top() );
+ GetWindow()->SetPosSizePixel( aPos, aSize );
+ }
+ else
+ {
+ SvBorder aBorder;
+ GetBorderSize( aBorder, rSize );
+ SetBorderPixel( aBorder );
+ aNewSize.AdjustWidth(aBorder.Left() + aBorder.Right() );
+ aNewSize.AdjustHeight(aBorder.Top() + aBorder.Bottom() );
+ }
+
+ DoResize( rOfs, aNewSize, true ); // rSize = size of gridwin
+
+ UpdateOleZoom(); // calculate zoom for in-place
+
+ if (!inplaceEditModeChange)
+ {
+ GetViewData().GetDocShell()->SetDocumentModified();
+ }
+}
+
+void ScTabViewShell::OuterResizePixel( const Point &rOfs, const Size &rSize )
+{
+ SvBorder aBorder;
+ GetBorderSize( aBorder, rSize );
+ SetBorderPixel( aBorder );
+
+ DoResize( rOfs, rSize ); // position and size of tabview as passed
+
+ // ForceMove as replacement for Sfx-Move mechanism
+ // (aWinPos must be kept current, so that ForceMove works for Ole deactivation)
+
+ ForceMove();
+}
+
+void ScTabViewShell::SetZoomFactor( const Fraction &rZoomX, const Fraction &rZoomY )
+{
+ // for OLE...
+
+ Fraction aFrac20( 1,5 );
+ Fraction aFrac400( 4,1 );
+
+ Fraction aNewX( rZoomX );
+ if ( aNewX < aFrac20 )
+ aNewX = aFrac20;
+ if ( aNewX > aFrac400 )
+ aNewX = aFrac400;
+ Fraction aNewY( rZoomY );
+ if ( aNewY < aFrac20 )
+ aNewY = aFrac20;
+ if ( aNewY > aFrac400 )
+ aNewY = aFrac400;
+
+ GetViewData().UpdateScreenZoom( aNewX, aNewY );
+ SetZoom( aNewX, aNewY, true );
+
+ PaintGrid();
+ PaintTop();
+ PaintLeft();
+
+ SfxViewShell::SetZoomFactor( rZoomX, rZoomY );
+}
+
+void ScTabViewShell::QueryObjAreaPixel( tools::Rectangle& rRect ) const
+{
+ // adjust to entire cells (in 1/100 mm)
+
+ Size aPixelSize = rRect.GetSize();
+ vcl::Window* pWin = const_cast<ScTabViewShell*>(this)->GetActiveWin();
+ Size aLogicSize = pWin->PixelToLogic( aPixelSize );
+
+ const ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScSplitPos ePos = rViewData.GetActivePart();
+ SCCOL nCol = rViewData.GetPosX(WhichH(ePos));
+ SCROW nRow = rViewData.GetPosY(WhichV(ePos));
+ SCTAB nTab = rViewData.GetTabNo();
+ bool bNegativePage = rDoc.IsNegativePage( nTab );
+
+ tools::Rectangle aLogicRect = rDoc.GetMMRect( nCol, nRow, nCol, nRow, nTab );
+ if ( bNegativePage )
+ {
+ // use right edge of aLogicRect, and aLogicSize
+ aLogicRect.SetLeft( aLogicRect.Right() - aLogicSize.Width() + 1 ); // Right() is set below
+ }
+ aLogicRect.SetSize( aLogicSize );
+
+ rViewData.GetDocShell()->SnapVisArea( aLogicRect );
+
+ rRect.SetSize( pWin->LogicToPixel( aLogicRect.GetSize() ) );
+}
+
+void ScTabViewShell::Move()
+{
+ Point aNewPos = GetViewFrame()->GetWindow().OutputToScreenPixel(Point());
+
+ if (aNewPos != aWinPos)
+ {
+ StopMarking();
+ aWinPos = aNewPos;
+ }
+}
+
+void ScTabViewShell::ShowCursor(bool /* bOn */)
+{
+/*!!! ShowCursor is not called as a pair as in gridwin.
+ here the CursorLockCount for Gridwin must be set directly to 0
+
+ if (bOn)
+ ShowAllCursors();
+ else
+ HideAllCursors();
+*/
+}
+
+void ScTabViewShell::WriteUserData(OUString& rData, bool /* bBrowse */)
+{
+ GetViewData().WriteUserData(rData);
+}
+
+void ScTabViewShell::WriteUserDataSequence (uno::Sequence < beans::PropertyValue >& rSettings )
+{
+ GetViewData().WriteUserDataSequence(rSettings);
+}
+
+void ScTabViewShell::ReadUserData(const OUString& rData, bool /* bBrowse */)
+{
+ if ( !GetViewData().GetDocShell()->IsPreview() )
+ DoReadUserData( rData );
+}
+
+void ScTabViewShell::ReadUserDataSequence (const uno::Sequence < beans::PropertyValue >& rSettings )
+{
+ if ( !GetViewData().GetDocShell()->IsPreview() )
+ DoReadUserDataSequence( rSettings );
+}
+
+void ScTabViewShell::DoReadUserDataSequence( const uno::Sequence < beans::PropertyValue >& rSettings )
+{
+ vcl::Window* pOldWin = GetActiveWin();
+ bool bFocus = pOldWin && pOldWin->HasFocus();
+
+ GetViewData().ReadUserDataSequence(rSettings);
+ SetTabNo( GetViewData().GetTabNo(), true );
+
+ if ( GetViewData().IsPagebreakMode() )
+ SetCurSubShell( GetCurObjectSelectionType(), true );
+
+ vcl::Window* pNewWin = GetActiveWin();
+ if (pNewWin && pNewWin != pOldWin)
+ {
+ SetWindow( pNewWin ); //! is this ViewShell always active???
+ if (bFocus)
+ pNewWin->GrabFocus();
+ WindowChanged(); // drawing layer (for instance #56771#)
+ }
+
+ if (GetViewData().GetHSplitMode() == SC_SPLIT_FIX ||
+ GetViewData().GetVSplitMode() == SC_SPLIT_FIX)
+ {
+ InvalidateSplit();
+ }
+
+ ZoomChanged();
+
+ TestHintWindow();
+
+ //! if ViewData has more tables than document, remove tables in ViewData
+}
+
+// DoReadUserData is also called from ctor when switching from print preview
+
+void ScTabViewShell::DoReadUserData( std::u16string_view rData )
+{
+ vcl::Window* pOldWin = GetActiveWin();
+ bool bFocus = pOldWin && pOldWin->HasFocus();
+
+ GetViewData().ReadUserData(rData);
+ SetTabNo( GetViewData().GetTabNo(), true );
+
+ if ( GetViewData().IsPagebreakMode() )
+ SetCurSubShell( GetCurObjectSelectionType(), true );
+
+ vcl::Window* pNewWin = GetActiveWin();
+ if (pNewWin && pNewWin != pOldWin)
+ {
+ SetWindow( pNewWin ); //! is this ViewShell always active???
+ if (bFocus)
+ pNewWin->GrabFocus();
+ WindowChanged(); // drawing layer (for instance #56771#)
+ }
+
+ if (GetViewData().GetHSplitMode() == SC_SPLIT_FIX ||
+ GetViewData().GetVSplitMode() == SC_SPLIT_FIX)
+ {
+ InvalidateSplit();
+ }
+
+ ZoomChanged();
+
+ TestHintWindow();
+
+ //! if ViewData has more tables than document, remove tables in ViewData
+}
+
+void ScTabViewShell::UpdateDrawShell()
+{
+ // Called after user interaction that may delete the selected drawing object.
+ // Remove DrawShell if nothing is selected.
+
+ SdrView* pDrView = GetScDrawView();
+ if ( pDrView && !pDrView->AreObjectsMarked() && !IsDrawSelMode() )
+ SetDrawShell( false );
+}
+
+void ScTabViewShell::SetDrawShellOrSub()
+{
+ bActiveDrawSh = true;
+
+ if(bActiveDrawFormSh)
+ {
+ SetCurSubShell(OST_DrawForm);
+ }
+ else if(bActiveGraphicSh)
+ {
+ SetCurSubShell(OST_Graphic);
+ }
+ else if(bActiveMediaSh)
+ {
+ SetCurSubShell(OST_Media);
+ }
+ else if(bActiveChartSh)
+ {
+ SetCurSubShell(OST_Chart);
+ }
+ else if(bActiveOleObjectSh)
+ {
+ SetCurSubShell(OST_OleObject);
+ }
+ else
+ {
+ SetCurSubShell(OST_Drawing, true /* force: different toolbars are
+ visible concerning shape type
+ and shape state */);
+ }
+}
+
+void ScTabViewShell::SetDrawShell( bool bActive )
+{
+ if(bActive)
+ {
+ SetCurSubShell(OST_Drawing, true /* force: different toolbars are
+ visible concerning shape type
+ and shape state */);
+ }
+ else
+ {
+ if(bActiveDrawFormSh || bActiveDrawSh ||
+ bActiveGraphicSh || bActiveMediaSh || bActiveOleObjectSh||
+ bActiveChartSh || bActiveDrawTextSh)
+ {
+ SetCurSubShell(OST_Cell);
+ }
+ bActiveDrawFormSh=false;
+ bActiveGraphicSh=false;
+ bActiveMediaSh=false;
+ bActiveOleObjectSh=false;
+ bActiveChartSh=false;
+ }
+
+ bool bWasDraw = bActiveDrawSh || bActiveDrawTextSh;
+
+ bActiveDrawSh = bActive;
+ bActiveDrawTextSh = false;
+
+ if ( !bActive )
+ {
+ ResetDrawDragMode(); // switch off Mirror / Rotate
+
+ if (bWasDraw && (GetViewData().GetHSplitMode() == SC_SPLIT_FIX ||
+ GetViewData().GetVSplitMode() == SC_SPLIT_FIX))
+ {
+ // adjust active part to cursor, etc.
+ MoveCursorAbs( GetViewData().GetCurX(), GetViewData().GetCurY(),
+ SC_FOLLOW_NONE, false, false, true );
+ }
+ }
+}
+
+void ScTabViewShell::SetDrawTextShell( bool bActive )
+{
+ bActiveDrawTextSh = bActive;
+ if ( bActive )
+ {
+ bActiveDrawFormSh=false;
+ bActiveGraphicSh=false;
+ bActiveMediaSh=false;
+ bActiveOleObjectSh=false;
+ bActiveChartSh=false;
+ bActiveDrawSh = false;
+ SetCurSubShell(OST_DrawText);
+ }
+ else
+ SetCurSubShell(OST_Cell);
+
+}
+
+void ScTabViewShell::SetPivotShell( bool bActive )
+{
+ // SetPivotShell is called from CursorPosChanged every time
+ // -> don't change anything except switching between cell and pivot shell
+
+ if (eCurOST != OST_Pivot && eCurOST != OST_Cell)
+ return;
+
+ if ( bActive )
+ {
+ bActiveDrawTextSh = bActiveDrawSh = false;
+ bActiveDrawFormSh=false;
+ bActiveGraphicSh=false;
+ bActiveMediaSh=false;
+ bActiveOleObjectSh=false;
+ bActiveChartSh=false;
+ SetCurSubShell(OST_Pivot);
+ }
+ else
+ SetCurSubShell(OST_Cell);
+}
+
+void ScTabViewShell::SetSparklineShell(bool bActive)
+{
+ if (eCurOST != OST_Sparkline && eCurOST != OST_Cell)
+ return;
+
+ if (bActive)
+ {
+ bActiveDrawTextSh = bActiveDrawSh = false;
+ bActiveDrawFormSh=false;
+ bActiveGraphicSh=false;
+ bActiveMediaSh=false;
+ bActiveOleObjectSh=false;
+ bActiveChartSh=false;
+ SetCurSubShell(OST_Sparkline);
+ }
+ else
+ SetCurSubShell(OST_Cell);
+}
+
+void ScTabViewShell::SetAuditShell( bool bActive )
+{
+ if ( bActive )
+ {
+ bActiveDrawTextSh = bActiveDrawSh = false;
+ bActiveDrawFormSh=false;
+ bActiveGraphicSh=false;
+ bActiveMediaSh=false;
+ bActiveOleObjectSh=false;
+ bActiveChartSh=false;
+ SetCurSubShell(OST_Auditing);
+ }
+ else
+ SetCurSubShell(OST_Cell);
+}
+
+void ScTabViewShell::SetDrawFormShell( bool bActive )
+{
+ bActiveDrawFormSh = bActive;
+
+ if(bActiveDrawFormSh)
+ SetCurSubShell(OST_DrawForm);
+}
+void ScTabViewShell::SetChartShell( bool bActive )
+{
+ bActiveChartSh = bActive;
+
+ if(bActiveChartSh)
+ SetCurSubShell(OST_Chart);
+}
+
+void ScTabViewShell::SetGraphicShell( bool bActive )
+{
+ bActiveGraphicSh = bActive;
+
+ if(bActiveGraphicSh)
+ SetCurSubShell(OST_Graphic);
+}
+
+void ScTabViewShell::SetMediaShell( bool bActive )
+{
+ bActiveMediaSh = bActive;
+
+ if(bActiveMediaSh)
+ SetCurSubShell(OST_Media);
+}
+
+void ScTabViewShell::SetOleObjectShell( bool bActive )
+{
+ bActiveOleObjectSh = bActive;
+
+ if(bActiveOleObjectSh)
+ SetCurSubShell(OST_OleObject);
+ else
+ SetCurSubShell(OST_Cell);
+}
+
+void ScTabViewShell::SetEditShell(EditView* pView, bool bActive )
+{
+ if(bActive)
+ {
+ if (pEditShell)
+ pEditShell->SetEditView( pView );
+ else
+ pEditShell.reset( new ScEditShell(pView, GetViewData()) );
+
+ SetCurSubShell(OST_Editing);
+ }
+ else if(bActiveEditSh)
+ {
+ SetCurSubShell(OST_Cell);
+ }
+ bActiveEditSh = bActive;
+}
+
+void ScTabViewShell::SetCurSubShell(ObjectSelectionType eOST, bool bForce)
+{
+ ScViewData& rViewData = GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+
+ if(bDontSwitch) return;
+
+ if(!pCellShell) // is anyway always used
+ {
+ pCellShell.reset(new ScCellShell(GetViewData(), GetFrameWin()));
+ pCellShell->SetRepeatTarget( &aTarget );
+ }
+
+ bool bPgBrk = rViewData.IsPagebreakMode();
+
+ if(bPgBrk && !pPageBreakShell)
+ {
+ pPageBreakShell.reset( new ScPageBreakShell( this ) );
+ pPageBreakShell->SetRepeatTarget( &aTarget );
+ }
+
+ if ( !(eOST!=eCurOST || bForce) )
+ return;
+
+ bool bCellBrush = false; // "format paint brush" allowed for cells
+ bool bDrawBrush = false; // "format paint brush" allowed for drawing objects
+
+ if(eCurOST!=OST_NONE) RemoveSubShell();
+
+ if (pFormShell && !bFormShellAtTop)
+ AddSubShell(*pFormShell); // add below own subshells
+
+ switch(eOST)
+ {
+ case OST_Cell:
+ {
+ AddSubShell(*pCellShell);
+ if(bPgBrk) AddSubShell(*pPageBreakShell);
+ bCellBrush = true;
+ }
+ break;
+ case OST_Editing:
+ {
+ AddSubShell(*pCellShell);
+ if(bPgBrk) AddSubShell(*pPageBreakShell);
+
+ if(pEditShell)
+ {
+ AddSubShell(*pEditShell);
+ }
+ }
+ break;
+ case OST_DrawText:
+ {
+ if ( !pDrawTextShell )
+ {
+ pDocSh->MakeDrawLayer();
+ pDrawTextShell.reset( new ScDrawTextObjectBar(GetViewData()) );
+ }
+ AddSubShell(*pDrawTextShell);
+ }
+ break;
+ case OST_Drawing:
+ {
+ if (svx::checkForSelectedCustomShapes(
+ GetScDrawView(), true /* bOnlyExtruded */ )) {
+ if (pExtrusionBarShell == nullptr)
+ pExtrusionBarShell.reset( new svx::ExtrusionBar(this) );
+ AddSubShell( *pExtrusionBarShell );
+ }
+
+ if (svx::checkForSelectedFontWork(
+ GetScDrawView() )) {
+ if (pFontworkBarShell == nullptr)
+ pFontworkBarShell.reset( new svx::FontworkBar(this) );
+ AddSubShell( *pFontworkBarShell );
+ }
+
+ if ( !pDrawShell )
+ {
+ pDocSh->MakeDrawLayer();
+ pDrawShell.reset(new ScDrawShell(GetViewData()));
+ pDrawShell->SetRepeatTarget( &aTarget );
+ }
+ AddSubShell(*pDrawShell);
+ bDrawBrush = true;
+ }
+ break;
+
+ case OST_DrawForm:
+ {
+ if ( !pDrawFormShell )
+ {
+ pDocSh->MakeDrawLayer();
+ pDrawFormShell.reset( new ScDrawFormShell(GetViewData()) );
+ pDrawFormShell->SetRepeatTarget( &aTarget );
+ }
+ AddSubShell(*pDrawFormShell);
+ bDrawBrush = true;
+ }
+ break;
+
+ case OST_Chart:
+ {
+ if ( !pChartShell )
+ {
+ pDocSh->MakeDrawLayer();
+ pChartShell.reset( new ScChartShell(GetViewData()) );
+ pChartShell->SetRepeatTarget( &aTarget );
+ }
+ AddSubShell(*pChartShell);
+ bDrawBrush = true;
+ }
+ break;
+
+ case OST_OleObject:
+ {
+ if ( !pOleObjectShell )
+ {
+ pDocSh->MakeDrawLayer();
+ pOleObjectShell.reset( new ScOleObjectShell(GetViewData()) );
+ pOleObjectShell->SetRepeatTarget( &aTarget );
+ }
+ AddSubShell(*pOleObjectShell);
+ bDrawBrush = true;
+ }
+ break;
+
+ case OST_Graphic:
+ {
+ if ( !pGraphicShell)
+ {
+ pDocSh->MakeDrawLayer();
+ pGraphicShell.reset( new ScGraphicShell(GetViewData()) );
+ pGraphicShell->SetRepeatTarget( &aTarget );
+ }
+ AddSubShell(*pGraphicShell);
+ bDrawBrush = true;
+ }
+ break;
+
+ case OST_Media:
+ {
+ if ( !pMediaShell)
+ {
+ pDocSh->MakeDrawLayer();
+ pMediaShell.reset( new ScMediaShell(GetViewData()) );
+ pMediaShell->SetRepeatTarget( &aTarget );
+ }
+ AddSubShell(*pMediaShell);
+ }
+ break;
+
+ case OST_Pivot:
+ {
+ AddSubShell(*pCellShell);
+ if(bPgBrk) AddSubShell(*pPageBreakShell);
+
+ if ( !pPivotShell )
+ {
+ pPivotShell.reset( new ScPivotShell( this ) );
+ pPivotShell->SetRepeatTarget( &aTarget );
+ }
+ AddSubShell(*pPivotShell);
+ bCellBrush = true;
+ }
+ break;
+ case OST_Auditing:
+ {
+ AddSubShell(*pCellShell);
+ if(bPgBrk) AddSubShell(*pPageBreakShell);
+
+ if ( !pAuditingShell )
+ {
+ pDocSh->MakeDrawLayer(); // the waiting time rather now as on the click
+
+ pAuditingShell.reset( new ScAuditingShell(GetViewData()) );
+ pAuditingShell->SetRepeatTarget( &aTarget );
+ }
+ AddSubShell(*pAuditingShell);
+ bCellBrush = true;
+ }
+ break;
+ case OST_Sparkline:
+ {
+ AddSubShell(*pCellShell);
+ if(bPgBrk) AddSubShell(*pPageBreakShell);
+
+ if (!m_pSparklineShell)
+ {
+ m_pSparklineShell.reset(new sc::SparklineShell(this));
+ m_pSparklineShell->SetRepeatTarget(&aTarget);
+ }
+ AddSubShell(*m_pSparklineShell);
+ bCellBrush = true;
+ }
+ break;
+ default:
+ OSL_FAIL("wrong shell requested");
+ break;
+ }
+
+ if (pFormShell && bFormShellAtTop)
+ AddSubShell(*pFormShell); // add on top of own subshells
+
+ eCurOST=eOST;
+
+ // abort "format paint brush" when switching to an incompatible shell
+ if ( ( GetBrushDocument() && !bCellBrush ) || ( GetDrawBrushSet() && !bDrawBrush ) )
+ ResetBrushDocument();
+}
+
+void ScTabViewShell::SetFormShellAtTop( bool bSet )
+{
+ if ( pFormShell && !bSet )
+ pFormShell->ForgetActiveControl(); // let the FormShell know it no longer has the focus
+
+ if ( bFormShellAtTop != bSet )
+ {
+ bFormShellAtTop = bSet;
+ SetCurSubShell( GetCurObjectSelectionType(), true );
+ }
+}
+
+IMPL_LINK_NOARG(ScTabViewShell, FormControlActivated, LinkParamNone*, void)
+{
+ // a form control got the focus, so the form shell has to be on top
+ SetFormShellAtTop( true );
+}
+
+// GetMySubShell / SetMySubShell: simulate old behavior,
+// so that there is only one SubShell (only within the 5 own SubShells)
+
+SfxShell* ScTabViewShell::GetMySubShell() const
+{
+ // GetSubShell() was const before, and GetSubShell(sal_uInt16) should also be const...
+
+ sal_uInt16 nPos = 0;
+ SfxShell* pSub = const_cast<ScTabViewShell*>(this)->GetSubShell(nPos);
+ while (pSub)
+ {
+ if (pSub == pDrawShell.get() || pSub == pDrawTextShell.get() || pSub == pEditShell.get() ||
+ pSub == pPivotShell.get() || pSub == pAuditingShell.get() || pSub == pDrawFormShell.get() ||
+ pSub == pCellShell.get() || pSub == pOleObjectShell.get() || pSub == pChartShell.get() ||
+ pSub == pGraphicShell.get() || pSub == pMediaShell.get() || pSub == pPageBreakShell.get() ||
+ pSub == m_pSparklineShell.get())
+ {
+ return pSub; // found
+ }
+
+ pSub = const_cast<ScTabViewShell*>(this)->GetSubShell(++nPos);
+ }
+ return nullptr; // none from mine present
+}
+
+bool ScTabViewShell::IsDrawTextShell() const
+{
+ return ( pDrawTextShell && ( GetMySubShell() == pDrawTextShell.get() ) );
+}
+
+bool ScTabViewShell::IsAuditShell() const
+{
+ return ( pAuditingShell && ( GetMySubShell() == pAuditingShell.get() ) );
+}
+
+void ScTabViewShell::SetDrawTextUndo( SfxUndoManager* pNewUndoMgr )
+{
+ // Default: undo manager for DocShell
+ if (!pNewUndoMgr)
+ pNewUndoMgr = GetViewData().GetDocShell()->GetUndoManager();
+
+ if (pDrawTextShell)
+ {
+ pDrawTextShell->SetUndoManager(pNewUndoMgr);
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ if ( pNewUndoMgr == pDocSh->GetUndoManager() &&
+ !pDocSh->GetDocument().IsUndoEnabled() )
+ {
+ pNewUndoMgr->SetMaxUndoActionCount( 0 );
+ }
+ }
+ else
+ {
+ OSL_FAIL("SetDrawTextUndo without DrawTextShell");
+ }
+}
+
+ScTabViewShell* ScTabViewShell::GetActiveViewShell()
+{
+ return dynamic_cast< ScTabViewShell *>( Current() );
+}
+
+SfxPrinter* ScTabViewShell::GetPrinter( bool bCreate )
+{
+ // printer is always present (is created for the FontList already on start-up)
+ return GetViewData().GetDocShell()->GetPrinter(bCreate);
+}
+
+sal_uInt16 ScTabViewShell::SetPrinter( SfxPrinter *pNewPrinter, SfxPrinterChangeFlags nDiffFlags )
+{
+ return GetViewData().GetDocShell()->SetPrinter( pNewPrinter, nDiffFlags );
+}
+
+bool ScTabViewShell::HasPrintOptionsPage() const
+{
+ return true;
+}
+
+std::unique_ptr<SfxTabPage> ScTabViewShell::CreatePrintOptionsPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet &rOptions )
+{
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ::CreateTabPage ScTpPrintOptionsCreate = pFact->GetTabPageCreatorFunc(RID_SC_TP_PRINT);
+ if ( ScTpPrintOptionsCreate )
+ return ScTpPrintOptionsCreate(pPage, pController, &rOptions);
+ return nullptr;
+}
+
+void ScTabViewShell::StopEditShell()
+{
+ if ( pEditShell != nullptr && !bDontSwitch )
+ SetEditShell(nullptr, false );
+}
+
+// close handler to ensure function of dialog:
+
+IMPL_LINK_NOARG(ScTabViewShell, SimpleRefClose, const OUString*, void)
+{
+ SfxInPlaceClient* pClient = GetIPClient();
+ if ( pClient && pClient->IsObjectInPlaceActive() )
+ {
+ // If range selection was started with an active embedded object,
+ // switch back to original sheet (while the dialog is still open).
+
+ SetTabNo( GetViewData().GetRefTabNo() );
+ }
+
+ ScSimpleRefDlgWrapper::SetAutoReOpen( true );
+}
+
+// handlers to call UNO listeners:
+
+static ScTabViewObj* lcl_GetViewObj( const ScTabViewShell& rShell )
+{
+ ScTabViewObj* pRet = nullptr;
+ SfxViewFrame* pViewFrame = rShell.GetViewFrame();
+ if (pViewFrame)
+ {
+ SfxFrame& rFrame = pViewFrame->GetFrame();
+ uno::Reference<frame::XController> xController = rFrame.GetController();
+ if (xController.is())
+ pRet = comphelper::getFromUnoTunnel<ScTabViewObj>( xController );
+ }
+ return pRet;
+}
+
+IMPL_LINK( ScTabViewShell, SimpleRefDone, const OUString&, aResult, void )
+{
+ ScTabViewObj* pImpObj = lcl_GetViewObj( *this );
+ if ( pImpObj )
+ pImpObj->RangeSelDone( aResult );
+}
+
+IMPL_LINK( ScTabViewShell, SimpleRefAborted, const OUString&, rResult, void )
+{
+ ScTabViewObj* pImpObj = lcl_GetViewObj( *this );
+ if ( pImpObj )
+ pImpObj->RangeSelAborted( rResult );
+}
+
+IMPL_LINK( ScTabViewShell, SimpleRefChange, const OUString&, rResult, void )
+{
+ ScTabViewObj* pImpObj = lcl_GetViewObj( *this );
+ if ( pImpObj )
+ pImpObj->RangeSelChanged( rResult );
+}
+
+void ScTabViewShell::StartSimpleRefDialog(
+ const OUString& rTitle, const OUString& rInitVal,
+ bool bCloseOnButtonUp, bool bSingleCell, bool bMultiSelection )
+{
+ SfxViewFrame* pViewFrm = GetViewFrame();
+
+ if ( GetActiveViewShell() != this )
+ {
+ // #i18833# / #i34499# The API method can be called for a view that's not active.
+ // Then the view has to be activated first, the same way as in Execute for SID_CURRENTDOC.
+ // Can't use GrabFocus here, because it needs to take effect immediately.
+
+ pViewFrm->GetFrame().Appear();
+ }
+
+ sal_uInt16 nId = ScSimpleRefDlgWrapper::GetChildWindowId();
+
+ SC_MOD()->SetRefDialog( nId, true, pViewFrm );
+
+ ScSimpleRefDlgWrapper* pWnd = static_cast<ScSimpleRefDlgWrapper*>(pViewFrm->GetChildWindow( nId ));
+ if (!pWnd)
+ return;
+
+ pWnd->SetCloseHdl( LINK( this, ScTabViewShell, SimpleRefClose ) );
+ pWnd->SetUnoLinks( LINK( this, ScTabViewShell, SimpleRefDone ),
+ LINK( this, ScTabViewShell, SimpleRefAborted ),
+ LINK( this, ScTabViewShell, SimpleRefChange ) );
+ pWnd->SetRefString( rInitVal );
+ pWnd->SetFlags( bCloseOnButtonUp, bSingleCell, bMultiSelection );
+ ScSimpleRefDlgWrapper::SetAutoReOpen( false );
+ if (auto xWin = pWnd->GetController())
+ xWin->set_title(rTitle);
+ pWnd->StartRefInput();
+}
+
+void ScTabViewShell::StopSimpleRefDialog()
+{
+ SfxViewFrame* pViewFrm = GetViewFrame();
+ sal_uInt16 nId = ScSimpleRefDlgWrapper::GetChildWindowId();
+
+ ScSimpleRefDlgWrapper* pWnd = static_cast<ScSimpleRefDlgWrapper*>(pViewFrm->GetChildWindow( nId ));
+ if (pWnd)
+ {
+ if (auto pWin = pWnd->GetController())
+ pWin->response(RET_CLOSE);
+ }
+}
+
+bool ScTabViewShell::TabKeyInput(const KeyEvent& rKEvt)
+{
+ ScModule* pScMod = SC_MOD();
+
+ SfxViewFrame* pThisFrame = GetViewFrame();
+ if ( pThisFrame->GetChildWindow( SID_OPENDLG_FUNCTION ) )
+ return false;
+
+ vcl::KeyCode aCode = rKEvt.GetKeyCode();
+ bool bShift = aCode.IsShift();
+ bool bControl = aCode.IsMod1();
+ bool bAlt = aCode.IsMod2();
+ sal_uInt16 nCode = aCode.GetCode();
+ bool bUsed = false;
+ bool bInPlace = pScMod->IsEditMode(); // Editengine gets all
+ bool bAnyEdit = pScMod->IsInputMode(); // only characters & backspace
+ bool bDraw = IsDrawTextEdit();
+
+ HideNoteMarker(); // note marker
+
+ // don't do extra HideCursor/ShowCursor calls if EnterHandler will switch to a different sheet
+ bool bOnRefSheet = ( GetViewData().GetRefTabNo() == GetViewData().GetTabNo() );
+ bool bHideCursor = ( ( nCode == KEY_RETURN && bInPlace ) || nCode == KEY_TAB ) && bOnRefSheet;
+
+ if (bHideCursor)
+ HideAllCursors();
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ rDoc.KeyInput(); // TimerDelays etc.
+
+ if( bInPlace )
+ {
+ bUsed = pScMod->InputKeyEvent( rKEvt ); // input
+ if( !bUsed )
+ bUsed = SfxViewShell::KeyInput( rKEvt ); // accelerators
+ }
+ else if( bAnyEdit )
+ {
+ bool bIsType = false;
+ sal_uInt16 nModi = aCode.GetModifier();
+ sal_uInt16 nGroup = aCode.GetGroup();
+
+ if ( nGroup == KEYGROUP_NUM || nGroup == KEYGROUP_ALPHA || nGroup == 0 )
+ if ( !bControl && !bAlt )
+ bIsType = true;
+
+ if ( nGroup == KEYGROUP_MISC )
+ switch ( nCode )
+ {
+ case KEY_RETURN:
+ bIsType = bControl && !bAlt; // Control, Shift-Control-Return
+ if ( !bIsType && nModi == 0 )
+ {
+ // Does the Input Handler also want a simple Return?
+
+ ScInputHandler* pHdl = pScMod->GetInputHdl(this);
+ bIsType = pHdl && pHdl->TakesReturn();
+ }
+ break;
+ case KEY_SPACE:
+ bIsType = !bControl && !bAlt; // without modifier or Shift-Space
+ break;
+ case KEY_ESCAPE:
+ bIsType = (nModi == 0); // only without modifier
+ break;
+ default:
+ bIsType = true;
+ }
+ else if (nCode == KEY_RIGHT && !bControl && !bShift && !bAlt)
+ {
+ ScInputHandler* pHdl = pScMod->GetInputHdl(this);
+ bIsType = pHdl && pHdl->HasPartialComplete();
+ }
+
+ if( bIsType )
+ bUsed = pScMod->InputKeyEvent( rKEvt ); // input
+
+ if( !bUsed )
+ bUsed = SfxViewShell::KeyInput( rKEvt ); // accelerators
+
+ if ( !bUsed && !bIsType && nCode != KEY_RETURN ) // input once again afterwards
+ bUsed = pScMod->InputKeyEvent( rKEvt );
+ }
+ else
+ {
+ // special case: copy/cut for multiselect -> error message
+ // (Slot is disabled, so SfxViewShell::KeyInput would be swallowed without a comment)
+ KeyFuncType eFunc = aCode.GetFunction();
+ if ( eFunc == KeyFuncType::CUT )
+ {
+ ScRange aDummy;
+ ScMarkType eMarkType = GetViewData().GetSimpleArea( aDummy );
+ if (eMarkType != SC_MARK_SIMPLE)
+ {
+ ErrorMessage(STR_NOMULTISELECT);
+ bUsed = true;
+ }
+ }
+ if (!bUsed)
+ bUsed = SfxViewShell::KeyInput( rKEvt ); // accelerators
+
+ // during inplace editing, some slots are handled by the
+ // container app and are executed during Window::KeyInput.
+ // -> don't pass keys to input handler that would be used there
+ // but should call slots instead.
+ bool bParent = ( GetViewFrame()->GetFrame().IsInPlace() && eFunc != KeyFuncType::DONTKNOW );
+
+ if( !bUsed && !bDraw && nCode != KEY_RETURN && !bParent )
+ bUsed = pScMod->InputKeyEvent( rKEvt, true ); // input
+ }
+
+ if (!bInPlace && !bUsed && !bDraw)
+ {
+ switch (nCode)
+ {
+ case KEY_RETURN:
+ {
+ bool bNormal = !bControl && !bAlt;
+ if ( !bAnyEdit && bNormal )
+ {
+ // Depending on options, Enter switches to edit mode.
+ const ScInputOptions& rOpt = pScMod->GetInputOptions();
+ if ( rOpt.GetEnterEdit() )
+ {
+ pScMod->SetInputMode( SC_INPUT_TABLE );
+ bUsed = true;
+ }
+ }
+
+ bool bEditReturn = bControl && !bShift; // pass on to edit engine
+ if ( !bUsed && !bEditReturn )
+ {
+ if ( bOnRefSheet )
+ HideAllCursors();
+
+ ScEnterMode nMode = ScEnterMode::NORMAL;
+ if ( bShift && bControl )
+ nMode = ScEnterMode::MATRIX;
+ else if ( bAlt )
+ nMode = ScEnterMode::BLOCK;
+ pScMod->InputEnterHandler(nMode);
+
+ if (nMode == ScEnterMode::NORMAL)
+ {
+ if( bShift )
+ GetViewData().GetDispatcher().Execute( SID_CURSORENTERUP,
+ SfxCallMode::SLOT | SfxCallMode::RECORD );
+ else
+ GetViewData().GetDispatcher().Execute( SID_CURSORENTERDOWN,
+ SfxCallMode::SLOT | SfxCallMode::RECORD );
+ }
+ else
+ UpdateInputHandler(true);
+
+ if ( bOnRefSheet )
+ ShowAllCursors();
+
+ // here no UpdateInputHandler, since during reference input on another
+ // document this ViewShell is not the one that is used for input.
+
+ bUsed = true;
+ }
+ }
+ break;
+ }
+ }
+
+ // hard-code Alt-Cursor key, since Alt is not configurable
+
+ if ( !bUsed && bAlt && !bControl )
+ {
+ sal_uInt16 nSlotId = 0;
+ switch (nCode)
+ {
+ case KEY_UP:
+ ModifyCellSize( DIR_TOP, bShift );
+ bUsed = true;
+ break;
+ case KEY_DOWN:
+ ModifyCellSize( DIR_BOTTOM, bShift );
+ bUsed = true;
+ break;
+ case KEY_LEFT:
+ ModifyCellSize( DIR_LEFT, bShift );
+ bUsed = true;
+ break;
+ case KEY_RIGHT:
+ ModifyCellSize( DIR_RIGHT, bShift );
+ bUsed = true;
+ break;
+ case KEY_PAGEUP:
+ nSlotId = bShift ? SID_CURSORPAGELEFT_SEL : SID_CURSORPAGELEFT_;
+ break;
+ case KEY_PAGEDOWN:
+ nSlotId = bShift ? SID_CURSORPAGERIGHT_SEL : SID_CURSORPAGERIGHT_;
+ break;
+ case KEY_EQUAL:
+ {
+ // #tdf39302: Use "Alt + =" for autosum
+ if ( !bAnyEdit ) // Ignore shortcut if currently editing a cell
+ {
+ ScInputHandler* pHdl = pScMod->GetInputHdl(this);
+ if ( pHdl )
+ {
+ ScInputWindow* pWin = pHdl->GetInputWindow();
+ if ( pWin )
+ {
+ bool bRangeFinder = false;
+ bool bSubTotal = false;
+ pWin->AutoSum( bRangeFinder, bSubTotal, ocSum );
+ }
+ }
+
+ bUsed = true;
+ break;
+ }
+ }
+ }
+ if ( nSlotId )
+ {
+ GetViewData().GetDispatcher().Execute( nSlotId, SfxCallMode::SLOT | SfxCallMode::RECORD );
+ bUsed = true;
+ }
+ }
+
+ // use Ctrl+Alt+Shift+arrow keys to move the cursor in cells
+ // while keeping the last selection
+ if ( !bUsed && bAlt && bControl && bShift)
+ {
+ sal_uInt16 nSlotId = 0;
+ switch (nCode)
+ {
+ case KEY_UP:
+ nSlotId = SID_CURSORUP;
+ break;
+ case KEY_DOWN:
+ nSlotId = SID_CURSORDOWN;
+ break;
+ case KEY_LEFT:
+ nSlotId = SID_CURSORLEFT;
+ break;
+ case KEY_RIGHT:
+ nSlotId = SID_CURSORRIGHT;
+ break;
+ case KEY_PAGEUP:
+ nSlotId = SID_CURSORPAGEUP;
+ break;
+ case KEY_PAGEDOWN:
+ nSlotId = SID_CURSORPAGEDOWN;
+ break;
+ case KEY_HOME:
+ nSlotId = SID_CURSORHOME;
+ break;
+ case KEY_END:
+ nSlotId = SID_CURSOREND;
+ break;
+ default:
+ nSlotId = 0;
+ break;
+ }
+ if ( nSlotId )
+ {
+ sal_uInt16 nMode = GetLockedModifiers();
+ LockModifiers(KEY_MOD1);
+ GetViewData().GetDispatcher().Execute( nSlotId, SfxCallMode::SLOT | SfxCallMode::RECORD );
+ LockModifiers(nMode);
+ bUsed = true;
+ }
+ }
+ if (bHideCursor)
+ ShowAllCursors();
+
+ return bUsed;
+}
+
+bool ScTabViewShell::SfxKeyInput(const KeyEvent& rKeyEvent)
+{
+ return SfxViewShell::KeyInput( rKeyEvent );
+}
+
+bool ScTabViewShell::KeyInput( const KeyEvent &rKeyEvent )
+{
+ return TabKeyInput( rKeyEvent );
+}
+
+void ScTabViewShell::Construct( TriState nForceDesignMode )
+{
+ SfxApplication* pSfxApp = SfxGetpApp();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bReadOnly = pDocSh->IsReadOnly();
+ bIsActive = false;
+
+ EnableAutoSpell(rDoc.GetDocOptions().IsAutoSpell());
+
+ SetName("View"); // for SBX
+ Color aColBlack( COL_BLACK );
+ SetPool( &SC_MOD()->GetPool() );
+ SetWindow( GetActiveWin() );
+
+ pCurFrameLine.reset( new ::editeng::SvxBorderLine(&aColBlack, 20, SvxBorderLineStyle::SOLID) );
+ StartListening(*GetViewData().GetDocShell(), DuplicateHandling::Prevent);
+ StartListening(*GetViewFrame(), DuplicateHandling::Prevent);
+ StartListening(*pSfxApp, DuplicateHandling::Prevent); // #i62045# #i62046# application is needed for Calc's own hints
+
+ SfxViewFrame* pFirst = SfxViewFrame::GetFirst(pDocSh);
+ bool bFirstView = !pFirst
+ || (pFirst == GetViewFrame() && !SfxViewFrame::GetNext(*pFirst,pDocSh));
+
+ if ( pDocSh->GetCreateMode() == SfxObjectCreateMode::EMBEDDED )
+ {
+ //TODO/LATER: is there a difference between the two GetVisArea methods?
+ tools::Rectangle aVisArea = static_cast<const SfxObjectShell*>(pDocSh)->GetVisArea();
+
+ SCTAB nVisTab = rDoc.GetVisibleTab();
+ if (!rDoc.HasTable(nVisTab))
+ {
+ nVisTab = 0;
+ rDoc.SetVisibleTab(nVisTab);
+ }
+ SetTabNo( nVisTab );
+ bool bNegativePage = rDoc.IsNegativePage( nVisTab );
+ // show the right cells
+ GetViewData().SetScreenPos( bNegativePage ? aVisArea.TopRight() : aVisArea.TopLeft() );
+
+ if ( GetViewFrame()->GetFrame().IsInPlace() ) // inplace
+ {
+ pDocSh->SetInplace( true ); // already initiated like this
+ if (rDoc.IsEmbedded())
+ rDoc.ResetEmbedded(); // no blue mark
+ }
+ else if ( bFirstView )
+ {
+ pDocSh->SetInplace( false );
+ GetViewData().RefreshZoom(); // recalculate PPT
+ if (!rDoc.IsEmbedded())
+ rDoc.SetEmbedded( rDoc.GetVisibleTab(), aVisArea ); // mark VisArea
+ }
+ }
+
+ // ViewInputHandler
+ // Each task now has its own InputWindow,
+ // therefore either should each task get its own InputHandler,
+ // or the InputWindow should create its own InputHandler
+ // (then always search via InputWindow and only if not found
+ // use the InputHandler of the App).
+ // As an intermediate solution each View gets its own InputHandler,
+ // which only yields problems if two Views are in one task window.
+ mpInputHandler.reset(new ScInputHandler);
+
+ // old version:
+ // if ( !GetViewFrame()->ISA(SfxTopViewFrame) ) // OLE or Plug-In
+ // pInputHandler = new ScInputHandler;
+
+ // create FormShell before MakeDrawView, so that DrawView can be registered at the
+ // FormShell in every case
+ // the FormShell is pushed in the first activate
+ pFormShell.reset( new FmFormShell(this) );
+ pFormShell->SetControlActivationHandler( LINK( this, ScTabViewShell, FormControlActivated ) );
+
+ // DrawView must not be created in TabView - ctor,
+ // if the ViewShell is not yet constructed...
+ if (rDoc.GetDrawLayer())
+ MakeDrawView( nForceDesignMode );
+ ViewOptionsHasChanged(false, false); // possibly also creates DrawView
+
+ SfxUndoManager* pMgr = pDocSh->GetUndoManager();
+ SetUndoManager( pMgr );
+ pFormShell->SetUndoManager( pMgr );
+ if ( !rDoc.IsUndoEnabled() )
+ {
+ pMgr->SetMaxUndoActionCount( 0 );
+ }
+ SetRepeatTarget( &aTarget );
+ pFormShell->SetRepeatTarget( &aTarget );
+
+ if ( bFirstView ) // first view?
+ {
+ rDoc.SetDocVisible( true ); // used when creating new sheets
+ if ( pDocSh->IsEmpty() )
+ {
+ // set first sheet's RTL flag (following will already be initialized because of SetDocVisible)
+ rDoc.SetLayoutRTL( 0, ScGlobal::IsSystemRTL() );
+
+ // append additional sheets (not for OLE object)
+ if ( pDocSh->GetCreateMode() != SfxObjectCreateMode::EMBEDDED )
+ {
+ // Get the customized initial tab count
+ const ScDefaultsOptions& rOpt = SC_MOD()->GetDefaultsOptions();
+ SCTAB nInitTabCount = rOpt.GetInitTabCount();
+
+ for (SCTAB i=1; i<nInitTabCount; i++)
+ rDoc.MakeTable(i,false);
+ }
+
+ pDocSh->SetEmpty( false ); // #i6232# make sure this is done only once
+ }
+
+ // ReadExtOptions is now in Activate
+
+ // link update no nesting
+ if ( pDocSh->GetCreateMode() != SfxObjectCreateMode::INTERNAL &&
+ pDocSh->IsUpdateEnabled() ) // #105575#; update only in the first creation of the ViewShell
+ {
+ // Check if there are any external data.
+ bool bLink = rDoc.GetExternalRefManager()->hasExternalData();
+ if (!bLink)
+ {
+ // #i100042# sheet links can still exist independently from external formula references
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (SCTAB i=0; i<nTabCount && !bLink; i++)
+ if (rDoc.IsLinked(i))
+ bLink = true;
+ }
+ if (!bLink)
+ {
+ const sc::DocumentLinkManager& rMgr = rDoc.GetDocLinkManager();
+ if (rDoc.HasLinkFormulaNeedingCheck() || rDoc.HasAreaLinks() || rMgr.hasDdeOrOleOrWebServiceLinks())
+ bLink = true;
+ }
+ if (bLink)
+ {
+ if ( !pFirst )
+ pFirst = GetViewFrame();
+
+ if(SC_MOD()->GetCurRefDlgId()==0)
+ {
+ pFirst->GetDispatcher()->Execute( SID_UPDATETABLINKS,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ }
+ }
+ else
+ {
+ // No links yet, but loading an existing document may have
+ // disabled link update but there's no "Allow updating" infobar
+ // that could enable it again. So in order to enable the user
+ // to add formulas with external references allow link updates
+ // again.
+ pDocSh->AllowLinkUpdate();
+ }
+
+ bool bReImport = false; // update imported data
+ ScDBCollection* pDBColl = rDoc.GetDBCollection();
+ if ( pDBColl )
+ {
+ const ScDBCollection::NamedDBs& rDBs = pDBColl->getNamedDBs();
+ bReImport = std::any_of(rDBs.begin(), rDBs.end(),
+ [](const std::unique_ptr<ScDBData>& rxDB) { return rxDB->IsStripData() && rxDB->HasImportParam() && !rxDB->HasImportSelection(); });
+ }
+ if (bReImport)
+ {
+ if ( !pFirst )
+ pFirst = GetViewFrame();
+ if(SC_MOD()->GetCurRefDlgId()==0)
+ {
+ pFirst->GetDispatcher()->Execute( SID_REIMPORT_AFTER_LOAD,
+ SfxCallMode::ASYNCHRON | SfxCallMode::RECORD );
+ }
+ }
+ }
+ }
+
+ UpdateAutoFillMark();
+
+ // ScDispatchProviderInterceptor registers itself in ctor
+ xDisProvInterceptor = new ScDispatchProviderInterceptor( this );
+
+ bFirstActivate = true; // delay NavigatorUpdate until Activate()
+
+ // #105575#; update only in the first creation of the ViewShell
+ pDocSh->SetUpdateEnabled(false);
+
+ if ( GetViewFrame()->GetFrame().IsInPlace() )
+ UpdateHeaderWidth(); // The inplace activation requires headers to be calculated
+
+ SvBorder aBorder;
+ GetBorderSize( aBorder, Size() );
+ SetBorderPixel( aBorder );
+}
+
+ScTabViewShell::ScTabViewShell( SfxViewFrame* pViewFrame,
+ SfxViewShell* pOldSh ) :
+ SfxViewShell( pViewFrame, SfxViewShellFlags::HAS_PRINTOPTIONS ),
+ ScDBFunc( &pViewFrame->GetWindow(), static_cast<ScDocShell&>(*pViewFrame->GetObjectShell()), this ),
+ eCurOST(OST_NONE),
+ nDrawSfxId(0),
+ aTarget(this),
+ bActiveDrawSh(false),
+ bActiveDrawTextSh(false),
+ bActiveDrawFormSh(false),
+ bActiveOleObjectSh(false),
+ bActiveChartSh(false),
+ bActiveGraphicSh(false),
+ bActiveMediaSh(false),
+ bFormShellAtTop(false),
+ bDontSwitch(false),
+ bInFormatDialog(false),
+ bReadOnly(false),
+ bForceFocusOnCurCell(false),
+ bInPrepareClose(false),
+ bInDispose(false),
+ nCurRefDlgId(0),
+ mbInSwitch(false),
+ m_pDragData(new ScDragData)
+{
+ const ScAppOptions& rAppOpt = SC_MOD()->GetAppOptions();
+
+ // if switching back from print preview,
+ // restore the view settings that were active when creating the preview
+ // ReadUserData must not happen from ctor, because the view's edit window
+ // has to be shown by the sfx. ReadUserData is deferred until the first Activate call.
+ // old DesignMode state from form layer must be restored, too
+
+ TriState nForceDesignMode = TRISTATE_INDET;
+ if ( auto pPreviewShell = dynamic_cast<ScPreviewShell*>( pOldSh) )
+ {
+ nForceDesignMode = pPreviewShell->GetSourceDesignMode();
+ ScPreview* p = pPreviewShell->GetPreview();
+ if (p)
+ GetViewData().GetMarkData().SetSelectedTabs(p->GetSelectedTabs());
+ }
+
+ Construct( nForceDesignMode );
+
+ // make Controller known to SFX
+ new ScTabViewObj( this );
+
+ // Resolves: tdf#53899 if there is no controller, register the above
+ // ScTabViewObj as the current controller for the duration of the first
+ // round of calculations triggered here by SetZoom. That way any StarBasic
+ // macros triggered while the document is loading have a CurrentController
+ // available to them.
+ bool bInstalledScTabViewObjAsTempController = false;
+ uno::Reference<frame::XController> xCurrentController(GetViewData().GetDocShell()->GetModel()->getCurrentController());
+ if (!xCurrentController)
+ {
+ //GetController here returns the ScTabViewObj above
+ GetViewData().GetDocShell()->GetModel()->setCurrentController(GetController());
+ bInstalledScTabViewObjAsTempController = true;
+ }
+ xCurrentController.clear();
+
+ if ( GetViewData().GetDocShell()->IsPreview() )
+ {
+ // preview for template dialog: always show whole page
+ SetZoomType( SvxZoomType::WHOLEPAGE, true ); // zoom value is recalculated at next Resize
+ }
+ else
+ {
+ Fraction aFract( rAppOpt.GetZoom(), 100 );
+ SetZoom( aFract, aFract, true );
+ SetZoomType( rAppOpt.GetZoomType(), true );
+ }
+
+ SetCurSubShell(OST_Cell);
+ SvBorder aBorder;
+ GetBorderSize( aBorder, Size() );
+ SetBorderPixel( aBorder );
+
+ MakeDrawLayer();
+
+ //put things back as we found them
+ if (bInstalledScTabViewObjAsTempController)
+ GetViewData().GetDocShell()->GetModel()->setCurrentController(nullptr);
+
+ // formula mode in online is not usable in collaborative mode,
+ // this is a workaround for disabling formula mode in online
+ // when there is more than a single view
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ // have we already one view ?
+ if (!pViewShell)
+ return;
+
+ // this view is not yet visible at this stage, so we look for not visible views, too, for this same document
+ SfxViewShell* pViewShell2 = pViewShell;
+ do
+ {
+ pViewShell2 = SfxViewShell::GetNext(*pViewShell2, /*only visible shells*/ false);
+ } while (pViewShell2 && pViewShell2->GetDocId() != pViewShell->GetDocId());
+ // if the second view is not this one, it means that there is
+ // already more than one active view and so the formula mode
+ // has already been disabled
+ if (pViewShell2 && pViewShell2 == this)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ assert(pTabViewShell);
+ ScInputHandler* pInputHdl = pTabViewShell->GetInputHandler();
+ if (pInputHdl && pInputHdl->IsFormulaMode())
+ {
+ pInputHdl->SetMode(SC_INPUT_NONE);
+ }
+ }
+}
+
+ScTabViewShell::~ScTabViewShell()
+{
+ bInDispose = true;
+
+ // 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");
+ SfxLokHelper::notifyOtherViews(this, LOK_CALLBACK_CELL_VIEW_CURSOR, "rectangle", "EMPTY");
+
+ // all to NULL, in case the TabView-dtor tries to access them
+ //! (should not really! ??!?!)
+ if (mpInputHandler)
+ {
+ mpInputHandler->SetDocumentDisposing(true);
+ }
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ EndListening(*pDocSh);
+ EndListening(*GetViewFrame());
+ EndListening(*SfxGetpApp()); // #i62045# #i62046# needed now - SfxViewShell no longer does it
+
+ SC_MOD()->ViewShellGone(this);
+
+ RemoveSubShell(); // all
+ SetWindow(nullptr);
+
+ // need kill editview or we will touch the editengine after it has been freed by the ScInputHandler
+ KillEditView(true);
+
+ pFontworkBarShell.reset();
+ pExtrusionBarShell.reset();
+ pCellShell.reset();
+ pPageBreakShell.reset();
+ pDrawShell.reset();
+ pDrawFormShell.reset();
+ pOleObjectShell.reset();
+ pChartShell.reset();
+ pGraphicShell.reset();
+ pMediaShell.reset();
+ pDrawTextShell.reset();
+ pEditShell.reset();
+ pPivotShell.reset();
+ m_pSparklineShell.reset();
+ pAuditingShell.reset();
+ pCurFrameLine.reset();
+ mpFormEditData.reset();
+ mpInputHandler.reset();
+ pDialogDPObject.reset();
+ pNavSettings.reset();
+
+ pFormShell.reset();
+ pAccessibilityBroadcaster.reset();
+}
+
+void ScTabViewShell::SetDialogDPObject( std::unique_ptr<ScDPObject> pObj )
+{
+ pDialogDPObject = std::move(pObj);
+}
+
+void ScTabViewShell::FillFieldData( ScHeaderFieldData& rData )
+{
+ ScDocShell* pDocShell = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocShell->GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ OUString aTmp;
+ rDoc.GetName(nTab, aTmp);
+ rData.aTabName = aTmp;
+
+ if( pDocShell->getDocProperties()->getTitle().getLength() != 0 )
+ rData.aTitle = pDocShell->getDocProperties()->getTitle();
+ else
+ rData.aTitle = pDocShell->GetTitle();
+
+ const INetURLObject& rURLObj = pDocShell->GetMedium()->GetURLObject();
+ rData.aLongDocName = rURLObj.GetMainURL( INetURLObject::DecodeMechanism::Unambiguous );
+ if ( !rData.aLongDocName.isEmpty() )
+ rData.aShortDocName = rURLObj.GetLastName(INetURLObject::DecodeMechanism::Unambiguous);
+ else
+ rData.aShortDocName = rData.aLongDocName = rData.aTitle;
+ rData.nPageNo = 1;
+ rData.nTotalPages = 99;
+
+ // eNumType is known by the dialog
+}
+
+ScNavigatorSettings* ScTabViewShell::GetNavigatorSettings()
+{
+ if( !pNavSettings )
+ pNavSettings.reset(new ScNavigatorSettings);
+ return pNavSettings.get();
+}
+
+tools::Rectangle ScTabViewShell::getLOKVisibleArea() const
+{
+ return GetViewData().getLOKVisibleArea();
+}
+
+void ScTabViewShell::SetDragObject(ScTransferObj* pCellObj, ScDrawTransferObj* pDrawObj)
+{
+ ResetDragObject();
+ m_pDragData->pCellTransfer = pCellObj;
+ m_pDragData->pDrawTransfer = pDrawObj;
+}
+
+void ScTabViewShell::ResetDragObject()
+{
+ m_pDragData->pCellTransfer = nullptr;
+ m_pDragData->pDrawTransfer = nullptr;
+ m_pDragData->pJumpLocalDoc = nullptr;
+ m_pDragData->aLinkDoc.clear();
+ m_pDragData->aLinkTable.clear();
+ m_pDragData->aLinkArea.clear();
+ m_pDragData->aJumpTarget.clear();
+ m_pDragData->aJumpText.clear();
+}
+
+void ScTabViewShell::SetDragLink(const OUString& rDoc, const OUString& rTab, const OUString& rArea)
+{
+ ResetDragObject();
+ m_pDragData->aLinkDoc = rDoc;
+ m_pDragData->aLinkTable = rTab;
+ m_pDragData->aLinkArea = rArea;
+}
+
+void ScTabViewShell::SetDragJump(ScDocument* pLocalDoc, const OUString& rTarget, const OUString& rText)
+{
+ ResetDragObject();
+ m_pDragData->pJumpLocalDoc = pLocalDoc;
+ m_pDragData->aJumpTarget = rTarget;
+ m_pDragData->aJumpText = rText;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwsh5.cxx b/sc/source/ui/view/tabvwsh5.cxx
new file mode 100644
index 000000000..ae0b86f86
--- /dev/null
+++ b/sc/source/ui/view/tabvwsh5.cxx
@@ -0,0 +1,390 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/hint.hxx>
+#include <comphelper/lok.hxx>
+#include <svx/numfmtsh.hxx>
+#include <svx/numinf.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <osl/diagnose.h>
+
+#include <tabvwsh.hxx>
+#include <global.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <formulacell.hxx>
+#include <scmod.hxx>
+#include <uiitems.hxx>
+#include <hints.hxx>
+#include <cellvalue.hxx>
+#include <svl/numformat.hxx>
+#include <svl/sharedstring.hxx>
+
+void ScTabViewShell::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ if (const ScPaintHint* pPaintHint = dynamic_cast<const ScPaintHint*>(&rHint)) // draw new
+ {
+ PaintPartFlags nParts = pPaintHint->GetParts();
+ SCTAB nTab = GetViewData().GetTabNo();
+ if (pPaintHint->GetStartTab() <= nTab && pPaintHint->GetEndTab() >= nTab)
+ {
+ if (nParts & PaintPartFlags::Extras) // first if table vanished !!!
+ if (PaintExtras())
+ nParts = PaintPartFlags::All;
+
+ // if the current sheet has pending row height updates (sheet links refreshed),
+ // execute them before invalidating the window
+ GetViewData().GetDocShell()->UpdatePendingRowHeights( GetViewData().GetTabNo() );
+
+ if (nParts & PaintPartFlags::Size)
+ RepeatResize(); //! InvalidateBorder ???
+ if (nParts & PaintPartFlags::Grid)
+ PaintArea( pPaintHint->GetStartCol(), pPaintHint->GetStartRow(),
+ pPaintHint->GetEndCol(), pPaintHint->GetEndRow() );
+ if (nParts & PaintPartFlags::Marks)
+ PaintArea( pPaintHint->GetStartCol(), pPaintHint->GetStartRow(),
+ pPaintHint->GetEndCol(), pPaintHint->GetEndRow(), ScUpdateMode::Marks );
+ if (nParts & PaintPartFlags::Left)
+ PaintLeftArea( pPaintHint->GetStartRow(), pPaintHint->GetEndRow() );
+ if (nParts & PaintPartFlags::Top)
+ PaintTopArea( pPaintHint->GetStartCol(), pPaintHint->GetEndCol() );
+
+ // #i84689# call UpdateAllOverlays here instead of in ScTabView::PaintArea
+ if (nParts & ( PaintPartFlags::Left | PaintPartFlags::Top )) // only if widths or heights changed
+ UpdateAllOverlays();
+
+ HideNoteMarker();
+ }
+ }
+ else if (auto pEditViewHint = dynamic_cast<const ScEditViewHint*>(&rHint)) // create Edit-View
+ {
+ // ScEditViewHint is only received at active view
+
+ SCTAB nTab = GetViewData().GetTabNo();
+ if ( pEditViewHint->GetTab() == nTab )
+ {
+ SCCOL nCol = pEditViewHint->GetCol();
+ SCROW nRow = pEditViewHint->GetRow();
+ {
+ HideNoteMarker();
+
+ MakeEditView( pEditViewHint->GetEngine(), nCol, nRow );
+
+ StopEditShell(); // shouldn't be set
+
+ ScSplitPos eActive = GetViewData().GetActivePart();
+ if ( GetViewData().HasEditView(eActive) )
+ {
+ // MakeEditView will fail, if the cursor is outside the screen.
+ // Then GetEditView will return a none-active view, therefore
+ // calling HasEditView.
+
+ EditView* pView = GetViewData().GetEditView(eActive); // isn't zero
+
+ SetEditShell(pView, true);
+ }
+ }
+ }
+ }
+ else if (auto pTablesHint = dynamic_cast<const ScTablesHint*>(&rHint)) // table insert / deleted
+ {
+ // first fetch current table (can be changed during DeleteTab on ViewData)
+ SCTAB nActiveTab = GetViewData().GetTabNo();
+
+ SCTAB nTab1 = pTablesHint->GetTab1();
+ SCTAB nTab2 = pTablesHint->GetTab2();
+ sal_uInt16 nId = pTablesHint->GetTablesHintId();
+ switch (nId)
+ {
+ case SC_TAB_INSERTED:
+ GetViewData().InsertTab( nTab1 );
+ break;
+ case SC_TAB_DELETED:
+ GetViewData().DeleteTab( nTab1 );
+ break;
+ case SC_TAB_MOVED:
+ GetViewData().MoveTab( nTab1, nTab2 );
+ break;
+ case SC_TAB_COPIED:
+ GetViewData().CopyTab( nTab1, nTab2 );
+ break;
+ case SC_TAB_HIDDEN:
+ break;
+ case SC_TABS_INSERTED:
+ GetViewData().InsertTabs( nTab1, nTab2 );
+ break;
+ case SC_TABS_DELETED:
+ GetViewData().DeleteTabs( nTab1, nTab2 );
+ break;
+ default:
+ OSL_FAIL("unknown ScTablesHint");
+ }
+
+ // No calling of IsActive() here, because the actions can be coming from Basic
+ // and then also the active view has to be switched.
+
+ SCTAB nNewTab = nActiveTab;
+ bool bStayOnActiveTab = true;
+ switch (nId)
+ {
+ case SC_TAB_INSERTED:
+ if ( nTab1 <= nNewTab ) // insert before
+ ++nNewTab;
+ break;
+ case SC_TAB_DELETED:
+ if ( nTab1 < nNewTab ) // deleted before
+ --nNewTab;
+ else if ( nTab1 == nNewTab ) // deleted current
+ bStayOnActiveTab = false;
+ break;
+ case SC_TAB_MOVED:
+ if ( nNewTab == nTab1 ) // moved table
+ nNewTab = nTab2;
+ else if ( nTab1 < nTab2 ) // moved back
+ {
+ if ( nNewTab > nTab1 && nNewTab <= nTab2 ) // succeeding area
+ --nNewTab;
+ }
+ else // move in front
+ {
+ if ( nNewTab >= nTab2 && nNewTab < nTab1 ) // succeeding area
+ ++nNewTab;
+ }
+ break;
+ case SC_TAB_COPIED:
+ if ( nNewTab >= nTab2 ) // insert before
+ ++nNewTab;
+ break;
+ case SC_TAB_HIDDEN:
+ if ( nTab1 == nNewTab ) // current is hidden
+ bStayOnActiveTab = false;
+ break;
+ case SC_TABS_INSERTED:
+ if ( nTab1 <= nNewTab )
+ nNewTab += nTab2;
+ break;
+ case SC_TABS_DELETED:
+ if ( nTab1 < nNewTab )
+ nNewTab -= nTab2;
+ break;
+ }
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ if ( nNewTab >= rDoc.GetTableCount() )
+ nNewTab = rDoc.GetTableCount() - 1;
+
+ bool bForce = !bStayOnActiveTab;
+ SetTabNo( nNewTab, bForce, false, bStayOnActiveTab );
+ }
+ else if (const ScIndexHint* pIndexHint = dynamic_cast<const ScIndexHint*>(&rHint))
+ {
+ SfxHintId nId = pIndexHint->GetId();
+ sal_uInt16 nIndex = pIndexHint->GetIndex();
+ switch (nId)
+ {
+ case SfxHintId::ScShowRangeFinder:
+ PaintRangeFinder( nIndex );
+ break;
+ default: break;
+ }
+ }
+ else // without parameter
+ {
+ const SfxHintId nSlot = rHint.GetId();
+ switch ( nSlot )
+ {
+ case SfxHintId::ScDataChanged:
+ UpdateFormulas();
+ break;
+
+ case SfxHintId::ScRefModeChanged:
+ {
+ bool bRefMode = SC_MOD()->IsFormulaMode();
+ if (!bRefMode)
+ StopRefMode();
+ else
+ GetSelEngine()->Reset();
+ }
+ break;
+
+ case SfxHintId::ScKillEditView:
+ case SfxHintId::ScKillEditViewNoPaint:
+ if (!comphelper::LibreOfficeKit::isActive()
+ || this == SfxViewShell::Current()
+ || bInPrepareClose
+ || bInDispose)
+ {
+ StopEditShell();
+ KillEditView( nSlot == SfxHintId::ScKillEditViewNoPaint );
+ }
+ break;
+
+ case SfxHintId::DocChanged:
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ if (!rDoc.HasTable( GetViewData().GetTabNo() ))
+ {
+ SetTabNo(0);
+ }
+ }
+ break;
+
+ case SfxHintId::ScDrawLayerNew:
+ MakeDrawView(TRISTATE_INDET);
+ break;
+
+ case SfxHintId::ScDocSaved:
+ {
+ // "Save as" can make a write-protected document writable,
+ // therefore the Layer-Locks anew (#39884#)
+ // (Invalidate etc. is happening already from Sfx)
+ // by SID_EDITDOC no SfxHintId::TitleChanged will occur, that
+ // is why the own hint from DoSaveCompleted
+ //! what is with SfxHintId::SAVECOMPLETED ?
+
+ UpdateLayerLocks();
+
+ // Would be too much to change Design-Mode with every save
+ // (when saving under the name, it should remain unchanged)
+ // Therefore only by SfxHintId::ModeChanged (from ViewFrame)
+ }
+ break;
+
+ case SfxHintId::ModeChanged:
+ // Since you can no longer rely on it where this hint was coming
+ // from, always switch the design mode when the ReadOnly state
+ // really was changed:
+
+ if ( GetViewData().GetSfxDocShell()->IsReadOnly() != bReadOnly )
+ {
+ bReadOnly = GetViewData().GetSfxDocShell()->IsReadOnly();
+
+ SfxBoolItem aItem( SID_FM_DESIGN_MODE, !bReadOnly);
+ GetViewData().GetDispatcher().ExecuteList(SID_FM_DESIGN_MODE,
+ SfxCallMode::ASYNCHRON, { &aItem });
+
+ UpdateInputContext();
+ }
+ break;
+
+ case SfxHintId::ScShowRangeFinder:
+ PaintRangeFinder(-1);
+ break;
+
+ case SfxHintId::ScForceSetTab:
+ SetTabNo( GetViewData().GetTabNo(), true );
+ break;
+
+ case SfxHintId::LanguageChanged:
+ {
+ GetViewFrame()->GetBindings().Invalidate(SID_LANGUAGE_STATUS);
+ if ( ScGridWindow* pWin = GetViewData().GetActiveWin() )
+ pWin->ResetAutoSpell();
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ SfxViewShell::Notify( rBC, rHint );
+}
+
+std::unique_ptr<SvxNumberInfoItem> ScTabViewShell::MakeNumberInfoItem( ScDocument& rDoc, const ScViewData& rViewData )
+{
+
+ // construct NumberInfo item
+
+ SvxNumberValueType eValType = SvxNumberValueType::Undefined;
+ double nCellValue = 0;
+ OUString aCellString;
+
+ ScRefCellValue aCell(rDoc, rViewData.GetCurPos());
+
+ switch (aCell.meType)
+ {
+ case CELLTYPE_VALUE:
+ {
+ nCellValue = aCell.mfValue;
+ eValType = SvxNumberValueType::Number;
+ }
+ break;
+
+ case CELLTYPE_STRING:
+ {
+ aCellString = aCell.mpString->getString();
+ eValType = SvxNumberValueType::String;
+ }
+ break;
+
+ case CELLTYPE_FORMULA:
+ {
+ if (aCell.mpFormula->IsValue())
+ {
+ nCellValue = aCell.mpFormula->GetValue();
+ eValType = SvxNumberValueType::Number;
+ }
+ else
+ {
+ nCellValue = 0;
+ eValType = SvxNumberValueType::Undefined;
+ }
+ }
+ break;
+
+ default:
+ nCellValue = 0;
+ eValType = SvxNumberValueType::Undefined;
+ }
+
+ switch ( eValType )
+ {
+ case SvxNumberValueType::String:
+ return std::make_unique<SvxNumberInfoItem>(
+ rDoc.GetFormatTable(),
+ aCellString,
+ SID_ATTR_NUMBERFORMAT_INFO );
+
+ case SvxNumberValueType::Number:
+ return std::make_unique<SvxNumberInfoItem>(
+ rDoc.GetFormatTable(),
+ nCellValue,
+ SID_ATTR_NUMBERFORMAT_INFO );
+
+ case SvxNumberValueType::Undefined:
+ default:
+ ;
+ }
+
+ return std::make_unique<SvxNumberInfoItem>(
+ rDoc.GetFormatTable(), SID_ATTR_NUMBERFORMAT_INFO);
+}
+
+void ScTabViewShell::UpdateNumberFormatter(
+ const SvxNumberInfoItem& rInfoItem )
+{
+ for ( sal_uInt32 key : rInfoItem.GetDelFormats() )
+ rInfoItem.GetNumberFormatter()->DeleteEntry( key );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwsh8.cxx b/sc/source/ui/view/tabvwsh8.cxx
new file mode 100644
index 000000000..9a743c295
--- /dev/null
+++ b/sc/source/ui/view/tabvwsh8.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 <editeng/borderline.hxx>
+
+#include <tabvwsh.hxx>
+#include <document.hxx>
+
+void ScTabViewShell::SetDefaultFrameLine( const ::editeng::SvxBorderLine* pLine )
+{
+ if ( pLine )
+ {
+ pCurFrameLine.reset( new ::editeng::SvxBorderLine( &pLine->GetColor(),
+ pLine->GetWidth(),
+ pLine->GetBorderLineStyle() ) );
+ }
+ else
+ pCurFrameLine.reset();
+}
+
+bool ScTabViewShell::HasSelection( bool bText ) const
+{
+ bool bHas = false;
+ ScViewData& rData = const_cast<ScViewData&>(GetViewData());
+ if ( bText )
+ {
+ // Content contained: Count2 >= 1
+ ScDocument& rDoc = rData.GetDocument();
+ ScMarkData& rMark = rData.GetMarkData();
+ ScAddress aCursor( rData.GetCurX(), rData.GetCurY(), rData.GetTabNo() );
+ double fVal = 0.0;
+ if ( rDoc.GetSelectionFunction( SUBTOTAL_FUNC_CNT2, aCursor, rMark, fVal ) )
+ bHas = ( fVal > 0.5 );
+ }
+ else
+ {
+ ScRange aRange;
+ ScMarkType eMarkType = rData.GetSimpleArea( aRange );
+ if ( eMarkType == SC_MARK_SIMPLE )
+ bHas = ( aRange.aStart != aRange.aEnd ); // more than 1 cell
+ else
+ bHas = true; // multiple selection or filtered
+ }
+ return bHas;
+}
+
+void ScTabViewShell::UIDeactivated( SfxInPlaceClient* pClient )
+{
+ ClearHighlightRanges();
+
+ // Move in the ViewShell should really be called from Sfx, when the
+ // frame window is moved due to different toolboxes or other things
+ // (to not move painted objects by mistake, #56515#).
+ // this mechanism does however not work at the moment, that is why this
+ // call is here (in Move it is checked if the position has really changed).
+ ForceMove();
+ SfxViewShell::UIDeactivated( pClient );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwsh9.cxx b/sc/source/ui/view/tabvwsh9.cxx
new file mode 100644
index 000000000..03aa0615c
--- /dev/null
+++ b/sc/source/ui/view/tabvwsh9.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 <svx/imapdlg.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdview.hxx>
+#include <svx/ImageMapInfo.hxx>
+#include <svx/svxids.hrc>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/sidebar/Sidebar.hxx>
+#include <svl/whiter.hxx>
+#include <svl/stritem.hxx>
+
+#include "imapwrap.hxx"
+#include <tabvwsh.hxx>
+#include <viewdata.hxx>
+#include <docsh.hxx>
+
+#include <svx/galleryitem.hxx>
+#include <com/sun/star/gallery/GalleryItemType.hpp>
+
+class SvxIMapDlg;
+
+void ScTabViewShell::ExecChildWin(const SfxRequest& rReq)
+{
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch(nSlot)
+ {
+ case SID_GALLERY:
+ {
+ // First make sure that the sidebar is visible
+ GetViewFrame()->ShowChildWindow(SID_SIDEBAR);
+
+ ::sfx2::sidebar::Sidebar::ShowPanel(
+ u"GalleryPanel",
+ GetViewFrame()->GetFrame().GetFrameInterface());
+ }
+ break;
+ }
+}
+
+void ScTabViewShell::ExecGallery( const SfxRequest& rReq )
+{
+ const SfxItemSet* pArgs = rReq.GetArgs();
+
+ const SvxGalleryItem* pGalleryItem = SfxItemSet::GetItem<SvxGalleryItem>(pArgs, SID_GALLERY_FORMATS, false);
+ if ( !pGalleryItem )
+ return;
+
+ sal_Int8 nType( pGalleryItem->GetType() );
+ if ( nType == css::gallery::GalleryItemType::GRAPHIC )
+ {
+ MakeDrawLayer();
+
+ Graphic aGraphic( pGalleryItem->GetGraphic() );
+ Point aPos = GetInsertPos();
+
+ PasteGraphic( aPos, aGraphic, OUString() );
+ }
+ else if ( nType == css::gallery::GalleryItemType::MEDIA )
+ {
+ // for sounds (linked or not), insert a hyperlink button,
+ // like in Impress and Writer
+ const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, pGalleryItem->GetURL() );
+ GetViewFrame()->GetDispatcher()->ExecuteList(SID_INSERT_AVMEDIA,
+ SfxCallMode::SYNCHRON, { &aMediaURLItem });
+ }
+}
+
+void ScTabViewShell::ExecImageMap( SfxRequest& rReq )
+{
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch(nSlot)
+ {
+ case SID_IMAP:
+ {
+ SfxViewFrame* pThisFrame = GetViewFrame();
+ sal_uInt16 nId = ScIMapChildWindowId();
+ pThisFrame->ToggleChildWindow( nId );
+ GetViewFrame()->GetBindings().Invalidate( SID_IMAP );
+
+ if ( pThisFrame->HasChildWindow( nId ) )
+ {
+ SvxIMapDlg* pDlg = GetIMapDlg();
+ if ( pDlg )
+ {
+ SdrView* pDrView = GetScDrawView();
+ if ( pDrView )
+ {
+ const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
+ if ( rMarkList.GetMarkCount() == 1 )
+ UpdateIMap( rMarkList.GetMark( 0 )->GetMarkedSdrObj() );
+ }
+ }
+ }
+
+ rReq.Ignore();
+ }
+ break;
+
+ case SID_IMAP_EXEC:
+ {
+ SdrView* pDrView = GetScDrawView();
+ SdrMark* pMark = pDrView ? pDrView->GetMarkedObjectList().GetMark(0) : nullptr;
+
+ if ( pMark )
+ {
+ SdrObject* pSdrObj = pMark->GetMarkedSdrObj();
+ SvxIMapDlg* pDlg = GetIMapDlg();
+
+ if ( ScIMapDlgGetObj(pDlg) == static_cast<void*>(pSdrObj) )
+ {
+ const ImageMap& rImageMap = ScIMapDlgGetMap(pDlg);
+ SvxIMapInfo* pIMapInfo = SvxIMapInfo::GetIMapInfo( pSdrObj );
+
+ if ( !pIMapInfo )
+ pSdrObj->AppendUserData( std::unique_ptr<SdrObjUserData>(new SvxIMapInfo( rImageMap )) );
+ else
+ pIMapInfo->SetImageMap( rImageMap );
+
+ GetViewData().GetDocShell()->SetDrawModified();
+ }
+ }
+ }
+ break;
+ }
+}
+
+void ScTabViewShell::GetImageMapState( SfxItemSet& rSet )
+{
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while ( nWhich )
+ {
+ switch ( nWhich )
+ {
+ case SID_IMAP:
+ {
+ // We don't disable this anymore
+
+ bool bThere = false;
+ SfxViewFrame* pThisFrame = GetViewFrame();
+ sal_uInt16 nId = ScIMapChildWindowId();
+ if ( pThisFrame->KnowsChildWindow(nId) )
+ if ( pThisFrame->HasChildWindow(nId) )
+ bThere = true;
+
+ ObjectSelectionType eType=GetCurObjectSelectionType();
+ bool bEnable=(eType==OST_OleObject) ||(eType==OST_Graphic);
+ if(!bThere && !bEnable)
+ {
+ rSet.DisableItem( nWhich );
+ }
+ else
+ {
+ rSet.Put( SfxBoolItem( nWhich, bThere ) );
+ }
+ }
+ break;
+
+ case SID_IMAP_EXEC:
+ {
+ bool bDisable = true;
+
+ SdrView* pDrView = GetScDrawView();
+ if ( pDrView )
+ {
+ const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
+ if ( rMarkList.GetMarkCount() == 1 )
+ if ( ScIMapDlgGetObj(GetIMapDlg()) ==
+ static_cast<void*>(rMarkList.GetMark(0)->GetMarkedSdrObj()) )
+ bDisable = false;
+ }
+
+ rSet.Put( SfxBoolItem( SID_IMAP_EXEC, bDisable ) );
+ }
+ break;
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwsha.cxx b/sc/source/ui/view/tabvwsha.cxx
new file mode 100644
index 000000000..d44bd6b00
--- /dev/null
+++ b/sc/source/ui/view/tabvwsha.cxx
@@ -0,0 +1,896 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/table/BorderLineStyle.hpp>
+
+#include <comphelper/lok.hxx>
+#include <editeng/boxitem.hxx>
+#include <o3tl/temporary.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/request.hxx>
+#include <sfx2/sfxdlg.hxx>
+#include <sfx2/sidebar/Sidebar.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/ilstitem.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zformat.hxx>
+#include <svl/int64item.hxx>
+#include <svl/srchitem.hxx>
+#include <svl/srchdefs.hxx>
+#include <svl/stritem.hxx>
+#include <svl/whiter.hxx>
+#include <svx/numinf.hxx>
+#include <svx/zoomslideritem.hxx>
+
+#include <global.hxx>
+#include <appoptio.hxx>
+#include <attrib.hxx>
+#include <cellform.hxx>
+#include <cellvalue.hxx>
+#include <compiler.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <formulacell.hxx>
+#include <globstr.hrc>
+#include <inputhdl.hxx>
+#include <inputwin.hxx>
+#include <markdata.hxx>
+#include <patattr.hxx>
+#include <sc.hrc>
+#include <scabstdlg.hxx>
+#include <scitems.hxx>
+#include <scmod.hxx>
+#include <scresid.hxx>
+#include <stlpool.hxx>
+#include <tabvwsh.hxx>
+#include <tokenarray.hxx>
+#include <viewdata.hxx>
+
+#include <memory>
+
+using namespace com::sun::star;
+
+bool ScTabViewShell::GetFunction( OUString& rFuncStr, FormulaError nErrCode )
+{
+ sal_uInt32 nFuncs = SC_MOD()->GetAppOptions().GetStatusFunc();
+ ScViewData& rViewData = GetViewData();
+ ScMarkData& rMark = rViewData.GetMarkData();
+ bool bIgnoreError = (rMark.IsMarked() || rMark.IsMultiMarked());
+ bool bFirst = true;
+ for ( sal_uInt16 nFunc = 0; nFunc < 32; nFunc++ )
+ {
+ if ( !(nFuncs & (1U << nFunc)) )
+ continue;
+ ScSubTotalFunc eFunc = static_cast<ScSubTotalFunc>(nFunc);
+
+ if (bIgnoreError && (eFunc == SUBTOTAL_FUNC_CNT || eFunc == SUBTOTAL_FUNC_CNT2))
+ nErrCode = FormulaError::NONE;
+
+ if (nErrCode != FormulaError::NONE)
+ {
+ rFuncStr = ScGlobal::GetLongErrorString(nErrCode);
+ return true;
+ }
+
+ TranslateId pGlobStrId;
+ switch (eFunc)
+ {
+ case SUBTOTAL_FUNC_AVE: pGlobStrId = STR_FUN_TEXT_AVG; break;
+ case SUBTOTAL_FUNC_CNT: pGlobStrId = STR_FUN_TEXT_COUNT; break;
+ case SUBTOTAL_FUNC_CNT2: pGlobStrId = STR_FUN_TEXT_COUNT2; break;
+ case SUBTOTAL_FUNC_MAX: pGlobStrId = STR_FUN_TEXT_MAX; break;
+ case SUBTOTAL_FUNC_MIN: pGlobStrId = STR_FUN_TEXT_MIN; break;
+ case SUBTOTAL_FUNC_SUM: pGlobStrId = STR_FUN_TEXT_SUM; break;
+ case SUBTOTAL_FUNC_SELECTION_COUNT: pGlobStrId = STR_FUN_TEXT_SELECTION_COUNT; break;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ if (pGlobStrId)
+ {
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCCOL nPosX = rViewData.GetCurX();
+ SCROW nPosY = rViewData.GetCurY();
+ SCTAB nTab = rViewData.GetTabNo();
+
+ OUString aStr = ScResId(pGlobStrId) + ": ";
+
+ ScAddress aCursor( nPosX, nPosY, nTab );
+ double nVal;
+ if ( rDoc.GetSelectionFunction( eFunc, aCursor, rMark, nVal ) )
+ {
+ if ( nVal == 0.0 )
+ aStr += "0";
+ else
+ {
+ // Number in the standard format, the other on the cursor position
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ sal_uInt32 nNumFmt = 0;
+ if ( eFunc != SUBTOTAL_FUNC_CNT && eFunc != SUBTOTAL_FUNC_CNT2 && eFunc != SUBTOTAL_FUNC_SELECTION_COUNT)
+ {
+ // number format from attributes or formula
+ nNumFmt = rDoc.GetNumberFormat( nPosX, nPosY, nTab );
+ // If the number format is time (without date) and the
+ // result is not within 24 hours, use a duration
+ // format. Summing date+time doesn't make much sense
+ // otherwise but we also don't want to display duration
+ // for a single date+time value.
+ if (nVal < 0.0 || nVal >= 1.0)
+ {
+ const SvNumberformat* pFormat = pFormatter->GetEntry(nNumFmt);
+ if (pFormat && (pFormat->GetType() == SvNumFormatType::TIME))
+ nNumFmt = pFormatter->GetTimeFormat( nVal, pFormat->GetLanguage(), true);
+ }
+ }
+
+ OUString aValStr;
+ const Color* pDummy;
+ pFormatter->GetOutputString( nVal, nNumFmt, aValStr, &pDummy );
+ aStr += aValStr;
+ }
+ }
+ if ( bFirst )
+ {
+ rFuncStr += aStr;
+ bFirst = false;
+ }
+ else
+ rFuncStr += "; " + aStr;
+ }
+ }
+
+ return !rFuncStr.isEmpty();
+}
+
+// Functions that are disabled, depending on the selection
+// Default:
+// SID_DELETE,
+// SID_DELETE_CONTENTS,
+// FID_DELETE_CELL
+// FID_VALIDATION
+
+void ScTabViewShell::GetState( SfxItemSet& rSet )
+{
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScDocShell* pDocShell = rViewData.GetDocShell();
+ ScMarkData& rMark = rViewData.GetMarkData();
+ SCCOL nPosX = rViewData.GetCurX();
+ SCROW nPosY = rViewData.GetCurY();
+ SCTAB nTab = rViewData.GetTabNo();
+
+ SfxViewFrame* pThisFrame = GetViewFrame();
+ bool bOle = GetViewFrame()->GetFrame().IsInPlace();
+
+ SCTAB nTabSelCount = rMark.GetSelectCount();
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ while ( nWhich )
+ {
+ switch ( nWhich )
+ {
+ case FID_CHG_COMMENT:
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScAddress aPos( nPosX, nPosY, nTab );
+ if ( pDocSh->IsReadOnly() || !pDocSh->GetChangeAction(aPos) || pDocSh->IsDocShared() )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_OPENDLG_EDIT_PRINTAREA:
+ case SID_ADD_PRINTAREA:
+ case SID_DEFINE_PRINTAREA:
+ {
+ if ( pDocShell && pDocShell->IsDocShared() )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case SID_DELETE_PRINTAREA:
+ if ( pDocShell && pDocShell->IsDocShared() )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ else if (rDoc.IsPrintEntireSheet(nTab))
+ rSet.DisableItem(nWhich);
+ break;
+
+ case SID_STATUS_PAGESTYLE:
+ case SID_HFEDIT:
+ GetViewData().GetDocShell()->GetStatePageStyle( rSet, nTab );
+ break;
+
+ case SID_SEARCH_ITEM:
+ {
+ SvxSearchItem aItem(ScGlobal::GetSearchItem()); // make a copy.
+ // Search on current selection if a range is marked.
+ aItem.SetSelection(rMark.IsMarked());
+ rSet.Put(aItem);
+ break;
+ }
+
+ case SID_SEARCH_OPTIONS:
+ {
+ // Anything goes
+ SearchOptionFlags nOptions = SearchOptionFlags::ALL;
+
+ // No replacement if ReadOnly
+ if (GetViewData().GetDocShell()->IsReadOnly())
+ nOptions &= ~SearchOptionFlags( SearchOptionFlags::REPLACE | SearchOptionFlags::REPLACE_ALL );
+ rSet.Put( SfxUInt16Item( nWhich, static_cast<sal_uInt16>(nOptions) ) );
+ }
+ break;
+
+ case SID_CURRENTCELL:
+ {
+ ScAddress aScAddress( GetViewData().GetCurX(), GetViewData().GetCurY(), 0 );
+ OUString aAddr(aScAddress.Format(ScRefFlags::ADDR_ABS, nullptr, rDoc.GetAddressConvention()));
+ SfxStringItem aPosItem( SID_CURRENTCELL, aAddr );
+
+ rSet.Put( aPosItem );
+ }
+ break;
+
+ case SID_CURRENTTAB:
+ // Table for Basic is 1-based
+ rSet.Put( SfxUInt16Item( nWhich, static_cast<sal_uInt16>(GetViewData().GetTabNo()) + 1 ) );
+ break;
+
+ case SID_CURRENTDOC:
+ rSet.Put( SfxStringItem( nWhich, GetViewData().GetDocShell()->GetTitle() ) );
+ break;
+
+ case FID_TOGGLEINPUTLINE:
+ {
+ sal_uInt16 nId = ScInputWindowWrapper::GetChildWindowId();
+
+ if ( pThisFrame->KnowsChildWindow( nId ) )
+ {
+ SfxChildWindow* pWnd = pThisFrame->GetChildWindow( nId );
+ rSet.Put( SfxBoolItem( nWhich, pWnd != nullptr ) );
+ }
+ else
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case FID_DEL_MANUALBREAKS:
+ if (!rDoc.HasManualBreaks(nTab))
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_RESET_PRINTZOOM:
+ {
+ // disable if already set to default
+
+ OUString aStyleName = rDoc.GetPageStyle( nTab );
+ ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
+ SfxStyleSheetBase* pStyleSheet = pStylePool->Find( aStyleName,
+ SfxStyleFamily::Page );
+ OSL_ENSURE( pStyleSheet, "PageStyle not found" );
+ if ( pStyleSheet )
+ {
+ SfxItemSet& rStyleSet = pStyleSheet->GetItemSet();
+ sal_uInt16 nScale = rStyleSet.Get(ATTR_PAGE_SCALE).GetValue();
+ sal_uInt16 nPages = rStyleSet.Get(ATTR_PAGE_SCALETOPAGES).GetValue();
+ if ( nScale == 100 && nPages == 0 )
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case SID_ZOOM_IN:
+ {
+ const Fraction& rZoomY = GetViewData().GetZoomY();
+ tools::Long nZoom = tools::Long(rZoomY * 100);
+ if (nZoom >= tools::Long(MAXZOOM))
+ rSet.DisableItem(nWhich);
+ }
+ break;
+ case SID_ZOOM_OUT:
+ {
+ const Fraction& rZoomY = GetViewData().GetZoomY();
+ tools::Long nZoom = tools::Long(rZoomY * 100);
+ if (nZoom <= tools::Long(MINZOOM))
+ rSet.DisableItem(nWhich);
+ }
+ break;
+
+ case FID_SCALE:
+ case SID_ATTR_ZOOM:
+ if ( bOle )
+ rSet.DisableItem( nWhich );
+ else
+ {
+ const Fraction& rOldY = GetViewData().GetZoomY();
+ sal_uInt16 nZoom = static_cast<sal_uInt16>(tools::Long( rOldY * 100 ));
+ rSet.Put( SvxZoomItem( SvxZoomType::PERCENT, nZoom, nWhich ) );
+ }
+ break;
+
+ case SID_ATTR_ZOOMSLIDER:
+ {
+ if ( bOle )
+ rSet.DisableItem( nWhich );
+ else
+ {
+ const Fraction& rOldY = GetViewData().GetZoomY();
+ sal_uInt16 nCurrentZoom = static_cast<sal_uInt16>(tools::Long( rOldY * 100 ));
+
+ if( nCurrentZoom )
+ {
+ SvxZoomSliderItem aZoomSliderItem( nCurrentZoom, MINZOOM, MAXZOOM, SID_ATTR_ZOOMSLIDER );
+ aZoomSliderItem.AddSnappingPoint( 100 );
+ rSet.Put( aZoomSliderItem );
+ }
+ }
+ }
+ break;
+
+ case FID_FUNCTION_BOX:
+ {
+ const bool bBoxOpen = ::sfx2::sidebar::Sidebar::IsPanelVisible(u"ScFunctionsPanel",
+ pThisFrame->GetFrame().GetFrameInterface());
+ rSet.Put(SfxBoolItem(nWhich, bBoxOpen));
+ break;
+ }
+
+ case FID_TOGGLESYNTAX:
+ rSet.Put(SfxBoolItem(nWhich, GetViewData().IsSyntaxMode()));
+ break;
+
+ case FID_TOGGLEHEADERS:
+ rSet.Put(SfxBoolItem(nWhich, GetViewData().IsHeaderMode()));
+ break;
+
+ case FID_TOGGLEFORMULA:
+ {
+ const ScViewOptions& rOpts = rViewData.GetOptions();
+ bool bFormulaMode = rOpts.GetOption( VOPT_FORMULAS );
+ rSet.Put(SfxBoolItem(nWhich, bFormulaMode ));
+ }
+ break;
+
+ case FID_NORMALVIEWMODE:
+ case FID_PAGEBREAKMODE:
+ // always handle both slots - they exclude each other
+ if ( bOle )
+ {
+ rSet.DisableItem( FID_NORMALVIEWMODE );
+ rSet.DisableItem( FID_PAGEBREAKMODE );
+ }
+ else
+ {
+ rSet.Put(SfxBoolItem(FID_NORMALVIEWMODE, !GetViewData().IsPagebreakMode()));
+ rSet.Put(SfxBoolItem(FID_PAGEBREAKMODE, GetViewData().IsPagebreakMode()));
+ }
+ break;
+
+ case FID_PROTECT_DOC:
+ {
+ if ( pDocShell && pDocShell->IsDocShared() )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ else
+ {
+ rSet.Put( SfxBoolItem( nWhich, rDoc.IsDocProtected() ) );
+ }
+ }
+ break;
+
+ case FID_PROTECT_TABLE:
+ {
+ if ( pDocShell && pDocShell->IsDocShared() )
+ {
+ rSet.DisableItem( nWhich );
+ }
+ else
+ {
+ rSet.Put( SfxBoolItem( nWhich, rDoc.IsTabProtected( nTab ) ) );
+ }
+ }
+ break;
+
+ case SID_AUTO_OUTLINE:
+ {
+ if (rDoc.GetChangeTrack()!=nullptr || GetViewData().IsMultiMarked())
+ {
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case SID_OUTLINE_DELETEALL:
+ {
+ SCTAB nOlTab = GetViewData().GetTabNo();
+ ScOutlineTable* pOlTable = rDoc.GetOutlineTable( nOlTab );
+ if (pOlTable == nullptr)
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case SID_WINDOW_SPLIT:
+ rSet.Put(SfxBoolItem(nWhich,
+ rViewData.GetHSplitMode() == SC_SPLIT_NORMAL ||
+ rViewData.GetVSplitMode() == SC_SPLIT_NORMAL ));
+ break;
+
+ case SID_WINDOW_FIX:
+ if(!comphelper::LibreOfficeKit::isActive())
+ {
+ rSet.Put(SfxBoolItem(nWhich,
+ rViewData.GetHSplitMode() == SC_SPLIT_FIX ||
+ rViewData.GetVSplitMode() == SC_SPLIT_FIX ));
+ }
+ else
+ {
+ rSet.Put(SfxBoolItem(nWhich,
+ rViewData.GetLOKSheetFreezeIndex(true) > 0 ||
+ rViewData.GetLOKSheetFreezeIndex(false) > 0 ));
+ }
+ break;
+
+ case SID_WINDOW_FIX_COL:
+ case SID_WINDOW_FIX_ROW:
+ {
+ bool bIsCol = (nWhich == SID_WINDOW_FIX_COL);
+ sal_Int32 nFreezeIndex = rViewData.GetLOKSheetFreezeIndex(bIsCol);
+ rSet.Put(SfxInt32Item(nWhich, nFreezeIndex));
+ }
+ break;
+
+ case FID_CHG_SHOW:
+ {
+ if ( rDoc.GetChangeTrack() == nullptr || ( pDocShell && pDocShell->IsDocShared() ) )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+ case FID_CHG_ACCEPT:
+ {
+ if(
+ ( !rDoc.GetChangeTrack() && !pThisFrame->HasChildWindow(FID_CHG_ACCEPT) )
+ ||
+ ( pDocShell && pDocShell->IsDocShared() )
+ )
+ {
+ rSet.DisableItem( nWhich);
+ }
+ else
+ {
+ rSet.Put(SfxBoolItem(FID_CHG_ACCEPT,
+ pThisFrame->HasChildWindow(FID_CHG_ACCEPT)));
+ }
+ }
+ break;
+
+ case SID_FORMATPAGE:
+ // in protected tables
+ if ( pDocShell && ( pDocShell->IsReadOnly() || pDocShell->IsDocShared() ) )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_PRINTPREVIEW:
+ // Toggle slot needs a State
+ rSet.Put( SfxBoolItem( nWhich, false ) );
+ break;
+
+ case SID_READONLY_MODE:
+ rSet.Put( SfxBoolItem( nWhich, GetViewData().GetDocShell()->IsReadOnly() ) );
+ break;
+
+ case FID_TAB_DESELECTALL:
+ if ( nTabSelCount == 1 )
+ rSet.DisableItem( nWhich ); // enabled only if several sheets are selected
+ break;
+
+ case FID_TOGGLEHIDDENCOLROW:
+ const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
+ rSet.Put( SfxBoolItem( nWhich, rColorCfg.GetColorValue(svtools::CALCHIDDENROWCOL).bIsVisible) );
+ break;
+
+ } // switch ( nWitch )
+ nWhich = aIter.NextWhich();
+ } // while ( nWitch )
+}
+
+void ScTabViewShell::ExecuteCellFormatDlg(SfxRequest& rReq, const OString &rName)
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ std::shared_ptr<SvxBoxItem> aLineOuter(std::make_shared<SvxBoxItem>(ATTR_BORDER));
+ std::shared_ptr<SvxBoxInfoItem> aLineInner(std::make_shared<SvxBoxInfoItem>(ATTR_BORDER_INNER));
+
+ const ScPatternAttr* pOldAttrs = GetSelectionPattern();
+
+ auto pOldSet = std::make_shared<SfxItemSet>(pOldAttrs->GetItemSet());
+
+ pOldSet->MergeRange(XATTR_FILLSTYLE, XATTR_FILLCOLOR);
+
+ pOldSet->MergeRange(SID_ATTR_BORDER_STYLES, SID_ATTR_BORDER_DEFAULT_WIDTH);
+
+ // We only allow these border line types.
+ std::vector<sal_Int32> aBorderStyles{
+ table::BorderLineStyle::SOLID,
+ table::BorderLineStyle::DOTTED,
+ table::BorderLineStyle::DASHED,
+ table::BorderLineStyle::FINE_DASHED,
+ table::BorderLineStyle::DASH_DOT,
+ table::BorderLineStyle::DASH_DOT_DOT,
+ table::BorderLineStyle::DOUBLE_THIN };
+
+ pOldSet->Put(SfxIntegerListItem(SID_ATTR_BORDER_STYLES, std::move(aBorderStyles)));
+
+ // Set the default border width to 0.75 points.
+ SfxInt64Item aBorderWidthItem(SID_ATTR_BORDER_DEFAULT_WIDTH, 75);
+ pOldSet->Put(aBorderWidthItem);
+
+ // Get border items and put them in the set:
+ GetSelectionFrame( aLineOuter, aLineInner );
+
+ //Fix border incorrect for RTL fdo#62399
+ if( rDoc.IsLayoutRTL( GetViewData().GetTabNo() ) )
+ {
+ std::unique_ptr<SvxBoxItem> aNewFrame(aLineOuter->Clone());
+ std::unique_ptr<SvxBoxInfoItem> aTempInfo(aLineInner->Clone());
+
+ if ( aLineInner->IsValid(SvxBoxInfoItemValidFlags::LEFT) )
+ aNewFrame->SetLine( aLineOuter->GetLeft(), SvxBoxItemLine::RIGHT );
+ if ( aLineInner->IsValid(SvxBoxInfoItemValidFlags::RIGHT) )
+ aNewFrame->SetLine( aLineOuter->GetRight(), SvxBoxItemLine::LEFT );
+
+ aLineInner->SetValid( SvxBoxInfoItemValidFlags::LEFT, aTempInfo->IsValid(SvxBoxInfoItemValidFlags::RIGHT));
+ aLineInner->SetValid( SvxBoxInfoItemValidFlags::RIGHT, aTempInfo->IsValid(SvxBoxInfoItemValidFlags::LEFT));
+
+ pOldSet->Put( std::move(aNewFrame) );
+ }
+ else
+ {
+ pOldSet->Put( *aLineOuter );
+ }
+
+ pOldSet->Put( *aLineInner );
+
+ // Generate NumberFormat Value from Value and Language and box it.
+ pOldSet->Put( SfxUInt32Item( ATTR_VALUE_FORMAT,
+ pOldAttrs->GetNumberFormat( rDoc.GetFormatTable() ) ) );
+
+ std::unique_ptr<SvxNumberInfoItem> pNumberInfoItem = MakeNumberInfoItem(rDoc, GetViewData());
+ pOldSet->MergeRange( SID_ATTR_NUMBERFORMAT_INFO, SID_ATTR_NUMBERFORMAT_INFO );
+ pOldSet->Put( std::move(pNumberInfoItem) );
+
+ bInFormatDialog = true;
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ VclPtr<SfxAbstractTabDialog> pDlg(pFact->CreateScAttrDlg(GetFrameWeld(), pOldSet.get()));
+
+ if (!rName.isEmpty())
+ pDlg->SetCurPageId(rName);
+
+ auto pRequest = std::make_shared<SfxRequest>(rReq);
+ rReq.Ignore(); // the 'old' request is not relevant any more
+
+ pDlg->StartExecuteAsync([pDlg, pOldSet, pRequest, this](sal_Int32 nResult){
+ bInFormatDialog = false;
+
+ if ( nResult == RET_OK )
+ {
+ const SfxItemSet* pOutSet = pDlg->GetOutputItemSet();
+ if(const SvxNumberInfoItem* pItem = pOutSet->GetItemIfSet(SID_ATTR_NUMBERFORMAT_INFO))
+ {
+ UpdateNumberFormatter(*pItem);
+ }
+
+ ApplyAttributes(pOutSet, pOldSet.get());
+
+ pRequest->Done(*pOutSet);
+ }
+
+ pDlg->disposeOnce();
+ });
+}
+
+bool ScTabViewShell::IsRefInputMode() const
+{
+ ScModule* pScMod = SC_MOD();
+ if ( pScMod )
+ {
+ if( pScMod->IsRefDialogOpen() )
+ return pScMod->IsFormulaMode();
+ if( pScMod->IsFormulaMode() )
+ {
+ ScInputHandler* pHdl = pScMod->GetInputHdl();
+ if ( pHdl )
+ {
+ OUString aString = pHdl->GetEditString();
+ if ( !pHdl->GetSelIsRef() && aString.getLength() > 1 &&
+ ( aString[0] == '+' || aString[0] == '-' ) )
+ {
+ const ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ const ScAddress aPos( rViewData.GetCurPos() );
+ ScCompiler aComp( rDoc, aPos, rDoc.GetGrammar() );
+ aComp.SetCloseBrackets( false );
+ std::unique_ptr<ScTokenArray> pArr(aComp.CompileString(aString));
+ if ( pArr && pArr->MayReferenceFollow() )
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+void ScTabViewShell::ExecuteInputDirect()
+{
+ if ( !IsRefInputMode() )
+ {
+ ScModule* pScMod = SC_MOD();
+ if ( pScMod )
+ {
+ pScMod->InputEnterHandler();
+ }
+ }
+}
+
+void ScTabViewShell::UpdateInputHandler( bool bForce /* = sal_False */, bool bStopEditing /* = sal_True */ )
+{
+ ScInputHandler* pHdl = mpInputHandler ? mpInputHandler.get() : SC_MOD()->GetInputHdl();
+
+ if ( pHdl )
+ {
+ OUString aString;
+ const EditTextObject* pObject = nullptr;
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCCOL nPosX = rViewData.GetCurX();
+ SCROW nPosY = rViewData.GetCurY();
+ SCTAB nTab = rViewData.GetTabNo();
+ SCTAB nStartTab = 0;
+ SCTAB nEndTab = 0;
+ SCCOL nStartCol = 0;
+ SCROW nStartRow = 0;
+ SCCOL nEndCol = 0;
+ SCROW nEndRow = 0;
+ ScAddress aPos = rViewData.GetCurPos();
+
+ rViewData.GetSimpleArea( nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab );
+
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+
+ bool bHideFormula = false;
+ bool bHideAll = false;
+
+ if (rDoc.IsTabProtected(nTab))
+ {
+ const ScProtectionAttr* pProt = rDoc.GetAttr( nPosX,nPosY,nTab,
+ ATTR_PROTECTION);
+ bHideFormula = pProt->GetHideFormula();
+ bHideAll = pProt->GetHideCell();
+ }
+
+ if (!bHideAll)
+ {
+ ScRefCellValue rCell(rDoc, aPos);
+ if (rCell.meType == CELLTYPE_FORMULA)
+ {
+ if (!bHideFormula)
+ aString = rCell.mpFormula->GetFormula();
+ }
+ else if (rCell.meType == CELLTYPE_EDIT)
+ {
+ pObject = rCell.mpEditText;
+ }
+ else
+ {
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ sal_uInt32 nNumFmt = rDoc.GetNumberFormat( aPos );
+
+ aString = ScCellFormat::GetInputString( rCell, nNumFmt, *pFormatter, rDoc );
+ if (rCell.meType == CELLTYPE_STRING)
+ {
+ sal_Int32 i = 0;
+ while (i < aString.getLength() && aString[i] == '\'')
+ ++i;
+ OUString aTest((i && i < aString.getLength()) ? aString.copy(i) : aString);
+ // Put a ' in front if necessary, so that the string is not
+ // unintentionally interpreted as a number, and to show the
+ // user that it is a string (#35060#).
+ // NOTE: this corresponds with
+ // sc/source/core/data/column3.cxx ScColumn::ParseString()
+ // removing one apostrophe also for multiple consecutive
+ // apostrophes.
+ // For number format 'Text' this never results in numeric.
+ if (pFormatter->IsNumberFormat(aTest, nNumFmt, o3tl::temporary(double())))
+ aString = "'" + aString;
+ }
+ }
+ }
+
+ ScInputHdlState aState( ScAddress( nPosX, nPosY, nTab ),
+ ScAddress( nStartCol, nStartRow, nTab ),
+ ScAddress( nEndCol, nEndRow, nTab ),
+ aString,
+ pObject );
+
+ // if using the view's local input handler, this view can always be set
+ // as current view inside NotifyChange.
+ ScTabViewShell* pSourceSh = mpInputHandler ? this : nullptr;
+
+ pHdl->NotifyChange( &aState, bForce, pSourceSh, bStopEditing );
+ }
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( SID_STATUS_SUM ); // always together with the input row
+ rBindings.Invalidate( SID_ATTR_SIZE );
+ rBindings.Invalidate( SID_TABLE_CELL );
+}
+
+void ScTabViewShell::UpdateInputHandlerCellAdjust( SvxCellHorJustify eJust )
+{
+ if( ScInputHandler* pHdl = mpInputHandler ? mpInputHandler.get() : SC_MOD()->GetInputHdl() )
+ pHdl->UpdateCellAdjust( eJust );
+}
+
+void ScTabViewShell::ExecuteSave( SfxRequest& rReq )
+{
+ // only SID_SAVEDOC / SID_SAVEASDOC
+ bool bCommitChanges = true;
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ const SfxPoolItem* pItem;
+
+ if (pReqArgs && pReqArgs->HasItem(FN_PARAM_1, &pItem))
+ bCommitChanges = !static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ // Finish entering unless 'DontTerminateEdit' is specified, even if a formula is being processed
+ if (bCommitChanges)
+ {
+ bool bLOKActive = comphelper::LibreOfficeKit::isActive();
+
+ // Disable error dialog box when about to save in lok mode as
+ // this ultimately invokes SvpSalInstance::DoYield() when we want
+ // to save immediately without committing any erroneous input in possibly
+ // a cell with validation rules. After save is complete the user
+ // can continue editing.
+ SC_MOD()->InputEnterHandler(ScEnterMode::NORMAL, bLOKActive /* bBeforeSavingInLOK */);
+
+ if (bLOKActive)
+ {
+ // Normally this isn't needed, but in Calc when editing a cell formula
+ // and manually saving (without changing cells or hitting enter), while
+ // InputEnterHandler will mark the doc as modified (when it is), because
+ // we will save the doc immediately afterwards, the modified state event
+ // is clobbered. To avoid that, we need to update SID_DOC_MODIFIED so that
+ // a possible state of "true" after "InputEnterHandler" will be sent
+ // as a notification. It is important that the notification goes through
+ // normal process (cache) rather than directly notifying the views.
+ // Otherwise, because there is a previous state of "false" in cache, the
+ // "false" state after saving will be ignored.
+ // This will work only if .uno:ModifiedStatus message will be removed from
+ // the mechanism that keeps in the message queue only last message of
+ // a particular status even if the values are different.
+ GetViewData().GetDocShell()->GetViewBindings()->Update(SID_DOC_MODIFIED);
+ }
+ }
+
+ if ( GetViewData().GetDocShell()->IsDocShared() )
+ {
+ GetViewData().GetDocShell()->SetDocumentModified();
+ }
+
+ // otherwise as normal
+ GetViewData().GetDocShell()->ExecuteSlot( rReq );
+}
+
+void ScTabViewShell::GetSaveState( SfxItemSet& rSet )
+{
+ SfxShell* pDocSh = GetViewData().GetDocShell();
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while( nWhich )
+ {
+ if ( nWhich != SID_SAVEDOC || !GetViewData().GetDocShell()->IsDocShared() )
+ {
+ // get state from DocShell
+ pDocSh->GetSlotState( nWhich, nullptr, &rSet );
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void ScTabViewShell::ExecDrawOpt( const SfxRequest& rReq )
+{
+ ScViewOptions aViewOptions = GetViewData().GetOptions();
+ ScGridOptions aGridOptions = aViewOptions.GetGridOptions();
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ const SfxItemSet* pArgs = rReq.GetArgs();
+ const SfxPoolItem* pItem;
+ sal_uInt16 nSlotId = rReq.GetSlot();
+ switch (nSlotId)
+ {
+ case SID_GRID_VISIBLE:
+ if ( pArgs && pArgs->GetItemState(nSlotId,true,&pItem) == SfxItemState::SET )
+ {
+ aGridOptions.SetGridVisible( static_cast<const SfxBoolItem*>(pItem)->GetValue() );
+ aViewOptions.SetGridOptions(aGridOptions);
+ rBindings.Invalidate(SID_GRID_VISIBLE);
+ }
+ break;
+
+ case SID_GRID_USE:
+ if ( pArgs && pArgs->GetItemState(nSlotId,true,&pItem) == SfxItemState::SET )
+ {
+ aGridOptions.SetUseGridSnap( static_cast<const SfxBoolItem*>(pItem)->GetValue() );
+ aViewOptions.SetGridOptions(aGridOptions);
+ rBindings.Invalidate(SID_GRID_USE);
+ }
+ break;
+
+ case SID_HELPLINES_MOVE:
+ if ( pArgs && pArgs->GetItemState(nSlotId,true,&pItem) == SfxItemState::SET )
+ {
+ aViewOptions.SetOption( VOPT_HELPLINES, static_cast<const SfxBoolItem*>(pItem)->GetValue() );
+ rBindings.Invalidate(SID_HELPLINES_MOVE);
+ }
+ break;
+ }
+
+ GetViewData().SetOptions(aViewOptions);
+}
+
+void ScTabViewShell::GetDrawOptState( SfxItemSet& rSet )
+{
+ SfxBoolItem aBool;
+
+ const ScViewOptions& rViewOptions = GetViewData().GetOptions();
+ const ScGridOptions& rGridOptions = rViewOptions.GetGridOptions();
+
+ aBool.SetValue(rGridOptions.GetGridVisible());
+ aBool.SetWhich( SID_GRID_VISIBLE );
+ rSet.Put( aBool );
+
+ aBool.SetValue(rGridOptions.GetUseGridSnap());
+ aBool.SetWhich( SID_GRID_USE );
+ rSet.Put( aBool );
+
+ aBool.SetValue(rViewOptions.GetOption( VOPT_HELPLINES ));
+ aBool.SetWhich( SID_HELPLINES_MOVE );
+ rSet.Put( aBool );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwshb.cxx b/sc/source/ui/view/tabvwshb.cxx
new file mode 100644
index 000000000..c7265cab1
--- /dev/null
+++ b/sc/source/ui/view/tabvwshb.cxx
@@ -0,0 +1,831 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/chart2/data/XDataReceiver.hpp>
+#include <com/sun/star/awt/XRequestCallback.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+
+#include <com/sun/star/embed/EmbedMisc.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <vcl/errinf.hxx>
+#include <sfx2/app.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <svx/svxdlg.hxx>
+#include <svx/dataaccessdescriptor.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdview.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <svx/fontworkbar.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svtools/soerr.hxx>
+#include <svl/rectitem.hxx>
+#include <svl/stritem.hxx>
+#include <svl/slstitm.hxx>
+#include <svl/whiter.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <sot/exchange.hxx>
+#include <tools/diagnose_ex.h>
+
+#include <tabvwsh.hxx>
+#include <scmod.hxx>
+#include <document.hxx>
+#include <sc.hrc>
+#include <client.hxx>
+#include <fuinsert.hxx>
+#include <docsh.hxx>
+#include <drawview.hxx>
+#include <ChartRangeSelectionListener.hxx>
+#include <gridwin.hxx>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <svx/svdpagv.hxx>
+
+#include <comphelper/lok.hxx>
+
+using namespace com::sun::star;
+
+void ScTabViewShell::ConnectObject( const SdrOle2Obj* pObj )
+{
+ // is called from paint
+
+ uno::Reference < embed::XEmbeddedObject > xObj = pObj->GetObjRef();
+ vcl::Window* pWin = GetActiveWin();
+
+ // when already connected do not execute SetObjArea/SetSizeScale again
+
+ SfxInPlaceClient* pClient = FindIPClient( xObj, pWin );
+ if ( pClient )
+ return;
+
+ pClient = new ScClient( this, pWin, GetScDrawView()->GetModel(), pObj );
+ ScViewData& rViewData = GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bool bNegativeX = comphelper::LibreOfficeKit::isActive() && rDoc.IsNegativePage(rViewData.GetTabNo());
+ if (bNegativeX)
+ pClient->SetNegativeX(true);
+
+ tools::Rectangle aRect = pObj->GetLogicRect();
+ Size aDrawSize = aRect.GetSize();
+
+ Size aOleSize = pObj->GetOrigObjSize();
+
+ Fraction aScaleWidth (aDrawSize.Width(), aOleSize.Width() );
+ Fraction aScaleHeight(aDrawSize.Height(), aOleSize.Height() );
+ aScaleWidth.ReduceInaccurate(10); // compatible with SdrOle2Obj
+ aScaleHeight.ReduceInaccurate(10);
+ pClient->SetSizeScale(aScaleWidth,aScaleHeight);
+
+ // visible section is only changed inplace!
+ // the object area must be set after the scaling since it triggers the resizing
+ aRect.SetSize( aOleSize );
+ pClient->SetObjArea( aRect );
+}
+
+namespace {
+
+class PopupCallback : public cppu::WeakImplHelper<css::awt::XCallback>
+{
+ ScTabViewShell* m_pViewShell;
+ SdrOle2Obj* m_pObject;
+
+public:
+ explicit PopupCallback(ScTabViewShell* pViewShell, SdrOle2Obj* pObject)
+ : m_pViewShell(pViewShell)
+ , m_pObject(pObject)
+ {}
+
+ // XCallback
+ virtual void SAL_CALL notify(const css::uno::Any& aData) override
+ {
+ uno::Sequence<beans::PropertyValue> aProperties;
+ if (!(aData >>= aProperties))
+ return;
+
+ awt::Rectangle xRectangle;
+ sal_Int32 dimensionIndex = 0;
+ OUString sPivotTableName("DataPilot1");
+
+ for (beans::PropertyValue const & rProperty : std::as_const(aProperties))
+ {
+ if (rProperty.Name == "Rectangle")
+ rProperty.Value >>= xRectangle;
+ if (rProperty.Name == "DimensionIndex")
+ rProperty.Value >>= dimensionIndex;
+ if (rProperty.Name == "PivotTableName")
+ rProperty.Value >>= sPivotTableName;
+ }
+
+ tools::Rectangle aChartRect = m_pObject->GetLogicRect();
+
+ Point aPoint(xRectangle.X + aChartRect.Left(), xRectangle.Y + aChartRect.Top());
+ Size aSize(xRectangle.Width, xRectangle.Height);
+
+ m_pViewShell->DoDPFieldPopup(sPivotTableName, dimensionIndex, aPoint, aSize);
+ }
+};
+
+}
+
+void ScTabViewShell::ActivateObject(SdrOle2Obj* pObj, sal_Int32 nVerb)
+{
+ // Do not leave the hint message box on top of the object
+ RemoveHintWindow();
+
+ uno::Reference < embed::XEmbeddedObject > xObj = pObj->GetObjRef();
+ vcl::Window* pWin = GetActiveWin();
+ ErrCode nErr = ERRCODE_NONE;
+ bool bErrorShown = false;
+
+ {
+ ScViewData& rViewData = GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bool bNegativeX = comphelper::LibreOfficeKit::isActive() && rDoc.IsNegativePage(rViewData.GetTabNo());
+ SfxInPlaceClient* pClient = FindIPClient( xObj, pWin );
+ if ( !pClient )
+ pClient = new ScClient( this, pWin, GetScDrawView()->GetModel(), pObj );
+
+ if (bNegativeX)
+ pClient->SetNegativeX(true);
+
+ if ( (sal_uInt32(nErr) & ERRCODE_ERROR_MASK) == 0 && xObj.is() )
+ {
+ 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( MapUnit::Map100thMM );
+ Size aOleSize = pObj->GetOrigObjSize( &aMapMode );
+
+ if ( pClient->GetAspect() != embed::Aspects::MSOLE_ICON
+ && ( xObj->getStatus( pClient->GetAspect() ) & embed::EmbedMisc::MS_EMBED_RECOMPOSEONRESIZE ) )
+ {
+ // scale must always be 1 - change VisArea if different from client size
+
+ if ( aDrawSize != aOleSize )
+ {
+ MapUnit aUnit = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( pClient->GetAspect() ) );
+ aOleSize = OutputDevice::LogicToLogic( aDrawSize,
+ MapMode(MapUnit::Map100thMM), MapMode(aUnit));
+ awt::Size aSz( aOleSize.Width(), aOleSize.Height() );
+ xObj->setVisualAreaSize( pClient->GetAspect(), aSz );
+ }
+ Fraction aOne( 1, 1 );
+ pClient->SetSizeScale( aOne, aOne );
+ }
+ else
+ {
+ // calculate scale from client and VisArea size
+
+ Fraction aScaleWidth (aDrawSize.Width(), aOleSize.Width() );
+ Fraction aScaleHeight(aDrawSize.Height(), aOleSize.Height() );
+ aScaleWidth.ReduceInaccurate(10); // compatible with SdrOle2Obj
+ aScaleHeight.ReduceInaccurate(10);
+ pClient->SetSizeScale(aScaleWidth,aScaleHeight);
+ }
+
+ // visible section is only changed inplace!
+ // the object area must be set after the scaling since it triggers the resizing
+ aRect.SetSize( aOleSize );
+ pClient->SetObjArea( aRect );
+
+ nErr = pClient->DoVerb( nVerb );
+ bErrorShown = true;
+ // SfxViewShell::DoVerb shows its error messages
+
+ // attach listener to selection changes in chart that affect cell
+ // ranges, so those can be highlighted
+ // note: do that after DoVerb, so that the chart controller exists
+ if ( SvtModuleOptions().IsChart() )
+ {
+ SvGlobalName aObjClsId ( xObj->getClassID() );
+ if (SotExchange::IsChart( aObjClsId ))
+ {
+ try
+ {
+ uno::Reference < embed::XComponentSupplier > xSup( xObj, uno::UNO_QUERY_THROW );
+ uno::Reference< chart2::data::XDataReceiver > xDataReceiver(
+ xSup->getComponent(), uno::UNO_QUERY_THROW );
+ uno::Reference< chart2::data::XRangeHighlighter > xRangeHighlighter(
+ xDataReceiver->getRangeHighlighter());
+ if (xRangeHighlighter.is())
+ {
+ uno::Reference< view::XSelectionChangeListener > xListener(
+ new ScChartRangeSelectionListener( this ));
+ xRangeHighlighter->addSelectionChangeListener( xListener );
+ }
+ uno::Reference<awt::XRequestCallback> xPopupRequest(xDataReceiver->getPopupRequest());
+ if (xPopupRequest.is())
+ {
+ uno::Reference<awt::XCallback> xCallback(new PopupCallback(this, pObj));
+ uno::Any aAny;
+ xPopupRequest->addCallback(xCallback, aAny);
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ TOOLS_WARN_EXCEPTION( "sc", "Exception caught while querying chart" );
+ }
+ }
+ }
+ }
+ }
+ if (nErr != ERRCODE_NONE && !bErrorShown)
+ ErrorHandler::HandleError(nErr);
+
+ // #i118524# refresh handles to suppress for activated OLE
+ if(GetScDrawView())
+ {
+ GetScDrawView()->AdjustMarkHdl();
+ }
+ //! SetDocumentName should already happen in Sfx ???
+ //TODO/LATER: how "SetDocumentName"?
+ //xIPObj->SetDocumentName( GetViewData().GetDocShell()->GetTitle() );
+}
+
+ErrCode ScTabViewShell::DoVerb(sal_Int32 nVerb)
+{
+ SdrView* pView = GetScDrawView();
+ if (!pView)
+ return ERRCODE_SO_NOTIMPL; // should not be
+
+ SdrOle2Obj* pOle2Obj = nullptr;
+
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if (pObj->GetObjIdentifier() == SdrObjKind::OLE2)
+ pOle2Obj = static_cast<SdrOle2Obj*>(pObj);
+ }
+
+ if (pOle2Obj)
+ {
+ ActivateObject( pOle2Obj, nVerb );
+ }
+ else
+ {
+ OSL_FAIL("no object for Verb found");
+ }
+
+ return ERRCODE_NONE;
+}
+
+void ScTabViewShell::DeactivateOle()
+{
+ // deactivate inplace editing if currently active
+
+ ScModule* pScMod = SC_MOD();
+ bool bUnoRefDialog = pScMod->IsRefDialogOpen() && pScMod->GetCurRefDlgId() == WID_SIMPLE_REF;
+
+ ScClient* pClient = static_cast<ScClient*>(GetIPClient());
+ if ( pClient && pClient->IsObjectInPlaceActive() && !bUnoRefDialog )
+ pClient->DeactivateObject();
+}
+
+IMPL_LINK( ScTabViewShell, DialogClosedHdl, css::ui::dialogs::DialogClosedEvent*, pEvent, void )
+{
+ if( pEvent->DialogResult == ui::dialogs::ExecutableDialogResults::CANCEL )
+ {
+ ScTabView* pTabView = GetViewData().GetView();
+ ScDrawView* pView = pTabView->GetScDrawView();
+ ScViewData& rData = GetViewData();
+ ScDocShell* pScDocSh = rData.GetDocShell();
+ ScDocument& rScDoc = pScDocSh->GetDocument();
+ // leave OLE inplace mode and unmark
+ OSL_ASSERT( pView );
+ DeactivateOle();
+ pView->UnMarkAll();
+
+ rScDoc.GetUndoManager()->Undo();
+ rScDoc.GetUndoManager()->ClearRedo();
+
+ // leave the draw shell
+ SetDrawShell( false );
+
+ // reset marked cell area
+ ScMarkData aMark = GetViewData().GetMarkData();
+ GetViewData().GetViewShell()->SetMarkData(aMark);
+ }
+ else
+ {
+ OSL_ASSERT( pEvent->DialogResult == ui::dialogs::ExecutableDialogResults::OK );
+ //@todo maybe move chart to different table
+ }
+}
+
+void ScTabViewShell::ExecDrawIns(SfxRequest& rReq)
+{
+ sal_uInt16 nSlot = rReq.GetSlot();
+ if (nSlot != SID_OBJECTRESIZE )
+ {
+ SC_MOD()->InputEnterHandler();
+ UpdateInputHandler();
+ }
+
+ // insertion of border for Chart is cancelled:
+ FuPoor* pPoor = GetDrawFuncPtr();
+ if ( pPoor && pPoor->GetSlotID() == SID_DRAW_CHART )
+ GetViewData().GetDispatcher().Execute(SID_DRAW_CHART, SfxCallMode::SLOT | SfxCallMode::RECORD);
+
+ MakeDrawLayer();
+
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ ScTabView* pTabView = GetViewData().GetView();
+ vcl::Window* pWin = pTabView->GetActiveWin();
+ ScDrawView* pView = pTabView->GetScDrawView();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SdrModel* pDrModel = pView->GetModel();
+
+ switch ( nSlot )
+ {
+ case SID_INSERT_GRAPHIC:
+ FuInsertGraphic(*this, pWin, pView, pDrModel, rReq);
+ // shell is set in MarkListHasChanged
+ break;
+
+ case SID_INSERT_AVMEDIA:
+ FuInsertMedia(*this, pWin, pView, pDrModel, rReq);
+ // shell is set in MarkListHasChanged
+ break;
+
+ case SID_INSERT_DIAGRAM:
+ FuInsertChart(*this, pWin, pView, pDrModel, rReq, LINK( this, ScTabViewShell, DialogClosedHdl ));
+ if (comphelper::LibreOfficeKit::isActive())
+ pDocSh->SetModified();
+ break;
+
+ case SID_INSERT_OBJECT:
+ case SID_INSERT_SMATH:
+ case SID_INSERT_FLOATINGFRAME:
+ FuInsertOLE(*this, pWin, pView, pDrModel, rReq);
+ break;
+
+ case SID_INSERT_SIGNATURELINE:
+ case SID_EDIT_SIGNATURELINE:
+ {
+ const uno::Reference<frame::XModel> xModel( GetViewData().GetDocShell()->GetBaseModel() );
+
+ VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSignatureLineDialog> pDialog(pFact->CreateSignatureLineDialog(
+ pWin->GetFrameWeld(), xModel, rReq.GetSlot() == SID_EDIT_SIGNATURELINE));
+ pDialog->Execute();
+ break;
+ }
+
+ case SID_SIGN_SIGNATURELINE:
+ {
+ const uno::Reference<frame::XModel> xModel(
+ GetViewData().GetDocShell()->GetBaseModel());
+
+ VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractSignSignatureLineDialog> pDialog(
+ pFact->CreateSignSignatureLineDialog(GetFrameWeld(), xModel));
+ pDialog->Execute();
+ break;
+ }
+
+ case SID_INSERT_QRCODE:
+ case SID_EDIT_QRCODE:
+ {
+ const uno::Reference<frame::XModel> xModel( GetViewData().GetDocShell()->GetBaseModel() );
+
+ VclAbstractDialogFactory* pFact = VclAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractQrCodeGenDialog> pDialog(pFact->CreateQrCodeGenDialog(
+ pWin->GetFrameWeld(), xModel, rReq.GetSlot() == SID_EDIT_QRCODE));
+ pDialog->Execute();
+ 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> pDialog(
+ pFact->CreateAdditionsDialog(pWin->GetFrameWeld(), sAdditionsTag));
+ pDialog->Execute();
+ break;
+ }
+
+ case SID_OBJECTRESIZE:
+ {
+ // the server would like to change the client size
+
+ SfxInPlaceClient* pClient = GetIPClient();
+
+ if ( pClient && pClient->IsObjectInPlaceActive() )
+ {
+ const SfxRectangleItem& rRect = rReq.GetArgs()->Get(SID_OBJECTRESIZE);
+ tools::Rectangle aRect( pWin->PixelToLogic( rRect.GetValue() ) );
+
+ if ( pView->AreObjectsMarked() )
+ {
+ const SdrMarkList& rMarkList = pView->GetMarkedObjectList();
+
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrMark* pMark = rMarkList.GetMark(0);
+ SdrObject* pObj = pMark->GetMarkedSdrObj();
+
+ SdrObjKind nSdrObjKind = pObj->GetObjIdentifier();
+
+ if (nSdrObjKind == SdrObjKind::OLE2)
+ {
+ if ( static_cast<SdrOle2Obj*>(pObj)->GetObjRef().is() )
+ {
+ pObj->SetLogicRect(aRect);
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case SID_LINKS:
+ {
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<SfxAbstractLinksDialog> pDlg(pFact->CreateLinksDialog(pWin->GetFrameWeld(), rDoc.GetLinkManager()));
+ pDlg->Execute();
+ rBindings.Invalidate( nSlot );
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) ); // Navigator
+ rReq.Done();
+ }
+ break;
+
+ case SID_FM_CREATE_FIELDCONTROL:
+ {
+ const SfxUnoAnyItem* pDescriptorItem = rReq.GetArg<SfxUnoAnyItem>(SID_FM_DATACCESS_DESCRIPTOR);
+ OSL_ENSURE( pDescriptorItem, "SID_FM_CREATE_FIELDCONTROL: invalid request args!" );
+
+ if(pDescriptorItem)
+ {
+ //! merge with ScViewFunc::PasteDataFormat (SotClipboardFormatId::SBA_FIELDDATAEXCHANGE)?
+
+ ScDrawView* pDrView = GetScDrawView();
+ SdrPageView* pPageView = pDrView ? pDrView->GetSdrPageView() : nullptr;
+ if(pPageView)
+ {
+ svx::ODataAccessDescriptor aDescriptor(pDescriptorItem->GetValue());
+ SdrObjectUniquePtr pNewDBField = pDrView->CreateFieldControl(aDescriptor);
+
+ if(pNewDBField)
+ {
+ tools::Rectangle aVisArea = pWin->PixelToLogic(tools::Rectangle(Point(0,0), pWin->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);
+
+ // controls must be on control layer, groups on front layer
+ if ( dynamic_cast<const SdrUnoObj*>( pNewDBField.get() ) != nullptr )
+ pNewDBField->NbcSetLayer(SC_LAYER_CONTROLS);
+ else
+ pNewDBField->NbcSetLayer(SC_LAYER_FRONT);
+ if (dynamic_cast<const SdrObjGroup*>( pNewDBField.get() ) != nullptr)
+ {
+ SdrObjListIter aIter( *pNewDBField, SdrIterMode::DeepWithGroups );
+ SdrObject* pSubObj = aIter.Next();
+ while (pSubObj)
+ {
+ if ( dynamic_cast<const SdrUnoObj*>( pSubObj) != nullptr )
+ pSubObj->NbcSetLayer(SC_LAYER_CONTROLS);
+ else
+ pSubObj->NbcSetLayer(SC_LAYER_FRONT);
+ pSubObj = aIter.Next();
+ }
+ }
+
+ pView->InsertObjectAtView(pNewDBField.release(), *pPageView);
+ }
+ }
+ }
+ rReq.Done();
+ }
+ break;
+
+ case SID_FONTWORK_GALLERY_FLOATER:
+ svx::FontworkBar::execute(*pView, rReq, GetViewFrame()->GetBindings());
+ rReq.Ignore();
+ break;
+ }
+}
+
+void ScTabViewShell::GetDrawInsState(SfxItemSet &rSet)
+{
+ bool bOle = GetViewFrame()->GetFrame().IsInPlace();
+ bool bTabProt = GetViewData().GetDocument().IsTabProtected(GetViewData().GetTabNo());
+ ScDocShell* pDocShell = GetViewData().GetDocShell();
+ bool bShared = pDocShell && pDocShell->IsDocShared();
+ SdrView* pSdrView = GetScDrawView();
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while ( nWhich )
+ {
+ switch ( nWhich )
+ {
+ case SID_INSERT_DIAGRAM:
+ if ( bOle || bTabProt || !SvtModuleOptions().IsChart() || bShared )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_INSERT_SMATH:
+ if ( bOle || bTabProt || !SvtModuleOptions().IsMath() || bShared )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_INSERT_OBJECT:
+ case SID_INSERT_FLOATINGFRAME:
+ if ( bOle || bTabProt || bShared )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_INSERT_AVMEDIA:
+ case SID_FONTWORK_GALLERY_FLOATER:
+ if ( bTabProt || bShared )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case SID_INSERT_SIGNATURELINE:
+ if ( bTabProt || bShared || (pSdrView && pSdrView->GetMarkedObjectCount() != 0))
+ rSet.DisableItem( nWhich );
+ break;
+ case SID_EDIT_SIGNATURELINE:
+ case SID_SIGN_SIGNATURELINE:
+ if (!IsSignatureLineSelected() || IsSignatureLineSigned())
+ rSet.DisableItem(nWhich);
+ break;
+
+ case SID_INSERT_QRCODE:
+ if ( bTabProt || bShared || (pSdrView && pSdrView->GetMarkedObjectCount() != 0))
+ rSet.DisableItem( nWhich );
+ break;
+ case SID_EDIT_QRCODE:
+ if (!IsQRCodeSelected())
+ rSet.DisableItem(nWhich);
+ break;
+
+ case SID_INSERT_GRAPHIC:
+ if (bTabProt || bShared)
+ {
+ // do not disable 'insert graphic' item if the currently marked area is editable (not protected)
+ // if there is no marked area, check the current cell
+ bool bDisableInsertImage = true;
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ if (!rMark.GetMarkedRanges().empty() && GetViewData().GetDocument().IsSelectionEditable(rMark))
+ bDisableInsertImage = false;
+ else
+ {
+ if (GetViewData().GetDocument().IsBlockEditable
+ (GetViewData().GetTabNo(), GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetCurX(), GetViewData().GetCurY()))
+ {
+ bDisableInsertImage = false;
+ }
+ }
+
+ if (bDisableInsertImage)
+ rSet.DisableItem(nWhich);
+ }
+ break;
+
+ case SID_LINKS:
+ {
+ if (GetViewData().GetDocument().GetLinkManager()->GetLinks().empty())
+ rSet.DisableItem( SID_LINKS );
+ }
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+bool ScTabViewShell::IsSignatureLineSelected()
+{
+ SdrView* pSdrView = GetScDrawView();
+ if (!pSdrView)
+ return false;
+
+ if (pSdrView->GetMarkedObjectCount() != 1)
+ return false;
+
+ SdrObject* pPickObj = pSdrView->GetMarkedObjectByIndex(0);
+ if (!pPickObj)
+ return false;
+
+ SdrGrafObj* pGraphic = dynamic_cast<SdrGrafObj*>(pPickObj);
+ if (!pGraphic)
+ return false;
+
+ return pGraphic->isSignatureLine();
+}
+
+bool ScTabViewShell::IsQRCodeSelected()
+{
+ SdrView* pSdrView = GetScDrawView();
+ if (!pSdrView)
+ return false;
+
+ if (pSdrView->GetMarkedObjectCount() != 1)
+ return false;
+
+ SdrObject* pPickObj = pSdrView->GetMarkedObjectByIndex(0);
+ if (!pPickObj)
+ return false;
+
+ SdrGrafObj* pGraphic = dynamic_cast<SdrGrafObj*>(pPickObj);
+ if (!pGraphic)
+ return false;
+
+ if(pGraphic->getQrCode())
+ {
+ return true;
+ }
+ else{
+ return false;
+ }
+}
+
+bool ScTabViewShell::IsSignatureLineSigned()
+{
+ SdrView* pSdrView = GetScDrawView();
+ if (!pSdrView)
+ return false;
+
+ if (pSdrView->GetMarkedObjectCount() != 1)
+ return false;
+
+ SdrObject* pPickObj = pSdrView->GetMarkedObjectByIndex(0);
+ if (!pPickObj)
+ return false;
+
+ SdrGrafObj* pGraphic = dynamic_cast<SdrGrafObj*>(pPickObj);
+ if (!pGraphic)
+ return false;
+
+ return pGraphic->isSignatureLineSigned();
+}
+
+void ScTabViewShell::ExecuteUndo(SfxRequest& rReq)
+{
+ SfxShell* pSh = GetViewData().GetDispatcher().GetShell(0);
+ SfxUndoManager* pUndoManager = pSh->GetUndoManager();
+
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+
+ sal_uInt16 nSlot = rReq.GetSlot();
+ switch ( nSlot )
+ {
+ case SID_UNDO:
+ case SID_REDO:
+ if ( pUndoManager )
+ {
+ bool bIsUndo = ( nSlot == SID_UNDO );
+
+ sal_uInt16 nCount = 1;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && pReqArgs->GetItemState( nSlot, true, &pItem ) == SfxItemState::SET )
+ nCount = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
+
+ // Repair mode: allow undo/redo of all undo actions, even if access would
+ // be limited based on the view shell ID.
+ bool bRepair = false;
+ if (pReqArgs && pReqArgs->GetItemState(SID_REPAIRPACKAGE, false, &pItem) == SfxItemState::SET)
+ bRepair = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ if (comphelper::LibreOfficeKit::isActive() && !bRepair)
+ {
+ SfxUndoAction* pAction = nullptr;
+ if (bIsUndo)
+ {
+ if (pUndoManager->GetUndoActionCount() != 0)
+ pAction = pUndoManager->GetUndoAction();
+ }
+ else
+ {
+ if (pUndoManager->GetRedoActionCount() != 0)
+ pAction = pUndoManager->GetRedoAction();
+ }
+ if (pAction)
+ {
+ ViewShellId nViewShellId = GetViewShellId();
+ if (pAction->GetViewShellId() != nViewShellId)
+ {
+ rReq.SetReturnValue(SfxUInt32Item(SID_UNDO, static_cast<sal_uInt32>(SID_REPAIRPACKAGE)));
+ return;
+ }
+ }
+ }
+
+ // lock paint for more than one cell undo action (not for editing within a cell)
+ bool bLockPaint = ( nCount > 1 && pUndoManager == GetUndoManager() );
+ if ( bLockPaint )
+ pDocSh->LockPaint();
+
+ try
+ {
+ for (sal_uInt16 i=0; i<nCount; i++)
+ {
+ if ( bIsUndo )
+ pUndoManager->Undo();
+ else
+ pUndoManager->Redo();
+ }
+ }
+ catch ( const uno::Exception& )
+ {
+ // no need to handle. By definition, the UndoManager handled this by clearing the
+ // Undo/Redo stacks
+ }
+
+ if ( bLockPaint )
+ pDocSh->UnlockPaint();
+
+ GetViewFrame()->GetBindings().InvalidateAll(false);
+ }
+ break;
+// default:
+// GetViewFrame()->ExecuteSlot( rReq );
+ }
+}
+
+void ScTabViewShell::GetUndoState(SfxItemSet &rSet)
+{
+ SfxShell* pSh = GetViewData().GetDispatcher().GetShell(0);
+ SfxUndoManager* pUndoManager = pSh->GetUndoManager();
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while ( nWhich )
+ {
+ switch (nWhich)
+ {
+ case SID_GETUNDOSTRINGS:
+ case SID_GETREDOSTRINGS:
+ {
+ SfxStringListItem aStrLst( nWhich );
+ if ( pUndoManager )
+ {
+ std::vector<OUString> &aList = aStrLst.GetList();
+ bool bIsUndo = ( nWhich == SID_GETUNDOSTRINGS );
+ size_t nCount = bIsUndo ? pUndoManager->GetUndoActionCount() : pUndoManager->GetRedoActionCount();
+ for (size_t i=0; i<nCount; ++i)
+ {
+ aList.push_back( bIsUndo ? pUndoManager->GetUndoActionComment(i) :
+ pUndoManager->GetRedoActionComment(i) );
+ }
+ }
+ rSet.Put( aStrLst );
+ }
+ break;
+ default:
+ // get state from sfx view frame
+ GetViewFrame()->GetSlotState( nWhich, nullptr, &rSet );
+ }
+
+ nWhich = aIter.NextWhich();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwshc.cxx b/sc/source/ui/view/tabvwshc.cxx
new file mode 100644
index 000000000..e4d95ed55
--- /dev/null
+++ b/sc/source/ui/view/tabvwshc.cxx
@@ -0,0 +1,745 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <sfx2/childwin.hxx>
+#include <sfx2/dispatch.hxx>
+#include <editeng/editview.hxx>
+#include <inputhdl.hxx>
+
+#include <tabvwsh.hxx>
+#include <sc.hrc>
+#include <scres.hrc>
+#include <global.hxx>
+#include <scmod.hxx>
+#include <document.hxx>
+#include <uiitems.hxx>
+#include <namedlg.hxx>
+#include <namedefdlg.hxx>
+#include <solvrdlg.hxx>
+#include <optsolver.hxx>
+#include <tabopdlg.hxx>
+#include <consdlg.hxx>
+#include <filtdlg.hxx>
+#include <dbnamdlg.hxx>
+#include <areasdlg.hxx>
+#include <crnrdlg.hxx>
+#include <formula.hxx>
+#include <highred.hxx>
+#include <simpref.hxx>
+#include <funcdesc.hxx>
+#include <dpobject.hxx>
+#include <markdata.hxx>
+#include <reffact.hxx>
+#include <condformatdlg.hxx>
+#include <xmlsourcedlg.hxx>
+#include <condformatdlgitem.hxx>
+#include <formdata.hxx>
+#include <inputwin.hxx>
+
+#include <RandomNumberGeneratorDialog.hxx>
+#include <SamplingDialog.hxx>
+#include <DescriptiveStatisticsDialog.hxx>
+#include <AnalysisOfVarianceDialog.hxx>
+#include <CorrelationDialog.hxx>
+#include <CovarianceDialog.hxx>
+#include <ExponentialSmoothingDialog.hxx>
+#include <MovingAverageDialog.hxx>
+#include <RegressionDialog.hxx>
+#include <TTestDialog.hxx>
+#include <FTestDialog.hxx>
+#include <ZTestDialog.hxx>
+#include <ChiSquareTestDialog.hxx>
+#include <FourierAnalysisDialog.hxx>
+
+#include <PivotLayoutDialog.hxx>
+#include <SparklineDialog.hxx>
+#include <SparklineDataRangeDialog.hxx>
+
+#include <comphelper/lok.hxx>
+#include <o3tl/make_shared.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+
+void ScTabViewShell::SetCurRefDlgId( sal_uInt16 nNew )
+{
+ // CurRefDlgId is stored in ScModule to find if a ref dialog is open,
+ // and in the view to identify the view that has opened the dialog
+ nCurRefDlgId = nNew;
+}
+
+//ugly hack to call Define Name from Manage Names
+void ScTabViewShell::SwitchBetweenRefDialogs(SfxModelessDialogController* pDialog)
+{
+ sal_uInt16 nSlotId = SC_MOD()->GetCurRefDlgId();
+ if( nSlotId == FID_ADD_NAME )
+ {
+ static_cast<ScNameDefDlg*>(pDialog)->GetNewData(maName, maScope);
+ static_cast<ScNameDefDlg*>(pDialog)->Close();
+ sal_uInt16 nId = ScNameDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ SC_MOD()->SetRefDialog( nId, pWnd == nullptr );
+ }
+ else if (nSlotId == FID_DEFINE_NAME)
+ {
+ mbInSwitch = true;
+ static_cast<ScNameDlg*>(pDialog)->GetRangeNames(m_RangeMap);
+ static_cast<ScNameDlg*>(pDialog)->Close();
+ sal_uInt16 nId = ScNameDefDlgWrapper::GetChildWindowId();
+ SfxViewFrame* pViewFrm = GetViewFrame();
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow( nId );
+
+ SC_MOD()->SetRefDialog( nId, pWnd == nullptr );
+ }
+}
+
+std::shared_ptr<SfxModelessDialogController> ScTabViewShell::CreateRefDialogController(
+ SfxBindings* pB, SfxChildWindow* pCW,
+ const SfxChildWinInfo* pInfo,
+ weld::Window* pParent, sal_uInt16 nSlotId)
+{
+ // only open dialog when called through ScModule::SetRefDialog,
+ // so that it does not re appear for instance after a crash (#42341#).
+
+ if ( SC_MOD()->GetCurRefDlgId() != nSlotId )
+ return nullptr;
+
+ if ( nCurRefDlgId != nSlotId )
+ {
+ if (!(comphelper::LibreOfficeKit::isActive() && nSlotId == SID_OPENDLG_FUNCTION))
+ {
+ // the dialog has been opened in a different view
+ // -> lock the dispatcher for this view (modal mode)
+
+ GetViewData().GetDispatcher().Lock( true ); // lock is reset when closing dialog
+ }
+ return nullptr;
+ }
+
+ std::shared_ptr<SfxModelessDialogController> xResult;
+
+ if(pCW)
+ pCW->SetHideNotDelete(true);
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ switch( nSlotId )
+ {
+ case SID_CORRELATION_DIALOG:
+ xResult = std::make_shared<ScCorrelationDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_SAMPLING_DIALOG:
+ xResult = std::make_shared<ScSamplingDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_DESCRIPTIVE_STATISTICS_DIALOG:
+ xResult = std::make_shared<ScDescriptiveStatisticsDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_ANALYSIS_OF_VARIANCE_DIALOG:
+ xResult = std::make_shared<ScAnalysisOfVarianceDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_COVARIANCE_DIALOG:
+ xResult = std::make_shared<ScCovarianceDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_EXPONENTIAL_SMOOTHING_DIALOG:
+ xResult = std::make_shared<ScExponentialSmoothingDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_MOVING_AVERAGE_DIALOG:
+ xResult = std::make_shared<ScMovingAverageDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_REGRESSION_DIALOG:
+ xResult = std::make_shared<ScRegressionDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_FTEST_DIALOG:
+ xResult = std::make_shared<ScFTestDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_TTEST_DIALOG:
+ xResult = std::make_shared<ScTTestDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_ZTEST_DIALOG:
+ xResult = std::make_shared<ScZTestDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_CHI_SQUARE_TEST_DIALOG:
+ xResult = std::make_shared<ScChiSquareTestDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_FOURIER_ANALYSIS_DIALOG:
+ xResult = std::make_shared<ScFourierAnalysisDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case WID_SIMPLE_REF:
+ {
+ // dialog checks, what is in the cell
+
+ ScViewData& rViewData = GetViewData();
+ rViewData.SetRefTabNo( rViewData.GetTabNo() );
+ xResult = std::make_shared<ScSimpleRefDlg>(pB, pCW, pParent);
+ break;
+ }
+ case FID_DEFINE_NAME:
+ {
+ if (!mbInSwitch)
+ {
+ xResult = std::make_shared<ScNameDlg>(pB, pCW, pParent, GetViewData(),
+ ScAddress( GetViewData().GetCurX(),
+ GetViewData().GetCurY(),
+ GetViewData().GetTabNo() ) );
+ }
+ else
+ {
+ xResult = std::make_shared<ScNameDlg>( pB, pCW, pParent, GetViewData(),
+ ScAddress( GetViewData().GetCurX(),
+ GetViewData().GetCurY(),
+ GetViewData().GetTabNo() ), &m_RangeMap);
+ static_cast<ScNameDlg*>(xResult.get())->SetEntry(maName, maScope);
+ mbInSwitch = false;
+ }
+ break;
+ }
+ case FID_ADD_NAME:
+ {
+ if (!mbInSwitch)
+ {
+ std::map<OUString, ScRangeName*> aRangeMap;
+ rDoc.GetRangeNameMap(aRangeMap);
+ xResult = std::make_shared<ScNameDefDlg>(pB, pCW, pParent, GetViewData(), std::move(aRangeMap),
+ ScAddress(GetViewData().GetCurX(),
+ GetViewData().GetCurY(),
+ GetViewData().GetTabNo()), true);
+ }
+ else
+ {
+ std::map<OUString, ScRangeName*> aRangeMap;
+ for (auto const& itr : m_RangeMap)
+ {
+ aRangeMap.insert(std::pair<OUString, ScRangeName*>(itr.first, itr.second.get()));
+ }
+ xResult = std::make_shared<ScNameDefDlg>(pB, pCW, pParent, GetViewData(), std::move(aRangeMap),
+ ScAddress(GetViewData().GetCurX(),
+ GetViewData().GetCurY(),
+ GetViewData().GetTabNo()), false);
+ }
+ break;
+ }
+ case SID_RANDOM_NUMBER_GENERATOR_DIALOG:
+ xResult = std::make_shared<ScRandomNumberGeneratorDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_SPARKLINE_DIALOG:
+ {
+ xResult = std::make_shared<sc::SparklineDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ }
+ case SID_SPARKLINE_DATA_RANGE_DIALOG:
+ {
+ xResult = std::make_shared<sc::SparklineDataRangeDialog>(pB, pCW, pParent, GetViewData());
+ break;
+ }
+ case SID_DEFINE_DBNAME:
+ {
+ // when called for an existing range, then mark
+ GetDBData( true, SC_DB_OLD );
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
+ MarkDataArea( false );
+
+ xResult = std::make_shared<ScDbNameDlg>(pB, pCW, pParent, GetViewData());
+ break;
+ }
+ case SID_OPENDLG_EDIT_PRINTAREA:
+ xResult = std::make_shared<ScPrintAreasDlg>(pB, pCW, pParent);
+ break;
+ case SID_DEFINE_COLROWNAMERANGES:
+ xResult = std::make_shared<ScColRowNameRangesDlg>(pB, pCW, pParent, GetViewData());
+ break;
+ case SID_OPENDLG_SOLVE:
+ {
+ ScViewData& rViewData = GetViewData();
+ ScAddress aCurPos( rViewData.GetCurX(),
+ rViewData.GetCurY(),
+ rViewData.GetTabNo());
+ xResult = std::make_shared<ScSolverDlg>(pB, pCW, pParent, &rViewData.GetDocument(), aCurPos);
+ break;
+ }
+ case SID_OPENDLG_TABOP:
+ {
+ ScViewData& rViewData = GetViewData();
+ ScRefAddress aCurPos ( rViewData.GetCurX(),
+ rViewData.GetCurY(),
+ rViewData.GetTabNo());
+
+ xResult = std::make_shared<ScTabOpDlg>(pB, pCW, pParent, &rViewData.GetDocument(), aCurPos);
+ break;
+ }
+ case SID_OPENDLG_CONSOLIDATE:
+ {
+ SfxItemSetFixed<SCITEM_CONSOLIDATEDATA,
+ SCITEM_CONSOLIDATEDATA> aArgSet( GetPool() );
+
+ const ScConsolidateParam* pDlgData =
+ rDoc.GetConsolidateDlgData();
+
+ if ( !pDlgData )
+ {
+ ScConsolidateParam aConsParam;
+ SCCOL nStartCol, nEndCol;
+ SCROW nStartRow, nEndRow;
+ SCTAB nStartTab, nEndTab;
+
+ GetViewData().GetSimpleArea( nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab );
+
+ PutInOrder( nStartCol, nEndCol );
+ PutInOrder( nStartRow, nEndRow );
+ PutInOrder( nStartTab, nEndTab );
+
+ aConsParam.nCol = nStartCol;
+ aConsParam.nRow = nStartRow;
+ aConsParam.nTab = nStartTab;
+
+ aArgSet.Put( ScConsolidateItem( SCITEM_CONSOLIDATEDATA,
+ &aConsParam ) );
+ }
+ else
+ {
+ aArgSet.Put( ScConsolidateItem( SCITEM_CONSOLIDATEDATA, pDlgData ) );
+ }
+ xResult = std::make_shared<ScConsolidateDlg>(pB, pCW, pParent, aArgSet);
+ break;
+ }
+ case SID_FILTER:
+ {
+
+ ScQueryParam aQueryParam;
+ SfxItemSetFixed<SCITEM_QUERYDATA, SCITEM_QUERYDATA> aArgSet( GetPool() );
+
+ ScDBData* pDBData = GetDBData(false, SC_DB_MAKE, ScGetDBSelection::RowDown);
+ pDBData->ExtendDataArea(rDoc);
+ pDBData->GetQueryParam( aQueryParam );
+
+ ScRange aArea;
+ pDBData->GetArea(aArea);
+ MarkRange(aArea, false);
+
+ aArgSet.Put( ScQueryItem( SCITEM_QUERYDATA,
+ &GetViewData(),
+ &aQueryParam ) );
+
+ // mark current sheet (due to RefInput in dialog)
+ GetViewData().SetRefTabNo( GetViewData().GetTabNo() );
+
+ xResult = std::make_shared<ScFilterDlg>(pB, pCW, pParent, aArgSet);
+ break;
+ }
+ case SID_SPECIAL_FILTER:
+ {
+ ScQueryParam aQueryParam;
+ SfxItemSetFixed<SCITEM_QUERYDATA,
+ SCITEM_QUERYDATA> aArgSet( GetPool() );
+
+ ScDBData* pDBData = GetDBData(false, SC_DB_MAKE, ScGetDBSelection::RowDown);
+ pDBData->ExtendDataArea(rDoc);
+ pDBData->GetQueryParam( aQueryParam );
+
+ ScRange aArea;
+ pDBData->GetArea(aArea);
+ MarkRange(aArea, false);
+
+ ScQueryItem aItem( SCITEM_QUERYDATA, &GetViewData(), &aQueryParam );
+ ScRange aAdvSource;
+ if (pDBData->GetAdvancedQuerySource(aAdvSource))
+ aItem.SetAdvancedQuerySource( &aAdvSource );
+
+ aArgSet.Put( aItem );
+
+ // mark current sheet (due to RefInput in dialog)
+ GetViewData().SetRefTabNo( GetViewData().GetTabNo() );
+
+ xResult = std::make_shared<ScSpecialFilterDlg>(pB, pCW, pParent, aArgSet);
+ break;
+ }
+ case SID_OPENDLG_OPTSOLVER:
+ {
+ ScViewData& rViewData = GetViewData();
+ ScAddress aCurPos( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo());
+ xResult = std::make_shared<ScOptSolverDlg>(pB, pCW, pParent, rViewData.GetDocShell(), aCurPos);
+ break;
+ }
+ case FID_CHG_SHOW:
+ {
+ // dialog checks, what is in the cell
+ xResult = std::make_shared<ScHighlightChgDlg>(pB, pCW, pParent, GetViewData());
+ break;
+ }
+ case SID_MANAGE_XML_SOURCE:
+ {
+ xResult = std::make_shared<ScXMLSourceDlg>(pB, pCW, pParent, &rDoc);
+ break;
+ }
+ case SID_OPENDLG_PIVOTTABLE:
+ {
+ // all settings must be in pDialogDPObject
+
+ if( pDialogDPObject )
+ {
+ // Check for an existing datapilot output.
+ ScViewData& rViewData = GetViewData();
+ rViewData.SetRefTabNo( rViewData.GetTabNo() );
+ ScDPObject* pObj = rDoc.GetDPAtCursor(rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo());
+ xResult = std::make_shared<ScPivotLayoutDialog>(pB, pCW, pParent, &rViewData, pDialogDPObject.get(), pObj == nullptr);
+ }
+
+ break;
+ }
+ case SID_OPENDLG_FUNCTION:
+ {
+ if (!isLOKMobilePhone())
+ {
+ // dialog checks, what is in the cell
+ xResult = o3tl::make_shared<ScFormulaDlg>(pB, pCW, pParent, GetViewData(), ScGlobal::GetStarCalcFunctionMgr());
+ }
+ break;
+ }
+ case WID_CONDFRMT_REF:
+ {
+ const ScCondFormatDlgItem* pDlgItem = nullptr;
+ // Get the pool item stored by Conditional Format Manager Dialog.
+ auto itemsRange = GetPool().GetItemSurrogates(SCITEM_CONDFORMATDLGDATA);
+ if (itemsRange.begin() != itemsRange.end())
+ {
+ const SfxPoolItem* pItem = *itemsRange.begin();
+ pDlgItem = static_cast<const ScCondFormatDlgItem*>(pItem);
+ }
+
+ if (pDlgItem)
+ {
+ ScViewData& rViewData = GetViewData();
+ rViewData.SetRefTabNo( rViewData.GetTabNo() );
+
+ xResult = std::make_shared<ScCondFormatDlg>(pB, pCW, pParent, &rViewData, pDlgItem);
+
+ // Remove the pool item stored by Conditional Format Manager Dialog.
+ GetPool().Remove(*pDlgItem);
+ }
+
+ break;
+ }
+ }
+
+ if (xResult)
+ xResult->Initialize( pInfo );
+ return xResult;
+}
+
+int ScTabViewShell::getPart() const
+{
+ return GetViewData().GetTabNo();
+}
+
+void ScTabViewShell::afterCallbackRegistered()
+{
+ UpdateInputHandler(true, false);
+
+ ScInputHandler* pHdl = mpInputHandler ? mpInputHandler.get() : SC_MOD()->GetInputHdl();
+ if (pHdl)
+ {
+ ScInputWindow* pInputWindow = pHdl->GetInputWindow();
+ if (pInputWindow)
+ {
+ pInputWindow->NotifyLOKClient();
+ }
+ }
+}
+
+void ScTabViewShell::NotifyCursor(SfxViewShell* pOtherShell) const
+{
+ ScDrawView* pDrView = const_cast<ScTabViewShell*>(this)->GetScDrawView();
+ if (pDrView)
+ {
+ if (pDrView->GetTextEditObject())
+ {
+ // Blinking cursor.
+ EditView& rEditView = pDrView->GetTextEditOutlinerView()->GetEditView();
+ rEditView.RegisterOtherShell(pOtherShell);
+ rEditView.ShowCursor();
+ rEditView.RegisterOtherShell(nullptr);
+ // Text selection, if any.
+ rEditView.DrawSelectionXOR(pOtherShell);
+ }
+ else
+ {
+ // Graphic selection.
+ pDrView->AdjustMarkHdl(pOtherShell);
+ }
+ }
+
+ const ScGridWindow* pWin = GetViewData().GetActiveWin();
+ if (pWin)
+ pWin->updateKitCellCursor(pOtherShell);
+}
+
+css::uno::Reference<css::datatransfer::XTransferable2> ScTabViewShell::GetClipData(vcl::Window* pWin)
+{
+ SfxViewFrame* pViewFrame = nullptr;
+ css::uno::Reference<css::datatransfer::XTransferable2> xTransferable;
+ css::uno::Reference<css::datatransfer::clipboard::XClipboard> xClipboard;
+
+ if (pWin)
+ xClipboard = pWin->GetClipboard();
+ else if ((pViewFrame = SfxViewFrame::GetFirst(nullptr, false)))
+ xClipboard = pViewFrame->GetWindow().GetClipboard();
+
+ xTransferable.set(xClipboard.is() ? xClipboard->getContents() : nullptr, css::uno::UNO_QUERY);
+
+ return xTransferable;
+}
+
+void ScTabViewShell::notifyAllViewsHeaderInvalidation(const SfxViewShell* pForViewShell, HeaderType eHeaderType, SCTAB nCurrentTabIndex)
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ OString aPayload;
+ switch (eHeaderType)
+ {
+ case COLUMN_HEADER:
+ aPayload = "column";
+ break;
+ case ROW_HEADER:
+ aPayload = "row";
+ break;
+ case BOTH_HEADERS:
+ default:
+ aPayload = "all";
+ break;
+ }
+
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pTabViewShell && pViewShell->GetDocId() == pForViewShell->GetDocId()
+ && (nCurrentTabIndex == -1 || pTabViewShell->getPart() == nCurrentTabIndex))
+ {
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_HEADER, aPayload.getStr());
+ }
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
+bool ScTabViewShell::isAnyEditViewInRange(const SfxViewShell* pForViewShell, bool bColumns, SCCOLROW nStart, SCCOLROW nEnd)
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pTabViewShell && pTabViewShell->GetDocId() == pForViewShell->GetDocId())
+ {
+ ScInputHandler* pInputHandler = pTabViewShell->GetInputHandler();
+ if (pInputHandler && pInputHandler->GetActiveView())
+ {
+ const ScViewData& rViewData = pTabViewShell->GetViewData();
+ SCCOLROW nPos = bColumns ? rViewData.GetCurX() : rViewData.GetCurY();
+ if (nStart <= nPos && nPos <= nEnd)
+ return true;
+ }
+ }
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+ }
+ return false;
+}
+
+void ScTabViewShell::notifyAllViewsSheetGeomInvalidation(const SfxViewShell* pForViewShell, bool bColumns,
+ bool bRows, bool bSizes, bool bHidden, bool bFiltered,
+ bool bGroups, SCTAB nCurrentTabIndex)
+{
+ if (!comphelper::LibreOfficeKit::isActive() ||
+ !comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs))
+ return;
+
+ if (!bColumns && !bRows)
+ return;
+
+ bool bAllTypes = bSizes && bHidden && bFiltered && bGroups;
+ bool bAllDims = bColumns && bRows;
+ OString aPayload = bAllDims ? "all" : bColumns ? "columns" : "rows";
+
+ if (!bAllTypes)
+ {
+ if (bSizes)
+ aPayload += " sizes";
+
+ if (bHidden)
+ aPayload += " hidden";
+
+ if (bFiltered)
+ aPayload += " filtered";
+
+ if (bGroups)
+ aPayload += " groups";
+ }
+
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pTabViewShell && pViewShell->GetDocId() == pForViewShell->GetDocId() &&
+ (nCurrentTabIndex == -1 || pTabViewShell->getPart() == nCurrentTabIndex))
+ {
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_INVALIDATE_SHEET_GEOMETRY, aPayload.getStr());
+ }
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
+bool ScTabViewShell::UseSubTotal(ScRangeList* pRangeList)
+{
+ bool bSubTotal = false;
+ ScDocument& rDoc = GetViewData().GetDocument();
+ size_t nRangeCount (pRangeList->size());
+ size_t nRangeIndex (0);
+ while (!bSubTotal && nRangeIndex < nRangeCount)
+ {
+ const ScRange& rRange = (*pRangeList)[nRangeIndex];
+ SCTAB nTabEnd(rRange.aEnd.Tab());
+ SCTAB nTab(rRange.aStart.Tab());
+ while (!bSubTotal && nTab <= nTabEnd)
+ {
+ SCROW nRowEnd(rRange.aEnd.Row());
+ SCROW nRow(rRange.aStart.Row());
+ while (!bSubTotal && nRow <= nRowEnd)
+ {
+ if (rDoc.RowFiltered(nRow, nTab))
+ bSubTotal = true;
+ else
+ ++nRow;
+ }
+ ++nTab;
+ }
+ ++nRangeIndex;
+ }
+
+ if (!bSubTotal)
+ {
+ const ScDBCollection::NamedDBs& rDBs = rDoc.GetDBCollection()->getNamedDBs();
+ for (const auto& rxDB : rDBs)
+ {
+ const ScDBData& rDB = *rxDB;
+ if (!rDB.HasAutoFilter())
+ continue;
+
+ nRangeIndex = 0;
+ while (!bSubTotal && nRangeIndex < nRangeCount)
+ {
+ const ScRange & rRange = (*pRangeList)[nRangeIndex];
+ ScRange aDBArea;
+ rDB.GetArea(aDBArea);
+ if (aDBArea.Intersects(rRange))
+ bSubTotal = true;
+ ++nRangeIndex;
+ }
+
+ if (bSubTotal)
+ break;
+ }
+ }
+ return bSubTotal;
+}
+
+OUString ScTabViewShell::DoAutoSum(bool& rRangeFinder, bool& rSubTotal, const OpCode eCode)
+{
+ OUString aFormula;
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ {
+ ScRangeList aMarkRangeList;
+ rRangeFinder = rSubTotal = false;
+ rMark.FillRangeListWithMarks( &aMarkRangeList, false );
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ // check if one of the marked ranges is empty
+ bool bEmpty = false;
+ const size_t nCount = aMarkRangeList.size();
+ for ( size_t i = 0; i < nCount; ++i )
+ {
+ const ScRange & rRange( aMarkRangeList[i] );
+ if ( rDoc.IsBlockEmpty( rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rRange.aStart.Tab() ) )
+ {
+ bEmpty = true;
+ break;
+ }
+ }
+
+ if ( bEmpty )
+ {
+ ScRangeList aRangeList;
+ const bool bDataFound = GetAutoSumArea( aRangeList );
+ if ( bDataFound )
+ {
+ ScAddress aAddr = aRangeList.back().aEnd;
+ aAddr.IncRow();
+ const bool bSubTotal( UseSubTotal( &aRangeList ) );
+ EnterAutoSum( aRangeList, bSubTotal, aAddr, eCode );
+ }
+ }
+ else
+ {
+ const bool bSubTotal( UseSubTotal( &aMarkRangeList ) );
+ for ( size_t i = 0; i < nCount; ++i )
+ {
+ const ScRange & rRange = aMarkRangeList[i];
+ const bool bSetCursor = ( i == nCount - 1 );
+ const bool bContinue = ( i != 0 );
+ if ( !AutoSum( rRange, bSubTotal, bSetCursor, bContinue, eCode ) )
+ {
+ MarkRange( rRange, false );
+ SetCursor( rRange.aEnd.Col(), rRange.aEnd.Row() );
+ const ScRangeList aRangeList;
+ ScAddress aAddr = rRange.aEnd;
+ aAddr.IncRow();
+ aFormula = GetAutoSumFormula( aRangeList, bSubTotal, aAddr , eCode);
+ break;
+ }
+ }
+ }
+ }
+ else // Only insert into input row
+ {
+ ScRangeList aRangeList;
+ rRangeFinder = GetAutoSumArea( aRangeList );
+ rSubTotal = UseSubTotal( &aRangeList );
+ ScAddress aAddr = GetViewData().GetCurPos();
+ aFormula = GetAutoSumFormula( aRangeList, rSubTotal, aAddr , eCode);
+ }
+ return aFormula;
+}
+
+void ScTabViewShell::InitFormEditData()
+{
+ mpFormEditData.reset(new ScFormEditData);
+}
+
+void ScTabViewShell::ClearFormEditData()
+{
+ mpFormEditData.reset();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwshd.cxx b/sc/source/ui/view/tabvwshd.cxx
new file mode 100644
index 000000000..86a3c0e62
--- /dev/null
+++ b/sc/source/ui/view/tabvwshd.cxx
@@ -0,0 +1,67 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sfx2/childwin.hxx>
+#include <sfx2/viewfrm.hxx>
+
+#include <tabvwsh.hxx>
+#include <scmod.hxx>
+#include <docsh.hxx>
+#include <gridwin.hxx>
+
+//! parent window for dialogs
+//! Problem: OLE Server!
+
+weld::Window* ScTabViewShell::GetDialogParent()
+{
+ // if a ref-input dialog is open, use it as parent
+ // (necessary when a slot is executed from the dialog's OK handler)
+ if (nCurRefDlgId && nCurRefDlgId == SC_MOD()->GetCurRefDlgId())
+ {
+ SfxViewFrame* pViewFrm = GetViewFrame();
+ if (pViewFrm->HasChildWindow(nCurRefDlgId))
+ {
+ SfxChildWindow* pChild = pViewFrm->GetChildWindow(nCurRefDlgId);
+ if (pChild)
+ {
+ auto xController = pChild->GetController();
+ weld::Window* pRet = xController ? xController->getDialog() : nullptr;
+ if (pRet && pRet->get_visible())
+ return pRet;
+ }
+ }
+ }
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ if (pDocSh->IsOle())
+ {
+ // TODO/LATER: how to GetEditWindow in embedded document?!
+ // It should be OK to return the ViewShell Window!
+ vcl::Window* pWin = GetWindow();
+ return pWin ? pWin->GetFrameWeld() : nullptr;
+ // SvInPlaceEnvironment* pEnv = pDocSh->GetIPEnv();
+ // if (pEnv)
+ // return pEnv->GetEditWin();
+ }
+
+ vcl::Window* pWin = GetActiveWin(); // for normal views, too
+ return pWin ? pWin->GetFrameWeld() : nullptr;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwshe.cxx b/sc/source/ui/view/tabvwshe.cxx
new file mode 100644
index 000000000..7089c17aa
--- /dev/null
+++ b/sc/source/ui/view/tabvwshe.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 <comphelper/string.hxx>
+#include <comphelper/lok.hxx>
+#include <editeng/eeitem.hxx>
+#include <osl/diagnose.h>
+
+#include <editeng/editview.hxx>
+#include <editeng/flditem.hxx>
+#include <svx/hlnkitem.hxx>
+#include <svl/srchitem.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/request.hxx>
+#include <svl/stritem.hxx>
+
+#include <tabvwsh.hxx>
+#include <sc.hrc>
+#include <scmod.hxx>
+#include <impex.hxx>
+#include <editsh.hxx>
+#include <dociter.hxx>
+#include <inputhdl.hxx>
+#include <document.hxx>
+
+OUString ScTabViewShell::GetSelectionText( bool bWholeWord, bool bOnlyASample )
+{
+ OUString aStrSelection;
+
+ if ( pEditShell && pEditShell.get() == GetMySubShell() )
+ {
+ aStrSelection = pEditShell->GetSelectionText( bWholeWord );
+ }
+ else
+ {
+ ScRange aRange;
+
+ if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ if ( (bOnlyASample || bInFormatDialog) && aRange.aStart.Row() != aRange.aEnd.Row() )
+ {
+ // limit range to one data row
+ // (only when the call comes from a format dialog)
+ ScHorizontalCellIterator aIter( rDoc, aRange.aStart.Tab(),
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row() );
+ SCCOL nCol;
+ SCROW nRow;
+ if ( aIter.GetNext( nCol, nRow ) )
+ {
+ aRange.aStart.SetCol( nCol );
+ aRange.aStart.SetRow( nRow );
+ aRange.aEnd.SetRow( nRow );
+ }
+ else
+ aRange.aEnd = aRange.aStart;
+ }
+ else
+ {
+ // #i111531# with 1M rows it was necessary to limit the range
+ // to the actually used data area.
+ SCCOL nCol1, nCol2;
+ SCROW nRow1, nRow2;
+ SCTAB nTab1, nTab2;
+ aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ bool bShrunk;
+ rDoc.ShrinkToUsedDataArea( bShrunk, nTab1, nCol1, nRow1, nCol2, nRow2, false);
+ if (bShrunk)
+ {
+ aRange.aStart.SetCol( nCol1 );
+ aRange.aStart.SetRow( nRow1 );
+ aRange.aEnd.SetCol( nCol2 );
+ aRange.aEnd.SetRow( nRow2 );
+ }
+ }
+
+ ScImportExport aObj( rDoc, aRange );
+ // tdf#148437 - if cell contains a formula, overwrite entire content of the cell
+ aObj.SetFormulas(true);
+ OUString aExportOUString;
+ /* TODO: STRING_TSVC under some circumstances? */
+ aObj.ExportString( aExportOUString, SotClipboardFormatId::STRING );
+ aStrSelection = convertLineEnd(aExportOUString, LINEEND_CR);
+
+ // replace Tab/CR with space, if for dialog or through Basic/SelectionTextExt,
+ // or when it is a single row.
+ // Otherwise keep Tabs in multi-row (for instance mail or Basic/SelectionText).
+ // for mail the Tabs are then later changed into (multiple) spaces.
+
+ if ( bInFormatDialog || bWholeWord || aRange.aEnd.Row() == aRange.aStart.Row() )
+ {
+ aStrSelection = aStrSelection.replaceAll("\r", " ");
+ aStrSelection = aStrSelection.replaceAll("\t", " ");
+ aStrSelection = comphelper::string::stripEnd(aStrSelection, ' ');
+ }
+ }
+ }
+
+ return aStrSelection;
+}
+
+bool ScTabViewShell::ShouldDisableEditHyperlink() const
+{
+ bool bRet = false;
+
+ if (pEditShell && pEditShell.get() == GetMySubShell())
+ {
+ bRet = pEditShell->ShouldDisableEditHyperlink();
+ }
+
+ return bRet;
+}
+
+void ScTabViewShell::EnableEditHyperlink()
+{
+ if (pEditShell && pEditShell.get() == GetMySubShell())
+ {
+ pEditShell->EnableEditHyperlink();
+ }
+}
+
+void ScTabViewShell::InsertURL( const OUString& rName, const OUString& rURL, const OUString& rTarget,
+ sal_uInt16 nMode )
+{
+ SvxLinkInsertMode eMode = static_cast<SvxLinkInsertMode>(nMode);
+ bool bAsText = ( eMode != HLINK_BUTTON ); // default is now text
+
+ if ( bAsText )
+ {
+ if ( GetViewData().IsActive() )
+ {
+ // if the view is active, always use InsertURLField, which starts EditMode
+ // and selects the URL, so it can be changed from the URL bar / dialog
+
+ InsertURLField( rName, rURL, rTarget );
+ }
+ else
+ {
+ // if the view is not active, InsertURLField doesn't work
+ // -> use InsertBookmark to directly manipulate cell content
+ // bTryReplace=sal_True -> if cell contains only one URL, replace it
+
+ SCCOL nPosX = GetViewData().GetCurX();
+ SCROW nPosY = GetViewData().GetCurY();
+ InsertBookmark( rName, rURL, nPosX, nPosY, &rTarget, true );
+ }
+ }
+ else
+ {
+ SC_MOD()->InputEnterHandler();
+ InsertURLButton( rName, rURL, rTarget, nullptr );
+ }
+}
+
+static void lcl_SelectFieldAfterInsert( EditView& rView )
+{
+ ESelection aSel = rView.GetSelection();
+ if ( aSel.nStartPos == aSel.nEndPos && aSel.nStartPos > 0 )
+ {
+ // Cursor is behind the inserted field -> extend selection to the left
+
+ --aSel.nStartPos;
+ rView.SetSelection( aSel );
+ }
+}
+
+void ScTabViewShell::InsertURLField( const OUString& rName, const OUString& rURL, const OUString& rTarget )
+{
+ SvxURLField aURLField( rURL, rName, SvxURLFormat::Repr );
+ aURLField.SetTargetFrame( rTarget );
+ SvxFieldItem aURLItem( aURLField, EE_FEATURE_FIELD );
+
+ ScViewData& rViewData = GetViewData();
+ ScModule* pScMod = SC_MOD();
+ ScInputHandler* pHdl = pScMod->GetInputHdl( rViewData.GetViewShell() );
+
+ bool bSelectFirst = false;
+ bool bIsEditMode = pScMod->IsEditMode();
+ int nSelInd = 1;
+ OUString sSeltext(GetSelectionText());
+
+ if ( !bIsEditMode )
+ {
+ if ( !SelectionEditable() )
+ {
+ // no error message (may be called from drag&drop)
+ return;
+ }
+
+ // single url in cell is shown in the dialog and replaced
+ bSelectFirst = HasBookmarkAtCursor( nullptr );
+ pScMod->SetInputMode( SC_INPUT_TABLE );
+ }
+
+ EditView* pTopView = pHdl->GetTopView();
+ EditView* pTableView = pHdl->GetTableView();
+ OSL_ENSURE( pTopView || pTableView, "No EditView" );
+
+ // Check if user selected a whole cell by single click, and cell has content.
+ // tdf#80043 - if true, replace the entire content of the selected cell instead of
+ // inserting a duplicate, or appending the url.
+ if (!bIsEditMode && !bSelectFirst && pTableView && !sSeltext.isEmpty())
+ {
+ nSelInd = sSeltext.getLength();
+ bSelectFirst = true;
+ }
+
+ if ( bSelectFirst )
+ {
+ if ( pTopView )
+ pTopView->SetSelection( ESelection(0,0,0,1) );
+ if ( pTableView )
+ pTableView->SetSelection( ESelection(0,0,0,nSelInd) );
+ }
+
+ pHdl->DataChanging();
+
+ if ( pTopView )
+ {
+ pTopView->InsertField( aURLItem );
+ lcl_SelectFieldAfterInsert( *pTopView );
+ }
+ if ( pTableView )
+ {
+ pTableView->InsertField( aURLItem );
+ lcl_SelectFieldAfterInsert( *pTableView );
+ }
+
+ pHdl->DataChanged();
+}
+
+void ScTabViewShell::ExecSearch( SfxRequest& rReq )
+{
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+ sal_uInt16 nSlot = rReq.GetSlot();
+ const SfxPoolItem* pItem;
+
+ switch ( nSlot )
+ {
+ case FID_SEARCH_NOW:
+ {
+ const SvxSearchItem* pSearchItem;
+ if ( pReqArgs &&
+ (pSearchItem = pReqArgs->GetItemIfSet(SID_SEARCH_ITEM, false)) )
+ {
+ ScGlobal::SetSearchItem( *pSearchItem );
+ SearchAndReplace( pSearchItem, true, rReq.IsAPI() );
+ rReq.Done();
+ }
+ }
+ break;
+
+ case SID_SEARCH_ITEM:
+ {
+ const SvxSearchItem* pSearchItem;
+ if (pReqArgs && (pSearchItem =
+ pReqArgs->GetItemIfSet(SID_SEARCH_ITEM, false)))
+ {
+ // remember search item
+ ScGlobal::SetSearchItem( *pSearchItem );
+ }
+ else
+ {
+ OSL_FAIL("SID_SEARCH_ITEM without Parameter");
+ }
+ break;
+ }
+ case FID_SEARCH:
+ case FID_REPLACE:
+ case FID_REPLACE_ALL:
+ case FID_SEARCH_ALL:
+ {
+ if (pReqArgs && SfxItemState::SET == pReqArgs->GetItemState(nSlot, false, &pItem))
+ {
+ // get search item
+
+ SvxSearchItem aSearchItem = ScGlobal::GetSearchItem();
+
+ // fill search item
+
+ aSearchItem.SetSearchString(static_cast<const SfxStringItem*>(pItem)->GetValue());
+ if(SfxItemState::SET == pReqArgs->GetItemState(FN_PARAM_1, false, &pItem))
+ aSearchItem.SetReplaceString(static_cast<const SfxStringItem*>(pItem)->GetValue());
+
+ if (nSlot == FID_SEARCH)
+ aSearchItem.SetCommand(SvxSearchCmd::FIND);
+ else if(nSlot == FID_REPLACE)
+ aSearchItem.SetCommand(SvxSearchCmd::REPLACE);
+ else if(nSlot == FID_REPLACE_ALL)
+ aSearchItem.SetCommand(SvxSearchCmd::REPLACE_ALL);
+ else
+ aSearchItem.SetCommand(SvxSearchCmd::FIND_ALL);
+
+ // execute request (which stores the SearchItem)
+
+ aSearchItem.SetWhich(SID_SEARCH_ITEM);
+ GetViewData().GetDispatcher().ExecuteList(FID_SEARCH_NOW,
+ rReq.IsAPI() ? SfxCallMode::API|SfxCallMode::SYNCHRON :
+ SfxCallMode::RECORD,
+ { &aSearchItem });
+ }
+ else
+ {
+ GetViewData().GetDispatcher().Execute(
+ SID_SEARCH_DLG, SfxCallMode::ASYNCHRON|SfxCallMode::RECORD );
+ }
+ }
+ break;
+ case FID_REPEAT_SEARCH:
+ {
+ // once more with ScGlobal::GetSearchItem()
+
+ SvxSearchItem aSearchItem = ScGlobal::GetSearchItem();
+ aSearchItem.SetWhich(SID_SEARCH_ITEM);
+ GetViewData().GetDispatcher().ExecuteList( FID_SEARCH_NOW,
+ rReq.IsAPI() ? SfxCallMode::API|SfxCallMode::SYNCHRON :
+ SfxCallMode::RECORD,
+ { &aSearchItem });
+ }
+ break;
+// case FID_SEARCH_COUNT:
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwshf.cxx b/sc/source/ui/view/tabvwshf.cxx
new file mode 100644
index 000000000..b3db07466
--- /dev/null
+++ b/sc/source/ui/view/tabvwshf.cxx
@@ -0,0 +1,1055 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <memory>
+
+#include <sfx2/request.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <basic/sbstar.hxx>
+#include <basic/sberrors.hxx>
+#include <svl/ctloptions.hxx>
+#include <svl/stritem.hxx>
+#include <svl/whiter.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <sfx2/objface.hxx>
+#include <svx/svxdlg.hxx>
+#include <editeng/colritem.hxx>
+
+#include <tabvwsh.hxx>
+#include <sc.hrc>
+#include <helpids.h>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <scresid.hxx>
+#include <globstr.hrc>
+#include <strings.hrc>
+#include <docfunc.hxx>
+#include <eventuno.hxx>
+#include <dpobject.hxx>
+#include <dpshttab.hxx>
+
+#include <scabstdlg.hxx>
+
+#include <tabbgcolor.hxx>
+#include <markdata.hxx>
+
+#include <vector>
+
+using std::unique_ptr;
+using namespace com::sun::star;
+
+void ScTabViewShell::ExecuteTable( SfxRequest& rReq )
+{
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+
+ SCTAB nCurrentTab = rViewData.GetTabNo();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ sal_uInt16 nSlot = rReq.GetSlot();
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ HideListBox(); // Autofilter-DropDown-Listbox
+
+ switch ( nSlot )
+ {
+ case FID_TABLE_VISIBLE:
+ {
+ OUString aName;
+ rDoc.GetName( nCurrentTab, aName );
+
+ bool bVisible=true;
+ if( pReqArgs != nullptr )
+ {
+ const SfxPoolItem* pItem;
+ if( pReqArgs->HasItem( FID_TABLE_VISIBLE, &pItem ) )
+ bVisible = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+ }
+
+ if( ! bVisible ) // fade out
+ {
+ if ( rDoc.IsDocEditable() )
+ {
+ ScMarkData& rMark = rViewData.GetMarkData();
+ HideTable( rMark );
+ }
+ }
+ else // fade in
+ {
+ std::vector<OUString> rNames { aName };
+ ShowTable( rNames );
+ }
+ }
+ break;
+
+ case FID_TABLE_HIDE:
+ {
+ if ( rDoc.IsDocEditable() )
+ {
+ ScMarkData& rMark = rViewData.GetMarkData();
+ SCTAB nActiveTab = -1;
+ // For the cases when user right clicks on a non-active tab and hides it. This case is possible for Online.
+ if (pReqArgs)
+ {
+ const SfxPoolItem *pItem;
+ if( pReqArgs->HasItem( FID_TABLE_HIDE, &pItem ) )
+ {
+ SCTAB nTabNumber = static_cast<const SfxInt16Item*>(pItem)->GetValue();
+ // Does selected sheets (tabs) list include the sheet to be hidden?
+ std::set<SCTAB>::iterator it = rMark.GetSelectedTabs().find(nTabNumber);
+ if (it == rMark.GetSelectedTabs().end())
+ {
+ // No it doesn't, so we won't shift the selected tab. Let's remember its position.
+ nActiveTab = GetViewData().GetTabNo();
+ }
+ rMark.SelectOneTable(nTabNumber);
+ }
+ }
+ HideTable( rMark, nActiveTab );
+ }
+ }
+ break;
+
+ case FID_TABLE_SHOW:
+ {
+ std::vector<OUString> rNames;
+ if ( pReqArgs )
+ {
+ const SfxPoolItem* pItem;
+ if( pReqArgs->HasItem( FID_TABLE_SHOW, &pItem ) )
+ {
+ OUString aName = static_cast<const SfxStringItem*>(pItem)->GetValue();
+ rNames.push_back(aName);
+ ShowTable( rNames );
+
+ if( ! rReq.IsAPI() )
+ rReq.Done();
+ }
+ }
+ else
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ VclPtr<AbstractScShowTabDlg> pDlg(pFact->CreateScShowTabDlg(GetFrameWeld()));
+
+ OUString aTabName;
+ bool bFirst = true;
+ for ( SCTAB i=0; i != nTabCount; i++ )
+ {
+ if (!rDoc.IsVisible(i))
+ {
+ rDoc.GetName( i, aTabName );
+ pDlg->Insert( aTabName, bFirst );
+ bFirst = false;
+ }
+ }
+
+ std::shared_ptr<SfxRequest> pReq = std::make_shared<SfxRequest>(rReq);
+ pDlg->StartExecuteAsync([this, pDlg, pReq](sal_Int32 nResult){
+ std::vector<OUString> sTables;
+ if (RET_OK == nResult)
+ {
+ std::vector<sal_Int32> aSelectedRows = pDlg->GetSelectedRows();
+ for (auto a : aSelectedRows)
+ {
+ OUString sTable = pDlg->GetEntry(a);
+ pReq->AppendItem( SfxStringItem( FID_TABLE_SHOW, sTable ) );
+ sTables.push_back(sTable);
+ }
+ ShowTable( sTables );
+ pReq->Done();
+ }
+ pDlg->disposeOnce();
+ });
+ rReq.Ignore();
+ }
+ }
+ break;
+
+ case FID_INS_TABLE:
+ case FID_INS_TABLE_EXT:
+ {
+ ScMarkData& rMark = rViewData.GetMarkData();
+ SCTAB nTabSelCount = rMark.GetSelectCount();
+ SCTAB nTabNr = nCurrentTab;
+
+ if ( !rDoc.IsDocEditable() )
+ break; // locked
+
+ if ( pReqArgs != nullptr ) // from basic
+ {
+ bool bOk = false;
+ const SfxPoolItem* pTabItem;
+ const SfxPoolItem* pNameItem;
+
+ if ( pReqArgs->HasItem( FN_PARAM_1, &pTabItem ) &&
+ pReqArgs->HasItem( nSlot, &pNameItem ) )
+ {
+ OUString aName = static_cast<const SfxStringItem*>(pNameItem)->GetValue();
+ rDoc.CreateValidTabName(aName);
+
+ // sheet number from basic: 1-based
+ // 0 is special, means adding at the end
+ nTabNr = static_cast<const SfxUInt16Item*>(pTabItem)->GetValue();
+ if (nTabNr == 0)
+ nTabNr = nTabCount;
+ else
+ --nTabNr;
+
+ if (nTabNr > nTabCount)
+ nTabNr = nTabCount;
+
+ bOk = InsertTable(aName, nTabNr);
+ }
+
+ if (bOk)
+ rReq.Done( *pReqArgs );
+ //! else set error
+ }
+ else // dialog
+ {
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScInsertTableDlg> pDlg(pFact->CreateScInsertTableDlg(GetFrameWeld(), rViewData,
+ nTabSelCount, nSlot == FID_INS_TABLE_EXT));
+ if ( RET_OK == pDlg->Execute() )
+ {
+ if (pDlg->GetTablesFromFile())
+ {
+ std::vector<SCTAB> nTabs;
+ sal_uInt16 n = 0;
+ const OUString* pStr = pDlg->GetFirstTable( &n );
+ while ( pStr )
+ {
+ nTabs.push_back( static_cast<SCTAB>(n) );
+ pStr = pDlg->GetNextTable( &n );
+ }
+ bool bLink = pDlg->GetTablesAsLink();
+ if (!nTabs.empty())
+ {
+ if(pDlg->IsTableBefore())
+ {
+ ImportTables( pDlg->GetDocShellTables(), nTabs.size(), nTabs.data(),
+ bLink,nTabNr );
+ }
+ else
+ {
+ SCTAB nTabAfter = nTabNr+1;
+
+ for(SCTAB j=nCurrentTab+1;j<nTabCount;j++)
+ {
+ if(!rDoc.IsScenario(j))
+ {
+ nTabAfter=j;
+ break;
+ }
+ }
+
+ ImportTables( pDlg->GetDocShellTables(), nTabs.size(), nTabs.data(),
+ bLink,nTabAfter );
+ }
+ }
+ }
+ else
+ {
+ SCTAB nCount=pDlg->GetTableCount();
+ if(pDlg->IsTableBefore())
+ {
+ if(nCount==1 && !pDlg->GetFirstTable()->isEmpty())
+ {
+ rReq.AppendItem( SfxStringItem( FID_INS_TABLE, *pDlg->GetFirstTable() ) );
+ rReq.AppendItem( SfxUInt16Item( FN_PARAM_1, static_cast<sal_uInt16>(nTabNr) + 1 ) ); // 1-based
+ rReq.Done();
+
+ InsertTable( *pDlg->GetFirstTable(), nTabNr );
+ }
+ else
+ {
+ std::vector<OUString> aNames(0);
+ InsertTables( aNames, nTabNr,nCount );
+ }
+ }
+ else
+ {
+ SCTAB nTabAfter = nTabNr+1;
+ SCTAB nSelHigh = rMark.GetLastSelected();
+
+ for(SCTAB j=nSelHigh+1;j<nTabCount;j++)
+ {
+ if(!rDoc.IsScenario(j))
+ {
+ nTabAfter=j;
+ break;
+ }
+ else // #101672#; increase nTabAfter, because it is possible that the scenario tables are the last
+ nTabAfter = j + 1;
+ }
+
+ if(nCount==1 && !pDlg->GetFirstTable()->isEmpty())
+ {
+ rReq.AppendItem( SfxStringItem( FID_INS_TABLE, *pDlg->GetFirstTable() ) );
+ rReq.AppendItem( SfxUInt16Item( FN_PARAM_1, static_cast<sal_uInt16>(nTabAfter) + 1 ) ); // 1-based
+ rReq.Done();
+
+ InsertTable( *pDlg->GetFirstTable(), nTabAfter);
+ }
+ else
+ {
+ std::vector<OUString> aNames(0);
+ InsertTables( aNames, nTabAfter,nCount);
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case FID_TAB_APPEND:
+ case FID_TAB_RENAME:
+ case FID_TAB_MENU_RENAME:
+ {
+ // FID_TAB_MENU_RENAME - "rename" in menu
+ // FID_TAB_RENAME - "name"-property for basic
+ // equal execute, but MENU_RENAME may be disabled inside GetState
+
+ if ( nSlot == FID_TAB_MENU_RENAME )
+ nSlot = FID_TAB_RENAME; // equal execute
+
+ SCTAB nTabNr = rViewData.GetTabNo();
+ ScMarkData& rMark = rViewData.GetMarkData();
+ SCTAB nTabSelCount = rMark.GetSelectCount();
+
+ if ( !rDoc.IsDocEditable() )
+ break; // everything locked
+
+ if ( nSlot != FID_TAB_APPEND &&
+ ( rDoc.IsTabProtected( nTabNr ) || nTabSelCount > 1 ) )
+ break; // no rename
+
+ if( pReqArgs != nullptr )
+ {
+ bool bDone = false;
+ const SfxPoolItem* pItem;
+ OUString aName;
+
+ if( pReqArgs->HasItem( FN_PARAM_1, &pItem ) )
+ {
+ nTabNr = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
+
+ // inserting is 1-based, let's be consistent
+ if (nTabNr > 0)
+ --nTabNr;
+ }
+
+ if( pReqArgs->HasItem( nSlot, &pItem ) )
+ aName = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ switch ( nSlot )
+ {
+ case FID_TAB_APPEND:
+ bDone = AppendTable( aName );
+ break;
+ case FID_TAB_RENAME:
+ bDone = RenameTable( aName, nTabNr );
+ break;
+ }
+
+ if( bDone )
+ {
+ rReq.Done( *pReqArgs );
+ }
+ }
+ else
+ {
+ sal_uInt16 nRet = RET_OK;
+ bool bDone = false;
+ OUString aErrMsg ( ScResId( STR_INVALIDTABNAME ) );
+ OUString aName;
+ OUString aDlgTitle;
+ OString sHelpId;
+
+ switch ( nSlot )
+ {
+ case FID_TAB_APPEND:
+ aDlgTitle = ScResId(SCSTR_APDTABLE);
+ rDoc.CreateValidTabName( aName );
+ sHelpId = HID_SC_APPEND_NAME;
+ break;
+
+ case FID_TAB_RENAME:
+ aDlgTitle = ScResId(SCSTR_RENAMETAB);
+ rDoc.GetName( rViewData.GetTabNo(), aName );
+ sHelpId = HID_SC_RENAME_NAME;
+ break;
+ }
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScStringInputDlg> pDlg(pFact->CreateScStringInputDlg(
+ GetFrameWeld(), aDlgTitle, ScResId(SCSTR_NAME),
+ aName, GetStaticInterface()->GetSlot(nSlot)->GetCommand(),
+ sHelpId));
+
+
+ while ( !bDone && nRet == RET_OK )
+ {
+ nRet = pDlg->Execute();
+
+ if ( nRet == RET_OK )
+ {
+ aName = pDlg->GetInputString();
+
+ switch ( nSlot )
+ {
+ case FID_TAB_APPEND:
+ bDone = AppendTable( aName );
+ break;
+ case FID_TAB_RENAME:
+ bDone = RenameTable( aName, nTabNr );
+ break;
+ }
+
+ if ( bDone )
+ {
+ rReq.AppendItem( SfxStringItem( nSlot, aName ) );
+ rReq.Done();
+ }
+ else
+ {
+ if( rReq.IsAPI() )
+ {
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::Error( ERRCODE_BASIC_SETPROP_FAILED ); // XXX error handling???
+#endif
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Warning, VclButtonsType::Ok, aErrMsg));
+ nRet = xBox->run();
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case FID_TAB_MOVE:
+ {
+ if ( rDoc.GetChangeTrack() != nullptr )
+ break; // if ChangeTracking is active, then no TabMove
+
+ bool bDoIt = false;
+ sal_uInt16 nDoc = 0;
+ SCTAB nTab = rViewData.GetTabNo();
+ bool bCpy = false, bUseCurrentDocument = false;
+ OUString aDocName;
+ OUString aTabName;
+
+ if( pReqArgs != nullptr )
+ {
+ SCTAB nTableCount = rDoc.GetTableCount();
+ const SfxPoolItem* pItem;
+
+ // if UseCurrentDocument(FN_PARAM_3) is true ignore the document name provided and use current document
+ if( pReqArgs->HasItem( FN_PARAM_3, &pItem ) )
+ bUseCurrentDocument = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ if (bUseCurrentDocument)
+ aDocName = GetViewData().GetDocShell()->GetTitle();
+ else if(pReqArgs->HasItem( FID_TAB_MOVE, &pItem ))
+ aDocName = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ if( pReqArgs->HasItem( FN_PARAM_1, &pItem ) )
+ {
+ // table is 1-based
+ nTab = static_cast<const SfxUInt16Item*>(pItem)->GetValue() - 1;
+ if ( nTab >= nTableCount )
+ nTab = SC_TAB_APPEND;
+ }
+ if( pReqArgs->HasItem( FN_PARAM_2, &pItem ) )
+ bCpy = static_cast<const SfxBoolItem*>(pItem)->GetValue();
+
+ if (!aDocName.isEmpty())
+ {
+ SfxObjectShell* pSh = SfxObjectShell::GetFirst();
+ ScDocShell* pScSh = nullptr;
+ sal_uInt16 i=0;
+
+ while ( pSh )
+ {
+ pScSh = dynamic_cast<ScDocShell*>( pSh );
+
+ if( pScSh )
+ {
+ pScSh->GetTitle();
+
+ if (aDocName == pScSh->GetTitle())
+ {
+ nDoc = i;
+ ScDocument& rDestDoc = pScSh->GetDocument();
+ nTableCount = rDestDoc.GetTableCount();
+ bDoIt = rDestDoc.IsDocEditable();
+ break;
+ }
+
+ i++; // only count ScDocShell
+ }
+ pSh = SfxObjectShell::GetNext( *pSh );
+ }
+ }
+ else // no doc-name -> new doc
+ {
+ nDoc = SC_DOC_NEW;
+ bDoIt = true;
+ }
+
+ if ( bDoIt && nTab >= nTableCount ) // if necessary append
+ nTab = SC_TAB_APPEND;
+ }
+ else
+ {
+ OUString aDefaultName;
+ rDoc.GetName( rViewData.GetTabNo(), aDefaultName );
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+
+ ScopedVclPtr<AbstractScMoveTableDlg> pDlg(pFact->CreateScMoveTableDlg(GetFrameWeld(),
+ aDefaultName));
+
+ SCTAB nTableCount = rDoc.GetTableCount();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ SCTAB nTabSelCount = rMark.GetSelectCount();
+
+ if(nTableCount==nTabSelCount)
+ {
+ pDlg->SetForceCopyTable();
+ }
+
+ // We support direct renaming of sheet only when one sheet
+ // is selected.
+ pDlg->EnableRenameTable(nTabSelCount == 1);
+
+ if ( pDlg->Execute() == RET_OK )
+ {
+ nDoc = pDlg->GetSelectedDocument();
+ nTab = pDlg->GetSelectedTable();
+ bCpy = pDlg->GetCopyTable();
+ bool bRna = pDlg->GetRenameTable();
+ // Leave aTabName string empty, when Rename is FALSE.
+ if( bRna )
+ {
+ pDlg->GetTabNameString( aTabName );
+ }
+ bDoIt = true;
+
+ OUString aFoundDocName;
+ if ( nDoc != SC_DOC_NEW )
+ {
+ ScDocShell* pSh = ScDocShell::GetShellByNum( nDoc );
+ if (pSh)
+ {
+ aFoundDocName = pSh->GetTitle();
+ if ( !pSh->GetDocument().IsDocEditable() )
+ {
+ ErrorMessage(STR_READONLYERR);
+ bDoIt = false;
+ }
+ }
+ }
+ rReq.AppendItem( SfxStringItem( FID_TAB_MOVE, aFoundDocName ) );
+ // 1-based table, if not APPEND
+ SCTAB nBasicTab = ( nTab <= MAXTAB ) ? (nTab+1) : nTab;
+ rReq.AppendItem( SfxUInt16Item( FN_PARAM_1, static_cast<sal_uInt16>(nBasicTab) ) );
+ rReq.AppendItem( SfxBoolItem( FN_PARAM_2, bCpy ) );
+ }
+ }
+
+ if( bDoIt )
+ {
+ rReq.Done(); // record, while doc is active
+
+ MoveTable( nDoc, nTab, bCpy, &aTabName );
+ }
+ }
+ break;
+
+ case FID_TAB_DUPLICATE:
+ {
+ // Get info about current document and selected tab
+ SCTAB nTab = rViewData.GetTabNo();
+ OUString aDocName = GetViewData().GetDocShell()->GetTitle();
+ sal_uInt16 nDoc = 0;
+ bool bCpy = true;
+
+ SfxObjectShell* pSh = SfxObjectShell::GetFirst();
+ ScDocShell* pScSh = nullptr;
+ sal_uInt16 i = 0;
+
+ // Determine the index of the current document
+ while ( pSh )
+ {
+ pScSh = dynamic_cast<ScDocShell*>( pSh );
+
+ if( pScSh )
+ {
+ pScSh->GetTitle();
+
+ if (aDocName == pScSh->GetTitle())
+ {
+ nDoc = i;
+ break;
+ }
+ // Only count ScDocShell
+ i++;
+ }
+ pSh = SfxObjectShell::GetNext( *pSh );
+ }
+
+ MoveTable( nDoc, nTab + 1, bCpy );
+ }
+ break;
+
+ case FID_DELETE_TABLE:
+ {
+ bool bHasIndex = (pReqArgs != nullptr);
+
+ // allow removing via the Index/FID_DELETE_TABLE parameter
+ SCTAB nTabNr = nCurrentTab;
+ if (bHasIndex)
+ {
+ const SfxPoolItem* pItem;
+ if (pReqArgs->HasItem(FID_DELETE_TABLE, &pItem))
+ {
+ nTabNr = static_cast<const SfxUInt16Item*>(pItem)->GetValue();
+
+ // inserting is 1-based, let's be consistent
+ if (nTabNr > 0)
+ --nTabNr;
+ }
+ }
+
+ bool bDoIt = bHasIndex;
+ if (!bDoIt)
+ {
+ bool bTabWithPivotTable = false;
+ if (rDoc.HasPivotTable())
+ {
+ const ScDPCollection* pDPs = rDoc.GetDPCollection();
+ if (pDPs)
+ {
+ const ScMarkData::MarkedTabsType& rSelectedTabs = rViewData.GetMarkData().GetSelectedTabs();
+ for (const SCTAB nSelTab : rSelectedTabs)
+ {
+ const size_t nCount = pDPs->GetCount();
+ for (size_t i = 0; i < nCount; ++i)
+ {
+ const ScDPObject& rDPObj = (*pDPs)[i];
+ const ScSheetSourceDesc* pSheetSourceDesc = rDPObj.GetSheetDesc();
+ if (pSheetSourceDesc && pSheetSourceDesc->GetSourceRange().aStart.Tab() == nSelTab)
+ bTabWithPivotTable = true;
+ }
+ if (bTabWithPivotTable)
+ break;
+ }
+ }
+ }
+
+ if (bTabWithPivotTable)
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_QUERY_PIVOTTABLE_DELTAB)));
+ xQueryBox->set_default_response(RET_NO);
+
+ // Hard warning as there is potential of data loss on deletion
+ bDoIt = (RET_YES == xQueryBox->run());
+ }
+ else
+ {
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetFrameWeld(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ ScResId(STR_QUERY_DELTAB)));
+ xQueryBox->set_default_response(RET_YES);
+
+ // no parameter given, ask for confirmation
+ bDoIt = (RET_YES == xQueryBox->run());
+ }
+ }
+
+ if (bDoIt)
+ {
+ SCTAB nNewTab = nCurrentTab;
+ std::vector<SCTAB> TheTabs;
+
+ if (bHasIndex)
+ {
+ // sheet no. provided by the parameter
+ TheTabs.push_back(nTabNr);
+ if (nNewTab > nTabNr && nNewTab > 0)
+ --nNewTab;
+ }
+ else
+ {
+ SCTAB nFirstTab = 0;
+ bool bTabFlag = false;
+ ScMarkData& rMark = rViewData.GetMarkData();
+ for (SCTAB i = 0; i < nTabCount; i++)
+ {
+ if (rMark.GetTableSelect(i) && !rDoc.IsTabProtected(i))
+ {
+ TheTabs.push_back(i);
+ bTabFlag = true;
+ if (nNewTab == i && i+1 < nTabCount)
+ nNewTab++;
+ }
+ if (!bTabFlag)
+ nFirstTab = i;
+ }
+ if (nNewTab >= nTabCount - static_cast<SCTAB>(TheTabs.size()))
+ nNewTab = nFirstTab;
+ }
+
+ rViewData.SetTabNo(nNewTab);
+ DeleteTables(TheTabs);
+ TheTabs.clear();
+ rReq.Done();
+ }
+ }
+ break;
+
+ case FID_TAB_RTL:
+ {
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+ bool bSet = !rDoc.IsLayoutRTL( nCurrentTab );
+
+ const ScMarkData& rMark = rViewData.GetMarkData();
+ if ( rMark.GetSelectCount() != 0 )
+ {
+ // handle several sheets
+
+ SfxUndoManager* pUndoManager = pDocSh->GetUndoManager();
+ OUString aUndo = ScResId( STR_UNDO_TAB_RTL );
+ pUndoManager->EnterListAction( aUndo, aUndo, 0, rViewData.GetViewShell()->GetViewShellId() );
+
+ for (const auto& rTab : rMark)
+ rFunc.SetLayoutRTL( rTab, bSet );
+
+ pUndoManager->LeaveListAction();
+ }
+ else
+ rFunc.SetLayoutRTL( nCurrentTab, bSet );
+ }
+ break;
+
+ case FID_TAB_TOGGLE_GRID:
+ {
+ bool bShowGrid = rViewData.GetShowGrid();
+ rViewData.SetShowGrid(!bShowGrid);
+ SfxBindings& rBindings = GetViewFrame()->GetBindings();
+ rBindings.Invalidate( FID_TAB_TOGGLE_GRID );
+ ScDocShellModificator aModificator(*rViewData.GetDocShell());
+ aModificator.SetDocumentModified();
+ PaintGrid();
+ rReq.Done();
+ }
+ break;
+
+ case FID_TAB_SET_TAB_BG_COLOR:
+ case FID_TAB_MENU_SET_TAB_BG_COLOR:
+ {
+ if ( nSlot == FID_TAB_MENU_SET_TAB_BG_COLOR )
+ nSlot = FID_TAB_SET_TAB_BG_COLOR;
+ SCTAB nTabNr = rViewData.GetTabNo();
+ ScMarkData& rMark = rViewData.GetMarkData();
+ SCTAB nTabSelCount = rMark.GetSelectCount();
+ if ( !rDoc.IsDocEditable() )
+ break;
+
+ if ( rDoc.IsTabProtected( nTabNr ) ) // ||nTabSelCount > 1
+ break;
+
+ if( pReqArgs != nullptr )
+ {
+ bool bDone = false;
+ const SfxPoolItem* pItem;
+ Color aColor;
+
+ if( pReqArgs->HasItem( nSlot, &pItem ) )
+ aColor = static_cast<const SvxColorItem*>(pItem)->GetValue();
+
+ if ( nTabSelCount > 1 )
+ {
+ std::unique_ptr<ScUndoTabColorInfo::List>
+ pTabColorList(new ScUndoTabColorInfo::List);
+ for (const auto& rTab : rMark)
+ {
+ if ( !rDoc.IsTabProtected(rTab) )
+ {
+ ScUndoTabColorInfo aTabColorInfo(rTab);
+ aTabColorInfo.maNewTabBgColor = aColor;
+ pTabColorList->push_back(aTabColorInfo);
+ }
+ }
+ bDone = SetTabBgColor( *pTabColorList );
+ }
+ else
+ {
+ bDone = SetTabBgColor( aColor, nCurrentTab ); //ScViewFunc.SetTabBgColor
+ }
+ if( bDone )
+ {
+ rReq.Done( *pReqArgs );
+ }
+ }
+ else
+ {
+ sal_uInt16 nRet = RET_OK; /// temp
+ bool bDone = false; /// temp
+
+ Color aTabBgColor = rDoc.GetTabBgColor( nCurrentTab );
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ ScopedVclPtr<AbstractScTabBgColorDlg> pDlg(pFact->CreateScTabBgColorDlg(
+ GetFrameWeld(),
+ ScResId(SCSTR_SET_TAB_BG_COLOR),
+ ScResId(SCSTR_NO_TAB_BG_COLOR),
+ aTabBgColor));
+ while ( !bDone && nRet == RET_OK )
+ {
+ nRet = pDlg->Execute();
+ if( nRet == RET_OK )
+ {
+ Color aSelectedColor;
+ pDlg->GetSelectedColor(aSelectedColor);
+ std::unique_ptr<ScUndoTabColorInfo::List>
+ pTabColorList(new ScUndoTabColorInfo::List);
+ if ( nTabSelCount > 1 )
+ {
+ for (const auto& rTab : rMark)
+ {
+ if ( !rDoc.IsTabProtected(rTab) )
+ {
+ ScUndoTabColorInfo aTabColorInfo(rTab);
+ aTabColorInfo.maNewTabBgColor = aSelectedColor;
+ pTabColorList->push_back(aTabColorInfo);
+ }
+ }
+ bDone = SetTabBgColor( *pTabColorList );
+ }
+ else
+ {
+ bDone = SetTabBgColor( aSelectedColor, nCurrentTab ); //ScViewFunc.SetTabBgColor
+ }
+
+ if ( bDone )
+ {
+ rReq.AppendItem( SvxColorItem( aTabBgColor, nSlot ) );
+ rReq.Done();
+ }
+ else
+ {
+ if( rReq.IsAPI() )
+ {
+#if HAVE_FEATURE_SCRIPTING
+ StarBASIC::Error( ERRCODE_BASIC_SETPROP_FAILED );
+#endif
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case FID_TAB_EVENTS:
+ {
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ uno::Reference<container::XNameReplace> xEvents( new ScSheetEventsObj( pDocSh, nCurrentTab ) );
+ uno::Reference<frame::XFrame> xFrame = GetViewFrame()->GetFrame().GetFrameInterface();
+ SvxAbstractDialogFactory* pDlgFactory = SvxAbstractDialogFactory::Create();
+ ScopedVclPtr<VclAbstractDialog> pDialog( pDlgFactory->CreateSvxMacroAssignDlg(
+ GetFrameWeld(), xFrame, false, xEvents, 0 ) );
+ if ( pDialog->Execute() == RET_OK )
+ {
+ // the dialog modifies the settings directly
+ }
+ }
+ break;
+ case FID_TOGGLEHIDDENCOLROW:
+ {
+ svtools::EditableColorConfig aEditableConfig;
+ svtools::ColorConfigValue aValue = aEditableConfig.GetColorValue(svtools::CALCHIDDENROWCOL);
+ aValue.bIsVisible = !aValue.bIsVisible;
+ aEditableConfig.SetColorValue(svtools::CALCHIDDENROWCOL, aValue);
+ }
+ break;
+ default:
+ OSL_FAIL("unknown message for ViewShell");
+ break;
+ }
+}
+
+void ScTabViewShell::GetStateTable( SfxItemSet& rSet )
+{
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScDocShell* pDocShell = rViewData.GetDocShell();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ SCTAB nTab = rViewData.GetTabNo();
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCTAB nTabSelCount = rMark.GetSelectCount();
+
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+
+ while ( nWhich )
+ {
+ switch ( nWhich )
+ {
+
+ case FID_TABLE_VISIBLE:
+ rSet.Put( SfxBoolItem( nWhich, rDoc.IsVisible(nTab) ));
+ break;
+
+ case FID_TABLE_HIDE:
+ {
+ sal_uInt16 nVis = 0;
+ // enable menu : check to make sure we won't hide all sheets. we need at least one visible at all times.
+ for ( SCTAB i=0; i < nTabCount && nVis<nTabSelCount + 1; i++ )
+ if (rDoc.IsVisible(i))
+ ++nVis;
+ if ( nVis<=nTabSelCount || !rDoc.IsDocEditable() )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case FID_TABLE_SHOW:
+ {
+ bool bHasHidden = false;
+ for ( SCTAB i=0; i < nTabCount && !bHasHidden; i++ )
+ if (!rDoc.IsVisible(i))
+ bHasHidden = true;
+ if ( !bHasHidden || rDoc.IsDocProtected() || nTabSelCount > 1 )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case FID_DELETE_TABLE:
+ {
+ if ( rDoc.GetChangeTrack() )
+ rSet.DisableItem( nWhich );
+ else
+ {
+ sal_uInt16 nVis = 0;
+ for ( SCTAB i=0; i < nTabCount && nVis<2; i++ )
+ if (rDoc.IsVisible(i))
+ ++nVis;
+ if ( rDoc.IsTabProtected(nTab)
+ || !rDoc.IsDocEditable()
+ || nVis < 2
+ || nTabSelCount == nTabCount)
+ rSet.DisableItem( nWhich );
+ }
+ }
+ break;
+
+ case FID_INS_TABLE:
+ case FID_INS_TABLE_EXT:
+ case FID_TAB_APPEND:
+ if ( !rDoc.IsDocEditable() ||
+ nTabCount > MAXTAB ||
+ ( nWhich == FID_INS_TABLE_EXT && pDocShell && pDocShell->IsDocShared() ) )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_TAB_MOVE:
+ if ( !rDoc.IsDocEditable()
+ || rDoc.GetChangeTrack() != nullptr
+ || nTabCount > MAXTAB)
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_TAB_DUPLICATE:
+ if ( !rDoc.IsDocEditable()
+ || rDoc.GetChangeTrack() != nullptr
+ || nTabCount > MAXTAB)
+ rSet.DisableItem( nWhich );
+ break;
+
+ // FID_TAB_MENU_RENAME - "rename" from Menu
+ // FID_TAB_RENAME - "name"-property for Basic
+
+ case FID_TAB_MENU_RENAME:
+ if ( !rDoc.IsDocEditable() ||
+ rDoc.IsTabProtected(nTab) ||nTabSelCount > 1 ||
+ ( pDocShell && pDocShell->IsDocShared() ) )
+ rSet.DisableItem( nWhich );
+ break;
+
+ case FID_TAB_RENAME:
+ {
+ OUString aTabName;
+ rDoc.GetName( nTab, aTabName );
+
+ rSet.Put( SfxStringItem( nWhich, aTabName ));
+
+ }
+ break;
+
+ case FID_TAB_RTL:
+ {
+ if ( !SvtCTLOptions().IsCTLFontEnabled() )
+ rSet.DisableItem( nWhich );
+ else
+ rSet.Put( SfxBoolItem( nWhich, rDoc.IsLayoutRTL( nTab ) ) );
+ }
+ break;
+
+ case FID_TAB_MENU_SET_TAB_BG_COLOR:
+ {
+ if ( !rDoc.IsDocEditable()
+ || ( pDocShell && pDocShell->IsDocShared() )
+ || rDoc.IsTabProtected(nTab) )
+ rSet.DisableItem( nWhich );
+ }
+ break;
+
+ case FID_TAB_SET_TAB_BG_COLOR:
+ {
+ Color aColor = rDoc.GetTabBgColor( nTab );
+ rSet.Put( SvxColorItem( aColor, nWhich ) );
+ }
+ break;
+
+ case FID_TAB_TOGGLE_GRID:
+ rSet.Put( SfxBoolItem(nWhich, rViewData.GetShowGrid()) );
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwshg.cxx b/sc/source/ui/view/tabvwshg.cxx
new file mode 100644
index 000000000..365d51117
--- /dev/null
+++ b/sc/source/ui/view/tabvwshg.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 <config_features.h>
+
+#include <tools/urlobj.hxx>
+#include <svx/svdobjkind.hxx>
+#include <svx/svdouno.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/form/FormButtonType.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/awt/XControlModel.hpp>
+
+using namespace com::sun::star;
+
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <drawview.hxx>
+#include <globstr.hrc>
+#include <gridwin.hxx>
+#include <avmedia/mediawindow.hxx>
+
+void ScTabViewShell::InsertURLButton( const OUString& rName, const OUString& rURL,
+ const OUString& rTarget,
+ const Point* pInsPos )
+{
+ // protected sheet ?
+
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SCTAB nTab = rViewData.GetTabNo();
+ if ( rDoc.IsTabProtected(nTab) )
+ {
+ ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ MakeDrawLayer();
+
+ ScTabView* pView = rViewData.GetView();
+ ScDrawView* pDrView = pView->GetScDrawView();
+ SdrModel* pModel = pDrView->GetModel();
+
+ SdrObject* pObj = SdrObjFactory::MakeNewObject(
+ *pModel,
+ SdrInventor::FmForm,
+ SdrObjKind::FormButton);
+
+ SdrUnoObj* pUnoCtrl = dynamic_cast<SdrUnoObj*>( pObj );
+ OSL_ENSURE( pUnoCtrl, "no SdrUnoObj");
+ if( !pUnoCtrl )
+ return;
+
+ uno::Reference<awt::XControlModel> xControlModel = pUnoCtrl->GetUnoControlModel();
+ OSL_ENSURE( xControlModel.is(), "UNO control without model" );
+ if( !xControlModel.is() )
+ return;
+
+ uno::Reference< beans::XPropertySet > xPropSet( xControlModel, uno::UNO_QUERY );
+
+ xPropSet->setPropertyValue("Label", uno::Any(rName) );
+
+ OUString aTmp = INetURLObject::GetAbsURL( rDoc.GetDocumentShell()->GetMedium()->GetBaseURL(), rURL );
+ xPropSet->setPropertyValue("TargetURL", uno::Any(aTmp) );
+
+ if( !rTarget.isEmpty() )
+ {
+ xPropSet->setPropertyValue("TargetFrame", uno::Any(rTarget) );
+ }
+
+ xPropSet->setPropertyValue("ButtonType", uno::Any(form::FormButtonType_URL) );
+
+#if HAVE_FEATURE_AVMEDIA
+ if ( ::avmedia::MediaWindow::isMediaURL( rURL, ""/*TODO?*/ ) )
+ {
+ xPropSet->setPropertyValue("DispatchURLInternal", uno::Any(true) );
+ }
+#endif
+
+ Point aPos;
+ if (pInsPos)
+ aPos = *pInsPos;
+ else
+ aPos = GetInsertPos();
+
+ // Size as in 3.1:
+ Size aSize = GetActiveWin()->PixelToLogic(Size(140, 20));
+
+ if ( rDoc.IsNegativePage(nTab) )
+ aPos.AdjustX( -(aSize.Width()) );
+
+ pObj->SetLogicRect(tools::Rectangle(aPos, aSize));
+
+ // for the old VC-Button the position/size had to be set explicitly once more
+ // that seems not to be needed with UnoControls
+
+ // do not mark when Ole
+ pDrView->InsertObjectSafe( pObj, *pDrView->GetSdrPageView() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabvwshh.cxx b/sc/source/ui/view/tabvwshh.cxx
new file mode 100644
index 000000000..4e45f0153
--- /dev/null
+++ b/sc/source/ui/view/tabvwshh.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 <config_features.h>
+
+#include <basic/sberrors.hxx>
+#include <svx/svdmark.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdview.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/request.hxx>
+#include <basic/sbxcore.hxx>
+#include <svl/stritem.hxx>
+#include <svl/whiter.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/diagnose.h>
+
+#include <tabvwsh.hxx>
+#include <document.hxx>
+#include <sc.hrc>
+#include <drwlayer.hxx>
+#include <retypepassdlg.hxx>
+#include <tabprotection.hxx>
+
+#include <com/sun/star/embed/EmbedVerbs.hpp>
+
+using namespace com::sun::star;
+
+void ScTabViewShell::ExecuteObject( const SfxRequest& rReq )
+{
+ sal_uInt16 nSlotId = rReq.GetSlot();
+ const SfxItemSet* pReqArgs = rReq.GetArgs();
+
+ // Always activate/deactivate object in the visible View
+
+ ScTabViewShell* pVisibleSh = this;
+ if ( nSlotId == SID_OLE_SELECT || nSlotId == SID_OLE_ACTIVATE || nSlotId == SID_OLE_DEACTIVATE )
+ {
+ OSL_FAIL("old slot SID_OLE...");
+ }
+
+ switch (nSlotId)
+ {
+ case SID_OLE_SELECT:
+ case SID_OLE_ACTIVATE:
+ {
+ // In both cases, first select in the visible View
+
+ OUString aName;
+ SdrView* pDrView = GetScDrawView();
+ if (pDrView)
+ {
+ const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ aName = ScDrawLayer::GetVisibleName( rMarkList.GetMark(0)->GetMarkedSdrObj() );
+ }
+ pVisibleSh->SelectObject( aName );
+
+ // activate
+
+ if ( nSlotId == SID_OLE_ACTIVATE )
+ pVisibleSh->DoVerb(css::embed::EmbedVerbs::MS_OLEVERB_PRIMARY);
+ }
+ break;
+ case SID_OLE_DEACTIVATE:
+ pVisibleSh->DeactivateOle();
+ break;
+
+ case SID_OBJECT_LEFT:
+ case SID_OBJECT_TOP:
+ case SID_OBJECT_WIDTH:
+ case SID_OBJECT_HEIGHT:
+ {
+ bool bDone = false;
+ const SfxPoolItem* pItem;
+ if ( pReqArgs && pReqArgs->GetItemState( nSlotId, true, &pItem ) == SfxItemState::SET )
+ {
+ tools::Long nNewVal = static_cast<const SfxInt32Item*>(pItem)->GetValue();
+ if ( nNewVal < 0 )
+ nNewVal = 0;
+
+ //! convert from something into 1/100mm ??????
+
+ SdrView* pDrView = GetScDrawView();
+ if ( pDrView )
+ {
+ const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ tools::Rectangle aRect = pObj->GetLogicRect();
+
+ if ( nSlotId == SID_OBJECT_LEFT )
+ pDrView->MoveMarkedObj( Size( nNewVal - aRect.Left(), 0 ) );
+ else if ( nSlotId == SID_OBJECT_TOP )
+ pDrView->MoveMarkedObj( Size( 0, nNewVal - aRect.Top() ) );
+ else if ( nSlotId == SID_OBJECT_WIDTH )
+ pDrView->ResizeMarkedObj( aRect.TopLeft(),
+ Fraction( nNewVal, aRect.GetWidth() ),
+ Fraction( 1, 1 ) );
+ else // if ( nSlotId == SID_OBJECT_HEIGHT )
+ pDrView->ResizeMarkedObj( aRect.TopLeft(),
+ Fraction( 1, 1 ),
+ Fraction( nNewVal, aRect.GetHeight() ) );
+ bDone = true;
+ }
+ }
+ }
+#if HAVE_FEATURE_SCRIPTING
+ if (!bDone)
+ SbxBase::SetError( ERRCODE_BASIC_BAD_PARAMETER ); // basic error
+#endif
+ }
+ break;
+
+ }
+}
+
+static uno::Reference < embed::XEmbeddedObject > lcl_GetSelectedObj( const SdrView* pDrView ) //! member of ScDrawView?
+{
+ uno::Reference < embed::XEmbeddedObject > xRet;
+ if (pDrView)
+ {
+ const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ if (pObj->GetObjIdentifier() == SdrObjKind::OLE2)
+ {
+ SdrOle2Obj* pOle2Obj = static_cast<SdrOle2Obj*>(pObj);
+ xRet = pOle2Obj->GetObjRef();
+ }
+ }
+ }
+
+ return xRet;
+}
+
+void ScTabViewShell::GetObjectState( SfxItemSet& rSet )
+{
+ SfxWhichIter aIter(rSet);
+ sal_uInt16 nWhich = aIter.FirstWhich();
+ while ( nWhich )
+ {
+ switch (nWhich)
+ {
+ case SID_ACTIVE_OBJ_NAME:
+ {
+ OUString aName;
+ uno::Reference < embed::XEmbeddedObject > xOLE = lcl_GetSelectedObj( GetScDrawView() );
+ if (xOLE.is())
+ {
+ aName = GetViewData().GetSfxDocShell()->GetEmbeddedObjectContainer().GetEmbeddedObjectName( xOLE );
+ }
+ rSet.Put( SfxStringItem( nWhich, aName ) );
+ }
+ break;
+ case SID_OBJECT_LEFT:
+ case SID_OBJECT_TOP:
+ case SID_OBJECT_WIDTH:
+ case SID_OBJECT_HEIGHT:
+ {
+ SdrView* pDrView = GetScDrawView();
+ if ( pDrView )
+ {
+ const SdrMarkList& rMarkList = pDrView->GetMarkedObjectList();
+ if (rMarkList.GetMarkCount() == 1)
+ {
+ SdrObject* pObj = rMarkList.GetMark(0)->GetMarkedSdrObj();
+ tools::Rectangle aRect = pObj->GetLogicRect();
+
+ tools::Long nVal;
+ if ( nWhich == SID_OBJECT_LEFT )
+ nVal = aRect.Left();
+ else if ( nWhich == SID_OBJECT_TOP )
+ nVal = aRect.Top();
+ else if ( nWhich == SID_OBJECT_WIDTH )
+ nVal = aRect.GetWidth();
+ else // if ( nWhich == SID_OBJECT_HEIGHT )
+ nVal = aRect.GetHeight();
+
+ //! convert from 1/100mm to something else ??????
+
+ rSet.Put( SfxInt32Item( nWhich, nVal ) );
+ }
+ }
+ }
+ break;
+ }
+ nWhich = aIter.NextWhich();
+ }
+}
+
+void ScTabViewShell::AddAccessibilityObject( SfxListener& rObject )
+{
+ if (!pAccessibilityBroadcaster)
+ pAccessibilityBroadcaster.reset( new SfxBroadcaster );
+
+ rObject.StartListening( *pAccessibilityBroadcaster );
+ ScDocument& rDoc = GetViewData().GetDocument();
+ rDoc.AddUnoObject(rObject);
+}
+
+void ScTabViewShell::RemoveAccessibilityObject( SfxListener& rObject )
+{
+ SolarMutexGuard g;
+
+ if (pAccessibilityBroadcaster)
+ {
+ rObject.EndListening( *pAccessibilityBroadcaster );
+ ScDocument& rDoc = GetViewData().GetDocument();
+ rDoc.RemoveUnoObject(rObject);
+ }
+ else
+ {
+ OSL_FAIL("no accessibility broadcaster?");
+ }
+}
+
+void ScTabViewShell::BroadcastAccessibility( const SfxHint &rHint )
+{
+ if (pAccessibilityBroadcaster)
+ pAccessibilityBroadcaster->Broadcast( rHint );
+}
+
+bool ScTabViewShell::HasAccessibilityObjects() const
+{
+ return pAccessibilityBroadcaster != nullptr;
+}
+
+bool ScTabViewShell::ExecuteRetypePassDlg(ScPasswordHash eDesiredHash)
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ ScRetypePassDlg aDlg(GetFrameWeld());
+ aDlg.SetDataFromDocument(rDoc);
+ aDlg.SetDesiredHash(eDesiredHash);
+ if (aDlg.run() != RET_OK)
+ return false;
+
+ aDlg.WriteNewDataToDocument(rDoc);
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx
new file mode 100644
index 000000000..ae68a5dfc
--- /dev/null
+++ b/sc/source/ui/view/viewdata.cxx
@@ -0,0 +1,4366 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <editeng/eeitem.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <o3tl/string_view.hxx>
+#include <sfx2/lokhelper.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <editeng/adjustitem.hxx>
+#include <editeng/brushitem.hxx>
+#include <svtools/colorcfg.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/outliner.hxx>
+#include <editeng/unolingu.hxx>
+#include <editeng/justifyitem.hxx>
+
+#include <vcl/svapp.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+
+#include <viewdata.hxx>
+#include <docoptio.hxx>
+#include <scmod.hxx>
+#include <global.hxx>
+#include <document.hxx>
+#include <drwlayer.hxx>
+#include <attrib.hxx>
+#include <tabview.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <patattr.hxx>
+#include <editutil.hxx>
+#include <scextopt.hxx>
+#include <miscuno.hxx>
+#include <unonames.hxx>
+#include <inputopt.hxx>
+#include <inputhdl.hxx>
+#include <inputwin.hxx>
+#include <viewutil.hxx>
+#include <markdata.hxx>
+#include <ViewSettingsSequenceDefines.hxx>
+#include <gridwin.hxx>
+#include <transobj.hxx>
+#include <clipparam.hxx>
+#include <comphelper/flagguard.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/string.hxx>
+
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/document/NamedPropertyValues.hpp>
+
+using namespace com::sun::star;
+
+#define SC_GROWY_SMALL_EXTRA 100
+#define SC_GROWY_BIG_EXTRA 200
+
+constexpr OUStringLiteral TAG_TABBARWIDTH = u"tw:";
+
+namespace {
+
+void lcl_LOKRemoveWindow(ScTabViewShell* pTabViewShell, ScSplitPos eWhich)
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ auto lRemoveWindows =
+ [pTabViewShell, eWhich] (ScTabViewShell* pOtherViewShell)
+ { pOtherViewShell->RemoveWindowFromForeignEditView(pTabViewShell, eWhich); };
+
+ SfxLokHelper::forEachOtherView(pTabViewShell, lRemoveWindows);
+ }
+}
+
+} // anonymous namespace
+
+namespace {
+
+void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& rAction)
+{
+ EventDescription aDescription;
+ aDescription.aID = "grid_window";
+ aDescription.aAction = rAction;
+ aDescription.aParameters = std::move(aParameters);
+ aDescription.aParent = "MainWindow";
+ aDescription.aKeyWord = "ScGridWinUIObject";
+
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+}
+
+const ScPositionHelper::index_type ScPositionHelper::null; // definition
+
+bool ScPositionHelper::Comp::operator() (const value_type& rValue1, const value_type& rValue2) const
+{
+ if (rValue1.first == null || rValue2.first == null)
+ {
+ return rValue1.second < rValue2.second;
+ }
+ else
+ {
+ return rValue1.first < rValue2.first;
+ }
+}
+
+ScPositionHelper::ScPositionHelper(const ScDocument *pDoc, bool bColumn)
+ : MAX_INDEX(bColumn ? (pDoc ? pDoc->MaxCol() : -1) : MAXTILEDROW)
+{
+ mData.insert(std::make_pair(-1, 0));
+}
+
+void ScPositionHelper::setDocument(const ScDocument& rDoc, bool bColumn)
+{
+ MAX_INDEX = bColumn ? rDoc.MaxCol() : MAXTILEDROW;
+}
+
+void ScPositionHelper::insert(index_type nIndex, tools::Long nPos)
+{
+ if (nIndex < 0) return;
+ SAL_INFO("sc.lok.poshelper", "ScPositionHelper::insert: nIndex: "
+ << nIndex << ", nPos: " << nPos << ", size: " << mData.size());
+ value_type aValue = std::make_pair(nIndex, nPos);
+ mData.erase(aValue);
+ mData.insert(aValue);
+ SAL_INFO("sc.lok.poshelper",
+ "ScPositionHelper::insert: after insert: size: " << mData.size());
+}
+
+void ScPositionHelper::removeByIndex(index_type nIndex)
+{
+ if (nIndex < 0)
+ return;
+ SAL_INFO("sc.lok.poshelper", "ScPositionHelper::remove: nIndex: " << nIndex
+ << ", size: " << mData.size());
+ auto it = mData.find(std::make_pair(nIndex, 0));
+ if (it == mData.end()) return;
+ mData.erase(it);
+ SAL_INFO("sc.lok.poshelper",
+ "ScPositionHelper::remove: after erase: size: " << mData.size());
+}
+
+void ScPositionHelper::invalidateByIndex(index_type nIndex)
+{
+ SAL_INFO("sc.lok.poshelper", "ScPositionHelper::invalidate: nIndex: " << nIndex);
+ if (nIndex < 0)
+ {
+ mData.clear();
+ mData.insert(std::make_pair(-1, 0));
+ }
+ else
+ {
+ auto it = mData.lower_bound(std::make_pair(nIndex, 0));
+ mData.erase(it, mData.end());
+ }
+}
+
+void ScPositionHelper::invalidateByPosition(tools::Long nPos)
+{
+ SAL_INFO("sc.lok.poshelper", "ScPositionHelper::invalidate: nPos: " << nPos);
+ if (nPos <= 0)
+ {
+ mData.clear();
+ mData.insert(std::make_pair(-1, 0));
+ }
+ else
+ {
+ auto it = mData.lower_bound(std::make_pair(null, nPos));
+ mData.erase(it, mData.end());
+ }
+}
+
+const ScPositionHelper::value_type&
+ScPositionHelper::getNearestByIndex(index_type nIndex) const
+{
+ SAL_INFO("sc.lok.poshelper",
+ "ScPositionHelper::getNearest: nIndex: " << nIndex << ", size: " << mData.size());
+ auto posUB = mData.upper_bound(std::make_pair(nIndex, 0));
+ if (posUB == mData.begin())
+ {
+ return *posUB;
+ }
+
+ auto posLB = std::prev(posUB);
+ // coverity[copy_paste_error : FALSE] - posUB is correct
+ if (posUB == mData.end())
+ {
+ return *posLB;
+ }
+
+ tools::Long nDiffUB = posUB->first - nIndex;
+ tools::Long nDiffLB = posLB->first - nIndex;
+ if (nDiffUB < -nDiffLB)
+ {
+ return *posUB;
+ }
+ else
+ {
+ return *posLB;
+ }
+}
+
+const ScPositionHelper::value_type&
+ScPositionHelper::getNearestByPosition(tools::Long nPos) const
+{
+ SAL_INFO("sc.lok.poshelper",
+ "ScPositionHelper::getNearest: nPos: " << nPos << ", size: " << mData.size());
+ auto posUB = mData.upper_bound(std::make_pair(null, nPos));
+
+ if (posUB == mData.begin())
+ {
+ return *posUB;
+ }
+
+ auto posLB = std::prev(posUB);
+ // coverity[copy_paste_error : FALSE] - posUB is correct
+ if (posUB == mData.end())
+ {
+ return *posLB;
+ }
+
+ tools::Long nDiffUB = posUB->second - nPos;
+ tools::Long nDiffLB = posLB->second - nPos;
+
+ if (nDiffUB < -nDiffLB)
+ {
+ return *posUB;
+ }
+ else
+ {
+ return *posLB;
+ }
+}
+
+tools::Long ScPositionHelper::getPosition(index_type nIndex) const
+{
+ auto it = mData.find(std::make_pair(nIndex, 0));
+ if (it == mData.end()) return -1;
+ return it->second;
+}
+
+tools::Long ScPositionHelper::computePosition(index_type nIndex, const std::function<long (index_type)>& getSizePx)
+{
+ assert(MAX_INDEX > 0);
+ if (nIndex < 0) nIndex = 0;
+ if (nIndex > MAX_INDEX) nIndex = MAX_INDEX;
+
+ const auto& rNearest = getNearestByIndex(nIndex);
+ index_type nStartIndex = rNearest.first;
+ tools::Long nTotalPixels = rNearest.second;
+
+ if (nStartIndex < nIndex)
+ {
+ for (index_type nIdx = nStartIndex + 1; nIdx <= nIndex; ++nIdx)
+ {
+ nTotalPixels += getSizePx(nIdx);
+ }
+ }
+ else
+ {
+ for (index_type nIdx = nStartIndex; nIdx > nIndex; --nIdx)
+ {
+ nTotalPixels -= getSizePx(nIdx);
+ }
+ }
+ return nTotalPixels;
+}
+
+ScBoundsProvider::ScBoundsProvider(const ScViewData &rView, SCTAB nT, bool bColHeader)
+ : rDoc(rView.GetDocument())
+ , nTab(nT)
+ , bColumnHeader(bColHeader)
+ , MAX_INDEX(bColHeader ? rDoc.MaxCol() : MAXTILEDROW)
+ , mfPPTX(rView.GetPPTX())
+ , mfPPTY(rView.GetPPTY())
+ , nFirstIndex(-1)
+ , nSecondIndex(-1)
+ , nFirstPositionPx(-1)
+ , nSecondPositionPx(-1)
+{}
+
+void ScBoundsProvider::GetStartIndexAndPosition(SCCOL& nIndex, tools::Long& nPosition) const
+{
+ assert(bColumnHeader);
+ nIndex = nFirstIndex;
+ nPosition = nFirstPositionPx;
+}
+
+void ScBoundsProvider::GetEndIndexAndPosition(SCCOL& nIndex, tools::Long& nPosition) const
+{
+ assert(bColumnHeader);
+ nIndex = nSecondIndex;
+ nPosition = nSecondPositionPx;
+}
+
+void ScBoundsProvider::GetStartIndexAndPosition(SCROW& nIndex, tools::Long& nPosition) const
+{
+ assert(!bColumnHeader);
+ nIndex = nFirstIndex;
+ nPosition = nFirstPositionPx;
+}
+
+void ScBoundsProvider::GetEndIndexAndPosition(SCROW& nIndex, tools::Long& nPosition) const
+{
+ assert(!bColumnHeader);
+ nIndex = nSecondIndex;
+ nPosition = nSecondPositionPx;
+}
+
+tools::Long ScBoundsProvider::GetSize(index_type nIndex) const
+{
+ const sal_uInt16 nSize = bColumnHeader ? rDoc.GetColWidth(nIndex, nTab) : rDoc.GetRowHeight(nIndex, nTab);
+ return ScViewData::ToPixel(nSize, bColumnHeader ? mfPPTX : mfPPTY);
+}
+
+void ScBoundsProvider::GetIndexAndPos(index_type nNearestIndex, tools::Long nNearestPosition,
+ tools::Long nBound, index_type& nFoundIndex, tools::Long& nPosition,
+ bool bTowards, tools::Long nDiff)
+{
+ if (nDiff > 0) // nBound < nNearestPosition
+ GeIndexBackwards(nNearestIndex, nNearestPosition, nBound,
+ nFoundIndex, nPosition, bTowards);
+ else
+ GetIndexTowards(nNearestIndex, nNearestPosition, nBound,
+ nFoundIndex, nPosition, bTowards);
+}
+
+void ScBoundsProvider::Compute(
+ value_type aFirstNearest, value_type aSecondNearest,
+ tools::Long nFirstBound, tools::Long nSecondBound)
+{
+ SAL_INFO("sc.lok.header", "BoundsProvider: nFirstBound: " << nFirstBound
+ << ", nSecondBound: " << nSecondBound);
+
+ tools::Long nFirstDiff = aFirstNearest.second - nFirstBound;
+ tools::Long nSecondDiff = aSecondNearest.second - nSecondBound;
+ SAL_INFO("sc.lok.header", "BoundsProvider: rTopNearest: index: " << aFirstNearest.first
+ << ", pos: " << aFirstNearest.second << ", diff: " << nFirstDiff);
+ SAL_INFO("sc.lok.header", "BoundsProvider: rBottomNearest: index: " << aSecondNearest.first
+ << ", pos: " << aSecondNearest.second << ", diff: " << nSecondDiff);
+
+ bool bReverse = (std::abs(nFirstDiff) >= std::abs(nSecondDiff));
+
+ if(bReverse)
+ {
+ std::swap(aFirstNearest, aSecondNearest);
+ std::swap(nFirstBound, nSecondBound);
+ std::swap(nFirstDiff, nSecondDiff);
+ }
+
+ index_type nNearestIndex = aFirstNearest.first;
+ tools::Long nNearestPosition = aFirstNearest.second;
+ SAL_INFO("sc.lok.header", "BoundsProvider: nearest to first bound: nNearestIndex: "
+ << nNearestIndex << ", nNearestPosition: " << nNearestPosition);
+
+ GetIndexAndPos(nNearestIndex, nNearestPosition, nFirstBound,
+ nFirstIndex, nFirstPositionPx, !bReverse, nFirstDiff);
+ SAL_INFO("sc.lok.header", "BoundsProvider: nFirstIndex: " << nFirstIndex
+ << ", nFirstPositionPx: " << nFirstPositionPx);
+
+ if (std::abs(nSecondDiff) < std::abs(nSecondBound - nFirstPositionPx))
+ {
+ nNearestIndex = aSecondNearest.first;
+ nNearestPosition = aSecondNearest.second;
+ }
+ else
+ {
+ nNearestPosition = nFirstPositionPx;
+ nNearestIndex = nFirstIndex;
+ nSecondDiff = !bReverse ? -1 : 1;
+ }
+ SAL_INFO("sc.lok.header", "BoundsProvider: nearest to second bound: nNearestIndex: "
+ << nNearestIndex << ", nNearestPosition: " << nNearestPosition
+ << ", diff: " << nSecondDiff);
+
+ GetIndexAndPos(nNearestIndex, nNearestPosition, nSecondBound,
+ nSecondIndex, nSecondPositionPx, bReverse, nSecondDiff);
+ SAL_INFO("sc.lok.header", "BoundsProvider: nSecondIndex: " << nSecondIndex
+ << ", nSecondPositionPx: " << nSecondPositionPx);
+
+ if (bReverse)
+ {
+ std::swap(nFirstIndex, nSecondIndex);
+ std::swap(nFirstPositionPx, nSecondPositionPx);
+ }
+}
+
+void ScBoundsProvider::EnlargeStartBy(tools::Long nOffset)
+{
+ const index_type nNewFirstIndex =
+ std::max(static_cast<index_type>(-1),
+ static_cast<index_type>(nFirstIndex - nOffset));
+ for (index_type nIndex = nFirstIndex; nIndex > nNewFirstIndex; --nIndex)
+ {
+ const tools::Long nSizePx = GetSize(nIndex);
+ nFirstPositionPx -= nSizePx;
+ }
+ nFirstIndex = nNewFirstIndex;
+ SAL_INFO("sc.lok.header", "BoundsProvider: added offset: nFirstIndex: " << nFirstIndex
+ << ", nFirstPositionPx: " << nFirstPositionPx);
+}
+
+void ScBoundsProvider::EnlargeEndBy(tools::Long nOffset)
+{
+ const index_type nNewSecondIndex = std::min(MAX_INDEX, static_cast<index_type>(nSecondIndex + nOffset));
+ for (index_type nIndex = nSecondIndex + 1; nIndex <= nNewSecondIndex; ++nIndex)
+ {
+ const tools::Long nSizePx = GetSize(nIndex);
+ nSecondPositionPx += nSizePx;
+ }
+ nSecondIndex = nNewSecondIndex;
+ SAL_INFO("sc.lok.header", "BoundsProvider: added offset: nSecondIndex: " << nSecondIndex
+ << ", nSecondPositionPx: " << nSecondPositionPx);
+}
+
+void ScBoundsProvider::GeIndexBackwards(
+ index_type nNearestIndex, tools::Long nNearestPosition,
+ tools::Long nBound, index_type& nFoundIndex, tools::Long& nPosition, bool bTowards)
+{
+ nFoundIndex = -1;
+ for (index_type nIndex = nNearestIndex; nIndex >= 0; --nIndex)
+ {
+ if (nBound >= nNearestPosition)
+ {
+ nFoundIndex = nIndex; // last index whose nPosition is less than nBound
+ nPosition = nNearestPosition;
+ break;
+ }
+
+ const tools::Long nSizePx = GetSize(nIndex);
+ nNearestPosition -= nSizePx;
+ }
+ if (!bTowards && nFoundIndex != -1)
+ {
+ nFoundIndex += 1;
+ nPosition += GetSize(nFoundIndex);
+ }
+}
+
+void ScBoundsProvider::GetIndexTowards(
+ index_type nNearestIndex, tools::Long nNearestPosition,
+ tools::Long nBound, index_type& nFoundIndex, tools::Long& nPosition, bool bTowards)
+{
+ nFoundIndex = -2;
+ for (index_type nIndex = nNearestIndex + 1; nIndex <= MAX_INDEX; ++nIndex)
+ {
+ const tools::Long nSizePx = GetSize(nIndex);
+ nNearestPosition += nSizePx;
+
+ if (nNearestPosition > nBound)
+ {
+ nFoundIndex = nIndex; // first index whose nPosition is greater than nBound
+ nPosition = nNearestPosition;
+ break;
+ }
+ }
+ if (nFoundIndex == -2)
+ {
+ nFoundIndex = MAX_INDEX;
+ nPosition = nNearestPosition;
+ }
+ else if (bTowards)
+ {
+ nPosition -= GetSize(nFoundIndex);
+ nFoundIndex -= 1;
+ }
+}
+
+ScViewDataTable::ScViewDataTable(const ScDocument *pDoc) :
+ eZoomType( SvxZoomType::PERCENT ),
+ aZoomX( 1,1 ),
+ aZoomY( 1,1 ),
+ aPageZoomX( 3,5 ), // Page-Default: 60%
+ aPageZoomY( 3,5 ),
+ nHSplitPos( 0 ),
+ nVSplitPos( 0 ),
+ eHSplitMode( SC_SPLIT_NONE ),
+ eVSplitMode( SC_SPLIT_NONE ),
+ eWhichActive( SC_SPLIT_BOTTOMLEFT ),
+ nFixPosX( 0 ),
+ nFixPosY( 0 ),
+ nCurX( 0 ),
+ nCurY( 0 ),
+ nOldCurX( 0 ),
+ nOldCurY( 0 ),
+ aWidthHelper(pDoc, true),
+ aHeightHelper(pDoc, false),
+ nMaxTiledCol( 20 ),
+ nMaxTiledRow( 50 ),
+ bShowGrid( true ),
+ mbOldCursorValid( false )
+{
+ nPosX[0]=nPosX[1]=0;
+ nPosY[0]=nPosY[1]=0;
+ nTPosX[0]=nTPosX[1]=0;
+ nTPosY[0]=nTPosY[1]=0;
+ nMPosX[0]=nMPosX[1]=0;
+ nMPosY[0]=nMPosY[1]=0;
+ nPixPosX[0]=nPixPosX[1]=0;
+ nPixPosY[0]=nPixPosY[1]=0;
+}
+
+void ScViewDataTable::InitData(const ScDocument& rDoc)
+{
+ aWidthHelper.setDocument(rDoc, true);
+ aHeightHelper.setDocument(rDoc, false);
+}
+
+void ScViewDataTable::WriteUserDataSequence(uno::Sequence <beans::PropertyValue>& rSettings, const ScViewData& rViewData, SCTAB nTab) const
+{
+ rSettings.realloc(SC_TABLE_VIEWSETTINGS_COUNT);
+ beans::PropertyValue* pSettings = rSettings.getArray();
+
+ ScSplitMode eExHSplitMode = eHSplitMode;
+ ScSplitMode eExVSplitMode = eVSplitMode;
+ SCCOL nExFixPosX = nFixPosX;
+ SCROW nExFixPosY = nFixPosY;
+ tools::Long nExHSplitPos = nHSplitPos;
+ tools::Long nExVSplitPos = nVSplitPos;
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ rViewData.OverrideWithLOKFreeze(eExHSplitMode, eExVSplitMode,
+ nExFixPosX, nExFixPosY,
+ nExHSplitPos, nExVSplitPos, nTab);
+ }
+
+ pSettings[SC_CURSOR_X].Name = SC_CURSORPOSITIONX;
+ pSettings[SC_CURSOR_X].Value <<= sal_Int32(nCurX);
+ pSettings[SC_CURSOR_Y].Name = SC_CURSORPOSITIONY;
+ pSettings[SC_CURSOR_Y].Value <<= sal_Int32(nCurY);
+
+ // Write freezepan data only when freeze pans are set
+ if(nExFixPosX != 0 || nExFixPosY != 0 || nExHSplitPos != 0 || nExVSplitPos != 0)
+ {
+ pSettings[SC_HORIZONTAL_SPLIT_MODE].Name = SC_HORIZONTALSPLITMODE;
+ pSettings[SC_HORIZONTAL_SPLIT_MODE].Value <<= sal_Int16(eExHSplitMode);
+ pSettings[SC_VERTICAL_SPLIT_MODE].Name = SC_VERTICALSPLITMODE;
+ pSettings[SC_VERTICAL_SPLIT_MODE].Value <<= sal_Int16(eExVSplitMode);
+ pSettings[SC_HORIZONTAL_SPLIT_POSITION].Name = SC_HORIZONTALSPLITPOSITION;
+ if (eExHSplitMode == SC_SPLIT_FIX)
+ pSettings[SC_HORIZONTAL_SPLIT_POSITION].Value <<= sal_Int32(nExFixPosX);
+ else
+ pSettings[SC_HORIZONTAL_SPLIT_POSITION].Value <<= sal_Int32(nExHSplitPos);
+ pSettings[SC_VERTICAL_SPLIT_POSITION].Name = SC_VERTICALSPLITPOSITION;
+ if (eExVSplitMode == SC_SPLIT_FIX)
+ pSettings[SC_VERTICAL_SPLIT_POSITION].Value <<= sal_Int32(nExFixPosY);
+ else
+ pSettings[SC_VERTICAL_SPLIT_POSITION].Value <<= sal_Int32(nExVSplitPos);
+ }
+
+ // Prevent writing odd settings that would make crash versions that
+ // don't apply SanitizeWhichActive() when reading the settings.
+ // See tdf#117093
+ const ScSplitPos eActiveSplitRange = SanitizeWhichActive();
+ // And point out to give us a chance to inspect weird things (if anyone
+ // remembers what s/he did).
+ assert(eWhichActive == eActiveSplitRange);
+ pSettings[SC_ACTIVE_SPLIT_RANGE].Name = SC_ACTIVESPLITRANGE;
+ pSettings[SC_ACTIVE_SPLIT_RANGE].Value <<= sal_Int16(eActiveSplitRange);
+ pSettings[SC_POSITION_LEFT].Name = SC_POSITIONLEFT;
+ pSettings[SC_POSITION_LEFT].Value <<= sal_Int32(nPosX[SC_SPLIT_LEFT]);
+ pSettings[SC_POSITION_RIGHT].Name = SC_POSITIONRIGHT;
+ pSettings[SC_POSITION_RIGHT].Value <<= sal_Int32(nPosX[SC_SPLIT_RIGHT]);
+ pSettings[SC_POSITION_TOP].Name = SC_POSITIONTOP;
+ pSettings[SC_POSITION_TOP].Value <<= sal_Int32(nPosY[SC_SPLIT_TOP]);
+ pSettings[SC_POSITION_BOTTOM].Name = SC_POSITIONBOTTOM;
+ pSettings[SC_POSITION_BOTTOM].Value <<= sal_Int32(nPosY[SC_SPLIT_BOTTOM]);
+
+ sal_Int32 nZoomValue = tools::Long(aZoomY * 100);
+ sal_Int32 nPageZoomValue = tools::Long(aPageZoomY * 100);
+ pSettings[SC_TABLE_ZOOM_TYPE].Name = SC_ZOOMTYPE;
+ pSettings[SC_TABLE_ZOOM_TYPE].Value <<= sal_Int16(eZoomType);
+ pSettings[SC_TABLE_ZOOM_VALUE].Name = SC_ZOOMVALUE;
+ pSettings[SC_TABLE_ZOOM_VALUE].Value <<= nZoomValue;
+ pSettings[SC_TABLE_PAGE_VIEW_ZOOM_VALUE].Name = SC_PAGEVIEWZOOMVALUE;
+ pSettings[SC_TABLE_PAGE_VIEW_ZOOM_VALUE].Value <<= nPageZoomValue;
+
+ pSettings[SC_TABLE_SHOWGRID].Name = SC_UNO_SHOWGRID;
+ pSettings[SC_TABLE_SHOWGRID].Value <<= bShowGrid;
+
+ // Common SdrModel processing
+ rViewData.GetDocument().GetDrawLayer()->WriteUserDataSequence(rSettings);
+}
+
+void ScViewDataTable::ReadUserDataSequence(const uno::Sequence <beans::PropertyValue>& aSettings, ScViewData& rViewData, SCTAB nTab, bool& rHasZoom )
+{
+ rHasZoom = false;
+
+ sal_Int32 nTemp32(0);
+ sal_Int16 nTemp16(0);
+ sal_Int32 nTempPosV(0);
+ sal_Int32 nTempPosH(0);
+ sal_Int32 nTempPosVTw(0);
+ sal_Int32 nTempPosHTw(0);
+ bool bHasVSplitInTwips = false;
+ bool bHasHSplitInTwips = false;
+ for (const auto& rSetting : aSettings)
+ {
+ OUString sName(rSetting.Name);
+ if (sName == SC_CURSORPOSITIONX)
+ {
+ rSetting.Value >>= nTemp32;
+ nCurX = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>(nTemp32));
+ }
+ else if (sName == SC_CURSORPOSITIONY)
+ {
+ rSetting.Value >>= nTemp32;
+ nCurY = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>(nTemp32));
+ }
+ else if (sName == SC_HORIZONTALSPLITMODE)
+ {
+ if ((rSetting.Value >>= nTemp16) && nTemp16 <= ScSplitMode::SC_SPLIT_MODE_MAX_ENUM)
+ eHSplitMode = static_cast<ScSplitMode>(nTemp16);
+ }
+ else if (sName == SC_VERTICALSPLITMODE)
+ {
+ if ((rSetting.Value >>= nTemp16) && nTemp16 <= ScSplitMode::SC_SPLIT_MODE_MAX_ENUM)
+ eVSplitMode = static_cast<ScSplitMode>(nTemp16);
+ }
+ else if (sName == SC_HORIZONTALSPLITPOSITION)
+ {
+ rSetting.Value >>= nTempPosH;
+ bHasHSplitInTwips = false;
+ }
+ else if (sName == SC_VERTICALSPLITPOSITION)
+ {
+ rSetting.Value >>= nTempPosV;
+ bHasVSplitInTwips = false;
+ }
+ else if (sName == SC_HORIZONTALSPLITPOSITION_TWIPS)
+ {
+ rSetting.Value >>= nTempPosHTw;
+ bHasHSplitInTwips = true;
+ }
+ else if (sName == SC_VERTICALSPLITPOSITION_TWIPS)
+ {
+ rSetting.Value >>= nTempPosVTw;
+ bHasVSplitInTwips = true;
+ }
+ else if (sName == SC_ACTIVESPLITRANGE)
+ {
+ if ((rSetting.Value >>= nTemp16) && nTemp16 <= ScSplitPos::SC_SPLIT_POS_MAX_ENUM)
+ eWhichActive = static_cast<ScSplitPos>(nTemp16);
+ }
+ else if (sName == SC_POSITIONLEFT)
+ {
+ rSetting.Value >>= nTemp32;
+ nPosX[SC_SPLIT_LEFT] = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>(nTemp32));
+ }
+ else if (sName == SC_POSITIONRIGHT)
+ {
+ rSetting.Value >>= nTemp32;
+ nPosX[SC_SPLIT_RIGHT] = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>(nTemp32));
+ }
+ else if (sName == SC_POSITIONTOP)
+ {
+ rSetting.Value >>= nTemp32;
+ nPosY[SC_SPLIT_TOP] = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>(nTemp32));
+ }
+ else if (sName == SC_POSITIONBOTTOM)
+ {
+ rSetting.Value >>= nTemp32;
+ nPosY[SC_SPLIT_BOTTOM] = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>(nTemp32));
+ }
+ else if (sName == SC_ZOOMTYPE)
+ {
+ rSetting.Value >>= nTemp16;
+ eZoomType = SvxZoomType(nTemp16);
+ rHasZoom = true; // set if there is any zoom information
+ }
+ else if (sName == SC_ZOOMVALUE)
+ {
+ rSetting.Value >>= nTemp32;
+ Fraction aZoom(nTemp32, 100);
+ aZoomX = aZoomY = aZoom;
+ rHasZoom = true;
+ }
+ else if (sName == SC_PAGEVIEWZOOMVALUE)
+ {
+ rSetting.Value >>= nTemp32;
+ Fraction aZoom(nTemp32, 100);
+ aPageZoomX = aPageZoomY = aZoom;
+ rHasZoom = true;
+ }
+ else if (sName == SC_UNO_SHOWGRID)
+ {
+ rSetting.Value >>= bShowGrid;
+ }
+ else if (sName == SC_TABLESELECTED)
+ {
+ bool bSelected = false;
+ rSetting.Value >>= bSelected;
+ rViewData.GetMarkData().SelectTable( nTab, bSelected );
+ }
+ else if (sName == SC_UNONAME_TABCOLOR)
+ {
+ // There are documents out there that have their tab color defined as a view setting.
+ Color aColor = COL_AUTO;
+ rSetting.Value >>= aColor;
+ if (aColor != COL_AUTO)
+ {
+ ScDocument& rDoc = rViewData.GetDocument();
+ rDoc.SetTabBgColor(nTab, aColor);
+ }
+ }
+ // Fallback to common SdrModel processing
+ else rViewData.GetDocument().GetDrawLayer()->ReadUserDataSequenceValue(&rSetting);
+ }
+
+ if (eHSplitMode == SC_SPLIT_FIX)
+ nFixPosX = rViewData.GetDocument().SanitizeCol( static_cast<SCCOL>( bHasHSplitInTwips ? nTempPosHTw : nTempPosH ));
+ else
+ nHSplitPos = bHasHSplitInTwips ? static_cast< tools::Long >( nTempPosHTw * rViewData.GetPPTX() ) : nTempPosH;
+
+ if (eVSplitMode == SC_SPLIT_FIX)
+ nFixPosY = rViewData.GetDocument().SanitizeRow( static_cast<SCROW>( bHasVSplitInTwips ? nTempPosVTw : nTempPosV ));
+ else
+ nVSplitPos = bHasVSplitInTwips ? static_cast< tools::Long >( nTempPosVTw * rViewData.GetPPTY() ) : nTempPosV;
+
+ eWhichActive = SanitizeWhichActive();
+}
+
+ScSplitPos ScViewDataTable::SanitizeWhichActive() const
+{
+ if ((WhichH(eWhichActive) == SC_SPLIT_RIGHT && eHSplitMode == SC_SPLIT_NONE) ||
+ (WhichV(eWhichActive) == SC_SPLIT_TOP && eVSplitMode == SC_SPLIT_NONE))
+ {
+ SAL_WARN("sc.ui","ScViewDataTable::SanitizeWhichActive - bad eWhichActive " << eWhichActive);
+ // The default always initialized grid window is SC_SPLIT_BOTTOMLEFT.
+ return SC_SPLIT_BOTTOMLEFT;
+ }
+ return eWhichActive;
+}
+
+ScViewData::ScViewData(ScDocShell& rDocSh, ScTabViewShell* pViewSh)
+ : ScViewData(nullptr, &rDocSh, pViewSh)
+{
+}
+
+ScViewData::ScViewData(ScDocument& rDoc)
+ : ScViewData(&rDoc, nullptr, nullptr)
+{
+}
+
+static ScViewOptions DefaultOptions()
+{
+ ScViewOptions aOptions;
+ aOptions.SetOption(VOPT_GRID, true);
+ aOptions.SetOption(VOPT_SYNTAX, false);
+ aOptions.SetOption(VOPT_HEADER, true);
+ aOptions.SetOption(VOPT_TABCONTROLS, true);
+ aOptions.SetOption(VOPT_VSCROLL, true);
+ aOptions.SetOption(VOPT_HSCROLL, true);
+ aOptions.SetOption(VOPT_OUTLINER, true);
+ return aOptions;
+}
+
+// Either pDoc or pDocSh must be valid
+ScViewData::ScViewData(ScDocument* pDoc, ScDocShell* pDocSh, ScTabViewShell* pViewSh) :
+ nPPTX(0.0),
+ nPPTY(0.0),
+ maMarkData (pDocSh ? pDocSh->GetDocument().GetSheetLimits() : pDoc->GetSheetLimits()),
+ pDocShell ( pDocSh ),
+ mrDoc (pDocSh ? pDocSh->GetDocument() : *pDoc),
+ pView ( pViewSh ),
+ maOptions (pDocSh ? pDocSh->GetDocument().GetViewOptions() : DefaultOptions()),
+ pSpellingView ( nullptr ),
+ aLogicMode ( MapUnit::Map100thMM ),
+ eDefZoomType( SvxZoomType::PERCENT ),
+ aDefZoomX ( 1,1 ),
+ aDefZoomY ( 1,1 ),
+ aDefPageZoomX( 3,5 ),
+ aDefPageZoomY( 3,5 ),
+ eRefType ( SC_REFTYPE_NONE ),
+ nTabNo ( 0 ),
+ nRefTabNo ( 0 ),
+ nRefStartX(0),
+ nRefStartY(0),
+ nRefStartZ(0),
+ nRefEndX(0),
+ nRefEndY(0),
+ nRefEndZ(0),
+ nFillStartX(0),
+ nFillStartY(0),
+ nFillEndX(0),
+ nFillEndY(0),
+ nPasteFlags ( ScPasteFlags::NONE ),
+ eEditActivePart( SC_SPLIT_BOTTOMLEFT ),
+ nFillMode ( ScFillMode::NONE ),
+ eEditAdjust ( SvxAdjust::Left ),
+ bActive ( true ), // how to initialize?
+ bIsRefMode ( false ),
+ bDelMarkValid( false ),
+ bPagebreak ( false ),
+ bSelCtrlMouseClick( false ),
+ bMoveArea ( false ),
+ bGrowing (false),
+ nFormulaBarLines(1),
+ m_nLOKPageUpDownOffset( 0 )
+{
+ assert(bool(pDoc) != bool(pDocSh)); // either one or the other, not both
+ maMarkData.SelectOneTable(0); // Sync with nTabNo
+
+ aScrSize = Size( o3tl::convert(STD_COL_WIDTH * OLE_STD_CELLS_X, o3tl::Length::twip, o3tl::Length::px),
+ o3tl::convert(ScGlobal::nStdRowHeight * OLE_STD_CELLS_Y, o3tl::Length::twip, o3tl::Length::px));
+ maTabData.emplace_back( new ScViewDataTable(nullptr) );
+ pThisTab = maTabData[nTabNo].get();
+
+ nEditEndCol = nEditStartCol = nEditCol = 0;
+ nEditEndRow = nEditRow = 0;
+ nTabStartCol = SC_TABSTART_NONE;
+
+ // don't show hidden tables
+ if (!mrDoc.IsVisible(nTabNo))
+ {
+ while (!mrDoc.IsVisible(nTabNo) && mrDoc.HasTable(nTabNo + 1))
+ {
+ ++nTabNo;
+ maTabData.emplace_back(nullptr);
+ }
+ maTabData[nTabNo].reset( new ScViewDataTable(nullptr) );
+ pThisTab = maTabData[nTabNo].get();
+ }
+
+ SCTAB nTableCount = mrDoc.GetTableCount();
+ EnsureTabDataSize(nTableCount);
+
+ for (auto& xTabData : maTabData)
+ {
+ if (xTabData)
+ xTabData->InitData(mrDoc);
+ }
+
+ CalcPPT();
+}
+
+ScViewData::~ScViewData() COVERITY_NOEXCEPT_FALSE
+{
+ KillEditView();
+}
+
+ScDBFunc* ScViewData::GetView() const { return pView; }
+
+void ScViewData::UpdateCurrentTab()
+{
+ assert(0 <= nTabNo && o3tl::make_unsigned(nTabNo) < maTabData.size());
+ pThisTab = maTabData[nTabNo].get();
+ while (!pThisTab)
+ {
+ if (nTabNo > 0)
+ pThisTab = maTabData[--nTabNo].get();
+ else
+ {
+ maTabData[0].reset(new ScViewDataTable(&mrDoc));
+ pThisTab = maTabData[0].get();
+ }
+ }
+}
+
+void ScViewData::InsertTab( SCTAB nTab )
+{
+ if( nTab >= static_cast<SCTAB>(maTabData.size()))
+ maTabData.resize(nTab+1);
+ else
+ maTabData.insert( maTabData.begin() + nTab, nullptr );
+ CreateTabData( nTab );
+
+ UpdateCurrentTab();
+ maMarkData.InsertTab(nTab);
+
+ collectUIInformation({{}}, "InsertTab");
+}
+
+void ScViewData::InsertTabs( SCTAB nTab, SCTAB nNewSheets )
+{
+ if (nTab >= static_cast<SCTAB>(maTabData.size()))
+ maTabData.resize(nTab+nNewSheets);
+ else
+ {
+ // insert nNewSheets new tables at position nTab
+ auto prevSize = maTabData.size();
+ maTabData.resize(prevSize + nNewSheets);
+ std::move_backward(maTabData.begin() + nTab, maTabData.begin() + prevSize, maTabData.end());
+ }
+ for (SCTAB i = nTab; i < nTab + nNewSheets; ++i)
+ {
+ CreateTabData( i );
+ maMarkData.InsertTab(i);
+ }
+ UpdateCurrentTab();
+}
+
+void ScViewData::DeleteTab( SCTAB nTab )
+{
+ assert(nTab < static_cast<SCTAB>(maTabData.size()));
+ maTabData.erase(maTabData.begin() + nTab);
+
+ if (o3tl::make_unsigned(nTabNo) >= maTabData.size())
+ {
+ EnsureTabDataSize(1);
+ nTabNo = maTabData.size() - 1;
+ }
+ UpdateCurrentTab();
+ maMarkData.DeleteTab(nTab);
+}
+
+void ScViewData::DeleteTabs( SCTAB nTab, SCTAB nSheets )
+{
+ for (SCTAB i = 0; i < nSheets; ++i)
+ {
+ maMarkData.DeleteTab(nTab + i);
+ }
+ maTabData.erase(maTabData.begin() + nTab, maTabData.begin()+ nTab+nSheets);
+ if (o3tl::make_unsigned(nTabNo) >= maTabData.size())
+ {
+ EnsureTabDataSize(1);
+ nTabNo = maTabData.size() - 1;
+ }
+ UpdateCurrentTab();
+}
+
+void ScViewData::CopyTab( SCTAB nSrcTab, SCTAB nDestTab )
+{
+ if (nDestTab==SC_TAB_APPEND)
+ nDestTab = mrDoc.GetTableCount() - 1; // something had to have been copied
+
+ if (nDestTab > MAXTAB)
+ {
+ OSL_FAIL("too many sheets");
+ return;
+ }
+
+ if (nSrcTab >= static_cast<SCTAB>(maTabData.size()))
+ OSL_FAIL("pTabData out of bounds, FIX IT");
+
+ EnsureTabDataSize(nDestTab + 1);
+
+ if ( maTabData[nSrcTab] )
+ maTabData.emplace(maTabData.begin() + nDestTab, new ScViewDataTable( *maTabData[nSrcTab] ));
+ else
+ maTabData.insert(maTabData.begin() + nDestTab, nullptr);
+
+ UpdateCurrentTab();
+ maMarkData.InsertTab(nDestTab);
+}
+
+void ScViewData::MoveTab( SCTAB nSrcTab, SCTAB nDestTab )
+{
+ if (nDestTab==SC_TAB_APPEND)
+ nDestTab = mrDoc.GetTableCount() - 1;
+ std::unique_ptr<ScViewDataTable> pTab;
+ if (nSrcTab < static_cast<SCTAB>(maTabData.size()))
+ {
+ pTab = std::move(maTabData[nSrcTab]);
+ maTabData.erase( maTabData.begin() + nSrcTab );
+ }
+
+ if (nDestTab < static_cast<SCTAB>(maTabData.size()))
+ maTabData.insert( maTabData.begin() + nDestTab, std::move(pTab) );
+ else
+ {
+ EnsureTabDataSize(nDestTab + 1);
+ maTabData[nDestTab] = std::move(pTab);
+ }
+
+ UpdateCurrentTab();
+ maMarkData.DeleteTab(nSrcTab);
+ maMarkData.InsertTab(nDestTab); // adapted if needed
+}
+
+void ScViewData::CreateTabData( std::vector< SCTAB >& rvTabs )
+{
+ for ( const auto& rTab : rvTabs )
+ CreateTabData(rTab);
+}
+
+void ScViewData::SetZoomType( SvxZoomType eNew, std::vector< SCTAB >& tabs )
+{
+ bool bAll = tabs.empty();
+
+ if ( !bAll ) // create associated table data
+ CreateTabData( tabs );
+
+ if ( bAll )
+ {
+ for ( auto & i: maTabData )
+ {
+ if ( i )
+ i->eZoomType = eNew;
+ }
+ eDefZoomType = eNew;
+ }
+ else
+ {
+ for ( const SCTAB& i : tabs )
+ {
+ if ( i < static_cast<SCTAB>(maTabData.size()) && maTabData[i] )
+ maTabData[i]->eZoomType = eNew;
+ }
+ }
+}
+
+void ScViewData::SetZoomType( SvxZoomType eNew, bool bAll )
+{
+ std::vector< SCTAB > vTabs; // Empty for all tabs
+ if ( !bAll ) // get selected tabs
+ {
+ ScMarkData::const_iterator itr = maMarkData.begin(), itrEnd = maMarkData.end();
+ vTabs.insert(vTabs.begin(), itr, itrEnd);
+ }
+ SetZoomType( eNew, vTabs );
+}
+
+void ScViewData::SetZoom( const Fraction& rNewX, const Fraction& rNewY, std::vector< SCTAB >& tabs )
+{
+ bool bAll = tabs.empty();
+ if ( !bAll ) // create associated table data
+ CreateTabData( tabs );
+
+ // sanity check - we shouldn't need something this low / big
+ SAL_WARN_IF(rNewX < Fraction(1, 100) || rNewX > Fraction(100, 1), "sc.viewdata",
+ "fraction rNewX not sensible: " << static_cast<double>(rNewX));
+ SAL_WARN_IF(rNewY < Fraction(1, 100) || rNewY > Fraction(100, 1), "sc.viewdata",
+ "fraction rNewY not sensible: " << static_cast<double>(rNewY));
+
+ if ( bAll )
+ {
+ for ( auto & i: maTabData )
+ {
+ if ( i )
+ {
+ if ( bPagebreak )
+ {
+ i->aPageZoomX = rNewX;
+ i->aPageZoomY = rNewY;
+ }
+ else
+ {
+ i->aZoomX = rNewX;
+ i->aZoomY = rNewY;
+ }
+ }
+ }
+ if ( bPagebreak )
+ {
+ aDefPageZoomX = rNewX;
+ aDefPageZoomY = rNewY;
+ }
+ else
+ {
+ aDefZoomX = rNewX;
+ aDefZoomY = rNewY;
+ }
+ }
+ else
+ {
+ for ( const SCTAB& i : tabs )
+ {
+ if ( i < static_cast<SCTAB>(maTabData.size()) && maTabData[i] )
+ {
+ if ( bPagebreak )
+ {
+ maTabData[i]->aPageZoomX = rNewX;
+ maTabData[i]->aPageZoomY = rNewY;
+ }
+ else
+ {
+ maTabData[i]->aZoomX = rNewX;
+ maTabData[i]->aZoomY = rNewY;
+ }
+ }
+ }
+ }
+ RefreshZoom();
+}
+
+void ScViewData::SetZoom( const Fraction& rNewX, const Fraction& rNewY, bool bAll )
+{
+ std::vector< SCTAB > vTabs;
+ if ( !bAll ) // get selected tabs
+ {
+ ScMarkData::const_iterator itr = maMarkData.begin(), itrEnd = maMarkData.end();
+ vTabs.insert(vTabs.begin(), itr, itrEnd);
+ }
+ SetZoom( rNewX, rNewY, vTabs );
+}
+
+void ScViewData::SetShowGrid( bool bShow )
+{
+ CreateSelectedTabData();
+ maTabData[nTabNo]->bShowGrid = bShow;
+}
+
+void ScViewData::RefreshZoom()
+{
+ // recalculate zoom-dependent values (only for current sheet)
+
+ CalcPPT();
+ RecalcPixPos();
+ aScenButSize = Size(0,0);
+ aLogicMode.SetScaleX( GetZoomX() );
+ aLogicMode.SetScaleY( GetZoomY() );
+}
+
+void ScViewData::SetPagebreakMode( bool bSet )
+{
+ bPagebreak = bSet;
+
+ RefreshZoom();
+}
+
+ScMarkType ScViewData::GetSimpleArea( ScRange & rRange, ScMarkData & rNewMark ) const
+{
+ ScMarkType eMarkType = SC_MARK_NONE;
+
+ if ( rNewMark.IsMarked() || rNewMark.IsMultiMarked() )
+ {
+ if ( rNewMark.IsMultiMarked() )
+ rNewMark.MarkToSimple();
+
+ if ( rNewMark.IsMarked() && !rNewMark.IsMultiMarked() )
+ {
+ rRange = rNewMark.GetMarkArea();
+ if (ScViewUtil::HasFiltered(rRange, GetDocument()))
+ eMarkType = SC_MARK_SIMPLE_FILTERED;
+ else
+ eMarkType = SC_MARK_SIMPLE;
+ }
+ else
+ eMarkType = SC_MARK_MULTI;
+ }
+ if (eMarkType != SC_MARK_SIMPLE && eMarkType != SC_MARK_SIMPLE_FILTERED)
+ {
+ if (eMarkType == SC_MARK_NONE)
+ eMarkType = SC_MARK_SIMPLE;
+ const ScPatternAttr* pMarkPattern = mrDoc.GetPattern(GetCurX(), GetCurY(), GetTabNo());
+ if (pMarkPattern && pMarkPattern->GetItemSet().GetItemState(ATTR_MERGE, false) == SfxItemState::SET)
+ {
+ SCROW nRow = pMarkPattern->GetItem(ATTR_MERGE).GetRowMerge();
+ SCCOL nCol = pMarkPattern->GetItem(ATTR_MERGE).GetColMerge();
+ if ( nRow < 1 || nCol < 1 )
+ {
+ // This kind of cells do exist. Not sure if that is intended or a bug.
+ rRange = ScRange(GetCurX(), GetCurY(), GetTabNo());
+ }
+ else
+ {
+ rRange = ScRange(GetCurX(), GetCurY(), GetTabNo(),
+ GetCurX() + nCol - 1, GetCurY() + nRow - 1, GetTabNo());
+ if ( ScViewUtil::HasFiltered(rRange, GetDocument()) )
+ eMarkType = SC_MARK_SIMPLE_FILTERED;
+ }
+ }
+ else
+ rRange = ScRange(GetCurX(), GetCurY(), GetTabNo());
+ }
+ return eMarkType;
+}
+
+ScMarkType ScViewData::GetSimpleArea( SCCOL& rStartCol, SCROW& rStartRow, SCTAB& rStartTab,
+ SCCOL& rEndCol, SCROW& rEndRow, SCTAB& rEndTab ) const
+{
+ // parameter bMergeMark is no longer needed: The view's selection is never modified
+ // (a local copy is used), and a multi selection that adds to a single range can always
+ // be treated like a single selection (GetSimpleArea isn't used in selection
+ // handling itself)
+
+ ScRange aRange;
+ ScMarkData aNewMark(maMarkData); // use a local copy for MarkToSimple
+ ScMarkType eMarkType = GetSimpleArea( aRange, aNewMark);
+ aRange.GetVars( rStartCol, rStartRow, rStartTab, rEndCol, rEndRow, rEndTab);
+ return eMarkType;
+}
+
+ScMarkType ScViewData::GetSimpleArea( ScRange& rRange ) const
+{
+ // parameter bMergeMark is no longer needed, see above
+
+ ScMarkData aNewMark(maMarkData); // use a local copy for MarkToSimple
+ return GetSimpleArea( rRange, aNewMark);
+}
+
+void ScViewData::GetMultiArea( ScRangeListRef& rRange ) const
+{
+ // parameter bMergeMark is no longer needed, see GetSimpleArea
+
+ ScMarkData aNewMark(maMarkData); // use a local copy for MarkToSimple
+
+ bool bMulti = aNewMark.IsMultiMarked();
+ if (bMulti)
+ {
+ aNewMark.MarkToSimple();
+ bMulti = aNewMark.IsMultiMarked();
+ }
+ if (bMulti)
+ {
+ rRange = new ScRangeList;
+ aNewMark.FillRangeListWithMarks( rRange.get(), false );
+ }
+ else
+ {
+ ScRange aSimple;
+ GetSimpleArea(aSimple);
+ rRange = new ScRangeList(aSimple);
+ }
+}
+
+bool ScViewData::SimpleColMarked()
+{
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCTAB nStartTab;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ SCTAB nEndTab;
+ if (GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
+ if (nStartRow == 0 && nEndRow == mrDoc.MaxRow())
+ return true;
+
+ return false;
+}
+
+bool ScViewData::SimpleRowMarked()
+{
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCTAB nStartTab;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ SCTAB nEndTab;
+ if (GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
+ if (nStartCol == 0 && nEndCol == mrDoc.MaxCol())
+ return true;
+
+ return false;
+}
+
+bool ScViewData::IsMultiMarked() const
+{
+ // Test for "real" multi selection, calling MarkToSimple on a local copy,
+ // and taking filtered in simple area marks into account.
+
+ ScRange aDummy;
+ ScMarkType eType = GetSimpleArea(aDummy);
+ return (eType & SC_MARK_SIMPLE) != SC_MARK_SIMPLE;
+}
+
+bool ScViewData::SelectionForbidsPaste( ScDocument* pClipDoc )
+{
+ if (!pClipDoc)
+ {
+ // Same as checkDestRanges() in sc/source/ui/view/cellsh.cxx but
+ // different return details.
+
+ vcl::Window* pWin = GetActiveWin();
+ if (!pWin)
+ // No window doesn't mean paste would be forbidden.
+ return false;
+
+ const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pWin));
+ if (!pOwnClip)
+ // Foreign content does not get repeatedly replicated.
+ return false;
+
+ pClipDoc = pOwnClip->GetDocument();
+ if (!pClipDoc)
+ // No clipdoc doesn't mean paste would be forbidden.
+ return false;
+ }
+
+ const ScRange aSrcRange = pClipDoc->GetClipParam().getWholeRange();
+ const SCROW nRowSize = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
+ const SCCOL nColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
+
+ return SelectionForbidsPaste( nColSize, nRowSize);
+}
+
+bool ScViewData::SelectionForbidsPaste( SCCOL nSrcCols, SCROW nSrcRows )
+{
+ ScRange aSelRange( ScAddress::UNINITIALIZED );
+ ScMarkType eMarkType = GetSimpleArea( aSelRange);
+
+ if (eMarkType == SC_MARK_MULTI)
+ // Not because of DOOM.
+ return false;
+
+ if (aSelRange.aEnd.Row() - aSelRange.aStart.Row() + 1 == nSrcRows)
+ // This also covers entire col(s) copied to be pasted on entire cols.
+ return false;
+
+ if (aSelRange.aEnd.Col() - aSelRange.aStart.Col() + 1 == nSrcCols)
+ // This also covers entire row(s) copied to be pasted on entire rows.
+ return false;
+
+ return SelectionFillDOOM( aSelRange);
+}
+
+bool ScViewData::SelectionForbidsCellFill()
+{
+ ScRange aSelRange( ScAddress::UNINITIALIZED );
+ ScMarkType eMarkType = GetSimpleArea( aSelRange);
+ return eMarkType != SC_MARK_MULTI && SelectionFillDOOM( aSelRange);
+}
+
+// static
+bool ScViewData::SelectionFillDOOM( const ScRange& rRange )
+{
+ // Assume that more than 23 full columns (23M cells) will not be
+ // successful... Even with only 10 bytes per cell that would already be
+ // 230MB, formula cells would be 100 bytes and more per cell.
+ // rows * columns > 23m => rows > 23m / columns
+ // to not overflow in case number of available columns or rows would be
+ // arbitrarily increased.
+ // We could refine this and take some actual cell size into account,
+ // evaluate available memory and what not, but...
+ const sal_Int32 kMax = 23 * 1024 * 1024; // current MAXROWCOUNT1 is 1024*1024=1048576
+ return (rRange.aEnd.Row() - rRange.aStart.Row() + 1) > (kMax / (rRange.aEnd.Col() - rRange.aStart.Col() + 1));
+}
+
+void ScViewData::SetFillMode( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow )
+{
+ nFillMode = ScFillMode::FILL;
+ nFillStartX = nStartCol;
+ nFillStartY = nStartRow;
+ nFillEndX = nEndCol;
+ nFillEndY = nEndRow;
+}
+
+void ScViewData::SetDragMode( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
+ ScFillMode nMode )
+{
+ nFillMode = nMode;
+ nFillStartX = nStartCol;
+ nFillStartY = nStartRow;
+ nFillEndX = nEndCol;
+ nFillEndY = nEndRow;
+}
+
+void ScViewData::ResetFillMode()
+{
+ nFillMode = ScFillMode::NONE;
+}
+
+void ScViewData::GetFillData( SCCOL& rStartCol, SCROW& rStartRow,
+ SCCOL& rEndCol, SCROW& rEndRow )
+{
+ rStartCol = nFillStartX;
+ rStartRow = nFillStartY;
+ rEndCol = nFillEndX;
+ rEndRow = nFillEndY;
+}
+
+SCCOL ScViewData::GetOldCurX() const
+{
+ if (pThisTab->mbOldCursorValid)
+ return pThisTab->nOldCurX;
+ else
+ return pThisTab->nCurX;
+}
+
+SCROW ScViewData::GetOldCurY() const
+{
+ if (pThisTab->mbOldCursorValid)
+ return pThisTab->nOldCurY;
+ else
+ return pThisTab->nCurY;
+}
+
+void ScViewData::SetOldCursor( SCCOL nNewX, SCROW nNewY )
+{
+ pThisTab->nOldCurX = nNewX;
+ pThisTab->nOldCurY = nNewY;
+ pThisTab->mbOldCursorValid = true;
+}
+
+void ScViewData::ResetOldCursor()
+{
+ pThisTab->mbOldCursorValid = false;
+}
+
+SCCOL ScViewData::GetPosX( ScHSplitPos eWhich, SCTAB nForTab ) const
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ return 0;
+
+ if (nForTab == -1)
+ return pThisTab->nPosX[eWhich];
+
+ if (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size())))
+ return -1;
+
+ return maTabData[nForTab]->nPosX[eWhich];
+}
+
+SCROW ScViewData::GetPosY( ScVSplitPos eWhich, SCTAB nForTab ) const
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ return 0;
+
+ if (nForTab == -1)
+ return pThisTab->nPosY[eWhich];
+
+ if (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size())))
+ return -1;
+
+ return maTabData[nForTab]->nPosY[eWhich];
+}
+
+SCCOL ScViewData::GetCurXForTab( SCTAB nTabIndex ) const
+{
+ if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())) || !maTabData[nTabIndex])
+ return -1;
+
+ return maTabData[nTabIndex]->nCurX;
+}
+
+SCROW ScViewData::GetCurYForTab( SCTAB nTabIndex ) const
+{
+ if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())))
+ return -1;
+
+ return maTabData[nTabIndex]->nCurY;
+}
+
+void ScViewData::SetCurXForTab( SCCOL nNewCurX, SCTAB nTabIndex )
+{
+ if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())))
+ return;
+
+ maTabData[nTabIndex]->nCurX = nNewCurX;
+}
+
+void ScViewData::SetCurYForTab( SCCOL nNewCurY, SCTAB nTabIndex )
+{
+ if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())))
+ return;
+
+ maTabData[nTabIndex]->nCurY = nNewCurY;
+}
+
+void ScViewData::SetMaxTiledCol( SCCOL nNewMaxCol )
+{
+ nNewMaxCol = std::clamp(nNewMaxCol, SCCOL(0), mrDoc.MaxCol());
+
+ const SCTAB nTab = GetTabNo();
+ auto GetColWidthPx = [this, nTab](SCCOL nCol) {
+ const sal_uInt16 nSize = this->mrDoc.GetColWidth(nCol, nTab);
+ const tools::Long nSizePx = ScViewData::ToPixel(nSize, nPPTX);
+ return nSizePx;
+ };
+
+ tools::Long nTotalPixels = GetLOKWidthHelper().computePosition(nNewMaxCol, GetColWidthPx);
+
+ SAL_INFO("sc.lok.docsize", "ScViewData::SetMaxTiledCol: nNewMaxCol: "
+ << nNewMaxCol << ", nTotalPixels: " << nTotalPixels);
+
+ GetLOKWidthHelper().removeByIndex(pThisTab->nMaxTiledCol);
+ GetLOKWidthHelper().insert(nNewMaxCol, nTotalPixels);
+
+ pThisTab->nMaxTiledCol = nNewMaxCol;
+}
+
+void ScViewData::SetMaxTiledRow( SCROW nNewMaxRow )
+{
+ if (nNewMaxRow < 0)
+ nNewMaxRow = 0;
+ if (nNewMaxRow > MAXTILEDROW)
+ nNewMaxRow = MAXTILEDROW;
+
+ const SCTAB nTab = GetTabNo();
+ auto GetRowHeightPx = [this, nTab](SCROW nRow) {
+ const sal_uInt16 nSize = this->mrDoc.GetRowHeight(nRow, nTab);
+ const tools::Long nSizePx = ScViewData::ToPixel(nSize, nPPTY);
+ return nSizePx;
+ };
+
+ tools::Long nTotalPixels = GetLOKHeightHelper().computePosition(nNewMaxRow, GetRowHeightPx);
+
+ SAL_INFO("sc.lok.docsize", "ScViewData::SetMaxTiledRow: nNewMaxRow: "
+ << nNewMaxRow << ", nTotalPixels: " << nTotalPixels);
+
+ GetLOKHeightHelper().removeByIndex(pThisTab->nMaxTiledRow);
+ GetLOKHeightHelper().insert(nNewMaxRow, nTotalPixels);
+
+ pThisTab->nMaxTiledRow = nNewMaxRow;
+}
+
+tools::Rectangle ScViewData::GetEditArea( ScSplitPos eWhich, SCCOL nPosX, SCROW nPosY,
+ vcl::Window* pWin, const ScPatternAttr* pPattern,
+ bool bForceToTop, bool bInPrintTwips )
+{
+ Point aCellTopLeft = bInPrintTwips ?
+ GetPrintTwipsPos(nPosX, nPosY) : GetScrPos(nPosX, nPosY, eWhich, true);
+ return ScEditUtil(&mrDoc, nPosX, nPosY, nTabNo, aCellTopLeft,
+ pWin->GetOutDev(), nPPTX, nPPTY, GetZoomX(), GetZoomY(), bInPrintTwips ).
+ GetEditArea( pPattern, bForceToTop );
+}
+
+void ScViewData::SetEditEngine( ScSplitPos eWhich,
+ ScEditEngineDefaulter* pNewEngine,
+ vcl::Window* pWin, SCCOL nNewX, SCROW nNewY )
+{
+ bool bLayoutRTL = mrDoc.IsLayoutRTL(nTabNo);
+ ScHSplitPos eHWhich = WhichH(eWhich);
+ ScVSplitPos eVWhich = WhichV(eWhich);
+ bool bLOKActive = comphelper::LibreOfficeKit::isActive();
+ bool bLOKPrintTwips = bLOKActive && comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
+
+ bool bWasThere = false;
+ if (pEditView[eWhich])
+ {
+ // if the view is already there don't call anything that changes the cursor position
+ if (bEditActive[eWhich])
+ {
+ bWasThere = true;
+ }
+ else
+ {
+ lcl_LOKRemoveWindow(GetViewShell(), eWhich);
+ pEditView[eWhich]->SetEditEngine(pNewEngine);
+ }
+
+ if (pEditView[eWhich]->GetWindow() != pWin)
+ {
+ lcl_LOKRemoveWindow(GetViewShell(), eWhich);
+ pEditView[eWhich]->SetWindow(pWin);
+ OSL_FAIL("EditView Window has changed");
+ }
+ }
+ else
+ {
+ pEditView[eWhich].reset(new EditView( pNewEngine, pWin ));
+
+ if (bLOKActive)
+ {
+ // We can broadcast the view-cursor message in print-twips for all views.
+ pEditView[eWhich]->SetBroadcastLOKViewCursor(bLOKPrintTwips);
+ pEditView[eWhich]->RegisterViewShell(pView);
+ }
+ }
+
+ // add windows from other views
+ if (!bWasThere && bLOKActive)
+ {
+ ScTabViewShell* pThisViewShell = GetViewShell();
+ SCTAB nThisTabNo = GetTabNo();
+ auto lAddWindows =
+ [pThisViewShell, nThisTabNo, eWhich] (ScTabViewShell* pOtherViewShell)
+ {
+ ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
+ SCTAB nOtherTabNo = rOtherViewData.GetTabNo();
+ if (nThisTabNo == nOtherTabNo)
+ pOtherViewShell->AddWindowToForeignEditView(pThisViewShell, eWhich);
+ };
+
+ SfxLokHelper::forEachOtherView(pThisViewShell, lAddWindows);
+ }
+
+ // if view is gone then during IdleFormat sometimes a cursor is drawn
+
+ EEControlBits nEC = pNewEngine->GetControlWord();
+ pNewEngine->SetControlWord(nEC & ~EEControlBits::DOIDLEFORMAT);
+
+ EVControlBits nVC = pEditView[eWhich]->GetControlWord();
+ pEditView[eWhich]->SetControlWord(nVC & ~EVControlBits::AUTOSCROLL);
+
+ bEditActive[eWhich] = true;
+
+ const ScPatternAttr* pPattern = mrDoc.GetPattern(nNewX, nNewY, nTabNo);
+ SvxCellHorJustify eJust = pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue();
+
+ bool bBreak = ( eJust == SvxCellHorJustify::Block ) ||
+ pPattern->GetItem(ATTR_LINEBREAK).GetValue();
+
+ bool bAsianVertical = pNewEngine->IsEffectivelyVertical(); // set by InputHandler
+
+ tools::Rectangle aPixRect = ScEditUtil(&mrDoc, nNewX, nNewY, nTabNo, GetScrPos(nNewX, nNewY, eWhich),
+ pWin->GetOutDev(), nPPTX,nPPTY,GetZoomX(),GetZoomY() ).
+ GetEditArea( pPattern, true );
+
+ tools::Rectangle aPTwipsRect;
+ if (bLOKPrintTwips)
+ {
+ aPTwipsRect = ScEditUtil(&mrDoc, nNewX, nNewY, nTabNo, GetPrintTwipsPos(nNewX, nNewY),
+ pWin->GetOutDev(), nPPTX, nPPTY, GetZoomX(), GetZoomY(), true /* bInPrintTwips */).
+ GetEditArea(pPattern, true);
+ }
+
+ // when right-aligned, leave space for the cursor
+ // in vertical mode, editing is always right-aligned
+ if ( GetEditAdjust() == SvxAdjust::Right || bAsianVertical )
+ {
+ aPixRect.AdjustRight(1 );
+ if (bLOKPrintTwips)
+ aPTwipsRect.AdjustRight(o3tl::convert(1, o3tl::Length::px, o3tl::Length::twip));
+ }
+
+ if (bLOKPrintTwips)
+ {
+ if (!pEditView[eWhich]->HasLOKSpecialPositioning())
+ pEditView[eWhich]->InitLOKSpecialPositioning(MapUnit::MapTwip, aPTwipsRect, Point());
+ else
+ pEditView[eWhich]->SetLOKSpecialOutputArea(aPTwipsRect);
+ }
+
+ tools::Rectangle aOutputArea = pWin->PixelToLogic( aPixRect, GetLogicMode() );
+ pEditView[eWhich]->SetOutputArea( aOutputArea );
+
+ if ( bActive && eWhich == GetActivePart() )
+ {
+ // keep the part that has the active edit view available after
+ // switching sheets or reference input on a different part
+ eEditActivePart = eWhich;
+
+ // modify members nEditCol etc. only if also extending for needed area
+ nEditCol = nNewX;
+ nEditRow = nNewY;
+ const ScMergeAttr* pMergeAttr = &pPattern->GetItem(ATTR_MERGE);
+ nEditEndCol = nEditCol;
+ if (pMergeAttr->GetColMerge() > 1)
+ nEditEndCol += pMergeAttr->GetColMerge() - 1;
+ nEditEndRow = nEditRow;
+ if (pMergeAttr->GetRowMerge() > 1)
+ nEditEndRow += pMergeAttr->GetRowMerge() - 1;
+ nEditStartCol = nEditCol;
+
+ // For growing use only the alignment value from the attribute, numbers
+ // (existing or started) with default alignment extend to the right.
+ bool bGrowCentered = ( eJust == SvxCellHorJustify::Center );
+ bool bGrowToLeft = ( eJust == SvxCellHorJustify::Right ); // visual left
+ bool bLOKRTLInvert = (bLOKActive && bLayoutRTL);
+ if ( bAsianVertical )
+ bGrowCentered = bGrowToLeft = false; // keep old behavior for asian mode
+
+ tools::Long nSizeXPix, nSizeXPTwips = 0;
+
+ const tools::Long nGridWidthPx = pView->GetGridWidth(eHWhich);
+ const tools::Long nGridHeightPx = pView->GetGridHeight(eVWhich);
+ tools::Long nGridWidthTwips = 0, nGridHeightTwips = 0;
+ if (bLOKPrintTwips)
+ {
+ Size aGridSize(nGridWidthPx, nGridHeightPx);
+ const MapMode& rWinMapMode = GetLogicMode();
+ aGridSize = OutputDevice::LogicToLogic(
+ pWin->PixelToLogic(aGridSize, rWinMapMode),
+ rWinMapMode, MapMode(MapUnit::MapTwip));
+ nGridWidthTwips = aGridSize.Width();
+ nGridHeightTwips = aGridSize.Height();
+ }
+
+ if (bBreak && !bAsianVertical)
+ {
+ nSizeXPix = aPixRect.GetWidth(); // papersize -> no horizontal scrolling
+ if (bLOKPrintTwips)
+ nSizeXPTwips = aPTwipsRect.GetWidth();
+ }
+ else
+ {
+ OSL_ENSURE(pView,"no View for EditView");
+
+ if ( bGrowCentered )
+ {
+ // growing into both directions until one edge is reached
+ //! should be limited to whole cells in both directions
+ tools::Long nLeft = aPixRect.Left();
+ tools::Long nRight = nGridWidthPx - aPixRect.Right();
+ nSizeXPix = aPixRect.GetWidth() + 2 * std::min( nLeft, nRight );
+ if (bLOKPrintTwips)
+ {
+ tools::Long nLeftPTwips = aPTwipsRect.Left();
+ tools::Long nRightPTwips = nGridWidthTwips - aPTwipsRect.Right();
+ nSizeXPTwips = aPTwipsRect.GetWidth() + 2 * std::min(nLeftPTwips, nRightPTwips);
+ }
+ }
+ else if ( (bGrowToLeft && !bLOKRTLInvert) || (!bGrowToLeft && bLOKRTLInvert) )
+ {
+ nSizeXPix = aPixRect.Right(); // space that's available in the window when growing to the left
+ if (bLOKPrintTwips)
+ nSizeXPTwips = aPTwipsRect.Right();
+ }
+ else
+ {
+ nSizeXPix = nGridWidthPx - aPixRect.Left();
+ if (bLOKPrintTwips)
+ nSizeXPTwips = nGridWidthTwips - aPTwipsRect.Left();
+ }
+
+ if ( nSizeXPix <= 0 )
+ {
+ nSizeXPix = aPixRect.GetWidth(); // editing outside to the right of the window -> keep cell width
+ if (bLOKPrintTwips)
+ nSizeXPTwips = aPTwipsRect.GetWidth();
+ }
+ }
+ OSL_ENSURE(pView,"no View for EditView");
+ tools::Long nSizeYPix = nGridHeightPx - aPixRect.Top();
+ tools::Long nSizeYPTwips = bLOKPrintTwips ? (nGridHeightTwips - aPTwipsRect.Top()) : 0;
+
+ if ( nSizeYPix <= 0 )
+ {
+ nSizeYPix = aPixRect.GetHeight(); // editing outside below the window -> keep cell height
+ if (bLOKPrintTwips)
+ nSizeYPTwips = aPTwipsRect.GetHeight();
+ }
+
+ Size aPaperSize = pView->GetActiveWin()->PixelToLogic( Size( nSizeXPix, nSizeYPix ), GetLogicMode() );
+ Size aPaperSizePTwips(nSizeXPTwips, nSizeYPTwips);
+ if ( bBreak && !bAsianVertical && SC_MOD()->GetInputOptions().GetTextWysiwyg() )
+ {
+ // if text is formatted for printer, use the exact same paper width
+ // (and same line breaks) as for output.
+
+ Fraction aFract(1,1);
+ constexpr auto HMM_PER_TWIPS = o3tl::convert(1.0, o3tl::Length::twip, o3tl::Length::mm100);
+ tools::Rectangle aUtilRect = ScEditUtil(&mrDoc, nNewX, nNewY, nTabNo, Point(0, 0), pWin->GetOutDev(),
+ HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( pPattern, false );
+ aPaperSize.setWidth( aUtilRect.GetWidth() );
+ if (bLOKPrintTwips)
+ {
+ aPaperSizePTwips.setWidth(o3tl::convert(aUtilRect.GetWidth(), o3tl::Length::mm100, o3tl::Length::twip));
+ }
+ }
+
+ pNewEngine->SetPaperSize( aPaperSize );
+ if (bLOKPrintTwips)
+ pNewEngine->SetLOKSpecialPaperSize(aPaperSizePTwips);
+
+ // sichtbarer Ausschnitt
+ Size aPaper = pNewEngine->GetPaperSize();
+ tools::Rectangle aVis = pEditView[eWhich]->GetVisArea();
+ tools::Rectangle aVisPTwips;
+ if (bLOKPrintTwips)
+ aVisPTwips = pEditView[eWhich]->GetLOKSpecialVisArea();
+
+ tools::Long nDiff = aVis.Right() - aVis.Left();
+ tools::Long nDiffPTwips = bLOKPrintTwips ? (aVisPTwips.Right() - aVisPTwips.Left()) : 0;
+ if ( GetEditAdjust() == SvxAdjust::Right )
+ {
+ aVis.SetRight( aPaper.Width() - 1 );
+ if (bLOKPrintTwips)
+ aVisPTwips.SetRight( aPaperSizePTwips.Width() - 1 );
+ bMoveArea = !bLayoutRTL;
+ }
+ else if ( GetEditAdjust() == SvxAdjust::Center )
+ {
+ aVis.SetRight( ( aPaper.Width() - 1 + nDiff ) / 2 );
+ if (bLOKPrintTwips)
+ aVisPTwips.SetRight( ( aPaperSizePTwips.Width() - 1 + nDiffPTwips ) / 2 );
+ bMoveArea = true; // always
+ }
+ else
+ {
+ aVis.SetRight( nDiff );
+ if (bLOKPrintTwips)
+ aVisPTwips.SetRight(nDiffPTwips);
+ bMoveArea = bLayoutRTL;
+ }
+ aVis.SetLeft( aVis.Right() - nDiff );
+ if (bLOKPrintTwips)
+ aVisPTwips.SetLeft(aVisPTwips.Right() - nDiffPTwips);
+ // #i49561# Important note:
+ // The set offset of the visible area of the EditView for centered and
+ // right alignment in horizontal layout is consider by instances of
+ // class <ScEditObjectViewForwarder> in its methods <LogicToPixel(..)>
+ // and <PixelToLogic(..)>. This is needed for the correct visibility
+ // of paragraphs in edit mode at the accessibility API.
+ pEditView[eWhich]->SetVisArea(aVis);
+ if (bLOKPrintTwips)
+ pEditView[eWhich]->SetLOKSpecialVisArea(aVisPTwips);
+ // UpdateMode has been disabled in ScInputHandler::StartTable
+ // must be enabled before EditGrowY (GetTextHeight)
+ pNewEngine->SetUpdateLayout( true );
+
+ pNewEngine->SetStatusEventHdl( LINK( this, ScViewData, EditEngineHdl ) );
+
+ EditGrowY( true ); // adjust to existing text content
+ EditGrowX();
+
+ Point aDocPos = pEditView[eWhich]->GetWindowPosTopLeft(0);
+ if (aDocPos.Y() < aOutputArea.Top())
+ pEditView[eWhich]->Scroll( 0, aOutputArea.Top() - aDocPos.Y() );
+ }
+
+ // here bEditActive needs to be set already
+ // (due to Map-Mode during Paint)
+ if (!bWasThere)
+ pNewEngine->InsertView(pEditView[eWhich].get());
+
+ // background color of the cell
+ Color aBackCol = pPattern->GetItem(ATTR_BACKGROUND).GetColor();
+
+ ScModule* pScMod = SC_MOD();
+ if ( aBackCol.IsTransparent() )
+ {
+ aBackCol = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
+ }
+ pEditView[eWhich]->SetBackgroundColor( aBackCol );
+
+ pEditView[eWhich]->Invalidate(); // needed?
+ // needed, if position changed
+}
+
+IMPL_LINK( ScViewData, EditEngineHdl, EditStatus&, rStatus, void )
+{
+ EditStatusFlags nStatus = rStatus.GetStatusWord();
+ if (nStatus & (EditStatusFlags::HSCROLL | EditStatusFlags::TextHeightChanged | EditStatusFlags::TEXTWIDTHCHANGED | EditStatusFlags::CURSOROUT))
+ {
+ EditGrowY();
+ EditGrowX();
+
+ if (nStatus & EditStatusFlags::CURSOROUT)
+ {
+ ScSplitPos eWhich = GetActivePart();
+ if (pEditView[eWhich])
+ pEditView[eWhich]->ShowCursor(false);
+ }
+ }
+}
+
+void ScViewData::EditGrowX()
+{
+ // It is insane to call EditGrowX while the output area is already growing.
+ // That could occur because of the call to SetDefaultItem later.
+ // We end up with wrong start/end edit columns and the changes
+ // to the output area performed by the inner call to this method are
+ // useless since they are discarded by the outer call.
+ if (bGrowing)
+ return;
+
+ comphelper::FlagRestorationGuard aFlagGuard(bGrowing, true);
+
+ bool bLOKActive = comphelper::LibreOfficeKit::isActive();
+ bool bLOKPrintTwips = bLOKActive && comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
+
+ ScDocument& rLocalDoc = GetDocument();
+
+ ScSplitPos eWhich = GetActivePart();
+ ScHSplitPos eHWhich = WhichH(eWhich);
+ EditView* pCurView = pEditView[eWhich].get();
+
+ if ( !pCurView || !bEditActive[eWhich])
+ return;
+
+ bool bLayoutRTL = rLocalDoc.IsLayoutRTL( nTabNo );
+
+ ScEditEngineDefaulter* pEngine =
+ static_cast<ScEditEngineDefaulter*>( pCurView->GetEditEngine() );
+ vcl::Window* pWin = pCurView->GetWindow();
+
+ // Get the left- and right-most column positions.
+ SCCOL nLeft = GetPosX(eHWhich);
+ SCCOL nRight = nLeft + VisibleCellsX(eHWhich);
+
+ Size aSize = pEngine->GetPaperSize();
+ Size aSizePTwips;
+ if (bLOKPrintTwips)
+ aSizePTwips = pEngine->GetLOKSpecialPaperSize();
+
+ tools::Rectangle aArea = pCurView->GetOutputArea();
+ tools::Rectangle aAreaPTwips;
+ if (bLOKPrintTwips)
+ aAreaPTwips = pCurView->GetLOKSpecialOutputArea();
+
+ tools::Long nOldRight = aArea.Right();
+
+ // Margin is already included in the original width.
+ tools::Long nTextWidth = pEngine->CalcTextWidth();
+
+ bool bChanged = false;
+ bool bAsianVertical = pEngine->IsEffectivelyVertical();
+
+ // get bGrow... variables the same way as in SetEditEngine
+ const ScPatternAttr* pPattern = rLocalDoc.GetPattern( nEditCol, nEditRow, nTabNo );
+ SvxCellHorJustify eJust = pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue();
+ bool bGrowCentered = ( eJust == SvxCellHorJustify::Center );
+ bool bGrowToLeft = ( eJust == SvxCellHorJustify::Right ); // visual left
+ bool bGrowBackwards = bGrowToLeft; // logical left
+ if ( bLayoutRTL )
+ bGrowBackwards = !bGrowBackwards; // invert on RTL sheet
+ if ( bAsianVertical )
+ bGrowCentered = bGrowToLeft = bGrowBackwards = false; // keep old behavior for asian mode
+
+ bool bUnevenGrow = false;
+ if ( bGrowCentered )
+ {
+ while (aArea.GetWidth() + 0 < nTextWidth && ( nEditStartCol > nLeft || nEditEndCol < nRight ) )
+ {
+ tools::Long nLogicLeft = 0;
+ tools::Long nLogicLeftPTwips = 0;
+ if ( nEditStartCol > nLeft )
+ {
+ --nEditStartCol;
+ tools::Long nColWidth = rLocalDoc.GetColWidth( nEditStartCol, nTabNo );
+ tools::Long nLeftPix = ToPixel( nColWidth, nPPTX );
+ nLogicLeft = pWin->PixelToLogic(Size(nLeftPix,0)).Width();
+ if (bLOKPrintTwips)
+ nLogicLeftPTwips = nColWidth;
+ }
+ tools::Long nLogicRight = 0;
+ tools::Long nLogicRightPTwips = 0;
+ if ( nEditEndCol < nRight )
+ {
+ ++nEditEndCol;
+ tools::Long nColWidth = rLocalDoc.GetColWidth( nEditEndCol, nTabNo );
+ tools::Long nRightPix = ToPixel( nColWidth, nPPTX );
+ nLogicRight = pWin->PixelToLogic(Size(nRightPix,0)).Width();
+ if (bLOKPrintTwips)
+ nLogicRightPTwips = nColWidth;
+ }
+
+ aArea.AdjustLeft( -((bLayoutRTL && !bLOKActive) ? nLogicRight : nLogicLeft) );
+ aArea.AdjustRight((bLayoutRTL && !bLOKActive) ? nLogicLeft : nLogicRight );
+ if (bLOKPrintTwips)
+ {
+ aAreaPTwips.AdjustLeft(-nLogicLeftPTwips);
+ aAreaPTwips.AdjustRight(nLogicRightPTwips);
+ }
+
+ if ( aArea.Right() > aArea.Left() + aSize.Width() - 1 )
+ {
+ tools::Long nCenter = ( aArea.Left() + aArea.Right() ) / 2;
+ tools::Long nHalf = aSize.Width() / 2;
+ aArea.SetLeft( nCenter - nHalf + 1 );
+ aArea.SetRight( nCenter + aSize.Width() - nHalf - 1 );
+
+ if (bLOKPrintTwips)
+ {
+ tools::Long nCenterPTwips = ( aAreaPTwips.Left() + aAreaPTwips.Right() ) / 2;
+ tools::Long nHalfPTwips = aSizePTwips.Width() / 2;
+ aAreaPTwips.SetLeft( nCenterPTwips - nHalfPTwips + 1 );
+ aAreaPTwips.SetRight( nCenterPTwips + aSizePTwips.Width() - nHalfPTwips - 1 );
+ }
+ }
+
+ bChanged = true;
+ if ( nLogicLeft != nLogicRight )
+ bUnevenGrow = true;
+ }
+ }
+ else if ( bGrowBackwards )
+ {
+ while (aArea.GetWidth() + 0 < nTextWidth && nEditStartCol > nLeft)
+ {
+ --nEditStartCol;
+ tools::Long nColWidth = rLocalDoc.GetColWidth( nEditStartCol, nTabNo );
+ tools::Long nPix = ToPixel( nColWidth, nPPTX );
+ tools::Long nLogicWidth = pWin->PixelToLogic(Size(nPix,0)).Width();
+ tools::Long& nLogicWidthPTwips = nColWidth;
+
+ if ( !bLayoutRTL || bLOKActive )
+ {
+ aArea.AdjustLeft( -nLogicWidth );
+ if (bLOKPrintTwips)
+ aAreaPTwips.AdjustLeft( -nLogicWidthPTwips );
+ }
+ else
+ {
+ aArea.AdjustRight(nLogicWidth );
+ if (bLOKPrintTwips)
+ aAreaPTwips.AdjustRight(nLogicWidthPTwips);
+ }
+
+ if ( aArea.Right() > aArea.Left() + aSize.Width() - 1 )
+ {
+ if ( !bLayoutRTL || bLOKActive )
+ {
+ aArea.SetLeft( aArea.Right() - aSize.Width() + 1 );
+ if (bLOKPrintTwips)
+ aAreaPTwips.SetLeft( aAreaPTwips.Right() - aSizePTwips.Width() + 1 );
+ }
+ else
+ {
+ aArea.SetRight( aArea.Left() + aSize.Width() - 1 );
+ if (bLOKPrintTwips)
+ aAreaPTwips.SetRight( aAreaPTwips.Left() + aSizePTwips.Width() - 1 );
+ }
+ }
+
+ bChanged = true;
+ }
+ }
+ else
+ {
+ while (aArea.GetWidth() + 0 < nTextWidth && nEditEndCol < nRight)
+ {
+ ++nEditEndCol;
+ tools::Long nColWidth = rLocalDoc.GetColWidth( nEditEndCol, nTabNo );
+ tools::Long nPix = ToPixel( nColWidth, nPPTX );
+ tools::Long nLogicWidth = pWin->PixelToLogic(Size(nPix,0)).Width();
+ tools::Long& nLogicWidthPTwips = nColWidth;
+ if ( bLayoutRTL && !bLOKActive )
+ {
+ aArea.AdjustLeft( -nLogicWidth );
+ }
+ else
+ {
+ aArea.AdjustRight(nLogicWidth );
+ if (bLOKPrintTwips)
+ aAreaPTwips.AdjustRight(nLogicWidthPTwips);
+ }
+
+ if ( aArea.Right() > aArea.Left() + aSize.Width() - 1 )
+ {
+ if ( bLayoutRTL && !bLOKActive )
+ {
+ aArea.SetLeft( aArea.Right() - aSize.Width() + 1 );
+ }
+ else
+ {
+ aArea.SetRight( aArea.Left() + aSize.Width() - 1 );
+ if (bLOKPrintTwips)
+ aAreaPTwips.SetRight( aAreaPTwips.Left() + aSizePTwips.Width() - 1 );
+ }
+ }
+
+ bChanged = true;
+ }
+ }
+
+ if (!bChanged)
+ return;
+
+ if ( bMoveArea || bGrowCentered || bGrowBackwards || bLayoutRTL )
+ {
+ tools::Rectangle aVis = pCurView->GetVisArea();
+ tools::Rectangle aVisPTwips;
+ if (bLOKPrintTwips)
+ aVisPTwips = pCurView->GetLOKSpecialVisArea();
+
+ if ( bGrowCentered )
+ {
+ // switch to center-aligned (undo?) and reset VisArea to center
+
+ pEngine->SetDefaultItem( SvxAdjustItem( SvxAdjust::Center, EE_PARA_JUST ) );
+
+ tools::Long nCenter = aSize.Width() / 2;
+ tools::Long nVisSize = aArea.GetWidth();
+ aVis.SetLeft( nCenter - nVisSize / 2 );
+ aVis.SetRight( aVis.Left() + nVisSize - 1 );
+
+ if (bLOKPrintTwips)
+ {
+ tools::Long nCenterPTwips = aSizePTwips.Width() / 2;
+ tools::Long nVisSizePTwips = aAreaPTwips.GetWidth();
+ aVisPTwips.SetLeft( nCenterPTwips - nVisSizePTwips / 2 );
+ aVisPTwips.SetRight( aVisPTwips.Left() + nVisSizePTwips - 1 );
+ }
+ }
+ else if ( bGrowToLeft )
+ {
+ // switch to right-aligned (undo?) and reset VisArea to the right
+
+ pEngine->SetDefaultItem( SvxAdjustItem( SvxAdjust::Right, EE_PARA_JUST ) );
+
+ aVis.SetRight( aSize.Width() - 1 );
+ aVis.SetLeft( aSize.Width() - aArea.GetWidth() ); // with the new, increased area
+
+ if (bLOKPrintTwips)
+ {
+ aVisPTwips.SetRight( aSizePTwips.Width() - 1 );
+ aVisPTwips.SetLeft( aSizePTwips.Width() - aAreaPTwips.GetWidth() ); // with the new, increased area
+ }
+ }
+ else
+ {
+ // switch to left-aligned (undo?) and reset VisArea to the left
+
+ pEngine->SetDefaultItem( SvxAdjustItem( SvxAdjust::Left, EE_PARA_JUST ) );
+
+ tools::Long nMove = aVis.Left();
+ aVis.SetLeft( 0 );
+ aVis.AdjustRight( -nMove );
+
+ if (bLOKPrintTwips)
+ {
+ tools::Long nMovePTwips = aVisPTwips.Left();
+ aVisPTwips.SetLeft( 0 );
+ aVisPTwips.AdjustRight( -nMovePTwips );
+ }
+ }
+
+ pCurView->SetVisArea( aVis );
+ if (bLOKPrintTwips)
+ pCurView->SetLOKSpecialVisArea( aVisPTwips );
+
+ bMoveArea = false;
+ }
+
+ if (bLOKPrintTwips)
+ pCurView->SetLOKSpecialOutputArea(aAreaPTwips);
+
+ pCurView->SetOutputArea(aArea);
+
+ // In vertical mode, the whole text is moved to the next cell (right-aligned),
+ // so everything must be repainted. Otherwise, paint only the new area.
+ // If growing in centered alignment, if the cells left and right have different sizes,
+ // the whole text will move, and may not even obscure all of the original display.
+ if ( bUnevenGrow )
+ {
+ aArea.SetLeft( pWin->PixelToLogic( Point(0,0) ).X() );
+ aArea.SetRight( pWin->PixelToLogic( aScrSize ).Width() );
+ }
+ else if ( !bAsianVertical && !bGrowToLeft && !bGrowCentered )
+ aArea.SetLeft( nOldRight );
+ pWin->Invalidate(aArea);
+
+ // invalidate other views
+ pCurView->InvalidateOtherViewWindows(aArea);
+}
+
+void ScViewData::EditGrowY( bool bInitial )
+{
+ if (bGrowing)
+ return;
+
+ comphelper::FlagRestorationGuard aFlagGuard(bGrowing, true);
+
+ bool bLOKActive = comphelper::LibreOfficeKit::isActive();
+ bool bLOKPrintTwips = bLOKActive && comphelper::LibreOfficeKit::isCompatFlagSet(
+ comphelper::LibreOfficeKit::Compat::scPrintTwipsMsgs);
+
+ ScSplitPos eWhich = GetActivePart();
+ ScVSplitPos eVWhich = WhichV(eWhich);
+ EditView* pCurView = pEditView[eWhich].get();
+
+ if ( !pCurView || !bEditActive[eWhich])
+ return;
+
+ EVControlBits nControl = pEditView[eWhich]->GetControlWord();
+ if ( nControl & EVControlBits::AUTOSCROLL )
+ {
+ // if end of screen had already been reached and scrolling enabled,
+ // don't further try to grow the edit area
+
+ pCurView->SetOutputArea( pCurView->GetOutputArea() ); // re-align to pixels
+ return;
+ }
+
+ EditEngine* pEngine = pCurView->GetEditEngine();
+ vcl::Window* pWin = pCurView->GetWindow();
+
+ SCROW nBottom = GetPosY(eVWhich) + VisibleCellsY(eVWhich);
+
+ Size aSize = pEngine->GetPaperSize();
+ Size aSizePTwips;
+ tools::Rectangle aArea = pCurView->GetOutputArea();
+ tools::Rectangle aAreaPTwips;
+
+ if (bLOKPrintTwips)
+ {
+ aSizePTwips = pEngine->GetLOKSpecialPaperSize();
+ aAreaPTwips = pCurView->GetLOKSpecialOutputArea();
+ }
+
+ tools::Long nOldBottom = aArea.Bottom();
+ tools::Long nTextHeight = pEngine->GetTextHeight();
+
+ // When editing a formula in a cell with optimal height, allow a larger portion
+ // to be clipped before extending to following rows, to avoid obscuring cells for
+ // reference input (next row is likely to be useful in formulas).
+ tools::Long nAllowedExtra = SC_GROWY_SMALL_EXTRA;
+ if (nEditEndRow == nEditRow && !(mrDoc.GetRowFlags(nEditRow, nTabNo) & CRFlags::ManualSize) &&
+ pEngine->GetParagraphCount() <= 1 )
+ {
+ // If the (only) paragraph starts with a '=', it's a formula.
+ // If this is the initial call and the text is empty, allow the larger value, too,
+ // because this occurs in the normal progress of editing a formula.
+ // Subsequent calls with empty text might involve changed attributes (including
+ // font height), so they are treated like normal text.
+ OUString aText = pEngine->GetText( 0 );
+ if ( ( aText.isEmpty() && bInitial ) || aText.startsWith("=") )
+ nAllowedExtra = SC_GROWY_BIG_EXTRA;
+ }
+
+ bool bChanged = false;
+ bool bMaxReached = false;
+ while (aArea.GetHeight() + nAllowedExtra < nTextHeight && nEditEndRow < nBottom && !bMaxReached)
+ {
+ ++nEditEndRow;
+ ScDocument& rLocalDoc = GetDocument();
+ tools::Long nRowHeight = rLocalDoc.GetRowHeight( nEditEndRow, nTabNo );
+ tools::Long nPix = ToPixel( nRowHeight, nPPTY );
+ aArea.AdjustBottom(pWin->PixelToLogic(Size(0,nPix)).Height() );
+ if (bLOKPrintTwips)
+ aAreaPTwips.AdjustBottom(nRowHeight);
+
+ if ( aArea.Bottom() > aArea.Top() + aSize.Height() - 1 )
+ {
+ aArea.SetBottom( aArea.Top() + aSize.Height() - 1 );
+ if (bLOKPrintTwips)
+ aAreaPTwips.SetBottom( aAreaPTwips.Top() + aSizePTwips.Height() - 1 );
+ bMaxReached = true; // don't occupy more cells beyond paper size
+ }
+
+ bChanged = true;
+ nAllowedExtra = SC_GROWY_SMALL_EXTRA; // larger value is only for first row
+ }
+
+ if (!bChanged)
+ return;
+
+ if (bLOKPrintTwips)
+ pCurView->SetLOKSpecialOutputArea(aAreaPTwips);
+
+ pCurView->SetOutputArea(aArea);
+
+ if (nEditEndRow >= nBottom || bMaxReached)
+ {
+ if (!(nControl & EVControlBits::AUTOSCROLL))
+ pCurView->SetControlWord( nControl | EVControlBits::AUTOSCROLL );
+ }
+
+ aArea.SetTop( nOldBottom );
+ pWin->Invalidate(aArea);
+
+ // invalidate other views
+ pCurView->InvalidateOtherViewWindows(aArea);
+}
+
+void ScViewData::ResetEditView()
+{
+ EditEngine* pEngine = nullptr;
+ for (sal_uInt16 i=0; i<4; i++)
+ if (pEditView[i])
+ {
+ if (bEditActive[i])
+ {
+ lcl_LOKRemoveWindow(GetViewShell(), static_cast<ScSplitPos>(i));
+ pEngine = pEditView[i]->GetEditEngine();
+ pEngine->RemoveView(pEditView[i].get());
+ pEditView[i]->SetOutputArea( tools::Rectangle() );
+ }
+ bEditActive[i] = false;
+ }
+
+ if (pEngine)
+ pEngine->SetStatusEventHdl( Link<EditStatus&,void>() );
+}
+
+void ScViewData::KillEditView()
+{
+ EditEngine* pEngine = nullptr;
+ for (sal_uInt16 i=0; i<4; i++)
+ if (pEditView[i])
+ {
+ if (bEditActive[i])
+ {
+ pEngine = pEditView[i]->GetEditEngine();
+ if (pEngine)
+ pEngine->RemoveView(pEditView[i].get());
+ }
+ pEditView[i].reset();
+ }
+}
+
+void ScViewData::GetEditView( ScSplitPos eWhich, EditView*& rViewPtr, SCCOL& rCol, SCROW& rRow )
+{
+ rViewPtr = pEditView[eWhich].get();
+ rCol = nEditCol;
+ rRow = nEditRow;
+}
+
+void ScViewData::CreateTabData( SCTAB nNewTab )
+{
+ EnsureTabDataSize(nNewTab + 1);
+
+ if (!maTabData[nNewTab])
+ {
+ maTabData[nNewTab].reset(new ScViewDataTable(&mrDoc));
+
+ maTabData[nNewTab]->eZoomType = eDefZoomType;
+ maTabData[nNewTab]->aZoomX = aDefZoomX;
+ maTabData[nNewTab]->aZoomY = aDefZoomY;
+ maTabData[nNewTab]->aPageZoomX = aDefPageZoomX;
+ maTabData[nNewTab]->aPageZoomY = aDefPageZoomY;
+ }
+}
+
+void ScViewData::CreateSelectedTabData()
+{
+ for (const auto& rTab : maMarkData)
+ CreateTabData(rTab);
+}
+
+void ScViewData::EnsureTabDataSize(size_t nSize)
+{
+ if (nSize > maTabData.size())
+ maTabData.resize(nSize);
+}
+
+void ScViewData::SetTabNo( SCTAB nNewTab )
+{
+ if (!ValidTab(nNewTab))
+ {
+ OSL_FAIL("wrong sheet number");
+ return;
+ }
+
+ nTabNo = nNewTab;
+ CreateTabData(nTabNo);
+ pThisTab = maTabData[nTabNo].get();
+
+ CalcPPT(); // for common column width correction
+ RecalcPixPos(); //! not always needed!
+}
+
+ScPositionHelper* ScViewData::GetLOKWidthHelper(SCTAB nTabIndex)
+{
+ if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())) ||
+ !maTabData[nTabIndex])
+ {
+ return nullptr;
+ }
+ return &(maTabData[nTabIndex]->aWidthHelper);
+}
+
+ScPositionHelper* ScViewData::GetLOKHeightHelper(SCTAB nTabIndex)
+{
+ if (!ValidTab(nTabIndex) || (nTabIndex >= static_cast<SCTAB>(maTabData.size())) ||
+ !maTabData[nTabIndex])
+ {
+ return nullptr;
+ }
+ return &(maTabData[nTabIndex]->aHeightHelper);
+}
+
+void ScViewData::SetActivePart( ScSplitPos eNewActive )
+{
+ pThisTab->eWhichActive = eNewActive;
+
+ // Let's hope we find the culprit for tdf#117093
+ // Don't sanitize the real value (yet?) because this function might be
+ // called before setting the then corresponding split modes. For which in
+ // fact then the order should be changed.
+ assert(eNewActive == pThisTab->SanitizeWhichActive());
+}
+
+Point ScViewData::GetScrPos( SCCOL nWhereX, SCROW nWhereY, ScHSplitPos eWhich ) const
+{
+ OSL_ENSURE( eWhich==SC_SPLIT_LEFT || eWhich==SC_SPLIT_RIGHT, "wrong position" );
+ ScSplitPos ePos = ( eWhich == SC_SPLIT_LEFT ) ? SC_SPLIT_BOTTOMLEFT : SC_SPLIT_BOTTOMRIGHT;
+ return GetScrPos( nWhereX, nWhereY, ePos );
+}
+
+Point ScViewData::GetScrPos( SCCOL nWhereX, SCROW nWhereY, ScVSplitPos eWhich ) const
+{
+ OSL_ENSURE( eWhich==SC_SPLIT_TOP || eWhich==SC_SPLIT_BOTTOM, "wrong position" );
+ ScSplitPos ePos = ( eWhich == SC_SPLIT_TOP ) ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT;
+ return GetScrPos( nWhereX, nWhereY, ePos );
+}
+
+Point ScViewData::GetScrPos( SCCOL nWhereX, SCROW nWhereY, ScSplitPos eWhich,
+ bool bAllowNeg, SCTAB nForTab ) const
+{
+ ScHSplitPos eWhichX = SC_SPLIT_LEFT;
+ ScVSplitPos eWhichY = SC_SPLIT_BOTTOM;
+ switch( eWhich )
+ {
+ case SC_SPLIT_TOPLEFT:
+ eWhichX = SC_SPLIT_LEFT;
+ eWhichY = SC_SPLIT_TOP;
+ break;
+ case SC_SPLIT_TOPRIGHT:
+ eWhichX = SC_SPLIT_RIGHT;
+ eWhichY = SC_SPLIT_TOP;
+ break;
+ case SC_SPLIT_BOTTOMLEFT:
+ eWhichX = SC_SPLIT_LEFT;
+ eWhichY = SC_SPLIT_BOTTOM;
+ break;
+ case SC_SPLIT_BOTTOMRIGHT:
+ eWhichX = SC_SPLIT_RIGHT;
+ eWhichY = SC_SPLIT_BOTTOM;
+ break;
+ }
+
+ if (nForTab == -1)
+ nForTab = nTabNo;
+ bool bForCurTab = (nForTab == nTabNo);
+ if (!bForCurTab && (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size()))))
+ {
+ SAL_WARN("sc.viewdata", "ScViewData::GetScrPos : invalid nForTab = " << nForTab);
+ nForTab = nTabNo;
+ bForCurTab = true;
+ }
+
+ ScViewDataTable* pViewTable = bForCurTab ? pThisTab : maTabData[nForTab].get();
+
+ if (pView)
+ {
+ const_cast<ScViewData*>(this)->aScrSize.setWidth( pView->GetGridWidth(eWhichX) );
+ const_cast<ScViewData*>(this)->aScrSize.setHeight( pView->GetGridHeight(eWhichY) );
+ }
+
+ sal_uInt16 nTSize;
+ bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
+
+ SCCOL nPosX = GetPosX(eWhichX, nForTab);
+ tools::Long nScrPosX = 0;
+
+ if (bAllowNeg || nWhereX >= nPosX)
+ {
+ SCROW nStartPosX = nPosX;
+ if (bIsTiledRendering)
+ {
+ OSL_ENSURE(nPosX == 0, "Unsupported case.");
+ const auto& rNearest = pViewTable->aWidthHelper.getNearestByIndex(nWhereX - 1);
+ nStartPosX = rNearest.first + 1;
+ nScrPosX = rNearest.second;
+ }
+
+ if (nWhereX >= nStartPosX)
+ {
+ for (SCCOL nX = nStartPosX; nX < nWhereX && (bAllowNeg || bIsTiledRendering || nScrPosX <= aScrSize.Width()); nX++)
+ {
+ if (nX > mrDoc.MaxCol())
+ nScrPosX = 0x7FFFFFFF;
+ else
+ {
+ nTSize = mrDoc.GetColWidth(nX, nForTab);
+ if (nTSize)
+ {
+ tools::Long nSizeXPix = ToPixel( nTSize, nPPTX );
+ nScrPosX += nSizeXPix;
+ }
+ else
+ { // If the width is zero, the column is possibly hidden, skips groups of such columns.
+ SCCOL lastHidden = -1;
+ if(mrDoc.ColHidden(nX, nForTab, nullptr, &lastHidden) && lastHidden > nX)
+ nX = lastHidden - 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (SCCOL nX = nStartPosX; nX > nWhereX;)
+ {
+ --nX;
+ nTSize = mrDoc.GetColWidth(nX, nForTab);
+ if (nTSize)
+ {
+ tools::Long nSizeXPix = ToPixel( nTSize, nPPTX );
+ nScrPosX -= nSizeXPix;
+ }
+ else
+ { // If the width is zero, the column is possibly hidden, skips groups of such columns.
+ SCCOL firstHidden = -1;
+ if(mrDoc.ColHidden(nX, nForTab, &firstHidden, nullptr) && firstHidden >= 0)
+ nX = firstHidden;
+ }
+ }
+ }
+
+ }
+
+
+ SCROW nPosY = GetPosY(eWhichY, nForTab);
+ tools::Long nScrPosY = 0;
+
+ if (bAllowNeg || nWhereY >= nPosY)
+ {
+ SCROW nStartPosY = nPosY;
+ if (bIsTiledRendering)
+ {
+ OSL_ENSURE(nPosY == 0, "Unsupported case.");
+ const auto& rNearest = pViewTable->aHeightHelper.getNearestByIndex(nWhereY - 1);
+ nStartPosY = rNearest.first + 1;
+ nScrPosY = rNearest.second;
+ }
+
+ if (nWhereY >= nStartPosY)
+ {
+ for (SCROW nY = nStartPosY; nY < nWhereY && (bAllowNeg || bIsTiledRendering || nScrPosY <= aScrSize.Height()); nY++)
+ {
+ if ( nY > mrDoc.MaxRow() )
+ nScrPosY = 0x7FFFFFFF;
+ else
+ {
+ nTSize = mrDoc.GetRowHeight( nY, nTabNo );
+ if (nTSize)
+ {
+ tools::Long nSizeYPix = ToPixel( nTSize, nPPTY );
+ nScrPosY += nSizeYPix;
+ }
+ else if ( nY < mrDoc.MaxRow() )
+ {
+ // skip multiple hidden rows (forward only for now)
+ SCROW nNext = mrDoc.FirstVisibleRow(nY + 1, mrDoc.MaxRow(), nTabNo);
+ if ( nNext > mrDoc.MaxRow() )
+ nY = mrDoc.MaxRow();
+ else
+ nY = nNext - 1; // +=nDir advances to next visible row
+ }
+ }
+ }
+ }
+ else
+ {
+ for (SCROW nY = nStartPosY; nY > nWhereY;)
+ {
+ --nY;
+ nTSize = mrDoc.GetRowHeight(nY, nForTab);
+ if (nTSize)
+ {
+ tools::Long nSizeYPix = ToPixel( nTSize, nPPTY );
+ nScrPosY -= nSizeYPix;
+ }
+ else
+ { // If the height is zero, the row is possibly hidden, skips groups of such rows.
+ SCROW firstHidden = -1;
+ if(mrDoc.RowHidden(nY, nForTab, &firstHidden, nullptr) && firstHidden >= 0)
+ nY = firstHidden;
+ }
+ }
+ }
+ }
+
+ if (mrDoc.IsLayoutRTL(nForTab) && !bIsTiledRendering)
+ {
+ // mirror horizontal position
+ nScrPosX = aScrSize.Width() - 1 - nScrPosX;
+ }
+
+ return Point( nScrPosX, nScrPosY );
+}
+
+Point ScViewData::GetPrintTwipsPos(SCCOL nCol, SCROW nRow) const
+{
+ // hidden ones are given 0 sizes by these by default.
+ // TODO: rewrite this to loop over spans (matters for jumbosheets).
+ tools::Long nPosX = nCol ? mrDoc.GetColWidth(0, nCol - 1, nTabNo) : 0;
+ // This is now fast as it loops over spans.
+ tools::Long nPosY = nRow ? mrDoc.GetRowHeight(0, nRow - 1, nTabNo) : 0;
+ // TODO: adjust for RTL layout case.
+
+ return Point(nPosX, nPosY);
+}
+
+Point ScViewData::GetPrintTwipsPosFromTileTwips(const Point& rTileTwipsPos) const
+{
+ const tools::Long nPixelX = static_cast<tools::Long>(rTileTwipsPos.X() * nPPTX);
+ const tools::Long nPixelY = static_cast<tools::Long>(rTileTwipsPos.Y() * nPPTY);
+ SCCOL nCol = 0;
+ SCROW nRow = 0;
+
+ // The following call (with bTestMerge = false) will not modify any members.
+ const_cast<ScViewData*>(this)->GetPosFromPixel(nPixelX, nPixelY, SC_SPLIT_TOPLEFT, nCol, nRow, false /* bTestMerge */);
+ const Point aPixCellPos = GetScrPos(nCol, nRow, SC_SPLIT_TOPLEFT, true /* bAllowNeg */);
+ const Point aTileTwipsCellPos(aPixCellPos.X() / nPPTX, aPixCellPos.Y() / nPPTY);
+ const Point aPrintTwipsCellPos = GetPrintTwipsPos(nCol, nRow);
+ return aPrintTwipsCellPos + (rTileTwipsPos - aTileTwipsCellPos);
+}
+
+OString ScViewData::describeCellCursorAt(SCCOL nX, SCROW nY, bool bPixelAligned) const
+{
+ const bool bPosSizeInPixels = bPixelAligned;
+ Point aCellPos = bPosSizeInPixels ? GetScrPos( nX, nY, SC_SPLIT_BOTTOMRIGHT, true ) :
+ GetPrintTwipsPos(nX, nY);
+
+ tools::Long nSizeX;
+ tools::Long nSizeY;
+ if (bPosSizeInPixels)
+ GetMergeSizePixel( nX, nY, nSizeX, nSizeY );
+ else
+ GetMergeSizePrintTwips(nX, nY, nSizeX, nSizeY);
+
+ std::stringstream ss;
+ if (bPosSizeInPixels)
+ {
+ double fPPTX = GetPPTX();
+ double fPPTY = GetPPTY();
+
+ // make it a slim cell cursor, but not empty
+ if (nSizeX == 0)
+ nSizeX = 1;
+
+ if (nSizeY == 0)
+ nSizeY = 1;
+
+ tools::Long nPosXTw = rtl::math::round(aCellPos.getX() / fPPTX);
+ tools::Long nPosYTw = rtl::math::round(aCellPos.getY() / fPPTY);
+ // look at Rectangle( const Point& rLT, const Size& rSize ) for the '- 1'
+ tools::Long nSizeXTw = rtl::math::round(nSizeX / fPPTX) - 1;
+ tools::Long nSizeYTw = rtl::math::round(nSizeY / fPPTY) - 1;
+
+ ss << nPosXTw << ", " << nPosYTw << ", " << nSizeXTw << ", " << nSizeYTw << ", "
+ << nX << ", " << nY;
+ }
+ else
+ {
+ // look at Rectangle( const Point& rLT, const Size& rSize ) for the decrement.
+ if (nSizeX)
+ --nSizeX;
+ if (nSizeY)
+ --nSizeY;
+ ss << aCellPos.getX() << ", " << aCellPos.getY()
+ << ", " << nSizeX << ", " << nSizeY << ", "
+ << nX << ", " << nY;
+ }
+
+ return ss.str().c_str();
+}
+
+// Number of cells on a screen
+SCCOL ScViewData::CellsAtX( SCCOL nPosX, SCCOL nDir, ScHSplitPos eWhichX, sal_uInt16 nScrSizeX ) const
+{
+ OSL_ENSURE( nDir==1 || nDir==-1, "wrong CellsAt call" );
+
+ if (pView)
+ const_cast<ScViewData*>(this)->aScrSize.setWidth( pView->GetGridWidth(eWhichX) );
+
+ SCCOL nX;
+ sal_uInt16 nScrPosX = 0;
+ if (nScrSizeX == SC_SIZE_NONE) nScrSizeX = static_cast<sal_uInt16>(aScrSize.Width());
+
+ if (nDir==1)
+ nX = nPosX; // forwards
+ else
+ nX = nPosX-1; // backwards
+
+ bool bOut = false;
+ for ( ; nScrPosX<=nScrSizeX && !bOut; nX = sal::static_int_cast<SCCOL>(nX + nDir) )
+ {
+ SCCOL nColNo = nX;
+ if (nColNo < 0 || nColNo > mrDoc.MaxCol())
+ bOut = true;
+ else
+ {
+ sal_uInt16 nTSize = mrDoc.GetColWidth(nColNo, nTabNo);
+ if (nTSize)
+ {
+ tools::Long nSizeXPix = ToPixel( nTSize, nPPTX );
+ nScrPosX = sal::static_int_cast<sal_uInt16>( nScrPosX + static_cast<sal_uInt16>(nSizeXPix) );
+ }
+ }
+ }
+
+ if (nDir==1)
+ nX = sal::static_int_cast<SCCOL>( nX - nPosX );
+ else
+ nX = (nPosX-1)-nX;
+
+ if (nX>0) --nX;
+ return nX;
+}
+
+SCROW ScViewData::CellsAtY( SCROW nPosY, SCROW nDir, ScVSplitPos eWhichY, sal_uInt16 nScrSizeY ) const
+{
+ OSL_ENSURE( nDir==1 || nDir==-1, "wrong CellsAt call" );
+
+ if (pView)
+ const_cast<ScViewData*>(this)->aScrSize.setHeight( pView->GetGridHeight(eWhichY) );
+
+ if (nScrSizeY == SC_SIZE_NONE) nScrSizeY = static_cast<sal_uInt16>(aScrSize.Height());
+
+ SCROW nY;
+
+ if (nDir==1)
+ {
+ // forward
+ nY = nPosY;
+ tools::Long nScrPosY = 0;
+ AddPixelsWhile(nScrPosY, nScrSizeY, nY, mrDoc.MaxRow(), nPPTY, &mrDoc, nTabNo);
+ // Original loop ended on last evaluated +1 or if that was MaxRow even on MaxRow+2.
+ nY += (nY == mrDoc.MaxRow() ? 2 : 1);
+ nY -= nPosY;
+ }
+ else
+ {
+ // backward
+ nY = nPosY-1;
+ tools::Long nScrPosY = 0;
+ AddPixelsWhileBackward(nScrPosY, nScrSizeY, nY, 0, nPPTY, &mrDoc, nTabNo);
+ // Original loop ended on last evaluated -1 or if that was 0 even on -2.
+ nY -= (nY == 0 ? 2 : 1);
+ nY = (nPosY-1)-nY;
+ }
+
+ if (nY>0) --nY;
+ return nY;
+}
+
+SCCOL ScViewData::VisibleCellsX( ScHSplitPos eWhichX ) const
+{
+ return CellsAtX( GetPosX( eWhichX ), 1, eWhichX );
+}
+
+SCROW ScViewData::VisibleCellsY( ScVSplitPos eWhichY ) const
+{
+ return CellsAtY( GetPosY( eWhichY ), 1, eWhichY );
+}
+
+SCCOL ScViewData::PrevCellsX( ScHSplitPos eWhichX ) const
+{
+ return CellsAtX( GetPosX( eWhichX ), -1, eWhichX );
+}
+
+SCROW ScViewData::PrevCellsY( ScVSplitPos eWhichY ) const
+{
+ return CellsAtY( GetPosY( eWhichY ), -1, eWhichY );
+}
+
+bool ScViewData::GetMergeSizePixel( SCCOL nX, SCROW nY, tools::Long& rSizeXPix, tools::Long& rSizeYPix ) const
+{
+ const ScMergeAttr* pMerge = mrDoc.GetAttr(nX, nY, nTabNo, ATTR_MERGE);
+ if ( pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1 )
+ {
+ tools::Long nOutWidth = 0;
+ tools::Long nOutHeight = 0;
+ SCCOL nCountX = pMerge->GetColMerge();
+ for (SCCOL i=0; i<nCountX; i++)
+ nOutWidth += ToPixel(mrDoc.GetColWidth(nX + i, nTabNo), nPPTX);
+ SCROW nCountY = pMerge->GetRowMerge();
+
+ for (SCROW nRow = nY; nRow <= nY+nCountY-1; ++nRow)
+ {
+ SCROW nLastRow = nRow;
+ if (mrDoc.RowHidden(nRow, nTabNo, nullptr, &nLastRow))
+ {
+ nRow = nLastRow;
+ continue;
+ }
+
+ sal_uInt16 nHeight = mrDoc.GetRowHeight(nRow, nTabNo);
+ nOutHeight += ToPixel(nHeight, nPPTY);
+ }
+
+ rSizeXPix = nOutWidth;
+ rSizeYPix = nOutHeight;
+ return true;
+ }
+ else
+ {
+ rSizeXPix = ToPixel(mrDoc.GetColWidth(nX, nTabNo), nPPTX);
+ rSizeYPix = ToPixel(mrDoc.GetRowHeight(nY, nTabNo), nPPTY);
+ return false;
+ }
+}
+
+bool ScViewData::GetMergeSizePrintTwips(SCCOL nX, SCROW nY, tools::Long& rSizeXTwips, tools::Long& rSizeYTwips) const
+{
+ const ScMergeAttr* pMerge = mrDoc.GetAttr(nX, nY, nTabNo, ATTR_MERGE);
+ SCCOL nCountX = pMerge->GetColMerge();
+ if (!nCountX)
+ nCountX = 1;
+ rSizeXTwips = mrDoc.GetColWidth(nX, nX + nCountX - 1, nTabNo);
+
+ SCROW nCountY = pMerge->GetRowMerge();
+ if (!nCountY)
+ nCountY = 1;
+ rSizeYTwips = mrDoc.GetRowHeight(nY, nY + nCountY - 1, nTabNo);
+
+ return (nCountX > 1 || nCountY > 1);
+}
+
+void ScViewData::GetPosFromPixel( tools::Long nClickX, tools::Long nClickY, ScSplitPos eWhich,
+ SCCOL& rPosX, SCROW& rPosY,
+ bool bTestMerge, bool bRepair, SCTAB nForTab )
+{
+ // special handling of 0 is now in ScViewFunctionSet::SetCursorAtPoint
+
+ if (nForTab == -1)
+ nForTab = nTabNo;
+ bool bForCurTab = (nForTab == nTabNo);
+ if (!bForCurTab && (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size()))))
+ {
+ SAL_WARN("sc.viewdata", "ScViewData::GetPosFromPixel : invalid nForTab = " << nForTab);
+ nForTab = nTabNo;
+ bForCurTab = true;
+ }
+
+ ScHSplitPos eHWhich = WhichH(eWhich);
+ ScVSplitPos eVWhich = WhichV(eWhich);
+
+ if (mrDoc.IsLayoutRTL(nForTab))
+ {
+ if (!comphelper::LibreOfficeKit::isActive())
+ {
+ // mirror horizontal position
+ if (pView)
+ aScrSize.setWidth( pView->GetGridWidth(eHWhich) );
+ nClickX = aScrSize.Width() - 1 - nClickX;
+ }
+ }
+
+ SCCOL nStartPosX = GetPosX(eHWhich, nForTab);
+ SCROW nStartPosY = GetPosY(eVWhich, nForTab);
+ rPosX = nStartPosX;
+ rPosY = nStartPosY;
+ tools::Long nScrX = 0;
+ tools::Long nScrY = 0;
+
+ if (nClickX > 0)
+ {
+ while (rPosX <= mrDoc.MaxCol() && nClickX >= nScrX)
+ {
+ nScrX += ToPixel(mrDoc.GetColWidth(rPosX, nForTab), nPPTX);
+ ++rPosX;
+ }
+ --rPosX;
+ }
+ else
+ {
+ while ( rPosX>0 && nClickX < nScrX )
+ {
+ --rPosX;
+ nScrX -= ToPixel(mrDoc.GetColWidth(rPosX, nForTab), nPPTX);
+ }
+ }
+
+ if (nClickY > 0)
+ AddPixelsWhile(nScrY, nClickY, rPosY, mrDoc.MaxRow(), nPPTY, &mrDoc, nForTab);
+ else
+ {
+ /* TODO: could need some "SubPixelsWhileBackward" method */
+ while ( rPosY>0 && nClickY < nScrY )
+ {
+ --rPosY;
+ nScrY -= ToPixel(mrDoc.GetRowHeight(rPosY, nForTab), nPPTY);
+ }
+ }
+
+ // cells too big?
+ if ( rPosX == nStartPosX && nClickX > 0 )
+ {
+ if (pView)
+ aScrSize.setWidth( pView->GetGridWidth(eHWhich) );
+ if ( nClickX > aScrSize.Width() )
+ ++rPosX;
+ }
+ if ( rPosY == nStartPosY && nClickY > 0 )
+ {
+ if (pView)
+ aScrSize.setHeight( pView->GetGridHeight(eVWhich) );
+ if ( nClickY > aScrSize.Height() )
+ ++rPosY;
+ }
+
+ rPosX = std::clamp(rPosX, SCCOL(0), mrDoc.MaxCol());
+ rPosY = std::clamp(rPosY, SCROW(0), mrDoc.MaxRow());
+
+ if (!(bTestMerge && bForCurTab))
+ return;
+
+ // public method to adapt position
+ SCCOL nOrigX = rPosX;
+ SCROW nOrigY = rPosY;
+ mrDoc.SkipOverlapped(rPosX, rPosY, nTabNo);
+ bool bHOver = (nOrigX != rPosX);
+ bool bVOver = (nOrigY != rPosY);
+
+ if ( !(bRepair && ( bHOver || bVOver )) )
+ return;
+
+ const ScMergeAttr* pMerge = mrDoc.GetAttr(rPosX, rPosY, nTabNo, ATTR_MERGE);
+ if ( ( bHOver && pMerge->GetColMerge() <= 1 ) ||
+ ( bVOver && pMerge->GetRowMerge() <= 1 ) )
+ {
+ OSL_FAIL("merge error found");
+
+ mrDoc.RemoveFlagsTab(0, 0, mrDoc.MaxCol(), mrDoc.MaxRow(), nTabNo, ScMF::Hor | ScMF::Ver);
+ SCCOL nEndCol = mrDoc.MaxCol();
+ SCROW nEndRow = mrDoc.MaxRow();
+ mrDoc.ExtendMerge(0, 0, nEndCol, nEndRow, nTabNo, true);
+ if (pDocShell)
+ pDocShell->PostPaint(ScRange(0, 0, nTabNo, mrDoc.MaxCol(), mrDoc.MaxRow(), nTabNo),
+ PaintPartFlags::Grid);
+ }
+}
+
+void ScViewData::GetMouseQuadrant( const Point& rClickPos, ScSplitPos eWhich,
+ SCCOL nPosX, SCROW nPosY, bool& rLeft, bool& rTop )
+{
+ bool bLayoutRTL = mrDoc.IsLayoutRTL(nTabNo);
+ tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
+
+ Point aCellStart = GetScrPos( nPosX, nPosY, eWhich, true );
+ tools::Long nSizeX;
+ tools::Long nSizeY;
+ GetMergeSizePixel( nPosX, nPosY, nSizeX, nSizeY );
+ rLeft = ( rClickPos.X() - aCellStart.X() ) * nLayoutSign <= nSizeX / 2;
+ rTop = rClickPos.Y() - aCellStart.Y() <= nSizeY / 2;
+}
+
+void ScViewData::SetPosX( ScHSplitPos eWhich, SCCOL nNewPosX )
+{
+ // in the tiled rendering case, nPosX [the leftmost visible column] must be 0
+ bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
+ if (nNewPosX != 0 && !bIsTiledRendering)
+ {
+ SCCOL nOldPosX = pThisTab->nPosX[eWhich];
+ tools::Long nTPosX = pThisTab->nTPosX[eWhich];
+ tools::Long nPixPosX = pThisTab->nPixPosX[eWhich];
+ SCCOL i;
+ if ( nNewPosX > nOldPosX )
+ for ( i=nOldPosX; i<nNewPosX; i++ )
+ {
+ tools::Long nThis = mrDoc.GetColWidth(i, nTabNo);
+ nTPosX -= nThis;
+ nPixPosX -= ToPixel(sal::static_int_cast<sal_uInt16>(nThis), nPPTX);
+ }
+ else
+ for ( i=nNewPosX; i<nOldPosX; i++ )
+ {
+ tools::Long nThis = mrDoc.GetColWidth(i, nTabNo);
+ nTPosX += nThis;
+ nPixPosX += ToPixel(sal::static_int_cast<sal_uInt16>(nThis), nPPTX);
+ }
+
+ pThisTab->nPosX[eWhich] = nNewPosX;
+ pThisTab->nTPosX[eWhich] = nTPosX;
+ pThisTab->nMPosX[eWhich] = o3tl::convert(nTPosX, o3tl::Length::twip, o3tl::Length::mm100);
+ pThisTab->nPixPosX[eWhich] = nPixPosX;
+ }
+ else
+ {
+ pThisTab->nPixPosX[eWhich] =
+ pThisTab->nTPosX[eWhich] =
+ pThisTab->nMPosX[eWhich] =
+ pThisTab->nPosX[eWhich] = 0;
+ }
+}
+
+void ScViewData::SetPosY( ScVSplitPos eWhich, SCROW nNewPosY )
+{
+ // in the tiled rendering case, nPosY [the topmost visible row] must be 0
+ bool bIsTiledRendering = comphelper::LibreOfficeKit::isActive();
+ if (nNewPosY != 0 && !bIsTiledRendering)
+ {
+ SCROW nOldPosY = pThisTab->nPosY[eWhich];
+ tools::Long nTPosY = pThisTab->nTPosY[eWhich];
+ tools::Long nPixPosY = pThisTab->nPixPosY[eWhich];
+ SCROW i, nHeightEndRow;
+ if ( nNewPosY > nOldPosY )
+ for ( i=nOldPosY; i<nNewPosY; i++ )
+ {
+ tools::Long nThis = mrDoc.GetRowHeight(i, nTabNo, nullptr, &nHeightEndRow);
+ SCROW nRows = std::min( nNewPosY, nHeightEndRow + 1) - i;
+ i = nHeightEndRow;
+ nTPosY -= nThis * nRows;
+ nPixPosY -= ToPixel(sal::static_int_cast<sal_uInt16>(nThis), nPPTY) * nRows;
+ }
+ else
+ for ( i=nNewPosY; i<nOldPosY; i++ )
+ {
+ tools::Long nThis = mrDoc.GetRowHeight(i, nTabNo, nullptr, &nHeightEndRow);
+ SCROW nRows = std::min( nOldPosY, nHeightEndRow + 1) - i;
+ i = nHeightEndRow;
+ nTPosY += nThis * nRows;
+ nPixPosY += ToPixel(sal::static_int_cast<sal_uInt16>(nThis), nPPTY) * nRows;
+ }
+
+ pThisTab->nPosY[eWhich] = nNewPosY;
+ pThisTab->nTPosY[eWhich] = nTPosY;
+ pThisTab->nMPosY[eWhich] = o3tl::convert(nTPosY, o3tl::Length::twip, o3tl::Length::mm100);
+ pThisTab->nPixPosY[eWhich] = nPixPosY;
+ }
+ else
+ {
+ pThisTab->nPixPosY[eWhich] =
+ pThisTab->nTPosY[eWhich] =
+ pThisTab->nMPosY[eWhich] =
+ pThisTab->nPosY[eWhich] = 0;
+ }
+}
+
+void ScViewData::RecalcPixPos() // after zoom changes
+{
+ for (sal_uInt16 eWhich=0; eWhich<2; eWhich++)
+ {
+ tools::Long nPixPosX = 0;
+ SCCOL nPosX = pThisTab->nPosX[eWhich];
+ for (SCCOL i=0; i<nPosX; i++)
+ nPixPosX -= ToPixel(mrDoc.GetColWidth(i, nTabNo), nPPTX);
+ pThisTab->nPixPosX[eWhich] = nPixPosX;
+
+ tools::Long nPixPosY = 0;
+ SCROW nPosY = pThisTab->nPosY[eWhich];
+ tools::Long nRowHeight = -1;
+ SCROW nLastSameHeightRow = -1;
+ for (SCROW j=0; j<nPosY; j++)
+ {
+ if(nLastSameHeightRow < j)
+ nRowHeight = ToPixel(mrDoc.GetRowHeight(j, nTabNo, nullptr, &nLastSameHeightRow), nPPTY);
+ nPixPosY -= nRowHeight;
+ }
+ pThisTab->nPixPosY[eWhich] = nPixPosY;
+ }
+}
+
+const MapMode& ScViewData::GetLogicMode( ScSplitPos eWhich )
+{
+ aLogicMode.SetOrigin( Point( pThisTab->nMPosX[WhichH(eWhich)],
+ pThisTab->nMPosY[WhichV(eWhich)] ) );
+ return aLogicMode;
+}
+
+const MapMode& ScViewData::GetLogicMode()
+{
+ aLogicMode.SetOrigin( Point() );
+ return aLogicMode;
+}
+
+void ScViewData::SetScreen( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
+{
+ SCCOL nCol;
+ SCROW nRow;
+ sal_uInt16 nTSize;
+ tools::Long nSizePix;
+ tools::Long nScrPosX = 0;
+ tools::Long nScrPosY = 0;
+
+ SetActivePart( SC_SPLIT_BOTTOMLEFT );
+ SetPosX( SC_SPLIT_LEFT, nCol1 );
+ SetPosY( SC_SPLIT_BOTTOM, nRow1 );
+
+ for (nCol=nCol1; nCol<=nCol2; nCol++)
+ {
+ nTSize = mrDoc.GetColWidth(nCol, nTabNo);
+ if (nTSize)
+ {
+ nSizePix = ToPixel( nTSize, nPPTX );
+ nScrPosX += static_cast<sal_uInt16>(nSizePix);
+ }
+ }
+
+ for (nRow=nRow1; nRow<=nRow2; nRow++)
+ {
+ nTSize = mrDoc.GetRowHeight(nRow, nTabNo);
+ if (nTSize)
+ {
+ nSizePix = ToPixel( nTSize, nPPTY );
+ nScrPosY += static_cast<sal_uInt16>(nSizePix);
+ }
+ }
+
+ aScrSize = Size( nScrPosX, nScrPosY );
+}
+
+void ScViewData::SetScreenPos( const Point& rVisAreaStart )
+{
+ tools::Long nSize;
+ tools::Long nTwips;
+ tools::Long nAdd;
+ bool bEnd;
+
+ nSize = 0;
+ nTwips = o3tl::convert(rVisAreaStart.X(), o3tl::Length::mm100, o3tl::Length::twip);
+ if (mrDoc.IsLayoutRTL(nTabNo))
+ nTwips = -nTwips;
+ SCCOL nX1 = 0;
+ bEnd = false;
+ while (!bEnd)
+ {
+ nAdd = static_cast<tools::Long>(mrDoc.GetColWidth(nX1, nTabNo));
+ if (nSize + nAdd <= nTwips + 1 && nX1 < mrDoc.MaxCol())
+ {
+ nSize += nAdd;
+ ++nX1;
+ }
+ else
+ bEnd = true;
+ }
+
+ nSize = 0;
+ nTwips = o3tl::convert(rVisAreaStart.Y(), o3tl::Length::mm100, o3tl::Length::twip);
+ SCROW nY1 = 0;
+ bEnd = false;
+ while (!bEnd)
+ {
+ nAdd = static_cast<tools::Long>(mrDoc.GetRowHeight(nY1, nTabNo));
+ if (nSize + nAdd <= nTwips + 1 && nY1 < mrDoc.MaxRow())
+ {
+ nSize += nAdd;
+ ++nY1;
+ }
+ else
+ bEnd = true;
+ }
+
+ SetActivePart( SC_SPLIT_BOTTOMLEFT );
+ SetPosX( SC_SPLIT_LEFT, nX1 );
+ SetPosY( SC_SPLIT_BOTTOM, nY1 );
+
+ SetCurX( nX1 );
+ SetCurY( nY1 );
+}
+
+void ScViewData::SetScreen( const tools::Rectangle& rVisArea )
+{
+ SetScreenPos( rVisArea.TopLeft() );
+
+ // here without GetOutputFactor(), since it's for the output into a Metafile
+
+ aScrSize = rVisArea.GetSize();
+ aScrSize.setWidth(std::round(o3tl::convert( aScrSize.Width(), o3tl::Length::mm100, o3tl::Length::twip) * ScGlobal::nScreenPPTX));
+ aScrSize.setHeight(std::round(o3tl::convert( aScrSize.Height(), o3tl::Length::mm100, o3tl::Length::twip) * ScGlobal::nScreenPPTY));
+}
+
+ScDocFunc& ScViewData::GetDocFunc() const
+{
+ return pDocShell->GetDocFunc();
+}
+
+SfxBindings& ScViewData::GetBindings()
+{
+ assert(pView && "GetBindings() without ViewShell");
+ return pView->GetViewFrame()->GetBindings();
+}
+
+SfxDispatcher& ScViewData::GetDispatcher()
+{
+ assert(pView && "GetDispatcher() without ViewShell");
+ return *pView->GetViewFrame()->GetDispatcher();
+}
+
+ScMarkData& ScViewData::GetMarkData()
+{
+ return maMarkData;
+}
+
+const ScMarkData& ScViewData::GetMarkData() const
+{
+ return maMarkData;
+}
+
+weld::Window* ScViewData::GetDialogParent()
+{
+ assert(pView && "GetDialogParent() without ViewShell");
+ return pView->GetDialogParent();
+}
+
+ScGridWindow* ScViewData::GetActiveWin()
+{
+ assert(pView && "GetActiveWin() without View");
+ return pView->GetActiveWin();
+}
+
+const ScGridWindow* ScViewData::GetActiveWin() const
+{
+ assert(pView && "GetActiveWin() without View");
+ return pView->GetActiveWin();
+}
+
+ScDrawView* ScViewData::GetScDrawView()
+{
+ assert(pView && "GetScDrawView() without View");
+ return pView->GetScDrawView();
+}
+
+bool ScViewData::IsMinimized() const
+{
+ assert(pView && "IsMinimized() without View");
+ return pView->IsMinimized();
+}
+
+void ScViewData::UpdateScreenZoom( const Fraction& rNewX, const Fraction& rNewY )
+{
+ Fraction aOldX = GetZoomX();
+ Fraction aOldY = GetZoomY();
+
+ SetZoom( rNewX, rNewY, false );
+
+ Fraction aWidth = GetZoomX();
+ aWidth *= Fraction( aScrSize.Width(),1 );
+ aWidth /= aOldX;
+
+ Fraction aHeight = GetZoomY();
+ aHeight *= Fraction( aScrSize.Height(),1 );
+ aHeight /= aOldY;
+
+ aScrSize.setWidth( static_cast<tools::Long>(aWidth) );
+ aScrSize.setHeight( static_cast<tools::Long>(aHeight) );
+}
+
+void ScViewData::CalcPPT()
+{
+ double nOldPPTX = nPPTX;
+ double nOldPPTY = nPPTY;
+ nPPTX = ScGlobal::nScreenPPTX * static_cast<double>(GetZoomX());
+ if (pDocShell)
+ nPPTX = nPPTX / pDocShell->GetOutputFactor(); // Factor is printer to screen
+ nPPTY = ScGlobal::nScreenPPTY * static_cast<double>(GetZoomY());
+
+ // if detective objects are present,
+ // try to adjust horizontal scale so the most common column width has minimal rounding errors,
+ // to avoid differences between cell and drawing layer output
+
+ if (mrDoc.HasDetectiveObjects(nTabNo))
+ {
+ SCCOL nEndCol = 0;
+ SCROW nDummy = 0;
+ mrDoc.GetTableArea(nTabNo, nEndCol, nDummy);
+ if (nEndCol<20)
+ nEndCol = 20; // same end position as when determining draw scale
+
+ sal_uInt16 nTwips = mrDoc.GetCommonWidth(nEndCol, nTabNo);
+ if ( nTwips )
+ {
+ double fOriginal = nTwips * nPPTX;
+ if ( fOriginal < static_cast<double>(nEndCol) )
+ {
+ // if one column is smaller than the column count,
+ // rounding errors are likely to add up to a whole column.
+
+ double fRounded = ::rtl::math::approxFloor( fOriginal + 0.5 );
+ if ( fRounded > 0.0 )
+ {
+ double fScale = fRounded / fOriginal + 1E-6;
+ if ( fScale >= 0.9 && fScale <= 1.1 )
+ nPPTX *= fScale;
+ }
+ }
+ }
+ }
+
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ SCTAB nTabCount = maTabData.size();
+ bool bResetWidths = (nPPTX != nOldPPTX);
+ bool bResetHeights = (nPPTY != nOldPPTY);
+ for (SCTAB nTabIdx = 0; nTabIdx < nTabCount; ++nTabIdx)
+ {
+ if (!maTabData[nTabIdx])
+ continue;
+
+ if (bResetWidths)
+ if (auto* pWHelper = GetLOKWidthHelper(nTabIdx))
+ pWHelper->invalidateByPosition(0L);
+
+ if (bResetHeights)
+ if (auto* pHHelper = GetLOKHeightHelper(nTabIdx))
+ pHHelper->invalidateByPosition(0L);
+ }
+}
+
+#define SC_OLD_TABSEP '/'
+#define SC_NEW_TABSEP '+'
+
+void ScViewData::WriteUserData(OUString& rData)
+{
+ // nZoom (until 364v) or nZoom/nPageZoom/bPageMode (from 364w)
+ // nTab
+ // Tab control width
+ // per sheet:
+ // CursorX/CursorY/HSplitMode/VSplitMode/HSplitPos/VSplitPos/SplitActive/
+ // PosX[left]/PosX[right]/PosY[top]/PosY[bottom]
+ // when rows bigger than 8192, "+" instead of "/"
+
+ sal_uInt16 nZoom = static_cast<sal_uInt16>(tools::Long(pThisTab->aZoomY * 100));
+ rData = OUString::number( nZoom ) + "/";
+ nZoom = static_cast<sal_uInt16>(tools::Long(pThisTab->aPageZoomY * 100));
+ rData += OUString::number( nZoom ) + "/";
+ if (bPagebreak)
+ rData += "1";
+ else
+ rData += "0";
+
+ rData += ";" + OUString::number( nTabNo ) + ";" + TAG_TABBARWIDTH +
+ OUString::number( pView->GetTabBarWidth() );
+
+ SCTAB nTabCount = mrDoc.GetTableCount();
+ for (SCTAB i=0; i<nTabCount; i++)
+ {
+ rData += ";"; // Numbering must not get mixed up under any circumstances
+ if (i < static_cast<SCTAB>(maTabData.size()) && maTabData[i])
+ {
+ OUString cTabSep(SC_OLD_TABSEP); // like 3.1
+ if ( maTabData[i]->nCurY > MAXROW_30 ||
+ maTabData[i]->nPosY[0] > MAXROW_30 || maTabData[i]->nPosY[1] > MAXROW_30 ||
+ ( maTabData[i]->eVSplitMode == SC_SPLIT_FIX &&
+ maTabData[i]->nFixPosY > MAXROW_30 ) )
+ {
+ cTabSep = OUStringChar(SC_NEW_TABSEP); // in order to not kill a 3.1-version
+ }
+
+ rData += OUString::number( maTabData[i]->nCurX ) + cTabSep +
+ OUString::number( maTabData[i]->nCurY ) + cTabSep +
+ OUString::number( maTabData[i]->eHSplitMode ) + cTabSep +
+ OUString::number( maTabData[i]->eVSplitMode ) + cTabSep;
+ if ( maTabData[i]->eHSplitMode == SC_SPLIT_FIX )
+ rData += OUString::number( maTabData[i]->nFixPosX );
+ else
+ rData += OUString::number( maTabData[i]->nHSplitPos );
+ rData += cTabSep;
+ if ( maTabData[i]->eVSplitMode == SC_SPLIT_FIX )
+ rData += OUString::number( maTabData[i]->nFixPosY );
+ else
+ rData += OUString::number( maTabData[i]->nVSplitPos );
+ rData += cTabSep +
+ OUString::number( maTabData[i]->eWhichActive ) + cTabSep +
+ OUString::number( maTabData[i]->nPosX[0] ) + cTabSep +
+ OUString::number( maTabData[i]->nPosX[1] ) + cTabSep +
+ OUString::number( maTabData[i]->nPosY[0] ) + cTabSep +
+ OUString::number( maTabData[i]->nPosY[1] );
+ }
+ }
+}
+
+void ScViewData::ReadUserData(std::u16string_view rData)
+{
+ if (rData.empty()) // empty string on "reload"
+ return; // then exit without assertion
+
+ if ( comphelper::string::getTokenCount(rData, ';') <= 2 )
+ {
+ // when reload, in page preview, the preview UserData may have been left intact.
+ // we don't want the zoom from the page preview here.
+ OSL_FAIL("ReadUserData: This is not my data");
+ return;
+ }
+
+ sal_Int32 nMainIdx {0};
+ sal_Int32 nIdx {0};
+
+ std::u16string_view aZoomStr = o3tl::getToken(rData, 0, ';', nMainIdx); // Zoom/PageZoom/Mode
+ sal_Unicode cMode = o3tl::getToken(aZoomStr, 2, '/', nIdx)[0]; // 0 or "0"/"1"
+ SetPagebreakMode( cMode == '1' );
+ // SetPagebreakMode must always be called due to CalcPPT / RecalcPixPos()
+
+ // sheet may have become invalid (for instance last version):
+ SCTAB nNewTab = static_cast<SCTAB>(o3tl::toUInt32(o3tl::getToken(rData, 0, ';', nMainIdx)));
+ if (mrDoc.HasTable(nNewTab))
+ SetTabNo(nNewTab);
+
+ // if available, get tab bar width:
+ const sal_Int32 nMainIdxRef {nMainIdx};
+ std::u16string_view aTabOpt = o3tl::getToken(rData, 0, ';', nMainIdx);
+
+ std::u16string_view aRest;
+ if (o3tl::starts_with(aTabOpt, TAG_TABBARWIDTH, &aRest))
+ {
+ pView->SetTabBarWidth(o3tl::toInt32(aRest));
+ }
+ else
+ {
+ // Tab bar width not specified, token to be processed again
+ nMainIdx = nMainIdxRef;
+ }
+
+ // per sheet
+ SCTAB nPos = 0;
+ while ( nMainIdx>0 )
+ {
+ aTabOpt = o3tl::getToken(rData, 0, ';', nMainIdx);
+ EnsureTabDataSize(nPos + 1);
+ if (!maTabData[nPos])
+ maTabData[nPos].reset(new ScViewDataTable(&mrDoc));
+
+ sal_Unicode cTabSep = 0;
+ if (comphelper::string::getTokenCount(aTabOpt, SC_OLD_TABSEP) >= 11)
+ cTabSep = SC_OLD_TABSEP;
+ else if (comphelper::string::getTokenCount(aTabOpt, SC_NEW_TABSEP) >= 11)
+ cTabSep = SC_NEW_TABSEP;
+ // '+' is only allowed, if we can deal with rows > 8192
+
+ if (cTabSep)
+ {
+ nIdx = 0;
+ maTabData[nPos]->nCurX = mrDoc.SanitizeCol(static_cast<SCCOL>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx))));
+ maTabData[nPos]->nCurY = mrDoc.SanitizeRow(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
+ maTabData[nPos]->eHSplitMode = static_cast<ScSplitMode>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
+ maTabData[nPos]->eVSplitMode = static_cast<ScSplitMode>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
+
+ sal_Int32 nTmp = o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx));
+ if ( maTabData[nPos]->eHSplitMode == SC_SPLIT_FIX )
+ {
+ maTabData[nPos]->nFixPosX = mrDoc.SanitizeCol(static_cast<SCCOL>(nTmp));
+ UpdateFixX(nPos);
+ }
+ else
+ maTabData[nPos]->nHSplitPos = nTmp;
+
+ nTmp = o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx));
+ if ( maTabData[nPos]->eVSplitMode == SC_SPLIT_FIX )
+ {
+ maTabData[nPos]->nFixPosY = mrDoc.SanitizeRow(nTmp);
+ UpdateFixY(nPos);
+ }
+ else
+ maTabData[nPos]->nVSplitPos = nTmp;
+
+ maTabData[nPos]->eWhichActive = static_cast<ScSplitPos>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
+ maTabData[nPos]->nPosX[0] = mrDoc.SanitizeCol(static_cast<SCCOL>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx))));
+ maTabData[nPos]->nPosX[1] = mrDoc.SanitizeCol(static_cast<SCCOL>(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx))));
+ maTabData[nPos]->nPosY[0] = mrDoc.SanitizeRow(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
+ maTabData[nPos]->nPosY[1] = mrDoc.SanitizeRow(o3tl::toInt32(o3tl::getToken(aTabOpt, 0, cTabSep, nIdx)));
+
+ maTabData[nPos]->eWhichActive = maTabData[nPos]->SanitizeWhichActive();
+ }
+ ++nPos;
+ }
+
+ RecalcPixPos();
+}
+
+void ScViewData::WriteExtOptions( ScExtDocOptions& rDocOpt ) const
+{
+ // *** Fill extended document data for export filters ***
+
+ // document settings
+ ScExtDocSettings& rDocSett = rDocOpt.GetDocSettings();
+
+ // displayed sheet
+ rDocSett.mnDisplTab = GetTabNo();
+
+ // width of the tabbar, relative to frame window width
+ rDocSett.mfTabBarWidth = pView->GetPendingRelTabBarWidth();
+ if( rDocSett.mfTabBarWidth < 0.0 )
+ rDocSett.mfTabBarWidth = ScTabView::GetRelTabBarWidth();
+
+ bool bLOKActive = comphelper::LibreOfficeKit::isActive();
+
+ // sheet settings
+ for( SCTAB nTab = 0; nTab < static_cast<SCTAB>(maTabData.size()); ++nTab )
+ {
+ if( const ScViewDataTable* pViewTab = maTabData[ nTab ].get() )
+ {
+ ScExtTabSettings& rTabSett = rDocOpt.GetOrCreateTabSettings( nTab );
+
+ // split mode
+ ScSplitMode eExHSplit = pViewTab->eHSplitMode;
+ ScSplitMode eExVSplit = pViewTab->eVSplitMode;
+ SCCOL nExFixPosX = pViewTab->nFixPosX;
+ SCROW nExFixPosY = pViewTab->nFixPosY;
+ tools::Long nExHSplitPos = pViewTab->nHSplitPos;
+ tools::Long nExVSplitPos = pViewTab->nVSplitPos;
+
+ if (bLOKActive)
+ {
+ OverrideWithLOKFreeze(eExHSplit, eExVSplit,
+ nExFixPosX, nExFixPosY,
+ nExHSplitPos, nExVSplitPos, nTab);
+ }
+
+ bool bHSplit = eExHSplit != SC_SPLIT_NONE;
+ bool bVSplit = eExVSplit != SC_SPLIT_NONE;
+ bool bRealSplit = (eExHSplit == SC_SPLIT_NORMAL) || (eExVSplit == SC_SPLIT_NORMAL);
+ bool bFrozen = (eExHSplit == SC_SPLIT_FIX) || (eExVSplit == SC_SPLIT_FIX);
+ OSL_ENSURE( !bRealSplit || !bFrozen, "ScViewData::WriteExtOptions - split and freeze in same sheet" );
+ rTabSett.mbFrozenPanes = !bRealSplit && bFrozen;
+
+ // split and freeze position
+ rTabSett.maSplitPos = Point( 0, 0 );
+ rTabSett.maFreezePos.Set( 0, 0, nTab );
+ if( bRealSplit )
+ {
+ Point& rSplitPos = rTabSett.maSplitPos;
+ rSplitPos = Point( bHSplit ? nExHSplitPos : 0, bVSplit ? nExVSplitPos : 0 );
+ rSplitPos = Application::GetDefaultDevice()->PixelToLogic( rSplitPos, MapMode( MapUnit::MapTwip ) );
+ if( pDocShell )
+ rSplitPos.setX( static_cast<tools::Long>(static_cast<double>(rSplitPos.X()) / pDocShell->GetOutputFactor()) );
+ }
+ else if( bFrozen )
+ {
+ if( bHSplit ) rTabSett.maFreezePos.SetCol( nExFixPosX );
+ if( bVSplit ) rTabSett.maFreezePos.SetRow( nExFixPosY );
+ }
+
+ // first visible cell in top-left and additional panes
+ rTabSett.maFirstVis.Set( pViewTab->nPosX[ SC_SPLIT_LEFT ], pViewTab->nPosY[ bVSplit ? SC_SPLIT_TOP : SC_SPLIT_BOTTOM ], nTab );
+ rTabSett.maSecondVis.Set( pViewTab->nPosX[ SC_SPLIT_RIGHT ], pViewTab->nPosY[ SC_SPLIT_BOTTOM ], nTab );
+
+ // active pane
+ switch( pViewTab->eWhichActive )
+ {
+ // no horizontal split -> always use left panes
+ // no vertical split -> always use top panes
+ case SC_SPLIT_TOPLEFT:
+ rTabSett.meActivePane = SCEXT_PANE_TOPLEFT;
+ break;
+ case SC_SPLIT_TOPRIGHT:
+ rTabSett.meActivePane = bHSplit ? SCEXT_PANE_TOPRIGHT : SCEXT_PANE_TOPLEFT;
+ break;
+ case SC_SPLIT_BOTTOMLEFT:
+ rTabSett.meActivePane = bVSplit ? SCEXT_PANE_BOTTOMLEFT : SCEXT_PANE_TOPLEFT;
+ break;
+ case SC_SPLIT_BOTTOMRIGHT:
+ rTabSett.meActivePane = bHSplit ?
+ (bVSplit ? SCEXT_PANE_BOTTOMRIGHT : SCEXT_PANE_TOPRIGHT) :
+ (bVSplit ? SCEXT_PANE_BOTTOMLEFT : SCEXT_PANE_TOPLEFT);
+ break;
+ }
+
+ // cursor position
+ rTabSett.maCursor.Set( pViewTab->nCurX, pViewTab->nCurY, nTab );
+
+ // sheet selection and selected ranges
+ const ScMarkData& rMarkData = GetMarkData();
+ rTabSett.mbSelected = rMarkData.GetTableSelect( nTab );
+ rMarkData.FillRangeListWithMarks( &rTabSett.maSelection, true );
+
+ // grid color
+ rTabSett.maGridColor = COL_AUTO;
+ const Color& rGridColor = maOptions.GetGridColor();
+ if (rGridColor != SC_STD_GRIDCOLOR)
+ rTabSett.maGridColor = rGridColor;
+ rTabSett.mbShowGrid = pViewTab->bShowGrid;
+
+ // view mode and zoom
+ rTabSett.mbPageMode = bPagebreak;
+ rTabSett.mnNormalZoom = static_cast< tools::Long >( pViewTab->aZoomY * Fraction( 100.0 ) );
+ rTabSett.mnPageZoom = static_cast< tools::Long >( pViewTab->aPageZoomY * Fraction( 100.0 ) );
+ }
+ }
+}
+
+void ScViewData::ReadExtOptions( const ScExtDocOptions& rDocOpt )
+{
+ // *** Get extended document data from import filters ***
+
+ if( !rDocOpt.IsChanged() ) return;
+
+ // document settings
+ const ScExtDocSettings& rDocSett = rDocOpt.GetDocSettings();
+
+ // displayed sheet
+ SetTabNo( rDocSett.mnDisplTab );
+
+ /* Width of the tabbar, relative to frame window width. We do not have the
+ correct width of the frame window here -> store in ScTabView, which sets
+ the size in the next resize. */
+ pView->SetPendingRelTabBarWidth( rDocSett.mfTabBarWidth );
+
+ // sheet settings
+ SCTAB nLastTab = rDocOpt.GetLastTab();
+ if (static_cast<SCTAB>(maTabData.size()) <= nLastTab)
+ maTabData.resize(nLastTab+1);
+
+ for( SCTAB nTab = 0; nTab < static_cast<SCTAB>(maTabData.size()); ++nTab )
+ {
+ if( const ScExtTabSettings* pTabSett = rDocOpt.GetTabSettings( nTab ) )
+ {
+ if( !maTabData[ nTab ] )
+ maTabData[nTab].reset(new ScViewDataTable(&mrDoc));
+
+ const ScExtTabSettings& rTabSett = *pTabSett;
+ ScViewDataTable& rViewTab = *maTabData[ nTab ];
+
+ // split mode initialization
+ bool bFrozen = rTabSett.mbFrozenPanes;
+ bool bHSplit = bFrozen ? (rTabSett.maFreezePos.Col() > 0) : (rTabSett.maSplitPos.X() > 0);
+ bool bVSplit = bFrozen ? (rTabSett.maFreezePos.Row() > 0) : (rTabSett.maSplitPos.Y() > 0);
+
+ // first visible cell of top-left pane and additional panes
+ if (rTabSett.maFirstVis.IsValid())
+ {
+ rViewTab.nPosX[ SC_SPLIT_LEFT ] = rTabSett.maFirstVis.Col();
+ rViewTab.nPosY[ bVSplit ? SC_SPLIT_TOP : SC_SPLIT_BOTTOM ] = rTabSett.maFirstVis.Row();
+ }
+
+ if (rTabSett.maSecondVis.IsValid())
+ {
+ if (bHSplit)
+ rViewTab.nPosX[ SC_SPLIT_RIGHT ] = rTabSett.maSecondVis.Col();
+ if (bVSplit)
+ rViewTab.nPosY[ SC_SPLIT_BOTTOM ] = rTabSett.maSecondVis.Row();
+ }
+
+ // split mode, split and freeze position
+ rViewTab.eHSplitMode = rViewTab.eVSplitMode = SC_SPLIT_NONE;
+ rViewTab.nHSplitPos = rViewTab.nVSplitPos = 0;
+ rViewTab.nFixPosX = 0;
+ rViewTab.nFixPosY = 0;
+ if( bFrozen )
+ {
+ if( bHSplit )
+ {
+ rViewTab.eHSplitMode = SC_SPLIT_FIX;
+ rViewTab.nFixPosX = rTabSett.maFreezePos.Col();
+ UpdateFixX( nTab );
+ }
+ if( bVSplit )
+ {
+ rViewTab.eVSplitMode = SC_SPLIT_FIX;
+ rViewTab.nFixPosY = rTabSett.maFreezePos.Row();
+ UpdateFixY( nTab );
+ }
+ }
+ else
+ {
+ Point aPixel = Application::GetDefaultDevice()->LogicToPixel(
+ rTabSett.maSplitPos, MapMode( MapUnit::MapTwip ) ); //! Zoom?
+ // the test for use of printer metrics for text formatting here
+ // effectively results in the nFactor = 1.0 regardless of the Option setting.
+ if( pDocShell && SC_MOD()->GetInputOptions().GetTextWysiwyg())
+ {
+ double nFactor = pDocShell->GetOutputFactor();
+ aPixel.setX( static_cast<tools::Long>( aPixel.X() * nFactor + 0.5 ) );
+ }
+
+ bHSplit = bHSplit && aPixel.X() > 0;
+ bVSplit = bVSplit && aPixel.Y() > 0;
+ if( bHSplit )
+ {
+ rViewTab.eHSplitMode = SC_SPLIT_NORMAL;
+ rViewTab.nHSplitPos = aPixel.X();
+ }
+ if( bVSplit )
+ {
+ rViewTab.eVSplitMode = SC_SPLIT_NORMAL;
+ rViewTab.nVSplitPos = aPixel.Y();
+ }
+ }
+
+ // active pane
+ ScSplitPos ePos = SC_SPLIT_BOTTOMLEFT;
+ switch( rTabSett.meActivePane )
+ {
+ // no horizontal split -> always use left panes
+ // no vertical split -> always use *bottom* panes
+ case SCEXT_PANE_TOPLEFT:
+ ePos = bVSplit ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT;
+ break;
+ case SCEXT_PANE_TOPRIGHT:
+ ePos = bHSplit ?
+ (bVSplit ? SC_SPLIT_TOPRIGHT : SC_SPLIT_BOTTOMRIGHT) :
+ (bVSplit ? SC_SPLIT_TOPLEFT : SC_SPLIT_BOTTOMLEFT);
+ break;
+ case SCEXT_PANE_BOTTOMLEFT:
+ ePos = SC_SPLIT_BOTTOMLEFT;
+ break;
+ case SCEXT_PANE_BOTTOMRIGHT:
+ ePos = bHSplit ? SC_SPLIT_BOTTOMRIGHT : SC_SPLIT_BOTTOMLEFT;
+ break;
+ }
+ rViewTab.eWhichActive = ePos;
+
+ // cursor position
+ const ScAddress& rCursor = rTabSett.maCursor;
+ if( rCursor.IsValid() )
+ {
+ rViewTab.nCurX = rCursor.Col();
+ rViewTab.nCurY = rCursor.Row();
+ }
+
+ // sheet selection and selected ranges
+ ScMarkData& rMarkData = GetMarkData();
+ rMarkData.SelectTable( nTab, rTabSett.mbSelected );
+
+ // zoom for each sheet
+ if( rTabSett.mnNormalZoom )
+ rViewTab.aZoomX = rViewTab.aZoomY = Fraction( rTabSett.mnNormalZoom, 100 );
+ if( rTabSett.mnPageZoom )
+ rViewTab.aPageZoomX = rViewTab.aPageZoomY = Fraction( rTabSett.mnPageZoom, 100 );
+
+ rViewTab.bShowGrid = rTabSett.mbShowGrid;
+
+ // get some settings from displayed Excel sheet, set at Calc document
+ if( nTab == GetTabNo() )
+ {
+ // grid color -- #i47435# set automatic grid color explicitly
+ Color aGridColor(rTabSett.maGridColor);
+ if (aGridColor == COL_AUTO)
+ aGridColor = SC_STD_GRIDCOLOR;
+ maOptions.SetGridColor(aGridColor, OUString());
+
+ // view mode and default zoom (for new sheets) from current sheet
+ if( rTabSett.mnNormalZoom )
+ aDefZoomX = aDefZoomY = Fraction( rTabSett.mnNormalZoom, 100L );
+ if( rTabSett.mnPageZoom )
+ aDefPageZoomX = aDefPageZoomY = Fraction( rTabSett.mnPageZoom, 100L );
+ /* #i46820# set pagebreak mode via SetPagebreakMode(), this will
+ update map modes that are needed to draw text correctly. */
+ SetPagebreakMode( rTabSett.mbPageMode );
+ }
+ }
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ DeriveLOKFreezeAllSheets();
+
+ // RecalcPixPos or so - also nMPos - also for ReadUserData ??!?!
+}
+
+void ScViewData::WriteUserDataSequence(uno::Sequence <beans::PropertyValue>& rSettings) const
+{
+ rSettings.realloc(SC_VIEWSETTINGS_COUNT);
+ // + 1, because we have to put the view id in the sequence
+ beans::PropertyValue* pSettings = rSettings.getArray();
+
+ sal_uInt16 nViewID(pView->GetViewFrame()->GetCurViewId());
+ pSettings[SC_VIEW_ID].Name = SC_VIEWID;
+ pSettings[SC_VIEW_ID].Value <<= SC_VIEW + OUString::number(nViewID);
+
+ uno::Reference<container::XNameContainer> xNameContainer =
+ document::NamedPropertyValues::create( comphelper::getProcessComponentContext() );
+ for (SCTAB nTab=0; nTab<static_cast<SCTAB>(maTabData.size()); nTab++)
+ {
+ if (maTabData[nTab])
+ {
+ uno::Sequence <beans::PropertyValue> aTableViewSettings;
+ maTabData[nTab]->WriteUserDataSequence(aTableViewSettings, *this, nTab);
+ OUString sTabName;
+ GetDocument().GetName( nTab, sTabName );
+ try
+ {
+ xNameContainer->insertByName(sTabName, uno::Any(aTableViewSettings));
+ }
+ //#101739#; two tables with the same name are possible
+ catch ( container::ElementExistException& )
+ {
+ OSL_FAIL("seems there are two tables with the same name");
+ }
+ catch ( uno::RuntimeException& )
+ {
+ OSL_FAIL("something went wrong");
+ }
+ }
+ }
+ pSettings[SC_TABLE_VIEWSETTINGS].Name = SC_TABLES;
+ pSettings[SC_TABLE_VIEWSETTINGS].Value <<= xNameContainer;
+
+ OUString sName;
+ GetDocument().GetName( nTabNo, sName );
+ pSettings[SC_ACTIVE_TABLE].Name = SC_ACTIVETABLE;
+ pSettings[SC_ACTIVE_TABLE].Value <<= sName;
+ pSettings[SC_HORIZONTAL_SCROLL_BAR_WIDTH].Name = SC_HORIZONTALSCROLLBARWIDTH;
+ pSettings[SC_HORIZONTAL_SCROLL_BAR_WIDTH].Value <<= sal_Int32(pView->GetTabBarWidth());
+ sal_Int32 nZoomValue = tools::Long(pThisTab->aZoomY * 100);
+ sal_Int32 nPageZoomValue = tools::Long(pThisTab->aPageZoomY * 100);
+ pSettings[SC_ZOOM_TYPE].Name = SC_ZOOMTYPE;
+ pSettings[SC_ZOOM_TYPE].Value <<= sal_Int16(pThisTab->eZoomType);
+ pSettings[SC_ZOOM_VALUE].Name = SC_ZOOMVALUE;
+ pSettings[SC_ZOOM_VALUE].Value <<= nZoomValue;
+ pSettings[SC_PAGE_VIEW_ZOOM_VALUE].Name = SC_PAGEVIEWZOOMVALUE;
+ pSettings[SC_PAGE_VIEW_ZOOM_VALUE].Value <<= nPageZoomValue;
+ pSettings[SC_PAGE_BREAK_PREVIEW].Name = SC_SHOWPAGEBREAKPREVIEW;
+ pSettings[SC_PAGE_BREAK_PREVIEW].Value <<= bPagebreak;
+
+ pSettings[SC_SHOWZERO].Name = SC_UNO_SHOWZERO;
+ pSettings[SC_SHOWZERO].Value <<= maOptions.GetOption(VOPT_NULLVALS);
+ pSettings[SC_SHOWNOTES].Name = SC_UNO_SHOWNOTES;
+ pSettings[SC_SHOWNOTES].Value <<= maOptions.GetOption(VOPT_NOTES);
+ pSettings[SC_SHOWGRID].Name = SC_UNO_SHOWGRID;
+ pSettings[SC_SHOWGRID].Value <<= maOptions.GetOption(VOPT_GRID);
+ pSettings[SC_GRIDCOLOR].Name = SC_UNO_GRIDCOLOR;
+ OUString aColorName;
+ Color aColor = maOptions.GetGridColor(&aColorName);
+ pSettings[SC_GRIDCOLOR].Value <<= aColor;
+ pSettings[SC_SHOWPAGEBR].Name = SC_UNO_SHOWPAGEBR;
+ pSettings[SC_SHOWPAGEBR].Value <<= maOptions.GetOption(VOPT_PAGEBREAKS);
+ pSettings[SC_COLROWHDR].Name = SC_UNO_COLROWHDR;
+ pSettings[SC_COLROWHDR].Value <<= maOptions.GetOption(VOPT_HEADER);
+ pSettings[SC_SHEETTABS].Name = SC_UNO_SHEETTABS;
+ pSettings[SC_SHEETTABS].Value <<= maOptions.GetOption(VOPT_TABCONTROLS);
+ pSettings[SC_OUTLSYMB].Name = SC_UNO_OUTLSYMB;
+ pSettings[SC_OUTLSYMB].Value <<= maOptions.GetOption(VOPT_OUTLINER);
+ pSettings[SC_VALUE_HIGHLIGHTING].Name = SC_UNO_VALUEHIGH;
+ pSettings[SC_VALUE_HIGHLIGHTING].Value <<= maOptions.GetOption(VOPT_SYNTAX);
+ pSettings[SC_FORMULA_BAR_HEIGHT_VALUE].Name = SC_FORMULABARHEIGHT;
+ pSettings[SC_FORMULA_BAR_HEIGHT_VALUE].Value <<= GetFormulaBarLines();;
+
+ const ScGridOptions& aGridOpt = maOptions.GetGridOptions();
+ pSettings[SC_SNAPTORASTER].Name = SC_UNO_SNAPTORASTER;
+ pSettings[SC_SNAPTORASTER].Value <<= aGridOpt.GetUseGridSnap();
+ pSettings[SC_RASTERVIS].Name = SC_UNO_RASTERVIS;
+ pSettings[SC_RASTERVIS].Value <<= aGridOpt.GetGridVisible();
+ pSettings[SC_RASTERRESX].Name = SC_UNO_RASTERRESX;
+ pSettings[SC_RASTERRESX].Value <<= static_cast<sal_Int32>(aGridOpt.GetFieldDrawX());
+ pSettings[SC_RASTERRESY].Name = SC_UNO_RASTERRESY;
+ pSettings[SC_RASTERRESY].Value <<= static_cast<sal_Int32>(aGridOpt.GetFieldDrawY());
+ pSettings[SC_RASTERSUBX].Name = SC_UNO_RASTERSUBX;
+ pSettings[SC_RASTERSUBX].Value <<= static_cast<sal_Int32>(aGridOpt.GetFieldDivisionX());
+ pSettings[SC_RASTERSUBY].Name = SC_UNO_RASTERSUBY;
+ pSettings[SC_RASTERSUBY].Value <<= static_cast<sal_Int32>(aGridOpt.GetFieldDivisionY());
+ pSettings[SC_RASTERSYNC].Name = SC_UNO_RASTERSYNC;
+ pSettings[SC_RASTERSYNC].Value <<= aGridOpt.GetSynchronize();
+
+ // Common SdrModel processing
+ GetDocument().GetDrawLayer()->WriteUserDataSequence(rSettings);
+}
+
+void ScViewData::ReadUserDataSequence(const uno::Sequence <beans::PropertyValue>& rSettings)
+{
+ std::vector<bool> aHasZoomVect( GetDocument().GetTableCount(), false );
+
+ sal_Int32 nTemp32(0);
+ sal_Int16 nTemp16(0);
+ sal_Int16 nFormulaBarLineCount(0);
+ bool bPageMode(false);
+
+ EnsureTabDataSize(GetDocument().GetTableCount());
+
+ for (const auto& rSetting : rSettings)
+ {
+ // SC_VIEWID has to parse and use by mba
+ OUString sName(rSetting.Name);
+ if (sName == SC_TABLES)
+ {
+ uno::Reference<container::XNameContainer> xNameContainer;
+ if ((rSetting.Value >>= xNameContainer) && xNameContainer->hasElements())
+ {
+ const uno::Sequence< OUString > aNames(xNameContainer->getElementNames());
+ for (const OUString& sTabName : aNames)
+ {
+ SCTAB nTab(0);
+ if (GetDocument().GetTable(sTabName, nTab))
+ {
+ uno::Any aAny = xNameContainer->getByName(sTabName);
+ uno::Sequence<beans::PropertyValue> aTabSettings;
+ if (aAny >>= aTabSettings)
+ {
+ EnsureTabDataSize(nTab + 1);
+ if (!maTabData[nTab])
+ maTabData[nTab].reset(new ScViewDataTable(&mrDoc));
+
+ bool bHasZoom = false;
+ maTabData[nTab]->ReadUserDataSequence(aTabSettings, *this, nTab, bHasZoom);
+ aHasZoomVect[nTab] = bHasZoom;
+ }
+ }
+ }
+ }
+ }
+ else if (sName == SC_ACTIVETABLE)
+ {
+ OUString sTabName;
+ if(rSetting.Value >>= sTabName)
+ {
+ SCTAB nTab(0);
+ if (GetDocument().GetTable(sTabName, nTab))
+ nTabNo = nTab;
+ }
+ }
+ else if (sName == SC_HORIZONTALSCROLLBARWIDTH)
+ {
+ if (rSetting.Value >>= nTemp32)
+ pView->SetTabBarWidth(nTemp32);
+ }
+ else if (sName == SC_RELHORIZONTALTABBARWIDTH)
+ {
+ double fWidth = 0.0;
+ if (rSetting.Value >>= fWidth)
+ pView->SetPendingRelTabBarWidth( fWidth );
+ }
+ else if (sName == SC_ZOOMTYPE)
+ {
+ if (rSetting.Value >>= nTemp16)
+ eDefZoomType = SvxZoomType(nTemp16);
+ }
+ else if (sName == SC_ZOOMVALUE)
+ {
+ if (rSetting.Value >>= nTemp32)
+ {
+ Fraction aZoom(nTemp32, 100);
+ aDefZoomX = aDefZoomY = aZoom;
+ }
+ }
+ else if (sName == SC_PAGEVIEWZOOMVALUE)
+ {
+ if (rSetting.Value >>= nTemp32)
+ {
+ Fraction aZoom(nTemp32, 100);
+ aDefPageZoomX = aDefPageZoomY = aZoom;
+ }
+ }
+ else if (sName == SC_FORMULABARHEIGHT)
+ {
+ if (rSetting.Value >>= nFormulaBarLineCount)
+ {
+ SetFormulaBarLines(nFormulaBarLineCount);
+ // Notify formula bar about changed lines
+ ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl();
+ if (pInputHdl)
+ {
+ ScInputWindow* pInputWin = pInputHdl->GetInputWindow();
+ if (pInputWin)
+ pInputWin->NumLinesChanged();
+ }
+ }
+ }
+ else if (sName == SC_SHOWPAGEBREAKPREVIEW)
+ bPageMode = ScUnoHelpFunctions::GetBoolFromAny( rSetting.Value );
+ else if ( sName == SC_UNO_SHOWZERO )
+ maOptions.SetOption(VOPT_NULLVALS, ScUnoHelpFunctions::GetBoolFromAny(rSetting.Value));
+ else if ( sName == SC_UNO_SHOWNOTES )
+ maOptions.SetOption(VOPT_NOTES, ScUnoHelpFunctions::GetBoolFromAny(rSetting.Value));
+ else if ( sName == SC_UNO_SHOWGRID )
+ maOptions.SetOption(VOPT_GRID, ScUnoHelpFunctions::GetBoolFromAny(rSetting.Value));
+ else if ( sName == SC_UNO_GRIDCOLOR )
+ {
+ Color aColor;
+ if (rSetting.Value >>= aColor)
+ {
+ // #i47435# set automatic grid color explicitly
+ if( aColor == COL_AUTO )
+ aColor = SC_STD_GRIDCOLOR;
+ maOptions.SetGridColor(aColor, OUString());
+ }
+ }
+ else if ( sName == SC_UNO_SHOWPAGEBR )
+ maOptions.SetOption(VOPT_PAGEBREAKS, ScUnoHelpFunctions::GetBoolFromAny(rSetting.Value));
+ else if ( sName == SC_UNO_COLROWHDR )
+ maOptions.SetOption(VOPT_HEADER, ScUnoHelpFunctions::GetBoolFromAny(rSetting.Value));
+ else if ( sName == SC_UNO_SHEETTABS )
+ maOptions.SetOption(VOPT_TABCONTROLS, ScUnoHelpFunctions::GetBoolFromAny(rSetting.Value));
+ else if ( sName == SC_UNO_OUTLSYMB )
+ maOptions.SetOption(VOPT_OUTLINER, ScUnoHelpFunctions::GetBoolFromAny(rSetting.Value));
+ else if ( sName == SC_UNO_SHOWOBJ )
+ {
+ // #i80528# placeholders not supported anymore
+ if ( rSetting.Value >>= nTemp16 )
+ maOptions.SetObjMode(VOBJ_TYPE_OLE, (nTemp16 == 1) ? VOBJ_MODE_HIDE : VOBJ_MODE_SHOW);
+ }
+ else if ( sName == SC_UNO_SHOWCHARTS )
+ {
+ // #i80528# placeholders not supported anymore
+ if ( rSetting.Value >>= nTemp16 )
+ maOptions.SetObjMode(VOBJ_TYPE_CHART, (nTemp16 == 1) ? VOBJ_MODE_HIDE : VOBJ_MODE_SHOW);
+ }
+ else if ( sName == SC_UNO_SHOWDRAW )
+ {
+ // #i80528# placeholders not supported anymore
+ if ( rSetting.Value >>= nTemp16 )
+ maOptions.SetObjMode(VOBJ_TYPE_DRAW, (nTemp16 == 1) ? VOBJ_MODE_HIDE : VOBJ_MODE_SHOW);
+ }
+ else if ( sName == SC_UNO_VALUEHIGH )
+ maOptions.SetOption(VOPT_SYNTAX, ScUnoHelpFunctions::GetBoolFromAny(rSetting.Value));
+ else
+ {
+ ScGridOptions aGridOpt(maOptions.GetGridOptions());
+ if ( sName == SC_UNO_SNAPTORASTER )
+ aGridOpt.SetUseGridSnap( ScUnoHelpFunctions::GetBoolFromAny( rSetting.Value ) );
+ else if ( sName == SC_UNO_RASTERVIS )
+ aGridOpt.SetGridVisible( ScUnoHelpFunctions::GetBoolFromAny( rSetting.Value ) );
+ else if ( sName == SC_UNO_RASTERRESX )
+ aGridOpt.SetFieldDrawX( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( rSetting.Value ) ) );
+ else if ( sName == SC_UNO_RASTERRESY )
+ aGridOpt.SetFieldDrawY( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( rSetting.Value ) ) );
+ else if ( sName == SC_UNO_RASTERSUBX )
+ aGridOpt.SetFieldDivisionX( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( rSetting.Value ) ) );
+ else if ( sName == SC_UNO_RASTERSUBY )
+ aGridOpt.SetFieldDivisionY( static_cast <sal_uInt32> ( ScUnoHelpFunctions::GetInt32FromAny( rSetting.Value ) ) );
+ else if ( sName == SC_UNO_RASTERSYNC )
+ aGridOpt.SetSynchronize( ScUnoHelpFunctions::GetBoolFromAny( rSetting.Value ) );
+ // Fallback to common SdrModel processing
+ else GetDocument().GetDrawLayer()->ReadUserDataSequenceValue(&rSetting);
+
+ maOptions.SetGridOptions(aGridOpt);
+ }
+ }
+
+ // copy default zoom to sheets where a different one wasn't specified
+ for (SCTAB nZoomTab=0; nZoomTab< static_cast<SCTAB>(maTabData.size()); ++nZoomTab)
+ if (maTabData[nZoomTab] && ( nZoomTab >= static_cast<SCTAB>(aHasZoomVect.size()) || !aHasZoomVect[nZoomTab] ))
+ {
+ maTabData[nZoomTab]->eZoomType = eDefZoomType;
+ maTabData[nZoomTab]->aZoomX = aDefZoomX;
+ maTabData[nZoomTab]->aZoomY = aDefZoomY;
+ maTabData[nZoomTab]->aPageZoomX = aDefPageZoomX;
+ maTabData[nZoomTab]->aPageZoomY = aDefPageZoomY;
+ }
+
+ if (rSettings.hasElements())
+ SetPagebreakMode( bPageMode );
+
+ // #i47426# write view options to document, needed e.g. for Excel export
+ mrDoc.SetViewOptions(maOptions);
+
+ if (comphelper::LibreOfficeKit::isActive())
+ DeriveLOKFreezeAllSheets();
+}
+
+void ScViewData::SetOptions( const ScViewOptions& rOpt )
+{
+ // if visibility of horizontal ScrollBar is changed, TabBar may have to be resized...
+ bool bHScrollChanged = (rOpt.GetOption(VOPT_HSCROLL) != maOptions.GetOption(VOPT_HSCROLL));
+
+ // if graphics are turned on or off, animation has to be started or stopped
+ // graphics are controlled by VOBJ_TYPE_OLE
+ bool bGraphicsChanged = (maOptions.GetObjMode(VOBJ_TYPE_OLE) !=
+ rOpt.GetObjMode(VOBJ_TYPE_OLE) );
+
+ maOptions = rOpt;
+ OSL_ENSURE( pView, "No View" );
+
+ if( pView )
+ {
+ pView->ViewOptionsHasChanged( bHScrollChanged, bGraphicsChanged );
+ }
+}
+
+Point ScViewData::GetMousePosPixel()
+{
+ OSL_ENSURE( pView, "GetMousePosPixel() without View" );
+ return pView->GetMousePosPixel();
+}
+
+void ScViewData::UpdateInputHandler( bool bForce )
+{
+ if (pView)
+ pView->UpdateInputHandler(bForce);
+}
+
+bool ScViewData::IsOle() const
+{
+ return pDocShell && pDocShell->IsOle();
+}
+
+bool ScViewData::UpdateFixX( SCTAB nTab ) // true = value changed
+{
+ if (!ValidTab(nTab)) // Default
+ nTab=nTabNo; // current table
+
+ if (!pView || maTabData[nTab]->eHSplitMode != SC_SPLIT_FIX)
+ return false;
+
+ ScDocument& rLocalDoc = GetDocument();
+ if (!rLocalDoc.HasTable(nTab)) // if called from reload, the sheet may not exist
+ return false;
+
+ SCCOL nFix = maTabData[nTab]->nFixPosX;
+ tools::Long nNewPos = 0;
+ for (SCCOL nX=maTabData[nTab]->nPosX[SC_SPLIT_LEFT]; nX<nFix; nX++)
+ {
+ sal_uInt16 nTSize = rLocalDoc.GetColWidth( nX, nTab );
+ if (nTSize)
+ {
+ tools::Long nPix = ToPixel( nTSize, nPPTX );
+ nNewPos += nPix;
+ }
+ }
+ nNewPos += pView->GetGridOffset().X();
+ if (nNewPos != maTabData[nTab]->nHSplitPos)
+ {
+ maTabData[nTab]->nHSplitPos = nNewPos;
+ if (nTab == nTabNo)
+ RecalcPixPos(); // should not be needed
+ return true;
+ }
+
+ return false;
+}
+
+bool ScViewData::UpdateFixY( SCTAB nTab ) // true = value changed
+{
+ if (!ValidTab(nTab)) // Default
+ nTab=nTabNo; // current table
+
+ if (!pView || maTabData[nTab]->eVSplitMode != SC_SPLIT_FIX)
+ return false;
+
+ ScDocument& rLocalDoc = GetDocument();
+ if (!rLocalDoc.HasTable(nTab)) // if called from reload, the sheet may not exist
+ return false;
+
+ SCROW nFix = maTabData[nTab]->nFixPosY;
+ tools::Long nNewPos = 0;
+ for (SCROW nY=maTabData[nTab]->nPosY[SC_SPLIT_TOP]; nY<nFix; nY++)
+ {
+ sal_uInt16 nTSize = rLocalDoc.GetRowHeight( nY, nTab );
+ if (nTSize)
+ {
+ tools::Long nPix = ToPixel( nTSize, nPPTY );
+ nNewPos += nPix;
+ }
+ }
+ nNewPos += pView->GetGridOffset().Y();
+ if (nNewPos != maTabData[nTab]->nVSplitPos)
+ {
+ maTabData[nTab]->nVSplitPos = nNewPos;
+ if (nTab == nTabNo)
+ RecalcPixPos(); // should not be needed
+ return true;
+ }
+
+ return false;
+}
+
+void ScViewData::UpdateOutlinerFlags( Outliner& rOutl ) const
+{
+ ScDocument& rLocalDoc = GetDocument();
+ bool bOnlineSpell = rLocalDoc.GetDocOptions().IsAutoSpell();
+
+ EEControlBits nCntrl = rOutl.GetControlWord();
+ nCntrl |= EEControlBits::MARKNONURLFIELDS;
+ nCntrl &= ~EEControlBits::MARKURLFIELDS; // URLs not shaded for output
+ nCntrl |= EEControlBits::AUTOCORRECT;
+ if( bOnlineSpell )
+ nCntrl |= EEControlBits::ONLINESPELLING;
+ else
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+ rOutl.SetControlWord(nCntrl);
+
+ rOutl.SetCalcFieldValueHdl( LINK( SC_MOD(), ScModule, CalcFieldValueHdl ) );
+
+ // don't call GetSpellChecker if online spelling isn't enabled.
+ // The language for AutoCorrect etc. is taken from the pool defaults
+ // (set in ScDocument::UpdateDrawLanguages)
+
+ if ( bOnlineSpell )
+ {
+ css::uno::Reference<css::linguistic2::XSpellChecker1> xXSpellChecker1( LinguMgr::GetSpellChecker() );
+ rOutl.SetSpeller( xXSpellChecker1 );
+ }
+
+ rOutl.SetDefaultHorizontalTextDirection(
+ rLocalDoc.GetEditTextDirection( nTabNo ) );
+}
+
+ScAddress ScViewData::GetCurPos() const
+{
+ return ScAddress( GetCurX(), GetCurY(), GetTabNo() );
+}
+
+void ScViewData::SetRefStart( SCCOL nNewX, SCROW nNewY, SCTAB nNewZ )
+{
+ nRefStartX = nNewX; nRefStartY = nNewY; nRefStartZ = nNewZ;
+}
+
+void ScViewData::SetRefEnd( SCCOL nNewX, SCROW nNewY, SCTAB nNewZ )
+{
+ nRefEndX = nNewX; nRefEndY = nNewY; nRefEndZ = nNewZ;
+}
+
+void ScViewData::AddPixelsWhile( tools::Long & rScrY, tools::Long nEndPixels, SCROW & rPosY,
+ SCROW nEndRow, double nPPTY, const ScDocument * pDoc, SCTAB nTabNo )
+{
+ SCROW nRow = rPosY;
+ while (rScrY <= nEndPixels && nRow <= nEndRow)
+ {
+ SCROW nHeightEndRow;
+ sal_uInt16 nHeight = pDoc->GetRowHeight( nRow, nTabNo, nullptr, &nHeightEndRow);
+ if (nHeightEndRow > nEndRow)
+ nHeightEndRow = nEndRow;
+ if (!nHeight)
+ {
+ if (ValidTab(nTabNo) && nTabNo <= pDoc->GetMaxTableNumber())
+ nRow = nHeightEndRow + 1;
+ else
+ break;
+ }
+ else
+ {
+ SCROW nRows = nHeightEndRow - nRow + 1;
+ sal_Int64 nPixel = ToPixel( nHeight, nPPTY);
+ sal_Int64 nAdd = nPixel * nRows;
+ if (nAdd + rScrY > nEndPixels)
+ {
+ sal_Int64 nDiff = rScrY + nAdd - nEndPixels;
+ nRows -= static_cast<SCROW>(nDiff / nPixel);
+ nAdd = nPixel * nRows;
+ // We're looking for a value that satisfies loop condition.
+ if (nAdd + rScrY <= nEndPixels)
+ {
+ ++nRows;
+ nAdd += nPixel;
+ }
+ }
+ rScrY += static_cast<tools::Long>(nAdd);
+ nRow += nRows;
+ }
+ }
+ if (nRow > rPosY)
+ --nRow;
+ rPosY = nRow;
+}
+
+void ScViewData::AddPixelsWhileBackward( tools::Long & rScrY, tools::Long nEndPixels,
+ SCROW & rPosY, SCROW nStartRow, double nPPTY, const ScDocument * pDoc,
+ SCTAB nTabNo )
+{
+ SCROW nRow = rPosY;
+ while (rScrY <= nEndPixels && nRow >= nStartRow)
+ {
+ SCROW nHeightStartRow;
+ sal_uInt16 nHeight = pDoc->GetRowHeight( nRow, nTabNo, &nHeightStartRow, nullptr);
+ if (nHeightStartRow < nStartRow)
+ nHeightStartRow = nStartRow;
+ if (!nHeight)
+ nRow = nHeightStartRow - 1;
+ else
+ {
+ SCROW nRows = nRow - nHeightStartRow + 1;
+ sal_Int64 nPixel = ToPixel( nHeight, nPPTY);
+ sal_Int64 nAdd = nPixel * nRows;
+ if (nAdd + rScrY > nEndPixels)
+ {
+ sal_Int64 nDiff = nAdd + rScrY - nEndPixels;
+ nRows -= static_cast<SCROW>(nDiff / nPixel);
+ nAdd = nPixel * nRows;
+ // We're looking for a value that satisfies loop condition.
+ if (nAdd + rScrY <= nEndPixels)
+ {
+ ++nRows;
+ nAdd += nPixel;
+ }
+ }
+ rScrY += static_cast<tools::Long>(nAdd);
+ nRow -= nRows;
+ }
+ }
+ if (nRow < rPosY)
+ ++nRow;
+ rPosY = nRow;
+}
+
+SCCOLROW ScViewData::GetLOKSheetFreezeIndex(bool bIsCol) const
+{
+ SCCOLROW nFreezeIndex = bIsCol ? mrDoc.GetLOKFreezeCol(nTabNo) : mrDoc.GetLOKFreezeRow(nTabNo);
+ return nFreezeIndex >= 0 ? nFreezeIndex : 0;
+}
+
+bool ScViewData::SetLOKSheetFreezeIndex(const SCCOLROW nFreezeIndex, bool bIsCol, SCTAB nForTab)
+{
+ if (nForTab == -1)
+ {
+ nForTab = nTabNo;
+ }
+ else if (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size())))
+ {
+ SAL_WARN("sc.viewdata", "ScViewData::SetLOKSheetFreezeIndex : invalid nForTab = " << nForTab);
+ return false;
+ }
+
+ return bIsCol ? mrDoc.SetLOKFreezeCol(static_cast<SCCOL>(nFreezeIndex), nForTab)
+ : mrDoc.SetLOKFreezeRow(static_cast<SCROW>(nFreezeIndex), nForTab);
+}
+
+bool ScViewData::RemoveLOKFreeze()
+{
+ bool colUnfreezed = SetLOKSheetFreezeIndex(0, true);
+ bool rowUnfreezed = SetLOKSheetFreezeIndex(0, false);
+ return colUnfreezed || rowUnfreezed;
+}
+
+void ScViewData::DeriveLOKFreezeAllSheets()
+{
+ SCTAB nMaxTab = static_cast<SCTAB>(maTabData.size()) - 1;
+ for (SCTAB nTab = 0; nTab <= nMaxTab; ++nTab)
+ DeriveLOKFreezeIfNeeded(nTab);
+}
+
+void ScViewData::DeriveLOKFreezeIfNeeded(SCTAB nForTab)
+{
+ if (!ValidTab(nForTab) || (nForTab >= static_cast<SCTAB>(maTabData.size())))
+ {
+ SAL_WARN("sc.viewdata", "ScViewData::DeriveLOKFreezeIfNeeded : invalid nForTab = " << nForTab);
+ return;
+ }
+
+ ScViewDataTable* pViewTable = maTabData[nForTab].get();
+ if (!pViewTable)
+ return;
+
+ bool bConvertToFreezeX = false;
+ bool bConvertToFreezeY = false;
+ SCCOL nFreezeCol = mrDoc.GetLOKFreezeCol(nForTab);
+ SCROW nFreezeRow = mrDoc.GetLOKFreezeRow(nForTab);
+
+ if (nFreezeCol == -1)
+ {
+ ScSplitMode eSplitMode = pViewTable->eHSplitMode;
+ if (eSplitMode == SC_SPLIT_FIX)
+ nFreezeCol = pViewTable->nFixPosX;
+ else if (eSplitMode == SC_SPLIT_NORMAL)
+ bConvertToFreezeX = true;
+ else
+ nFreezeCol = 0;
+ }
+
+ if (nFreezeRow == -1)
+ {
+ ScSplitMode eSplitMode = pViewTable->eVSplitMode;
+ if (eSplitMode == SC_SPLIT_FIX)
+ nFreezeRow = pViewTable->nFixPosY;
+ else if (eSplitMode == SC_SPLIT_NORMAL)
+ bConvertToFreezeY = true;
+ else
+ nFreezeRow = 0;
+ }
+
+ if (bConvertToFreezeX || bConvertToFreezeY)
+ {
+ SCCOL nCol;
+ SCROW nRow;
+ GetPosFromPixel(bConvertToFreezeX ? pViewTable->nHSplitPos : 0,
+ bConvertToFreezeY ? pViewTable->nVSplitPos : 0,
+ SC_SPLIT_BOTTOMLEFT, nCol, nRow,
+ false /* bTestMerge */, false /* bRepair */,
+ nForTab);
+ if (bConvertToFreezeX)
+ nFreezeCol = nCol;
+ if (bConvertToFreezeY)
+ nFreezeRow = nRow;
+ }
+
+ mrDoc.SetLOKFreezeCol(nFreezeCol, nForTab);
+ mrDoc.SetLOKFreezeRow(nFreezeRow, nForTab);
+}
+
+void ScViewData::OverrideWithLOKFreeze(ScSplitMode& eExHSplitMode, ScSplitMode& eExVSplitMode,
+ SCCOL& nExFixPosX, SCROW& nExFixPosY,
+ tools::Long& nExHSplitPos, tools::Long& nExVSplitPos, SCTAB nForTab) const
+{
+ SCCOL nFreezeCol = mrDoc.GetLOKFreezeCol(nForTab);
+ SCROW nFreezeRow = mrDoc.GetLOKFreezeRow(nForTab);
+
+ bool bConvertToScrPosX = false;
+ bool bConvertToScrPosY = false;
+
+ if (nFreezeCol >= 0)
+ {
+ if (eExHSplitMode == SC_SPLIT_NONE)
+ eExHSplitMode = SC_SPLIT_FIX;
+
+ if (eExHSplitMode == SC_SPLIT_FIX)
+ {
+ nExFixPosX = nFreezeCol;
+ pThisTab->nPosX[SC_SPLIT_RIGHT] = nFreezeCol;
+ }
+ else
+ bConvertToScrPosX = true;
+ }
+
+ if (nFreezeRow >= 0)
+ {
+ if (eExVSplitMode == SC_SPLIT_NONE)
+ eExVSplitMode = SC_SPLIT_FIX;
+
+ if (eExVSplitMode == SC_SPLIT_FIX)
+ {
+ nExFixPosY = nFreezeRow;
+ pThisTab->nPosY[SC_SPLIT_BOTTOM] = nFreezeRow;
+ }
+ else
+ bConvertToScrPosY = true;
+ }
+
+ if (bConvertToScrPosX || bConvertToScrPosY)
+ {
+ Point aExSplitPos = GetScrPos(nFreezeCol, nFreezeRow, SC_SPLIT_BOTTOMLEFT, true, nForTab);
+ if (bConvertToScrPosX)
+ nExHSplitPos = aExSplitPos.X();
+ if (bConvertToScrPosY)
+ nExVSplitPos = aExSplitPos.Y();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/viewfun2.cxx b/sc/source/ui/view/viewfun2.cxx
new file mode 100644
index 000000000..dbee405f1
--- /dev/null
+++ b/sc/source/ui/view/viewfun2.cxx
@@ -0,0 +1,3464 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source eCode Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+
+#include <sfx2/app.hxx>
+#include <editeng/borderline.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/lineitem.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <svl/srchitem.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/objitem.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/numformat.hxx>
+#include <svl/stritem.hxx>
+#include <svl/zforlist.hxx>
+#include <svx/srchdlg.hxx>
+#include <svx/svdview.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <osl/diagnose.h>
+
+#include <viewfunc.hxx>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+
+#include <sc.hrc>
+#include <globstr.hrc>
+#include <scresid.hxx>
+
+#include <attrib.hxx>
+#include <autoform.hxx>
+#include <formulacell.hxx>
+#include <cellmergeoption.hxx>
+#include <compiler.hxx>
+#include <docfunc.hxx>
+#include <docpool.hxx>
+#include <docsh.hxx>
+#include <docoptio.hxx>
+#include <global.hxx>
+#include <patattr.hxx>
+#include <printfun.hxx>
+#include <refundo.hxx>
+#include <table.hxx>
+#include <tablink.hxx>
+#include <tabvwsh.hxx>
+#include <uiitems.hxx>
+#include <undoblk.hxx>
+#include <undotab.hxx>
+#include <sizedev.hxx>
+#include <editable.hxx>
+#include <docuno.hxx>
+#include <charthelper.hxx>
+#include <tabbgcolor.hxx>
+#include <clipparam.hxx>
+#include <prnsave.hxx>
+#include <searchresults.hxx>
+#include <tokenarray.hxx>
+#include <rowheightcontext.hxx>
+#include <LibreOfficeKit/LibreOfficeKitEnums.h>
+#include <comphelper/lok.hxx>
+#include <mergecellsdialog.hxx>
+#include <sheetevents.hxx>
+#include <columnspanset.hxx>
+
+#include <vector>
+#include <memory>
+#include <boost/property_tree/json_parser.hpp>
+#include <tools/json_writer.hxx>
+
+#include <officecfg/Office/Calc.hxx>
+
+using namespace com::sun::star;
+using ::editeng::SvxBorderLine;
+
+namespace {
+
+void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& rAction)
+{
+ EventDescription aDescription;
+ aDescription.aID = "grid_window";
+ aDescription.aAction = rAction;
+ aDescription.aParameters = std::move(aParameters);
+ aDescription.aParent = "MainWindow";
+ aDescription.aKeyWord = "ScGridWinUIObject";
+
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+}
+
+using ::std::vector;
+using ::std::unique_ptr;
+
+bool ScViewFunc::AdjustBlockHeight( bool bPaint, ScMarkData* pMarkData )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ if (!pMarkData)
+ pMarkData = &GetViewData().GetMarkData();
+
+ ScDocument& rDoc = pDocSh->GetDocument();
+ std::vector<sc::ColRowSpan> aMarkedRows = pMarkData->GetMarkedRowSpans();
+
+ if (aMarkedRows.empty())
+ {
+ SCROW nCurRow = GetViewData().GetCurY();
+ aMarkedRows.emplace_back(nCurRow, nCurRow);
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ SCCOLROW nStart = aMarkedRows[0].mnStart;
+ OnLOKSetWidthOrHeight(nStart, /*width: */ false);
+ }
+
+ double nPPTX = GetViewData().GetPPTX();
+ double nPPTY = GetViewData().GetPPTY();
+ Fraction aZoomX = GetViewData().GetZoomX();
+ Fraction aZoomY = GetViewData().GetZoomY();
+
+ ScSizeDeviceProvider aProv(pDocSh);
+ if (aProv.IsPrinter())
+ {
+ nPPTX = aProv.GetPPTX();
+ nPPTY = aProv.GetPPTY();
+ aZoomX = aZoomY = Fraction( 1, 1 );
+ }
+
+ sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, aZoomX, aZoomY, aProv.GetDevice());
+ bool bAnyChanged = false;
+ for (const SCTAB& nTab : *pMarkData)
+ {
+ bool bChanged = false;
+ SCROW nPaintY = 0;
+ for (const auto& rRow : aMarkedRows)
+ {
+ SCROW nStartNo = rRow.mnStart;
+ SCROW nEndNo = rRow.mnEnd;
+ ScAddress aTopLeft(0, nStartNo, nTab);
+ rDoc.UpdateScriptTypes(aTopLeft, rDoc.GetSheetLimits().GetMaxColCount(), nEndNo-nStartNo+1);
+ if (rDoc.SetOptimalHeight(aCxt, nStartNo, nEndNo, nTab, true))
+ {
+ if (!bChanged)
+ nPaintY = nStartNo;
+ bAnyChanged = bChanged = true;
+ }
+ }
+ // tdf#76183: recalculate objects' positions
+ if (bChanged)
+ rDoc.SetDrawPageSize(nTab);
+ if ( bPaint && bChanged )
+ pDocSh->PostPaint( 0, nPaintY, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab,
+ PaintPartFlags::Grid | PaintPartFlags::Left );
+ }
+
+ if ( bPaint && bAnyChanged )
+ pDocSh->UpdateOle(GetViewData());
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ GetViewData().GetViewShell(),
+ false /* bColumns */, true /* bRows */,
+ true /* bSizes*/, false /* bHidden */, false /* bFiltered */,
+ false /* bGroups */, nTab);
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, nTab);
+ }
+
+ return bAnyChanged;
+}
+
+bool ScViewFunc::AdjustRowHeight( SCROW nStartRow, SCROW nEndRow, bool bApi )
+{
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ OnLOKSetWidthOrHeight(nStartRow, /*width: */ false);
+ }
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ double nPPTX = GetViewData().GetPPTX();
+ double nPPTY = GetViewData().GetPPTY();
+ Fraction aZoomX = GetViewData().GetZoomX();
+ Fraction aZoomY = GetViewData().GetZoomY();
+ sal_uInt16 nOldPixel = 0;
+ if (nStartRow == nEndRow)
+ nOldPixel = static_cast<sal_uInt16>(rDoc.GetRowHeight(nStartRow,nTab) * nPPTY);
+
+ ScSizeDeviceProvider aProv(pDocSh);
+ if (aProv.IsPrinter())
+ {
+ nPPTX = aProv.GetPPTX();
+ nPPTY = aProv.GetPPTY();
+ aZoomX = aZoomY = Fraction( 1, 1 );
+ }
+ sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, aZoomX, aZoomY, aProv.GetDevice());
+ bool bChanged = rDoc.SetOptimalHeight(aCxt, nStartRow, nEndRow, nTab, bApi);
+
+ // tdf#76183: recalculate objects' positions
+ if (bChanged)
+ rDoc.SetDrawPageSize(nTab);
+
+ if (bChanged && ( nStartRow == nEndRow ))
+ {
+ sal_uInt16 nNewPixel = static_cast<sal_uInt16>(rDoc.GetRowHeight(nStartRow,nTab) * nPPTY);
+ if ( nNewPixel == nOldPixel )
+ bChanged = false;
+ }
+
+ if ( bChanged )
+ pDocSh->PostPaint( 0, nStartRow, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab,
+ PaintPartFlags::Grid | PaintPartFlags::Left );
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(
+ GetViewData().GetViewShell(),
+ false /* bColumns */, true /* bRows */,
+ true /* bSizes*/, false /* bHidden */, false /* bFiltered */,
+ false /* bGroups */, nTab);
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNo());
+ }
+
+ return bChanged;
+}
+
+namespace {
+
+enum ScAutoSum
+{
+ ScAutoSumNone = 0,
+ ScAutoSumData,
+ ScAutoSumSum,
+ ScAutoSumAverage,
+ ScAutoSumMax,
+ ScAutoSumMin,
+ ScAutoSumCount,
+ ScAutoSumCountA,
+ ScAutoSumProduct,
+ ScAutoSumStDev,
+ ScAutoSumStDevP,
+ ScAutoSumVar,
+ ScAutoSumVarP,
+ ScAutoSumEnd
+};
+
+}
+
+static ScAutoSum lcl_IsAutoSumData( ScDocument& rDoc, SCCOL nCol, SCROW nRow,
+ SCTAB nTab, ScDirection eDir, SCCOLROW& nExtend )
+{
+ ScRefCellValue aCell(rDoc, ScAddress(nCol, nRow, nTab));
+ if (aCell.hasNumeric())
+ {
+ if (aCell.meType == CELLTYPE_FORMULA)
+ {
+ ScAutoSum val = ScAutoSumNone;
+ ScTokenArray* pCode = aCell.mpFormula->GetCode();
+ if ( pCode )
+ {
+ switch( pCode->GetOuterFuncOpCode() )
+ {
+ case ocSum : val = ScAutoSumSum;
+ break;
+ case ocAverage : val = ScAutoSumAverage;
+ break;
+ case ocMax : val = ScAutoSumMax;
+ break;
+ case ocMin : val = ScAutoSumMin;
+ break;
+ case ocCount : val = ScAutoSumCount;
+ break;
+ case ocCount2 : val = ScAutoSumCountA;
+ break;
+ case ocProduct : val = ScAutoSumProduct;
+ break;
+ case ocStDev : val = ScAutoSumStDev;
+ break;
+ case ocStDevP : val = ScAutoSumStDevP;
+ break;
+ case ocVar : val = ScAutoSumVar;
+ break;
+ case ocVarP : val = ScAutoSumVarP;
+ break;
+ default :
+ break;
+ }
+ if ( pCode->GetAdjacentExtendOfOuterFuncRefs( nExtend,
+ ScAddress( nCol, nRow, nTab ), eDir ) )
+ return val;
+ }
+ }
+ return ScAutoSumData;
+ }
+ return ScAutoSumNone;
+}
+
+#define SC_AUTOSUM_MAXCOUNT 20
+
+static ScAutoSum lcl_SeekAutoSumData( ScDocument& rDoc, SCCOL& nCol, SCROW& nRow,
+ SCTAB nTab, ScDirection eDir, SCCOLROW& nExtend )
+{
+ sal_uInt16 nCount = 0;
+ while (nCount < SC_AUTOSUM_MAXCOUNT)
+ {
+ if ( eDir == DIR_TOP )
+ {
+ if (nRow > 0)
+ --nRow;
+ else
+ return ScAutoSumNone;
+ }
+ else
+ {
+ if (nCol > 0)
+ --nCol;
+ else
+ return ScAutoSumNone;
+ }
+ ScAutoSum eSum;
+ if ( (eSum = lcl_IsAutoSumData(
+ rDoc, nCol, nRow, nTab, eDir, nExtend )) != ScAutoSumNone )
+ return eSum;
+ ++nCount;
+ }
+ return ScAutoSumNone;
+}
+
+#undef SC_AUTOSUM_MAXCOUNT
+
+static bool lcl_FindNextSumEntryInColumn( ScDocument& rDoc, SCCOL nCol, SCROW& nRow,
+ SCTAB nTab, SCCOLROW& nExtend, SCROW nMinRow )
+{
+ const SCROW nTmp = nRow;
+ ScAutoSum eSkip = ScAutoSumNone;
+ for (;;)
+ {
+ eSkip = lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_TOP, nExtend );
+ if (eSkip != ScAutoSumData || nRow <= nMinRow )
+ break;
+ --nRow;
+ }
+ return eSkip >= ScAutoSumSum && nRow < nTmp;
+}
+
+static bool lcl_FindNextSumEntryInRow( ScDocument& rDoc, SCCOL& nCol, SCROW nRow,
+ SCTAB nTab, SCCOLROW& nExtend, SCCOL nMinCol )
+{
+ const SCCOL nTmp = nCol;
+ ScAutoSum eSkip = ScAutoSumNone;
+ for (;;)
+ {
+ eSkip = lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_LEFT, nExtend );
+ if (eSkip != ScAutoSumData || nCol <= nMinCol )
+ break;
+ --nCol;
+ }
+ return eSkip >= ScAutoSumSum && nCol < nTmp;
+}
+
+static ScAutoSum lcl_GetAutoSumForColumnRange( ScDocument& rDoc, ScRangeList& rRangeList, const ScRange& rRange )
+{
+ const ScAddress aStart = rRange.aStart;
+ const ScAddress aEnd = rRange.aEnd;
+ if ( aStart.Col() != aEnd.Col() )
+ {
+ return ScAutoSumNone;
+ }
+
+ const SCTAB nTab = aEnd.Tab();
+ const SCCOL nCol = aEnd.Col();
+ SCROW nEndRow = aEnd.Row();
+ SCROW nStartRow = nEndRow;
+ SCCOLROW nExtend = 0;
+ ScAutoSum eSum = lcl_IsAutoSumData( rDoc, nCol, nEndRow, nTab, DIR_TOP, nExtend /*out*/ );
+
+ if ( eSum >= ScAutoSumSum )
+ {
+ bool bContinue = false;
+ do
+ {
+ rRangeList.push_back( ScRange( nCol, nStartRow, nTab, nCol, nEndRow, nTab ) );
+ nEndRow = static_cast< SCROW >( nExtend );
+ bContinue = lcl_FindNextSumEntryInColumn( rDoc, nCol, nEndRow /*inout*/, nTab, nExtend /*out*/, aStart.Row() );
+ if ( bContinue )
+ {
+ nStartRow = nEndRow;
+ }
+ } while ( bContinue );
+ }
+ else
+ {
+ while ( nStartRow > aStart.Row() )
+ {
+ eSum = lcl_IsAutoSumData( rDoc, nCol, nStartRow-1, nTab, DIR_TOP, nExtend /*out*/ );
+ if (eSum >= ScAutoSumSum )
+ break;
+ --nStartRow;
+ }
+ rRangeList.push_back( ScRange( nCol, nStartRow, nTab, nCol, nEndRow, nTab ) );
+ if (eSum == ScAutoSumNone)
+ eSum = ScAutoSumData;
+ }
+
+ return eSum;
+}
+
+static ScAutoSum lcl_GetAutoSumForRowRange( ScDocument& rDoc, ScRangeList& rRangeList, const ScRange& rRange )
+{
+ const ScAddress aStart = rRange.aStart;
+ const ScAddress aEnd = rRange.aEnd;
+ if ( aStart.Row() != aEnd.Row() )
+ {
+ return ScAutoSumNone;
+ }
+
+ const SCTAB nTab = aEnd.Tab();
+ const SCROW nRow = aEnd.Row();
+ SCCOL nEndCol = aEnd.Col();
+ SCCOL nStartCol = nEndCol;
+ SCCOLROW nExtend = 0;
+ ScAutoSum eSum = lcl_IsAutoSumData( rDoc, nEndCol, nRow, nTab, DIR_LEFT, nExtend /*out*/ );
+
+ if ( eSum >= ScAutoSumSum )
+ {
+ bool bContinue = false;
+ do
+ {
+ rRangeList.push_back( ScRange( nStartCol, nRow, nTab, nEndCol, nRow, nTab ) );
+ nEndCol = static_cast< SCCOL >( nExtend );
+ bContinue = lcl_FindNextSumEntryInRow( rDoc, nEndCol /*inout*/, nRow, nTab, nExtend /*out*/, aStart.Col() );
+ if ( bContinue )
+ {
+ nStartCol = nEndCol;
+ }
+ } while ( bContinue );
+ }
+ else
+ {
+ while ( nStartCol > aStart.Col() )
+ {
+ eSum = lcl_IsAutoSumData( rDoc, nStartCol-1, nRow, nTab, DIR_LEFT, nExtend /*out*/ );
+ if (eSum >= ScAutoSumSum )
+ break;
+ --nStartCol;
+ }
+ rRangeList.push_back( ScRange( nStartCol, nRow, nTab, nEndCol, nRow, nTab ) );
+ if (eSum == ScAutoSumNone)
+ eSum = ScAutoSumData;
+ }
+
+ return eSum;
+}
+
+static sal_Int8 GetSubTotal( const OpCode eCode )
+{
+ sal_Int8 val;
+ switch ( eCode )
+ {
+ case ocSum : val = 9;
+ break;
+ case ocAverage : val = 1;
+ break;
+ case ocMax : val = 4;
+ break;
+ case ocMin : val = 5;
+ break;
+ case ocCount : val = 2;
+ break;
+ case ocCount2 : val = 3;
+ break;
+ case ocProduct : val = 6;
+ break;
+ case ocStDev : val = 7;
+ break;
+ case ocStDevP : val = 8;
+ break;
+ case ocVar : val = 10;
+ break;
+ case ocVarP : val = 11;
+ break;
+ default : val = 9;
+ }
+
+ return val;
+}
+
+bool ScViewFunc::GetAutoSumArea( ScRangeList& rRangeList )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+
+ SCCOL nCol = GetViewData().GetCurX();
+ SCROW nRow = GetViewData().GetCurY();
+
+ SCCOL nStartCol = nCol;
+ SCROW nStartRow = nRow;
+ SCCOL nEndCol = nCol;
+ SCROW nEndRow = nRow;
+ SCCOL nSeekCol = nCol;
+ SCROW nSeekRow = nRow;
+ SCCOLROW nExtend; // will become valid via reference for ScAutoSumSum
+
+ bool bCol = false;
+ bool bRow = false;
+
+ ScAutoSum eSum;
+ if ( nRow != 0
+ && ((eSum = lcl_IsAutoSumData( rDoc, nCol, nRow-1, nTab,
+ DIR_TOP, nExtend /*out*/ )) == ScAutoSumData )
+ && ((eSum = lcl_IsAutoSumData( rDoc, nCol, nRow-1, nTab,
+ DIR_LEFT, nExtend /*out*/ )) == ScAutoSumData )
+ )
+ {
+ bRow = true;
+ nSeekRow = nRow - 1;
+ }
+ else if ( nCol != 0 && (eSum = lcl_IsAutoSumData( rDoc, nCol-1, nRow, nTab,
+ DIR_LEFT, nExtend /*out*/ )) == ScAutoSumData )
+ {
+ bCol = true;
+ nSeekCol = nCol - 1;
+ }
+ else if ( (eSum = lcl_SeekAutoSumData( rDoc, nCol, nSeekRow, nTab, DIR_TOP, nExtend /*out*/ )) != ScAutoSumNone )
+ bRow = true;
+ else if (( eSum = lcl_SeekAutoSumData( rDoc, nSeekCol, nRow, nTab, DIR_LEFT, nExtend /*out*/ )) != ScAutoSumNone )
+ bCol = true;
+
+ if ( bCol || bRow )
+ {
+ if ( bRow )
+ {
+ nStartRow = nSeekRow; // nSeekRow might be adjusted via reference
+ if ( eSum >= ScAutoSumSum && eSum < ScAutoSumEnd )
+ nEndRow = nStartRow; // only sum sums
+ else
+ nEndRow = nRow - 1; // maybe extend data area at bottom
+ }
+ else
+ {
+ nStartCol = nSeekCol; // nSeekCol might be adjusted via reference
+ if ( eSum >= ScAutoSumSum )
+ nEndCol = nStartCol; // only sum sums
+ else
+ nEndCol = nCol - 1; // maybe extend data area to the right
+ }
+ bool bContinue = false;
+ do
+ {
+ if ( eSum == ScAutoSumData )
+ {
+ if ( bRow )
+ {
+ while ( nStartRow != 0 && lcl_IsAutoSumData( rDoc, nCol,
+ nStartRow-1, nTab, DIR_TOP, nExtend /*out*/ ) == eSum )
+ --nStartRow;
+ }
+ else
+ {
+ while ( nStartCol != 0 && lcl_IsAutoSumData( rDoc, nStartCol-1,
+ nRow, nTab, DIR_LEFT, nExtend /*out*/ ) == eSum )
+ --nStartCol;
+ }
+ }
+ rRangeList.push_back(
+ ScRange( nStartCol, nStartRow, nTab, nEndCol, nEndRow, nTab ) );
+ if ( eSum >= ScAutoSumSum )
+ {
+ if ( bRow )
+ {
+ nEndRow = static_cast< SCROW >( nExtend );
+ bContinue = lcl_FindNextSumEntryInColumn( rDoc, nCol, nEndRow /*inout*/, nTab, nExtend /*out*/, 0 );
+ if ( bContinue )
+ {
+ nStartRow = nEndRow;
+ }
+ }
+ else
+ {
+ nEndCol = static_cast< SCCOL >( nExtend );
+ bContinue = lcl_FindNextSumEntryInRow( rDoc, nEndCol /*inout*/, nRow, nTab, nExtend /*out*/, 0 );
+ if ( bContinue )
+ {
+ nStartCol = nEndCol;
+ }
+ }
+ }
+ } while ( bContinue );
+ return true;
+ }
+ return false;
+}
+
+void ScViewFunc::EnterAutoSum(const ScRangeList& rRangeList, bool bSubTotal, const ScAddress& rAddr, const OpCode eCode)
+{
+ OUString aFormula = GetAutoSumFormula( rRangeList, bSubTotal, rAddr , eCode);
+ EnterBlock( aFormula, nullptr );
+}
+
+bool ScViewFunc::AutoSum( const ScRange& rRange, bool bSubTotal, bool bSetCursor, bool bContinue , const OpCode eCode)
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ const SCTAB nTab = rRange.aStart.Tab();
+ SCCOL nStartCol = rRange.aStart.Col();
+ SCROW nStartRow = rRange.aStart.Row();
+ const SCCOL nEndCol = rRange.aEnd.Col();
+ const SCROW nEndRow = rRange.aEnd.Row();
+ SCCOLROW nExtend = 0; // out parameter for lcl_IsAutoSumData
+
+ // ignore rows at the top of the given range which don't contain autosum data
+ bool bRowData = false;
+ for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow )
+ {
+ for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
+ {
+ if ( lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_TOP, nExtend ) != ScAutoSumNone )
+ {
+ bRowData = true;
+ break;
+ }
+ }
+ if ( bRowData )
+ {
+ nStartRow = nRow;
+ break;
+ }
+ }
+ if ( !bRowData )
+ {
+ return false;
+ }
+
+ // ignore columns at the left of the given range which don't contain autosum data
+ bool bColData = false;
+ for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
+ {
+ for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow )
+ {
+ if ( lcl_IsAutoSumData( rDoc, nCol, nRow, nTab, DIR_LEFT, nExtend ) != ScAutoSumNone )
+ {
+ bColData = true;
+ break;
+ }
+ }
+ if ( bColData )
+ {
+ nStartCol = nCol;
+ break;
+ }
+ }
+ if ( !bColData )
+ {
+ return false;
+ }
+
+ const bool bEndRowEmpty = rDoc.IsBlockEmpty( nStartCol, nEndRow, nEndCol, nEndRow, nTab );
+ const bool bEndColEmpty = rDoc.IsBlockEmpty( nEndCol, nStartRow, nEndCol, nEndRow, nTab );
+ bool bRow = ( nStartRow != nEndRow ) && ( bEndRowEmpty || !bEndColEmpty );
+ bool bCol = ( nStartCol != nEndCol ) && ( bEndColEmpty || nStartRow == nEndRow );
+
+ // find an empty row for entering the result
+ SCROW nInsRow = nEndRow;
+ if ( bRow && !bEndRowEmpty )
+ {
+ if ( nInsRow < rDoc.MaxRow() )
+ {
+ ++nInsRow;
+ while ( !rDoc.IsBlockEmpty( nStartCol, nInsRow, nEndCol, nInsRow, nTab ) )
+ {
+ if ( nInsRow < rDoc.MaxRow() )
+ {
+ ++nInsRow;
+ }
+ else
+ {
+ bRow = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ bRow = false;
+ }
+ }
+
+ // find an empty column for entering the result
+ SCCOL nInsCol = nEndCol;
+ if ( bCol && !bEndColEmpty )
+ {
+ if ( nInsCol < rDoc.MaxCol() )
+ {
+ ++nInsCol;
+ while ( !rDoc.IsBlockEmpty( nInsCol, nStartRow, nInsCol, nEndRow, nTab ) )
+ {
+ if ( nInsCol < rDoc.MaxCol() )
+ {
+ ++nInsCol;
+ }
+ else
+ {
+ bCol = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ bCol = false;
+ }
+ }
+
+ if ( !bRow && !bCol )
+ {
+ return false;
+ }
+
+ SCCOL nMarkEndCol = nEndCol;
+ SCROW nMarkEndRow = nEndRow;
+ ScAutoSum eSum = ScAutoSumNone;
+ SCROW nColSums = 0;
+ SCCOL nRowSums = 0;
+ SCROW nColSumsStartRow = 0;
+ SCCOL nRowSumsStartCol = 0;
+
+ if ( bRow )
+ {
+ // calculate the row sums for all columns of the given range
+
+ SCROW nSumEndRow = nEndRow;
+
+ if ( bEndRowEmpty )
+ {
+ // the last row of the given range is empty;
+ // don't take into account for calculating the autosum
+ --nSumEndRow;
+ }
+ else
+ {
+ // increase mark range
+ ++nMarkEndRow;
+ }
+
+ for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
+ {
+ if ( !rDoc.IsBlockEmpty( nCol, nStartRow, nCol, nSumEndRow, nTab ) )
+ {
+ ScRangeList aRangeList;
+ // Include the originally selected start row.
+ const ScRange aRange( nCol, rRange.aStart.Row(), nTab, nCol, nSumEndRow, nTab );
+ if ( (eSum = lcl_GetAutoSumForColumnRange( rDoc, aRangeList, aRange )) != ScAutoSumNone )
+ {
+ if (++nRowSums == 1)
+ nRowSumsStartCol = aRangeList[0].aStart.Col();
+ const OUString aFormula = GetAutoSumFormula(
+ aRangeList, bSubTotal, ScAddress(nCol, nInsRow, nTab), eCode);
+ EnterData( nCol, nInsRow, nTab, aFormula );
+ }
+ }
+ }
+ }
+
+ if ( bCol )
+ {
+ // calculate the column sums for all rows of the given range
+
+ SCCOL nSumEndCol = nEndCol;
+
+ if ( bEndColEmpty )
+ {
+ // the last column of the given range is empty;
+ // don't take into account for calculating the autosum
+ --nSumEndCol;
+ }
+ else
+ {
+ // increase mark range
+ ++nMarkEndCol;
+ }
+
+ for ( SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow )
+ {
+ if ( !rDoc.IsBlockEmpty( nStartCol, nRow, nSumEndCol, nRow, nTab ) )
+ {
+ ScRangeList aRangeList;
+ // Include the originally selected start column.
+ const ScRange aRange( rRange.aStart.Col(), nRow, nTab, nSumEndCol, nRow, nTab );
+ if ( (eSum = lcl_GetAutoSumForRowRange( rDoc, aRangeList, aRange )) != ScAutoSumNone )
+ {
+ if (++nColSums == 1)
+ nColSumsStartRow = aRangeList[0].aStart.Row();
+ const OUString aFormula = GetAutoSumFormula( aRangeList, bSubTotal, ScAddress(nInsCol, nRow, nTab), eCode );
+ EnterData( nInsCol, nRow, nTab, aFormula );
+ }
+ }
+ }
+ }
+
+ // Set new mark range and cursor position.
+ // For sum of sums (and data until sum) mark the actual resulting range if
+ // there is only one, or the data range if more than one. Otherwise use the
+ // original selection. All extended by end column/row where the sum is put.
+ const ScRange aMarkRange(
+ (eSum >= ScAutoSumSum ?
+ (nRowSums == 1 ? nRowSumsStartCol : nStartCol) :
+ rRange.aStart.Col()),
+ (eSum >= ScAutoSumSum ?
+ (nColSums == 1 ? nColSumsStartRow : nStartRow) :
+ rRange.aStart.Row()),
+ nTab, nMarkEndCol, nMarkEndRow, nTab );
+ MarkRange( aMarkRange, false, bContinue );
+ if ( bSetCursor )
+ {
+ SetCursor( nMarkEndCol, nMarkEndRow );
+ }
+
+ return true;
+}
+
+OUString ScViewFunc::GetAutoSumFormula( const ScRangeList& rRangeList, bool bSubTotal, const ScAddress& rAddr , const OpCode eCode)
+{
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScTokenArray aArray(rDoc);
+
+ aArray.AddOpCode(bSubTotal ? ocSubTotal : eCode);
+ aArray.AddOpCode(ocOpen);
+
+ if (bSubTotal)
+ {
+ aArray.AddDouble( GetSubTotal( eCode ) );
+ aArray.AddOpCode(ocSep);
+ }
+
+ if(!rRangeList.empty())
+ {
+ ScRangeList aRangeList = rRangeList;
+ size_t ListSize = aRangeList.size();
+ for ( size_t i = 0; i < ListSize; ++i )
+ {
+ const ScRange & r = aRangeList[i];
+ if (i != 0)
+ aArray.AddOpCode(ocSep);
+ ScComplexRefData aRef;
+ aRef.InitRangeRel(rDoc, r, rAddr);
+ aArray.AddDoubleReference(aRef);
+ }
+ }
+
+ aArray.AddOpCode(ocClose);
+
+ ScCompiler aComp(rDoc, rAddr, aArray, rDoc.GetGrammar());
+ OUStringBuffer aBuf;
+ aComp.CreateStringFromTokenArray(aBuf);
+ OUString aFormula = aBuf.makeStringAndClear();
+ aBuf.append('=');
+ aBuf.append(aFormula);
+ return aBuf.makeStringAndClear();
+}
+
+void ScViewFunc::EnterBlock( const OUString& rString, const EditTextObject* pData )
+{
+ // test for multi selection
+
+ SCCOL nCol = GetViewData().GetCurX();
+ SCROW nRow = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ if ( rMark.IsMultiMarked() )
+ {
+ rMark.MarkToSimple();
+ if ( rMark.IsMultiMarked() )
+ { // "Insert into multi selection not possible"
+ ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
+
+ // insert into single cell
+ if ( pData )
+ EnterData(nCol, nRow, nTab, *pData);
+ else
+ EnterData( nCol, nRow, nTab, rString );
+ return;
+ }
+ }
+
+ if (GetViewData().SelectionForbidsCellFill())
+ {
+ PaintArea(nCol, nRow, nCol, nRow); // possibly the edit-engine is still painted there
+ return;
+ }
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ OUString aNewStr = rString;
+ if ( pData )
+ {
+ const ScPatternAttr* pOldPattern = rDoc.GetPattern( nCol, nRow, nTab );
+ ScTabEditEngine aEngine( *pOldPattern, rDoc.GetEnginePool(), &rDoc );
+ aEngine.SetTextCurrentDefaults(*pData);
+
+ ScEditAttrTester aTester( &aEngine );
+ if (!aTester.NeedsObject())
+ {
+ aNewStr = aEngine.GetText();
+ pData = nullptr;
+ }
+ }
+
+ // Insert via PasteFromClip
+ weld::WaitObject aWait(GetViewData().GetDialogParent());
+
+ ScAddress aPos( nCol, nRow, nTab );
+
+ ScDocumentUniquePtr pInsDoc(new ScDocument( SCDOCMODE_CLIP ));
+ pInsDoc->ResetClip( &rDoc, nTab );
+
+ if (aNewStr[0] == '=') // Formula ?
+ {
+ // SetString not possible, because in Clipboard-Documents nothing will be compiled!
+ pInsDoc->SetFormulaCell(aPos, new ScFormulaCell(rDoc, aPos, aNewStr));
+ }
+ else if ( pData )
+ {
+ // A copy of pData will be stored.
+ pInsDoc->SetEditText(aPos, *pData, rDoc.GetEditPool());
+ }
+ else
+ pInsDoc->SetString( nCol, nRow, nTab, aNewStr );
+
+ pInsDoc->SetClipArea( ScRange(aPos) );
+ // insert Block, with Undo etc.
+ if ( !PasteFromClip( InsertDeleteFlags::CONTENTS, pInsDoc.get(), ScPasteFunc::NONE, false, false,
+ false, INS_NONE, InsertDeleteFlags::ATTRIB ) )
+ return;
+
+ const SfxUInt32Item* pItem = pInsDoc->GetAttr(
+ nCol, nRow, nTab, ATTR_VALUE_FORMAT );
+ if ( pItem )
+ { // set number format if incompatible
+ // MarkData was already MarkToSimple'ed in PasteFromClip
+ const ScRange& aRange = rMark.GetMarkArea();
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( *pItem );
+ SvNumFormatType nNewType = rDoc.GetFormatTable()->GetType( pItem->GetValue() );
+ rDoc.ApplyPatternIfNumberformatIncompatible( aRange, rMark,
+ aPattern, nNewType );
+ }
+}
+
+// manual page break
+
+void ScViewFunc::InsertPageBreak( bool bColumn, bool bRecord, const ScAddress* pPos,
+ bool bSetModified )
+{
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScAddress aCursor;
+ if (pPos)
+ aCursor = *pPos;
+ else
+ aCursor = ScAddress( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab );
+
+ bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
+ InsertPageBreak( bColumn, aCursor, bRecord, bSetModified );
+
+ if ( bSuccess && bSetModified )
+ UpdatePageBreakData( true ); // for PageBreak-Mode
+}
+
+void ScViewFunc::DeletePageBreak( bool bColumn, bool bRecord, const ScAddress* pPos,
+ bool bSetModified )
+{
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScAddress aCursor;
+ if (pPos)
+ aCursor = *pPos;
+ else
+ aCursor = ScAddress( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab );
+
+ bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
+ RemovePageBreak( bColumn, aCursor, bRecord, bSetModified );
+
+ if ( bSuccess && bSetModified )
+ UpdatePageBreakData( true ); // for PageBreak-Mode
+}
+
+void ScViewFunc::RemoveManualBreaks()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ if (bUndo)
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true, true );
+ rDoc.CopyToDocument( 0,0,nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRemoveBreaks>( pDocSh, nTab, std::move(pUndoDoc) ) );
+ }
+
+ rDoc.RemoveManualBreaks(nTab);
+ rDoc.UpdatePageBreaks(nTab);
+
+ UpdatePageBreakData( true );
+ pDocSh->SetDocumentModified();
+ pDocSh->PostPaint( 0,0,nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid );
+}
+
+void ScViewFunc::SetPrintZoom(sal_uInt16 nScale)
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ SCTAB nTab = GetViewData().GetTabNo();
+ pDocSh->SetPrintZoom( nTab, nScale, 0/*nPages*/ );
+}
+
+void ScViewFunc::AdjustPrintZoom()
+{
+ ScRange aRange;
+ if ( GetViewData().GetSimpleArea( aRange ) != SC_MARK_SIMPLE )
+ aRange = GetViewData().GetMarkData().GetMultiMarkArea();
+ GetViewData().GetDocShell()->AdjustPrintZoom( aRange );
+}
+
+void ScViewFunc::SetPrintRanges( bool bEntireSheet, const OUString* pPrint,
+ const OUString* pRepCol, const OUString* pRepRow,
+ bool bAddPrint )
+{
+ // on all selected tables
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ bool bUndo (rDoc.IsUndoEnabled());
+
+ std::unique_ptr<ScPrintRangeSaver> pOldRanges = rDoc.CreatePrintRangeSaver();
+
+ ScAddress::Details aDetails(rDoc.GetAddressConvention(), 0, 0);
+
+ for (const SCTAB& nTab : rMark)
+ {
+ ScRange aRange( 0,0,nTab );
+
+ // print ranges
+
+ if( !bAddPrint )
+ rDoc.ClearPrintRanges( nTab );
+
+ if( bEntireSheet )
+ {
+ rDoc.SetPrintEntireSheet( nTab );
+ }
+ else if ( pPrint )
+ {
+ if ( !pPrint->isEmpty() )
+ {
+ const sal_Unicode sep = ScCompiler::GetNativeSymbolChar(ocSep);
+ sal_Int32 nPos = 0;
+ do
+ {
+ const OUString aToken = pPrint->getToken(0, sep, nPos);
+ if ( aRange.ParseAny( aToken, rDoc, aDetails ) & ScRefFlags::VALID )
+ rDoc.AddPrintRange( nTab, aRange );
+ }
+ while (nPos >= 0);
+ }
+ }
+ else // NULL = use selection (print range is always set), use empty string to delete all ranges
+ {
+ if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
+ {
+ rDoc.AddPrintRange( nTab, aRange );
+ }
+ else if ( rMark.IsMultiMarked() )
+ {
+ rMark.MarkToMulti();
+ ScRangeListRef pList( new ScRangeList );
+ rMark.FillRangeListWithMarks( pList.get(), false );
+ for (size_t i = 0, n = pList->size(); i < n; ++i)
+ {
+ const ScRange & rR = (*pList)[i];
+ rDoc.AddPrintRange(nTab, rR);
+ }
+ }
+ }
+
+ // repeat columns
+
+ if ( pRepCol )
+ {
+ if ( pRepCol->isEmpty() )
+ rDoc.SetRepeatColRange( nTab, std::nullopt );
+ else
+ if ( aRange.ParseAny( *pRepCol, rDoc, aDetails ) & ScRefFlags::VALID )
+ rDoc.SetRepeatColRange( nTab, std::move(aRange) );
+ }
+
+ // repeat rows
+
+ if ( pRepRow )
+ {
+ if ( pRepRow->isEmpty() )
+ rDoc.SetRepeatRowRange( nTab, std::nullopt );
+ else
+ if ( aRange.ParseAny( *pRepRow, rDoc, aDetails ) & ScRefFlags::VALID )
+ rDoc.SetRepeatRowRange( nTab, std::move(aRange) );
+ }
+ }
+
+ // undo (for all tables)
+ if (bUndo)
+ {
+ SCTAB nCurTab = GetViewData().GetTabNo();
+ std::unique_ptr<ScPrintRangeSaver> pNewRanges = rDoc.CreatePrintRangeSaver();
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ tools::JsonWriter aJsonWriter;
+ pNewRanges->GetPrintRangesInfo(aJsonWriter);
+
+ SfxViewShell* pViewShell = GetViewData().GetViewShell();
+ const std::string message = aJsonWriter.extractAsStdString();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_PRINT_RANGES, message.c_str());
+ }
+
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoPrintRange>( pDocSh, nCurTab, std::move(pOldRanges), std::move(pNewRanges) ) );
+ }
+ else
+ pOldRanges.reset();
+
+ // update page breaks
+
+ for (const auto& rTab : rMark)
+ ScPrintFunc( pDocSh, pDocSh->GetPrinter(), rTab ).UpdatePages();
+
+ SfxBindings& rBindings = GetViewData().GetBindings();
+ rBindings.Invalidate( SID_DELETE_PRINTAREA );
+
+ pDocSh->SetDocumentModified();
+}
+
+// Merge cells
+
+bool ScViewFunc::TestMergeCells() // pre-test (for menu)
+{
+ // simple test: true if there's a selection but no multi selection and not filtered
+
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ {
+ ScRange aRange;
+ bool bMergeable = ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE );
+ bMergeable = bMergeable && ( aRange.aStart.Col() != aRange.aEnd.Col() ||
+ aRange.aStart.Row() != aRange.aEnd.Row() );
+ return bMergeable;
+ }
+ else
+ return false;
+}
+
+bool ScViewFunc::MergeCells( bool bApi, bool& rDoContents, bool bCenter )
+{
+ // Editable- and Being-Nested- test must be at the beginning (in DocFunc too),
+ // so that the Contents-QueryBox won't appear
+ ScEditableTester aTester( this );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ rMark.MarkToSimple();
+ if (!rMark.IsMarked())
+ {
+ ErrorMessage(STR_NOMULTISELECT);
+ return false;
+ }
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ const ScRange& aMarkRange = rMark.GetMarkArea();
+ SCCOL nStartCol = aMarkRange.aStart.Col();
+ SCROW nStartRow = aMarkRange.aStart.Row();
+ SCTAB nStartTab = aMarkRange.aStart.Tab();
+ SCCOL nEndCol = aMarkRange.aEnd.Col();
+ SCROW nEndRow = aMarkRange.aEnd.Row();
+ SCTAB nEndTab = aMarkRange.aEnd.Tab();
+ if ( nStartCol == nEndCol && nStartRow == nEndRow )
+ {
+ // nothing to do
+ return true;
+ }
+
+ if ( rDoc.HasAttrib( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
+ HasAttrFlags::Merged | HasAttrFlags::Overlapped ) )
+ { // "Don't nest merging !"
+ ErrorMessage(STR_MSSG_MERGECELLS_0);
+ return false;
+ }
+
+ // Check for the contents of all selected tables.
+ bool bAskDialog = false;
+ ScCellMergeOption aMergeOption(nStartCol, nStartRow, nEndCol, nEndRow, bCenter);
+ for (const SCTAB& i : rMark)
+ {
+ aMergeOption.maTabs.insert(i);
+
+ sc::MultiDataCellState aState = rDoc.HasMultipleDataCells(aMergeOption.getSingleRange(i));
+ switch (aState.meState)
+ {
+ case sc::MultiDataCellState::HasMultipleCells:
+ {
+ // this range contains multiple data cells.
+ bAskDialog = true;
+ break;
+ }
+ case sc::MultiDataCellState::HasOneCell:
+ {
+ // this range contains only one data cell.
+ if (nStartCol != aState.mnCol1 || nStartRow != aState.mnRow1)
+ rDoContents = true; // move the value to the top-left.
+ break;
+ }
+ default:
+ ;
+ }
+ }
+
+ bool bOk = true;
+ bool bEmptyMergedCells = officecfg::Office::Calc::Compatibility::MergeCells::EmptyMergedCells::get();
+
+ if (bAskDialog)
+ {
+ bool bShowDialog = officecfg::Office::Calc::Compatibility::MergeCells::ShowDialog::get();
+ if (!bApi && bShowDialog)
+ {
+ ScMergeCellsDialog aBox(GetViewData().GetDialogParent());
+ sal_uInt16 nRetVal = aBox.run();
+
+ if ( nRetVal == RET_OK )
+ {
+ switch (aBox.GetMergeCellsOption())
+ {
+ case MoveContentHiddenCells:
+ rDoContents = true;
+ break;
+ case KeepContentHiddenCells:
+ bEmptyMergedCells = false;
+ break;
+ case EmptyContentHiddenCells:
+ bEmptyMergedCells = true;
+ break;
+ default:
+ assert(!"Unknown option for merge cells.");
+ break;
+ }
+ }
+ else if ( nRetVal == RET_CANCEL )
+ bOk = false;
+ }
+ }
+
+ if (bOk)
+ {
+ bOk = pDocSh->GetDocFunc().MergeCells( aMergeOption, rDoContents, true/*bRecord*/, bApi, bEmptyMergedCells );
+
+ if (bOk)
+ {
+ SetCursor( nStartCol, nStartRow );
+ //DoneBlockMode( sal_False);
+ Unmark();
+
+ pDocSh->UpdateOle(GetViewData());
+ UpdateInputLine();
+
+ OUString aStartAddress = aMarkRange.aStart.GetColRowString();
+ OUString aEndAddress = aMarkRange.aEnd.GetColRowString();
+
+ collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, "MERGE_CELLS");
+ }
+ }
+
+ return bOk;
+}
+
+bool ScViewFunc::TestRemoveMerge()
+{
+ bool bMerged = false;
+ ScRange aRange;
+ if (GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE)
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ if ( rDoc.HasAttrib( aRange, HasAttrFlags::Merged ) )
+ bMerged = true;
+ }
+ return bMerged;
+}
+
+static bool lcl_extendMergeRange(ScCellMergeOption& rOption, const ScRange& rRange)
+{
+ bool bExtended = false;
+ if (rOption.mnStartCol > rRange.aStart.Col())
+ {
+ rOption.mnStartCol = rRange.aStart.Col();
+ bExtended = true;
+ }
+ if (rOption.mnStartRow > rRange.aStart.Row())
+ {
+ rOption.mnStartRow = rRange.aStart.Row();
+ bExtended = true;
+ }
+ if (rOption.mnEndCol < rRange.aEnd.Col())
+ {
+ rOption.mnEndCol = rRange.aEnd.Col();
+ bExtended = true;
+ }
+ if (rOption.mnEndRow < rRange.aEnd.Row())
+ {
+ rOption.mnEndRow = rRange.aEnd.Row();
+ bExtended = true;
+ }
+ return bExtended;
+}
+
+bool ScViewFunc::RemoveMerge()
+{
+ ScRange aRange;
+ ScEditableTester aTester( this );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+ else if (GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE)
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScRange aExtended( aRange );
+ rDoc.ExtendMerge( aExtended );
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ ScCellMergeOption aOption(aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row());
+ bool bExtended = false;
+ do
+ {
+ bExtended = false;
+ for (const SCTAB& i : rMark)
+ {
+ aOption.maTabs.insert(i);
+ aExtended.aStart.SetTab(i);
+ aExtended.aEnd.SetTab(i);
+ rDoc.ExtendMerge(aExtended);
+ rDoc.ExtendOverlapped(aExtended);
+
+ // Expand the current range to be inclusive of all merged
+ // areas on all sheets.
+ bExtended = lcl_extendMergeRange(aOption, aExtended);
+ }
+ }
+ while (bExtended);
+
+ bool bOk = pDocSh->GetDocFunc().UnmergeCells(aOption, true/*bRecord*/, nullptr);
+ aExtended = aOption.getFirstSingleRange();
+ MarkRange( aExtended );
+
+ if (bOk)
+ pDocSh->UpdateOle(GetViewData());
+ }
+
+ OUString aCellLocation = aRange.aStart.GetColRowString();
+ collectUIInformation({{"CELL", aCellLocation}}, "UNMERGE_CELL");
+
+ return true; //! bOk ??
+}
+
+void ScViewFunc::FillSimple( FillDir eDir )
+{
+ ScRange aRange;
+ if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ bool bSuccess = pDocSh->GetDocFunc().FillSimple( aRange, &rMark, eDir, false );
+ if (bSuccess)
+ {
+ pDocSh->UpdateOle(GetViewData());
+ UpdateScrollBars();
+
+ auto& rDoc = pDocSh->GetDocument();
+ bool bDoAutoSpell = rDoc.GetDocOptions().IsAutoSpell();
+ if ( bDoAutoSpell )
+ {
+ // Copy AutoSpellData from above(left/right/below) if no selection.
+ switch (eDir)
+ {
+ case FILL_TO_BOTTOM:
+ if (aRange.aStart.Row() > 0 && aRange.aStart.Row() == aRange.aEnd.Row())
+ aRange.aStart.IncRow(-1);
+ break;
+ case FILL_TO_TOP:
+ if (aRange.aEnd.Row() < rDoc.MaxRow() && aRange.aStart.Row() == aRange.aEnd.Row())
+ aRange.aEnd.IncRow(1);
+ break;
+ case FILL_TO_RIGHT:
+ if (aRange.aStart.Col() > 0 && aRange.aStart.Col() == aRange.aEnd.Col())
+ aRange.aStart.IncCol(-1);
+ break;
+ case FILL_TO_LEFT:
+ if (aRange.aEnd.Col() < rDoc.MaxCol() && aRange.aStart.Col() == aRange.aEnd.Col())
+ aRange.aEnd.IncCol(1);
+ break;
+ }
+ CopyAutoSpellData(eDir, aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(),
+ ::std::numeric_limits<sal_uLong>::max());
+ }
+
+ // Invalidate cell slots and update input line with new content.
+ CellContentChanged();
+ }
+ }
+ else
+ ErrorMessage(STR_NOMULTISELECT);
+}
+
+void ScViewFunc::FillSeries( FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd,
+ double fStart, double fStep, double fMax )
+{
+ ScRange aRange;
+ if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ bool bSuccess = pDocSh->GetDocFunc().
+ FillSeries( aRange, &rMark, eDir, eCmd, eDateCmd,
+ fStart, fStep, fMax, false );
+ if (bSuccess)
+ {
+ pDocSh->UpdateOle(GetViewData());
+ UpdateScrollBars();
+
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, aRange);
+ }
+ }
+ else
+ ErrorMessage(STR_NOMULTISELECT);
+}
+
+void ScViewFunc::FillAuto( FillDir eDir, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount )
+{
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScRange aRange( nStartCol,nStartRow,nTab, nEndCol,nEndRow,nTab );
+ ScRange aSourceRange( aRange );
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ bool bSuccess = pDocSh->GetDocFunc().
+ FillAuto( aRange, &rMark, eDir, nCount, false );
+ if (!bSuccess)
+ return;
+
+ MarkRange( aRange, false ); // aRange was modified in FillAuto
+ pDocSh->UpdateOle(GetViewData());
+ UpdateScrollBars();
+
+ bool bDoAutoSpell = pDocSh->GetDocument().GetDocOptions().IsAutoSpell();
+ if ( bDoAutoSpell )
+ CopyAutoSpellData(eDir, nStartCol, nStartRow, nEndCol, nEndRow, nCount);
+
+ ScModelObj* pModelObj = HelperNotifyChanges::getMustPropagateChangesModel(*pDocSh);
+ if (!pModelObj)
+ return;
+
+ ScRangeList aChangeRanges;
+ ScRange aChangeRange( aRange );
+ switch (eDir)
+ {
+ case FILL_TO_BOTTOM:
+ aChangeRange.aStart.SetRow( aSourceRange.aEnd.Row() + 1 );
+ break;
+ case FILL_TO_TOP:
+ aChangeRange.aEnd.SetRow( aSourceRange.aStart.Row() - 1 );
+ break;
+ case FILL_TO_RIGHT:
+ aChangeRange.aStart.SetCol( aSourceRange.aEnd.Col() + 1 );
+ break;
+ case FILL_TO_LEFT:
+ aChangeRange.aEnd.SetCol( aSourceRange.aStart.Col() - 1 );
+ break;
+ default:
+ break;
+ }
+ aChangeRanges.push_back( aChangeRange );
+ HelperNotifyChanges::Notify(*pModelObj, aChangeRanges);
+}
+
+void ScViewFunc::CopyAutoSpellData( FillDir eDir, SCCOL nStartCol, SCROW nStartRow,
+ SCCOL nEndCol, SCROW nEndRow, sal_uLong nCount )
+{
+ const ScDocument* pDoc = &GetViewData().GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ CellType eCellType;
+
+ ScGridWindow* pWin = GetActiveWin();
+ if ( pWin->InsideVisibleRange(nStartCol, nStartRow) && pWin->InsideVisibleRange(nEndCol, nEndRow) )
+ {
+ if ( nCount == ::std::numeric_limits<sal_uLong>::max() )
+ {
+ switch( eDir )
+ {
+ case FILL_TO_BOTTOM:
+ for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
+ {
+ eCellType = pDoc->GetCellType(nColItr, nStartRow, nTab); // We need this optimization only for EditTextObject source cells
+ if (eCellType != CELLTYPE_EDIT)
+ continue;
+
+ const std::vector<editeng::MisspellRanges>* pRanges = pWin->GetAutoSpellData(nColItr, nStartRow);
+ if ( !pRanges )
+ continue;
+ for ( SCROW nRowItr = nStartRow + 1; nRowItr <= nEndRow; ++nRowItr )
+ pWin->SetAutoSpellData(nColItr, nRowItr, pRanges);
+ }
+ break;
+ case FILL_TO_TOP:
+ for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
+ {
+ eCellType = pDoc->GetCellType(nColItr, nEndRow, nTab); // We need this optimization only for EditTextObject source cells
+ if (eCellType != CELLTYPE_EDIT)
+ continue;
+
+ const std::vector<editeng::MisspellRanges>* pRanges = pWin->GetAutoSpellData(nColItr, nEndRow);
+ if ( !pRanges )
+ continue;
+ for ( SCROW nRowItr = nEndRow - 1; nRowItr >= nStartRow; --nRowItr )
+ pWin->SetAutoSpellData(nColItr, nRowItr, pRanges);
+ }
+ break;
+ case FILL_TO_RIGHT:
+ for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
+ {
+ eCellType = pDoc->GetCellType(nStartCol, nRowItr, nTab); // We need this optimization only for EditTextObject source cells
+ if (eCellType != CELLTYPE_EDIT)
+ continue;
+
+ const std::vector<editeng::MisspellRanges>* pRanges = pWin->GetAutoSpellData(nStartCol, nRowItr);
+ if ( !pRanges )
+ continue;
+ for ( SCCOL nColItr = nStartCol + 1; nColItr <= nEndCol; ++nColItr )
+ pWin->SetAutoSpellData(nColItr, nRowItr, pRanges);
+ }
+ break;
+ case FILL_TO_LEFT:
+ for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
+ {
+ eCellType = pDoc->GetCellType(nEndCol, nRowItr, nTab); // We need this optimization only for EditTextObject source cells
+ if (eCellType != CELLTYPE_EDIT)
+ continue;
+
+ const std::vector<editeng::MisspellRanges>* pRanges = pWin->GetAutoSpellData(nEndCol, nRowItr);
+ if ( !pRanges )
+ continue;
+ for ( SCCOL nColItr = nEndCol - 1; nColItr >= nStartCol; --nColItr )
+ pWin->SetAutoSpellData(nColItr, nRowItr, pRanges);
+ }
+ break;
+ }
+ return;
+ }
+
+ typedef const std::vector<editeng::MisspellRanges>* MisspellRangesType;
+ SCROW nRowRepeatSize = nEndRow - nStartRow + 1;
+ SCCOL nColRepeatSize = nEndCol - nStartCol + 1;
+ SCROW nTillRow = 0;
+ SCCOL nTillCol = 0;
+ std::vector<std::vector<MisspellRangesType>> aSourceSpellRanges(nRowRepeatSize, std::vector<MisspellRangesType>(nColRepeatSize, nullptr));
+
+ for ( SCROW nRowIdx = 0; nRowIdx < nRowRepeatSize; ++nRowIdx )
+ {
+ for ( SCCOL nColIdx = 0; nColIdx < nColRepeatSize; ++nColIdx )
+ {
+ eCellType = pDoc->GetCellType(nStartCol + nColIdx, nStartRow + nRowIdx, nTab); // We need this optimization only for EditTextObject source cells
+ if (eCellType != CELLTYPE_EDIT)
+ continue;
+
+ aSourceSpellRanges[nRowIdx][nColIdx] = pWin->GetAutoSpellData( nStartCol + nColIdx, nStartRow + nRowIdx );
+ }
+ }
+
+ switch( eDir )
+ {
+ case FILL_TO_BOTTOM:
+ nTillRow = nEndRow + nCount;
+ for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
+ {
+ for ( SCROW nRowItr = nEndRow + 1; nRowItr <= nTillRow; ++nRowItr )
+ {
+ size_t nSourceRowIdx = ( nRowItr - nEndRow - 1 ) % nRowRepeatSize;
+ MisspellRangesType pRanges = aSourceSpellRanges[nSourceRowIdx][nColItr - nStartCol];
+ if ( !pRanges )
+ continue;
+ pWin->SetAutoSpellData(nColItr, nRowItr, pRanges);
+ }
+ }
+ break;
+
+ case FILL_TO_TOP:
+ nTillRow = nStartRow - nCount;
+ for ( SCCOL nColItr = nStartCol; nColItr <= nEndCol; ++nColItr )
+ {
+ for ( SCROW nRowItr = nStartRow - 1; nRowItr >= nTillRow; --nRowItr )
+ {
+ size_t nSourceRowIdx = nRowRepeatSize - 1 - ( ( nStartRow - 1 - nRowItr ) % nRowRepeatSize );
+ MisspellRangesType pRanges = aSourceSpellRanges[nSourceRowIdx][nColItr - nStartCol];
+ if ( !pRanges )
+ continue;
+ pWin->SetAutoSpellData(nColItr, nRowItr, pRanges);
+ }
+ }
+ break;
+
+ case FILL_TO_RIGHT:
+ nTillCol = nEndCol + nCount;
+ for ( SCCOL nColItr = nEndCol + 1; nColItr <= nTillCol; ++nColItr )
+ {
+ size_t nSourceColIdx = ( nColItr - nEndCol - 1 ) % nColRepeatSize;
+ for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
+ {
+ MisspellRangesType pRanges = aSourceSpellRanges[nRowItr - nStartRow][nSourceColIdx];
+ if ( !pRanges )
+ continue;
+ pWin->SetAutoSpellData(nColItr, nRowItr, pRanges);
+ }
+ }
+ break;
+
+ case FILL_TO_LEFT:
+ nTillCol = nStartCol - nCount;
+ for ( SCCOL nColItr = nStartCol - 1; nColItr >= nTillCol; --nColItr )
+ {
+ size_t nSourceColIdx = nColRepeatSize - 1 - ( ( nStartCol - 1 - nColItr ) % nColRepeatSize );
+ for ( SCROW nRowItr = nStartRow; nRowItr <= nEndRow; ++nRowItr )
+ {
+ MisspellRangesType pRanges = aSourceSpellRanges[nRowItr - nStartRow][nSourceColIdx];
+ if ( !pRanges )
+ continue;
+ pWin->SetAutoSpellData(nColItr, nRowItr, pRanges);
+ }
+ }
+ break;
+ }
+ }
+ else
+ pWin->ResetAutoSpellForContentChange();
+
+}
+
+void ScViewFunc::FillTab( InsertDeleteFlags nFlags, ScPasteFunc nFunction, bool bSkipEmpty, bool bAsLink )
+{
+ //! allow source sheet to be protected
+ ScEditableTester aTester( this );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ SCTAB nTab = GetViewData().GetTabNo();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ ScRange aMarkRange;
+ rMark.MarkToSimple();
+ bool bMulti = rMark.IsMultiMarked();
+ if (bMulti)
+ aMarkRange = rMark.GetMultiMarkArea();
+ else if (rMark.IsMarked())
+ aMarkRange = rMark.GetMarkArea();
+ else
+ aMarkRange = ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab );
+
+ ScDocumentUniquePtr pUndoDoc;
+
+ if (bUndo)
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+
+ for (const SCTAB& i : rMark)
+ if (i != nTab )
+ {
+ pUndoDoc->AddUndoTab( i, i );
+ aMarkRange.aStart.SetTab( i );
+ aMarkRange.aEnd.SetTab( i );
+ rDoc.CopyToDocument( aMarkRange, InsertDeleteFlags::ALL, bMulti, *pUndoDoc );
+ }
+ }
+
+ if (bMulti)
+ rDoc.FillTabMarked( nTab, rMark, nFlags, nFunction, bSkipEmpty, bAsLink );
+ else
+ {
+ aMarkRange.aStart.SetTab( nTab );
+ aMarkRange.aEnd.SetTab( nTab );
+ rDoc.FillTab( aMarkRange, rMark, nFlags, nFunction, bSkipEmpty, bAsLink );
+ }
+
+ if (bUndo)
+ { //! for ChangeTrack not until the end
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoFillTable>( pDocSh, rMark,
+ aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), nTab,
+ aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), nTab,
+ std::move(pUndoDoc), bMulti, nTab, nFlags, nFunction, bSkipEmpty, bAsLink ) );
+ }
+
+ pDocSh->PostPaintGridAll();
+ pDocSh->PostDataChanged();
+}
+
+/** Downward fill of selected cell(s) by double-clicking cross-hair cursor
+
+ Either, extends a current selection if non-empty cells exist immediately
+ below the selection, overwriting cells below the selection up to the
+ minimum row of already filled cells.
+
+ Or, extends a current selection down to the last non-empty cell of an
+ adjacent column when the lower-right corner of the selection is
+ double-clicked. It uses a left-adjoining non-empty column as a guide if
+ such is available, otherwise a right-adjoining non-empty column is used.
+
+ @return No return value
+
+ @see #i12313#
+*/
+void ScViewFunc::FillCrossDblClick()
+{
+ ScRange aRange;
+ GetViewData().GetSimpleArea( aRange );
+ aRange.PutInOrder();
+
+ SCTAB nTab = GetViewData().GetCurPos().Tab();
+ SCCOL nStartX = aRange.aStart.Col();
+ SCROW nStartY = aRange.aStart.Row();
+ SCCOL nEndX = aRange.aEnd.Col();
+ SCROW nEndY = aRange.aEnd.Row();
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ if (nEndY >= rDoc.MaxRow())
+ // Nothing to fill.
+ return;
+
+ // Make sure the selection is not empty
+ if ( rDoc.IsBlockEmpty( nStartX, nStartY, nEndX, nEndY, nTab ) )
+ return;
+
+ // If there is data in all columns immediately below the selection then
+ // switch to overwriting fill.
+ SCROW nOverWriteEndRow = rDoc.MaxRow();
+ for (SCCOL nCol = nStartX; nCol <= nEndX; ++nCol)
+ {
+ if (rDoc.HasData( nCol, nEndY + 1, nTab))
+ {
+ // Determine the shortest data column to end the fill.
+ SCROW nY = nEndY + 1;
+ // FindAreaPos() returns the start row of the next data block if
+ // the current row is the last row of a data block and an empty
+ // cell follows. Somewhat unexpected behaviour...
+ // So check beforehand if there is one non-empty cell following.
+ if (rDoc.HasData( nCol, nY + 1, nTab))
+ {
+ rDoc.FindAreaPos( nCol, nY, nTab, SC_MOVE_DOWN);
+ if (nOverWriteEndRow > nY)
+ nOverWriteEndRow = nY;
+ }
+ else
+ {
+ nOverWriteEndRow = nY;
+ }
+ }
+ else
+ {
+ nOverWriteEndRow = 0;
+ break; // for
+ }
+ }
+
+ if (nOverWriteEndRow > nEndY)
+ {
+ FillAuto( FILL_TO_BOTTOM, nStartX, nStartY, nEndX, nEndY, nOverWriteEndRow - nEndY);
+ return;
+ }
+
+ // Non-overwriting fill follows.
+
+ const bool bDataLeft = (nStartX > 0);
+ if (!bDataLeft && nEndX >= rDoc.MaxCol())
+ // Absolutely no data left or right of selection.
+ return;
+
+ // Check that there is
+ // 1) data immediately left (preferred) or right of start (row) of selection
+ // 2) data there below
+ // 3) no data immediately below selection
+
+ SCCOL nMovX = (bDataLeft ? nStartX - 1 : nEndX + 1);
+ SCROW nMovY = nStartY;
+ bool bDataFound = (rDoc.HasData( nMovX, nStartY, nTab) && rDoc.HasData( nMovX, nStartY + 1, nTab));
+ if (!bDataFound && bDataLeft && nEndX < rDoc.MaxCol())
+ {
+ nMovX = nEndX + 1; // check right
+ bDataFound = (rDoc.HasData( nMovX, nStartY, nTab) && rDoc.HasData( nMovX, nStartY + 1, nTab));
+ }
+
+ if (!(bDataFound && rDoc.IsEmptyData( nStartX, nEndY + 1, nEndX, nEndY + 1, nTab )))
+ return;
+
+ // Get end of data left or right.
+ rDoc.FindAreaPos( nMovX, nMovY, nTab, SC_MOVE_DOWN);
+ // Find minimum end row of below empty area and data right.
+ for (SCCOL nX = nStartX; nX <= nEndX; ++nX)
+ {
+ SCROW nY = nEndY + 1;
+ // Get next row with data in this column.
+ rDoc.FindAreaPos( nX, nY, nTab, SC_MOVE_DOWN);
+ if (nMovY == rDoc.MaxRow() && nY == rDoc.MaxRow())
+ {
+ // FindAreaPos() returns MAXROW also if there is no data at all
+ // from the start, so check if that contains data if the nearby
+ // (left or right) data ends there and increment if no data
+ // here, pretending the next data would be thereafter so nMovY
+ // will not be decremented.
+ if (!rDoc.HasData( nX, nY, nTab))
+ ++nY;
+ }
+ if (nMovY > nY - 1)
+ nMovY = nY - 1;
+ }
+
+ if (nMovY > nEndY)
+ {
+ FillAuto( FILL_TO_BOTTOM, nStartX, nStartY, nEndX, nEndY, nMovY - nEndY);
+ }
+}
+
+void ScViewFunc::ConvertFormulaToValue()
+{
+ ScRange aRange;
+ GetViewData().GetSimpleArea(aRange);
+ aRange.PutInOrder();
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ pDocSh->GetDocFunc().ConvertFormulaToValue(aRange, true);
+ pDocSh->PostPaint(aRange, PaintPartFlags::Grid);
+}
+
+void ScViewFunc::TransliterateText( TransliterationFlags nType )
+{
+ ScMarkData aFuncMark = GetViewData().GetMarkData();
+ if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() )
+ {
+ // no selection -> use cursor position
+
+ ScAddress aCursor( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ aFuncMark.SetMarkArea( ScRange( aCursor ) );
+ }
+
+ bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
+ TransliterateText( aFuncMark, nType, false );
+ if (bSuccess)
+ {
+ GetViewData().GetViewShell()->UpdateInputHandler();
+ }
+}
+
+// AutoFormat
+
+ScAutoFormatData* ScViewFunc::CreateAutoFormatData()
+{
+ ScAutoFormatData* pData = nullptr;
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCTAB nStartTab;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ SCTAB nEndTab;
+ if (GetViewData().GetSimpleArea(nStartCol,nStartRow,nStartTab,nEndCol,nEndRow,nEndTab) == SC_MARK_SIMPLE)
+ {
+ if ( nEndCol-nStartCol >= 3 && nEndRow-nStartRow >= 3 )
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ pData = new ScAutoFormatData;
+ rDoc.GetAutoFormatData( nStartTab, nStartCol,nStartRow,nEndCol,nEndRow, *pData );
+ }
+ }
+ return pData;
+}
+
+void ScViewFunc::AutoFormat( sal_uInt16 nFormatNo )
+{
+ ScRange aRange;
+ if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+
+ bool bSuccess = pDocSh->GetDocFunc().AutoFormat( aRange, &rMark, nFormatNo, false );
+ if (bSuccess)
+ pDocSh->UpdateOle(GetViewData());
+ }
+ else
+ ErrorMessage(STR_NOMULTISELECT);
+}
+
+// Search & Replace
+
+bool ScViewFunc::SearchAndReplace( const SvxSearchItem* pSearchItem,
+ bool bAddUndo, bool bIsApi )
+{
+ SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::Empty);
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ if (bAddUndo && !rDoc.IsUndoEnabled())
+ bAddUndo = false;
+
+ if ( !rMark.IsMarked() && !rMark.IsMultiMarked() && (pSearchItem->HasStartPoint()) )
+ {
+ // No selection -> but we have a start point (top left corner of the
+ // current view), start searching from there, not from the current
+ // cursor position.
+ SCCOL nPosX;
+ SCROW nPosY;
+
+ int nPixelX = pSearchItem->GetStartPointX() * GetViewData().GetPPTX();
+ int nPixelY = pSearchItem->GetStartPointY() * GetViewData().GetPPTY();
+
+ GetViewData().GetPosFromPixel(nPixelX, nPixelY, GetViewData().GetActivePart(), nPosX, nPosY);
+
+ AlignToCursor( nPosX, nPosY, SC_FOLLOW_JUMP );
+ SetCursor( nPosX, nPosY, true );
+ }
+
+ SCCOL nCol, nOldCol;
+ SCROW nRow, nOldRow;
+ SCTAB nTab, nOldTab;
+ nCol = nOldCol = GetViewData().GetCurX();
+ nRow = nOldRow = GetViewData().GetCurY();
+ nTab = nOldTab = GetViewData().GetTabNo();
+
+ SvxSearchCmd nCommand = pSearchItem->GetCommand();
+ bool bAllTables = pSearchItem->IsAllTables();
+ std::set<SCTAB> aOldSelectedTables;
+ SCTAB nLastTab = rDoc.GetTableCount() - 1;
+ SCTAB nStartTab, nEndTab;
+ if ( bAllTables )
+ {
+ nStartTab = 0;
+ nEndTab = nLastTab;
+ std::set<SCTAB> aTmp(rMark.begin(), rMark.end());
+ aOldSelectedTables.swap(aTmp);
+ }
+ else
+ { //! at least one is always selected
+ nStartTab = rMark.GetFirstSelected();
+ nEndTab = rMark.GetLastSelected();
+ }
+
+ if ( nCommand == SvxSearchCmd::FIND
+ || nCommand == SvxSearchCmd::FIND_ALL)
+ bAddUndo = false;
+
+ //! account for bAttrib during Undo !!!
+
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScMarkData> pUndoMark;
+ OUString aUndoStr;
+ if (bAddUndo)
+ {
+ pUndoMark.reset(new ScMarkData(rMark)); // Mark is being modified
+ if ( nCommand == SvxSearchCmd::REPLACE_ALL )
+ {
+ pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ pUndoDoc->InitUndo( rDoc, nStartTab, nEndTab );
+ }
+ }
+
+ if ( bAllTables )
+ { //! select all, after pUndoMark has been created
+ for ( SCTAB j = nStartTab; j <= nEndTab; j++ )
+ {
+ rMark.SelectTable( j, true );
+ }
+ }
+
+ DoneBlockMode(true); // don't delete mark
+ InitOwnBlockMode( ScRange( nCol, nRow, nStartTab, nCol, nRow, nEndTab));
+
+ // If search starts at the beginning don't ask again whether it shall start at the beginning
+ bool bFirst = true;
+ if ( nCol == 0 && nRow == 0 && nTab == nStartTab && !pSearchItem->GetBackward() )
+ bFirst = false;
+
+ bool bFound = false;
+ while (true)
+ {
+ GetFrameWin()->EnterWait();
+ ScRangeList aMatchedRanges;
+ if (rDoc.SearchAndReplace(*pSearchItem, nCol, nRow, nTab, rMark, aMatchedRanges, aUndoStr, pUndoDoc.get()))
+ {
+ bFound = true;
+ if (bAddUndo)
+ {
+ GetViewData().GetDocShell()->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoReplace>( GetViewData().GetDocShell(), *pUndoMark,
+ nCol, nRow, nTab,
+ aUndoStr, std::move(pUndoDoc), pSearchItem ) );
+ }
+
+ if (nCommand == SvxSearchCmd::FIND_ALL || nCommand == SvxSearchCmd::REPLACE_ALL)
+ {
+ SfxViewFrame* pViewFrm = SfxViewFrame::Current();
+ bool bShow = GetViewData().GetViewShell()->GetViewData().GetOptions().GetOption( VOPT_SUMMARY );
+
+ if (bShow && pViewFrm && !comphelper::LibreOfficeKit::isActive())
+ {
+ pViewFrm->ShowChildWindow(sc::SearchResultsDlgWrapper::GetChildWindowId());
+ SfxChildWindow* pWnd = pViewFrm->GetChildWindow(sc::SearchResultsDlgWrapper::GetChildWindowId());
+ if (pWnd)
+ {
+ sc::SearchResultsDlg* pDlg = static_cast<sc::SearchResultsDlg*>(pWnd->GetController().get());
+ if (pDlg)
+ {
+ const bool bCellNotes = (pSearchItem->GetCellType() == SvxSearchCellType::NOTE);
+ // ScCellIterator iterates over cells with content,
+ // for empty cells iterate over match positions.
+ const bool bEmptyCells = (!bCellNotes
+ && ((nCommand == SvxSearchCmd::FIND_ALL
+ && ScDocument::IsEmptyCellSearch(*pSearchItem))
+ || (nCommand == SvxSearchCmd::REPLACE_ALL
+ && pSearchItem->GetReplaceString().isEmpty())));
+ pDlg->FillResults(rDoc, aMatchedRanges, bCellNotes, bEmptyCells);
+ }
+ }
+ }
+
+ rMark.ResetMark();
+ for (size_t i = 0, n = aMatchedRanges.size(); i < n; ++i)
+ {
+ const ScRange& r = aMatchedRanges[i];
+ if (r.aStart.Tab() == nTab)
+ rMark.SetMultiMarkArea(r);
+ }
+ }
+
+ break; // break 'while (TRUE)'
+ }
+ else if ( bFirst && (nCommand == SvxSearchCmd::FIND ||
+ nCommand == SvxSearchCmd::REPLACE) )
+ {
+ bFirst = false;
+ GetFrameWin()->LeaveWait();
+ if (!bIsApi)
+ {
+ if ( nStartTab == nEndTab )
+ SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::EndSheet);
+ else
+ SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::End);
+
+ rDoc.GetSearchAndReplaceStart( *pSearchItem, nCol, nRow );
+ if (pSearchItem->GetBackward())
+ nTab = nEndTab;
+ else
+ nTab = nStartTab;
+ }
+ else
+ {
+ break; // break 'while (TRUE)'
+ }
+ }
+ else // nothing found
+ {
+ if ( nCommand == SvxSearchCmd::FIND_ALL || nCommand == SvxSearchCmd::REPLACE_ALL )
+ {
+ pDocSh->PostPaintGridAll(); // Mark
+ }
+
+ GetFrameWin()->LeaveWait();
+ if (!bIsApi)
+ {
+ GetViewData().GetViewShell()->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_NOT_FOUND, pSearchItem->GetSearchString().toUtf8().getStr());
+ SvxSearchDialogWrapper::SetSearchLabel(SearchLabel::NotFound);
+ }
+
+ break; // break 'while (TRUE)'
+ }
+ } // of while true
+
+ if (!aOldSelectedTables.empty())
+ {
+ // restore originally selected table
+ for (SCTAB i = 0; i <= nEndTab; ++i)
+ rMark.SelectTable(i, false);
+
+ for (const auto& rTab : aOldSelectedTables)
+ rMark.SelectTable(rTab, true);
+
+ if ( bFound )
+ { // if a table is selected as a "match" it remains selected.
+ rMark.SelectTable( nTab, true );
+ // It's a swap if only one table was selected before
+ //! otherwise now one table more might be selected
+ if ( aOldSelectedTables.size() == 1 && nTab != nOldTab )
+ rMark.SelectTable( nOldTab, false );
+ }
+ }
+
+ // Avoid LOK selection notifications before we have all the results.
+ GetViewData().GetViewShell()->setTiledSearching(true);
+ MarkDataChanged();
+ GetViewData().GetViewShell()->setTiledSearching(false);
+
+ if ( bFound )
+ {
+ if ( nTab != GetViewData().GetTabNo() )
+ SetTabNo( nTab );
+
+ // if nothing is marked, DoneBlockMode, then marking can start
+ // directly from this place via Shift-Cursor
+ if (!rMark.IsMarked() && !rMark.IsMultiMarked())
+ DoneBlockMode(true);
+
+ AlignToCursor( nCol, nRow, SC_FOLLOW_JUMP );
+ SetCursor( nCol, nRow, true );
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ Point aCurPos = GetViewData().GetScrPos(nCol, nRow, GetViewData().GetActivePart());
+
+ // just update the cell selection
+ ScGridWindow* pGridWindow = GetViewData().GetActiveWin();
+ // Don't move cell selection handles for find-all: selection of all but the first result would be lost.
+ if (pGridWindow && nCommand == SvxSearchCmd::FIND)
+ {
+ // move the cell selection handles
+ pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_RESET, aCurPos.X(), aCurPos.Y());
+ pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_START, aCurPos.X(), aCurPos.Y());
+ pGridWindow->SetCellSelectionPixel(LOK_SETTEXTSELECTION_END, aCurPos.X(), aCurPos.Y());
+ }
+
+ if (pGridWindow)
+ {
+ std::vector<tools::Rectangle> aLogicRects;
+ pGridWindow->GetCellSelection(aLogicRects);
+
+ boost::property_tree::ptree aTree;
+ aTree.put("searchString", pSearchItem->GetSearchString().toUtf8().getStr());
+ aTree.put("highlightAll", nCommand == SvxSearchCmd::FIND_ALL);
+
+ boost::property_tree::ptree aSelections;
+ for (const tools::Rectangle& rLogicRect : aLogicRects)
+ {
+ boost::property_tree::ptree aSelection;
+ aSelection.put("part", OString::number(nTab).getStr());
+ aSelection.put("rectangles", rLogicRect.toString().getStr());
+ aSelections.push_back(std::make_pair("", aSelection));
+ }
+ aTree.add_child("searchResultSelection", aSelections);
+
+ std::stringstream aStream;
+ boost::property_tree::write_json(aStream, aTree);
+ OString aPayload = aStream.str().c_str();
+ SfxViewShell* pViewShell = GetViewData().GetViewShell();
+ pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_SEARCH_RESULT_SELECTION, aPayload.getStr());
+
+ // Trigger LOK_CALLBACK_TEXT_SELECTION now.
+ MarkDataChanged();
+ }
+ }
+
+ if ( nCommand == SvxSearchCmd::REPLACE
+ || nCommand == SvxSearchCmd::REPLACE_ALL )
+ {
+ if ( nCommand == SvxSearchCmd::REPLACE )
+ {
+ pDocSh->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid );
+
+ // jump to next cell if we replaced everything in the cell
+ // where the cursor was positioned (but avoid switching tabs)
+ if ( nCol == nOldCol && nRow == nOldRow && nTab == nOldTab )
+ {
+ SvxSearchItem aSearchItem = ScGlobal::GetSearchItem();
+ aSearchItem.SetCommand(SvxSearchCmd::FIND);
+ aSearchItem.SetWhich(SID_SEARCH_ITEM);
+
+ ScRangeList aMatchedRanges;
+ ScTable::UpdateSearchItemAddressForReplace( aSearchItem, nCol, nRow );
+ if ( rDoc.SearchAndReplace( aSearchItem, nCol, nRow, nTab, rMark, aMatchedRanges, aUndoStr ) &&
+ ( nTab == nOldTab ) &&
+ ( nCol != nOldCol || nRow != nOldRow ) )
+ {
+ AlignToCursor(nCol, nRow, SC_FOLLOW_JUMP);
+ SetCursor( nCol, nRow, true );
+ }
+ }
+ }
+ else
+ pDocSh->PostPaintGridAll();
+ pDocSh->SetDocumentModified();
+ }
+ else if ( nCommand == SvxSearchCmd::FIND_ALL )
+ pDocSh->PostPaintGridAll(); // mark
+ GetFrameWin()->LeaveWait();
+ }
+ return bFound;
+}
+
+// Goal Seek
+
+void ScViewFunc::Solve( const ScSolveParam& rParam )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+
+ SCCOL nDestCol = rParam.aRefVariableCell.Col();
+ SCROW nDestRow = rParam.aRefVariableCell.Row();
+ SCTAB nDestTab = rParam.aRefVariableCell.Tab();
+
+ ScEditableTester aTester( rDoc, nDestTab, nDestCol,nDestRow, nDestCol,nDestRow );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ OUString aTargetValStr;
+ if ( rParam.pStrTargetVal )
+ aTargetValStr = *rParam.pStrTargetVal;
+
+ OUString aMsgStr;
+ OUString aResStr;
+ double nSolveResult;
+
+ GetFrameWin()->EnterWait();
+
+ bool bExact =
+ rDoc.Solver(
+ rParam.aRefFormulaCell.Col(),
+ rParam.aRefFormulaCell.Row(),
+ rParam.aRefFormulaCell.Tab(),
+ nDestCol, nDestRow, nDestTab,
+ aTargetValStr,
+ nSolveResult );
+
+ GetFrameWin()->LeaveWait();
+
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ sal_uLong nFormat = 0;
+ const ScPatternAttr* pPattern = rDoc.GetPattern( nDestCol, nDestRow, nDestTab );
+ if ( pPattern )
+ nFormat = pPattern->GetNumberFormat( pFormatter );
+ const Color* p;
+ pFormatter->GetOutputString( nSolveResult, nFormat, aResStr, &p );
+
+ if ( bExact )
+ {
+ aMsgStr += ScResId( STR_MSSG_SOLVE_0 ) +
+ aResStr +
+ ScResId( STR_MSSG_SOLVE_1 );
+ }
+ else
+ {
+ aMsgStr = ScResId( STR_MSSG_SOLVE_2 ) +
+ ScResId( STR_MSSG_SOLVE_3 ) +
+ aResStr +
+ ScResId( STR_MSSG_SOLVE_4 );
+ }
+
+ std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
+ VclMessageType::Question, VclButtonsType::YesNo, aMsgStr));
+ xBox->set_title(ScResId(STR_MSSG_DOSUBTOTALS_0));
+ xBox->set_default_response(RET_NO);
+ if (xBox->run() == RET_YES)
+ EnterValue( nDestCol, nDestRow, nDestTab, nSolveResult );
+
+ GetViewData().GetViewShell()->UpdateInputHandler( true );
+}
+
+// multi operation
+
+void ScViewFunc::TabOp( const ScTabOpParam& rParam, bool bRecord )
+{
+ ScRange aRange;
+ if (GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ pDocSh->GetDocFunc().TabOp( aRange, &rMark, rParam, bRecord, false );
+ }
+ else
+ ErrorMessage(STR_NOMULTISELECT);
+}
+
+void ScViewFunc::MakeScenario( const OUString& rName, const OUString& rComment,
+ const Color& rColor, ScScenarioFlags nFlags )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ SCTAB nTab = GetViewData().GetTabNo();
+
+ SCTAB nNewTab = pDocSh->MakeScenario( nTab, rName, rComment, rColor, nFlags, rMark );
+ if (nFlags & ScScenarioFlags::CopyAll)
+ SetTabNo( nNewTab, true ); // ScScenarioFlags::CopyAll -> visible
+ else
+ {
+ SfxBindings& rBindings = GetViewData().GetBindings();
+ rBindings.Invalidate( SID_STATUS_DOCPOS ); // Statusbar
+ rBindings.Invalidate( SID_ROWCOL_SELCOUNT ); // Statusbar
+ rBindings.Invalidate( SID_TABLES_COUNT );
+ rBindings.Invalidate( SID_SELECT_SCENARIO );
+ rBindings.Invalidate( FID_TABLE_SHOW );
+ }
+}
+
+void ScViewFunc::ExtendScenario()
+{
+ ScEditableTester aTester( this );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ // Undo: apply attributes
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( ScMergeFlagAttr( ScMF::Scenario ) );
+ aPattern.GetItemSet().Put( ScProtectionAttr( true ) );
+ ApplySelectionPattern(aPattern);
+}
+
+void ScViewFunc::UseScenario( const OUString& rName )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ SCTAB nTab = GetViewData().GetTabNo();
+
+ DoneBlockMode();
+ InitOwnBlockMode( ScRange( GetViewData().GetCurX(), GetViewData().GetCurY(), nTab));
+ pDocSh->UseScenario( nTab, rName );
+}
+
+// Insert table
+
+bool ScViewFunc::InsertTable( const OUString& rName, SCTAB nTab, bool bRecord )
+{
+ // Order Table/Name is inverted for DocFunc
+ bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
+ InsertTable( nTab, rName, bRecord, false );
+ if (bSuccess)
+ SetTabNo( nTab, true );
+
+ return bSuccess;
+}
+
+// Insert tables
+
+void ScViewFunc::InsertTables(std::vector<OUString>& aNames, SCTAB nTab,
+ SCTAB nCount, bool bRecord )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ weld::WaitObject aWait(GetViewData().GetDialogParent());
+
+ if (bRecord)
+ {
+ rDoc.BeginDrawUndo(); // InsertTab creates a SdrUndoNewPage
+ }
+
+ bool bFlag=false;
+
+ if(aNames.empty())
+ {
+ rDoc.CreateValidTabNames(aNames, nCount);
+ }
+ if (rDoc.InsertTabs(nTab, aNames))
+ {
+ pDocSh->Broadcast( ScTablesHint( SC_TABS_INSERTED, nTab, nCount ) );
+ bFlag = true;
+ }
+
+ if (!bFlag)
+ return;
+
+ if (bRecord)
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoInsertTables>( pDocSh, nTab, std::move(aNames)));
+
+ // Update views
+
+ SetTabNo( nTab, true );
+ pDocSh->PostPaintExtras();
+ pDocSh->SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+}
+
+bool ScViewFunc::AppendTable( const OUString& rName, bool bRecord )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ weld::WaitObject aWait(GetViewData().GetDialogParent());
+
+ if (bRecord)
+ rDoc.BeginDrawUndo(); // InsertTab creates a SdrUndoNewPage
+
+ if (rDoc.InsertTab( SC_TAB_APPEND, rName ))
+ {
+ SCTAB nTab = rDoc.GetTableCount()-1;
+ if (bRecord)
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoInsertTab>( pDocSh, nTab, true, rName));
+ GetViewData().InsertTab( nTab );
+ SetTabNo( nTab, true );
+ pDocSh->PostPaintExtras();
+ pDocSh->SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void ScViewFunc::DeleteTable( SCTAB nTab, bool bRecord )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ bool bSuccess = pDocSh->GetDocFunc().DeleteTable( nTab, bRecord );
+ if (bSuccess)
+ {
+ SCTAB nNewTab = nTab;
+ if ( nNewTab >= rDoc.GetTableCount() )
+ --nNewTab;
+ SetTabNo( nNewTab, true );
+ }
+}
+
+//only use this method for undo for now, all sheets must be connected
+//this method doesn't support undo for now, merge it when it with the other method later
+void ScViewFunc::DeleteTables( const SCTAB nTab, SCTAB nSheets )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bool bVbaEnabled = rDoc.IsInVBAMode();
+ SCTAB nNewTab = nTab;
+ weld::WaitObject aWait(GetViewData().GetDialogParent());
+
+ while ( nNewTab > 0 && !rDoc.IsVisible( nNewTab ) )
+ --nNewTab;
+
+ if (!rDoc.DeleteTabs(nTab, nSheets))
+ return;
+
+ if( bVbaEnabled )
+ {
+ for (SCTAB aTab = 0; aTab < nSheets; ++aTab)
+ {
+ OUString sCodeName;
+ bool bHasCodeName = rDoc.GetCodeName( nTab + aTab, sCodeName );
+ if ( bHasCodeName )
+ VBA_DeleteModule( *pDocSh, sCodeName );
+ }
+ }
+
+ pDocSh->Broadcast( ScTablesHint( SC_TABS_DELETED, nTab, nSheets ) );
+ if ( nNewTab >= rDoc.GetTableCount() )
+ nNewTab = rDoc.GetTableCount() - 1;
+ SetTabNo( nNewTab, true );
+
+ pDocSh->PostPaintExtras();
+ pDocSh->SetDocumentModified();
+
+ SfxApplication* pSfxApp = SfxGetpApp(); // Navigator
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+bool ScViewFunc::DeleteTables(const vector<SCTAB> &TheTabs, bool bRecord )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bool bVbaEnabled = rDoc.IsInVBAMode();
+ SCTAB nNewTab = TheTabs.front();
+ weld::WaitObject aWait(GetViewData().GetDialogParent());
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+ if ( bVbaEnabled )
+ bRecord = false;
+
+ while ( nNewTab > 0 && !rDoc.IsVisible( nNewTab ) )
+ --nNewTab;
+
+ bool bWasLinked = false;
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScRefUndoData> pUndoData;
+ if (bRecord)
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ SCTAB nCount = rDoc.GetTableCount();
+
+ OUString aOldName;
+ for(size_t i=0; i<TheTabs.size(); ++i)
+ {
+ SCTAB nTab = TheTabs[i];
+ if (i==0)
+ pUndoDoc->InitUndo( rDoc, nTab,nTab, true,true ); // incl. column/fow flags
+ else
+ pUndoDoc->AddUndoTab( nTab,nTab, true,true ); // incl. column/fow flags
+
+ rDoc.CopyToDocument(0,0,nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, InsertDeleteFlags::ALL,false, *pUndoDoc );
+ rDoc.GetName( nTab, aOldName );
+ pUndoDoc->RenameTab( nTab, aOldName );
+ if (rDoc.IsLinked(nTab))
+ {
+ bWasLinked = true;
+ pUndoDoc->SetLink( nTab, rDoc.GetLinkMode(nTab), rDoc.GetLinkDoc(nTab),
+ rDoc.GetLinkFlt(nTab), rDoc.GetLinkOpt(nTab),
+ rDoc.GetLinkTab(nTab),
+ rDoc.GetLinkRefreshDelay(nTab) );
+ }
+ if ( rDoc.IsScenario(nTab) )
+ {
+ pUndoDoc->SetScenario( nTab, true );
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nScenFlags;
+ rDoc.GetScenarioData( nTab, aComment, aColor, nScenFlags );
+ pUndoDoc->SetScenarioData( nTab, aComment, aColor, nScenFlags );
+ bool bActive = rDoc.IsActiveScenario( nTab );
+ pUndoDoc->SetActiveScenario( nTab, bActive );
+ }
+ pUndoDoc->SetVisible( nTab, rDoc.IsVisible( nTab ) );
+ pUndoDoc->SetTabBgColor( nTab, rDoc.GetTabBgColor(nTab) );
+ auto pSheetEvents = rDoc.GetSheetEvents( nTab );
+ pUndoDoc->SetSheetEvents( nTab, std::unique_ptr<ScSheetEvents>(pSheetEvents ? new ScSheetEvents(*pSheetEvents) : nullptr) );
+ pUndoDoc->SetLayoutRTL( nTab, rDoc.IsLayoutRTL( nTab ) );
+
+ if ( rDoc.IsTabProtected( nTab ) )
+ pUndoDoc->SetTabProtection(nTab, rDoc.GetTabProtection(nTab));
+
+ // Drawing-Layer is responsible for its Undo !!!
+ // pUndoDoc->TransferDrawPage(rDoc, nTab,nTab);
+ }
+
+ pUndoDoc->AddUndoTab( 0, nCount-1 ); // all Tabs for references
+
+ rDoc.BeginDrawUndo(); // DeleteTab creates a SdrUndoDelPage
+
+ pUndoData.reset(new ScRefUndoData( &rDoc ));
+ }
+
+ bool bDelDone = false;
+
+ for(int i=TheTabs.size()-1; i>=0; --i)
+ {
+ OUString sCodeName;
+ bool bHasCodeName = rDoc.GetCodeName( TheTabs[i], sCodeName );
+ if (rDoc.DeleteTab(TheTabs[i]))
+ {
+ bDelDone = true;
+ if( bVbaEnabled && bHasCodeName )
+ {
+ VBA_DeleteModule( *pDocSh, sCodeName );
+ }
+ pDocSh->Broadcast( ScTablesHint( SC_TAB_DELETED, TheTabs[i] ) );
+ }
+ }
+ if (bRecord)
+ {
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDeleteTab>( GetViewData().GetDocShell(), TheTabs,
+ std::move(pUndoDoc), std::move(pUndoData) ));
+ }
+
+ if (bDelDone)
+ {
+ if ( nNewTab >= rDoc.GetTableCount() )
+ nNewTab = rDoc.GetTableCount() - 1;
+
+ SetTabNo( nNewTab, true );
+
+ if (bWasLinked)
+ {
+ pDocSh->UpdateLinks(); // update Link-Manager
+ GetViewData().GetBindings().Invalidate(SID_LINKS);
+ }
+
+ pDocSh->PostPaintExtras();
+ pDocSh->SetDocumentModified();
+
+ SfxApplication* pSfxApp = SfxGetpApp(); // Navigator
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScDbAreasChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+ }
+ return bDelDone;
+}
+
+bool ScViewFunc::RenameTable( const OUString& rName, SCTAB nTab )
+{
+ // order Table/Name is inverted for DocFunc
+ bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().
+ RenameTable( nTab, rName, true, false );
+ if (bSuccess)
+ {
+ // the table name might be part of a formula
+ GetViewData().GetViewShell()->UpdateInputHandler();
+ }
+ return bSuccess;
+}
+
+bool ScViewFunc::SetTabBgColor( const Color& rColor, SCTAB nTab )
+{
+ bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().SetTabBgColor( nTab, rColor, true, false );
+ if (bSuccess)
+ {
+ GetViewData().GetViewShell()->UpdateInputHandler();
+ }
+ return bSuccess;
+}
+
+bool ScViewFunc::SetTabBgColor( ScUndoTabColorInfo::List& rUndoSetTabBgColorInfoList )
+{
+ bool bSuccess = GetViewData().GetDocShell()->GetDocFunc().SetTabBgColor( rUndoSetTabBgColorInfoList, false );
+ if (bSuccess)
+ {
+ GetViewData().GetViewShell()->UpdateInputHandler();
+ }
+ return bSuccess;
+}
+
+void ScViewFunc::InsertAreaLink( const OUString& rFile,
+ const OUString& rFilter, const OUString& rOptions,
+ const OUString& rSource )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ SCCOL nPosX = GetViewData().GetCurX();
+ SCROW nPosY = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScAddress aPos( nPosX, nPosY, nTab );
+
+ pDocSh->GetDocFunc().InsertAreaLink( rFile, rFilter, rOptions, rSource, aPos, 0/*nRefresh*/, false, false );
+}
+
+void ScViewFunc::InsertTableLink( const OUString& rFile,
+ const OUString& rFilter, const OUString& rOptions,
+ std::u16string_view rTabName )
+{
+ OUString aFilterName = rFilter;
+ OUString aOpt = rOptions;
+ ScDocumentLoader aLoader( rFile, aFilterName, aOpt );
+ if (aLoader.IsError())
+ return;
+
+ ScDocShell* pSrcSh = aLoader.GetDocShell();
+ ScDocument& rSrcDoc = pSrcSh->GetDocument();
+ SCTAB nTab = MAXTAB+1;
+ if (rTabName.empty()) // no name given -> first table
+ nTab = 0;
+ else
+ {
+ OUString aTemp;
+ SCTAB nCount = rSrcDoc.GetTableCount();
+ for (SCTAB i=0; i<nCount; i++)
+ {
+ rSrcDoc.GetName( i, aTemp );
+ if ( aTemp == rTabName )
+ nTab = i;
+ }
+ }
+
+ if ( nTab <= MAXTAB )
+ ImportTables( pSrcSh, 1, &nTab, true,
+ GetViewData().GetTabNo() );
+}
+
+// Copy/link tables from another document
+
+void ScViewFunc::ImportTables( ScDocShell* pSrcShell,
+ SCTAB nCount, const SCTAB* pSrcTabs, bool bLink,SCTAB nTab )
+{
+ ScDocument& rSrcDoc = pSrcShell->GetDocument();
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ bool bError = false;
+ bool bRefs = false;
+ bool bName = false;
+
+ if (rSrcDoc.GetDrawLayer())
+ pDocSh->MakeDrawLayer();
+
+ if (bUndo)
+ rDoc.BeginDrawUndo(); // drawing layer must do its own undo actions
+
+ SCTAB nInsCount = 0;
+ SCTAB i;
+ for( i=0; i<nCount; i++ )
+ { // insert sheets first and update all references
+ OUString aName;
+ rSrcDoc.GetName( pSrcTabs[i], aName );
+ rDoc.CreateValidTabName( aName );
+ if ( !rDoc.InsertTab( nTab+i, aName ) )
+ {
+ bError = true; // total error
+ break; // for
+ }
+ ++nInsCount;
+ }
+ for (i=0; i<nCount && !bError; i++)
+ {
+ SCTAB nSrcTab = pSrcTabs[i];
+ SCTAB nDestTab1=nTab+i;
+ sal_uLong nErrVal = pDocSh->TransferTab( *pSrcShell, nSrcTab, nDestTab1,
+ false, false ); // no insert
+
+ switch (nErrVal)
+ {
+ case 0: // internal error or full of errors
+ bError = true;
+ break;
+ case 2:
+ bRefs = true;
+ break;
+ case 3:
+ bName = true;
+ break;
+ case 4:
+ bRefs = bName = true;
+ break;
+ }
+
+ }
+
+ if (bLink)
+ {
+ sfx2::LinkManager* pLinkManager = rDoc.GetLinkManager();
+
+ SfxMedium* pMed = pSrcShell->GetMedium();
+ OUString aFileName = pMed->GetName();
+ OUString aFilterName;
+ if (pMed->GetFilter())
+ aFilterName = pMed->GetFilter()->GetFilterName();
+ OUString aOptions = ScDocumentLoader::GetOptions(*pMed);
+
+ bool bWasThere = rDoc.HasLink( aFileName, aFilterName, aOptions );
+
+ sal_uLong nRefresh = 0;
+ OUString aTabStr;
+ for (i=0; i<nInsCount; i++)
+ {
+ rSrcDoc.GetName( pSrcTabs[i], aTabStr );
+ rDoc.SetLink( nTab+i, ScLinkMode::NORMAL,
+ aFileName, aFilterName, aOptions, aTabStr, nRefresh );
+ }
+
+ if (!bWasThere) // Insert link only once per source document
+ {
+ ScTableLink* pLink = new ScTableLink( pDocSh, aFileName, aFilterName, aOptions, nRefresh );
+ pLink->SetInCreate( true );
+ pLinkManager->InsertFileLink( *pLink, sfx2::SvBaseLinkObjectType::ClientFile, aFileName, &aFilterName );
+ pLink->Update();
+ pLink->SetInCreate( false );
+
+ SfxBindings& rBindings = GetViewData().GetBindings();
+ rBindings.Invalidate( SID_LINKS );
+ }
+ }
+
+ if (bUndo)
+ {
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoImportTab>( pDocSh, nTab, nCount ) );
+ }
+
+ for (i=0; i<nInsCount; i++)
+ GetViewData().InsertTab(nTab);
+ SetTabNo(nTab,true);
+ pDocSh->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB,
+ PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left | PaintPartFlags::Extras );
+
+ SfxApplication* pSfxApp = SfxGetpApp();
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ pSfxApp->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+
+ pDocSh->PostPaintExtras();
+ pDocSh->PostPaintGridAll();
+ pDocSh->SetDocumentModified();
+
+ if (bRefs)
+ ErrorMessage(STR_ABSREFLOST);
+ if (bName)
+ ErrorMessage(STR_NAMECONFLICT);
+}
+
+// Move/Copy table to another document
+
+void ScViewFunc::MoveTable(
+ sal_uInt16 nDestDocNo, SCTAB nDestTab, bool bCopy, const OUString* pNewTabName )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDocShell* pDocShell = GetViewData().GetDocShell();
+ ScDocShell* pDestShell = nullptr;
+ ScTabViewShell* pDestViewSh = nullptr;
+ bool bUndo (rDoc.IsUndoEnabled());
+ bool bRename = pNewTabName && !pNewTabName->isEmpty();
+
+ bool bNewDoc = (nDestDocNo == SC_DOC_NEW);
+ if ( bNewDoc )
+ {
+ nDestTab = 0; // firstly insert
+
+ // execute without SfxCallMode::RECORD, because already contained in move command
+
+ SfxStringItem aItem( SID_FILE_NAME, "private:factory/" + STRING_SCAPP );
+ SfxStringItem aTarget( SID_TARGETNAME, "_blank" );
+
+ const SfxPoolItem* pRetItem = GetViewData().GetDispatcher().ExecuteList(
+ SID_OPENDOC, SfxCallMode::API|SfxCallMode::SYNCHRON,
+ { &aItem, &aTarget });
+ if ( pRetItem )
+ {
+ if ( auto pObjectItem = dynamic_cast<const SfxObjectItem*>(pRetItem) )
+ pDestShell = dynamic_cast<ScDocShell*>( pObjectItem->GetShell() );
+ else if ( auto pViewFrameItem = dynamic_cast<const SfxViewFrameItem*>( pRetItem) )
+ {
+ SfxViewFrame* pFrm = pViewFrameItem->GetFrame();
+ if (pFrm)
+ pDestShell = dynamic_cast<ScDocShell*>( pFrm->GetObjectShell() );
+ }
+ if (pDestShell)
+ pDestViewSh = pDestShell->GetBestViewShell();
+ }
+ }
+ else
+ pDestShell = ScDocShell::GetShellByNum( nDestDocNo );
+
+ if (!pDestShell)
+ {
+ OSL_FAIL("Destination document not found !!!");
+ return;
+ }
+
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ if (bRename && rMark.GetSelectCount() != 1)
+ {
+ // Custom sheet name is provided, but more than one sheet is selected.
+ // We don't support this scenario at the moment.
+ return;
+ }
+
+ ScDocument& rDestDoc = pDestShell->GetDocument();
+
+ if (&rDestDoc != &rDoc)
+ {
+ if (bNewDoc)
+ {
+ while (rDestDoc.GetTableCount() > 1)
+ rDestDoc.DeleteTab(0);
+ rDestDoc.RenameTab( 0, "______42_____" );
+ }
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ SCTAB nTabSelCount = rMark.GetSelectCount();
+
+ vector<SCTAB> TheTabs;
+
+ for(SCTAB i=0; i<nTabCount; ++i)
+ {
+ if(rMark.GetTableSelect(i))
+ {
+ OUString aTabName;
+ rDoc.GetName( i, aTabName);
+ TheTabs.push_back(i);
+ for(SCTAB j=i+1;j<nTabCount;j++)
+ {
+ if((!rDoc.IsVisible(j)) && rDoc.IsScenario(j))
+ {
+ rDoc.GetName( j, aTabName);
+ TheTabs.push_back(j);
+ i=j;
+ }
+ else break;
+ }
+ }
+ }
+
+ GetFrameWin()->EnterWait();
+
+ if (rDoc.GetDrawLayer())
+ pDestShell->MakeDrawLayer();
+
+ if (!bNewDoc && bUndo)
+ rDestDoc.BeginDrawUndo(); // drawing layer must do its own undo actions
+
+ sal_uLong nErrVal =1;
+ if(nDestTab==SC_TAB_APPEND)
+ nDestTab=rDestDoc.GetTableCount();
+ SCTAB nDestTab1=nDestTab;
+ ScClipParam aParam;
+ for( size_t j=0; j<TheTabs.size(); ++j, ++nDestTab1 )
+ { // insert sheets first and update all references
+ OUString aName;
+ if (bRename)
+ aName = *pNewTabName;
+ else
+ rDoc.GetName( TheTabs[j], aName );
+
+ rDestDoc.CreateValidTabName( aName );
+ if ( !rDestDoc.InsertTab( nDestTab1, aName ) )
+ {
+ nErrVal = 0; // total error
+ break; // for
+ }
+ ScRange aRange( 0, 0, TheTabs[j], rDoc.MaxCol(), rDoc.MaxRow(), TheTabs[j] );
+ aParam.maRanges.push_back(aRange);
+ }
+ rDoc.SetClipParam(aParam);
+ if ( nErrVal > 0 )
+ {
+ nDestTab1 = nDestTab;
+ for(SCTAB nTab : TheTabs)
+ {
+ nErrVal = pDestShell->TransferTab( *pDocShell, nTab, nDestTab1, false, false );
+ nDestTab1++;
+ }
+ }
+ if (!bNewDoc && bUndo)
+ {
+ OUString sName;
+ rDestDoc.GetName(nDestTab, sName);
+ pDestShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoImportTab>( pDestShell, nDestTab,
+ static_cast<SCTAB>(TheTabs.size())));
+
+ }
+ else
+ {
+ pDestShell->GetUndoManager()->Clear();
+ }
+
+ GetFrameWin()->LeaveWait();
+ switch (nErrVal)
+ {
+ case 0: // internal error or full of errors
+ {
+ ErrorMessage(STR_TABINSERT_ERROR);
+ return;
+ }
+ case 2:
+ ErrorMessage(STR_ABSREFLOST);
+ break;
+ case 3:
+ ErrorMessage(STR_NAMECONFLICT);
+ break;
+ case 4:
+ {
+ ErrorMessage(STR_ABSREFLOST);
+ ErrorMessage(STR_NAMECONFLICT);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!bCopy)
+ {
+ if(nTabCount!=nTabSelCount)
+ DeleteTables(TheTabs); // incl. Paint & Undo
+ else
+ ErrorMessage(STR_TABREMOVE_ERROR);
+ }
+
+ if (bNewDoc)
+ {
+ // ChartListenerCollection must be updated before DeleteTab
+ if ( rDestDoc.IsChartListenerCollectionNeedsUpdate() )
+ rDestDoc.UpdateChartListenerCollection();
+
+ SCTAB nNumTabsInserted = static_cast<SCTAB>(TheTabs.size());
+ pDestShell->Broadcast( ScTablesHint( SC_TABS_INSERTED, 0, nNumTabsInserted ) );
+
+ rDestDoc.DeleteTab( nNumTabsInserted ); // old first table
+ pDestShell->Broadcast( ScTablesHint( SC_TAB_DELETED, nNumTabsInserted ) );
+
+ if (pDestViewSh)
+ {
+ // Make sure to clear the cached page view after sheet
+ // deletion, which still points to the sdr page belonging to
+ // the deleted sheet.
+ SdrView* pSdrView = pDestViewSh->GetScDrawView();
+ if (pSdrView)
+ pSdrView->ClearPageView();
+
+ pDestViewSh->TabChanged(); // pages on the drawing layer
+ }
+ pDestShell->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB,
+ PaintPartFlags::Grid | PaintPartFlags::Top | PaintPartFlags::Left |
+ PaintPartFlags::Extras | PaintPartFlags::Size );
+ // PaintPartFlags::Size for outline
+ }
+ else
+ {
+ pDestShell->Broadcast( ScTablesHint( SC_TAB_INSERTED, nDestTab ) );
+ pDestShell->PostPaintExtras();
+ pDestShell->PostPaintGridAll();
+ }
+
+ TheTabs.clear();
+
+ pDestShell->SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ }
+ else
+ {
+ // Move or copy within the same document.
+ SCTAB nTabCount = rDoc.GetTableCount();
+
+ unique_ptr< vector<SCTAB> > pSrcTabs(new vector<SCTAB>);
+ unique_ptr< vector<SCTAB> > pDestTabs(new vector<SCTAB>);
+ unique_ptr< vector<OUString> > pTabNames(new vector<OUString>);
+ unique_ptr< vector<OUString> > pDestNames;
+ pSrcTabs->reserve(nTabCount);
+ pDestTabs->reserve(nTabCount);
+ pTabNames->reserve(nTabCount);
+ OUString aDestName;
+
+ for(SCTAB i=0;i<nTabCount;i++)
+ {
+ if(rMark.GetTableSelect(i))
+ {
+ OUString aTabName;
+ rDoc.GetName( i, aTabName);
+ pTabNames->push_back(aTabName);
+
+ for(SCTAB j=i+1;j<nTabCount;j++)
+ {
+ if((!rDoc.IsVisible(j)) && rDoc.IsScenario(j))
+ {
+ rDoc.GetName( j, aTabName);
+ pTabNames->push_back(aTabName);
+ i=j;
+ }
+ else break;
+ }
+ }
+ }
+
+ if (bCopy && bUndo)
+ rDoc.BeginDrawUndo(); // drawing layer must do its own undo actions
+
+ rDoc.GetName( nDestTab, aDestName);
+ SCTAB nDestTab1=nDestTab;
+ SCTAB nMovTab=0;
+ for (size_t j = 0, n = pTabNames->size(); j < n; ++j)
+ {
+ nTabCount = rDoc.GetTableCount();
+ const OUString& rStr = (*pTabNames)[j];
+ if(!rDoc.GetTable(rStr,nMovTab))
+ {
+ nMovTab=nTabCount;
+ }
+ if(!rDoc.GetTable(aDestName,nDestTab1))
+ {
+ nDestTab1=nTabCount;
+ }
+ pDocShell->MoveTable( nMovTab, nDestTab1, bCopy, false ); // Undo is here
+
+ // tdf#43175 - Adjust chart references on every copied sheet
+ if (bCopy)
+ {
+ // New position of source table after moving
+ SCTAB nSrcTab = (nDestTab1 <= nMovTab) ? nMovTab + 1 : nMovTab;
+ //#i29848# adjust references to data on the copied sheet
+ ScChartHelper::AdjustRangesOfChartsOnDestinationPage(rDoc, rDestDoc, nSrcTab,
+ nDestTab1);
+ }
+
+ if(bCopy && rDoc.IsScenario(nMovTab))
+ {
+ OUString aComment;
+ Color aColor;
+ ScScenarioFlags nFlags;
+
+ rDoc.GetScenarioData(nMovTab, aComment,aColor, nFlags);
+ rDoc.SetScenario(nDestTab1,true);
+ rDoc.SetScenarioData(nDestTab1,aComment,aColor,nFlags);
+ bool bActive = rDoc.IsActiveScenario(nMovTab );
+ rDoc.SetActiveScenario( nDestTab1, bActive );
+ bool bVisible=rDoc.IsVisible(nMovTab);
+ rDoc.SetVisible(nDestTab1,bVisible );
+ }
+
+ pSrcTabs->push_back(nMovTab);
+
+ if(!bCopy)
+ {
+ if(!rDoc.GetTable(rStr,nDestTab1))
+ {
+ nDestTab1=nTabCount;
+ }
+ }
+
+ pDestTabs->push_back(nDestTab1);
+ }
+
+ // Rename must be done after all sheets have been moved.
+ if (bRename)
+ {
+ pDestNames.reset(new vector<OUString>);
+ size_t n = pDestTabs->size();
+ pDestNames->reserve(n);
+ for (size_t j = 0; j < n; ++j)
+ {
+ SCTAB nRenameTab = (*pDestTabs)[j];
+ OUString aTabName = *pNewTabName;
+ rDoc.CreateValidTabName( aTabName );
+ pDestNames->push_back(aTabName);
+ rDoc.RenameTab(nRenameTab, aTabName);
+ }
+ }
+ else
+ // No need to keep this around when we are not renaming.
+ pTabNames.reset();
+
+ SCTAB nTab = GetViewData().GetTabNo();
+
+ if (bUndo)
+ {
+ if (bCopy)
+ {
+ pDocShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoCopyTab>(
+ pDocShell, std::move(pSrcTabs), std::move(pDestTabs), std::move(pDestNames)));
+ }
+ else
+ {
+ pDocShell->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoMoveTab>(
+ pDocShell, std::move(pSrcTabs), std::move(pDestTabs), std::move(pTabNames), std::move(pDestNames)));
+ }
+ }
+
+ SCTAB nNewTab = nDestTab;
+ if (nNewTab == SC_TAB_APPEND)
+ nNewTab = rDoc.GetTableCount()-1;
+ else if (!bCopy && nTab<nDestTab)
+ nNewTab--;
+
+ SetTabNo( nNewTab, true );
+ }
+}
+
+void ScViewFunc::ShowTable( const std::vector<OUString>& rNames )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ std::vector<SCTAB> undoTabs;
+ SCTAB nPos = 0;
+
+ bool bFound(false);
+
+ for (const OUString& aName : rNames)
+ {
+ if (rDoc.GetTable(aName, nPos))
+ {
+ rDoc.SetVisible( nPos, true );
+ SetTabNo( nPos, true );
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ if (!bFound)
+ bFound = true;
+ if (bUndo)
+ undoTabs.push_back(nPos);
+ }
+ }
+ if (bFound)
+ {
+ if (bUndo)
+ {
+ pDocSh->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideTab>( pDocSh, std::move(undoTabs), true ) );
+ }
+ pDocSh->PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Extras);
+ pDocSh->SetDocumentModified();
+ }
+}
+
+void ScViewFunc::HideTable( const ScMarkData& rMark, SCTAB nTabToSelect )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bool bUndo(rDoc.IsUndoEnabled());
+ SCTAB nVisible = 0;
+ SCTAB nTabCount = rDoc.GetTableCount();
+
+ SCTAB nTabSelCount = rMark.GetSelectCount();
+
+ // check to make sure we won't hide all sheets. we need at least one visible at all times.
+ for ( SCTAB i=0; i < nTabCount && nVisible <= nTabSelCount ; i++ )
+ if (rDoc.IsVisible(i))
+ ++nVisible;
+
+ if (nVisible <= nTabSelCount)
+ return;
+
+ std::vector<SCTAB> undoTabs;
+
+ // need to take a copy of selectedtabs since it is modified in the loop
+ const ScMarkData::MarkedTabsType selectedTabs = rMark.GetSelectedTabs();
+ for (const SCTAB& nTab : selectedTabs)
+ {
+ if (rDoc.IsVisible( nTab ))
+ {
+ rDoc.SetVisible( nTab, false );
+ // Update views
+ pDocSh->Broadcast( ScTablesHint( SC_TAB_HIDDEN, nTab ) );
+ SetTabNo( nTab, true );
+ // Store for undo
+ if (bUndo)
+ undoTabs.push_back(nTab);
+ }
+ }
+
+ if (nTabToSelect != -1)
+ SetTabNo(nTabToSelect);
+
+ if (bUndo)
+ {
+ pDocSh->GetUndoManager()->AddUndoAction( std::make_unique<ScUndoShowHideTab>( pDocSh, std::move(undoTabs), false ) );
+ }
+
+ // Update views
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScTablesChanged ) );
+ pDocSh->PostPaint(0,0,0,rDoc.MaxCol(),rDoc.MaxRow(),MAXTAB, PaintPartFlags::Extras);
+ pDocSh->SetDocumentModified();
+}
+
+void ScViewFunc::InsertSpecialChar( const OUString& rStr, const vcl::Font& rFont )
+{
+ ScEditableTester aTester( this );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ const sal_Unicode* pChar = rStr.getStr();
+ ScTabViewShell* pViewShell = GetViewData().GetViewShell();
+ SvxFontItem aFontItem( rFont.GetFamilyType(),
+ rFont.GetFamilyName(),
+ rFont.GetStyleName(),
+ rFont.GetPitch(),
+ rFont.GetCharSet(),
+ ATTR_FONT );
+
+ // if string contains WEAK characters, set all fonts
+ SvtScriptType nScript;
+ ScDocument& rDoc = GetViewData().GetDocument();
+ if ( rDoc.HasStringWeakCharacters( rStr ) )
+ nScript = SvtScriptType::LATIN | SvtScriptType::ASIAN | SvtScriptType::COMPLEX;
+ else
+ nScript = rDoc.GetStringScriptType( rStr );
+
+ SvxScriptSetItem aSetItem( SID_ATTR_CHAR_FONT, pViewShell->GetPool() );
+ aSetItem.PutItemForScriptType( nScript, aFontItem );
+ ApplyUserItemSet( aSetItem.GetItemSet() );
+
+ while ( *pChar )
+ pViewShell->TabKeyInput( KeyEvent( *(pChar++), vcl::KeyCode() ) );
+}
+
+void ScViewFunc::UpdateLineAttrs( SvxBorderLine& rLine,
+ const SvxBorderLine* pDestLine,
+ const SvxBorderLine* pSrcLine,
+ bool bColor )
+{
+ if ( !(pSrcLine && pDestLine) )
+ return;
+
+ if ( bColor )
+ {
+ rLine.SetColor ( pSrcLine->GetColor() );
+ rLine.SetBorderLineStyle(pDestLine->GetBorderLineStyle());
+ rLine.SetWidth ( pDestLine->GetWidth() );
+ }
+ else
+ {
+ rLine.SetColor ( pDestLine->GetColor() );
+ rLine.SetBorderLineStyle(pSrcLine->GetBorderLineStyle());
+ rLine.SetWidth ( pSrcLine->GetWidth() );
+ }
+}
+
+#define SET_LINE_ATTRIBUTES(LINE,BOXLINE) \
+ pBoxLine = aBoxItem.Get##LINE(); \
+ if ( pBoxLine ) \
+ { \
+ if ( pLine ) \
+ { \
+ UpdateLineAttrs( aLine, pBoxLine, pLine, bColorOnly ); \
+ aBoxItem.SetLine( &aLine, BOXLINE ); \
+ } \
+ else \
+ aBoxItem.SetLine( nullptr, BOXLINE ); \
+ }
+
+void ScViewFunc::SetSelectionFrameLines( const SvxBorderLine* pLine,
+ bool bColorOnly )
+{
+ // Not editable only due to a matrix? Attribute is ok anyhow.
+ bool bOnlyNotBecauseOfMatrix;
+ if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
+ {
+ ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScMarkData aFuncMark( GetViewData().GetMarkData() ); // local copy for UnmarkFiltered
+ ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ const ScPatternAttr* pSelAttrs = GetSelectionPattern();
+ const SfxItemSet& rSelItemSet = pSelAttrs->GetItemSet();
+
+ const SfxPoolItem* pBorderAttr = nullptr;
+ SfxItemState eItemState = rSelItemSet.GetItemState( ATTR_BORDER, true, &pBorderAttr );
+
+ const SfxPoolItem* pTLBRItem = nullptr;
+ SfxItemState eTLBRState = rSelItemSet.GetItemState( ATTR_BORDER_TLBR, true, &pTLBRItem );
+
+ const SfxPoolItem* pBLTRItem = nullptr;
+ SfxItemState eBLTRState = rSelItemSet.GetItemState( ATTR_BORDER_BLTR, true, &pBLTRItem );
+
+ // any of the lines visible?
+ if( !((eItemState != SfxItemState::DEFAULT) || (eTLBRState != SfxItemState::DEFAULT) || (eBLTRState != SfxItemState::DEFAULT)) )
+ return;
+
+ // none of the lines don't care?
+ if( (eItemState != SfxItemState::DONTCARE) && (eTLBRState != SfxItemState::DONTCARE) && (eBLTRState != SfxItemState::DONTCARE) )
+ {
+ SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aOldSet( *rDoc.GetPool() );
+ SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END> aNewSet( *rDoc.GetPool() );
+
+ SvxBorderLine aLine;
+
+ if( pBorderAttr )
+ {
+ const SvxBorderLine* pBoxLine = nullptr;
+ SvxBoxItem aBoxItem( *static_cast<const SvxBoxItem*>(pBorderAttr) );
+ SvxBoxInfoItem aBoxInfoItem( ATTR_BORDER_INNER );
+
+ // here pBoxLine is used
+ SET_LINE_ATTRIBUTES(Top,SvxBoxItemLine::TOP)
+ SET_LINE_ATTRIBUTES(Bottom,SvxBoxItemLine::BOTTOM)
+ SET_LINE_ATTRIBUTES(Left,SvxBoxItemLine::LEFT)
+ SET_LINE_ATTRIBUTES(Right,SvxBoxItemLine::RIGHT)
+
+ aBoxInfoItem.SetLine( aBoxItem.GetTop(), SvxBoxInfoItemLine::HORI );
+ aBoxInfoItem.SetLine( aBoxItem.GetLeft(), SvxBoxInfoItemLine::VERT );
+ aBoxInfoItem.ResetFlags(); // set Lines to Valid
+
+ aOldSet.Put( *pBorderAttr );
+ aNewSet.Put( aBoxItem );
+ aNewSet.Put( aBoxInfoItem );
+ }
+
+ if( pTLBRItem && static_cast<const SvxLineItem*>(pTLBRItem)->GetLine() )
+ {
+ SvxLineItem aTLBRItem( *static_cast<const SvxLineItem*>(pTLBRItem) );
+ UpdateLineAttrs( aLine, aTLBRItem.GetLine(), pLine, bColorOnly );
+ aTLBRItem.SetLine( &aLine );
+ aOldSet.Put( *pTLBRItem );
+ aNewSet.Put( aTLBRItem );
+ }
+
+ if( pBLTRItem && static_cast<const SvxLineItem*>(pBLTRItem)->GetLine() )
+ {
+ SvxLineItem aBLTRItem( *static_cast<const SvxLineItem*>(pBLTRItem) );
+ UpdateLineAttrs( aLine, aBLTRItem.GetLine(), pLine, bColorOnly );
+ aBLTRItem.SetLine( &aLine );
+ aOldSet.Put( *pBLTRItem );
+ aNewSet.Put( aBLTRItem );
+ }
+
+ ApplyAttributes( &aNewSet, &aOldSet );
+ }
+ else // if ( eItemState == SfxItemState::DONTCARE )
+ {
+ aFuncMark.MarkToMulti();
+ rDoc.ApplySelectionLineStyle( aFuncMark, pLine, bColorOnly );
+ }
+
+ const ScRange& aMarkRange = aFuncMark.GetMultiMarkArea();
+ SCCOL nStartCol = aMarkRange.aStart.Col();
+ SCROW nStartRow = aMarkRange.aStart.Row();
+ SCTAB nStartTab = aMarkRange.aStart.Tab();
+ SCCOL nEndCol = aMarkRange.aEnd.Col();
+ SCROW nEndRow = aMarkRange.aEnd.Row();
+ SCTAB nEndTab = aMarkRange.aEnd.Tab();
+ pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab,
+ PaintPartFlags::Grid, SC_PF_LINES | SC_PF_TESTMERGE );
+
+ pDocSh->UpdateOle(GetViewData());
+ pDocSh->SetDocumentModified();
+}
+
+#undef SET_LINE_ATTRIBUTES
+
+void ScViewFunc::SetValidation( const ScValidationData& rNew )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ sal_uLong nIndex = rDoc.AddValidationEntry(rNew); // for it there is no Undo
+ SfxUInt32Item aItem( ATTR_VALIDDATA, nIndex );
+
+ ApplyAttr( aItem ); // with Paint and Undo...
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/viewfun3.cxx b/sc/source/ui/view/viewfun3.cxx
new file mode 100644
index 000000000..6f9807755
--- /dev/null
+++ b/sc/source/ui/view/viewfun3.cxx
@@ -0,0 +1,2027 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <svx/svdpage.hxx>
+#include <sfx2/docfile.hxx>
+#include <comphelper/classids.hxx>
+#include <comphelper/lok.hxx>
+#include <sot/formats.hxx>
+#include <sot/storage.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <tools/urlobj.hxx>
+#include <sot/exchange.hxx>
+#include <memory>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+#include <vcl/TypeSerializer.hxx>
+#include <osl/diagnose.h>
+
+#include <attrib.hxx>
+#include <patattr.hxx>
+#include <dociter.hxx>
+#include <viewfunc.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <docfunc.hxx>
+#include <undoblk.hxx>
+#include <refundo.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <global.hxx>
+#include <transobj.hxx>
+#include <drwtrans.hxx>
+#include <chgtrack.hxx>
+#include <waitoff.hxx>
+#include <scmod.hxx>
+#include <inputopt.hxx>
+#include <warnbox.hxx>
+#include <drwlayer.hxx>
+#include <editable.hxx>
+#include <docuno.hxx>
+#include <clipparam.hxx>
+#include <undodat.hxx>
+#include <drawview.hxx>
+#include <cliputil.hxx>
+#include <clipoptions.hxx>
+#include <gridwin.hxx>
+#include <com/sun/star/util/XCloneable.hpp>
+
+using namespace com::sun::star;
+
+namespace {
+
+void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& action)
+{
+ EventDescription aDescription;
+ aDescription.aID = "grid_window";
+ aDescription.aAction = action;
+ aDescription.aParameters = std::move(aParameters);
+ aDescription.aParent = "MainWindow";
+ aDescription.aKeyWord = "ScGridWinUIObject";
+
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+// GlobalName of writer-DocShell from comphelper/classids.hxx
+
+// C U T
+
+void ScViewFunc::CutToClip()
+{
+ UpdateInputLine();
+
+ ScEditableTester aTester( this );
+ if (!aTester.IsEditable()) // selection editable?
+ {
+ ErrorMessage( aTester.GetMessageId() );
+ return;
+ }
+
+ ScRange aRange; // delete this range
+ if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ const bool bRecord(rDoc.IsUndoEnabled()); // Undo/Redo
+
+ ScDocShellModificator aModificator( *pDocSh );
+
+ if ( !rMark.IsMarked() && !rMark.IsMultiMarked() ) // mark the range if not marked yet
+ {
+ DoneBlockMode();
+ InitOwnBlockMode( aRange );
+ rMark.SetMarkArea( aRange );
+ MarkDataChanged();
+ }
+
+ CopyToClip( nullptr, true, false, true/*bIncludeObjects*/ ); // copy to clipboard
+
+ ScAddress aOldEnd( aRange.aEnd ); // combined cells in this range?
+ rDoc.ExtendMerge( aRange, true );
+
+ ScDocumentUniquePtr pUndoDoc;
+ if ( bRecord )
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndoSelected( rDoc, rMark );
+ // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
+ ScRange aCopyRange = aRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(rDoc.GetTableCount()-1);
+ rDoc.CopyToDocument( aCopyRange, (InsertDeleteFlags::ALL & ~InsertDeleteFlags::OBJECTS) | InsertDeleteFlags::NOCAPTIONS, false, *pUndoDoc );
+ rDoc.BeginDrawUndo();
+ }
+
+ sal_uInt16 nExtFlags = 0;
+ pDocSh->UpdatePaintExt( nExtFlags, aRange );
+
+ rMark.MarkToMulti();
+ rDoc.DeleteSelection( InsertDeleteFlags::ALL, rMark );
+ rDoc.DeleteObjectsInSelection( rMark );
+ rMark.MarkToSimple();
+
+ if ( !AdjustRowHeight( aRange.aStart.Row(), aRange.aEnd.Row(), true ) )
+ pDocSh->PostPaint( aRange, PaintPartFlags::Grid, nExtFlags );
+
+ if ( bRecord ) // Draw-Undo now available
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoCut>( pDocSh, aRange, aOldEnd, rMark, std::move(pUndoDoc) ) );
+
+ aModificator.SetDocumentModified();
+ pDocSh->UpdateOle(GetViewData());
+
+ CellContentChanged();
+
+ OUString aStartAddress = aRange.aStart.GetColRowString();
+ OUString aEndAddress = aRange.aEnd.GetColRowString();
+
+ collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, "CUT");
+ }
+ else
+ ErrorMessage( STR_NOMULTISELECT );
+}
+
+// C O P Y
+
+bool ScViewFunc::CopyToClip( ScDocument* pClipDoc, bool bCut, bool bApi, bool bIncludeObjects, bool bStopEdit )
+{
+ ScRange aRange;
+ ScMarkType eMarkType = GetViewData().GetSimpleArea( aRange );
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ bool bDone = false;
+
+ if ( eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED )
+ {
+ ScRangeList aRangeList( aRange );
+ bDone = CopyToClip( pClipDoc, aRangeList, bCut, bApi, bIncludeObjects, bStopEdit );
+ }
+ else if (eMarkType == SC_MARK_MULTI)
+ {
+ ScRangeList aRangeList;
+ rMark.MarkToSimple();
+ rMark.FillRangeListWithMarks(&aRangeList, false);
+ bDone = CopyToClip( pClipDoc, aRangeList, bCut, bApi, bIncludeObjects, bStopEdit );
+ }
+ else
+ {
+ if (!bApi)
+ ErrorMessage(STR_NOMULTISELECT);
+ }
+ if( !bCut ){
+ OUString aStartAddress = aRange.aStart.GetColRowString();
+ OUString aEndAddress = aRange.aEnd.GetColRowString();
+ collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, "COPY");
+ }
+ return bDone;
+}
+
+// Copy the content of the Range into clipboard.
+bool ScViewFunc::CopyToClip( ScDocument* pClipDoc, const ScRangeList& rRanges, bool bCut, bool bApi, bool bIncludeObjects, bool bStopEdit )
+{
+ if ( rRanges.empty() )
+ return false;
+ if ( bStopEdit )
+ UpdateInputLine();
+
+ bool bDone;
+ if (rRanges.size() > 1) // isMultiRange
+ bDone = CopyToClipMultiRange(pClipDoc, rRanges, bCut, bApi, bIncludeObjects);
+ else
+ bDone = CopyToClipSingleRange(pClipDoc, rRanges, bCut, bIncludeObjects);
+
+ return bDone;
+}
+
+bool ScViewFunc::CopyToClipSingleRange( ScDocument* pClipDoc, const ScRangeList& rRanges, bool bCut, bool bIncludeObjects )
+{
+ ScRange aRange = rRanges[0];
+ ScClipParam aClipParam( aRange, bCut );
+ aClipParam.maRanges = rRanges;
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+
+ if (rDoc.HasSelectedBlockMatrixFragment( aRange.aStart.Col(), aRange.aStart.Row(), aRange.aEnd.Col(), aRange.aEnd.Row(), rMark ) )
+ return false;
+
+ bool bSysClip = false;
+ std::shared_ptr<ScDocument> pSysClipDoc;
+ if ( !pClipDoc ) // no clip doc specified
+ {
+ // Create one (deleted by ScTransferObj).
+ pSysClipDoc = std::make_shared<ScDocument>( SCDOCMODE_CLIP );
+ pClipDoc = pSysClipDoc.get();
+ bSysClip = true; // and copy into system
+ }
+ if ( !bCut )
+ {
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->ResetLastCut();
+ }
+
+ if ( bSysClip && bIncludeObjects )
+ {
+ bool bAnyOle = rDoc.HasOLEObjectsInArea( aRange );
+ // Update ScGlobal::xDrawClipDocShellRef.
+ ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle, pSysClipDoc ) );
+ }
+
+ // is this necessary?, will setting the doc id upset the
+ // following paste operation with range? would be nicer to just set this always
+ // and lose the 'if' above
+ aClipParam.setSourceDocID( rDoc.GetDocumentID() );
+
+ if (SfxObjectShell* pObjectShell = rDoc.GetDocumentShell())
+ {
+ // Copy document properties from pObjectShell to pClipDoc (to its clip options, as it has no object shell).
+ uno::Reference<util::XCloneable> xCloneable(pObjectShell->getDocProperties(), uno::UNO_QUERY_THROW);
+ std::unique_ptr<ScClipOptions> pOptions(new ScClipOptions);
+ pOptions->m_xDocumentProperties.set(xCloneable->createClone(), uno::UNO_QUERY);
+ pClipDoc->SetClipOptions(std::move(pOptions));
+ }
+
+ rDoc.CopyToClip( aClipParam, pClipDoc, &rMark, false, bIncludeObjects );
+ if (ScDrawLayer* pDrawLayer = pClipDoc->GetDrawLayer())
+ {
+ ScClipParam& rClipDocClipParam = pClipDoc->GetClipParam();
+ ScRangeListVector& rRangesVector = rClipDocClipParam.maProtectedChartRangesVector;
+ SCTAB nTabCount = pClipDoc->GetTableCount();
+ for ( SCTAB nTab = 0; nTab < nTabCount; ++nTab )
+ {
+ SdrPage* pPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( nTab ) );
+ if ( pPage )
+ {
+ ScChartHelper::FillProtectedChartRangesVector( rRangesVector, rDoc, pPage );
+ }
+ }
+ }
+
+ if ( bSysClip )
+ {
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+ ScGlobal::SetClipDocName( rDoc.GetDocumentShell()->GetTitle( SFX_TITLE_FULLNAME ) );
+ }
+ pClipDoc->ExtendMerge( aRange, true );
+
+ if ( bSysClip )
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScTransferObj ctor
+
+ rtl::Reference<ScTransferObj> pTransferObj(new ScTransferObj( pSysClipDoc, aObjDesc ));
+ if ( ScGlobal::xDrawClipDocShellRef.is() )
+ {
+ SfxObjectShellRef aPersistRef( ScGlobal::xDrawClipDocShellRef.get() );
+ pTransferObj->SetDrawPersist( aPersistRef );// keep persist for ole objects alive
+ }
+ pTransferObj->CopyToClipboard( GetActiveWin() );
+ }
+
+ return true;
+}
+
+bool ScViewFunc::CopyToClipMultiRange( const ScDocument* pInputClipDoc, const ScRangeList& rRanges, bool bCut, bool bApi, bool bIncludeObjects )
+{
+ if (bCut)
+ {
+ // We don't support cutting of multi-selections.
+ if (!bApi)
+ ErrorMessage(STR_NOMULTISELECT);
+ return false;
+ }
+ if (pInputClipDoc)
+ {
+ // TODO: What's this for?
+ if (!bApi)
+ ErrorMessage(STR_NOMULTISELECT);
+ return false;
+ }
+
+ ScClipParam aClipParam( rRanges[0], bCut );
+ aClipParam.maRanges = rRanges;
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ bool bDone = false;
+ bool bSuccess = false;
+ aClipParam.mbCutMode = false;
+
+ do
+ {
+ ScDocumentUniquePtr pDocClip(new ScDocument(SCDOCMODE_CLIP));
+
+ // Check for geometrical feasibility of the ranges.
+ bool bValidRanges = true;
+ ScRange const * p = &aClipParam.maRanges.front();
+ SCCOL nPrevColDelta = 0;
+ SCROW nPrevRowDelta = 0;
+ SCCOL nPrevCol = p->aStart.Col();
+ SCROW nPrevRow = p->aStart.Row();
+ SCCOL nPrevColSize = p->aEnd.Col() - p->aStart.Col() + 1;
+ SCROW nPrevRowSize = p->aEnd.Row() - p->aStart.Row() + 1;
+ for ( size_t i = 1; i < aClipParam.maRanges.size(); ++i )
+ {
+ p = &aClipParam.maRanges[i];
+ if ( rDoc.HasSelectedBlockMatrixFragment(
+ p->aStart.Col(), p->aStart.Row(), p->aEnd.Col(), p->aEnd.Row(), rMark) )
+ {
+ if (!bApi)
+ ErrorMessage(STR_MATRIXFRAGMENTERR);
+ return false;
+ }
+
+ SCCOL nColDelta = p->aStart.Col() - nPrevCol;
+ SCROW nRowDelta = p->aStart.Row() - nPrevRow;
+
+ if ((nColDelta && nRowDelta) || (nPrevColDelta && nRowDelta) || (nPrevRowDelta && nColDelta))
+ {
+ bValidRanges = false;
+ break;
+ }
+
+ if (aClipParam.meDirection == ScClipParam::Unspecified)
+ {
+ if (nColDelta)
+ aClipParam.meDirection = ScClipParam::Column;
+ if (nRowDelta)
+ aClipParam.meDirection = ScClipParam::Row;
+ }
+
+ SCCOL nColSize = p->aEnd.Col() - p->aStart.Col() + 1;
+ SCROW nRowSize = p->aEnd.Row() - p->aStart.Row() + 1;
+
+ if (aClipParam.meDirection == ScClipParam::Column && nRowSize != nPrevRowSize)
+ {
+ // column-oriented ranges must have identical row size.
+ bValidRanges = false;
+ break;
+ }
+ if (aClipParam.meDirection == ScClipParam::Row && nColSize != nPrevColSize)
+ {
+ // likewise, row-oriented ranges must have identical
+ // column size.
+ bValidRanges = false;
+ break;
+ }
+
+ nPrevCol = p->aStart.Col();
+ nPrevRow = p->aStart.Row();
+ nPrevColDelta = nColDelta;
+ nPrevRowDelta = nRowDelta;
+ nPrevColSize = nColSize;
+ nPrevRowSize = nRowSize;
+ }
+ if (!bValidRanges)
+ break;
+ rDoc.CopyToClip(aClipParam, pDocClip.get(), &rMark, false, bIncludeObjects );
+
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->ResetLastCut(); // no more cut-mode
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ // maSize is set in ScTransferObj ctor
+
+ rtl::Reference<ScTransferObj> pTransferObj(new ScTransferObj( std::move(pDocClip), aObjDesc ));
+ if ( ScGlobal::xDrawClipDocShellRef.is() )
+ {
+ SfxObjectShellRef aPersistRef( ScGlobal::xDrawClipDocShellRef.get() );
+ pTransferObj->SetDrawPersist( aPersistRef ); // keep persist for ole objects alive
+ }
+ pTransferObj->CopyToClipboard( GetActiveWin() ); // system clipboard
+
+ bSuccess = true;
+ }
+ while (false);
+
+ if (!bSuccess && !bApi)
+ ErrorMessage(STR_NOMULTISELECT);
+
+ bDone = bSuccess;
+
+ return bDone;
+}
+
+rtl::Reference<ScTransferObj> ScViewFunc::CopyToTransferable()
+{
+ ScRange aRange;
+ if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ if ( !rDoc.HasSelectedBlockMatrixFragment(
+ aRange.aStart.Col(), aRange.aStart.Row(),
+ aRange.aEnd.Col(), aRange.aEnd.Row(),
+ rMark ) )
+ {
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP )); // create one (deleted by ScTransferObj)
+
+ bool bAnyOle = rDoc.HasOLEObjectsInArea( aRange, &rMark );
+ ScDrawLayer::SetGlobalDrawPersist( ScTransferObj::SetDrawClipDoc( bAnyOle ) );
+
+ ScClipParam aClipParam(aRange, false);
+ rDoc.CopyToClip(aClipParam, pClipDoc.get(), &rMark, false, true);
+
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+ pClipDoc->ExtendMerge( aRange, true );
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ TransferableObjectDescriptor aObjDesc;
+ pDocSh->FillTransferableObjectDescriptor( aObjDesc );
+ aObjDesc.maDisplayName = pDocSh->GetMedium()->GetURLObject().GetURLNoPass();
+ return new ScTransferObj( std::move(pClipDoc), aObjDesc );
+ }
+ }
+
+ return nullptr;
+}
+
+// P A S T E
+
+void ScViewFunc::PasteDraw()
+{
+ ScViewData& rViewData = GetViewData();
+ SCCOL nPosX = rViewData.GetCurX();
+ SCROW nPosY = rViewData.GetCurY();
+ vcl::Window* pWin = GetActiveWin();
+ Point aPos = pWin->PixelToLogic( rViewData.GetScrPos( nPosX, nPosY,
+ rViewData.GetActivePart() ) );
+ const ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(rViewData.GetActiveWin()));
+ if (pDrawClip)
+ {
+ const OUString& aSrcShellID = pDrawClip->GetShellID();
+ OUString aDestShellID = SfxObjectShell::CreateShellID(rViewData.GetDocShell());
+ PasteDraw(aPos, pDrawClip->GetModel(), false, aSrcShellID, aDestShellID);
+ }
+}
+
+void ScViewFunc::PasteFromSystem()
+{
+ UpdateInputLine();
+
+ vcl::Window* pWin = GetActiveWin();
+ css::uno::Reference<css::datatransfer::XTransferable2> xTransferable2(ScTabViewShell::GetClipData(pWin));
+ const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(xTransferable2);
+ // keep a reference in case the clipboard is changed during PasteFromClip
+ const ScDrawTransferObj* pDrawClip = ScDrawTransferObj::GetOwnClipboard(xTransferable2);
+ if (pOwnClip)
+ {
+ PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
+ ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
+ true ); // allow warning dialog
+ }
+ else if (pDrawClip)
+ PasteDraw();
+ else
+ {
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
+
+ {
+ SotClipboardFormatId nBiff8 = SotExchange::RegisterFormatName("Biff8");
+ SotClipboardFormatId nBiff5 = SotExchange::RegisterFormatName("Biff5");
+
+ SotClipboardFormatId nFormat; // output param for GetExchangeAction
+ sal_uInt8 nEventAction; // output param for GetExchangeAction
+
+ uno::Reference<css::datatransfer::XTransferable> xTransferable( aDataHelper.GetXTransferable() );
+ sal_uInt8 nAction = SotExchange::GetExchangeAction(
+ aDataHelper.GetDataFlavorExVector(),
+ SotExchangeDest::SCDOC_FREE_AREA,
+ EXCHG_IN_ACTION_COPY,
+ EXCHG_IN_ACTION_DEFAULT,
+ nFormat, nEventAction, SotClipboardFormatId::NONE,
+ &xTransferable );
+
+ if ( nAction != EXCHG_INOUT_ACTION_NONE )
+ {
+ switch( nAction )
+ {
+ case EXCHG_OUT_ACTION_INSERT_SVXB:
+ case EXCHG_OUT_ACTION_INSERT_GDIMETAFILE:
+ case EXCHG_OUT_ACTION_INSERT_BITMAP:
+ case EXCHG_OUT_ACTION_INSERT_GRAPH:
+ // SotClipboardFormatId::BITMAP
+ // SotClipboardFormatId::PNG
+ // SotClipboardFormatId::GDIMETAFILE
+ // SotClipboardFormatId::SVXB
+ PasteFromSystem(nFormat);
+ break;
+ default:
+ nAction = EXCHG_INOUT_ACTION_NONE;
+ }
+ }
+
+ if ( nAction == EXCHG_INOUT_ACTION_NONE )
+ {
+ // first SvDraw-model, then drawing
+ // (only one drawing is allowed)
+
+ if (aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ))
+ {
+ // special case for tables from drawing
+ if( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) )
+ {
+ PasteFromSystem( SotClipboardFormatId::RTF );
+ }
+ else if( aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) )
+ {
+ PasteFromSystem( SotClipboardFormatId::RICHTEXT );
+ }
+ else
+ {
+ PasteFromSystem( SotClipboardFormatId::DRAWING );
+ }
+ }
+ else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ))
+ {
+ // If it's a Writer object, insert RTF instead of OLE
+
+ // Else, if the class id is all-zero, and SYLK is available,
+ // it probably is spreadsheet cells that have been put
+ // on the clipboard by OOo, so use the SYLK. (fdo#31077)
+
+ bool bDoRtf = false;
+ TransferableObjectDescriptor aObjDesc;
+ if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
+ {
+ bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
+ aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
+ && ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ) );
+ }
+ if ( bDoRtf )
+ PasteFromSystem( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT );
+ else if ( aObjDesc.maClassName == SvGlobalName( 0,0,0,0,0,0,0,0,0,0,0 )
+ && aDataHelper.HasFormat( SotClipboardFormatId::SYLK ))
+ PasteFromSystem( SotClipboardFormatId::SYLK );
+ else
+ PasteFromSystem( SotClipboardFormatId::EMBED_SOURCE );
+ }
+ else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ))
+ PasteFromSystem( SotClipboardFormatId::LINK_SOURCE );
+ // the following format can not affect scenario from #89579#
+ else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ))
+ PasteFromSystem( SotClipboardFormatId::EMBEDDED_OBJ_OLE );
+ // SotClipboardFormatId::PRIVATE no longer here (can't work if pOwnClip is NULL)
+ else if (aDataHelper.HasFormat(nBiff8)) // before xxx_OLE formats
+ PasteFromSystem(nBiff8);
+ else if (aDataHelper.HasFormat(nBiff5))
+ PasteFromSystem(nBiff5);
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::RTF))
+ PasteFromSystem(SotClipboardFormatId::RTF);
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::RICHTEXT))
+ PasteFromSystem(SotClipboardFormatId::RICHTEXT);
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML))
+ PasteFromSystem(SotClipboardFormatId::HTML);
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML_SIMPLE))
+ PasteFromSystem(SotClipboardFormatId::HTML_SIMPLE);
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::SYLK))
+ PasteFromSystem(SotClipboardFormatId::SYLK);
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING_TSVC))
+ PasteFromSystem(SotClipboardFormatId::STRING_TSVC);
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING))
+ PasteFromSystem(SotClipboardFormatId::STRING);
+ // xxx_OLE formats come last, like in SotExchange tables
+ else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ))
+ PasteFromSystem( SotClipboardFormatId::EMBED_SOURCE_OLE );
+ else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ))
+ PasteFromSystem( SotClipboardFormatId::LINK_SOURCE_OLE );
+ }
+ }
+ }
+ // no exception-> SID_PASTE has FastCall-flag from idl
+ // will be called in case of empty clipboard (#42531#)
+}
+
+void ScViewFunc::PasteFromTransferable( const uno::Reference<datatransfer::XTransferable>& rxTransferable )
+{
+ uno::Reference<lang::XUnoTunnel> xTunnel( rxTransferable, uno::UNO_QUERY );
+
+ if (auto pOwnClip = comphelper::getFromUnoTunnel<ScTransferObj>(xTunnel))
+ {
+ PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
+ ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
+ true ); // allow warning dialog
+ }
+ else if (auto pDrawClip = comphelper::getFromUnoTunnel<ScDrawTransferObj>(xTunnel))
+ {
+ ScViewData& rViewData = GetViewData();
+ SCCOL nPosX = rViewData.GetCurX();
+ SCROW nPosY = rViewData.GetCurY();
+ vcl::Window* pWin = GetActiveWin();
+ Point aPos = pWin->PixelToLogic( rViewData.GetScrPos( nPosX, nPosY, rViewData.GetActivePart() ) );
+ PasteDraw(
+ aPos, pDrawClip->GetModel(), false,
+ pDrawClip->GetShellID(), SfxObjectShell::CreateShellID(rViewData.GetDocShell()));
+ }
+ else
+ {
+ TransferableDataHelper aDataHelper( rxTransferable );
+ SotClipboardFormatId nBiff8 = SotExchange::RegisterFormatName("Biff8");
+ SotClipboardFormatId nBiff5 = SotExchange::RegisterFormatName("Biff5");
+ SotClipboardFormatId nFormatId = SotClipboardFormatId::NONE;
+ // first SvDraw-model, then drawing
+ // (only one drawing is allowed)
+
+ if (aDataHelper.HasFormat( SotClipboardFormatId::DRAWING ))
+ nFormatId = SotClipboardFormatId::DRAWING;
+ else if (aDataHelper.HasFormat( SotClipboardFormatId::SVXB ))
+ nFormatId = SotClipboardFormatId::SVXB;
+ else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE ))
+ {
+ // If it's a Writer object, insert RTF instead of OLE
+ bool bDoRtf = false;
+ TransferableObjectDescriptor aObjDesc;
+ if( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc ) )
+ {
+ bDoRtf = ( ( aObjDesc.maClassName == SvGlobalName( SO3_SW_CLASSID ) ||
+ aObjDesc.maClassName == SvGlobalName( SO3_SWWEB_CLASSID ) )
+ && ( aDataHelper.HasFormat( SotClipboardFormatId::RTF ) || aDataHelper.HasFormat( SotClipboardFormatId::RICHTEXT ) ));
+ }
+ if ( bDoRtf )
+ nFormatId = aDataHelper.HasFormat( SotClipboardFormatId::RTF ) ? SotClipboardFormatId::RTF : SotClipboardFormatId::RICHTEXT;
+ else
+ nFormatId = SotClipboardFormatId::EMBED_SOURCE;
+ }
+ else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE ))
+ nFormatId = SotClipboardFormatId::LINK_SOURCE;
+ // the following format can not affect scenario from #89579#
+ else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBEDDED_OBJ_OLE ))
+ nFormatId = SotClipboardFormatId::EMBEDDED_OBJ_OLE;
+ // SotClipboardFormatId::PRIVATE no longer here (can't work if pOwnClip is NULL)
+ else if (aDataHelper.HasFormat(nBiff8)) // before xxx_OLE formats
+ nFormatId = nBiff8;
+ else if (aDataHelper.HasFormat(nBiff5))
+ nFormatId = nBiff5;
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::RTF))
+ nFormatId = SotClipboardFormatId::RTF;
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::RICHTEXT))
+ nFormatId = SotClipboardFormatId::RICHTEXT;
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML))
+ nFormatId = SotClipboardFormatId::HTML;
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::HTML_SIMPLE))
+ nFormatId = SotClipboardFormatId::HTML_SIMPLE;
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::SYLK))
+ nFormatId = SotClipboardFormatId::SYLK;
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING_TSVC))
+ nFormatId = SotClipboardFormatId::STRING_TSVC;
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::STRING))
+ nFormatId = SotClipboardFormatId::STRING;
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::GDIMETAFILE))
+ nFormatId = SotClipboardFormatId::GDIMETAFILE;
+ else if (aDataHelper.HasFormat(SotClipboardFormatId::BITMAP))
+ nFormatId = SotClipboardFormatId::BITMAP;
+ // xxx_OLE formats come last, like in SotExchange tables
+ else if (aDataHelper.HasFormat( SotClipboardFormatId::EMBED_SOURCE_OLE ))
+ nFormatId = SotClipboardFormatId::EMBED_SOURCE_OLE;
+ else if (aDataHelper.HasFormat( SotClipboardFormatId::LINK_SOURCE_OLE ))
+ nFormatId = SotClipboardFormatId::LINK_SOURCE_OLE;
+ else
+ return;
+
+ PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
+ GetViewData().GetCurX(), GetViewData().GetCurY(), nullptr );
+ }
+}
+
+bool ScViewFunc::PasteFromSystem( SotClipboardFormatId nFormatId, bool bApi )
+{
+ UpdateInputLine();
+
+ bool bRet = true;
+ vcl::Window* pWin = GetActiveWin();
+ // keep a reference in case the clipboard is changed during PasteFromClip
+ const ScTransferObj* pOwnClip = ScTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(pWin));
+ if ( nFormatId == SotClipboardFormatId::NONE && pOwnClip )
+ {
+ PasteFromClip( InsertDeleteFlags::ALL, pOwnClip->GetDocument(),
+ ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
+ !bApi ); // allow warning dialog
+ }
+ else
+ {
+ TransferableDataHelper aDataHelper( TransferableDataHelper::CreateFromSystemClipboard( pWin ) );
+ if ( !aDataHelper.GetTransferable().is() )
+ return false;
+
+ SCCOL nPosX = 0;
+ SCROW nPosY = 0;
+
+ ScViewData& rViewData = GetViewData();
+ ScRange aRange;
+ if ( rViewData.GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
+ {
+ nPosX = aRange.aStart.Col();
+ nPosY = aRange.aStart.Row();
+ }
+ else
+ {
+ nPosX = rViewData.GetCurX();
+ nPosY = rViewData.GetCurY();
+ }
+
+ bRet = PasteDataFormat( nFormatId, aDataHelper.GetTransferable(),
+ nPosX, nPosY,
+ nullptr, false, !bApi ); // allow warning dialog
+
+ if ( !bRet && !bApi )
+ {
+ ErrorMessage(STR_PASTE_ERROR);
+ }
+ else if (comphelper::LibreOfficeKit::isActive())
+ {
+ SfxViewShell* pViewShell = rViewData.GetViewShell();
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(pViewShell, true /* bColumns */, true /* bRows */,
+ true /* bSizes */, false /* bHidden */, false /* bFiltered */, false /* bGroups */, rViewData.GetTabNo());
+ }
+ }
+ return bRet;
+}
+
+// P A S T E
+
+bool ScViewFunc::PasteOnDrawObjectLinked(
+ const uno::Reference<datatransfer::XTransferable>& rxTransferable,
+ SdrObject& rHitObj)
+{
+ TransferableDataHelper aDataHelper( rxTransferable );
+
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::SVXB ) )
+ {
+ tools::SvRef<SotTempStream> xStm;
+ ScDrawView* pScDrawView = GetScDrawView();
+
+ if( pScDrawView && aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB, xStm ) )
+ {
+ Graphic aGraphic;
+ TypeSerializer aSerializer(*xStm);
+ aSerializer.readGraphic(aGraphic);
+
+ const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
+
+ if(pScDrawView->ApplyGraphicToObject( rHitObj, aGraphic, aBeginUndo, "" ))
+ {
+ return true;
+ }
+ }
+ }
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::GDIMETAFILE ) )
+ {
+ GDIMetaFile aMtf;
+ ScDrawView* pScDrawView = GetScDrawView();
+
+ if( pScDrawView && aDataHelper.GetGDIMetaFile( SotClipboardFormatId::GDIMETAFILE, aMtf ) )
+ {
+ const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
+
+ if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aMtf), aBeginUndo, "" ))
+ {
+ return true;
+ }
+ }
+ }
+ else if ( aDataHelper.HasFormat( SotClipboardFormatId::BITMAP ) || aDataHelper.HasFormat( SotClipboardFormatId::PNG ) )
+ {
+ BitmapEx aBmpEx;
+ ScDrawView* pScDrawView = GetScDrawView();
+
+ if( pScDrawView && aDataHelper.GetBitmapEx( SotClipboardFormatId::BITMAP, aBmpEx ) )
+ {
+ const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
+
+ if(pScDrawView->ApplyGraphicToObject( rHitObj, Graphic(aBmpEx), aBeginUndo, "" ))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static bool lcl_SelHasAttrib( const ScDocument& rDoc, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
+ const ScMarkData& rTabSelection, HasAttrFlags nMask )
+{
+ return std::any_of(rTabSelection.begin(), rTabSelection.end(),
+ [&](const SCTAB& rTab) { return rDoc.HasAttrib( nCol1, nRow1, rTab, nCol2, nRow2, rTab, nMask ); });
+}
+
+// paste into sheet:
+
+// internal paste
+
+namespace {
+
+bool checkDestRangeForOverwrite(const ScRangeList& rDestRanges, const ScDocument& rDoc, const ScMarkData& rMark, weld::Window* pParentWnd)
+{
+ bool bIsEmpty = true;
+ size_t nRangeSize = rDestRanges.size();
+ for (const auto& rTab : rMark)
+ {
+ for (size_t i = 0; i < nRangeSize && bIsEmpty; ++i)
+ {
+ const ScRange& rRange = rDestRanges[i];
+ bIsEmpty = rDoc.IsBlockEmpty(
+ rRange.aStart.Col(), rRange.aStart.Row(),
+ rRange.aEnd.Col(), rRange.aEnd.Row(), rTab );
+ }
+ if (!bIsEmpty)
+ break;
+ }
+
+ if (!bIsEmpty)
+ {
+ ScReplaceWarnBox aBox(pParentWnd);
+ if (aBox.run() != RET_YES)
+ {
+ // changing the configuration is within the ScReplaceWarnBox
+ return false;
+ }
+ }
+ return true;
+}
+
+}
+
+bool ScViewFunc::PasteFromClip( InsertDeleteFlags nFlags, ScDocument* pClipDoc,
+ ScPasteFunc nFunction, bool bSkipEmptyCells,
+ bool bTranspose, bool bAsLink,
+ InsCellCmd eMoveMode, InsertDeleteFlags nUndoExtraFlags,
+ bool bAllowDialogs )
+{
+ if (!pClipDoc)
+ {
+ OSL_FAIL("PasteFromClip: pClipDoc=0 not allowed");
+ return false;
+ }
+
+ if (GetViewData().SelectionForbidsPaste(pClipDoc))
+ return false;
+
+ // undo: save all or no content
+ InsertDeleteFlags nContFlags = InsertDeleteFlags::NONE;
+ if (nFlags & InsertDeleteFlags::CONTENTS)
+ nContFlags |= InsertDeleteFlags::CONTENTS;
+ if (nFlags & InsertDeleteFlags::ATTRIB)
+ nContFlags |= InsertDeleteFlags::ATTRIB;
+ // move attributes to undo without copying them from clip to doc
+ InsertDeleteFlags nUndoFlags = nContFlags;
+ if (nUndoExtraFlags & InsertDeleteFlags::ATTRIB)
+ nUndoFlags |= InsertDeleteFlags::ATTRIB;
+ // do not copy note captions into undo document
+ nUndoFlags |= InsertDeleteFlags::NOCAPTIONS;
+
+ ScClipParam& rClipParam = pClipDoc->GetClipParam();
+ if (rClipParam.isMultiRange())
+ {
+ // Source data is multi-range.
+ return PasteMultiRangesFromClip(nFlags, pClipDoc, nFunction, bSkipEmptyCells, bTranspose,
+ bAsLink, bAllowDialogs, eMoveMode, nUndoFlags);
+ }
+
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ if (rMark.IsMultiMarked())
+ {
+ // Source data is single-range but destination is multi-range.
+ return PasteFromClipToMultiRanges(
+ nFlags, pClipDoc, nFunction, bSkipEmptyCells, bTranspose, bAsLink, bAllowDialogs,
+ eMoveMode, nUndoFlags);
+ }
+
+ bool bCutMode = pClipDoc->IsCutMode(); // if transposing, take from original clipdoc
+ bool bIncludeFiltered = bCutMode;
+
+ // paste drawing: also if InsertDeleteFlags::NOTE is set (to create drawing layer for note captions)
+ bool bPasteDraw = ( pClipDoc->GetDrawLayer() && ( nFlags & (InsertDeleteFlags::OBJECTS|InsertDeleteFlags::NOTE) ) );
+
+ ScDocShellRef aTransShellRef; // for objects in xTransClip - must remain valid as long as xTransClip
+ ScDocument* pOrigClipDoc = nullptr;
+ ScDocumentUniquePtr xTransClip;
+ if ( bTranspose )
+ {
+ SCCOL nX;
+ SCROW nY;
+ // include filtered rows until TransposeClip can skip them
+ pClipDoc->GetClipArea( nX, nY, true );
+ if ( nY > static_cast<sal_Int32>(pClipDoc->MaxCol()) ) // too many lines for transpose
+ {
+ ErrorMessage(STR_PASTE_FULL);
+ return false;
+ }
+ pOrigClipDoc = pClipDoc; // refs
+
+ if ( bPasteDraw )
+ {
+ aTransShellRef = new ScDocShell; // DocShell needs a Ref immediately
+ aTransShellRef->DoInitNew();
+ }
+ ScDrawLayer::SetGlobalDrawPersist( aTransShellRef.get() );
+
+ xTransClip.reset( new ScDocument( SCDOCMODE_CLIP ));
+ pClipDoc->TransposeClip(xTransClip.get(), nFlags, bAsLink, bIncludeFiltered);
+ pClipDoc = xTransClip.get();
+
+ ScDrawLayer::SetGlobalDrawPersist(nullptr);
+ }
+
+ // TODO: position this call better for performance.
+ ResetAutoSpellForContentChange();
+
+ SCCOL nStartCol;
+ SCROW nStartRow;
+ SCTAB nStartTab;
+ SCCOL nEndCol;
+ SCROW nEndRow;
+ SCTAB nEndTab;
+ SCCOL nClipSizeX;
+ SCROW nClipSizeY;
+ pClipDoc->GetClipArea( nClipSizeX, nClipSizeY, true ); // size in clipboard doc
+
+ // size in target doc: include filtered rows only if CutMode is set
+ SCCOL nDestSizeX;
+ SCROW nDestSizeY;
+ pClipDoc->GetClipArea( nDestSizeX, nDestSizeY, bIncludeFiltered );
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
+ const bool bRecord(rDoc.IsUndoEnabled());
+
+ ScDocShellModificator aModificator( *pDocSh );
+
+ ScRange aMarkRange;
+ ScMarkData aFilteredMark( rMark); // local copy for all modifications
+ ScMarkType eMarkType = GetViewData().GetSimpleArea( aMarkRange, aFilteredMark);
+ bool bMarkIsFiltered = (eMarkType == SC_MARK_SIMPLE_FILTERED);
+ bool bNoPaste = ((eMarkType != SC_MARK_SIMPLE && !bMarkIsFiltered) ||
+ (bMarkIsFiltered && (eMoveMode != INS_NONE || bAsLink)));
+
+ if (!bNoPaste)
+ {
+ if (!rMark.IsMarked())
+ {
+ // Create a selection with clipboard row count and check that for
+ // filtered.
+ nStartCol = GetViewData().GetCurX();
+ nStartRow = GetViewData().GetCurY();
+ nStartTab = GetViewData().GetTabNo();
+ nEndCol = nStartCol + nDestSizeX;
+ nEndRow = nStartRow + nDestSizeY;
+ nEndTab = nStartTab;
+ aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
+ if (ScViewUtil::HasFiltered(aMarkRange, rDoc))
+ {
+ bMarkIsFiltered = true;
+ // Fit to clipboard's row count unfiltered rows. If there is no
+ // fit assume that pasting is not possible. Note that nDestSizeY is
+ // size-1 (difference).
+ if (!ScViewUtil::FitToUnfilteredRows(aMarkRange, rDoc, nDestSizeY+1))
+ bNoPaste = true;
+ }
+ aFilteredMark.SetMarkArea( aMarkRange);
+ }
+ else
+ {
+ // Expand the marked area when the destination area is larger than the
+ // current selection, to get the undo do the right thing. (i#106711)
+ ScRange aRange = aFilteredMark.GetMarkArea();
+ if( (aRange.aEnd.Col() - aRange.aStart.Col()) < nDestSizeX )
+ {
+ aRange.aEnd.SetCol(aRange.aStart.Col() + nDestSizeX);
+ aFilteredMark.SetMarkArea(aRange);
+ }
+ }
+ }
+
+ if (bNoPaste)
+ {
+ ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
+ return false;
+ }
+
+ SCROW nUnfilteredRows = aMarkRange.aEnd.Row() - aMarkRange.aStart.Row() + 1;
+ ScRangeList aRangeList;
+ if (bMarkIsFiltered)
+ {
+ ScViewUtil::UnmarkFiltered(aFilteredMark, rDoc);
+ aFilteredMark.FillRangeListWithMarks( &aRangeList, false);
+ nUnfilteredRows = 0;
+ size_t ListSize = aRangeList.size();
+ for ( size_t i = 0; i < ListSize; ++i )
+ {
+ ScRange & r = aRangeList[i];
+ nUnfilteredRows += r.aEnd.Row() - r.aStart.Row() + 1;
+ }
+#if 0
+ /* This isn't needed but could be a desired restriction. */
+ // For filtered, destination rows have to be an exact multiple of
+ // source rows. Note that nDestSizeY is size-1 (difference), so
+ // nDestSizeY==0 fits always.
+ if ((nUnfilteredRows % (nDestSizeY+1)) != 0)
+ {
+ /* FIXME: this should be a more descriptive error message then. */
+ ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
+ return false;
+ }
+#endif
+ }
+
+ // Also for a filtered selection the area is used, for undo et al.
+ if ( aFilteredMark.IsMarked() || bMarkIsFiltered )
+ {
+ aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
+ SCCOL nBlockAddX = nEndCol-nStartCol;
+ SCROW nBlockAddY = nEndRow-nStartRow;
+
+ // request, if the selection is greater than one row/column, but smaller
+ // as the Clipboard (then inserting is done beyond the selection)
+
+ // ClipSize is not size, but difference
+ if ( ( nBlockAddX != 0 && nBlockAddX < nDestSizeX ) ||
+ ( nBlockAddY != 0 && nBlockAddY < nDestSizeY ) ||
+ ( bMarkIsFiltered && nUnfilteredRows < nDestSizeY+1 ) )
+ {
+ ScWaitCursorOff aWaitOff( GetFrameWin() );
+ OUString aMessage = ScResId( STR_PASTE_BIGGER );
+
+ std::unique_ptr<weld::MessageDialog> xQueryBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
+ VclMessageType::Question, VclButtonsType::YesNo,
+ aMessage));
+ xQueryBox->set_default_response(RET_NO);
+ if (xQueryBox->run() != RET_YES)
+ {
+ return false;
+ }
+ }
+
+ if (nBlockAddX <= nDestSizeX)
+ nEndCol = nStartCol + nDestSizeX;
+
+ if (nBlockAddY <= nDestSizeY)
+ {
+ nEndRow = nStartRow + nDestSizeY;
+ if (bMarkIsFiltered || nEndRow > aMarkRange.aEnd.Row())
+ {
+ // Same as above if nothing was marked: re-fit selection to
+ // unfiltered rows. Extending the selection actually may
+ // introduce filtered rows where there weren't any before, so
+ // we also need to test for that.
+ aMarkRange = ScRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
+ if (bMarkIsFiltered || ScViewUtil::HasFiltered(aMarkRange, rDoc))
+ {
+ bMarkIsFiltered = true;
+ // Worst case: all rows up to the end of the sheet are filtered.
+ if (!ScViewUtil::FitToUnfilteredRows(aMarkRange, rDoc, nDestSizeY+1))
+ {
+ ErrorMessage(STR_PASTE_FULL);
+ return false;
+ }
+ }
+ aMarkRange.GetVars( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab);
+ aFilteredMark.SetMarkArea( aMarkRange);
+ if (bMarkIsFiltered)
+ {
+ ScViewUtil::UnmarkFiltered(aFilteredMark, rDoc);
+ aFilteredMark.FillRangeListWithMarks( &aRangeList, true);
+ }
+ }
+ }
+ }
+ else
+ {
+ nStartCol = GetViewData().GetCurX();
+ nStartRow = GetViewData().GetCurY();
+ nStartTab = GetViewData().GetTabNo();
+ nEndCol = nStartCol + nDestSizeX;
+ nEndRow = nStartRow + nDestSizeY;
+ nEndTab = nStartTab;
+ }
+
+ bool bOffLimits = !rDoc.ValidCol(nEndCol) || !rDoc.ValidRow(nEndRow);
+
+ // target-range, as displayed:
+ ScRange aUserRange( nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab );
+
+ // should lines be inserted?
+ // ( too large nEndCol/nEndRow are detected below)
+ bool bInsertCells = ( eMoveMode != INS_NONE && !bOffLimits );
+ if ( bInsertCells )
+ {
+ // Instead of EnterListAction, the paste undo action is merged into the
+ // insert action, so Repeat can insert the right cells
+
+ MarkRange( aUserRange ); // set through CopyFromClip
+
+ // CutMode is reset on insertion of cols/rows but needed again on cell move
+ bool bCut = pClipDoc->IsCutMode();
+ if (!InsertCells( eMoveMode, bRecord, true )) // is inserting possible?
+ {
+ return false;
+ // #i21036# EnterListAction isn't used, and InsertCells doesn't insert
+ // its undo action on failure, so no undo handling is needed here
+ }
+ if ( bCut )
+ pClipDoc->SetCutMode( bCut );
+ }
+ else if (!bOffLimits)
+ {
+ bool bAskIfNotEmpty = bAllowDialogs &&
+ ( nFlags & InsertDeleteFlags::CONTENTS ) &&
+ nFunction == ScPasteFunc::NONE &&
+ SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
+ if ( bAskIfNotEmpty )
+ {
+ ScRangeList aTestRanges(aUserRange);
+ if (!checkDestRangeForOverwrite(aTestRanges, rDoc, aFilteredMark, GetViewData().GetDialogParent()))
+ return false;
+ }
+ }
+
+ SCCOL nClipStartX; // enlarge clipboard-range
+ SCROW nClipStartY;
+ pClipDoc->GetClipStart( nClipStartX, nClipStartY );
+ SCCOL nUndoEndCol = nClipStartX + nClipSizeX;
+ SCROW nUndoEndRow = nClipStartY + nClipSizeY; // end of source area in clipboard document
+ bool bClipOver = false;
+ // #i68690# ExtendMerge for the clip doc must be called with the clipboard's sheet numbers.
+ // The same end column/row can be used for all calls because the clip doc doesn't contain
+ // content outside the clip area.
+ for (SCTAB nClipTab=0; nClipTab < pClipDoc->GetTableCount(); nClipTab++)
+ if ( pClipDoc->HasTable(nClipTab) )
+ if ( pClipDoc->ExtendMerge( nClipStartX,nClipStartY, nUndoEndCol,nUndoEndRow, nClipTab ) )
+ bClipOver = true;
+ nUndoEndCol -= nClipStartX + nClipSizeX;
+ nUndoEndRow -= nClipStartY + nClipSizeY; // now contains only the difference added by ExtendMerge
+ nUndoEndCol = sal::static_int_cast<SCCOL>( nUndoEndCol + nEndCol );
+ nUndoEndRow = sal::static_int_cast<SCROW>( nUndoEndRow + nEndRow ); // destination area, expanded for merged cells
+
+ if (nUndoEndCol>pClipDoc->MaxCol() || nUndoEndRow>pClipDoc->MaxRow())
+ {
+ ErrorMessage(STR_PASTE_FULL);
+ return false;
+ }
+
+ rDoc.ExtendMergeSel( nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark );
+
+ // check cell-protection
+
+ ScEditableTester aTester( rDoc, nStartTab, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return false;
+ }
+
+ //! check overlapping
+ //! just check truly intersection !!!!!!!
+
+ ScDocFunc& rDocFunc = pDocSh->GetDocFunc();
+ if ( bRecord )
+ {
+ OUString aUndo = ScResId( pClipDoc->IsCutMode() ? STR_UNDO_MOVE : STR_UNDO_COPY );
+ pUndoMgr->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
+ }
+
+ if (bClipOver)
+ if (lcl_SelHasAttrib( rDoc, nStartCol,nStartRow, nUndoEndCol,nUndoEndRow, aFilteredMark, HasAttrFlags::Overlapped ))
+ { // "Cell merge not possible if cells already merged"
+ ScDocAttrIterator aIter( rDoc, nStartTab, nStartCol, nStartRow, nUndoEndCol, nUndoEndRow );
+ const ScPatternAttr* pPattern = nullptr;
+ SCCOL nCol = -1;
+ SCROW nRow1 = -1;
+ SCROW nRow2 = -1;
+ while ( ( pPattern = aIter.GetNext( nCol, nRow1, nRow2 ) ) != nullptr )
+ {
+ const ScMergeAttr& rMergeFlag = pPattern->GetItem(ATTR_MERGE);
+ const ScMergeFlagAttr& rMergeFlagAttr = pPattern->GetItem(ATTR_MERGE_FLAG);
+ if (rMergeFlag.IsMerged() || rMergeFlagAttr.IsOverlapped())
+ {
+ ScRange aRange(nCol, nRow1, nStartTab);
+ rDoc.ExtendOverlapped(aRange);
+ rDoc.ExtendMerge(aRange, true);
+ rDocFunc.UnmergeCells(aRange, bRecord, nullptr /*TODO: should pass combined UndoDoc if bRecord*/);
+ }
+ }
+ }
+
+ if ( !bCutMode )
+ {
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->ResetLastCut(); // no more cut-mode
+ }
+
+ bool bColInfo = ( nStartRow==0 && nEndRow==rDoc.MaxRow() );
+ bool bRowInfo = ( nStartCol==0 && nEndCol==rDoc.MaxCol() );
+
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScDocument> pRefUndoDoc;
+ std::unique_ptr<ScRefUndoData> pUndoData;
+
+ if ( bRecord )
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndoSelected( rDoc, aFilteredMark, bColInfo, bRowInfo );
+
+ // all sheets - CopyToDocument skips those that don't exist in pUndoDoc
+ SCTAB nTabCount = rDoc.GetTableCount();
+ rDoc.CopyToDocument( nStartCol, nStartRow, 0, nUndoEndCol, nUndoEndRow, nTabCount-1,
+ nUndoFlags, false, *pUndoDoc );
+
+ if ( bCutMode )
+ {
+ pRefUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pRefUndoDoc->InitUndo( rDoc, 0, nTabCount-1 );
+
+ pUndoData.reset(new ScRefUndoData( &rDoc ));
+ }
+ }
+
+ sal_uInt16 nExtFlags = 0;
+ pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab ); // content before the change
+
+ if (GetViewData().IsActive())
+ {
+ DoneBlockMode();
+ InitOwnBlockMode( aUserRange );
+ }
+ rMark.SetMarkArea( aUserRange );
+ MarkDataChanged();
+
+ // copy from clipboard
+ // save original data in case of calculation
+
+ ScDocumentUniquePtr pMixDoc;
+ if (nFunction != ScPasteFunc::NONE)
+ {
+ bSkipEmptyCells = false;
+ if ( nFlags & InsertDeleteFlags::CONTENTS )
+ {
+ pMixDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pMixDoc->InitUndo( rDoc, nStartTab, nEndTab );
+ rDoc.CopyToDocument(nStartCol, nStartRow, nStartTab, nEndCol, nEndRow, nEndTab,
+ InsertDeleteFlags::CONTENTS, false, *pMixDoc);
+ }
+ }
+
+ /* Make draw layer and start drawing undo.
+ - Needed before AdjustBlockHeight to track moved drawing objects.
+ - Needed before rDoc.CopyFromClip to track inserted note caption objects.
+ */
+ if ( bPasteDraw )
+ pDocSh->MakeDrawLayer();
+ if ( bRecord )
+ rDoc.BeginDrawUndo();
+
+ InsertDeleteFlags nNoObjFlags = nFlags & ~InsertDeleteFlags::OBJECTS;
+ if (!bAsLink)
+ {
+ // copy normally (original range)
+ rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags,
+ pRefUndoDoc.get(), pClipDoc, true, false, bIncludeFiltered,
+ bSkipEmptyCells, (bMarkIsFiltered ? &aRangeList : nullptr) );
+
+ // adapt refs manually in case of transpose
+ if ( bTranspose && bCutMode && (nFlags & InsertDeleteFlags::CONTENTS) )
+ rDoc.UpdateTranspose( aUserRange.aStart, pOrigClipDoc, aFilteredMark, pRefUndoDoc.get() );
+ }
+ else if (!bTranspose)
+ {
+ // copy with bAsLink=TRUE
+ rDoc.CopyFromClip( aUserRange, aFilteredMark, nNoObjFlags, pRefUndoDoc.get(), pClipDoc,
+ true, true, bIncludeFiltered, bSkipEmptyCells );
+ }
+ else
+ {
+ // copy all content (TransClipDoc contains only formula)
+ rDoc.CopyFromClip( aUserRange, aFilteredMark, nContFlags, pRefUndoDoc.get(), pClipDoc );
+ }
+
+ // skipped rows and merged cells don't mix
+ if ( !bIncludeFiltered && pClipDoc->HasClipFilteredRows() )
+ rDocFunc.UnmergeCells( aUserRange, false, nullptr );
+
+ rDoc.ExtendMergeSel( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, true ); // refresh
+ // new range
+
+ if ( pMixDoc ) // calculate with original data?
+ {
+ rDoc.MixDocument( aUserRange, nFunction, bSkipEmptyCells, *pMixDoc );
+ }
+ pMixDoc.reset();
+
+ AdjustBlockHeight(); // update row heights before pasting objects
+
+ ::std::vector< OUString > aExcludedChartNames;
+ SdrPage* pPage = nullptr;
+
+ if ( nFlags & InsertDeleteFlags::OBJECTS )
+ {
+ ScDrawView* pScDrawView = GetScDrawView();
+ SdrModel* pModel = ( pScDrawView ? pScDrawView->GetModel() : nullptr );
+ pPage = ( pModel ? pModel->GetPage( static_cast< sal_uInt16 >( nStartTab ) ) : nullptr );
+ if ( pPage )
+ {
+ ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
+ }
+
+ // Paste the drawing objects after the row heights have been updated.
+
+ rDoc.CopyFromClip( aUserRange, aFilteredMark, InsertDeleteFlags::OBJECTS, pRefUndoDoc.get(), pClipDoc,
+ true, false, bIncludeFiltered );
+ }
+
+ pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab ); // content after the change
+
+ // if necessary, delete autofilter-heads
+ if (bCutMode)
+ if (rDoc.RefreshAutoFilter( nClipStartX,nClipStartY, nClipStartX+nClipSizeX,
+ nClipStartY+nClipSizeY, nStartTab ))
+ {
+ pDocSh->PostPaint(
+ ScRange(nClipStartX, nClipStartY, nStartTab, nClipStartX+nClipSizeX, nClipStartY, nStartTab),
+ PaintPartFlags::Grid );
+ }
+
+ //! remove block-range on RefUndoDoc !!!
+
+ if ( bRecord )
+ {
+ ScDocumentUniquePtr pRedoDoc;
+ // copy redo data after appearance of the first undo
+ // don't create Redo-Doc without RefUndoDoc
+
+ if (pRefUndoDoc)
+ {
+ pRedoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pRedoDoc->InitUndo( rDoc, nStartTab, nEndTab, bColInfo, bRowInfo );
+
+ // move adapted refs to Redo-Doc
+
+ SCTAB nTabCount = rDoc.GetTableCount();
+ pRedoDoc->AddUndoTab( 0, nTabCount-1 );
+ rDoc.CopyUpdated( pRefUndoDoc.get(), pRedoDoc.get() );
+
+ // move old refs to Undo-Doc
+
+ // not charts?
+ pUndoDoc->AddUndoTab( 0, nTabCount-1 );
+ pRefUndoDoc->DeleteArea( nStartCol, nStartRow, nEndCol, nEndRow, aFilteredMark, InsertDeleteFlags::ALL );
+ pRefUndoDoc->CopyToDocument( 0,0,0, pUndoDoc->MaxCol(), pUndoDoc->MaxRow(), nTabCount-1,
+ InsertDeleteFlags::FORMULA, false, *pUndoDoc );
+ pRefUndoDoc.reset();
+ }
+
+ // DeleteUnchanged for pUndoData is in ScUndoPaste ctor,
+ // UndoData for redo is made during first undo
+
+ ScUndoPasteOptions aOptions; // store options for repeat
+ aOptions.nFunction = nFunction;
+ aOptions.bSkipEmptyCells = bSkipEmptyCells;
+ aOptions.bTranspose = bTranspose;
+ aOptions.bAsLink = bAsLink;
+ aOptions.eMoveMode = eMoveMode;
+
+ std::unique_ptr<SfxUndoAction> pUndo(new ScUndoPaste(
+ pDocSh, ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
+ aFilteredMark, std::move(pUndoDoc), std::move(pRedoDoc), nFlags | nUndoFlags, std::move(pUndoData),
+ false, &aOptions )); // false = Redo data not yet copied
+
+ if ( bInsertCells )
+ {
+ // Merge the paste undo action into the insert action.
+ // Use ScUndoWrapper so the ScUndoPaste pointer can be stored in the insert action.
+
+ pUndoMgr->AddUndoAction( std::make_unique<ScUndoWrapper>( std::move(pUndo) ), true );
+ }
+ else
+ pUndoMgr->AddUndoAction( std::move(pUndo) );
+ pUndoMgr->LeaveListAction();
+ }
+
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+ if (bColInfo)
+ {
+ nPaint |= PaintPartFlags::Top;
+ nUndoEndCol = rDoc.MaxCol(); // just for drawing !
+ }
+ if (bRowInfo)
+ {
+ nPaint |= PaintPartFlags::Left;
+ nUndoEndRow = rDoc.MaxRow(); // just for drawing !
+ }
+ pDocSh->PostPaint(
+ ScRange(nStartCol, nStartRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
+ nPaint, nExtFlags);
+ // AdjustBlockHeight has already been called above
+
+ aModificator.SetDocumentModified();
+ PostPasteFromClip(aUserRange, rMark);
+
+ if ( nFlags & InsertDeleteFlags::OBJECTS )
+ {
+ ScModelObj* pModelObj = comphelper::getFromUnoTunnel<ScModelObj>( pDocSh->GetModel() );
+ if ( pPage && pModelObj )
+ {
+ bool bSameDoc = ( rClipParam.getSourceDocID() == rDoc.GetDocumentID() );
+ const ScRangeListVector& rProtectedChartRangesVector( rClipParam.maProtectedChartRangesVector );
+ ScChartHelper::CreateProtectedChartListenersAndNotify( rDoc, pPage, pModelObj, nStartTab,
+ rProtectedChartRangesVector, aExcludedChartNames, bSameDoc );
+ }
+ }
+ OUString aStartAddress = aMarkRange.aStart.GetColRowString();
+ OUString aEndAddress = aMarkRange.aEnd.GetColRowString();
+ collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, "PASTE");
+ return true;
+}
+
+bool ScViewFunc::PasteMultiRangesFromClip(InsertDeleteFlags nFlags, ScDocument* pClipDoc,
+ ScPasteFunc nFunction, bool bSkipEmptyCells,
+ bool bTranspose, bool bAsLink,
+ bool bAllowDialogs, InsCellCmd eMoveMode,
+ InsertDeleteFlags nUndoFlags)
+{
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScMarkData aMark(rViewData.GetMarkData());
+ const ScAddress& rCurPos = rViewData.GetCurPos();
+ ScClipParam& rClipParam = pClipDoc->GetClipParam();
+ SCCOL nColSize = rClipParam.getPasteColSize();
+ SCROW nRowSize = rClipParam.getPasteRowSize(*pClipDoc, /*bIncludeFiltered*/false);
+
+ if (bTranspose)
+ {
+ if (static_cast<SCROW>(rCurPos.Col()) + nRowSize-1 > static_cast<SCROW>(pClipDoc->MaxCol()))
+ {
+ ErrorMessage(STR_PASTE_FULL);
+ return false;
+ }
+
+ ScDocumentUniquePtr pTransClip(new ScDocument(SCDOCMODE_CLIP));
+ pClipDoc->TransposeClip(pTransClip.get(), nFlags, bAsLink, /*bIncludeFiltered*/false);
+ pClipDoc = pTransClip.release();
+ SCCOL nTempColSize = nColSize;
+ nColSize = static_cast<SCCOL>(nRowSize);
+ nRowSize = static_cast<SCROW>(nTempColSize);
+ }
+
+ if (!rDoc.ValidCol(rCurPos.Col()+nColSize-1) || !rDoc.ValidRow(rCurPos.Row()+nRowSize-1))
+ {
+ ErrorMessage(STR_PASTE_FULL);
+ return false;
+ }
+
+ // Determine the first and last selected sheet numbers.
+ SCTAB nTab1 = aMark.GetFirstSelected();
+ SCTAB nTab2 = aMark.GetLastSelected();
+
+ ScDocShellModificator aModificator(*pDocSh);
+
+ // For multi-selection paste, we don't support cell duplication for larger
+ // destination range. In case the destination is marked, we reset it to
+ // the clip size.
+ ScRange aMarkedRange(rCurPos.Col(), rCurPos.Row(), nTab1,
+ rCurPos.Col()+nColSize-1, rCurPos.Row()+nRowSize-1, nTab2);
+
+ // Extend the marked range to account for filtered rows in the destination
+ // area.
+ if (ScViewUtil::HasFiltered(aMarkedRange, rDoc))
+ {
+ if (!ScViewUtil::FitToUnfilteredRows(aMarkedRange, rDoc, nRowSize))
+ return false;
+ }
+
+ bool bAskIfNotEmpty =
+ bAllowDialogs && (nFlags & InsertDeleteFlags::CONTENTS) &&
+ nFunction == ScPasteFunc::NONE && SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
+
+ if (bAskIfNotEmpty)
+ {
+ ScRangeList aTestRanges(aMarkedRange);
+ if (!checkDestRangeForOverwrite(aTestRanges, rDoc, aMark, GetViewData().GetDialogParent()))
+ return false;
+ }
+
+ aMark.SetMarkArea(aMarkedRange);
+ MarkRange(aMarkedRange);
+
+ bool bInsertCells = (eMoveMode != INS_NONE);
+ if (bInsertCells)
+ {
+ if (!InsertCells(eMoveMode, rDoc.IsUndoEnabled(), true))
+ return false;
+ }
+
+ // TODO: position this call better for performance.
+ ResetAutoSpellForContentChange();
+
+ bool bRowInfo = ( aMarkedRange.aStart.Col()==0 && aMarkedRange.aEnd.Col()==pClipDoc->MaxCol() );
+ ScDocumentUniquePtr pUndoDoc;
+ if (rDoc.IsUndoEnabled())
+ {
+ pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ pUndoDoc->InitUndoSelected(rDoc, aMark, false, bRowInfo);
+ rDoc.CopyToDocument(aMarkedRange, nUndoFlags, false, *pUndoDoc, &aMark);
+ }
+
+ ScDocumentUniquePtr pMixDoc;
+ if ( bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
+ {
+ if ( nFlags & InsertDeleteFlags::CONTENTS )
+ {
+ pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ pMixDoc->InitUndoSelected(rDoc, aMark);
+ rDoc.CopyToDocument(aMarkedRange, InsertDeleteFlags::CONTENTS, false, *pMixDoc, &aMark);
+ }
+ }
+
+ /* Make draw layer and start drawing undo.
+ - Needed before AdjustBlockHeight to track moved drawing objects.
+ - Needed before rDoc.CopyFromClip to track inserted note caption objects.
+ */
+ if (nFlags & InsertDeleteFlags::OBJECTS)
+ pDocSh->MakeDrawLayer();
+ if (rDoc.IsUndoEnabled())
+ rDoc.BeginDrawUndo();
+
+ InsertDeleteFlags nCopyFlags = nFlags & ~InsertDeleteFlags::OBJECTS;
+ // in case of transpose, links were added in TransposeClip()
+ if (bAsLink && bTranspose)
+ nCopyFlags |= InsertDeleteFlags::FORMULA;
+ rDoc.CopyMultiRangeFromClip(rCurPos, aMark, nCopyFlags, pClipDoc, true, bAsLink && !bTranspose,
+ /*bIncludeFiltered*/false, bSkipEmptyCells);
+
+ if (pMixDoc)
+ rDoc.MixDocument(aMarkedRange, nFunction, bSkipEmptyCells, *pMixDoc);
+
+ AdjustBlockHeight(); // update row heights before pasting objects
+
+ if (nFlags & InsertDeleteFlags::OBJECTS)
+ {
+ // Paste the drawing objects after the row heights have been updated.
+ rDoc.CopyMultiRangeFromClip(rCurPos, aMark, InsertDeleteFlags::OBJECTS, pClipDoc, true,
+ false, /*bIncludeFiltered*/false, true);
+ }
+
+ if (bRowInfo)
+ pDocSh->PostPaint(aMarkedRange.aStart.Col(), aMarkedRange.aStart.Row(), nTab1, pClipDoc->MaxCol(), pClipDoc->MaxRow(), nTab1, PaintPartFlags::Grid|PaintPartFlags::Left);
+ else
+ {
+ ScRange aTmp = aMarkedRange;
+ aTmp.aStart.SetTab(nTab1);
+ aTmp.aEnd.SetTab(nTab1);
+ pDocSh->PostPaint(aTmp, PaintPartFlags::Grid);
+ }
+
+ if (rDoc.IsUndoEnabled())
+ {
+ SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
+ OUString aUndo = ScResId(
+ pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
+ pUndoMgr->EnterListAction(aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId());
+
+ ScUndoPasteOptions aOptions; // store options for repeat
+ aOptions.nFunction = nFunction;
+ aOptions.bSkipEmptyCells = bSkipEmptyCells;
+ aOptions.bTranspose = bTranspose;
+ aOptions.bAsLink = bAsLink;
+ aOptions.eMoveMode = eMoveMode;
+
+ std::unique_ptr<ScUndoPaste> pUndo(new ScUndoPaste(pDocSh,
+ aMarkedRange, aMark, std::move(pUndoDoc), nullptr, nFlags|nUndoFlags, nullptr, false, &aOptions));
+
+ if (bInsertCells)
+ pUndoMgr->AddUndoAction(std::make_unique<ScUndoWrapper>(std::move(pUndo)), true);
+ else
+ pUndoMgr->AddUndoAction(std::move(pUndo));
+
+ pUndoMgr->LeaveListAction();
+ }
+
+ aModificator.SetDocumentModified();
+ PostPasteFromClip(aMarkedRange, aMark);
+ return true;
+}
+
+bool ScViewFunc::PasteFromClipToMultiRanges(
+ InsertDeleteFlags nFlags, ScDocument* pClipDoc, ScPasteFunc nFunction,
+ bool bSkipEmptyCells, bool bTranspose, bool bAsLink, bool bAllowDialogs,
+ InsCellCmd eMoveMode, InsertDeleteFlags nUndoFlags )
+{
+ if (bTranspose)
+ {
+ // We don't allow transpose for this yet.
+ ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
+ return false;
+ }
+
+ if (eMoveMode != INS_NONE)
+ {
+ // We don't allow insertion mode either. Too complicated.
+ ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
+ return false;
+ }
+
+ ScViewData& rViewData = GetViewData();
+ ScClipParam& rClipParam = pClipDoc->GetClipParam();
+ if (rClipParam.mbCutMode)
+ {
+ // No cut and paste with this, please.
+ ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
+ return false;
+ }
+
+ const ScAddress& rCurPos = rViewData.GetCurPos();
+ ScDocument& rDoc = rViewData.GetDocument();
+
+ ScRange aSrcRange = rClipParam.getWholeRange();
+ SCROW nRowSize = aSrcRange.aEnd.Row() - aSrcRange.aStart.Row() + 1;
+ SCCOL nColSize = aSrcRange.aEnd.Col() - aSrcRange.aStart.Col() + 1;
+
+ if (!rDoc.ValidCol(rCurPos.Col()+nColSize-1) || !rDoc.ValidRow(rCurPos.Row()+nRowSize-1))
+ {
+ ErrorMessage(STR_PASTE_FULL);
+ return false;
+ }
+
+ ScMarkData aMark(rViewData.GetMarkData());
+
+ ScRangeList aRanges;
+ aMark.MarkToSimple();
+ aMark.FillRangeListWithMarks(&aRanges, false);
+ if (!ScClipUtil::CheckDestRanges(rDoc, nColSize, nRowSize, aMark, aRanges))
+ {
+ ErrorMessage(STR_MSSG_PASTEFROMCLIP_0);
+ return false;
+ }
+
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+
+ ScDocShellModificator aModificator(*pDocSh);
+
+ bool bAskIfNotEmpty =
+ bAllowDialogs && (nFlags & InsertDeleteFlags::CONTENTS) &&
+ nFunction == ScPasteFunc::NONE && SC_MOD()->GetInputOptions().GetReplaceCellsWarn();
+
+ if (bAskIfNotEmpty)
+ {
+ if (!checkDestRangeForOverwrite(aRanges, rDoc, aMark, GetViewData().GetDialogParent()))
+ return false;
+ }
+
+ // TODO: position this call better for performance.
+ ResetAutoSpellForContentChange();
+
+ ScDocumentUniquePtr pUndoDoc;
+ if (rDoc.IsUndoEnabled())
+ {
+ pUndoDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ pUndoDoc->InitUndoSelected(rDoc, aMark);
+ for (size_t i = 0, n = aRanges.size(); i < n; ++i)
+ {
+ rDoc.CopyToDocument(
+ aRanges[i], nUndoFlags, false, *pUndoDoc, &aMark);
+ }
+ }
+
+ ScDocumentUniquePtr pMixDoc;
+ if (bSkipEmptyCells || nFunction != ScPasteFunc::NONE)
+ {
+ if (nFlags & InsertDeleteFlags::CONTENTS)
+ {
+ pMixDoc.reset(new ScDocument(SCDOCMODE_UNDO));
+ pMixDoc->InitUndoSelected(rDoc, aMark);
+ for (size_t i = 0, n = aRanges.size(); i < n; ++i)
+ {
+ rDoc.CopyToDocument(
+ aRanges[i], InsertDeleteFlags::CONTENTS, false, *pMixDoc, &aMark);
+ }
+ }
+ }
+
+ if (nFlags & InsertDeleteFlags::OBJECTS)
+ pDocSh->MakeDrawLayer();
+ if (rDoc.IsUndoEnabled())
+ rDoc.BeginDrawUndo();
+
+ // First, paste everything but the drawing objects.
+ for (size_t i = 0, n = aRanges.size(); i < n; ++i)
+ {
+ rDoc.CopyFromClip(
+ aRanges[i], aMark, (nFlags & ~InsertDeleteFlags::OBJECTS), nullptr, pClipDoc,
+ false, false, true, bSkipEmptyCells);
+ }
+
+ if (pMixDoc)
+ {
+ for (size_t i = 0, n = aRanges.size(); i < n; ++i)
+ rDoc.MixDocument(aRanges[i], nFunction, bSkipEmptyCells, *pMixDoc);
+ }
+
+ AdjustBlockHeight(); // update row heights before pasting objects
+
+ // Then paste the objects.
+ if (nFlags & InsertDeleteFlags::OBJECTS)
+ {
+ for (size_t i = 0, n = aRanges.size(); i < n; ++i)
+ {
+ rDoc.CopyFromClip(
+ aRanges[i], aMark, InsertDeleteFlags::OBJECTS, nullptr, pClipDoc,
+ false, false, true, bSkipEmptyCells);
+ }
+ }
+
+ // Refresh the range that includes all pasted ranges. We only need to
+ // refresh the current sheet.
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+ bool bRowInfo = (aSrcRange.aStart.Col()==0 && aSrcRange.aEnd.Col()==pClipDoc->MaxCol());
+ if (bRowInfo)
+ nPaint |= PaintPartFlags::Left;
+ pDocSh->PostPaint(aRanges, nPaint);
+
+ if (rDoc.IsUndoEnabled())
+ {
+ SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
+ OUString aUndo = ScResId(
+ pClipDoc->IsCutMode() ? STR_UNDO_CUT : STR_UNDO_COPY);
+ pUndoMgr->EnterListAction(aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId());
+
+ ScUndoPasteOptions aOptions; // store options for repeat
+ aOptions.nFunction = nFunction;
+ aOptions.bSkipEmptyCells = bSkipEmptyCells;
+ aOptions.bTranspose = bTranspose;
+ aOptions.bAsLink = bAsLink;
+ aOptions.eMoveMode = eMoveMode;
+
+
+ pUndoMgr->AddUndoAction(
+ std::make_unique<ScUndoPaste>(
+ pDocSh, aRanges, aMark, std::move(pUndoDoc), nullptr, nFlags|nUndoFlags, nullptr, false, &aOptions));
+ pUndoMgr->LeaveListAction();
+ }
+
+ aModificator.SetDocumentModified();
+ PostPasteFromClip(aRanges, aMark);
+
+ return false;
+}
+
+void ScViewFunc::PostPasteFromClip(const ScRangeList& rPasteRanges, const ScMarkData& rMark)
+{
+ ScViewData& rViewData = GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ pDocSh->UpdateOle(rViewData);
+
+ SelectionChanged(true);
+
+ ScModelObj* pModelObj = HelperNotifyChanges::getMustPropagateChangesModel(*pDocSh);
+ if (!pModelObj)
+ return;
+
+ ScRangeList aChangeRanges;
+ for (size_t i = 0, n = rPasteRanges.size(); i < n; ++i)
+ {
+ const ScRange& r = rPasteRanges[i];
+ for (const auto& rTab : rMark)
+ {
+ ScRange aChangeRange(r);
+ aChangeRange.aStart.SetTab(rTab);
+ aChangeRange.aEnd.SetTab(rTab);
+ aChangeRanges.push_back(aChangeRange);
+ }
+ }
+ HelperNotifyChanges::Notify(*pModelObj, aChangeRanges);
+}
+
+// D R A G A N D D R O P
+
+// inside the doc
+
+bool ScViewFunc::MoveBlockTo( const ScRange& rSource, const ScAddress& rDestPos,
+ bool bCut )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ HideAllCursors();
+
+ ResetAutoSpellForContentChange();
+
+ bool bSuccess = true;
+ SCTAB nDestTab = rDestPos.Tab();
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ if ( rSource.aStart.Tab() == nDestTab && rSource.aEnd.Tab() == nDestTab && rMark.GetSelectCount() > 1 )
+ {
+ // moving within one table and several tables selected -> apply to all selected tables
+
+ OUString aUndo = ScResId( bCut ? STR_UNDO_MOVE : STR_UNDO_COPY );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
+
+ // collect ranges of consecutive selected tables
+
+ ScRange aLocalSource = rSource;
+ ScAddress aLocalDest = rDestPos;
+ SCTAB nTabCount = pDocSh->GetDocument().GetTableCount();
+ SCTAB nStartTab = 0;
+ while ( nStartTab < nTabCount && bSuccess )
+ {
+ while ( nStartTab < nTabCount && !rMark.GetTableSelect(nStartTab) )
+ ++nStartTab;
+ if ( nStartTab < nTabCount )
+ {
+ SCTAB nEndTab = nStartTab;
+ while ( nEndTab+1 < nTabCount && rMark.GetTableSelect(nEndTab+1) )
+ ++nEndTab;
+
+ aLocalSource.aStart.SetTab( nStartTab );
+ aLocalSource.aEnd.SetTab( nEndTab );
+ aLocalDest.SetTab( nStartTab );
+
+ bSuccess = pDocSh->GetDocFunc().MoveBlock(
+ aLocalSource, aLocalDest, bCut, true/*bRecord*/, true/*bPaint*/, true/*bApi*/ );
+
+ nStartTab = nEndTab + 1;
+ }
+ }
+
+ pDocSh->GetUndoManager()->LeaveListAction();
+ }
+ else
+ {
+ // move the block as specified
+ bSuccess = pDocSh->GetDocFunc().MoveBlock(
+ rSource, rDestPos, bCut, true/*bRecord*/, true/*bPaint*/, true/*bApi*/ );
+ }
+
+ ShowAllCursors();
+ if (bSuccess)
+ {
+ // mark destination range
+ ScAddress aDestEnd(
+ rDestPos.Col() + rSource.aEnd.Col() - rSource.aStart.Col(),
+ rDestPos.Row() + rSource.aEnd.Row() - rSource.aStart.Row(),
+ nDestTab );
+
+ bool bIncludeFiltered = bCut;
+ if ( !bIncludeFiltered )
+ {
+ // find number of non-filtered rows
+ SCROW nPastedCount = pDocSh->GetDocument().CountNonFilteredRows(
+ rSource.aStart.Row(), rSource.aEnd.Row(), rSource.aStart.Tab());
+
+ if ( nPastedCount == 0 )
+ nPastedCount = 1;
+ aDestEnd.SetRow( rDestPos.Row() + nPastedCount - 1 );
+ }
+
+ MarkRange( ScRange( rDestPos, aDestEnd ), false ); //! sal_False ???
+
+ pDocSh->UpdateOle(GetViewData());
+ SelectionChanged();
+ }
+ return bSuccess;
+}
+
+// link inside the doc
+
+bool ScViewFunc::LinkBlock( const ScRange& rSource, const ScAddress& rDestPos )
+{
+ // check overlapping
+
+ if ( rSource.aStart.Tab() == rDestPos.Tab() )
+ {
+ SCCOL nDestEndCol = rDestPos.Col() + ( rSource.aEnd.Col() - rSource.aStart.Col() );
+ SCROW nDestEndRow = rDestPos.Row() + ( rSource.aEnd.Row() - rSource.aStart.Row() );
+
+ if ( rSource.aStart.Col() <= nDestEndCol && rDestPos.Col() <= rSource.aEnd.Col() &&
+ rSource.aStart.Row() <= nDestEndRow && rDestPos.Row() <= rSource.aEnd.Row() )
+ {
+ return false;
+ }
+ }
+
+ // run with paste
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+ rDoc.CopyTabToClip( rSource.aStart.Col(), rSource.aStart.Row(),
+ rSource.aEnd.Col(), rSource.aEnd.Row(),
+ rSource.aStart.Tab(), pClipDoc.get() );
+
+ // mark destination area (set cursor, no marks)
+
+ if ( GetViewData().GetTabNo() != rDestPos.Tab() )
+ SetTabNo( rDestPos.Tab() );
+
+ MoveCursorAbs( rDestPos.Col(), rDestPos.Row(), SC_FOLLOW_NONE, false, false );
+
+ // Paste
+
+ PasteFromClip( InsertDeleteFlags::ALL, pClipDoc.get(), ScPasteFunc::NONE, false, false, true ); // as a link
+
+ return true;
+}
+
+void ScViewFunc::DataFormPutData( SCROW nCurrentRow ,
+ SCROW nStartRow , SCCOL nStartCol ,
+ SCROW nEndRow , SCCOL nEndCol ,
+ std::vector<std::unique_ptr<ScDataFormFragment>>& rEdits,
+ sal_uInt16 aColLength )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ ScDocShellModificator aModificator( *pDocSh );
+ SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
+
+ const bool bRecord( rDoc.IsUndoEnabled());
+ ScDocumentUniquePtr pUndoDoc;
+ ScDocumentUniquePtr pRedoDoc;
+ std::unique_ptr<ScRefUndoData> pUndoData;
+ SCTAB nTab = GetViewData().GetTabNo();
+ SCTAB nStartTab = nTab;
+ SCTAB nEndTab = nTab;
+
+ {
+ ScChangeTrack* pChangeTrack = rDoc.GetChangeTrack();
+ if ( pChangeTrack )
+ pChangeTrack->ResetLastCut(); // no more cut-mode
+ }
+ ScRange aUserRange( nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab );
+ bool bColInfo = ( nStartRow==0 && nEndRow==rDoc.MaxRow() );
+ bool bRowInfo = ( nStartCol==0 && nEndCol==rDoc.MaxCol() );
+ SCCOL nUndoEndCol = nStartCol+aColLength-1;
+ SCROW nUndoEndRow = nCurrentRow;
+
+ if ( bRecord )
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndoSelected( rDoc , rMark , bColInfo , bRowInfo );
+ rDoc.CopyToDocument( aUserRange , InsertDeleteFlags::VALUE , false, *pUndoDoc );
+ }
+ sal_uInt16 nExtFlags = 0;
+ pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nStartRow, nStartTab , nEndCol, nEndRow, nEndTab ); // content before the change
+ rDoc.BeginDrawUndo();
+
+ for(sal_uInt16 i = 0; i < aColLength; i++)
+ {
+ if (rEdits[i] != nullptr)
+ {
+ OUString aFieldName = rEdits[i]->m_xEdit->get_text();
+ rDoc.SetString( nStartCol + i, nCurrentRow, nTab, aFieldName );
+ }
+ }
+ pDocSh->UpdatePaintExt( nExtFlags, nStartCol, nCurrentRow, nStartTab, nEndCol, nCurrentRow, nEndTab ); // content after the change
+ std::unique_ptr<SfxUndoAction> pUndo( new ScUndoDataForm( pDocSh,
+ nStartCol, nCurrentRow, nStartTab,
+ nUndoEndCol, nUndoEndRow, nEndTab, rMark,
+ std::move(pUndoDoc), std::move(pRedoDoc),
+ std::move(pUndoData) ) );
+ pUndoMgr->AddUndoAction( std::make_unique<ScUndoWrapper>( std::move(pUndo) ), true );
+
+ PaintPartFlags nPaint = PaintPartFlags::Grid;
+ if (bColInfo)
+ {
+ nPaint |= PaintPartFlags::Top;
+ nUndoEndCol = rDoc.MaxCol(); // just for drawing !
+ }
+ if (bRowInfo)
+ {
+ nPaint |= PaintPartFlags::Left;
+ nUndoEndRow = rDoc.MaxRow(); // just for drawing !
+ }
+
+ pDocSh->PostPaint(
+ ScRange(nStartCol, nCurrentRow, nStartTab, nUndoEndCol, nUndoEndRow, nEndTab),
+ nPaint, nExtFlags);
+ pDocSh->UpdateOle(GetViewData());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/viewfun4.cxx b/sc/source/ui/view/viewfun4.cxx
new file mode 100644
index 000000000..024b11e3b
--- /dev/null
+++ b/sc/source/ui/view/viewfun4.cxx
@@ -0,0 +1,789 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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 <memory>
+#include <editeng/eeitem.hxx>
+
+#include <editeng/editobj.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/editview.hxx>
+#include <editeng/flditem.hxx>
+#include <sot/storage.hxx>
+#include <svx/hlnkitem.hxx>
+#include <editeng/unolingu.hxx>
+
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/docfilt.hxx>
+#include <sfx2/fcontnr.hxx>
+#include <svtools/langtab.hxx>
+#include <vcl/graphicfilter.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/transfer.hxx>
+#include <svl/urlbmk.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <avmedia/mediawindow.hxx>
+#include <osl/diagnose.h>
+
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/storagehelper.hxx>
+
+#include <viewfunc.hxx>
+#include <docsh.hxx>
+#include <document.hxx>
+#include <globstr.hrc>
+#include <global.hxx>
+#include <scresid.hxx>
+#include <undoblk.hxx>
+#include <undocell.hxx>
+#include <formulacell.hxx>
+#include <scmod.hxx>
+#include <spelleng.hxx>
+#include <patattr.hxx>
+#include <tabvwsh.hxx>
+#include <impex.hxx>
+#include <editutil.hxx>
+#include <editable.hxx>
+#include <dociter.hxx>
+#include <reffind.hxx>
+#include <compiler.hxx>
+#include <tokenarray.hxx>
+#include <refupdatecontext.hxx>
+#include <gridwin.hxx>
+#include <refundo.hxx>
+
+using namespace com::sun::star;
+
+void ScViewFunc::PasteRTF( SCCOL nStartCol, SCROW nStartRow,
+ const css::uno::Reference< css::datatransfer::XTransferable >& rxTransferable )
+{
+ TransferableDataHelper aDataHelper( rxTransferable );
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT ) )
+ {
+ HideAllCursors();
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ const bool bRecord (rDoc.IsUndoEnabled());
+
+ const ScPatternAttr* pPattern = rDoc.GetPattern( nStartCol, nStartRow, nTab );
+ std::optional<ScTabEditEngine> pEngine(std::in_place, *pPattern, rDoc.GetEnginePool(), &rDoc );
+ pEngine->EnableUndo( false );
+
+ vcl::Window* pActWin = GetActiveWin();
+ if (pActWin)
+ {
+ pEngine->SetPaperSize(Size(100000,100000));
+ ScopedVclPtrInstance< vcl::Window > aWin( pActWin );
+ EditView aEditView( &*pEngine, aWin.get() );
+ aEditView.SetOutputArea(tools::Rectangle(0,0,100000,100000));
+
+ // same method now for clipboard or drag&drop
+ // mba: clipboard always must contain absolute URLs (could be from alien source)
+ aEditView.InsertText( rxTransferable, OUString(), true );
+ }
+
+ sal_Int32 nParCnt = pEngine->GetParagraphCount();
+ if (nParCnt)
+ {
+ SCROW nEndRow = nStartRow + static_cast<SCROW>(nParCnt) - 1;
+ if (nEndRow > rDoc.MaxRow())
+ nEndRow = rDoc.MaxRow();
+
+ ScDocumentUniquePtr pUndoDoc;
+ if (bRecord)
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ rDoc.CopyToDocument( nStartCol,nStartRow,nTab, nStartCol,nEndRow,nTab, InsertDeleteFlags::ALL, false, *pUndoDoc );
+ }
+
+ SCROW nRow = nStartRow;
+
+ // Temporarily turn off undo generation for this lot
+ bool bUndoEnabled = rDoc.IsUndoEnabled();
+ rDoc.EnableUndo( false );
+ for( sal_Int32 n = 0; n < nParCnt; n++ )
+ {
+ std::unique_ptr<EditTextObject> pObject(pEngine->CreateTextObject(n));
+ EnterData(nStartCol, nRow, nTab, *pObject, true);
+ if( ++nRow > rDoc.MaxRow() )
+ break;
+ }
+ rDoc.EnableUndo(bUndoEnabled);
+
+ if (bRecord)
+ {
+ ScDocumentUniquePtr pRedoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pRedoDoc->InitUndo( rDoc, nTab, nTab );
+ rDoc.CopyToDocument( nStartCol,nStartRow,nTab, nStartCol,nEndRow,nTab, InsertDeleteFlags::ALL|InsertDeleteFlags::NOCAPTIONS, false, *pRedoDoc );
+
+ ScRange aMarkRange(nStartCol, nStartRow, nTab, nStartCol, nEndRow, nTab);
+ ScMarkData aDestMark(rDoc.GetSheetLimits());
+ aDestMark.SetMarkArea( aMarkRange );
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoPaste>( pDocSh, aMarkRange, aDestMark,
+ std::move(pUndoDoc), std::move(pRedoDoc), InsertDeleteFlags::ALL, nullptr));
+ }
+ }
+
+ pEngine.reset();
+
+ ShowAllCursors();
+ }
+ else
+ {
+ HideAllCursors();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScImportExport aImpEx( pDocSh->GetDocument(),
+ ScAddress( nStartCol, nStartRow, GetViewData().GetTabNo() ) );
+
+ OUString aStr;
+ tools::SvRef<SotTempStream> xStream;
+ if ( aDataHelper.GetSotStorageStream( SotClipboardFormatId::RTF, xStream ) && xStream.is() )
+ // mba: clipboard always must contain absolute URLs (could be from alien source)
+ aImpEx.ImportStream( *xStream, OUString(), SotClipboardFormatId::RTF );
+ else if ( aDataHelper.GetString( SotClipboardFormatId::RTF, aStr ) )
+ aImpEx.ImportString( aStr, SotClipboardFormatId::RTF );
+ else if ( aDataHelper.GetSotStorageStream( SotClipboardFormatId::RICHTEXT, xStream ) && xStream.is() )
+ aImpEx.ImportStream( *xStream, OUString(), SotClipboardFormatId::RICHTEXT );
+ else if ( aDataHelper.GetString( SotClipboardFormatId::RICHTEXT, aStr ) )
+ aImpEx.ImportString( aStr, SotClipboardFormatId::RICHTEXT );
+
+ AdjustRowHeight( nStartRow, aImpEx.GetRange().aEnd.Row(), true );
+ pDocSh->UpdateOle(GetViewData());
+ ShowAllCursors();
+ }
+}
+void ScViewFunc::DoRefConversion()
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScRange aMarkRange;
+ rMark.MarkToSimple();
+ bool bMulti = rMark.IsMultiMarked();
+ if (bMulti)
+ aMarkRange = rMark.GetMultiMarkArea();
+ else if (rMark.IsMarked())
+ aMarkRange = rMark.GetMarkArea();
+ else
+ {
+ aMarkRange = ScRange( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ }
+ ScEditableTester aTester( rDoc, aMarkRange.aStart.Col(), aMarkRange.aStart.Row(),
+ aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(),rMark );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ bool bOk = false;
+
+ ScDocumentUniquePtr pUndoDoc;
+ if (bRecord)
+ {
+ pUndoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
+ SCTAB nTab = aMarkRange.aStart.Tab();
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+
+ if ( rMark.GetSelectCount() > 1 )
+ {
+ for (const auto& rTab : rMark)
+ if ( rTab != nTab )
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ }
+ ScRange aCopyRange = aMarkRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ALL, bMulti, *pUndoDoc, &rMark );
+ }
+
+ ScRangeListRef xRanges;
+ GetViewData().GetMultiArea( xRanges );
+ size_t nCount = xRanges->size();
+
+ for (const SCTAB& i : rMark)
+ {
+ for (size_t j = 0; j < nCount; ++j)
+ {
+ ScRange aRange = (*xRanges)[j];
+ aRange.aStart.SetTab(i);
+ aRange.aEnd.SetTab(i);
+ ScCellIterator aIter( rDoc, aRange );
+ for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
+ {
+ if (aIter.getType() != CELLTYPE_FORMULA)
+ continue;
+
+ ScFormulaCell* pCell = aIter.getFormulaCell();
+ ScMatrixMode eMatrixMode = pCell->GetMatrixFlag();
+ if (eMatrixMode == ScMatrixMode::Reference)
+ continue;
+
+ OUString aOld = pCell->GetFormula();
+ sal_Int32 nLen = aOld.getLength();
+ if (eMatrixMode == ScMatrixMode::Formula)
+ {
+ assert(nLen >= 2 && aOld[0] == '{' && aOld[nLen-1] == '}');
+ nLen -= 2;
+ aOld = aOld.copy( 1, nLen);
+ }
+ ScRefFinder aFinder( aOld, aIter.GetPos(), rDoc, rDoc.GetAddressConvention() );
+ aFinder.ToggleRel( 0, nLen );
+ if (aFinder.GetFound())
+ {
+ ScAddress aPos = pCell->aPos;
+ const OUString& aNew = aFinder.GetText();
+ ScCompiler aComp( rDoc, aPos, rDoc.GetGrammar());
+ std::unique_ptr<ScTokenArray> pArr(aComp.CompileString(aNew));
+ ScFormulaCell* pNewCell =
+ new ScFormulaCell(
+ rDoc, aPos, *pArr, formula::FormulaGrammar::GRAM_DEFAULT, eMatrixMode);
+
+ rDoc.SetFormulaCell(aPos, pNewCell);
+ bOk = true;
+ }
+ }
+ }
+ }
+ if (bRecord)
+ {
+ ScDocumentUniquePtr pRedoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ SCTAB nTab = aMarkRange.aStart.Tab();
+ pRedoDoc->InitUndo( rDoc, nTab, nTab );
+
+ if ( rMark.GetSelectCount() > 1 )
+ {
+ for (const auto& rTab : rMark)
+ if ( rTab != nTab )
+ pRedoDoc->AddUndoTab( rTab, rTab );
+ }
+ ScRange aCopyRange = aMarkRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ALL, bMulti, *pRedoDoc, &rMark );
+
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoRefConversion>( pDocSh,
+ aMarkRange, rMark, std::move(pUndoDoc), std::move(pRedoDoc), bMulti) );
+ }
+
+ pDocSh->PostPaint( aMarkRange, PaintPartFlags::Grid );
+ pDocSh->UpdateOle(GetViewData());
+ pDocSh->SetDocumentModified();
+ CellContentChanged();
+
+ if (!bOk)
+ ErrorMessage(STR_ERR_NOREF);
+}
+
+// Thesaurus - Undo ok
+void ScViewFunc::DoThesaurus()
+{
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ ScSplitPos eWhich = GetViewData().GetActivePart();
+ EESpellState eState;
+ EditView* pEditView = nullptr;
+ std::unique_ptr<ESelection> pEditSel;
+ std::unique_ptr<ScEditEngineDefaulter> pThesaurusEngine;
+ bool bIsEditMode = GetViewData().HasEditView(eWhich);
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+ if (bIsEditMode) // edit mode active
+ {
+ GetViewData().GetEditView(eWhich, pEditView, nCol, nRow);
+ pEditSel.reset(new ESelection(pEditView->GetSelection()));
+ SC_MOD()->InputEnterHandler();
+ GetViewData().GetBindings().Update(); // otherwise the Sfx becomes mixed-up...
+ }
+ else
+ {
+ nCol = GetViewData().GetCurX();
+ nRow = GetViewData().GetCurY();
+ }
+ nTab = GetViewData().GetTabNo();
+
+ ScAddress aPos(nCol, nRow, nTab);
+ ScEditableTester aTester( rDoc, nCol, nRow, nCol, nRow, rMark );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+
+ ScCellValue aOldText;
+ aOldText.assign(rDoc, aPos);
+ if (aOldText.meType != CELLTYPE_STRING && aOldText.meType != CELLTYPE_EDIT)
+ {
+ ErrorMessage(STR_THESAURUS_NO_STRING);
+ return;
+ }
+
+ uno::Reference<linguistic2::XSpellChecker1> xSpeller = LinguMgr::GetSpellChecker();
+
+ pThesaurusEngine.reset(new ScEditEngineDefaulter(rDoc.GetEnginePool()));
+ pThesaurusEngine->SetEditTextObjectPool( rDoc.GetEditPool() );
+ pThesaurusEngine->SetRefDevice(GetViewData().GetActiveWin()->GetOutDev());
+ pThesaurusEngine->SetSpeller(xSpeller);
+ MakeEditView(pThesaurusEngine.get(), nCol, nRow );
+ SfxItemSet aEditDefaults(pThesaurusEngine->GetEmptyItemSet());
+ const ScPatternAttr* pPattern = rDoc.GetPattern(nCol, nRow, nTab);
+ if (pPattern)
+ {
+ pPattern->FillEditItemSet( &aEditDefaults );
+ pThesaurusEngine->SetDefaults( aEditDefaults );
+ }
+
+ if (aOldText.meType == CELLTYPE_EDIT)
+ pThesaurusEngine->SetTextCurrentDefaults(*aOldText.mpEditText);
+ else
+ pThesaurusEngine->SetTextCurrentDefaults(aOldText.getString(rDoc));
+
+ pEditView = GetViewData().GetEditView(GetViewData().GetActivePart());
+ if (pEditSel)
+ pEditView->SetSelection(*pEditSel);
+ else
+ pEditView->SetSelection(ESelection(0,0,0,0));
+
+ pThesaurusEngine->ClearModifyFlag();
+
+ // language is now in EditEngine attributes -> no longer passed to StartThesaurus
+
+ eState = pEditView->StartThesaurus(GetViewData().GetDialogParent());
+ OSL_ENSURE(eState != EESpellState::NoSpeller, "No SpellChecker");
+
+ if (eState == EESpellState::ErrorFound) // should happen later through Wrapper!
+ {
+ LanguageType eLnge = ScViewUtil::GetEffLanguage( rDoc, ScAddress( nCol, nRow, nTab ) );
+ OUString aErr = SvtLanguageTable::GetLanguageString(eLnge) + ScResId( STR_SPELLING_NO_LANG );
+
+ std::unique_ptr<weld::MessageDialog> xInfoBox(Application::CreateMessageDialog(GetViewData().GetDialogParent(),
+ VclMessageType::Info, VclButtonsType::Ok,
+ aErr));
+ xInfoBox->run();
+ }
+ if (pThesaurusEngine->IsModified())
+ {
+ ScCellValue aNewText;
+
+ if (aOldText.meType == CELLTYPE_EDIT)
+ {
+ // The cell will own the text object instance.
+ std::unique_ptr<EditTextObject> pText = pThesaurusEngine->CreateTextObject();
+ auto tmp = pText.get();
+ if (rDoc.SetEditText(ScAddress(nCol,nRow,nTab), std::move(pText)))
+ aNewText.set(*tmp);
+ }
+ else
+ {
+ OUString aStr = pThesaurusEngine->GetText();
+ aNewText.set(rDoc.GetSharedStringPool().intern(aStr));
+ rDoc.SetString(nCol, nRow, nTab, aStr);
+ }
+
+ pDocSh->SetDocumentModified();
+ if (bRecord)
+ {
+ GetViewData().GetDocShell()->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoThesaurus>(
+ GetViewData().GetDocShell(), nCol, nRow, nTab, aOldText, aNewText));
+ }
+ }
+
+ KillEditView(true);
+ pDocSh->PostPaintGridAll();
+}
+
+void ScViewFunc::DoHangulHanjaConversion()
+{
+ ScConversionParam aConvParam( SC_CONVERSION_HANGULHANJA, LANGUAGE_KOREAN, 0, true );
+ DoSheetConversion( aConvParam );
+}
+
+void ScViewFunc::DoSheetConversion( const ScConversionParam& rConvParam )
+{
+ SCCOL nCol;
+ SCROW nRow;
+ SCTAB nTab;
+ ScViewData& rViewData = GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData& rMark = rViewData.GetMarkData();
+ ScSplitPos eWhich = rViewData.GetActivePart();
+ EditView* pEditView = nullptr;
+ bool bIsEditMode = rViewData.HasEditView(eWhich);
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+ if (bIsEditMode) // edit mode active
+ {
+ rViewData.GetEditView(eWhich, pEditView, nCol, nRow);
+ SC_MOD()->InputEnterHandler();
+ }
+ else
+ {
+ nCol = rViewData.GetCurX();
+ nRow = rViewData.GetCurY();
+
+ AlignToCursor( nCol, nRow, SC_FOLLOW_JUMP);
+ }
+ nTab = rViewData.GetTabNo();
+
+ rMark.MarkToMulti();
+ bool bMarked = rMark.IsMultiMarked();
+ if (bMarked)
+ {
+ ScEditableTester aTester( rDoc, rMark );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ return;
+ }
+ }
+
+ ScDocumentUniquePtr pUndoDoc;
+ ScDocumentUniquePtr pRedoDoc;
+ if (bRecord)
+ {
+ pUndoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ pRedoDoc.reset( new ScDocument( SCDOCMODE_UNDO ) );
+ pRedoDoc->InitUndo( rDoc, nTab, nTab );
+
+ if ( rMark.GetSelectCount() > 1 )
+ {
+ for (const auto& rTab : rMark)
+ if ( rTab != nTab )
+ {
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ pRedoDoc->AddUndoTab( rTab, rTab );
+ }
+ }
+ }
+
+ // from here no return
+
+ bool bOldEnabled = rDoc.IsIdleEnabled();
+ rDoc.EnableIdle(false); // stop online spelling
+
+ // *** create and init the edit engine *** --------------------------------
+
+ std::unique_ptr<ScConversionEngineBase> pEngine;
+ switch( rConvParam.GetType() )
+ {
+ case SC_CONVERSION_SPELLCHECK:
+ pEngine.reset(new ScSpellingEngine(
+ rDoc.GetEnginePool(), rViewData, pUndoDoc.get(), pRedoDoc.get(), LinguMgr::GetSpellChecker() ));
+ break;
+ case SC_CONVERSION_HANGULHANJA:
+ case SC_CONVERSION_CHINESE_TRANSL:
+ pEngine.reset(new ScTextConversionEngine(
+ rDoc.GetEnginePool(), rViewData, rConvParam, pUndoDoc.get(), pRedoDoc.get() ));
+ break;
+ default:
+ OSL_FAIL( "ScViewFunc::DoSheetConversion - unknown conversion type" );
+ }
+
+ MakeEditView( pEngine.get(), nCol, nRow );
+ pEngine->SetRefDevice( rViewData.GetActiveWin()->GetOutDev() );
+ // simulate dummy cell:
+ pEditView = rViewData.GetEditView( rViewData.GetActivePart() );
+ rViewData.SetSpellingView( pEditView );
+ tools::Rectangle aRect( Point( 0, 0 ), Point( 0, 0 ) );
+ pEditView->SetOutputArea( aRect );
+ pEngine->SetControlWord( EEControlBits::USECHARATTRIBS );
+ pEngine->EnableUndo( false );
+ pEngine->SetPaperSize( aRect.GetSize() );
+ pEngine->SetTextCurrentDefaults( OUString() );
+
+ // *** do the conversion *** ----------------------------------------------
+
+ pEngine->ClearModifyFlag();
+ pEngine->ConvertAll(GetViewData().GetDialogParent(), *pEditView);
+
+ // *** undo/redo *** ------------------------------------------------------
+
+ if( pEngine->IsAnyModified() )
+ {
+ if (bRecord)
+ {
+ SCCOL nNewCol = rViewData.GetCurX();
+ SCROW nNewRow = rViewData.GetCurY();
+ rViewData.GetDocShell()->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoConversion>(
+ pDocSh, rMark,
+ nCol, nRow, nTab, std::move(pUndoDoc),
+ nNewCol, nNewRow, nTab, std::move(pRedoDoc), rConvParam ) );
+ }
+
+ sc::SetFormulaDirtyContext aCxt;
+ rDoc.SetAllFormulasDirty(aCxt);
+
+ pDocSh->SetDocumentModified();
+ }
+ else
+ {
+ pUndoDoc.reset();
+ pRedoDoc.reset();
+ }
+
+ // *** final cleanup *** --------------------------------------------------
+
+ rViewData.SetSpellingView( nullptr );
+ KillEditView(true);
+ pEngine.reset();
+ pDocSh->PostPaintGridAll();
+ rViewData.GetViewShell()->UpdateInputHandler();
+ rDoc.EnableIdle(bOldEnabled);
+}
+
+// past from SotClipboardFormatId::FILE items
+// is not called directly from Drop, but asynchronously -> dialogs are allowed
+
+bool ScViewFunc::PasteFile( const Point& rPos, const OUString& rFile, bool bLink )
+{
+ INetURLObject aURL;
+ aURL.SetSmartURL( rFile );
+ OUString aStrURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
+
+ // is it a media URL?
+#if HAVE_FEATURE_AVMEDIA
+ if( ::avmedia::MediaWindow::isMediaURL( aStrURL, ""/*TODO?*/ ) )
+ {
+ const SfxStringItem aMediaURLItem( SID_INSERT_AVMEDIA, aStrURL );
+ return ( nullptr != GetViewData().GetDispatcher().ExecuteList(
+ SID_INSERT_AVMEDIA, SfxCallMode::SYNCHRON,
+ { &aMediaURLItem }) );
+ }
+#endif
+
+ if (!bLink) // for bLink only graphics or URL
+ {
+ // 1. can I open the file?
+ std::shared_ptr<const SfxFilter> pFlt;
+
+ // search only for its own filters, without selection box (as in ScDocumentLoader)
+ SfxFilterMatcher aMatcher( ScDocShell::Factory().GetFilterContainer()->GetName() );
+ SfxMedium aSfxMedium( aStrURL, (StreamMode::READ | StreamMode::SHARE_DENYNONE) );
+ // #i73992# GuessFilter no longer calls UseInteractionHandler.
+ // This is UI, so it can be called here.
+ aSfxMedium.UseInteractionHandler(true);
+ ErrCode nErr = aMatcher.GuessFilter( aSfxMedium, pFlt );
+
+ if ( pFlt && !nErr )
+ {
+ // code stolen from the SFX!
+ SfxDispatcher &rDispatcher = GetViewData().GetDispatcher();
+ SfxStringItem aFileNameItem( SID_FILE_NAME, aStrURL );
+ SfxStringItem aFilterItem( SID_FILTER_NAME, pFlt->GetName() );
+ // #i69524# add target, as in SfxApplication when the Open dialog is used
+ SfxStringItem aTargetItem( SID_TARGETNAME, "_default" );
+
+ // Open Asynchronously, because it can also happen from D&D
+ // and that is not so good for the MAC...
+ return (nullptr != rDispatcher.ExecuteList(SID_OPENDOC,
+ SfxCallMode::ASYNCHRON,
+ { &aFileNameItem, &aFilterItem, &aTargetItem}));
+ }
+ }
+
+ // 2. can the file be inserted using the graphics filter?
+ // (as a link, since the Gallery provides it in this way)
+
+ Graphic aGraphic;
+ GraphicFilter& rGraphicFilter = GraphicFilter::GetGraphicFilter();
+
+ if (!rGraphicFilter.ImportGraphic(aGraphic, aURL,
+ GRFILTER_FORMAT_DONTKNOW ))
+ {
+ if ( bLink )
+ {
+ return PasteGraphic( rPos, aGraphic, aStrURL );
+ }
+ else
+ {
+ // #i76709# if bLink isn't set, pass empty URL/filter, so a non-linked image is inserted
+ return PasteGraphic( rPos, aGraphic, OUString() );
+ }
+ }
+
+ if (bLink) // for bLink everything, which is not graphics, as URL
+ {
+ tools::Rectangle aRect( rPos, Size(0,0) );
+ ScRange aRange = GetViewData().GetDocument().
+ GetRange( GetViewData().GetTabNo(), aRect );
+ SCCOL nPosX = aRange.aStart.Col();
+ SCROW nPosY = aRange.aStart.Row();
+
+ InsertBookmark( aStrURL, aStrURL, nPosX, nPosY );
+ return true;
+ }
+ else
+ {
+ // 3. can the file be inserted as OLE?
+ // also non-storages, for instance sounds (#38282#)
+ uno::Reference < embed::XStorage > xStorage = comphelper::OStorageHelper::GetTemporaryStorage();
+
+ //TODO/LATER: what about "bLink"?
+
+ uno::Sequence < beans::PropertyValue > aMedium{ comphelper::makePropertyValue("URL",
+ aStrURL) };
+
+ comphelper::EmbeddedObjectContainer aCnt( xStorage );
+ OUString aName;
+ uno::Reference < embed::XEmbeddedObject > xObj = aCnt.InsertEmbeddedObject( aMedium, aName );
+ if( xObj.is() )
+ return PasteObject( rPos, xObj, nullptr );
+
+ // If an OLE object can't be created, insert a URL button
+
+ GetViewData().GetViewShell()->InsertURLButton( aStrURL, aStrURL, OUString(), &rPos );
+ return true;
+ }
+}
+
+bool ScViewFunc::PasteBookmark( SotClipboardFormatId nFormatId,
+ const css::uno::Reference< css::datatransfer::XTransferable >& rxTransferable,
+ SCCOL nPosX, SCROW nPosY )
+{
+ INetBookmark aBookmark;
+ TransferableDataHelper aDataHelper( rxTransferable );
+ if ( !aDataHelper.GetINetBookmark( nFormatId, aBookmark ) )
+ return false;
+
+ InsertBookmark( aBookmark.GetDescription(), aBookmark.GetURL(), nPosX, nPosY );
+ return true;
+}
+
+void ScViewFunc::InsertBookmark( const OUString& rDescription, const OUString& rURL,
+ SCCOL nPosX, SCROW nPosY, const OUString* pTarget,
+ bool bTryReplace )
+{
+ ScViewData& rViewData = GetViewData();
+ if ( rViewData.HasEditView( rViewData.GetActivePart() ) &&
+ nPosX >= rViewData.GetEditStartCol() && nPosX <= rViewData.GetEditEndCol() &&
+ nPosY >= rViewData.GetEditStartRow() && nPosY <= rViewData.GetEditEndRow() )
+ {
+ // insert into the cell which just got edited
+
+ OUString aTargetFrame;
+ if (pTarget)
+ aTargetFrame = *pTarget;
+ rViewData.GetViewShell()->InsertURLField( rDescription, rURL, aTargetFrame );
+ return;
+ }
+
+ // insert into not edited cell
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScAddress aCellPos( nPosX, nPosY, nTab );
+ EditEngine aEngine( rDoc.GetEnginePool() );
+
+ const EditTextObject* pOld = rDoc.GetEditText(aCellPos);
+ if (pOld)
+ aEngine.SetText(*pOld);
+ else
+ {
+ OUString aOld = rDoc.GetInputString(nPosX, nPosY, nTab);
+ if (!aOld.isEmpty())
+ aEngine.SetText(aOld);
+ }
+
+ sal_Int32 nPara = aEngine.GetParagraphCount();
+ if (nPara)
+ --nPara;
+ sal_Int32 nTxtLen = aEngine.GetTextLen(nPara);
+ ESelection aInsSel( nPara, nTxtLen, nPara, nTxtLen );
+
+ if ( bTryReplace && HasBookmarkAtCursor( nullptr ) )
+ {
+ // if called from hyperlink slot and cell contains only a URL,
+ // replace old URL with new one
+
+ aInsSel = ESelection( 0, 0, 0, 1 ); // replace first character (field)
+ }
+
+ SvxURLField aField( rURL, rDescription, SvxURLFormat::AppDefault );
+ if (pTarget)
+ aField.SetTargetFrame(*pTarget);
+ aEngine.QuickInsertField( SvxFieldItem( aField, EE_FEATURE_FIELD ), aInsSel );
+
+ std::unique_ptr<EditTextObject> pData(aEngine.CreateTextObject());
+ EnterData(nPosX, nPosY, nTab, *pData);
+}
+
+bool ScViewFunc::HasBookmarkAtCursor( SvxHyperlinkItem* pContent )
+{
+ ScAddress aPos( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ ScDocument& rDoc = GetViewData().GetDocShell()->GetDocument();
+
+ const EditTextObject* pData = rDoc.GetEditText(aPos);
+ if (!pData)
+ return false;
+
+ if (!pData->IsFieldObject())
+ // not a field object.
+ return false;
+
+ const SvxFieldItem* pFieldItem = pData->GetField();
+ if (!pFieldItem)
+ // doesn't have a field item.
+ return false;
+
+ const SvxFieldData* pField = pFieldItem->GetField();
+ if (!pField)
+ // doesn't have a field item data.
+ return false;
+
+ if (pField->GetClassId() != css::text::textfield::Type::URL)
+ // not a URL field.
+ return false;
+
+ if (pContent)
+ {
+ const SvxURLField* pURLField = static_cast<const SvxURLField*>(pField);
+ pContent->SetName( pURLField->GetRepresentation() );
+ pContent->SetURL( pURLField->GetURL() );
+ pContent->SetTargetFrame( pURLField->GetTargetFrame() );
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/viewfun5.cxx b/sc/source/ui/view/viewfun5.cxx
new file mode 100644
index 000000000..714a759ed
--- /dev/null
+++ b/sc/source/ui/view/viewfun5.cxx
@@ -0,0 +1,818 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * 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/XEmbedObjectClipboardCreator.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/MSOLEObjectSystemCreator.hpp>
+
+#include <svx/unomodel.hxx>
+#include <unotools/streamwrap.hxx>
+
+#include <svx/fmmodel.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdobj.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdpage.hxx>
+#include <sfx2/dispatch.hxx>
+#include <sfx2/docfile.hxx>
+#include <comphelper/classids.hxx>
+#include <sot/formats.hxx>
+#include <sot/filelist.hxx>
+#include <sot/storage.hxx>
+#include <svl/stritem.hxx>
+#include <vcl/transfer.hxx>
+#include <vcl/graph.hxx>
+#include <vcl/TypeSerializer.hxx>
+#include <osl/thread.h>
+#include <o3tl/unit_conversion.hxx>
+#include <o3tl/string_view.hxx>
+
+#include <comphelper/automationinvokedzone.hxx>
+#include <comphelper/lok.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/string.hxx>
+
+#include <viewfunc.hxx>
+#include <docsh.hxx>
+#include <drawview.hxx>
+#include <impex.hxx>
+#include <dbdata.hxx>
+#include <sc.hrc>
+#include <filter.hxx>
+#include <globstr.hrc>
+#include <global.hxx>
+#include <scextopt.hxx>
+#include <tabvwsh.hxx>
+#include <compiler.hxx>
+#include <scmod.hxx>
+
+#include <asciiopt.hxx>
+#include <scabstdlg.hxx>
+#include <clipparam.hxx>
+#include <markdata.hxx>
+#include <sfx2/frame.hxx>
+#include <svx/dbaexchange.hxx>
+#include <memory>
+
+using namespace com::sun::star;
+
+bool ScViewFunc::PasteDataFormat( SotClipboardFormatId nFormatId,
+ const uno::Reference<datatransfer::XTransferable>& rxTransferable,
+ SCCOL nPosX, SCROW nPosY, const Point* pLogicPos, bool bLink, bool bAllowDialogs )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ rDoc.SetPastingDrawFromOtherDoc( true );
+
+ Point aPos; // inserting position (1/100 mm)
+ if (pLogicPos)
+ aPos = *pLogicPos;
+ else
+ {
+ // inserting position isn't needed for text formats
+ bool bIsTextFormat = ( ScImportExport::IsFormatSupported( nFormatId ) ||
+ nFormatId == SotClipboardFormatId::RTF );
+ if ( !bIsTextFormat )
+ {
+ // Window MapMode isn't drawing MapMode if DrawingLayer hasn't been created yet
+
+ SCTAB nTab = GetViewData().GetTabNo();
+ tools::Long nXT = 0;
+ for (SCCOL i=0; i<nPosX; i++)
+ nXT += rDoc.GetColWidth(i,nTab);
+ if (rDoc.IsNegativePage(nTab))
+ nXT = -nXT;
+ tools::Long nYT = rDoc.GetRowHeight( 0, nPosY-1, nTab);
+ aPos = Point(o3tl::convert(nXT, o3tl::Length::twip, o3tl::Length::mm100),
+ o3tl::convert(nYT, o3tl::Length::twip, o3tl::Length::mm100));
+ }
+ }
+
+ TransferableDataHelper aDataHelper( rxTransferable );
+ bool bRet = false;
+
+ // handle individual formats
+
+ if ( nFormatId == SotClipboardFormatId::EMBED_SOURCE ||
+ nFormatId == SotClipboardFormatId::LINK_SOURCE ||
+ nFormatId == SotClipboardFormatId::EMBED_SOURCE_OLE ||
+ nFormatId == SotClipboardFormatId::LINK_SOURCE_OLE ||
+ nFormatId == SotClipboardFormatId::EMBEDDED_OBJ_OLE )
+ {
+ uno::Reference < io::XInputStream > xStm;
+ TransferableObjectDescriptor aObjDesc;
+
+ if (aDataHelper.GetTransferableObjectDescriptor(SotClipboardFormatId::OBJECTDESCRIPTOR, aObjDesc))
+ xStm = aDataHelper.GetInputStream(nFormatId, OUString());
+
+ if (xStm.is())
+ {
+ if ( aObjDesc.maClassName == SvGlobalName( SO3_SC_CLASSID_60 ) )
+ {
+ uno::Reference < embed::XStorage > xStore = ::comphelper::OStorageHelper::GetStorageFromInputStream( xStm );
+
+ // mba: BaseURL doesn't make sense for clipboard
+ // #i43716# Medium must be allocated with "new".
+ // DoLoad stores the pointer and deletes it with the SfxObjectShell.
+ SfxMedium* pMedium = new SfxMedium( xStore, OUString() );
+
+ // TODO/LATER: is it a problem that we don't support binary formats here?
+ ScDocShellRef xDocShRef = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT);
+ if (xDocShRef->DoLoad(pMedium))
+ {
+ ScDocument& rSrcDoc = xDocShRef->GetDocument();
+ SCTAB nSrcTab = rSrcDoc.GetVisibleTab();
+ if (!rSrcDoc.HasTable(nSrcTab))
+ nSrcTab = 0;
+
+ ScMarkData aSrcMark(rSrcDoc.GetSheetLimits());
+ aSrcMark.SelectOneTable( nSrcTab ); // for CopyToClip
+ ScDocumentUniquePtr pClipDoc(new ScDocument( SCDOCMODE_CLIP ));
+
+ SCCOL nFirstCol, nLastCol;
+ SCROW nFirstRow, nLastRow;
+ if ( rSrcDoc.GetDataStart( nSrcTab, nFirstCol, nFirstRow ) )
+ {
+ rSrcDoc.GetCellArea( nSrcTab, nLastCol, nLastRow );
+ if (nLastCol < nFirstCol)
+ nLastCol = nFirstCol;
+ if (nLastRow < nFirstRow)
+ nLastRow = nFirstRow;
+ }
+ else
+ {
+ nFirstCol = nLastCol = 0;
+ nFirstRow = nLastRow = 0;
+ }
+
+ bool bIncludeObjects = false; // include drawing layer objects in CopyToClip ?
+
+ if (nFormatId == SotClipboardFormatId::EMBED_SOURCE)
+ {
+ const ScDrawLayer* pDraw = rSrcDoc.GetDrawLayer();
+ SCCOL nPrintEndCol = nFirstCol;
+ SCROW nPrintEndRow = nFirstRow;
+ bool bHasObjects = pDraw && pDraw->HasObjects();
+ // Extend the range to include the drawing layer objects.
+ if (bHasObjects && rSrcDoc.GetPrintArea(nSrcTab, nPrintEndCol, nPrintEndRow, true))
+ {
+ nLastCol = std::max<SCCOL>(nLastCol, nPrintEndCol);
+ nLastRow = std::max<SCROW>(nLastRow, nPrintEndRow);
+ }
+
+ bIncludeObjects = bHasObjects;
+ }
+
+ ScClipParam aClipParam(ScRange(nFirstCol, nFirstRow, nSrcTab, nLastCol, nLastRow, nSrcTab), false);
+ rSrcDoc.CopyToClip(aClipParam, pClipDoc.get(), &aSrcMark, false, bIncludeObjects);
+ ScGlobal::SetClipDocName( xDocShRef->GetTitle( SFX_TITLE_FULLNAME ) );
+
+ SetCursor( nPosX, nPosY );
+ Unmark();
+ PasteFromClip( InsertDeleteFlags::ALL, pClipDoc.get(),
+ ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
+ bAllowDialogs );
+ bRet = true;
+ }
+
+ xDocShRef->DoClose();
+ xDocShRef.clear();
+ }
+ else
+ {
+ OUString aName;
+ uno::Reference < embed::XEmbeddedObject > xObj = GetViewData().GetViewShell()->GetObjectShell()->
+ GetEmbeddedObjectContainer().InsertEmbeddedObject( xStm, aName );
+ if ( xObj.is() )
+ {
+ // try to get the replacement image from the clipboard
+ Graphic aGraphic;
+ SotClipboardFormatId nGrFormat = SotClipboardFormatId::NONE;
+
+ // limit the size of the preview metafile to 100000 actions
+ GDIMetaFile aMetafile;
+ if (aDataHelper.GetGDIMetaFile(SotClipboardFormatId::GDIMETAFILE, aMetafile, 100000))
+ {
+ nGrFormat = SotClipboardFormatId::GDIMETAFILE;
+ aGraphic = aMetafile;
+ }
+
+ // insert replacement image ( if there is one ) into the object helper
+ if ( nGrFormat != SotClipboardFormatId::NONE )
+ {
+ datatransfer::DataFlavor aDataFlavor;
+ SotExchange::GetFormatDataFlavor( nGrFormat, aDataFlavor );
+ PasteObject( aPos, xObj, &aObjDesc.maSize, &aGraphic, aDataFlavor.MimeType, aObjDesc.mnViewAspect );
+ }
+ else
+ PasteObject( aPos, xObj, &aObjDesc.maSize );
+
+ bRet = true;
+ }
+ else
+ {
+ OSL_FAIL("Error in CreateAndLoad");
+ }
+ }
+ }
+ else
+ {
+ if ( aDataHelper.GetTransferableObjectDescriptor( SotClipboardFormatId::OBJECTDESCRIPTOR_OLE, aObjDesc ) )
+ {
+ OUString aName;
+ uno::Reference < embed::XEmbeddedObject > xObj;
+ xStm = aDataHelper.GetInputStream(SotClipboardFormatId::EMBED_SOURCE_OLE, OUString());
+ if (!xStm.is())
+ aDataHelper.GetInputStream(SotClipboardFormatId::EMBEDDED_OBJ_OLE, OUString());
+
+ if (xStm.is())
+ {
+ xObj = GetViewData().GetDocShell()->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() )
+ GetViewData().GetDocShell()->GetEmbeddedObjectContainer().InsertEmbeddedObject( xObj, aName );
+ }
+ catch( uno::Exception& )
+ {}
+ }
+
+ if ( xObj.is() )
+ {
+ // 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 );
+ PasteObject( aPos, xObj, &aObjDesc.maSize, &aGraphic, aDataFlavor.MimeType, aObjDesc.mnViewAspect );
+ }
+ else
+ PasteObject( aPos, xObj, &aObjDesc.maSize );
+
+ // let object stay in loaded state after insertion
+ SdrOle2Obj::Unload( xObj, embed::Aspects::MSOLE_CONTENT );
+ bRet = true;
+ }
+ else
+ {
+ OSL_FAIL("Error creating external OLE object");
+ }
+ }
+ //TODO/LATER: if format is not available, create picture
+ }
+ }
+ else if ( nFormatId == SotClipboardFormatId::LINK ) // LINK is also in ScImportExport
+ {
+ bRet = PasteLink( rxTransferable );
+ }
+ else if ( ScImportExport::IsFormatSupported( nFormatId ) || nFormatId == SotClipboardFormatId::RTF ||
+ nFormatId == SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT )
+ {
+ if ( nFormatId == SotClipboardFormatId::RTF && ( aDataHelper.HasFormat( SotClipboardFormatId::EDITENGINE_ODF_TEXT_FLAT ) ) )
+ {
+ // use EditView's PasteSpecial / Drop
+ PasteRTF( nPosX, nPosY, rxTransferable );
+ bRet = true;
+ }
+ else
+ {
+ ScAddress aCellPos( nPosX, nPosY, GetViewData().GetTabNo() );
+ auto pObj = std::make_shared<ScImportExport>(GetViewData().GetDocument(), aCellPos);
+ pObj->SetOverwriting( true );
+
+
+ auto pStrBuffer = std::make_shared<OUString>();
+ tools::SvRef<SotTempStream> xStream;
+ if ( aDataHelper.GetSotStorageStream( nFormatId, xStream ) && xStream.is() )
+ {
+ // Static variables for per-session storage. This could be
+ // changed to longer-term storage in future.
+ static bool bHaveSavedPreferences = false;
+ static LanguageType eSavedLanguage;
+ static bool bSavedDateConversion;
+
+ if (nFormatId == SotClipboardFormatId::HTML &&
+ !comphelper::LibreOfficeKit::isActive())
+ {
+ if (bHaveSavedPreferences)
+ {
+ ScAsciiOptions aOptions;
+ aOptions.SetLanguage(eSavedLanguage);
+ aOptions.SetDetectSpecialNumber(bSavedDateConversion);
+ pObj->SetExtOptions(aOptions);
+ }
+ else
+ {
+ // Launch the text import options dialog. For now, we do
+ // this for html pasting only, but in the future it may
+ // make sense to do it for other data types too.
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ vcl::Window* pParent = GetActiveWin();
+ ScopedVclPtr<AbstractScTextImportOptionsDlg> pDlg(
+ pFact->CreateScTextImportOptionsDlg(pParent ? pParent->GetFrameWeld() : nullptr));
+
+ if (pDlg->Execute() == RET_OK)
+ {
+ ScAsciiOptions aOptions;
+ aOptions.SetLanguage(pDlg->GetLanguageType());
+ aOptions.SetDetectSpecialNumber(pDlg->IsDateConversionSet());
+ if (!pDlg->IsKeepAskingSet())
+ {
+ bHaveSavedPreferences = true;
+ eSavedLanguage = pDlg->GetLanguageType();
+ bSavedDateConversion = pDlg->IsDateConversionSet();
+ }
+ pObj->SetExtOptions(aOptions);
+ }
+ else
+ {
+ // prevent error dialog for user cancel action
+ bRet = true;
+ }
+ }
+ }
+ if(!bRet)
+ bRet = pObj->ImportStream( *xStream, OUString(), nFormatId );
+ // mba: clipboard always must contain absolute URLs (could be from alien source)
+ }
+ else if ((nFormatId == SotClipboardFormatId::STRING || nFormatId == SotClipboardFormatId::STRING_TSVC)
+ && aDataHelper.GetString( nFormatId, *pStrBuffer ))
+ {
+ // Do CSV dialog if more than one line. But not if invoked from Automation.
+ const SfxViewShell* pViewShell = SfxViewShell::Current();
+ sal_Int32 nDelim = pStrBuffer->indexOf('\n');
+ if (!(pViewShell && pViewShell->isLOKMobilePhone()) && !comphelper::Automation::AutomationInvokedZone::isActive()
+ && nDelim >= 0 && nDelim != pStrBuffer->getLength () - 1)
+ {
+ vcl::Window* pParent = GetActiveWin();
+
+ auto pStrm = std::make_shared<ScImportStringStream>(*pStrBuffer);
+
+ ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
+ VclPtr<AbstractScImportAsciiDlg> pDlg(
+ pFact->CreateScImportAsciiDlg(pParent ? pParent->GetFrameWeld() : nullptr, OUString(), pStrm.get(), SC_PASTETEXT));
+
+ bAllowDialogs = bAllowDialogs && !SC_MOD()->IsInExecuteDrop();
+
+ pDlg->StartExecuteAsync([this, pDlg, &rDoc, pStrm, nFormatId, pStrBuffer, pObj, bAllowDialogs](sal_Int32 nResult){
+ bool bShowErrorDialog = bAllowDialogs;
+ if (RET_OK == nResult)
+ {
+ ScAsciiOptions aOptions;
+ pDlg->GetOptions( aOptions );
+ pDlg->SaveParameters();
+ pObj->SetExtOptions( aOptions );
+ pObj->ImportString( *pStrBuffer, nFormatId );
+
+ // TODO: what if (aObj.IsOverflow())
+ // Content was partially pasted, which can be undone by
+ // the user though.
+ bShowErrorDialog = bShowErrorDialog && pObj->IsOverflow();
+ }
+ else
+ {
+ bShowErrorDialog = false;
+ // Yes, no failure, don't raise a "couldn't paste"
+ // dialog if user cancelled.
+ }
+
+ InvalidateAttribs();
+ GetViewData().UpdateInputHandler();
+
+ rDoc.SetPastingDrawFromOtherDoc( false );
+
+ if (bShowErrorDialog)
+ ErrorMessage(STR_PASTE_ERROR);
+ pDlg->disposeOnce();
+ });
+ return true;
+ }
+ else
+ bRet = pObj->ImportString( *pStrBuffer, nFormatId );
+ }
+ else if ((nFormatId != SotClipboardFormatId::STRING && nFormatId != SotClipboardFormatId::STRING_TSVC)
+ && aDataHelper.GetString( nFormatId, *pStrBuffer ))
+ bRet = pObj->ImportString( *pStrBuffer, nFormatId );
+
+ InvalidateAttribs();
+ GetViewData().UpdateInputHandler();
+ }
+ }
+ else if (nFormatId == SotClipboardFormatId::SBA_DATAEXCHANGE)
+ {
+ // import of database data into table
+
+ const DataFlavorExVector& rVector = aDataHelper.GetDataFlavorExVector();
+ if ( svx::ODataAccessObjectTransferable::canExtractObjectDescriptor(rVector) )
+ {
+ // transport the whole ODataAccessDescriptor as slot parameter
+ svx::ODataAccessDescriptor aDesc = svx::ODataAccessObjectTransferable::extractObjectDescriptor(aDataHelper);
+ uno::Any aDescAny;
+ uno::Sequence<beans::PropertyValue> aProperties = aDesc.createPropertyValueSequence();
+ aDescAny <<= aProperties;
+ SfxUnoAnyItem aDataDesc(SID_SBA_IMPORT, aDescAny);
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ SCTAB nTab = GetViewData().GetTabNo();
+
+ ClickCursor(nPosX, nPosY, false); // set cursor position
+
+ // Creation of database area "Import1" isn't here, but in the DocShell
+ // slot execute, so it can be added to the undo action
+
+ ScDBData* pDBData = pDocSh->GetDBData( ScRange(nPosX,nPosY,nTab), SC_DB_OLD, ScGetDBSelection::Keep );
+ OUString sTarget;
+ if (pDBData)
+ sTarget = pDBData->GetName();
+ else
+ {
+ ScAddress aCellPos( nPosX,nPosY,nTab );
+ sTarget = aCellPos.Format(ScRefFlags::ADDR_ABS_3D, &rDoc, rDoc.GetAddressConvention());
+ }
+ SfxStringItem aTarget(FN_PARAM_1, sTarget);
+
+ bool bAreaIsNew = !pDBData;
+ SfxBoolItem aAreaNew(FN_PARAM_2, bAreaIsNew);
+
+ // asynchronous, to avoid doing the whole import in drop handler
+ SfxDispatcher& rDisp = GetViewData().GetDispatcher();
+ rDisp.ExecuteList(SID_SBA_IMPORT, SfxCallMode::ASYNCHRON,
+ { &aDataDesc, &aTarget, &aAreaNew });
+
+ bRet = true;
+ }
+ }
+ else if (nFormatId == SotClipboardFormatId::SBA_FIELDDATAEXCHANGE)
+ {
+ // insert database field control
+
+ if ( svx::OColumnTransferable::canExtractColumnDescriptor( aDataHelper.GetDataFlavorExVector(), ColumnTransferFormatFlags::COLUMN_DESCRIPTOR | ColumnTransferFormatFlags::CONTROL_EXCHANGE ) )
+ {
+ MakeDrawLayer();
+ ScDrawView* pScDrawView = GetScDrawView();
+ SdrObjectUniquePtr pObj = pScDrawView->CreateFieldControl( svx::OColumnTransferable::extractColumnDescriptor( aDataHelper ) );
+ if (pObj)
+ {
+ Point aInsPos = aPos;
+ tools::Rectangle aRect(pObj->GetLogicRect());
+ aInsPos.AdjustX( -(aRect.GetSize().Width() / 2) );
+ aInsPos.AdjustY( -(aRect.GetSize().Height() / 2) );
+ if ( aInsPos.X() < 0 ) aInsPos.setX( 0 );
+ if ( aInsPos.Y() < 0 ) aInsPos.setY( 0 );
+ aRect.SetPos(aInsPos);
+ pObj->SetLogicRect(aRect);
+
+ if ( dynamic_cast<const SdrUnoObj*>( pObj.get() ) != nullptr )
+ pObj->NbcSetLayer(SC_LAYER_CONTROLS);
+ else
+ pObj->NbcSetLayer(SC_LAYER_FRONT);
+ if (dynamic_cast<const SdrObjGroup*>( pObj.get() ) != nullptr)
+ {
+ SdrObjListIter aIter( *pObj, SdrIterMode::DeepWithGroups );
+ SdrObject* pSubObj = aIter.Next();
+ while (pSubObj)
+ {
+ if ( dynamic_cast<const SdrUnoObj*>( pSubObj) != nullptr )
+ pSubObj->NbcSetLayer(SC_LAYER_CONTROLS);
+ else
+ pSubObj->NbcSetLayer(SC_LAYER_FRONT);
+ pSubObj = aIter.Next();
+ }
+ }
+
+ pScDrawView->InsertObjectSafe(pObj.release(), *pScDrawView->GetSdrPageView());
+
+ GetViewData().GetViewShell()->SetDrawShell( true );
+ bRet = true;
+ }
+ }
+ }
+ else if (nFormatId == SotClipboardFormatId::BITMAP || nFormatId == SotClipboardFormatId::PNG || nFormatId == SotClipboardFormatId::JPEG)
+ {
+ BitmapEx aBmpEx;
+ if( aDataHelper.GetBitmapEx( SotClipboardFormatId::BITMAP, aBmpEx ) )
+ bRet = PasteBitmapEx( aPos, aBmpEx );
+ }
+ else if (nFormatId == SotClipboardFormatId::GDIMETAFILE)
+ {
+ GDIMetaFile aMtf;
+ if( aDataHelper.GetGDIMetaFile( SotClipboardFormatId::GDIMETAFILE, aMtf ) )
+ bRet = PasteMetaFile( aPos, aMtf );
+ }
+ else if (nFormatId == SotClipboardFormatId::SVXB)
+ {
+ tools::SvRef<SotTempStream> xStm;
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::SVXB, xStm ) )
+ {
+ Graphic aGraphic;
+ TypeSerializer aSerializer(*xStm);
+ aSerializer.readGraphic(aGraphic);
+ bRet = PasteGraphic( aPos, aGraphic, OUString() );
+ }
+ }
+ else if ( nFormatId == SotClipboardFormatId::DRAWING )
+ {
+ tools::SvRef<SotTempStream> xStm;
+ if( aDataHelper.GetSotStorageStream( SotClipboardFormatId::DRAWING, xStm ) )
+ {
+ MakeDrawLayer(); // before loading model, so 3D factory has been created
+
+ ScDocShellRef aDragShellRef( new ScDocShell );
+ aDragShellRef->DoInitNew();
+
+ std::unique_ptr<FmFormModel> pModel(
+ new FmFormModel(
+ nullptr,
+ aDragShellRef.get()));
+
+ pModel->GetItemPool().FreezeIdRanges();
+ xStm->Seek(0);
+
+ css::uno::Reference< css::io::XInputStream > xInputStream( new utl::OInputStreamWrapper( *xStm ) );
+ SvxDrawingLayerImport( pModel.get(), xInputStream );
+
+ // set everything to right layer:
+ size_t nObjCount = 0;
+ sal_uInt16 nPages = pModel->GetPageCount();
+ for (sal_uInt16 i=0; i<nPages; i++)
+ {
+ SdrPage* pPage = pModel->GetPage(i);
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( dynamic_cast<const SdrUnoObj*>( pObject) != nullptr )
+ pObject->NbcSetLayer(SC_LAYER_CONTROLS);
+ else
+ pObject->NbcSetLayer(SC_LAYER_FRONT);
+ pObject = aIter.Next();
+ }
+
+ nObjCount += pPage->GetObjCount(); // count group object only once
+ }
+
+ PasteDraw(aPos, pModel.get(), (nObjCount > 1), u"A", u"B"); // grouped if more than 1 object
+ pModel.reset();
+ aDragShellRef->DoClose();
+ bRet = true;
+ }
+ }
+ else if ( (nFormatId == SotClipboardFormatId::BIFF_5) || (nFormatId == SotClipboardFormatId::BIFF_8) )
+ {
+ // do excel import into a clipboard document
+ //TODO/MBA: testing
+ uno::Reference <io::XInputStream> xStm = aDataHelper.GetInputStream(nFormatId, OUString());
+ if (xStm.is())
+ {
+ ScDocument aInsDoc( SCDOCMODE_CLIP );
+ SCTAB nSrcTab = 0; // Biff5 in clipboard: always sheet 0
+ aInsDoc.ResetClip( &rDoc, nSrcTab );
+
+ SfxMedium aMed;
+ aMed.GetItemSet()->Put( SfxUnoAnyItem( SID_INPUTSTREAM, uno::Any( xStm ) ) );
+ ErrCode eErr = ScFormatFilter::Get().ScImportExcel( aMed, &aInsDoc, EIF_AUTO );
+ if ( eErr == ERRCODE_NONE )
+ {
+ ScRange aSource;
+ const ScExtDocOptions* pExtOpt = aInsDoc.GetExtDocOptions();
+ const ScExtTabSettings* pTabSett = pExtOpt ? pExtOpt->GetTabSettings( nSrcTab ) : nullptr;
+ if( pTabSett && pTabSett->maUsedArea.IsValid() )
+ {
+ aSource = pTabSett->maUsedArea;
+ // ensure correct sheet indexes
+ aSource.aStart.SetTab( nSrcTab );
+ aSource.aEnd.SetTab( nSrcTab );
+// don't use selection area: if cursor is moved in Excel after Copy, selection
+// represents the new cursor position and not the copied area
+ }
+ else
+ {
+ OSL_FAIL("no dimension"); //! possible?
+ SCCOL nFirstCol, nLastCol;
+ SCROW nFirstRow, nLastRow;
+ if ( aInsDoc.GetDataStart( nSrcTab, nFirstCol, nFirstRow ) )
+ aInsDoc.GetCellArea( nSrcTab, nLastCol, nLastRow );
+ else
+ {
+ nFirstCol = nLastCol = 0;
+ nFirstRow = nLastRow = 0;
+ }
+ aSource = ScRange( nFirstCol, nFirstRow, nSrcTab,
+ nLastCol, nLastRow, nSrcTab );
+ }
+
+ if ( pLogicPos )
+ {
+ // position specified (Drag&Drop) - change selection
+ MoveCursorAbs( nPosX, nPosY, SC_FOLLOW_NONE, false, false );
+ Unmark();
+ }
+
+ aInsDoc.SetClipArea( aSource );
+ PasteFromClip( InsertDeleteFlags::ALL, &aInsDoc,
+ ScPasteFunc::NONE, false, false, false, INS_NONE, InsertDeleteFlags::NONE,
+ bAllowDialogs );
+ bRet = true;
+ }
+ }
+ }
+ else if ( nFormatId == SotClipboardFormatId::SIMPLE_FILE )
+ {
+ OUString aFile;
+ if ( aDataHelper.GetString( nFormatId, aFile ) )
+ bRet = PasteFile( aPos, aFile, bLink );
+ }
+ else if ( nFormatId == SotClipboardFormatId::FILE_LIST )
+ {
+ FileList aFileList;
+ if ( aDataHelper.GetFileList( nFormatId, aFileList ) )
+ {
+ sal_uLong nCount = aFileList.Count();
+ for( sal_uLong i = 0; i < nCount ; i++ )
+ {
+ OUString aFile = aFileList.GetFile( i );
+
+ PasteFile( aPos, aFile, bLink );
+
+ aPos.AdjustX(400 );
+ aPos.AdjustY(400 );
+ }
+ bRet = true;
+ }
+ }
+ else if ( nFormatId == SotClipboardFormatId::SOLK ||
+ nFormatId == SotClipboardFormatId::UNIFORMRESOURCELOCATOR ||
+ nFormatId == SotClipboardFormatId::NETSCAPE_BOOKMARK ||
+ nFormatId == SotClipboardFormatId::FILEGRPDESCRIPTOR )
+ {
+ bRet = PasteBookmark( nFormatId, rxTransferable, nPosX, nPosY );
+ }
+
+ rDoc.SetPastingDrawFromOtherDoc( false );
+
+ return bRet;
+}
+
+bool ScViewFunc::PasteLink( const uno::Reference<datatransfer::XTransferable>& rxTransferable )
+{
+ TransferableDataHelper aDataHelper( rxTransferable );
+
+ // get link data from transferable before string data,
+ // so the source knows it will be used for a link
+
+ uno::Sequence<sal_Int8> aSequence = aDataHelper.GetSequence(SotClipboardFormatId::LINK, OUString());
+ if (!aSequence.hasElements())
+ {
+ OSL_FAIL("DDE Data not found.");
+ return false;
+ }
+
+ // check size (only if string is available in transferable)
+
+ sal_uInt16 nCols = 1;
+ sal_uInt16 nRows = 1;
+ if ( aDataHelper.HasFormat( SotClipboardFormatId::STRING ) )
+ {
+ OUString aDataStr;
+ if ( aDataHelper.GetString( SotClipboardFormatId::STRING, aDataStr ) )
+ {
+ // get size from string the same way as in ScDdeLink::DataChanged
+
+ aDataStr = convertLineEnd(aDataStr, LINEEND_LF);
+ sal_Int32 nLen = aDataStr.getLength();
+ if (nLen && aDataStr[nLen-1] == '\n')
+ aDataStr = aDataStr.copy(0, nLen-1);
+
+ if (!aDataStr.isEmpty())
+ {
+ nRows = comphelper::string::getTokenCount(aDataStr, '\n');
+ std::u16string_view aLine = o3tl::getToken(aDataStr, 0, '\n' );
+ if (!aLine.empty())
+ nCols = comphelper::string::getTokenCount(aLine, '\t');
+ }
+ }
+ }
+
+ // create formula
+
+ sal_Int32 nSeqLen = aSequence.getLength();
+ const char* p = reinterpret_cast<const char*>(aSequence.getConstArray());
+
+ rtl_TextEncoding eSysEnc = osl_getThreadTextEncoding();
+
+ // char array delimited by \0.
+ // app \0 topic \0 item \0 (extra \0) where the extra is optional.
+ ::std::vector<OUString> aStrs;
+ const char* pStart = p;
+ sal_Int32 nStart = 0;
+ for (sal_Int32 i = 0; i < nSeqLen; ++i, ++p)
+ {
+ if (*p == '\0')
+ {
+ sal_Int32 nLen = i - nStart;
+ aStrs.emplace_back(pStart, nLen, eSysEnc);
+ nStart = ++i;
+ pStart = ++p;
+ }
+ }
+
+ if (aStrs.size() < 3)
+ return false;
+
+ const OUString& pApp = aStrs[0];
+ const OUString& pTopic = aStrs[1];
+ const OUString& pItem = aStrs[2];
+ const OUString* pExtra = nullptr;
+ if (aStrs.size() > 3)
+ pExtra = &aStrs[3];
+
+ if ( pExtra && *pExtra == "calc:extref" )
+ {
+ // Paste this as an external reference. Note that paste link always
+ // uses Calc A1 syntax even when another formula syntax is specified
+ // in the UI.
+ EnterMatrix("='"
+ + ScGlobal::GetAbsDocName(pTopic, GetViewData().GetDocument().GetDocumentShell())
+ + "'#" + pItem
+ , ::formula::FormulaGrammar::GRAM_NATIVE);
+ return true;
+ }
+ else
+ {
+ // DDE in all other cases.
+
+ // TODO: we could define ocQuote for "
+ EnterMatrix("=" + ScCompiler::GetNativeSymbol(ocDde)
+ + ScCompiler::GetNativeSymbol(ocOpen)
+ + "\"" + pApp + "\""
+ + ScCompiler::GetNativeSymbol(ocSep)
+ + "\"" + pTopic + "\""
+ + ScCompiler::GetNativeSymbol(ocSep)
+ + "\"" + pItem + "\""
+ + ScCompiler::GetNativeSymbol(ocClose)
+ , ::formula::FormulaGrammar::GRAM_NATIVE);
+ }
+
+ // mark range
+
+ SCTAB nTab = GetViewData().GetTabNo();
+ SCCOL nCurX = GetViewData().GetCurX();
+ SCROW nCurY = GetViewData().GetCurY();
+ HideAllCursors();
+ DoneBlockMode();
+ InitBlockMode( nCurX, nCurY, nTab );
+ MarkCursor( nCurX+static_cast<SCCOL>(nCols)-1, nCurY+static_cast<SCROW>(nRows)-1, nTab );
+ ShowAllCursors();
+ CursorPosChanged();
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/viewfun6.cxx b/sc/source/ui/view/viewfun6.cxx
new file mode 100644
index 000000000..160ee6ce5
--- /dev/null
+++ b/sc/source/ui/view/viewfun6.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 <formula/token.hxx>
+#include <svx/svdocapt.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/dispatch.hxx>
+#include <svl/stritem.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+#include <editeng/editview.hxx>
+#include <rtl/math.hxx>
+#include <sal/log.hxx>
+
+#include <viewfunc.hxx>
+#include <viewdata.hxx>
+#include <drwlayer.hxx>
+#include <docsh.hxx>
+#include <futext.hxx>
+#include <docfunc.hxx>
+#include <sc.hrc>
+#include <fusel.hxx>
+#include <reftokenhelper.hxx>
+#include <externalrefmgr.hxx>
+#include <markdata.hxx>
+#include <drawview.hxx>
+#include <inputhdl.hxx>
+#include <tabvwsh.hxx>
+#include <scmod.hxx>
+#include <postit.hxx>
+
+#include <vector>
+
+namespace
+{
+
+void collectUIInformation( const OUString& aevent )
+{
+ EventDescription aDescription;
+ aDescription.aID = "grid_window";
+ aDescription.aParameters = {{ aevent , ""}};
+ aDescription.aAction = "COMMENT";
+ aDescription.aParent = "MainWindow";
+ aDescription.aKeyWord = "ScGridWinUIObject";
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+using ::std::vector;
+
+void ScViewFunc::DetectiveAddPred()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ pDocSh->GetDocFunc().DetectiveAddPred( GetViewData().GetCurPos() );
+ RecalcPPT(); //! use broadcast in DocFunc instead?
+}
+
+void ScViewFunc::DetectiveDelPred()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ pDocSh->GetDocFunc().DetectiveDelPred( GetViewData().GetCurPos() );
+ RecalcPPT();
+}
+
+void ScViewFunc::DetectiveAddSucc()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ pDocSh->GetDocFunc().DetectiveAddSucc( GetViewData().GetCurPos() );
+ RecalcPPT();
+}
+
+void ScViewFunc::DetectiveDelSucc()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ pDocSh->GetDocFunc().DetectiveDelSucc( GetViewData().GetCurPos() );
+ RecalcPPT();
+}
+
+void ScViewFunc::DetectiveAddError()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ pDocSh->GetDocFunc().DetectiveAddError( GetViewData().GetCurPos() );
+ RecalcPPT();
+}
+
+void ScViewFunc::DetectiveDelAll()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ pDocSh->GetDocFunc().DetectiveDelAll( GetViewData().GetTabNo() );
+ RecalcPPT();
+}
+
+void ScViewFunc::DetectiveMarkInvalid()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ pDocSh->GetDocFunc().DetectiveMarkInvalid( GetViewData().GetTabNo() );
+ RecalcPPT();
+}
+
+void ScViewFunc::DetectiveRefresh()
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ pDocSh->GetDocFunc().DetectiveRefresh();
+ RecalcPPT();
+}
+
+static void lcl_jumpToRange(const ScRange& rRange, ScViewData* pView, const ScDocument& rDoc)
+{
+ OUString aAddrText(rRange.Format(rDoc, ScRefFlags::RANGE_ABS_3D));
+ SfxStringItem aPosItem(SID_CURRENTCELL, aAddrText);
+ SfxBoolItem aUnmarkItem(FN_PARAM_1, true); // remove existing selection
+ pView->GetDispatcher().ExecuteList(
+ SID_CURRENTCELL, SfxCallMode::SYNCHRON | SfxCallMode::RECORD,
+ { &aPosItem, &aUnmarkItem });
+}
+
+void ScViewFunc::MarkAndJumpToRanges(const ScRangeList& rRanges)
+{
+ ScViewData& rView = GetViewData();
+ ScDocShell* pDocSh = rView.GetDocShell();
+
+ ScRangeList aRanges(rRanges);
+ ScRangeList aRangesToMark;
+ ScAddress aCurPos = rView.GetCurPos();
+ size_t ListSize = aRanges.size();
+ for ( size_t i = 0; i < ListSize; ++i )
+ {
+ const ScRange & r = aRanges[i];
+ // Collect only those ranges that are on the same sheet as the current
+ // cursor.
+ if (r.aStart.Tab() == aCurPos.Tab())
+ aRangesToMark.push_back(r);
+ }
+
+ if (aRangesToMark.empty())
+ return;
+
+ // Jump to the first range of all precedent ranges.
+ const ScRange & r = aRangesToMark.front();
+ lcl_jumpToRange(r, &rView, pDocSh->GetDocument());
+
+ ListSize = aRangesToMark.size();
+ for ( size_t i = 0; i < ListSize; ++i )
+ {
+ MarkRange(aRangesToMark[i], false, true);
+ }
+}
+
+void ScViewFunc::DetectiveMarkPred()
+{
+ ScViewData& rView = GetViewData();
+ ScDocShell* pDocSh = rView.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData& rMarkData = rView.GetMarkData();
+ ScAddress aCurPos = rView.GetCurPos();
+ ScRangeList aRanges;
+ if (rMarkData.IsMarked() || rMarkData.IsMultiMarked())
+ rMarkData.FillRangeListWithMarks(&aRanges, false);
+ else
+ aRanges.push_back(aCurPos);
+
+ vector<ScTokenRef> aRefTokens;
+ pDocSh->GetDocFunc().DetectiveCollectAllPreds(aRanges, aRefTokens);
+
+ if (aRefTokens.empty())
+ // No precedents found. Nothing to do.
+ return;
+
+ ScTokenRef p = aRefTokens.front();
+ if (ScRefTokenHelper::isExternalRef(p))
+ {
+ // This is external. Open the external document if available, and
+ // jump to the destination.
+
+ sal_uInt16 nFileId = p->GetIndex();
+ ScExternalRefManager* pRefMgr = rDoc.GetExternalRefManager();
+ const OUString* pPath = pRefMgr->getExternalFileName(nFileId);
+
+ ScRange aRange;
+ if (pPath && ScRefTokenHelper::getRangeFromToken(&rDoc, aRange, p, aCurPos, true))
+ {
+ OUString aTabName = p->GetString().getString();
+ OUString aRangeStr(aRange.Format(rDoc, ScRefFlags::VALID));
+ OUString sUrl =
+ *pPath +
+ "#" +
+ aTabName +
+ "." +
+ aRangeStr;
+
+ ScGlobal::OpenURL(sUrl, OUString());
+ }
+ return;
+ }
+ else
+ {
+ ScRange aRange;
+ ScRefTokenHelper::getRangeFromToken(&rDoc, aRange, p, aCurPos);
+ if (aRange.aStart.Tab() != aCurPos.Tab())
+ {
+ // The first precedent range is on a different sheet. Jump to it
+ // immediately and forget the rest.
+ lcl_jumpToRange(aRange, &rView, rDoc);
+ return;
+ }
+ }
+
+ ScRangeList aDestRanges;
+ ScRefTokenHelper::getRangeListFromTokens(&rDoc, aDestRanges, aRefTokens, aCurPos);
+ MarkAndJumpToRanges(aDestRanges);
+}
+
+void ScViewFunc::DetectiveMarkSucc()
+{
+ ScViewData& rView = GetViewData();
+ ScDocShell* pDocSh = rView.GetDocShell();
+ ScMarkData& rMarkData = rView.GetMarkData();
+ ScAddress aCurPos = rView.GetCurPos();
+ ScRangeList aRanges;
+ if (rMarkData.IsMarked() || rMarkData.IsMultiMarked())
+ rMarkData.FillRangeListWithMarks(&aRanges, false);
+ else
+ aRanges.push_back(aCurPos);
+
+ vector<ScTokenRef> aRefTokens;
+ pDocSh->GetDocFunc().DetectiveCollectAllSuccs(aRanges, aRefTokens);
+
+ if (aRefTokens.empty())
+ // No dependents found. Nothing to do.
+ return;
+
+ ScRangeList aDestRanges;
+ ScRefTokenHelper::getRangeListFromTokens(&rView.GetDocument(), aDestRanges, aRefTokens, aCurPos);
+ MarkAndJumpToRanges(aDestRanges);
+}
+
+/** Insert date or time into current cell.
+
+ If cell is in input or edit mode, insert date/time at cursor position, else
+ create a date or time or date+time cell as follows:
+
+ - key date on time cell => current date + time of cell => date+time formatted cell
+ - unless time cell was empty or 00:00 time => current date => date formatted cell
+ - key date on date+time cell => current date + 00:00 time => date+time formatted cell
+ - unless date was current date => current date => date formatted cell
+ - key date on other cell => current date => date formatted cell
+ - key time on date cell => date of cell + current time => date+time formatted cell
+ - unless date cell was empty => current time => time formatted cell
+ - key time on date+time cell => current time => time formatted cell
+ - unless cell was empty => current date+time => date+time formatted cell
+ - key time on other cell => current time => time formatted cell
+ */
+void ScViewFunc::InsertCurrentTime(SvNumFormatType nReqFmt, const OUString& rUndoStr)
+{
+ ScViewData& rViewData = GetViewData();
+
+ ScInputHandler* pInputHdl = SC_MOD()->GetInputHdl( rViewData.GetViewShell());
+ bool bInputMode = (pInputHdl && pInputHdl->IsInputMode());
+
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScAddress aCurPos = rViewData.GetCurPos();
+ const sal_uInt32 nCurNumFormat = rDoc.GetNumberFormat(aCurPos);
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ const SvNumberformat* pCurNumFormatEntry = pFormatter->GetEntry(nCurNumFormat);
+ const SvNumFormatType nCurNumFormatType = (pCurNumFormatEntry ?
+ pCurNumFormatEntry->GetMaskedType() : SvNumFormatType::UNDEFINED);
+
+ if (bInputMode)
+ {
+ double fVal = 0.0;
+ sal_uInt32 nFormat = 0;
+ switch (nReqFmt)
+ {
+ case SvNumFormatType::DATE:
+ {
+ Date aActDate( Date::SYSTEM );
+ fVal = aActDate - pFormatter->GetNullDate();
+ if (nCurNumFormatType == SvNumFormatType::DATE)
+ nFormat = nCurNumFormat;
+ }
+ break;
+ case SvNumFormatType::TIME:
+ {
+ tools::Time aActTime( tools::Time::SYSTEM );
+ fVal = aActTime.GetTimeInDays();
+ if (nCurNumFormatType == SvNumFormatType::TIME)
+ nFormat = nCurNumFormat;
+ }
+ break;
+ default:
+ SAL_WARN("sc.ui","unhandled current date/time request");
+ nReqFmt = SvNumFormatType::DATETIME;
+ [[fallthrough]];
+ case SvNumFormatType::DATETIME:
+ {
+ DateTime aActDateTime( DateTime::SYSTEM );
+ fVal = aActDateTime - DateTime( pFormatter->GetNullDate());
+ if (nCurNumFormatType == SvNumFormatType::DATETIME)
+ nFormat = nCurNumFormat;
+ }
+ break;
+ }
+
+ if (!nFormat)
+ {
+ const LanguageType nLang = (pCurNumFormatEntry ? pCurNumFormatEntry->GetLanguage() : ScGlobal::eLnge);
+ nFormat = pFormatter->GetStandardFormat( nReqFmt, nLang);
+ // This would return a more precise format with seconds and 100th
+ // seconds for a time request.
+ //nFormat = pFormatter->GetStandardFormat( fVal, nFormat, nReqFmt, nLang);
+ }
+ OUString aString;
+ const Color* pColor;
+ pFormatter->GetOutputString( fVal, nFormat, aString, &pColor);
+
+ pInputHdl->DataChanging();
+ EditView* pTopView = pInputHdl->GetTopView();
+ if (pTopView)
+ pTopView->InsertText( aString);
+ EditView* pTableView = pInputHdl->GetTableView();
+ if (pTableView)
+ pTableView->InsertText( aString);
+ pInputHdl->DataChanged();
+ }
+ else
+ {
+ // Clear "Enter pastes" mode.
+ rViewData.SetPasteMode( ScPasteFlags::NONE );
+ // Clear CopySourceOverlay in each window of a split/frozen tabview.
+ rViewData.GetViewShell()->UpdateCopySourceOverlay();
+
+ bool bForceReqFmt = false;
+ const double fCell = rDoc.GetValue( aCurPos);
+ // Combine requested date/time stamp with existing cell time/date, if any.
+ switch (nReqFmt)
+ {
+ case SvNumFormatType::DATE:
+ switch (nCurNumFormatType)
+ {
+ case SvNumFormatType::TIME:
+ // An empty cell formatted as time (or 00:00 time) shall
+ // not result in the current date with 00:00 time, but only
+ // in current date.
+ if (fCell != 0.0)
+ nReqFmt = SvNumFormatType::DATETIME;
+ break;
+ case SvNumFormatType::DATETIME:
+ {
+ // Force to only date if the existing date+time is the
+ // current date. This way inserting current date twice
+ // on an existing date+time cell can be used to force
+ // date, which otherwise would only be possible by
+ // applying a date format.
+ double fDate = rtl::math::approxFloor( fCell);
+ if (fDate == (Date( Date::SYSTEM) - pFormatter->GetNullDate()))
+ bForceReqFmt = true;
+ }
+ break;
+ default: break;
+ }
+ break;
+ case SvNumFormatType::TIME:
+ switch (nCurNumFormatType)
+ {
+ case SvNumFormatType::DATE:
+ // An empty cell formatted as date shall not result in the
+ // null date and current time, but only in current time.
+ if (fCell != 0.0)
+ nReqFmt = SvNumFormatType::DATETIME;
+ break;
+ case SvNumFormatType::DATETIME:
+ // Requesting current time on an empty date+time cell
+ // inserts both current date+time.
+ if (fCell == 0.0)
+ nReqFmt = SvNumFormatType::DATETIME;
+ else
+ {
+ // Add current time to an existing date+time where time is
+ // zero and date is current date, else force time only.
+ double fDate = rtl::math::approxFloor( fCell);
+ double fTime = fCell - fDate;
+ if (fTime == 0.0 && fDate == (Date( Date::SYSTEM) - pFormatter->GetNullDate()))
+ nReqFmt = SvNumFormatType::DATETIME;
+ else
+ bForceReqFmt = true;
+ }
+ break;
+ default: break;
+ }
+ break;
+ default:
+ SAL_WARN("sc.ui","unhandled current date/time request");
+ nReqFmt = SvNumFormatType::DATETIME;
+ [[fallthrough]];
+ case SvNumFormatType::DATETIME:
+ break;
+ }
+ double fVal = 0.0;
+ switch (nReqFmt)
+ {
+ case SvNumFormatType::DATE:
+ {
+ Date aActDate( Date::SYSTEM );
+ fVal = aActDate - pFormatter->GetNullDate();
+ }
+ break;
+ case SvNumFormatType::TIME:
+ {
+ tools::Time aActTime( tools::Time::SYSTEM );
+ fVal = aActTime.GetTimeInDays();
+ }
+ break;
+ case SvNumFormatType::DATETIME:
+ switch (nCurNumFormatType)
+ {
+ case SvNumFormatType::DATE:
+ {
+ double fDate = rtl::math::approxFloor( fCell);
+ tools::Time aActTime( tools::Time::SYSTEM );
+ fVal = fDate + aActTime.GetTimeInDays();
+ }
+ break;
+ case SvNumFormatType::TIME:
+ {
+ double fTime = fCell - rtl::math::approxFloor( fCell);
+ Date aActDate( Date::SYSTEM );
+ fVal = (aActDate - pFormatter->GetNullDate()) + fTime;
+ }
+ break;
+ default:
+ {
+ DateTime aActDateTime( DateTime::SYSTEM );
+ // Converting the null date to DateTime forces the
+ // correct operator-() to be used, resulting in a
+ // fractional date+time instead of only date value.
+ fVal = aActDateTime - DateTime( pFormatter->GetNullDate());
+ }
+ }
+ break;
+ default: break;
+
+ }
+
+ SfxUndoManager* pUndoMgr = pDocSh->GetUndoManager();
+ pUndoMgr->EnterListAction(rUndoStr, rUndoStr, 0, rViewData.GetViewShell()->GetViewShellId());
+
+ pDocSh->GetDocFunc().SetValueCell(aCurPos, fVal, true);
+
+ // Set the new cell format only when it differs from the current cell
+ // format type. Preserve a date+time format unless we force a format
+ // through.
+ if (bForceReqFmt || (nReqFmt != nCurNumFormatType && nCurNumFormatType != SvNumFormatType::DATETIME))
+ SetNumberFormat(nReqFmt);
+ else
+ rViewData.UpdateInputHandler(); // update input bar with new value
+
+ pUndoMgr->LeaveListAction();
+ }
+}
+
+void ScViewFunc::ShowNote( bool bShow )
+{
+ if( bShow )
+ HideNoteMarker();
+ const ScViewData& rViewData = GetViewData();
+ ScAddress aPos( rViewData.GetCurX(), rViewData.GetCurY(), rViewData.GetTabNo() );
+ // show note moved to ScDocFunc, to be able to use it in notesuno.cxx
+ rViewData.GetDocShell()->GetDocFunc().ShowNote( aPos, bShow );
+}
+
+void ScViewFunc::EditNote()
+{
+ // for editing display and activate
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCCOL nCol = GetViewData().GetCurX();
+ SCROW nRow = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScAddress aPos( nCol, nRow, nTab );
+
+ // start drawing undo to catch undo action for insertion of the caption object
+ pDocSh->MakeDrawLayer();
+ ScDrawLayer* pDrawLayer = rDoc.GetDrawLayer();
+ pDrawLayer->BeginCalcUndo(true);
+ // generated undo action is processed in FuText::StopEditMode
+
+ // get existing note or create a new note (including caption drawing object)
+ ScPostIt* pNote = rDoc.GetOrCreateNote( aPos );
+ if(!pNote)
+ return;
+
+ // hide temporary note caption
+ HideNoteMarker();
+ // show caption object without changing internal visibility state
+ pNote->ShowCaptionTemp( aPos );
+
+ /* Drawing object has been created in ScDocument::GetOrCreateNote() or
+ in ScPostIt::ShowCaptionTemp(), so ScPostIt::GetCaption() should
+ return a caption object. */
+ SdrCaptionObj* pCaption = pNote->GetCaption();
+ if( !pCaption )
+ return;
+
+ if ( ScDrawView* pScDrawView = GetScDrawView() )
+ pScDrawView->SyncForGrid( pCaption );
+ // #i33764# enable the resize handles before starting edit mode
+ if( FuPoor* pDraw = GetDrawFuncPtr() )
+ static_cast< FuSelection* >( pDraw )->ActivateNoteHandles( pCaption );
+
+ // activate object (as in FuSelection::TestComment)
+ GetViewData().GetDispatcher().Execute( SID_DRAW_NOTEEDIT, SfxCallMode::SYNCHRON | SfxCallMode::RECORD );
+ // now get the created FuText and set into EditMode
+ FuText* pFuText = dynamic_cast<FuText*>(GetDrawFuncPtr());
+ if (pFuText)
+ {
+ ScrollToObject( pCaption ); // make object fully visible
+ pFuText->SetInEditMode( pCaption );
+
+ ScTabView::OnLOKNoteStateChanged( pNote );
+ }
+ collectUIInformation("OPEN");
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/viewfun7.cxx b/sc/source/ui/view/viewfun7.cxx
new file mode 100644
index 000000000..d83d6867f
--- /dev/null
+++ b/sc/source/ui/view/viewfun7.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 <com/sun/star/embed/NoVisualAreaSizeException.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+
+#include <svx/svditer.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdoole2.hxx>
+#include <svx/svdouno.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/svdundo.hxx>
+#include <svtools/embedhlp.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/ipclient.hxx>
+#include <toolkit/helper/vclunohelper.hxx>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <osl/diagnose.h>
+
+#include <document.hxx>
+#include <viewfunc.hxx>
+#include <tabvwsh.hxx>
+#include <drawview.hxx>
+#include <scmod.hxx>
+#include <drwlayer.hxx>
+#include <drwtrans.hxx>
+#include <globstr.hrc>
+#include <scresid.hxx>
+#include <docuno.hxx>
+#include <docsh.hxx>
+#include <dragdata.hxx>
+#include <gridwin.hxx>
+
+bool bPasteIsMove = false;
+
+using namespace com::sun::star;
+
+static void lcl_AdjustInsertPos( ScViewData& rData, Point& rPos, const Size& rSize )
+{
+ SdrPage* pPage = rData.GetScDrawView()->GetModel()->GetPage( static_cast<sal_uInt16>(rData.GetTabNo()) );
+ OSL_ENSURE(pPage,"pPage ???");
+ Size aPgSize( pPage->GetSize() );
+ if (aPgSize.Width() < 0)
+ aPgSize.setWidth( -aPgSize.Width() );
+ tools::Long x = aPgSize.Width() - rPos.X() - rSize.Width();
+ tools::Long y = aPgSize.Height() - rPos.Y() - rSize.Height();
+ // if necessary: adjustments (80/200) for pixel approx. errors
+ if( x < 0 )
+ rPos.AdjustX(x + 80 );
+ if( y < 0 )
+ rPos.AdjustY(y + 200 );
+ rPos.AdjustX(rSize.Width() / 2 ); // position at paste is center
+ rPos.AdjustY(rSize.Height() / 2 );
+}
+
+void ScViewFunc::PasteDraw( const Point& rLogicPos, SdrModel* pModel,
+ bool bGroup, std::u16string_view rSrcShellID, std::u16string_view rDestShellID )
+{
+ bool bSameDocClipboard = rSrcShellID == rDestShellID;
+
+ MakeDrawLayer();
+ Point aPos( rLogicPos );
+
+ // MapMode at Outliner-RefDevice has to be right (as in FuText::MakeOutliner)
+ //! merge with FuText::MakeOutliner?
+ MapMode aOldMapMode;
+ OutputDevice* pRef = GetViewData().GetDocument().GetDrawLayer()->GetRefDevice();
+ if (pRef)
+ {
+ aOldMapMode = pRef->GetMapMode();
+ pRef->SetMapMode( MapMode(MapUnit::Map100thMM) );
+ }
+
+ bool bNegativePage = GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() );
+
+ SdrView* pDragEditView = nullptr;
+ ScModule* pScMod = SC_MOD();
+ const ScDragData& rData = pScMod->GetDragData();
+ ScDrawTransferObj* pDrawTrans = rData.pDrawTransfer;
+ if (pDrawTrans)
+ {
+ pDragEditView = pDrawTrans->GetDragSourceView();
+
+ aPos -= aDragStartDiff;
+ if ( bNegativePage )
+ {
+ if (aPos.X() > 0) aPos.setX( 0 );
+ }
+ else
+ {
+ if (aPos.X() < 0) aPos.setX( 0 );
+ }
+ if (aPos.Y() < 0) aPos.setY( 0 );
+ }
+
+ ScDrawView* pScDrawView = GetScDrawView();
+ if (bGroup)
+ pScDrawView->BegUndo( ScResId( STR_UNDO_PASTE ) );
+
+ bool bSameDoc = ( pDragEditView && pDragEditView->GetModel() == pScDrawView->GetModel() );
+ if (bSameDoc)
+ {
+ // copy locally - incl. charts
+
+ Point aSourceStart = pDragEditView->GetAllMarkedRect().TopLeft();
+ tools::Long nDiffX = aPos.X() - aSourceStart.X();
+ tools::Long nDiffY = aPos.Y() - aSourceStart.Y();
+
+ // move within a page?
+
+ if ( bPasteIsMove &&
+ pScDrawView->GetSdrPageView()->GetPage() ==
+ pDragEditView->GetSdrPageView()->GetPage() )
+ {
+ if ( nDiffX != 0 || nDiffY != 0 )
+ pDragEditView->MoveAllMarked(Size(nDiffX,nDiffY));
+ }
+ else
+ {
+ SdrModel* pDrawModel = pDragEditView->GetModel();
+ SCTAB nTab = GetViewData().GetTabNo();
+ SdrPage* pDestPage = pDrawModel->GetPage( static_cast< sal_uInt16 >( nTab ) );
+ OSL_ENSURE(pDestPage,"who is this, Page?");
+
+ ::std::vector< OUString > aExcludedChartNames;
+ if ( pDestPage )
+ {
+ ScChartHelper::GetChartNames( aExcludedChartNames, pDestPage );
+ }
+
+ SdrMarkList aMark = pDragEditView->GetMarkedObjectList();
+ aMark.ForceSort();
+ const size_t nMarkCnt=aMark.GetMarkCount();
+ for (size_t nm=0; nm<nMarkCnt; ++nm) {
+ const SdrMark* pM=aMark.GetMark(nm);
+ const SdrObject* pObj=pM->GetMarkedSdrObj();
+
+ // Directly Clone to target SdrModel
+ SdrObject* pNewObj(pObj->CloneSdrObject(*pDrawModel));
+
+ if (pNewObj!=nullptr)
+ {
+ // copy graphics within the same model - always needs new name
+ if ( dynamic_cast<const SdrGrafObj*>( pNewObj) != nullptr && !bPasteIsMove )
+ pNewObj->SetName(static_cast<ScDrawLayer*>(pDrawModel)->GetNewGraphicName());
+
+ if (nDiffX!=0 || nDiffY!=0)
+ pNewObj->NbcMove(Size(nDiffX,nDiffY));
+ if (pDestPage)
+ pDestPage->InsertObject( pNewObj );
+ pScDrawView->AddUndo(std::make_unique<SdrUndoInsertObj>( *pNewObj ));
+
+ if (ScDrawLayer::IsCellAnchored(*pNewObj))
+ ScDrawLayer::SetCellAnchoredFromPosition(*pNewObj, GetViewData().GetDocument(), nTab,
+ ScDrawLayer::IsResizeWithCell(*pNewObj));
+ }
+ }
+
+ if (bPasteIsMove)
+ pDragEditView->DeleteMarked();
+
+ ScDocument& rDocument = GetViewData().GetDocument();
+ ScDocShell* pDocShell = GetViewData().GetDocShell();
+ ScModelObj* pModelObj = ( pDocShell ? comphelper::getFromUnoTunnel<ScModelObj>( pDocShell->GetModel() ) : nullptr );
+ if ( pDestPage && pModelObj && pDrawTrans )
+ {
+ const ScRangeListVector& rProtectedChartRangesVector( pDrawTrans->GetProtectedChartRangesVector() );
+ ScChartHelper::CreateProtectedChartListenersAndNotify( rDocument, pDestPage, pModelObj, nTab,
+ rProtectedChartRangesVector, aExcludedChartNames, bSameDoc );
+ }
+ }
+ }
+ else
+ {
+ bPasteIsMove = false; // no internal move happened
+ SdrView aView(*pModel); // #i71529# never create a base class of SdrView directly!
+ SdrPageView* pPv = aView.ShowSdrPage(aView.GetModel()->GetPage(0));
+ aView.MarkAllObj(pPv);
+ Size aSize = aView.GetAllMarkedRect().GetSize();
+ lcl_AdjustInsertPos( GetViewData(), aPos, aSize );
+
+ // don't change marking if OLE object is active
+ // (at Drop from OLE object it would be deactivated in the middle of ExecuteDrag!)
+
+ SdrInsertFlags nOptions = SdrInsertFlags::NONE;
+ SfxInPlaceClient* pClient = GetViewData().GetViewShell()->GetIPClient();
+ if ( pClient && pClient->IsObjectInPlaceActive() )
+ nOptions |= SdrInsertFlags::DONTMARK;
+
+ ::std::vector< OUString > aExcludedChartNames;
+ SCTAB nTab = GetViewData().GetTabNo();
+ SdrPage* pPage = pScDrawView->GetModel()->GetPage( static_cast< sal_uInt16 >( nTab ) );
+ OSL_ENSURE( pPage, "Page?" );
+ if ( pPage )
+ {
+ ScChartHelper::GetChartNames( aExcludedChartNames, pPage );
+ }
+
+ // #89247# Set flag for ScDocument::UpdateChartListeners() which is
+ // called during paste.
+ if ( !bSameDocClipboard )
+ GetViewData().GetDocument().SetPastingDrawFromOtherDoc( true );
+
+ pScDrawView->Paste(*pModel, aPos, nullptr, nOptions);
+
+ if ( !bSameDocClipboard )
+ GetViewData().GetDocument().SetPastingDrawFromOtherDoc( false );
+
+ // Paste puts all objects on the active (front) layer
+ // controls must be on SC_LAYER_CONTROLS
+ if (pPage)
+ {
+ SdrObjListIter aIter( pPage, SdrIterMode::DeepNoGroups );
+ SdrObject* pObject = aIter.Next();
+ while (pObject)
+ {
+ if ( dynamic_cast<const SdrUnoObj*>( pObject) != nullptr && pObject->GetLayer() != SC_LAYER_CONTROLS )
+ pObject->NbcSetLayer(SC_LAYER_CONTROLS);
+
+ if (ScDrawLayer::IsCellAnchored(*pObject))
+ ScDrawLayer::SetCellAnchoredFromPosition(*pObject, GetViewData().GetDocument(), nTab,
+ ScDrawLayer::IsResizeWithCell(*pObject));
+
+ pObject = aIter.Next();
+ }
+ }
+
+ // all graphics objects must have names
+ GetViewData().GetDocument().EnsureGraphicNames();
+
+ ScDocument& rDocument = GetViewData().GetDocument();
+ ScDocShell* pDocShell = GetViewData().GetDocShell();
+ ScModelObj* pModelObj = ( pDocShell ? comphelper::getFromUnoTunnel<ScModelObj>( pDocShell->GetModel() ) : nullptr );
+ const ScDrawTransferObj* pTransferObj = ScDrawTransferObj::GetOwnClipboard(ScTabViewShell::GetClipData(GetViewData().GetActiveWin()));
+ if ( pPage && pModelObj && ( pTransferObj || pDrawTrans ) )
+ {
+ const ScRangeListVector& rProtectedChartRangesVector(
+ pTransferObj ? pTransferObj->GetProtectedChartRangesVector() : pDrawTrans->GetProtectedChartRangesVector() );
+ ScChartHelper::CreateProtectedChartListenersAndNotify( rDocument, pPage, pModelObj, nTab,
+ rProtectedChartRangesVector, aExcludedChartNames, bSameDocClipboard );
+ }
+ }
+
+ if (bGroup)
+ {
+ pScDrawView->GroupMarked();
+ pScDrawView->EndUndo();
+ }
+
+ if (pRef)
+ pRef->SetMapMode( aOldMapMode );
+
+ // GetViewData().GetViewShell()->SetDrawShell( true );
+ // It is not sufficient to just set the DrawShell if we pasted, for
+ // example, a chart. SetDrawShellOrSub() would only work for D&D in the
+ // same document but not if inserting from the clipboard, therefore
+ // MarkListHasChanged() is what we need.
+ pScDrawView->MarkListHasChanged();
+
+}
+
+bool ScViewFunc::PasteObject( const Point& rPos, const uno::Reference < embed::XEmbeddedObject >& xObj,
+ const Size* pDescSize, const Graphic* pReplGraph, const OUString& aMediaType, sal_Int64 nAspect )
+{
+ MakeDrawLayer();
+ if ( xObj.is() )
+ {
+ OUString aName;
+ //TODO/MBA: is that OK?
+ comphelper::EmbeddedObjectContainer& aCnt = GetViewData().GetViewShell()->GetObjectShell()->GetEmbeddedObjectContainer();
+ if ( !aCnt.HasEmbeddedObject( xObj ) )
+ aCnt.InsertEmbeddedObject( xObj, aName );
+ else
+ aName = aCnt.GetEmbeddedObjectName( xObj );
+
+ svt::EmbeddedObjectRef aObjRef( xObj, nAspect );
+ if ( pReplGraph )
+ aObjRef.SetGraphic( *pReplGraph, aMediaType );
+
+ Size aSize;
+ if ( nAspect == embed::Aspects::MSOLE_ICON )
+ {
+ MapMode aMapMode( MapUnit::Map100thMM );
+ aSize = aObjRef.GetSize( &aMapMode );
+ }
+ else
+ {
+ // working with visual area can switch object to running state
+ MapUnit aMapObj = VCLUnoHelper::UnoEmbed2VCLMapUnit( xObj->getMapUnit( nAspect ) );
+ MapUnit aMap100 = MapUnit::Map100thMM;
+
+ if ( pDescSize && pDescSize->Width() && pDescSize->Height() )
+ {
+ // use size from object descriptor if given
+ aSize = OutputDevice::LogicToLogic(*pDescSize, MapMode(aMap100), MapMode(aMapObj));
+ awt::Size aSz;
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+ xObj->setVisualAreaSize( nAspect, aSz );
+ }
+
+ awt::Size aSz;
+ try
+ {
+ aSz = xObj->getVisualAreaSize( nAspect );
+ }
+ catch ( embed::NoVisualAreaSizeException& )
+ {
+ // the default size will be set later
+ }
+
+ aSize = Size( aSz.Width, aSz.Height );
+ aSize = OutputDevice::LogicToLogic(aSize, MapMode(aMapObj), MapMode(aMap100)); // for SdrOle2Obj
+
+ if( aSize.IsEmpty() )
+ {
+ OSL_FAIL("SvObjectDescriptor::GetSize == 0");
+ aSize.setWidth( 5000 );
+ aSize.setHeight( 5000 );
+ aSize = OutputDevice::LogicToLogic(aSize, MapMode(aMap100), MapMode(aMapObj));
+ aSz.Width = aSize.Width();
+ aSz.Height = aSize.Height();
+ xObj->setVisualAreaSize( nAspect, aSz );
+ }
+ }
+
+ // don't call AdjustInsertPos
+ Point aInsPos = rPos;
+ if ( GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() ) )
+ aInsPos.AdjustX( -(aSize.Width()) );
+ tools::Rectangle aRect( aInsPos, aSize );
+
+ ScDrawView* pDrView = GetScDrawView();
+ SdrOle2Obj* pSdrObj = new SdrOle2Obj(
+ pDrView->getSdrModelFromSdrView(),
+ aObjRef,
+ aName,
+ aRect);
+
+ SdrPageView* pPV = pDrView->GetSdrPageView();
+ pDrView->InsertObjectSafe( pSdrObj, *pPV ); // don't mark if OLE
+ GetViewData().GetViewShell()->SetDrawShell( true );
+ return true;
+ }
+ else
+ return false;
+}
+
+bool ScViewFunc::PasteBitmapEx( const Point& rPos, const BitmapEx& rBmpEx )
+{
+ Graphic aGraphic(rBmpEx);
+ return PasteGraphic( rPos, aGraphic, "" );
+}
+
+bool ScViewFunc::PasteMetaFile( const Point& rPos, const GDIMetaFile& rMtf )
+{
+ Graphic aGraphic(rMtf);
+ return PasteGraphic( rPos, aGraphic, "" );
+}
+
+bool ScViewFunc::PasteGraphic( const Point& rPos, const Graphic& rGraphic,
+ const OUString& rFile )
+{
+ MakeDrawLayer();
+ ScDrawView* pScDrawView = GetScDrawView();
+
+ if (!pScDrawView)
+ return false;
+
+ // #i123922# check if the drop was over an existing object; if yes, evtl. replace
+ // the graphic for a SdrGraphObj (including link state updates) or adapt the fill
+ // style for other objects
+ SdrPageView* pPageView = pScDrawView->GetSdrPageView();
+ if (pPageView)
+ {
+ SdrObject* pPickObj = pScDrawView->PickObj(rPos, pScDrawView->getHitTolLog(), pPageView);
+ if (pPickObj)
+ {
+ const OUString aBeginUndo(ScResId(STR_UNDO_DRAGDROP));
+ SdrObject* pResult = pScDrawView->ApplyGraphicToObject(
+ *pPickObj,
+ rGraphic,
+ aBeginUndo,
+ rFile);
+
+ if (pResult)
+ {
+ // we are done; mark the modified/new object
+ pScDrawView->MarkObj(pResult, pScDrawView->GetSdrPageView());
+ return true;
+ }
+ }
+ }
+
+ Point aPos( rPos );
+ vcl::Window* pWin = GetActiveWin();
+ MapMode aSourceMap = rGraphic.GetPrefMapMode();
+ MapMode aDestMap( MapUnit::Map100thMM );
+
+ if (aSourceMap.GetMapUnit() == MapUnit::MapPixel)
+ {
+ // consider pixel correction, so bitmap fits to screen
+ Fraction aScaleX, aScaleY;
+ pScDrawView->CalcNormScale( aScaleX, aScaleY );
+ aDestMap.SetScaleX(aScaleX);
+ aDestMap.SetScaleY(aScaleY);
+ }
+
+ Size aSize = pWin->LogicToLogic( rGraphic.GetPrefSize(), &aSourceMap, &aDestMap );
+
+ if ( GetViewData().GetDocument().IsNegativePage( GetViewData().GetTabNo() ) )
+ aPos.AdjustX( -(aSize.Width()) );
+
+ GetViewData().GetViewShell()->SetDrawShell( true );
+ tools::Rectangle aRect(aPos, aSize);
+ SdrGrafObj* pGrafObj = new SdrGrafObj(
+ pScDrawView->getSdrModelFromSdrView(),
+ rGraphic,
+ aRect);
+
+ // path was the name of the graphic in history
+
+ ScDrawLayer* pLayer = static_cast<ScDrawLayer*>( pScDrawView->GetModel() );
+ OUString aName = pLayer->GetNewGraphicName(); // "Graphics"
+ pGrafObj->SetName(aName);
+
+ // don't mark if OLE
+ bool bSuccess = pScDrawView->InsertObjectSafe(pGrafObj, *pScDrawView->GetSdrPageView());
+
+ // SetGraphicLink has to be used after inserting the object,
+ // otherwise an empty graphic is swapped in and the contact stuff crashes.
+ // See #i37444#.
+ if (bSuccess && !rFile.isEmpty())
+ pGrafObj->SetGraphicLink( rFile );
+
+ return bSuccess;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
new file mode 100644
index 000000000..d343551c9
--- /dev/null
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -0,0 +1,3073 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_features.h>
+
+#include <scitems.hxx>
+
+#include <sfx2/app.hxx>
+#include <svx/algitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/editobj.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/justifyitem.hxx>
+#include <o3tl/unit_conversion.hxx>
+#include <sfx2/bindings.hxx>
+#include <svl/numformat.hxx>
+#include <svl/zforlist.hxx>
+#include <svl/zformat.hxx>
+#include <vcl/weld.hxx>
+#include <vcl/virdev.hxx>
+#include <stdlib.h>
+#include <unotools/charclass.hxx>
+#include <vcl/uitest/logger.hxx>
+#include <vcl/uitest/eventdescription.hxx>
+#include <osl/diagnose.h>
+#include <formula/paramclass.hxx>
+
+#include <viewfunc.hxx>
+#include <tabvwsh.hxx>
+#include <docsh.hxx>
+#include <attrib.hxx>
+#include <patattr.hxx>
+#include <docpool.hxx>
+#include <sc.hrc>
+#include <undocell.hxx>
+#include <undoblk.hxx>
+#include <refundo.hxx>
+#include <olinetab.hxx>
+#include <rangenam.hxx>
+#include <globstr.hrc>
+#include <global.hxx>
+#include <stlsheet.hxx>
+#include <editutil.hxx>
+#include <formulacell.hxx>
+#include <scresid.hxx>
+#include <inputhdl.hxx>
+#include <scmod.hxx>
+#include <inputopt.hxx>
+#include <compiler.hxx>
+#include <docfunc.hxx>
+#include <appoptio.hxx>
+#include <sizedev.hxx>
+#include <editable.hxx>
+#include <scui_def.hxx>
+#include <funcdesc.hxx>
+#include <docuno.hxx>
+#include <cellsuno.hxx>
+#include <tokenarray.hxx>
+#include <rowheightcontext.hxx>
+#include <comphelper/lok.hxx>
+#include <conditio.hxx>
+#include <columnspanset.hxx>
+#include <stringutil.hxx>
+
+#include <memory>
+
+static void lcl_PostRepaintCondFormat( const ScConditionalFormat *pCondFmt, ScDocShell *pDocSh )
+{
+ if( pCondFmt )
+ {
+ const ScRangeList& rRanges = pCondFmt->GetRange();
+
+ pDocSh->PostPaint( rRanges, PaintPartFlags::All );
+ }
+}
+
+ScViewFunc::ScViewFunc( vcl::Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pViewShell ) :
+ ScTabView( pParent, rDocSh, pViewShell ),
+ bFormatValid( false )
+{
+}
+
+ScViewFunc::~ScViewFunc()
+{
+}
+
+namespace {
+
+void collectUIInformation(std::map<OUString, OUString>&& aParameters, const OUString& rAction)
+{
+ EventDescription aDescription;
+ aDescription.aID = "grid_window";
+ aDescription.aAction = rAction;
+ aDescription.aParameters = std::move(aParameters);
+ aDescription.aParent = "MainWindow";
+ aDescription.aKeyWord = "ScGridWinUIObject";
+
+ UITestLogger::getInstance().logEvent(aDescription);
+}
+
+}
+
+void ScViewFunc::StartFormatArea()
+{
+ // anything to do?
+ if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
+ return;
+
+ // start only with single cell (marked or cursor position)
+ ScRange aMarkRange;
+ bool bOk = (GetViewData().GetSimpleArea( aMarkRange ) == SC_MARK_SIMPLE);
+ if ( bOk && aMarkRange.aStart != aMarkRange.aEnd )
+ bOk = false;
+
+ if (bOk)
+ {
+ bFormatValid = true;
+ aFormatSource = aMarkRange.aStart;
+ aFormatArea = ScRange( aFormatSource );
+ }
+ else
+ bFormatValid = false; // discard old range
+}
+
+bool ScViewFunc::TestFormatArea( SCCOL nCol, SCROW nRow, SCTAB nTab, bool bAttrChanged )
+{
+ // anything to do?
+ if ( !SC_MOD()->GetInputOptions().GetExtendFormat() )
+ return false;
+
+ // Test: treat input with numberformat (bAttrChanged) always as new Attribute
+ // (discard old Area ). If not wanted, discard if-statement
+ if ( bAttrChanged )
+ {
+ StartFormatArea();
+ return false;
+ }
+
+ //! Test if cell empty ???
+
+ bool bFound = false;
+ ScRange aNewRange = aFormatArea;
+ if ( bFormatValid && nTab == aFormatSource.Tab() )
+ {
+ if ( nRow >= aFormatArea.aStart.Row() && nRow <= aFormatArea.aEnd.Row() )
+ {
+ // within range?
+ if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
+ {
+ bFound = true; // do not change range
+ }
+ // left ?
+ if ( nCol+1 == aFormatArea.aStart.Col() )
+ {
+ bFound = true;
+ aNewRange.aStart.SetCol( nCol );
+ }
+ // right ?
+ if ( nCol == aFormatArea.aEnd.Col()+1 )
+ {
+ bFound = true;
+ aNewRange.aEnd.SetCol( nCol );
+ }
+ }
+ if ( nCol >= aFormatArea.aStart.Col() && nCol <= aFormatArea.aEnd.Col() )
+ {
+ // top ?
+ if ( nRow+1 == aFormatArea.aStart.Row() )
+ {
+ bFound = true;
+ aNewRange.aStart.SetRow( nRow );
+ }
+ // bottom ?
+ if ( nRow == aFormatArea.aEnd.Row()+1 )
+ {
+ bFound = true;
+ aNewRange.aEnd.SetRow( nRow );
+ }
+ }
+ }
+
+ if (bFound)
+ aFormatArea = aNewRange; // extend
+ else
+ bFormatValid = false; // outside of range -> break
+
+ return bFound;
+}
+
+void ScViewFunc::DoAutoAttributes( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ bool bAttrChanged )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ const ScPatternAttr* pSource = rDoc.GetPattern(
+ aFormatSource.Col(), aFormatSource.Row(), nTab );
+ if ( !pSource->GetItem(ATTR_MERGE).IsMerged() )
+ {
+ ScRange aRange( nCol, nRow, nTab, nCol, nRow, nTab );
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SetMarkArea( aRange );
+
+ ScDocFunc &rFunc = GetViewData().GetDocFunc();
+
+ // pOldPattern is only valid until call to ApplyAttributes!
+ const ScPatternAttr* pOldPattern = rDoc.GetPattern( nCol, nRow, nTab );
+ const ScStyleSheet* pSrcStyle = pSource->GetStyleSheet();
+ if ( pSrcStyle && pSrcStyle != pOldPattern->GetStyleSheet() )
+ rFunc.ApplyStyle( aMark, pSrcStyle->GetName(), false );
+
+ rFunc.ApplyAttributes( aMark, *pSource, false );
+ }
+
+ if ( bAttrChanged ) // value entered with number format?
+ aFormatSource.Set( nCol, nRow, nTab ); // then set a new source
+}
+
+// additional routines
+
+sal_uInt16 ScViewFunc::GetOptimalColWidth( SCCOL nCol, SCTAB nTab, bool bFormula )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+
+ double nPPTX = GetViewData().GetPPTX();
+ double nPPTY = GetViewData().GetPPTY();
+ Fraction aZoomX = GetViewData().GetZoomX();
+ Fraction aZoomY = GetViewData().GetZoomY();
+
+ ScSizeDeviceProvider aProv(pDocSh);
+ if (aProv.IsPrinter())
+ {
+ nPPTX = aProv.GetPPTX();
+ nPPTY = aProv.GetPPTY();
+ aZoomX = aZoomY = Fraction( 1, 1 );
+ }
+
+ sal_uInt16 nTwips = rDoc.GetOptimalColWidth( nCol, nTab, aProv.GetDevice(),
+ nPPTX, nPPTY, aZoomX, aZoomY, bFormula, &rMark );
+ return nTwips;
+}
+
+bool ScViewFunc::SelectionEditable( bool* pOnlyNotBecauseOfMatrix /* = NULL */ )
+{
+ bool bRet;
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ if (rMark.IsMarked() || rMark.IsMultiMarked())
+ bRet = rDoc.IsSelectionEditable( rMark, pOnlyNotBecauseOfMatrix );
+ else
+ {
+ SCCOL nCol = GetViewData().GetCurX();
+ SCROW nRow = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+ bRet = rDoc.IsBlockEditable( nTab, nCol, nRow, nCol, nRow,
+ pOnlyNotBecauseOfMatrix );
+ }
+ return bRet;
+}
+
+static bool lcl_FunctionKnown( sal_uInt16 nOpCode )
+{
+ const ScFunctionList* pFuncList = ScGlobal::GetStarCalcFunctionList();
+ if ( pFuncList )
+ {
+ sal_uLong nCount = pFuncList->GetCount();
+ for (sal_uLong i=0; i<nCount; i++)
+ if ( pFuncList->GetFunction(i)->nFIndex == nOpCode )
+ return true;
+ }
+ return false;
+}
+
+static bool lcl_AddFunction( ScAppOptions& rAppOpt, sal_uInt16 nOpCode )
+{
+ sal_uInt16 nOldCount = rAppOpt.GetLRUFuncListCount();
+ sal_uInt16* pOldList = rAppOpt.GetLRUFuncList();
+ sal_uInt16 nPos;
+ for (nPos=0; nPos<nOldCount; nPos++)
+ if (pOldList[nPos] == nOpCode) // is the function already in the list?
+ {
+ if ( nPos == 0 )
+ return false; // already at the top -> no change
+
+ // count doesn't change, so the original array is modified
+
+ for (sal_uInt16 nCopy=nPos; nCopy>0; nCopy--)
+ pOldList[nCopy] = pOldList[nCopy-1];
+ pOldList[0] = nOpCode;
+
+ return true; // list has changed
+ }
+
+ if ( !lcl_FunctionKnown( nOpCode ) )
+ return false; // not in function list -> no change
+
+ sal_uInt16 nNewCount = std::min( static_cast<sal_uInt16>(nOldCount + 1), sal_uInt16(LRU_MAX) );
+ sal_uInt16 nNewList[LRU_MAX];
+ nNewList[0] = nOpCode;
+ for (nPos=1; nPos<nNewCount; nPos++)
+ nNewList[nPos] = pOldList[nPos-1];
+ rAppOpt.SetLRUFuncList( nNewList, nNewCount );
+
+ return true; // list has changed
+}
+
+namespace HelperNotifyChanges
+{
+ static void NotifyIfChangesListeners(const ScDocShell &rDocShell, ScMarkData& rMark, SCCOL nCol, SCROW nRow)
+ {
+ if (ScModelObj *pModelObj = getMustPropagateChangesModel(rDocShell))
+ {
+ ScRangeList aChangeRanges;
+ for (const auto& rTab : rMark)
+ aChangeRanges.push_back( ScRange( nCol, nRow, rTab ) );
+
+ HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, "cell-change");
+ }
+ }
+}
+
+namespace
+{
+ class AutoCorrectQuery : public weld::MessageDialogController
+ {
+ private:
+ std::unique_ptr<weld::TextView> m_xError;
+ public:
+ AutoCorrectQuery(weld::Window* pParent, const OUString& rFormula)
+ : weld::MessageDialogController(pParent, "modules/scalc/ui/warnautocorrect.ui", "WarnAutoCorrect", "grid")
+ , m_xError(m_xBuilder->weld_text_view("error"))
+ {
+ m_xDialog->set_default_response(RET_YES);
+
+ const int nMaxWidth = m_xError->get_approximate_digit_width() * 65;
+ const int nMaxHeight = m_xError->get_height_rows(6);
+ m_xError->set_size_request(nMaxWidth, nMaxHeight);
+
+ m_xError->set_text(rFormula);
+ }
+ };
+}
+
+// actual functions
+
+// input - undo OK
+void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ const OUString& rString,
+ const EditTextObject* pData,
+ bool bMatrixExpand )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScMarkData rMark(GetViewData().GetMarkData());
+ bool bRecord = rDoc.IsUndoEnabled();
+ SCTAB i;
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocFunc &rFunc = GetViewData().GetDocFunc();
+ ScDocShellModificator aModificator( *pDocSh );
+
+ ScEditableTester aTester( rDoc, nCol,nRow, nCol,nRow, rMark );
+ if (!aTester.IsEditable())
+ {
+ ErrorMessage(aTester.GetMessageId());
+ PaintArea(nCol, nRow, nCol, nRow); // possibly the edit-engine is still painted there
+ return;
+ }
+
+ if ( bRecord )
+ rFunc.EnterListAction( STR_UNDO_ENTERDATA );
+
+ bool bFormula = false;
+
+ // a single '=' character is handled as string (needed for special filters)
+ if ( rString.getLength() > 1 )
+ {
+ if ( rString[0] == '=' )
+ {
+ // handle as formula
+ bFormula = true;
+ }
+ else if ( rString[0] == '+' || rString[0] == '-' )
+ {
+ // if there is more than one leading '+' or '-' character, remove the additional ones
+ sal_Int32 nIndex = 1;
+ sal_Int32 nLen = rString.getLength();
+ while ( nIndex < nLen && ( rString[ nIndex ] == '+' || rString[ nIndex ] == '-' ) )
+ {
+ ++nIndex;
+ }
+ OUString aString = rString.replaceAt( 1, nIndex - 1, u"" );
+
+ // if the remaining part without the leading '+' or '-' character
+ // is non-empty and not a number, handle as formula
+ if ( aString.getLength() > 1 )
+ {
+ sal_uInt32 nFormat = rDoc.GetNumberFormat( nCol, nRow, nTab );
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ double fNumber = 0;
+ if ( !pFormatter->IsNumberFormat( aString, nFormat, fNumber ) )
+ {
+ bFormula = true;
+ }
+ }
+ }
+ }
+
+ bool bNumFmtChanged = false;
+ if ( bFormula )
+ { // formula, compile with autoCorrection
+ i = rMark.GetFirstSelected();
+ ScAddress aPos( nCol, nRow, i );
+ ScCompiler aComp( rDoc, aPos, rDoc.GetGrammar(), true, false );
+//2do: enable/disable autoCorrection via calcoptions
+ aComp.SetAutoCorrection( true );
+ if ( rString[0] == '+' || rString[0] == '-' )
+ {
+ aComp.SetExtendedErrorDetection( ScCompiler::EXTENDED_ERROR_DETECTION_NAME_BREAK );
+ }
+ OUString aFormula( rString );
+ std::unique_ptr< ScTokenArray > pArr;
+ bool bAgain;
+ do
+ {
+ bAgain = false;
+ bool bAddEqual = false;
+ pArr = aComp.CompileString( aFormula );
+ bool bCorrected = aComp.IsCorrected();
+ std::unique_ptr< ScTokenArray > pArrFirst;
+ if ( bCorrected )
+ { // try to parse with first parser-correction
+ pArrFirst = std::move( pArr );
+ pArr = aComp.CompileString( aComp.GetCorrectedFormula() );
+ }
+ if ( pArr->GetCodeError() == FormulaError::NONE )
+ {
+ bAddEqual = true;
+ aComp.CompileTokenArray();
+ bCorrected |= aComp.IsCorrected();
+ }
+ if ( bCorrected )
+ {
+ OUString aCorrectedFormula;
+ if ( bAddEqual )
+ {
+ aCorrectedFormula = "=" + aComp.GetCorrectedFormula();
+ }
+ else
+ aCorrectedFormula = aComp.GetCorrectedFormula();
+ short nResult;
+ if ( aCorrectedFormula.getLength() == 1 )
+ nResult = RET_NO; // empty formula, just '='
+ else
+ {
+ AutoCorrectQuery aQueryBox(GetViewData().GetDialogParent(), aCorrectedFormula);
+ nResult = aQueryBox.run();
+ }
+ if ( nResult == RET_YES )
+ {
+ aFormula = aCorrectedFormula;
+ bAgain = true;
+ }
+ else
+ {
+ if ( pArrFirst )
+ pArr = std::move( pArrFirst );
+ }
+ }
+ } while ( bAgain );
+ // to be used in multiple tabs, the formula must be compiled anew
+ // via ScFormulaCell copy-ctor because of RangeNames,
+ // the same code-array for all cells is not possible.
+ // If the array has an error, (it) must be RPN-erased in the newly generated
+ // cells and the error be set explicitly, so that
+ // via FormulaCell copy-ctor and Interpreter it will be, when possible,
+ // ironed out again, too intelligent... e.g.: =1))
+ FormulaError nError = pArr->GetCodeError();
+ if ( nError == FormulaError::NONE )
+ {
+ // update list of recent functions with all functions that
+ // are not within parentheses
+
+ ScModule* pScMod = SC_MOD();
+ ScAppOptions aAppOpt = pScMod->GetAppOptions();
+ bool bOptChanged = false;
+
+ formula::FormulaToken** ppToken = pArr->GetArray();
+ sal_uInt16 nTokens = pArr->GetLen();
+ sal_uInt16 nLevel = 0;
+ for (sal_uInt16 nTP=0; nTP<nTokens; nTP++)
+ {
+ formula::FormulaToken* pTok = ppToken[nTP];
+ OpCode eOp = pTok->GetOpCode();
+ if ( eOp == ocOpen )
+ ++nLevel;
+ else if ( eOp == ocClose && nLevel )
+ --nLevel;
+ if ( nLevel == 0 && pTok->IsFunction() &&
+ lcl_AddFunction( aAppOpt, sal::static_int_cast<sal_uInt16>( eOp ) ) )
+ bOptChanged = true;
+ }
+
+ if ( bOptChanged )
+ {
+ pScMod->SetAppOptions(aAppOpt);
+ }
+
+ if (bMatrixExpand)
+ {
+ // If the outer function/operator returns an array/matrix then
+ // enter a matrix formula. ScViewFunc::EnterMatrix() takes care
+ // of selection/mark of the result dimensions or preselected
+ // mark. If the user wanted less or a single cell then should
+ // mark such prior to entering the formula.
+ const formula::FormulaToken* pToken = pArr->LastRPNToken();
+ if (pToken && (formula::FormulaCompiler::IsMatrixFunction( pToken->GetOpCode())
+ || pToken->IsInForceArray()))
+ {
+ // Discard this (still empty here) Undo action,
+ // EnterMatrix() will create its own.
+ if (bRecord)
+ rFunc.EndListAction();
+
+ // Use corrected formula string.
+ EnterMatrix( aFormula, rDoc.GetGrammar());
+
+ return;
+ }
+ }
+ }
+
+ ScFormulaCell aCell(rDoc, aPos, std::move( pArr ), formula::FormulaGrammar::GRAM_DEFAULT, ScMatrixMode::NONE);
+
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+ for (const auto& rTab : rMark)
+ {
+ i = rTab;
+ aPos.SetTab( i );
+ const sal_uInt32 nIndex = rDoc.GetAttr(
+ nCol, nRow, i, ATTR_VALUE_FORMAT )->GetValue();
+ const SvNumFormatType nType = pFormatter->GetType( nIndex);
+ if (nType == SvNumFormatType::TEXT ||
+ ((rString[0] == '+' || rString[0] == '-') && nError != FormulaError::NONE && rString == aFormula))
+ {
+ if ( pData )
+ {
+ // A clone of pData will be stored in the cell.
+ rFunc.SetEditCell(aPos, *pData, true);
+ }
+ else
+ rFunc.SetStringCell(aPos, aFormula, true);
+ }
+ else
+ {
+ ScFormulaCell* pCell = new ScFormulaCell( aCell, rDoc, aPos );
+ if ( nError != FormulaError::NONE )
+ {
+ pCell->GetCode()->DelRPN();
+ pCell->SetErrCode( nError );
+ if(pCell->GetCode()->IsHyperLink())
+ pCell->GetCode()->SetHyperLink(false);
+ }
+ if (nType == SvNumFormatType::LOGICAL)
+ {
+ // Reset to General so the actual format can be determined
+ // after the cell has been interpreted. A sticky boolean
+ // number format is highly likely unwanted... see tdf#75650.
+ // General of same locale as current number format.
+ const SvNumberformat* pEntry = pFormatter->GetEntry( nIndex);
+ const LanguageType nLang = (pEntry ? pEntry->GetLanguage() : ScGlobal::eLnge);
+ const sal_uInt32 nFormat = pFormatter->GetStandardFormat( SvNumFormatType::NUMBER, nLang);
+ ScPatternAttr aPattern( rDoc.GetPool());
+ aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nFormat));
+ ScMarkData aMark(rDoc.GetSheetLimits());
+ aMark.SelectTable( i, true);
+ aMark.SetMarkArea( ScRange( aPos));
+ rFunc.ApplyAttributes( aMark, aPattern, false);
+ bNumFmtChanged = true;
+ }
+ rFunc.SetFormulaCell(aPos, pCell, true);
+ }
+ }
+ }
+ else
+ {
+ ScFieldEditEngine& rEngine = rDoc.GetEditEngine();
+ for (const auto& rTab : rMark)
+ {
+ bool bNumFmtSet = false;
+ const ScAddress aScAddress(nCol, nRow, rTab);
+
+ // tdf#104902 - handle embedded newline
+ if (ScStringUtil::isMultiline(rString))
+ {
+ rEngine.SetTextCurrentDefaults(rString);
+ rDoc.SetEditText(aScAddress, rEngine.CreateTextObject());
+ pDocSh->AdjustRowHeight(nRow, nRow, rTab);
+ }
+ else
+ {
+ rFunc.SetNormalString(bNumFmtSet, aScAddress, rString, false);
+ }
+
+ if (bNumFmtSet)
+ {
+ /* FIXME: if set on any sheet results in changed only on
+ * sheet nTab for TestFormatArea() and DoAutoAttributes() */
+ bNumFmtChanged = true;
+ }
+ }
+ }
+
+ bool bAutoFormat = TestFormatArea(nCol, nRow, nTab, bNumFmtChanged);
+
+ if (bAutoFormat)
+ DoAutoAttributes(nCol, nRow, nTab, bNumFmtChanged);
+
+ pDocSh->UpdateOle(GetViewData());
+
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, rMark, nCol, nRow);
+
+ if ( bRecord )
+ rFunc.EndListAction();
+
+ aModificator.SetDocumentModified();
+ lcl_PostRepaintCondFormat( rDoc.GetCondFormat( nCol, nRow, nTab ), pDocSh );
+}
+
+// enter value in single cell (on nTab only)
+
+void ScViewFunc::EnterValue( SCCOL nCol, SCROW nRow, SCTAB nTab, const double& rValue )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+
+ if (!pDocSh)
+ return;
+
+ bool bUndo(rDoc.IsUndoEnabled());
+ ScDocShellModificator aModificator( *pDocSh );
+
+ ScEditableTester aTester( rDoc, nTab, nCol,nRow, nCol,nRow );
+ if (aTester.IsEditable())
+ {
+ ScAddress aPos( nCol, nRow, nTab );
+ ScCellValue aUndoCell;
+ if (bUndo)
+ aUndoCell.assign(rDoc, aPos);
+
+ rDoc.SetValue( nCol, nRow, nTab, rValue );
+
+ // because of ChangeTrack after change in document
+ if (bUndo)
+ {
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoEnterValue>(pDocSh, aPos, aUndoCell, rValue));
+ }
+
+ pDocSh->PostPaintCell( aPos );
+ pDocSh->UpdateOle(GetViewData());
+ aModificator.SetDocumentModified();
+ }
+ else
+ ErrorMessage(aTester.GetMessageId());
+}
+
+void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
+ const EditTextObject& rData, bool bTestSimple )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ bool bRecord = rDoc.IsUndoEnabled();
+
+ ScDocShellModificator aModificator( *pDocSh );
+
+ ScEditableTester aTester( rDoc, nTab, nCol,nRow, nCol,nRow );
+ if (aTester.IsEditable())
+ {
+
+ // test for attribute
+
+ bool bSimple = false;
+ bool bCommon = false;
+ std::unique_ptr<ScPatternAttr> pCellAttrs;
+ OUString aString;
+
+ const ScPatternAttr* pOldPattern = rDoc.GetPattern( nCol, nRow, nTab );
+ ScTabEditEngine aEngine( *pOldPattern, rDoc.GetEnginePool(), &rDoc );
+ aEngine.SetTextCurrentDefaults(rData);
+
+ if (bTestSimple) // test, if simple string without attribute
+ {
+ ScEditAttrTester aAttrTester( &aEngine );
+ bSimple = !aAttrTester.NeedsObject();
+ bCommon = aAttrTester.NeedsCellAttr();
+
+ // formulas have to be recognized even if they're formatted
+ // (but common attributes are still collected)
+
+ if (!bSimple)
+ {
+ OUString aParStr(aEngine.GetText( 0 ));
+ if ( aParStr[0] == '=' )
+ bSimple = true;
+ }
+
+ if (bCommon) // attribute for tab
+ {
+ pCellAttrs.reset(new ScPatternAttr( *pOldPattern ));
+ pCellAttrs->GetFromEditItemSet( &aAttrTester.GetAttribs() );
+ //! remove common attributes from EditEngine?
+ }
+ }
+
+ // #i97726# always get text for "repeat" of undo action
+ aString = ScEditUtil::GetMultilineString(aEngine);
+
+ // undo
+
+ std::unique_ptr<EditTextObject> pUndoData;
+ ScUndoEnterData::ValuesType aOldValues;
+
+ if (bRecord && !bSimple)
+ {
+ for (const auto& rTab : rMark)
+ {
+ ScUndoEnterData::Value aOldValue;
+ aOldValue.mnTab = rTab;
+ aOldValue.maCell.assign(rDoc, ScAddress(nCol, nRow, rTab));
+ aOldValues.push_back(aOldValue);
+ }
+
+ pUndoData = rData.Clone();
+ }
+
+ // enter data
+
+ if (bCommon)
+ rDoc.ApplyPattern(nCol,nRow,nTab,*pCellAttrs); //! undo
+
+ if (bSimple)
+ {
+ if (bCommon)
+ AdjustRowHeight(nRow,nRow,true);
+
+ EnterData( nCol, nRow, nTab, aString, nullptr, true /*bMatrixExpand*/);
+ }
+ else
+ {
+ for (const auto& rTab : rMark)
+ {
+ ScAddress aPos(nCol, nRow, rTab);
+ rDoc.SetEditText(aPos, rData, rDoc.GetEditPool());
+ }
+
+ if ( bRecord )
+ { // because of ChangeTrack current first
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoEnterData>(pDocSh, ScAddress(nCol,nRow,nTab), aOldValues, aString, std::move(pUndoData)));
+ }
+
+ HideAllCursors();
+
+ AdjustRowHeight(nRow,nRow,true);
+
+ for (const auto& rTab : rMark)
+ pDocSh->PostPaintCell( nCol, nRow, rTab );
+
+ ShowAllCursors();
+
+ pDocSh->UpdateOle(GetViewData());
+
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, rMark, nCol, nRow);
+
+ aModificator.SetDocumentModified();
+ }
+ lcl_PostRepaintCondFormat( rDoc.GetCondFormat( nCol, nRow, nTab ), pDocSh );
+ }
+ else
+ {
+ ErrorMessage(aTester.GetMessageId());
+ PaintArea( nCol, nRow, nCol, nRow ); // possibly the edit-engine is still painted there
+ }
+}
+
+void ScViewFunc::EnterDataAtCursor( const OUString& rString )
+{
+ SCCOL nPosX = GetViewData().GetCurX();
+ SCROW nPosY = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+
+ EnterData( nPosX, nPosY, nTab, rString );
+}
+
+void ScViewFunc::EnterMatrix( const OUString& rString, ::formula::FormulaGrammar::Grammar eGram )
+{
+ ScViewData& rData = GetViewData();
+ const SCCOL nCol = rData.GetCurX();
+ const SCROW nRow = rData.GetCurY();
+ const ScMarkData& rMark = rData.GetMarkData();
+ if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ // nothing marked -> temporarily calculate block
+ // with size of result formula to get the size
+
+ ScDocument& rDoc = rData.GetDocument();
+ SCTAB nTab = rData.GetTabNo();
+ ScFormulaCell aFormCell( rDoc, ScAddress(nCol,nRow,nTab), rString, eGram, ScMatrixMode::Formula );
+
+ SCSIZE nSizeX;
+ SCSIZE nSizeY;
+ aFormCell.GetResultDimensions( nSizeX, nSizeY );
+ if ( nSizeX != 0 && nSizeY != 0 &&
+ nCol+nSizeX-1 <= sal::static_int_cast<SCSIZE>(rDoc.MaxCol()) &&
+ nRow+nSizeY-1 <= sal::static_int_cast<SCSIZE>(rDoc.MaxRow()) )
+ {
+ ScRange aResult( nCol, nRow, nTab,
+ sal::static_int_cast<SCCOL>(nCol+nSizeX-1),
+ sal::static_int_cast<SCROW>(nRow+nSizeY-1), nTab );
+ MarkRange( aResult, false );
+ }
+ }
+
+ ScRange aRange;
+ if (rData.GetSimpleArea(aRange) == SC_MARK_SIMPLE)
+ {
+ ScDocShell* pDocSh = rData.GetDocShell();
+ bool bSuccess = pDocSh->GetDocFunc().EnterMatrix(
+ aRange, &rMark, nullptr, rString, false, false, OUString(), eGram );
+ if (bSuccess)
+ pDocSh->UpdateOle(GetViewData());
+ else
+ PaintArea(nCol, nRow, nCol, nRow); // possibly the edit-engine is still painted there
+ }
+ else
+ ErrorMessage(STR_NOMULTISELECT);
+}
+
+SvtScriptType ScViewFunc::GetSelectionScriptType()
+{
+ SvtScriptType nScript = SvtScriptType::NONE;
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ if ( !rMark.IsMarked() && !rMark.IsMultiMarked() )
+ {
+ // no selection -> cursor
+
+ nScript = rDoc.GetScriptType( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo());
+ }
+ else
+ {
+ ScRangeList aRanges;
+ rMark.FillRangeListWithMarks( &aRanges, false );
+ nScript = rDoc.GetRangeScriptType(aRanges);
+ }
+
+ if (nScript == SvtScriptType::NONE)
+ nScript = ScGlobal::GetDefaultScriptType();
+
+ return nScript;
+}
+
+const ScPatternAttr* ScViewFunc::GetSelectionPattern()
+{
+ // Don't use UnmarkFiltered in slot state functions, for performance reasons.
+ // The displayed state is always that of the whole selection including filtered rows.
+
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ ScDocument& rDoc = GetViewData().GetDocument();
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ {
+ // MarkToMulti is no longer necessary for rDoc.GetSelectionPattern
+ const ScPatternAttr* pAttr = rDoc.GetSelectionPattern( rMark );
+ return pAttr;
+ }
+ else
+ {
+ SCCOL nCol = GetViewData().GetCurX();
+ SCROW nRow = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+
+ ScMarkData aTempMark( rMark ); // copy sheet selection
+ aTempMark.SetMarkArea( ScRange( nCol, nRow, nTab ) );
+ const ScPatternAttr* pAttr = rDoc.GetSelectionPattern( aTempMark );
+ return pAttr;
+ }
+}
+
+void ScViewFunc::GetSelectionFrame(
+ std::shared_ptr<SvxBoxItem>& rLineOuter,
+ std::shared_ptr<SvxBoxInfoItem>& rLineInner )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ {
+ rDoc.GetSelectionFrame( rMark, *rLineOuter, *rLineInner );
+ }
+ else
+ {
+ const ScPatternAttr* pAttrs =
+ rDoc.GetPattern( GetViewData().GetCurX(),
+ GetViewData().GetCurY(),
+ GetViewData().GetTabNo() );
+
+ rLineOuter.reset(pAttrs->GetItem(ATTR_BORDER).Clone());
+ rLineInner.reset(pAttrs->GetItem(ATTR_BORDER_INNER).Clone());
+
+ rLineInner->SetTable(false);
+ rLineInner->SetDist(true);
+ rLineInner->SetMinDist(false);
+ }
+}
+
+// apply attribute - undo OK
+//
+// complete set ( ATTR_STARTINDEX, ATTR_ENDINDEX )
+
+void ScViewFunc::ApplyAttributes( const SfxItemSet* pDialogSet,
+ const SfxItemSet* pOldSet,
+ bool bAdjustBlockHeight)
+{
+ // not editable because of matrix only? attribute OK nonetheless
+ bool bOnlyNotBecauseOfMatrix;
+ if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
+ {
+ ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ ScPatternAttr aOldAttrs(( SfxItemSet(*pOldSet) ));
+ ScPatternAttr aNewAttrs(( SfxItemSet(*pDialogSet) ));
+ aNewAttrs.DeleteUnchanged( &aOldAttrs );
+
+ if ( pDialogSet->GetItemState( ATTR_VALUE_FORMAT ) == SfxItemState::SET )
+ { // don't reset to default SYSTEM GENERAL if not intended
+ sal_uInt32 nOldFormat =
+ pOldSet->Get( ATTR_VALUE_FORMAT ).GetValue();
+ sal_uInt32 nNewFormat =
+ pDialogSet->Get( ATTR_VALUE_FORMAT ).GetValue();
+ if ( nNewFormat != nOldFormat )
+ {
+ SvNumberFormatter* pFormatter =
+ GetViewData().GetDocument().GetFormatTable();
+ const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
+ LanguageType eOldLang =
+ pOldEntry ? pOldEntry->GetLanguage() : LANGUAGE_DONTKNOW;
+ const SvNumberformat* pNewEntry = pFormatter->GetEntry( nNewFormat );
+ LanguageType eNewLang =
+ pNewEntry ? pNewEntry->GetLanguage() : LANGUAGE_DONTKNOW;
+ if ( eNewLang != eOldLang )
+ {
+ aNewAttrs.GetItemSet().Put(
+ SvxLanguageItem( eNewLang, ATTR_LANGUAGE_FORMAT ) );
+
+ // only the language has changed -> do not touch numberformat-attribute
+ sal_uInt32 nNewMod = nNewFormat % SV_COUNTRY_LANGUAGE_OFFSET;
+ if ( nNewMod == ( nOldFormat % SV_COUNTRY_LANGUAGE_OFFSET ) &&
+ nNewMod <= SV_MAX_COUNT_STANDARD_FORMATS )
+ aNewAttrs.GetItemSet().ClearItem( ATTR_VALUE_FORMAT );
+ }
+ }
+ }
+
+ if (pDialogSet->HasItem(ATTR_FONT_LANGUAGE))
+ // font language has changed. Redo the online spelling.
+ ResetAutoSpell();
+
+ const SvxBoxItem& rOldOuter = pOldSet->Get(ATTR_BORDER);
+ const SvxBoxItem& rNewOuter = pDialogSet->Get(ATTR_BORDER);
+ const SvxBoxInfoItem& rOldInner = pOldSet->Get(ATTR_BORDER_INNER);
+ const SvxBoxInfoItem& rNewInner = pDialogSet->Get(ATTR_BORDER_INNER);
+ SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
+ SfxItemPool* pNewPool = rNewSet.GetPool();
+
+ pNewPool->Put(rNewOuter); // don't delete yet
+ pNewPool->Put(rNewInner);
+ rNewSet.ClearItem( ATTR_BORDER );
+ rNewSet.ClearItem( ATTR_BORDER_INNER );
+
+ /*
+ * establish whether border attribute is to be set:
+ * 1. new != old
+ * 2. is one of the borders not-DontCare (since 238.f: IsxxValid())
+ *
+ */
+
+ bool bFrame = (pDialogSet->GetItemState( ATTR_BORDER ) != SfxItemState::DEFAULT)
+ || (pDialogSet->GetItemState( ATTR_BORDER_INNER ) != SfxItemState::DEFAULT);
+
+ if (&rNewOuter == &rOldOuter && &rNewInner == &rOldInner)
+ bFrame = false;
+
+ // this should be intercepted by the pool: ?!??!??
+
+ if (bFrame && rNewOuter == rOldOuter && rNewInner == rOldInner)
+ bFrame = false;
+
+ bFrame = bFrame
+ && ( rNewInner.IsValid(SvxBoxInfoItemValidFlags::LEFT)
+ || rNewInner.IsValid(SvxBoxInfoItemValidFlags::RIGHT)
+ || rNewInner.IsValid(SvxBoxInfoItemValidFlags::TOP)
+ || rNewInner.IsValid(SvxBoxInfoItemValidFlags::BOTTOM)
+ || rNewInner.IsValid(SvxBoxInfoItemValidFlags::HORI)
+ || rNewInner.IsValid(SvxBoxInfoItemValidFlags::VERT) );
+
+ if (!bFrame)
+ ApplySelectionPattern( aNewAttrs ); // standard only
+ else
+ {
+ // if new items are default-items, overwrite the old items:
+
+ bool bDefNewOuter = IsStaticDefaultItem(&rNewOuter);
+ bool bDefNewInner = IsStaticDefaultItem(&rNewInner);
+
+ ApplyPatternLines( aNewAttrs,
+ bDefNewOuter ? rOldOuter : rNewOuter,
+ bDefNewInner ? &rOldInner : &rNewInner );
+ }
+
+ pNewPool->Remove(rNewOuter); // release
+ pNewPool->Remove(rNewInner);
+
+ // adjust height only if needed
+ if (bAdjustBlockHeight)
+ AdjustBlockHeight();
+
+ // CellContentChanged is called in ApplySelectionPattern / ApplyPatternLines
+}
+
+void ScViewFunc::ApplyAttr( const SfxPoolItem& rAttrItem, bool bAdjustBlockHeight )
+{
+ // not editable because of matrix only? attribute OK nonetheless
+ bool bOnlyNotBecauseOfMatrix;
+ if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
+ {
+ ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ ScPatternAttr aNewAttrs(
+ SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END>( *GetViewData().GetDocument().GetPool() ) );
+
+ aNewAttrs.GetItemSet().Put( rAttrItem );
+ // if justify is set (with Buttons), always indentation 0
+ if ( rAttrItem.Which() == ATTR_HOR_JUSTIFY )
+ aNewAttrs.GetItemSet().Put( ScIndentItem( 0 ) );
+ ApplySelectionPattern( aNewAttrs );
+
+ // Prevent useless compute
+ if (bAdjustBlockHeight)
+ AdjustBlockHeight();
+
+ // CellContentChanged is called in ApplySelectionPattern
+}
+
+// patterns and borders
+
+void ScViewFunc::ApplyPatternLines( const ScPatternAttr& rAttr, const SvxBoxItem& rNewOuter,
+ const SvxBoxInfoItem* pNewInner )
+{
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScMarkData aFuncMark( GetViewData().GetMarkData() ); // local copy for UnmarkFiltered
+ ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ bool bRemoveAdjCellBorder = rNewOuter.IsRemoveAdjacentCellBorder();
+ ScRange aMarkRange, aMarkRangeWithEnvelope;
+ aFuncMark.MarkToSimple();
+ bool bMulti = aFuncMark.IsMultiMarked();
+ if (bMulti)
+ aMarkRange = aFuncMark.GetMultiMarkArea();
+ else if (aFuncMark.IsMarked())
+ aMarkRange = aFuncMark.GetMarkArea();
+ else
+ {
+ aMarkRange = ScRange( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ DoneBlockMode();
+ InitOwnBlockMode( aMarkRange );
+ aFuncMark.SetMarkArea(aMarkRange);
+ MarkDataChanged();
+ }
+ if( bRemoveAdjCellBorder )
+ aFuncMark.GetSelectionCover( aMarkRangeWithEnvelope );
+ else
+ aMarkRangeWithEnvelope = aMarkRange;
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+
+ ScDocShellModificator aModificator( *pDocSh );
+
+ if (bRecord)
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ SCTAB nStartTab = aMarkRange.aStart.Tab();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ bool bCopyOnlyMarked = false;
+ if( !bRemoveAdjCellBorder )
+ bCopyOnlyMarked = bMulti;
+ pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab );
+ for (const auto& rTab : aFuncMark)
+ if (rTab != nStartTab)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+
+ ScRange aCopyRange = aMarkRangeWithEnvelope;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, bCopyOnlyMarked, *pUndoDoc, &aFuncMark );
+
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoSelectionAttr>(
+ pDocSh, aFuncMark,
+ aMarkRange.aStart.Col(), aMarkRange.aStart.Row(), aMarkRange.aStart.Tab(),
+ aMarkRange.aEnd.Col(), aMarkRange.aEnd.Row(), aMarkRange.aEnd.Tab(),
+ std::move(pUndoDoc), bCopyOnlyMarked, &rAttr, &rNewOuter, pNewInner, &aMarkRangeWithEnvelope ) );
+ }
+
+ sal_uInt16 nExt = SC_PF_TESTMERGE;
+ pDocSh->UpdatePaintExt( nExt, aMarkRangeWithEnvelope ); // content before the change
+
+ rDoc.ApplySelectionFrame(aFuncMark, rNewOuter, pNewInner);
+
+ pDocSh->UpdatePaintExt( nExt, aMarkRangeWithEnvelope ); // content after the change
+
+ aFuncMark.MarkToMulti();
+ rDoc.ApplySelectionPattern( rAttr, aFuncMark );
+
+ pDocSh->PostPaint( aMarkRange, PaintPartFlags::Grid, nExt );
+ pDocSh->UpdateOle(GetViewData());
+ aModificator.SetDocumentModified();
+ CellContentChanged();
+
+ StartFormatArea();
+}
+
+// pattern only
+
+void ScViewFunc::ApplySelectionPattern( const ScPatternAttr& rAttr, bool bCursorOnly )
+{
+ ScViewData& rViewData = GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData aFuncMark( rViewData.GetMarkData() ); // local copy for UnmarkFiltered
+ ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
+
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ // State from old ItemSet doesn't matter for paint flags, as any change will be
+ // from SfxItemState::SET in the new ItemSet (default is ignored in ApplyPattern).
+ // New alignment is checked (check in PostPaint isn't enough) in case a right
+ // alignment is changed to left.
+ const SfxItemSet& rNewSet = rAttr.GetItemSet();
+ bool bSetLines = rNewSet.GetItemState( ATTR_BORDER ) == SfxItemState::SET ||
+ rNewSet.GetItemState( ATTR_SHADOW ) == SfxItemState::SET;
+ bool bSetAlign = rNewSet.GetItemState( ATTR_HOR_JUSTIFY ) == SfxItemState::SET;
+
+ sal_uInt16 nExtFlags = 0;
+ if ( bSetLines )
+ nExtFlags |= SC_PF_LINES;
+ if ( bSetAlign )
+ nExtFlags |= SC_PF_WHOLEROWS;
+
+ ScDocShellModificator aModificator( *pDocSh );
+
+ bool bMulti = aFuncMark.IsMultiMarked();
+ aFuncMark.MarkToMulti();
+ bool bOnlyTab = (!aFuncMark.IsMultiMarked() && !bCursorOnly && aFuncMark.GetSelectCount() > 1);
+ if (bOnlyTab)
+ {
+ SCCOL nCol = rViewData.GetCurX();
+ SCROW nRow = rViewData.GetCurY();
+ SCTAB nTab = rViewData.GetTabNo();
+ aFuncMark.SetMarkArea(ScRange(nCol,nRow,nTab));
+ aFuncMark.MarkToMulti();
+ }
+
+ ScRangeList aChangeRanges;
+
+ if (aFuncMark.IsMultiMarked() && !bCursorOnly)
+ {
+ const ScRange& aMarkRange = aFuncMark.GetMultiMarkArea();
+ SCTAB nTabCount = rDoc.GetTableCount();
+ for (const auto& rTab : aFuncMark)
+ {
+ ScRange aChangeRange( aMarkRange );
+ aChangeRange.aStart.SetTab( rTab );
+ aChangeRange.aEnd.SetTab( rTab );
+ aChangeRanges.push_back( aChangeRange );
+ }
+
+ SCCOL nStartCol = aMarkRange.aStart.Col();
+ SCROW nStartRow = aMarkRange.aStart.Row();
+ SCTAB nStartTab = aMarkRange.aStart.Tab();
+ SCCOL nEndCol = aMarkRange.aEnd.Col();
+ SCROW nEndRow = aMarkRange.aEnd.Row();
+ SCTAB nEndTab = aMarkRange.aEnd.Tab();
+
+ ScEditDataArray* pEditDataArray = nullptr;
+ if (bRecord)
+ {
+ ScRange aCopyRange = aMarkRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nStartTab, nStartTab );
+ for (const auto& rTab : aFuncMark)
+ if (rTab != nStartTab)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+ rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, bMulti, *pUndoDoc, &aFuncMark );
+
+ aFuncMark.MarkToMulti();
+
+ ScUndoSelectionAttr* pUndoAttr = new ScUndoSelectionAttr(
+ pDocSh, aFuncMark, nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab, std::move(pUndoDoc), bMulti, &rAttr );
+ pDocSh->GetUndoManager()->AddUndoAction(std::unique_ptr<ScUndoSelectionAttr>(pUndoAttr));
+ pEditDataArray = pUndoAttr->GetDataArray();
+ }
+
+ rDoc.ApplySelectionPattern( rAttr, aFuncMark, pEditDataArray );
+
+ pDocSh->PostPaint( nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab,
+ PaintPartFlags::Grid, nExtFlags | SC_PF_TESTMERGE );
+ pDocSh->UpdateOle(GetViewData());
+ aModificator.SetDocumentModified();
+ CellContentChanged();
+ }
+ else // single cell - simpler undo
+ {
+ SCCOL nCol = rViewData.GetCurX();
+ SCROW nRow = rViewData.GetCurY();
+ SCTAB nTab = rViewData.GetTabNo();
+
+ std::unique_ptr<EditTextObject> pOldEditData;
+ std::unique_ptr<EditTextObject> pNewEditData;
+ ScAddress aPos(nCol, nRow, nTab);
+ ScRefCellValue aCell(rDoc, aPos);
+ if (aCell.meType == CELLTYPE_EDIT)
+ {
+ const EditTextObject* pEditObj = aCell.mpEditText;
+ pOldEditData = pEditObj->Clone();
+ rDoc.RemoveEditTextCharAttribs(aPos, rAttr);
+ pEditObj = rDoc.GetEditText(aPos);
+ pNewEditData = pEditObj->Clone();
+ }
+
+ aChangeRanges.push_back(aPos);
+ std::optional<ScPatternAttr> pOldPat(*rDoc.GetPattern( nCol, nRow, nTab ));
+
+ rDoc.ApplyPattern( nCol, nRow, nTab, rAttr );
+
+ const ScPatternAttr* pNewPat = rDoc.GetPattern( nCol, nRow, nTab );
+
+ if (bRecord)
+ {
+ std::unique_ptr<ScUndoCursorAttr> pUndo(new ScUndoCursorAttr(
+ pDocSh, nCol, nRow, nTab, &*pOldPat, pNewPat, &rAttr ));
+ pUndo->SetEditData(std::move(pOldEditData), std::move(pNewEditData));
+ pDocSh->GetUndoManager()->AddUndoAction(std::move(pUndo));
+ }
+ pOldPat.reset(); // is copied in undo (Pool)
+
+ pDocSh->PostPaint( nCol,nRow,nTab, nCol,nRow,nTab, PaintPartFlags::Grid, nExtFlags | SC_PF_TESTMERGE );
+ pDocSh->UpdateOle(GetViewData());
+ aModificator.SetDocumentModified();
+ CellContentChanged();
+ }
+
+ ScModelObj* pModelObj = HelperNotifyChanges::getMustPropagateChangesModel(*pDocSh);
+ if (pModelObj)
+ {
+ css::uno::Sequence< css::beans::PropertyValue > aProperties;
+ sal_Int32 nCount = 0;
+ const SfxItemPropertyMap& rMap = ScCellObj::GetCellPropertyMap();
+ for ( sal_uInt16 nWhich = ATTR_PATTERN_START; nWhich <= ATTR_PATTERN_END; ++nWhich )
+ {
+ const SfxPoolItem* pItem = nullptr;
+ if ( rNewSet.GetItemState( nWhich, true, &pItem ) == SfxItemState::SET && pItem )
+ {
+ for ( const auto pEntry : rMap.getPropertyEntries())
+ {
+ if ( pEntry->nWID == nWhich )
+ {
+ css::uno::Any aVal;
+ pItem->QueryValue( aVal, pEntry->nMemberId );
+ aProperties.realloc( nCount + 1 );
+ auto pProperties = aProperties.getArray();
+ pProperties[ nCount ].Name = pEntry->aName;
+ pProperties[ nCount ].Value = aVal;
+ ++nCount;
+ }
+ }
+ }
+ }
+ HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, "attribute", aProperties);
+ }
+
+ StartFormatArea();
+}
+
+void ScViewFunc::ApplyUserItemSet( const SfxItemSet& rItemSet )
+{
+ // ItemSet from UI, may have different pool
+
+ bool bOnlyNotBecauseOfMatrix;
+ if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
+ {
+ ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ ScPatternAttr aNewAttrs( GetViewData().GetDocument().GetPool() );
+ SfxItemSet& rNewSet = aNewAttrs.GetItemSet();
+ rNewSet.Put( rItemSet, false );
+ ApplySelectionPattern( aNewAttrs );
+
+ AdjustBlockHeight();
+}
+
+const SfxStyleSheet* ScViewFunc::GetStyleSheetFromMarked()
+{
+ // Don't use UnmarkFiltered in slot state functions, for performance reasons.
+ // The displayed state is always that of the whole selection including filtered rows.
+
+ const ScStyleSheet* pSheet = nullptr;
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScMarkData& rMark = rViewData.GetMarkData();
+
+ if ( rMark.IsMarked() || rMark.IsMultiMarked() )
+ pSheet = rDoc.GetSelectionStyle( rMark ); // MarkToMulti isn't necessary
+ else
+ pSheet = rDoc.GetStyle( rViewData.GetCurX(),
+ rViewData.GetCurY(),
+ rViewData.GetTabNo() );
+
+ return pSheet;
+}
+
+void ScViewFunc::SetStyleSheetToMarked( const SfxStyleSheet* pStyleSheet )
+{
+ // not editable because of matrix only? attribute OK nonetheless
+ bool bOnlyNotBecauseOfMatrix;
+ if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
+ {
+ ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ if ( !pStyleSheet) return;
+
+ ScViewData& rViewData = GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData aFuncMark( rViewData.GetMarkData() ); // local copy for UnmarkFiltered
+ ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
+ SCTAB nTabCount = rDoc.GetTableCount();
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScDocShellModificator aModificator( *pDocSh );
+
+ if ( aFuncMark.IsMarked() || aFuncMark.IsMultiMarked() )
+ {
+ aFuncMark.MarkToMulti();
+ const ScRange& aMarkRange = aFuncMark.GetMultiMarkArea();
+
+ if ( bRecord )
+ {
+ SCTAB nTab = rViewData.GetTabNo();
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ for (const auto& rTab : aFuncMark)
+ if (rTab != nTab)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+
+ ScRange aCopyRange = aMarkRange;
+ aCopyRange.aStart.SetTab(0);
+ aCopyRange.aEnd.SetTab(nTabCount-1);
+ rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, true, *pUndoDoc, &aFuncMark );
+ aFuncMark.MarkToMulti();
+
+ OUString aName = pStyleSheet->GetName();
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoSelectionStyle>( pDocSh, aFuncMark, aMarkRange, aName, std::move(pUndoDoc) ) );
+ }
+
+ rDoc.ApplySelectionStyle( static_cast<const ScStyleSheet&>(*pStyleSheet), aFuncMark );
+
+ if (!AdjustBlockHeight())
+ rViewData.GetDocShell()->PostPaint( aMarkRange, PaintPartFlags::Grid );
+
+ aFuncMark.MarkToSimple();
+ }
+ else
+ {
+ SCCOL nCol = rViewData.GetCurX();
+ SCROW nRow = rViewData.GetCurY();
+ SCTAB nTab = rViewData.GetTabNo();
+
+ if ( bRecord )
+ {
+ ScDocumentUniquePtr pUndoDoc(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab );
+ for (const auto& rTab : aFuncMark)
+ if (rTab != nTab)
+ pUndoDoc->AddUndoTab( rTab, rTab );
+
+ ScRange aCopyRange( nCol, nRow, 0, nCol, nRow, nTabCount-1 );
+ rDoc.CopyToDocument( aCopyRange, InsertDeleteFlags::ATTRIB, false, *pUndoDoc );
+
+ ScRange aMarkRange ( nCol, nRow, nTab );
+ ScMarkData aUndoMark = aFuncMark;
+ aUndoMark.SetMultiMarkArea( aMarkRange );
+
+ OUString aName = pStyleSheet->GetName();
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoSelectionStyle>( pDocSh, aUndoMark, aMarkRange, aName, std::move(pUndoDoc) ) );
+ }
+
+ for (const auto& rTab : aFuncMark)
+ rDoc.ApplyStyle( nCol, nRow, rTab, static_cast<const ScStyleSheet&>(*pStyleSheet) );
+
+ if (!AdjustBlockHeight())
+ rViewData.GetDocShell()->PostPaintCell( nCol, nRow, nTab );
+
+ }
+
+ aModificator.SetDocumentModified();
+
+ StartFormatArea();
+}
+
+void ScViewFunc::RemoveStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet )
+{
+ if ( !pStyleSheet) return;
+
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+
+ ScDocShellModificator aModificator( *pDocSh );
+
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ pVirtDev->SetMapMode(MapMode(MapUnit::MapPixel));
+ rDoc.StyleSheetChanged( pStyleSheet, true, pVirtDev,
+ rViewData.GetPPTX(),
+ rViewData.GetPPTY(),
+ rViewData.GetZoomX(),
+ rViewData.GetZoomY() );
+
+ pDocSh->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+ aModificator.SetDocumentModified();
+
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if (pHdl)
+ pHdl->ForgetLastPattern();
+}
+
+void ScViewFunc::UpdateStyleSheetInUse( const SfxStyleSheetBase* pStyleSheet )
+{
+ if ( !pStyleSheet) return;
+
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+
+ ScDocShellModificator aModificator( *pDocSh );
+
+ ScopedVclPtrInstance< VirtualDevice > pVirtDev;
+ pVirtDev->SetMapMode(MapMode(MapUnit::MapPixel));
+ rDoc.StyleSheetChanged( pStyleSheet, false, pVirtDev,
+ rViewData.GetPPTX(),
+ rViewData.GetPPTY(),
+ rViewData.GetZoomX(),
+ rViewData.GetZoomY() );
+
+ pDocSh->PostPaint( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB, PaintPartFlags::Grid|PaintPartFlags::Left );
+ aModificator.SetDocumentModified();
+
+ ScInputHandler* pHdl = SC_MOD()->GetInputHdl();
+ if (pHdl)
+ pHdl->ForgetLastPattern();
+}
+
+
+void ScViewFunc::OnLOKInsertDeleteColumn(SCCOL nStartCol, tools::Long nOffset)
+{
+ if (!comphelper::LibreOfficeKit::isActive() || nOffset == 0)
+ return;
+
+ SCTAB nCurrentTabIndex = GetViewData().GetTabNo();
+ SfxViewShell* pCurrentViewShell = GetViewData().GetViewShell();
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pTabViewShell && pTabViewShell->GetDocId() == pCurrentViewShell->GetDocId())
+ {
+ if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKWidthHelper(nCurrentTabIndex))
+ pPosHelper->invalidateByIndex(nStartCol);
+
+ // if we remove a column the cursor position and the current selection
+ // in other views could need to be moved on the left by one column.
+ if (pTabViewShell != this)
+ {
+ if (pTabViewShell->getPart() == nCurrentTabIndex)
+ {
+ SCCOL nX = pTabViewShell->GetViewData().GetCurX();
+ if (nX > nStartCol || (nX == nStartCol && nOffset > 0))
+ {
+ ScInputHandler* pInputHdl = pTabViewShell->GetInputHandler();
+ SCROW nY = pTabViewShell->GetViewData().GetCurY();
+ pTabViewShell->SetCursor(nX + nOffset, nY);
+ if (pInputHdl && pInputHdl->IsInputMode())
+ {
+ pInputHdl->SetModified();
+ }
+ }
+
+ ScMarkData aMultiMark( pTabViewShell->GetViewData().GetMarkData() );
+ aMultiMark.SetMarking( false );
+ aMultiMark.MarkToMulti();
+ if (aMultiMark.IsMultiMarked())
+ {
+ aMultiMark.ShiftCols(pTabViewShell->GetViewData().GetDocument(), nStartCol, nOffset);
+ pTabViewShell->SetMarkData(aMultiMark);
+ }
+ }
+ else
+ {
+ SCROW nX = pTabViewShell->GetViewData().GetCurXForTab(nCurrentTabIndex);
+ if (nX > nStartCol || (nX == nStartCol && nOffset > 0))
+ {
+ pTabViewShell->GetViewData().SetCurXForTab(nX + nOffset, nCurrentTabIndex);
+ }
+ }
+ }
+ }
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
+void ScViewFunc::OnLOKInsertDeleteRow(SCROW nStartRow, tools::Long nOffset)
+{
+ if (!comphelper::LibreOfficeKit::isActive() || nOffset == 0)
+ return;
+
+ SCTAB nCurrentTabIndex = GetViewData().GetTabNo();
+ SfxViewShell* pCurrentViewShell = GetViewData().GetViewShell();
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pTabViewShell && pTabViewShell->GetDocId() == pCurrentViewShell->GetDocId())
+ {
+ if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKHeightHelper(nCurrentTabIndex))
+ pPosHelper->invalidateByIndex(nStartRow);
+
+ // if we remove a row the cursor position and the current selection
+ // in other views could need to be moved up by one row.
+ if (pTabViewShell != this)
+ {
+ if (pTabViewShell->getPart() == nCurrentTabIndex)
+ {
+ SCROW nY = pTabViewShell->GetViewData().GetCurY();
+ if (nY > nStartRow || (nY == nStartRow && nOffset > 0))
+ {
+ ScInputHandler* pInputHdl = pTabViewShell->GetInputHandler();
+ SCCOL nX = pTabViewShell->GetViewData().GetCurX();
+ pTabViewShell->SetCursor(nX, nY + nOffset);
+ if (pInputHdl && pInputHdl->IsInputMode())
+ {
+ pInputHdl->SetModified();
+ }
+ }
+
+ ScMarkData aMultiMark( pTabViewShell->GetViewData().GetMarkData() );
+ aMultiMark.SetMarking( false );
+ aMultiMark.MarkToMulti();
+ if (aMultiMark.IsMultiMarked())
+ {
+ aMultiMark.ShiftRows(pTabViewShell->GetViewData().GetDocument(), nStartRow, nOffset);
+ pTabViewShell->SetMarkData(aMultiMark);
+ }
+ }
+ else
+ {
+ SCROW nY = pTabViewShell->GetViewData().GetCurYForTab(nCurrentTabIndex);
+ if (nY > nStartRow || (nY == nStartRow && nOffset > 0))
+ {
+ pTabViewShell->GetViewData().SetCurYForTab(nY + nOffset, nCurrentTabIndex);
+ }
+ }
+ }
+ }
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
+void ScViewFunc::OnLOKSetWidthOrHeight(SCCOLROW nStart, bool bWidth)
+{
+ if (!comphelper::LibreOfficeKit::isActive())
+ return;
+
+ SCTAB nCurTab = GetViewData().GetTabNo();
+ SfxViewShell* pCurrentViewShell = GetViewData().GetViewShell();
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+ while (pViewShell)
+ {
+ ScTabViewShell* pTabViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pTabViewShell && pTabViewShell->GetDocId() == pCurrentViewShell->GetDocId())
+ {
+ if (bWidth)
+ {
+ if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKWidthHelper(nCurTab))
+ pPosHelper->invalidateByIndex(nStart);
+ }
+ else
+ {
+ if (ScPositionHelper* pPosHelper = pTabViewShell->GetViewData().GetLOKHeightHelper(nCurTab))
+ pPosHelper->invalidateByIndex(nStart);
+ }
+ }
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
+// insert cells - undo OK
+
+bool ScViewFunc::InsertCells( InsCellCmd eCmd, bool bRecord, bool bPartOfPaste )
+{
+ ScRange aRange;
+ ScMarkType eMarkType = GetViewData().GetSimpleArea(aRange);
+ if (eMarkType == SC_MARK_SIMPLE || eMarkType == SC_MARK_SIMPLE_FILTERED)
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+ bool bSuccess = pDocSh->GetDocFunc().InsertCells( aRange, &rMark, eCmd, bRecord, false, bPartOfPaste );
+ if (bSuccess)
+ {
+ ResetAutoSpellForContentChange();
+ bool bInsertCols = ( eCmd == INS_INSCOLS_BEFORE || eCmd == INS_INSCOLS_AFTER);
+ bool bInsertRows = ( eCmd == INS_INSROWS_BEFORE || eCmd == INS_INSROWS_AFTER );
+
+ pDocSh->UpdateOle(GetViewData());
+ CellContentChanged();
+
+ if ( bInsertCols || bInsertRows )
+ {
+ OUString aOperation = bInsertRows ?
+ OUString("insert-rows"):
+ OUString("insert-columns");
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, aRange, aOperation);
+ }
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ if (bInsertCols)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), COLUMN_HEADER, GetViewData().GetTabNo());
+
+ if (bInsertRows)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNo());
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
+ bInsertCols, bInsertRows, true /* bSizes*/,
+ true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, GetViewData().GetTabNo());
+ }
+ }
+ OUString aStartAddress = aRange.aStart.GetColRowString();
+ OUString aEndAddress = aRange.aEnd.GetColRowString();
+ collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, "INSERT_CELLS");
+ return bSuccess;
+ }
+ else
+ {
+ ErrorMessage(STR_NOMULTISELECT);
+ return false;
+ }
+}
+
+// delete cells - undo OK
+
+void ScViewFunc::DeleteCells( DelCellCmd eCmd )
+{
+ ScRange aRange;
+ if ( GetViewData().GetSimpleArea( aRange ) == SC_MARK_SIMPLE )
+ {
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ const ScMarkData& rMark = GetViewData().GetMarkData();
+
+#if HAVE_FEATURE_MULTIUSER_ENVIRONMENT
+ // #i94841# [Collaboration] if deleting rows is rejected, the content is sometimes wrong
+ if ( pDocSh->IsDocShared() && ( eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::Cols ) )
+ {
+ ScRange aDelRange( aRange.aStart );
+ SCCOLROW nCount = 0;
+ if ( eCmd == DelCellCmd::Rows )
+ {
+ nCount = sal::static_int_cast< SCCOLROW >( aRange.aEnd.Row() - aRange.aStart.Row() + 1 );
+ }
+ else
+ {
+ nCount = sal::static_int_cast< SCCOLROW >( aRange.aEnd.Col() - aRange.aStart.Col() + 1 );
+ }
+ while ( nCount > 0 )
+ {
+ pDocSh->GetDocFunc().DeleteCells( aDelRange, &rMark, eCmd, false );
+ --nCount;
+ }
+ }
+ else
+#endif
+ {
+ pDocSh->GetDocFunc().DeleteCells( aRange, &rMark, eCmd, false );
+ }
+
+ ResetAutoSpellForContentChange();
+ pDocSh->UpdateOle(GetViewData());
+ CellContentChanged();
+
+ if ( eCmd == DelCellCmd::Rows || eCmd == DelCellCmd::Cols )
+ {
+ OUString aOperation = ( eCmd == DelCellCmd::Rows) ?
+ OUString("delete-rows"):
+ OUString("delete-columns");
+ HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, aRange, aOperation);
+ }
+
+ // put cursor directly behind deleted range
+ SCCOL nCurX = GetViewData().GetCurX();
+ SCROW nCurY = GetViewData().GetCurY();
+ if ( eCmd==DelCellCmd::CellsLeft || eCmd==DelCellCmd::Cols )
+ nCurX = aRange.aStart.Col();
+ else
+ nCurY = aRange.aStart.Row();
+ SetCursor( nCurX, nCurY );
+
+ if (comphelper::LibreOfficeKit::isActive())
+ {
+ bool bColsDeleted = (eCmd == DelCellCmd::Cols);
+ bool bRowsDeleted = (eCmd == DelCellCmd::Rows);
+ if (bColsDeleted)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), COLUMN_HEADER, GetViewData().GetTabNo());
+
+ if (bRowsDeleted)
+ ScTabViewShell::notifyAllViewsHeaderInvalidation(GetViewData().GetViewShell(), ROW_HEADER, GetViewData().GetTabNo());
+
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
+ bColsDeleted, bRowsDeleted, true /* bSizes*/,
+ true /* bHidden */, true /* bFiltered */,
+ true /* bGroups */, GetViewData().GetTabNo());
+ }
+ }
+ else
+ {
+ if (eCmd == DelCellCmd::Cols)
+ DeleteMulti( false );
+ else if (eCmd == DelCellCmd::Rows)
+ DeleteMulti( true );
+ else
+ ErrorMessage(STR_NOMULTISELECT);
+ }
+
+ OUString aStartAddress = aRange.aStart.GetColRowString();
+ OUString aEndAddress = aRange.aEnd.GetColRowString();
+ collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, "DELETE_CELLS");
+
+ Unmark();
+}
+
+void ScViewFunc::DeleteMulti( bool bRows )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocShellModificator aModificator( *pDocSh );
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScMarkData aFuncMark( GetViewData().GetMarkData() ); // local copy for UnmarkFiltered
+ ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
+
+ bool bRecord = true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ std::vector<sc::ColRowSpan> aSpans;
+ if (bRows)
+ aSpans = aFuncMark.GetMarkedRowSpans();
+ else
+ aSpans = aFuncMark.GetMarkedColSpans();
+
+ if (aSpans.empty())
+ {
+ SCCOLROW nCurPos = bRows ? GetViewData().GetCurY() : GetViewData().GetCurX();
+ aSpans.emplace_back(nCurPos, nCurPos);
+ }
+
+ // test if allowed
+
+ TranslateId pErrorId;
+ bool bNeedRefresh = false;
+ for (size_t i = 0, n = aSpans.size(); i < n && !pErrorId; ++i)
+ {
+ SCCOLROW nStart = aSpans[i].mnStart;
+ SCCOLROW nEnd = aSpans[i].mnEnd;
+
+ SCCOL nStartCol, nEndCol;
+ SCROW nStartRow, nEndRow;
+ if ( bRows )
+ {
+ nStartCol = 0;
+ nEndCol = rDoc.MaxCol();
+ nStartRow = static_cast<SCROW>(nStart);
+ nEndRow = static_cast<SCROW>(nEnd);
+ }
+ else
+ {
+ nStartCol = static_cast<SCCOL>(nStart);
+ nEndCol = static_cast<SCCOL>(nEnd);
+ nStartRow = 0;
+ nEndRow = rDoc.MaxRow();
+ }
+
+ // cell protection (only needed for first range, as all following cells are moved)
+ if (i == 0)
+ {
+ // test to the end of the sheet
+ ScEditableTester aTester( rDoc, nTab, nStartCol, nStartRow, rDoc.MaxCol(), rDoc.MaxRow() );
+ if (!aTester.IsEditable())
+ pErrorId = aTester.GetMessageId();
+ }
+
+ // merged cells
+ SCCOL nMergeStartX = nStartCol;
+ SCROW nMergeStartY = nStartRow;
+ SCCOL nMergeEndX = nEndCol;
+ SCROW nMergeEndY = nEndRow;
+ rDoc.ExtendMerge( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
+ rDoc.ExtendOverlapped( nMergeStartX, nMergeStartY, nMergeEndX, nMergeEndY, nTab );
+
+ if ( nMergeStartX != nStartCol || nMergeStartY != nStartRow )
+ {
+ // Disallow deleting parts of a merged cell.
+ // Deleting the start is allowed (merge is removed), so the end doesn't have to be checked.
+
+ pErrorId = STR_MSSG_DELETECELLS_0;
+ }
+ if ( nMergeEndX != nEndCol || nMergeEndY != nEndRow )
+ {
+ // detect if the start of a merged cell is deleted, so the merge flags can be refreshed
+
+ bNeedRefresh = true;
+ }
+ }
+
+ if (pErrorId)
+ {
+ ErrorMessage(pErrorId);
+ return;
+ }
+
+ // proceed
+
+ weld::WaitObject aWait(GetViewData().GetDialogParent()); // important for TrackFormulas in UpdateReference
+
+ ResetAutoSpellForContentChange();
+
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScRefUndoData> pUndoData;
+ if (bRecord)
+ {
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, !bRows, bRows ); // row height
+
+ for (const sc::ColRowSpan & rSpan : aSpans)
+ {
+ SCCOLROW nStart = rSpan.mnStart;
+ SCCOLROW nEnd = rSpan.mnEnd;
+ if (bRows)
+ rDoc.CopyToDocument( 0,nStart,nTab, rDoc.MaxCol(), nEnd,nTab, InsertDeleteFlags::ALL,false,*pUndoDoc );
+ else
+ rDoc.CopyToDocument( static_cast<SCCOL>(nStart),0,nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab,
+ InsertDeleteFlags::ALL,false,*pUndoDoc );
+ }
+
+ // all Formulas because of references
+ SCTAB nTabCount = rDoc.GetTableCount();
+ pUndoDoc->AddUndoTab( 0, nTabCount-1 );
+ rDoc.CopyToDocument( 0,0,0, rDoc.MaxCol(), rDoc.MaxRow(), MAXTAB, InsertDeleteFlags::FORMULA,false,*pUndoDoc );
+
+ pUndoData.reset(new ScRefUndoData( &rDoc ));
+
+ rDoc.BeginDrawUndo();
+ }
+
+ std::vector<sc::ColRowSpan>::const_reverse_iterator ri = aSpans.rbegin(), riEnd = aSpans.rend();
+ aFuncMark.SelectOneTable(nTab);
+ for (; ri != riEnd; ++ri)
+ {
+ SCCOLROW nEnd = ri->mnEnd;
+ SCCOLROW nStart = ri->mnStart;
+
+ if (bRows)
+ {
+ rDoc.DeleteObjectsInArea(0, nStart, rDoc.MaxCol(), nEnd, aFuncMark, true);
+ rDoc.DeleteRow(0, nTab, rDoc.MaxCol(), nTab, nStart, static_cast<SCSIZE>(nEnd - nStart + 1));
+ }
+ else
+ {
+ rDoc.DeleteObjectsInArea(nStart, 0, nEnd, rDoc.MaxRow(), aFuncMark, true);
+ rDoc.DeleteCol(0, nTab, rDoc.MaxRow(), nTab, static_cast<SCCOL>(nStart), static_cast<SCSIZE>(nEnd - nStart + 1));
+ }
+ }
+
+ if (bNeedRefresh)
+ {
+ SCCOLROW nFirstStart = aSpans[0].mnStart;
+ SCCOL nStartCol = bRows ? 0 : static_cast<SCCOL>(nFirstStart);
+ SCROW nStartRow = bRows ? static_cast<SCROW>(nFirstStart) : 0;
+ SCCOL nEndCol = rDoc.MaxCol();
+ SCROW nEndRow = rDoc.MaxRow();
+
+ rDoc.RemoveFlagsTab( nStartCol, nStartRow, nEndCol, nEndRow, nTab, ScMF::Hor | ScMF::Ver );
+ rDoc.ExtendMerge( nStartCol, nStartRow, nEndCol, nEndRow, nTab, true );
+ }
+
+ if (bRecord)
+ {
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoDeleteMulti>(
+ pDocSh, bRows, bNeedRefresh, nTab, std::vector(aSpans), std::move(pUndoDoc), std::move(pUndoData)));
+ }
+
+ if (!AdjustRowHeight(0, rDoc.MaxRow(), true))
+ {
+ if (bRows)
+ {
+ pDocSh->PostPaint(
+ 0, aSpans[0].mnStart, nTab,
+ rDoc.MaxCol(), rDoc.MaxRow(), nTab, (PaintPartFlags::Grid | PaintPartFlags::Left));
+ }
+ else
+ {
+ pDocSh->PostPaint(
+ static_cast<SCCOL>(aSpans[0].mnStart), 0, nTab,
+ rDoc.MaxCol(), rDoc.MaxRow(), nTab, (PaintPartFlags::Grid | PaintPartFlags::Top));
+ }
+ }
+
+ aModificator.SetDocumentModified();
+
+ CellContentChanged();
+
+ // put cursor directly behind the first deleted range
+ SCCOL nCurX = GetViewData().GetCurX();
+ SCROW nCurY = GetViewData().GetCurY();
+ if ( bRows )
+ nCurY = aSpans[0].mnStart;
+ else
+ nCurX = static_cast<SCCOL>(aSpans[0].mnStart);
+ SetCursor( nCurX, nCurY );
+
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreaLinksChanged ) );
+}
+
+// delete contents
+
+void ScViewFunc::DeleteContents( InsertDeleteFlags nFlags )
+{
+ ScViewData& rViewData = GetViewData();
+ rViewData.SetPasteMode( ScPasteFlags::NONE );
+ rViewData.GetViewShell()->UpdateCopySourceOverlay();
+
+ // not editable because of matrix only? attribute OK nonetheless
+ bool bOnlyNotBecauseOfMatrix;
+ bool bEditable = SelectionEditable( &bOnlyNotBecauseOfMatrix );
+ if ( !bEditable )
+ {
+ if ( !(bOnlyNotBecauseOfMatrix &&
+ ((nFlags & (InsertDeleteFlags::ATTRIB | InsertDeleteFlags::EDITATTR)) == nFlags)) )
+ {
+ ErrorMessage(bOnlyNotBecauseOfMatrix ? STR_MATRIXFRAGMENTERR : STR_PROTECTIONERR);
+ return;
+ }
+ }
+
+ ScRange aMarkRange;
+ bool bSimple = false;
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScMarkData aFuncMark( GetViewData().GetMarkData() ); // local copy for UnmarkFiltered
+ ScViewUtil::UnmarkFiltered( aFuncMark, rDoc );
+
+ bool bRecord =true;
+ if (!rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ if ( !aFuncMark.IsMarked() && !aFuncMark.IsMultiMarked() )
+ {
+ aMarkRange.aStart.SetCol(GetViewData().GetCurX());
+ aMarkRange.aStart.SetRow(GetViewData().GetCurY());
+ aMarkRange.aStart.SetTab(GetViewData().GetTabNo());
+ aMarkRange.aEnd = aMarkRange.aStart;
+ if ( rDoc.HasAttrib( aMarkRange, HasAttrFlags::Merged ) )
+ {
+ aFuncMark.SetMarkArea( aMarkRange );
+ }
+ else
+ bSimple = true;
+ }
+
+ HideAllCursors(); // for if summary is cancelled
+
+ ScDocFunc& rDocFunc = pDocSh->GetDocFunc();
+
+ // Can we really be sure that we can pass the bApi parameter as false to DeleteCell() and
+ // DeleteContents() here? (Meaning that this is interactive use.) Is this never invoked from
+ // scripting and whatnot?
+ if (bSimple)
+ rDocFunc.DeleteCell(aMarkRange.aStart, aFuncMark, nFlags, bRecord, /*bApi=*/ false);
+ else
+ rDocFunc.DeleteContents(aFuncMark, nFlags, bRecord, /*bApi=*/ false);
+
+ pDocSh->UpdateOle(GetViewData());
+
+ if (ScModelObj *pModelObj = HelperNotifyChanges::getMustPropagateChangesModel(*pDocSh))
+ {
+ ScRangeList aChangeRanges;
+ if ( bSimple )
+ {
+ aChangeRanges.push_back( aMarkRange );
+ }
+ else
+ {
+ aFuncMark.FillRangeListWithMarks( &aChangeRanges, false );
+ }
+ HelperNotifyChanges::Notify(*pModelObj, aChangeRanges);
+ }
+
+ CellContentChanged();
+ ShowAllCursors();
+
+ if ( nFlags & InsertDeleteFlags::ATTRIB )
+ {
+ if ( nFlags & InsertDeleteFlags::CONTENTS )
+ bFormatValid = false;
+ else
+ StartFormatArea(); // delete attribute is also attribute-change
+ }
+ OUString aStartAddress = aMarkRange.aStart.GetColRowString();
+ OUString aEndAddress = aMarkRange.aEnd.GetColRowString();
+ collectUIInformation({{"RANGE", aStartAddress + ":" + aEndAddress}}, "DELETE");
+}
+
+// column width/row height (via header) - undo OK
+
+void ScViewFunc::SetWidthOrHeight(
+ bool bWidth, const std::vector<sc::ColRowSpan>& rRanges, ScSizeMode eMode,
+ sal_uInt16 nSizeTwips, bool bRecord, const ScMarkData* pMarkData )
+{
+ if (rRanges.empty())
+ return;
+
+ // Use view's mark if none specified, but do not modify the original data,
+ // i.e. no MarkToMulti() on that.
+ ScMarkData aMarkData( pMarkData ? *pMarkData : GetViewData().GetMarkData());
+
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCCOL nCurX = GetViewData().GetCurX();
+ SCROW nCurY = GetViewData().GetCurY();
+ SCTAB nFirstTab = aMarkData.GetFirstSelected();
+ SCTAB nCurTab = GetViewData().GetTabNo();
+ if (bRecord && !rDoc.IsUndoEnabled())
+ bRecord = false;
+
+ ScDocShellModificator aModificator( *pDocSh );
+
+ bool bAllowed = true;
+ for (const SCTAB& nTab : aMarkData)
+ {
+ bAllowed = std::all_of(rRanges.begin(), rRanges.end(),
+ [&bWidth, &rDoc, &nTab](const sc::ColRowSpan& rRange) {
+ bool bOnlyMatrix;
+ bool bIsBlockEditable;
+ if (bWidth)
+ bIsBlockEditable = rDoc.IsBlockEditable(nTab, rRange.mnStart, 0, rRange.mnEnd, rDoc.MaxRow(), &bOnlyMatrix);
+ else
+ bIsBlockEditable = rDoc.IsBlockEditable(nTab, 0, rRange.mnStart, rDoc.MaxCol(), rRange.mnEnd, &bOnlyMatrix);
+ return bIsBlockEditable || bOnlyMatrix;
+ });
+ if (!bAllowed)
+ break;
+ }
+
+ // Allow users to resize cols/rows in readonly docs despite the r/o state.
+ // It is frustrating to be unable to see content in mis-sized cells.
+ if( !bAllowed && !pDocSh->IsReadOnly() )
+ {
+ ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ SCCOLROW nStart = rRanges.front().mnStart;
+ SCCOLROW nEnd = rRanges.back().mnEnd;
+
+ OnLOKSetWidthOrHeight(nStart, bWidth);
+
+ bool bFormula = false;
+ if ( eMode == SC_SIZE_OPTIMAL )
+ {
+ const ScViewOptions& rOpts = GetViewData().GetOptions();
+ bFormula = rOpts.GetOption( VOPT_FORMULAS );
+ }
+
+ ScDocumentUniquePtr pUndoDoc;
+ std::unique_ptr<ScOutlineTable> pUndoTab;
+ std::vector<sc::ColRowSpan> aUndoRanges;
+
+ if ( bRecord )
+ {
+ rDoc.BeginDrawUndo(); // Drawing Updates
+
+ pUndoDoc.reset(new ScDocument( SCDOCMODE_UNDO ));
+ for (const SCTAB& nTab : aMarkData)
+ {
+ if (bWidth)
+ {
+ if ( nTab == nFirstTab )
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, true );
+ else
+ pUndoDoc->AddUndoTab( nTab, nTab, true );
+ rDoc.CopyToDocument( static_cast<SCCOL>(nStart), 0, nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab, InsertDeleteFlags::NONE,
+ false, *pUndoDoc );
+ }
+ else
+ {
+ if ( nTab == nFirstTab )
+ pUndoDoc->InitUndo( rDoc, nTab, nTab, false, true );
+ else
+ pUndoDoc->AddUndoTab( nTab, nTab, false, true );
+ rDoc.CopyToDocument( 0, nStart, nTab, rDoc.MaxCol(), nEnd, nTab, InsertDeleteFlags::NONE, false, *pUndoDoc );
+ }
+ }
+
+ aUndoRanges = rRanges;
+
+ //! outlines from all tab?
+ ScOutlineTable* pTable = rDoc.GetOutlineTable( nCurTab );
+ if (pTable)
+ pUndoTab.reset(new ScOutlineTable( *pTable ));
+ }
+
+ if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
+ aMarkData.MarkToMulti();
+
+ bool bShow = nSizeTwips > 0 || eMode != SC_SIZE_DIRECT;
+ bool bOutline = false;
+
+ for (const SCTAB& nTab : aMarkData)
+ {
+ for (const sc::ColRowSpan & rRange : rRanges)
+ {
+ SCCOLROW nStartNo = rRange.mnStart;
+ SCCOLROW nEndNo = rRange.mnEnd;
+
+ if ( !bWidth ) // height always blockwise
+ {
+ if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
+ {
+ bool bAll = ( eMode==SC_SIZE_OPTIMAL );
+ if (!bAll)
+ {
+ // delete CRFlags::ManualSize for all in range,
+ // then SetOptimalHeight with bShrink = FALSE
+ for (SCROW nRow = nStartNo; nRow <= nEndNo; ++nRow)
+ {
+ SCROW nLastRow = nRow;
+ if (rDoc.RowHidden(nRow, nTab, nullptr, &nLastRow))
+ {
+ nRow = nLastRow;
+ continue;
+ }
+
+ CRFlags nOld = rDoc.GetRowFlags(nRow, nTab);
+ if (nOld & CRFlags::ManualSize)
+ rDoc.SetRowFlags(nRow, nTab, nOld & ~CRFlags::ManualSize);
+ }
+ }
+
+ double nPPTX = GetViewData().GetPPTX();
+ double nPPTY = GetViewData().GetPPTY();
+ Fraction aZoomX = GetViewData().GetZoomX();
+ Fraction aZoomY = GetViewData().GetZoomY();
+
+ ScSizeDeviceProvider aProv(pDocSh);
+ if (aProv.IsPrinter())
+ {
+ nPPTX = aProv.GetPPTX();
+ nPPTY = aProv.GetPPTY();
+ aZoomX = aZoomY = Fraction( 1, 1 );
+ }
+
+ sc::RowHeightContext aCxt(rDoc.MaxRow(), nPPTX, nPPTY, aZoomX, aZoomY, aProv.GetDevice());
+ aCxt.setForceAutoSize(bAll);
+ aCxt.setExtraHeight(nSizeTwips);
+ rDoc.SetOptimalHeight(aCxt, nStartNo, nEndNo, nTab, true);
+
+ // Manual-Flag already (re)set in SetOptimalHeight in case of bAll=sal_True
+ // (set for Extra-Height, else reset).
+ }
+ else if ( eMode==SC_SIZE_DIRECT )
+ {
+ if (nSizeTwips)
+ {
+ rDoc.SetRowHeightRange( nStartNo, nEndNo, nTab, nSizeTwips );
+ rDoc.SetManualHeight( nStartNo, nEndNo, nTab, true ); // height was set manually
+ }
+
+ rDoc.ShowRows( nStartNo, nEndNo, nTab, nSizeTwips != 0 );
+
+ if (!bShow && nStartNo <= nCurY && nCurY <= nEndNo && nTab == nCurTab)
+ {
+ nCurY = -1;
+ }
+ }
+ else if ( eMode==SC_SIZE_SHOW )
+ {
+ rDoc.ShowRows( nStartNo, nEndNo, nTab, true );
+ }
+ }
+ else // column width
+ {
+ for (SCCOL nCol=static_cast<SCCOL>(nStartNo); nCol<=static_cast<SCCOL>(nEndNo); nCol++)
+ {
+ const bool bIsColHidden = rDoc.ColHidden(nCol, nTab);
+ if ( eMode != SC_SIZE_VISOPT || !bIsColHidden )
+ {
+ sal_uInt16 nThisSize = nSizeTwips;
+
+ if ( eMode==SC_SIZE_OPTIMAL || eMode==SC_SIZE_VISOPT )
+ nThisSize = nSizeTwips + GetOptimalColWidth( nCol, nTab, bFormula );
+ if ( nThisSize )
+ rDoc.SetColWidth( nCol, nTab, nThisSize );
+
+ // tdf#131073 - Don't show hidden cols after setting optimal col width
+ if (eMode == SC_SIZE_OPTIMAL)
+ rDoc.ShowCol(nCol, nTab, !bIsColHidden);
+ else
+ rDoc.ShowCol( nCol, nTab, bShow );
+
+ if (!bShow && nCol == nCurX && nTab == nCurTab)
+ {
+ nCurX = -1;
+ }
+ }
+ }
+ }
+
+ // adjust outline
+ if (bWidth)
+ {
+ if ( rDoc.UpdateOutlineCol( static_cast<SCCOL>(nStartNo),
+ static_cast<SCCOL>(nEndNo), nTab, bShow ) )
+ bOutline = true;
+ }
+ else
+ {
+ if ( rDoc.UpdateOutlineRow( nStartNo, nEndNo, nTab, bShow ) )
+ bOutline = true;
+ }
+ }
+ rDoc.SetDrawPageSize(nTab);
+ }
+
+ if (!bOutline)
+ pUndoTab.reset();
+
+ if (bRecord)
+ {
+ pDocSh->GetUndoManager()->AddUndoAction(
+ std::make_unique<ScUndoWidthOrHeight>(
+ pDocSh, aMarkData, nStart, nCurTab, nEnd, nCurTab,
+ std::move(pUndoDoc), std::move(aUndoRanges), std::move(pUndoTab), eMode, nSizeTwips, bWidth));
+ }
+
+ if (nCurX < 0)
+ {
+ MoveCursorRel( 1, 0, SC_FOLLOW_LINE, false );
+ }
+
+ if (nCurY < 0)
+ {
+ MoveCursorRel( 0, 1, SC_FOLLOW_LINE, false );
+ }
+
+ // fdo#36247 Ensure that the drawing layer's map mode scaling factors match
+ // the new heights and widths.
+ GetViewData().GetView()->RefreshZoom();
+
+ for (const SCTAB& nTab : aMarkData)
+ rDoc.UpdatePageBreaks( nTab );
+
+ bool bAffectsVisibility = (eMode != SC_SIZE_ORIGINAL && eMode != SC_SIZE_VISOPT);
+ ScTabViewShell::notifyAllViewsSheetGeomInvalidation(GetViewData().GetViewShell(),
+ bWidth /* bColumns */, !bWidth /* bRows */,
+ true /* bSizes*/, bAffectsVisibility /* bHidden */, bAffectsVisibility /* bFiltered */,
+ false /* bGroups */, nCurTab);
+ GetViewData().GetView()->UpdateScrollBars(bWidth ? COLUMN_HEADER : ROW_HEADER);
+
+ {
+ for (const SCTAB& nTab : aMarkData)
+ {
+ if (bWidth)
+ {
+ if (rDoc.HasAttrib( static_cast<SCCOL>(nStart),0,nTab,
+ static_cast<SCCOL>(nEnd), rDoc.MaxRow(), nTab,
+ HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
+ nStart = 0;
+ if (nStart > 0) // go upwards because of Lines and cursor
+ --nStart;
+ pDocSh->PostPaint( static_cast<SCCOL>(nStart), 0, nTab,
+ rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid | PaintPartFlags::Top );
+ }
+ else
+ {
+ if (rDoc.HasAttrib( 0,nStart,nTab, rDoc.MaxCol(), nEnd,nTab, HasAttrFlags::Merged | HasAttrFlags::Overlapped ))
+ nStart = 0;
+ if (nStart != 0)
+ --nStart;
+ pDocSh->PostPaint( 0, nStart, nTab, rDoc.MaxCol(), rDoc.MaxRow(), nTab, PaintPartFlags::Grid | PaintPartFlags::Left );
+ }
+ }
+
+ pDocSh->UpdateOle(GetViewData());
+ if( !pDocSh->IsReadOnly() )
+ aModificator.SetDocumentModified();
+ }
+
+ if ( !bWidth )
+ return;
+
+ ScModelObj* pModelObj = HelperNotifyChanges::getMustPropagateChangesModel(*pDocSh);
+ if (!pModelObj)
+ return;
+
+ ScRangeList aChangeRanges;
+ for (const SCTAB& nTab : aMarkData)
+ {
+ for (const sc::ColRowSpan & rRange : rRanges)
+ {
+ SCCOL nStartCol = rRange.mnStart;
+ SCCOL nEndCol = rRange.mnEnd;
+ for ( SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol )
+ {
+ aChangeRanges.push_back( ScRange( nCol, 0, nTab ) );
+ }
+ }
+ }
+ HelperNotifyChanges::Notify(*pModelObj, aChangeRanges, "column-resize");
+}
+
+// column width/row height (via marked range)
+
+void ScViewFunc::SetMarkedWidthOrHeight( bool bWidth, ScSizeMode eMode, sal_uInt16 nSizeTwips )
+{
+ ScMarkData& rMark = GetViewData().GetMarkData();
+
+ rMark.MarkToMulti();
+ if (!rMark.IsMultiMarked())
+ {
+ SCCOL nCol = GetViewData().GetCurX();
+ SCROW nRow = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+ const ScRange aMarkRange( nCol, nRow, nTab);
+ DoneBlockMode();
+ InitOwnBlockMode( aMarkRange );
+ rMark.SetMultiMarkArea( aMarkRange );
+ MarkDataChanged();
+ }
+
+ std::vector<sc::ColRowSpan> aRanges =
+ bWidth ? rMark.GetMarkedColSpans() : rMark.GetMarkedRowSpans();
+
+ SetWidthOrHeight(bWidth, aRanges, eMode, nSizeTwips);
+
+ rMark.MarkToSimple();
+}
+
+void ScViewFunc::ModifyCellSize( ScDirection eDir, bool bOptimal )
+{
+ //! step size adjustable
+ // step size is also minimum
+ constexpr sal_uInt16 nStepX = STD_COL_WIDTH / 5;
+ sal_uInt16 nStepY = ScGlobal::nStdRowHeight;
+
+ ScModule* pScMod = SC_MOD();
+ bool bAnyEdit = pScMod->IsInputMode();
+ SCCOL nCol = GetViewData().GetCurX();
+ SCROW nRow = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+
+ bool bAllowed, bOnlyMatrix;
+ if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
+ bAllowed = rDoc.IsBlockEditable( nTab, nCol,0, nCol,rDoc.MaxRow(), &bOnlyMatrix );
+ else
+ bAllowed = rDoc.IsBlockEditable( nTab, 0,nRow, rDoc.MaxCol(), nRow, &bOnlyMatrix );
+ if ( !bAllowed && !bOnlyMatrix )
+ {
+ ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ HideAllCursors();
+
+ sal_uInt16 nWidth = rDoc.GetColWidth( nCol, nTab );
+ sal_uInt16 nHeight = rDoc.GetRowHeight( nRow, nTab );
+ std::vector<sc::ColRowSpan> aRange(1, sc::ColRowSpan(0,0));
+ if ( eDir == DIR_LEFT || eDir == DIR_RIGHT )
+ {
+ if (bOptimal) // width of this single cell
+ {
+ if ( bAnyEdit )
+ {
+ // when editing the actual entered width
+ ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData().GetViewShell() );
+ if (pHdl)
+ {
+ tools::Long nEdit = pHdl->GetTextSize().Width(); // in 0.01 mm
+
+ const ScPatternAttr* pPattern = rDoc.GetPattern( nCol, nRow, nTab );
+ const SvxMarginItem& rMItem = pPattern->GetItem(ATTR_MARGIN);
+ sal_uInt16 nMargin = rMItem.GetLeftMargin() + rMItem.GetRightMargin();
+ if ( pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue() == SvxCellHorJustify::Left )
+ nMargin = sal::static_int_cast<sal_uInt16>(
+ nMargin + pPattern->GetItem(ATTR_INDENT).GetValue() );
+
+ nWidth = std::round(o3tl::convert(nEdit * pDocSh->GetOutputFactor(),
+ o3tl::Length::mm100, o3tl::Length::twip))
+ + nMargin + STD_EXTRA_WIDTH;
+ }
+ }
+ else
+ {
+ double nPPTX = GetViewData().GetPPTX();
+ double nPPTY = GetViewData().GetPPTY();
+ Fraction aZoomX = GetViewData().GetZoomX();
+ Fraction aZoomY = GetViewData().GetZoomY();
+
+ ScSizeDeviceProvider aProv(pDocSh);
+ if (aProv.IsPrinter())
+ {
+ nPPTX = aProv.GetPPTX();
+ nPPTY = aProv.GetPPTY();
+ aZoomX = aZoomY = Fraction( 1, 1 );
+ }
+
+ tools::Long nPixel = rDoc.GetNeededSize( nCol, nRow, nTab, aProv.GetDevice(),
+ nPPTX, nPPTY, aZoomX, aZoomY, true );
+ sal_uInt16 nTwips = static_cast<sal_uInt16>( nPixel / nPPTX );
+ if (nTwips != 0)
+ nWidth = nTwips + STD_EXTRA_WIDTH;
+ else
+ nWidth = STD_COL_WIDTH;
+ }
+ }
+ else // increment / decrement
+ {
+ if ( eDir == DIR_RIGHT )
+ nWidth = sal::static_int_cast<sal_uInt16>( nWidth + nStepX );
+ else if ( nWidth > nStepX )
+ nWidth = sal::static_int_cast<sal_uInt16>( nWidth - nStepX );
+ if ( nWidth < nStepX ) nWidth = nStepX;
+ if ( nWidth > MAX_COL_WIDTH ) nWidth = MAX_COL_WIDTH;
+ }
+ aRange[0].mnStart = nCol;
+ aRange[0].mnEnd = nCol;
+ SetWidthOrHeight(true, aRange, SC_SIZE_DIRECT, nWidth);
+
+ // adjust height of this row if width demands/allows this
+
+ if (!bAnyEdit)
+ {
+ const ScPatternAttr* pPattern = rDoc.GetPattern( nCol, nRow, nTab );
+ bool bNeedHeight =
+ pPattern->GetItem( ATTR_LINEBREAK ).GetValue() ||
+ pPattern->GetItem( ATTR_HOR_JUSTIFY ).GetValue() == SvxCellHorJustify::Block;
+ if (bNeedHeight)
+ AdjustRowHeight( nRow, nRow, true );
+ }
+ }
+ else
+ {
+ ScSizeMode eMode;
+ if (bOptimal)
+ {
+ eMode = SC_SIZE_OPTIMAL;
+ nHeight = 0;
+ }
+ else
+ {
+ eMode = SC_SIZE_DIRECT;
+ if ( eDir == DIR_BOTTOM )
+ nHeight = sal::static_int_cast<sal_uInt16>( nHeight + nStepY );
+ else if ( nHeight > nStepY )
+ nHeight = sal::static_int_cast<sal_uInt16>( nHeight - nStepY );
+ if ( nHeight < nStepY ) nHeight = nStepY;
+ if ( nHeight > MAX_ROW_HEIGHT ) nHeight = MAX_ROW_HEIGHT;
+ }
+ aRange[0].mnStart = nRow;
+ aRange[0].mnEnd = nRow;
+ SetWidthOrHeight(false, aRange, eMode, nHeight);
+ }
+
+ if ( bAnyEdit )
+ {
+ UpdateEditView();
+ if ( rDoc.HasAttrib( nCol, nRow, nTab, nCol, nRow, nTab, HasAttrFlags::NeedHeight ) )
+ {
+ ScInputHandler* pHdl = pScMod->GetInputHdl( GetViewData().GetViewShell() );
+ if (pHdl)
+ pHdl->SetModified(); // so that the height is adjusted with Enter
+ }
+ }
+
+ ShowAllCursors();
+}
+
+void ScViewFunc::ProtectSheet( SCTAB nTab, const ScTableProtection& rProtect )
+{
+ if (nTab == TABLEID_DOC)
+ return;
+
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+ bool bUndo(rDoc.IsUndoEnabled());
+
+ // modifying several tabs is handled here
+
+ if (bUndo)
+ {
+ OUString aUndo = ScResId( STR_UNDO_PROTECT_TAB );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
+ }
+
+ for (const auto& rTab : rMark)
+ {
+ rFunc.ProtectSheet(rTab, rProtect);
+ }
+
+ if (bUndo)
+ pDocSh->GetUndoManager()->LeaveListAction();
+
+ UpdateLayerLocks(); //! broadcast to all views
+}
+
+void ScViewFunc::ProtectDoc( const OUString& rPassword )
+{
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+
+ rFunc.Protect( TABLEID_DOC, rPassword );
+
+ UpdateLayerLocks(); //! broadcast to all views
+}
+
+bool ScViewFunc::Unprotect( SCTAB nTab, const OUString& rPassword )
+{
+ ScMarkData& rMark = GetViewData().GetMarkData();
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ ScDocFunc &rFunc = pDocSh->GetDocFunc();
+ bool bChanged = false;
+ bool bUndo (rDoc.IsUndoEnabled());
+
+ if ( nTab == TABLEID_DOC || rMark.GetSelectCount() <= 1 )
+ {
+ bChanged = rFunc.Unprotect( nTab, rPassword, false );
+ if (bChanged && nTab != TABLEID_DOC)
+ SetTabProtectionSymbol(nTab, false);
+ }
+ else
+ {
+ // modifying several tabs is handled here
+
+ if (bUndo)
+ {
+ OUString aUndo = ScResId( STR_UNDO_UNPROTECT_TAB );
+ pDocSh->GetUndoManager()->EnterListAction( aUndo, aUndo, 0, GetViewData().GetViewShell()->GetViewShellId() );
+ }
+
+ for (const auto& rTab : rMark)
+ {
+ if ( rFunc.Unprotect( rTab, rPassword, false ) )
+ {
+ bChanged = true;
+ SetTabProtectionSymbol( rTab, false);
+ }
+ }
+
+ if (bUndo)
+ pDocSh->GetUndoManager()->LeaveListAction();
+ }
+
+ if (bChanged)
+ UpdateLayerLocks(); //! broadcast to all views
+
+ return bChanged;
+}
+
+void ScViewFunc::SetNoteText( const ScAddress& rPos, const OUString& rNoteText )
+{
+ GetViewData().GetDocShell()->GetDocFunc().SetNoteText( rPos, rNoteText, false );
+}
+
+void ScViewFunc::ReplaceNote( const ScAddress& rPos, const OUString& rNoteText, const OUString* pAuthor, const OUString* pDate )
+{
+ GetViewData().GetDocShell()->GetDocFunc().ReplaceNote( rPos, rNoteText, pAuthor, pDate, false );
+}
+
+void ScViewFunc::SetNumberFormat( SvNumFormatType nFormatType, sal_uLong nAdd )
+{
+ // not editable because of matrix only? attribute OK nonetheless
+ bool bOnlyNotBecauseOfMatrix;
+ if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
+ {
+ ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ sal_uInt32 nNumberFormat = 0;
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SvNumberFormatter* pNumberFormatter = rDoc.GetFormatTable();
+ LanguageType eLanguage = ScGlobal::eLnge;
+ ScPatternAttr aNewAttrs( rDoc.GetPool() );
+
+ // always take language from cursor position, even if there is a selection
+
+ sal_uInt32 nCurrentNumberFormat = rDoc.GetNumberFormat( rViewData.GetCurX(),
+ rViewData.GetCurY(),
+ rViewData.GetTabNo());
+ const SvNumberformat* pEntry = pNumberFormatter->GetEntry( nCurrentNumberFormat );
+ if (pEntry)
+ eLanguage = pEntry->GetLanguage(); // else keep ScGlobal::eLnge
+
+ nNumberFormat = pNumberFormatter->GetStandardFormat( nFormatType, eLanguage ) + nAdd;
+
+ SfxItemSet& rSet = aNewAttrs.GetItemSet();
+ rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
+ // ATTR_LANGUAGE_FORMAT not
+ ApplySelectionPattern( aNewAttrs );
+}
+
+void ScViewFunc::SetNumFmtByStr( const OUString& rCode )
+{
+ // not editable because of matrix only? attribute OK nonetheless
+ bool bOnlyNotBecauseOfMatrix;
+ if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
+ {
+ ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ ScViewData& rViewData = GetViewData();
+ ScDocument& rDoc = rViewData.GetDocument();
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+
+ // language always from cursor position
+
+ sal_uInt32 nCurrentNumberFormat = rDoc.GetNumberFormat( rViewData.GetCurX(), rViewData.GetCurY(),
+ rViewData.GetTabNo());
+ const SvNumberformat* pEntry = pFormatter->GetEntry( nCurrentNumberFormat );
+ LanguageType eLanguage = pEntry ? pEntry->GetLanguage() : ScGlobal::eLnge;
+
+ // determine index for String
+
+ bool bOk = true;
+ sal_uInt32 nNumberFormat = pFormatter->GetEntryKey( rCode, eLanguage );
+ if ( nNumberFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
+ {
+ // enter new
+
+ OUString aFormat = rCode; // will be changed
+ sal_Int32 nErrPos = 0;
+ SvNumFormatType nType = SvNumFormatType::ALL; //! ???
+ bOk = pFormatter->PutEntry( aFormat, nErrPos, nType, nNumberFormat, eLanguage );
+ }
+
+ if ( bOk ) // valid format?
+ {
+ ScPatternAttr aNewAttrs( rDoc.GetPool() );
+ SfxItemSet& rSet = aNewAttrs.GetItemSet();
+ rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNumberFormat ) );
+ rSet.Put( SvxLanguageItem( eLanguage, ATTR_LANGUAGE_FORMAT ) );
+ ApplySelectionPattern( aNewAttrs );
+ }
+
+ //! else return error / issue warning ???
+}
+
+void ScViewFunc::ChangeNumFmtDecimals( bool bIncrement )
+{
+ // not editable because of matrix only? attribute OK nonetheless
+ bool bOnlyNotBecauseOfMatrix;
+ if ( !SelectionEditable( &bOnlyNotBecauseOfMatrix ) && !bOnlyNotBecauseOfMatrix )
+ {
+ ErrorMessage(STR_PROTECTIONERR);
+ return;
+ }
+
+ ScDocument& rDoc = GetViewData().GetDocument();
+ SvNumberFormatter* pFormatter = rDoc.GetFormatTable();
+
+ SCCOL nCol = GetViewData().GetCurX();
+ SCROW nRow = GetViewData().GetCurY();
+ SCTAB nTab = GetViewData().GetTabNo();
+
+ sal_uInt32 nOldFormat = rDoc.GetNumberFormat( nCol, nRow, nTab );
+ const SvNumberformat* pOldEntry = pFormatter->GetEntry( nOldFormat );
+ if (!pOldEntry)
+ {
+ OSL_FAIL("numberformat not found !!!");
+ return;
+ }
+
+ // what have we got here?
+
+ sal_uInt32 nNewFormat = nOldFormat;
+ bool bError = false;
+
+ LanguageType eLanguage = pOldEntry->GetLanguage();
+ bool bThousand, bNegRed;
+ sal_uInt16 nPrecision, nLeading;
+ pOldEntry->GetFormatSpecialInfo( bThousand, bNegRed, nPrecision, nLeading );
+
+ SvNumFormatType nOldType = pOldEntry->GetType();
+ if ( SvNumFormatType::ALL == ( nOldType & (
+ SvNumFormatType::NUMBER | SvNumFormatType::CURRENCY | SvNumFormatType::PERCENT | SvNumFormatType::SCIENTIFIC | SvNumFormatType::TIME ) ) )
+ {
+ // date, fraction, logical, text can not be changed
+ bError = true;
+ }
+
+ //! SvNumberformat has a Member bStandard, but doesn't disclose it
+ bool bWasStandard = ( nOldFormat == pFormatter->GetStandardIndex( eLanguage ) );
+ OUString sExponentialStandardFormat = "";
+ if (bWasStandard)
+ {
+ // with "Standard" the decimal places depend on cell content
+ // 0 if empty or text -> no decimal places
+ double nVal = rDoc.GetValue( ScAddress( nCol, nRow, nTab ) );
+
+ // the ways of the Numberformatters are unfathomable, so try:
+ OUString aOut;
+ const Color* pCol;
+ const_cast<SvNumberformat*>(pOldEntry)->GetOutputString( nVal, aOut, &pCol );
+
+ nPrecision = 0;
+ // 'E' for exponential is fixed in Numberformatter
+ sal_Int32 nIndexE = aOut.indexOf('E');
+ if ( nIndexE >= 0 )
+ {
+ sExponentialStandardFormat = aOut.copy( nIndexE ).replace( '-', '+' );
+ for ( sal_Int32 i=1 ; i<sExponentialStandardFormat.getLength() ; i++ )
+ {
+ if ( sExponentialStandardFormat[i] >= '1' && sExponentialStandardFormat[i] <= '9' )
+ sExponentialStandardFormat = sExponentialStandardFormat.replaceAt( i, 1, u"0" );
+ }
+ aOut = aOut.copy( 0, nIndexE ); // remove exponential part
+ }
+ OUString aDecSep( pFormatter->GetFormatDecimalSep( nOldFormat ) );
+ sal_Int32 nPos = aOut.indexOf( aDecSep );
+ if ( nPos >= 0 )
+ nPrecision = aOut.getLength() - nPos - aDecSep.getLength();
+ // else keep 0
+ }
+ else
+ {
+ if ( (nOldType & SvNumFormatType::SCIENTIFIC) && !bThousand &&
+ (pOldEntry->GetFormatIntegerDigits()%3 == 0) && pOldEntry->GetFormatIntegerDigits() > 0 )
+ bThousand = true;
+ }
+
+ if (!bError)
+ {
+ if (bIncrement)
+ {
+ if (nPrecision<20)
+ ++nPrecision; // increment
+ else
+ bError = true; // 20 is maximum
+ }
+ else
+ {
+ if (nPrecision)
+ --nPrecision; // decrement
+ else
+ bError = true; // 0 is minimum
+ }
+ }
+
+ if (!bError)
+ {
+ OUString aNewPicture = pFormatter->GenerateFormat(nOldFormat, eLanguage,
+ bThousand, bNegRed,
+ nPrecision, nLeading)
+ + sExponentialStandardFormat;
+
+ nNewFormat = pFormatter->GetEntryKey( aNewPicture, eLanguage );
+ if ( nNewFormat == NUMBERFORMAT_ENTRY_NOT_FOUND )
+ {
+ sal_Int32 nErrPos = 0;
+ SvNumFormatType nNewType = SvNumFormatType::ALL;
+ bool bOk = pFormatter->PutEntry( aNewPicture, nErrPos,
+ nNewType, nNewFormat, eLanguage );
+ OSL_ENSURE( bOk, "incorrect numberformat generated" );
+ if (!bOk)
+ bError = true;
+ }
+ }
+
+ if (!bError)
+ {
+ ScPatternAttr aNewAttrs( rDoc.GetPool() );
+ SfxItemSet& rSet = aNewAttrs.GetItemSet();
+ rSet.Put( SfxUInt32Item( ATTR_VALUE_FORMAT, nNewFormat ) );
+ // ATTR_LANGUAGE_FORMAT not
+ ApplySelectionPattern( aNewAttrs );
+ }
+}
+
+void ScViewFunc::ChangeIndent( bool bIncrement )
+{
+ ScViewData& rViewData = GetViewData();
+ ScDocShell* pDocSh = rViewData.GetDocShell();
+ ScMarkData& rMark = rViewData.GetMarkData();
+
+ ScMarkData aWorkMark = rMark;
+ ScViewUtil::UnmarkFiltered( aWorkMark, pDocSh->GetDocument() );
+ aWorkMark.MarkToMulti();
+ if (!aWorkMark.IsMultiMarked())
+ {
+ SCCOL nCol = rViewData.GetCurX();
+ SCROW nRow = rViewData.GetCurY();
+ SCTAB nTab = rViewData.GetTabNo();
+ aWorkMark.SetMultiMarkArea( ScRange(nCol,nRow,nTab) );
+ }
+
+ bool bSuccess = pDocSh->GetDocFunc().ChangeIndent( aWorkMark, bIncrement, false );
+ if (bSuccess)
+ {
+ pDocSh->UpdateOle(rViewData);
+ StartFormatArea();
+
+ // stuff for sidebar panels
+ SfxBindings& rBindings = GetViewData().GetBindings();
+ rBindings.Invalidate( SID_H_ALIGNCELL );
+ rBindings.Invalidate( SID_ATTR_ALIGN_INDENT );
+ }
+}
+
+bool ScViewFunc::InsertName( const OUString& rName, const OUString& rSymbol,
+ const OUString& rType )
+{
+ // Type = P,R,C,F (and combinations)
+ //! undo...
+
+ bool bOk = false;
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ ScDocument& rDoc = pDocSh->GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ ScRangeName* pList = rDoc.GetRangeName();
+
+ ScRangeData::Type nType = ScRangeData::Type::Name;
+ auto pNewEntry = std::make_unique<ScRangeData>(
+ rDoc, rName, rSymbol, ScAddress( GetViewData().GetCurX(),
+ GetViewData().GetCurY(), nTab), nType );
+ OUString aUpType = rType.toAsciiUpperCase();
+ if ( aUpType.indexOf( 'P' ) != -1 )
+ nType |= ScRangeData::Type::PrintArea;
+ if ( aUpType.indexOf( 'R' ) != -1 )
+ nType |= ScRangeData::Type::RowHeader;
+ if ( aUpType.indexOf( 'C' ) != -1 )
+ nType |= ScRangeData::Type::ColHeader;
+ if ( aUpType.indexOf( 'F' ) != -1 )
+ nType |= ScRangeData::Type::Criteria;
+ pNewEntry->AddType(nType);
+
+ if ( pNewEntry->GetErrCode() == FormulaError::NONE ) // text valid?
+ {
+ ScDocShellModificator aModificator( *pDocSh );
+
+ rDoc.PreprocessRangeNameUpdate();
+
+ // input available yet? Then remove beforehand (=change)
+ ScRangeData* pData = pList->findByUpperName(ScGlobal::getCharClass().uppercase(rName));
+ if (pData)
+ { // take old Index
+ pNewEntry->SetIndex(pData->GetIndex());
+ pList->erase(*pData);
+ }
+
+ // don't delete, insert took ownership, even on failure!
+ if ( pList->insert( pNewEntry.release() ) )
+ bOk = true;
+
+ rDoc.CompileHybridFormula();
+
+ aModificator.SetDocumentModified();
+ SfxGetpApp()->Broadcast( SfxHint( SfxHintId::ScAreasChanged ) );
+ }
+
+ return bOk;
+}
+
+void ScViewFunc::CreateNames( CreateNameFlags nFlags )
+{
+ bool bDone = false;
+ ScRange aRange;
+ if ( GetViewData().GetSimpleArea(aRange) == SC_MARK_SIMPLE )
+ bDone = GetViewData().GetDocShell()->GetDocFunc().CreateNames( aRange, nFlags, false );
+
+ if (!bDone)
+ ErrorMessage(STR_CREATENAME_MARKERR);
+}
+
+CreateNameFlags ScViewFunc::GetCreateNameFlags()
+{
+ CreateNameFlags nFlags = CreateNameFlags::NONE;
+
+ SCCOL nStartCol, nEndCol;
+ SCROW nStartRow, nEndRow;
+ SCTAB nDummy;
+ if (GetViewData().GetSimpleArea(nStartCol,nStartRow,nDummy,nEndCol,nEndRow,nDummy) == SC_MARK_SIMPLE)
+ {
+ ScDocument& rDoc = GetViewData().GetDocument();
+ SCTAB nTab = GetViewData().GetTabNo();
+ bool bOk;
+ SCCOL i;
+ SCROW j;
+
+ bOk = true;
+ SCCOL nFirstCol = nStartCol;
+ SCCOL nLastCol = nEndCol;
+ if (nStartCol+1 < nEndCol) { ++nFirstCol; --nLastCol; }
+ for (i=nFirstCol; i<=nLastCol && bOk; i++)
+ if (!rDoc.HasStringData( i,nStartRow,nTab ))
+ bOk = false;
+ if (bOk)
+ nFlags |= CreateNameFlags::Top;
+ else // Bottom only if not Top
+ {
+ bOk = true;
+ for (i=nFirstCol; i<=nLastCol && bOk; i++)
+ if (!rDoc.HasStringData( i,nEndRow,nTab ))
+ bOk = false;
+ if (bOk)
+ nFlags |= CreateNameFlags::Bottom;
+ }
+
+ bOk = true;
+ SCROW nFirstRow = nStartRow;
+ SCROW nLastRow = nEndRow;
+ if (nStartRow+1 < nEndRow) { ++nFirstRow; --nLastRow; }
+ for (j=nFirstRow; j<=nLastRow && bOk; j++)
+ if (!rDoc.HasStringData( nStartCol,j,nTab ))
+ bOk = false;
+ if (bOk)
+ nFlags |= CreateNameFlags::Left;
+ else // Right only if not Left
+ {
+ bOk = true;
+ for (j=nFirstRow; j<=nLastRow && bOk; j++)
+ if (!rDoc.HasStringData( nEndCol,j,nTab ))
+ bOk = false;
+ if (bOk)
+ nFlags |= CreateNameFlags::Right;
+ }
+ }
+
+ if (nStartCol == nEndCol)
+ nFlags &= ~CreateNameFlags( CreateNameFlags::Left | CreateNameFlags::Right );
+ if (nStartRow == nEndRow)
+ nFlags &= ~CreateNameFlags( CreateNameFlags::Top | CreateNameFlags::Bottom );
+
+ return nFlags;
+}
+
+void ScViewFunc::InsertNameList()
+{
+ ScAddress aPos( GetViewData().GetCurX(), GetViewData().GetCurY(), GetViewData().GetTabNo() );
+ ScDocShell* pDocSh = GetViewData().GetDocShell();
+ if ( pDocSh->GetDocFunc().InsertNameList( aPos, false ) )
+ pDocSh->UpdateOle(GetViewData());
+}
+
+void ScViewFunc::UpdateSelectionArea( const ScMarkData& rSel, ScPatternAttr* pAttr )
+{
+ ScDocShell* pDocShell = GetViewData().GetDocShell();
+ ScRange aMarkRange;
+ if (rSel.IsMultiMarked() )
+ aMarkRange = rSel.GetMultiMarkArea();
+ else
+ aMarkRange = rSel.GetMarkArea();
+
+ bool bSetLines = false;
+ bool bSetAlign = false;
+ if ( pAttr )
+ {
+ const SfxItemSet& rNewSet = pAttr->GetItemSet();
+ bSetLines = rNewSet.GetItemState( ATTR_BORDER ) == SfxItemState::SET ||
+ rNewSet.GetItemState( ATTR_SHADOW ) == SfxItemState::SET;
+ bSetAlign = rNewSet.GetItemState( ATTR_HOR_JUSTIFY ) == SfxItemState::SET;
+ }
+
+ sal_uInt16 nExtFlags = 0;
+ if ( bSetLines )
+ nExtFlags |= SC_PF_LINES;
+ if ( bSetAlign )
+ nExtFlags |= SC_PF_WHOLEROWS;
+
+ SCCOL nStartCol = aMarkRange.aStart.Col();
+ SCROW nStartRow = aMarkRange.aStart.Row();
+ SCTAB nStartTab = aMarkRange.aStart.Tab();
+ SCCOL nEndCol = aMarkRange.aEnd.Col();
+ SCROW nEndRow = aMarkRange.aEnd.Row();
+ SCTAB nEndTab = aMarkRange.aEnd.Tab();
+ pDocShell->PostPaint( nStartCol, nStartRow, nStartTab,
+ nEndCol, nEndRow, nEndTab,
+ PaintPartFlags::Grid, nExtFlags | SC_PF_TESTMERGE );
+ ScTabViewShell* pTabViewShell = GetViewData().GetViewShell();
+ pTabViewShell->AdjustBlockHeight(false, const_cast<ScMarkData*>(&rSel));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/viewutil.cxx b/sc/source/ui/view/viewutil.cxx
new file mode 100644
index 000000000..7607c8f71
--- /dev/null
+++ b/sc/source/ui/view/viewutil.cxx
@@ -0,0 +1,426 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <scitems.hxx>
+#include <sfx2/bindings.hxx>
+#include <sfx2/viewsh.hxx>
+#include <sfx2/dispatch.hxx>
+#include <editeng/fontitem.hxx>
+#include <editeng/langitem.hxx>
+#include <editeng/scripttypeitem.hxx>
+#include <i18nutil/transliteration.hxx>
+#include <svl/itempool.hxx>
+#include <svl/itemset.hxx>
+#include <svl/cjkoptions.hxx>
+#include <svl/ctloptions.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/settings.hxx>
+#include <sfx2/objsh.hxx>
+#include <sfx2/viewfrm.hxx>
+#include <svl/eitem.hxx>
+#include <osl/diagnose.h>
+
+#include <viewutil.hxx>
+#include <chgtrack.hxx>
+#include <chgviset.hxx>
+#include <markdata.hxx>
+#include <document.hxx>
+#include <tabvwsh.hxx>
+
+#include <svx/svxdlg.hxx>
+#include <svx/svxids.hrc>
+#include <memory>
+
+void ScViewUtil::PutItemScript( SfxItemSet& rShellSet, const SfxItemSet& rCoreSet,
+ sal_uInt16 nWhichId, SvtScriptType nScript )
+{
+ // take the effective item from rCoreSet according to nScript
+ // and put in rShellSet under the (base) nWhichId
+
+ SfxItemPool& rPool = *rShellSet.GetPool();
+ SvxScriptSetItem aSetItem( rPool.GetSlotId(nWhichId), rPool );
+ // use PutExtended with eDefaultAs = SfxItemState::SET, so defaults from rCoreSet
+ // (document pool) are read and put into rShellSet (MessagePool)
+ aSetItem.GetItemSet().PutExtended( rCoreSet, SfxItemState::DONTCARE, SfxItemState::SET );
+ const SfxPoolItem* pI = aSetItem.GetItemOfScript( nScript );
+ if (pI)
+ {
+ rShellSet.Put( pI->CloneSetWhich(nWhichId) );
+ }
+ else
+ rShellSet.InvalidateItem( nWhichId );
+}
+
+LanguageType ScViewUtil::GetEffLanguage( ScDocument& rDoc, const ScAddress& rPos )
+{
+ // used for thesaurus
+
+ SvtScriptType nScript = rDoc.GetScriptType(rPos.Col(), rPos.Row(), rPos.Tab());
+ sal_uInt16 nWhich = ( nScript == SvtScriptType::ASIAN ) ? ATTR_CJK_FONT_LANGUAGE :
+ ( ( nScript == SvtScriptType::COMPLEX ) ? ATTR_CTL_FONT_LANGUAGE : ATTR_FONT_LANGUAGE );
+ const SfxPoolItem* pItem = rDoc.GetAttr( rPos.Col(), rPos.Row(), rPos.Tab(), nWhich);
+ const SvxLanguageItem* pLangIt = dynamic_cast<const SvxLanguageItem*>( pItem );
+ LanguageType eLnge;
+ if (pLangIt)
+ {
+ eLnge = pLangIt->GetValue();
+ if (eLnge == LANGUAGE_DONTKNOW) //! can this happen?
+ {
+ LanguageType eLatin, eCjk, eCtl;
+ rDoc.GetLanguage( eLatin, eCjk, eCtl );
+ eLnge = ( nScript == SvtScriptType::ASIAN ) ? eCjk :
+ ( ( nScript == SvtScriptType::COMPLEX ) ? eCtl : eLatin );
+ }
+ }
+ else
+ eLnge = LANGUAGE_ENGLISH_US;
+ if ( eLnge == LANGUAGE_SYSTEM )
+ eLnge = Application::GetSettings().GetLanguageTag().getLanguageType(); // never use SYSTEM for spelling
+
+ return eLnge;
+}
+
+TransliterationFlags ScViewUtil::GetTransliterationType( sal_uInt16 nSlotID )
+{
+ TransliterationFlags nType = TransliterationFlags::NONE;
+ switch ( nSlotID )
+ {
+ 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;
+ }
+ return nType;
+}
+
+bool ScViewUtil::IsActionShown( const ScChangeAction& rAction,
+ const ScChangeViewSettings& rSettings,
+ ScDocument& rDocument )
+{
+ // discarded are displayed as inverted accepted action, because of this
+ // order of ShowRejected/ShowAccepted is important
+
+ if ( !rSettings.IsShowRejected() && rAction.IsRejecting() )
+ return false;
+
+ if ( !rSettings.IsShowAccepted() && rAction.IsAccepted() && !rAction.IsRejecting() )
+ return false;
+
+ if ( rSettings.HasAuthor() && rAction.GetUser() != rSettings.GetTheAuthorToShow() )
+ return false;
+
+ if ( rSettings.HasComment() )
+ {
+ OUString aTmp = rAction.GetDescription(rDocument);
+ OUString aComStr = rAction.GetComment() + " (" + aTmp + ")";
+
+ if(!rSettings.IsValidComment(&aComStr))
+ return false;
+ }
+
+ if ( rSettings.HasRange() )
+ if ( !rSettings.GetTheRangeList().Intersects( rAction.GetBigRange().MakeRange( rDocument ) ) )
+ return false;
+
+ if (rSettings.HasDate() && rSettings.GetTheDateMode() != SvxRedlinDateMode::NONE)
+ {
+ DateTime aDateTime = rAction.GetDateTime();
+ const DateTime& rFirst = rSettings.GetTheFirstDateTime();
+ const DateTime& rLast = rSettings.GetTheLastDateTime();
+ switch ( rSettings.GetTheDateMode() )
+ { // corresponds with ScHighlightChgDlg::OKBtnHdl
+ case SvxRedlinDateMode::BEFORE:
+ if ( aDateTime > rFirst )
+ return false;
+ break;
+
+ case SvxRedlinDateMode::SINCE:
+ if ( aDateTime < rFirst )
+ return false;
+ break;
+
+ case SvxRedlinDateMode::EQUAL:
+ case SvxRedlinDateMode::BETWEEN:
+ if ( aDateTime < rFirst || aDateTime > rLast )
+ return false;
+ break;
+
+ case SvxRedlinDateMode::NOTEQUAL:
+ if ( aDateTime >= rFirst && aDateTime <= rLast )
+ return false;
+ break;
+
+ case SvxRedlinDateMode::SAVE:
+ {
+ ScChangeTrack* pTrack = rDocument.GetChangeTrack();
+ if ( !pTrack || pTrack->GetLastSavedActionNumber() >=
+ rAction.GetActionNumber() )
+ return false;
+ }
+ break;
+
+ default:
+ {
+ // added to avoid warnings
+ }
+ }
+ }
+
+ if ( rSettings.HasActionRange() )
+ {
+ sal_uLong nAction = rAction.GetActionNumber();
+ sal_uLong nFirstAction;
+ sal_uLong nLastAction;
+ rSettings.GetTheActionRange( nFirstAction, nLastAction );
+ if ( nAction < nFirstAction || nAction > nLastAction )
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+void ScViewUtil::UnmarkFiltered( ScMarkData& rMark, const ScDocument& rDoc )
+{
+ rMark.MarkToMulti();
+
+ const ScRange& aMultiArea = rMark.GetMultiMarkArea();
+ SCCOL nStartCol = aMultiArea.aStart.Col();
+ SCROW nStartRow = aMultiArea.aStart.Row();
+ SCCOL nEndCol = aMultiArea.aEnd.Col();
+ SCROW nEndRow = aMultiArea.aEnd.Row();
+
+ bool bChanged = false;
+ for (const SCTAB& nTab : rMark)
+ {
+ for (SCROW nRow = nStartRow; nRow <= nEndRow; ++nRow)
+ {
+ SCROW nLastRow = nRow;
+ if (rDoc.RowFiltered(nRow, nTab, nullptr, &nLastRow))
+ {
+ // use nStartCol/nEndCol, so the multi mark area isn't extended to all columns
+ // (visible in repaint for indentation)
+ rMark.SetMultiMarkArea(
+ ScRange(nStartCol, nRow, nTab, nEndCol, nLastRow, nTab), false);
+ bChanged = true;
+ nRow = nLastRow;
+ }
+ }
+ }
+
+ if ( bChanged && !rMark.HasAnyMultiMarks() )
+ rMark.ResetMark();
+
+ rMark.MarkToSimple();
+}
+
+bool ScViewUtil::FitToUnfilteredRows( ScRange & rRange, const ScDocument& rDoc, size_t nRows )
+{
+ SCTAB nTab = rRange.aStart.Tab();
+ bool bOneTabOnly = (nTab == rRange.aEnd.Tab());
+ // Always fit the range on its first sheet.
+ OSL_ENSURE( bOneTabOnly, "ScViewUtil::ExtendToUnfilteredRows: works only on one sheet");
+ SCROW nStartRow = rRange.aStart.Row();
+ SCROW nLastRow = rDoc.LastNonFilteredRow(nStartRow, rDoc.MaxRow(), nTab);
+ if (rDoc.ValidRow(nLastRow))
+ rRange.aEnd.SetRow(nLastRow);
+ SCROW nCount = rDoc.CountNonFilteredRows(nStartRow, rDoc.MaxRow(), nTab);
+ return static_cast<size_t>(nCount) == nRows && bOneTabOnly;
+}
+
+bool ScViewUtil::HasFiltered( const ScRange& rRange, const ScDocument& rDoc )
+{
+ SCROW nStartRow = rRange.aStart.Row();
+ SCROW nEndRow = rRange.aEnd.Row();
+ for (SCTAB nTab=rRange.aStart.Tab(); nTab<=rRange.aEnd.Tab(); nTab++)
+ {
+ if (rDoc.HasFilteredRows(nStartRow, nEndRow, nTab))
+ return true;
+ }
+
+ return false;
+}
+
+void ScViewUtil::HideDisabledSlot( SfxItemSet& rSet, SfxBindings& rBindings, sal_uInt16 nSlotId )
+{
+ SvtCTLOptions aCTLOptions;
+ bool bEnabled = true;
+
+ switch( nSlotId )
+ {
+ case SID_CHINESE_CONVERSION:
+ case SID_HANGUL_HANJA_CONVERSION:
+ bEnabled = SvtCJKOptions::IsAnyEnabled();
+ break;
+
+ case SID_TRANSLITERATE_HALFWIDTH:
+ case SID_TRANSLITERATE_FULLWIDTH:
+ case SID_TRANSLITERATE_HIRAGANA:
+ case SID_TRANSLITERATE_KATAKANA:
+ bEnabled = SvtCJKOptions::IsChangeCaseMapEnabled();
+ break;
+
+ case SID_INSERT_RLM:
+ case SID_INSERT_LRM:
+ bEnabled = aCTLOptions.IsCTLFontEnabled();
+ break;
+
+ default:
+ OSL_FAIL( "ScViewUtil::HideDisabledSlot - unknown slot ID" );
+ return;
+ }
+
+ rBindings.SetVisibleState( nSlotId, bEnabled );
+ if( !bEnabled )
+ rSet.DisableItem( nSlotId );
+}
+
+void ScViewUtil::ExecuteCharMap(const SvxFontItem& rOldFont,
+ const ScTabViewShell& rShell)
+{
+ SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create();
+ SfxViewFrame& rFrame = *rShell.GetViewFrame();
+ SfxAllItemSet aSet( rFrame.GetObjectShell()->GetPool() );
+ aSet.Put( SfxBoolItem( FN_PARAM_1, false ) );
+ aSet.Put( SvxFontItem( rOldFont.GetFamily(), rOldFont.GetFamilyName(), rOldFont.GetStyleName(), rOldFont.GetPitch(), rOldFont.GetCharSet(), aSet.GetPool()->GetWhich( SID_ATTR_CHAR_FONT ) ) );
+ auto xFrame = rFrame.GetFrame().GetFrameInterface();
+ ScopedVclPtr<SfxAbstractDialog> pDlg(pFact->CreateCharMapDialog(rShell.GetFrameWeld(), aSet, xFrame));
+ pDlg->Execute();
+}
+
+bool ScViewUtil::IsFullScreen( const SfxViewShell& rViewShell )
+{
+ SfxBindings& rBindings = rViewShell.GetViewFrame()->GetBindings();
+ std::unique_ptr<SfxBoolItem> pItem;
+ bool bIsFullScreen = false;
+
+ if (rBindings.QueryState( SID_WIN_FULLSCREEN, pItem ) >= SfxItemState::DEFAULT)
+ bIsFullScreen = pItem->GetValue();
+
+ return bIsFullScreen;
+}
+
+void ScViewUtil::SetFullScreen( const SfxViewShell& rViewShell, bool bSet )
+{
+ if( IsFullScreen( rViewShell ) != bSet )
+ {
+ SfxBoolItem aItem( SID_WIN_FULLSCREEN, bSet );
+ rViewShell.GetDispatcher()->ExecuteList(SID_WIN_FULLSCREEN,
+ SfxCallMode::RECORD, { &aItem });
+ }
+}
+
+ScUpdateRect::ScUpdateRect( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2 )
+ : nNewStartX(0)
+ , nNewStartY(0)
+ , nNewEndX(0)
+ , nNewEndY(0)
+{
+ PutInOrder( nX1, nX2 );
+ PutInOrder( nY1, nY2 );
+
+ nOldStartX = nX1;
+ nOldStartY = nY1;
+ nOldEndX = nX2;
+ nOldEndY = nY2;
+}
+
+void ScUpdateRect::SetNew( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2 )
+{
+ PutInOrder( nX1, nX2 );
+ PutInOrder( nY1, nY2 );
+
+ nNewStartX = nX1;
+ nNewStartY = nY1;
+ nNewEndX = nX2;
+ nNewEndY = nY2;
+}
+
+bool ScUpdateRect::GetDiff( SCCOL& rX1, SCROW& rY1, SCCOL& rX2, SCROW& rY2 )
+{
+ if ( nNewStartX == nOldStartX && nNewEndX == nOldEndX &&
+ nNewStartY == nOldStartY && nNewEndY == nOldEndY )
+ {
+ rX1 = nNewStartX;
+ rY1 = nNewStartY;
+ rX2 = nNewStartX;
+ rY2 = nNewStartY;
+ return false;
+ }
+
+ rX1 = std::min(nNewStartX,nOldStartX);
+ rY1 = std::min(nNewStartY,nOldStartY);
+ rX2 = std::max(nNewEndX,nOldEndX);
+ rY2 = std::max(nNewEndY,nOldEndY);
+
+ if ( nNewStartX == nOldStartX && nNewEndX == nOldEndX )
+ {
+ if ( nNewStartY == nOldStartY )
+ {
+ rY1 = std::min( nNewEndY, nOldEndY );
+ rY2 = std::max( nNewEndY, nOldEndY );
+ }
+ else if ( nNewEndY == nOldEndY )
+ {
+ rY1 = std::min( nNewStartY, nOldStartY );
+ rY2 = std::max( nNewStartY, nOldStartY );
+ }
+ }
+ else if ( nNewStartY == nOldStartY && nNewEndY == nOldEndY )
+ {
+ if ( nNewStartX == nOldStartX )
+ {
+ rX1 = std::min( nNewEndX, nOldEndX );
+ rX2 = std::max( nNewEndX, nOldEndX );
+ }
+ else if ( nNewEndX == nOldEndX )
+ {
+ rX1 = std::min( nNewStartX, nOldStartX );
+ rX2 = std::max( nNewStartX, nOldStartX );
+ }
+ }
+
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/waitoff.cxx b/sc/source/ui/view/waitoff.cxx
new file mode 100644
index 000000000..94b2728bc
--- /dev/null
+++ b/sc/source/ui/view/waitoff.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 <vcl/window.hxx>
+
+#include <waitoff.hxx>
+
+ScWaitCursorOff::ScWaitCursorOff( vcl::Window* pWinP )
+ :
+ pWin( pWinP ),
+ nWaiters(0)
+{
+ if ( pWin )
+ {
+ while ( pWin->IsWait() )
+ {
+ nWaiters++;
+ pWin->LeaveWait();
+ }
+ }
+}
+
+ScWaitCursorOff::~ScWaitCursorOff()
+{
+ if ( pWin )
+ {
+ while ( nWaiters )
+ {
+ nWaiters--;
+ pWin->EnterWait();
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/xmlsource/xmlsourcedlg.cxx b/sc/source/ui/xmlsource/xmlsourcedlg.cxx
new file mode 100644
index 000000000..902c8c0a0
--- /dev/null
+++ b/sc/source/ui/xmlsource/xmlsourcedlg.cxx
@@ -0,0 +1,622 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.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 <xmlsourcedlg.hxx>
+#include <bitmaps.hlst>
+#include <document.hxx>
+#include <orcusfilters.hxx>
+#include <filter.hxx>
+#include <reffact.hxx>
+#include <tabvwsh.hxx>
+
+#include <tools/urlobj.hxx>
+#include <sfx2/filedlghelper.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <com/sun/star/ui/dialogs/XFilePicker3.hpp>
+#include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
+#include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
+
+using namespace com::sun::star;
+
+namespace {
+
+bool isAttribute(const weld::TreeView& rControl, const weld::TreeIter& rEntry)
+{
+ const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rControl, rEntry);
+ if (!pUserData)
+ return false;
+
+ return pUserData->meType == ScOrcusXMLTreeParam::Attribute;
+}
+
+OUString getXPath(
+ const weld::TreeView& rTree, const weld::TreeIter& rEntry, std::vector<size_t>& rNamespaces)
+{
+ OUStringBuffer aBuf;
+ std::unique_ptr<weld::TreeIter> xEntry(rTree.make_iterator(&rEntry));
+ do
+ {
+ // Collect used namespace.
+ const ScOrcusXMLTreeParam::EntryData* pData = ScOrcusXMLTreeParam::getUserData(rTree, *xEntry);
+ if (pData)
+ rNamespaces.push_back(pData->mnNamespaceID);
+
+ // element separator is '/' whereas attribute separator is '/@' in xpath.
+ aBuf.insert(0, rTree.get_text(*xEntry, 0));
+ if (isAttribute(rTree, *xEntry))
+ aBuf.insert(0, "/@");
+ else
+ aBuf.insert(0, '/');
+ }
+ while (rTree.iter_parent(*xEntry));
+
+ return aBuf.makeStringAndClear();
+}
+
+}
+
+ScXMLSourceDlg::ScXMLSourceDlg(
+ SfxBindings* pB, SfxChildWindow* pCW, weld::Window* pParent, ScDocument* pDoc)
+ : ScAnyRefDlgController(pB, pCW, pParent, "modules/scalc/ui/xmlsourcedialog.ui", "XMLSourceDialog")
+ , mpDoc(pDoc)
+ , mbDlgLostFocus(false)
+ , mxBtnSelectSource(m_xBuilder->weld_button("selectsource"))
+ , mxFtSourceFile(m_xBuilder->weld_label("sourcefile"))
+ , mxMapGrid(m_xBuilder->weld_container("mapgrid"))
+ , mxLbTree(m_xBuilder->weld_tree_view("tree"))
+ , mxRefEdit(new formula::RefEdit(m_xBuilder->weld_entry("edit")))
+ , mxRefBtn(new formula::RefButton(m_xBuilder->weld_button("ref")))
+ , mxBtnOk(m_xBuilder->weld_button("ok"))
+ , mxBtnCancel(m_xBuilder->weld_button("cancel"))
+ , maCustomCompare(*mxLbTree)
+ , maCellLinks(maCustomCompare)
+ , maRangeLinks(maCustomCompare)
+{
+ mxLbTree->set_size_request(mxLbTree->get_approximate_digit_width() * 40,
+ mxLbTree->get_height_rows(15));
+ mxLbTree->set_selection_mode(SelectionMode::Multiple);
+ mxRefEdit->SetReferences(this, nullptr);
+ mxRefBtn->SetReferences(this, mxRefEdit.get());
+
+ mpActiveEdit = mxRefEdit.get();
+
+ maXMLParam.maImgElementDefault = RID_BMP_ELEMENT_DEFAULT;
+ maXMLParam.maImgElementRepeat = RID_BMP_ELEMENT_REPEAT;
+ maXMLParam.maImgAttribute = RID_BMP_ELEMENT_ATTRIBUTE;
+
+ Link<weld::Button&,void> aBtnHdl = LINK(this, ScXMLSourceDlg, BtnPressedHdl);
+ mxBtnSelectSource->connect_clicked(aBtnHdl);
+ mxBtnOk->connect_clicked(aBtnHdl);
+ mxBtnCancel->connect_clicked(aBtnHdl);
+
+ mxLbTree->connect_changed(LINK(this, ScXMLSourceDlg, TreeItemSelectHdl));
+
+ Link<formula::RefEdit&,void> aLink = LINK(this, ScXMLSourceDlg, RefModifiedHdl);
+ mxRefEdit->SetModifyHdl(aLink);
+
+ mxBtnOk->set_sensitive(false);
+
+ SetNonLinkable();
+ mxBtnSelectSource->grab_focus(); // Initial focus is on the select source button.
+}
+
+ScXMLSourceDlg::~ScXMLSourceDlg()
+{
+}
+
+bool ScXMLSourceDlg::IsRefInputMode() const
+{
+ return mpActiveEdit != nullptr && mpActiveEdit->GetWidget()->get_sensitive();
+}
+
+void ScXMLSourceDlg::SetReference(const ScRange& rRange, ScDocument& rDoc)
+{
+ if (!mpActiveEdit)
+ return;
+
+ if (rRange.aStart != rRange.aEnd)
+ RefInputStart(mpActiveEdit);
+
+ OUString aStr(rRange.aStart.Format(ScRefFlags::ADDR_ABS_3D, &rDoc, rDoc.GetAddressConvention()));
+ mpActiveEdit->SetRefString(aStr);
+
+ RefEditModified();
+}
+
+void ScXMLSourceDlg::Deactivate()
+{
+ mbDlgLostFocus = true;
+}
+
+void ScXMLSourceDlg::SetActive()
+{
+ if (mbDlgLostFocus)
+ {
+ mbDlgLostFocus = false;
+ if (mpActiveEdit)
+ {
+ mpActiveEdit->GrabFocus();
+ }
+ }
+ else
+ {
+ m_xDialog->grab_focus();
+ }
+
+ RefInputDone();
+}
+
+void ScXMLSourceDlg::Close()
+{
+ DoClose(ScXMLSourceDlgWrapper::GetChildWindowId());
+}
+
+void ScXMLSourceDlg::SelectSourceFile()
+{
+ sfx2::FileDialogHelper aDlgHelper(ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE,
+ FileDialogFlags::NONE, m_xDialog.get());
+ aDlgHelper.SetContext(sfx2::FileDialogHelper::CalcXMLSource);
+
+ uno::Reference<ui::dialogs::XFilePicker3> xFilePicker = aDlgHelper.GetFilePicker();
+
+ // Use the directory of current source file.
+ INetURLObject aURL(maSrcPath);
+ aURL.removeSegment();
+ aURL.removeFinalSlash();
+ OUString aPath = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
+ xFilePicker->setDisplayDirectory(aPath);
+
+ if (xFilePicker->execute() != ui::dialogs::ExecutableDialogResults::OK)
+ // File picker dialog cancelled.
+ return;
+
+ uno::Sequence<OUString> aFiles = xFilePicker->getSelectedFiles();
+ if (!aFiles.hasElements())
+ return;
+
+ // There should only be one file returned from the file picker.
+ maSrcPath = aFiles[0];
+ mxFtSourceFile->set_label(maSrcPath);
+ LoadSourceFileStructure(maSrcPath);
+}
+
+void ScXMLSourceDlg::LoadSourceFileStructure(const OUString& rPath)
+{
+ ScOrcusFilters* pOrcus = ScFormatFilter::Get().GetOrcusFilters();
+ if (!pOrcus)
+ return;
+
+ mpXMLContext = pOrcus->createXMLContext(*mpDoc, rPath);
+ if (!mpXMLContext)
+ return;
+
+ mpXMLContext->loadXMLStructure(*mxLbTree, maXMLParam);
+}
+
+namespace {
+
+/**
+ * The current entry is the reference entry for a cell link. For a range
+ * link, the reference entry is the shallowest repeat element entry up from
+ * the current entry position. The mapped cell position for a range link is
+ * stored with the reference entry.
+ */
+std::unique_ptr<weld::TreeIter> getReferenceEntry(const weld::TreeView& rTree, const weld::TreeIter& rCurEntry)
+{
+ std::unique_ptr<weld::TreeIter> xParent(rTree.make_iterator(&rCurEntry));
+ bool bParent = rTree.iter_parent(*xParent);
+ std::unique_ptr<weld::TreeIter> xRefEntry;
+ while (bParent)
+ {
+ ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rTree, *xParent);
+ OSL_ASSERT(pUserData);
+ if (pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat)
+ {
+ // This is a repeat element - a potential reference entry.
+ xRefEntry = rTree.make_iterator(xParent.get());
+ }
+ bParent = rTree.iter_parent(*xParent);
+ }
+
+ if (xRefEntry)
+ return xRefEntry;
+
+ std::unique_ptr<weld::TreeIter> xCurEntry(rTree.make_iterator(&rCurEntry));
+ return xCurEntry;
+}
+
+}
+
+void ScXMLSourceDlg::TreeItemSelected()
+{
+ std::unique_ptr<weld::TreeIter> xEntry(mxLbTree->make_iterator());
+ if (!mxLbTree->get_cursor(xEntry.get()))
+ return;
+
+ mxLbTree->unselect_all();
+ mxLbTree->select(*xEntry);
+
+ mxCurRefEntry = getReferenceEntry(*mxLbTree, *xEntry);
+
+ ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *mxCurRefEntry);
+ OSL_ASSERT(pUserData);
+
+ const ScAddress& rPos = pUserData->maLinkedPos;
+ if (rPos.IsValid())
+ {
+ OUString aStr(rPos.Format(ScRefFlags::ADDR_ABS_3D, mpDoc, mpDoc->GetAddressConvention()));
+ mxRefEdit->SetRefString(aStr);
+ }
+ else
+ mxRefEdit->SetRefString(OUString());
+
+ switch (pUserData->meType)
+ {
+ case ScOrcusXMLTreeParam::Attribute:
+ AttributeSelected(*mxCurRefEntry);
+ break;
+ case ScOrcusXMLTreeParam::ElementDefault:
+ DefaultElementSelected(*mxCurRefEntry);
+ break;
+ case ScOrcusXMLTreeParam::ElementRepeat:
+ RepeatElementSelected(*mxCurRefEntry);
+ break;
+ default:
+ ;
+ }
+}
+
+void ScXMLSourceDlg::DefaultElementSelected(const weld::TreeIter& rEntry)
+{
+ if (mxLbTree->iter_has_child(rEntry))
+ {
+ // Only an element with no child elements (leaf element) can be linked.
+ bool bHasChild = false;
+ std::unique_ptr<weld::TreeIter> xChild(mxLbTree->make_iterator(&rEntry));
+ (void)mxLbTree->iter_children(*xChild);
+ do
+ {
+ ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xChild);
+ OSL_ASSERT(pUserData);
+ if (pUserData->meType != ScOrcusXMLTreeParam::Attribute)
+ {
+ // This child is not an attribute. Bail out.
+ bHasChild = true;
+ break;
+ }
+ }
+ while (mxLbTree->iter_next_sibling(*xChild));
+
+ if (bHasChild)
+ {
+ SetNonLinkable();
+ return;
+ }
+ }
+
+ // Check all its parents and make sure non of them are range-linked nor
+ // repeat elements.
+ if (IsParentDirty(&rEntry))
+ {
+ SetNonLinkable();
+ return;
+ }
+
+ SetSingleLinkable();
+}
+
+void ScXMLSourceDlg::RepeatElementSelected(const weld::TreeIter& rEntry)
+{
+ // Check all its parents first.
+
+ if (IsParentDirty(&rEntry))
+ {
+ SetNonLinkable();
+ return;
+ }
+
+ // Check all its child elements / attributes and make sure non of them are
+ // linked.
+
+ if (IsChildrenDirty(&rEntry))
+ {
+ SetNonLinkable();
+ return;
+ }
+
+ if (!mxLbTree->is_selected(rEntry))
+ {
+ // Highlight the entry if not highlighted already. This can happen
+ // when the current entry is a child entry of a repeat element entry.
+ mxLbTree->select(rEntry);
+ }
+
+ SelectAllChildEntries(rEntry);
+ SetRangeLinkable();
+}
+
+void ScXMLSourceDlg::AttributeSelected(const weld::TreeIter& rEntry)
+{
+ // Check all its parent elements and make sure non of them are linked nor
+ // repeat elements. In attribute's case, it's okay to have the immediate
+ // parent element linked (but not range-linked).
+ std::unique_ptr<weld::TreeIter> xParent(mxLbTree->make_iterator(&rEntry));
+ mxLbTree->iter_parent(*xParent);
+
+ ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xParent);
+ OSL_ASSERT(pUserData);
+ if (pUserData->maLinkedPos.IsValid() && pUserData->mbRangeParent)
+ {
+ // Parent element is range-linked. Bail out.
+ SetNonLinkable();
+ return;
+ }
+
+ if (IsParentDirty(&rEntry))
+ {
+ SetNonLinkable();
+ return;
+ }
+
+ SetSingleLinkable();
+}
+
+void ScXMLSourceDlg::SetNonLinkable()
+{
+ mxMapGrid->set_sensitive(false);
+}
+
+void ScXMLSourceDlg::SetSingleLinkable()
+{
+ mxMapGrid->set_sensitive(true);
+}
+
+void ScXMLSourceDlg::SetRangeLinkable()
+{
+ mxMapGrid->set_sensitive(true);
+}
+
+void ScXMLSourceDlg::SelectAllChildEntries(const weld::TreeIter& rEntry)
+{
+ std::unique_ptr<weld::TreeIter> xChild(mxLbTree->make_iterator(&rEntry));
+ if (!mxLbTree->iter_children(*xChild))
+ return;
+ do
+ {
+ SelectAllChildEntries(*xChild); // select recursively.
+ mxLbTree->select(*xChild);
+ } while (mxLbTree->iter_next_sibling(*xChild));
+}
+
+bool ScXMLSourceDlg::IsParentDirty(const weld::TreeIter* pEntry) const
+{
+ std::unique_ptr<weld::TreeIter> xParent(mxLbTree->make_iterator(pEntry));
+ if (!mxLbTree->iter_parent(*xParent))
+ return false;
+ do
+ {
+ ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xParent);
+ assert(pUserData);
+ if (pUserData->maLinkedPos.IsValid())
+ {
+ // This parent is already linked.
+ return true;
+ }
+ }
+ while (mxLbTree->iter_parent(*xParent));
+ return false;
+}
+
+bool ScXMLSourceDlg::IsChildrenDirty(const weld::TreeIter* pEntry) const
+{
+ std::unique_ptr<weld::TreeIter> xChild(mxLbTree->make_iterator(pEntry));
+ if (!mxLbTree->iter_children(*xChild))
+ return false;
+
+ do
+ {
+ ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *xChild);
+ OSL_ASSERT(pUserData);
+ if (pUserData->maLinkedPos.IsValid())
+ // Already linked.
+ return true;
+
+ if (pUserData->meType == ScOrcusXMLTreeParam::ElementDefault)
+ {
+ // Check recursively.
+ if (IsChildrenDirty(xChild.get()))
+ return true;
+ }
+ } while (mxLbTree->iter_next_sibling(*xChild));
+
+ return false;
+}
+
+namespace {
+
+/**
+ * Pick only the leaf elements.
+ */
+void getFieldLinks(
+ ScOrcusImportXMLParam::RangeLink& rRangeLink, std::vector<size_t>& rNamespaces,
+ const weld::TreeView& rTree, const weld::TreeIter& rEntry)
+{
+ std::unique_ptr<weld::TreeIter> xChild(rTree.make_iterator(&rEntry));
+ if (!rTree.iter_children(*xChild))
+ // No more children. We're done.
+ return;
+
+ do
+ {
+ OUString aPath = getXPath(rTree, *xChild, rNamespaces);
+ const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(rTree, *xChild);
+
+ if (pUserData)
+ {
+ if (pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat)
+ // nested repeat element automatically becomes a row-group node.
+ rRangeLink.maRowGroups.push_back(
+ OUStringToOString(aPath, RTL_TEXTENCODING_UTF8));
+
+ if (pUserData->mbLeafNode && !aPath.isEmpty())
+ // XPath should never be empty anyway, but it won't hurt to check...
+ rRangeLink.maFieldPaths.push_back(OUStringToOString(aPath, RTL_TEXTENCODING_UTF8));
+ }
+
+ // Walk recursively.
+ getFieldLinks(rRangeLink, rNamespaces, rTree, *xChild);
+ } while (rTree.iter_next_sibling(*xChild));
+}
+
+void removeDuplicates(std::vector<size_t>& rArray)
+{
+ std::sort(rArray.begin(), rArray.end());
+ std::vector<size_t>::iterator it = std::unique(rArray.begin(), rArray.end());
+ rArray.erase(it, rArray.end());
+}
+
+}
+
+void ScXMLSourceDlg::OkPressed()
+{
+ if (!mpXMLContext)
+ return;
+
+ // Begin import.
+
+ ScOrcusImportXMLParam aParam;
+
+ // Convert single cell links.
+ for (const auto& rEntry : maCellLinks)
+ {
+ OUString aPath = getXPath(*mxLbTree, *rEntry, aParam.maNamespaces);
+ const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *rEntry);
+
+ aParam.maCellLinks.emplace_back(
+ pUserData->maLinkedPos, OUStringToOString(aPath, RTL_TEXTENCODING_UTF8));
+ }
+
+ // Convert range links. For now, an element with range link takes all its
+ // child elements as its fields.
+ for (const auto& rEntry: maRangeLinks)
+ {
+ const ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *rEntry);
+
+ ScOrcusImportXMLParam::RangeLink aRangeLink;
+ aRangeLink.maPos = pUserData->maLinkedPos;
+
+ // Go through all its child elements.
+ getFieldLinks(aRangeLink, aParam.maNamespaces, *mxLbTree, *rEntry);
+
+ // Add the reference entry as a row-group node, which will be used
+ // as a row position increment point.
+ OUString aThisEntry = getXPath(*mxLbTree, *rEntry, aParam.maNamespaces);
+ aRangeLink.maRowGroups.push_back(
+ OUStringToOString(aThisEntry, RTL_TEXTENCODING_UTF8));
+
+ aParam.maRangeLinks.push_back(aRangeLink);
+ }
+
+ // Remove duplicate namespace IDs.
+ removeDuplicates(aParam.maNamespaces);
+
+ // Now do the import.
+ mpXMLContext->importXML(aParam);
+
+ // Don't forget to broadcast the change.
+ SfxObjectShell* pShell = mpDoc->GetDocumentShell();
+ pShell->Broadcast(SfxHint(SfxHintId::ScDataChanged));
+
+ // Repaint the grid to force repaint the cell values.
+ ScTabViewShell* pViewShell = ScTabViewShell::GetActiveViewShell();
+ if (pViewShell)
+ pViewShell->PaintGrid();
+
+ m_xDialog->response(RET_OK);
+}
+
+void ScXMLSourceDlg::CancelPressed()
+{
+ m_xDialog->response(RET_CANCEL);
+}
+
+void ScXMLSourceDlg::RefEditModified()
+{
+ OUString aRefStr = mxRefEdit->GetText();
+
+ // Check if the address is valid.
+ // Preset current sheet in case only address was entered.
+ ScAddress aLinkedPos;
+ aLinkedPos.SetTab( ScDocShell::GetCurTab());
+ ScRefFlags nRes = aLinkedPos.Parse(aRefStr, *mpDoc, mpDoc->GetAddressConvention());
+ bool bValid = ( (nRes & ScRefFlags::VALID) == ScRefFlags::VALID );
+
+ // TODO: For some unknown reason, setting the ref invalid will hide the text altogether.
+ // Find out how to make this work.
+// mxRefEdit->SetRefValid(bValid);
+
+ if (!bValid)
+ aLinkedPos.SetInvalid();
+
+ // Set this address to the current reference entry.
+ if (!mxCurRefEntry)
+ // This should never happen.
+ return;
+
+ ScOrcusXMLTreeParam::EntryData* pUserData = ScOrcusXMLTreeParam::getUserData(*mxLbTree, *mxCurRefEntry);
+ if (!pUserData)
+ // This should never happen either.
+ return;
+
+ bool bRepeatElem = pUserData->meType == ScOrcusXMLTreeParam::ElementRepeat;
+ pUserData->maLinkedPos = aLinkedPos;
+ pUserData->mbRangeParent = aLinkedPos.IsValid() && bRepeatElem;
+
+ if (bRepeatElem)
+ {
+ if (bValid)
+ maRangeLinks.insert(mxLbTree->make_iterator(mxCurRefEntry.get()));
+ else
+ maRangeLinks.erase(mxCurRefEntry);
+ }
+ else
+ {
+ if (bValid)
+ maCellLinks.insert(mxLbTree->make_iterator(mxCurRefEntry.get()));
+ else
+ maCellLinks.erase(mxCurRefEntry);
+ }
+
+ // Enable the import button only when at least one link exists.
+ bool bHasLink = !maCellLinks.empty() || !maRangeLinks.empty();
+ mxBtnOk->set_sensitive(bHasLink);
+}
+
+IMPL_LINK(ScXMLSourceDlg, BtnPressedHdl, weld::Button&, rBtn, void)
+{
+ if (&rBtn == mxBtnSelectSource.get())
+ SelectSourceFile();
+ else if (&rBtn == mxBtnOk.get())
+ OkPressed();
+ else if (&rBtn == mxBtnCancel.get())
+ CancelPressed();
+}
+
+IMPL_LINK_NOARG(ScXMLSourceDlg, TreeItemSelectHdl, weld::TreeView&, void)
+{
+ TreeItemSelected();
+}
+
+IMPL_LINK_NOARG(ScXMLSourceDlg, RefModifiedHdl, formula::RefEdit&, void)
+{
+ RefEditModified();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */